diff --git a/.github/build.in.yml b/.github/build.in.yml index 3facc8b60a92b..4d0134b8b6c39 100644 --- a/.github/build.in.yml +++ b/.github/build.in.yml @@ -33,7 +33,7 @@ jobs: uses: credfeto/action-case-checker@v1.3.0 - name: Look for ignored files - uses: credfeto/action-no-ignored-files@v1.1.0 + uses: credfeto/action-no-ignored-files@v1.2.0 - name: "Check for Lean files with the executable bit set" shell: bash @@ -92,7 +92,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | @@ -303,7 +303,7 @@ jobs: - uses: actions/checkout@v4 - id: PR - uses: 8BitJonny/gh-get-current-pr@2.2.0 + uses: 8BitJonny/gh-get-current-pr@3.0.0 # TODO: this may not work properly if the same commit is pushed to multiple branches: # https://github.com/8BitJonny/gh-get-current-pr/issues/8 with: diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..4e43547be01ea --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +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 + schedule: + # Check for updates to GitHub Actions every month + interval: "monthly" diff --git a/.github/workflows/bench_summary_comment.yml b/.github/workflows/bench_summary_comment.yml new file mode 100644 index 0000000000000..6672fb8443e98 --- /dev/null +++ b/.github/workflows/bench_summary_comment.yml @@ -0,0 +1,35 @@ +name: Bench output summary + +on: + issue_comment: + types: created + +jobs: + Produce_bench_summary: + name: Post summary of benchmarking results + if: github.event.issue.pull_request && (startsWith(github.event.comment.body, 'Here are the [benchmark results]')) + runs-on: ubuntu-latest + steps: + - 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}" + + - uses: actions/checkout@v4 + with: + ref: master + sparse-checkout: | + scripts/bench_summary.lean + + - name: Summarize bench output + run: | + { + cat scripts/bench_summary.lean + printf $'run_cmd BenchAction.addBenchSummaryComment %s "leanprover-community/mathlib4"' "${PR}" + } | + lake env lean --stdin + env: + PR: ${{ github.event.issue.number }} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 207aee8482616..816f0864dc82c 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -43,7 +43,7 @@ jobs: uses: credfeto/action-case-checker@v1.3.0 - name: Look for ignored files - uses: credfeto/action-no-ignored-files@v1.1.0 + uses: credfeto/action-no-ignored-files@v1.2.0 - name: "Check for Lean files with the executable bit set" shell: bash @@ -102,7 +102,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | @@ -313,7 +313,7 @@ jobs: - uses: actions/checkout@v4 - id: PR - uses: 8BitJonny/gh-get-current-pr@2.2.0 + uses: 8BitJonny/gh-get-current-pr@3.0.0 # TODO: this may not work properly if the same commit is pushed to multiple branches: # https://github.com/8BitJonny/gh-get-current-pr/issues/8 with: diff --git a/.github/workflows/bot_fix_style_comment.yaml b/.github/workflows/bot_fix_style_comment.yaml index 4414eb4b576b5..5e0cbbbffd648 100644 --- a/.github/workflows/bot_fix_style_comment.yaml +++ b/.github/workflows/bot_fix_style_comment.yaml @@ -41,7 +41,7 @@ jobs: - name: install Python if: steps.user_permission.outputs.require-result == 'true' - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 diff --git a/.github/workflows/bot_fix_style_review.yaml b/.github/workflows/bot_fix_style_review.yaml index 99fa4ae9a7dab..ec389af5ce65b 100644 --- a/.github/workflows/bot_fix_style_review.yaml +++ b/.github/workflows/bot_fix_style_review.yaml @@ -47,7 +47,7 @@ jobs: - name: install Python if: steps.user_permission.outputs.require-result == 'true' - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 diff --git a/.github/workflows/bot_fix_style_review_comment.yaml b/.github/workflows/bot_fix_style_review_comment.yaml index 097b24ba35954..d997a6ad7989a 100644 --- a/.github/workflows/bot_fix_style_review_comment.yaml +++ b/.github/workflows/bot_fix_style_review_comment.yaml @@ -45,7 +45,7 @@ jobs: - name: install Python if: steps.user_permission.outputs.require-result == 'true' - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c47cd306ed4da..f1c9dfc8fc360 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: uses: credfeto/action-case-checker@v1.3.0 - name: Look for ignored files - uses: credfeto/action-no-ignored-files@v1.1.0 + uses: credfeto/action-no-ignored-files@v1.2.0 - name: "Check for Lean files with the executable bit set" shell: bash @@ -109,7 +109,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | @@ -320,7 +320,7 @@ jobs: - uses: actions/checkout@v4 - id: PR - uses: 8BitJonny/gh-get-current-pr@2.2.0 + uses: 8BitJonny/gh-get-current-pr@3.0.0 # TODO: this may not work properly if the same commit is pushed to multiple branches: # https://github.com/8BitJonny/gh-get-current-pr/issues/8 with: diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index c431ad5e7d2f2..b1bffcfcd5e0b 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -47,7 +47,7 @@ jobs: uses: credfeto/action-case-checker@v1.3.0 - name: Look for ignored files - uses: credfeto/action-no-ignored-files@v1.1.0 + uses: credfeto/action-no-ignored-files@v1.2.0 - name: "Check for Lean files with the executable bit set" shell: bash @@ -106,7 +106,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | @@ -317,7 +317,7 @@ jobs: - uses: actions/checkout@v4 - id: PR - uses: 8BitJonny/gh-get-current-pr@2.2.0 + uses: 8BitJonny/gh-get-current-pr@3.0.0 # TODO: this may not work properly if the same commit is pushed to multiple branches: # https://github.com/8BitJonny/gh-get-current-pr/issues/8 with: diff --git a/.github/workflows/dependent-issues.yml b/.github/workflows/dependent-issues.yml index 9e0b3d2da4b71..16c75acafbf69 100644 --- a/.github/workflows/dependent-issues.yml +++ b/.github/workflows/dependent-issues.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest # timeout-minutes: 3 steps: - - uses: styfle/cancel-workflow-action@0.11.0 + - uses: styfle/cancel-workflow-action@0.12.1 with: all_but_latest: true access_token: ${{ github.token }} diff --git a/.github/workflows/labels_from_comment.yml b/.github/workflows/labels_from_comment.yml index b40b8d4c4daf6..02e881f3e822c 100644 --- a/.github/workflows/labels_from_comment.yml +++ b/.github/workflows/labels_from_comment.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Add label based on comment - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/lean4checker.yml b/.github/workflows/lean4checker.yml index 8405cde825320..b98c03bba301e 100644 --- a/.github/workflows/lean4checker.yml +++ b/.github/workflows/lean4checker.yml @@ -25,7 +25,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | @@ -70,21 +70,19 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout v4.12.0-rc1 + # This should be changed back to a version tag when + # anything subsequent to `v4.13.0-rc3` is released. + git checkout master # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . lake build ./test.sh cd .. - lake env lean4checker/.lake/build/bin/lean4checker - - - id: ci_url - run: | - url=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - curl -s "${url}" | - # extract the CI run number from the unique line that matches ` href=".../job/[job number]"` - awk -v url="${url}" -F'/' '/^ *href/ {gsub(/"/, "", $NF); printf("summary<> "$GITHUB_OUTPUT" + # After https://github.com/leanprover/lean4checker/pull/26 + # lean4checker by default only runs on the current project + # so we explicitly check Batteries as well here. + lake env lean4checker/.lake/build/bin/lean4checker Batteries Mathlib - name: Post success message on Zulip if: success() @@ -97,7 +95,7 @@ jobs: type: 'stream' topic: 'lean4checker' content: | - ✅ lean4checker [succeeded](${{ steps.ci_url.outputs.summary }}) on ${{ github.sha }} + ✅ lean4checker [succeeded](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} - name: Post failure message on Zulip if: failure() @@ -110,7 +108,7 @@ jobs: type: 'stream' topic: 'lean4checker failure' content: | - ❌ lean4checker [failed](${{ steps.ci_url.outputs.summary }}) on ${{ github.sha }} + ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} continue-on-error: true - name: Post failure message on Zulip main topic @@ -124,5 +122,5 @@ jobs: type: 'stream' topic: 'lean4checker' content: | - ❌ lean4checker failed on ${{ github.sha }} + ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} continue-on-error: true diff --git a/.github/workflows/lint_and_suggest_pr.yml b/.github/workflows/lint_and_suggest_pr.yml index 409e78ebc223e..47029833459db 100644 --- a/.github/workflows/lint_and_suggest_pr.yml +++ b/.github/workflows/lint_and_suggest_pr.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 diff --git a/.github/workflows/maintainer_merge_comment.yml b/.github/workflows/maintainer_merge_comment.yml index db769c6592ab6..7cdc17fe4ab74 100644 --- a/.github/workflows/maintainer_merge_comment.yml +++ b/.github/workflows/maintainer_merge_comment.yml @@ -52,7 +52,7 @@ jobs: body: | 🚀 Pull request has been placed on the maintainer queue by ${{ github.event.comment.user.login }}. - name: Add label to PR - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | diff --git a/.github/workflows/maintainer_merge_review.yml b/.github/workflows/maintainer_merge_review.yml index c7d8357bbfa64..e3b5954d6486c 100644 --- a/.github/workflows/maintainer_merge_review.yml +++ b/.github/workflows/maintainer_merge_review.yml @@ -51,7 +51,7 @@ jobs: body: | 🚀 Pull request has been placed on the maintainer queue by ${{ github.event.review.user.login }}. - name: Add label to PR - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | diff --git a/.github/workflows/maintainer_merge_review_comment.yml b/.github/workflows/maintainer_merge_review_comment.yml index 79a5ea176d9d9..10cb9570bac49 100644 --- a/.github/workflows/maintainer_merge_review_comment.yml +++ b/.github/workflows/maintainer_merge_review_comment.yml @@ -50,7 +50,7 @@ jobs: body: | 🚀 Pull request has been placed on the maintainer queue by ${{ github.event.comment.user.login }}. - name: Add label to PR - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | diff --git a/.github/workflows/nightly_detect_failure.yml b/.github/workflows/nightly_detect_failure.yml index 25835698e99ab..0f52fa1c48fc2 100644 --- a/.github/workflows/nightly_detect_failure.yml +++ b/.github/workflows/nightly_detect_failure.yml @@ -212,14 +212,25 @@ jobs: payload = f"🛠️: it looks like it's time to create a new bump/nightly-{current_version} branch from nightly-testing (specifically {sha}), and then PR that to {bump_branch}. " payload += "To do so semi-automatically, run the following script from mathlib root:\n\n" payload += f"```bash\n./scripts/create-adaptation-pr.sh --bumpversion={bump_branch_suffix} --nightlydate={current_version} --nightlysha={sha}\n```\n" - # Post the reminder message - request = { - 'type': 'stream', - 'to': 'nightly-testing', - 'topic': 'Mathlib bump branch reminders', - 'content': payload - } - result = client.send_message(request) - print(result) + # Only post if the message is different + # We compare the first 160 characters, since that includes the date and bump version + if not messages or messages[0]['content'][:160] != payload[:160]: + # Log messages, because the bot seems to repeat itself... + if messages: + print("###### Last message:") + print(messages[0]['content']) + print("###### Current message:") + print(payload) + else: + print('The strings match!') + # Post the reminder message + request = { + 'type': 'stream', + 'to': 'nightly-testing', + 'topic': 'Mathlib bump branch reminders', + 'content': payload + } + result = client.send_message(request) + print(result) else: print('No action needed.') diff --git a/.github/workflows/nolints.yml b/.github/workflows/nolints.yml index 847e24854e855..33fda1bb1154c 100644 --- a/.github/workflows/nolints.yml +++ b/.github/workflows/nolints.yml @@ -16,7 +16,7 @@ jobs: # The Hoskinson runners may not have jq installed, so do that now. - name: 'Setup jq' - uses: dcarbone/install-jq-action@v1.0.1 + uses: dcarbone/install-jq-action@v2.1.0 - name: install elan run: | diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000000..ea5585c38e83e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' # every day at 01:30 UTC + workflow_dispatch: + +jobs: + stale: + runs-on: ubuntu-latest + steps: + # until https://github.com/actions/stale/pull/1145 is merged + - uses: asterisk/github-actions-stale@main-only-matching-filter + with: + debug-only: 'true' # TODO: remove in follow-up PR after testing is done! + stale-pr-label: 'stale' + stale-pr-message: 'Message to comment on stale PRs.' + close-pr-label: 'closed-due-to-inactivity' + close-pr-message: 'Comment on the staled PRs while closed' + days-before-stale: 60 + days-before-close: 120 + # search string from the Zulip #queue link at https://bit.ly/4eo6brN + # "is:open is:pr -is:draft base:master sort:updated-asc status:success -label:blocked-by-other-PR -label:merge-conflict -label:awaiting-CI -label:WIP -label:awaiting-author -label:delegated -label:auto-merge-after-CI -label:ready-to-merge -label:please-adopt -label:help-wanted -label:awaiting-zulip" + # We want PRs _not_ on the queue, so we keep "is:pr -is:draft base:master" (is:open is added by the action by default) as a prefix for all queries and then negate the rest of the params in separate queries to simulate boolean OR (see https://github.com/actions/stale/pull/1145) + # except for label:auto-merge-after-CI and label:ready-to-merge which presumably will be noticed before they go stale + only-matching-filter: '[ "is:pr -is:draft base:master -status:success", "is:pr -is:draft base:master label:blocked-by-other-PR", "is:pr -is:draft base:master label:merge-conflict", "is:pr -is:draft base:master label:awaiting-CI", "is:pr -is:draft base:master label:WIP", "is:pr -is:draft base:master label:awaiting-author", "is:pr -is:draft base:master label:delegated", "is:pr -is:draft base:master label:please-adopt", "is:pr -is:draft base:master label:help-wanted", "is:pr -is:draft base:master label:awaiting-zulip" ]' diff --git a/.github/workflows/update_dependencies.yml b/.github/workflows/update_dependencies.yml index b415c88c6a8c8..27646aaec561b 100644 --- a/.github/workflows/update_dependencies.yml +++ b/.github/workflows/update_dependencies.yml @@ -57,7 +57,7 @@ jobs: - name: Create Pull Request if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: "${{ secrets.UPDATE_DEPENDENCIES_TOKEN }}" commit-message: "chore: update Mathlib dependencies ${{ env.timestamp }}" diff --git a/Archive.lean b/Archive.lean index 2804883c9b27e..4c1d10437efaf 100644 --- a/Archive.lean +++ b/Archive.lean @@ -18,6 +18,7 @@ import Archive.Imo.Imo1972Q5 import Archive.Imo.Imo1975Q1 import Archive.Imo.Imo1977Q6 import Archive.Imo.Imo1981Q3 +import Archive.Imo.Imo1982Q1 import Archive.Imo.Imo1986Q5 import Archive.Imo.Imo1987Q1 import Archive.Imo.Imo1988Q6 @@ -62,6 +63,6 @@ import Archive.Wiedijk100Theorems.InverseTriangleSum import Archive.Wiedijk100Theorems.Konigsberg import Archive.Wiedijk100Theorems.Partition import Archive.Wiedijk100Theorems.PerfectNumbers -import Archive.Wiedijk100Theorems.SolutionOfCubic +import Archive.Wiedijk100Theorems.SolutionOfCubicQuartic import Archive.Wiedijk100Theorems.SumOfPrimeReciprocalsDiverges import Archive.ZagierTwoSquares diff --git a/Archive/Examples/IfNormalization/Result.lean b/Archive/Examples/IfNormalization/Result.lean index ef69269689c77..30ac2f21636cd 100644 --- a/Archive/Examples/IfNormalization/Result.lean +++ b/Archive/Examples/IfNormalization/Result.lean @@ -54,7 +54,7 @@ We don't want a `simp` lemma for `(ite i t e).eval` in general, only once we kno `e` to the literal booleans given by `l` -/ def normalize (l : AList (fun _ : ℕ => Bool)) : (e : IfExpr) → { e' : IfExpr // - (∀ f, e'.eval f = e.eval (fun w => (l.lookup w).elim (f w) (fun b => b))) + (∀ f, e'.eval f = e.eval (fun w => (l.lookup w).elim (f w) id)) ∧ e'.normalized ∧ ∀ (v : ℕ), v ∈ vars e' → l.lookup v = none } | lit b => ⟨lit b, ◾⟩ diff --git a/Archive/Examples/IfNormalization/WithoutAesop.lean b/Archive/Examples/IfNormalization/WithoutAesop.lean index b3e94e0a5653e..0f376cdbd1590 100644 --- a/Archive/Examples/IfNormalization/WithoutAesop.lean +++ b/Archive/Examples/IfNormalization/WithoutAesop.lean @@ -36,7 +36,7 @@ theorem eval_ite_ite' {a b c d e : IfExpr} {f : ℕ → Bool} : `e` to the literal booleans given by `l` -/ def normalize' (l : AList (fun _ : ℕ => Bool)) : (e : IfExpr) → { e' : IfExpr // - (∀ f, e'.eval f = e.eval (fun w => (l.lookup w).elim (f w) (fun b => b))) + (∀ f, e'.eval f = e.eval (fun w => (l.lookup w).elim (f w) id)) ∧ e'.normalized ∧ ∀ (v : ℕ), v ∈ vars e' → l.lookup v = none } | lit b => ⟨lit b, by simp⟩ diff --git a/Archive/Examples/MersennePrimes.lean b/Archive/Examples/MersennePrimes.lean index a19f23f8431d4..ed395b0b58e41 100644 --- a/Archive/Examples/MersennePrimes.lean +++ b/Archive/Examples/MersennePrimes.lean @@ -80,8 +80,22 @@ example : (mersenne 4253).Prime := example : (mersenne 4423).Prime := lucas_lehmer_sufficiency _ (by norm_num) (by norm_num) --- First failure ("deep recursion detected") /- -example : (mersenne 9689).Prime := - lucas_lehmer_sufficiency _ (by norm_num) (by norm_num) +`mersenne 9689` seems to be system dependent: +locally it works fine, but in CI it fails with `(kernel) deep recursion detected` +-/ +-- example : (mersenne 9689).Prime := +-- lucas_lehmer_sufficiency _ (by norm_num) (by norm_num) + +/- +`mersenne 9941` seems to be system dependent: +locally it works fine, but in CI it fails with `(kernel) deep recursion detected` +-/ +-- example : (mersenne 9941).Prime := +-- lucas_lehmer_sufficiency _ (by norm_num) (by norm_num) + +/- +`mersenne 11213` fails with `(kernel) deep recursion detected` locally as well. -/ +-- example : (mersenne 11213).Prime := +-- lucas_lehmer_sufficiency _ (by norm_num) (by norm_num) diff --git a/Archive/Imo/Imo1982Q1.lean b/Archive/Imo/Imo1982Q1.lean new file mode 100644 index 0000000000000..98a0dd60777a6 --- /dev/null +++ b/Archive/Imo/Imo1982Q1.lean @@ -0,0 +1,126 @@ +/- +Copyright (c) 2024 Alex Brodbelt. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Alex Brodbelt, Violeta Hernández +-/ + +import Mathlib.Tactic.NormNum +import Mathlib.Tactic.Linarith +import Mathlib.Data.PNat.Basic + +/-! +# IMO 1982 Q1 + +The function `f` is defined for all positive integers `n` and takes on +non-negative integer values. Also, for all `m`, `n` + +`f (m + n) - f(m) - f(n) = 0` or `1` +`f 2 = 0`, `f 3 > 0`, and `f 9999 = 3333`. + +Determine `f 1982`. + +The solution is based on the one at the +[Art of Problem Solving](https://artofproblemsolving.com/wiki/index.php/1982_IMO_Problems/Problem_1) +website. + +We prove the helper lemmas: +1. `f m + f n ≤ f(m + n)` `superadditive`. +2. `n * f(m) ≤ f(m * n)` `superhomogeneous`. +3. `a * f a + c * f d ≤ f (a * b + c * d)` `superlinear`, (derived from 1. and 2.). + +So we can establish on the one hand that `f 1980 ≤ 660`, +by observing that `660 * 1 = 660 * f3 ≤ f 1980 = f (660 * 3)`. + +On the other hand, we establish that `f 1980 ≥ 660` +from `5 * f 1980 + 33 * f 3 ≤ f (5 * 1980 + 33 * 1) = f 9999 = 3333`. + +We then conclude `f 1980 = 660` and then eventually determine that either +`f 1982 = 660` or `f 1982 = 661`. + +In the latter case we derive a contradiction, because if `f 1982 = 661` then +`3334 = 5 * f 1982 + 29 * f(3) + f(2) ≤ f (5 * 1982 + 29 * 3 + 2) = f 9999 = 3333`. +-/ + +namespace Imo1982Q1 + +structure IsGood (f : ℕ+ → ℕ) : Prop where + /-- The function satisfies the functional relation-/ + rel: ∀ m n : ℕ+, f (m + n) = f m + f n ∨ f (m + n) = f m + f n + 1 + f₂ : f 2 = 0 + hf₃ : 0 < f 3 + f_9999 : f 9999 = 3333 + +namespace IsGood + +variable {f : ℕ+ → ℕ} (hf : IsGood f) +include hf + +lemma f₁ : f 1 = 0 := by + have h : f 2 = 2 * f 1 ∨ f 2 = 2 * f 1 + 1 := by rw [two_mul]; exact hf.rel 1 1 + obtain h₁ | h₂ := hf.f₂ ▸ h + · rw [eq_comm, mul_eq_zero] at h₁ + apply h₁.resolve_left + norm_num + · cases Nat.succ_ne_zero _ h₂.symm + +lemma f₃ : f 3 = 1 := by + have h : f 3 = f 2 + f 1 ∨ f 3 = f 2 + f 1 + 1 := by apply hf.rel 2 1 + rw [hf.f₁, hf.f₂, add_zero, zero_add] at h + have not_left : ¬ f 3 = 0 := by apply ne_of_gt hf.hf₃ + rw [or_iff_right (not_left)] at h + exact h + +lemma superadditive {m n : ℕ+} : f m + f n ≤ f (m + n) := by + have h := hf.rel m n + rcases h with ( hl | hr ) + · rw [hl] + · rw [hr]; nth_rewrite 1 [← add_zero (f n), ← add_assoc]; apply add_le_add_right (by norm_num) + +lemma superhomogeneous {m n : ℕ+} : ↑n * f m ≤ f (n * m) := by + induction n using PNat.recOn + case p1 => simp + case hp n' ih => + calc + ↑(n' + 1) * f m = ↑n' * f m + f m := by rw [PNat.add_coe, add_mul, PNat.val_ofNat, one_mul] + _ ≤ f (n' * m) + f m := add_le_add_right ih (f m) + _ ≤ f (n' * m + m) := hf.superadditive + _ = f ((n' + 1) * m) := by congr; rw [add_mul, one_mul] + +lemma superlinear {a b c d : ℕ+} : a * f b + c * f d ≤ f (a * b + c * d) := + (add_le_add hf.superhomogeneous hf.superhomogeneous).trans hf.superadditive + +lemma le_mul_three_apply (n : ℕ+) : n ≤ f (3 * n) := by + rw [← mul_one (n : ℕ), ← hf.f₃, mul_comm 3] + exact hf.superhomogeneous + +lemma part_1 : 660 ≤ f (1980) := by + exact hf.le_mul_three_apply 660 + +lemma part_2 : f 1980 ≤ 660 := by + have h : 5 * f 1980 + 33 * f 3 ≤ 5 * 660 + 33 := by + calc (5 : ℕ+) * f 1980 + (33 : ℕ+) * f 3 ≤ f (5 * 1980 + 33 * 3) := by apply hf.superlinear + _ = f 9999 := by rfl + _ = 5 * 660 + 33 := by rw [hf.f_9999] + rw [hf.f₃, mul_one] at h + -- from 5 * f 1980 + 33 ≤ 5 * 660 + 33 we show f 1980 ≤ 660 + linarith + +end IsGood + +end Imo1982Q1 + +open Imo1982Q1 + +lemma imo1982_q1 {f : ℕ+ → ℕ} (hf : IsGood f) : f 1982 = 660 := by + have f_1980 := hf.part_2.antisymm hf.part_1 + have h : f 1982 = f 1980 + f 2 ∨ f 1982 = f 1980 + f 2 + 1 := hf.rel 1980 2 + rw [f_1980, hf.f₂, add_zero] at h + apply h.resolve_right + intro hr + suffices h : 3334 ≤ 3333 by norm_num at h + calc + 3334 = 5 * f 1982 + 29 * f 3 + f 2 := by rw [hf.f₃, hf.f₂, hr, add_zero, mul_one] + (5 : ℕ+) * f 1982 + (29 : ℕ+) * f 3 + f 2 ≤ f (5 * 1982 + 29 * 3) + f 2 := + add_le_add_right hf.superlinear _ + _ ≤ f (5 * 1982 + 29 * 3 + 2) := hf.superadditive + _ = 3333 := hf.f_9999 diff --git a/Archive/Imo/Imo1986Q5.lean b/Archive/Imo/Imo1986Q5.lean index 82fe5961c1647..e8ca0c898f1d5 100644 --- a/Archive/Imo/Imo1986Q5.lean +++ b/Archive/Imo/Imo1986Q5.lean @@ -71,7 +71,7 @@ theorem isGood_iff {f : ℝ≥0 → ℝ≥0} : IsGood f ↔ f = fun x ↦ 2 / (2 refine ⟨fun hf ↦ funext hf.map_eq, ?_⟩ rintro rfl constructor - case map_two => simp + case map_two => simp [tsub_self] case map_ne_zero => intro x hx; simpa [tsub_eq_zero_iff_le] case map_add_rev => intro x y diff --git a/Archive/Imo/Imo1994Q1.lean b/Archive/Imo/Imo1994Q1.lean index 6ea9e04e8862f..4420507ec7f59 100644 --- a/Archive/Imo/Imo1994Q1.lean +++ b/Archive/Imo/Imo1994Q1.lean @@ -43,7 +43,7 @@ end Imo1994Q1 open Imo1994Q1 -theorem imo1994_q1 (n : ℕ) (m : ℕ) (A : Finset ℕ) (hm : A.card = m + 1) +theorem imo1994_q1 (n : ℕ) (m : ℕ) (A : Finset ℕ) (hm : #A = m + 1) (hrange : ∀ a ∈ A, 0 < a ∧ a ≤ n) (hadd : ∀ a ∈ A, ∀ b ∈ A, a + b ≤ n → a + b ∈ A) : (m + 1) * (n + 1) ≤ 2 * ∑ x ∈ A, x := by diff --git a/Archive/Imo/Imo1998Q2.lean b/Archive/Imo/Imo1998Q2.lean index 367aec35fd5fc..db7ae35345496 100644 --- a/Archive/Imo/Imo1998Q2.lean +++ b/Archive/Imo/Imo1998Q2.lean @@ -5,7 +5,7 @@ Authors: Oliver Nash -/ import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Algebra.Order.Field.Basic -import Mathlib.Algebra.Ring.Int +import Mathlib.Algebra.Order.Field.Rat import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.Tactic.NoncommRing import Mathlib.Tactic.Ring diff --git a/Archive/Imo/Imo2013Q1.lean b/Archive/Imo/Imo2013Q1.lean index 42b43f937926c..295886d7e18ea 100644 --- a/Archive/Imo/Imo2013Q1.lean +++ b/Archive/Imo/Imo2013Q1.lean @@ -3,12 +3,11 @@ Copyright (c) 2021 David Renshaw. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Renshaw -/ -import Mathlib.Algebra.BigOperators.Pi -import Mathlib.Algebra.Order.Ring.Abs -import Mathlib.Data.PNat.Basic -import Mathlib.Tactic.Ring +import Mathlib.Algebra.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Field.Rat import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.Positivity.Basic +import Mathlib.Tactic.Ring /-! # IMO 2013 Q1 diff --git a/Archive/Imo/Imo2019Q4.lean b/Archive/Imo/Imo2019Q4.lean index e9b0ff74200d4..fe10780d6586f 100644 --- a/Archive/Imo/Imo2019Q4.lean +++ b/Archive/Imo/Imo2019Q4.lean @@ -5,7 +5,7 @@ Authors: Floris van Doorn -/ import Mathlib.Data.Nat.Factorial.BigOperators import Mathlib.Data.Nat.Multiplicity -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Int import Mathlib.Tactic.IntervalCases import Mathlib.Tactic.GCongr @@ -37,14 +37,14 @@ namespace Imo2019Q4 theorem upper_bound {k n : ℕ} (hk : k > 0) (h : (k ! : ℤ) = ∏ i ∈ range n, ((2:ℤ) ^ n - (2:ℤ) ^ i)) : n < 6 := by have h2 : ∑ i ∈ range n, i < k := by - suffices multiplicity 2 (k ! : ℤ) = ↑(∑ i ∈ range n, i : ℕ) by - rw [← PartENat.coe_lt_coe, ← this]; change multiplicity ((2 : ℕ) : ℤ) _ < _ - simp_rw [Int.natCast_multiplicity, multiplicity_two_factorial_lt hk.lt.ne.symm] - rw [h, multiplicity.Finset.prod Int.prime_two, Nat.cast_sum] + suffices emultiplicity 2 (k ! : ℤ) = ↑(∑ i ∈ range n, i : ℕ) by + rw [← Nat.cast_lt (α := ℕ∞), ← this]; change emultiplicity ((2 : ℕ) : ℤ) _ < _ + simp_rw [Int.natCast_emultiplicity, emultiplicity_two_factorial_lt hk.lt.ne.symm] + rw [h, Finset.emultiplicity_prod Int.prime_two, Nat.cast_sum] apply sum_congr rfl; intro i hi - rw [multiplicity_sub_of_gt, multiplicity_pow_self_of_prime Int.prime_two] - rwa [multiplicity_pow_self_of_prime Int.prime_two, multiplicity_pow_self_of_prime Int.prime_two, - PartENat.coe_lt_coe, ← mem_range] + rw [emultiplicity_sub_of_gt, emultiplicity_pow_self_of_prime Int.prime_two] + rwa [emultiplicity_pow_self_of_prime Int.prime_two, + emultiplicity_pow_self_of_prime Int.prime_two, Nat.cast_lt, ← mem_range] rw [← not_le]; intro hn apply _root_.ne_of_gt _ h calc ∏ i ∈ range n, ((2:ℤ) ^ n - (2:ℤ) ^ i) ≤ ∏ __ ∈ range n, (2:ℤ) ^ n := ?_ diff --git a/Archive/Imo/Imo2021Q1.lean b/Archive/Imo/Imo2021Q1.lean index 8cb685761f6bb..54f3cdf9ec531 100644 --- a/Archive/Imo/Imo2021Q1.lean +++ b/Archive/Imo/Imo2021Q1.lean @@ -10,7 +10,7 @@ import Mathlib.Tactic.Linarith /-! # IMO 2021 Q1 -Let `n≥100` be an integer. Ivan writes the numbers `n, n+1,..., 2n` each on different cards. +Let `n ≥ 100` be an integer. Ivan writes the numbers `n, n+1, ..., 2*n` each on different cards. He then shuffles these `n+1` cards, and divides them into two piles. Prove that at least one of the piles contains two cards such that the sum of their numbers is a perfect square. @@ -30,7 +30,7 @@ which can be solved to give b = 2 * l ^ 2 + 1 c = 2 * l ^ 2 + 4 * l -Therefore, it is enough to show that there exists a natural number l such that +Therefore, it is enough to show that there exists a natural number `l` such that `n ≤ 2 * l ^ 2 - 4 * l` and `2 * l ^ 2 + 4 * l ≤ 2 * n` for `n ≥ 100`. Then, by the Pigeonhole principle, at least two numbers in the triplet must lie in the same pile, @@ -41,13 +41,13 @@ open Finset namespace Imo2021Q1 --- We will later make use of the fact that there exists (l : ℕ) such that --- n ≤ 2 * l ^ 2 - 4 * l and 2 * l ^ 2 + 4 * l ≤ 2 * n for n ≥ 100. -theorem exists_numbers_in_interval (n : ℕ) (hn : 100 ≤ n) : +-- We will later make use of the fact that there exists `l : ℕ` such that +-- `n ≤ 2 * l ^ 2 - 4 * l` and `2 * l ^ 2 + 4 * l ≤ 2 * n` for `n ≥ 100`. +lemma exists_numbers_in_interval {n : ℕ} (hn : 100 ≤ n) : ∃ l : ℕ, n + 4 * l ≤ 2 * l ^ 2 ∧ 2 * l ^ 2 + 4 * l ≤ 2 * n := by have hn' : 1 ≤ Nat.sqrt (n + 1) := by rw [Nat.le_sqrt] - linarith + apply Nat.le_add_left have h₁ := Nat.sqrt_le' (n + 1) have h₂ := Nat.succ_le_succ_sqrt' (n + 1) have h₃ : 10 ≤ (n + 1).sqrt := by @@ -60,11 +60,11 @@ theorem exists_numbers_in_interval (n : ℕ) (hn : 100 ≤ n) : _ ≤ 2 * l ^ 2 := by nlinarith only [h₃] · linarith only [h₁] -theorem exists_triplet_summing_to_squares (n : ℕ) (hn : 100 ≤ n) : +lemma exists_triplet_summing_to_squares {n : ℕ} (hn : 100 ≤ n) : ∃ a b c : ℕ, n ≤ a ∧ a < b ∧ b < c ∧ c ≤ 2 * n ∧ - (∃ k : ℕ, a + b = k ^ 2) ∧ (∃ l : ℕ, c + a = l ^ 2) ∧ ∃ m : ℕ, b + c = m ^ 2 := by - obtain ⟨l, hl1, hl2⟩ := exists_numbers_in_interval n hn - have p : 1 < l := by contrapose! hl1; interval_cases l <;> linarith + IsSquare (a + b) ∧ IsSquare (c + a) ∧ IsSquare (b + c) := by + obtain ⟨l, hl1, hl2⟩ := exists_numbers_in_interval hn + have hl : 1 < l := by contrapose! hl1; interval_cases l <;> linarith have h₁ : 4 * l ≤ 2 * l ^ 2 := by linarith have h₂ : 1 ≤ 2 * l := by linarith refine ⟨2 * l ^ 2 - 4 * l, 2 * l ^ 2 + 1, 2 * l ^ 2 + 4 * l, ?_, ?_, ?_, @@ -74,15 +74,14 @@ theorem exists_triplet_summing_to_squares (n : ℕ) (hn : 100 ≤ n) : -- Since it will be more convenient to work with sets later on, we will translate the above claim -- to state that there always exists a set B ⊆ [n, 2n] of cardinality at least 3, such that each -- pair of pairwise unequal elements of B sums to a perfect square. -theorem exists_finset_3_le_card_with_pairs_summing_to_squares (n : ℕ) (hn : 100 ≤ n) : +lemma exists_finset_3_le_card_with_pairs_summing_to_squares {n : ℕ} (hn : 100 ≤ n) : ∃ B : Finset ℕ, - 2 * 1 + 1 ≤ B.card ∧ - (∀ a ∈ B, ∀ b ∈ B, a ≠ b → ∃ k, a + b = k ^ 2) ∧ + 2 * 1 + 1 ≤ #B ∧ + (∀ a ∈ B, ∀ b ∈ B, a ≠ b → IsSquare (a + b)) ∧ ∀ c ∈ B, n ≤ c ∧ c ≤ 2 * n := by - obtain ⟨a, b, c, hna, hab, hbc, hcn, h₁, h₂, h₃⟩ := exists_triplet_summing_to_squares n hn + obtain ⟨a, b, c, hna, hab, hbc, hcn, h₁, h₂, h₃⟩ := exists_triplet_summing_to_squares hn refine ⟨{a, b, c}, ?_, ?_, ?_⟩ - · suffices ({a, b, c} : Finset ℕ).card = 3 by rw [this] - suffices a ∉ {b, c} ∧ b ∉ {c} by + · suffices a ∉ {b, c} ∧ b ∉ {c} by rw [Finset.card_insert_of_not_mem this.1, Finset.card_insert_of_not_mem this.2, Finset.card_singleton] rw [Finset.mem_insert, Finset.mem_singleton, Finset.mem_singleton] @@ -105,22 +104,20 @@ open Imo2021Q1 theorem imo2021_q1 : ∀ n : ℕ, 100 ≤ n → ∀ A ⊆ Finset.Icc n (2 * n), - (∃ a ∈ A, ∃ b ∈ A, a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2) ∨ - ∃ a ∈ Finset.Icc n (2 * n) \ A, ∃ b ∈ Finset.Icc n (2 * n) \ A, - a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2 := by + (∃ a ∈ A, ∃ b ∈ A, a ≠ b ∧ IsSquare (a + b)) ∨ + ∃ a ∈ Finset.Icc n (2 * n) \ A, ∃ b ∈ Finset.Icc n (2 * n) \ A, a ≠ b ∧ IsSquare (a + b) := by intro n hn A hA -- For each n ∈ ℕ such that 100 ≤ n, there exists a pairwise unequal triplet {a, b, c} ⊆ [n, 2n] -- such that all pairwise sums are perfect squares. In practice, it will be easier to use -- a finite set B ⊆ [n, 2n] such that all pairwise unequal pairs of B sum to a perfect square -- noting that B has cardinality greater or equal to 3, by the explicit construction of the -- triplet {a, b, c} before. - obtain ⟨B, hB, h₁, h₂⟩ := exists_finset_3_le_card_with_pairs_summing_to_squares n hn + obtain ⟨B, hB, h₁, h₂⟩ := exists_finset_3_le_card_with_pairs_summing_to_squares hn have hBsub : B ⊆ Finset.Icc n (2 * n) := by intro c hcB; simpa only [Finset.mem_Icc] using h₂ c hcB - have hB' : 2 * 1 < (B ∩ (Finset.Icc n (2 * n) \ A) ∪ B ∩ A).card := by - rw [← inter_union_distrib_left, sdiff_union_self_eq_union, union_eq_left.2 hA, - inter_eq_left.2 hBsub] - exact Nat.succ_le_iff.mp hB + have hB' : 2 * 1 < #(B ∩ (Icc n (2 * n) \ A) ∪ B ∩ A) := by + rwa [← inter_union_distrib_left, sdiff_union_self_eq_union, union_eq_left.2 hA, + inter_eq_left.2 hBsub, ← Nat.succ_le_iff] -- Since B has cardinality greater or equal to 3, there must exist a subset C ⊆ B such that -- for any A ⊆ [n, 2n], either C ⊆ A or C ⊆ [n, 2n] \ A and C has cardinality greater -- or equal to 2. diff --git a/Archive/Imo/Imo2024Q1.lean b/Archive/Imo/Imo2024Q1.lean index 0e94469d1e0d9..00575c6abc94a 100644 --- a/Archive/Imo/Imo2024Q1.lean +++ b/Archive/Imo/Imo2024Q1.lean @@ -71,7 +71,7 @@ lemma mem_Ico_one_of_mem_Ioo (h : α ∈ Set.Ioo 0 2) : α ∈ Set.Ico 1 2 := by by_contra! hn have hr : 1 < ⌈α⁻¹⌉₊ := by rw [Nat.lt_ceil] - exact_mod_cast one_lt_inv h0 hn + exact_mod_cast (one_lt_inv₀ h0).2 hn apply hr.ne' suffices ⌈α⁻¹⌉₊ = (1 : ℤ) from mod_cast this apply Int.eq_one_of_dvd_one (Int.zero_le_ofNat _) @@ -153,7 +153,7 @@ lemma not_condition_of_mem_Ioo {α : ℝ} (h : α ∈ Set.Ioo 0 2) : ¬Condition convert hna using 1 field_simp rw [sub_eq_add_neg, ← le_sub_iff_add_le', neg_le, neg_sub] at hna' - rw [le_inv (by linarith) (mod_cast hn), ← not_lt] at hna' + rw [le_inv_comm₀ (by linarith) (mod_cast hn), ← not_lt] at hna' apply hna' exact_mod_cast Nat.lt_floor_add_one (_ : ℝ) diff --git a/Archive/MiuLanguage/DecisionNec.lean b/Archive/MiuLanguage/DecisionNec.lean index 694b599ac899d..3bd06ca5463c6 100644 --- a/Archive/MiuLanguage/DecisionNec.lean +++ b/Archive/MiuLanguage/DecisionNec.lean @@ -5,9 +5,7 @@ Authors: Gihan Marasingha -/ import Archive.MiuLanguage.Basic import Mathlib.Data.List.Basic -import Mathlib.Data.List.Count import Mathlib.Data.Nat.ModEq -import Mathlib.Tactic.Ring /-! # Decision procedure: necessary condition diff --git a/Archive/Sensitivity.lean b/Archive/Sensitivity.lean index 5cae8d062537c..ab52f935c6633 100644 --- a/Archive/Sensitivity.lean +++ b/Archive/Sensitivity.lean @@ -41,7 +41,7 @@ noncomputable section local notation "√" => Real.sqrt -open Function Bool LinearMap Fintype Module Module.DualBases +open Bool Finset Fintype Function LinearMap Module Module.DualBases /-! ### The hypercube @@ -357,7 +357,7 @@ local notation "Span" => Submodule.span ℝ natural number. -/ -local notation "Card " X:70 => Finset.card (Set.toFinset X) +local notation "Card " X:70 => #(Set.toFinset X) /-! In the following, `⊓` and `⊔` will denote intersection and sums of ℝ-subspaces, equipped with their subspace structures. The notations come from the general @@ -431,20 +431,19 @@ theorem huang_degree_theorem (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) : (norm_sum_le _ fun p => coeffs y p * _) _ = ∑ p ∈ (coeffs y).support, |coeffs y p| * ite (p ∈ q.adjacent) 1 0 := by simp only [abs_mul, f_matrix] - _ = ∑ p ∈ (coeffs y).support.filter q.adjacent, |coeffs y p| := by - simp [Finset.sum_filter]; rfl - _ ≤ ∑ _p ∈ (coeffs y).support.filter q.adjacent, |coeffs y q| := - (Finset.sum_le_sum fun p _ => H_max p) - _ = (((coeffs y).support.filter q.adjacent).card : ℝ) * |coeffs y q| := by - rw [Finset.sum_const, nsmul_eq_mul] - _ = (((coeffs y).support ∩ q.adjacent.toFinset).card : ℝ) * |coeffs y q| := by + _ = ∑ p ∈ (coeffs y).support with q.adjacent p, |coeffs y p| := by + simp [sum_filter]; rfl + _ ≤ ∑ p ∈ (coeffs y).support with q.adjacent p, |coeffs y q| := sum_le_sum fun p _ ↦ H_max p + _ = #{p ∈ (coeffs y).support | q.adjacent p} * |coeffs y q| := by + rw [sum_const, nsmul_eq_mul] + _ = #((coeffs y).support ∩ q.adjacent.toFinset) * |coeffs y q| := by congr with x; simp; rfl - _ ≤ Finset.card (H ∩ q.adjacent).toFinset * |ε q y| := by + _ ≤ #(H ∩ q.adjacent).toFinset * |ε q y| := by refine (mul_le_mul_right H_q_pos).2 ?_ norm_cast - apply Finset.card_le_card + apply card_le_card rw [Set.toFinset_inter] - convert Finset.inter_subset_inter_right coeffs_support + convert inter_subset_inter_right coeffs_support end diff --git a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean index df05d9256c5a5..884fb11207295 100644 --- a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean +++ b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean @@ -39,8 +39,8 @@ We then show the pair of labels must be unique. Now if there is no increasing se which is a contradiction if there are more than `r * s` elements. -/ theorem erdos_szekeres {r s n : ℕ} {f : Fin n → α} (hn : r * s < n) (hf : Injective f) : - (∃ t : Finset (Fin n), r < t.card ∧ StrictMonoOn f ↑t) ∨ - ∃ t : Finset (Fin n), s < t.card ∧ StrictAntiOn f ↑t := by + (∃ t : Finset (Fin n), r < #t ∧ StrictMonoOn f ↑t) ∨ + ∃ t : Finset (Fin n), s < #t ∧ StrictAntiOn f ↑t := by -- Given an index `i`, produce the set of increasing (resp., decreasing) subsequences which ends -- at `i`. let inc_sequences_ending_in : Fin n → Finset (Finset (Fin n)) := fun i => diff --git a/Archive/Wiedijk100Theorems/BallotProblem.lean b/Archive/Wiedijk100Theorems/BallotProblem.lean index 8fbd5b2ecf7d0..d11275c43b41a 100644 --- a/Archive/Wiedijk100Theorems/BallotProblem.lean +++ b/Archive/Wiedijk100Theorems/BallotProblem.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Bhavik Mehta, Kexing Ying. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Kexing Ying -/ -import Mathlib.Probability.CondCount +import Mathlib.Probability.UniformOn /-! # Ballot problem @@ -188,21 +188,21 @@ theorem count_countedSequence : ∀ p q : ℕ, count (countedSequence p q) = (p theorem first_vote_pos : ∀ p q, - 0 < p + q → condCount (countedSequence p q : Set (List ℤ)) {l | l.headI = 1} = p / (p + q) + 0 < p + q → uniformOn (countedSequence p q : Set (List ℤ)) {l | l.headI = 1} = p / (p + q) | p + 1, 0, _ => by - rw [counted_right_zero, condCount_singleton] + rw [counted_right_zero, uniformOn_singleton] simp [ENNReal.div_self _ _, List.replicate_succ] | 0, q + 1, _ => by - rw [counted_left_zero, condCount_singleton] + rw [counted_left_zero, uniformOn_singleton] simp only [List.replicate, Nat.add_eq, add_zero, mem_setOf_eq, List.headI_cons, Nat.cast_zero, ENNReal.zero_div, ite_eq_right_iff] decide | p + 1, q + 1, _ => by simp_rw [counted_succ_succ] - rw [← condCount_disjoint_union ((countedSequence_finite _ _).image _) + rw [← uniformOn_disjoint_union ((countedSequence_finite _ _).image _) ((countedSequence_finite _ _).image _) (disjoint_bits _ _), ← counted_succ_succ, - condCount_eq_one_of ((countedSequence_finite p (q + 1)).image _) + uniformOn_eq_one_of ((countedSequence_finite p (q + 1)).image _) ((countedSequence_nonempty _ _).image _)] · have : List.cons (-1) '' countedSequence (p + 1) q ∩ {l : List ℤ | l.headI = 1} = ∅ := by ext @@ -215,8 +215,8 @@ theorem first_vote_pos : List.cons 1 '' countedSequence p (q + 1) := by rw [inter_eq_right, counted_succ_succ] exact subset_union_left - rw [(condCount_eq_zero_iff <| (countedSequence_finite _ _).image _).2 this, condCount, - cond_apply _ list_int_measurableSet, hint, count_injective_image List.cons_injective, + rw [(uniformOn_eq_zero_iff <| (countedSequence_finite _ _).image _).2 this, uniformOn, + cond_apply list_int_measurableSet, hint, count_injective_image List.cons_injective, count_countedSequence, count_countedSequence, one_mul, zero_mul, add_zero, Nat.cast_add, Nat.cast_one, mul_comm, ← div_eq_mul_inv, ENNReal.div_eq_div_iff] · norm_cast @@ -230,17 +230,17 @@ theorem headI_mem_of_nonempty {α : Type*} [Inhabited α] : ∀ {l : List α} (_ | x::l, _ => List.mem_cons_self x l theorem first_vote_neg (p q : ℕ) (h : 0 < p + q) : - condCount (countedSequence p q) {l | l.headI = 1}ᶜ = q / (p + q) := by + uniformOn (countedSequence p q) {l | l.headI = 1}ᶜ = q / (p + q) := by have h' : (p + q : ℝ≥0∞) ≠ 0 := mod_cast h.ne' - have := condCount_compl + have := uniformOn_compl {l : List ℤ | l.headI = 1}ᶜ (countedSequence_finite p q) (countedSequence_nonempty p q) rw [compl_compl, first_vote_pos _ _ h] at this rw [ENNReal.eq_sub_of_add_eq _ this, ENNReal.eq_div_iff, ENNReal.mul_sub, mul_one, ENNReal.mul_div_cancel', ENNReal.add_sub_cancel_left] all_goals simp_all [ENNReal.div_eq_top] -theorem ballot_same (p : ℕ) : condCount (countedSequence (p + 1) (p + 1)) staysPositive = 0 := by - rw [condCount_eq_zero_iff (countedSequence_finite _ _), eq_empty_iff_forall_not_mem] +theorem ballot_same (p : ℕ) : uniformOn (countedSequence (p + 1) (p + 1)) staysPositive = 0 := by + rw [uniformOn_eq_zero_iff (countedSequence_finite _ _), eq_empty_iff_forall_not_mem] rintro x ⟨hx, t⟩ apply ne_of_gt (t x _ x.suffix_refl) · simpa using sum_of_mem_countedSequence hx @@ -248,9 +248,9 @@ theorem ballot_same (p : ℕ) : condCount (countedSequence (p + 1) (p + 1)) stay rw [length_of_mem_countedSequence hx] exact Nat.add_pos_left (Nat.succ_pos _) _ -theorem ballot_edge (p : ℕ) : condCount (countedSequence (p + 1) 0) staysPositive = 1 := by +theorem ballot_edge (p : ℕ) : uniformOn (countedSequence (p + 1) 0) staysPositive = 1 := by rw [counted_right_zero] - refine condCount_eq_one_of (finite_singleton _) (singleton_nonempty _) ?_ + refine uniformOn_eq_one_of (finite_singleton _) (singleton_nonempty _) ?_ refine singleton_subset_iff.2 fun l hl₁ hl₂ => List.sum_pos _ (fun x hx => ?_) hl₁ rw [List.eq_of_mem_replicate (hl₂.mem hx)] norm_num @@ -267,10 +267,10 @@ theorem countedSequence_int_pos_counted_succ_succ (p q : ℕ) : norm_num theorem ballot_pos (p q : ℕ) : - condCount (countedSequence (p + 1) (q + 1) ∩ {l | l.headI = 1}) staysPositive = - condCount (countedSequence p (q + 1)) staysPositive := by - rw [countedSequence_int_pos_counted_succ_succ, condCount, condCount, - cond_apply _ list_int_measurableSet, cond_apply _ list_int_measurableSet, + uniformOn (countedSequence (p + 1) (q + 1) ∩ {l | l.headI = 1}) staysPositive = + uniformOn (countedSequence p (q + 1)) staysPositive := by + rw [countedSequence_int_pos_counted_succ_succ, uniformOn, uniformOn, + cond_apply list_int_measurableSet, cond_apply list_int_measurableSet, count_injective_image List.cons_injective] congr 1 have : (1 :: ·) '' countedSequence p (q + 1) ∩ staysPositive = @@ -294,10 +294,10 @@ theorem countedSequence_int_neg_counted_succ_succ (p q : ℕ) : norm_num theorem ballot_neg (p q : ℕ) (qp : q < p) : - condCount (countedSequence (p + 1) (q + 1) ∩ {l | l.headI = 1}ᶜ) staysPositive = - condCount (countedSequence (p + 1) q) staysPositive := by - rw [countedSequence_int_neg_counted_succ_succ, condCount, condCount, - cond_apply _ list_int_measurableSet, cond_apply _ list_int_measurableSet, + uniformOn (countedSequence (p + 1) (q + 1) ∩ {l | l.headI = 1}ᶜ) staysPositive = + uniformOn (countedSequence (p + 1) q) staysPositive := by + rw [countedSequence_int_neg_counted_succ_succ, uniformOn, uniformOn, + cond_apply list_int_measurableSet, cond_apply list_int_measurableSet, count_injective_image List.cons_injective] congr 1 have : List.cons (-1) '' countedSequence (p + 1) q ∩ staysPositive = @@ -310,7 +310,7 @@ theorem ballot_neg (p q : ℕ) (qp : q < p) : exact List.cons_injective theorem ballot_problem' : - ∀ q p, q < p → (condCount (countedSequence p q) staysPositive).toReal = (p - q) / (p + q) := by + ∀ q p, q < p → (uniformOn (countedSequence p q) staysPositive).toReal = (p - q) / (p + q) := by classical apply Nat.diag_induction · intro p @@ -322,12 +322,12 @@ theorem ballot_problem' : rw [div_self] exact Nat.cast_add_one_ne_zero p · intro q p qp h₁ h₂ - haveI := condCount_isProbabilityMeasure + haveI := uniformOn_isProbabilityMeasure (countedSequence_finite p (q + 1)) (countedSequence_nonempty _ _) - haveI := condCount_isProbabilityMeasure + haveI := uniformOn_isProbabilityMeasure (countedSequence_finite (p + 1) q) (countedSequence_nonempty _ _) have h₃ : p + 1 + (q + 1) > 0 := Nat.add_pos_left (Nat.succ_pos _) _ - rw [← condCount_add_compl_eq {l : List ℤ | l.headI = 1} _ (countedSequence_finite _ _), + rw [← uniformOn_add_compl_eq {l : List ℤ | l.headI = 1} _ (countedSequence_finite _ _), first_vote_pos _ _ h₃, first_vote_neg _ _ h₃, ballot_pos, ballot_neg _ _ qp] rw [ENNReal.toReal_add, ENNReal.toReal_mul, ENNReal.toReal_mul, ← Nat.cast_add, ENNReal.toReal_div, ENNReal.toReal_div, ENNReal.toReal_nat, ENNReal.toReal_nat, @@ -349,12 +349,12 @@ theorem ballot_problem' : /-- The ballot problem. -/ theorem ballot_problem : - ∀ q p, q < p → condCount (countedSequence p q) staysPositive = (p - q) / (p + q) := by + ∀ q p, q < p → uniformOn (countedSequence p q) staysPositive = (p - q) / (p + q) := by intro q p qp haveI := - condCount_isProbabilityMeasure (countedSequence_finite p q) (countedSequence_nonempty _ _) + uniformOn_isProbabilityMeasure (countedSequence_finite p q) (countedSequence_nonempty _ _) have : - (condCount (countedSequence p q) staysPositive).toReal = + (uniformOn (countedSequence p q) staysPositive).toReal = ((p - q) / (p + q) : ℝ≥0∞).toReal := by rw [ballot_problem' q p qp] rw [ENNReal.toReal_div, ← Nat.cast_add, ← Nat.cast_add, ENNReal.toReal_nat, diff --git a/Archive/Wiedijk100Theorems/BirthdayProblem.lean b/Archive/Wiedijk100Theorems/BirthdayProblem.lean index 67d6fec9989c3..5919848caeb0a 100644 --- a/Archive/Wiedijk100Theorems/BirthdayProblem.lean +++ b/Archive/Wiedijk100Theorems/BirthdayProblem.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ import Mathlib.Data.Fintype.CardEmbedding -import Mathlib.Probability.CondCount +import Mathlib.Probability.UniformOn import Mathlib.Probability.Notation /-! @@ -52,15 +52,15 @@ instance : MeasurableSingletonClass (Fin m) := /- We then endow the space with a canonical measure, which is called ℙ. We define this to be the conditional counting measure. -/ noncomputable instance : MeasureSpace (Fin n → Fin m) := - ⟨condCount Set.univ⟩ + ⟨uniformOn Set.univ⟩ -- The canonical measure on `Fin n → Fin m` is a probability measure (except on an empty space). instance : IsProbabilityMeasure (ℙ : Measure (Fin n → Fin (m + 1))) := - condCount_isProbabilityMeasure Set.finite_univ Set.univ_nonempty + uniformOn_isProbabilityMeasure Set.finite_univ Set.univ_nonempty theorem FinFin.measure_apply {s : Set <| Fin n → Fin m} : ℙ s = |s.toFinite.toFinset| / ‖Fin n → Fin m‖ := by - erw [condCount_univ, Measure.count_apply_finite] + erw [uniformOn_univ, Measure.count_apply_finite] /-- **Birthday Problem**: first probabilistic interpretation. -/ theorem birthday_measure : @@ -76,12 +76,9 @@ theorem birthday_measure : · rw [Fintype.card_embedding_eq, Fintype.card_fin, Fintype.card_fin] rfl rw [this, ENNReal.lt_div_iff_mul_lt, mul_comm, mul_div, ENNReal.div_lt_iff] - rotate_left - iterate 2 right; norm_num - · decide - iterate 2 left; norm_num - simp only [Fintype.card_pi] - norm_num + all_goals + simp only [Fintype.card_pi, Fintype.card_fin, Finset.prod_const, Finset.card_univ] + norm_num end MeasureTheory diff --git a/Archive/Wiedijk100Theorems/BuffonsNeedle.lean b/Archive/Wiedijk100Theorems/BuffonsNeedle.lean index e27b8be9851f2..eff8809144258 100644 --- a/Archive/Wiedijk100Theorems/BuffonsNeedle.lean +++ b/Archive/Wiedijk100Theorems/BuffonsNeedle.lean @@ -4,11 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Enrico Z. Borba -/ -import Mathlib.Probability.Density -import Mathlib.Probability.Notation -import Mathlib.MeasureTheory.Constructions.Prod.Integral import Mathlib.Analysis.SpecialFunctions.Integrals +import Mathlib.MeasureTheory.Integral.Prod +import Mathlib.Probability.Density import Mathlib.Probability.Distributions.Uniform +import Mathlib.Probability.Notation /-! diff --git a/Archive/Wiedijk100Theorems/InverseTriangleSum.lean b/Archive/Wiedijk100Theorems/InverseTriangleSum.lean index 6a32da4b6aa4c..af36acfaa873d 100644 --- a/Archive/Wiedijk100Theorems/InverseTriangleSum.lean +++ b/Archive/Wiedijk100Theorems/InverseTriangleSum.lean @@ -27,10 +27,8 @@ open Finset /-- **Sum of the Reciprocals of the Triangular Numbers** -/ theorem Theorems100.inverse_triangle_sum : ∀ n, ∑ k ∈ range n, (2 : ℚ) / (k * (k + 1)) = if n = 0 then 0 else 2 - (2 : ℚ) / n := by - refine sum_range_induction _ _ (if_pos rfl) ?_ - rintro (_ | n) - · rw [if_neg, if_pos] <;> norm_num - simp only [Nat.succ_ne_zero, ↓reduceIte, Nat.cast_succ] - have A : (n + 1 + 1 : ℚ) ≠ 0 := by norm_cast + refine sum_range_induction _ _ rfl ?_ + rintro (_ | _) + · norm_num field_simp ring diff --git a/Archive/Wiedijk100Theorems/Partition.lean b/Archive/Wiedijk100Theorems/Partition.lean index 0ced772d9f68f..96f1877c186a5 100644 --- a/Archive/Wiedijk100Theorems/Partition.lean +++ b/Archive/Wiedijk100Theorems/Partition.lean @@ -87,7 +87,7 @@ or `ℝ`. def partialDistinctGF (m : ℕ) [CommSemiring α] := ∏ i ∈ range m, (1 + (X : PowerSeries α) ^ (i + 1)) -open Finset.HasAntidiagonal Finset +open Finset.HasAntidiagonal universe u variable {ι : Type u} @@ -134,9 +134,7 @@ theorem num_series' [Field α] (i : ℕ) : sub_eq_iff_eq_add, zero_add] symm split_ifs with h - · suffices - ((antidiagonal (n+1)).filter fun a : ℕ × ℕ => i + 1 ∣ a.fst ∧ a.snd = i + 1).card = - 1 by + · suffices #{a ∈ antidiagonal (n + 1) | i + 1 ∣ a.fst ∧ a.snd = i + 1} = 1 by simp only [Set.mem_setOf_eq]; convert congr_arg ((↑) : ℕ → α) this; norm_cast rw [card_eq_one] cases' h with p hp @@ -151,9 +149,7 @@ theorem num_series' [Field α] (i : ℕ) : match p with | 0 => rw [mul_zero] at hp; cases hp | p + 1 => rw [hp]; simp [mul_add] - · suffices - (filter (fun a : ℕ × ℕ => i + 1 ∣ a.fst ∧ a.snd = i + 1) (antidiagonal (n+1))).card = - 0 by + · suffices #{a ∈ antidiagonal (n + 1) | i + 1 ∣ a.fst ∧ a.snd = i + 1} = 0 by simp only [Set.mem_setOf_eq]; convert congr_arg ((↑) : ℕ → α) this; norm_cast rw [card_eq_zero] apply eq_empty_of_forall_not_mem @@ -169,11 +165,8 @@ def mkOdd : ℕ ↪ ℕ := -- The main workhorse of the partition theorem proof. theorem partialGF_prop (α : Type*) [CommSemiring α] (n : ℕ) (s : Finset ℕ) (hs : ∀ i ∈ s, 0 < i) (c : ℕ → Set ℕ) (hc : ∀ i, i ∉ s → 0 ∈ c i) : - (Finset.card - ((univ : Finset (Nat.Partition n)).filter fun p => - (∀ j, p.parts.count j ∈ c j) ∧ ∀ j ∈ p.parts, j ∈ s) : - α) = - (coeff α n) (∏ i ∈ s, indicatorSeries α ((· * i) '' c i)) := by + #{p : n.Partition | (∀ j, p.parts.count j ∈ c j) ∧ ∀ j ∈ p.parts, j ∈ s} = + coeff α n (∏ i ∈ s, indicatorSeries α ((· * i) '' c i)) := by simp_rw [coeff_prod, coeff_indicator, prod_boole, sum_boole] apply congr_arg simp only [mem_univ, forall_true_left, not_and, not_forall, exists_prop, @@ -216,7 +209,7 @@ theorem partialGF_prop (α : Type*) [CommSemiring α] (n : ℕ) (s : Finset ℕ) intro a; exact Nat.lt_irrefl 0 (hs 0 (hp₂.2 0 a)) intro a; exact Nat.lt_irrefl 0 (hs 0 (hp₁.2 0 a)) · rw [← mul_left_inj' hi] - rw [Function.funext_iff] at h + rw [funext_iff] at h exact h.2 i · simp only [φ, mem_filter, mem_finsuppAntidiag, mem_univ, exists_prop, true_and, and_assoc] rintro f ⟨hf, hf₃, hf₄⟩ @@ -257,11 +250,7 @@ theorem partialGF_prop (α : Type*) [CommSemiring α] (n : ℕ) (s : Finset ℕ) exact not_mem_mono hf'.2 h theorem partialOddGF_prop [Field α] (n m : ℕ) : - (Finset.card - ((univ : Finset (Nat.Partition n)).filter fun p => - ∀ j ∈ p.parts, j ∈ (range m).map mkOdd) : - α) = - coeff α n (partialOddGF m) := by + #{p : n.Partition | ∀ j ∈ p.parts, j ∈ (range m).map mkOdd} = coeff α n (partialOddGF m) := by rw [partialOddGF] convert partialGF_prop α n ((range m).map mkOdd) _ (fun _ => Set.univ) (fun _ _ => trivial) using 2 @@ -284,7 +273,7 @@ theorem partialOddGF_prop [Field α] (n m : ℕ) : /-- If m is big enough, the partial product's coefficient counts the number of odd partitions -/ theorem oddGF_prop [Field α] (n m : ℕ) (h : n < m * 2) : - (Finset.card (Nat.Partition.odds n) : α) = coeff α n (partialOddGF m) := by + #(Nat.Partition.odds n) = coeff α n (partialOddGF m) := by rw [← partialOddGF_prop, Nat.Partition.odds] congr with p apply forall₂_congr @@ -305,10 +294,8 @@ theorem oddGF_prop [Field α] (n m : ℕ) (h : n < m * 2) : apply Nat.two_not_dvd_two_mul_add_one theorem partialDistinctGF_prop [CommSemiring α] (n m : ℕ) : - (Finset.card - ((univ : Finset (Nat.Partition n)).filter fun p => - p.parts.Nodup ∧ ∀ j ∈ p.parts, j ∈ (range m).map ⟨Nat.succ, Nat.succ_injective⟩) : - α) = + #{p : n.Partition | + p.parts.Nodup ∧ ∀ j ∈ p.parts, j ∈ (range m).map ⟨Nat.succ, Nat.succ_injective⟩} = coeff α n (partialDistinctGF m) := by rw [partialDistinctGF] convert partialGF_prop α n @@ -328,8 +315,8 @@ theorem partialDistinctGF_prop [CommSemiring α] (n m : ℕ) : /-- If m is big enough, the partial product's coefficient counts the number of distinct partitions -/ theorem distinctGF_prop [CommSemiring α] (n m : ℕ) (h : n < m + 1) : - ((Nat.Partition.distincts n).card : α) = coeff α n (partialDistinctGF m) := by - erw [← partialDistinctGF_prop, Nat.Partition.distincts] + #(Nat.Partition.distincts n) = coeff α n (partialDistinctGF m) := by + rw [← partialDistinctGF_prop, Nat.Partition.distincts] congr with p apply (and_iff_left _).symm intro i hi @@ -388,10 +375,9 @@ theorem same_coeffs [Field α] (m n : ℕ) (h : n ≤ m) : rw [order_X_pow] exact mod_cast Nat.lt_succ_of_le (le_add_right h) -theorem partition_theorem (n : ℕ) : - (Nat.Partition.odds n).card = (Nat.Partition.distincts n).card := by +theorem partition_theorem (n : ℕ) : #(Nat.Partition.odds n) = #(Nat.Partition.distincts n) := by -- We need the counts to live in some field (which contains ℕ), so let's just use ℚ - suffices ((Nat.Partition.odds n).card : ℚ) = (Nat.Partition.distincts n).card from + suffices (#(Nat.Partition.odds n) : ℚ) = #(Nat.Partition.distincts n) from mod_cast this rw [distinctGF_prop n (n + 1) (by linarith)] rw [oddGF_prop n (n + 1) (by linarith)] diff --git a/Archive/Wiedijk100Theorems/PerfectNumbers.lean b/Archive/Wiedijk100Theorems/PerfectNumbers.lean index e23628d48b3e3..9769bcd84b18c 100644 --- a/Archive/Wiedijk100Theorems/PerfectNumbers.lean +++ b/Archive/Wiedijk100Theorems/PerfectNumbers.lean @@ -17,10 +17,10 @@ This file proves Theorem 70 from the [100 Theorems List](https://www.cs.ru.nl/~f The theorem characterizes even perfect numbers. Euclid proved that if `2 ^ (k + 1) - 1` is prime (these primes are known as Mersenne primes), - then `2 ^ k * 2 ^ (k + 1) - 1` is perfect. + then `2 ^ k * (2 ^ (k + 1) - 1)` is perfect. Euler proved the converse, that if `n` is even and perfect, then there exists `k` such that - `n = 2 ^ k * 2 ^ (k + 1) - 1` and `2 ^ (k + 1) - 1` is prime. + `n = 2 ^ k * (2 ^ (k + 1) - 1)` and `2 ^ (k + 1) - 1` is prime. ## References https://en.wikipedia.org/wiki/Euclid%E2%80%93Euler_theorem @@ -55,12 +55,12 @@ 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 := multiplicity.finite_nat_iff.2 ⟨Nat.prime_two.ne_one, hpos⟩ - cases' multiplicity.pow_multiplicity_dvd h with m hm - use (multiplicity 2 n).get h, m + have h := Nat.multiplicity_finite_iff.2 ⟨Nat.prime_two.ne_one, hpos⟩ + cases' pow_multiplicity_dvd 2 n with m hm + use multiplicity 2 n, m refine ⟨hm, ?_⟩ rw [even_iff_two_dvd] - have hg := multiplicity.is_greatest' h (Nat.lt_succ_self _) + have hg := h.not_pow_dvd_of_multiplicity_lt (Nat.lt_succ_self _) contrapose! hg rcases hg with ⟨k, rfl⟩ apply Dvd.intro k diff --git a/Archive/Wiedijk100Theorems/SolutionOfCubic.lean b/Archive/Wiedijk100Theorems/SolutionOfCubicQuartic.lean similarity index 67% rename from Archive/Wiedijk100Theorems/SolutionOfCubic.lean rename to Archive/Wiedijk100Theorems/SolutionOfCubicQuartic.lean index f61bda51e27dd..fba2b5ed1f999 100644 --- a/Archive/Wiedijk100Theorems/SolutionOfCubic.lean +++ b/Archive/Wiedijk100Theorems/SolutionOfCubicQuartic.lean @@ -1,32 +1,40 @@ /- Copyright (c) 2022 Jeoff Lee. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jeoff Lee +Authors: Jeoff Lee, Thomas Zhu -/ import Mathlib.Tactic.LinearCombination import Mathlib.RingTheory.Polynomial.Cyclotomic.Roots /-! -# The Solution of a Cubic +# The roots of cubic polynomials This file proves Theorem 37 from the [100 Theorems List](https://www.cs.ru.nl/~freek/100/). -In this file, we give the solutions to the cubic equation `a * x^3 + b * x^2 + c * x + d = 0` -over a field `K` that has characteristic neither 2 nor 3, that has a third primitive root of -unity, and in which certain other quantities admit square and cube roots. - -This is based on the [Cardano's Formula](https://en.wikipedia.org/wiki/Cubic_equation#Cardano's_formula). +We give the solutions to the cubic equation `a * x^3 + b * x^2 + c * x + d = 0` over a field `K` +that has characteristic neither 2 nor 3, that has a third primitive root of +unity, and in which certain other quantities admit square and cube roots. This is based on the +[Cardano's Formula](https://en.wikipedia.org/wiki/Cubic_equation#Cardano's_formula). ## Main statements -- `cubic_eq_zero_iff` : gives the roots of the cubic equation +- `cubic_eq_zero_iff`: gives the roots of the cubic equation where the discriminant `p = 3 * a * c - b^2` is nonzero. -- `cubic_eq_zero_iff_of_p_eq_zero` : gives the roots of the cubic equation +- `cubic_eq_zero_iff_of_p_eq_zero`: gives the roots of the cubic equation where the discriminant equals zero. +## Proof outline + +1. Given cubic $ax^3 + bx^2 + cx + d = 0$, we show it is equivalent to some "depressed cubic" + $y^3 + 3py - 2q = 0$ where $y = x + b / (3a)$, $p = (3ac - b^2) / (9a^2)$, and + $q = (9abc - 2b^3 - 27a^2d) / (54a^3)$ (`h₁` in `cubic_eq_zero_iff`). +2. When $p$ is zero, this is easily solved (`cubic_eq_zero_iff_of_p_eq_zero`). +3. Otherwise one can directly derive a factorization of the depressed cubic, in terms of some + primitive cube root of unity $\omega^3 = 1$ (`cubic_depressed_eq_zero_iff`). + ## References -Originally ported from Isabelle/HOL. The +The cubic formula was originally ported from Isabelle/HOL. The [original file](https://isabelle.in.tum.de/dist/library/HOL/HOL-ex/Cubic_Quartic.html) was written by Amine Chaieb. ## Tags @@ -41,13 +49,15 @@ section Field open Polynomial -variable {K : Type*} [Field K] (a b c d : K) {ω p q r s t : K} +variable {K : Type*} [Field K] (a b c d e : K) {ω p q r s t u v w x y : K} + +section Cubic theorem cube_root_of_unity_sum (hω : IsPrimitiveRoot ω 3) : 1 + ω + ω ^ 2 = 0 := by simpa [cyclotomic_prime, Finset.sum_range_succ] using hω.isRoot_cyclotomic (by decide) -/-- The roots of a monic cubic whose quadratic term is zero and whose discriminant is nonzero. -/ -theorem cubic_basic_eq_zero_iff (hω : IsPrimitiveRoot ω 3) (hp_nonzero : p ≠ 0) +/-- The roots of a monic cubic whose quadratic term is zero and whose linear term is nonzero. -/ +theorem cubic_depressed_eq_zero_iff (hω : IsPrimitiveRoot ω 3) (hp_nonzero : p ≠ 0) (hr : r ^ 2 = q ^ 2 + p ^ 3) (hs3 : s ^ 3 = q + r) (ht : t * s = p) (x : K) : x ^ 3 + 3 * p * x - 2 * q = 0 ↔ x = s - t ∨ x = s * ω - t * ω ^ 2 ∨ x = s * ω ^ 2 - t * ω := by have h₁ : ∀ x a₁ a₂ a₃ : K, x = a₁ ∨ x = a₂ ∨ x = a₃ ↔ (x - a₁) * (x - a₂) * (x - a₃) = 0 := by @@ -66,23 +76,6 @@ theorem cubic_basic_eq_zero_iff (hω : IsPrimitiveRoot ω 3) (hp_nonzero : p ≠ variable [Invertible (2 : K)] [Invertible (3 : K)] -/-- Roots of a monic cubic whose discriminant is nonzero. -/ -theorem cubic_monic_eq_zero_iff (hω : IsPrimitiveRoot ω 3) (hp : p = (3 * c - b ^ 2) / 9) - (hp_nonzero : p ≠ 0) (hq : q = (9 * b * c - 2 * b ^ 3 - 27 * d) / 54) - (hr : r ^ 2 = q ^ 2 + p ^ 3) (hs3 : s ^ 3 = q + r) (ht : t * s = p) (x : K) : - x ^ 3 + b * x ^ 2 + c * x + d = 0 ↔ - x = s - t - b / 3 ∨ x = s * ω - t * ω ^ 2 - b / 3 ∨ x = s * ω ^ 2 - t * ω - b / 3 := by - let y := x + b / 3 - have hi2 : (2 : K) ≠ 0 := Invertible.ne_zero _ - have hi3 : (3 : K) ≠ 0 := Invertible.ne_zero _ - have h9 : (9 : K) = 3 ^ 2 := by norm_num - have h54 : (54 : K) = 2 * 3 ^ 3 := by norm_num - have h₁ : x ^ 3 + b * x ^ 2 + c * x + d = y ^ 3 + 3 * p * y - 2 * q := by - rw [hp, hq] - field_simp [y, h9, h54]; ring - rw [h₁, cubic_basic_eq_zero_iff hω hp_nonzero hr hs3 ht y] - simp_rw [eq_sub_iff_add_eq] - /-- **The Solution of Cubic**. The roots of a cubic polynomial whose discriminant is nonzero. -/ theorem cubic_eq_zero_iff (ha : a ≠ 0) (hω : IsPrimitiveRoot ω 3) @@ -92,25 +85,17 @@ theorem cubic_eq_zero_iff (ha : a ≠ 0) (hω : IsPrimitiveRoot ω 3) a * x ^ 3 + b * x ^ 2 + c * x + d = 0 ↔ x = s - t - b / (3 * a) ∨ x = s * ω - t * ω ^ 2 - b / (3 * a) ∨ x = s * ω ^ 2 - t * ω - b / (3 * a) := by - have hi3 : (3 : K) ≠ 0 := Invertible.ne_zero _ + let y := x + b / (3 * a) have h9 : (9 : K) = 3 ^ 2 := by norm_num have h54 : (54 : K) = 2 * 3 ^ 3 := by norm_num - have h₁ : a * x ^ 3 + b * x ^ 2 + c * x + d - = a * (x ^ 3 + b / a * x ^ 2 + c / a * x + d / a) := by field_simp; ring + have h₁ : a * x ^ 3 + b * x ^ 2 + c * x + d = a * (y ^ 3 + 3 * p * y - 2 * q) := by + rw [hp, hq] + simp [field_simps, y, ha, h9, h54]; ring have h₂ : ∀ x, a * x = 0 ↔ x = 0 := by intro x; simp [ha] - have hp' : p = (3 * (c / a) - (b / a) ^ 2) / 9 := by field_simp [hp, h9]; ring_nf - have hq' : q = (9 * (b / a) * (c / a) - 2 * (b / a) ^ 3 - 27 * (d / a)) / 54 := by - rw [hq, h54] - simp [field_simps, ha] - ring_nf - rw [h₁, h₂, cubic_monic_eq_zero_iff (b / a) (c / a) (d / a) hω hp' hp_nonzero hq' hr hs3 ht x] - have h₄ := - calc - b / a / 3 = b / (a * 3) := by field_simp [ha] - _ = b / (3 * a) := by rw [mul_comm] - rw [h₄] + rw [h₁, h₂, cubic_depressed_eq_zero_iff hω hp_nonzero hr hs3 ht] + simp_rw [eq_sub_iff_add_eq] -/-- the solution of the cubic equation when p equals zero. -/ +/-- The solution of the cubic equation when p equals zero. -/ theorem cubic_eq_zero_iff_of_p_eq_zero (ha : a ≠ 0) (hω : IsPrimitiveRoot ω 3) (hpz : 3 * a * c - b ^ 2 = 0) (hq : q = (9 * a * b * c - 2 * b ^ 3 - 27 * a ^ 2 * d) / (54 * a ^ 3)) (hs3 : s ^ 3 = 2 * q) @@ -144,6 +129,8 @@ theorem cubic_eq_zero_iff_of_p_eq_zero (ha : a ≠ 0) (hω : IsPrimitiveRoot ω rw [h₁, h₂, h₃, h₄ (x + b / (3 * a))] ring_nf +end Cubic + end Field end Theorems100 diff --git a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean index e30881c10059f..914eeefba8a81 100644 --- a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean +++ b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean @@ -44,20 +44,17 @@ namespace Theorems100 /-- The primes in `(k, x]`. -/ -def P (x k : ℕ) : Finset ℕ := - Finset.filter (fun p => k < p ∧ Nat.Prime p) (range (x + 1)) +def P (x k : ℕ) : Finset ℕ := {p ∈ range (x + 1) | k < p ∧ p.Prime} /-- The union over those primes `p ∈ (k, x]` of the sets of `e < x` for which `e + 1` is a multiple of `p`, i.e., those `e < x` for which there is a prime `p ∈ (k, x]` that divides `e + 1`. -/ -def U (x k : ℕ) := - Finset.biUnion (P x k) (fun p => Finset.filter (fun e => p ∣ e + 1) (range x)) +def U (x k : ℕ) : Finset ℕ := (P x k).biUnion fun p ↦ {e ∈ range x | p ∣ e + 1} open Classical in /-- Those `e < x` for which `e + 1` is a product of powers of primes smaller than or equal to `k`. -/ -noncomputable def M (x k : ℕ) := - Finset.filter (fun e => ∀ p : ℕ, Nat.Prime p ∧ p ∣ e + 1 → p ≤ k) (range x) +noncomputable def M (x k : ℕ) : Finset ℕ := {e ∈ range x | ∀ p : ℕ, p.Prime ∧ p ∣ e + 1 → p ≤ k} /-- If the sum of the reciprocals of the primes converges, there exists a `k : ℕ` such that the sum of @@ -67,11 +64,11 @@ More precisely, for any `x : ℕ`, the sum of the reciprocals of the primes betw is less than 1/2. -/ theorem sum_lt_half_of_not_tendsto - (h : ¬Tendsto (fun n => ∑ p ∈ Finset.filter (fun p => Nat.Prime p) (range n), 1 / (p : ℝ)) + (h : ¬Tendsto (fun n => ∑ p ∈ range n with p.Prime, 1 / (p : ℝ)) atTop atTop) : ∃ k, ∀ x, ∑ p ∈ P x k, 1 / (p : ℝ) < 1 / 2 := by have h0 : - (fun n => ∑ p ∈ Finset.filter (fun p => Nat.Prime p) (range n), 1 / (p : ℝ)) = fun n => + (fun n => ∑ p ∈ range n with p.Prime, 1 / (p : ℝ)) = fun n => ∑ p ∈ range n, ite (Nat.Prime p) (1 / (p : ℝ)) 0 := by simp only [sum_filter] have hf : ∀ n : ℕ, 0 ≤ ite (Nat.Prime n) (1 / (n : ℝ)) 0 := by @@ -113,12 +110,12 @@ theorem range_sdiff_eq_biUnion {x k : ℕ} : range x \ M x k = U x k := by The number of `e < x` for which `e + 1` has a prime factor `p > k` is bounded by `x` times the sum of reciprocals of primes in `(k, x]`. -/ -theorem card_le_mul_sum {x k : ℕ} : (card (U x k) : ℝ) ≤ x * ∑ p ∈ P x k, 1 / (p : ℝ) := by - let P := Finset.filter (fun p => k < p ∧ Nat.Prime p) (range (x + 1)) - let N p := Finset.filter (fun e => p ∣ e + 1) (range x) - have h : card (Finset.biUnion P N) ≤ ∑ p ∈ P, card (N p) := card_biUnion_le +theorem card_le_mul_sum {x k : ℕ} : #(U x k) ≤ x * ∑ p ∈ P x k, 1 / (p : ℝ) := by + let P := {p ∈ range (x + 1) | k < p ∧ p.Prime} + let N p := {e ∈ range x | p ∣ e + 1} + have h : #(P.biUnion N) ≤ ∑ p ∈ P, #(N p) := card_biUnion_le calc - (card (Finset.biUnion P N) : ℝ) ≤ ∑ p ∈ P, (card (N p) : ℝ) := by assumption_mod_cast + (#(P.biUnion N) : ℝ) ≤ ∑ p ∈ P, (#(N p) : ℝ) := by assumption_mod_cast _ ≤ ∑ p ∈ P, x * (1 / (p : ℝ)) := sum_le_sum fun p _ => ?_ _ = x * ∑ p ∈ P, 1 / (p : ℝ) := by rw [mul_sum] simp only [N, mul_one_div, Nat.card_multiples, Nat.cast_div_le] @@ -127,9 +124,8 @@ theorem card_le_mul_sum {x k : ℕ} : (card (U x k) : ℝ) ≤ x * ∑ p ∈ P x The number of `e < x` for which `e + 1` is a squarefree product of primes smaller than or equal to `k` is bounded by `2 ^ k`, the number of subsets of `[1, k]`. -/ -theorem card_le_two_pow {x k : ℕ} : - card (Finset.filter (fun e => Squarefree (e + 1)) (M x k)) ≤ 2 ^ k := by - let M₁ := Finset.filter (fun e => Squarefree (e + 1)) (M x k) +theorem card_le_two_pow {x k : ℕ} : #{e ∈ M x k | Squarefree (e + 1)} ≤ 2 ^ k := by + let M₁ := {e ∈ M x k | Squarefree (e + 1)} let f s := (∏ a ∈ s, a) - 1 let K := powerset (image Nat.succ (range k)) -- Take `e` in `M x k`. If `e + 1` is squarefree, then it is the product of a subset of `[1, k]`. @@ -151,18 +147,18 @@ theorem card_le_two_pow {x k : ℕ} : -- The number of elements of `M x k` with `e + 1` squarefree is bounded by the number of subsets -- of `[1, k]`. calc - card M₁ ≤ card (image f K) := card_le_card h - _ ≤ card K := card_image_le - _ ≤ 2 ^ card (image Nat.succ (range k)) := by simp only [K, card_powerset]; rfl - _ ≤ 2 ^ card (range k) := pow_right_mono₀ one_le_two card_image_le + #M₁ ≤ #(image f K) := card_le_card h + _ ≤ #K := card_image_le + _ ≤ 2 ^ #(image Nat.succ (range k)) := by simp only [K, card_powerset]; rfl + _ ≤ 2 ^ #(range k) := pow_right_mono₀ one_le_two card_image_le _ = 2 ^ k := by rw [card_range k] /-- The number of `e < x` for which `e + 1` is a product of powers of primes smaller than or equal to `k` is bounded by `2 ^ k * nat.sqrt x`. -/ -theorem card_le_two_pow_mul_sqrt {x k : ℕ} : card (M x k) ≤ 2 ^ k * Nat.sqrt x := by - let M₁ := Finset.filter (fun e => Squarefree (e + 1)) (M x k) +theorem card_le_two_pow_mul_sqrt {x k : ℕ} : #(M x k) ≤ 2 ^ k * Nat.sqrt x := by + let M₁ := {e ∈ M x k | Squarefree (e + 1)} let M₂ := M (Nat.sqrt x) k let K := M₁ ×ˢ M₂ let f : ℕ × ℕ → ℕ := fun mn => (mn.2 + 1) ^ 2 * (mn.1 + 1) - 1 @@ -185,16 +181,16 @@ theorem card_le_two_pow_mul_sqrt {x k : ℕ} : card (M x k) ≤ 2 ^ k * Nat.sqrt _ ≤ (m + 1).sqrt := by simpa only [Nat.le_sqrt, pow_two] using Nat.le_of_dvd hm' hbm _ ≤ x.sqrt := Nat.sqrt_le_sqrt (Nat.succ_le_iff.mpr hm.1) · exact hm.2 p ⟨hp.1, hp.2.trans (Nat.dvd_of_pow_dvd one_le_two hbm)⟩ - have h2 : card M₂ ≤ Nat.sqrt x := by + have h2 : #M₂ ≤ Nat.sqrt x := by rw [← card_range (Nat.sqrt x)]; apply card_le_card; simp [M, M₂] calc - card (M x k) ≤ card (image f K) := card_le_card h1 - _ ≤ card K := card_image_le - _ = card M₁ * card M₂ := card_product M₁ M₂ + #(M x k) ≤ #(image f K) := card_le_card h1 + _ ≤ #K := card_image_le + _ = #M₁ * #M₂ := card_product M₁ M₂ _ ≤ 2 ^ k * x.sqrt := mul_le_mul' card_le_two_pow h2 theorem Real.tendsto_sum_one_div_prime_atTop : - Tendsto (fun n => ∑ p ∈ Finset.filter (fun p => Nat.Prime p) (range n), 1 / (p : ℝ)) + Tendsto (fun n => ∑ p ∈ range n with p.Prime, 1 / (p : ℝ)) atTop atTop := by -- Assume that the sum of the reciprocals of the primes converges. by_contra h @@ -209,10 +205,10 @@ theorem Real.tendsto_sum_one_div_prime_atTop : -- than or equal to `k`; set M' := M x k with hM' -- * `U`, the subset of those `e` for which there is a prime `p > k` that divides `e + 1`. - let P := Finset.filter (fun p => k < p ∧ Nat.Prime p) (range (x + 1)) + let P := {p ∈ range (x + 1) | k < p ∧ p.Prime} set U' := U x k with hU' -- This is indeed a partition, so `|U| + |M| = |range x| = x`. - have h2 : x = card U' + card M' := by + have h2 : x = #U' + #M' := by rw [← card_range x, hU', hM', ← range_sdiff_eq_biUnion] classical exact (card_sdiff_add_card_eq_card (Finset.filter_subset _ _)).symm @@ -220,17 +216,17 @@ theorem Real.tendsto_sum_one_div_prime_atTop : -- and for U, the inequality is strict. have h3 := calc - (card U' : ℝ) ≤ x * ∑ p ∈ P, 1 / (p : ℝ) := card_le_mul_sum + (#U' : ℝ) ≤ x * ∑ p ∈ P, 1 / (p : ℝ) := card_le_mul_sum _ < x * (1 / 2) := mul_lt_mul_of_pos_left (h1 x) (by norm_num [x]) _ = x / 2 := mul_one_div (x : ℝ) 2 have h4 := calc - (card M' : ℝ) ≤ 2 ^ k * x.sqrt := by exact mod_cast card_le_two_pow_mul_sqrt + (#M' : ℝ) ≤ 2 ^ k * x.sqrt := by exact mod_cast card_le_two_pow_mul_sqrt _ = 2 ^ k * (2 ^ (k + 1) : ℕ) := by rw [Nat.sqrt_eq] _ = x / 2 := by field_simp [x, mul_right_comm, ← pow_succ] refine lt_irrefl (x : ℝ) ?_ calc - (x : ℝ) = (card U' : ℝ) + (card M' : ℝ) := by assumption_mod_cast + (x : ℝ) = (#U' : ℝ) + (#M' : ℝ) := by assumption_mod_cast _ < x / 2 + x / 2 := add_lt_add_of_lt_of_le h3 h4 _ = x := add_halves (x : ℝ) diff --git a/Cache/Hashing.lean b/Cache/Hashing.lean index f50466b1c1980..5ebc53b76db24 100644 --- a/Cache/Hashing.lean +++ b/Cache/Hashing.lean @@ -73,9 +73,9 @@ def getRootHash : CacheM UInt64 := do pure id else pure ((← mathlibDepPath) / ·) - let hashs ← rootFiles.mapM fun path => + let hashes ← rootFiles.mapM fun path => hashFileContents <$> IO.FS.readFile (qualifyPath path) - return hash (hash Lean.githash :: hashs) + return hash (hash Lean.githash :: hashes) /-- Computes the hash of a file, which mixes: diff --git a/Counterexamples/CharPZeroNeCharZero.lean b/Counterexamples/CharPZeroNeCharZero.lean index 06e30c54a4a82..4edc1ed83998c 100644 --- a/Counterexamples/CharPZeroNeCharZero.lean +++ b/Counterexamples/CharPZeroNeCharZero.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa, Eric Wieser -/ -import Mathlib.Algebra.CharP.Basic +import Mathlib.Algebra.CharP.Lemmas import Mathlib.Algebra.PUnitInstances.Algebra /-! # `CharP R 0` and `CharZero R` need not coincide for semirings diff --git a/Counterexamples/CliffordAlgebraNotInjective.lean b/Counterexamples/CliffordAlgebraNotInjective.lean index c924cfe15c215..8670d40f77954 100644 --- a/Counterexamples/CliffordAlgebraNotInjective.lean +++ b/Counterexamples/CliffordAlgebraNotInjective.lean @@ -208,7 +208,7 @@ def Q : QuadraticForm K L := QuadraticMap.ofPolar (fun x => Quotient.liftOn' x Q' fun a b h => by - rw [Submodule.quotientRel_r_def] at h + rw [Submodule.quotientRel_def] at h suffices Q' (a - b) = 0 by rwa [Q'_sub, sub_eq_zero] at this apply Q'_zero_under_ideal (a - b) h) (fun a x => by diff --git a/Counterexamples/Phillips.lean b/Counterexamples/Phillips.lean index cf03d0dc7c250..177816e1a065b 100644 --- a/Counterexamples/Phillips.lean +++ b/Counterexamples/Phillips.lean @@ -385,7 +385,7 @@ section theorem norm_indicator_le_one (s : Set α) (x : α) : ‖(indicator s (1 : α → ℝ)) x‖ ≤ 1 := by - simp only [indicator, Pi.one_apply]; split_ifs <;> norm_num + simp only [Set.indicator, Pi.one_apply]; split_ifs <;> norm_num /-- A functional in the dual space of bounded functions gives rise to a bounded additive measure, by applying the functional to the indicator functions. -/ @@ -461,7 +461,7 @@ We need the continuum hypothesis to construct it. -/ -theorem sierpinski_pathological_family (Hcont : #ℝ = aleph 1) : +theorem sierpinski_pathological_family (Hcont : #ℝ = ℵ₁) : ∃ f : ℝ → Set ℝ, (∀ x, (univ \ f x).Countable) ∧ ∀ y, {x : ℝ | y ∈ f x}.Countable := by rcases Cardinal.ord_eq ℝ with ⟨r, hr, H⟩ refine ⟨fun x => {y | r x y}, fun x => ?_, fun y => ?_⟩ @@ -484,13 +484,13 @@ theorem sierpinski_pathological_family (Hcont : #ℝ = aleph 1) : /-- A family of sets in `ℝ` which only miss countably many points, but such that any point is contained in only countably many of them. -/ -def spf (Hcont : #ℝ = aleph 1) (x : ℝ) : Set ℝ := +def spf (Hcont : #ℝ = ℵ₁) (x : ℝ) : Set ℝ := (sierpinski_pathological_family Hcont).choose x -theorem countable_compl_spf (Hcont : #ℝ = aleph 1) (x : ℝ) : (univ \ spf Hcont x).Countable := +theorem countable_compl_spf (Hcont : #ℝ = ℵ₁) (x : ℝ) : (univ \ spf Hcont x).Countable := (sierpinski_pathological_family Hcont).choose_spec.1 x -theorem countable_spf_mem (Hcont : #ℝ = aleph 1) (y : ℝ) : {x | y ∈ spf Hcont x}.Countable := +theorem countable_spf_mem (Hcont : #ℝ = ℵ₁) (y : ℝ) : {x | y ∈ spf Hcont x}.Countable := (sierpinski_pathological_family Hcont).choose_spec.2 y /-! @@ -510,10 +510,10 @@ which is large (it has countable complement), as in the Sierpinski pathological /-- A family of bounded functions `f_x` from `ℝ` (seen with the discrete topology) to `ℝ` (in fact taking values in `{0, 1}`), indexed by a real parameter `x`, corresponding to the characteristic functions of the different fibers of the Sierpinski pathological family -/ -def f (Hcont : #ℝ = aleph 1) (x : ℝ) : DiscreteCopy ℝ →ᵇ ℝ := +def f (Hcont : #ℝ = ℵ₁) (x : ℝ) : DiscreteCopy ℝ →ᵇ ℝ := ofNormedAddCommGroupDiscrete (indicator (spf Hcont x) 1) 1 (norm_indicator_le_one _) -theorem apply_f_eq_continuousPart (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) +theorem apply_f_eq_continuousPart (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) (x : ℝ) (hx : φ.toBoundedAdditiveMeasure.discreteSupport ∩ spf Hcont x = ∅) : φ (f Hcont x) = φ.toBoundedAdditiveMeasure.continuousPart univ := by set ψ := φ.toBoundedAdditiveMeasure @@ -523,7 +523,7 @@ theorem apply_f_eq_continuousPart (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ψ.continuousPart.additive _ _ disjoint_sdiff_self_right, ψ.continuousPart_apply_eq_zero_of_countable _ (countable_compl_spf Hcont x), add_zero] -theorem countable_ne (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : +theorem countable_ne (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : {x | φ.toBoundedAdditiveMeasure.continuousPart univ ≠ φ (f Hcont x)}.Countable := by have A : {x | φ.toBoundedAdditiveMeasure.continuousPart univ ≠ φ (f Hcont x)} ⊆ @@ -543,7 +543,7 @@ theorem countable_ne (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ apply Countable.mono (Subset.trans A B) exact Countable.biUnion (countable_discreteSupport _) fun a _ => countable_spf_mem Hcont a -theorem comp_ae_eq_const (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : +theorem comp_ae_eq_const (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : ∀ᵐ x ∂volume.restrict (Icc (0 : ℝ) 1), φ.toBoundedAdditiveMeasure.continuousPart univ = φ (f Hcont x) := by apply ae_restrict_of_ae @@ -551,7 +551,7 @@ theorem comp_ae_eq_const (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ intro x simp only [imp_self, mem_setOf_eq, mem_compl_iff] -theorem integrable_comp (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : +theorem integrable_comp (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : IntegrableOn (fun x => φ (f Hcont x)) (Icc 0 1) := by have : IntegrableOn (fun _ => φ.toBoundedAdditiveMeasure.continuousPart univ) (Icc (0 : ℝ) 1) @@ -559,7 +559,7 @@ theorem integrable_comp (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ simp [integrableOn_const] apply Integrable.congr this (comp_ae_eq_const Hcont φ) -theorem integral_comp (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : +theorem integral_comp (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : ∫ x in Icc 0 1, φ (f Hcont x) = φ.toBoundedAdditiveMeasure.continuousPart univ := by rw [← integral_congr_ae (comp_ae_eq_const Hcont φ)] simp @@ -574,18 +574,18 @@ no Pettis integral. example : CompleteSpace (DiscreteCopy ℝ →ᵇ ℝ) := by infer_instance /-- The function `f Hcont : ℝ → (DiscreteCopy ℝ →ᵇ ℝ)` is scalarly measurable. -/ -theorem measurable_comp (Hcont : #ℝ = aleph 1) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : +theorem measurable_comp (Hcont : #ℝ = ℵ₁) (φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ) : Measurable fun x => φ (f Hcont x) := by have : Measurable fun _ : ℝ => φ.toBoundedAdditiveMeasure.continuousPart univ := measurable_const refine this.measurable_of_countable_ne ?_ exact countable_ne Hcont φ /-- The function `f Hcont : ℝ → (DiscreteCopy ℝ →ᵇ ℝ)` is uniformly bounded by `1` in norm. -/ -theorem norm_bound (Hcont : #ℝ = aleph 1) (x : ℝ) : ‖f Hcont x‖ ≤ 1 := +theorem norm_bound (Hcont : #ℝ = ℵ₁) (x : ℝ) : ‖f Hcont x‖ ≤ 1 := norm_ofNormedAddCommGroup_le _ zero_le_one (norm_indicator_le_one _) /-- The function `f Hcont : ℝ → (DiscreteCopy ℝ →ᵇ ℝ)` has no Pettis integral. -/ -theorem no_pettis_integral (Hcont : #ℝ = aleph 1) : +theorem no_pettis_integral (Hcont : #ℝ = ℵ₁) : ¬∃ g : DiscreteCopy ℝ →ᵇ ℝ, ∀ φ : (DiscreteCopy ℝ →ᵇ ℝ) →L[ℝ] ℝ, ∫ x in Icc 0 1, φ (f Hcont x) = φ g := by rintro ⟨g, h⟩ diff --git a/Counterexamples/SorgenfreyLine.lean b/Counterexamples/SorgenfreyLine.lean index dc20c635dcc46..bdebf6085e105 100644 --- a/Counterexamples/SorgenfreyLine.lean +++ b/Counterexamples/SorgenfreyLine.lean @@ -110,7 +110,7 @@ theorem nhds_countable_basis_Ico_inv_pnat (a : ℝₗ) : theorem nhds_antitone_basis_Ico_inv_pnat (a : ℝₗ) : (𝓝 a).HasAntitoneBasis fun n : ℕ+ => Ico a (a + (n : ℝₗ)⁻¹) := ⟨nhds_basis_Ico_inv_pnat a, monotone_const.Ico <| Antitone.const_add - (fun k _l hkl => inv_le_inv_of_le (Nat.cast_pos.2 k.2) + (fun k _l hkl => inv_anti₀ (Nat.cast_pos.2 k.2) (Nat.mono_cast <| Subtype.coe_le_coe.2 hkl)) _⟩ theorem isOpen_iff {s : Set ℝₗ} : IsOpen s ↔ ∀ x ∈ s, ∃ y > x, Ico x y ⊆ s := diff --git a/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean b/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean index 703b8f0eded4e..b13cc110a5128 100644 --- a/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean +++ b/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean @@ -28,8 +28,8 @@ nontrivial ring `R` and the additive group `G` with a torsion element can be any Besides this example, we also address a comment in `Data.Finsupp.Lex` to the effect that the proof that addition is monotone on `α →₀ N` uses that it is *strictly* monotone on `N`. -The specific statement is about `Finsupp.Lex.covariantClass_lt_left` and its analogue -`Finsupp.Lex.covariantClass_le_right`. We do not need two separate counterexamples, since the +The specific statement is about `Finsupp.Lex.addLeftStrictMono` and its analogue +`Finsupp.Lex.addRightStrictMono`. We do not need two separate counterexamples, since the operation is commutative. The example is very simple. Let `F = {0, 1}` with order determined by `0 < 1` and absorbing @@ -142,9 +142,9 @@ elab "guard_decl" na:ident mod:ident : command => do let .some mdni := env.getModuleIdx? mdn | throwError "the module {mod} is not imported!" unless dcli = mdni do throwError "instance {na} is no longer in {mod}." -guard_decl Finsupp.Lex.covariantClass_le_left Mathlib.Data.Finsupp.Lex +guard_decl Finsupp.Lex.addLeftMono Mathlib.Data.Finsupp.Lex -guard_decl Finsupp.Lex.covariantClass_le_right Mathlib.Data.Finsupp.Lex +guard_decl Finsupp.Lex.addRightMono Mathlib.Data.Finsupp.Lex namespace F @@ -182,20 +182,20 @@ instance : AddCommMonoid F where add_comm := by boom nsmul := nsmulRec -/-- The `CovariantClass`es asserting monotonicity of addition hold for `F`. -/ -instance covariantClass_add_le : CovariantClass F F (· + ·) (· ≤ ·) := +/-- The `AddLeftMono`es asserting monotonicity of addition hold for `F`. -/ +instance addLeftMono : AddLeftMono F := ⟨by boom⟩ -example : CovariantClass F F (Function.swap (· + ·)) (· ≤ ·) := by infer_instance +example : AddRightMono F := by infer_instance /-- The following examples show that `F` has all the typeclasses used by -`Finsupp.Lex.covariantClass_le_left`... -/ +`Finsupp.Lex.addLeftStrictMono`... -/ example : LinearOrder F := by infer_instance example : AddMonoid F := by infer_instance /-- ... except for the strict monotonicity of addition, the crux of the matter. -/ -example : ¬CovariantClass F F (· + ·) (· < ·) := fun h => +example : ¬AddLeftStrictMono F := fun h => lt_irrefl 1 <| (h.elim : Covariant F F (· + ·) (· < ·)) 1 z01 /-- A few `simp`-lemmas to take care of trivialities in the proof of the example below. -/ @@ -220,8 +220,8 @@ theorem f110 : ofLex (Finsupp.single (1 : F) (1 : F)) 0 = 0 := /-- Here we see that (not-necessarily strict) monotonicity of addition on `Lex (F →₀ F)` is not a consequence of monotonicity of addition on `F`. Strict monotonicity of addition on `F` is -enough and is the content of `Finsupp.Lex.covariantClass_le_left`. -/ -example : ¬CovariantClass (Lex (F →₀ F)) (Lex (F →₀ F)) (· + ·) (· ≤ ·) := by +enough and is the content of `Finsupp.Lex.addLeftStrictMono`. -/ +example : ¬AddLeftMono (Lex (F →₀ F)) := by rintro ⟨h⟩ refine (not_lt (α := Lex (F →₀ F))).mpr (@h (Finsupp.single (0 : F) (1 : F)) (Finsupp.single 1 1) (Finsupp.single 0 1) ?_) ⟨1, ?_⟩ diff --git a/LongestPole/Main.lean b/LongestPole/Main.lean index b4abb23680785..65c21307d676d 100644 --- a/LongestPole/Main.lean +++ b/LongestPole/Main.lean @@ -54,7 +54,7 @@ def RunResponse.instructions (response : RunResponse) : for m in response.run.result.measurements do let n := m.dimension.benchmark if n.startsWith "~" then - r := r.insert (n.drop 1).toName m.value + r := r.insert (n.drop 1).toName (m.value/10^6) return r def instructions (run : String) : IO (NameMap Float) := @@ -116,6 +116,18 @@ def Float.toStringDecimals (r : Float) (digits : Nat) : String := | [a, b] => a ++ "." ++ b.take digits | _ => r.toString +open System in +-- Lines of code is obviously a `Nat` not a `Float`, +-- but we're using it here as a very rough proxy for instruction count. +def countLOC (modules : List Name) : IO (NameMap Float) := do + let mut r := {} + for m in modules do + if let .some fp ← Lean.SearchPath.findModuleWithExt [s!".{FilePath.pathSeparator}"] "lean" m + then + let src ← IO.FS.readFile fp + r := r.insert m (src.toList.count '\n').toFloat + return r + /-- Implementation of the longest pole command line program. -/ def longestPoleCLI (args : Cli.Parsed) : IO UInt32 := do let to ← match args.flag? "to" with @@ -126,7 +138,10 @@ def longestPoleCLI (args : Cli.Parsed) : IO UInt32 := do let graph := env.importGraph let sha ← headSha IO.eprintln s!"Analyzing {to} at {sha}" - let instructions ← SpeedCenterAPI.instructions (sha) + let instructions ← if args.hasFlag "loc" then + countLOC (graph.toList.map (·.1)) + else + SpeedCenterAPI.instructions sha let cumulative := cumulativeInstructions instructions graph let total := totalInstructions instructions graph let slowest := slowestParents cumulative graph @@ -138,10 +153,11 @@ def longestPoleCLI (args : Cli.Parsed) : IO UInt32 := do let c := cumulative.find! n' let t := total.find! n' let r := (t / c).toStringDecimals 2 - table := table.push #[n.get!.toString, toString (i/10^6 |>.toUInt64), toString (c/10^6 |>.toUInt64), r] + table := table.push #[n.get!.toString, toString i.toUInt64, toString c.toUInt64, r] n := slowest.find? n' + let instructionsHeader := if args.hasFlag "loc" then "LoC" else "instructions" IO.println (formatTable - #["file", "instructions", "cumulative", "parallelism"] + #["file", instructionsHeader, "cumulative", "parallelism"] table #[Alignment.left, Alignment.right, Alignment.right, Alignment.center]) return 0 @@ -157,6 +173,7 @@ def pole : Cmd := `[Cli| FLAGS: to : ModuleName; "Calculate the longest pole to the specified module." + loc; "Use lines of code instead of speedcenter instruction counts." ] /-- `lake exe pole` -/ diff --git a/LongestPole/Rectangles.lean b/LongestPole/Rectangles.lean new file mode 100644 index 0000000000000..bc1cb181c5269 --- /dev/null +++ b/LongestPole/Rectangles.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2024 Lean FRO. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ + +/-! +# Finding the maximal rectangles in a list of points. +-/ + +/-- +A rectangle `r` is a product of the left-closed, right-open intervals +`[r.left, r.right) × [r.bottom, r.top)`, whose corners are indexed by natural numbers. +-/ +structure Rectangle where + left : Nat + right : Nat + bottom : Nat + top : Nat +deriving DecidableEq, Repr + +namespace Rectangle + +def width (r : Rectangle) : Nat := r.right - r.left +def height (r : Rectangle) : Nat := r.top - r.bottom + +def toString (r : Rectangle) : String := + s!"[{r.left}, {r.right}) × [{r.bottom}, {r.top})" + +instance : ToString Rectangle where + toString := toString + +instance instPointMembership : Membership (Nat × Nat) Rectangle where + mem r x := r.left ≤ x.1 ∧ x.1 < r.right ∧ r.bottom ≤ x.2 ∧ x.2 < r.top + +instance (x : Nat × Nat) (r : Rectangle) : Decidable (x ∈ r) := by + dsimp [Membership.mem] + infer_instance + +/-- +We say `r₁ ≤ r₂` if and only if every point in `r₁` is contained in `r₂`. +-/ +instance instLE : LE Rectangle where + le r₁ r₂ := r₁.width = 0 ∨ r₁.height = 0 ∨ ((r₁.left, r₁.bottom) ∈ r₂ ∧ (r₁.right - 1, r₁.top - 1) ∈ r₂) + +instance : DecidableRel ((· : Rectangle) ≤ ·) := by + dsimp [LE.le, instLE] + infer_instance + +instance : Membership Rectangle (List (Nat × Nat)) where + mem xs r := (List.range' r.left r.width).all fun x => (List.range' r.bottom r.height).all fun y => (x, y) ∈ xs + +instance (r : Rectangle) (xs : List (Nat × Nat)) : Decidable (r ∈ xs) := by + dsimp [Membership.mem] + infer_instance + +/-- +Given a rectangle `r`, return the up to four four rectangles obtained from `r` by +- shifting the bottom left corner one coordinate to the left resp. bottom (if possible), or +- shifting the top right corner one coordinate to the right resp. top. +-/ +def expansions (r : Rectangle) : List Rectangle := + (if r.left = 0 then [] else [{ r with left := r.left - 1 }]) ++ + (if r.bottom = 0 then [] else [{ r with bottom := r.bottom - 1 }]) ++ + [{ r with right := r.right + 1 }, { r with top := r.top + 1 }] + +def area (r : Rectangle) : Nat := r.width * r.height + +/-- +The number of points in `r`, weighted by the function `w`. +-/ +def weightedArea (r : Rectangle) (w : Nat × Nat → Nat) : Nat := + Nat.sum <| + (List.range' r.left r.width).bind fun x => (List.range' r.bottom r.height).map fun y => w (x, y) + +end Rectangle + +/-- Find all (inclusion-)maximal rectangles contained within `xs`. -/ +partial def maximalRectangles (xs : List (Nat × Nat)) : List Rectangle := + go [] (xs.map fun (x, y) => Rectangle.mk x (x+1) y (y+1)) +where + go (maximal : List Rectangle) (queue : List Rectangle) : List Rectangle := + match queue with + | [] => maximal + | r :: rs => + if maximal.any (r ≤ ·) then + go maximal rs + else + match r.expansions.filter (· ∈ xs) with + | [] => go (r :: maximal) rs + | rs' => go maximal (rs' ++ rs) + +/-- +info: [{ left := 2, right := 3, bottom := 0, top := 3 }, + { left := 0, right := 1, bottom := 0, top := 3 }, + { left := 0, right := 3, bottom := 0, top := 2 }] +-/ +#guard_msgs in +#eval maximalRectangles [(0, 0), (1, 0), (0, 1), (1, 1), (2, 0), (0, 2), (2, 1), (2, 2)] diff --git a/LongestPole/Unused.lean b/LongestPole/Unused.lean new file mode 100644 index 0000000000000..6633c405110b9 --- /dev/null +++ b/LongestPole/Unused.lean @@ -0,0 +1,131 @@ +/- +Copyright (c) 2024 Lean FRO. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ +import Cli +import Batteries.Data.List.Basic +import ImportGraph.Imports +import LongestPole.Rectangles +import Mathlib.Util.FormatTable + +/-! +# `lake exe unused` + +A tool for library-scale analysis of unused imports. + +`lake exe unused module_1 module_2 ... module_n` will generate a markdown table with rows and +columns indexed 1 through n, with an `x` in `(i, j)` if `module_i` transitively imports `module_j`, +but makes no direct use of the declarations there. + +(This is often an indication that some *intermediate* file `module_k` could be split into two parts, +one that needs `module_j`, and another that is needed by `module_i`, thereby removing the transitive +import of `module_j` into `module_i`.) + +The tool further identifies large rectangles of `x`s in this table, and suggests `lake exe graph` +commands that can show the dependency structure from the unused import up to the earliest file which +"unnecessarily" transitively imports it. + +`scripts/unused_in_pole.sh module` (or no argument for all of Mathlib), will calculate the current +longest pole in Mathlib (note for this you need to be on a commit on which the speed center has +run), and then feed that list of modules into `lake exe unused`. + +Demo video at https://youtu.be/PVj_FHGwhUI +-/ + + +open Cli +open Lean + +/-- Count the number of declarations in each module. -/ +def countDecls (modules : Array Name) : CoreM (Array Nat) := do + let env ← getEnv + let mut counts := Array.mkArray modules.size 0 + let moduleIndices := Std.HashMap.ofList <| modules.zipWithIndex.toList + for (n, _) in env.constants.map₁ do + if ! n.isInternal then + if let some m := env.getModuleFor? n then + if let some i := moduleIndices[m]? then + counts := counts.modify i (· + 1) + return counts + +/-- Implementation of `lake exe unused` -/ +def unusedImportsCLI (args : Cli.Parsed) : IO UInt32 := do + let output := args.flag! "output" |>.as! String + let n := args.flag! "n" |>.as! Nat + let modules := (args.variableArgsAs! ModuleName).toList + if modules.isEmpty then + IO.eprintln + "No modules specified, please specify at least two modules on the command line." + return 1 + + -- Should we sort the modules? + -- The code below assumes that it is "deeper files first", as reported by `lake exe pole`. + + searchPathRef.set compile_time_search_path% + let (unused, _) ← unsafe withImportModules #[{module := `Mathlib}] {} (trustLevel := 1024) + fun env => Prod.fst <$> Core.CoreM.toIO + (ctx := { fileName := "", fileMap := default }) (s := { env := env }) do + let unused ← unusedTransitiveImports modules + let counts ← countDecls modules.toArray + return (unused, counts) + + let headings := #["#", "module"] ++ ((List.range' 1 modules.length).map toString) + let rows := modules.mapIdx fun i m => + let data := (unused.lookup m).getD [] + #[toString (i + 1), m.toString] ++ + modules.map fun m' => if data.contains m' then "x" else "" + IO.println s!"Writing table to {output}." + IO.FS.writeFile output (formatTable headings rows.toArray) + + let data := unused.bind fun (m, u) => u.map fun n => (modules.indexOf m, modules.indexOf n) + let rectangles := maximalRectangles data + |>.map (fun r => (r, r.area)) + -- Prefer rectangles with larger areas. + |>.mergeSort (fun r₁ r₂ => r₁.2 > r₂.2) + -- The `lake exe graph` command we print only depends on the top-right corner, so deduplicate. + |>.pwFilter (fun r₁ r₂ => (r₁.1.top, r₂.1.right) ≠ (r₂.1.top, r₁.1.right)) + |>.take n + + for (i, (r, _)) in rectangles.enum do + -- We use `--from top` so that the graph starts at the module immediately *before* + -- the block of unused imports. This is useful for deciding how a split should be made. + -- We use `--to (right-1)` so that the graph ends at the earliest of the modules + -- which do not make use of any of the unused block. + -- Note that this means that the later modules which do not use the block are not displayed, + -- and in particular it is not possible to see from the graph the size of the later block + -- which makes no use of the earlier unused block. + -- Perhaps modifying `to` to allow multiple modules, and highlighting all of these in some way, + -- would be a useful addition. + let from_idx := min r.top (modules.length - 1) + let to_idx := r.right - 1 + IO.println + s!"lake exe graph --from {modules[from_idx]!} --to {modules[to_idx]!} unused{i}.pdf" + + return 0 + +/-- Setting up command line options and help text for `lake exe unused`. -/ +def unused : Cmd := `[Cli| + unused VIA unusedImportsCLI; ["0.0.1"] + "Determine unused imports amongst a given set of modules.\n\ + Produces a table with rows and columns indexed by the specified modules,\n\ + with an 'x' in row A, column B if module A imports module B,\n\ + but does not make any transitive use of constants defined in B. + This table is written to `unused.md`, and a number of `lake exe graph` commands are printed + to visualize the largest rectangles of unused imports." + + FLAGS: + output : String; "Write the table to a given file instead of `unused.md`." + n : Nat; "Number of `lake exe graph` commands to print." + + ARGS: + ...modules : ModuleName; "Modules to check for unused imports." + + EXTENSIONS: + author "mhuisi"; + defaultValues! #[("output", "unused.md"), ("n", "10")] +] + +/-- `lake exe unused` -/ +def main (args : List String) : IO UInt32 := + unused.validate args diff --git a/Mathlib.lean b/Mathlib.lean index 7caab9ae96b88..9ff29007e3369 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -100,6 +100,7 @@ import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings import Mathlib.Algebra.Category.ModuleCat.Colimits import Mathlib.Algebra.Category.ModuleCat.Differentials.Basic import Mathlib.Algebra.Category.ModuleCat.Differentials.Presheaf +import Mathlib.Algebra.Category.ModuleCat.EnoughInjectives import Mathlib.Algebra.Category.ModuleCat.EpiMono import Mathlib.Algebra.Category.ModuleCat.FilteredColimits import Mathlib.Algebra.Category.ModuleCat.Free @@ -114,7 +115,10 @@ import Mathlib.Algebra.Category.ModuleCat.Presheaf import Mathlib.Algebra.Category.ModuleCat.Presheaf.Abelian import Mathlib.Algebra.Category.ModuleCat.Presheaf.ChangeOfRings import Mathlib.Algebra.Category.ModuleCat.Presheaf.Colimits +import Mathlib.Algebra.Category.ModuleCat.Presheaf.EpiMono +import Mathlib.Algebra.Category.ModuleCat.Presheaf.Free import Mathlib.Algebra.Category.ModuleCat.Presheaf.Limits +import Mathlib.Algebra.Category.ModuleCat.Presheaf.Monoidal import Mathlib.Algebra.Category.ModuleCat.Presheaf.Pushforward import Mathlib.Algebra.Category.ModuleCat.Presheaf.Sheafification import Mathlib.Algebra.Category.ModuleCat.Presheaf.Sheafify @@ -145,6 +149,8 @@ import Mathlib.Algebra.Category.Ring.FilteredColimits import Mathlib.Algebra.Category.Ring.Instances import Mathlib.Algebra.Category.Ring.Limits import Mathlib.Algebra.Category.Semigrp.Basic +import Mathlib.Algebra.Central.Basic +import Mathlib.Algebra.Central.Defs import Mathlib.Algebra.CharP.Algebra import Mathlib.Algebra.CharP.Basic import Mathlib.Algebra.CharP.CharAndCard @@ -152,6 +158,7 @@ import Mathlib.Algebra.CharP.Defs import Mathlib.Algebra.CharP.ExpChar import Mathlib.Algebra.CharP.IntermediateField import Mathlib.Algebra.CharP.Invertible +import Mathlib.Algebra.CharP.Lemmas import Mathlib.Algebra.CharP.LocalRing import Mathlib.Algebra.CharP.MixedCharZero import Mathlib.Algebra.CharP.Pi @@ -211,6 +218,7 @@ import Mathlib.Algebra.Free import Mathlib.Algebra.FreeAlgebra import Mathlib.Algebra.FreeMonoid.Basic import Mathlib.Algebra.FreeMonoid.Count +import Mathlib.Algebra.FreeMonoid.Symbols import Mathlib.Algebra.FreeNonUnitalNonAssocAlgebra import Mathlib.Algebra.GCDMonoid.Basic import Mathlib.Algebra.GCDMonoid.Finset @@ -222,12 +230,16 @@ import Mathlib.Algebra.GradedMonoid import Mathlib.Algebra.GradedMulAction import Mathlib.Algebra.Group.Action.Basic import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.End +import Mathlib.Algebra.Group.Action.Faithful import Mathlib.Algebra.Group.Action.Opposite import Mathlib.Algebra.Group.Action.Option import Mathlib.Algebra.Group.Action.Pi +import Mathlib.Algebra.Group.Action.Pretransitive import Mathlib.Algebra.Group.Action.Prod import Mathlib.Algebra.Group.Action.Sigma import Mathlib.Algebra.Group.Action.Sum +import Mathlib.Algebra.Group.Action.TypeTags import Mathlib.Algebra.Group.Action.Units import Mathlib.Algebra.Group.AddChar import Mathlib.Algebra.Group.Aut @@ -277,12 +289,14 @@ import Mathlib.Algebra.Group.Semiconj.Defs import Mathlib.Algebra.Group.Semiconj.Units import Mathlib.Algebra.Group.Subgroup.Actions import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.Algebra.Group.Subgroup.Finite import Mathlib.Algebra.Group.Subgroup.MulOpposite import Mathlib.Algebra.Group.Subgroup.Order import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Group.Subgroup.ZPowers import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.Group.Submonoid.DistribMulAction import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Group.Submonoid.MulOpposite @@ -290,6 +304,7 @@ import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.Group.Submonoid.Pointwise import Mathlib.Algebra.Group.Submonoid.Units import Mathlib.Algebra.Group.Subsemigroup.Basic +import Mathlib.Algebra.Group.Subsemigroup.Defs import Mathlib.Algebra.Group.Subsemigroup.Membership import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.Group.Support @@ -297,7 +312,8 @@ import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Group.ULift import Mathlib.Algebra.Group.UniqueProds.Basic import Mathlib.Algebra.Group.UniqueProds.VectorSpace -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic +import Mathlib.Algebra.Group.Units.Defs import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Algebra.Group.Units.Hom import Mathlib.Algebra.Group.WithOne.Basic @@ -306,6 +322,8 @@ import Mathlib.Algebra.Group.ZeroOne import Mathlib.Algebra.GroupPower.IterateHom import Mathlib.Algebra.GroupWithZero.Action.Basic import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.GroupWithZero.Action.End +import Mathlib.Algebra.GroupWithZero.Action.Faithful import Mathlib.Algebra.GroupWithZero.Action.Opposite import Mathlib.Algebra.GroupWithZero.Action.Pi import Mathlib.Algebra.GroupWithZero.Action.Prod @@ -324,7 +342,9 @@ import Mathlib.Algebra.GroupWithZero.NeZero import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.Algebra.GroupWithZero.Opposite import Mathlib.Algebra.GroupWithZero.Pi +import Mathlib.Algebra.GroupWithZero.Pointwise.Finset import Mathlib.Algebra.GroupWithZero.Pointwise.Set.Basic +import Mathlib.Algebra.GroupWithZero.Pointwise.Set.Card import Mathlib.Algebra.GroupWithZero.Prod import Mathlib.Algebra.GroupWithZero.Semiconj import Mathlib.Algebra.GroupWithZero.ULift @@ -412,6 +432,7 @@ import Mathlib.Algebra.Homology.ShortComplex.ShortExact import Mathlib.Algebra.Homology.ShortComplex.SnakeLemma import Mathlib.Algebra.Homology.Single import Mathlib.Algebra.Homology.SingleHomology +import Mathlib.Algebra.Homology.Square import Mathlib.Algebra.Homology.TotalComplex import Mathlib.Algebra.Homology.TotalComplexShift import Mathlib.Algebra.Homology.TotalComplexSymmetry @@ -468,8 +489,10 @@ import Mathlib.Algebra.Module.Card import Mathlib.Algebra.Module.CharacterModule import Mathlib.Algebra.Module.DedekindDomain import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.End import Mathlib.Algebra.Module.Equiv.Basic import Mathlib.Algebra.Module.Equiv.Defs +import Mathlib.Algebra.Module.Equiv.Opposite import Mathlib.Algebra.Module.FinitePresentation import Mathlib.Algebra.Module.GradedModule import Mathlib.Algebra.Module.Hom @@ -484,10 +507,12 @@ import Mathlib.Algebra.Module.LinearMap.Star import Mathlib.Algebra.Module.LocalizedModule import Mathlib.Algebra.Module.LocalizedModuleIntegers import Mathlib.Algebra.Module.MinimalAxioms -import Mathlib.Algebra.Module.Opposites +import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Module.PID import Mathlib.Algebra.Module.Pi import Mathlib.Algebra.Module.PointwisePi +import Mathlib.Algebra.Module.Presentation.Basic +import Mathlib.Algebra.Module.Presentation.Free import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Module.Projective import Mathlib.Algebra.Module.Rat @@ -495,6 +520,7 @@ import Mathlib.Algebra.Module.Submodule.Basic import Mathlib.Algebra.Module.Submodule.Bilinear import Mathlib.Algebra.Module.Submodule.EqLocus import Mathlib.Algebra.Module.Submodule.Equiv +import Mathlib.Algebra.Module.Submodule.Invariant import Mathlib.Algebra.Module.Submodule.IterateMapComap import Mathlib.Algebra.Module.Submodule.Ker import Mathlib.Algebra.Module.Submodule.Lattice @@ -538,6 +564,11 @@ import Mathlib.Algebra.MvPolynomial.Rename import Mathlib.Algebra.MvPolynomial.Supported import Mathlib.Algebra.MvPolynomial.Variables import Mathlib.Algebra.NeZero +import Mathlib.Algebra.NoZeroSMulDivisors.Basic +import Mathlib.Algebra.NoZeroSMulDivisors.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Pi +import Mathlib.Algebra.NoZeroSMulDivisors.Prod +import Mathlib.Algebra.Notation import Mathlib.Algebra.Opposites import Mathlib.Algebra.Order.AbsoluteValue import Mathlib.Algebra.Order.AddGroupWithTop @@ -616,7 +647,9 @@ import Mathlib.Algebra.Order.GroupWithZero.Unbundled.Lemmas import Mathlib.Algebra.Order.GroupWithZero.WithZero import Mathlib.Algebra.Order.Hom.Basic import Mathlib.Algebra.Order.Hom.Monoid +import Mathlib.Algebra.Order.Hom.Normed import Mathlib.Algebra.Order.Hom.Ring +import Mathlib.Algebra.Order.Hom.Ultra import Mathlib.Algebra.Order.Interval.Basic import Mathlib.Algebra.Order.Interval.Finset import Mathlib.Algebra.Order.Interval.Multiset @@ -647,6 +680,7 @@ import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax import Mathlib.Algebra.Order.Monoid.Unbundled.OrderDual import Mathlib.Algebra.Order.Monoid.Unbundled.Pow +import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop import Mathlib.Algebra.Order.Monoid.Units import Mathlib.Algebra.Order.Monoid.WithTop @@ -681,6 +715,7 @@ import Mathlib.Algebra.Order.Ring.Unbundled.Rat import Mathlib.Algebra.Order.Ring.WithTop import Mathlib.Algebra.Order.Star.Basic import Mathlib.Algebra.Order.Star.Conjneg +import Mathlib.Algebra.Order.Star.Prod import Mathlib.Algebra.Order.Sub.Basic import Mathlib.Algebra.Order.Sub.Defs import Mathlib.Algebra.Order.Sub.Prod @@ -695,6 +730,7 @@ import Mathlib.Algebra.Order.UpperLower import Mathlib.Algebra.Order.ZeroLEOne import Mathlib.Algebra.PEmptyInstances import Mathlib.Algebra.PUnitInstances.Algebra +import Mathlib.Algebra.PUnitInstances.GCDMonoid import Mathlib.Algebra.PUnitInstances.Module import Mathlib.Algebra.PUnitInstances.Order import Mathlib.Algebra.Periodic @@ -738,8 +774,11 @@ import Mathlib.Algebra.Polynomial.Roots import Mathlib.Algebra.Polynomial.Smeval import Mathlib.Algebra.Polynomial.SpecificDegree import Mathlib.Algebra.Polynomial.Splits +import Mathlib.Algebra.Polynomial.SumIteratedDerivative import Mathlib.Algebra.Polynomial.Taylor import Mathlib.Algebra.Polynomial.UnitTrinomial +import Mathlib.Algebra.Prime.Defs +import Mathlib.Algebra.Prime.Lemmas import Mathlib.Algebra.QuadraticDiscriminant import Mathlib.Algebra.Quandle import Mathlib.Algebra.Quaternion @@ -781,6 +820,7 @@ import Mathlib.Algebra.Ring.NegOnePow import Mathlib.Algebra.Ring.Opposite import Mathlib.Algebra.Ring.Parity import Mathlib.Algebra.Ring.Pi +import Mathlib.Algebra.Ring.Pointwise.Finset import Mathlib.Algebra.Ring.Pointwise.Set import Mathlib.Algebra.Ring.Prod import Mathlib.Algebra.Ring.Rat @@ -800,6 +840,7 @@ import Mathlib.Algebra.Ring.Subsemiring.Pointwise import Mathlib.Algebra.Ring.SumsOfSquares import Mathlib.Algebra.Ring.ULift import Mathlib.Algebra.Ring.Units +import Mathlib.Algebra.Ring.WithAbs import Mathlib.Algebra.Ring.WithZero import Mathlib.Algebra.RingQuot import Mathlib.Algebra.SMulWithZero @@ -837,6 +878,7 @@ 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.Jacobian import Mathlib.AlgebraicGeometry.EllipticCurve.NormalForms import Mathlib.AlgebraicGeometry.EllipticCurve.Projective @@ -856,19 +898,23 @@ import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion import Mathlib.AlgebraicGeometry.Morphisms.Constructors import Mathlib.AlgebraicGeometry.Morphisms.FinitePresentation import Mathlib.AlgebraicGeometry.Morphisms.FiniteType +import Mathlib.AlgebraicGeometry.Morphisms.Immersion import Mathlib.AlgebraicGeometry.Morphisms.IsIso import Mathlib.AlgebraicGeometry.Morphisms.OpenImmersion import Mathlib.AlgebraicGeometry.Morphisms.Preimmersion +import Mathlib.AlgebraicGeometry.Morphisms.Proper import Mathlib.AlgebraicGeometry.Morphisms.QuasiCompact import Mathlib.AlgebraicGeometry.Morphisms.QuasiSeparated import Mathlib.AlgebraicGeometry.Morphisms.RingHomProperties import Mathlib.AlgebraicGeometry.Morphisms.Separated +import Mathlib.AlgebraicGeometry.Morphisms.Smooth import Mathlib.AlgebraicGeometry.Morphisms.UnderlyingMap import Mathlib.AlgebraicGeometry.Morphisms.UniversallyClosed import Mathlib.AlgebraicGeometry.Noetherian import Mathlib.AlgebraicGeometry.OpenImmersion import Mathlib.AlgebraicGeometry.PrimeSpectrum.Basic import Mathlib.AlgebraicGeometry.PrimeSpectrum.IsOpenComapC +import Mathlib.AlgebraicGeometry.PrimeSpectrum.Jacobson import Mathlib.AlgebraicGeometry.PrimeSpectrum.Maximal import Mathlib.AlgebraicGeometry.PrimeSpectrum.Module import Mathlib.AlgebraicGeometry.PrimeSpectrum.Noetherian @@ -878,11 +924,13 @@ import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Topology import Mathlib.AlgebraicGeometry.Properties import Mathlib.AlgebraicGeometry.Pullbacks +import Mathlib.AlgebraicGeometry.RationalMap import Mathlib.AlgebraicGeometry.ResidueField import Mathlib.AlgebraicGeometry.Restrict import Mathlib.AlgebraicGeometry.Scheme import Mathlib.AlgebraicGeometry.Sites.BigZariski import Mathlib.AlgebraicGeometry.Spec +import Mathlib.AlgebraicGeometry.SpreadingOut import Mathlib.AlgebraicGeometry.Stalk import Mathlib.AlgebraicGeometry.StructureSheaf import Mathlib.AlgebraicTopology.AlternatingFaceMapComplex @@ -913,16 +961,16 @@ import Mathlib.AlgebraicTopology.FundamentalGroupoid.InducedMaps import Mathlib.AlgebraicTopology.FundamentalGroupoid.PUnit import Mathlib.AlgebraicTopology.FundamentalGroupoid.Product import Mathlib.AlgebraicTopology.FundamentalGroupoid.SimplyConnected -import Mathlib.AlgebraicTopology.KanComplex import Mathlib.AlgebraicTopology.MooreComplex -import Mathlib.AlgebraicTopology.Nerve -import Mathlib.AlgebraicTopology.Quasicategory import Mathlib.AlgebraicTopology.SimplexCategory import Mathlib.AlgebraicTopology.SimplicialCategory.Basic import Mathlib.AlgebraicTopology.SimplicialCategory.SimplicialObject import Mathlib.AlgebraicTopology.SimplicialObject -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic +import Mathlib.AlgebraicTopology.SimplicialSet.KanComplex import Mathlib.AlgebraicTopology.SimplicialSet.Monoidal +import Mathlib.AlgebraicTopology.SimplicialSet.Nerve +import Mathlib.AlgebraicTopology.SimplicialSet.Quasicategory import Mathlib.AlgebraicTopology.SingularSet import Mathlib.AlgebraicTopology.SplitSimplicialObject import Mathlib.AlgebraicTopology.TopologicalSimplex @@ -935,6 +983,7 @@ import Mathlib.Analysis.Analytic.Inverse import Mathlib.Analysis.Analytic.IsolatedZeros import Mathlib.Analysis.Analytic.Linear import Mathlib.Analysis.Analytic.Meromorphic +import Mathlib.Analysis.Analytic.OfScalars import Mathlib.Analysis.Analytic.Polynomial import Mathlib.Analysis.Analytic.RadiusLiminf import Mathlib.Analysis.Analytic.Uniqueness @@ -957,16 +1006,22 @@ import Mathlib.Analysis.BoxIntegral.Partition.Measure import Mathlib.Analysis.BoxIntegral.Partition.Split import Mathlib.Analysis.BoxIntegral.Partition.SubboxInduction import Mathlib.Analysis.BoxIntegral.Partition.Tagged +import Mathlib.Analysis.CStarAlgebra.ApproximateUnit import Mathlib.Analysis.CStarAlgebra.Basic +import Mathlib.Analysis.CStarAlgebra.Classes import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Basic import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Integral +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Isometric import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Order +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.PosPart import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Restrict import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unique import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unital import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unitary +import Mathlib.Analysis.CStarAlgebra.ContinuousLinearMap +import Mathlib.Analysis.CStarAlgebra.ContinuousMap import Mathlib.Analysis.CStarAlgebra.Exponential import Mathlib.Analysis.CStarAlgebra.GelfandDuality import Mathlib.Analysis.CStarAlgebra.Hom @@ -977,6 +1032,7 @@ import Mathlib.Analysis.CStarAlgebra.Module.Synonym import Mathlib.Analysis.CStarAlgebra.Multiplier import Mathlib.Analysis.CStarAlgebra.Spectrum import Mathlib.Analysis.CStarAlgebra.Unitization +import Mathlib.Analysis.CStarAlgebra.lpSpace import Mathlib.Analysis.Calculus.AddTorsor.AffineMap import Mathlib.Analysis.Calculus.AddTorsor.Coord import Mathlib.Analysis.Calculus.BumpFunction.Basic @@ -992,6 +1048,7 @@ import Mathlib.Analysis.Calculus.ContDiff.Defs import Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries import Mathlib.Analysis.Calculus.ContDiff.FiniteDimension import Mathlib.Analysis.Calculus.ContDiff.RCLike +import Mathlib.Analysis.Calculus.ContDiff.WithLp import Mathlib.Analysis.Calculus.Darboux import Mathlib.Analysis.Calculus.Deriv.Abs import Mathlib.Analysis.Calculus.Deriv.Add @@ -1023,11 +1080,14 @@ import Mathlib.Analysis.Calculus.FDeriv.Extend import Mathlib.Analysis.Calculus.FDeriv.Linear import Mathlib.Analysis.Calculus.FDeriv.Measurable import Mathlib.Analysis.Calculus.FDeriv.Mul +import Mathlib.Analysis.Calculus.FDeriv.Norm import Mathlib.Analysis.Calculus.FDeriv.Pi import Mathlib.Analysis.Calculus.FDeriv.Prod import Mathlib.Analysis.Calculus.FDeriv.RestrictScalars import Mathlib.Analysis.Calculus.FDeriv.Star import Mathlib.Analysis.Calculus.FDeriv.Symmetric +import Mathlib.Analysis.Calculus.FDeriv.WithLp +import Mathlib.Analysis.Calculus.FirstDerivativeTest import Mathlib.Analysis.Calculus.FormalMultilinearSeries import Mathlib.Analysis.Calculus.Gradient.Basic import Mathlib.Analysis.Calculus.Implicit @@ -1079,6 +1139,7 @@ import Mathlib.Analysis.Complex.OperatorNorm import Mathlib.Analysis.Complex.PhragmenLindelof import Mathlib.Analysis.Complex.Polynomial.Basic import Mathlib.Analysis.Complex.Polynomial.UnitTrinomial +import Mathlib.Analysis.Complex.Positivity import Mathlib.Analysis.Complex.ReImTopology import Mathlib.Analysis.Complex.RealDeriv import Mathlib.Analysis.Complex.RemovableSingularity @@ -1096,6 +1157,7 @@ import Mathlib.Analysis.ConstantSpeed import Mathlib.Analysis.Convex.AmpleSet import Mathlib.Analysis.Convex.Basic import Mathlib.Analysis.Convex.Between +import Mathlib.Analysis.Convex.Birkhoff import Mathlib.Analysis.Convex.Body import Mathlib.Analysis.Convex.Caratheodory import Mathlib.Analysis.Convex.Combination @@ -1143,6 +1205,7 @@ import Mathlib.Analysis.Convex.StrictConvexBetween import Mathlib.Analysis.Convex.StrictConvexSpace import Mathlib.Analysis.Convex.Strong import Mathlib.Analysis.Convex.Topology +import Mathlib.Analysis.Convex.TotallyBounded import Mathlib.Analysis.Convex.Uniform import Mathlib.Analysis.Convolution import Mathlib.Analysis.Distribution.AEEqOfIntegralContDiff @@ -1217,6 +1280,7 @@ import Mathlib.Analysis.Normed.Field.Basic import Mathlib.Analysis.Normed.Field.InfiniteSum import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.Normed.Field.ProperSpace +import Mathlib.Analysis.Normed.Field.Ultra import Mathlib.Analysis.Normed.Field.UnitBall import Mathlib.Analysis.Normed.Group.AddCircle import Mathlib.Analysis.Normed.Group.AddTorsor @@ -1314,6 +1378,7 @@ import Mathlib.Analysis.PSeries import Mathlib.Analysis.PSeriesComplex import Mathlib.Analysis.Quaternion import Mathlib.Analysis.RCLike.Basic +import Mathlib.Analysis.RCLike.Inner import Mathlib.Analysis.RCLike.Lemmas import Mathlib.Analysis.Seminorm import Mathlib.Analysis.SpecialFunctions.Arsinh @@ -1337,6 +1402,7 @@ import Mathlib.Analysis.SpecialFunctions.Gamma.Basic import Mathlib.Analysis.SpecialFunctions.Gamma.Beta import Mathlib.Analysis.SpecialFunctions.Gamma.BohrMollerup import Mathlib.Analysis.SpecialFunctions.Gamma.Deligne +import Mathlib.Analysis.SpecialFunctions.Gamma.Deriv import Mathlib.Analysis.SpecialFunctions.Gaussian.FourierTransform import Mathlib.Analysis.SpecialFunctions.Gaussian.GaussianIntegral import Mathlib.Analysis.SpecialFunctions.Gaussian.PoissonSummation @@ -1352,6 +1418,7 @@ import Mathlib.Analysis.SpecialFunctions.Log.ERealExp import Mathlib.Analysis.SpecialFunctions.Log.Monotone import Mathlib.Analysis.SpecialFunctions.Log.NegMulLog import Mathlib.Analysis.SpecialFunctions.NonIntegrable +import Mathlib.Analysis.SpecialFunctions.OrdinaryHypergeometric import Mathlib.Analysis.SpecialFunctions.PolarCoord import Mathlib.Analysis.SpecialFunctions.PolynomialExp import Mathlib.Analysis.SpecialFunctions.Polynomials @@ -1421,6 +1488,7 @@ import Mathlib.CategoryTheory.Adjunction.Limits import Mathlib.CategoryTheory.Adjunction.Mates import Mathlib.CategoryTheory.Adjunction.Opposites import Mathlib.CategoryTheory.Adjunction.Over +import Mathlib.CategoryTheory.Adjunction.PartialAdjoint import Mathlib.CategoryTheory.Adjunction.Reflective import Mathlib.CategoryTheory.Adjunction.Restrict import Mathlib.CategoryTheory.Adjunction.Triple @@ -1434,14 +1502,17 @@ import Mathlib.CategoryTheory.Bicategory.End import Mathlib.CategoryTheory.Bicategory.Extension import Mathlib.CategoryTheory.Bicategory.Free import Mathlib.CategoryTheory.Bicategory.Functor.Lax +import Mathlib.CategoryTheory.Bicategory.Functor.LocallyDiscrete import Mathlib.CategoryTheory.Bicategory.Functor.Oplax import Mathlib.CategoryTheory.Bicategory.Functor.Prelax import Mathlib.CategoryTheory.Bicategory.Functor.Pseudofunctor -import Mathlib.CategoryTheory.Bicategory.FunctorBicategory +import Mathlib.CategoryTheory.Bicategory.FunctorBicategory.Oplax +import Mathlib.CategoryTheory.Bicategory.Grothendieck import Mathlib.CategoryTheory.Bicategory.Kan.Adjunction import Mathlib.CategoryTheory.Bicategory.Kan.HasKan import Mathlib.CategoryTheory.Bicategory.Kan.IsKan import Mathlib.CategoryTheory.Bicategory.LocallyDiscrete +import Mathlib.CategoryTheory.Bicategory.Modification.Oplax import Mathlib.CategoryTheory.Bicategory.NaturalTransformation.Oplax import Mathlib.CategoryTheory.Bicategory.NaturalTransformation.Strong import Mathlib.CategoryTheory.Bicategory.SingleObj @@ -1470,8 +1541,10 @@ import Mathlib.CategoryTheory.ChosenFiniteProducts import Mathlib.CategoryTheory.ChosenFiniteProducts.Cat import Mathlib.CategoryTheory.ChosenFiniteProducts.FunctorCategory import Mathlib.CategoryTheory.Closed.Cartesian +import Mathlib.CategoryTheory.Closed.Enrichment import Mathlib.CategoryTheory.Closed.Functor -import Mathlib.CategoryTheory.Closed.FunctorCategory +import Mathlib.CategoryTheory.Closed.FunctorCategory.Complete +import Mathlib.CategoryTheory.Closed.FunctorCategory.Groupoid import Mathlib.CategoryTheory.Closed.FunctorToTypes import Mathlib.CategoryTheory.Closed.Ideal import Mathlib.CategoryTheory.Closed.Monoidal @@ -1483,8 +1556,11 @@ import Mathlib.CategoryTheory.CommSq import Mathlib.CategoryTheory.Comma.Arrow import Mathlib.CategoryTheory.Comma.Basic import Mathlib.CategoryTheory.Comma.Over -import Mathlib.CategoryTheory.Comma.Presheaf -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.Presheaf.Basic +import Mathlib.CategoryTheory.Comma.Presheaf.Colimit +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic +import Mathlib.CategoryTheory.Comma.StructuredArrow.Functor +import Mathlib.CategoryTheory.Comma.StructuredArrow.Small import Mathlib.CategoryTheory.ComposableArrows import Mathlib.CategoryTheory.ConcreteCategory.Basic import Mathlib.CategoryTheory.ConcreteCategory.Bundled @@ -1513,6 +1589,7 @@ import Mathlib.CategoryTheory.Elementwise import Mathlib.CategoryTheory.Endofunctor.Algebra import Mathlib.CategoryTheory.Endomorphism import Mathlib.CategoryTheory.Enriched.Basic +import Mathlib.CategoryTheory.Enriched.Ordinary import Mathlib.CategoryTheory.EpiMono import Mathlib.CategoryTheory.EqToHom import Mathlib.CategoryTheory.Equivalence @@ -1522,6 +1599,7 @@ import Mathlib.CategoryTheory.Extensive import Mathlib.CategoryTheory.FiberedCategory.BasedCategory import Mathlib.CategoryTheory.FiberedCategory.Cartesian import Mathlib.CategoryTheory.FiberedCategory.Cocartesian +import Mathlib.CategoryTheory.FiberedCategory.Fiber import Mathlib.CategoryTheory.FiberedCategory.Fibered import Mathlib.CategoryTheory.FiberedCategory.HomLift import Mathlib.CategoryTheory.Filtered.Basic @@ -1572,6 +1650,7 @@ import Mathlib.CategoryTheory.GradedObject.Unitor import Mathlib.CategoryTheory.Grothendieck import Mathlib.CategoryTheory.Groupoid import Mathlib.CategoryTheory.Groupoid.Basic +import Mathlib.CategoryTheory.Groupoid.Discrete import Mathlib.CategoryTheory.Groupoid.FreeGroupoid import Mathlib.CategoryTheory.Groupoid.Subgroupoid import Mathlib.CategoryTheory.Groupoid.VertexGroup @@ -1630,11 +1709,13 @@ import Mathlib.CategoryTheory.Limits.FunctorCategory.Finite import Mathlib.CategoryTheory.Limits.FunctorToTypes import Mathlib.CategoryTheory.Limits.HasLimits import Mathlib.CategoryTheory.Limits.IndYoneda +import Mathlib.CategoryTheory.Limits.Indization.FilteredColimits import Mathlib.CategoryTheory.Limits.Indization.IndObject import Mathlib.CategoryTheory.Limits.IsConnected import Mathlib.CategoryTheory.Limits.IsLimit import Mathlib.CategoryTheory.Limits.Lattice import Mathlib.CategoryTheory.Limits.MonoCoprod +import Mathlib.CategoryTheory.Limits.MorphismProperty import Mathlib.CategoryTheory.Limits.Opposites import Mathlib.CategoryTheory.Limits.Over import Mathlib.CategoryTheory.Limits.Pi @@ -1655,14 +1736,17 @@ import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Square import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Terminal import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Zero import Mathlib.CategoryTheory.Limits.Preserves.Ulift +import Mathlib.CategoryTheory.Limits.Preserves.Yoneda import Mathlib.CategoryTheory.Limits.Presheaf import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts import Mathlib.CategoryTheory.Limits.Shapes.Biproducts import Mathlib.CategoryTheory.Limits.Shapes.CombinedProducts import Mathlib.CategoryTheory.Limits.Shapes.ConcreteCategory +import Mathlib.CategoryTheory.Limits.Shapes.Connected import Mathlib.CategoryTheory.Limits.Shapes.Countable import Mathlib.CategoryTheory.Limits.Shapes.Diagonal import Mathlib.CategoryTheory.Limits.Shapes.DisjointCoproduct +import Mathlib.CategoryTheory.Limits.Shapes.End import Mathlib.CategoryTheory.Limits.Shapes.Equalizers import Mathlib.CategoryTheory.Limits.Shapes.Equivalence import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits @@ -1670,6 +1754,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts import Mathlib.CategoryTheory.Limits.Shapes.FunctorCategory import Mathlib.CategoryTheory.Limits.Shapes.FunctorToTypes import Mathlib.CategoryTheory.Limits.Shapes.Images +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal import Mathlib.CategoryTheory.Limits.Shapes.KernelPair import Mathlib.CategoryTheory.Limits.Shapes.Kernels import Mathlib.CategoryTheory.Limits.Shapes.Multiequalizer @@ -1679,6 +1764,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.Products import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Assoc import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Cospan +import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Equalizer import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Iso import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Mono @@ -1698,6 +1784,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.WideEqualizers import Mathlib.CategoryTheory.Limits.Shapes.WidePullbacks import Mathlib.CategoryTheory.Limits.Shapes.ZeroMorphisms import Mathlib.CategoryTheory.Limits.Shapes.ZeroObjects +import Mathlib.CategoryTheory.Limits.Sifted import Mathlib.CategoryTheory.Limits.SmallComplete import Mathlib.CategoryTheory.Limits.Types import Mathlib.CategoryTheory.Limits.TypesFiltered @@ -1748,6 +1835,7 @@ import Mathlib.CategoryTheory.Monoidal.Bimod import Mathlib.CategoryTheory.Monoidal.Bimon_ import Mathlib.CategoryTheory.Monoidal.Braided.Basic import Mathlib.CategoryTheory.Monoidal.Braided.Opposite +import Mathlib.CategoryTheory.Monoidal.Braided.Reflection import Mathlib.CategoryTheory.Monoidal.Cartesian.Comon_ import Mathlib.CategoryTheory.Monoidal.Category import Mathlib.CategoryTheory.Monoidal.Center @@ -1789,6 +1877,7 @@ import Mathlib.CategoryTheory.Monoidal.Types.Basic import Mathlib.CategoryTheory.Monoidal.Types.Coyoneda import Mathlib.CategoryTheory.Monoidal.Types.Symmetric import Mathlib.CategoryTheory.MorphismProperty.Basic +import Mathlib.CategoryTheory.MorphismProperty.Comma import Mathlib.CategoryTheory.MorphismProperty.Composition import Mathlib.CategoryTheory.MorphismProperty.Concrete import Mathlib.CategoryTheory.MorphismProperty.Factorization @@ -1801,7 +1890,8 @@ import Mathlib.CategoryTheory.Noetherian import Mathlib.CategoryTheory.Opposites import Mathlib.CategoryTheory.PEmpty import Mathlib.CategoryTheory.PUnit -import Mathlib.CategoryTheory.PathCategory +import Mathlib.CategoryTheory.PathCategory.Basic +import Mathlib.CategoryTheory.PathCategory.MorphismProperty import Mathlib.CategoryTheory.Pi.Basic import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor import Mathlib.CategoryTheory.Preadditive.Basic @@ -1843,6 +1933,7 @@ import Mathlib.CategoryTheory.Shift.Pullback import Mathlib.CategoryTheory.Shift.Quotient import Mathlib.CategoryTheory.Shift.ShiftSequence import Mathlib.CategoryTheory.Shift.ShiftedHom +import Mathlib.CategoryTheory.Shift.ShiftedHomOpposite import Mathlib.CategoryTheory.Shift.SingleFunctors import Mathlib.CategoryTheory.Sigma.Basic import Mathlib.CategoryTheory.Simple @@ -1891,6 +1982,7 @@ import Mathlib.CategoryTheory.Sites.LocallyFullyFaithful import Mathlib.CategoryTheory.Sites.LocallyInjective import Mathlib.CategoryTheory.Sites.LocallySurjective import Mathlib.CategoryTheory.Sites.MayerVietorisSquare +import Mathlib.CategoryTheory.Sites.MorphismProperty import Mathlib.CategoryTheory.Sites.NonabelianCohomology.H1 import Mathlib.CategoryTheory.Sites.OneHypercover import Mathlib.CategoryTheory.Sites.Over @@ -1912,7 +2004,7 @@ import Mathlib.CategoryTheory.Sites.Types import Mathlib.CategoryTheory.Sites.Whiskering import Mathlib.CategoryTheory.Skeletal import Mathlib.CategoryTheory.SmallObject.Construction -import Mathlib.CategoryTheory.SmallObject.Iteration +import Mathlib.CategoryTheory.SmallObject.Iteration.Basic import Mathlib.CategoryTheory.Square import Mathlib.CategoryTheory.Subobject.Basic import Mathlib.CategoryTheory.Subobject.Comma @@ -2066,6 +2158,8 @@ import Mathlib.Computability.TuringMachine import Mathlib.Condensed.Basic import Mathlib.Condensed.CartesianClosed import Mathlib.Condensed.Discrete.Basic +import Mathlib.Condensed.Discrete.Characterization +import Mathlib.Condensed.Discrete.Colimit import Mathlib.Condensed.Discrete.LocallyConstant import Mathlib.Condensed.Discrete.Module import Mathlib.Condensed.Epi @@ -2123,7 +2217,6 @@ import Mathlib.Data.Bool.Count import Mathlib.Data.Bool.Set import Mathlib.Data.Bracket import Mathlib.Data.Bundle -import Mathlib.Data.ByteArray import Mathlib.Data.Char import Mathlib.Data.Complex.Abs import Mathlib.Data.Complex.Basic @@ -2148,11 +2241,10 @@ import Mathlib.Data.DFinsupp.NeLocus import Mathlib.Data.DFinsupp.Notation import Mathlib.Data.DFinsupp.Order import Mathlib.Data.DFinsupp.WellFounded -import Mathlib.Data.DList.Basic -import Mathlib.Data.DList.Defs import Mathlib.Data.DList.Instances import Mathlib.Data.ENNReal.Basic import Mathlib.Data.ENNReal.Inv +import Mathlib.Data.ENNReal.Lemmas import Mathlib.Data.ENNReal.Operations import Mathlib.Data.ENNReal.Real import Mathlib.Data.ENat.Basic @@ -2170,12 +2262,17 @@ import Mathlib.Data.Fin.Tuple.Finset import Mathlib.Data.Fin.Tuple.NatAntidiagonal import Mathlib.Data.Fin.Tuple.Reflection import Mathlib.Data.Fin.Tuple.Sort +import Mathlib.Data.Fin.Tuple.Take import Mathlib.Data.Fin.VecNotation import Mathlib.Data.FinEnum -import Mathlib.Data.Finite.Basic import Mathlib.Data.Finite.Card import Mathlib.Data.Finite.Defs +import Mathlib.Data.Finite.Powerset +import Mathlib.Data.Finite.Prod import Mathlib.Data.Finite.Set +import Mathlib.Data.Finite.Sigma +import Mathlib.Data.Finite.Sum +import Mathlib.Data.Finite.Vector import Mathlib.Data.Finmap import Mathlib.Data.Finset.Attr import Mathlib.Data.Finset.Basic @@ -2261,7 +2358,6 @@ import Mathlib.Data.FunLike.Equiv import Mathlib.Data.FunLike.Fintype import Mathlib.Data.Holor import Mathlib.Data.Int.AbsoluteValue -import Mathlib.Data.Int.Align import Mathlib.Data.Int.Associated import Mathlib.Data.Int.Bitwise import Mathlib.Data.Int.CardIntervalMod @@ -2308,8 +2404,10 @@ import Mathlib.Data.List.Enum import Mathlib.Data.List.FinRange import Mathlib.Data.List.Forall2 import Mathlib.Data.List.GetD +import Mathlib.Data.List.GroupBy import Mathlib.Data.List.Indexes import Mathlib.Data.List.Infix +import Mathlib.Data.List.InsertIdx import Mathlib.Data.List.InsertNth import Mathlib.Data.List.Intervals import Mathlib.Data.List.Iterate @@ -2325,7 +2423,9 @@ import Mathlib.Data.List.NodupEquivFin import Mathlib.Data.List.OfFn import Mathlib.Data.List.Pairwise import Mathlib.Data.List.Palindrome -import Mathlib.Data.List.Perm +import Mathlib.Data.List.Perm.Basic +import Mathlib.Data.List.Perm.Lattice +import Mathlib.Data.List.Perm.Subperm import Mathlib.Data.List.Permutation import Mathlib.Data.List.Pi import Mathlib.Data.List.Prime @@ -2354,6 +2454,7 @@ import Mathlib.Data.Matrix.CharP import Mathlib.Data.Matrix.ColumnRowPartitioned import Mathlib.Data.Matrix.Composition import Mathlib.Data.Matrix.DMatrix +import Mathlib.Data.Matrix.DoublyStochastic import Mathlib.Data.Matrix.DualNumber import Mathlib.Data.Matrix.Hadamard import Mathlib.Data.Matrix.Invertible @@ -2394,10 +2495,13 @@ import Mathlib.Data.Multiset.Sum import Mathlib.Data.Multiset.Sym import Mathlib.Data.NNRat.BigOperators import Mathlib.Data.NNRat.Defs +import Mathlib.Data.NNRat.Floor import Mathlib.Data.NNRat.Lemmas import Mathlib.Data.NNRat.Order import Mathlib.Data.NNReal.Basic +import Mathlib.Data.NNReal.Defs import Mathlib.Data.NNReal.Star +import Mathlib.Data.Nat.BinaryRec import Mathlib.Data.Nat.BitIndices import Mathlib.Data.Nat.Bits import Mathlib.Data.Nat.Bitwise @@ -2460,6 +2564,11 @@ import Mathlib.Data.Nat.PartENat import Mathlib.Data.Nat.Periodic import Mathlib.Data.Nat.Prime.Basic import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.Prime.Factorial +import Mathlib.Data.Nat.Prime.Infinite +import Mathlib.Data.Nat.Prime.Int +import Mathlib.Data.Nat.Prime.Nth +import Mathlib.Data.Nat.Prime.Pow import Mathlib.Data.Nat.PrimeFin import Mathlib.Data.Nat.Set import Mathlib.Data.Nat.Size @@ -2535,6 +2644,7 @@ import Mathlib.Data.Real.EReal import Mathlib.Data.Real.GoldenRatio import Mathlib.Data.Real.Hyperreal import Mathlib.Data.Real.Irrational +import Mathlib.Data.Real.IsNonarchimedean import Mathlib.Data.Real.Pi.Bounds import Mathlib.Data.Real.Pi.Irrational import Mathlib.Data.Real.Pi.Leibniz @@ -2590,6 +2700,7 @@ import Mathlib.Data.Set.Sigma import Mathlib.Data.Set.Subset import Mathlib.Data.Set.Subsingleton import Mathlib.Data.Set.Sups +import Mathlib.Data.Set.SymmDiff import Mathlib.Data.Set.UnionLift import Mathlib.Data.SetLike.Basic import Mathlib.Data.SetLike.Fintype @@ -2617,6 +2728,7 @@ import Mathlib.Data.Sym.Sym2.Init import Mathlib.Data.Sym.Sym2.Order import Mathlib.Data.Tree.Basic import Mathlib.Data.Tree.Get +import Mathlib.Data.Tree.RBMap import Mathlib.Data.TwoPointing import Mathlib.Data.TypeMax import Mathlib.Data.TypeVec @@ -2639,10 +2751,17 @@ import Mathlib.Data.ZMod.Factorial import Mathlib.Data.ZMod.IntUnitsPower import Mathlib.Data.ZMod.Quotient import Mathlib.Data.ZMod.Units +import Mathlib.Deprecated.AlgebraClasses import Mathlib.Deprecated.Aliases +import Mathlib.Deprecated.ByteArray import Mathlib.Deprecated.Combinator +import Mathlib.Deprecated.Equiv import Mathlib.Deprecated.Group import Mathlib.Deprecated.HashMap +import Mathlib.Deprecated.Logic +import Mathlib.Deprecated.MinMax +import Mathlib.Deprecated.NatLemmas +import Mathlib.Deprecated.RelClasses import Mathlib.Deprecated.Ring import Mathlib.Deprecated.Subfield import Mathlib.Deprecated.Subgroup @@ -2670,9 +2789,11 @@ import Mathlib.Dynamics.PeriodicPts import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage import Mathlib.Dynamics.TopologicalEntropy.NetEntropy +import Mathlib.Dynamics.TopologicalEntropy.Semiconj import Mathlib.FieldTheory.AbelRuffini import Mathlib.FieldTheory.AbsoluteGaloisGroup import Mathlib.FieldTheory.Adjoin +import Mathlib.FieldTheory.AlgebraicClosure import Mathlib.FieldTheory.AxGrothendieck import Mathlib.FieldTheory.Cardinality import Mathlib.FieldTheory.ChevalleyWarning @@ -2685,6 +2806,8 @@ import Mathlib.FieldTheory.Finite.Trace import Mathlib.FieldTheory.Finiteness import Mathlib.FieldTheory.Fixed import Mathlib.FieldTheory.Galois.Basic +import Mathlib.FieldTheory.Galois.GaloisClosure +import Mathlib.FieldTheory.Galois.Profinite import Mathlib.FieldTheory.IntermediateField.Algebraic import Mathlib.FieldTheory.IntermediateField.Basic import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure @@ -2698,6 +2821,7 @@ import Mathlib.FieldTheory.KummerExtension import Mathlib.FieldTheory.Laurent import Mathlib.FieldTheory.Minpoly.Basic import Mathlib.FieldTheory.Minpoly.Field +import Mathlib.FieldTheory.Minpoly.IsConjRoot import Mathlib.FieldTheory.Minpoly.IsIntegrallyClosed import Mathlib.FieldTheory.Minpoly.MinpolyDiv import Mathlib.FieldTheory.MvPolynomial @@ -2770,6 +2894,7 @@ import Mathlib.Geometry.Manifold.MFDeriv.Basic import Mathlib.Geometry.Manifold.MFDeriv.Defs import Mathlib.Geometry.Manifold.MFDeriv.FDeriv import Mathlib.Geometry.Manifold.MFDeriv.SpecificFunctions +import Mathlib.Geometry.Manifold.MFDeriv.Tangent import Mathlib.Geometry.Manifold.MFDeriv.UniqueDifferential import Mathlib.Geometry.Manifold.Metrizable import Mathlib.Geometry.Manifold.PartitionOfUnity @@ -2806,11 +2931,14 @@ import Mathlib.GroupTheory.CommutingProbability import Mathlib.GroupTheory.Complement import Mathlib.GroupTheory.Congruence.Basic import Mathlib.GroupTheory.Congruence.BigOperators +import Mathlib.GroupTheory.Congruence.Defs +import Mathlib.GroupTheory.Congruence.Hom import Mathlib.GroupTheory.Congruence.Opposite import Mathlib.GroupTheory.Coprod.Basic import Mathlib.GroupTheory.CoprodI import Mathlib.GroupTheory.Coset.Basic import Mathlib.GroupTheory.Coset.Card +import Mathlib.GroupTheory.Coset.Defs import Mathlib.GroupTheory.CosetCover import Mathlib.GroupTheory.Coxeter.Basic import Mathlib.GroupTheory.Coxeter.Inversion @@ -2833,6 +2961,7 @@ import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.Blocks import Mathlib.GroupTheory.GroupAction.CardCommute import Mathlib.GroupTheory.GroupAction.ConjAct +import Mathlib.GroupTheory.GroupAction.Defs import Mathlib.GroupTheory.GroupAction.DomAct.ActionHom import Mathlib.GroupTheory.GroupAction.DomAct.Basic import Mathlib.GroupTheory.GroupAction.Embedding @@ -2850,6 +2979,7 @@ import Mathlib.GroupTheory.GroupAction.Support import Mathlib.GroupTheory.GroupExtension.Defs import Mathlib.GroupTheory.HNNExtension import Mathlib.GroupTheory.Index +import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.GroupTheory.MonoidLocalization.Basic import Mathlib.GroupTheory.MonoidLocalization.MonoidWithZero import Mathlib.GroupTheory.MonoidLocalization.Order @@ -2858,6 +2988,8 @@ import Mathlib.GroupTheory.NoncommCoprod import Mathlib.GroupTheory.NoncommPiCoprod import Mathlib.GroupTheory.Order.Min import Mathlib.GroupTheory.OrderOfElement +import Mathlib.GroupTheory.OreLocalization.Basic +import Mathlib.GroupTheory.OreLocalization.OreSet import Mathlib.GroupTheory.PGroup import Mathlib.GroupTheory.Perm.Basic import Mathlib.GroupTheory.Perm.Closure @@ -2880,6 +3012,7 @@ import Mathlib.GroupTheory.Perm.ViaEmbedding import Mathlib.GroupTheory.PresentedGroup import Mathlib.GroupTheory.PushoutI import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.GroupTheory.QuotientGroup.Finite import Mathlib.GroupTheory.Schreier import Mathlib.GroupTheory.SchurZassenhaus @@ -2904,9 +3037,6 @@ import Mathlib.GroupTheory.Torsion import Mathlib.GroupTheory.Transfer import Mathlib.InformationTheory.Hamming import Mathlib.Init -import Mathlib.Init.Algebra.Classes -import Mathlib.Init.Data.Nat.Lemmas -import Mathlib.Init.Logic import Mathlib.Lean.CoreM import Mathlib.Lean.Elab.Tactic.Basic import Mathlib.Lean.Elab.Term @@ -2915,6 +3045,7 @@ import Mathlib.Lean.Exception import Mathlib.Lean.Expr import Mathlib.Lean.Expr.Basic import Mathlib.Lean.Expr.ExtraRecognizers +import Mathlib.Lean.Expr.Rat import Mathlib.Lean.Expr.ReplaceRec import Mathlib.Lean.GoalsLocation import Mathlib.Lean.Json @@ -2999,6 +3130,7 @@ import Mathlib.LinearAlgebra.Dual import Mathlib.LinearAlgebra.Eigenspace.Basic import Mathlib.LinearAlgebra.Eigenspace.Matrix import Mathlib.LinearAlgebra.Eigenspace.Minpoly +import Mathlib.LinearAlgebra.Eigenspace.Pi import Mathlib.LinearAlgebra.Eigenspace.Semisimple import Mathlib.LinearAlgebra.Eigenspace.Triangularizable import Mathlib.LinearAlgebra.Eigenspace.Zero @@ -3047,12 +3179,14 @@ import Mathlib.LinearAlgebra.Matrix.Diagonal import Mathlib.LinearAlgebra.Matrix.DotProduct import Mathlib.LinearAlgebra.Matrix.Dual import Mathlib.LinearAlgebra.Matrix.FiniteDimensional +import Mathlib.LinearAlgebra.Matrix.FixedDetMatrices import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Basic import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Card import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Defs import Mathlib.LinearAlgebra.Matrix.Gershgorin import Mathlib.LinearAlgebra.Matrix.Hermitian import Mathlib.LinearAlgebra.Matrix.HermitianFunctionalCalculus +import Mathlib.LinearAlgebra.Matrix.Ideal import Mathlib.LinearAlgebra.Matrix.InvariantBasisNumber import Mathlib.LinearAlgebra.Matrix.IsDiag import Mathlib.LinearAlgebra.Matrix.LDL @@ -3077,7 +3211,9 @@ import Mathlib.LinearAlgebra.Matrix.Transvection import Mathlib.LinearAlgebra.Matrix.ZPow import Mathlib.LinearAlgebra.Multilinear.Basic import Mathlib.LinearAlgebra.Multilinear.Basis +import Mathlib.LinearAlgebra.Multilinear.DFinsupp import Mathlib.LinearAlgebra.Multilinear.FiniteDimensional +import Mathlib.LinearAlgebra.Multilinear.Pi import Mathlib.LinearAlgebra.Multilinear.TensorProduct import Mathlib.LinearAlgebra.Orientation import Mathlib.LinearAlgebra.PID @@ -3103,8 +3239,9 @@ import Mathlib.LinearAlgebra.QuadraticForm.QuadraticModuleCat.Symmetric import Mathlib.LinearAlgebra.QuadraticForm.Real import Mathlib.LinearAlgebra.QuadraticForm.TensorProduct import Mathlib.LinearAlgebra.QuadraticForm.TensorProduct.Isometries -import Mathlib.LinearAlgebra.Quotient -import Mathlib.LinearAlgebra.QuotientPi +import Mathlib.LinearAlgebra.Quotient.Basic +import Mathlib.LinearAlgebra.Quotient.Defs +import Mathlib.LinearAlgebra.Quotient.Pi import Mathlib.LinearAlgebra.Ray import Mathlib.LinearAlgebra.Reflection import Mathlib.LinearAlgebra.RootSystem.Basic @@ -3135,6 +3272,7 @@ import Mathlib.LinearAlgebra.TensorProduct.Matrix import Mathlib.LinearAlgebra.TensorProduct.Opposite import Mathlib.LinearAlgebra.TensorProduct.Pi import Mathlib.LinearAlgebra.TensorProduct.Prod +import Mathlib.LinearAlgebra.TensorProduct.Quotient import Mathlib.LinearAlgebra.TensorProduct.RightExactness import Mathlib.LinearAlgebra.TensorProduct.Subalgebra import Mathlib.LinearAlgebra.TensorProduct.Submodule @@ -3194,6 +3332,7 @@ import Mathlib.Logic.Small.Set import Mathlib.Logic.Unique import Mathlib.Logic.UnivLE import Mathlib.MeasureTheory.Category.MeasCat +import Mathlib.MeasureTheory.Constructions.AddChar import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic import Mathlib.MeasureTheory.Constructions.BorelSpace.Complex import Mathlib.MeasureTheory.Constructions.BorelSpace.ContinuousLinearMap @@ -3207,9 +3346,8 @@ import Mathlib.MeasureTheory.Constructions.HaarToSphere import Mathlib.MeasureTheory.Constructions.Pi import Mathlib.MeasureTheory.Constructions.Polish.Basic import Mathlib.MeasureTheory.Constructions.Polish.EmbeddingReal -import Mathlib.MeasureTheory.Constructions.Prod.Basic -import Mathlib.MeasureTheory.Constructions.Prod.Integral import Mathlib.MeasureTheory.Constructions.Projective +import Mathlib.MeasureTheory.Constructions.SubmoduleQuotient import Mathlib.MeasureTheory.Constructions.UnitInterval import Mathlib.MeasureTheory.Covering.Besicovitch import Mathlib.MeasureTheory.Covering.BesicovitchVectorSpace @@ -3309,6 +3447,7 @@ import Mathlib.MeasureTheory.Integral.MeanInequalities import Mathlib.MeasureTheory.Integral.PeakFunction import Mathlib.MeasureTheory.Integral.Periodic import Mathlib.MeasureTheory.Integral.Pi +import Mathlib.MeasureTheory.Integral.Prod import Mathlib.MeasureTheory.Integral.RieszMarkovKakutani import Mathlib.MeasureTheory.Integral.SetIntegral import Mathlib.MeasureTheory.Integral.SetToL1 @@ -3323,6 +3462,7 @@ import Mathlib.MeasureTheory.MeasurableSpace.Instances import Mathlib.MeasureTheory.MeasurableSpace.Invariants import Mathlib.MeasureTheory.MeasurableSpace.NCard import Mathlib.MeasureTheory.MeasurableSpace.PreorderRestrict +import Mathlib.MeasureTheory.MeasurableSpace.Prod import Mathlib.MeasureTheory.Measure.AEDisjoint import Mathlib.MeasureTheory.Measure.AEMeasurable import Mathlib.MeasureTheory.Measure.AddContent @@ -3360,6 +3500,7 @@ import Mathlib.MeasureTheory.Measure.NullMeasurable import Mathlib.MeasureTheory.Measure.OpenPos import Mathlib.MeasureTheory.Measure.Portmanteau import Mathlib.MeasureTheory.Measure.ProbabilityMeasure +import Mathlib.MeasureTheory.Measure.Prod import Mathlib.MeasureTheory.Measure.Regular import Mathlib.MeasureTheory.Measure.Restrict import Mathlib.MeasureTheory.Measure.SeparableMeasure @@ -3447,6 +3588,7 @@ import Mathlib.NumberTheory.FLT.Basic import Mathlib.NumberTheory.FLT.Four import Mathlib.NumberTheory.FLT.Three import Mathlib.NumberTheory.FactorisationProperties +import Mathlib.NumberTheory.Fermat import Mathlib.NumberTheory.FermatPsp import Mathlib.NumberTheory.FrobeniusNumber import Mathlib.NumberTheory.FunctionField @@ -3472,6 +3614,7 @@ import Mathlib.NumberTheory.LSeries.HurwitzZetaOdd import Mathlib.NumberTheory.LSeries.HurwitzZetaValues import Mathlib.NumberTheory.LSeries.Linearity import Mathlib.NumberTheory.LSeries.MellinEqDirichlet +import Mathlib.NumberTheory.LSeries.Positivity import Mathlib.NumberTheory.LSeries.RiemannZeta import Mathlib.NumberTheory.LSeries.ZMod import Mathlib.NumberTheory.LegendreSymbol.AddCharacter @@ -3513,7 +3656,8 @@ import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.Basic import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.ConvexBody import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.FundamentalCone import Mathlib.NumberTheory.NumberField.ClassNumber -import Mathlib.NumberTheory.NumberField.Discriminant +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.FractionalIdeal @@ -3564,6 +3708,8 @@ import Mathlib.Order.Booleanisation import Mathlib.Order.Bounded import Mathlib.Order.BoundedOrder import Mathlib.Order.Bounds.Basic +import Mathlib.Order.Bounds.Defs +import Mathlib.Order.Bounds.Image import Mathlib.Order.Bounds.OrderIso import Mathlib.Order.Category.BddDistLat import Mathlib.Order.Category.BddLat @@ -3599,6 +3745,7 @@ import Mathlib.Order.Concept import Mathlib.Order.ConditionallyCompleteLattice.Basic import Mathlib.Order.ConditionallyCompleteLattice.Finset import Mathlib.Order.ConditionallyCompleteLattice.Group +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Order.Copy import Mathlib.Order.CountableDenseLinearOrder import Mathlib.Order.Cover @@ -3626,6 +3773,7 @@ import Mathlib.Order.Filter.Cofinite import Mathlib.Order.Filter.CountableInter import Mathlib.Order.Filter.CountableSeparatingOn import Mathlib.Order.Filter.Curry +import Mathlib.Order.Filter.Defs import Mathlib.Order.Filter.ENNReal import Mathlib.Order.Filter.EventuallyConst import Mathlib.Order.Filter.Extr @@ -3645,6 +3793,7 @@ import Mathlib.Order.Filter.Prod import Mathlib.Order.Filter.Ring import Mathlib.Order.Filter.SmallSets import Mathlib.Order.Filter.Subsingleton +import Mathlib.Order.Filter.Tendsto import Mathlib.Order.Filter.Ultrafilter import Mathlib.Order.Filter.ZeroAndBoundedAtFilter import Mathlib.Order.Fin.Basic @@ -3689,7 +3838,6 @@ import Mathlib.Order.Interval.Set.SurjOn import Mathlib.Order.Interval.Set.UnorderedInterval import Mathlib.Order.Interval.Set.WithBotTop import Mathlib.Order.Irreducible -import Mathlib.Order.IsWellOrderLimitElement import Mathlib.Order.Iterate import Mathlib.Order.JordanHolder import Mathlib.Order.KonigLemma @@ -3739,6 +3887,7 @@ import Mathlib.Order.SuccPred.IntervalSucc import Mathlib.Order.SuccPred.Limit import Mathlib.Order.SuccPred.LinearLocallyFinite import Mathlib.Order.SuccPred.Relation +import Mathlib.Order.SuccPred.Tree import Mathlib.Order.SupClosed import Mathlib.Order.SupIndep import Mathlib.Order.SymmDiff @@ -3755,7 +3904,6 @@ import Mathlib.Order.Zorn import Mathlib.Order.ZornAtoms import Mathlib.Probability.BorelCantelli import Mathlib.Probability.CDF -import Mathlib.Probability.CondCount import Mathlib.Probability.ConditionalExpectation import Mathlib.Probability.ConditionalProbability import Mathlib.Probability.Density @@ -3813,6 +3961,7 @@ import Mathlib.Probability.Process.HittingTime import Mathlib.Probability.Process.PartitionFiltration import Mathlib.Probability.Process.Stopping import Mathlib.Probability.StrongLaw +import Mathlib.Probability.UniformOn import Mathlib.Probability.Variance import Mathlib.RepresentationTheory.Action.Basic import Mathlib.RepresentationTheory.Action.Concrete @@ -3848,6 +3997,7 @@ import Mathlib.RingTheory.Bezout import Mathlib.RingTheory.Bialgebra.Basic import Mathlib.RingTheory.Bialgebra.Equiv import Mathlib.RingTheory.Bialgebra.Hom +import Mathlib.RingTheory.Bialgebra.TensorProduct import Mathlib.RingTheory.Binomial import Mathlib.RingTheory.ChainOfDivisors import Mathlib.RingTheory.ClassGroup @@ -3858,6 +4008,7 @@ import Mathlib.RingTheory.Coalgebra.TensorProduct import Mathlib.RingTheory.Complex import Mathlib.RingTheory.Congruence.Basic import Mathlib.RingTheory.Congruence.BigOperators +import Mathlib.RingTheory.Congruence.Defs import Mathlib.RingTheory.Congruence.Opposite import Mathlib.RingTheory.Coprime.Basic import Mathlib.RingTheory.Coprime.Ideal @@ -3881,11 +4032,14 @@ import Mathlib.RingTheory.Derivation.ToSquareZero import Mathlib.RingTheory.DiscreteValuationRing.Basic import Mathlib.RingTheory.DiscreteValuationRing.TFAE import Mathlib.RingTheory.Discriminant +import Mathlib.RingTheory.DualNumber import Mathlib.RingTheory.EisensteinCriterion import Mathlib.RingTheory.EssentialFiniteness import Mathlib.RingTheory.Etale.Basic +import Mathlib.RingTheory.Etale.Field import Mathlib.RingTheory.EuclideanDomain import Mathlib.RingTheory.Filtration +import Mathlib.RingTheory.FiniteLength import Mathlib.RingTheory.FinitePresentation import Mathlib.RingTheory.FiniteStability import Mathlib.RingTheory.FiniteType @@ -3895,6 +4049,7 @@ import Mathlib.RingTheory.Flat.Algebra import Mathlib.RingTheory.Flat.Basic import Mathlib.RingTheory.Flat.CategoryTheory import Mathlib.RingTheory.Flat.EquationalCriterion +import Mathlib.RingTheory.Flat.FaithfullyFlat import Mathlib.RingTheory.Flat.Stability import Mathlib.RingTheory.FractionalIdeal.Basic import Mathlib.RingTheory.FractionalIdeal.Extended @@ -3921,18 +4076,27 @@ import Mathlib.RingTheory.Ideal.Basic import Mathlib.RingTheory.Ideal.Basis import Mathlib.RingTheory.Ideal.Colon import Mathlib.RingTheory.Ideal.Cotangent +import Mathlib.RingTheory.Ideal.Defs import Mathlib.RingTheory.Ideal.IdempotentFG import Mathlib.RingTheory.Ideal.IsPrimary import Mathlib.RingTheory.Ideal.IsPrincipal +import Mathlib.RingTheory.Ideal.IsPrincipalPowQuotient +import Mathlib.RingTheory.Ideal.Lattice import Mathlib.RingTheory.Ideal.Maps +import Mathlib.RingTheory.Ideal.Maximal import Mathlib.RingTheory.Ideal.MinimalPrime import Mathlib.RingTheory.Ideal.Norm import Mathlib.RingTheory.Ideal.Operations import Mathlib.RingTheory.Ideal.Over import Mathlib.RingTheory.Ideal.Pointwise +import Mathlib.RingTheory.Ideal.Prime import Mathlib.RingTheory.Ideal.Prod -import Mathlib.RingTheory.Ideal.Quotient -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Basic +import Mathlib.RingTheory.Ideal.Quotient.Defs +import Mathlib.RingTheory.Ideal.Quotient.Nilpotent +import Mathlib.RingTheory.Ideal.Quotient.Noetherian +import Mathlib.RingTheory.Ideal.Quotient.Operations +import Mathlib.RingTheory.Ideal.Span import Mathlib.RingTheory.Idempotents import Mathlib.RingTheory.Int.Basic import Mathlib.RingTheory.IntegralClosure.Algebra.Basic @@ -3945,15 +4109,19 @@ import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Basic import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Defs 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.Kaehler.Basic import Mathlib.RingTheory.Kaehler.CotangentComplex import Mathlib.RingTheory.Kaehler.Polynomial +import Mathlib.RingTheory.Kaehler.TensorProduct import Mathlib.RingTheory.KrullDimension.Basic import Mathlib.RingTheory.KrullDimension.Field +import Mathlib.RingTheory.Lasker import Mathlib.RingTheory.LaurentSeries +import Mathlib.RingTheory.LinearDisjoint import Mathlib.RingTheory.LittleWedderburn import Mathlib.RingTheory.LocalProperties.Basic import Mathlib.RingTheory.LocalProperties.IntegrallyClosed @@ -3963,10 +4131,10 @@ import Mathlib.RingTheory.LocalRing.Defs import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic import Mathlib.RingTheory.LocalRing.MaximalIdeal.Defs import Mathlib.RingTheory.LocalRing.Module +import Mathlib.RingTheory.LocalRing.Quotient import Mathlib.RingTheory.LocalRing.ResidueField.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs import Mathlib.RingTheory.LocalRing.RingHom.Basic -import Mathlib.RingTheory.LocalRing.RingHom.Defs import Mathlib.RingTheory.Localization.Algebra import Mathlib.RingTheory.Localization.AsSubring import Mathlib.RingTheory.Localization.AtPrime @@ -3976,6 +4144,7 @@ import Mathlib.RingTheory.Localization.Away.Lemmas import Mathlib.RingTheory.Localization.BaseChange import Mathlib.RingTheory.Localization.Basic import Mathlib.RingTheory.Localization.Cardinality +import Mathlib.RingTheory.Localization.Defs import Mathlib.RingTheory.Localization.Finiteness import Mathlib.RingTheory.Localization.FractionRing import Mathlib.RingTheory.Localization.Ideal @@ -4061,8 +4230,6 @@ import Mathlib.RingTheory.Prime import Mathlib.RingTheory.PrimeSpectrum import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.RingTheory.QuotSMulTop -import Mathlib.RingTheory.QuotientNilpotent -import Mathlib.RingTheory.QuotientNoetherian import Mathlib.RingTheory.Radical import Mathlib.RingTheory.ReesAlgebra import Mathlib.RingTheory.Regular.IsSMulRegular @@ -4072,6 +4239,7 @@ import Mathlib.RingTheory.RingHom.FinitePresentation import Mathlib.RingTheory.RingHom.FiniteType import Mathlib.RingTheory.RingHom.Integral import Mathlib.RingTheory.RingHom.Locally +import Mathlib.RingTheory.RingHom.StandardSmooth import Mathlib.RingTheory.RingHom.Surjective import Mathlib.RingTheory.RingHomProperties import Mathlib.RingTheory.RingInvo @@ -4084,6 +4252,7 @@ import Mathlib.RingTheory.SimpleRing.Basic import Mathlib.RingTheory.SimpleRing.Defs import Mathlib.RingTheory.Smooth.Basic import Mathlib.RingTheory.Smooth.Kaehler +import Mathlib.RingTheory.Smooth.Pi import Mathlib.RingTheory.Smooth.StandardSmooth import Mathlib.RingTheory.Support import Mathlib.RingTheory.SurjectiveOnStalks @@ -4091,6 +4260,7 @@ import Mathlib.RingTheory.TensorProduct.Basic import Mathlib.RingTheory.TensorProduct.MvPolynomial import Mathlib.RingTheory.Trace.Basic import Mathlib.RingTheory.Trace.Defs +import Mathlib.RingTheory.Trace.Quotient import Mathlib.RingTheory.TwoSidedIdeal.Basic import Mathlib.RingTheory.TwoSidedIdeal.BigOperators import Mathlib.RingTheory.TwoSidedIdeal.Instances @@ -4098,7 +4268,6 @@ import Mathlib.RingTheory.TwoSidedIdeal.Lattice import Mathlib.RingTheory.TwoSidedIdeal.Operations import Mathlib.RingTheory.UniqueFactorizationDomain import Mathlib.RingTheory.Unramified.Basic -import Mathlib.RingTheory.Unramified.Derivations import Mathlib.RingTheory.Unramified.Field import Mathlib.RingTheory.Unramified.Finite import Mathlib.RingTheory.Unramified.Pi @@ -4134,6 +4303,8 @@ import Mathlib.RingTheory.WittVector.Truncated import Mathlib.RingTheory.WittVector.Verschiebung import Mathlib.RingTheory.WittVector.WittPolynomial import Mathlib.RingTheory.ZMod +import Mathlib.SetTheory.Cardinal.Aleph +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Basic import Mathlib.SetTheory.Cardinal.Cofinality import Mathlib.SetTheory.Cardinal.Continuum @@ -4142,7 +4313,7 @@ import Mathlib.SetTheory.Cardinal.Divisibility import Mathlib.SetTheory.Cardinal.ENat import Mathlib.SetTheory.Cardinal.Finite import Mathlib.SetTheory.Cardinal.Finsupp -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Free import Mathlib.SetTheory.Cardinal.PartENat import Mathlib.SetTheory.Cardinal.SchroederBernstein import Mathlib.SetTheory.Cardinal.Subfield @@ -4161,6 +4332,7 @@ import Mathlib.SetTheory.Lists import Mathlib.SetTheory.Ordinal.Arithmetic import Mathlib.SetTheory.Ordinal.Basic import Mathlib.SetTheory.Ordinal.CantorNormalForm +import Mathlib.SetTheory.Ordinal.Enum import Mathlib.SetTheory.Ordinal.Exponential import Mathlib.SetTheory.Ordinal.FixedPoint import Mathlib.SetTheory.Ordinal.FixedPointApproximants @@ -4168,6 +4340,7 @@ import Mathlib.SetTheory.Ordinal.NaturalOps import Mathlib.SetTheory.Ordinal.Nimber import Mathlib.SetTheory.Ordinal.Notation import Mathlib.SetTheory.Ordinal.Principal +import Mathlib.SetTheory.Ordinal.Rank import Mathlib.SetTheory.Ordinal.Topology import Mathlib.SetTheory.Surreal.Basic import Mathlib.SetTheory.Surreal.Dyadic @@ -4241,6 +4414,7 @@ import Mathlib.Tactic.Contrapose import Mathlib.Tactic.Conv import Mathlib.Tactic.Convert import Mathlib.Tactic.Core +import Mathlib.Tactic.DeclarationNames import Mathlib.Tactic.DefEqTransformations import Mathlib.Tactic.DeprecateMe import Mathlib.Tactic.DeriveFintype @@ -4260,6 +4434,8 @@ import Mathlib.Tactic.FailIfNoProgress import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.FinCases import Mathlib.Tactic.Find +import Mathlib.Tactic.Finiteness +import Mathlib.Tactic.Finiteness.Attr import Mathlib.Tactic.FunProp import Mathlib.Tactic.FunProp.Attr import Mathlib.Tactic.FunProp.ContDiff @@ -4319,9 +4495,12 @@ import Mathlib.Tactic.Linter.FlexibleLinter import Mathlib.Tactic.Linter.GlobalAttributeIn import Mathlib.Tactic.Linter.HashCommandLinter import Mathlib.Tactic.Linter.HaveLetLinter +import Mathlib.Tactic.Linter.Header import Mathlib.Tactic.Linter.Lint import Mathlib.Tactic.Linter.MinImports +import Mathlib.Tactic.Linter.Multigoal import Mathlib.Tactic.Linter.OldObtain +import Mathlib.Tactic.Linter.PPRoundtrip import Mathlib.Tactic.Linter.RefineLinter import Mathlib.Tactic.Linter.Style import Mathlib.Tactic.Linter.TextBased @@ -4355,6 +4534,7 @@ import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.NatSqrt import Mathlib.Tactic.NormNum.OfScientific import Mathlib.Tactic.NormNum.Pow +import Mathlib.Tactic.NormNum.PowMod import Mathlib.Tactic.NormNum.Prime import Mathlib.Tactic.NormNum.Result import Mathlib.Tactic.NthRewrite @@ -4379,7 +4559,6 @@ import Mathlib.Tactic.ReduceModChar import Mathlib.Tactic.ReduceModChar.Ext import Mathlib.Tactic.Relation.Rfl import Mathlib.Tactic.Relation.Symm -import Mathlib.Tactic.Relation.Trans import Mathlib.Tactic.Rename import Mathlib.Tactic.RenameBVar import Mathlib.Tactic.Replace @@ -4387,6 +4566,7 @@ import Mathlib.Tactic.RewriteSearch import Mathlib.Tactic.Rify import Mathlib.Tactic.Ring import Mathlib.Tactic.Ring.Basic +import Mathlib.Tactic.Ring.Compare import Mathlib.Tactic.Ring.PNat import Mathlib.Tactic.Ring.RingNF import Mathlib.Tactic.Sat.FromLRAT @@ -4442,6 +4622,7 @@ import Mathlib.Topology.Algebra.Affine import Mathlib.Topology.Algebra.Algebra import Mathlib.Topology.Algebra.Algebra.Rat import Mathlib.Topology.Algebra.Category.ProfiniteGrp.Basic +import Mathlib.Topology.Algebra.ClopenNhdofOne import Mathlib.Topology.Algebra.ClosedSubgroup import Mathlib.Topology.Algebra.ConstMulAction import Mathlib.Topology.Algebra.Constructions @@ -4454,6 +4635,7 @@ import Mathlib.Topology.Algebra.FilterBasis import Mathlib.Topology.Algebra.Group.Basic import Mathlib.Topology.Algebra.Group.Compact import Mathlib.Topology.Algebra.Group.OpenMapping +import Mathlib.Topology.Algebra.Group.Quotient import Mathlib.Topology.Algebra.Group.SubmonoidClosure import Mathlib.Topology.Algebra.Group.TopologicalAbelianization import Mathlib.Topology.Algebra.GroupCompletion @@ -4480,6 +4662,7 @@ import Mathlib.Topology.Algebra.Module.Determinant import Mathlib.Topology.Algebra.Module.FiniteDimension import Mathlib.Topology.Algebra.Module.LinearPMap import Mathlib.Topology.Algebra.Module.LocallyConvex +import Mathlib.Topology.Algebra.Module.ModuleTopology import Mathlib.Topology.Algebra.Module.Multilinear.Basic import Mathlib.Topology.Algebra.Module.Multilinear.Bounded import Mathlib.Topology.Algebra.Module.Multilinear.Topology @@ -4496,29 +4679,31 @@ import Mathlib.Topology.Algebra.Nonarchimedean.AdicTopology import Mathlib.Topology.Algebra.Nonarchimedean.Bases import Mathlib.Topology.Algebra.Nonarchimedean.Basic import Mathlib.Topology.Algebra.Nonarchimedean.Completion +import Mathlib.Topology.Algebra.Nonarchimedean.TotallyDisconnected import Mathlib.Topology.Algebra.OpenSubgroup import Mathlib.Topology.Algebra.Order.Archimedean -import Mathlib.Topology.Algebra.Order.Compact import Mathlib.Topology.Algebra.Order.Field import Mathlib.Topology.Algebra.Order.Floor import Mathlib.Topology.Algebra.Order.Group import Mathlib.Topology.Algebra.Order.LiminfLimsup -import Mathlib.Topology.Algebra.Order.Rolle import Mathlib.Topology.Algebra.Order.UpperLower import Mathlib.Topology.Algebra.Polynomial import Mathlib.Topology.Algebra.PontryaginDual -import Mathlib.Topology.Algebra.ProperAction +import Mathlib.Topology.Algebra.ProperAction.Basic +import Mathlib.Topology.Algebra.ProperAction.ProperlyDiscontinuous import Mathlib.Topology.Algebra.ProperConstSMul import Mathlib.Topology.Algebra.Ring.Basic import Mathlib.Topology.Algebra.Ring.Ideal import Mathlib.Topology.Algebra.Semigroup -import Mathlib.Topology.Algebra.SeparationQuotient +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.UniformConvergence import Mathlib.Topology.Algebra.UniformField import Mathlib.Topology.Algebra.UniformFilterBasis -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Topology.Algebra.UniformGroup.Basic +import Mathlib.Topology.Algebra.UniformGroup.Defs import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Topology.Algebra.UniformRing import Mathlib.Topology.Algebra.Valued.NormedValued @@ -4589,6 +4774,7 @@ import Mathlib.Topology.Clopen import Mathlib.Topology.ClopenBox import Mathlib.Topology.CompactOpen import Mathlib.Topology.Compactification.OnePoint +import Mathlib.Topology.Compactification.OnePointEquiv import Mathlib.Topology.Compactness.Compact import Mathlib.Topology.Compactness.CompactlyGeneratedSpace import Mathlib.Topology.Compactness.Exterior @@ -4613,6 +4799,7 @@ import Mathlib.Topology.ContinuousMap.CocompactMap import Mathlib.Topology.ContinuousMap.Compact import Mathlib.Topology.ContinuousMap.CompactlySupported import Mathlib.Topology.ContinuousMap.ContinuousMapZero +import Mathlib.Topology.ContinuousMap.Defs import Mathlib.Topology.ContinuousMap.Ideals import Mathlib.Topology.ContinuousMap.LocallyConstant import Mathlib.Topology.ContinuousMap.Ordered @@ -4650,9 +4837,12 @@ import Mathlib.Topology.FiberBundle.IsHomeomorphicTrivialBundle import Mathlib.Topology.FiberBundle.Trivialization import Mathlib.Topology.FiberPartition import Mathlib.Topology.Filter -import Mathlib.Topology.GDelta +import Mathlib.Topology.GDelta.Basic +import Mathlib.Topology.GDelta.UniformSpace import Mathlib.Topology.Germ import Mathlib.Topology.Gluing +import Mathlib.Topology.Hom.ContinuousEval +import Mathlib.Topology.Hom.ContinuousEvalConst import Mathlib.Topology.Hom.Open import Mathlib.Topology.Homeomorph import Mathlib.Topology.Homotopy.Basic @@ -4684,8 +4874,10 @@ import Mathlib.Topology.Instances.RealVectorSpace import Mathlib.Topology.Instances.Sign import Mathlib.Topology.Instances.TrivSqZeroExt import Mathlib.Topology.Instances.ZMod +import Mathlib.Topology.Instances.ZMultiples import Mathlib.Topology.Irreducible import Mathlib.Topology.IsLocalHomeomorph +import Mathlib.Topology.JacobsonSpace import Mathlib.Topology.KrullDimension import Mathlib.Topology.List import Mathlib.Topology.LocalAtTarget @@ -4696,6 +4888,7 @@ import Mathlib.Topology.LocallyFinite import Mathlib.Topology.Maps.Basic import Mathlib.Topology.Maps.OpenQuotient import Mathlib.Topology.Maps.Proper.Basic +import Mathlib.Topology.Maps.Proper.CompactlyGenerated import Mathlib.Topology.Maps.Proper.UniversallyClosed import Mathlib.Topology.MetricSpace.Algebra import Mathlib.Topology.MetricSpace.Antilipschitz @@ -4718,6 +4911,7 @@ import Mathlib.Topology.MetricSpace.GromovHausdorffRealized import Mathlib.Topology.MetricSpace.HausdorffDimension import Mathlib.Topology.MetricSpace.HausdorffDistance import Mathlib.Topology.MetricSpace.Holder +import Mathlib.Topology.MetricSpace.HolderNorm import Mathlib.Topology.MetricSpace.Infsep import Mathlib.Topology.MetricSpace.IsometricSMul import Mathlib.Topology.MetricSpace.Isometry @@ -4742,7 +4936,7 @@ import Mathlib.Topology.MetricSpace.ThickenedIndicator import Mathlib.Topology.MetricSpace.Thickening import Mathlib.Topology.MetricSpace.Ultra.Basic import Mathlib.Topology.MetricSpace.Ultra.ContinuousMaps -import Mathlib.Topology.MetricSpace.Ultra.TotallyDisconnected +import Mathlib.Topology.MetricSpace.Ultra.TotallySeparated import Mathlib.Topology.Metrizable.Basic import Mathlib.Topology.Metrizable.ContinuousMap import Mathlib.Topology.Metrizable.Uniformity @@ -4756,6 +4950,7 @@ import Mathlib.Topology.Order.Bornology import Mathlib.Topology.Order.Bounded import Mathlib.Topology.Order.Category.AlexDisc import Mathlib.Topology.Order.Category.FrameAdjunction +import Mathlib.Topology.Order.Compact import Mathlib.Topology.Order.DenselyOrdered import Mathlib.Topology.Order.ExtendFrom import Mathlib.Topology.Order.ExtrClosure @@ -4776,9 +4971,11 @@ import Mathlib.Topology.Order.MonotoneContinuity import Mathlib.Topology.Order.MonotoneConvergence import Mathlib.Topology.Order.NhdsSet import Mathlib.Topology.Order.OrderClosed +import Mathlib.Topology.Order.OrderClosedExtr import Mathlib.Topology.Order.PartialSups import Mathlib.Topology.Order.Priestley import Mathlib.Topology.Order.ProjIcc +import Mathlib.Topology.Order.Rolle import Mathlib.Topology.Order.ScottTopology import Mathlib.Topology.Order.T5 import Mathlib.Topology.Order.UpperLowerSetTopology @@ -4791,7 +4988,8 @@ import Mathlib.Topology.QuasiSeparated import Mathlib.Topology.RestrictGen import Mathlib.Topology.Semicontinuous import Mathlib.Topology.SeparatedMap -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic +import Mathlib.Topology.Separation.GDelta import Mathlib.Topology.Separation.NotNormal import Mathlib.Topology.Sequences import Mathlib.Topology.Sets.Closeds diff --git a/Mathlib/Algebra/AddTorsor.lean b/Mathlib/Algebra/AddTorsor.lean index ed65a54d0f15f..d615b53f28671 100644 --- a/Mathlib/Algebra/AddTorsor.lean +++ b/Mathlib/Algebra/AddTorsor.lean @@ -54,9 +54,6 @@ class AddTorsor (G : outParam Type*) (P : Type*) [AddGroup G] extends AddAction -- Porting note(#12096): removed `nolint instance_priority`; lint not ported yet attribute [instance 100] AddTorsor.nonempty --- Porting note(#12094): removed nolint; dangerous_instance linter not ported yet ---attribute [nolint dangerous_instance] AddTorsor.toVSub - /-- An `AddGroup G` is a torsor for itself. -/ -- Porting note(#12096): linter not ported yet --@[nolint instance_priority] @@ -168,8 +165,6 @@ namespace Set open Pointwise --- porting note (#10618): simp can prove this ---@[simp] theorem singleton_vsub_self (p : P) : ({p} : Set P) -ᵥ {p} = {(0 : G)} := by rw [Set.singleton_vsub_singleton, vsub_self] diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean index f4a24f5977006..e9e129ad5c0fd 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -9,6 +9,7 @@ import Mathlib.Algebra.Module.Equiv.Basic import Mathlib.Algebra.Module.Submodule.Ker import Mathlib.Algebra.Module.Submodule.RestrictScalars import Mathlib.Algebra.Module.ULift +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Ring.Subring.Basic import Mathlib.Data.Nat.Cast.Order.Basic import Mathlib.Data.Int.CharZero @@ -479,8 +480,8 @@ def LinearMap.extendScalarsOfSurjectiveEquiv (h : Function.Surjective (algebraMa map_add' _ _ := rfl map_smul' _ _ := rfl invFun f := f.restrictScalars S - left_inv f := rfl - right_inv f := rfl + left_inv _ := rfl + right_inv _ := rfl /-- If `R →+* S` is surjective, then `R`-linear maps are also `S`-linear. -/ abbrev LinearMap.extendScalarsOfSurjective (h : Function.Surjective (algebraMap R S)) diff --git a/Mathlib/Algebra/Algebra/Bilinear.lean b/Mathlib/Algebra/Algebra/Bilinear.lean index 65e3fda3f286f..82c8c45e63e1c 100644 --- a/Mathlib/Algebra/Algebra/Bilinear.lean +++ b/Mathlib/Algebra/Algebra/Bilinear.lean @@ -215,6 +215,9 @@ theorem pow_mulRight (a : A) (n : ℕ) : mulRight R a ^ n = mulRight R (a ^ n) : exact LinearMap.coe_injective (((mulRight R a).coe_pow n).symm ▸ mul_right_iterate a n) +theorem toSpanSingleton_eq_algebra_linearMap : toSpanSingleton R A 1 = Algebra.linearMap R A := by + ext; simp + end Semiring section Ring diff --git a/Mathlib/Algebra/Algebra/Defs.lean b/Mathlib/Algebra/Algebra/Defs.lean index 0393439d7bb1f..9683ddd51e176 100644 --- a/Mathlib/Algebra/Algebra/Defs.lean +++ b/Mathlib/Algebra/Algebra/Defs.lean @@ -237,7 +237,8 @@ theorem algebra_ext {R : Type*} [CommSemiring R] {A : Type*} [Semiring A] (P Q : congr -- see Note [lower instance priority] -instance (priority := 200) toModule : Module R A where +instance (priority := 200) toModule {R A} {_ : CommSemiring R} {_ : Semiring A} [Algebra R A] : + Module R A where one_smul _ := by simp [smul_def'] mul_smul := by simp [smul_def', mul_assoc] smul_add := by simp [smul_def', mul_add] diff --git a/Mathlib/Algebra/Algebra/Equiv.lean b/Mathlib/Algebra/Algebra/Equiv.lean index d19412446121d..e2b8615f7f94f 100644 --- a/Mathlib/Algebra/Algebra/Equiv.lean +++ b/Mathlib/Algebra/Algebra/Equiv.lean @@ -44,8 +44,6 @@ class AlgEquivClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [Semir /-- An equivalence of algebras commutes with the action of scalars. -/ commutes : ∀ (f : F) (r : R), f (algebraMap R A r) = algebraMap R B r --- Porting note: Removed nolint dangerousInstance from AlgEquivClass.toRingEquivClass - namespace AlgEquivClass -- See note [lower instance priority] @@ -132,7 +130,6 @@ theorem mk_coe (e : A₁ ≃ₐ[R] A₂) (e' h₁ h₂ h₃ h₄ h₅) : theorem toEquiv_eq_coe : e.toEquiv = e := rfl --- Porting note: `protected` used to be an attribute below @[simp] protected theorem coe_coe {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] (f : F) : ⇑(f : A₁ ≃ₐ[R] A₂) = f := @@ -141,7 +138,6 @@ protected theorem coe_coe {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R theorem coe_fun_injective : @Function.Injective (A₁ ≃ₐ[R] A₂) (A₁ → A₂) fun e => (e : A₁ → A₂) := DFunLike.coe_injective --- Porting note: Made to CoeOut instance from Coe, not dangerous anymore instance hasCoeToRingEquiv : CoeOut (A₁ ≃ₐ[R] A₂) (A₁ ≃+* A₂) := ⟨AlgEquiv.toRingEquiv⟩ @@ -219,7 +215,6 @@ protected theorem map_mul : ∀ x y, e (x * y) = e x * e y := protected theorem map_one : e 1 = 1 := map_one e --- @[simp] -- Porting note (#10618): simp can prove this @[deprecated map_smul (since := "2024-06-20")] protected theorem map_smul (r : R) (x : A₁) : e (r • x) = r • e x := map_smul _ _ _ @@ -288,13 +283,13 @@ def symm (e : A₁ ≃ₐ[R] A₂) : A₂ ≃ₐ[R] A₁ := theorem invFun_eq_symm {e : A₁ ≃ₐ[R] A₂} : e.invFun = e.symm := rfl ---@[simp] -- Porting note (#10618): simp can prove this once symm_mk is introduced +@[simp] theorem coe_apply_coe_coe_symm_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] (f : F) (x : A₂) : f ((f : A₁ ≃ₐ[R] A₂).symm x) = x := EquivLike.right_inv f x ---@[simp] -- Porting note (#10618): simp can prove this once symm_mk is introduced +@[simp] theorem coe_coe_symm_apply_coe_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] (f : F) (x : A₁) : (f : A₁ ≃ₐ[R] A₂).symm (f x) = x := @@ -625,10 +620,10 @@ end OfRingEquiv -- @[simps (config := .lemmasOnly) one] instance aut : Group (A₁ ≃ₐ[R] A₁) where mul ϕ ψ := ψ.trans ϕ - mul_assoc ϕ ψ χ := rfl + mul_assoc _ _ _ := rfl one := refl - one_mul ϕ := ext fun x => rfl - mul_one ϕ := ext fun x => rfl + one_mul _ := ext fun _ => rfl + mul_one _ := ext fun _ => rfl inv := symm inv_mul_cancel ϕ := ext <| symm_apply_apply ϕ @@ -801,6 +796,18 @@ theorem toAlgEquiv_injective [FaithfulSMul G A] : Function.Injective (MulSemiringAction.toAlgEquiv R A : G → A ≃ₐ[R] A) := fun _ _ h => eq_of_smul_eq_smul fun r => AlgEquiv.ext_iff.1 h r +variable (G) + +/-- Each element of the group defines an algebra equivalence. + +This is a stronger version of `MulSemiringAction.toRingAut` and +`DistribMulAction.toModuleEnd`. -/ +@[simps] +def toAlgAut : G →* A ≃ₐ[R] A where + toFun := toAlgEquiv R A + map_one' := AlgEquiv.ext <| one_smul _ + map_mul' g h := AlgEquiv.ext <| mul_smul g h + end end MulSemiringAction diff --git a/Mathlib/Algebra/Algebra/Hom.lean b/Mathlib/Algebra/Algebra/Hom.lean index 0942b526635de..96b78e4f6c6d4 100644 --- a/Mathlib/Algebra/Algebra/Hom.lean +++ b/Mathlib/Algebra/Algebra/Hom.lean @@ -45,10 +45,9 @@ class AlgHomClass (F : Type*) (R A B : outParam Type*) [FunLike F A B] extends RingHomClass F A B : Prop where commutes : ∀ (f : F) (r : R), f (algebraMap R A r) = algebraMap R B r --- Porting note: `dangerousInstance` linter has become smarter about `outParam`s --- attribute [nolint dangerousInstance] AlgHomClass.toRingHomClass - --- Porting note (#10618): simp can prove this +-- For now, don't replace `AlgHom.commutes` and `AlgHomClass.commutes` with the more generic lemma. +-- The file `Mathlib.NumberTheory.NumberField.CanonicalEmbedding.FundamentalCone` slows down by +-- 15% if we would do so (see benchmark on PR #18040). -- attribute [simp] AlgHomClass.commutes namespace AlgHomClass @@ -85,8 +84,6 @@ section Semiring variable [CommSemiring R] [Semiring A] [Semiring B] [Semiring C] [Semiring D] variable [Algebra R A] [Algebra R B] [Algebra R C] [Algebra R D] --- Porting note: we don't port specialized `CoeFun` instances if there is `DFunLike` instead - instance funLike : FunLike (A →ₐ[R] B) A B where coe f := f.toFun coe_injective' f g h := by @@ -221,7 +218,6 @@ protected theorem map_one : φ 1 = 1 := protected theorem map_pow (x : A) (n : ℕ) : φ (x ^ n) = φ x ^ n := map_pow _ _ _ --- @[simp] -- Porting note (#10618): simp can prove this @[deprecated map_smul (since := "2024-06-26")] protected theorem map_smul (r : R) (x : A) : φ (r • x) = r • φ x := map_smul _ _ _ @@ -354,10 +350,10 @@ protected theorem map_list_prod (s : List A) : φ s.prod = (s.map φ).prod := @[simps (config := .lemmasOnly) toSemigroup_toMul_mul toOne_one] instance End : Monoid (A →ₐ[R] A) where mul := comp - mul_assoc ϕ ψ χ := rfl + mul_assoc _ _ _ := rfl one := AlgHom.id R A - one_mul ϕ := rfl - mul_one ϕ := rfl + one_mul _ := rfl + mul_one _ := rfl @[simp] theorem one_apply (x : A) : (1 : A →ₐ[R] A) x = x := diff --git a/Mathlib/Algebra/Algebra/NonUnitalHom.lean b/Mathlib/Algebra/Algebra/NonUnitalHom.lean index 34a5518dc4de3..157c90299af2a 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalHom.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalHom.lean @@ -80,12 +80,8 @@ abbrev NonUnitalAlgHomClass (F : Type*) (R A B : outParam Type*) [DistribMulAction R A] [DistribMulAction R B] [FunLike F A B] := NonUnitalAlgSemiHomClass F (MonoidHom.id R) A B --- Porting note: commented out, not dangerous --- attribute [nolint dangerousInstance] NonUnitalAlgHomClass.toMulHomClass - namespace NonUnitalAlgHomClass --- Porting note: Made following instance non-dangerous through [...] -> [...] replacement -- See note [lower instance priority] instance (priority := 100) toNonUnitalRingHomClass {F R S A B : Type*} {_ : Monoid R} {_ : Monoid S} {φ : outParam (R →* S)} @@ -156,11 +152,6 @@ variable [NonUnitalNonAssocSemiring A] [DistribMulAction R A] variable [NonUnitalNonAssocSemiring B] [DistribMulAction S B] variable [NonUnitalNonAssocSemiring C] [DistribMulAction T C] --- Porting note: Replaced with DFunLike instance --- /-- see Note [function coercion] -/ --- instance : CoeFun (A →ₙₐ[R] B) fun _ => A → B := --- ⟨toFun⟩ - instance : DFunLike (A →ₛₙₐ[φ] B) A fun _ => B where coe f := f.toFun coe_injective' := by rintro ⟨⟨⟨f, _⟩, _⟩, _⟩ ⟨⟨⟨g, _⟩, _⟩, _⟩ h; congr @@ -250,19 +241,16 @@ theorem coe_mulHom_mk (f : A →ₛₙₐ[φ] B) (h₁ h₂ h₃ h₄) : ((⟨⟨⟨f, h₁⟩, h₂, h₃⟩, h₄⟩ : A →ₛₙₐ[φ] B) : A →ₙ* B) = ⟨f, h₄⟩ := by rfl --- @[simp] -- Porting note (#10618) : simp can prove this +@[simp] -- Marked as `@[simp]` because `MulActionSemiHomClass.map_smulₛₗ` can't be. protected theorem map_smul (f : A →ₛₙₐ[φ] B) (c : R) (x : A) : f (c • x) = (φ c) • f x := map_smulₛₗ _ _ _ --- @[simp] -- Porting note (#10618) : simp can prove this protected theorem map_add (f : A →ₛₙₐ[φ] B) (x y : A) : f (x + y) = f x + f y := map_add _ _ _ --- @[simp] -- Porting note (#10618) : simp can prove this protected theorem map_mul (f : A →ₛₙₐ[φ] B) (x y : A) : f (x * y) = f x * f y := map_mul _ _ _ --- @[simp] -- Porting note (#10618) : simp can prove this protected theorem map_zero (f : A →ₛₙₐ[φ] B) : f 0 = 0 := map_zero _ diff --git a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean index d7beda182c549..d1fc4f0c9f0a5 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean @@ -523,16 +523,17 @@ def adjoin (s : Set A) : NonUnitalSubalgebra R A := @fun a b (ha : a ∈ Submodule.span R (NonUnitalSubsemiring.closure s : Set A)) (hb : b ∈ Submodule.span R (NonUnitalSubsemiring.closure s : Set A)) => show a * b ∈ Submodule.span R (NonUnitalSubsemiring.closure s : Set A) by - refine Submodule.span_induction ha ?_ ?_ ?_ ?_ - · refine Submodule.span_induction hb ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ ha + · refine Submodule.span_induction ?_ ?_ ?_ ?_ hb · exact fun x (hx : x ∈ NonUnitalSubsemiring.closure s) y (hy : y ∈ NonUnitalSubsemiring.closure s) => Submodule.subset_span (mul_mem hy hx) · exact fun x _hx => (mul_zero x).symm ▸ Submodule.zero_mem _ - · exact fun x y hx hy z hz => (mul_add z x y).symm ▸ add_mem (hx z hz) (hy z hz) - · exact fun r x hx y hy => (mul_smul_comm r y x).symm ▸ SMulMemClass.smul_mem r (hx y hy) + · exact fun x y _ _ hx hy z hz => (mul_add z x y).symm ▸ add_mem (hx z hz) (hy z hz) + · exact fun r x _ hx y hy => + (mul_smul_comm r y x).symm ▸ SMulMemClass.smul_mem r (hx y hy) · exact (zero_mul b).symm ▸ Submodule.zero_mem _ - · exact fun x y => (add_mul x y b).symm ▸ add_mem - · exact fun r x hx => (smul_mul_assoc r x b).symm ▸ SMulMemClass.smul_mem r hx } + · exact fun x y _ _ => (add_mul x y b).symm ▸ add_mem + · exact fun r x _ hx => (smul_mul_assoc r x b).symm ▸ SMulMemClass.smul_mem r hx } theorem adjoin_toSubmodule (s : Set A) : (adjoin R s).toSubmodule = Submodule.span R (NonUnitalSubsemiring.closure s : Set A) := @@ -547,59 +548,6 @@ theorem self_mem_adjoin_singleton (x : A) : x ∈ adjoin R ({x} : Set A) := variable {R} -/-- If some predicate holds for all `x ∈ (s : Set A)` and this predicate is closed under the -`algebraMap`, addition, multiplication and star operations, then it holds for `a ∈ adjoin R s`. -/ -@[elab_as_elim] -theorem adjoin_induction {s : Set A} {p : A → Prop} {a : A} (h : a ∈ adjoin R s) - (mem : ∀ x ∈ s, p x) (add : ∀ x y, p x → p y → p (x + y)) (zero : p 0) - (mul : ∀ x y, p x → p y → p (x * y)) (smul : ∀ (r : R) x, p x → p (r • x)) : p a := - Submodule.span_induction h - (fun _a ha => NonUnitalSubsemiring.closure_induction ha mem zero add mul) zero add smul - -@[elab_as_elim] -theorem adjoin_induction₂ {s : Set A} {p : A → A → Prop} {a b : A} (ha : a ∈ adjoin R s) - (hb : b ∈ adjoin R s) (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H0_left : ∀ y, p 0 y) - (H0_right : ∀ x, p x 0) (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) - (Hsmul_left : ∀ (r : R) x y, p x y → p (r • x) y) - (Hsmul_right : ∀ (r : R) x y, p x y → p x (r • y)) : p a b := - Submodule.span_induction₂ ha hb - (fun _x hx _y hy => - NonUnitalSubsemiring.closure_induction₂ hx hy Hs H0_left H0_right Hadd_left Hadd_right - Hmul_left Hmul_right) - H0_left H0_right Hadd_left Hadd_right Hsmul_left Hsmul_right - -/-- The difference with `NonUnitalAlgebra.adjoin_induction` is that this acts on the subtype. -/ -@[elab_as_elim] -lemma adjoin_induction_subtype {s : Set A} {p : adjoin R s → Prop} (a : adjoin R s) - (mem : ∀ x (h : x ∈ s), p ⟨x, subset_adjoin R h⟩) - (add : ∀ x y, p x → p y → p (x + y)) (zero : p 0) - (mul : ∀ x y, p x → p y → p (x * y)) (smul : ∀ (r : R) x, p x → p (r • x)) : p a := - Subtype.recOn a fun b hb => by - refine Exists.elim ?_ (fun (hb : b ∈ adjoin R s) (hc : p ⟨b, hb⟩) => hc) - refine adjoin_induction hb ?_ ?_ ?_ ?_ ?_ - · exact fun x hx => ⟨subset_adjoin R hx, mem x hx⟩ - · exact fun x y hx hy => Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => - ⟨add_mem hx' hy', add _ _ hx hy⟩ - · exact ⟨_, zero⟩ - · exact fun x y hx hy => Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => - ⟨mul_mem hx' hy', mul _ _ hx hy⟩ - · exact fun r x hx => Exists.elim hx fun hx' hx => - ⟨SMulMemClass.smul_mem r hx', smul r _ hx⟩ - -/-- A dependent version of `NonUnitalAlgebra.adjoin_induction`. -/ -theorem adjoin_induction' {s : Set A} {p : ∀ x, x ∈ adjoin R s → Prop} - (mem : ∀ (x) (h : x ∈ s), p x (subset_adjoin R h)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem ‹_› ‹_›)) - (zero : p 0 (zero_mem _)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem ‹_› ‹_›)) - (smul : ∀ (r : R) (x hx), p x hx → p (r • x) (SMulMemClass.smul_mem _ ‹_›)) - {a} (ha : a ∈ adjoin R s) : p a ha := - adjoin_induction_subtype ⟨a, ha⟩ (p := fun x ↦ p x.1 x.2) mem (fun x y ↦ add x.1 x.2 y.1 y.2) - zero (fun x y ↦ mul x.1 x.2 y.1 y.2) (fun r x ↦ smul r x.1 x.2) - protected theorem gc : GaloisConnection (adjoin R : Set A → NonUnitalSubalgebra R A) (↑) := fun s S => ⟨fun H => (NonUnitalSubsemiring.subset_closure.trans Submodule.subset_span).trans H, @@ -629,21 +577,80 @@ theorem adjoin_union (s t : Set A) : adjoin R (s ∪ t) = adjoin R s ⊔ adjoin lemma adjoin_eq (s : NonUnitalSubalgebra R A) : adjoin R (s : Set A) = s := le_antisymm (adjoin_le le_rfl) (subset_adjoin R) +/-- If some predicate holds for all `x ∈ (s : Set A)` and this predicate is closed under the +`algebraMap`, addition, multiplication and star operations, then it holds for `a ∈ adjoin R s`. -/ +@[elab_as_elim] +theorem adjoin_induction {s : Set A} {p : (x : A) → x ∈ adjoin R s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_adjoin R hx)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) (zero : p 0 (zero_mem _)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + (smul : ∀ r x hx, p x hx → p (r • x) (SMulMemClass.smul_mem r hx)) + {x} (hx : x ∈ adjoin R s) : p x hx := + let S : NonUnitalSubalgebra R A := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := (Exists.elim · fun _ ha ↦ (Exists.elim · fun _ hb ↦ ⟨_, mul _ _ _ _ ha hb⟩)) + add_mem' := (Exists.elim · fun _ ha ↦ (Exists.elim · fun _ hb ↦ ⟨_, add _ _ _ _ ha hb⟩)) + smul_mem' := fun r ↦ (Exists.elim · fun _ hb ↦ ⟨_, smul r _ _ hb⟩) + zero_mem' := ⟨_, zero⟩ } + adjoin_le (S := S) (fun y hy ↦ ⟨subset_adjoin R hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated adjoin_induction (since := "2024-10-10")] +alias adjoin_induction' := adjoin_induction + +@[elab_as_elim] +theorem adjoin_induction₂ {s : Set A} {p : ∀ x y, x ∈ adjoin R s → y ∈ adjoin R s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_adjoin R hx) (subset_adjoin R hy)) + (zero_left : ∀ x hx, p 0 x (zero_mem _) hx) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + (smul_left : ∀ r x y hx hy, p x y hx hy → p (r • x) y (SMulMemClass.smul_mem r hx) hy) + (smul_right : ∀ r x y hx hy, p x y hx hy → p x (r • y) hx (SMulMemClass.smul_mem r hy)) + {x y : A} (hx : x ∈ adjoin R s) (hy : y ∈ adjoin R s) : + p x y hx hy := by + induction hy using adjoin_induction with + | mem z hz => + induction hx using adjoin_induction with + | mem _ h => exact mem_mem _ _ h hz + | zero => exact zero_left _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | smul _ _ _ h => exact smul_left _ _ _ _ _ h + | zero => exact zero_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ + | smul _ _ _ h => exact smul_right _ _ _ _ _ h + +/-- The difference with `NonUnitalAlgebra.adjoin_induction` is that this acts on the subtype. -/ +@[elab_as_elim, deprecated adjoin_induction (since := "2024-10-11")] +lemma adjoin_induction_subtype {s : Set A} {p : adjoin R s → Prop} (a : adjoin R s) + (mem : ∀ x (h : x ∈ s), p ⟨x, subset_adjoin R h⟩) + (add : ∀ x y, p x → p y → p (x + y)) (zero : p 0) + (mul : ∀ x y, p x → p y → p (x * y)) (smul : ∀ (r : R) x, p x → p (r • x)) : p a := + Subtype.recOn a fun b hb => by + induction hb using adjoin_induction with + | mem _ h => exact mem _ h + | zero => exact zero + | mul _ _ _ _ h₁ h₂ => exact mul _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add _ _ h₁ h₂ + | smul _ _ _ h => exact smul _ _ h + open Submodule in lemma adjoin_eq_span (s : Set A) : (adjoin R s).toSubmodule = span R (Subsemigroup.closure s) := by apply le_antisymm · intro x hx - induction hx using adjoin_induction' with + induction hx using adjoin_induction with | mem x hx => exact subset_span <| Subsemigroup.subset_closure hx - | add x _ y _ hpx hpy => exact add_mem hpx hpy + | add x y _ _ hpx hpy => exact add_mem hpx hpy | zero => exact zero_mem _ - | mul x _ y _ hpx hpy => - apply span_induction₂ hpx hpy ?Hs (by simp) (by simp) ?Hadd_l ?Hadd_r ?Hsmul_l ?Hsmul_r - case Hs => exact fun x hx y hy ↦ subset_span <| mul_mem hx hy - case Hadd_l => exact fun x y z hxz hyz ↦ by simpa [add_mul] using add_mem hxz hyz - case Hadd_r => exact fun x y z hxz hyz ↦ by simpa [mul_add] using add_mem hxz hyz - case Hsmul_l => exact fun r x y hxy ↦ by simpa [smul_mul_assoc] using smul_mem _ _ hxy - case Hsmul_r => exact fun r x y hxy ↦ by simpa [mul_smul_comm] using smul_mem _ _ hxy + | mul x y _ _ hpx hpy => + apply span_induction₂ ?Hs (by simp) (by simp) ?Hadd_l ?Hadd_r ?Hsmul_l ?Hsmul_r hpx hpy + case Hs => exact fun x y hx hy ↦ subset_span <| mul_mem hx hy + case Hadd_l => exact fun x y z _ _ _ hxz hyz ↦ by simpa [add_mul] using add_mem hxz hyz + case Hadd_r => exact fun x y z _ _ _ hxz hyz ↦ by simpa [mul_add] using add_mem hxz hyz + case Hsmul_l => exact fun r x y _ _ hxy ↦ by simpa [smul_mul_assoc] using smul_mem _ _ hxy + case Hsmul_r => exact fun r x y _ _ hxy ↦ by simpa [mul_smul_comm] using smul_mem _ _ hxy | smul r x _ hpx => exact smul_mem _ _ hpx · apply span_le.2 _ show Subsemigroup.closure s ≤ (adjoin R s).toSubsemigroup diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index 15f0ec29f05ab..a962fa9ac33d8 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Algebra.Equiv import Mathlib.Algebra.Algebra.Opposite import Mathlib.Algebra.Group.Pointwise.Finset.Basic import Mathlib.Algebra.GroupWithZero.NonZeroDivisors -import Mathlib.Algebra.Module.Opposites +import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Module.Submodule.Bilinear import Mathlib.Algebra.Module.Submodule.Pointwise import Mathlib.Algebra.Order.Kleene @@ -36,6 +36,11 @@ It is proved that `Submodule R A` is a semiring, and also an algebra over `Set A Additionally, in the `Pointwise` locale we promote `Submodule.pointwiseDistribMulAction` to a `MulSemiringAction` as `Submodule.pointwiseMulSemiringAction`. +When `R` is not necessarily commutative, and `A` is merely a `R`-module with a ring structure +such that `IsScalarTower R A A` holds (equivalent to the data of a ring homomorphism `R →+* A` +by `ringHomEquivModuleIsScalarTower`), we can still define `1 : Submodule R A` and +`Mul (Submodule R A)`, but `1` is only a left identity, not necessarily a right one. + ## Tags multiplication of submodules, division of submodules, submodule semiring @@ -62,49 +67,57 @@ end SubMulAction namespace Submodule -variable {ι : Sort uι} -variable {R : Type u} [CommSemiring R] - -section Ring +section Module -variable {A : Type v} [Semiring A] [Algebra R A] -variable (S T : Set A) {M N P Q : Submodule R A} {m n : A} +variable {R : Type u} [Semiring R] {A : Type v} [Semiring A] [Module R A] -/-- `1 : Submodule R A` is the submodule R of A. -/ +/-- `1 : Submodule R A` is the submodule `R ∙ 1` of A. +TODO: potentially change this back to `LinearMap.range (Algebra.linearMap R A)` +once a version of `Algebra` without the `commutes'` field is introduced. +See issue #18110. +-/ instance one : One (Submodule R A) := - -- Porting note: `f.range` notation doesn't work - ⟨LinearMap.range (Algebra.linearMap R A)⟩ + ⟨LinearMap.range (LinearMap.toSpanSingleton R A 1)⟩ -theorem one_eq_range : (1 : Submodule R A) = LinearMap.range (Algebra.linearMap R A) := - rfl +theorem one_eq_span : (1 : Submodule R A) = R ∙ 1 := + (LinearMap.span_singleton_eq_range _ _ _).symm theorem le_one_toAddSubmonoid : 1 ≤ (1 : Submodule R A).toAddSubmonoid := by rintro x ⟨n, rfl⟩ - exact ⟨n, map_natCast (algebraMap R A) n⟩ - -theorem algebraMap_mem (r : R) : algebraMap R A r ∈ (1 : Submodule R A) := - LinearMap.mem_range_self (Algebra.linearMap R A) _ - -@[simp] -theorem mem_one {x : A} : x ∈ (1 : Submodule R A) ↔ ∃ y, algebraMap R A y = x := - Iff.rfl + exact ⟨n, show (n : R) • (1 : A) = n by rw [Nat.cast_smul_eq_nsmul, nsmul_one]⟩ @[simp] theorem toSubMulAction_one : (1 : Submodule R A).toSubMulAction = 1 := - SetLike.ext fun _ => mem_one.trans SubMulAction.mem_one'.symm - -theorem one_eq_span : (1 : Submodule R A) = R ∙ 1 := by - apply Submodule.ext - intro a - simp only [mem_one, mem_span_singleton, Algebra.smul_def, mul_one] + SetLike.ext fun _ ↦ by rw [one_eq_span, SubMulAction.mem_one]; exact mem_span_singleton theorem one_eq_span_one_set : (1 : Submodule R A) = span R 1 := one_eq_span -theorem one_le : (1 : Submodule R A) ≤ P ↔ (1 : A) ∈ P := by +theorem one_le {P : Submodule R A} : (1 : Submodule R A) ≤ P ↔ (1 : A) ∈ P := by -- 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] +end Module + +variable {ι : Sort uι} +variable {R : Type u} [CommSemiring R] + +section AlgebraSemiring + +variable {A : Type v} [Semiring A] [Algebra R A] +variable (S T : Set A) {M N P Q : Submodule R A} {m n : A} + +theorem one_eq_range : (1 : Submodule R A) = LinearMap.range (Algebra.linearMap R A) := by + rw [one_eq_span, LinearMap.span_singleton_eq_range, + LinearMap.toSpanSingleton_eq_algebra_linearMap] + +theorem algebraMap_mem (r : R) : algebraMap R A r ∈ (1 : Submodule R A) := by + rw [one_eq_range]; exact LinearMap.mem_range_self _ _ + +@[simp] +theorem mem_one {x : A} : x ∈ (1 : Submodule R A) ↔ ∃ y, algebraMap R A y = x := by + rw [one_eq_range]; rfl + protected theorem map_one {A'} [Semiring A'] [Algebra R A'] (f : A →ₐ[R] A') : map f.toLinearMap (1 : Submodule R A) = 1 := by ext @@ -184,12 +197,10 @@ theorem mul_bot : M * ⊥ = ⊥ := theorem bot_mul : ⊥ * M = ⊥ := map₂_bot_left _ _ --- @[simp] -- Porting note (#10618): simp can prove this once we have a monoid structure protected theorem one_mul : (1 : Submodule R A) * M = M := by conv_lhs => rw [one_eq_span, ← span_eq M] erw [span_mul_span, one_mul, span_eq] --- @[simp] -- Porting note (#10618): simp can prove this once we have a monoid structure protected theorem mul_one : M * 1 = M := by conv_lhs => rw [one_eq_span, ← span_eq M] erw [span_mul_span, mul_one, span_eq] @@ -425,7 +436,7 @@ protected theorem pow_induction_on_left' {C : ∀ (n : ℕ) (x), x ∈ M ^ n → induction n generalizing x with | zero => rw [pow_zero] at hx - obtain ⟨r, rfl⟩ := hx + obtain ⟨r, rfl⟩ := mem_one.mp hx exact algebraMap r | succ n n_ih => revert hx @@ -446,7 +457,7 @@ protected theorem pow_induction_on_right' {C : ∀ (n : ℕ) (x), x ∈ M ^ n induction n generalizing x with | zero => rw [pow_zero] at hx - obtain ⟨r, rfl⟩ := hx + obtain ⟨r, rfl⟩ := mem_one.mp hx exact algebraMap r | succ n n_ih => revert hx @@ -490,10 +501,10 @@ submodules. -/ def equivOpposite : Submodule R Aᵐᵒᵖ ≃+* (Submodule R A)ᵐᵒᵖ where toFun p := op <| p.comap (↑(opLinearEquiv R : A ≃ₗ[R] Aᵐᵒᵖ) : A →ₗ[R] Aᵐᵒᵖ) invFun p := p.unop.comap (↑(opLinearEquiv R : A ≃ₗ[R] Aᵐᵒᵖ).symm : Aᵐᵒᵖ →ₗ[R] A) - left_inv p := SetLike.coe_injective <| rfl - right_inv p := unop_injective <| SetLike.coe_injective rfl + left_inv _ := SetLike.coe_injective <| rfl + right_inv _ := unop_injective <| SetLike.coe_injective rfl map_add' p q := by simp [comap_equiv_eq_map_symm, ← op_add] - map_mul' p q := congr_arg op <| comap_op_mul _ _ + map_mul' _ _ := congr_arg op <| comap_op_mul _ _ protected theorem map_pow {A'} [Semiring A'] [Algebra R A'] (f : A →ₐ[R] A') (n : ℕ) : map f.toLinearMap (M ^ n) = map f.toLinearMap M ^ n := @@ -551,9 +562,9 @@ scoped[Pointwise] attribute [instance] Submodule.pointwiseMulSemiringAction end -end Ring +end AlgebraSemiring -section CommRing +section AlgebraCommSemiring variable {A : Type v} [CommSemiring A] [Algebra R A] variable {M N : Submodule R A} {m n : A} @@ -647,7 +658,7 @@ theorem mem_div_iff_smul_subset {x : A} {I J : Submodule R A} : x ∈ I / J ↔ ⟨fun h y ⟨y', hy', xy'_eq_y⟩ => by rw [← xy'_eq_y] apply h - assumption, fun h y hy => h (Set.smul_mem_smul_set hy)⟩ + assumption, fun h _ hy => h (Set.smul_mem_smul_set hy)⟩ theorem le_div_iff {I J K : Submodule R A} : I ≤ J / K ↔ ∀ x ∈ I, ∀ z ∈ K, x * z ∈ J := Iff.refl _ @@ -689,6 +700,6 @@ protected theorem map_div {B : Type*} [CommSemiring B] [Algebra R B] (I J : Subm end Quotient -end CommRing +end AlgebraCommSemiring end Submodule diff --git a/Mathlib/Algebra/Algebra/Opposite.lean b/Mathlib/Algebra/Algebra/Opposite.lean index 65999d70a14c3..f98ba51332141 100644 --- a/Mathlib/Algebra/Algebra/Opposite.lean +++ b/Mathlib/Algebra/Algebra/Opposite.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Algebra.Equiv -import Mathlib.Algebra.Module.Opposites +import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Ring.Opposite /-! @@ -38,7 +38,7 @@ variable [IsScalarTower R S A] namespace MulOpposite instance instAlgebra : Algebra R Aᵐᵒᵖ where - toRingHom := (algebraMap R A).toOpposite fun x y => Algebra.commutes _ _ + toRingHom := (algebraMap R A).toOpposite fun _ _ => Algebra.commutes _ _ smul_def' c x := unop_injective <| by simp only [unop_smul, RingHom.toOpposite_apply, Function.comp_apply, unop_mul, op_mul, Algebra.smul_def, Algebra.commutes, op_unop, unop_op] diff --git a/Mathlib/Algebra/Algebra/Pi.lean b/Mathlib/Algebra/Algebra/Pi.lean index db4ea723211c1..fbdfdb6ca061d 100644 --- a/Mathlib/Algebra/Algebra/Pi.lean +++ b/Mathlib/Algebra/Algebra/Pi.lean @@ -52,6 +52,15 @@ theorem algebraMap_apply {_ : CommSemiring R} [_s : ∀ i, Semiring (f i)] [∀ -- when each `A i` is an `R i`-algebra, although I'm not sure that it's useful. variable {I} (R) +/-- A family of algebra homomorphisms `g i : A →ₐ[R] f i` defines a ring homomorphism +`Pi.algHom g : A →ₐ[R] Π i, f i` given by `Pi.algHom g x i = f i x`. -/ +@[simps!] +def algHom [CommSemiring R] [s : ∀ i, Semiring (f i)] [∀ i, Algebra R (f i)] + {A : Type*} [Semiring A] [Algebra R A] (g : ∀ i, A →ₐ[R] f i) : + A →ₐ[R] ∀ i, f i where + __ := Pi.ringHom fun i ↦ (g i).toRingHom + commutes' r := by ext; simp + /-- `Function.eval` as an `AlgHom`. The name matches `Pi.evalRingHom`, `Pi.evalMonoidHom`, etc. -/ @[simps] diff --git a/Mathlib/Algebra/Algebra/Quasispectrum.lean b/Mathlib/Algebra/Algebra/Quasispectrum.lean index 33a5807e877b8..712888eb8d3ff 100644 --- a/Mathlib/Algebra/Algebra/Quasispectrum.lean +++ b/Mathlib/Algebra/Algebra/Quasispectrum.lean @@ -254,6 +254,9 @@ lemma quasispectrum.not_isUnit_mem (a : A) {r : R} (hr : ¬ IsUnit r) : r ∈ qu lemma quasispectrum.zero_mem [Nontrivial R] (a : A) : 0 ∈ quasispectrum R a := quasispectrum.not_isUnit_mem a <| by simp +theorem quasispectrum.nonempty [Nontrivial R] (a : A) : (quasispectrum R a).Nonempty := + Set.nonempty_of_mem <| quasispectrum.zero_mem R a + instance quasispectrum.instZero [Nontrivial R] (a : A) : Zero (quasispectrum R a) where zero := ⟨0, quasispectrum.zero_mem R a⟩ @@ -338,8 +341,9 @@ lemma mem_spectrum_inr_of_not_isUnit {R A : Type*} [CommRing R] (a : A) (r : R) (hr : ¬ IsUnit r) : r ∈ spectrum R (a : Unitization R A) := fun h ↦ hr <| by simpa [map_sub] using h.map (fstHom R A) -lemma quasispectrum_eq_spectrum_inr (R : Type*) {A : Type*} [CommRing R] [Ring A] - [Algebra R A] (a : A) : quasispectrum R a = spectrum R (a : Unitization R A) := by +lemma quasispectrum_eq_spectrum_inr (R : Type*) {A : Type*} [CommRing R] [NonUnitalRing A] + [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] (a : A) : + quasispectrum R a = spectrum R (a : Unitization R A) := by ext r have : { r | ¬ IsUnit r} ⊆ spectrum R _ := mem_spectrum_inr_of_not_isUnit a rw [← Set.union_eq_left.mpr this, ← quasispectrum_eq_spectrum_union] @@ -356,6 +360,14 @@ lemma quasispectrum_eq_spectrum_inr' (R S : Type*) {A : Type*} [Semifield R] apply forall_congr' fun x ↦ ?_ rw [not_iff_not, Units.smul_def, Units.smul_def, ← inr_smul, ← inr_neg, isQuasiregular_inr_iff] +lemma quasispectrum_inr_eq (R S : Type*) {A : Type*} [Semifield R] + [Field S] [NonUnitalRing A] [Algebra R S] [Module S A] [IsScalarTower S A A] + [SMulCommClass S A A] [Module R A] [IsScalarTower R S A] (a : A) : + quasispectrum R (a : Unitization S A) = quasispectrum R a := by + rw [quasispectrum_eq_spectrum_union_zero, quasispectrum_eq_spectrum_inr' R S] + apply Set.union_eq_self_of_subset_right + simpa using zero_mem_spectrum_inr _ _ _ + end Unitization /-- A class for `𝕜`-algebras with a partial order where the ordering is compatible with the diff --git a/Mathlib/Algebra/Algebra/Rat.lean b/Mathlib/Algebra/Algebra/Rat.lean index ed05e1a90ee28..bfccd9246f030 100644 --- a/Mathlib/Algebra/Algebra/Rat.lean +++ b/Mathlib/Algebra/Algebra/Rat.lean @@ -5,6 +5,7 @@ Authors: Kenny Lau, Yury Kudryashov -/ import Mathlib.Algebra.Algebra.Defs import Mathlib.Algebra.GroupWithZero.Action.Basic +import Mathlib.Algebra.Module.End import Mathlib.Data.Rat.Cast.CharZero /-! diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean index 311a49067acad..7683b0c0af36d 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean @@ -46,7 +46,6 @@ instance SubsemiringClass : SubsemiringClass (Subalgebra R A) A where theorem mem_toSubsemiring {S : Subalgebra R A} {x} : x ∈ S.toSubsemiring ↔ x ∈ S := Iff.rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem mem_carrier {s : Subalgebra R A} {x : A} : x ∈ s.carrier ↔ x ∈ s := Iff.rfl @@ -280,8 +279,8 @@ instance (priority := 500) algebra' [CommSemiring R'] [SMul R' R] [Algebra R' A] Algebra.algebraMap_eq_smul_one] exact algebraMap_mem S _ with - commutes' := fun c x => Subtype.eq <| Algebra.commutes _ _ - smul_def' := fun c x => Subtype.eq <| Algebra.smul_def _ _ } + commutes' := fun _ _ => Subtype.eq <| Algebra.commutes _ _ + smul_def' := fun _ _ => Subtype.eq <| Algebra.smul_def _ _ } instance algebra : Algebra R S := S.algebra' @@ -614,6 +613,7 @@ variable (R : Type u) {A : Type v} {B : Type w} variable [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] /-- The minimal subalgebra that includes `s`. -/ +@[simps toSubsemiring] def adjoin (s : Set A) : Subalgebra R A := { Subsemiring.closure (Set.range (algebraMap R A) ∪ s) with algebraMap_mem' := fun r => Subsemiring.subset_closure <| Or.inl ⟨r, rfl⟩ } @@ -637,6 +637,10 @@ instance : CompleteLattice (Subalgebra R A) where bot := (Algebra.ofId R A).range bot_le _S := fun _a ⟨_r, hr⟩ => hr ▸ algebraMap_mem _ _ +theorem sup_def (S T : Subalgebra R A) : S ⊔ T = adjoin R (S ∪ T : Set A) := rfl + +theorem sSup_def (S : Set (Subalgebra R A)) : sSup S = adjoin R (⋃₀ (SetLike.coe '' S)) := rfl + @[simp] theorem coe_top : (↑(⊤ : Subalgebra R A) : Set A) = Set.univ := rfl @@ -697,6 +701,16 @@ theorem inf_toSubsemiring (S T : Subalgebra R A) : (S ⊓ T).toSubsemiring = S.toSubsemiring ⊓ T.toSubsemiring := rfl +@[simp] +theorem sup_toSubsemiring (S T : Subalgebra R A) : + (S ⊔ T).toSubsemiring = S.toSubsemiring ⊔ T.toSubsemiring := by + rw [← S.toSubsemiring.closure_eq, ← T.toSubsemiring.closure_eq, ← Subsemiring.closure_union] + simp_rw [sup_def, adjoin_toSubsemiring, Subalgebra.coe_toSubsemiring] + congr 1 + rw [Set.union_eq_right] + rintro _ ⟨x, rfl⟩ + exact Set.mem_union_left _ (algebraMap_mem S x) + @[simp, norm_cast] theorem coe_sInf (S : Set (Subalgebra R A)) : (↑(sInf S) : Set A) = ⋂ s ∈ S, ↑s := sInf_image @@ -714,6 +728,22 @@ theorem sInf_toSubsemiring (S : Set (Subalgebra R A)) : (sInf S).toSubsemiring = sInf (Subalgebra.toSubsemiring '' S) := SetLike.coe_injective <| by simp +open Subalgebra in +@[simp] +theorem sSup_toSubsemiring (S : Set (Subalgebra R A)) (hS : S.Nonempty) : + (sSup S).toSubsemiring = sSup (toSubsemiring '' S) := by + have h : toSubsemiring '' S = Subsemiring.closure '' (SetLike.coe '' S) := by + rw [Set.image_image] + congr! with x + exact x.toSubsemiring.closure_eq.symm + rw [h, sSup_image, ← Subsemiring.closure_sUnion, sSup_def, adjoin_toSubsemiring] + congr 1 + rw [Set.union_eq_right] + rintro _ ⟨x, rfl⟩ + obtain ⟨y, hy⟩ := hS + simp only [Set.mem_sUnion, Set.mem_image, exists_exists_and_eq_and, SetLike.mem_coe] + exact ⟨y, hy, algebraMap_mem y x⟩ + @[simp, norm_cast] theorem coe_iInf {ι : Sort*} {S : ι → Subalgebra R A} : (↑(⨅ i, S i) : Set A) = ⋂ i, S i := by simp [iInf] @@ -732,11 +762,23 @@ theorem iInf_toSubmodule {ι : Sort*} (S : ι → Subalgebra R A) : toSubmodule (⨅ i, S i) = ⨅ i, toSubmodule (S i) := SetLike.coe_injective <| by simp +@[simp] +theorem iInf_toSubsemiring {ι : Sort*} (S : ι → Subalgebra R A) : + (iInf S).toSubsemiring = ⨅ i, (S i).toSubsemiring := by + simp only [iInf, sInf_toSubsemiring, ← Set.range_comp, Function.comp_def] + +@[simp] +theorem iSup_toSubsemiring {ι : Sort*} [Nonempty ι] (S : ι → Subalgebra R A) : + (iSup S).toSubsemiring = ⨆ i, (S i).toSubsemiring := by + simp only [iSup, Set.range_nonempty, sSup_toSubsemiring, ← Set.range_comp, Function.comp_def] + instance : Inhabited (Subalgebra R A) := ⟨⊥⟩ theorem mem_bot {x : A} : x ∈ (⊥ : Subalgebra R A) ↔ x ∈ Set.range (algebraMap R A) := Iff.rfl -theorem toSubmodule_bot : Subalgebra.toSubmodule (⊥ : Subalgebra R A) = 1 := rfl +/-- TODO: change proof to `rfl` when fixing #18110. -/ +theorem toSubmodule_bot : Subalgebra.toSubmodule (⊥ : Subalgebra R A) = 1 := + Submodule.one_eq_range.symm @[simp] theorem coe_bot : ((⊥ : Subalgebra R A) : Set A) = Set.range (algebraMap R A) := rfl @@ -759,7 +801,8 @@ theorem map_top (f : A →ₐ[R] B) : (⊤ : Subalgebra R A).map f = f.range := @[simp] theorem map_bot (f : A →ₐ[R] B) : (⊥ : Subalgebra R A).map f = ⊥ := - Subalgebra.toSubmodule_injective <| Submodule.map_one _ + Subalgebra.toSubmodule_injective <| by + simpa only [Subalgebra.map_toSubmodule, toSubmodule_bot] using Submodule.map_one _ @[simp] theorem comap_top (f : A →ₐ[R] B) : (⊤ : Subalgebra R B).comap f = ⊤ := diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean b/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean index 6328cb01ad700..5003f01d48ca5 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean @@ -47,8 +47,8 @@ theorem mul_toSubmodule {R : Type*} {A : Type*} [CommSemiring R] [CommSemiring A refine le_antisymm (mul_toSubmodule_le _ _) ?_ rintro x (hx : x ∈ Algebra.adjoin R (S ∪ T : Set A)) refine - Algebra.adjoin_induction hx (fun x hx => ?_) (fun r => ?_) (fun _ _ => Submodule.add_mem _) - fun x y hx hy => ?_ + Algebra.adjoin_induction (fun x hx => ?_) (fun r => ?_) (fun _ _ _ _ => Submodule.add_mem _) + (fun x y _ _ hx hy => ?_) hx · rcases hx with hxS | hxT · rw [← mul_one x] exact Submodule.mul_mem_mul hxS (show (1 : A) ∈ T from one_mem T) diff --git a/Mathlib/Algebra/Algebra/Tower.lean b/Mathlib/Algebra/Algebra/Tower.lean index 3ad6359102d47..f973ed4d98f83 100644 --- a/Mathlib/Algebra/Algebra/Tower.lean +++ b/Mathlib/Algebra/Algebra/Tower.lean @@ -240,7 +240,7 @@ variable [Module R M] [Module A M] [IsScalarTower R A M] theorem restrictScalars_span (hsur : Function.Surjective (algebraMap R A)) (X : Set M) : restrictScalars R (span A X) = span R X := by refine ((span_le_restrictScalars R A X).antisymm fun m hm => ?_).symm - refine span_induction hm subset_span (zero_mem _) (fun _ _ => add_mem) fun a m hm => ?_ + refine span_induction subset_span (zero_mem _) (fun _ _ _ _ => add_mem) (fun a m _ hm => ?_) hm obtain ⟨r, rfl⟩ := hsur a simpa [algebraMap_smul] using smul_mem _ r hm @@ -265,21 +265,21 @@ open IsScalarTower theorem smul_mem_span_smul_of_mem {s : Set S} {t : Set A} {k : S} (hks : k ∈ span R s) {x : A} (hx : x ∈ t) : k • x ∈ span R (s • t) := - span_induction hks (fun c hc => subset_span <| Set.smul_mem_smul hc hx) + span_induction (fun _ hc => subset_span <| Set.smul_mem_smul hc hx) (by rw [zero_smul]; exact zero_mem _) - (fun c₁ c₂ ih₁ ih₂ => by rw [add_smul]; exact add_mem ih₁ ih₂) - fun b c hc => by rw [IsScalarTower.smul_assoc]; exact smul_mem _ _ hc + (fun c₁ c₂ _ _ ih₁ ih₂ => by rw [add_smul]; exact add_mem ih₁ ih₂) + (fun b c _ hc => by rw [IsScalarTower.smul_assoc]; exact smul_mem _ _ hc) hks theorem span_smul_of_span_eq_top {s : Set S} (hs : span R s = ⊤) (t : Set A) : span R (s • t) = (span S t).restrictScalars R := le_antisymm (span_le.2 fun _x ⟨p, _hps, _q, hqt, hpqx⟩ ↦ hpqx ▸ (span S t).smul_mem p (subset_span hqt)) - fun p hp ↦ closure_induction hp (zero_mem _) (fun _ _ ↦ add_mem) fun s0 y hy ↦ by - refine span_induction (hs ▸ mem_top : s0 ∈ span R s) - (fun x hx ↦ subset_span ⟨x, hx, y, hy, rfl⟩) ?_ ?_ ?_ + fun _ hp ↦ closure_induction (hx := hp) (zero_mem _) (fun _ _ _ _ ↦ add_mem) fun s0 y hy ↦ by + refine span_induction (fun x hx ↦ subset_span <| by exact ⟨x, hx, y, hy, rfl⟩) ?_ ?_ ?_ + (hs ▸ mem_top : s0 ∈ span R s) · rw [zero_smul]; apply zero_mem - · intro _ _; rw [add_smul]; apply add_mem - · intro r s0 hy; rw [IsScalarTower.smul_assoc]; exact smul_mem _ r hy + · intro _ _ _ _; rw [add_smul]; apply add_mem + · intro r s0 _ hy; rw [IsScalarTower.smul_assoc]; exact smul_mem _ r hy -- The following two lemmas were originally used to prove `span_smul_of_span_eq_top` -- but are now not needed. diff --git a/Mathlib/Algebra/Algebra/ZMod.lean b/Mathlib/Algebra/Algebra/ZMod.lean index a04244c46ce31..0d26ab239fe68 100644 --- a/Mathlib/Algebra/Algebra/ZMod.lean +++ b/Mathlib/Algebra/Algebra/ZMod.lean @@ -32,7 +32,7 @@ abbrev algebra' (h : m ∣ n) : Algebra (ZMod n) R := rcases ZMod.intCast_surjective a with ⟨k, rfl⟩ show ZMod.castHom h R k * r = r * ZMod.castHom h R k rw [map_intCast, Int.cast_comm] - smul_def' := fun a r => rfl } + smul_def' := fun _ _ => rfl } end diff --git a/Mathlib/Algebra/Associated/Basic.lean b/Mathlib/Algebra/Associated/Basic.lean index 6eb45fd0b5183..3697b4cbe06ce 100644 --- a/Mathlib/Algebra/Associated/Basic.lean +++ b/Mathlib/Algebra/Associated/Basic.lean @@ -7,22 +7,15 @@ import Mathlib.Algebra.Group.Even import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.GroupWithZero.Hom import Mathlib.Algebra.Group.Commute.Units -import Mathlib.Algebra.Group.Units.Hom +import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Order.BoundedOrder import Mathlib.Algebra.Ring.Units +import Mathlib.Algebra.Prime.Lemmas /-! -# Associated, prime, and irreducible elements. +# Associated elements. -In this file we define the predicate `Prime p` -saying that an element of a commutative monoid with zero is prime. -Namely, `Prime p` means that `p` isn't zero, it isn't a unit, -and `p ∣ a * b → p ∣ a ∨ p ∣ b` for all `a`, `b`; - -In decomposition monoids (e.g., `ℕ`, `ℤ`), this predicate is equivalent to `Irreducible`, -however this is not true in general. - -We also define an equivalence relation `Associated` +In this file we define an equivalence relation `Associated` saying that two elements of a monoid differ by a multiplication by a unit. Then we show that the quotient type `Associates` is a monoid and prove basic properties of this quotient. @@ -33,330 +26,6 @@ assert_not_exists Multiset variable {M N : Type*} -section Prime - -variable [CommMonoidWithZero M] - -/-- An element `p` of a commutative monoid with zero (e.g., a ring) is called *prime*, -if it's not zero, not a unit, and `p ∣ a * b → p ∣ a ∨ p ∣ b` for all `a`, `b`. -/ -def Prime (p : M) : Prop := - p ≠ 0 ∧ ¬IsUnit p ∧ ∀ a b, p ∣ a * b → p ∣ a ∨ p ∣ b - -namespace Prime - -variable {p : M} (hp : Prime p) -include hp - -theorem ne_zero : p ≠ 0 := - hp.1 - -theorem not_unit : ¬IsUnit p := - hp.2.1 - -theorem not_dvd_one : ¬p ∣ 1 := - mt (isUnit_of_dvd_one ·) hp.not_unit - -theorem ne_one : p ≠ 1 := fun h => hp.2.1 (h.symm ▸ isUnit_one) - -theorem dvd_or_dvd {a b : M} (h : p ∣ a * b) : p ∣ a ∨ p ∣ b := - hp.2.2 a b h - -theorem dvd_mul {a b : M} : p ∣ a * b ↔ p ∣ a ∨ p ∣ b := - ⟨hp.dvd_or_dvd, (Or.elim · (dvd_mul_of_dvd_left · _) (dvd_mul_of_dvd_right · _))⟩ - -theorem isPrimal : IsPrimal p := fun _a _b dvd ↦ (hp.dvd_or_dvd dvd).elim - (fun h ↦ ⟨p, 1, h, one_dvd _, (mul_one p).symm⟩) fun h ↦ ⟨1, p, one_dvd _, h, (one_mul p).symm⟩ - -theorem not_dvd_mul {a b : M} (ha : ¬ p ∣ a) (hb : ¬ p ∣ b) : ¬ p ∣ a * b := - hp.dvd_mul.not.mpr <| not_or.mpr ⟨ha, hb⟩ - -theorem dvd_of_dvd_pow {a : M} {n : ℕ} (h : p ∣ a ^ n) : p ∣ a := by - induction n with - | zero => - rw [pow_zero] at h - have := isUnit_of_dvd_one h - have := not_unit hp - contradiction - | succ n ih => - rw [pow_succ'] at h - rcases dvd_or_dvd hp h with dvd_a | dvd_pow - · assumption - · exact ih dvd_pow - -theorem dvd_pow_iff_dvd {a : M} {n : ℕ} (hn : n ≠ 0) : p ∣ a ^ n ↔ p ∣ a := - ⟨hp.dvd_of_dvd_pow, (dvd_pow · hn)⟩ - -end Prime - -@[simp] -theorem not_prime_zero : ¬Prime (0 : M) := fun h => h.ne_zero rfl - -@[simp] -theorem not_prime_one : ¬Prime (1 : M) := fun h => h.not_unit isUnit_one - -section Map - -variable [CommMonoidWithZero N] {F : Type*} {G : Type*} [FunLike F M N] -variable [MonoidWithZeroHomClass F M N] [FunLike G N M] [MulHomClass G N M] -variable (f : F) (g : G) {p : M} - -theorem comap_prime (hinv : ∀ a, g (f a : N) = a) (hp : Prime (f p)) : Prime p := - ⟨fun h => hp.1 <| by simp [h], fun h => hp.2.1 <| h.map f, fun a b h => by - refine - (hp.2.2 (f a) (f b) <| by - convert map_dvd f h - simp).imp - ?_ ?_ <;> - · intro h - convert ← map_dvd g h <;> apply hinv⟩ - -theorem MulEquiv.prime_iff (e : M ≃* N) : Prime p ↔ Prime (e p) := - ⟨fun h => (comap_prime e.symm e fun a => by simp) <| (e.symm_apply_apply p).substr h, - comap_prime e e.symm fun a => by simp⟩ - -end Map - -end Prime - -theorem Prime.left_dvd_or_dvd_right_of_dvd_mul [CancelCommMonoidWithZero M] {p : M} (hp : Prime p) - {a b : M} : a ∣ p * b → p ∣ a ∨ a ∣ b := by - rintro ⟨c, hc⟩ - rcases hp.2.2 a c (hc ▸ dvd_mul_right _ _) with (h | ⟨x, rfl⟩) - · exact Or.inl h - · rw [mul_left_comm, mul_right_inj' hp.ne_zero] at hc - exact Or.inr (hc.symm ▸ dvd_mul_right _ _) - -theorem Prime.pow_dvd_of_dvd_mul_left [CancelCommMonoidWithZero M] {p a b : M} (hp : Prime p) - (n : ℕ) (h : ¬p ∣ a) (h' : p ^ n ∣ a * b) : p ^ n ∣ b := by - induction n with - | zero => - rw [pow_zero] - exact one_dvd b - | succ n ih => - obtain ⟨c, rfl⟩ := ih (dvd_trans (pow_dvd_pow p n.le_succ) h') - rw [pow_succ] - apply mul_dvd_mul_left _ ((hp.dvd_or_dvd _).resolve_left h) - rwa [← mul_dvd_mul_iff_left (pow_ne_zero n hp.ne_zero), ← pow_succ, mul_left_comm] - -theorem Prime.pow_dvd_of_dvd_mul_right [CancelCommMonoidWithZero M] {p a b : M} (hp : Prime p) - (n : ℕ) (h : ¬p ∣ b) (h' : p ^ n ∣ a * b) : p ^ n ∣ a := by - rw [mul_comm] at h' - exact hp.pow_dvd_of_dvd_mul_left n h h' - -theorem Prime.dvd_of_pow_dvd_pow_mul_pow_of_square_not_dvd [CancelCommMonoidWithZero M] {p a b : M} - {n : ℕ} (hp : Prime p) (hpow : p ^ n.succ ∣ a ^ n.succ * b ^ n) (hb : ¬p ^ 2 ∣ b) : p ∣ a := by - -- Suppose `p ∣ b`, write `b = p * x` and `hy : a ^ n.succ * b ^ n = p ^ n.succ * y`. - rcases hp.dvd_or_dvd ((dvd_pow_self p (Nat.succ_ne_zero n)).trans hpow) with H | hbdiv - · exact hp.dvd_of_dvd_pow H - obtain ⟨x, rfl⟩ := hp.dvd_of_dvd_pow hbdiv - obtain ⟨y, hy⟩ := hpow - -- Then we can divide out a common factor of `p ^ n` from the equation `hy`. - have : a ^ n.succ * x ^ n = p * y := by - refine mul_left_cancel₀ (pow_ne_zero n hp.ne_zero) ?_ - rw [← mul_assoc _ p, ← pow_succ, ← hy, mul_pow, ← mul_assoc (a ^ n.succ), mul_comm _ (p ^ n), - mul_assoc] - -- So `p ∣ a` (and we're done) or `p ∣ x`, which can't be the case since it implies `p^2 ∣ b`. - refine hp.dvd_of_dvd_pow ((hp.dvd_or_dvd ⟨_, this⟩).resolve_right fun hdvdx => hb ?_) - obtain ⟨z, rfl⟩ := hp.dvd_of_dvd_pow hdvdx - rw [pow_two, ← mul_assoc] - exact dvd_mul_right _ _ - -theorem prime_pow_succ_dvd_mul {M : Type*} [CancelCommMonoidWithZero M] {p x y : M} (h : Prime p) - {i : ℕ} (hxy : p ^ (i + 1) ∣ x * y) : p ^ (i + 1) ∣ x ∨ p ∣ y := by - rw [or_iff_not_imp_right] - intro hy - induction i generalizing x with - | zero => rw [pow_one] at hxy ⊢; exact (h.dvd_or_dvd hxy).resolve_right hy - | succ i ih => - rw [pow_succ'] at hxy ⊢ - obtain ⟨x', rfl⟩ := (h.dvd_or_dvd (dvd_of_mul_right_dvd hxy)).resolve_right hy - rw [mul_assoc] at hxy - exact mul_dvd_mul_left p (ih ((mul_dvd_mul_iff_left h.ne_zero).mp hxy)) - -/-- `Irreducible p` states that `p` is non-unit and only factors into units. - -We explicitly avoid stating that `p` is non-zero, this would require a semiring. Assuming only a -monoid allows us to reuse irreducible for associated elements. --/ -structure Irreducible [Monoid M] (p : M) : Prop where - /-- `p` is not a unit -/ - not_unit : ¬IsUnit p - /-- if `p` factors then one factor is a unit -/ - isUnit_or_isUnit' : ∀ a b, p = a * b → IsUnit a ∨ IsUnit b - -namespace Irreducible - -theorem not_dvd_one [CommMonoid M] {p : M} (hp : Irreducible p) : ¬p ∣ 1 := - mt (isUnit_of_dvd_one ·) hp.not_unit - -theorem isUnit_or_isUnit [Monoid M] {p : M} (hp : Irreducible p) {a b : M} (h : p = a * b) : - IsUnit a ∨ IsUnit b := - hp.isUnit_or_isUnit' a b h - -end Irreducible - -theorem irreducible_iff [Monoid M] {p : M} : - Irreducible p ↔ ¬IsUnit p ∧ ∀ a b, p = a * b → IsUnit a ∨ IsUnit b := - ⟨fun h => ⟨h.1, h.2⟩, fun h => ⟨h.1, h.2⟩⟩ - -@[simp] -theorem not_irreducible_one [Monoid M] : ¬Irreducible (1 : M) := by simp [irreducible_iff] - -theorem Irreducible.ne_one [Monoid M] : ∀ {p : M}, Irreducible p → p ≠ 1 - | _, hp, rfl => not_irreducible_one hp - -@[simp] -theorem not_irreducible_zero [MonoidWithZero M] : ¬Irreducible (0 : M) - | ⟨hn0, h⟩ => - have : IsUnit (0 : M) ∨ IsUnit (0 : M) := h 0 0 (mul_zero 0).symm - this.elim hn0 hn0 - -theorem Irreducible.ne_zero [MonoidWithZero M] : ∀ {p : M}, Irreducible p → p ≠ 0 - | _, hp, rfl => not_irreducible_zero hp - -theorem of_irreducible_mul {M} [Monoid M] {x y : M} : Irreducible (x * y) → IsUnit x ∨ IsUnit y - | ⟨_, h⟩ => h _ _ rfl - -theorem not_irreducible_pow {M} [Monoid M] {x : M} {n : ℕ} (hn : n ≠ 1) : - ¬ Irreducible (x ^ n) := by - cases n with - | zero => simp - | succ n => - intro ⟨h₁, h₂⟩ - have := h₂ _ _ (pow_succ _ _) - rw [isUnit_pow_iff (Nat.succ_ne_succ.mp hn), or_self] at this - exact h₁ (this.pow _) - -theorem irreducible_or_factor {M} [Monoid M] (x : M) (h : ¬IsUnit x) : - Irreducible x ∨ ∃ a b, ¬IsUnit a ∧ ¬IsUnit b ∧ a * b = x := by - haveI := Classical.dec - refine or_iff_not_imp_right.2 fun H => ?_ - simp? [h, irreducible_iff] at H ⊢ says - simp only [exists_and_left, not_exists, not_and, irreducible_iff, h, not_false_eq_true, - true_and] at H ⊢ - refine fun a b h => by_contradiction fun o => ?_ - simp? [not_or] at o says simp only [not_or] at o - exact H _ o.1 _ o.2 h.symm - -/-- If `p` and `q` are irreducible, then `p ∣ q` implies `q ∣ p`. -/ -theorem Irreducible.dvd_symm [Monoid M] {p q : M} (hp : Irreducible p) (hq : Irreducible q) : - p ∣ q → q ∣ p := by - rintro ⟨q', rfl⟩ - rw [IsUnit.mul_right_dvd (Or.resolve_left (of_irreducible_mul hq) hp.not_unit)] - -theorem Irreducible.dvd_comm [Monoid M] {p q : M} (hp : Irreducible p) (hq : Irreducible q) : - p ∣ q ↔ q ∣ p := - ⟨hp.dvd_symm hq, hq.dvd_symm hp⟩ - -section - -variable [Monoid M] - -theorem irreducible_units_mul (a : Mˣ) (b : M) : Irreducible (↑a * b) ↔ Irreducible b := by - simp only [irreducible_iff, Units.isUnit_units_mul, and_congr_right_iff] - refine fun _ => ⟨fun h A B HAB => ?_, fun h A B HAB => ?_⟩ - · rw [← a.isUnit_units_mul] - apply h - rw [mul_assoc, ← HAB] - · rw [← a⁻¹.isUnit_units_mul] - apply h - rw [mul_assoc, ← HAB, Units.inv_mul_cancel_left] - -theorem irreducible_isUnit_mul {a b : M} (h : IsUnit a) : Irreducible (a * b) ↔ Irreducible b := - let ⟨a, ha⟩ := h - ha ▸ irreducible_units_mul a b - -theorem irreducible_mul_units (a : Mˣ) (b : M) : Irreducible (b * ↑a) ↔ Irreducible b := by - simp only [irreducible_iff, Units.isUnit_mul_units, and_congr_right_iff] - refine fun _ => ⟨fun h A B HAB => ?_, fun h A B HAB => ?_⟩ - · rw [← Units.isUnit_mul_units B a] - apply h - rw [← mul_assoc, ← HAB] - · rw [← Units.isUnit_mul_units B a⁻¹] - apply h - rw [← mul_assoc, ← HAB, Units.mul_inv_cancel_right] - -theorem irreducible_mul_isUnit {a b : M} (h : IsUnit a) : Irreducible (b * a) ↔ Irreducible b := - let ⟨a, ha⟩ := h - ha ▸ irreducible_mul_units a b - -theorem irreducible_mul_iff {a b : M} : - Irreducible (a * b) ↔ Irreducible a ∧ IsUnit b ∨ Irreducible b ∧ IsUnit a := by - constructor - · refine fun h => Or.imp (fun h' => ⟨?_, h'⟩) (fun h' => ⟨?_, h'⟩) (h.isUnit_or_isUnit rfl).symm - · rwa [irreducible_mul_isUnit h'] at h - · rwa [irreducible_isUnit_mul h'] at h - · rintro (⟨ha, hb⟩ | ⟨hb, ha⟩) - · rwa [irreducible_mul_isUnit hb] - · rwa [irreducible_isUnit_mul ha] - -end - -section CommMonoid - -variable [CommMonoid M] {a : M} - -theorem Irreducible.not_square (ha : Irreducible a) : ¬IsSquare a := by - rw [isSquare_iff_exists_sq] - rintro ⟨b, rfl⟩ - exact not_irreducible_pow (by decide) ha - -theorem IsSquare.not_irreducible (ha : IsSquare a) : ¬Irreducible a := fun h => h.not_square ha - -end CommMonoid - -section CommMonoidWithZero - -variable [CommMonoidWithZero M] - -theorem Irreducible.prime_of_isPrimal {a : M} - (irr : Irreducible a) (primal : IsPrimal a) : Prime a := - ⟨irr.ne_zero, irr.not_unit, fun a b dvd ↦ by - obtain ⟨d₁, d₂, h₁, h₂, rfl⟩ := primal dvd - exact (of_irreducible_mul irr).symm.imp (·.mul_right_dvd.mpr h₁) (·.mul_left_dvd.mpr h₂)⟩ - -theorem Irreducible.prime [DecompositionMonoid M] {a : M} (irr : Irreducible a) : Prime a := - irr.prime_of_isPrimal (DecompositionMonoid.primal a) - -end CommMonoidWithZero - -section CancelCommMonoidWithZero - -variable [CancelCommMonoidWithZero M] {a p : M} - -protected theorem Prime.irreducible (hp : Prime p) : Irreducible p := - ⟨hp.not_unit, fun a b ↦ by - rintro rfl - exact (hp.dvd_or_dvd dvd_rfl).symm.imp - (isUnit_of_dvd_one <| (mul_dvd_mul_iff_right <| right_ne_zero_of_mul hp.ne_zero).mp <| - dvd_mul_of_dvd_right · _) - (isUnit_of_dvd_one <| (mul_dvd_mul_iff_left <| left_ne_zero_of_mul hp.ne_zero).mp <| - dvd_mul_of_dvd_left · _)⟩ - -theorem irreducible_iff_prime [DecompositionMonoid M] {a : M} : Irreducible a ↔ Prime a := - ⟨Irreducible.prime, Prime.irreducible⟩ - -theorem succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul (hp : Prime p) {a b : M} {k l : ℕ} : - p ^ k ∣ a → p ^ l ∣ b → p ^ (k + l + 1) ∣ a * b → p ^ (k + 1) ∣ a ∨ p ^ (l + 1) ∣ b := - fun ⟨x, hx⟩ ⟨y, hy⟩ ⟨z, hz⟩ => - have h : p ^ (k + l) * (x * y) = p ^ (k + l) * (p * z) := by - simpa [mul_comm, pow_add, hx, hy, mul_assoc, mul_left_comm] using hz - have hp0 : p ^ (k + l) ≠ 0 := pow_ne_zero _ hp.ne_zero - have hpd : p ∣ x * y := ⟨z, by rwa [mul_right_inj' hp0] at h⟩ - (hp.dvd_or_dvd hpd).elim - (fun ⟨d, hd⟩ => Or.inl ⟨d, by simp [*, pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩) - fun ⟨d, hd⟩ => Or.inr ⟨d, by simp [*, pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩ - -theorem Prime.not_square (hp : Prime p) : ¬IsSquare p := - hp.irreducible.not_square - -theorem IsSquare.not_prime (ha : IsSquare a) : ¬Prime a := fun h => h.not_square ha - -theorem not_prime_pow {n : ℕ} (hn : n ≠ 1) : ¬Prime (a ^ n) := fun hp => - not_irreducible_pow hn hp.irreducible - -end CancelCommMonoidWithZero - /-- Two elements of a `Monoid` are `Associated` if one of them is another one multiplied by a unit on the right. -/ def Associated [Monoid M] (x y : M) : Prop := @@ -825,7 +494,7 @@ instance instCommMonoid : CommMonoid (Associates M) where instance instPreorder : Preorder (Associates M) where le := Dvd.dvd le_refl := dvd_refl - le_trans a b c := dvd_trans + le_trans _ _ _ := dvd_trans /-- `Associates.mk` as a `MonoidHom`. -/ protected def mkMonoidHom : M →* Associates M where @@ -1080,19 +749,6 @@ end Associates section CommMonoidWithZero -theorem DvdNotUnit.isUnit_of_irreducible_right [CommMonoidWithZero M] {p q : M} - (h : DvdNotUnit p q) (hq : Irreducible q) : IsUnit p := by - obtain ⟨_, x, hx, hx'⟩ := h - exact Or.resolve_right ((irreducible_iff.1 hq).right p x hx') hx - -theorem not_irreducible_of_not_unit_dvdNotUnit [CommMonoidWithZero M] {p q : M} (hp : ¬IsUnit p) - (h : DvdNotUnit p q) : ¬Irreducible q := - mt h.isUnit_of_irreducible_right hp - -theorem DvdNotUnit.not_unit [CommMonoidWithZero M] {p q : M} (hp : DvdNotUnit p q) : ¬IsUnit q := by - obtain ⟨-, x, hx, rfl⟩ := hp - exact fun hc => hx (isUnit_iff_dvd_one.mpr (dvd_of_mul_left_dvd (isUnit_iff_dvd_one.mp hc))) - theorem dvdNotUnit_of_dvdNotUnit_associated [CommMonoidWithZero M] [Nontrivial M] {p q r : M} (h : DvdNotUnit p q) (h' : Associated q r) : DvdNotUnit p r := by obtain ⟨u, rfl⟩ := Associated.symm h' @@ -1117,26 +773,6 @@ theorem DvdNotUnit.not_associated [CancelCommMonoidWithZero M] {p q : M} (h : Dv rcases (mul_right_inj' hp).mp hx' with rfl exact hx a.isUnit -theorem DvdNotUnit.ne [CancelCommMonoidWithZero M] {p q : M} (h : DvdNotUnit p q) : p ≠ q := by - by_contra hcontra - obtain ⟨hp, x, hx', hx''⟩ := h - conv_lhs at hx'' => rw [← hcontra, ← mul_one p] - rw [(mul_left_cancel₀ hp hx'').symm] at hx' - exact hx' isUnit_one - -theorem pow_injective_of_not_isUnit [CancelCommMonoidWithZero M] {q : M} (hq : ¬IsUnit q) - (hq' : q ≠ 0) : Function.Injective fun n : ℕ => q ^ n := by - refine injective_of_lt_imp_ne fun n m h => DvdNotUnit.ne ⟨pow_ne_zero n hq', q ^ (m - n), ?_, ?_⟩ - · exact not_isUnit_of_not_isUnit_dvd hq (dvd_pow (dvd_refl _) (Nat.sub_pos_of_lt h).ne') - · exact (pow_mul_pow_sub q h.le).symm - -@[deprecated (since := "2024-09-22")] -alias pow_injective_of_not_unit := pow_injective_of_not_isUnit - -theorem pow_inj_of_not_isUnit [CancelCommMonoidWithZero M] {q : M} (hq : ¬IsUnit q) - (hq' : q ≠ 0) {m n : ℕ} : q ^ m = q ^ n ↔ m = n := - (pow_injective_of_not_isUnit hq hq').eq_iff - theorem dvd_prime_pow [CancelCommMonoidWithZero M] {p q : M} (hp : Prime p) (n : ℕ) : q ∣ p ^ n ↔ ∃ i ≤ n, Associated q (p ^ i) := by induction n generalizing q with diff --git a/Mathlib/Algebra/BigOperators/Associated.lean b/Mathlib/Algebra/BigOperators/Associated.lean index ebe6b44cb5983..1c4e80f7431fa 100644 --- a/Mathlib/Algebra/BigOperators/Associated.lean +++ b/Mathlib/Algebra/BigOperators/Associated.lean @@ -187,7 +187,7 @@ variable [CancelCommMonoidWithZero α] theorem exists_mem_multiset_le_of_prime {s : Multiset (Associates α)} {p : Associates α} (hp : Prime p) : p ≤ s.prod → ∃ a ∈ s, p ≤ a := - Multiset.induction_on s (fun ⟨d, Eq⟩ => (hp.ne_one (mul_eq_one.1 Eq.symm).1).elim) + Multiset.induction_on s (fun ⟨_, Eq⟩ => (hp.ne_one (mul_eq_one.1 Eq.symm).1).elim) fun a s ih h => have : p ≤ a * s.prod := by simpa using h match Prime.le_or_le hp this with diff --git a/Mathlib/Algebra/BigOperators/Expect.lean b/Mathlib/Algebra/BigOperators/Expect.lean index cf6a0e4d72664..df5560dfae390 100644 --- a/Mathlib/Algebra/BigOperators/Expect.lean +++ b/Mathlib/Algebra/BigOperators/Expect.lean @@ -53,7 +53,7 @@ local notation a " /ℚ " q => (q : ℚ≥0)⁻¹ • a /-- Average of a function over a finset. If the finset is empty, this is equal to zero. -/ def Finset.expect [AddCommMonoid M] [Module ℚ≥0 M] (s : Finset ι) (f : ι → M) : M := - (s.card : ℚ≥0)⁻¹ • ∑ i ∈ s, f i + (#s : ℚ≥0)⁻¹ • ∑ i ∈ s, f i namespace BigOperators open Batteries.ExtendedBinder Lean Meta @@ -111,7 +111,7 @@ open scoped BigOperators namespace Finset section AddCommMonoid variable [AddCommMonoid M] [Module ℚ≥0 M] [AddCommMonoid N] [Module ℚ≥0 N] {s t : Finset ι} - {f g : ι → M} {m : N → M} {p q : ι → Prop} [DecidablePred p] [DecidablePred q] + {f g : ι → M} {p q : ι → Prop} [DecidablePred p] [DecidablePred q] lemma expect_univ [Fintype ι] : 𝔼 i, f i = (∑ i, f i) /ℚ Fintype.card ι := by rw [expect, card_univ] @@ -152,36 +152,36 @@ lemma expect_add_expect_comm (f₁ f₂ g₁ g₂ : ι → M) : simp_rw [expect_add_distrib, add_add_add_comm] lemma expect_eq_single_of_mem (i : ι) (hi : i ∈ s) (h : ∀ j ∈ s, j ≠ i → f j = 0) : - 𝔼 i ∈ s, f i = f i /ℚ s.card := by rw [expect, sum_eq_single_of_mem _ hi h] + 𝔼 i ∈ s, f i = f i /ℚ #s := by rw [expect, sum_eq_single_of_mem _ hi h] lemma expect_ite_zero (s : Finset ι) (p : ι → Prop) [DecidablePred p] (h : ∀ i ∈ s, ∀ j ∈ s, p i → p j → i = j) (a : M) : - 𝔼 i ∈ s, ite (p i) a 0 = ite (∃ i ∈ s, p i) (a /ℚ s.card) 0 := by + 𝔼 i ∈ s, ite (p i) a 0 = ite (∃ i ∈ s, p i) (a /ℚ #s) 0 := by split_ifs <;> simp [expect, sum_ite_zero _ _ h, *] section DecidableEq variable [DecidableEq ι] lemma expect_ite_mem (s t : Finset ι) (f : ι → M) : - 𝔼 i ∈ s, (if i ∈ t then f i else 0) = ((s ∩ t).card / s.card : ℚ≥0) • 𝔼 i ∈ s ∩ t, f i := by + 𝔼 i ∈ s, (if i ∈ t then f i else 0) = (#(s ∩ t) / #s : ℚ≥0) • 𝔼 i ∈ s ∩ t, f i := by obtain hst | hst := (s ∩ t).eq_empty_or_nonempty · simp [expect, hst] · simp [expect, smul_smul, ← inv_mul_eq_div, hst.card_ne_zero] @[simp] lemma expect_dite_eq (i : ι) (f : ∀ j, i = j → M) : - 𝔼 j ∈ s, (if h : i = j then f j h else 0) = if i ∈ s then f i rfl /ℚ s.card else 0 := by + 𝔼 j ∈ s, (if h : i = j then f j h else 0) = if i ∈ s then f i rfl /ℚ #s else 0 := by split_ifs <;> simp [expect, *] @[simp] lemma expect_dite_eq' (i : ι) (f : ∀ j, j = i → M) : - 𝔼 j ∈ s, (if h : j = i then f j h else 0) = if i ∈ s then f i rfl /ℚ s.card else 0 := by + 𝔼 j ∈ s, (if h : j = i then f j h else 0) = if i ∈ s then f i rfl /ℚ #s else 0 := by split_ifs <;> simp [expect, *] @[simp] lemma expect_ite_eq (i : ι) (f : ι → M) : - 𝔼 j ∈ s, (if i = j then f j else 0) = if i ∈ s then f i /ℚ s.card else 0 := by + 𝔼 j ∈ s, (if i = j then f j else 0) = if i ∈ s then f i /ℚ #s else 0 := by split_ifs <;> simp [expect, *] @[simp] lemma expect_ite_eq' (i : ι) (f : ι → M) : - 𝔼 j ∈ s, (if j = i then f j else 0) = if i ∈ s then f i /ℚ s.card else 0 := by + 𝔼 j ∈ s, (if j = i then f j else 0) = if i ∈ s then f i /ℚ #s else 0 := by split_ifs <;> simp [expect, *] end DecidableEq @@ -279,7 +279,7 @@ lemma _root_.map_expect {F : Type*} [FunLike F M N] [LinearMapClass F ℚ≥0 M g (𝔼 i ∈ s, f i) = 𝔼 i ∈ s, g (f i) := by simp only [expect, map_smul, map_natCast, map_sum] @[simp] -lemma card_smul_expect (s : Finset ι) (f : ι → M) : s.card • 𝔼 i ∈ s, f i = ∑ i ∈ s, f i := by +lemma card_smul_expect (s : Finset ι) (f : ι → M) : #s • 𝔼 i ∈ s, f i = ∑ i ∈ s, f i := by obtain rfl | hs := s.eq_empty_or_nonempty · simp · rw [expect, ← Nat.cast_smul_eq_nsmul ℚ≥0, smul_inv_smul₀] @@ -299,7 +299,7 @@ lemma smul_expect {G : Type*} [DistribSMul G M] [SMulCommClass G ℚ≥0 M] (a : end AddCommMonoid section AddCommGroup -variable [AddCommGroup M] [Module ℚ≥0 M] [Field N] [Module ℚ≥0 N] {s : Finset ι} +variable [AddCommGroup M] [Module ℚ≥0 M] lemma expect_sub_distrib (s : Finset ι) (f g : ι → M) : 𝔼 i ∈ s, (f i - g i) = 𝔼 i ∈ s, f i - 𝔼 i ∈ s, g i := by @@ -312,10 +312,10 @@ lemma expect_neg_distrib (s : Finset ι) (f : ι → M) : 𝔼 i ∈ s, -f i = - end AddCommGroup section Semiring -variable [Semiring M] [Module ℚ≥0 M] {s : Finset ι} {f g : ι → M} {m : N → M} +variable [Semiring M] [Module ℚ≥0 M] @[simp] lemma card_mul_expect (s : Finset ι) (f : ι → M) : - s.card * 𝔼 i ∈ s, f i = ∑ i ∈ s, f i := by rw [← nsmul_eq_mul, card_smul_expect] + #s * 𝔼 i ∈ s, f i = ∑ i ∈ s, f i := by rw [← nsmul_eq_mul, card_smul_expect] @[simp] lemma _root_.Fintype.card_mul_expect [Fintype ι] (f : ι → M) : Fintype.card ι * 𝔼 i, f i = ∑ i, f i := Finset.card_mul_expect _ _ @@ -344,7 +344,7 @@ lemma expect_pow (s : Finset ι) (f : ι → M) (n : ℕ) : end CommSemiring section Semifield -variable [Semifield M] [CharZero M] {s : Finset ι} {f g : ι → M} {m : N → M} +variable [Semifield M] [CharZero M] lemma expect_boole_mul [Fintype ι] [Nonempty ι] [DecidableEq ι] (f : ι → M) (i : ι) : 𝔼 j, ite (i = j) (Fintype.card ι : M) 0 * f j = f i := by @@ -357,7 +357,7 @@ lemma expect_boole_mul' [Fintype ι] [Nonempty ι] [DecidableEq ι] (f : ι → simp_rw [@eq_comm _ _ i, expect_boole_mul] lemma expect_eq_sum_div_card (s : Finset ι) (f : ι → M) : - 𝔼 i ∈ s, f i = (∑ i ∈ s, f i) / s.card := by + 𝔼 i ∈ s, f i = (∑ i ∈ s, f i) / #s := by rw [expect, NNRat.smul_def, div_eq_inv_mul, NNRat.cast_inv, NNRat.cast_natCast] lemma _root_.Fintype.expect_eq_sum_div_card [Fintype ι] (f : ι → M) : @@ -387,7 +387,7 @@ namespace Fintype variable [Fintype ι] [Fintype κ] section AddCommMonoid -variable [AddCommMonoid M] [Module ℚ≥0 M] {f : ι → M} +variable [AddCommMonoid M] [Module ℚ≥0 M] /-- `Fintype.expect_bijective` is a variant of `Finset.expect_bij` that accepts `Function.Bijective`. diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index fbfabaaebfca3..33329a6e81269 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -5,8 +5,9 @@ Authors: Kexing Ying, Kevin Buzzard, Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.GroupWithZero.Finset import Mathlib.Algebra.Group.FiniteSupport -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Ring.Defs import Mathlib.Data.Set.Subsingleton /-! diff --git a/Mathlib/Algebra/BigOperators/Finsupp.lean b/Mathlib/Algebra/BigOperators/Finsupp.lean index 10fdcfb6979ea..9b241247cc785 100644 --- a/Mathlib/Algebra/BigOperators/Finsupp.lean +++ b/Mathlib/Algebra/BigOperators/Finsupp.lean @@ -61,7 +61,7 @@ theorem prod_single_index {a : α} {b : M} {h : α → M → N} (h_zero : h a 0 (single a b).prod h = h a b := calc (single a b).prod h = ∏ x ∈ {a}, h x (single a b x) := - prod_of_support_subset _ support_single_subset h fun x hx => + prod_of_support_subset _ support_single_subset h fun _ hx => (mem_singleton.1 hx).symm ▸ h_zero _ = h a b := by simp @@ -113,8 +113,6 @@ theorem prod_ite_eq' [DecidableEq α] (f : α →₀ M) (a : α) (b : α → M dsimp [Finsupp.prod] rw [f.support.prod_ite_eq'] --- Porting note (#10618): simp can prove this --- @[simp] theorem sum_ite_self_eq' [DecidableEq α] {N : Type*} [AddCommMonoid N] (f : α →₀ N) (a : α) : (f.sum fun x v => ite (x = a) v 0) = f a := by classical @@ -406,8 +404,6 @@ theorem equivFunOnFinite_symm_eq_sum [Fintype α] [AddCommMonoid M] (f : α → ext simp --- Porting note (#10618): simp can prove this --- @[simp] theorem liftAddHom_apply_single [AddCommMonoid M] [AddCommMonoid N] (f : α → M →+ N) (a : α) (b : M) : (liftAddHom (α := α) (M := M) (N := N)) f (single a b) = f a b := sum_single_index (f a).map_zero diff --git a/Mathlib/Algebra/BigOperators/Group/Finset.lean b/Mathlib/Algebra/BigOperators/Group/Finset.lean index eb06a95f3115d..a15dd8845f035 100644 --- a/Mathlib/Algebra/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Finset.lean @@ -416,7 +416,7 @@ theorem prod_union [DecidableEq α] (h : Disjoint s₁ s₂) : @[to_additive] theorem prod_filter_mul_prod_filter_not (s : Finset α) (p : α → Prop) [DecidablePred p] [∀ x, Decidable (¬p x)] (f : α → β) : - (∏ x ∈ s.filter p, f x) * ∏ x ∈ s.filter fun x => ¬p x, f x = ∏ x ∈ s, f x := by + (∏ x ∈ s with p x, f x) * ∏ x ∈ s with ¬p x, f x = ∏ x ∈ s, f x := by have := Classical.decEq α rw [← prod_union (disjoint_filter_filter_neg s s p), filter_union_filter_neg_eq] @@ -463,11 +463,11 @@ lemma prod_powerset_cons (ha : a ∉ s) (f : Finset α → β) : rw [prod_powerset_insert ha, prod_attach _ fun t ↦ f (insert a t)] /-- A product over `powerset s` is equal to the double product over sets of subsets of `s` with -`card s = k`, for `k = 1, ..., card s`. -/ +`#s = k`, for `k = 1, ..., #s`. -/ @[to_additive "A sum over `powerset s` is equal to the double sum over sets of subsets of `s` with - `card s = k`, for `k = 1, ..., card s`"] +`#s = k`, for `k = 1, ..., #s`"] lemma prod_powerset (s : Finset α) (f : Finset α → β) : - ∏ t ∈ powerset s, f t = ∏ j ∈ range (card s + 1), ∏ t ∈ powersetCard j s, f t := by + ∏ t ∈ powerset s, f t = ∏ j ∈ range (#s + 1), ∏ t ∈ powersetCard j s, f t := by rw [powerset_card_disjiUnion, prod_disjiUnion] end CommMonoid @@ -676,27 +676,27 @@ variable [DecidableEq κ] @[to_additive] lemma prod_fiberwise_eq_prod_filter (s : Finset ι) (t : Finset κ) (g : ι → κ) (f : ι → α) : - ∏ j ∈ t, ∏ i ∈ s.filter fun i ↦ g i = j, f i = ∏ i ∈ s.filter fun i ↦ g i ∈ t, f i := by + ∏ j ∈ t, ∏ i ∈ s with g i = j, f i = ∏ i ∈ s with g i ∈ t, f i := by rw [← prod_disjiUnion, disjiUnion_filter_eq] @[to_additive] lemma prod_fiberwise_eq_prod_filter' (s : Finset ι) (t : Finset κ) (g : ι → κ) (f : κ → α) : - ∏ j ∈ t, ∏ _i ∈ s.filter fun i ↦ g i = j, f j = ∏ i ∈ s.filter fun i ↦ g i ∈ t, f (g i) := by + ∏ j ∈ t, ∏ i ∈ s with g i = j, f j = ∏ i ∈ s with g i ∈ t, f (g i) := by calc - _ = ∏ j ∈ t, ∏ i ∈ s.filter fun i ↦ g i = j, f (g i) := + _ = ∏ j ∈ t, ∏ i ∈ s with g i = j, f (g i) := prod_congr rfl fun j _ ↦ prod_congr rfl fun i hi ↦ by rw [(mem_filter.1 hi).2] _ = _ := prod_fiberwise_eq_prod_filter _ _ _ _ @[to_additive] lemma prod_fiberwise_of_maps_to {g : ι → κ} (h : ∀ i ∈ s, g i ∈ t) (f : ι → α) : - ∏ j ∈ t, ∏ i ∈ s.filter fun i ↦ g i = j, f i = ∏ i ∈ s, f i := by + ∏ j ∈ t, ∏ i ∈ s with g i = j, f i = ∏ i ∈ s, f i := by rw [← prod_disjiUnion, disjiUnion_filter_eq_of_maps_to h] @[to_additive] lemma prod_fiberwise_of_maps_to' {g : ι → κ} (h : ∀ i ∈ s, g i ∈ t) (f : κ → α) : - ∏ j ∈ t, ∏ _i ∈ s.filter fun i ↦ g i = j, f j = ∏ i ∈ s, f (g i) := by + ∏ j ∈ t, ∏ i ∈ s with g i = j, f j = ∏ i ∈ s, f (g i) := by calc - _ = ∏ y ∈ t, ∏ x ∈ s.filter fun x ↦ g x = y, f (g x) := + _ = ∏ j ∈ t, ∏ i ∈ s with g i = j, f (g i) := prod_congr rfl fun y _ ↦ prod_congr rfl fun x hx ↦ by rw [(mem_filter.1 hx).2] _ = _ := prod_fiberwise_of_maps_to h _ @@ -704,12 +704,12 @@ variable [Fintype κ] @[to_additive] lemma prod_fiberwise (s : Finset ι) (g : ι → κ) (f : ι → α) : - ∏ j, ∏ i ∈ s.filter fun i ↦ g i = j, f i = ∏ i ∈ s, f i := + ∏ j, ∏ i ∈ s with g i = j, f i = ∏ i ∈ s, f i := prod_fiberwise_of_maps_to (fun _ _ ↦ mem_univ _) _ @[to_additive] lemma prod_fiberwise' (s : Finset ι) (g : ι → κ) (f : κ → α) : - ∏ j, ∏ _i ∈ s.filter fun i ↦ g i = j, f j = ∏ i ∈ s, f (g i) := + ∏ j, ∏ i ∈ s with g i = j, f j = ∏ i ∈ s, f (g i) := prod_fiberwise_of_maps_to' (fun _ _ ↦ mem_univ _) _ end bij @@ -759,15 +759,15 @@ theorem prod_finset_product_right' (r : Finset (α × γ)) (s : Finset γ) (t : prod_finset_product_right r s t h @[to_additive] -theorem prod_image' [DecidableEq α] {s : Finset γ} {g : γ → α} (h : γ → β) - (eq : ∀ c ∈ s, f (g c) = ∏ x ∈ s.filter fun c' => g c' = g c, h x) : - ∏ x ∈ s.image g, f x = ∏ x ∈ s, h x := +theorem prod_image' [DecidableEq α] {s : Finset ι} {g : ι → α} (h : ι → β) + (eq : ∀ i ∈ s, f (g i) = ∏ j ∈ s with g j = g i, h j) : + ∏ a ∈ s.image g, f a = ∏ i ∈ s, h i := calc - ∏ x ∈ s.image g, f x = ∏ x ∈ s.image g, ∏ x ∈ s.filter fun c' => g c' = x, h x := - (prod_congr rfl) fun _x hx => - let ⟨c, hcs, hc⟩ := mem_image.1 hx - hc ▸ eq c hcs - _ = ∏ x ∈ s, h x := prod_fiberwise_of_maps_to (fun _x => mem_image_of_mem g) _ + ∏ a ∈ s.image g, f a = ∏ a ∈ s.image g, ∏ j ∈ s with g j = a, h j := + (prod_congr rfl) fun _a hx => + let ⟨i, his, hi⟩ := mem_image.1 hx + hi ▸ eq i his + _ = ∏ i ∈ s, h i := prod_fiberwise_of_maps_to (fun _ => mem_image_of_mem g) _ @[to_additive] theorem prod_mul_distrib : ∏ x ∈ s, f x * g x = (∏ x ∈ s, f x) * ∏ x ∈ s, g x := @@ -836,7 +836,7 @@ theorem prod_hom_rel [CommMonoid γ] {r : β → γ → Prop} {f : α → β} {g @[to_additive] theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, f x ≠ 1 → p x) : - ∏ x ∈ s.filter p, f x = ∏ x ∈ s, f x := + ∏ x ∈ s with p x, f x = ∏ x ∈ s, f x := (prod_subset (filter_subset _ _)) fun x => by classical rw [not_imp_comm, mem_filter] @@ -846,14 +846,14 @@ theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, -- instance first; `{∀ x, Decidable (f x ≠ 1)}` doesn't work with `rw ← prod_filter_ne_one` @[to_additive] theorem prod_filter_ne_one (s : Finset α) [∀ x, Decidable (f x ≠ 1)] : - ∏ x ∈ s.filter fun x => f x ≠ 1, f x = ∏ x ∈ s, f x := + ∏ x ∈ s with f x ≠ 1, f x = ∏ x ∈ s, f x := prod_filter_of_ne fun _ _ => id @[to_additive] theorem prod_filter (p : α → Prop) [DecidablePred p] (f : α → β) : - ∏ a ∈ s.filter p, f a = ∏ a ∈ s, if p a then f a else 1 := + ∏ a ∈ s with p a, f a = ∏ a ∈ s, if p a then f a else 1 := calc - ∏ a ∈ s.filter p, f a = ∏ a ∈ s.filter p, if p a then f a else 1 := + ∏ a ∈ s with p a, f a = ∏ a ∈ s with p a, if p a then f a else 1 := prod_congr rfl fun a h => by rw [if_pos]; simpa using (mem_filter.1 h).2 _ = ∏ a ∈ s, if p a then f a else 1 := by { refine prod_subset (filter_subset _ s) fun x hs h => ?_ @@ -929,11 +929,11 @@ theorem prod_eq_mul {s : Finset α} {f : α → β} (a b : α) (hn : a ≠ b) prod_const_one -- Porting note: simpNF linter complains that LHS doesn't simplify, but it does -/-- A product over `s.subtype p` equals one over `s.filter p`. -/ +/-- A product over `s.subtype p` equals one over `{x ∈ s | p x}`. -/ @[to_additive (attr := simp, nolint simpNF) - "A sum over `s.subtype p` equals one over `s.filter p`."] +"A sum over `s.subtype p` equals one over `{x ∈ s | p x}`."] theorem prod_subtype_eq_prod_filter (f : α → β) {p : α → Prop} [DecidablePred p] : - ∏ x ∈ s.subtype p, f x = ∏ x ∈ s.filter p, f x := by + ∏ x ∈ s.subtype p, f x = ∏ x ∈ s with p x, f x := by conv_lhs => erw [← prod_map (s.subtype p) (Function.Embedding.subtype _) f] exact prod_congr (subtype_map _) fun x _hx => rfl @@ -983,12 +983,12 @@ theorem prod_subtype {p : α → Prop} {F : Fintype (Subtype p)} (s : Finset α) @[to_additive] lemma prod_preimage' (f : ι → κ) [DecidablePred (· ∈ Set.range f)] (s : Finset κ) (hf) (g : κ → β) : - ∏ x ∈ s.preimage f hf, g (f x) = ∏ x ∈ s.filter (· ∈ Set.range f), g x := by + ∏ x ∈ s.preimage f hf, g (f x) = ∏ x ∈ s with x ∈ Set.range f, g x := by classical calc ∏ x ∈ preimage s f hf, g (f x) = ∏ x ∈ image f (preimage s f hf), g x := Eq.symm <| prod_image <| by simpa only [mem_preimage, Set.InjOn] using hf - _ = ∏ x ∈ s.filter fun x => x ∈ Set.range f, g x := by rw [image_preimage] + _ = ∏ x ∈ s with x ∈ Set.range f, g x := by rw [image_preimage] @[to_additive] lemma prod_preimage (f : ι → κ) (s : Finset κ) (hf) (g : κ → β) @@ -1026,18 +1026,18 @@ theorem prod_congr_set {α : Type*} [CommMonoid α] {β : Type*} [Fintype β] (s theorem prod_apply_dite {s : Finset α} {p : α → Prop} {hp : DecidablePred p} [DecidablePred fun x => ¬p x] (f : ∀ x : α, p x → γ) (g : ∀ x : α, ¬p x → γ) (h : γ → β) : (∏ x ∈ s, h (if hx : p x then f x hx else g x hx)) = - (∏ x ∈ (s.filter p).attach, h (f x.1 <| by simpa using (mem_filter.mp x.2).2)) * - ∏ x ∈ (s.filter fun x => ¬p x).attach, h (g x.1 <| by simpa using (mem_filter.mp x.2).2) := + (∏ x : {x ∈ s | p x}, h (f x.1 <| by simpa using (mem_filter.mp x.2).2)) * + ∏ x : {x ∈ s | ¬p x}, h (g x.1 <| by simpa using (mem_filter.mp x.2).2) := calc (∏ x ∈ s, h (if hx : p x then f x hx else g x hx)) = - (∏ x ∈ s.filter p, h (if hx : p x then f x hx else g x hx)) * - ∏ x ∈ s.filter (¬p ·), h (if hx : p x then f x hx else g x hx) := + (∏ x ∈ s with p x, h (if hx : p x then f x hx else g x hx)) * + ∏ x ∈ s with ¬p x, h (if hx : p x then f x hx else g x hx) := (prod_filter_mul_prod_filter_not s p _).symm - _ = (∏ x ∈ (s.filter p).attach, h (if hx : p x.1 then f x.1 hx else g x.1 hx)) * - ∏ x ∈ (s.filter (¬p ·)).attach, h (if hx : p x.1 then f x.1 hx else g x.1 hx) := + _ = (∏ x : {x ∈ s | p x}, h (if hx : p x.1 then f x.1 hx else g x.1 hx)) * + ∏ x : {x ∈ s | ¬p x}, h (if hx : p x.1 then f x.1 hx else g x.1 hx) := congr_arg₂ _ (prod_attach _ _).symm (prod_attach _ _).symm - _ = (∏ x ∈ (s.filter p).attach, h (f x.1 <| by simpa using (mem_filter.mp x.2).2)) * - ∏ x ∈ (s.filter (¬p ·)).attach, h (g x.1 <| by simpa using (mem_filter.mp x.2).2) := + _ = (∏ x : {x ∈ s | p x}, h (f x.1 <| by simpa using (mem_filter.mp x.2).2)) * + ∏ x : {x ∈ s | ¬p x}, h (g x.1 <| by simpa using (mem_filter.mp x.2).2) := congr_arg₂ _ (prod_congr rfl fun x _hx ↦ congr_arg h (dif_pos <| by simpa using (mem_filter.mp x.2).2)) (prod_congr rfl fun x _hx => congr_arg h (dif_neg <| by simpa using (mem_filter.mp x.2).2)) @@ -1046,21 +1046,20 @@ theorem prod_apply_dite {s : Finset α} {p : α → Prop} {hp : DecidablePred p} theorem prod_apply_ite {s : Finset α} {p : α → Prop} {_hp : DecidablePred p} (f g : α → γ) (h : γ → β) : (∏ x ∈ s, h (if p x then f x else g x)) = - (∏ x ∈ s.filter p, h (f x)) * ∏ x ∈ s.filter fun x => ¬p x, h (g x) := + (∏ x ∈ s with p x, h (f x)) * ∏ x ∈ s with ¬p x, h (g x) := (prod_apply_dite _ _ _).trans <| congr_arg₂ _ (prod_attach _ (h ∘ f)) (prod_attach _ (h ∘ g)) @[to_additive] theorem prod_dite {s : Finset α} {p : α → Prop} {hp : DecidablePred p} (f : ∀ x : α, p x → β) (g : ∀ x : α, ¬p x → β) : ∏ x ∈ s, (if hx : p x then f x hx else g x hx) = - (∏ x ∈ (s.filter p).attach, f x.1 (by simpa using (mem_filter.mp x.2).2)) * - ∏ x ∈ (s.filter fun x => ¬p x).attach, g x.1 (by simpa using (mem_filter.mp x.2).2) := by + (∏ x : {x ∈ s | p x}, f x.1 (by simpa using (mem_filter.mp x.2).2)) * + ∏ x : {x ∈ s | ¬p x}, g x.1 (by simpa using (mem_filter.mp x.2).2) := by simp [prod_apply_dite _ _ fun x => x] @[to_additive] theorem prod_ite {s : Finset α} {p : α → Prop} {hp : DecidablePred p} (f g : α → β) : - ∏ x ∈ s, (if p x then f x else g x) = - (∏ x ∈ s.filter p, f x) * ∏ x ∈ s.filter fun x => ¬p x, g x := by + ∏ x ∈ s, (if p x then f x else g x) = (∏ x ∈ s with p x, f x) * ∏ x ∈ s with ¬p x, g x := by simp [prod_apply_ite _ _ fun x => x] @[to_additive] @@ -1219,7 +1218,7 @@ lemma prod_mulIndicator_subset (f : ι → β) {s t : Finset ι} (h : s ⊆ t) : @[to_additive] lemma prod_mulIndicator_eq_prod_filter (s : Finset ι) (f : ι → κ → β) (t : ι → Set κ) (g : ι → κ) [DecidablePred fun i ↦ g i ∈ t i] : - ∏ i ∈ s, mulIndicator (t i) (f i) (g i) = ∏ i ∈ s.filter fun i ↦ g i ∈ t i, f i (g i) := by + ∏ i ∈ s, mulIndicator (t i) (f i) (g i) = ∏ i ∈ s with g i ∈ t i, f i (g i) := by refine (prod_filter_mul_prod_filter_not s (fun i ↦ g i ∈ t i) _).symm.trans <| Eq.trans (congr_arg₂ (· * ·) ?_ ?_) (mul_one _) · exact prod_congr rfl fun x hx ↦ mulIndicator_of_mem (mem_filter.1 hx).2 _ @@ -1264,8 +1263,8 @@ theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ ∏ x ∈ s, f x = ∏ x ∈ t, g x := by classical calc - ∏ x ∈ s, f x = ∏ x ∈ s.filter fun x => f x ≠ 1, f x := by rw [prod_filter_ne_one] - _ = ∏ x ∈ t.filter fun x => g x ≠ 1, g x := + ∏ x ∈ s, f x = ∏ x ∈ s with f x ≠ 1, f x := by rw [prod_filter_ne_one] + _ = ∏ x ∈ t with g x ≠ 1, g x := prod_bij (fun a ha => i a (mem_filter.mp ha).1 <| by simpa using (mem_filter.mp ha).2) ?_ ?_ ?_ ?_ _ = ∏ x ∈ t, g x := prod_filter_ne_one _ @@ -1376,7 +1375,7 @@ theorem prod_list_count_of_subset [DecidableEq α] [CommMonoid α] (m : List α) rw [count_eq_zero_of_not_mem hx, pow_zero] theorem sum_filter_count_eq_countP [DecidableEq α] (p : α → Prop) [DecidablePred p] (l : List α) : - ∑ x ∈ l.toFinset.filter p, l.count x = l.countP p := by + ∑ x ∈ l.toFinset with p x, l.count x = l.countP p := by simp [Finset.sum, sum_map_count_dedup_filter_eq_countP p l] open Multiset @@ -1467,7 +1466,7 @@ reduces to the difference of the last and first terms when the function we are summing is monotone. -/ theorem sum_range_tsub [AddCommMonoid α] [PartialOrder α] [Sub α] [OrderedSub α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] [ExistsAddOfLE α] + [AddLeftMono α] [AddLeftReflectLE α] [ExistsAddOfLE α] {f : ℕ → α} (h : Monotone f) (n : ℕ) : ∑ i ∈ range n, (f (i + 1) - f i) = f n - f 0 := by apply sum_range_induction @@ -1478,20 +1477,25 @@ theorem sum_range_tsub [AddCommMonoid α] [PartialOrder α] [Sub α] [OrderedSub have h₂ : f 0 ≤ f n := h (Nat.zero_le _) rw [tsub_add_eq_add_tsub h₂, add_tsub_cancel_of_le h₁] +theorem sum_tsub_distrib [AddCommMonoid α] [PartialOrder α] [ExistsAddOfLE α] + [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] [Sub α] + [OrderedSub α] (s : Finset ι) {f g : ι → α} (hfg : ∀ x ∈ s, g x ≤ f x) : + ∑ x ∈ s, (f x - g x) = ∑ x ∈ s, f x - ∑ x ∈ s, g x := sum_map_tsub _ hfg + @[to_additive (attr := simp)] -theorem prod_const (b : β) : ∏ _x ∈ s, b = b ^ s.card := - (congr_arg _ <| s.val.map_const b).trans <| Multiset.prod_replicate s.card b +theorem prod_const (b : β) : ∏ _x ∈ s, b = b ^ #s := + (congr_arg _ <| s.val.map_const b).trans <| Multiset.prod_replicate #s b @[to_additive sum_eq_card_nsmul] -theorem prod_eq_pow_card {b : β} (hf : ∀ a ∈ s, f a = b) : ∏ a ∈ s, f a = b ^ s.card := +theorem prod_eq_pow_card {b : β} (hf : ∀ a ∈ s, f a = b) : ∏ a ∈ s, f a = b ^ #s := (prod_congr rfl hf).trans <| prod_const _ @[to_additive card_nsmul_add_sum] -theorem pow_card_mul_prod {b : β} : b ^ s.card * ∏ a ∈ s, f a = ∏ a ∈ s, b * f a := +theorem pow_card_mul_prod {b : β} : b ^ #s * ∏ a ∈ s, f a = ∏ a ∈ s, b * f a := (Finset.prod_const b).symm ▸ prod_mul_distrib.symm @[to_additive sum_add_card_nsmul] -theorem prod_mul_pow_card {b : β} : (∏ a ∈ s, f a) * b ^ s.card = ∏ a ∈ s, f a * b := +theorem prod_mul_pow_card {b : β} : (∏ a ∈ s, f a) * b ^ #s = ∏ a ∈ s, f a * b := (Finset.prod_const b).symm ▸ prod_mul_distrib.symm @[to_additive] @@ -1510,7 +1514,7 @@ lemma prod_pow_eq_pow_sum (s : Finset ι) (f : ι → ℕ) (a : β) : @[to_additive "A sum over `Finset.powersetCard` which only depends on the size of the sets is constant."] lemma prod_powersetCard (n : ℕ) (s : Finset α) (f : ℕ → β) : - ∏ t ∈ powersetCard n s, f t.card = f n ^ s.card.choose n := by + ∏ t ∈ powersetCard n s, f #t = f n ^ (#s).choose n := by rw [prod_eq_pow_card, card_powersetCard]; rintro a ha; rw [(mem_powersetCard.1 ha).2] @[to_additive] @@ -1563,7 +1567,7 @@ lemma prod_ninvolution (g : α → α) (hg₁ : ∀ a, f a * f (g a) = 1) (hg₂ @[to_additive "The sum of the composition of functions `f` and `g`, is the sum over `b ∈ s.image g` of `f b` times of the cardinality of the fibre of `b`. See also `Finset.sum_image`."] theorem prod_comp [DecidableEq γ] (f : γ → β) (g : α → γ) : - ∏ a ∈ s, f (g a) = ∏ b ∈ s.image g, f b ^ (s.filter fun a => g a = b).card := by + ∏ a ∈ s, f (g a) = ∏ b ∈ s.image g, f b ^ #{a ∈ s | g a = b} := by simp_rw [← prod_const, prod_fiberwise_of_maps_to' fun _ ↦ mem_image_of_mem _] @[to_additive] @@ -1606,14 +1610,14 @@ theorem dvd_prod_of_mem (f : α → β) {a : α} {s : Finset α} (ha : a ∈ s) /-- A product can be partitioned into a product of products, each equivalent under a setoid. -/ @[to_additive "A sum can be partitioned into a sum of sums, each equivalent under a setoid."] theorem prod_partition (R : Setoid α) [DecidableRel R.r] : - ∏ x ∈ s, f x = ∏ xbar ∈ s.image Quotient.mk'', ∏ y ∈ s.filter (⟦·⟧ = xbar), f y := by + ∏ x ∈ s, f x = ∏ xbar ∈ s.image (Quotient.mk _), ∏ y ∈ s with ⟦y⟧ = xbar, f y := by refine (Finset.prod_image' f fun x _hx => ?_).symm rfl /-- If we can partition a product into subsets that cancel out, then the whole product cancels. -/ @[to_additive "If we can partition a sum into subsets that cancel out, then the whole sum cancels."] -theorem prod_cancels_of_partition_cancels (R : Setoid α) [DecidableRel R.r] - (h : ∀ x ∈ s, ∏ a ∈ s.filter fun y => y ≈ x, f a = 1) : ∏ x ∈ s, f x = 1 := by +theorem prod_cancels_of_partition_cancels (R : Setoid α) [DecidableRel R] + (h : ∀ x ∈ s, ∏ a ∈ s with R a x, f a = 1) : ∏ x ∈ s, f x = 1 := by rw [prod_partition R, ← Finset.prod_eq_one] intro xbar xbar_in_s obtain ⟨x, x_in_s, rfl⟩ := mem_image.mp xbar_in_s @@ -1640,12 +1644,12 @@ theorem prod_update_of_mem [DecidableEq α] {s : Finset α} {i : α} (h : i ∈ do the terms in that product. -/ @[to_additive eq_of_card_le_one_of_sum_eq "If a sum of a `Finset` of size at most 1 has a given value, so do the terms in that sum."] -theorem eq_of_card_le_one_of_prod_eq {s : Finset α} (hc : s.card ≤ 1) {f : α → β} {b : β} +theorem eq_of_card_le_one_of_prod_eq {s : Finset α} (hc : #s ≤ 1) {f : α → β} {b : β} (h : ∏ x ∈ s, f x = b) : ∀ x ∈ s, f x = b := by intro x hx - by_cases hc0 : s.card = 0 + by_cases hc0 : #s = 0 · exact False.elim (card_ne_zero_of_mem hx hc0) - · have h1 : s.card = 1 := le_antisymm hc (Nat.one_le_of_lt (Nat.pos_of_ne_zero hc0)) + · have h1 : #s = 1 := le_antisymm hc (Nat.one_le_of_lt (Nat.pos_of_ne_zero hc0)) rw [card_eq_one] at h1 obtain ⟨x2, hx2⟩ := h1 rw [hx2, mem_singleton] at hx @@ -1697,7 +1701,7 @@ theorem prod_ite_one (s : Finset α) (p : α → Prop) [DecidablePred p] @[to_additive] theorem prod_erase_lt_of_one_lt {γ : Type*} [DecidableEq α] [CommMonoid γ] [Preorder γ] - [CovariantClass γ γ (· * ·) (· < ·)] {s : Finset α} {d : α} (hd : d ∈ s) {f : α → γ} + [MulLeftStrictMono γ] {s : Finset α} {d : α} (hd : d ∈ s) {f : α → γ} (hdf : 1 < f d) : ∏ m ∈ s.erase d, f m < ∏ m ∈ s, f m := by conv in ∏ m ∈ s, f m => rw [← Finset.insert_erase hd] rw [Finset.prod_insert (Finset.not_mem_erase d s)] @@ -1776,19 +1780,18 @@ lemma prod_sdiff_ne_prod_sdiff_iff : end CancelCommMonoid -theorem card_eq_sum_ones (s : Finset α) : s.card = ∑ x ∈ s, 1 := by simp +theorem card_eq_sum_ones (s : Finset α) : #s = ∑ _ ∈ s, 1 := by simp -theorem sum_const_nat {m : ℕ} {f : α → ℕ} (h₁ : ∀ x ∈ s, f x = m) : - ∑ x ∈ s, f x = card s * m := by +theorem sum_const_nat {m : ℕ} {f : α → ℕ} (h₁ : ∀ x ∈ s, f x = m) : ∑ x ∈ s, f x = #s * m := by rw [← Nat.nsmul_eq_mul, ← sum_const] apply sum_congr rfl h₁ lemma sum_card_fiberwise_eq_card_filter {κ : Type*} [DecidableEq κ] (s : Finset ι) (t : Finset κ) - (g : ι → κ) : ∑ j ∈ t, (s.filter fun i ↦ g i = j).card = (s.filter fun i ↦ g i ∈ t).card := by + (g : ι → κ) : ∑ j ∈ t, #{i ∈ s | g i = j} = #{i ∈ s | g i ∈ t} := by simpa only [card_eq_sum_ones] using sum_fiberwise_eq_sum_filter _ _ _ _ -lemma card_filter (p) [DecidablePred p] (s : Finset α) : - (filter p s).card = ∑ a ∈ s, ite (p a) 1 0 := by simp [sum_ite] +lemma card_filter (p) [DecidablePred p] (s : Finset ι) : + #{i ∈ s | p i} = ∑ i ∈ s, ite (p i) 1 0 := by simp [sum_ite] section Opposite @@ -1848,37 +1851,33 @@ end CommGroup @[simp] theorem card_sigma {σ : α → Type*} (s : Finset α) (t : ∀ a, Finset (σ a)) : - card (s.sigma t) = ∑ a ∈ s, card (t a) := + #(s.sigma t) = ∑ a ∈ s, #(t a) := Multiset.card_sigma _ _ @[simp] theorem card_disjiUnion (s : Finset α) (t : α → Finset β) (h) : - (s.disjiUnion t h).card = s.sum fun i => (t i).card := + #(s.disjiUnion t h) = ∑ a ∈ s, #(t a) := Multiset.card_bind _ _ theorem card_biUnion [DecidableEq β] {s : Finset α} {t : α → Finset β} - (h : ∀ x ∈ s, ∀ y ∈ s, x ≠ y → Disjoint (t x) (t y)) : - (s.biUnion t).card = ∑ u ∈ s, card (t u) := - calc - (s.biUnion t).card = ∑ i ∈ s.biUnion t, 1 := card_eq_sum_ones _ - _ = ∑ a ∈ s, ∑ _i ∈ t a, 1 := Finset.sum_biUnion h - _ = ∑ u ∈ s, card (t u) := by simp_rw [card_eq_sum_ones] + (h : ∀ x ∈ s, ∀ y ∈ s, x ≠ y → Disjoint (t x) (t y)) : #(s.biUnion t) = ∑ u ∈ s, #(t u) := by + simpa using sum_biUnion h (β := ℕ) (f := 1) theorem card_biUnion_le [DecidableEq β] {s : Finset α} {t : α → Finset β} : - (s.biUnion t).card ≤ ∑ a ∈ s, (t a).card := + #(s.biUnion t) ≤ ∑ a ∈ s, #(t a) := haveI := Classical.decEq α Finset.induction_on s (by simp) fun a s has ih => calc - ((insert a s).biUnion t).card ≤ (t a).card + (s.biUnion t).card := by - { rw [biUnion_insert]; exact Finset.card_union_le _ _ } - _ ≤ ∑ a ∈ insert a s, card (t a) := by rw [sum_insert has]; exact Nat.add_le_add_left ih _ + #((insert a s).biUnion t) ≤ #(t a) + #(s.biUnion t) := by + rw [biUnion_insert]; exact card_union_le .. + _ ≤ ∑ a ∈ insert a s, #(t a) := by rw [sum_insert has]; exact Nat.add_le_add_left ih _ theorem card_eq_sum_card_fiberwise [DecidableEq β] {f : α → β} {s : Finset α} {t : Finset β} - (H : ∀ x ∈ s, f x ∈ t) : s.card = ∑ a ∈ t, (s.filter fun x => f x = a).card := by + (H : ∀ x ∈ s, f x ∈ t) : #s = ∑ b ∈ t, #{a ∈ s | f a = b} := by simp only [card_eq_sum_ones, sum_fiberwise_of_maps_to H] theorem card_eq_sum_card_image [DecidableEq β] (f : α → β) (s : Finset α) : - s.card = ∑ a ∈ s.image f, (s.filter fun x => f x = a).card := + #s = ∑ b ∈ s.image f, #{a ∈ s | f a = b} := card_eq_sum_card_fiberwise fun _ => mem_image_of_mem _ theorem mem_sum {f : α → Multiset β} (s : Finset α) (b : β) : @@ -2260,8 +2259,7 @@ end AddCommMonoid theorem Finset.sum_sym2_filter_not_isDiag {ι α} [LinearOrder ι] [AddCommMonoid α] (s : Finset ι) (p : Sym2 ι → α) : - ∑ i in s.sym2.filter (¬ ·.IsDiag), p i = - ∑ i in s.offDiag.filter (fun i => i.1 < i.2), p s(i.1, i.2) := by + ∑ i ∈ s.sym2 with ¬ i.IsDiag, p i = ∑ i ∈ s.offDiag with i.1 < i.2, p s(i.1, i.2) := by rw [Finset.offDiag_filter_lt_eq_filter_le] conv_rhs => rw [← Finset.sum_subtype_eq_sum_filter] refine (Finset.sum_equiv Sym2.sortEquiv.symm ?_ ?_).symm diff --git a/Mathlib/Algebra/BigOperators/Group/List.lean b/Mathlib/Algebra/BigOperators/Group/List.lean index 6a1a5fb8af68e..c354261cd7b5d 100644 --- a/Mathlib/Algebra/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/BigOperators/Group/List.lean @@ -7,12 +7,14 @@ import Mathlib.Algebra.Divisibility.Basic import Mathlib.Algebra.Group.Int import Mathlib.Algebra.Group.Nat import Mathlib.Algebra.Group.Opposite -import Mathlib.Algebra.Group.Units -import Mathlib.Data.List.Perm +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Data.List.ProdSigma import Mathlib.Data.List.Range import Mathlib.Data.List.Rotate import Mathlib.Data.List.Pairwise +import Mathlib.Data.List.Join +import Mathlib.Data.List.Dedup +import Mathlib.Data.List.Perm.Basic /-! # Sums and products from lists @@ -31,10 +33,10 @@ section Defs /-- Product of a list. -`List.prod [a, b, c] = ((1 * a) * b) * c` -/ -@[to_additive "Sum of a list.\n\n`List.sum [a, b, c] = ((0 + a) + b) + c`"] +`List.prod [a, b, c] = a * (b * (c * 1))` -/ +@[to_additive "Sum of a list.\n\n`List.sum [a, b, c] = a + (b + (c + 0))`"] def prod {α} [Mul α] [One α] : List α → α := - foldl (· * ·) 1 + foldr (· * ·) 1 /-- The alternating sum of a list. -/ def alternatingSum {G : Type*} [Zero G] [Add G] [Neg G] : List G → G @@ -51,21 +53,41 @@ def alternatingProd {G : Type*} [One G] [Mul G] [Inv G] : List G → G end Defs -section MulOneClass +section Mul -variable [MulOneClass M] {l : List M} {a : M} +variable [Mul M] [One M] {l : List M} {a : M} @[to_additive (attr := simp)] theorem prod_nil : ([] : List M).prod = 1 := rfl +@[to_additive (attr := simp)] +theorem prod_cons : (a :: l).prod = a * l.prod := rfl + +@[to_additive] +lemma prod_induction + (p : M → Prop) (hom : ∀ a b, p a → p b → p (a * b)) (unit : p 1) (base : ∀ x ∈ l, p x) : + p l.prod := by + induction l with + | nil => simpa + | cons a l ih => + rw [List.prod_cons] + simp only [mem_cons, forall_eq_or_imp] at base + exact hom _ _ (base.1) (ih base.2) + +end Mul + +section MulOneClass + +variable [MulOneClass M] {l : List M} {a : M} + @[to_additive] theorem prod_singleton : [a].prod = a := - one_mul a + mul_one a -@[to_additive (attr := simp)] +@[to_additive] theorem prod_one_cons : (1 :: l).prod = l.prod := by - rw [prod, foldl, mul_one] + rw [prod, foldr, one_mul] @[to_additive] theorem prod_map_one {l : List ι} : @@ -80,29 +102,18 @@ section Monoid variable [Monoid M] [Monoid N] [Monoid P] {l l₁ l₂ : List M} {a : M} -@[to_additive (attr := simp)] -theorem prod_cons : (a :: l).prod = a * l.prod := - calc - (a :: l).prod = foldl (· * ·) (a * 1) l := by - simp only [List.prod, foldl_cons, one_mul, mul_one] - _ = _ := foldl_assoc - @[to_additive] -lemma prod_induction - (p : M → Prop) (hom : ∀ a b, p a → p b → p (a * b)) (unit : p 1) (base : ∀ x ∈ l, p x) : - p l.prod := by - induction l with - | nil => simpa - | cons a l ih => - rw [List.prod_cons] - simp only [Bool.not_eq_true, List.mem_cons, forall_eq_or_imp] at base - exact hom _ _ (base.1) (ih base.2) +theorem prod_eq_foldl : ∀ {l : List M}, l.prod = foldl (· * ·) 1 l + | [] => rfl + | cons a l => by + rw [prod_cons, prod_eq_foldl, ← foldl_assoc (α := M) (op := (· * ·))] + simp @[to_additive (attr := simp)] theorem prod_append : (l₁ ++ l₂).prod = l₁.prod * l₂.prod := calc - (l₁ ++ l₂).prod = foldl (· * ·) (foldl (· * ·) 1 l₁ * 1) l₂ := by simp [List.prod] - _ = l₁.prod * l₂.prod := foldl_assoc + (l₁ ++ l₂).prod = foldr (· * ·) (1 * foldr (· * ·) 1 l₂) l₁ := by simp [List.prod] + _ = l₁.prod * l₂.prod := foldr_assoc @[to_additive] theorem prod_concat : (l.concat a).prod = l.prod * a := by @@ -113,9 +124,7 @@ theorem prod_join {l : List (List M)} : l.join.prod = (l.map List.prod).prod := induction l <;> [rfl; simp only [*, List.join, map, prod_append, prod_cons]] @[to_additive] -theorem prod_eq_foldr : ∀ {l : List M}, l.prod = foldr (· * ·) 1 l - | [] => rfl - | cons a l => by rw [prod_cons, foldr_cons, prod_eq_foldr] +theorem prod_eq_foldr {l : List M} : l.prod = foldr (· * ·) 1 l := rfl @[to_additive (attr := simp)] theorem prod_replicate (n : ℕ) (a : M) : (replicate n a).prod = a ^ n := by @@ -135,7 +144,7 @@ theorem prod_hom_rel (l : List ι) {r : M → N → Prop} {f : ι → M} {g : ι @[to_additive] theorem rel_prod {R : M → N → Prop} (h : R 1 1) (hf : (R ⇒ R ⇒ R) (· * ·) (· * ·)) : (Forall₂ R ⇒ R) prod prod := - rel_foldl hf h + rel_foldr hf h @[to_additive] theorem prod_hom_nonempty {l : List M} {F : Type*} [FunLike F M N] [MulHomClass F M N] (f : F) @@ -145,8 +154,8 @@ theorem prod_hom_nonempty {l : List M} {F : Type*} [FunLike F M N] [MulHomClass @[to_additive] theorem prod_hom (l : List M) {F : Type*} [FunLike F M N] [MonoidHomClass F M N] (f : F) : (l.map f).prod = f l.prod := by - simp only [prod, foldl_map, ← map_one f] - exact l.foldl_hom f (· * ·) (· * f ·) 1 (fun x y => (map_mul f x y).symm) + simp only [prod, foldr_map, ← map_one f] + exact l.foldr_hom f (· * ·) (f · * ·) 1 (fun x y => (map_mul f x y).symm) @[to_additive] theorem prod_hom₂_nonempty {l : List ι} (f : M → N → P) @@ -158,8 +167,8 @@ theorem prod_hom₂_nonempty {l : List ι} (f : M → N → P) theorem prod_hom₂ (l : List ι) (f : M → N → P) (hf : ∀ a b c d, f (a * b) (c * d) = f a c * f b d) (hf' : f 1 1 = 1) (f₁ : ι → M) (f₂ : ι → N) : (l.map fun i => f (f₁ i) (f₂ i)).prod = f (l.map f₁).prod (l.map f₂).prod := by - rw [prod, prod, prod, foldl_map, foldl_map, foldl_map, - ← l.foldl_hom₂ f _ _ (fun x y => x * f (f₁ y) (f₂ y)) _ _ (by simp [hf]), hf'] + rw [prod, prod, prod, foldr_map, foldr_map, foldr_map, + ← l.foldr_hom₂ f _ _ (fun x y => f (f₁ x) (f₂ x) * y) _ _ (by simp [hf]), hf'] @[to_additive (attr := simp)] theorem prod_map_mul {α : Type*} [CommMonoid α] {l : List ι} {f g : ι → α} : @@ -315,14 +324,14 @@ depend on the order of elements. -/ @[to_additive "If elements of a list additively commute with each other, then their sum does not depend on the order of elements."] lemma Perm.prod_eq' (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) : l₁.prod = l₂.prod := by - refine h.foldl_eq' ?_ _ + refine h.foldr_eq' ?_ _ apply Pairwise.forall_of_forall · intro x y h z exact (h z).symm · intros; rfl · apply hc.imp intro a b h z - rw [mul_assoc z, mul_assoc z, h] + rw [← mul_assoc, ← mul_assoc, h] end Monoid @@ -342,7 +351,7 @@ lemma prod_map_erase [DecidableEq α] (f : α → M) {a} : · simp only [map, erase_cons_tail (not_beq_of_ne ne.symm), prod_cons, prod_map_erase _ h, mul_left_comm (f a) (f b)] -@[to_additive] lemma Perm.prod_eq (h : Perm l₁ l₂) : prod l₁ = prod l₂ := h.foldl_op_eq +@[to_additive] lemma Perm.prod_eq (h : Perm l₁ l₂) : prod l₁ = prod l₂ := h.foldr_op_eq @[to_additive] lemma prod_reverse (l : List M) : prod l.reverse = prod l := (reverse_perm l).prod_eq @@ -419,7 +428,7 @@ theorem prod_reverse_noncomm : ∀ L : List G, L.reverse.prod = (L.map fun x => "Counterpart to `List.sum_take_succ` when we have a negation operation"] theorem prod_drop_succ : ∀ (L : List G) (i : ℕ) (p : i < L.length), (L.drop (i + 1)).prod = L[i]⁻¹ * (L.drop i).prod - | [], i, p => False.elim (Nat.not_lt_zero _ p) + | [], _, p => False.elim (Nat.not_lt_zero _ p) | _ :: _, 0, _ => by simp | _ :: xs, i + 1, p => prod_drop_succ xs i (Nat.lt_of_succ_lt_succ p) @@ -618,15 +627,13 @@ namespace MonoidHom protected theorem map_list_prod (f : M →* N) (l : List M) : f l.prod = (l.map f).prod := map_list_prod f l -attribute [deprecated map_list_prod (since := "2023-01-10")] MonoidHom.map_list_prod attribute [deprecated map_list_sum (since := "2024-05-02")] AddMonoidHom.map_list_sum end MonoidHom end MonoidHom -@[simp] lemma Nat.sum_eq_listSum (l : List ℕ) : Nat.sum l = l.sum := - (List.foldl_eq_foldr _ _).symm +@[simp] lemma Nat.sum_eq_listSum (l : List ℕ) : Nat.sum l = l.sum := rfl namespace List diff --git a/Mathlib/Algebra/BigOperators/Group/Multiset.lean b/Mathlib/Algebra/BigOperators/Group/Multiset.lean index 0a0e9b28703cd..a0bb921c056e3 100644 --- a/Mathlib/Algebra/BigOperators/Group/Multiset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Multiset.lean @@ -49,8 +49,7 @@ theorem prod_eq_foldl (s : Multiset α) : (foldr_swap _ _ _).trans (by simp [mul_comm]) @[to_additive (attr := simp, norm_cast)] -theorem prod_coe (l : List α) : prod ↑l = l.prod := - prod_eq_foldl _ +theorem prod_coe (l : List α) : prod ↑l = l.prod := rfl @[to_additive (attr := simp)] theorem prod_toList (s : Multiset α) : s.toList.prod = s.prod := by @@ -294,4 +293,17 @@ theorem sum_int_mod (s : Multiset ℤ) (n : ℤ) : s.sum % n = (s.map (· % n)). theorem prod_int_mod (s : Multiset ℤ) (n : ℤ) : s.prod % n = (s.map (· % n)).prod % n := by induction s using Multiset.induction <;> simp [Int.mul_emod, *] +section OrderedSub + +theorem sum_map_tsub [AddCommMonoid α] [PartialOrder α] [ExistsAddOfLE α] + [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] [Sub α] + [OrderedSub α] (l : Multiset ι) {f g : ι → α} (hfg : ∀ x ∈ l, g x ≤ f x) : + (l.map fun x ↦ f x - g x).sum = (l.map f).sum - (l.map g).sum := + eq_tsub_of_add_eq <| by + rw [← sum_map_add] + congr 1 + exact map_congr rfl fun x hx => tsub_add_cancel_of_le <| hfg _ hx + +end OrderedSub + end Multiset diff --git a/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean b/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean index 71d86a299d148..6f377d4ff77be 100644 --- a/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean +++ b/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean @@ -73,6 +73,18 @@ theorem smul_finprod' {ι : Sort*} [Finite ι] {f : ι → β} (r : α) : simp only [finprod_eq_prod_plift_of_mulSupport_subset (s := Finset.univ) (by simp), finprod_eq_prod_of_fintype, Finset.smul_prod'] +variable {G : Type*} [Group G] [MulDistribMulAction G β] + +theorem Finset.smul_prod_perm [Fintype G] (b : β) (g : G) : + (g • ∏ h : G, h • b) = ∏ h : G, h • b := by + simp only [smul_prod', smul_smul] + exact Finset.prod_bijective (g * ·) (Group.mulLeft_bijective g) (by simp) (fun _ _ ↦ rfl) + +theorem smul_finprod_perm [Finite G] (b : β) (g : G) : + (g • ∏ᶠ h : G, h • b) = ∏ᶠ h : G, h • b := by + cases nonempty_fintype G + simp only [finprod_eq_prod_of_fintype, Finset.smul_prod_perm] + end namespace List @@ -104,7 +116,7 @@ theorem smul_prod (s : Finset β) (b : α) (f : β → β) : b ^ s.card • ∏ x in s, f x = ∏ x in s, b • f x := by have : Multiset.map (fun (x : β) ↦ b • f x) s.val = - Multiset.map (fun x ↦ b • x) (Multiset.map (fun x ↦ f x) s.val) := by + Multiset.map (fun x ↦ b • x) (Multiset.map f s.val) := by simp only [Multiset.map_map, Function.comp_apply] simp_rw [prod_eq_multiset_prod, card_def, this, ← Multiset.smul_prod _ b, Multiset.card_map] diff --git a/Mathlib/Algebra/BigOperators/Intervals.lean b/Mathlib/Algebra/BigOperators/Intervals.lean index 3193db4f355ef..00cf03b53b607 100644 --- a/Mathlib/Algebra/BigOperators/Intervals.lean +++ b/Mathlib/Algebra/BigOperators/Intervals.lean @@ -252,8 +252,8 @@ theorem sum_range_id_mul_two (n : ℕ) : (∑ i ∈ range n, i) * 2 = n * (n - 1 (∑ i ∈ range n, i) * 2 = (∑ i ∈ range n, i) + ∑ i ∈ range n, (n - 1 - i) := by rw [sum_range_reflect (fun i => i) n, mul_two] _ = ∑ i ∈ range n, (i + (n - 1 - i)) := sum_add_distrib.symm - _ = ∑ i ∈ range n, (n - 1) := - sum_congr rfl fun i hi => add_tsub_cancel_of_le <| Nat.le_sub_one_of_lt <| mem_range.1 hi + _ = ∑ _ ∈ range n, (n - 1) := + sum_congr rfl fun _ hi => add_tsub_cancel_of_le <| Nat.le_sub_one_of_lt <| mem_range.1 hi _ = n * (n - 1) := by rw [sum_const, card_range, Nat.nsmul_eq_mul] /-- Gauss' summation formula -/ diff --git a/Mathlib/Algebra/BigOperators/Pi.lean b/Mathlib/Algebra/BigOperators/Pi.lean index 4f4ccb8bfbffe..215b6cb5305d4 100644 --- a/Mathlib/Algebra/BigOperators/Pi.lean +++ b/Mathlib/Algebra/BigOperators/Pi.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Patrick Massot -/ -import Mathlib.Algebra.BigOperators.Group.Finset +import Mathlib.Algebra.BigOperators.GroupWithZero.Finset import Mathlib.Algebra.Group.Action.Pi import Mathlib.Algebra.Ring.Pi @@ -14,6 +14,9 @@ This file contains theorems relevant to big operators in binary and arbitrary pr of monoids and groups -/ +open scoped Finset + +variable {ι κ α : Type*} namespace Pi @@ -57,6 +60,33 @@ theorem pi_eq_sum_univ {ι : Type*} [Fintype ι] [DecidableEq ι] {R : Type*} [S ext simp +section CommSemiring +variable [CommSemiring α] + +lemma prod_indicator_apply (s : Finset ι) (f : ι → Set κ) (g : ι → κ → α) (j : κ) : + ∏ i ∈ s, (f i).indicator (g i) j = (⋂ x ∈ s, f x).indicator (∏ i ∈ s, g i) j := by + rw [Set.indicator] + split_ifs with hj + · rw [Finset.prod_apply] + congr! 1 with i hi + simp only [Finset.inf_set_eq_iInter, Set.mem_iInter] at hj + exact Set.indicator_of_mem (hj _ hi) _ + · obtain ⟨i, hi, hj⟩ := by simpa using hj + exact Finset.prod_eq_zero hi <| Set.indicator_of_not_mem hj _ + +lemma prod_indicator (s : Finset ι) (f : ι → Set κ) (g : ι → κ → α) : + ∏ i ∈ s, (f i).indicator (g i) = (⋂ x ∈ s, f x).indicator (∏ i ∈ s, g i) := by + ext a; simpa using prod_indicator_apply .. + +lemma prod_indicator_const_apply (s : Finset ι) (f : ι → Set κ) (g : κ → α) (j : κ) : + ∏ i ∈ s, (f i).indicator g j = (⋂ x ∈ s, f x).indicator (g ^ #s) j := by + simp [prod_indicator_apply] + +lemma prod_indicator_const (s : Finset ι) (f : ι → Set κ) (g : κ → α) : + ∏ i ∈ s, (f i).indicator g = (⋂ x ∈ s, f x).indicator (g ^ #s) := by simp [prod_indicator] + +end CommSemiring + section MulSingle variable {I : Type*} [DecidableEq I] {Z : I → Type*} diff --git a/Mathlib/Algebra/BigOperators/Ring.lean b/Mathlib/Algebra/BigOperators/Ring.lean index 8ffa27de019be..a25c14300bd4b 100644 --- a/Mathlib/Algebra/BigOperators/Ring.lean +++ b/Mathlib/Algebra/BigOperators/Ring.lean @@ -26,11 +26,11 @@ section AddCommMonoidWithOne variable [AddCommMonoidWithOne α] lemma natCast_card_filter (p) [DecidablePred p] (s : Finset ι) : - ((filter p s).card : α) = ∑ a ∈ s, if p a then (1 : α) else 0 := by + (#{x ∈ s | p x} : α) = ∑ a ∈ s, if p a then (1 : α) else 0 := by rw [sum_ite, sum_const_zero, add_zero, sum_const, nsmul_one] @[simp] lemma sum_boole (p) [DecidablePred p] (s : Finset ι) : - (∑ x ∈ s, if p x then 1 else 0 : α) = (s.filter p).card := + (∑ x ∈ s, if p x then 1 else 0 : α) = #{x ∈ s | p x} := (natCast_card_filter _ _).symm end AddCommMonoidWithOne @@ -164,11 +164,11 @@ theorem prod_add (f g : ι → α) (s : Finset ι) : ∏ a ∈ s.attach, if p a.1 a.2 then f a.1 else g a.1 := prod_sum _ _ _ _ = ∑ t ∈ s.powerset, (∏ a ∈ t, f a) * ∏ a ∈ s \ t, g a := sum_bij' - (fun f _ ↦ s.filter fun a ↦ ∃ h : a ∈ s, f a h) + (fun f _ ↦ {a ∈ s | ∃ h : a ∈ s, f a h}) (fun t _ a _ => a ∈ t) (by simp) (by simp [Classical.em]) - (by simp_rw [mem_filter, Function.funext_iff, eq_iff_iff, mem_pi, mem_insert]; tauto) + (by simp_rw [mem_filter, funext_iff, eq_iff_iff, mem_pi, mem_insert]; tauto) (by simp_rw [Finset.ext_iff, @mem_filter _ _ (id _), mem_powerset]; tauto) (fun a _ ↦ by simp only [prod_ite, filter_attach', prod_map, Function.Embedding.coeFn_mk, @@ -183,8 +183,7 @@ end DecidableEq theorem prod_add_ordered [LinearOrder ι] (s : Finset ι) (f g : ι → α) : ∏ i ∈ s, (f i + g i) = (∏ i ∈ s, f i) + - ∑ i ∈ s, - g i * (∏ j ∈ s.filter (· < i), (f j + g j)) * ∏ j ∈ s.filter fun j => i < j, f j := by + ∑ i ∈ s, g i * (∏ j ∈ s with j < i, (f j + g j)) * ∏ j ∈ s with i < j, f j := by refine Finset.induction_on_max s (by simp) ?_ clear s intro a s ha ihs @@ -202,21 +201,21 @@ theorem prod_add_ordered [LinearOrder ι] (s : Finset ι) (f g : ι → α) : mul_left_comm] exact mt (fun ha => (mem_filter.1 ha).1) ha' -/-- Summing `a^s.card * b^(n-s.card)` over all finite subsets `s` of a `Finset` -gives `(a + b)^s.card`. -/ +/-- Summing `a ^ #t * b ^ (n - #t)` over all finite subsets `t` of a finset `s` +gives `(a + b) ^ #s`. -/ theorem sum_pow_mul_eq_add_pow (a b : α) (s : Finset ι) : - (∑ t ∈ s.powerset, a ^ t.card * b ^ (s.card - t.card)) = (a + b) ^ s.card := by + (∑ t ∈ s.powerset, a ^ #t * b ^ (#s - #t)) = (a + b) ^ #s := by classical rw [← prod_const, prod_add] refine Finset.sum_congr rfl fun t ht => ?_ rw [prod_const, prod_const, ← card_sdiff (mem_powerset.1 ht)] -/-- Summing `a^s.card * b^(n-s.card)` over all finite subsets `s` of a fintype of cardinality `n` +/-- Summing `a^#s * b^(n-#s)` over all finite subsets `s` of a fintype of cardinality `n` gives `(a + b)^n`. The "good" proof involves expanding along all coordinates using the fact that `x^n` is multilinear, but multilinear maps are only available now over rings, so we give instead a proof reducing to the usual binomial theorem to have a result over semirings. -/ lemma _root_.Fintype.sum_pow_mul_eq_add_pow (ι : Type*) [Fintype ι] (a b : α) : - ∑ s : Finset ι, a ^ s.card * b ^ (Fintype.card ι - s.card) = (a + b) ^ Fintype.card ι := + ∑ s : Finset ι, a ^ #s * b ^ (Fintype.card ι - #s) = (a + b) ^ Fintype.card ι := Finset.sum_pow_mul_eq_add_pow _ _ _ @[norm_cast] @@ -228,12 +227,17 @@ end CommSemiring section CommRing variable [CommRing α] +/-- The product of `f i - g i` over all of `s` is the sum over the powerset of `s` of the product of +`g` over a subset `t` times the product of `f` over the complement of `t` times `(-1) ^ #t`. -/ +lemma prod_sub [DecidableEq ι] (f g : ι → α) (s : Finset ι) : + ∏ i ∈ s, (f i - g i) = ∑ t ∈ s.powerset, (-1) ^ #t * (∏ i ∈ s \ t, f i) * ∏ i ∈ t, g i := by + simp [sub_eq_neg_add, prod_add, ← prod_const, ← prod_mul_distrib, mul_right_comm] + /-- `∏ i, (f i - g i) = (∏ i, f i) - ∑ i, g i * (∏ j < i, f j - g j) * (∏ j > i, f j)`. -/ lemma prod_sub_ordered [LinearOrder ι] (s : Finset ι) (f g : ι → α) : ∏ i ∈ s, (f i - g i) = (∏ i ∈ s, f i) - - ∑ i ∈ s, - g i * (∏ j ∈ s.filter (· < i), (f j - g j)) * ∏ j ∈ s.filter fun j => i < j, f j := by + ∑ i ∈ s, g i * (∏ j ∈ s with j < i, (f j - g j)) * ∏ j ∈ s with i < j, f j := by simp only [sub_eq_add_neg] convert prod_add_ordered s f fun i => -g i simp @@ -241,7 +245,7 @@ lemma prod_sub_ordered [LinearOrder ι] (s : Finset ι) (f g : ι → α) : /-- `∏ i, (1 - f i) = 1 - ∑ i, f i * (∏ j < i, 1 - f j)`. This formula is useful in construction of a partition of unity from a collection of “bump” functions. -/ theorem prod_one_sub_ordered [LinearOrder ι] (s : Finset ι) (f : ι → α) : - ∏ i ∈ s, (1 - f i) = 1 - ∑ i ∈ s, f i * ∏ j ∈ s.filter (· < i), (1 - f j) := by + ∏ i ∈ s, (1 - f i) = 1 - ∑ i ∈ s, f i * ∏ j ∈ s with j < i, (1 - f j) := by rw [prod_sub_ordered] simp diff --git a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean index e0919abefa13d..bafe58b5b5db8 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean @@ -77,7 +77,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.ofHom f.toLinearMap } + map := fun f => ModuleCat.asHom f.toLinearMap } @[simp] lemma forget₂_module_obj (X : AlgebraCat.{v} R) : @@ -86,7 +86,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.ofHom f.toLinearMap := + (forget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R)).map f = ModuleCat.asHom f.toLinearMap := rfl /-- The object in the category of R-algebras associated to a type equipped with the appropriate @@ -154,7 +154,7 @@ def free : Type u ⥤ AlgebraCat.{u} R where /-- The free/forget adjunction for `R`-algebras. -/ def adj : free.{u} R ⊣ forget (AlgebraCat.{u} R) := Adjunction.mkOfHomEquiv - { homEquiv := fun X A => (FreeAlgebra.lift _).symm + { homEquiv := fun _ _ => (FreeAlgebra.lift _).symm -- Relying on `obviously` to fill out these proofs is very slow :( homEquiv_naturality_left_symm := by -- Porting note (#11041): `apply FreeAlgebra.hom_ext` was `ext1`. diff --git a/Mathlib/Algebra/Category/AlgebraCat/Limits.lean b/Mathlib/Algebra/Category/AlgebraCat/Limits.lean index a2f702f99e183..7957211163d58 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Limits.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Limits.lean @@ -108,7 +108,7 @@ def limitConeIsLimit : IsLimit (limitCone.{v, w} F) := by ext j simp only [Functor.comp_obj, Functor.mapCone_pt, Functor.mapCone_π_app, forget_map_eq_coe] - erw [map_one] + rw [map_one] rfl · intro x y simp only [Functor.comp_obj, Functor.mapCone_pt, Functor.mapCone_π_app] diff --git a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean index 9dbed63a629b2..28e837f52f457 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean @@ -58,11 +58,11 @@ instance : MonoidalCategoryStruct (AlgebraCat.{u} R) where noncomputable instance instMonoidalCategory : MonoidalCategory (AlgebraCat.{u} R) := Monoidal.induced (forget₂ (AlgebraCat R) (ModuleCat R)) - { μIso := fun X Y => Iso.refl _ + { μIso := fun _ _ => Iso.refl _ εIso := Iso.refl _ - associator_eq := fun X Y Z => TensorProduct.ext₃ (fun x y z => rfl) - leftUnitor_eq := fun X => TensorProduct.ext' (fun x y => rfl) - rightUnitor_eq := fun X => TensorProduct.ext' (fun x y => rfl) } + associator_eq := fun _ _ _ => TensorProduct.ext_threefold (fun _ _ _ => rfl) + leftUnitor_eq := fun _ => TensorProduct.ext' (fun _ _ => rfl) + rightUnitor_eq := fun _ => TensorProduct.ext' (fun _ _ => rfl) } variable (R) in /-- `forget₂ (AlgebraCat R) (ModuleCat R)` as a monoidal functor. -/ diff --git a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean index 3cf9cd5c6fcbe..b4d9a43bf7236 100644 --- a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean @@ -59,7 +59,7 @@ lemma of_counit {X : Type v} [Ring X] [Bialgebra R X] : /-- A type alias for `BialgHom` to avoid confusion between the categorical and algebraic spellings of composition. -/ @[ext] -structure Hom (V W : BialgebraCat.{v} R) := +structure Hom (V W : BialgebraCat.{v} R) where /-- The underlying `BialgHom` -/ toBialgHom : V →ₐc[R] W @@ -97,7 +97,7 @@ instance concreteCategory : ConcreteCategory.{v} (BialgebraCat.{v} R) where { obj := fun M => M map := fun f => f.toBialgHom } forget_faithful := - { map_injective := fun {M N} => DFunLike.coe_injective.comp <| Hom.toBialgHom_injective _ _ } + { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toBialgHom_injective _ _ } instance hasForgetToAlgebra : HasForget₂ (BialgebraCat R) (AlgebraCat R) where forget₂ := @@ -117,7 +117,7 @@ theorem forget₂_algebra_map (X Y : BialgebraCat R) (f : X ⟶ Y) : instance hasForgetToCoalgebra : HasForget₂ (BialgebraCat R) (CoalgebraCat R) where forget₂ := { obj := fun X => CoalgebraCat.of R X - map := fun {X Y} f => CoalgebraCat.ofHom f.toBialgHom } + map := fun {_ _} f => CoalgebraCat.ofHom f.toBialgHom } @[simp] theorem forget₂_coalgebra_obj (X : BialgebraCat R) : diff --git a/Mathlib/Algebra/Category/BoolRing.lean b/Mathlib/Algebra/Category/BoolRing.lean index 0967458354f17..396dd1283f25f 100644 --- a/Mathlib/Algebra/Category/BoolRing.lean +++ b/Mathlib/Algebra/Category/BoolRing.lean @@ -80,7 +80,7 @@ end BoolRing instance BoolRing.hasForgetToBoolAlg : HasForget₂ BoolRing BoolAlg where forget₂ := { obj := fun X => BoolAlg.of (AsBoolAlg X) - map := fun {X Y} => RingHom.asBoolAlg } + map := fun {_ _} => RingHom.asBoolAlg } -- Porting note: Added. somehow it does not find this instance. instance {X : BoolAlg} : @@ -91,7 +91,7 @@ instance {X : BoolAlg} : instance BoolAlg.hasForgetToBoolRing : HasForget₂ BoolAlg BoolRing where forget₂ := { obj := fun X => BoolRing.of (AsBoolRing X) - map := fun {X Y} => BoundedLatticeHom.asBoolRing } + map := fun {_ _} => BoundedLatticeHom.asBoolRing } /-- The equivalence between Boolean rings and Boolean algebras. This is actually an isomorphism. -/ @[simps functor inverse] @@ -99,6 +99,6 @@ def boolRingCatEquivBoolAlg : BoolRing ≌ BoolAlg where functor := forget₂ BoolRing BoolAlg inverse := forget₂ BoolAlg BoolRing unitIso := NatIso.ofComponents (fun X => BoolRing.Iso.mk <| - (RingEquiv.asBoolRingAsBoolAlg X).symm) fun {X Y} f => rfl + (RingEquiv.asBoolRingAsBoolAlg X).symm) fun {_ _} _ => rfl counitIso := NatIso.ofComponents (fun X => BoolAlg.Iso.mk <| - OrderIso.asBoolAlgAsBoolRing X) fun {X Y} f => rfl + OrderIso.asBoolAlgAsBoolRing X) fun {_ _} _ => rfl diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean index 2e3227b072f57..3d24b8db74884 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean @@ -62,7 +62,7 @@ lemma of_counit {X : Type v} [AddCommGroup X] [Module R X] [Coalgebra R X] : /-- A type alias for `CoalgHom` to avoid confusion between the categorical and algebraic spellings of composition. -/ @[ext] -structure Hom (V W : CoalgebraCat.{v} R) := +structure Hom (V W : CoalgebraCat.{v} R) where /-- The underlying `CoalgHom` -/ toCoalgHom : V →ₗc[R] W @@ -100,7 +100,7 @@ instance concreteCategory : ConcreteCategory.{v} (CoalgebraCat.{v} R) where { obj := fun M => M map := fun f => f.toCoalgHom } forget_faithful := - { map_injective := fun {M N} => DFunLike.coe_injective.comp <| Hom.toCoalgHom_injective _ _ } + { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toCoalgHom_injective _ _ } instance hasForgetToModule : HasForget₂ (CoalgebraCat R) (ModuleCat R) where forget₂ := diff --git a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean index e6957905eb7f9..0a138d78803f1 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean @@ -38,8 +38,8 @@ 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 X := ModuleCat.of R X - counit := ModuleCat.ofHom Coalgebra.counit - comul := ModuleCat.ofHom Coalgebra.comul + 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 @@ -50,7 +50,7 @@ variable (R) in def toComon : CoalgebraCat R ⥤ Comon_ (ModuleCat R) where obj X := toComonObj X map f := - { hom := ModuleCat.ofHom f.1 + { hom := ModuleCat.asHom f.1 hom_counit := f.1.counit_comp hom_comul := f.1.map_comp_comul.symm } diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean index 6eb6644109de4..dbd37c50e0b59 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean @@ -45,7 +45,7 @@ noncomputable instance instMonoidalCategoryStruct : @[simps] noncomputable def MonoidalCategory.inducingFunctorData : Monoidal.InducingFunctorData (forget₂ (CoalgebraCat R) (ModuleCat R)) where - μIso X Y := Iso.refl _ + μIso _ _ := Iso.refl _ whiskerLeft_eq X Y Z f := by ext; rfl whiskerRight_eq X f := by ext; rfl tensorHom_eq f g := by ext; rfl diff --git a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean index 01ae8aab6bb4d..50f9e8d2c035a 100644 --- a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean @@ -278,8 +278,8 @@ 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.ofHom f) + Category.id_comp (ModuleCat.asHom 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.ofHom f) + Category.comp_id (ModuleCat.asHom f) diff --git a/Mathlib/Algebra/Category/Grp/Adjunctions.lean b/Mathlib/Algebra/Category/Grp/Adjunctions.lean index d3443fcb9cfc5..65064b1835e0b 100644 --- a/Mathlib/Algebra/Category/Grp/Adjunctions.lean +++ b/Mathlib/Algebra/Category/Grp/Adjunctions.lean @@ -64,7 +64,7 @@ theorem free_map_coe {α β : Type u} {f : α → β} (x : FreeAbelianGroup α) -/ def adj : free ⊣ forget AddCommGrp.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun X G => FreeAbelianGroup.lift.symm + { homEquiv := fun _ _ => FreeAbelianGroup.lift.symm -- Porting note (#11041): used to be just `by intros; ext; rfl`. homEquiv_naturality_left_symm := by intros @@ -122,7 +122,7 @@ def free : Type u ⥤ Grp where -/ def adj : free ⊣ forget Grp.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun X G => FreeGroup.lift.symm + { homEquiv := fun _ _ => FreeGroup.lift.symm -- Porting note (#11041): used to be just `by intros; ext1; rfl`. homEquiv_naturality_left_symm := by intros @@ -153,7 +153,7 @@ def abelianize : Grp.{u} ⥤ CommGrp.{u} where /-- The abelianization-forgetful adjuction from `Group` to `CommGroup`. -/ def abelianizeAdj : abelianize ⊣ forget₂ CommGrp.{u} Grp.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun G A => Abelianization.lift.symm + { homEquiv := fun _ _ => Abelianization.lift.symm -- Porting note (#11041): used to be just `by intros; ext1; rfl`. homEquiv_naturality_left_symm := by intros @@ -178,14 +178,14 @@ def MonCat.units : MonCat.{u} ⥤ Grp.{u} where /-- The forgetful-units adjunction between `Grp` and `MonCat`. -/ def Grp.forget₂MonAdj : forget₂ Grp MonCat ⊣ MonCat.units.{u} := Adjunction.mk' { - homEquiv := fun X Y ↦ + homEquiv := fun _ Y ↦ { toFun := fun f => MonoidHom.toHomUnits f invFun := fun f => (Units.coeHom Y).comp f - left_inv := fun f => MonoidHom.ext fun _ => rfl - right_inv := fun f => MonoidHom.ext fun _ => Units.ext rfl } + left_inv := fun _ => MonoidHom.ext fun _ => rfl + right_inv := fun _ => MonoidHom.ext fun _ => Units.ext rfl } unit := { app := fun X => { (@toUnits X _).toMonoidHom with } - naturality := fun X Y f => MonoidHom.ext fun x => Units.ext rfl } + naturality := fun _ _ _ => MonoidHom.ext fun _ => Units.ext rfl } counit := { app := fun X => Units.coeHom X naturality := by intros; exact MonoidHom.ext fun x => rfl } } @@ -204,14 +204,14 @@ def CommMonCat.units : CommMonCat.{u} ⥤ CommGrp.{u} where /-- The forgetful-units adjunction between `CommGrp` and `CommMonCat`. -/ def CommGrp.forget₂CommMonAdj : forget₂ CommGrp CommMonCat ⊣ CommMonCat.units.{u} := Adjunction.mk' { - homEquiv := fun X Y ↦ + homEquiv := fun _ Y ↦ { toFun := fun f => MonoidHom.toHomUnits f invFun := fun f => (Units.coeHom Y).comp f - left_inv := fun f => MonoidHom.ext fun _ => rfl - right_inv := fun f => MonoidHom.ext fun _ => Units.ext rfl } + left_inv := fun _ => MonoidHom.ext fun _ => rfl + right_inv := fun _ => MonoidHom.ext fun _ => Units.ext rfl } unit := { app := fun X => { (@toUnits X _).toMonoidHom with } - naturality := fun X Y f => MonoidHom.ext fun x => Units.ext rfl } + naturality := fun _ _ _ => MonoidHom.ext fun _ => Units.ext rfl } counit := { app := fun X => Units.coeHom X naturality := by intros; exact MonoidHom.ext fun x => rfl } } diff --git a/Mathlib/Algebra/Category/Grp/Basic.lean b/Mathlib/Algebra/Category/Grp/Basic.lean index 0a0eecfaec00e..1c03372df70b3 100644 --- a/Mathlib/Algebra/Category/Grp/Basic.lean +++ b/Mathlib/Algebra/Category/Grp/Basic.lean @@ -112,7 +112,6 @@ instance hasForgetToMonCat : HasForget₂ Grp MonCat := @[to_additive] instance : Coe Grp.{u} MonCat.{u} where coe := (forget₂ Grp MonCat).obj --- porting note (#10670): this instance was not necessary in mathlib @[to_additive] instance (G H : Grp) : One (G ⟶ H) := (inferInstance : One (MonoidHom G H)) @@ -145,7 +144,7 @@ example {R S : Grp} (i : R ⟶ S) (r : R) (h : r = 1) : i r = 1 := by simp [h] "Universe lift functor for additive groups."] def uliftFunctor : Grp.{u} ⥤ Grp.{max u v} where obj X := Grp.of (ULift.{v, u} X) - map {X Y} f := Grp.ofHom <| + map {_ _} f := Grp.ofHom <| MulEquiv.ulift.symm.toMonoidHom.comp <| f.comp MulEquiv.ulift.toMonoidHom map_id X := by rfl map_comp {X Y Z} f g := by rfl @@ -257,7 +256,6 @@ instance hasForgetToCommMonCat : HasForget₂ CommGrp CommMonCat := @[to_additive] instance : Coe CommGrp.{u} CommMonCat.{u} where coe := (forget₂ CommGrp CommMonCat).obj --- porting note (#10670): this instance was not necessary in mathlib @[to_additive] instance (G H : CommGrp) : One (G ⟶ H) := (inferInstance : One (MonoidHom G H)) @@ -287,7 +285,7 @@ example {R S : CommGrp} (i : R ⟶ S) (r : R) (h : r = 1) : i r = 1 := by simp [ "Universe lift functor for additive commutative groups."] def uliftFunctor : CommGrp.{u} ⥤ CommGrp.{max u v} where obj X := CommGrp.of (ULift.{v, u} X) - map {X Y} f := CommGrp.ofHom <| + map {_ _} f := CommGrp.ofHom <| MulEquiv.ulift.symm.toMonoidHom.comp <| f.comp MulEquiv.ulift.toMonoidHom map_id X := by rfl map_comp {X Y Z} f g := by rfl diff --git a/Mathlib/Algebra/Category/Grp/Biproducts.lean b/Mathlib/Algebra/Category/Grp/Biproducts.lean index a45ba714db4a0..cd3163c30ea9f 100644 --- a/Mathlib/Algebra/Category/Grp/Biproducts.lean +++ b/Mathlib/Algebra/Category/Grp/Biproducts.lean @@ -112,7 +112,7 @@ def productLimitCone : Limits.LimitCone (Discrete.functor f) where π := Discrete.natTrans fun j => Pi.evalAddMonoidHom (fun j => f j) j.as } isLimit := { lift := lift.{_, u} f - fac := fun s j => rfl + fac := fun _ _ => rfl uniq := fun s m w => by ext x funext j diff --git a/Mathlib/Algebra/Category/Grp/Colimits.lean b/Mathlib/Algebra/Category/Grp/Colimits.lean index 52e9b257663ec..ffd0441416766 100644 --- a/Mathlib/Algebra/Category/Grp/Colimits.lean +++ b/Mathlib/Algebra/Category/Grp/Colimits.lean @@ -7,7 +7,7 @@ import Mathlib.Algebra.Category.Grp.Preadditive import Mathlib.CategoryTheory.Limits.Shapes.Kernels import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits import Mathlib.CategoryTheory.ConcreteCategory.Elementwise -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # The category of additive commutative groups has all colimits. @@ -227,7 +227,7 @@ def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where rw [map_neg, map_neg, ih] | add x y ihx ihy => simp only [quot_add] - erw [m.map_add, (descMorphism F s).map_add, ihx, ihy] + rw [m.map_add, (descMorphism F s).map_add, ihx, ihy] end Colimits diff --git a/Mathlib/Algebra/Category/Grp/EnoughInjectives.lean b/Mathlib/Algebra/Category/Grp/EnoughInjectives.lean index 781920a5448fc..b43e1077c56c4 100644 --- a/Mathlib/Algebra/Category/Grp/EnoughInjectives.lean +++ b/Mathlib/Algebra/Category/Grp/EnoughInjectives.lean @@ -7,6 +7,7 @@ Authors: Jujian Zhang, Junyan Xu import Mathlib.Algebra.Module.CharacterModule import Mathlib.Algebra.Category.Grp.EquivalenceGroupAddGroup import Mathlib.Algebra.Category.Grp.EpiMono +import Mathlib.Algebra.Category.Grp.Injective /-! @@ -17,8 +18,7 @@ injective presentation for `A`, hence category of abelian groups has enough inje ## Implementation notes -This file is split from `Mathlib.Algebra.Grp.Injective` is to prevent import loop. -This file's dependency imports `Mathlib.Algebra.Grp.Injective`. +This file is split from `Mathlib.Algebra.Category.Grp.Injective` to prevent import loops. -/ open CategoryTheory @@ -35,7 +35,7 @@ instance enoughInjectives : EnoughInjectives AddCommGrp.{u} where injective := injective_of_divisible _ f := ⟨⟨fun a i ↦ ULift.up (i a), by aesop⟩, by aesop⟩ mono := (AddCommGrp.mono_iff_injective _).mpr <| (injective_iff_map_eq_zero _).mpr - fun a h0 ↦ eq_zero_of_character_apply (congr_arg ULift.down <| congr_fun h0 ·) } + fun _ h0 ↦ eq_zero_of_character_apply (congr_arg ULift.down <| congr_fun h0 ·) } end AddCommGrp diff --git a/Mathlib/Algebra/Category/Grp/EpiMono.lean b/Mathlib/Algebra/Category/Grp/EpiMono.lean index 472da6d5b3651..08201ebf6c83b 100644 --- a/Mathlib/Algebra/Category/Grp/EpiMono.lean +++ b/Mathlib/Algebra/Category/Grp/EpiMono.lean @@ -6,7 +6,8 @@ Authors: Jujian Zhang import Mathlib.Algebra.Category.Grp.EquivalenceGroupAddGroup import Mathlib.CategoryTheory.ConcreteCategory.EpiMono import Mathlib.CategoryTheory.Limits.Constructions.EpiMono -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.Coset.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Monomorphisms and epimorphisms in `Group` diff --git a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean index ba62f49de2a29..1a42f23763056 100644 --- a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean +++ b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean @@ -31,7 +31,7 @@ private instance (X : AddCommGrp) : AddZeroClass X.α := X.str.toAddZeroClass @[simps] def toAddGrp : Grp ⥤ AddGrp where obj X := AddGrp.of (Additive X) - map {X} {Y} := MonoidHom.toAdditive + map {_} {_} := MonoidHom.toAdditive end Grp @@ -42,7 +42,7 @@ namespace CommGrp @[simps] def toAddCommGrp : CommGrp ⥤ AddCommGrp where obj X := AddCommGrp.of (Additive X) - map {X} {Y} := MonoidHom.toAdditive + map {_} {_} := MonoidHom.toAdditive end CommGrp @@ -53,7 +53,7 @@ namespace AddGrp @[simps] def toGrp : AddGrp ⥤ Grp where obj X := Grp.of (Multiplicative X) - map {X} {Y} := AddMonoidHom.toMultiplicative + map {_} {_} := AddMonoidHom.toMultiplicative end AddGrp @@ -64,7 +64,7 @@ namespace AddCommGrp @[simps] def toCommGrp : AddCommGrp ⥤ CommGrp where obj X := CommGrp.of (Multiplicative X) - map {X} {Y} := AddMonoidHom.toMultiplicative + map {_} {_} := AddMonoidHom.toMultiplicative end AddCommGrp diff --git a/Mathlib/Algebra/Category/Grp/Injective.lean b/Mathlib/Algebra/Category/Grp/Injective.lean index 04d0f6d61c4a0..f8ea96a6004ef 100644 --- a/Mathlib/Algebra/Category/Grp/Injective.lean +++ b/Mathlib/Algebra/Category/Grp/Injective.lean @@ -3,9 +3,11 @@ Copyright (c) 2022 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ +import Mathlib.Algebra.Category.ModuleCat.EpiMono import Mathlib.Algebra.Category.Grp.ZModuleEquivalence import Mathlib.Algebra.EuclideanDomain.Int -import Mathlib.Algebra.Module.Injective +import Mathlib.Algebra.Category.ModuleCat.Injective +import Mathlib.CategoryTheory.Preadditive.Injective import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Topology.Instances.AddCircle @@ -40,7 +42,6 @@ universe u variable (A : Type u) [AddCommGroup A] - theorem Module.Baer.of_divisible [DivisibleBy A ℤ] : Module.Baer ℤ A := fun I g ↦ by rcases IsPrincipalIdealRing.principal I with ⟨m, rfl⟩ obtain rfl | h0 := eq_or_ne m 0 diff --git a/Mathlib/Algebra/Category/Grp/Limits.lean b/Mathlib/Algebra/Category/Grp/Limits.lean index 0763ecc4606e9..d9ca3a039ecba 100644 --- a/Mathlib/Algebra/Category/Grp/Limits.lean +++ b/Mathlib/Algebra/Category/Grp/Limits.lean @@ -97,7 +97,7 @@ noncomputable instance Forget₂.createsLimit : validLift := by apply IsLimit.uniqueUpToIso (MonCat.HasLimits.limitConeIsLimit.{v, u} _) t makesLimit := IsLimit.ofFaithful (forget₂ Grp MonCat.{u}) (MonCat.HasLimits.limitConeIsLimit _) - (fun s => _) fun s => rfl } + (fun _ => _) fun _ => rfl } /-- A choice of limit cone for a functor into `Grp`. (Generally, you'll just want to use `limit F`.) diff --git a/Mathlib/Algebra/Category/Grp/Preadditive.lean b/Mathlib/Algebra/Category/Grp/Preadditive.lean index 5866733e35b85..fd7ca0d120ef3 100644 --- a/Mathlib/Algebra/Category/Grp/Preadditive.lean +++ b/Mathlib/Algebra/Category/Grp/Preadditive.lean @@ -16,7 +16,6 @@ universe u namespace AddCommGrp --- porting note (#10670): this instance was not necessary in mathlib instance (P Q : AddCommGrp) : AddCommGroup (P ⟶ Q) := (inferInstance : AddCommGroup (AddMonoidHom P Q)) diff --git a/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean b/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean index b690a7f5f0bb5..851259eabc101 100644 --- a/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean @@ -58,7 +58,7 @@ lemma of_counit {X : Type v} [Ring X] [HopfAlgebra R X] : /-- A type alias for `BialgHom` to avoid confusion between the categorical and algebraic spellings of composition. -/ @[ext] -structure Hom (V W : HopfAlgebraCat.{v} R) := +structure Hom (V W : HopfAlgebraCat.{v} R) where /-- The underlying `BialgHom`. -/ toBialgHom : V →ₐc[R] W @@ -96,12 +96,12 @@ instance concreteCategory : ConcreteCategory.{v} (HopfAlgebraCat.{v} R) where { obj := fun M => M map := fun f => f.toBialgHom } forget_faithful := - { map_injective := fun {M N} => DFunLike.coe_injective.comp <| Hom.toBialgHom_injective _ _ } + { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toBialgHom_injective _ _ } instance hasForgetToBialgebra : HasForget₂ (HopfAlgebraCat R) (BialgebraCat R) where forget₂ := { obj := fun X => BialgebraCat.of R X - map := fun {X Y} f => BialgebraCat.ofHom f.toBialgHom } + map := fun {_ _} f => BialgebraCat.ofHom f.toBialgHom } @[simp] theorem forget₂_bialgebra_obj (X : HopfAlgebraCat R) : diff --git a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean index 5fbd14b8fb7c0..229bb1717e4b4 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean @@ -33,22 +33,63 @@ variable [Ring R] /-- The free functor `Type u ⥤ ModuleCat R` sending a type `X` to the free `R`-module with generators `x : X`, implemented as the type `X →₀ R`. -/ -@[simps] def free : Type u ⥤ ModuleCat R where obj X := ModuleCat.of R (X →₀ R) - map {X Y} f := Finsupp.lmapDomain _ _ f + map {_ _} f := Finsupp.lmapDomain _ _ f map_id := by intros; exact Finsupp.lmapDomain_id _ _ map_comp := by intros; exact Finsupp.lmapDomain_comp _ _ _ _ +variable {R} + +/-- Constructor for elements in the module `(free R).obj X`. -/ +noncomputable def freeMk {X : Type u} (x : X) : (free R).obj X := Finsupp.single x 1 + +@[ext 1200] +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))) + +/-- 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 + +@[simp] +lemma freeDesc_apply {X : Type u} {M : ModuleCat.{u} R} (f : X ⟶ M) (x : X) : + freeDesc f (freeMk x) = f x := by + dsimp [freeDesc] + erw [Finsupp.lift_apply, Finsupp.sum_single_index] + all_goals simp + +@[simp] +lemma free_map_apply {X Y : Type u} (f : X → Y) (x : X) : + (free R).map f (freeMk x) = freeMk (f x) := by + apply Finsupp.mapDomain_single + +/-- The bijection `((free R).obj X ⟶ M) ≃ (X → M)` when `X` is a type and `M` a module. -/ +@[simps] +def freeHomEquiv {X : Type u} {M : ModuleCat.{u} R} : + ((free R).obj X ⟶ M) ≃ (X → M) where + toFun φ x := φ (freeMk x) + invFun ψ := freeDesc ψ + left_inv _ := by ext; simp + right_inv _ := by ext; simp + +variable (R) + /-- The free-forgetful adjunction for R-modules. -/ def adj : free R ⊣ forget (ModuleCat.{u} R) := Adjunction.mkOfHomEquiv - { homEquiv := fun X M => (Finsupp.lift M R X).toEquiv.symm - homEquiv_naturality_left_symm := fun {_ _} M f g => - Finsupp.lhom_ext' fun x => - LinearMap.ext_ring - (Finsupp.sum_mapDomain_index_addMonoidHom fun y => (smulAddHom R M).flip (g y)).symm } + { homEquiv := fun _ _ => freeHomEquiv + homEquiv_naturality_left_symm := fun {X Y M} f g ↦ by ext; simp [freeHomEquiv] } + +@[simp] +lemma adj_homEquiv (X : Type u) (M : ModuleCat.{u} R) : + (adj R).homEquiv X M = freeHomEquiv := by + simp only [adj, Adjunction.mkOfHomEquiv_homEquiv] instance : (forget (ModuleCat.{u} R)).IsRightAdjoint := (adj R).isRightAdjoint @@ -246,7 +287,7 @@ open Finsupp instance categoryFree : Category (Free R C) where Hom := fun X Y : C => (X ⟶ Y) →₀ R id := fun X : C => Finsupp.single (𝟙 X) 1 - comp {X Y Z : C} f g := + comp {X _ Z : C} f g := (f.sum (fun f' s => g.sum (fun g' t => Finsupp.single (f' ≫ g') (s * t))) : (X ⟶ Z) →₀ R) assoc {W X Y Z} f g h := by dsimp @@ -263,7 +304,7 @@ section -- accordingly instance : Preadditive (Free R C) where - homGroup X Y := Finsupp.instAddCommGroup + homGroup _ _ := Finsupp.instAddCommGroup add_comp X Y Z f f' g := by dsimp [CategoryTheory.categoryFree] rw [Finsupp.sum_add_index'] <;> · simp [add_mul] @@ -274,7 +315,7 @@ instance : Preadditive (Free R C) where rw [Finsupp.sum_add_index'] <;> · simp [mul_add] instance : Linear R (Free R C) where - homModule X Y := Finsupp.module _ R + homModule _ _ := Finsupp.module _ R smul_comp X Y Z r f g := by dsimp [CategoryTheory.categoryFree] rw [Finsupp.sum_smul_index] <;> simp [Finsupp.smul_sum, mul_assoc] @@ -297,8 +338,8 @@ attribute [local simp] single_comp_single @[simps] def embedding : C ⥤ Free R C where obj X := X - map {X Y} f := Finsupp.single f 1 - map_id X := rfl + map {_ _} f := Finsupp.single f 1 + map_id _ := rfl map_comp {X Y Z} f g := by -- Porting note (#10959): simp used to be able to close this goal dsimp only [] @@ -313,13 +354,11 @@ open Preadditive Linear @[simps] def lift (F : C ⥤ D) : Free R C ⥤ D where obj X := F.obj X - map {X Y} f := f.sum fun f' r => r • F.map f' + map {_ _} f := f.sum fun f' r => r • F.map f' map_id := by dsimp [CategoryTheory.categoryFree]; simp map_comp {X Y Z} f g := by apply Finsupp.induction_linear f - · -- Porting note (#10959): simp used to be able to close this goal - dsimp - rw [Limits.zero_comp, sum_zero_index, Limits.zero_comp] + · simp · intro f₁ f₂ w₁ w₂ rw [add_comp] dsimp at * @@ -331,9 +370,7 @@ def lift (F : C ⥤ D) : Free R C ⥤ D where · intros; simp only [add_smul] · intro f' r apply Finsupp.induction_linear g - · -- Porting note (#10959): simp used to be able to close this goal - dsimp - rw [Limits.comp_zero, sum_zero_index, Limits.comp_zero] + · simp · intro f₁ f₂ w₁ w₂ rw [comp_add] dsimp at * @@ -364,20 +401,18 @@ instance lift_linear (F : C ⥤ D) : (lift R F).Linear R where is isomorphic to the original functor. -/ def embeddingLiftIso (F : C ⥤ D) : embedding R C ⋙ lift R F ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- Two `R`-linear functors out of the `R`-linear completion are isomorphic iff their compositions with the embedding functor are isomorphic. -/ --- Porting note: used to be @[ext] def ext {F G : Free R C ⥤ D} [F.Additive] [F.Linear R] [G.Additive] [G.Linear R] (α : embedding R C ⋙ F ≅ embedding R C ⋙ G) : F ≅ G := NatIso.ofComponents (fun X => α.app X) (by intro X Y f apply Finsupp.induction_linear f - · -- Porting note (#10959): simp used to be able to close this goal - rw [Functor.map_zero, Limits.zero_comp, Functor.map_zero, Limits.comp_zero] + · simp · intro f₁ f₂ w₁ w₂ -- Porting note: Using rw instead of simp rw [Functor.map_add, add_comp, w₁, w₂, Functor.map_add, comp_add] diff --git a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean index 96c3070180a88..d2d388822bfff 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean @@ -56,7 +56,7 @@ example (M N : ModuleCat.{v} A) : Module k (M ⟶ N) := LinearMap.module instance linearOverField : Linear k (ModuleCat.{v} A) where -- Porting note: used to be `by infer_instance` instead of `LinearMap.module` - homModule M N := LinearMap.module + homModule _ _ := LinearMap.module smul_comp := by -- Porting note: this was automatic by `aesop_cat` intros diff --git a/Mathlib/Algebra/Category/ModuleCat/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Basic.lean index 48187e0d55415..4a1b72b744e82 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Basic.lean @@ -151,18 +151,6 @@ theorem forget₂_map (X Y : ModuleCat R) (f : X ⟶ Y) : (forget₂ (ModuleCat R) AddCommGrp).map f = LinearMap.toAddMonoidHom f := rfl --- Porting note (#11215): TODO: `ofHom` and `asHom` are duplicates! - -/-- Typecheck a `LinearMap` as a morphism in `Module R`. -/ -def ofHom {R : Type u} [Ring R] {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 - -@[simp 1100] -theorem ofHom_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) : ofHom f x = f x := - rfl - instance : Inhabited (ModuleCat R) := ⟨of R PUnit⟩ @@ -218,14 +206,25 @@ end ModuleCat variable {R} 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 +@[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 + /-- 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₂) := @@ -304,7 +303,7 @@ section variable {S : Type u} [CommRing S] instance : Linear S (ModuleCat.{v} S) where - homModule X Y := LinearMap.module + homModule _ _ := LinearMap.module smul_comp := by intros ext @@ -441,8 +440,9 @@ end ModuleCat @[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.ofHom f) + Category.id_comp (ModuleCat.asHom f) @[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.ofHom f) + Category.comp_id (ModuleCat.asHom f) + diff --git a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean index 445b26e61ac33..02972a04dba1a 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean @@ -107,7 +107,7 @@ def productLimitCone : Limits.LimitCone (Discrete.functor f) where π := Discrete.natTrans fun j => (LinearMap.proj j.as : (∀ j, f j) →ₗ[R] f j.as) } isLimit := { lift := lift.{_, v} f - fac := fun s j => rfl + fac := fun _ _ => rfl uniq := fun s m w => by ext x funext j @@ -152,8 +152,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.ofHom j) - (ModuleCat.ofHom g) exac) (asHom f) h + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.asHom j) + (ModuleCat.asHom g) exac) (asHom f) h (by simpa only [ModuleCat.mono_iff_injective])).isoBinaryBiproduct ≪≫ biprodIsoProd _ _ ).symm.toLinearEquiv @@ -162,8 +162,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.ofHom j) - (ModuleCat.ofHom g) exac) (ModuleCat.ofHom f) h + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.asHom j) + (ModuleCat.asHom g) exac) (ModuleCat.asHom f) 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 42e62db55eedd..b74a03abb8658 100644 --- a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean @@ -137,9 +137,9 @@ def semilinearMapAddEquiv {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : { toFun := g map_add' := by simp map_smul' := g.map_smul } - left_inv g := rfl - right_inv g := rfl - map_add' g₁ g₂ := rfl + left_inv _ := rfl + right_inv _ := rfl + map_add' _ _ := rfl section @@ -248,7 +248,7 @@ def restrictScalarsEquivalenceOfRingEquiv {R S} [Ring R] [Ring S] (e : R ≃+* S map_smul' := fun s m ↦ congr_arg (· • m) (e.right_inv s).symm }) (by intros; rfl) counitIso := NatIso.ofComponents (fun M ↦ LinearEquiv.toModuleIso' { __ := AddEquiv.refl M - map_smul' := fun r m ↦ congr_arg (· • (_ : M)) (e.left_inv r)}) (by intros; rfl) + map_smul' := fun r _ ↦ congr_arg (· • (_ : M)) (e.left_inv r)}) (by intros; rfl) functor_unitIso_comp := by intros; rfl instance restrictScalars_isEquivalence_of_ringEquiv {R S} [Ring R] [Ring S] (e : R ≃+* S) : @@ -375,7 +375,7 @@ instance mulAction : MulAction S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M instance distribMulAction : DistribMulAction S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M := { CoextendScalars.mulAction f _ with smul_add := fun s g h => LinearMap.ext fun _ : S => by simp - smul_zero := fun s => LinearMap.ext fun _ : S => by simp } + smul_zero := fun _ => LinearMap.ext fun _ : S => by simp } /-- `S` acts on Hom(S, M) by `s • g = x ↦ g (x • s)`, this action defines an `S`-module structure on Hom(S, M). @@ -496,7 +496,7 @@ def HomEquiv.toRestriction {X Y} (g : Y ⟶ (coextendScalars f).obj X) : def app' (Y : ModuleCat S) : Y →ₗ[S] (restrictScalars f ⋙ coextendScalars f).obj Y := { toFun := fun y : Y => { toFun := fun s : S => (s • y : Y) - map_add' := fun s s' => add_smul _ _ _ + map_add' := fun _ _ => add_smul _ _ _ map_smul' := fun r (s : S) => by dsimp only [AddHom.toFun_eq_coe, AddHom.coe_mk, RingHom.id_apply] erw [smul_eq_mul, mul_smul] @@ -531,7 +531,7 @@ protected def unit' : 𝟭 (ModuleCat S) ⟶ restrictScalars f ⋙ coextendScala Functor.comp_map] rw [coe_comp, coe_comp, Function.comp, Function.comp] conv_rhs => rw [← LinearMap.coe_toAddHom, ← AddHom.toFun_eq_coe] - erw [CoextendScalars.map_apply, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, + rw [CoextendScalars.map_apply, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, restrictScalars.map_apply f] change s • (g y) = g (s • y) rw [map_smul] @@ -582,7 +582,7 @@ def restrictCoextendScalarsAdj {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] CoextendScalars.smul_apply', one_mul] } unit := RestrictionCoextensionAdj.unit'.{u₁,u₂,v} f counit := RestrictionCoextensionAdj.counit'.{u₁,u₂,v} f - homEquiv_unit := LinearMap.ext fun y => rfl + homEquiv_unit := LinearMap.ext fun _ => rfl homEquiv_counit := fun {X Y g} => LinearMap.ext <| by -- Porting note (#10745): previously simp [RestrictionCoextensionAdj.counit'] intro x; dsimp @@ -808,21 +808,15 @@ def extendRestrictScalarsAdj {R : Type u₁} {S : Type u₂} [CommRing R] [CommR rw [ModuleCat.coe_comp, Function.comp_apply, restrictScalars.map_apply] rfl homEquiv_counit := fun {X Y g} ↦ LinearMap.ext fun x => by - -- Porting note: once again reminding Lean of the instances - letI m1 : Module R S := Module.compHom S f - letI m2 : Module R Y := Module.compHom Y f induction x using TensorProduct.induction_on with | zero => rw [map_zero, map_zero] | tmul => rw [ExtendRestrictScalarsAdj.homEquiv_symm_apply] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [ModuleCat.coe_comp] - rw [Function.comp_apply, ExtendRestrictScalarsAdj.counit_app] + dsimp + rw [ModuleCat.coe_comp, Function.comp_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [ExtendRestrictScalarsAdj.Counit.map_apply] - set_option tactic.skipAssignedInstances false in dsimp - rw [TensorProduct.lift.tmul] - rfl + dsimp | 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/Colimits.lean b/Mathlib/Algebra/Category/ModuleCat/Colimits.lean index dd77562189b3e..d3858a83537a4 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Colimits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Colimits.lean @@ -42,7 +42,7 @@ noncomputable def coconePointSMul : R →+* End (colimit (F ⋙ forget₂ _ AddCommGrp)) where toFun r := colimMap { app := fun j => (F.obj j).smul r - naturality := fun X Y f => smul_naturality _ _ } + naturality := fun _ _ _ => smul_naturality _ _ } map_zero' := colimit.hom_ext (by simp) map_one' := colimit.hom_ext (by simp) map_add' r s := colimit.hom_ext (fun j => by diff --git a/Mathlib/Algebra/Category/ModuleCat/EnoughInjectives.lean b/Mathlib/Algebra/Category/ModuleCat/EnoughInjectives.lean new file mode 100644 index 0000000000000..d167130dd9438 --- /dev/null +++ b/Mathlib/Algebra/Category/ModuleCat/EnoughInjectives.lean @@ -0,0 +1,34 @@ +/- +Copyright (c) 2023 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang +-/ +import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings +import Mathlib.Algebra.Category.ModuleCat.Injective +import Mathlib.Algebra.Category.Grp.EnoughInjectives +import Mathlib.Algebra.Category.Grp.ZModuleEquivalence +import Mathlib.Logic.Equiv.TransferInstance + +/-! +# Category of $R$-modules has enough injectives + +we lift enough injectives of abelian groups to arbitrary $R$-modules by adjoint functors +`restrictScalars ⊣ coextendScalars` +-/ + +open CategoryTheory + +universe v u +variable (R : Type u) [Ring R] + +instance : EnoughInjectives (ModuleCat.{v} ℤ) := + EnoughInjectives.of_equivalence (forget₂ (ModuleCat ℤ) AddCommGrp) + +lemma ModuleCat.enoughInjectives : EnoughInjectives (ModuleCat.{max v u} R) := + EnoughInjectives.of_adjunction (ModuleCat.restrictCoextendScalarsAdj.{max v u} (algebraMap ℤ R)) + +open ModuleCat in +instance [UnivLE.{u,v}] : EnoughInjectives (ModuleCat.{v} R) := + letI := (equivShrink.{v} R).symm.ring + letI := enoughInjectives.{v} (Shrink.{v} R) + EnoughInjectives.of_equivalence (restrictScalars (equivShrink R).symm.ringEquiv.toRingHom) diff --git a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean index ce1d6cca433f8..4ba5ef78289de 100644 --- a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean +++ b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic import Mathlib.Algebra.Category.ModuleCat.Basic import Mathlib.CategoryTheory.ConcreteCategory.EpiMono @@ -31,7 +31,7 @@ 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 mono_iff_ker_eq_bot : Mono f ↔ LinearMap.ker f = ⊥ := - ⟨fun hf => ker_eq_bot_of_mono _, fun hf => + ⟨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 diff --git a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean index 16abcd3247283..58c0fe8253d3a 100644 --- a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Justus Springer -/ import Mathlib.Algebra.Category.Grp.FilteredColimits -import Mathlib.Algebra.Category.ModuleCat.Basic +import Mathlib.Algebra.Category.ModuleCat.Colimits /-! # The forgetful functor from `R`-modules preserves filtered colimits. @@ -184,6 +184,9 @@ instance forgetPreservesFilteredColimits : PreservesFilteredColimits (forget (Mo Limits.compPreservesFilteredColimits (forget₂ (ModuleCat R) AddCommGrp) (forget AddCommGrp) +instance forgetReflectsFilteredColimits : ReflectsFilteredColimits (forget (ModuleCat.{u} R)) where + reflects_filtered_colimits _ := { reflectsColimit := reflectsColimitOfReflectsIsomorphisms _ _ } + end end ModuleCat.FilteredColimits diff --git a/Mathlib/Algebra/Category/ModuleCat/Images.lean b/Mathlib/Algebra/Category/ModuleCat/Images.lean index f08f291b4ebfa..9a516ef12b9b4 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Images.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Images.lean @@ -97,12 +97,12 @@ noncomputable def imageIsoRange {G H : ModuleCat.{v} R} (f : G ⟶ H) : @[simp, reassoc, elementwise] theorem imageIsoRange_inv_image_ι {G H : ModuleCat.{v} R} (f : G ⟶ H) : - (imageIsoRange f).inv ≫ Limits.image.ι f = ModuleCat.ofHom f.range.subtype := + (imageIsoRange f).inv ≫ Limits.image.ι f = ModuleCat.asHom f.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.ofHom f.range.subtype = Limits.image.ι f := by - erw [← imageIsoRange_inv_image_ι f, Iso.hom_inv_id_assoc] + (imageIsoRange f).hom ≫ ModuleCat.asHom f.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 ab64c32a4c6ea..f579799501b6a 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Injective.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Injective.lean @@ -3,36 +3,47 @@ Copyright (c) 2023 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ -import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings -import Mathlib.Algebra.Category.Grp.EnoughInjectives -import Mathlib.Algebra.Category.Grp.ZModuleEquivalence -import Mathlib.Logic.Equiv.TransferInstance +import Mathlib.Algebra.Module.Injective +import Mathlib.CategoryTheory.Preadditive.Injective +import Mathlib.Algebra.Category.ModuleCat.EpiMono /-! -# Category of $R$-modules has enough injectives - -we lift enough injectives of abelian groups to arbitrary $R$-modules by adjoint functors -`restrictScalars ⊣ coextendScalars` - -## Implementation notes -This file is not part of `Algebra/Module/Injective.lean` to prevent import loop: enough-injectives -of abelian groups needs `Algebra/Module/Injective.lean` and this file needs enough-injectives of -abelian groups. +# Injective objects in the category of $R$-modules -/ open CategoryTheory -universe v u -variable (R : Type u) [Ring R] - -instance : EnoughInjectives (ModuleCat.{v} ℤ) := - EnoughInjectives.of_equivalence (forget₂ (ModuleCat ℤ) AddCommGrp) - -lemma ModuleCat.enoughInjectives : EnoughInjectives (ModuleCat.{max v u} R) := - EnoughInjectives.of_adjunction (ModuleCat.restrictCoextendScalarsAdj.{max v u} (algebraMap ℤ R)) - -open ModuleCat in -instance [UnivLE.{u,v}] : EnoughInjectives (ModuleCat.{v} R) := - letI := (equivShrink.{v} R).symm.ring - letI := enoughInjectives.{v} (Shrink.{v} R) - EnoughInjectives.of_equivalence (restrictScalars (equivShrink R).symm.ringEquiv.toRingHom) +universe u v +variable (R : Type u) (M : Type v) [Ring R] [AddCommGroup M] [Module R M] +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⟩ + +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⟩ + +theorem injective_iff_injective_object : + Module.Injective R M ↔ + CategoryTheory.Injective (ModuleCat.of R M) := + ⟨fun _ => injective_object_of_injective_module R M, + fun _ => injective_module_of_injective_object R M⟩ + +end Module + + +instance ModuleCat.ulift_injective_of_injective.{v'} + [Small.{v} R] [AddCommGroup M] [Module R M] + [CategoryTheory.Injective <| ModuleCat.of R M] : + CategoryTheory.Injective <| ModuleCat.of R (ULift.{v'} M) := + Module.injective_object_of_injective_module + (inj := Module.ulift_injective_of_injective + (inj := Module.injective_module_of_injective_object _ _)) diff --git a/Mathlib/Algebra/Category/ModuleCat/Kernels.lean b/Mathlib/Algebra/Category/ModuleCat/Kernels.lean index b93458aaf0343..22f0ec3245835 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Kernels.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Kernels.lean @@ -39,7 +39,7 @@ def kernelIsLimit : IsLimit (kernelCone f) := erw [← @Function.comp_apply _ _ _ f (Fork.ι s) c, ← coe_comp] rw [Fork.condition, HasZeroMorphisms.comp_zero (Fork.ι s) N] rfl) - (fun s => LinearMap.subtype_comp_codRestrict _ _ _) fun s m h => + (fun _ => LinearMap.subtype_comp_codRestrict _ _ _) fun s m h => LinearMap.ext fun x => Subtype.ext_iff_val.2 (by simp [← h]; rfl) /-- The cokernel cocone induced by the projection onto the quotient. -/ diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean index cad418c48ab2a..b801c34fa8861 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean @@ -203,10 +203,13 @@ instance : CommRing ((𝟙_ (ModuleCat.{u} R) : ModuleCat.{u} R) : Type u) := namespace MonoidalCategory @[simp] -theorem hom_apply {K L M N : ModuleCat.{u} R} (f : K ⟶ L) (g : M ⟶ N) (k : K) (m : M) : +theorem tensorHom_tmul {K L M N : ModuleCat.{u} R} (f : K ⟶ L) (g : M ⟶ N) (k : K) (m : M) : (f ⊗ g) (k ⊗ₜ m) = f k ⊗ₜ g m := rfl +@[deprecated (since := "2024-09-30")] alias hom_apply := tensorHom_tmul + + @[simp] theorem whiskerLeft_apply (L : ModuleCat.{u} R) {M N : ModuleCat.{u} R} (f : M ⟶ N) (l : L) (m : M) : @@ -249,6 +252,42 @@ theorem associator_inv_apply {M N K : ModuleCat.{u} R} (m : M) (n : N) (k : K) : ((α_ M N K).inv : M ⊗ N ⊗ K ⟶ (M ⊗ N) ⊗ K) (m ⊗ₜ (n ⊗ₜ k)) = m ⊗ₜ n ⊗ₜ k := rfl +variable {M₁ M₂ M₃ M₄ : ModuleCat.{u} R} + +section + +variable (f : M₁ → M₂ → M₃) (h₁ : ∀ m₁ m₂ n, f (m₁ + m₂) n = f m₁ n + f m₂ n) + (h₂ : ∀ (a : R) m n, f (a • m) n = a • f m n) + (h₃ : ∀ m n₁ n₂, f m (n₁ + n₂) = f m n₁ + f m n₂) + (h₄ : ∀ (a : R) m n, f m (a • n) = a • f 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₄) + +@[simp] +lemma tensorLift_tmul (m : M₁) (n : M₂) : + tensorLift f h₁ h₂ h₃ h₄ (m ⊗ₜ n) = f m n := rfl + +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) + +/-- 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 + +/-- 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 := by + rw [← cancel_epi (α_ _ _ _).hom] + exact tensor_ext₃' h + end MonoidalCategory open Opposite diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean index 55bbfb7b8390c..979e0ee459b68 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean @@ -38,7 +38,7 @@ def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) : rw [Function.comp_apply] -- This used to be `rw` and was longer (?), but we need `erw` after leanprover/lean4#2644 erw [MonoidalCategory.braiding_hom_apply, TensorProduct.lift.tmul] - right_inv f := rfl + right_inv _ := rfl instance : MonoidalClosed (ModuleCat.{u} R) where closed M := diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean index caf2f760e93ea..653280c6b57bd 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kim Morrison +Authors: Kim Morrison, Joël Riou -/ import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings import Mathlib.Algebra.Category.Ring.Basic @@ -96,6 +96,19 @@ lemma naturality_apply (f : M₁ ⟶ M₂) {X Y : Cᵒᵖ} (g : X ⟶ Y) (x : M Hom.app f Y (M₁.map g x) = M₂.map g (Hom.app f X x) := congr_fun ((forget _).congr_map (Hom.naturality f g)) x +/-- Constructor for isomorphisms in the category of presheaves of modules. -/ +@[simps!] +def isoMk (app : ∀ (X : Cᵒᵖ), M₁.obj X ≅ M₂.obj X) + (naturality : ∀ ⦃X Y : Cᵒᵖ⦄ (f : X ⟶ Y), + M₁.map f ≫ (ModuleCat.restrictScalars (R.map f)).map (app Y).hom = + (app X).hom ≫ M₂.map f := by aesop_cat) : M₁ ≅ M₂ where + hom := { app := fun X ↦ (app X).hom } + inv := + { app := fun X ↦ (app X).inv + naturality := fun {X Y} f ↦ by + rw [← cancel_epi (app X).hom, ← reassoc_of% (naturality f), Iso.map_hom_inv_id, + Category.comp_id, Iso.hom_inv_id_assoc]} + /-- The underlying presheaf of abelian groups of a presheaf of modules. -/ def presheaf : Cᵒᵖ ⥤ Ab where obj X := (forget₂ _ _).obj (M.obj X) diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean index 26b9df8025f49..f58ed17c074ed 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Colimits.lean @@ -63,22 +63,22 @@ taking a colimit in the category of modules over `R.obj X` for all `X`. -/ @[simps] noncomputable def colimitPresheafOfModules : PresheafOfModules R where obj X := colimit (F ⋙ evaluation R X) - map {X Y} f := colimMap (whiskerLeft F (restriction R f)) ≫ + map {_ Y} f := colimMap (whiskerLeft F (restriction R f)) ≫ (preservesColimitIso (ModuleCat.restrictScalars (R.map f)) (F ⋙ evaluation R Y)).inv map_id X := colimit.hom_ext (fun j => by dsimp rw [ι_colimMap_assoc, whiskerLeft_app, restriction_app] - erw [ι_preservesColimitsIso_inv (G := ModuleCat.restrictScalars (R.map (𝟙 X))), + erw [ι_preservesColimitIso_inv (G := ModuleCat.restrictScalars (R.map (𝟙 X))), ModuleCat.restrictScalarsId'App_inv_naturality] rw [map_id] dsimp) map_comp {X Y Z} f g := colimit.hom_ext (fun j => by dsimp rw [ι_colimMap_assoc, whiskerLeft_app, restriction_app, assoc, ι_colimMap_assoc] - erw [ι_preservesColimitsIso_inv (G := ModuleCat.restrictScalars (R.map (f ≫ g))), - ι_preservesColimitsIso_inv_assoc (G := ModuleCat.restrictScalars (R.map f))] + erw [ι_preservesColimitIso_inv (G := ModuleCat.restrictScalars (R.map (f ≫ g))), + ι_preservesColimitIso_inv_assoc (G := ModuleCat.restrictScalars (R.map f))] rw [← Functor.map_comp_assoc, ι_colimMap_assoc] - erw [ι_preservesColimitsIso_inv (G := ModuleCat.restrictScalars (R.map g))] + erw [ι_preservesColimitIso_inv (G := ModuleCat.restrictScalars (R.map g))] rw [map_comp, ModuleCat.restrictScalarsComp'_inv_app, assoc, assoc, whiskerLeft_app, whiskerLeft_app, restriction_app, restriction_app] simp only [Functor.map_comp, assoc] @@ -94,7 +94,7 @@ noncomputable def colimitCocone : Cocone F where { app := fun X ↦ colimit.ι (F ⋙ evaluation R X) j naturality := fun {X Y} f ↦ by dsimp - erw [colimit.ι_desc_assoc, assoc, ← ι_preservesColimitsIso_inv] + erw [colimit.ι_desc_assoc, assoc, ← ι_preservesColimitIso_inv] rfl } naturality := fun {X Y} f ↦ by ext1 X diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/EpiMono.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/EpiMono.lean new file mode 100644 index 0000000000000..2bdcf0998ad7c --- /dev/null +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/EpiMono.lean @@ -0,0 +1,64 @@ +/- +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.Category.ModuleCat.Presheaf.Colimits +import Mathlib.Algebra.Category.ModuleCat.Presheaf.Limits + +/-! +# Epimorphisms and monomorphisms in the category of presheaves of modules + +In this file, we give characterizations of epimorphisms and monomorphisms +in the category of presheaves of modules. + +-/ + +universe v v₁ u₁ u + +open CategoryTheory + +namespace PresheafOfModules + +variable {C : Type u₁} [Category.{v₁} C] {R : Cᵒᵖ ⥤ RingCat.{u}} + {M₁ M₂ : PresheafOfModules.{v} R} {f : M₁ ⟶ M₂} + +lemma epi_of_surjective (hf : ∀ ⦃X : Cᵒᵖ⦄, Function.Surjective (f.app X)) : Epi f where + left_cancellation g₁ g₂ hg := by + ext X m₂ + obtain ⟨m₁, rfl⟩ := hf m₂ + exact congr_fun ((evaluation R X ⋙ forget _).congr_map hg) m₁ + +lemma mono_of_injective (hf : ∀ ⦃X : Cᵒᵖ⦄, Function.Injective (f.app X)) : Mono f where + right_cancellation {M} g₁ g₂ hg := by + ext X m + exact hf (congr_fun ((evaluation R X ⋙ forget _).congr_map hg) m) + +variable (f) + +instance [Epi f] (X : Cᵒᵖ) : Epi (f.app X) := + inferInstanceAs (Epi ((evaluation R X).map f)) + +instance [Mono f] (X : Cᵒᵖ) : Mono (f.app X) := + inferInstanceAs (Mono ((evaluation R X).map f)) + +lemma surjective_of_epi [Epi f] (X : Cᵒᵖ) : + Function.Surjective (f.app X) := by + rw [← ModuleCat.epi_iff_surjective] + infer_instance + +lemma injective_of_mono [Mono f] (X : Cᵒᵖ) : + Function.Injective (f.app X) := by + rw [← ModuleCat.mono_iff_injective] + infer_instance + +lemma epi_iff_surjective : + Epi f ↔ ∀ ⦃X : Cᵒᵖ⦄, Function.Surjective (f.app X) := + ⟨fun _ ↦ surjective_of_epi f, epi_of_surjective⟩ + +lemma mono_iff_surjective : + Mono f ↔ ∀ ⦃X : Cᵒᵖ⦄, Function.Injective (f.app X) := + ⟨fun _ ↦ injective_of_mono f, mono_of_injective⟩ + +end PresheafOfModules diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Free.lean new file mode 100644 index 0000000000000..e17dd748c6cfd --- /dev/null +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Free.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2024 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin, Joel Riou +-/ +import Mathlib.Algebra.Category.ModuleCat.Presheaf +import Mathlib.Algebra.Category.ModuleCat.Adjunctions + +/-! +# The free presheaf of modules on a presheaf of sets + +In this file, given a presheaf of rings `R` on a category `C`, +we construct the functor +`PresheafOfModules.free : (Cᵒᵖ ⥤ Type u) ⥤ PresheafOfModules.{u} R` +which sends a presheaf of types to the corresponding presheaf of free modules. +`PresheafOfModules.freeAdjunction` shows that this functor is the left +adjoint to the forget functor. + +## Notes + +This contribution was created as part of the AIM workshop +"Formalizing algebraic geometry" in June 2024. + +-/ + +universe u v₁ u₁ + +open CategoryTheory + +namespace PresheafOfModules + +variable {C : Type u₁} [Category.{v₁} C] (R : Cᵒᵖ ⥤ RingCat.{u}) + +variable {R} in +/-- Given a presheaf of types `F : Cᵒᵖ ⥤ Type u`, this is the presheaf +of modules over `R` which sends `X : Cᵒᵖ` to the free `R.obj X`-module on `F.obj X`. -/ +@[simps] +noncomputable def freeObj (F : Cᵒᵖ ⥤ Type u) : PresheafOfModules.{u} R where + obj X := (ModuleCat.free (R.obj X)).obj (F.obj X) + map {X Y} f := ModuleCat.freeDesc (fun x ↦ ModuleCat.freeMk (F.map f x)) + map_id := by aesop + +/-- The free presheaf of modules functor `(Cᵒᵖ ⥤ Type u) ⥤ PresheafOfModules.{u} R`. -/ +@[simps] +noncomputable def free : (Cᵒᵖ ⥤ Type u) ⥤ PresheafOfModules.{u} R where + obj := freeObj + map {F G} φ := + { app := fun X ↦ (ModuleCat.free (R.obj X)).map (φ.app X) + naturality := fun {X Y} f ↦ by + dsimp + ext x + simp [FunctorToTypes.naturality] } + +section + +variable {R} + +variable {F : Cᵒᵖ ⥤ Type u} {G : PresheafOfModules.{u} R} + +/-- The morphism of presheaves of modules `freeObj F ⟶ G` corresponding to +a morphism `F ⟶ G.presheaf ⋙ forget _` of presheaves of types. -/ +@[simps] +noncomputable def freeObjDesc (φ : F ⟶ G.presheaf ⋙ forget _) : freeObj F ⟶ G where + app X := ModuleCat.freeDesc (φ.app X) + naturality {X Y} f := by + dsimp + ext x + simpa using NatTrans.naturality_apply φ f x + +variable (F R) in +/-- The unit of `PresheafOfModules.freeAdjunction`. -/ +@[simps] +noncomputable def freeAdjunctionUnit : F ⟶ (freeObj (R := R) F).presheaf ⋙ forget _ where + app X x := ModuleCat.freeMk x + naturality X Y f := by ext; simp [presheaf] + +/-- The bijection `(freeObj F ⟶ G) ≃ (F ⟶ G.presheaf ⋙ forget _)` when +`F` is a presheaf of types and `G` a presheaf of modules. -/ +noncomputable def freeHomEquiv : (freeObj F ⟶ G) ≃ (F ⟶ G.presheaf ⋙ forget _) where + toFun ψ := freeAdjunctionUnit R F ≫ whiskerRight ((toPresheaf _).map ψ) _ + invFun φ := freeObjDesc φ + left_inv ψ := by ext1 X; dsimp; ext x; simp [toPresheaf] + right_inv φ := by ext; simp [toPresheaf] + +lemma free_hom_ext {ψ ψ' : freeObj F ⟶ G} + (h : freeAdjunctionUnit R F ≫ whiskerRight ((toPresheaf _).map ψ) _ = + freeAdjunctionUnit R F ≫ whiskerRight ((toPresheaf _).map ψ') _ ) : ψ = ψ' := + freeHomEquiv.injective h + +variable (R) in +/-- The free presheaf of modules functor is left adjoint to the forget functor +`PresheafOfModules.{u} R ⥤ Cᵒᵖ ⥤ Type u`. -/ +noncomputable def freeAdjunction : + free.{u} R ⊣ (toPresheaf R ⋙ (whiskeringRight _ _ _).obj (forget Ab)) := + Adjunction.mkOfHomEquiv + { homEquiv := fun _ _ ↦ freeHomEquiv + homEquiv_naturality_left_symm := fun {F₁ F₂ G} f g ↦ + free_hom_ext (by ext; simp [freeHomEquiv, toPresheaf]) + homEquiv_naturality_right := fun {F G₁ G₂} f g ↦ rfl } + +variable (F G) in +@[simp] +lemma freeAdjunction_homEquiv : (freeAdjunction R).homEquiv F G = freeHomEquiv := by + simp [freeAdjunction, Adjunction.mkOfHomEquiv_homEquiv] + +variable (R F) in +@[simp] +lemma freeAdjunction_unit_app : + (freeAdjunction R).unit.app F = freeAdjunctionUnit R F := rfl + +end + +end PresheafOfModules diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean index a8c8858cd5bfe..127f29b50a89e 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean @@ -63,7 +63,7 @@ taking a limit in the category of modules over `R.obj X` for all `X`. -/ @[simps] noncomputable def limitPresheafOfModules : PresheafOfModules R where obj X := limit (F ⋙ evaluation R X) - map {X Y} f := limMap (whiskerLeft F (restriction R f)) ≫ + map {_ Y} f := limMap (whiskerLeft F (restriction R f)) ≫ (preservesLimitIso (ModuleCat.restrictScalars (R.map f)) (F ⋙ evaluation R Y)).inv map_id X := by dsimp @@ -73,7 +73,7 @@ noncomputable def limitPresheafOfModules : PresheafOfModules R where dsimp simp only [limMap_π, Functor.comp_obj, evaluation_obj, whiskerLeft_app, restriction_app, assoc] - erw [preservesLimitsIso_hom_π] + erw [preservesLimitIso_hom_π] rw [← ModuleCat.restrictScalarsId'App_inv_naturality, map_id, ModuleCat.restrictScalarsId'_inv_app] dsimp @@ -85,14 +85,14 @@ noncomputable def limitPresheafOfModules : PresheafOfModules R where intro j simp only [Functor.comp_obj, evaluation_obj, limMap_π, whiskerLeft_app, restriction_app, map_comp, ModuleCat.restrictScalarsComp'_inv_app, Functor.map_comp, assoc] - erw [preservesLimitsIso_hom_π] + erw [preservesLimitIso_hom_π] rw [← ModuleCat.restrictScalarsComp'App_inv_naturality] dsimp rw [← Functor.map_comp_assoc, ← Functor.map_comp_assoc, assoc, - preservesLimitsIso_inv_π] + preservesLimitIso_inv_π] erw [limMap_π] dsimp - simp only [Functor.map_comp, assoc, preservesLimitsIso_inv_π_assoc] + simp only [Functor.map_comp, assoc, preservesLimitIso_inv_π_assoc] erw [limMap_π_assoc] dsimp @@ -106,7 +106,7 @@ noncomputable def limitCone : Cone F where { app := fun X ↦ limit.π (F ⋙ evaluation R X) j naturality := fun {X Y} f ↦ by dsimp - simp only [assoc, preservesLimitsIso_inv_π] + simp only [assoc, preservesLimitIso_inv_π] apply limMap_π } naturality := fun {j j'} f ↦ by ext1 X diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean new file mode 100644 index 0000000000000..2b9de6dc8f4e9 --- /dev/null +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson, Jack McKoen, Joël Riou +-/ +import Mathlib.Algebra.Category.ModuleCat.Presheaf +import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic + +/-! +# The monoidal category structure on presheaves of modules + +Given a presheaf of commutative rings `R : Cᵒᵖ ⥤ CommRingCat`, we construct +the monoidal category structure on the category of presheaves of modules +`PresheafOfModules (R ⋙ forget₂ _ _)`. The tensor product `M₁ ⊗ M₂` is defined +as the presheaf of modules which sends `X : Cᵒᵖ` to `M₁.obj X ⊗ M₂.obj X`. + +## Notes + +This contribution was created as part of the AIM workshop +"Formalizing algebraic geometry" in June 2024. + +-/ + +open CategoryTheory MonoidalCategory Category + +universe v u v₁ u₁ + +variable {C : Type*} [Category C] {R : Cᵒᵖ ⥤ CommRingCat.{u}} + +instance (X : Cᵒᵖ) : CommRing ((R ⋙ forget₂ _ RingCat).obj X) := + inferInstanceAs (CommRing (R.obj X)) + +namespace PresheafOfModules + +namespace Monoidal + +variable (M₁ M₂ M₃ M₄ : PresheafOfModules.{u} (R ⋙ forget₂ _ _)) + +/-- Auxiliary definition for `tensorObj`. -/ +noncomputable def tensorObjMap {X Y : Cᵒᵖ} (f : X ⟶ Y) : M₁.obj X ⊗ M₂.obj X ⟶ + (ModuleCat.restrictScalars (R.map f)).obj (M₁.obj Y ⊗ M₂.obj Y) := + ModuleCat.MonoidalCategory.tensorLift (fun m₁ m₂ ↦ M₁.map f m₁ ⊗ₜ M₂.map f m₂) + (by intro m₁ m₁' m₂; dsimp; rw [map_add, TensorProduct.add_tmul]) + (by intro a m₁ m₂; dsimp; erw [M₁.map_smul]; rfl) + (by intro m₁ m₂ m₂'; dsimp; rw [map_add, TensorProduct.tmul_add]) + (by intro a m₁ m₂; dsimp; erw [M₂.map_smul, TensorProduct.tmul_smul (r := R.map f a)]; rfl) + +/-- The tensor product of two presheaves of modules. -/ +@[simps obj] +noncomputable def tensorObj : PresheafOfModules (R ⋙ forget₂ _ _) where + obj X := M₁.obj X ⊗ M₂.obj X + map f := tensorObjMap M₁ M₂ f + map_id X := ModuleCat.MonoidalCategory.tensor_ext (by + intro m₁ m₂ + dsimp [tensorObjMap] + simp only [map_id, Functor.comp_obj, CommRingCat.forgetToRingCat_obj, Functor.comp_map, + ModuleCat.restrictScalarsId'_inv_app, ModuleCat.restrictScalarsId'App_inv_apply] + rfl) + map_comp f g := ModuleCat.MonoidalCategory.tensor_ext (by + 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.restrictScalars.map_apply, ModuleCat.restrictScalarsComp'App_inv_apply] + rfl) + +variable {M₁ M₂ M₃ M₄} + +@[simp] +lemma tensorObj_map_tmul {X Y : Cᵒᵖ} (f : X ⟶ Y) (m₁ : M₁.obj X) (m₂ : M₂.obj X) : + 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 + +/-- The tensor product of two morphisms of presheaves of modules. -/ +@[simps] +noncomputable def tensorHom (f : M₁ ⟶ M₂) (g : M₃ ⟶ M₄) : tensorObj M₁ M₃ ⟶ tensorObj M₂ M₄ where + 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) + +end Monoidal + +open Monoidal + +open ModuleCat.MonoidalCategory in +noncomputable instance monoidalCategoryStruct : + MonoidalCategoryStruct (PresheafOfModules.{u} (R ⋙ forget₂ _ _)) where + tensorObj := tensorObj + whiskerLeft _ _ _ g := tensorHom (𝟙 _) g + whiskerRight f _ := tensorHom f (𝟙 _) + tensorHom := tensorHom + tensorUnit := unit _ + associator M₁ M₂ M₃ := isoMk (fun _ ↦ α_ _ _ _) + (fun _ _ _ ↦ ModuleCat.MonoidalCategory.tensor_ext₃' (by intros; rfl)) + leftUnitor M := Iso.symm (isoMk (fun _ ↦ (λ_ _).symm) (fun X Y f ↦ by + ext m + dsimp + erw [leftUnitor_inv_apply, leftUnitor_inv_apply, tensorObj_map_tmul, (R.map f).map_one] + rfl)) + rightUnitor M := Iso.symm (isoMk (fun _ ↦ (ρ_ _).symm) (fun X Y f ↦ by + ext m + dsimp + erw [rightUnitor_inv_apply, rightUnitor_inv_apply, tensorObj_map_tmul, (R.map f).map_one] + rfl)) + +noncomputable instance monoidalCategory : + MonoidalCategory (PresheafOfModules.{u} (R ⋙ forget₂ _ _)) where + tensorHom_def _ _ := by ext1; apply tensorHom_def + tensor_id _ _ := by ext1; apply tensor_id + tensor_comp _ _ _ _ := by ext1; apply tensor_comp + whiskerLeft_id M₁ M₂ := by + ext1 X + apply MonoidalCategory.whiskerLeft_id (C := ModuleCat (R.obj X)) + id_whiskerRight _ _ := by + ext1 X + apply MonoidalCategory.id_whiskerRight (C := ModuleCat (R.obj X)) + associator_naturality _ _ _ := by ext1; apply associator_naturality + leftUnitor_naturality _ := by ext1; apply leftUnitor_naturality + rightUnitor_naturality _ := by ext1; apply rightUnitor_naturality + pentagon _ _ _ _ := by ext1; apply pentagon + triangle _ _ := by ext1; apply triangle + +end PresheafOfModules diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean index db55107701398..55d42463d8a56 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafification.lean @@ -124,7 +124,7 @@ noncomputable def sheafificationAdjunction : apply (toPresheaf _).map_injective erw [toPresheaf_map_sheafificationHomEquiv] } -lemma sheaififcationAdjunction_homEquiv_apply {P : PresheafOfModules.{v} R₀} +lemma sheafificationAdjunction_homEquiv_apply {P : PresheafOfModules.{v} R₀} {F : SheafOfModules.{v} R} (f : (sheafification α).obj P ⟶ F) : (sheafificationAdjunction α).homEquiv P F f = sheafificationHomEquiv α f := rfl diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean index 60d937b2076ae..c00b766a8362d 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean @@ -81,7 +81,6 @@ lemma isCompatible_map_smul_aux {Y Z : C} (f : Y ⟶ X) (g : Z ⟶ Y) · rw [hr₀', R.map_comp, comp_apply, ← hr₀, NatTrans.naturality_apply] · rw [hm₀', A.map_comp, AddCommGrp.coe_comp, Function.comp_apply, ← hm₀] erw [NatTrans.naturality_apply] - rfl variable (hr₀ : (r₀.map (whiskerRight α (forget _))).IsAmalgamation r) (hm₀ : (m₀.map (whiskerRight φ (forget _))).IsAmalgamation m) @@ -105,7 +104,6 @@ lemma isCompatible_map_smul : ((r₀.smul m₀).map (whiskerRight φ (forget _)) have hb₀ : (φ.app (Opposite.op Z)) b₀ = (A.map (f₁.op ≫ g₁.op)) m := by dsimp [b₀] erw [NatTrans.naturality_apply, hb₁, Functor.map_comp, comp_apply] - rfl have ha₀' : (α.app (Opposite.op Z)) a₀ = (R.map (f₂.op ≫ g₂.op)) r := by rw [ha₀, ← op_comp, fac, op_comp] have hb₀' : (φ.app (Opposite.op Z)) b₀ = (A.map (f₂.op ≫ g₂.op)) m := by @@ -203,7 +201,7 @@ instance : Subsingleton (SMulCandidate α φ r m) where all_goals apply Presheaf.imageSieve_mem apply A.isSeparated _ _ hS intro Y f ⟨⟨r₀, hr₀⟩, ⟨m₀, hm₀⟩⟩ - erw [h₁ f.op r₀ hr₀ m₀ hm₀, h₂ f.op r₀ hr₀ m₀ hm₀] + rw [h₁ f.op r₀ hr₀ m₀ hm₀, h₂ f.op r₀ hr₀ m₀ hm₀] noncomputable instance : Unique (SMulCandidate α φ r m) := uniqueOfSubsingleton (Nonempty.some inferInstance) @@ -222,20 +220,18 @@ lemma map_smul_eq {Y : Cᵒᵖ} (f : X ⟶ Y) (r₀ : R₀.obj Y) (hr₀ : α.ap protected lemma one_smul : smul α φ 1 m = m := by apply A.isSeparated _ _ (Presheaf.imageSieve_mem J φ m) rintro Y f ⟨m₀, hm₀⟩ - rw [← hm₀] - erw [map_smul_eq α φ 1 m f.op 1 (by simp) m₀ hm₀, one_smul] - rfl + rw [← hm₀, map_smul_eq α φ 1 m f.op 1 (by simp) m₀ hm₀, one_smul] protected lemma zero_smul : smul α φ 0 m = 0 := by apply A.isSeparated _ _ (Presheaf.imageSieve_mem J φ m) rintro Y f ⟨m₀, hm₀⟩ - erw [map_smul_eq α φ 0 m f.op 0 (by simp) m₀ hm₀, zero_smul, map_zero, + rw [map_smul_eq α φ 0 m f.op 0 (by simp) m₀ hm₀, zero_smul, map_zero, (A.val.map f.op).map_zero] protected lemma smul_zero : smul α φ r 0 = 0 := by apply A.isSeparated _ _ (Presheaf.imageSieve_mem J α r) rintro Y f ⟨r₀, hr₀⟩ - erw [(A.val.map f.op).map_zero, map_smul_eq α φ r 0 f.op r₀ hr₀ 0 (by simp), + rw [(A.val.map f.op).map_zero, map_smul_eq α φ r 0 f.op r₀ hr₀ 0 (by simp), smul_zero, map_zero] protected lemma smul_add : smul α φ r (m + m') = smul α φ r m + smul α φ r m' := by @@ -245,10 +241,10 @@ protected lemma smul_add : smul α φ r (m + m') = smul α φ r m + smul α φ r all_goals apply Presheaf.imageSieve_mem apply A.isSeparated _ _ hS rintro Y f ⟨⟨⟨r₀, hr₀⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩, ⟨m₀' : M₀.obj _, hm₀'⟩⟩ - erw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀, + rw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀, map_smul_eq α φ r m' f.op r₀ hr₀ m₀' hm₀', map_smul_eq α φ r (m + m') f.op r₀ hr₀ (m₀ + m₀') - (by erw [map_add, map_add, hm₀, hm₀']; rfl), + (by rw [map_add, map_add, hm₀, hm₀']), smul_add, map_add] protected lemma add_smul : smul α φ (r + r') m = smul α φ r m + smul α φ r' m := by @@ -258,7 +254,7 @@ protected lemma add_smul : smul α φ (r + r') m = smul α φ r m + smul α φ r all_goals apply Presheaf.imageSieve_mem apply A.isSeparated _ _ hS rintro Y f ⟨⟨⟨r₀ : R₀.obj _, hr₀⟩, ⟨r₀' : R₀.obj _, hr₀'⟩⟩, ⟨m₀, hm₀⟩⟩ - erw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀, + rw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀, map_smul_eq α φ r' m f.op r₀' hr₀' m₀ hm₀, map_smul_eq α φ (r + r') m f.op (r₀ + r₀') (by rw [map_add, map_add, hr₀, hr₀']) m₀ hm₀, add_smul, map_add] @@ -270,7 +266,7 @@ protected lemma mul_smul : smul α φ (r * r') m = smul α φ r (smul α φ r' m all_goals apply Presheaf.imageSieve_mem apply A.isSeparated _ _ hS rintro Y f ⟨⟨⟨r₀ : R₀.obj _, hr₀⟩, ⟨r₀' : R₀.obj _, hr₀'⟩⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩ - erw [map_smul_eq α φ (r * r') m f.op (r₀ * r₀') + rw [map_smul_eq α φ (r * r') m f.op (r₀ * r₀') (by rw [map_mul, map_mul, hr₀, hr₀']) m₀ hm₀, mul_smul, map_smul_eq α φ r (smul α φ r' m) f.op r₀ hr₀ (r₀' • m₀) (map_smul_eq α φ r' m f.op r₀' hr₀' m₀ hm₀).symm] @@ -296,9 +292,9 @@ lemma map_smul : all_goals apply Presheaf.imageSieve_mem apply A.isSeparated _ _ hS rintro Y f ⟨⟨r₀, hr₀⟩, ⟨m₀, hm₀⟩⟩ - erw [← comp_apply, ← Functor.map_comp, + rw [← comp_apply, ← Functor.map_comp, map_smul_eq α φ r m (π ≫ f.op) r₀ (by rw [hr₀, Functor.map_comp, comp_apply]) m₀ - (by erw [hm₀, Functor.map_comp, comp_apply]; rfl), + (by rw [hm₀, Functor.map_comp, comp_apply]), map_smul_eq α φ (R.val.map π r) (A.val.map π m) f.op r₀ hr₀ m₀ hm₀] end Sheafify diff --git a/Mathlib/Algebra/Category/ModuleCat/Subobject.lean b/Mathlib/Algebra/Category/ModuleCat/Subobject.lean index 134f3702fde18..a1508f23b2e54 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Subobject.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Subobject.lean @@ -82,7 +82,7 @@ noncomputable def toKernelSubobject {M N : ModuleCat.{v} R} {f : M ⟶ N} : @[simp] theorem toKernelSubobject_arrow {M N : ModuleCat R} {f : M ⟶ N} (x : LinearMap.ker f) : (kernelSubobject f).arrow (toKernelSubobject x) = x.1 := by - -- Porting note: The whole proof was just `simp [toKernelSubobject]`. + -- Porting note (#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] @@ -105,7 +105,7 @@ theorem cokernel_π_imageSubobject_ext {L M N : ModuleCat.{v} R} (f : L ⟶ M) [ (g : (imageSubobject f : ModuleCat.{v} R) ⟶ N) [HasCokernel g] {x y : N} (l : L) (w : x = y + g (factorThruImageSubobject f l)) : cokernel.π g x = cokernel.π g y := by subst w - -- Porting note: The proof from here used to just be `simp`. + -- Porting note (#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] diff --git a/Mathlib/Algebra/Category/MonCat/Adjunctions.lean b/Mathlib/Algebra/Category/MonCat/Adjunctions.lean index 6b618ac579624..256b8f3478523 100644 --- a/Mathlib/Algebra/Category/MonCat/Adjunctions.lean +++ b/Mathlib/Algebra/Category/MonCat/Adjunctions.lean @@ -46,7 +46,7 @@ instance hasForgetToSemigroup : HasForget₂ MonCat Semigrp where @[to_additive "The `adjoinZero`-forgetful adjunction from `AddSemigrp` to `AddMonCat`"] def adjoinOneAdj : adjoinOne ⊣ forget₂ MonCat.{u} Semigrp.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun S M => WithOne.lift.symm + { homEquiv := fun _ _ => WithOne.lift.symm homEquiv_naturality_left_symm := by intro S T M f g ext x @@ -67,7 +67,7 @@ def free : Type u ⥤ MonCat.{u} where /-- The free-forgetful adjunction for monoids. -/ def adj : free ⊣ forget MonCat.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun X G => FreeMonoid.lift.symm + { homEquiv := fun _ _ => FreeMonoid.lift.symm homEquiv_naturality_left_symm := fun _ _ => FreeMonoid.hom_eq (fun _ => rfl) } instance : (forget MonCat.{u}).IsRightAdjoint := diff --git a/Mathlib/Algebra/Category/MonCat/Basic.lean b/Mathlib/Algebra/Category/MonCat/Basic.lean index 22bdae9208498..4dbb96dfa65aa 100644 --- a/Mathlib/Algebra/Category/MonCat/Basic.lean +++ b/Mathlib/Algebra/Category/MonCat/Basic.lean @@ -46,7 +46,7 @@ add_decl_doc AddMonCat.AssocAddMonoidHom @[to_additive] instance bundledHom : BundledHom AssocMonoidHom where - toFun {X Y} _ _ f := ⇑f + toFun {_ _} _ _ f := ⇑f id _ := MonoidHom.id _ comp _ _ _ := MonoidHom.comp @@ -145,7 +145,7 @@ instance {G : Type*} [Group G] : Group (MonCat.of G) := by assumption "Universe lift functor for additive monoids."] def uliftFunctor : MonCat.{u} ⥤ MonCat.{max u v} where obj X := MonCat.of (ULift.{v, u} X) - map {X Y} f := MonCat.ofHom <| + map {_ _} f := MonCat.ofHom <| MulEquiv.ulift.symm.toMonoidHom.comp <| f.comp MulEquiv.ulift.toMonoidHom map_id X := by rfl map_comp {X Y Z} f g := by rfl @@ -249,7 +249,7 @@ lemma ofHom_apply {X Y : Type u} [CommMonoid X] [CommMonoid Y] (f : X →* Y) (x "Universe lift functor for additive commutative monoids."] def uliftFunctor : CommMonCat.{u} ⥤ CommMonCat.{max u v} where obj X := CommMonCat.of (ULift.{v, u} X) - map {X Y} f := CommMonCat.ofHom <| + map {_ _} f := CommMonCat.ofHom <| MulEquiv.ulift.symm.toMonoidHom.comp <| f.comp MulEquiv.ulift.toMonoidHom map_id X := by rfl map_comp {X Y Z} f g := by rfl diff --git a/Mathlib/Algebra/Category/MonCat/Colimits.lean b/Mathlib/Algebra/Category/MonCat/Colimits.lean index bfb19dcc5a1bc..ac67635fefbbe 100644 --- a/Mathlib/Algebra/Category/MonCat/Colimits.lean +++ b/Mathlib/Algebra/Category/MonCat/Colimits.lean @@ -122,7 +122,7 @@ instance : Inhabited (ColimitType F) := by instance monoidColimitType : Monoid (ColimitType F) where one := Quotient.mk _ one - mul := Quotient.map₂ mul fun x x' rx y y' ry => + mul := Quotient.map₂ mul fun _ x' rx y _ ry => Setoid.trans (Relation.mul_1 _ _ y rx) (Relation.mul_2 x' _ _ ry) one_mul := Quotient.ind fun _ => Quotient.sound <| Relation.one_mul _ mul_one := Quotient.ind fun _ => Quotient.sound <| Relation.mul_one _ diff --git a/Mathlib/Algebra/Category/MonCat/Limits.lean b/Mathlib/Algebra/Category/MonCat/Limits.lean index 77a05ad7f091f..123dc3372c9c1 100644 --- a/Mathlib/Algebra/Category/MonCat/Limits.lean +++ b/Mathlib/Algebra/Category/MonCat/Limits.lean @@ -207,7 +207,7 @@ noncomputable instance forget₂CreatesLimit : CreatesLimit F (forget₂ CommMon validLift := by apply IsLimit.uniqueUpToIso (MonCat.HasLimits.limitConeIsLimit _) t makesLimit := IsLimit.ofFaithful (forget₂ CommMonCat MonCat.{u}) - (MonCat.HasLimits.limitConeIsLimit _) (fun s => _) fun s => rfl } + (MonCat.HasLimits.limitConeIsLimit _) (fun _ => _) fun _ => rfl } /-- A choice of limit cone for a functor into `CommMonCat`. (Generally, you'll just want to use `limit F`.) diff --git a/Mathlib/Algebra/Category/Ring/Adjunctions.lean b/Mathlib/Algebra/Category/Ring/Adjunctions.lean index 7e9619ecea87c..968ee34718fb1 100644 --- a/Mathlib/Algebra/Category/Ring/Adjunctions.lean +++ b/Mathlib/Algebra/Category/Ring/Adjunctions.lean @@ -47,7 +47,7 @@ theorem free_map_coe {α β : Type u} {f : α → β} : ⇑(free.map f) = ⇑(re -/ def adj : free ⊣ forget CommRingCat.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun X R => homEquiv + { homEquiv := fun _ _ => homEquiv homEquiv_naturality_left_symm := fun {_ _ Y} f g => RingHom.ext fun x => eval₂_cast_comp f (Int.castRingHom Y) g x } diff --git a/Mathlib/Algebra/Category/Ring/Basic.lean b/Mathlib/Algebra/Category/Ring/Basic.lean index 4542d373913f0..4d03754154342 100644 --- a/Mathlib/Algebra/Category/Ring/Basic.lean +++ b/Mathlib/Algebra/Category/Ring/Basic.lean @@ -47,10 +47,6 @@ instance bundledHom : BundledHom AssocRingHom where --deriving instance LargeCategory, ConcreteCategory for SemiRingCat -- see https://github.com/leanprover-community/mathlib4/issues/5020 --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : SemiRingCat) where ⊢ - (forget SemiRingCat).obj R ≟ R - instance instSemiring (X : SemiRingCat) : Semiring X := X.str instance instFunLike {X Y : SemiRingCat} : FunLike (X ⟶ Y) X Y := @@ -143,6 +139,11 @@ theorem ofHom_apply {R S : Type u} [Semiring R] [Semiring S] (f : R →+* S) (x ofHom f x = f x := rfl +/-- A variant of `ofHom_apply` that makes `simpNF` happy -/ +@[simp] +theorem ofHom_apply' {R S : Type u} [Semiring R] [Semiring S] (f : R →+* S) (x : R) : + DFunLike.coe (α := R) (β := fun _ ↦ S) (ofHom f) x = f x := rfl + /-- Ring equivalence are isomorphisms in category of semirings -/ @@ -176,10 +177,6 @@ instance : BundledHom.ParentProjection @Ring.toSemiring := instance (X : RingCat) : Ring X := X.str --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : RingCat) where ⊢ - (forget RingCat).obj R ≟ R - instance instRing (X : RingCat) : Ring X := X.str instance instFunLike {X Y : RingCat} : FunLike (X ⟶ Y) X Y := @@ -207,10 +204,9 @@ def of (R : Type u) [Ring R] : RingCat := def ofHom {R S : Type u} [Ring R] [Ring S] (f : R →+* S) : of R ⟶ of S := f --- Porting note: I think this is now redundant. --- @[simp] --- theorem ofHom_apply {R S : Type u} [Ring R] [Ring S] (f : R →+* S) (x : R) : ofHom f x = f x := --- rfl +theorem ofHom_apply {R S : Type u} [Ring R] [Ring S] (f : R →+* S) (x : R) : ofHom f x = f x := + rfl + instance : Inhabited RingCat := ⟨of PUnit⟩ @@ -222,6 +218,11 @@ instance (R : RingCat) : Ring R := theorem coe_of (R : Type u) [Ring R] : (RingCat.of R : Type u) = R := rfl +/-- A variant of `ofHom_apply` that makes `simpNF` happy -/ +@[simp] +theorem ofHom_apply' {R S : Type u} [Ring R] [Ring S] (f : R →+* S) (x : R) : + DFunLike.coe (α := R) (β := fun _ ↦ S) (ofHom f) x = f x := rfl + -- Coercing the identity morphism, as a ring homomorphism, gives the identity function. @[simp] theorem coe_ringHom_id {X : RingCat} : @DFunLike.coe (X →+* X) X (fun _ ↦ X) _ (𝟙 X) = id := @@ -273,7 +274,7 @@ instance hasForgetToAddCommGrp : HasForget₂ RingCat AddCommGrp where end RingCat /-- The category of commutative semirings. -/ -def CommSemiRingCat : Type (u + 1) := +abbrev CommSemiRingCat : Type (u + 1) := Bundled CommSemiring namespace CommSemiRingCat @@ -294,10 +295,6 @@ instance : CoeSort CommSemiRingCat Type* where instance (X : CommSemiRingCat) : CommSemiring X := X.str --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : CommSemiRingCat) where ⊢ - (forget CommSemiRingCat).obj R ≟ R - instance instCommSemiring (X : CommSemiRingCat) : CommSemiring X := X.str instance instCommSemiring' (X : CommSemiRingCat) : CommSemiring <| (forget CommSemiRingCat).obj X := @@ -336,11 +333,14 @@ lemma RingEquiv_coe_eq {X Y : Type _} [CommSemiring X] [CommSemiring Y] (e : X ConcreteCategory.instFunLike (e : X →+* Y) : X → Y) = ↑e := rfl --- Porting note: I think this is now redundant. --- @[simp] --- theorem ofHom_apply {R S : Type u} [CommSemiring R] [CommSemiring S] (f : R →+* S) (x : R) : --- ofHom f x = f x := --- rfl +theorem ofHom_apply {R S : Type u} [CommSemiring R] [CommSemiring S] (f : R →+* S) (x : R) : + ofHom f x = f x := + rfl + +/-- A variant of `ofHom_apply` that makes `simpNF` happy -/ +@[simp] +theorem ofHom_apply' {R S : Type u} [CommSemiring R] [CommSemiring S] (f : R →+* S) (x : R) : + DFunLike.coe (α := R) (β := fun _ ↦ S) (ofHom f) x = f x := rfl instance : Inhabited CommSemiRingCat := ⟨of PUnit⟩ @@ -389,7 +389,7 @@ instance hasForgetToSemiRingCat : HasForget₂ CommSemiRingCat SemiRingCat := /-- The forgetful functor from commutative rings to (multiplicative) commutative monoids. -/ instance hasForgetToCommMonCat : HasForget₂ CommSemiRingCat CommMonCat := - HasForget₂.mk' (fun R : CommSemiRingCat => CommMonCat.of R) (fun R => rfl) + HasForget₂.mk' (fun R : CommSemiRingCat => CommMonCat.of R) (fun _ => rfl) -- Porting note: `(_ := _)` trick (fun {R₁ R₂} f => RingHom.toMonoidHom (α := R₁) (β := R₂) f) (by rfl) @@ -412,7 +412,7 @@ instance forgetReflectIsos : (forget CommSemiRingCat).ReflectsIsomorphisms where end CommSemiRingCat /-- The category of commutative rings. -/ -def CommRingCat : Type (u + 1) := +abbrev CommRingCat : Type (u + 1) := Bundled CommRing namespace CommRingCat @@ -424,17 +424,6 @@ instance : BundledHom.ParentProjection @CommRing.toRing := -- see https://github.com/leanprover-community/mathlib4/issues/5020 deriving instance LargeCategory for CommRingCat -instance : ConcreteCategory CommRingCat := by - dsimp [CommRingCat] - infer_instance - -instance : CoeSort CommRingCat Type* where - coe X := X.α - --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : CommRingCat) where ⊢ - (forget CommRingCat).obj R ≟ R - instance instCommRing (X : CommRingCat) : CommRing X := X.str instance instCommRing' (X : CommRingCat) : CommRing <| (forget CommRingCat).obj X := X.str @@ -495,11 +484,15 @@ lemma RingEquiv_coe_eq {X Y : Type _} [CommRing X] [CommRing Y] (e : X ≃+* Y) ConcreteCategory.instFunLike (e : X →+* Y) : X → Y) = ↑e := rfl --- Porting note: I think this is now redundant. --- @[simp] --- theorem ofHom_apply {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (x : R) : --- ofHom f x = f x := --- rfl +theorem ofHom_apply {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (x : R) : + ofHom f x = f x := + rfl + +/-- A variant of `ofHom_apply` that makes `simpNF` happy -/ +@[simp] +theorem ofHom_apply' {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (x : R) : + DFunLike.coe (α := R) (β := fun _ ↦ S) (ofHom f) x = f x := rfl + instance : Inhabited CommRingCat := ⟨of PUnit⟩ @@ -554,8 +547,8 @@ instance hasForgetToRingCat : HasForget₂ CommRingCat RingCat := /-- The forgetful functor from commutative rings to (multiplicative) commutative monoids. -/ instance hasForgetToCommSemiRingCat : HasForget₂ CommRingCat CommSemiRingCat := - HasForget₂.mk' (fun R : CommRingCat => CommSemiRingCat.of R) (fun R => rfl) - (fun {R₁ R₂} f => f) (by rfl) + HasForget₂.mk' (fun R : CommRingCat => CommSemiRingCat.of R) (fun _ => rfl) + (fun {_ _} f => f) (by rfl) instance : (forget₂ CommRingCat CommSemiRingCat).Full where map_surjective f := ⟨f, rfl⟩ @@ -607,6 +600,16 @@ theorem commRingIsoToRingEquiv_symm_toRingHom {X Y : CommRingCat} (i : X ≅ Y) ext rfl +@[simp] +lemma commRingIsoToRingEquiv_apply {X Y : CommRingCat} (i : X ≅ Y) (x : X) : + i.commRingCatIsoToRingEquiv x = i.hom x := + rfl + +@[simp] +lemma commRingIsoToRingEquiv_symm_apply {X Y : CommRingCat} (i : X ≅ Y) (y : Y) : + i.commRingCatIsoToRingEquiv.symm y = i.inv y := + rfl + end CategoryTheory.Iso /-- Ring equivalences between `RingCat`s are the same as (isomorphic to) isomorphisms in diff --git a/Mathlib/Algebra/Category/Ring/Colimits.lean b/Mathlib/Algebra/Category/Ring/Colimits.lean index b2c1204a2af62..8e8ac95f71651 100644 --- a/Mathlib/Algebra/Category/Ring/Colimits.lean +++ b/Mathlib/Algebra/Category/Ring/Colimits.lean @@ -135,14 +135,14 @@ instance ColimitType.AddGroupWithOne : AddGroupWithOne (ColimitType F) := instance : Ring (ColimitType.{v} F) := { ColimitType.AddGroupWithOne F with mul := Quot.map₂ Prequotient.mul Relation.mul_2 Relation.mul_1 - one_mul := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.one_mul _ - mul_one := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.mul_one _ - add_comm := fun x y => Quot.induction_on₂ x y fun x y => Quot.sound <| Relation.add_comm _ _ + one_mul := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.one_mul _ + mul_one := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.mul_one _ + add_comm := fun x y => Quot.induction_on₂ x y fun _ _ => Quot.sound <| Relation.add_comm _ _ mul_assoc := fun x y z => Quot.induction_on₃ x y z fun x y z => by simp only [(· * ·)] exact Quot.sound (Relation.mul_assoc _ _ _) - mul_zero := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.mul_zero _ - zero_mul := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.zero_mul _ + mul_zero := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.mul_zero _ + zero_mul := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.zero_mul _ left_distrib := fun x y z => Quot.induction_on₃ x y z fun x y z => by simp only [(· + ·), (· * ·), Add.add] exact Quot.sound (Relation.left_distrib _ _ _) @@ -442,15 +442,15 @@ instance ColimitType.AddGroupWithOne : AddGroupWithOne (ColimitType F) := instance : CommRing (ColimitType.{v} F) := { ColimitType.AddGroupWithOne F with mul := Quot.map₂ Prequotient.mul Relation.mul_2 Relation.mul_1 - one_mul := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.one_mul _ - mul_one := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.mul_one _ - add_comm := fun x y => Quot.induction_on₂ x y fun x y => Quot.sound <| Relation.add_comm _ _ - mul_comm := fun x y => Quot.induction_on₂ x y fun x y => Quot.sound <| Relation.mul_comm _ _ + one_mul := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.one_mul _ + mul_one := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.mul_one _ + add_comm := fun x y => Quot.induction_on₂ x y fun _ _ => Quot.sound <| Relation.add_comm _ _ + mul_comm := fun x y => Quot.induction_on₂ x y fun _ _ => Quot.sound <| Relation.mul_comm _ _ mul_assoc := fun x y z => Quot.induction_on₃ x y z fun x y z => by simp only [(· * ·)] exact Quot.sound (Relation.mul_assoc _ _ _) - mul_zero := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.mul_zero _ - zero_mul := fun x => Quot.inductionOn x fun x => Quot.sound <| Relation.zero_mul _ + mul_zero := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.mul_zero _ + zero_mul := fun x => Quot.inductionOn x fun _ => Quot.sound <| Relation.zero_mul _ left_distrib := fun x y z => Quot.induction_on₃ x y z fun x y z => by simp only [(· + ·), (· * ·), Add.add] exact Quot.sound (Relation.left_distrib _ _ _) diff --git a/Mathlib/Algebra/Category/Ring/Constructions.lean b/Mathlib/Algebra/Category/Ring/Constructions.lean index 0736d93d4951f..d9bb67a3267cd 100644 --- a/Mathlib/Algebra/Category/Ring/Constructions.lean +++ b/Mathlib/Algebra/Category/Ring/Constructions.lean @@ -183,7 +183,7 @@ The categorical product of rings is the cartesian product of rings. def piFanIsLimit : IsLimit (piFan R) where lift s := Pi.ringHom fun i ↦ s.π.1 ⟨i⟩ fac s i := by rfl - uniq s g h := DFunLike.ext _ _ fun x ↦ funext fun i ↦ DFunLike.congr_fun (h ⟨i⟩) x + uniq _ _ h := DFunLike.ext _ _ fun x ↦ funext fun i ↦ DFunLike.congr_fun (h ⟨i⟩) x /-- The categorical product and the usual product agrees @@ -224,7 +224,7 @@ def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by · intro m hm exact RingHom.ext fun x => Subtype.ext <| ConcreteCategory.congr_hom hm x -instance : IsLocalRingHom (equalizerFork f g).ι := by +instance : IsLocalHom (equalizerFork f g).ι := by constructor rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a) have : y ∈ RingHom.eqLocus f g := by @@ -234,8 +234,9 @@ instance : IsLocalRingHom (equalizerFork f g).ι := by rw [isUnit_iff_exists_inv] exact ⟨⟨y, this⟩, Subtype.eq h₃⟩ -instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) : - IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by +@[instance] +theorem equalizer_ι_isLocalHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) : + IsLocalHom (limit.π F WalkingParallelPair.zero) := by have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero rw [← IsIso.comp_inv_eq] at this rw [← this] @@ -244,15 +245,18 @@ instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u equalizerForkIsLimit (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right)⟩ WalkingParallelPair.zero] - change IsLocalRingHom ((lim.map _ ≫ _ ≫ (equalizerFork _ _).ι) ≫ _) + change IsLocalHom ((lim.map _ ≫ _ ≫ (equalizerFork _ _).ι) ≫ _) infer_instance +@[deprecated (since := "2024-10-10")] +alias equalizer_ι_isLocalRingHom := equalizer_ι_isLocalHom + open CategoryTheory.Limits.WalkingParallelPair Opposite open CategoryTheory.Limits.WalkingParallelPairHom instance equalizer_ι_is_local_ring_hom' (F : WalkingParallelPairᵒᵖ ⥤ CommRingCat.{u}) : - IsLocalRingHom (limit.π F (Opposite.op WalkingParallelPair.one)) := by + IsLocalHom (limit.π F (Opposite.op WalkingParallelPair.one)) := by have : _ = limit.π F (walkingParallelPairOpEquiv.functor.obj _) := (limit.isoLimitCone_inv_π ⟨_, IsLimit.whiskerEquivalence (limit.isLimit F) walkingParallelPairOpEquiv⟩ diff --git a/Mathlib/Algebra/Category/Ring/Instances.lean b/Mathlib/Algebra/Category/Ring/Instances.lean index c1e005f022104..def5d4f5edf11 100644 --- a/Mathlib/Algebra/Category/Ring/Instances.lean +++ b/Mathlib/Algebra/Category/Ring/Instances.lean @@ -11,6 +11,7 @@ import Mathlib.RingTheory.LocalRing.RingHom.Basic # Ring-theoretic results in terms of categorical languages -/ +universe u open CategoryTheory @@ -36,16 +37,53 @@ instance Localization.epi' {R : CommRingCat} (M : Submonoid R) : rcases R with ⟨α, str⟩ exact IsLocalization.epi M _ -instance CommRingCat.isLocalRingHom_comp {R S T : CommRingCat} (f : R ⟶ S) (g : S ⟶ T) - [IsLocalRingHom g] [IsLocalRingHom f] : IsLocalRingHom (f ≫ g) := - _root_.isLocalRingHom_comp _ _ +/- +These three instances solve the issue where the `FunLike` instances provided by +`CommRingCat.instFunLike'`, `CommRingCat.instFunLike''`, and `CommRingCat.instFunLike'''` +are not syntactically equal to `CommRingCat.instFunLike` when applied to +objects of the form `CommRingCat.of R`. +To prevent infinite loops, the priority of these three instances must be set lower +than that of other instances. +-/ +instance (priority := 50) {R : Type*} [CommRing R] {S : CommRingCat} (f : CommRingCat.of R ⟶ S) + [IsLocalHom (R := CommRingCat.of R) f] : IsLocalHom f := + inferInstance + +instance (priority := 50) {R : CommRingCat} {S : Type*} [CommRing S] (f : R ⟶ CommRingCat.of S) + [IsLocalHom (S := CommRingCat.of S) f] : IsLocalHom f := + inferInstance + +instance (priority := 50) {R S : Type u} [CommRing R] [CommRing S] + (f : CommRingCat.of R ⟶ CommRingCat.of S) + [IsLocalHom (R := CommRingCat.of R) (S := CommRingCat.of S) f] : IsLocalHom f := + inferInstance + +-- This instance handles the coercion of a morphism into a real `RingHom`. +instance {R S : CommRingCat} (f : R ⟶ S) [IsLocalHom f] : + IsLocalHom (F := R →+* S) f := + inferInstance -theorem isLocalRingHom_of_iso {R S : CommRingCat} (f : R ≅ S) : IsLocalRingHom f.hom := +@[instance] +theorem CommRingCat.isLocalHom_comp {R S T : CommRingCat} (f : R ⟶ S) (g : S ⟶ T) + [IsLocalHom g] [IsLocalHom f] : IsLocalHom (f ≫ g) := + RingHom.isLocalHom_comp _ _ + +@[deprecated (since := "2024-10-10")] +alias CommRingCat.isLocalRingHom_comp := CommRingCat.isLocalHom_comp + +theorem isLocalHom_of_iso {R S : CommRingCat} (f : R ≅ S) : IsLocalHom f.hom := { map_nonunit := fun a ha => by convert f.inv.isUnit_map ha exact (RingHom.congr_fun f.hom_inv_id _).symm } +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_of_iso := isLocalHom_of_iso + -- see Note [lower instance priority] -instance (priority := 100) isLocalRingHom_of_isIso {R S : CommRingCat} (f : R ⟶ S) [IsIso f] : - IsLocalRingHom f := - isLocalRingHom_of_iso (asIso f) +@[instance 100] +theorem isLocalHom_of_isIso {R S : CommRingCat} (f : R ⟶ S) [IsIso f] : + IsLocalHom f := + isLocalHom_of_iso (asIso f) + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_of_isIso := isLocalHom_of_isIso diff --git a/Mathlib/Algebra/Category/Ring/Limits.lean b/Mathlib/Algebra/Category/Ring/Limits.lean index a0c514581878e..bc7c9f6b9f853 100644 --- a/Mathlib/Algebra/Category/Ring/Limits.lean +++ b/Mathlib/Algebra/Category/Ring/Limits.lean @@ -340,7 +340,7 @@ instance : CreatesLimit F (forget₂ RingCat.{u} SemiRingCat.{u}) := validLift := by apply IsLimit.uniqueUpToIso (SemiRingCat.HasLimits.limitConeIsLimit _) t makesLimit := IsLimit.ofFaithful (forget₂ RingCat SemiRingCat.{u}) - (by apply SemiRingCat.HasLimits.limitConeIsLimit _) (fun s => _) fun s => rfl } + (by apply SemiRingCat.HasLimits.limitConeIsLimit _) (fun _ => _) fun _ => rfl } /-- A choice of limit cone for a functor into `RingCat`. (Generally, you'll just want to use `limit F`.) diff --git a/Mathlib/Algebra/Category/Semigrp/Basic.lean b/Mathlib/Algebra/Category/Semigrp/Basic.lean index a9305e7dd672d..d30f2b19f232e 100644 --- a/Mathlib/Algebra/Category/Semigrp/Basic.lean +++ b/Mathlib/Algebra/Category/Semigrp/Basic.lean @@ -44,7 +44,6 @@ namespace MagmaCat @[to_additive] instance bundledHom : BundledHom @MulHom := ⟨@MulHom.toFun, @MulHom.id, @MulHom.comp, - -- Porting note: was `@MulHom.coe_inj` which is deprecated by intros; apply @DFunLike.coe_injective, by aesop_cat, by aesop_cat⟩ -- Porting note: deriving failed for `ConcreteCategory`, diff --git a/Mathlib/Algebra/Central/Basic.lean b/Mathlib/Algebra/Central/Basic.lean new file mode 100644 index 0000000000000..b2aedab38df07 --- /dev/null +++ b/Mathlib/Algebra/Central/Basic.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2024 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang +-/ + +import Mathlib.Algebra.Central.Defs + +/-! +# Central Algebras + +In this file, we prove some basic results about central algebras over a commutative ring. + +## Main results + +- `Algebra.IsCentral.center_eq_bot`: the center of a central algebra over `K` is equal to `K`. +- `Algebra.IsCentral.self`: a commutative ring is a central algebra over itself. +- `Algebra.IsCentral.baseField_essentially_unique`: Let `D/K/k` is a tower of scalars where + `K` and `k` are fields. If `D` is a nontrivial central algebra over `k`, `K` is isomorphic to `k`. +-/ + +universe u v + +namespace Algebra.IsCentral + +variable (K : Type u) [CommSemiring K] (D : Type v) [Semiring D] [Algebra K D] [IsCentral K D] + +@[simp] +lemma center_eq_bot : Subalgebra.center K D = ⊥ := eq_bot_iff.2 IsCentral.out + +variable {D} in +lemma mem_center_iff {x : D} : x ∈ Subalgebra.center K D ↔ ∃ (a : K), x = algebraMap K D a := by + rw [center_eq_bot, Algebra.mem_bot] + simp [eq_comm] + +instance self : IsCentral K K where + out x := by simp [Algebra.mem_bot] + +lemma baseField_essentially_unique + (k K D : Type*) [Field k] [Field K] [Ring D] [Nontrivial D] + [Algebra k K] [Algebra K D] [Algebra k D] [IsScalarTower k K D] + [IsCentral k D] : + Function.Bijective (algebraMap k K) := by + haveI : IsCentral K D := + { out := fun x ↦ show x ∈ Subalgebra.center k D → _ by + simp only [center_eq_bot, mem_bot, Set.mem_range, forall_exists_index] + rintro x rfl + exact ⟨algebraMap k K x, by simp [algebraMap_eq_smul_one, smul_assoc]⟩ } + refine ⟨NoZeroSMulDivisors.algebraMap_injective k K, fun x => ?_⟩ + have H : algebraMap K D x ∈ (Subalgebra.center K D : Set D) := Subalgebra.algebraMap_mem _ _ + rw [show (Subalgebra.center K D : Set D) = Subalgebra.center k D by rfl] at H + simp only [center_eq_bot, coe_bot, Set.mem_range] at H + obtain ⟨x', H⟩ := H + exact ⟨x', (algebraMap K D).injective <| by simp [← H, algebraMap_eq_smul_one]⟩ + +end Algebra.IsCentral diff --git a/Mathlib/Algebra/Central/Defs.lean b/Mathlib/Algebra/Central/Defs.lean new file mode 100644 index 0000000000000..c88a10b8b3aba --- /dev/null +++ b/Mathlib/Algebra/Central/Defs.lean @@ -0,0 +1,66 @@ +/- +Copyright (c) 2024 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang +-/ + +import Mathlib.Algebra.Algebra.Subalgebra.Basic + +/-! +# Central Algebras + +In this file we define the predicate `Algebra.IsCentral K D` where `K` is a commutative ring and `D` +is a (not necessarily commutative) `K`-algebra. + +## Main definitions + +- `Algebra.IsCentral K D` : `D` is a central algebra over `K` iff the center of `D` is exactly `K`. + +## Implementation notes + +We require the `K`-center of `D` to be smaller than or equal to the smallest subalgebra so that when +we prove something is central, there we don't need to prove `⊥ ≤ center K D` even though this +direction is trivial. + +### Central Simple Algebras + +To define central simple algebras, we could do the following: +```lean +class Algebra.IsCentralSimple (K : Type u) [Field K] (D : Type v) [Ring D] [Algebra K D] where + [is_central : IsCentral K D] + [is_simple : IsSimpleRing D] +``` +but an instance of `[Algebra.IsCentralSimple K D]` would not imply `[IsSimpleRing D]` because of +synthesization orders (`K` cannot be inferred). Thus, to obtain a central simple `K`-algebra `D`, +one should use `Algebra.IsCentral K D` and `IsSimpleRing D` separately. + +Note that the predicate `Albgera.IsCentral K D` and `IsSimpleRing D` makes sense just for `K` a +`CommRing` but it doesn't give the right definition for central simple algebra; for a commutative +ring base, one should use the theory of Azumaya algebras. In fact ideals of `K` immediately give +rise to nontrivial quotients of `D` so there are no central simple algebras in this case according +to our definition, if K is not a field. +The theory of central simple algebras really is a theory over fields. + +Thus to declare a central simple algebra, one should use the following: +```lean +variable (k D : Type*) [Field k] [Ring D] [Algebra k D] +variable [Algebra.IsCentral k D] [IsSimpleRing D] +variable [FiniteDimensional k D] +``` +where `FiniteDimensional k D` is almost always assumed in most references, but some results does not +need this assumption. + +## Tags +central algebra, center, simple ring, central simple algebra + +-/ + +universe u v + +/-- +For a commutative ring `K` and a `K`-algebra `D`, we say that `D` is a central algebra over `K` if +the center of `D` is the image of `K` in `D`. +-/ +class Algebra.IsCentral + (K : Type u) [CommSemiring K] (D : Type v) [Semiring D] [Algebra K D] : Prop where + out : Subalgebra.center K D ≤ ⊥ diff --git a/Mathlib/Algebra/CharP/Algebra.lean b/Mathlib/Algebra/CharP/Algebra.lean index 05641583b0b03..4b23ad5f49507 100644 --- a/Mathlib/Algebra/CharP/Algebra.lean +++ b/Mathlib/Algebra/CharP/Algebra.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Jon Eugster. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jon Eugster, Eric Wieser -/ -import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.CharP.Basic import Mathlib.Algebra.FreeAlgebra import Mathlib.RingTheory.Localization.FractionRing @@ -67,6 +67,35 @@ theorem RingHom.charP_iff {R A : Type*} [NonAssocSemiring R] [NonAssocSemiring A (H : Function.Injective f) (p : ℕ) : CharP R p ↔ CharP A p := ⟨fun _ ↦ charP_of_injective_ringHom H p, fun _ ↦ f.charP H p⟩ +/-- If a ring homomorphism `R →+* A` is injective then `A` has the same exponential characteristic +as `R`. -/ +lemma expChar_of_injective_ringHom {R A : Type*} + [Semiring R] [Semiring A] {f : R →+* A} (h : Function.Injective f) + (q : ℕ) [hR : ExpChar R q] : ExpChar A q := by + rcases hR with _ | hprime + · haveI := charZero_of_injective_ringHom h; exact .zero + haveI := charP_of_injective_ringHom h q; exact .prime hprime + +/-- If `R →+* A` is injective, and `A` is of exponential characteristic `p`, then `R` is also of +exponential characteristic `p`. Similar to `RingHom.charZero`. -/ +lemma RingHom.expChar {R A : Type*} [Semiring R] [Semiring A] (f : R →+* A) + (H : Function.Injective f) (p : ℕ) [ExpChar A p] : ExpChar R p := by + cases ‹ExpChar A p› with + | zero => haveI := f.charZero; exact .zero + | prime hp => haveI := f.charP H p; exact .prime hp + +/-- If `R →+* A` is injective, then `R` is of exponential characteristic `p` if and only if `A` is +also of exponential characteristic `p`. Similar to `RingHom.charZero_iff`. -/ +lemma RingHom.expChar_iff {R A : Type*} [Semiring R] [Semiring A] (f : R →+* A) + (H : Function.Injective f) (p : ℕ) : ExpChar R p ↔ ExpChar A p := + ⟨fun _ ↦ expChar_of_injective_ringHom H p, fun _ ↦ f.expChar H p⟩ + +/-- If the algebra map `R →+* A` is injective then `A` has the same exponential characteristic +as `R`. -/ +lemma expChar_of_injective_algebraMap {R A : Type*} [CommSemiring R] [Semiring A] [Algebra R A] + (h : Function.Injective (algebraMap R A)) (q : ℕ) [ExpChar R q] : ExpChar A q := + expChar_of_injective_ringHom h q + /-! As an application, a `ℚ`-algebra has characteristic zero. -/ diff --git a/Mathlib/Algebra/CharP/Basic.lean b/Mathlib/Algebra/CharP/Basic.lean index af8e256be0815..bb0db6f85c58a 100644 --- a/Mathlib/Algebra/CharP/Basic.lean +++ b/Mathlib/Algebra/CharP/Basic.lean @@ -4,168 +4,184 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Joey van Langen, Casper Putz -/ import Mathlib.Algebra.CharP.Defs -import Mathlib.Data.Nat.Multiplicity -import Mathlib.Data.Nat.Choose.Sum +import Mathlib.Algebra.Field.Basic +import Mathlib.Algebra.Group.Fin.Basic +import Mathlib.Algebra.Group.ULift +import Mathlib.Data.Int.ModEq +import Mathlib.Data.Nat.Cast.Prod +import Mathlib.Data.Nat.Find +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.ULift +import Mathlib.Tactic.NormNum.Basic +import Mathlib.Order.Interval.Set.Basic /-! # Characteristic of semirings + +This file collects some fundamental results on the characteristic of rings that don't need the extra +imports of `CharP/Lemmas.lean`. + +As such, we can probably reorganize and find a better home for most of these lemmas. -/ -assert_not_exists orderOf +assert_not_exists Finset + +open Set + +variable (R : Type*) -universe u v +namespace CharP +section AddMonoidWithOne +variable [AddMonoidWithOne R] (p : ℕ) + +variable [CharP R p] {a b : ℕ} -open Finset +variable [IsRightCancelAdd R] -variable {R : Type*} +lemma natCast_injOn_Iio : (Set.Iio p).InjOn ((↑) : ℕ → R) := + fun _a ha _b hb hab ↦ ((natCast_eq_natCast _ _).1 hab).eq_of_lt_of_lt ha hb -namespace Commute +end AddMonoidWithOne -variable [Semiring R] {p : ℕ} {x y : R} +section AddGroupWithOne +variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ} -protected theorem add_pow_prime_pow_eq (hp : p.Prime) (h : Commute x y) (n : ℕ) : - (x + y) ^ p ^ n = - x ^ p ^ n + y ^ p ^ n + - p * ∑ k ∈ Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * ↑((p ^ n).choose k / p) := by - trans x ^ p ^ n + y ^ p ^ n + ∑ k ∈ Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * (p ^ n).choose k - · simp_rw [h.add_pow, ← Nat.Ico_zero_eq_range, Nat.Ico_succ_right, Icc_eq_cons_Ico (zero_le _), - Finset.sum_cons, Ico_eq_cons_Ioo (pow_pos hp.pos _), Finset.sum_cons, tsub_self, tsub_zero, - pow_zero, Nat.choose_zero_right, Nat.choose_self, Nat.cast_one, mul_one, one_mul, ← add_assoc] - · congr 1 - simp_rw [Finset.mul_sum, Nat.cast_comm, mul_assoc _ _ (p : R), ← Nat.cast_mul] - refine Finset.sum_congr rfl fun i hi => ?_ - rw [mem_Ioo] at hi - rw [Nat.div_mul_cancel (hp.dvd_choose_pow hi.1.ne' hi.2.ne)] +lemma intCast_injOn_Ico [IsRightCancelAdd R] : InjOn (Int.cast : ℤ → R) (Ico 0 p) := by + rintro a ⟨ha₀, ha⟩ b ⟨hb₀, hb⟩ hab + lift a to ℕ using ha₀ + lift b to ℕ using hb₀ + norm_cast at * + exact natCast_injOn_Iio _ _ ha hb hab + +end AddGroupWithOne +end CharP -protected theorem add_pow_prime_eq (hp : p.Prime) (h : Commute x y) : - (x + y) ^ p = - x ^ p + y ^ p + p * ∑ k ∈ Finset.Ioo 0 p, x ^ k * y ^ (p - k) * ↑(p.choose k / p) := by - simpa using h.add_pow_prime_pow_eq hp 1 - -protected theorem exists_add_pow_prime_pow_eq (hp : p.Prime) (h : Commute x y) (n : ℕ) : - ∃ r, (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n + p * r := - ⟨_, h.add_pow_prime_pow_eq hp n⟩ - -protected theorem exists_add_pow_prime_eq (hp : p.Prime) (h : Commute x y) : - ∃ r, (x + y) ^ p = x ^ p + y ^ p + p * r := - ⟨_, h.add_pow_prime_eq hp⟩ - -end Commute - -section CommSemiring - -variable [CommSemiring R] {p : ℕ} {x y : R} - -theorem add_pow_prime_pow_eq (hp : p.Prime) (x y : R) (n : ℕ) : - (x + y) ^ p ^ n = - x ^ p ^ n + y ^ p ^ n + - p * ∑ k ∈ Finset.Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * ↑((p ^ n).choose k / p) := - (Commute.all x y).add_pow_prime_pow_eq hp n - -theorem add_pow_prime_eq (hp : p.Prime) (x y : R) : - (x + y) ^ p = - x ^ p + y ^ p + p * ∑ k ∈ Finset.Ioo 0 p, x ^ k * y ^ (p - k) * ↑(p.choose k / p) := - (Commute.all x y).add_pow_prime_eq hp - -theorem exists_add_pow_prime_pow_eq (hp : p.Prime) (x y : R) (n : ℕ) : - ∃ r, (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n + p * r := - (Commute.all x y).exists_add_pow_prime_pow_eq hp n - -theorem exists_add_pow_prime_eq (hp : p.Prime) (x y : R) : - ∃ r, (x + y) ^ p = x ^ p + y ^ p + p * r := - (Commute.all x y).exists_add_pow_prime_eq hp - -end CommSemiring - -variable (R) - -theorem add_pow_char_of_commute [Semiring R] {p : ℕ} [hp : Fact p.Prime] [CharP R p] (x y : R) - (h : Commute x y) : (x + y) ^ p = x ^ p + y ^ p := by - let ⟨r, hr⟩ := h.exists_add_pow_prime_eq hp.out - simp [hr] - -theorem add_pow_char_pow_of_commute [Semiring R] {p n : ℕ} [hp : Fact p.Prime] [CharP R p] - (x y : R) (h : Commute x y) : (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := by - let ⟨r, hr⟩ := h.exists_add_pow_prime_pow_eq hp.out n - simp [hr] - -theorem sub_pow_char_of_commute [Ring R] {p : ℕ} [Fact p.Prime] [CharP R p] (x y : R) - (h : Commute x y) : (x - y) ^ p = x ^ p - y ^ p := by - rw [eq_sub_iff_add_eq, ← add_pow_char_of_commute _ _ _ (Commute.sub_left h rfl)] - simp - -theorem sub_pow_char_pow_of_commute [Ring R] {p : ℕ} [Fact p.Prime] [CharP R p] {n : ℕ} (x y : R) - (h : Commute x y) : (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := by - induction n with - | zero => simp - | succ n n_ih => - rw [pow_succ, pow_mul, pow_mul, pow_mul, n_ih] - apply sub_pow_char_of_commute; apply Commute.pow_pow h - -theorem add_pow_char [CommSemiring R] {p : ℕ} [Fact p.Prime] [CharP R p] (x y : R) : - (x + y) ^ p = x ^ p + y ^ p := - add_pow_char_of_commute _ _ _ (Commute.all _ _) - -theorem add_pow_char_pow [CommSemiring R] {p : ℕ} [Fact p.Prime] [CharP R p] {n : ℕ} (x y : R) : - (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := - add_pow_char_pow_of_commute _ _ _ (Commute.all _ _) - -theorem add_pow_eq_add_pow_mod_mul_pow_add_pow_div - [CommSemiring R] {p : ℕ} [Fact p.Prime] [CharP R p] {n : ℕ} (x y : R) : - (x + y) ^ n = (x + y) ^ (n % p) * (x ^ p + y ^ p) ^ (n / p) := by - rw [← add_pow_char, ← pow_mul, ← pow_add, Nat.mod_add_div] - -theorem sub_pow_char [CommRing R] {p : ℕ} [Fact p.Prime] [CharP R p] (x y : R) : - (x - y) ^ p = x ^ p - y ^ p := - sub_pow_char_of_commute _ _ _ (Commute.all _ _) - -theorem sub_pow_char_pow [CommRing R] {p : ℕ} [Fact p.Prime] [CharP R p] {n : ℕ} (x y : R) : - (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := - sub_pow_char_pow_of_commute _ _ _ (Commute.all _ _) - -theorem sub_pow_eq_sub_pow_mod_mul_pow_sub_pow_div - [CommRing R] {p : ℕ} [Fact p.Prime] [CharP R p] {n : ℕ} (x y : R) : - (x - y) ^ n = (x - y) ^ (n % p) * (x ^ p - y ^ p) ^ (n / p) := by - rw [← sub_pow_char, ← pow_mul, ← pow_add, Nat.mod_add_div] - -theorem CharP.neg_one_pow_char [Ring R] (p : ℕ) [CharP R p] [Fact p.Prime] : - (-1 : R) ^ p = -1 := by - rw [eq_neg_iff_add_eq_zero] - nth_rw 2 [← one_pow p] - rw [← add_pow_char_of_commute R _ _ (Commute.one_right _), neg_add_cancel, - zero_pow (Fact.out (p := Nat.Prime p)).ne_zero] - -theorem CharP.neg_one_pow_char_pow [Ring R] (p n : ℕ) [CharP R p] [Fact p.Prime] : - (-1 : R) ^ p ^ n = -1 := by - rw [eq_neg_iff_add_eq_zero] - nth_rw 2 [← one_pow (p ^ n)] - rw [← add_pow_char_pow_of_commute R _ _ (Commute.one_right _), neg_add_cancel, - zero_pow (pow_ne_zero _ (Fact.out (p := Nat.Prime p)).ne_zero)] +lemma RingHom.charP_iff_charP {K L : Type*} [DivisionRing K] [Semiring L] [Nontrivial L] + (f : K →+* L) (p : ℕ) : CharP K p ↔ CharP L p := by + simp only [charP_iff, ← f.injective.eq_iff, map_natCast f, map_zero f] namespace CharP +section NonAssocSemiring + +variable {R} [NonAssocSemiring R] + +variable (R) in +/-- If a ring `R` is of characteristic `p`, then for any prime number `q` different from `p`, +it is not zero in `R`. -/ +lemma cast_ne_zero_of_ne_of_prime [Nontrivial R] + {p q : ℕ} [CharP R p] (hq : q.Prime) (hneq : p ≠ q) : (q : R) ≠ 0 := fun h ↦ by + rw [cast_eq_zero_iff R p q] at h + rcases hq.eq_one_or_self_of_dvd _ h with h | h + · subst h + exact false_of_nontrivial_of_char_one (R := R) + · exact hneq h + +lemma ringChar_of_prime_eq_zero [Nontrivial R] {p : ℕ} (hprime : Nat.Prime p) + (hp0 : (p : R) = 0) : ringChar R = p := + Or.resolve_left ((Nat.dvd_prime hprime).1 (ringChar.dvd hp0)) ringChar_ne_one + +lemma charP_iff_prime_eq_zero [Nontrivial R] {p : ℕ} (hp : p.Prime) : + CharP R p ↔ (p : R) = 0 := + ⟨fun _ => cast_eq_zero R p, + fun hp0 => (ringChar_of_prime_eq_zero hp hp0) ▸ inferInstance⟩ + +end NonAssocSemiring +end CharP + section -variable [NonAssocRing R] +/-- We have `2 ≠ 0` in a nontrivial ring whose characteristic is not `2`. -/ +protected lemma Ring.two_ne_zero {R : Type*} [NonAssocSemiring R] [Nontrivial R] + (hR : ringChar R ≠ 2) : (2 : R) ≠ 0 := by + rw [Ne, (by norm_cast : (2 : R) = (2 : ℕ)), ringChar.spec, Nat.dvd_prime Nat.prime_two] + exact mt (or_iff_left hR).mp CharP.ringChar_ne_one + +-- We have `CharP.neg_one_ne_one`, which assumes `[Ring R] (p : ℕ) [CharP R p] [Fact (2 < p)]`. +-- This is a version using `ringChar` instead. +/-- Characteristic `≠ 2` and nontrivial implies that `-1 ≠ 1`. -/ +lemma Ring.neg_one_ne_one_of_char_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] + (hR : ringChar R ≠ 2) : (-1 : R) ≠ 1 := fun h => + Ring.two_ne_zero hR (one_add_one_eq_two (R := R) ▸ neg_eq_iff_add_eq_zero.mp h) + +/-- Characteristic `≠ 2` in a domain implies that `-a = a` iff `a = 0`. -/ +lemma Ring.eq_self_iff_eq_zero_of_char_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] + [NoZeroDivisors R] (hR : ringChar R ≠ 2) {a : R} : -a = a ↔ a = 0 := + ⟨fun h => + (mul_eq_zero.mp <| (two_mul a).trans <| neg_eq_iff_add_eq_zero.mp h).resolve_left + (Ring.two_ne_zero hR), + fun h => ((congr_arg (fun x => -x) h).trans neg_zero).trans h.symm⟩ + +end + +section Prod +variable (S : Type*) [AddMonoidWithOne R] [AddMonoidWithOne S] (p q : ℕ) [CharP R p] + +/-- The characteristic of the product of rings is the least common multiple of the +characteristics of the two rings. -/ +instance Nat.lcm.charP [CharP S q] : CharP (R × S) (Nat.lcm p q) where + cast_eq_zero_iff' := by + simp [Prod.ext_iff, CharP.cast_eq_zero_iff R p, CharP.cast_eq_zero_iff S q, Nat.lcm_dvd_iff] + +/-- The characteristic of the product of two rings of the same characteristic + is the same as the characteristic of the rings -/ +instance Prod.charP [CharP S p] : CharP (R × S) p := by + convert Nat.lcm.charP R S p p; simp + +instance Prod.charZero_of_left [CharZero R] : CharZero (R × S) where + cast_injective _ _ h := CharZero.cast_injective congr(Prod.fst $h) + +instance Prod.charZero_of_right [CharZero S] : CharZero (R × S) where + cast_injective _ _ h := CharZero.cast_injective congr(Prod.snd $h) + +end Prod + +instance ULift.charP [AddMonoidWithOne R] (p : ℕ) [CharP R p] : CharP (ULift R) p where + cast_eq_zero_iff' n := Iff.trans ULift.ext_iff <| CharP.cast_eq_zero_iff R p n -/-- The characteristic of a finite ring cannot be zero. -/ -theorem char_ne_zero_of_finite (p : ℕ) [CharP R p] [Finite R] : p ≠ 0 := by - rintro rfl - haveI : CharZero R := charP_to_charZero R - cases nonempty_fintype R - exact absurd Nat.cast_injective (not_injective_infinite_finite ((↑) : ℕ → R)) +instance MulOpposite.charP [AddMonoidWithOne R] (p : ℕ) [CharP R p] : CharP Rᵐᵒᵖ p where + cast_eq_zero_iff' n := MulOpposite.unop_inj.symm.trans <| CharP.cast_eq_zero_iff R p n -theorem ringChar_ne_zero_of_finite [Finite R] : ringChar R ≠ 0 := - char_ne_zero_of_finite R (ringChar R) +section + +/-- If two integers from `{0, 1, -1}` result in equal elements in a ring `R` +that is nontrivial and of characteristic not `2`, then they are equal. -/ +lemma Int.cast_injOn_of_ringChar_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] + (hR : ringChar R ≠ 2) : ({0, 1, -1} : Set ℤ).InjOn ((↑) : ℤ → R) := by + rintro _ (rfl | rfl | rfl) _ (rfl | rfl | rfl) h <;> + simp only + [cast_neg, cast_one, cast_zero, neg_eq_zero, one_ne_zero, zero_ne_one, zero_eq_neg] at h ⊢ + · exact ((Ring.neg_one_ne_one_of_char_ne_two hR).symm h).elim + · exact ((Ring.neg_one_ne_one_of_char_ne_two hR) h).elim end -section Ring +namespace CharZero -variable [Ring R] [NoZeroDivisors R] [Nontrivial R] [Finite R] +lemma charZero_iff_forall_prime_ne_zero [NonAssocRing R] [NoZeroDivisors R] [Nontrivial R] : + CharZero R ↔ ∀ p : ℕ, p.Prime → (p : R) ≠ 0 := by + refine ⟨fun h p hp => by simp [hp.ne_zero], fun h => ?_⟩ + let p := ringChar R + cases CharP.char_is_prime_or_zero R p with + | inl hp => simpa using h p hp + | inr h => have : CharP R 0 := h ▸ inferInstance; exact CharP.charP_to_charZero R -theorem char_is_prime (p : ℕ) [CharP R p] : p.Prime := - Or.resolve_right (char_is_prime_or_zero R p) (char_ne_zero_of_finite R p) +end CharZero -end Ring -end CharP +namespace Fin + +instance charP (n : ℕ) [NeZero n] : CharP (Fin n) n where cast_eq_zero_iff' _ := natCast_eq_zero + +end Fin + +section AddMonoidWithOne +variable [AddMonoidWithOne R] + +instance (S : Type*) [Semiring S] (p) [ExpChar R p] [ExpChar S p] : ExpChar (R × S) p := by + obtain hp | ⟨hp⟩ := ‹ExpChar R p› + · have := Prod.charZero_of_left R S; exact .zero + obtain _ | _ := ‹ExpChar S p› + · exact (Nat.not_prime_one hp).elim + · have := Prod.charP R S p; exact .prime hp + +end AddMonoidWithOne diff --git a/Mathlib/Algebra/CharP/CharAndCard.lean b/Mathlib/Algebra/CharP/CharAndCard.lean index 75671724d2c94..f78ed1df476fc 100644 --- a/Mathlib/Algebra/CharP/CharAndCard.lean +++ b/Mathlib/Algebra/CharP/CharAndCard.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Stoll -/ import Mathlib.Algebra.CharP.Basic +import Mathlib.Algebra.CharP.Lemmas import Mathlib.GroupTheory.Perm.Cycle.Type import Mathlib.RingTheory.Coprime.Lemmas diff --git a/Mathlib/Algebra/CharP/Defs.lean b/Mathlib/Algebra/CharP/Defs.lean index 34b448a97de44..9c41f5a2b3741 100644 --- a/Mathlib/Algebra/CharP/Defs.lean +++ b/Mathlib/Algebra/CharP/Defs.lean @@ -3,18 +3,21 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Joey van Langen, Casper Putz -/ -import Mathlib.Algebra.Field.Basic -import Mathlib.Algebra.Group.Fin.Basic -import Mathlib.Algebra.Group.ULift import Mathlib.Data.Int.ModEq -import Mathlib.Data.Nat.Cast.Prod +import Mathlib.Data.Nat.Cast.Defs import Mathlib.Data.Nat.Find import Mathlib.Data.Nat.Prime.Defs -import Mathlib.Data.ULift import Mathlib.Tactic.NormNum.Basic /-! # Characteristic of semirings + +## Main definitions + * `CharP R p` expresses that the ring (additive monoid with one) `R` has characteristic `p` + * `ringChar`: the characteristic of a ring + * `ExpChar R p` expresses that the ring (additive monoid with one) `R` has + exponential characteristic `p` (which is `1` if `R` has characteristic 0, and `p` if it has + prime characteristic `p`) -/ assert_not_exists Finset @@ -86,21 +89,11 @@ lemma natCast_eq_natCast : (a : R) = b ↔ a ≡ b [MOD p] := by ← add_right_cancel_iff (G := R) (a := a) (b := b - a), zero_add, ← Nat.cast_add, Nat.sub_add_cancel hle, eq_comm] -lemma natCast_injOn_Iio : (Set.Iio p).InjOn ((↑) : ℕ → R) := - fun _a ha _b hb hab ↦ ((natCast_eq_natCast _ _).1 hab).eq_of_lt_of_lt ha hb - end AddMonoidWithOne section AddGroupWithOne variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ} -lemma intCast_injOn_Ico [IsRightCancelAdd R] : InjOn (Int.cast : ℤ → R) (Ico 0 p) := by - rintro a ⟨ha₀, ha⟩ b ⟨hb₀, hb⟩ hab - lift a to ℕ using ha₀ - lift b to ℕ using hb₀ - norm_cast at * - exact natCast_injOn_Iio _ _ ha hb hab - lemma intCast_eq_zero_iff (a : ℤ) : (a : R) = 0 ↔ (p : ℤ) ∣ a := by rcases lt_trichotomy a 0 with (h | rfl | h) · rw [← neg_eq_zero, ← Int.cast_neg, ← Int.dvd_neg] @@ -191,7 +184,6 @@ lemma dvd {x : ℕ} (hx : (x : R) = 0) : ringChar R ∣ x := lemma eq_zero [CharZero R] : ringChar R = 0 := eq R 0 --- @[simp] -- Porting note (#10618): simp can prove this lemma Nat.cast_ringChar : (ringChar R : R) = 0 := by rw [ringChar.spec] end ringChar @@ -211,10 +203,6 @@ lemma CharP.neg_one_ne_one [Ring R] (p : ℕ) [CharP R p] [Fact (2 < p)] : (-1 : rw [fact_iff] at * omega -lemma RingHom.charP_iff_charP {K L : Type*} [DivisionRing K] [Semiring L] [Nontrivial L] - (f : K →+* L) (p : ℕ) : CharP K p ↔ CharP L p := by - simp only [charP_iff, ← f.injective.eq_iff, map_natCast f, map_zero f] - namespace CharP section @@ -243,7 +231,7 @@ section NoZeroDivisors variable [NoZeroDivisors R] -lemma char_is_prime_of_two_le (p : ℕ) [hc : CharP R p] (hp : 2 ≤ p) : Nat.Prime p := +lemma char_is_prime_of_two_le (p : ℕ) [CharP R p] (hp : 2 ≤ p) : Nat.Prime p := suffices ∀ (d) (_ : d ∣ p), d = 1 ∨ d = p from Nat.prime_def_lt''.mpr ⟨hp, this⟩ fun (d : ℕ) (hdvd : ∃ e, p = d * e) => let ⟨e, hmul⟩ := hdvd @@ -271,6 +259,10 @@ lemma char_is_prime_or_zero (p : ℕ) [hc : CharP R p] : Nat.Prime p ∨ p = 0 : | 1, hc => absurd (Eq.refl (1 : ℕ)) (@char_ne_one R _ _ (1 : ℕ) hc) | m + 2, hc => Or.inl (@char_is_prime_of_two_le R _ _ (m + 2) hc (Nat.le_add_left 2 m)) +/-- The characteristic is prime if it is non-zero. -/ +lemma char_prime_of_ne_zero {p : ℕ} [CharP R p] (hp : p ≠ 0) : p.Prime := + (CharP.char_is_prime_or_zero R p).resolve_right hp + lemma exists' (R : Type*) [NonAssocRing R] [NoZeroDivisors R] [Nontrivial R] : CharZero R ∨ ∃ p : ℕ, Fact p.Prime ∧ CharP R p := by obtain ⟨p, hchar⟩ := CharP.exists R @@ -316,111 +308,151 @@ lemma nontrivial_of_char_ne_one {v : ℕ} (hv : v ≠ 1) [hr : CharP R v] : Nont ⟨⟨(1 : ℕ), 0, fun h => hv <| by rwa [CharP.cast_eq_zero_iff _ v, Nat.dvd_one] at h⟩⟩ -lemma ringChar_of_prime_eq_zero [Nontrivial R] {p : ℕ} (hprime : Nat.Prime p) - (hp0 : (p : R) = 0) : ringChar R = p := - Or.resolve_left ((Nat.dvd_prime hprime).1 (ringChar.dvd hp0)) ringChar_ne_one - -lemma charP_iff_prime_eq_zero [Nontrivial R] {p : ℕ} (hp : p.Prime) : - CharP R p ↔ (p : R) = 0 := - ⟨fun _ => cast_eq_zero R p, - fun hp0 => (ringChar_of_prime_eq_zero hp hp0) ▸ inferInstance⟩ - end NonAssocSemiring end CharP -section - -/-- We have `2 ≠ 0` in a nontrivial ring whose characteristic is not `2`. -/ -protected lemma Ring.two_ne_zero {R : Type*} [NonAssocSemiring R] [Nontrivial R] - (hR : ringChar R ≠ 2) : (2 : R) ≠ 0 := by - rw [Ne, (by norm_cast : (2 : R) = (2 : ℕ)), ringChar.spec, Nat.dvd_prime Nat.prime_two] - exact mt (or_iff_left hR).mp CharP.ringChar_ne_one - --- We have `CharP.neg_one_ne_one`, which assumes `[Ring R] (p : ℕ) [CharP R p] [Fact (2 < p)]`. --- This is a version using `ringChar` instead. -/-- Characteristic `≠ 2` and nontrivial implies that `-1 ≠ 1`. -/ -lemma Ring.neg_one_ne_one_of_char_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] - (hR : ringChar R ≠ 2) : (-1 : R) ≠ 1 := fun h => - Ring.two_ne_zero hR (one_add_one_eq_two (R := R) ▸ neg_eq_iff_add_eq_zero.mp h) - -/-- Characteristic `≠ 2` in a domain implies that `-a = a` iff `a = 0`. -/ -lemma Ring.eq_self_iff_eq_zero_of_char_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] - [NoZeroDivisors R] (hR : ringChar R ≠ 2) {a : R} : -a = a ↔ a = 0 := - ⟨fun h => - (mul_eq_zero.mp <| (two_mul a).trans <| neg_eq_iff_add_eq_zero.mp h).resolve_left - (Ring.two_ne_zero hR), - fun h => ((congr_arg (fun x => -x) h).trans neg_zero).trans h.symm⟩ +namespace NeZero -end +variable [AddMonoidWithOne R] {r : R} {n p : ℕ} -section Prod -variable (S : Type*) [AddMonoidWithOne R] [AddMonoidWithOne S] (p q : ℕ) [CharP R p] +lemma of_not_dvd [CharP R p] (h : ¬p ∣ n) : NeZero (n : R) := + ⟨(CharP.cast_eq_zero_iff R p n).not.mpr h⟩ -/-- The characteristic of the product of rings is the least common multiple of the -characteristics of the two rings. -/ -instance Nat.lcm.charP [CharP S q] : CharP (R × S) (Nat.lcm p q) where - cast_eq_zero_iff' := by - simp [Prod.ext_iff, CharP.cast_eq_zero_iff R p, CharP.cast_eq_zero_iff S q, Nat.lcm_dvd_iff] +lemma not_char_dvd (p : ℕ) [CharP R p] (k : ℕ) [h : NeZero (k : R)] : ¬p ∣ k := by + rwa [← CharP.cast_eq_zero_iff R p k, ← Ne, ← neZero_iff] -/-- The characteristic of the product of two rings of the same characteristic - is the same as the characteristic of the rings -/ -instance Prod.charP [CharP S p] : CharP (R × S) p := by - convert Nat.lcm.charP R S p p; simp +end NeZero -instance Prod.charZero_of_left [CharZero R] : CharZero (R × S) where - cast_injective _ _ h := CharZero.cast_injective congr(Prod.fst $h) +/-! +### Exponential characteristic + +This section defines the exponential characteristic, which is defined to be 1 for a ring with +characteristic 0 and the same as the ordinary characteristic, if the ordinary characteristic is +prime. This concept is useful to simplify some theorem statements. +This file establishes a few basic results relating it to the (ordinary characteristic). +The definition is stated for a semiring, but the actual results are for nontrivial rings +(as far as exponential characteristic one is concerned), respectively a ring without zero-divisors +(for prime characteristic). +-/ -instance Prod.charZero_of_right [CharZero S] : CharZero (R × S) where - cast_injective _ _ h := CharZero.cast_injective congr(Prod.snd $h) +section AddMonoidWithOne +variable [AddMonoidWithOne R] -end Prod +/-- The definition of the exponential characteristic of a semiring. -/ +class inductive ExpChar : ℕ → Prop + | zero [CharZero R] : ExpChar 1 + | prime {q : ℕ} (hprime : q.Prime) [hchar : CharP R q] : ExpChar q -instance ULift.charP [AddMonoidWithOne R] (p : ℕ) [CharP R p] : CharP (ULift R) p where - cast_eq_zero_iff' n := Iff.trans ULift.ext_iff <| CharP.cast_eq_zero_iff R p n +instance expChar_prime (p) [CharP R p] [Fact p.Prime] : ExpChar R p := ExpChar.prime Fact.out +instance expChar_one [CharZero R] : ExpChar R 1 := ExpChar.zero -instance MulOpposite.charP [AddMonoidWithOne R] (p : ℕ) [CharP R p] : CharP Rᵐᵒᵖ p where - cast_eq_zero_iff' n := MulOpposite.unop_inj.symm.trans <| CharP.cast_eq_zero_iff R p n +lemma expChar_ne_zero (p : ℕ) [hR : ExpChar R p] : p ≠ 0 := by + cases hR + · exact one_ne_zero + · exact ‹p.Prime›.ne_zero -section +variable {R} in +/-- The exponential characteristic is unique. -/ +lemma ExpChar.eq {p q : ℕ} (hp : ExpChar R p) (hq : ExpChar R q) : p = q := by + rcases hp with ⟨hp⟩ | ⟨hp'⟩ + · rcases hq with hq | hq' + exacts [rfl, False.elim (Nat.not_prime_zero (CharP.eq R ‹_› (CharP.ofCharZero R) ▸ hq'))] + · rcases hq with hq | hq' + exacts [False.elim (Nat.not_prime_zero (CharP.eq R ‹_› (CharP.ofCharZero R) ▸ hp')), + CharP.eq R ‹_› ‹_›] + +lemma ExpChar.congr {p : ℕ} (q : ℕ) [hq : ExpChar R q] (h : q = p) : ExpChar R p := h ▸ hq + +/-- The exponential characteristic is one if the characteristic is zero. -/ +lemma expChar_one_of_char_zero (q : ℕ) [hp : CharP R 0] [hq : ExpChar R q] : q = 1 := by + rcases hq with q | hq_prime + · rfl + · exact False.elim <| hq_prime.ne_zero <| ‹CharP R q›.eq R hp + +/-- The characteristic equals the exponential characteristic iff the former is prime. -/ +lemma char_eq_expChar_iff (p q : ℕ) [hp : CharP R p] [hq : ExpChar R q] : p = q ↔ p.Prime := by + rcases hq with q | hq_prime + · rw [(CharP.eq R hp inferInstance : p = 0)] + decide + · exact ⟨fun hpq => hpq.symm ▸ hq_prime, fun _ => CharP.eq R hp ‹CharP R q›⟩ + +/-- The exponential characteristic is a prime number or one. +See also `CharP.char_is_prime_or_zero`. -/ +lemma expChar_is_prime_or_one (q : ℕ) [hq : ExpChar R q] : Nat.Prime q ∨ q = 1 := by + cases hq with + | zero => exact .inr rfl + | prime hp => exact .inl hp + +/-- The exponential characteristic is positive. -/ +lemma expChar_pos (q : ℕ) [ExpChar R q] : 0 < q := by + rcases expChar_is_prime_or_one R q with h | rfl + exacts [Nat.Prime.pos h, Nat.one_pos] + +/-- Any power of the exponential characteristic is positive. -/ +lemma expChar_pow_pos (q : ℕ) [ExpChar R q] (n : ℕ) : 0 < q ^ n := + Nat.pos_pow_of_pos n (expChar_pos R q) -/-- If two integers from `{0, 1, -1}` result in equal elements in a ring `R` -that is nontrivial and of characteristic not `2`, then they are equal. -/ -lemma Int.cast_injOn_of_ringChar_ne_two {R : Type*} [NonAssocRing R] [Nontrivial R] - (hR : ringChar R ≠ 2) : ({0, 1, -1} : Set ℤ).InjOn ((↑) : ℤ → R) := by - rintro _ (rfl | rfl | rfl) _ (rfl | rfl | rfl) h <;> - simp only - [cast_neg, cast_one, cast_zero, neg_eq_zero, one_ne_zero, zero_ne_one, zero_eq_neg] at h ⊢ - · exact ((Ring.neg_one_ne_one_of_char_ne_two hR).symm h).elim - · exact ((Ring.neg_one_ne_one_of_char_ne_two hR) h).elim +end AddMonoidWithOne -end +section NonAssocSemiring +variable [NonAssocSemiring R] -namespace NeZero +/-- Noncomputable function that outputs the unique exponential characteristic of a semiring. -/ +noncomputable def ringExpChar : ℕ := max (ringChar R) 1 -variable [AddMonoidWithOne R] {r : R} {n p : ℕ} +lemma ringExpChar.eq (q : ℕ) [h : ExpChar R q] : ringExpChar R = q := by + rcases h with _ | h + · haveI := CharP.ofCharZero R + rw [ringExpChar, ringChar.eq R 0]; rfl + rw [ringExpChar, ringChar.eq R q] + exact Nat.max_eq_left h.one_lt.le -lemma of_not_dvd [CharP R p] (h : ¬p ∣ n) : NeZero (n : R) := - ⟨(CharP.cast_eq_zero_iff R p n).not.mpr h⟩ +@[simp] lemma ringExpChar.eq_one [CharZero R] : ringExpChar R = 1 := by + rw [ringExpChar, ringChar.eq_zero, max_eq_right (Nat.zero_le _)] -lemma not_char_dvd (p : ℕ) [CharP R p] (k : ℕ) [h : NeZero (k : R)] : ¬p ∣ k := by - rwa [← CharP.cast_eq_zero_iff R p k, ← Ne, ← neZero_iff] +section Nontrivial +variable [Nontrivial R] -end NeZero +/-- The exponential characteristic is one if the characteristic is zero. -/ +lemma char_zero_of_expChar_one (p : ℕ) [hp : CharP R p] [hq : ExpChar R 1] : p = 0 := by + cases hq + · exact CharP.eq R hp inferInstance + · exact False.elim (CharP.char_ne_one R 1 rfl) + +-- This could be an instance, but there are no `ExpChar R 1` instances in mathlib. +/-- The characteristic is zero if the exponential characteristic is one. -/ +lemma charZero_of_expChar_one' [hq : ExpChar R 1] : CharZero R := by + cases hq + · assumption + · exact False.elim (CharP.char_ne_one R 1 rfl) + +/-- The exponential characteristic is one iff the characteristic is zero. -/ +lemma expChar_one_iff_char_zero (p q : ℕ) [CharP R p] [ExpChar R q] : q = 1 ↔ p = 0 := by + constructor + · rintro rfl + exact char_zero_of_expChar_one R p + · rintro rfl + exact expChar_one_of_char_zero R q -namespace CharZero +end Nontrivial +end NonAssocSemiring -lemma charZero_iff_forall_prime_ne_zero [NonAssocRing R] [NoZeroDivisors R] [Nontrivial R] : - CharZero R ↔ ∀ p : ℕ, p.Prime → (p : R) ≠ 0 := by - refine ⟨fun h p hp => by simp [hp.ne_zero], fun h => ?_⟩ - let p := ringChar R - cases CharP.char_is_prime_or_zero R p with - | inl hp => simpa using h p hp - | inr h => have : CharP R 0 := h ▸ inferInstance; exact CharP.charP_to_charZero R +lemma ExpChar.exists [Ring R] [IsDomain R] : ∃ q, ExpChar R q := by + obtain _ | ⟨p, ⟨hp⟩, _⟩ := CharP.exists' R + exacts [⟨1, .zero⟩, ⟨p, .prime hp⟩] -end CharZero +lemma ExpChar.exists_unique [Ring R] [IsDomain R] : ∃! q, ExpChar R q := + let ⟨q, H⟩ := ExpChar.exists R + ⟨q, H, fun _ H2 ↦ ExpChar.eq H2 H⟩ -namespace Fin +instance ringExpChar.expChar [Ring R] [IsDomain R] : ExpChar R (ringExpChar R) := by + obtain ⟨q, _⟩ := ExpChar.exists R + rwa [ringExpChar.eq R q] -instance charP (n : ℕ) [NeZero n] : CharP (Fin n) n where cast_eq_zero_iff' _ := natCast_eq_zero +variable {R} in +lemma ringExpChar.of_eq [Ring R] [IsDomain R] {q : ℕ} (h : ringExpChar R = q) : ExpChar R q := + h ▸ ringExpChar.expChar R -end Fin +variable {R} in +lemma ringExpChar.eq_iff [Ring R] [IsDomain R] {q : ℕ} : ringExpChar R = q ↔ ExpChar R q := + ⟨ringExpChar.of_eq, fun _ ↦ ringExpChar.eq R q⟩ diff --git a/Mathlib/Algebra/CharP/ExpChar.lean b/Mathlib/Algebra/CharP/ExpChar.lean index 3c3955406e021..9053124e1a464 100644 --- a/Mathlib/Algebra/CharP/ExpChar.lean +++ b/Mathlib/Algebra/CharP/ExpChar.lean @@ -3,9 +3,8 @@ Copyright (c) 2021 Jakob Scholbach. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob Scholbach -/ -import Mathlib.Algebra.CharP.Basic -import Mathlib.Algebra.CharP.Algebra -import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Algebra.Algebra.Defs +import Mathlib.Algebra.CharP.Lemmas /-! # Exponential characteristic @@ -28,235 +27,12 @@ The definition is stated for a semiring, but the actual results are for nontrivi exponential characteristic, characteristic -/ +open ExpChar universe u variable (R : Type u) -section Semiring - -variable [Semiring R] - -/-- The definition of the exponential characteristic of a semiring. -/ -class inductive ExpChar (R : Type u) [Semiring R] : ℕ → Prop - | zero [CharZero R] : ExpChar R 1 - | prime {q : ℕ} (hprime : q.Prime) [hchar : CharP R q] : ExpChar R q - -instance expChar_prime (p) [CharP R p] [Fact p.Prime] : ExpChar R p := ExpChar.prime Fact.out -instance expChar_zero [CharZero R] : ExpChar R 1 := ExpChar.zero - -instance (S : Type*) [Semiring S] (p) [ExpChar R p] [ExpChar S p] : ExpChar (R × S) p := by - obtain hp | ⟨hp⟩ := ‹ExpChar R p› - · have := Prod.charZero_of_left R S; exact .zero - obtain _ | _ := ‹ExpChar S p› - · exact (Nat.not_prime_one hp).elim - · have := Prod.charP R S p; exact .prime hp - -variable {R} in -/-- The exponential characteristic is unique. -/ -theorem ExpChar.eq {p q : ℕ} (hp : ExpChar R p) (hq : ExpChar R q) : p = q := by - rcases hp with ⟨hp⟩ | ⟨hp'⟩ - · rcases hq with hq | hq' - exacts [rfl, False.elim (Nat.not_prime_zero (CharP.eq R ‹_› (CharP.ofCharZero R) ▸ hq'))] - · rcases hq with hq | hq' - exacts [False.elim (Nat.not_prime_zero (CharP.eq R ‹_› (CharP.ofCharZero R) ▸ hp')), - CharP.eq R ‹_› ‹_›] - -theorem ExpChar.congr {p : ℕ} (q : ℕ) [hq : ExpChar R q] (h : q = p) : ExpChar R p := h ▸ hq - -/-- Noncomputable function that outputs the unique exponential characteristic of a semiring. -/ -noncomputable def ringExpChar (R : Type*) [NonAssocSemiring R] : ℕ := max (ringChar R) 1 - -theorem ringExpChar.eq (q : ℕ) [h : ExpChar R q] : ringExpChar R = q := by - rcases h with _ | h - · haveI := CharP.ofCharZero R - rw [ringExpChar, ringChar.eq R 0]; rfl - rw [ringExpChar, ringChar.eq R q] - exact Nat.max_eq_left h.one_lt.le - -@[simp] -theorem ringExpChar.eq_one (R : Type*) [NonAssocSemiring R] [CharZero R] : ringExpChar R = 1 := by - rw [ringExpChar, ringChar.eq_zero, max_eq_right zero_le_one] - -/-- The exponential characteristic is one if the characteristic is zero. -/ -theorem expChar_one_of_char_zero (q : ℕ) [hp : CharP R 0] [hq : ExpChar R q] : q = 1 := by - rcases hq with q | hq_prime - · rfl - · exact False.elim <| hq_prime.ne_zero <| ‹CharP R q›.eq R hp - -/-- The characteristic equals the exponential characteristic iff the former is prime. -/ -theorem char_eq_expChar_iff (p q : ℕ) [hp : CharP R p] [hq : ExpChar R q] : p = q ↔ p.Prime := by - rcases hq with q | hq_prime - · rw [(CharP.eq R hp inferInstance : p = 0)] - decide - · exact ⟨fun hpq => hpq.symm ▸ hq_prime, fun _ => CharP.eq R hp ‹CharP R q›⟩ - -/-- The exponential characteristic is a prime number or one. -See also `CharP.char_is_prime_or_zero`. -/ -theorem expChar_is_prime_or_one (q : ℕ) [hq : ExpChar R q] : Nat.Prime q ∨ q = 1 := by - cases hq with - | zero => exact .inr rfl - | prime hp => exact .inl hp - -/-- The exponential characteristic is positive. -/ -theorem expChar_pos (q : ℕ) [ExpChar R q] : 0 < q := by - rcases expChar_is_prime_or_one R q with h | rfl - exacts [Nat.Prime.pos h, Nat.one_pos] - -/-- Any power of the exponential characteristic is positive. -/ -theorem expChar_pow_pos (q : ℕ) [ExpChar R q] (n : ℕ) : 0 < q ^ n := - Nat.pos_pow_of_pos n (expChar_pos R q) - -section Nontrivial - -variable [Nontrivial R] - -/-- The exponential characteristic is one if the characteristic is zero. -/ -theorem char_zero_of_expChar_one (p : ℕ) [hp : CharP R p] [hq : ExpChar R 1] : p = 0 := by - cases hq - · exact CharP.eq R hp inferInstance - · exact False.elim (CharP.char_ne_one R 1 rfl) - --- This could be an instance, but there are no `ExpChar R 1` instances in mathlib. -/-- The characteristic is zero if the exponential characteristic is one. -/ -theorem charZero_of_expChar_one' [hq : ExpChar R 1] : CharZero R := by - cases hq - · assumption - · exact False.elim (CharP.char_ne_one R 1 rfl) - -/-- The exponential characteristic is one iff the characteristic is zero. -/ -theorem expChar_one_iff_char_zero (p q : ℕ) [CharP R p] [ExpChar R q] : q = 1 ↔ p = 0 := by - constructor - · rintro rfl - exact char_zero_of_expChar_one R p - · rintro rfl - exact expChar_one_of_char_zero R q - -section NoZeroDivisors - -variable [NoZeroDivisors R] - -/-- A helper lemma: the characteristic is prime if it is non-zero. -/ -theorem char_prime_of_ne_zero {p : ℕ} [hp : CharP R p] (p_ne_zero : p ≠ 0) : Nat.Prime p := by - rcases CharP.char_is_prime_or_zero R p with h | h - · exact h - · contradiction - -end NoZeroDivisors - -end Nontrivial - -end Semiring - -theorem ExpChar.exists [Ring R] [IsDomain R] : ∃ q, ExpChar R q := by - obtain _ | ⟨p, ⟨hp⟩, _⟩ := CharP.exists' R - exacts [⟨1, .zero⟩, ⟨p, .prime hp⟩] - -theorem ExpChar.exists_unique [Ring R] [IsDomain R] : ∃! q, ExpChar R q := - let ⟨q, H⟩ := ExpChar.exists R - ⟨q, H, fun _ H2 ↦ ExpChar.eq H2 H⟩ - -instance ringExpChar.expChar [Ring R] [IsDomain R] : ExpChar R (ringExpChar R) := by - obtain ⟨q, _⟩ := ExpChar.exists R - rwa [ringExpChar.eq R q] - -variable {R} in -theorem ringExpChar.of_eq [Ring R] [IsDomain R] {q : ℕ} (h : ringExpChar R = q) : ExpChar R q := - h ▸ ringExpChar.expChar R - -variable {R} in -theorem ringExpChar.eq_iff [Ring R] [IsDomain R] {q : ℕ} : ringExpChar R = q ↔ ExpChar R q := - ⟨ringExpChar.of_eq, fun _ ↦ ringExpChar.eq R q⟩ - -/-- If a ring homomorphism `R →+* A` is injective then `A` has the same exponential characteristic -as `R`. -/ -theorem expChar_of_injective_ringHom {R A : Type*} - [Semiring R] [Semiring A] {f : R →+* A} (h : Function.Injective f) - (q : ℕ) [hR : ExpChar R q] : ExpChar A q := by - rcases hR with _ | hprime - · haveI := charZero_of_injective_ringHom h; exact .zero - haveI := charP_of_injective_ringHom h q; exact .prime hprime - -/-- If `R →+* A` is injective, and `A` is of exponential characteristic `p`, then `R` is also of -exponential characteristic `p`. Similar to `RingHom.charZero`. -/ -theorem RingHom.expChar {R A : Type*} [Semiring R] [Semiring A] (f : R →+* A) - (H : Function.Injective f) (p : ℕ) [ExpChar A p] : ExpChar R p := by - cases ‹ExpChar A p› with - | zero => haveI := f.charZero; exact .zero - | prime hp => haveI := f.charP H p; exact .prime hp - -/-- If `R →+* A` is injective, then `R` is of exponential characteristic `p` if and only if `A` is -also of exponential characteristic `p`. Similar to `RingHom.charZero_iff`. -/ -theorem RingHom.expChar_iff {R A : Type*} [Semiring R] [Semiring A] (f : R →+* A) - (H : Function.Injective f) (p : ℕ) : ExpChar R p ↔ ExpChar A p := - ⟨fun _ ↦ expChar_of_injective_ringHom H p, fun _ ↦ f.expChar H p⟩ - -/-- If the algebra map `R →+* A` is injective then `A` has the same exponential characteristic -as `R`. -/ -theorem expChar_of_injective_algebraMap {R A : Type*} - [CommSemiring R] [Semiring A] [Algebra R A] (h : Function.Injective (algebraMap R A)) - (q : ℕ) [ExpChar R q] : ExpChar A q := expChar_of_injective_ringHom h q - -theorem add_pow_expChar_of_commute [Semiring R] {q : ℕ} [hR : ExpChar R q] - (x y : R) (h : Commute x y) : (x + y) ^ q = x ^ q + y ^ q := by - rcases hR with _ | hprime - · simp only [pow_one] - haveI := Fact.mk hprime; exact add_pow_char_of_commute R x y h - -theorem add_pow_expChar_pow_of_commute [Semiring R] {q : ℕ} [hR : ExpChar R q] - {n : ℕ} (x y : R) (h : Commute x y) : (x + y) ^ q ^ n = x ^ q ^ n + y ^ q ^ n := by - rcases hR with _ | hprime - · simp only [one_pow, pow_one] - haveI := Fact.mk hprime; exact add_pow_char_pow_of_commute R x y h - -theorem sub_pow_expChar_of_commute [Ring R] {q : ℕ} [hR : ExpChar R q] - (x y : R) (h : Commute x y) : (x - y) ^ q = x ^ q - y ^ q := by - rcases hR with _ | hprime - · simp only [pow_one] - haveI := Fact.mk hprime; exact sub_pow_char_of_commute R x y h - -theorem sub_pow_expChar_pow_of_commute [Ring R] {q : ℕ} [hR : ExpChar R q] - {n : ℕ} (x y : R) (h : Commute x y) : (x - y) ^ q ^ n = x ^ q ^ n - y ^ q ^ n := by - rcases hR with _ | hprime - · simp only [one_pow, pow_one] - haveI := Fact.mk hprime; exact sub_pow_char_pow_of_commute R x y h - -theorem add_pow_expChar [CommSemiring R] {q : ℕ} [hR : ExpChar R q] - (x y : R) : (x + y) ^ q = x ^ q + y ^ q := by - rcases hR with _ | hprime - · simp only [pow_one] - haveI := Fact.mk hprime; exact add_pow_char R x y - -theorem add_pow_expChar_pow [CommSemiring R] {q : ℕ} [hR : ExpChar R q] - {n : ℕ} (x y : R) : (x + y) ^ q ^ n = x ^ q ^ n + y ^ q ^ n := by - rcases hR with _ | hprime - · simp only [one_pow, pow_one] - haveI := Fact.mk hprime; exact add_pow_char_pow R x y - -theorem sub_pow_expChar [CommRing R] {q : ℕ} [hR : ExpChar R q] - (x y : R) : (x - y) ^ q = x ^ q - y ^ q := by - rcases hR with _ | hprime - · simp only [pow_one] - haveI := Fact.mk hprime; exact sub_pow_char R x y - -theorem sub_pow_expChar_pow [CommRing R] {q : ℕ} [hR : ExpChar R q] - {n : ℕ} (x y : R) : (x - y) ^ q ^ n = x ^ q ^ n - y ^ q ^ n := by - rcases hR with _ | hprime - · simp only [one_pow, pow_one] - haveI := Fact.mk hprime; exact sub_pow_char_pow R x y - -theorem ExpChar.neg_one_pow_expChar [Ring R] (q : ℕ) [hR : ExpChar R q] : - (-1 : R) ^ q = -1 := by - rcases hR with _ | hprime - · simp only [pow_one] - haveI := Fact.mk hprime; exact CharP.neg_one_pow_char R q - -theorem ExpChar.neg_one_pow_expChar_pow [Ring R] (q n : ℕ) [hR : ExpChar R q] : - (-1 : R) ^ q ^ n = -1 := by - rcases hR with _ | hprime - · simp only [one_pow, pow_one] - haveI := Fact.mk hprime; exact CharP.neg_one_pow_char_pow R q n - section frobenius section CommSemiring @@ -264,91 +40,7 @@ section CommSemiring variable [CommSemiring R] {S : Type*} [CommSemiring S] (f : R →* S) (g : R →+* S) (p m n : ℕ) [ExpChar R p] [ExpChar S p] (x y : R) -/-- The frobenius map that sends x to x^p -/ -def frobenius : R →+* R where - __ := powMonoidHom p - map_zero' := zero_pow (expChar_pos R p).ne' - map_add' := add_pow_expChar R - -/-- The iterated frobenius map sending x to x^p^n -/ -def iterateFrobenius : R →+* R where - __ := powMonoidHom (p ^ n) - map_zero' := zero_pow (expChar_pow_pos R p n).ne' - map_add' := add_pow_expChar_pow R - -variable {R} - -theorem frobenius_def : frobenius R p x = x ^ p := rfl - -theorem iterateFrobenius_def : iterateFrobenius R p n x = x ^ p ^ n := rfl - -theorem iterate_frobenius : (frobenius R p)^[n] x = x ^ p ^ n := congr_fun (pow_iterate p n) x - -variable (R) - -theorem coe_iterateFrobenius : iterateFrobenius R p n = (frobenius R p)^[n] := - (pow_iterate p n).symm - -theorem iterateFrobenius_one_apply : iterateFrobenius R p 1 x = x ^ p := by - rw [iterateFrobenius_def, pow_one] - -@[simp] -theorem iterateFrobenius_one : iterateFrobenius R p 1 = frobenius R p := - RingHom.ext (iterateFrobenius_one_apply R p) - -theorem iterateFrobenius_zero_apply : iterateFrobenius R p 0 x = x := by - rw [iterateFrobenius_def, pow_zero, pow_one] - -@[simp] -theorem iterateFrobenius_zero : iterateFrobenius R p 0 = RingHom.id R := - RingHom.ext (iterateFrobenius_zero_apply R p) - -theorem iterateFrobenius_add_apply : - iterateFrobenius R p (m + n) x = iterateFrobenius R p m (iterateFrobenius R p n x) := by - simp_rw [iterateFrobenius_def, add_comm m n, pow_add, pow_mul] - -theorem iterateFrobenius_add : - iterateFrobenius R p (m + n) = (iterateFrobenius R p m).comp (iterateFrobenius R p n) := - RingHom.ext (iterateFrobenius_add_apply R p m n) - -theorem iterateFrobenius_mul_apply : - iterateFrobenius R p (m * n) x = (iterateFrobenius R p m)^[n] x := by - simp_rw [coe_iterateFrobenius, Function.iterate_mul] - -theorem coe_iterateFrobenius_mul : iterateFrobenius R p (m * n) = (iterateFrobenius R p m)^[n] := - funext (iterateFrobenius_mul_apply R p m n) - -variable {R} - -theorem frobenius_mul : frobenius R p (x * y) = frobenius R p x * frobenius R p y := - map_mul (frobenius R p) x y - -theorem frobenius_one : frobenius R p 1 = 1 := - one_pow _ - -theorem MonoidHom.map_frobenius : f (frobenius R p x) = frobenius S p (f x) := - map_pow f x p - -theorem RingHom.map_frobenius : g (frobenius R p x) = frobenius S p (g x) := - map_pow g x p - -theorem MonoidHom.map_iterate_frobenius (n : ℕ) : - f ((frobenius R p)^[n] x) = (frobenius S p)^[n] (f x) := - Function.Semiconj.iterate_right (f.map_frobenius p) n x - -theorem RingHom.map_iterate_frobenius (n : ℕ) : - g ((frobenius R p)^[n] x) = (frobenius S p)^[n] (g x) := - g.toMonoidHom.map_iterate_frobenius p x n - -theorem MonoidHom.iterate_map_frobenius (f : R →* R) (p : ℕ) [ExpChar R p] (n : ℕ) : - f^[n] (frobenius R p x) = frobenius R p (f^[n] x) := - iterate_map_pow f _ _ _ - -theorem RingHom.iterate_map_frobenius (f : R →+* R) (p : ℕ) [ExpChar R p] (n : ℕ) : - f^[n] (frobenius R p x) = frobenius R p (f^[n] x) := - iterate_map_pow f _ _ _ - -variable (R S) +variable (S) /-- The frobenius map of an algebra as a frobenius-semilinear map. -/ nonrec def LinearMap.frobenius [Algebra R S] : S →ₛₗ[frobenius R p] S where @@ -379,43 +71,5 @@ theorem frobenius_natCast (n : ℕ) : frobenius R p n = n := @[deprecated (since := "2024-04-17")] alias frobenius_nat_cast := frobenius_natCast -variable {R} - -theorem list_sum_pow_char (l : List R) : l.sum ^ p = (l.map (· ^ p : R → R)).sum := - map_list_sum (frobenius R p) _ - -theorem multiset_sum_pow_char (s : Multiset R) : s.sum ^ p = (s.map (· ^ p : R → R)).sum := - map_multiset_sum (frobenius R p) _ - -theorem sum_pow_char {ι : Type*} (s : Finset ι) (f : ι → R) : - (∑ i ∈ s, f i) ^ p = ∑ i ∈ s, f i ^ p := - map_sum (frobenius R p) _ _ - -variable (n : ℕ) - -theorem list_sum_pow_char_pow (l : List R) : l.sum ^ p ^ n = (l.map (· ^ p ^ n : R → R)).sum := - map_list_sum (iterateFrobenius R p n) _ - -theorem multiset_sum_pow_char_pow (s : Multiset R) : - s.sum ^ p ^ n = (s.map (· ^ p ^ n : R → R)).sum := - map_multiset_sum (iterateFrobenius R p n) _ - -theorem sum_pow_char_pow {ι : Type*} (s : Finset ι) (f : ι → R) : - (∑ i ∈ s, f i) ^ p ^ n = ∑ i ∈ s, f i ^ p ^ n := - map_sum (iterateFrobenius R p n) _ _ - end CommSemiring - -section CommRing - -variable [CommRing R] (p : ℕ) [ExpChar R p] (x y : R) - -theorem frobenius_neg : frobenius R p (-x) = -frobenius R p x := - map_neg .. - -theorem frobenius_sub : frobenius R p (x - y) = frobenius R p x - frobenius R p y := - map_sub .. - -end CommRing - end frobenius diff --git a/Mathlib/Algebra/CharP/IntermediateField.lean b/Mathlib/Algebra/CharP/IntermediateField.lean index a577f00bd38d8..611dc38c84f62 100644 --- a/Mathlib/Algebra/CharP/IntermediateField.lean +++ b/Mathlib/Algebra/CharP/IntermediateField.lean @@ -3,9 +3,9 @@ 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.Algebra.CharP.ExpChar -import Mathlib.FieldTheory.IntermediateField.Basic +import Mathlib.Algebra.CharP.Algebra import Mathlib.Algebra.EuclideanDomain.Field +import Mathlib.FieldTheory.IntermediateField.Basic /-! diff --git a/Mathlib/Algebra/CharP/Lemmas.lean b/Mathlib/Algebra/CharP/Lemmas.lean new file mode 100644 index 0000000000000..68a618f1adec5 --- /dev/null +++ b/Mathlib/Algebra/CharP/Lemmas.lean @@ -0,0 +1,400 @@ +/- +Copyright (c) 2018 Kenny Lau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kenny Lau, Joey van Langen, Casper Putz +-/ +import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.GroupPower.IterateHom +import Mathlib.Data.Nat.Multiplicity +import Mathlib.Data.Nat.Choose.Sum + +/-! +# Characteristic of semirings +-/ + +assert_not_exists Algebra +assert_not_exists LinearMap +assert_not_exists orderOf + +open Finset + +variable {R S : Type*} + +namespace Commute + +variable [Semiring R] {p : ℕ} (hp : p.Prime) {x y : R} +include hp + +protected theorem add_pow_prime_pow_eq (h : Commute x y) (n : ℕ) : + (x + y) ^ p ^ n = + x ^ p ^ n + y ^ p ^ n + + p * ∑ k ∈ Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * ↑((p ^ n).choose k / p) := by + trans x ^ p ^ n + y ^ p ^ n + ∑ k ∈ Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * (p ^ n).choose k + · simp_rw [h.add_pow, ← Nat.Ico_zero_eq_range, Nat.Ico_succ_right, Icc_eq_cons_Ico (zero_le _), + Finset.sum_cons, Ico_eq_cons_Ioo (pow_pos hp.pos _), Finset.sum_cons, tsub_self, tsub_zero, + pow_zero, Nat.choose_zero_right, Nat.choose_self, Nat.cast_one, mul_one, one_mul, ← add_assoc] + · congr 1 + simp_rw [Finset.mul_sum, Nat.cast_comm, mul_assoc _ _ (p : R), ← Nat.cast_mul] + refine Finset.sum_congr rfl fun i hi => ?_ + rw [mem_Ioo] at hi + rw [Nat.div_mul_cancel (hp.dvd_choose_pow hi.1.ne' hi.2.ne)] + +protected theorem add_pow_prime_eq (h : Commute x y) : + (x + y) ^ p = + x ^ p + y ^ p + p * ∑ k ∈ Finset.Ioo 0 p, x ^ k * y ^ (p - k) * ↑(p.choose k / p) := by + simpa using h.add_pow_prime_pow_eq hp 1 + +protected theorem exists_add_pow_prime_pow_eq (h : Commute x y) (n : ℕ) : + ∃ r, (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n + p * r := + ⟨_, h.add_pow_prime_pow_eq hp n⟩ + +protected theorem exists_add_pow_prime_eq (h : Commute x y) : + ∃ r, (x + y) ^ p = x ^ p + y ^ p + p * r := + ⟨_, h.add_pow_prime_eq hp⟩ + +end Commute + +section CommSemiring + +variable [CommSemiring R] {p : ℕ} (hp : p.Prime) (x y : R) (n : ℕ) +include hp + +theorem add_pow_prime_pow_eq : + (x + y) ^ p ^ n = + x ^ p ^ n + y ^ p ^ n + + p * ∑ k ∈ Finset.Ioo 0 (p ^ n), x ^ k * y ^ (p ^ n - k) * ↑((p ^ n).choose k / p) := + (Commute.all x y).add_pow_prime_pow_eq hp n + +theorem add_pow_prime_eq : + (x + y) ^ p = + x ^ p + y ^ p + p * ∑ k ∈ Finset.Ioo 0 p, x ^ k * y ^ (p - k) * ↑(p.choose k / p) := + (Commute.all x y).add_pow_prime_eq hp + +theorem exists_add_pow_prime_pow_eq : + ∃ r, (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n + p * r := + (Commute.all x y).exists_add_pow_prime_pow_eq hp n + +theorem exists_add_pow_prime_eq : + ∃ r, (x + y) ^ p = x ^ p + y ^ p + p * r := + (Commute.all x y).exists_add_pow_prime_eq hp + +end CommSemiring + +section Semiring +variable [Semiring R] {x y : R} (p n : ℕ) + +section ExpChar +variable [hR : ExpChar R p] + +lemma add_pow_expChar_of_commute (h : Commute x y) : (x + y) ^ p = x ^ p + y ^ p := by + obtain _ | hprime := hR + · simp only [pow_one] + · let ⟨r, hr⟩ := h.exists_add_pow_prime_eq hprime + simp [hr] + +lemma add_pow_expChar_pow_of_commute (h : Commute x y) : + (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := by + obtain _ | hprime := hR + · simp only [one_pow, pow_one] + · let ⟨r, hr⟩ := h.exists_add_pow_prime_pow_eq hprime n + simp [hr] + +lemma add_pow_eq_mul_pow_add_pow_div_expChar_of_commute (h : Commute x y) : + (x + y) ^ n = (x + y) ^ (n % p) * (x ^ p + y ^ p) ^ (n / p) := by + rw [← add_pow_expChar_of_commute _ h, ← pow_mul, ← pow_add, Nat.mod_add_div] + +end ExpChar + +section CharP +variable [hp : Fact p.Prime] [CharP R p] + +lemma add_pow_char_of_commute (h : Commute x y) : (x + y) ^ p = x ^ p + y ^ p := + add_pow_expChar_of_commute _ h + +lemma add_pow_char_pow_of_commute (h : Commute x y) : (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := + add_pow_expChar_pow_of_commute _ _ h + +lemma add_pow_eq_mul_pow_add_pow_div_char_of_commute (h : Commute x y) : + (x + y) ^ n = (x + y) ^ (n % p) * (x ^ p + y ^ p) ^ (n / p) := + add_pow_eq_mul_pow_add_pow_div_expChar_of_commute _ _ h + +end CharP +end Semiring + +section CommSemiring +variable [CommSemiring R] (x y : R) (p n : ℕ) + +section ExpChar +variable [hR : ExpChar R p] + +lemma add_pow_expChar : (x + y) ^ p = x ^ p + y ^ p := add_pow_expChar_of_commute _ <| .all .. + +lemma add_pow_expChar_pow : (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := + add_pow_expChar_pow_of_commute _ _ <| .all .. + +lemma add_pow_eq_mul_pow_add_pow_div_expChar : + (x + y) ^ n = (x + y) ^ (n % p) * (x ^ p + y ^ p) ^ (n / p) := + add_pow_eq_mul_pow_add_pow_div_expChar_of_commute _ _ <| .all .. + +end ExpChar + +section CharP +variable [hp : Fact p.Prime] [CharP R p] + +lemma add_pow_char : (x + y) ^ p = x ^ p + y ^ p := add_pow_expChar .. +lemma add_pow_char_pow : (x + y) ^ p ^ n = x ^ p ^ n + y ^ p ^ n := add_pow_expChar_pow .. + +lemma add_pow_eq_mul_pow_add_pow_div_char : + (x + y) ^ n = (x + y) ^ (n % p) * (x ^ p + y ^ p) ^ (n / p) := + add_pow_eq_mul_pow_add_pow_div_expChar .. + +@[deprecated (since := "2024-10-21")] +alias add_pow_eq_add_pow_mod_mul_pow_add_pow_div := add_pow_eq_mul_pow_add_pow_div_char + +end CharP +end CommSemiring + +section Ring +variable [Ring R] {x y : R} (p n : ℕ) + +section ExpChar +variable [hR : ExpChar R p] +include hR + +lemma sub_pow_expChar_of_commute (h : Commute x y) : (x - y) ^ p = x ^ p - y ^ p := by + simp [eq_sub_iff_add_eq, ← add_pow_expChar_of_commute _ (h.sub_left rfl)] + +lemma sub_pow_expChar_pow_of_commute (h : Commute x y) : + (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := by + simp [eq_sub_iff_add_eq, ← add_pow_expChar_pow_of_commute _ _ (h.sub_left rfl)] + +lemma sub_pow_eq_mul_pow_sub_pow_div_expChar_of_commute (h : Commute x y) : + (x - y) ^ n = (x - y) ^ (n % p) * (x ^ p - y ^ p) ^ (n / p) := by + rw [← sub_pow_expChar_of_commute _ h, ← pow_mul, ← pow_add, Nat.mod_add_div] + +variable (R) + +lemma neg_one_pow_expChar : (-1 : R) ^ p = -1 := by + rw [eq_neg_iff_add_eq_zero] + nth_rw 2 [← one_pow p] + rw [← add_pow_expChar_of_commute _ (Commute.one_right _), neg_add_cancel, + zero_pow (expChar_ne_zero R p)] + +lemma neg_one_pow_expChar_pow : (-1 : R) ^ p ^ n = -1 := by + rw [eq_neg_iff_add_eq_zero] + nth_rw 2 [← one_pow (p ^ n)] + rw [← add_pow_expChar_pow_of_commute _ _ (Commute.one_right _), neg_add_cancel, + zero_pow (pow_ne_zero _ <| expChar_ne_zero R p)] + +end ExpChar + +section CharP +variable [hp : Fact p.Prime] [CharP R p] + +lemma sub_pow_char_of_commute (h : Commute x y) : (x - y) ^ p = x ^ p - y ^ p := + sub_pow_expChar_of_commute _ h + +lemma sub_pow_char_pow_of_commute (h : Commute x y) : (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := + sub_pow_expChar_pow_of_commute _ _ h + +variable (R) + +lemma neg_one_pow_char : (-1 : R) ^ p = -1 := neg_one_pow_expChar .. + +lemma neg_one_pow_char_pow : (-1 : R) ^ p ^ n = -1 := neg_one_pow_expChar_pow .. + +lemma sub_pow_eq_mul_pow_sub_pow_div_char_of_commute (h : Commute x y) : + (x - y) ^ n = (x - y) ^ (n % p) * (x ^ p - y ^ p) ^ (n / p) := + sub_pow_eq_mul_pow_sub_pow_div_expChar_of_commute _ _ h + +end CharP +end Ring + +section CommRing +variable [CommRing R] (x y : R) (n : ℕ) {p : ℕ} + +section ExpChar +variable [hR : ExpChar R p] + +lemma sub_pow_expChar : (x - y) ^ p = x ^ p - y ^ p := sub_pow_expChar_of_commute _ <| .all .. + +lemma sub_pow_expChar_pow : (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := + sub_pow_expChar_pow_of_commute _ _ <| .all .. + +lemma sub_pow_eq_mul_pow_sub_pow_div_expChar : + (x - y) ^ n = (x - y) ^ (n % p) * (x ^ p - y ^ p) ^ (n / p) := + sub_pow_eq_mul_pow_sub_pow_div_expChar_of_commute _ _ <| .all .. + +end ExpChar + +section CharP +variable [hp : Fact p.Prime] [CharP R p] + +lemma sub_pow_char : (x - y) ^ p = x ^ p - y ^ p := sub_pow_expChar .. +lemma sub_pow_char_pow : (x - y) ^ p ^ n = x ^ p ^ n - y ^ p ^ n := sub_pow_expChar_pow .. + +lemma sub_pow_eq_mul_pow_sub_pow_div_char : + (x - y) ^ n = (x - y) ^ (n % p) * (x ^ p - y ^ p) ^ (n / p) := + sub_pow_eq_mul_pow_sub_pow_div_expChar .. + +end CharP + +lemma Nat.Prime.dvd_add_pow_sub_pow_of_dvd (hpri : p.Prime) {r : R} (h₁ : r ∣ x ^ p) + (h₂ : r ∣ p * x) : r ∣ (x + y) ^ p - y ^ p := by + rw [add_pow_prime_eq hpri, add_right_comm, add_assoc, add_sub_assoc, add_sub_cancel_right] + apply dvd_add h₁ (h₂.trans <| mul_dvd_mul_left _ <| Finset.dvd_sum _) + simp only [Finset.mem_Ioo, and_imp, mul_assoc] + intro i hi0 _ + exact dvd_mul_of_dvd_left (dvd_rfl.pow hi0.ne') _ + +end CommRing + + +namespace CharP + +section + +variable (R) [NonAssocRing R] + +/-- The characteristic of a finite ring cannot be zero. -/ +theorem char_ne_zero_of_finite (p : ℕ) [CharP R p] [Finite R] : p ≠ 0 := by + rintro rfl + haveI : CharZero R := charP_to_charZero R + cases nonempty_fintype R + exact absurd Nat.cast_injective (not_injective_infinite_finite ((↑) : ℕ → R)) + +theorem ringChar_ne_zero_of_finite [Finite R] : ringChar R ≠ 0 := + char_ne_zero_of_finite R (ringChar R) + +end + +section Ring + +variable (R) [Ring R] [NoZeroDivisors R] [Nontrivial R] [Finite R] + +theorem char_is_prime (p : ℕ) [CharP R p] : p.Prime := + Or.resolve_right (char_is_prime_or_zero R p) (char_ne_zero_of_finite R p) + +end Ring +end CharP + +/-! ### The Frobenius automorphism -/ + +section frobenius +section CommSemiring +variable [CommSemiring R] {S : Type*} [CommSemiring S] (f : R →* S) (g : R →+* S) (p m n : ℕ) + [ExpChar R p] [ExpChar S p] (x y : R) + +open ExpChar + +variable (R) in +/-- The frobenius map `x ↦ x ^ p`. -/ +def frobenius : R →+* R where + __ := powMonoidHom p + map_zero' := zero_pow (expChar_pos R p).ne' + map_add' _ _ := add_pow_expChar .. + +variable (R) in +/-- The iterated frobenius map `x ↦ x ^ p ^ n`. -/ +def iterateFrobenius : R →+* R where + __ := powMonoidHom (p ^ n) + map_zero' := zero_pow (expChar_pow_pos R p n).ne' + map_add' _ _ := add_pow_expChar_pow .. + + +lemma frobenius_def : frobenius R p x = x ^ p := rfl + +lemma iterateFrobenius_def : iterateFrobenius R p n x = x ^ p ^ n := rfl + +lemma iterate_frobenius : (frobenius R p)^[n] x = x ^ p ^ n := congr_fun (pow_iterate p n) x + +variable (R) + +lemma coe_iterateFrobenius : iterateFrobenius R p n = (frobenius R p)^[n] := + (pow_iterate p n).symm + +lemma iterateFrobenius_one_apply : iterateFrobenius R p 1 x = x ^ p := by + rw [iterateFrobenius_def, pow_one] + +@[simp] +lemma iterateFrobenius_one : iterateFrobenius R p 1 = frobenius R p := + RingHom.ext (iterateFrobenius_one_apply R p) + +lemma iterateFrobenius_zero_apply : iterateFrobenius R p 0 x = x := by + rw [iterateFrobenius_def, pow_zero, pow_one] + +@[simp] +lemma iterateFrobenius_zero : iterateFrobenius R p 0 = RingHom.id R := + RingHom.ext (iterateFrobenius_zero_apply R p) + +lemma iterateFrobenius_add_apply : + iterateFrobenius R p (m + n) x = iterateFrobenius R p m (iterateFrobenius R p n x) := by + simp_rw [iterateFrobenius_def, add_comm m n, pow_add, pow_mul] + +lemma iterateFrobenius_add : + iterateFrobenius R p (m + n) = (iterateFrobenius R p m).comp (iterateFrobenius R p n) := + RingHom.ext (iterateFrobenius_add_apply R p m n) + +lemma iterateFrobenius_mul_apply : + iterateFrobenius R p (m * n) x = (iterateFrobenius R p m)^[n] x := by + simp_rw [coe_iterateFrobenius, Function.iterate_mul] + +lemma coe_iterateFrobenius_mul : iterateFrobenius R p (m * n) = (iterateFrobenius R p m)^[n] := + funext (iterateFrobenius_mul_apply R p m n) + +variable {R} + +lemma frobenius_mul : frobenius R p (x * y) = frobenius R p x * frobenius R p y := + map_mul (frobenius R p) x y + +lemma frobenius_one : frobenius R p 1 = 1 := one_pow _ + +lemma MonoidHom.map_frobenius : f (frobenius R p x) = frobenius S p (f x) := map_pow f x p +lemma RingHom.map_frobenius : g (frobenius R p x) = frobenius S p (g x) := map_pow g x p + +lemma MonoidHom.map_iterate_frobenius (n : ℕ) : + f ((frobenius R p)^[n] x) = (frobenius S p)^[n] (f x) := + Function.Semiconj.iterate_right (f.map_frobenius p) n x + +lemma RingHom.map_iterate_frobenius (n : ℕ) : + g ((frobenius R p)^[n] x) = (frobenius S p)^[n] (g x) := + g.toMonoidHom.map_iterate_frobenius p x n + +lemma MonoidHom.iterate_map_frobenius (f : R →* R) (p : ℕ) [ExpChar R p] (n : ℕ) : + f^[n] (frobenius R p x) = frobenius R p (f^[n] x) := + iterate_map_pow f _ _ _ + +lemma RingHom.iterate_map_frobenius (f : R →+* R) (p : ℕ) [ExpChar R p] (n : ℕ) : + f^[n] (frobenius R p x) = frobenius R p (f^[n] x) := iterate_map_pow f _ _ _ + +lemma list_sum_pow_char (l : List R) : l.sum ^ p = (l.map (· ^ p : R → R)).sum := + map_list_sum (frobenius R p) _ + +lemma multiset_sum_pow_char (s : Multiset R) : s.sum ^ p = (s.map (· ^ p : R → R)).sum := + map_multiset_sum (frobenius R p) _ + +lemma sum_pow_char {ι : Type*} (s : Finset ι) (f : ι → R) : (∑ i ∈ s, f i) ^ p = ∑ i ∈ s, f i ^ p := + map_sum (frobenius R p) _ _ + +variable (n : ℕ) + +lemma list_sum_pow_char_pow (l : List R) : l.sum ^ p ^ n = (l.map (· ^ p ^ n : R → R)).sum := + map_list_sum (iterateFrobenius R p n) _ + +lemma multiset_sum_pow_char_pow (s : Multiset R) : + s.sum ^ p ^ n = (s.map (· ^ p ^ n : R → R)).sum := map_multiset_sum (iterateFrobenius R p n) _ + +lemma sum_pow_char_pow {ι : Type*} (s : Finset ι) (f : ι → R) : + (∑ i ∈ s, f i) ^ p ^ n = ∑ i ∈ s, f i ^ p ^ n := map_sum (iterateFrobenius R p n) _ _ + +end CommSemiring + +section CommRing +variable [CommRing R] (p : ℕ) [ExpChar R p] (x y : R) + +lemma frobenius_neg : frobenius R p (-x) = -frobenius R p x := map_neg .. + +lemma frobenius_sub : frobenius R p (x - y) = frobenius R p x - frobenius R p y := map_sub .. + +end CommRing +end frobenius diff --git a/Mathlib/Algebra/CharP/LocalRing.lean b/Mathlib/Algebra/CharP/LocalRing.lean index 645df7bf14817..224e3821a2e71 100644 --- a/Mathlib/Algebra/CharP/LocalRing.lean +++ b/Mathlib/Algebra/CharP/LocalRing.lean @@ -3,7 +3,6 @@ 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.Basic import Mathlib.Algebra.IsPrimePow import Mathlib.Data.Nat.Factorization.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs diff --git a/Mathlib/Algebra/CharP/MixedCharZero.lean b/Mathlib/Algebra/CharP/MixedCharZero.lean index 71c1c3e90b751..4f9d5da352239 100644 --- a/Mathlib/Algebra/CharP/MixedCharZero.lean +++ b/Mathlib/Algebra/CharP/MixedCharZero.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jon Eugster -/ import Mathlib.Algebra.CharP.LocalRing -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Basic import Mathlib.Tactic.FieldSimp /-! diff --git a/Mathlib/Algebra/CharP/Quotient.lean b/Mathlib/Algebra/CharP/Quotient.lean index 5f016371c3d73..599a0c714c1b3 100644 --- a/Mathlib/Algebra/CharP/Quotient.lean +++ b/Mathlib/Algebra/CharP/Quotient.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Eric Wieser -/ import Mathlib.GroupTheory.OrderOfElement import Mathlib.RingTheory.Ideal.Maps -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Defs /-! # Characteristic of quotients rings diff --git a/Mathlib/Algebra/CharP/Reduced.lean b/Mathlib/Algebra/CharP/Reduced.lean index 045af0fb1b707..deea5f7b1eb53 100644 --- a/Mathlib/Algebra/CharP/Reduced.lean +++ b/Mathlib/Algebra/CharP/Reduced.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, Joey van Langen, Casper Putz -/ -import Mathlib.Algebra.CharP.ExpChar +import Mathlib.Algebra.CharP.Lemmas import Mathlib.RingTheory.Nilpotent.Defs /-! diff --git a/Mathlib/Algebra/CharP/Two.lean b/Mathlib/Algebra/CharP/Two.lean index 0f91ff1fa1e5b..508390fa0fa72 100644 --- a/Mathlib/Algebra/CharP/Two.lean +++ b/Mathlib/Algebra/CharP/Two.lean @@ -3,7 +3,7 @@ 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.CharP.ExpChar +import Mathlib.Algebra.CharP.Lemmas import Mathlib.GroupTheory.OrderOfElement /-! @@ -15,20 +15,41 @@ The lemmas in this file with a `_sq` suffix are just special cases of the `_pow_ elsewhere, with a shorter name for ease of discovery, and no need for a `[Fact (Prime 2)]` argument. -/ +assert_not_exists Algebra +assert_not_exists LinearMap variable {R ι : Type*} namespace CharTwo +section AddMonoidWithOne + +variable [AddMonoidWithOne R] + +theorem two_eq_zero [CharP R 2] : (2 : R) = 0 := by + rw [← Nat.cast_two, CharP.cast_eq_zero] + +/-- The only hypotheses required to build a `CharP R 2` instance are `1 ≠ 0` and `2 = 0`. -/ +theorem of_one_ne_zero_of_two_eq_zero (h₁ : (1 : R) ≠ 0) (h₂ : (2 : R) = 0) : CharP R 2 where + cast_eq_zero_iff' n := by + obtain hn | hn := Nat.even_or_odd n + · simp_rw [hn.two_dvd, iff_true] + exact natCast_eq_zero_of_even_of_two_eq_zero hn h₂ + · simp_rw [hn.not_two_dvd_nat, iff_false] + rwa [natCast_eq_one_of_odd_of_two_eq_zero hn h₂] + +end AddMonoidWithOne + section Semiring variable [Semiring R] [CharP R 2] -theorem two_eq_zero : (2 : R) = 0 := by rw [← Nat.cast_two, CharP.cast_eq_zero] - @[scoped simp] theorem add_self_eq_zero (x : R) : x + x = 0 := by rw [← two_smul R x, two_eq_zero, zero_smul] +@[scoped simp] +protected theorem two_nsmul (x : R) : 2 • x = 0 := by rw [two_smul, add_self_eq_zero] + end Semiring section Ring @@ -37,7 +58,7 @@ variable [Ring R] [CharP R 2] @[scoped simp] theorem neg_eq (x : R) : -x = x := by - rw [neg_eq_iff_add_eq_zero, ← two_smul R x, two_eq_zero, zero_smul] + rw [neg_eq_iff_add_eq_zero, add_self_eq_zero] theorem neg_eq' : Neg.neg = (id : R → R) := funext neg_eq @@ -45,8 +66,19 @@ theorem neg_eq' : Neg.neg = (id : R → R) := @[scoped simp] theorem sub_eq_add (x y : R) : x - y = x + y := by rw [sub_eq_add_neg, neg_eq] -theorem sub_eq_add' : HSub.hSub = ((· + ·) : R → R → R) := - funext fun x => funext fun y => sub_eq_add x y +@[deprecated sub_eq_add (since := "2024-10-24")] +theorem sub_eq_add' : HSub.hSub = (· + · : R → R → R) := + funext₂ sub_eq_add + +theorem add_eq_iff_eq_add {a b c : R} : a + b = c ↔ a = c + b := by + rw [← sub_eq_iff_eq_add, sub_eq_add] + +theorem eq_add_iff_add_eq {a b c : R} : a = b + c ↔ a + c = b := by + rw [← eq_sub_iff_add_eq, sub_eq_add] + +@[scoped simp] +protected theorem two_zsmul (x : R) : (2 : ℤ) • x = 0 := by + rw [two_zsmul, add_self_eq_zero] end Ring diff --git a/Mathlib/Algebra/CharZero/Lemmas.lean b/Mathlib/Algebra/CharZero/Lemmas.lean index 15bdc16d9f97e..5c3ac417809dd 100644 --- a/Mathlib/Algebra/CharZero/Lemmas.lean +++ b/Mathlib/Algebra/CharZero/Lemmas.lean @@ -154,7 +154,7 @@ theorem RingHom.charZero (ϕ : R →+* S) [CharZero S] : CharZero R := theorem RingHom.charZero_iff {ϕ : R →+* S} (hϕ : Function.Injective ϕ) : CharZero R ↔ CharZero S := ⟨fun hR => ⟨by intro a b h; rwa [← @Nat.cast_inj R, ← hϕ.eq_iff, map_natCast ϕ, map_natCast ϕ]⟩, - fun hS => ϕ.charZero⟩ + fun _ => ϕ.charZero⟩ theorem RingHom.injective_nat (f : ℕ →+* R) [CharZero R] : Function.Injective f := Subsingleton.elim (Nat.castRingHom _) f ▸ Nat.cast_injective diff --git a/Mathlib/Algebra/CharZero/Quotient.lean b/Mathlib/Algebra/CharZero/Quotient.lean index 8a44865763c7e..5907ad58db1a0 100644 --- a/Mathlib/Algebra/CharZero/Quotient.lean +++ b/Mathlib/Algebra/CharZero/Quotient.lean @@ -4,8 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Field.Basic -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Algebra.Group.Subgroup.ZPowers import Mathlib.Algebra.Order.Group.Unbundled.Int +import Mathlib.Algebra.Module.Defs +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Lemmas about quotients in characteristic zero @@ -51,11 +53,11 @@ namespace QuotientAddGroup theorem zmultiples_zsmul_eq_zsmul_iff {ψ θ : R ⧸ AddSubgroup.zmultiples p} {z : ℤ} (hz : z ≠ 0) : z • ψ = z • θ ↔ ∃ k : Fin z.natAbs, ψ = θ + ((k : ℕ) • (p / z) : R) := by - induction ψ using Quotient.inductionOn' - induction θ using Quotient.inductionOn' + induction ψ using Quotient.inductionOn + induction θ using Quotient.inductionOn -- Porting note: Introduced Zp notation to shorten lines let Zp := AddSubgroup.zmultiples p - have : (Quotient.mk'' : R → R ⧸ Zp) = ((↑) : R → R ⧸ Zp) := rfl + have : (Quotient.mk _ : R → R ⧸ Zp) = ((↑) : R → R ⧸ Zp) := rfl simp only [this] simp_rw [← QuotientAddGroup.mk_zsmul, ← QuotientAddGroup.mk_add, QuotientAddGroup.eq_iff_sub_mem, ← smul_sub, ← sub_sub] diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean index be6b7195e1964..e2e525d76dcdc 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean @@ -94,12 +94,9 @@ theorem one_le_succ_nth_stream_b {ifp_succ_n : IntFractPair K} ∃ ifp_n, IntFractPair.stream v n = some ifp_n ∧ ifp_n.fr ≠ 0 ∧ IntFractPair.of ifp_n.fr⁻¹ = ifp_succ_n := succ_nth_stream_eq_some_iff.1 succ_nth_stream_eq - suffices 1 ≤ ifp_n.fr⁻¹ by rwa [IntFractPair.of, le_floor, cast_one] - suffices ifp_n.fr ≤ 1 by - have h : 0 < ifp_n.fr := - lt_of_le_of_ne (nth_stream_fr_nonneg nth_stream_eq) stream_nth_fr_ne_zero.symm - apply one_le_inv h this - simp only [le_of_lt (nth_stream_fr_lt_one nth_stream_eq)] + rw [IntFractPair.of, le_floor, cast_one, one_le_inv₀ + ((nth_stream_fr_nonneg nth_stream_eq).lt_of_ne' stream_nth_fr_ne_zero)] + exact (nth_stream_fr_lt_one nth_stream_eq).le /-- Shows that the `n + 1`th integer part `bₙ₊₁` of the stream is smaller or equal than the inverse of diff --git a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean index 99e76fa64a5f5..fa5e59f20d0ad 100644 --- a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean +++ b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean @@ -3,6 +3,7 @@ Copyright (c) 2020 Kevin Kappelmann. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kevin Kappelmann -/ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Algebra.ContinuedFractions.ContinuantsRecurrence import Mathlib.Algebra.ContinuedFractions.TerminatedStable import Mathlib.Tactic.FieldSimp diff --git a/Mathlib/Algebra/CubicDiscriminant.lean b/Mathlib/Algebra/CubicDiscriminant.lean index 7280b1a8b0e49..42e56fed93eff 100644 --- a/Mathlib/Algebra/CubicDiscriminant.lean +++ b/Mathlib/Algebra/CubicDiscriminant.lean @@ -194,7 +194,6 @@ theorem leadingCoeff_of_c_eq_zero (ha : P.a = 0) (hb : P.b = 0) (hc : P.c = 0) : P.toPoly.leadingCoeff = P.d := by rw [of_c_eq_zero ha hb hc, leadingCoeff_C] --- @[simp] -- porting note (#10618): simp can prove this theorem leadingCoeff_of_c_eq_zero' : (toPoly ⟨0, 0, 0, d⟩).leadingCoeff = d := leadingCoeff_of_c_eq_zero rfl rfl rfl @@ -304,7 +303,6 @@ theorem degree_of_d_eq_zero (ha : P.a = 0) (hb : P.b = 0) (hc : P.c = 0) (hd : P P.toPoly.degree = ⊥ := by rw [of_d_eq_zero ha hb hc hd, degree_zero] --- @[simp] -- porting note (#10618): simp can prove this theorem degree_of_d_eq_zero' : (⟨0, 0, 0, 0⟩ : Cubic R).toPoly.degree = ⊥ := degree_of_d_eq_zero rfl rfl rfl rfl @@ -354,7 +352,6 @@ theorem natDegree_of_c_eq_zero (ha : P.a = 0) (hb : P.b = 0) (hc : P.c = 0) : P.toPoly.natDegree = 0 := by rw [of_c_eq_zero ha hb hc, natDegree_C] --- @[simp] -- porting note (#10618): simp can prove this theorem natDegree_of_c_eq_zero' : (toPoly ⟨0, 0, 0, d⟩).natDegree = 0 := natDegree_of_c_eq_zero rfl rfl rfl diff --git a/Mathlib/Algebra/DirectLimit.lean b/Mathlib/Algebra/DirectLimit.lean index f077a686dc355..02e8cd959b5e4 100644 --- a/Mathlib/Algebra/DirectLimit.lean +++ b/Mathlib/Algebra/DirectLimit.lean @@ -3,11 +3,12 @@ Copyright (c) 2019 Kenny Lau, Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Chris Hughes, Jujian Zhang -/ -import Mathlib.Data.Finset.Order import Mathlib.Algebra.DirectSum.Module +import Mathlib.Data.Finset.Order +import Mathlib.LinearAlgebra.Quotient.Basic import Mathlib.RingTheory.FreeCommRing import Mathlib.RingTheory.Ideal.Maps -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Defs import Mathlib.Tactic.SuppressCompilation /-! @@ -203,7 +204,7 @@ def map (g : (i : ι) → G i →ₗ[R] G' i) (hg : ∀ i j h, g j ∘ₗ f i j lift_of _ _ _ @[simp] lemma map_id [IsDirected ι (· ≤ ·)] : - map (fun i ↦ LinearMap.id) (fun _ _ _ ↦ rfl) = LinearMap.id (R := R) (M := DirectLimit G f) := + map (fun _ ↦ LinearMap.id) (fun _ _ _ ↦ rfl) = LinearMap.id (R := R) (M := DirectLimit G f) := DFunLike.ext _ _ fun x ↦ (isEmpty_or_nonempty ι).elim (by subsingleton) fun _ ↦ x.induction_on fun i g ↦ by simp @@ -292,7 +293,7 @@ theorem of.zero_exact_aux [∀ i (k : G i), Decidable (k ≠ 0)] [Nonempty ι] [ (∀ k ∈ x.support, k ≤ j) ∧ DirectSum.toModule R ι (G j) (fun i => totalize G f i j) x = (0 : G j) := Nonempty.elim (by infer_instance) fun ind : ι => - span_induction ((Quotient.mk_eq_zero _).1 H) + span_induction (hx := (Quotient.mk_eq_zero _).1 H) (fun x ⟨i, j, hij, y, hxy⟩ => let ⟨k, hik, hjk⟩ := exists_ge_ge i j ⟨k, by @@ -311,14 +312,14 @@ theorem of.zero_exact_aux [∀ i (k : G i), Decidable (k ≠ 0)] [Nonempty ι] [ simp [LinearMap.map_sub, totalize_of_le, hik, hjk, DirectedSystem.map_map, DirectSum.apply_eq_component, DirectSum.component.of]⟩) ⟨ind, fun _ h => (Finset.not_mem_empty _ h).elim, LinearMap.map_zero _⟩ - (fun x y ⟨i, hi, hxi⟩ ⟨j, hj, hyj⟩ => + (fun x y _ _ ⟨i, hi, hxi⟩ ⟨j, hj, hyj⟩ => let ⟨k, hik, hjk⟩ := exists_ge_ge i j - ⟨k, fun l hl => + ⟨k, fun _ hl => (Finset.mem_union.1 (DFinsupp.support_add hl)).elim (fun hl => le_trans (hi _ hl) hik) fun hl => le_trans (hj _ hl) hjk, by simp [LinearMap.map_add, hxi, hyj, toModule_totalize_of_le hik hi, toModule_totalize_of_le hjk hj]⟩) - fun a x ⟨i, hi, hxi⟩ => + fun a x _ ⟨i, hi, hxi⟩ => ⟨i, fun k hk => hi k (DirectSum.support_smul _ _ hk), by simp [LinearMap.map_smul, hxi]⟩ open Classical in @@ -458,7 +459,7 @@ def map (g : (i : ι) → G i →+ G' i) lift_of _ _ _ _ _ @[simp] lemma map_id [IsDirected ι (· ≤ ·)] : - map (fun i ↦ AddMonoidHom.id _) (fun _ _ _ ↦ rfl) = AddMonoidHom.id (DirectLimit G f) := + map (fun _ ↦ AddMonoidHom.id _) (fun _ _ _ ↦ rfl) = AddMonoidHom.id (DirectLimit G f) := DFunLike.ext _ _ fun x ↦ (isEmpty_or_nonempty ι).elim (by subsingleton) fun _ ↦ x.induction_on fun i g ↦ by simp @@ -664,7 +665,7 @@ theorem of.zero_exact_aux [Nonempty ι] [IsDirected ι (· ≤ ·)] {x : FreeCom ∀ [DecidablePred (· ∈ s)], lift (fun ix : s => f' ix.1.1 j (H ix ix.2) ix.1.2) (restriction s x) = (0 : G j) := by have := Classical.decEq - refine span_induction (Ideal.Quotient.eq_zero_iff_mem.1 H) ?_ ?_ ?_ ?_ + refine span_induction ?_ ?_ ?_ ?_ (Ideal.Quotient.eq_zero_iff_mem.1 H) · rintro x (⟨i, j, hij, x, rfl⟩ | ⟨i, rfl⟩ | ⟨i, x, y, rfl⟩ | ⟨i, x, y, rfl⟩) · refine ⟨j, {⟨i, x⟩, ⟨j, f' i j hij x⟩}, ?_, @@ -720,9 +721,8 @@ theorem of.zero_exact_aux [Nonempty ι] [IsDirected ι (· ≤ ·)] {x : FreeCom exacts [Or.inl rfl, Or.inr (Or.inr rfl), Or.inr (Or.inl rfl)] · refine Nonempty.elim (by infer_instance) fun ind : ι => ?_ refine ⟨ind, ∅, fun _ => False.elim, isSupported_zero, fun [_] => ?_⟩ - -- Porting note: `RingHom.map_zero` was `(restriction _).map_zero` - rw [RingHom.map_zero, (FreeCommRing.lift _).map_zero] - · intro x y ⟨i, s, hi, hxs, ihs⟩ ⟨j, t, hj, hyt, iht⟩ + rw [(restriction _).map_zero, (FreeCommRing.lift _).map_zero] + · intro x y _ _ ⟨i, s, hi, hxs, ihs⟩ ⟨j, t, hj, hyt, iht⟩ obtain ⟨k, hik, hjk⟩ := exists_ge_ge i j have : ∀ z : Σi, G i, z ∈ s ∪ t → z.1 ≤ k := by rintro z (hz | hz) @@ -732,12 +732,11 @@ theorem of.zero_exact_aux [Nonempty ι] [IsDirected ι (· ≤ ·)] {x : FreeCom ⟨k, s ∪ t, this, isSupported_add (isSupported_upwards hxs Set.subset_union_left) (isSupported_upwards hyt Set.subset_union_right), fun [_] => ?_⟩ - -- Porting note: was `(restriction _).map_add` - classical rw [RingHom.map_add, (FreeCommRing.lift _).map_add, ← + classical rw [(restriction _).map_add, (FreeCommRing.lift _).map_add, ← of.zero_exact_aux2 G f' hxs hi this hik Set.subset_union_left, ← of.zero_exact_aux2 G f' hyt hj this hjk Set.subset_union_right, ihs, (f' i k hik).map_zero, iht, (f' j k hjk).map_zero, zero_add] - · rintro x y ⟨j, t, hj, hyt, iht⟩ + · rintro x y - ⟨j, t, hj, hyt, iht⟩ rw [smul_eq_mul] rcases exists_finset_support x with ⟨s, hxs⟩ rcases (s.image Sigma.fst).exists_le with ⟨i, hi⟩ @@ -861,7 +860,7 @@ def map (g : (i : ι) → G i →+* G' i) variable [Nonempty ι] @[simp] lemma map_id [IsDirected ι (· ≤ ·)] : - map (fun i ↦ RingHom.id _) (fun _ _ _ ↦ rfl) = + map (fun _ ↦ RingHom.id _) (fun _ _ _ ↦ rfl) = RingHom.id (DirectLimit G fun _ _ h ↦ f _ _ h) := DFunLike.ext _ _ fun x ↦ x.induction_on fun i g ↦ by simp @@ -938,7 +937,7 @@ instance nontrivial [DirectedSystem G fun i j h => f' i j h] : theorem exists_inv {p : Ring.DirectLimit G f} : p ≠ 0 → ∃ y, p * y = 1 := Ring.DirectLimit.induction_on p fun i x H => ⟨Ring.DirectLimit.of G f i x⁻¹, by - erw [← (Ring.DirectLimit.of _ _ _).map_mul, + rw [← (Ring.DirectLimit.of _ _ _).map_mul, mul_inv_cancel₀ fun h : x = 0 => H <| by rw [h, (Ring.DirectLimit.of _ _ _).map_zero], (Ring.DirectLimit.of _ _ _).map_one]⟩ @@ -963,12 +962,12 @@ protected noncomputable abbrev field [DirectedSystem G fun i j h => f' i j h] : -- This used to include the parent CommRing and Nontrivial instances, -- but leaving them implicit avoids a very expensive (2-3 minutes!) eta expansion. inv := inv G fun i j h => f' i j h - mul_inv_cancel := fun p => DirectLimit.mul_inv_cancel G fun i j h => f' i j h + mul_inv_cancel := fun _ => DirectLimit.mul_inv_cancel G fun i j h => f' i j h inv_zero := dif_pos rfl nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl end diff --git a/Mathlib/Algebra/DirectSum/Basic.lean b/Mathlib/Algebra/DirectSum/Basic.lean index be12e9e5145fb..f4f49ac054598 100644 --- a/Mathlib/Algebra/DirectSum/Basic.lean +++ b/Mathlib/Algebra/DirectSum/Basic.lean @@ -272,7 +272,7 @@ protected def id (M : Type v) (ι : Type* := PUnit) [AddCommMonoid M] [Unique ι DirectSum.induction_on x (by rw [AddMonoidHom.map_zero, AddMonoidHom.map_zero]) (fun p x => by rw [Unique.default_eq p, toAddMonoid_of]; rfl) fun x y ihx ihy => by rw [AddMonoidHom.map_add, AddMonoidHom.map_add, ihx, ihy] - right_inv := fun x => toAddMonoid_of _ _ _ } + right_inv := fun _ => toAddMonoid_of _ _ _ } section CongrLeft diff --git a/Mathlib/Algebra/DirectSum/Internal.lean b/Mathlib/Algebra/DirectSum/Internal.lean index 4c03bf25b2f72..aaf84929ec1cc 100644 --- a/Mathlib/Algebra/DirectSum/Internal.lean +++ b/Mathlib/Algebra/DirectSum/Internal.lean @@ -53,12 +53,6 @@ open DirectSum variable {ι : Type*} {σ S R : Type*} -instance AddCommMonoid.ofSubmonoidOnSemiring [Semiring R] [SetLike σ R] [AddSubmonoidClass σ R] - (A : ι → σ) : ∀ i, AddCommMonoid (A i) := fun i => by infer_instance - -instance AddCommGroup.ofSubgroupOnRing [Ring R] [SetLike σ R] [AddSubgroupClass σ R] (A : ι → σ) : - ∀ i, AddCommGroup (A i) := fun i => by infer_instance - theorem SetLike.algebraMap_mem_graded [Zero ι] [CommSemiring S] [Semiring R] [Algebra S R] (A : ι → Submodule S R) [SetLike.GradedOne A] (s : S) : algebraMap S R s ∈ A 0 := by rw [Algebra.algebraMap_eq_smul_one] @@ -243,7 +237,7 @@ theorem coe_mul_of_apply_of_not_le (r : ⨁ i, A i) {i : ι} (r' : A i) (n : ι) · rw [DFinsupp.sum, Finset.sum_ite_of_false, Finset.sum_const_zero] exact fun x _ H => h ((self_le_add_left i x).trans_eq H) -variable [Sub ι] [OrderedSub ι] [ContravariantClass ι ι (· + ·) (· ≤ ·)] +variable [Sub ι] [OrderedSub ι] [AddLeftReflectLE ι] /- The following two lemmas only require the same hypotheses as `eq_tsub_iff_add_eq_of_le`, but we state them for `CanonicallyOrderedAddCommMonoid` + the above three typeclasses for convenience. -/ diff --git a/Mathlib/Algebra/DirectSum/LinearMap.lean b/Mathlib/Algebra/DirectSum/LinearMap.lean index 7ca4b191553b8..25ffc82193de4 100644 --- a/Mathlib/Algebra/DirectSum/LinearMap.lean +++ b/Mathlib/Algebra/DirectSum/LinearMap.lean @@ -78,12 +78,12 @@ lemma trace_eq_sum_trace_restrict' (h : IsInternal N) (hN : {i | N i ≠ ⊥}.Fi rw [← Finset.sum_coe_sort, trace_eq_sum_trace_restrict (isInternal_ne_bot_iff.mpr h) _] exact Fintype.sum_equiv hN.subtypeEquivToFinset _ _ (fun i ↦ rfl) -lemma trace_eq_zero_of_mapsTo_ne (h : IsInternal N) [hn : IsNoetherian R M] +lemma trace_eq_zero_of_mapsTo_ne (h : IsInternal N) [IsNoetherian R M] (σ : ι → ι) (hσ : ∀ i, σ i ≠ i) {f : Module.End R M} (hf : ∀ i, MapsTo f (N i) (N <| σ i)) : trace R M f = 0 := by - have hN : {i | N i ≠ ⊥}.Finite := CompleteLattice.WellFounded.finite_ne_bot_of_independent - hn.wf h.submodule_independent + have hN : {i | N i ≠ ⊥}.Finite := CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent + h.submodule_independent let s := hN.toFinset let κ := fun i ↦ Module.Free.ChooseBasisIndex R (N i) let b : (i : s) → Basis (κ i) R (N i) := fun i ↦ Module.Free.chooseBasis R (N i) @@ -112,8 +112,7 @@ lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top f.independent_maxGenEigenspace hf have h_fin : {μ | f.maxGenEigenspace μ ≠ ⊥}.Finite := - CompleteLattice.WellFounded.finite_ne_bot_of_independent IsWellFounded.wf - f.independent_maxGenEigenspace + CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent f.independent_maxGenEigenspace simp [trace_eq_sum_trace_restrict' hds h_fin hfg, this] intro μ replace h_comm : Commute (g.restrict (f.mapsTo_maxGenEigenspace_of_comm h_comm μ)) diff --git a/Mathlib/Algebra/DirectSum/Module.lean b/Mathlib/Algebra/DirectSum/Module.lean index 291bd79759b1b..0b82afa6bcc70 100644 --- a/Mathlib/Algebra/DirectSum/Module.lean +++ b/Mathlib/Algebra/DirectSum/Module.lean @@ -223,7 +223,7 @@ variable {α : ι → Type*} {δ : ∀ i, α i → Type w} variable [DecidableEq ι] [∀ i j, AddCommMonoid (δ i j)] [∀ i j, Module R (δ i j)] /-- `curry` as a linear map. -/ -def sigmaLcurry : (⨁ i : Σi, _, δ i.1 i.2) →ₗ[R] ⨁ (i) (j), δ i j := +def sigmaLcurry : (⨁ i : Σ_, _, δ i.1 i.2) →ₗ[R] ⨁ (i) (j), δ i j := { sigmaCurry with map_smul' := fun r ↦ by convert DFinsupp.sigmaCurry_smul (δ := δ) r } @[simp] @@ -269,7 +269,7 @@ variable {ι : Type v} [dec_ι : DecidableEq ι] variable {M : Type*} [AddCommMonoid M] [Module R M] variable (A : ι → Submodule R M) -/-- The canonical embedding from `⨁ i, A i` to `M` where `A` is a collection of `Submodule R M` +/-- The canonical linear map from `⨁ i, A i` to `M` where `A` is a collection of `Submodule R M` indexed by `ι`. This is `DirectSum.coeAddMonoidHom` as a `LinearMap`. -/ def coeLinearMap : (⨁ i, A i) →ₗ[R] M := toModule R ι M fun i ↦ (A i).subtype @@ -288,6 +288,9 @@ theorem coeLinearMap_of (i : ι) (x : A i) : DirectSum.coeLinearMap A (of (fun i variable {A} +theorem range_coeLinearMap : LinearMap.range (coeLinearMap A) = ⨆ i, A i := + (Submodule.iSup_eq_range_dfinsupp_lsum _).symm + @[simp] theorem IsInternal.ofBijective_coeLinearMap_same (h : IsInternal A) {i : ι} (x : A i) : diff --git a/Mathlib/Algebra/DirectSum/Ring.lean b/Mathlib/Algebra/DirectSum/Ring.lean index adc80f5bfe07a..e30b34a16eff9 100644 --- a/Mathlib/Algebra/DirectSum/Ring.lean +++ b/Mathlib/Algebra/DirectSum/Ring.lean @@ -222,7 +222,6 @@ private nonrec theorem one_mul (x : ⨁ i, A i) : 1 * x = x := by rw [mulHom_of_of] exact of_eq_of_gradedMonoid_eq (one_mul <| GradedMonoid.mk i xi) --- Porting note (#11083): `suffices` is very slow here. private nonrec theorem mul_one (x : ⨁ i, A i) : x * 1 = x := by suffices (mulHom A).flip One.one = AddMonoidHom.id (⨁ i, A i) from DFunLike.congr_fun this x apply addHom_ext; intro i xi @@ -230,17 +229,13 @@ private nonrec theorem mul_one (x : ⨁ i, A i) : x * 1 = x := by rw [flip_apply, mulHom_of_of] exact of_eq_of_gradedMonoid_eq (mul_one <| GradedMonoid.mk i xi) -/- Porting note: Some auxiliary statements were needed in the proof of the `suffices`, -otherwise would timeout -/ private theorem mul_assoc (a b c : ⨁ i, A i) : a * b * c = a * (b * c) := by -- (`fun a b c => a * b * c` as a bundled hom) = (`fun a b c => a * (b * c)` as a bundled hom) suffices (mulHom A).compHom.comp (mulHom A) = (AddMonoidHom.compHom flipHom <| (mulHom A).flip.compHom.comp (mulHom A)).flip by - have sol := DFunLike.congr_fun (DFunLike.congr_fun (DFunLike.congr_fun this a) b) c - have aux : ∀ a b, (mulHom A) a b = a * b := fun _ _ ↦ rfl - simp only [coe_comp, Function.comp_apply, AddMonoidHom.compHom_apply_apply, aux, flip_apply, - AddMonoidHom.flipHom_apply] at sol - exact sol + simpa only [coe_comp, Function.comp_apply, AddMonoidHom.compHom_apply_apply, flip_apply, + AddMonoidHom.flipHom_apply] + using DFunLike.congr_fun (DFunLike.congr_fun (DFunLike.congr_fun this a) b) c ext ai ax bi bx ci cx dsimp only [coe_comp, Function.comp_apply, AddMonoidHom.compHom_apply_apply, flip_apply, AddMonoidHom.flipHom_apply] @@ -287,7 +282,7 @@ theorem list_prod_ofFn_of_eq_dProd (n : ℕ) (fι : Fin n → ι) (fA : ∀ a, A theorem mul_eq_dfinsupp_sum [∀ (i : ι) (x : A i), Decidable (x ≠ 0)] (a a' : ⨁ i, A i) : a * a' - = a.sum fun i ai => a'.sum fun j aj => DirectSum.of _ _ <| GradedMonoid.GMul.mul ai aj := by + = a.sum fun _ ai => a'.sum fun _ aj => DirectSum.of _ _ <| GradedMonoid.GMul.mul ai aj := by change mulHom _ a a' = _ -- Porting note: I have no idea how the proof from ml3 worked it used to be -- simpa only [mul_hom, to_add_monoid, dfinsupp.lift_add_hom_apply, dfinsupp.sum_add_hom_apply, @@ -558,7 +553,6 @@ def toSemiring (f : ∀ i, A i →+ R) (hone : f _ GradedMonoid.GOne.one = 1) simp_rw [of_mul_of, toAddMonoid_of] exact hmul _ _ } --- Porting note (#10618): removed @[simp] as simp can prove this theorem toSemiring_of (f : ∀ i, A i →+ R) (hone hmul) (i : ι) (x : A i) : toSemiring f hone hmul (of _ i x) = f _ x := toAddMonoid_of f i x diff --git a/Mathlib/Algebra/Divisibility/Prod.lean b/Mathlib/Algebra/Divisibility/Prod.lean index 5eda6b629ea04..355b2cfd6033d 100644 --- a/Mathlib/Algebra/Divisibility/Prod.lean +++ b/Mathlib/Algebra/Divisibility/Prod.lean @@ -33,7 +33,7 @@ instance [DecompositionMonoid G₁] [DecompositionMonoid G₂] : DecompositionMo exact ⟨(a₁, a₂), (a₁', a₂'), ⟨h₁, h₂⟩, ⟨h₁', h₂'⟩, Prod.ext eq₁ eq₂⟩ theorem pi_dvd_iff {x y : ∀ i, G i} : x ∣ y ↔ ∀ i, x i ∣ y i := by - simp_rw [dvd_def, Function.funext_iff, Classical.skolem]; rfl + simp_rw [dvd_def, funext_iff, Classical.skolem]; rfl instance [∀ i, DecompositionMonoid (G i)] : DecompositionMonoid (∀ i, G i) where primal a b c h := by diff --git a/Mathlib/Algebra/Divisibility/Units.lean b/Mathlib/Algebra/Divisibility/Units.lean index aee46556f879c..4afd288068460 100644 --- a/Mathlib/Algebra/Divisibility/Units.lean +++ b/Mathlib/Algebra/Divisibility/Units.lean @@ -5,7 +5,7 @@ Authors: Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Amelia Livingston, Neil Strickland, Aaron Anderson -/ import Mathlib.Algebra.Divisibility.Basic -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic /-! # Divisibility and units @@ -34,7 +34,7 @@ theorem coe_dvd : ↑u ∣ a := associates of `b`. -/ theorem dvd_mul_right : a ∣ b * u ↔ a ∣ b := Iff.intro (fun ⟨c, Eq⟩ ↦ ⟨c * ↑u⁻¹, by rw [← mul_assoc, ← Eq, Units.mul_inv_cancel_right]⟩) - fun ⟨c, Eq⟩ ↦ Eq.symm ▸ (_root_.dvd_mul_right _ _).mul_right _ + fun ⟨_, Eq⟩ ↦ Eq.symm ▸ (_root_.dvd_mul_right _ _).mul_right _ /-- In a monoid, an element `a` divides an element `b` iff all associates of `a` divide `b`. -/ theorem mul_right_dvd : a * u ∣ b ↔ a ∣ b := diff --git a/Mathlib/Algebra/DualNumber.lean b/Mathlib/Algebra/DualNumber.lean index eb913a5ad941f..6e2ef4a79c866 100644 --- a/Mathlib/Algebra/DualNumber.lean +++ b/Mathlib/Algebra/DualNumber.lean @@ -149,16 +149,37 @@ theorem lift_apply_apply (fe : {_fe : (A →ₐ[R] B) × B // _}) (a : A[ε]) : @[simp] theorem coe_lift_symm_apply (F : A[ε] →ₐ[R] B) : (lift.symm F).val = (F.comp (inlAlgHom _ _ _), F ε) := rfl +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{fe : (A →ₐ[R] B) × B // _}`. +-/ +set_option linter.unusedVariables false in /-- When applied to `inl`, `DualNumber.lift` applies the map `f : A →ₐ[R] B`. -/ @[simp] theorem lift_apply_inl (fe : {fe : (A →ₐ[R] B) × B // _}) (a : A) : lift fe (inl a : A[ε]) = fe.val.1 a := by rw [lift_apply_apply, fst_inl, snd_inl, map_zero, zero_mul, add_zero] +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{fe : (A →ₐ[R] B) × B // _}`. +-/ +set_option linter.unusedVariables false in /-- Scaling on the left is sent by `DualNumber.lift` to multiplication on the left -/ @[simp] theorem lift_smul (fe : {fe : (A →ₐ[R] B) × B // _}) (a : A) (ad : A[ε]) : lift fe (a • ad) = fe.val.1 a * lift fe ad := by rw [← inl_mul_eq_smul, map_mul, lift_apply_inl] +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{fe : (A →ₐ[R] B) × B // _}`. +-/ +set_option linter.unusedVariables false in /-- Scaling on the right is sent by `DualNumber.lift` to multiplication on the right -/ @[simp] theorem lift_op_smul (fe : {fe : (A →ₐ[R] B) × B // _}) (a : A) (ad : A[ε]) : lift fe (MulOpposite.op a • ad) = lift fe ad * fe.val.1 a := by diff --git a/Mathlib/Algebra/DualQuaternion.lean b/Mathlib/Algebra/DualQuaternion.lean index 70ed1572d86ac..c1178645b683e 100644 --- a/Mathlib/Algebra/DualQuaternion.lean +++ b/Mathlib/Algebra/DualQuaternion.lean @@ -36,20 +36,18 @@ def dualNumberEquiv : Quaternion (DualNumber R) ≃ₐ[R] DualNumber (Quaternion (⟨q.re.fst, q.imI.fst, q.imJ.fst, q.imK.fst⟩, ⟨q.re.snd, q.imI.snd, q.imJ.snd, q.imK.snd⟩) invFun d := ⟨(d.fst.re, d.snd.re), (d.fst.imI, d.snd.imI), (d.fst.imJ, d.snd.imJ), (d.fst.imK, d.snd.imK)⟩ - left_inv := fun ⟨⟨r, rε⟩, ⟨i, iε⟩, ⟨j, jε⟩, ⟨k, kε⟩⟩ => rfl - right_inv := fun ⟨⟨r, i, j, k⟩, ⟨rε, iε, jε, kε⟩⟩ => rfl + left_inv := fun _ => rfl + right_inv := fun _ => rfl map_mul' := by - rintro ⟨⟨xr, xrε⟩, ⟨xi, xiε⟩, ⟨xj, xjε⟩, ⟨xk, xkε⟩⟩ - rintro ⟨⟨yr, yrε⟩, ⟨yi, yiε⟩, ⟨yj, yjε⟩, ⟨yk, ykε⟩⟩ + intros ext : 1 · rfl · dsimp congr 1 <;> simp <;> ring map_add' := by - rintro ⟨⟨xr, xrε⟩, ⟨xi, xiε⟩, ⟨xj, xjε⟩, ⟨xk, xkε⟩⟩ - rintro ⟨⟨yr, yrε⟩, ⟨yi, yiε⟩, ⟨yj, yjε⟩, ⟨yk, ykε⟩⟩ + intros rfl - commutes' r := rfl + commutes' _ := rfl /-! Lemmas characterizing `Quaternion.dualNumberEquiv`. -/ diff --git a/Mathlib/Algebra/EuclideanDomain/Field.lean b/Mathlib/Algebra/EuclideanDomain/Field.lean index 63d2c16a2f524..10ee495e3d968 100644 --- a/Mathlib/Algebra/EuclideanDomain/Field.lean +++ b/Mathlib/Algebra/EuclideanDomain/Field.lean @@ -20,7 +20,7 @@ instance (priority := 100) Field.toEuclideanDomain {K : Type*} [Field K] : Eucli by_cases h : b = 0 <;> simp [h, mul_div_cancel₀] r := fun a b => a = 0 ∧ b ≠ 0, r_wellFounded := - WellFounded.intro fun a => - (Acc.intro _) fun b ⟨hb, _⟩ => (Acc.intro _) fun c ⟨_, hnb⟩ => False.elim <| hnb hb, + WellFounded.intro fun _ => + (Acc.intro _) fun _ ⟨hb, _⟩ => (Acc.intro _) fun _ ⟨_, hnb⟩ => False.elim <| hnb hb, remainder_lt := fun a b hnb => by simp [hnb], - mul_left_not_lt := fun a b hnb ⟨hab, hna⟩ => Or.casesOn (mul_eq_zero.1 hab) hna hnb } + mul_left_not_lt := fun _ _ hnb ⟨hab, hna⟩ => Or.casesOn (mul_eq_zero.1 hab) hna hnb } diff --git a/Mathlib/Algebra/Exact.lean b/Mathlib/Algebra/Exact.lean index e3eb8a8116504..23d6d705097ab 100644 --- a/Mathlib/Algebra/Exact.lean +++ b/Mathlib/Algebra/Exact.lean @@ -6,7 +6,7 @@ Authors: Antoine Chambert-Loir import Mathlib.Algebra.Module.Submodule.Range import Mathlib.LinearAlgebra.Prod -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic /-! # Exactness of a pair diff --git a/Mathlib/Algebra/Expr.lean b/Mathlib/Algebra/Expr.lean index 73a6d49606b8e..df4e9330035a2 100644 --- a/Mathlib/Algebra/Expr.lean +++ b/Mathlib/Algebra/Expr.lean @@ -9,8 +9,6 @@ import Qq /-! # Helpers to invoke functions involving algebra at tactic time This file provides instances on `x y : Q($α)` such that `x + y = q($x + $y)`. - -Porting note: This has been rewritten to use `Qq` instead of `Expr`. -/ open Qq diff --git a/Mathlib/Algebra/Field/Basic.lean b/Mathlib/Algebra/Field/Basic.lean index fe9961bb0230a..989ee8b232df3 100644 --- a/Mathlib/Algebra/Field/Basic.lean +++ b/Mathlib/Algebra/Field/Basic.lean @@ -228,9 +228,9 @@ noncomputable abbrev DivisionRing.ofIsUnitOrEqZero [Ring R] (h : ∀ a : R, IsUn toRing := ‹Ring R› __ := groupWithZeroOfIsUnitOrEqZero h nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl /-- Constructs a `Field` structure on a `CommRing` consisting only of units and 0. -/ -- See note [reducible non-instances] @@ -274,9 +274,9 @@ protected abbrev divisionRing [DivisionRing L] (zero : f 0 = 0) (one : f 1 = 1) toRing := hf.ring f zero one add mul neg sub nsmul zsmul npow natCast intCast __ := hf.groupWithZero f zero one mul inv div npow zpow __ := hf.divisionSemiring f zero one add mul inv div nsmul nnqsmul npow zpow natCast nnratCast - ratCast_def q := hf <| by erw [ratCast, div, intCast, natCast, Rat.cast_def] + ratCast_def q := hf <| by rw [ratCast, div, intCast, natCast, Rat.cast_def] qsmul := (· • ·) - qsmul_def q a := hf <| by erw [qsmul, mul, Rat.smul_def, ratCast] + qsmul_def q a := hf <| by rw [qsmul, mul, Rat.smul_def, ratCast] /-- Pullback a `Field` along an injective function. -/ -- See note [reducible non-instances] diff --git a/Mathlib/Algebra/Field/Defs.lean b/Mathlib/Algebra/Field/Defs.lean index 46e889528e3e6..4bb07df74d908 100644 --- a/Mathlib/Algebra/Field/Defs.lean +++ b/Mathlib/Algebra/Field/Defs.lean @@ -194,7 +194,7 @@ variable (K) end NNRat namespace Rat -variable [DivisionRing K] {a b : K} +variable [DivisionRing K] lemma cast_def (q : ℚ) : (q : K) = q.num / q.den := DivisionRing.ratCast_def _ diff --git a/Mathlib/Algebra/Field/IsField.lean b/Mathlib/Algebra/Field/IsField.lean index a3d3847cbc41f..e9b67d20db248 100644 --- a/Mathlib/Algebra/Field/IsField.lean +++ b/Mathlib/Algebra/Field/IsField.lean @@ -62,13 +62,13 @@ noncomputable def IsField.toSemifield {R : Type u} [Semiring R] (h : IsField R) inv_zero := dif_pos rfl mul_inv_cancel a ha := by convert Classical.choose_spec (h.mul_inv_cancel ha); exact dif_neg ha nnqsmul := _ - nnqsmul_def q a := rfl + nnqsmul_def _ _ := rfl /-- Transferring from `IsField` to `Field`. -/ noncomputable def IsField.toField {R : Type u} [Ring R] (h : IsField R) : Field R := { ‹Ring R›, IsField.toSemifield h with qsmul := _ - qsmul_def := fun q a => rfl } + qsmul_def := fun _ _ => rfl } /-- For each field, and for each nonzero element of said field, there is a unique inverse. Since `IsField` doesn't remember the data of an `inv` function and as such, diff --git a/Mathlib/Algebra/Field/MinimalAxioms.lean b/Mathlib/Algebra/Field/MinimalAxioms.lean index b80f40d16d801..17bc0cba5c298 100644 --- a/Mathlib/Algebra/Field/MinimalAxioms.lean +++ b/Mathlib/Algebra/Field/MinimalAxioms.lean @@ -42,6 +42,6 @@ abbrev Field.ofMinimalAxioms (K : Type u) mul_inv_cancel := mul_inv_cancel inv_zero := inv_zero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl } + qsmul_def := fun _ _ => rfl } diff --git a/Mathlib/Algebra/Field/Opposite.lean b/Mathlib/Algebra/Field/Opposite.lean index 99f0c22d73388..b5e42f500972c 100644 --- a/Mathlib/Algebra/Field/Opposite.lean +++ b/Mathlib/Algebra/Field/Opposite.lean @@ -34,7 +34,7 @@ instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring αᵐᵒ __ := instSemiring __ := instGroupWithZero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl nnratCast_def q := unop_injective <| by rw [unop_nnratCast, unop_div, unop_natCast, unop_natCast, NNRat.cast_def, div_eq_mul_inv, Nat.cast_comm] @@ -42,7 +42,7 @@ instance instDivisionRing [DivisionRing α] : DivisionRing αᵐᵒᵖ where __ := instRing __ := instDivisionSemiring qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl ratCast_def q := unop_injective <| by rw [unop_ratCast, Rat.cast_def, unop_div, unop_natCast, unop_intCast, Int.commute_cast, div_eq_mul_inv] @@ -62,7 +62,7 @@ instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring αᵃᵒ __ := instSemiring __ := instGroupWithZero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl nnratCast_def q := unop_injective <| by rw [unop_nnratCast, unop_div, unop_natCast, unop_natCast, NNRat.cast_def, div_eq_mul_inv] @@ -70,7 +70,7 @@ instance instDivisionRing [DivisionRing α] : DivisionRing αᵃᵒᵖ where __ := instRing __ := instDivisionSemiring qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl ratCast_def q := unop_injective <| by rw [unop_ratCast, Rat.cast_def, unop_div, unop_natCast, unop_intCast, div_eq_mul_inv] diff --git a/Mathlib/Algebra/Field/Rat.lean b/Mathlib/Algebra/Field/Rat.lean index fa3f4d1154ec5..ad60ac2ab4bb0 100644 --- a/Mathlib/Algebra/Field/Rat.lean +++ b/Mathlib/Algebra/Field/Rat.lean @@ -13,11 +13,6 @@ This file contains the field instance on the rational numbers. See note [foundational algebra order theory]. -## TODO - -Move the `Semifield ℚ≥0` instance here. This will involve proving it by hand rather than relying on -the `Nonneg` machinery. - ## Tags rat, rationals, field, ℚ, numerator, denominator, num, denom @@ -29,12 +24,12 @@ instance instField : Field ℚ where __ := commRing __ := commGroupWithZero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl nnratCast_def q := by rw [← NNRat.den_coe, ← Int.cast_natCast q.num, ← NNRat.num_coe]; exact(num_div_den _).symm - ratCast_def q := (num_div_den _).symm + ratCast_def _ := (num_div_den _).symm /-! ### Extra instances to short-circuit type class resolution @@ -44,4 +39,51 @@ These also prevent non-computable instances being used to construct these instan instance instDivisionRing : DivisionRing ℚ := inferInstance +protected lemma inv_nonneg {a : ℚ} (ha : 0 ≤ a) : 0 ≤ a⁻¹ := by + rw [inv_def'] + exact divInt_nonneg (Int.ofNat_nonneg a.den) (num_nonneg.mpr ha) + +protected lemma div_nonneg {a b : ℚ} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a / b := + mul_nonneg ha (Rat.inv_nonneg hb) + end Rat + +namespace NNRat + +instance instInv : Inv ℚ≥0 where + inv x := ⟨x⁻¹, Rat.inv_nonneg x.2⟩ + +instance instDiv : Div ℚ≥0 where + div x y := ⟨x / y, Rat.div_nonneg x.2 y.2⟩ + +@[simp, norm_cast] lemma coe_inv (q : ℚ≥0) : ((q⁻¹ : ℚ≥0) : ℚ) = (q : ℚ)⁻¹ := rfl +@[simp, norm_cast] lemma coe_div (p q : ℚ≥0) : ((p / q : ℚ≥0) : ℚ) = p / q := rfl + +lemma inv_def (q : ℚ≥0) : q⁻¹ = divNat q.den q.num := by ext; simp [Rat.inv_def', num_coe, den_coe] +lemma div_def (p q : ℚ≥0) : p / q = divNat (p.num * q.den) (p.den * q.num) := by + ext; simp [Rat.div_def', num_coe, den_coe] + +lemma num_inv_of_ne_zero {q : ℚ≥0} (hq : q ≠ 0) : q⁻¹.num = q.den := by + rw [inv_def, divNat, num, coe_mk, Rat.divInt_ofNat, ← Rat.mk_eq_mkRat _ _ (num_ne_zero.mpr hq), + Int.natAbs_ofNat] + simpa using q.coprime_num_den.symm + +lemma den_inv_of_ne_zero {q : ℚ≥0} (hq : q ≠ 0) : q⁻¹.den = q.num := by + rw [inv_def, divNat, den, coe_mk, Rat.divInt_ofNat, ← Rat.mk_eq_mkRat _ _ (num_ne_zero.mpr hq)] + simpa using q.coprime_num_den.symm + +@[simp] +lemma num_div_den (q : ℚ≥0) : (q.num : ℚ≥0) / q.den = q := by + ext1 + rw [coe_div, coe_natCast, coe_natCast, num, ← Int.cast_natCast] + exact (cast_def _).symm + +instance instSemifield : Semifield ℚ≥0 where + __ := instNNRatCommSemiring + inv_zero := by ext; simp + mul_inv_cancel q h := by ext; simp [h] + nnratCast_def q := q.num_div_den.symm + nnqsmul q a := q * a + nnqsmul_def q a := rfl + +end NNRat diff --git a/Mathlib/Algebra/Field/Subfield.lean b/Mathlib/Algebra/Field/Subfield.lean index 30b6731d7f52c..c1d8534cddfbe 100644 --- a/Mathlib/Algebra/Field/Subfield.lean +++ b/Mathlib/Algebra/Field/Subfield.lean @@ -176,7 +176,6 @@ instance : SubfieldClass (Subfield K) K where one_mem s := s.one_mem' inv_mem {s} := s.inv_mem' _ --- @[simp] -- Porting note (#10618): simp can prove this (with `coe_toSubring`, which comes later) theorem mem_carrier {s : Subfield K} {x : K} : x ∈ s.carrier ↔ x ∈ s := Iff.rfl @@ -373,7 +372,6 @@ theorem toSubring_subtype_eq_subtype (S : Subfield K) : /-! # Partial order -/ ---@[simp] -- Porting note (#10618): simp can prove this theorem mem_toSubmonoid {s : Subfield K} {x : K} : x ∈ s.toSubmonoid ↔ x ∈ s := Iff.rfl @@ -873,3 +871,69 @@ theorem comap_map (f : K →+* L) (s : Subfield K) : (s.map f).comap f = s := SetLike.coe_injective (Set.preimage_image_eq _ f.injective) end Subfield + +/-! ## Actions by `Subfield`s + +These are just copies of the definitions about `Subsemiring` starting from +`Subsemiring.MulAction`. +-/ +section Actions + +namespace Subfield + +variable {X Y} + +/-- The action by a subfield is the action by the underlying field. -/ +instance [SMul K X] (F : Subfield K) : SMul F X := + inferInstanceAs (SMul F.toSubsemiring X) + +theorem smul_def [SMul K X] {F : Subfield K} (g : F) (m : X) : g • m = (g : K) • m := + rfl + +instance smulCommClass_left [SMul K Y] [SMul X Y] [SMulCommClass K X Y] (F : Subfield K) : + SMulCommClass F X Y := + inferInstanceAs (SMulCommClass F.toSubsemiring X Y) + +instance smulCommClass_right [SMul X Y] [SMul K Y] [SMulCommClass X K Y] (F : Subfield K) : + SMulCommClass X F Y := + inferInstanceAs (SMulCommClass X F.toSubsemiring Y) + +/-- Note that this provides `IsScalarTower F K K` which is needed by `smul_mul_assoc`. -/ +instance [SMul X Y] [SMul K X] [SMul K Y] [IsScalarTower K X Y] (F : Subfield K) : + IsScalarTower F X Y := + inferInstanceAs (IsScalarTower F.toSubsemiring X Y) + +instance [SMul K X] [FaithfulSMul K X] (F : Subfield K) : FaithfulSMul F X := + inferInstanceAs (FaithfulSMul F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [MulAction K X] (F : Subfield K) : MulAction F X := + inferInstanceAs (MulAction F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [AddMonoid X] [DistribMulAction K X] (F : Subfield K) : DistribMulAction F X := + inferInstanceAs (DistribMulAction F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [Monoid X] [MulDistribMulAction K X] (F : Subfield K) : MulDistribMulAction F X := + inferInstanceAs (MulDistribMulAction F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [Zero X] [SMulWithZero K X] (F : Subfield K) : SMulWithZero F X := + inferInstanceAs (SMulWithZero F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [Zero X] [MulActionWithZero K X] (F : Subfield K) : MulActionWithZero F X := + inferInstanceAs (MulActionWithZero F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [AddCommMonoid X] [Module K X] (F : Subfield K) : Module F X := + inferInstanceAs (Module F.toSubsemiring X) + +/-- The action by a subfield is the action by the underlying field. -/ +instance [Semiring X] [MulSemiringAction K X] (F : Subfield K) : MulSemiringAction F X := + inferInstanceAs (MulSemiringAction F.toSubsemiring X) + +end Subfield + +end Actions diff --git a/Mathlib/Algebra/Field/ULift.lean b/Mathlib/Algebra/Field/ULift.lean index ccb6baccbc575..215b218b67831 100644 --- a/Mathlib/Algebra/Field/ULift.lean +++ b/Mathlib/Algebra/Field/ULift.lean @@ -15,8 +15,8 @@ This file defines instances for field, semifield and related structures on `ULif (Recall `ULift α` is just a "copy" of a type `α` in a higher universe.) -/ -universe u v -variable {α : Type u} {x y : ULift.{v} α} +universe u +variable {α : Type u} namespace ULift diff --git a/Mathlib/Algebra/Free.lean b/Mathlib/Algebra/Free.lean index 134a4e81ed9ff..78cdb51b06d87 100644 --- a/Mathlib/Algebra/Free.lean +++ b/Mathlib/Algebra/Free.lean @@ -105,9 +105,9 @@ variable {α : Type u} {β : Type v} [Mul β] (f : α → β) def lift : (α → β) ≃ (FreeMagma α →ₙ* β) where toFun f := { toFun := liftAux f - map_mul' := fun x y ↦ rfl } + map_mul' := fun _ _ ↦ rfl } invFun F := F ∘ of - left_inv f := rfl + left_inv _ := rfl right_inv F := by ext; rfl @[to_additive (attr := simp)] @@ -173,8 +173,8 @@ theorem mul_seq {α β : Type u} {f g : FreeMagma (α → β)} {x : FreeMagma α @[to_additive] instance instLawfulMonad : LawfulMonad FreeMagma.{u} := LawfulMonad.mk' - (pure_bind := fun f x ↦ rfl) - (bind_assoc := fun x f g ↦ FreeMagma.recOnPure x (fun x ↦ rfl) fun x y ih1 ih2 ↦ by + (pure_bind := fun _ _ ↦ rfl) + (bind_assoc := fun x f g ↦ FreeMagma.recOnPure x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [mul_bind, mul_bind, mul_bind, ih1, ih2]) (id_map := fun x ↦ FreeMagma.recOnPure x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [map_mul', ih1, ih2]) @@ -239,7 +239,7 @@ theorem mul_map_seq (x y : FreeMagma α) : instance : LawfulTraversable FreeMagma.{u} := { instLawfulMonad with id_traverse := fun x ↦ - FreeMagma.recOnPure x (fun x ↦ rfl) fun x y ih1 ih2 ↦ by + FreeMagma.recOnPure x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [traverse_mul, ih1, ih2, mul_map_seq] comp_traverse := fun f g x ↦ FreeMagma.recOnPure x @@ -260,7 +260,6 @@ end Category end FreeMagma --- Porting note: changed String to Lean.Format #adaptation_note /-- around nightly-2024-02-25, we need to write `mul x y` in the second pattern, instead of `x * y`. -/ /-- Representation of an element of a free magma. -/ @@ -373,8 +372,8 @@ def lift : (α →ₙ* β) ≃ (AssocQuotient α →ₙ* β) where Quot.liftOn x f <| by rintro a b (⟨c, d, e⟩ | ⟨c, d, e, f⟩) <;> simp only [map_mul, mul_assoc] map_mul' := fun x y ↦ Quot.induction_on₂ x y (map_mul f) } invFun f := f.comp of - left_inv f := (DFunLike.ext _ _) fun x ↦ rfl - right_inv f := hom_ext <| (DFunLike.ext _ _) fun x ↦ rfl + left_inv _ := (DFunLike.ext _ _) fun _ ↦ rfl + right_inv _ := hom_ext <| (DFunLike.ext _ _) fun _ ↦ rfl @[to_additive (attr := simp)] theorem lift_of (x : α) : lift f (of x) = f x := rfl @@ -483,8 +482,8 @@ def lift : (α → β) ≃ (FreeSemigroup α →ₙ* β) where simp [head_mul, tail_mul, ← List.foldl_map, List.foldl_append, List.foldl_cons, List.foldl_assoc] } invFun f := f ∘ of - left_inv f := rfl - right_inv f := hom_ext rfl + left_inv _ := rfl + right_inv _ := hom_ext rfl @[to_additive (attr := simp)] theorem lift_of (x : α) : lift f (of x) = f x := rfl @@ -514,7 +513,7 @@ theorem map_of (x) : map f (of x) = of (f x) := rfl @[to_additive (attr := simp)] theorem length_map (x) : (map f x).length = x.length := - FreeSemigroup.recOnMul x (fun x ↦ rfl) (fun x y hx hy ↦ by simp only [map_mul, length_mul, *]) + FreeSemigroup.recOnMul x (fun _ ↦ rfl) (fun x y hx hy ↦ by simp only [map_mul, length_mul, *]) end Map @@ -558,7 +557,7 @@ theorem mul_seq {f g : FreeSemigroup (α → β)} {x : FreeSemigroup α} : instance instLawfulMonad : LawfulMonad FreeSemigroup.{u} := LawfulMonad.mk' (pure_bind := fun _ _ ↦ rfl) (bind_assoc := fun x g f ↦ - recOnPure x (fun x ↦ rfl) fun x y ih1 ih2 ↦ by rw [mul_bind, mul_bind, mul_bind, ih1, ih2]) + recOnPure x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [mul_bind, mul_bind, mul_bind, ih1, ih2]) (id_map := fun x ↦ recOnPure x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [map_mul', ih1, ih2]) /-- `FreeSemigroup` is traversable. -/ @@ -587,7 +586,7 @@ theorem traverse_mul (x y : FreeSemigroup α) : traverse F (x * y) = (· * ·) <$> traverse F x <*> traverse F y := let ⟨x, L1⟩ := x let ⟨y, L2⟩ := y - List.recOn L1 (fun x ↦ rfl) + List.recOn L1 (fun _ ↦ rfl) (fun hd tl ih x ↦ show (· * ·) <$> pure <$> F x <*> traverse F (mk hd tl * mk y L2) = (· * ·) <$> ((· * ·) <$> pure <$> F x <*> traverse F (mk hd tl)) <*> traverse F (mk y L2) @@ -614,7 +613,7 @@ theorem mul_map_seq (x y : FreeSemigroup α) : instance : LawfulTraversable FreeSemigroup.{u} := { instLawfulMonad with id_traverse := fun x ↦ - FreeSemigroup.recOnMul x (fun x ↦ rfl) fun x y ih1 ih2 ↦ by + FreeSemigroup.recOnMul x (fun _ ↦ rfl) fun x y ih1 ih2 ↦ by rw [traverse_mul, ih1, ih2, mul_map_seq] comp_traverse := fun f g x ↦ recOnPure x (fun x ↦ by simp only [traverse_pure, functor_norm, Function.comp_def]) @@ -661,7 +660,7 @@ theorem toFreeSemigroup_map (f : α → β) (x : FreeMagma α) : @[to_additive (attr := simp)] theorem length_toFreeSemigroup (x : FreeMagma α) : (toFreeSemigroup x).length = x.length := - FreeMagma.recOnMul x (fun x ↦ rfl) fun x y hx hy ↦ by + FreeMagma.recOnMul x (fun _ ↦ rfl) fun x y hx hy ↦ by rw [map_mul, FreeSemigroup.length_mul, hx, hy]; rfl end FreeMagma diff --git a/Mathlib/Algebra/FreeMonoid/Basic.lean b/Mathlib/Algebra/FreeMonoid/Basic.lean index 9f12ab8a83686..412668ee82a6c 100644 --- a/Mathlib/Algebra/FreeMonoid/Basic.lean +++ b/Mathlib/Algebra/FreeMonoid/Basic.lean @@ -5,7 +5,7 @@ Authors: Simon Hudon, Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.Group.List import Mathlib.Algebra.Group.Action.Defs -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic /-! # Free monoid over a given alphabet @@ -67,6 +67,9 @@ instance : CancelMonoid (FreeMonoid α) where @[to_additive] instance : Inhabited (FreeMonoid α) := ⟨1⟩ +@[to_additive] +instance [IsEmpty α] : Unique (FreeMonoid α) := inferInstanceAs <| Unique (List α) + @[to_additive (attr := simp)] theorem toList_one : toList (1 : FreeMonoid α) = [] := rfl @@ -106,6 +109,72 @@ theorem toList_of_mul (x : α) (xs : FreeMonoid α) : toList (of x * xs) = x :: @[to_additive] theorem of_injective : Function.Injective (@of α) := List.singleton_injective +/-! ### Length -/ + +section Length +variable {a : FreeMonoid α} + +/-- The length of a free monoid element: 1.length = 0 and (a * b).length = a.length + b.length -/ +@[to_additive "The length of an additive free monoid element: 1.length = 0 and (a + b).length = + a.length + b.length"] +def length (a : FreeMonoid α) : ℕ := List.length a + +@[to_additive (attr := simp)] +theorem length_one : length (1 : FreeMonoid α) = 0 := rfl + +@[to_additive (attr := simp)] +theorem length_eq_zero : length a = 0 ↔ a = 1 := List.length_eq_zero + +@[to_additive (attr := simp)] +theorem length_of (m : α) : length (of m) = 1 := rfl + +@[to_additive existing] +theorem length_eq_one : length a = 1 ↔ ∃ m, a = FreeMonoid.of m := + List.length_eq_one + +@[to_additive] +theorem length_eq_two {v : FreeMonoid α} : + v.length = 2 ↔ ∃ c d, v = FreeMonoid.of c * FreeMonoid.of d := List.length_eq_two + +@[to_additive (attr := simp)] +theorem length_mul (a b : FreeMonoid α) : (a * b).length = a.length + b.length := + List.length_append _ _ + +@[to_additive (attr := simp)] +theorem of_ne_one (a : α) : of a ≠ 1 := by + intro h + have := congrArg FreeMonoid.length h + simp only [length_of, length_one, Nat.succ_ne_self] at this + +@[to_additive (attr := simp)] +theorem one_ne_of (a : α) : 1 ≠ of a := of_ne_one _ |>.symm + +end Length + +section Mem +variable {m : α} + +/-- Membership in a free monoid element -/ +@[to_additive "Membership in a free monoid element"] +def mem (a : FreeMonoid α) (m : α) := m ∈ toList a + +@[to_additive] +instance : Membership α (FreeMonoid α) := ⟨mem⟩ + +@[to_additive] +theorem not_mem_one : ¬ m ∈ (1 : FreeMonoid α) := List.not_mem_nil _ + +@[to_additive (attr := simp)] +theorem mem_of {n : α} : m ∈ of n ↔ m = n := List.mem_singleton + +@[to_additive] +theorem mem_of_self : m ∈ of m := List.mem_singleton_self _ + +@[to_additive (attr := simp)] +theorem mem_mul {a b : FreeMonoid α} : m ∈ (a * b) ↔ m ∈ a ∨ m ∈ b := List.mem_append + +end Mem + /-- Recursor for `FreeMonoid` using `1` and `FreeMonoid.of x * xs` instead of `[]` and `x :: xs`. -/ @[to_additive (attr := elab_as_elim, induction_eliminator) "Recursor for `FreeAddMonoid` using `0` and @@ -123,6 +192,27 @@ theorem recOn_of_mul {C : FreeMonoid α → Sort*} (x : α) (xs : FreeMonoid α) (ih : ∀ x xs, C xs → C (of x * xs)) : @recOn α C (of x * xs) h0 ih = ih x xs (recOn xs h0 ih) := rfl +/-! ### Induction -/ + +section induction_principles + +/-- An induction principle on free monoids, with cases for `1`, `FreeMonoid.of` and `*`. -/ +@[to_additive (attr := elab_as_elim, induction_eliminator) +"An induction principle on free monoids, with cases for `0`, `FreeAddMonoid.of` and `+`."] +protected theorem inductionOn {C : FreeMonoid α → Prop} (z : FreeMonoid α) (one : C 1) + (of : ∀ (x : α), C (FreeMonoid.of x)) (mul : ∀ (x y : FreeMonoid α), C x → C y → C (x * y)) : + C z := List.rec one (fun _ _ ih => mul [_] _ (of _) ih) z + +/-- An induction principle for free monoids which mirrors induction on lists, with cases analogous +to the empty list and cons -/ +@[to_additive (attr := elab_as_elim) "An induction principle for free monoids which mirrors +induction on lists, with cases analogous to the empty list and cons"] +protected theorem inductionOn' {p : FreeMonoid α → Prop} (a : FreeMonoid α) + (one : p (1 : FreeMonoid α)) (mul_of : ∀ b a, p a → p (of b * a)) : p a := + List.rec one (fun _ _ tail_ih => mul_of _ _ tail_ih) a + +end induction_principles + /-- A version of `List.cases_on` for `FreeMonoid` using `1` and `FreeMonoid.of x * xs` instead of `[]` and `x :: xs`. -/ @[to_additive (attr := elab_as_elim, cases_eliminator) @@ -155,7 +245,7 @@ def prodAux {M} [Monoid M] : List M → M @[to_additive] lemma prodAux_eq : ∀ l : List M, FreeMonoid.prodAux l = l.prod | [] => rfl - | (_ :: xs) => congr_arg (fun x => List.foldl (· * ·) x xs) (one_mul _).symm + | (_ :: xs) => by simp [prodAux, List.prod_eq_foldl] /-- Equivalence between maps `α → M` and monoid homomorphisms `FreeMonoid α →* M`. -/ @[to_additive "Equivalence between maps `α → A` and additive monoid homomorphisms @@ -166,8 +256,8 @@ def lift : (α → M) ≃ (FreeMonoid α →* M) where map_one' := rfl map_mul' := fun _ _ ↦ by simp only [prodAux_eq, toList_mul, List.map_append, List.prod_append] } invFun f x := f (of x) - left_inv f := rfl - right_inv f := hom_eq fun x ↦ rfl + left_inv _ := rfl + right_inv _ := hom_eq fun _ ↦ rfl @[to_additive (attr := simp)] theorem lift_ofList (f : α → M) (l : List α) : lift f (ofList l) = (l.map f).prod := @@ -220,6 +310,10 @@ theorem of_smul (f : α → β → β) (x : α) (y : β) : (haveI := mkMulAction f of x • y) = f x y := rfl +/-! ### map -/ + +section Map +variable {f : α → β} {a b : FreeMonoid α} /-- The unique monoid homomorphism `FreeMonoid α →* FreeMonoid β` that sends each `of x` to `of (f x)`. -/ @[to_additive "The unique additive monoid homomorphism `FreeAddMonoid α →+ FreeAddMonoid β` @@ -232,6 +326,15 @@ def map (f : α → β) : FreeMonoid α →* FreeMonoid β where @[to_additive (attr := simp)] theorem map_of (f : α → β) (x : α) : map f (of x) = of (f x) := rfl +@[to_additive] +theorem mem_map {m : β} : m ∈ map f a ↔ ∃ n ∈ a, f n = m := List.mem_map + +@[to_additive] +theorem map_map {α₁ : Type*} {g : α₁ → α} {x : FreeMonoid α₁} : + map f (map g x) = map (f ∘ g) x := by + unfold map + simp only [MonoidHom.coe_mk, OneHom.coe_mk, toList_ofList, List.map_map] + @[to_additive] theorem toList_map (f : α → β) (xs : FreeMonoid α) : toList (map f xs) = xs.toList.map f := rfl @@ -254,4 +357,54 @@ instance uniqueUnits : Unique (FreeMonoid α)ˣ where have : toList u.val ++ toList u.inv = [] := DFunLike.congr_arg toList u.val_inv (List.append_eq_nil.mp this).1 +@[to_additive (attr := simp)] +theorem map_surjective {f : α → β} : Function.Surjective (map f) ↔ Function.Surjective f := by + constructor + · intro fs d + rcases fs (FreeMonoid.of d) with ⟨b, hb⟩ + induction' b using FreeMonoid.inductionOn' with head _ _ + · have H := congr_arg length hb + simp only [length_one, length_of, Nat.zero_ne_one, map_one] at H + simp only [map_mul, map_of] at hb + use head + have H := congr_arg length hb + simp only [length_mul, length_of, add_right_eq_self, length_eq_zero] at H + rw [H, mul_one] at hb + exact FreeMonoid.of_injective hb + intro fs d + induction' d using FreeMonoid.inductionOn' with head tail ih + · use 1 + rfl + specialize fs head + rcases fs with ⟨a, rfl⟩ + rcases ih with ⟨b, rfl⟩ + use FreeMonoid.of a * b + rfl + +end Map + +/-! ### reverse -/ + +section Reverse +/-- reverses the symbols in a free monoid element -/ +@[to_additive "reverses the symbols in an additive free monoid element"] +def reverse : FreeMonoid α → FreeMonoid α := List.reverse + +@[to_additive (attr := simp)] +theorem reverse_of (a : α) : reverse (of a) = of a := rfl + +@[to_additive] +theorem reverse_mul {a b : FreeMonoid α} : reverse (a * b) = reverse b * reverse a := + List.reverse_append _ _ + +@[to_additive (attr := simp)] +theorem reverse_reverse {a : FreeMonoid α} : reverse (reverse a) = a := by + apply List.reverse_reverse + +@[to_additive (attr := simp)] +theorem length_reverse {a : FreeMonoid α} : a.reverse.length = a.length := + List.length_reverse _ + +end Reverse + end FreeMonoid diff --git a/Mathlib/Algebra/FreeMonoid/Symbols.lean b/Mathlib/Algebra/FreeMonoid/Symbols.lean new file mode 100644 index 0000000000000..c387561d37f6c --- /dev/null +++ b/Mathlib/Algebra/FreeMonoid/Symbols.lean @@ -0,0 +1,39 @@ +/- +Copyright (c) 2024 Hannah Fechtner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Hannah Fechtner +-/ + +import Mathlib.Algebra.FreeMonoid.Basic +import Mathlib.Data.Finset.Basic + +/-! +# The finite set of symbols in a FreeMonoid element + +This is separated from the main FreeMonoid file, as it imports the finiteness hierarchy +-/ + +variable {α : Type*} [DecidableEq α] + +namespace FreeMonoid + +/-- the set of unique symbols in a free monoid element -/ +@[to_additive "The set of unique symbols in an additive free monoid element"] +def symbols (a : FreeMonoid α) : Finset α := List.toFinset a + +@[to_additive (attr := simp)] +theorem symbols_one : symbols (1 : FreeMonoid α) = ∅ := rfl + +@[to_additive (attr := simp)] +theorem symbols_of {m : α} : symbols (of m) = {m} := rfl + +@[to_additive (attr := simp)] +theorem symbols_mul {a b : FreeMonoid α} : symbols (a * b) = symbols a ∪ symbols b := by + simp only [symbols, List.mem_toFinset, Finset.mem_union] + apply List.toFinset_append + +@[to_additive (attr := simp)] +theorem mem_symbols {m : α} {a : FreeMonoid α} : m ∈ symbols a ↔ m ∈ a := + List.mem_toFinset + +end FreeMonoid diff --git a/Mathlib/Algebra/GCDMonoid/Basic.lean b/Mathlib/Algebra/GCDMonoid/Basic.lean index fee781f192238..1eb6be1251a77 100644 --- a/Mathlib/Algebra/GCDMonoid/Basic.lean +++ b/Mathlib/Algebra/GCDMonoid/Basic.lean @@ -89,7 +89,6 @@ variable [CancelCommMonoidWithZero α] [NormalizationMonoid α] theorem normUnit_one : normUnit (1 : α) = 1 := normUnit_coe_units 1 --- Porting note (#11083): quite slow. Improve performance? /-- Chooses an element of each associate class, by multiplying by `normUnit` -/ def normalize : α →*₀ α where toFun x := x * normUnit x @@ -117,21 +116,16 @@ theorem normalize_associated_iff {x y : α} : Associated (normalize x) y ↔ Ass theorem Associates.mk_normalize (x : α) : Associates.mk (normalize x) = Associates.mk x := Associates.mk_eq_mk_iff_associated.2 (normalize_associated _) -@[simp] theorem normalize_apply (x : α) : normalize x = x * normUnit x := rfl --- Porting note (#10618): `simp` can prove this --- @[simp] theorem normalize_zero : normalize (0 : α) = 0 := normalize.map_zero --- Porting note (#10618): `simp` can prove this --- @[simp] theorem normalize_one : normalize (1 : α) = 1 := normalize.map_one -theorem normalize_coe_units (u : αˣ) : normalize (u : α) = 1 := by simp +theorem normalize_coe_units (u : αˣ) : normalize (u : α) = 1 := by simp [normalize_apply] theorem normalize_eq_zero {x : α} : normalize x = 0 ↔ x = 0 := ⟨fun hx => (associated_zero_iff_eq_zero x).1 <| hx ▸ associated_normalize _, by @@ -148,7 +142,8 @@ theorem normUnit_mul_normUnit (a : α) : normUnit (a * normUnit a) = 1 := by · rw [normUnit_zero, zero_mul, normUnit_zero] · rw [normUnit_mul h (Units.ne_zero _), normUnit_coe_units, mul_inv_eq_one] -theorem normalize_idem (x : α) : normalize (normalize x) = normalize x := by simp +@[simp] +theorem normalize_idem (x : α) : normalize (normalize x) = normalize x := by simp [normalize_apply] theorem normalize_eq_normalize {a b : α} (hab : a ∣ b) (hba : b ∣ a) : normalize a = normalize b := by @@ -174,11 +169,11 @@ theorem Associated.eq_of_normalized a = b := dvd_antisymm_of_normalize_eq ha hb h.dvd h.dvd' ---can be proven by simp +@[simp] theorem dvd_normalize_iff {a b : α} : a ∣ normalize b ↔ a ∣ b := Units.dvd_mul_right ---can be proven by simp +@[simp] theorem normalize_dvd_iff {a b : α} : normalize a ∣ b ↔ a ∣ b := Units.mul_right_dvd @@ -217,8 +212,7 @@ theorem out_dvd_iff (a : α) (b : Associates α) : b.out ∣ a ↔ b ≤ Associa theorem out_top : (⊤ : Associates α).out = 0 := normalize_zero --- Porting note: lower priority to avoid linter complaints about simp-normal form -@[simp 1100] +@[simp] theorem normalize_out (a : Associates α) : normalize a.out = a.out := Quotient.inductionOn a normalize_idem @@ -288,8 +282,7 @@ theorem gcd_isUnit_iff_isRelPrime [GCDMonoid α] {a b : α} : IsUnit (gcd a b) ↔ IsRelPrime a b := ⟨fun h _ ha hb ↦ isUnit_of_dvd_unit (dvd_gcd ha hb) h, (· (gcd_dvd_left a b) (gcd_dvd_right a b))⟩ --- Porting note: lower priority to avoid linter complaints about simp-normal form -@[simp 1100] +@[simp] theorem normalize_gcd [NormalizedGCDMonoid α] : ∀ a b : α, normalize (gcd a b) = gcd a b := NormalizedGCDMonoid.normalize_gcd @@ -400,7 +393,7 @@ theorem gcd_mul_left [NormalizedGCDMonoid α] (a b c : α) : gcd (a * b) (a * c) = normalize a * gcd b c := (by_cases (by rintro rfl; simp only [zero_mul, gcd_zero_left, normalize_zero])) fun ha : a ≠ 0 => - suffices gcd (a * b) (a * c) = normalize (a * gcd b c) by simpa [- normalize_apply] + suffices gcd (a * b) (a * c) = normalize (a * gcd b c) by simpa let ⟨d, eq⟩ := dvd_gcd (dvd_mul_right a b) (dvd_mul_right a c) gcd_eq_normalize (eq.symm ▸ mul_dvd_mul_left a @@ -690,8 +683,7 @@ theorem lcm_eq_zero_iff [GCDMonoid α] (a b : α) : lcm a b = 0 ↔ a = 0 ∨ b rwa [← mul_eq_zero, ← associated_zero_iff_eq_zero]) (by rintro (rfl | rfl) <;> [apply lcm_zero_left; apply lcm_zero_right]) --- Porting note: lower priority to avoid linter complaints about simp-normal form -@[simp 1100] +@[simp] theorem normalize_lcm [NormalizedGCDMonoid α] (a b : α) : normalize (lcm a b) = lcm a b := NormalizedGCDMonoid.normalize_lcm a b @@ -767,9 +759,9 @@ theorem lcm_mul_left [NormalizedGCDMonoid α] (a b c : α) : lcm (a * b) (a * c) = normalize a * lcm b c := (by_cases (by rintro rfl; simp only [zero_mul, lcm_zero_left, normalize_zero])) fun ha : a ≠ 0 => - suffices lcm (a * b) (a * c) = normalize (a * lcm b c) by simpa [- normalize_apply] + suffices lcm (a * b) (a * c) = normalize (a * lcm b c) by simpa have : a ∣ lcm (a * b) (a * c) := (dvd_mul_right _ _).trans (dvd_lcm_left _ _) - let ⟨d, eq⟩ := this + let ⟨_, eq⟩ := this lcm_eq_normalize (lcm_dvd (mul_dvd_mul_left a (dvd_lcm_left _ _)) (mul_dvd_mul_left a (dvd_lcm_right _ _))) (eq.symm ▸ @@ -867,8 +859,7 @@ instance subsingleton_normalizedGCDMonoid_of_unique_units : Subsingleton (Normal theorem normUnit_eq_one (x : α) : normUnit x = 1 := rfl --- Porting note (#10618): `simp` can prove this --- @[simp] +@[simp] theorem normalize_eq (x : α) : normalize x = x := mul_one x @@ -953,7 +944,7 @@ noncomputable def gcdMonoidOfGCD [DecidableEq α] (gcd : α → α → α) { gcd gcd_dvd_left gcd_dvd_right - dvd_gcd := fun {a b c} => dvd_gcd + dvd_gcd := fun {_ _ _} => dvd_gcd lcm := fun a b => if a = 0 then 0 else Classical.choose ((gcd_dvd_left a b).trans (Dvd.intro b rfl)) gcd_mul_lcm := fun a b => by @@ -962,7 +953,7 @@ noncomputable def gcdMonoidOfGCD [DecidableEq α] (gcd : α → α → α) split_ifs with a0 · rw [mul_zero, a0, zero_mul] · rw [← Classical.choose_spec ((gcd_dvd_left a b).trans (Dvd.intro b rfl))] - lcm_zero_left := fun a => if_pos rfl + lcm_zero_left := fun _ => if_pos rfl lcm_zero_right := fun a => by -- Porting note(#12129): additional beta reduction needed beta_reduce @@ -985,7 +976,7 @@ noncomputable def normalizedGCDMonoidOfGCD [NormalizationMonoid α] [DecidableEq gcd gcd_dvd_left gcd_dvd_right - dvd_gcd := fun {a b c} => dvd_gcd + dvd_gcd := fun {_ _ _} => dvd_gcd normalize_gcd lcm := fun a b => if a = 0 then 0 @@ -1023,7 +1014,7 @@ noncomputable def normalizedGCDMonoidOfGCD [NormalizationMonoid α] [DecidableEq · rw [← Classical.choose_spec (dvd_normalize_iff.2 ((gcd_dvd_left a b).trans (Dvd.intro b rfl)))] exact normalize_associated (a * b) - lcm_zero_left := fun a => if_pos rfl + lcm_zero_left := fun _ => if_pos rfl lcm_zero_right := fun a => by -- Porting note(#12129): additional beta reduction needed beta_reduce @@ -1054,8 +1045,8 @@ noncomputable def gcdMonoidOfLCM [DecidableEq α] (lcm : α → α → α) · rw [h, eq_zero_of_zero_dvd (dvd_lcm_left _ _), mul_zero, zero_mul] · rw [h_1, eq_zero_of_zero_dvd (dvd_lcm_right _ _)] rw [mul_comm, ← Classical.choose_spec (exists_gcd a b)] - lcm_zero_left := fun a => eq_zero_of_zero_dvd (dvd_lcm_left _ _) - lcm_zero_right := fun a => eq_zero_of_zero_dvd (dvd_lcm_right _ _) + lcm_zero_left := fun _ => eq_zero_of_zero_dvd (dvd_lcm_left _ _) + lcm_zero_right := fun _ => eq_zero_of_zero_dvd (dvd_lcm_right _ _) gcd_dvd_left := fun a b => by -- Porting note(#12129): additional beta reduction needed beta_reduce @@ -1112,7 +1103,6 @@ noncomputable def gcdMonoidOfLCM [DecidableEq α] (lcm : α → α → α) rw [mul_comm, mul_dvd_mul_iff_right h_1.2] apply ac } --- Porting note (#11083): very slow; improve performance? /-- Define `NormalizedGCDMonoid` on a structure just from the `lcm` and its properties. -/ noncomputable def normalizedGCDMonoidOfLCM [NormalizationMonoid α] [DecidableEq α] (lcm : α → α → α) (dvd_lcm_left : ∀ a b, a ∣ lcm a b) (dvd_lcm_right : ∀ a b, b ∣ lcm a b) @@ -1150,8 +1140,8 @@ noncomputable def normalizedGCDMonoidOfLCM [NormalizationMonoid α] [DecidableEq congr rw [← normalize_lcm a b] erw [← normalize.map_mul, ← Classical.choose_spec (exists_gcd a b), normalize_idem] - lcm_zero_left := fun a => eq_zero_of_zero_dvd (dvd_lcm_left _ _) - lcm_zero_right := fun a => eq_zero_of_zero_dvd (dvd_lcm_right _ _) + lcm_zero_left := fun _ => eq_zero_of_zero_dvd (dvd_lcm_left _ _) + lcm_zero_right := fun _ => eq_zero_of_zero_dvd (dvd_lcm_right _ _) gcd_dvd_left := fun a b => by beta_reduce split_ifs with h h_1 @@ -1252,7 +1242,6 @@ namespace CommGroupWithZero variable (G₀ : Type*) [CommGroupWithZero G₀] [DecidableEq G₀] --- Porting note (#11083): very slow; improve performance? -- see Note [lower instance priority] instance (priority := 100) : NormalizedGCDMonoid G₀ where normUnit x := if h : x = 0 then 1 else (Units.mk0 x h)⁻¹ @@ -1308,8 +1297,8 @@ instance (priority := 100) : NormalizedGCDMonoid G₀ where · beta_reduce rw [if_neg (not_and_of_not_left _ ha), one_mul, if_neg (not_or_intro ha hb)] exact (associated_one_iff_isUnit.mpr ((IsUnit.mk0 _ ha).mul (IsUnit.mk0 _ hb))).symm - lcm_zero_left b := if_pos (Or.inl rfl) - lcm_zero_right a := if_pos (Or.inr rfl) + lcm_zero_left _ := if_pos (Or.inl rfl) + lcm_zero_right _ := if_pos (Or.inr rfl) -- `split_ifs` wants to split `normalize`, so handle the cases manually normalize_gcd a b := if h : a = 0 ∧ b = 0 then by simp [if_pos h] else by simp [if_neg h] normalize_lcm a b := if h : a = 0 ∨ b = 0 then by simp [if_pos h] else by simp [if_neg h] @@ -1326,8 +1315,8 @@ namespace Associates variable [CancelCommMonoidWithZero α] [GCDMonoid α] instance instGCDMonoid : GCDMonoid (Associates α) where - gcd := Quotient.map₂' gcd fun a₁ a₂ (ha : Associated _ _) b₁ b₂ (hb : Associated _ _) => ha.gcd hb - lcm := Quotient.map₂' lcm fun a₁ a₂ (ha : Associated _ _) b₁ b₂ (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/GCDMonoid/Multiset.lean b/Mathlib/Algebra/GCDMonoid/Multiset.lean index ea5a208bda10a..4bbe0597cd14b 100644 --- a/Mathlib/Algebra/GCDMonoid/Multiset.lean +++ b/Mathlib/Algebra/GCDMonoid/Multiset.lean @@ -199,9 +199,6 @@ theorem extract_gcd' (s t : Multiset α) (hs : ∃ x, x ∈ s ∧ x ≠ (0 : α) contrapose! hs exact s.gcd_eq_zero_iff.1 hs -/- Porting note: Deprecated lemmas like `map_repeat` and `eq_repeat` weren't "officially" -converted to `Multiset.replicate` format yet, so I made some ad hoc ones in `Data.Multiset.Basic` -using the originals. -/ /- Porting note: The old proof used a strange form `have := _, refine ⟨s.pmap @f (fun _ ↦ id), this, extract_gcd' s _ h this⟩,` so I rearranged the proof slightly. -/ diff --git a/Mathlib/Algebra/GCDMonoid/Nat.lean b/Mathlib/Algebra/GCDMonoid/Nat.lean index 11c7bd9c63679..a36ea2e3acbc3 100644 --- a/Mathlib/Algebra/GCDMonoid/Nat.lean +++ b/Mathlib/Algebra/GCDMonoid/Nat.lean @@ -79,7 +79,7 @@ theorem normalize_coe_nat (n : ℕ) : normalize (n : ℤ) = n := theorem abs_eq_normalize (z : ℤ) : |z| = normalize z := by cases le_total 0 z <;> - simp [-normalize_apply, abs_of_nonneg, abs_of_nonpos, normalize_of_nonneg, normalize_of_nonpos, *] + simp [abs_of_nonneg, abs_of_nonpos, normalize_of_nonneg, normalize_of_nonpos, *] theorem nonneg_of_normalize_eq_self {z : ℤ} (hz : normalize z = z) : 0 ≤ z := by by_cases h : 0 ≤ z @@ -101,14 +101,14 @@ section GCDMonoid instance : GCDMonoid ℤ where gcd a b := Int.gcd a b lcm a b := Int.lcm a b - gcd_dvd_left a b := Int.gcd_dvd_left - gcd_dvd_right a b := Int.gcd_dvd_right + gcd_dvd_left _ _ := Int.gcd_dvd_left + gcd_dvd_right _ _ := Int.gcd_dvd_right dvd_gcd := dvd_gcd gcd_mul_lcm a b := by rw [← Int.ofNat_mul, gcd_mul_lcm, natCast_natAbs, abs_eq_normalize] exact normalize_associated (a * b) - lcm_zero_left a := natCast_eq_zero.2 <| Nat.lcm_zero_left _ - lcm_zero_right a := natCast_eq_zero.2 <| Nat.lcm_zero_right _ + lcm_zero_left _ := natCast_eq_zero.2 <| Nat.lcm_zero_left _ + lcm_zero_right _ := natCast_eq_zero.2 <| Nat.lcm_zero_right _ instance : NormalizedGCDMonoid ℤ := { Int.normalizationMonoid, @@ -147,7 +147,7 @@ def associatesIntEquivNat : Associates ℤ ≃ ℕ := by refine ⟨(·.out.natAbs), (Associates.mk ·), ?_, fun n ↦ ?_⟩ · refine Associates.forall_associated.2 fun a ↦ ?_ refine Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, ?_⟩ - simp [Int.abs_eq_normalize] + simp [Int.abs_eq_normalize, normalize_apply] · dsimp only [Associates.out_mk] rw [← Int.abs_eq_normalize, Int.natAbs_abs, Int.natAbs_ofNat] diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index 70a08526df06e..3cbed430844f5 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -31,8 +31,6 @@ which `x` and `y` commute. Even versions not using division or subtraction, vali are recorded. -/ --- Porting note: corrected type in the description of `geom_sum₂_Ico` (in the doc string only). - universe u variable {α : Type u} @@ -69,12 +67,9 @@ theorem zero_geom_sum : ∀ {n}, ∑ i ∈ range n, (0 : α) ^ i = if n = 0 then theorem one_geom_sum (n : ℕ) : ∑ i ∈ range n, (1 : α) ^ i = n := by simp --- porting note (#10618): simp can prove this --- @[simp] theorem op_geom_sum (x : α) (n : ℕ) : op (∑ i ∈ range n, x ^ i) = ∑ i ∈ range n, op x ^ i := by simp --- Porting note: linter suggested to change left hand side @[simp] theorem op_geom_sum₂ (x y : α) (n : ℕ) : ∑ i ∈ range n, op y ^ (n - 1 - i) * op x ^ i = ∑ i ∈ range n, op y ^ i * op x ^ (n - 1 - i) := by @@ -132,9 +127,9 @@ theorem geom_sum₂_self {α : Type*} [CommRing α] (x : α) (n : ℕ) : ∑ i ∈ Finset.range n, x ^ (i + (n - 1 - i)) := by simp_rw [← pow_add] _ = ∑ _i ∈ Finset.range n, x ^ (n - 1) := - Finset.sum_congr rfl fun i hi => + Finset.sum_congr rfl fun _ hi => congr_arg _ <| add_tsub_cancel_of_le <| Nat.le_sub_one_of_lt <| Finset.mem_range.1 hi - _ = (Finset.range n).card • x ^ (n - 1) := Finset.sum_const _ + _ = #(range n) • x ^ (n - 1) := sum_const _ _ = n * x ^ (n - 1) := by rw [Finset.card_range, nsmul_eq_mul] /-- $x^n-y^n = (x-y) \sum x^ky^{n-1-k}$ reformulated without `-` signs. -/ @@ -422,7 +417,7 @@ variable {n : ℕ} {x : α} theorem geom_sum_pos [StrictOrderedSemiring α] (hx : 0 ≤ x) (hn : n ≠ 0) : 0 < ∑ i ∈ range n, x ^ i := - sum_pos' (fun k _ => pow_nonneg hx _) ⟨0, mem_range.2 hn.bot_lt, by simp⟩ + sum_pos' (fun _ _ => pow_nonneg hx _) ⟨0, mem_range.2 hn.bot_lt, by simp⟩ theorem geom_sum_pos_and_lt_one [StrictOrderedRing α] (hx : x < 0) (hx' : 0 < x + 1) (hn : 1 < n) : (0 < ∑ i ∈ range n, x ^ i) ∧ ∑ i ∈ range n, x ^ i < 1 := by @@ -547,7 +542,7 @@ lemma Nat.geomSum_eq (hm : 2 ≤ m) (n : ℕ) : `m ≥ 2` is less than `m ^ n`. -/ lemma Nat.geomSum_lt (hm : 2 ≤ m) (hs : ∀ k ∈ s, k < n) : ∑ k ∈ s, m ^ k < m ^ n := calc - ∑ k ∈ s, m ^ k ≤ ∑ k ∈ range n, m ^ k := sum_le_sum_of_subset fun k hk ↦ + ∑ k ∈ s, m ^ k ≤ ∑ k ∈ range n, m ^ k := sum_le_sum_of_subset fun _ hk ↦ mem_range.2 <| hs _ hk _ = (m ^ n - 1) / (m - 1) := Nat.geomSum_eq hm _ _ ≤ m ^ n - 1 := Nat.div_le_self _ _ diff --git a/Mathlib/Algebra/GradedMonoid.lean b/Mathlib/Algebra/GradedMonoid.lean index 5f4ad73f043d1..12fa6e2789b3c 100644 --- a/Mathlib/Algebra/GradedMonoid.lean +++ b/Mathlib/Algebra/GradedMonoid.lean @@ -4,11 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.BigOperators.Group.List -import Mathlib.Algebra.Group.InjSurj +import Mathlib.Algebra.Group.Action.End +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Data.List.FinRange -import Mathlib.Algebra.Group.Action.Defs import Mathlib.Data.SetLike.Basic -import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Data.Sigma.Basic import Lean.Elab.Tactic diff --git a/Mathlib/Algebra/Group/Action/Basic.lean b/Mathlib/Algebra/Group/Action/Basic.lean index 8515f84bac94f..0077326ec936b 100644 --- a/Mathlib/Algebra/Group/Action/Basic.lean +++ b/Mathlib/Algebra/Group/Action/Basic.lean @@ -16,7 +16,7 @@ This file contains lemmas about group actions that require more imports than assert_not_exists MonoidWithZero -variable {α β γ : Type*} +variable {α β : Type*} section MulAction diff --git a/Mathlib/Algebra/Group/Action/Defs.lean b/Mathlib/Algebra/Group/Action/Defs.lean index 91a530d0f239f..823dbf69f3586 100644 --- a/Mathlib/Algebra/Group/Action/Defs.lean +++ b/Mathlib/Algebra/Group/Action/Defs.lean @@ -4,9 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Yury Kudryashov -/ import Mathlib.Algebra.Group.Commute.Defs -import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Opposites +import Mathlib.Data.FunLike.Basic import Mathlib.Logic.Embedding.Basic +import Mathlib.Logic.Function.Iterate +import Mathlib.Logic.Nontrivial.Basic +import Mathlib.Tactic.Spread /-! # Definitions of group actions @@ -22,8 +25,7 @@ notation classes `SMul` and its additive version `VAdd`: The hierarchy is extended further by `Module`, defined elsewhere. -Also provided are typeclasses for faithful and transitive actions, and typeclasses regarding the -interaction of different group actions, +Also provided are typeclasses regarding the interaction of different group actions, * `SMulCommClass M N α` and its additive version `VAddCommClass M N α`; * `IsScalarTower M N α` and its additive version `VAddAssocClass M N α`; @@ -48,27 +50,7 @@ assert_not_exists MonoidWithZero open Function (Injective Surjective) -variable {M N G H A B α β γ δ : Type*} - -/-! ### Faithful actions -/ - -/-- Typeclass for faithful actions. -/ -class FaithfulVAdd (G : Type*) (P : Type*) [VAdd G P] : Prop where - /-- Two elements `g₁` and `g₂` are equal whenever they act in the same way on all points. -/ - eq_of_vadd_eq_vadd : ∀ {g₁ g₂ : G}, (∀ p : P, g₁ +ᵥ p = g₂ +ᵥ p) → g₁ = g₂ - -/-- Typeclass for faithful actions. -/ -@[to_additive] -class FaithfulSMul (M : Type*) (α : Type*) [SMul M α] : Prop where - /-- Two elements `m₁` and `m₂` are equal whenever they act in the same way on all points. -/ - eq_of_smul_eq_smul : ∀ {m₁ m₂ : M}, (∀ a : α, m₁ • a = m₂ • a) → m₁ = m₂ - -export FaithfulSMul (eq_of_smul_eq_smul) -export FaithfulVAdd (eq_of_vadd_eq_vadd) - -@[to_additive] -lemma smul_left_injective' [SMul M α] [FaithfulSMul M α] : Injective ((· • ·) : M → α → α) := - fun _ _ h ↦ FaithfulSMul.eq_of_smul_eq_smul (congr_fun h) +variable {M N G H α β γ δ : Type*} -- see Note [lower instance priority] /-- See also `Monoid.toMulAction` and `MulZeroClass.toSMulWithZero`. -/ @@ -78,11 +60,6 @@ instance (priority := 910) Mul.toSMul (α : Type*) [Mul α] : SMul α α := ⟨( @[to_additive (attr := simp)] lemma smul_eq_mul (α : Type*) [Mul α] {a a' : α} : a • a' = a * a' := rfl -/-- `Monoid.toMulAction` is faithful on cancellative monoids. -/ -@[to_additive " `AddMonoid.toAddAction` is faithful on additive cancellative monoids. "] -instance RightCancelMonoid.faithfulSMul [RightCancelMonoid α] : FaithfulSMul α α := - ⟨fun h ↦ mul_right_cancel (h 1)⟩ - /-- Type class for additive monoid actions. -/ class AddAction (G : Type*) (P : Type*) [AddMonoid G] extends VAdd G P where /-- Zero is a neutral element for `+ᵥ` -/ @@ -98,48 +75,6 @@ class MulAction (α : Type*) (β : Type*) [Monoid α] extends SMul α β where /-- Associativity of `•` and `*` -/ mul_smul : ∀ (x y : α) (b : β), (x * y) • b = x • y • b -/-! -### (Pre)transitive action - -`M` acts pretransitively on `α` if for any `x y` there is `g` such that `g • x = y` (or `g +ᵥ x = y` -for an additive action). A transitive action should furthermore have `α` nonempty. - -In this section we define typeclasses `MulAction.IsPretransitive` and -`AddAction.IsPretransitive` and provide `MulAction.exists_smul_eq`/`AddAction.exists_vadd_eq`, -`MulAction.surjective_smul`/`AddAction.surjective_vadd` as public interface to access this -property. We do not provide typeclasses `*Action.IsTransitive`; users should assume -`[MulAction.IsPretransitive M α] [Nonempty α]` instead. --/ - -/-- `M` acts pretransitively on `α` if for any `x y` there is `g` such that `g +ᵥ x = y`. - A transitive action should furthermore have `α` nonempty. -/ -class AddAction.IsPretransitive (M α : Type*) [VAdd M α] : Prop where - /-- There is `g` such that `g +ᵥ x = y`. -/ - exists_vadd_eq : ∀ x y : α, ∃ g : M, g +ᵥ x = y - -/-- `M` acts pretransitively on `α` if for any `x y` there is `g` such that `g • x = y`. - A transitive action should furthermore have `α` nonempty. -/ -@[to_additive] -class MulAction.IsPretransitive (M α : Type*) [SMul M α] : Prop where - /-- There is `g` such that `g • x = y`. -/ - exists_smul_eq : ∀ x y : α, ∃ g : M, g • x = y - -namespace MulAction -variable (M) [SMul M α] [IsPretransitive M α] - -@[to_additive] -lemma exists_smul_eq (x y : α) : ∃ m : M, m • x = y := IsPretransitive.exists_smul_eq x y - -@[to_additive] -lemma surjective_smul (x : α) : Surjective fun c : M ↦ c • x := exists_smul_eq M x - -/-- The regular action of a group on itself is transitive. -/ -@[to_additive "The regular action of a group on itself is transitive."] -instance Regular.isPretransitive [Group G] : IsPretransitive G G := - ⟨fun x y ↦ ⟨y * x⁻¹, inv_mul_cancel_right _ _⟩⟩ - -end MulAction - /-! ### Scalar tower and commuting actions -/ /-- A typeclass mixin saying that two additive actions on the same space commute. -/ @@ -427,19 +362,6 @@ protected abbrev Function.Surjective.mulAction [SMul M β] (f : α → β) (hf : one_smul := by simp [hf.forall, ← smul] mul_smul := by simp [hf.forall, ← smul, mul_smul] -/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →* S`. - -See also `Function.Surjective.distribMulActionLeft` and `Function.Surjective.moduleLeft`. --/ -@[to_additive -"Push forward the action of `R` on `M` along a compatible surjective map `f : R →+ S`."] -abbrev Function.Surjective.mulActionLeft {R S M : Type*} [Monoid R] [MulAction R M] [Monoid S] - [SMul S M] (f : R →* S) (hf : Surjective f) (hsmul : ∀ (c) (x : M), f c • x = c • x) : - MulAction S M where - smul := (· • ·) - one_smul b := by rw [← f.map_one, hsmul, one_smul] - mul_smul := hf.forall₂.mpr fun a b x ↦ by simp only [← f.map_mul, hsmul, mul_smul] - section variable (M) @@ -487,7 +409,7 @@ lemma smul_inv_smul (g : G) (a : α) : g • g⁻¹ • a = a := by rw [smul_smu ⟨fun h ↦ by rw [h, smul_inv_smul], fun h ↦ by rw [← h, inv_smul_smul]⟩ section Mul -variable [Mul H] [MulAction G H] [SMulCommClass G H H] [IsScalarTower G H H] {g : G} {a b : H} +variable [Mul H] [MulAction G H] [SMulCommClass G H H] [IsScalarTower G H H] {a b : H} @[simp] lemma Commute.smul_right_iff : Commute a (g • b) ↔ Commute a b := ⟨fun h ↦ inv_smul_smul g b ▸ h.smul_right g⁻¹, fun h ↦ h.smul_right g⟩ @@ -528,55 +450,6 @@ def toFun : α ↪ M → α := @[to_additive (attr := simp)] lemma toFun_apply (x : M) (y : α) : MulAction.toFun M α y x = x • y := rfl -variable (α) - -/-- A multiplicative action of `M` on `α` and a monoid homomorphism `N → M` induce -a multiplicative action of `N` on `α`. - -See note [reducible non-instances]. -/ -@[to_additive] -abbrev compHom [Monoid N] (g : N →* M) : MulAction N α where - smul := SMul.comp.smul g - -- Porting note: was `by simp [g.map_one, MulAction.one_smul]` - one_smul _ := by simpa [(· • ·)] using MulAction.one_smul .. - -- Porting note: was `by simp [g.map_mul, MulAction.mul_smul]` - mul_smul _ _ _ := by simpa [(· • ·)] using MulAction.mul_smul .. - -/-- An additive action of `M` on `α` and an additive monoid homomorphism `N → M` induce -an additive action of `N` on `α`. - -See note [reducible non-instances]. -/ -add_decl_doc AddAction.compHom - -@[to_additive] -lemma compHom_smul_def - {E F G : Type*} [Monoid E] [Monoid F] [MulAction F G] (f : E →* F) (a : E) (x : G) : - letI : MulAction E G := MulAction.compHom _ f - a • x = (f a) • x := rfl - -/-- If an action is transitive, then composing this action with a surjective homomorphism gives -again a transitive action. -/ -@[to_additive] -lemma isPretransitive_compHom {E F G : Type*} [Monoid E] [Monoid F] [MulAction F G] - [IsPretransitive F G] {f : E →* F} (hf : Surjective f) : - letI : MulAction E G := MulAction.compHom _ f - IsPretransitive E G := by - let _ : MulAction E G := MulAction.compHom _ f - refine ⟨fun x y ↦ ?_⟩ - obtain ⟨m, rfl⟩ : ∃ m : F, m • x = y := exists_smul_eq F x y - obtain ⟨e, rfl⟩ : ∃ e, f e = m := hf m - exact ⟨e, rfl⟩ - -@[to_additive] -lemma IsPretransitive.of_smul_eq {M N α : Type*} [SMul M α] [SMul N α] [IsPretransitive M α] - (f : M → N) (hf : ∀ {c : M} {x : α}, f c • x = c • x) : IsPretransitive N α where - exists_smul_eq x y := (exists_smul_eq x y).elim fun m h ↦ ⟨f m, hf.trans h⟩ - -@[to_additive] -lemma IsPretransitive.of_compHom {M N α : Type*} [Monoid M] [Monoid N] [MulAction N α] - (f : M →* N) [h : letI := compHom α f; IsPretransitive M α] : IsPretransitive N α := - letI := compHom α f; h.of_smul_eq f rfl - end MulAction end @@ -587,11 +460,6 @@ lemma smul_one_smul {M} (N) [Monoid N] [SMul M N] [MulAction N α] [SMul M α] [IsScalarTower M N α] (x : M) (y : α) : (x • (1 : N)) • y = x • y := by rw [smul_assoc, one_smul] -@[to_additive] -lemma MulAction.IsPretransitive.of_isScalarTower (M : Type*) {N α : Type*} [Monoid N] [SMul M N] - [MulAction N α] [SMul M α] [IsScalarTower M N α] [IsPretransitive M α] : IsPretransitive N α := - of_smul_eq (fun x : M ↦ x • 1) (smul_one_smul N _ _) - @[to_additive (attr := simp)] lemma smul_one_mul {M N} [MulOneClass N] [SMul M N] [IsScalarTower M N N] (x : M) (y : N) : x • (1 : N) * y = x • y := by rw [smul_mul_assoc, one_mul] @@ -610,153 +478,4 @@ lemma SMulCommClass.of_mul_smul_one {M N} [Monoid N] [SMul M N] (H : ∀ (x : M) (y : N), y * x • (1 : N) = x • y) : SMulCommClass M N N := ⟨fun x y z ↦ by rw [← H x z, smul_eq_mul, ← H, smul_eq_mul, mul_assoc]⟩ -/-- If the multiplicative action of `M` on `N` is compatible with multiplication on `N`, then -`fun x ↦ x • 1` is a monoid homomorphism from `M` to `N`. -/ -@[to_additive (attr := simps) -"If the additive action of `M` on `N` is compatible with addition on `N`, then -`fun x ↦ x +ᵥ 0` is an additive monoid homomorphism from `M` to `N`."] -def MonoidHom.smulOneHom {M N} [Monoid M] [MulOneClass N] [MulAction M N] [IsScalarTower M N N] : - M →* N where - toFun x := x • (1 : N) - map_one' := one_smul _ _ - map_mul' x y := by rw [smul_one_mul, smul_smul] - -/-- A monoid homomorphism between two monoids M and N can be equivalently specified by a -multiplicative action of M on N that is compatible with the multiplication on N. -/ -@[to_additive -"A monoid homomorphism between two additive monoids M and N can be equivalently -specified by an additive action of M on N that is compatible with the addition on N."] -def monoidHomEquivMulActionIsScalarTower (M N) [Monoid M] [Monoid N] : - (M →* N) ≃ {_inst : MulAction M N // IsScalarTower M N N} where - toFun f := ⟨MulAction.compHom N f, SMul.comp.isScalarTower _⟩ - invFun := fun ⟨_, _⟩ ↦ MonoidHom.smulOneHom - left_inv f := MonoidHom.ext fun m ↦ mul_one (f m) - right_inv := fun ⟨_, _⟩ ↦ Subtype.ext <| MulAction.ext <| funext₂ <| smul_one_smul N - end CompatibleScalar - -variable (α) - -/-- The monoid of endomorphisms. - -Note that this is generalized by `CategoryTheory.End` to categories other than `Type u`. -/ -protected def Function.End := α → α - -instance : Monoid (Function.End α) where - one := id - mul := (· ∘ ·) - mul_assoc f g h := rfl - mul_one f := rfl - one_mul f := rfl - npow n f := f^[n] - npow_succ n f := Function.iterate_succ _ _ - -instance : Inhabited (Function.End α) := ⟨1⟩ - -variable {α} - -/-- The tautological action by `Function.End α` on `α`. - -This is generalized to bundled endomorphisms by: -* `Equiv.Perm.applyMulAction` -* `AddMonoid.End.applyDistribMulAction` -* `AddMonoid.End.applyModule` -* `AddAut.applyDistribMulAction` -* `MulAut.applyMulDistribMulAction` -* `LinearEquiv.applyDistribMulAction` -* `LinearMap.applyModule` -* `RingHom.applyMulSemiringAction` -* `RingAut.applyMulSemiringAction` -* `AlgEquiv.applyMulSemiringAction` --/ -instance Function.End.applyMulAction : MulAction (Function.End α) α where - smul := (· <| ·) - one_smul _ := rfl - mul_smul _ _ _ := rfl - -@[simp] lemma Function.End.smul_def (f : Function.End α) (a : α) : f • a = f a := rfl - ---TODO - This statement should be somethting like `toFun (f * g) = toFun f ∘ toFun g` -lemma Function.End.mul_def (f g : Function.End α) : (f * g) = f ∘ g := rfl - ---TODO - This statement should be somethting like `toFun 1 = id` -lemma Function.End.one_def : (1 : Function.End α) = id := rfl - -/-- `Function.End.applyMulAction` is faithful. -/ -instance Function.End.apply_FaithfulSMul : FaithfulSMul (Function.End α) α := - ⟨fun {_ _} ↦ funext⟩ - -/-- The monoid hom representing a monoid action. - -When `M` is a group, see `MulAction.toPermHom`. -/ -def MulAction.toEndHom [Monoid M] [MulAction M α] : M →* Function.End α where - toFun := (· • ·) - map_one' := funext (one_smul M) - map_mul' x y := funext (mul_smul x y) - -/-- The monoid action induced by a monoid hom to `Function.End α` - -See note [reducible non-instances]. -/ -abbrev MulAction.ofEndHom [Monoid M] (f : M →* Function.End α) : MulAction M α := - MulAction.compHom α f - -/-! ### `Additive`, `Multiplicative` -/ - -section - -open Additive Multiplicative - -instance Additive.vadd [SMul α β] : VAdd (Additive α) β where vadd a := (toMul a • ·) - -instance Multiplicative.smul [VAdd α β] : SMul (Multiplicative α) β where smul a := (toAdd a +ᵥ ·) - -@[simp] lemma toMul_smul [SMul α β] (a) (b : β) : (toMul a : α) • b = a +ᵥ b := rfl - -@[simp] lemma ofMul_vadd [SMul α β] (a : α) (b : β) : ofMul a +ᵥ b = a • b := rfl - -@[simp] lemma toAdd_vadd [VAdd α β] (a) (b : β) : (toAdd a : α) +ᵥ b = a • b := rfl - -@[simp] lemma ofAdd_smul [VAdd α β] (a : α) (b : β) : ofAdd a • b = a +ᵥ b := rfl - --- Porting note: I don't know why `one_smul` can do without an explicit α and `mul_smul` can't. -instance Additive.addAction [Monoid α] [MulAction α β] : AddAction (Additive α) β where - zero_vadd := MulAction.one_smul - add_vadd := MulAction.mul_smul (α := α) - -instance Multiplicative.mulAction [AddMonoid α] [AddAction α β] : - MulAction (Multiplicative α) β where - one_smul := AddAction.zero_vadd - mul_smul := AddAction.add_vadd (G := α) - -instance Additive.addAction_isPretransitive [Monoid α] [MulAction α β] - [MulAction.IsPretransitive α β] : AddAction.IsPretransitive (Additive α) β := - ⟨@MulAction.exists_smul_eq α _ _ _⟩ - -instance Multiplicative.mulAction_isPretransitive [AddMonoid α] [AddAction α β] - [AddAction.IsPretransitive α β] : MulAction.IsPretransitive (Multiplicative α) β := - ⟨@AddAction.exists_vadd_eq α _ _ _⟩ - -instance Additive.vaddCommClass [SMul α γ] [SMul β γ] [SMulCommClass α β γ] : - VAddCommClass (Additive α) (Additive β) γ := - ⟨@smul_comm α β _ _ _ _⟩ - -instance Multiplicative.smulCommClass [VAdd α γ] [VAdd β γ] [VAddCommClass α β γ] : - SMulCommClass (Multiplicative α) (Multiplicative β) γ := - ⟨@vadd_comm α β _ _ _ _⟩ - -end - -/-- The tautological additive action by `Additive (Function.End α)` on `α`. -/ -instance AddAction.functionEnd : AddAction (Additive (Function.End α)) α := inferInstance - -/-- The additive monoid hom representing an additive monoid action. - -When `M` is a group, see `AddAction.toPermHom`. -/ -def AddAction.toEndHom [AddMonoid M] [AddAction M α] : M →+ Additive (Function.End α) := - MonoidHom.toAdditive'' MulAction.toEndHom - -/-- The additive action induced by a hom to `Additive (Function.End α)` - -See note [reducible non-instances]. -/ -abbrev AddAction.ofEndHom [AddMonoid M] (f : M →+ Additive (Function.End α)) : AddAction M α := - AddAction.compHom α f diff --git a/Mathlib/Algebra/Group/Action/End.lean b/Mathlib/Algebra/Group/Action/End.lean new file mode 100644 index 0000000000000..302230a0828c8 --- /dev/null +++ b/Mathlib/Algebra/Group/Action/End.lean @@ -0,0 +1,169 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Hom.Defs + +/-! +# Endomorphisms, homomorphisms and group actions + +This file defines `Function.End` as the monoid of endomorphisms on a type, +and provides results relating group actions with these endomorphisms. + +## Notation + +- `a • b` is used as notation for `SMul.smul a b`. +- `a +ᵥ b` is used as notation for `VAdd.vadd a b`. + +## Implementation details + +This file should avoid depending on other parts of `GroupTheory`, to avoid import cycles. +More sophisticated lemmas belong in `GroupTheory.GroupAction`. + +## Tags + +group action +-/ + +assert_not_exists MonoidWithZero + +open Function (Injective Surjective) + +variable {M N G H α β γ δ : Type*} + +section +variable [Monoid M] [MulAction M α] + +/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →* S`. + +See also `Function.Surjective.distribMulActionLeft` and `Function.Surjective.moduleLeft`. +-/ +@[to_additive +"Push forward the action of `R` on `M` along a compatible surjective map `f : R →+ S`."] +abbrev Function.Surjective.mulActionLeft {R S M : Type*} [Monoid R] [MulAction R M] [Monoid S] + [SMul S M] (f : R →* S) (hf : Surjective f) (hsmul : ∀ (c) (x : M), f c • x = c • x) : + MulAction S M where + smul := (· • ·) + one_smul b := by rw [← f.map_one, hsmul, one_smul] + mul_smul := hf.forall₂.mpr fun a b x ↦ by simp only [← f.map_mul, hsmul, mul_smul] + +namespace MulAction + +variable (α) + +/-- A multiplicative action of `M` on `α` and a monoid homomorphism `N → M` induce +a multiplicative action of `N` on `α`. + +See note [reducible non-instances]. -/ +@[to_additive] +abbrev compHom [Monoid N] (g : N →* M) : MulAction N α where + smul := SMul.comp.smul g + -- Porting note: was `by simp [g.map_one, MulAction.one_smul]` + one_smul _ := by simpa [(· • ·)] using MulAction.one_smul .. + -- Porting note: was `by simp [g.map_mul, MulAction.mul_smul]` + mul_smul _ _ _ := by simpa [(· • ·)] using MulAction.mul_smul .. + +/-- An additive action of `M` on `α` and an additive monoid homomorphism `N → M` induce +an additive action of `N` on `α`. + +See note [reducible non-instances]. -/ +add_decl_doc AddAction.compHom + +@[to_additive] +lemma compHom_smul_def + {E F G : Type*} [Monoid E] [Monoid F] [MulAction F G] (f : E →* F) (a : E) (x : G) : + letI : MulAction E G := MulAction.compHom _ f + a • x = (f a) • x := rfl + +end MulAction +end + +section CompatibleScalar + +/-- If the multiplicative action of `M` on `N` is compatible with multiplication on `N`, then +`fun x ↦ x • 1` is a monoid homomorphism from `M` to `N`. -/ +@[to_additive (attr := simps) +"If the additive action of `M` on `N` is compatible with addition on `N`, then +`fun x ↦ x +ᵥ 0` is an additive monoid homomorphism from `M` to `N`."] +def MonoidHom.smulOneHom {M N} [Monoid M] [MulOneClass N] [MulAction M N] [IsScalarTower M N N] : + M →* N where + toFun x := x • (1 : N) + map_one' := one_smul _ _ + map_mul' x y := by rw [smul_one_mul, smul_smul] + +/-- A monoid homomorphism between two monoids M and N can be equivalently specified by a +multiplicative action of M on N that is compatible with the multiplication on N. -/ +@[to_additive +"A monoid homomorphism between two additive monoids M and N can be equivalently +specified by an additive action of M on N that is compatible with the addition on N."] +def monoidHomEquivMulActionIsScalarTower (M N) [Monoid M] [Monoid N] : + (M →* N) ≃ {_inst : MulAction M N // IsScalarTower M N N} where + toFun f := ⟨MulAction.compHom N f, SMul.comp.isScalarTower _⟩ + invFun := fun ⟨_, _⟩ ↦ MonoidHom.smulOneHom + left_inv f := MonoidHom.ext fun m ↦ mul_one (f m) + right_inv := fun ⟨_, _⟩ ↦ Subtype.ext <| MulAction.ext <| funext₂ <| smul_one_smul N + +end CompatibleScalar + +variable (α) + +/-- The monoid of endomorphisms. + +Note that this is generalized by `CategoryTheory.End` to categories other than `Type u`. -/ +protected def Function.End := α → α + +instance : Monoid (Function.End α) where + one := id + mul := (· ∘ ·) + mul_assoc _ _ _ := rfl + mul_one _ := rfl + one_mul _ := rfl + npow n f := f^[n] + npow_succ _ _ := Function.iterate_succ _ _ + +instance : Inhabited (Function.End α) := ⟨1⟩ + +variable {α} + +/-- The tautological action by `Function.End α` on `α`. + +This is generalized to bundled endomorphisms by: +* `Equiv.Perm.applyMulAction` +* `AddMonoid.End.applyDistribMulAction` +* `AddMonoid.End.applyModule` +* `AddAut.applyDistribMulAction` +* `MulAut.applyMulDistribMulAction` +* `LinearEquiv.applyDistribMulAction` +* `LinearMap.applyModule` +* `RingHom.applyMulSemiringAction` +* `RingAut.applyMulSemiringAction` +* `AlgEquiv.applyMulSemiringAction` +-/ +instance Function.End.applyMulAction : MulAction (Function.End α) α where + smul := (· <| ·) + one_smul _ := rfl + mul_smul _ _ _ := rfl + +@[simp] lemma Function.End.smul_def (f : Function.End α) (a : α) : f • a = f a := rfl + +--TODO - This statement should be somethting like `toFun (f * g) = toFun f ∘ toFun g` +lemma Function.End.mul_def (f g : Function.End α) : (f * g) = f ∘ g := rfl + +--TODO - This statement should be somethting like `toFun 1 = id` +lemma Function.End.one_def : (1 : Function.End α) = id := rfl + +/-- The monoid hom representing a monoid action. + +When `M` is a group, see `MulAction.toPermHom`. -/ +def MulAction.toEndHom [Monoid M] [MulAction M α] : M →* Function.End α where + toFun := (· • ·) + map_one' := funext (one_smul M) + map_mul' x y := funext (mul_smul x y) + +/-- The monoid action induced by a monoid hom to `Function.End α` + +See note [reducible non-instances]. -/ +abbrev MulAction.ofEndHom [Monoid M] (f : M →* Function.End α) : MulAction M α := + MulAction.compHom α f diff --git a/Mathlib/Algebra/Group/Action/Faithful.lean b/Mathlib/Algebra/Group/Action/Faithful.lean new file mode 100644 index 0000000000000..19ba00c7bcc60 --- /dev/null +++ b/Mathlib/Algebra/Group/Action/Faithful.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.End + +/-! +# Faithful group actions + +This file provides typeclasses for faithful actions. + +## Notation + +- `a • b` is used as notation for `SMul.smul a b`. +- `a +ᵥ b` is used as notation for `VAdd.vadd a b`. + +## Implementation details + +This file should avoid depending on other parts of `GroupTheory`, to avoid import cycles. +More sophisticated lemmas belong in `GroupTheory.GroupAction`. + +## Tags + +group action +-/ + +assert_not_exists MonoidWithZero + +open Function (Injective Surjective) + +variable {M N G H α β γ δ : Type*} + +/-! ### Faithful actions -/ + +/-- Typeclass for faithful actions. -/ +class FaithfulVAdd (G : Type*) (P : Type*) [VAdd G P] : Prop where + /-- Two elements `g₁` and `g₂` are equal whenever they act in the same way on all points. -/ + eq_of_vadd_eq_vadd : ∀ {g₁ g₂ : G}, (∀ p : P, g₁ +ᵥ p = g₂ +ᵥ p) → g₁ = g₂ + +/-- Typeclass for faithful actions. -/ +@[to_additive] +class FaithfulSMul (M : Type*) (α : Type*) [SMul M α] : Prop where + /-- Two elements `m₁` and `m₂` are equal whenever they act in the same way on all points. -/ + eq_of_smul_eq_smul : ∀ {m₁ m₂ : M}, (∀ a : α, m₁ • a = m₂ • a) → m₁ = m₂ + +export FaithfulSMul (eq_of_smul_eq_smul) +export FaithfulVAdd (eq_of_vadd_eq_vadd) + +@[to_additive] +lemma smul_left_injective' [SMul M α] [FaithfulSMul M α] : Injective ((· • ·) : M → α → α) := + fun _ _ h ↦ FaithfulSMul.eq_of_smul_eq_smul (congr_fun h) + +/-- `Monoid.toMulAction` is faithful on cancellative monoids. -/ +@[to_additive " `AddMonoid.toAddAction` is faithful on additive cancellative monoids. "] +instance RightCancelMonoid.faithfulSMul [RightCancelMonoid α] : FaithfulSMul α α := + ⟨fun h ↦ mul_right_cancel (h 1)⟩ + +/-- `Function.End.applyMulAction` is faithful. -/ +instance Function.End.apply_FaithfulSMul : FaithfulSMul (Function.End α) α := + ⟨fun {_ _} ↦ funext⟩ diff --git a/Mathlib/Algebra/Group/Action/Opposite.lean b/Mathlib/Algebra/Group/Action/Opposite.lean index 252781fd7b4bd..1b5ea20d99733 100644 --- a/Mathlib/Algebra/Group/Action/Opposite.lean +++ b/Mathlib/Algebra/Group/Action/Opposite.lean @@ -3,7 +3,8 @@ Copyright (c) 2020 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful +import Mathlib.Algebra.Group.Action.Pretransitive import Mathlib.Algebra.Group.Opposite /-! @@ -27,7 +28,7 @@ With `open scoped RightActions`, this provides: assert_not_exists MonoidWithZero -variable {M N α : Type*} +variable {M N α β : Type*} /-! ### Actions _on_ the opposite type @@ -97,7 +98,7 @@ In lemma names this is still called `op_vadd`. -/ scoped notation3:73 m:73 " <+ᵥ " r:74 => AddOpposite.op r +ᵥ m section examples -variable {α β : Type*} [SMul α β] [SMul αᵐᵒᵖ β] [VAdd α β] [VAdd αᵃᵒᵖ β] {a a₁ a₂ a₃ a₄ : α} {b : β} +variable [SMul α β] [SMul αᵐᵒᵖ β] [VAdd α β] [VAdd αᵃᵒᵖ β] {a a₁ a₂ a₃ a₄ : α} {b : β} -- Left and right actions are just notation around the general `•` and `+ᵥ` notations example : a •> b = a • b := rfl @@ -124,7 +125,7 @@ end examples end RightActions section -variable {α β : Type*} [Monoid α] [MulAction αᵐᵒᵖ β] +variable [Monoid α] [MulAction αᵐᵒᵖ β] open scoped RightActions diff --git a/Mathlib/Algebra/Group/Action/Option.lean b/Mathlib/Algebra/Group/Action/Option.lean index 1a56618022160..72a1fef15f92a 100644 --- a/Mathlib/Algebra/Group/Action/Option.lean +++ b/Mathlib/Algebra/Group/Action/Option.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful /-! # Option instances for additive and multiplicative actions diff --git a/Mathlib/Algebra/Group/Action/Pi.lean b/Mathlib/Algebra/Group/Action/Pi.lean index d8c0c7b05deb3..7e61da3072d3a 100644 --- a/Mathlib/Algebra/Group/Action/Pi.lean +++ b/Mathlib/Algebra/Group/Action/Pi.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Patrick Massot -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful import Mathlib.Data.Set.Function /-! @@ -21,7 +21,7 @@ This file defines instances for `MulAction` and related structures on `Pi` types assert_not_exists MonoidWithZero -variable {ι M N : Type*} {α β γ : ι → Type*} (x y : ∀ i, α i) (i : ι) +variable {ι M N : Type*} {α β γ : ι → Type*} (i : ι) namespace Pi diff --git a/Mathlib/Algebra/Group/Action/Pretransitive.lean b/Mathlib/Algebra/Group/Action/Pretransitive.lean new file mode 100644 index 0000000000000..cbbc533efdfc1 --- /dev/null +++ b/Mathlib/Algebra/Group/Action/Pretransitive.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.TypeTags + +/-! +# Pretransitive group actions + +This file defines a typeclass for pretransitive group actions. + +## Notation + +- `a • b` is used as notation for `SMul.smul a b`. +- `a +ᵥ b` is used as notation for `VAdd.vadd a b`. + +## Implementation details + +This file should avoid depending on other parts of `GroupTheory`, to avoid import cycles. +More sophisticated lemmas belong in `GroupTheory.GroupAction`. + +## Tags + +group action +-/ + +assert_not_exists MonoidWithZero + +open Function (Injective Surjective) + +variable {M G α β : Type*} + +/-! +### (Pre)transitive action + +`M` acts pretransitively on `α` if for any `x y` there is `g` such that `g • x = y` (or `g +ᵥ x = y` +for an additive action). A transitive action should furthermore have `α` nonempty. + +In this section we define typeclasses `MulAction.IsPretransitive` and +`AddAction.IsPretransitive` and provide `MulAction.exists_smul_eq`/`AddAction.exists_vadd_eq`, +`MulAction.surjective_smul`/`AddAction.surjective_vadd` as public interface to access this +property. We do not provide typeclasses `*Action.IsTransitive`; users should assume +`[MulAction.IsPretransitive M α] [Nonempty α]` instead. +-/ + +/-- `M` acts pretransitively on `α` if for any `x y` there is `g` such that `g +ᵥ x = y`. + A transitive action should furthermore have `α` nonempty. -/ +class AddAction.IsPretransitive (M α : Type*) [VAdd M α] : Prop where + /-- There is `g` such that `g +ᵥ x = y`. -/ + exists_vadd_eq : ∀ x y : α, ∃ g : M, g +ᵥ x = y + +/-- `M` acts pretransitively on `α` if for any `x y` there is `g` such that `g • x = y`. + A transitive action should furthermore have `α` nonempty. -/ +@[to_additive] +class MulAction.IsPretransitive (M α : Type*) [SMul M α] : Prop where + /-- There is `g` such that `g • x = y`. -/ + exists_smul_eq : ∀ x y : α, ∃ g : M, g • x = y + +namespace MulAction +variable (M) [SMul M α] [IsPretransitive M α] + +@[to_additive] +lemma exists_smul_eq (x y : α) : ∃ m : M, m • x = y := IsPretransitive.exists_smul_eq x y + +@[to_additive] +lemma surjective_smul (x : α) : Surjective fun c : M ↦ c • x := exists_smul_eq M x + +/-- The regular action of a group on itself is transitive. -/ +@[to_additive "The regular action of a group on itself is transitive."] +instance Regular.isPretransitive [Group G] : IsPretransitive G G := + ⟨fun x y ↦ ⟨y * x⁻¹, inv_mul_cancel_right _ _⟩⟩ + +end MulAction + +namespace MulAction + +variable (α) + +/-- If an action is transitive, then composing this action with a surjective homomorphism gives +again a transitive action. -/ +@[to_additive] +lemma isPretransitive_compHom {E F G : Type*} [Monoid E] [Monoid F] [MulAction F G] + [IsPretransitive F G] {f : E →* F} (hf : Surjective f) : + letI : MulAction E G := MulAction.compHom _ f + IsPretransitive E G := by + let _ : MulAction E G := MulAction.compHom _ f + refine ⟨fun x y ↦ ?_⟩ + obtain ⟨m, rfl⟩ : ∃ m : F, m • x = y := exists_smul_eq F x y + obtain ⟨e, rfl⟩ : ∃ e, f e = m := hf m + exact ⟨e, rfl⟩ + +@[to_additive] +lemma IsPretransitive.of_smul_eq {M N α : Type*} [SMul M α] [SMul N α] [IsPretransitive M α] + (f : M → N) (hf : ∀ {c : M} {x : α}, f c • x = c • x) : IsPretransitive N α where + exists_smul_eq x y := (exists_smul_eq x y).elim fun m h ↦ ⟨f m, hf.trans h⟩ + +@[to_additive] +lemma IsPretransitive.of_compHom {M N α : Type*} [Monoid M] [Monoid N] [MulAction N α] + (f : M →* N) [h : letI := compHom α f; IsPretransitive M α] : IsPretransitive N α := + letI := compHom α f; h.of_smul_eq f rfl + +end MulAction + +section CompatibleScalar + +@[to_additive] +lemma MulAction.IsPretransitive.of_isScalarTower (M : Type*) {N α : Type*} [Monoid N] [SMul M N] + [MulAction N α] [SMul M α] [IsScalarTower M N α] [IsPretransitive M α] : IsPretransitive N α := + of_smul_eq (fun x : M ↦ x • 1) (smul_one_smul N _ _) + +end CompatibleScalar + +/-! ### `Additive`, `Multiplicative` -/ + +section + +open Additive Multiplicative + +instance Additive.addAction_isPretransitive [Monoid α] [MulAction α β] + [MulAction.IsPretransitive α β] : AddAction.IsPretransitive (Additive α) β := + ⟨@MulAction.exists_smul_eq α _ _ _⟩ + +instance Multiplicative.mulAction_isPretransitive [AddMonoid α] [AddAction α β] + [AddAction.IsPretransitive α β] : MulAction.IsPretransitive (Multiplicative α) β := + ⟨@AddAction.exists_vadd_eq α _ _ _⟩ + +end diff --git a/Mathlib/Algebra/Group/Action/Prod.lean b/Mathlib/Algebra/Group/Action/Prod.lean index e4434083c689b..898caa223cdc3 100644 --- a/Mathlib/Algebra/Group/Action/Prod.lean +++ b/Mathlib/Algebra/Group/Action/Prod.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Patrick Massot, Eric Wieser -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful import Mathlib.Algebra.Group.Prod /-! diff --git a/Mathlib/Algebra/Group/Action/Sigma.lean b/Mathlib/Algebra/Group/Action/Sigma.lean index 5aaeee6501dcc..bdd561079350c 100644 --- a/Mathlib/Algebra/Group/Action/Sigma.lean +++ b/Mathlib/Algebra/Group/Action/Sigma.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful /-! # Sigma instances for additive and multiplicative actions diff --git a/Mathlib/Algebra/Group/Action/Sum.lean b/Mathlib/Algebra/Group/Action/Sum.lean index 5bc1602680cfc..d7db12fe9d54b 100644 --- a/Mathlib/Algebra/Group/Action/Sum.lean +++ b/Mathlib/Algebra/Group/Action/Sum.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful /-! # Sum instances for additive and multiplicative actions @@ -20,7 +20,7 @@ This file defines instances for additive and multiplicative actions on the binar assert_not_exists MonoidWithZero -variable {M N P α β γ : Type*} +variable {M N α β : Type*} namespace Sum diff --git a/Mathlib/Algebra/Group/Action/TypeTags.lean b/Mathlib/Algebra/Group/Action/TypeTags.lean new file mode 100644 index 0000000000000..23a3579798c6e --- /dev/null +++ b/Mathlib/Algebra/Group/Action/TypeTags.lean @@ -0,0 +1,72 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.End +import Mathlib.Algebra.Group.TypeTags + +/-! +# Additive and Multiplicative for group actions + +## Tags + +group action +-/ + +assert_not_exists MonoidWithZero + +open Function (Injective Surjective) + +variable {M N G H α β γ δ : Type*} + +section + +open Additive Multiplicative + +instance Additive.vadd [SMul α β] : VAdd (Additive α) β where vadd a := (toMul a • ·) + +instance Multiplicative.smul [VAdd α β] : SMul (Multiplicative α) β where smul a := (toAdd a +ᵥ ·) + +@[simp] lemma toMul_smul [SMul α β] (a) (b : β) : (toMul a : α) • b = a +ᵥ b := rfl + +@[simp] lemma ofMul_vadd [SMul α β] (a : α) (b : β) : ofMul a +ᵥ b = a • b := rfl + +@[simp] lemma toAdd_vadd [VAdd α β] (a) (b : β) : (toAdd a : α) +ᵥ b = a • b := rfl + +@[simp] lemma ofAdd_smul [VAdd α β] (a : α) (b : β) : ofAdd a • b = a +ᵥ b := rfl + +-- Porting note: I don't know why `one_smul` can do without an explicit α and `mul_smul` can't. +instance Additive.addAction [Monoid α] [MulAction α β] : AddAction (Additive α) β where + zero_vadd := MulAction.one_smul + add_vadd := MulAction.mul_smul (α := α) + +instance Multiplicative.mulAction [AddMonoid α] [AddAction α β] : + MulAction (Multiplicative α) β where + one_smul := AddAction.zero_vadd + mul_smul := AddAction.add_vadd (G := α) + +instance Additive.vaddCommClass [SMul α γ] [SMul β γ] [SMulCommClass α β γ] : + VAddCommClass (Additive α) (Additive β) γ := + ⟨@smul_comm α β _ _ _ _⟩ + +instance Multiplicative.smulCommClass [VAdd α γ] [VAdd β γ] [VAddCommClass α β γ] : + SMulCommClass (Multiplicative α) (Multiplicative β) γ := + ⟨@vadd_comm α β _ _ _ _⟩ + +end + +/-- The tautological additive action by `Additive (Function.End α)` on `α`. -/ +instance AddAction.functionEnd : AddAction (Additive (Function.End α)) α := inferInstance + +/-- The additive monoid hom representing an additive monoid action. + +When `M` is a group, see `AddAction.toPermHom`. -/ +def AddAction.toEndHom [AddMonoid M] [AddAction M α] : M →+ Additive (Function.End α) := + MonoidHom.toAdditive'' MulAction.toEndHom + +/-- The additive action induced by a hom to `Additive (Function.End α)` + +See note [reducible non-instances]. -/ +abbrev AddAction.ofEndHom [AddMonoid M] (f : M →+ Additive (Function.End α)) : AddAction M α := + AddAction.compHom α f diff --git a/Mathlib/Algebra/Group/Action/Units.lean b/Mathlib/Algebra/Group/Action/Units.lean index b1b817a1fb920..f2a6ef61171a5 100644 --- a/Mathlib/Algebra/Group/Action/Units.lean +++ b/Mathlib/Algebra/Group/Action/Units.lean @@ -3,8 +3,9 @@ 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.Group.Action.Defs -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Action.Faithful +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Group.Units.Defs /-! # Group actions on and by `Mˣ` @@ -71,8 +72,8 @@ instance mulAction' [Group G] [Monoid M] [MulAction G M] [SMulCommClass G M M] ⟨g • (m : M), (g⁻¹ • ((m⁻¹ : Mˣ) : M)), by rw [smul_mul_smul_comm, Units.mul_inv, mul_inv_cancel, one_smul], by rw [smul_mul_smul_comm, Units.inv_mul, inv_mul_cancel, one_smul]⟩ - one_smul m := Units.ext <| one_smul _ _ - mul_smul g₁ g₂ m := Units.ext <| mul_smul _ _ _ + one_smul _ := Units.ext <| one_smul _ _ + mul_smul _ _ _ := Units.ext <| mul_smul _ _ _ @[to_additive (attr := simp)] lemma val_smul [Group G] [Monoid M] [MulAction G M] [SMulCommClass G M M] [IsScalarTower G M M] diff --git a/Mathlib/Algebra/Group/AddChar.lean b/Mathlib/Algebra/Group/AddChar.lean index f9a1d383c185c..23505cff4f752 100644 --- a/Mathlib/Algebra/Group/AddChar.lean +++ b/Mathlib/Algebra/Group/AddChar.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Michael Stoll. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Stoll -/ +import Mathlib.Algebra.Ring.Regular import Mathlib.Logic.Equiv.TransferInstance /-! @@ -88,7 +89,6 @@ instance instFunLike : FunLike (AddChar A M) A M where coe := AddChar.toFun coe_injective' φ ψ h := by cases φ; cases ψ; congr --- Porting note (#5229): added. @[ext] lemma ext (f g : AddChar A M) (h : ∀ x : A, f x = g x) : f = g := DFunLike.ext f g h diff --git a/Mathlib/Algebra/Group/Basic.lean b/Mathlib/Algebra/Group/Basic.lean index 244c63da588ad..84357784965a1 100644 --- a/Mathlib/Algebra/Group/Basic.lean +++ b/Mathlib/Algebra/Group/Basic.lean @@ -24,8 +24,6 @@ assert_not_exists DenselyOrdered open Function -universe u - variable {α β G M : Type*} section ite @@ -117,7 +115,7 @@ instance CommMagma.to_isCommutative [CommMagma G] : Std.Commutative (α := G) ( section MulOneClass -variable {M : Type u} [MulOneClass M] +variable [MulOneClass M] @[to_additive] theorem ite_mul_one {P : Prop} [Decidable P] {a b : M} : @@ -226,7 +224,7 @@ end CommMonoid section LeftCancelMonoid -variable {M : Type u} [LeftCancelMonoid M] {a b : M} +variable [LeftCancelMonoid M] {a b : M} @[to_additive (attr := simp)] theorem mul_right_eq_self : a * b = a ↔ b = 1 := calc @@ -247,7 +245,7 @@ end LeftCancelMonoid section RightCancelMonoid -variable {M : Type u} [RightCancelMonoid M] {a b : M} +variable [RightCancelMonoid M] {a b : M} @[to_additive (attr := simp)] theorem mul_left_eq_self : a * b = b ↔ a = 1 := calc @@ -426,7 +424,7 @@ lemma one_zpow : ∀ n : ℤ, (1 : α) ^ n = 1 @[to_additive (attr := simp) neg_zsmul] lemma zpow_neg (a : α) : ∀ n : ℤ, a ^ (-n) = (a ^ n)⁻¹ - | (n + 1 : ℕ) => DivInvMonoid.zpow_neg' _ _ + | (_ + 1 : ℕ) => DivInvMonoid.zpow_neg' _ _ | 0 => by change a ^ (0 : ℤ) = (a ^ (0 : ℤ))⁻¹ simp diff --git a/Mathlib/Algebra/Group/Center.lean b/Mathlib/Algebra/Group/Center.lean index de1591f22ebe2..d5fd79ac44d8c 100644 --- a/Mathlib/Algebra/Group/Center.lean +++ b/Mathlib/Algebra/Group/Center.lean @@ -5,8 +5,8 @@ Authors: Eric Wieser, Jireh Loreaux -/ import Mathlib.Algebra.Group.Commute.Units import Mathlib.Algebra.Group.Invertible.Basic -import Mathlib.Data.Set.Basic import Mathlib.Logic.Basic +import Mathlib.Data.Set.Basic /-! # Centers of magmas and semigroups @@ -70,7 +70,7 @@ attribute [to_additive existing] isMulCentral_iff namespace IsMulCentral -variable {a b c : M} [Mul M] +variable {a c : M} [Mul M] -- cf. `Commute.left_comm` @[to_additive] diff --git a/Mathlib/Algebra/Group/Conj.lean b/Mathlib/Algebra/Group/Conj.lean index 3dbb4606b7541..1c2dafc677b31 100644 --- a/Mathlib/Algebra/Group/Conj.lean +++ b/Mathlib/Algebra/Group/Conj.lean @@ -62,7 +62,7 @@ variable [CancelMonoid α] -- not generalised. @[simp] theorem isConj_one_right {a : α} : IsConj 1 a ↔ a = 1 := - ⟨fun ⟨c, hc⟩ => mul_right_cancel (hc.symm.trans ((mul_one _).trans (one_mul _).symm)), fun h => by + ⟨fun ⟨_, hc⟩ => mul_right_cancel (hc.symm.trans ((mul_one _).trans (one_mul _).symm)), fun h => by rw [h]⟩ @[simp] @@ -222,7 +222,7 @@ theorem mk_bijective : Function.Bijective (@ConjClasses.mk α _) := /-- The bijection between a `CommGroup` and its `ConjClasses`. -/ def mkEquiv : α ≃ ConjClasses α := - ⟨ConjClasses.mk, Quotient.lift id fun (a : α) b => isConj_iff_eq.1, Quotient.lift_mk _ _, by + ⟨ConjClasses.mk, Quotient.lift id fun (_ : α) _ => isConj_iff_eq.1, Quotient.lift_mk _ _, by rw [Function.RightInverse, Function.LeftInverse, forall_isConj] intro x rw [← quotient_mk_eq_mk, ← quotient_mk_eq_mk, Quotient.lift_mk, id]⟩ diff --git a/Mathlib/Algebra/Group/ConjFinite.lean b/Mathlib/Algebra/Group/ConjFinite.lean index a432f381360cd..aab17a8c4e97a 100644 --- a/Mathlib/Algebra/Group/ConjFinite.lean +++ b/Mathlib/Algebra/Group/ConjFinite.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ import Mathlib.Algebra.Group.Conj -import Mathlib.Data.Finite.Basic +import Mathlib.Data.Finite.Prod import Mathlib.Data.Fintype.Units /-! diff --git a/Mathlib/Algebra/Group/Defs.lean b/Mathlib/Algebra/Group/Defs.lean index cd436c8a8fdfc..119ee7ece01ce 100644 --- a/Mathlib/Algebra/Group/Defs.lean +++ b/Mathlib/Algebra/Group/Defs.lean @@ -35,7 +35,7 @@ actions and register the following instances: - `SMul ℕ M` for additive monoids `M`, and `SMul ℤ G` for additive groups `G`. `SMul` is typically, but not exclusively, used for scalar multiplication-like operators. -See the module `Algebra.AddTorsor` for a motivating example for the name `VAdd` (vector addition)`. +See the module `Algebra.AddTorsor` for a motivating example for the name `VAdd` (vector addition). ## Notation @@ -168,6 +168,73 @@ class Inv (α : Type u) where @[inherit_doc] postfix:max "⁻¹" => Inv.inv +section ite +variable {α : Type*} (P : Prop) [Decidable P] + +section Mul +variable [Mul α] + +@[to_additive] +lemma mul_dite (a : α) (b : P → α) (c : ¬ P → α) : + (a * if h : P then b h else c h) = if h : P then a * b h else a * c h := by split <;> rfl + +@[to_additive] +lemma mul_ite (a b c : α) : (a * if P then b else c) = if P then a * b else a * c := mul_dite .. + +@[to_additive] +lemma dite_mul (a : P → α) (b : ¬ P → α) (c : α) : + (if h : P then a h else b h) * c = if h : P then a h * c else b h * c := by split <;> rfl + +@[to_additive] +lemma ite_mul (a b c : α) : (if P then a else b) * c = if P then a * c else b * c := dite_mul .. + +-- We make `mul_ite` and `ite_mul` simp lemmas, but not `add_ite` or `ite_add`. +-- The problem we're trying to avoid is dealing with sums of the form `∑ x ∈ s, (f x + ite P 1 0)`, +-- in which `add_ite` followed by `sum_ite` would needlessly slice up +-- the `f x` terms according to whether `P` holds at `x`. +-- There doesn't appear to be a corresponding difficulty so far with `mul_ite` and `ite_mul`. +attribute [simp] mul_dite dite_mul mul_ite ite_mul + +@[to_additive] +lemma dite_mul_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : + ((if h : P then a h else b h) * if h : P then c h else d h) = + if h : P then a h * c h else b h * d h := by split <;> rfl + +@[to_additive] +lemma ite_mul_ite (a b c d : α) : + ((if P then a else b) * if P then c else d) = if P then a * c else b * d := by split <;> rfl + +end Mul + +section Div +variable [Div α] + +@[to_additive] +lemma div_dite (a : α) (b : P → α) (c : ¬ P → α) : + (a / if h : P then b h else c h) = if h : P then a / b h else a / c h := by split <;> rfl + +@[to_additive] +lemma div_ite (a b c : α) : (a / if P then b else c) = if P then a / b else a / c := div_dite .. + +@[to_additive] +lemma dite_div (a : P → α) (b : ¬ P → α) (c : α) : + (if h : P then a h else b h) / c = if h : P then a h / c else b h / c := by split <;> rfl + +@[to_additive] +lemma ite_div (a b c : α) : (if P then a else b) / c = if P then a / c else b / c := dite_div .. + +@[to_additive] +lemma dite_div_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : + ((if h : P then a h else b h) / if h : P then c h else d h) = + if h : P then a h / c h else b h / d h := by split <;> rfl + +@[to_additive] +lemma ite_div_ite (a b c d : α) : + ((if P then a else b) / if P then c else d) = if P then a / c else b / d := dite_div_dite .. + +end Div +end ite + section Mul variable [Mul G] @@ -516,6 +583,165 @@ needed. These problems do not come up in practice, so most of the time we will n the `npow` field when defining multiplicative objects. -/ +/-- +Scalar multiplication by repeated self-addition, +the additive version of exponentation by repeated squaring. +-/ +-- Ideally this would be generated by `@[to_additive]` from `npowBinRec`. +def nsmulBinRec {M : Type*} [Zero M] [Add M] (k : ℕ) (m : M) : M := + go k 0 m +where + /-- Auxiliary tail-recursive implementation for `nsmulBinRec`-/ + go : ℕ → M → M → M + | 0, y, _ => y + | (k + 1), y, x => + let k' := (k + 1) >>> 1 + if k &&& 1 = 1 then + go k' y (x + x) + else + go k' (y + x) (x + x) + +/-- Exponentiation by repeated squaring. -/ +@[to_additive existing] +def npowBinRec {M : Type*} [One M] [Mul M] (k : ℕ) (m : M) : M := + go k 1 m +where + /-- Auxiliary tail-recursive implementation for `npowBinRec`-/ + go : ℕ → M → M → M + | 0, y, _ => y + | (k + 1), y, x => + let k' := (k + 1) >>> 1 + if k &&& 1 = 1 then + go k' y (x * x) + else + go k' (y * x) (x * x) + +attribute [to_additive existing] npowBinRec.go + +/-- +A variant of `npowRec` which is a semigroup homomorphisms from `ℕ₊` to `M`. +-/ +def npowRec' {M : Type*} [One M] [Mul M] : ℕ → M → M + | 0, _ => 1 + | 1, m => m + | k + 2, m => npowRec' (k + 1) m * m + +/-- +A variant of `nsmulRec` which is a semigroup homomorphisms from `ℕ₊` to `M`. +-/ +def nsmulRec' {M : Type*} [Zero M] [Add M] : ℕ → M → M + | 0, _ => 0 + | 1, m => m + | k + 2, m => nsmulRec' (k + 1) m + m + +attribute [to_additive existing] npowRec' + +@[to_additive] +theorem npowRec'_succ {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : + npowRec' (k + 2) m = npowRec' (k + 1) m * m := by + rfl + +@[to_additive] +theorem npowRec'_two_mul {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : + npowRec' (2 * k) m = npowRec' k (m * m) := by + induction k using Nat.strongRecOn with + | ind k' ih => + match k' with + | 0 => rfl + | 1 => simp [npowRec'] + | k + 2 => simp [npowRec', ← mul_assoc, ← ih] + +@[to_additive] +theorem npowRec'_mul_comm {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : + m * npowRec' (k + 1) m = npowRec' (k + 1) m * m := by + induction k using Nat.strongRecOn with + | ind k' ih => + match k' with + | 0 => rfl + | 1 => simp [npowRec', mul_assoc] + | k + 2 => simp [npowRec', ← mul_assoc, ih] + +@[to_additive] +theorem npowRec_eq {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : + npowRec (k + 1) m = 1 * npowRec' (k + 1) m := by + induction k using Nat.strongRecOn with + | ind k' ih => + match k' with + | 0 => rfl + | k + 1 => + rw [npowRec, npowRec'_succ, ← mul_assoc] + congr + simp [ih] + +@[to_additive] +theorem npowBinRec.go_spec {M : Type*} [Semigroup M] [One M] (k : ℕ) (m n : M) : + npowBinRec.go (k + 1) m n = m * npowRec' (k + 1) n := by + induction k using Nat.strongRecOn generalizing m n with + | ind k' ih => + cases k' with + | zero => simp [go, npowRec'] + | succ k' => + rw [go] + split <;> rename_i w <;> rw [(by omega : (k' + 1 + 1) >>> 1 = k' >>> 1 + 1)] + · rw [ih] + · congr 1 + rw [← npowRec'_two_mul] + congr 1 + rw [Nat.shiftRight_eq_div_pow, Nat.pow_one, Nat.mul_add, Nat.mul_div_cancel'] + simp only [Nat.and_one_is_mod] at w + omega + · omega + · rw [ih] + · rw [mul_assoc] + rw [← npowRec'_two_mul] + congr 1 + conv => + rhs + rw [npowRec'] + rw [← npowRec'_mul_comm] + congr 2 + · rw [Nat.shiftRight_eq_div_pow, Nat.pow_one] + simp only [Nat.and_one_is_mod] at w + omega + · omega +/-- +An abbreviation for `npowRec` with an additional typeclass assumption on associativity +so that we can use `@[csimp]` to replace it with an implementation by repeated squaring +in compiled code. +-/ +@[to_additive +"An abbreviation for `nsmulRec` with an additional typeclass assumptions on associativity +so that we can use `@[csimp]` to replace it with an implementation by repeated doubling in compiled +code as an automatic parameter."] +abbrev npowRecAuto {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : M := + npowRec k m + +/-- +An abbreviation for `npowBinRec` with an additional typeclass assumption on associativity +so that we can use it in `@[csimp]` for more performant code generation. +-/ +@[to_additive +"An abbreviation for `nsmulBinRec` with an additional typeclass assumption on associativity +so that we can use it in `@[csimp]` for more performant code generation +as an automatic parameter."] +abbrev npowBinRecAuto {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : M := + npowBinRec k m + +@[csimp] +theorem nsmulRec_eq_nsmulBinRec : @nsmulRecAuto = @nsmulBinRecAuto := by + funext M _ _ k m + rw [nsmulBinRecAuto, nsmulRecAuto, nsmulBinRec] + match k with + | 0 => rw [nsmulRec, nsmulBinRec.go] + | k + 1 => rw [nsmulBinRec.go_spec, nsmulRec_eq] + +@[csimp] +theorem npowRec_eq_npowBinRec : @npowRecAuto = @npowBinRecAuto := by + funext M _ _ k m + rw [npowBinRecAuto, npowRecAuto, npowBinRec] + match k with + | 0 => rw [npowRec, npowBinRec.go] + | k + 1 => rw [npowBinRec.go_spec, npowRec_eq] /-- An `AddMonoid` is an `AddSemigroup` with an element `0` such that `0 + a = a + 0 = a`. -/ class AddMonoid (M : Type u) extends AddSemigroup M, AddZeroClass M where @@ -534,7 +760,7 @@ attribute [instance 50] AddZeroClass.toAdd @[to_additive] class Monoid (M : Type u) extends Semigroup M, MulOneClass M where /-- Raising to the power of a natural number. -/ - protected npow : ℕ → M → M := npowRec + protected npow : ℕ → M → M := npowRecAuto /-- Raising to the power `(0 : ℕ)` gives `1`. -/ protected npow_zero : ∀ x, npow 0 x = 1 := by intros; rfl /-- Raising to the power `(n + 1 : ℕ)` behaves as expected. -/ @@ -807,7 +1033,7 @@ class DivInvMonoid (G : Type u) extends Monoid G, Inv G, Div G where /-- `a ^ 0 = 1` -/ protected zpow_zero' : ∀ a : G, zpow 0 a = 1 := by intros; rfl /-- `a ^ (n + 1) = a ^ n * a` -/ - protected zpow_succ' (n : ℕ) (a : G) : zpow (Int.ofNat n.succ) a = zpow (Int.ofNat n) a * a := by + protected zpow_succ' (n : ℕ) (a : G) : zpow n.succ a = zpow n a * a := by intros; rfl /-- `a ^ -(n + 1) = (a ^ (n + 1))⁻¹` -/ protected zpow_neg' (n : ℕ) (a : G) : zpow (Int.negSucc n) a = (zpow n.succ a)⁻¹ := by intros; rfl @@ -848,7 +1074,7 @@ class SubNegMonoid (G : Type u) extends AddMonoid G, Neg G, Sub G where protected zsmul : ℤ → G → G protected zsmul_zero' : ∀ a : G, zsmul 0 a = 0 := by intros; rfl protected zsmul_succ' (n : ℕ) (a : G) : - zsmul (Int.ofNat n.succ) a = zsmul (Int.ofNat n) a + a := by + zsmul n.succ a = zsmul n a + a := by intros; rfl protected zsmul_neg' (n : ℕ) (a : G) : zsmul (Int.negSucc n) a = -zsmul n.succ a := by intros; rfl @@ -1050,7 +1276,7 @@ attribute [to_additive] Group section Group -variable [Group G] {a b c : G} +variable [Group G] {a b : G} @[to_additive (attr := simp)] theorem inv_mul_cancel (a : G) : a⁻¹ * a = 1 := diff --git a/Mathlib/Algebra/Group/Equiv/Basic.lean b/Mathlib/Algebra/Group/Equiv/Basic.lean index c95faf764777a..b11426351ebef 100644 --- a/Mathlib/Algebra/Group/Equiv/Basic.lean +++ b/Mathlib/Algebra/Group/Equiv/Basic.lean @@ -28,7 +28,7 @@ Equiv, MulEquiv, AddEquiv open Function -variable {F α β A B M N P Q G H : Type*} +variable {F α β M N P G H : Type*} /-- Makes a `OneHom` inverse from the bijective inverse of a `OneHom` -/ @[to_additive (attr := simps) @@ -168,7 +168,7 @@ theorem MulEquivClass.toMulEquiv_injective [Mul α] [Mul β] [MulEquivClass F α namespace MulEquiv section Mul -variable [Mul M] [Mul N] [Mul P] [Mul Q] +variable [Mul M] [Mul N] [Mul P] section coe @@ -265,7 +265,6 @@ protected theorem injective (e : M ≃* N) : Function.Injective e := protected theorem surjective (e : M ≃* N) : Function.Surjective e := EquivLike.surjective e --- Porting note (#10618): `simp` can prove this @[to_additive] theorem apply_eq_iff_eq (e : M ≃* N) {x y : M} : e x = e y ↔ x = y := e.injective.eq_iff @@ -472,11 +471,13 @@ end Mul section MulOneClass variable [MulOneClass M] [MulOneClass N] [MulOneClass P] --- Porting note (#10618): `simp` can prove this +-- Porting note (#10618): `simp` can prove this but it is a valid `dsimp` lemma. +-- However, we would need to redesign the the `dsimp` set to make this `@[simp]`. @[to_additive] theorem coe_monoidHom_refl : (refl M : M →* M) = MonoidHom.id M := rfl --- Porting note (#10618): `simp` can prove this +-- Porting note (#10618): `simp` can prove this but it is a valid `dsimp` lemma. +-- However, we would need to redesign the the `dsimp` set to make this `@[simp]`. @[to_additive] lemma coe_monoidHom_trans (e₁ : M ≃* N) (e₂ : N ≃* P) : (e₁.trans e₂ : M →* P) = (e₂ : N →* P).comp ↑e₁ := rfl diff --git a/Mathlib/Algebra/Group/Even.lean b/Mathlib/Algebra/Group/Even.lean index 428970edc8bf0..5bd24647c2f65 100644 --- a/Mathlib/Algebra/Group/Even.lean +++ b/Mathlib/Algebra/Group/Even.lean @@ -34,7 +34,7 @@ assert_not_exists DenselyOrdered open MulOpposite -variable {F α β R : Type*} +variable {F α β : Type*} section Mul variable [Mul α] diff --git a/Mathlib/Algebra/Group/EvenFunction.lean b/Mathlib/Algebra/Group/EvenFunction.lean index 3896969ce6795..81ddf35dcd57c 100644 --- a/Mathlib/Algebra/Group/EvenFunction.lean +++ b/Mathlib/Algebra/Group/EvenFunction.lean @@ -3,9 +3,9 @@ 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.Algebra.Group.Action.Pi -import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.BigOperators.Group.Finset +import Mathlib.Algebra.Group.Action.Pi +import Mathlib.Algebra.NoZeroSMulDivisors.Basic /-! # Even and odd functions @@ -18,8 +18,6 @@ conflicting with the root-level definitions `Even` and `Odd` (which, for functio function takes even resp. odd _values_, a wholly different concept). -/ -open scoped BigOperators - namespace Function variable {α β : Type*} [Neg α] diff --git a/Mathlib/Algebra/Group/Fin/Basic.lean b/Mathlib/Algebra/Group/Fin/Basic.lean index d9710b7aedc23..06f0bb2f7ad67 100644 --- a/Mathlib/Algebra/Group/Fin/Basic.lean +++ b/Mathlib/Algebra/Group/Fin/Basic.lean @@ -23,7 +23,7 @@ assert_not_exists MonoidWithZero open Nat namespace Fin -variable {m n : ℕ} +variable {n : ℕ} /-! ### Instances -/ @@ -43,7 +43,7 @@ instance addCommMonoid (n : ℕ) [NeZero n] : AddCommMonoid (Fin n) where instance instAddMonoidWithOne (n) [NeZero n] : AddMonoidWithOne (Fin n) where __ := inferInstanceAs (AddCommMonoid (Fin n)) - natCast n := Fin.ofNat'' n + natCast i := Fin.ofNat' n i natCast_zero := rfl natCast_succ _ := Fin.ext (add_mod _ _ _) diff --git a/Mathlib/Algebra/Group/Hom/Basic.lean b/Mathlib/Algebra/Group/Hom/Basic.lean index 094fd70d45cc5..114dff59a75ba 100644 --- a/Mathlib/Algebra/Group/Hom/Basic.lean +++ b/Mathlib/Algebra/Group/Hom/Basic.lean @@ -16,7 +16,7 @@ import Mathlib.Algebra.Group.Hom.Defs -- `Algebra.Group` folder. assert_not_imported Mathlib.Algebra.NeZero -variable {α β M N P : Type*} +variable {α M N P : Type*} -- monoids variable {G : Type*} {H : Type*} @@ -98,7 +98,7 @@ end MulHom namespace MonoidHom section Group -variable [Group G] [CommGroup H] +variable [Group G] /-- A homomorphism from a group to a monoid is injective iff its kernel is trivial. For the iff statement on the triviality of the kernel, see `injective_iff_map_eq_one'`. -/ @@ -109,7 +109,7 @@ For the iff statement on the triviality of the kernel, see `injective_iff_map_eq theorem _root_.injective_iff_map_eq_one {G H} [Group G] [MulOneClass H] [FunLike F G H] [MonoidHomClass F G H] (f : F) : Function.Injective f ↔ ∀ a, f a = 1 → a = 1 := - ⟨fun h x => (map_eq_one_iff f h).mp, fun h x y hxy => + ⟨fun h _ => (map_eq_one_iff f h).mp, fun h x y hxy => mul_inv_eq_one.1 <| h _ <| by rw [map_mul, hxy, ← map_mul, mul_inv_cancel, map_one]⟩ /-- A homomorphism from a group to a monoid is injective iff its kernel is trivial, @@ -125,8 +125,6 @@ theorem _root_.injective_iff_map_eq_one' {G H} [Group G] [MulOneClass H] (injective_iff_map_eq_one f).trans <| forall_congr' fun _ => ⟨fun h => ⟨h, fun H => H.symm ▸ map_one f⟩, Iff.mp⟩ -variable [MulOneClass M] - /-- Makes a group homomorphism from a proof that the map preserves right division `fun x y => x * y⁻¹`. See also `MonoidHom.of_map_div` for a version using `fun x y => x / y`. -/ diff --git a/Mathlib/Algebra/Group/Hom/Defs.lean b/Mathlib/Algebra/Group/Hom/Defs.lean index 1a3bf932f98fd..14f51627f6d9d 100644 --- a/Mathlib/Algebra/Group/Hom/Defs.lean +++ b/Mathlib/Algebra/Group/Hom/Defs.lean @@ -867,7 +867,7 @@ instance : Monoid (Monoid.End M) where mul_one := MonoidHom.comp_id one_mul := MonoidHom.id_comp npow n f := (npowRec n f).copy f^[n] <| by induction n <;> simp [npowRec, *] <;> rfl - npow_succ n f := DFunLike.coe_injective <| Function.iterate_succ _ _ + npow_succ _ _ := DFunLike.coe_injective <| Function.iterate_succ _ _ instance : Inhabited (Monoid.End M) := ⟨1⟩ @@ -908,7 +908,7 @@ instance monoid : Monoid (AddMonoid.End A) where mul_one := AddMonoidHom.comp_id one_mul := AddMonoidHom.id_comp npow n f := (npowRec n f).copy (Nat.iterate f n) <| by induction n <;> simp [npowRec, *] <;> rfl - npow_succ n f := DFunLike.coe_injective <| Function.iterate_succ _ _ + npow_succ _ _ := DFunLike.coe_injective <| Function.iterate_succ _ _ @[simp, norm_cast] lemma coe_pow (f : AddMonoid.End A) (n : ℕ) : (↑(f ^ n) : A → A) = f^[n] := rfl diff --git a/Mathlib/Algebra/Group/Hom/End.lean b/Mathlib/Algebra/Group/Hom/End.lean index 00405f5550e0e..caa7de5333f3d 100644 --- a/Mathlib/Algebra/Group/Hom/End.lean +++ b/Mathlib/Algebra/Group/Hom/End.lean @@ -19,9 +19,9 @@ They are separate, and if someone would like to split this file in two that may -/ -universe uM uN uP uQ +universe uM -variable {M : Type uM} {N : Type uN} {P : Type uP} {Q : Type uQ} +variable {M : Type uM} namespace AddMonoid.End @@ -121,7 +121,7 @@ end Semiring section CommSemiring -variable {R S : Type*} [NonUnitalNonAssocCommSemiring R] +variable {R : Type*} [NonUnitalNonAssocCommSemiring R] namespace AddMonoid.End diff --git a/Mathlib/Algebra/Group/Indicator.lean b/Mathlib/Algebra/Group/Indicator.lean index ccb3633809bca..b30e9c0da0970 100644 --- a/Mathlib/Algebra/Group/Indicator.lean +++ b/Mathlib/Algebra/Group/Indicator.lean @@ -5,6 +5,7 @@ Authors: Zhouhang Zhou -/ import Mathlib.Algebra.Group.Pi.Lemmas import Mathlib.Algebra.Group.Support +import Mathlib.Data.Set.SymmDiff /-! # Indicator function @@ -33,7 +34,7 @@ assert_not_exists MonoidWithZero open Function -variable {α β ι M N : Type*} +variable {α β M N : Type*} namespace Set @@ -94,7 +95,7 @@ theorem mulIndicator_apply_eq_one : mulIndicator s f a = 1 ↔ a ∈ s → f a = ite_eq_right_iff @[to_additive (attr := simp)] -theorem mulIndicator_eq_one : (mulIndicator s f = fun x => 1) ↔ Disjoint (mulSupport f) s := by +theorem mulIndicator_eq_one : (mulIndicator s f = fun _ => 1) ↔ Disjoint (mulSupport f) s := by simp only [funext_iff, mulIndicator_apply_eq_one, Set.disjoint_left, mem_mulSupport, not_imp_not] @@ -262,7 +263,7 @@ end One section Monoid -variable [MulOneClass M] {s t : Set α} {f g : α → M} {a : α} +variable [MulOneClass M] {s t : Set α} {a : α} @[to_additive] theorem mulIndicator_union_mul_inter_apply (f : α → M) (s t : Set α) (a : α) : @@ -360,7 +361,7 @@ end Monoid section Group -variable {G : Type*} [Group G] {s t : Set α} {f g : α → G} {a : α} +variable {G : Type*} [Group G] {s t : Set α} @[to_additive] theorem mulIndicator_inv' (s : Set α) (f : α → G) : mulIndicator s f⁻¹ = (mulIndicator s f)⁻¹ := diff --git a/Mathlib/Algebra/Group/InjSurj.lean b/Mathlib/Algebra/Group/InjSurj.lean index a47bbde22c75a..c25210c59545a 100644 --- a/Mathlib/Algebra/Group/InjSurj.lean +++ b/Mathlib/Algebra/Group/InjSurj.lean @@ -55,7 +55,7 @@ a semigroup. See note [reducible non-instances]. -/ injective map that preserves `+` to an additive semigroup."] protected abbrev semigroup [Semigroup M₂] (f : M₁ → M₂) (hf : Injective f) (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₁ := - { ‹Mul M₁› with mul_assoc := fun x y z => hf <| by erw [mul, mul, mul, mul, mul_assoc] } + { ‹Mul M₁› with mul_assoc := fun x y z => hf <| by rw [mul, mul, mul, mul, mul_assoc] } /-- A type endowed with `*` is a commutative magma, if it admits a surjective map that preserves `*` from a commutative magma. -/ @@ -83,7 +83,7 @@ semigroup, if it admits an injective map that preserves `+` to an additive left protected abbrev leftCancelSemigroup [LeftCancelSemigroup M₂] (f : M₁ → M₂) (hf : Injective f) (mul : ∀ x y, f (x * y) = f x * f y) : LeftCancelSemigroup M₁ := { hf.semigroup f mul with - mul_left_cancel := fun x y z H => hf <| (mul_right_inj (f x)).1 <| by erw [← mul, ← mul, H] } + mul_left_cancel := fun x y z H => hf <| (mul_right_inj (f x)).1 <| by rw [← mul, ← mul, H] } /-- A type endowed with `*` is a right cancel semigroup, if it admits an injective map that preserves `*` to a right cancel semigroup. See note [reducible non-instances]. -/ @@ -93,7 +93,7 @@ semigroup."] protected abbrev rightCancelSemigroup [RightCancelSemigroup M₂] (f : M₁ → M₂) (hf : Injective f) (mul : ∀ x y, f (x * y) = f x * f y) : RightCancelSemigroup M₁ := { hf.semigroup f mul with - mul_right_cancel := fun x y z H => hf <| (mul_left_inj (f y)).1 <| by erw [← mul, ← mul, H] } + mul_right_cancel := fun x y z H => hf <| (mul_left_inj (f y)).1 <| by rw [← mul, ← mul, H] } variable [One M₁] @@ -105,8 +105,8 @@ injective map that preserves `0` and `+` to an `AddZeroClass`."] protected abbrev mulOneClass [MulOneClass M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₁ := { ‹One M₁›, ‹Mul M₁› with - one_mul := fun x => hf <| by erw [mul, one, one_mul], - mul_one := fun x => hf <| by erw [mul, one, mul_one] } + one_mul := fun x => hf <| by rw [mul, one, one_mul], + mul_one := fun x => hf <| by rw [mul, one, mul_one] } variable [Pow M₁ ℕ] @@ -120,8 +120,8 @@ protected abbrev monoid [Monoid M₂] (f : M₁ → M₂) (hf : Injective f) (on (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₁ := { hf.mulOneClass f one mul, hf.semigroup f mul with npow := fun n x => x ^ n, - npow_zero := fun x => hf <| by erw [npow, one, pow_zero], - npow_succ := fun n x => hf <| by erw [npow, pow_succ, mul, npow] } + npow_zero := fun x => hf <| by rw [npow, one, pow_zero], + npow_succ := fun n x => hf <| by rw [npow, pow_succ, mul, npow] } /-- A type endowed with `0`, `1` and `+` is an additive monoid with one, if it admits an injective map that preserves `0`, `1` and `+` to an additive monoid with one. @@ -132,8 +132,8 @@ protected abbrev addMonoidWithOne {M₁} [Zero M₁] [One M₁] [Add M₁] [SMul (natCast : ∀ n : ℕ, f n = n) : AddMonoidWithOne M₁ := { hf.addMonoid f zero add (swap nsmul) with natCast := Nat.cast, - natCast_zero := hf (by erw [natCast, Nat.cast_zero, zero]), - natCast_succ := fun n => hf (by erw [natCast, Nat.cast_succ, add, one, natCast]), one := 1 } + natCast_zero := hf (by rw [natCast, Nat.cast_zero, zero]), + natCast_succ := fun n => hf (by rw [natCast, Nat.cast_succ, add, one, natCast]), one := 1 } /-- A type endowed with `1` and `*` is a left cancel monoid, if it admits an injective map that preserves `1` and `*` to a left cancel monoid. See note [reducible non-instances]. -/ @@ -215,7 +215,7 @@ injective map that preserves `0` and unary `-` to an `NegZeroClass`."] protected abbrev invOneClass [InvOneClass M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) : InvOneClass M₁ := { ‹One M₁›, ‹Inv M₁› with - inv_one := hf <| by erw [inv, one, inv_one] } + inv_one := hf <| by rw [inv, one, inv_one] } variable [Div M₁] [Pow M₁ ℤ] @@ -232,10 +232,10 @@ protected abbrev divInvMonoid [DivInvMonoid M₂] (f : M₁ → M₂) (hf : Inje (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₁ := { hf.monoid f one mul npow, ‹Inv M₁›, ‹Div M₁› with zpow := fun n x => x ^ n, - zpow_zero' := fun x => hf <| by erw [zpow, zpow_zero, one], - zpow_succ' := fun n x => hf <| by erw [zpow, mul, zpow_natCast, pow_succ, zpow, zpow_natCast], - zpow_neg' := fun n x => hf <| by erw [zpow, zpow_negSucc, inv, zpow, zpow_natCast], - div_eq_mul_inv := fun x y => hf <| by erw [div, mul, inv, div_eq_mul_inv] } + zpow_zero' := fun x => hf <| by rw [zpow, zpow_zero, one], + zpow_succ' := fun n x => hf <| by rw [zpow, mul, zpow_natCast, pow_succ, zpow, zpow_natCast], + zpow_neg' := fun n x => hf <| by rw [zpow, zpow_negSucc, inv, zpow, zpow_natCast], + div_eq_mul_inv := fun x y => hf <| by rw [div, mul, inv, div_eq_mul_inv] } /-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivInvOneMonoid` if it admits an injective map that preserves `1`, `*`, `⁻¹`, and `/` to a `DivInvOneMonoid`. See note @@ -263,9 +263,9 @@ protected abbrev divisionMonoid [DivisionMonoid M₂] (f : M₁ → M₂) (hf : (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivisionMonoid M₁ := { hf.divInvMonoid f one mul inv div npow zpow, hf.involutiveInv f inv with - mul_inv_rev := fun x y => hf <| by erw [inv, mul, mul_inv_rev, mul, inv, inv], + mul_inv_rev := fun x y => hf <| by rw [inv, mul, mul_inv_rev, mul, inv, inv], inv_eq_of_mul := fun x y h => hf <| by - erw [inv, inv_eq_of_mul_eq_one_right (by erw [← mul, h, one])] } + rw [inv, inv_eq_of_mul_eq_one_right (by rw [← mul, h, one])] } /-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivisionCommMonoid` if it admits an injective map that preserves `1`, `*`, `⁻¹`, and `/` to a `DivisionCommMonoid`. @@ -291,7 +291,7 @@ protected abbrev group [Group M₂] (f : M₁ → M₂) (hf : Injective f) (one (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : Group M₁ := { hf.divInvMonoid f one mul inv div npow zpow with - inv_mul_cancel := fun x => hf <| by erw [mul, inv, inv_mul_cancel, one] } + inv_mul_cancel := fun x => hf <| by rw [mul, inv, inv_mul_cancel, one] } /-- A type endowed with `0`, `1` and `+` is an additive group with one, if it admits an injective map that preserves `0`, `1` and `+` to an additive group with one. See note @@ -306,7 +306,7 @@ protected abbrev addGroupWithOne {M₁} [Zero M₁] [One M₁] [Add M₁] [SMul hf.addMonoidWithOne f zero one add nsmul natCast with intCast := Int.cast, intCast_ofNat := fun n => hf (by rw [natCast, ← Int.cast, intCast, Int.cast_natCast]), - intCast_negSucc := fun n => hf (by erw [intCast, neg, natCast, Int.cast_negSucc] ) } + intCast_negSucc := fun n => hf (by rw [intCast, neg, natCast, Int.cast_negSucc] ) } /-- A type endowed with `1`, `*` and `⁻¹` is a commutative group, if it admits an injective map that preserves `1`, `*` and `⁻¹` to a commutative group. See note [reducible non-instances]. -/ @@ -358,7 +358,7 @@ protected abbrev semigroup [Semigroup M₁] (f : M₁ → M₂) (hf : Surjective a surjective map that preserves `+` from an additive commutative semigroup."] protected abbrev commMagma [CommMagma M₁] (f : M₁ → M₂) (hf : Surjective f) (mul : ∀ x y, f (x * y) = f x * f y) : CommMagma M₂ where - mul_comm := hf.forall₂.2 fun x y => by erw [← mul, ← mul, mul_comm] + mul_comm := hf.forall₂.2 fun x y => by rw [← mul, ← mul, mul_comm] /-- A type endowed with `*` is a commutative semigroup, if it admits a surjective map that preserves `*` from a commutative semigroup. See note [reducible non-instances]. -/ @@ -380,8 +380,8 @@ surjective map that preserves `0` and `+` to an `AddZeroClass`."] protected abbrev mulOneClass [MulOneClass M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₂ := { ‹One M₂›, ‹Mul M₂› with - one_mul := hf.forall.2 fun x => by erw [← one, ← mul, one_mul], - mul_one := hf.forall.2 fun x => by erw [← one, ← mul, mul_one] } + one_mul := hf.forall.2 fun x => by rw [← one, ← mul, one_mul], + mul_one := hf.forall.2 fun x => by rw [← one, ← mul, mul_one] } variable [Pow M₂ ℕ] @@ -395,10 +395,10 @@ protected abbrev monoid [Monoid M₁] (f : M₁ → M₂) (hf : Surjective f) (o (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₂ := { hf.semigroup f mul, hf.mulOneClass f one mul with npow := fun n x => x ^ n, - npow_zero := hf.forall.2 fun x => by dsimp only; erw [← npow, pow_zero, ← one], + npow_zero := hf.forall.2 fun x => by dsimp only; rw [← npow, pow_zero, ← one], npow_succ := fun n => hf.forall.2 fun x => by dsimp only - erw [← npow, pow_succ, ← npow, ← mul] } + rw [← npow, pow_succ, ← npow, ← mul] } /-- A type endowed with `0`, `1` and `+` is an additive monoid with one, if it admits a surjective map that preserves `0`, `1` and `*` from an additive monoid with one. See note @@ -441,7 +441,7 @@ preserves `-` to a type which has an involutive negation."] protected abbrev involutiveInv {M₂ : Type*} [Inv M₂] [InvolutiveInv M₁] (f : M₁ → M₂) (hf : Surjective f) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) : InvolutiveInv M₂ where inv := Inv.inv - inv_inv := hf.forall.2 fun x => by erw [← inv, ← inv, inv_inv] + inv_inv := hf.forall.2 fun x => by rw [← inv, ← inv, inv_inv] variable [Inv M₂] [Div M₂] [Pow M₂ ℤ] @@ -457,14 +457,14 @@ protected abbrev divInvMonoid [DivInvMonoid M₁] (f : M₁ → M₂) (hf : Surj (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₂ := { hf.monoid f one mul npow, ‹Div M₂›, ‹Inv M₂› with zpow := fun n x => x ^ n, - zpow_zero' := hf.forall.2 fun x => by dsimp only; erw [← zpow, zpow_zero, ← one], + zpow_zero' := hf.forall.2 fun x => by dsimp only; rw [← zpow, zpow_zero, ← one], zpow_succ' := fun n => hf.forall.2 fun x => by dsimp only - erw [← zpow, ← zpow, zpow_natCast, zpow_natCast, pow_succ, ← mul], + rw [← zpow, ← zpow, zpow_natCast, zpow_natCast, pow_succ, ← mul], zpow_neg' := fun n => hf.forall.2 fun x => by dsimp only - erw [← zpow, ← zpow, zpow_negSucc, zpow_natCast, inv], - div_eq_mul_inv := hf.forall₂.2 fun x y => by erw [← inv, ← mul, ← div, div_eq_mul_inv] } + rw [← zpow, ← zpow, zpow_negSucc, zpow_natCast, inv], + div_eq_mul_inv := hf.forall₂.2 fun x y => by rw [← inv, ← mul, ← div, div_eq_mul_inv] } /-- A type endowed with `1`, `*` and `⁻¹` is a group, if it admits a surjective map that preserves `1`, `*` and `⁻¹` to a group. See note [reducible non-instances]. -/ @@ -476,7 +476,7 @@ protected abbrev group [Group M₁] (f : M₁ → M₂) (hf : Surjective f) (one (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : Group M₂ := { hf.divInvMonoid f one mul inv div npow zpow with - inv_mul_cancel := hf.forall.2 fun x => by erw [← inv, ← mul, inv_mul_cancel, one] } + inv_mul_cancel := hf.forall.2 fun x => by rw [← inv, ← mul, inv_mul_cancel, one] } /-- A type endowed with `0`, `1`, `+` is an additive group with one, if it admits a surjective map that preserves `0`, `1`, and `+` to an additive group with one. diff --git a/Mathlib/Algebra/Group/Int.lean b/Mathlib/Algebra/Group/Int.lean index 720440a2282fb..d0d47342d4add 100644 --- a/Mathlib/Algebra/Group/Int.lean +++ b/Mathlib/Algebra/Group/Int.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad -/ import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Data.Int.Sqrt /-! @@ -47,7 +48,7 @@ instance instAddCommGroup : AddCommGroup ℤ where zsmul := (·*·) zsmul_zero' := Int.zero_mul zsmul_succ' m n := by - simp only [ofNat_eq_coe, ofNat_succ, Int.add_mul, Int.add_comm, Int.one_mul] + simp only [ofNat_succ, Int.add_mul, Int.add_comm, Int.one_mul] zsmul_neg' m n := by simp only [negSucc_coe, ofNat_succ, Int.neg_mul] sub_eq_add_neg _ _ := Int.sub_eq_add_neg @@ -145,13 +146,10 @@ lemma ofNat_isUnit {n : ℕ} : IsUnit (n : ℤ) ↔ IsUnit n := by simp [isUnit_ lemma isUnit_mul_self (hu : IsUnit u) : u * u = 1 := (isUnit_eq_one_or hu).elim (fun h ↦ h.symm ▸ rfl) fun h ↦ h.symm ▸ rfl --- Porting note: this was proven in mathlib3 with `tidy` which hasn't been ported yet lemma isUnit_add_isUnit_eq_isUnit_add_isUnit {a b c d : ℤ} (ha : IsUnit a) (hb : IsUnit b) (hc : IsUnit c) (hd : IsUnit d) : a + b = c + d ↔ a = c ∧ b = d ∨ a = d ∧ b = c := by rw [isUnit_iff] at ha hb hc hd - cases ha <;> cases hb <;> cases hc <;> cases hd <;> - subst a <;> subst b <;> subst c <;> subst d <;> - simp (config := {decide := true}) + aesop lemma eq_one_or_neg_one_of_mul_eq_neg_one (h : u * v = -1) : u = 1 ∨ u = -1 := Or.elim (eq_one_or_neg_one_of_mul_eq_neg_one' h) (fun H => Or.inl H.1) fun H => Or.inr H.1 diff --git a/Mathlib/Algebra/Group/Nat.lean b/Mathlib/Algebra/Group/Nat.lean index 8ccb770e633d4..16a01aab071b6 100644 --- a/Mathlib/Algebra/Group/Nat.lean +++ b/Mathlib/Algebra/Group/Nat.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Algebra.Group.Even -import Mathlib.Algebra.Group.Units import Mathlib.Data.Nat.Sqrt /-! diff --git a/Mathlib/Algebra/Group/Opposite.lean b/Mathlib/Algebra/Group/Opposite.lean index d7ea15a86adfe..147c42a01e34a 100644 --- a/Mathlib/Algebra/Group/Opposite.lean +++ b/Mathlib/Algebra/Group/Opposite.lean @@ -6,7 +6,7 @@ Authors: Kenny Lau import Mathlib.Algebra.Group.Commute.Defs import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.InjSurj -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Defs import Mathlib.Algebra.Opposites import Mathlib.Data.Int.Cast.Defs import Mathlib.Tactic.Spread @@ -161,7 +161,6 @@ instance instDivInvMonoid [DivInvMonoid α] : DivInvMonoid αᵐᵒᵖ where zpow n a := op <| a.unop ^ n zpow_zero' _ := unop_injective <| zpow_zero _ zpow_succ' _ _ := unop_injective <| by - simp only [Int.ofNat_eq_coe] rw [unop_op, zpow_natCast, pow_succ', unop_mul, unop_op, zpow_natCast] zpow_neg' _ _ := unop_injective <| DivInvMonoid.zpow_neg' _ _ @@ -424,7 +423,7 @@ def MonoidHom.fromOpposite {M N : Type*} [MulOneClass M] [MulOneClass N] (f : M def Units.opEquiv {M} [Monoid M] : Mᵐᵒᵖˣ ≃* Mˣᵐᵒᵖ where toFun u := op ⟨unop u, unop ↑u⁻¹, op_injective u.4, op_injective u.3⟩ invFun := MulOpposite.rec' fun u => ⟨op ↑u, op ↑u⁻¹, unop_injective <| u.4, unop_injective u.3⟩ - map_mul' x y := unop_injective <| Units.ext <| rfl + map_mul' _ _ := unop_injective <| Units.ext <| rfl left_inv x := Units.ext <| by simp right_inv x := unop_injective <| Units.ext <| by rfl diff --git a/Mathlib/Algebra/Group/Pi/Basic.lean b/Mathlib/Algebra/Group/Pi/Basic.lean index 480759b083256..7a88ae8220a12 100644 --- a/Mathlib/Algebra/Group/Pi/Basic.lean +++ b/Mathlib/Algebra/Group/Pi/Basic.lean @@ -400,18 +400,6 @@ theorem extend_div [Div γ] (f : α → β) (g₁ g₂ : α → γ) (e₁ e₂ : end Extend -theorem surjective_pi_map {F : ∀ i, f i → g i} (hF : ∀ i, Surjective (F i)) : - Surjective fun x : ∀ i, f i => fun i => F i (x i) := fun y => - ⟨fun i => (hF i (y i)).choose, funext fun i => (hF i (y i)).choose_spec⟩ - -theorem injective_pi_map {F : ∀ i, f i → g i} (hF : ∀ i, Injective (F i)) : - Injective fun x : ∀ i, f i => fun i => F i (x i) := - fun _ _ h => funext fun i => hF i <| (congr_fun h i : _) - -theorem bijective_pi_map {F : ∀ i, f i → g i} (hF : ∀ i, Bijective (F i)) : - Bijective fun x : ∀ i, f i => fun i => F i (x i) := - ⟨injective_pi_map fun i => (hF i).injective, surjective_pi_map fun i => (hF i).surjective⟩ - lemma comp_eq_const_iff (b : β) (f : α → β) {g : β → γ} (hg : Injective g) : g ∘ f = Function.const _ (g b) ↔ f = Function.const _ b := hg.comp_left.eq_iff' rfl diff --git a/Mathlib/Algebra/Group/Pi/Lemmas.lean b/Mathlib/Algebra/Group/Pi/Lemmas.lean index 672442bbd487d..0f412767df4f9 100644 --- a/Mathlib/Algebra/Group/Pi/Lemmas.lean +++ b/Mathlib/Algebra/Group/Pi/Lemmas.lean @@ -26,8 +26,7 @@ variable {I : Type u} -- The indexing type variable {f : I → Type v} --- The family of types already equipped with instances -variable (x y : ∀ i, f i) (i j : I) +variable (i : I) @[to_additive (attr := simp)] theorem Set.range_one {α β : Type*} [One β] [Nonempty α] : Set.range (1 : α → β) = {1} := @@ -68,9 +67,9 @@ def Pi.mulHom {γ : Type w} [∀ i, Mul (f i)] [Mul γ] (g : ∀ i, γ →ₙ* f @[to_additive] theorem Pi.mulHom_injective {γ : Type w} [Nonempty I] [∀ i, Mul (f i)] [Mul γ] (g : ∀ i, γ →ₙ* f i) - (hg : ∀ i, Function.Injective (g i)) : Function.Injective (Pi.mulHom g) := fun x y h => + (hg : ∀ i, Function.Injective (g i)) : Function.Injective (Pi.mulHom g) := fun _ _ h => let ⟨i⟩ := ‹Nonempty I› - hg i ((Function.funext_iff.mp h : _) i) + hg i ((funext_iff.mp h : _) i) /-- A family of monoid homomorphisms `f a : γ →* β a` defines a monoid homomorphism `Pi.monoidHom f : γ →* Π a, β a` given by `Pi.monoidHom f x b = f b x`. -/ @@ -337,7 +336,7 @@ theorem SemiconjBy.pi {x y z : ∀ i, f i} (h : ∀ i, SemiconjBy (x i) (y i) (z @[to_additive] theorem Pi.semiconjBy_iff {x y z : ∀ i, f i} : - SemiconjBy x y z ↔ ∀ i, SemiconjBy (x i) (y i) (z i) := Function.funext_iff + SemiconjBy x y z ↔ ∀ i, SemiconjBy (x i) (y i) (z i) := funext_iff @[to_additive] theorem Commute.pi {x y : ∀ i, f i} (h : ∀ i, Commute (x i) (y i)) : Commute x y := .pi h diff --git a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean index 5e5ebeefca3c2..1f5104d65643a 100644 --- a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean @@ -5,8 +5,6 @@ Authors: Floris van Doorn, Yaël Dillies -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Group.Action.Pi -import Mathlib.Algebra.Order.Ring.Nat -import Mathlib.Algebra.Ring.Pointwise.Set import Mathlib.Data.Finset.Density import Mathlib.Data.Finset.NAry import Mathlib.Data.Set.Pointwise.Finite @@ -55,7 +53,8 @@ finset multiplication, finset addition, pointwise addition, pointwise multiplica pointwise subtraction -/ - +-- TODO +-- assert_not_exists MonoidWithZero assert_not_exists Cardinal open Function MulOpposite @@ -94,6 +93,8 @@ lemma coe_eq_one : (s : Set α) = 1 ↔ s = 1 := coe_eq_singleton theorem one_subset : (1 : Finset α) ⊆ s ↔ (1 : α) ∈ s := singleton_subset_iff +-- TODO: This would be a good simp lemma scoped to `Pointwise`, but it seems `@[simp]` can't be +-- scoped @[to_additive] theorem singleton_one : ({1} : Finset α) = 1 := rfl @@ -170,13 +171,19 @@ lemma max'_one [LinearOrder α] : (1 : Finset α).max' one_nonempty = 1 := rfl @[to_additive (attr := simp)] lemma min'_one [LinearOrder α] : (1 : Finset α).min' one_nonempty = 1 := rfl +@[to_additive (attr := simp)] +lemma image_op_one [DecidableEq α] : (1 : Finset α).image op = 1 := rfl + +@[to_additive (attr := simp)] +lemma map_op_one : (1 : Finset α).map opEquiv.toEmbedding = 1 := rfl + end One /-! ### Finset negation/inversion -/ section Inv -variable [DecidableEq α] [Inv α] {s s₁ s₂ t t₁ t₂ u : Finset α} {a b : α} +variable [DecidableEq α] [Inv α] {s t : Finset α} {a : α} /-- The pointwise inversion of finset `s⁻¹` is defined as `{x⁻¹ | x ∈ s}` in locale `Pointwise`. -/ @[to_additive @@ -256,6 +263,10 @@ lemma inf'_inv [SemilatticeInf β] {s : Finset α} (hs : s⁻¹.Nonempty) (f : @[to_additive] lemma image_op_inv (s : Finset α) : s⁻¹.image op = (s.image op)⁻¹ := image_comm op_inv +@[to_additive] +lemma map_op_inv (s : Finset α) : s⁻¹.map opEquiv.toEmbedding = (s.map opEquiv.toEmbedding)⁻¹ := by + simp [map_eq_image, image_op_inv] + end Inv open Pointwise @@ -287,6 +298,164 @@ lemma inv_inter (s t : Finset α) : (s ∩ t)⁻¹ = s⁻¹ ∩ t⁻¹ := coe_in end InvolutiveInv +/-! ### Scalar addition/multiplication of finsets -/ + +section SMul +variable [DecidableEq β] [SMul α β] {s s₁ s₂ : Finset α} {t t₁ t₂ u : Finset β} {a : α} {b : β} + +/-- The pointwise product of two finsets `s` and `t`: `s • t = {x • y | x ∈ s, y ∈ t}`. -/ +@[to_additive "The pointwise sum of two finsets `s` and `t`: `s +ᵥ t = {x +ᵥ y | x ∈ s, y ∈ t}`."] +protected def smul : SMul (Finset α) (Finset β) := ⟨image₂ (· • ·)⟩ + +scoped[Pointwise] attribute [instance] Finset.smul Finset.vadd + +@[to_additive] lemma smul_def : s • t = (s ×ˢ t).image fun p : α × β => p.1 • p.2 := rfl + +@[to_additive] +lemma image_smul_product : ((s ×ˢ t).image fun x : α × β => x.fst • x.snd) = s • t := rfl + +@[to_additive] lemma mem_smul {x : β} : x ∈ s • t ↔ ∃ y ∈ s, ∃ z ∈ t, y • z = x := mem_image₂ + +@[to_additive (attr := simp, norm_cast)] +lemma coe_smul (s : Finset α) (t : Finset β) : ↑(s • t) = (s : Set α) • (t : Set β) := coe_image₂ .. + +@[to_additive] lemma smul_mem_smul : a ∈ s → b ∈ t → a • b ∈ s • t := mem_image₂_of_mem + +@[to_additive] lemma smul_card_le : (s • t).card ≤ s.card • t.card := card_image₂_le .. + +@[to_additive (attr := simp)] +lemma empty_smul (t : Finset β) : (∅ : Finset α) • t = ∅ := image₂_empty_left + +@[to_additive (attr := simp)] +lemma smul_empty (s : Finset α) : s • (∅ : Finset β) = ∅ := image₂_empty_right + +@[to_additive (attr := simp)] +lemma smul_eq_empty : s • t = ∅ ↔ s = ∅ ∨ t = ∅ := image₂_eq_empty_iff + +@[to_additive (attr := simp)] +lemma smul_nonempty_iff : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := image₂_nonempty_iff + +@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] +lemma Nonempty.smul : s.Nonempty → t.Nonempty → (s • t).Nonempty := .image₂ + +@[to_additive] lemma Nonempty.of_smul_left : (s • t).Nonempty → s.Nonempty := .of_image₂_left +@[to_additive] lemma Nonempty.of_smul_right : (s • t).Nonempty → t.Nonempty := .of_image₂_right + +@[to_additive] +lemma smul_singleton (b : β) : s • ({b} : Finset β) = s.image (· • b) := image₂_singleton_right + +@[to_additive] +lemma singleton_smul_singleton (a : α) (b : β) : ({a} : Finset α) • ({b} : Finset β) = {a • b} := + image₂_singleton + +@[to_additive (attr := mono, gcongr)] +lemma smul_subset_smul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ • t₁ ⊆ s₂ • t₂ := image₂_subset + +@[to_additive] lemma smul_subset_smul_left : t₁ ⊆ t₂ → s • t₁ ⊆ s • t₂ := image₂_subset_left +@[to_additive] lemma smul_subset_smul_right : s₁ ⊆ s₂ → s₁ • t ⊆ s₂ • t := image₂_subset_right +@[to_additive] lemma smul_subset_iff : s • t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a • b ∈ u := image₂_subset_iff + +@[to_additive] +lemma union_smul [DecidableEq α] : (s₁ ∪ s₂) • t = s₁ • t ∪ s₂ • t := image₂_union_left + +@[to_additive] +lemma smul_union : s • (t₁ ∪ t₂) = s • t₁ ∪ s • t₂ := image₂_union_right + +@[to_additive] +lemma inter_smul_subset [DecidableEq α] : (s₁ ∩ s₂) • t ⊆ s₁ • t ∩ s₂ • t := + image₂_inter_subset_left + +@[to_additive] +lemma smul_inter_subset : s • (t₁ ∩ t₂) ⊆ s • t₁ ∩ s • t₂ := image₂_inter_subset_right + +@[to_additive] +lemma inter_smul_union_subset_union [DecidableEq α] : (s₁ ∩ s₂) • (t₁ ∪ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ := + image₂_inter_union_subset_union + +@[to_additive] +lemma union_smul_inter_subset_union [DecidableEq α] : (s₁ ∪ s₂) • (t₁ ∩ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ := + image₂_union_inter_subset_union + +/-- If a finset `u` is contained in the scalar product of two sets `s • t`, we can find two finsets +`s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' • t'`. -/ +@[to_additive +"If a finset `u` is contained in the scalar sum of two sets `s +ᵥ t`, we can find two +finsets `s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' +ᵥ t'`."] +lemma subset_smul {s : Set α} {t : Set β} : + ↑u ⊆ s • t → ∃ (s' : Finset α) (t' : Finset β), ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' • t' := + subset_set_image₂ + +end SMul + +/-! ### Translation/scaling of finsets -/ + +section SMul +variable [DecidableEq β] [SMul α β] {s s₁ s₂ t : Finset β} {a : α} {b : β} + +/-- The scaling of a finset `s` by a scalar `a`: `a • s = {a • x | x ∈ s}`. -/ +@[to_additive "The translation of a finset `s` by a vector `a`: `a +ᵥ s = {a +ᵥ x | x ∈ s}`."] +protected def smulFinset : SMul α (Finset β) where smul a := image <| (a • ·) + +scoped[Pointwise] attribute [instance] Finset.smulFinset Finset.vaddFinset + +@[to_additive] lemma smul_finset_def : a • s = s.image (a • ·) := rfl + +@[to_additive] lemma image_smul : s.image (a • ·) = a • s := rfl + +@[to_additive] +lemma mem_smul_finset {x : β} : x ∈ a • s ↔ ∃ y, y ∈ s ∧ a • y = x := by + simp only [Finset.smul_finset_def, and_assoc, mem_image, exists_prop, Prod.exists, mem_product] + +@[to_additive (attr := simp, norm_cast)] +lemma coe_smul_finset (a : α) (s : Finset β) : ↑(a • s) = a • (↑s : Set β) := coe_image + +@[to_additive] lemma smul_mem_smul_finset : b ∈ s → a • b ∈ a • s := mem_image_of_mem _ + +@[to_additive] lemma smul_finset_card_le : (a • s).card ≤ s.card := card_image_le + +@[to_additive (attr := simp)] +lemma smul_finset_empty (a : α) : a • (∅ : Finset β) = ∅ := image_empty _ + +@[to_additive (attr := simp)] +lemma smul_finset_eq_empty : a • s = ∅ ↔ s = ∅ := image_eq_empty + +@[to_additive (attr := simp)] +lemma smul_finset_nonempty : (a • s).Nonempty ↔ s.Nonempty := image_nonempty + +@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] +lemma Nonempty.smul_finset (hs : s.Nonempty) : (a • s).Nonempty := + hs.image _ + +@[to_additive (attr := simp)] +lemma singleton_smul (a : α) : ({a} : Finset α) • t = a • t := image₂_singleton_left + +@[to_additive (attr := mono, gcongr)] +lemma smul_finset_subset_smul_finset : s ⊆ t → a • s ⊆ a • t := image_subset_image + +@[to_additive (attr := simp)] +lemma smul_finset_singleton (b : β) : a • ({b} : Finset β) = {a • b} := image_singleton .. + +@[to_additive] +lemma smul_finset_union : a • (s₁ ∪ s₂) = a • s₁ ∪ a • s₂ := image_union _ _ + +@[to_additive] +lemma smul_finset_insert (a : α) (b : β) (s : Finset β) : a • insert b s = insert (a • b) (a • s) := + image_insert .. + +@[to_additive] +lemma smul_finset_inter_subset : a • (s₁ ∩ s₂) ⊆ a • s₁ ∩ a • s₂ := image_inter_subset _ _ _ + +@[to_additive] +lemma smul_finset_subset_smul {s : Finset α} : a ∈ s → a • t ⊆ s • t := image_subset_image₂_right + +@[to_additive (attr := simp)] +lemma biUnion_smul_finset (s : Finset α) (t : Finset β) : s.biUnion (· • t) = s • t := + biUnion_image_left + +end SMul + +open scoped Pointwise + /-! ### Finset addition/multiplication -/ @@ -361,13 +530,9 @@ theorem Nonempty.of_mul_left : (s * t).Nonempty → s.Nonempty := theorem Nonempty.of_mul_right : (s * t).Nonempty → t.Nonempty := Nonempty.of_image₂_right -@[to_additive] -theorem mul_singleton (a : α) : s * {a} = s.image (· * a) := - image₂_singleton_right - -@[to_additive] -theorem singleton_mul (a : α) : {a} * s = s.image (a * ·) := - image₂_singleton_left +open scoped RightActions in +@[to_additive] lemma mul_singleton (a : α) : s * {a} = s <• a := image₂_singleton_right +@[to_additive] lemma singleton_mul (a : α) : {a} * s = a • s := image₂_singleton_left @[to_additive (attr := simp)] theorem singleton_mul_singleton (a b : α) : ({a} : Finset α) * {b} = {a * b} := @@ -426,6 +591,15 @@ theorem subset_mul {s t : Set α} : theorem image_mul [DecidableEq β] : (s * t).image (f : α → β) = s.image f * t.image f := image_image₂_distrib <| map_mul f +@[to_additive] +lemma image_op_mul (s t : Finset α) : (s * t).image op = t.image op * s.image op := + image_image₂_antidistrib op_mul + +@[to_additive] +lemma map_op_mul (s t : Finset α) : + (s * t).map opEquiv.toEmbedding = t.map opEquiv.toEmbedding * s.map opEquiv.toEmbedding := by + simp [map_eq_image, image_op_mul] + /-- The singleton operation as a `MulHom`. -/ @[to_additive "The singleton operation as an `AddHom`."] def singletonMulHom : α →ₙ* Finset α where @@ -553,8 +727,6 @@ theorem div_singleton (a : α) : s / {a} = s.image (· / a) := theorem singleton_div (a : α) : {a} / s = s.image (a / ·) := image₂_singleton_left --- @[to_additive (attr := simp)] --- Porting note (#10618): simp can prove this & the additive version @[to_additive] theorem singleton_div_singleton (a b : α) : ({a} : Finset α) / {b} = {a / b} := image₂_singleton @@ -810,14 +982,24 @@ theorem mem_prod_list_ofFn {a : α} {s : Fin n → Finset α} : @[to_additive] theorem mem_pow {a : α} {n : ℕ} : a ∈ s ^ n ↔ ∃ f : Fin n → s, (List.ofFn fun i => ↑(f i)).prod = a := by - -- Also compiles without the option, but much slower. - set_option tactic.skipAssignedInstances false in simp [← mem_coe, coe_pow, Set.mem_pow] -@[to_additive (attr := simp)] +@[to_additive (attr := simp) nsmul_empty] theorem empty_pow (hn : n ≠ 0) : (∅ : Finset α) ^ n = ∅ := by rw [← tsub_add_cancel_of_le (Nat.succ_le_of_lt <| Nat.pos_of_ne_zero hn), pow_succ', empty_mul] +@[deprecated (since := "2024-10-21")] alias empty_nsmul := nsmul_empty + +@[to_additive (attr := simp) nsmul_singleton] +lemma singleton_pow (a : α) : ∀ n, ({a} : Finset α) ^ n = {a ^ n} + | 0 => by simp [singleton_one] + | n + 1 => by simp [pow_succ, singleton_pow _ n] + +@[to_additive] +lemma card_pow_le : ∀ {n}, (s ^ n).card ≤ s.card ^ n + | 0 => by simp + | n + 1 => by rw [pow_succ, pow_succ]; refine card_mul_le.trans (by gcongr; exact card_pow_le) + @[to_additive] theorem mul_univ_of_one_mem [Fintype α] (hs : (1 : α) ∈ s) : s * univ = univ := eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, hs, _, mem_univ _, one_mul _⟩ @@ -862,11 +1044,11 @@ open Pointwise section DivisionMonoid -variable [DivisionMonoid α] {s t : Finset α} +variable [DivisionMonoid α] {s t : Finset α} {n : ℤ} @[to_additive (attr := simp)] theorem coe_zpow (s : Finset α) : ∀ n : ℤ, ↑(s ^ n) = (s : Set α) ^ n - | Int.ofNat n => coe_pow _ _ + | Int.ofNat _ => coe_pow _ _ | Int.negSucc n => by refine (coe_inv _).trans ?_ exact congr_arg Inv.inv (coe_pow _ _) @@ -907,6 +1089,12 @@ lemma univ_div_univ [Fintype α] : (univ / univ : Finset α) = univ := by simp [ @[to_additive] lemma inv_subset_div_right (hs : 1 ∈ s) : t⁻¹ ⊆ s / t := by rw [div_eq_mul_inv]; exact subset_mul_right _ hs +@[to_additive (attr := simp) zsmul_empty] +lemma empty_zpow (hn : n ≠ 0) : (∅ : Finset α) ^ n = ∅ := by cases n <;> aesop + +@[to_additive (attr := simp) zsmul_singleton] +lemma singleton_zpow (a : α) (n : ℤ) : ({a} : Finset α) ^ n = {a ^ n} := by cases n <;> simp + end DivisionMonoid /-- `Finset α` is a commutative division monoid under pointwise operations if `α` is. -/ @@ -915,58 +1103,7 @@ end DivisionMonoid protected def divisionCommMonoid [DivisionCommMonoid α] : DivisionCommMonoid (Finset α) := coe_injective.divisionCommMonoid _ coe_one coe_mul coe_inv coe_div coe_pow coe_zpow -/-- `Finset α` has distributive negation if `α` has. -/ -protected def distribNeg [Mul α] [HasDistribNeg α] : HasDistribNeg (Finset α) := - coe_injective.hasDistribNeg _ coe_neg coe_mul - -scoped[Pointwise] - attribute [instance] Finset.divisionCommMonoid Finset.subtractionCommMonoid Finset.distribNeg - -section Distrib - -variable [Distrib α] (s t u : Finset α) - -/-! -Note that `Finset α` is not a `Distrib` because `s * t + s * u` has cross terms that `s * (t + u)` -lacks. - -```lean --- {10, 16, 18, 20, 8, 9} -#eval {1, 2} * ({3, 4} + {5, 6} : Finset ℕ) - --- {10, 11, 12, 13, 14, 15, 16, 18, 20, 8, 9} -#eval ({1, 2} : Finset ℕ) * {3, 4} + {1, 2} * {5, 6} -``` --/ - - -theorem mul_add_subset : s * (t + u) ⊆ s * t + s * u := - image₂_distrib_subset_left mul_add - -theorem add_mul_subset : (s + t) * u ⊆ s * u + t * u := - image₂_distrib_subset_right add_mul - -end Distrib - -section MulZeroClass - -variable [MulZeroClass α] {s t : Finset α} - -/-! Note that `Finset` is not a `MulZeroClass` because `0 * ∅ ≠ 0`. -/ - - -theorem mul_zero_subset (s : Finset α) : s * 0 ⊆ 0 := by simp [subset_iff, mem_mul] - -theorem zero_mul_subset (s : Finset α) : 0 * s ⊆ 0 := by simp [subset_iff, mem_mul] - -theorem Nonempty.mul_zero (hs : s.Nonempty) : s * 0 = 0 := - s.mul_zero_subset.antisymm <| by simpa [mem_mul] using hs - -theorem Nonempty.zero_mul (hs : s.Nonempty) : 0 * s = 0 := - s.zero_mul_subset.antisymm <| by simpa [mem_mul] using hs - -end MulZeroClass - +scoped[Pointwise] attribute [instance] Finset.divisionCommMonoid Finset.subtractionCommMonoid section Group variable [Group α] [DivisionMonoid β] [FunLike F α β] [MonoidHomClass F α β] @@ -1029,27 +1166,11 @@ theorem image_div : (s / t).image (f : α → β) = s.image f / t.image f := end Group -section GroupWithZero - -variable [GroupWithZero α] {s t : Finset α} - -theorem div_zero_subset (s : Finset α) : s / 0 ⊆ 0 := by simp [subset_iff, mem_div] - -theorem zero_div_subset (s : Finset α) : 0 / s ⊆ 0 := by simp [subset_iff, mem_div] - -theorem Nonempty.div_zero (hs : s.Nonempty) : s / 0 = 0 := - s.div_zero_subset.antisymm <| by simpa [mem_div] using hs - -theorem Nonempty.zero_div (hs : s.Nonempty) : 0 / s = 0 := - s.zero_div_subset.antisymm <| by simpa [mem_div] using hs - -end GroupWithZero - end Instances section Group -variable [Group α] {s t : Finset α} {a b : α} +variable [Group α] {a b : α} @[to_additive (attr := simp)] theorem preimage_mul_left_singleton : @@ -1079,137 +1200,11 @@ theorem preimage_mul_right_one' : preimage 1 (· * b⁻¹) (mul_left_injective _ end Group -/-! ### Scalar addition/multiplication of finsets -/ - - -section SMul - -variable [DecidableEq β] [SMul α β] {s s₁ s₂ : Finset α} {t t₁ t₂ u : Finset β} {a : α} {b : β} - -/-- The pointwise product of two finsets `s` and `t`: `s • t = {x • y | x ∈ s, y ∈ t}`. -/ -@[to_additive "The pointwise sum of two finsets `s` and `t`: `s +ᵥ t = {x +ᵥ y | x ∈ s, y ∈ t}`."] -protected def smul : SMul (Finset α) (Finset β) := - ⟨image₂ (· • ·)⟩ - -scoped[Pointwise] attribute [instance] Finset.smul Finset.vadd - -@[to_additive] -theorem smul_def : s • t = (s ×ˢ t).image fun p : α × β => p.1 • p.2 := - rfl - -@[to_additive] -theorem image_smul_product : ((s ×ˢ t).image fun x : α × β => x.fst • x.snd) = s • t := - rfl - -@[to_additive] -theorem mem_smul {x : β} : x ∈ s • t ↔ ∃ y ∈ s, ∃ z ∈ t, y • z = x := - mem_image₂ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_smul (s : Finset α) (t : Finset β) : ↑(s • t) = (s : Set α) • (t : Set β) := - coe_image₂ _ _ _ - -@[to_additive] -theorem smul_mem_smul : a ∈ s → b ∈ t → a • b ∈ s • t := - mem_image₂_of_mem - -@[to_additive] -theorem smul_card_le : (s • t).card ≤ s.card • t.card := - card_image₂_le _ _ _ - -@[to_additive (attr := simp)] -theorem empty_smul (t : Finset β) : (∅ : Finset α) • t = ∅ := - image₂_empty_left - -@[to_additive (attr := simp)] -theorem smul_empty (s : Finset α) : s • (∅ : Finset β) = ∅ := - image₂_empty_right - -@[to_additive (attr := simp)] -theorem smul_eq_empty : s • t = ∅ ↔ s = ∅ ∨ t = ∅ := - image₂_eq_empty_iff - -@[to_additive (attr := simp)] -theorem smul_nonempty_iff : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := - image₂_nonempty_iff - -@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] -theorem Nonempty.smul : s.Nonempty → t.Nonempty → (s • t).Nonempty := - Nonempty.image₂ - -@[to_additive] -theorem Nonempty.of_smul_left : (s • t).Nonempty → s.Nonempty := - Nonempty.of_image₂_left - -@[to_additive] -theorem Nonempty.of_smul_right : (s • t).Nonempty → t.Nonempty := - Nonempty.of_image₂_right - -@[to_additive] -theorem smul_singleton (b : β) : s • ({b} : Finset β) = s.image (· • b) := - image₂_singleton_right - -@[to_additive] -theorem singleton_smul_singleton (a : α) (b : β) : ({a} : Finset α) • ({b} : Finset β) = {a • b} := - image₂_singleton - -@[to_additive (attr := mono, gcongr)] -theorem smul_subset_smul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ • t₁ ⊆ s₂ • t₂ := - image₂_subset - -@[to_additive] -theorem smul_subset_smul_left : t₁ ⊆ t₂ → s • t₁ ⊆ s • t₂ := - image₂_subset_left - -@[to_additive] -theorem smul_subset_smul_right : s₁ ⊆ s₂ → s₁ • t ⊆ s₂ • t := - image₂_subset_right - -@[to_additive] -theorem smul_subset_iff : s • t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a • b ∈ u := - image₂_subset_iff - -@[to_additive] -theorem union_smul [DecidableEq α] : (s₁ ∪ s₂) • t = s₁ • t ∪ s₂ • t := - image₂_union_left - -@[to_additive] -theorem smul_union : s • (t₁ ∪ t₂) = s • t₁ ∪ s • t₂ := - image₂_union_right - -@[to_additive] -theorem inter_smul_subset [DecidableEq α] : (s₁ ∩ s₂) • t ⊆ s₁ • t ∩ s₂ • t := - image₂_inter_subset_left - -@[to_additive] -theorem smul_inter_subset : s • (t₁ ∩ t₂) ⊆ s • t₁ ∩ s • t₂ := - image₂_inter_subset_right - -@[to_additive] -theorem inter_smul_union_subset_union [DecidableEq α] : (s₁ ∩ s₂) • (t₁ ∪ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ := - image₂_inter_union_subset_union - -@[to_additive] -theorem union_smul_inter_subset_union [DecidableEq α] : (s₁ ∪ s₂) • (t₁ ∩ t₂) ⊆ s₁ • t₁ ∪ s₂ • t₂ := - image₂_union_inter_subset_union - -/-- If a finset `u` is contained in the scalar product of two sets `s • t`, we can find two finsets -`s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' • t'`. -/ -@[to_additive - "If a finset `u` is contained in the scalar sum of two sets `s +ᵥ t`, we can find two - finsets `s'`, `t'` such that `s' ⊆ s`, `t' ⊆ t` and `u ⊆ s' +ᵥ t'`."] -theorem subset_smul {s : Set α} {t : Set β} : - ↑u ⊆ s • t → ∃ (s' : Finset α) (t' : Finset β), ↑s' ⊆ s ∧ ↑t' ⊆ t ∧ u ⊆ s' • t' := - subset_set_image₂ - -end SMul - /-! ### Scalar subtraction of finsets -/ section VSub --- Porting note: Reordered [VSub α β] and [DecidableEq α] to make vsub less dangerous. Bad? variable [VSub α β] [DecidableEq α] {s s₁ s₂ t t₁ t₂ : Finset β} {u : Finset α} {a : α} {b c : β} /-- The pointwise subtraction of two finsets `s` and `t`: `s -ᵥ t = {x -ᵥ y | x ∈ s, y ∈ t}`. -/ @@ -1271,7 +1266,6 @@ theorem vsub_singleton (b : β) : s -ᵥ ({b} : Finset β) = s.image (· -ᵥ b) theorem singleton_vsub (a : β) : ({a} : Finset β) -ᵥ t = t.image (a -ᵥ ·) := image₂_singleton_left --- @[simp] -- Porting note (#10618): simp can prove this theorem singleton_vsub_singleton (a b : β) : ({a} : Finset β) -ᵥ {b} = {a -ᵥ b} := image₂_singleton @@ -1314,98 +1308,6 @@ theorem subset_vsub {s t : Set β} : end VSub -open Pointwise - -/-! ### Translation/scaling of finsets -/ - - -section SMul - -variable [DecidableEq β] [SMul α β] {s s₁ s₂ t u : Finset β} {a : α} {b : β} - -/-- The scaling of a finset `s` by a scalar `a`: `a • s = {a • x | x ∈ s}`. -/ -@[to_additive "The translation of a finset `s` by a vector `a`: `a +ᵥ s = {a +ᵥ x | x ∈ s}`."] -protected def smulFinset : SMul α (Finset β) := - ⟨fun a => image <| (a • ·)⟩ - -scoped[Pointwise] attribute [instance] Finset.smulFinset Finset.vaddFinset - -@[to_additive] -theorem smul_finset_def : a • s = s.image (a • ·) := - rfl - -@[to_additive] -theorem image_smul : (s.image fun x => a • x) = a • s := - rfl - -@[to_additive] -theorem mem_smul_finset {x : β} : x ∈ a • s ↔ ∃ y, y ∈ s ∧ a • y = x := by - simp only [Finset.smul_finset_def, and_assoc, mem_image, exists_prop, Prod.exists, mem_product] - -@[to_additive (attr := simp, norm_cast)] -theorem coe_smul_finset (a : α) (s : Finset β) : ↑(a • s) = a • (↑s : Set β) := - coe_image - -@[to_additive] -theorem smul_mem_smul_finset : b ∈ s → a • b ∈ a • s := - mem_image_of_mem _ - -@[to_additive] -theorem smul_finset_card_le : (a • s).card ≤ s.card := - card_image_le - -@[to_additive (attr := simp)] -theorem smul_finset_empty (a : α) : a • (∅ : Finset β) = ∅ := - image_empty _ - -@[to_additive (attr := simp)] -theorem smul_finset_eq_empty : a • s = ∅ ↔ s = ∅ := - image_eq_empty - -@[to_additive (attr := simp)] -theorem smul_finset_nonempty : (a • s).Nonempty ↔ s.Nonempty := - image_nonempty - -@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] -theorem Nonempty.smul_finset (hs : s.Nonempty) : (a • s).Nonempty := - hs.image _ - -@[to_additive (attr := simp)] -theorem singleton_smul (a : α) : ({a} : Finset α) • t = a • t := - image₂_singleton_left - -@[to_additive (attr := mono, gcongr)] -theorem smul_finset_subset_smul_finset : s ⊆ t → a • s ⊆ a • t := - image_subset_image - -@[to_additive (attr := simp)] -theorem smul_finset_singleton (b : β) : a • ({b} : Finset β) = {a • b} := - image_singleton _ _ - -@[to_additive] -theorem smul_finset_union : a • (s₁ ∪ s₂) = a • s₁ ∪ a • s₂ := - image_union _ _ - -@[to_additive] -lemma smul_finset_insert (a : α) (b : β) (s : Finset β) : a • insert b s = insert (a • b) (a • s) := - image_insert .. - -@[to_additive] -theorem smul_finset_inter_subset : a • (s₁ ∩ s₂) ⊆ a • s₁ ∩ a • s₂ := - image_inter_subset _ _ _ - -@[to_additive] -theorem smul_finset_subset_smul {s : Finset α} : a ∈ s → a • t ⊆ s • t := - image_subset_image₂_right - -@[to_additive (attr := simp)] -theorem biUnion_smul_finset (s : Finset α) (t : Finset β) : s.biUnion (· • t) = s • t := - biUnion_image_left - -end SMul - -open Pointwise - section Instances variable [DecidableEq γ] @@ -1475,48 +1377,6 @@ scoped[Pointwise] attribute [instance] Finset.mulActionFinset Finset.addActionFinset Finset.mulAction Finset.addAction -/-- If scalar multiplication by elements of `α` sends `(0 : β)` to zero, -then the same is true for `(0 : Finset β)`. -/ -protected def smulZeroClassFinset [Zero β] [SMulZeroClass α β] : - SMulZeroClass α (Finset β) := - coe_injective.smulZeroClass ⟨(↑), coe_zero⟩ coe_smul_finset - -scoped[Pointwise] attribute [instance] Finset.smulZeroClassFinset - -/-- If the scalar multiplication `(· • ·) : α → β → β` is distributive, -then so is `(· • ·) : α → Finset β → Finset β`. -/ -protected def distribSMulFinset [AddZeroClass β] [DistribSMul α β] : - DistribSMul α (Finset β) := - coe_injective.distribSMul coeAddMonoidHom coe_smul_finset - -scoped[Pointwise] attribute [instance] Finset.distribSMulFinset - -/-- A distributive multiplicative action of a monoid on an additive monoid `β` gives a distributive -multiplicative action on `Finset β`. -/ -protected def distribMulActionFinset [Monoid α] [AddMonoid β] [DistribMulAction α β] : - DistribMulAction α (Finset β) := - Function.Injective.distribMulAction coeAddMonoidHom coe_injective coe_smul_finset - -/-- A multiplicative action of a monoid on a monoid `β` gives a multiplicative action on `Set β`. -/ -protected def mulDistribMulActionFinset [Monoid α] [Monoid β] [MulDistribMulAction α β] : - MulDistribMulAction α (Finset β) := - Function.Injective.mulDistribMulAction coeMonoidHom coe_injective coe_smul_finset - -scoped[Pointwise] - attribute [instance] Finset.distribMulActionFinset Finset.mulDistribMulActionFinset - -instance [DecidableEq α] [Zero α] [Mul α] [NoZeroDivisors α] : NoZeroDivisors (Finset α) := - Function.Injective.noZeroDivisors (↑) coe_injective coe_zero coe_mul - -instance noZeroSMulDivisors [Zero α] [Zero β] [SMul α β] [NoZeroSMulDivisors α β] : - NoZeroSMulDivisors (Finset α) (Finset β) where - eq_zero_or_eq_zero_of_smul_eq_zero {s t} := by - exact_mod_cast eq_zero_or_eq_zero_of_smul_eq_zero (c := s.toSet) (x := t.toSet) - -instance noZeroSMulDivisors_finset [Zero α] [Zero β] [SMul α β] [NoZeroSMulDivisors α β] : - NoZeroSMulDivisors α (Finset β) := - Function.Injective.noZeroSMulDivisors (↑) coe_injective coe_zero coe_smul_finset - end Instances section SMul @@ -1628,6 +1488,27 @@ theorem card_le_card_mul_self' {s : Finset α} : s.card ≤ (s * s).card := by end +section CancelMonoid +variable [DecidableEq α] [CancelMonoid α] {s : Finset α} {m n : ℕ} + +/-- 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 + +/-- 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."] +lemma card_pow_mono (hm : m ≠ 0) (hmn : m ≤ n) : (s ^ m).card ≤ (s ^ n).card := by + obtain rfl | hs := s.eq_empty_or_nonempty + · simp [hm] + · exact hs.card_pow_mono hmn + +@[to_additive] +lemma card_le_card_pow (hn : n ≠ 0) : s.card ≤ (s ^ n).card := by + simpa using card_pow_mono (s := s) one_ne_zero (Nat.one_le_iff_ne_zero.2 hn) + +end CancelMonoid + section Group variable [Group α] [DecidableEq α] {s t : Finset α} @@ -1753,148 +1634,6 @@ lemma inv_op_smul_finset_distrib (a : α) (s : Finset α) : (op a • s)⁻¹ = end Group -section SMulZeroClass - -variable [Zero β] [SMulZeroClass α β] [DecidableEq β] {s : Finset α} {t : Finset β} {a : α} - -theorem smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] - -theorem Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := - s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs - -theorem zero_mem_smul_finset (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := - mem_smul_finset.2 ⟨0, h, smul_zero _⟩ - -variable [Zero α] [NoZeroSMulDivisors α β] - -theorem zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by - rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] - -end SMulZeroClass - -section SMulWithZero - -variable [Zero α] [Zero β] [SMulWithZero α β] [DecidableEq β] {s : Finset α} {t : Finset β} - -/-! -Note that we have neither `SMulWithZero α (Finset β)` nor `SMulWithZero (Finset α) (Finset β)` -because `0 • ∅ ≠ 0`. --/ - -lemma zero_smul_subset (t : Finset β) : (0 : Finset α) • t ⊆ 0 := by simp [subset_iff, mem_smul] - -lemma Nonempty.zero_smul (ht : t.Nonempty) : (0 : Finset α) • t = 0 := - t.zero_smul_subset.antisymm <| by simpa [mem_smul] using ht - -/-- A nonempty set is scaled by zero to the singleton set containing zero. -/ -@[simp] lemma zero_smul_finset {s : Finset β} (h : s.Nonempty) : (0 : α) • s = (0 : Finset β) := - coe_injective <| by simpa using @Set.zero_smul_set α _ _ _ _ _ h - -lemma zero_smul_finset_subset (s : Finset β) : (0 : α) • s ⊆ 0 := - image_subset_iff.2 fun x _ ↦ mem_zero.2 <| zero_smul α x - -variable [NoZeroSMulDivisors α β] {a : α} - -lemma zero_mem_smul_iff : - (0 : β) ∈ s • t ↔ (0 : α) ∈ s ∧ t.Nonempty ∨ (0 : β) ∈ t ∧ s.Nonempty := by - rw [← mem_coe, coe_smul, Set.zero_mem_smul_iff]; rfl - -end SMulWithZero - -section GroupWithZero - -variable [DecidableEq β] [GroupWithZero α] [MulAction α β] {s t : Finset β} {a : α} {b : β} - -@[simp] -theorem smul_mem_smul_finset_iff₀ (ha : a ≠ 0) : a • b ∈ a • s ↔ b ∈ s := - smul_mem_smul_finset_iff (Units.mk0 a ha) - -theorem inv_smul_mem_iff₀ (ha : a ≠ 0) : a⁻¹ • b ∈ s ↔ b ∈ a • s := - show _ ↔ _ ∈ Units.mk0 a ha • _ from inv_smul_mem_iff - -theorem mem_inv_smul_finset_iff₀ (ha : a ≠ 0) : b ∈ a⁻¹ • s ↔ a • b ∈ s := - show _ ∈ (Units.mk0 a ha)⁻¹ • _ ↔ _ from mem_inv_smul_finset_iff - -@[simp] -theorem smul_finset_subset_smul_finset_iff₀ (ha : a ≠ 0) : a • s ⊆ a • t ↔ s ⊆ t := - show Units.mk0 a ha • _ ⊆ _ ↔ _ from smul_finset_subset_smul_finset_iff - -theorem smul_finset_subset_iff₀ (ha : a ≠ 0) : a • s ⊆ t ↔ s ⊆ a⁻¹ • t := - show Units.mk0 a ha • _ ⊆ _ ↔ _ from smul_finset_subset_iff - -theorem subset_smul_finset_iff₀ (ha : a ≠ 0) : s ⊆ a • t ↔ a⁻¹ • s ⊆ t := - show _ ⊆ Units.mk0 a ha • _ ↔ _ from subset_smul_finset_iff - -theorem smul_finset_inter₀ (ha : a ≠ 0) : a • (s ∩ t) = a • s ∩ a • t := - image_inter _ _ <| MulAction.injective₀ ha - -theorem smul_finset_sdiff₀ (ha : a ≠ 0) : a • (s \ t) = a • s \ a • t := - image_sdiff _ _ <| MulAction.injective₀ ha - -open scoped symmDiff in -theorem smul_finset_symmDiff₀ (ha : a ≠ 0) : a • s ∆ t = (a • s) ∆ (a • t) := - image_symmDiff _ _ <| MulAction.injective₀ ha - -lemma smul_finset_univ₀ [Fintype β] (ha : a ≠ 0) : a • (univ : Finset β) = univ := - coe_injective <| by push_cast; exact Set.smul_set_univ₀ ha - -theorem smul_univ₀ [Fintype β] {s : Finset α} (hs : ¬s ⊆ 0) : s • (univ : Finset β) = univ := - coe_injective <| by - rw [← coe_subset] at hs - push_cast at hs ⊢ - exact Set.smul_univ₀ hs - -lemma smul_univ₀' [Fintype β] {s : Finset α} (hs : s.Nontrivial) : s • (univ : Finset β) = univ := - coe_injective <| by push_cast; exact Set.smul_univ₀' hs - -variable [DecidableEq α] - -@[simp] protected lemma inv_zero : (0 : Finset α)⁻¹ = 0 := by ext; simp - -@[simp] lemma inv_smul_finset_distrib₀ (a : α) (s : Finset α) : (a • s)⁻¹ = op a⁻¹ • s⁻¹ := by - obtain rfl | ha := eq_or_ne a 0 - · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] - · ext; simp [← inv_smul_mem_iff₀, *] - -@[simp] lemma inv_op_smul_finset_distrib₀ (a : α) (s : Finset α) : (op a • s)⁻¹ = a⁻¹ • s⁻¹ := by - obtain rfl | ha := eq_or_ne a 0 - · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] - · ext; simp [← inv_smul_mem_iff₀, *] - -end GroupWithZero - -section Monoid - -variable [Monoid α] [AddGroup β] [DistribMulAction α β] [DecidableEq β] (a : α) (s : Finset α) - (t : Finset β) - -@[simp] -theorem smul_finset_neg : a • -t = -(a • t) := by - simp only [← image_smul, ← image_neg, Function.comp_def, image_image, smul_neg] - -@[simp] -protected theorem smul_neg : s • -t = -(s • t) := by - simp_rw [← image_neg] - exact image_image₂_right_comm smul_neg - -end Monoid - -section Ring - -variable [Ring α] [AddCommGroup β] [Module α β] [DecidableEq β] {s : Finset α} {t : Finset β} - {a : α} - -@[simp] -theorem neg_smul_finset : -a • t = -(a • t) := by - simp only [← image_smul, ← image_neg, image_image, neg_smul, Function.comp_def] - -@[simp] -protected theorem neg_smul [DecidableEq α] : -s • t = -(s • t) := by - simp_rw [← image_neg] - exact image₂_image_left_comm neg_smul - -end Ring - section BigOps section CommMonoid variable [CommMonoid α] {ι : Type*} [DecidableEq ι] @@ -1990,7 +1729,7 @@ end Mul section SMul -variable [SMul α β] [DecidableEq β] {a : α} {s : Set α} {t : Set β} +variable [SMul α β] [DecidableEq β] {s : Set α} {t : Set β} @[to_additive (attr := simp)] theorem toFinset_smul (s : Set α) (t : Set β) [Fintype s] [Fintype t] [Fintype ↑(s • t)] : @@ -2042,4 +1781,4 @@ instance Nat.decidablePred_mem_vadd_set {s : Set ℕ} [DecidablePred (· ∈ s)] fun n ↦ decidable_of_iff' (a ≤ n ∧ n - a ∈ s) <| by simp only [Set.mem_vadd_set, vadd_eq_add]; aesop -set_option linter.style.longFile 2100 +set_option linter.style.longFile 1800 diff --git a/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean index fd9cc57c0dd5b..479121a3d4a1b 100644 --- a/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean @@ -31,7 +31,7 @@ the unprimed names have been reserved for section ContravariantLE variable [Mul α] [Preorder α] [DecidableEq α] -variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Function.swap HMul.hMul) LE.le] +variable [MulLeftMono α] [MulRightMono α] @[to_additive Icc_add_Icc_subset] theorem Icc_mul_Icc_subset' [LocallyFiniteOrder α] (a b c d : α) : @@ -51,7 +51,7 @@ end ContravariantLE section ContravariantLT variable [Mul α] [PartialOrder α] [DecidableEq α] -variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (Function.swap HMul.hMul) LT.lt] +variable [MulLeftStrictMono α] [MulRightStrictMono α] @[to_additive Icc_add_Ico_subset] theorem Icc_mul_Ico_subset' [LocallyFiniteOrder α] (a b c d : α) : diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean index bb8aba1b06f3a..e62af9d0fc374 100644 --- a/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean @@ -67,8 +67,7 @@ Because the pointwise action can easily be spelled out in such cases, we give hi nat and int actions. -/ - -open Function +open Function MulOpposite variable {F α β γ : Type*} @@ -89,6 +88,8 @@ scoped[Pointwise] attribute [instance] Set.one Set.zero open Pointwise +-- TODO: This would be a good simp lemma scoped to `Pointwise`, but it seems `@[simp]` can't be +-- scoped @[to_additive] theorem singleton_one : ({1} : Set α) = 1 := rfl @@ -130,6 +131,8 @@ noncomputable def singletonOneHom : OneHom α (Set α) where theorem coe_singletonOneHom : (singletonOneHom : α → Set α) = singleton := rfl +@[to_additive] lemma image_op_one : (1 : Set α).image op = 1 := image_singleton + end One /-! ### Set negation/inversion -/ @@ -327,7 +330,6 @@ theorem mul_singleton : s * {b} = (· * b) '' s := theorem singleton_mul : {a} * t = (a * ·) '' t := image2_singleton_left --- Porting note (#10618): simp can prove this @[to_additive] theorem singleton_mul_singleton : ({a} : Set α) * {b} = {a * b} := image2_singleton @@ -531,7 +533,6 @@ theorem div_singleton : s / {b} = (· / b) '' s := theorem singleton_div : {a} / t = (· / ·) a '' t := image2_singleton_left --- Porting note (#10618): simp can prove this @[to_additive] theorem singleton_div_singleton : ({a} : Set α) / {b} = {a / b} := image2_singleton @@ -1098,11 +1099,18 @@ theorem pow_subset_pow_of_one_mem (hs : (1 : α) ∈ s) (hn : m ≤ n) : s ^ m rw [pow_succ'] exact ih.trans (subset_mul_right _ hs) -@[to_additive (attr := simp)] +@[to_additive (attr := simp) nsmul_empty] theorem empty_pow {n : ℕ} (hn : n ≠ 0) : (∅ : Set α) ^ n = ∅ := by match n with | n + 1 => rw [pow_succ', empty_mul] +@[deprecated (since := "2024-10-21")] alias empty_nsmul := nsmul_empty + +@[to_additive (attr := simp) nsmul_singleton] +lemma singleton_pow (a : α) : ∀ n, ({a} : Set α) ^ n = {a ^ n} + | 0 => by simp [singleton_one] + | n + 1 => by simp [pow_succ, singleton_pow _ n] + @[to_additive] theorem mul_univ_of_one_mem (hs : (1 : α) ∈ s) : s * univ = univ := eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, hs, _, mem_univ _, one_mul _⟩ @@ -1138,7 +1146,7 @@ open Pointwise section DivisionMonoid -variable [DivisionMonoid α] {s t : Set α} +variable [DivisionMonoid α] {s t : Set α} {n : ℤ} @[to_additive] protected theorem mul_eq_one_iff : s * t = 1 ↔ ∃ a b, s = {a} ∧ t = {b} ∧ a * b = 1 := by @@ -1191,6 +1199,12 @@ lemma univ_div_univ : (univ / univ : Set α) = univ := by simp [div_eq_mul_inv] @[to_additive] lemma inv_subset_div_right (hs : 1 ∈ s) : t⁻¹ ⊆ s / t := by rw [div_eq_mul_inv]; exact subset_mul_right _ hs +@[to_additive (attr := simp) zsmul_empty] +lemma empty_zpow (hn : n ≠ 0) : (∅ : Set α) ^ n = ∅ := by cases n <;> aesop + +@[to_additive (attr := simp) zsmul_singleton] +lemma singleton_zpow (a : α) (n : ℤ) : ({a} : Set α) ^ n = {a ^ n} := by cases n <;> simp + end DivisionMonoid /-- `Set α` is a commutative division monoid under pointwise operations if `α` is. -/ diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean index 341ed441df932..80a073b792385 100644 --- a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean @@ -3,60 +3,84 @@ 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.Set.Pointwise.Finite import Mathlib.SetTheory.Cardinal.Finite /-! -# Cardinalities of pointwise operations on sets. +# Cardinalities of pointwise operations on sets -/ -namespace Set - -open Pointwise - -variable {α β : Type*} +open scoped Cardinal Pointwise -section MulAction -variable [Group α] [MulAction α β] +namespace Set +variable {G M α : Type*} -@[to_additive (attr := simp)] -lemma card_smul_set (a : α) (s : Set β) : Nat.card ↥(a • s) = Nat.card s := - Nat.card_image_of_injective (MulAction.injective a) _ +section Mul +variable [Mul M] {s t : Set M} -end MulAction +@[to_additive] +lemma _root_.Cardinal.mk_mul_le : #(s * t) ≤ #s * #t := by + rw [← image2_mul]; exact Cardinal.mk_image2_le -section IsCancelMul -variable [Mul α] [IsCancelMul α] {s t : Set α} +variable [IsCancelMul M] @[to_additive] -lemma card_mul_le : Nat.card (s * t) ≤ Nat.card s * Nat.card t := by - classical +lemma natCard_mul_le : Nat.card (s * t) ≤ Nat.card s * Nat.card t := by obtain h | h := (s * t).infinite_or_finite · simp [Set.Infinite.card_eq_zero h] - obtain ⟨hs, ht⟩ | rfl | rfl := finite_mul.1 h - · lift s to Finset α using hs - lift t to Finset α using ht - rw [← Finset.coe_mul] - simpa [-Finset.coe_mul] using Finset.card_mul_le - all_goals simp + simp only [Nat.card, ← Cardinal.toNat_mul] + refine Cardinal.toNat_le_toNat Cardinal.mk_mul_le ?_ + aesop (add simp [Cardinal.mul_lt_aleph0_iff, finite_mul]) + +@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_mul_le := natCard_mul_le -end IsCancelMul +end Mul section InvolutiveInv -variable [InvolutiveInv α] {s t : Set α} +variable [InvolutiveInv G] {s t : Set G} + +@[to_additive (attr := simp)] +lemma _root_.Cardinal.mk_inv (s : Set G) : #↥(s⁻¹) = #s := by + rw [← image_inv, Cardinal.mk_image_eq_of_injOn _ _ inv_injective.injOn] @[to_additive (attr := simp)] -lemma card_inv (s : Set α) : Nat.card ↥(s⁻¹) = Nat.card s := by +lemma natCard_inv (s : Set G) : Nat.card ↥(s⁻¹) = Nat.card s := by rw [← image_inv, Nat.card_image_of_injective inv_injective] +@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_inv := natCard_inv + end InvolutiveInv +section DivInvMonoid +variable [DivInvMonoid M] {s t : Set M} + +@[to_additive] +lemma _root_.Cardinal.mk_div_le : #(s / t) ≤ #s * #t := by + rw [← image2_div]; exact Cardinal.mk_image2_le + +end DivInvMonoid + section Group -variable [Group α] {s t : Set α} +variable [Group G] {s t : Set G} @[to_additive] -lemma card_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by - rw [div_eq_mul_inv, ← card_inv t]; exact card_mul_le +lemma natCard_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by + rw [div_eq_mul_inv, ← natCard_inv t]; exact natCard_mul_le + +@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_div_le := natCard_div_le + +variable [MulAction G α] + +@[to_additive (attr := simp)] +lemma _root_.Cardinal.mk_smul_set (a : G) (s : Set α) : #↥(a • s) = #s := + Cardinal.mk_image_eq_of_injOn _ _ (MulAction.injective a).injOn + +@[to_additive (attr := simp)] +lemma natCard_smul_set (a : G) (s : Set α) : Nat.card ↥(a • s) = Nat.card s := + Nat.card_image_of_injective (MulAction.injective a) _ + +@[to_additive (attr := deprecated (since := "2024-09-30"))] +alias card_smul_set := Cardinal.mk_smul_set end Group end Set diff --git a/Mathlib/Algebra/Group/Prod.lean b/Mathlib/Algebra/Group/Prod.lean index 5870914629f9a..02781d10d0067 100644 --- a/Mathlib/Algebra/Group/Prod.lean +++ b/Mathlib/Algebra/Group/Prod.lean @@ -34,7 +34,7 @@ assert_not_exists MonoidWithZero -- assert_not_exists AddMonoidWithOne assert_not_exists DenselyOrdered -variable {A : Type*} {B : Type*} {G : Type*} {H : Type*} {M : Type*} {N : Type*} {P : Type*} +variable {G : Type*} {H : Type*} {M : Type*} {N : Type*} {P : Type*} namespace Prod @@ -165,8 +165,8 @@ instance instMulOneClass [MulOneClass M] [MulOneClass N] : MulOneClass (M × N) @[to_additive] instance instMonoid [Monoid M] [Monoid N] : Monoid (M × N) := { npow := fun z a => ⟨Monoid.npow z a.1, Monoid.npow z a.2⟩, - npow_zero := fun z => Prod.ext (Monoid.npow_zero _) (Monoid.npow_zero _), - npow_succ := fun z a => Prod.ext (Monoid.npow_succ _ _) (Monoid.npow_succ _ _), + npow_zero := fun _ => Prod.ext (Monoid.npow_zero _) (Monoid.npow_zero _), + npow_succ := fun _ _ => Prod.ext (Monoid.npow_succ _ _) (Monoid.npow_succ _ _), one_mul := by simp, mul_one := by simp } @@ -180,8 +180,8 @@ instance [DivInvMonoid G] [DivInvMonoid H] : DivInvMonoid (G × H) := @[to_additive] instance [DivisionMonoid G] [DivisionMonoid H] : DivisionMonoid (G × H) := - { mul_inv_rev := fun a b => Prod.ext (mul_inv_rev _ _) (mul_inv_rev _ _), - inv_eq_of_mul := fun a b h => + { mul_inv_rev := fun _ _ => Prod.ext (mul_inv_rev _ _) (mul_inv_rev _ _), + inv_eq_of_mul := fun _ _ h => Prod.ext (inv_eq_of_mul_eq_one_right <| congr_arg fst h) (inv_eq_of_mul_eq_one_right <| congr_arg snd h), inv_inv := by simp } @@ -587,7 +587,24 @@ theorem coe_prodComm : ⇑(prodComm : M × N ≃* N × M) = Prod.swap := theorem coe_prodComm_symm : ⇑(prodComm : M × N ≃* N × M).symm = Prod.swap := rfl -variable {M' N' : Type*} [MulOneClass M'] [MulOneClass N'] +variable [MulOneClass P] + +/-- The equivalence between `(M × N) × P` and `M × (N × P)` is multiplicative. -/ +@[to_additive prodAssoc + "The equivalence between `(M × N) × P` and `M × (N × P)` is additive."] +def prodAssoc : (M × N) × P ≃* M × (N × P) := + { Equiv.prodAssoc M N P with map_mul' := fun ⟨_, _⟩ ⟨_, _⟩ => rfl } + +@[to_additive (attr := simp) coe_prodAssoc] +theorem coe_prodAssoc : ⇑(prodAssoc : (M × N) × P ≃* M × (N × P)) = Equiv.prodAssoc M N P := + rfl + +@[to_additive (attr := simp) coe_prodAssoc_symm] +theorem coe_prodAssoc_symm : + ⇑(prodAssoc : (M × N) × P ≃* M × (N × P)).symm = (Equiv.prodAssoc M N P).symm := + rfl + +variable {M' : Type*} {N' : Type*} [MulOneClass N'] [MulOneClass M'] section diff --git a/Mathlib/Algebra/Group/Semiconj/Units.lean b/Mathlib/Algebra/Group/Semiconj/Units.lean index 5a31a5e5130e9..45c46f379e4c2 100644 --- a/Mathlib/Algebra/Group/Semiconj/Units.lean +++ b/Mathlib/Algebra/Group/Semiconj/Units.lean @@ -6,7 +6,7 @@ Authors: Yury Kudryashov -- Some proofs and docs came from mathlib3 `src/algebra/commute.lean` (c) Neil Strickland import Mathlib.Algebra.Group.Semiconj.Defs -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic /-! # Semiconjugate elements of a semigroup diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index 556df038ddca9..4896096b2e55e 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -5,17 +5,14 @@ Authors: Kexing Ying -/ import Mathlib.Algebra.Group.Conj import Mathlib.Algebra.Group.Pi.Lemmas -import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.Data.Set.Image import Mathlib.Tactic.ApplyFun /-! # Subgroups -This file defines multiplicative and additive subgroups as an extension of submonoids, in a bundled -form (unbundled subgroups are in `Deprecated/Subgroups.lean`). - We prove subgroups of a group form a complete lattice, and results about images and preimages of subgroups under group homomorphisms. The bundled subgroups use bundled monoid homomorphisms. @@ -43,10 +40,6 @@ Notation used here: Definitions in the file: -* `Subgroup G` : the type of subgroups of a group `G` - -* `AddSubgroup A` : the type of subgroups of an additive group `A` - * `CompleteLattice (Subgroup G)` : the subgroups of `G` form a complete lattice * `Subgroup.closure k` : the minimal subgroup that includes the set `k` @@ -93,302 +86,16 @@ variable {A : Type*} [AddGroup A] section SubgroupClass -/-- `InvMemClass S G` states `S` is a type of subsets `s ⊆ G` closed under inverses. -/ -class InvMemClass (S : Type*) (G : outParam Type*) [Inv G] [SetLike S G] : Prop where - /-- `s` is closed under inverses -/ - inv_mem : ∀ {s : S} {x}, x ∈ s → x⁻¹ ∈ s - -export InvMemClass (inv_mem) - -/-- `NegMemClass S G` states `S` is a type of subsets `s ⊆ G` closed under negation. -/ -class NegMemClass (S : Type*) (G : outParam Type*) [Neg G] [SetLike S G] : Prop where - /-- `s` is closed under negation -/ - neg_mem : ∀ {s : S} {x}, x ∈ s → -x ∈ s - -export NegMemClass (neg_mem) - -/-- `SubgroupClass S G` states `S` is a type of subsets `s ⊆ G` that are subgroups of `G`. -/ -class SubgroupClass (S : Type*) (G : outParam Type*) [DivInvMonoid G] [SetLike S G] - extends SubmonoidClass S G, InvMemClass S G : Prop - -/-- `AddSubgroupClass S G` states `S` is a type of subsets `s ⊆ G` that are -additive subgroups of `G`. -/ -class AddSubgroupClass (S : Type*) (G : outParam Type*) [SubNegMonoid G] [SetLike S G] - extends AddSubmonoidClass S G, NegMemClass S G : Prop - -attribute [to_additive] InvMemClass SubgroupClass - -attribute [aesop safe apply (rule_sets := [SetLike])] inv_mem neg_mem - -@[to_additive (attr := simp)] -theorem inv_mem_iff {S G} [InvolutiveInv G] {_ : SetLike S G} [InvMemClass S G] {H : S} - {x : G} : x⁻¹ ∈ H ↔ x ∈ H := - ⟨fun h => inv_inv x ▸ inv_mem h, inv_mem⟩ - variable {M S : Type*} [DivInvMonoid M] [SetLike S M] [hSM : SubgroupClass S M] {H K : S} -/-- A subgroup is closed under division. -/ -@[to_additive (attr := aesop safe apply (rule_sets := [SetLike])) - "An additive subgroup is closed under subtraction."] -theorem div_mem {x y : M} (hx : x ∈ H) (hy : y ∈ H) : x / y ∈ H := by - rw [div_eq_mul_inv]; exact mul_mem hx (inv_mem hy) - -@[to_additive (attr := aesop safe apply (rule_sets := [SetLike]))] -theorem zpow_mem {x : M} (hx : x ∈ K) : ∀ n : ℤ, x ^ n ∈ K - | (n : ℕ) => by - rw [zpow_natCast] - exact pow_mem hx n - | -[n+1] => by - rw [zpow_negSucc] - exact inv_mem (pow_mem hx n.succ) - variable [SetLike S G] [SubgroupClass S G] @[to_additive] theorem div_mem_comm_iff {a b : G} : a / b ∈ H ↔ b / a ∈ H := inv_div b a ▸ inv_mem_iff -@[to_additive /-(attr := simp)-/] -- Porting note: `simp` cannot simplify LHS -theorem exists_inv_mem_iff_exists_mem {P : G → Prop} : - (∃ x : G, x ∈ H ∧ P x⁻¹) ↔ ∃ x ∈ H, P x := by - constructor <;> - · rintro ⟨x, x_in, hx⟩ - exact ⟨x⁻¹, inv_mem x_in, by simp [hx]⟩ - -@[to_additive] -theorem mul_mem_cancel_right {x y : G} (h : x ∈ H) : y * x ∈ H ↔ y ∈ H := - ⟨fun hba => by simpa using mul_mem hba (inv_mem h), fun hb => mul_mem hb h⟩ - -@[to_additive] -theorem mul_mem_cancel_left {x y : G} (h : x ∈ H) : x * y ∈ H ↔ y ∈ H := - ⟨fun hab => by simpa using mul_mem (inv_mem h) hab, mul_mem h⟩ - -namespace InvMemClass - -/-- A subgroup of a group inherits an inverse. -/ -@[to_additive "An additive subgroup of an `AddGroup` inherits an inverse."] -instance inv {G : Type u_1} {S : Type u_2} [Inv G] [SetLike S G] - [InvMemClass S G] {H : S} : Inv H := - ⟨fun a => ⟨a⁻¹, inv_mem a.2⟩⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_inv (x : H) : (x⁻¹).1 = x.1⁻¹ := - rfl - -end InvMemClass - -namespace SubgroupClass - -@[to_additive (attr := deprecated (since := "2024-01-15"))] alias coe_inv := InvMemClass.coe_inv - --- Here we assume H, K, and L are subgroups, but in fact any one of them --- could be allowed to be a subsemigroup. --- Counterexample where K and L are submonoids: H = ℤ, K = ℕ, L = -ℕ --- Counterexample where H and K are submonoids: H = {n | n = 0 ∨ 3 ≤ n}, K = 3ℕ + 4ℕ, L = 5ℤ -@[to_additive] -theorem subset_union {H K L : S} : (H : Set G) ⊆ K ∪ L ↔ H ≤ K ∨ H ≤ L := by - refine ⟨fun h ↦ ?_, fun h x xH ↦ h.imp (· xH) (· xH)⟩ - rw [or_iff_not_imp_left, SetLike.not_le_iff_exists] - exact fun ⟨x, xH, xK⟩ y yH ↦ (h <| mul_mem xH yH).elim - ((h yH).resolve_left fun yK ↦ xK <| (mul_mem_cancel_right yK).mp ·) - (mul_mem_cancel_left <| (h xH).resolve_left xK).mp - -/-- A subgroup of a group inherits a division -/ -@[to_additive "An additive subgroup of an `AddGroup` inherits a subtraction."] -instance div {G : Type u_1} {S : Type u_2} [DivInvMonoid G] [SetLike S G] - [SubgroupClass S G] {H : S} : Div H := - ⟨fun a b => ⟨a / b, div_mem a.2 b.2⟩⟩ - -/-- An additive subgroup of an `AddGroup` inherits an integer scaling. -/ -instance _root_.AddSubgroupClass.zsmul {M S} [SubNegMonoid M] [SetLike S M] - [AddSubgroupClass S M] {H : S} : SMul ℤ H := - ⟨fun n a => ⟨n • a.1, zsmul_mem a.2 n⟩⟩ - -/-- A subgroup of a group inherits an integer power. -/ -@[to_additive existing] -instance zpow {M S} [DivInvMonoid M] [SetLike S M] [SubgroupClass S M] {H : S} : Pow H ℤ := - ⟨fun a n => ⟨a.1 ^ n, zpow_mem a.2 n⟩⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_div (x y : H) : (x / y).1 = x.1 / y.1 := - rfl - -variable (H) - --- Prefer subclasses of `Group` over subclasses of `SubgroupClass`. -/-- A subgroup of a group inherits a group structure. -/ -@[to_additive "An additive subgroup of an `AddGroup` inherits an `AddGroup` structure."] -instance (priority := 75) toGroup : Group H := - Subtype.coe_injective.group _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) fun _ _ => rfl - --- Prefer subclasses of `CommGroup` over subclasses of `SubgroupClass`. -/-- A subgroup of a `CommGroup` is a `CommGroup`. -/ -@[to_additive "An additive subgroup of an `AddCommGroup` is an `AddCommGroup`."] -instance (priority := 75) toCommGroup {G : Type*} [CommGroup G] [SetLike S G] [SubgroupClass S G] : - CommGroup H := - Subtype.coe_injective.commGroup _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) fun _ _ => rfl - -/-- The natural group hom from a subgroup of group `G` to `G`. -/ -@[to_additive (attr := coe) - "The natural group hom from an additive subgroup of `AddGroup` `G` to `G`."] -protected def subtype : H →* G where - toFun := ((↑) : H → G); map_one' := rfl; map_mul' := fun _ _ => rfl - -@[to_additive (attr := simp)] -theorem coeSubtype : (SubgroupClass.subtype H : H → G) = ((↑) : H → G) := by - rfl - -variable {H} - -@[to_additive (attr := simp, norm_cast)] -theorem coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = (x : G) ^ n := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_zpow (x : H) (n : ℤ) : ((x ^ n : H) : G) = (x : G) ^ n := - rfl - -/-- The inclusion homomorphism from a subgroup `H` contained in `K` to `K`. -/ -@[to_additive "The inclusion homomorphism from an additive subgroup `H` contained in `K` to `K`."] -def inclusion {H K : S} (h : H ≤ K) : H →* K := - MonoidHom.mk' (fun x => ⟨x, h x.prop⟩) fun _ _=> rfl - -@[to_additive (attr := simp)] -theorem inclusion_self (x : H) : inclusion le_rfl x = x := by - cases x - rfl - -@[to_additive (attr := simp)] -theorem inclusion_mk {h : H ≤ K} (x : G) (hx : x ∈ H) : inclusion h ⟨x, hx⟩ = ⟨x, h hx⟩ := - rfl - -@[to_additive] -theorem inclusion_right (h : H ≤ K) (x : K) (hx : (x : G) ∈ H) : inclusion h ⟨x, hx⟩ = x := by - cases x - rfl - -@[simp] -theorem inclusion_inclusion {L : S} (hHK : H ≤ K) (hKL : K ≤ L) (x : H) : - inclusion hKL (inclusion hHK x) = inclusion (hHK.trans hKL) x := by - cases x - rfl - -@[to_additive (attr := simp)] -theorem coe_inclusion {H K : S} {h : H ≤ K} (a : H) : (inclusion h a : G) = a := by - cases a - simp only [inclusion, MonoidHom.mk'_apply] - -@[to_additive (attr := simp)] -theorem subtype_comp_inclusion {H K : S} (hH : H ≤ K) : - (SubgroupClass.subtype K).comp (inclusion hH) = SubgroupClass.subtype H := by - ext - simp only [MonoidHom.comp_apply, coeSubtype, coe_inclusion] - -end SubgroupClass - end SubgroupClass -/-- A subgroup of a group `G` is a subset containing 1, closed under multiplication -and closed under multiplicative inverse. -/ -structure Subgroup (G : Type*) [Group G] extends Submonoid G where - /-- `G` is closed under inverses -/ - inv_mem' {x} : x ∈ carrier → x⁻¹ ∈ carrier - -/-- An additive subgroup of an additive group `G` is a subset containing 0, closed -under addition and additive inverse. -/ -structure AddSubgroup (G : Type*) [AddGroup G] extends AddSubmonoid G where - /-- `G` is closed under negation -/ - neg_mem' {x} : x ∈ carrier → -x ∈ carrier - -attribute [to_additive] Subgroup - --- Porting note: Removed, translation already exists --- attribute [to_additive AddSubgroup.toAddSubmonoid] Subgroup.toSubmonoid - -/-- Reinterpret a `Subgroup` as a `Submonoid`. -/ -add_decl_doc Subgroup.toSubmonoid - -/-- Reinterpret an `AddSubgroup` as an `AddSubmonoid`. -/ -add_decl_doc AddSubgroup.toAddSubmonoid - -namespace Subgroup - -@[to_additive] -instance : SetLike (Subgroup G) G where - coe s := s.carrier - coe_injective' p q h := by - obtain ⟨⟨⟨hp,_⟩,_⟩,_⟩ := p - obtain ⟨⟨⟨hq,_⟩,_⟩,_⟩ := q - congr - --- Porting note: Below can probably be written more uniformly -@[to_additive] -instance : SubgroupClass (Subgroup G) G where - inv_mem := Subgroup.inv_mem' _ - one_mem _ := (Subgroup.toSubmonoid _).one_mem' - mul_mem := (Subgroup.toSubmonoid _).mul_mem' - -@[to_additive (attr := simp, nolint simpNF)] -- Porting note (#10675): dsimp can not prove this -theorem mem_carrier {s : Subgroup G} {x : G} : x ∈ s.carrier ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_mk {s : Set G} {x : G} (h_one) (h_mul) (h_inv) : - x ∈ mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_set_mk {s : Set G} (h_one) (h_mul) (h_inv) : - (mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv : Set G) = s := - rfl - -@[to_additive (attr := simp)] -theorem mk_le_mk {s t : Set G} (h_one) (h_mul) (h_inv) (h_one') (h_mul') (h_inv') : - mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv ≤ mk ⟨⟨t, h_one'⟩, h_mul'⟩ h_inv' ↔ s ⊆ t := - Iff.rfl - -initialize_simps_projections Subgroup (carrier → coe) -initialize_simps_projections AddSubgroup (carrier → coe) - -@[to_additive (attr := simp)] -theorem coe_toSubmonoid (K : Subgroup G) : (K.toSubmonoid : Set G) = K := - rfl - -@[to_additive (attr := simp)] -theorem mem_toSubmonoid (K : Subgroup G) (x : G) : x ∈ K.toSubmonoid ↔ x ∈ K := - Iff.rfl - -@[to_additive] -theorem toSubmonoid_injective : Function.Injective (toSubmonoid : Subgroup G → Submonoid G) := - -- fun p q h => SetLike.ext'_iff.2 (show _ from SetLike.ext'_iff.1 h) - fun p q h => by - have := SetLike.ext'_iff.1 h - rw [coe_toSubmonoid, coe_toSubmonoid] at this - exact SetLike.ext'_iff.2 this - -@[to_additive (attr := simp)] -theorem toSubmonoid_eq {p q : Subgroup G} : p.toSubmonoid = q.toSubmonoid ↔ p = q := - toSubmonoid_injective.eq_iff - -@[to_additive (attr := mono)] -theorem toSubmonoid_strictMono : StrictMono (toSubmonoid : Subgroup G → Submonoid G) := fun _ _ => - id - -@[to_additive (attr := mono)] -theorem toSubmonoid_mono : Monotone (toSubmonoid : Subgroup G → Submonoid G) := - toSubmonoid_strictMono.monotone - -@[to_additive (attr := simp)] -theorem toSubmonoid_le {p q : Subgroup G} : p.toSubmonoid ≤ q.toSubmonoid ↔ p ≤ q := - Iff.rfl - -@[to_additive (attr := simp)] -lemma coe_nonempty (s : Subgroup G) : (s : Set G).Nonempty := ⟨1, one_mem _⟩ - -end Subgroup - /-! ### Conversion to/from `Additive`/`Multiplicative` -/ @@ -430,211 +137,10 @@ namespace Subgroup variable (H K : Subgroup G) -/-- Copy of a subgroup with a new `carrier` equal to the old one. Useful to fix definitional -equalities. -/ -@[to_additive - "Copy of an additive subgroup with a new `carrier` equal to the old one. - Useful to fix definitional equalities"] -protected def copy (K : Subgroup G) (s : Set G) (hs : s = K) : Subgroup G where - carrier := s - one_mem' := hs.symm ▸ K.one_mem' - mul_mem' := hs.symm ▸ K.mul_mem' - inv_mem' hx := by simpa [hs] using hx -- Porting note: `▸` didn't work here - -@[to_additive (attr := simp)] -theorem coe_copy (K : Subgroup G) (s : Set G) (hs : s = ↑K) : (K.copy s hs : Set G) = s := - rfl - -@[to_additive] -theorem copy_eq (K : Subgroup G) (s : Set G) (hs : s = ↑K) : K.copy s hs = K := - SetLike.coe_injective hs - -/-- Two subgroups are equal if they have the same elements. -/ -@[to_additive (attr := ext) "Two `AddSubgroup`s are equal if they have the same elements."] -theorem ext {H K : Subgroup G} (h : ∀ x, x ∈ H ↔ x ∈ K) : H = K := - SetLike.ext h - -/-- A subgroup contains the group's 1. -/ -@[to_additive "An `AddSubgroup` contains the group's 0."] -protected theorem one_mem : (1 : G) ∈ H := - one_mem _ - -/-- A subgroup is closed under multiplication. -/ -@[to_additive "An `AddSubgroup` is closed under addition."] -protected theorem mul_mem {x y : G} : x ∈ H → y ∈ H → x * y ∈ H := - mul_mem - -/-- A subgroup is closed under inverse. -/ -@[to_additive "An `AddSubgroup` is closed under inverse."] -protected theorem inv_mem {x : G} : x ∈ H → x⁻¹ ∈ H := - inv_mem - -/-- A subgroup is closed under division. -/ -@[to_additive "An `AddSubgroup` is closed under subtraction."] -protected theorem div_mem {x y : G} (hx : x ∈ H) (hy : y ∈ H) : x / y ∈ H := - div_mem hx hy - -@[to_additive] -protected theorem inv_mem_iff {x : G} : x⁻¹ ∈ H ↔ x ∈ H := - inv_mem_iff - @[to_additive] protected theorem div_mem_comm_iff {a b : G} : a / b ∈ H ↔ b / a ∈ H := div_mem_comm_iff -@[to_additive] -protected theorem exists_inv_mem_iff_exists_mem (K : Subgroup G) {P : G → Prop} : - (∃ x : G, x ∈ K ∧ P x⁻¹) ↔ ∃ x ∈ K, P x := - exists_inv_mem_iff_exists_mem - -@[to_additive] -protected theorem mul_mem_cancel_right {x y : G} (h : x ∈ H) : y * x ∈ H ↔ y ∈ H := - mul_mem_cancel_right h - -@[to_additive] -protected theorem mul_mem_cancel_left {x y : G} (h : x ∈ H) : x * y ∈ H ↔ y ∈ H := - mul_mem_cancel_left h - -@[to_additive] -protected theorem pow_mem {x : G} (hx : x ∈ K) : ∀ n : ℕ, x ^ n ∈ K := - pow_mem hx - -@[to_additive] -protected theorem zpow_mem {x : G} (hx : x ∈ K) : ∀ n : ℤ, x ^ n ∈ K := - zpow_mem hx - -/-- Construct a subgroup from a nonempty set that is closed under division. -/ -@[to_additive "Construct a subgroup from a nonempty set that is closed under subtraction"] -def ofDiv (s : Set G) (hsn : s.Nonempty) (hs : ∀ᵉ (x ∈ s) (y ∈ s), x * y⁻¹ ∈ s) : - Subgroup G := - have one_mem : (1 : G) ∈ s := by - let ⟨x, hx⟩ := hsn - simpa using hs x hx x hx - have inv_mem : ∀ x, x ∈ s → x⁻¹ ∈ s := fun x hx => by simpa using hs 1 one_mem x hx - { carrier := s - one_mem' := one_mem - inv_mem' := inv_mem _ - mul_mem' := fun hx hy => by simpa using hs _ hx _ (inv_mem _ hy) } - -/-- A subgroup of a group inherits a multiplication. -/ -@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an addition."] -instance mul : Mul H := - H.toSubmonoid.mul - -/-- A subgroup of a group inherits a 1. -/ -@[to_additive "An `AddSubgroup` of an `AddGroup` inherits a zero."] -instance one : One H := - H.toSubmonoid.one - -/-- A subgroup of a group inherits an inverse. -/ -@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an inverse."] -instance inv : Inv H := - ⟨fun a => ⟨a⁻¹, H.inv_mem a.2⟩⟩ - -/-- A subgroup of a group inherits a division -/ -@[to_additive "An `AddSubgroup` of an `AddGroup` inherits a subtraction."] -instance div : Div H := - ⟨fun a b => ⟨a / b, H.div_mem a.2 b.2⟩⟩ - -/-- An `AddSubgroup` of an `AddGroup` inherits a natural scaling. -/ -instance _root_.AddSubgroup.nsmul {G} [AddGroup G] {H : AddSubgroup G} : SMul ℕ H := - ⟨fun n a => ⟨n • a, H.nsmul_mem a.2 n⟩⟩ - -/-- A subgroup of a group inherits a natural power -/ -@[to_additive existing] -protected instance npow : Pow H ℕ := - ⟨fun a n => ⟨a ^ n, H.pow_mem a.2 n⟩⟩ - -/-- An `AddSubgroup` of an `AddGroup` inherits an integer scaling. -/ -instance _root_.AddSubgroup.zsmul {G} [AddGroup G] {H : AddSubgroup G} : SMul ℤ H := - ⟨fun n a => ⟨n • a, H.zsmul_mem a.2 n⟩⟩ - -/-- A subgroup of a group inherits an integer power -/ -@[to_additive existing] -instance zpow : Pow H ℤ := - ⟨fun a n => ⟨a ^ n, H.zpow_mem a.2 n⟩⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_mul (x y : H) : (↑(x * y) : G) = ↑x * ↑y := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_one : ((1 : H) : G) = 1 := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_inv (x : H) : ↑(x⁻¹ : H) = (x⁻¹ : G) := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_div (x y : H) : (↑(x / y) : G) = ↑x / ↑y := - rfl - --- Porting note: removed simp, theorem has variable as head symbol -@[to_additive (attr := norm_cast)] -theorem coe_mk (x : G) (hx : x ∈ H) : ((⟨x, hx⟩ : H) : G) = x := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = (x : G) ^ n := - rfl - -@[to_additive (attr := norm_cast)] -- Porting note (#10685): dsimp can prove this -theorem coe_zpow (x : H) (n : ℤ) : ((x ^ n : H) : G) = (x : G) ^ n := - rfl - -@[to_additive (attr := simp)] -theorem mk_eq_one {g : G} {h} : (⟨g, h⟩ : H) = 1 ↔ g = 1 := Submonoid.mk_eq_one .. - -/-- A subgroup of a group inherits a group structure. -/ -@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an `AddGroup` structure."] -instance toGroup {G : Type*} [Group G] (H : Subgroup G) : Group H := - Subtype.coe_injective.group _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) fun _ _ => rfl - -/-- A subgroup of a `CommGroup` is a `CommGroup`. -/ -@[to_additive "An `AddSubgroup` of an `AddCommGroup` is an `AddCommGroup`."] -instance toCommGroup {G : Type*} [CommGroup G] (H : Subgroup G) : CommGroup H := - Subtype.coe_injective.commGroup _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) fun _ _ => rfl - -/-- The natural group hom from a subgroup of group `G` to `G`. -/ -@[to_additive "The natural group hom from an `AddSubgroup` of `AddGroup` `G` to `G`."] -protected def subtype : H →* G where - toFun := ((↑) : H → G); map_one' := rfl; map_mul' _ _ := rfl - -@[to_additive (attr := simp)] -theorem coeSubtype : ⇑ H.subtype = ((↑) : H → G) := - rfl - -@[to_additive] -theorem subtype_injective : Function.Injective (Subgroup.subtype H) := - Subtype.coe_injective - -/-- The inclusion homomorphism from a subgroup `H` contained in `K` to `K`. -/ -@[to_additive "The inclusion homomorphism from an additive subgroup `H` contained in `K` to `K`."] -def inclusion {H K : Subgroup G} (h : H ≤ K) : H →* K := - MonoidHom.mk' (fun x => ⟨x, h x.2⟩) fun _ _ => rfl - -@[to_additive (attr := simp)] -theorem coe_inclusion {H K : Subgroup G} {h : H ≤ K} (a : H) : (inclusion h a : G) = a := by - cases a - simp only [inclusion, coe_mk, MonoidHom.mk'_apply] - -@[to_additive] -theorem inclusion_injective {H K : Subgroup G} (h : H ≤ K) : Function.Injective <| inclusion h := - Set.inclusion_injective h - -@[to_additive (attr := simp)] -lemma inclusion_inj {H K : Subgroup G} (h : H ≤ K) {x y : H} : - inclusion h x = inclusion h y ↔ x = y := - (inclusion_injective h).eq_iff - -@[to_additive (attr := simp)] -theorem subtype_comp_inclusion {H K : Subgroup G} (hH : H ≤ K) : - K.subtype.comp (inclusion hH) = H.subtype := - rfl - /-- The subgroup `G` of the group `G`. -/ @[to_additive "The `AddSubgroup G` of the `AddGroup G`."] instance : Top (Subgroup G) := @@ -818,12 +324,12 @@ theorem mem_sSup_of_mem {S : Set (Subgroup G)} {s : Subgroup G} (hs : s ∈ S) : @[to_additive (attr := simp)] theorem subsingleton_iff : Subsingleton (Subgroup G) ↔ Subsingleton G := - ⟨fun h => + ⟨fun _ => ⟨fun x y => have : ∀ i : G, i = 1 := fun i => mem_bot.mp <| Subsingleton.elim (⊤ : Subgroup G) ⊥ ▸ mem_top i (this x).trans (this y).symm⟩, - fun h => ⟨fun x y => Subgroup.ext fun i => Subsingleton.elim 1 i ▸ by simp [Subgroup.one_mem]⟩⟩ + fun _ => ⟨fun x y => Subgroup.ext fun i => Subsingleton.elim 1 i ▸ by simp [Subgroup.one_mem]⟩⟩ @[to_additive (attr := simp)] theorem nontrivial_iff : Nontrivial (Subgroup G) ↔ Nontrivial G := @@ -888,43 +394,47 @@ only require showing `p` is preserved by multiplication by elements in `k`. -/ See also `AddSubgroup.closure_induction_left` and `AddSubgroup.closure_induction_left` for versions that only require showing `p` is preserved by addition by elements in `k`."] -theorem closure_induction {p : G → Prop} {x} (h : x ∈ closure k) (mem : ∀ x ∈ k, p x) (one : p 1) - (mul : ∀ x y, p x → p y → p (x * y)) (inv : ∀ x, p x → p x⁻¹) : p x := - (@closure_le _ _ ⟨⟨⟨setOf p, fun {x y} ↦ mul x y⟩, one⟩, fun {x} ↦ inv x⟩ k).2 mem h - -/-- A dependent version of `Subgroup.closure_induction`. -/ -@[to_additive (attr := elab_as_elim) "A dependent version of `AddSubgroup.closure_induction`. "] -theorem closure_induction' {p : ∀ x, x ∈ closure k → Prop} - (mem : ∀ (x) (h : x ∈ k), p x (subset_closure h)) (one : p 1 (one_mem _)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) - (inv : ∀ x hx, p x hx → p x⁻¹ (inv_mem hx)) {x} (hx : x ∈ closure k) : p x hx := by - refine Exists.elim ?_ fun (hx : x ∈ closure k) (hc : p x hx) => hc - exact - closure_induction hx (fun x hx => ⟨_, mem x hx⟩) ⟨_, one⟩ - (fun x y ⟨hx', hx⟩ ⟨hy', hy⟩ => ⟨_, mul _ _ _ _ hx hy⟩) fun x ⟨hx', hx⟩ => ⟨_, inv _ _ hx⟩ +theorem closure_induction {p : (g : G) → g ∈ closure k → Prop} + (mem : ∀ x (hx : x ∈ k), p x (subset_closure hx)) (one : p 1 (one_mem _)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + (inv : ∀ x hx, p x hx → p x⁻¹ (inv_mem hx)) {x} (hx : x ∈ closure k) : p x hx := + let K : Subgroup G := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, ha⟩ ⟨_, hb⟩ ↦ ⟨_, mul _ _ _ _ ha hb⟩ + one_mem' := ⟨_, one⟩ + inv_mem' := fun ⟨_, hb⟩ ↦ ⟨_, inv _ _ hb⟩ } + closure_le (K := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction /-- An induction principle for closure membership for predicates with two arguments. -/ @[to_additive (attr := elab_as_elim) "An induction principle for additive closure membership, for predicates with two arguments."] -theorem closure_induction₂ {p : G → G → Prop} {x} {y : G} (hx : x ∈ closure k) (hy : y ∈ closure k) - (Hk : ∀ x ∈ k, ∀ y ∈ k, p x y) (H1_left : ∀ x, p 1 x) (H1_right : ∀ x, p x 1) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) (Hinv_left : ∀ x y, p x y → p x⁻¹ y) - (Hinv_right : ∀ x y, p x y → p x y⁻¹) : p x y := - closure_induction hx - (fun x xk => closure_induction hy (Hk x xk) (H1_right x) (Hmul_right x) (Hinv_right x)) - (H1_left y) (fun z z' => Hmul_left z z' y) fun z => Hinv_left z y +theorem closure_induction₂ {p : (x y : G) → x ∈ closure k → y ∈ closure k → Prop} + (mem : ∀ (x) (y) (hx : x ∈ k) (hy : y ∈ k), p x y (subset_closure hx) (subset_closure hy)) + (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ y z x hy hz hx, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + (inv_left : ∀ x y hx hy, p x y hx hy → p x⁻¹ y (inv_mem hx) hy) + (inv_right : ∀ x y hx hy, p x y hx hy → p x y⁻¹ hx (inv_mem hy)) + {x y : G} (hx : x ∈ closure k) (hy : y ∈ closure k) : p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem _ _ h hz + | one => exact one_left _ (subset_closure hz) + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | inv _ _ h => exact inv_left _ _ _ _ h + | one => exact one_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ hx h₁ h₂ + | inv _ _ h => exact inv_right _ _ _ _ h @[to_additive (attr := simp)] theorem closure_closure_coe_preimage {k : Set G} : closure (((↑) : closure k → G) ⁻¹' k) = ⊤ := - eq_top_iff.2 fun x => - Subtype.recOn x fun x hx _ => by - refine closure_induction' (fun g hg => ?_) ?_ (fun g₁ g₂ hg₁ hg₂ => ?_) (fun g hg => ?_) hx - · exact subset_closure hg - · exact one_mem _ - · exact mul_mem - · exact inv_mem + eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ + closure_induction (fun _ h ↦ subset_closure h) (one_mem _) (fun _ _ _ _ ↦ mul_mem) + (fun _ _ ↦ inv_mem) hx' /-- If all the elements of a set `s` commute, then `closure s` is a commutative group. -/ @[to_additive @@ -933,18 +443,19 @@ theorem closure_closure_coe_preimage {k : Set G} : closure (((↑) : closure k def closureCommGroupOfComm {k : Set G} (hcomm : ∀ x ∈ k, ∀ y ∈ k, x * y = y * x) : CommGroup (closure k) := { (closure k).toGroup with - mul_comm := fun x y => by + mul_comm := fun ⟨x, hx⟩ ⟨y, hy⟩ => by ext simp only [Subgroup.coe_mul] - refine - closure_induction₂ x.prop y.prop hcomm (fun x => by simp only [mul_one, one_mul]) - (fun x => by simp only [mul_one, one_mul]) - (fun x y z h₁ h₂ => by rw [mul_assoc, h₂, ← mul_assoc, h₁, mul_assoc]) - (fun x y z h₁ h₂ => by rw [← mul_assoc, h₁, mul_assoc, h₂, ← mul_assoc]) - (fun x y h => by - rw [inv_mul_eq_iff_eq_mul, ← mul_assoc, h, mul_assoc, mul_inv_cancel, mul_one]) - fun x y h => by - rw [mul_inv_eq_iff_eq_mul, mul_assoc, h, ← mul_assoc, inv_mul_cancel, one_mul] } + induction hx, hy using closure_induction₂ with + | mem x y hx hy => exact hcomm x hx y hy + | one_left x _ => exact Commute.one_left x + | one_right x _ => exact Commute.one_right x + | mul_left _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_left h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_right h₁ h₂ + | inv_left _ _ _ _ h => -- `Commute.inv_left` is not imported + rw [inv_mul_eq_iff_eq_mul, ← mul_assoc, h, mul_assoc, mul_inv_cancel, mul_one] + | inv_right _ _ _ _ h => + rw [mul_inv_eq_iff_eq_mul, mul_assoc, h, ← mul_assoc, inv_mul_cancel, one_mul] } variable (G) @@ -1005,15 +516,15 @@ theorem iSup_eq_closure {ι : Sort*} (p : ι → Subgroup G) : natural number multiples of the element."] theorem mem_closure_singleton {x y : G} : y ∈ closure ({x} : Set G) ↔ ∃ n : ℤ, x ^ n = y := by refine - ⟨fun hy => closure_induction hy ?_ ?_ ?_ ?_, fun ⟨n, hn⟩ => + ⟨fun hy => closure_induction ?_ ?_ ?_ ?_ hy, fun ⟨n, hn⟩ => hn ▸ zpow_mem (subset_closure <| mem_singleton x) n⟩ · intro y hy rw [eq_of_mem_singleton hy] exact ⟨1, zpow_one x⟩ · exact ⟨0, zpow_zero x⟩ - · rintro _ _ ⟨n, rfl⟩ ⟨m, rfl⟩ + · rintro _ _ _ _ ⟨n, rfl⟩ ⟨m, rfl⟩ exact ⟨n + m, zpow_add x n m⟩ - rintro _ ⟨n, rfl⟩ + rintro _ _ ⟨n, rfl⟩ exact ⟨-n, zpow_neg x n⟩ @[to_additive] @@ -1039,12 +550,12 @@ theorem mem_iSup_of_directed {ι} [hι : Nonempty ι] {K : ι → Subgroup G} (h refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup K i hi⟩ suffices x ∈ closure (⋃ i, (K i : Set G)) → ∃ i, x ∈ K i by simpa only [closure_iUnion, closure_eq (K _)] using this - refine fun hx ↦ closure_induction hx (fun _ ↦ mem_iUnion.1) ?_ ?_ ?_ + refine fun hx ↦ closure_induction (fun _ ↦ mem_iUnion.1) ?_ ?_ ?_ hx · exact hι.elim fun i ↦ ⟨i, (K i).one_mem⟩ - · rintro x y ⟨i, hi⟩ ⟨j, hj⟩ + · rintro x y _ _ ⟨i, hi⟩ ⟨j, hj⟩ rcases hK i j with ⟨k, hki, hkj⟩ exact ⟨k, mul_mem (hki hi) (hkj hj)⟩ - · rintro _ ⟨i, hi⟩ + · rintro _ _ ⟨i, hi⟩ exact ⟨i, inv_mem hi⟩ @[to_additive] @@ -1396,6 +907,15 @@ theorem prod_le_iff {H : Subgroup G} {K : Subgroup N} {J : Subgroup (G × N)} : theorem prod_eq_bot_iff {H : Subgroup G} {K : Subgroup N} : H.prod K = ⊥ ↔ H = ⊥ ∧ K = ⊥ := by simpa only [← Subgroup.toSubmonoid_eq] using Submonoid.prod_eq_bot_iff +@[to_additive closure_prod] +theorem closure_prod {s : Set G} {t : Set N} (hs : 1 ∈ s) (ht : 1 ∈ t) : + closure (s ×ˢ t) = (closure s).prod (closure t) := + le_antisymm + (closure_le _ |>.2 <| Set.prod_subset_prod_iff.2 <| .inl ⟨subset_closure, subset_closure⟩) + (prod_le_iff.2 ⟨ + map_le_iff_le_comap.2 <| closure_le _ |>.2 fun _x hx => subset_closure ⟨hx, ht⟩, + map_le_iff_le_comap.2 <| closure_le _ |>.2 fun _y hy => subset_closure ⟨hs, hy⟩⟩) + /-- Product of subgroups is isomorphic to their product as groups. -/ @[to_additive prodEquiv "Product of additive subgroups is isomorphic to their product @@ -1493,57 +1013,12 @@ theorem pi_eq_bot_iff (H : ∀ i, Subgroup (f i)) : pi Set.univ H = ⊥ ↔ ∀ end Pi -/-- A subgroup is normal if whenever `n ∈ H`, then `g * n * g⁻¹ ∈ H` for every `g : G` -/ -structure Normal : Prop where - /-- `N` is closed under conjugation -/ - conj_mem : ∀ n, n ∈ H → ∀ g : G, g * n * g⁻¹ ∈ H - -attribute [class] Normal - end Subgroup -namespace AddSubgroup - -/-- An AddSubgroup is normal if whenever `n ∈ H`, then `g + n - g ∈ H` for every `g : G` -/ -structure Normal (H : AddSubgroup A) : Prop where - /-- `N` is closed under additive conjugation -/ - conj_mem : ∀ n, n ∈ H → ∀ g : A, g + n + -g ∈ H - -attribute [to_additive] Subgroup.Normal - -attribute [class] Normal - -end AddSubgroup - namespace Subgroup variable {H K : Subgroup G} -@[to_additive] -instance (priority := 100) normal_of_comm {G : Type*} [CommGroup G] (H : Subgroup G) : H.Normal := - ⟨by simp [mul_comm, mul_left_comm]⟩ - -namespace Normal - -@[to_additive] -theorem conj_mem' (nH : H.Normal) (n : G) (hn : n ∈ H) (g : G) : - g⁻¹ * n * g ∈ H := by - convert nH.conj_mem n hn g⁻¹ - rw [inv_inv] - -@[to_additive] -theorem mem_comm (nH : H.Normal) {a b : G} (h : a * b ∈ H) : b * a ∈ H := by - have : a⁻¹ * (a * b) * a⁻¹⁻¹ ∈ H := nH.conj_mem (a * b) h a⁻¹ - -- Porting note: Previous code was: - -- simpa - simp_all only [inv_mul_cancel_left, inv_inv] - -@[to_additive] -theorem mem_comm_iff (nH : H.Normal) {a b : G} : a * b ∈ H ↔ b * a ∈ H := - ⟨nH.mem_comm, nH.mem_comm⟩ - -end Normal - variable (H) /-- A subgroup is characteristic if it is fixed by all automorphisms. @@ -1626,53 +1101,8 @@ variable (H) section Normalizer -/-- The `normalizer` of `H` is the largest subgroup of `G` inside which `H` is normal. -/ -@[to_additive "The `normalizer` of `H` is the largest subgroup of `G` inside which `H` is normal."] -def normalizer : Subgroup G where - carrier := { g : G | ∀ n, n ∈ H ↔ g * n * g⁻¹ ∈ H } - one_mem' := by simp - mul_mem' {a b} (ha : ∀ n, n ∈ H ↔ a * n * a⁻¹ ∈ H) (hb : ∀ n, n ∈ H ↔ b * n * b⁻¹ ∈ H) n := by - rw [hb, ha] - simp only [mul_assoc, mul_inv_rev] - inv_mem' {a} (ha : ∀ n, n ∈ H ↔ a * n * a⁻¹ ∈ H) n := by - rw [ha (a⁻¹ * n * a⁻¹⁻¹)] - simp only [inv_inv, mul_assoc, mul_inv_cancel_left, mul_inv_cancel, mul_one] - --- variant for sets. --- TODO should this replace `normalizer`? -/-- The `setNormalizer` of `S` is the subgroup of `G` whose elements satisfy `g*S*g⁻¹=S` -/ -@[to_additive - "The `setNormalizer` of `S` is the subgroup of `G` whose elements satisfy - `g+S-g=S`."] -def setNormalizer (S : Set G) : Subgroup G where - carrier := { g : G | ∀ n, n ∈ S ↔ g * n * g⁻¹ ∈ S } - one_mem' := by simp - mul_mem' {a b} (ha : ∀ n, n ∈ S ↔ a * n * a⁻¹ ∈ S) (hb : ∀ n, n ∈ S ↔ b * n * b⁻¹ ∈ S) n := by - rw [hb, ha] - simp only [mul_assoc, mul_inv_rev] - inv_mem' {a} (ha : ∀ n, n ∈ S ↔ a * n * a⁻¹ ∈ S) n := by - rw [ha (a⁻¹ * n * a⁻¹⁻¹)] - simp only [inv_inv, mul_assoc, mul_inv_cancel_left, mul_inv_cancel, mul_one] - variable {H} -@[to_additive] -theorem mem_normalizer_iff {g : G} : g ∈ H.normalizer ↔ ∀ h, h ∈ H ↔ g * h * g⁻¹ ∈ H := - Iff.rfl - -@[to_additive] -theorem mem_normalizer_iff'' {g : G} : g ∈ H.normalizer ↔ ∀ h : G, h ∈ H ↔ g⁻¹ * h * g ∈ H := by - rw [← inv_mem_iff (x := g), mem_normalizer_iff, inv_inv] - -@[to_additive] -theorem mem_normalizer_iff' {g : G} : g ∈ H.normalizer ↔ ∀ n, n * g ∈ H ↔ g * n ∈ H := - ⟨fun h n => by rw [h, mul_assoc, mul_inv_cancel_right], fun h n => by - rw [mul_assoc, ← h, inv_mul_cancel_right]⟩ - -@[to_additive] -theorem le_normalizer : H ≤ normalizer H := fun x xH n => by - rw [H.mul_mem_cancel_right (H.inv_mem xH), H.mul_mem_cancel_left xH] - @[to_additive] instance (priority := 100) normal_in_normalizer : (H.subgroupOf H.normalizer).Normal := ⟨fun x xH g => by simpa only [mem_subgroupOf] using (g.2 x.1).1 xH⟩ @@ -1734,32 +1164,6 @@ variable (H) end Normalizer -/-- Commutativity of a subgroup -/ -structure IsCommutative : Prop where - /-- `*` is commutative on `H` -/ - is_comm : Std.Commutative (α := H) (· * ·) - -attribute [class] IsCommutative - -/-- Commutativity of an additive subgroup -/ -structure _root_.AddSubgroup.IsCommutative (H : AddSubgroup A) : Prop where - /-- `+` is commutative on `H` -/ - is_comm : Std.Commutative (α := H) (· + ·) - -attribute [to_additive] Subgroup.IsCommutative - -attribute [class] AddSubgroup.IsCommutative - -/-- A commutative subgroup is commutative. -/ -@[to_additive "A commutative subgroup is commutative."] -instance IsCommutative.commGroup [h : H.IsCommutative] : CommGroup H := - { H.toGroup with mul_comm := h.is_comm.comm } - -/-- A subgroup of a commutative group is commutative. -/ -@[to_additive "A subgroup of a commutative group is commutative."] -instance commGroup_isCommutative {G : Type*} [CommGroup G] (H : Subgroup G) : H.IsCommutative := - ⟨CommMagma.to_isCommutative⟩ - @[to_additive] instance map_isCommutative (f : G →* G') [H.IsCommutative] : (H.map f).IsCommutative := ⟨⟨by @@ -1781,11 +1185,6 @@ theorem comap_injective_isCommutative {f : G' →* G} (hf : Injective f) [H.IsCo instance subgroupOf_isCommutative [H.IsCommutative] : (H.subgroupOf K).IsCommutative := H.comap_injective_isCommutative Subtype.coe_injective -@[to_additive] -lemma mul_comm_of_mem_isCommutative [H.IsCommutative] {a b : G} (ha : a ∈ H) (hb : b ∈ H) : - a * b = b * a := by - simpa only [MulMemClass.mk_mul_mk, Subtype.mk.injEq] using mul_comm (⟨a, ha⟩ : H) (⟨b, hb⟩ : H) - end Subgroup namespace MulEquiv @@ -1884,7 +1283,8 @@ theorem le_normalClosure {H : Subgroup G} : H ≤ normalClosure ↑H := fun _ h /-- The normal closure of `s` is a normal subgroup. -/ instance normalClosure_normal : (normalClosure s).Normal := ⟨fun n h g => by - refine Subgroup.closure_induction h (fun x hx => ?_) ?_ (fun x y ihx ihy => ?_) fun x ihx => ?_ + refine Subgroup.closure_induction (fun x hx => ?_) ?_ (fun x y _ _ ihx ihy => ?_) + (fun x _ ihx => ?_) h · exact conjugatesOfSet_subset_normalClosure (conj_mem_conjugatesOfSet hx) · simpa using (normalClosure s).one_mem · rw [← conj_mul] @@ -1895,7 +1295,7 @@ instance normalClosure_normal : (normalClosure s).Normal := /-- The normal closure of `s` is the smallest normal subgroup containing `s`. -/ theorem normalClosure_le_normal {N : Subgroup G} [N.Normal] (h : s ⊆ N) : normalClosure s ≤ N := by intro a w - refine closure_induction w (fun x hx => ?_) ?_ (fun x y ihx ihy => ?_) fun x ihx => ?_ + refine closure_induction (fun x hx => ?_) ?_ (fun x y _ _ ihx ihy => ?_) (fun x _ ihx => ?_) w · exact conjugatesOfSet_subset h hx · exact one_mem _ · exact mul_mem ihx ihy @@ -1909,7 +1309,7 @@ theorem normalClosure_mono {s t : Set G} (h : s ⊆ t) : normalClosure s ≤ nor theorem normalClosure_eq_iInf : normalClosure s = ⨅ (N : Subgroup G) (_ : Normal N) (_ : s ⊆ N), N := - le_antisymm (le_iInf fun N => le_iInf fun hN => le_iInf normalClosure_le_normal) + le_antisymm (le_iInf fun _ => le_iInf fun _ => le_iInf normalClosure_le_normal) (iInf_le_of_le (normalClosure s) (iInf_le_of_le (by infer_instance) (iInf_le_of_le subset_normalClosure le_rfl))) @@ -1917,7 +1317,6 @@ theorem normalClosure_eq_iInf : theorem normalClosure_eq_self (H : Subgroup G) [H.Normal] : normalClosure ↑H = H := le_antisymm (normalClosure_le_normal rfl.subset) le_normalClosure --- @[simp] -- Porting note (#10618): simp can prove this theorem normalClosure_idempotent : normalClosure ↑(normalClosure s) = normalClosure s := normalClosure_eq_self _ @@ -1934,8 +1333,8 @@ as shown by `Subgroup.normalCore_eq_iSup`. -/ def normalCore (H : Subgroup G) : Subgroup G where carrier := { a : G | ∀ b : G, b * a * b⁻¹ ∈ H } one_mem' a := by rw [mul_one, mul_inv_cancel]; exact H.one_mem - inv_mem' {a} h b := (congr_arg (· ∈ H) conj_inv).mp (H.inv_mem (h b)) - mul_mem' {a b} ha hb c := (congr_arg (· ∈ H) conj_mul).mp (H.mul_mem (ha c) (hb c)) + inv_mem' {_} h b := (congr_arg (· ∈ H) conj_inv).mp (H.inv_mem (h b)) + mul_mem' {_ _} ha hb c := (congr_arg (· ∈ H) conj_mul).mp (H.mul_mem (ha c) (hb c)) theorem normalCore_le (H : Subgroup G) : H.normalCore ≤ H := fun a h => by rw [← mul_one a, ← inv_one, ← one_mul a] @@ -1963,7 +1362,6 @@ theorem normalCore_eq_iSup (H : Subgroup G) : theorem normalCore_eq_self (H : Subgroup G) [H.Normal] : H.normalCore = H := le_antisymm H.normalCore_le (normal_le_normalCore.mpr le_rfl) --- @[simp] -- Porting note (#10618): simp can prove this theorem normalCore_idempotent (H : Subgroup G) : H.normalCore.normalCore = H.normalCore := H.normalCore.normalCore_eq_self @@ -2104,7 +1502,7 @@ theorem ofLeftInverse_symm_apply {f : G →* N} {g : N →* G} (h : Function.Lef domain."] noncomputable def ofInjective {f : G →* N} (hf : Function.Injective f) : G ≃* f.range := MulEquiv.ofBijective (f.codRestrict f.range fun x => ⟨x, rfl⟩) - ⟨fun x y h => hf (Subtype.ext_iff.mp h), by + ⟨fun _ _ h => hf (Subtype.ext_iff.mp h), by rintro ⟨x, y, rfl⟩ exact ⟨y, rfl⟩⟩ @@ -2193,7 +1591,7 @@ theorem ker_id : (MonoidHom.id G).ker = ⊥ := @[to_additive] theorem ker_eq_bot_iff (f : G →* M) : f.ker = ⊥ ↔ Function.Injective f := ⟨fun h x y hxy => by rwa [eq_iff, h, mem_bot, inv_mul_eq_one, eq_comm] at hxy, fun h => - bot_unique fun x hx => h (hx.trans f.map_one.symm)⟩ + bot_unique fun _ hx => h (hx.trans f.map_one.symm)⟩ @[to_additive (attr := simp)] theorem _root_.Subgroup.ker_subtype (H : Subgroup G) : H.subtype.ker = ⊥ := @@ -2758,14 +2156,14 @@ variable {C : Type*} [CommGroup C] {s t : Subgroup C} {x : C} theorem mem_sup : x ∈ s ⊔ t ↔ ∃ y ∈ s, ∃ z ∈ t, y * z = x := ⟨fun h => by rw [sup_eq_closure] at h - refine Subgroup.closure_induction h ?_ ?_ ?_ ?_ + refine Subgroup.closure_induction ?_ ?_ ?_ ?_ h · rintro y (h | h) · exact ⟨y, h, 1, t.one_mem, by simp⟩ · exact ⟨1, s.one_mem, y, h, by simp⟩ · exact ⟨1, s.one_mem, 1, ⟨t.one_mem, mul_one 1⟩⟩ - · rintro _ _ ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ + · rintro _ _ _ _ ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ exact ⟨_, mul_mem hy₁ hy₂, _, mul_mem hz₁ hz₂, by simp [mul_assoc, mul_left_comm]⟩ - · rintro _ ⟨y, hy, z, hz, rfl⟩ + · rintro _ _ ⟨y, hy, z, hz, rfl⟩ exact ⟨_, inv_mem hy, _, inv_mem hz, mul_comm z y ▸ (mul_inv_rev z y).symm⟩, by rintro ⟨y, hy, z, hz, rfl⟩; exact mul_mem_sup hy hz⟩ @@ -2879,7 +2277,7 @@ theorem disjoint_iff_mul_eq_one {H₁ H₂ : Subgroup G} : ⟨fun h x y hx hy hxy => let hx1 : x = 1 := h hx (H₂.inv_mem hy) (eq_inv_iff_mul_eq_one.mpr hxy) ⟨hx1, by simpa [hx1] using hxy⟩, - fun h x y hx hy hxy => (h hx (H₂.inv_mem hy) (mul_inv_eq_one.mpr hxy)).1⟩ + fun h _ _ hx hy hxy => (h hx (H₂.inv_mem hy) (mul_inv_eq_one.mpr hxy)).1⟩ @[to_additive] theorem mul_injective_of_disjoint {H₁ H₂ : Subgroup G} (h : Disjoint H₁ H₂) : @@ -2931,4 +2329,4 @@ def noncenter (G : Type*) [Monoid G] : Set (ConjClasses G) := end ConjClasses -set_option linter.style.longFile 3000 +set_option linter.style.longFile 2500 diff --git a/Mathlib/Algebra/Group/Subgroup/Defs.lean b/Mathlib/Algebra/Group/Subgroup/Defs.lean new file mode 100644 index 0000000000000..2bbdaa180486f --- /dev/null +++ b/Mathlib/Algebra/Group/Subgroup/Defs.lean @@ -0,0 +1,704 @@ +/- +Copyright (c) 2020 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying +-/ +import Mathlib.Algebra.Group.Submonoid.Defs +import Mathlib.Tactic.Common + +/-! +# Subgroups + +This file defines multiplicative and additive subgroups as an extension of submonoids, in a bundled +form (unbundled subgroups are in `Deprecated/Subgroups.lean`). + +Special thanks goes to Amelia Livingston and Yury Kudryashov for their help and inspiration. + +## Main definitions + +Notation used here: + +- `G N` are `Group`s + +- `A` is an `AddGroup` + +- `H K` are `Subgroup`s of `G` or `AddSubgroup`s of `A` + +- `x` is an element of type `G` or type `A` + +- `f g : N →* G` are group homomorphisms + +- `s k` are sets of elements of type `G` + +Definitions in the file: + +* `Subgroup G` : the type of subgroups of a group `G` + +* `AddSubgroup A` : the type of subgroups of an additive group `A` + +* `Subgroup.subtype` : the natural group homomorphism from a subgroup of group `G` to `G` + +## Implementation notes + +Subgroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a subgroup's underlying set. + +## Tags +subgroup, subgroups +-/ + +assert_not_exists OrderedAddCommMonoid +assert_not_exists Multiset +assert_not_exists Ring + +open Function +open scoped Int + +variable {G G' G'' : Type*} [Group G] [Group G'] [Group G''] +variable {A : Type*} [AddGroup A] + +section SubgroupClass + +/-- `InvMemClass S G` states `S` is a type of subsets `s ⊆ G` closed under inverses. -/ +class InvMemClass (S : Type*) (G : outParam Type*) [Inv G] [SetLike S G] : Prop where + /-- `s` is closed under inverses -/ + inv_mem : ∀ {s : S} {x}, x ∈ s → x⁻¹ ∈ s + +export InvMemClass (inv_mem) + +/-- `NegMemClass S G` states `S` is a type of subsets `s ⊆ G` closed under negation. -/ +class NegMemClass (S : Type*) (G : outParam Type*) [Neg G] [SetLike S G] : Prop where + /-- `s` is closed under negation -/ + neg_mem : ∀ {s : S} {x}, x ∈ s → -x ∈ s + +export NegMemClass (neg_mem) + +/-- `SubgroupClass S G` states `S` is a type of subsets `s ⊆ G` that are subgroups of `G`. -/ +class SubgroupClass (S : Type*) (G : outParam Type*) [DivInvMonoid G] [SetLike S G] + extends SubmonoidClass S G, InvMemClass S G : Prop + +/-- `AddSubgroupClass S G` states `S` is a type of subsets `s ⊆ G` that are +additive subgroups of `G`. -/ +class AddSubgroupClass (S : Type*) (G : outParam Type*) [SubNegMonoid G] [SetLike S G] + extends AddSubmonoidClass S G, NegMemClass S G : Prop + +attribute [to_additive] InvMemClass SubgroupClass + +attribute [aesop safe apply (rule_sets := [SetLike])] inv_mem neg_mem + +@[to_additive (attr := simp)] +theorem inv_mem_iff {S G} [InvolutiveInv G] {_ : SetLike S G} [InvMemClass S G] {H : S} + {x : G} : x⁻¹ ∈ H ↔ x ∈ H := + ⟨fun h => inv_inv x ▸ inv_mem h, inv_mem⟩ + +variable {M S : Type*} [DivInvMonoid M] [SetLike S M] [hSM : SubgroupClass S M] {H K : S} + +/-- A subgroup is closed under division. -/ +@[to_additive (attr := aesop safe apply (rule_sets := [SetLike])) + "An additive subgroup is closed under subtraction."] +theorem div_mem {x y : M} (hx : x ∈ H) (hy : y ∈ H) : x / y ∈ H := by + rw [div_eq_mul_inv]; exact mul_mem hx (inv_mem hy) + +@[to_additive (attr := aesop safe apply (rule_sets := [SetLike]))] +theorem zpow_mem {x : M} (hx : x ∈ K) : ∀ n : ℤ, x ^ n ∈ K + | (n : ℕ) => by + rw [zpow_natCast] + exact pow_mem hx n + | -[n+1] => by + rw [zpow_negSucc] + exact inv_mem (pow_mem hx n.succ) + +variable [SetLike S G] [SubgroupClass S G] + +@[to_additive /-(attr := simp)-/] -- Porting note: `simp` cannot simplify LHS +theorem exists_inv_mem_iff_exists_mem {P : G → Prop} : + (∃ x : G, x ∈ H ∧ P x⁻¹) ↔ ∃ x ∈ H, P x := by + constructor <;> + · rintro ⟨x, x_in, hx⟩ + exact ⟨x⁻¹, inv_mem x_in, by simp [hx]⟩ + +@[to_additive] +theorem mul_mem_cancel_right {x y : G} (h : x ∈ H) : y * x ∈ H ↔ y ∈ H := + ⟨fun hba => by simpa using mul_mem hba (inv_mem h), fun hb => mul_mem hb h⟩ + +@[to_additive] +theorem mul_mem_cancel_left {x y : G} (h : x ∈ H) : x * y ∈ H ↔ y ∈ H := + ⟨fun hab => by simpa using mul_mem (inv_mem h) hab, mul_mem h⟩ + +namespace InvMemClass + +/-- A subgroup of a group inherits an inverse. -/ +@[to_additive "An additive subgroup of an `AddGroup` inherits an inverse."] +instance inv {G : Type u_1} {S : Type u_2} [Inv G] [SetLike S G] + [InvMemClass S G] {H : S} : Inv H := + ⟨fun a => ⟨a⁻¹, inv_mem a.2⟩⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_inv (x : H) : (x⁻¹).1 = x.1⁻¹ := + rfl + +end InvMemClass + +namespace SubgroupClass + +@[to_additive (attr := deprecated (since := "2024-01-15"))] alias coe_inv := InvMemClass.coe_inv + +-- Here we assume H, K, and L are subgroups, but in fact any one of them +-- could be allowed to be a subsemigroup. +-- Counterexample where K and L are submonoids: H = ℤ, K = ℕ, L = -ℕ +-- Counterexample where H and K are submonoids: H = {n | n = 0 ∨ 3 ≤ n}, K = 3ℕ + 4ℕ, L = 5ℤ +@[to_additive] +theorem subset_union {H K L : S} : (H : Set G) ⊆ K ∪ L ↔ H ≤ K ∨ H ≤ L := by + refine ⟨fun h ↦ ?_, fun h x xH ↦ h.imp (· xH) (· xH)⟩ + rw [or_iff_not_imp_left, SetLike.not_le_iff_exists] + exact fun ⟨x, xH, xK⟩ y yH ↦ (h <| mul_mem xH yH).elim + ((h yH).resolve_left fun yK ↦ xK <| (mul_mem_cancel_right yK).mp ·) + (mul_mem_cancel_left <| (h xH).resolve_left xK).mp + +/-- A subgroup of a group inherits a division -/ +@[to_additive "An additive subgroup of an `AddGroup` inherits a subtraction."] +instance div {G : Type u_1} {S : Type u_2} [DivInvMonoid G] [SetLike S G] + [SubgroupClass S G] {H : S} : Div H := + ⟨fun a b => ⟨a / b, div_mem a.2 b.2⟩⟩ + +/-- An additive subgroup of an `AddGroup` inherits an integer scaling. -/ +instance _root_.AddSubgroupClass.zsmul {M S} [SubNegMonoid M] [SetLike S M] + [AddSubgroupClass S M] {H : S} : SMul ℤ H := + ⟨fun n a => ⟨n • a.1, zsmul_mem a.2 n⟩⟩ + +/-- A subgroup of a group inherits an integer power. -/ +@[to_additive existing] +instance zpow {M S} [DivInvMonoid M] [SetLike S M] [SubgroupClass S M] {H : S} : Pow H ℤ := + ⟨fun a n => ⟨a.1 ^ n, zpow_mem a.2 n⟩⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_div (x y : H) : (x / y).1 = x.1 / y.1 := + rfl + +variable (H) + +-- Prefer subclasses of `Group` over subclasses of `SubgroupClass`. +/-- A subgroup of a group inherits a group structure. -/ +@[to_additive "An additive subgroup of an `AddGroup` inherits an `AddGroup` structure."] +instance (priority := 75) toGroup : Group H := + Subtype.coe_injective.group _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) fun _ _ => rfl + +-- Prefer subclasses of `CommGroup` over subclasses of `SubgroupClass`. +/-- A subgroup of a `CommGroup` is a `CommGroup`. -/ +@[to_additive "An additive subgroup of an `AddCommGroup` is an `AddCommGroup`."] +instance (priority := 75) toCommGroup {G : Type*} [CommGroup G] [SetLike S G] [SubgroupClass S G] : + CommGroup H := + Subtype.coe_injective.commGroup _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) fun _ _ => rfl + +/-- The natural group hom from a subgroup of group `G` to `G`. -/ +@[to_additive (attr := coe) + "The natural group hom from an additive subgroup of `AddGroup` `G` to `G`."] +protected def subtype : H →* G where + toFun := ((↑) : H → G); map_one' := rfl; map_mul' := fun _ _ => rfl + +@[to_additive (attr := simp)] +theorem coeSubtype : (SubgroupClass.subtype H : H → G) = ((↑) : H → G) := by + rfl + +variable {H} + +@[to_additive (attr := simp, norm_cast)] +theorem coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = (x : G) ^ n := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_zpow (x : H) (n : ℤ) : ((x ^ n : H) : G) = (x : G) ^ n := + rfl + +/-- The inclusion homomorphism from a subgroup `H` contained in `K` to `K`. -/ +@[to_additive "The inclusion homomorphism from an additive subgroup `H` contained in `K` to `K`."] +def inclusion {H K : S} (h : H ≤ K) : H →* K := + MonoidHom.mk' (fun x => ⟨x, h x.prop⟩) fun _ _=> rfl + +@[to_additive (attr := simp)] +theorem inclusion_self (x : H) : inclusion le_rfl x = x := by + cases x + rfl + +@[to_additive (attr := simp)] +theorem inclusion_mk {h : H ≤ K} (x : G) (hx : x ∈ H) : inclusion h ⟨x, hx⟩ = ⟨x, h hx⟩ := + rfl + +@[to_additive] +theorem inclusion_right (h : H ≤ K) (x : K) (hx : (x : G) ∈ H) : inclusion h ⟨x, hx⟩ = x := by + cases x + rfl + +@[simp] +theorem inclusion_inclusion {L : S} (hHK : H ≤ K) (hKL : K ≤ L) (x : H) : + inclusion hKL (inclusion hHK x) = inclusion (hHK.trans hKL) x := by + cases x + rfl + +@[to_additive (attr := simp)] +theorem coe_inclusion {H K : S} {h : H ≤ K} (a : H) : (inclusion h a : G) = a := by + cases a + simp only [inclusion, MonoidHom.mk'_apply] + +@[to_additive (attr := simp)] +theorem subtype_comp_inclusion {H K : S} (hH : H ≤ K) : + (SubgroupClass.subtype K).comp (inclusion hH) = SubgroupClass.subtype H := by + ext + simp only [MonoidHom.comp_apply, coeSubtype, coe_inclusion] + +end SubgroupClass + +end SubgroupClass + +/-- A subgroup of a group `G` is a subset containing 1, closed under multiplication +and closed under multiplicative inverse. -/ +structure Subgroup (G : Type*) [Group G] extends Submonoid G where + /-- `G` is closed under inverses -/ + inv_mem' {x} : x ∈ carrier → x⁻¹ ∈ carrier + +/-- An additive subgroup of an additive group `G` is a subset containing 0, closed +under addition and additive inverse. -/ +structure AddSubgroup (G : Type*) [AddGroup G] extends AddSubmonoid G where + /-- `G` is closed under negation -/ + neg_mem' {x} : x ∈ carrier → -x ∈ carrier + +attribute [to_additive] Subgroup + +-- Porting note: Removed, translation already exists +-- attribute [to_additive AddSubgroup.toAddSubmonoid] Subgroup.toSubmonoid + +/-- Reinterpret a `Subgroup` as a `Submonoid`. -/ +add_decl_doc Subgroup.toSubmonoid + +/-- Reinterpret an `AddSubgroup` as an `AddSubmonoid`. -/ +add_decl_doc AddSubgroup.toAddSubmonoid + +namespace Subgroup + +@[to_additive] +instance : SetLike (Subgroup G) G where + coe s := s.carrier + coe_injective' p q h := by + obtain ⟨⟨⟨hp,_⟩,_⟩,_⟩ := p + obtain ⟨⟨⟨hq,_⟩,_⟩,_⟩ := q + congr + +-- Porting note: Below can probably be written more uniformly +@[to_additive] +instance : SubgroupClass (Subgroup G) G where + inv_mem := Subgroup.inv_mem' _ + one_mem _ := (Subgroup.toSubmonoid _).one_mem' + mul_mem := (Subgroup.toSubmonoid _).mul_mem' + +@[to_additive (attr := simp, nolint simpNF)] -- Porting note (#10675): dsimp can not prove this +theorem mem_carrier {s : Subgroup G} {x : G} : x ∈ s.carrier ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_mk {s : Set G} {x : G} (h_one) (h_mul) (h_inv) : + x ∈ mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_set_mk {s : Set G} (h_one) (h_mul) (h_inv) : + (mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv : Set G) = s := + rfl + +@[to_additive (attr := simp)] +theorem mk_le_mk {s t : Set G} (h_one) (h_mul) (h_inv) (h_one') (h_mul') (h_inv') : + mk ⟨⟨s, h_one⟩, h_mul⟩ h_inv ≤ mk ⟨⟨t, h_one'⟩, h_mul'⟩ h_inv' ↔ s ⊆ t := + Iff.rfl + +initialize_simps_projections Subgroup (carrier → coe) +initialize_simps_projections AddSubgroup (carrier → coe) + +@[to_additive (attr := simp)] +theorem coe_toSubmonoid (K : Subgroup G) : (K.toSubmonoid : Set G) = K := + rfl + +@[to_additive (attr := simp)] +theorem mem_toSubmonoid (K : Subgroup G) (x : G) : x ∈ K.toSubmonoid ↔ x ∈ K := + Iff.rfl + +@[to_additive] +theorem toSubmonoid_injective : Function.Injective (toSubmonoid : Subgroup G → Submonoid G) := + -- fun p q h => SetLike.ext'_iff.2 (show _ from SetLike.ext'_iff.1 h) + fun p q h => by + have := SetLike.ext'_iff.1 h + rw [coe_toSubmonoid, coe_toSubmonoid] at this + exact SetLike.ext'_iff.2 this + +@[to_additive (attr := simp)] +theorem toSubmonoid_eq {p q : Subgroup G} : p.toSubmonoid = q.toSubmonoid ↔ p = q := + toSubmonoid_injective.eq_iff + +@[to_additive (attr := mono)] +theorem toSubmonoid_strictMono : StrictMono (toSubmonoid : Subgroup G → Submonoid G) := fun _ _ => + id + +@[to_additive (attr := mono)] +theorem toSubmonoid_mono : Monotone (toSubmonoid : Subgroup G → Submonoid G) := + toSubmonoid_strictMono.monotone + +@[to_additive (attr := simp)] +theorem toSubmonoid_le {p q : Subgroup G} : p.toSubmonoid ≤ q.toSubmonoid ↔ p ≤ q := + Iff.rfl + +@[to_additive (attr := simp)] +lemma coe_nonempty (s : Subgroup G) : (s : Set G).Nonempty := ⟨1, one_mem _⟩ + +end Subgroup + +namespace Subgroup + +variable (H K : Subgroup G) + +/-- Copy of a subgroup with a new `carrier` equal to the old one. Useful to fix definitional +equalities. -/ +@[to_additive + "Copy of an additive subgroup with a new `carrier` equal to the old one. + Useful to fix definitional equalities"] +protected def copy (K : Subgroup G) (s : Set G) (hs : s = K) : Subgroup G where + carrier := s + one_mem' := hs.symm ▸ K.one_mem' + mul_mem' := hs.symm ▸ K.mul_mem' + inv_mem' hx := by simpa [hs] using hx -- Porting note: `▸` didn't work here + +@[to_additive (attr := simp)] +theorem coe_copy (K : Subgroup G) (s : Set G) (hs : s = ↑K) : (K.copy s hs : Set G) = s := + rfl + +@[to_additive] +theorem copy_eq (K : Subgroup G) (s : Set G) (hs : s = ↑K) : K.copy s hs = K := + SetLike.coe_injective hs + +/-- Two subgroups are equal if they have the same elements. -/ +@[to_additive (attr := ext) "Two `AddSubgroup`s are equal if they have the same elements."] +theorem ext {H K : Subgroup G} (h : ∀ x, x ∈ H ↔ x ∈ K) : H = K := + SetLike.ext h + +/-- A subgroup contains the group's 1. -/ +@[to_additive "An `AddSubgroup` contains the group's 0."] +protected theorem one_mem : (1 : G) ∈ H := + one_mem _ + +/-- A subgroup is closed under multiplication. -/ +@[to_additive "An `AddSubgroup` is closed under addition."] +protected theorem mul_mem {x y : G} : x ∈ H → y ∈ H → x * y ∈ H := + mul_mem + +/-- A subgroup is closed under inverse. -/ +@[to_additive "An `AddSubgroup` is closed under inverse."] +protected theorem inv_mem {x : G} : x ∈ H → x⁻¹ ∈ H := + inv_mem + +/-- A subgroup is closed under division. -/ +@[to_additive "An `AddSubgroup` is closed under subtraction."] +protected theorem div_mem {x y : G} (hx : x ∈ H) (hy : y ∈ H) : x / y ∈ H := + div_mem hx hy + +@[to_additive] +protected theorem inv_mem_iff {x : G} : x⁻¹ ∈ H ↔ x ∈ H := + inv_mem_iff + +@[to_additive] +protected theorem exists_inv_mem_iff_exists_mem (K : Subgroup G) {P : G → Prop} : + (∃ x : G, x ∈ K ∧ P x⁻¹) ↔ ∃ x ∈ K, P x := + exists_inv_mem_iff_exists_mem + +@[to_additive] +protected theorem mul_mem_cancel_right {x y : G} (h : x ∈ H) : y * x ∈ H ↔ y ∈ H := + mul_mem_cancel_right h + +@[to_additive] +protected theorem mul_mem_cancel_left {x y : G} (h : x ∈ H) : x * y ∈ H ↔ y ∈ H := + mul_mem_cancel_left h + +@[to_additive] +protected theorem pow_mem {x : G} (hx : x ∈ K) : ∀ n : ℕ, x ^ n ∈ K := + pow_mem hx + +@[to_additive] +protected theorem zpow_mem {x : G} (hx : x ∈ K) : ∀ n : ℤ, x ^ n ∈ K := + zpow_mem hx + +/-- Construct a subgroup from a nonempty set that is closed under division. -/ +@[to_additive "Construct a subgroup from a nonempty set that is closed under subtraction"] +def ofDiv (s : Set G) (hsn : s.Nonempty) (hs : ∀ᵉ (x ∈ s) (y ∈ s), x * y⁻¹ ∈ s) : + Subgroup G := + have one_mem : (1 : G) ∈ s := by + let ⟨x, hx⟩ := hsn + simpa using hs x hx x hx + have inv_mem : ∀ x, x ∈ s → x⁻¹ ∈ s := fun x hx => by simpa using hs 1 one_mem x hx + { carrier := s + one_mem' := one_mem + inv_mem' := inv_mem _ + mul_mem' := fun hx hy => by simpa using hs _ hx _ (inv_mem _ hy) } + +/-- A subgroup of a group inherits a multiplication. -/ +@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an addition."] +instance mul : Mul H := + H.toSubmonoid.mul + +/-- A subgroup of a group inherits a 1. -/ +@[to_additive "An `AddSubgroup` of an `AddGroup` inherits a zero."] +instance one : One H := + H.toSubmonoid.one + +/-- A subgroup of a group inherits an inverse. -/ +@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an inverse."] +instance inv : Inv H := + ⟨fun a => ⟨a⁻¹, H.inv_mem a.2⟩⟩ + +/-- A subgroup of a group inherits a division -/ +@[to_additive "An `AddSubgroup` of an `AddGroup` inherits a subtraction."] +instance div : Div H := + ⟨fun a b => ⟨a / b, H.div_mem a.2 b.2⟩⟩ + +/-- An `AddSubgroup` of an `AddGroup` inherits a natural scaling. -/ +instance _root_.AddSubgroup.nsmul {G} [AddGroup G] {H : AddSubgroup G} : SMul ℕ H := + ⟨fun n a => ⟨n • a, H.nsmul_mem a.2 n⟩⟩ + +/-- A subgroup of a group inherits a natural power -/ +@[to_additive existing] +protected instance npow : Pow H ℕ := + ⟨fun a n => ⟨a ^ n, H.pow_mem a.2 n⟩⟩ + +/-- An `AddSubgroup` of an `AddGroup` inherits an integer scaling. -/ +instance _root_.AddSubgroup.zsmul {G} [AddGroup G] {H : AddSubgroup G} : SMul ℤ H := + ⟨fun n a => ⟨n • a, H.zsmul_mem a.2 n⟩⟩ + +/-- A subgroup of a group inherits an integer power -/ +@[to_additive existing] +instance zpow : Pow H ℤ := + ⟨fun a n => ⟨a ^ n, H.zpow_mem a.2 n⟩⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_mul (x y : H) : (↑(x * y) : G) = ↑x * ↑y := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_one : ((1 : H) : G) = 1 := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_inv (x : H) : ↑(x⁻¹ : H) = (x⁻¹ : G) := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_div (x y : H) : (↑(x / y) : G) = ↑x / ↑y := + rfl + +-- Porting note: removed simp, theorem has variable as head symbol +@[to_additive (attr := norm_cast)] +theorem coe_mk (x : G) (hx : x ∈ H) : ((⟨x, hx⟩ : H) : G) = x := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = (x : G) ^ n := + rfl + +@[to_additive (attr := norm_cast)] -- Porting note (#10685): dsimp can prove this +theorem coe_zpow (x : H) (n : ℤ) : ((x ^ n : H) : G) = (x : G) ^ n := + rfl + +@[to_additive (attr := simp)] +theorem mk_eq_one {g : G} {h} : (⟨g, h⟩ : H) = 1 ↔ g = 1 := Submonoid.mk_eq_one .. + +/-- A subgroup of a group inherits a group structure. -/ +@[to_additive "An `AddSubgroup` of an `AddGroup` inherits an `AddGroup` structure."] +instance toGroup {G : Type*} [Group G] (H : Subgroup G) : Group H := + Subtype.coe_injective.group _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) fun _ _ => rfl + +/-- A subgroup of a `CommGroup` is a `CommGroup`. -/ +@[to_additive "An `AddSubgroup` of an `AddCommGroup` is an `AddCommGroup`."] +instance toCommGroup {G : Type*} [CommGroup G] (H : Subgroup G) : CommGroup H := + Subtype.coe_injective.commGroup _ rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) fun _ _ => rfl + +/-- The natural group hom from a subgroup of group `G` to `G`. -/ +@[to_additive "The natural group hom from an `AddSubgroup` of `AddGroup` `G` to `G`."] +protected def subtype : H →* G where + toFun := ((↑) : H → G); map_one' := rfl; map_mul' _ _ := rfl + +@[to_additive (attr := simp)] +theorem coeSubtype : ⇑ H.subtype = ((↑) : H → G) := + rfl + +@[to_additive] +theorem subtype_injective : Function.Injective (Subgroup.subtype H) := + Subtype.coe_injective + +/-- The inclusion homomorphism from a subgroup `H` contained in `K` to `K`. -/ +@[to_additive "The inclusion homomorphism from an additive subgroup `H` contained in `K` to `K`."] +def inclusion {H K : Subgroup G} (h : H ≤ K) : H →* K := + MonoidHom.mk' (fun x => ⟨x, h x.2⟩) fun _ _ => rfl + +@[to_additive (attr := simp)] +theorem coe_inclusion {H K : Subgroup G} {h : H ≤ K} (a : H) : (inclusion h a : G) = a := by + cases a + simp only [inclusion, coe_mk, MonoidHom.mk'_apply] + +@[to_additive] +theorem inclusion_injective {H K : Subgroup G} (h : H ≤ K) : Function.Injective <| inclusion h := + Set.inclusion_injective h + +@[to_additive (attr := simp)] +lemma inclusion_inj {H K : Subgroup G} (h : H ≤ K) {x y : H} : + inclusion h x = inclusion h y ↔ x = y := + (inclusion_injective h).eq_iff + +@[to_additive (attr := simp)] +theorem subtype_comp_inclusion {H K : Subgroup G} (hH : H ≤ K) : + K.subtype.comp (inclusion hH) = H.subtype := + rfl + +variable {k : Set G} + +open Set + +variable {N : Type*} [Group N] {P : Type*} [Group P] + +/-- A subgroup is normal if whenever `n ∈ H`, then `g * n * g⁻¹ ∈ H` for every `g : G` -/ +structure Normal : Prop where + /-- `N` is closed under conjugation -/ + conj_mem : ∀ n, n ∈ H → ∀ g : G, g * n * g⁻¹ ∈ H + +attribute [class] Normal + +end Subgroup + +namespace AddSubgroup + +/-- An AddSubgroup is normal if whenever `n ∈ H`, then `g + n - g ∈ H` for every `g : G` -/ +structure Normal (H : AddSubgroup A) : Prop where + /-- `N` is closed under additive conjugation -/ + conj_mem : ∀ n, n ∈ H → ∀ g : A, g + n + -g ∈ H + +attribute [to_additive] Subgroup.Normal + +attribute [class] Normal + +end AddSubgroup + +namespace Subgroup + +variable {H K : Subgroup G} + +@[to_additive] +instance (priority := 100) normal_of_comm {G : Type*} [CommGroup G] (H : Subgroup G) : H.Normal := + ⟨by simp [mul_comm, mul_left_comm]⟩ + +namespace Normal + +@[to_additive] +theorem conj_mem' (nH : H.Normal) (n : G) (hn : n ∈ H) (g : G) : + g⁻¹ * n * g ∈ H := by + convert nH.conj_mem n hn g⁻¹ + rw [inv_inv] + +@[to_additive] +theorem mem_comm (nH : H.Normal) {a b : G} (h : a * b ∈ H) : b * a ∈ H := by + have : a⁻¹ * (a * b) * a⁻¹⁻¹ ∈ H := nH.conj_mem (a * b) h a⁻¹ + -- Porting note: Previous code was: + -- simpa + simp_all only [inv_mul_cancel_left, inv_inv] + +@[to_additive] +theorem mem_comm_iff (nH : H.Normal) {a b : G} : a * b ∈ H ↔ b * a ∈ H := + ⟨nH.mem_comm, nH.mem_comm⟩ + +end Normal + +end Subgroup + +namespace Subgroup + +variable (H : Subgroup G) {K : Subgroup G} + +section Normalizer + +/-- The `normalizer` of `H` is the largest subgroup of `G` inside which `H` is normal. -/ +@[to_additive "The `normalizer` of `H` is the largest subgroup of `G` inside which `H` is normal."] +def normalizer : Subgroup G where + carrier := { g : G | ∀ n, n ∈ H ↔ g * n * g⁻¹ ∈ H } + one_mem' := by simp + mul_mem' {a b} (ha : ∀ n, n ∈ H ↔ a * n * a⁻¹ ∈ H) (hb : ∀ n, n ∈ H ↔ b * n * b⁻¹ ∈ H) n := by + rw [hb, ha] + simp only [mul_assoc, mul_inv_rev] + inv_mem' {a} (ha : ∀ n, n ∈ H ↔ a * n * a⁻¹ ∈ H) n := by + rw [ha (a⁻¹ * n * a⁻¹⁻¹)] + simp only [inv_inv, mul_assoc, mul_inv_cancel_left, mul_inv_cancel, mul_one] + +-- variant for sets. +-- TODO should this replace `normalizer`? +/-- The `setNormalizer` of `S` is the subgroup of `G` whose elements satisfy `g*S*g⁻¹=S` -/ +@[to_additive + "The `setNormalizer` of `S` is the subgroup of `G` whose elements satisfy + `g+S-g=S`."] +def setNormalizer (S : Set G) : Subgroup G where + carrier := { g : G | ∀ n, n ∈ S ↔ g * n * g⁻¹ ∈ S } + one_mem' := by simp + mul_mem' {a b} (ha : ∀ n, n ∈ S ↔ a * n * a⁻¹ ∈ S) (hb : ∀ n, n ∈ S ↔ b * n * b⁻¹ ∈ S) n := by + rw [hb, ha] + simp only [mul_assoc, mul_inv_rev] + inv_mem' {a} (ha : ∀ n, n ∈ S ↔ a * n * a⁻¹ ∈ S) n := by + rw [ha (a⁻¹ * n * a⁻¹⁻¹)] + simp only [inv_inv, mul_assoc, mul_inv_cancel_left, mul_inv_cancel, mul_one] + +variable {H} + +@[to_additive] +theorem mem_normalizer_iff {g : G} : g ∈ H.normalizer ↔ ∀ h, h ∈ H ↔ g * h * g⁻¹ ∈ H := + Iff.rfl + +@[to_additive] +theorem mem_normalizer_iff'' {g : G} : g ∈ H.normalizer ↔ ∀ h : G, h ∈ H ↔ g⁻¹ * h * g ∈ H := by + rw [← inv_mem_iff (x := g), mem_normalizer_iff, inv_inv] + +@[to_additive] +theorem mem_normalizer_iff' {g : G} : g ∈ H.normalizer ↔ ∀ n, n * g ∈ H ↔ g * n ∈ H := + ⟨fun h n => by rw [h, mul_assoc, mul_inv_cancel_right], fun h n => by + rw [mul_assoc, ← h, inv_mul_cancel_right]⟩ + +@[to_additive] +theorem le_normalizer : H ≤ normalizer H := fun x xH n => by + rw [H.mul_mem_cancel_right (H.inv_mem xH), H.mul_mem_cancel_left xH] + +end Normalizer + +/-- Commutativity of a subgroup -/ +structure IsCommutative : Prop where + /-- `*` is commutative on `H` -/ + is_comm : Std.Commutative (α := H) (· * ·) + +attribute [class] IsCommutative + +/-- Commutativity of an additive subgroup -/ +structure _root_.AddSubgroup.IsCommutative (H : AddSubgroup A) : Prop where + /-- `+` is commutative on `H` -/ + is_comm : Std.Commutative (α := H) (· + ·) + +attribute [to_additive] Subgroup.IsCommutative + +attribute [class] AddSubgroup.IsCommutative + +/-- A commutative subgroup is commutative. -/ +@[to_additive "A commutative subgroup is commutative."] +instance IsCommutative.commGroup [h : H.IsCommutative] : CommGroup H := + { H.toGroup with mul_comm := h.is_comm.comm } + +/-- A subgroup of a commutative group is commutative. -/ +@[to_additive "A subgroup of a commutative group is commutative."] +instance commGroup_isCommutative {G : Type*} [CommGroup G] (H : Subgroup G) : H.IsCommutative := + ⟨CommMagma.to_isCommutative⟩ + +@[to_additive] +lemma mul_comm_of_mem_isCommutative [H.IsCommutative] {a b : G} (ha : a ∈ H) (hb : b ∈ H) : + a * b = b * a := by + simpa only [MulMemClass.mk_mul_mk, Subtype.mk.injEq] using mul_comm (⟨a, ha⟩ : H) (⟨b, hb⟩ : H) + +end Subgroup diff --git a/Mathlib/Algebra/Group/Subgroup/Order.lean b/Mathlib/Algebra/Group/Subgroup/Order.lean index 0578e6adbde06..6229466df62b8 100644 --- a/Mathlib/Algebra/Group/Subgroup/Order.lean +++ b/Mathlib/Algebra/Group/Subgroup/Order.lean @@ -5,6 +5,7 @@ Authors: Damiano Testa, Ruben Van de Velde -/ import Mathlib.Order.Atoms import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.Order.Group.InjSurj import Mathlib.Algebra.Order.Group.Unbundled.Abs @@ -21,7 +22,7 @@ theorem mabs_mem_iff {S G} [Group G] [LinearOrder G] {_ : SetLike S G} section ModularLattice -variable {C : Type*} [CommGroup C] {s t : Subgroup C} {x : C} +variable {C : Type*} [CommGroup C] @[to_additive] instance : IsModularLattice (Subgroup C) := diff --git a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean index 99bb82ddad9cc..0378c1dd57b4b 100644 --- a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean +++ b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean @@ -41,6 +41,10 @@ lemma smul_coe_set [Group G] [SetLike S G] [SubgroupClass S G] {s : S} {a : G} ( a • (s : Set G) = s := by ext; simp [Set.mem_smul_set_iff_inv_smul_mem, mul_mem_cancel_left, ha] +@[norm_cast, to_additive] +lemma coe_set_eq_one [Group G] {s : Subgroup G} : (s : Set G) = 1 ↔ s = ⊥ := + (SetLike.ext'_iff.trans (by rfl)).symm + @[to_additive (attr := simp)] lemma op_smul_coe_set [Group G] [SetLike S G] [SubgroupClass S G] {s : S} {a : G} (ha : a ∈ s) : MulOpposite.op a • (s : Set G) = s := by @@ -68,9 +72,9 @@ theorem closure_toSubmonoid (S : Set G) : (closure S).toSubmonoid = Submonoid.closure (S ∪ S⁻¹) := by refine le_antisymm (fun x hx => ?_) (Submonoid.closure_le.2 ?_) · refine - closure_induction hx + closure_induction (fun x hx => Submonoid.closure_mono subset_union_left (Submonoid.subset_closure hx)) - (Submonoid.one_mem _) (fun x y hx hy => Submonoid.mul_mem _ hx hy) fun x hx => ?_ + (Submonoid.one_mem _) (fun x y _ _ hx hy => Submonoid.mul_mem _ hx hy) (fun x _ hx => ?_) hx rwa [← Submonoid.mem_closure_inv, Set.union_inv, inv_inv, Set.union_comm] · simp only [true_and, coe_toSubmonoid, union_subset_iff, subset_closure, inv_subset_closure] @@ -105,8 +109,8 @@ theorem closure_induction_right {p : (x : G) → x ∈ closure s → Prop} (one closure_induction_left (s := MulOpposite.unop ⁻¹' s) (p := fun m hm => p m.unop <| by rwa [← op_closure] at hm) one - (fun _x hx _y hy => mul_right _ _ _ hx) - (fun _x hx _y hy => mul_inv_cancel _ _ _ hx) + (fun _x hx _y _ => mul_right _ _ _ hx) + (fun _x hx _y _ => mul_inv_cancel _ _ _ hx) (by rwa [← op_closure]) @[to_additive (attr := simp)] @@ -282,7 +286,7 @@ protected def pointwiseMulAction : MulAction α (Subgroup G) where one_smul S := by change S.map _ = S simpa only [map_one] using S.map_id - mul_smul a₁ a₂ S := + mul_smul _ _ S := (congr_arg (fun f : Monoid.End G => S.map f) (MonoidHom.map_mul _ _ _)).trans (S.map_map _ _).symm @@ -543,4 +547,24 @@ theorem le_pointwise_smul_iff₀ {a : α} (ha : a ≠ 0) {S T : AddSubgroup A} : end GroupWithZero +section Mul + +variable {R : Type*} [NonUnitalNonAssocRing R] + +/-- For additive subgroups `S` and `T` of a ring, the product of `S` and `T` as submonoids +is automatically a subgroup, which we define as the product of `S` and `T` as subgroups. -/ +protected def mul : Mul (AddSubgroup R) where + mul M N := + { __ := M.toAddSubmonoid * N.toAddSubmonoid + neg_mem' := fun h ↦ AddSubmonoid.mul_induction_on h + (fun m hm n hn ↦ by rw [← neg_mul]; exact AddSubmonoid.mul_mem_mul (M.neg_mem hm) hn) + fun r₁ r₂ h₁ h₂ ↦ by rw [neg_add]; exact (M.1 * N.1).add_mem h₁ h₂ } + +scoped[Pointwise] attribute [instance] AddSubgroup.mul + +theorem mul_toAddSubmonoid (M N : AddSubgroup R) : + (M * N).toAddSubmonoid = M.toAddSubmonoid * N.toAddSubmonoid := rfl + +end Mul + end AddSubgroup diff --git a/Mathlib/Algebra/Group/Submonoid/Basic.lean b/Mathlib/Algebra/Group/Submonoid/Basic.lean index ddb7f8577ed46..04690c8d30132 100644 --- a/Mathlib/Algebra/Group/Submonoid/Basic.lean +++ b/Mathlib/Algebra/Group/Submonoid/Basic.lean @@ -5,24 +5,20 @@ Authors: Johannes Hölzl, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzza Amelia Livingston, Yury Kudryashov -/ import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.Group.Subsemigroup.Basic -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Defs /-! -# Submonoids: definition and `CompleteLattice` structure +# Submonoids: `CompleteLattice` structure -This file defines bundled multiplicative and additive submonoids. We also define -a `CompleteLattice` structure on `Submonoid`s, define the closure of a set as the minimal submonoid -that includes this set, and prove a few results about extending properties from a dense set (i.e. -a set with `closure s = ⊤`) to the whole monoid, see `Submonoid.dense_induction` and +This file defines a `CompleteLattice` structure on `Submonoid`s, define the closure of a set as the +minimal submonoid that includes this set, and prove a few results about extending properties from a +dense set (i.e. a set with `closure s = ⊤`) to the whole monoid, see `Submonoid.dense_induction` and `MonoidHom.ofClosureEqTopLeft`/`MonoidHom.ofClosureEqTopRight`. ## Main definitions -* `Submonoid M`: the type of bundled submonoids of a monoid `M`; the underlying set is given in - the `carrier` field of the structure, and should be accessed through coercion as in `(S : Set M)`. -* `AddSubmonoid M` : the type of bundled submonoids of an additive monoid `M`. - For each of the following definitions in the `Submonoid` namespace, there is a corresponding definition in the `AddSubmonoid` namespace. @@ -64,197 +60,9 @@ section NonAssoc variable [MulOneClass M] {s : Set M} variable [AddZeroClass A] {t : Set A} -/-- `OneMemClass S M` says `S` is a type of subsets `s ≤ M`, such that `1 ∈ s` for all `s`. -/ -class OneMemClass (S : Type*) (M : Type*) [One M] [SetLike S M] : Prop where - /-- By definition, if we have `OneMemClass S M`, we have `1 ∈ s` for all `s : S`. -/ - one_mem : ∀ s : S, (1 : M) ∈ s - -export OneMemClass (one_mem) - -/-- `ZeroMemClass S M` says `S` is a type of subsets `s ≤ M`, such that `0 ∈ s` for all `s`. -/ -class ZeroMemClass (S : Type*) (M : Type*) [Zero M] [SetLike S M] : Prop where - /-- By definition, if we have `ZeroMemClass S M`, we have `0 ∈ s` for all `s : S`. -/ - zero_mem : ∀ s : S, (0 : M) ∈ s - -export ZeroMemClass (zero_mem) - -attribute [to_additive] OneMemClass - -attribute [aesop safe apply (rule_sets := [SetLike])] one_mem zero_mem - -section - -/-- A submonoid of a monoid `M` is a subset containing 1 and closed under multiplication. -/ -structure Submonoid (M : Type*) [MulOneClass M] extends Subsemigroup M where - /-- A submonoid contains `1`. -/ - one_mem' : (1 : M) ∈ carrier - -end - -/-- A submonoid of a monoid `M` can be considered as a subsemigroup of that monoid. -/ -add_decl_doc Submonoid.toSubsemigroup - -/-- `SubmonoidClass S M` says `S` is a type of subsets `s ≤ M` that contain `1` -and are closed under `(*)` -/ -class SubmonoidClass (S : Type*) (M : Type*) [MulOneClass M] [SetLike S M] extends - MulMemClass S M, OneMemClass S M : Prop - -section - -/-- An additive submonoid of an additive monoid `M` is a subset containing 0 and - closed under addition. -/ -structure AddSubmonoid (M : Type*) [AddZeroClass M] extends AddSubsemigroup M where - /-- An additive submonoid contains `0`. -/ - zero_mem' : (0 : M) ∈ carrier - -end - -/-- An additive submonoid of an additive monoid `M` can be considered as an -additive subsemigroup of that additive monoid. -/ -add_decl_doc AddSubmonoid.toAddSubsemigroup - -/-- `AddSubmonoidClass S M` says `S` is a type of subsets `s ≤ M` that contain `0` -and are closed under `(+)` -/ -class AddSubmonoidClass (S : Type*) (M : Type*) [AddZeroClass M] [SetLike S M] extends - AddMemClass S M, ZeroMemClass S M : Prop - -attribute [to_additive] Submonoid SubmonoidClass - -@[to_additive (attr := aesop safe apply (rule_sets := [SetLike]))] -theorem pow_mem {M A} [Monoid M] [SetLike A M] [SubmonoidClass A M] {S : A} {x : M} - (hx : x ∈ S) : ∀ n : ℕ, x ^ n ∈ S - | 0 => by - rw [pow_zero] - exact OneMemClass.one_mem S - | n + 1 => by - rw [pow_succ] - exact mul_mem (pow_mem hx n) hx - namespace Submonoid -@[to_additive] -instance : SetLike (Submonoid M) M where - coe s := s.carrier - coe_injective' p q h := by cases p; cases q; congr; exact SetLike.coe_injective' h - -@[to_additive] -instance : SubmonoidClass (Submonoid M) M where - one_mem := Submonoid.one_mem' - mul_mem {s} := s.mul_mem' - -initialize_simps_projections Submonoid (carrier → coe) - -initialize_simps_projections AddSubmonoid (carrier → coe) - -@[to_additive (attr := simp)] -theorem mem_toSubsemigroup {s : Submonoid M} {x : M} : x ∈ s.toSubsemigroup ↔ x ∈ s := - Iff.rfl - --- Porting note: `x ∈ s.carrier` is now syntactically `x ∈ s.toSubsemigroup.carrier`, --- which `simp` already simplifies to `x ∈ s.toSubsemigroup`. So we remove the `@[simp]` attribute --- here, and instead add the simp lemma `mem_toSubsemigroup` to allow `simp` to do this exact --- simplification transitively. -@[to_additive] -theorem mem_carrier {s : Submonoid M} {x : M} : x ∈ s.carrier ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_mk {s : Subsemigroup M} {x : M} (h_one) : x ∈ mk s h_one ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp)] -theorem coe_set_mk {s : Subsemigroup M} (h_one) : (mk s h_one : Set M) = s := - rfl - -@[to_additive (attr := simp)] -theorem mk_le_mk {s t : Subsemigroup M} (h_one) (h_one') : mk s h_one ≤ mk t h_one' ↔ s ≤ t := - Iff.rfl - -/-- Two submonoids are equal if they have the same elements. -/ -@[to_additive (attr := ext) "Two `AddSubmonoid`s are equal if they have the same elements."] -theorem ext {S T : Submonoid M} (h : ∀ x, x ∈ S ↔ x ∈ T) : S = T := - SetLike.ext h - -/-- Copy a submonoid replacing `carrier` with a set that is equal to it. -/ -@[to_additive "Copy an additive submonoid replacing `carrier` with a set that is equal to it."] -protected def copy (S : Submonoid M) (s : Set M) (hs : s = S) : Submonoid M where - carrier := s - one_mem' := show 1 ∈ s from hs.symm ▸ S.one_mem' - mul_mem' := hs.symm ▸ S.mul_mem' - -variable {S : Submonoid M} - -@[to_additive (attr := simp)] -theorem coe_copy {s : Set M} (hs : s = S) : (S.copy s hs : Set M) = s := - rfl - -@[to_additive] -theorem copy_eq {s : Set M} (hs : s = S) : S.copy s hs = S := - SetLike.coe_injective hs - -variable (S) - -/-- A submonoid contains the monoid's 1. -/ -@[to_additive "An `AddSubmonoid` contains the monoid's 0."] -protected theorem one_mem : (1 : M) ∈ S := - one_mem S - -/-- A submonoid is closed under multiplication. -/ -@[to_additive "An `AddSubmonoid` is closed under addition."] -protected theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := - mul_mem - -/-- The submonoid `M` of the monoid `M`. -/ -@[to_additive "The additive submonoid `M` of the `AddMonoid M`."] -instance : Top (Submonoid M) := - ⟨{ carrier := Set.univ - one_mem' := Set.mem_univ 1 - mul_mem' := fun _ _ => Set.mem_univ _ }⟩ - -/-- The trivial submonoid `{1}` of a monoid `M`. -/ -@[to_additive "The trivial `AddSubmonoid` `{0}` of an `AddMonoid` `M`."] -instance : Bot (Submonoid M) := - ⟨{ carrier := {1} - one_mem' := Set.mem_singleton 1 - mul_mem' := fun ha hb => by - simp only [Set.mem_singleton_iff] at * - rw [ha, hb, mul_one] }⟩ - -@[to_additive] -instance : Inhabited (Submonoid M) := - ⟨⊥⟩ - -@[to_additive (attr := simp)] -theorem mem_bot {x : M} : x ∈ (⊥ : Submonoid M) ↔ x = 1 := - Set.mem_singleton_iff - -@[to_additive (attr := simp)] -theorem mem_top (x : M) : x ∈ (⊤ : Submonoid M) := - Set.mem_univ x - -@[to_additive (attr := simp)] -theorem coe_top : ((⊤ : Submonoid M) : Set M) = Set.univ := - rfl - -@[to_additive (attr := simp)] -theorem coe_bot : ((⊥ : Submonoid M) : Set M) = {1} := - rfl - -/-- The inf of two submonoids is their intersection. -/ -@[to_additive "The inf of two `AddSubmonoid`s is their intersection."] -instance : Inf (Submonoid M) := - ⟨fun S₁ S₂ => - { carrier := S₁ ∩ S₂ - one_mem' := ⟨S₁.one_mem, S₂.one_mem⟩ - mul_mem' := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ => ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ - -@[to_additive (attr := simp)] -theorem coe_inf (p p' : Submonoid M) : ((p ⊓ p' : Submonoid M) : Set M) = (p : Set M) ∩ p' := - rfl - -@[to_additive (attr := simp)] -theorem mem_inf {p p' : Submonoid M} {x : M} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := - Iff.rfl +variable (S : Submonoid M) @[to_additive] instance : InfSet (Submonoid M) := @@ -300,30 +108,6 @@ instance : CompleteLattice (Submonoid M) := inf_le_left := fun _ _ _ => And.left inf_le_right := fun _ _ _ => And.right } -@[to_additive (attr := simp)] -theorem subsingleton_iff : Subsingleton (Submonoid M) ↔ Subsingleton M := - ⟨fun h => - ⟨fun x y => - have : ∀ i : M, i = 1 := fun i => - mem_bot.mp <| Subsingleton.elim (⊤ : Submonoid M) ⊥ ▸ mem_top i - (this x).trans (this y).symm⟩, - fun h => - ⟨fun x y => Submonoid.ext fun i => Subsingleton.elim 1 i ▸ by simp [Submonoid.one_mem]⟩⟩ - -@[to_additive (attr := simp)] -theorem nontrivial_iff : Nontrivial (Submonoid M) ↔ Nontrivial M := - not_iff_not.mp - ((not_nontrivial_iff_subsingleton.trans subsingleton_iff).trans - not_nontrivial_iff_subsingleton.symm) - -@[to_additive] -instance [Subsingleton M] : Unique (Submonoid M) := - ⟨⟨⊥⟩, fun a => @Subsingleton.elim _ (subsingleton_iff.mpr ‹_›) a _⟩ - -@[to_additive] -instance [Nontrivial M] : Nontrivial (Submonoid M) := - nontrivial_iff.mpr ‹_› - /-- The `Submonoid` generated by a set. -/ @[to_additive "The `AddSubmonoid` generated by a set"] def closure (s : Set M) : Submonoid M := @@ -372,32 +156,35 @@ is preserved under multiplication, then `p` holds for all elements of the closur "An induction principle for additive closure membership. If `p` holds for `0` and all elements of `s`, and is preserved under addition, then `p` holds for all elements of the additive closure of `s`."] -theorem closure_induction {p : M → Prop} {x} (h : x ∈ closure s) (mem : ∀ x ∈ s, p x) (one : p 1) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨⟨p, mul _ _⟩, one⟩).2 mem h - -/-- A dependent version of `Submonoid.closure_induction`. -/ -@[to_additive (attr := elab_as_elim) "A dependent version of `AddSubmonoid.closure_induction`. "] -theorem closure_induction' (s : Set M) {p : ∀ x, x ∈ closure s → Prop} +theorem closure_induction {s : Set M} {p : (x : M) → x ∈ closure s → Prop} (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) (one : p 1 (one_mem _)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) {x} (hx : x ∈ closure s) : - p x hx := by - refine Exists.elim ?_ fun (hx : x ∈ closure s) (hc : p x hx) => hc - exact - closure_induction hx (fun x hx => ⟨_, mem x hx⟩) ⟨_, one⟩ fun x y ⟨hx', hx⟩ ⟨hy', hy⟩ => - ⟨_, mul _ _ _ _ hx hy⟩ + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) {x} (hx : x ∈ closure s) : + p x hx := + let S : Submonoid M := + { carrier := { x | ∃ hx, p x hx } + one_mem' := ⟨_, one⟩ + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ } + closure_le (S := S) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction /-- An induction principle for closure membership for predicates with two arguments. -/ @[to_additive (attr := elab_as_elim) "An induction principle for additive closure membership for predicates with two arguments."] -theorem closure_induction₂ {p : M → M → Prop} {x} {y : M} (hx : x ∈ closure s) (hy : y ∈ closure s) - (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H1_left : ∀ x, p 1 x) (H1_right : ∀ x, p x 1) - (Hmul_left : ∀ x y z, p x z → p y z → p (x * y) z) - (Hmul_right : ∀ x y z, p z x → p z y → p z (x * y)) : p x y := - closure_induction hx - (fun x xs => - closure_induction hy (Hs x xs) (H1_right x) fun z _ h₁ h₂ => Hmul_right z _ _ h₁ h₂) - (H1_left y) fun _ _ h₁ h₂ => Hmul_left _ _ _ h₁ h₂ +theorem closure_induction₂ {p : (x y : M) → x ∈ closure s → y ∈ closure s → Prop} + (mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p z x hz hx → p z y hz hy → p z (x * y) hz (mul_mem hx hy)) + {x y : M} (hx : x ∈ closure s) (hy : y ∈ closure s) : p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem _ _ h hz + | one => exact one_left _ (subset_closure hz) + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | one => exact one_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ hx h₁ h₂ /-- If `s` is a dense set in a monoid `M`, `Submonoid.closure s = ⊤`, then in order to prove that some predicate `p` holds for all `x : M` it suffices to verify `p x` for `x ∈ s`, verify `p 1`, @@ -406,18 +193,31 @@ and verify that `p x` and `p y` imply `p (x * y)`. -/ "If `s` is a dense set in an additive monoid `M`, `AddSubmonoid.closure s = ⊤`, then in order to prove that some predicate `p` holds for all `x : M` it suffices to verify `p x` for `x ∈ s`, verify `p 0`, and verify that `p x` and `p y` imply `p (x + y)`."] -theorem dense_induction {p : M → Prop} (x : M) {s : Set M} (hs : closure s = ⊤) - (mem : ∀ x ∈ s, p x) - (one : p 1) (mul : ∀ x y, p x → p y → p (x * y)) : p x := by - have : ∀ x ∈ closure s, p x := fun x hx => closure_induction hx mem one mul - simpa [hs] using this x +theorem dense_induction {p : M → Prop} (s : Set M) (closure : closure s = ⊤) (mem : ∀ x ∈ s, p x) + (one : p 1) (mul : ∀ x y, p x → p y → p (x * y)) (x : M) : p x := by + induction closure.symm ▸ mem_top x using closure_induction with + | mem _ h => exact mem _ h + | one => exact one + | mul _ _ _ _ h₁ h₂ => exact mul _ _ h₁ h₂ + +/- The argument `s : Set M` is explicit in `Submonoid.dense_induction` because the type of the +induction variable, namely `x : M`, does not reference `x`. Making `s` explicit allows the user +to apply the induction principle while deferring the proof of `closure s = ⊤` without creating +metavariables, as in the following example. -/ +example {p : M → Prop} (s : Set M) (closure : closure s = ⊤) (mem : ∀ x ∈ s, p x) + (one : p 1) (mul : ∀ x y, p x → p y → p (x * y)) (x : M) : p x := by + induction x using dense_induction s with + | closure => exact closure + | mem x hx => exact mem x hx + | one => exact one + | mul _ _ h₁ h₂ => exact mul _ _ h₁ h₂ /-- The `Submonoid.closure` of a set is the union of `{1}` and its `Subsemigroup.closure`. -/ lemma closure_eq_one_union (s : Set M) : closure s = {(1 : M)} ∪ (Subsemigroup.closure s : Set M) := by apply le_antisymm · intro x hx - induction hx using closure_induction' with + induction hx using closure_induction with | mem x hx => exact Or.inr <| Subsemigroup.subset_closure hx | one => exact Or.inl <| by simp | mul x hx y hy hx hy => @@ -466,7 +266,6 @@ theorem sup_eq_closure (N N' : Submonoid M) : N ⊔ N' = closure ((N : Set M) theorem closure_iUnion {ι} (s : ι → Set M) : closure (⋃ i, s i) = ⨆ i, closure (s i) := (Submonoid.gi M).gc.l_iSup --- Porting note (#10618): `simp` can now prove this, so we remove the `@[simp]` attribute @[to_additive] theorem closure_singleton_le_iff_mem (m : M) (p : Submonoid M) : closure {m} ≤ p ↔ m ∈ p := by rw [closure_le, singleton_subset_iff, SetLike.mem_coe] @@ -500,17 +299,6 @@ variable [MulOneClass N] open Submonoid -/-- The submonoid of elements `x : M` such that `f x = g x` -/ -@[to_additive "The additive submonoid of elements `x : M` such that `f x = g x`"] -def eqLocusM (f g : M →* N) : Submonoid M where - carrier := { x | f x = g x } - one_mem' := by rw [Set.mem_setOf_eq, f.map_one, g.map_one] - mul_mem' (hx : _ = _) (hy : _ = _) := by simp [*] - -@[to_additive (attr := simp)] -theorem eqLocusM_same (f : M →* N) : f.eqLocusM f = ⊤ := - SetLike.ext fun _ => eq_self_iff_true _ - /-- If two monoid homomorphisms are equal on a set, then they are equal on its submonoid closure. -/ @[to_additive "If two monoid homomorphisms are equal on a set, then they are equal on its submonoid @@ -518,10 +306,6 @@ theorem eqLocusM_same (f : M →* N) : f.eqLocusM f = ⊤ := theorem eqOn_closureM {f g : M →* N} {s : Set M} (h : Set.EqOn f g s) : Set.EqOn f g (closure s) := show closure s ≤ f.eqLocusM g from closure_le.2 h -@[to_additive] -theorem eq_of_eqOn_topM {f g : M →* N} (h : Set.EqOn f g (⊤ : Submonoid M)) : f = g := - ext fun _ => h trivial - @[to_additive] theorem eq_of_eqOn_denseM {s : Set M} (hs : closure s = ⊤) {f g : M →* N} (h : s.EqOn f g) : f = g := @@ -572,8 +356,8 @@ def ofClosureMEqTopLeft {M N} [Monoid M] [Monoid N] {s : Set M} (f : M → N) (h toFun := f map_one' := h1 map_mul' x := - (dense_induction (p := _) x hs hmul fun y => by rw [one_mul, h1, one_mul]) fun a b ha hb y => by - rw [mul_assoc, ha, ha, hb, mul_assoc] + dense_induction (p := _) _ hs hmul fun y => by rw [one_mul, h1, one_mul] + (fun a b ha hb y => by rw [mul_assoc, ha, ha, hb, mul_assoc]) x @[to_additive (attr := simp, norm_cast)] theorem coe_ofClosureMEqTopLeft (f : M → N) (hs : closure s = ⊤) (h1 hmul) : @@ -593,9 +377,9 @@ def ofClosureMEqTopRight {M N} [Monoid M] [Monoid N] {s : Set M} (f : M → N) ( toFun := f map_one' := h1 map_mul' x y := - dense_induction y hs (fun y hy x => hmul x y hy) (by simp [h1]) - (fun y₁ y₂ (h₁ : ∀ x, f _ = f _ * f _) (h₂ : ∀ x, f _ = f _ * f _) x => by - simp [← mul_assoc, h₁, h₂]) x + dense_induction _ hs (fun y hy x => hmul x y hy) (by simp [h1]) + (fun y₁ y₂ (h₁ : ∀ _, f _ = f _ * f _) (h₂ : ∀ _, f _ = f _ * f _) x => by + simp [← mul_assoc, h₁, h₂]) y x @[to_additive (attr := simp, norm_cast)] theorem coe_ofClosureMEqTopRight (f : M → N) (hs : closure s = ⊤) (h1 hmul) : diff --git a/Mathlib/Algebra/Group/Submonoid/Defs.lean b/Mathlib/Algebra/Group/Submonoid/Defs.lean new file mode 100644 index 0000000000000..3bb3c3e2e3ea9 --- /dev/null +++ b/Mathlib/Algebra/Group/Submonoid/Defs.lean @@ -0,0 +1,452 @@ +/- +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.Hom.Defs +import Mathlib.Algebra.Group.Subsemigroup.Defs + +/-! +# Submonoids: definition + +This file defines bundled multiplicative and additive submonoids. We also define +a `CompleteLattice` structure on `Submonoid`s, define the closure of a set as the minimal submonoid +that includes this set, and prove a few results about extending properties from a dense set (i.e. +a set with `closure s = ⊤`) to the whole monoid, see `Submonoid.dense_induction` and +`MonoidHom.ofClosureEqTopLeft`/`MonoidHom.ofClosureEqTopRight`. + +## Main definitions + +* `Submonoid M`: the type of bundled submonoids of a monoid `M`; the underlying set is given in + the `carrier` field of the structure, and should be accessed through coercion as in `(S : Set M)`. +* `AddSubmonoid M` : the type of bundled submonoids of an additive monoid `M`. + +For each of the following definitions in the `Submonoid` namespace, there is a corresponding +definition in the `AddSubmonoid` namespace. + +* `Submonoid.copy` : copy of a submonoid with `carrier` replaced by a set that is equal but possibly + not definitionally equal to the carrier of the original `Submonoid`. +* `MonoidHom.eqLocusM`: the submonoid of elements `x : M` such that `f x = g x`; + +## Implementation notes + +Submonoid inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a submonoid's underlying set. + +Note that `Submonoid M` does not actually require `Monoid M`, instead requiring only the weaker +`MulOneClass M`. + +This file is designed to have very few dependencies. In particular, it should not use natural +numbers. `Submonoid` is implemented by extending `Subsemigroup` requiring `one_mem'`. + +## Tags +submonoid, submonoids +-/ + +assert_not_exists CompleteLattice +assert_not_exists MonoidWithZero + +variable {M : Type*} {N : Type*} + +section NonAssoc + +variable [MulOneClass M] {s : Set M} + +/-- `OneMemClass S M` says `S` is a type of subsets `s ≤ M`, such that `1 ∈ s` for all `s`. -/ +class OneMemClass (S : Type*) (M : outParam Type*) [One M] [SetLike S M] : Prop where + /-- By definition, if we have `OneMemClass S M`, we have `1 ∈ s` for all `s : S`. -/ + one_mem : ∀ s : S, (1 : M) ∈ s + +export OneMemClass (one_mem) + +/-- `ZeroMemClass S M` says `S` is a type of subsets `s ≤ M`, such that `0 ∈ s` for all `s`. -/ +class ZeroMemClass (S : Type*) (M : outParam Type*) [Zero M] [SetLike S M] : Prop where + /-- By definition, if we have `ZeroMemClass S M`, we have `0 ∈ s` for all `s : S`. -/ + zero_mem : ∀ s : S, (0 : M) ∈ s + +export ZeroMemClass (zero_mem) + +attribute [to_additive] OneMemClass + +attribute [aesop safe apply (rule_sets := [SetLike])] one_mem zero_mem + +section + +/-- A submonoid of a monoid `M` is a subset containing 1 and closed under multiplication. -/ +structure Submonoid (M : Type*) [MulOneClass M] extends Subsemigroup M where + /-- A submonoid contains `1`. -/ + one_mem' : (1 : M) ∈ carrier + +end + +/-- A submonoid of a monoid `M` can be considered as a subsemigroup of that monoid. -/ +add_decl_doc Submonoid.toSubsemigroup + +/-- `SubmonoidClass S M` says `S` is a type of subsets `s ≤ M` that contain `1` +and are closed under `(*)` -/ +class SubmonoidClass (S : Type*) (M : outParam Type*) [MulOneClass M] [SetLike S M] extends + MulMemClass S M, OneMemClass S M : Prop + +section + +/-- An additive submonoid of an additive monoid `M` is a subset containing 0 and + closed under addition. -/ +structure AddSubmonoid (M : Type*) [AddZeroClass M] extends AddSubsemigroup M where + /-- An additive submonoid contains `0`. -/ + zero_mem' : (0 : M) ∈ carrier + +end + +/-- An additive submonoid of an additive monoid `M` can be considered as an +additive subsemigroup of that additive monoid. -/ +add_decl_doc AddSubmonoid.toAddSubsemigroup + +/-- `AddSubmonoidClass S M` says `S` is a type of subsets `s ≤ M` that contain `0` +and are closed under `(+)` -/ +class AddSubmonoidClass (S : Type*) (M : outParam Type*) [AddZeroClass M] [SetLike S M] extends + AddMemClass S M, ZeroMemClass S M : Prop + +attribute [to_additive] Submonoid SubmonoidClass + +@[to_additive (attr := aesop safe apply (rule_sets := [SetLike]))] +theorem pow_mem {M A} [Monoid M] [SetLike A M] [SubmonoidClass A M] {S : A} {x : M} + (hx : x ∈ S) : ∀ n : ℕ, x ^ n ∈ S + | 0 => by + rw [pow_zero] + exact OneMemClass.one_mem S + | n + 1 => by + rw [pow_succ] + exact mul_mem (pow_mem hx n) hx + +namespace Submonoid + +@[to_additive] +instance : SetLike (Submonoid M) M where + coe s := s.carrier + coe_injective' p q h := by cases p; cases q; congr; exact SetLike.coe_injective' h + +@[to_additive] +instance : SubmonoidClass (Submonoid M) M where + one_mem := Submonoid.one_mem' + mul_mem {s} := s.mul_mem' + +initialize_simps_projections Submonoid (carrier → coe) + +initialize_simps_projections AddSubmonoid (carrier → coe) + +@[to_additive (attr := simp)] +theorem mem_toSubsemigroup {s : Submonoid M} {x : M} : x ∈ s.toSubsemigroup ↔ x ∈ s := + Iff.rfl + +-- Porting note: `x ∈ s.carrier` is now syntactically `x ∈ s.toSubsemigroup.carrier`, +-- which `simp` already simplifies to `x ∈ s.toSubsemigroup`. So we remove the `@[simp]` attribute +-- here, and instead add the simp lemma `mem_toSubsemigroup` to allow `simp` to do this exact +-- simplification transitively. +@[to_additive] +theorem mem_carrier {s : Submonoid M} {x : M} : x ∈ s.carrier ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_mk {s : Subsemigroup M} {x : M} (h_one) : x ∈ mk s h_one ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp)] +theorem coe_set_mk {s : Subsemigroup M} (h_one) : (mk s h_one : Set M) = s := + rfl + +@[to_additive (attr := simp)] +theorem mk_le_mk {s t : Subsemigroup M} (h_one) (h_one') : mk s h_one ≤ mk t h_one' ↔ s ≤ t := + Iff.rfl + +/-- Two submonoids are equal if they have the same elements. -/ +@[to_additive (attr := ext) "Two `AddSubmonoid`s are equal if they have the same elements."] +theorem ext {S T : Submonoid M} (h : ∀ x, x ∈ S ↔ x ∈ T) : S = T := + SetLike.ext h + +/-- Copy a submonoid replacing `carrier` with a set that is equal to it. -/ +@[to_additive "Copy an additive submonoid replacing `carrier` with a set that is equal to it."] +protected def copy (S : Submonoid M) (s : Set M) (hs : s = S) : Submonoid M where + carrier := s + one_mem' := show 1 ∈ s from hs.symm ▸ S.one_mem' + mul_mem' := hs.symm ▸ S.mul_mem' + +variable {S : Submonoid M} + +@[to_additive (attr := simp)] +theorem coe_copy {s : Set M} (hs : s = S) : (S.copy s hs : Set M) = s := + rfl + +@[to_additive] +theorem copy_eq {s : Set M} (hs : s = S) : S.copy s hs = S := + SetLike.coe_injective hs + +variable (S) + +/-- A submonoid contains the monoid's 1. -/ +@[to_additive "An `AddSubmonoid` contains the monoid's 0."] +protected theorem one_mem : (1 : M) ∈ S := + one_mem S + +/-- A submonoid is closed under multiplication. -/ +@[to_additive "An `AddSubmonoid` is closed under addition."] +protected theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := + mul_mem + +/-- The submonoid `M` of the monoid `M`. -/ +@[to_additive "The additive submonoid `M` of the `AddMonoid M`."] +instance : Top (Submonoid M) := + ⟨{ carrier := Set.univ + one_mem' := Set.mem_univ 1 + mul_mem' := fun _ _ => Set.mem_univ _ }⟩ + +/-- The trivial submonoid `{1}` of a monoid `M`. -/ +@[to_additive "The trivial `AddSubmonoid` `{0}` of an `AddMonoid` `M`."] +instance : Bot (Submonoid M) := + ⟨{ carrier := {1} + one_mem' := Set.mem_singleton 1 + mul_mem' := fun ha hb => by + simp only [Set.mem_singleton_iff] at * + rw [ha, hb, mul_one] }⟩ + +@[to_additive] +instance : Inhabited (Submonoid M) := + ⟨⊥⟩ + +@[to_additive (attr := simp)] +theorem mem_bot {x : M} : x ∈ (⊥ : Submonoid M) ↔ x = 1 := + Set.mem_singleton_iff + +@[to_additive (attr := simp)] +theorem mem_top (x : M) : x ∈ (⊤ : Submonoid M) := + Set.mem_univ x + +@[to_additive (attr := simp)] +theorem coe_top : ((⊤ : Submonoid M) : Set M) = Set.univ := + rfl + +@[to_additive (attr := simp)] +theorem coe_bot : ((⊥ : Submonoid M) : Set M) = {1} := + rfl + +/-- The inf of two submonoids is their intersection. -/ +@[to_additive "The inf of two `AddSubmonoid`s is their intersection."] +instance : Inf (Submonoid M) := + ⟨fun S₁ S₂ => + { carrier := S₁ ∩ S₂ + one_mem' := ⟨S₁.one_mem, S₂.one_mem⟩ + mul_mem' := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ => ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ + +@[to_additive (attr := simp)] +theorem coe_inf (p p' : Submonoid M) : ((p ⊓ p' : Submonoid M) : Set M) = (p : Set M) ∩ p' := + rfl + +@[to_additive (attr := simp)] +theorem mem_inf {p p' : Submonoid M} {x : M} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := + Iff.rfl + +@[to_additive (attr := simp)] +theorem subsingleton_iff : Subsingleton (Submonoid M) ↔ Subsingleton M := + ⟨fun _ => + ⟨fun x y => + have : ∀ i : M, i = 1 := fun i => + mem_bot.mp <| Subsingleton.elim (⊤ : Submonoid M) ⊥ ▸ mem_top i + (this x).trans (this y).symm⟩, + fun _ => + ⟨fun x y => Submonoid.ext fun i => Subsingleton.elim 1 i ▸ by simp [Submonoid.one_mem]⟩⟩ + +@[to_additive (attr := simp)] +theorem nontrivial_iff : Nontrivial (Submonoid M) ↔ Nontrivial M := + not_iff_not.mp + ((not_nontrivial_iff_subsingleton.trans subsingleton_iff).trans + not_nontrivial_iff_subsingleton.symm) + +@[to_additive] +instance [Subsingleton M] : Unique (Submonoid M) := + ⟨⟨⊥⟩, fun a => @Subsingleton.elim _ (subsingleton_iff.mpr ‹_›) a _⟩ + +@[to_additive] +instance [Nontrivial M] : Nontrivial (Submonoid M) := + nontrivial_iff.mpr ‹_› + +end Submonoid + +namespace MonoidHom + +variable [MulOneClass N] + +open Submonoid + +/-- The submonoid of elements `x : M` such that `f x = g x` -/ +@[to_additive "The additive submonoid of elements `x : M` such that `f x = g x`"] +def eqLocusM (f g : M →* N) : Submonoid M where + carrier := { x | f x = g x } + one_mem' := by rw [Set.mem_setOf_eq, f.map_one, g.map_one] + mul_mem' (hx : _ = _) (hy : _ = _) := by simp [*] + +@[to_additive (attr := simp)] +theorem eqLocusM_same (f : M →* N) : f.eqLocusM f = ⊤ := + SetLike.ext fun _ => eq_self_iff_true _ + +@[to_additive] +theorem eq_of_eqOn_topM {f g : M →* N} (h : Set.EqOn f g (⊤ : Submonoid M)) : f = g := + ext fun _ => h trivial + +end MonoidHom + +end NonAssoc + +namespace OneMemClass + +variable {A M₁ : Type*} [SetLike A M₁] [One M₁] [hA : OneMemClass A M₁] (S' : A) + +/-- A submonoid of a monoid inherits a 1. -/ +@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits a zero."] +instance one : One S' := + ⟨⟨1, OneMemClass.one_mem S'⟩⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_one : ((1 : S') : M₁) = 1 := + rfl + +variable {S'} + +@[to_additive (attr := simp, norm_cast)] +theorem coe_eq_one {x : S'} : (↑x : M₁) = 1 ↔ x = 1 := + (Subtype.ext_iff.symm : (x : M₁) = (1 : S') ↔ x = 1) + +variable (S') + +@[to_additive] +theorem one_def : (1 : S') = ⟨1, OneMemClass.one_mem S'⟩ := + rfl + +end OneMemClass + +variable {A : Type*} [MulOneClass M] [SetLike A M] [hA : SubmonoidClass A M] (S' : A) + +/-- An `AddSubmonoid` of an `AddMonoid` inherits a scalar multiplication. -/ +instance AddSubmonoidClass.nSMul {M} [AddMonoid M] {A : Type*} [SetLike A M] + [AddSubmonoidClass A M] (S : A) : SMul ℕ S := + ⟨fun n a => ⟨n • a.1, nsmul_mem a.2 n⟩⟩ + +namespace SubmonoidClass + +/-- A submonoid of a monoid inherits a power operator. -/ +instance nPow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] (S : A) : Pow S ℕ := + ⟨fun a n => ⟨a.1 ^ n, pow_mem a.2 n⟩⟩ + +attribute [to_additive existing nSMul] nPow + +@[to_additive (attr := simp, norm_cast)] +theorem coe_pow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] {S : A} (x : S) + (n : ℕ) : ↑(x ^ n) = (x : M) ^ n := + rfl + +@[to_additive (attr := simp)] +theorem mk_pow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] {S : A} (x : M) + (hx : x ∈ S) (n : ℕ) : (⟨x, hx⟩ : S) ^ n = ⟨x ^ n, pow_mem hx n⟩ := + rfl + +-- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. +/-- A submonoid of a unital magma inherits a unital magma structure. -/ +@[to_additive + "An `AddSubmonoid` of a unital additive magma inherits a unital additive magma structure."] +instance (priority := 75) toMulOneClass {M : Type*} [MulOneClass M] {A : Type*} [SetLike A M] + [SubmonoidClass A M] (S : A) : MulOneClass S := + Subtype.coe_injective.mulOneClass (↑) rfl (fun _ _ => rfl) + +-- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. +/-- A submonoid of a monoid inherits a monoid structure. -/ +@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an `AddMonoid` structure."] +instance (priority := 75) toMonoid {M : Type*} [Monoid M] {A : Type*} [SetLike A M] + [SubmonoidClass A M] (S : A) : Monoid S := + Subtype.coe_injective.monoid (↑) rfl (fun _ _ => rfl) (fun _ _ => rfl) + +-- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. +/-- A submonoid of a `CommMonoid` is a `CommMonoid`. -/ +@[to_additive "An `AddSubmonoid` of an `AddCommMonoid` is an `AddCommMonoid`."] +instance (priority := 75) toCommMonoid {M} [CommMonoid M] {A : Type*} [SetLike A M] + [SubmonoidClass A M] (S : A) : CommMonoid S := + Subtype.coe_injective.commMonoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl + +/-- The natural monoid hom from a submonoid of monoid `M` to `M`. -/ +@[to_additive "The natural monoid hom from an `AddSubmonoid` of `AddMonoid` `M` to `M`."] +def subtype : S' →* M where + toFun := Subtype.val; map_one' := rfl; map_mul' _ _ := by simp + +@[to_additive (attr := simp)] +theorem coe_subtype : (SubmonoidClass.subtype S' : S' → M) = Subtype.val := + rfl + +end SubmonoidClass + +namespace Submonoid + +variable {M : Type*} [MulOneClass M] (S : Submonoid M) + +/-- A submonoid of a monoid inherits a multiplication. -/ +@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an addition."] +instance mul : Mul S := + ⟨fun a b => ⟨a.1 * b.1, S.mul_mem a.2 b.2⟩⟩ + +/-- A submonoid of a monoid inherits a 1. -/ +@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits a zero."] +instance one : One S := + ⟨⟨_, S.one_mem⟩⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_mul (x y : S) : (↑(x * y) : M) = ↑x * ↑y := + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_one : ((1 : S) : M) = 1 := + rfl + +@[to_additive (attr := simp)] +lemma mk_eq_one {a : M} {ha} : (⟨a, ha⟩ : S) = 1 ↔ a = 1 := by simp [← SetLike.coe_eq_coe] + +@[to_additive (attr := simp)] +theorem mk_mul_mk (x y : M) (hx : x ∈ S) (hy : y ∈ S) : + (⟨x, hx⟩ : S) * ⟨y, hy⟩ = ⟨x * y, S.mul_mem hx hy⟩ := + rfl + +@[to_additive] +theorem mul_def (x y : S) : x * y = ⟨x * y, S.mul_mem x.2 y.2⟩ := + rfl + +@[to_additive] +theorem one_def : (1 : S) = ⟨1, S.one_mem⟩ := + rfl + +/-- A submonoid of a unital magma inherits a unital magma structure. -/ +@[to_additive + "An `AddSubmonoid` of a unital additive magma inherits a unital additive magma structure."] +instance toMulOneClass {M : Type*} [MulOneClass M] (S : Submonoid M) : MulOneClass S := + Subtype.coe_injective.mulOneClass (↑) rfl fun _ _ => rfl + +@[to_additive] +protected theorem pow_mem {M : Type*} [Monoid M] (S : Submonoid M) {x : M} (hx : x ∈ S) (n : ℕ) : + x ^ n ∈ S := + pow_mem hx n + +/-- A submonoid of a monoid inherits a monoid structure. -/ +@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an `AddMonoid` structure."] +instance toMonoid {M : Type*} [Monoid M] (S : Submonoid M) : Monoid S := + Subtype.coe_injective.monoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl + +/-- A submonoid of a `CommMonoid` is a `CommMonoid`. -/ +@[to_additive "An `AddSubmonoid` of an `AddCommMonoid` is an `AddCommMonoid`."] +instance toCommMonoid {M} [CommMonoid M] (S : Submonoid M) : CommMonoid S := + Subtype.coe_injective.commMonoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl + +/-- The natural monoid hom from a submonoid of monoid `M` to `M`. -/ +@[to_additive "The natural monoid hom from an `AddSubmonoid` of `AddMonoid` `M` to `M`."] +def subtype : S →* M where + toFun := Subtype.val; map_one' := rfl; map_mul' _ _ := by simp + +@[to_additive (attr := simp)] +theorem coe_subtype : ⇑S.subtype = Subtype.val := + rfl + +end Submonoid diff --git a/Mathlib/Algebra/Group/Submonoid/DistribMulAction.lean b/Mathlib/Algebra/Group/Submonoid/DistribMulAction.lean index d11f9c6414e1f..aa2205e477ee9 100644 --- a/Mathlib/Algebra/Group/Submonoid/DistribMulAction.lean +++ b/Mathlib/Algebra/Group/Submonoid/DistribMulAction.lean @@ -3,8 +3,8 @@ 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.Algebra.Group.Submonoid.Operations -import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.Group.Submonoid.Defs +import Mathlib.Algebra.GroupWithZero.Action.End /-! # Distributive actions by submonoids diff --git a/Mathlib/Algebra/Group/Submonoid/Membership.lean b/Mathlib/Algebra/Group/Submonoid/Membership.lean index e1ec1fb022a46..9b396e3f6c38b 100644 --- a/Mathlib/Algebra/Group/Submonoid/Membership.lean +++ b/Mathlib/Algebra/Group/Submonoid/Membership.lean @@ -56,7 +56,7 @@ theorem coe_multiset_prod {M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (m.prod : M) = (m.map (↑)).prod := (SubmonoidClass.subtype S : _ →* M).map_multiset_prod m -@[to_additive (attr := norm_cast)] -- Porting note (#10618): removed `simp`, `simp` can prove it +@[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 @@ -97,16 +97,16 @@ namespace Submonoid variable (s : Submonoid M) -@[to_additive (attr := norm_cast)] -- Porting note (#10618): removed `simp`, `simp` can prove it +@[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)] -- Porting note (#10618): removed `simp`, `simp` can prove it +@[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, simp)] +@[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 @@ -175,9 +175,9 @@ theorem mem_iSup_of_directed {ι} [hι : Nonempty ι] {S : ι → Submonoid M} ( refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup S i hi⟩ suffices x ∈ closure (⋃ i, (S i : Set M)) → ∃ i, x ∈ S i by simpa only [closure_iUnion, closure_eq (S _)] using this - refine fun hx ↦ closure_induction hx (fun _ ↦ mem_iUnion.1) ?_ ?_ + refine closure_induction (fun _ ↦ mem_iUnion.1) ?_ ?_ · exact hι.elim fun i ↦ ⟨i, (S i).one_mem⟩ - · rintro x y ⟨i, hi⟩ ⟨j, hj⟩ + · rintro x y - - ⟨i, hi⟩ ⟨j, hj⟩ rcases hS i j with ⟨k, hki, hkj⟩ exact ⟨k, (S k).mul_mem (hki hi) (hkj hj)⟩ @@ -233,7 +233,7 @@ then it holds for all elements of the supremum of `S`. -/ theorem iSup_induction {ι : Sort*} (S : ι → Submonoid M) {C : M → Prop} {x : M} (hx : x ∈ ⨆ i, S i) (mem : ∀ (i), ∀ x ∈ S i, C x) (one : C 1) (mul : ∀ x y, C x → C y → C (x * y)) : C x := by rw [iSup_eq_closure] at hx - refine closure_induction hx (fun x hx => ?_) one mul + refine closure_induction (fun x hx => ?_) one (fun _ _ _ _ ↦ mul _ _) hx obtain ⟨i, hi⟩ := Set.mem_iUnion.mp hx exact mem _ _ hi @@ -356,9 +356,9 @@ theorem closure_induction_left {s : Set M} {p : (m : M) → m ∈ closure s → p x h := by simp_rw [closure_eq_mrange] at h obtain ⟨l, rfl⟩ := h - induction l with - | h0 => exact one - | ih x y ih => + induction l using FreeMonoid.inductionOn' with + | one => exact one + | mul_of x y ih => simp only [map_mul, FreeMonoid.lift_eval_of] refine mul_left _ x.prop (FreeMonoid.lift Subtype.val y) _ (ih ?_) simp only [closure_eq_mrange, mem_mrange, exists_apply_eq_apply] @@ -379,7 +379,7 @@ theorem closure_induction_right {s : Set M} {p : (m : M) → m ∈ closure s → closure_induction_left (s := MulOpposite.unop ⁻¹' s) (p := fun m hm => p m.unop <| by rwa [← op_closure] at hm) one - (fun _x hx _y hy => mul_right _ _ _ hx) + (fun _x hx _y _ => mul_right _ _ _ hx) (by rwa [← op_closure]) @[to_additive (attr := elab_as_elim)] @@ -440,7 +440,7 @@ abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (po ← pow_eq_pow_mod _ hx, pow_mul, pow_mul] zpow_succ' m x := Subtype.ext <| by obtain ⟨_, k, rfl⟩ := x - simp only [← pow_mul, Int.natMod, Int.ofNat_eq_coe, SubmonoidClass.coe_pow, coe_mul] + simp only [← pow_mul, Int.natMod, SubmonoidClass.coe_pow, coe_mul] norm_cast iterate 2 rw [Int.toNat_natCast, mul_comm, pow_mul, ← pow_eq_pow_mod _ hx] rw [← pow_mul _ m, mul_comm, pow_mul, ← pow_succ, ← pow_mul, mul_comm, pow_mul] @@ -504,9 +504,9 @@ def closureCommMonoidOfComm {s : Set M} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b mul_comm := fun x y => by ext simp only [Submonoid.coe_mul] - exact - closure_induction₂ x.prop y.prop hcomm Commute.one_left Commute.one_right - (fun x y z => Commute.mul_left) fun x y z => Commute.mul_right } + exact closure_induction₂ (fun _ _ h₁ h₂ ↦ hcomm _ h₁ _ h₂) (fun _ _ ↦ Commute.one_left _) + (fun _ _ ↦ Commute.one_right _) (fun _ _ _ _ _ _ ↦ Commute.mul_left) + (fun _ _ _ _ _ _ ↦ Commute.mul_right) x.prop y.prop } end Submonoid @@ -609,26 +609,19 @@ variable {R : Type*} [NonUnitalNonAssocSemiring R] [SetLike M R] [MulMemClass M and an element of `M` is contained in the additive closure of `M`. -/ theorem mul_right_mem_add_closure (ha : a ∈ AddSubmonoid.closure (S : Set R)) (hb : b ∈ S) : a * b ∈ AddSubmonoid.closure (S : Set R) := by - revert b - apply @AddSubmonoid.closure_induction _ _ _ - (fun z => ∀ (b : R), b ∈ S → z * b ∈ AddSubmonoid.closure S) _ ha <;> clear ha a - · exact fun r hr b hb => AddSubmonoid.mem_closure.mpr fun y hy => hy (mul_mem hr hb) - · exact fun b _ => by simp only [zero_mul, (AddSubmonoid.closure (S : Set R)).zero_mem] - · simp_rw [add_mul] - exact fun r s hr hs b hb => (AddSubmonoid.closure (S : Set R)).add_mem (hr _ hb) (hs _ hb) + induction ha using AddSubmonoid.closure_induction with + | mem r hr => exact AddSubmonoid.mem_closure.mpr fun y hy => hy (mul_mem hr hb) + | one => simp only [zero_mul, zero_mem _] + | mul r s _ _ hr hs => simpa only [add_mul] using add_mem hr hs /-- The product of two elements of the additive closure of a submonoid `M` is an element of the additive closure of `M`. -/ theorem mul_mem_add_closure (ha : a ∈ AddSubmonoid.closure (S : Set R)) (hb : b ∈ AddSubmonoid.closure (S : Set R)) : a * b ∈ AddSubmonoid.closure (S : Set R) := by - revert a - apply @AddSubmonoid.closure_induction _ _ _ - (fun z => ∀ {a : R}, a ∈ AddSubmonoid.closure ↑S → a * z ∈ AddSubmonoid.closure ↑S) - _ hb <;> clear hb b - · exact fun r hr b hb => MulMemClass.mul_right_mem_add_closure hb hr - · exact fun _ => by simp only [mul_zero, (AddSubmonoid.closure (S : Set R)).zero_mem] - · simp_rw [mul_add] - exact fun r s hr hs b hb => (AddSubmonoid.closure (S : Set R)).add_mem (hr hb) (hs hb) + induction hb using AddSubmonoid.closure_induction with + | mem r hr => exact MulMemClass.mul_right_mem_add_closure ha hr + | one => simp only [mul_zero, zero_mem _] + | mul r s _ _ hr hs => simpa only [mul_add] using add_mem hr hs /-- The product of an element of `S` and an element of the additive closure of a multiplicative submonoid `S` is contained in the additive closure of `S`. -/ diff --git a/Mathlib/Algebra/Group/Submonoid/Operations.lean b/Mathlib/Algebra/Group/Submonoid/Operations.lean index f84160423a5b5..de4a43436a3bd 100644 --- a/Mathlib/Algebra/Group/Submonoid/Operations.lean +++ b/Mathlib/Algebra/Group/Submonoid/Operations.lean @@ -4,10 +4,10 @@ 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.Action.Defs +import Mathlib.Algebra.Group.Action.Faithful import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Submonoid.Basic -import Mathlib.Algebra.Group.Subsemigroup.Operations /-! # Operations on `Submonoid`s @@ -407,158 +407,7 @@ theorem comap_strictMono_of_surjective : StrictMono (comap f) := end GaloisInsertion -end Submonoid - -namespace OneMemClass - -variable {A M₁ : Type*} [SetLike A M₁] [One M₁] [hA : OneMemClass A M₁] (S' : A) - -/-- A submonoid of a monoid inherits a 1. -/ -@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits a zero."] -instance one : One S' := - ⟨⟨1, OneMemClass.one_mem S'⟩⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_one : ((1 : S') : M₁) = 1 := - rfl - -variable {S'} - -@[to_additive (attr := simp, norm_cast)] -theorem coe_eq_one {x : S'} : (↑x : M₁) = 1 ↔ x = 1 := - (Subtype.ext_iff.symm : (x : M₁) = (1 : S') ↔ x = 1) - -variable (S') - -@[to_additive] -theorem one_def : (1 : S') = ⟨1, OneMemClass.one_mem S'⟩ := - rfl - -end OneMemClass - -variable {A : Type*} [SetLike A M] [hA : SubmonoidClass A M] (S' : A) - -/-- An `AddSubmonoid` of an `AddMonoid` inherits a scalar multiplication. -/ -instance AddSubmonoidClass.nSMul {M} [AddMonoid M] {A : Type*} [SetLike A M] - [AddSubmonoidClass A M] (S : A) : SMul ℕ S := - ⟨fun n a => ⟨n • a.1, nsmul_mem a.2 n⟩⟩ - -namespace SubmonoidClass - -/-- A submonoid of a monoid inherits a power operator. -/ -instance nPow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] (S : A) : Pow S ℕ := - ⟨fun a n => ⟨a.1 ^ n, pow_mem a.2 n⟩⟩ - -attribute [to_additive existing nSMul] nPow - -@[to_additive (attr := simp, norm_cast)] -theorem coe_pow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] {S : A} (x : S) - (n : ℕ) : ↑(x ^ n) = (x : M) ^ n := - rfl - -@[to_additive (attr := simp)] -theorem mk_pow {M} [Monoid M] {A : Type*} [SetLike A M] [SubmonoidClass A M] {S : A} (x : M) - (hx : x ∈ S) (n : ℕ) : (⟨x, hx⟩ : S) ^ n = ⟨x ^ n, pow_mem hx n⟩ := - rfl - --- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. -/-- A submonoid of a unital magma inherits a unital magma structure. -/ -@[to_additive - "An `AddSubmonoid` of a unital additive magma inherits a unital additive magma structure."] -instance (priority := 75) toMulOneClass {M : Type*} [MulOneClass M] {A : Type*} [SetLike A M] - [SubmonoidClass A M] (S : A) : MulOneClass S := - Subtype.coe_injective.mulOneClass (↑) rfl (fun _ _ => rfl) - --- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. -/-- A submonoid of a monoid inherits a monoid structure. -/ -@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an `AddMonoid` structure."] -instance (priority := 75) toMonoid {M : Type*} [Monoid M] {A : Type*} [SetLike A M] - [SubmonoidClass A M] (S : A) : Monoid S := - Subtype.coe_injective.monoid (↑) rfl (fun _ _ => rfl) (fun _ _ => rfl) - --- Prefer subclasses of `Monoid` over subclasses of `SubmonoidClass`. -/-- A submonoid of a `CommMonoid` is a `CommMonoid`. -/ -@[to_additive "An `AddSubmonoid` of an `AddCommMonoid` is an `AddCommMonoid`."] -instance (priority := 75) toCommMonoid {M} [CommMonoid M] {A : Type*} [SetLike A M] - [SubmonoidClass A M] (S : A) : CommMonoid S := - Subtype.coe_injective.commMonoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl - -/-- The natural monoid hom from a submonoid of monoid `M` to `M`. -/ -@[to_additive "The natural monoid hom from an `AddSubmonoid` of `AddMonoid` `M` to `M`."] -def subtype : S' →* M where - toFun := Subtype.val; map_one' := rfl; map_mul' _ _ := by simp - -@[to_additive (attr := simp)] -theorem coe_subtype : (SubmonoidClass.subtype S' : S' → M) = Subtype.val := - rfl - -end SubmonoidClass - -namespace Submonoid - -/-- A submonoid of a monoid inherits a multiplication. -/ -@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an addition."] -instance mul : Mul S := - ⟨fun a b => ⟨a.1 * b.1, S.mul_mem a.2 b.2⟩⟩ - -/-- A submonoid of a monoid inherits a 1. -/ -@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits a zero."] -instance one : One S := - ⟨⟨_, S.one_mem⟩⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_mul (x y : S) : (↑(x * y) : M) = ↑x * ↑y := - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_one : ((1 : S) : M) = 1 := - rfl - -@[to_additive (attr := simp)] -lemma mk_eq_one {a : M} {ha} : (⟨a, ha⟩ : S) = 1 ↔ a = 1 := by simp [← SetLike.coe_eq_coe] - -@[to_additive (attr := simp)] -theorem mk_mul_mk (x y : M) (hx : x ∈ S) (hy : y ∈ S) : - (⟨x, hx⟩ : S) * ⟨y, hy⟩ = ⟨x * y, S.mul_mem hx hy⟩ := - rfl - -@[to_additive] -theorem mul_def (x y : S) : x * y = ⟨x * y, S.mul_mem x.2 y.2⟩ := - rfl - -@[to_additive] -theorem one_def : (1 : S) = ⟨1, S.one_mem⟩ := - rfl - -/-- A submonoid of a unital magma inherits a unital magma structure. -/ -@[to_additive - "An `AddSubmonoid` of a unital additive magma inherits a unital additive magma structure."] -instance toMulOneClass {M : Type*} [MulOneClass M] (S : Submonoid M) : MulOneClass S := - Subtype.coe_injective.mulOneClass (↑) rfl fun _ _ => rfl - -@[to_additive] -protected theorem pow_mem {M : Type*} [Monoid M] (S : Submonoid M) {x : M} (hx : x ∈ S) (n : ℕ) : - x ^ n ∈ S := - pow_mem hx n - -/-- A submonoid of a monoid inherits a monoid structure. -/ -@[to_additive "An `AddSubmonoid` of an `AddMonoid` inherits an `AddMonoid` structure."] -instance toMonoid {M : Type*} [Monoid M] (S : Submonoid M) : Monoid S := - Subtype.coe_injective.monoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl - -/-- A submonoid of a `CommMonoid` is a `CommMonoid`. -/ -@[to_additive "An `AddSubmonoid` of an `AddCommMonoid` is an `AddCommMonoid`."] -instance toCommMonoid {M} [CommMonoid M] (S : Submonoid M) : CommMonoid S := - Subtype.coe_injective.commMonoid (↑) rfl (fun _ _ => rfl) fun _ _ => rfl - -/-- The natural monoid hom from a submonoid of monoid `M` to `M`. -/ -@[to_additive "The natural monoid hom from an `AddSubmonoid` of `AddMonoid` `M` to `M`."] -def subtype : S →* M where - toFun := Subtype.val; map_one' := rfl; map_mul' _ _ := by simp - -@[to_additive (attr := simp)] -theorem coe_subtype : ⇑S.subtype = Subtype.val := - rfl +variable {M : Type*} [MulOneClass M] (S : Submonoid M) /-- The top submonoid is isomorphic to the monoid. -/ @[to_additive (attr := simps) "The top additive submonoid is isomorphic to the additive monoid."] @@ -587,13 +436,8 @@ theorem coe_equivMapOfInjective_apply (f : M →* N) (hf : Function.Injective f) @[to_additive (attr := simp)] theorem closure_closure_coe_preimage {s : Set M} : closure (((↑) : closure s → M) ⁻¹' s) = ⊤ := - eq_top_iff.2 fun x => - Subtype.recOn x fun x hx _ => by - refine closure_induction' - (p := fun y hy ↦ (⟨y, hy⟩ : closure s) ∈ closure (((↑) : closure s → M) ⁻¹' s)) - _ (fun g hg => subset_closure hg) ?_ (fun g₁ g₂ hg₁ hg₂ => ?_) hx - · exact Submonoid.one_mem _ - · exact Submonoid.mul_mem _ + eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ + closure_induction (fun _ h ↦ subset_closure h) (one_mem _) (fun _ _ _ _ ↦ mul_mem) hx' /-- Given submonoids `s`, `t` of monoids `M`, `N` respectively, `s × t` as a submonoid of `M × N`. -/ @@ -720,6 +564,15 @@ theorem prod_le_iff {s : Submonoid M} {t : Submonoid N} {u : Submonoid (M × N)} simpa using h2 simpa using Submonoid.mul_mem _ h1' h2' +@[to_additive closure_prod] +theorem closure_prod {s : Set M} {t : Set N} (hs : 1 ∈ s) (ht : 1 ∈ t) : + closure (s ×ˢ t) = (closure s).prod (closure t) := + le_antisymm + (closure_le.2 <| Set.prod_subset_prod_iff.2 <| .inl ⟨subset_closure, subset_closure⟩) + (prod_le_iff.2 ⟨ + map_le_of_le_comap _ <| closure_le.2 fun _x hx => subset_closure ⟨hx, ht⟩, + map_le_of_le_comap _ <| closure_le.2 fun _y hy => subset_closure ⟨hs, hy⟩⟩) + end Submonoid namespace MonoidHom @@ -1182,7 +1035,7 @@ elements of `M`. -/ noncomputable def unitsTypeEquivIsUnitSubmonoid [Monoid M] : Mˣ ≃* IsUnit.submonoid M where toFun x := ⟨x, Units.isUnit x⟩ invFun x := x.prop.unit - left_inv x := IsUnit.unit_of_val_units _ + left_inv _ := IsUnit.unit_of_val_units _ right_inv x := by simp_rw [IsUnit.unit_spec] map_mul' x y := by simp_rw [Units.val_mul]; rfl diff --git a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean index c2123399f6037..fc97cb647e916 100644 --- a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean +++ b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean @@ -3,6 +3,7 @@ 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.Group.Hom.End import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Order.BigOperators.Group.List import Mathlib.Data.Set.Pointwise.SMul @@ -85,11 +86,11 @@ theorem sup_eq_closure_mul (H K : Submonoid M) : H ⊔ K = closure ((H : Set M) @[to_additive] theorem pow_smul_mem_closure_smul {N : Type*} [CommMonoid N] [MulAction M N] [IsScalarTower M N N] (r : M) (s : Set N) {x : N} (hx : x ∈ closure s) : ∃ n : ℕ, r ^ n • x ∈ closure (r • s) := by - refine @closure_induction N _ s (fun x : N => ∃ n : ℕ, r ^ n • x ∈ closure (r • s)) _ hx ?_ ?_ ?_ - · intro x hx - exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩ - · exact ⟨0, by simpa using one_mem _⟩ - · rintro x y ⟨nx, hx⟩ ⟨ny, hy⟩ + induction hx using closure_induction with + | mem x hx => exact ⟨1, subset_closure ⟨_, hx, by rw [pow_one]⟩⟩ + | one => exact ⟨0, by simpa using one_mem _⟩ + | mul x y _ _ hx hy => + obtain ⟨⟨nx, hx⟩, ⟨ny, hy⟩⟩ := And.intro hx hy use ny + nx rw [pow_add, mul_smul, ← smul_mul_assoc, mul_comm, ← smul_mul_assoc] exact mul_mem hy hx @@ -184,7 +185,7 @@ protected def pointwiseMulAction : MulAction α (Submonoid M) where one_smul S := by change S.map _ = S simpa only [map_one] using S.map_id - mul_smul a₁ a₂ S := + mul_smul _ _ S := (congr_arg (fun f : Monoid.End M => S.map f) (MonoidHom.map_mul _ _ _)).trans (S.map_map _ _).symm @@ -435,6 +436,69 @@ theorem one_eq_closure_one_set : (1 : AddSubmonoid R) = closure 1 := end AddMonoidWithOne +section SMul + +variable [AddMonoid R] [DistribSMul R A] + +/-- For `M : Submonoid R` and `N : AddSubmonoid A`, `M • N` is the additive submonoid +generated by all `m • n` where `m ∈ M` and `n ∈ N`. -/ +protected def smul : SMul (AddSubmonoid R) (AddSubmonoid A) where + smul M N := ⨆ s : M, N.map (DistribSMul.toAddMonoidHom A s.1) + +scoped[Pointwise] attribute [instance] AddSubmonoid.smul + +variable {M M' : AddSubmonoid R} {N P : AddSubmonoid A} {m : R} {n : A} + +theorem smul_mem_smul (hm : m ∈ M) (hn : n ∈ N) : m • n ∈ M • N := + (le_iSup _ ⟨m, hm⟩ : _ ≤ M • N) ⟨n, hn, by rfl⟩ + +theorem smul_le : M • N ≤ P ↔ ∀ m ∈ M, ∀ n ∈ N, m • n ∈ P := + ⟨fun H _m hm _n hn => H <| smul_mem_smul hm hn, fun H => + iSup_le fun ⟨m, hm⟩ => map_le_iff_le_comap.2 fun n hn => H m hm n hn⟩ + +@[elab_as_elim] +protected theorem smul_induction_on {C : A → Prop} {a : A} (ha : a ∈ M • N) + (hm : ∀ m ∈ M, ∀ n ∈ N, C (m • n)) (hadd : ∀ x y, C x → C y → C (x + y)) : C a := + (@smul_le _ _ _ _ _ _ _ ⟨⟨setOf C, hadd _ _⟩, by + simpa only [smul_zero] using hm _ (zero_mem _) _ (zero_mem _)⟩).2 hm ha + +@[simp] +theorem addSubmonoid_smul_bot (S : AddSubmonoid R) : S • (⊥ : AddSubmonoid A) = ⊥ := + eq_bot_iff.2 <| smul_le.2 fun m _ n hn => by + rw [AddSubmonoid.mem_bot] at hn ⊢; rw [hn, smul_zero] + +theorem smul_le_smul (h : M ≤ M') (hnp : N ≤ P) : M • N ≤ M' • P := + smul_le.2 fun _m hm _n hn => smul_mem_smul (h hm) (hnp hn) + +theorem smul_le_smul_left (h : M ≤ M') : M • P ≤ M' • P := + smul_le_smul h le_rfl + +theorem smul_le_smul_right (h : N ≤ P) : M • N ≤ M • P := + smul_le_smul le_rfl h + +theorem smul_subset_smul : (↑M : Set R) • (↑N : Set A) ⊆ (↑(M • N) : Set A) := + smul_subset_iff.2 fun _i hi _j hj ↦ smul_mem_smul hi hj + +theorem addSubmonoid_smul_sup : M • (N ⊔ P) = M • N ⊔ M • P := + le_antisymm (smul_le.mpr fun m hm np hnp ↦ by + refine closure_induction (p := (fun _ ↦ _ • · ∈ _)) ?_ ?_ ?_ (sup_eq_closure N P ▸ hnp) + · rintro x (hx | hx) + exacts [le_sup_left (a := M • N) (smul_mem_smul hm hx), + le_sup_right (a := M • N) (smul_mem_smul hm hx)] + · apply (smul_zero (A := A) m).symm ▸ (M • N ⊔ M • P).zero_mem + · intros _ _ _ _ h1 h2; rw [smul_add]; exact add_mem h1 h2) + (sup_le (smul_le_smul_right le_sup_left) <| smul_le_smul_right le_sup_right) + +variable {ι : Sort*} + +theorem smul_iSup (T : AddSubmonoid R) (S : ι → AddSubmonoid A) : (T • ⨆ i, S i) = ⨆ i, T • S i := + le_antisymm (smul_le.mpr fun t ht s hs ↦ iSup_induction _ (C := (t • · ∈ _)) hs + (fun i s hs ↦ mem_iSup_of_mem i <| smul_mem_smul ht hs) + (by simp_rw [smul_zero]; apply zero_mem) fun x y ↦ by simp_rw [smul_add]; apply add_mem) + (iSup_le fun i ↦ smul_le_smul_right <| le_iSup _ i) + +end SMul + section NonUnitalNonAssocSemiring variable [NonUnitalNonAssocSemiring R] @@ -446,20 +510,19 @@ protected def mul : Mul (AddSubmonoid R) := scoped[Pointwise] attribute [instance] AddSubmonoid.mul theorem mul_mem_mul {M N : AddSubmonoid R} {m n : R} (hm : m ∈ M) (hn : n ∈ N) : m * n ∈ M * N := - (le_iSup _ ⟨m, hm⟩ : _ ≤ M * N) ⟨n, hn, by rfl⟩ + smul_mem_smul hm hn theorem mul_le {M N P : AddSubmonoid R} : M * N ≤ P ↔ ∀ m ∈ M, ∀ n ∈ N, m * n ∈ P := - ⟨fun H _m hm _n hn => H <| mul_mem_mul hm hn, fun H => - iSup_le fun ⟨m, hm⟩ => map_le_iff_le_comap.2 fun n hn => H m hm n hn⟩ + smul_le @[elab_as_elim] protected theorem mul_induction_on {M N : AddSubmonoid R} {C : R → Prop} {r : R} (hr : r ∈ M * N) (hm : ∀ m ∈ M, ∀ n ∈ N, C (m * n)) (ha : ∀ x y, C x → C y → C (x + y)) : C r := - (@mul_le _ _ _ _ ⟨⟨setOf C, ha _ _⟩, by - simpa only [zero_mul] using hm _ (zero_mem _) _ (zero_mem _)⟩).2 hm hr + AddSubmonoid.smul_induction_on hr hm ha -- this proof is copied directly from `Submodule.span_mul_span` -- Porting note: proof rewritten +-- need `add_smul` to generalize to `SMul` theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * T) := by apply le_antisymm · refine mul_le.2 fun a ha b hb => ?_ @@ -479,27 +542,50 @@ theorem mul_eq_closure_mul_set (M N : AddSubmonoid R) : @[simp] theorem mul_bot (S : AddSubmonoid R) : S * ⊥ = ⊥ := - eq_bot_iff.2 <| mul_le.2 fun m _ n hn => by - rw [AddSubmonoid.mem_bot] at hn ⊢; rw [hn, mul_zero] + addSubmonoid_smul_bot S +-- need `zero_smul` to generalize to `SMul` @[simp] theorem bot_mul (S : AddSubmonoid R) : ⊥ * S = ⊥ := - eq_bot_iff.2 <| mul_le.2 fun m hm n hn => by + eq_bot_iff.2 <| mul_le.2 fun m hm n _ => by rw [AddSubmonoid.mem_bot] at hm ⊢; rw [hm, zero_mul] +variable {M N P Q : AddSubmonoid R} + @[mono] -theorem mul_le_mul {M N P Q : AddSubmonoid R} (hmp : M ≤ P) (hnq : N ≤ Q) : M * N ≤ P * Q := - mul_le.2 fun _m hm _n hn => mul_mem_mul (hmp hm) (hnq hn) +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 + +theorem 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 + +theorem mul_sup : M * (N ⊔ P) = M * N ⊔ M * P := + addSubmonoid_smul_sup + +-- need `zero_smul` and `add_smul` to generalize to `SMul` +theorem sup_mul : (M ⊔ N) * P = M * P ⊔ N * P := + le_antisymm (mul_le.mpr fun mn hmn p hp ↦ by + obtain ⟨m, hm, n, hn, rfl⟩ := mem_sup.mp hmn + rw [right_distrib]; exact add_mem_sup (mul_mem_mul hm hp) <| mul_mem_mul hn hp) + (sup_le (mul_le_mul_left le_sup_left) <| mul_le_mul_left le_sup_right) -theorem mul_le_mul_left {M N P : AddSubmonoid R} (h : M ≤ N) : M * P ≤ N * P := - mul_le_mul h (le_refl P) +variable {ι : Sort*} -theorem mul_le_mul_right {M N P : AddSubmonoid R} (h : N ≤ P) : M * N ≤ M * P := - mul_le_mul (le_refl M) h +-- need `zero_smul` and `add_smul` to generalize to `SMul` +theorem iSup_mul (S : ι → AddSubmonoid R) (T : AddSubmonoid R) : (⨆ i, S i) * T = ⨆ i, S i * T := + le_antisymm (mul_le.mpr fun s hs t ht ↦ iSup_induction _ (C := (· * t ∈ _)) hs + (fun i s hs ↦ mem_iSup_of_mem i <| mul_mem_mul hs ht) (by simp_rw [zero_mul]; apply zero_mem) + fun _ _ ↦ by simp_rw [right_distrib]; apply add_mem) <| + iSup_le fun i ↦ mul_le_mul_left (le_iSup _ i) -theorem mul_subset_mul {M N : AddSubmonoid R} : - (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := - mul_subset_iff.2 fun _i hi _j hj ↦ mul_mem_mul hi hj +theorem mul_iSup (T : AddSubmonoid R) (S : ι → AddSubmonoid R) : (T * ⨆ i, S i) = ⨆ i, T * S i := + smul_iSup T S end NonUnitalNonAssocSemiring @@ -552,17 +638,14 @@ variable [NonUnitalSemiring R] /-- Semigroup structure on additive submonoids of a (possibly, non-unital) semiring. -/ protected def semigroup : Semigroup (AddSubmonoid R) where mul := (· * ·) - mul_assoc M N P := + mul_assoc _M _N _P := le_antisymm - (mul_le.2 fun _mn hmn p hp => - suffices M * N ≤ (M * (N * P)).comap (AddMonoidHom.mulRight p) from this hmn - mul_le.2 fun m hm n hn => - show m * n * p ∈ M * (N * P) from - (mul_assoc m n p).symm ▸ mul_mem_mul hm (mul_mem_mul hn hp)) - (mul_le.2 fun m hm _np hnp => - suffices N * P ≤ (M * N * P).comap (AddMonoidHom.mulLeft m) from this hnp - mul_le.2 fun n hn p hp => - show m * (n * p) ∈ M * N * P from mul_assoc m n p ▸ mul_mem_mul (mul_mem_mul hm hn) hp) + (mul_le.2 fun _mn hmn p hp => AddSubmonoid.mul_induction_on hmn + (fun m hm n hn ↦ mul_assoc m n p ▸ mul_mem_mul hm <| mul_mem_mul hn hp) + fun x y ↦ (add_mul x y p).symm ▸ add_mem) + (mul_le.2 fun m hm _np hnp => AddSubmonoid.mul_induction_on hnp + (fun n hn p hp ↦ mul_assoc m n p ▸ mul_mem_mul (mul_mem_mul hm hn) hp) + fun x y ↦ (mul_add m x y) ▸ add_mem) scoped[Pointwise] attribute [instance] AddSubmonoid.semigroup end NonUnitalSemiring diff --git a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean index 88cda9b9d5583..31ab296bcc1c3 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean @@ -4,23 +4,17 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzzard, Amelia Livingston, Yury Kudryashov, Yakov Pechersky -/ -import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.Algebra.Group.Subsemigroup.Defs import Mathlib.Data.Set.Lattice -import Mathlib.Data.SetLike.Basic /-! -# Subsemigroups: definition and `CompleteLattice` structure +# Subsemigroups: `CompleteLattice` structure -This file defines bundled multiplicative and additive subsemigroups. We also define -a `CompleteLattice` structure on `Subsemigroup`s, +This file defines a `CompleteLattice` structure on `Subsemigroup`s, and define the closure of a set as the minimal subsemigroup that includes this set. ## Main definitions -* `Subsemigroup M`: the type of bundled subsemigroup of a magma `M`; the underlying set is given in - the `carrier` field of the structure, and should be accessed through coercion as in `(S : Set M)`. -* `AddSubsemigroup M` : the type of bundled subsemigroups of an additive magma `M`. - For each of the following definitions in the `Subsemigroup` namespace, there is a corresponding definition in the `AddSubsemigroup` namespace. @@ -56,143 +50,9 @@ section NonAssoc variable [Mul M] {s : Set M} variable [Add A] {t : Set A} -/-- `MulMemClass S M` says `S` is a type of sets `s : Set M` that are closed under `(*)` -/ -class MulMemClass (S : Type*) (M : Type*) [Mul M] [SetLike S M] : Prop where - /-- A substructure satisfying `MulMemClass` is closed under multiplication. -/ - mul_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a * b ∈ s - -export MulMemClass (mul_mem) - -/-- `AddMemClass S M` says `S` is a type of sets `s : Set M` that are closed under `(+)` -/ -class AddMemClass (S : Type*) (M : Type*) [Add M] [SetLike S M] : Prop where - /-- A substructure satisfying `AddMemClass` is closed under addition. -/ - add_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a + b ∈ s - -export AddMemClass (add_mem) - -attribute [to_additive] MulMemClass - -attribute [aesop safe apply (rule_sets := [SetLike])] mul_mem add_mem - -/-- A subsemigroup of a magma `M` is a subset closed under multiplication. -/ -structure Subsemigroup (M : Type*) [Mul M] where - /-- The carrier of a subsemigroup. -/ - carrier : Set M - /-- The product of two elements of a subsemigroup belongs to the subsemigroup. -/ - mul_mem' {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier - -/-- An additive subsemigroup of an additive magma `M` is a subset closed under addition. -/ -structure AddSubsemigroup (M : Type*) [Add M] where - /-- The carrier of an additive subsemigroup. -/ - carrier : Set M - /-- The sum of two elements of an additive subsemigroup belongs to the subsemigroup. -/ - add_mem' {a b} : a ∈ carrier → b ∈ carrier → a + b ∈ carrier - -attribute [to_additive AddSubsemigroup] Subsemigroup - namespace Subsemigroup -@[to_additive] -instance : SetLike (Subsemigroup M) M := - ⟨Subsemigroup.carrier, fun p q h => by cases p; cases q; congr⟩ - -@[to_additive] -instance : MulMemClass (Subsemigroup M) M where mul_mem := fun {_ _ _} => Subsemigroup.mul_mem' _ - -initialize_simps_projections Subsemigroup (carrier → coe) -initialize_simps_projections AddSubsemigroup (carrier → coe) - -@[to_additive (attr := simp)] -theorem mem_carrier {s : Subsemigroup M} {x : M} : x ∈ s.carrier ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_mk {s : Set M} {x : M} (h_mul) : x ∈ mk s h_mul ↔ x ∈ s := - Iff.rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_set_mk (s : Set M) (h_mul) : (mk s h_mul : Set M) = s := - rfl - -@[to_additive (attr := simp)] -theorem mk_le_mk {s t : Set M} (h_mul) (h_mul') : mk s h_mul ≤ mk t h_mul' ↔ s ⊆ t := - Iff.rfl - -/-- Two subsemigroups are equal if they have the same elements. -/ -@[to_additive (attr := ext) "Two `AddSubsemigroup`s are equal if they have the same elements."] -theorem ext {S T : Subsemigroup M} (h : ∀ x, x ∈ S ↔ x ∈ T) : S = T := - SetLike.ext h - -/-- Copy a subsemigroup replacing `carrier` with a set that is equal to it. -/ -@[to_additive "Copy an additive subsemigroup replacing `carrier` with a set that is equal to it."] -protected def copy (S : Subsemigroup M) (s : Set M) (hs : s = S) : - Subsemigroup M where - carrier := s - mul_mem' := hs.symm ▸ S.mul_mem' - -variable {S : Subsemigroup M} - -@[to_additive (attr := simp)] -theorem coe_copy {s : Set M} (hs : s = S) : (S.copy s hs : Set M) = s := - rfl - -@[to_additive] -theorem copy_eq {s : Set M} (hs : s = S) : S.copy s hs = S := - SetLike.coe_injective hs - -variable (S) - -/-- A subsemigroup is closed under multiplication. -/ -@[to_additive "An `AddSubsemigroup` is closed under addition."] -protected theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := - Subsemigroup.mul_mem' S - -/-- The subsemigroup `M` of the magma `M`. -/ -@[to_additive "The additive subsemigroup `M` of the magma `M`."] -instance : Top (Subsemigroup M) := - ⟨{ carrier := Set.univ - mul_mem' := fun _ _ => Set.mem_univ _ }⟩ - -/-- The trivial subsemigroup `∅` of a magma `M`. -/ -@[to_additive "The trivial `AddSubsemigroup` `∅` of an additive magma `M`."] -instance : Bot (Subsemigroup M) := - ⟨{ carrier := ∅ - mul_mem' := False.elim }⟩ - -@[to_additive] -instance : Inhabited (Subsemigroup M) := - ⟨⊥⟩ - -@[to_additive] -theorem not_mem_bot {x : M} : x ∉ (⊥ : Subsemigroup M) := - Set.not_mem_empty x - -@[to_additive (attr := simp)] -theorem mem_top (x : M) : x ∈ (⊤ : Subsemigroup M) := - Set.mem_univ x - -@[to_additive (attr := simp)] -theorem coe_top : ((⊤ : Subsemigroup M) : Set M) = Set.univ := - rfl - -@[to_additive (attr := simp)] -theorem coe_bot : ((⊥ : Subsemigroup M) : Set M) = ∅ := - rfl - -/-- The inf of two subsemigroups is their intersection. -/ -@[to_additive "The inf of two `AddSubsemigroup`s is their intersection."] -instance : Inf (Subsemigroup M) := - ⟨fun S₁ S₂ => - { carrier := S₁ ∩ S₂ - mul_mem' := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ => ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ - -@[to_additive (attr := simp)] -theorem coe_inf (p p' : Subsemigroup M) : ((p ⊓ p' : Subsemigroup M) : Set M) = (p : Set M) ∩ p' := - rfl - -@[to_additive (attr := simp)] -theorem mem_inf {p p' : Subsemigroup M} {x : M} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := - Iff.rfl +variable (S : Subsemigroup M) @[to_additive] instance : InfSet (Subsemigroup M) := @@ -235,19 +95,6 @@ instance : CompleteLattice (Subsemigroup M) := inf_le_left := fun _ _ _ => And.left inf_le_right := fun _ _ _ => And.right } -@[to_additive] -theorem subsingleton_of_subsingleton [Subsingleton (Subsemigroup M)] : Subsingleton M := by - constructor; intro x y - have : ∀ a : M, a ∈ (⊥ : Subsemigroup M) := by simp [Subsingleton.elim (⊥ : Subsemigroup M) ⊤] - exact absurd (this x) not_mem_bot - -@[to_additive] -instance [hn : Nonempty M] : Nontrivial (Subsemigroup M) := - ⟨⟨⊥, ⊤, fun h => by - obtain ⟨x⟩ := id hn - refine absurd (?_ : x ∈ ⊥) not_mem_bot - simp [h]⟩⟩ - /-- The `Subsemigroup` generated by a set. -/ @[to_additive "The `AddSubsemigroup` generated by a set"] def closure (s : Set M) : Subsemigroup M := @@ -294,30 +141,31 @@ is preserved under multiplication, then `p` holds for all elements of the closur @[to_additive (attr := elab_as_elim) "An induction principle for additive closure membership. If `p` holds for all elements of `s`, and is preserved under addition, then `p` holds for all elements of the additive closure of `s`."] -theorem closure_induction {p : M → Prop} {x} (h : x ∈ closure s) (mem : ∀ x ∈ s, p x) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨p, mul _ _⟩).2 mem h - -/-- A dependent version of `Subsemigroup.closure_induction`. -/ -@[to_additive (attr := elab_as_elim) "A dependent version of `AddSubsemigroup.closure_induction`. "] -theorem closure_induction' (s : Set M) {p : ∀ x, x ∈ closure s → Prop} +theorem closure_induction {p : (x : M) → x ∈ closure s → Prop} (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) {x} (hx : x ∈ closure s) : - p x hx := by - refine Exists.elim ?_ fun (hx : x ∈ closure s) (hc : p x hx) => hc - exact - closure_induction hx (fun x hx => ⟨_, mem x hx⟩) fun x y ⟨hx', hx⟩ ⟨hy', hy⟩ => - ⟨_, mul _ _ _ _ hx hy⟩ + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) {x} (hx : x ∈ closure s) : + p x hx := + let S : Subsemigroup M := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ } + closure_le (S := S) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-09")] +alias closure_induction' := closure_induction /-- An induction principle for closure membership for predicates with two arguments. -/ @[to_additive (attr := elab_as_elim) "An induction principle for additive closure membership for predicates with two arguments."] -theorem closure_induction₂ {p : M → M → Prop} {x} {y : M} (hx : x ∈ closure s) (hy : y ∈ closure s) - (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (Hmul_left : ∀ x y z, p x z → p y z → p (x * y) z) - (Hmul_right : ∀ x y z, p z x → p z y → p z (x * y)) : p x y := - closure_induction hx - (fun x xs => closure_induction hy (Hs x xs) fun z _ h₁ h₂ => Hmul_right z _ _ h₁ h₂) - fun _ _ h₁ h₂ => Hmul_left _ _ _ h₁ h₂ +theorem closure_induction₂ {p : (x y : M) → x ∈ closure s → y ∈ closure s → Prop} + (mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p z x hz hx → p z y hz hy → p z (x * y) hz (mul_mem hx hy)) + {x y : M} (hx : x ∈ closure s) (hy : y ∈ closure s) : p x y hx hy := by + induction hx using closure_induction with + | mem z hz => induction hy using closure_induction with + | mem _ h => exact mem _ _ hz h + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ hy h₁ h₂ /-- If `s` is a dense set in a magma `M`, `Subsemigroup.closure s = ⊤`, then in order to prove that some predicate `p` holds for all `x : M` it suffices to verify `p x` for `x ∈ s`, @@ -326,11 +174,24 @@ and verify that `p x` and `p y` imply `p (x * y)`. -/ `AddSubsemigroup.closure s = ⊤`, then in order to prove that some predicate `p` holds for all `x : M` it suffices to verify `p x` for `x ∈ s`, and verify that `p x` and `p y` imply `p (x + y)`."] -theorem dense_induction {p : M → Prop} (x : M) {s : Set M} (hs : closure s = ⊤) - (mem : ∀ x ∈ s, p x) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := by - have : ∀ x ∈ closure s, p x := fun x hx => closure_induction hx mem mul - simpa [hs] using this x +theorem dense_induction {p : M → Prop} (s : Set M) (closure : closure s = ⊤) + (mem : ∀ x ∈ s, p x) (mul : ∀ x y, p x → p y → p (x * y)) (x : M) : + p x := by + induction closure.symm ▸ mem_top x using closure_induction with + | mem _ h => exact mem _ h + | mul _ _ _ _ h₁ h₂ => exact mul _ _ h₁ h₂ + +/- The argument `s : Set M` is explicit in `Subsemigroup.dense_induction` because the type of the +induction variable, namely `x : M`, does not reference `x`. Making `s` explicit allows the user +to apply the induction principle while deferring the proof of `closure s = ⊤` without creating +metavariables, as in the following example. -/ +example {p : M → Prop} (s : Set M) (closure : closure s = ⊤) + (mem : ∀ x ∈ s, p x) (mul : ∀ x y, p x → p y → p (x * y)) (x : M) : + p x := by + induction x using dense_induction s with + | closure => exact closure + | mem x hx => exact mem x hx + | mul _ _ h₁ h₂ => exact mul _ _ h₁ h₂ variable (M) @@ -385,12 +246,6 @@ variable [Mul N] open Subsemigroup -/-- The subsemigroup of elements `x : M` such that `f x = g x` -/ -@[to_additive "The additive subsemigroup of elements `x : M` such that `f x = g x`"] -def eqLocus (f g : M →ₙ* N) : Subsemigroup M where - carrier := { x | f x = g x } - mul_mem' (hx : _ = _) (hy : _ = _) := by simp [*] - /-- If two mul homomorphisms are equal on a set, then they are equal on its subsemigroup closure. -/ @[to_additive "If two add homomorphisms are equal on a set, then they are equal on its additive subsemigroup closure."] @@ -398,10 +253,6 @@ theorem eqOn_closure {f g : M →ₙ* N} {s : Set M} (h : Set.EqOn f g s) : Set.EqOn f g (closure s) := show closure s ≤ f.eqLocus g from closure_le.2 h -@[to_additive] -theorem eq_of_eqOn_top {f g : M →ₙ* N} (h : Set.EqOn f g (⊤ : Subsemigroup M)) : f = g := - ext fun _ => h trivial - @[to_additive] theorem eq_of_eqOn_dense {s : Set M} (hs : closure s = ⊤) {f g : M →ₙ* N} (h : s.EqOn f g) : f = g := @@ -426,8 +277,8 @@ def ofDense {M N} [Semigroup M] [Semigroup N] {s : Set M} (f : M → N) (hs : cl M →ₙ* N where toFun := f map_mul' x y := - dense_induction y hs (fun y hy x => hmul x y hy) - (fun y₁ y₂ h₁ h₂ x => by simp only [← mul_assoc, h₁, h₂]) x + dense_induction _ hs (fun y hy x => hmul x y hy) + (fun y₁ y₂ h₁ h₂ x => by simp only [← mul_assoc, h₁, h₂]) y x /-- Let `s` be a subset of an additive semigroup `M` such that the closure of `s` is the whole semigroup. Then `AddHom.ofDense` defines an additive homomorphism from `M` asking for a proof diff --git a/Mathlib/Algebra/Group/Subsemigroup/Defs.lean b/Mathlib/Algebra/Group/Subsemigroup/Defs.lean new file mode 100644 index 0000000000000..99b1585fb36fb --- /dev/null +++ b/Mathlib/Algebra/Group/Subsemigroup/Defs.lean @@ -0,0 +1,277 @@ +/- +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, Yakov Pechersky +-/ +import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.Algebra.Group.InjSurj +import Mathlib.Data.SetLike.Basic + +/-! +# Subsemigroups: definition + +This file defines bundled multiplicative and additive subsemigroups. + +## Main definitions + +* `Subsemigroup M`: the type of bundled subsemigroup of a magma `M`; the underlying set is given in + the `carrier` field of the structure, and should be accessed through coercion as in `(S : Set M)`. +* `AddSubsemigroup M` : the type of bundled subsemigroups of an additive magma `M`. + +For each of the following definitions in the `Subsemigroup` namespace, there is a corresponding +definition in the `AddSubsemigroup` namespace. + +* `Subsemigroup.copy` : copy of a subsemigroup with `carrier` replaced by a set that is equal but + possibly not definitionally equal to the carrier of the original `Subsemigroup`. + +Similarly, for each of these definitions in the `MulHom` namespace, there is a corresponding +definition in the `AddHom` namespace. + +* `MulHom.eqLocus f g`: the subsemigroup of those `x` such that `f x = g x` + +## Implementation notes + +Subsemigroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a subsemigroup's underlying set. + +Note that `Subsemigroup M` does not actually require `Semigroup M`, +instead requiring only the weaker `Mul M`. + +This file is designed to have very few dependencies. In particular, it should not use natural +numbers. + +## Tags +subsemigroup, subsemigroups +-/ + +assert_not_exists CompleteLattice +assert_not_exists MonoidWithZero + +variable {M : Type*} {N : Type*} + +section NonAssoc + +variable [Mul M] {s : Set M} + +/-- `MulMemClass S M` says `S` is a type of sets `s : Set M` that are closed under `(*)` -/ +class MulMemClass (S : Type*) (M : outParam Type*) [Mul M] [SetLike S M] : Prop where + /-- A substructure satisfying `MulMemClass` is closed under multiplication. -/ + mul_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a * b ∈ s + +export MulMemClass (mul_mem) + +/-- `AddMemClass S M` says `S` is a type of sets `s : Set M` that are closed under `(+)` -/ +class AddMemClass (S : Type*) (M : outParam Type*) [Add M] [SetLike S M] : Prop where + /-- A substructure satisfying `AddMemClass` is closed under addition. -/ + add_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a + b ∈ s + +export AddMemClass (add_mem) + +attribute [to_additive] MulMemClass + +attribute [aesop safe apply (rule_sets := [SetLike])] mul_mem add_mem + +/-- A subsemigroup of a magma `M` is a subset closed under multiplication. -/ +structure Subsemigroup (M : Type*) [Mul M] where + /-- The carrier of a subsemigroup. -/ + carrier : Set M + /-- The product of two elements of a subsemigroup belongs to the subsemigroup. -/ + mul_mem' {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier + +/-- An additive subsemigroup of an additive magma `M` is a subset closed under addition. -/ +structure AddSubsemigroup (M : Type*) [Add M] where + /-- The carrier of an additive subsemigroup. -/ + carrier : Set M + /-- The sum of two elements of an additive subsemigroup belongs to the subsemigroup. -/ + add_mem' {a b} : a ∈ carrier → b ∈ carrier → a + b ∈ carrier + +attribute [to_additive AddSubsemigroup] Subsemigroup + +namespace Subsemigroup + +@[to_additive] +instance : SetLike (Subsemigroup M) M := + ⟨Subsemigroup.carrier, fun p q h => by cases p; cases q; congr⟩ + +@[to_additive] +instance : MulMemClass (Subsemigroup M) M where mul_mem := fun {_ _ _} => Subsemigroup.mul_mem' _ + +initialize_simps_projections Subsemigroup (carrier → coe) +initialize_simps_projections AddSubsemigroup (carrier → coe) + +@[to_additive (attr := simp)] +theorem mem_carrier {s : Subsemigroup M} {x : M} : x ∈ s.carrier ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_mk {s : Set M} {x : M} (h_mul) : x ∈ mk s h_mul ↔ x ∈ s := + Iff.rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_set_mk (s : Set M) (h_mul) : (mk s h_mul : Set M) = s := + rfl + +@[to_additive (attr := simp)] +theorem mk_le_mk {s t : Set M} (h_mul) (h_mul') : mk s h_mul ≤ mk t h_mul' ↔ s ⊆ t := + Iff.rfl + +/-- Two subsemigroups are equal if they have the same elements. -/ +@[to_additive (attr := ext) "Two `AddSubsemigroup`s are equal if they have the same elements."] +theorem ext {S T : Subsemigroup M} (h : ∀ x, x ∈ S ↔ x ∈ T) : S = T := + SetLike.ext h + +/-- Copy a subsemigroup replacing `carrier` with a set that is equal to it. -/ +@[to_additive "Copy an additive subsemigroup replacing `carrier` with a set that is equal to it."] +protected def copy (S : Subsemigroup M) (s : Set M) (hs : s = S) : + Subsemigroup M where + carrier := s + mul_mem' := hs.symm ▸ S.mul_mem' + +variable {S : Subsemigroup M} + +@[to_additive (attr := simp)] +theorem coe_copy {s : Set M} (hs : s = S) : (S.copy s hs : Set M) = s := + rfl + +@[to_additive] +theorem copy_eq {s : Set M} (hs : s = S) : S.copy s hs = S := + SetLike.coe_injective hs + +variable (S) + +/-- A subsemigroup is closed under multiplication. -/ +@[to_additive "An `AddSubsemigroup` is closed under addition."] +protected theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := + Subsemigroup.mul_mem' S + +/-- The subsemigroup `M` of the magma `M`. -/ +@[to_additive "The additive subsemigroup `M` of the magma `M`."] +instance : Top (Subsemigroup M) := + ⟨{ carrier := Set.univ + mul_mem' := fun _ _ => Set.mem_univ _ }⟩ + +/-- The trivial subsemigroup `∅` of a magma `M`. -/ +@[to_additive "The trivial `AddSubsemigroup` `∅` of an additive magma `M`."] +instance : Bot (Subsemigroup M) := + ⟨{ carrier := ∅ + mul_mem' := False.elim }⟩ + +@[to_additive] +instance : Inhabited (Subsemigroup M) := + ⟨⊥⟩ + +@[to_additive] +theorem not_mem_bot {x : M} : x ∉ (⊥ : Subsemigroup M) := + Set.not_mem_empty x + +@[to_additive (attr := simp)] +theorem mem_top (x : M) : x ∈ (⊤ : Subsemigroup M) := + Set.mem_univ x + +@[to_additive (attr := simp)] +theorem coe_top : ((⊤ : Subsemigroup M) : Set M) = Set.univ := + rfl + +@[to_additive (attr := simp)] +theorem coe_bot : ((⊥ : Subsemigroup M) : Set M) = ∅ := + rfl + +/-- The inf of two subsemigroups is their intersection. -/ +@[to_additive "The inf of two `AddSubsemigroup`s is their intersection."] +instance : Inf (Subsemigroup M) := + ⟨fun S₁ S₂ => + { carrier := S₁ ∩ S₂ + mul_mem' := fun ⟨hx, hx'⟩ ⟨hy, hy'⟩ => ⟨S₁.mul_mem hx hy, S₂.mul_mem hx' hy'⟩ }⟩ + +@[to_additive (attr := simp)] +theorem coe_inf (p p' : Subsemigroup M) : ((p ⊓ p' : Subsemigroup M) : Set M) = (p : Set M) ∩ p' := + rfl + +@[to_additive (attr := simp)] +theorem mem_inf {p p' : Subsemigroup M} {x : M} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := + Iff.rfl + +@[to_additive] +theorem subsingleton_of_subsingleton [Subsingleton (Subsemigroup M)] : Subsingleton M := by + constructor; intro x y + have : ∀ a : M, a ∈ (⊥ : Subsemigroup M) := by simp [Subsingleton.elim (⊥ : Subsemigroup M) ⊤] + exact absurd (this x) not_mem_bot + +@[to_additive] +instance [hn : Nonempty M] : Nontrivial (Subsemigroup M) := + ⟨⟨⊥, ⊤, fun h => by + obtain ⟨x⟩ := id hn + refine absurd (?_ : x ∈ ⊥) not_mem_bot + simp [h]⟩⟩ + +end Subsemigroup + +namespace MulHom + +variable [Mul N] + +open Subsemigroup + +/-- The subsemigroup of elements `x : M` such that `f x = g x` -/ +@[to_additive "The additive subsemigroup of elements `x : M` such that `f x = g x`"] +def eqLocus (f g : M →ₙ* N) : Subsemigroup M where + carrier := { x | f x = g x } + mul_mem' (hx : _ = _) (hy : _ = _) := by simp [*] + +@[to_additive] +theorem eq_of_eqOn_top {f g : M →ₙ* N} (h : Set.EqOn f g (⊤ : Subsemigroup M)) : f = g := + ext fun _ => h trivial + +end MulHom + +end NonAssoc + +namespace MulMemClass + +variable {A : Type*} [Mul M] [SetLike A M] [hA : MulMemClass A M] (S' : A) + +-- lower priority so other instances are found first +/-- A submagma of a magma inherits a multiplication. -/ +@[to_additive "An additive submagma of an additive magma inherits an addition."] +instance (priority := 900) mul : Mul S' := + ⟨fun a b => ⟨a.1 * b.1, mul_mem a.2 b.2⟩⟩ + +-- lower priority so later simp lemmas are used first; to appease simp_nf +@[to_additive (attr := simp low, norm_cast)] +theorem coe_mul (x y : S') : (↑(x * y) : M) = ↑x * ↑y := + rfl + +-- lower priority so later simp lemmas are used first; to appease simp_nf +@[to_additive (attr := simp low)] +theorem mk_mul_mk (x y : M) (hx : x ∈ S') (hy : y ∈ S') : + (⟨x, hx⟩ : S') * ⟨y, hy⟩ = ⟨x * y, mul_mem hx hy⟩ := + rfl + +@[to_additive] +theorem mul_def (x y : S') : x * y = ⟨x * y, mul_mem x.2 y.2⟩ := + rfl + +/-- A subsemigroup of a semigroup inherits a semigroup structure. -/ +@[to_additive "An `AddSubsemigroup` of an `AddSemigroup` inherits an `AddSemigroup` structure."] +instance toSemigroup {M : Type*} [Semigroup M] {A : Type*} [SetLike A M] [MulMemClass A M] + (S : A) : Semigroup S := + Subtype.coe_injective.semigroup Subtype.val fun _ _ => rfl + +/-- A subsemigroup of a `CommSemigroup` is a `CommSemigroup`. -/ +@[to_additive "An `AddSubsemigroup` of an `AddCommSemigroup` is an `AddCommSemigroup`."] +instance toCommSemigroup {M} [CommSemigroup M] {A : Type*} [SetLike A M] [MulMemClass A M] + (S : A) : CommSemigroup S := + Subtype.coe_injective.commSemigroup Subtype.val fun _ _ => rfl + +/-- The natural semigroup hom from a subsemigroup of semigroup `M` to `M`. -/ +@[to_additive "The natural semigroup hom from an `AddSubsemigroup` of +`AddSubsemigroup` `M` to `M`."] +def subtype : S' →ₙ* M where + toFun := Subtype.val; map_mul' := fun _ _ => rfl + +@[to_additive (attr := simp)] +theorem coe_subtype : (MulMemClass.subtype S' : S' → M) = Subtype.val := + rfl + +end MulMemClass diff --git a/Mathlib/Algebra/Group/Subsemigroup/Membership.lean b/Mathlib/Algebra/Group/Subsemigroup/Membership.lean index 0dd74bcae6654..c00916259db08 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Membership.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Membership.lean @@ -47,8 +47,8 @@ theorem mem_iSup_of_directed {S : ι → Subsemigroup M} (hS : Directed (· ≤ refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup S i hi⟩ suffices x ∈ closure (⋃ i, (S i : Set M)) → ∃ i, x ∈ S i by simpa only [closure_iUnion, closure_eq (S _)] using this - refine fun hx ↦ closure_induction hx (fun y hy ↦ mem_iUnion.mp hy) ?_ - rintro x y ⟨i, hi⟩ ⟨j, hj⟩ + refine fun hx ↦ closure_induction (fun y hy ↦ mem_iUnion.mp hy) ?_ hx + rintro x y - - ⟨i, hi⟩ ⟨j, hj⟩ rcases hS i j with ⟨k, hki, hkj⟩ exact ⟨k, (S k).mul_mem (hki hi) (hkj hj)⟩ @@ -103,7 +103,7 @@ the supremum of `S`."] theorem iSup_induction (S : ι → Subsemigroup M) {C : M → Prop} {x₁ : M} (hx₁ : x₁ ∈ ⨆ i, S i) (mem : ∀ i, ∀ x₂ ∈ S i, C x₂) (mul : ∀ x y, C x → C y → C (x * y)) : C x₁ := by rw [iSup_eq_closure] at hx₁ - refine closure_induction hx₁ (fun x₂ hx₂ => ?_) mul + refine closure_induction (fun x₂ hx₂ => ?_) (fun x y _ _ ↦ mul x y) hx₁ obtain ⟨i, hi⟩ := Set.mem_iUnion.mp hx₂ exact mem _ _ hi diff --git a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean index 85f523619d7ca..5f2d5a377ff34 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean @@ -417,55 +417,6 @@ end GaloisInsertion end Subsemigroup -namespace MulMemClass - -variable {A : Type*} [Mul M] [SetLike A M] [hA : MulMemClass A M] (S' : A) - --- lower priority so other instances are found first -/-- A submagma of a magma inherits a multiplication. -/ -@[to_additive "An additive submagma of an additive magma inherits an addition."] -instance (priority := 900) mul : Mul S' := - ⟨fun a b => ⟨a.1 * b.1, mul_mem a.2 b.2⟩⟩ - --- lower priority so later simp lemmas are used first; to appease simp_nf -@[to_additive (attr := simp low, norm_cast)] -theorem coe_mul (x y : S') : (↑(x * y) : M) = ↑x * ↑y := - rfl - --- lower priority so later simp lemmas are used first; to appease simp_nf -@[to_additive (attr := simp low)] -theorem mk_mul_mk (x y : M) (hx : x ∈ S') (hy : y ∈ S') : - (⟨x, hx⟩ : S') * ⟨y, hy⟩ = ⟨x * y, mul_mem hx hy⟩ := - rfl - -@[to_additive] -theorem mul_def (x y : S') : x * y = ⟨x * y, mul_mem x.2 y.2⟩ := - rfl - -/-- A subsemigroup of a semigroup inherits a semigroup structure. -/ -@[to_additive "An `AddSubsemigroup` of an `AddSemigroup` inherits an `AddSemigroup` structure."] -instance toSemigroup {M : Type*} [Semigroup M] {A : Type*} [SetLike A M] [MulMemClass A M] - (S : A) : Semigroup S := - Subtype.coe_injective.semigroup Subtype.val fun _ _ => rfl - -/-- A subsemigroup of a `CommSemigroup` is a `CommSemigroup`. -/ -@[to_additive "An `AddSubsemigroup` of an `AddCommSemigroup` is an `AddCommSemigroup`."] -instance toCommSemigroup {M} [CommSemigroup M] {A : Type*} [SetLike A M] [MulMemClass A M] - (S : A) : CommSemigroup S := - Subtype.coe_injective.commSemigroup Subtype.val fun _ _ => rfl - -/-- The natural semigroup hom from a subsemigroup of semigroup `M` to `M`. -/ -@[to_additive "The natural semigroup hom from an `AddSubsemigroup` of -`AddSubsemigroup` `M` to `M`."] -def subtype : S' →ₙ* M where - toFun := Subtype.val; map_mul' := fun _ _ => rfl - -@[to_additive (attr := simp)] -theorem coe_subtype : (MulMemClass.subtype S' : S' → M) = Subtype.val := - rfl - -end MulMemClass - namespace Subsemigroup variable [Mul M] [Mul N] [Mul P] (S : Subsemigroup M) @@ -498,10 +449,8 @@ theorem coe_equivMapOfInjective_apply (f : M →ₙ* N) (hf : Function.Injective @[to_additive (attr := simp)] theorem closure_closure_coe_preimage {s : Set M} : closure ((Subtype.val : closure s → M) ⁻¹' s) = ⊤ := - eq_top_iff.2 fun x => - Subtype.recOn x fun _ hx' _ => closure_induction' - (p := fun y hy ↦ (⟨y, hy⟩ : closure s) ∈ closure (((↑) : closure s → M) ⁻¹' s)) - _ (fun _ hg => subset_closure hg) (fun _ _ _ _ => Subsemigroup.mul_mem _) hx' + eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ + closure_induction (fun _ h ↦ subset_closure h) (fun _ _ _ _ ↦ mul_mem) hx' /-- Given `Subsemigroup`s `s`, `t` of semigroups `M`, `N` respectively, `s × t` as a subsemigroup of `M × N`. -/ diff --git a/Mathlib/Algebra/Group/UniqueProds/Basic.lean b/Mathlib/Algebra/Group/UniqueProds/Basic.lean index 99d252eee8364..78c9df91994a4 100644 --- a/Mathlib/Algebra/Group/UniqueProds/Basic.lean +++ b/Mathlib/Algebra/Group/UniqueProds/Basic.lean @@ -52,6 +52,8 @@ assert_not_exists Algebra assert_not_exists Submodule assert_not_exists StarModule +open Finset + /-- Let `G` be a Type with multiplication, let `A B : Finset G` be finite subsets and let `a0 b0 : G` be two elements. `UniqueMul A B a0 b0` asserts `a0 * b0` can be written in at most one way as a product of an element of `A` and an element of `B`. -/ @@ -71,7 +73,7 @@ theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by simp [UniqueMul, eq_iff_true_of_subsingleton] @[to_additive of_card_le_one] -theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : A.card ≤ 1) (hB1 : B.card ≤ 1) : +theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : #A ≤ 1) (hB1 : #B ≤ 1) : ∃ a ∈ A, ∃ b ∈ B, UniqueMul A B a b := by rw [Finset.card_le_one_iff] at hA1 hB1 obtain ⟨a, ha⟩ := hA; obtain ⟨b, hb⟩ := hB @@ -118,7 +120,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) : open Finset in @[to_additive iff_card_le_one] theorem iff_card_le_one [DecidableEq G] (ha0 : a0 ∈ A) (hb0 : b0 ∈ B) : - UniqueMul A B a0 b0 ↔ ((A ×ˢ B).filter (fun p ↦ p.1 * p.2 = a0 * b0)).card ≤ 1 := by + UniqueMul A B a0 b0 ↔ #{p ∈ A ×ˢ B | p.1 * p.2 = a0 * b0} ≤ 1 := by simp_rw [card_le_one_iff, mem_filter, mem_product] refine ⟨fun h p1 p2 ⟨⟨ha1, hb1⟩, he1⟩ ⟨⟨ha2, hb2⟩, he2⟩ ↦ ?_, fun h a b ha hb he ↦ ?_⟩ · have h1 := h ha1 hb1 he1; have h2 := h ha2 hb2 he2 @@ -136,7 +138,7 @@ alias _root_.UniqueAdd.iff_card_nonpos := UniqueAdd.iff_card_le_one theorem exists_iff_exists_existsUnique : (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔ ∃ g : G, ∃! ab, ab ∈ A ×ˢ B ∧ ab.1 * ab.2 = g := - ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by + ⟨fun ⟨_, _, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by have h' := h rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩ cases' Finset.mem_product.mp hab with ha hb @@ -210,7 +212,7 @@ open Finset in theorem of_image_filter [DecidableEq H] (f : G →ₙ* H) {A B : Finset G} {aG bG : G} {aH bH : H} (hae : f aG = aH) (hbe : f bG = bH) (huH : UniqueMul (A.image f) (B.image f) aH bH) - (huG : UniqueMul (A.filter (f · = aH)) (B.filter (f · = bH)) aG bG) : + (huG : UniqueMul {a ∈ A | f a = aH} {b ∈ B | f b = bH} aG bG) : UniqueMul A B aG bG := fun a b ha hb he ↦ by specialize huH (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) rw [← map_mul, he, map_mul, hae, hbe] at huH @@ -245,7 +247,7 @@ of elements satisfying the `UniqueAdd` property. -/ class TwoUniqueSums (G) [Add G] : Prop where /-- For `A B` two finite sets whose product has cardinality at least 2, we can find at least two unique pairs. -/ - uniqueAdd_of_one_lt_card : ∀ {A B : Finset G}, 1 < A.card * B.card → + uniqueAdd_of_one_lt_card : ∀ {A B : Finset G}, 1 < #A * #B → ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueAdd A B p1.1 p1.2 ∧ UniqueAdd A B p2.1 p2.2 /-- Let `G` be a Type with multiplication. `TwoUniqueProds G` asserts that any two non-empty @@ -254,16 +256,16 @@ of elements satisfying the `UniqueMul` property. -/ class TwoUniqueProds (G) [Mul G] : Prop where /-- For `A B` two finite sets whose product has cardinality at least 2, we can find at least two unique pairs. -/ - uniqueMul_of_one_lt_card : ∀ {A B : Finset G}, 1 < A.card * B.card → + uniqueMul_of_one_lt_card : ∀ {A B : Finset G}, 1 < #A * #B → ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueMul A B p1.1 p1.2 ∧ UniqueMul A B p2.1 p2.2 attribute [to_additive] TwoUniqueProds @[to_additive] -lemma uniqueMul_of_twoUniqueMul {G} [Mul G] {A B : Finset G} (h : 1 < A.card * B.card → +lemma uniqueMul_of_twoUniqueMul {G} [Mul G] {A B : Finset G} (h : 1 < #A * #B → ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueMul A B p1.1 p1.2 ∧ UniqueMul A B p2.1 p2.2) (hA : A.Nonempty) (hB : B.Nonempty) : ∃ a ∈ A, ∃ b ∈ B, UniqueMul A B a b := by - by_cases hc : A.card ≤ 1 ∧ B.card ≤ 1 + by_cases hc : #A ≤ 1 ∧ #B ≤ 1 · exact UniqueMul.of_card_le_one hA hB hc.1 hc.2 simp_rw [not_and_or, not_le] at hc rw [← Finset.card_pos] at hA hB @@ -388,7 +390,7 @@ open MulOpposite in obtain ⟨a, ha, b, hb, hu⟩ := uniqueMul_of_nonempty hc.1 hc.2.1 let C := A.map ⟨_, mul_right_injective a⁻¹⟩ -- C = a⁻¹A let D := B.map ⟨_, mul_left_injective b⁻¹⟩ -- D = Bb⁻¹ - have hcard : 1 < C.card ∨ 1 < D.card := by simp_rw [C, D, card_map]; exact hc.2.2 + have hcard : 1 < #C ∨ 1 < #D := by simp_rw [C, D, card_map]; exact hc.2.2 have hC : 1 ∈ C := mem_map.mpr ⟨a, ha, inv_mul_cancel a⟩ have hD : 1 ∈ D := mem_map.mpr ⟨b, hb, mul_inv_cancel b⟩ suffices ∃ c ∈ C, ∃ d ∈ D, (c ≠ 1 ∨ d ≠ 1) ∧ UniqueMul C D c d by @@ -439,13 +441,13 @@ open UniqueMul in let _ := isWellFounded_ssubset (α := ∀ i, G i) -- why need this? apply IsWellFounded.induction (· ⊂ ·) A; intro A ihA B hA apply IsWellFounded.induction (· ⊂ ·) B; intro B ihB hB - by_cases hc : A.card ≤ 1 ∧ B.card ≤ 1 + by_cases hc : #A ≤ 1 ∧ #B ≤ 1 · exact of_card_le_one hA hB hc.1 hc.2 simp_rw [not_and_or, not_le] at hc obtain ⟨i, hc⟩ := exists_or.mpr (hc.imp exists_of_one_lt_card_pi exists_of_one_lt_card_pi) obtain ⟨ai, hA, bi, hB, hi⟩ := uniqueMul_of_nonempty (hA.image (· i)) (hB.image (· i)) rw [mem_image, ← filter_nonempty_iff] at hA hB - let A' := A.filter (· i = ai); let B' := B.filter (· i = bi) + let A' := {a ∈ A | a i = ai}; let B' := {b ∈ B | b i = bi} obtain ⟨a0, ha0, b0, hb0, hu⟩ : ∃ a0 ∈ A', ∃ b0 ∈ B', UniqueMul A' B' a0 b0 := by rcases hc with hc | hc; · exact ihA A' (hc.2 ai) hA hB by_cases hA' : A' = A @@ -484,7 +486,7 @@ open Finset [TwoUniqueProds G] : TwoUniqueProds H where uniqueMul_of_one_lt_card {A B} hc := by classical - obtain hc' | hc' := lt_or_le 1 ((A.image f).card * (B.image f).card) + obtain hc' | hc' := lt_or_le 1 (#(A.image f) * #(B.image f)) · obtain ⟨⟨a1, b1⟩, h1, ⟨a2, b2⟩, h2, hne, hu1, hu2⟩ := uniqueMul_of_one_lt_card hc' simp_rw [mem_product, mem_image] at h1 h2 ⊢ obtain ⟨⟨a1, ha1, rfl⟩, b1, hb1, rfl⟩ := h1 @@ -536,11 +538,11 @@ instance instForall {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUnique contrapose! hne; rw [Prod.mk.inj_iff] at hne ⊢ rw [← ha1.2, ← hb1.2, ← ha2.2, ← hb2.2, hne.1, hne.2]; exact ⟨rfl, rfl⟩ all_goals rcases hc with hc | hc; · exact ihA _ (hc.2 _) - · by_cases hA : A.filter (· i = p2.1) = A + · by_cases hA : {a ∈ A | a i = p2.1} = A · rw [hA] exact ihB _ (hc.2 _) · exact ihA _ ((A.filter_subset _).ssubset_of_ne hA) - · by_cases hA : A.filter (· i = p1.1) = A + · by_cases hA : {a ∈ A | a i = p1.1} = A · rw [hA] exact ihB _ (hc.2 _) · exact ihA _ ((A.filter_subset _).ssubset_of_ne hA) @@ -579,7 +581,7 @@ theorem of_mulOpposite (h : TwoUniqueProds Gᵐᵒᵖ) : TwoUniqueProds G where "This instance asserts that if `G` has a right-cancellative addition, a linear order, and addition is strictly monotone w.r.t. the second argument, then `G` has `TwoUniqueSums`." ] instance (priority := 100) of_covariant_right [IsRightCancelMul G] - [LinearOrder G] [CovariantClass G G (· * ·) (· < ·)] : + [LinearOrder G] [MulLeftStrictMono G] : TwoUniqueProds G where uniqueMul_of_one_lt_card {A B} hc := by obtain ⟨hA, hB, -⟩ := Nat.one_lt_mul_iff.mp hc @@ -613,10 +615,10 @@ open MulOpposite in "This instance asserts that if `G` has a left-cancellative addition, a linear order, and addition is strictly monotone w.r.t. the first argument, then `G` has `TwoUniqueSums`." ] instance (priority := 100) of_covariant_left [IsLeftCancelMul G] - [LinearOrder G] [CovariantClass G G (Function.swap (· * ·)) (· < ·)] : + [LinearOrder G] [MulRightStrictMono G] : TwoUniqueProds G := let _ := LinearOrder.lift' (unop : Gᵐᵒᵖ → G) unop_injective - let _ : CovariantClass Gᵐᵒᵖ Gᵐᵒᵖ (· * ·) (· < ·) := + let _ : MulLeftStrictMono Gᵐᵒᵖ := { elim := fun _ _ _ bc ↦ mul_lt_mul_right' (α := G) bc (unop _) } of_mulOpposite of_covariant_right diff --git a/Mathlib/Algebra/Group/Units/Basic.lean b/Mathlib/Algebra/Group/Units/Basic.lean new file mode 100644 index 0000000000000..3630673d90f59 --- /dev/null +++ b/Mathlib/Algebra/Group/Units/Basic.lean @@ -0,0 +1,478 @@ +/- +Copyright (c) 2017 Kenny Lau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kenny Lau, Mario Carneiro, Johannes Hölzl, Chris Hughes, Jens Wagemaker, Jon Eugster +-/ +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Group.Commute.Defs +import Mathlib.Algebra.Group.Units.Defs +import Mathlib.Logic.Unique +import Mathlib.Tactic.Nontriviality +import Mathlib.Tactic.Lift +import Mathlib.Tactic.Subsingleton + +/-! +# Units (i.e., invertible elements) of a monoid + +An element of a `Monoid` is a unit if it has a two-sided inverse. +This file contains the basic lemmas on units in a monoid, especially focussing on singleton types +and unique types. + +## TODO + +The results here should be used to golf the basic `Group` lemmas. +-/ + +assert_not_exists Multiplicative +assert_not_exists MonoidWithZero +assert_not_exists DenselyOrdered + +open Function + +universe u + +variable {α : Type u} + +section HasElem + +@[to_additive] +theorem unique_one {α : Type*} [Unique α] [One α] : default = (1 : α) := + Unique.default_eq 1 + +end HasElem + +namespace Units +section Monoid +variable [Monoid α] + +variable (b c : αˣ) {u : αˣ} + +@[to_additive (attr := simp)] +theorem mul_inv_cancel_right (a : α) (b : αˣ) : a * b * ↑b⁻¹ = a := by + rw [mul_assoc, mul_inv, mul_one] + +@[to_additive (attr := simp)] +theorem inv_mul_cancel_right (a : α) (b : αˣ) : a * ↑b⁻¹ * b = a := by + rw [mul_assoc, inv_mul, mul_one] + +@[to_additive (attr := simp)] +theorem mul_right_inj (a : αˣ) {b c : α} : (a : α) * b = a * c ↔ b = c := + ⟨fun h => by simpa only [inv_mul_cancel_left] using congr_arg (fun x : α => ↑(a⁻¹ : αˣ) * x) h, + congr_arg _⟩ + +@[to_additive (attr := simp)] +theorem mul_left_inj (a : αˣ) {b c : α} : b * a = c * a ↔ b = c := + ⟨fun h => by simpa only [mul_inv_cancel_right] using congr_arg (fun x : α => x * ↑(a⁻¹ : αˣ)) h, + congr_arg (· * a.val)⟩ + +@[to_additive] +theorem eq_mul_inv_iff_mul_eq {a b : α} : a = b * ↑c⁻¹ ↔ a * c = b := + ⟨fun h => by rw [h, inv_mul_cancel_right], fun h => by rw [← h, mul_inv_cancel_right]⟩ + +@[to_additive] +theorem eq_inv_mul_iff_mul_eq {a c : α} : a = ↑b⁻¹ * c ↔ ↑b * a = c := + ⟨fun h => by rw [h, mul_inv_cancel_left], fun h => by rw [← h, inv_mul_cancel_left]⟩ + +@[to_additive] +theorem mul_inv_eq_iff_eq_mul {a c : α} : a * ↑b⁻¹ = c ↔ a = c * b := + ⟨fun h => by rw [← h, inv_mul_cancel_right], fun h => by rw [h, mul_inv_cancel_right]⟩ + +-- Porting note: have to explicitly type annotate the 1 +@[to_additive] +protected theorem inv_eq_of_mul_eq_one_left {a : α} (h : a * u = 1) : ↑u⁻¹ = a := + calc + ↑u⁻¹ = (1 : α) * ↑u⁻¹ := by rw [one_mul] + _ = a := by rw [← h, mul_inv_cancel_right] + + +-- Porting note: have to explicitly type annotate the 1 +@[to_additive] +protected theorem inv_eq_of_mul_eq_one_right {a : α} (h : ↑u * a = 1) : ↑u⁻¹ = a := + calc + ↑u⁻¹ = ↑u⁻¹ * (1 : α) := by rw [mul_one] + _ = a := by rw [← h, inv_mul_cancel_left] + + +@[to_additive] +protected theorem eq_inv_of_mul_eq_one_left {a : α} (h : ↑u * a = 1) : a = ↑u⁻¹ := + (Units.inv_eq_of_mul_eq_one_right h).symm + +@[to_additive] +protected theorem eq_inv_of_mul_eq_one_right {a : α} (h : a * u = 1) : a = ↑u⁻¹ := + (Units.inv_eq_of_mul_eq_one_left h).symm + +@[to_additive (attr := simp)] +theorem mul_inv_eq_one {a : α} : a * ↑u⁻¹ = 1 ↔ a = u := + ⟨inv_inv u ▸ Units.eq_inv_of_mul_eq_one_right, fun h => mul_inv_of_eq h.symm⟩ + +@[to_additive (attr := simp)] +theorem inv_mul_eq_one {a : α} : ↑u⁻¹ * a = 1 ↔ ↑u = a := + ⟨inv_inv u ▸ Units.inv_eq_of_mul_eq_one_right, inv_mul_of_eq⟩ + +@[to_additive] +theorem mul_eq_one_iff_eq_inv {a : α} : a * u = 1 ↔ a = ↑u⁻¹ := by rw [← mul_inv_eq_one, inv_inv] + +@[to_additive] +theorem mul_eq_one_iff_inv_eq {a : α} : ↑u * a = 1 ↔ ↑u⁻¹ = a := by rw [← inv_mul_eq_one, inv_inv] + +@[to_additive] +theorem inv_unique {u₁ u₂ : αˣ} (h : (↑u₁ : α) = ↑u₂) : (↑u₁⁻¹ : α) = ↑u₂⁻¹ := + Units.inv_eq_of_mul_eq_one_right <| by rw [h, u₂.mul_inv] + +end Monoid + +end Units + +section Monoid + +variable [Monoid α] + +@[simp] +theorem divp_left_inj (u : αˣ) {a b : α} : a /ₚ u = b /ₚ u ↔ a = b := + Units.mul_left_inj _ + +/- Porting note: to match the mathlib3 behavior, this needs to have higher simp +priority than eq_divp_iff_mul_eq. -/ +@[field_simps 1010] +theorem divp_eq_iff_mul_eq {x : α} {u : αˣ} {y : α} : x /ₚ u = y ↔ y * u = x := + u.mul_left_inj.symm.trans <| by rw [divp_mul_cancel]; exact ⟨Eq.symm, Eq.symm⟩ + +@[field_simps] +theorem eq_divp_iff_mul_eq {x : α} {u : αˣ} {y : α} : x = y /ₚ u ↔ x * u = y := by + rw [eq_comm, divp_eq_iff_mul_eq] + +theorem divp_eq_one_iff_eq {a : α} {u : αˣ} : a /ₚ u = 1 ↔ a = u := + (Units.mul_left_inj u).symm.trans <| by rw [divp_mul_cancel, one_mul] + +/-- Used for `field_simp` to deal with inverses of units. This form of the lemma +is essential since `field_simp` likes to use `inv_eq_one_div` to rewrite +`↑u⁻¹ = ↑(1 / u)`. +-/ +@[field_simps] +theorem inv_eq_one_divp' (u : αˣ) : ((1 / u : αˣ) : α) = 1 /ₚ u := by + rw [one_div, one_divp] + +end Monoid + +namespace LeftCancelMonoid + +variable [LeftCancelMonoid α] [Subsingleton αˣ] {a b : α} + +@[to_additive] +protected theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := + congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by + rw [← mul_left_cancel_iff (a := a), ← mul_assoc, h, one_mul, mul_one]) h) 1 + +@[to_additive] +protected theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := by + rwa [LeftCancelMonoid.eq_one_of_mul_right h, one_mul] at h + +@[to_additive (attr := simp)] +protected theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := + ⟨fun h => ⟨LeftCancelMonoid.eq_one_of_mul_right h, LeftCancelMonoid.eq_one_of_mul_left h⟩, by + rintro ⟨rfl, rfl⟩ + exact mul_one _⟩ + +@[to_additive] +protected theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp + +end LeftCancelMonoid + +namespace RightCancelMonoid + +variable [RightCancelMonoid α] [Subsingleton αˣ] {a b : α} + +@[to_additive] +protected theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := + congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by + rw [← mul_right_cancel_iff (a := b), mul_assoc, h, one_mul, mul_one]) h) 1 + +@[to_additive] +protected theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := by + rwa [RightCancelMonoid.eq_one_of_mul_right h, one_mul] at h + +@[to_additive (attr := simp)] +protected theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := + ⟨fun h => ⟨RightCancelMonoid.eq_one_of_mul_right h, RightCancelMonoid.eq_one_of_mul_left h⟩, by + rintro ⟨rfl, rfl⟩ + exact mul_one _⟩ + +@[to_additive] +protected theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp + +end RightCancelMonoid + +section CancelMonoid + +variable [CancelMonoid α] [Subsingleton αˣ] {a b : α} + +@[to_additive] +theorem eq_one_of_mul_right' (h : a * b = 1) : a = 1 := LeftCancelMonoid.eq_one_of_mul_right h + +@[to_additive] +theorem eq_one_of_mul_left' (h : a * b = 1) : b = 1 := LeftCancelMonoid.eq_one_of_mul_left h + +@[to_additive] +theorem mul_eq_one' : a * b = 1 ↔ a = 1 ∧ b = 1 := LeftCancelMonoid.mul_eq_one + +@[to_additive] +theorem mul_ne_one' : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := LeftCancelMonoid.mul_ne_one + +end CancelMonoid + +section CommMonoid + +variable [CommMonoid α] + +@[field_simps] +theorem divp_mul_eq_mul_divp (x y : α) (u : αˣ) : x /ₚ u * y = x * y /ₚ u := by + rw [divp, divp, mul_right_comm] + +-- Theoretically redundant as `field_simp` lemma. +@[field_simps] +theorem divp_eq_divp_iff {x y : α} {ux uy : αˣ} : x /ₚ ux = y /ₚ uy ↔ x * uy = y * ux := by + rw [divp_eq_iff_mul_eq, divp_mul_eq_mul_divp, divp_eq_iff_mul_eq] + +-- Theoretically redundant as `field_simp` lemma. +@[field_simps] +theorem divp_mul_divp (x y : α) (ux uy : αˣ) : x /ₚ ux * (y /ₚ uy) = x * y /ₚ (ux * uy) := by + rw [divp_mul_eq_mul_divp, divp_assoc', divp_divp_eq_divp_mul] + +variable [Subsingleton αˣ] {a b : α} + +@[to_additive] +theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := + congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by rwa [mul_comm]) h) 1 + +@[to_additive] +theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := + congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ h <| by rwa [mul_comm]) 1 + +@[to_additive (attr := simp)] +theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := + ⟨fun h => ⟨eq_one_of_mul_right h, eq_one_of_mul_left h⟩, by + rintro ⟨rfl, rfl⟩ + exact mul_one _⟩ + +@[to_additive] theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp + +end CommMonoid + +/-! +# `IsUnit` predicate +-/ + + +section IsUnit + +variable {M : Type*} + +@[to_additive (attr := nontriviality)] +theorem isUnit_of_subsingleton [Monoid M] [Subsingleton M] (a : M) : IsUnit a := + ⟨⟨a, a, by subsingleton, by subsingleton⟩, rfl⟩ + +@[to_additive] +instance [Monoid M] : CanLift M Mˣ Units.val IsUnit := + { prf := fun _ ↦ id } + +/-- A subsingleton `Monoid` has a unique unit. -/ +@[to_additive "A subsingleton `AddMonoid` has a unique additive unit."] +instance [Monoid M] [Subsingleton M] : Unique Mˣ where + uniq _ := Units.val_eq_one.mp (by subsingleton) + +section Monoid +variable [Monoid M] + +theorem units_eq_one [Subsingleton Mˣ] (u : Mˣ) : u = 1 := by subsingleton + +end Monoid + +namespace IsUnit + +section Monoid + +variable [Monoid M] {a b c : M} + +@[to_additive] +theorem mul_left_inj (h : IsUnit a) : b * a = c * a ↔ b = c := + let ⟨u, hu⟩ := h + hu ▸ u.mul_left_inj + +@[to_additive] +theorem mul_right_inj (h : IsUnit a) : a * b = a * c ↔ b = c := + let ⟨u, hu⟩ := h + hu ▸ u.mul_right_inj + +@[to_additive] +protected theorem mul_left_cancel (h : IsUnit a) : a * b = a * c → b = c := + h.mul_right_inj.1 + +@[to_additive] +protected theorem mul_right_cancel (h : IsUnit b) : a * b = c * b → a = c := + h.mul_left_inj.1 + +@[to_additive] +protected theorem mul_right_injective (h : IsUnit a) : Injective (a * ·) := + fun _ _ => h.mul_left_cancel + +@[to_additive] +protected theorem mul_left_injective (h : IsUnit b) : Injective (· * b) := + fun _ _ => h.mul_right_cancel + +@[to_additive] +theorem isUnit_iff_mulLeft_bijective {a : M} : + IsUnit a ↔ Function.Bijective (a * ·) := + ⟨fun h ↦ ⟨h.mul_right_injective, fun y ↦ ⟨h.unit⁻¹ * y, by simp [← mul_assoc]⟩⟩, fun h ↦ + ⟨⟨a, _, (h.2 1).choose_spec, h.1 + (by simpa [mul_assoc] using congr_arg (· * a) (h.2 1).choose_spec)⟩, rfl⟩⟩ + +@[to_additive] +theorem isUnit_iff_mulRight_bijective {a : M} : + IsUnit a ↔ Function.Bijective (· * a) := + ⟨fun h ↦ ⟨h.mul_left_injective, fun y ↦ ⟨y * h.unit⁻¹, by simp [mul_assoc]⟩⟩, + fun h ↦ ⟨⟨a, _, h.1 (by simpa [mul_assoc] using congr_arg (a * ·) (h.2 1).choose_spec), + (h.2 1).choose_spec⟩, rfl⟩⟩ + +end Monoid + +section DivisionMonoid +variable [DivisionMonoid α] {a b c : α} + +@[to_additive (attr := simp)] +protected lemma mul_inv_cancel_right (h : IsUnit b) (a : α) : a * b * b⁻¹ = a := + h.unit'.mul_inv_cancel_right _ + +@[to_additive (attr := simp)] +protected lemma inv_mul_cancel_right (h : IsUnit b) (a : α) : a * b⁻¹ * b = a := + h.unit'.inv_mul_cancel_right _ + +@[to_additive] +protected lemma eq_mul_inv_iff_mul_eq (h : IsUnit c) : a = b * c⁻¹ ↔ a * c = b := + h.unit'.eq_mul_inv_iff_mul_eq + +@[to_additive] +protected lemma eq_inv_mul_iff_mul_eq (h : IsUnit b) : a = b⁻¹ * c ↔ b * a = c := + h.unit'.eq_inv_mul_iff_mul_eq + +@[to_additive] +protected lemma inv_mul_eq_iff_eq_mul (h : IsUnit a) : a⁻¹ * b = c ↔ b = a * c := + h.unit'.inv_mul_eq_iff_eq_mul + +@[to_additive] +protected lemma mul_inv_eq_iff_eq_mul (h : IsUnit b) : a * b⁻¹ = c ↔ a = c * b := + h.unit'.mul_inv_eq_iff_eq_mul + +@[to_additive] +protected lemma mul_inv_eq_one (h : IsUnit b) : a * b⁻¹ = 1 ↔ a = b := + @Units.mul_inv_eq_one _ _ h.unit' _ + +@[to_additive] +protected lemma inv_mul_eq_one (h : IsUnit a) : a⁻¹ * b = 1 ↔ a = b := + @Units.inv_mul_eq_one _ _ h.unit' _ + +@[to_additive] +protected lemma mul_eq_one_iff_eq_inv (h : IsUnit b) : a * b = 1 ↔ a = b⁻¹ := + @Units.mul_eq_one_iff_eq_inv _ _ h.unit' _ + +@[to_additive] +protected lemma mul_eq_one_iff_inv_eq (h : IsUnit a) : a * b = 1 ↔ a⁻¹ = b := + @Units.mul_eq_one_iff_inv_eq _ _ h.unit' _ + +@[to_additive (attr := simp)] +protected lemma div_mul_cancel (h : IsUnit b) (a : α) : a / b * b = a := by + rw [div_eq_mul_inv, h.inv_mul_cancel_right] + +@[to_additive (attr := simp)] +protected lemma mul_div_cancel_right (h : IsUnit b) (a : α) : a * b / b = a := by + rw [div_eq_mul_inv, h.mul_inv_cancel_right] + +@[to_additive] +protected lemma mul_one_div_cancel (h : IsUnit a) : a * (1 / a) = 1 := by simp [h] + +@[to_additive] +protected lemma one_div_mul_cancel (h : IsUnit a) : 1 / a * a = 1 := by simp [h] + +@[to_additive] +protected lemma div_left_inj (h : IsUnit c) : a / c = b / c ↔ a = b := by + simp only [div_eq_mul_inv] + exact Units.mul_left_inj h.inv.unit' + +@[to_additive] +protected lemma div_eq_iff (h : IsUnit b) : a / b = c ↔ a = c * b := by + rw [div_eq_mul_inv, h.mul_inv_eq_iff_eq_mul] + +@[to_additive] +protected lemma eq_div_iff (h : IsUnit c) : a = b / c ↔ a * c = b := by + rw [div_eq_mul_inv, h.eq_mul_inv_iff_mul_eq] + +@[to_additive] +protected lemma div_eq_of_eq_mul (h : IsUnit b) : a = c * b → a / b = c := + h.div_eq_iff.2 + +@[to_additive] +protected lemma eq_div_of_mul_eq (h : IsUnit c) : a * c = b → a = b / c := + h.eq_div_iff.2 + +@[to_additive] +protected lemma div_eq_one_iff_eq (h : IsUnit b) : a / b = 1 ↔ a = b := + ⟨eq_of_div_eq_one, fun hab => hab.symm ▸ h.div_self⟩ + +@[to_additive] +protected lemma div_mul_left (h : IsUnit b) : b / (a * b) = 1 / a := by + rw [h.div_mul_cancel_right, one_div] + +@[to_additive] +protected lemma mul_mul_div (a : α) (h : IsUnit b) : a * b * (1 / b) = a := by simp [h] + +end DivisionMonoid + +section DivisionCommMonoid +variable [DivisionCommMonoid α] {a b c d : α} + +@[to_additive] +protected lemma div_mul_right (h : IsUnit a) (b : α) : a / (a * b) = 1 / b := by + rw [mul_comm, h.div_mul_left] + +@[to_additive] +protected lemma mul_div_cancel_left (h : IsUnit a) (b : α) : a * b / a = b := by + rw [mul_comm, h.mul_div_cancel_right] + +@[to_additive] +protected lemma mul_div_cancel (h : IsUnit a) (b : α) : a * (b / a) = b := by + rw [mul_comm, h.div_mul_cancel] + +@[to_additive] +protected lemma mul_eq_mul_of_div_eq_div (hb : IsUnit b) (hd : IsUnit d) + (a c : α) (h : a / b = c / d) : a * d = c * b := by + rw [← mul_one a, ← hb.div_self, ← mul_comm_div, h, div_mul_eq_mul_div, hd.div_mul_cancel] + +@[to_additive] +protected lemma div_eq_div_iff (hb : IsUnit b) (hd : IsUnit d) : + a / b = c / d ↔ a * d = c * b := by + rw [← (hb.mul hd).mul_left_inj, ← mul_assoc, hb.div_mul_cancel, ← mul_assoc, mul_right_comm, + hd.div_mul_cancel] + +@[to_additive] +protected lemma div_div_cancel (h : IsUnit a) : a / (a / b) = b := by + rw [div_div_eq_mul_div, h.mul_div_cancel_left] + +@[to_additive] +protected lemma div_div_cancel_left (h : IsUnit a) : a / b / a = b⁻¹ := by + rw [div_eq_mul_inv, div_eq_mul_inv, mul_right_comm, h.mul_inv_cancel, one_mul] + +end DivisionCommMonoid +end IsUnit + +-- namespace +end IsUnit + +attribute [deprecated div_mul_cancel_right (since := "2024-03-20")] IsUnit.div_mul_left +attribute [deprecated sub_add_cancel_right (since := "2024-03-20")] IsAddUnit.sub_add_left +attribute [deprecated div_mul_cancel_left (since := "2024-03-20")] IsUnit.div_mul_right +attribute [deprecated sub_add_cancel_left (since := "2024-03-20")] IsAddUnit.sub_add_right +-- The names `IsUnit.mul_div_cancel` and `IsAddUnit.add_sub_cancel` have been reused +-- @[deprecated (since := "2024-03-20")] alias IsUnit.mul_div_cancel := IsUnit.mul_div_cancel_right +-- @[deprecated (since := "2024-03-20")] +-- alias IsAddUnit.add_sub_cancel := IsAddUnit.add_sub_cancel_right +@[deprecated (since := "2024-03-20")] alias IsUnit.mul_div_cancel' := IsUnit.mul_div_cancel +@[deprecated (since := "2024-03-20")] alias IsAddUnit.add_sub_cancel' := IsAddUnit.add_sub_cancel diff --git a/Mathlib/Algebra/Group/Units.lean b/Mathlib/Algebra/Group/Units/Defs.lean similarity index 60% rename from Mathlib/Algebra/Group/Units.lean rename to Mathlib/Algebra/Group/Units/Defs.lean index da042a1542c09..f603439477532 100644 --- a/Mathlib/Algebra/Group/Units.lean +++ b/Mathlib/Algebra/Group/Units/Defs.lean @@ -3,12 +3,9 @@ Copyright (c) 2017 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro, Johannes Hölzl, Chris Hughes, Jens Wagemaker, Jon Eugster -/ -import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Group.Defs import Mathlib.Algebra.Group.Commute.Defs -import Mathlib.Logic.Unique -import Mathlib.Tactic.Nontriviality -import Mathlib.Tactic.Lift -import Mathlib.Tactic.Subsingleton +import Mathlib.Logic.Function.Basic /-! # Units (i.e., invertible elements) of a monoid @@ -82,14 +79,6 @@ structure AddUnits (α : Type u) [AddMonoid α] where attribute [to_additive] Units attribute [coe] AddUnits.val -section HasElem - -@[to_additive] -theorem unique_one {α : Type*} [Unique α] [One α] : default = (1 : α) := - Unique.default_eq 1 - -end HasElem - namespace Units section Monoid variable [Monoid α] @@ -181,7 +170,7 @@ the `AddMonoid`."] instance [Repr α] : Repr αˣ := ⟨reprPrec ∘ val⟩ -variable (a b c : αˣ) {u : αˣ} +variable (a b : αˣ) {u : αˣ} @[to_additive (attr := simp, norm_cast)] theorem val_mul : (↑(a * b) : α) = a * b := @@ -231,64 +220,10 @@ theorem mul_inv_cancel_left (a : αˣ) (b : α) : (a : α) * (↑a⁻¹ * b) = b theorem inv_mul_cancel_left (a : αˣ) (b : α) : (↑a⁻¹ : α) * (a * b) = b := by rw [← mul_assoc, inv_mul, one_mul] -@[to_additive (attr := simp)] -theorem mul_inv_cancel_right (a : α) (b : αˣ) : a * b * ↑b⁻¹ = a := by - rw [mul_assoc, mul_inv, mul_one] - -@[to_additive (attr := simp)] -theorem inv_mul_cancel_right (a : α) (b : αˣ) : a * ↑b⁻¹ * b = a := by - rw [mul_assoc, inv_mul, mul_one] - -@[to_additive (attr := simp)] -theorem mul_right_inj (a : αˣ) {b c : α} : (a : α) * b = a * c ↔ b = c := - ⟨fun h => by simpa only [inv_mul_cancel_left] using congr_arg (fun x : α => ↑(a⁻¹ : αˣ) * x) h, - congr_arg _⟩ - -@[to_additive (attr := simp)] -theorem mul_left_inj (a : αˣ) {b c : α} : b * a = c * a ↔ b = c := - ⟨fun h => by simpa only [mul_inv_cancel_right] using congr_arg (fun x : α => x * ↑(a⁻¹ : αˣ)) h, - congr_arg (· * a.val)⟩ - -@[to_additive] -theorem eq_mul_inv_iff_mul_eq {a b : α} : a = b * ↑c⁻¹ ↔ a * c = b := - ⟨fun h => by rw [h, inv_mul_cancel_right], fun h => by rw [← h, mul_inv_cancel_right]⟩ - -@[to_additive] -theorem eq_inv_mul_iff_mul_eq {a c : α} : a = ↑b⁻¹ * c ↔ ↑b * a = c := - ⟨fun h => by rw [h, mul_inv_cancel_left], fun h => by rw [← h, inv_mul_cancel_left]⟩ - @[to_additive] theorem inv_mul_eq_iff_eq_mul {b c : α} : ↑a⁻¹ * b = c ↔ b = a * c := ⟨fun h => by rw [← h, mul_inv_cancel_left], fun h => by rw [h, inv_mul_cancel_left]⟩ -@[to_additive] -theorem mul_inv_eq_iff_eq_mul {a c : α} : a * ↑b⁻¹ = c ↔ a = c * b := - ⟨fun h => by rw [← h, inv_mul_cancel_right], fun h => by rw [h, mul_inv_cancel_right]⟩ - --- Porting note: have to explicitly type annotate the 1 -@[to_additive] -protected theorem inv_eq_of_mul_eq_one_left {a : α} (h : a * u = 1) : ↑u⁻¹ = a := - calc - ↑u⁻¹ = (1 : α) * ↑u⁻¹ := by rw [one_mul] - _ = a := by rw [← h, mul_inv_cancel_right] - - --- Porting note: have to explicitly type annotate the 1 -@[to_additive] -protected theorem inv_eq_of_mul_eq_one_right {a : α} (h : ↑u * a = 1) : ↑u⁻¹ = a := - calc - ↑u⁻¹ = ↑u⁻¹ * (1 : α) := by rw [mul_one] - _ = a := by rw [← h, inv_mul_cancel_left] - - -@[to_additive] -protected theorem eq_inv_of_mul_eq_one_left {a : α} (h : ↑u * a = 1) : a = ↑u⁻¹ := - (Units.inv_eq_of_mul_eq_one_right h).symm - -@[to_additive] -protected theorem eq_inv_of_mul_eq_one_right {a : α} (h : a * u = 1) : a = ↑u⁻¹ := - (Units.inv_eq_of_mul_eq_one_left h).symm - @[to_additive] instance instMonoid : Monoid αˣ := { (inferInstance : MulOneClass αˣ) with @@ -334,24 +269,6 @@ instance instCommGroupUnits {α} [CommMonoid α] : CommGroup αˣ where @[to_additive (attr := simp, norm_cast)] lemma val_pow_eq_pow_val (n : ℕ) : ↑(a ^ n) = (a ^ n : α) := rfl -@[to_additive (attr := simp)] -theorem mul_inv_eq_one {a : α} : a * ↑u⁻¹ = 1 ↔ a = u := - ⟨inv_inv u ▸ Units.eq_inv_of_mul_eq_one_right, fun h => mul_inv_of_eq h.symm⟩ - -@[to_additive (attr := simp)] -theorem inv_mul_eq_one {a : α} : ↑u⁻¹ * a = 1 ↔ ↑u = a := - ⟨inv_inv u ▸ Units.inv_eq_of_mul_eq_one_right, inv_mul_of_eq⟩ - -@[to_additive] -theorem mul_eq_one_iff_eq_inv {a : α} : a * u = 1 ↔ a = ↑u⁻¹ := by rw [← mul_inv_eq_one, inv_inv] - -@[to_additive] -theorem mul_eq_one_iff_inv_eq {a : α} : ↑u * a = 1 ↔ ↑u⁻¹ = a := by rw [← inv_mul_eq_one, inv_inv] - -@[to_additive] -theorem inv_unique {u₁ u₂ : αˣ} (h : (↑u₁ : α) = ↑u₂) : (↑u₁⁻¹ : α) = ↑u₂⁻¹ := - Units.inv_eq_of_mul_eq_one_right <| by rw [h, u₂.mul_inv] - end Monoid section DivisionMonoid @@ -379,7 +296,7 @@ theorem Units.val_mkOfMulEqOne [CommMonoid α] {a b : α} (h : a * b = 1) : section Monoid -variable [Monoid α] {a b c : α} +variable [Monoid α] {a : α} /-- Partial division. It is defined when the second argument is invertible, and unlike the division operator @@ -418,27 +335,10 @@ theorem divp_mul_cancel (a : α) (u : αˣ) : a /ₚ u * u = a := theorem mul_divp_cancel (a : α) (u : αˣ) : a * u /ₚ u = a := (mul_assoc _ _ _).trans <| by rw [Units.mul_inv, mul_one] -@[simp] -theorem divp_left_inj (u : αˣ) {a b : α} : a /ₚ u = b /ₚ u ↔ a = b := - Units.mul_left_inj _ - @[field_simps] theorem divp_divp_eq_divp_mul (x : α) (u₁ u₂ : αˣ) : x /ₚ u₁ /ₚ u₂ = x /ₚ (u₂ * u₁) := by simp only [divp, mul_inv_rev, Units.val_mul, mul_assoc] -/- Porting note: to match the mathlib3 behavior, this needs to have higher simp -priority than eq_divp_iff_mul_eq. -/ -@[field_simps 1010] -theorem divp_eq_iff_mul_eq {x : α} {u : αˣ} {y : α} : x /ₚ u = y ↔ y * u = x := - u.mul_left_inj.symm.trans <| by rw [divp_mul_cancel]; exact ⟨Eq.symm, Eq.symm⟩ - -@[field_simps] -theorem eq_divp_iff_mul_eq {x : α} {u : αˣ} {y : α} : x = y /ₚ u ↔ x * u = y := by - rw [eq_comm, divp_eq_iff_mul_eq] - -theorem divp_eq_one_iff_eq {a : α} {u : αˣ} : a /ₚ u = 1 ↔ a = u := - (Units.mul_left_inj u).symm.trans <| by rw [divp_mul_cancel, one_mul] - @[simp] theorem one_divp (u : αˣ) : 1 /ₚ u = ↑u⁻¹ := one_mul _ @@ -447,14 +347,6 @@ theorem one_divp (u : αˣ) : 1 /ₚ u = ↑u⁻¹ := @[field_simps] theorem inv_eq_one_divp (u : αˣ) : ↑u⁻¹ = 1 /ₚ u := by rw [one_divp] -/-- Used for `field_simp` to deal with inverses of units. This form of the lemma -is essential since `field_simp` likes to use `inv_eq_one_div` to rewrite -`↑u⁻¹ = ↑(1 / u)`. --/ -@[field_simps] -theorem inv_eq_one_divp' (u : αˣ) : ((1 / u : αˣ) : α) = 1 /ₚ u := by - rw [one_div, one_divp] - /-- `field_simp` moves division inside `αˣ` to the right, and this lemma lifts the calculation to `α`. -/ @@ -464,115 +356,10 @@ theorem val_div_eq_divp (u₁ u₂ : αˣ) : ↑(u₁ / u₂) = ↑u₁ /ₚ u end Monoid -namespace LeftCancelMonoid - -variable [LeftCancelMonoid α] [Subsingleton αˣ] {a b : α} - -@[to_additive] -protected theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := - congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by - rw [← mul_left_cancel_iff (a := a), ← mul_assoc, h, one_mul, mul_one]) h) 1 - -@[to_additive] -protected theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := by - rwa [LeftCancelMonoid.eq_one_of_mul_right h, one_mul] at h - -@[to_additive (attr := simp)] -protected theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := - ⟨fun h => ⟨LeftCancelMonoid.eq_one_of_mul_right h, LeftCancelMonoid.eq_one_of_mul_left h⟩, by - rintro ⟨rfl, rfl⟩ - exact mul_one _⟩ - -@[to_additive] -protected theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp - -end LeftCancelMonoid - -namespace RightCancelMonoid - -variable [RightCancelMonoid α] [Subsingleton αˣ] {a b : α} - -@[to_additive] -protected theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := - congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by - rw [← mul_right_cancel_iff (a := b), mul_assoc, h, one_mul, mul_one]) h) 1 - -@[to_additive] -protected theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := by - rwa [RightCancelMonoid.eq_one_of_mul_right h, one_mul] at h - -@[to_additive (attr := simp)] -protected theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := - ⟨fun h => ⟨RightCancelMonoid.eq_one_of_mul_right h, RightCancelMonoid.eq_one_of_mul_left h⟩, by - rintro ⟨rfl, rfl⟩ - exact mul_one _⟩ - -@[to_additive] -protected theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp - -end RightCancelMonoid - -section CancelMonoid - -variable [CancelMonoid α] [Subsingleton αˣ] {a b : α} - -@[to_additive] -theorem eq_one_of_mul_right' (h : a * b = 1) : a = 1 := LeftCancelMonoid.eq_one_of_mul_right h - -@[to_additive] -theorem eq_one_of_mul_left' (h : a * b = 1) : b = 1 := LeftCancelMonoid.eq_one_of_mul_left h - -@[to_additive] -theorem mul_eq_one' : a * b = 1 ↔ a = 1 ∧ b = 1 := LeftCancelMonoid.mul_eq_one - -@[to_additive] -theorem mul_ne_one' : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := LeftCancelMonoid.mul_ne_one - -end CancelMonoid - -section CommMonoid - -variable [CommMonoid α] - -@[field_simps] -theorem divp_mul_eq_mul_divp (x y : α) (u : αˣ) : x /ₚ u * y = x * y /ₚ u := by - rw [divp, divp, mul_right_comm] - --- Theoretically redundant as `field_simp` lemma. -@[field_simps] -theorem divp_eq_divp_iff {x y : α} {ux uy : αˣ} : x /ₚ ux = y /ₚ uy ↔ x * uy = y * ux := by - rw [divp_eq_iff_mul_eq, divp_mul_eq_mul_divp, divp_eq_iff_mul_eq] - --- Theoretically redundant as `field_simp` lemma. -@[field_simps] -theorem divp_mul_divp (x y : α) (ux uy : αˣ) : x /ₚ ux * (y /ₚ uy) = x * y /ₚ (ux * uy) := by - rw [divp_mul_eq_mul_divp, divp_assoc', divp_divp_eq_divp_mul] - -variable [Subsingleton αˣ] {a b : α} - -@[to_additive] -theorem eq_one_of_mul_right (h : a * b = 1) : a = 1 := - congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ (by rwa [mul_comm]) h) 1 - -@[to_additive] -theorem eq_one_of_mul_left (h : a * b = 1) : b = 1 := - congr_arg Units.inv <| Subsingleton.elim (Units.mk _ _ h <| by rwa [mul_comm]) 1 - -@[to_additive (attr := simp)] -theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := - ⟨fun h => ⟨eq_one_of_mul_right h, eq_one_of_mul_left h⟩, by - rintro ⟨rfl, rfl⟩ - exact mul_one _⟩ - -@[to_additive] theorem mul_ne_one : a * b ≠ 1 ↔ a ≠ 1 ∨ b ≠ 1 := by rw [not_iff_comm]; simp - -end CommMonoid - /-! # `IsUnit` predicate -/ - section IsUnit variable {M : Type*} {N : Type*} @@ -602,19 +389,6 @@ theorem isUnit_iff_exists_and_exists [Monoid M] {a : M} : ⟨fun ⟨b, hba, hab⟩ => ⟨⟨b, hba⟩, ⟨b, hab⟩⟩, fun ⟨⟨b, hb⟩, ⟨_, hc⟩⟩ => ⟨b, hb, left_inv_eq_right_inv hc hb ▸ hc⟩⟩ -@[to_additive (attr := nontriviality)] -theorem isUnit_of_subsingleton [Monoid M] [Subsingleton M] (a : M) : IsUnit a := - ⟨⟨a, a, by subsingleton, by subsingleton⟩, rfl⟩ - -@[to_additive] -instance [Monoid M] : CanLift M Mˣ Units.val IsUnit := - { prf := fun _ ↦ id } - -/-- A subsingleton `Monoid` has a unique unit. -/ -@[to_additive "A subsingleton `AddMonoid` has a unique additive unit."] -instance [Monoid M] [Subsingleton M] : Unique Mˣ where - uniq _ := Units.val_eq_one.mp (by subsingleton) - @[to_additive (attr := simp)] protected theorem Units.isUnit [Monoid M] (u : Mˣ) : IsUnit (u : M) := ⟨u, rfl⟩ @@ -651,8 +425,6 @@ lemma IsUnit.exists_left_inv {a : M} (h : IsUnit a) : ∃ b, b * a = 1 := by @[to_additive] lemma IsUnit.pow (n : ℕ) : IsUnit a → IsUnit (a ^ n) := by rintro ⟨u, rfl⟩; exact ⟨u ^ n, rfl⟩ -theorem units_eq_one [Subsingleton Mˣ] (u : Mˣ) : u = 1 := by subsingleton - @[to_additive] lemma isUnit_iff_eq_one [Subsingleton Mˣ] {x : M} : IsUnit x ↔ x = 1 := ⟨fun ⟨u, hu⟩ ↦ by rw [← hu, Subsingleton.elim u 1, Units.val_one], fun h ↦ h ▸ isUnit_one⟩ @@ -705,7 +477,7 @@ theorem mul_iff [CommMonoid M] {x y : M} : IsUnit (x * y) ↔ IsUnit x ∧ IsUni section Monoid -variable [Monoid M] {a b c : M} +variable [Monoid M] {a : M} /-- The element of the group of units, corresponding to an element of a monoid which is a unit. When `α` is a `DivisionMonoid`, use `IsUnit.unit'` instead. -/ @@ -746,46 +518,6 @@ theorem mul_val_inv (h : IsUnit a) : a * ↑h.unit⁻¹ = 1 := by instance (x : M) [h : Decidable (∃ u : Mˣ, ↑u = x)] : Decidable (IsUnit x) := h -@[to_additive] -theorem mul_left_inj (h : IsUnit a) : b * a = c * a ↔ b = c := - let ⟨u, hu⟩ := h - hu ▸ u.mul_left_inj - -@[to_additive] -theorem mul_right_inj (h : IsUnit a) : a * b = a * c ↔ b = c := - let ⟨u, hu⟩ := h - hu ▸ u.mul_right_inj - -@[to_additive] -protected theorem mul_left_cancel (h : IsUnit a) : a * b = a * c → b = c := - h.mul_right_inj.1 - -@[to_additive] -protected theorem mul_right_cancel (h : IsUnit b) : a * b = c * b → a = c := - h.mul_left_inj.1 - -@[to_additive] -protected theorem mul_right_injective (h : IsUnit a) : Injective (a * ·) := - fun _ _ => h.mul_left_cancel - -@[to_additive] -protected theorem mul_left_injective (h : IsUnit b) : Injective (· * b) := - fun _ _ => h.mul_right_cancel - -@[to_additive] -theorem isUnit_iff_mulLeft_bijective {a : M} : - IsUnit a ↔ Function.Bijective (a * ·) := - ⟨fun h ↦ ⟨h.mul_right_injective, fun y ↦ ⟨h.unit⁻¹ * y, by simp [← mul_assoc]⟩⟩, fun h ↦ - ⟨⟨a, _, (h.2 1).choose_spec, h.1 - (by simpa [mul_assoc] using congr_arg (· * a) (h.2 1).choose_spec)⟩, rfl⟩⟩ - -@[to_additive] -theorem isUnit_iff_mulRight_bijective {a : M} : - IsUnit a ↔ Function.Bijective (· * a) := - ⟨fun h ↦ ⟨h.mul_left_injective, fun y ↦ ⟨y * h.unit⁻¹, by simp [mul_assoc]⟩⟩, - fun h ↦ ⟨⟨a, _, h.1 (by simpa [mul_assoc] using congr_arg (a * ·) (h.2 1).choose_spec), - (h.2 1).choose_spec⟩, rfl⟩⟩ - end Monoid section DivisionMonoid @@ -822,63 +554,9 @@ protected lemma mul_inv_cancel_left (h : IsUnit a) : ∀ b, a * (a⁻¹ * b) = b protected lemma inv_mul_cancel_left (h : IsUnit a) : ∀ b, a⁻¹ * (a * b) = b := h.unit'.inv_mul_cancel_left -@[to_additive (attr := simp)] -protected lemma mul_inv_cancel_right (h : IsUnit b) (a : α) : a * b * b⁻¹ = a := - h.unit'.mul_inv_cancel_right _ - -@[to_additive (attr := simp)] -protected lemma inv_mul_cancel_right (h : IsUnit b) (a : α) : a * b⁻¹ * b = a := - h.unit'.inv_mul_cancel_right _ - @[to_additive] protected lemma div_self (h : IsUnit a) : a / a = 1 := by rw [div_eq_mul_inv, h.mul_inv_cancel] -@[to_additive] -protected lemma eq_mul_inv_iff_mul_eq (h : IsUnit c) : a = b * c⁻¹ ↔ a * c = b := - h.unit'.eq_mul_inv_iff_mul_eq - -@[to_additive] -protected lemma eq_inv_mul_iff_mul_eq (h : IsUnit b) : a = b⁻¹ * c ↔ b * a = c := - h.unit'.eq_inv_mul_iff_mul_eq - -@[to_additive] -protected lemma inv_mul_eq_iff_eq_mul (h : IsUnit a) : a⁻¹ * b = c ↔ b = a * c := - h.unit'.inv_mul_eq_iff_eq_mul - -@[to_additive] -protected lemma mul_inv_eq_iff_eq_mul (h : IsUnit b) : a * b⁻¹ = c ↔ a = c * b := - h.unit'.mul_inv_eq_iff_eq_mul - -@[to_additive] -protected lemma mul_inv_eq_one (h : IsUnit b) : a * b⁻¹ = 1 ↔ a = b := - @Units.mul_inv_eq_one _ _ h.unit' _ - -@[to_additive] -protected lemma inv_mul_eq_one (h : IsUnit a) : a⁻¹ * b = 1 ↔ a = b := - @Units.inv_mul_eq_one _ _ h.unit' _ - -@[to_additive] -protected lemma mul_eq_one_iff_eq_inv (h : IsUnit b) : a * b = 1 ↔ a = b⁻¹ := - @Units.mul_eq_one_iff_eq_inv _ _ h.unit' _ - -@[to_additive] -protected lemma mul_eq_one_iff_inv_eq (h : IsUnit a) : a * b = 1 ↔ a⁻¹ = b := - @Units.mul_eq_one_iff_inv_eq _ _ h.unit' _ - -@[to_additive (attr := simp)] -protected lemma div_mul_cancel (h : IsUnit b) (a : α) : a / b * b = a := by - rw [div_eq_mul_inv, h.inv_mul_cancel_right] - -@[to_additive (attr := simp)] -protected lemma mul_div_cancel_right (h : IsUnit b) (a : α) : a * b / b = a := by - rw [div_eq_mul_inv, h.mul_inv_cancel_right] - -@[to_additive] -protected lemma mul_one_div_cancel (h : IsUnit a) : a * (1 / a) = 1 := by simp [h] - -@[to_additive] -protected lemma one_div_mul_cancel (h : IsUnit a) : 1 / a * a = 1 := by simp [h] - @[to_additive] lemma inv (h : IsUnit a) : IsUnit a⁻¹ := by obtain ⟨u, hu⟩ := h @@ -888,90 +566,27 @@ lemma inv (h : IsUnit a) : IsUnit a⁻¹ := by @[to_additive] lemma div (ha : IsUnit a) (hb : IsUnit b) : IsUnit (a / b) := by rw [div_eq_mul_inv]; exact ha.mul hb.inv -@[to_additive] -protected lemma div_left_inj (h : IsUnit c) : a / c = b / c ↔ a = b := by - simp only [div_eq_mul_inv] - exact Units.mul_left_inj h.inv.unit' - -@[to_additive] -protected lemma div_eq_iff (h : IsUnit b) : a / b = c ↔ a = c * b := by - rw [div_eq_mul_inv, h.mul_inv_eq_iff_eq_mul] - -@[to_additive] -protected lemma eq_div_iff (h : IsUnit c) : a = b / c ↔ a * c = b := by - rw [div_eq_mul_inv, h.eq_mul_inv_iff_mul_eq] - -@[to_additive] -protected lemma div_eq_of_eq_mul (h : IsUnit b) : a = c * b → a / b = c := - h.div_eq_iff.2 - -@[to_additive] -protected lemma eq_div_of_mul_eq (h : IsUnit c) : a * c = b → a = b / c := - h.eq_div_iff.2 - -@[to_additive] -protected lemma div_eq_one_iff_eq (h : IsUnit b) : a / b = 1 ↔ a = b := - ⟨eq_of_div_eq_one, fun hab => hab.symm ▸ h.div_self⟩ - @[to_additive] protected lemma div_mul_cancel_right (h : IsUnit b) (a : α) : b / (a * b) = a⁻¹ := by rw [div_eq_mul_inv, mul_inv_rev, h.mul_inv_cancel_left] -@[to_additive] -protected lemma div_mul_left (h : IsUnit b) : b / (a * b) = 1 / a := by - rw [h.div_mul_cancel_right, one_div] - @[to_additive] protected lemma mul_div_mul_right (h : IsUnit c) (a b : α) : a * c / (b * c) = a / b := by simp only [div_eq_mul_inv, mul_inv_rev, mul_assoc, h.mul_inv_cancel_left] -@[to_additive] -protected lemma mul_mul_div (a : α) (h : IsUnit b) : a * b * (1 / b) = a := by simp [h] - end DivisionMonoid section DivisionCommMonoid -variable [DivisionCommMonoid α] {a b c d : α} +variable [DivisionCommMonoid α] {a c : α} @[to_additive] protected lemma div_mul_cancel_left (h : IsUnit a) (b : α) : a / (a * b) = b⁻¹ := by rw [mul_comm, h.div_mul_cancel_right] -@[to_additive] -protected lemma div_mul_right (h : IsUnit a) (b : α) : a / (a * b) = 1 / b := by - rw [mul_comm, h.div_mul_left] - -@[to_additive] -protected lemma mul_div_cancel_left (h : IsUnit a) (b : α) : a * b / a = b := by - rw [mul_comm, h.mul_div_cancel_right] - -@[to_additive] -protected lemma mul_div_cancel (h : IsUnit a) (b : α) : a * (b / a) = b := by - rw [mul_comm, h.div_mul_cancel] - @[to_additive] protected lemma mul_div_mul_left (h : IsUnit c) (a b : α) : c * a / (c * b) = a / b := by rw [mul_comm c, mul_comm c, h.mul_div_mul_right] -@[to_additive] -protected lemma mul_eq_mul_of_div_eq_div (hb : IsUnit b) (hd : IsUnit d) - (a c : α) (h : a / b = c / d) : a * d = c * b := by - rw [← mul_one a, ← hb.div_self, ← mul_comm_div, h, div_mul_eq_mul_div, hd.div_mul_cancel] - -@[to_additive] -protected lemma div_eq_div_iff (hb : IsUnit b) (hd : IsUnit d) : - a / b = c / d ↔ a * d = c * b := by - rw [← (hb.mul hd).mul_left_inj, ← mul_assoc, hb.div_mul_cancel, ← mul_assoc, mul_right_comm, - hd.div_mul_cancel] - -@[to_additive] -protected lemma div_div_cancel (h : IsUnit a) : a / (a / b) = b := by - rw [div_div_eq_mul_div, h.mul_div_cancel_left] - -@[to_additive] -protected lemma div_div_cancel_left (h : IsUnit a) : a / b / a = b⁻¹ := by - rw [div_eq_mul_inv, div_eq_mul_inv, mul_right_comm, h.mul_inv_cancel, one_mul] - end DivisionCommMonoid end IsUnit @@ -1012,14 +627,3 @@ noncomputable def commGroupOfIsUnit [hM : CommMonoid M] (h : ∀ a : M, IsUnit a rw [Units.inv_mul_eq_iff_eq_mul, (h a).unit_spec, mul_one] } end NoncomputableDefs - -attribute [deprecated div_mul_cancel_right (since := "2024-03-20")] IsUnit.div_mul_left -attribute [deprecated sub_add_cancel_right (since := "2024-03-20")] IsAddUnit.sub_add_left -attribute [deprecated div_mul_cancel_left (since := "2024-03-20")] IsUnit.div_mul_right -attribute [deprecated sub_add_cancel_left (since := "2024-03-20")] IsAddUnit.sub_add_right --- The names `IsUnit.mul_div_cancel` and `IsAddUnit.add_sub_cancel` have been reused --- @[deprecated (since := "2024-03-20")] alias IsUnit.mul_div_cancel := IsUnit.mul_div_cancel_right --- @[deprecated (since := "2024-03-20")] --- alias IsAddUnit.add_sub_cancel := IsAddUnit.add_sub_cancel_right -@[deprecated (since := "2024-03-20")] alias IsUnit.mul_div_cancel' := IsUnit.mul_div_cancel -@[deprecated (since := "2024-03-20")] alias IsAddUnit.add_sub_cancel' := IsAddUnit.add_sub_cancel diff --git a/Mathlib/Algebra/Group/Units/Equiv.lean b/Mathlib/Algebra/Group/Units/Equiv.lean index a3ae5f7904381..27f2a366dd06d 100644 --- a/Mathlib/Algebra/Group/Units/Equiv.lean +++ b/Mathlib/Algebra/Group/Units/Equiv.lean @@ -13,7 +13,7 @@ import Mathlib.Algebra.Group.Units.Hom assert_not_exists MonoidWithZero assert_not_exists DenselyOrdered -variable {F α β A B M N P Q G H : Type*} +variable {F α M N G : Type*} /-- A group is isomorphic to its group of units. -/ @[to_additive (attr := simps apply_val symm_apply) @@ -31,7 +31,7 @@ lemma toUnits_val_apply {G : Type*} [Group G] (x : Gˣ) : toUnits (x : G) = x := namespace Units -variable [Monoid M] [Monoid N] [Monoid P] +variable [Monoid M] [Monoid N] /-- A multiplicative equivalence of monoids defines a multiplicative equivalence of their groups of units. -/ @@ -192,11 +192,14 @@ def MulEquiv.inv (G : Type*) [DivisionCommMonoid G] : G ≃* G := theorem MulEquiv.inv_symm (G : Type*) [DivisionCommMonoid G] : (MulEquiv.inv G).symm = MulEquiv.inv G := rfl --- Porting note: no `add_equiv.neg_symm` in `mathlib3` -@[to_additive] -protected -theorem MulEquiv.map_isUnit_iff {M N} [Monoid M] [Monoid N] [EquivLike F M N] [MonoidHomClass F M N] - (f : F) {m : M} : IsUnit (f m) ↔ IsUnit m := - isUnit_map_of_leftInverse (MonoidHom.inverse (f : M →* N) (EquivLike.inv f) - (EquivLike.left_inv f) <| EquivLike.right_inv f) (EquivLike.left_inv f) +@[instance] +theorem isLocalHom_equiv [Monoid M] [Monoid N] [EquivLike F M N] + [MulEquivClass F M N] (f : F) : IsLocalHom f where + map_nonunit a ha := by + convert ha.map (f : M ≃* N).symm + rw [MulEquiv.eq_symm_apply] + rfl -- note to reviewers: ugly `rfl` + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_equiv := isLocalHom_equiv diff --git a/Mathlib/Algebra/Group/Units/Hom.lean b/Mathlib/Algebra/Group/Units/Hom.lean index 1a84f0441934c..5a210213562a4 100644 --- a/Mathlib/Algebra/Group/Units/Hom.lean +++ b/Mathlib/Algebra/Group/Units/Hom.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Chris Hughes, Kevin Buzzard -/ import Mathlib.Algebra.Group.Hom.Defs -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic /-! # Monoid homomorphisms and units @@ -17,6 +17,18 @@ also contains unrelated results about `Units` that depend on `MonoidHom`. * `Units.map`: Turn a homomorphism from `α` to `β` monoids into a homomorphism from `αˣ` to `βˣ`. * `MonoidHom.toHomUnits`: Turn a homomorphism from a group `α` to `β` into a homomorphism from `α` to `βˣ`. +* `IsLocalHom`: A predicate on monoid maps, requiring that it maps nonunits + to nonunits. For local rings, this means that the image of the unique maximal ideal is again + contained in the unique maximal ideal. This is developed earlier, and in the generality of + monoids, as it allows its use in non-local-ring related contexts, but it does have the + strange consequence that it does not require local rings, or even rings. + +## TODO + +The results that don't mention homomorphisms should be proved (earlier?) in a different file and be +used to golf the basic `Group` lemmas. + +Add a `@[to_additive]` version of `IsLocalHom`. -/ assert_not_exists MonoidWithZero @@ -152,7 +164,7 @@ end MonoidHom namespace IsUnit -variable {F G α M N : Type*} [FunLike F M N] [FunLike G N M] +variable {F G M N : Type*} [FunLike F M N] [FunLike G N M] section Monoid @@ -167,6 +179,7 @@ theorem of_leftInverse [MonoidHomClass G N M] {f : F} {x : M} (g : G) (hfg : Function.LeftInverse g f) (h : IsUnit (f x)) : IsUnit x := by simpa only [hfg x] using h.map g +/-- Prefer `IsLocalHom.of_leftInverse`, but we can't get rid of this because of `ToAdditive`. -/ @[to_additive] theorem _root_.isUnit_map_of_leftInverse [MonoidHomClass F M N] [MonoidHomClass G N M] {f : F} {x : M} (g : G) (hfg : Function.LeftInverse g f) : @@ -194,3 +207,66 @@ theorem liftRight_inv_mul (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) : end Monoid end IsUnit + +section IsLocalHom + +variable {G R S T F : Type*} + +variable [Monoid R] [Monoid S] [Monoid T] [FunLike F R S] + +/-- A local ring homomorphism is a map `f` between monoids such that `a` in the domain + is a unit if `f a` is a unit for any `a`. See `LocalRing.local_hom_TFAE` for other equivalent + definitions in the local ring case - from where this concept originates, but it is useful in + other contexts, so we allow this generalisation in mathlib. -/ +class IsLocalHom (f : F) : Prop where + /-- A local homomorphism `f : R ⟶ S` will send nonunits of `R` to nonunits of `S`. -/ + map_nonunit : ∀ a, IsUnit (f a) → IsUnit a + +@[deprecated (since := "2024-10-10")] +alias IsLocalRingHom := IsLocalHom + +@[simp] +theorem IsUnit.of_map (f : F) [IsLocalHom f] (a : R) (h : IsUnit (f a)) : IsUnit a := + IsLocalHom.map_nonunit a h + +-- TODO : remove alias, change the parenthesis of `f` and `a` +alias isUnit_of_map_unit := IsUnit.of_map + +variable [MonoidHomClass F R S] + +@[simp] +theorem isUnit_map_iff (f : F) [IsLocalHom f] (a : R) : IsUnit (f a) ↔ IsUnit a := + ⟨IsLocalHom.map_nonunit a, IsUnit.map f⟩ + +theorem isLocalHom_of_leftInverse [FunLike G S R] [MonoidHomClass G S R] + {f : F} (g : G) (hfg : Function.LeftInverse g f) : IsLocalHom f where + map_nonunit a ha := by rwa [isUnit_map_of_leftInverse g hfg] at ha + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_of_leftInverse := isLocalHom_of_leftInverse + +@[instance] +theorem MonoidHom.isLocalHom_comp (g : S →* T) (f : R →* S) [IsLocalHom g] + [IsLocalHom f] : IsLocalHom (g.comp f) where + map_nonunit a := IsLocalHom.map_nonunit a ∘ IsLocalHom.map_nonunit (f := g) (f a) + +@[deprecated (since := "2024-10-10")] +alias MonoidHom.isLocalRingHom_comp := MonoidHom.isLocalHom_comp + +-- see note [lower instance priority] +@[instance 100] +theorem isLocalHom_toMonoidHom (f : F) [IsLocalHom f] : + IsLocalHom (f : R →* S) := + ⟨IsLocalHom.map_nonunit (f := f)⟩ + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_toMonoidHom := isLocalHom_toMonoidHom + +theorem MonoidHom.isLocalHom_of_comp (f : R →* S) (g : S →* T) [IsLocalHom (g.comp f)] : + IsLocalHom f := + ⟨fun _ ha => (isUnit_map_iff (g.comp f) _).mp (ha.map g)⟩ + +@[deprecated (since := "2024-10-10")] +alias MonoidHom.isLocalRingHom_of_comp := MonoidHom.isLocalHom_of_comp + +end IsLocalHom diff --git a/Mathlib/Algebra/Group/WithOne/Basic.lean b/Mathlib/Algebra/Group/WithOne/Basic.lean index 7687d4bd15dca..3dca5ba0dab77 100644 --- a/Mathlib/Algebra/Group/WithOne/Basic.lean +++ b/Mathlib/Algebra/Group/WithOne/Basic.lean @@ -63,8 +63,8 @@ def lift : (α →ₙ* β) ≃ (WithOne α →* β) where (fun x => WithOne.cases_on y (by rw [mul_one]; exact (mul_one _).symm) (fun y => f.map_mul x y)) } invFun F := F.toMulHom.comp coeMulHom - left_inv f := MulHom.ext fun x => rfl - right_inv F := MonoidHom.ext fun x => WithOne.cases_on x F.map_one.symm (fun x => rfl) + left_inv _ := MulHom.ext fun _ => rfl + right_inv F := MonoidHom.ext fun x => WithOne.cases_on x F.map_one.symm (fun _ => rfl) -- Porting note: the above proofs were broken because they were parenthesized wrong by mathport? variable (f : α →ₙ* β) diff --git a/Mathlib/Algebra/Group/WithOne/Defs.lean b/Mathlib/Algebra/Group/WithOne/Defs.lean index cb45380e57fa6..39ed722267c5d 100644 --- a/Mathlib/Algebra/Group/WithOne/Defs.lean +++ b/Mathlib/Algebra/Group/WithOne/Defs.lean @@ -43,7 +43,7 @@ assert_not_exists DenselyOrdered universe u v w -variable {α : Type u} {β : Type v} {γ : Type w} +variable {α : Type u} /-- Add an extra element `1` to a type -/ @[to_additive "Add an extra element `0` to a type"] diff --git a/Mathlib/Algebra/GroupPower/IterateHom.lean b/Mathlib/Algebra/GroupPower/IterateHom.lean index d28361dadaa6e..50ac0d58a372a 100644 --- a/Mathlib/Algebra/GroupPower/IterateHom.lean +++ b/Mathlib/Algebra/GroupPower/IterateHom.lean @@ -31,7 +31,7 @@ assert_not_exists DenselyOrdered open Function -variable {M : Type*} {N : Type*} {G : Type*} {H : Type*} +variable {M : Type*} {G : Type*} {H : Type*} /-- An auxiliary lemma that can be used to prove `⇑(f ^ n) = ⇑f^[n]`. -/ theorem hom_coe_pow {F : Type*} [Monoid F] (c : F → M → M) (h1 : c 1 = id) diff --git a/Mathlib/Algebra/GroupWithZero/Action/Basic.lean b/Mathlib/Algebra/GroupWithZero/Action/Basic.lean index 616b74daf1af9..39b682e9f1e61 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Basic.lean @@ -51,7 +51,7 @@ group action open Function -variable {G G₀ A M N M₀ N₀ R α : Type*} +variable {G G₀ A M M₀ N₀ R α : Type*} section GroupWithZero variable [GroupWithZero G₀] [MulAction G₀ α] {a : G₀} @@ -68,7 +68,7 @@ protected lemma MulAction.surjective₀ (ha : a ≠ 0) : Surjective (a • · : end GroupWithZero section DistribMulAction -variable [Group G] [Monoid M] [AddMonoid A] [DistribMulAction M A] +variable [Group G] [Monoid M] [AddMonoid A] variable (A) /-- Each element of the group defines an additive monoid isomorphism. diff --git a/Mathlib/Algebra/GroupWithZero/Action/Defs.lean b/Mathlib/Algebra/GroupWithZero/Action/Defs.lean index 28a7f1306d857..f4420acfd2b38 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Defs.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Defs.lean @@ -3,9 +3,8 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Yury Kudryashov -/ -import Mathlib.Algebra.Group.Action.Units -import Mathlib.Algebra.Group.Equiv.Basic -import Mathlib.Algebra.GroupWithZero.Units.Basic +import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Group.Hom.Defs /-! # Definitions of group actions @@ -13,25 +12,17 @@ import Mathlib.Algebra.GroupWithZero.Units.Basic This file defines a hierarchy of group action type-classes on top of the previously defined notation classes `SMul` and its additive version `VAdd`: -* `MulAction M α` and its additive version `AddAction G P` are typeclasses used for - actions of multiplicative and additive monoids and groups; they extend notation classes - `SMul` and `VAdd` that are defined in `Algebra.Group.Defs`; +* `SMulZeroClass` is a typeclass for an action that preserves zero +* `DistribSMul M A` is a typeclass for an action on an additive monoid (`AddZeroClass`) that + preserves addition and zero * `DistribMulAction M A` is a typeclass for an action of a multiplicative monoid on an additive monoid such that `a • (b + c) = a • b + a • c` and `a • 0 = 0`. The hierarchy is extended further by `Module`, defined elsewhere. -Also provided are typeclasses for faithful and transitive actions, and typeclasses regarding the -interaction of different group actions, - -* `SMulCommClass M N α` and its additive version `VAddCommClass M N α`; -* `IsScalarTower M N α` and its additive version `VAddAssocClass M N α`; -* `IsCentralScalar M α` and its additive version `IsCentralVAdd M N α`. - ## Notation - `a • b` is used as notation for `SMul.smul a b`. -- `a +ᵥ b` is used as notation for `VAdd.vadd a b`. ## Implementation details @@ -49,43 +40,7 @@ assert_not_exists Ring open Function -variable {R R' M M' N G A B α β : Type*} - -/-- `Monoid.toMulAction` is faithful on nontrivial cancellative monoids with zero. -/ -instance CancelMonoidWithZero.faithfulSMul [CancelMonoidWithZero α] [Nontrivial α] : - FaithfulSMul α α where eq_of_smul_eq_smul h := mul_left_injective₀ one_ne_zero (h 1) - -section GroupWithZero -variable [GroupWithZero α] [MulAction α β] {a : α} - -@[simp] lemma inv_smul_smul₀ (ha : a ≠ 0) (x : β) : a⁻¹ • a • x = x := - inv_smul_smul (Units.mk0 a ha) x - -@[simp] -lemma smul_inv_smul₀ (ha : a ≠ 0) (x : β) : a • a⁻¹ • x = x := smul_inv_smul (Units.mk0 a ha) x - -lemma inv_smul_eq_iff₀ (ha : a ≠ 0) {x y : β} : a⁻¹ • x = y ↔ x = a • y := - inv_smul_eq_iff (g := Units.mk0 a ha) - -lemma eq_inv_smul_iff₀ (ha : a ≠ 0) {x y : β} : x = a⁻¹ • y ↔ a • x = y := - eq_inv_smul_iff (g := Units.mk0 a ha) - -@[simp] -lemma Commute.smul_right_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {x y : β} - (ha : a ≠ 0) : Commute x (a • y) ↔ Commute x y := Commute.smul_right_iff (g := Units.mk0 a ha) - -@[simp] -lemma Commute.smul_left_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {x y : β} - (ha : a ≠ 0) : Commute (a • x) y ↔ Commute x y := Commute.smul_left_iff (g := Units.mk0 a ha) - -/-- Right scalar multiplication as an order isomorphism. -/ -@[simps] def Equiv.smulRight (ha : a ≠ 0) : β ≃ β where - toFun b := a • b - invFun b := a⁻¹ • b - left_inv := inv_smul_smul₀ ha - right_inv := smul_inv_smul₀ ha - -end GroupWithZero +variable {M N A B α β : Type*} /-- Typeclass for scalar multiplication that preserves `0` on the right. -/ class SMulZeroClass (M A : Type*) [Zero A] extends SMul M A where @@ -172,7 +127,7 @@ instance AddMonoidHom.smulZeroClass [AddZeroClass B] : SMulZeroClass M (B →+ A { toFun := fun a => r • (f a) map_zero' := by simp only [map_zero, smul_zero] map_add' := fun x y => by simp only [map_add, smul_add] } - smul_zero r := ext fun _ => smul_zero _ + smul_zero _ := ext fun _ => smul_zero _ /-- Pullback a distributive scalar multiplication along an injective additive monoid homomorphism. @@ -214,7 +169,7 @@ abbrev DistribSMul.compFun (f : N → M) : DistribSMul N A := /-- Each element of the scalars defines an additive monoid homomorphism. -/ @[simps] def DistribSMul.toAddMonoidHom (x : M) : A →+ A := - { SMulZeroClass.toZeroHom A x with toFun := (· • ·) x, map_add' := smul_add x } + { SMulZeroClass.toZeroHom A x with toFun := (x • ·), map_add' := smul_add x } end DistribSMul @@ -257,22 +212,8 @@ protected abbrev Function.Surjective.distribMulAction [AddMonoid B] [SMul M B] ( (hf : Surjective f) (smul : ∀ (c : M) (x), f (c • x) = c • f x) : DistribMulAction M B := { hf.distribSMul f smul, hf.mulAction f smul with } -/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →* S`. - -See also `Function.Surjective.mulActionLeft` and `Function.Surjective.moduleLeft`. --/ -abbrev Function.Surjective.distribMulActionLeft {R S M : Type*} [Monoid R] [AddMonoid M] - [DistribMulAction R M] [Monoid S] [SMul S M] (f : R →* S) (hf : Function.Surjective f) - (hsmul : ∀ (c) (x : M), f c • x = c • x) : DistribMulAction S M := - { hf.distribSMulLeft f hsmul, hf.mulActionLeft f hsmul with } - variable (A) -/-- Compose a `DistribMulAction` with a `MonoidHom`, with action `f r' • m`. -See note [reducible non-instances]. -/ -abbrev DistribMulAction.compHom [Monoid N] (f : N →* M) : DistribMulAction N A := - { DistribSMul.compFun A f, MulAction.compHom A f with } - /-- Each element of the monoid defines an additive monoid homomorphism. -/ @[simps!] def DistribMulAction.toAddMonoidHom (x : M) : A →+ A := @@ -360,13 +301,6 @@ protected abbrev Function.Surjective.mulDistribMulAction [Monoid B] [SMul M B] ( variable (A) -/-- Compose a `MulDistribMulAction` with a `MonoidHom`, with action `f r' • m`. -See note [reducible non-instances]. -/ -abbrev MulDistribMulAction.compHom [Monoid N] (f : N →* M) : MulDistribMulAction N A := - { MulAction.compHom A f with - smul_one := fun x => smul_one (f x), - smul_mul := fun x => smul_mul' (f x) } - /-- Scalar multiplication by `r` as a `MonoidHom`. -/ def MulDistribMulAction.toMonoidHom (r : M) : A →* A where @@ -384,16 +318,6 @@ theorem MulDistribMulAction.toMonoidHom_apply (r : M) (x : A) : @[simp] lemma smul_pow' (r : M) (x : A) (n : ℕ) : r • x ^ n = (r • x) ^ n := (MulDistribMulAction.toMonoidHom _ _).map_pow _ _ -variable (M A) - -/-- Each element of the monoid defines a monoid homomorphism. -/ -@[simps] -def MulDistribMulAction.toMonoidEnd : - M →* Monoid.End A where - toFun := MulDistribMulAction.toMonoidHom A - map_one' := MonoidHom.ext <| one_smul M - map_mul' x y := MonoidHom.ext <| mul_smul x y - end section @@ -409,36 +333,6 @@ theorem smul_div' (r : M) (x y : A) : r • (x / y) = r • x / r • y := end -/-- The tautological action by `AddMonoid.End α` on `α`. - -This generalizes `Function.End.applyMulAction`. -/ -instance AddMonoid.End.applyDistribMulAction [AddMonoid α] : - DistribMulAction (AddMonoid.End α) α where - smul := (· <| ·) - smul_zero := AddMonoidHom.map_zero - smul_add := AddMonoidHom.map_add - one_smul _ := rfl - mul_smul _ _ _ := rfl - -@[simp] -theorem AddMonoid.End.smul_def [AddMonoid α] (f : AddMonoid.End α) (a : α) : f • a = f a := - rfl - -/-- `AddMonoid.End.applyDistribMulAction` is faithful. -/ -instance AddMonoid.End.applyFaithfulSMul [AddMonoid α] : - FaithfulSMul (AddMonoid.End α) α := - ⟨fun {_ _ h} => AddMonoidHom.ext h⟩ - -/-- Each non-zero element of a `GroupWithZero` defines an additive monoid isomorphism of an -`AddMonoid` on which it acts distributively. -This is a stronger version of `DistribMulAction.toAddMonoidHom`. -/ -def DistribMulAction.toAddEquiv₀ {α : Type*} (β : Type*) [GroupWithZero α] [AddMonoid β] - [DistribMulAction α β] (x : α) (hx : x ≠ 0) : β ≃+ β := - { DistribMulAction.toAddMonoidHom β x with - invFun := fun b ↦ x⁻¹ • b - left_inv := fun b ↦ inv_smul_smul₀ hx b - right_inv := fun b ↦ smul_inv_smul₀ hx b } - section Group variable [Group α] [AddMonoid β] [DistribMulAction α β] diff --git a/Mathlib/Algebra/GroupWithZero/Action/End.lean b/Mathlib/Algebra/GroupWithZero/Action/End.lean new file mode 100644 index 0000000000000..e38aaaf10e21d --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Action/End.lean @@ -0,0 +1,93 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.End +import Mathlib.Algebra.Group.Equiv.Basic +import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.GroupWithZero.Action.Units + +/-! +# Group actions and (endo)morphisms +-/ + +assert_not_exists Equiv.Perm.equivUnitsEnd +assert_not_exists Prod.fst_mul +assert_not_exists Ring + +open Function + +variable {M N A B α β : Type*} + +/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →* S`. + +See also `Function.Surjective.mulActionLeft` and `Function.Surjective.moduleLeft`. +-/ +abbrev Function.Surjective.distribMulActionLeft {R S M : Type*} [Monoid R] [AddMonoid M] + [DistribMulAction R M] [Monoid S] [SMul S M] (f : R →* S) (hf : Function.Surjective f) + (hsmul : ∀ (c) (x : M), f c • x = c • x) : DistribMulAction S M := + { hf.distribSMulLeft f hsmul, hf.mulActionLeft f hsmul with } + +section AddMonoid + +variable (A) [AddMonoid A] [Monoid M] [DistribMulAction M A] + +/-- Compose a `DistribMulAction` with a `MonoidHom`, with action `f r' • m`. +See note [reducible non-instances]. -/ +abbrev DistribMulAction.compHom [Monoid N] (f : N →* M) : DistribMulAction N A := + { DistribSMul.compFun A f, MulAction.compHom A f with } + +end AddMonoid + +section Monoid + +variable (A) [Monoid A] [Monoid M] [MulDistribMulAction M A] + +/-- Compose a `MulDistribMulAction` with a `MonoidHom`, with action `f r' • m`. +See note [reducible non-instances]. -/ +abbrev MulDistribMulAction.compHom [Monoid N] (f : N →* M) : MulDistribMulAction N A := + { MulAction.compHom A f with + smul_one := fun x => smul_one (f x), + smul_mul := fun x => smul_mul' (f x) } + +end Monoid + +/-- The tautological action by `AddMonoid.End α` on `α`. + +This generalizes `Function.End.applyMulAction`. -/ +instance AddMonoid.End.applyDistribMulAction [AddMonoid α] : + DistribMulAction (AddMonoid.End α) α where + smul := (· <| ·) + smul_zero := AddMonoidHom.map_zero + smul_add := AddMonoidHom.map_add + one_smul _ := rfl + mul_smul _ _ _ := rfl + +@[simp] +theorem AddMonoid.End.smul_def [AddMonoid α] (f : AddMonoid.End α) (a : α) : f • a = f a := + rfl + +/-- `AddMonoid.End.applyDistribMulAction` is faithful. -/ +instance AddMonoid.End.applyFaithfulSMul [AddMonoid α] : + FaithfulSMul (AddMonoid.End α) α := + ⟨fun {_ _ h} => AddMonoidHom.ext h⟩ + +/-- Each non-zero element of a `GroupWithZero` defines an additive monoid isomorphism of an +`AddMonoid` on which it acts distributively. +This is a stronger version of `DistribMulAction.toAddMonoidHom`. -/ +def DistribMulAction.toAddEquiv₀ {α : Type*} (β : Type*) [GroupWithZero α] [AddMonoid β] + [DistribMulAction α β] (x : α) (hx : x ≠ 0) : β ≃+ β := + { DistribMulAction.toAddMonoidHom β x with + invFun := fun b ↦ x⁻¹ • b + left_inv := fun b ↦ inv_smul_smul₀ hx b + right_inv := fun b ↦ smul_inv_smul₀ hx b } + +variable (M A) in +/-- Each element of the monoid defines a monoid homomorphism. -/ +@[simps] +def MulDistribMulAction.toMonoidEnd [Monoid M] [Monoid A] [MulDistribMulAction M A] : + M →* Monoid.End A where + toFun := MulDistribMulAction.toMonoidHom A + map_one' := MonoidHom.ext <| one_smul M + map_mul' x y := MonoidHom.ext <| mul_smul x y diff --git a/Mathlib/Algebra/GroupWithZero/Action/Faithful.lean b/Mathlib/Algebra/GroupWithZero/Action/Faithful.lean new file mode 100644 index 0000000000000..9fb6f8fc8c954 --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Action/Faithful.lean @@ -0,0 +1,23 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Action.Faithful +import Mathlib.Algebra.GroupWithZero.NeZero + +/-! +# Faithful actions involving groups with zero +-/ + +assert_not_exists Equiv.Perm.equivUnitsEnd +assert_not_exists Prod.fst_mul +assert_not_exists Ring + +open Function + +variable {M N A B α β : Type*} + +/-- `Monoid.toMulAction` is faithful on nontrivial cancellative monoids with zero. -/ +instance CancelMonoidWithZero.faithfulSMul [CancelMonoidWithZero α] [Nontrivial α] : + FaithfulSMul α α where eq_of_smul_eq_smul h := mul_left_injective₀ one_ne_zero (h 1) diff --git a/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean b/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean index e78af0c456d38..27bab44a1aaed 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean @@ -27,7 +27,7 @@ With `open scoped RightActions`, this provides: * `p <+ᵥ v` as an alias for `AddOpposite.op v +ᵥ p` -/ -variable {R M N α : Type*} +variable {M α : Type*} /-! ### Actions _on_ the opposite type diff --git a/Mathlib/Algebra/GroupWithZero/Action/Pi.lean b/Mathlib/Algebra/GroupWithZero/Action/Pi.lean index a68e1a97b1d8a..f465f4b4caa56 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Pi.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Pi.lean @@ -21,16 +21,13 @@ This file defines instances for `MulActionWithZero` and related structures on `P -/ -universe u v w +universe u v variable {I : Type u} -- The indexing type variable {f : I → Type v} --- The family of types already equipped with instances -variable (x y : ∀ i, f i) (i : I) - namespace Pi instance smulZeroClass (α) {n : ∀ i, Zero <| f i} [∀ i, SMulZeroClass α <| f i] : diff --git a/Mathlib/Algebra/GroupWithZero/Action/Prod.lean b/Mathlib/Algebra/GroupWithZero/Action/Prod.lean index b3ca53b145019..ff3a88f7e4b13 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Prod.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Prod.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Patrick Massot, Eric Wieser -/ import Mathlib.Algebra.Group.Action.Prod -import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.GroupWithZero.Action.End /-! # Prod instances for multiplicative actions with zero @@ -26,7 +26,7 @@ namespace Prod section -variable [SMul M α] [SMul M β] [SMul N α] [SMul N β] (a : M) (x : α × β) +variable [SMul M α] [SMul M β] theorem smul_zero_mk {α : Type*} [Monoid M] [AddMonoid α] [DistribMulAction M α] (a : M) (c : β) : a • ((0 : α), c) = (0, a • c) := by rw [Prod.smul_mk, smul_zero] diff --git a/Mathlib/Algebra/GroupWithZero/Action/Units.lean b/Mathlib/Algebra/GroupWithZero/Action/Units.lean index c517ff3399f1e..5a5df0d53edce 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Units.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Units.lean @@ -5,6 +5,7 @@ Authors: Eric Wieser -/ import Mathlib.Algebra.Group.Action.Units import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.GroupWithZero.Units.Basic /-! # Multiplicative actions with zero on and by `Mˣ` @@ -23,7 +24,39 @@ admits a `MulDistribMulAction G Mˣ` structure, again with the obvious definitio * `Algebra.GroupWithZero.Action.Prod` -/ -variable {G M α : Type*} +variable {G M α β : Type*} + +section GroupWithZero +variable [GroupWithZero α] [MulAction α β] {a : α} + +@[simp] lemma inv_smul_smul₀ (ha : a ≠ 0) (x : β) : a⁻¹ • a • x = x := + inv_smul_smul (Units.mk0 a ha) x + +@[simp] +lemma smul_inv_smul₀ (ha : a ≠ 0) (x : β) : a • a⁻¹ • x = x := smul_inv_smul (Units.mk0 a ha) x + +lemma inv_smul_eq_iff₀ (ha : a ≠ 0) {x y : β} : a⁻¹ • x = y ↔ x = a • y := + inv_smul_eq_iff (g := Units.mk0 a ha) + +lemma eq_inv_smul_iff₀ (ha : a ≠ 0) {x y : β} : x = a⁻¹ • y ↔ a • x = y := + eq_inv_smul_iff (g := Units.mk0 a ha) + +@[simp] +lemma Commute.smul_right_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {x y : β} + (ha : a ≠ 0) : Commute x (a • y) ↔ Commute x y := Commute.smul_right_iff (g := Units.mk0 a ha) + +@[simp] +lemma Commute.smul_left_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {x y : β} + (ha : a ≠ 0) : Commute (a • x) y ↔ Commute x y := Commute.smul_left_iff (g := Units.mk0 a ha) + +/-- Right scalar multiplication as an order isomorphism. -/ +@[simps] def Equiv.smulRight (ha : a ≠ 0) : β ≃ β where + toFun b := a • b + invFun b := a⁻¹ • b + left_inv := inv_smul_smul₀ ha + right_inv := smul_inv_smul₀ ha + +end GroupWithZero namespace Units diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index 26f0af2649201..c09c2c9f7742f 100644 --- a/Mathlib/Algebra/GroupWithZero/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Basic.lean @@ -37,7 +37,7 @@ assert_not_exists DenselyOrdered open Function -variable {α M₀ G₀ M₀' G₀' F F' : Type*} +variable {M₀ G₀ : Type*} section @@ -136,7 +136,7 @@ theorem right_ne_zero_of_mul_eq_one (h : a * b = 1) : b ≠ 0 := end section MonoidWithZero -variable [MonoidWithZero M₀] {a : M₀} {m n : ℕ} +variable [MonoidWithZero M₀] {a : M₀} {n : ℕ} @[simp] lemma zero_pow : ∀ {n : ℕ}, n ≠ 0 → (0 : M₀) ^ n = 0 | n + 1, _ => by rw [pow_succ, mul_zero] @@ -146,7 +146,10 @@ lemma zero_pow_eq (n : ℕ) : (0 : M₀) ^ n = if n = 0 then 1 else 0 := by · rw [h, pow_zero] · rw [zero_pow h] -lemma pow_eq_zero_of_le : ∀ {m n} (hmn : m ≤ n) (ha : a ^ m = 0), a ^ n = 0 +lemma zero_pow_eq_one₀ [Nontrivial M₀] : (0 : M₀) ^ n = 1 ↔ n = 0 := by + rw [zero_pow_eq, one_ne_zero.ite_eq_left_iff] + +lemma pow_eq_zero_of_le : ∀ {m n} (_ : m ≤ n) (_ : a ^ m = 0), a ^ n = 0 | _, _, Nat.le.refl, ha => ha | _, _, Nat.le.step hmn, ha => by rw [pow_succ, pow_eq_zero_of_le hmn ha, zero_mul] @@ -156,6 +159,11 @@ lemma ne_zero_pow (hn : n ≠ 0) (ha : a ^ n ≠ 0) : a ≠ 0 := by rintro rfl; lemma zero_pow_eq_zero [Nontrivial M₀] : (0 : M₀) ^ n = 0 ↔ n ≠ 0 := ⟨by rintro h rfl; simp at h, zero_pow⟩ +lemma pow_mul_eq_zero_of_le {a b : M₀} {m n : ℕ} (hmn : m ≤ n) + (h : a ^ m * b = 0) : a ^ n * b = 0 := by + rw [show n = n - m + m by omega, pow_add, mul_assoc, h] + simp + variable [NoZeroDivisors M₀] lemma pow_eq_zero : ∀ {n}, a ^ n = 0 → a = 0 @@ -234,7 +242,7 @@ end CancelMonoidWithZero section GroupWithZero -variable [GroupWithZero G₀] {a b c g h x : G₀} +variable [GroupWithZero G₀] {a b x : G₀} theorem GroupWithZero.mul_left_injective (h : x ≠ 0) : Function.Injective fun y => x * y := fun y y' w => by @@ -384,6 +392,9 @@ lemma zero_zpow_eq (n : ℤ) : (0 : G₀) ^ n = if n = 0 then 1 else 0 := by · rw [h, zpow_zero] · rw [zero_zpow _ h] +lemma zero_zpow_eq_one₀ {n : ℤ} : (0 : G₀) ^ n = 1 ↔ n = 0 := by + rw [zero_zpow_eq, one_ne_zero.ite_eq_left_iff] + lemma zpow_add_one₀ (ha : a ≠ 0) : ∀ n : ℤ, a ^ (n + 1) = a ^ n * a | (n : ℕ) => by simp only [← Int.ofNat_succ, zpow_natCast, pow_succ] | .negSucc 0 => by erw [zpow_zero, zpow_negSucc, pow_one, inv_mul_cancel₀ ha] diff --git a/Mathlib/Algebra/GroupWithZero/Commute.lean b/Mathlib/Algebra/GroupWithZero/Commute.lean index 24a2a0afe674b..5190f384c283e 100644 --- a/Mathlib/Algebra/GroupWithZero/Commute.lean +++ b/Mathlib/Algebra/GroupWithZero/Commute.lean @@ -83,7 +83,7 @@ theorem div_left (hac : Commute a c) (hbc : Commute b c) : Commute (a / b) c := end Commute section GroupWithZero -variable {G₀ : Type*} [GroupWithZero G₀] +variable [GroupWithZero G₀] theorem pow_inv_comm₀ (a : G₀) (m n : ℕ) : a⁻¹ ^ m * a ^ n = a ^ n * a⁻¹ ^ m := (Commute.refl a).inv_left₀.pow_pow m n diff --git a/Mathlib/Algebra/GroupWithZero/Defs.lean b/Mathlib/Algebra/GroupWithZero/Defs.lean index 78481e6ef63c0..221f060ebda9a 100644 --- a/Mathlib/Algebra/GroupWithZero/Defs.lean +++ b/Mathlib/Algebra/GroupWithZero/Defs.lean @@ -26,7 +26,7 @@ universe u -- We have to fix the universe of `G₀` here, since the default argument to -- `GroupWithZero.div'` cannot contain a universe metavariable. -variable {G₀ : Type u} {M₀ M₀' G₀' : Type*} +variable {G₀ : Type u} {M₀ : Type*} /-- Typeclass for expressing that a type `M₀` with multiplication and a zero satisfies `0 * a = 0` and `a * 0 = 0` for all `a : M₀`. -/ @@ -182,16 +182,15 @@ Examples include division rings and the ordered monoids that are the target of valuations in general valuation theory. -/ class GroupWithZero (G₀ : Type u) extends MonoidWithZero G₀, DivInvMonoid G₀, Nontrivial G₀ where /-- The inverse of `0` in a group with zero is `0`. -/ - inv_zero : (0 : G₀)⁻¹ = 0 + protected inv_zero : (0 : G₀)⁻¹ = 0 /-- Every nonzero element of a group with zero is invertible. -/ protected mul_inv_cancel (a : G₀) : a ≠ 0 → a * a⁻¹ = 1 -export GroupWithZero (inv_zero) -attribute [simp] inv_zero - section GroupWithZero variable [GroupWithZero G₀] {a : G₀} +@[simp] lemma inv_zero : (0 : G₀)⁻¹ = 0 := GroupWithZero.inv_zero + @[simp] lemma mul_inv_cancel₀ (h : a ≠ 0) : a * a⁻¹ = 1 := GroupWithZero.mul_inv_cancel a h -- See note [lower instance priority] diff --git a/Mathlib/Algebra/GroupWithZero/Divisibility.lean b/Mathlib/Algebra/GroupWithZero/Divisibility.lean index 9b07a41369654..c2ff18e038a60 100644 --- a/Mathlib/Algebra/GroupWithZero/Divisibility.lean +++ b/Mathlib/Algebra/GroupWithZero/Divisibility.lean @@ -139,9 +139,6 @@ theorem dvd_antisymm : a ∣ b → b ∣ a → a = b := by rw [mul_assoc, eq_comm, mul_right_eq_self₀, mul_eq_one] at hcd obtain ⟨rfl, -⟩ | rfl := hcd <;> simp --- Porting note: `attribute [protected]` is currently unsupported --- attribute [protected] Nat.dvd_antisymm --This lemma is in core, so we protect it here - theorem dvd_antisymm' : a ∣ b → b ∣ a → b = a := flip dvd_antisymm diff --git a/Mathlib/Algebra/GroupWithZero/Hom.lean b/Mathlib/Algebra/GroupWithZero/Hom.lean index 75d6481cf412f..e4d19ee977799 100644 --- a/Mathlib/Algebra/GroupWithZero/Hom.lean +++ b/Mathlib/Algebra/GroupWithZero/Hom.lean @@ -39,6 +39,13 @@ open Function namespace NeZero variable {F α β : Type*} [Zero α] [Zero β] [FunLike F α β] [ZeroHomClass F α β] {a : α} +#adaptation_note +/-- +We name `neZero` so it can be used as a named argument, +but since https://github.com/leanprover/lean4/pull/5338, this is considered unused, +so we need to disable the linter. +-/ +set_option linter.unusedVariables false in lemma of_map (f : F) [neZero : NeZero (f a)] : NeZero a := ⟨fun h ↦ ne (f a) <| by rw [h]; exact ZeroHomClass.map_zero f⟩ diff --git a/Mathlib/Algebra/GroupWithZero/Indicator.lean b/Mathlib/Algebra/GroupWithZero/Indicator.lean index 7ad962522c252..52d9d31a8d50e 100644 --- a/Mathlib/Algebra/GroupWithZero/Indicator.lean +++ b/Mathlib/Algebra/GroupWithZero/Indicator.lean @@ -16,7 +16,7 @@ variable {ι κ G₀ M₀ R : Type*} namespace Set section MulZeroClass -variable [MulZeroClass M₀] {s t : Set ι} {f g : ι → M₀} {i : ι} +variable [MulZeroClass M₀] {s t : Set ι} {i : ι} lemma indicator_mul (s : Set ι) (f g : ι → M₀) : indicator s (fun i ↦ f i * g i) = fun i ↦ indicator s f i * indicator s g i := by diff --git a/Mathlib/Algebra/GroupWithZero/InjSurj.lean b/Mathlib/Algebra/GroupWithZero/InjSurj.lean index 26278384167c1..75dc801b0bbb6 100644 --- a/Mathlib/Algebra/GroupWithZero/InjSurj.lean +++ b/Mathlib/Algebra/GroupWithZero/InjSurj.lean @@ -149,7 +149,7 @@ end MonoidWithZero section CancelMonoidWithZero -variable [CancelMonoidWithZero M₀] {a b c : M₀} +variable [CancelMonoidWithZero M₀] /-- Pull back a `CancelMonoidWithZero` along an injective function. See note [reducible non-instances]. -/ @@ -159,15 +159,15 @@ protected abbrev Function.Injective.cancelMonoidWithZero [Zero M₀'] [Mul M₀' CancelMonoidWithZero M₀' := { hf.monoid f one mul npow, hf.mulZeroClass f zero mul with mul_left_cancel_of_ne_zero := fun hx H => - hf <| mul_left_cancel₀ ((hf.ne_iff' zero).2 hx) <| by erw [← mul, ← mul, H], + hf <| mul_left_cancel₀ ((hf.ne_iff' zero).2 hx) <| by rw [← mul, ← mul, H], mul_right_cancel_of_ne_zero := fun hx H => - hf <| mul_right_cancel₀ ((hf.ne_iff' zero).2 hx) <| by erw [← mul, ← mul, H] } + hf <| mul_right_cancel₀ ((hf.ne_iff' zero).2 hx) <| by rw [← mul, ← mul, H] } end CancelMonoidWithZero section CancelCommMonoidWithZero -variable [CancelCommMonoidWithZero M₀] {a b c : M₀} +variable [CancelCommMonoidWithZero M₀] /-- Pull back a `CancelCommMonoidWithZero` along an injective function. See note [reducible non-instances]. -/ @@ -181,7 +181,7 @@ end CancelCommMonoidWithZero section GroupWithZero -variable [GroupWithZero G₀] {a b c g h x : G₀} +variable [GroupWithZero G₀] /-- Pull back a `GroupWithZero` along an injective function. See note [reducible non-instances]. -/ @@ -193,9 +193,9 @@ protected abbrev Function.Injective.groupWithZero [Zero G₀'] [Mul G₀'] [One { hf.monoidWithZero f zero one mul npow, hf.divInvMonoid f one mul inv div npow zpow, pullback_nonzero f zero one with - inv_zero := hf <| by erw [inv, zero, inv_zero], + inv_zero := hf <| by rw [inv, zero, inv_zero], mul_inv_cancel := fun x hx => hf <| by - erw [one, mul, inv, mul_inv_cancel₀ ((hf.ne_iff' zero).2 hx)] } + rw [one, mul, inv, mul_inv_cancel₀ ((hf.ne_iff' zero).2 hx)] } /-- Push forward a `GroupWithZero` along a surjective function. See note [reducible non-instances]. -/ @@ -206,16 +206,16 @@ protected abbrev Function.Surjective.groupWithZero [Zero G₀'] [Mul G₀'] [One (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (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 with - inv_zero := by erw [← zero, ← inv, inv_zero], + inv_zero := by rw [← zero, ← inv, inv_zero], mul_inv_cancel := hf.forall.2 fun x hx => by - erw [← inv, ← mul, mul_inv_cancel₀ (mt (congr_arg f) fun h ↦ hx (h.trans zero)), one] + rw [← inv, ← mul, mul_inv_cancel₀ (mt (congr_arg f) fun h ↦ hx (h.trans zero)), one] exists_pair_ne := ⟨0, 1, h01⟩ } end GroupWithZero section CommGroupWithZero -variable [CommGroupWithZero G₀] {a b c d : G₀} +variable [CommGroupWithZero G₀] /-- Pull back a `CommGroupWithZero` along an injective function. See note [reducible non-instances]. -/ diff --git a/Mathlib/Algebra/GroupWithZero/Invertible.lean b/Mathlib/Algebra/GroupWithZero/Invertible.lean index 6895aebeb4888..73b809c2847b2 100644 --- a/Mathlib/Algebra/GroupWithZero/Invertible.lean +++ b/Mathlib/Algebra/GroupWithZero/Invertible.lean @@ -80,7 +80,6 @@ theorem div_self_of_invertible (a : α) [Invertible a] : a / a = 1 := def invertibleDiv (a b : α) [Invertible a] [Invertible b] : Invertible (a / b) := ⟨b / a, by simp [← mul_div_assoc], by simp [← mul_div_assoc]⟩ --- Porting note (#10618): removed `simp` attribute as `simp` can prove it theorem invOf_div (a b : α) [Invertible a] [Invertible b] [Invertible (a / b)] : ⅟ (a / b) = b / a := invOf_eq_right_inv (by simp [← mul_div_assoc]) diff --git a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean index 2c4e1832cb5a3..f28e2198589e2 100644 --- a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean +++ b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean @@ -214,7 +214,7 @@ theorem map_mem_nonZeroDivisors [Nontrivial M] [NoZeroDivisors M'] [ZeroHomClass theorem le_nonZeroDivisors_of_noZeroDivisors [NoZeroDivisors M] {S : Submonoid M} (hS : (0 : M) ∉ S) : S ≤ M⁰ := fun _ hx _ hy ↦ - Or.recOn (eq_zero_or_eq_zero_of_mul_eq_zero hy) (fun h ↦ h) fun h ↦ + Or.recOn (eq_zero_or_eq_zero_of_mul_eq_zero hy) id fun h ↦ absurd (h ▸ hx : (0 : M) ∈ S) hS theorem powers_le_nonZeroDivisors_of_noZeroDivisors [NoZeroDivisors M] {a : M} (ha : a ≠ 0) : diff --git a/Mathlib/Algebra/GroupWithZero/Pi.lean b/Mathlib/Algebra/GroupWithZero/Pi.lean index 547f6a5013092..f11c9daf124b3 100644 --- a/Mathlib/Algebra/GroupWithZero/Pi.lean +++ b/Mathlib/Algebra/GroupWithZero/Pi.lean @@ -22,7 +22,7 @@ variable {ι : Type*} {α : ι → Type*} namespace Pi section MulZeroClass -variable [∀ i, MulZeroClass (α i)] [DecidableEq ι] {i j : ι} {f : ∀ i, α i} +variable [∀ i, MulZeroClass (α i)] [DecidableEq ι] {i : ι} {f : ∀ i, α i} instance mulZeroClass : MulZeroClass (∀ i, α i) where zero_mul := by intros; ext; exact zero_mul _ diff --git a/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean new file mode 100644 index 0000000000000..7d763b441f0c9 --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean @@ -0,0 +1,209 @@ +/- +Copyright (c) 2021 Yaël Dillies, Bhavik Mehta. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies, Bhavik Mehta +-/ +import Mathlib.Algebra.Group.Pointwise.Finset.Basic + +/-! +# Pointwise operations of finsets in a group with zero + +This file proves properties of pointwise operations of finsets in a group with zero. +-/ + +-- TODO +-- assert_not_exists Ring + +open scoped Pointwise + +namespace Finset +variable {α β : Type*} [DecidableEq β] + +/-- If scalar multiplication by elements of `α` sends `(0 : β)` to zero, +then the same is true for `(0 : Finset β)`. -/ +protected def smulZeroClass [Zero β] [SMulZeroClass α β] : SMulZeroClass α (Finset β) := + coe_injective.smulZeroClass ⟨(↑), coe_zero⟩ coe_smul_finset + +/-- If the scalar multiplication `(· • ·) : α → β → β` is distributive, +then so is `(· • ·) : α → Finset β → Finset β`. -/ +protected def distribSMul [AddZeroClass β] [DistribSMul α β] : DistribSMul α (Finset β) := + coe_injective.distribSMul coeAddMonoidHom coe_smul_finset + +/-- A distributive multiplicative action of a monoid on an additive monoid `β` gives a distributive +multiplicative action on `Finset β`. -/ +protected def distribMulAction [Monoid α] [AddMonoid β] [DistribMulAction α β] : + DistribMulAction α (Finset β) := + coe_injective.distribMulAction coeAddMonoidHom coe_smul_finset + +/-- A multiplicative action of a monoid on a monoid `β` gives a multiplicative action on `Set β`. -/ +protected def mulDistribMulAction [Monoid α] [Monoid β] [MulDistribMulAction α β] : + MulDistribMulAction α (Finset β) := + coe_injective.mulDistribMulAction coeMonoidHom coe_smul_finset + +scoped[Pointwise] attribute [instance] Finset.smulZeroClass Finset.distribSMul + Finset.distribMulAction Finset.mulDistribMulAction + +instance [DecidableEq α] [Zero α] [Mul α] [NoZeroDivisors α] : NoZeroDivisors (Finset α) := + Function.Injective.noZeroDivisors (↑) coe_injective coe_zero coe_mul + +instance noZeroSMulDivisors [Zero α] [Zero β] [SMul α β] [NoZeroSMulDivisors α β] : + NoZeroSMulDivisors (Finset α) (Finset β) where + eq_zero_or_eq_zero_of_smul_eq_zero {s t} := by + exact_mod_cast eq_zero_or_eq_zero_of_smul_eq_zero (c := s.toSet) (x := t.toSet) + +instance noZeroSMulDivisors_finset [Zero α] [Zero β] [SMul α β] [NoZeroSMulDivisors α β] : + NoZeroSMulDivisors α (Finset β) := + Function.Injective.noZeroSMulDivisors (↑) coe_injective coe_zero coe_smul_finset + +section SMulZeroClass +variable [Zero β] [SMulZeroClass α β] {s : Finset α} {t : Finset β} {a : α} + +lemma smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] + +lemma Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := + s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs + +lemma zero_mem_smul_finset (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := + mem_smul_finset.2 ⟨0, h, smul_zero _⟩ + +variable [Zero α] [NoZeroSMulDivisors α β] + +lemma zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by + rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] + +end SMulZeroClass + +section SMulWithZero +variable [Zero α] [Zero β] [SMulWithZero α β] {s : Finset α} {t : Finset β} + +/-! +Note that we have neither `SMulWithZero α (Finset β)` nor `SMulWithZero (Finset α) (Finset β)` +because `0 • ∅ ≠ 0`. +-/ + +lemma zero_smul_subset (t : Finset β) : (0 : Finset α) • t ⊆ 0 := by simp [subset_iff, mem_smul] + +lemma Nonempty.zero_smul (ht : t.Nonempty) : (0 : Finset α) • t = 0 := + t.zero_smul_subset.antisymm <| by simpa [mem_smul] using ht + +/-- A nonempty set is scaled by zero to the singleton set containing zero. -/ +@[simp] lemma zero_smul_finset {s : Finset β} (h : s.Nonempty) : (0 : α) • s = (0 : Finset β) := + coe_injective <| by simpa using @Set.zero_smul_set α _ _ _ _ _ h + +lemma zero_smul_finset_subset (s : Finset β) : (0 : α) • s ⊆ 0 := + image_subset_iff.2 fun x _ ↦ mem_zero.2 <| zero_smul α x + +variable [NoZeroSMulDivisors α β] + +lemma zero_mem_smul_iff : + (0 : β) ∈ s • t ↔ (0 : α) ∈ s ∧ t.Nonempty ∨ (0 : β) ∈ t ∧ s.Nonempty := by + rw [← mem_coe, coe_smul, Set.zero_mem_smul_iff]; rfl + +end SMulWithZero + +section MulZeroClass +variable [DecidableEq α] [MulZeroClass α] {s : Finset α} + +/-! Note that `Finset` is not a `MulZeroClass` because `0 * ∅ ≠ 0`. -/ + +lemma mul_zero_subset (s : Finset α) : s * 0 ⊆ 0 := by simp [subset_iff, mem_mul] +lemma zero_mul_subset (s : Finset α) : 0 * s ⊆ 0 := by simp [subset_iff, mem_mul] + +lemma Nonempty.mul_zero (hs : s.Nonempty) : s * 0 = 0 := + s.mul_zero_subset.antisymm <| by simpa [mem_mul] using hs + +lemma Nonempty.zero_mul (hs : s.Nonempty) : 0 * s = 0 := + s.zero_mul_subset.antisymm <| by simpa [mem_mul] using hs + +end MulZeroClass + +section GroupWithZero +variable [GroupWithZero α] + +section MulAction +variable [MulAction α β] {s t : Finset β} {a : α} {b : β} + +@[simp] lemma smul_mem_smul_finset_iff₀ (ha : a ≠ 0) : a • b ∈ a • s ↔ b ∈ s := + smul_mem_smul_finset_iff (Units.mk0 a ha) + +lemma inv_smul_mem_iff₀ (ha : a ≠ 0) : a⁻¹ • b ∈ s ↔ b ∈ a • s := + show _ ↔ _ ∈ Units.mk0 a ha • _ from inv_smul_mem_iff + +lemma mem_inv_smul_finset_iff₀ (ha : a ≠ 0) : b ∈ a⁻¹ • s ↔ a • b ∈ s := + show _ ∈ (Units.mk0 a ha)⁻¹ • _ ↔ _ from mem_inv_smul_finset_iff + +@[simp] +lemma smul_finset_subset_smul_finset_iff₀ (ha : a ≠ 0) : a • s ⊆ a • t ↔ s ⊆ t := + show Units.mk0 a ha • _ ⊆ _ ↔ _ from smul_finset_subset_smul_finset_iff + +lemma smul_finset_subset_iff₀ (ha : a ≠ 0) : a • s ⊆ t ↔ s ⊆ a⁻¹ • t := + show Units.mk0 a ha • _ ⊆ _ ↔ _ from smul_finset_subset_iff + +lemma subset_smul_finset_iff₀ (ha : a ≠ 0) : s ⊆ a • t ↔ a⁻¹ • s ⊆ t := + show _ ⊆ Units.mk0 a ha • _ ↔ _ from subset_smul_finset_iff + +lemma smul_finset_inter₀ (ha : a ≠ 0) : a • (s ∩ t) = a • s ∩ a • t := + image_inter _ _ <| MulAction.injective₀ ha + +lemma smul_finset_sdiff₀ (ha : a ≠ 0) : a • (s \ t) = a • s \ a • t := + image_sdiff _ _ <| MulAction.injective₀ ha + +open scoped symmDiff in +lemma smul_finset_symmDiff₀ (ha : a ≠ 0) : a • s ∆ t = (a • s) ∆ (a • t) := + image_symmDiff _ _ <| MulAction.injective₀ ha + +lemma smul_finset_univ₀ [Fintype β] (ha : a ≠ 0) : a • (univ : Finset β) = univ := + coe_injective <| by push_cast; exact Set.smul_set_univ₀ ha + +lemma smul_univ₀ [Fintype β] {s : Finset α} (hs : ¬s ⊆ 0) : s • (univ : Finset β) = univ := + coe_injective <| by + rw [← coe_subset] at hs + push_cast at hs ⊢ + exact Set.smul_univ₀ hs + +lemma smul_univ₀' [Fintype β] {s : Finset α} (hs : s.Nontrivial) : s • (univ : Finset β) = univ := + coe_injective <| by push_cast; exact Set.smul_univ₀' hs + +end MulAction + +variable [DecidableEq α] {s : Finset α} + +lemma div_zero_subset (s : Finset α) : s / 0 ⊆ 0 := by simp [subset_iff, mem_div] + +lemma zero_div_subset (s : Finset α) : 0 / s ⊆ 0 := by simp [subset_iff, mem_div] + +lemma Nonempty.div_zero (hs : s.Nonempty) : s / 0 = 0 := + s.div_zero_subset.antisymm <| by simpa [mem_div] using hs + +lemma Nonempty.zero_div (hs : s.Nonempty) : 0 / s = 0 := + s.zero_div_subset.antisymm <| by simpa [mem_div] using hs + +@[simp] protected lemma inv_zero : (0 : Finset α)⁻¹ = 0 := by ext; simp + +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₀, *] + +@[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₀, *] + +end GroupWithZero + +section Monoid +variable [Monoid α] [AddGroup β] [DistribMulAction α β] + +@[simp] +lemma smul_finset_neg (a : α) (t : Finset β) : a • -t = -(a • t) := by + simp only [← image_smul, ← image_neg, Function.comp_def, image_image, smul_neg] + +@[simp] +protected lemma smul_neg (s : Finset α) (t : Finset β) : s • -t = -(s • t) := by + simp_rw [← image_neg]; exact image_image₂_right_comm smul_neg + +end Monoid +end Finset diff --git a/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean new file mode 100644 index 0000000000000..8466c8876f1c1 --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean @@ -0,0 +1,27 @@ +/- +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.Set.Basic +import Mathlib.Algebra.GroupWithZero.Action.Basic +import Mathlib.SetTheory.Cardinal.Finite + +/-! +# Cardinality of sets under pointwise group with zero operations +-/ + +open scoped Cardinal Pointwise + +variable {G G₀ M M₀ : Type*} + +namespace Set +variable [GroupWithZero G₀] [Zero M₀] [MulActionWithZero G₀ M₀] {a : G₀} + +lemma _root_.Cardinal.mk_smul_set₀ (ha : a ≠ 0) (s : Set M₀) : #↥(a • s) = #s := + Cardinal.mk_image_eq_of_injOn _ _ (MulAction.injective₀ ha).injOn + +lemma natCard_smul_set₀ (ha : a ≠ 0) (s : Set M₀) : Nat.card ↥(a • s) = Nat.card s := + Nat.card_image_of_injective (MulAction.injective₀ ha) _ + +end Set diff --git a/Mathlib/Algebra/GroupWithZero/Units/Basic.lean b/Mathlib/Algebra/GroupWithZero/Units/Basic.lean index a32ad81fb22e8..7f2b3f9ec3ad8 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Algebra.GroupWithZero.Basic import Mathlib.Logic.Equiv.Defs import Mathlib.Tactic.Contrapose @@ -23,7 +23,7 @@ We also define `Ring.inverse`, a globally defined function on any ring assert_not_exists Multiplicative assert_not_exists DenselyOrdered -variable {α M₀ G₀ M₀' G₀' F F' : Type*} +variable {α M₀ G₀ : Type*} variable [MonoidWithZero M₀] namespace Units @@ -87,6 +87,12 @@ noncomputable def inverse : M₀ → M₀ := fun x => if h : IsUnit x then ((h.u theorem inverse_unit (u : M₀ˣ) : inverse (u : M₀) = (u⁻¹ : M₀ˣ) := by rw [inverse, dif_pos u.isUnit, IsUnit.unit_of_val_units] +theorem IsUnit.ringInverse {x : M₀} (h : IsUnit x) : IsUnit (inverse x) := + match h with + | ⟨u, hu⟩ => hu ▸ ⟨u⁻¹, (inverse_unit u).symm⟩ + +theorem inverse_of_isUnit {x : M₀} (h : IsUnit x) : inverse x = ((h.unit⁻¹ : M₀ˣ) : M₀) := dif_pos h + /-- By definition, if `x` is not invertible then `inverse x = 0`. -/ @[simp] theorem inverse_non_unit (x : M₀) (h : ¬IsUnit x) : inverse x = 0 := @@ -152,7 +158,6 @@ theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a := namespace Units variable [GroupWithZero G₀] -variable {a b : G₀} /-- Embed a non-zero element of a `GroupWithZero` into the unit group. By combining this function with the operations on units, @@ -208,7 +213,7 @@ theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ end Units section GroupWithZero -variable [GroupWithZero G₀] {a b c d : G₀} {m n : ℕ} +variable [GroupWithZero G₀] {a b c : G₀} {m n : ℕ} theorem IsUnit.mk0 (x : G₀) (hx : x ≠ 0) : IsUnit x := (Units.mk0 x hx).isUnit diff --git a/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean b/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean index bbf5c0a8dc88f..2d5790637992e 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean @@ -15,10 +15,37 @@ import Mathlib.Algebra.GroupWithZero.Hom assert_not_exists DenselyOrdered -variable {α M₀ G₀ M₀' G₀' F F' : Type*} +variable {M M₀ G₀ M₀' G₀' F F' : Type*} variable [MonoidWithZero M₀] +section Monoid + +variable [Monoid M] [GroupWithZero G₀] + +lemma isLocalHom_of_exists_map_ne_one [FunLike F G₀ M] [MonoidHomClass F G₀ M] {f : F} + (hf : ∃ x : G₀, f x ≠ 1) : IsLocalHom f where + map_nonunit a h := by + rcases eq_or_ne a 0 with (rfl | h) + · obtain ⟨t, ht⟩ := hf + refine (ht ?_).elim + have := map_mul f t 0 + rw [← one_mul (f (t * 0)), mul_zero] at this + exact (h.mul_right_cancel this).symm + · exact ⟨⟨a, a⁻¹, mul_inv_cancel₀ h, inv_mul_cancel₀ h⟩, rfl⟩ + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_of_exists_map_ne_one := isLocalHom_of_exists_map_ne_one + +instance [GroupWithZero G₀] [FunLike F G₀ M₀] [MonoidWithZeroHomClass F G₀ M₀] [Nontrivial M₀] + (f : F) : IsLocalHom f := + isLocalHom_of_exists_map_ne_one ⟨0, by simp⟩ + +end Monoid + +section GroupWithZero + namespace Commute + variable [GroupWithZero G₀] {a b c d : G₀} /-- The `MonoidWithZero` version of `div_eq_div_iff_mul_eq_mul`. -/ @@ -107,3 +134,5 @@ end Units theorem map_zpow₀ {F G₀ G₀' : Type*} [GroupWithZero G₀] [GroupWithZero G₀'] [FunLike F G₀ G₀'] [MonoidWithZeroHomClass F G₀ G₀'] (f : F) (x : G₀) (n : ℤ) : f (x ^ n) = f x ^ n := map_zpow' f (map_inv₀ f) x n + +end GroupWithZero diff --git a/Mathlib/Algebra/GroupWithZero/WithZero.lean b/Mathlib/Algebra/GroupWithZero/WithZero.lean index 9790623ef1ff9..66c0edd8d8c17 100644 --- a/Mathlib/Algebra/GroupWithZero/WithZero.lean +++ b/Mathlib/Algebra/GroupWithZero/WithZero.lean @@ -157,10 +157,10 @@ instance monoidWithZero [Monoid α] : MonoidWithZero (WithZero α) where npow n a := a ^ n npow_zero a := match a with | none => rfl - | some a => congr_arg some (pow_zero _) + | some _ => congr_arg some (pow_zero _) npow_succ n a := match a with | none => by change 0 ^ (n + 1) = 0 ^ n * 0; simp only [mul_zero]; rfl - | some a => congr_arg some <| pow_succ _ _ + | some _ => congr_arg some <| pow_succ _ _ instance commMonoidWithZero [CommMonoid α] : CommMonoidWithZero (WithZero α) := { WithZero.monoidWithZero, WithZero.commSemigroup with } @@ -212,13 +212,13 @@ instance divInvMonoid [DivInvMonoid α] : DivInvMonoid (WithZero α) where zpow n a := a ^ n zpow_zero' a := match a with | none => rfl - | some a => congr_arg some (zpow_zero _) + | some _ => congr_arg some (zpow_zero _) zpow_succ' n a := match a with | none => by change 0 ^ _ = 0 ^ _ * 0; simp only [mul_zero]; rfl - | some a => congr_arg some (DivInvMonoid.zpow_succ' _ _) - zpow_neg' n a := match a with + | some _ => congr_arg some (DivInvMonoid.zpow_succ' _ _) + zpow_neg' _ a := match a with | none => rfl - | some a => congr_arg some (DivInvMonoid.zpow_neg' _ _) + | some _ => congr_arg some (DivInvMonoid.zpow_neg' _ _) instance divInvOneMonoid [DivInvOneMonoid α] : DivInvOneMonoid (WithZero α) where __ := divInvMonoid @@ -232,14 +232,14 @@ instance divisionMonoid [DivisionMonoid α] : DivisionMonoid (WithZero α) where __ := involutiveInv mul_inv_rev a b := match a, b with | none, none => rfl - | none, some b => rfl - | some a, none => rfl - | some a, some b => congr_arg some (mul_inv_rev _ _) + | none, some _ => rfl + | some _, none => rfl + | some _, some _ => congr_arg some (mul_inv_rev _ _) inv_eq_of_mul a b := match a, b with | none, none => fun _ ↦ rfl | none, some b => fun _ ↦ by contradiction | some a, none => fun _ ↦ by contradiction - | some a, some b => fun h ↦ + | some _, some _ => fun h ↦ congr_arg some <| inv_eq_of_mul_eq_one_right <| Option.some_injective _ h instance divisionCommMonoid [DivisionCommMonoid α] : DivisionCommMonoid (WithZero α) where diff --git a/Mathlib/Algebra/Homology/Additive.lean b/Mathlib/Algebra/Homology/Additive.lean index 85979eabec627..5fbebb2c8beb9 100644 --- a/Mathlib/Algebra/Homology/Additive.lean +++ b/Mathlib/Algebra/Homology/Additive.lean @@ -29,7 +29,7 @@ variable (f g : C ⟶ D) (h k : D ⟶ E) (i : ι) namespace HomologicalComplex instance : Zero (C ⟶ D) := - ⟨{ f := fun i => 0 }⟩ + ⟨{ f := fun _ => 0 }⟩ instance : Add (C ⟶ D) := ⟨fun f g => { f := fun i => f.f i + g.f i }⟩ @@ -133,7 +133,7 @@ isomorphic to the identity functor. -/ @[simps!] def Functor.mapHomologicalComplexIdIso (c : ComplexShape ι) : (𝟭 W₁).mapHomologicalComplex c ≅ 𝟭 _ := - NatIso.ofComponents fun K => Hom.isoOfComponents fun i => Iso.refl _ + NatIso.ofComponents fun K => Hom.isoOfComponents fun _ => Iso.refl _ instance Functor.mapHomologicalComplex_reflects_iso (F : W₁ ⥤ W₂) [F.PreservesZeroMorphisms] [ReflectsIsomorphisms F] (c : ComplexShape ι) : @@ -155,7 +155,7 @@ between those functors applied to homological complexes. def NatTrans.mapHomologicalComplex {F G : W₁ ⥤ W₂} [F.PreservesZeroMorphisms] [G.PreservesZeroMorphisms] (α : F ⟶ G) (c : ComplexShape ι) : F.mapHomologicalComplex c ⟶ G.mapHomologicalComplex c where - app C := { f := fun i => α.app _ } + app C := { f := fun _ => α.app _ } @[simp] theorem NatTrans.mapHomologicalComplex_id diff --git a/Mathlib/Algebra/Homology/Augment.lean b/Mathlib/Algebra/Homology/Augment.lean index c72e003fc7557..e9554f54c2961 100644 --- a/Mathlib/Algebra/Homology/Augment.lean +++ b/Mathlib/Algebra/Homology/Augment.lean @@ -55,7 +55,7 @@ def augment (C : ChainComplex V ℕ) {X : V} (f : C.X 0 ⟶ X) (w : C.d 1 0 ≫ | _, _ => 0 shape | 1, 0, h => absurd rfl h - | i + 2, 0, _ => rfl + | _ + 2, 0, _ => rfl | 0, _, _ => rfl | i + 1, j + 1, h => by simp only; exact C.shape i j (Nat.succ_ne_succ.1 h) @@ -88,9 +88,9 @@ to the original complex. -/ def truncateAugment (C : ChainComplex V ℕ) {X : V} (f : C.X 0 ⟶ X) (w : C.d 1 0 ≫ f = 0) : truncate.obj (augment C f w) ≅ C where - hom := { f := fun i => 𝟙 _ } + hom := { f := fun _ => 𝟙 _ } inv := - { f := fun i => 𝟙 _ + { f := fun _ => 𝟙 _ comm' := fun i j => by cases j <;> · dsimp @@ -125,7 +125,7 @@ theorem chainComplex_d_succ_succ_zero (C : ChainComplex V ℕ) (i : ℕ) : C.d ( def augmentTruncate (C : ChainComplex V ℕ) : augment (truncate.obj C) (C.d 1 0) (C.d_comp_d _ _ _) ≅ C where hom := - { f := fun | 0 => 𝟙 _ | n+1 => 𝟙 _ + { f := fun | 0 => 𝟙 _ | _+1 => 𝟙 _ comm' := fun i j => by -- Porting note: was an rcases n with (_|_|n) but that was causing issues match i with @@ -133,7 +133,7 @@ def augmentTruncate (C : ChainComplex V ℕ) : cases' j with j <;> dsimp [augment, truncate] <;> simp } inv := - { f := fun | 0 => 𝟙 _ | n+1 => 𝟙 _ + { f := fun | 0 => 𝟙 _ | _+1 => 𝟙 _ comm' := fun i j => by -- Porting note: was an rcases n with (_|_|n) but that was causing issues match i with @@ -259,9 +259,9 @@ to the original complex. -/ def truncateAugment (C : CochainComplex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : f ≫ C.d 0 1 = 0) : truncate.obj (augment C f w) ≅ C where - hom := { f := fun i => 𝟙 _ } + hom := { f := fun _ => 𝟙 _ } inv := - { f := fun i => 𝟙 _ + { f := fun _ => 𝟙 _ comm' := fun i j => by cases j <;> · dsimp @@ -300,14 +300,14 @@ theorem cochainComplex_d_succ_succ_zero (C : CochainComplex V ℕ) (i : ℕ) : C def augmentTruncate (C : CochainComplex V ℕ) : augment (truncate.obj C) (C.d 0 1) (C.d_comp_d _ _ _) ≅ C where hom := - { f := fun | 0 => 𝟙 _ | n+1 => 𝟙 _ + { f := fun | 0 => 𝟙 _ | _+1 => 𝟙 _ comm' := fun i j => by rcases j with (_ | _ | j) <;> cases i <;> · dsimp -- Porting note (#10959): simp can't handle this now but aesop does aesop } inv := - { f := fun | 0 => 𝟙 _ | n+1 => 𝟙 _ + { f := fun | 0 => 𝟙 _ | _+1 => 𝟙 _ comm' := fun i j => by rcases j with (_ | _ | j) <;> cases' i with i <;> · dsimp diff --git a/Mathlib/Algebra/Homology/BifunctorShift.lean b/Mathlib/Algebra/Homology/BifunctorShift.lean index 4f6b9ee6aabb4..b5493653d24f8 100644 --- a/Mathlib/Algebra/Homology/BifunctorShift.lean +++ b/Mathlib/Algebra/Homology/BifunctorShift.lean @@ -67,7 +67,7 @@ def mapBifunctorHomologicalComplexShift₁Iso : ((F.mapBifunctorHomologicalComplex _ _).obj (K₁⟦x⟧)).obj K₂ ≅ (HomologicalComplex₂.shiftFunctor₁ D x).obj (((F.mapBifunctorHomologicalComplex _ _).obj K₁).obj K₂) := - HomologicalComplex.Hom.isoOfComponents (fun i₁ => Iso.refl _) + HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) instance : HasMapBifunctor (K₁⟦x⟧) K₂ F := HomologicalComplex₂.hasTotal_of_iso (mapBifunctorHomologicalComplexShift₁Iso K₁ K₂ F x).symm _ @@ -95,7 +95,7 @@ def mapBifunctorHomologicalComplexShift₂Iso : (HomologicalComplex₂.shiftFunctor₂ D y).obj (((F.mapBifunctorHomologicalComplex _ _).obj K₁).obj K₂) := HomologicalComplex.Hom.isoOfComponents - (fun i₁ => HomologicalComplex.Hom.isoOfComponents (fun i₂ => Iso.refl _)) + (fun i₁ => HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _)) instance : HasMapBifunctor K₁ (K₂⟦y⟧) F := HomologicalComplex₂.hasTotal_of_iso (mapBifunctorHomologicalComplexShift₂Iso K₁ K₂ F y).symm _ diff --git a/Mathlib/Algebra/Homology/ConcreteCategory.lean b/Mathlib/Algebra/Homology/ConcreteCategory.lean index 8d0b74ba8ec07..ec495e24a7d91 100644 --- a/Mathlib/Algebra/Homology/ConcreteCategory.lean +++ b/Mathlib/Algebra/Homology/ConcreteCategory.lean @@ -75,21 +75,20 @@ lemma δ_apply (x₃ : (forget₂ C Ab).obj (S.X₃.X i)) (forget₂ C Ab).map (S.X₁.homologyπ j) (S.X₁.cyclesMk x₁ k hk (by have := hS.mono_f apply (Preadditive.mono_iff_injective (S.f.f k)).1 inferInstance - erw [← forget₂_comp_apply, ← HomologicalComplex.Hom.comm, forget₂_comp_apply, hx₁, + rw [← forget₂_comp_apply, ← HomologicalComplex.Hom.comm, forget₂_comp_apply, hx₁, ← forget₂_comp_apply, HomologicalComplex.d_comp_d, Functor.map_zero, map_zero, AddMonoidHom.zero_apply])) := by refine hS.δ_apply' i j hij _ ((forget₂ C Ab).map (S.X₂.pOpcycles i) x₂) _ ?_ ?_ - · erw [← forget₂_comp_apply, ← forget₂_comp_apply, + · rw [← forget₂_comp_apply, ← forget₂_comp_apply, HomologicalComplex.p_opcyclesMap, Functor.map_comp, comp_apply, HomologicalComplex.homology_π_ι, forget₂_comp_apply, hx₂, HomologicalComplex.i_cyclesMk] · apply (Preadditive.mono_iff_injective (S.X₂.iCycles j)).1 inferInstance conv_lhs => - erw [← forget₂_comp_apply, HomologicalComplex.cyclesMap_i, forget₂_comp_apply, + rw [← forget₂_comp_apply, HomologicalComplex.cyclesMap_i, forget₂_comp_apply, HomologicalComplex.i_cyclesMk, hx₁] conv_rhs => - erw [← forget₂_comp_apply, ← forget₂_comp_apply, + rw [← forget₂_comp_apply, ← forget₂_comp_apply, HomologicalComplex.pOpcycles_opcyclesToCycles_assoc, HomologicalComplex.toCycles_i] - rfl end ShortExact diff --git a/Mathlib/Algebra/Homology/Functor.lean b/Mathlib/Algebra/Homology/Functor.lean index 81f80b27fe33b..7560ad47ae5ed 100644 --- a/Mathlib/Algebra/Homology/Functor.lean +++ b/Mathlib/Algebra/Homology/Functor.lean @@ -37,15 +37,15 @@ def asFunctor {T : Type*} [Category T] (C : HomologicalComplex (T ⥤ V) c) : d := fun i j => (C.d i j).app t d_comp_d' := fun i j k _ _ => by have := C.d_comp_d i j k - rw [NatTrans.ext_iff, Function.funext_iff] at this + rw [NatTrans.ext_iff, funext_iff] at this exact this t shape := fun i j h => by have := C.shape _ _ h - rw [NatTrans.ext_iff, Function.funext_iff] at this + rw [NatTrans.ext_iff, funext_iff] at this exact this t } map h := { f := fun i => (C.X i).map h - comm' := fun i j _ => NatTrans.naturality _ _ } + comm' := fun _ _ _ => NatTrans.naturality _ _ } map_id t := by ext i dsimp diff --git a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean index dbd85f9d8e710..634f2df3056f2 100644 --- a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean +++ b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean @@ -149,7 +149,7 @@ def flip (K : HomologicalComplex₂ C c₁ c₂) : HomologicalComplex₂ C c₂ X i := { X := fun j => (K.X j).X i d := fun j j' => (K.d j j').f i - shape := fun j j' w => K.shape_f _ _ w i } + shape := fun _ _ w => K.shape_f _ _ w i } d i i' := { f := fun j => (K.X j).d i i' } shape i i' w := by ext j @@ -176,7 +176,7 @@ def flipFunctor : def flipEquivalenceUnitIso : 𝟭 (HomologicalComplex₂ C c₁ c₂) ≅ flipFunctor C c₁ c₂ ⋙ flipFunctor C c₂ c₁ := NatIso.ofComponents (fun K => HomologicalComplex.Hom.isoOfComponents (fun i₁ => - HomologicalComplex.Hom.isoOfComponents (fun i₂ => Iso.refl _) + HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) (by aesop_cat)) (by aesop_cat)) (by aesop_cat) /-- Auxiliary definition for `HomologicalComplex₂.flipEquivalence`. -/ @@ -184,7 +184,7 @@ def flipEquivalenceUnitIso : def flipEquivalenceCounitIso : flipFunctor C c₂ c₁ ⋙ flipFunctor C c₁ c₂ ≅ 𝟭 (HomologicalComplex₂ C c₂ c₁) := NatIso.ofComponents (fun K => HomologicalComplex.Hom.isoOfComponents (fun i₂ => - HomologicalComplex.Hom.isoOfComponents (fun i₁ => Iso.refl _) + HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) (by aesop_cat)) (by aesop_cat)) (by aesop_cat) /-- Flipping a complex of complexes over the diagonal, as an equivalence of categories. -/ diff --git a/Mathlib/Algebra/Homology/HomologicalComplex.lean b/Mathlib/Algebra/Homology/HomologicalComplex.lean index 2494b21c2eb58..03b17997ea652 100644 --- a/Mathlib/Algebra/Homology/HomologicalComplex.lean +++ b/Mathlib/Algebra/Homology/HomologicalComplex.lean @@ -224,7 +224,7 @@ theorem Hom.comm {A B : HomologicalComplex V c} (f : A.Hom B) (i j : ι) : · rw [A.shape i j hij, B.shape i j hij, comp_zero, zero_comp] instance (A B : HomologicalComplex V c) : Inhabited (Hom A B) := - ⟨{ f := fun i => 0 }⟩ + ⟨{ f := fun _ => 0 }⟩ /-- Identity chain map. -/ def id (A : HomologicalComplex V c) : Hom A A where f _ := 𝟙 _ @@ -244,7 +244,6 @@ instance : Category (HomologicalComplex V c) where end --- Porting note: added because `Hom.ext` is not triggered automatically @[ext] lemma hom_ext {C D : HomologicalComplex V c} (f g : C ⟶ D) (h : ∀ i, f.f i = g.f i) : f = g := by @@ -273,7 +272,7 @@ theorem hom_f_injective {C₁ C₂ : HomologicalComplex V c} : Function.Injective fun f : Hom C₁ C₂ => f.f := by aesop_cat instance (X Y : HomologicalComplex V c) : Zero (X ⟶ Y) := - ⟨{ f := fun i => 0}⟩ + ⟨{ f := fun _ => 0}⟩ @[simp] theorem zero_f (C D : HomologicalComplex V c) (i : ι) : (0 : C ⟶ D).f i = 0 := @@ -346,7 +345,7 @@ instance : (forget V c).Faithful where just picking out the `i`-th object. -/ @[simps!] def forgetEval (i : ι) : forget V c ⋙ GradedObject.eval i ≅ eval V c i := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ end @@ -549,14 +548,14 @@ theorem next_eq (f : Hom C₁ C₂) {i j : ι} (w : c.Rel i j) : obtain rfl := c.next_eq' w simp only [xNextIso, eqToIso_refl, Iso.refl_hom, Iso.refl_inv, comp_id, id_comp] -@[reassoc, elementwise] -- @[simp] -- Porting note (#10618): simp can prove this +@[reassoc, elementwise] theorem comm_from (f : Hom C₁ C₂) (i : ι) : f.f i ≫ C₂.dFrom i = C₁.dFrom i ≫ f.next i := f.comm _ _ attribute [simp 1100] comm_from_assoc attribute [simp] comm_from_apply -@[reassoc, elementwise] -- @[simp] -- Porting note (#10618): simp can prove this +@[reassoc, elementwise] theorem comm_to (f : Hom C₁ C₂) (j : ι) : f.prev j ≫ C₂.dTo j = C₁.dTo j ≫ f.f j := f.comm _ _ diff --git a/Mathlib/Algebra/Homology/HomologicalComplexLimits.lean b/Mathlib/Algebra/Homology/HomologicalComplexLimits.lean index 2589bf52e1e50..0e2a446e27264 100644 --- a/Mathlib/Algebra/Homology/HomologicalComplexLimits.lean +++ b/Mathlib/Algebra/Homology/HomologicalComplexLimits.lean @@ -66,7 +66,7 @@ noncomputable def coneOfHasLimitEval : Cone F where dsimp rw [(F.obj j).shape _ _ h, comp_zero, zero_comp] } π := - { app := fun j => { f := fun n => limit.π _ j } + { app := fun j => { f := fun _ => limit.π _ j } naturality := fun i j φ => by ext n dsimp diff --git a/Mathlib/Algebra/Homology/Homotopy.lean b/Mathlib/Algebra/Homology/Homotopy.lean index f8c43c0d2b844..82243da05a6b3 100644 --- a/Mathlib/Algebra/Homology/Homotopy.lean +++ b/Mathlib/Algebra/Homology/Homotopy.lean @@ -131,11 +131,11 @@ namespace Homotopy def equivSubZero : Homotopy f g ≃ Homotopy (f - g) 0 where toFun h := { hom := fun i j => h.hom i j - zero := fun i j w => h.zero _ _ w + zero := fun _ _ w => h.zero _ _ w comm := fun i => by simp [h.comm] } invFun h := { hom := fun i j => h.hom i j - zero := fun i j w => h.zero _ _ w + zero := fun _ _ w => h.zero _ _ w comm := fun i => by simpa [sub_eq_iff_eq_add] using h.comm i } left_inv := by aesop_cat right_inv := by aesop_cat diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/DegreewiseSplit.lean b/Mathlib/Algebra/Homology/HomotopyCategory/DegreewiseSplit.lean index a8ad46dc1d626..57c6b0f92cedd 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/DegreewiseSplit.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/DegreewiseSplit.lean @@ -70,7 +70,6 @@ noncomputable abbrev trianglehOfDegreewiseSplit : variable [HasBinaryBiproducts C] -set_option tactic.skipAssignedInstances false in /-- The canonical isomorphism `(mappingCone (homOfDegreewiseSplit S σ)).X p ≅ S.X₂.X q` when `p + 1 = q`. -/ noncomputable def mappingConeHomOfDegreewiseSplitXIso (p q : ℤ) (hpq : p + 1 = q) : @@ -104,7 +103,9 @@ noncomputable def mappingConeHomOfDegreewiseSplitXIso (p q : ℤ) (hpq : p + 1 = mappingCone.inl_v_snd_v_assoc, mappingCone.inr_f_snd_v_assoc, zero_sub, sub_neg_eq_add, ← h] abel -set_option backward.isDefEq.lazyWhnfCore false in -- See https://github.com/leanprover-community/mathlib4/issues/12534 +-- See https://github.com/leanprover-community/mathlib4/issues/12534 +-- Removing this adds about 7% to the instruction count in this file. +set_option backward.isDefEq.lazyWhnfCore false in /-- The canonical isomorphism `mappingCone (homOfDegreewiseSplit S σ) ≅ S.X₂⟦(1 : ℤ)⟧`. -/ @[simps!] noncomputable def mappingConeHomOfDegreewiseSplitIso : @@ -114,7 +115,6 @@ noncomputable def mappingConeHomOfDegreewiseSplitIso : have r_f := (σ (p + 1 + 1)).r_f have s_g := (σ (p + 1)).s_g dsimp at r_f s_g - set_option tactic.skipAssignedInstances false in simp [mappingConeHomOfDegreewiseSplitXIso, mappingCone.ext_from_iff _ _ _ rfl, mappingCone.inl_v_d_assoc _ (p + 1) _ (p + 1 + 1) (by linarith) (by linarith), cocycleOfDegreewiseSplit, r_f] diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean index d5e210fe2d0c1..78e5edc499ba5 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean @@ -323,13 +323,11 @@ noncomputable def shiftTriangleIso (n : ℤ) : Triangle.mk_obj₂, Triangle.mk_mor₁, Preadditive.smul_iso_hom, Iso.refl_hom, Linear.comp_smul, comp_id, smul_smul, Int.units_coe_mul_self, one_smul, id_comp] · ext p - set_option tactic.skipAssignedInstances false in dsimp simp only [Units.smul_def, shiftIso, Int.reduceNeg, Linear.smul_comp, id_comp, ext_to_iff _ _ (p + 1) rfl, shiftFunctor_obj_X', assoc, lift_f_fst_v, Cocycle.coe_smul, Cocycle.shift_coe, Cochain.smul_v, Cochain.shift_v', Linear.comp_smul, inr_f_fst_v, smul_zero, lift_f_snd_v, inr_f_snd_v, and_true] - rw [smul_zero] · ext p dsimp simp only [triangle, Triangle.mk_mor₃, Cocycle.homOf_f, Cocycle.rightShift_coe, diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean index 9341e60b09122..ccbab125d8ff9 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean @@ -40,7 +40,7 @@ multiplies the differentials by `(-1)^n`. -/ def shiftFunctor (n : ℤ) : CochainComplex C ℤ ⥤ CochainComplex C ℤ where obj K := { X := fun i => K.X (i + n) - d := fun i j => n.negOnePow • K.d _ _ + d := fun _ _ => n.negOnePow • K.d _ _ d_comp_d' := by intros simp only [Linear.comp_units_smul, Linear.units_smul_comp, d_comp_d, smul_zero] @@ -52,7 +52,7 @@ def shiftFunctor (n : ℤ) : CochainComplex C ℤ ⥤ CochainComplex C ℤ where dsimp at hij' ⊢ omega } map φ := - { f := fun i => φ.f _ + { f := fun _ => φ.f _ comm' := by intros dsimp @@ -244,7 +244,7 @@ instance commShiftMapCochainComplex : ext rw [CommShift.isoAdd_hom_app] dsimp - erw [id_comp, id_comp] + rw [id_comp, id_comp] simp only [CochainComplex.shiftFunctorAdd_hom_app_f, CochainComplex.shiftFunctorAdd_inv_app_f, HomologicalComplex.XIsoOfEq, eqToIso, eqToHom_map, eqToHom_trans, eqToHom_refl] @@ -273,7 +273,7 @@ variable {C} between `φ₁⟦n⟧'` and `φ₂⟦n⟧'`. -/ def shift {K L : CochainComplex C ℤ} {φ₁ φ₂ : K ⟶ L} (h : Homotopy φ₁ φ₂) (n : ℤ) : Homotopy (φ₁⟦n⟧') (φ₂⟦n⟧') where - hom i j := n.negOnePow • h.hom _ _ + hom _ _ := n.negOnePow • h.hom _ _ zero i j hij := by dsimp rw [h.zero, smul_zero] diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/ShiftSequence.lean b/Mathlib/Algebra/Homology/HomotopyCategory/ShiftSequence.lean index 190ca3c42f6fe..9984135144e10 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/ShiftSequence.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/ShiftSequence.lean @@ -29,7 +29,9 @@ open HomologicalComplex attribute [local simp] XIsoOfEq_hom_naturality smul_smul -set_option backward.isDefEq.lazyWhnfCore false in -- See https://github.com/leanprover-community/mathlib4/issues/12534 +-- See https://github.com/leanprover-community/mathlib4/issues/12534 +-- Removing this adds about 10% to the instruction count in this file. +set_option backward.isDefEq.lazyWhnfCore false in /-- The natural isomorphism `(K⟦n⟧).sc' i j k ≅ K.sc' i' j' k'` when `n + i = i'`, `n + j = j'` and `n + k = k'`. -/ @[simps!] diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Triangulated.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Triangulated.lean index b49421f3f25b8..85cb5a4752ba7 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Triangulated.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Triangulated.lean @@ -61,7 +61,7 @@ noncomputable def hom : (descCochain _ 0 (Cochain.ofHom (inr (f ≫ g))) (neg_add_cancel 1)) (by ext p _ rfl simp [mappingConeCompTriangle, map, ext_from_iff _ _ _ rfl, - inl_v_d_assoc _ (p+1) p (p+2) (by linarith) (by linarith)]) + inl_v_d_assoc _ (p+1) p (p+2) (by omega) (by omega)]) /-- Given two composable morphisms `f` and `g` in the category of cochain complexes, this is the canonical morphism (which is an homotopy equivalence) from the mapping cone of @@ -72,7 +72,7 @@ noncomputable def inv : mappingCone (mappingConeCompTriangle f g).mor₁ ⟶ map ext p rw [ext_from_iff _ (p + 1) _ rfl, ext_to_iff _ _ (p + 1) rfl] simp [map, δ_zero_cochain_comp, - Cochain.comp_v _ _ (add_neg_cancel 1) p (p+1) p (by linarith) (by linarith)]) + Cochain.comp_v _ _ (add_neg_cancel 1) p (p+1) p (by omega) (by omega)]) @[reassoc (attr := simp)] lemma hom_inv_id : hom f g ≫ inv f g = 𝟙 _ := by @@ -86,44 +86,25 @@ this is the `homotopyInvHomId` field of the homotopy equivalence the morphism `mappingCone f ⟶ mappingCone (f ≫ g)`. -/ noncomputable def homotopyInvHomId : Homotopy (inv f g ≫ hom f g) (𝟙 _) := (Cochain.equivHomotopy _ _).symm ⟨-((snd _).comp ((fst (f ≫ g)).1.comp - ((inl f).comp (inl _) (by linarith)) (show 1 + (-2) = -1 by linarith)) (zero_add (-1))), by + ((inl f).comp (inl _) (by omega)) (show 1 + (-2) = -1 by omega)) (zero_add (-1))), by rw [δ_neg, δ_zero_cochain_comp _ _ _ (neg_add_cancel 1), Int.negOnePow_neg, Int.negOnePow_one, Units.neg_smul, one_smul, - δ_comp _ _ (show 1 + (-2) = -1 by linarith) 2 (-1) 0 (by linarith) - (by linarith) (by linarith), - δ_comp _ _ (show (-1) + (-1) = -2 by linarith) 0 0 (-1) (by linarith) - (by linarith) (by linarith), Int.negOnePow_neg, Int.negOnePow_neg, - Int.negOnePow_even 2 ⟨1, by linarith⟩, Int.negOnePow_one, Units.neg_smul, + δ_comp _ _ (show 1 + (-2) = -1 by omega) 2 (-1) 0 (by omega) + (by omega) (by omega), + δ_comp _ _ (show (-1) + (-1) = -2 by omega) 0 0 (-1) (by omega) + (by omega) (by omega), Int.negOnePow_neg, Int.negOnePow_neg, + Int.negOnePow_even 2 ⟨1, by omega⟩, Int.negOnePow_one, Units.neg_smul, one_smul, one_smul, δ_inl, δ_inl, δ_snd, Cocycle.δ_eq_zero, Cochain.zero_comp, add_zero, Cochain.neg_comp, neg_neg] ext n rw [ext_from_iff _ (n + 1) n rfl, ext_from_iff _ (n + 1) n rfl, - ext_from_iff _ (n + 2) (n + 1) (by linarith)] - simp? [hom, inv, ext_to_iff _ n (n + 1) rfl, map, Cochain.comp_v _ _ - (add_neg_cancel 1) n (n + 1) n (by linarith) (by linarith), - Cochain.comp_v _ _ (show 1 + -2 = -1 by linarith) (n + 1) (n + 2) n - (by linarith) (by linarith), - Cochain.comp_v _ _ (show (-1) + -1 = -2 by linarith) (n + 2) (n + 1) n - (by linarith) (by linarith)] says - simp only [mappingConeCompTriangle_obj₁, mappingConeCompTriangle_obj₂, - mappingConeCompTriangle_mor₁, map, Int.reduceNeg, inv, hom, Cochain.ofHom_comp, - ofHom_desc, ofHom_lift, descCocycle_coe, AddSubmonoid.coe_zero, - Cochain.comp_zero_cochain_v, inl_v_descCochain_v_assoc, Cochain.zero_cochain_comp_v, - assoc, inl_v_snd_v_assoc, zero_comp, Cochain.id_comp, - Cochain.comp_assoc_of_first_is_zero_cochain, Cochain.comp_add, Cochain.comp_neg, - Cochain.comp_assoc_of_second_is_zero_cochain, neg_add_rev, neg_neg, Cochain.add_v, - Cochain.neg_v, - Cochain.comp_v _ _ (add_neg_cancel 1) n (n + 1) n (by linarith) (by linarith), - Cochain.comp_v _ _ (show 1 + -2 = -1 by linarith) (n + 1) (n + 2) n (by linarith) - (by linarith), - Cochain.comp_v _ _ (show (-1) + -1 = -2 by linarith) (n + 2) (n + 1) n (by linarith) - (by linarith), - Cochain.ofHom_v, HomologicalComplex.id_f, Preadditive.comp_add, Preadditive.comp_neg, - inl_v_fst_v_assoc, neg_zero, add_zero, comp_id, neg_add_cancel, inr_f_snd_v_assoc, - inr_f_descCochain_v_assoc, inr_f_fst_v_assoc, comp_zero, zero_add, - ext_to_iff _ n (n + 1) rfl, liftCochain_v_fst_v, inl_v_descCochain_v, inl_v_fst_v, - liftCochain_v_snd_v, Cochain.zero_v, inl_v_snd_v, and_self, neg_add_cancel_right, - inr_f_descCochain_v, inr_f_fst_v, inr_f_snd_v]⟩ + ext_from_iff _ (n + 2) (n + 1) (by omega)] + simp [hom, inv, ext_to_iff _ n (n + 1) rfl, map, Cochain.comp_v _ _ + (add_neg_cancel 1) n (n + 1) n (by omega) (by omega), + Cochain.comp_v _ _ (show 1 + -2 = -1 by omega) (n + 1) (n + 2) n + (by omega) (by omega), + Cochain.comp_v _ _ (show (-1) + -1 = -2 by omega) (n + 2) (n + 1) n + (by omega) (by omega)]⟩ end MappingConeCompHomotopyEquiv diff --git a/Mathlib/Algebra/Homology/HomotopyCofiber.lean b/Mathlib/Algebra/Homology/HomotopyCofiber.lean index dfbe3a72907ca..c09675a4982fc 100644 --- a/Mathlib/Algebra/Homology/HomotopyCofiber.lean +++ b/Mathlib/Algebra/Homology/HomotopyCofiber.lean @@ -245,7 +245,7 @@ noncomputable def inrCompHomotopy (hc : ∀ j, ∃ i, c.Rel i j) : Homotopy (φ ≫ inr φ) 0 where hom i j := if hij : c.Rel j i then inlX φ i j hij else 0 - zero i j hij := dif_neg hij + zero _ _ hij := dif_neg hij comm j := by obtain ⟨i, hij⟩ := hc j rw [prevD_eq _ hij, dif_pos hij] diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean index 4ea0bfce99d36..f8d4b17460856 100644 --- a/Mathlib/Algebra/Homology/LocalCohomology.lean +++ b/Mathlib/Algebra/Homology/LocalCohomology.lean @@ -206,26 +206,13 @@ def idealPowersToSelfLERadical (J : Ideal R) : ℕᵒᵖ ⥤ SelfLERadical J := variable {I J K : Ideal R} -/-- The lemma below essentially says that `idealPowersToSelfLERadical I` is initial in -`selfLERadicalDiagram I`. - -Porting note: This lemma should probably be moved to `Mathlib/RingTheory/Finiteness` -to be near `Ideal.exists_radical_pow_le_of_fg`, which it generalizes. -/ -theorem Ideal.exists_pow_le_of_le_radical_of_fG (hIJ : I ≤ J.radical) (hJ : J.radical.FG) : - ∃ k : ℕ, I ^ k ≤ J := by - obtain ⟨k, hk⟩ := J.exists_radical_pow_le_of_fg hJ - use k - calc - I ^ k ≤ J.radical ^ k := Ideal.pow_right_mono hIJ _ - _ ≤ J := hk - /-- The diagram of powers of `J` is initial in the diagram of all ideals with radical containing `J`. This uses noetherianness. -/ instance ideal_powers_initial [hR : IsNoetherian R R] : Functor.Initial (idealPowersToSelfLERadical J) where out J' := by apply (config := {allowSynthFailures := true }) zigzag_isConnected - · obtain ⟨k, hk⟩ := Ideal.exists_pow_le_of_le_radical_of_fG J'.2 (isNoetherian_def.mp hR _) + · obtain ⟨k, hk⟩ := Ideal.exists_pow_le_of_le_radical_of_fg J'.2 (isNoetherian_def.mp hR _) exact ⟨CostructuredArrow.mk (⟨⟨hk⟩⟩ : (idealPowersToSelfLERadical J).obj (op k) ⟶ J')⟩ · intro j1 j2 apply Relation.ReflTransGen.single diff --git a/Mathlib/Algebra/Homology/Localization.lean b/Mathlib/Algebra/Homology/Localization.lean index 197ad242ab355..9401e72715760 100644 --- a/Mathlib/Algebra/Homology/Localization.lean +++ b/Mathlib/Algebra/Homology/Localization.lean @@ -223,8 +223,8 @@ def ComplexShape.strictUniversalPropertyFixedTargetQuotient (E : Type*) [Categor intro K L f g ⟨h⟩ have : DecidableRel c.Rel := by classical infer_instance exact h.map_eq_of_inverts_homotopyEquivalences hc F hF) - fac F hF := rfl - uniq F₁ F₂ h := Quotient.lift_unique' _ _ _ h + fac _ _ := rfl + uniq _ _ h := Quotient.lift_unique' _ _ _ h lemma ComplexShape.quotient_isLocalization : (HomotopyCategory.quotient C c).IsLocalization diff --git a/Mathlib/Algebra/Homology/Opposite.lean b/Mathlib/Algebra/Homology/Opposite.lean index ae00fdfe5a5f1..ba39dfe50ab4e 100644 --- a/Mathlib/Algebra/Homology/Opposite.lean +++ b/Mathlib/Algebra/Homology/Opposite.lean @@ -123,7 +123,7 @@ def opInverse : HomologicalComplex Vᵒᵖ c.symm ⥤ (HomologicalComplex V c) def opUnitIso : 𝟭 (HomologicalComplex V c)ᵒᵖ ≅ opFunctor V c ⋙ opInverse V c := NatIso.ofComponents (fun X => - (HomologicalComplex.Hom.isoOfComponents (fun i => Iso.refl _) fun i j _ => by + (HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) fun i j _ => by simp only [Iso.refl_hom, Category.id_comp, unopSymm_d, op_d, Quiver.Hom.unop_op, Category.comp_id] : (Opposite.unop X).op.unopSymm ≅ unop X).op) @@ -138,7 +138,7 @@ def opUnitIso : 𝟭 (HomologicalComplex V c)ᵒᵖ ≅ opFunctor V c ⋙ opInve /-- Auxiliary definition for `opEquivalence`. -/ def opCounitIso : opInverse V c ⋙ opFunctor V c ≅ 𝟭 (HomologicalComplex Vᵒᵖ c.symm) := NatIso.ofComponents - fun X => HomologicalComplex.Hom.isoOfComponents fun i => Iso.refl _ + fun X => HomologicalComplex.Hom.isoOfComponents fun _ => Iso.refl _ /-- Given a category of complexes with objects in `V`, there is a natural equivalence between its opposite category and a category of complexes with objects in `Vᵒᵖ`. -/ @@ -174,7 +174,7 @@ def unopInverse : HomologicalComplex V c.symm ⥤ (HomologicalComplex Vᵒᵖ c) def unopUnitIso : 𝟭 (HomologicalComplex Vᵒᵖ c)ᵒᵖ ≅ unopFunctor V c ⋙ unopInverse V c := NatIso.ofComponents (fun X => - (HomologicalComplex.Hom.isoOfComponents (fun i => Iso.refl _) fun i j _ => by + (HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) fun i j _ => by simp only [Iso.refl_hom, Category.id_comp, unopSymm_d, op_d, Quiver.Hom.unop_op, Category.comp_id] : (Opposite.unop X).op.unopSymm ≅ unop X).op) @@ -189,7 +189,7 @@ def unopUnitIso : 𝟭 (HomologicalComplex Vᵒᵖ c)ᵒᵖ ≅ unopFunctor V c /-- Auxiliary definition for `unopEquivalence`. -/ def unopCounitIso : unopInverse V c ⋙ unopFunctor V c ≅ 𝟭 (HomologicalComplex V c.symm) := NatIso.ofComponents - fun X => HomologicalComplex.Hom.isoOfComponents fun i => Iso.refl _ + fun X => HomologicalComplex.Hom.isoOfComponents fun _ => Iso.refl _ /-- Given a category of complexes with objects in `Vᵒᵖ`, there is a natural equivalence between its opposite category and a category of complexes with objects in `V`. -/ diff --git a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean index 474f801a48272..393b22f24e512 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean @@ -37,7 +37,7 @@ variable (S : ShortComplex Ab.{u}) @[simp] lemma ab_zero_apply (x : S.X₁) : S.g (S.f x) = 0 := by - erw [← comp_apply, S.zero] + rw [← comp_apply, S.zero] rfl /-- The canonical additive morphism `S.X₁ →+ AddMonoidHom.ker S.g` induced by `S.f`. -/ @@ -81,7 +81,7 @@ noncomputable def abCyclesIso : S.cycles ≅ AddCommGrp.of (AddMonoidHom.ker S.g lemma abCyclesIso_inv_apply_iCycles (x : AddMonoidHom.ker S.g) : S.iCycles (S.abCyclesIso.inv x) = x := by dsimp only [abCyclesIso] - erw [← comp_apply, S.abLeftHomologyData.cyclesIso_inv_comp_iCycles] + rw [← comp_apply, S.abLeftHomologyData.cyclesIso_inv_comp_iCycles] rfl /-- Given a short complex `S` of abelian groups, this is the isomorphism between @@ -129,7 +129,7 @@ lemma ab_exact_iff_range_eq_ker : S.Exact ↔ S.f.range = S.g.ker := by · intro h refine le_antisymm ?_ h rintro _ ⟨x₁, rfl⟩ - erw [AddMonoidHom.mem_ker, ← comp_apply, S.zero] + rw [AddMonoidHom.mem_ker, ← comp_apply, S.zero] rfl · intro h rw [h] diff --git a/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean b/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean index 2c1cd6db62c31..51fd7a82b8752 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean @@ -32,7 +32,7 @@ lemma ShortComplex.zero_apply [Limits.HasZeroMorphisms C] [(forget₂ C Ab).PreservesZeroMorphisms] (S : ShortComplex C) (x : (forget₂ C Ab).obj S.X₁) : ((forget₂ C Ab).map S.g) (((forget₂ C Ab).map S.f) x) = 0 := by - erw [← comp_apply, ← Functor.map_comp, S.zero, Functor.map_zero] + rw [← comp_apply, ← Functor.map_comp, S.zero, Functor.map_zero] rfl section preadditive diff --git a/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean b/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean index 7523eadd214dd..59034f288455b 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.ofHom f) (ModuleCat.ofHom g) hfg + ShortComplex.mk (ModuleCat.asHom f) (ModuleCat.asHom g) hfg variable (S : ShortComplex (ModuleCat.{v} R)) @@ -138,7 +138,7 @@ def moduleCatLeftHomologyData : S.LeftHomologyData where erw [Submodule.Quotient.mk_eq_zero] rw [LinearMap.mem_range] apply exists_apply_eq_apply - hπ := ModuleCat.cokernelIsColimit (ModuleCat.ofHom S.moduleCatToCycles) + hπ := ModuleCat.cokernelIsColimit (ModuleCat.asHom S.moduleCatToCycles) @[simp] lemma moduleCatLeftHomologyData_f' : diff --git a/Mathlib/Algebra/Homology/ShortComplex/SnakeLemma.lean b/Mathlib/Algebra/Homology/ShortComplex/SnakeLemma.lean index 77769d32f3b80..8fe3dbac06932 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/SnakeLemma.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/SnakeLemma.lean @@ -381,7 +381,7 @@ variable (S₁ S₂ S₃ : SnakeInput C) /-- A morphism of snake inputs involve four morphisms of short complexes which make the obvious diagram commute. -/ @[ext] -structure Hom := +structure Hom where /-- a morphism between the zeroth lines -/ f₀ : S₁.L₀ ⟶ S₂.L₀ /-- a morphism between the first lines -/ diff --git a/Mathlib/Algebra/Homology/Single.lean b/Mathlib/Algebra/Homology/Single.lean index 6adb409ebcd24..a9cbef23cd3c9 100644 --- a/Mathlib/Algebra/Homology/Single.lean +++ b/Mathlib/Algebra/Homology/Single.lean @@ -34,7 +34,7 @@ variable {ι : Type*} [DecidableEq ι] (c : ComplexShape ι) noncomputable def single (j : ι) : V ⥤ HomologicalComplex V c where obj A := { X := fun i => if i = j then A else 0 - d := fun i j => 0 } + d := fun _ _ => 0 } map f := { f := fun i => if h : i = j then eqToHom (by dsimp; rw [if_pos h]) ≫ f ≫ eqToHom (by dsimp; rw [if_pos h]) else 0 } @@ -201,7 +201,7 @@ lemma single₀_map_f_zero {A B : V} (f : A ⟶ B) : ((single₀ V).map f).f 0 = f := by rw [HomologicalComplex.single_map_f_self] dsimp [HomologicalComplex.singleObjXSelf, HomologicalComplex.singleObjXIsoOfEq] - erw [comp_id, id_comp] + rw [comp_id, id_comp] @[simp] @@ -269,7 +269,7 @@ lemma single₀_map_f_zero {A B : V} (f : A ⟶ B) : ((single₀ V).map f).f 0 = f := by rw [HomologicalComplex.single_map_f_self] dsimp [HomologicalComplex.singleObjXSelf, HomologicalComplex.singleObjXIsoOfEq] - erw [comp_id, id_comp] + rw [comp_id, id_comp] @[simp] lemma single₀ObjXSelf (X : V) : diff --git a/Mathlib/Algebra/Homology/Square.lean b/Mathlib/Algebra/Homology/Square.lean new file mode 100644 index 0000000000000..d2c3faea2d9aa --- /dev/null +++ b/Mathlib/Algebra/Homology/Square.lean @@ -0,0 +1,72 @@ +/- +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.CommSq +import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Square + +/-! +# Relation between pullback/pushout squares and kernel/cokernel sequences + +This file is the bundled counterpart of `Algebra.Homology.CommSq`. +The same results are obtained here for squares `sq : Square C` where +`C` is an additive category. + +-/ +namespace CategoryTheory + +open Category Limits + +namespace Square + +variable {C : Type*} [Category C] [Preadditive C] + (sq : Square C) [HasBinaryBiproduct sq.X₂ sq.X₃] + +/-- The cokernel cofork attached to a commutative square in a preadditive category. -/ +noncomputable abbrev cokernelCofork : + CokernelCofork (biprod.lift sq.f₁₂ (-sq.f₁₃)) := + CokernelCofork.ofπ (biprod.desc sq.f₂₄ sq.f₃₄) (by simp [sq.fac]) + +/-- A commutative square in a preadditive category is a pushout square iff +the corresponding diagram `X₁ ⟶ X₂ ⊞ X₃ ⟶ X₄ ⟶ 0` makes `X₄` a cokernel. -/ +noncomputable def isPushoutEquivIsColimitCokernelCofork : + sq.IsPushout ≃ IsColimit sq.cokernelCofork := + Equiv.trans + { toFun := fun h ↦ h.isColimit + invFun := fun h ↦ IsPushout.mk _ h + left_inv := fun _ ↦ rfl + right_inv := fun _ ↦ Subsingleton.elim _ _ } + sq.commSq.isColimitEquivIsColimitCokernelCofork + +variable {sq} in +/-- The colimit cokernel cofork attached to a pushout square. -/ +noncomputable def IsPushout.isColimitCokernelCofork (h : sq.IsPushout) : + IsColimit sq.cokernelCofork := + h.isColimitEquivIsColimitCokernelCofork h.isColimit + +/-- The kernel fork attached to a commutative square in a preadditive category. -/ +noncomputable abbrev kernelFork : + KernelFork (biprod.desc sq.f₂₄ (-sq.f₃₄)) := + KernelFork.ofι (biprod.lift sq.f₁₂ sq.f₁₃) (by simp [sq.fac]) + +/-- A commutative square in a preadditive category is a pullback square iff +the corresponding diagram `0 ⟶ X₁ ⟶ X₂ ⊞ X₃ ⟶ X₄ ⟶ 0` makes `X₁` a kernel. -/ +noncomputable def isPullbackEquivIsLimitKernelFork : + sq.IsPullback ≃ IsLimit sq.kernelFork := + Equiv.trans + { toFun := fun h ↦ h.isLimit + invFun := fun h ↦ IsPullback.mk _ h + left_inv := fun _ ↦ rfl + right_inv := fun _ ↦ Subsingleton.elim _ _ } + sq.commSq.isLimitEquivIsLimitKernelFork + +variable {sq} in +/-- The limit kernel fork attached to a pullback square. -/ +noncomputable def IsPullback.isLimitKernelFork (h : sq.IsPullback) : + IsLimit sq.kernelFork := + h.isLimitEquivIsLimitKernelFork h.isLimit + +end Square + +end CategoryTheory diff --git a/Mathlib/Algebra/IsPrimePow.lean b/Mathlib/Algebra/IsPrimePow.lean index 1aa00c6f31818..c21cf0363fe86 100644 --- a/Mathlib/Algebra/IsPrimePow.lean +++ b/Mathlib/Algebra/IsPrimePow.lean @@ -27,7 +27,7 @@ theorem isPrimePow_def : IsPrimePow n ↔ ∃ (p : R) (k : ℕ), Prime p ∧ 0 < natural `k` such that `n` can be written as `p^(k+1)`. -/ theorem isPrimePow_iff_pow_succ : IsPrimePow n ↔ ∃ (p : R) (k : ℕ), Prime p ∧ p ^ (k + 1) = n := (isPrimePow_def _).trans - ⟨fun ⟨p, k, hp, hk, hn⟩ => ⟨p, k - 1, hp, by rwa [Nat.sub_add_cancel hk]⟩, fun ⟨p, k, hp, hn⟩ => + ⟨fun ⟨p, k, hp, hk, hn⟩ => ⟨p, k - 1, hp, by rwa [Nat.sub_add_cancel hk]⟩, fun ⟨_, _, hp, hn⟩ => ⟨_, _, hp, Nat.succ_pos', hn⟩⟩ theorem not_isPrimePow_zero [NoZeroDivisors R] : ¬IsPrimePow (0 : R) := by diff --git a/Mathlib/Algebra/Lie/BaseChange.lean b/Mathlib/Algebra/Lie/BaseChange.lean index 232b3327a85d3..5ca3c13673a21 100644 --- a/Mathlib/Algebra/Lie/BaseChange.lean +++ b/Mathlib/Algebra/Lie/BaseChange.lean @@ -118,7 +118,7 @@ instance instLieRingModule : LieRingModule (A ⊗[R] L) (A ⊗[R] M) where instance instLieModule : LieModule A (A ⊗[R] L) (A ⊗[R] M) where smul_lie t x m := by simp only [bracket_def, map_smul, LinearMap.smul_apply] - lie_smul t x m := map_smul _ _ _ + lie_smul _ _ _ := map_smul _ _ _ end ExtendScalars @@ -223,25 +223,26 @@ lemma lie_baseChange {I : LieIdeal R L} {N : LieSubmodule R L M} : · rintro - ⟨x, hx, m, hm, rfl⟩ revert m apply Submodule.span_induction - (p := fun x' ↦ ∀ m' ∈ N.baseChange A, ⁅x', m'⁆ ∈ Submodule.span A s) hx + (p := fun x' _ ↦ ∀ m' ∈ N.baseChange A, ⁅x', m'⁆ ∈ Submodule.span A s) (hx := hx) · rintro _ ⟨y : L, hy : y ∈ I, rfl⟩ m hm - apply Submodule.span_induction (p := fun m' ↦ ⁅(1 : A) ⊗ₜ[R] y, m'⁆ ∈ Submodule.span A s) hm + apply Submodule.span_induction + (p := fun m' _ ↦ ⁅(1 : A) ⊗ₜ[R] y, m'⁆ ∈ Submodule.span A s) (hx := hm) · rintro - ⟨m', hm' : m' ∈ N, rfl⟩ rw [TensorProduct.mk_apply, LieAlgebra.ExtendScalars.bracket_tmul, mul_one] apply Submodule.subset_span exact ⟨y, hy, m', hm', rfl⟩ · simp - · intro u v hu hv + · intro u v _ _ hu hv rw [lie_add] exact Submodule.add_mem _ hu hv - · intro a u hu + · intro a u _ hu rw [lie_smul] exact Submodule.smul_mem _ a hu · simp - · intro x y hx hy m' hm' + · intro x y _ _ hx hy m' hm' rw [add_lie] exact Submodule.add_mem _ (hx _ hm') (hy _ hm') - · intro a x hx m' hm' + · intro a x _ hx m' hm' rw [smul_lie] exact Submodule.smul_mem _ a (hx _ hm') diff --git a/Mathlib/Algebra/Lie/Character.lean b/Mathlib/Algebra/Lie/Character.lean index 29b50665fe1db..24978ce025055 100644 --- a/Mathlib/Algebra/Lie/Character.lean +++ b/Mathlib/Algebra/Lie/Character.lean @@ -49,11 +49,11 @@ theorem lieCharacter_apply_of_mem_derived (χ : LieCharacter R L) {x : L} (h : x ∈ derivedSeries R L 1) : χ x = 0 := by rw [derivedSeries_def, derivedSeriesOfIdeal_succ, derivedSeriesOfIdeal_zero, ← LieSubmodule.mem_coeSubmodule, LieSubmodule.lieIdeal_oper_eq_linear_span] at h - refine Submodule.span_induction h ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ h · rintro y ⟨⟨z, hz⟩, ⟨⟨w, hw⟩, rfl⟩⟩; apply lieCharacter_apply_lie · exact χ.map_zero - · intro y z hy hz; rw [LieHom.map_add, hy, hz, add_zero] - · intro t y hy; rw [LieHom.map_smul, hy, smul_zero] + · intro y z _ _ hy hz; rw [LieHom.map_add, hy, hz, add_zero] + · intro t y _ hy; rw [LieHom.map_smul, hy, smul_zero] /-- For an Abelian Lie algebra, characters are just linear forms. -/ @[simps! apply symm_apply] diff --git a/Mathlib/Algebra/Lie/Derivation/Basic.lean b/Mathlib/Algebra/Lie/Derivation/Basic.lean index 00c92eef36252..3838771725325 100644 --- a/Mathlib/Algebra/Lie/Derivation/Basic.lean +++ b/Mathlib/Algebra/Lie/Derivation/Basic.lean @@ -104,7 +104,7 @@ lemma apply_lie_eq_add (D : LieDerivation R L L) (a b : L) : /-- Two Lie derivations equal on a set are equal on its Lie span. -/ theorem eqOn_lieSpan {s : Set L} (h : Set.EqOn D1 D2 s) : Set.EqOn D1 D2 (LieSubalgebra.lieSpan R L s) := - fun z hz => + fun _ hz => have zero : D1 0 = D2 0 := by simp only [map_zero] have smul : ∀ (r : R), ∀ {x : L}, D1 x = D2 x → D1 (r • x) = D2 (r • x) := fun _ _ hx => by simp only [map_smul, hx] diff --git a/Mathlib/Algebra/Lie/DirectSum.lean b/Mathlib/Algebra/Lie/DirectSum.lean index 7d4a6efc56417..830fec1d310b7 100644 --- a/Mathlib/Algebra/Lie/DirectSum.lean +++ b/Mathlib/Algebra/Lie/DirectSum.lean @@ -41,15 +41,15 @@ variable [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] variable [∀ i, LieRingModule L (M i)] [∀ i, LieModule R L (M i)] instance : LieRingModule L (⨁ i, M i) where - bracket x m := m.mapRange (fun i m' => ⁅x, m'⁆) fun i => lie_zero x + bracket x m := m.mapRange (fun _ m' => ⁅x, m'⁆) fun _ => lie_zero x add_lie x y m := by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [mapRange_apply, add_apply, add_lie] lie_add x m n := by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [mapRange_apply, add_apply, lie_add] leibniz_lie x y m := by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [mapRange_apply, lie_lie, add_apply, sub_add_cancel] @[simp] @@ -58,10 +58,10 @@ theorem lie_module_bracket_apply (x : L) (m : ⨁ i, M i) (i : ι) : ⁅x, m⁆ instance : LieModule R L (⨁ i, M i) where smul_lie t x m := by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext i` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext i` simp only [smul_lie, lie_module_bracket_apply, smul_apply] lie_smul t x m := by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext i` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext i` simp only [lie_smul, lie_module_bracket_apply, smul_apply] variable (R ι L M) @@ -70,7 +70,7 @@ variable (R ι L M) def lieModuleOf [DecidableEq ι] (j : ι) : M j →ₗ⁅R,L⁆ ⨁ i, M i := { lof R ι M j with map_lie' := fun {x m} => by - refine DFinsupp.ext fun i => ?_ -- Porting note: Originally `ext i` + refine DFinsupp.ext fun i => ?_ -- Porting note (#11041): Originally `ext i` by_cases h : j = i · rw [← h]; simp · -- This used to be the end of the proof before leanprover/lean4#2644 @@ -96,18 +96,18 @@ variable [∀ i, LieRing (L i)] [∀ i, LieAlgebra R (L i)] instance lieRing : LieRing (⨁ i, L i) := { (inferInstance : AddCommGroup _) with - bracket := zipWith (fun i => fun x y => ⁅x, y⁆) fun i => lie_zero 0 + bracket := zipWith (fun _ => fun x y => ⁅x, y⁆) fun _ => lie_zero 0 add_lie := fun x y z => by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [zipWith_apply, add_apply, add_lie] lie_add := fun x y z => by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [zipWith_apply, add_apply, lie_add] lie_self := fun x => by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [zipWith_apply, add_apply, lie_self, zero_apply] leibniz_lie := fun x y z => by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [sub_apply, zipWith_apply, add_apply, zero_apply] apply leibniz_lie } @@ -137,7 +137,7 @@ theorem lie_of [DecidableEq ι] {i j : ι} (x : L i) (y : L j) : instance lieAlgebra : LieAlgebra R (⨁ i, L i) := { (inferInstance : Module R _) with lie_smul := fun c x y => by - refine DFinsupp.ext fun _ => ?_ -- Porting note: Originally `ext` + refine DFinsupp.ext fun _ => ?_ -- Porting note (#11041): Originally `ext` simp only [zipWith_apply, smul_apply, bracket_apply, lie_smul] } variable (R ι) @@ -148,7 +148,7 @@ def lieAlgebraOf [DecidableEq ι] (j : ι) : L j →ₗ⁅R⁆ ⨁ i, L i := { lof R ι L j with toFun := of L j map_lie' := fun {x y} => by - refine DFinsupp.ext fun i => ?_ -- Porting note: Originally `ext i` + refine DFinsupp.ext fun i => ?_ -- Porting note (#11041): Originally `ext i` by_cases h : j = i · rw [← h] -- This used to be the end of the proof before leanprover/lean4#2644 @@ -157,14 +157,14 @@ def lieAlgebraOf [DecidableEq ι] (j : ι) : L j →ₗ⁅R⁆ ⨁ i, L i := erw [AddHom.coe_mk, single_apply, single_apply] · simp? [h] says simp only [h, ↓reduceDIte, single_apply] · intros - erw [single_add] + rw [single_add] · -- This used to be the end of the proof before leanprover/lean4#2644 -- with `simp [of, singleAddHom]` simp only [of, singleAddHom, bracket_apply] erw [AddHom.coe_mk, single_apply, single_apply] · simp only [h, dite_false, single_apply, lie_self] · intros - erw [single_add] } + rw [single_add] } /-- The projection map onto one component, as a morphism of Lie algebras. -/ @[simps] diff --git a/Mathlib/Algebra/Lie/IdealOperations.lean b/Mathlib/Algebra/Lie/IdealOperations.lean index 0c18a9d49f2d5..75e9facacd878 100644 --- a/Mathlib/Algebra/Lie/IdealOperations.lean +++ b/Mathlib/Algebra/Lie/IdealOperations.lean @@ -85,14 +85,14 @@ theorem lieIdeal_oper_eq_linear_span [LieModule R L M] : have aux : ∀ (y : L), ∀ m' ∈ Submodule.span R s, ⁅y, m'⁆ ∈ Submodule.span R s := by intro y m' hm' refine Submodule.span_induction (R := R) (M := M) (s := s) - (p := fun m' ↦ ⁅y, m'⁆ ∈ Submodule.span R s) hm' ?_ ?_ ?_ ?_ + (p := fun m' _ ↦ ⁅y, m'⁆ ∈ Submodule.span R s) ?_ ?_ ?_ ?_ hm' · rintro m'' ⟨x, n, hm''⟩; rw [← hm'', leibniz_lie] refine Submodule.add_mem _ ?_ ?_ <;> apply Submodule.subset_span · use ⟨⁅y, ↑x⁆, I.lie_mem x.property⟩, n · use x, ⟨⁅y, ↑n⁆, N.lie_mem n.property⟩ · simp only [lie_zero, Submodule.zero_mem] - · intro m₁ m₂ hm₁ hm₂; rw [lie_add]; exact Submodule.add_mem _ hm₁ hm₂ - · intro t m'' hm''; rw [lie_smul]; exact Submodule.smul_mem _ t hm'' + · intro m₁ m₂ _ _ hm₁ hm₂; rw [lie_add]; exact Submodule.add_mem _ hm₁ hm₂ + · intro t m'' _ hm''; rw [lie_smul]; exact Submodule.smul_mem _ t hm'' change _ ≤ ({ Submodule.span R s with lie_mem := fun hm' => aux _ _ hm' } : LieSubmodule R L M) rw [lieIdeal_oper_eq_span, lieSpan_le] exact Submodule.subset_span @@ -175,7 +175,7 @@ theorem lie_sup : ⁅I, N ⊔ N'⁆ = ⁅I, N⁆ ⊔ ⁅I, N'⁆ := by apply mono_lie_right <;> [exact le_sup_left; exact le_sup_right] suffices ⁅I, N ⊔ N'⁆ ≤ ⁅I, N⁆ ⊔ ⁅I, N'⁆ by exact le_antisymm this h rw [lieIdeal_oper_eq_span, lieSpan_le]; rintro m ⟨x, ⟨n, hn⟩, h⟩; erw [LieSubmodule.mem_sup] - erw [LieSubmodule.mem_sup] at hn; rcases hn with ⟨n₁, hn₁, n₂, hn₂, hn'⟩ + rw [LieSubmodule.mem_sup] at hn; rcases hn with ⟨n₁, hn₁, n₂, hn₂, hn'⟩ use ⁅(x : L), (⟨n₁, hn₁⟩ : N)⁆; constructor; · apply lie_coe_mem_lie use ⁅(x : L), (⟨n₂, hn₂⟩ : N')⁆; constructor; · apply lie_coe_mem_lie simp [← h, ← hn'] @@ -187,7 +187,7 @@ theorem sup_lie : ⁅I ⊔ J, N⁆ = ⁅I, N⁆ ⊔ ⁅J, N⁆ := by apply mono_lie_left <;> [exact le_sup_left; exact le_sup_right] suffices ⁅I ⊔ J, N⁆ ≤ ⁅I, N⁆ ⊔ ⁅J, N⁆ by exact le_antisymm this h rw [lieIdeal_oper_eq_span, lieSpan_le]; rintro m ⟨⟨x, hx⟩, n, h⟩; erw [LieSubmodule.mem_sup] - erw [LieSubmodule.mem_sup] at hx; rcases hx with ⟨x₁, hx₁, x₂, hx₂, hx'⟩ + rw [LieSubmodule.mem_sup] at hx; rcases hx with ⟨x₁, hx₁, x₂, hx₂, hx'⟩ use ⁅((⟨x₁, hx₁⟩ : I) : L), (n : N)⁆; constructor; · apply lie_coe_mem_lie use ⁅((⟨x₂, hx₂⟩ : J) : L), (n : N)⁆; constructor; · apply lie_coe_mem_lie simp [← h, ← hx'] @@ -275,7 +275,7 @@ theorem comap_bracket_eq {J₁ J₂ : LieIdeal R L'} (h : f.IsIdealMorphism) : congr; simp only [LieHom.coe_toLinearMap, Set.mem_setOf_eq]; ext y constructor · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩, hy⟩; rw [← hy] - erw [LieSubmodule.mem_inf, f.mem_idealRange_iff h] at hx₁ hx₂ + rw [LieSubmodule.mem_inf, f.mem_idealRange_iff h] at hx₁ hx₂ obtain ⟨⟨z₁, hz₁⟩, hz₁'⟩ := hx₁; rw [← hz₁] at hz₁' obtain ⟨⟨z₂, hz₂⟩, hz₂'⟩ := hx₂; rw [← hz₂] at hz₂' refine ⟨⁅z₁, z₂⁆, ⟨⟨z₁, hz₁'⟩, ⟨z₂, hz₂'⟩, rfl⟩, ?_⟩ diff --git a/Mathlib/Algebra/Lie/Killing.lean b/Mathlib/Algebra/Lie/Killing.lean index ba952dab65ff0..d884a6db4b9f2 100644 --- a/Mathlib/Algebra/Lie/Killing.lean +++ b/Mathlib/Algebra/Lie/Killing.lean @@ -38,7 +38,7 @@ This file contains basic definitions and results for such Lie algebras. -/ -variable (R K L M : Type*) [CommRing R] [Field K] [LieRing L] [LieAlgebra R L] [LieAlgebra K L] +variable (R K L : Type*) [CommRing R] [Field K] [LieRing L] [LieAlgebra R L] [LieAlgebra K L] namespace LieAlgebra @@ -46,7 +46,7 @@ namespace LieAlgebra NB: This is not standard terminology (the literature does not seem to name Lie algebras with this property). -/ -class IsKilling : Prop := +class IsKilling : Prop where /-- We say a Lie algebra is Killing if its Killing form is non-singular. -/ killingCompl_top_eq_bot : LieIdeal.killingCompl R L ⊤ = ⊥ diff --git a/Mathlib/Algebra/Lie/Nilpotent.lean b/Mathlib/Algebra/Lie/Nilpotent.lean index a215550676406..84d773813fa84 100644 --- a/Mathlib/Algebra/Lie/Nilpotent.lean +++ b/Mathlib/Algebra/Lie/Nilpotent.lean @@ -644,10 +644,10 @@ theorem coe_lowerCentralSeries_ideal_quot_eq {I : LieIdeal R L} (k : ℕ) : ext x constructor · rintro ⟨⟨y, -⟩, ⟨z, hz⟩, rfl : ⁅y, z⁆ = x⟩ - erw [← LieSubmodule.mem_coeSubmodule, ih, LieSubmodule.mem_coeSubmodule] at hz + rw [← LieSubmodule.mem_coeSubmodule, ih, LieSubmodule.mem_coeSubmodule] at hz exact ⟨⟨LieSubmodule.Quotient.mk y, LieSubmodule.mem_top _⟩, ⟨z, hz⟩, rfl⟩ · rintro ⟨⟨⟨y⟩, -⟩, ⟨z, hz⟩, rfl : ⁅y, z⁆ = x⟩ - erw [← LieSubmodule.mem_coeSubmodule, ← ih, LieSubmodule.mem_coeSubmodule] at hz + rw [← LieSubmodule.mem_coeSubmodule, ← ih, LieSubmodule.mem_coeSubmodule] at hz exact ⟨⟨y, LieSubmodule.mem_top _⟩, ⟨z, hz⟩, rfl⟩ /-- Note that the below inequality can be strict. For example the ideal of strictly-upper-triangular diff --git a/Mathlib/Algebra/Lie/Quotient.lean b/Mathlib/Algebra/Lie/Quotient.lean index cefd7b350bb49..86913a4a41213 100644 --- a/Mathlib/Algebra/Lie/Quotient.lean +++ b/Mathlib/Algebra/Lie/Quotient.lean @@ -111,7 +111,7 @@ instance lieQuotientHasBracket : Bracket (L ⧸ I) (L ⧸ I) := apply Quotient.liftOn₂' x y fun x' y' => mk ⁅x', y'⁆ intro x₁ x₂ y₁ y₂ h₁ h₂ apply (Submodule.Quotient.eq I.toSubmodule).2 - rw [Submodule.quotientRel_r_def] at h₁ h₂ + rw [Submodule.quotientRel_def] at h₁ h₂ have h : ⁅x₁, x₂⁆ - ⁅y₁, y₂⁆ = ⁅x₁, x₂ - y₂⁆ + ⁅x₁ - y₁, y₂⁆ := by simp [-lie_skew, sub_eq_add_neg, add_assoc] rw [h] diff --git a/Mathlib/Algebra/Lie/Solvable.lean b/Mathlib/Algebra/Lie/Solvable.lean index f51e86e77306c..1ce5fd8fdcf58 100644 --- a/Mathlib/Algebra/Lie/Solvable.lean +++ b/Mathlib/Algebra/Lie/Solvable.lean @@ -266,8 +266,8 @@ def radical := /-- The radical of a Noetherian Lie algebra is solvable. -/ instance radicalIsSolvable [IsNoetherian R L] : IsSolvable R (radical R L) := by - have hwf := (LieSubmodule.wellFoundedGT_of_noetherian R L L).wf - rw [← CompleteLattice.isSupClosedCompact_iff_wellFounded] at hwf + have hwf := LieSubmodule.wellFoundedGT_of_noetherian R L L + rw [← CompleteLattice.isSupClosedCompact_iff_wellFoundedGT] at hwf refine hwf { I : LieIdeal R L | IsSolvable R I } ⟨⊥, ?_⟩ fun I hI J hJ => ?_ · exact LieAlgebra.isSolvableBot R L · rw [Set.mem_setOf_eq] at hI hJ ⊢ diff --git a/Mathlib/Algebra/Lie/Subalgebra.lean b/Mathlib/Algebra/Lie/Subalgebra.lean index a1d215735203f..6421cf0fe0753 100644 --- a/Mathlib/Algebra/Lie/Subalgebra.lean +++ b/Mathlib/Algebra/Lie/Subalgebra.lean @@ -295,7 +295,7 @@ theorem rangeRestrict_apply (x : L) : f.rangeRestrict x = ⟨f x, f.mem_range_se theorem surjective_rangeRestrict : Function.Surjective f.rangeRestrict := by rintro ⟨y, hy⟩ - erw [mem_range] at hy; obtain ⟨x, rfl⟩ := hy + rw [mem_range] at hy; obtain ⟨x, rfl⟩ := hy use x simp only [Subtype.mk_eq_mk, rangeRestrict_apply] @@ -461,7 +461,7 @@ instance completeLattice : CompleteLattice (LieSubalgebra R L) := top := ⊤ le_top := fun _ _ _ ↦ trivial inf := (· ⊓ ·) - le_inf := fun N₁ N₂ N₃ h₁₂ h₁₃ m hm ↦ ⟨h₁₂ hm, h₁₃ hm⟩ + le_inf := fun _ _ _ h₁₂ h₁₃ _ hm ↦ ⟨h₁₂ hm, h₁₃ hm⟩ inf_le_left := fun _ _ _ ↦ And.left inf_le_right := fun _ _ _ ↦ And.right } @@ -694,7 +694,7 @@ def ofEq (h : (L₁' : Set L₁) = L₁'') : L₁' ≃ₗ⁅R⁆ L₁'' := ext x change x ∈ (L₁' : Set L₁) ↔ x ∈ (L₁'' : Set L₁) rw [h]) with - map_lie' := @fun x y ↦ rfl } + map_lie' := @fun _ _ ↦ rfl } @[simp] theorem ofEq_apply (L L' : LieSubalgebra R L₁) (h : (L : Set L₁) = L') (x : L) : diff --git a/Mathlib/Algebra/Lie/Submodule.lean b/Mathlib/Algebra/Lie/Submodule.lean index 1ce9ee98b69dc..f09b3652b769d 100644 --- a/Mathlib/Algebra/Lie/Submodule.lean +++ b/Mathlib/Algebra/Lie/Submodule.lean @@ -83,7 +83,7 @@ instance (priority := mid) coeSubmodule : CoeOut (LieSubmodule R L M) (Submodule theorem coe_toSubmodule : ((N : Submodule R M) : Set M) = N := rfl --- Porting note (#10618): `simp` can prove this after `mem_coeSubmodule` is added to the simp set, +-- `simp` can prove this after `mem_coeSubmodule` is added to the simp set, -- but `dsimp` can't. @[simp, nolint simpNF] theorem mem_carrier {x : M} : x ∈ N.carrier ↔ x ∈ (N : Set M) := @@ -885,7 +885,7 @@ Submodules. -/ invFun := comap e left_inv := fun N ↦ by ext; simp right_inv := fun N ↦ by ext; simp [e.apply_eq_iff_eq_symm_apply] - map_rel_iff' := fun {N N'} ↦ Set.image_subset_image_iff e.injective + map_rel_iff' := fun {_ _} ↦ Set.image_subset_image_iff e.injective end LieSubmodule @@ -1386,7 +1386,7 @@ def LieSubalgebra.topEquiv : (⊤ : LieSubalgebra R L) ≃ₗ⁅R⁆ L := { (⊤ : LieSubalgebra R L).incl with invFun := fun x ↦ ⟨x, Set.mem_univ x⟩ left_inv := fun x ↦ by ext; rfl - right_inv := fun x ↦ rfl } + right_inv := fun _ ↦ rfl } @[simp] theorem LieSubalgebra.topEquiv_apply (x : (⊤ : LieSubalgebra R L)) : LieSubalgebra.topEquiv x = x := diff --git a/Mathlib/Algebra/Lie/TensorProduct.lean b/Mathlib/Algebra/Lie/TensorProduct.lean index 0fe6b3f7fb9e8..0974b6a2d5a2d 100644 --- a/Mathlib/Algebra/Lie/TensorProduct.lean +++ b/Mathlib/Algebra/Lie/TensorProduct.lean @@ -51,7 +51,7 @@ instance lieRingModule : LieRingModule L (M ⊗[R] N) where simp only [hasBracketAux, LinearMap.lTensor_add, LinearMap.rTensor_add, LieHom.map_add, LinearMap.add_apply] abel - lie_add x := LinearMap.map_add _ + lie_add _ := LinearMap.map_add _ leibniz_lie x y t := by suffices (hasBracketAux x).comp (hasBracketAux y) = hasBracketAux ⁅x, y⁆ + (hasBracketAux y).comp (hasBracketAux x) by @@ -69,7 +69,7 @@ instance lieModule : LieModule R L (M ⊗[R] N) where change hasBracketAux (c • x) _ = c • hasBracketAux _ _ simp only [hasBracketAux, smul_add, LinearMap.rTensor_smul, LinearMap.smul_apply, LinearMap.lTensor_smul, LieHom.map_smul, LinearMap.add_apply] - lie_smul c x := LinearMap.map_smul _ c + lie_smul c _ := LinearMap.map_smul _ c @[simp] theorem lie_tmul_right (x : L) (m : M) (n : N) : ⁅x, m ⊗ₜ[R] n⁆ = ⁅x, m⁆ ⊗ₜ n + m ⊗ₜ ⁅x, n⁆ := diff --git a/Mathlib/Algebra/Lie/TraceForm.lean b/Mathlib/Algebra/Lie/TraceForm.lean index bddebc215744c..2d1253e2b18c9 100644 --- a/Mathlib/Algebra/Lie/TraceForm.lean +++ b/Mathlib/Algebra/Lie/TraceForm.lean @@ -135,7 +135,7 @@ lemma traceForm_eq_zero_if_mem_lcs_of_mem_ucs {x y : L} (k : ℕ) rw [LieSubmodule.ucs_succ, LieSubmodule.mem_normalizer] at hy simp_rw [LieIdeal.lcs_succ, ← LieSubmodule.mem_coeSubmodule, LieSubmodule.lieIdeal_oper_eq_linear_span', LieSubmodule.mem_top, true_and] at hx - refine Submodule.span_induction hx ?_ ?_ (fun z w hz hw ↦ ?_) (fun t z hz ↦ ?_) + refine Submodule.span_induction ?_ ?_ (fun z w _ _ hz hw ↦ ?_) (fun t z _ hz ↦ ?_) hx · rintro - ⟨z, w, hw, rfl⟩ rw [← lie_skew, map_neg, LinearMap.neg_apply, neg_eq_zero, traceForm_apply_lie_apply] exact ih hw (hy _) @@ -192,9 +192,10 @@ lemma trace_toEnd_eq_zero_of_mem_lcs rw [lowerCentralSeries_succ, ← LieSubmodule.mem_coeSubmodule, LieSubmodule.lieIdeal_oper_eq_linear_span'] at hx simpa using hx - refine Submodule.span_induction (p := fun x ↦ trace R _ (toEnd R L M x) = 0) hx - (fun y ⟨u, v, huv⟩ ↦ ?_) ?_ (fun u v hu hv ↦ ?_) (fun t u hu ↦ ?_) - · simp [← huv] + refine Submodule.span_induction (p := fun x _ ↦ trace R _ (toEnd R L M x) = 0) + ?_ ?_ (fun u v _ _ hu hv ↦ ?_) (fun t u _ hu ↦ ?_) hx + · intro y ⟨u, v, huv⟩ + simp [← huv] · simp · simp [hu, hv] · simp [hu] @@ -276,7 +277,7 @@ lemma lowerCentralSeries_one_inf_center_le_ker_traceForm [Module.Free R M] [Modu intro y exact y.induction_on rfl (fun a u ↦ by simp [hzc u]) (fun u v hu hv ↦ by simp [hu, hv]) apply LinearMap.trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero - · simpa only [Module.End.maxGenEigenspace_def] using IsTriangularizable.iSup_eq_top (1 ⊗ₜ[R] x) + · exact IsTriangularizable.maxGenEigenspace_eq_top (1 ⊗ₜ[R] x) · exact fun μ ↦ trace_toEnd_eq_zero_of_mem_lcs A (A ⊗[R] L) (genWeightSpaceOf (A ⊗[R] M) μ ((1:A) ⊗ₜ[R] x)) (le_refl 1) hz · exact commute_toEnd_of_mem_center_right (A ⊗[R] M) hzc (1 ⊗ₜ x) diff --git a/Mathlib/Algebra/Lie/Weights/Basic.lean b/Mathlib/Algebra/Lie/Weights/Basic.lean index 090ee19929b33..128294e766cf1 100644 --- a/Mathlib/Algebra/Lie/Weights/Basic.lean +++ b/Mathlib/Algebra/Lie/Weights/Basic.lean @@ -6,7 +6,7 @@ Authors: Oliver Nash import Mathlib.Algebra.Ring.Divisibility.Lemmas import Mathlib.Algebra.Lie.Nilpotent import Mathlib.Algebra.Lie.Engel -import Mathlib.LinearAlgebra.Eigenspace.Triangularizable +import Mathlib.LinearAlgebra.Eigenspace.Pi import Mathlib.RingTheory.Artinian import Mathlib.LinearAlgebra.Trace import Mathlib.LinearAlgebra.FreeModule.PID @@ -165,7 +165,7 @@ theorem mem_genWeightSpaceOf (χ : R) (x : L) (m : M) : theorem coe_genWeightSpaceOf_zero (x : L) : ↑(genWeightSpaceOf M (0 : R) x) = ⨆ k, LinearMap.ker (toEnd R L M x ^ k) := by - simp [genWeightSpaceOf, Module.End.maxGenEigenspace_def] + simp [genWeightSpaceOf, ← Module.End.iSup_genEigenspace_eq] /-- If `M` is a representation of a nilpotent Lie algebra `L` and `χ : L → R` is a family of scalars, @@ -267,7 +267,7 @@ lemma genWeightSpaceOf_ne_bot (χ : Weight R L M) (x : L) : lemma hasEigenvalueAt (χ : Weight R L M) (x : L) : (toEnd R L M x).HasEigenvalue (χ x) := by obtain ⟨k : ℕ, hk : (toEnd R L M x).genEigenspace (χ x) k ≠ ⊥⟩ := by - simpa [genWeightSpaceOf, Module.End.maxGenEigenspace_def] using χ.genWeightSpaceOf_ne_bot x + simpa [genWeightSpaceOf, ← Module.End.iSup_genEigenspace_eq] using χ.genWeightSpaceOf_ne_bot x exact Module.End.hasEigenvalue_of_hasGenEigenvalue hk lemma apply_eq_zero_of_isNilpotent [NoZeroSMulDivisors R M] [IsReduced R] @@ -308,7 +308,7 @@ theorem exists_genWeightSpace_le_ker_of_isNoetherian [IsNoetherian R M] (χ : L intro m hm replace hm : m ∈ (toEnd R L M x).maxGenEigenspace (χ x) := genWeightSpace_le_genWeightSpaceOf M x χ hm - rwa [Module.End.maxGenEigenspace_eq, Module.End.genEigenspace_def] at hm + rwa [Module.End.maxGenEigenspace_eq, Module.End.genEigenspace_nat] at hm variable (R) in theorem exists_genWeightSpace_zero_le_ker_of_isNoetherian @@ -631,8 +631,7 @@ lemma disjoint_genWeightSpaceOf [NoZeroSMulDivisors R M] {x : L} {φ₁ φ₂ : Disjoint (genWeightSpaceOf M φ₁ x) (genWeightSpaceOf M φ₂ x) := by rw [LieSubmodule.disjoint_iff_coe_toSubmodule] dsimp [genWeightSpaceOf] - simp_rw [Module.End.maxGenEigenspace_def] - exact Module.End.disjoint_iSup_genEigenspace _ h + exact Module.End.disjoint_genEigenspace _ h _ _ lemma disjoint_genWeightSpace [NoZeroSMulDivisors R M] {χ₁ χ₂ : L → R} (h : χ₁ ≠ χ₂) : Disjoint (genWeightSpace M χ₁) (genWeightSpace M χ₂) := by @@ -650,48 +649,11 @@ lemma injOn_genWeightSpace [NoZeroSMulDivisors R M] : See also `LieModule.independent_genWeightSpace'`. -/ lemma independent_genWeightSpace [NoZeroSMulDivisors R M] : - CompleteLattice.Independent fun (χ : L → R) ↦ genWeightSpace M χ := by - classical - suffices ∀ χ (s : Finset (L → R)) (_ : χ ∉ s), - Disjoint (genWeightSpace M χ) (s.sup fun (χ : L → R) ↦ genWeightSpace M χ) by - simpa only [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_genWeightSpace R L M), - Finset.supIndep_iff_disjoint_erase] using fun s χ _ ↦ this _ _ (s.not_mem_erase χ) - intro χ₁ s - induction s using Finset.induction_on with - | empty => simp - | insert _n ih => - rename_i χ₂ s - intro hχ₁₂ - obtain ⟨hχ₁₂ : χ₁ ≠ χ₂, hχ₁ : χ₁ ∉ s⟩ := by rwa [Finset.mem_insert, not_or] at hχ₁₂ - specialize ih hχ₁ - rw [Finset.sup_insert, disjoint_iff, LieSubmodule.eq_bot_iff] - rintro x ⟨hx, hx'⟩ - simp only [SetLike.mem_coe, LieSubmodule.mem_coeSubmodule] at hx hx' - suffices x ∈ genWeightSpace M χ₂ by - rw [← LieSubmodule.mem_bot (R := R) (L := L), ← (disjoint_genWeightSpace R L M hχ₁₂).eq_bot] - exact ⟨hx, this⟩ - obtain ⟨y, hy, z, hz, rfl⟩ := (LieSubmodule.mem_sup _ _ _).mp hx'; clear hx' - suffices ∀ l, ∃ (k : ℕ), - ((toEnd R L M l - algebraMap R (Module.End R M) (χ₂ l)) ^ k) (y + z) ∈ - genWeightSpace M χ₁ ⊓ Finset.sup s fun χ ↦ genWeightSpace M χ by - simpa only [ih.eq_bot, LieSubmodule.mem_bot, mem_genWeightSpace] using this - intro l - let g : Module.End R M := toEnd R L M l - algebraMap R (Module.End R M) (χ₂ l) - obtain ⟨k, hk : (g ^ k) y = 0⟩ := (mem_genWeightSpace _ _ _).mp hy l - refine ⟨k, (LieSubmodule.mem_inf _ _ _).mp ⟨?_, ?_⟩⟩ - · exact LieSubmodule.mapsTo_pow_toEnd_sub_algebraMap _ hx - · rw [map_add, hk, zero_add] - suffices (s.sup fun χ ↦ genWeightSpace M χ : Submodule R M).map (g ^ k) ≤ - s.sup fun χ ↦ genWeightSpace M χ by - refine this (Submodule.mem_map_of_mem ?_) - simp_rw [← LieSubmodule.mem_coeSubmodule, Finset.sup_eq_iSup, - LieSubmodule.iSup_coe_toSubmodule, ← Finset.sup_eq_iSup] at hz - exact hz - simp_rw [Finset.sup_eq_iSup, Submodule.map_iSup (ι := L → R), Submodule.map_iSup (ι := _ ∈ s), - LieSubmodule.iSup_coe_toSubmodule] - refine iSup₂_mono fun χ _ ↦ ?_ - rintro - ⟨u, hu, rfl⟩ - exact LieSubmodule.mapsTo_pow_toEnd_sub_algebraMap _ hu + CompleteLattice.Independent fun χ : L → R ↦ genWeightSpace M χ := by + simp only [LieSubmodule.independent_iff_coe_toSubmodule, genWeightSpace, + LieSubmodule.iInf_coe_toSubmodule] + exact Module.End.independent_iInf_maxGenEigenspace_of_forall_mapsTo (toEnd R L M) + (fun x y φ z ↦ (genWeightSpaceOf M φ y).lie_mem) lemma independent_genWeightSpace' [NoZeroSMulDivisors R M] : CompleteLattice.Independent fun χ : Weight R L M ↦ genWeightSpace M χ := @@ -702,18 +664,15 @@ lemma independent_genWeightSpaceOf [NoZeroSMulDivisors R M] (x : L) : CompleteLattice.Independent fun (χ : R) ↦ genWeightSpaceOf M χ x := by rw [LieSubmodule.independent_iff_coe_toSubmodule] dsimp [genWeightSpaceOf] - simp_rw [Module.End.maxGenEigenspace_def] - exact (toEnd R L M x).independent_genEigenspace + exact (toEnd R L M x).independent_genEigenspace _ lemma finite_genWeightSpaceOf_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] (x : L) : {χ : R | genWeightSpaceOf M χ x ≠ ⊥}.Finite := - CompleteLattice.WellFounded.finite_ne_bot_of_independent - IsWellFounded.wf (independent_genWeightSpaceOf R L M x) + CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent (independent_genWeightSpaceOf R L M x) lemma finite_genWeightSpace_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] : {χ : L → R | genWeightSpace M χ ≠ ⊥}.Finite := - CompleteLattice.WellFounded.finite_ne_bot_of_independent - IsWellFounded.wf (independent_genWeightSpace R L M) + CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent (independent_genWeightSpace R L M) instance Weight.instFinite [NoZeroSMulDivisors R M] [IsNoetherian R M] : Finite (Weight R L M) := by @@ -726,17 +685,19 @@ noncomputable instance Weight.instFintype [NoZeroSMulDivisors R M] [IsNoetherian /-- A Lie module `M` of a Lie algebra `L` is triangularizable if the endomorhpism of `M` defined by any `x : L` is triangularizable. -/ -class IsTriangularizable : Prop := - iSup_eq_top : ∀ x, ⨆ φ, ⨆ k, (toEnd R L M x).genEigenspace φ k = ⊤ +class IsTriangularizable : Prop where + maxGenEigenspace_eq_top : ∀ x, ⨆ φ, (toEnd R L M x).maxGenEigenspace φ = ⊤ instance (L' : LieSubalgebra R L) [IsTriangularizable R L M] : IsTriangularizable R L' M where - iSup_eq_top x := IsTriangularizable.iSup_eq_top (x : L) + maxGenEigenspace_eq_top x := IsTriangularizable.maxGenEigenspace_eq_top (x : L) instance (I : LieIdeal R L) [IsTriangularizable R L M] : IsTriangularizable R I M where - iSup_eq_top x := IsTriangularizable.iSup_eq_top (x : L) + maxGenEigenspace_eq_top x := IsTriangularizable.maxGenEigenspace_eq_top (x : L) instance [IsTriangularizable R L M] : IsTriangularizable R (LieModule.toEnd R L M).range M where - iSup_eq_top := by rintro ⟨-, x, rfl⟩; exact IsTriangularizable.iSup_eq_top x + maxGenEigenspace_eq_top := by + rintro ⟨-, x, rfl⟩ + exact IsTriangularizable.maxGenEigenspace_eq_top x @[simp] lemma iSup_genWeightSpaceOf_eq_top [IsTriangularizable R L M] (x : L) : @@ -744,8 +705,7 @@ lemma iSup_genWeightSpaceOf_eq_top [IsTriangularizable R L M] (x : L) : rw [← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.iSup_coe_toSubmodule, LieSubmodule.top_coeSubmodule] dsimp [genWeightSpaceOf] - simp_rw [Module.End.maxGenEigenspace_def] - exact IsTriangularizable.iSup_eq_top x + exact IsTriangularizable.maxGenEigenspace_eq_top x open LinearMap Module in @[simp] @@ -768,12 +728,12 @@ variable [Field K] [LieAlgebra K L] [Module K M] [LieModule K L M] [LieAlgebra.I [FiniteDimensional K M] instance instIsTriangularizableOfIsAlgClosed [IsAlgClosed K] : IsTriangularizable K L M := - ⟨fun _ ↦ Module.End.iSup_genEigenspace_eq_top _⟩ + ⟨fun _ ↦ Module.End.iSup_maxGenEigenspace_eq_top _⟩ instance (N : LieSubmodule K L M) [IsTriangularizable K L M] : IsTriangularizable K L N := by refine ⟨fun y ↦ ?_⟩ rw [← N.toEnd_restrict_eq_toEnd y] - exact Module.End.iSup_genEigenspace_restrict_eq_top _ (IsTriangularizable.iSup_eq_top y) + exact Module.End.genEigenspace_restrict_eq_top _ (IsTriangularizable.maxGenEigenspace_eq_top y) /-- For a triangularizable Lie module in finite dimensions, the weight spaces span the entire space. @@ -784,8 +744,7 @@ lemma iSup_genWeightSpace_eq_top [IsTriangularizable K L M] : LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.top_coeSubmodule, genWeightSpace] refine Module.End.iSup_iInf_maxGenEigenspace_eq_top_of_forall_mapsTo (toEnd K L M) (fun x y φ z ↦ (genWeightSpaceOf M φ y).lie_mem) ?_ - simp_rw [Module.End.maxGenEigenspace_def] - apply IsTriangularizable.iSup_eq_top + apply IsTriangularizable.maxGenEigenspace_eq_top lemma iSup_genWeightSpace_eq_top' [IsTriangularizable K L M] : ⨆ χ : Weight K L M, genWeightSpace M χ = ⊤ := by diff --git a/Mathlib/Algebra/Lie/Weights/Cartan.lean b/Mathlib/Algebra/Lie/Weights/Cartan.lean index 0ef812f460f9e..e494e0e19ba5d 100644 --- a/Mathlib/Algebra/Lie/Weights/Cartan.lean +++ b/Mathlib/Algebra/Lie/Weights/Cartan.lean @@ -105,8 +105,6 @@ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ + simp only [SetLike.val_smul, smul_lie, LinearMap.coe_mk, AddHom.coe_mk, LinearMap.smul_apply, SetLike.mk_smul_mk] --- Porting note (#11083): this def is _really_ slow --- See https://github.com/leanprover-community/mathlib4/issues/5028 /-- Given a nilpotent Lie subalgebra `H ⊆ L` together with `χ₁ χ₂ : H → R`, there is a natural `R`-bilinear product of root vectors and weight vectors, compatible with the actions of `H`. -/ def rootSpaceWeightSpaceProduct (χ₁ χ₂ χ₃ : H → R) (hχ : χ₁ + χ₂ = χ₃) : diff --git a/Mathlib/Algebra/Lie/Weights/Chain.lean b/Mathlib/Algebra/Lie/Weights/Chain.lean index 428b6ff73884c..4107e1e4cd27f 100644 --- a/Mathlib/Algebra/Lie/Weights/Chain.lean +++ b/Mathlib/Algebra/Lie/Weights/Chain.lean @@ -160,7 +160,7 @@ lemma trace_toEnd_genWeightSpaceChain_eq_zero {x : H} (hx : x ∈ corootSpace α) : LinearMap.trace R _ (toEnd R H (genWeightSpaceChain M α χ p q) x) = 0 := by rw [LieAlgebra.mem_corootSpace'] at hx - induction hx using Submodule.span_induction' + induction hx using Submodule.span_induction · next u hu => obtain ⟨y, hy, z, hz, hyz⟩ := hu let f : Module.End R (genWeightSpaceChain M α χ p q) := diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean index 80e8ca2ed6bf3..3fe00e4149748 100644 --- a/Mathlib/Algebra/Lie/Weights/Killing.lean +++ b/Mathlib/Algebra/Lie/Weights/Killing.lean @@ -269,7 +269,7 @@ lemma isSemisimple_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) : (genWeightSpace_le_genWeightSpaceOf L x' α) hy rw [maxGenEigenspace_eq] at hy set k := maxGenEigenspaceIndex (ad K L x) (α x') - rw [apply_eq_of_mem_genEigenspace_of_comm_of_isSemisimple_of_isNilpotent_sub hy hS₀ hS hN] + rw [apply_eq_of_mem_of_comm_of_isFinitelySemisimple_of_isNil hy hS₀ hS.isFinitelySemisimple hN] /- So `S` obeys the derivation axiom if we restrict to root spaces. -/ have h_der (y z : L) (α β : H → K) (hy : y ∈ rootSpace H α) (hz : z ∈ rootSpace H β) : S ⁅y, z⁆ = ⁅S y, z⁆ + ⁅y, S z⁆ := by @@ -317,7 +317,8 @@ lemma lie_eq_smul_of_mem_rootSpace {α : H → K} {x : L} (hx : x ∈ rootSpace replace hx : x ∈ (ad K L h).maxGenEigenspace (α h) := genWeightSpace_le_genWeightSpaceOf L h α hx rw [(isSemisimple_ad_of_mem_isCartanSubalgebra - h.property).maxGenEigenspace_eq_eigenspace, Module.End.mem_eigenspace_iff] at hx + h.property).isFinitelySemisimple.maxGenEigenspace_eq_eigenspace, + Module.End.mem_eigenspace_iff] at hx simpa using hx lemma lie_eq_killingForm_smul_of_mem_rootSpace_of_mem_rootSpace_neg @@ -429,7 +430,7 @@ lemma traceForm_eq_zero_of_mem_ker_of_mem_span_coroot {α : Weight K H L} {x y : (hx : x ∈ α.ker) (hy : y ∈ K ∙ coroot α) : traceForm K H L x y = 0 := by rw [← coe_corootSpace_eq_span_singleton, LieSubmodule.mem_coeSubmodule, mem_corootSpace'] at hy - induction hy using Submodule.span_induction' with + induction hy using Submodule.span_induction with | mem z hz => obtain ⟨u, hu, v, -, huv⟩ := hz change killingForm K L (x : L) (z : L) = 0 diff --git a/Mathlib/Algebra/Lie/Weights/Linear.lean b/Mathlib/Algebra/Lie/Weights/Linear.lean index 9798876d617f9..5e1934aa2fd39 100644 --- a/Mathlib/Algebra/Lie/Weights/Linear.lean +++ b/Mathlib/Algebra/Lie/Weights/Linear.lean @@ -48,7 +48,7 @@ namespace LieModule /-- A typeclass encoding the fact that a given Lie module has linear weights, vanishing on the derived ideal. -/ -class LinearWeights [LieAlgebra.IsNilpotent R L] : Prop := +class LinearWeights [LieAlgebra.IsNilpotent R L] : Prop where map_add : ∀ χ : L → R, genWeightSpace M χ ≠ ⊥ → ∀ x y, χ (x + y) = χ x + χ y map_smul : ∀ χ : L → R, genWeightSpace M χ ≠ ⊥ → ∀ (t : R) x, χ (t • x) = t • χ x map_lie : ∀ χ : L → R, genWeightSpace M χ ≠ ⊥ → ∀ x y : L, χ ⁅x, y⁆ = 0 @@ -98,17 +98,15 @@ instance instLinearWeightsOfIsLieAbelian [IsLieAbelian L] [NoZeroSMulDivisors R rw [commute_iff_lie_eq, ← LieHom.map_lie, trivial_lie_zero, LieHom.map_zero] intro χ hχ x y simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, genWeightSpace, genWeightSpaceOf, - LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule, - Module.End.maxGenEigenspace_def] at hχ + LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule] at hχ exact Module.End.map_add_of_iInf_genEigenspace_ne_bot_of_commute - (toEnd R L M).toLinearMap χ hχ h x y + (toEnd R L M).toLinearMap χ _ hχ h x y { map_add := aux map_smul := fun χ hχ t x ↦ by simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, genWeightSpace, genWeightSpaceOf, - LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule, - Module.End.maxGenEigenspace_def] at hχ + LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule] at hχ exact Module.End.map_smul_of_iInf_genEigenspace_ne_bot - (toEnd R L M).toLinearMap χ hχ t x + (toEnd R L M).toLinearMap χ _ hχ t x map_lie := fun χ hχ t x ↦ by rw [trivial_lie_zero, ← add_left_inj (χ 0), ← aux χ hχ, zero_add, zero_add] } diff --git a/Mathlib/Algebra/LinearRecurrence.lean b/Mathlib/Algebra/LinearRecurrence.lean index b3b5648ee9db0..182a96ce2cf20 100644 --- a/Mathlib/Algebra/LinearRecurrence.lean +++ b/Mathlib/Algebra/LinearRecurrence.lean @@ -138,7 +138,7 @@ def toInit : E.solSpace ≃ₗ[α] Fin E.order → α where simp invFun u := ⟨E.mkSol u, E.is_sol_mkSol u⟩ left_inv u := by ext n; symm; apply E.eq_mk_of_is_sol_of_eq_init u.2; intro k; rfl - right_inv u := Function.funext_iff.mpr fun n ↦ E.mkSol_eq_init u n + right_inv u := funext_iff.mpr fun n ↦ E.mkSol_eq_init u n /-- Two solutions are equal iff they are equal on `range E.order`. -/ theorem sol_eq_of_eq_init (u v : ℕ → α) (hu : E.IsSolution u) (hv : E.IsSolution v) : diff --git a/Mathlib/Algebra/ModEq.lean b/Mathlib/Algebra/ModEq.lean index a275aad2c7254..daf547441d69c 100644 --- a/Mathlib/Algebra/ModEq.lean +++ b/Mathlib/Algebra/ModEq.lean @@ -3,10 +3,12 @@ Copyright (c) 2023 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Data.Int.ModEq import Mathlib.Algebra.Field.Basic +import Mathlib.Algebra.Group.Subgroup.ZPowers +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Order.Ring.Int -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Data.Int.ModEq +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Equality modulo an element @@ -172,16 +174,13 @@ protected theorem sub_iff_right : a₂ ≡ b₂ [PMOD p] → (a₁ - a₂ ≡ b₁ - b₂ [PMOD p] ↔ a₁ ≡ b₁ [PMOD p]) := fun ⟨m, hm⟩ => (Equiv.subRight m).symm.exists_congr_left.trans <| by simp [sub_sub_sub_comm, hm, sub_smul, ModEq] -alias ⟨add_left_cancel, add⟩ := ModEq.add_iff_left - -alias ⟨add_right_cancel, _⟩ := ModEq.add_iff_right +protected alias ⟨add_left_cancel, add⟩ := ModEq.add_iff_left -alias ⟨sub_left_cancel, sub⟩ := ModEq.sub_iff_left +protected alias ⟨add_right_cancel, _⟩ := ModEq.add_iff_right -alias ⟨sub_right_cancel, _⟩ := ModEq.sub_iff_right +protected alias ⟨sub_left_cancel, sub⟩ := ModEq.sub_iff_left --- Porting note: doesn't work --- attribute [protected] add_left_cancel add_right_cancel add sub_left_cancel sub_right_cancel sub +protected alias ⟨sub_right_cancel, _⟩ := ModEq.sub_iff_right protected theorem add_left (c : α) (h : a ≡ b [PMOD p]) : c + a ≡ c + b [PMOD p] := modEq_rfl.add h diff --git a/Mathlib/Algebra/Module/Basic.lean b/Mathlib/Algebra/Module/Basic.lean index 8656e47667f24..0eeee9934e3d3 100644 --- a/Mathlib/Algebra/Module/Basic.lean +++ b/Mathlib/Algebra/Module/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Field.Basic import Mathlib.Algebra.Group.Action.Pi import Mathlib.Algebra.Group.Indicator import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Defs /-! # Further basic results about modules. @@ -22,6 +23,12 @@ universe u v variable {α R M M₂ : Type*} +@[simp] +theorem invOf_two_smul_add_invOf_two_smul (R) [Semiring R] [AddCommMonoid M] [Module R M] + [Invertible (2 : R)] (x : M) : + (⅟ 2 : R) • x + (⅟ 2 : R) • x = x := + Convex.combo_self invOf_two_add_invOf_two _ + @[deprecated (since := "2024-04-17")] alias map_nat_cast_smul := map_natCast_smul @@ -95,30 +102,6 @@ theorem inv_intCast_smul_comm {α E : Type*} (R : Type*) [AddCommGroup E] [Divis @[deprecated (since := "2024-04-17")] alias inv_int_cast_smul_comm := inv_intCast_smul_comm - - -section NoZeroSMulDivisors - -section Module - -instance [AddCommGroup M] [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := - ⟨fun {c x} hcx ↦ by rwa [← Nat.cast_smul_eq_nsmul ℤ c x, smul_eq_zero, Nat.cast_eq_zero] at hcx⟩ - -end Module - -section GroupWithZero - -variable [GroupWithZero R] [AddMonoid M] [DistribMulAction R M] - --- see note [lower instance priority] -/-- This instance applies to `DivisionSemiring`s, in particular `NNReal` and `NNRat`. -/ -instance (priority := 100) GroupWithZero.toNoZeroSMulDivisors : NoZeroSMulDivisors R M := - ⟨fun {a _} h ↦ or_iff_not_imp_left.2 fun ha ↦ (smul_eq_zero_iff_eq <| Units.mk0 a ha).1 h⟩ - -end GroupWithZero - -end NoZeroSMulDivisors - namespace Function lemma support_smul_subset_left [Zero R] [Zero M] [SMulWithZero R M] (f : α → R) (g : α → M) : diff --git a/Mathlib/Algebra/Module/BigOperators.lean b/Mathlib/Algebra/Module/BigOperators.lean index d15e7274ec57a..9be3a61dd0e46 100644 --- a/Mathlib/Algebra/Module/BigOperators.lean +++ b/Mathlib/Algebra/Module/BigOperators.lean @@ -41,16 +41,16 @@ lemma Fintype.sum_smul_sum [Fintype α] [Fintype β] (f : α → R) (g : β → end AddCommMonoid -theorem Finset.cast_card [CommSemiring R] (s : Finset α) : (s.card : R) = ∑ a ∈ s, 1 := by - rw [Finset.sum_const, Nat.smul_one_eq_cast] - open Finset +theorem Finset.cast_card [CommSemiring R] (s : Finset α) : (#s : R) = ∑ _ ∈ s, 1 := by + rw [Finset.sum_const, Nat.smul_one_eq_cast] + namespace Fintype variable [DecidableEq ι] [Fintype ι] [AddCommMonoid α] lemma sum_piFinset_apply (f : κ → α) (s : Finset κ) (i : ι) : - ∑ g ∈ piFinset fun _ : ι ↦ s, f (g i) = s.card ^ (card ι - 1) • ∑ b ∈ s, f b := by + ∑ g ∈ piFinset fun _ : ι ↦ s, f (g i) = #s ^ (card ι - 1) • ∑ b ∈ s, f b := by classical rw [Finset.sum_comp] simp only [eval_image_piFinset_const, card_filter_piFinset_const s, ite_smul, zero_smul, smul_sum, diff --git a/Mathlib/Algebra/Module/Card.lean b/Mathlib/Algebra/Module/Card.lean index e9c8b1d5446ec..3941ffd972d1d 100644 --- a/Mathlib/Algebra/Module/Card.lean +++ b/Mathlib/Algebra/Module/Card.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 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.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.SetTheory.Cardinal.Basic /-! diff --git a/Mathlib/Algebra/Module/CharacterModule.lean b/Mathlib/Algebra/Module/CharacterModule.lean index ec58e2bbe758b..1f39cb315264c 100644 --- a/Mathlib/Algebra/Module/CharacterModule.lean +++ b/Mathlib/Algebra/Module/CharacterModule.lean @@ -108,10 +108,10 @@ Any character `c` in `(A ⊗ B)⋆` induces a linear map `A → B⋆` by `a ↦ CharacterModule (A ⊗[R] B) →ₗ[R] (A →ₗ[R] CharacterModule B) where toFun c := { toFun := (c.comp <| TensorProduct.mk R A B ·) - map_add' := fun a a' ↦ DFunLike.ext _ _ fun b ↦ + map_add' := fun _ _ ↦ DFunLike.ext _ _ fun b ↦ congr(c <| $(map_add (mk R A B) _ _) b).trans (c.map_add _ _) map_smul' := fun r a ↦ by ext; exact congr(c $(TensorProduct.tmul_smul _ _ _)).symm } - map_add' c c' := rfl + map_add' _ _ := rfl map_smul' r c := by ext; exact congr(c $(TensorProduct.tmul_smul _ _ _)).symm /-- diff --git a/Mathlib/Algebra/Module/Defs.lean b/Mathlib/Algebra/Module/Defs.lean index a80f140f53d26..394dd7a778e54 100644 --- a/Mathlib/Algebra/Module/Defs.lean +++ b/Mathlib/Algebra/Module/Defs.lean @@ -3,10 +3,8 @@ Copyright (c) 2015 Nathaniel Thomas. All rights reserved. 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.Group.Hom.End +import Mathlib.Algebra.GroupWithZero.Action.End import Mathlib.Algebra.GroupWithZero.Action.Units -import Mathlib.Algebra.Ring.Invertible -import Mathlib.Algebra.Ring.Opposite import Mathlib.Algebra.SMulWithZero import Mathlib.Data.Int.Cast.Lemmas @@ -37,16 +35,17 @@ to use a canonical `Module` typeclass throughout. semimodule, module, vector space -/ +assert_not_exists Field +assert_not_exists Invertible assert_not_exists Multiset -assert_not_exists Set.indicator assert_not_exists Pi.single_smul₀ -assert_not_exists Field +assert_not_exists Set.indicator open Function Set universe u v -variable {α R k S M M₂ M₃ ι : Type*} +variable {R S M M₂ : Type*} /-- A module is a generalization of vector spaces to a scalar semiring. It consists of a scalar semiring `R` and an additive monoid of "vectors" `M`, @@ -63,11 +62,12 @@ class Module (R : Type u) (M : Type v) [Semiring R] [AddCommMonoid M] extends section AddCommMonoid -variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x y : M) +variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x : M) -- see Note [lower instance priority] /-- A module over a semiring automatically inherits a `MulActionWithZero` structure. -/ -instance (priority := 100) Module.toMulActionWithZero : MulActionWithZero R M := +instance (priority := 100) Module.toMulActionWithZero + {R M} {_ : Semiring R} {_ : AddCommMonoid M} [Module R M] : MulActionWithZero R M := { (inferInstance : MulAction R M) with smul_zero := smul_zero zero_smul := Module.zero_smul } @@ -80,10 +80,6 @@ instance AddCommGroup.toNatModule : Module ℕ M where zero_smul := zero_nsmul add_smul r s x := add_nsmul x r s -theorem AddMonoid.End.natCast_def (n : ℕ) : - (↑n : AddMonoid.End M) = DistribMulAction.toAddMonoidEnd ℕ M n := - rfl - theorem add_smul : (r + s) • x = r • x + s • x := Module.add_smul r s x @@ -95,11 +91,6 @@ variable (R) -- Porting note: this is the letter of the mathlib3 version, but not really the spirit theorem two_smul : (2 : R) • x = x + x := by rw [← one_add_one_eq_two, add_smul, one_smul] -@[simp] -theorem invOf_two_smul_add_invOf_two_smul [Invertible (2 : R)] (x : M) : - (⅟ 2 : R) • x + (⅟ 2 : R) • x = x := - Convex.combo_self invOf_two_add_invOf_two _ - /-- Pullback a `Module` structure along an injective additive monoid homomorphism. See note [reducible non-instances]. -/ protected abbrev Function.Injective.module [AddCommMonoid M₂] [SMul R M₂] (f : M₂ →+ M) @@ -144,32 +135,7 @@ abbrev Module.compHom [Semiring S] (f : S →+* R) : Module S M := -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Heterogeneous.20scalar.20multiplication add_smul := fun r s x => show f (r + s) • x = f r • x + f s • x by simp [add_smul] } -variable (R) - -/-- `(•)` as an `AddMonoidHom`. - -This is a stronger version of `DistribMulAction.toAddMonoidEnd` -/ -@[simps! apply_apply] -def Module.toAddMonoidEnd : R →+* AddMonoid.End M := - { DistribMulAction.toAddMonoidEnd R M with - -- Porting note: the two `show`s weren't needed in mathlib3. - -- Somehow, now that `SMul` is heterogeneous, it can't unfold earlier fields of a definition for - -- use in later fields. See - -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Heterogeneous.20scalar.20multiplication - map_zero' := AddMonoidHom.ext fun r => show (0 : R) • r = 0 by simp - map_add' := fun x y => - AddMonoidHom.ext fun r => show (x + y) • r = x • r + y • r by simp [add_smul] } - -/-- A convenience alias for `Module.toAddMonoidEnd` as an `AddMonoidHom`, usually to allow the -use of `AddMonoidHom.flip`. -/ -def smulAddHom : R →+ M →+ M := - (Module.toAddMonoidEnd R M).toAddMonoidHom - -variable {R M} - -@[simp] -theorem smulAddHom_apply (r : R) (x : M) : smulAddHom R M r x = r • x := - rfl +variable {M} theorem Module.eq_zero_of_zero_eq_one (zero_eq_one : (0 : R) = 1) : x = 0 := by rw [← one_smul R x, ← zero_eq_one, zero_smul] @@ -193,10 +159,6 @@ instance AddCommGroup.toIntModule : Module ℤ M where zero_smul := zero_zsmul add_smul r s x := add_zsmul x r s -theorem AddMonoid.End.intCast_def (z : ℤ) : - (↑z : AddMonoid.End M) = DistribMulAction.toAddMonoidEnd ℤ M z := - rfl - variable {R M} theorem Convex.combo_eq_smul_sub_add [Module R M] {x y : M} {a b : R} (h : a + b = 1) : @@ -217,14 +179,12 @@ theorem Module.ext' {R : Type*} [Semiring R] {M : Type*} [AddCommMonoid M] (P Q section Module -variable [Ring R] [AddCommGroup M] [Module R M] (r s : R) (x y : M) +variable [Ring R] [AddCommGroup M] [Module R M] (r : R) (x : M) @[simp] theorem neg_smul : -r • x = -(r • x) := eq_neg_of_add_eq_zero_left <| by rw [← add_smul, neg_add_cancel, zero_smul] --- Porting note (#10618): simp can prove this ---@[simp] theorem neg_smul_neg : -r • -x = r • x := by rw [neg_smul, smul_neg, neg_neg] @[simp] @@ -280,12 +240,8 @@ instance (priority := 910) Semiring.toModule [Semiring R] : Module R R where zero_smul := zero_mul smul_zero := mul_zero --- see Note [lower instance priority] -/-- Like `Semiring.toModule`, but multiplies on the right. -/ -instance (priority := 910) Semiring.toOppositeModule [Semiring R] : Module Rᵐᵒᵖ R := - { MonoidWithZero.toOppositeMulActionWithZero R with - smul_add := fun _ _ _ => add_mul _ _ _ - add_smul := fun _ _ _ => mul_add _ _ _ } +instance [NonUnitalNonAssocSemiring R] : DistribSMul R R where + smul_add := left_distrib /-- A ring homomorphism `f : R →+* M` defines a module structure by `r • x = f r * x`. -/ def RingHom.toModule [Semiring R] [Semiring S] (f : R →+* S) : Module R S := @@ -357,239 +313,14 @@ instance AddCommMonoid.nat_isScalarTower : IsScalarTower ℕ R M where end AddCommMonoid -section AddCommGroup - -variable [Semiring S] [Ring R] [AddCommGroup M] [Module S M] [Module R M] - -section - -variable (R) - -/-- `zsmul` is equal to any other module structure via a 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 - simp - DFunLike.congr_fun this n - -@[deprecated (since := "2024-07-23")] alias intCast_smul := Int.cast_smul_eq_zsmul - -/-- `zsmul` is equal to any other module structure via a cast. -/ -@[deprecated Int.cast_smul_eq_zsmul (since := "2024-07-23")] -theorem zsmul_eq_smul_cast (n : ℤ) (b : M) : n • b = (n : R) • b := (Int.cast_smul_eq_zsmul ..).symm - -end - -/-- Convert back any exotic `ℤ`-smul to the canonical instance. This should not be needed since in -mathlib all `AddCommGroup`s should normally have exactly one `ℤ`-module structure by design. -/ -theorem int_smul_eq_zsmul (h : Module ℤ M) (n : ℤ) (x : M) : @SMul.smul ℤ M h.toSMul n x = n • x := - Int.cast_smul_eq_zsmul .. - -/-- All `ℤ`-module structures are equal. Not an instance since in mathlib all `AddCommGroup` -should normally have exactly one `ℤ`-module structure by design. -/ -def AddCommGroup.uniqueIntModule : Unique (Module ℤ M) where - default := by infer_instance - uniq P := (Module.ext' P _) fun n => by convert int_smul_eq_zsmul P n - -end AddCommGroup - -theorem map_intCast_smul [AddCommGroup M] [AddCommGroup M₂] {F : Type*} [FunLike F M M₂] - [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [Ring R] [Ring S] [Module R M] [Module S M₂] - (x : ℤ) (a : M) : - f ((x : R) • a) = (x : S) • f a := by simp only [Int.cast_smul_eq_zsmul, map_zsmul] - theorem map_natCast_smul [AddCommMonoid M] [AddCommMonoid M₂] {F : Type*} [FunLike F M M₂] [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [Semiring R] [Semiring S] [Module R M] [Module S M₂] (x : ℕ) (a : M) : f ((x : R) • a) = (x : S) • f a := by simp only [Nat.cast_smul_eq_nsmul, AddMonoidHom.map_nsmul, map_nsmul] -instance AddCommGroup.intIsScalarTower {R : Type u} {M : Type v} [Ring R] [AddCommGroup M] - [Module R M] : IsScalarTower ℤ R M where - smul_assoc n x y := ((smulAddHom R M).flip y).map_zsmul x n - -section NoZeroSMulDivisors - -/-! ### `NoZeroSMulDivisors` - -This section defines the `NoZeroSMulDivisors` class, and includes some tests -for the vanishing of elements (especially in modules over division rings). --/ - - -/-- `NoZeroSMulDivisors R M` states that a scalar multiple is `0` only if either argument is `0`. -This is a version of saying that `M` is torsion free, without assuming `R` is zero-divisor free. - -The main application of `NoZeroSMulDivisors R M`, when `M` is a module, -is the result `smul_eq_zero`: a scalar multiple is `0` iff either argument is `0`. - -It is a generalization of the `NoZeroDivisors` class to heterogeneous multiplication. --/ -@[mk_iff] -class NoZeroSMulDivisors (R M : Type*) [Zero R] [Zero M] [SMul R M] : Prop where - /-- If scalar multiplication yields zero, either the scalar or the vector was zero. -/ - eq_zero_or_eq_zero_of_smul_eq_zero : ∀ {c : R} {x : M}, c • x = 0 → c = 0 ∨ x = 0 - -export NoZeroSMulDivisors (eq_zero_or_eq_zero_of_smul_eq_zero) - -/-- Pullback a `NoZeroSMulDivisors` instance along an injective function. -/ -theorem Function.Injective.noZeroSMulDivisors {R M N : Type*} [Zero R] [Zero M] [Zero N] - [SMul R M] [SMul R N] [NoZeroSMulDivisors R N] (f : M → N) (hf : Function.Injective f) - (h0 : f 0 = 0) (hs : ∀ (c : R) (x : M), f (c • x) = c • f x) : NoZeroSMulDivisors R M := - ⟨fun {_ _} h => - Or.imp_right (@hf _ _) <| h0.symm ▸ eq_zero_or_eq_zero_of_smul_eq_zero (by rw [← hs, h, h0])⟩ - --- See note [lower instance priority] -instance (priority := 100) NoZeroDivisors.toNoZeroSMulDivisors [Zero R] [Mul R] - [NoZeroDivisors R] : NoZeroSMulDivisors R R := - ⟨fun {_ _} => eq_zero_or_eq_zero_of_mul_eq_zero⟩ - -theorem smul_ne_zero [Zero R] [Zero M] [SMul R M] [NoZeroSMulDivisors R M] {c : R} {x : M} - (hc : c ≠ 0) (hx : x ≠ 0) : c • x ≠ 0 := fun h => - (eq_zero_or_eq_zero_of_smul_eq_zero h).elim hc hx - -section SMulWithZero - -variable [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] {c : R} {x : M} - -@[simp] -theorem smul_eq_zero : c • x = 0 ↔ c = 0 ∨ x = 0 := - ⟨eq_zero_or_eq_zero_of_smul_eq_zero, fun h => - h.elim (fun h => h.symm ▸ zero_smul R x) fun h => h.symm ▸ smul_zero c⟩ - -theorem smul_ne_zero_iff : c • x ≠ 0 ↔ c ≠ 0 ∧ x ≠ 0 := by rw [Ne, smul_eq_zero, not_or] - -lemma smul_eq_zero_iff_left (hx : x ≠ 0) : c • x = 0 ↔ c = 0 := by simp [hx] -lemma smul_eq_zero_iff_right (hc : c ≠ 0) : c • x = 0 ↔ x = 0 := by simp [hc] -lemma smul_ne_zero_iff_left (hx : x ≠ 0) : c • x ≠ 0 ↔ c ≠ 0 := by simp [hx] -lemma smul_ne_zero_iff_right (hc : c ≠ 0) : c • x ≠ 0 ↔ x ≠ 0 := by simp [hc] - -end SMulWithZero - -section Module - -section Nat - -theorem Nat.noZeroSMulDivisors - (R) (M) [Semiring R] [CharZero R] [AddCommMonoid M] [Module R M] [NoZeroSMulDivisors R M] : - NoZeroSMulDivisors ℕ M where - eq_zero_or_eq_zero_of_smul_eq_zero {c x} := by rw [← Nat.cast_smul_eq_nsmul R, smul_eq_zero]; simp - -theorem two_nsmul_eq_zero - (R) (M) [Semiring R] [CharZero R] [AddCommMonoid M] [Module R M] [NoZeroSMulDivisors R M] - {v : M} : 2 • v = 0 ↔ v = 0 := by - haveI := Nat.noZeroSMulDivisors R M - simp [smul_eq_zero] - -end Nat - -variable [Semiring R] [AddCommMonoid M] [Module R M] -variable (R M) - -/-- If `M` is an `R`-module with one and `M` has characteristic zero, then `R` has characteristic -zero as well. Usually `M` is an `R`-algebra. -/ -theorem CharZero.of_module (M) [AddCommMonoidWithOne M] [CharZero M] [Module R M] : CharZero R := by - refine ⟨fun m n h => @Nat.cast_injective M _ _ _ _ ?_⟩ - rw [← nsmul_one, ← nsmul_one, ← Nat.cast_smul_eq_nsmul R, ← Nat.cast_smul_eq_nsmul R, h] - -end Module - -section AddCommGroup - --- `R` can still be a semiring here -variable [Semiring R] [AddCommGroup M] [Module R M] - -section SMulInjective - -variable (M) - -theorem smul_right_injective [NoZeroSMulDivisors R M] {c : R} (hc : c ≠ 0) : - Function.Injective (c • · : M → M) := - (injective_iff_map_eq_zero (smulAddHom R M c)).2 fun _ ha => (smul_eq_zero.mp ha).resolve_left hc - -variable {M} - -theorem smul_right_inj [NoZeroSMulDivisors R M] {c : R} (hc : c ≠ 0) {x y : M} : - c • x = c • y ↔ x = y := - (smul_right_injective M hc).eq_iff - -end SMulInjective - -section Nat - -theorem self_eq_neg - (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] - {v : M} : v = -v ↔ v = 0 := by - rw [← two_nsmul_eq_zero R M, two_smul, add_eq_zero_iff_eq_neg] - -theorem neg_eq_self - (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] - {v : M} : -v = v ↔ v = 0 := by - rw [eq_comm, self_eq_neg R M] - -theorem self_ne_neg - (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] - {v : M} : v ≠ -v ↔ v ≠ 0 := - (self_eq_neg R M).not - -theorem neg_ne_self - (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] - {v : M} : -v ≠ v ↔ v ≠ 0 := - (neg_eq_self R M).not - -end Nat - -end AddCommGroup - -section Module - -variable [Ring R] [AddCommGroup M] [Module R M] - -section SMulInjective - -variable (R) -variable [NoZeroSMulDivisors R M] - -theorem smul_left_injective {x : M} (hx : x ≠ 0) : Function.Injective fun c : R => c • x := - fun c d h => - sub_eq_zero.mp - ((smul_eq_zero.mp - (calc - (c - d) • x = c • x - d • x := sub_smul c d x - _ = 0 := sub_eq_zero.mpr h - )).resolve_right - hx) - -end SMulInjective - -instance [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := - ⟨fun {c x} hcx ↦ by rwa [← Nat.cast_smul_eq_nsmul ℤ, smul_eq_zero, Nat.cast_eq_zero] at hcx⟩ - -variable (R M) - -theorem NoZeroSMulDivisors.int_of_charZero - (R) (M) [Ring R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] [CharZero R] : - NoZeroSMulDivisors ℤ M := - ⟨fun {z x} h ↦ by simpa [← smul_one_smul R z x] using h⟩ - -/-- Only a ring of characteristic zero can have a non-trivial module without additive or -scalar torsion. -/ -theorem CharZero.of_noZeroSMulDivisors [Nontrivial M] [NoZeroSMulDivisors ℤ M] : CharZero R := by - refine ⟨fun {n m h} ↦ ?_⟩ - obtain ⟨x, hx⟩ := exists_ne (0 : M) - replace h : (n : ℤ) • x = (m : ℤ) • x := by simp [← Nat.cast_smul_eq_nsmul R, h] - simpa using smul_left_injective ℤ hx h - -end Module - -end NoZeroSMulDivisors - --- Porting note (#10618): simp can prove this ---@[simp] theorem Nat.smul_one_eq_cast {R : Type*} [NonAssocSemiring R] (m : ℕ) : m • (1 : R) = ↑m := by rw [nsmul_eq_mul, mul_one] --- Porting note (#10618): simp can prove this ---@[simp] theorem Int.smul_one_eq_cast {R : Type*} [NonAssocRing R] (m : ℤ) : m • (1 : R) = ↑m := by rw [zsmul_eq_mul, mul_one] diff --git a/Mathlib/Algebra/Module/End.lean b/Mathlib/Algebra/Module/End.lean new file mode 100644 index 0000000000000..b1269c071ad3d --- /dev/null +++ b/Mathlib/Algebra/Module/End.lean @@ -0,0 +1,117 @@ +/- +Copyright (c) 2015 Nathaniel Thomas. All rights reserved. +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.Group.Hom.End +import Mathlib.Algebra.Module.Defs + +/-! +# Module structure and endomorphisms + +In this file, we define `Module.toAddMonoidEnd`, which is `(•)` as a monoid homomorphism. +We use this to prove some results on scalar multiplication by integers. +-/ + +assert_not_exists Multiset +assert_not_exists Set.indicator +assert_not_exists Pi.single_smul₀ +assert_not_exists Field + +open Function Set + +universe u v + +variable {R S M M₂ : Type*} + +section AddCommMonoid + +variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x : M) + +theorem AddMonoid.End.natCast_def (n : ℕ) : + (↑n : AddMonoid.End M) = DistribMulAction.toAddMonoidEnd ℕ M n := + rfl + +variable (R M) + +/-- `(•)` as an `AddMonoidHom`. + +This is a stronger version of `DistribMulAction.toAddMonoidEnd` -/ +@[simps! apply_apply] +def Module.toAddMonoidEnd : R →+* AddMonoid.End M := + { DistribMulAction.toAddMonoidEnd R M with + -- Porting note: the two `show`s weren't needed in mathlib3. + -- Somehow, now that `SMul` is heterogeneous, it can't unfold earlier fields of a definition for + -- use in later fields. See + -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Heterogeneous.20scalar.20multiplication + map_zero' := AddMonoidHom.ext fun r => show (0 : R) • r = 0 by simp + map_add' := fun x y => + AddMonoidHom.ext fun r => show (x + y) • r = x • r + y • r by simp [add_smul] } + +/-- A convenience alias for `Module.toAddMonoidEnd` as an `AddMonoidHom`, usually to allow the +use of `AddMonoidHom.flip`. -/ +def smulAddHom : R →+ M →+ M := + (Module.toAddMonoidEnd R M).toAddMonoidHom + +variable {R M} + +@[simp] +theorem smulAddHom_apply (r : R) (x : M) : smulAddHom R M r x = r • x := + rfl + +end AddCommMonoid + +section AddCommGroup + +variable (R M) [Semiring R] [AddCommGroup M] + +theorem AddMonoid.End.intCast_def (z : ℤ) : + (↑z : AddMonoid.End M) = DistribMulAction.toAddMonoidEnd ℤ M z := + rfl + +end AddCommGroup + +section AddCommGroup + +variable [Ring R] [AddCommGroup M] [Module R M] + +section + +variable (R) + +/-- `zsmul` is equal to any other module structure via a 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 + simp + DFunLike.congr_fun this n + +@[deprecated (since := "2024-07-23")] alias intCast_smul := Int.cast_smul_eq_zsmul + +/-- `zsmul` is equal to any other module structure via a cast. -/ +@[deprecated Int.cast_smul_eq_zsmul (since := "2024-07-23")] +theorem zsmul_eq_smul_cast (n : ℤ) (b : M) : n • b = (n : R) • b := (Int.cast_smul_eq_zsmul ..).symm + +end + +/-- Convert back any exotic `ℤ`-smul to the canonical instance. This should not be needed since in +mathlib all `AddCommGroup`s should normally have exactly one `ℤ`-module structure by design. -/ +theorem int_smul_eq_zsmul (h : Module ℤ M) (n : ℤ) (x : M) : @SMul.smul ℤ M h.toSMul n x = n • x := + Int.cast_smul_eq_zsmul .. + +/-- All `ℤ`-module structures are equal. Not an instance since in mathlib all `AddCommGroup` +should normally have exactly one `ℤ`-module structure by design. -/ +def AddCommGroup.uniqueIntModule : Unique (Module ℤ M) where + default := by infer_instance + uniq P := (Module.ext' P _) fun n => by convert int_smul_eq_zsmul P n + +end AddCommGroup + +theorem map_intCast_smul [AddCommGroup M] [AddCommGroup M₂] {F : Type*} [FunLike F M M₂] + [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [Ring R] [Ring S] [Module R M] [Module S M₂] + (x : ℤ) (a : M) : + f ((x : R) • a) = (x : S) • f a := by simp only [Int.cast_smul_eq_zsmul, map_zsmul] + +instance AddCommGroup.intIsScalarTower {R : Type u} {M : Type v} [Ring R] [AddCommGroup M] + [Module R M] : IsScalarTower ℤ R M where + smul_assoc n x y := ((smulAddHom R M).flip y).map_zsmul x n diff --git a/Mathlib/Algebra/Module/Equiv/Basic.lean b/Mathlib/Algebra/Module/Equiv/Basic.lean index 502f5ddd8ebdf..b5a356bcc0795 100644 --- a/Mathlib/Algebra/Module/Equiv/Basic.lean +++ b/Mathlib/Algebra/Module/Equiv/Basic.lean @@ -6,6 +6,7 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro, Anne -/ import Mathlib.Algebra.Field.Defs import Mathlib.Algebra.GroupWithZero.Action.Basic +import Mathlib.Algebra.GroupWithZero.Action.Units import Mathlib.Algebra.Module.Equiv.Defs import Mathlib.Algebra.Module.Hom import Mathlib.Algebra.Module.LinearMap.End @@ -78,9 +79,9 @@ instance automorphismGroup : Group (M ≃ₗ[R] M) where mul f g := g.trans f one := LinearEquiv.refl R M inv f := f.symm - mul_assoc f g h := rfl - mul_one f := ext fun x ↦ rfl - one_mul f := ext fun x ↦ rfl + mul_assoc _ _ _ := rfl + mul_one _ := ext fun _ ↦ rfl + one_mul _ := ext fun _ ↦ rfl inv_mul_cancel f := ext <| f.left_inv @[simp] diff --git a/Mathlib/Algebra/Module/Equiv/Defs.lean b/Mathlib/Algebra/Module/Equiv/Defs.lean index 9a5d7dcbdfd0d..cf3df68ab785c 100644 --- a/Mathlib/Algebra/Module/Equiv/Defs.lean +++ b/Mathlib/Algebra/Module/Equiv/Defs.lean @@ -38,11 +38,9 @@ assert_not_exists Pi.module open Function -universe u u' v w x y z - variable {R : Type*} {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} -variable {k : Type*} {K : Type*} {S : Type*} {M : Type*} {M₁ : Type*} {M₂ : Type*} {M₃ : Type*} -variable {N₁ : Type*} {N₂ : Type*} {N₃ : Type*} {N₄ : Type*} {ι : Type*} +variable {S : Type*} {M : Type*} {M₁ : Type*} {M₂ : Type*} {M₃ : Type*} +variable {N₁ : Type*} {N₂ : Type*} section @@ -133,7 +131,6 @@ namespace LinearEquiv section AddCommMonoid -variable {M₄ : Type*} variable [Semiring R] [Semiring S] section @@ -171,15 +168,6 @@ instance : EquivLike (M ≃ₛₗ[σ] M₂) M M₂ where left_inv := LinearEquiv.left_inv right_inv := LinearEquiv.right_inv -/-- Helper instance for when inference gets stuck on following the normal chain -`EquivLike → FunLike`. - -TODO: this instance doesn't appear to be necessary: remove it (after benchmarking?) --/ -instance : FunLike (M ≃ₛₗ[σ] M₂) M M₂ where - coe := DFunLike.coe - coe_injective' := DFunLike.coe_injective - instance : SemilinearEquivClass (M ≃ₛₗ[σ] M₂) σ M M₂ where map_add := (·.map_add') --map_add' Porting note (#11215): TODO why did I need to change this? map_smulₛₗ := (·.map_smul') --map_smul' Porting note (#11215): TODO why did I need to change this? @@ -198,7 +186,7 @@ section variable [Semiring R₁] [Semiring R₂] [Semiring R₃] variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] -variable [AddCommMonoid M₃] [AddCommMonoid M₄] +variable [AddCommMonoid M₃] variable [AddCommMonoid N₁] [AddCommMonoid N₂] variable {module_M : Module R M} {module_S_M₂ : Module S M₂} {σ : R →+* S} {σ' : S →+* R} variable {re₁ : RingHomInvPair σ σ'} {re₂ : RingHomInvPair σ' σ} @@ -403,6 +391,18 @@ theorem toLinearMap_symm_comp_eq (f : M₃ →ₛₗ[σ₃₁] M₁) (g : M₃ · simp [← H, ← e₁₂.toEquiv.symm_comp_eq f g] · simp [H, e₁₂.toEquiv.symm_comp_eq f g] +@[simp] +theorem comp_toLinearMap_eq_iff (f g : M₃ →ₛₗ[σ₃₁] M₁) : + e₁₂.toLinearMap.comp f = e₁₂.toLinearMap.comp g ↔ f = g := by + refine ⟨fun h => ?_, congrArg e₁₂.comp⟩ + rw [← (toLinearMap_symm_comp_eq g (e₁₂.toLinearMap.comp f)).mpr h, eq_toLinearMap_symm_comp] + +@[simp] +theorem eq_comp_toLinearMap_iff (f g : M₂ →ₛₗ[σ₂₃] M₃) : + f.comp e₁₂.toLinearMap = g.comp e₁₂.toLinearMap ↔ f = g := by + refine ⟨fun h => ?_, fun a ↦ congrFun (congrArg LinearMap.comp a) e₁₂.toLinearMap⟩ + rw [(eq_comp_toLinearMap_symm g (f.comp e₁₂.toLinearMap)).mpr h.symm, eq_comp_toLinearMap_symm] + @[simp] theorem refl_symm [Module R M] : (refl R M).symm = LinearEquiv.refl R M := rfl @@ -506,8 +506,7 @@ def _root_.RingEquiv.toSemilinearEquiv (f : R ≃+* S) : toFun := f map_smul' := f.map_mul } -variable [Semiring R₁] [Semiring R₂] [Semiring R₃] -variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] +variable [AddCommMonoid M] /-- An involutive linear map is a linear equivalence. -/ def ofInvolutive {σ σ' : R →+* R} [RingHomInvPair σ σ'] [RingHomInvPair σ' σ] diff --git a/Mathlib/Algebra/Module/Opposites.lean b/Mathlib/Algebra/Module/Equiv/Opposite.lean similarity index 73% rename from Mathlib/Algebra/Module/Opposites.lean rename to Mathlib/Algebra/Module/Equiv/Opposite.lean index 914d9f3145572..1412025bff29f 100644 --- a/Mathlib/Algebra/Module/Opposites.lean +++ b/Mathlib/Algebra/Module/Equiv/Opposite.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ -import Mathlib.Algebra.GroupWithZero.Action.Opposite import Mathlib.Algebra.Module.Equiv.Defs +import Mathlib.Algebra.Module.Opposite /-! # Module operations on `Mᵐᵒᵖ` @@ -13,6 +13,23 @@ This file contains definitions that build on top of the group action definitions `Mathlib.Algebra.GroupWithZero.Action.Opposite`. -/ +section + +variable {R S M : Type*} [Semiring R] [Semiring S] [AddCommMonoid M] [Module S M] + +@[ext high] +theorem LinearMap.ext_ring_op + {σ : Rᵐᵒᵖ →+* S} {f g : R →ₛₗ[σ] M} (h : f (1 : R) = g (1 : R)) : + f = g := + ext fun x ↦ by + -- Porting note: replaced the oneliner `rw` proof with a partially term-mode proof + -- because `rw` was giving "motive is type incorrect" errors + rw [← one_mul x, ← op_smul_eq_mul] + refine (f.map_smulₛₗ (MulOpposite.op x) 1).trans ?_ + rw [h] + exact (g.map_smulₛₗ (MulOpposite.op x) 1).symm + +end namespace MulOpposite @@ -20,11 +37,6 @@ universe u v variable (R : Type u) {M : Type v} [Semiring R] [AddCommMonoid M] [Module R M] -/-- `MulOpposite.distribMulAction` extends to a `Module` -/ -instance instModule : Module R Mᵐᵒᵖ where - add_smul _ _ _ := unop_injective <| add_smul _ _ _ - zero_smul _ := unop_injective <| zero_smul _ _ - /-- The function `op` is a linear equivalence. -/ def opLinearEquiv : M ≃ₗ[R] Mᵐᵒᵖ := { opAddEquiv with map_smul' := MulOpposite.op_smul } diff --git a/Mathlib/Algebra/Module/FinitePresentation.lean b/Mathlib/Algebra/Module/FinitePresentation.lean index 024751ec3f4b5..32e989298a018 100644 --- a/Mathlib/Algebra/Module/FinitePresentation.lean +++ b/Mathlib/Algebra/Module/FinitePresentation.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.RingTheory.Noetherian -import Mathlib.Algebra.Module.LocalizedModule +import Mathlib.RingTheory.Localization.Module import Mathlib.LinearAlgebra.Isomorphisms import Mathlib.LinearAlgebra.FreeModule.Finite.Basic /-! @@ -289,10 +289,10 @@ lemma Module.Finite.exists_smul_of_comp_eq_of_isLocalizedModule simp only [SetLike.mem_coe, LinearMap.mem_ker, LinearMap.sub_apply, LinearMap.smul_apply, sub_eq_zero, ← Finset.prod_erase_mul σ s hx, mul_smul, hs] -lemma Module.FinitePresentation.isLocalizedModule_map - {M' : Type*} [AddCommGroup M'] [Module R M'] (f : M →ₗ[R] M') [IsLocalizedModule S f] - {N' : Type*} [AddCommGroup N'] [Module R N'] (g : N →ₗ[R] N') [IsLocalizedModule S g] - [Module.FinitePresentation R M] : +variable {M' : Type*} [AddCommGroup M'] [Module R M'] (f : M →ₗ[R] M') [IsLocalizedModule S f] +variable {N' : Type*} [AddCommGroup N'] [Module R N'] (g : N →ₗ[R] N') [IsLocalizedModule S g] + +instance Module.FinitePresentation.isLocalizedModule_map [Module.FinitePresentation R M] : IsLocalizedModule S (IsLocalizedModule.map S f g) := by constructor · intro s @@ -315,4 +315,11 @@ lemma Module.FinitePresentation.isLocalizedModule_map ext x simpa using LinearMap.congr_fun e (f x) +instance Module.FinitePresentation.isLocalizedModule_mapExtendScalars + (Rₛ) [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ M'] [Module Rₛ N'] + [IsScalarTower R Rₛ M'] [IsScalarTower R Rₛ N'] [IsLocalization S Rₛ] + [Module.FinitePresentation R M] : + IsLocalizedModule S (IsLocalizedModule.mapExtendScalars S f g Rₛ) := + IsLocalizedModule.of_linearEquiv _ _ _ + end CommRing diff --git a/Mathlib/Algebra/Module/Hom.lean b/Mathlib/Algebra/Module/Hom.lean index 19bee131fe2dd..66bdfade35658 100644 --- a/Mathlib/Algebra/Module/Hom.lean +++ b/Mathlib/Algebra/Module/Hom.lean @@ -3,8 +3,9 @@ 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.Module.Defs import Mathlib.Algebra.Group.Hom.Instances +import Mathlib.Algebra.Module.End +import Mathlib.Algebra.Ring.Opposite import Mathlib.GroupTheory.GroupAction.DomAct.Basic /-! diff --git a/Mathlib/Algebra/Module/Injective.lean b/Mathlib/Algebra/Module/Injective.lean index 9462f04c45e08..9e82f0784bba8 100644 --- a/Mathlib/Algebra/Module/Injective.lean +++ b/Mathlib/Algebra/Module/Injective.lean @@ -3,11 +3,10 @@ Copyright (c) 2022 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ -import Mathlib.CategoryTheory.Preadditive.Injective -import Mathlib.Algebra.Category.ModuleCat.EpiMono -import Mathlib.RingTheory.Ideal.Basic import Mathlib.LinearAlgebra.LinearPMap import Mathlib.Logic.Equiv.TransferInstance +import Mathlib.Logic.Small.Basic +import Mathlib.RingTheory.Ideal.Defs /-! # Injective modules @@ -33,6 +32,7 @@ import Mathlib.Logic.Equiv.TransferInstance -/ +assert_not_exists ModuleCat noncomputable section @@ -57,26 +57,6 @@ map to `Q`, i.e. in the following diagram, if `f` is injective then there is an (f : X →ₗ[R] Y) (_ : Function.Injective f) (g : X →ₗ[R] Q), ∃ h : Y →ₗ[R] Q, ∀ x, h (f x) = g x -theorem Module.injective_object_of_injective_module [inj : Module.Injective R Q] : - CategoryTheory.Injective (ModuleCat.of R Q) where - factors g f m := - have ⟨l, h⟩ := inj.out f ((ModuleCat.mono_iff_injective f).mp m) g - ⟨l, LinearMap.ext h⟩ - -theorem Module.injective_module_of_injective_object - [inj : CategoryTheory.Injective <| ModuleCat.of R Q] : - Module.Injective R Q where - out X Y _ _ _ _ f hf g := by - have : CategoryTheory.Mono (ModuleCat.ofHom f) := (ModuleCat.mono_iff_injective _).mpr hf - obtain ⟨l, rfl⟩ := inj.factors (ModuleCat.ofHom g) (ModuleCat.ofHom f) - exact ⟨l, fun _ ↦ rfl⟩ - -theorem Module.injective_iff_injective_object : - Module.Injective R Q ↔ - CategoryTheory.Injective (ModuleCat.of R Q) := - ⟨fun _ => injective_object_of_injective_module R Q, - fun _ => injective_module_of_injective_object R Q⟩ - /-- An `R`-module `Q` satisfies Baer's criterion if any `R`-linear map from an `Ideal R` extends to an `R`-linear map `R ⟶ Q`-/ def Module.Baer : Prop := @@ -126,7 +106,7 @@ instance : Inf (ExtensionOf i f) where refine ⟨X1.le (Set.mem_range_self _), X2.le (Set.mem_range_self _), ?_⟩ rw [← X1.is_extension x, ← X2.is_extension x] : x ∈ X1.toLinearPMap.eqLocus X2.toLinearPMap) - is_extension := fun m => X1.is_extension _ } + is_extension := fun _ => X1.is_extension _ } instance : SemilatticeInf (ExtensionOf i f) := Function.Injective.semilatticeInf ExtensionOf.toLinearPMap @@ -440,13 +420,6 @@ lemma Module.injective_iff_ulift_injective : ⟨Module.ulift_injective_of_injective R, Module.injective_of_ulift_injective R⟩ -instance ModuleCat.ulift_injective_of_injective - [inj : CategoryTheory.Injective <| ModuleCat.of R M] : - CategoryTheory.Injective <| ModuleCat.of R (ULift.{v'} M) := - Module.injective_object_of_injective_module - (inj := Module.ulift_injective_of_injective - (inj := Module.injective_module_of_injective_object (inj := inj))) - end ULift section lifting_property diff --git a/Mathlib/Algebra/Module/LinearMap/Basic.lean b/Mathlib/Algebra/Module/LinearMap/Basic.lean index f50429fa64814..b82258f2ecc03 100644 --- a/Mathlib/Algebra/Module/LinearMap/Basic.lean +++ b/Mathlib/Algebra/Module/LinearMap/Basic.lean @@ -5,7 +5,8 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro, Anne Frédéric Dupuis, Heather Macbeth -/ import Mathlib.Algebra.Module.LinearMap.Defs -import Mathlib.Algebra.Module.Pi +import Mathlib.Algebra.NoZeroSMulDivisors.Pi +import Mathlib.Algebra.Ring.Opposite import Mathlib.GroupTheory.GroupAction.DomAct.Basic /-! @@ -21,41 +22,41 @@ open Function universe u u' v w x y z -variable {R R₁ R₂ R₃ k S S₃ T M M₁ M₂ M₃ N₁ N₂ N₃ ι : Type*} +variable {R R' S M M' : Type*} namespace LinearMap section SMul -variable [Semiring R] [Semiring R₂] -variable [AddCommMonoid M] [AddCommMonoid M₂] -variable [Module R M] [Module R₂ M₂] -variable {σ₁₂ : R →+* R₂} +variable [Semiring R] [Semiring R'] +variable [AddCommMonoid M] [AddCommMonoid M'] +variable [Module R M] [Module R' M'] +variable {σ₁₂ : R →+* R'} variable {S' T' : Type*} variable [Monoid S'] [DistribMulAction S' M] [SMulCommClass R S' M] variable [Monoid T'] [DistribMulAction T' M] [SMulCommClass R T' M] -instance : SMul S'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M₂) where +instance : SMul S'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M') where smul a f := - { toFun := a • (f : M → M₂) + { toFun := a • (f : M → M') map_add' := fun x y ↦ by simp only [DomMulAct.smul_apply, f.map_add, smul_add] map_smul' := fun c x ↦ by simp_rw [DomMulAct.smul_apply, ← smul_comm, f.map_smulₛₗ] } -theorem _root_.DomMulAct.smul_linearMap_apply (a : S'ᵈᵐᵃ) (f : M →ₛₗ[σ₁₂] M₂) (x : M) : +theorem _root_.DomMulAct.smul_linearMap_apply (a : S'ᵈᵐᵃ) (f : M →ₛₗ[σ₁₂] M') (x : M) : (a • f) x = f (DomMulAct.mk.symm a • x) := rfl @[simp] -theorem _root_.DomMulAct.mk_smul_linearMap_apply (a : S') (f : M →ₛₗ[σ₁₂] M₂) (x : M) : +theorem _root_.DomMulAct.mk_smul_linearMap_apply (a : S') (f : M →ₛₗ[σ₁₂] M') (x : M) : (DomMulAct.mk a • f) x = f (a • x) := rfl -theorem _root_.DomMulAct.coe_smul_linearMap (a : S'ᵈᵐᵃ) (f : M →ₛₗ[σ₁₂] M₂) : - (a • f : M →ₛₗ[σ₁₂] M₂) = a • (f : M → M₂) := +theorem _root_.DomMulAct.coe_smul_linearMap (a : S'ᵈᵐᵃ) (f : M →ₛₗ[σ₁₂] M') : + (a • f : M →ₛₗ[σ₁₂] M') = a • (f : M → M') := rfl -instance [SMulCommClass S' T' M] : SMulCommClass S'ᵈᵐᵃ T'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M₂) := +instance [SMulCommClass S' T' M] : SMulCommClass S'ᵈᵐᵃ T'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M') := ⟨fun s t f ↦ ext fun m ↦ by simp_rw [DomMulAct.smul_linearMap_apply, smul_comm]⟩ end SMul @@ -63,19 +64,15 @@ end SMul section Actions -variable [Semiring R] [Semiring R₂] [Semiring R₃] -variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] -variable {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] +variable [Semiring R] [Semiring R'] +variable [AddCommMonoid M] [AddCommMonoid M'] +variable [Module R M] [Module R' M'] +variable {σ₁₂ : R →+* R'} section SMul -variable [Monoid S] [DistribMulAction S M₂] [SMulCommClass R₂ S M₂] -variable [Monoid S₃] [DistribMulAction S₃ M₃] [SMulCommClass R₃ S₃ M₃] -variable [Monoid T] [DistribMulAction T M₂] [SMulCommClass R₂ T M₂] - instance {S'} [Monoid S'] [DistribMulAction S' M] [SMulCommClass R S' M] : - DistribMulAction S'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M₂) where + DistribMulAction S'ᵈᵐᵃ (M →ₛₗ[σ₁₂] M') where one_smul _ := ext fun _ ↦ congr_arg _ (one_smul _ _) mul_smul _ _ _ := ext fun _ ↦ congr_arg _ (mul_smul _ _ _) smul_add _ _ _ := ext fun _ ↦ rfl @@ -85,12 +82,12 @@ end SMul section Module -variable [Semiring S] [Module S M] [Module S M₂] [SMulCommClass R₂ S M₂] +variable [Semiring S] [Module S M] [Module S M'] [SMulCommClass R' S M'] -instance [NoZeroSMulDivisors S M₂] : NoZeroSMulDivisors S (M →ₛₗ[σ₁₂] M₂) := +instance [NoZeroSMulDivisors S M'] : NoZeroSMulDivisors S (M →ₛₗ[σ₁₂] M') := coe_injective.noZeroSMulDivisors _ rfl coe_smul -instance [SMulCommClass R S M] : Module Sᵈᵐᵃ (M →ₛₗ[σ₁₂] M₂) where +instance [SMulCommClass R S M] : Module Sᵈᵐᵃ (M →ₛₗ[σ₁₂] M') where add_smul _ _ _ := ext fun _ ↦ by simp_rw [add_apply, DomMulAct.smul_linearMap_apply, ← map_add, ← add_smul]; rfl zero_smul _ := ext fun _ ↦ by erw [DomMulAct.smul_linearMap_apply, zero_smul, map_zero]; rfl diff --git a/Mathlib/Algebra/Module/LinearMap/Defs.lean b/Mathlib/Algebra/Module/LinearMap/Defs.lean index e2c0d89223846..f0138c3409d11 100644 --- a/Mathlib/Algebra/Module/LinearMap/Defs.lean +++ b/Mathlib/Algebra/Module/LinearMap/Defs.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, Anne Baanen, Frédéric Dupuis, Heather Macbeth -/ -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Group.Hom.Instances import Mathlib.Algebra.Ring.CompTypeclasses import Mathlib.GroupTheory.GroupAction.Hom @@ -57,9 +57,9 @@ assert_not_exists Field open Function -universe u u' v w x y z +universe u u' v w -variable {R R₁ R₂ R₃ k S S₃ T M M₁ M₂ M₃ N₁ N₂ N₃ ι : Type*} +variable {R R₁ R₂ R₃ S S₃ T M M₁ M₂ M₃ N₂ N₃ : Type*} /-- A map `f` between modules over a semiring is linear if it satisfies the two properties `f (x + y) = f x + f y` and `f (c • x) = c • f x`. The predicate `IsLinearMap R f` asserts this @@ -110,10 +110,6 @@ class SemilinearMapClass (F : Type*) {R S : outParam Type*} [Semiring R] [Semiri end --- Porting note: `dangerousInstance` linter has become smarter about `outParam`s --- `σ` becomes a metavariable but that's fine because it's an `outParam` --- attribute [nolint dangerousInstance] SemilinearMapClass.toAddHomClass - -- `map_smulₛₗ` should be `@[simp]` but doesn't fire due to `lean4#3701`. -- attribute [simp] map_smulₛₗ @@ -139,7 +135,6 @@ variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMon variable [Module R M] [Module R M₂] [Module S M₃] variable {σ : R →+* S} --- Porting note: the `dangerousInstance` linter has become smarter about `outParam`s instance (priority := 100) instAddMonoidHomClass [FunLike F M M₃] [SemilinearMapClass F σ M M₃] : AddMonoidHomClass F M M₃ := { SemilinearMapClass.toAddHomClass with @@ -194,7 +189,6 @@ variable [Semiring R] [Semiring S] section variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [AddCommMonoid N₁] [AddCommMonoid N₂] [AddCommMonoid N₃] variable [Module R M] [Module R M₂] [Module S M₃] variable {σ : R →+* S} @@ -216,8 +210,6 @@ lemma coe_coe {F : Type*} [FunLike F M M₃] [SemilinearMapClass F σ M M₃] {f ⇑(f : M →ₛₗ[σ] M₃) = f := rfl --- Porting note: we don't port specialized `CoeFun` instances if there is `DFunLike` instead - /-- The `DistribMulActionHom` underlying a `LinearMap`. -/ def toDistribMulActionHom (f : M →ₛₗ[σ] M₃) : DistribMulActionHom σ.toMonoidHom M M₃ := { f with map_zero' := show f 0 = 0 from map_zero f } @@ -286,7 +278,7 @@ as a `σ`-semilinear map for any ring homomorphism `σ` which we know is the ide @[simps] def id' {σ : R →+* R} [RingHomId σ] : M →ₛₗ[σ] M where toFun x := x - map_add' x y := rfl + map_add' _ _ := rfl map_smul' r x := by have := (RingHomId.eq_id : σ = _) subst this @@ -301,15 +293,14 @@ end section variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [AddCommMonoid N₁] [AddCommMonoid N₂] [AddCommMonoid N₃] variable [Module R M] [Module R M₂] [Module S M₃] variable (σ : R →+* S) -variable (fₗ gₗ : M →ₗ[R] M₂) (f g : M →ₛₗ[σ] M₃) +variable (fₗ : M →ₗ[R] M₂) (f g : M →ₛₗ[σ] M₃) theorem isLinear : IsLinearMap R fₗ := ⟨fₗ.map_add', fₗ.map_smul'⟩ -variable {fₗ gₗ f g σ} +variable {fₗ f g σ} theorem coe_injective : Injective (DFunLike.coe : (M →ₛₗ[σ] M₃) → _) := DFunLike.coe_injective @@ -325,7 +316,7 @@ protected theorem congr_fun (h : f = g) (x : M) : f x = g x := theorem mk_coe (f : M →ₛₗ[σ] M₃) (h) : (LinearMap.mk f h : M →ₛₗ[σ] M₃) = f := rfl -variable (fₗ gₗ f g) +variable (fₗ f g) protected theorem map_add (x y : M) : f (x + y) = f x + f y := map_add f x y @@ -452,17 +443,6 @@ theorem toAddMonoidHom_injective : theorem ext_ring {f g : R →ₛₗ[σ] M₃} (h : f 1 = g 1) : f = g := ext fun x ↦ by rw [← mul_one x, ← smul_eq_mul, f.map_smulₛₗ, g.map_smulₛₗ, h] -@[ext high] -theorem ext_ring_op {σ : Rᵐᵒᵖ →+* S} {f g : R →ₛₗ[σ] M₃} (h : f (1 : R) = g (1 : R)) : - f = g := - ext fun x ↦ by - -- Porting note: replaced the oneliner `rw` proof with a partially term-mode proof - -- because `rw` was giving "motive is type incorrect" errors - rw [← one_mul x, ← op_smul_eq_mul] - refine (f.map_smulₛₗ (MulOpposite.op x) 1).trans ?_ - rw [h] - exact (g.map_smulₛₗ (MulOpposite.op x) 1).symm - end /-- Interpret a `RingHom` `f` as an `f`-semilinear map. -/ @@ -539,7 +519,7 @@ theorem cancel_left (hf : Injective f) : f.comp g = f.comp g' ↔ g = g' := end -variable [AddCommMonoid M] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] +variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] /-- If a function `g` is a left and right inverse of a linear map `f`, then `g` is linear itself. -/ def inverse [Module R M] [Module S M₂] {σ : R →+* S} {σ' : S →+* R} [RingHomInvPair σ σ'] @@ -723,12 +703,11 @@ namespace LinearMap section SMul -variable [Semiring R] [Semiring R₂] [Semiring R₃] -variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] -variable {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] +variable [Semiring R] [Semiring R₂] +variable [AddCommMonoid M] [AddCommMonoid M₂] +variable [Module R M] [Module R₂ M₂] +variable {σ₁₂ : R →+* R₂} variable [Monoid S] [DistribMulAction S M₂] [SMulCommClass R₂ S M₂] -variable [Monoid S₃] [DistribMulAction S₃ M₃] [SMulCommClass R₃ S₃ M₃] variable [Monoid T] [DistribMulAction T M₂] [SMulCommClass R₂ T M₂] instance : SMul S (M →ₛₗ[σ₁₂] M₂) := @@ -764,9 +743,9 @@ section Arithmetic variable [Semiring R₁] [Semiring R₂] [Semiring R₃] variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [AddCommGroup N₁] [AddCommGroup N₂] [AddCommGroup N₃] +variable [AddCommGroup N₂] [AddCommGroup N₃] variable [Module R₁ M] [Module R₂ M₂] [Module R₃ M₃] -variable [Module R₁ N₁] [Module R₂ N₂] [Module R₃ N₃] +variable [Module R₂ N₂] [Module R₃ N₃] variable {σ₁₂ : R₁ →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R₁ →+* R₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] /-- The constant 0 map is linear. -/ @@ -899,7 +878,6 @@ section SMul variable [Monoid S] [DistribMulAction S M₂] [SMulCommClass R₂ S M₂] variable [Monoid S₃] [DistribMulAction S₃ M₃] [SMulCommClass R₃ S₃ M₃] -variable [Monoid T] [DistribMulAction T M₂] [SMulCommClass R₂ T M₂] instance : DistribMulAction S (M →ₛₗ[σ₁₂] M₂) where one_smul _ := ext fun _ ↦ one_smul _ _ diff --git a/Mathlib/Algebra/Module/LinearMap/End.lean b/Mathlib/Algebra/Module/LinearMap/End.lean index 0c0b70a638554..f2c1f9a46d3d6 100644 --- a/Mathlib/Algebra/Module/LinearMap/End.lean +++ b/Mathlib/Algebra/Module/LinearMap/End.lean @@ -6,6 +6,8 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro, Anne -/ import Mathlib.Algebra.GroupPower.IterateHom import Mathlib.Algebra.Module.LinearMap.Defs +import Mathlib.Algebra.Module.Equiv.Opposite +import Mathlib.Algebra.NoZeroSMulDivisors.Defs /-! # Endomorphisms of a module @@ -67,7 +69,7 @@ instance _root_.Module.End.instNontrivial [Nontrivial M] : Nontrivial (Module.En instance _root_.Module.End.monoid : Monoid (Module.End R M) where mul := (· * ·) one := (1 : M →ₗ[R] M) - mul_assoc f g h := LinearMap.ext fun x ↦ rfl + mul_assoc _ _ _ := LinearMap.ext fun _ ↦ rfl mul_one := comp_id one_mul := id_comp diff --git a/Mathlib/Algebra/Module/LinearMap/Prod.lean b/Mathlib/Algebra/Module/LinearMap/Prod.lean index c21bf6e0c5a84..5b80a635be778 100644 --- a/Mathlib/Algebra/Module/LinearMap/Prod.lean +++ b/Mathlib/Algebra/Module/LinearMap/Prod.lean @@ -35,9 +35,7 @@ theorem isLinearMap_sub [AddCommGroup M] [Module R M] : IsLinearMap R fun x : M × M => x.1 - x.2 := by apply IsLinearMap.mk · intro x y - -- porting note (#10745): was `simp [add_comm, add_left_comm, sub_eq_add_neg]` - rw [Prod.fst_add, Prod.snd_add] - abel + simp [add_comm, add_assoc, add_left_comm, sub_eq_add_neg] · intro x y simp [smul_sub] diff --git a/Mathlib/Algebra/Module/LocalizedModule.lean b/Mathlib/Algebra/Module/LocalizedModule.lean index 5edf2a007db89..5eaa8d3b23559 100644 --- a/Mathlib/Algebra/Module/LocalizedModule.lean +++ b/Mathlib/Algebra/Module/LocalizedModule.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang, Jujian Zhang -/ import Mathlib.Algebra.Algebra.Bilinear -import Mathlib.RingTheory.Localization.Basic import Mathlib.Algebra.Exact +import Mathlib.Algebra.Algebra.Tower +import Mathlib.RingTheory.Localization.Defs /-! # Localized Module @@ -59,7 +60,7 @@ theorem r.isEquiv : IsEquiv _ (r S M) := have hu2' := congr_arg ((u1 * s1) • ·) hu2.symm simp only [← mul_smul, smul_assoc, mul_assoc, mul_comm, mul_left_comm] at hu1' hu2' ⊢ rw [hu2', hu1'] - symm := fun ⟨m1, s1⟩ ⟨m2, s2⟩ ⟨u, hu⟩ => ⟨u, hu.symm⟩ } + symm := fun ⟨_, _⟩ ⟨_, _⟩ ⟨u, hu⟩ => ⟨u, hu.symm⟩ } instance r.setoid : Setoid (M × S) where r := r S M @@ -484,7 +485,7 @@ variable (S M) def mkLinearMap : M →ₗ[R] LocalizedModule S M where toFun m := mk m 1 map_add' x y := by simp [mk_add_mk] - map_smul' r x := (smul'_mk _ _ _).symm + map_smul' _ _ := (smul'_mk _ _ _).symm end @@ -628,7 +629,7 @@ noncomputable def lift' (g : M →ₗ[R] M'') simp only [Submonoid.smul_def, ← g.map_smul, eq1] have : Function.Injective (h c).unit.inv := ((Module.End_isUnit_iff _).1 (by simp)).1 apply_fun (h c).unit.inv - erw [Units.inv_eq_val_inv, Module.End_algebraMap_isUnit_inv_apply_eq_iff, ← + rw [Units.inv_eq_val_inv, Module.End_algebraMap_isUnit_inv_apply_eq_iff, ← (h c).unit⁻¹.val.map_smul] symm rw [Module.End_algebraMap_isUnit_inv_apply_eq_iff, ← g.map_smul, ← g.map_smul, ← g.map_smul, ← @@ -648,13 +649,13 @@ theorem lift'_add (g : M →ₗ[R] M'') (h : ∀ x : S, IsUnit ((algebraMap R (M intro a a' b b' erw [LocalizedModule.lift'_mk, LocalizedModule.lift'_mk, LocalizedModule.lift'_mk] -- Porting note: We remove `generalize_proofs h1 h2 h3`. This only generalize `h1`. - erw [map_add, Module.End_algebraMap_isUnit_inv_apply_eq_iff, smul_add, ← map_smul, + rw [map_add, Module.End_algebraMap_isUnit_inv_apply_eq_iff, smul_add, ← map_smul, ← map_smul, ← map_smul] congr 1 <;> symm · erw [Module.End_algebraMap_isUnit_inv_apply_eq_iff, mul_smul, ← map_smul] rfl · dsimp - erw [Module.End_algebraMap_isUnit_inv_apply_eq_iff, mul_comm, mul_smul, ← map_smul] + rw [Module.End_algebraMap_isUnit_inv_apply_eq_iff, mul_comm, mul_smul, ← map_smul] rfl) x y @@ -1002,8 +1003,6 @@ theorem mk'_mul_mk' {M M' : Type*} [Semiring M] [Semiring M'] [Algebra R M] [Alg variable {f} -/-- Porting note (#10618): simp can prove this -@[simp] -/ theorem mk'_eq_iff {m : M} {s : S} {m' : M'} : mk' f m s = m' ↔ f m = s • m' := by rw [← smul_inj f s, Submonoid.smul_def, ← mk'_smul, ← Submonoid.smul_def, mk'_cancel] @@ -1038,7 +1037,7 @@ theorem mk'_surjective : Function.Surjective (Function.uncurry <| mk' f : M × S obtain ⟨⟨m, s⟩, e : s • x = f m⟩ := IsLocalizedModule.surj S f x exact ⟨⟨m, s⟩, mk'_eq_iff.mpr e.symm⟩ -variable {N N'} [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] +variable {N N'} [AddCommMonoid N] [AddCommMonoid N'] [Module R N] [Module R N'] variable (g : N →ₗ[R] N') [IsLocalizedModule S g] /-- A linear map `M →ₗ[R] N` gives a map between localized modules `Mₛ →ₗ[R] Nₛ`. -/ @@ -1068,6 +1067,31 @@ lemma map_mk' (h : M →ₗ[R] N) (x) (s : S) : rw [iso_symm_apply' S f (mk' f x s) x s (mk'_cancel' f x s), LocalizedModule.lift_mk] rfl +@[simp] +lemma map_id : map S f f (.id ) = .id := by + ext x + obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S f x + simp + +@[simp] +theorem map_injective (h : M →ₗ[R] N) (h_inj : Function.Injective h) : + Function.Injective (map S f g h) := by + intros x y + obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S f x + obtain ⟨⟨y, t⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S f y + simp only [Function.uncurry_apply_pair, map_mk', mk'_eq_mk'_iff, Subtype.exists, + Submonoid.mk_smul, exists_prop, forall_exists_index, and_imp] + intros c hc e + exact ⟨c, hc, h_inj (by simpa)⟩ + +@[simp] +theorem map_surjective (h : M →ₗ[R] N) (h_surj : Function.Surjective h) : + Function.Surjective (map S f g h) := by + intros x + obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S g x + obtain ⟨x, rfl⟩ := h_surj x + exact ⟨mk' f x s, by simp⟩ + open LocalizedModule LinearEquiv LinearMap Submonoid variable (M) @@ -1079,9 +1103,9 @@ lemma iso_localizedModule_eq_refl : iso S (mkLinearMap S M) = refl R (LocalizedM rw [← toLinearMap_inj, univ (iso S f) ((eq_toLinearMap_symm_comp f f).1 (iso_symm_comp S f).symm)] exact Eq.symm <| univ (refl R (LocalizedModule S M)) (by simp) -variable {M₀ M₀'} [AddCommGroup M₀] [AddCommGroup M₀'] [Module R M₀] [Module R M₀'] +variable {M₀ M₀'} [AddCommMonoid M₀] [AddCommMonoid M₀'] [Module R M₀] [Module R M₀'] variable (f₀ : M₀ →ₗ[R] M₀') [IsLocalizedModule S f₀] -variable {M₁ M₁'} [AddCommGroup M₁] [AddCommGroup M₁'] [Module R M₁] [Module R M₁'] +variable {M₁ M₁'} [AddCommMonoid M₁] [AddCommMonoid M₁'] [Module R M₁] [Module R M₁'] variable (f₁ : M₁ →ₗ[R] M₁') [IsLocalizedModule S f₁] /-- Formula for `IsLocalizedModule.map` when each localized module is a `LocalizedModule`.-/ @@ -1106,9 +1130,9 @@ namespace LocalizedModule open IsLocalizedModule LocalizedModule Function Submonoid -variable {M₀ M₀'} [AddCommGroup M₀] [Module R M₀] -variable {M₁ M₁'} [AddCommGroup M₁] [Module R M₁] -variable {M₂ M₂'} [AddCommGroup M₂] [Module R M₂] +variable {M₀ M₀'} [AddCommMonoid M₀] [Module R M₀] +variable {M₁ M₁'} [AddCommMonoid M₁] [Module R M₁] +variable {M₂ M₂'} [AddCommMonoid M₂] [Module R M₂] /-- Localization of modules is an exact functor, proven here for `LocalizedModule`. See `IsLocalizedModule.map_exact` for the more general version. -/ @@ -1134,11 +1158,11 @@ end LocalizedModule namespace IsLocalizedModule -variable {M₀ M₀'} [AddCommGroup M₀] [AddCommGroup M₀'] [Module R M₀] [Module R M₀'] +variable {M₀ M₀'} [AddCommMonoid M₀] [AddCommMonoid M₀'] [Module R M₀] [Module R M₀'] variable (f₀ : M₀ →ₗ[R] M₀') [IsLocalizedModule S f₀] -variable {M₁ M₁'} [AddCommGroup M₁] [AddCommGroup M₁'] [Module R M₁] [Module R M₁'] +variable {M₁ M₁'} [AddCommMonoid M₁] [AddCommMonoid M₁'] [Module R M₁] [Module R M₁'] variable (f₁ : M₁ →ₗ[R] M₁') [IsLocalizedModule S f₁] -variable {M₂ M₂'} [AddCommGroup M₂] [AddCommGroup M₂'] [Module R M₂] [Module R M₂'] +variable {M₂ M₂'} [AddCommMonoid M₂] [AddCommMonoid M₂'] [Module R M₂] [Module R M₂'] variable (f₂ : M₂ →ₗ[R] M₂') [IsLocalizedModule S f₂] /-- Localization of modules is an exact functor. -/ @@ -1147,6 +1171,13 @@ theorem map_exact (g : M₀ →ₗ[R] M₁) (h : M₁ →ₗ[R] M₂) (ex : Func Function.Exact.of_ladder_linearEquiv_of_exact (map_iso_commute S f₀ f₁ g) (map_iso_commute S f₁ f₂ h) (LocalizedModule.map_exact S g h ex) +/-- Localization of composition is the composition of localization -/ +theorem map_comp' (g : M₀ →ₗ[R] M₁) (h : M₁ →ₗ[R] M₂) : + map S f₀ f₂ (h ∘ₗ g) = map S f₁ f₂ h ∘ₗ map S f₀ f₁ g := by + ext x + obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S f₀ x + simp + section Algebra theorem mkOfAlgebra {R S S' : Type*} [CommRing R] [CommRing S] [CommRing S'] [Algebra R S] @@ -1183,7 +1214,7 @@ end IsLocalizedModule section Subsingleton -variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] +variable {R M : Type*} [CommRing R] [AddCommMonoid M] [Module R M] lemma LocalizedModule.mem_ker_mkLinearMap_iff {S : Submonoid R} {m} : m ∈ LinearMap.ker (LocalizedModule.mkLinearMap S M) ↔ ∃ r ∈ S, r • m = 0 := by diff --git a/Mathlib/Algebra/Module/Opposite.lean b/Mathlib/Algebra/Module/Opposite.lean new file mode 100644 index 0000000000000..5994afcd97b8f --- /dev/null +++ b/Mathlib/Algebra/Module/Opposite.lean @@ -0,0 +1,43 @@ +/- +Copyright (c) 2020 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Algebra.GroupWithZero.Action.Opposite +import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Ring.Opposite + +/-! +# Module operations on `Mᵐᵒᵖ` + +This file contains definitions that build on top of the group action definitions in +`Mathlib.Algebra.GroupWithZero.Action.Opposite`. +-/ + +assert_not_exists LinearMap + +section + +variable {R S M : Type*} [Semiring R] [Semiring S] [AddCommMonoid M] [Module S M] + +-- see Note [lower instance priority] +/-- Like `Semiring.toModule`, but multiplies on the right. -/ +instance (priority := 910) Semiring.toOppositeModule [Semiring R] : Module Rᵐᵒᵖ R := + { MonoidWithZero.toOppositeMulActionWithZero R with + smul_add := fun _ _ _ => add_mul _ _ _ + add_smul := fun _ _ _ => mul_add _ _ _ } + +end + +namespace MulOpposite + +universe u v + +variable (R : Type u) {M : Type v} [Semiring R] [AddCommMonoid M] [Module R M] + +/-- `MulOpposite.distribMulAction` extends to a `Module` -/ +instance instModule : Module R Mᵐᵒᵖ where + add_smul _ _ _ := unop_injective <| add_smul _ _ _ + zero_smul _ := unop_injective <| zero_smul _ _ + +end MulOpposite diff --git a/Mathlib/Algebra/Module/Pi.lean b/Mathlib/Algebra/Module/Pi.lean index 002ec529cf852..23c86123bb947 100644 --- a/Mathlib/Algebra/Module/Pi.lean +++ b/Mathlib/Algebra/Module/Pi.lean @@ -22,9 +22,6 @@ variable {I : Type u} -- The indexing type variable {f : I → Type v} --- The family of types already equipped with instances -variable (x y : ∀ i, f i) (i : I) - namespace Pi theorem _root_.IsSMulRegular.pi {α : Type*} [∀ i, SMul α <| f i] {k : α} @@ -86,17 +83,4 @@ instance module' {g : I → Type*} {r : ∀ i, Semiring (f i)} {m : ∀ i, AddCo -- Porting note: not sure why `apply zero_smul` fails here. rw [zero_smul] -instance noZeroSMulDivisors (α) [Semiring α] [∀ i, AddCommMonoid <| f i] - [∀ i, Module α <| f i] [∀ i, NoZeroSMulDivisors α <| f i] : - NoZeroSMulDivisors α (∀ i : I, f i) := - ⟨fun {_ _} h => - or_iff_not_imp_left.mpr fun hc => - funext fun i => (smul_eq_zero.mp (congr_fun h i)).resolve_left hc⟩ - -/-- A special case of `Pi.noZeroSMulDivisors` for non-dependent types. Lean struggles to -synthesize this instance by itself elsewhere in the library. -/ -instance _root_.Function.noZeroSMulDivisors {ι α β : Type*} [Semiring α] [AddCommMonoid β] - [Module α β] [NoZeroSMulDivisors α β] : NoZeroSMulDivisors α (ι → β) := - Pi.noZeroSMulDivisors _ - end Pi diff --git a/Mathlib/Algebra/Module/Presentation/Basic.lean b/Mathlib/Algebra/Module/Presentation/Basic.lean new file mode 100644 index 0000000000000..a9797ef47cab2 --- /dev/null +++ b/Mathlib/Algebra/Module/Presentation/Basic.lean @@ -0,0 +1,459 @@ +/- +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.Exact +import Mathlib.Algebra.Module.ULift +import Mathlib.LinearAlgebra.Finsupp +import Mathlib.LinearAlgebra.Quotient.Basic + +/-! +# Presentations of modules + +Given a ring `A`, we introduce a structure `Relations A` which +contains the data that is necessary to define a module by generators and relations. +A term `relations : Relations A` involves two index types: a type `G` for the +generators and a type `R` for the relations. The relation attached to `r : R` is +an element `G →₀ A` which expresses the coefficients of the expected linear relation. + +One may think of `relations : Relations A` as a particular shape for systems of +linear equations in any `A`-module `M`. Each `g : G` can be thought of as a +variable (in `M`) and each `r : R` specifies a linear relation that these +variables should satisfy. This way, we get a type `relations.Solution M`. +Then, if `solution : relations.Solution M`, we introduce the predicate +`solution.IsPresentation` which asserts that `solution` is the universal +solution to the given equations, i.e. `solution` gives a presentation +of `M` by generators and relations. + +Given an `A`-module `M`, we also introduce the type `Presentation A M` which +contains all the data and properties involved in a presentation of `M` by +generators and relations. + +## TODO +* Relate this to `Module.FinitePresentation` +* Behaviour of presentations with respect to the extension of scalars and +the restriction of scalars + +-/ + +universe w' w'' w₀ w₁ v'' v' v u + +namespace Module + +variable (A : Type u) [Ring A] + +/-- Given a ring `A`, this structure involves a family of elements (indexed by a type `R`) +in a free module `G →₀ A`. This allows to define an `A`-module by generators and relations, +see `Relations.Quotient`. -/ +@[nolint checkUnivs] +structure Relations where + /-- the index type for generators -/ + G : Type w₀ + /-- the index type for relations -/ + R : Type w₁ + /-- the coefficients of the linear relations that are expected between the generators -/ + relation (r : R) : G →₀ A + +namespace Relations + +variable {A} (relations : Relations.{w₀, w₁} A) + +/-- The module that is presented by generators and relations given by `relations : Relations A`. +This is the quotient of the free `A`-module on `relations.G` by the submodule generated by +the given relations. -/ +def Quotient := (relations.G →₀ A) ⧸ Submodule.span A (Set.range relations.relation) + +noncomputable instance : AddCommGroup relations.Quotient := by + dsimp only [Quotient]; infer_instance + +noncomputable instance : Module A relations.Quotient := by + dsimp only [Quotient]; infer_instance + +/-- The canonical (surjective) linear map `(relations.G →₀ A) →ₗ[A] relations.Quotient`. -/ +def toQuotient : (relations.G →₀ A) →ₗ[A] relations.Quotient := Submodule.mkQ _ + +variable {relations} in +@[ext] +lemma Quotient.linearMap_ext {M : Type v} [AddCommGroup M] [Module A M] + {f f' : relations.Quotient →ₗ[A] M} + (h : ∀ (g : relations.G), f (relations.toQuotient (Finsupp.single g 1)) = + f' (relations.toQuotient (Finsupp.single g 1))) : + f = f' := + Submodule.linearMap_qext _ (Finsupp.lhom_ext' (fun g ↦ LinearMap.ext_ring (h g))) + +lemma surjective_toQuotient : Function.Surjective relations.toQuotient := + Submodule.mkQ_surjective _ + +lemma ker_toQuotient : + LinearMap.ker relations.toQuotient = Submodule.span A (Set.range relations.relation) := + Submodule.ker_mkQ _ + +@[simp] +lemma toQuotient_relation (r : relations.R) : + relations.toQuotient (relations.relation r) = 0 := by + dsimp only [toQuotient, Quotient] + rw [Submodule.mkQ_apply, Submodule.Quotient.mk_eq_zero] + exact Submodule.subset_span (by simp) + +/-- The linear map `(relations.R →₀ A) →ₗ[A] (relations.G →₀ A)` corresponding to the relations +given by `relations : Relations A`. -/ +noncomputable def map : (relations.R →₀ A) →ₗ[A] (relations.G →₀ A) := + Finsupp.linearCombination _ relations.relation + +@[simp] +lemma map_single (r : relations.R) : + relations.map (Finsupp.single r 1) = relations.relation r := by + simp [map] + +@[simp] +lemma range_map : + LinearMap.range relations.map = Submodule.span A (Set.range relations.relation) := + Finsupp.range_linearCombination _ + +variable (M : Type v) [AddCommGroup M] [Module A M] + +/-- The type of solutions in a module `M` of the equations given by `relations : Relations A`. -/ +@[ext] +structure Solution where + /-- the image in `M` of each variable -/ + var (g : relations.G) : M + linearCombination_var_relation (r : relations.R) : + Finsupp.linearCombination _ var (relations.relation r) = 0 + +namespace Solution + +variable {relations M} + +section + +variable (solution : relations.Solution M) + +/-- Given `relations : Relations A` and a solution in `relations.Solution M`, this is +the linear map `(relations.G →₀ A) →ₗ[A] M` canonically associated to the solution. -/ +noncomputable def π : (relations.G →₀ A) →ₗ[A] M := Finsupp.linearCombination _ solution.var + +@[simp] +lemma π_single (g : relations.G) : + solution.π (Finsupp.single g 1) = solution.var g := by simp [π] + +@[simp] +lemma π_relation (r : relations.R) : solution.π (relations.relation r) = 0 := + solution.linearCombination_var_relation r + +@[simp] +lemma π_comp_map : solution.π.comp relations.map = 0 := by aesop + +@[simp] +lemma π_comp_map_apply (x : relations.R →₀ A) : solution.π (relations.map x) = 0 := by + change solution.π.comp relations.map x = 0 + rw [π_comp_map, LinearMap.zero_apply] + +/-- Given `relations : Relations A` and `solution : relations.Solution M`, +this is the canonical linear map from `relations.R →₀ A` to the kernel +of `solution.π : (relations.G →₀ A) →ₗ[A] M`. -/ +noncomputable def mapToKer : (relations.R →₀ A) →ₗ[A] (LinearMap.ker solution.π) := + LinearMap.codRestrict _ relations.map (by simp) + +@[simp] +lemma mapToKer_coe (x : relations.R →₀ A) : (solution.mapToKer x).1 = relations.map x := rfl + +lemma span_relation_le_ker_π : + Submodule.span A (Set.range relations.relation) ≤ LinearMap.ker solution.π := by + rw [Submodule.span_le] + rintro _ ⟨r, rfl⟩ + simp only [SetLike.mem_coe, LinearMap.mem_ker, π_relation] + +/-- Given `relations : Relations A` and `solution : relations.Solution M`, this is +the canonical linear map `relations.Quotient →ₗ[A] M` from the module. -/ +noncomputable def fromQuotient : relations.Quotient →ₗ[A] M := + Submodule.liftQ _ solution.π solution.span_relation_le_ker_π + +@[simp] +lemma fromQuotient_comp_toQuotient : + solution.fromQuotient.comp relations.toQuotient = solution.π := rfl + +@[simp] +lemma fromQuotient_toQuotient (x : relations.G →₀ A) : + solution.fromQuotient (relations.toQuotient x) = solution.π x := rfl + +variable {N : Type v'} [AddCommGroup N] [Module A N] (f : M →ₗ[A] N) + +/-- The image of a solution to `relations : Relation A` by a linear map `M →ₗ[A] N`. -/ +@[simps] +def postcomp : relations.Solution N where + var g := f (solution.var g) + linearCombination_var_relation r := by + have : Finsupp.linearCombination _ (fun g ↦ f (solution.var g)) = f.comp solution.π := by aesop + simp [this] + +@[simp] +lemma postcomp_comp {N' : Type v''} [AddCommGroup N'] [Module A N'] (g : N →ₗ[A] N') : + solution.postcomp (g.comp f) = (solution.postcomp f).postcomp g := rfl + +@[simp] +lemma postcomp_id : solution.postcomp LinearMap.id = solution := rfl + +variable {solution} + +lemma congr_var {solution' : relations.Solution M} (h : solution = solution') (g : relations.G) : + solution.var g = solution'.var g := by rw [h] + +lemma congr_postcomp {solution' : relations.Solution M} (h : solution = solution') + (f : M →ₗ[A] N) : solution.postcomp f = solution'.postcomp f := by rw [h] + +end + +section + +variable (π : (relations.G →₀ A) →ₗ[A] M) (hπ : ∀ (r : relations.R), π (relations.relation r) = 0) + +/-- Given `relations : Relations A` and an `A`-module `M`, this is a constructor +for `relations.Solution M` for which the data is given as +a linear map `π : (relations.G →₀ A) →ₗ[A] M`. (See also `ofπ'` for an alternate +vanishing criterion.) -/ +@[simps (config := .lemmasOnly)] +noncomputable def ofπ : relations.Solution M where + var g := π (Finsupp.single g 1) + linearCombination_var_relation r := by + have : π = Finsupp.linearCombination _ (fun g ↦ π (Finsupp.single g 1)) := by ext; simp + rw [← this] + exact hπ r + +@[simp] +lemma ofπ_π : (ofπ π hπ).π = π := by ext; simp [ofπ] + +end + +section + +variable (π : (relations.G →₀ A) →ₗ[A] M) (hπ : π.comp relations.map = 0) + +/-- Variant of `ofπ` where the vanishing condition is expressed in terms +of a composition of linear maps. -/ +@[simps! (config := .lemmasOnly)] +noncomputable def ofπ' : relations.Solution M := + ofπ π (fun r ↦ by + simpa using DFunLike.congr_fun hπ (Finsupp.single r 1)) + +@[simp] +lemma ofπ'_π : (ofπ' π hπ).π = π := by simp [ofπ'] + +end + +/-- Given `relations : Relations A`, an `A`-module `M` and `solution : relations.Solution M`, +this property asserts that `solution` gives a presentation of `M` by generators and relations. -/ +structure IsPresentation (solution : relations.Solution M) : Prop where + bijective : Function.Bijective solution.fromQuotient + +namespace IsPresentation + +variable {solution : relations.Solution M} (h : solution.IsPresentation) + +include h + +/-- When `M` admits a presentation by generators and relations given +by `solution : relations.Solutions M`, this is the associated linear equivalence +`relations.Quotient ≃ₗ[A] M`. -/ +noncomputable def linearEquiv : relations.Quotient ≃ₗ[A] M := LinearEquiv.ofBijective _ h.bijective + +@[simp] +lemma linearEquiv_apply (x : relations.Quotient) : + h.linearEquiv x = solution.fromQuotient x := rfl + +@[simp] +lemma linearEquiv_symm_var (g : relations.G) : + h.linearEquiv.symm (solution.var g) = relations.toQuotient (Finsupp.single g 1) := + h.linearEquiv.injective (by simp) + +lemma surjective_π : Function.Surjective solution.π := by + rw [← fromQuotient_comp_toQuotient, LinearMap.coe_comp] + exact h.bijective.2.comp relations.surjective_toQuotient + +lemma ker_π : LinearMap.ker solution.π = Submodule.span A (Set.range relations.relation) := by + rw [← ker_toQuotient, ← fromQuotient_comp_toQuotient, LinearMap.ker_comp, + LinearMap.ker_eq_bot.2 h.bijective.1, Submodule.comap_bot] + +lemma surjective_mapToKer : Function.Surjective solution.mapToKer := by + rintro ⟨x, hx⟩ + rw [h.ker_π, ← relations.range_map] at hx + obtain ⟨r, rfl⟩ := hx + exact ⟨r, rfl⟩ + +/-- The sequence `(relations.R →₀ A) → (relations.G →₀ A) → M → 0` is exact. -/ +lemma exact : Function.Exact relations.map solution.π := by + intro x₂ + constructor + · intro hx₂ + obtain ⟨x₁, hx₁⟩ := h.surjective_mapToKer ⟨x₂, hx₂⟩ + exact ⟨x₁, by simpa only [mapToKer_coe, Subtype.ext_iff] using hx₁⟩ + · rintro ⟨x₁, rfl⟩ + rw [π_comp_map_apply] + +variable {N : Type v'} [AddCommGroup N] [Module A N] + +/-- If `M` admits a presentation by generators and relations, and we have a solution of the +same equations in a module `N`, then this is the canonical induced linear map `M →ₗ[A] N`. -/ +noncomputable def desc (s : relations.Solution N) : M →ₗ[A] N := + s.fromQuotient.comp h.linearEquiv.symm.toLinearMap + +@[simp] +lemma desc_var (s : relations.Solution N) (g : relations.G) : + h.desc s (solution.var g) = s.var g := by + dsimp [desc] + simp only [linearEquiv_symm_var, fromQuotient_toQuotient, π_single] + +@[simp] +lemma postcomp_desc (s : relations.Solution N) : + solution.postcomp (h.desc s) = s := by aesop + +lemma postcomp_injective {f f' : M →ₗ[A] N} + (h' : solution.postcomp f = solution.postcomp f') : f = f' := by + suffices f.comp solution.fromQuotient = f'.comp solution.fromQuotient by + ext x + obtain ⟨y, rfl⟩ := h.bijective.2 x + exact DFunLike.congr_fun this y + ext g + simpa using congr_var h' g + +/-- If `M` admits a presentation by generators and relations, then +linear maps from `M` can be (naturally) identified to the solutions of +certain linear equations. -/ +@[simps] +noncomputable def linearMapEquiv : (M →ₗ[A] N) ≃ relations.Solution N where + toFun f := solution.postcomp f + invFun s := h.desc s + left_inv f := h.postcomp_injective (by aesop) + right_inv s := by aesop + +section + +variable {solution' : relations.Solution N} (h' : solution'.IsPresentation) + +/-- Uniqueness (up to a unique linear equivalence) of the module defined +by generators and relations. -/ +noncomputable def uniq : M ≃ₗ[A] N := LinearEquiv.ofLinear + (h.desc solution') (h'.desc solution) + (h'.postcomp_injective (by simp)) + (h.postcomp_injective (by simp)) + +@[simp] +lemma postcomp_uniq : solution.postcomp (uniq h h').toLinearMap = solution' := by + simp [uniq] + +@[simp] +lemma postcomp_uniq_symm : solution'.postcomp (uniq h h').symm.toLinearMap = solution := by + simp [uniq] + +@[simp] +lemma uniq_var (g : relations.G) : uniq h h' (solution.var g) = solution'.var g := by + simp [uniq] + +@[simp] +lemma uniq_symm_var (g : relations.G) : (uniq h h').symm (solution'.var g) = solution.var g := by + simp [uniq] + +end + +lemma ofLinearEquiv (e : M ≃ₗ[A] N) : (solution.postcomp e.toLinearMap).IsPresentation where + bijective := by + have : (solution.postcomp e.toLinearMap).fromQuotient = + e.toLinearMap.comp (solution.fromQuotient) := by aesop + rw [this, LinearMap.coe_comp, LinearEquiv.coe_coe] + exact Function.Bijective.comp e.bijective h.bijective + +end IsPresentation + +variable (relations) + +/-- Given `relations : Relations A`, this is the obvious solution to `relations` +in the quotient `relations.Quotient`. -/ +@[simps!] +noncomputable def ofQuotient : relations.Solution relations.Quotient := + ofπ relations.toQuotient (by simp) + +@[simp] +lemma ofQuotient_π : (ofQuotient relations).π = Submodule.mkQ _ := ofπ_π _ _ + +@[simp] +lemma ofQuotient_fromQuotient : (ofQuotient relations).fromQuotient = .id := by aesop + +lemma ofQuotient_isPresentation : (ofQuotient relations).IsPresentation where + bijective := by + simpa only [ofQuotient_fromQuotient, LinearMap.id_coe] using Function.bijective_id + +variable {relations} + +/-- Helper structure in order to prove `Module.Relations.Solutions.IsPresentation` +by showing the universal property of the module defined by generators and relations. +The universal property is restricted to modules that are in `Type w'` for +an auxiliary universe `w'`. See `IsPresentationCore.isPresentation`. -/ +structure IsPresentationCore (solution : relations.Solution M) where + /-- any solution in a module `N : Type w'` is obtained in a unique way + by postcomposing `solution : relations.Solution M` by a linear map `M →ₗ[A] N`. -/ + desc {N : Type w'} [AddCommGroup N] [Module A N] (s : relations.Solution N) : M →ₗ[A] N + postcomp_desc {N : Type w'} [AddCommGroup N] [Module A N] (s : relations.Solution N) : + solution.postcomp (desc s) = s + postcomp_injective {N : Type w'} [AddCommGroup N] [Module A N] {f f' : M →ₗ[A] N} + (h : solution.postcomp f = solution.postcomp f') : f = f' + +namespace IsPresentationCore + +variable {solution : relations.Solution M} + +@[simp] +lemma desc_var (h : IsPresentationCore.{w'} solution) + {N : Type w'} [AddCommGroup N] [Module A N] (s : relations.Solution N) (g : relations.G) : + h.desc s (solution.var g) = s.var g := + congr_var (h.postcomp_desc s) g + +/-- The structure `IsPresentationCore` can be shrunk to a lower universe. -/ +def down (h : IsPresentationCore.{max w' w''} solution) : + IsPresentationCore.{w''} solution where + desc s := ULift.moduleEquiv.toLinearMap.comp + (h.desc (s.postcomp ULift.moduleEquiv.symm.toLinearMap)) + postcomp_desc s:= by + simpa using congr_postcomp + (h.postcomp_desc (s.postcomp ULift.moduleEquiv.symm.toLinearMap)) + ULift.moduleEquiv.toLinearMap + postcomp_injective {N _ _ f f'} h' := by + ext x + have := congr_postcomp h' ULift.moduleEquiv.{_, _, w'}.symm.toLinearMap + simp only [← postcomp_comp] at this + simpa using DFunLike.congr_fun (h.postcomp_injective this) x + +lemma isPresentation {solution : relations.Solution M} + (h : IsPresentationCore.{max u v w₀} solution) : + solution.IsPresentation where + bijective := by + let e : relations.Quotient ≃ₗ[A] M := + LinearEquiv.ofLinear solution.fromQuotient + ((down.{v} h).desc (ofQuotient relations)) + ((down.{max u w₀} h).postcomp_injective (by aesop)) (by aesop) + exact e.bijective + +end IsPresentationCore + +end Solution + +end Relations + +variable (M : Type v) [AddCommGroup M] [Module A M] + +/-- Given an `A`-module `M`, a term in this type is a presentation by `M` by +generators and relations. -/ +@[nolint checkUnivs] +structure Presentation extends Relations.{w₀, w₁} A, + toRelations.Solution M, toSolution.IsPresentation where + +variable {A M} + +/-- Constructor for `Module.Presentation`. -/ +@[simps toRelations toSolution] +def Presentation.ofIsPresentation {relations : Relations.{w₀, w₁} A} + {solution : relations.Solution M} (h : solution.IsPresentation) : + Presentation.{w₀, w₁} A M where + toSolution := solution + toIsPresentation := h + +end Module diff --git a/Mathlib/Algebra/Module/Presentation/Free.lean b/Mathlib/Algebra/Module/Presentation/Free.lean new file mode 100644 index 0000000000000..fef0b13ee1aba --- /dev/null +++ b/Mathlib/Algebra/Module/Presentation/Free.lean @@ -0,0 +1,84 @@ +/- +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.Basic +import Mathlib.LinearAlgebra.FreeModule.Basic +import Mathlib.Logic.UnivLE + +/-! +# Presentation of free modules + +A module is free iff it admits a presentation with generators but no relation, +see `Module.free_iff_exists_presentation`. + +-/ + +universe w w₀ w₁ v u + +namespace Module + +variable {A : Type u} [Ring A] (relations : Relations.{w₀, w₁} A) + (M : Type v) [AddCommGroup M] [Module A M] + +namespace Relations + +variable [IsEmpty relations.R] + +/-- If `relations : Relations A` involved no relation, then it has an obvious +solution in the module `relations.G →₀ A`. -/ +@[simps] +noncomputable def solutionFinsupp : relations.Solution (relations.G →₀ A) where + var g := Finsupp.single g 1 + linearCombination_var_relation r := by exfalso; exact IsEmpty.false r + +/-- If `relations : Relations A` involves no relations (`[IsEmpty relations.R]`), +then the free module `relations.G →₀ A` satisfies the universal property of the +corresponding module defined by generators (and relations). -/ +noncomputable def solutionFinsupp.isPresentationCore : + Solution.IsPresentationCore.{w} relations.solutionFinsupp where + desc s := Finsupp.linearCombination _ s.var + postcomp_desc := by aesop + postcomp_injective h := by ext; apply Solution.congr_var h + +lemma solutionFinsupp_isPresentation : + relations.solutionFinsupp.IsPresentation := + (solutionFinsupp.isPresentationCore relations).isPresentation + +variable {relations} + +lemma Solution.IsPresentation.free {solution : relations.Solution M} + (h : solution.IsPresentation) : + Module.Free A M := + Free.of_equiv ((solutionFinsupp_isPresentation relations).uniq h) + +end Relations + +variable (A) + +/-- The presentation of the `A`-module `G →₀ A` with generators indexed by `G`, +and no relation. (Note that there is an auxiliary universe parameter `w₁` for the +empty type `R`.) -/ +@[simps! G R var] +noncomputable def presentationFinsupp (G : Type w₀) : + Presentation.{w₀, w₁} A (G →₀ A) where + G := G + R := PEmpty.{w₁ + 1} + relation := by rintro ⟨⟩ + toSolution := Relations.solutionFinsupp _ + toIsPresentation := Relations.solutionFinsupp_isPresentation _ + +lemma free_iff_exists_presentation : + Free A M ↔ ∃ (p : Presentation.{v, w₁} A M), IsEmpty p.R := by + constructor + · rw [free_def.{_, _, v}] + rintro ⟨G, ⟨⟨e⟩⟩⟩ + exact ⟨Presentation.ofIsPresentation + ((presentationFinsupp A G).ofLinearEquiv e.symm), + by dsimp; infer_instance⟩ + · rintro ⟨p, h⟩ + exact p.toIsPresentation.free + +end Module diff --git a/Mathlib/Algebra/Module/Prod.lean b/Mathlib/Algebra/Module/Prod.lean index 11b934777a06a..de41fcccad536 100644 --- a/Mathlib/Algebra/Module/Prod.lean +++ b/Mathlib/Algebra/Module/Prod.lean @@ -35,17 +35,4 @@ instance instModule [Semiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M add_smul := fun _ _ _ => mk.inj_iff.mpr ⟨add_smul _ _ _, add_smul _ _ _⟩ zero_smul := fun _ => mk.inj_iff.mpr ⟨zero_smul _ _, zero_smul _ _⟩ } -instance noZeroSMulDivisors {r : Semiring R} [AddCommMonoid M] [AddCommMonoid N] - [Module R M] [Module R N] [NoZeroSMulDivisors R M] [NoZeroSMulDivisors R N] : - NoZeroSMulDivisors R (M × N) := - { eq_zero_or_eq_zero_of_smul_eq_zero := by -- Porting note: in mathlib3 there is no need for `by`/ - -- `intro`/`exact`, i.e. the following works: - -- ⟨fun c ⟨x, y⟩ h => - -- or_iff_not_imp_left.mpr fun hc => - intro c ⟨x, y⟩ h - exact or_iff_not_imp_left.mpr fun hc => - mk.inj_iff.mpr - ⟨(smul_eq_zero.mp (congr_arg fst h)).resolve_left hc, - (smul_eq_zero.mp (congr_arg snd h)).resolve_left hc⟩ } - end Prod diff --git a/Mathlib/Algebra/Module/Projective.lean b/Mathlib/Algebra/Module/Projective.lean index b4387f01f63c9..9bba5e8dd708a 100644 --- a/Mathlib/Algebra/Module/Projective.lean +++ b/Mathlib/Algebra/Module/Projective.lean @@ -91,7 +91,7 @@ theorem projective_def' : /-- A projective R-module has the property that maps from it lift along surjections. -/ theorem projective_lifting_property [h : Projective R P] (f : M →ₗ[R] N) (g : P →ₗ[R] N) - (hf : Function.Surjective f) : ∃ h : P →ₗ[R] M, f.comp h = g := by + (hf : Function.Surjective f) : ∃ h : P →ₗ[R] M, f ∘ₗ h = g := by /- Here's the first step of the proof. Recall that `X →₀ R` is Lean's way of talking about the free `R`-module @@ -110,6 +110,10 @@ theorem projective_lifting_property [h : Projective R P] (f : M →ₗ[R] N) (g conv_rhs => rw [← hs p] simp [φ, Finsupp.linearCombination_apply, Function.surjInv_eq hf, map_finsupp_sum] +theorem _root_.LinearMap.exists_rightInverse_of_surjective [Projective R P] + (f : M →ₗ[R] P) (hf_surj : range f = ⊤) : ∃ g : P →ₗ[R] M, f ∘ₗ g = LinearMap.id := + projective_lifting_property f (.id : P →ₗ[R] P) (LinearMap.range_eq_top.1 hf_surj) + /-- A module which satisfies the universal property is projective: If all surjections of `R`-modules `(P →₀ R) →ₗ[R] P` have `R`-linear left inverse maps, then `P` is projective. -/ @@ -171,6 +175,20 @@ theorem Projective.iff_split_of_projective [Module.Projective R M] (s : M →ₗ Module.Projective R P ↔ ∃ i, s ∘ₗ i = LinearMap.id := ⟨fun _ ↦ projective_lifting_property _ _ hs, fun ⟨i, H⟩ ↦ Projective.of_split i s H⟩ +attribute [local instance] RingHomInvPair.of_ringEquiv in +theorem Projective.of_ringEquiv {R S} [Semiring R] [Semiring S] {M N} + [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module S N] + (e₁ : R ≃+* S) (e₂ : M ≃ₛₗ[RingHomClass.toRingHom e₁] N) + [Projective R M] : Projective S N := by + obtain ⟨f, hf⟩ := ‹Projective R M› + let g : N →ₗ[S] N →₀ S := + { toFun := fun x ↦ (equivCongrLeft e₂ (f (e₂.symm x))).mapRange e₁ e₁.map_zero + map_add' := fun x y ↦ by ext; simp + map_smul' := fun r v ↦ by ext i; simp [e₂.symm.map_smulₛₗ] } + refine ⟨⟨g, fun x ↦ ?_⟩⟩ + replace hf := congr(e₂ $(hf (e₂.symm x))) + simpa [linearCombination_apply, sum_mapRange_index, g, map_finsupp_sum, e₂.map_smulₛₗ] using hf + end Semiring section Ring diff --git a/Mathlib/Algebra/Module/Rat.lean b/Mathlib/Algebra/Module/Rat.lean index c0ed84a4366ed..3ce5e5ac011a8 100644 --- a/Mathlib/Algebra/Module/Rat.lean +++ b/Mathlib/Algebra/Module/Rat.lean @@ -4,6 +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.Module.Basic +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Field.Rat import Mathlib.Algebra.Order.Field.Rat diff --git a/Mathlib/Algebra/Module/Submodule/Basic.lean b/Mathlib/Algebra/Module/Submodule/Basic.lean index 3958ed075e9fb..215bf168b5468 100644 --- a/Mathlib/Algebra/Module/Submodule/Basic.lean +++ b/Mathlib/Algebra/Module/Submodule/Basic.lean @@ -4,7 +4,9 @@ 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.Subgroup.Basic import Mathlib.Algebra.Group.Submonoid.Membership +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 d6c065576cbbf..11fcc080a6112 100644 --- a/Mathlib/Algebra/Module/Submodule/Bilinear.lean +++ b/Mathlib/Algebra/Module/Submodule/Bilinear.lean @@ -55,10 +55,10 @@ theorem map₂_span_span (f : M →ₗ[R] N →ₗ[R] P) (s : Set M) (t : Set N) map₂ f (span R s) (span R t) = span R (Set.image2 (fun m n => f m n) s t) := by apply le_antisymm · rw [map₂_le] - apply @span_induction' R M _ _ _ s + apply @span_induction R M _ _ _ s on_goal 1 => intro a ha - apply @span_induction' R N _ _ _ t + apply @span_induction R N _ _ _ t · intro b hb exact subset_span ⟨_, ‹_›, _, ‹_›, rfl⟩ all_goals @@ -80,7 +80,7 @@ theorem map₂_bot_right (f : M →ₗ[R] N →ₗ[R] P) (p : Submodule R M) : m @[simp] theorem map₂_bot_left (f : M →ₗ[R] N →ₗ[R] P) (q : Submodule R N) : map₂ f ⊥ q = ⊥ := eq_bot_iff.2 <| - map₂_le.2 fun m hm n hn => by + map₂_le.2 fun m hm n _ => by rw [Submodule.mem_bot] at hm ⊢ rw [hm, LinearMap.map_zero₂] diff --git a/Mathlib/Algebra/Module/Submodule/Equiv.lean b/Mathlib/Algebra/Module/Submodule/Equiv.lean index f5de6d41357b8..30f945c04ad80 100644 --- a/Mathlib/Algebra/Module/Submodule/Equiv.lean +++ b/Mathlib/Algebra/Module/Submodule/Equiv.lean @@ -231,7 +231,7 @@ noncomputable def comap_equiv_self_of_inj_of_le {f : M →ₗ[R] N} {p : Submodu (hf : Injective f) (h : p ≤ LinearMap.range f) : p.comap f ≃ₗ[R] p := LinearEquiv.ofBijective - ((f ∘ₗ (p.comap f).subtype).codRestrict p <| fun ⟨x, hx⟩ ↦ mem_comap.mp hx) + ((f ∘ₗ (p.comap f).subtype).codRestrict p <| fun ⟨_, hx⟩ ↦ mem_comap.mp hx) (⟨fun x y hxy ↦ by simpa using hf (Subtype.ext_iff.mp hxy), fun ⟨x, hx⟩ ↦ by obtain ⟨y, rfl⟩ := h hx; exact ⟨⟨y, hx⟩, by simp [Subtype.ext_iff]⟩⟩) diff --git a/Mathlib/Algebra/Module/Submodule/Invariant.lean b/Mathlib/Algebra/Module/Submodule/Invariant.lean new file mode 100644 index 0000000000000..76e70e00cd1fa --- /dev/null +++ b/Mathlib/Algebra/Module/Submodule/Invariant.lean @@ -0,0 +1,119 @@ +/- +Copyright (c) 2024 Oliver Nash. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Oliver Nash +-/ +import Mathlib.Algebra.Module.Submodule.Map +import Mathlib.Order.Sublattice + +/-! +# The lattice of invariant submodules + +In this file we defined the type `Module.End.invtSubmodule`, associated to a linear endomorphism of +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`. + +-/ + +namespace Module.End + +variable {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] (f : End R M) + +/-- Given an endomorphism, `f` of some module, this is the sublattice of all `f`-invariant +submodules. -/ +def invtSubmodule : Sublattice (Submodule R M) where + carrier := {p : Submodule R M | p ≤ p.comap f} + supClosed' p hp q hq := sup_le_iff.mpr + ⟨le_trans hp <| Submodule.comap_mono le_sup_left, + le_trans hq <| Submodule.comap_mono le_sup_right⟩ + infClosed' p hp q hq := by + simp only [Set.mem_setOf_eq, Submodule.comap_inf, le_inf_iff] + exact ⟨inf_le_of_left_le hp, inf_le_of_right_le hq⟩ + +lemma mem_invtSubmodule {p : Submodule R M} : + p ∈ f.invtSubmodule ↔ p ≤ p.comap f := + Iff.rfl + +namespace invtSubmodule + +@[simp] +protected lemma top_mem : ⊤ ∈ f.invtSubmodule := by simp [invtSubmodule] + +@[simp] +protected lemma bot_mem : ⊥ ∈ f.invtSubmodule := by simp [invtSubmodule] + +instance : BoundedOrder (f.invtSubmodule) where + top := ⟨⊤, invtSubmodule.top_mem f⟩ + bot := ⟨⊥, invtSubmodule.bot_mem f⟩ + le_top := fun ⟨p, hp⟩ ↦ by simp + bot_le := fun ⟨p, hp⟩ ↦ by simp + +@[simp] +protected lemma zero : + (0 : End R M).invtSubmodule = ⊤ := + eq_top_iff.mpr fun x ↦ by simp [invtSubmodule] + +@[simp] +protected lemma id : + invtSubmodule (LinearMap.id : End R M) = ⊤ := + eq_top_iff.mpr fun x ↦ by simp [invtSubmodule] + +protected lemma mk_eq_bot_iff {p : Submodule R M} (hp : p ∈ f.invtSubmodule) : + (⟨p, hp⟩ : f.invtSubmodule) = ⊥ ↔ p = ⊥ := + Subtype.mk_eq_bot_iff (by simp [invtSubmodule]) _ + +protected lemma mk_eq_top_iff {p : Submodule R M} (hp : p ∈ f.invtSubmodule) : + (⟨p, hp⟩ : f.invtSubmodule) = ⊤ ↔ p = ⊤ := + Subtype.mk_eq_top_iff (by simp [invtSubmodule]) _ + +@[simp] +protected lemma disjoint_mk_iff {p q : Submodule R M} + (hp : p ∈ f.invtSubmodule) (hq : q ∈ f.invtSubmodule) : + Disjoint (α := f.invtSubmodule) ⟨p, hp⟩ ⟨q, hq⟩ ↔ Disjoint p q := by + rw [disjoint_iff, disjoint_iff, Sublattice.mk_inf_mk, + Subtype.mk_eq_bot_iff (⊥ : f.invtSubmodule).property] + +protected lemma disjoint_iff {p q : f.invtSubmodule} : + Disjoint p q ↔ Disjoint (p : Submodule R M) (q : Submodule R M) := by + obtain ⟨p, hp⟩ := p + obtain ⟨q, hq⟩ := q + simp + +@[simp] +protected lemma codisjoint_mk_iff {p q : Submodule R M} + (hp : p ∈ f.invtSubmodule) (hq : q ∈ f.invtSubmodule) : + Codisjoint (α := f.invtSubmodule) ⟨p, hp⟩ ⟨q, hq⟩ ↔ Codisjoint p q := by + rw [codisjoint_iff, codisjoint_iff, Sublattice.mk_sup_mk, + Subtype.mk_eq_top_iff (⊤ : f.invtSubmodule).property] + +protected lemma codisjoint_iff {p q : f.invtSubmodule} : + Codisjoint p q ↔ Codisjoint (p : Submodule R M) (q : Submodule R M) := by + obtain ⟨p, hp⟩ := p + obtain ⟨q, hq⟩ := q + simp + +@[simp] +protected lemma isCompl_mk_iff {p q : Submodule R M} + (hp : p ∈ f.invtSubmodule) (hq : q ∈ f.invtSubmodule) : + IsCompl (α := f.invtSubmodule) ⟨p, hp⟩ ⟨q, hq⟩ ↔ IsCompl p q := by + simp [isCompl_iff] + +protected lemma isCompl_iff {p q : f.invtSubmodule} : + IsCompl p q ↔ IsCompl (p : Submodule R M) (q : Submodule R M) := by + obtain ⟨p, hp⟩ := p + obtain ⟨q, hq⟩ := q + simp + +lemma map_subtype_mem_of_mem_invtSubmodule {p : Submodule R M} (hp : p ∈ f.invtSubmodule) + {q : Submodule R p} (hq : q ∈ invtSubmodule (LinearMap.restrict f hp)) : + Submodule.map p.subtype q ∈ f.invtSubmodule := by + rintro - ⟨⟨x, hx⟩, hx', rfl⟩ + specialize hq hx' + rw [Submodule.mem_comap, LinearMap.restrict_apply] at hq + simpa [hq] using hp hx + +end invtSubmodule + +end Module.End diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index e329b35726b80..b291dd847675d 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -29,7 +29,7 @@ open Function open Pointwise -variable {R : Type*} {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} +variable {R : Type*} {R₂ : Type*} {R₃ : Type*} variable {K : Type*} variable {M : Type*} {M₁ : Type*} {M₂ : Type*} {M₃ : Type*} variable {V : Type*} {V₂ : Type*} @@ -43,13 +43,11 @@ section AddCommMonoid variable [Semiring R] [Semiring R₂] [Semiring R₃] variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} -variable [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] open Submodule -variable {σ₂₁ : R₂ →+* R} {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} +variable {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} variable [RingHomCompTriple τ₁₂ τ₂₃ τ₁₃] variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] @@ -111,10 +109,13 @@ theorem le_ker_iff_map [RingHomSurjective τ₁₂] {f : F} {p : Submodule R M} theorem ker_codRestrict {τ₂₁ : R₂ →+* R} (p : Submodule R M) (f : M₂ →ₛₗ[τ₂₁] M) (hf) : ker (codRestrict p f hf) = ker f := by rw [ker, comap_codRestrict, Submodule.map_bot]; rfl +lemma ker_domRestrict [AddCommMonoid M₁] [Module R M₁] (p : Submodule R M) (f : M →ₗ[R] M₁) : + ker (domRestrict f p) = (ker f).comap p.subtype := ker_comp .. + theorem ker_restrict [AddCommMonoid M₁] [Module R M₁] {p : Submodule R M} {q : Submodule R M₁} {f : M →ₗ[R] M₁} (hf : ∀ x : M, x ∈ p → f x ∈ q) : - ker (f.restrict hf) = LinearMap.ker (f.domRestrict p) := by - rw [restrict_eq_codRestrict_domRestrict, ker_codRestrict] + ker (f.restrict hf) = (ker f).comap p.subtype := by + rw [restrict_eq_codRestrict_domRestrict, ker_codRestrict, ker_domRestrict] @[simp] theorem ker_zero : ker (0 : M →ₛₗ[τ₁₂] M₂) = ⊤ := @@ -150,11 +151,10 @@ end AddCommMonoid section Ring -variable [Ring R] [Ring R₂] [Ring R₃] -variable [AddCommGroup M] [AddCommGroup M₂] [AddCommGroup M₃] -variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] -variable {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} -variable [RingHomCompTriple τ₁₂ τ₂₃ τ₁₃] +variable [Ring R] [Ring R₂] +variable [AddCommGroup M] [AddCommGroup M₂] +variable [Module R M] [Module R₂ M₂] +variable {τ₁₂ : R →+* R₂} variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] variable {f : F} @@ -201,7 +201,8 @@ theorem ker_eq_bot {f : M →ₛₗ[τ₁₂] M₂} : ker f = ⊥ ↔ Injective @[simp] theorem injective_restrict_iff_disjoint {p : Submodule R M} {f : M →ₗ[R] M} (hf : ∀ x ∈ p, f x ∈ p) : Injective (f.restrict hf) ↔ Disjoint p (ker f) := by - rw [← ker_eq_bot, ker_restrict hf, ker_eq_bot, injective_domRestrict_iff, disjoint_iff] + rw [← ker_eq_bot, ker_restrict hf, ← ker_domRestrict, ker_eq_bot, injective_domRestrict_iff, + disjoint_iff] end Ring @@ -227,7 +228,7 @@ section AddCommMonoid variable [Semiring R] [Semiring R₂] [AddCommMonoid M] [AddCommMonoid M₂] variable [Module R M] [Module R₂ M₂] -variable (p p' : Submodule R M) (q : Submodule R₂ M₂) +variable (p : Submodule R M) variable {τ₁₂ : R →+* R₂} variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] diff --git a/Mathlib/Algebra/Module/Submodule/Localization.lean b/Mathlib/Algebra/Module/Submodule/Localization.lean index 9530de7dfed44..42dd4e3d8240d 100644 --- a/Mathlib/Algebra/Module/Submodule/Localization.lean +++ b/Mathlib/Algebra/Module/Submodule/Localization.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.Algebra.Module.LocalizedModule -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic import Mathlib.RingTheory.Localization.Module /-! @@ -57,6 +57,35 @@ lemma Submodule.mem_localized' (x : N) : abbrev Submodule.localized : Submodule (Localization p) (LocalizedModule p M) := M'.localized' (Localization p) p (LocalizedModule.mkLinearMap p M) +@[simp] +lemma Submodule.localized'_bot : (⊥ : Submodule R M).localized' S p f = ⊥ := by + rw [← le_bot_iff] + rintro _ ⟨_, rfl, s, rfl⟩ + simp only [IsLocalizedModule.mk'_zero, mem_bot] + +@[simp] +lemma Submodule.localized'_top : (⊤ : Submodule R M).localized' S p f = ⊤ := by + rw [← top_le_iff] + rintro x _ + obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective p f x + exact ⟨x, trivial, s, rfl⟩ + +@[simp] +lemma Submodule.localized'_span (s : Set M) : (span R s).localized' S p f = span S (f '' s) := by + apply le_antisymm + · rintro _ ⟨x, hx, t, rfl⟩ + have := IsLocalizedModule.mk'_smul_mk' S f 1 x t 1 + simp only [IsLocalizedModule.mk'_one, one_smul, mul_one] at this + rw [← this] + apply Submodule.smul_mem + rw [← Submodule.restrictScalars_mem R, ← Submodule.mem_comap] + refine (show span R s ≤ _ from ?_) hx + rw [← Submodule.map_le_iff_le_comap, Submodule.map_span] + exact span_le_restrictScalars _ _ _ + · rw [Submodule.span_le, Set.image_subset_iff] + intro x hx + exact ⟨x, subset_span hx, 1, IsLocalizedModule.mk'_one _ _ _⟩ + /-- The localization map of a submodule. -/ @[simps!] def Submodule.toLocalized' : M' →ₗ[R] M'.localized' S p f := diff --git a/Mathlib/Algebra/Module/Submodule/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index 0e08a969e1c07..022184894e59c 100644 --- a/Mathlib/Algebra/Module/Submodule/Map.lean +++ b/Mathlib/Algebra/Module/Submodule/Map.lean @@ -290,9 +290,12 @@ theorem map_iInf_comap_of_surjective {ι : Sort*} (S : ι → Submodule R₂ M (⨅ i, (S i).comap f).map f = iInf S := (giMapComap hf).l_iInf_u _ -theorem comap_le_comap_iff_of_surjective (p q : Submodule R₂ M₂) : p.comap f ≤ q.comap f ↔ p ≤ q := +theorem comap_le_comap_iff_of_surjective {p q : Submodule R₂ M₂} : p.comap f ≤ q.comap f ↔ p ≤ q := (giMapComap hf).u_le_u_iff +lemma comap_lt_comap_iff_of_surjective {p q : Submodule R₂ M₂} : p.comap f < q.comap f ↔ p < q := by + apply lt_iff_lt_of_le_iff_le' <;> exact comap_le_comap_iff_of_surjective hf + theorem comap_strictMono_of_surjective : StrictMono (comap f) := (giMapComap hf).strictMono_u @@ -361,10 +364,16 @@ def orderIsoMapComapOfBijective [FunLike F M M₂] [SemilinearMapClass F σ₁ map_rel_iff' := map_le_map_iff_of_injective hf.injective _ _ /-- A linear isomorphism induces an order isomorphism of submodules. -/ -@[simps! symm_apply apply] +@[simps! apply] def orderIsoMapComap [EquivLike F M M₂] [SemilinearMapClass F σ₁₂ M M₂] (f : F) : Submodule R M ≃o Submodule R₂ M₂ := orderIsoMapComapOfBijective f (EquivLike.bijective f) +@[simp] +lemma orderIsoMapComap_symm_apply [EquivLike F M M₂] [SemilinearMapClass F σ₁₂ M M₂] + (f : F) (p : Submodule R₂ M₂) : + (orderIsoMapComap f).symm p = comap f p := + rfl + end OrderIso variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F σ₁₂ M M₂] @@ -463,8 +472,8 @@ def comapSubtypeEquivOfLe {p q : Submodule R M} (hpq : p ≤ q) : comap q.subtyp invFun x := ⟨⟨x, hpq x.2⟩, x.2⟩ left_inv x := by simp only [coe_mk, SetLike.eta, LinearEquiv.coe_coe] right_inv x := by simp only [Subtype.coe_mk, SetLike.eta, LinearEquiv.coe_coe] - map_add' x y := rfl - map_smul' c x := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl -- Porting note: The original theorem generated by `simps` was using `LinearEquiv.toLinearMap`, -- different from the theorem on Lean 3, and not simp-normal form. diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index c8d8a18665f39..91345386ec6af 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -6,7 +6,8 @@ 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.Basic +import Mathlib.LinearAlgebra.Finsupp +import Mathlib.RingTheory.Ideal.Span /-! # Pointwise instances on `Submodule`s @@ -530,7 +531,7 @@ lemma coe_span_smul {R' M' : Type*} [CommSemiring R'] [AddCommMonoid M'] [Module (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 + 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 diff --git a/Mathlib/Algebra/Module/Submodule/Range.lean b/Mathlib/Algebra/Module/Submodule/Range.lean index 32fdf052d8793..7f70cb40186fa 100644 --- a/Mathlib/Algebra/Module/Submodule/Range.lean +++ b/Mathlib/Algebra/Module/Submodule/Range.lean @@ -28,7 +28,7 @@ linear algebra, vector space, module, range open Function variable {R : Type*} {R₂ : Type*} {R₃ : Type*} -variable {K : Type*} {K₂ : Type*} +variable {K : Type*} variable {M : Type*} {M₂ : Type*} {M₃ : Type*} variable {V : Type*} {V₂ : Type*} @@ -38,13 +38,11 @@ section AddCommMonoid variable [Semiring R] [Semiring R₂] [Semiring R₃] variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} -variable [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] open Submodule -variable {σ₂₁ : R₂ →+* R} {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} +variable {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} variable [RingHomCompTriple τ₁₂ τ₂₃ τ₁₃] section @@ -102,6 +100,9 @@ theorem range_neg {R : Type*} {R₂ : Type*} {M : Type*} {M₂ : Type*} [Semirin change range ((-LinearMap.id : M₂ →ₗ[R₂] M₂).comp f) = _ rw [range_comp, Submodule.map_neg, Submodule.map_id] +@[simp] lemma range_domRestrict [Module R M₂] (K : Submodule R M) (f : M →ₗ[R] M₂) : + range (domRestrict f K) = K.map f := by ext; simp + lemma range_domRestrict_le_range [RingHomSurjective τ₁₂] (f : M →ₛₗ[τ₁₂] M₂) (S : Submodule R M) : LinearMap.range (f.domRestrict S) ≤ LinearMap.range f := by rintro x ⟨⟨y, hy⟩, rfl⟩ @@ -175,7 +176,7 @@ theorem range_eq_bot {f : M →ₛₗ[τ₁₂] M₂} : range f = ⊥ ↔ f = 0 theorem range_le_ker_iff {f : M →ₛₗ[τ₁₂] M₂} {g : M₂ →ₛₗ[τ₂₃] M₃} : range f ≤ ker g ↔ (g.comp f : M →ₛₗ[τ₁₃] M₃) = 0 := - ⟨fun h => ker_eq_top.1 <| eq_top_iff'.2 fun x => h <| ⟨_, rfl⟩, fun h x hx => + ⟨fun h => ker_eq_top.1 <| eq_top_iff'.2 fun _ => h <| ⟨_, rfl⟩, fun h x hx => mem_ker.2 <| Exists.elim hx fun y hy => by rw [← hy, ← comp_apply, h, zero_apply]⟩ theorem comap_le_comap_iff {f : F} (hf : range f = ⊤) {p p'} : comap f p ≤ comap f p' ↔ p ≤ p' := @@ -190,11 +191,10 @@ end AddCommMonoid section Ring -variable [Ring R] [Ring R₂] [Ring R₃] -variable [AddCommGroup M] [AddCommGroup M₂] [AddCommGroup M₃] -variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] -variable {τ₁₂ : R →+* R₂} {τ₂₃ : R₂ →+* R₃} {τ₁₃ : R →+* R₃} -variable [RingHomCompTriple τ₁₂ τ₂₃ τ₁₃] +variable [Ring R] [Ring R₂] +variable [AddCommGroup M] [AddCommGroup M₂] +variable [Module R M] [Module R₂ M₂] +variable {τ₁₂ : R →+* R₂} variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] variable {f : F} @@ -228,7 +228,7 @@ end Ring section Semifield -variable [Semifield K] [Semifield K₂] +variable [Semifield K] variable [AddCommMonoid V] [Module K V] variable [AddCommMonoid V₂] [Module K V₂] @@ -249,7 +249,7 @@ section AddCommMonoid variable [Semiring R] [Semiring R₂] [AddCommMonoid M] [AddCommMonoid M₂] variable [Module R M] [Module R₂ M₂] -variable (p p' : Submodule R M) (q : Submodule R₂ M₂) +variable (p : Submodule R M) variable {τ₁₂ : R →+* R₂} variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] @@ -266,7 +266,6 @@ theorem map_subtype_le (p' : Submodule R p) : map p.subtype p' ≤ p := by /-- Under the canonical linear map from a submodule `p` to the ambient space `M`, the image of the maximal submodule of `p` is just `p`. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem map_subtype_top : map p.subtype (⊤ : Submodule R p) = p := by simp @[simp] @@ -277,6 +276,12 @@ theorem comap_subtype_eq_top {p p' : Submodule R M} : comap p.subtype p' = ⊤ theorem comap_subtype_self : comap p.subtype p = ⊤ := comap_subtype_eq_top.2 le_rfl +@[simp] +lemma comap_subtype_le_iff {p q r : Submodule R M} : + q.comap p.subtype ≤ r.comap p.subtype ↔ p ⊓ q ≤ p ⊓ r := + ⟨fun h ↦ by simpa using map_mono (f := p.subtype) h, + fun h ↦ by simpa using comap_mono (f := p.subtype) h⟩ + theorem range_inclusion (p q : Submodule R M) (h : p ≤ q) : range (inclusion h) = comap q.subtype p := by rw [← map_top, inclusion, LinearMap.map_codRestrict, map_top, range_subtype] diff --git a/Mathlib/Algebra/Module/Torsion.lean b/Mathlib/Algebra/Module/Torsion.lean index 5be854af327cb..096deecf0532a 100644 --- a/Mathlib/Algebra/Module/Torsion.lean +++ b/Mathlib/Algebra/Module/Torsion.lean @@ -631,7 +631,6 @@ variable (S : Type*) [CommMonoid S] [DistribMulAction S M] [SMulCommClass S R M] theorem mem_torsion'_iff (x : M) : x ∈ torsion' R M S ↔ ∃ a : S, a • x = 0 := Iff.rfl --- @[simp] Porting note (#10618): simp can prove this theorem mem_torsion_iff (x : M) : x ∈ torsion R M ↔ ∃ a : R⁰, a • x = 0 := Iff.rfl @@ -666,7 +665,6 @@ theorem torsion'_torsion'_eq_top : torsion' R (torsion' R M S) S = ⊤ := /-- The torsion submodule of the torsion submodule (viewed as a module) is the full torsion module. -/ --- @[simp] Porting note (#10618): simp can prove this theorem torsion_torsion_eq_top : torsion R (torsion R M) = ⊤ := torsion'_torsion'_eq_top R⁰ diff --git a/Mathlib/Algebra/Module/ZLattice/Basic.lean b/Mathlib/Algebra/Module/ZLattice/Basic.lean index a436852b2ab88..8113915f8a6a5 100644 --- a/Mathlib/Algebra/Module/ZLattice/Basic.lean +++ b/Mathlib/Algebra/Module/ZLattice/Basic.lean @@ -24,7 +24,7 @@ A `ℤ`-lattice `L` can be defined in two ways: Results about the first point of view are in the `ZSpan` namespace and results about the second point of view are in the `ZLattice` namespace. -## Main results +## Main results and definitions * `ZSpan.isAddFundamentalDomain`: for a ℤ-lattice `Submodule.span ℤ (Set.range b)`, proves that the set defined by `ZSpan.fundamentalDomain` is a fundamental domain. @@ -32,6 +32,9 @@ the set defined by `ZSpan.fundamentalDomain` is a fundamental domain. `ℤ`-module * `ZLattice.rank`: a `ℤ`-submodule of `E` that is discrete and spans `E` over `K` is free of `ℤ`-rank equal to the `K`-rank of `E` +* `ZLattice.comap`: for `e : E → F` a linear map and `L : Submodule ℤ E`, define the pullback of +`L` by `e`. If `L` is a `IsZLattice` and `e` is a continuous linear equiv, then it is also a +`IsZLattice`, see `instIsZLatticeComap`. ## Implementation Notes @@ -58,6 +61,11 @@ 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] + /-- 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} @@ -276,7 +284,7 @@ theorem discreteTopology_pi_basisFun [Finite ι] : refine discreteTopology_iff_isOpen_singleton_zero.mpr ⟨Metric.ball 0 1, Metric.isOpen_ball, ?_⟩ ext x rw [Set.mem_preimage, mem_ball_zero_iff, pi_norm_lt_iff zero_lt_one, Set.mem_singleton_iff] - simp_rw [← coe_eq_zero, Function.funext_iff, Pi.zero_apply, Real.norm_eq_abs] + simp_rw [← coe_eq_zero, funext_iff, Pi.zero_apply, Real.norm_eq_abs] refine forall_congr' (fun i => ?_) rsuffices ⟨y, hy⟩ : ∃ (y : ℤ), (y : ℝ) = (x : ι → ℝ) i · rw [← hy, ← Int.cast_abs, ← Int.cast_one, Int.cast_lt, Int.abs_lt_one_iff, Int.cast_eq_zero] @@ -399,6 +407,8 @@ theorem _root_.ZSpan.isZLattice {E ι : Type*} [NormedAddCommGroup E] [NormedSpa IsZLattice ℝ (span ℤ (Set.range b)) where span_top := ZSpan.span_top b +section NormedLinearOrderedField + variable (K : Type*) [NormedLinearOrderedField K] [HasSolidNorm K] [FloorRing K] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] [FiniteDimensional K E] variable [ProperSpace E] (L : Submodule ℤ E) [DiscreteTopology L] @@ -607,4 +617,81 @@ instance instCountable_of_discrete_submodule {E : Type*} [NormedAddCommGroup E] simp_rw [← (Module.Free.chooseBasis ℤ L).ofZLatticeBasis_span ℝ] infer_instance +end NormedLinearOrderedField + +section comap + +variable (K : Type*) [NormedField K] {E F : Type*} [NormedAddCommGroup E] [NormedSpace K E] + [NormedAddCommGroup F] [NormedSpace K F] (L : Submodule ℤ E) + +/-- Let `e : E → F` a linear map, the map that sends a `L : Submodule ℤ E` to the +`Submodule ℤ F` that is the pullback of `L` by `e`. If `IsZLattice L` and `e` is a continuous +linear equiv, then it is a `IsZLattice` of `E`, see `instIsZLatticeComap`. -/ +protected def ZLattice.comap (e : F →ₗ[K] E) := L.comap (e.restrictScalars ℤ) + +@[simp] +theorem ZLattice.coe_comap (e : F →ₗ[K] E) : + (ZLattice.comap K L e : Set F) = e⁻¹' L := rfl + +theorem ZLattice.comap_refl : + ZLattice.comap K L (1 : E →ₗ[K] E)= L := Submodule.comap_id L + +theorem ZLattice.comap_discreteTopology [hL : DiscreteTopology L] {e : F →ₗ[K] E} + (he₁ : Continuous e) (he₂ : Function.Injective e) : + DiscreteTopology (ZLattice.comap K L e) := by + exact DiscreteTopology.preimage_of_continuous_injective L he₁ he₂ + +instance [DiscreteTopology L] (e : F ≃L[K] E) : + DiscreteTopology (ZLattice.comap K L e.toLinearMap) := + ZLattice.comap_discreteTopology K L e.continuous e.injective + +theorem ZLattice.comap_span_top (hL : span K (L : Set E) = ⊤) {e : F →ₗ[K] E} + (he : (L : Set E) ⊆ LinearMap.range e) : + span K (ZLattice.comap K L e : Set F) = ⊤ := by + rw [ZLattice.coe_comap, Submodule.span_preimage_eq (Submodule.nonempty L) he, hL, comap_top] + +instance instIsZLatticeComap [DiscreteTopology L] [IsZLattice K L] (e : F ≃L[K] E) : + IsZLattice K (ZLattice.comap K L e.toLinearMap) where + span_top := by + rw [ZLattice.coe_comap, LinearEquiv.coe_coe, e.coe_toLinearEquiv, ← e.image_symm_eq_preimage, + ← Submodule.map_span, IsZLattice.span_top, Submodule.map_top, LinearEquivClass.range] + +theorem ZLattice.comap_comp {G : Type*} [NormedAddCommGroup G] [NormedSpace K G] + (e : F →ₗ[K] E) (e' : G →ₗ[K] F) : + (ZLattice.comap K (ZLattice.comap K L e) e') = ZLattice.comap K L (e ∘ₗ e') := + (Submodule.comap_comp _ _ L).symm + +/-- If `e` is a linear equivalence, it induces a `ℤ`-linear equivalence between +`L` and `ZLattice.comap K L e`. -/ +def ZLattice.comap_equiv (e : F ≃ₗ[K] E) : + L ≃ₗ[ℤ] (ZLattice.comap K L e.toLinearMap) := + LinearEquiv.ofBijective + ((e.symm.toLinearMap.restrictScalars ℤ).restrict + (fun _ h ↦ by simpa [← SetLike.mem_coe] using h)) + ⟨fun _ _ h ↦ Subtype.ext_iff_val.mpr (e.symm.injective (congr_arg Subtype.val h)), + fun ⟨x, hx⟩ ↦ ⟨⟨e x, by rwa [← SetLike.mem_coe, ZLattice.coe_comap] at hx⟩, + by simp [Subtype.ext_iff_val]⟩⟩ + +@[simp] +theorem ZLattice.comap_equiv_apply (e : F ≃ₗ[K] E) (x : L) : + ZLattice.comap_equiv K L e x = e.symm x := rfl + +/-- The basis of `ZLattice.comap K L e` given by the image of a basis `b` of `L` by `e.symm`. -/ +def Basis.ofZLatticeComap (e : F ≃ₗ[K] E) {ι : Type*} + (b : Basis ι ℤ L) : + Basis ι ℤ (ZLattice.comap K L e.toLinearMap) := b.map (ZLattice.comap_equiv K L e) + +@[simp] +theorem Basis.ofZLatticeComap_apply (e : F ≃ₗ[K] E) {ι : Type*} + (b : Basis ι ℤ L) (i : ι) : + b.ofZLatticeComap K L e i = e.symm (b i) := by simp [Basis.ofZLatticeComap] + +@[simp] +theorem Basis.ofZLatticeComap_repr_apply (e : F ≃ₗ[K] E) {ι : Type*} (b : Basis ι ℤ L) (x : L) + (i : ι) : + (b.ofZLatticeComap K L e).repr (ZLattice.comap_equiv K L e x) i = b.repr x i := by + simp [Basis.ofZLatticeComap] + +end comap + end ZLattice diff --git a/Mathlib/Algebra/Module/ZLattice/Covolume.lean b/Mathlib/Algebra/Module/ZLattice/Covolume.lean index 04e559d80a384..f5740d29e7505 100644 --- a/Mathlib/Algebra/Module/ZLattice/Covolume.lean +++ b/Mathlib/Algebra/Module/ZLattice/Covolume.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Module.ZLattice.Basic /-! # Covolume of ℤ-lattices -Let `E` be a finite dimensional real vector space with an inner product. +Let `E` be a finite dimensional real vector space. Let `L` be a `ℤ`-lattice `L` defined as a discrete `ℤ`-submodule of `E` that spans `E` over `ℝ`. @@ -29,14 +29,11 @@ noncomputable section namespace ZLattice -open Submodule MeasureTheory Module MeasureTheory Module +open Submodule MeasureTheory Module MeasureTheory Module ZSpan section General -variable (K : Type*) [NormedLinearOrderedField K] [HasSolidNorm K] [FloorRing K] -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] [FiniteDimensional K E] -variable [ProperSpace E] [MeasurableSpace E] -variable (L : Submodule ℤ E) [DiscreteTopology L] [IsZLattice K L] +variable {E : Type*} [NormedAddCommGroup E] [ProperSpace E] [MeasurableSpace E] (L : Submodule ℤ E) /-- The covolume of a `ℤ`-lattice is the volume of some fundamental domain; see `ZLattice.covolume_eq_volume` for the proof that the volume does not depend on the choice of @@ -61,18 +58,30 @@ theorem covolume_eq_measure_fundamentalDomain {F : Set E} (h : IsAddFundamentalD theorem covolume_ne_zero : covolume L μ ≠ 0 := by rw [covolume_eq_measure_fundamentalDomain L μ (isAddFundamentalDomain (Free.chooseBasis ℤ L) μ), ENNReal.toReal_ne_zero] - refine ⟨ZSpan.measure_fundamentalDomain_ne_zero _, ne_of_lt ?_⟩ - exact Bornology.IsBounded.measure_lt_top (ZSpan.fundamentalDomain_isBounded _) + refine ⟨measure_fundamentalDomain_ne_zero _, ne_of_lt ?_⟩ + exact Bornology.IsBounded.measure_lt_top (fundamentalDomain_isBounded _) theorem covolume_pos : 0 < covolume L μ := lt_of_le_of_ne ENNReal.toReal_nonneg (covolume_ne_zero L μ).symm +theorem covolume_comap {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] [FiniteDimensional ℝ F] + [MeasurableSpace F] [BorelSpace F] (ν : Measure F := by volume_tac) [Measure.IsAddHaarMeasure ν] + {e : F ≃L[ℝ] E} (he : MeasurePreserving e ν μ) : + covolume (ZLattice.comap ℝ L e.toLinearMap) ν = covolume L μ := by + rw [covolume_eq_measure_fundamentalDomain _ _ (isAddFundamentalDomain (Free.chooseBasis ℤ L) μ), + covolume_eq_measure_fundamentalDomain _ _ ((isAddFundamentalDomain + ((Free.chooseBasis ℤ L).ofZLatticeComap ℝ L e.toLinearEquiv) ν)), ← he.measure_preimage + (fundamentalDomain_measurableSet _).nullMeasurableSet, ← e.image_symm_eq_preimage, + ← e.symm.coe_toLinearEquiv, map_fundamentalDomain] + congr! + ext; simp + theorem covolume_eq_det_mul_measure {ι : Type*} [Fintype ι] [DecidableEq ι] (b : Basis ι ℤ L) (b₀ : Basis ι ℝ E) : - covolume L μ = |b₀.det ((↑) ∘ b)| * (μ (ZSpan.fundamentalDomain b₀)).toReal := by + covolume L μ = |b₀.det ((↑) ∘ b)| * (μ (fundamentalDomain b₀)).toReal := by rw [covolume_eq_measure_fundamentalDomain L μ (isAddFundamentalDomain b μ), - ZSpan.measure_fundamentalDomain _ _ b₀, - measure_congr (ZSpan.fundamentalDomain_ae_parallelepiped b₀ μ), ENNReal.toReal_mul, + measure_fundamentalDomain _ _ b₀, + measure_congr (fundamentalDomain_ae_parallelepiped b₀ μ), ENNReal.toReal_mul, ENNReal.toReal_ofReal (by positivity)] congr ext @@ -82,7 +91,7 @@ theorem covolume_eq_det {ι : Type*} [Fintype ι] [DecidableEq ι] (L : Submodul [DiscreteTopology L] [IsZLattice ℝ L] (b : Basis ι ℤ L) : covolume L = |(Matrix.of ((↑) ∘ b)).det| := by rw [covolume_eq_measure_fundamentalDomain L volume (isAddFundamentalDomain b volume), - ZSpan.volume_fundamentalDomain, ENNReal.toReal_ofReal (by positivity)] + volume_fundamentalDomain, ENNReal.toReal_ofReal (by positivity)] congr ext1 exact b.ofZLatticeBasis_apply ℝ L _ diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index c859345b543ca..e5d8512805835 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -90,8 +90,7 @@ def liftMagma [Module k A] [IsScalarTower k A A] [SMulCommClass k A A] : sum_single_index, Function.comp_apply, one_smul, zero_smul, MulHom.coe_comp, NonUnitalAlgHom.coe_to_mulHom] right_inv F := by - -- Porting note: `ext` → `refine nonUnitalAlgHom_ext' k (MulHom.ext fun m => ?_)` - refine nonUnitalAlgHom_ext' k (MulHom.ext fun m => ?_) + ext m simp only [NonUnitalAlgHom.coe_mk, ofMagma_apply, NonUnitalAlgHom.toMulHom_eq_coe, sum_single_index, Function.comp_apply, one_smul, zero_smul, MulHom.coe_comp, NonUnitalAlgHom.coe_to_mulHom] @@ -109,9 +108,8 @@ In particular this provides the instance `Algebra k (MonoidAlgebra k G)`. instance algebra {A : Type*} [CommSemiring k] [Semiring A] [Algebra k A] [Monoid G] : Algebra k (MonoidAlgebra A G) := { singleOneRingHom.comp (algebraMap k A) with - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` smul_def' := fun r a => by - refine Finsupp.ext fun _ => ?_ + ext -- Porting note: Newly required. rw [Finsupp.coe_smul] simp [single_one_mul_apply, Algebra.smul_def, Pi.smul_apply] @@ -125,8 +123,7 @@ def singleOneAlgHom {A : Type*} [CommSemiring k] [Semiring A] [Algebra k A] [Mon A →ₐ[k] MonoidAlgebra A G := { singleOneRingHom with commutes' := fun r => by - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` - refine Finsupp.ext fun _ => ?_ + ext simp rfl } @@ -390,9 +387,8 @@ In particular this provides the instance `Algebra k k[G]`. instance algebra [CommSemiring R] [Semiring k] [Algebra R k] [AddMonoid G] : Algebra R k[G] := { singleZeroRingHom.comp (algebraMap R k) with - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` smul_def' := fun r a => by - refine Finsupp.ext fun _ => ?_ + ext -- Porting note: Newly required. rw [Finsupp.coe_smul] simp [single_zero_mul_apply, Algebra.smul_def, Pi.smul_apply] @@ -405,8 +401,7 @@ instance algebra [CommSemiring R] [Semiring k] [Algebra R k] [AddMonoid G] : def singleZeroAlgHom [CommSemiring R] [Semiring k] [Algebra R k] [AddMonoid G] : k →ₐ[R] k[G] := { singleZeroRingHom with commutes' := fun r => by - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` - refine Finsupp.ext fun _ => ?_ + ext simp rfl } diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean index a2574ffe76219..09ff3e900210d 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Defs.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -86,7 +86,7 @@ instance MonoidAlgebra.instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (MonoidAlge inferInstanceAs (IsCancelAdd (G →₀ k)) instance MonoidAlgebra.coeFun : CoeFun (MonoidAlgebra k G) fun _ => G → k := - Finsupp.instCoeFun + inferInstanceAs (CoeFun (G →₀ k) _) end @@ -377,6 +377,63 @@ def comapDistribMulActionSelf [Group G] [Semiring k] : DistribMulAction G (Monoi end DerivedInstances +/-! +#### Copies of `ext` lemmas and bundled `single`s from `Finsupp` + +As `MonoidAlgebra` is a type synonym, `ext` will not unfold it to find `ext` lemmas. +We need bundled version of `Finsupp.single` with the right types to state these lemmas. +It is good practice to have those, regardless of the `ext` issue. +-/ + +section ExtLemmas + +/-- A copy of `Finsupp.ext` for `MonoidAlgebra`. -/ +@[ext] +theorem ext [Semiring k] ⦃f g : MonoidAlgebra k G⦄ (H : ∀ (x : G), f x = g x) : + f = g := + Finsupp.ext H + +/-- A copy of `Finsupp.singleAddHom` for `MonoidAlgebra`. -/ +abbrev singleAddHom [Semiring k] (a : G) : k →+ MonoidAlgebra k G := Finsupp.singleAddHom a + +@[simp] lemma singleAddHom_apply [Semiring k] (a : G) (b : k) : + singleAddHom a b = single a b := rfl + +/-- A copy of `Finsupp.addHom_ext'` for `MonoidAlgebra`. -/ +@[ext high] +theorem addHom_ext' {N : Type*} [Semiring k] [AddZeroClass N] + ⦃f g : MonoidAlgebra k G →+ N⦄ + (H : ∀ (x : G), AddMonoidHom.comp f (singleAddHom x) = AddMonoidHom.comp g (singleAddHom x)) : + f = g := + Finsupp.addHom_ext' H + +/-- A copy of `Finsupp.distribMulActionHom_ext'` for `MonoidAlgebra`. -/ +@[ext] +theorem distribMulActionHom_ext' {N : Type*} [Monoid R] [Semiring k] [AddMonoid N] + [DistribMulAction R N] [DistribMulAction R k] + {f g : MonoidAlgebra k G →+[R] N} + (h : ∀ a : G, + f.comp (DistribMulActionHom.single (M := k) a) = g.comp (DistribMulActionHom.single a)) : + f = g := + Finsupp.distribMulActionHom_ext' h + +/-- A copy of `Finsupp.lsingle` for `MonoidAlgebra`. -/ +abbrev lsingle [Semiring R] [Semiring k] [Module R k] (a : G) : + k →ₗ[R] MonoidAlgebra k G := Finsupp.lsingle a + +@[simp] lemma lsingle_apply [Semiring R] [Semiring k] [Module R k] (a : G) (b : k) : + lsingle (R := R) a b = single a b := rfl + +/-- A copy of `Finsupp.lhom_ext'` for `MonoidAlgebra`. -/ +@[ext high] +lemma lhom_ext' {N : Type*} [Semiring R] [Semiring k] [AddCommMonoid N] [Module R N] [Module R k] + ⦃f g : MonoidAlgebra k G →ₗ[R] N⦄ + (H : ∀ (x : G), LinearMap.comp f (lsingle x) = LinearMap.comp g (lsingle x)) : + f = g := + Finsupp.lhom_ext' H + +end ExtLemmas + section MiscTheorems variable [Semiring k] @@ -397,14 +454,10 @@ theorem mul_apply_antidiagonal [Mul G] (f g : MonoidAlgebra k G) (x : G) (s : Fi calc (f * g) x = ∑ a₁ ∈ f.support, ∑ a₂ ∈ g.support, F (a₁, a₂) := mul_apply f g x _ = ∑ p ∈ f.support ×ˢ g.support, F p := by rw [Finset.sum_product] - _ = ∑ p ∈ (f.support ×ˢ g.support).filter fun p : G × G => p.1 * p.2 = x, f p.1 * g p.2 := + _ = ∑ p ∈ f.support ×ˢ g.support with p.1 * p.2 = x, f p.1 * g p.2 := (Finset.sum_filter _ _).symm - _ = ∑ p ∈ s.filter fun p : G × G => p.1 ∈ f.support ∧ p.2 ∈ g.support, f p.1 * g p.2 := - (sum_congr - (by - ext - simp only [mem_filter, mem_product, hs, and_comm]) - fun _ _ => rfl) + _ = ∑ p ∈ s with p.1 ∈ f.support ∧ p.2 ∈ g.support, f p.1 * g p.2 := by + congr! 1; ext; simp only [mem_filter, mem_product, hs, and_comm] _ = ∑ p ∈ s, f p.1 * g p.2 := sum_subset (filter_subset _ _) fun p hps hp => by simp only [mem_filter, mem_support_iff, not_and, Classical.not_not] at hp ⊢ @@ -477,9 +530,13 @@ def of [MulOneClass G] : G →* MonoidAlgebra k G := end +/-- Copy of `Finsupp.smul_single'` that avoids the `MonoidAlgebra = Finsupp` defeq abuse. -/ +@[simp] +theorem smul_single' (c : k) (a : G) (b : k) : c • single a b = single a (c * b) := + Finsupp.smul_single' c a b + theorem smul_of [MulOneClass G] (g : G) (r : k) : r • of k G g = single g r := by - -- porting note (#10745): was `simp`. - rw [of_apply, smul_single', mul_one] + simp theorem of_injective [MulOneClass G] [Nontrivial k] : Function.Injective (of k G) := fun a b h => by @@ -563,12 +620,11 @@ theorem liftNC_smul [MulOneClass G] {R : Type*} [Semiring R] (f : k →+* R) (g suffices (liftNC (↑f) g).comp (smulAddHom k (MonoidAlgebra k G) c) = (AddMonoidHom.mulLeft (f c)).comp (liftNC (↑f) g) from DFunLike.congr_fun this φ - -- Porting note: `ext` couldn't a find appropriate theorem. - refine addHom_ext' fun a => AddMonoidHom.ext fun b => ?_ + ext -- Porting note: `reducible` cannot be `local` so the proof gets more complex. unfold MonoidAlgebra simp only [AddMonoidHom.coe_comp, Function.comp_apply, singleAddHom_apply, smulAddHom_apply, - smul_single, smul_eq_mul, AddMonoidHom.coe_mulLeft] + smul_single, smul_eq_mul, AddMonoidHom.coe_mulLeft, Finsupp.singleAddHom_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [liftNC_single, liftNC_single]; rw [AddMonoidHom.coe_coe, map_mul, mul_assoc] @@ -582,34 +638,32 @@ section NonUnitalNonAssocAlgebra variable (k) [Semiring k] [DistribSMul R k] [Mul G] instance isScalarTower_self [IsScalarTower R k k] : - IsScalarTower R (MonoidAlgebra k G) (MonoidAlgebra k G) := - ⟨fun t a b => by - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` - refine Finsupp.ext fun m => ?_ + IsScalarTower R (MonoidAlgebra k G) (MonoidAlgebra k G) where + smul_assoc t a b := by + ext -- Porting note: `refine` & `rw` are required because `simp` behaves differently. classical - simp only [smul_eq_mul, mul_apply] - rw [coe_smul] - refine Eq.trans (sum_smul_index' (g := a) (b := t) ?_) ?_ <;> - simp only [mul_apply, Finsupp.smul_sum, smul_ite, smul_mul_assoc, - zero_mul, ite_self, imp_true_iff, sum_zero, Pi.smul_apply, smul_zero]⟩ + simp only [smul_eq_mul, mul_apply] + rw [coe_smul] + refine Eq.trans (sum_smul_index' (g := a) (b := t) ?_) ?_ <;> + simp only [mul_apply, Finsupp.smul_sum, smul_ite, smul_mul_assoc, + zero_mul, ite_self, imp_true_iff, sum_zero, Pi.smul_apply, smul_zero] /-- Note that if `k` is a `CommSemiring` then we have `SMulCommClass k k k` and so we can take `R = k` in the below. In other words, if the coefficients are commutative amongst themselves, they also commute with the algebra multiplication. -/ instance smulCommClass_self [SMulCommClass R k k] : - SMulCommClass R (MonoidAlgebra k G) (MonoidAlgebra k G) := - ⟨fun t a b => by - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` - refine Finsupp.ext fun m => ?_ + SMulCommClass R (MonoidAlgebra k G) (MonoidAlgebra k G) where + smul_comm t a b := by + ext -- Porting note: `refine` & `rw` are required because `simp` behaves differently. classical - simp only [smul_eq_mul, mul_apply] - rw [coe_smul] - refine Eq.symm (Eq.trans (congr_arg (sum a) - (funext₂ fun a₁ b₁ => sum_smul_index' (g := b) (b := t) ?_)) ?_) <;> - simp only [mul_apply, Finsupp.sum, Finset.smul_sum, smul_ite, mul_smul_comm, - imp_true_iff, ite_eq_right_iff, Pi.smul_apply, mul_zero, smul_zero]⟩ + simp only [smul_eq_mul, mul_apply] + rw [coe_smul] + refine Eq.symm (Eq.trans (congr_arg (sum a) + (funext₂ fun a₁ b₁ => sum_smul_index' (g := b) (b := t) ?_)) ?_) <;> + simp only [mul_apply, Finsupp.sum, Finset.smul_sum, smul_ite, mul_smul_comm, + imp_true_iff, ite_eq_right_iff, Pi.smul_apply, mul_zero, smul_zero] instance smulCommClass_symm_self [SMulCommClass k R k] : SMulCommClass (MonoidAlgebra k G) R (MonoidAlgebra k G) := @@ -628,10 +682,7 @@ theorem single_one_comm [CommSemiring k] [MulOneClass G] (r : k) (f : MonoidAlge def singleOneRingHom [Semiring k] [MulOneClass G] : k →+* MonoidAlgebra k G := { Finsupp.singleAddHom 1 with map_one' := rfl - map_mul' := fun x y => by - -- Porting note (#10691): Was `rw`. - simp only [ZeroHom.toFun_eq_coe, AddMonoidHom.toZeroHom_coe, singleAddHom_apply, - single_mul_single, mul_one] } + map_mul' := fun x y => by simp } /-- If `f : G → H` is a multiplicative homomorphism between two monoids, then `Finsupp.mapDomain f` is a ring homomorphism between their monoid algebras. -/ @@ -671,8 +722,7 @@ theorem induction_on [Semiring k] [Monoid G] {p : MonoidAlgebra k G → Prop} (f refine Finsupp.induction_linear f ?_ (fun f g hf hg => hadd f g hf hg) fun g r => ?_ · simpa using hsmul 0 (of k G 1) (hM 1) · convert hsmul r (of k G g) (hM g) - -- Porting note: Was `simp only`. - rw [of_apply, smul_single', mul_one] + simp section @@ -742,9 +792,7 @@ protected noncomputable def opRingEquiv [Monoid G] : rw [← AddEquiv.coe_toAddMonoidHom] refine Iff.mpr (AddMonoidHom.map_mul_iff (R := (MonoidAlgebra k G)ᵐᵒᵖ) (S := MonoidAlgebra kᵐᵒᵖ Gᵐᵒᵖ) _) ?_ - -- Porting note: Was `ext`. - refine AddMonoidHom.mul_op_ext _ _ <| addHom_ext' fun i₁ => AddMonoidHom.ext fun r₁ => - AddMonoidHom.mul_op_ext _ _ <| addHom_ext' fun i₂ => AddMonoidHom.ext fun r₂ => ?_ + ext -- Porting note: `reducible` cannot be `local` so proof gets long. simp only [AddMonoidHom.coe_comp, AddEquiv.coe_toAddMonoidHom, opAddEquiv_apply, Function.comp_apply, singleAddHom_apply, AddMonoidHom.compr₂_apply, AddMonoidHom.coe_mul, @@ -752,16 +800,15 @@ protected noncomputable def opRingEquiv [Monoid G] : -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply, MulOpposite.opAddEquiv_symm_apply] - rw [MulOpposite.unop_mul (α := MonoidAlgebra k G)] - -- This was not needed before leanprover/lean4#2644 - erw [unop_op, unop_op, single_mul_single] + rw [MulOpposite.unop_mul (α := MonoidAlgebra k G), unop_op, unop_op, single_mul_single] simp } --- @[simp] -- Porting note (#10618): simp can prove this +-- @[simp] -- Porting note (#10618): simp can prove this. +-- More specifically, the LHS simplifies to `Finsupp.single`, which implies there's some +-- defeq abuse going on. theorem opRingEquiv_single [Monoid G] (r : k) (x : G) : MonoidAlgebra.opRingEquiv (op (single x r)) = single (op x) (op r) := by simp --- @[simp] -- Porting note (#10618): simp can prove this theorem opRingEquiv_symm_single [Monoid G] (r : kᵐᵒᵖ) (x : Gᵐᵒᵖ) : MonoidAlgebra.opRingEquiv.symm (single x r) = op (single x.unop r.unop) := by simp @@ -821,7 +868,7 @@ instance instIsCancelAdd [IsCancelAdd k] : IsCancelAdd (AddMonoidAlgebra k G) := inferInstanceAs (IsCancelAdd (G →₀ k)) instance coeFun : CoeFun k[G] fun _ => G → k := - Finsupp.instCoeFun + inferInstanceAs (CoeFun (G →₀ k) _) end AddMonoidAlgebra @@ -924,7 +971,7 @@ instance nonUnitalNonAssocSemiring : NonUnitalNonAssocSemiring k[G] := simp only [mul_def] exact Eq.trans (congr_arg (sum f) (funext₂ fun a₁ b₁ => sum_zero_index)) sum_zero nsmul := fun n f => n • f - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` + -- Porting note (#11041): `ext` → `refine Finsupp.ext fun _ => ?_` nsmul_zero := by intros refine Finsupp.ext fun _ => ?_ @@ -1119,6 +1166,63 @@ because we've never discussed actions of additive groups. -/ end DerivedInstances +/-! +#### Copies of `ext` lemmas and bundled `single`s from `Finsupp` + +As `AddMonoidAlgebra` is a type synonym, `ext` will not unfold it to find `ext` lemmas. +We need bundled version of `Finsupp.single` with the right types to state these lemmas. +It is good practice to have those, regardless of the `ext` issue. +-/ + +section ExtLemmas + +/-- A copy of `Finsupp.ext` for `AddMonoidAlgebra`. -/ +@[ext] +theorem ext [Semiring k] ⦃f g : AddMonoidAlgebra k G⦄ (H : ∀ (x : G), f x = g x) : + f = g := + Finsupp.ext H + +/-- A copy of `Finsupp.singleAddHom` for `AddMonoidAlgebra`. -/ +abbrev singleAddHom [Semiring k] (a : G) : k →+ AddMonoidAlgebra k G := Finsupp.singleAddHom a + +@[simp] lemma singleAddHom_apply [Semiring k] (a : G) (b : k) : + singleAddHom a b = single a b := rfl + +/-- A copy of `Finsupp.addHom_ext'` for `AddMonoidAlgebra`. -/ +@[ext high] +theorem addHom_ext' {N : Type*} [Semiring k] [AddZeroClass N] + ⦃f g : AddMonoidAlgebra k G →+ N⦄ + (H : ∀ (x : G), AddMonoidHom.comp f (singleAddHom x) = AddMonoidHom.comp g (singleAddHom x)) : + f = g := + Finsupp.addHom_ext' H + +/-- A copy of `Finsupp.distribMulActionHom_ext'` for `AddMonoidAlgebra`. -/ +@[ext] +theorem distribMulActionHom_ext' {N : Type*} [Monoid R] [Semiring k] [AddMonoid N] + [DistribMulAction R N] [DistribMulAction R k] + {f g : AddMonoidAlgebra k G →+[R] N} + (h : ∀ a : G, + f.comp (DistribMulActionHom.single (M := k) a) = g.comp (DistribMulActionHom.single a)) : + f = g := + Finsupp.distribMulActionHom_ext' h + +/-- A copy of `Finsupp.lsingle` for `AddMonoidAlgebra`. -/ +abbrev lsingle [Semiring R] [Semiring k] [Module R k] (a : G) : + k →ₗ[R] AddMonoidAlgebra k G := Finsupp.lsingle a + +@[simp] lemma lsingle_apply [Semiring R] [Semiring k] [Module R k] (a : G) (b : k) : + lsingle (R := R) a b = single a b := rfl + +/-- A copy of `Finsupp.lhom_ext'` for `AddMonoidAlgebra`. -/ +@[ext high] +lemma lhom_ext' {N : Type*} [Semiring R] [Semiring k] [AddCommMonoid N] [Module R N] [Module R k] + ⦃f g : AddMonoidAlgebra k G →ₗ[R] N⦄ + (H : ∀ (x : G), LinearMap.comp f (lsingle x) = LinearMap.comp g (lsingle x)) : + f = g := + Finsupp.lhom_ext' H + +end ExtLemmas + section MiscTheorems variable [Semiring k] @@ -1223,6 +1327,11 @@ def singleHom [AddZeroClass G] : k × Multiplicative G →* k[G] where map_one' := rfl map_mul' _a _b := single_mul_single.symm +/-- Copy of `Finsupp.smul_single'` that avoids the `AddMonoidAlgebra = Finsupp` defeq abuse. -/ +@[simp] +theorem smul_single' (c : k) (a : G) (b : k) : c • single a b = single a (c * b) := + Finsupp.smul_single' c a b + theorem mul_single_apply_aux [Add G] (f : k[G]) (r : k) (x y z : G) (H : ∀ a, a + x = z ↔ a = y) : (f * single x r) z = f y * r := @MonoidAlgebra.mul_single_apply_aux k (Multiplicative G) _ _ _ _ _ _ _ H @@ -1267,8 +1376,7 @@ theorem induction_on [AddMonoid G] {p : k[G] → Prop} (f : k[G]) refine Finsupp.induction_linear f ?_ (fun f g hf hg => hadd f g hf hg) fun g r => ?_ · simpa using hsmul 0 (of k G (Multiplicative.ofAdd 0)) (hM 0) · convert hsmul r (of k G (Multiplicative.ofAdd g)) (hM g) - -- Porting note: Was `simp only`. - rw [of_apply, toAdd_ofAdd, smul_single', mul_one] + simp /-- If `f : G → H` is an additive homomorphism between two additive monoids, then `Finsupp.mapDomain f` is a ring homomorphism between their add monoid algebras. -/ @@ -1360,8 +1468,7 @@ section Algebra def singleZeroRingHom [Semiring k] [AddMonoid G] : k →+* k[G] := { Finsupp.singleAddHom 0 with map_one' := rfl - -- Porting note (#10691): Was `rw`. - map_mul' := fun x y => by simp only [singleAddHom, single_mul_single, zero_add] } + map_mul' := fun x y => by simp only [Finsupp.singleAddHom, single_mul_single, zero_add] } /-- If two ring homomorphisms from `k[G]` are equal on all `single a 1` and `single 0 b`, then they are equal. -/ @@ -1399,7 +1506,7 @@ protected noncomputable def opRingEquiv [AddCommMonoid G] : rw [Equiv.toFun_as_coe, AddEquiv.toEquiv_eq_coe]; erw [AddEquiv.coe_toEquiv] rw [← AddEquiv.coe_toAddMonoidHom] refine Iff.mpr (AddMonoidHom.map_mul_iff (R := k[G]ᵐᵒᵖ) (S := kᵐᵒᵖ[G]) _) ?_ - -- Porting note: Was `ext`. + -- Porting note (#11041): Was `ext`. refine AddMonoidHom.mul_op_ext _ _ <| addHom_ext' fun i₁ => AddMonoidHom.ext fun r₁ => AddMonoidHom.mul_op_ext _ _ <| addHom_ext' fun i₂ => AddMonoidHom.ext fun r₂ => ?_ -- Porting note: `reducible` cannot be `local` so proof gets long. @@ -1408,15 +1515,15 @@ protected noncomputable def opRingEquiv [AddCommMonoid G] : erw [AddEquiv.trans_apply, AddEquiv.trans_apply, AddEquiv.trans_apply, MulOpposite.opAddEquiv_symm_apply]; rw [MulOpposite.unop_mul (α := k[G])] dsimp - -- This was not needed before leanprover/lean4#2644 - erw [mapRange_single, single_mul_single, mapRange_single, mapRange_single] + rw [mapRange_single, single_mul_single, mapRange_single, mapRange_single] simp only [mapRange_single, single_mul_single, ← op_mul, add_comm] } --- @[simp] -- Porting note (#10618): simp can prove this +-- @[simp] -- Porting note (#10618): simp can prove this. +-- More specifically, the LHS simplifies to `Finsupp.single`, which implies there's some +-- defeq abuse going on. theorem opRingEquiv_single [AddCommMonoid G] (r : k) (x : G) : AddMonoidAlgebra.opRingEquiv (op (single x r)) = single x (op r) := by simp --- @[simp] -- Porting note (#10618): simp can prove this theorem opRingEquiv_symm_single [AddCommMonoid G] (r : kᵐᵒᵖ) (x : Gᵐᵒᵖ) : AddMonoidAlgebra.opRingEquiv.symm (single x r) = op (single x r.unop) := by simp @@ -1440,3 +1547,5 @@ theorem prod_single [CommSemiring k] [AddCommMonoid G] {s : Finset ι} {a : ι end end AddMonoidAlgebra + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Algebra/MonoidAlgebra/Degree.lean b/Mathlib/Algebra/MonoidAlgebra/Degree.lean index 4546eb21d1d13..16c11daef0708 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Degree.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Degree.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.MonoidAlgebra.Support import Mathlib.Order.Filter.Extr @@ -93,9 +94,8 @@ end ExplicitDegrees section AddOnly -variable [Add A] [Add B] [Add T] [CovariantClass B B (· + ·) (· ≤ ·)] - [CovariantClass B B (Function.swap (· + ·)) (· ≤ ·)] [CovariantClass T T (· + ·) (· ≤ ·)] - [CovariantClass T T (Function.swap (· + ·)) (· ≤ ·)] +variable [Add A] [Add B] [Add T] [AddLeftMono B] [AddRightMono B] + [AddLeftMono T] [AddRightMono T] theorem sup_support_mul_le {degb : A → B} (degbm : ∀ {a b}, degb (a + b) ≤ degb a + degb b) (f g : R[A]) : @@ -113,9 +113,8 @@ end AddOnly section AddMonoids -variable [AddMonoid A] [AddMonoid B] [CovariantClass B B (· + ·) (· ≤ ·)] - [CovariantClass B B (Function.swap (· + ·)) (· ≤ ·)] [AddMonoid T] - [CovariantClass T T (· + ·) (· ≤ ·)] [CovariantClass T T (Function.swap (· + ·)) (· ≤ ·)] +variable [AddMonoid A] [AddMonoid B] [AddLeftMono B] [AddRightMono B] + [AddMonoid T] [AddLeftMono T] [AddRightMono T] {degb : A → B} {degt : A → T} theorem sup_support_list_prod_le (degb0 : degb 0 ≤ 0) @@ -159,9 +158,8 @@ end Semiring section CommutativeLemmas -variable [CommSemiring R] [AddCommMonoid A] [AddCommMonoid B] [CovariantClass B B (· + ·) (· ≤ ·)] - [CovariantClass B B (Function.swap (· + ·)) (· ≤ ·)] [AddCommMonoid T] - [CovariantClass T T (· + ·) (· ≤ ·)] [CovariantClass T T (Function.swap (· + ·)) (· ≤ ·)] +variable [CommSemiring R] [AddCommMonoid A] [AddCommMonoid B] [AddLeftMono B] [AddRightMono B] + [AddCommMonoid T] [AddLeftMono T] [AddRightMono T] {degb : A → B} {degt : A → T} theorem sup_support_multiset_prod_le (degb0 : degb 0 ≤ 0) @@ -285,13 +283,13 @@ theorem supDegree_eq_of_max {b : B} (hb : b ∈ Set.range D) (hmem : D.invFun b variable [Add B] theorem supDegree_mul_le (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) - [CovariantClass B B (· + ·) (· ≤ ·)] [CovariantClass B B (Function.swap (· + ·)) (· ≤ ·)] : + [AddLeftMono B] [AddRightMono B] : (p * q).supDegree D ≤ p.supDegree D + q.supDegree D := sup_support_mul_le (fun {_ _} => (hadd _ _).le) p q theorem supDegree_prod_le {R A B : Type*} [CommSemiring R] [AddCommMonoid A] [AddCommMonoid B] [SemilatticeSup B] [OrderBot B] - [CovariantClass B B (· + ·) (· ≤ ·)] [CovariantClass B B (Function.swap (· + ·)) (· ≤ ·)] + [AddLeftMono B] [AddRightMono B] {D : A → B} (hzero : D 0 = 0) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) {ι} {s : Finset ι} {f : ι → R[A]} : (∏ i ∈ s, f i).supDegree D ≤ ∑ i ∈ s, (f i).supDegree D := by @@ -304,7 +302,7 @@ theorem supDegree_prod_le {R A B : Type*} [CommSemiring R] [AddCommMonoid A] [Ad exact (supDegree_mul_le hadd).trans (add_le_add_left ih _) theorem apply_add_of_supDegree_le (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) - [CovariantClass B B (· + ·) (· < ·)] [CovariantClass B B (Function.swap (· + ·)) (· < ·)] + [AddLeftStrictMono B] [AddRightStrictMono B] (hD : D.Injective) {ap aq : A} (hp : p.supDegree D ≤ D ap) (hq : q.supDegree D ≤ D aq) : (p * q) (ap + aq) = p ap * q aq := by classical @@ -317,7 +315,7 @@ theorem apply_add_of_supDegree_le (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) · refine fun a ha hne => Finset.sum_eq_zero (fun a' ha' => if_neg <| fun he => ?_) apply_fun D at he simp_rw [hadd] at he - have := covariantClass_le_of_lt B B (· + ·) + have := addLeftMono_of_addLeftStrictMono B exact (add_lt_add_of_lt_of_le (((Finset.le_sup ha).trans hp).lt_of_ne <| hD.ne_iff.2 hne) <| (Finset.le_sup ha').trans hq).ne he · refine fun h => Finset.sum_eq_zero (fun a _ => ite_eq_right_iff.mpr <| fun _ => ?_) @@ -459,7 +457,7 @@ lemma sum_ne_zero_of_injOn_supDegree (hs : s ≠ ∅) sum_ne_zero_of_injOn_supDegree' ⟨i, hi, hf i hi⟩ hd variable [Add B] -variable [CovariantClass B B (· + ·) (· < ·)] [CovariantClass B B (Function.swap (· + ·)) (· < ·)] +variable [AddLeftStrictMono B] [AddRightStrictMono B] lemma apply_supDegree_add_supDegree (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) : (p * q) (D.invFun (p.supDegree D + q.supDegree D)) = p.leadingCoeff D * q.leadingCoeff D := by @@ -545,7 +543,7 @@ lemma Monic.mul section AddMonoid variable {A B : Type*} [AddMonoid A] [AddMonoid B] [LinearOrder B] [OrderBot B] - [CovariantClass B B (· + ·) (· < ·)] [CovariantClass B B (Function.swap (· + ·)) (· < ·)] + [AddLeftStrictMono B] [AddRightStrictMono B] {D : A → B} {p : R[A]} {n : ℕ} lemma Monic.pow @@ -592,9 +590,7 @@ theorem infDegree_withTop_some_comp {s : AddMonoidAlgebra R A} (hs : s.support.N unfold AddMonoidAlgebra.infDegree rw [← Finset.coe_inf' hs, Finset.inf'_eq_inf] -theorem le_infDegree_mul - [AddZeroClass A] [Add T] - [CovariantClass T T (· + ·) (· ≤ ·)] [CovariantClass T T (Function.swap (· + ·)) (· ≤ ·)] +theorem le_infDegree_mul [AddZeroClass A] [Add T] [AddLeftMono T] [AddRightMono T] (D : AddHom A T) (f g : R[A]) : f.infDegree D + g.infDegree D ≤ (f * g).infDegree D := le_inf_support_mul (fun {a b : A} => (map_add D a b).ge) _ _ diff --git a/Mathlib/Algebra/MonoidAlgebra/Division.lean b/Mathlib/Algebra/MonoidAlgebra/Division.lean index 3eb1337dc2017..6ed612e48a0a5 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Division.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Division.lean @@ -69,14 +69,14 @@ theorem zero_divOf (g : G) : (0 : k[G]) /ᵒᶠ g = 0 := @[simp] theorem divOf_zero (x : k[G]) : x /ᵒᶠ 0 = x := by - refine Finsupp.ext fun _ => ?_ -- Porting note: `ext` doesn't work + refine Finsupp.ext fun _ => ?_ -- Porting note (#11041): `ext` doesn't work simp only [AddMonoidAlgebra.divOf_apply, zero_add] theorem add_divOf (x y : k[G]) (g : G) : (x + y) /ᵒᶠ g = x /ᵒᶠ g + y /ᵒᶠ g := map_add (Finsupp.comapDomain.addMonoidHom _) _ _ theorem divOf_add (x : k[G]) (a b : G) : x /ᵒᶠ (a + b) = x /ᵒᶠ a /ᵒᶠ b := by - refine Finsupp.ext fun _ => ?_ -- Porting note: `ext` doesn't work + refine Finsupp.ext fun _ => ?_ -- Porting note (#11041): `ext` doesn't work simp only [AddMonoidAlgebra.divOf_apply, add_assoc] /-- A bundled version of `AddMonoidAlgebra.divOf`. -/ @@ -93,13 +93,13 @@ noncomputable def divOfHom : Multiplicative G →* AddMonoid.End k[G] where (divOf_add _ _ _) theorem of'_mul_divOf (a : G) (x : k[G]) : of' k G a * x /ᵒᶠ a = x := by - refine Finsupp.ext fun _ => ?_ -- Porting note: `ext` doesn't work + refine Finsupp.ext fun _ => ?_ -- Porting note (#11041): `ext` doesn't work rw [AddMonoidAlgebra.divOf_apply, of'_apply, single_mul_apply_aux, one_mul] intro c exact add_right_inj _ theorem mul_of'_divOf (x : k[G]) (a : G) : x * of' k G a /ᵒᶠ a = x := by - refine Finsupp.ext fun _ => ?_ -- Porting note: `ext` doesn't work + refine Finsupp.ext fun _ => ?_ -- Porting note (#11041): `ext` doesn't work rw [AddMonoidAlgebra.divOf_apply, of'_apply, mul_single_apply_aux, mul_one] intro c rw [add_comm] @@ -129,19 +129,18 @@ theorem modOf_apply_of_exists_add (x : k[G]) (g : G) (g' : G) theorem modOf_apply_add_self (x : k[G]) (g : G) (d : G) : (x %ᵒᶠ g) (d + g) = 0 := modOf_apply_of_exists_add _ _ _ ⟨_, add_comm _ _⟩ --- @[simp] -- Porting note (#10618): simp can prove this theorem modOf_apply_self_add (x : k[G]) (g : G) (d : G) : (x %ᵒᶠ g) (g + d) = 0 := modOf_apply_of_exists_add _ _ _ ⟨_, rfl⟩ theorem of'_mul_modOf (g : G) (x : k[G]) : of' k G g * x %ᵒᶠ g = 0 := by - refine Finsupp.ext fun g' => ?_ -- Porting note: `ext g'` doesn't work + refine Finsupp.ext fun g' => ?_ -- Porting note (#11041): `ext g'` doesn't work rw [Finsupp.zero_apply] obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d) · rw [modOf_apply_self_add] · rw [modOf_apply_of_not_exists_add _ _ _ h, of'_apply, single_mul_apply_of_not_exists_add _ _ h] theorem mul_of'_modOf (x : k[G]) (g : G) : x * of' k G g %ᵒᶠ g = 0 := by - refine Finsupp.ext fun g' => ?_ -- Porting note: `ext g'` doesn't work + refine Finsupp.ext fun g' => ?_ -- Porting note (#11041): `ext g'` doesn't work rw [Finsupp.zero_apply] obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d) · rw [modOf_apply_self_add] @@ -153,7 +152,7 @@ theorem of'_modOf (g : G) : of' k G g %ᵒᶠ g = 0 := by theorem divOf_add_modOf (x : k[G]) (g : G) : of' k G g * (x /ᵒᶠ g) + x %ᵒᶠ g = x := by - refine Finsupp.ext fun g' => ?_ -- Porting note: `ext` doesn't work + refine Finsupp.ext fun g' => ?_ -- Porting note (#11041): `ext` doesn't work rw [Finsupp.add_apply] -- Porting note: changed from `simp_rw` which can't see through the type obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d) swap diff --git a/Mathlib/Algebra/MonoidAlgebra/Grading.lean b/Mathlib/Algebra/MonoidAlgebra/Grading.lean index e13d03a50b709..86426ba1b8376 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Grading.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Grading.lean @@ -48,7 +48,7 @@ abbrev gradeBy (f : M → ι) (i : ι) : Submodule R R[M] where zero_mem' m h := by cases h add_mem' {a b} ha hb m h := by classical exact (Finset.mem_union.mp (Finsupp.support_add h)).elim (ha m) (hb m) - smul_mem' a m h := Set.Subset.trans Finsupp.support_smul h + smul_mem' _ _ h := Set.Subset.trans Finsupp.support_smul h /-- The submodule corresponding to each grade. -/ abbrev grade (m : M) : Submodule R R[M] := @@ -132,7 +132,7 @@ theorem decomposeAux_single (m : M) (r : R) : refine (DirectSum.of_smul R _ _ _).symm.trans ?_ apply DirectSum.of_eq_of_gradedMonoid_eq refine Sigma.subtype_ext rfl ?_ - refine (Finsupp.smul_single' _ _ _).trans ?_ + refine (smul_single' _ _ _).trans ?_ rw [mul_one] rfl diff --git a/Mathlib/Algebra/MonoidAlgebra/Ideal.lean b/Mathlib/Algebra/MonoidAlgebra/Ideal.lean index 65393744fc7ce..a7249d132bff9 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Ideal.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Ideal.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ -import Mathlib.RingTheory.Ideal.Basic import Mathlib.Algebra.MonoidAlgebra.Defs +import Mathlib.RingTheory.Ideal.Span /-! # Lemmas about ideals of `MonoidAlgebra` and `AddMonoidAlgebra` diff --git a/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean b/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean index 111fe27da2293..9f6803f7cbf49 100644 --- a/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean +++ b/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean @@ -129,24 +129,28 @@ theorem toDirectSum_mul [DecidableEq ι] [AddMonoid ι] [Semiring M] (f g : AddM let _ : NonUnitalNonAssocSemiring (ι →₀ M) := AddMonoidAlgebra.nonUnitalNonAssocSemiring revert f g rw [AddMonoidHom.map_mul_iff] - -- Porting note: does not find `addHom_ext'`, was `ext (xi xv yi yv) : 4` + -- Porting note (#11041): does not find `addHom_ext'`, was `ext (xi xv yi yv) : 4` refine Finsupp.addHom_ext' fun xi => AddMonoidHom.ext fun xv => ?_ refine Finsupp.addHom_ext' fun yi => AddMonoidHom.ext fun yv => ?_ dsimp only [AddMonoidHom.comp_apply, AddMonoidHom.compl₂_apply, AddMonoidHom.compr₂_apply, AddMonoidHom.mul_apply, Finsupp.singleAddHom_apply] -- This was not needed before leanprover/lean4#2644 erw [AddMonoidHom.compl₂_apply] + -- If we remove the next `rw`, the `erw` after it will complain (when we get an `erw` linter) + -- that it could be a `rw`. But the `erw` and `rw` will rewrite different occurrences. + -- So first get rid of the `rw`-able occurrences to force `erw` to do the expensive rewrite only. + rw [AddMonoidHom.coe_mk, AddMonoidHom.coe_mk] -- This was not needed before leanprover/lean4#2644 erw [AddMonoidHom.coe_mk] simp only [AddMonoidHom.coe_mk, ZeroHom.coe_mk, toDirectSum_single] -- This was not needed before leanprover/lean4#2644 dsimp - erw [AddMonoidAlgebra.single_mul_single, AddMonoidHom.coe_mk, ZeroHom.coe_mk, + rw [AddMonoidAlgebra.single_mul_single, AddMonoidHom.coe_mk, AddMonoidHom.coe_mk, ZeroHom.coe_mk, AddMonoidAlgebra.toDirectSum_single] simp only [AddMonoidHom.coe_comp, AddMonoidHom.coe_mul, AddMonoidHom.coe_mk, ZeroHom.coe_mk, Function.comp_apply, toDirectSum_single, AddMonoidHom.id_apply, Finsupp.singleAddHom_apply, AddMonoidHom.coe_mulLeft] - erw [DirectSum.of_mul_of, Mul.gMul_mul] + rw [DirectSum.of_mul_of, Mul.gMul_mul] end AddMonoidAlgebra diff --git a/Mathlib/Algebra/MvPolynomial/Basic.lean b/Mathlib/Algebra/MvPolynomial/Basic.lean index 722c1bdf7b69a..93c6613dfbc95 100644 --- a/Mathlib/Algebra/MvPolynomial/Basic.lean +++ b/Mathlib/Algebra/MvPolynomial/Basic.lean @@ -155,7 +155,7 @@ variable [CommSemiring R] [CommSemiring S₁] {p q : MvPolynomial σ R} /-- `monomial s a` is the monomial with coefficient `a` and exponents given by `s` -/ def monomial (s : σ →₀ ℕ) : R →ₗ[R] MvPolynomial σ R := - lsingle s + AddMonoidAlgebra.lsingle s theorem single_eq_monomial (s : σ →₀ ℕ) (a : R) : Finsupp.single s a = monomial s a := rfl @@ -191,10 +191,10 @@ theorem monomial_left_inj {s t : σ →₀ ℕ} {r : R} (hr : r ≠ 0) : theorem C_apply : (C a : MvPolynomial σ R) = monomial 0 a := rfl --- Porting note (#10618): `simp` can prove this +@[simp] theorem C_0 : C 0 = (0 : MvPolynomial σ R) := map_zero _ --- Porting note (#10618): `simp` can prove this +@[simp] theorem C_1 : C 1 = (1 : MvPolynomial σ R) := rfl @@ -203,15 +203,15 @@ theorem C_mul_monomial : C a * monomial s a' = monomial s (a * a') := by show AddMonoidAlgebra.single _ _ * AddMonoidAlgebra.single _ _ = AddMonoidAlgebra.single _ _ simp [C_apply, single_mul_single] --- Porting note (#10618): `simp` can prove this +@[simp] theorem C_add : (C (a + a') : MvPolynomial σ R) = C a + C a' := Finsupp.single_add _ _ _ --- Porting note (#10618): `simp` can prove this +@[simp] theorem C_mul : (C (a * a') : MvPolynomial σ R) = C a * C a' := C_mul_monomial.symm --- Porting note (#10618): `simp` can prove this +@[simp] theorem C_pow (a : R) (n : ℕ) : (C (a ^ n) : MvPolynomial σ R) = C a ^ n := map_pow _ _ _ @@ -303,7 +303,7 @@ theorem C_mul_X_pow_eq_monomial {s : σ} {a : R} {n : ℕ} : theorem C_mul_X_eq_monomial {s : σ} {a : R} : C a * X s = monomial (Finsupp.single s 1) a := by rw [← C_mul_X_pow_eq_monomial, pow_one] --- Porting note (#10618): `simp` can prove this +@[simp] theorem monomial_zero {s : σ →₀ ℕ} : monomial s (0 : R) = 0 := Finsupp.single_zero _ @@ -373,7 +373,7 @@ theorem induction_on' {P : MvPolynomial σ R → Prop} (p : MvPolynomial σ R) Finsupp.induction p (suffices P (monomial 0 0) by rwa [monomial_zero] at this show P (monomial 0 0) from h1 0 0) - fun a b f _ha _hb hPf => h2 _ _ (h1 _ _) hPf + fun _ _ _ _ha _hb hPf => h2 _ _ (h1 _ _) hPf /-- Similar to `MvPolynomial.induction_on` but only a weak form of `h_add` is required. -/ theorem induction_on''' {M : MvPolynomial σ R → Prop} (p : MvPolynomial σ R) (h_C : ∀ a, M (C a)) @@ -404,12 +404,12 @@ theorem induction_on {M : MvPolynomial σ R → Prop} (p : MvPolynomial σ R) (h theorem ringHom_ext {A : Type*} [Semiring A] {f g : MvPolynomial σ R →+* A} (hC : ∀ r, f (C r) = g (C r)) (hX : ∀ i, f (X i) = g (X i)) : f = g := by refine AddMonoidAlgebra.ringHom_ext' ?_ ?_ - -- Porting note: this has high priority, but Lean still chooses `RingHom.ext`, why? + -- Porting note (#11041): this has high priority, but Lean still chooses `RingHom.ext`, why? -- probably because of the type synonym · ext x exact hC _ · apply Finsupp.mulHom_ext'; intros x - -- Porting note: `Finsupp.mulHom_ext'` needs to have increased priority + -- Porting note (#11041): `Finsupp.mulHom_ext'` needs to have increased priority apply MonoidHom.ext_mnat exact hX _ @@ -509,8 +509,6 @@ section Coeff /-- The coefficient of the monomial `m` in the multi-variable polynomial `p`. -/ def coeff (m : σ →₀ ℕ) (p : MvPolynomial σ R) : R := @DFunLike.coe ((σ →₀ ℕ) →₀ R) _ _ _ p m - -- Porting note: I changed this from `@CoeFun.coe _ _ (MonoidAlgebra.coeFun _ _) p m` because - -- I think it should work better syntactically. They are defeq. @[simp] theorem mem_support_iff {p : MvPolynomial σ R} {m : σ →₀ ℕ} : m ∈ p.support ↔ p.coeff m ≠ 0 := by @@ -691,7 +689,7 @@ theorem coeff_mul_monomial' (m) (s : σ →₀ ℕ) (r : R) (p : MvPolynomial σ · contrapose! h rw [← mem_support_iff] at h obtain ⟨j, -, rfl⟩ : ∃ j ∈ support p, j + s = m := by - simpa [Finset.add_singleton] + simpa [Finset.mem_add] using Finset.add_subset_add_left support_monomial_subset <| support_mul _ _ h exact le_add_left le_rfl diff --git a/Mathlib/Algebra/MvPolynomial/CommRing.lean b/Mathlib/Algebra/MvPolynomial/CommRing.lean index 71f9d8c13a24d..fc473489090b6 100644 --- a/Mathlib/Algebra/MvPolynomial/CommRing.lean +++ b/Mathlib/Algebra/MvPolynomial/CommRing.lean @@ -55,11 +55,11 @@ instance instCommRingMvPolynomial : CommRing (MvPolynomial σ R) := variable (σ a a') --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem C_sub : (C (a - a') : MvPolynomial σ R) = C a - C a' := RingHom.map_sub _ _ _ --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem C_neg : (C (-a) : MvPolynomial σ R) = -C a := RingHom.map_neg _ _ @@ -151,7 +151,7 @@ functions out of the type `σ`, -/ def homEquiv : (MvPolynomial σ ℤ →+* S) ≃ (σ → S) where toFun f := f ∘ X invFun f := eval₂Hom (Int.castRingHom S) f - left_inv f := RingHom.ext <| eval₂Hom_X _ _ + left_inv _ := RingHom.ext <| eval₂Hom_X _ _ right_inv f := funext fun x => by simp only [coe_eval₂Hom, Function.comp_apply, eval₂_X] end Eval diff --git a/Mathlib/Algebra/MvPolynomial/Derivation.lean b/Mathlib/Algebra/MvPolynomial/Derivation.lean index 49d6860a55c77..1d88e3c8c50e2 100644 --- a/Mathlib/Algebra/MvPolynomial/Derivation.lean +++ b/Mathlib/Algebra/MvPolynomial/Derivation.lean @@ -45,7 +45,7 @@ theorem mkDerivationₗ_C (f : σ → A) (r : R) : mkDerivationₗ R f (C r) = 0 (mkDerivationₗ_monomial f _ _).trans (smul_zero _) theorem mkDerivationₗ_X (f : σ → A) (i : σ) : mkDerivationₗ R f (X i) = f i := - (mkDerivationₗ_monomial f _ _).trans <| by simp + (mkDerivationₗ_monomial f _ _).trans <| by simp [tsub_self] @[simp] theorem derivation_C (D : Derivation R (MvPolynomial σ R) A) (a : R) : D (C a) = 0 := diff --git a/Mathlib/Algebra/MvPolynomial/Expand.lean b/Mathlib/Algebra/MvPolynomial/Expand.lean index 8b06a208a6ea6..1252dd9b13b66 100644 --- a/Mathlib/Algebra/MvPolynomial/Expand.lean +++ b/Mathlib/Algebra/MvPolynomial/Expand.lean @@ -29,7 +29,6 @@ noncomputable def expand (p : ℕ) : MvPolynomial σ R →ₐ[R] MvPolynomial σ { (eval₂Hom C fun i ↦ X i ^ p : MvPolynomial σ R →+* MvPolynomial σ R) with commutes' := fun _ ↦ eval₂Hom_C _ _ _ } --- @[simp] -- Porting note (#10618): simp can prove this theorem expand_C (p : ℕ) (r : R) : expand p (C r : MvPolynomial σ R) = C r := eval₂Hom_C _ _ _ diff --git a/Mathlib/Algebra/MvPolynomial/Monad.lean b/Mathlib/Algebra/MvPolynomial/Monad.lean index ac7de02a758d8..aa9516b1d70fd 100644 --- a/Mathlib/Algebra/MvPolynomial/Monad.lean +++ b/Mathlib/Algebra/MvPolynomial/Monad.lean @@ -268,8 +268,7 @@ theorem aeval_bind₂ [Algebra S T] (f : σ → T) (g : R →+* MvPolynomial σ aeval f (bind₂ g φ) = eval₂Hom ((↑(aeval f : _ →ₐ[S] _) : _ →+* _).comp g) f φ := eval₂Hom_bind₂ _ _ _ _ -theorem eval₂Hom_C_left (f : σ → MvPolynomial τ R) : eval₂Hom C f = bind₁ f := - rfl +alias eval₂Hom_C_left := eval₂Hom_C_eq_bind₁ theorem bind₁_monomial (f : σ → MvPolynomial τ R) (d : σ →₀ ℕ) (r : R) : bind₁ f (monomial d r) = C r * ∏ i ∈ d.support, f i ^ d i := by diff --git a/Mathlib/Algebra/MvPolynomial/PDeriv.lean b/Mathlib/Algebra/MvPolynomial/PDeriv.lean index 2f36da703dccd..9c6e2c3c43e7c 100644 --- a/Mathlib/Algebra/MvPolynomial/PDeriv.lean +++ b/Mathlib/Algebra/MvPolynomial/PDeriv.lean @@ -79,7 +79,7 @@ theorem pderiv_one {i : σ} : pderiv i (1 : MvPolynomial σ R) = 0 := pderiv_C @[simp] theorem pderiv_X [DecidableEq σ] (i j : σ) : - pderiv i (X j : MvPolynomial σ R) = Pi.single (f := fun j => _) i 1 j := by + pderiv i (X j : MvPolynomial σ R) = Pi.single (f := fun _ => _) i 1 j := by rw [pderiv_def, mkDerivation_X] @[simp] @@ -104,7 +104,6 @@ theorem pderiv_pow {i : σ} {f : MvPolynomial σ R} {n : ℕ} : pderiv i (f ^ n) = n * f ^ (n - 1) * pderiv i f := by rw [(pderiv i).leibniz_pow f n, nsmul_eq_mul, smul_eq_mul, mul_assoc] --- @[simp] -- Porting note (#10618): simp can prove this theorem pderiv_C_mul {f : MvPolynomial σ R} {i : σ} : pderiv i (C a * f) = C a * pderiv i f := by rw [C_mul', Derivation.map_smul, C_mul'] diff --git a/Mathlib/Algebra/NoZeroSMulDivisors/Basic.lean b/Mathlib/Algebra/NoZeroSMulDivisors/Basic.lean new file mode 100644 index 0000000000000..c4b95955f40ac --- /dev/null +++ b/Mathlib/Algebra/NoZeroSMulDivisors/Basic.lean @@ -0,0 +1,156 @@ +/- +Copyright (c) 2015 Nathaniel Thomas. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anne Baanen, Yury Kudryashov, Joseph Myers, Heather Macbeth, Kim Morrison, Yaël Dillies +-/ +import Mathlib.Algebra.GroupWithZero.Action.Units +import Mathlib.Algebra.Module.End +import Mathlib.Algebra.NoZeroSMulDivisors.Defs + +/-! +# `NoZeroSMulDivisors` + +This file defines the `NoZeroSMulDivisors` class, and includes some tests +for the vanishing of elements (especially in modules over division rings). +-/ + +assert_not_exists Multiset +assert_not_exists Set.indicator +assert_not_exists Pi.single_smul₀ +assert_not_exists Field + +section NoZeroSMulDivisors + +variable {R M : Type*} + +section Module + +section Nat + +theorem Nat.noZeroSMulDivisors + (R) (M) [Semiring R] [CharZero R] [AddCommMonoid M] [Module R M] [NoZeroSMulDivisors R M] : + NoZeroSMulDivisors ℕ M where + eq_zero_or_eq_zero_of_smul_eq_zero {c x} := by rw [← Nat.cast_smul_eq_nsmul R, smul_eq_zero]; simp + +theorem two_nsmul_eq_zero + (R) (M) [Semiring R] [CharZero R] [AddCommMonoid M] [Module R M] [NoZeroSMulDivisors R M] + {v : M} : 2 • v = 0 ↔ v = 0 := by + haveI := Nat.noZeroSMulDivisors R M + simp [smul_eq_zero] + +end Nat + +variable [Semiring R] +variable (R M) + +/-- If `M` is an `R`-module with one and `M` has characteristic zero, then `R` has characteristic +zero as well. Usually `M` is an `R`-algebra. -/ +theorem CharZero.of_module (M) [AddCommMonoidWithOne M] [CharZero M] [Module R M] : CharZero R := by + refine ⟨fun m n h => @Nat.cast_injective M _ _ _ _ ?_⟩ + rw [← nsmul_one, ← nsmul_one, ← Nat.cast_smul_eq_nsmul R, ← Nat.cast_smul_eq_nsmul R, h] + +end Module + +section AddCommGroup + +-- `R` can still be a semiring here +variable [Semiring R] [AddCommGroup M] [Module R M] + +section SMulInjective + +variable (M) + +theorem smul_right_injective [NoZeroSMulDivisors R M] {c : R} (hc : c ≠ 0) : + Function.Injective (c • · : M → M) := + (injective_iff_map_eq_zero (smulAddHom R M c)).2 fun _ ha => (smul_eq_zero.mp ha).resolve_left hc + +variable {M} + +theorem smul_right_inj [NoZeroSMulDivisors R M] {c : R} (hc : c ≠ 0) {x y : M} : + c • x = c • y ↔ x = y := + (smul_right_injective M hc).eq_iff + +end SMulInjective + +section Nat + +theorem self_eq_neg + (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] + {v : M} : v = -v ↔ v = 0 := by + rw [← two_nsmul_eq_zero R M, two_smul, add_eq_zero_iff_eq_neg] + +theorem neg_eq_self + (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] + {v : M} : -v = v ↔ v = 0 := by + rw [eq_comm, self_eq_neg R M] + +theorem self_ne_neg + (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] + {v : M} : v ≠ -v ↔ v ≠ 0 := + (self_eq_neg R M).not + +theorem neg_ne_self + (R) (M) [Semiring R] [CharZero R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] + {v : M} : -v ≠ v ↔ v ≠ 0 := + (neg_eq_self R M).not + +end Nat + +end AddCommGroup + +section Module + +variable [Ring R] [AddCommGroup M] [Module R M] + +section SMulInjective + +variable (R) +variable [NoZeroSMulDivisors R M] + +theorem smul_left_injective {x : M} (hx : x ≠ 0) : Function.Injective fun c : R => c • x := + fun c d h => + sub_eq_zero.mp + ((smul_eq_zero.mp + (calc + (c - d) • x = c • x - d • x := sub_smul c d x + _ = 0 := sub_eq_zero.mpr h + )).resolve_right + hx) + +end SMulInjective + +instance [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := + ⟨fun {c x} hcx ↦ by rwa [← Nat.cast_smul_eq_nsmul ℤ, smul_eq_zero, Nat.cast_eq_zero] at hcx⟩ + +variable (R M) + +theorem NoZeroSMulDivisors.int_of_charZero + (R) (M) [Ring R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] [CharZero R] : + NoZeroSMulDivisors ℤ M := + ⟨fun {z x} h ↦ by simpa [← smul_one_smul R z x] using h⟩ + +/-- Only a ring of characteristic zero can have a non-trivial module without additive or +scalar torsion. -/ +theorem CharZero.of_noZeroSMulDivisors [Nontrivial M] [NoZeroSMulDivisors ℤ M] : CharZero R := by + refine ⟨fun {n m h} ↦ ?_⟩ + obtain ⟨x, hx⟩ := exists_ne (0 : M) + replace h : (n : ℤ) • x = (m : ℤ) • x := by simp [← Nat.cast_smul_eq_nsmul R, h] + simpa using smul_left_injective ℤ hx h + +instance [AddCommGroup M] [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := + ⟨fun {c x} hcx ↦ by rwa [← Nat.cast_smul_eq_nsmul ℤ c x, smul_eq_zero, Nat.cast_eq_zero] at hcx⟩ + +end Module + +section GroupWithZero + +variable [GroupWithZero R] [AddMonoid M] [DistribMulAction R M] + +-- see note [lower instance priority] +/-- This instance applies to `DivisionSemiring`s, in particular `NNReal` and `NNRat`. -/ +instance (priority := 100) GroupWithZero.toNoZeroSMulDivisors : NoZeroSMulDivisors R M := + ⟨fun {a _} h ↦ or_iff_not_imp_left.2 fun ha ↦ (smul_eq_zero_iff_eq <| Units.mk0 a ha).1 h⟩ + +end GroupWithZero + +end NoZeroSMulDivisors diff --git a/Mathlib/Algebra/NoZeroSMulDivisors/Defs.lean b/Mathlib/Algebra/NoZeroSMulDivisors/Defs.lean new file mode 100644 index 0000000000000..caa70e20f08e3 --- /dev/null +++ b/Mathlib/Algebra/NoZeroSMulDivisors/Defs.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2015 Nathaniel Thomas. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anne Baanen, Yury Kudryashov, Joseph Myers, Heather Macbeth, Kim Morrison, Yaël Dillies +-/ +import Mathlib.Algebra.SMulWithZero + +/-! +# `NoZeroSMulDivisors` + +This file defines the `NoZeroSMulDivisors` class, and includes some tests +for the vanishing of elements (especially in modules over division rings). +-/ + +assert_not_exists Multiset +assert_not_exists Set.indicator +assert_not_exists Pi.single_smul₀ +assert_not_exists Field +assert_not_exists Module + +section NoZeroSMulDivisors + +/-! ### `NoZeroSMulDivisors` + +-/ + +variable {R M : Type*} + +/-- `NoZeroSMulDivisors R M` states that a scalar multiple is `0` only if either argument is `0`. +This is a version of saying that `M` is torsion free, without assuming `R` is zero-divisor free. + +The main application of `NoZeroSMulDivisors R M`, when `M` is a module, +is the result `smul_eq_zero`: a scalar multiple is `0` iff either argument is `0`. + +It is a generalization of the `NoZeroDivisors` class to heterogeneous multiplication. +-/ +@[mk_iff] +class NoZeroSMulDivisors (R M : Type*) [Zero R] [Zero M] [SMul R M] : Prop where + /-- If scalar multiplication yields zero, either the scalar or the vector was zero. -/ + eq_zero_or_eq_zero_of_smul_eq_zero : ∀ {c : R} {x : M}, c • x = 0 → c = 0 ∨ x = 0 + +export NoZeroSMulDivisors (eq_zero_or_eq_zero_of_smul_eq_zero) + +/-- Pullback a `NoZeroSMulDivisors` instance along an injective function. -/ +theorem Function.Injective.noZeroSMulDivisors {R M N : Type*} [Zero R] [Zero M] [Zero N] + [SMul R M] [SMul R N] [NoZeroSMulDivisors R N] (f : M → N) (hf : Function.Injective f) + (h0 : f 0 = 0) (hs : ∀ (c : R) (x : M), f (c • x) = c • f x) : NoZeroSMulDivisors R M := + ⟨fun {_ _} h => + Or.imp_right (@hf _ _) <| h0.symm ▸ eq_zero_or_eq_zero_of_smul_eq_zero (by rw [← hs, h, h0])⟩ + +-- See note [lower instance priority] +instance (priority := 100) NoZeroDivisors.toNoZeroSMulDivisors [Zero R] [Mul R] + [NoZeroDivisors R] : NoZeroSMulDivisors R R := + ⟨fun {_ _} => eq_zero_or_eq_zero_of_mul_eq_zero⟩ + +theorem smul_ne_zero [Zero R] [Zero M] [SMul R M] [NoZeroSMulDivisors R M] {c : R} {x : M} + (hc : c ≠ 0) (hx : x ≠ 0) : c • x ≠ 0 := fun h => + (eq_zero_or_eq_zero_of_smul_eq_zero h).elim hc hx + +section SMulWithZero + +variable [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] {c : R} {x : M} + +@[simp] +theorem smul_eq_zero : c • x = 0 ↔ c = 0 ∨ x = 0 := + ⟨eq_zero_or_eq_zero_of_smul_eq_zero, fun h => + h.elim (fun h => h.symm ▸ zero_smul R x) fun h => h.symm ▸ smul_zero c⟩ + +theorem smul_ne_zero_iff : c • x ≠ 0 ↔ c ≠ 0 ∧ x ≠ 0 := by rw [Ne, smul_eq_zero, not_or] + +lemma smul_eq_zero_iff_left (hx : x ≠ 0) : c • x = 0 ↔ c = 0 := by simp [hx] +lemma smul_eq_zero_iff_right (hc : c ≠ 0) : c • x = 0 ↔ x = 0 := by simp [hc] +lemma smul_ne_zero_iff_left (hx : x ≠ 0) : c • x ≠ 0 ↔ c ≠ 0 := by simp [hx] +lemma smul_ne_zero_iff_right (hc : c ≠ 0) : c • x ≠ 0 ↔ x ≠ 0 := by simp [hc] + +end SMulWithZero + +end NoZeroSMulDivisors diff --git a/Mathlib/Algebra/NoZeroSMulDivisors/Pi.lean b/Mathlib/Algebra/NoZeroSMulDivisors/Pi.lean new file mode 100644 index 0000000000000..ac7b42a019040 --- /dev/null +++ b/Mathlib/Algebra/NoZeroSMulDivisors/Pi.lean @@ -0,0 +1,34 @@ +/- +Copyright (c) 2018 Simon Hudon. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anne Baanen, Yaël Dillies +-/ +import Mathlib.Algebra.NoZeroSMulDivisors.Defs +import Mathlib.Algebra.Group.Action.Pi + +/-! +# Pi instances for NoZeroSMulDivisors + +This file defines instances for NoZeroSMulDivisors on Pi types. +-/ + + +universe u v + +variable {I : Type u} + +-- The indexing type +variable {f : I → Type v} + +instance Pi.noZeroSMulDivisors (α) [Zero α] [∀ i, Zero <| f i] + [∀ i, SMulWithZero α <| f i] [∀ i, NoZeroSMulDivisors α <| f i] : + NoZeroSMulDivisors α (∀ i : I, f i) := + ⟨fun {_ _} h => + or_iff_not_imp_left.mpr fun hc => + funext fun i => (smul_eq_zero.mp (congr_fun h i)).resolve_left hc⟩ + +/-- A special case of `Pi.noZeroSMulDivisors` for non-dependent types. Lean struggles to +synthesize this instance by itself elsewhere in the library. -/ +instance _root_.Function.noZeroSMulDivisors {ι α β : Type*} [Zero α] [Zero β] + [SMulWithZero α β] [NoZeroSMulDivisors α β] : NoZeroSMulDivisors α (ι → β) := + Pi.noZeroSMulDivisors _ diff --git a/Mathlib/Algebra/NoZeroSMulDivisors/Prod.lean b/Mathlib/Algebra/NoZeroSMulDivisors/Prod.lean new file mode 100644 index 0000000000000..e836979c0377a --- /dev/null +++ b/Mathlib/Algebra/NoZeroSMulDivisors/Prod.lean @@ -0,0 +1,32 @@ +/- +Copyright (c) 2018 Simon Hudon. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anne Baanen +-/ +import Mathlib.Algebra.NoZeroSMulDivisors.Defs +import Mathlib.Algebra.Group.Action.Prod + +/-! +# Prod instances for NoZeroSMulDivisors + +This file defines a NoZeroSMulDivisors instance for the binary product of actions. +-/ + +variable {R M N : Type*} + +namespace Prod + +instance noZeroSMulDivisors [Zero R] [Zero M] [Zero N] + [SMulWithZero R M] [SMulWithZero R N] [NoZeroSMulDivisors R M] [NoZeroSMulDivisors R N] : + NoZeroSMulDivisors R (M × N) := + { eq_zero_or_eq_zero_of_smul_eq_zero := by -- Porting note: in mathlib3 there is no need for `by`/ + -- `intro`/`exact`, i.e. the following works: + -- ⟨fun c ⟨x, y⟩ h => + -- or_iff_not_imp_left.mpr fun hc => + intro c ⟨x, y⟩ h + exact or_iff_not_imp_left.mpr fun hc => + mk.inj_iff.mpr + ⟨(smul_eq_zero.mp (congr_arg fst h)).resolve_left hc, + (smul_eq_zero.mp (congr_arg snd h)).resolve_left hc⟩ } + +end Prod diff --git a/Mathlib/Algebra/Notation.lean b/Mathlib/Algebra/Notation.lean new file mode 100644 index 0000000000000..ffb3097c7ba73 --- /dev/null +++ b/Mathlib/Algebra/Notation.lean @@ -0,0 +1,50 @@ +/- +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.Tactic.TypeStar +import Mathlib.Tactic.ToAdditive + +/-! +# Notations for operations involving order and algebraic structure + +## Notations + +* `a⁺ᵐ = a ⊔ 1`: *Positive component* of an element `a` of a multiplicative lattice ordered group +* `a⁻ᵐ = a⁻¹ ⊔ 1`: *Negative component* of an element `a` of a multiplicative lattice ordered group +* `a⁺ = a ⊔ 0`: *Positive component* of an element `a` of a lattice ordered group +* `a⁻ = (-a) ⊔ 0`: *Negative component* of an element `a` of a lattice ordered group +-/ + +/-- A notation class for the *positive part* function: `a⁺`. -/ +class PosPart (α : Type*) where + /-- The *positive part* of an element `a`. -/ + posPart : α → α + +/-- A notation class for the *positive part* function (multiplicative version): `a⁺ᵐ`. -/ +@[to_additive] +class OneLePart (α : Type*) where + /-- The *positive part* of an element `a`. -/ + oneLePart : α → α + +/-- A notation class for the *negative part* function: `a⁻`. -/ +class NegPart (α : Type*) where + /-- The *negative part* of an element `a`. -/ + negPart : α → α + +/-- A notation class for the *negative part* function (multiplicative version): `a⁻ᵐ`. -/ +@[to_additive] +class LeOnePart (α : Type*) where + /-- The *negative part* of an element `a`. -/ + leOnePart : α → α + +export OneLePart (oneLePart) +export LeOnePart (leOnePart) +export PosPart (posPart) +export NegPart (negPart) + +@[inherit_doc] postfix:max "⁺ᵐ " => OneLePart.oneLePart +@[inherit_doc] postfix:max "⁻ᵐ" => LeOnePart.leOnePart +@[inherit_doc] postfix:max "⁺" => PosPart.posPart +@[inherit_doc] postfix:max "⁻" => NegPart.negPart diff --git a/Mathlib/Algebra/Opposites.lean b/Mathlib/Algebra/Opposites.lean index 0fa41a147a2a7..4848307dbf92e 100644 --- a/Mathlib/Algebra/Opposites.lean +++ b/Mathlib/Algebra/Opposites.lean @@ -138,6 +138,12 @@ theorem unop_inj {x y : αᵐᵒᵖ} : unop x = unop y ↔ x = y := attribute [nolint simpComm] AddOpposite.unop_inj +@[to_additive (attr := simp)] lemma «forall» {p : αᵐᵒᵖ → Prop} : (∀ a, p a) ↔ ∀ a, p (op a) := + op_surjective.forall + +@[to_additive (attr := simp)] lemma «exists» {p : αᵐᵒᵖ → Prop} : (∃ a, p a) ↔ ∃ a, p (op a) := + op_surjective.exists + @[to_additive] instance instNontrivial [Nontrivial α] : Nontrivial αᵐᵒᵖ := op_injective.nontrivial @[to_additive] instance instInhabited [Inhabited α] : Inhabited αᵐᵒᵖ := ⟨op default⟩ diff --git a/Mathlib/Algebra/Order/AbsoluteValue.lean b/Mathlib/Algebra/Order/AbsoluteValue.lean index 0dcc6acdcfbb4..8f31d949787d9 100644 --- a/Mathlib/Algebra/Order/AbsoluteValue.lean +++ b/Mathlib/Algebra/Order/AbsoluteValue.lean @@ -77,11 +77,6 @@ def Simps.apply (f : AbsoluteValue R S) : R → S := initialize_simps_projections AbsoluteValue (toMulHom_toFun → apply) -/-- Helper instance for when there's too many metavariables to apply `DFunLike.has_coe_to_fun` -directly. -/ -instance : CoeFun (AbsoluteValue R S) fun _ => R → S := - DFunLike.hasCoeToFun - @[simp] theorem coe_toMulHom : ⇑abv.toMulHom = abv := rfl @@ -98,7 +93,7 @@ protected theorem eq_zero {x : R} : abv x = 0 ↔ x = 0 := protected theorem add_le (x y : R) : abv (x + y) ≤ abv x + abv y := abv.add_le' x y --- Porting note (#10618): was `@[simp]` but `simp` can prove it +@[simp] protected theorem map_mul (x y : R) : abv (x * y) = abv x * abv y := abv.map_mul' x y @@ -118,7 +113,7 @@ protected theorem ne_zero {x : R} (hx : x ≠ 0) : abv x ≠ 0 := theorem map_one_of_isLeftRegular (h : IsLeftRegular (abv 1)) : abv 1 = 1 := h <| by simp [← abv.map_mul] --- Porting note (#10618): was `@[simp]` but `simp` can prove it +@[simp] protected theorem map_zero : abv 0 = 0 := abv.eq_zero.2 rfl @@ -150,7 +145,7 @@ section IsDomain variable {R S : Type*} [Semiring R] [OrderedRing S] (abv : AbsoluteValue R S) variable [IsDomain S] [Nontrivial R] --- Porting note (#10618): was `@[simp]` but `simp` can prove it +@[simp] protected theorem map_one : abv 1 = 1 := abv.map_one_of_isLeftRegular (isRegular_of_ne_zero <| abv.ne_zero one_ne_zero).left @@ -175,7 +170,7 @@ def toMonoidHom : R →* S := theorem coe_toMonoidHom : ⇑abv.toMonoidHom = abv := rfl --- Porting note (#10618): was `@[simp]` but `simp` can prove it +@[simp] protected theorem map_pow (a : R) (n : ℕ) : abv (a ^ n) = abv a ^ n := abv.toMonoidHom.map_pow a n diff --git a/Mathlib/Algebra/Order/AddGroupWithTop.lean b/Mathlib/Algebra/Order/AddGroupWithTop.lean index a977f5a486e68..77246c1a05a1c 100644 --- a/Mathlib/Algebra/Order/AddGroupWithTop.lean +++ b/Mathlib/Algebra/Order/AddGroupWithTop.lean @@ -25,7 +25,7 @@ whereas it is a very common target for valuations. The solutions is to use a typeclass, and that is exactly what we do in this file. -/ -variable {α β : Type*} +variable {α : Type*} /-- A linearly ordered commutative monoid with an additively absorbing `⊤` element. Instances should include number systems with an infinite element adjoined. -/ @@ -47,7 +47,7 @@ instance WithTop.linearOrderedAddCommMonoidWithTop [LinearOrderedAddCommMonoid top_add' := WithTop.top_add } section LinearOrderedAddCommMonoidWithTop -variable [LinearOrderedAddCommMonoidWithTop α] {a b c d x y z : α} {n : ℕ} +variable [LinearOrderedAddCommMonoidWithTop α] @[simp] theorem top_add (a : α) : ⊤ + a = ⊤ := @@ -65,7 +65,7 @@ open Function namespace LinearOrderedAddCommGroup -variable [LinearOrderedAddCommGroup α] {a b c d : α} +variable [LinearOrderedAddCommGroup α] instance instNeg : Neg (WithTop α) where neg := Option.map fun a : α => -a diff --git a/Mathlib/Algebra/Order/Antidiag/Finsupp.lean b/Mathlib/Algebra/Order/Antidiag/Finsupp.lean index 05c533be79868..150ff45ab21d7 100644 --- a/Mathlib/Algebra/Order/Antidiag/Finsupp.lean +++ b/Mathlib/Algebra/Order/Antidiag/Finsupp.lean @@ -5,7 +5,6 @@ Authors: Antoine Chambert-Loir, María Inés de Frutos-Fernández, Eric Wieser, Yaël Dillies -/ import Mathlib.Algebra.Order.Antidiag.Pi -import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Data.Finsupp.Basic /-! @@ -39,7 +38,7 @@ variable [DecidableEq ι] [AddCommMonoid μ] [HasAntidiagonal μ] [DecidableEq /-- The finset of functions `ι →₀ μ` with support contained in `s` and sum equal to `n`. -/ def finsuppAntidiag (s : Finset ι) (n : μ) : Finset (ι →₀ μ) := (piAntidiag s n).attach.map ⟨fun f ↦ ⟨s.filter (f.1 · ≠ 0), f.1, by - simpa using (mem_piAntidiag.1 f.2).2⟩, fun f g hfg ↦ Subtype.ext (congr_arg (⇑) hfg)⟩ + simpa using (mem_piAntidiag.1 f.2).2⟩, fun _ _ hfg ↦ Subtype.ext (congr_arg (⇑) hfg)⟩ @[simp] lemma mem_finsuppAntidiag : f ∈ finsuppAntidiag s n ↔ s.sum f = n ∧ f.support ⊆ s := by simp [finsuppAntidiag, ← DFunLike.coe_fn_eq, subset_iff] diff --git a/Mathlib/Algebra/Order/Antidiag/Pi.lean b/Mathlib/Algebra/Order/Antidiag/Pi.lean index fea1cd40e9b83..e61fa45890bab 100644 --- a/Mathlib/Algebra/Order/Antidiag/Pi.lean +++ b/Mathlib/Algebra/Order/Antidiag/Pi.lean @@ -226,7 +226,7 @@ lemma nsmul_piAntidiag [DecidableEq (ι → ℕ)] (s : Finset ι) (m : ℕ) {n : lemma map_nsmul_piAntidiag (s : Finset ι) (m : ℕ) {n : ℕ} (hn : n ≠ 0) : (piAntidiag s m).map - ⟨(n • ·), fun f g h ↦ funext fun i ↦ mul_right_injective₀ hn (congr_fun h i)⟩ = + ⟨(n • ·), fun _ _ h ↦ funext fun i ↦ mul_right_injective₀ hn (congr_fun h i)⟩ = (piAntidiag s (n * m)).filter fun f : ι → ℕ ↦ ∀ i ∈ s, n ∣ f i := by classical rw [map_eq_image]; exact nsmul_piAntidiag _ _ hn @@ -237,7 +237,7 @@ lemma nsmul_piAntidiag_univ [Fintype ι] (m : ℕ) {n : ℕ} (hn : n ≠ 0) : lemma map_nsmul_piAntidiag_univ [Fintype ι] (m : ℕ) {n : ℕ} (hn : n ≠ 0) : (piAntidiag (univ : Finset ι) m).map - ⟨(n • ·), fun f g h ↦ funext fun i ↦ mul_right_injective₀ hn (congr_fun h i)⟩ = + ⟨(n • ·), fun _ _ h ↦ funext fun i ↦ mul_right_injective₀ hn (congr_fun h i)⟩ = (piAntidiag univ (n * m)).filter fun f : ι → ℕ ↦ ∀ i, n ∣ f i := by simpa using map_nsmul_piAntidiag (univ : Finset ι) m hn diff --git a/Mathlib/Algebra/Order/Antidiag/Prod.lean b/Mathlib/Algebra/Order/Antidiag/Prod.lean index 6f49ffaa10635..1bd46120668a9 100644 --- a/Mathlib/Algebra/Order/Antidiag/Prod.lean +++ b/Mathlib/Algebra/Order/Antidiag/Prod.lean @@ -144,7 +144,7 @@ end CanonicallyOrderedAddCommMonoid section OrderedSub variable [CanonicallyOrderedAddCommMonoid A] [Sub A] [OrderedSub A] -variable [ContravariantClass A A (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE A] variable [HasAntidiagonal A] theorem filter_fst_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] : @@ -181,7 +181,7 @@ def sigmaAntidiagonalEquivProd [AddMonoid A] [HasAntidiagonal A] : rintro ⟨n, ⟨k, l⟩, h⟩ rw [mem_antidiagonal] at h exact Sigma.subtype_ext h rfl - right_inv x := rfl + right_inv _ := rfl variable {A : Type*} [CanonicallyOrderedAddCommMonoid A] diff --git a/Mathlib/Algebra/Order/Archimedean/Basic.lean b/Mathlib/Algebra/Order/Archimedean/Basic.lean index c9b87a14420e8..fdb47f471b9bb 100644 --- a/Mathlib/Algebra/Order/Archimedean/Basic.lean +++ b/Mathlib/Algebra/Order/Archimedean/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Algebra.Order.Field.Power +import Mathlib.Algebra.Order.Ring.Pow import Mathlib.Data.Int.LeastGreatest import Mathlib.Data.Rat.Floor import Mathlib.Data.NNRat.Defs @@ -71,7 +71,7 @@ variable {M : Type*} @[to_additive] theorem exists_lt_pow [OrderedCommMonoid M] [MulArchimedean M] - [CovariantClass M M (· * ·) (· < ·)] {a : M} (ha : 1 < a) (b : M) : + [MulLeftStrictMono M] {a : M} (ha : 1 < a) (b : M) : ∃ n : ℕ, b < a ^ n := let ⟨k, hk⟩ := MulArchimedean.arch b ha ⟨k + 1, hk.trans_lt <| pow_lt_pow_right' ha k.lt_succ_self⟩ @@ -241,12 +241,12 @@ theorem exists_mem_Ico_zpow (hx : 0 < x) (hy : 1 < y) : ∃ n : ℤ, x ∈ Ico ( le_of_lt (by rw [zpow_neg y ↑N, zpow_natCast] - exact (inv_lt hx (lt_trans (inv_pos.2 hx) hN)).1 hN)⟩ + exact (inv_lt_comm₀ hx (lt_trans (inv_pos.2 hx) hN)).1 hN)⟩ let ⟨M, hM⟩ := pow_unbounded_of_one_lt x hy have hb : ∃ b : ℤ, ∀ m, y ^ m ≤ x → m ≤ b := ⟨M, fun m hm => le_of_not_lt fun hlt => - not_lt_of_ge (zpow_le_of_le hy.le hlt.le) + not_lt_of_ge (zpow_le_zpow_right₀ hy.le hlt.le) (lt_of_le_of_lt hm (by rwa [← zpow_natCast] at hM))⟩ let ⟨n, hn₁, hn₂⟩ := Int.exists_greatest_of_bdd hb he ⟨n, hn₁, lt_of_not_ge fun hge => not_le_of_gt (Int.lt_succ _) (hn₂ _ hge)⟩ @@ -257,8 +257,8 @@ but with ≤ and < the other way around. -/ theorem exists_mem_Ioc_zpow (hx : 0 < x) (hy : 1 < y) : ∃ n : ℤ, x ∈ Ioc (y ^ n) (y ^ (n + 1)) := let ⟨m, hle, hlt⟩ := exists_mem_Ico_zpow (inv_pos.2 hx) hy have hyp : 0 < y := lt_trans zero_lt_one hy - ⟨-(m + 1), by rwa [zpow_neg, inv_lt (zpow_pos_of_pos hyp _) hx], by - rwa [neg_add, neg_add_cancel_right, zpow_neg, le_inv hx (zpow_pos_of_pos hyp _)]⟩ + ⟨-(m + 1), by rwa [zpow_neg, inv_lt_comm₀ (zpow_pos hyp _) hx], by + rwa [neg_add, neg_add_cancel_right, zpow_neg, le_inv_comm₀ hx (zpow_pos hyp _)]⟩ /-- For any `y < 1` and any positive `x`, there exists `n : ℕ` with `y ^ n < x`. -/ theorem exists_pow_lt_of_lt_one (hx : 0 < x) (hy : y < 1) : ∃ n : ℕ, y ^ n < x := by @@ -267,18 +267,18 @@ theorem exists_pow_lt_of_lt_one (hx : 0 < x) (hy : y < 1) : ∃ n : ℕ, y ^ n < simp only [pow_one] exact y_pos.trans_lt hx rw [not_le] at y_pos - rcases pow_unbounded_of_one_lt x⁻¹ (one_lt_inv y_pos hy) with ⟨q, hq⟩ - exact ⟨q, by rwa [inv_pow, inv_lt_inv hx (pow_pos y_pos _)] at hq⟩ + rcases pow_unbounded_of_one_lt x⁻¹ ((one_lt_inv₀ y_pos).2 hy) with ⟨q, hq⟩ + exact ⟨q, by rwa [inv_pow, inv_lt_inv₀ hx (pow_pos y_pos _)] at hq⟩ /-- Given `x` and `y` between `0` and `1`, `x` is between two successive powers of `y`. This is the same as `exists_nat_pow_near`, but for elements between `0` and `1` -/ theorem exists_nat_pow_near_of_lt_one (xpos : 0 < x) (hx : x ≤ 1) (ypos : 0 < y) (hy : y < 1) : ∃ n : ℕ, y ^ (n + 1) < x ∧ x ≤ y ^ n := by - rcases exists_nat_pow_near (one_le_inv_iff.2 ⟨xpos, hx⟩) (one_lt_inv_iff.2 ⟨ypos, hy⟩) with + rcases exists_nat_pow_near (one_le_inv_iff₀.2 ⟨xpos, hx⟩) (one_lt_inv_iff₀.2 ⟨ypos, hy⟩) with ⟨n, hn, h'n⟩ refine ⟨n, ?_, ?_⟩ - · rwa [inv_pow, inv_lt_inv xpos (pow_pos ypos _)] at h'n - · rwa [inv_pow, inv_le_inv (pow_pos ypos _) xpos] at hn + · rwa [inv_pow, inv_lt_inv₀ xpos (pow_pos ypos _)] at h'n + · rwa [inv_pow, inv_le_inv₀ (pow_pos ypos _) xpos] at hn end LinearOrderedSemifield diff --git a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean index d5cdc6b8f86e7..67e509080c462 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean @@ -5,10 +5,9 @@ Authors: Johannes Hölzl -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Order.BigOperators.Group.Multiset +import Mathlib.Algebra.Order.Group.Nat import Mathlib.Data.Multiset.OrderedMonoid import Mathlib.Tactic.Bound.Attribute -import Mathlib.Tactic.NormNum.Basic -import Mathlib.Tactic.Positivity.Core /-! # Big operators on a finset in ordered groups @@ -17,6 +16,8 @@ This file contains the results concerning the interaction of multiset big operat groups/monoids. -/ +assert_not_exists Ring + open Function variable {ι α β M N G k R : Type*} @@ -174,38 +175,36 @@ lemma mul_le_prod {i j : ι} (hf : ∀ i ∈ s, 1 ≤ f i) (hi : i ∈ s) (hj : @[to_additive sum_le_card_nsmul] theorem prod_le_pow_card (s : Finset ι) (f : ι → N) (n : N) (h : ∀ x ∈ s, f x ≤ n) : - s.prod f ≤ n ^ s.card := by + s.prod f ≤ n ^ #s := by refine (Multiset.prod_le_pow_card (s.val.map f) n ?_).trans ?_ · simpa using h · simp @[to_additive card_nsmul_le_sum] theorem pow_card_le_prod (s : Finset ι) (f : ι → N) (n : N) (h : ∀ x ∈ s, n ≤ f x) : - n ^ s.card ≤ s.prod f := @Finset.prod_le_pow_card _ Nᵒᵈ _ _ _ _ h + n ^ #s ≤ s.prod f := @Finset.prod_le_pow_card _ Nᵒᵈ _ _ _ _ h theorem card_biUnion_le_card_mul [DecidableEq β] (s : Finset ι) (f : ι → Finset β) (n : ℕ) - (h : ∀ a ∈ s, (f a).card ≤ n) : (s.biUnion f).card ≤ s.card * n := + (h : ∀ a ∈ s, #(f a) ≤ n) : #(s.biUnion f) ≤ #s * n := card_biUnion_le.trans <| sum_le_card_nsmul _ _ _ h variable {ι' : Type*} [DecidableEq ι'] --- Porting note: Mathport warning: expanding binder collection (y «expr ∉ » t) @[to_additive sum_fiberwise_le_sum_of_sum_fiber_nonneg] theorem prod_fiberwise_le_prod_of_one_le_prod_fiber' {t : Finset ι'} {g : ι → ι'} {f : ι → N} - (h : ∀ y ∉ t, (1 : N) ≤ ∏ x ∈ s.filter fun x ↦ g x = y, f x) : - (∏ y ∈ t, ∏ x ∈ s.filter fun x ↦ g x = y, f x) ≤ ∏ x ∈ s, f x := + (h : ∀ y ∉ t, (1 : N) ≤ ∏ x ∈ s with g x = y, f x) : + (∏ y ∈ t, ∏ x ∈ s with g x = y, f x) ≤ ∏ x ∈ s, f x := calc - (∏ y ∈ t, ∏ x ∈ s.filter fun x ↦ g x = y, f x) ≤ - ∏ y ∈ t ∪ s.image g, ∏ x ∈ s.filter fun x ↦ g x = y, f x := + (∏ y ∈ t, ∏ x ∈ s with g x = y, f x) ≤ + ∏ y ∈ t ∪ s.image g, ∏ x ∈ s with g x = y, f x := prod_le_prod_of_subset_of_one_le' subset_union_left fun y _ ↦ h y _ = ∏ x ∈ s, f x := prod_fiberwise_of_maps_to (fun _ hx ↦ mem_union.2 <| Or.inr <| mem_image_of_mem _ hx) _ --- Porting note: Mathport warning: expanding binder collection (y «expr ∉ » t) @[to_additive sum_le_sum_fiberwise_of_sum_fiber_nonpos] theorem prod_le_prod_fiberwise_of_prod_fiber_le_one' {t : Finset ι'} {g : ι → ι'} {f : ι → N} - (h : ∀ y ∉ t, ∏ x ∈ s.filter fun x ↦ g x = y, f x ≤ 1) : - ∏ x ∈ s, f x ≤ ∏ y ∈ t, ∏ x ∈ s.filter fun x ↦ g x = y, f x := + (h : ∀ y ∉ t, ∏ x ∈ s with g x = y, f x ≤ 1) : + ∏ x ∈ s, f x ≤ ∏ y ∈ t, ∏ x ∈ s with g x = y, f x := @prod_fiberwise_le_prod_of_one_le_prod_fiber' _ Nᵒᵈ _ _ _ _ _ _ _ h end OrderedCommMonoid @@ -232,7 +231,7 @@ theorem abs_sum_of_nonneg' {G : Type*} [LinearOrderedAddCommGroup G] {f : ι → rw [abs_of_nonneg (Finset.sum_nonneg' hf)] section CommMonoid -variable [CommMonoid α] [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {s : Finset ι} {f : ι → α} +variable [CommMonoid α] [LE α] [MulLeftMono α] {s : Finset ι} {f : ι → α} @[to_additive (attr := simp)] lemma mulLECancellable_prod : @@ -246,27 +245,26 @@ section Pigeonhole variable [DecidableEq β] theorem card_le_mul_card_image_of_maps_to {f : α → β} {s : Finset α} {t : Finset β} - (Hf : ∀ a ∈ s, f a ∈ t) (n : ℕ) (hn : ∀ a ∈ t, (s.filter fun x ↦ f x = a).card ≤ n) : - s.card ≤ n * t.card := + (Hf : ∀ a ∈ s, f a ∈ t) (n : ℕ) (hn : ∀ b ∈ t, #{a ∈ s | f a = b} ≤ n) : #s ≤ n * #t := calc - s.card = ∑ a ∈ t, (s.filter fun x ↦ f x = a).card := card_eq_sum_card_fiberwise Hf - _ ≤ ∑ _a ∈ t, n := sum_le_sum hn + #s = ∑ b ∈ t, #{a ∈ s | f a = b} := card_eq_sum_card_fiberwise Hf + _ ≤ ∑ _b ∈ t, n := sum_le_sum hn _ = _ := by simp [mul_comm] theorem card_le_mul_card_image {f : α → β} (s : Finset α) (n : ℕ) - (hn : ∀ a ∈ s.image f, (s.filter fun x ↦ f x = a).card ≤ n) : s.card ≤ n * (s.image f).card := + (hn : ∀ b ∈ s.image f, #{a ∈ s | f a = b} ≤ n) : #s ≤ n * #(s.image f) := card_le_mul_card_image_of_maps_to (fun _ ↦ mem_image_of_mem _) n hn theorem mul_card_image_le_card_of_maps_to {f : α → β} {s : Finset α} {t : Finset β} - (Hf : ∀ a ∈ s, f a ∈ t) (n : ℕ) (hn : ∀ a ∈ t, n ≤ (s.filter fun x ↦ f x = a).card) : - n * t.card ≤ s.card := + (Hf : ∀ a ∈ s, f a ∈ t) (n : ℕ) (hn : ∀ b ∈ t, n ≤ #{a ∈ s | f a = b}) : + n * #t ≤ #s := calc - n * t.card = ∑ _a ∈ t, n := by simp [mul_comm] - _ ≤ ∑ a ∈ t, (s.filter fun x ↦ f x = a).card := sum_le_sum hn - _ = s.card := by rw [← card_eq_sum_card_fiberwise Hf] + n * #t = ∑ _a ∈ t, n := by simp [mul_comm] + _ ≤ ∑ b ∈ t, #{a ∈ s | f a = b} := sum_le_sum hn + _ = #s := by rw [← card_eq_sum_card_fiberwise Hf] theorem mul_card_image_le_card {f : α → β} (s : Finset α) (n : ℕ) - (hn : ∀ a ∈ s.image f, n ≤ (s.filter fun x ↦ f x = a).card) : n * (s.image f).card ≤ s.card := + (hn : ∀ b ∈ s.image f, n ≤ #{a ∈ s | f a = b}) : n * #(s.image f) ≤ #s := mul_card_image_le_card_of_maps_to (fun _ ↦ mem_image_of_mem _) n hn end Pigeonhole @@ -277,56 +275,52 @@ variable [DecidableEq α] {s : Finset α} {B : Finset (Finset α)} {n : ℕ} /-- If every element belongs to at most `n` Finsets, then the sum of their sizes is at most `n` times how many they are. -/ -theorem sum_card_inter_le (h : ∀ a ∈ s, (B.filter (a ∈ ·)).card ≤ n) : - (∑ t ∈ B, (s ∩ t).card) ≤ s.card * n := by +theorem sum_card_inter_le (h : ∀ a ∈ s, #{b ∈ B | a ∈ b} ≤ n) : (∑ t ∈ B, #(s ∩ t)) ≤ #s * n := by refine le_trans ?_ (s.sum_le_card_nsmul _ _ h) simp_rw [← filter_mem_eq_inter, card_eq_sum_ones, sum_filter] exact sum_comm.le /-- If every element belongs to at most `n` Finsets, then the sum of their sizes is at most `n` times how many they are. -/ -theorem sum_card_le [Fintype α] (h : ∀ a, (B.filter (a ∈ ·)).card ≤ n) : - ∑ s ∈ B, s.card ≤ Fintype.card α * n := +lemma sum_card_le [Fintype α] (h : ∀ a, #{b ∈ B | a ∈ b} ≤ n) : ∑ s ∈ B, #s ≤ Fintype.card α * n := calc - ∑ s ∈ B, s.card = ∑ s ∈ B, (univ ∩ s).card := by simp_rw [univ_inter] + ∑ s ∈ B, #s = ∑ s ∈ B, #(univ ∩ s) := by simp_rw [univ_inter] _ ≤ Fintype.card α * n := sum_card_inter_le fun a _ ↦ h a /-- If every element belongs to at least `n` Finsets, then the sum of their sizes is at least `n` times how many they are. -/ -theorem le_sum_card_inter (h : ∀ a ∈ s, n ≤ (B.filter (a ∈ ·)).card) : - s.card * n ≤ ∑ t ∈ B, (s ∩ t).card := by +theorem le_sum_card_inter (h : ∀ a ∈ s, n ≤ #{b ∈ B | a ∈ b}) : #s * n ≤ ∑ t ∈ B, #(s ∩ t) := by apply (s.card_nsmul_le_sum _ _ h).trans simp_rw [← filter_mem_eq_inter, card_eq_sum_ones, sum_filter] exact sum_comm.le /-- If every element belongs to at least `n` Finsets, then the sum of their sizes is at least `n` times how many they are. -/ -theorem le_sum_card [Fintype α] (h : ∀ a, n ≤ (B.filter (a ∈ ·)).card) : - Fintype.card α * n ≤ ∑ s ∈ B, s.card := +theorem le_sum_card [Fintype α] (h : ∀ a, n ≤ #{b ∈ B | a ∈ b}) : + Fintype.card α * n ≤ ∑ s ∈ B, #s := calc - Fintype.card α * n ≤ ∑ s ∈ B, (univ ∩ s).card := le_sum_card_inter fun a _ ↦ h a - _ = ∑ s ∈ B, s.card := by simp_rw [univ_inter] + Fintype.card α * n ≤ ∑ s ∈ B, #(univ ∩ s) := le_sum_card_inter fun a _ ↦ h a + _ = ∑ s ∈ B, #s := by simp_rw [univ_inter] /-- If every element belongs to exactly `n` Finsets, then the sum of their sizes is `n` times how many they are. -/ -theorem sum_card_inter (h : ∀ a ∈ s, (B.filter (a ∈ ·)).card = n) : - (∑ t ∈ B, (s ∩ t).card) = s.card * n := +theorem sum_card_inter (h : ∀ a ∈ s, #{b ∈ B | a ∈ b} = n) : + (∑ t ∈ B, #(s ∩ t)) = #s * n := (sum_card_inter_le fun a ha ↦ (h a ha).le).antisymm (le_sum_card_inter fun a ha ↦ (h a ha).ge) /-- If every element belongs to exactly `n` Finsets, then the sum of their sizes is `n` times how many they are. -/ -theorem sum_card [Fintype α] (h : ∀ a, (B.filter (a ∈ ·)).card = n) : - ∑ s ∈ B, s.card = Fintype.card α * n := by +theorem sum_card [Fintype α] (h : ∀ a, #{b ∈ B | a ∈ b} = n) : + ∑ s ∈ B, #s = Fintype.card α * n := by simp_rw [Fintype.card, ← sum_card_inter fun a _ ↦ h a, univ_inter] theorem card_le_card_biUnion {s : Finset ι} {f : ι → Finset α} (hs : (s : Set ι).PairwiseDisjoint f) - (hf : ∀ i ∈ s, (f i).Nonempty) : s.card ≤ (s.biUnion f).card := by + (hf : ∀ i ∈ s, (f i).Nonempty) : #s ≤ #(s.biUnion f) := by rw [card_biUnion hs, card_eq_sum_ones] exact sum_le_sum fun i hi ↦ (hf i hi).card_pos theorem card_le_card_biUnion_add_card_fiber {s : Finset ι} {f : ι → Finset α} - (hs : (s : Set ι).PairwiseDisjoint f) : - s.card ≤ (s.biUnion f).card + (s.filter fun i ↦ f i = ∅).card := by + (hs : (s : Set ι).PairwiseDisjoint f) : #s ≤ #(s.biUnion f) + #{i ∈ s | f i = ∅} := by rw [← Finset.filter_card_add_filter_neg_card_eq_card fun i ↦ f i = ∅, add_comm] exact add_le_add_right @@ -336,7 +330,7 @@ theorem card_le_card_biUnion_add_card_fiber {s : Finset ι} {f : ι → Finset _ theorem card_le_card_biUnion_add_one {s : Finset ι} {f : ι → Finset α} (hf : Injective f) - (hs : (s : Set ι).PairwiseDisjoint f) : s.card ≤ (s.biUnion f).card + 1 := + (hs : (s : Set ι).PairwiseDisjoint f) : #s ≤ #(s.biUnion f) + 1 := (card_le_card_biUnion_add_card_fiber hs).trans <| add_le_add_left (card_le_one.2 fun _ hi _ hj ↦ hf <| (mem_filter.1 hi).2.trans (mem_filter.1 hj).2.symm) _ @@ -373,8 +367,7 @@ theorem prod_mono_set' (f : ι → M) : Monotone fun s ↦ ∏ x ∈ s, f x := f theorem prod_le_prod_of_ne_one' (h : ∀ x ∈ s, f x ≠ 1 → x ∈ t) : ∏ x ∈ s, f x ≤ ∏ x ∈ t, f x := by classical calc - ∏ x ∈ s, f x = (∏ x ∈ s.filter fun x ↦ f x = 1, f x) * - ∏ x ∈ s.filter fun x ↦ f x ≠ 1, f x := by + ∏ x ∈ s, f x = (∏ x ∈ s with f x = 1, f x) * ∏ x ∈ s with f x ≠ 1, f x := by rw [← prod_union, filter_union_filter_neg_eq] exact disjoint_filter.2 fun _ _ h n_h ↦ n_h h _ ≤ ∏ x ∈ t, f x := @@ -519,11 +512,11 @@ lemma one_le_prod (hf : 1 ≤ f) : 1 ≤ ∏ i, f i := Finset.one_le_prod' fun _ @[to_additive] lemma prod_eq_one_iff_of_one_le (hf : 1 ≤ f) : ∏ i, f i = 1 ↔ f = 1 := - (Finset.prod_eq_one_iff_of_one_le' fun i _ ↦ hf i).trans <| by simp [Function.funext_iff] + (Finset.prod_eq_one_iff_of_one_le' fun i _ ↦ hf i).trans <| by simp [funext_iff] @[to_additive] lemma prod_eq_one_iff_of_le_one (hf : f ≤ 1) : ∏ i, f i = 1 ↔ f = 1 := - (Finset.prod_eq_one_iff_of_le_one' fun i _ ↦ hf i).trans <| by simp [Function.funext_iff] + (Finset.prod_eq_one_iff_of_le_one' fun i _ ↦ hf i).trans <| by simp [funext_iff] end OrderedCommMonoid @@ -581,43 +574,3 @@ theorem sup_powerset_len {α : Type*} [DecidableEq α] (x : Multiset α) : Eq.symm (finset_sum_eq_sup_iff_disjoint.mpr fun _ _ _ _ h => pairwise_disjoint_powersetCard x h) end Multiset - -namespace Mathlib.Meta.Positivity -open Qq Lean Meta Finset - -/-- The `positivity` extension which proves that `∑ i ∈ s, f i` is nonnegative if `f` is, and -positive if each `f i` is and `s` is nonempty. - -TODO: The following example does not work -``` -example (s : Finset ℕ) (f : ℕ → ℤ) (hf : ∀ n, 0 ≤ f n) : 0 ≤ s.sum f := by positivity -``` -because `compareHyp` can't look for assumptions behind binders. --/ -@[positivity Finset.sum _ _] -def evalFinsetSum : PositivityExt where eval {u α} zα pα e := do - match e with - | ~q(@Finset.sum $ι _ $instα $s $f) => - let i : Q($ι) ← mkFreshExprMVarQ q($ι) .syntheticOpaque - have body : Q($α) := .betaRev f #[i] - let rbody ← core zα pα body - let p_pos : Option Q(0 < $e) := ← (do - let .positive pbody := rbody | pure none -- Fail if the body is not provably positive - let .some ps ← proveFinsetNonempty s | pure none - let .some pα' ← trySynthInstanceQ q(OrderedCancelAddCommMonoid $α) | pure none - assertInstancesCommute - let pr : Q(∀ i, 0 < $f i) ← mkLambdaFVars #[i] pbody - return some q(@sum_pos $ι $α $pα' $f $s (fun i _ ↦ $pr i) $ps)) - -- Try to show that the sum is positive - if let some p_pos := p_pos then - return .positive p_pos - -- Fall back to showing that the sum is nonnegative - else - let pbody ← rbody.toNonneg - let pr : Q(∀ i, 0 ≤ $f i) ← mkLambdaFVars #[i] pbody - let pα' ← synthInstanceQ q(OrderedAddCommMonoid $α) - assertInstancesCommute - return .nonnegative q(@sum_nonneg $ι $α $pα' $f $s fun i _ ↦ $pr i) - | _ => throwError "not Finset.sum" - -end Mathlib.Meta.Positivity diff --git a/Mathlib/Algebra/Order/BigOperators/Group/List.lean b/Mathlib/Algebra/Order/BigOperators/Group/List.lean index 94dd5a115870c..bf44e7ef2b251 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/List.lean @@ -21,8 +21,8 @@ section Monoid variable [Monoid M] @[to_additive sum_le_sum] -lemma Forall₂.prod_le_prod' [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] {l₁ l₂ : List M} (h : Forall₂ (· ≤ ·) l₁ l₂) : +lemma Forall₂.prod_le_prod' [Preorder M] [MulRightMono M] + [MulLeftMono M] {l₁ l₂ : List M} (h : Forall₂ (· ≤ ·) l₁ l₂) : l₁.prod ≤ l₂.prod := by induction' h with a b la lb hab ih ih' · rfl @@ -35,8 +35,8 @@ of `∀ a ∈ l₂, 1 ≤ a` but this lemma is not yet in `mathlib`. -/ then `l₁.sum ≤ l₂.sum`. One can prove a stronger version assuming `∀ a ∈ l₂.diff l₁, 0 ≤ a` instead of `∀ a ∈ l₂, 0 ≤ a` but this lemma is not yet in `mathlib`."] -lemma Sublist.prod_le_prod' [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] {l₁ l₂ : List M} (h : l₁ <+ l₂) +lemma Sublist.prod_le_prod' [Preorder M] [MulRightMono M] + [MulLeftMono M] {l₁ l₂ : List M} (h : l₁ <+ l₂) (h₁ : ∀ a ∈ l₂, (1 : M) ≤ a) : l₁.prod ≤ l₂.prod := by induction h with | slnil => rfl @@ -49,22 +49,22 @@ lemma Sublist.prod_le_prod' [Preorder M] [CovariantClass M M (Function.swap (· @[to_additive sum_le_sum] lemma SublistForall₂.prod_le_prod' [Preorder M] - [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] [CovariantClass M M (· * ·) (· ≤ ·)] + [MulRightMono M] [MulLeftMono M] {l₁ l₂ : List M} (h : SublistForall₂ (· ≤ ·) l₁ l₂) (h₁ : ∀ a ∈ l₂, (1 : M) ≤ a) : l₁.prod ≤ l₂.prod := let ⟨_, hall, hsub⟩ := sublistForall₂_iff.1 h hall.prod_le_prod'.trans <| hsub.prod_le_prod' h₁ @[to_additive sum_le_sum] -lemma prod_le_prod' [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] {l : List ι} {f g : ι → M} (h : ∀ i ∈ l, f i ≤ g i) : +lemma prod_le_prod' [Preorder M] [MulRightMono M] + [MulLeftMono M] {l : List ι} {f g : ι → M} (h : ∀ i ∈ l, f i ≤ g i) : (l.map f).prod ≤ (l.map g).prod := Forall₂.prod_le_prod' <| by simpa @[to_additive sum_lt_sum] -lemma prod_lt_prod' [Preorder M] [CovariantClass M M (· * ·) (· < ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (Function.swap (· * ·)) (· < ·)] - [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] {l : List ι} (f g : ι → M) +lemma prod_lt_prod' [Preorder M] [MulLeftStrictMono M] + [MulLeftMono M] [MulRightStrictMono M] + [MulRightMono M] {l : List ι} (f g : ι → M) (h₁ : ∀ i ∈ l, f i ≤ g i) (h₂ : ∃ i ∈ l, f i < g i) : (l.map f).prod < (l.map g).prod := by induction' l with i l ihl · rcases h₂ with ⟨_, ⟨⟩, _⟩ @@ -75,42 +75,42 @@ lemma prod_lt_prod' [Preorder M] [CovariantClass M M (· * ·) (· < ·)] · exact mul_lt_mul_of_le_of_lt h₁.1 <| ihl h₁.2 ‹_› @[to_additive] -lemma prod_lt_prod_of_ne_nil [Preorder M] [CovariantClass M M (· * ·) (· < ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (Function.swap (· * ·)) (· < ·)] - [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] {l : List ι} (hl : l ≠ []) (f g : ι → M) +lemma prod_lt_prod_of_ne_nil [Preorder M] [MulLeftStrictMono M] + [MulLeftMono M] [MulRightStrictMono M] + [MulRightMono M] {l : List ι} (hl : l ≠ []) (f g : ι → M) (hlt : ∀ i ∈ l, f i < g i) : (l.map f).prod < (l.map g).prod := (prod_lt_prod' f g fun i hi => (hlt i hi).le) <| (exists_mem_of_ne_nil l hl).imp fun i hi => ⟨hi, hlt i hi⟩ @[to_additive sum_le_card_nsmul] -lemma prod_le_pow_card [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] (l : List M) (n : M) (h : ∀ x ∈ l, x ≤ n) : +lemma prod_le_pow_card [Preorder M] [MulRightMono M] + [MulLeftMono M] (l : List M) (n : M) (h : ∀ x ∈ l, x ≤ n) : l.prod ≤ n ^ l.length := by simpa only [map_id', map_const', prod_replicate] using prod_le_prod' h @[to_additive card_nsmul_le_sum] -lemma pow_card_le_prod [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] (l : List M) (n : M) (h : ∀ x ∈ l, n ≤ x) : +lemma pow_card_le_prod [Preorder M] [MulRightMono M] + [MulLeftMono M] (l : List M) (n : M) (h : ∀ x ∈ l, n ≤ x) : n ^ l.length ≤ l.prod := @prod_le_pow_card Mᵒᵈ _ _ _ _ l n h @[to_additive exists_lt_of_sum_lt] -lemma exists_lt_of_prod_lt' [LinearOrder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] {l : List ι} (f g : ι → M) +lemma exists_lt_of_prod_lt' [LinearOrder M] [MulRightMono M] + [MulLeftMono M] {l : List ι} (f g : ι → M) (h : (l.map f).prod < (l.map g).prod) : ∃ i ∈ l, f i < g i := by contrapose! h exact prod_le_prod' h @[to_additive exists_le_of_sum_le] -lemma exists_le_of_prod_le' [LinearOrder M] [CovariantClass M M (· * ·) (· < ·)] - [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (Function.swap (· * ·)) (· < ·)] - [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] {l : List ι} (hl : l ≠ []) (f g : ι → M) +lemma exists_le_of_prod_le' [LinearOrder M] [MulLeftStrictMono M] + [MulLeftMono M] [MulRightStrictMono M] + [MulRightMono M] {l : List ι} (hl : l ≠ []) (f g : ι → M) (h : (l.map f).prod ≤ (l.map g).prod) : ∃ x ∈ l, f x ≤ g x := by contrapose! h exact prod_lt_prod_of_ne_nil hl _ _ h @[to_additive sum_nonneg] -lemma one_le_prod_of_one_le [Preorder M] [CovariantClass M M (· * ·) (· ≤ ·)] {l : List M} +lemma one_le_prod_of_one_le [Preorder M] [MulLeftMono M] {l : List M} (hl₁ : ∀ x ∈ l, (1 : M) ≤ x) : 1 ≤ l.prod := by -- We don't use `pow_card_le_prod` to avoid assumption -- [covariant_class M M (function.swap (*)) (≤)] @@ -121,7 +121,7 @@ lemma one_le_prod_of_one_le [Preorder M] [CovariantClass M M (· * ·) (· ≤ @[to_additive] lemma max_prod_le (l : List α) (f g : α → M) [LinearOrder M] - [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] : + [MulLeftMono M] [MulRightMono M] : max (l.map f).prod (l.map g).prod ≤ (l.map fun i ↦ max (f i) (g i)).prod := by rw [max_le_iff] constructor <;> apply List.prod_le_prod' <;> intros @@ -129,8 +129,8 @@ lemma max_prod_le (l : List α) (f g : α → M) [LinearOrder M] · apply le_max_right @[to_additive] -lemma prod_min_le [LinearOrder M] [CovariantClass M M (· * ·) (· ≤ ·)] - [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] (l : List α) (f g : α → M) : +lemma prod_min_le [LinearOrder M] [MulLeftMono M] + [MulRightMono M] (l : List α) (f g : α → M) : (l.map fun i ↦ min (f i) (g i)).prod ≤ min (l.map f).prod (l.map g).prod := by rw [le_min_iff] constructor <;> apply List.prod_le_prod' <;> intros diff --git a/Mathlib/Algebra/Order/CauSeq/Basic.lean b/Mathlib/Algebra/Order/CauSeq/Basic.lean index b390f7b8dceaf..380eb60f96e79 100644 --- a/Mathlib/Algebra/Order/CauSeq/Basic.lean +++ b/Mathlib/Algebra/Order/CauSeq/Basic.lean @@ -374,21 +374,21 @@ def LimZero {abv : β → α} (f : CauSeq β abv) : Prop := theorem add_limZero {f g : CauSeq β abv} (hf : LimZero f) (hg : LimZero g) : LimZero (f + g) | ε, ε0 => - (exists_forall_ge_and (hf _ <| half_pos ε0) (hg _ <| half_pos ε0)).imp fun i H j ij => by + (exists_forall_ge_and (hf _ <| half_pos ε0) (hg _ <| half_pos ε0)).imp fun _ H j ij => by let ⟨H₁, H₂⟩ := H _ ij simpa [add_halves ε] using lt_of_le_of_lt (abv_add abv _ _) (add_lt_add H₁ H₂) theorem mul_limZero_right (f : CauSeq β abv) {g} (hg : LimZero g) : LimZero (f * g) | ε, ε0 => let ⟨F, F0, hF⟩ := f.bounded' 0 - (hg _ <| div_pos ε0 F0).imp fun i H j ij => by + (hg _ <| div_pos ε0 F0).imp fun _ H j ij => by have := mul_lt_mul' (le_of_lt <| hF j) (H _ ij) (abv_nonneg abv _) F0 rwa [mul_comm F, div_mul_cancel₀ _ (ne_of_gt F0), ← abv_mul] at this theorem mul_limZero_left {f} (g : CauSeq β abv) (hg : LimZero f) : LimZero (f * g) | ε, ε0 => let ⟨G, G0, hG⟩ := g.bounded' 0 - (hg _ <| div_pos ε0 G0).imp fun i H j ij => by + (hg _ <| div_pos ε0 G0).imp fun _ H j ij => by have := mul_lt_mul'' (H _ ij) (hG j) (abv_nonneg abv _) (abv_nonneg abv _) rwa [div_mul_cancel₀ _ (ne_of_gt G0), ← abv_mul] at this @@ -430,7 +430,7 @@ theorem sub_equiv_sub {f1 f2 g1 g2 : CauSeq β abv} (hf : f1 ≈ f2) (hg : g1 theorem equiv_def₃ {f g : CauSeq β abv} (h : f ≈ g) {ε : α} (ε0 : 0 < ε) : ∃ i, ∀ j ≥ i, ∀ k ≥ j, abv (f k - g j) < ε := - (exists_forall_ge_and (h _ <| half_pos ε0) (f.cauchy₃ <| half_pos ε0)).imp fun i H j ij k jk => by + (exists_forall_ge_and (h _ <| half_pos ε0) (f.cauchy₃ <| half_pos ε0)).imp fun _ H j ij k jk => by let ⟨h₁, h₂⟩ := H _ ij have := lt_of_le_of_lt (abv_add abv (f j - g j) _) (add_lt_add h₁ (h₂ _ jk)) rwa [sub_add_sub_cancel', add_halves] at this @@ -749,14 +749,14 @@ theorem coe_inf (f g : CauSeq α abs) : ⇑(f ⊓ g) = (f : ℕ → α) ⊓ g := theorem sup_limZero {f g : CauSeq α abs} (hf : LimZero f) (hg : LimZero g) : LimZero (f ⊔ g) | ε, ε0 => - (exists_forall_ge_and (hf _ ε0) (hg _ ε0)).imp fun i H j ij => by + (exists_forall_ge_and (hf _ ε0) (hg _ ε0)).imp fun _ H j ij => by let ⟨H₁, H₂⟩ := H _ ij rw [abs_lt] at H₁ H₂ ⊢ exact ⟨lt_sup_iff.mpr (Or.inl H₁.1), sup_lt_iff.mpr ⟨H₁.2, H₂.2⟩⟩ theorem inf_limZero {f g : CauSeq α abs} (hf : LimZero f) (hg : LimZero g) : LimZero (f ⊓ g) | ε, ε0 => - (exists_forall_ge_and (hf _ ε0) (hg _ ε0)).imp fun i H j ij => by + (exists_forall_ge_and (hf _ ε0) (hg _ ε0)).imp fun _ H j ij => by let ⟨H₁, H₂⟩ := H _ ij rw [abs_lt] at H₁ H₂ ⊢ exact ⟨lt_inf_iff.mpr ⟨H₁.1, H₂.1⟩, inf_lt_iff.mpr (Or.inl H₁.2)⟩ diff --git a/Mathlib/Algebra/Order/CauSeq/BigOperators.lean b/Mathlib/Algebra/Order/CauSeq/BigOperators.lean index 96a11d63d193a..ed1fb71669c94 100644 --- a/Mathlib/Algebra/Order/CauSeq/BigOperators.lean +++ b/Mathlib/Algebra/Order/CauSeq/BigOperators.lean @@ -121,9 +121,9 @@ theorem _root_.cauchy_product (ha : IsCauSeq abs fun m ↦ ∑ n ∈ range m, ab (by rw [← sum_mul, mul_comm]; gcongr) rw [sum_range_sub_sum_range (le_of_lt hNMK)] calc - (∑ i ∈ (range K).filter fun k ↦ max N M + 1 ≤ k, + (∑ i ∈ range K with max N M + 1 ≤ i, abv (f i) * abv ((∑ k ∈ range (K - i), g k) - ∑ k ∈ range K, g k)) ≤ - ∑ i ∈ (range K).filter fun k ↦ max N M + 1 ≤ k, abv (f i) * (2 * Q) := by + ∑ i ∈ range K with max N M + 1 ≤ i, abv (f i) * (2 * Q) := by gcongr rw [sub_eq_add_neg] refine le_trans (abv_add _ _ _) ?_ @@ -213,7 +213,7 @@ lemma series_ratio_test {f : ℕ → β} (n : ℕ) (r : α) (hr0 : 0 ≤ r) (hr1 positivity · have kn : k + n.succ ≥ n.succ := by rw [← zero_add n.succ]; exact add_le_add (Nat.zero_le _) (by simp) - erw [hk, Nat.succ_add, pow_succ r, ← mul_assoc] + rw [hk, Nat.succ_add, pow_succ r, ← mul_assoc] refine le_trans (by rw [mul_comm] <;> exact h _ (Nat.le_of_succ_le kn)) (mul_le_mul_of_nonneg_right ?_ hr0) diff --git a/Mathlib/Algebra/Order/CauSeq/Completion.lean b/Mathlib/Algebra/Order/CauSeq/Completion.lean index 1cf2efa956c83..501a26686963e 100644 --- a/Mathlib/Algebra/Order/CauSeq/Completion.lean +++ b/Mathlib/Algebra/Order/CauSeq/Completion.lean @@ -198,8 +198,6 @@ noncomputable instance : Inv (Cauchy abv) := rw [mk_eq.2 fg, ← Ig] at If rw [← mul_one (mk (inv f hf)), ← Ig', ← mul_assoc, If, mul_assoc, Ig', mul_one]⟩ --- porting note (#10618): simp can prove this --- @[simp] theorem inv_zero : (0 : (Cauchy abv))⁻¹ = 0 := congr_arg mk <| by rw [dif_pos] <;> [rfl; exact zero_limZero] @@ -239,13 +237,13 @@ lemma ofRat_div (x y : β) : ofRat (x / y) = (ofRat x / ofRat y : Cauchy abv) := noncomputable instance Cauchy.divisionRing : DivisionRing (Cauchy abv) where exists_pair_ne := ⟨0, 1, zero_ne_one⟩ inv_zero := inv_zero - mul_inv_cancel x := CauSeq.Completion.mul_inv_cancel + mul_inv_cancel _ := CauSeq.Completion.mul_inv_cancel nnqsmul := (· • ·) qsmul := (· • ·) nnratCast_def q := by simp_rw [← ofRat_nnratCast, NNRat.cast_def, ofRat_div, ofRat_natCast] ratCast_def q := by rw [← ofRat_ratCast, Rat.cast_def, ofRat_div, ofRat_natCast, ofRat_intCast] - nnqsmul_def q x := Quotient.inductionOn x fun f ↦ congr_arg mk <| ext fun i ↦ NNRat.smul_def _ _ - qsmul_def q x := Quotient.inductionOn x fun f ↦ congr_arg mk <| ext fun i ↦ Rat.smul_def _ _ + nnqsmul_def _ x := Quotient.inductionOn x fun _ ↦ congr_arg mk <| ext fun _ ↦ NNRat.smul_def _ _ + qsmul_def _ x := Quotient.inductionOn x fun _ ↦ congr_arg mk <| ext fun _ ↦ Rat.smul_def _ _ /-- Show the first 10 items of a representative of this equivalence class of cauchy sequences. diff --git a/Mathlib/Algebra/Order/Chebyshev.lean b/Mathlib/Algebra/Order/Chebyshev.lean index 439d79b0c4e2b..25c25f0275d3c 100644 --- a/Mathlib/Algebra/Order/Chebyshev.lean +++ b/Mathlib/Algebra/Order/Chebyshev.lean @@ -3,7 +3,6 @@ Copyright (c) 2023 Mantas Bakšys, Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mantas Bakšys, Yaël Dillies -/ -import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Algebra.Order.Monovary import Mathlib.Algebra.Order.Rearrangement import Mathlib.GroupTheory.Perm.Cycle.Basic @@ -16,7 +15,7 @@ import Mathlib.Tactic.Positivity.Finset This file proves the Chebyshev sum inequality. -Chebyshev's inequality states `(∑ i ∈ s, f i) * (∑ i ∈ s, g i) ≤ s.card * ∑ i ∈ s, f i * g i` +Chebyshev's inequality states `(∑ i ∈ s, f i) * (∑ i ∈ s, g i) ≤ #s * ∑ i ∈ s, f i * g i` when `f g : ι → α` monovary, and the reverse inequality when `f` and `g` antivary. @@ -54,10 +53,10 @@ variable [LinearOrderedSemiring α] [ExistsAddOfLE α] [LinearOrderedCancelAddCo monotone/antitone), the scalar product of their sum is less than the size of the set times their scalar product. -/ theorem MonovaryOn.sum_smul_sum_le_card_smul_sum (hfg : MonovaryOn f g s) : - (∑ i ∈ s, f i) • ∑ i ∈ s, g i ≤ s.card • ∑ i ∈ s, f i • g i := by + (∑ i ∈ s, f i) • ∑ i ∈ s, g i ≤ #s • ∑ i ∈ s, f i • g i := by classical obtain ⟨σ, hσ, hs⟩ := s.countable_toSet.exists_cycleOn - rw [← card_range s.card, sum_smul_sum_eq_sum_perm hσ] + rw [← card_range #s, sum_smul_sum_eq_sum_perm hσ] exact sum_le_card_nsmul _ _ _ fun n _ ↦ hfg.sum_smul_comp_perm_le_sum_smul fun x hx ↦ hs fun h ↦ hx <| IsFixedPt.perm_pow h _ @@ -65,7 +64,7 @@ theorem MonovaryOn.sum_smul_sum_le_card_smul_sum (hfg : MonovaryOn f g s) : other is antitone), the scalar product of their sum is less than the size of the set times their scalar product. -/ theorem AntivaryOn.card_smul_sum_le_sum_smul_sum (hfg : AntivaryOn f g s) : - s.card • ∑ i ∈ s, f i • g i ≤ (∑ i ∈ s, f i) • ∑ i ∈ s, g i := + #s • ∑ i ∈ s, f i • g i ≤ (∑ i ∈ s, f i) • ∑ i ∈ s, g i := hfg.dual_right.sum_smul_sum_le_card_smul_sum variable [Fintype ι] @@ -100,7 +99,7 @@ variable [LinearOrderedSemiring α] [ExistsAddOfLE α] {s : Finset ι} {σ : Per monotone/antitone), the product of their sum is less than the size of the set times their scalar product. -/ theorem MonovaryOn.sum_mul_sum_le_card_mul_sum (hfg : MonovaryOn f g s) : - (∑ i ∈ s, f i) * ∑ i ∈ s, g i ≤ s.card * ∑ i ∈ s, f i * g i := by + (∑ i ∈ s, f i) * ∑ i ∈ s, g i ≤ #s * ∑ i ∈ s, f i * g i := by rw [← nsmul_eq_mul] exact hfg.sum_smul_sum_le_card_smul_sum @@ -108,29 +107,29 @@ theorem MonovaryOn.sum_mul_sum_le_card_mul_sum (hfg : MonovaryOn f g s) : other is antitone), the product of their sum is greater than the size of the set times their scalar product. -/ theorem AntivaryOn.card_mul_sum_le_sum_mul_sum (hfg : AntivaryOn f g s) : - (s.card : α) * ∑ i ∈ s, f i * g i ≤ (∑ i ∈ s, f i) * ∑ i ∈ s, g i := by + (#s : α) * ∑ i ∈ s, f i * g i ≤ (∑ i ∈ s, f i) * ∑ i ∈ s, g i := by rw [← nsmul_eq_mul] exact hfg.card_smul_sum_le_sum_smul_sum /-- Special case of **Jensen's inequality** for sums of powers. -/ lemma pow_sum_le_card_mul_sum_pow (hf : ∀ i ∈ s, 0 ≤ f i) : - ∀ n, (∑ i ∈ s, f i) ^ (n + 1) ≤ (s.card : α) ^ n * ∑ i ∈ s, f i ^ (n + 1) + ∀ n, (∑ i ∈ s, f i) ^ (n + 1) ≤ (#s : α) ^ n * ∑ i ∈ s, f i ^ (n + 1) | 0 => by simp | n + 1 => calc _ = (∑ i ∈ s, f i) ^ (n + 1) * ∑ i ∈ s, f i := by rw [pow_succ] - _ ≤ (s.card ^ n * ∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i := by + _ ≤ (#s ^ n * ∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i := by gcongr exacts [sum_nonneg hf, pow_sum_le_card_mul_sum_pow hf _] - _ = s.card ^ n * ((∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i) := by rw [mul_assoc] - _ ≤ s.card ^ n * (s.card * ∑ i ∈ s, f i ^ (n + 1) * f i) := by + _ = #s ^ n * ((∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i) := by rw [mul_assoc] + _ ≤ #s ^ n * (#s * ∑ i ∈ s, f i ^ (n + 1) * f i) := by gcongr _ * ?_ exact ((monovaryOn_self ..).pow_left₀ hf _).sum_mul_sum_le_card_mul_sum _ = _ := by simp_rw [← mul_assoc, ← pow_succ] /-- Special case of **Chebyshev's Sum Inequality** or the **Cauchy-Schwarz Inequality**: The square of the sum is less than the size of the set times the sum of the squares. -/ -theorem sq_sum_le_card_mul_sum_sq : (∑ i ∈ s, f i) ^ 2 ≤ s.card * ∑ i ∈ s, f i ^ 2 := by +theorem sq_sum_le_card_mul_sum_sq : (∑ i ∈ s, f i) ^ 2 ≤ #s * ∑ i ∈ s, f i ^ 2 := by simp_rw [sq] exact (monovaryOn_self _ _).sum_mul_sum_le_card_mul_sum @@ -156,16 +155,16 @@ variable [LinearOrderedSemifield α] [ExistsAddOfLE α] {s : Finset ι} {f : ι /-- Special case of **Jensen's inequality** for sums of powers. -/ lemma pow_sum_div_card_le_sum_pow (hf : ∀ i ∈ s, 0 ≤ f i) (n : ℕ) : - (∑ i ∈ s, f i) ^ (n + 1) / s.card ^ n ≤ ∑ i ∈ s, f i ^ (n + 1) := by + (∑ i ∈ s, f i) ^ (n + 1) / #s ^ n ≤ ∑ i ∈ s, f i ^ (n + 1) := by obtain rfl | hs := s.eq_empty_or_nonempty · simp rw [div_le_iff₀' (by positivity)] exact pow_sum_le_card_mul_sum_pow hf _ theorem sum_div_card_sq_le_sum_sq_div_card : - ((∑ i ∈ s, f i) / s.card) ^ 2 ≤ (∑ i ∈ s, f i ^ 2) / s.card := by + ((∑ i ∈ s, f i) / #s) ^ 2 ≤ (∑ i ∈ s, f i ^ 2) / #s := by obtain rfl | hs := s.eq_empty_or_nonempty · simp - rw [div_pow, div_le_div_iff (by positivity) (by positivity), sq (s.card : α), mul_left_comm, + rw [div_pow, div_le_div_iff (by positivity) (by positivity), sq (#s : α), mul_left_comm, ← mul_assoc] exact mul_le_mul_of_nonneg_right sq_sum_le_card_mul_sum_sq (by positivity) diff --git a/Mathlib/Algebra/Order/CompleteField.lean b/Mathlib/Algebra/Order/CompleteField.lean index 680ebceb3f631..31a14a28943a9 100644 --- a/Mathlib/Algebra/Order/CompleteField.lean +++ b/Mathlib/Algebra/Order/CompleteField.lean @@ -202,7 +202,7 @@ theorem coe_lt_inducedMap_iff : (q : β) < inducedMap α β a ↔ (q : α) < a : exact mod_cast hq theorem lt_inducedMap_iff : b < inducedMap α β a ↔ ∃ q : ℚ, b < q ∧ (q : α) < a := - ⟨fun h => (exists_rat_btwn h).imp fun q => And.imp_right coe_lt_inducedMap_iff.1, + ⟨fun h => (exists_rat_btwn h).imp fun _ => And.imp_right coe_lt_inducedMap_iff.1, fun ⟨q, hbq, hqa⟩ => hbq.trans <| by rwa [coe_lt_inducedMap_iff]⟩ @[simp] @@ -216,7 +216,6 @@ theorem inducedMap_inducedMap (a : α) : inducedMap β γ (inducedMap α β a) = eq_of_forall_rat_lt_iff_lt fun q => by rw [coe_lt_inducedMap_iff, coe_lt_inducedMap_iff, Iff.comm, coe_lt_inducedMap_iff] ---@[simp] -- Porting note (#10618): simp can prove it theorem inducedMap_inv_self (b : β) : inducedMap γ β (inducedMap β γ b) = b := by rw [inducedMap_inducedMap, inducedMap_self] diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index b349a1c749325..4e76076e79d17 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -8,7 +8,6 @@ import Mathlib.Algebra.Order.Field.Defs import Mathlib.Algebra.Order.GroupWithZero.Unbundled.Lemmas import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Order.Bounds.OrderIso -import Mathlib.Tactic.Bound.Attribute import Mathlib.Tactic.Positivity.Core /-! @@ -86,10 +85,6 @@ theorem div_le_of_nonneg_of_le_mul (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * lemma mul_le_of_nonneg_of_le_div (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b / c) : a * c ≤ b := mul_le_of_le_div₀ hb hc h -attribute [bound] div_le_one_of_le₀ -attribute [bound] mul_inv_le_one_of_le₀ -attribute [bound] inv_mul_le_one_of_le₀ - @[deprecated div_le_one_of_le₀ (since := "2024-10-03")] theorem div_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a / b ≤ 1 := div_le_one_of_le₀ h hb @@ -103,77 +98,68 @@ lemma inv_mul_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : b⁻¹ * a ≤ 1 := in ### Bi-implications of inequalities using inversions -/ -@[gcongr, bound] -theorem inv_le_inv_of_le (ha : 0 < a) (h : a ≤ b) : b⁻¹ ≤ a⁻¹ := by - rwa [← one_div a, le_div_iff₀' ha, ← div_eq_mul_inv, div_le_iff₀ (ha.trans_le h), one_mul] +@[deprecated inv_anti₀ (since := "2024-10-05")] +theorem inv_le_inv_of_le (ha : 0 < a) (h : a ≤ b) : b⁻¹ ≤ a⁻¹ := inv_anti₀ ha h /-- See `inv_le_inv_of_le` for the implication from right-to-left with one fewer assumption. -/ -theorem inv_le_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a := by - rw [← one_div, div_le_iff₀ ha, ← div_eq_inv_mul, le_div_iff₀ hb, one_mul] +@[deprecated inv_le_inv₀ (since := "2024-10-05")] +theorem inv_le_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a := inv_le_inv₀ ha hb /-- In a linear ordered field, for positive `a` and `b` we have `a⁻¹ ≤ b ↔ b⁻¹ ≤ a`. See also `inv_le_of_inv_le` for a one-sided implication with one fewer assumption. -/ -theorem inv_le (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a := by - rw [← inv_le_inv hb (inv_pos.2 ha), inv_inv] +@[deprecated inv_le_comm₀ (since := "2024-10-05")] +theorem inv_le (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a := inv_le_comm₀ ha hb -theorem inv_le_of_inv_le (ha : 0 < a) (h : a⁻¹ ≤ b) : b⁻¹ ≤ a := - (inv_le ha ((inv_pos.2 ha).trans_le h)).1 h +@[deprecated inv_le_of_inv_le₀ (since := "2024-10-05")] +theorem inv_le_of_inv_le (ha : 0 < a) (h : a⁻¹ ≤ b) : b⁻¹ ≤ a := inv_le_of_inv_le₀ ha h -theorem le_inv (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ := by - rw [← inv_le_inv (inv_pos.2 hb) ha, inv_inv] +@[deprecated le_inv_comm₀ (since := "2024-10-05")] +theorem le_inv (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ := le_inv_comm₀ ha hb /-- See `inv_lt_inv_of_lt` for the implication from right-to-left with one fewer assumption. -/ -theorem inv_lt_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b⁻¹ ↔ b < a := - lt_iff_lt_of_le_iff_le (inv_le_inv hb ha) +@[deprecated inv_lt_inv₀ (since := "2024-10-05")] +theorem inv_lt_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b⁻¹ ↔ b < a := inv_lt_inv₀ ha hb -@[gcongr] -theorem inv_lt_inv_of_lt (hb : 0 < b) (h : b < a) : a⁻¹ < b⁻¹ := - (inv_lt_inv (hb.trans h) hb).2 h +@[deprecated inv_strictAnti₀ (since := "2024-10-05")] +theorem inv_lt_inv_of_lt (hb : 0 < b) (h : b < a) : a⁻¹ < b⁻¹ := inv_strictAnti₀ hb h /-- In a linear ordered field, for positive `a` and `b` we have `a⁻¹ < b ↔ b⁻¹ < a`. See also `inv_lt_of_inv_lt` for a one-sided implication with one fewer assumption. -/ -theorem inv_lt (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b ↔ b⁻¹ < a := - lt_iff_lt_of_le_iff_le (le_inv hb ha) +@[deprecated inv_lt_comm₀ (since := "2024-10-05")] +theorem inv_lt (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b ↔ b⁻¹ < a := inv_lt_comm₀ ha hb -theorem inv_lt_of_inv_lt (ha : 0 < a) (h : a⁻¹ < b) : b⁻¹ < a := - (inv_lt ha ((inv_pos.2 ha).trans h)).1 h +@[deprecated inv_lt_of_inv_lt₀ (since := "2024-10-05")] +theorem inv_lt_of_inv_lt (ha : 0 < a) (h : a⁻¹ < b) : b⁻¹ < a := inv_lt_of_inv_lt₀ ha h -theorem lt_inv (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ := - lt_iff_lt_of_le_iff_le (inv_le hb ha) +@[deprecated lt_inv_comm₀ (since := "2024-10-05")] +theorem lt_inv (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ := lt_inv_comm₀ ha hb -theorem inv_lt_one (ha : 1 < a) : a⁻¹ < 1 := by - rwa [inv_lt (zero_lt_one.trans ha) zero_lt_one, inv_one] +@[deprecated inv_lt_one_of_one_lt₀ (since := "2024-10-05")] +theorem inv_lt_one (ha : 1 < a) : a⁻¹ < 1 := inv_lt_one_of_one_lt₀ ha -theorem one_lt_inv (h₁ : 0 < a) (h₂ : a < 1) : 1 < a⁻¹ := by - rwa [lt_inv (@zero_lt_one α _ _ _ _ _) h₁, inv_one] +@[deprecated one_lt_inv₀ (since := "2024-10-05")] +theorem one_lt_inv (h₁ : 0 < a) (h₂ : a < 1) : 1 < a⁻¹ := (one_lt_inv₀ h₁).2 h₂ -@[bound] -theorem inv_le_one (ha : 1 ≤ a) : a⁻¹ ≤ 1 := by - rwa [inv_le (zero_lt_one.trans_le ha) zero_lt_one, inv_one] +@[deprecated inv_le_one_of_one_le₀ (since := "2024-10-05")] +theorem inv_le_one (ha : 1 ≤ a) : a⁻¹ ≤ 1 := inv_le_one_of_one_le₀ ha -theorem one_le_inv (h₁ : 0 < a) (h₂ : a ≤ 1) : 1 ≤ a⁻¹ := by - rwa [le_inv (@zero_lt_one α _ _ _ _ _) h₁, inv_one] +@[deprecated one_le_inv₀ (since := "2024-10-05")] +theorem one_le_inv (h₁ : 0 < a) (h₂ : a ≤ 1) : 1 ≤ a⁻¹ := (one_le_inv₀ h₁).2 h₂ -theorem inv_lt_one_iff_of_pos (h₀ : 0 < a) : a⁻¹ < 1 ↔ 1 < a := - ⟨fun h₁ => inv_inv a ▸ one_lt_inv (inv_pos.2 h₀) h₁, inv_lt_one⟩ +@[deprecated inv_lt_one₀ (since := "2024-10-05")] +theorem inv_lt_one_iff_of_pos (h₀ : 0 < a) : a⁻¹ < 1 ↔ 1 < a := inv_lt_one₀ h₀ -theorem inv_lt_one_iff : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a := by - rcases le_or_lt a 0 with ha | ha - · simp [ha, (inv_nonpos.2 ha).trans_lt zero_lt_one] - · simp only [ha.not_le, false_or, inv_lt_one_iff_of_pos ha] +@[deprecated inv_lt_one_iff₀ (since := "2024-10-05")] +theorem inv_lt_one_iff : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a := inv_lt_one_iff₀ -theorem one_lt_inv_iff : 1 < a⁻¹ ↔ 0 < a ∧ a < 1 := - ⟨fun h => ⟨inv_pos.1 (zero_lt_one.trans h), - inv_inv a ▸ inv_lt_one h⟩, and_imp.2 one_lt_inv⟩ +@[deprecated one_lt_inv_iff₀ (since := "2024-10-05")] +theorem one_lt_inv_iff : 1 < a⁻¹ ↔ 0 < a ∧ a < 1 := one_lt_inv_iff₀ -theorem inv_le_one_iff : a⁻¹ ≤ 1 ↔ a ≤ 0 ∨ 1 ≤ a := by - rcases em (a = 1) with (rfl | ha) - · simp [le_rfl] - · simp only [Ne.le_iff_lt (Ne.symm ha), Ne.le_iff_lt (mt inv_eq_one.1 ha), inv_lt_one_iff] +@[deprecated inv_le_one_iff₀ (since := "2024-10-05")] +theorem inv_le_one_iff : a⁻¹ ≤ 1 ↔ a ≤ 0 ∨ 1 ≤ a := inv_le_one_iff₀ -theorem one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 := - ⟨fun h => ⟨inv_pos.1 (zero_lt_one.trans_le h), - inv_inv a ▸ inv_le_one h⟩, and_imp.2 one_le_inv⟩ +@[deprecated one_le_inv_iff₀ (since := "2024-10-05")] +theorem one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 := one_le_inv_iff₀ /-! ### Relating two divisions. @@ -194,11 +180,11 @@ lemma div_lt_div_of_pos_right (h : a < b) (hc : 0 < c) : a / c < b / c := by @[gcongr] lemma div_le_div_of_nonneg_left (ha : 0 ≤ a) (hc : 0 < c) (h : c ≤ b) : a / b ≤ a / c := by rw [div_eq_mul_inv, div_eq_mul_inv] - exact mul_le_mul_of_nonneg_left ((inv_le_inv (hc.trans_le h) hc).mpr h) ha + exact mul_le_mul_of_nonneg_left ((inv_le_inv₀ (hc.trans_le h) hc).mpr h) ha @[gcongr, bound] lemma div_lt_div_of_pos_left (ha : 0 < a) (hc : 0 < c) (h : c < b) : a / b < a / c := by - simpa only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv (hc.trans h) hc] + simpa only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv₀ (hc.trans h) hc] @[deprecated (since := "2024-02-16")] alias div_le_div_of_le_of_nonneg := div_le_div_of_nonneg_right @[deprecated (since := "2024-02-16")] alias div_lt_div_of_lt := div_lt_div_of_pos_right @@ -217,7 +203,7 @@ theorem div_lt_div_right (hc : 0 < c) : a / c < b / c ↔ a < b := lt_iff_lt_of_le_iff_le <| div_le_div_right hc theorem div_lt_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b < a / c ↔ c < b := by - simp only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv hb hc] + simp only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv₀ hb hc] theorem div_le_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b ≤ a / c ↔ c ≤ b := le_iff_le_iff_lt_iff_lt.2 (div_lt_div_left ha hc hb) @@ -265,13 +251,17 @@ theorem one_lt_div (hb : 0 < b) : 1 < a / b ↔ b < a := by rw [lt_div_iff₀ hb theorem div_lt_one (hb : 0 < b) : a / b < 1 ↔ a < b := by rw [div_lt_iff₀ hb, one_mul] -theorem one_div_le (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ b ↔ 1 / b ≤ a := by simpa using inv_le ha hb +theorem one_div_le (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ b ↔ 1 / b ≤ a := by + simpa using inv_le_comm₀ ha hb -theorem one_div_lt (ha : 0 < a) (hb : 0 < b) : 1 / a < b ↔ 1 / b < a := by simpa using inv_lt ha hb +theorem one_div_lt (ha : 0 < a) (hb : 0 < b) : 1 / a < b ↔ 1 / b < a := by + simpa using inv_lt_comm₀ ha hb -theorem le_one_div (ha : 0 < a) (hb : 0 < b) : a ≤ 1 / b ↔ b ≤ 1 / a := by simpa using le_inv ha hb +theorem le_one_div (ha : 0 < a) (hb : 0 < b) : a ≤ 1 / b ↔ b ≤ 1 / a := by + simpa using le_inv_comm₀ ha hb -theorem lt_one_div (ha : 0 < a) (hb : 0 < b) : a < 1 / b ↔ b < 1 / a := by simpa using lt_inv ha hb +theorem lt_one_div (ha : 0 < a) (hb : 0 < b) : a < 1 / b ↔ b < 1 / a := by + simpa using lt_inv_comm₀ ha hb @[bound] lemma Bound.one_lt_div_of_pos_of_lt (b0 : 0 < b) : b < a → 1 < a / b := (one_lt_div b0).mpr @@ -283,7 +273,7 @@ theorem lt_one_div (ha : 0 < a) (hb : 0 < b) : a < 1 / b ↔ b < 1 / a := by sim theorem one_div_le_one_div_of_le (ha : 0 < a) (h : a ≤ b) : 1 / b ≤ 1 / a := by - simpa using inv_le_inv_of_le ha h + simpa using inv_anti₀ ha h theorem one_div_lt_one_div_of_lt (ha : 0 < a) (h : a < b) : 1 / b < 1 / a := by rwa [lt_div_iff₀' ha, ← div_eq_mul_one_div, div_lt_one (ha.trans h)] @@ -430,7 +420,7 @@ theorem one_div_pow_strictAnti (a1 : 1 < a) : StrictAnti fun n : ℕ => 1 / a ^ one_div_pow_lt_one_div_pow_of_lt a1 theorem inv_strictAntiOn : StrictAntiOn (fun x : α => x⁻¹) (Set.Ioi 0) := fun _ hx _ hy xy => - (inv_lt_inv hy hx).2 xy + (inv_lt_inv₀ hy hx).2 xy theorem inv_pow_le_inv_pow_of_le (a1 : 1 ≤ a) {m n : ℕ} (mn : m ≤ n) : (a ^ n)⁻¹ ≤ (a ^ m)⁻¹ := by convert one_div_pow_le_one_div_pow_of_le a1 mn using 1 <;> simp @@ -555,7 +545,7 @@ theorem lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a < b⁻¹ ↔ b < a⁻¹ := theorem sub_inv_antitoneOn_Ioi : AntitoneOn (fun x ↦ (x-c)⁻¹) (Set.Ioi c) := antitoneOn_iff_forall_lt.mpr fun _ ha _ hb hab ↦ - inv_le_inv (sub_pos.mpr hb) (sub_pos.mpr ha) |>.mpr <| sub_le_sub (le_of_lt hab) le_rfl + inv_le_inv₀ (sub_pos.mpr hb) (sub_pos.mpr ha) |>.mpr <| sub_le_sub (le_of_lt hab) le_rfl theorem sub_inv_antitoneOn_Iio : AntitoneOn (fun x ↦ (x-c)⁻¹) (Set.Iio c) := @@ -709,11 +699,11 @@ theorem add_sub_div_two_lt (h : a < b) : a + (b - a) / 2 < b := by /-- An inequality involving `2`. -/ theorem sub_one_div_inv_le_two (a2 : 2 ≤ a) : (1 - 1 / a)⁻¹ ≤ 2 := by -- Take inverses on both sides to obtain `2⁻¹ ≤ 1 - 1 / a` - refine (inv_le_inv_of_le (inv_pos.2 <| zero_lt_two' α) ?_).trans_eq (inv_inv (2 : α)) + refine (inv_anti₀ (inv_pos.2 <| zero_lt_two' α) ?_).trans_eq (inv_inv (2 : α)) -- move `1 / a` to the left and `2⁻¹` to the right. rw [le_sub_iff_add_le, add_comm, ← le_sub_iff_add_le] -- take inverses on both sides and use the assumption `2 ≤ a`. - convert (one_div a).le.trans (inv_le_inv_of_le zero_lt_two a2) using 1 + convert (one_div a).le.trans (inv_anti₀ zero_lt_two a2) using 1 -- show `1 - 1 / 2 = 1 / 2`. rw [sub_eq_iff_eq_add, ← two_mul, mul_inv_cancel₀ two_ne_zero] diff --git a/Mathlib/Algebra/Order/Field/Canonical/Defs.lean b/Mathlib/Algebra/Order/Field/Canonical/Defs.lean index f09b170c98fab..0242074ec4697 100644 --- a/Mathlib/Algebra/Order/Field/Canonical/Defs.lean +++ b/Mathlib/Algebra/Order/Field/Canonical/Defs.lean @@ -23,7 +23,7 @@ class CanonicallyLinearOrderedSemifield (α : Type*) extends CanonicallyOrderedC instance (priority := 100) CanonicallyLinearOrderedSemifield.toLinearOrderedCommGroupWithZero [CanonicallyLinearOrderedSemifield α] : LinearOrderedCommGroupWithZero α := { ‹CanonicallyLinearOrderedSemifield α› with - mul_le_mul_left := fun a b h c ↦ mul_le_mul_of_nonneg_left h <| zero_le _ } + mul_le_mul_left := fun _ _ h _ ↦ mul_le_mul_of_nonneg_left h <| zero_le _ } -- See note [lower instance priority] instance (priority := 100) CanonicallyLinearOrderedSemifield.toCanonicallyLinearOrderedAddCommMonoid diff --git a/Mathlib/Algebra/Order/Field/Defs.lean b/Mathlib/Algebra/Order/Field/Defs.lean index ad7ae9d36bb7a..86284a304dde6 100644 --- a/Mathlib/Algebra/Order/Field/Defs.lean +++ b/Mathlib/Algebra/Order/Field/Defs.lean @@ -36,7 +36,7 @@ instance (priority := 100) LinearOrderedField.toLinearOrderedSemifield [LinearOr LinearOrderedSemifield α := { LinearOrderedRing.toLinearOrderedSemiring, ‹LinearOrderedField α› with } -variable [LinearOrderedSemifield α] {a b : α} +variable [LinearOrderedSemifield α] {a b c : α} /-- Equality holds when `a ≠ 0`. See `mul_inv_cancel`. -/ lemma mul_inv_le_one : a * a⁻¹ ≤ 1 := by obtain rfl | ha := eq_or_ne a 0 <;> simp [*] @@ -75,3 +75,27 @@ lemma inv_mul_right_le (ha : 0 ≤ a) : a * b⁻¹ * b ≤ a := by /-- Equality holds when `b ≠ 0`. See `inv_mul_cancel_right`. -/ lemma le_inv_mul_right (ha : a ≤ 0) : a ≤ a * b⁻¹ * b := by obtain rfl | hb := eq_or_ne b 0 <;> simp [*] + +/-- Equality holds when `c ≠ 0`. See `mul_div_mul_left`. -/ +lemma mul_div_mul_left_le (h : 0 ≤ a / b) : c * a / (c * b) ≤ a / b := by + obtain rfl | hc := eq_or_ne c 0 + · simpa + · rw [mul_div_mul_left _ _ hc] + +/-- Equality holds when `c ≠ 0`. See `mul_div_mul_left`. -/ +lemma le_mul_div_mul_left (h : a / b ≤ 0) : a / b ≤ c * a / (c * b) := by + obtain rfl | hc := eq_or_ne c 0 + · simpa + · rw [mul_div_mul_left _ _ hc] + +/-- Equality holds when `c ≠ 0`. See `mul_div_mul_right`. -/ +lemma mul_div_mul_right_le (h : 0 ≤ a / b) : a * c / (b * c) ≤ a / b := by + obtain rfl | hc := eq_or_ne c 0 + · simpa + · rw [mul_div_mul_right _ _ hc] + +/-- Equality holds when `c ≠ 0`. See `mul_div_mul_right`. -/ +lemma le_mul_div_mul_right (h : a / b ≤ 0) : a / b ≤ a * c / (b * c) := by + obtain rfl | hc := eq_or_ne c 0 + · simpa + · rw [mul_div_mul_right _ _ hc] diff --git a/Mathlib/Algebra/Order/Field/InjSurj.lean b/Mathlib/Algebra/Order/Field/InjSurj.lean index 73fb2c67d8eac..771fd9b18fbb1 100644 --- a/Mathlib/Algebra/Order/Field/InjSurj.lean +++ b/Mathlib/Algebra/Order/Field/InjSurj.lean @@ -13,7 +13,7 @@ import Mathlib.Algebra.Order.Ring.InjSurj open Function OrderDual -variable {ι α β : Type*} +variable {α β : Type*} namespace Function.Injective variable [Zero β] [One β] [Add β] [Mul β] [Neg β] [Sub β] [Pow β ℕ] [SMul ℕ β] [SMul ℤ β] diff --git a/Mathlib/Algebra/Order/Field/Power.lean b/Mathlib/Algebra/Order/Field/Power.lean index 70c83a1869e07..67ff27a9c705f 100644 --- a/Mathlib/Algebra/Order/Field/Power.lean +++ b/Mathlib/Algebra/Order/Field/Power.lean @@ -24,80 +24,68 @@ variable [LinearOrderedSemifield α] {a b c d e : α} {m n : ℤ} /-! ### Integer powers -/ -@[gcongr] -theorem zpow_le_of_le (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n := by - have ha₀ : 0 < a := one_pos.trans_le ha - lift n - m to ℕ using sub_nonneg.2 h with k hk - calc - a ^ m = a ^ m * 1 := (mul_one _).symm - _ ≤ a ^ m * a ^ k := - mul_le_mul_of_nonneg_left (one_le_pow₀ ha) (zpow_nonneg ha₀.le _) - _ = a ^ n := by rw [← zpow_natCast, ← zpow_add₀ ha₀.ne', hk, add_sub_cancel] +@[deprecated zpow_le_zpow_right₀ (since := "2024-10-08")] +theorem zpow_le_of_le (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n := zpow_le_zpow_right₀ ha h +@[deprecated zpow_le_one_of_nonpos₀ (since := "2024-10-08")] theorem zpow_le_one_of_nonpos (ha : 1 ≤ a) (hn : n ≤ 0) : a ^ n ≤ 1 := - (zpow_le_of_le ha hn).trans_eq <| zpow_zero _ + zpow_le_one_of_nonpos₀ ha hn +@[deprecated one_le_zpow₀ (since := "2024-10-08")] theorem one_le_zpow_of_nonneg (ha : 1 ≤ a) (hn : 0 ≤ n) : 1 ≤ a ^ n := - (zpow_zero _).symm.trans_le <| zpow_le_of_le ha hn + one_le_zpow₀ ha hn -protected theorem Nat.zpow_pos_of_pos {a : ℕ} (h : 0 < a) (n : ℤ) : 0 < (a : α) ^ n := by - apply zpow_pos_of_pos - exact mod_cast h +@[deprecated zpow_pos (since := "2024-10-08")] +protected theorem Nat.zpow_pos_of_pos {a : ℕ} (h : 0 < a) (n : ℤ) : 0 < (a : α) ^ n := + zpow_pos (mod_cast h) _ +@[deprecated zpow_ne_zero (since := "2024-10-08")] theorem Nat.zpow_ne_zero_of_pos {a : ℕ} (h : 0 < a) (n : ℤ) : (a : α) ^ n ≠ 0 := - (Nat.zpow_pos_of_pos h n).ne' + zpow_ne_zero _ (mod_cast h.ne') -theorem one_lt_zpow (ha : 1 < a) : ∀ n : ℤ, 0 < n → 1 < a ^ n - | (n : ℕ), h => (zpow_natCast _ _).symm.subst (one_lt_pow₀ ha <| Int.natCast_ne_zero.mp h.ne') - | -[_+1], h => ((Int.negSucc_not_pos _).mp h).elim +@[deprecated one_lt_zpow₀ (since := "2024-10-08")] +theorem one_lt_zpow (ha : 1 < a) (n : ℤ) (hn : 0 < n) : 1 < a ^ n := one_lt_zpow₀ ha hn +@[deprecated zpow_right_strictMono₀ (since := "2024-10-08")] theorem zpow_strictMono (hx : 1 < a) : StrictMono (a ^ · : ℤ → α) := - strictMono_int_of_lt_succ fun n => - have xpos : 0 < a := zero_lt_one.trans hx - calc - a ^ n < a ^ n * a := lt_mul_of_one_lt_right (zpow_pos_of_pos xpos _) hx - _ = a ^ (n + 1) := (zpow_add_one₀ xpos.ne' _).symm + zpow_right_strictMono₀ hx +@[deprecated zpow_right_strictAnti₀ (since := "2024-10-08")] theorem zpow_strictAnti (h₀ : 0 < a) (h₁ : a < 1) : StrictAnti (a ^ · : ℤ → α) := - strictAnti_int_of_succ_lt fun n => - calc - a ^ (n + 1) = a ^ n * a := zpow_add_one₀ h₀.ne' _ - _ < a ^ n * 1 := (mul_lt_mul_left <| zpow_pos_of_pos h₀ _).2 h₁ - _ = a ^ n := mul_one _ + zpow_right_strictAnti₀ h₀ h₁ -@[simp] +@[deprecated zpow_lt_zpow_iff_right₀ (since := "2024-10-08")] theorem zpow_lt_iff_lt (hx : 1 < a) : a ^ m < a ^ n ↔ m < n := - (zpow_strictMono hx).lt_iff_lt + zpow_lt_zpow_iff_right₀ hx -@[gcongr] alias ⟨_, GCongr.zpow_lt_of_lt⟩ := zpow_lt_iff_lt +@[deprecated (since := "2024-02-10")] alias ⟨_, zpow_lt_of_lt⟩ := zpow_lt_iff_lt -@[deprecated (since := "2024-02-10")] alias zpow_lt_of_lt := GCongr.zpow_lt_of_lt - -@[simp] +@[deprecated zpow_le_zpow_iff_right₀ (since := "2024-10-08")] theorem zpow_le_iff_le (hx : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := - (zpow_strictMono hx).le_iff_le + zpow_le_zpow_iff_right₀ hx -@[simp] +@[deprecated div_le_self (since := "2024-10-08")] theorem div_pow_le (ha : 0 ≤ a) (hb : 1 ≤ b) (k : ℕ) : a / b ^ k ≤ a := div_le_self ha <| one_le_pow₀ hb -theorem zpow_injective (h₀ : 0 < a) (h₁ : a ≠ 1) : Injective (a ^ · : ℤ → α) := by - rcases h₁.lt_or_lt with (H | H) - · exact (zpow_strictAnti h₀ H).injective - · exact (zpow_strictMono H).injective +@[deprecated zpow_right_injective₀ (since := "2024-10-08")] +theorem zpow_injective (h₀ : 0 < a) (h₁ : a ≠ 1) : Injective (a ^ · : ℤ → α) := + zpow_right_injective₀ h₀ h₁ -@[simp] +@[deprecated zpow_right_inj₀ (since := "2024-10-08")] theorem zpow_inj (h₀ : 0 < a) (h₁ : a ≠ 1) : a ^ m = a ^ n ↔ m = n := - (zpow_injective h₀ h₁).eq_iff + zpow_right_inj₀ h₀ h₁ +@[deprecated (since := "2024-10-08")] theorem zpow_le_max_of_min_le {x : α} (hx : 1 ≤ x) {a b c : ℤ} (h : min a b ≤ c) : x ^ (-c) ≤ max (x ^ (-a)) (x ^ (-b)) := - have : Antitone fun n : ℤ => x ^ (-n) := fun _ _ h => zpow_le_of_le hx (neg_le_neg h) + have : Antitone fun n : ℤ => x ^ (-n) := fun _ _ h => zpow_le_zpow_right₀ hx (neg_le_neg h) (this h).trans_eq this.map_min +@[deprecated (since := "2024-10-08")] theorem zpow_le_max_iff_min_le {x : α} (hx : 1 < x) {a b c : ℤ} : x ^ (-c) ≤ max (x ^ (-a)) (x ^ (-b)) ↔ min a b ≤ c := by - simp_rw [le_max_iff, min_le_iff, zpow_le_iff_le hx, neg_le_neg_iff] + simp_rw [le_max_iff, min_le_iff, zpow_le_zpow_iff_right₀ hx, neg_le_neg_iff] end LinearOrderedSemifield @@ -205,7 +193,7 @@ def evalZPow : PositivityExt where eval {u α} zα pα e := do let _a ← synthInstanceQ (q(LinearOrderedSemifield $α) : Q(Type u)) haveI' : $e =Q $a ^ $b := ⟨⟩ assumeInstancesCommute - pure (.positive q(zpow_pos_of_pos $pa $b)) + pure (.positive q(zpow_pos $pa $b)) catch e : Exception => trace[Tactic.positivity.failure] "{e.toMessageData}" let oα ← synthInstanceQ q(LinearOrderedSemifield $α) diff --git a/Mathlib/Algebra/Order/Field/Rat.lean b/Mathlib/Algebra/Order/Field/Rat.lean index 228df54d19272..7b6ba3bfd819a 100644 --- a/Mathlib/Algebra/Order/Field/Rat.lean +++ b/Mathlib/Algebra/Order/Field/Rat.lean @@ -32,25 +32,3 @@ end Rat -- instances for performance deriving instance CanonicallyLinearOrderedSemifield, LinearOrderedSemifield, LinearOrderedCommGroupWithZero for NNRat - -/-! ### Miscellaneous lemmas -/ - -namespace NNRat - -@[simp, norm_cast] lemma coe_inv (q : ℚ≥0) : ((q⁻¹ : ℚ≥0) : ℚ) = (q : ℚ)⁻¹ := rfl -@[simp, norm_cast] lemma coe_div (p q : ℚ≥0) : ((p / q : ℚ≥0) : ℚ) = p / q := rfl - -lemma inv_def (q : ℚ≥0) : q⁻¹ = divNat q.den q.num := by ext; simp [Rat.inv_def', num_coe, den_coe] -lemma div_def (p q : ℚ≥0) : p / q = divNat (p.num * q.den) (p.den * q.num) := by - ext; simp [Rat.div_def', num_coe, den_coe] - -lemma num_inv_of_ne_zero {q : ℚ≥0} (hq : q ≠ 0) : q⁻¹.num = q.den := by - rw [inv_def, divNat, num, coe_mk, Rat.divInt_ofNat, ← Rat.mk_eq_mkRat _ _ (num_ne_zero.mpr hq), - Int.natAbs_ofNat] - simpa using q.coprime_num_den.symm - -lemma den_inv_of_ne_zero {q : ℚ≥0} (hq : q ≠ 0) : q⁻¹.den = q.num := by - rw [inv_def, divNat, den, coe_mk, Rat.divInt_ofNat, ← Rat.mk_eq_mkRat _ _ (num_ne_zero.mpr hq)] - simpa using q.coprime_num_den.symm - -end NNRat diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 478a21d5d6e8c..a05e2fffee157 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -251,8 +251,6 @@ theorem preimage_floor_of_ne_zero {n : ℕ} (hn : n ≠ 0) : theorem lt_ceil : n < ⌈a⌉₊ ↔ (n : α) < a := lt_iff_lt_of_le_iff_le ceil_le --- porting note (#10618): simp can prove this --- @[simp] theorem add_one_le_ceil_iff : n + 1 ≤ ⌈a⌉₊ ↔ (n : α) < a := by rw [← Nat.lt_ceil, Nat.add_one_le_iff] @@ -924,8 +922,6 @@ theorem fract_ofNat (n : ℕ) [n.AtLeastTwo] : fract ((no_index (OfNat.ofNat n)) : α) = 0 := fract_natCast n --- porting note (#10618): simp can prove this --- @[simp] theorem fract_floor (a : α) : fract (⌊a⌋ : α) = 0 := fract_intCast _ @@ -1261,7 +1257,7 @@ lemma ceil_div_ceil_inv_sub_one (ha : 1 ≤ a) : ⌈⌈(a - 1)⁻¹⌉ / a⌉ = have : 0 < ⌈(a - 1)⁻¹⌉ := ceil_pos.2 <| by positivity refine le_antisymm (ceil_le.2 <| div_le_self (by positivity) ha.le) <| ?_ rw [le_ceil_iff, sub_lt_comm, div_eq_mul_inv, ← mul_one_sub, - ← lt_div_iff₀ (sub_pos.2 <| inv_lt_one ha)] + ← lt_div_iff₀ (sub_pos.2 <| inv_lt_one_of_one_lt₀ ha)] convert ceil_lt_add_one _ using 1 field_simp @@ -1584,7 +1580,7 @@ variable [LinearOrderedRing α] [FloorRing α] instance (priority := 100) FloorRing.toFloorSemiring : FloorSemiring α where floor a := ⌊a⌋.toNat ceil a := ⌈a⌉.toNat - floor_of_neg {a} ha := Int.toNat_of_nonpos (Int.floor_nonpos ha.le) + floor_of_neg {_} ha := Int.toNat_of_nonpos (Int.floor_nonpos ha.le) gc_floor {a n} ha := by rw [Int.le_toNat (Int.floor_nonneg.2 ha), Int.le_floor, Int.cast_natCast] gc_ceil a n := by rw [Int.toNat_le, Int.ceil_le, Int.cast_natCast] diff --git a/Mathlib/Algebra/Order/Floor/Prime.lean b/Mathlib/Algebra/Order/Floor/Prime.lean index f3545648ae511..506029de21811 100644 --- a/Mathlib/Algebra/Order/Floor/Prime.lean +++ b/Mathlib/Algebra/Order/Floor/Prime.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yuyang Zhao. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuyang Zhao -/ -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Infinite import Mathlib.Topology.Algebra.Order.Floor /-! diff --git a/Mathlib/Algebra/Order/Group/Abs.lean b/Mathlib/Algebra/Order/Group/Abs.lean index 9693c189cfb6c..06283c5ee633b 100644 --- a/Mathlib/Algebra/Order/Group/Abs.lean +++ b/Mathlib/Algebra/Order/Group/Abs.lean @@ -60,12 +60,12 @@ end LinearOrderedCommGroup section LinearOrderedAddCommGroup -variable [LinearOrderedAddCommGroup α] {a b c d : α} +variable [LinearOrderedAddCommGroup α] {a b c : α} -- Porting note: -- Lean can perfectly well find this instance, -- but in the rewrites below it is going looking for it without having fixed `α`. -example : CovariantClass α α (swap fun x y ↦ x + y) fun x y ↦ x ≤ y := inferInstance +example : AddRightMono α := inferInstance theorem abs_le : |a| ≤ b ↔ -b ≤ a ∧ a ≤ b := by rw [abs_le', and_comm, @neg_le α] @@ -79,14 +79,14 @@ theorem le_of_abs_le (h : |a| ≤ b) : a ≤ b := @[to_additive] theorem apply_abs_le_mul_of_one_le' {β : Type*} [MulOneClass β] [Preorder β] - [CovariantClass β β (· * ·) (· ≤ ·)] [CovariantClass β β (swap (· * ·)) (· ≤ ·)] {f : α → β} + [MulLeftMono β] [MulRightMono β] {f : α → β} {a : α} (h₁ : 1 ≤ f a) (h₂ : 1 ≤ f (-a)) : f |a| ≤ f a * f (-a) := (le_total a 0).rec (fun ha => (abs_of_nonpos ha).symm ▸ le_mul_of_one_le_left' h₁) fun ha => (abs_of_nonneg ha).symm ▸ le_mul_of_one_le_right' h₂ @[to_additive] theorem apply_abs_le_mul_of_one_le {β : Type*} [MulOneClass β] [Preorder β] - [CovariantClass β β (· * ·) (· ≤ ·)] [CovariantClass β β (swap (· * ·)) (· ≤ ·)] {f : α → β} + [MulLeftMono β] [MulRightMono β] {f : α → β} (h : ∀ x, 1 ≤ f x) (a : α) : f |a| ≤ f a * f (-a) := apply_abs_le_mul_of_one_le' (h _) (h _) diff --git a/Mathlib/Algebra/Order/Group/Basic.lean b/Mathlib/Algebra/Order/Group/Basic.lean index bc99b34b1b895..09aac4f739e3c 100644 --- a/Mathlib/Algebra/Order/Group/Basic.lean +++ b/Mathlib/Algebra/Order/Group/Basic.lean @@ -15,7 +15,7 @@ assert_not_exists Set.Subsingleton open Function Int -variable {α M R : Type*} +variable {α : Type*} section OrderedCommGroup variable [OrderedCommGroup α] {m n : ℤ} {a b : α} diff --git a/Mathlib/Algebra/Order/Group/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/CompleteLattice.lean index 19c8f5fda8e68..69e9649b537de 100644 --- a/Mathlib/Algebra/Order/Group/CompleteLattice.lean +++ b/Mathlib/Algebra/Order/Group/CompleteLattice.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury G. Kudryashov -/ import Mathlib.Algebra.Order.Group.OrderIso -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed /-! # Distributivity of group operations over supremum/infimum @@ -15,7 +15,7 @@ open Function Set variable {ι G : Type*} [Group G] [ConditionallyCompleteLattice G] [Nonempty ι] {f : ι → G} section Right -variable [CovariantClass G G (swap (· * ·)) (· ≤ ·)] +variable [MulRightMono G] @[to_additive] lemma ciSup_mul (hf : BddAbove (range f)) (a : G) : (⨆ i, f i) * a = ⨆ i, f i * a := @@ -36,7 +36,7 @@ lemma ciInf_div (hf : BddBelow (range f)) (a : G) : (⨅ i, f i) / a = ⨅ i, f end Right section Left -variable [CovariantClass G G (· * ·) (· ≤ ·)] +variable [MulLeftMono G] @[to_additive] lemma mul_ciSup (hf : BddAbove (range f)) (a : G) : (a * ⨆ i, f i) = ⨆ i, a * f i := diff --git a/Mathlib/Algebra/Order/Group/Cone.lean b/Mathlib/Algebra/Order/Group/Cone.lean index 59f273599f45a..5f110e86b0c0e 100644 --- a/Mathlib/Algebra/Order/Group/Cone.lean +++ b/Mathlib/Algebra/Order/Group/Cone.lean @@ -24,7 +24,7 @@ class AddGroupConeClass (S : Type*) (G : outParam Type*) [AddCommGroup G] [SetLi /-- `GroupConeClass S G` says that `S` is a type of cones in `G`. -/ @[to_additive] -class GroupConeClass (S G : Type*) [CommGroup G] [SetLike S G] extends +class GroupConeClass (S : Type*) (G : outParam Type*) [CommGroup G] [SetLike S G] extends SubmonoidClass S G : Prop where eq_one_of_mem_of_inv_mem {C : S} {a : G} : a ∈ C → a⁻¹ ∈ C → a = 1 @@ -117,4 +117,4 @@ def LinearOrderedCommGroup.mkOfCone LinearOrderedCommGroup G where __ := OrderedCommGroup.mkOfCone C le_total a b := by simpa using mem_or_inv_mem (b / a) - decidableLE a b := dec _ + decidableLE _ _ := dec _ diff --git a/Mathlib/Algebra/Order/Group/Defs.lean b/Mathlib/Algebra/Order/Group/Defs.lean index 53b53337c45d3..d18bd57fc7cfe 100644 --- a/Mathlib/Algebra/Order/Group/Defs.lean +++ b/Mathlib/Algebra/Order/Group/Defs.lean @@ -46,18 +46,18 @@ class OrderedCommGroup (α : Type u) extends CommGroup α, PartialOrder α where attribute [to_additive] OrderedCommGroup @[to_additive] -instance OrderedCommGroup.to_covariantClass_left_le (α : Type u) [OrderedCommGroup α] : - CovariantClass α α (· * ·) (· ≤ ·) where +instance OrderedCommGroup.toMulLeftMono (α : Type u) [OrderedCommGroup α] : + MulLeftMono α where elim a b c bc := OrderedCommGroup.mul_le_mul_left b c bc a -- See note [lower instance priority] @[to_additive OrderedAddCommGroup.toOrderedCancelAddCommMonoid] instance (priority := 100) OrderedCommGroup.toOrderedCancelCommMonoid [OrderedCommGroup α] : OrderedCancelCommMonoid α := -{ ‹OrderedCommGroup α› with le_of_mul_le_mul_left := fun a b c ↦ le_of_mul_le_mul_left' } +{ ‹OrderedCommGroup α› with le_of_mul_le_mul_left := fun _ _ _ ↦ le_of_mul_le_mul_left' } -example (α : Type u) [OrderedAddCommGroup α] : CovariantClass α α (swap (· + ·)) (· < ·) := - IsRightCancelAdd.covariant_swap_add_lt_of_covariant_swap_add_le α +example (α : Type u) [OrderedAddCommGroup α] : AddRightStrictMono α := + inferInstance -- Porting note: this instance is not used, -- and causes timeouts after lean4#2210. @@ -65,17 +65,17 @@ example (α : Type u) [OrderedAddCommGroup α] : CovariantClass α α (swap (· -- but without the motivation clearly explained. /-- A choice-free shortcut instance. -/ @[to_additive "A choice-free shortcut instance."] -theorem OrderedCommGroup.to_contravariantClass_left_le (α : Type u) [OrderedCommGroup α] : - ContravariantClass α α (· * ·) (· ≤ ·) where +theorem OrderedCommGroup.toMulLeftReflectLE (α : Type u) [OrderedCommGroup α] : + MulLeftReflectLE α where elim a b c bc := by simpa using mul_le_mul_left' bc a⁻¹ -- Porting note: this instance is not used, -- and causes timeouts after lean4#2210. --- See further explanation on `OrderedCommGroup.to_contravariantClass_left_le`. +-- See further explanation on `OrderedCommGroup.toMulLeftReflectLE`. /-- A choice-free shortcut instance. -/ @[to_additive "A choice-free shortcut instance."] -theorem OrderedCommGroup.to_contravariantClass_right_le (α : Type u) [OrderedCommGroup α] : - ContravariantClass α α (swap (· * ·)) (· ≤ ·) where +theorem OrderedCommGroup.toMulRightReflectLE (α : Type u) [OrderedCommGroup α] : + MulRightReflectLE α where elim a b c bc := by simpa using mul_le_mul_right' bc a⁻¹ alias OrderedCommGroup.mul_lt_mul_left' := mul_lt_mul_left' @@ -109,7 +109,7 @@ class LinearOrderedCommGroup (α : Type u) extends OrderedCommGroup α, LinearOr section LinearOrderedCommGroup -variable [LinearOrderedCommGroup α] {a b c : α} +variable [LinearOrderedCommGroup α] {a : α} @[to_additive LinearOrderedAddCommGroup.add_lt_add_left] theorem LinearOrderedCommGroup.mul_lt_mul_left' (a b : α) (h : a < b) (c : α) : c * a < c * b := diff --git a/Mathlib/Algebra/Order/Group/DenselyOrdered.lean b/Mathlib/Algebra/Order/Group/DenselyOrdered.lean index 5548fdf7d08d1..70408fea662ab 100644 --- a/Mathlib/Algebra/Order/Group/DenselyOrdered.lean +++ b/Mathlib/Algebra/Order/Group/DenselyOrdered.lean @@ -17,8 +17,8 @@ variable {α : Type*} section DenselyOrdered variable [Group α] [LinearOrder α] -variable [CovariantClass α α (· * ·) (· ≤ ·)] -variable [DenselyOrdered α] {a b c : α} +variable [MulLeftMono α] +variable [DenselyOrdered α] {a b : α} @[to_additive] theorem le_of_forall_lt_one_mul_le (h : ∀ ε < 1, a * ε ≤ b) : a ≤ b := diff --git a/Mathlib/Algebra/Order/Group/Indicator.lean b/Mathlib/Algebra/Order/Group/Indicator.lean index a8e229c800374..cc07de02c0ed9 100644 --- a/Mathlib/Algebra/Order/Group/Indicator.lean +++ b/Mathlib/Algebra/Order/Group/Indicator.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Indicator -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Algebra.Order.Group.Defs import Mathlib.Algebra.Order.Group.Synonym import Mathlib.Algebra.Order.Group.Unbundled.Abs diff --git a/Mathlib/Algebra/Order/Group/Lattice.lean b/Mathlib/Algebra/Order/Group/Lattice.lean index d8a8bf48a1b20..8260bbb4f5c92 100644 --- a/Mathlib/Algebra/Order/Group/Lattice.lean +++ b/Mathlib/Algebra/Order/Group/Lattice.lean @@ -14,8 +14,8 @@ underpinnings of vector lattices, Banach lattices, AL-space, AM-space etc. A lattice ordered group is a type `α` satisfying: * `Lattice α` * `CommGroup α` -* `CovariantClass α α (· * ·) (· ≤ ·)` -* `CovariantClass α α (swap (· * ·)) (· ≤ ·)` +* `MulLeftMono α` +* `MulRightMono α` This file establishes basic properties of lattice ordered groups. It is shown that when the group is commutative, the lattice is distributive. This also holds in the non-commutative case @@ -37,44 +37,44 @@ lattice, order, group open Function -variable {α β : Type*} +variable {α : Type*} section Group variable [Lattice α] [Group α] -- Special case of Bourbaki A.VI.9 (1) @[to_additive] -lemma mul_sup [CovariantClass α α (· * ·) (· ≤ ·)] (a b c : α) : +lemma mul_sup [MulLeftMono α] (a b c : α) : c * (a ⊔ b) = c * a ⊔ c * b := (OrderIso.mulLeft _).map_sup _ _ @[to_additive] -lemma sup_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : +lemma sup_mul [MulRightMono α] (a b c : α) : (a ⊔ b) * c = a * c ⊔ b * c := (OrderIso.mulRight _).map_sup _ _ @[to_additive] -lemma mul_inf [CovariantClass α α (· * ·) (· ≤ ·)] (a b c : α) : +lemma mul_inf [MulLeftMono α] (a b c : α) : c * (a ⊓ b) = c * a ⊓ c * b := (OrderIso.mulLeft _).map_inf _ _ @[to_additive] -lemma inf_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : +lemma inf_mul [MulRightMono α] (a b c : α) : (a ⊓ b) * c = a * c ⊓ b * c := (OrderIso.mulRight _).map_inf _ _ @[to_additive] -lemma sup_div [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : +lemma sup_div [MulRightMono α] (a b c : α) : (a ⊔ b) / c = a / c ⊔ b / c := (OrderIso.divRight _).map_sup _ _ @[to_additive] -lemma inf_div [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : +lemma inf_div [MulRightMono α] (a b c : α) : (a ⊓ b) / c = a / c ⊓ b / c := (OrderIso.divRight _).map_inf _ _ section -variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulLeftMono α] [MulRightMono α] @[to_additive] lemma inv_sup (a b : α) : (a ⊔ b)⁻¹ = a⁻¹ ⊓ b⁻¹ := (OrderIso.inv α).map_sup _ _ @@ -106,7 +106,7 @@ variable [Lattice α] [CommGroup α] -- Fuchs p67 -- Bourbaki A.VI.10 Prop 7 @[to_additive] -lemma inf_mul_sup [CovariantClass α α (· * ·) (· ≤ ·)] (a b : α) : (a ⊓ b) * (a ⊔ b) = a * b := +lemma inf_mul_sup [MulLeftMono α] (a b : α) : (a ⊓ b) * (a ⊔ b) = a * b := calc (a ⊓ b) * (a ⊔ b) = (a ⊓ b) * (a * b * (b⁻¹ ⊔ a⁻¹)) := by rw [mul_sup b⁻¹ a⁻¹ (a * b), mul_inv_cancel_right, mul_inv_cancel_comm] @@ -117,7 +117,7 @@ lemma inf_mul_sup [CovariantClass α α (· * ·) (· ≤ ·)] (a b : α) : (a -- Non-comm case needs cancellation law https://ncatlab.org/nlab/show/distributive+lattice @[to_additive "Every lattice ordered commutative additive group is a distributive lattice"] def CommGroup.toDistribLattice (α : Type*) [Lattice α] [CommGroup α] - [CovariantClass α α (· * ·) (· ≤ ·)] : DistribLattice α where + [MulLeftMono α] : DistribLattice α where le_sup_inf x y z := by rw [← mul_le_mul_iff_left (x ⊓ (y ⊓ z)), inf_mul_sup x (y ⊓ z), ← inv_mul_le_iff_le_mul, le_inf_iff] diff --git a/Mathlib/Algebra/Order/Group/MinMax.lean b/Mathlib/Algebra/Order/Group/MinMax.lean index adf6af1c4b904..06f9007ec5e6f 100644 --- a/Mathlib/Algebra/Order/Group/MinMax.lean +++ b/Mathlib/Algebra/Order/Group/MinMax.lean @@ -13,7 +13,7 @@ import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax section -variable {α : Type*} [Group α] [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] +variable {α : Type*} [Group α] [LinearOrder α] [MulLeftMono α] -- TODO: This duplicates `oneLePart_div_leOnePart` @[to_additive (attr := simp)] @@ -35,14 +35,12 @@ variable {α : Type*} [LinearOrderedCommGroup α] @[to_additive min_neg_neg] theorem min_inv_inv' (a b : α) : min a⁻¹ b⁻¹ = (max a b)⁻¹ := Eq.symm <| (@Monotone.map_max α αᵒᵈ _ _ Inv.inv a b) fun _ _ => - -- Porting note: Explicit `α` necessary to infer `CovariantClass` instance - (@inv_le_inv_iff α _ _ _).mpr + inv_le_inv_iff.mpr @[to_additive max_neg_neg] theorem max_inv_inv' (a b : α) : max a⁻¹ b⁻¹ = (min a b)⁻¹ := Eq.symm <| (@Monotone.map_min α αᵒᵈ _ _ Inv.inv a b) fun _ _ => - -- Porting note: Explicit `α` necessary to infer `CovariantClass` instance - (@inv_le_inv_iff α _ _ _).mpr + inv_le_inv_iff.mpr @[to_additive min_sub_sub_right] theorem min_div_div_right' (a b c : α) : min (a / c) (b / c) = min a b / c := by diff --git a/Mathlib/Algebra/Order/Group/OrderIso.lean b/Mathlib/Algebra/Order/Group/OrderIso.lean index f4cd51d207bb2..21e6893bb45b5 100644 --- a/Mathlib/Algebra/Order/Group/OrderIso.lean +++ b/Mathlib/Algebra/Order/Group/OrderIso.lean @@ -24,8 +24,7 @@ variable [Group α] section TypeclassesLeftRightLE -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] - {a b c d : α} +variable [LE α] [MulLeftMono α] [MulRightMono α] {a b : α} section @@ -71,7 +70,7 @@ variable [Group α] [LE α] section Right -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +variable [MulRightMono α] {a : α} /-- `Equiv.mulRight` as an `OrderIso`. See also `OrderEmbedding.mulRight`. -/ @[to_additive (attr := simps! (config := { simpRhs := true }) toEquiv apply) @@ -95,7 +94,7 @@ end Right section Left -variable [CovariantClass α α (· * ·) (· ≤ ·)] +variable [MulLeftMono α] /-- `Equiv.mulLeft` as an `OrderIso`. See also `OrderEmbedding.mulLeft`. -/ @[to_additive (attr := simps! (config := { simpRhs := true }) toEquiv apply) diff --git a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean index 1b1e0d3b70882..d7e523a2a6595 100644 --- a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean +++ b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean @@ -21,8 +21,8 @@ open scoped Pointwise variable {ι G M : Type*} section Mul -variable [Mul M] [Preorder M] [CovariantClass M M (· * ·) (· ≤ ·)] - [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {f g : ι → M} {s t : Set M} {a b : M} +variable [Mul M] [Preorder M] [MulLeftMono M] + [MulRightMono M] {f g : ι → M} {s t : Set M} {a b : M} @[to_additive] lemma mul_mem_upperBounds_mul (ha : a ∈ upperBounds s) (hb : b ∈ upperBounds t) : @@ -61,8 +61,8 @@ lemma BddBelow.range_mul (hf : BddBelow (range f)) (hg : BddBelow (range g)) : end Mul section InvNeg -variable [Group G] [Preorder G] [CovariantClass G G (· * ·) (· ≤ ·)] - [CovariantClass G G (swap (· * ·)) (· ≤ ·)] {s : Set G} {a : G} +variable [Group G] [Preorder G] [MulLeftMono G] + [MulRightMono G] {s : Set G} {a : G} @[to_additive (attr := simp)] theorem bddAbove_inv : BddAbove s⁻¹ ↔ BddBelow s := diff --git a/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean index 6f09d373cffd4..64ef925d173b5 100644 --- a/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean +++ b/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Order.Group.Pointwise.Bounds -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed /-! # Infima/suprema in ordered monoids and groups @@ -34,7 +34,7 @@ variable [One M] end One section Group -variable [Group M] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] +variable [Group M] [MulLeftMono M] [MulRightMono M] {s t : Set M} @[to_additive] @@ -84,7 +84,7 @@ variable [One M] end One section Group -variable [Group M] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] +variable [Group M] [MulLeftMono M] [MulRightMono M] (s t : Set M) @[to_additive] diff --git a/Mathlib/Algebra/Order/Group/PosPart.lean b/Mathlib/Algebra/Order/Group/PosPart.lean index b8af733a70b23..3fae44d631e4e 100644 --- a/Mathlib/Algebra/Order/Group/PosPart.lean +++ b/Mathlib/Algebra/Order/Group/PosPart.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Christopher Hoskin, Yaël Dillies -/ import Mathlib.Algebra.Order.Group.Unbundled.Abs +import Mathlib.Algebra.Notation /-! # Positive & negative parts @@ -12,8 +13,8 @@ Mathematical structures possessing an absolute value often also possess a unique elements into "positive" and "negative" parts which are in some sense "disjoint" (e.g. the Jordan decomposition of a measure). -This file defines `posPart` and `negPart`, the positive and negative parts of an element in a -lattice ordered group. +This file provides instances of `PosPart` and `NegPart`, the positive and negative parts of an +element in a lattice ordered group. ## Main statements @@ -21,13 +22,6 @@ lattice ordered group. positive and negative parts. * `posPart_inf_negPart_eq_zero`: The positive and negative parts are coprime. -## Notations - -* `a⁺ᵐ = a ⊔ 1`: *Positive component* of an element `a` of a multiplicative lattice ordered group -* `a⁻ᵐ = a⁻¹ ⊔ 1`: *Negative component* of an element `a` of a multiplicative lattice ordered group -* `a⁺ = a ⊔ 0`: *Positive component* of an element `a` of a lattice ordered group -* `a⁻ = (-a) ⊔ 0`: *Negative component* of an element `a` of a lattice ordered group - ## References * [Birkhoff, Lattice-ordered Groups][birkhoff1942] @@ -43,7 +37,7 @@ positive part, negative part open Function -variable {α β : Type*} +variable {α : Type*} section Lattice variable [Lattice α] @@ -54,23 +48,24 @@ variable [Group α] {a b : α} /-- The *positive part* of an element `a` in a lattice ordered group is `a ⊔ 1`, denoted `a⁺ᵐ`. -/ @[to_additive "The *positive part* of an element `a` in a lattice ordered group is `a ⊔ 0`, denoted `a⁺`."] -def oneLePart (a : α) : α := a ⊔ 1 +instance instOneLePart : OneLePart α where + oneLePart a := a ⊔ 1 /-- The *negative part* of an element `a` in a lattice ordered group is `a⁻¹ ⊔ 1`, denoted `a⁻ᵐ `. -/ @[to_additive "The *negative part* of an element `a` in a lattice ordered group is `(-a) ⊔ 0`, denoted `a⁻`."] -def leOnePart (a : α) : α := a⁻¹ ⊔ 1 +instance instLeOnePart : LeOnePart α where + leOnePart a := a⁻¹ ⊔ 1 + +@[to_additive] lemma leOnePart_def (a : α) : a⁻ᵐ = a⁻¹ ⊔ 1 := rfl -@[inherit_doc] postfix:max "⁺ᵐ " => oneLePart -@[inherit_doc] postfix:max "⁻ᵐ" => leOnePart -@[inherit_doc] postfix:max "⁺" => posPart -@[inherit_doc] postfix:max "⁻" => negPart +@[to_additive] lemma oneLePart_def (a : α) : a⁺ᵐ = a ⊔ 1 := rfl -@[to_additive] lemma oneLePart_mono : Monotone (oneLePart : α → α) := +@[to_additive] lemma oneLePart_mono : Monotone (·⁺ᵐ : α → α) := fun _a _b hab ↦ sup_le_sup_right hab _ -@[to_additive (attr := simp)] lemma oneLePart_one : (1 : α)⁺ᵐ = 1 := sup_idem _ +@[to_additive (attr := simp high)] lemma oneLePart_one : (1 : α)⁺ᵐ = 1 := sup_idem _ @[to_additive (attr := simp)] lemma leOnePart_one : (1 : α)⁻ᵐ = 1 := by simp [leOnePart] @@ -84,8 +79,10 @@ def leOnePart (a : α) : α := a⁻¹ ⊔ 1 @[to_additive] lemma inv_le_leOnePart (a : α) : a⁻¹ ≤ a⁻ᵐ := le_sup_left @[to_additive (attr := simp)] lemma oneLePart_eq_self : a⁺ᵐ = a ↔ 1 ≤ a := sup_eq_left +@[to_additive (attr := simp)] lemma oneLePart_eq_one : a⁺ᵐ = 1 ↔ a ≤ 1 := sup_eq_right -@[to_additive] lemma oneLePart_eq_one : a⁺ᵐ = 1 ↔ a ≤ 1 := sup_eq_right +@[to_additive (attr := simp)] alias ⟨_, oneLePart_of_one_le⟩ := oneLePart_eq_self +@[to_additive (attr := simp)] alias ⟨_, oneLePart_of_le_one⟩ := oneLePart_eq_one /-- See also `leOnePart_eq_inv`. -/ @[to_additive "See also `negPart_eq_neg`."] @@ -111,21 +108,24 @@ lemma leOnePart_le_one' : a⁻ᵐ ≤ 1 ↔ a⁻¹ ≤ 1 := by simp [leOnePart] @[to_additive (attr := simp)] lemma leOnePart_inv (a : α) : a⁻¹⁻ᵐ = a⁺ᵐ := by simp [oneLePart, leOnePart] -section covariantmul -variable [CovariantClass α α (· * ·) (· ≤ ·)] +section MulLeftMono +variable [MulLeftMono α] @[to_additive (attr := simp)] lemma leOnePart_eq_inv : a⁻ᵐ = a⁻¹ ↔ a ≤ 1 := by simp [leOnePart] @[to_additive (attr := simp)] lemma leOnePart_eq_one : a⁻ᵐ = 1 ↔ 1 ≤ a := by simp [leOnePart_eq_one'] +@[to_additive (attr := simp)] alias ⟨_, leOnePart_of_le_one⟩ := leOnePart_eq_inv +@[to_additive (attr := simp)] alias ⟨_, leOnePart_of_one_le⟩ := leOnePart_eq_one + @[to_additive (attr := simp) negPart_pos] lemma one_lt_ltOnePart (ha : a < 1) : 1 < a⁻ᵐ := by rwa [leOnePart_eq_inv.2 ha.le, one_lt_inv'] -- Bourbaki A.VI.12 Prop 9 a) @[to_additive (attr := simp)] lemma oneLePart_div_leOnePart (a : α) : a⁺ᵐ / a⁻ᵐ = a := by - rw [div_eq_mul_inv, mul_inv_eq_iff_eq_mul, leOnePart, mul_sup, mul_one, mul_inv_cancel, sup_comm, - oneLePart] + rw [div_eq_mul_inv, mul_inv_eq_iff_eq_mul, leOnePart_def, mul_sup, mul_one, mul_inv_cancel, + sup_comm, oneLePart_def] @[to_additive (attr := simp)] lemma leOnePart_div_oneLePart (a : α) : a⁻ᵐ / a⁺ᵐ = a⁻¹ := by rw [← inv_div, oneLePart_div_leOnePart] @@ -140,24 +140,24 @@ lemma oneLePart_leOnePart_injective : Injective fun a : α ↦ (a⁺ᵐ, a⁻ᵐ lemma oneLePart_leOnePart_inj : a⁺ᵐ = b⁺ᵐ ∧ a⁻ᵐ = b⁻ᵐ ↔ a = b := Prod.mk.inj_iff.symm.trans oneLePart_leOnePart_injective.eq_iff -section covariantmulop -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +section MulRightMono +variable [MulRightMono α] @[to_additive] lemma leOnePart_anti : Antitone (leOnePart : α → α) := fun _a _b hab ↦ sup_le_sup_right (inv_le_inv_iff.2 hab) _ @[to_additive] lemma leOnePart_eq_inv_inf_one (a : α) : a⁻ᵐ = (a ⊓ 1)⁻¹ := by - rw [leOnePart, ← inv_inj, inv_sup, inv_inv, inv_inv, inv_one] + rw [leOnePart_def, ← inv_inj, inv_sup, inv_inv, inv_inv, inv_one] -- Bourbaki A.VI.12 Prop 9 d) @[to_additive] lemma oneLePart_mul_leOnePart (a : α) : a⁺ᵐ * a⁻ᵐ = |a|ₘ := by - rw [oneLePart, sup_mul, one_mul, leOnePart, mul_sup, mul_one, mul_inv_cancel, sup_assoc, + rw [oneLePart_def, sup_mul, one_mul, leOnePart_def, mul_sup, mul_one, mul_inv_cancel, sup_assoc, ← sup_assoc a, sup_eq_right.2 le_sup_right] exact sup_eq_left.2 <| one_le_mabs a @[to_additive] lemma leOnePart_mul_oneLePart (a : α) : a⁻ᵐ * a⁺ᵐ = |a|ₘ := by - rw [oneLePart, mul_sup, mul_one, leOnePart, sup_mul, one_mul, inv_mul_cancel, sup_assoc, + rw [oneLePart_def, mul_sup, mul_one, leOnePart_def, sup_mul, one_mul, inv_mul_cancel, sup_assoc, ← @sup_assoc _ _ a, sup_eq_right.2 le_sup_right] exact sup_eq_left.2 <| one_le_mabs a @@ -167,14 +167,14 @@ lemma leOnePart_eq_inv_inf_one (a : α) : a⁻ᵐ = (a ⊓ 1)⁻¹ := by rw [← mul_left_inj a⁻ᵐ⁻¹, inf_mul, one_mul, mul_inv_cancel, ← div_eq_mul_inv, oneLePart_div_leOnePart, leOnePart_eq_inv_inf_one, inv_inv] -end covariantmulop +end MulRightMono -end covariantmul +end MulLeftMono end Group section CommGroup -variable [CommGroup α] [CovariantClass α α (· * ·) (· ≤ ·)] +variable [CommGroup α] [MulLeftMono α] -- Bourbaki A.VI.12 (with a and b swapped) @[to_additive] lemma sup_eq_mul_oneLePart_div (a b : α) : a ⊔ b = b * (a / b)⁺ᵐ := by @@ -213,27 +213,27 @@ section LinearOrder variable [LinearOrder α] [Group α] {a b : α} @[to_additive] lemma oneLePart_eq_ite : a⁺ᵐ = if 1 ≤ a then a else 1 := by - rw [oneLePart, ← maxDefault, ← sup_eq_maxDefault]; simp_rw [sup_comm] + rw [oneLePart_def, ← maxDefault, ← sup_eq_maxDefault]; simp_rw [sup_comm] @[to_additive (attr := simp) posPart_pos_iff] lemma one_lt_oneLePart_iff : 1 < a⁺ᵐ ↔ 1 < a := lt_iff_lt_of_le_iff_le <| (one_le_oneLePart _).le_iff_eq.trans oneLePart_eq_one @[to_additive posPart_eq_of_posPart_pos] lemma oneLePart_of_one_lt_oneLePart (ha : 1 < a⁺ᵐ) : a⁺ᵐ = a := by - rw [oneLePart, right_lt_sup, not_le] at ha; exact oneLePart_eq_self.2 ha.le + rw [oneLePart_def, right_lt_sup, not_le] at ha; exact oneLePart_eq_self.2 ha.le @[to_additive (attr := simp)] lemma oneLePart_lt : a⁺ᵐ < b ↔ a < b ∧ 1 < b := sup_lt_iff section covariantmul -variable [CovariantClass α α (· * ·) (· ≤ ·)] +variable [MulLeftMono α] @[to_additive] lemma leOnePart_eq_ite : a⁻ᵐ = if a ≤ 1 then a⁻¹ else 1 := by - simp_rw [← one_le_inv']; rw [leOnePart, ← maxDefault, ← sup_eq_maxDefault]; simp_rw [sup_comm] + simp_rw [← one_le_inv']; rw [leOnePart_def, ← maxDefault, ← sup_eq_maxDefault]; simp_rw [sup_comm] @[to_additive (attr := simp) negPart_pos_iff] lemma one_lt_ltOnePart_iff : 1 < a⁻ᵐ ↔ a < 1 := lt_iff_lt_of_le_iff_le <| (one_le_leOnePart _).le_iff_eq.trans leOnePart_eq_one -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulRightMono α] @[to_additive (attr := simp)] lemma leOnePart_lt : a⁻ᵐ < b ↔ b⁻¹ < a ∧ 1 < b := sup_lt_iff.trans <| by rw [inv_lt'] @@ -242,12 +242,12 @@ end covariantmul end LinearOrder namespace Pi -variable {ι : Type*} {α : ι → Type*} [∀ i, Lattice (α i)] [∀ i, AddCommGroup (α i)] +variable {ι : Type*} {α : ι → Type*} [∀ i, Lattice (α i)] [∀ i, Group (α i)] -@[to_additive (attr := simp)] lemma oneLePart_apply (f : ∀ i, α i) (i : ι) : f⁺ i = (f i)⁺ := rfl -@[to_additive (attr := simp)] lemma leOnePart_apply (f : ∀ i, α i) (i : ι) : f⁻ i = (f i)⁻ := rfl +@[to_additive (attr := simp)] lemma oneLePart_apply (f : ∀ i, α i) (i : ι) : f⁺ᵐ i = (f i)⁺ᵐ := rfl +@[to_additive (attr := simp)] lemma leOnePart_apply (f : ∀ i, α i) (i : ι) : f⁻ᵐ i = (f i)⁻ᵐ := rfl -@[to_additive] lemma oneLePart_def (f : ∀ i, α i) : f⁺ = fun i ↦ (f i)⁺ := rfl -@[to_additive] lemma leOnePart_def (f : ∀ i, α i) : f⁻ = fun i ↦ (f i)⁻ := rfl +@[to_additive] lemma oneLePart_def (f : ∀ i, α i) : f⁺ᵐ = fun i ↦ (f i)⁺ᵐ := rfl +@[to_additive] lemma leOnePart_def (f : ∀ i, α i) : f⁻ᵐ = fun i ↦ (f i)⁻ᵐ := rfl end Pi diff --git a/Mathlib/Algebra/Order/Group/Prod.lean b/Mathlib/Algebra/Order/Group/Prod.lean index 3d325521fa712..9faaea7bf1205 100644 --- a/Mathlib/Algebra/Order/Group/Prod.lean +++ b/Mathlib/Algebra/Order/Group/Prod.lean @@ -11,8 +11,6 @@ import Mathlib.Algebra.Order.Monoid.Prod -/ -variable {α : Type*} - namespace Prod variable {G H : Type*} diff --git a/Mathlib/Algebra/Order/Group/Unbundled/Abs.lean b/Mathlib/Algebra/Order/Group/Unbundled/Abs.lean index 5ad660f7f4f37..d5bc417fef884 100644 --- a/Mathlib/Algebra/Order/Group/Unbundled/Abs.lean +++ b/Mathlib/Algebra/Order/Group/Unbundled/Abs.lean @@ -70,7 +70,7 @@ def abs.unexpander : Lean.PrettyPrinter.Unexpander @[to_additive] lemma mabs_div_comm (a b : α) : |a / b|ₘ = |b / a|ₘ := by rw [← mabs_inv, inv_div] -variable [CovariantClass α α (· * ·) (· ≤ ·)] +variable [MulLeftMono α] @[to_additive] lemma mabs_of_one_le (h : 1 ≤ a) : |a|ₘ = a := sup_eq_left.2 <| (inv_le_one'.2 h).trans h @@ -89,7 +89,7 @@ attribute [gcongr] abs_le_abs_of_nonneg @[to_additive (attr := simp)] lemma mabs_one : |(1 : α)|ₘ = 1 := mabs_of_one_le le_rfl -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulRightMono α] @[to_additive (attr := simp) abs_nonneg] lemma one_le_mabs (a : α) : 1 ≤ |a|ₘ := by apply pow_two_semiclosed _ @@ -102,7 +102,7 @@ variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] end Group section CommGroup -variable [CommGroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} +variable [CommGroup α] [MulLeftMono α] -- Banasiak Proposition 2.12, Zaanen 2nd lecture /-- The absolute value satisfies the triangle inequality. -/ @@ -204,7 +204,7 @@ variable [Group α] [LinearOrder α] {a b : α} @[to_additive] lemma lt_of_mabs_lt : |a|ₘ < b → a < b := (le_mabs_self _).trans_lt -variable [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} +variable [MulLeftMono α] {a b : α} @[to_additive (attr := simp) abs_pos] lemma one_lt_mabs : 1 < |a|ₘ ↔ a ≠ 1 := by obtain ha | rfl | ha := lt_trichotomy a 1 @@ -228,7 +228,7 @@ variable [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} @[to_additive] lemma inv_mabs_le_inv (a : α) : |a|ₘ⁻¹ ≤ a⁻¹ := by simpa using inv_mabs_le a⁻¹ -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulRightMono α] @[to_additive] lemma mabs_ne_one : |a|ₘ ≠ 1 ↔ a ≠ 1 := (one_le_mabs a).gt_iff_ne.symm.trans one_lt_mabs diff --git a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean index f0e95176dbb3d..03c9d7579e5f1 100644 --- a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean @@ -31,9 +31,9 @@ section Group variable [Group α] -section TypeclassesLeftLE +section MulLeftMono -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [LE α] [MulLeftMono α] {a b c : α} /-- Uses `left` co(ntra)variant. -/ @[to_additive (attr := simp) "Uses `left` co(ntra)variant."] @@ -73,11 +73,11 @@ theorem inv_mul_le_one_iff : a⁻¹ * b ≤ 1 ↔ b ≤ a := -- Porting note: why is the `_root_` needed? _root_.trans inv_mul_le_iff_le_mul <| by rw [mul_one] -end TypeclassesLeftLE +end MulLeftMono -section TypeclassesLeftLT +section MulLeftStrictMono -variable [LT α] [CovariantClass α α (· * ·) (· < ·)] {a b c : α} +variable [LT α] [MulLeftStrictMono α] {a b c : α} /-- Uses `left` co(ntra)variant. -/ @[to_additive (attr := simp) Left.neg_pos_iff "Uses `left` co(ntra)variant."] @@ -114,11 +114,11 @@ theorem lt_inv_mul_iff_lt : 1 < b⁻¹ * a ↔ b < a := by theorem inv_mul_lt_one_iff : a⁻¹ * b < 1 ↔ b < a := _root_.trans inv_mul_lt_iff_lt_mul <| by rw [mul_one] -end TypeclassesLeftLT +end MulLeftStrictMono -section TypeclassesRightLE +section MulRightMono -variable [LE α] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +variable [LE α] [MulRightMono α] {a b c : α} /-- Uses `right` co(ntra)variant. -/ @[to_additive (attr := simp) "Uses `right` co(ntra)variant."] @@ -148,7 +148,6 @@ theorem mul_inv_le_iff_le_mul : a * b⁻¹ ≤ c ↔ a ≤ c * b := theorem le_mul_inv_iff_mul_le : c ≤ a * b⁻¹ ↔ c * b ≤ a := (mul_le_mul_iff_right b).symm.trans <| by rw [inv_mul_cancel_right] --- Porting note (#10618): `simp` can prove this @[to_additive] theorem mul_inv_le_one_iff_le : a * b⁻¹ ≤ 1 ↔ a ≤ b := mul_inv_le_iff_le_mul.trans <| by rw [one_mul] @@ -161,11 +160,11 @@ theorem le_mul_inv_iff_le : 1 ≤ a * b⁻¹ ↔ b ≤ a := by theorem mul_inv_le_one_iff : b * a⁻¹ ≤ 1 ↔ b ≤ a := _root_.trans mul_inv_le_iff_le_mul <| by rw [one_mul] -end TypeclassesRightLE +end MulRightMono -section TypeclassesRightLT +section MulRightStrictMono -variable [LT α] [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} +variable [LT α] [MulRightStrictMono α] {a b c : α} /-- Uses `right` co(ntra)variant. -/ @[to_additive (attr := simp) "Uses `right` co(ntra)variant."] @@ -193,7 +192,6 @@ theorem mul_inv_lt_iff_lt_mul : a * b⁻¹ < c ↔ a < c * b := by theorem lt_mul_inv_iff_mul_lt : c < a * b⁻¹ ↔ c * b < a := (mul_lt_mul_iff_right b).symm.trans <| by rw [inv_mul_cancel_right] --- Porting note (#10618): `simp` can prove this @[to_additive] theorem inv_mul_lt_one_iff_lt : a * b⁻¹ < 1 ↔ a < b := by rw [← mul_lt_mul_iff_right b, inv_mul_cancel_right, one_mul] @@ -206,12 +204,11 @@ theorem lt_mul_inv_iff_lt : 1 < a * b⁻¹ ↔ b < a := by theorem mul_inv_lt_one_iff : b * a⁻¹ < 1 ↔ b < a := _root_.trans mul_inv_lt_iff_lt_mul <| by rw [one_mul] -end TypeclassesRightLT +end MulRightStrictMono -section TypeclassesLeftRightLE +section MulLeftMono_MulRightMono -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] - {a b c d : α} +variable [LE α] [MulLeftMono α] {a b c d : α} @[to_additive (attr := simp)] theorem div_le_self_iff (a : α) {b : α} : a / b ≤ a ↔ 1 ≤ b := by @@ -223,7 +220,7 @@ theorem le_div_self_iff (a : α) {b : α} : a ≤ a / b ↔ b ≤ 1 := by alias ⟨_, sub_le_self⟩ := sub_le_self_iff -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulRightMono α] @[to_additive (attr := simp)] theorem inv_le_inv_iff : a⁻¹ ≤ b⁻¹ ↔ b ≤ a := by @@ -237,12 +234,11 @@ theorem mul_inv_le_inv_mul_iff : a * b⁻¹ ≤ d⁻¹ * c ↔ d * a ≤ c * b : rw [← mul_le_mul_iff_left d, ← mul_le_mul_iff_right b, mul_inv_cancel_left, mul_assoc, inv_mul_cancel_right] -end TypeclassesLeftRightLE +end MulLeftMono_MulRightMono -section TypeclassesLeftRightLT +section MulLeftStrictMono_MulRightStrictMono -variable [LT α] [CovariantClass α α (· * ·) (· < ·)] - {a b c d : α} +variable [LT α] [MulLeftStrictMono α] {a b c d : α} @[to_additive (attr := simp)] theorem div_lt_self_iff (a : α) {b : α} : a / b < a ↔ 1 < b := by @@ -250,7 +246,7 @@ theorem div_lt_self_iff (a : α) {b : α} : a / b < a ↔ 1 < b := by alias ⟨_, sub_lt_self⟩ := sub_lt_self_iff -variable [CovariantClass α α (swap (· * ·)) (· < ·)] +variable [MulRightStrictMono α] @[to_additive (attr := simp)] theorem inv_lt_inv_iff : a⁻¹ < b⁻¹ ↔ b < a := by @@ -276,7 +272,7 @@ theorem mul_inv_lt_inv_mul_iff : a * b⁻¹ < d⁻¹ * c ↔ d * a < c * b := by rw [← mul_lt_mul_iff_left d, ← mul_lt_mul_iff_right b, mul_inv_cancel_left, mul_assoc, inv_mul_cancel_right] -end TypeclassesLeftRightLT +end MulLeftStrictMono_MulRightStrictMono section Preorder @@ -284,7 +280,7 @@ variable [Preorder α] section LeftLE -variable [CovariantClass α α (· * ·) (· ≤ ·)] {a : α} +variable [MulLeftMono α] {a : α} @[to_additive] theorem Left.inv_le_self (h : 1 ≤ a) : a⁻¹ ≤ a := @@ -300,7 +296,7 @@ end LeftLE section LeftLT -variable [CovariantClass α α (· * ·) (· < ·)] {a : α} +variable [MulLeftStrictMono α] {a : α} @[to_additive] theorem Left.inv_lt_self (h : 1 < a) : a⁻¹ < a := @@ -316,7 +312,7 @@ end LeftLT section RightLE -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a : α} +variable [MulRightMono α] {a : α} @[to_additive] theorem Right.inv_le_self (h : 1 ≤ a) : a⁻¹ ≤ a := @@ -330,7 +326,7 @@ end RightLE section RightLT -variable [CovariantClass α α (swap (· * ·)) (· < ·)] {a : α} +variable [MulRightStrictMono α] {a : α} @[to_additive] theorem Right.inv_lt_self (h : 1 < a) : a⁻¹ < a := @@ -352,7 +348,7 @@ variable [CommGroup α] section LE -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [LE α] [MulLeftMono α] {a b c d : α} @[to_additive] theorem inv_mul_le_iff_le_mul' : c⁻¹ * a ≤ b ↔ a ≤ b * c := by rw [inv_mul_le_iff_le_mul, mul_comm] @@ -370,7 +366,7 @@ end LE section LT -variable [LT α] [CovariantClass α α (· * ·) (· < ·)] {a b c d : α} +variable [LT α] [MulLeftStrictMono α] {a b c d : α} @[to_additive] theorem inv_mul_lt_iff_lt_mul' : c⁻¹ * a < b ↔ a < b * c := by rw [inv_mul_lt_iff_lt_mul, mul_comm] @@ -471,7 +467,7 @@ variable [Group α] [LE α] section Right -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +variable [MulRightMono α] {a b c : α} @[to_additive] theorem div_le_div_iff_right (c : α) : a / c ≤ b / c ↔ a ≤ b := by @@ -511,15 +507,14 @@ attribute [simp] div_le_iff_le_mul -- (a renamed version of) `tsub_le_iff_right`? -- see Note [lower instance priority] instance (priority := 100) AddGroup.toOrderedSub {α : Type*} [AddGroup α] [LE α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] : OrderedSub α := + [AddRightMono α] : OrderedSub α := ⟨fun _ _ _ => sub_le_iff_le_add⟩ end Right section Left -variable [CovariantClass α α (· * ·) (· ≤ ·)] -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +variable [MulLeftMono α] [MulRightMono α] {a b c : α} @[to_additive] theorem div_le_div_iff_left (a : α) : a / b ≤ a / c ↔ c ≤ b := by @@ -540,7 +535,7 @@ variable [CommGroup α] section LE -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [LE α] [MulLeftMono α] {a b c d : α} @[to_additive sub_le_sub_iff] theorem div_le_div_iff' : a / b ≤ c / d ↔ a * d ≤ c * b := by @@ -575,7 +570,7 @@ end LE section Preorder -variable [Preorder α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [Preorder α] [MulLeftMono α] {a b c d : α} @[to_additive (attr := gcongr) sub_le_sub] theorem div_le_div'' (hab : a ≤ b) (hcd : c ≤ d) : a / d ≤ b / c := by @@ -594,7 +589,7 @@ variable [Group α] [LT α] section Right -variable [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c d : α} +variable [MulRightStrictMono α] {a b c : α} @[to_additive (attr := simp)] theorem div_lt_div_iff_right (c : α) : a / c < b / c ↔ a < b := by @@ -634,7 +629,7 @@ end Right section Left -variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (swap (· * ·)) (· < ·)] +variable [MulLeftStrictMono α] [MulRightStrictMono α] {a b c : α} @[to_additive (attr := simp)] @@ -660,7 +655,7 @@ variable [CommGroup α] section LT -variable [LT α] [CovariantClass α α (· * ·) (· < ·)] {a b c d : α} +variable [LT α] [MulLeftStrictMono α] {a b c d : α} @[to_additive sub_lt_sub_iff] theorem div_lt_div_iff' : a / b < c / d ↔ a * d < c * b := by @@ -692,7 +687,7 @@ end LT section Preorder -variable [Preorder α] [CovariantClass α α (· * ·) (· < ·)] {a b c d : α} +variable [Preorder α] [MulLeftStrictMono α] {a b c d : α} @[to_additive (attr := gcongr) sub_lt_sub] theorem div_lt_div'' (hab : a < b) (hcd : c < d) : a / d < b / c := by @@ -702,7 +697,7 @@ theorem div_lt_div'' (hab : a < b) (hcd : c < d) : a / d < b / c := by end Preorder section LinearOrder -variable [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [LinearOrder α] [MulLeftMono α] {a b c d : α} @[to_additive] lemma lt_or_lt_of_div_lt_div : a / d < b / c → a < b ∨ c < d := by contrapose!; exact fun h ↦ div_le_div'' h.1 h.2 @@ -715,14 +710,14 @@ section LinearOrder variable [Group α] [LinearOrder α] @[to_additive (attr := simp) cmp_sub_zero] -theorem cmp_div_one' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b : α) : +theorem cmp_div_one' [MulRightMono α] (a b : α) : cmp (a / b) 1 = cmp a b := by rw [← cmp_mul_right' _ _ b, one_mul, div_mul_cancel] -variable [CovariantClass α α (· * ·) (· ≤ ·)] +variable [MulLeftMono α] section VariableNames -variable {a b c : α} +variable {a b : α} @[to_additive] theorem le_of_forall_one_lt_lt_mul (h : ∀ ε : α, 1 < ε → a < b * ε) : a ≤ b := @@ -735,7 +730,7 @@ theorem le_iff_forall_one_lt_lt_mul : a ≤ b ↔ ∀ ε, 1 < ε → a < b * ε /- I (DT) introduced this lemma to prove (the additive version `sub_le_sub_flip` of) `div_le_div_flip` below. Now I wonder what is the point of either of these lemmas... -/ @[to_additive] -theorem div_le_inv_mul_iff [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : +theorem div_le_inv_mul_iff [MulRightMono α] : a / b ≤ a⁻¹ * b ↔ a ≤ b := by rw [div_eq_mul_inv, mul_inv_le_inv_mul_iff] exact @@ -747,7 +742,7 @@ theorem div_le_inv_mul_iff [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : -- since the LHS simplifies with `tsub_le_iff_right` @[to_additive] theorem div_le_div_flip {α : Type*} [CommGroup α] [LinearOrder α] - [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} : a / b ≤ b / a ↔ a ≤ b := by + [MulLeftMono α] {a b : α} : a / b ≤ b / a ↔ a ≤ b := by rw [div_eq_mul_inv b, mul_comm] exact div_le_inv_mul_iff @@ -757,8 +752,8 @@ end LinearOrder section -variable {β : Type*} [Group α] [Preorder α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] [Preorder β] {f : β → α} {s : Set β} +variable {β : Type*} [Group α] [Preorder α] [MulLeftMono α] + [MulRightMono α] [Preorder β] {f : β → α} {s : Set β} @[to_additive] theorem Monotone.inv (hf : Monotone f) : Antitone fun x => (f x)⁻¹ := fun _ _ hxy => @@ -780,8 +775,8 @@ end section -variable {β : Type*} [Group α] [Preorder α] [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] [Preorder β] {f : β → α} {s : Set β} +variable {β : Type*} [Group α] [Preorder α] [MulLeftStrictMono α] + [MulRightStrictMono α] [Preorder β] {f : β → α} {s : Set β} @[to_additive] theorem StrictMono.inv (hf : StrictMono f) : StrictAnti fun x => (f x)⁻¹ := fun _ _ hxy => diff --git a/Mathlib/Algebra/Order/Group/Units.lean b/Mathlib/Algebra/Order/Group/Units.lean index af674406ea62a..c32449fad0ca7 100644 --- a/Mathlib/Algebra/Order/Group/Units.lean +++ b/Mathlib/Algebra/Order/Group/Units.lean @@ -20,11 +20,7 @@ variable {α : Type*} additive group."] instance Units.orderedCommGroup [OrderedCommMonoid α] : OrderedCommGroup αˣ := { Units.instPartialOrderUnits, Units.instCommGroupUnits with - mul_le_mul_left := fun _ _ h _ => (@mul_le_mul_left' α _ _ _ _ _ h _) } - --- Porting note: the mathlib3 proof was --- mul_le_mul_left := fun a b h c => (mul_le_mul_left' (h : (a : α) ≤ b) _ : (c : α) * a ≤ c * b) } --- see https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/elaboration.20failure.20in.20algebra.2Eorder.2Egroup.2Eunits + mul_le_mul_left := fun _ _ h _ => (mul_le_mul_left' (α := α) h _) } /-- The units of a linearly ordered commutative monoid form a linearly ordered commutative group. -/ @[to_additive "The units of a linearly ordered commutative additive monoid form a diff --git a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean index 5809731874601..798ea261934d2 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean @@ -49,7 +49,7 @@ instance (priority := 100) canonicallyOrderedAddCommMonoid.toZeroLeOneClass ⟨zero_le 1⟩ section LinearOrderedCommMonoidWithZero -variable [LinearOrderedCommMonoidWithZero α] {a b c d x y z : α} {n : ℕ} +variable [LinearOrderedCommMonoidWithZero α] {a b : α} {n : ℕ} /- The following facts are true more generally in a (linearly) ordered commutative monoid. @@ -180,19 +180,9 @@ theorem inv_mul_lt_of_lt_mul₀ (h : a < b * c) : b⁻¹ * a < c := by theorem mul_lt_right₀ (c : α) (h : a < b) (hc : c ≠ 0) : a * c < b * c := mul_lt_mul_of_pos_right h (zero_lt_iff.2 hc) -theorem inv_lt_inv₀ (ha : a ≠ 0) (hb : b ≠ 0) : a⁻¹ < b⁻¹ ↔ b < a := - show (Units.mk0 a ha)⁻¹ < (Units.mk0 b hb)⁻¹ ↔ Units.mk0 b hb < Units.mk0 a ha from - have : CovariantClass αˣ αˣ (· * ·) (· < ·) := - IsLeftCancelMul.covariant_mul_lt_of_covariant_mul_le αˣ - inv_lt_inv_iff - -theorem inv_le_inv₀ (ha : a ≠ 0) (hb : b ≠ 0) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a := - show (Units.mk0 a ha)⁻¹ ≤ (Units.mk0 b hb)⁻¹ ↔ Units.mk0 b hb ≤ Units.mk0 a ha from - inv_le_inv_iff - theorem lt_of_mul_lt_mul_of_le₀ (h : a * b < c * d) (hc : 0 < c) (hh : c ≤ a) : b < d := by have ha : a ≠ 0 := ne_of_gt (lt_of_lt_of_le hc hh) - simp_rw [← inv_le_inv₀ ha (ne_of_gt hc)] at hh + rw [← inv_le_inv₀ (zero_lt_iff.2 ha) hc] at hh have := mul_lt_mul_of_lt_of_le₀ hh (inv_ne_zero (ne_of_gt hc)) h simpa [inv_mul_cancel_left₀ ha, inv_mul_cancel_left₀ (ne_of_gt hc)] using this @@ -208,7 +198,8 @@ theorem div_le_div_right₀ (hc : c ≠ 0) : a / c ≤ b / c ↔ a ≤ b := by rw [div_eq_mul_inv, div_eq_mul_inv, mul_le_mul_right (zero_lt_iff.2 (inv_ne_zero hc))] theorem div_le_div_left₀ (ha : a ≠ 0) (hb : b ≠ 0) (hc : c ≠ 0) : a / b ≤ a / c ↔ c ≤ b := by - simp only [div_eq_mul_inv, mul_le_mul_left (zero_lt_iff.2 ha), inv_le_inv₀ hb hc] + simp only [div_eq_mul_inv, mul_le_mul_left (zero_lt_iff.2 ha), + inv_le_inv₀ (zero_lt_iff.2 hb) (zero_lt_iff.2 hc)] /-- `Equiv.mulLeft₀` as an `OrderIso` on a `LinearOrderedCommGroupWithZero.`. @@ -234,15 +225,10 @@ theorem OrderIso.mulRight₀'_symm {a : α} (ha : a ≠ 0) : ext rfl -#adaptation_note /-- 2024-04-23 -After https://github.com/leanprover/lean4/pull/3965, -we need to either write `@inv_zero (G₀ := α) (_)` in `neg_top`, -or use `set_option backward.isDefEq.lazyProjDelta false`. -See https://github.com/leanprover-community/mathlib4/issues/12535 -/ instance : LinearOrderedAddCommGroupWithTop (Additive αᵒᵈ) := { Additive.subNegMonoid, instLinearOrderedAddCommMonoidWithTopAdditiveOrderDual, Additive.instNontrivial with - neg_top := set_option backward.isDefEq.lazyProjDelta false in @inv_zero _ (_) + neg_top := inv_zero (G₀ := α) add_neg_cancel := fun a ha ↦ mul_inv_cancel₀ (G₀ := α) (id ha : Additive.toMul a ≠ 0) } lemma pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := by @@ -300,8 +286,8 @@ lemma zero_eq_bot : (0 : WithZero α) = ⊥ := rfl theorem coe_le_iff {x : WithZero α} : (a : WithZero α) ≤ x ↔ ∃ b : α, x = b ∧ a ≤ b := WithBot.coe_le_iff -instance covariantClass_mul_le [Mul α] [CovariantClass α α (· * ·) (· ≤ ·)] : - CovariantClass (WithZero α) (WithZero α) (· * ·) (· ≤ ·) := by +instance mulLeftMono [Mul α] [MulLeftMono α] : + MulLeftMono (WithZero α) := by refine ⟨fun a b c hbc => ?_⟩ induction a; · exact zero_le _ induction b; · exact zero_le _ @@ -309,8 +295,8 @@ instance covariantClass_mul_le [Mul α] [CovariantClass α α (· * ·) (· ≤ rw [← coe_mul _ c, ← coe_mul, coe_le_coe] exact mul_le_mul_left' hbc' _ -protected lemma covariantClass_add_le [AddZeroClass α] [CovariantClass α α (· + ·) (· ≤ ·)] - (h : ∀ a : α, 0 ≤ a) : CovariantClass (WithZero α) (WithZero α) (· + ·) (· ≤ ·) := by +protected lemma addLeftMono [AddZeroClass α] [AddLeftMono α] + (h : ∀ a : α, 0 ≤ a) : AddLeftMono (WithZero α) := by refine ⟨fun a b c hbc => ?_⟩ induction a · rwa [zero_add, zero_add] @@ -341,8 +327,8 @@ variable [PartialOrder α] instance partialOrder : PartialOrder (WithZero α) := WithBot.partialOrder -instance contravariantClass_mul_lt [Mul α] [ContravariantClass α α (· * ·) (· < ·)] : - ContravariantClass (WithZero α) (WithZero α) (· * ·) (· < ·) := by +instance mulLeftReflectLT [Mul α] [MulLeftReflectLT α] : + MulLeftReflectLT (WithZero α) := by refine ⟨fun a b c h => ?_⟩ have := ((zero_le _).trans_lt h).ne' induction a @@ -361,11 +347,9 @@ variable [LinearOrder α] {a b c : α} instance linearOrder : LinearOrder (WithZero α) := WithBot.linearOrder --- Porting note (#10618): @[simp] can prove this protected lemma le_max_iff : (a : WithZero α) ≤ max (b : WithZero α) c ↔ a ≤ max b c := by simp only [WithZero.coe_le_coe, le_max_iff] --- Porting note (#10618): @[simp] can prove this protected lemma min_le_iff : min (a : WithZero α) b ≤ c ↔ min a b ≤ c := by simp only [WithZero.coe_le_coe, min_le_iff] @@ -387,7 +371,7 @@ elements are ≤ 1 and then 1 is the top element. protected abbrev orderedAddCommMonoid [OrderedAddCommMonoid α] (zero_le : ∀ a : α, 0 ≤ a) : OrderedAddCommMonoid (WithZero α) := { WithZero.partialOrder, WithZero.addCommMonoid with - add_le_add_left := @add_le_add_left _ _ _ (WithZero.covariantClass_add_le zero_le).. } + add_le_add_left := @add_le_add_left _ _ _ (WithZero.addLeftMono zero_le).. } -- This instance looks absurd: a monoid already has a zero /-- Adding a new zero to a canonically ordered additive monoid produces another one. -/ diff --git a/Mathlib/Algebra/Order/GroupWithZero/Submonoid.lean b/Mathlib/Algebra/Order/GroupWithZero/Submonoid.lean index c3b553bb0ca38..7f47ae1ee88aa 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Submonoid.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Submonoid.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ -import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.Order.GroupWithZero.Unbundled +import Mathlib.Order.Interval.Set.Basic /-! # The submonoid of positive elements diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean index 54e2ea4cb2615..d773fa40a750e 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Group.Pi.Basic import Mathlib.Algebra.GroupWithZero.Units.Basic import Mathlib.Algebra.Order.Monoid.Unbundled.Defs import Mathlib.Algebra.Order.ZeroLEOne +import Mathlib.Tactic.Bound.Attribute import Mathlib.Tactic.GCongr.CoreAttrs import Mathlib.Tactic.Nontriviality @@ -83,6 +84,8 @@ for a discussion about this notation, and whether to enable it globally (note th currently global but broken, hence actually only works locally). -/ +open Function + variable {M₀ G₀ : Type*} (α : Type*) set_option quotPrecheck false in @@ -935,7 +938,7 @@ section MonoidWithZero variable [MonoidWithZero M₀] section Preorder -variable [Preorder M₀] {a b c d : M₀} {m n : ℕ} +variable [Preorder M₀] {a b : M₀} {m n : ℕ} @[simp] lemma pow_nonneg [ZeroLEOneClass M₀] [PosMulMono M₀] (ha : 0 ≤ a) : ∀ n, 0 ≤ a ^ n | 0 => pow_zero a ▸ zero_le_one @@ -1045,7 +1048,7 @@ variable [PartialOrder M₀] {a b c d : M₀} @[simp] lemma pow_pos [ZeroLEOneClass M₀] [PosMulStrictMono M₀] (ha : 0 < a) : ∀ n, 0 < a ^ n | 0 => by nontriviality; rw [pow_zero]; exact zero_lt_one - | n + 1 => pow_succ a _ ▸ mul_pos (pow_pos ha _) ha + | _ + 1 => pow_succ a _ ▸ mul_pos (pow_pos ha _) ha lemma mul_self_lt_mul_self [PosMulStrictMono M₀] [MulPosMono M₀] (ha : 0 ≤ a) (hab : a < b) : a * a < b * b := mul_lt_mul' hab.le hab ha <| ha.trans_lt hab @@ -1160,7 +1163,7 @@ lemma div_self_le_one (a : G₀) : a / a ≤ 1 := by obtain rfl | ha := eq_or_ne end Preorder section PartialOrder -variable [PartialOrder G₀] [ZeroLEOneClass G₀] [PosMulReflectLT G₀] {a b c d : G₀} +variable [PartialOrder G₀] [ZeroLEOneClass G₀] [PosMulReflectLT G₀] {a b c : G₀} @[simp] lemma inv_pos : 0 < a⁻¹ ↔ 0 < a := suffices ∀ a : G₀, 0 < a → 0 < a⁻¹ from ⟨fun h ↦ inv_inv a ▸ this _ h, this a⟩ @@ -1188,12 +1191,14 @@ lemma zpow_nonneg [PosMulMono G₀] (ha : 0 ≤ a) : ∀ n : ℤ, 0 ≤ a ^ n | (n : ℕ) => by rw [zpow_natCast]; exact pow_nonneg ha _ |-(n + 1 : ℕ) => by rw [zpow_neg, inv_nonneg, zpow_natCast]; exact pow_nonneg ha _ -lemma zpow_pos_of_pos [PosMulStrictMono G₀] (ha : 0 < a) : ∀ n : ℤ, 0 < a ^ n +lemma zpow_pos [PosMulStrictMono G₀] (ha : 0 < a) : ∀ n : ℤ, 0 < a ^ n | (n : ℕ) => by rw [zpow_natCast]; exact pow_pos ha _ |-(n + 1 : ℕ) => by rw [zpow_neg, inv_pos, zpow_natCast]; exact pow_pos ha _ +@[deprecated (since := "2024-10-08")] alias zpow_pos_of_pos := zpow_pos + section PosMulMono -variable [PosMulMono G₀] +variable [PosMulMono G₀] {m n : ℤ} /-- See `le_inv_mul_iff₀'` for a version with multiplication on the other side. -/ lemma le_inv_mul_iff₀ (hc : 0 < c) : a ≤ c⁻¹ * b ↔ c * a ≤ b where @@ -1208,13 +1213,21 @@ lemma inv_mul_le_iff₀ (hc : 0 < c) : c⁻¹ * b ≤ a ↔ b ≤ c * a where lemma one_le_inv_mul₀ (ha : 0 < a) : 1 ≤ a⁻¹ * b ↔ a ≤ b := by rw [le_inv_mul_iff₀ ha, mul_one] lemma inv_mul_le_one₀ (ha : 0 < a) : a⁻¹ * b ≤ 1 ↔ b ≤ a := by rw [inv_mul_le_iff₀ ha, mul_one] -lemma one_le_inv₀ (ha : 0 < a) : 1 ≤ a⁻¹ ↔ a ≤ 1 := by simpa using one_le_inv_mul₀ ha (b := 1) -lemma inv_le_one₀ (ha : 0 < a) : a⁻¹ ≤ 1 ↔ 1 ≤ a := by simpa using inv_mul_le_one₀ ha (b := 1) - /-- See `inv_le_iff_one_le_mul₀` for a version with multiplication on the other side. -/ lemma inv_le_iff_one_le_mul₀' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b := by rw [← inv_mul_le_iff₀ ha, mul_one] +lemma one_le_inv₀ (ha : 0 < a) : 1 ≤ a⁻¹ ↔ a ≤ 1 := by simpa using one_le_inv_mul₀ ha (b := 1) +lemma inv_le_one₀ (ha : 0 < a) : a⁻¹ ≤ 1 ↔ 1 ≤ a := by simpa using inv_mul_le_one₀ ha (b := 1) + +@[bound] +lemma inv_le_one_of_one_le₀ (ha : 1 ≤ a) : a⁻¹ ≤ 1 := (inv_le_one₀ <| zero_lt_one.trans_le ha).2 ha + +lemma one_le_inv_iff₀ : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 where + mp h := ⟨inv_pos.1 (zero_lt_one.trans_le h), + inv_inv a ▸ (inv_le_one₀ <| zero_lt_one.trans_le h).2 h⟩ + mpr h := (one_le_inv₀ h.1).2 h.2 + /-- One direction of `le_inv_mul_iff₀` where `c` is allowed to be `0` (but `b` must be nonnegative). -/ lemma mul_le_of_le_inv_mul₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c⁻¹ * b) : c * a ≤ b := by @@ -1229,9 +1242,38 @@ lemma inv_mul_le_of_le_mul₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b * c) : · simp [hc] · rwa [inv_mul_le_iff₀ hb] +@[bound] lemma inv_mul_le_one_of_le₀ (h : a ≤ b) (hb : 0 ≤ b) : b⁻¹ * a ≤ 1 := inv_mul_le_of_le_mul₀ hb zero_le_one <| by rwa [mul_one] +lemma zpow_right_mono₀ (ha : 1 ≤ a) : Monotone fun n : ℤ ↦ a ^ n := by + refine monotone_int_of_le_succ fun n ↦ ?_ + rw [zpow_add_one₀ (zero_lt_one.trans_le ha).ne'] + exact le_mul_of_one_le_right (zpow_nonneg (zero_le_one.trans ha) _) ha + +lemma zpow_right_anti₀ (ha₀ : 0 < a) (ha₁ : a ≤ 1) : Antitone fun n : ℤ ↦ a ^ n := by + refine antitone_int_of_succ_le fun n ↦ ?_ + rw [zpow_add_one₀ ha₀.ne'] + exact mul_le_of_le_one_right (zpow_nonneg ha₀.le _) ha₁ + +@[gcongr] +lemma zpow_le_zpow_right₀ (ha : 1 ≤ a) (hmn : m ≤ n) : a ^ m ≤ a ^ n := zpow_right_mono₀ ha hmn + +@[gcongr] +lemma zpow_le_zpow_right_of_le_one₀ (ha₀ : 0 < a) (ha₁ : a ≤ 1) (hmn : m ≤ n) : a ^ n ≤ a ^ m := + zpow_right_anti₀ ha₀ ha₁ hmn + +lemma one_le_zpow₀ (ha : 1 ≤ a) (hn : 0 ≤ n) : 1 ≤ a ^ n := by simpa using zpow_right_mono₀ ha hn + +lemma zpow_le_one₀ (ha₀ : 0 < a) (ha₁ : a ≤ 1) (hn : 0 ≤ n) : a ^ n ≤ 1 := by + simpa using zpow_right_anti₀ ha₀ ha₁ hn + +lemma zpow_le_one_of_nonpos₀ (ha : 1 ≤ a) (hn : n ≤ 0) : a ^ n ≤ 1 := by + simpa using zpow_right_mono₀ ha hn + +lemma one_le_zpow_of_nonpos₀ (ha₀ : 0 < a) (ha₁ : a ≤ 1) (hn : n ≤ 0) : 1 ≤ a ^ n := by + simpa using zpow_right_anti₀ ha₀ ha₁ hn + end PosMulMono section MulPosMono @@ -1255,13 +1297,13 @@ lemma le_div_iff₀ (hc : 0 < c) : a ≤ b / c ↔ a * c ≤ b := by lemma div_le_iff₀ (hc : 0 < c) : b / c ≤ a ↔ b ≤ a * c := by rw [div_eq_mul_inv, mul_inv_le_iff₀ hc] -lemma one_le_div₀ (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by rw [le_div_iff₀ hb, one_mul] -lemma div_le_one₀ (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b := by rw [div_le_iff₀ hb, one_mul] - /-- See `inv_le_iff_one_le_mul₀'` for a version with multiplication on the other side. -/ lemma inv_le_iff_one_le_mul₀ (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ b * a := by rw [← mul_inv_le_iff₀ ha, one_mul] +lemma one_le_div₀ (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by rw [le_div_iff₀ hb, one_mul] +lemma div_le_one₀ (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b := by rw [div_le_iff₀ hb, one_mul] + /-- One direction of `le_mul_inv_iff₀` where `c` is allowed to be `0` (but `b` must be nonnegative). -/ lemma mul_le_of_le_mul_inv₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b * c⁻¹) : a * c ≤ b := by @@ -1284,19 +1326,44 @@ lemma mul_le_of_le_div₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ b / c) : a * lemma div_le_of_le_mul₀ (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a / b ≤ c := div_eq_mul_inv a _ ▸ mul_inv_le_of_le_mul₀ hb hc h +@[bound] lemma mul_inv_le_one_of_le₀ (h : a ≤ b) (hb : 0 ≤ b) : a * b⁻¹ ≤ 1 := mul_inv_le_of_le_mul₀ hb zero_le_one <| by rwa [one_mul] +@[bound] lemma div_le_one_of_le₀ (h : a ≤ b) (hb : 0 ≤ b) : a / b ≤ 1 := div_le_of_le_mul₀ hb zero_le_one <| by rwa [one_mul] @[deprecated (since := "2024-08-21")] alias le_div_iff := le_div_iff₀ @[deprecated (since := "2024-08-21")] alias div_le_iff := div_le_iff₀ +variable [PosMulMono G₀] + +/-- See `inv_anti₀` for the implication from right-to-left with one fewer assumption. -/ +lemma inv_le_inv₀ (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a := by + rw [inv_le_iff_one_le_mul₀' ha, le_mul_inv_iff₀ hb, one_mul] + +@[gcongr, bound] +lemma inv_anti₀ (hb : 0 < b) (hba : b ≤ a) : a⁻¹ ≤ b⁻¹ := (inv_le_inv₀ (hb.trans_le hba) hb).2 hba + +/-- See also `inv_le_of_inv_le₀` for a one-sided implication with one fewer assumption. -/ +lemma inv_le_comm₀ (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a := by + rw [← inv_le_inv₀ hb (inv_pos.2 ha), inv_inv] + +lemma inv_le_of_inv_le₀ (ha : 0 < a) (h : a⁻¹ ≤ b) : b⁻¹ ≤ a := + (inv_le_comm₀ ha <| (inv_pos.2 ha).trans_le h).1 h + +/-- See also `le_inv_of_le_inv₀` for a one-sided implication with one fewer assumption. -/ +lemma le_inv_comm₀ (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ := by + rw [← inv_le_inv₀ (inv_pos.2 hb) ha, inv_inv] + +lemma le_inv_of_le_inv₀ (ha : 0 < a) (h : a ≤ b⁻¹) : b ≤ a⁻¹ := + (le_inv_comm₀ ha <| inv_pos.1 <| ha.trans_le h).1 h + end MulPosMono section PosMulStrictMono -variable [PosMulStrictMono G₀] +variable [PosMulStrictMono G₀] {m n : ℤ} /-- See `lt_inv_mul_iff₀'` for a version with multiplication on the other side. -/ lemma lt_inv_mul_iff₀ (hc : 0 < c) : a < c⁻¹ * b ↔ c * a < b where @@ -1308,15 +1375,64 @@ lemma inv_mul_lt_iff₀ (hc : 0 < c) : c⁻¹ * b < a ↔ b < c * a where mp h := by simpa [hc.ne'] using mul_lt_mul_of_pos_left h hc mpr h := by simpa [hc.ne'] using mul_lt_mul_of_pos_left h (inv_pos.2 hc) +/-- See `inv_lt_iff_one_lt_mul₀` for a version with multiplication on the other side. -/ +lemma inv_lt_iff_one_lt_mul₀' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b := by + rw [← inv_mul_lt_iff₀ ha, mul_one] + lemma one_lt_inv_mul₀ (ha : 0 < a) : 1 < a⁻¹ * b ↔ a < b := by rw [lt_inv_mul_iff₀ ha, mul_one] lemma inv_mul_lt_one₀ (ha : 0 < a) : a⁻¹ * b < 1 ↔ b < a := by rw [inv_mul_lt_iff₀ ha, mul_one] lemma one_lt_inv₀ (ha : 0 < a) : 1 < a⁻¹ ↔ a < 1 := by simpa using one_lt_inv_mul₀ ha (b := 1) lemma inv_lt_one₀ (ha : 0 < a) : a⁻¹ < 1 ↔ 1 < a := by simpa using inv_mul_lt_one₀ ha (b := 1) -/-- See `inv_lt_iff_one_lt_mul₀` for a version with multiplication on the other side. -/ -lemma inv_lt_iff_one_lt_mul₀' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b := by - rw [← inv_mul_lt_iff₀ ha, mul_one] +@[bound] +lemma inv_lt_one_of_one_lt₀ (ha : 1 < a) : a⁻¹ < 1 := (inv_lt_one₀ <| zero_lt_one.trans ha).2 ha + +lemma one_lt_inv_iff₀ : 1 < a⁻¹ ↔ 0 < a ∧ a < 1 where + mp h := ⟨inv_pos.1 (zero_lt_one.trans h), inv_inv a ▸ (inv_lt_one₀ <| zero_lt_one.trans h).2 h⟩ + mpr h := (one_lt_inv₀ h.1).2 h.2 + +lemma zpow_right_strictMono₀ (ha : 1 < a) : StrictMono fun n : ℤ ↦ a ^ n := by + refine strictMono_int_of_lt_succ fun n ↦ ?_ + rw [zpow_add_one₀ (zero_lt_one.trans ha).ne'] + exact lt_mul_of_one_lt_right (zpow_pos (zero_lt_one.trans ha) _) ha + +lemma zpow_right_strictAnti₀ (ha₀ : 0 < a) (ha₁ : a < 1) : StrictAnti fun n : ℤ ↦ a ^ n := by + refine strictAnti_int_of_succ_lt fun n ↦ ?_ + rw [zpow_add_one₀ ha₀.ne'] + exact mul_lt_of_lt_one_right (zpow_pos ha₀ _) ha₁ + +@[gcongr] +lemma zpow_lt_zpow_right₀ (ha : 1 < a) (hmn : m < n) : a ^ m < a ^ n := + zpow_right_strictMono₀ ha hmn + +@[gcongr] +lemma zpow_lt_zpow_right_of_lt_one₀ (ha₀ : 0 < a) (ha₁ : a < 1) (hmn : m < n) : a ^ n < a ^ m := + zpow_right_strictAnti₀ ha₀ ha₁ hmn + +lemma one_lt_zpow₀ (ha : 1 < a) (hn : 0 < n) : 1 < a ^ n := by + simpa using zpow_right_strictMono₀ ha hn + +lemma zpow_lt_one₀ (ha₀ : 0 < a) (ha₁ : a < 1) (hn : 0 < n) : a ^ n < 1 := by + simpa using zpow_right_strictAnti₀ ha₀ ha₁ hn + +lemma zpow_lt_one_of_neg₀ (ha : 1 < a) (hn : n < 0) : a ^ n < 1 := by + simpa using zpow_right_strictMono₀ ha hn + +lemma one_lt_zpow_of_neg₀ (ha₀ : 0 < a) (ha₁ : a < 1) (hn : n < 0) : 1 < a ^ n := by + simpa using zpow_right_strictAnti₀ ha₀ ha₁ hn + +@[simp] lemma zpow_le_zpow_iff_right₀ (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := + (zpow_right_strictMono₀ ha).le_iff_le + +@[simp] lemma zpow_lt_zpow_iff_right₀ (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := + (zpow_right_strictMono₀ ha).lt_iff_lt + +lemma zpow_le_zpow_iff_right_of_lt_one₀ (ha₀ : 0 < a) (ha₁ : a < 1) : + a ^ m ≤ a ^ n ↔ n ≤ m := (zpow_right_strictAnti₀ ha₀ ha₁).le_iff_le + +lemma zpow_lt_zpow_iff_right_of_lt_one₀ (ha₀ : 0 < a) (ha₁ : a < 1) : + a ^ m < a ^ n ↔ n < m := (zpow_right_strictAnti₀ ha₀ ha₁).lt_iff_lt end PosMulStrictMono @@ -1345,23 +1461,84 @@ lemma div_lt_iff₀ (hc : 0 < c) : b / c < a ↔ b < a * c := by lemma inv_lt_iff_one_lt_mul₀ (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a := by rw [← mul_inv_lt_iff₀ ha, one_mul] +variable [PosMulStrictMono G₀] + +/-- See `inv_strictAnti₀` for the implication from right-to-left with one fewer assumption. -/ +lemma inv_lt_inv₀ (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b⁻¹ ↔ b < a := by + rw [inv_lt_iff_one_lt_mul₀' ha, lt_mul_inv_iff₀ hb, one_mul] + +@[gcongr, bound] +lemma inv_strictAnti₀ (hb : 0 < b) (hba : b < a) : a⁻¹ < b⁻¹ := + (inv_lt_inv₀ (hb.trans hba) hb).2 hba + +/-- See also `inv_lt_of_inv_lt₀` for a one-sided implication with one fewer assumption. -/ +lemma inv_lt_comm₀ (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b ↔ b⁻¹ < a := by + rw [← inv_lt_inv₀ hb (inv_pos.2 ha), inv_inv] + +lemma inv_lt_of_inv_lt₀ (ha : 0 < a) (h : a⁻¹ < b) : b⁻¹ < a := + (inv_lt_comm₀ ha <| (inv_pos.2 ha).trans h).1 h + +/-- See also `lt_inv_of_lt_inv₀` for a one-sided implication with one fewer assumption. -/ +lemma lt_inv_comm₀ (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ := by + rw [← inv_lt_inv₀ (inv_pos.2 hb) ha, inv_inv] + +lemma lt_inv_of_lt_inv₀ (ha : 0 < a) (h : a < b⁻¹) : b < a⁻¹ := + (lt_inv_comm₀ ha <| inv_pos.1 <| ha.trans h).1 h + end MulPosStrictMono end PartialOrder section LinearOrder -variable [LinearOrder G₀] [ZeroLEOneClass G₀] [PosMulReflectLT G₀] {a b c : G₀} +variable [LinearOrder G₀] [ZeroLEOneClass G₀] {a b : G₀} -@[simp] lemma inv_neg'' : a⁻¹ < 0 ↔ a < 0 := by simp only [← not_le, inv_nonneg] -@[simp] lemma inv_nonpos : a⁻¹ ≤ 0 ↔ a ≤ 0 := by simp only [← not_lt, inv_pos] +section PosMulMono +variable [PosMulMono G₀] + +@[simp] lemma inv_neg'' : a⁻¹ < 0 ↔ a < 0 := by + have := PosMulMono.toPosMulReflectLT (α := G₀); simp only [← not_le, inv_nonneg] + +@[simp] lemma inv_nonpos : a⁻¹ ≤ 0 ↔ a ≤ 0 := by + have := PosMulMono.toPosMulReflectLT (α := G₀); simp only [← not_lt, inv_pos] alias inv_lt_zero := inv_neg'' lemma one_div_neg : 1 / a < 0 ↔ a < 0 := one_div a ▸ inv_neg'' lemma one_div_nonpos : 1 / a ≤ 0 ↔ a ≤ 0 := one_div a ▸ inv_nonpos -lemma div_nonpos_of_nonneg_of_nonpos [PosMulMono G₀] (ha : 0 ≤ a) (hb : b ≤ 0) : a / b ≤ 0 := by +lemma div_nonpos_of_nonneg_of_nonpos (ha : 0 ≤ a) (hb : b ≤ 0) : a / b ≤ 0 := by rw [div_eq_mul_inv]; exact mul_nonpos_of_nonneg_of_nonpos ha (inv_nonpos.2 hb) +lemma neg_of_div_neg_right (h : a / b < 0) (ha : 0 ≤ a) : b < 0 := + have := PosMulMono.toPosMulReflectLT (α := G₀) + lt_of_not_ge fun hb ↦ (div_nonneg ha hb).not_lt h + +lemma neg_of_div_neg_left (h : a / b < 0) (hb : 0 ≤ b) : a < 0 := + have := PosMulMono.toPosMulReflectLT (α := G₀) + lt_of_not_ge fun ha ↦ (div_nonneg ha hb).not_lt h + +end PosMulMono + +variable [PosMulStrictMono G₀] {m n : ℤ} + +lemma inv_lt_one_iff₀ : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a := by + simp_rw [← not_le, one_le_inv_iff₀, not_and_or, not_lt] + +lemma inv_le_one_iff₀ : a⁻¹ ≤ 1 ↔ a ≤ 0 ∨ 1 ≤ a := by + simp only [← not_lt, one_lt_inv_iff₀, not_and_or] + +lemma zpow_right_injective₀ (ha₀ : 0 < a) (ha₁ : a ≠ 1) : Injective fun n : ℤ ↦ a ^ n := by + obtain ha₁ | ha₁ := ha₁.lt_or_lt + · exact (zpow_right_strictAnti₀ ha₀ ha₁).injective + · exact (zpow_right_strictMono₀ ha₁).injective + +@[simp] lemma zpow_right_inj₀ (ha₀ : 0 < a) (ha₁ : a ≠ 1) : a ^ m = a ^ n ↔ m = n := + (zpow_right_injective₀ ha₀ ha₁).eq_iff + +lemma zpow_eq_one_iff_right₀ (ha₀ : 0 ≤ a) (ha₁ : a ≠ 1) {n : ℤ} : a ^ n = 1 ↔ n = 0 := by + obtain rfl | ha₀ := ha₀.eq_or_lt + · exact zero_zpow_eq_one₀ + simpa using zpow_right_inj₀ ha₀ ha₁ (n := 0) + end GroupWithZero.LinearOrder section CommSemigroupHasZero @@ -1476,3 +1653,5 @@ lemma div_lt_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b < c ↔ a / c < b := by end PosMulStrictMono end CommGroupWithZero + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean index edc0cb47b953d..0bbdd7163e56c 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean @@ -12,7 +12,7 @@ import Mathlib.Order.Hom.Basic # Multiplication by a positive element as an order isomorphism -/ -variable {G₀} [GroupWithZero G₀] [Preorder G₀] [ZeroLEOneClass G₀] {a b c d : G₀} +variable {G₀} [GroupWithZero G₀] [Preorder G₀] [ZeroLEOneClass G₀] {a : G₀} /-- `Equiv.mulLeft₀` as an order isomorphism. -/ @[simps! (config := { simpRhs := true })] diff --git a/Mathlib/Algebra/Order/GroupWithZero/WithZero.lean b/Mathlib/Algebra/Order/GroupWithZero/WithZero.lean index f17648684e922..1595fba036e41 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/WithZero.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/WithZero.lean @@ -28,7 +28,7 @@ theory. These instances enable lemmas such as `mul_pos` to fire on `ℤₘ₀`. assert_not_exists Ring -- this makes `mul_lt_mul_left`, `mul_pos` etc work on `ℤₘ₀` -instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (· * ·) (· < ·)] : +instance {α : Type*} [Mul α] [Preorder α] [MulLeftStrictMono α] : PosMulStrictMono (WithZero α) where elim := @fun | ⟨(x : α), hx⟩, 0, (b : α), _ => by @@ -39,7 +39,7 @@ instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (· * ·) (· exact mul_lt_mul_left' h x open Function in -instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (swap (· * ·)) (· < ·)] : +instance {α : Type*} [Mul α] [Preorder α] [MulRightStrictMono α] : MulPosStrictMono (WithZero α) where elim := @fun | ⟨(x : α), hx⟩, 0, (b : α), _ => by @@ -49,14 +49,14 @@ instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (swap (· * norm_cast at h ⊢ exact mul_lt_mul_right' h x -instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (· * ·) (· ≤ ·)] : +instance {α : Type*} [Mul α] [Preorder α] [MulLeftMono α] : PosMulMono (WithZero α) where elim := @fun | ⟨0, _⟩, a, b, _ => by simp only [zero_mul, le_refl] | ⟨(x : α), _⟩, 0, _, _ => by simp only [mul_zero, WithZero.zero_le] - | ⟨(x : α), hx⟩, (a : α), 0, h => + | ⟨(x : α), _⟩, (a : α), 0, h => (lt_irrefl 0 (lt_of_lt_of_le (WithZero.zero_lt_coe a) h)).elim | ⟨(x : α), hx⟩, (a : α), (b : α), h => by dsimp only @@ -65,14 +65,14 @@ instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (· * ·) (· -- This makes `lt_mul_of_le_of_one_lt'` work on `ℤₘ₀` open Function in -instance {α : Type*} [Mul α] [Preorder α] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : +instance {α : Type*} [Mul α] [Preorder α] [MulRightMono α] : MulPosMono (WithZero α) where elim := @fun | ⟨0, _⟩, a, b, _ => by simp only [mul_zero, le_refl] | ⟨(x : α), _⟩, 0, _, _ => by simp only [zero_mul, WithZero.zero_le] - | ⟨(x : α), hx⟩, (a : α), 0, h => + | ⟨(x : α), _⟩, (a : α), 0, h => (lt_irrefl 0 (lt_of_lt_of_le (WithZero.zero_lt_coe a) h)).elim | ⟨(x : α), hx⟩, (a : α), (b : α), h => by dsimp only diff --git a/Mathlib/Algebra/Order/Hom/Basic.lean b/Mathlib/Algebra/Order/Hom/Basic.lean index b97b19b03d22d..a90bc7fe9e004 100644 --- a/Mathlib/Algebra/Order/Hom/Basic.lean +++ b/Mathlib/Algebra/Order/Hom/Basic.lean @@ -323,7 +323,7 @@ instance (priority := 100) RingSeminormClass.toNonnegHomClass [NonUnitalNonAssoc -- See note [lower instance priority] instance (priority := 100) MulRingSeminormClass.toRingSeminormClass [NonAssocRing α] [OrderedSemiring β] [MulRingSeminormClass F α β] : RingSeminormClass F α β := - { ‹MulRingSeminormClass F α β› with map_mul_le_mul := fun f a b => (map_mul _ _ _).le } + { ‹MulRingSeminormClass F α β› with map_mul_le_mul := fun _ _ _ => (map_mul _ _ _).le } -- See note [lower instance priority] instance (priority := 100) MulRingNormClass.toRingNormClass [NonAssocRing α] diff --git a/Mathlib/Algebra/Order/Hom/Monoid.lean b/Mathlib/Algebra/Order/Hom/Monoid.lean index 89356b58c0ecf..2c821fe45eb5c 100644 --- a/Mathlib/Algebra/Order/Hom/Monoid.lean +++ b/Mathlib/Algebra/Order/Hom/Monoid.lean @@ -265,7 +265,7 @@ theorem monotone_iff_map_nonpos : Monotone (f : α → β) ↔ ∀ a ≤ 0, f a theorem antitone_iff_map_nonneg : Antitone (f : α → β) ↔ ∀ a ≤ 0, 0 ≤ f a := monotone_comp_ofDual_iff.symm.trans <| monotone_iff_map_nonneg (α := αᵒᵈ) (iamhc := iamhc) _ -variable [CovariantClass β β (· + ·) (· < ·)] +variable [AddLeftStrictMono β] theorem strictMono_iff_map_pos : StrictMono (f : α → β) ↔ ∀ a, 0 < a → 0 < f a := by diff --git a/Mathlib/Algebra/Order/Hom/Normed.lean b/Mathlib/Algebra/Order/Hom/Normed.lean new file mode 100644 index 0000000000000..b44ee621b367a --- /dev/null +++ b/Mathlib/Algebra/Order/Hom/Normed.lean @@ -0,0 +1,75 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.Algebra.Order.Hom.Basic +import Mathlib.Analysis.Normed.Group.Basic + +/-! +# Constructing (semi)normed groups from (semi)normed homs + +This file defines constructions that upgrade `(Comm)Group` to `(Semi)Normed(Comm)Group` +using a `Group(Semi)normClass` when the codomain is the reals. + +See `Mathlib.Algebra.Order.Hom.Ultra` for further upgrades to nonarchimedean normed groups. + +-/ + +variable {F α : Type*} [FunLike F α ℝ] + +/-- Constructs a `SeminormedGroup` structure from a `GroupSeminormClass` on a `Group`. -/ +-- See note [reducible non-instances] +@[to_additive "Constructs a `SeminormedAddGroup` structure from an `AddGroupSeminormClass` on an +`AddGroup`."] +abbrev GroupSeminormClass.toSeminormedGroup [Group α] [GroupSeminormClass F α ℝ] + (f : F) : SeminormedGroup α where + norm := f + dist x y := f (x / y) + dist_eq _ _ := rfl + dist_self _ := by simp + dist_comm x y := by simp only [← map_inv_eq_map f (x / y), inv_div] + dist_triangle x y z := by simpa using map_mul_le_add f (x / y) (y / z) + +@[to_additive] +lemma GroupSeminormClass.toSeminormedGroup_norm_eq [Group α] [GroupSeminormClass F α ℝ] + (f : F) (x : α) : @norm _ (GroupSeminormClass.toSeminormedGroup f).toNorm x = f x := rfl + +/-- Constructs a `SeminormedCommGroup` structure from a `GroupSeminormClass` on a `CommGroup`. -/ +-- See note [reducible non-instances] +@[to_additive "Constructs a `SeminormedAddCommGroup` structure from an `AddGroupSeminormClass` on an +`AddCommGroup`."] +abbrev GroupSeminormClass.toSeminormedCommGroup [CommGroup α] [GroupSeminormClass F α ℝ] + (f : F) : SeminormedCommGroup α where + __ := GroupSeminormClass.toSeminormedGroup f + __ : CommGroup α := inferInstance + +@[to_additive] +lemma GroupSeminormClass.toSeminormedCommGroup_norm_eq [CommGroup α] [GroupSeminormClass F α ℝ] + (f : F) (x : α) : @norm _ (GroupSeminormClass.toSeminormedCommGroup f).toNorm x = f x := rfl + +/-- Constructs a `NormedGroup` structure from a `GroupNormClass` on a `Group`. -/ +-- See note [reducible non-instances] +@[to_additive "Constructs a `NormedAddGroup` structure from an `AddGroupNormClass` on an +`AddGroup`."] +abbrev GroupNormClass.toNormedGroup [Group α] [GroupNormClass F α ℝ] + (f : F) : NormedGroup α where + __ := GroupSeminormClass.toSeminormedGroup f + eq_of_dist_eq_zero h := div_eq_one.mp (eq_one_of_map_eq_zero f h) + +@[to_additive] +lemma GroupNormClass.toNormedGroup_norm_eq [Group α] [GroupNormClass F α ℝ] + (f : F) (x : α) : @norm _ (GroupNormClass.toNormedGroup f).toNorm x = f x := rfl + +/-- Constructs a `NormedCommGroup` structure from a `GroupNormClass` on a `CommGroup`. -/ +-- See note [reducible non-instances] +@[to_additive "Constructs a `NormedAddCommGroup` structure from an `AddGroupNormClass` on an +`AddCommGroup`."] +abbrev GroupNormClass.toNormedCommGroup [CommGroup α] [GroupNormClass F α ℝ] + (f : F) : NormedCommGroup α where + __ := GroupNormClass.toNormedGroup f + __ : CommGroup α := inferInstance + +@[to_additive] +lemma GroupNormClass.toNormedCommGroup_norm_eq [CommGroup α] [GroupNormClass F α ℝ] + (f : F) (x : α) : @norm _ (GroupNormClass.toNormedCommGroup f).toNorm x = f x := rfl diff --git a/Mathlib/Algebra/Order/Hom/Ultra.lean b/Mathlib/Algebra/Order/Hom/Ultra.lean new file mode 100644 index 0000000000000..a0a03cd82334a --- /dev/null +++ b/Mathlib/Algebra/Order/Hom/Ultra.lean @@ -0,0 +1,32 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.Algebra.Order.Hom.Normed +import Mathlib.Topology.MetricSpace.Ultra.Basic + +/-! +# Constructing nonarchimedean (ultrametric) normed groups from nonarchimedean normed homs + +This file defines constructions that upgrade `Add(Comm)Group` to `(Semi)NormedAdd(Comm)Group` +using an `AddGroup(Semi)normClass` when the codomain is the reals and the hom is nonarchimedean. + +## Implementation details + +The lemmas need to assume `[Dist α]` to be able to be stated, so they take an extra argument +that shows that this distance instance is propositionally equal to the one that comes from the +hom-based `AddGroupSeminormClass.toSeminormedAddGroup f` construction. To help at use site, +the argument is an autoparam that resolves by definitional equality when using these constructions. +-/ + +variable {F α : Type*} [FunLike F α ℝ] + +/-- Proves that when a `SeminormedAddGroup` structure is constructed from an +`AddGroupSeminormClass` that satifies `IsNonarchimedean`, the group has an `IsUltrametricDist`. -/ +lemma AddGroupSeminormClass.isUltrametricDist [AddGroup α] [AddGroupSeminormClass F α ℝ] + [inst : Dist α] {f : F} (hna : IsNonarchimedean f) + (hd : inst = (AddGroupSeminormClass.toSeminormedAddGroup f).toDist := by rfl) : + IsUltrametricDist α := + ⟨fun x y z ↦ by simpa only [hd, dist_eq_norm, AddGroupSeminormClass.toSeminormedAddGroup_norm_eq, + ← sub_add_sub_cancel x y z] using hna _ _⟩ diff --git a/Mathlib/Algebra/Order/Interval/Basic.lean b/Mathlib/Algebra/Order/Interval/Basic.lean index dcd8a5d261e09..a8d682494ed1f 100644 --- a/Mathlib/Algebra/Order/Interval/Basic.lean +++ b/Mathlib/Algebra/Order/Interval/Basic.lean @@ -6,6 +6,7 @@ Authors: Yaël Dillies import Mathlib.Algebra.Group.Pointwise.Set.Basic import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Order.Interval.Basic +import Mathlib.Tactic.Positivity.Core /-! # Interval arithmetic @@ -117,8 +118,7 @@ Note that this multiplication does not apply to `ℚ` or `ℝ`. section Mul -variable [Preorder α] [Mul α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [Preorder α] [Mul α] [MulLeftMono α] [MulRightMono α] @[to_additive] instance : Mul (NonemptyInterval α) := @@ -177,8 +177,8 @@ end Mul -- TODO: if `to_additive` gets improved sufficiently, derive this from `hasPow` -instance NonemptyInterval.hasNSMul [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] : SMul ℕ (NonemptyInterval α) := +instance NonemptyInterval.hasNSMul [AddMonoid α] [Preorder α] [AddLeftMono α] + [AddRightMono α] : SMul ℕ (NonemptyInterval α) := ⟨fun n s => ⟨(n • s.fst, n • s.snd), nsmul_le_nsmul_right s.fst_le_snd _⟩⟩ section Pow @@ -186,14 +186,13 @@ section Pow variable [Monoid α] [Preorder α] @[to_additive existing] -instance NonemptyInterval.hasPow - [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : +instance NonemptyInterval.hasPow [MulLeftMono α] [MulRightMono α] : Pow (NonemptyInterval α) ℕ := ⟨fun s n => ⟨s.toProd ^ n, pow_le_pow_left' s.fst_le_snd _⟩⟩ namespace NonemptyInterval -variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +variable [MulLeftMono α] [MulRightMono α] variable (s : NonemptyInterval α) (a : α) (n : ℕ) @[to_additive (attr := simp) toProd_nsmul] @@ -274,8 +273,7 @@ is not a thing and probably should not become one). section Sub -variable [Preorder α] [AddCommSemigroup α] [Sub α] [OrderedSub α] - [CovariantClass α α (· + ·) (· ≤ ·)] +variable [Preorder α] [AddCommSemigroup α] [Sub α] [OrderedSub α] [AddLeftMono α] instance : Sub (NonemptyInterval α) := ⟨fun s t => ⟨(s.fst - t.snd, s.snd - t.fst), tsub_le_tsub s.fst_le_snd t.fst_le_snd⟩⟩ @@ -333,7 +331,7 @@ Note that this division does not apply to `ℚ` or `ℝ`. section Div -variable [Preorder α] [CommGroup α] [CovariantClass α α (· * ·) (· ≤ ·)] +variable [Preorder α] [CommGroup α] [MulLeftMono α] @[to_additive existing] instance : Div (NonemptyInterval α) := @@ -611,11 +609,8 @@ theorem length_sub_le : (s - t).length ≤ s.length + t.length := by simpa [sub_eq_add_neg] using length_add_le s (-t) theorem length_sum_le (f : ι → Interval α) (s : Finset ι) : - (∑ i ∈ s, f i).length ≤ ∑ i ∈ s, (f i).length := by - -- Porting note: Old proof was `:= Finset.le_sum_of_subadditive _ length_zero length_add_le _ _` - apply Finset.le_sum_of_subadditive - · exact length_zero - · exact length_add_le + (∑ i ∈ s, f i).length ≤ ∑ i ∈ s, (f i).length := + Finset.le_sum_of_subadditive _ length_zero length_add_le _ _ end Interval diff --git a/Mathlib/Algebra/Order/Interval/Set/Group.lean b/Mathlib/Algebra/Order/Interval/Set/Group.lean index a95c3a44af7a1..d9684e57e4eb9 100644 --- a/Mathlib/Algebra/Order/Interval/Set/Group.lean +++ b/Mathlib/Algebra/Order/Interval/Set/Group.lean @@ -19,7 +19,7 @@ namespace Set section OrderedCommGroup -variable [OrderedCommGroup α] {a b c d : α} +variable [OrderedCommGroup α] {a c d : α} /-! `inv_mem_Ixx_iff`, `sub_mem_Ixx_iff` -/ diff --git a/Mathlib/Algebra/Order/Kleene.lean b/Mathlib/Algebra/Order/Kleene.lean index 064a1499bf6bf..bc8e1a8feedb4 100644 --- a/Mathlib/Algebra/Order/Kleene.lean +++ b/Mathlib/Algebra/Order/Kleene.lean @@ -162,13 +162,11 @@ instance (priority := 100) IdemSemiring.toCanonicallyOrderedAddCommMonoid : le_self_add := fun a b ↦ add_eq_right_iff_le.1 <| by rw [← add_assoc, add_idem] } -- See note [lower instance priority] -instance (priority := 100) IdemSemiring.toCovariantClass_mul_le : - CovariantClass α α (· * ·) (· ≤ ·) := +instance (priority := 100) IdemSemiring.toMulLeftMono : MulLeftMono α := ⟨fun a b c hbc ↦ add_eq_left_iff_le.1 <| by rw [← mul_add, hbc.add_eq_left]⟩ -- See note [lower instance priority] -instance (priority := 100) IdemSemiring.toCovariantClass_swap_mul_le : - CovariantClass α α (swap (· * ·)) (· ≤ ·) := +instance (priority := 100) IdemSemiring.toMulRightMono : MulRightMono α := ⟨fun a b c hbc ↦ add_eq_left_iff_le.1 <| by rw [← add_mul, hbc.add_eq_left]⟩ end IdemSemiring @@ -321,7 +319,7 @@ protected abbrev idemSemiring [IdemSemiring α] [Zero β] [One β] [Add β] [Mul IdemSemiring β := { hf.semiring f zero one add mul nsmul npow natCast, hf.semilatticeSup _ sup, ‹Bot β› with - add_eq_sup := fun a b ↦ hf <| by erw [sup, add, add_eq_sup] + add_eq_sup := fun a b ↦ hf <| by rw [sup, add, add_eq_sup] bot := ⊥ bot_le := fun a ↦ bot.trans_le <| @bot_le _ _ _ <| f a } @@ -347,25 +345,25 @@ protected abbrev kleeneAlgebra [KleeneAlgebra α] [Zero β] [One β] [Add β] [M { hf.idemSemiring f zero one add mul nsmul npow natCast sup bot, ‹KStar β› with one_le_kstar := fun a ↦ one.trans_le <| by - erw [kstar] + rw [kstar] exact one_le_kstar mul_kstar_le_kstar := fun a ↦ by change f _ ≤ _ - erw [mul, kstar] + rw [mul, kstar] exact mul_kstar_le_kstar kstar_mul_le_kstar := fun a ↦ by change f _ ≤ _ - erw [mul, kstar] + rw [mul, kstar] exact kstar_mul_le_kstar mul_kstar_le_self := fun a b (h : f _ ≤ _) ↦ by change f _ ≤ _ - erw [mul, kstar] - erw [mul] at h + rw [mul, kstar] + rw [mul] at h exact mul_kstar_le_self h kstar_mul_le_self := fun a b (h : f _ ≤ _) ↦ by change f _ ≤ _ - erw [mul, kstar] - erw [mul] at h + rw [mul, kstar] + rw [mul] at h exact kstar_mul_le_self h } end Function.Injective diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean index 8323669b29434..a1172e5a8524d 100644 --- a/Mathlib/Algebra/Order/Module/Defs.lean +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Order.Field.Defs import Mathlib.Algebra.Order.GroupWithZero.Action.Synonym import Mathlib.Tactic.GCongr diff --git a/Mathlib/Algebra/Order/Module/OrderedSMul.lean b/Mathlib/Algebra/Order/Module/OrderedSMul.lean index ff7892c724901..6afca816cb005 100644 --- a/Mathlib/Algebra/Order/Module/OrderedSMul.lean +++ b/Mathlib/Algebra/Order/Module/OrderedSMul.lean @@ -136,7 +136,7 @@ end LinearOrderedSemifield section Invertible variable (α : Type*) {β : Type*} variable [Semiring α] [Invertible (2 : α)] [Lattice β] [AddCommGroup β] [Module α β] - [CovariantClass β β (· + ·) (· ≤ ·)] + [AddLeftMono β] lemma inf_eq_half_smul_add_sub_abs_sub (x y : β) : x ⊓ y = (⅟2 : α) • (x + y - |y - x|) := by rw [← two_nsmul_inf_eq_add_sub_abs_sub x y, two_smul, ← two_smul α, @@ -151,7 +151,7 @@ end Invertible section DivisionSemiring variable (α : Type*) {β : Type*} variable [DivisionSemiring α] [NeZero (2 : α)] [Lattice β] [AddCommGroup β] [Module α β] - [CovariantClass β β (· + ·) (· ≤ ·)] + [AddLeftMono β] lemma inf_eq_half_smul_add_sub_abs_sub' (x y : β) : x ⊓ y = (2⁻¹ : α) • (x + y - |y - x|) := by letI := invertibleOfNonzero (two_ne_zero' α) diff --git a/Mathlib/Algebra/Order/Module/Rat.lean b/Mathlib/Algebra/Order/Module/Rat.lean index 0368ae68efa89..21b376b2c7771 100644 --- a/Mathlib/Algebra/Order/Module/Rat.lean +++ b/Mathlib/Algebra/Order/Module/Rat.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Order.Module.Defs +import Mathlib.Data.NNRat.Lemmas import Mathlib.Data.Rat.Cast.Order /-! @@ -12,6 +13,12 @@ import Mathlib.Data.Rat.Cast.Order variable {α : Type*} +instance PosSMulMono.nnrat_of_rat [Preorder α] [MulAction ℚ α] [PosSMulMono ℚ α] : + PosSMulMono ℚ≥0 α where elim _q hq _a₁ _a₂ ha := smul_le_smul_of_nonneg_left (α := ℚ) ha hq + +instance PosSMulStrictMono.nnrat_of_rat [Preorder α] [MulAction ℚ α] [PosSMulStrictMono ℚ α] : + PosSMulStrictMono ℚ≥0 α where elim _q hq _a₁ _a₂ ha := smul_lt_smul_of_pos_left (α := ℚ) ha hq + section LinearOrderedAddCommGroup variable [LinearOrderedAddCommGroup α] diff --git a/Mathlib/Algebra/Order/Monoid/Basic.lean b/Mathlib/Algebra/Order/Monoid/Basic.lean index 824c12d19dddf..32184a47b1ed6 100644 --- a/Mathlib/Algebra/Order/Monoid/Basic.lean +++ b/Mathlib/Algebra/Order/Monoid/Basic.lean @@ -73,7 +73,7 @@ See also `OrderIso.mulLeft` when working in an ordered group. -/ "The order embedding sending `b` to `a + b`, for some fixed `a`. See also `OrderIso.addLeft` when working in an additive ordered group."] def OrderEmbedding.mulLeft {α : Type*} [Mul α] [LinearOrder α] - [CovariantClass α α (· * ·) (· < ·)] (m : α) : α ↪o α := + [MulLeftStrictMono α] (m : α) : α ↪o α := OrderEmbedding.ofStrictMono (fun n => m * n) fun _ _ w => mul_lt_mul_left' w m /-- The order embedding sending `b` to `b * a`, for some fixed `a`. @@ -82,5 +82,5 @@ See also `OrderIso.mulRight` when working in an ordered group. -/ "The order embedding sending `b` to `b + a`, for some fixed `a`. See also `OrderIso.addRight` when working in an additive ordered group."] def OrderEmbedding.mulRight {α : Type*} [Mul α] [LinearOrder α] - [CovariantClass α α (swap (· * ·)) (· < ·)] (m : α) : α ↪o α := + [MulRightStrictMono α] (m : α) : α ↪o α := OrderEmbedding.ofStrictMono (fun n => n * m) fun _ _ w => mul_lt_mul_right' w m diff --git a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean index 7cf5e1c4143ca..b18b3c81d456e 100644 --- a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean @@ -3,7 +3,7 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl -/ -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Algebra.Order.Monoid.Defs import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE import Mathlib.Algebra.NeZero @@ -156,7 +156,7 @@ theorem le_mul_right (h : a ≤ b) : a ≤ b * c := _ ≤ b * c := mul_le_mul' h (one_le _) @[to_additive] -theorem lt_iff_exists_mul [CovariantClass α α (· * ·) (· < ·)] : a < b ↔ ∃ c > 1, b = a * c := by +theorem lt_iff_exists_mul [MulLeftStrictMono α] : a < b ↔ ∃ c > 1, b = a * c := by rw [lt_iff_le_and_ne, le_iff_exists_mul, ← exists_and_right] apply exists_congr intro c @@ -226,12 +226,10 @@ theorem min_mul_distrib (a b c : α) : min a (b * c) = min a (min a b * min a c) theorem min_mul_distrib' (a b c : α) : min (a * b) c = min (min a c * min b c) c := by simpa [min_comm _ c] using min_mul_distrib c a b --- Porting note (#10618): no longer `@[simp]`, as `simp` can prove this. @[to_additive] theorem one_min (a : α) : min 1 a = 1 := min_eq_left (one_le a) --- Porting note (#10618): no longer `@[simp]`, as `simp` can prove this. @[to_additive] theorem min_one (a : α) : min a 1 = 1 := min_eq_right (one_le a) diff --git a/Mathlib/Algebra/Order/Monoid/Defs.lean b/Mathlib/Algebra/Order/Monoid/Defs.lean index 3e9fcaaa3a139..32ed5678901e7 100644 --- a/Mathlib/Algebra/Order/Monoid/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Defs.lean @@ -15,7 +15,7 @@ This file provides the definitions of ordered monoids. open Function -variable {α β : Type*} +variable {α : Type*} /-- An ordered (additive) commutative monoid is a commutative monoid with a partial order such that addition is monotone. -/ @@ -32,12 +32,12 @@ section OrderedCommMonoid variable [OrderedCommMonoid α] @[to_additive] -instance OrderedCommMonoid.toCovariantClassLeft : CovariantClass α α (· * ·) (· ≤ ·) where +instance OrderedCommMonoid.toMulLeftMono : MulLeftMono α where elim := fun a _ _ bc ↦ OrderedCommMonoid.mul_le_mul_left _ _ bc a @[to_additive] -theorem OrderedCommMonoid.toCovariantClassRight (M : Type*) [OrderedCommMonoid M] : - CovariantClass M M (swap (· * ·)) (· ≤ ·) := +theorem OrderedCommMonoid.toMulRightMono (M : Type*) [OrderedCommMonoid M] : + MulRightMono M := inferInstance end OrderedCommMonoid @@ -58,18 +58,18 @@ variable [OrderedCancelCommMonoid α] -- See note [lower instance priority] @[to_additive] -instance (priority := 200) OrderedCancelCommMonoid.toContravariantClassLeLeft : - ContravariantClass α α (· * ·) (· ≤ ·) := +instance (priority := 200) OrderedCancelCommMonoid.toMulLeftReflectLE : + MulLeftReflectLE α := ⟨OrderedCancelCommMonoid.le_of_mul_le_mul_left⟩ @[to_additive] -instance OrderedCancelCommMonoid.toContravariantClassLeft : - ContravariantClass α α (· * ·) (· < ·) where +instance OrderedCancelCommMonoid.toMulLeftReflectLT : + MulLeftReflectLT α where elim := contravariant_lt_of_contravariant_le α α _ ContravariantClass.elim @[to_additive] -theorem OrderedCancelCommMonoid.toContravariantClassRight : - ContravariantClass α α (swap (· * ·)) (· < ·) := +theorem OrderedCancelCommMonoid.toMulRightReflectLT : + MulRightReflectLT α := inferInstance -- See note [lower instance priority] @@ -77,7 +77,7 @@ theorem OrderedCancelCommMonoid.toContravariantClassRight : instance (priority := 100) OrderedCancelCommMonoid.toCancelCommMonoid : CancelCommMonoid α := { ‹OrderedCancelCommMonoid α› with mul_left_cancel := - fun a b c h => (le_of_mul_le_mul_left' h.le).antisymm <| le_of_mul_le_mul_left' h.ge } + fun _ _ _ h => (le_of_mul_le_mul_left' h.le).antisymm <| le_of_mul_le_mul_left' h.ge } end OrderedCancelCommMonoid diff --git a/Mathlib/Algebra/Order/Monoid/NatCast.lean b/Mathlib/Algebra/Order/Monoid/NatCast.lean index f5a1d382ff7a2..d1d107db41833 100644 --- a/Mathlib/Algebra/Order/Monoid/NatCast.lean +++ b/Mathlib/Algebra/Order/Monoid/NatCast.lean @@ -16,37 +16,37 @@ variable {α : Type*} open Function lemma lt_add_one [One α] [AddZeroClass α] [PartialOrder α] [ZeroLEOneClass α] - [NeZero (1 : α)] [CovariantClass α α (·+·) (·<·)] (a : α) : a < a + 1 := + [NeZero (1 : α)] [AddLeftStrictMono α] (a : α) : a < a + 1 := lt_add_of_pos_right _ zero_lt_one lemma lt_one_add [One α] [AddZeroClass α] [PartialOrder α] [ZeroLEOneClass α] - [NeZero (1 : α)] [CovariantClass α α (swap (·+·)) (·<·)] (a : α) : a < 1 + a := + [NeZero (1 : α)] [AddRightStrictMono α] (a : α) : a < 1 + a := lt_add_of_pos_left _ zero_lt_one variable [AddMonoidWithOne α] -lemma zero_le_two [Preorder α] [ZeroLEOneClass α] [CovariantClass α α (·+·) (·≤·)] : +lemma zero_le_two [Preorder α] [ZeroLEOneClass α] [AddLeftMono α] : (0 : α) ≤ 2 := by rw [← one_add_one_eq_two] exact add_nonneg zero_le_one zero_le_one -lemma zero_le_three [Preorder α] [ZeroLEOneClass α] [CovariantClass α α (·+·) (·≤·)] : +lemma zero_le_three [Preorder α] [ZeroLEOneClass α] [AddLeftMono α] : (0 : α) ≤ 3 := by rw [← two_add_one_eq_three] exact add_nonneg zero_le_two zero_le_one -lemma zero_le_four [Preorder α] [ZeroLEOneClass α] [CovariantClass α α (·+·) (·≤·)] : +lemma zero_le_four [Preorder α] [ZeroLEOneClass α] [AddLeftMono α] : (0 : α) ≤ 4 := by rw [← three_add_one_eq_four] exact add_nonneg zero_le_three zero_le_one -lemma one_le_two [LE α] [ZeroLEOneClass α] [CovariantClass α α (·+·) (·≤·)] : +lemma one_le_two [LE α] [ZeroLEOneClass α] [AddLeftMono α] : (1 : α) ≤ 2 := calc (1 : α) = 1 + 0 := (add_zero 1).symm _ ≤ 1 + 1 := add_le_add_left zero_le_one _ _ = 2 := one_add_one_eq_two -lemma one_le_two' [LE α] [ZeroLEOneClass α] [CovariantClass α α (swap (·+·)) (·≤·)] : +lemma one_le_two' [LE α] [ZeroLEOneClass α] [AddRightMono α] : (1 : α) ≤ 2 := calc (1 : α) = 0 + 1 := (zero_add 1).symm _ ≤ 1 + 1 := add_le_add_right zero_le_one _ @@ -56,7 +56,7 @@ section variable [PartialOrder α] [ZeroLEOneClass α] [NeZero (1 : α)] section -variable [CovariantClass α α (·+·) (·≤·)] +variable [AddLeftMono α] /-- See `zero_lt_two'` for a version with the type explicit. -/ @[simp] lemma zero_lt_two : (0 : α) < 2 := zero_lt_one.trans_le one_le_two @@ -88,7 +88,7 @@ instance ZeroLEOneClass.neZero.four : NeZero (4 : α) := ⟨zero_lt_four.ne'⟩ end -lemma one_lt_two [CovariantClass α α (·+·) (·<·)] : (1 : α) < 2 := by +lemma one_lt_two [AddLeftStrictMono α] : (1 : α) < 2 := by rw [← one_add_one_eq_two] exact lt_add_one _ diff --git a/Mathlib/Algebra/Order/Monoid/OrderDual.lean b/Mathlib/Algebra/Order/Monoid/OrderDual.lean index 6c9ac68a97316..a56f9ffa0a23b 100644 --- a/Mathlib/Algebra/Order/Monoid/OrderDual.lean +++ b/Mathlib/Algebra/Order/Monoid/OrderDual.lean @@ -21,9 +21,9 @@ namespace OrderDual instance orderedCommMonoid [OrderedCommMonoid α] : OrderedCommMonoid αᵒᵈ := { mul_le_mul_left := fun _ _ h c => mul_le_mul_left' h c } -@[to_additive OrderDual.OrderedCancelAddCommMonoid.to_contravariantClass] -instance OrderedCancelCommMonoid.to_contravariantClass [OrderedCancelCommMonoid α] : - ContravariantClass αᵒᵈ αᵒᵈ HMul.hMul LE.le where +@[to_additive OrderDual.OrderedCancelAddCommMonoid.to_mulLeftReflectLE] +instance OrderedCancelCommMonoid.to_mulLeftReflectLE [OrderedCancelCommMonoid α] : + MulLeftReflectLE αᵒᵈ where elim a b c := OrderedCancelCommMonoid.le_of_mul_le_mul_left (α := α) a c b -- Porting note: Lean 3 to_additive name omits first namespace part diff --git a/Mathlib/Algebra/Order/Monoid/Prod.lean b/Mathlib/Algebra/Order/Monoid/Prod.lean index e3d9ab5369849..4ed2d8ca1fa79 100644 --- a/Mathlib/Algebra/Order/Monoid/Prod.lean +++ b/Mathlib/Algebra/Order/Monoid/Prod.lean @@ -46,7 +46,7 @@ namespace Lex @[to_additive] instance orderedCommMonoid [OrderedCommMonoid α] - [CovariantClass α α (· * ·) (· < ·)] [OrderedCommMonoid β] : + [MulLeftStrictMono α] [OrderedCommMonoid β] : OrderedCommMonoid (α ×ₗ β) where mul_le_mul_left _ _ hxy z := ((le_iff _ _).1 hxy).elim (fun hxy => left _ _ <| mul_lt_mul_left' hxy _) diff --git a/Mathlib/Algebra/Order/Monoid/Submonoid.lean b/Mathlib/Algebra/Order/Monoid/Submonoid.lean index d88dd033520c1..450cea09f161c 100644 --- a/Mathlib/Algebra/Order/Monoid/Submonoid.lean +++ b/Mathlib/Algebra/Order/Monoid/Submonoid.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ -import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.Order.Monoid.Basic +import Mathlib.Algebra.Group.Submonoid.Defs +import Mathlib.Order.Interval.Set.Basic /-! # Ordered instances on submonoids @@ -88,7 +89,7 @@ instance toLinearOrderedCancelCommMonoid [LinearOrderedCancelCommMonoid M] (S : section Preorder variable (M) -variable [Monoid M] [Preorder M] [CovariantClass M M (· * ·) (· ≤ ·)] {a : M} +variable [Monoid M] [Preorder M] [MulLeftMono M] {a : M} /-- The submonoid of elements greater than `1`. -/ @[to_additive (attr := simps) nonneg "The submonoid of nonnegative elements."] diff --git a/Mathlib/Algebra/Order/Monoid/ToMulBot.lean b/Mathlib/Algebra/Order/Monoid/ToMulBot.lean index 96f8542fa024c..ab578ee5f849e 100644 --- a/Mathlib/Algebra/Order/Monoid/ToMulBot.lean +++ b/Mathlib/Algebra/Order/Monoid/ToMulBot.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl -/ import Mathlib.Algebra.Order.GroupWithZero.Canonical -import Mathlib.Algebra.Order.Monoid.TypeTags +import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop diff --git a/Mathlib/Algebra/Order/Monoid/TypeTags.lean b/Mathlib/Algebra/Order/Monoid/TypeTags.lean index c8a194531eb5b..31b5a417097b5 100644 --- a/Mathlib/Algebra/Order/Monoid/TypeTags.lean +++ b/Mathlib/Algebra/Order/Monoid/TypeTags.lean @@ -3,62 +3,13 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl -/ -import Mathlib.Algebra.Group.TypeTags -import Mathlib.Algebra.Order.Monoid.Defs +import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags import Mathlib.Algebra.Order.Monoid.Canonical.Defs -/-! # Ordered monoid structures on `Multiplicative α` and `Additive α`. -/ +/-! # Bundled ordered monoid structures on `Multiplicative α` and `Additive α`. -/ variable {α : Type*} -instance : ∀ [LE α], LE (Multiplicative α) := - fun {inst} => inst - -instance : ∀ [LE α], LE (Additive α) := - fun {inst} => inst - -instance : ∀ [LT α], LT (Multiplicative α) := - fun {inst} => inst - -instance : ∀ [LT α], LT (Additive α) := - fun {inst} => inst - -instance Multiplicative.preorder : ∀ [Preorder α], Preorder (Multiplicative α) := - fun {inst} => inst - -instance Additive.preorder : ∀ [Preorder α], Preorder (Additive α) := - fun {inst} => inst - -instance Multiplicative.partialOrder : ∀ [PartialOrder α], PartialOrder (Multiplicative α) := - fun {inst} => inst - -instance Additive.partialOrder : ∀ [PartialOrder α], PartialOrder (Additive α) := - fun {inst} => inst - -instance Multiplicative.linearOrder : ∀ [LinearOrder α], LinearOrder (Multiplicative α) := - fun {inst} => inst - -instance Additive.linearOrder : ∀ [LinearOrder α], LinearOrder (Additive α) := - fun {inst} => inst - -instance Multiplicative.orderBot [LE α] : ∀ [OrderBot α], OrderBot (Multiplicative α) := - fun {inst} => inst - -instance Additive.orderBot [LE α] : ∀ [OrderBot α], OrderBot (Additive α) := - fun {inst} => inst - -instance Multiplicative.orderTop [LE α] : ∀ [OrderTop α], OrderTop (Multiplicative α) := - fun {inst} => inst - -instance Additive.orderTop [LE α] : ∀ [OrderTop α], OrderTop (Additive α) := - fun {inst} => inst - -instance Multiplicative.boundedOrder [LE α] : ∀ [BoundedOrder α], BoundedOrder (Multiplicative α) := - fun {inst} => inst - -instance Additive.boundedOrder [LE α] : ∀ [BoundedOrder α], BoundedOrder (Additive α) := - fun {inst} => inst - instance Multiplicative.orderedCommMonoid [OrderedAddCommMonoid α] : OrderedCommMonoid (Multiplicative α) := { Multiplicative.partialOrder, Multiplicative.commMonoid with @@ -87,13 +38,6 @@ instance Additive.linearOrderedAddCommMonoid [LinearOrderedCommMonoid α] : LinearOrderedAddCommMonoid (Additive α) := { Additive.linearOrder, Additive.orderedAddCommMonoid with } -instance Multiplicative.existsMulOfLe [Add α] [LE α] [ExistsAddOfLE α] : - ExistsMulOfLE (Multiplicative α) := - ⟨@exists_add_of_le α _ _ _⟩ - -instance Additive.existsAddOfLe [Mul α] [LE α] [ExistsMulOfLE α] : ExistsAddOfLE (Additive α) := - ⟨@exists_mul_of_le α _ _ _⟩ - instance Multiplicative.canonicallyOrderedCommMonoid [CanonicallyOrderedAddCommMonoid α] : CanonicallyOrderedCommMonoid (Multiplicative α) := { Multiplicative.orderedCommMonoid, Multiplicative.orderBot, @@ -112,47 +56,3 @@ instance Multiplicative.canonicallyLinearOrderedCommMonoid instance [CanonicallyLinearOrderedCommMonoid α] : CanonicallyLinearOrderedAddCommMonoid (Additive α) := { Additive.canonicallyOrderedAddCommMonoid, Additive.linearOrder with } - -namespace Additive - -variable [Preorder α] - -@[simp] -theorem ofMul_le {a b : α} : ofMul a ≤ ofMul b ↔ a ≤ b := - Iff.rfl - -@[simp] -theorem ofMul_lt {a b : α} : ofMul a < ofMul b ↔ a < b := - Iff.rfl - -@[simp] -theorem toMul_le {a b : Additive α} : toMul a ≤ toMul b ↔ a ≤ b := - Iff.rfl - -@[simp] -theorem toMul_lt {a b : Additive α} : toMul a < toMul b ↔ a < b := - Iff.rfl - -end Additive - -namespace Multiplicative - -variable [Preorder α] - -@[simp] -theorem ofAdd_le {a b : α} : ofAdd a ≤ ofAdd b ↔ a ≤ b := - Iff.rfl - -@[simp] -theorem ofAdd_lt {a b : α} : ofAdd a < ofAdd b ↔ a < b := - Iff.rfl - -@[simp] -theorem toAdd_le {a b : Multiplicative α} : toAdd a ≤ toAdd b ↔ a ≤ b := - Iff.rfl - -@[simp] -theorem toAdd_lt {a b : Multiplicative α} : toAdd a < toAdd b ↔ a < b := - Iff.rfl - -end Multiplicative diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean index f33502550e3da..10493ab993ec0 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean @@ -35,14 +35,14 @@ open Function section Nat -instance Nat.instCovariantClassMulLE : CovariantClass ℕ ℕ (· * ·) (· ≤ ·) where +instance Nat.instMulLeftMono : MulLeftMono ℕ where elim := fun _ _ _ h => mul_le_mul_left _ h end Nat section Int -instance Int.instCovariantClassAddLE : CovariantClass ℤ ℤ ((· + ·)) (· ≤ ·) where +instance Int.instAddLeftMono : AddLeftMono ℤ where elim := fun _ _ _ h => Int.add_le_add_left h _ end Int @@ -60,12 +60,12 @@ variable [LE α] /- The prime on this lemma is present only on the multiplicative version. The unprimed version is taken by the analogous lemma for semiring, with an extra non-negativity assumption. -/ @[to_additive (attr := gcongr) add_le_add_left] -theorem mul_le_mul_left' [CovariantClass α α (· * ·) (· ≤ ·)] {b c : α} (bc : b ≤ c) (a : α) : +theorem mul_le_mul_left' [MulLeftMono α] {b c : α} (bc : b ≤ c) (a : α) : a * b ≤ a * c := CovariantClass.elim _ bc @[to_additive le_of_add_le_add_left] -theorem le_of_mul_le_mul_left' [ContravariantClass α α (· * ·) (· ≤ ·)] {a b c : α} +theorem le_of_mul_le_mul_left' [MulLeftReflectLE α] {a b c : α} (bc : a * b ≤ a * c) : b ≤ c := ContravariantClass.elim _ bc @@ -73,26 +73,26 @@ theorem le_of_mul_le_mul_left' [ContravariantClass α α (· * ·) (· ≤ ·)] /- The prime on this lemma is present only on the multiplicative version. The unprimed version is taken by the analogous lemma for semiring, with an extra non-negativity assumption. -/ @[to_additive (attr := gcongr) add_le_add_right] -theorem mul_le_mul_right' [i : CovariantClass α α (swap (· * ·)) (· ≤ ·)] {b c : α} (bc : b ≤ c) +theorem mul_le_mul_right' [i : MulRightMono α] {b c : α} (bc : b ≤ c) (a : α) : b * a ≤ c * a := i.elim a bc @[to_additive le_of_add_le_add_right] -theorem le_of_mul_le_mul_right' [i : ContravariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem le_of_mul_le_mul_right' [i : MulRightReflectLE α] {a b c : α} (bc : b * a ≤ c * a) : b ≤ c := i.elim a bc @[to_additive (attr := simp)] -theorem mul_le_mul_iff_left [CovariantClass α α (· * ·) (· ≤ ·)] - [ContravariantClass α α (· * ·) (· ≤ ·)] (a : α) {b c : α} : +theorem mul_le_mul_iff_left [MulLeftMono α] + [MulLeftReflectLE α] (a : α) {b c : α} : a * b ≤ a * c ↔ b ≤ c := rel_iff_cov α α (· * ·) (· ≤ ·) a @[to_additive (attr := simp)] -theorem mul_le_mul_iff_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] - [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] (a : α) {b c : α} : +theorem mul_le_mul_iff_right [MulRightMono α] + [MulRightReflectLE α] (a : α) {b c : α} : b * a ≤ c * a ↔ b ≤ c := rel_iff_cov α α (swap (· * ·)) (· ≤ ·) a @@ -103,36 +103,36 @@ section LT variable [LT α] @[to_additive (attr := simp)] -theorem mul_lt_mul_iff_left [CovariantClass α α (· * ·) (· < ·)] - [ContravariantClass α α (· * ·) (· < ·)] (a : α) {b c : α} : +theorem mul_lt_mul_iff_left [MulLeftStrictMono α] + [MulLeftReflectLT α] (a : α) {b c : α} : a * b < a * c ↔ b < c := rel_iff_cov α α (· * ·) (· < ·) a @[to_additive (attr := simp)] -theorem mul_lt_mul_iff_right [CovariantClass α α (swap (· * ·)) (· < ·)] - [ContravariantClass α α (swap (· * ·)) (· < ·)] (a : α) {b c : α} : +theorem mul_lt_mul_iff_right [MulRightStrictMono α] + [MulRightReflectLT α] (a : α) {b c : α} : b * a < c * a ↔ b < c := rel_iff_cov α α (swap (· * ·)) (· < ·) a @[to_additive (attr := gcongr) add_lt_add_left] -theorem mul_lt_mul_left' [CovariantClass α α (· * ·) (· < ·)] {b c : α} (bc : b < c) (a : α) : +theorem mul_lt_mul_left' [MulLeftStrictMono α] {b c : α} (bc : b < c) (a : α) : a * b < a * c := CovariantClass.elim _ bc @[to_additive lt_of_add_lt_add_left] -theorem lt_of_mul_lt_mul_left' [ContravariantClass α α (· * ·) (· < ·)] {a b c : α} +theorem lt_of_mul_lt_mul_left' [MulLeftReflectLT α] {a b c : α} (bc : a * b < a * c) : b < c := ContravariantClass.elim _ bc @[to_additive (attr := gcongr) add_lt_add_right] -theorem mul_lt_mul_right' [i : CovariantClass α α (swap (· * ·)) (· < ·)] {b c : α} (bc : b < c) +theorem mul_lt_mul_right' [i : MulRightStrictMono α] {b c : α} (bc : b < c) (a : α) : b * a < c * a := i.elim a bc @[to_additive lt_of_add_lt_add_right] -theorem lt_of_mul_lt_mul_right' [i : ContravariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} +theorem lt_of_mul_lt_mul_right' [i : MulRightReflectLT α] {a b c : α} (bc : b * a < c * a) : b < c := i.elim a bc @@ -144,8 +144,8 @@ section Preorder variable [Preorder α] @[to_additive (attr := gcongr)] -theorem mul_lt_mul_of_lt_of_lt [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] +theorem mul_lt_mul_of_lt_of_lt [MulLeftStrictMono α] + [MulRightStrictMono α] {a b c d : α} (h₁ : a < b) (h₂ : c < d) : a * c < b * d := calc a * c < a * d := mul_lt_mul_left' h₂ a @@ -154,89 +154,89 @@ theorem mul_lt_mul_of_lt_of_lt [CovariantClass α α (· * ·) (· < ·)] alias add_lt_add := add_lt_add_of_lt_of_lt @[to_additive] -theorem mul_lt_mul_of_le_of_lt [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} (h₁ : a ≤ b) (h₂ : c < d) : +theorem mul_lt_mul_of_le_of_lt [MulLeftStrictMono α] + [MulRightMono α] {a b c d : α} (h₁ : a ≤ b) (h₂ : c < d) : a * c < b * d := (mul_le_mul_right' h₁ _).trans_lt (mul_lt_mul_left' h₂ b) @[to_additive] -theorem mul_lt_mul_of_lt_of_le [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c d : α} (h₁ : a < b) (h₂ : c ≤ d) : +theorem mul_lt_mul_of_lt_of_le [MulLeftMono α] + [MulRightStrictMono α] {a b c d : α} (h₁ : a < b) (h₂ : c ≤ d) : a * c < b * d := (mul_le_mul_left' h₂ _).trans_lt (mul_lt_mul_right' h₁ d) /-- Only assumes left strict covariance. -/ @[to_additive "Only assumes left strict covariance"] -theorem Left.mul_lt_mul [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} (h₁ : a < b) (h₂ : c < d) : +theorem Left.mul_lt_mul [MulLeftStrictMono α] + [MulRightMono α] {a b c d : α} (h₁ : a < b) (h₂ : c < d) : a * c < b * d := mul_lt_mul_of_le_of_lt h₁.le h₂ /-- Only assumes right strict covariance. -/ @[to_additive "Only assumes right strict covariance"] -theorem Right.mul_lt_mul [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c d : α} +theorem Right.mul_lt_mul [MulLeftMono α] + [MulRightStrictMono α] {a b c d : α} (h₁ : a < b) (h₂ : c < d) : a * c < b * d := mul_lt_mul_of_lt_of_le h₁ h₂.le @[to_additive (attr := gcongr) add_le_add] -theorem mul_le_mul' [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] +theorem mul_le_mul' [MulLeftMono α] [MulRightMono α] {a b c d : α} (h₁ : a ≤ b) (h₂ : c ≤ d) : a * c ≤ b * d := (mul_le_mul_left' h₂ _).trans (mul_le_mul_right' h₁ d) @[to_additive] -theorem mul_le_mul_three [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d e f : α} (h₁ : a ≤ d) (h₂ : b ≤ e) +theorem mul_le_mul_three [MulLeftMono α] + [MulRightMono α] {a b c d e f : α} (h₁ : a ≤ d) (h₂ : b ≤ e) (h₃ : c ≤ f) : a * b * c ≤ d * e * f := mul_le_mul' (mul_le_mul' h₁ h₂) h₃ @[to_additive] -theorem mul_lt_of_mul_lt_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} (h : a * b < c) +theorem mul_lt_of_mul_lt_left [MulLeftMono α] {a b c d : α} (h : a * b < c) (hle : d ≤ b) : a * d < c := (mul_le_mul_left' hle a).trans_lt h @[to_additive] -theorem mul_le_of_mul_le_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} (h : a * b ≤ c) +theorem mul_le_of_mul_le_left [MulLeftMono α] {a b c d : α} (h : a * b ≤ c) (hle : d ≤ b) : a * d ≤ c := @act_rel_of_rel_of_act_rel _ _ _ (· ≤ ·) _ _ a _ _ _ hle h @[to_additive] -theorem mul_lt_of_mul_lt_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +theorem mul_lt_of_mul_lt_right [MulRightMono α] {a b c d : α} (h : a * b < c) (hle : d ≤ a) : d * b < c := (mul_le_mul_right' hle b).trans_lt h @[to_additive] -theorem mul_le_of_mul_le_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +theorem mul_le_of_mul_le_right [MulRightMono α] {a b c d : α} (h : a * b ≤ c) (hle : d ≤ a) : d * b ≤ c := (mul_le_mul_right' hle b).trans h @[to_additive] -theorem lt_mul_of_lt_mul_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} (h : a < b * c) +theorem lt_mul_of_lt_mul_left [MulLeftMono α] {a b c d : α} (h : a < b * c) (hle : c ≤ d) : a < b * d := h.trans_le (mul_le_mul_left' hle b) @[to_additive] -theorem le_mul_of_le_mul_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} (h : a ≤ b * c) +theorem le_mul_of_le_mul_left [MulLeftMono α] {a b c d : α} (h : a ≤ b * c) (hle : c ≤ d) : a ≤ b * d := @rel_act_of_rel_of_rel_act _ _ _ (· ≤ ·) _ _ b _ _ _ hle h @[to_additive] -theorem lt_mul_of_lt_mul_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +theorem lt_mul_of_lt_mul_right [MulRightMono α] {a b c d : α} (h : a < b * c) (hle : b ≤ d) : a < d * c := h.trans_le (mul_le_mul_right' hle c) @[to_additive] -theorem le_mul_of_le_mul_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +theorem le_mul_of_le_mul_right [MulRightMono α] {a b c d : α} (h : a ≤ b * c) (hle : b ≤ d) : a ≤ d * c := h.trans (mul_le_mul_right' hle c) @@ -248,31 +248,31 @@ section PartialOrder variable [PartialOrder α] @[to_additive] -theorem mul_left_cancel'' [ContravariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (h : a * b = a * c) : +theorem mul_left_cancel'' [MulLeftReflectLE α] {a b c : α} (h : a * b = a * c) : b = c := (le_of_mul_le_mul_left' h.le).antisymm (le_of_mul_le_mul_left' h.ge) @[to_additive] -theorem mul_right_cancel'' [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem mul_right_cancel'' [MulRightReflectLE α] {a b c : α} (h : a * b = c * b) : a = c := (le_of_mul_le_mul_right' h.le).antisymm (le_of_mul_le_mul_right' h.ge) -@[to_additive] lemma mul_le_mul_iff_of_ge [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] {a₁ a₂ b₁ b₂ : α} (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) : +@[to_additive] lemma mul_le_mul_iff_of_ge [MulLeftStrictMono α] + [MulRightStrictMono α] {a₁ a₂ b₁ b₂ : α} (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) : a₂ * b₂ ≤ a₁ * b₁ ↔ a₁ = a₂ ∧ b₁ = b₂ := by - haveI := covariantClass_le_of_lt α α (· * ·) - haveI := covariantClass_le_of_lt α α (swap (· * ·)) + haveI := mulLeftMono_of_mulLeftStrictMono α + haveI := mulRightMono_of_mulRightStrictMono α refine ⟨fun h ↦ ?_, by rintro ⟨rfl, rfl⟩; rfl⟩ simp only [eq_iff_le_not_lt, ha, hb, true_and] refine ⟨fun ha ↦ h.not_lt ?_, fun hb ↦ h.not_lt ?_⟩ exacts [mul_lt_mul_of_lt_of_le ha hb, mul_lt_mul_of_le_of_lt ha hb] -@[to_additive] theorem mul_eq_mul_iff_eq_and_eq [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c d : α} (hac : a ≤ c) (hbd : b ≤ d) : +@[to_additive] theorem mul_eq_mul_iff_eq_and_eq [MulLeftStrictMono α] + [MulRightStrictMono α] {a b c d : α} (hac : a ≤ c) (hbd : b ≤ d) : a * b = c * d ↔ a = c ∧ b = d := by - haveI := covariantClass_le_of_lt α α (· * ·) - haveI := covariantClass_le_of_lt α α (swap (· * ·)) + haveI := mulLeftMono_of_mulLeftStrictMono α + haveI := mulRightMono_of_mulRightStrictMono α rw [le_antisymm_iff, eq_true (mul_le_mul' hac hbd), true_and, mul_le_mul_iff_of_ge hac hbd] end PartialOrder @@ -281,31 +281,30 @@ section LinearOrder variable [LinearOrder α] {a b c d : α} @[to_additive] lemma min_lt_max_of_mul_lt_mul - [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] + [MulLeftMono α] [MulRightMono α] (h : a * b < c * d) : min a b < max c d := by simp_rw [min_lt_iff, lt_max_iff]; contrapose! h; exact mul_le_mul' h.1.1 h.2.2 @[to_additive] lemma Left.min_le_max_of_mul_le_mul - [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] + [MulLeftStrictMono α] [MulRightMono α] (h : a * b ≤ c * d) : min a b ≤ max c d := by simp_rw [min_le_iff, le_max_iff]; contrapose! h; exact mul_lt_mul_of_le_of_lt h.1.1.le h.2.2 @[to_additive] lemma Right.min_le_max_of_mul_le_mul - [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· < ·)] + [MulLeftMono α] [MulRightStrictMono α] (h : a * b ≤ c * d) : min a b ≤ max c d := by simp_rw [min_le_iff, le_max_iff]; contrapose! h; exact mul_lt_mul_of_lt_of_le h.1.1 h.2.2.le @[to_additive] lemma min_le_max_of_mul_le_mul - [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (swap (· * ·)) (· < ·)] + [MulLeftStrictMono α] [MulRightStrictMono α] (h : a * b ≤ c * d) : min a b ≤ max c d := - let _ := covariantClass_le_of_lt α α (swap (· * ·)) + haveI := mulRightMono_of_mulRightStrictMono α Left.min_le_max_of_mul_le_mul h end LinearOrder section LinearOrder -variable [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +variable [LinearOrder α] [MulLeftMono α] [MulRightMono α] {a b c d : α} @[to_additive max_add_add_le_max_add_max] theorem max_mul_mul_le_max_mul_max' : max (a * b) (c * d) ≤ max a c * max b d := @@ -330,76 +329,76 @@ section LE variable [LE α] @[to_additive le_add_of_nonneg_right] -theorem le_mul_of_one_le_right' [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (h : 1 ≤ b) : +theorem le_mul_of_one_le_right' [MulLeftMono α] {a b : α} (h : 1 ≤ b) : a ≤ a * b := calc a = a * 1 := (mul_one a).symm _ ≤ a * b := mul_le_mul_left' h a @[to_additive add_le_of_nonpos_right] -theorem mul_le_of_le_one_right' [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (h : b ≤ 1) : +theorem mul_le_of_le_one_right' [MulLeftMono α] {a b : α} (h : b ≤ 1) : a * b ≤ a := calc a * b ≤ a * 1 := mul_le_mul_left' h a _ = a := mul_one a @[to_additive le_add_of_nonneg_left] -theorem le_mul_of_one_le_left' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (h : 1 ≤ b) : +theorem le_mul_of_one_le_left' [MulRightMono α] {a b : α} (h : 1 ≤ b) : a ≤ b * a := calc a = 1 * a := (one_mul a).symm _ ≤ b * a := mul_le_mul_right' h a @[to_additive add_le_of_nonpos_left] -theorem mul_le_of_le_one_left' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (h : b ≤ 1) : +theorem mul_le_of_le_one_left' [MulRightMono α] {a b : α} (h : b ≤ 1) : b * a ≤ a := calc b * a ≤ 1 * a := mul_le_mul_right' h a _ = a := one_mul a @[to_additive] -theorem one_le_of_le_mul_right [ContravariantClass α α (· * ·) (· ≤ ·)] {a b : α} (h : a ≤ a * b) : +theorem one_le_of_le_mul_right [MulLeftReflectLE α] {a b : α} (h : a ≤ a * b) : 1 ≤ b := le_of_mul_le_mul_left' (a := a) <| by simpa only [mul_one] @[to_additive] -theorem le_one_of_mul_le_right [ContravariantClass α α (· * ·) (· ≤ ·)] {a b : α} (h : a * b ≤ a) : +theorem le_one_of_mul_le_right [MulLeftReflectLE α] {a b : α} (h : a * b ≤ a) : b ≤ 1 := le_of_mul_le_mul_left' (a := a) <| by simpa only [mul_one] @[to_additive] -theorem one_le_of_le_mul_left [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} +theorem one_le_of_le_mul_left [MulRightReflectLE α] {a b : α} (h : b ≤ a * b) : 1 ≤ a := le_of_mul_le_mul_right' (a := b) <| by simpa only [one_mul] @[to_additive] -theorem le_one_of_mul_le_left [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} +theorem le_one_of_mul_le_left [MulRightReflectLE α] {a b : α} (h : a * b ≤ b) : a ≤ 1 := le_of_mul_le_mul_right' (a := b) <| by simpa only [one_mul] @[to_additive (attr := simp) le_add_iff_nonneg_right] -theorem le_mul_iff_one_le_right' [CovariantClass α α (· * ·) (· ≤ ·)] - [ContravariantClass α α (· * ·) (· ≤ ·)] (a : α) {b : α} : +theorem le_mul_iff_one_le_right' [MulLeftMono α] + [MulLeftReflectLE α] (a : α) {b : α} : a ≤ a * b ↔ 1 ≤ b := Iff.trans (by rw [mul_one]) (mul_le_mul_iff_left a) @[to_additive (attr := simp) le_add_iff_nonneg_left] -theorem le_mul_iff_one_le_left' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] - [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] (a : α) {b : α} : +theorem le_mul_iff_one_le_left' [MulRightMono α] + [MulRightReflectLE α] (a : α) {b : α} : a ≤ b * a ↔ 1 ≤ b := Iff.trans (by rw [one_mul]) (mul_le_mul_iff_right a) @[to_additive (attr := simp) add_le_iff_nonpos_right] -theorem mul_le_iff_le_one_right' [CovariantClass α α (· * ·) (· ≤ ·)] - [ContravariantClass α α (· * ·) (· ≤ ·)] (a : α) {b : α} : +theorem mul_le_iff_le_one_right' [MulLeftMono α] + [MulLeftReflectLE α] (a : α) {b : α} : a * b ≤ a ↔ b ≤ 1 := Iff.trans (by rw [mul_one]) (mul_le_mul_iff_left a) @[to_additive (attr := simp) add_le_iff_nonpos_left] -theorem mul_le_iff_le_one_left' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] - [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} : +theorem mul_le_iff_le_one_left' [MulRightMono α] + [MulRightReflectLE α] {a b : α} : a * b ≤ b ↔ a ≤ 1 := Iff.trans (by rw [one_mul]) (mul_le_mul_iff_right b) @@ -410,21 +409,21 @@ section LT variable [LT α] @[to_additive lt_add_of_pos_right] -theorem lt_mul_of_one_lt_right' [CovariantClass α α (· * ·) (· < ·)] (a : α) {b : α} (h : 1 < b) : +theorem lt_mul_of_one_lt_right' [MulLeftStrictMono α] (a : α) {b : α} (h : 1 < b) : a < a * b := calc a = a * 1 := (mul_one a).symm _ < a * b := mul_lt_mul_left' h a @[to_additive add_lt_of_neg_right] -theorem mul_lt_of_lt_one_right' [CovariantClass α α (· * ·) (· < ·)] (a : α) {b : α} (h : b < 1) : +theorem mul_lt_of_lt_one_right' [MulLeftStrictMono α] (a : α) {b : α} (h : b < 1) : a * b < a := calc a * b < a * 1 := mul_lt_mul_left' h a _ = a := mul_one a @[to_additive lt_add_of_pos_left] -theorem lt_mul_of_one_lt_left' [CovariantClass α α (swap (· * ·)) (· < ·)] (a : α) {b : α} +theorem lt_mul_of_one_lt_left' [MulRightStrictMono α] (a : α) {b : α} (h : 1 < b) : a < b * a := calc @@ -432,7 +431,7 @@ theorem lt_mul_of_one_lt_left' [CovariantClass α α (swap (· * ·)) (· < ·)] _ < b * a := mul_lt_mul_right' h a @[to_additive add_lt_of_neg_left] -theorem mul_lt_of_lt_one_left' [CovariantClass α α (swap (· * ·)) (· < ·)] (a : α) {b : α} +theorem mul_lt_of_lt_one_left' [MulRightStrictMono α] (a : α) {b : α} (h : b < 1) : b * a < a := calc @@ -440,47 +439,47 @@ theorem mul_lt_of_lt_one_left' [CovariantClass α α (swap (· * ·)) (· < ·)] _ = a := one_mul a @[to_additive] -theorem one_lt_of_lt_mul_right [ContravariantClass α α (· * ·) (· < ·)] {a b : α} (h : a < a * b) : +theorem one_lt_of_lt_mul_right [MulLeftReflectLT α] {a b : α} (h : a < a * b) : 1 < b := lt_of_mul_lt_mul_left' (a := a) <| by simpa only [mul_one] @[to_additive] -theorem lt_one_of_mul_lt_right [ContravariantClass α α (· * ·) (· < ·)] {a b : α} (h : a * b < a) : +theorem lt_one_of_mul_lt_right [MulLeftReflectLT α] {a b : α} (h : a * b < a) : b < 1 := lt_of_mul_lt_mul_left' (a := a) <| by simpa only [mul_one] @[to_additive] -theorem one_lt_of_lt_mul_left [ContravariantClass α α (swap (· * ·)) (· < ·)] {a b : α} +theorem one_lt_of_lt_mul_left [MulRightReflectLT α] {a b : α} (h : b < a * b) : 1 < a := lt_of_mul_lt_mul_right' (a := b) <| by simpa only [one_mul] @[to_additive] -theorem lt_one_of_mul_lt_left [ContravariantClass α α (swap (· * ·)) (· < ·)] {a b : α} +theorem lt_one_of_mul_lt_left [MulRightReflectLT α] {a b : α} (h : a * b < b) : a < 1 := lt_of_mul_lt_mul_right' (a := b) <| by simpa only [one_mul] @[to_additive (attr := simp) lt_add_iff_pos_right] -theorem lt_mul_iff_one_lt_right' [CovariantClass α α (· * ·) (· < ·)] - [ContravariantClass α α (· * ·) (· < ·)] (a : α) {b : α} : +theorem lt_mul_iff_one_lt_right' [MulLeftStrictMono α] + [MulLeftReflectLT α] (a : α) {b : α} : a < a * b ↔ 1 < b := Iff.trans (by rw [mul_one]) (mul_lt_mul_iff_left a) @[to_additive (attr := simp) lt_add_iff_pos_left] -theorem lt_mul_iff_one_lt_left' [CovariantClass α α (swap (· * ·)) (· < ·)] - [ContravariantClass α α (swap (· * ·)) (· < ·)] (a : α) {b : α} : a < b * a ↔ 1 < b := +theorem lt_mul_iff_one_lt_left' [MulRightStrictMono α] + [MulRightReflectLT α] (a : α) {b : α} : a < b * a ↔ 1 < b := Iff.trans (by rw [one_mul]) (mul_lt_mul_iff_right a) @[to_additive (attr := simp) add_lt_iff_neg_left] -theorem mul_lt_iff_lt_one_left' [CovariantClass α α (· * ·) (· < ·)] - [ContravariantClass α α (· * ·) (· < ·)] {a b : α} : +theorem mul_lt_iff_lt_one_left' [MulLeftStrictMono α] + [MulLeftReflectLT α] {a b : α} : a * b < a ↔ b < 1 := Iff.trans (by rw [mul_one]) (mul_lt_mul_iff_left a) @[to_additive (attr := simp) add_lt_iff_neg_right] -theorem mul_lt_iff_lt_one_right' [CovariantClass α α (swap (· * ·)) (· < ·)] - [ContravariantClass α α (swap (· * ·)) (· < ·)] {a : α} (b : α) : a * b < b ↔ a < 1 := +theorem mul_lt_iff_lt_one_right' [MulRightStrictMono α] + [MulRightReflectLT α] {a : α} (b : α) : a * b < b ↔ a < 1 := Iff.trans (by rw [one_mul]) (mul_lt_mul_iff_right b) end LT @@ -494,7 +493,7 @@ which assume left covariance. -/ @[to_additive] -theorem mul_le_of_le_of_le_one [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b ≤ c) +theorem mul_le_of_le_of_le_one [MulLeftMono α] {a b c : α} (hbc : b ≤ c) (ha : a ≤ 1) : b * a ≤ c := calc @@ -503,7 +502,7 @@ theorem mul_le_of_le_of_le_one [CovariantClass α α (· * ·) (· ≤ ·)] {a b _ ≤ c := hbc @[to_additive] -theorem mul_lt_of_le_of_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b c : α} (hbc : b ≤ c) +theorem mul_lt_of_le_of_lt_one [MulLeftStrictMono α] {a b c : α} (hbc : b ≤ c) (ha : a < 1) : b * a < c := calc @@ -512,7 +511,7 @@ theorem mul_lt_of_le_of_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b c _ ≤ c := hbc @[to_additive] -theorem mul_lt_of_lt_of_le_one [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b < c) +theorem mul_lt_of_lt_of_le_one [MulLeftMono α] {a b c : α} (hbc : b < c) (ha : a ≤ 1) : b * a < c := calc @@ -521,7 +520,7 @@ theorem mul_lt_of_lt_of_le_one [CovariantClass α α (· * ·) (· ≤ ·)] {a b _ < c := hbc @[to_additive] -theorem mul_lt_of_lt_of_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b c : α} (hbc : b < c) +theorem mul_lt_of_lt_of_lt_one [MulLeftStrictMono α] {a b c : α} (hbc : b < c) (ha : a < 1) : b * a < c := calc @@ -530,7 +529,7 @@ theorem mul_lt_of_lt_of_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b c _ < c := hbc @[to_additive] -theorem mul_lt_of_lt_of_lt_one' [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b < c) +theorem mul_lt_of_lt_of_lt_one' [MulLeftMono α] {a b c : α} (hbc : b < c) (ha : a < 1) : b * a < c := mul_lt_of_lt_of_le_one hbc ha.le @@ -539,7 +538,7 @@ theorem mul_lt_of_lt_of_lt_one' [CovariantClass α α (· * ·) (· ≤ ·)] {a The lemma assuming right covariance is `Right.mul_le_one`. -/ @[to_additive "Assumes left covariance. The lemma assuming right covariance is `Right.add_nonpos`."] -theorem Left.mul_le_one [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : a ≤ 1) (hb : b ≤ 1) : +theorem Left.mul_le_one [MulLeftMono α] {a b : α} (ha : a ≤ 1) (hb : b ≤ 1) : a * b ≤ 1 := mul_le_of_le_of_le_one ha hb @@ -548,7 +547,7 @@ The lemma assuming right covariance is `Right.mul_lt_one_of_le_of_lt`. -/ @[to_additive Left.add_neg_of_nonpos_of_neg "Assumes left covariance. The lemma assuming right covariance is `Right.add_neg_of_nonpos_of_neg`."] -theorem Left.mul_lt_one_of_le_of_lt [CovariantClass α α (· * ·) (· < ·)] {a b : α} (ha : a ≤ 1) +theorem Left.mul_lt_one_of_le_of_lt [MulLeftStrictMono α] {a b : α} (ha : a ≤ 1) (hb : b < 1) : a * b < 1 := mul_lt_of_le_of_lt_one ha hb @@ -558,7 +557,7 @@ The lemma assuming right covariance is `Right.mul_lt_one_of_lt_of_le`. -/ @[to_additive Left.add_neg_of_neg_of_nonpos "Assumes left covariance. The lemma assuming right covariance is `Right.add_neg_of_neg_of_nonpos`."] -theorem Left.mul_lt_one_of_lt_of_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : a < 1) +theorem Left.mul_lt_one_of_lt_of_le [MulLeftMono α] {a b : α} (ha : a < 1) (hb : b ≤ 1) : a * b < 1 := mul_lt_of_lt_of_le_one ha hb @@ -567,7 +566,7 @@ theorem Left.mul_lt_one_of_lt_of_le [CovariantClass α α (· * ·) (· ≤ ·)] The lemma assuming right covariance is `Right.mul_lt_one`. -/ @[to_additive "Assumes left covariance. The lemma assuming right covariance is `Right.add_neg`."] -theorem Left.mul_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b : α} (ha : a < 1) (hb : b < 1) : +theorem Left.mul_lt_one [MulLeftStrictMono α] {a b : α} (ha : a < 1) (hb : b < 1) : a * b < 1 := mul_lt_of_lt_of_lt_one ha hb @@ -575,7 +574,7 @@ theorem Left.mul_lt_one [CovariantClass α α (· * ·) (· < ·)] {a b : α} (h The lemma assuming right covariance is `Right.mul_lt_one'`. -/ @[to_additive "Assumes left covariance. The lemma assuming right covariance is `Right.add_neg'`."] -theorem Left.mul_lt_one' [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : a < 1) (hb : b < 1) : +theorem Left.mul_lt_one' [MulLeftMono α] {a b : α} (ha : a < 1) (hb : b < 1) : a * b < 1 := mul_lt_of_lt_of_lt_one' ha hb @@ -584,7 +583,7 @@ which assume left covariance. -/ @[to_additive] -theorem le_mul_of_le_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b ≤ c) +theorem le_mul_of_le_of_one_le [MulLeftMono α] {a b c : α} (hbc : b ≤ c) (ha : 1 ≤ a) : b ≤ c * a := calc @@ -593,7 +592,7 @@ theorem le_mul_of_le_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b _ ≤ c * a := mul_le_mul_left' ha c @[to_additive] -theorem lt_mul_of_le_of_one_lt [CovariantClass α α (· * ·) (· < ·)] {a b c : α} (hbc : b ≤ c) +theorem lt_mul_of_le_of_one_lt [MulLeftStrictMono α] {a b c : α} (hbc : b ≤ c) (ha : 1 < a) : b < c * a := calc @@ -602,7 +601,7 @@ theorem lt_mul_of_le_of_one_lt [CovariantClass α α (· * ·) (· < ·)] {a b c _ < c * a := mul_lt_mul_left' ha c @[to_additive] -theorem lt_mul_of_lt_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b < c) +theorem lt_mul_of_lt_of_one_le [MulLeftMono α] {a b c : α} (hbc : b < c) (ha : 1 ≤ a) : b < c * a := calc @@ -611,7 +610,7 @@ theorem lt_mul_of_lt_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b _ ≤ c * a := mul_le_mul_left' ha c @[to_additive] -theorem lt_mul_of_lt_of_one_lt [CovariantClass α α (· * ·) (· < ·)] {a b c : α} (hbc : b < c) +theorem lt_mul_of_lt_of_one_lt [MulLeftStrictMono α] {a b c : α} (hbc : b < c) (ha : 1 < a) : b < c * a := calc @@ -620,7 +619,7 @@ theorem lt_mul_of_lt_of_one_lt [CovariantClass α α (· * ·) (· < ·)] {a b c _ < c * a := mul_lt_mul_left' ha c @[to_additive] -theorem lt_mul_of_lt_of_one_lt' [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (hbc : b < c) +theorem lt_mul_of_lt_of_one_lt' [MulLeftMono α] {a b c : α} (hbc : b < c) (ha : 1 < a) : b < c * a := lt_mul_of_lt_of_one_le hbc ha.le @@ -629,7 +628,7 @@ theorem lt_mul_of_lt_of_one_lt' [CovariantClass α α (· * ·) (· ≤ ·)] {a The lemma assuming right covariance is `Right.one_le_mul`. -/ @[to_additive Left.add_nonneg "Assumes left covariance. The lemma assuming right covariance is `Right.add_nonneg`."] -theorem Left.one_le_mul [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : +theorem Left.one_le_mul [MulLeftMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : 1 ≤ a * b := le_mul_of_le_of_one_le ha hb @@ -638,7 +637,7 @@ The lemma assuming right covariance is `Right.one_lt_mul_of_le_of_lt`. -/ @[to_additive Left.add_pos_of_nonneg_of_pos "Assumes left covariance. The lemma assuming right covariance is `Right.add_pos_of_nonneg_of_pos`."] -theorem Left.one_lt_mul_of_le_of_lt [CovariantClass α α (· * ·) (· < ·)] {a b : α} (ha : 1 ≤ a) +theorem Left.one_lt_mul_of_le_of_lt [MulLeftStrictMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 < b) : 1 < a * b := lt_mul_of_le_of_one_lt ha hb @@ -648,7 +647,7 @@ The lemma assuming right covariance is `Right.one_lt_mul_of_lt_of_le`. -/ @[to_additive Left.add_pos_of_pos_of_nonneg "Assumes left covariance. The lemma assuming right covariance is `Right.add_pos_of_pos_of_nonneg`."] -theorem Left.one_lt_mul_of_lt_of_le [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : 1 < a) +theorem Left.one_lt_mul_of_lt_of_le [MulLeftMono α] {a b : α} (ha : 1 < a) (hb : 1 ≤ b) : 1 < a * b := lt_mul_of_lt_of_one_le ha hb @@ -657,7 +656,7 @@ theorem Left.one_lt_mul_of_lt_of_le [CovariantClass α α (· * ·) (· ≤ ·)] The lemma assuming right covariance is `Right.one_lt_mul`. -/ @[to_additive Left.add_pos "Assumes left covariance. The lemma assuming right covariance is `Right.add_pos`."] -theorem Left.one_lt_mul [CovariantClass α α (· * ·) (· < ·)] {a b : α} (ha : 1 < a) (hb : 1 < b) : +theorem Left.one_lt_mul [MulLeftStrictMono α] {a b : α} (ha : 1 < a) (hb : 1 < b) : 1 < a * b := lt_mul_of_lt_of_one_lt ha hb @@ -665,7 +664,7 @@ theorem Left.one_lt_mul [CovariantClass α α (· * ·) (· < ·)] {a b : α} (h The lemma assuming right covariance is `Right.one_lt_mul'`. -/ @[to_additive Left.add_pos' "Assumes left covariance. The lemma assuming right covariance is `Right.add_pos'`."] -theorem Left.one_lt_mul' [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : 1 < a) (hb : 1 < b) : +theorem Left.one_lt_mul' [MulLeftMono α] {a b : α} (ha : 1 < a) (hb : 1 < b) : 1 < a * b := lt_mul_of_lt_of_one_lt' ha hb @@ -674,7 +673,7 @@ which assume right covariance. -/ @[to_additive] -theorem mul_le_of_le_one_of_le [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : a ≤ 1) +theorem mul_le_of_le_one_of_le [MulRightMono α] {a b c : α} (ha : a ≤ 1) (hbc : b ≤ c) : a * b ≤ c := calc @@ -683,7 +682,7 @@ theorem mul_le_of_le_one_of_le [CovariantClass α α (swap (· * ·)) (· ≤ · _ ≤ c := hbc @[to_additive] -theorem mul_lt_of_lt_one_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} (ha : a < 1) +theorem mul_lt_of_lt_one_of_le [MulRightStrictMono α] {a b c : α} (ha : a < 1) (hbc : b ≤ c) : a * b < c := calc @@ -692,7 +691,7 @@ theorem mul_lt_of_lt_one_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] _ ≤ c := hbc @[to_additive] -theorem mul_lt_of_le_one_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : a ≤ 1) +theorem mul_lt_of_le_one_of_lt [MulRightMono α] {a b c : α} (ha : a ≤ 1) (hb : b < c) : a * b < c := calc @@ -701,7 +700,7 @@ theorem mul_lt_of_le_one_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ · _ < c := hb @[to_additive] -theorem mul_lt_of_lt_one_of_lt [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} (ha : a < 1) +theorem mul_lt_of_lt_one_of_lt [MulRightStrictMono α] {a b c : α} (ha : a < 1) (hb : b < c) : a * b < c := calc @@ -710,7 +709,7 @@ theorem mul_lt_of_lt_one_of_lt [CovariantClass α α (swap (· * ·)) (· < ·)] _ < c := hb @[to_additive] -theorem mul_lt_of_lt_one_of_lt' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : a < 1) +theorem mul_lt_of_lt_one_of_lt' [MulRightMono α] {a b c : α} (ha : a < 1) (hbc : b < c) : a * b < c := mul_lt_of_le_one_of_lt ha.le hbc @@ -719,7 +718,7 @@ theorem mul_lt_of_lt_one_of_lt' [CovariantClass α α (swap (· * ·)) (· ≤ The lemma assuming left covariance is `Left.mul_le_one`. -/ @[to_additive "Assumes right covariance. The lemma assuming left covariance is `Left.add_nonpos`."] -theorem Right.mul_le_one [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (ha : a ≤ 1) +theorem Right.mul_le_one [MulRightMono α] {a b : α} (ha : a ≤ 1) (hb : b ≤ 1) : a * b ≤ 1 := mul_le_of_le_one_of_le ha hb @@ -729,7 +728,7 @@ The lemma assuming left covariance is `Left.mul_lt_one_of_lt_of_le`. -/ @[to_additive Right.add_neg_of_neg_of_nonpos "Assumes right covariance. The lemma assuming left covariance is `Left.add_neg_of_neg_of_nonpos`."] -theorem Right.mul_lt_one_of_lt_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] {a b : α} +theorem Right.mul_lt_one_of_lt_of_le [MulRightStrictMono α] {a b : α} (ha : a < 1) (hb : b ≤ 1) : a * b < 1 := mul_lt_of_lt_one_of_le ha hb @@ -739,7 +738,7 @@ The lemma assuming left covariance is `Left.mul_lt_one_of_le_of_lt`. -/ @[to_additive Right.add_neg_of_nonpos_of_neg "Assumes right covariance. The lemma assuming left covariance is `Left.add_neg_of_nonpos_of_neg`."] -theorem Right.mul_lt_one_of_le_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} +theorem Right.mul_lt_one_of_le_of_lt [MulRightMono α] {a b : α} (ha : a ≤ 1) (hb : b < 1) : a * b < 1 := mul_lt_of_le_one_of_lt ha hb @@ -748,7 +747,7 @@ theorem Right.mul_lt_one_of_le_of_lt [CovariantClass α α (swap (· * ·)) (· The lemma assuming left covariance is `Left.mul_lt_one`. -/ @[to_additive "Assumes right covariance. The lemma assuming left covariance is `Left.add_neg`."] -theorem Right.mul_lt_one [CovariantClass α α (swap (· * ·)) (· < ·)] {a b : α} (ha : a < 1) +theorem Right.mul_lt_one [MulRightStrictMono α] {a b : α} (ha : a < 1) (hb : b < 1) : a * b < 1 := mul_lt_of_lt_one_of_lt ha hb @@ -757,7 +756,7 @@ theorem Right.mul_lt_one [CovariantClass α α (swap (· * ·)) (· < ·)] {a b The lemma assuming left covariance is `Left.mul_lt_one'`. -/ @[to_additive "Assumes right covariance. The lemma assuming left covariance is `Left.add_neg'`."] -theorem Right.mul_lt_one' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (ha : a < 1) +theorem Right.mul_lt_one' [MulRightMono α] {a b : α} (ha : a < 1) (hb : b < 1) : a * b < 1 := mul_lt_of_lt_one_of_lt' ha hb @@ -767,7 +766,7 @@ which assume right covariance. -/ @[to_additive] -theorem le_mul_of_one_le_of_le [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : 1 ≤ a) +theorem le_mul_of_one_le_of_le [MulRightMono α] {a b c : α} (ha : 1 ≤ a) (hbc : b ≤ c) : b ≤ a * c := calc @@ -776,7 +775,7 @@ theorem le_mul_of_one_le_of_le [CovariantClass α α (swap (· * ·)) (· ≤ · _ ≤ a * c := mul_le_mul_right' ha c @[to_additive] -theorem lt_mul_of_one_lt_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} (ha : 1 < a) +theorem lt_mul_of_one_lt_of_le [MulRightStrictMono α] {a b c : α} (ha : 1 < a) (hbc : b ≤ c) : b < a * c := calc @@ -785,7 +784,7 @@ theorem lt_mul_of_one_lt_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] _ < a * c := mul_lt_mul_right' ha c @[to_additive] -theorem lt_mul_of_one_le_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : 1 ≤ a) +theorem lt_mul_of_one_le_of_lt [MulRightMono α] {a b c : α} (ha : 1 ≤ a) (hbc : b < c) : b < a * c := calc @@ -794,7 +793,7 @@ theorem lt_mul_of_one_le_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ · _ ≤ a * c := mul_le_mul_right' ha c @[to_additive] -theorem lt_mul_of_one_lt_of_lt [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} (ha : 1 < a) +theorem lt_mul_of_one_lt_of_lt [MulRightStrictMono α] {a b c : α} (ha : 1 < a) (hbc : b < c) : b < a * c := calc @@ -803,7 +802,7 @@ theorem lt_mul_of_one_lt_of_lt [CovariantClass α α (swap (· * ·)) (· < ·)] _ < a * c := mul_lt_mul_right' ha c @[to_additive] -theorem lt_mul_of_one_lt_of_lt' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} (ha : 1 < a) +theorem lt_mul_of_one_lt_of_lt' [MulRightMono α] {a b c : α} (ha : 1 < a) (hbc : b < c) : b < a * c := lt_mul_of_one_le_of_lt ha.le hbc @@ -812,7 +811,7 @@ theorem lt_mul_of_one_lt_of_lt' [CovariantClass α α (swap (· * ·)) (· ≤ The lemma assuming left covariance is `Left.one_le_mul`. -/ @[to_additive Right.add_nonneg "Assumes right covariance. The lemma assuming left covariance is `Left.add_nonneg`."] -theorem Right.one_le_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (ha : 1 ≤ a) +theorem Right.one_le_mul [MulRightMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : 1 ≤ a * b := le_mul_of_one_le_of_le ha hb @@ -822,7 +821,7 @@ The lemma assuming left covariance is `Left.one_lt_mul_of_lt_of_le`. -/ @[to_additive Right.add_pos_of_pos_of_nonneg "Assumes right covariance. The lemma assuming left covariance is `Left.add_pos_of_pos_of_nonneg`."] -theorem Right.one_lt_mul_of_lt_of_le [CovariantClass α α (swap (· * ·)) (· < ·)] {a b : α} +theorem Right.one_lt_mul_of_lt_of_le [MulRightStrictMono α] {a b : α} (ha : 1 < a) (hb : 1 ≤ b) : 1 < a * b := lt_mul_of_one_lt_of_le ha hb @@ -832,7 +831,7 @@ The lemma assuming left covariance is `Left.one_lt_mul_of_le_of_lt`. -/ @[to_additive Right.add_pos_of_nonneg_of_pos "Assumes right covariance. The lemma assuming left covariance is `Left.add_pos_of_nonneg_of_pos`."] -theorem Right.one_lt_mul_of_le_of_lt [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} +theorem Right.one_lt_mul_of_le_of_lt [MulRightMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 < b) : 1 < a * b := lt_mul_of_one_le_of_lt ha hb @@ -841,7 +840,7 @@ theorem Right.one_lt_mul_of_le_of_lt [CovariantClass α α (swap (· * ·)) (· The lemma assuming left covariance is `Left.one_lt_mul`. -/ @[to_additive Right.add_pos "Assumes right covariance. The lemma assuming left covariance is `Left.add_pos`."] -theorem Right.one_lt_mul [CovariantClass α α (swap (· * ·)) (· < ·)] {a b : α} (ha : 1 < a) +theorem Right.one_lt_mul [MulRightStrictMono α] {a b : α} (ha : 1 < a) (hb : 1 < b) : 1 < a * b := lt_mul_of_one_lt_of_lt ha hb @@ -850,7 +849,7 @@ theorem Right.one_lt_mul [CovariantClass α α (swap (· * ·)) (· < ·)] {a b The lemma assuming left covariance is `Left.one_lt_mul'`. -/ @[to_additive Right.add_pos' "Assumes right covariance. The lemma assuming left covariance is `Left.add_pos'`."] -theorem Right.one_lt_mul' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (ha : 1 < a) +theorem Right.one_lt_mul' [MulRightMono α] {a b : α} (ha : 1 < a) (hb : 1 < b) : 1 < a * b := lt_mul_of_one_lt_of_lt' ha hb @@ -900,49 +899,49 @@ attribute [to_additive add_pos "**Alias** of `Left.add_pos`."] one_lt_mul' attribute [to_additive add_pos' "**Alias** of `Left.add_pos'`."] one_lt_mul'' @[to_additive] -theorem lt_of_mul_lt_of_one_le_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (h : a * b < c) +theorem lt_of_mul_lt_of_one_le_left [MulLeftMono α] {a b c : α} (h : a * b < c) (hle : 1 ≤ b) : a < c := (le_mul_of_one_le_right' hle).trans_lt h @[to_additive] -theorem le_of_mul_le_of_one_le_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (h : a * b ≤ c) +theorem le_of_mul_le_of_one_le_left [MulLeftMono α] {a b c : α} (h : a * b ≤ c) (hle : 1 ≤ b) : a ≤ c := (le_mul_of_one_le_right' hle).trans h @[to_additive] -theorem lt_of_lt_mul_of_le_one_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (h : a < b * c) +theorem lt_of_lt_mul_of_le_one_left [MulLeftMono α] {a b c : α} (h : a < b * c) (hle : c ≤ 1) : a < b := h.trans_le (mul_le_of_le_one_right' hle) @[to_additive] -theorem le_of_le_mul_of_le_one_left [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (h : a ≤ b * c) +theorem le_of_le_mul_of_le_one_left [MulLeftMono α] {a b c : α} (h : a ≤ b * c) (hle : c ≤ 1) : a ≤ b := h.trans (mul_le_of_le_one_right' hle) @[to_additive] -theorem lt_of_mul_lt_of_one_le_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem lt_of_mul_lt_of_one_le_right [MulRightMono α] {a b c : α} (h : a * b < c) (hle : 1 ≤ a) : b < c := (le_mul_of_one_le_left' hle).trans_lt h @[to_additive] -theorem le_of_mul_le_of_one_le_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem le_of_mul_le_of_one_le_right [MulRightMono α] {a b c : α} (h : a * b ≤ c) (hle : 1 ≤ a) : b ≤ c := (le_mul_of_one_le_left' hle).trans h @[to_additive] -theorem lt_of_lt_mul_of_le_one_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem lt_of_lt_mul_of_le_one_right [MulRightMono α] {a b c : α} (h : a < b * c) (hle : b ≤ 1) : a < c := h.trans_le (mul_le_of_le_one_left' hle) @[to_additive] -theorem le_of_le_mul_of_le_one_right [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} +theorem le_of_le_mul_of_le_one_right [MulRightMono α] {a b c : α} (h : a ≤ b * c) (hle : b ≤ 1) : a ≤ c := h.trans (mul_le_of_le_one_left' hle) @@ -954,8 +953,8 @@ section PartialOrder variable [PartialOrder α] @[to_additive] -theorem mul_eq_one_iff_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : +theorem mul_eq_one_iff_of_one_le [MulLeftMono α] + [MulRightMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : a * b = 1 ↔ a = 1 ∧ b = 1 := Iff.intro (fun hab : a * b = 1 => @@ -971,7 +970,7 @@ theorem mul_eq_one_iff_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] section Left -variable [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} +variable [MulLeftMono α] {a b : α} @[to_additive eq_zero_of_add_nonneg_left] theorem eq_one_of_one_le_mul_left (ha : a ≤ 1) (hb : b ≤ 1) (hab : 1 ≤ a * b) : a = 1 := @@ -985,7 +984,7 @@ end Left section Right -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b : α} +variable [MulRightMono α] {a b : α} @[to_additive eq_zero_of_add_nonneg_right] theorem eq_one_of_one_le_mul_right (ha : a ≤ 1) (hb : b ≤ 1) (hab : 1 ≤ a * b) : b = 1 := @@ -1003,7 +1002,7 @@ section LinearOrder variable [LinearOrder α] -theorem exists_square_le [CovariantClass α α (· * ·) (· < ·)] (a : α) : ∃ b : α, b * b ≤ a := by +theorem exists_square_le [MulLeftStrictMono α] (a : α) : ∃ b : α, b * b ≤ a := by by_cases h : a < 1 · use a have : a * a < a * 1 := mul_lt_mul_left' h a @@ -1026,26 +1025,26 @@ section PartialOrder variable [PartialOrder α] /- This is not instance, since we want to have an instance from `LeftCancelSemigroup`s -to the appropriate `CovariantClass`. -/ +to the appropriate covariant class. -/ /-- A semigroup with a partial order and satisfying `LeftCancelSemigroup` -(i.e. `a * c < b * c → a < b`) is a `left_cancel Semigroup`. -/ +(i.e. `a * c < b * c → a < b`) is a `LeftCancelSemigroup`. -/ @[to_additive "An additive semigroup with a partial order and satisfying `AddLeftCancelSemigroup` -(i.e. `c + a < c + b → a < b`) is a `left_cancel AddSemigroup`."] -def Contravariant.toLeftCancelSemigroup [ContravariantClass α α (· * ·) (· ≤ ·)] : +(i.e. `c + a < c + b → a < b`) is a `AddLeftCancelSemigroup`."] +def Contravariant.toLeftCancelSemigroup [MulLeftReflectLE α] : LeftCancelSemigroup α := - { ‹Semigroup α› with mul_left_cancel := fun a b c => mul_left_cancel'' } + { ‹Semigroup α› with mul_left_cancel := fun _ _ _ => mul_left_cancel'' } /- This is not instance, since we want to have an instance from `RightCancelSemigroup`s -to the appropriate `CovariantClass`. -/ +to the appropriate covariant class. -/ /-- A semigroup with a partial order and satisfying `RightCancelSemigroup` -(i.e. `a * c < b * c → a < b`) is a `right_cancel Semigroup`. -/ +(i.e. `a * c < b * c → a < b`) is a `RightCancelSemigroup`. -/ @[to_additive "An additive semigroup with a partial order and satisfying `AddRightCancelSemigroup` -(`a + c < b + c → a < b`) is a `right_cancel AddSemigroup`."] -def Contravariant.toRightCancelSemigroup [ContravariantClass α α (swap (· * ·)) (· ≤ ·)] : +(`a + c < b + c → a < b`) is a `AddRightCancelSemigroup`."] +def Contravariant.toRightCancelSemigroup [MulRightReflectLE α] : RightCancelSemigroup α := - { ‹Semigroup α› with mul_right_cancel := fun a b c => mul_right_cancel'' } + { ‹Semigroup α› with mul_right_cancel := fun _ _ _ => mul_right_cancel'' } end PartialOrder @@ -1056,68 +1055,68 @@ section Mono variable [Mul α] [Preorder α] [Preorder β] {f g : β → α} {s : Set β} @[to_additive const_add] -theorem Monotone.const_mul' [CovariantClass α α (· * ·) (· ≤ ·)] (hf : Monotone f) (a : α) : +theorem Monotone.const_mul' [MulLeftMono α] (hf : Monotone f) (a : α) : Monotone fun x => a * f x := fun _ _ h => mul_le_mul_left' (hf h) a @[to_additive const_add] -theorem MonotoneOn.const_mul' [CovariantClass α α (· * ·) (· ≤ ·)] (hf : MonotoneOn f s) (a : α) : +theorem MonotoneOn.const_mul' [MulLeftMono α] (hf : MonotoneOn f s) (a : α) : MonotoneOn (fun x => a * f x) s := fun _ hx _ hy h => mul_le_mul_left' (hf hx hy h) a @[to_additive const_add] -theorem Antitone.const_mul' [CovariantClass α α (· * ·) (· ≤ ·)] (hf : Antitone f) (a : α) : +theorem Antitone.const_mul' [MulLeftMono α] (hf : Antitone f) (a : α) : Antitone fun x => a * f x := fun _ _ h => mul_le_mul_left' (hf h) a @[to_additive const_add] -theorem AntitoneOn.const_mul' [CovariantClass α α (· * ·) (· ≤ ·)] (hf : AntitoneOn f s) (a : α) : +theorem AntitoneOn.const_mul' [MulLeftMono α] (hf : AntitoneOn f s) (a : α) : AntitoneOn (fun x => a * f x) s := fun _ hx _ hy h => mul_le_mul_left' (hf hx hy h) a @[to_additive add_const] -theorem Monotone.mul_const' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : Monotone f) (a : α) : +theorem Monotone.mul_const' [MulRightMono α] (hf : Monotone f) (a : α) : Monotone fun x => f x * a := fun _ _ h => mul_le_mul_right' (hf h) a @[to_additive add_const] -theorem MonotoneOn.mul_const' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : MonotoneOn f s) +theorem MonotoneOn.mul_const' [MulRightMono α] (hf : MonotoneOn f s) (a : α) : MonotoneOn (fun x => f x * a) s := fun _ hx _ hy h => mul_le_mul_right' (hf hx hy h) a @[to_additive add_const] -theorem Antitone.mul_const' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : Antitone f) (a : α) : +theorem Antitone.mul_const' [MulRightMono α] (hf : Antitone f) (a : α) : Antitone fun x => f x * a := fun _ _ h => mul_le_mul_right' (hf h) a @[to_additive add_const] -theorem AntitoneOn.mul_const' [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : AntitoneOn f s) +theorem AntitoneOn.mul_const' [MulRightMono α] (hf : AntitoneOn f s) (a : α) : AntitoneOn (fun x => f x * a) s := fun _ hx _ hy h => mul_le_mul_right' (hf hx hy h) a /-- The product of two monotone functions is monotone. -/ @[to_additive add "The sum of two monotone functions is monotone."] -theorem Monotone.mul' [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : Monotone f) (hg : Monotone g) : +theorem Monotone.mul' [MulLeftMono α] + [MulRightMono α] (hf : Monotone f) (hg : Monotone g) : Monotone fun x => f x * g x := fun _ _ h => mul_le_mul' (hf h) (hg h) /-- The product of two monotone functions is monotone. -/ @[to_additive add "The sum of two monotone functions is monotone."] -theorem MonotoneOn.mul' [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : MonotoneOn f s) (hg : MonotoneOn g s) : +theorem MonotoneOn.mul' [MulLeftMono α] + [MulRightMono α] (hf : MonotoneOn f s) (hg : MonotoneOn g s) : MonotoneOn (fun x => f x * g x) s := fun _ hx _ hy h => mul_le_mul' (hf hx hy h) (hg hx hy h) /-- The product of two antitone functions is antitone. -/ @[to_additive add "The sum of two antitone functions is antitone."] -theorem Antitone.mul' [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : Antitone f) (hg : Antitone g) : +theorem Antitone.mul' [MulLeftMono α] + [MulRightMono α] (hf : Antitone f) (hg : Antitone g) : Antitone fun x => f x * g x := fun _ _ h => mul_le_mul' (hf h) (hg h) /-- The product of two antitone functions is antitone. -/ @[to_additive add "The sum of two antitone functions is antitone."] -theorem AntitoneOn.mul' [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (hf : AntitoneOn f s) (hg : AntitoneOn g s) : +theorem AntitoneOn.mul' [MulLeftMono α] + [MulRightMono α] (hf : AntitoneOn f s) (hg : AntitoneOn g s) : AntitoneOn (fun x => f x * g x) s := fun _ hx _ hy h => mul_le_mul' (hf hx hy h) (hg hx hy h) section Left -variable [CovariantClass α α (· * ·) (· < ·)] +variable [MulLeftStrictMono α] @[to_additive const_add] theorem StrictMono.const_mul' (hf : StrictMono f) (c : α) : StrictMono fun x => c * f x := @@ -1141,7 +1140,7 @@ end Left section Right -variable [CovariantClass α α (swap (· * ·)) (· < ·)] +variable [MulRightStrictMono α] @[to_additive add_const] theorem StrictMono.mul_const' (hf : StrictMono f) (c : α) : StrictMono fun x => f x * c := @@ -1165,37 +1164,37 @@ end Right /-- The product of two strictly monotone functions is strictly monotone. -/ @[to_additive add "The sum of two strictly monotone functions is strictly monotone."] -theorem StrictMono.mul' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] (hf : StrictMono f) (hg : StrictMono g) : +theorem StrictMono.mul' [MulLeftStrictMono α] + [MulRightStrictMono α] (hf : StrictMono f) (hg : StrictMono g) : StrictMono fun x => f x * g x := fun _ _ ab => mul_lt_mul_of_lt_of_lt (hf ab) (hg ab) /-- The product of two strictly monotone functions is strictly monotone. -/ @[to_additive add "The sum of two strictly monotone functions is strictly monotone."] -theorem StrictMonoOn.mul' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] (hf : StrictMonoOn f s) (hg : StrictMonoOn g s) : +theorem StrictMonoOn.mul' [MulLeftStrictMono α] + [MulRightStrictMono α] (hf : StrictMonoOn f s) (hg : StrictMonoOn g s) : StrictMonoOn (fun x => f x * g x) s := fun _ ha _ hb ab => mul_lt_mul_of_lt_of_lt (hf ha hb ab) (hg ha hb ab) /-- The product of two strictly antitone functions is strictly antitone. -/ @[to_additive add "The sum of two strictly antitone functions is strictly antitone."] -theorem StrictAnti.mul' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] (hf : StrictAnti f) (hg : StrictAnti g) : +theorem StrictAnti.mul' [MulLeftStrictMono α] + [MulRightStrictMono α] (hf : StrictAnti f) (hg : StrictAnti g) : StrictAnti fun x => f x * g x := fun _ _ ab => mul_lt_mul_of_lt_of_lt (hf ab) (hg ab) /-- The product of two strictly antitone functions is strictly antitone. -/ @[to_additive add "The sum of two strictly antitone functions is strictly antitone."] -theorem StrictAntiOn.mul' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· < ·)] (hf : StrictAntiOn f s) (hg : StrictAntiOn g s) : +theorem StrictAntiOn.mul' [MulLeftStrictMono α] + [MulRightStrictMono α] (hf : StrictAntiOn f s) (hg : StrictAntiOn g s) : StrictAntiOn (fun x => f x * g x) s := fun _ ha _ hb ab => mul_lt_mul_of_lt_of_lt (hf ha hb ab) (hg ha hb ab) /-- The product of a monotone function and a strictly monotone function is strictly monotone. -/ @[to_additive add_strictMono "The sum of a monotone function and a strictly monotone function is strictly monotone."] -theorem Monotone.mul_strictMono' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {f g : β → α} (hf : Monotone f) +theorem Monotone.mul_strictMono' [MulLeftStrictMono α] + [MulRightMono α] {f g : β → α} (hf : Monotone f) (hg : StrictMono g) : StrictMono fun x => f x * g x := fun _ _ h => mul_lt_mul_of_le_of_lt (hf h.le) (hg h) @@ -1203,16 +1202,16 @@ theorem Monotone.mul_strictMono' [CovariantClass α α (· * ·) (· < ·)] /-- The product of a monotone function and a strictly monotone function is strictly monotone. -/ @[to_additive add_strictMono "The sum of a monotone function and a strictly monotone function is strictly monotone."] -theorem MonotoneOn.mul_strictMono' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {f g : β → α} (hf : MonotoneOn f s) +theorem MonotoneOn.mul_strictMono' [MulLeftStrictMono α] + [MulRightMono α] {f g : β → α} (hf : MonotoneOn f s) (hg : StrictMonoOn g s) : StrictMonoOn (fun x => f x * g x) s := fun _ hx _ hy h => mul_lt_mul_of_le_of_lt (hf hx hy h.le) (hg hx hy h) /-- The product of an antitone function and a strictly antitone function is strictly antitone. -/ @[to_additive add_strictAnti "The sum of an antitone function and a strictly antitone function is strictly antitone."] -theorem Antitone.mul_strictAnti' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {f g : β → α} (hf : Antitone f) +theorem Antitone.mul_strictAnti' [MulLeftStrictMono α] + [MulRightMono α] {f g : β → α} (hf : Antitone f) (hg : StrictAnti g) : StrictAnti fun x => f x * g x := fun _ _ h => mul_lt_mul_of_le_of_lt (hf h.le) (hg h) @@ -1220,13 +1219,13 @@ theorem Antitone.mul_strictAnti' [CovariantClass α α (· * ·) (· < ·)] /-- The product of an antitone function and a strictly antitone function is strictly antitone. -/ @[to_additive add_strictAnti "The sum of an antitone function and a strictly antitone function is strictly antitone."] -theorem AntitoneOn.mul_strictAnti' [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {f g : β → α} (hf : AntitoneOn f s) +theorem AntitoneOn.mul_strictAnti' [MulLeftStrictMono α] + [MulRightMono α] {f g : β → α} (hf : AntitoneOn f s) (hg : StrictAntiOn g s) : StrictAntiOn (fun x => f x * g x) s := fun _ hx _ hy h => mul_lt_mul_of_le_of_lt (hf hx hy h.le) (hg hx hy h) -variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· < ·)] +variable [MulLeftMono α] [MulRightStrictMono α] /-- The product of a strictly monotone function and a monotone function is strictly monotone. -/ @[to_additive add_monotone "The sum of a strictly monotone function and a monotone function is @@ -1257,34 +1256,34 @@ theorem StrictAntiOn.mul_antitone' (hf : StrictAntiOn f s) (hg : AntitoneOn g s) fun _ hx _ hy h => mul_lt_mul_of_lt_of_le (hf hx hy h) (hg hx hy h.le) @[to_additive (attr := simp) cmp_add_left] -theorem cmp_mul_left' {α : Type*} [Mul α] [LinearOrder α] [CovariantClass α α (· * ·) (· < ·)] +theorem cmp_mul_left' {α : Type*} [Mul α] [LinearOrder α] [MulLeftStrictMono α] (a b c : α) : cmp (a * b) (a * c) = cmp b c := (strictMono_id.const_mul' a).cmp_map_eq b c @[to_additive (attr := simp) cmp_add_right] theorem cmp_mul_right' {α : Type*} [Mul α] [LinearOrder α] - [CovariantClass α α (swap (· * ·)) (· < ·)] (a b c : α) : + [MulRightStrictMono α] (a b c : α) : cmp (a * c) (b * c) = cmp a b := (strictMono_id.mul_const' c).cmp_map_eq a b end Mono /-- An element `a : α` is `MulLECancellable` if `x ↦ a * x` is order-reflecting. -We will make a separate version of many lemmas that require `[ContravariantClass α α (*) (≤)]` with +We will make a separate version of many lemmas that require `[MulLeftReflectLE α]` with `MulLECancellable` assumptions instead. These lemmas can then be instantiated to specific types, like `ENNReal`, where we can replace the assumption `AddLECancellable x` by `x ≠ ∞`. -/ @[to_additive "An element `a : α` is `AddLECancellable` if `x ↦ a + x` is order-reflecting. -We will make a separate version of many lemmas that require `[ContravariantClass α α (+) (≤)]` with +We will make a separate version of many lemmas that require `[MulLeftReflectLE α]` with `AddLECancellable` assumptions instead. These lemmas can then be instantiated to specific types, like `ENNReal`, where we can replace the assumption `AddLECancellable x` by `x ≠ ∞`. "] def MulLECancellable [Mul α] [LE α] (a : α) : Prop := ∀ ⦃b c⦄, a * b ≤ a * c → b ≤ c @[to_additive] -theorem Contravariant.MulLECancellable [Mul α] [LE α] [ContravariantClass α α (· * ·) (· ≤ ·)] +theorem Contravariant.MulLECancellable [Mul α] [LE α] [MulLeftReflectLE α] {a : α} : MulLECancellable a := fun _ _ => le_of_mul_le_mul_left' @@ -1319,51 +1318,51 @@ protected theorem inj_left [Mul α] [@Std.Commutative α (· * ·)] [PartialOrde variable [LE α] @[to_additive] -protected theorem mul_le_mul_iff_left [Mul α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} +protected theorem mul_le_mul_iff_left [Mul α] [MulLeftMono α] {a b c : α} (ha : MulLECancellable a) : a * b ≤ a * c ↔ b ≤ c := ⟨fun h => ha h, fun h => mul_le_mul_left' h a⟩ @[to_additive] protected theorem mul_le_mul_iff_right [Mul α] [i : @Std.Commutative α (· * ·)] - [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} (ha : MulLECancellable a) : + [MulLeftMono α] {a b c : α} (ha : MulLECancellable a) : b * a ≤ c * a ↔ b ≤ c := by rw [i.comm b, i.comm c, ha.mul_le_mul_iff_left] @[to_additive] -protected theorem le_mul_iff_one_le_right [MulOneClass α] [CovariantClass α α (· * ·) (· ≤ ·)] +protected theorem le_mul_iff_one_le_right [MulOneClass α] [MulLeftMono α] {a b : α} (ha : MulLECancellable a) : a ≤ a * b ↔ 1 ≤ b := Iff.trans (by rw [mul_one]) ha.mul_le_mul_iff_left @[to_additive] -protected theorem mul_le_iff_le_one_right [MulOneClass α] [CovariantClass α α (· * ·) (· ≤ ·)] +protected theorem mul_le_iff_le_one_right [MulOneClass α] [MulLeftMono α] {a b : α} (ha : MulLECancellable a) : a * b ≤ a ↔ b ≤ 1 := Iff.trans (by rw [mul_one]) ha.mul_le_mul_iff_left @[to_additive] protected theorem le_mul_iff_one_le_left [MulOneClass α] [i : @Std.Commutative α (· * ·)] - [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) : + [MulLeftMono α] {a b : α} (ha : MulLECancellable a) : a ≤ b * a ↔ 1 ≤ b := by rw [i.comm, ha.le_mul_iff_one_le_right] @[to_additive] protected theorem mul_le_iff_le_one_left [MulOneClass α] [i : @Std.Commutative α (· * ·)] - [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) : + [MulLeftMono α] {a b : α} (ha : MulLECancellable a) : b * a ≤ a ↔ b ≤ 1 := by rw [i.comm, ha.mul_le_iff_le_one_right] @[to_additive] lemma mul [Semigroup α] {a b : α} (ha : MulLECancellable a) (hb : MulLECancellable b) : MulLECancellable (a * b) := fun c d hcd ↦ hb <| ha <| by rwa [← mul_assoc, ← mul_assoc] -@[to_additive] lemma of_mul_right [Semigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} +@[to_additive] lemma of_mul_right [Semigroup α] [MulLeftMono α] {a b : α} (h : MulLECancellable (a * b)) : MulLECancellable b := fun c d hcd ↦ h <| by rw [mul_assoc, mul_assoc]; exact mul_le_mul_left' hcd _ -@[to_additive] lemma of_mul_left [CommSemigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} +@[to_additive] lemma of_mul_left [CommSemigroup α] [MulLeftMono α] {a b : α} (h : MulLECancellable (a * b)) : MulLECancellable a := (mul_comm a b ▸ h).of_mul_right end MulLECancellable @[to_additive (attr := simp)] -lemma mulLECancellable_mul [LE α] [CommSemigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} : +lemma mulLECancellable_mul [LE α] [CommSemigroup α] [MulLeftMono α] {a b : α} : MulLECancellable (a * b) ↔ MulLECancellable a ∧ MulLECancellable b := ⟨fun h ↦ ⟨h.of_mul_left, h.of_mul_right⟩, fun h ↦ h.1.mul h.2⟩ diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean index c6b6740ff867f..8c000a8d6ddd3 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean @@ -328,7 +328,7 @@ theorem Group.mulRightReflectLT_of_mulRightStrictMono [Group N] [LT N] section Trans -variable [IsTrans N r] (m n : M) {a b c d : N} +variable [IsTrans N r] (m : M) {a b c : N} -- Lemmas with 3 elements. theorem act_rel_of_rel_of_act_rel (ab : r a b) (rl : r (μ m b) c) : r (μ m a) c := @@ -361,7 +361,7 @@ theorem rel_of_act_rel_act (m : M) {a b : N} (ab : r (μ m a) (μ m b)) : r a b section Trans -variable [IsTrans N r] (m n : M) {a b c d : N} +variable [IsTrans N r] (m : M) {a b c : N} -- Lemmas with 3 elements. theorem act_rel_of_act_rel_of_rel_act_rel (ab : r (μ m a) b) (rl : r (μ m b) (μ m c)) : @@ -531,28 +531,28 @@ theorem contravariant_le_of_contravariant_eq_and_lt [PartialOrder N] then the following four instances (actually eight) can be removed in favor of the above two. -/ @[to_additive] -instance IsLeftCancelMul.covariant_mul_lt_of_covariant_mul_le [Mul N] [IsLeftCancelMul N] - [PartialOrder N] [CovariantClass N N (· * ·) (· ≤ ·)] : - CovariantClass N N (· * ·) (· < ·) where +instance IsLeftCancelMul.mulLeftStrictMono_of_mulLeftMono [Mul N] [IsLeftCancelMul N] + [PartialOrder N] [MulLeftMono N] : + MulLeftStrictMono N where elim a _ _ bc := (CovariantClass.elim a bc.le).lt_of_ne ((mul_ne_mul_right a).mpr bc.ne) @[to_additive] -instance IsRightCancelMul.covariant_swap_mul_lt_of_covariant_swap_mul_le - [Mul N] [IsRightCancelMul N] [PartialOrder N] [CovariantClass N N (swap (· * ·)) (· ≤ ·)] : - CovariantClass N N (swap (· * ·)) (· < ·) where +instance IsRightCancelMul.mulRightStrictMono_of_mulRightMono + [Mul N] [IsRightCancelMul N] [PartialOrder N] [MulRightMono N] : + MulRightStrictMono N where elim a _ _ bc := (CovariantClass.elim a bc.le).lt_of_ne ((mul_ne_mul_left a).mpr bc.ne) @[to_additive] -instance IsLeftCancelMul.contravariant_mul_le_of_contravariant_mul_lt [Mul N] [IsLeftCancelMul N] - [PartialOrder N] [ContravariantClass N N (· * ·) (· < ·)] : - ContravariantClass N N (· * ·) (· ≤ ·) where +instance IsLeftCancelMul.mulLeftReflectLE_of_mulLeftReflectLT [Mul N] [IsLeftCancelMul N] + [PartialOrder N] [MulLeftReflectLT N] : + MulLeftReflectLE N where elim := (contravariant_le_iff_contravariant_lt_and_eq N N _).mpr ⟨ContravariantClass.elim, fun _ ↦ mul_left_cancel⟩ @[to_additive] -instance IsRightCancelMul.contravariant_swap_mul_le_of_contravariant_swap_mul_lt - [Mul N] [IsRightCancelMul N] [PartialOrder N] [ContravariantClass N N (swap (· * ·)) (· < ·)] : - ContravariantClass N N (swap (· * ·)) (· ≤ ·) where +instance IsRightCancelMul.mulRightReflectLE_of_mulRightReflectLT + [Mul N] [IsRightCancelMul N] [PartialOrder N] [MulRightReflectLT N] : + MulRightReflectLE N where elim := (contravariant_le_iff_contravariant_lt_and_eq N N _).mpr ⟨ContravariantClass.elim, fun _ ↦ mul_right_cancel⟩ diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean index da6e069dc2d22..4868b5b043691 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean @@ -44,20 +44,20 @@ instance (priority := 100) Group.existsMulOfLE (α : Type u) [Group α] [LE α] section MulOneClass variable [MulOneClass α] [Preorder α] [ExistsMulOfLE α] {a b : α} -@[to_additive] lemma exists_one_le_mul_of_le [ContravariantClass α α (· * ·) (· ≤ ·)] (h : a ≤ b) : +@[to_additive] lemma exists_one_le_mul_of_le [MulLeftReflectLE α] (h : a ≤ b) : ∃ c, 1 ≤ c ∧ a * c = b := by obtain ⟨c, rfl⟩ := exists_mul_of_le h; exact ⟨c, one_le_of_le_mul_right h, rfl⟩ -@[to_additive] lemma exists_one_lt_mul_of_lt' [ContravariantClass α α (· * ·) (· < ·)] (h : a < b) : +@[to_additive] lemma exists_one_lt_mul_of_lt' [MulLeftReflectLT α] (h : a < b) : ∃ c, 1 < c ∧ a * c = b := by obtain ⟨c, rfl⟩ := exists_mul_of_le h.le; exact ⟨c, one_lt_of_lt_mul_right h, rfl⟩ -@[to_additive] lemma le_iff_exists_one_le_mul [CovariantClass α α (· * ·) (· ≤ ·)] - [ContravariantClass α α (· * ·) (· ≤ ·)] : a ≤ b ↔ ∃ c, 1 ≤ c ∧ a * c = b := +@[to_additive] lemma le_iff_exists_one_le_mul [MulLeftMono α] + [MulLeftReflectLE α] : a ≤ b ↔ ∃ c, 1 ≤ c ∧ a * c = b := ⟨exists_one_le_mul_of_le, by rintro ⟨c, hc, rfl⟩; exact le_mul_of_one_le_right' hc⟩ -@[to_additive] lemma lt_iff_exists_one_lt_mul [CovariantClass α α (· * ·) (· < ·)] - [ContravariantClass α α (· * ·) (· < ·)] : a < b ↔ ∃ c, 1 < c ∧ a * c = b := +@[to_additive] lemma lt_iff_exists_one_lt_mul [MulLeftStrictMono α] + [MulLeftReflectLT α] : a < b ↔ ∃ c, 1 < c ∧ a * c = b := ⟨exists_one_lt_mul_of_lt', by rintro ⟨c, hc, rfl⟩; exact lt_mul_of_one_lt_right' _ hc⟩ end MulOneClass @@ -65,20 +65,21 @@ end MulOneClass section ExistsMulOfLE variable [LinearOrder α] [DenselyOrdered α] [Monoid α] [ExistsMulOfLE α] - [CovariantClass α α (· * ·) (· < ·)] [ContravariantClass α α (· * ·) (· < ·)] {a b : α} + [MulLeftReflectLT α] {a b : α} @[to_additive] theorem le_of_forall_one_lt_le_mul (h : ∀ ε : α, 1 < ε → a ≤ b * ε) : a ≤ b := le_of_forall_le_of_dense fun x hxb => by obtain ⟨ε, rfl⟩ := exists_mul_of_le hxb.le - exact h _ ((lt_mul_iff_one_lt_right' b).1 hxb) + exact h _ (one_lt_of_lt_mul_right hxb) @[to_additive] theorem le_of_forall_one_lt_lt_mul' (h : ∀ ε : α, 1 < ε → a < b * ε) : a ≤ b := le_of_forall_one_lt_le_mul fun ε hε => (h ε hε).le @[to_additive] -theorem le_iff_forall_one_lt_lt_mul' : a ≤ b ↔ ∀ ε, 1 < ε → a < b * ε := +theorem le_iff_forall_one_lt_lt_mul' [MulLeftStrictMono α] : + a ≤ b ↔ ∀ ε, 1 < ε → a < b * ε := ⟨fun h _ => lt_mul_of_le_of_one_lt h, le_of_forall_one_lt_lt_mul'⟩ end ExistsMulOfLE diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean index b509125489cc7..f8cdd57c1e851 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean @@ -48,7 +48,7 @@ variable [Mul α] section Left -variable [CovariantClass α α (· * ·) (· ≤ ·)] +variable [MulLeftMono α] @[to_additive] theorem min_mul_mul_left (a b c : α) : min (a * b) (a * c) = a * min b c := @@ -62,7 +62,7 @@ end Left section Right -variable [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] +variable [MulRightMono α] @[to_additive] theorem min_mul_mul_right (a b c : α) : min (a * c) (b * c) = min a b * c := @@ -75,37 +75,33 @@ theorem max_mul_mul_right (a b c : α) : max (a * c) (b * c) = max a b * c := end Right @[to_additive] -theorem lt_or_lt_of_mul_lt_mul [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a₁ a₂ b₁ b₂ : α} : +theorem lt_or_lt_of_mul_lt_mul [MulLeftMono α] [MulRightMono α] {a₁ a₂ b₁ b₂ : α} : a₁ * b₁ < a₂ * b₂ → a₁ < a₂ ∨ b₁ < b₂ := by contrapose! exact fun h => mul_le_mul' h.1 h.2 @[to_additive] -theorem le_or_lt_of_mul_le_mul [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· < ·)] {a₁ a₂ b₁ b₂ : α} : +theorem le_or_lt_of_mul_le_mul [MulLeftMono α] [MulRightStrictMono α] {a₁ a₂ b₁ b₂ : α} : a₁ * b₁ ≤ a₂ * b₂ → a₁ ≤ a₂ ∨ b₁ < b₂ := by contrapose! exact fun h => mul_lt_mul_of_lt_of_le h.1 h.2 @[to_additive] -theorem lt_or_le_of_mul_le_mul [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a₁ a₂ b₁ b₂ : α} : +theorem lt_or_le_of_mul_le_mul [MulLeftStrictMono α] [MulRightMono α] {a₁ a₂ b₁ b₂ : α} : a₁ * b₁ ≤ a₂ * b₂ → a₁ < a₂ ∨ b₁ ≤ b₂ := by contrapose! exact fun h => mul_lt_mul_of_le_of_lt h.1 h.2 @[to_additive] -theorem le_or_le_of_mul_le_mul [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (Function.swap (· * ·)) (· < ·)] {a₁ a₂ b₁ b₂ : α} : +theorem le_or_le_of_mul_le_mul [MulLeftStrictMono α] [MulRightStrictMono α] {a₁ a₂ b₁ b₂ : α} : a₁ * b₁ ≤ a₂ * b₂ → a₁ ≤ a₂ ∨ b₁ ≤ b₂ := by contrapose! exact fun h => mul_lt_mul_of_lt_of_lt h.1 h.2 @[to_additive] -theorem mul_lt_mul_iff_of_le_of_le [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] [CovariantClass α α (· * ·) (· < ·)] - [CovariantClass α α (Function.swap (· * ·)) (· < ·)] {a₁ a₂ b₁ b₂ : α} (ha : a₁ ≤ a₂) +theorem mul_lt_mul_iff_of_le_of_le [MulLeftMono α] + [MulRightMono α] [MulLeftStrictMono α] + [MulRightStrictMono α] {a₁ a₂ b₁ b₂ : α} (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) : a₁ * b₁ < a₂ * b₂ ↔ a₁ < a₂ ∨ b₁ < b₂ := by refine ⟨lt_or_lt_of_mul_lt_mul, fun h => ?_⟩ rcases h with ha' | hb' @@ -117,18 +113,17 @@ end Mul variable [MulOneClass α] @[to_additive] -theorem min_le_mul_of_one_le_right [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (hb : 1 ≤ b) : +theorem min_le_mul_of_one_le_right [MulLeftMono α] {a b : α} (hb : 1 ≤ b) : min a b ≤ a * b := min_le_iff.2 <| Or.inl <| le_mul_of_one_le_right' hb @[to_additive] -theorem min_le_mul_of_one_le_left [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a b : α} - (ha : 1 ≤ a) : min a b ≤ a * b := +theorem min_le_mul_of_one_le_left [MulRightMono α] {a b : α} (ha : 1 ≤ a) : + min a b ≤ a * b := min_le_iff.2 <| Or.inr <| le_mul_of_one_le_left' ha @[to_additive] -theorem max_le_mul_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : +theorem max_le_mul_of_one_le [MulLeftMono α] [MulRightMono α] {a b : α} (ha : 1 ≤ a) (hb : 1 ≤ b) : max a b ≤ a * b := max_le_iff.2 ⟨le_mul_of_one_le_right' hb, le_mul_of_one_le_left' ha⟩ diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean index 7a9819c7230f1..c93cbe11c4902 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean @@ -17,47 +17,35 @@ open Function namespace OrderDual @[to_additive] -instance contravariantClass_mul_le [LE α] [Mul α] [c : ContravariantClass α α (· * ·) (· ≤ ·)] : - ContravariantClass αᵒᵈ αᵒᵈ (· * ·) (· ≤ ·) := +instance mulLeftReflectLE [LE α] [Mul α] [c : MulLeftReflectLE α] : MulLeftReflectLE αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance covariantClass_mul_le [LE α] [Mul α] [c : CovariantClass α α (· * ·) (· ≤ ·)] : - CovariantClass αᵒᵈ αᵒᵈ (· * ·) (· ≤ ·) := +instance mulLeftMono [LE α] [Mul α] [c : MulLeftMono α] : MulLeftMono αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance contravariantClass_swap_mul_le [LE α] [Mul α] - [c : ContravariantClass α α (swap (· * ·)) (· ≤ ·)] : - ContravariantClass αᵒᵈ αᵒᵈ (swap (· * ·)) (· ≤ ·) := +instance mulRightReflectLE [LE α] [Mul α] [c : MulRightReflectLE α] : MulRightReflectLE αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance covariantClass_swap_mul_le [LE α] [Mul α] - [c : CovariantClass α α (swap (· * ·)) (· ≤ ·)] : - CovariantClass αᵒᵈ αᵒᵈ (swap (· * ·)) (· ≤ ·) := +instance mulRightMono [LE α] [Mul α] [c : MulRightMono α] : MulRightMono αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance contravariantClass_mul_lt [LT α] [Mul α] [c : ContravariantClass α α (· * ·) (· < ·)] : - ContravariantClass αᵒᵈ αᵒᵈ (· * ·) (· < ·) := +instance mulLeftReflectLT [LT α] [Mul α] [c : MulLeftReflectLT α] : MulLeftReflectLT αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance covariantClass_mul_lt [LT α] [Mul α] [c : CovariantClass α α (· * ·) (· < ·)] : - CovariantClass αᵒᵈ αᵒᵈ (· * ·) (· < ·) := +instance mulLeftStrictMono [LT α] [Mul α] [c : MulLeftStrictMono α] : MulLeftStrictMono αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance contravariantClass_swap_mul_lt [LT α] [Mul α] - [c : ContravariantClass α α (swap (· * ·)) (· < ·)] : - ContravariantClass αᵒᵈ αᵒᵈ (swap (· * ·)) (· < ·) := +instance mulRightReflectLT [LT α] [Mul α] [c : MulRightReflectLT α] : MulRightReflectLT αᵒᵈ := ⟨c.1.flip⟩ @[to_additive] -instance covariantClass_swap_mul_lt [LT α] [Mul α] - [c : CovariantClass α α (swap (· * ·)) (· < ·)] : - CovariantClass αᵒᵈ αᵒᵈ (swap (· * ·)) (· < ·) := +instance mulRightStrictMono [LT α] [Mul α] [c : MulRightStrictMono α] : MulRightStrictMono αᵒᵈ := ⟨c.1.flip⟩ end OrderDual diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean index 533bff0ac5793..348b449849781 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean @@ -26,7 +26,7 @@ variable [Preorder M] namespace Left -variable [CovariantClass M M (· * ·) (· ≤ ·)] {a b : M} +variable [MulLeftMono M] {a : M} @[to_additive Left.nsmul_nonneg] theorem one_le_pow_of_le (ha : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n @@ -58,7 +58,7 @@ end Left section Left -variable [CovariantClass M M (· * ·) (· ≤ ·)] {x : M} +variable [MulLeftMono M] @[to_additive nsmul_left_monotone] theorem pow_right_monotone {a : M} (ha : 1 ≤ a) : Monotone fun n : ℕ ↦ a ^ n := @@ -80,7 +80,7 @@ end Left section LeftLt -variable [CovariantClass M M (· * ·) (· < ·)] {a : M} {n m : ℕ} +variable [MulLeftStrictMono M] {a : M} {n m : ℕ} @[to_additive nsmul_left_strictMono] theorem pow_right_strictMono' (ha : 1 < a) : StrictMono ((a ^ ·) : ℕ → M) := @@ -94,7 +94,7 @@ end LeftLt section Right -variable [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {x : M} +variable [MulRightMono M] {x : M} @[to_additive Right.nsmul_nonneg] theorem Right.one_le_pow_of_le (hx : 1 ≤ x) : ∀ {n : ℕ}, 1 ≤ x ^ n @@ -123,8 +123,7 @@ end Right section CovariantLTSwap -variable [Preorder β] [CovariantClass M M (· * ·) (· < ·)] - [CovariantClass M M (swap (· * ·)) (· < ·)] {f : β → M} {n : ℕ} +variable [Preorder β] [MulLeftStrictMono M] [MulRightStrictMono M] {f : β → M} {n : ℕ} @[to_additive StrictMono.const_nsmul] theorem StrictMono.pow_const (hf : StrictMono f) : ∀ {n : ℕ}, n ≠ 0 → StrictMono (f · ^ n) @@ -145,8 +144,7 @@ end CovariantLTSwap section CovariantLESwap -variable [Preorder β] [CovariantClass M M (· * ·) (· ≤ ·)] - [CovariantClass M M (swap (· * ·)) (· ≤ ·)] +variable [Preorder β] [MulLeftMono M] [MulRightMono M] @[to_additive (attr := mono, gcongr) nsmul_le_nsmul_right] theorem pow_le_pow_left' {a b : M} (hab : a ≤ b) : ∀ i : ℕ, a ^ i ≤ b ^ i @@ -175,7 +173,7 @@ variable [LinearOrder M] section CovariantLE -variable [CovariantClass M M (· * ·) (· ≤ ·)] +variable [MulLeftMono M] -- This generalises to lattices. See `pow_two_semiclosed` @[to_additive nsmul_nonneg_iff] @@ -203,7 +201,7 @@ end CovariantLE section CovariantLT -variable [CovariantClass M M (· * ·) (· < ·)] {a : M} {m n : ℕ} +variable [MulLeftStrictMono M] {a : M} {m n : ℕ} @[to_additive nsmul_le_nsmul_iff_left] theorem pow_le_pow_iff_right' (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := @@ -217,7 +215,7 @@ end CovariantLT section CovariantLESwap -variable [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] +variable [MulLeftMono M] [MulRightMono M] @[to_additive lt_of_nsmul_lt_nsmul_right] theorem lt_of_pow_lt_pow_left' {a b : M} (n : ℕ) : a ^ n < b ^ n → a < b := @@ -235,7 +233,7 @@ end CovariantLESwap section CovariantLTSwap -variable [CovariantClass M M (· * ·) (· < ·)] [CovariantClass M M (swap (· * ·)) (· < ·)] +variable [MulLeftStrictMono M] [MulRightStrictMono M] @[to_additive le_of_nsmul_le_nsmul_right] theorem le_of_pow_le_pow_left' {a b : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ b ^ n → a ≤ b := @@ -252,18 +250,18 @@ theorem le_max_of_sq_le_mul {a b c : M} (h : a ^ 2 ≤ b * c) : a ≤ max b c := end CovariantLTSwap @[to_additive Left.nsmul_neg_iff] -theorem Left.pow_lt_one_iff' [CovariantClass M M (· * ·) (· < ·)] {n : ℕ} {x : M} (hn : 0 < n) : +theorem Left.pow_lt_one_iff' [MulLeftStrictMono M] {n : ℕ} {x : M} (hn : 0 < n) : x ^ n < 1 ↔ x < 1 := - haveI := covariantClass_le_of_lt M M (· * ·) + haveI := mulLeftMono_of_mulLeftStrictMono M pow_lt_one_iff hn.ne' -theorem Left.pow_lt_one_iff [CovariantClass M M (· * ·) (· < ·)] {n : ℕ} {x : M} (hn : 0 < n) : +theorem Left.pow_lt_one_iff [MulLeftStrictMono M] {n : ℕ} {x : M} (hn : 0 < n) : x ^ n < 1 ↔ x < 1 := Left.pow_lt_one_iff' hn @[to_additive] -theorem Right.pow_lt_one_iff [CovariantClass M M (swap (· * ·)) (· < ·)] {n : ℕ} {x : M} +theorem Right.pow_lt_one_iff [MulRightStrictMono M] {n : ℕ} {x : M} (hn : 0 < n) : x ^ n < 1 ↔ x < 1 := - haveI := covariantClass_le_of_lt M M (swap (· * ·)) + haveI := mulRightMono_of_mulRightStrictMono M ⟨fun H => not_le.mp fun k => H.not_le <| Right.one_le_pow_of_le k, Right.pow_lt_one_of_lt hn⟩ end LinearOrder @@ -272,7 +270,7 @@ end Monoid section DivInvMonoid -variable [DivInvMonoid G] [Preorder G] [CovariantClass G G (· * ·) (· ≤ ·)] +variable [DivInvMonoid G] [Preorder G] [MulLeftMono G] @[to_additive zsmul_nonneg] theorem one_le_zpow {x : G} (H : 1 ≤ x) {n : ℤ} (hn : 0 ≤ n) : 1 ≤ x ^ n := by diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean new file mode 100644 index 0000000000000..1647d43c6a434 --- /dev/null +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean @@ -0,0 +1,111 @@ +/- +Copyright (c) 2016 Jeremy Avigad. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl +-/ +import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE +import Mathlib.Order.BoundedOrder + +/-! # Ordered monoid structures on `Multiplicative α` and `Additive α`. -/ + +variable {α : Type*} + +instance : ∀ [LE α], LE (Multiplicative α) := + fun {inst} => inst + +instance : ∀ [LE α], LE (Additive α) := + fun {inst} => inst + +instance : ∀ [LT α], LT (Multiplicative α) := + fun {inst} => inst + +instance : ∀ [LT α], LT (Additive α) := + fun {inst} => inst + +instance Multiplicative.preorder : ∀ [Preorder α], Preorder (Multiplicative α) := + fun {inst} => inst + +instance Additive.preorder : ∀ [Preorder α], Preorder (Additive α) := + fun {inst} => inst + +instance Multiplicative.partialOrder : ∀ [PartialOrder α], PartialOrder (Multiplicative α) := + fun {inst} => inst + +instance Additive.partialOrder : ∀ [PartialOrder α], PartialOrder (Additive α) := + fun {inst} => inst + +instance Multiplicative.linearOrder : ∀ [LinearOrder α], LinearOrder (Multiplicative α) := + fun {inst} => inst + +instance Additive.linearOrder : ∀ [LinearOrder α], LinearOrder (Additive α) := + fun {inst} => inst + +instance Multiplicative.orderBot [LE α] : ∀ [OrderBot α], OrderBot (Multiplicative α) := + fun {inst} => inst + +instance Additive.orderBot [LE α] : ∀ [OrderBot α], OrderBot (Additive α) := + fun {inst} => inst + +instance Multiplicative.orderTop [LE α] : ∀ [OrderTop α], OrderTop (Multiplicative α) := + fun {inst} => inst + +instance Additive.orderTop [LE α] : ∀ [OrderTop α], OrderTop (Additive α) := + fun {inst} => inst + +instance Multiplicative.boundedOrder [LE α] : ∀ [BoundedOrder α], BoundedOrder (Multiplicative α) := + fun {inst} => inst + +instance Additive.boundedOrder [LE α] : ∀ [BoundedOrder α], BoundedOrder (Additive α) := + fun {inst} => inst + +instance Multiplicative.existsMulOfLe [Add α] [LE α] [ExistsAddOfLE α] : + ExistsMulOfLE (Multiplicative α) := + ⟨@exists_add_of_le α _ _ _⟩ + +instance Additive.existsAddOfLe [Mul α] [LE α] [ExistsMulOfLE α] : ExistsAddOfLE (Additive α) := + ⟨@exists_mul_of_le α _ _ _⟩ + +namespace Additive + +variable [Preorder α] + +@[simp] +theorem ofMul_le {a b : α} : ofMul a ≤ ofMul b ↔ a ≤ b := + Iff.rfl + +@[simp] +theorem ofMul_lt {a b : α} : ofMul a < ofMul b ↔ a < b := + Iff.rfl + +@[simp] +theorem toMul_le {a b : Additive α} : toMul a ≤ toMul b ↔ a ≤ b := + Iff.rfl + +@[simp] +theorem toMul_lt {a b : Additive α} : toMul a < toMul b ↔ a < b := + Iff.rfl + +end Additive + +namespace Multiplicative + +variable [Preorder α] + +@[simp] +theorem ofAdd_le {a b : α} : ofAdd a ≤ ofAdd b ↔ a ≤ b := + Iff.rfl + +@[simp] +theorem ofAdd_lt {a b : α} : ofAdd a < ofAdd b ↔ a < b := + Iff.rfl + +@[simp] +theorem toAdd_le {a b : Multiplicative α} : toAdd a ≤ toAdd b ↔ a ≤ b := + Iff.rfl + +@[simp] +theorem toAdd_lt {a b : Multiplicative α} : toAdd a < toAdd b ↔ a < b := + Iff.rfl + +end Multiplicative diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean index 7d7bdb4f2ff25..cd7326219233b 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean @@ -80,7 +80,7 @@ end One section Add -variable [Add α] {a b c d : WithTop α} {x y : α} +variable [Add α] {a b c d : WithTop α} {x : α} instance add : Add (WithTop α) := ⟨Option.map₂ (· + ·)⟩ @@ -113,12 +113,8 @@ theorem add_eq_coe : | some a, ⊤, c => by simp | some a, some b, c => by norm_cast; simp --- Porting note (#10618): simp can already prove this. --- @[simp] theorem add_coe_eq_top_iff {x : WithTop α} {y : α} : x + y = ⊤ ↔ x = ⊤ := by simp --- Porting note (#10618): simp can already prove this. --- @[simp] theorem coe_add_eq_top_iff {y : WithTop α} : ↑x + y = ⊤ ↔ y = ⊤ := by simp theorem add_right_cancel_iff [IsRightCancelAdd α] (ha : a ≠ ⊤) : b + a = c + a ↔ b = c := by @@ -143,22 +139,19 @@ theorem add_left_cancel_iff [IsLeftCancelAdd α] (ha : a ≠ ⊤) : a + b = a + theorem add_left_cancel [IsLeftCancelAdd α] (ha : a ≠ ⊤) (h : a + b = a + c) : b = c := (WithTop.add_left_cancel_iff ha).1 h -instance covariantClass_add_le [LE α] [CovariantClass α α (· + ·) (· ≤ ·)] : - CovariantClass (WithTop α) (WithTop α) (· + ·) (· ≤ ·) := +instance addLeftMono [LE α] [AddLeftMono α] : AddLeftMono (WithTop α) := ⟨fun a b c h => by cases a <;> cases c <;> try exact le_top rcases le_coe_iff.1 h with ⟨b, rfl, _⟩ exact coe_le_coe.2 (add_le_add_left (coe_le_coe.1 h) _)⟩ -instance covariantClass_swap_add_le [LE α] [CovariantClass α α (swap (· + ·)) (· ≤ ·)] : - CovariantClass (WithTop α) (WithTop α) (swap (· + ·)) (· ≤ ·) := +instance addRightMono [LE α] [AddRightMono α] : AddRightMono (WithTop α) := ⟨fun a b c h => by cases a <;> cases c <;> try exact le_top rcases le_coe_iff.1 h with ⟨b, rfl, _⟩ exact coe_le_coe.2 (add_le_add_right (coe_le_coe.1 h) _)⟩ -instance contravariantClass_add_lt [LT α] [ContravariantClass α α (· + ·) (· < ·)] : - ContravariantClass (WithTop α) (WithTop α) (· + ·) (· < ·) := +instance addLeftReflectLT [LT α] [AddLeftReflectLT α] : AddLeftReflectLT (WithTop α) := ⟨fun a b c h => by induction a; · exact (WithTop.not_top_lt _ h).elim induction b; · exact (WithTop.not_top_lt _ h).elim @@ -166,15 +159,14 @@ instance contravariantClass_add_lt [LT α] [ContravariantClass α α (· + ·) ( · exact coe_lt_top _ · exact coe_lt_coe.2 (lt_of_add_lt_add_left <| coe_lt_coe.1 h)⟩ -instance contravariantClass_swap_add_lt [LT α] [ContravariantClass α α (swap (· + ·)) (· < ·)] : - ContravariantClass (WithTop α) (WithTop α) (swap (· + ·)) (· < ·) := +instance addRightReflectLT [LT α] [AddRightReflectLT α] : AddRightReflectLT (WithTop α) := ⟨fun a b c h => by cases a <;> cases b <;> try exact (WithTop.not_top_lt _ h).elim cases c · exact coe_lt_top _ · exact coe_lt_coe.2 (lt_of_add_lt_add_right <| coe_lt_coe.1 h)⟩ -protected theorem le_of_add_le_add_left [LE α] [ContravariantClass α α (· + ·) (· ≤ ·)] (ha : a ≠ ⊤) +protected theorem le_of_add_le_add_left [LE α] [AddLeftReflectLE α] (ha : a ≠ ⊤) (h : a + b ≤ a + c) : b ≤ c := by lift a to α using ha induction c @@ -184,7 +176,7 @@ protected theorem le_of_add_le_add_left [LE α] [ContravariantClass α α (· + · simp only [← coe_add, coe_le_coe] at h ⊢ exact le_of_add_le_add_left h -protected theorem le_of_add_le_add_right [LE α] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] +protected theorem le_of_add_le_add_right [LE α] [AddRightReflectLE α] (ha : a ≠ ⊤) (h : b + a ≤ c + a) : b ≤ c := by lift a to α using ha cases c @@ -193,7 +185,7 @@ protected theorem le_of_add_le_add_right [LE α] [ContravariantClass α α (swap · exact (not_top_le_coe _ h).elim · exact coe_le_coe.2 (le_of_add_le_add_right <| coe_le_coe.1 h) -protected theorem add_lt_add_left [LT α] [CovariantClass α α (· + ·) (· < ·)] (ha : a ≠ ⊤) +protected theorem add_lt_add_left [LT α] [AddLeftStrictMono α] (ha : a ≠ ⊤) (h : b < c) : a + b < a + c := by lift a to α using ha rcases lt_iff_exists_coe.1 h with ⟨b, rfl, h'⟩ @@ -201,7 +193,7 @@ protected theorem add_lt_add_left [LT α] [CovariantClass α α (· + ·) (· < · exact coe_lt_top _ · exact coe_lt_coe.2 (add_lt_add_left (coe_lt_coe.1 h) _) -protected theorem add_lt_add_right [LT α] [CovariantClass α α (swap (· + ·)) (· < ·)] (ha : a ≠ ⊤) +protected theorem add_lt_add_right [LT α] [AddRightStrictMono α] (ha : a ≠ ⊤) (h : b < c) : b + a < c + a := by lift a to α using ha rcases lt_iff_exists_coe.1 h with ⟨b, rfl, h'⟩ @@ -209,29 +201,29 @@ protected theorem add_lt_add_right [LT α] [CovariantClass α α (swap (· + ·) · exact coe_lt_top _ · exact coe_lt_coe.2 (add_lt_add_right (coe_lt_coe.1 h) _) -protected theorem add_le_add_iff_left [LE α] [CovariantClass α α (· + ·) (· ≤ ·)] - [ContravariantClass α α (· + ·) (· ≤ ·)] (ha : a ≠ ⊤) : a + b ≤ a + c ↔ b ≤ c := +protected theorem add_le_add_iff_left [LE α] [AddLeftMono α] + [AddLeftReflectLE α] (ha : a ≠ ⊤) : a + b ≤ a + c ↔ b ≤ c := ⟨WithTop.le_of_add_le_add_left ha, fun h => add_le_add_left h a⟩ -protected theorem add_le_add_iff_right [LE α] [CovariantClass α α (swap (· + ·)) (· ≤ ·)] - [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] (ha : a ≠ ⊤) : b + a ≤ c + a ↔ b ≤ c := +protected theorem add_le_add_iff_right [LE α] [AddRightMono α] + [AddRightReflectLE α] (ha : a ≠ ⊤) : b + a ≤ c + a ↔ b ≤ c := ⟨WithTop.le_of_add_le_add_right ha, fun h => add_le_add_right h a⟩ -protected theorem add_lt_add_iff_left [LT α] [CovariantClass α α (· + ·) (· < ·)] - [ContravariantClass α α (· + ·) (· < ·)] (ha : a ≠ ⊤) : a + b < a + c ↔ b < c := +protected theorem add_lt_add_iff_left [LT α] [AddLeftStrictMono α] + [AddLeftReflectLT α] (ha : a ≠ ⊤) : a + b < a + c ↔ b < c := ⟨lt_of_add_lt_add_left, WithTop.add_lt_add_left ha⟩ -protected theorem add_lt_add_iff_right [LT α] [CovariantClass α α (swap (· + ·)) (· < ·)] - [ContravariantClass α α (swap (· + ·)) (· < ·)] (ha : a ≠ ⊤) : b + a < c + a ↔ b < c := +protected theorem add_lt_add_iff_right [LT α] [AddRightStrictMono α] + [AddRightReflectLT α] (ha : a ≠ ⊤) : b + a < c + a ↔ b < c := ⟨lt_of_add_lt_add_right, WithTop.add_lt_add_right ha⟩ -protected theorem add_lt_add_of_le_of_lt [Preorder α] [CovariantClass α α (· + ·) (· < ·)] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] (ha : a ≠ ⊤) (hab : a ≤ b) (hcd : c < d) : +protected theorem add_lt_add_of_le_of_lt [Preorder α] [AddLeftStrictMono α] + [AddRightMono α] (ha : a ≠ ⊤) (hab : a ≤ b) (hcd : c < d) : a + c < b + d := (WithTop.add_lt_add_left ha hcd).trans_le <| add_le_add_right hab _ -protected theorem add_lt_add_of_lt_of_le [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] - [CovariantClass α α (swap (· + ·)) (· < ·)] (hc : c ≠ ⊤) (hab : a < b) (hcd : c ≤ d) : +protected theorem add_lt_add_of_lt_of_le [Preorder α] [AddLeftMono α] + [AddRightStrictMono α] (hc : c ≠ ⊤) (hab : a < b) (hcd : c ≤ d) : a + c < b + d := (WithTop.add_lt_add_right hc hab).trans_le <| add_le_add_left hcd _ @@ -368,13 +360,13 @@ instance existsAddOfLE [LE α] [Add α] [ExistsAddOfLE α] : ExistsAddOfLE (With -- CanonicallyLinearOrderedAddCommMonoid (WithTop α) := -- { WithTop.canonicallyOrderedAddCommMonoid, WithTop.linearOrder with } -@[simp] -theorem zero_lt_top [Zero α] [LT α] : (0 : WithTop α) < ⊤ := - coe_lt_top 0 +@[to_additive (attr := simp) top_pos] +theorem one_lt_top [One α] [LT α] : (1 : WithTop α) < ⊤ := coe_lt_top _ + +@[deprecated top_pos (since := "2024-10-22")] +alias zero_lt_top := top_pos --- Porting note (#10618): simp can already prove this. --- @[simp] -@[norm_cast] +@[norm_cast, deprecated coe_pos (since := "2024-10-22")] theorem zero_lt_coe [Zero α] [LT α] (a : α) : (0 : WithTop α) < a ↔ 0 < a := coe_lt_coe @@ -546,13 +538,9 @@ theorem bot_lt_add [LT α] {a b : WithBot α} : ⊥ < a + b ↔ ⊥ < a ∧ ⊥ theorem add_eq_coe : a + b = x ↔ ∃ a' b' : α, ↑a' = a ∧ ↑b' = b ∧ a' + b' = x := WithTop.add_eq_coe --- Porting note (#10618): simp can already prove this. --- @[simp] theorem add_coe_eq_bot_iff : a + y = ⊥ ↔ a = ⊥ := WithTop.add_coe_eq_top_iff --- Porting note (#10618): simp can already prove this. --- @[simp] theorem coe_add_eq_bot_iff : ↑x + b = ⊥ ↔ b = ⊥ := WithTop.coe_add_eq_top_iff @@ -598,61 +586,57 @@ protected def _root_.AddMonoidHom.withBotMap {M N : Type*} [AddZeroClass M] [Add variable [Preorder α] -instance covariantClass_add_le [CovariantClass α α (· + ·) (· ≤ ·)] : - CovariantClass (WithBot α) (WithBot α) (· + ·) (· ≤ ·) := - OrderDual.covariantClass_add_le (α := WithTop αᵒᵈ) +instance addLeftMono [AddLeftMono α] : AddLeftMono (WithBot α) := + OrderDual.addLeftMono (α := WithTop αᵒᵈ) -instance covariantClass_swap_add_le [CovariantClass α α (swap (· + ·)) (· ≤ ·)] : - CovariantClass (WithBot α) (WithBot α) (swap (· + ·)) (· ≤ ·) := - OrderDual.covariantClass_swap_add_le (α := WithTop αᵒᵈ) +instance addRightMono [AddRightMono α] : AddRightMono (WithBot α) := + OrderDual.addRightMono (α := WithTop αᵒᵈ) -instance contravariantClass_add_lt [ContravariantClass α α (· + ·) (· < ·)] : - ContravariantClass (WithBot α) (WithBot α) (· + ·) (· < ·) := - OrderDual.contravariantClass_add_lt (α := WithTop αᵒᵈ) +instance addLeftReflectLT [AddLeftReflectLT α] : AddLeftReflectLT (WithBot α) := + OrderDual.addLeftReflectLT (α := WithTop αᵒᵈ) -instance contravariantClass_swap_add_lt [ContravariantClass α α (swap (· + ·)) (· < ·)] : - ContravariantClass (WithBot α) (WithBot α) (swap (· + ·)) (· < ·) := - OrderDual.contravariantClass_swap_add_lt (α := WithTop αᵒᵈ) +instance addRightReflectLT [AddRightReflectLT α] : AddRightReflectLT (WithBot α) := + OrderDual.addRightReflectLT (α := WithTop αᵒᵈ) -protected theorem le_of_add_le_add_left [ContravariantClass α α (· + ·) (· ≤ ·)] (ha : a ≠ ⊥) +protected theorem le_of_add_le_add_left [AddLeftReflectLE α] (ha : a ≠ ⊥) (h : a + b ≤ a + c) : b ≤ c := WithTop.le_of_add_le_add_left (α := αᵒᵈ) ha h -protected theorem le_of_add_le_add_right [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] +protected theorem le_of_add_le_add_right [AddRightReflectLE α] (ha : a ≠ ⊥) (h : b + a ≤ c + a) : b ≤ c := WithTop.le_of_add_le_add_right (α := αᵒᵈ) ha h -protected theorem add_lt_add_left [CovariantClass α α (· + ·) (· < ·)] (ha : a ≠ ⊥) (h : b < c) : +protected theorem add_lt_add_left [AddLeftStrictMono α] (ha : a ≠ ⊥) (h : b < c) : a + b < a + c := WithTop.add_lt_add_left (α := αᵒᵈ) ha h -protected theorem add_lt_add_right [CovariantClass α α (swap (· + ·)) (· < ·)] (ha : a ≠ ⊥) +protected theorem add_lt_add_right [AddRightStrictMono α] (ha : a ≠ ⊥) (h : b < c) : b + a < c + a := WithTop.add_lt_add_right (α := αᵒᵈ) ha h -protected theorem add_le_add_iff_left [CovariantClass α α (· + ·) (· ≤ ·)] - [ContravariantClass α α (· + ·) (· ≤ ·)] (ha : a ≠ ⊥) : a + b ≤ a + c ↔ b ≤ c := +protected theorem add_le_add_iff_left [AddLeftMono α] + [AddLeftReflectLE α] (ha : a ≠ ⊥) : a + b ≤ a + c ↔ b ≤ c := ⟨WithBot.le_of_add_le_add_left ha, fun h => add_le_add_left h a⟩ -protected theorem add_le_add_iff_right [CovariantClass α α (swap (· + ·)) (· ≤ ·)] - [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] (ha : a ≠ ⊥) : b + a ≤ c + a ↔ b ≤ c := +protected theorem add_le_add_iff_right [AddRightMono α] + [AddRightReflectLE α] (ha : a ≠ ⊥) : b + a ≤ c + a ↔ b ≤ c := ⟨WithBot.le_of_add_le_add_right ha, fun h => add_le_add_right h a⟩ -protected theorem add_lt_add_iff_left [CovariantClass α α (· + ·) (· < ·)] - [ContravariantClass α α (· + ·) (· < ·)] (ha : a ≠ ⊥) : a + b < a + c ↔ b < c := +protected theorem add_lt_add_iff_left [AddLeftStrictMono α] + [AddLeftReflectLT α] (ha : a ≠ ⊥) : a + b < a + c ↔ b < c := ⟨lt_of_add_lt_add_left, WithBot.add_lt_add_left ha⟩ -protected theorem add_lt_add_iff_right [CovariantClass α α (swap (· + ·)) (· < ·)] - [ContravariantClass α α (swap (· + ·)) (· < ·)] (ha : a ≠ ⊥) : b + a < c + a ↔ b < c := +protected theorem add_lt_add_iff_right [AddRightStrictMono α] + [AddRightReflectLT α] (ha : a ≠ ⊥) : b + a < c + a ↔ b < c := ⟨lt_of_add_lt_add_right, WithBot.add_lt_add_right ha⟩ -protected theorem add_lt_add_of_le_of_lt [CovariantClass α α (· + ·) (· < ·)] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] (hb : b ≠ ⊥) (hab : a ≤ b) (hcd : c < d) : +protected theorem add_lt_add_of_le_of_lt [AddLeftStrictMono α] + [AddRightMono α] (hb : b ≠ ⊥) (hab : a ≤ b) (hcd : c < d) : a + c < b + d := WithTop.add_lt_add_of_le_of_lt (α := αᵒᵈ) hb hab hcd -protected theorem add_lt_add_of_lt_of_le [CovariantClass α α (· + ·) (· ≤ ·)] - [CovariantClass α α (swap (· + ·)) (· < ·)] (hd : d ≠ ⊥) (hab : a < b) (hcd : c ≤ d) : +protected theorem add_lt_add_of_lt_of_le [AddLeftMono α] + [AddRightStrictMono α] (hd : d ≠ ⊥) (hab : a < b) (hcd : c ≤ d) : a + c < b + d := WithTop.add_lt_add_of_lt_of_le (α := αᵒᵈ) hd hab hcd diff --git a/Mathlib/Algebra/Order/Monoid/Units.lean b/Mathlib/Algebra/Order/Monoid/Units.lean index 9e0572e82a0cc..daf01bce3fef7 100644 --- a/Mathlib/Algebra/Order/Monoid/Units.lean +++ b/Mathlib/Algebra/Order/Monoid/Units.lean @@ -5,7 +5,7 @@ Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl -/ import Mathlib.Order.Hom.Basic import Mathlib.Order.MinMax -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Defs /-! # Units in ordered monoids diff --git a/Mathlib/Algebra/Order/Monoid/WithTop.lean b/Mathlib/Algebra/Order/Monoid/WithTop.lean index 7ce0466e1bece..b13f9b50c072b 100644 --- a/Mathlib/Algebra/Order/Monoid/WithTop.lean +++ b/Mathlib/Algebra/Order/Monoid/WithTop.lean @@ -9,9 +9,9 @@ import Mathlib.Algebra.Order.Monoid.Canonical.Defs /-! # Adjoining top/bottom elements to ordered monoids. -/ -universe u v +universe u -variable {α : Type u} {β : Type v} +variable {α : Type u} open Function diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index f742a97bcf60e..60f025df1e810 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -26,7 +26,7 @@ variable {ι α β : Type*} /-! ### Algebraic operations on monovarying functions -/ section OrderedCommGroup -variable [OrderedCommGroup α] [OrderedCommGroup β] {s : Set ι} {f f₁ f₂ : ι → α} {g g₁ g₂ : ι → β} +variable [OrderedCommGroup α] [OrderedCommGroup β] {s : Set ι} {f f₁ f₂ : ι → α} {g : ι → β} @[to_additive (attr := simp)] lemma monovaryOn_inv_left : MonovaryOn f⁻¹ g s ↔ AntivaryOn f g s := by @@ -118,7 +118,7 @@ lemma Antivary.div_left (h₁ : Antivary f₁ g) (h₂ : Monovary f₂ g) : Anti end OrderedCommGroup section LinearOrderedCommGroup -variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f f₁ f₂ : ι → α} +variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f : ι → α} {g g₁ g₂ : ι → β} @[to_additive] lemma MonovaryOn.mul_right (h₁ : MonovaryOn f g₁ s) (h₂ : MonovaryOn f g₂ s) : @@ -168,7 +168,7 @@ variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f f₁ end LinearOrderedCommGroup section OrderedSemiring -variable [OrderedSemiring α] [OrderedSemiring β] {s : Set ι} {f f₁ f₂ : ι → α} {g g₁ g₂ : ι → β} +variable [OrderedSemiring α] [OrderedSemiring β] {s : Set ι} {f f₁ f₂ : ι → α} {g : ι → β} lemma MonovaryOn.mul_left₀ (hf₁ : ∀ i ∈ s, 0 ≤ f₁ i) (hf₂ : ∀ i ∈ s, 0 ≤ f₂ i) (h₁ : MonovaryOn f₁ g s) (h₂ : MonovaryOn f₂ g s) : MonovaryOn (f₁ * f₂) g s := @@ -201,7 +201,7 @@ lemma Antivary.pow_left₀ (hf : 0 ≤ f) (hfg : Antivary f g) (n : ℕ) : Antiv end OrderedSemiring section LinearOrderedSemiring -variable [LinearOrderedSemiring α] [LinearOrderedSemiring β] {s : Set ι} {f f₁ f₂ : ι → α} +variable [LinearOrderedSemiring α] [LinearOrderedSemiring β] {s : Set ι} {f : ι → α} {g g₁ g₂ : ι → β} lemma MonovaryOn.mul_right₀ (hg₁ : ∀ i ∈ s, 0 ≤ g₁ i) (hg₂ : ∀ i ∈ s, 0 ≤ g₂ i) @@ -238,19 +238,19 @@ variable [LinearOrderedSemifield α] [LinearOrderedSemifield β] {s : Set ι} {f @[simp] lemma monovaryOn_inv_left₀ (hf : ∀ i ∈ s, 0 < f i) : MonovaryOn f⁻¹ g s ↔ AntivaryOn f g s := - forall₅_congr fun _i hi _j hj _ ↦ inv_le_inv (hf _ hi) (hf _ hj) + forall₅_congr fun _i hi _j hj _ ↦ inv_le_inv₀ (hf _ hi) (hf _ hj) @[simp] lemma antivaryOn_inv_left₀ (hf : ∀ i ∈ s, 0 < f i) : AntivaryOn f⁻¹ g s ↔ MonovaryOn f g s := - forall₅_congr fun _i hi _j hj _ ↦ inv_le_inv (hf _ hj) (hf _ hi) + forall₅_congr fun _i hi _j hj _ ↦ inv_le_inv₀ (hf _ hj) (hf _ hi) @[simp] lemma monovaryOn_inv_right₀ (hg : ∀ i ∈ s, 0 < g i) : MonovaryOn f g⁻¹ s ↔ AntivaryOn f g s := - forall₂_swap.trans <| forall₄_congr fun i hi j hj ↦ by erw [inv_lt_inv (hg _ hj) (hg _ hi)] + forall₂_swap.trans <| forall₄_congr fun i hi j hj ↦ by erw [inv_lt_inv₀ (hg _ hj) (hg _ hi)] @[simp] lemma antivaryOn_inv_right₀ (hg : ∀ i ∈ s, 0 < g i) : AntivaryOn f g⁻¹ s ↔ MonovaryOn f g s := - forall₂_swap.trans <| forall₄_congr fun i hi j hj ↦ by erw [inv_lt_inv (hg _ hj) (hg _ hi)] + forall₂_swap.trans <| forall₄_congr fun i hi j hj ↦ by erw [inv_lt_inv₀ (hg _ hj) (hg _ hi)] lemma monovaryOn_inv₀ (hf : ∀ i ∈ s, 0 < f i) (hg : ∀ i ∈ s, 0 < g i) : MonovaryOn f⁻¹ g⁻¹ s ↔ MonovaryOn f g s := by @@ -260,16 +260,16 @@ lemma antivaryOn_inv₀ (hf : ∀ i ∈ s, 0 < f i) (hg : ∀ i ∈ s, 0 < g i) rw [antivaryOn_inv_left₀ hf, monovaryOn_inv_right₀ hg] @[simp] lemma monovary_inv_left₀ (hf : StrongLT 0 f) : Monovary f⁻¹ g ↔ Antivary f g := - forall₃_congr fun _i _j _ ↦ inv_le_inv (hf _) (hf _) + forall₃_congr fun _i _j _ ↦ inv_le_inv₀ (hf _) (hf _) @[simp] lemma antivary_inv_left₀ (hf : StrongLT 0 f) : Antivary f⁻¹ g ↔ Monovary f g := - forall₃_congr fun _i _j _ ↦ inv_le_inv (hf _) (hf _) + forall₃_congr fun _i _j _ ↦ inv_le_inv₀ (hf _) (hf _) @[simp] lemma monovary_inv_right₀ (hg : StrongLT 0 g) : Monovary f g⁻¹ ↔ Antivary f g := - forall_swap.trans <| forall₂_congr fun i j ↦ by erw [inv_lt_inv (hg _) (hg _)] + forall_swap.trans <| forall₂_congr fun i j ↦ by erw [inv_lt_inv₀ (hg _) (hg _)] @[simp] lemma antivary_inv_right₀ (hg : StrongLT 0 g) : Antivary f g⁻¹ ↔ Monovary f g := - forall_swap.trans <| forall₂_congr fun i j ↦ by erw [inv_lt_inv (hg _) (hg _)] + forall_swap.trans <| forall₂_congr fun i j ↦ by erw [inv_lt_inv₀ (hg _) (hg _)] lemma monovary_inv₀ (hf : StrongLT 0 f) (hg : StrongLT 0 g) : Monovary f⁻¹ g⁻¹ ↔ Monovary f g := by rw [monovary_inv_left₀ hf, antivary_inv_right₀ hg] @@ -325,7 +325,7 @@ end LinearOrderedSemifield section LinearOrderedAddCommGroup variable [LinearOrderedRing α] [LinearOrderedAddCommGroup β] [Module α β] - [OrderedSMul α β] {f : ι → α} {g : ι → β} {s : Set ι} {a a₁ a₂ : α} {b b₁ b₂ : β} + [OrderedSMul α β] {f : ι → α} {g : ι → β} {s : Set ι} lemma monovaryOn_iff_forall_smul_nonneg : MonovaryOn f g s ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃j⦄, j ∈ s → 0 ≤ (f j - f i) • (g j - g i) := by @@ -380,7 +380,7 @@ alias ⟨AntivaryOn.smul_add_smul_le_smul_add_smul, _⟩ := antivaryOn_iff_smul_ end LinearOrderedAddCommGroup section LinearOrderedRing -variable [LinearOrderedRing α] {f g : ι → α} {s : Set ι} {a b c d : α} +variable [LinearOrderedRing α] {f g : ι → α} {s : Set ι} lemma monovaryOn_iff_forall_mul_nonneg : MonovaryOn f g s ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃j⦄, j ∈ s → 0 ≤ (f j - f i) * (g j - g i) := by diff --git a/Mathlib/Algebra/Order/Pi.lean b/Mathlib/Algebra/Order/Pi.lean index 9710857e2382b..601b52a20fee9 100644 --- a/Mathlib/Algebra/Order/Pi.lean +++ b/Mathlib/Algebra/Order/Pi.lean @@ -13,14 +13,11 @@ import Mathlib.Algebra.Ring.Pi This file defines instances for ordered group, monoid, and related structures on Pi types. -/ -variable {ι I α β γ : Type*} +variable {I α β γ : Type*} -- The indexing type variable {f : I → Type*} --- The family of types already equipped with instances -variable (x y : ∀ i, f i) (i : I) - namespace Pi /-- The product of a family of ordered commutative monoids is an ordered commutative monoid. -/ diff --git a/Mathlib/Algebra/Order/Positive/Field.lean b/Mathlib/Algebra/Order/Positive/Field.lean index 3a053adc33a18..5d1fc0b381760 100644 --- a/Mathlib/Algebra/Order/Positive/Field.lean +++ b/Mathlib/Algebra/Order/Positive/Field.lean @@ -25,7 +25,7 @@ theorem coe_inv (x : { x : K // 0 < x }) : ↑x⁻¹ = (x⁻¹ : K) := rfl instance : Pow { x : K // 0 < x } ℤ := - ⟨fun x n => ⟨(x : K) ^ n, zpow_pos_of_pos x.2 _⟩⟩ + ⟨fun x n => ⟨(x : K) ^ n, zpow_pos x.2 _⟩⟩ @[simp] theorem coe_zpow (x : { x : K // 0 < x }) (n : ℤ) : ↑(x ^ n) = (x : K) ^ n := diff --git a/Mathlib/Algebra/Order/Positive/Ring.lean b/Mathlib/Algebra/Order/Positive/Ring.lean index 27a63fd2e7278..ff395b0df05ef 100644 --- a/Mathlib/Algebra/Order/Positive/Ring.lean +++ b/Mathlib/Algebra/Order/Positive/Ring.lean @@ -19,11 +19,11 @@ open Function namespace Positive -variable {M R K : Type*} +variable {M R : Type*} section AddBasic -variable [AddMonoid M] [Preorder M] [CovariantClass M M (· + ·) (· < ·)] +variable [AddMonoid M] [Preorder M] [AddLeftStrictMono M] instance : Add { x : M // 0 < x } := ⟨fun x y => ⟨x + y, add_pos x.2 y.2⟩⟩ @@ -36,46 +36,39 @@ instance addSemigroup : AddSemigroup { x : M // 0 < x } := Subtype.coe_injective.addSemigroup _ coe_add instance addCommSemigroup {M : Type*} [AddCommMonoid M] [Preorder M] - [CovariantClass M M (· + ·) (· < ·)] : AddCommSemigroup { x : M // 0 < x } := + [AddLeftStrictMono M] : AddCommSemigroup { x : M // 0 < x } := Subtype.coe_injective.addCommSemigroup _ coe_add instance addLeftCancelSemigroup {M : Type*} [AddLeftCancelMonoid M] [Preorder M] - [CovariantClass M M (· + ·) (· < ·)] : AddLeftCancelSemigroup { x : M // 0 < x } := + [AddLeftStrictMono M] : AddLeftCancelSemigroup { x : M // 0 < x } := Subtype.coe_injective.addLeftCancelSemigroup _ coe_add instance addRightCancelSemigroup {M : Type*} [AddRightCancelMonoid M] [Preorder M] - [CovariantClass M M (· + ·) (· < ·)] : AddRightCancelSemigroup { x : M // 0 < x } := + [AddLeftStrictMono M] : AddRightCancelSemigroup { x : M // 0 < x } := Subtype.coe_injective.addRightCancelSemigroup _ coe_add -instance covariantClass_add_lt : - CovariantClass { x : M // 0 < x } { x : M // 0 < x } (· + ·) (· < ·) := +instance addLeftStrictMono : AddLeftStrictMono { x : M // 0 < x } := ⟨fun _ y z hyz => Subtype.coe_lt_coe.1 <| add_lt_add_left (show (y : M) < z from hyz) _⟩ -instance covariantClass_swap_add_lt [CovariantClass M M (swap (· + ·)) (· < ·)] : - CovariantClass { x : M // 0 < x } { x : M // 0 < x } (swap (· + ·)) (· < ·) := +instance addRightStrictMono [AddRightStrictMono M] : AddRightStrictMono { x : M // 0 < x } := ⟨fun _ y z hyz => Subtype.coe_lt_coe.1 <| add_lt_add_right (show (y : M) < z from hyz) _⟩ -instance contravariantClass_add_lt [ContravariantClass M M (· + ·) (· < ·)] : - ContravariantClass { x : M // 0 < x } { x : M // 0 < x } (· + ·) (· < ·) := +instance addLeftReflectLT [AddLeftReflectLT M] : AddLeftReflectLT { x : M // 0 < x } := ⟨fun _ _ _ h => Subtype.coe_lt_coe.1 <| lt_of_add_lt_add_left h⟩ -instance contravariantClass_swap_add_lt [ContravariantClass M M (swap (· + ·)) (· < ·)] : - ContravariantClass { x : M // 0 < x } { x : M // 0 < x } (swap (· + ·)) (· < ·) := +instance addRightReflectLT [AddRightReflectLT M] : AddRightReflectLT { x : M // 0 < x } := ⟨fun _ _ _ h => Subtype.coe_lt_coe.1 <| lt_of_add_lt_add_right h⟩ -instance contravariantClass_add_le [ContravariantClass M M (· + ·) (· ≤ ·)] : - ContravariantClass { x : M // 0 < x } { x : M // 0 < x } (· + ·) (· ≤ ·) := +instance addLeftReflectLE [AddLeftReflectLE M] : AddLeftReflectLE { x : M // 0 < x } := ⟨fun _ _ _ h => Subtype.coe_le_coe.1 <| le_of_add_le_add_left h⟩ -instance contravariantClass_swap_add_le [ContravariantClass M M (swap (· + ·)) (· ≤ ·)] : - ContravariantClass { x : M // 0 < x } { x : M // 0 < x } (swap (· + ·)) (· ≤ ·) := +instance addRightReflectLE [AddRightReflectLE M] : AddRightReflectLE { x : M // 0 < x } := ⟨fun _ _ _ h => Subtype.coe_le_coe.1 <| le_of_add_le_add_right h⟩ end AddBasic -instance covariantClass_add_le [AddMonoid M] [PartialOrder M] - [CovariantClass M M (· + ·) (· < ·)] : - CovariantClass { x : M // 0 < x } { x : M // 0 < x } (· + ·) (· ≤ ·) := +instance addLeftMono [AddMonoid M] [PartialOrder M] [AddLeftStrictMono M] : + AddLeftMono { x : M // 0 < x } := ⟨@fun _ _ _ h₁ => StrictMono.monotone (fun _ _ h => add_lt_add_left h _) h₁⟩ section Mul diff --git a/Mathlib/Algebra/Order/Ring/Abs.lean b/Mathlib/Algebra/Order/Ring/Abs.lean index e61b8d4297a31..25cd393bf7434 100644 --- a/Mathlib/Algebra/Order/Ring/Abs.lean +++ b/Mathlib/Algebra/Order/Ring/Abs.lean @@ -17,7 +17,7 @@ import Mathlib.Data.Nat.Cast.Order.Ring variable {α : Type*} section LinearOrderedAddCommGroup -variable [LinearOrderedCommGroup α] {a b : α} +variable [LinearOrderedCommGroup α] @[to_additive] lemma mabs_zpow (n : ℤ) (a : α) : |a ^ n|ₘ = |a|ₘ ^ |n| := by obtain n0 | n0 := le_total 0 n @@ -34,7 +34,7 @@ lemma odd_abs [LinearOrder α] [Ring α] {a : α} : Odd (abs a) ↔ Odd a := by section LinearOrderedRing -variable [LinearOrderedRing α] {n : ℕ} {a b c : α} +variable [LinearOrderedRing α] {n : ℕ} {a b : α} @[simp] lemma abs_one : |(1 : α)| = 1 := abs_of_pos zero_lt_one @@ -141,7 +141,7 @@ end LinearOrderedRing section LinearOrderedCommRing -variable [LinearOrderedCommRing α] {a b c d : α} +variable [LinearOrderedCommRing α] theorem abs_sub_sq (a b : α) : |a - b| * |a - b| = a * a + b * b - (1 + 1) * a * b := by rw [abs_mul_abs_self] @@ -152,7 +152,7 @@ end LinearOrderedCommRing section -variable [Ring α] [LinearOrder α] {a b : α} +variable [Ring α] [LinearOrder α] @[simp] theorem abs_dvd (a b : α) : |a| ∣ b ↔ a ∣ b := by diff --git a/Mathlib/Algebra/Order/Ring/Basic.lean b/Mathlib/Algebra/Order/Ring/Basic.lean index 5e64f73cc40ea..284772133e61f 100644 --- a/Mathlib/Algebra/Order/Ring/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Basic.lean @@ -21,7 +21,7 @@ variable {α M R : Type*} namespace MonoidHom -variable [Ring R] [Monoid M] [LinearOrder M] [CovariantClass M M (· * ·) (· ≤ ·)] (f : R →* M) +variable [Ring R] [Monoid M] [LinearOrder M] [MulLeftMono M] (f : R →* M) theorem map_neg_one : f (-1) = 1 := (pow_eq_one_iff (Nat.succ_ne_zero 1)).1 <| by rw [← map_pow, neg_one_sq, map_one] @@ -99,7 +99,7 @@ abbrev OrderedRing.toStrictOrderedRing (α : Type*) [OrderedRing α] [NoZeroDivisors α] [Nontrivial α] : StrictOrderedRing α where __ := ‹OrderedRing α› __ := ‹NoZeroDivisors α› - mul_pos a b ap bp := (mul_nonneg ap.le bp.le).lt_of_ne' (mul_ne_zero ap.ne' bp.ne') + mul_pos _ _ ap bp := (mul_nonneg ap.le bp.le).lt_of_ne' (mul_ne_zero ap.ne' bp.ne') section StrictOrderedSemiring diff --git a/Mathlib/Algebra/Order/Ring/Canonical.lean b/Mathlib/Algebra/Order/Ring/Canonical.lean index 1f64f689d1e79..3c7a907838251 100644 --- a/Mathlib/Algebra/Order/Ring/Canonical.lean +++ b/Mathlib/Algebra/Order/Ring/Canonical.lean @@ -27,7 +27,7 @@ open Function universe u -variable {α : Type u} {β : Type*} +variable {α : Type u} /-- A canonically ordered commutative semiring is an ordered, commutative semiring in which `a ≤ b` iff there exists `c` with `b = a + c`. This is satisfied by the natural numbers, for example, but @@ -51,8 +51,8 @@ instance (priority := 100) toNoZeroDivisors : NoZeroDivisors α := ⟨CanonicallyOrderedCommSemiring.eq_zero_or_eq_zero_of_mul_eq_zero⟩ -- see Note [lower instance priority] -instance (priority := 100) toCovariantClassMulLE : CovariantClass α α (· * ·) (· ≤ ·) := by - refine ⟨fun a b c h => ?_⟩ +instance (priority := 100) toMulLeftMono : MulLeftMono α := by + refine ⟨fun a b c h => ?_⟩; dsimp rcases exists_add_of_le h with ⟨c, rfl⟩ rw [mul_add] apply self_le_add_right @@ -65,8 +65,8 @@ instance (priority := 100) toOrderedCommMonoid : OrderedCommMonoid α where instance (priority := 100) toOrderedCommSemiring : OrderedCommSemiring α := { ‹CanonicallyOrderedCommSemiring α› with zero_le_one := zero_le _, - mul_le_mul_of_nonneg_left := fun a b c h _ => mul_le_mul_left' h _, - mul_le_mul_of_nonneg_right := fun a b c h _ => mul_le_mul_right' h _ } + mul_le_mul_of_nonneg_left := fun _ _ _ h _ => mul_le_mul_left' h _, + mul_le_mul_of_nonneg_right := fun _ _ _ h _ => mul_le_mul_right' h _ } @[simp] protected theorem mul_pos : 0 < a * b ↔ 0 < a ∧ 0 < b := by @@ -106,7 +106,7 @@ protected theorem tsub_mul (h : AddLECancellable (b * c)) : (a - b) * c = a * c end AddLECancellable -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] theorem mul_tsub (a b c : α) : a * (b - c) = a * b - a * c := Contravariant.AddLECancellable.mul_tsub diff --git a/Mathlib/Algebra/Order/Ring/Cast.lean b/Mathlib/Algebra/Order/Ring/Cast.lean index bd47e1f894415..74581d5714f35 100644 --- a/Mathlib/Algebra/Order/Ring/Cast.lean +++ b/Mathlib/Algebra/Order/Ring/Cast.lean @@ -27,7 +27,7 @@ variable {R : Type*} namespace Int section OrderedAddCommGroupWithOne -variable [AddCommGroupWithOne R] [PartialOrder R] [CovariantClass R R (· + ·) (· ≤ ·)] +variable [AddCommGroupWithOne R] [PartialOrder R] [AddLeftMono R] variable [ZeroLEOneClass R] lemma cast_mono : Monotone (Int.cast : ℤ → R) := by diff --git a/Mathlib/Algebra/Order/Ring/Cone.lean b/Mathlib/Algebra/Order/Ring/Cone.lean index 71c21076f0093..097bfc9afe3ca 100644 --- a/Mathlib/Algebra/Order/Ring/Cone.lean +++ b/Mathlib/Algebra/Order/Ring/Cone.lean @@ -83,4 +83,4 @@ due to non-customisable fields: `lt`, `decidableLT`, `decidableEq`, `compare`. - __ := OrderedRing.mkOfCone C __ := OrderedRing.toStrictOrderedRing R le_total a b := by simpa using mem_or_neg_mem (b - a) - decidableLE a b := dec _ + decidableLE _ _ := dec _ diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index 2a1301cc48fc2..d9128b14a9a37 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -109,7 +109,7 @@ open Function universe u -variable {α : Type u} {β : Type*} +variable {α : Type u} /-! Note that `OrderDual` does not satisfy any of the ordered ring typeclasses due to the `zero_le_one` field. -/ @@ -195,7 +195,7 @@ class LinearOrderedCommRing (α : Type u) extends LinearOrderedRing α, CommMono section OrderedSemiring -variable [OrderedSemiring α] {a b c d : α} +variable [OrderedSemiring α] -- see Note [lower instance priority] instance (priority := 100) OrderedSemiring.zeroLEOneClass : ZeroLEOneClass α := { ‹OrderedSemiring α› with } @@ -212,7 +212,7 @@ end OrderedSemiring section OrderedRing -variable [OrderedRing α] {a b c d : α} +variable [OrderedRing α] {a b c : α} -- see Note [lower instance priority] instance (priority := 100) OrderedRing.toOrderedSemiring : OrderedSemiring α := @@ -252,7 +252,7 @@ end OrderedCommRing section StrictOrderedSemiring -variable [StrictOrderedSemiring α] {a b c d : α} +variable [StrictOrderedSemiring α] -- see Note [lower instance priority] instance (priority := 200) StrictOrderedSemiring.toPosMulStrictMono : PosMulStrictMono α := @@ -320,7 +320,7 @@ instance (priority := 100) StrictOrderedCommSemiring.toOrderedCommSemiring : end StrictOrderedCommSemiring section StrictOrderedRing -variable [StrictOrderedRing α] {a b c : α} +variable [StrictOrderedRing α] -- see Note [lower instance priority] instance (priority := 100) StrictOrderedRing.toStrictOrderedSemiring : StrictOrderedSemiring α := @@ -373,7 +373,7 @@ end StrictOrderedCommRing section LinearOrderedSemiring -variable [LinearOrderedSemiring α] {a b c d : α} +variable [LinearOrderedSemiring α] -- see Note [lower instance priority] instance (priority := 200) LinearOrderedSemiring.toPosMulReflectLT : PosMulReflectLT α := @@ -412,7 +412,7 @@ instance (priority := 100) LinearOrderedSemiring.toLinearOrderedCancelAddCommMon end LinearOrderedSemiring section LinearOrderedRing -variable [LinearOrderedRing α] {a b c : α} +variable [LinearOrderedRing α] attribute [local instance] LinearOrderedRing.decidableLE LinearOrderedRing.decidableLT diff --git a/Mathlib/Algebra/Order/Ring/Rat.lean b/Mathlib/Algebra/Order/Ring/Rat.lean index 88cca6d79229f..12e6c49ad09a5 100644 --- a/Mathlib/Algebra/Order/Ring/Rat.lean +++ b/Mathlib/Algebra/Order/Ring/Rat.lean @@ -31,8 +31,8 @@ instance instLinearOrderedCommRing : LinearOrderedCommRing ℚ where __ := Rat.linearOrder __ := Rat.commRing zero_le_one := by decide - add_le_add_left := fun a b ab c => Rat.add_le_add_left.2 ab - mul_pos a b ha hb := (Rat.mul_nonneg ha.le hb.le).lt_of_ne' (mul_ne_zero ha.ne' hb.ne') + add_le_add_left := fun _ _ ab _ => Rat.add_le_add_left.2 ab + mul_pos _ _ ha hb := (Rat.mul_nonneg ha.le hb.le).lt_of_ne' (mul_ne_zero ha.ne' hb.ne') -- Extra instances to short-circuit type class resolution instance : LinearOrderedRing ℚ := by infer_instance diff --git a/Mathlib/Algebra/Order/Ring/Star.lean b/Mathlib/Algebra/Order/Ring/Star.lean index 06f3ffa17e0cc..8c80169e52db5 100644 --- a/Mathlib/Algebra/Order/Ring/Star.lean +++ b/Mathlib/Algebra/Order/Ring/Star.lean @@ -35,7 +35,7 @@ argument in the instance below for `mul_le_mul_of_nonneg_right`. -/ private lemma mul_le_mul_of_nonneg_left {R : Type*} [CommSemiring R] [PartialOrder R] [StarRing R] [StarOrderedRing R] {a b c : R} (hab : a ≤ b) (hc : 0 ≤ c) : c * a ≤ c * b := by rw [StarOrderedRing.nonneg_iff] at hc - induction hc using AddSubmonoid.closure_induction' with + induction hc using AddSubmonoid.closure_induction with | mem _ h => obtain ⟨x, rfl⟩ := h simp_rw [mul_assoc, mul_comm x, ← mul_assoc] diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean index ea150bfb7d6fe..06cc0315f08b0 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Yaël Dillies -/ import Mathlib.Algebra.Group.Pi.Basic -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Algebra.GroupWithZero.NeZero import Mathlib.Algebra.Order.Group.Unbundled.Basic import Mathlib.Algebra.Order.GroupWithZero.Unbundled @@ -126,7 +126,7 @@ variable {α : Type u} {β : Type*} `zero_le_one` field. -/ -theorem add_one_le_two_mul [LE α] [Semiring α] [CovariantClass α α (· + ·) (· ≤ ·)] {a : α} +theorem add_one_le_two_mul [LE α] [Semiring α] [AddLeftMono α] {a : α} (a1 : 1 ≤ a) : a + 1 ≤ 2 * a := calc a + 1 ≤ a + a := add_le_add_left a1 a @@ -137,7 +137,7 @@ section OrderedSemiring variable [Semiring α] [Preorder α] {a b c d : α} -- Porting note: it's unfortunate we need to write `(@one_le_two α)` here. -theorem add_le_mul_two_add [ZeroLEOneClass α] [MulPosMono α] [CovariantClass α α (· + ·) (· ≤ ·)] +theorem add_le_mul_two_add [ZeroLEOneClass α] [MulPosMono α] [AddLeftMono α] (a2 : 2 ≤ a) (b0 : 0 ≤ b) : a + (2 + b) ≤ a * (2 + b) := calc a + (2 + b) ≤ a + (a + a * b) := @@ -145,7 +145,7 @@ theorem add_le_mul_two_add [ZeroLEOneClass α] [MulPosMono α] [CovariantClass _ ≤ a * (2 + b) := by rw [mul_add, mul_two, add_assoc] theorem mul_le_mul_of_nonpos_left [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (h : b ≤ a) (hc : c ≤ 0) : c * a ≤ c * b := by obtain ⟨d, hcd⟩ := exists_add_of_le hc refine le_of_add_le_add_right (a := d * b + d * a) ?_ @@ -155,7 +155,7 @@ theorem mul_le_mul_of_nonpos_left [ExistsAddOfLE α] [PosMulMono α] _ = _ := by rw [← add_assoc, ← add_mul, ← hcd, zero_mul, zero_add] theorem mul_le_mul_of_nonpos_right [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (h : b ≤ a) (hc : c ≤ 0) : a * c ≤ b * c := by obtain ⟨d, hcd⟩ := exists_add_of_le hc refine le_of_add_le_add_right (a := b * d + a * d) ?_ @@ -165,61 +165,61 @@ theorem mul_le_mul_of_nonpos_right [ExistsAddOfLE α] [MulPosMono α] _ = _ := by rw [← add_assoc, ← mul_add, ← hcd, mul_zero, zero_add] theorem mul_nonneg_of_nonpos_of_nonpos [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a * b := by simpa only [zero_mul] using mul_le_mul_of_nonpos_right ha hb theorem mul_le_mul_of_nonneg_of_nonpos [ExistsAddOfLE α] [MulPosMono α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hca : c ≤ a) (hbd : b ≤ d) (hc : 0 ≤ c) (hb : b ≤ 0) : a * b ≤ c * d := (mul_le_mul_of_nonpos_right hca hb).trans <| mul_le_mul_of_nonneg_left hbd hc theorem mul_le_mul_of_nonneg_of_nonpos' [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hca : c ≤ a) (hbd : b ≤ d) (ha : 0 ≤ a) (hd : d ≤ 0) : a * b ≤ c * d := (mul_le_mul_of_nonneg_left hbd ha).trans <| mul_le_mul_of_nonpos_right hca hd theorem mul_le_mul_of_nonpos_of_nonneg [ExistsAddOfLE α] [MulPosMono α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hac : a ≤ c) (hdb : d ≤ b) (hc : c ≤ 0) (hb : 0 ≤ b) : a * b ≤ c * d := (mul_le_mul_of_nonneg_right hac hb).trans <| mul_le_mul_of_nonpos_left hdb hc theorem mul_le_mul_of_nonpos_of_nonneg' [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hca : c ≤ a) (hbd : b ≤ d) (ha : 0 ≤ a) (hd : d ≤ 0) : a * b ≤ c * d := (mul_le_mul_of_nonneg_left hbd ha).trans <| mul_le_mul_of_nonpos_right hca hd theorem mul_le_mul_of_nonpos_of_nonpos [ExistsAddOfLE α] [MulPosMono α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hca : c ≤ a) (hdb : d ≤ b) (hc : c ≤ 0) (hb : b ≤ 0) : a * b ≤ c * d := (mul_le_mul_of_nonpos_right hca hb).trans <| mul_le_mul_of_nonpos_left hdb hc theorem mul_le_mul_of_nonpos_of_nonpos' [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hca : c ≤ a) (hdb : d ≤ b) (ha : a ≤ 0) (hd : d ≤ 0) : a * b ≤ c * d := (mul_le_mul_of_nonpos_left hdb ha).trans <| mul_le_mul_of_nonpos_right hca hd /-- Variant of `mul_le_of_le_one_left` for `b` non-positive instead of non-negative. -/ theorem le_mul_of_le_one_left [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hb : b ≤ 0) (h : a ≤ 1) : b ≤ a * b := by simpa only [one_mul] using mul_le_mul_of_nonpos_right h hb /-- Variant of `le_mul_of_one_le_left` for `b` non-positive instead of non-negative. -/ theorem mul_le_of_one_le_left [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hb : b ≤ 0) (h : 1 ≤ a) : a * b ≤ b := by simpa only [one_mul] using mul_le_mul_of_nonpos_right h hb /-- Variant of `mul_le_of_le_one_right` for `a` non-positive instead of non-negative. -/ theorem le_mul_of_le_one_right [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (ha : a ≤ 0) (h : b ≤ 1) : a ≤ a * b := by simpa only [mul_one] using mul_le_mul_of_nonpos_left h ha /-- Variant of `le_mul_of_one_le_right` for `a` non-positive instead of non-negative. -/ theorem mul_le_of_one_le_right [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (ha : a ≤ 0) (h : 1 ≤ b) : a * b ≤ a := by simpa only [mul_one] using mul_le_mul_of_nonpos_left h ha @@ -228,49 +228,49 @@ section Monotone variable [Preorder β] {f g : β → α} theorem antitone_mul_left [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a : α} (ha : a ≤ 0) : Antitone (a * ·) := fun _ _ b_le_c => mul_le_mul_of_nonpos_left b_le_c ha theorem antitone_mul_right [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a : α} (ha : a ≤ 0) : Antitone fun x => x * a := fun _ _ b_le_c => mul_le_mul_of_nonpos_right b_le_c ha theorem Monotone.const_mul_of_nonpos [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Monotone f) (ha : a ≤ 0) : Antitone fun x => a * f x := (antitone_mul_left ha).comp_monotone hf theorem Monotone.mul_const_of_nonpos [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Monotone f) (ha : a ≤ 0) : Antitone fun x => f x * a := (antitone_mul_right ha).comp_monotone hf theorem Antitone.const_mul_of_nonpos [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Antitone f) (ha : a ≤ 0) : Monotone fun x => a * f x := (antitone_mul_left ha).comp hf theorem Antitone.mul_const_of_nonpos [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Antitone f) (ha : a ≤ 0) : Monotone fun x => f x * a := (antitone_mul_right ha).comp hf theorem Antitone.mul_monotone [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Antitone f) (hg : Monotone g) (hf₀ : ∀ x, f x ≤ 0) (hg₀ : ∀ x, 0 ≤ g x) : Antitone (f * g) := fun _ _ h => mul_le_mul_of_nonpos_of_nonneg (hf h) (hg h) (hf₀ _) (hg₀ _) theorem Monotone.mul_antitone [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Monotone f) (hg : Antitone g) (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, g x ≤ 0) : Antitone (f * g) := fun _ _ h => mul_le_mul_of_nonneg_of_nonpos (hf h) (hg h) (hf₀ _) (hg₀ _) theorem Antitone.mul [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hf : Antitone f) (hg : Antitone g) (hf₀ : ∀ x, f x ≤ 0) (hg₀ : ∀ x, g x ≤ 0) : Monotone (f * g) := fun _ _ h => mul_le_mul_of_nonpos_of_nonpos (hf h) (hg h) (hf₀ _) (hg₀ _) @@ -284,11 +284,11 @@ section StrictOrderedSemiring variable [Semiring α] [PartialOrder α] {a b c d : α} theorem lt_two_mul_self [ZeroLEOneClass α] [MulPosStrictMono α] [NeZero (R := α) 1] - [CovariantClass α α (· + ·) (· < ·)] (ha : 0 < a) : a < 2 * a := + [AddLeftStrictMono α] (ha : 0 < a) : a < 2 * a := lt_mul_of_one_lt_left ha one_lt_two theorem mul_lt_mul_of_neg_left [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (h : b < a) (hc : c < 0) : c * a < c * b := by obtain ⟨d, hcd⟩ := exists_add_of_le hc.le refine (add_lt_add_iff_right (d * b + d * a)).1 ?_ @@ -298,7 +298,7 @@ theorem mul_lt_mul_of_neg_left [ExistsAddOfLE α] [PosMulStrictMono α] _ = _ := by rw [← add_assoc, ← add_mul, ← hcd, zero_mul, zero_add] theorem mul_lt_mul_of_neg_right [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (h : b < a) (hc : c < 0) : a * c < b * c := by obtain ⟨d, hcd⟩ := exists_add_of_le hc.le refine (add_lt_add_iff_right (b * d + a * d)).1 ?_ @@ -308,65 +308,65 @@ theorem mul_lt_mul_of_neg_right [ExistsAddOfLE α] [MulPosStrictMono α] _ = _ := by rw [← add_assoc, ← mul_add, ← hcd, mul_zero, zero_add] theorem mul_pos_of_neg_of_neg [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] {a b : α} (ha : a < 0) (hb : b < 0) : 0 < a * b := by simpa only [zero_mul] using mul_lt_mul_of_neg_right ha hb /-- Variant of `mul_lt_of_lt_one_left` for `b` negative instead of positive. -/ theorem lt_mul_of_lt_one_left [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hb : b < 0) (h : a < 1) : b < a * b := by simpa only [one_mul] using mul_lt_mul_of_neg_right h hb /-- Variant of `lt_mul_of_one_lt_left` for `b` negative instead of positive. -/ theorem mul_lt_of_one_lt_left [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hb : b < 0) (h : 1 < a) : a * b < b := by simpa only [one_mul] using mul_lt_mul_of_neg_right h hb /-- Variant of `mul_lt_of_lt_one_right` for `a` negative instead of positive. -/ theorem lt_mul_of_lt_one_right [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (ha : a < 0) (h : b < 1) : a < a * b := by simpa only [mul_one] using mul_lt_mul_of_neg_left h ha /-- Variant of `lt_mul_of_lt_one_right` for `a` negative instead of positive. -/ theorem mul_lt_of_one_lt_right [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (ha : a < 0) (h : 1 < b) : a * b < a := by simpa only [mul_one] using mul_lt_mul_of_neg_left h ha section Monotone -variable [Preorder β] {f g : β → α} +variable [Preorder β] {f : β → α} theorem strictAnti_mul_left [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] {a : α} (ha : a < 0) : StrictAnti (a * ·) := fun _ _ b_lt_c => mul_lt_mul_of_neg_left b_lt_c ha theorem strictAnti_mul_right [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] {a : α} (ha : a < 0) : StrictAnti fun x => x * a := fun _ _ b_lt_c => mul_lt_mul_of_neg_right b_lt_c ha theorem StrictMono.const_mul_of_neg [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hf : StrictMono f) (ha : a < 0) : StrictAnti fun x => a * f x := (strictAnti_mul_left ha).comp_strictMono hf theorem StrictMono.mul_const_of_neg [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hf : StrictMono f) (ha : a < 0) : StrictAnti fun x => f x * a := (strictAnti_mul_right ha).comp_strictMono hf theorem StrictAnti.const_mul_of_neg [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hf : StrictAnti f) (ha : a < 0) : StrictMono fun x => a * f x := (strictAnti_mul_left ha).comp hf theorem StrictAnti.mul_const_of_neg [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] (hf : StrictAnti f) (ha : a < 0) : StrictMono fun x => f x * a := (strictAnti_mul_right ha).comp hf @@ -374,7 +374,7 @@ end Monotone /-- Binary **rearrangement inequality**. -/ lemma mul_add_mul_le_mul_add_mul [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] + [AddLeftMono α] [AddLeftReflectLE α] (hab : a ≤ b) (hcd : c ≤ d) : a * d + b * c ≤ a * c + b * d := by obtain ⟨b, rfl⟩ := exists_add_of_le hab obtain ⟨d, hd, rfl⟩ := exists_nonneg_add_of_le hcd @@ -383,15 +383,15 @@ lemma mul_add_mul_le_mul_add_mul [ExistsAddOfLE α] [MulPosMono α] /-- Binary **rearrangement inequality**. -/ lemma mul_add_mul_le_mul_add_mul' [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] + [AddLeftMono α] [AddLeftReflectLE α] (hba : b ≤ a) (hdc : d ≤ c) : a * d + b * c ≤ a * c + b * d := by rw [add_comm (a * d), add_comm (a * c)]; exact mul_add_mul_le_mul_add_mul hba hdc -variable [ContravariantClass α α (· + ·) (· < ·)] +variable [AddLeftReflectLT α] /-- Binary strict **rearrangement inequality**. -/ lemma mul_add_mul_lt_mul_add_mul [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· < ·)] + [AddLeftStrictMono α] (hab : a < b) (hcd : c < d) : a * d + b * c < a * c + b * d := by obtain ⟨b, rfl⟩ := exists_add_of_le hab.le obtain ⟨d, hd, rfl⟩ := exists_pos_add_of_lt' hcd @@ -400,7 +400,7 @@ lemma mul_add_mul_lt_mul_add_mul [ExistsAddOfLE α] [MulPosStrictMono α] /-- Binary **rearrangement inequality**. -/ lemma mul_add_mul_lt_mul_add_mul' [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· < ·)] + [AddLeftStrictMono α] (hba : b < a) (hdc : d < c) : a * d + b * c < a * c + b * d := by rw [add_comm (a * d), add_comm (a * c)] exact mul_add_mul_lt_mul_add_mul hba hdc @@ -409,7 +409,7 @@ end StrictOrderedSemiring section LinearOrderedSemiring -variable [Semiring α] [LinearOrder α] {a b c d : α} +variable [Semiring α] [LinearOrder α] {a b c : α} theorem nonneg_and_nonneg_or_nonpos_and_nonpos_of_mul_nonneg [MulPosStrictMono α] [PosMulStrictMono α] @@ -449,7 +449,7 @@ theorem mul_nonneg_iff_of_pos_right [MulPosStrictMono α] simpa using (mul_le_mul_right h : 0 * c ≤ b * c ↔ 0 ≤ b) theorem add_le_mul_of_left_le_right [ZeroLEOneClass α] [NeZero (R := α) 1] - [MulPosStrictMono α] [CovariantClass α α (· + ·) (· ≤ ·)] + [MulPosStrictMono α] [AddLeftMono α] (a2 : 2 ≤ a) (ab : a ≤ b) : a + b ≤ a * b := have : 0 < b := calc @@ -463,7 +463,7 @@ theorem add_le_mul_of_left_le_right [ZeroLEOneClass α] [NeZero (R := α) 1] -- Porting note: we used to not need the type annotation on `(0 : α)` at the start of the `calc`. theorem add_le_mul_of_right_le_left [ZeroLEOneClass α] [NeZero (R := α) 1] - [CovariantClass α α (· + ·) (· ≤ ·)] [PosMulStrictMono α] + [AddLeftMono α] [PosMulStrictMono α] (b2 : 2 ≤ b) (ba : b ≤ a) : a + b ≤ a * b := have : 0 < a := calc (0 : α) @@ -476,13 +476,13 @@ theorem add_le_mul_of_right_le_left [ZeroLEOneClass α] [NeZero (R := α) 1] _ ≤ a * b := (mul_le_mul_left this).mpr b2 theorem add_le_mul [ZeroLEOneClass α] [NeZero (R := α) 1] - [MulPosStrictMono α] [PosMulStrictMono α] [CovariantClass α α (· + ·) (· ≤ ·)] + [MulPosStrictMono α] [PosMulStrictMono α] [AddLeftMono α] (a2 : 2 ≤ a) (b2 : 2 ≤ b) : a + b ≤ a * b := if hab : a ≤ b then add_le_mul_of_left_le_right a2 hab else add_le_mul_of_right_le_left b2 (le_of_not_le hab) theorem add_le_mul' [ZeroLEOneClass α] [NeZero (R := α) 1] - [MulPosStrictMono α] [PosMulStrictMono α] [CovariantClass α α (· + ·) (· ≤ ·)] + [MulPosStrictMono α] [PosMulStrictMono α] [AddLeftMono α] (a2 : 2 ≤ a) (b2 : 2 ≤ b) : a + b ≤ b * a := (le_of_eq (add_comm _ _)).trans (add_le_mul b2 a2) @@ -570,20 +570,20 @@ lemma sign_cases_of_C_mul_pow_nonneg [PosMulStrictMono α] simpa only [pow_one] using h 1 theorem mul_pos_iff [ExistsAddOfLE α] [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· < ·)] [ContravariantClass α α (· + ·) (· < ·)] : + [AddLeftStrictMono α] [AddLeftReflectLT α] : 0 < a * b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := ⟨pos_and_pos_or_neg_and_neg_of_mul_pos, fun h => h.elim (and_imp.2 mul_pos) (and_imp.2 mul_pos_of_neg_of_neg)⟩ theorem mul_nonneg_iff [ExistsAddOfLE α] [MulPosStrictMono α] [PosMulStrictMono α] - [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)]: + [AddLeftReflectLE α] [AddLeftMono α]: 0 ≤ a * b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := ⟨nonneg_and_nonneg_or_nonpos_and_nonpos_of_mul_nonneg, fun h => h.elim (and_imp.2 mul_nonneg) (and_imp.2 mul_nonneg_of_nonpos_of_nonpos)⟩ /-- Out of three elements of a `LinearOrderedRing`, two must have the same sign. -/ theorem mul_nonneg_of_three [ExistsAddOfLE α] [MulPosStrictMono α] [PosMulStrictMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] + [AddLeftMono α] [AddLeftReflectLE α] (a b c : α) : 0 ≤ a * b ∨ 0 ≤ b * c ∨ 0 ≤ c * a := by iterate 3 rw [mul_nonneg_iff] have or_a := le_total 0 a @@ -609,7 +609,7 @@ theorem mul_nonneg_of_three [ExistsAddOfLE α] [MulPosStrictMono α] [PosMulStri (fun (h6 : a ≤ 0) => Or.inl (Or.inr ⟨h6, h4⟩)))) lemma mul_nonneg_iff_pos_imp_nonneg [ExistsAddOfLE α] [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] : + [AddLeftMono α] [AddLeftReflectLE α] : 0 ≤ a * b ↔ (0 < a → 0 ≤ b) ∧ (0 < b → 0 ≤ a) := by refine mul_nonneg_iff.trans ?_ simp_rw [← not_le, ← or_iff_not_imp_left] @@ -619,51 +619,51 @@ lemma mul_nonneg_iff_pos_imp_nonneg [ExistsAddOfLE α] [PosMulStrictMono α] [Mu @[simp] theorem mul_le_mul_left_of_neg [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b c : α} (h : c < 0) : c * a ≤ c * b ↔ b ≤ a := (strictAnti_mul_left h).le_iff_le @[simp] theorem mul_le_mul_right_of_neg [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b c : α} (h : c < 0) : a * c ≤ b * c ↔ b ≤ a := (strictAnti_mul_right h).le_iff_le @[simp] theorem mul_lt_mul_left_of_neg [ExistsAddOfLE α] [PosMulStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] {a b c : α} (h : c < 0) : c * a < c * b ↔ b < a := (strictAnti_mul_left h).lt_iff_lt @[simp] theorem mul_lt_mul_right_of_neg [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· < ·)] [ContravariantClass α α (swap (· + ·)) (· < ·)] + [AddRightStrictMono α] [AddRightReflectLT α] {a b c : α} (h : c < 0) : a * c < b * c ↔ b < a := (strictAnti_mul_right h).lt_iff_lt theorem lt_of_mul_lt_mul_of_nonpos_left [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (h : c * a < c * b) (hc : c ≤ 0) : b < a := (antitone_mul_left hc).reflect_lt h theorem lt_of_mul_lt_mul_of_nonpos_right [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (h : a * c < b * c) (hc : c ≤ 0) : b < a := (antitone_mul_right hc).reflect_lt h theorem cmp_mul_neg_left [ExistsAddOfLE α] [PosMulStrictMono α] - [ContravariantClass α α (swap (· + ·)) (· < ·)] [CovariantClass α α (swap (· + ·)) (· < ·)] + [AddRightReflectLT α] [AddRightStrictMono α] {a : α} (ha : a < 0) (b c : α) : cmp (a * b) (a * c) = cmp c b := (strictAnti_mul_left ha).cmp_map_eq b c theorem cmp_mul_neg_right [ExistsAddOfLE α] [MulPosStrictMono α] - [ContravariantClass α α (swap (· + ·)) (· < ·)] [CovariantClass α α (swap (· + ·)) (· < ·)] + [AddRightReflectLT α] [AddRightStrictMono α] {a : α} (ha : a < 0) (b c : α) : cmp (b * a) (c * a) = cmp c b := (strictAnti_mul_right ha).cmp_map_eq b c @[simp] theorem mul_self_pos [ExistsAddOfLE α] [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· < ·)] [ContravariantClass α α (· + ·) (· < ·)] + [AddLeftStrictMono α] [AddLeftReflectLT α] {a : α} : 0 < a * a ↔ a ≠ 0 := by constructor · rintro h rfl @@ -674,37 +674,37 @@ theorem mul_self_pos [ExistsAddOfLE α] [PosMulStrictMono α] [MulPosStrictMono exacts [mul_pos_of_neg_of_neg h h, mul_pos h h] theorem nonneg_of_mul_nonpos_left [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b : α} (h : a * b ≤ 0) (hb : b < 0) : 0 ≤ a := le_of_not_gt fun ha => absurd h (mul_pos_of_neg_of_neg ha hb).not_le theorem nonneg_of_mul_nonpos_right [ExistsAddOfLE α] [MulPosStrictMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b : α} (h : a * b ≤ 0) (ha : a < 0) : 0 ≤ b := le_of_not_gt fun hb => absurd h (mul_pos_of_neg_of_neg ha hb).not_le theorem pos_of_mul_neg_left [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b : α} (h : a * b < 0) (hb : b ≤ 0) : 0 < a := lt_of_not_ge fun ha => absurd h (mul_nonneg_of_nonpos_of_nonpos ha hb).not_lt theorem pos_of_mul_neg_right [ExistsAddOfLE α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] {a b : α} (h : a * b < 0) (ha : a ≤ 0) : 0 < b := lt_of_not_ge fun hb => absurd h (mul_nonneg_of_nonpos_of_nonpos ha hb).not_lt theorem neg_iff_pos_of_mul_neg [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hab : a * b < 0) : a < 0 ↔ 0 < b := ⟨pos_of_mul_neg_right hab ∘ le_of_lt, neg_of_mul_neg_left hab ∘ le_of_lt⟩ theorem pos_iff_neg_of_mul_neg [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] - [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] + [AddRightMono α] [AddRightReflectLE α] (hab : a * b < 0) : 0 < a ↔ b < 0 := ⟨neg_of_mul_neg_right hab ∘ le_of_lt, pos_of_mul_neg_left hab ∘ le_of_lt⟩ lemma sq_nonneg [IsRightCancelAdd α] - [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] [CovariantClass α α (· + ·) (· < ·)] + [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] [AddLeftStrictMono α] (a : α) : 0 ≤ a ^ 2 := by obtain ha | ha := le_total 0 a · exact pow_nonneg ha _ @@ -720,20 +720,20 @@ lemma sq_nonneg [IsRightCancelAdd α] alias pow_two_nonneg := sq_nonneg lemma mul_self_nonneg [IsRightCancelAdd α] - [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] [CovariantClass α α (· + ·) (· < ·)] + [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] [AddLeftStrictMono α] (a : α) : 0 ≤ a * a := by simpa only [sq] using sq_nonneg a /-- The sum of two squares is zero iff both elements are zero. -/ lemma mul_self_add_mul_self_eq_zero [IsRightCancelAdd α] [NoZeroDivisors α] [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· < ·)] : + [AddLeftMono α] [AddLeftStrictMono α] : a * a + b * b = 0 ↔ a = 0 ∧ b = 0 := by rw [add_eq_zero_iff_of_nonneg, mul_self_eq_zero (M₀ := α), mul_self_eq_zero (M₀ := α)] <;> apply mul_self_nonneg lemma eq_zero_of_mul_self_add_mul_self_eq_zero [IsRightCancelAdd α] [NoZeroDivisors α] [ZeroLEOneClass α] [ExistsAddOfLE α] [PosMulMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· < ·)] + [AddLeftMono α] [AddLeftStrictMono α] (h : a * a + b * b = 0) : a = 0 := (mul_self_add_mul_self_eq_zero.mp h).left @@ -741,7 +741,7 @@ end LinearOrderedSemiring section LinearOrderedCommSemiring -variable [CommSemiring α] [LinearOrder α] {a b c d : α} +variable [CommSemiring α] [LinearOrder α] {a d : α} lemma max_mul_mul_le_max_mul_max [PosMulMono α] [MulPosMono α] (b c : α) (ha : 0 ≤ a) (hd : 0 ≤ d) : max (a * b) (d * c) ≤ max a c * max d b := @@ -751,16 +751,29 @@ lemma max_mul_mul_le_max_mul_max [PosMulMono α] [MulPosMono α] (b c : α) (ha mul_le_mul (le_max_right a c) (le_max_right b d) hd (le_trans ha (le_max_left a c)) max_le (by simpa [mul_comm, max_comm] using ba) (by simpa [mul_comm, max_comm] using cd) -/-- Binary **arithmetic mean-geometric mean inequality** (aka AM-GM inequality) for linearly ordered -commutative semirings. -/ +/-- Binary, squared, and division-free **arithmetic mean-geometric mean inequality** +(aka AM-GM inequality) for linearly ordered commutative semirings. -/ lemma two_mul_le_add_sq [ExistsAddOfLE α] [MulPosStrictMono α] - [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)] + [AddLeftReflectLE α] [AddLeftMono α] (a b : α) : 2 * a * b ≤ a ^ 2 + b ^ 2 := by simpa [fn_min_add_fn_max (fun x ↦ x * x), sq, two_mul, add_mul] using mul_add_mul_le_mul_add_mul (@min_le_max _ _ a b) (@min_le_max _ _ a b) alias two_mul_le_add_pow_two := two_mul_le_add_sq +/-- Binary, squared, and division-free **arithmetic mean-geometric mean inequality** +(aka AM-GM inequality) for linearly ordered commutative semirings. -/ +lemma four_mul_le_sq_add [ExistsAddOfLE α] [MulPosStrictMono α] + [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)] + (a b : α) : 4 * a * b ≤ (a + b) ^ 2 := by + calc 4 * a * b + _ = 2 * a * b + 2 * a * b := by rw [mul_assoc, two_add_two_eq_four.symm, add_mul, mul_assoc] + _ ≤ a ^ 2 + b ^ 2 + 2 * a * b := by gcongr; exact two_mul_le_add_sq _ _ + _ = a ^ 2 + 2 * a * b + b ^ 2 := by rw [add_right_comm] + _ = (a + b) ^ 2 := (add_sq a b).symm + +alias four_mul_le_pow_two_add := four_mul_le_sq_add + end LinearOrderedCommSemiring section LinearOrderedRing @@ -771,42 +784,42 @@ variable [Ring α] [LinearOrder α] {a b : α} -- `[Semiring α] [LinearOrder α] [ExistsAddOfLE α] ..`? lemma mul_neg_iff [PosMulStrictMono α] [MulPosStrictMono α] - [ContravariantClass α α (· + ·) (· < ·)] [CovariantClass α α (· + ·) (· < ·)] : + [AddLeftReflectLT α] [AddLeftStrictMono α] : a * b < 0 ↔ 0 < a ∧ b < 0 ∨ a < 0 ∧ 0 < b := by rw [← neg_pos, neg_mul_eq_mul_neg, mul_pos_iff (α := α), neg_pos, neg_lt_zero] lemma mul_nonpos_iff [MulPosStrictMono α] [PosMulStrictMono α] - [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)] : + [AddLeftReflectLE α] [AddLeftMono α] : a * b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b := by rw [← neg_nonneg, neg_mul_eq_mul_neg, mul_nonneg_iff (α := α), neg_nonneg, neg_nonpos] lemma mul_nonneg_iff_neg_imp_nonpos [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] : + [AddLeftMono α] [AddLeftReflectLE α] : 0 ≤ a * b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by rw [← neg_mul_neg, mul_nonneg_iff_pos_imp_nonneg (α := α)]; simp only [neg_pos, neg_nonneg] lemma mul_nonpos_iff_pos_imp_nonpos [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] : + [AddLeftMono α] [AddLeftReflectLE α] : a * b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by rw [← neg_nonneg, ← mul_neg, mul_nonneg_iff_pos_imp_nonneg (α := α)] simp only [neg_pos, neg_nonneg] lemma mul_nonpos_iff_neg_imp_nonneg [PosMulStrictMono α] [MulPosStrictMono α] - [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] : + [AddLeftMono α] [AddLeftReflectLE α] : a * b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by rw [← neg_nonneg, ← neg_mul, mul_nonneg_iff_pos_imp_nonneg (α := α)] simp only [neg_pos, neg_nonneg] lemma neg_one_lt_zero - [ZeroLEOneClass α] [NeZero (R := α) 1] [CovariantClass α α (· + ·) (· < ·)] : + [ZeroLEOneClass α] [NeZero (R := α) 1] [AddLeftStrictMono α] : -1 < (0 : α) := neg_lt_zero.2 zero_lt_one lemma sub_one_lt [ZeroLEOneClass α] [NeZero (R := α) 1] - [CovariantClass α α (· + ·) (· < ·)] + [AddLeftStrictMono α] (a : α) : a - 1 < a := sub_lt_iff_lt_add.2 <| lt_add_one a lemma mul_self_le_mul_self_of_le_of_neg_le - [MulPosMono α] [PosMulMono α] [CovariantClass α α (· + ·) (· ≤ ·)] + [MulPosMono α] [PosMulMono α] [AddLeftMono α] (h₁ : a ≤ b) (h₂ : -a ≤ b) : a * a ≤ b * b := (le_total 0 a).elim (mul_self_le_mul_self · h₁) fun h ↦ (neg_mul_neg a a).symm.trans_le <| diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Nonneg.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Nonneg.lean index af0b158eae60c..1993a125516c0 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Nonneg.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Nonneg.lean @@ -98,32 +98,30 @@ theorem mk_eq_zero [Zero α] [Preorder α] {x : α} (hx : 0 ≤ x) : (⟨x, hx⟩ : { x : α // 0 ≤ x }) = 0 ↔ x = 0 := Subtype.ext_iff -instance add [AddZeroClass α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] : - Add { x : α // 0 ≤ x } := +instance add [AddZeroClass α] [Preorder α] [AddLeftMono α] : Add { x : α // 0 ≤ x } := ⟨fun x y => ⟨x + y, add_nonneg x.2 y.2⟩⟩ @[simp] -theorem mk_add_mk [AddZeroClass α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] {x y : α} +theorem mk_add_mk [AddZeroClass α] [Preorder α] [AddLeftMono α] {x y : α} (hx : 0 ≤ x) (hy : 0 ≤ y) : (⟨x, hx⟩ : { x : α // 0 ≤ x }) + ⟨y, hy⟩ = ⟨x + y, add_nonneg hx hy⟩ := rfl @[simp, norm_cast] -protected theorem coe_add [AddZeroClass α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] +protected theorem coe_add [AddZeroClass α] [Preorder α] [AddLeftMono α] (a b : { x : α // 0 ≤ x }) : ((a + b : { x : α // 0 ≤ x }) : α) = a + b := rfl -instance nsmul [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] : - SMul ℕ { x : α // 0 ≤ x } := +instance nsmul [AddMonoid α] [Preorder α] [AddLeftMono α] : SMul ℕ { x : α // 0 ≤ x } := ⟨fun n x => ⟨n • (x : α), nsmul_nonneg x.prop n⟩⟩ @[simp] -theorem nsmul_mk [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] (n : ℕ) {x : α} +theorem nsmul_mk [AddMonoid α] [Preorder α] [AddLeftMono α] (n : ℕ) {x : α} (hx : 0 ≤ x) : (n • (⟨x, hx⟩ : { x : α // 0 ≤ x })) = ⟨n • x, nsmul_nonneg hx n⟩ := rfl @[simp, norm_cast] -protected theorem coe_nsmul [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] +protected theorem coe_nsmul [AddMonoid α] [Preorder α] [AddLeftMono α] (n : ℕ) (a : { x : α // 0 ≤ x }) : ((n • a : { x : α // 0 ≤ x }) : α) = n • (a : α) := rfl @@ -166,7 +164,7 @@ end Mul section AddMonoid -variable [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] +variable [AddMonoid α] [Preorder α] [AddLeftMono α] instance addMonoid : AddMonoid { x : α // 0 ≤ x } := Subtype.coe_injective.addMonoid _ Nonneg.coe_zero (fun _ _ => rfl) fun _ _ => rfl @@ -186,7 +184,7 @@ end AddMonoid section AddCommMonoid -variable [AddCommMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] +variable [AddCommMonoid α] [Preorder α] [AddLeftMono α] instance addCommMonoid : AddCommMonoid { x : α // 0 ≤ x } := Subtype.coe_injective.addCommMonoid _ Nonneg.coe_zero (fun _ _ => rfl) (fun _ _ => rfl) @@ -195,8 +193,7 @@ end AddCommMonoid section AddMonoidWithOne -variable [AddMonoidWithOne α] [PartialOrder α] -variable [CovariantClass α α (· + ·) (· ≤ ·)] [ZeroLEOneClass α] +variable [AddMonoidWithOne α] [PartialOrder α] [AddLeftMono α] [ZeroLEOneClass α] instance natCast : NatCast { x : α // 0 ≤ x } := ⟨fun n => ⟨n, Nat.cast_nonneg' n⟩⟩ @@ -254,7 +251,7 @@ end Pow section Semiring variable [Semiring α] [PartialOrder α] [ZeroLEOneClass α] - [CovariantClass α α (· + ·) (· ≤ ·)] [PosMulMono α] + [AddLeftMono α] [PosMulMono α] instance semiring : Semiring { x : α // 0 ≤ x } := Subtype.coe_injective.semiring _ Nonneg.coe_zero Nonneg.coe_one @@ -273,17 +270,10 @@ def coeRingHom : { x : α // 0 ≤ x } →+* α := end Semiring -section Nontrivial - -variable [Semiring α] [PartialOrder α] [ZeroLEOneClass α] [NeZero 1] - [CovariantClass α α (· + ·) (· ≤ ·)] [PosMulMono α] - -end Nontrivial - section CommSemiring variable [CommSemiring α] [PartialOrder α] [ZeroLEOneClass α] - [CovariantClass α α (· + ·) (· ≤ ·)] [PosMulMono α] + [AddLeftMono α] [PosMulMono α] instance commSemiring : CommSemiring { x : α // 0 ≤ x } := Subtype.coe_injective.commSemiring _ Nonneg.coe_zero Nonneg.coe_one diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean index b2ad2a602b376..4ad83938866b6 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean @@ -29,7 +29,7 @@ assert_not_exists GaloisConnection namespace Rat -variable {a b c p q : ℚ} +variable {a b p q : ℚ} @[simp] lemma divInt_nonneg_iff_of_pos_right {a b : ℤ} (hb : 0 < b) : 0 ≤ a /. b ↔ 0 ≤ a := by cases' hab : a /. b with n d hd hnd @@ -191,7 +191,7 @@ protected lemma lt_def : p < q ↔ p.num * q.den < q.num * p.den := by protected theorem add_le_add_left {a b c : ℚ} : c + a ≤ c + b ↔ a ≤ b := by rw [Rat.le_iff_sub_nonneg, add_sub_add_left_eq_sub, ← Rat.le_iff_sub_nonneg] -instance : CovariantClass ℚ ℚ (· + ·) (· ≤ ·) where +instance : AddLeftMono ℚ where elim := fun _ _ _ h => Rat.add_le_add_left.2 h @[simp] lemma num_nonpos {a : ℚ} : a.num ≤ 0 ↔ a ≤ 0 := by diff --git a/Mathlib/Algebra/Order/Star/Basic.lean b/Mathlib/Algebra/Order/Star/Basic.lean index b07145ac25911..42f4b5b776602 100644 --- a/Mathlib/Algebra/Order/Star/Basic.lean +++ b/Mathlib/Algebra/Order/Star/Basic.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.NoZeroSMulDivisors.Defs +import Mathlib.Algebra.Order.Group.Defs +import Mathlib.Algebra.Order.Group.Nat import Mathlib.Algebra.Star.SelfAdjoint import Mathlib.Algebra.Star.StarRingHom -import Mathlib.Algebra.Regular.Basic import Mathlib.Tactic.ContinuousFunctionalCalculus /-! # Star ordered rings @@ -96,10 +98,10 @@ lemma of_le_iff [NonUnitalSemiring R] [PartialOrder R] [StarRing R] exact ⟨star p * p, AddSubmonoid.subset_closure ⟨p, rfl⟩, hp⟩ · rintro ⟨p, hp, hpxy⟩ revert x y hpxy - refine AddSubmonoid.closure_induction hp ?_ (fun x y h => add_zero x ▸ h.ge) ?_ + refine AddSubmonoid.closure_induction ?_ (fun x y h => add_zero x ▸ h.ge) ?_ hp · rintro _ ⟨s, rfl⟩ x y rfl exact (h_le_iff _ _).mpr ⟨s, rfl⟩ - · rintro a b ha hb x y rfl + · rintro _ _ _ _ ha hb x y rfl rw [← add_assoc] exact (ha _ _ rfl).trans (hb _ _ rfl) @@ -111,7 +113,7 @@ lemma of_nonneg_iff [NonUnitalRing R] [PartialOrder R] [StarRing R] (h_nonneg_iff : ∀ x : R, 0 ≤ x ↔ x ∈ AddSubmonoid.closure (Set.range fun s : R => star s * s)) : StarOrderedRing R where le_iff x y := by - haveI : CovariantClass R R (· + ·) (· ≤ ·) := ⟨fun _ _ _ h => h_add h _⟩ + have : AddLeftMono R := ⟨fun _ _ _ h => h_add h _⟩ simpa only [← sub_eq_iff_eq_add', sub_nonneg, exists_eq_right'] using h_nonneg_iff (y - x) /-- When `R` is a non-unital ring, to construct a `StarOrderedRing` instance it suffices to @@ -125,7 +127,7 @@ lemma of_nonneg_iff' [NonUnitalRing R] [PartialOrder R] [StarRing R] (h_add : ∀ {x y : R}, x ≤ y → ∀ z, z + x ≤ z + y) (h_nonneg_iff : ∀ x : R, 0 ≤ x ↔ ∃ s, x = star s * s) : StarOrderedRing R := of_le_iff <| by - haveI : CovariantClass R R (· + ·) (· ≤ ·) := ⟨fun _ _ _ h => h_add h _⟩ + have : AddLeftMono R := ⟨fun _ _ _ h => h_add h _⟩ simpa [sub_eq_iff_eq_add', sub_nonneg] using fun x y => h_nonneg_iff (y - x) theorem nonneg_iff [NonUnitalSemiring R] [PartialOrder R] [StarRing R] [StarOrderedRing R] {x : R} : @@ -160,8 +162,8 @@ theorem mul_star_self_nonneg (r : R) : 0 ≤ r * star r := by @[aesop safe apply] theorem conjugate_nonneg {a : R} (ha : 0 ≤ a) (c : R) : 0 ≤ star c * a * c := by rw [StarOrderedRing.nonneg_iff] at ha - refine AddSubmonoid.closure_induction ha (fun x hx => ?_) - (by rw [mul_zero, zero_mul]) fun x y hx hy => ?_ + refine AddSubmonoid.closure_induction (fun x hx => ?_) + (by rw [mul_zero, zero_mul]) (fun x y _ _ hx hy => ?_) ha · obtain ⟨x, rfl⟩ := hx convert star_mul_self_nonneg (x * c) using 1 rw [star_mul, ← mul_assoc, mul_assoc _ _ c] @@ -302,12 +304,12 @@ lemma StarModule.smul_lt_smul_of_pos {a b : A} {c : R} (hab : a < b) (hc : 0 < c case le => have hab := le_of_lt hab rw [StarOrderedRing.nonneg_iff] at hab ⊢ - refine AddSubmonoid.closure_induction hab ?mem ?zero ?add + refine AddSubmonoid.closure_induction ?mem ?zero ?add hab case mem => intro x hx have hc := le_of_lt hc rw [StarOrderedRing.nonneg_iff] at hc - refine AddSubmonoid.closure_induction hc ?memc ?zeroc ?addc + refine AddSubmonoid.closure_induction ?memc ?zeroc ?addc hc case memc => intro c' hc' obtain ⟨z, hz⟩ := hc' @@ -316,9 +318,9 @@ lemma StarModule.smul_lt_smul_of_pos {a b : A} {c : R} (hab : a < b) (hc : 0 < c refine ⟨z • y, ?_⟩ simp only [star_smul, smul_mul_smul_comm, hz, hy] case zeroc => simpa only [zero_smul] using zero_mem _ - case addc => exact fun c' d ↦ by simpa only [add_smul] using add_mem + case addc => exact fun c' d _ _ ↦ by simpa only [add_smul] using add_mem case zero => simpa only [smul_zero] using zero_mem _ - case add => exact fun x y ↦ by simpa only [smul_add] using add_mem + case add => exact fun x y _ _ ↦ by simpa only [smul_add] using add_mem case ne => refine (smul_ne_zero ?_ ?_).symm · exact (ne_of_lt hc).symm @@ -339,7 +341,7 @@ lemma NonUnitalStarRingHom.map_le_map_of_map_star (f : R →⋆ₙ+* S) {x y : R obtain ⟨p, hp, rfl⟩ := hxy refine ⟨f p, ?_, map_add f _ _⟩ have hf : ∀ r, f (star r) = star (f r) := map_star _ - induction hp using AddSubmonoid.closure_induction' + induction hp using AddSubmonoid.closure_induction all_goals aesop instance (priority := 100) StarRingHomClass.instOrderHomClass [FunLike F R S] diff --git a/Mathlib/Algebra/Order/Star/Prod.lean b/Mathlib/Algebra/Order/Star/Prod.lean new file mode 100644 index 0000000000000..f2375c7d57a81 --- /dev/null +++ b/Mathlib/Algebra/Order/Star/Prod.lean @@ -0,0 +1,30 @@ +/- +Copyright (c) 2024 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Algebra.Order.Star.Basic +import Mathlib.Algebra.Star.Prod +import Mathlib.Algebra.Ring.Prod + +/-! +# Products of star-ordered rings +-/ + +variable {α β : Type*} + +open AddSubmonoid in +instance Prod.instStarOrderedRing + [NonUnitalSemiring α] [NonUnitalSemiring β] [PartialOrder α] [PartialOrder β] + [StarRing α] [StarRing β] [StarOrderedRing α] [StarOrderedRing β] : + StarOrderedRing (α × β) where + le_iff := Prod.forall.2 fun xa xy => Prod.forall.2 fun ya yb => by + have : + closure (Set.range fun s : α × β ↦ star s * s) = + (closure <| Set.range fun s : α ↦ star s * s).prod + (closure <| Set.range fun s : β ↦ star s * s) := by + rw [← closure_prod (Set.mem_range.2 ⟨0, by simp⟩) (Set.mem_range.2 ⟨0, by simp⟩), + Set.prod_range_range_eq] + simp_rw [Prod.mul_def, Prod.star_def] + simp only [mk_le_mk, Prod.exists, mk_add_mk, mk.injEq, StarOrderedRing.le_iff, this, + AddSubmonoid.mem_prod, exists_and_exists_comm, and_and_and_comm] diff --git a/Mathlib/Algebra/Order/Sub/Basic.lean b/Mathlib/Algebra/Order/Sub/Basic.lean index 79046c54164c0..2bab771de332d 100644 --- a/Mathlib/Algebra/Order/Sub/Basic.lean +++ b/Mathlib/Algebra/Order/Sub/Basic.lean @@ -16,7 +16,7 @@ variable {α : Type*} section CanonicallyOrderedAddCommMonoid -variable [CanonicallyOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} +variable [CanonicallyOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c : α} theorem add_tsub_cancel_iff_le : a + (b - a) = b ↔ a ≤ b := ⟨fun h => le_iff_exists_add.mpr ⟨b - a, h.symm⟩, add_tsub_cancel_of_le⟩ @@ -32,8 +32,6 @@ theorem tsub_eq_zero_iff_le : a - b = 0 ↔ a ≤ b := by alias ⟨_, tsub_eq_zero_of_le⟩ := tsub_eq_zero_iff_le -attribute [simp] tsub_eq_zero_of_le - theorem tsub_self (a : α) : a - a = 0 := tsub_eq_zero_of_le le_rfl @@ -76,7 +74,7 @@ end AddLECancellable section Contra -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] theorem tsub_le_tsub_iff_left (h : c ≤ a) : a - b ≤ a - c ↔ c ≤ b := Contravariant.AddLECancellable.tsub_le_tsub_iff_left Contravariant.AddLECancellable h @@ -105,7 +103,7 @@ end CanonicallyOrderedAddCommMonoid section CanonicallyLinearOrderedAddCommMonoid -variable [CanonicallyLinearOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} +variable [CanonicallyLinearOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c : α} @[simp] theorem tsub_pos_iff_lt : 0 < a - b ↔ b < a := by rw [tsub_pos_iff_not_le, not_le] @@ -147,7 +145,7 @@ end AddLECancellable section Contra -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] /-- This lemma also holds for `ENNReal`, but we need a different proof for that. -/ theorem tsub_lt_tsub_iff_right (h : c ≤ a) : a - c < b - c ↔ a < b := @@ -188,8 +186,7 @@ theorem tsub_add_min : a - b + min a b = a := by apply min_le_left -- `Odd.tsub` requires `CanonicallyLinearOrderedSemiring`, which we don't have -lemma Even.tsub - [ContravariantClass α α (· + ·) (· ≤ ·)] {m n : α} (hm : Even m) (hn : Even n) : +lemma Even.tsub [AddLeftReflectLE α] {m n : α} (hm : Even m) (hn : Even n) : Even (m - n) := by obtain ⟨a, rfl⟩ := hm obtain ⟨b, rfl⟩ := hn diff --git a/Mathlib/Algebra/Order/Sub/Defs.lean b/Mathlib/Algebra/Order/Sub/Defs.lean index 9966239cd270f..e4c6643431795 100644 --- a/Mathlib/Algebra/Order/Sub/Defs.lean +++ b/Mathlib/Algebra/Order/Sub/Defs.lean @@ -30,7 +30,7 @@ implications if a bi-implication can be proven under the same assumptions. Lemmas using this class are named using `tsub` instead of `sub` (short for "truncated subtraction"). This is to avoid naming conflicts with similar lemmas about ordered groups. -We provide a second version of most results that require `[ContravariantClass α α (+) (≤)]`. In the +We provide a second version of most results that require `[AddLeftReflectLE α]`. In the second version we replace this type-class assumption by explicit `AddLECancellable` assumptions. TODO: maybe we should make a multiplicative version of this, so that we can replace some identical @@ -62,7 +62,7 @@ theorem tsub_le_iff_right [LE α] [Add α] [Sub α] [OrderedSub α] {a b c : α} variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b : α} -/-- See `add_tsub_cancel_right` for the equality if `ContravariantClass α α (+) (≤)`. -/ +/-- See `add_tsub_cancel_right` for the equality if `AddLeftReflectLE α`. -/ theorem add_tsub_le_right : a + b - b ≤ a := tsub_le_iff_right.mpr le_rfl @@ -90,7 +90,7 @@ theorem tsub_le_iff_left : a - b ≤ c ↔ a ≤ b + c := by rw [tsub_le_iff_rig theorem le_add_tsub : a ≤ b + (a - b) := tsub_le_iff_left.mp le_rfl -/-- See `add_tsub_cancel_left` for the equality if `ContravariantClass α α (+) (≤)`. -/ +/-- See `add_tsub_cancel_left` for the equality if `AddLeftReflectLE α`. -/ theorem add_tsub_le_left : a + b - a ≤ b := tsub_le_iff_left.mpr le_rfl @@ -105,7 +105,7 @@ theorem tsub_tsub_le : b - (b - a) ≤ a := section Cov -variable [CovariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftMono α] @[gcongr] theorem tsub_le_tsub_left (h : a ≤ b) (c : α) : c - b ≤ c - a := tsub_le_iff_left.mpr <| le_add_tsub.trans <| add_le_add_right h _ @@ -192,7 +192,7 @@ end AddLECancellable section Contra -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] theorem le_add_tsub_swap : a ≤ b + a - b := Contravariant.AddLECancellable.le_add_tsub_swap @@ -252,7 +252,7 @@ protected theorem tsub_eq_of_eq_add (hb : AddLECancellable b) (h : a = c + b) : /-- Weaker version of `AddLECancellable.tsub_eq_of_eq_add` assuming that `a = c + b` itself is cancellable rather than `b`. -/ -protected lemma tsub_eq_of_eq_add' [CovariantClass α α (· + ·) (· ≤ ·)] (ha : AddLECancellable a) +protected lemma tsub_eq_of_eq_add' [AddLeftMono α] (ha : AddLECancellable a) (h : a = c + b) : a - b = c := (h ▸ ha).of_add_right.tsub_eq_of_eq_add h /-- See `AddLECancellable.eq_tsub_of_add_eq'` for a version assuming that `b = a + c` itself is @@ -262,7 +262,7 @@ protected theorem eq_tsub_of_add_eq (hc : AddLECancellable c) (h : a + c = b) : /-- Weaker version of `AddLECancellable.eq_tsub_of_add_eq` assuming that `b = a + c` itself is cancellable rather than `c`. -/ -protected lemma eq_tsub_of_add_eq' [CovariantClass α α (· + ·) (· ≤ ·)] (hb : AddLECancellable b) +protected lemma eq_tsub_of_add_eq' [AddLeftMono α] (hb : AddLECancellable b) (h : a + c = b) : a = b - c := (hb.tsub_eq_of_eq_add' h.symm).symm /-- See `AddLECancellable.tsub_eq_of_eq_add_rev'` for a version assuming that `a = b + c` itself is @@ -272,7 +272,7 @@ protected theorem tsub_eq_of_eq_add_rev (hb : AddLECancellable b) (h : a = b + c /-- Weaker version of `AddLECancellable.tsub_eq_of_eq_add_rev` assuming that `a = b + c` itself is cancellable rather than `b`. -/ -protected lemma tsub_eq_of_eq_add_rev' [CovariantClass α α (· + ·) (· ≤ ·)] +protected lemma tsub_eq_of_eq_add_rev' [AddLeftMono α] (ha : AddLECancellable a) (h : a = b + c) : a - b = c := ha.tsub_eq_of_eq_add' <| by rw [add_comm, h] @@ -312,7 +312,7 @@ end AddLECancellable section Contra -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] theorem tsub_eq_of_eq_add (h : a = c + b) : a - b = c := Contravariant.AddLECancellable.tsub_eq_of_eq_add h @@ -355,7 +355,7 @@ end Contra section Both -variable [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftMono α] [AddLeftReflectLE α] theorem add_tsub_add_eq_tsub_right (a c b : α) : a + c - (b + c) = a - b := by refine add_tsub_add_le_tsub_right.antisymm (tsub_le_iff_right.2 <| ?_) @@ -394,7 +394,7 @@ theorem lt_tsub_comm : a < b - c ↔ c < b - a := section Cov -variable [CovariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftMono α] /-- See `lt_of_tsub_lt_tsub_left_of_le` for a weaker statement in a partial order. -/ theorem lt_of_tsub_lt_tsub_left (h : a - b < a - c) : c < b := diff --git a/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean index 979e4903eb48f..899776822e162 100644 --- a/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean @@ -18,7 +18,7 @@ variable {α : Type*} section ExistsAddOfLE variable [AddCommSemigroup α] [PartialOrder α] [ExistsAddOfLE α] - [CovariantClass α α (· + ·) (· ≤ ·)] [Sub α] [OrderedSub α] {a b c d : α} + [AddLeftMono α] [Sub α] [OrderedSub α] {a b c d : α} @[simp] theorem add_tsub_cancel_of_le (h : a ≤ b) : a + (b - a) = b := by @@ -130,7 +130,7 @@ protected theorem tsub_inj_right (hab : AddLECancellable (a - b)) (h₁ : b ≤ rw [← hab.inj] rw [tsub_add_cancel_of_le h₁, h₃, tsub_add_cancel_of_le h₂] -protected theorem lt_of_tsub_lt_tsub_left_of_le [ContravariantClass α α (· + ·) (· < ·)] +protected theorem lt_of_tsub_lt_tsub_left_of_le [AddLeftReflectLT α] (hb : AddLECancellable b) (hca : c ≤ a) (h : a - b < a - c) : c < b := by conv_lhs at h => rw [← tsub_add_cancel_of_le hca] exact lt_of_add_lt_add_left (hb.lt_add_of_tsub_lt_right h) @@ -144,7 +144,7 @@ protected theorem tsub_lt_tsub_right_of_le (hc : AddLECancellable c) (h : c ≤ apply hc.lt_tsub_of_add_lt_left rwa [add_tsub_cancel_of_le h] -protected theorem tsub_lt_tsub_iff_left_of_le_of_le [ContravariantClass α α (· + ·) (· < ·)] +protected theorem tsub_lt_tsub_iff_left_of_le_of_le [AddLeftReflectLT α] (hb : AddLECancellable b) (hab : AddLECancellable (a - b)) (h₁ : b ≤ a) (h₂ : c ≤ a) : a - b < a - c ↔ c < b := ⟨hb.lt_of_tsub_lt_tsub_left_of_le h₂, hab.tsub_lt_tsub_left_of_le h₁⟩ @@ -168,7 +168,7 @@ section Contra /-! ### Lemmas where addition is order-reflecting. -/ -variable [ContravariantClass α α (· + ·) (· ≤ ·)] +variable [AddLeftReflectLE α] theorem eq_tsub_iff_add_eq_of_le (h : c ≤ b) : a = b - c ↔ a + c = b := Contravariant.AddLECancellable.eq_tsub_iff_add_eq_of_le h @@ -216,7 +216,7 @@ theorem lt_tsub_iff_left_of_le (h : c ≤ b) : a < b - c ↔ c + a < b := Contravariant.AddLECancellable.lt_tsub_iff_left_of_le h /-- See `lt_of_tsub_lt_tsub_left` for a stronger statement in a linear order. -/ -theorem lt_of_tsub_lt_tsub_left_of_le [ContravariantClass α α (· + ·) (· < ·)] (hca : c ≤ a) +theorem lt_of_tsub_lt_tsub_left_of_le [AddLeftReflectLT α] (hca : c ≤ a) (h : a - b < a - c) : c < b := Contravariant.AddLECancellable.lt_of_tsub_lt_tsub_left_of_le hca h @@ -230,7 +230,7 @@ theorem tsub_inj_right (h₁ : b ≤ a) (h₂ : c ≤ a) (h₃ : a - b = a - c) Contravariant.AddLECancellable.tsub_inj_right h₁ h₂ h₃ /-- See `tsub_lt_tsub_iff_left_of_le` for a stronger statement in a linear order. -/ -theorem tsub_lt_tsub_iff_left_of_le_of_le [ContravariantClass α α (· + ·) (· < ·)] (h₁ : b ≤ a) +theorem tsub_lt_tsub_iff_left_of_le_of_le [AddLeftReflectLT α] (h₁ : b ≤ a) (h₂ : c ≤ a) : a - b < a - c ↔ c < b := Contravariant.AddLECancellable.tsub_lt_tsub_iff_left_of_le_of_le Contravariant.AddLECancellable h₁ h₂ diff --git a/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean b/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean index fedfe17b0c39c..6d9cedb09fb7c 100644 --- a/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean +++ b/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean @@ -24,11 +24,11 @@ theorem AddHom.le_map_tsub [Preorder β] [Add β] [Sub β] [OrderedSub β] (f : exact hf le_tsub_add theorem le_mul_tsub {R : Type*} [Distrib R] [Preorder R] [Sub R] [OrderedSub R] - [CovariantClass R R (· * ·) (· ≤ ·)] {a b c : R} : a * b - a * c ≤ a * (b - c) := + [MulLeftMono R] {a b c : R} : a * b - a * c ≤ a * (b - c) := (AddHom.mulLeft a).le_map_tsub (monotone_id.const_mul' a) _ _ theorem le_tsub_mul {R : Type*} [CommSemiring R] [Preorder R] [Sub R] [OrderedSub R] - [CovariantClass R R (· * ·) (· ≤ ·)] {a b c : R} : a * c - b * c ≤ (a - b) * c := by + [MulLeftMono R] {a b c : R} : a * c - b * c ≤ (a - b) * c := by simpa only [mul_comm _ c] using le_mul_tsub end Add diff --git a/Mathlib/Algebra/Order/SuccPred.lean b/Mathlib/Algebra/Order/SuccPred.lean index 9ef68870ecd16..185ea8250d6f9 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.Basic +import Mathlib.Order.SuccPred.Archimedean /-! # Interaction between successors and arithmetic @@ -183,3 +183,73 @@ theorem lt_one_iff_nonpos [AddMonoidWithOne α] [ZeroLEOneClass α] [NeZero (1 : end LinearOrder end Order + +section Monotone +variable {α β : Type*} [PartialOrder α] [Preorder β] + +section SuccAddOrder +variable [Add α] [One α] [SuccAddOrder α] [IsSuccArchimedean α] {s : Set α} {f : α → β} + +lemma monotoneOn_of_le_add_one (hs : s.OrdConnected) : + (∀ a, ¬ IsMax a → a ∈ s → a + 1 ∈ s → f a ≤ f (a + 1)) → MonotoneOn f s := by + simpa [Order.succ_eq_add_one] using monotoneOn_of_le_succ hs (f := f) + +lemma antitoneOn_of_add_one_le (hs : s.OrdConnected) : + (∀ a, ¬ IsMax a → a ∈ s → a + 1 ∈ s → f (a + 1) ≤ f a) → AntitoneOn f s := by + simpa [Order.succ_eq_add_one] using antitoneOn_of_succ_le hs (f := f) + +lemma strictMonoOn_of_lt_add_one (hs : s.OrdConnected) : + (∀ a, ¬ IsMax a → a ∈ s → a + 1 ∈ s → f a < f (a + 1)) → StrictMonoOn f s := by + simpa [Order.succ_eq_add_one] using strictMonoOn_of_lt_succ hs (f := f) + +lemma strictAntiOn_of_add_one_lt (hs : s.OrdConnected) : + (∀ a, ¬ IsMax a → a ∈ s → a + 1 ∈ s → f (a + 1) < f a) → StrictAntiOn f s := by + simpa [Order.succ_eq_add_one] using strictAntiOn_of_succ_lt hs (f := f) + +lemma monotone_of_le_add_one : (∀ a, ¬ IsMax a → f a ≤ f (a + 1)) → Monotone f := by + simpa [Order.succ_eq_add_one] using monotone_of_le_succ (f := f) + +lemma antitone_of_add_one_le : (∀ a, ¬ IsMax a → f (a + 1) ≤ f a) → Antitone f := by + simpa [Order.succ_eq_add_one] using antitone_of_succ_le (f := f) + +lemma strictMono_of_lt_add_one : (∀ a, ¬ IsMax a → f a < f (a + 1)) → StrictMono f := by + simpa [Order.succ_eq_add_one] using strictMono_of_lt_succ (f := f) + +lemma strictAnti_of_add_one_lt : (∀ a, ¬ IsMax a → f (a + 1) < f a) → StrictAnti f := by + simpa [Order.succ_eq_add_one] using strictAnti_of_succ_lt (f := f) + +end SuccAddOrder + +section PredSubOrder +variable [Sub α] [One α] [PredSubOrder α] [IsPredArchimedean α] {s : Set α} {f : α → β} + +lemma monotoneOn_of_sub_one_le (hs : s.OrdConnected) : + (∀ a, ¬ IsMin a → a ∈ s → a - 1 ∈ s → f (a - 1) ≤ f a) → MonotoneOn f s := by + simpa [Order.pred_eq_sub_one] using monotoneOn_of_pred_le hs (f := f) + +lemma antitoneOn_of_le_sub_one (hs : s.OrdConnected) : + (∀ a, ¬ IsMin a → a ∈ s → a - 1 ∈ s → f a ≤ f (a - 1)) → AntitoneOn f s := by + simpa [Order.pred_eq_sub_one] using antitoneOn_of_le_pred hs (f := f) + +lemma strictMonoOn_of_sub_one_lt (hs : s.OrdConnected) : + (∀ a, ¬ IsMin a → a ∈ s → a - 1 ∈ s → f (a - 1) < f a) → StrictMonoOn f s := by + simpa [Order.pred_eq_sub_one] using strictMonoOn_of_pred_lt hs (f := f) + +lemma strictAntiOn_of_lt_sub_one (hs : s.OrdConnected) : + (∀ a, ¬ IsMin a → a ∈ s → a - 1 ∈ s → f a < f (a - 1)) → StrictAntiOn f s := by + simpa [Order.pred_eq_sub_one] using strictAntiOn_of_lt_pred hs (f := f) + +lemma monotone_of_sub_one_le : (∀ a, ¬ IsMin a → f (a - 1) ≤ f a) → Monotone f := by + simpa [Order.pred_eq_sub_one] using monotone_of_pred_le (f := f) + +lemma antitone_of_le_sub_one : (∀ a, ¬ IsMin a → f a ≤ f (a - 1)) → Antitone f := by + simpa [Order.pred_eq_sub_one] using antitone_of_le_pred (f := f) + +lemma strictMono_of_sub_one_lt : (∀ a, ¬ IsMin a → f (a - 1) < f a) → StrictMono f := by + simpa [Order.pred_eq_sub_one] using strictMono_of_pred_lt (f := f) + +lemma strictAnti_of_lt_sub_one : (∀ a, ¬ IsMin a → f a < f (a - 1)) → StrictAnti f := by + simpa [Order.pred_eq_sub_one] using strictAnti_of_lt_pred (f := f) + +end PredSubOrder +end Monotone diff --git a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean index 4293cd851694a..7c69e6dc40162 100644 --- a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean +++ b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean @@ -3,8 +3,8 @@ Copyright (c) 2024 Yakov Pechersky. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yakov Pechersky -/ -import Mathlib.Algebra.Order.Monoid.TypeTags import Mathlib.Order.SuccPred.Archimedean +import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags /-! # Successor and predecessor on type tags diff --git a/Mathlib/Algebra/Order/ToIntervalMod.lean b/Mathlib/Algebra/Order/ToIntervalMod.lean index 260764b5fe69c..0080b14e43fd5 100644 --- a/Mathlib/Algebra/Order/ToIntervalMod.lean +++ b/Mathlib/Algebra/Order/ToIntervalMod.lean @@ -760,7 +760,7 @@ private theorem toIxxMod_total' (a b c : α) : Thus if a ≠ b and b ≠ c then ({a-b} + {b-c}) + ({c-b} + {b-a}) = 2 * period, so one of `{a-b} + {b-c}` and `{c-b} + {b-a}` must be `≤ period` -/ have := congr_arg₂ (· + ·) (toIcoMod_add_toIocMod_zero hp a b) (toIcoMod_add_toIocMod_zero hp c b) - simp only [add_add_add_comm] at this -- Porting note (#10691): Was `rw` + simp only [add_add_add_comm] at this rw [_root_.add_comm (toIocMod _ _ _), add_add_add_comm, ← two_nsmul] at this replace := min_le_of_add_le_two_nsmul this.le rw [min_le_iff] at this diff --git a/Mathlib/Algebra/PUnitInstances/Algebra.lean b/Mathlib/Algebra/PUnitInstances/Algebra.lean index a9860604f2c27..8a9c98a4aebdc 100644 --- a/Mathlib/Algebra/PUnitInstances/Algebra.lean +++ b/Mathlib/Algebra/PUnitInstances/Algebra.lean @@ -3,7 +3,7 @@ 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.GCDMonoid.Basic +import Mathlib.Algebra.Ring.Basic /-! # Instances on PUnit @@ -64,33 +64,4 @@ instance commRing : CommRing PUnit where instance cancelCommMonoidWithZero : CancelCommMonoidWithZero PUnit where --- This is too high-powered and should be split off also -instance normalizedGCDMonoid : NormalizedGCDMonoid PUnit where - gcd _ _ := unit - lcm _ _ := unit - normUnit _ := 1 - normUnit_zero := rfl - normUnit_mul := by intros; rfl - normUnit_coe_units := by intros; rfl - gcd_dvd_left _ _ := ⟨unit, by subsingleton⟩ - gcd_dvd_right _ _ := ⟨unit, by subsingleton⟩ - dvd_gcd {_ _} _ _ _ := ⟨unit, by subsingleton⟩ - gcd_mul_lcm _ _ := ⟨1, by subsingleton⟩ - lcm_zero_left := by intros; rfl - lcm_zero_right := by intros; rfl - normalize_gcd := by intros; rfl - normalize_lcm := by intros; rfl - --- Porting note (#10618): simpNF lint: simp can prove this @[simp] -theorem gcd_eq {x y : PUnit} : gcd x y = unit := - rfl - --- Porting note (#10618): simpNF lint: simp can prove this @[simp] -theorem lcm_eq {x y : PUnit} : lcm x y = unit := - rfl - -@[simp] -theorem norm_unit_eq {x : PUnit} : normUnit x = 1 := - rfl - end PUnit diff --git a/Mathlib/Algebra/PUnitInstances/GCDMonoid.lean b/Mathlib/Algebra/PUnitInstances/GCDMonoid.lean new file mode 100644 index 0000000000000..3609ecaa55b47 --- /dev/null +++ b/Mathlib/Algebra/PUnitInstances/GCDMonoid.lean @@ -0,0 +1,47 @@ +/- +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.GCDMonoid.Basic +import Mathlib.Algebra.PUnitInstances.Algebra + +/-! +# Instances on PUnit + +This file collects facts about algebraic structures on the one-element type, e.g. that it is a +commutative ring. +-/ + +namespace PUnit + +-- This is too high-powered and should be split off also +instance normalizedGCDMonoid : NormalizedGCDMonoid PUnit where + gcd _ _ := unit + lcm _ _ := unit + normUnit _ := 1 + normUnit_zero := rfl + normUnit_mul := by intros; rfl + normUnit_coe_units := by intros; rfl + gcd_dvd_left _ _ := ⟨unit, by subsingleton⟩ + gcd_dvd_right _ _ := ⟨unit, by subsingleton⟩ + dvd_gcd {_ _} _ _ _ := ⟨unit, by subsingleton⟩ + gcd_mul_lcm _ _ := ⟨1, by subsingleton⟩ + lcm_zero_left := by intros; rfl + lcm_zero_right := by intros; rfl + normalize_gcd := by intros; rfl + normalize_lcm := by intros; rfl + +@[simp] +theorem gcd_eq {x y : PUnit} : gcd x y = unit := + rfl + +@[simp] +theorem lcm_eq {x y : PUnit} : lcm x y = unit := + rfl + +@[simp] +theorem norm_unit_eq {x : PUnit} : normUnit x = 1 := + rfl + +end PUnit diff --git a/Mathlib/Algebra/Periodic.lean b/Mathlib/Algebra/Periodic.lean index 995e7e734029d..1225d22fde07c 100644 --- a/Mathlib/Algebra/Periodic.lean +++ b/Mathlib/Algebra/Periodic.lean @@ -6,8 +6,9 @@ Authors: Benjamin Davidson import Mathlib.Algebra.Field.Opposite import Mathlib.Algebra.Group.Subgroup.ZPowers import Mathlib.Algebra.Group.Submonoid.Membership -import Mathlib.Algebra.Ring.NegOnePow +import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Order.Archimedean.Basic +import Mathlib.Algebra.Ring.NegOnePow import Mathlib.GroupTheory.Coset.Card /-! diff --git a/Mathlib/Algebra/Pointwise/Stabilizer.lean b/Mathlib/Algebra/Pointwise/Stabilizer.lean index de0ffac8e167c..0596f27478672 100644 --- a/Mathlib/Algebra/Pointwise/Stabilizer.lean +++ b/Mathlib/Algebra/Pointwise/Stabilizer.lean @@ -4,7 +4,7 @@ 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.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Stabilizer of a set under a pointwise action @@ -74,7 +74,7 @@ lemma stabilizer_subgroup (s : Subgroup G) : stabilizer G (s : Set G) = s := by @[to_additive (attr := simp)] lemma stabilizer_op_subgroup (s : Subgroup G) : stabilizer Gᵐᵒᵖ (s : Set G) = s.op := by simp_rw [SetLike.ext_iff, mem_stabilizer_set] - simp? says simp only [smul_eq_mul_unop, SetLike.mem_coe, Subgroup.mem_op] + simp only [smul_eq_mul_unop, SetLike.mem_coe, Subgroup.mem_op, «forall», unop_op] refine fun a ↦ ⟨fun h ↦ ?_, fun ha b ↦ s.mul_mem_cancel_right ha⟩ simpa only [op_smul_eq_mul, SetLike.mem_coe, one_mul] using (h 1).2 s.one_mem diff --git a/Mathlib/Algebra/Polynomial/AlgebraMap.lean b/Mathlib/Algebra/Polynomial/AlgebraMap.lean index 5928ff633fda6..8b2599a1e1c97 100644 --- a/Mathlib/Algebra/Polynomial/AlgebraMap.lean +++ b/Mathlib/Algebra/Polynomial/AlgebraMap.lean @@ -294,12 +294,32 @@ def algEquivOfCompEqX (p q : R[X]) (hpq : p.comp q = X) (hqp : q.comp p = X) : R refine AlgEquiv.ofAlgHom (aeval p) (aeval q) ?_ ?_ <;> exact AlgHom.ext fun _ ↦ by simp [← comp_eq_aeval, comp_assoc, hpq, hqp] +@[simp] +theorem algEquivOfCompEqX_eq_iff (p q p' q' : R[X]) + (hpq : p.comp q = X) (hqp : q.comp p = X) (hpq' : p'.comp q' = X) (hqp' : q'.comp p' = X) : + algEquivOfCompEqX p q hpq hqp = algEquivOfCompEqX p' q' hpq' hqp' ↔ p = p' := + ⟨fun h ↦ by simpa using congr($h X), fun h ↦ by ext1; simp [h]⟩ + +@[simp] +theorem algEquivOfCompEqX_symm (p q : R[X]) (hpq : p.comp q = X) (hqp : q.comp p = X) : + (algEquivOfCompEqX p q hpq hqp).symm = algEquivOfCompEqX q p hqp hpq := rfl + /-- The automorphism of the polynomial algebra given by `p(X) ↦ p(X+t)`, with inverse `p(X) ↦ p(X-t)`. -/ @[simps!] def algEquivAevalXAddC {R} [CommRing R] (t : R) : R[X] ≃ₐ[R] R[X] := algEquivOfCompEqX (X + C t) (X - C t) (by simp) (by simp) +@[simp] +theorem algEquivAevalXAddC_eq_iff {R} [CommRing R] (t t' : R) : + algEquivAevalXAddC t = algEquivAevalXAddC t' ↔ t = t' := by + simp [algEquivAevalXAddC] + +@[simp] +theorem algEquivAevalXAddC_symm {R} [CommRing R] (t : R) : + (algEquivAevalXAddC t).symm = algEquivAevalXAddC (-t) := by + simp [algEquivAevalXAddC, sub_eq_add_neg] + theorem aeval_algHom (f : A →ₐ[R] B) (x : A) : aeval (f x) = f.comp (aeval x) := algHom_ext <| by simp only [aeval_X, AlgHom.comp_apply] @@ -527,15 +547,44 @@ theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by simp [coeff_monomial] theorem not_isUnit_X_sub_C [Nontrivial R] (r : R) : ¬IsUnit (X - C r) := - fun ⟨⟨_, g, _hfg, hgf⟩, rfl⟩ => zero_ne_one' R <| by erw [← eval_mul_X_sub_C, hgf, eval_one] + fun ⟨⟨_, g, _hfg, hgf⟩, rfl⟩ => zero_ne_one' R <| by rw [← eval_mul_X_sub_C, hgf, eval_one] end Ring -theorem aeval_endomorphism {M : Type*} [CommRing R] [AddCommGroup M] [Module R M] (f : M →ₗ[R] M) +section CommRing +variable [CommRing R] {p : R[X]} {t : R} + +theorem aeval_endomorphism {M : Type*} [AddCommGroup M] [Module R M] (f : M →ₗ[R] M) (v : M) (p : R[X]) : aeval f p v = p.sum fun n b => b • (f ^ n) v := by rw [aeval_def, eval₂_eq_sum] exact map_sum (LinearMap.applyₗ v) _ _ +lemma X_sub_C_pow_dvd_iff {n : ℕ} : (X - C t) ^ n ∣ p ↔ X ^ n ∣ p.comp (X + C t) := by + convert (map_dvd_iff <| algEquivAevalXAddC t).symm using 2 + simp [C_eq_algebraMap] + +lemma comp_X_add_C_eq_zero_iff : p.comp (X + C t) = 0 ↔ p = 0 := + AddEquivClass.map_eq_zero_iff (algEquivAevalXAddC t) + +lemma comp_X_add_C_ne_zero_iff : p.comp (X + C t) ≠ 0 ↔ p ≠ 0 := comp_X_add_C_eq_zero_iff.not + +lemma dvd_comp_X_sub_C_iff (p q : R[X]) (a : R) : + p ∣ q.comp (X - C a) ↔ p.comp (X + C a) ∣ q := by + convert (map_dvd_iff <| algEquivAevalXAddC a).symm using 2 + rw [C_eq_algebraMap, algEquivAevalXAddC_apply, ← comp_eq_aeval] + simp [comp_assoc] + +lemma dvd_comp_X_add_C_iff (p q : R[X]) (a : R) : + p ∣ q.comp (X + C a) ↔ p.comp (X - C a) ∣ q := by + simpa using dvd_comp_X_sub_C_iff p q (-a) + +variable [IsDomain R] + +lemma units_coeff_zero_smul (c : R[X]ˣ) (p : R[X]) : (c : R[X]).coeff 0 • p = c * p := by + rw [← Polynomial.C_mul', ← Polynomial.eq_C_of_degree_eq_zero (degree_coe_units c)] + +end CommRing + section StableSubmodule variable {M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] @@ -561,4 +610,55 @@ lemma aeval_apply_smul_mem_of_le_comap end StableSubmodule +section CommSemiring + +variable [CommSemiring R] {a p : R[X]} + +theorem eq_zero_of_mul_eq_zero_of_smul (P : R[X]) (h : ∀ r : R, r • P = 0 → r = 0) : + ∀ (Q : R[X]), P * Q = 0 → Q = 0 := by + intro Q hQ + suffices ∀ i, P.coeff i • Q = 0 by + rw [← leadingCoeff_eq_zero] + apply h + simpa [ext_iff, mul_comm Q.leadingCoeff] using fun i ↦ congr_arg (·.coeff Q.natDegree) (this i) + apply Nat.strong_decreasing_induction + · use P.natDegree + intro i hi + rw [coeff_eq_zero_of_natDegree_lt hi, zero_smul] + intro l IH + obtain _|hl := (natDegree_smul_le (P.coeff l) Q).lt_or_eq + · apply eq_zero_of_mul_eq_zero_of_smul _ h (P.coeff l • Q) + rw [smul_eq_C_mul, mul_left_comm, hQ, mul_zero] + suffices P.coeff l * Q.leadingCoeff = 0 by + rwa [← leadingCoeff_eq_zero, ← coeff_natDegree, coeff_smul, hl, coeff_natDegree, smul_eq_mul] + let m := Q.natDegree + suffices (P * Q).coeff (l + m) = P.coeff l * Q.leadingCoeff by rw [← this, hQ, coeff_zero] + rw [coeff_mul] + apply Finset.sum_eq_single (l, m) _ (by simp) + simp only [Finset.mem_antidiagonal, ne_eq, Prod.forall, Prod.mk.injEq, not_and] + intro i j hij H + obtain hi|rfl|hi := lt_trichotomy i l + · have hj : m < j := by omega + rw [coeff_eq_zero_of_natDegree_lt hj, mul_zero] + · omega + · rw [← coeff_C_mul, ← smul_eq_C_mul, IH _ hi, coeff_zero] +termination_by Q => Q.natDegree + +open nonZeroDivisors in +/-- *McCoy theorem*: a polynomial `P : R[X]` is a zerodivisor if and only if there is `a : R` +such that `a ≠ 0` and `a • P = 0`. -/ +theorem nmem_nonZeroDivisors_iff {P : R[X]} : P ∉ R[X]⁰ ↔ ∃ a : R, a ≠ 0 ∧ a • P = 0 := by + refine ⟨fun hP ↦ ?_, fun ⟨a, ha, h⟩ h1 ↦ ha <| C_eq_zero.1 <| (h1 _) <| smul_eq_C_mul a ▸ h⟩ + by_contra! h + obtain ⟨Q, hQ⟩ := _root_.nmem_nonZeroDivisors_iff.1 hP + refine hQ.2 (eq_zero_of_mul_eq_zero_of_smul P (fun a ha ↦ ?_) Q (mul_comm P _ ▸ hQ.1)) + contrapose! ha + exact h a ha + +open nonZeroDivisors in +protected lemma mem_nonZeroDivisors_iff {P : R[X]} : P ∈ R[X]⁰ ↔ ∀ a : R, a • P = 0 → a = 0 := by + simpa [not_imp_not] using (nmem_nonZeroDivisors_iff (P := P)).not + +end CommSemiring + end Polynomial diff --git a/Mathlib/Algebra/Polynomial/Basic.lean b/Mathlib/Algebra/Polynomial/Basic.lean index b1d85a96da4bd..57f4bba5519be 100644 --- a/Mathlib/Algebra/Polynomial/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Basic.lean @@ -60,7 +60,7 @@ structure Polynomial (R : Type*) [Semiring R] where ofFinsupp :: @[inherit_doc] scoped[Polynomial] notation:9000 R "[X]" => Polynomial R -open AddMonoidAlgebra +open AddMonoidAlgebra Finset open Finsupp hiding single open Function hiding Commute @@ -361,7 +361,7 @@ theorem support_eq_empty : p.support = ∅ ↔ p = 0 := by @[simp] lemma support_nonempty : p.support.Nonempty ↔ p ≠ 0 := Finset.nonempty_iff_ne_empty.trans support_eq_empty.not -theorem card_support_eq_zero : p.support.card = 0 ↔ p = 0 := by simp +theorem card_support_eq_zero : #p.support = 0 ↔ p = 0 := by simp /-- `monomial s a` is the monomial `a * X^s` -/ def monomial (n : ℕ) : R →ₗ[R] R[X] where @@ -379,7 +379,7 @@ theorem toFinsupp_monomial (n : ℕ) (r : R) : (monomial n r).toFinsupp = Finsup theorem ofFinsupp_single (n : ℕ) (r : R) : (⟨Finsupp.single n r⟩ : R[X]) = monomial n r := by simp [monomial] --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem monomial_zero_right (n : ℕ) : monomial n (0 : R) = 0 := (monomial n).map_zero @@ -455,7 +455,6 @@ theorem smul_C {S} [SMulZeroClass S R] (s : S) (r : R) : s • C r = C (s • r) theorem C_pow : C (a ^ n) = C a ^ n := C.map_pow a n --- @[simp] -- Porting note (#10618): simp can prove this theorem C_eq_natCast (n : ℕ) : C (n : R) = (n : R[X]) := map_natCast C n @@ -1028,7 +1027,7 @@ theorem coeff_sub (p q : R[X]) (n : ℕ) : coeff (p - q) n = coeff p n - coeff q -- Porting note: The last rule should be `apply`ed. rw [← ofFinsupp_sub, coeff, coeff, coeff]; apply Finsupp.sub_apply --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem monomial_neg (n : ℕ) (a : R) : monomial n (-a) = -monomial n a := by rw [eq_neg_iff_add_eq_zero, ← monomial_add, neg_add_cancel, monomial_zero_right] diff --git a/Mathlib/Algebra/Polynomial/BigOperators.lean b/Mathlib/Algebra/Polynomial/BigOperators.lean index cef12c507490a..557f139b15527 100644 --- a/Mathlib/Algebra/Polynomial/BigOperators.lean +++ b/Mathlib/Algebra/Polynomial/BigOperators.lean @@ -193,17 +193,28 @@ theorem natDegree_multiset_prod_of_monic (h : ∀ f ∈ t, Monic f) : assumption · simp +theorem degree_multiset_prod_of_monic [Nontrivial R] (h : ∀ f ∈ t, Monic f) : + t.prod.degree = (t.map degree).sum := by + have : t.prod ≠ 0 := Monic.ne_zero <| by simpa using monic_multiset_prod_of_monic _ _ h + rw [degree_eq_natDegree this, natDegree_multiset_prod_of_monic _ h, Nat.cast_multiset_sum, + Multiset.map_map, Function.comp_def, + Multiset.map_congr rfl (fun f hf => (degree_eq_natDegree (h f hf).ne_zero).symm)] + theorem natDegree_prod_of_monic (h : ∀ i ∈ s, (f i).Monic) : (∏ i ∈ s, f i).natDegree = ∑ i ∈ s, (f i).natDegree := by simpa using natDegree_multiset_prod_of_monic (s.1.map f) (by simpa using h) +theorem degree_prod_of_monic [Nontrivial R] (h : ∀ i ∈ s, (f i).Monic) : + (∏ i ∈ s, f i).degree = ∑ i ∈ s, (f i).degree := by + simpa using degree_multiset_prod_of_monic (s.1.map f) (by simpa using h) + theorem coeff_multiset_prod_of_natDegree_le (n : ℕ) (hl : ∀ p ∈ t, natDegree p ≤ n) : coeff t.prod ((Multiset.card t) * n) = (t.map fun p => coeff p n).prod := by induction t using Quotient.inductionOn simpa using coeff_list_prod_of_natDegree_le _ _ hl theorem coeff_prod_of_natDegree_le (f : ι → R[X]) (n : ℕ) (h : ∀ p ∈ s, natDegree (f p) ≤ n) : - coeff (∏ i ∈ s, f i) (s.card * n) = ∏ i ∈ s, coeff (f i) n := by + coeff (∏ i ∈ s, f i) (#s * n) = ∏ i ∈ s, coeff (f i) n := by cases' s with l hl convert coeff_multiset_prod_of_natDegree_le (l.map f) n ?_ · simp @@ -255,10 +266,20 @@ theorem multiset_prod_X_sub_C_coeff_card_pred (t : Multiset R) (ht : 0 < Multise exact fun h => one_ne_zero <| h 1 ⟨_, ⟨x, hx, rfl⟩, natDegree_X_sub_C _⟩ congr; rw [natDegree_multiset_prod_of_monic] <;> · simp [natDegree_X_sub_C, monic_X_sub_C] -theorem prod_X_sub_C_coeff_card_pred (s : Finset ι) (f : ι → R) (hs : 0 < s.card) : - (∏ i ∈ s, (X - C (f i))).coeff (s.card - 1) = -∑ i ∈ s, f i := by +theorem prod_X_sub_C_coeff_card_pred (s : Finset ι) (f : ι → R) (hs : 0 < #s) : + (∏ i ∈ s, (X - C (f i))).coeff (#s - 1) = -∑ i ∈ s, f i := by simpa using multiset_prod_X_sub_C_coeff_card_pred (s.1.map f) (by simpa using hs) +variable [IsDomain R] + +@[simp] +lemma natDegree_multiset_prod_X_sub_C_eq_card (s : Multiset R) : + (s.map (X - C ·)).prod.natDegree = Multiset.card s := by + rw [natDegree_multiset_prod_of_monic, Multiset.map_map] + · simp only [(· ∘ ·), natDegree_X_sub_C, Multiset.map_const', Multiset.sum_replicate, smul_eq_mul, + mul_one] + · exact Multiset.forall_mem_map_iff.2 fun a _ => monic_X_sub_C a + end CommRing section NoZeroDivisors diff --git a/Mathlib/Algebra/Polynomial/Coeff.lean b/Mathlib/Algebra/Polynomial/Coeff.lean index a0550adae74d1..383ce0d93d741 100644 --- a/Mathlib/Algebra/Polynomial/Coeff.lean +++ b/Mathlib/Algebra/Polynomial/Coeff.lean @@ -55,12 +55,12 @@ theorem support_smul [SMulZeroClass S R] (r : S) (p : R[X]) : simp [hi] open scoped Pointwise in -theorem card_support_mul_le : (p * q).support.card ≤ p.support.card * q.support.card := by - calc (p * q).support.card - _ = (p.toFinsupp * q.toFinsupp).support.card := by rw [← support_toFinsupp, toFinsupp_mul] - _ ≤ (p.toFinsupp.support + q.toFinsupp.support).card := +theorem card_support_mul_le : #(p * q).support ≤ #p.support * #q.support := by + calc #(p * q).support + _ = #(p.toFinsupp * q.toFinsupp).support := by rw [← support_toFinsupp, toFinsupp_mul] + _ ≤ #(p.toFinsupp.support + q.toFinsupp.support) := Finset.card_le_card (AddMonoidAlgebra.support_mul p.toFinsupp q.toFinsupp) - _ ≤ p.support.card * q.support.card := Finset.card_image₂_le .. + _ ≤ #p.support * #q.support := Finset.card_image₂_le .. /-- `Polynomial.sum` as a linear map. -/ @[simps] @@ -104,7 +104,6 @@ lemma coeff_list_sum_map {ι : Type*} (l : List ι) (f : ι → R[X]) (n : ℕ) 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 ⟨⟩ - -- porting note (#10745): was `simp [Polynomial.sum, support, coeff]`. simp [Polynomial.sum, support_ofFinsupp, coeff_ofFinsupp] /-- Decomposes the coefficient of the product `p * q` as a sum @@ -213,11 +212,11 @@ theorem support_trinomial {k m n : ℕ} (hkm : k < m) (hmn : m < n) {x y z : R} zero_add, Ne, hx, hy, hz, not_false_eq_true, and_true] theorem card_support_binomial {k m : ℕ} (h : k ≠ m) {x y : R} (hx : x ≠ 0) (hy : y ≠ 0) : - card (support (C x * X ^ k + C y * X ^ m)) = 2 := by + #(support (C x * X ^ k + C y * X ^ m)) = 2 := by rw [support_binomial h hx hy, card_insert_of_not_mem (mt mem_singleton.mp h), card_singleton] theorem card_support_trinomial {k m n : ℕ} (hkm : k < m) (hmn : m < n) {x y z : R} (hx : x ≠ 0) - (hy : y ≠ 0) (hz : z ≠ 0) : card (support (C x * X ^ k + C y * X ^ m + C z * X ^ n)) = 3 := by + (hy : y ≠ 0) (hz : z ≠ 0) : #(support (C x * X ^ k + C y * X ^ m + C z * X ^ n)) = 3 := by rw [support_trinomial hkm hmn hx hy hz, card_insert_of_not_mem (mt mem_insert.mp (not_or_intro hkm.ne (mt mem_singleton.mp (hkm.trans hmn).ne))), @@ -347,7 +346,7 @@ theorem natCast_coeff_zero {n : ℕ} {R : Type*} [Semiring R] : (n : R[X]).coeff @[deprecated (since := "2024-04-17")] alias nat_cast_coeff_zero := natCast_coeff_zero -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem natCast_inj {m n : ℕ} {R : Type*} [Semiring R] [CharZero R] : (↑m : R[X]) = ↑n ↔ m = n := by constructor @@ -367,7 +366,7 @@ theorem intCast_coeff_zero {i : ℤ} {R : Type*} [Ring R] : (i : R[X]).coeff 0 = @[deprecated (since := "2024-04-17")] alias int_cast_coeff_zero := intCast_coeff_zero -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem intCast_inj {m n : ℤ} {R : Type*} [Ring R] [CharZero R] : (↑m : R[X]) = ↑n ↔ m = n := by constructor · intro h diff --git a/Mathlib/Algebra/Polynomial/Degree/Definitions.lean b/Mathlib/Algebra/Polynomial/Degree/Definitions.lean index 3a3fe3f22832f..e5cc71815055f 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Definitions.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Definitions.lean @@ -414,11 +414,11 @@ theorem natDegree_X_le : (X : R[X]).natDegree ≤ 1 := theorem mem_support_C_mul_X_pow {n a : ℕ} {c : R} (h : a ∈ support (C c * X ^ n)) : a = n := mem_singleton.1 <| support_C_mul_X_pow' n c h -theorem card_support_C_mul_X_pow_le_one {c : R} {n : ℕ} : card (support (C c * X ^ n)) ≤ 1 := by +theorem card_support_C_mul_X_pow_le_one {c : R} {n : ℕ} : #(support (C c * X ^ n)) ≤ 1 := by rw [← card_singleton n] apply card_le_card (support_C_mul_X_pow' n c) -theorem card_supp_le_succ_natDegree (p : R[X]) : p.support.card ≤ p.natDegree + 1 := by +theorem card_supp_le_succ_natDegree (p : R[X]) : #p.support ≤ p.natDegree + 1 := by rw [← Finset.card_range (p.natDegree + 1)] exact Finset.card_le_card supp_subset_range_natDegree_succ @@ -758,11 +758,9 @@ theorem leadingCoeff_C_mul_X (a : R) : leadingCoeff (C a * X) = a := by theorem leadingCoeff_C (a : R) : leadingCoeff (C a) = a := leadingCoeff_monomial a 0 --- @[simp] -- Porting note (#10618): simp can prove this theorem leadingCoeff_X_pow (n : ℕ) : leadingCoeff ((X : R[X]) ^ n) = 1 := by simpa only [C_1, one_mul] using leadingCoeff_C_mul_X_pow (1 : R) n --- @[simp] -- Porting note (#10618): simp can prove this theorem leadingCoeff_X : leadingCoeff (X : R[X]) = 1 := by simpa only [pow_one] using @leadingCoeff_X_pow R _ 1 @@ -774,7 +772,6 @@ theorem monic_X_pow (n : ℕ) : Monic (X ^ n : R[X]) := theorem monic_X : Monic (X : R[X]) := leadingCoeff_X --- @[simp] -- Porting note (#10618): simp can prove this theorem leadingCoeff_one : leadingCoeff (1 : R[X]) = 1 := leadingCoeff_C 1 @@ -888,13 +885,13 @@ theorem leadingCoeff_mul' (h : leadingCoeff p * leadingCoeff q ≠ 0) : rw [natDegree_mul' h, coeff_mul_degree_add_degree] rfl -theorem monomial_natDegree_leadingCoeff_eq_self (h : p.support.card ≤ 1) : +theorem monomial_natDegree_leadingCoeff_eq_self (h : #p.support ≤ 1) : monomial p.natDegree p.leadingCoeff = p := by classical rcases card_support_le_one_iff_monomial.1 h with ⟨n, a, rfl⟩ by_cases ha : a = 0 <;> simp [ha] -theorem C_mul_X_pow_eq_self (h : p.support.card ≤ 1) : C p.leadingCoeff * X ^ p.natDegree = p := by +theorem C_mul_X_pow_eq_self (h : #p.support ≤ 1) : C p.leadingCoeff * X ^ p.natDegree = p := by rw [C_mul_X_pow_eq_monomial, monomial_natDegree_leadingCoeff_eq_self h] theorem leadingCoeff_pow' : leadingCoeff p ^ n ≠ 0 → leadingCoeff (p ^ n) = leadingCoeff p ^ n := @@ -1370,8 +1367,188 @@ theorem leadingCoeff_pow_X_add_C (r : R) (i : ℕ) : leadingCoeff ((X + C r) ^ i nontriviality rw [leadingCoeff_pow'] <;> simp +variable [NoZeroDivisors R] {p q : R[X]} + +@[simp] +lemma degree_mul : degree (p * q) = degree p + degree q := + letI := Classical.decEq R + if hp0 : p = 0 then by simp only [hp0, degree_zero, zero_mul, WithBot.bot_add] + else + if hq0 : q = 0 then by simp only [hq0, degree_zero, mul_zero, WithBot.add_bot] + else degree_mul' <| mul_ne_zero (mt leadingCoeff_eq_zero.1 hp0) (mt leadingCoeff_eq_zero.1 hq0) + +/-- `degree` as a monoid homomorphism between `R[X]` and `Multiplicative (WithBot ℕ)`. + This is useful to prove results about multiplication and degree. -/ +def degreeMonoidHom [Nontrivial R] : R[X] →* Multiplicative (WithBot ℕ) where + toFun := degree + map_one' := degree_one + map_mul' _ _ := degree_mul + +@[simp] +lemma degree_pow [Nontrivial R] (p : R[X]) (n : ℕ) : degree (p ^ n) = n • degree p := + map_pow (@degreeMonoidHom R _ _ _) _ _ + +@[simp] +lemma leadingCoeff_mul (p q : R[X]) : leadingCoeff (p * q) = leadingCoeff p * leadingCoeff q := by + by_cases hp : p = 0 + · simp only [hp, zero_mul, leadingCoeff_zero] + · by_cases hq : q = 0 + · simp only [hq, mul_zero, leadingCoeff_zero] + · rw [leadingCoeff_mul'] + exact mul_ne_zero (mt leadingCoeff_eq_zero.1 hp) (mt leadingCoeff_eq_zero.1 hq) + +/-- `Polynomial.leadingCoeff` bundled as a `MonoidHom` when `R` has `NoZeroDivisors`, and thus + `leadingCoeff` is multiplicative -/ +def leadingCoeffHom : R[X] →* R where + toFun := leadingCoeff + map_one' := by simp + map_mul' := leadingCoeff_mul + +@[simp] +lemma leadingCoeffHom_apply (p : R[X]) : leadingCoeffHom p = leadingCoeff p := + rfl + +@[simp] +lemma leadingCoeff_pow (p : R[X]) (n : ℕ) : leadingCoeff (p ^ n) = leadingCoeff p ^ n := + (leadingCoeffHom : R[X] →* R).map_pow p n + +lemma leadingCoeff_dvd_leadingCoeff {a p : R[X]} (hap : a ∣ p) : + a.leadingCoeff ∣ p.leadingCoeff := + map_dvd leadingCoeffHom hap + +instance : NoZeroDivisors R[X] where + eq_zero_or_eq_zero_of_mul_eq_zero h := by + rw [← leadingCoeff_eq_zero, ← leadingCoeff_eq_zero] + refine eq_zero_or_eq_zero_of_mul_eq_zero ?_ + rw [← leadingCoeff_zero, ← leadingCoeff_mul, h] +lemma natDegree_mul (hp : p ≠ 0) (hq : q ≠ 0) : (p*q).natDegree = p.natDegree + q.natDegree := by + 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] + +@[simp] +lemma natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by + classical + obtain rfl | hp := eq_or_ne p 0 + · obtain rfl | hn := eq_or_ne n 0 <;> simp [*] + exact natDegree_pow' <| by + rw [← leadingCoeff_pow, Ne, leadingCoeff_eq_zero]; exact pow_ne_zero _ hp + +lemma degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by + classical + obtain rfl | hp := eq_or_ne p 0 + · simp + · rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq] + exact WithBot.coe_le_coe.2 (Nat.le_add_right _ _) + +lemma natDegree_le_of_dvd (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by + obtain ⟨q, rfl⟩ := h1 + rw [mul_ne_zero_iff] at h2 + rw [natDegree_mul h2.1 h2.2]; exact Nat.le_add_right _ _ + +lemma degree_le_of_dvd (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by + rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2 + exact degree_le_mul_left p h2.2 + +lemma eq_zero_of_dvd_of_degree_lt (h₁ : p ∣ q) (h₂ : degree q < degree p) : q = 0 := by + by_contra hc + exact (lt_iff_not_ge _ _).mp h₂ (degree_le_of_dvd h₁ hc) + +lemma eq_zero_of_dvd_of_natDegree_lt (h₁ : p ∣ q) (h₂ : natDegree q < natDegree p) : + q = 0 := by + by_contra hc + exact (lt_iff_not_ge _ _).mp h₂ (natDegree_le_of_dvd h₁ hc) + +lemma not_dvd_of_degree_lt (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q := by + by_contra hcontra + exact h0 (eq_zero_of_dvd_of_degree_lt hcontra hl) + +lemma not_dvd_of_natDegree_lt (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) : + ¬p ∣ q := by + by_contra hcontra + exact h0 (eq_zero_of_dvd_of_natDegree_lt hcontra hl) + +/-- This lemma is useful for working with the `intDegree` of a rational function. -/ +lemma natDegree_sub_eq_of_prod_eq {p₁ p₂ q₁ q₂ : R[X]} (hp₁ : p₁ ≠ 0) (hq₁ : q₁ ≠ 0) + (hp₂ : p₂ ≠ 0) (hq₂ : q₂ ≠ 0) (h_eq : p₁ * q₂ = p₂ * q₁) : + (p₁.natDegree : ℤ) - q₁.natDegree = (p₂.natDegree : ℤ) - q₂.natDegree := by + rw [sub_eq_sub_iff_add_eq_add] + norm_cast + rw [← natDegree_mul hp₁ hq₂, ← natDegree_mul hp₂ hq₁, h_eq] + +lemma natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by + nontriviality R + obtain ⟨q, hq⟩ := h.exists_right_inv + have := natDegree_mul (left_ne_zero_of_mul_eq_one hq) (right_ne_zero_of_mul_eq_one hq) + rw [hq, natDegree_one, eq_comm, add_eq_zero] at this + exact this.1 + +lemma degree_eq_zero_of_isUnit [Nontrivial R] (h : IsUnit p) : degree p = 0 := + (natDegree_eq_zero_iff_degree_le_zero.mp <| natDegree_eq_zero_of_isUnit h).antisymm + (zero_le_degree_iff.mpr h.ne_zero) + +@[simp] +lemma degree_coe_units [Nontrivial R] (u : R[X]ˣ) : degree (u : R[X]) = 0 := + degree_eq_zero_of_isUnit ⟨u, rfl⟩ + +/-- Characterization of a unit of a polynomial ring over an integral domain `R`. +See `Polynomial.isUnit_iff_coeff_isUnit_isNilpotent` when `R` is a commutative ring. -/ +lemma isUnit_iff : IsUnit p ↔ ∃ r : R, IsUnit r ∧ C r = p := + ⟨fun hp => + ⟨p.coeff 0, + let h := eq_C_of_natDegree_eq_zero (natDegree_eq_zero_of_isUnit hp) + ⟨isUnit_C.1 (h ▸ hp), h.symm⟩⟩, + fun ⟨_, hr, hrp⟩ => hrp ▸ isUnit_C.2 hr⟩ + +lemma not_isUnit_of_degree_pos (p : R[X]) (hpl : 0 < p.degree) : ¬ IsUnit p := by + cases subsingleton_or_nontrivial R + · simp [Subsingleton.elim p 0] at hpl + intro h + simp [degree_eq_zero_of_isUnit h] at hpl + +lemma not_isUnit_of_natDegree_pos (p : R[X]) (hpl : 0 < p.natDegree) : ¬ IsUnit p := + not_isUnit_of_degree_pos _ (natDegree_pos_iff_degree_pos.mp hpl) + +@[simp] lemma natDegree_coe_units (u : R[X]ˣ) : natDegree (u : R[X]) = 0 := by + nontriviality R + exact natDegree_eq_of_degree_eq_some (degree_coe_units u) + +theorem coeff_coe_units_zero_ne_zero [Nontrivial R] (u : R[X]ˣ) : coeff (u : R[X]) 0 ≠ 0 := by + conv in 0 => rw [← natDegree_coe_units u] + rw [← leadingCoeff, Ne, leadingCoeff_eq_zero] + exact Units.ne_zero _ + end Semiring +section CommSemiring +variable [CommSemiring R] {a p : R[X]} (hp : p.Monic) +include hp + +lemma Monic.C_dvd_iff_isUnit {a : R} : C a ∣ p ↔ IsUnit a where + mp h := isUnit_iff_dvd_one.mpr <| hp.coeff_natDegree ▸ (C_dvd_iff_dvd_coeff _ _).mp h p.natDegree + mpr ha := (ha.map C).dvd + +lemma Monic.natDegree_pos : 0 < natDegree p ↔ p ≠ 1 := + Nat.pos_iff_ne_zero.trans hp.natDegree_eq_zero.not + +lemma Monic.degree_pos : 0 < degree p ↔ p ≠ 1 := + natDegree_pos_iff_degree_pos.symm.trans hp.natDegree_pos + +lemma Monic.degree_pos_of_not_isUnit (hu : ¬IsUnit p) : 0 < degree p := + hp.degree_pos.mpr fun hp' ↦ (hp' ▸ hu) isUnit_one + +lemma Monic.natDegree_pos_of_not_isUnit (hu : ¬IsUnit p) : 0 < natDegree p := + hp.natDegree_pos.mpr fun hp' ↦ (hp' ▸ hu) isUnit_one + +lemma degree_pos_of_not_isUnit_of_dvd_monic (ha : ¬IsUnit a) (hap : a ∣ p) : 0 < degree a := by + contrapose! ha with h + rw [Polynomial.eq_C_of_degree_le_zero h] at hap ⊢ + simpa [hp.C_dvd_iff_isUnit, isUnit_C] using hap + +lemma natDegree_pos_of_not_isUnit_of_dvd_monic (ha : ¬IsUnit a) (hap : a ∣ p) : 0 < natDegree a := + natDegree_pos_iff_degree_pos.mpr <| degree_pos_of_not_isUnit_of_dvd_monic hp ha hap + +end CommSemiring + section Ring variable [Ring R] @@ -1420,59 +1597,11 @@ theorem natDegree_X_pow_sub_C {n : ℕ} {r : R} : (X ^ n - C r).natDegree = n := theorem leadingCoeff_X_sub_C [Ring S] (r : S) : (X - C r).leadingCoeff = 1 := by rw [sub_eq_add_neg, ← map_neg C r, leadingCoeff_X_add_C] -end Ring - -section NoZeroDivisors - -variable [Semiring R] [NoZeroDivisors R] {p q : R[X]} - -@[simp] -theorem degree_mul : degree (p * q) = degree p + degree q := - letI := Classical.decEq R - if hp0 : p = 0 then by simp only [hp0, degree_zero, zero_mul, WithBot.bot_add] - else - if hq0 : q = 0 then by simp only [hq0, degree_zero, mul_zero, WithBot.add_bot] - else degree_mul' <| mul_ne_zero (mt leadingCoeff_eq_zero.1 hp0) (mt leadingCoeff_eq_zero.1 hq0) - -/-- `degree` as a monoid homomorphism between `R[X]` and `Multiplicative (WithBot ℕ)`. - This is useful to prove results about multiplication and degree. -/ -def degreeMonoidHom [Nontrivial R] : R[X] →* Multiplicative (WithBot ℕ) where - toFun := degree - map_one' := degree_one - map_mul' _ _ := degree_mul +variable [IsDomain R] {p q : R[X]} -@[simp] -theorem degree_pow [Nontrivial R] (p : R[X]) (n : ℕ) : degree (p ^ n) = n • degree p := - map_pow (@degreeMonoidHom R _ _ _) _ _ - -@[simp] -theorem leadingCoeff_mul (p q : R[X]) : leadingCoeff (p * q) = leadingCoeff p * leadingCoeff q := by - by_cases hp : p = 0 - · simp only [hp, zero_mul, leadingCoeff_zero] - · by_cases hq : q = 0 - · simp only [hq, mul_zero, leadingCoeff_zero] - · rw [leadingCoeff_mul'] - exact mul_ne_zero (mt leadingCoeff_eq_zero.1 hp) (mt leadingCoeff_eq_zero.1 hq) - -/-- `Polynomial.leadingCoeff` bundled as a `MonoidHom` when `R` has `NoZeroDivisors`, and thus - `leadingCoeff` is multiplicative -/ -def leadingCoeffHom : R[X] →* R where - toFun := leadingCoeff - map_one' := by simp - map_mul' := leadingCoeff_mul - -@[simp] -theorem leadingCoeffHom_apply (p : R[X]) : leadingCoeffHom p = leadingCoeff p := - rfl - -@[simp] -theorem leadingCoeff_pow (p : R[X]) (n : ℕ) : leadingCoeff (p ^ n) = leadingCoeff p ^ n := - (leadingCoeffHom : R[X] →* R).map_pow p n - -theorem leadingCoeff_dvd_leadingCoeff {a p : R[X]} (hap : a ∣ p) : - a.leadingCoeff ∣ p.leadingCoeff := - map_dvd leadingCoeffHom hap - -end NoZeroDivisors +instance : IsDomain R[X] := NoZeroDivisors.to_isDomain _ +end Ring end Polynomial + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean index 649bab3a13526..00c456c6a6f64 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean @@ -368,6 +368,31 @@ 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]) : + (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] + +lemma comp_eq_zero_iff : 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] + obtain key | key := Or.imp eq_C_of_natDegree_eq_zero eq_C_of_natDegree_eq_zero key + · rw [key, C_comp] at h + exact Or.inl (key.trans h) + · 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/Degree/TrailingDegree.lean b/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean index 78ee6ce26e4a0..d68474f05ed6e 100644 --- a/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean +++ b/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean @@ -228,7 +228,7 @@ theorem coeff_eq_zero_of_lt_natTrailingDegree {p : R[X]} {n : ℕ} (h : n < p.na theorem coeff_natTrailingDegree_pred_eq_zero {p : R[X]} {hp : (0 : ℕ∞) < natTrailingDegree p} : p.coeff (p.natTrailingDegree - 1) = 0 := coeff_eq_zero_of_lt_natTrailingDegree <| - Nat.sub_lt ((WithTop.zero_lt_coe (natTrailingDegree p)).mp hp) Nat.one_pos + Nat.sub_lt (WithTop.coe_pos.mp hp) Nat.one_pos theorem le_trailingDegree_X_pow (n : ℕ) : (n : ℕ∞) ≤ trailingDegree (X ^ n : R[X]) := by simpa only [C_1, one_mul] using le_trailingDegree_C_mul_X_pow n (1 : R) diff --git a/Mathlib/Algebra/Polynomial/Derivative.lean b/Mathlib/Algebra/Polynomial/Derivative.lean index b2767e3897214..899b80f020a97 100644 --- a/Mathlib/Algebra/Polynomial/Derivative.lean +++ b/Mathlib/Algebra/Polynomial/Derivative.lean @@ -12,6 +12,7 @@ import Mathlib.GroupTheory.GroupAction.Ring ## Main definitions * `Polynomial.derivative`: The formal derivative of polynomials, expressed as a linear map. + * `Polynomial.derivativeFinsupp`: Iterated derivatives as a finite support function. -/ @@ -22,6 +23,8 @@ open Finset open Polynomial +open scoped Nat + namespace Polynomial universe u v w y z @@ -68,7 +71,7 @@ theorem coeff_derivative (p : R[X]) (n : ℕ) : push_neg at h simp [h] --- Porting note (#10618): removed `simp`: `simp` can prove it. +@[simp] theorem derivative_zero : derivative (0 : R[X]) = 0 := derivative.map_zero @@ -95,7 +98,6 @@ theorem derivative_C_mul_X_sq (a : R) : derivative (C a * X ^ 2) = C (a * 2) * X theorem derivative_X_pow (n : ℕ) : derivative (X ^ n : R[X]) = C (n : R) * X ^ (n - 1) := by convert derivative_C_mul_X_pow (1 : R) n <;> simp --- Porting note (#10618): removed `simp`: `simp` can prove it. theorem derivative_X_sq : derivative (X ^ 2 : R[X]) = C 2 * X := by rw [derivative_X_pow, Nat.cast_two, pow_one] @@ -113,20 +115,17 @@ theorem derivative_X : derivative (X : R[X]) = 1 := theorem derivative_one : derivative (1 : R[X]) = 0 := derivative_C --- Porting note (#10618): removed `simp`: `simp` can prove it. +@[simp] theorem derivative_add {f g : R[X]} : derivative (f + g) = derivative f + derivative g := derivative.map_add f g --- Porting note (#10618): removed `simp`: `simp` can prove it. theorem derivative_X_add_C (c : R) : derivative (X + C c) = 1 := by rw [derivative_add, derivative_X, derivative_C, add_zero] --- Porting note (#10618): removed `simp`: `simp` can prove it. theorem derivative_sum {s : Finset ι} {f : ι → R[X]} : derivative (∑ b ∈ s, f b) = ∑ b ∈ s, derivative (f b) := map_sum .. --- Porting note (#10618): removed `simp`: `simp` can prove it. theorem derivative_smul {S : Type*} [Monoid S] [DistribMulAction S R] [IsScalarTower S R R] (s : S) (p : R[X]) : derivative (s • p) = s • derivative p := derivative.map_smul_of_tower s p @@ -330,6 +329,21 @@ theorem coeff_iterate_derivative {k} (p : R[X]) (m : ℕ) : _ = Nat.descFactorial (m + k.succ) k.succ • p.coeff (m + k.succ) := by rw [Nat.succ_add_eq_add_succ] +theorem iterate_derivative_eq_sum (p : R[X]) (k : ℕ) : + derivative^[k] p = + ∑ x ∈ (derivative^[k] p).support, C ((x + k).descFactorial k • p.coeff (x + k)) * X ^ x := by + conv_lhs => rw [(derivative^[k] p).as_sum_support_C_mul_X_pow] + refine sum_congr rfl fun i _ ↦ ?_ + rw [coeff_iterate_derivative, Nat.descFactorial_eq_factorial_mul_choose] + +theorem iterate_derivative_eq_factorial_smul_sum (p : R[X]) (k : ℕ) : + derivative^[k] p = k ! • + ∑ x ∈ (derivative^[k] p).support, C ((x + k).choose k • p.coeff (x + k)) * X ^ x := by + conv_lhs => rw [iterate_derivative_eq_sum] + rw [smul_sum] + refine sum_congr rfl fun i _ ↦ ?_ + rw [← smul_mul_assoc, smul_C, smul_smul, Nat.descFactorial_eq_factorial_mul_choose] + theorem iterate_derivative_mul {n} (p q : R[X]) : derivative^[n] (p * q) = ∑ k ∈ range n.succ, (n.choose k • (derivative^[n - k] p * derivative^[k] q)) := by @@ -374,6 +388,52 @@ theorem iterate_derivative_mul {n} (p q : R[X]) : omega · rw [Nat.choose_zero_right, tsub_zero] +/-- +Iterated derivatives as a finite support function. +-/ +@[simps! apply_toFun] +noncomputable def derivativeFinsupp : R[X] →ₗ[R] ℕ →₀ R[X] where + toFun p := .onFinset (range (p.natDegree + 1)) (derivative^[·] p) fun i ↦ by + contrapose; simp_all [iterate_derivative_eq_zero, Nat.succ_le] + map_add' _ _ := by ext; simp + map_smul' _ _ := by ext; simp + +@[simp] +theorem support_derivativeFinsupp_subset_range {p : R[X]} {n : ℕ} (h : p.natDegree < n) : + (derivativeFinsupp p).support ⊆ range n := by + dsimp [derivativeFinsupp] + exact Finsupp.support_onFinset_subset.trans (Finset.range_subset.mpr h) + +@[simp] +theorem derivativeFinsupp_C (r : R) : derivativeFinsupp (C r : R[X]) = .single 0 (C r) := by + ext i : 1 + match i with + | 0 => simp + | i + 1 => simp + +@[simp] +theorem derivativeFinsupp_one : derivativeFinsupp (1 : R[X]) = .single 0 1 := by + simpa using derivativeFinsupp_C (1 : R) + +@[simp] +theorem derivativeFinsupp_X : derivativeFinsupp (X : R[X]) = .single 0 X + .single 1 1 := by + ext i : 1 + match i with + | 0 => simp + | 1 => simp + | (n + 2) => simp + +theorem derivativeFinsupp_map [Semiring S] (p : R[X]) (f : R →+* S) : + derivativeFinsupp (p.map f) = (derivativeFinsupp p).mapRange (·.map f) (by simp) := by + ext i : 1 + simp + +theorem derivativeFinsupp_derivative (p : R[X]) : + derivativeFinsupp (derivative p) = + (derivativeFinsupp p).comapDomain Nat.succ Nat.succ_injective.injOn := by + ext i : 1 + simp + end Semiring section CommSemiring @@ -422,7 +482,7 @@ theorem iterate_derivative_X_pow_eq_natCast_mul (n k : ℕ) : derivative^[k] (X ^ n : R[X]) = ↑(Nat.descFactorial n k : R[X]) * X ^ (n - k) := by induction k with | zero => - erw [Function.iterate_zero_apply, tsub_zero, Nat.descFactorial_zero, Nat.cast_one, one_mul] + rw [Function.iterate_zero_apply, tsub_zero, Nat.descFactorial_zero, Nat.cast_one, one_mul] | succ k ih => rw [Function.iterate_succ_apply', ih, derivative_natCast_mul, derivative_X_pow, C_eq_natCast, Nat.descFactorial_succ, Nat.sub_sub, Nat.cast_mul] @@ -496,18 +556,17 @@ section Ring variable [Ring R] --- Porting note (#10618): removed `simp`: `simp` can prove it. +@[simp] theorem derivative_neg (f : R[X]) : derivative (-f) = -derivative f := LinearMap.map_neg derivative f theorem iterate_derivative_neg {f : R[X]} {k : ℕ} : derivative^[k] (-f) = -derivative^[k] f := iterate_map_neg derivative k f --- Porting note (#10618): removed `simp`: `simp` can prove it. +@[simp] theorem derivative_sub {f g : R[X]} : derivative (f - g) = derivative f - derivative g := LinearMap.map_sub derivative f g --- Porting note (#10618): removed `simp`: `simp` can prove it. theorem derivative_X_sub_C (c : R) : derivative (X - C c) = 1 := by rw [derivative_sub, derivative_X, derivative_C, sub_zero] diff --git a/Mathlib/Algebra/Polynomial/Div.lean b/Mathlib/Algebra/Polynomial/Div.lean index 7ac2f94a0beb8..804749c1a188a 100644 --- a/Mathlib/Algebra/Polynomial/Div.lean +++ b/Mathlib/Algebra/Polynomial/Div.lean @@ -502,11 +502,17 @@ theorem rootMultiplicity_eq_nat_find_of_nonzero [DecidableEq R] {p : R[X]} (p0 : cases Subsingleton.elim ‹DecidableEq R› (Classical.decEq R) rw [dif_neg p0] -theorem rootMultiplicity_eq_multiplicity [DecidableEq R] [@DecidableRel R[X] (· ∣ ·)] +theorem rootMultiplicity_eq_multiplicity [DecidableEq R] (p : R[X]) (a : R) : rootMultiplicity a p = - if h0 : p = 0 then 0 else (multiplicity (X - C a) p).get (multiplicity_X_sub_C_finite a h0) := - by simp only [rootMultiplicity, multiplicity, PartENat.find_get]; congr; funext; congr + if p = 0 then 0 else multiplicity (X - C a) p := by + simp only [rootMultiplicity, multiplicity, emultiplicity] + split + · rfl + rename_i h + simp only [multiplicity_X_sub_C_finite a h, ↓reduceDIte] + rw [← ENat.some_eq_coe, WithTop.untop'_coe] + congr @[simp] theorem rootMultiplicity_zero {x : R} : rootMultiplicity x 0 = 0 := @@ -521,15 +527,14 @@ theorem rootMultiplicity_C (r a : R) : rootMultiplicity a (C r) = 0 := by split_ifs with hr · rfl have h : natDegree (C r) < natDegree (X - C a) := by simp - simp_rw [multiplicity.multiplicity_eq_zero.mpr ((monic_X_sub_C a).not_dvd_of_natDegree_lt hr h), - PartENat.get_zero] + simp_rw [multiplicity_eq_zero.mpr ((monic_X_sub_C a).not_dvd_of_natDegree_lt hr h)] theorem pow_rootMultiplicity_dvd (p : R[X]) (a : R) : (X - C a) ^ rootMultiplicity a p ∣ p := letI := Classical.decEq R if h : p = 0 then by simp [h] else by classical - rw [rootMultiplicity_eq_multiplicity, dif_neg h]; exact multiplicity.pow_multiplicity_dvd _ + rw [rootMultiplicity_eq_multiplicity, if_neg h]; apply pow_multiplicity_dvd theorem pow_mul_divByMonic_rootMultiplicity_eq (p : R[X]) (a : R) : (X - C a) ^ rootMultiplicity a p * (p /ₘ (X - C a) ^ rootMultiplicity a p) = p := by @@ -542,8 +547,8 @@ theorem pow_mul_divByMonic_rootMultiplicity_eq (p : R[X]) (a : R) : theorem exists_eq_pow_rootMultiplicity_mul_and_not_dvd (p : R[X]) (hp : p ≠ 0) (a : R) : ∃ q : R[X], p = (X - C a) ^ p.rootMultiplicity a * q ∧ ¬ (X - C a) ∣ q := by classical - rw [rootMultiplicity_eq_multiplicity, dif_neg hp] - apply multiplicity.exists_eq_pow_mul_and_not_dvd + rw [rootMultiplicity_eq_multiplicity, if_neg hp] + apply (multiplicity_X_sub_C_finite a hp).exists_eq_pow_mul_and_not_dvd end multiplicity @@ -551,7 +556,7 @@ end Ring section CommRing -variable [CommRing R] {p q : R[X]} +variable [CommRing R] {p p₁ p₂ q : R[X]} @[simp] theorem modByMonic_X_sub_C_eq_C_eval (p : R[X]) (a : R) : p %ₘ (X - C a) = C (p.eval a) := by @@ -618,8 +623,8 @@ theorem ker_evalRingHom (x : R) : RingHom.ker (evalRingHom x) = Ideal.span {X - theorem rootMultiplicity_eq_zero_iff {p : R[X]} {x : R} : rootMultiplicity x p = 0 ↔ IsRoot p x → p = 0 := by classical - simp only [rootMultiplicity_eq_multiplicity, dite_eq_left_iff, PartENat.get_eq_iff_eq_coe, - Nat.cast_zero, multiplicity.multiplicity_eq_zero, dvd_iff_isRoot, not_imp_not] + simp only [rootMultiplicity_eq_multiplicity, ite_eq_left_iff, + Nat.cast_zero, multiplicity_eq_zero, dvd_iff_isRoot, not_imp_not] theorem rootMultiplicity_eq_zero {p : R[X]} {x : R} (h : ¬IsRoot p x) : rootMultiplicity x p = 0 := rootMultiplicity_eq_zero_iff.2 fun h' => (h h').elim @@ -640,12 +645,11 @@ theorem eval_divByMonic_pow_rootMultiplicity_ne_zero {p : R[X]} (a : R) (hp : p rw [Ne, ← IsRoot, ← dvd_iff_isRoot] rintro ⟨q, hq⟩ have := pow_mul_divByMonic_rootMultiplicity_eq p a - rw [hq, ← mul_assoc, ← pow_succ, rootMultiplicity_eq_multiplicity, dif_neg hp] at this + rw [hq, ← mul_assoc, ← pow_succ, rootMultiplicity_eq_multiplicity, if_neg hp] at this exact - multiplicity.is_greatest' - (multiplicity_finite_of_degree_pos_of_monic - (show (0 : WithBot ℕ) < degree (X - C a) by rw [degree_X_sub_C]; decide) - (monic_X_sub_C _) hp) + (multiplicity_finite_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) /-- See `Polynomial.mul_right_modByMonic` for the other multiplication order. This version, unlike @@ -655,6 +659,177 @@ lemma mul_self_modByMonic (hq : q.Monic) : (p * q) %ₘ q = 0 := by rw [modByMonic_eq_zero_iff_dvd hq] exact dvd_mul_left q p +lemma modByMonic_eq_of_dvd_sub (hq : q.Monic) (h : q ∣ p₁ - p₂) : p₁ %ₘ q = p₂ %ₘ q := by + nontriviality R + obtain ⟨f, sub_eq⟩ := h + refine (div_modByMonic_unique (p₂ /ₘ q + f) _ hq ⟨?_, degree_modByMonic_lt _ hq⟩).2 + rw [sub_eq_iff_eq_add.mp sub_eq, mul_add, ← add_assoc, modByMonic_add_div _ hq, add_comm] + +lemma add_modByMonic (p₁ p₂ : R[X]) : (p₁ + p₂) %ₘ q = p₁ %ₘ q + p₂ %ₘ q := by + by_cases hq : q.Monic + · cases' subsingleton_or_nontrivial R with hR hR + · simp only [eq_iff_true_of_subsingleton] + · exact + (div_modByMonic_unique (p₁ /ₘ q + p₂ /ₘ q) _ hq + ⟨by + rw [mul_add, add_left_comm, add_assoc, modByMonic_add_div _ hq, ← add_assoc, + add_comm (q * _), modByMonic_add_div _ hq], + (degree_add_le _ _).trans_lt + (max_lt (degree_modByMonic_lt _ hq) (degree_modByMonic_lt _ hq))⟩).2 + · simp_rw [modByMonic_eq_of_not_monic _ hq] + +lemma neg_modByMonic (p q : R[X]) : (-p) %ₘ q = - (p %ₘ q) := by + rw [eq_neg_iff_add_eq_zero, ← add_modByMonic, neg_add_cancel, zero_modByMonic] + +lemma sub_modByMonic (p₁ p₂ q : R[X]) : (p₁ - p₂) %ₘ q = p₁ %ₘ q - p₂ %ₘ q := by + simp [sub_eq_add_neg, add_modByMonic, neg_modByMonic] + +lemma eval_divByMonic_eq_trailingCoeff_comp {p : R[X]} {t : R} : + (p /ₘ (X - C t) ^ p.rootMultiplicity t).eval t = (p.comp (X + C t)).trailingCoeff := by + obtain rfl | hp := eq_or_ne p 0 + · rw [zero_divByMonic, eval_zero, zero_comp, trailingCoeff_zero] + have mul_eq := p.pow_mul_divByMonic_rootMultiplicity_eq t + set m := p.rootMultiplicity t + set g := p /ₘ (X - C t) ^ m + have : (g.comp (X + C t)).coeff 0 = g.eval t := by + rw [coeff_zero_eq_eval_zero, eval_comp, eval_add, eval_X, eval_C, zero_add] + rw [← congr_arg (comp · <| X + C t) mul_eq, mul_comp, pow_comp, sub_comp, X_comp, C_comp, + add_sub_cancel_right, ← reverse_leadingCoeff, reverse_X_pow_mul, reverse_leadingCoeff, + trailingCoeff, Nat.le_zero.1 (natTrailingDegree_le_of_ne_zero <| + this ▸ eval_divByMonic_pow_rootMultiplicity_ne_zero t hp), this] + +/- Porting note: the ML3 proof no longer worked because of a conflict in the +inferred type and synthesized type for `DecidableRel` when using `Nat.le_find_iff` from +`Mathlib.Algebra.Polynomial.Div` After some discussion on [Zulip] +(https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/decidability.20leakage) +introduced `Polynomial.rootMultiplicity_eq_nat_find_of_nonzero` to contain the issue +-/ +/-- The multiplicity of `a` as root of a nonzero polynomial `p` is at least `n` iff +`(X - a) ^ n` divides `p`. -/ +lemma le_rootMultiplicity_iff (p0 : p ≠ 0) {a : R} {n : ℕ} : + n ≤ rootMultiplicity a p ↔ (X - C a) ^ n ∣ p := by + classical + rw [rootMultiplicity_eq_nat_find_of_nonzero p0, @Nat.le_find_iff _ (_)] + simp_rw [Classical.not_not] + refine ⟨fun h => ?_, fun h m hm => (pow_dvd_pow _ hm).trans h⟩ + cases' n with n + · rw [pow_zero] + apply one_dvd + · exact h n n.lt_succ_self + +lemma rootMultiplicity_le_iff (p0 : p ≠ 0) (a : R) (n : ℕ) : + rootMultiplicity a p ≤ n ↔ ¬(X - C a) ^ (n + 1) ∣ p := by + rw [← (le_rootMultiplicity_iff p0).not, not_le, Nat.lt_add_one_iff] + +/-- The multiplicity of `p + q` is at least the minimum of the multiplicities. -/ +lemma rootMultiplicity_add {p q : R[X]} (a : R) (hzero : p + q ≠ 0) : + min (rootMultiplicity a p) (rootMultiplicity a q) ≤ rootMultiplicity a (p + q) := by + rw [le_rootMultiplicity_iff hzero] + exact min_pow_dvd_add (pow_rootMultiplicity_dvd p a) (pow_rootMultiplicity_dvd q a) + +lemma le_rootMultiplicity_mul {p q : R[X]} (x : R) (hpq : p * q ≠ 0) : + rootMultiplicity x p + rootMultiplicity x q ≤ rootMultiplicity x (p * q) := by + rw [le_rootMultiplicity_iff hpq, pow_add] + exact mul_dvd_mul (pow_rootMultiplicity_dvd p x) (pow_rootMultiplicity_dvd q x) + +lemma pow_rootMultiplicity_not_dvd (p0 : p ≠ 0) (a : R) : + ¬(X - C a) ^ (rootMultiplicity a p + 1) ∣ p := by rw [← rootMultiplicity_le_iff p0] + +/-- See `Polynomial.rootMultiplicity_eq_natTrailingDegree` for the general case. -/ +lemma rootMultiplicity_eq_natTrailingDegree' : p.rootMultiplicity 0 = p.natTrailingDegree := by + by_cases h : p = 0 + · simp only [h, rootMultiplicity_zero, natTrailingDegree_zero] + refine le_antisymm ?_ ?_ + · rw [rootMultiplicity_le_iff h, map_zero, sub_zero, X_pow_dvd_iff, not_forall] + exact ⟨p.natTrailingDegree, + fun h' ↦ trailingCoeff_nonzero_iff_nonzero.2 h <| h' <| Nat.lt.base _⟩ + · rw [le_rootMultiplicity_iff h, map_zero, sub_zero, X_pow_dvd_iff] + exact fun _ ↦ coeff_eq_zero_of_lt_natTrailingDegree + +/-- Division by a monic polynomial doesn't change the leading coefficient. -/ +lemma leadingCoeff_divByMonic_of_monic (hmonic : q.Monic) + (hdegree : q.degree ≤ p.degree) : (p /ₘ q).leadingCoeff = p.leadingCoeff := by + nontriviality + have h : q.leadingCoeff * (p /ₘ q).leadingCoeff ≠ 0 := by + simpa [divByMonic_eq_zero_iff hmonic, hmonic.leadingCoeff, + Nat.WithBot.one_le_iff_zero_lt] using hdegree + nth_rw 2 [← modByMonic_add_div p hmonic] + rw [leadingCoeff_add_of_degree_lt, leadingCoeff_monic_mul hmonic] + rw [degree_mul' h, degree_add_divByMonic hmonic hdegree] + exact (degree_modByMonic_lt p hmonic).trans_le hdegree + +variable [IsDomain R] + +lemma degree_eq_one_of_irreducible_of_root (hi : Irreducible p) {x : R} (hx : IsRoot p x) : + degree p = 1 := + let ⟨g, hg⟩ := dvd_iff_isRoot.2 hx + have : IsUnit (X - C x) ∨ IsUnit g := hi.isUnit_or_isUnit hg + this.elim + (fun h => by + have h₁ : degree (X - C x) = 1 := degree_X_sub_C x + have h₂ : degree (X - C x) = 0 := degree_eq_zero_of_isUnit h + rw [h₁] at h₂; exact absurd h₂ (by decide)) + fun hgu => by rw [hg, degree_mul, degree_X_sub_C, degree_eq_zero_of_isUnit hgu, add_zero] + +lemma leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) : + leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by + nontriviality + cases' hp.lt_or_lt with hd hd + · rw [degree_eq_bot.mp <| Nat.WithBot.lt_zero_iff.mp hd, zero_divByMonic] + refine leadingCoeff_divByMonic_of_monic (monic_X_sub_C a) ?_ + rwa [degree_X_sub_C, Nat.WithBot.one_le_iff_zero_lt] + +lemma eq_of_dvd_of_natDegree_le_of_leadingCoeff {p q : R[X]} (hpq : p ∣ q) + (h₁ : q.natDegree ≤ p.natDegree) (h₂ : p.leadingCoeff = q.leadingCoeff) : + p = q := by + by_cases hq : q = 0 + · rwa [hq, leadingCoeff_zero, leadingCoeff_eq_zero, ← hq] at h₂ + replace h₁ := (natDegree_le_of_dvd hpq hq).antisymm h₁ + obtain ⟨u, rfl⟩ := hpq + replace hq := mul_ne_zero_iff.mp hq + rw [natDegree_mul hq.1 hq.2, self_eq_add_right] at h₁ + rw [eq_C_of_natDegree_eq_zero h₁, leadingCoeff_mul, leadingCoeff_C, + eq_comm, mul_eq_left₀ (leadingCoeff_ne_zero.mpr hq.1)] at h₂ + rw [eq_C_of_natDegree_eq_zero h₁, h₂, map_one, mul_one] + +lemma associated_of_dvd_of_natDegree_le_of_leadingCoeff {p q : R[X]} (hpq : p ∣ q) + (h₁ : q.natDegree ≤ p.natDegree) (h₂ : q.leadingCoeff ∣ p.leadingCoeff) : + Associated p q := + have ⟨r, hr⟩ := hpq + have ⟨u, hu⟩ := associated_of_dvd_dvd ⟨leadingCoeff r, hr ▸ leadingCoeff_mul p r⟩ h₂ + ⟨Units.map C.toMonoidHom u, eq_of_dvd_of_natDegree_le_of_leadingCoeff + (by rwa [Units.mul_right_dvd]) (by simpa [natDegree_mul_C] using h₁) (by simpa using hu)⟩ + +lemma associated_of_dvd_of_natDegree_le {K} [Field K] {p q : K[X]} (hpq : p ∣ q) (hq : q ≠ 0) + (h₁ : q.natDegree ≤ p.natDegree) : Associated p q := + associated_of_dvd_of_natDegree_le_of_leadingCoeff hpq h₁ + (IsUnit.dvd (by rwa [← leadingCoeff_ne_zero, ← isUnit_iff_ne_zero] at hq)) + +lemma associated_of_dvd_of_degree_eq {K} [Field K] {p q : K[X]} (hpq : p ∣ q) + (h₁ : p.degree = q.degree) : Associated p q := + (Classical.em (q = 0)).elim (fun hq ↦ (show p = q by simpa [hq] using h₁) ▸ Associated.refl p) + (associated_of_dvd_of_natDegree_le hpq · (natDegree_le_natDegree h₁.ge)) + +lemma eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} + (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : + q = C q.leadingCoeff * p := by + obtain ⟨r, hr⟩ := hdiv + obtain rfl | hq := eq_or_ne q 0; · simp + have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr + rw [hr, natDegree_mul'] at hdeg; swap + · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero] + exact rzero + rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr + · convert hr + convert leadingCoeff_C (coeff r 0) using 1 + rw [hr, leadingCoeff_mul_monic hp] + · exact (add_right_inj _).1 (le_antisymm hdeg <| Nat.le.intro rfl) + +lemma eq_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} (hp : p.Monic) + (hq : q.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : q = p := by + convert eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le hp hdiv hdeg + rw [hq.leadingCoeff, C_1, one_mul] + end CommRing end Polynomial diff --git a/Mathlib/Algebra/Polynomial/EraseLead.lean b/Mathlib/Algebra/Polynomial/EraseLead.lean index 7f0f5dd10d6e4..3a13d453a7189 100644 --- a/Mathlib/Algebra/Polynomial/EraseLead.lean +++ b/Mathlib/Algebra/Polynomial/EraseLead.lean @@ -72,7 +72,7 @@ theorem self_sub_C_mul_X_pow {R : Type*} [Ring R] (f : R[X]) : f - C f.leadingCoeff * X ^ f.natDegree = f.eraseLead := by rw [C_mul_X_pow_eq_monomial, self_sub_monomial_natDegree_leadingCoeff] -theorem eraseLead_ne_zero (f0 : 2 ≤ f.support.card) : eraseLead f ≠ 0 := by +theorem eraseLead_ne_zero (f0 : 2 ≤ #f.support) : eraseLead f ≠ 0 := by rw [Ne, ← card_support_eq_zero, eraseLead_support] exact (zero_lt_one.trans_le <| (tsub_le_tsub_right f0 1).trans Finset.pred_card_le_card_erase).ne.symm @@ -89,13 +89,12 @@ theorem ne_natDegree_of_mem_eraseLead_support {a : ℕ} (h : a ∈ (eraseLead f) theorem natDegree_not_mem_eraseLead_support : f.natDegree ∉ (eraseLead f).support := fun h => ne_natDegree_of_mem_eraseLead_support h rfl -theorem eraseLead_support_card_lt (h : f ≠ 0) : (eraseLead f).support.card < f.support.card := by +theorem eraseLead_support_card_lt (h : f ≠ 0) : #(eraseLead f).support < #f.support := by rw [eraseLead_support] exact card_lt_card (erase_ssubset <| natDegree_mem_support_of_nonzero h) -theorem card_support_eraseLead_add_one (h : f ≠ 0) : - f.eraseLead.support.card + 1 = f.support.card := by - set c := f.support.card with hc +theorem card_support_eraseLead_add_one (h : f ≠ 0) : #f.eraseLead.support + 1 = #f.support := by + set c := #f.support with hc cases h₁ : c case zero => by_contra @@ -105,20 +104,20 @@ theorem card_support_eraseLead_add_one (h : f ≠ 0) : rfl @[simp] -theorem card_support_eraseLead : f.eraseLead.support.card = f.support.card - 1 := by +theorem card_support_eraseLead : #f.eraseLead.support = #f.support - 1 := by by_cases hf : f = 0 · rw [hf, eraseLead_zero, support_zero, card_empty] · rw [← card_support_eraseLead_add_one hf, add_tsub_cancel_right] -theorem card_support_eraseLead' {c : ℕ} (fc : f.support.card = c + 1) : - f.eraseLead.support.card = c := by +theorem card_support_eraseLead' {c : ℕ} (fc : #f.support = c + 1) : + #f.eraseLead.support = c := by rw [card_support_eraseLead, fc, add_tsub_cancel_right] theorem card_support_eq_one_of_eraseLead_eq_zero (h₀ : f ≠ 0) (h₁ : f.eraseLead = 0) : - f.support.card = 1 := + #f.support = 1 := (card_support_eq_zero.mpr h₁ ▸ card_support_eraseLead_add_one h₀).symm -theorem card_support_le_one_of_eraseLead_eq_zero (h : f.eraseLead = 0) : f.support.card ≤ 1 := by +theorem card_support_le_one_of_eraseLead_eq_zero (h : f.eraseLead = 0) : #f.support ≤ 1 := by by_cases hpz : f = 0 case pos => simp [hpz] case neg => exact le_of_eq (card_support_eq_one_of_eraseLead_eq_zero hpz h) @@ -187,7 +186,7 @@ theorem degree_eraseLead_lt (hf : f ≠ 0) : (eraseLead f).degree < f.degree := theorem eraseLead_natDegree_le_aux : (eraseLead f).natDegree ≤ f.natDegree := natDegree_le_natDegree eraseLead_degree_le -theorem eraseLead_natDegree_lt (f0 : 2 ≤ f.support.card) : (eraseLead f).natDegree < f.natDegree := +theorem eraseLead_natDegree_lt (f0 : 2 ≤ #f.support) : (eraseLead f).natDegree < f.natDegree := lt_of_le_of_ne eraseLead_natDegree_le_aux <| ne_natDegree_of_mem_eraseLead_support <| natDegree_mem_support_of_nonzero <| eraseLead_ne_zero f0 @@ -199,7 +198,7 @@ theorem natDegree_pos_of_eraseLead_ne_zero (h : f.eraseLead ≠ 0) : 0 < f.natDe theorem eraseLead_natDegree_lt_or_eraseLead_eq_zero (f : R[X]) : (eraseLead f).natDegree < f.natDegree ∨ f.eraseLead = 0 := by - by_cases h : f.support.card ≤ 1 + by_cases h : #f.support ≤ 1 · right rw [← C_mul_X_pow_eq_self h] simp @@ -264,7 +263,7 @@ theorem induction_with_natDegree_le (P : R[X] → Prop) (N : ℕ) (P_0 : P 0) (P_C_add : ∀ f g : R[X], f.natDegree < g.natDegree → g.natDegree ≤ N → P f → P g → P (f + g)) : ∀ f : R[X], f.natDegree ≤ N → P f := by intro f df - generalize hd : card f.support = c + generalize hd : #f.support = c revert f induction' c with c hc · intro f _ f0 @@ -321,18 +320,18 @@ theorem map_natDegree_eq_sub {S F : Type*} [Semiring S] (φ_mon : ∀ n c, c ≠ 0 → (φ (monomial n c)).natDegree = n - k) : (φ p).natDegree = p.natDegree - k := mono_map_natDegree_eq k (fun j => j - k) (by simp_all) - (@fun m n h => (tsub_lt_tsub_iff_right h).mpr) + (@fun _ _ h => (tsub_lt_tsub_iff_right h).mpr) (φ_k _) φ_mon theorem map_natDegree_eq_natDegree {S F : Type*} [Semiring S] [FunLike F R[X] S[X]] [AddMonoidHomClass F R[X] S[X]] {φ : F} (p) (φ_mon_nat : ∀ n c, c ≠ 0 → (φ (monomial n c)).natDegree = n) : (φ p).natDegree = p.natDegree := - (map_natDegree_eq_sub (fun f h => (Nat.not_lt_zero _ h).elim) (by simpa)).trans + (map_natDegree_eq_sub (fun _ h => (Nat.not_lt_zero _ h).elim) (by simpa)).trans p.natDegree.sub_zero theorem card_support_eq' {n : ℕ} (k : Fin n → ℕ) (x : Fin n → R) (hk : Function.Injective k) - (hx : ∀ i, x i ≠ 0) : (∑ i, C (x i) * X ^ k i).support.card = n := by + (hx : ∀ i, x i ≠ 0) : #(∑ i, C (x i) * X ^ k i).support = n := by suffices (∑ i, C (x i) * X ^ k i).support = image k univ by rw [this, univ.card_image_of_injective hk, card_fin] simp_rw [Finset.ext_iff, mem_support_iff, finset_sum_coeff, coeff_C_mul_X_pow, mem_image, @@ -346,8 +345,8 @@ theorem card_support_eq' {n : ℕ} (k : Fin n → ℕ) (x : Fin n → R) (hk : F · exact fun m _ hmj => if_neg fun h => hmj.symm (hk h) theorem card_support_eq {n : ℕ} : - f.support.card = n ↔ - ∃ (k : Fin n → ℕ) (x : Fin n → R) (hk : StrictMono k) (hx : ∀ i, x i ≠ 0), + #f.support = n ↔ + ∃ (k : Fin n → ℕ) (x : Fin n → R) (_ : StrictMono k) (_ : ∀ i, x i ≠ 0), f = ∑ i, C (x i) * X ^ k i := by refine ⟨?_, fun ⟨k, x, hk, hx, hf⟩ => hf.symm ▸ card_support_eq' k x hk.injective hx⟩ induction n generalizing f with @@ -391,8 +390,8 @@ theorem card_support_eq {n : ℕ} : rw [← hf, Function.extend_apply', Function.extend_apply', eraseLead_add_C_mul_X_pow] all_goals exact H -theorem card_support_eq_one : f.support.card = 1 ↔ - ∃ (k : ℕ) (x : R) (hx : x ≠ 0), f = C x * X ^ k := by +theorem card_support_eq_one : #f.support = 1 ↔ + ∃ (k : ℕ) (x : R) (_ : x ≠ 0), f = C x * X ^ k := by refine ⟨fun h => ?_, ?_⟩ · obtain ⟨k, x, _, hx, rfl⟩ := card_support_eq.mp h exact ⟨k 0, x 0, hx 0, Fin.sum_univ_one _⟩ @@ -400,8 +399,8 @@ theorem card_support_eq_one : f.support.card = 1 ↔ rw [support_C_mul_X_pow k hx, card_singleton] theorem card_support_eq_two : - f.support.card = 2 ↔ - ∃ (k m : ℕ) (hkm : k < m) (x y : R) (hx : x ≠ 0) (hy : y ≠ 0), + #f.support = 2 ↔ + ∃ (k m : ℕ) (_ : k < m) (x y : R) (_ : x ≠ 0) (_ : y ≠ 0), f = C x * X ^ k + C y * X ^ m := by refine ⟨fun h => ?_, ?_⟩ · obtain ⟨k, x, hk, hx, rfl⟩ := card_support_eq.mp h @@ -412,8 +411,8 @@ theorem card_support_eq_two : exact card_support_binomial hkm.ne hx hy theorem card_support_eq_three : - f.support.card = 3 ↔ - ∃ (k m n : ℕ) (hkm : k < m) (hmn : m < n) (x y z : R) (hx : x ≠ 0) (hy : y ≠ 0) (hz : z ≠ 0), + #f.support = 3 ↔ + ∃ (k m n : ℕ) (_ : k < m) (_ : m < n) (x y z : R) (_ : x ≠ 0) (_ : y ≠ 0) (_ : z ≠ 0), f = C x * X ^ k + C y * X ^ m + C z * X ^ n := by refine ⟨fun h => ?_, ?_⟩ · obtain ⟨k, x, hk, hx, rfl⟩ := card_support_eq.mp h diff --git a/Mathlib/Algebra/Polynomial/Eval.lean b/Mathlib/Algebra/Polynomial/Eval.lean index e6b4d34e657aa..3c5b199f6c28d 100644 --- a/Mathlib/Algebra/Polynomial/Eval.lean +++ b/Mathlib/Algebra/Polynomial/Eval.lean @@ -1038,6 +1038,14 @@ theorem eval_eq_zero_of_dvd_of_eval_eq_zero : p ∣ q → eval x p = 0 → eval theorem eval_geom_sum {R} [CommSemiring R] {n : ℕ} {x : R} : eval x (∑ i ∈ range n, X ^ i) = ∑ i ∈ range n, x ^ i := by simp [eval_finset_sum] +variable [NoZeroDivisors R] + +lemma root_mul : IsRoot (p * q) a ↔ IsRoot p a ∨ IsRoot q a := by + simp_rw [IsRoot, eval_mul, mul_eq_zero] + +lemma root_or_root_of_root_mul (h : IsRoot (p * q) a) : IsRoot p a ∨ IsRoot q a := + root_mul.1 h + end end Eval @@ -1155,4 +1163,50 @@ alias mul_X_sub_int_cast_comp := mul_X_sub_intCast_comp end Ring +section +variable [Semiring R] [CommRing S] [IsDomain S] (φ : R →+* S) {f : R[X]} + +lemma isUnit_of_isUnit_leadingCoeff_of_isUnit_map (hf : IsUnit f.leadingCoeff) + (H : IsUnit (map φ f)) : IsUnit f := by + have dz := degree_eq_zero_of_isUnit H + rw [degree_map_eq_of_leadingCoeff_ne_zero] at dz + · rw [eq_C_of_degree_eq_zero dz] + refine IsUnit.map C ?_ + convert hf + change coeff f 0 = coeff f (natDegree f) + rw [(degree_eq_iff_natDegree_eq _).1 dz] + · rfl + rintro rfl + simp at H + · intro h + have u : IsUnit (φ f.leadingCoeff) := IsUnit.map φ hf + rw [h] at u + simp at u + +end + +section +variable [CommRing R] [IsDomain R] [CommRing S] [IsDomain S] (φ : R →+* S) + +/-- A polynomial over an integral domain `R` is irreducible if it is monic and +irreducible after mapping into an integral domain `S`. + +A special case of this lemma is that a polynomial over `ℤ` is irreducible if +it is monic and irreducible over `ℤ/pℤ` for some prime `p`. +-/ +lemma Monic.irreducible_of_irreducible_map (f : R[X]) (h_mon : Monic f) + (h_irr : Irreducible (f.map φ)) : Irreducible f := by + refine ⟨h_irr.not_unit ∘ IsUnit.map (mapRingHom φ), fun a b h => ?_⟩ + dsimp [Monic] at h_mon + have q := (leadingCoeff_mul a b).symm + rw [← h, h_mon] at q + refine (h_irr.isUnit_or_isUnit <| + (congr_arg (Polynomial.map φ) h).trans (Polynomial.map_mul φ)).imp ?_ ?_ <;> + apply isUnit_of_isUnit_leadingCoeff_of_isUnit_map <;> + apply isUnit_of_mul_eq_one + · exact q + · rw [mul_comm] + exact q + +end end Polynomial diff --git a/Mathlib/Algebra/Polynomial/Expand.lean b/Mathlib/Algebra/Polynomial/Expand.lean index e1db94a64141b..4b443cdf08aa9 100644 --- a/Mathlib/Algebra/Polynomial/Expand.lean +++ b/Mathlib/Algebra/Polynomial/Expand.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ +import Mathlib.Algebra.CharP.Lemmas import Mathlib.RingTheory.Polynomial.Basic -import Mathlib.RingTheory.LocalRing.RingHom.Basic /-! # Expand a polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`. @@ -269,19 +269,21 @@ section IsDomain variable (R : Type u) [CommRing R] [IsDomain R] -theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) : - IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by - refine ⟨fun f hf1 => ?_⟩; norm_cast at hf1 +theorem isLocalHom_expand {p : ℕ} (hp : 0 < p) : IsLocalHom (expand R p) := by + refine ⟨fun f hf1 => ?_⟩ have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1) rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2 rw [hf2, isUnit_C] at hf1; rw [expand_eq_C hp] at hf2; rwa [hf2, isUnit_C] +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_expand := isLocalHom_expand + variable {R} theorem of_irreducible_expand {p : ℕ} (hp : p ≠ 0) {f : R[X]} (hf : Irreducible (expand R p f)) : Irreducible f := - let _ := isLocalRingHom_expand R hp.bot_lt - of_irreducible_map (↑(expand R p)) hf + let _ := isLocalHom_expand R hp.bot_lt + hf.of_map theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} : Irreducible (expand R (p ^ n) f) → Irreducible f := diff --git a/Mathlib/Algebra/Polynomial/FieldDivision.lean b/Mathlib/Algebra/Polynomial/FieldDivision.lean index 06134da2f5675..b0f395c366efb 100644 --- a/Mathlib/Algebra/Polynomial/FieldDivision.lean +++ b/Mathlib/Algebra/Polynomial/FieldDivision.lean @@ -195,13 +195,17 @@ instance instNormalizationMonoid : NormalizationMonoid R[X] where theorem coe_normUnit {p : R[X]} : (normUnit p : R[X]) = C ↑(normUnit p.leadingCoeff) := by simp [normUnit] +@[simp] theorem leadingCoeff_normalize (p : R[X]) : - leadingCoeff (normalize p) = normalize (leadingCoeff p) := by simp + leadingCoeff (normalize p) = normalize (leadingCoeff p) := by simp [normalize_apply] theorem Monic.normalize_eq_self {p : R[X]} (hp : p.Monic) : normalize p = p := by simp only [Polynomial.coe_normUnit, normalize_apply, hp.leadingCoeff, normUnit_one, Units.val_one, Polynomial.C.map_one, mul_one] +@[deprecated Polynomial.Monic.normalize_eq_self (since := "2024-10-21")] +alias normalize_monic := Monic.normalize_eq_self + theorem roots_normalize {p : R[X]} : (normalize p).roots = p.roots := by rw [normalize_apply, mul_comm, coe_normUnit, roots_C_mul _ (normUnit (leadingCoeff p)).ne_zero] @@ -323,8 +327,8 @@ instance instEuclideanDomain : EuclideanDomain R[X] := r := _ r_wellFounded := degree_lt_wf quotient_mul_add_remainder_eq := quotient_mul_add_remainder_eq_aux - remainder_lt := fun p q hq => remainder_lt_aux _ hq - mul_left_not_lt := fun p q hq => not_lt_of_ge (degree_le_mul_left _ hq) } + remainder_lt := fun _ _ hq => remainder_lt_aux _ hq + mul_left_not_lt := fun _ _ hq => not_lt_of_ge (degree_le_mul_left _ hq) } theorem mod_eq_self_iff (hq0 : q ≠ 0) : p % q = p ↔ degree p < degree q := ⟨fun h => h ▸ EuclideanDomain.mod_lt _ hq0, fun h => by @@ -524,8 +528,6 @@ theorem coe_normUnit_of_ne_zero [DecidableEq R] (hp : p ≠ 0) : have : p.leadingCoeff ≠ 0 := mt leadingCoeff_eq_zero.mp hp simp [CommGroupWithZero.coe_normUnit _ this] -theorem normalize_monic [DecidableEq R] (h : Monic p) : normalize p = p := by simp [h] - theorem map_dvd_map' [Field k] (f : R →+* k) {x y : R[X]} : x.map f ∣ y.map f ↔ x ∣ y := by by_cases H : x = 0 · rw [H, Polynomial.map_zero, zero_dvd_iff, zero_dvd_iff, map_eq_zero] @@ -535,7 +537,9 @@ theorem map_dvd_map' [Field k] (f : R →+* k) {x y : R[X]} : x.map f ∣ y.map leadingCoeff_map, ← map_inv₀ f, ← map_C, ← Polynomial.map_mul, map_dvd_map _ f.injective (monic_mul_leadingCoeff_inv H)] -theorem degree_normalize [DecidableEq R] : degree (normalize p) = degree p := by simp +@[simp] +theorem degree_normalize [DecidableEq R] : degree (normalize p) = degree p := by + simp [normalize_apply] theorem prime_of_degree_eq_one (hp1 : degree p = 1) : Prime p := by classical diff --git a/Mathlib/Algebra/Polynomial/GroupRingAction.lean b/Mathlib/Algebra/Polynomial/GroupRingAction.lean index 586acacc30c03..a14a7d6e696b8 100644 --- a/Mathlib/Algebra/Polynomial/GroupRingAction.lean +++ b/Mathlib/Algebra/Polynomial/GroupRingAction.lean @@ -128,9 +128,9 @@ protected noncomputable def polynomial (g : P →+*[M] Q) : P[X] →+*[M] Q[X] w smul_mul', smul_C, smul_pow', smul_X, coe_fn_coe] -- Porting note: added `.toRingHom` map_zero' := Polynomial.map_zero g.toRingHom - map_add' p q := Polynomial.map_add g.toRingHom + map_add' _ _ := Polynomial.map_add g.toRingHom map_one' := Polynomial.map_one g.toRingHom - map_mul' p q := Polynomial.map_mul g.toRingHom + map_mul' _ _ := Polynomial.map_mul g.toRingHom @[simp] theorem coe_polynomial (g : P →+*[M] Q) : (g.polynomial : P[X] → Q[X]) = map g := rfl diff --git a/Mathlib/Algebra/Polynomial/Induction.lean b/Mathlib/Algebra/Polynomial/Induction.lean index a4fc244b867ab..572d1091e012c 100644 --- a/Mathlib/Algebra/Polynomial/Induction.lean +++ b/Mathlib/Algebra/Polynomial/Induction.lean @@ -4,7 +4,7 @@ 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.Basic -import Mathlib.RingTheory.Ideal.Basic +import Mathlib.RingTheory.Ideal.Span /-! # Induction on polynomials diff --git a/Mathlib/Algebra/Polynomial/Laurent.lean b/Mathlib/Algebra/Polynomial/Laurent.lean index c5523266588fe..52e9ac7978fee 100644 --- a/Mathlib/Algebra/Polynomial/Laurent.lean +++ b/Mathlib/Algebra/Polynomial/Laurent.lean @@ -6,7 +6,7 @@ Authors: Damiano Testa import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.Algebra.Polynomial.Reverse import Mathlib.Algebra.Polynomial.Inductions -import Mathlib.RingTheory.Localization.Basic +import Mathlib.RingTheory.Localization.Defs /-! # Laurent polynomials @@ -87,7 +87,6 @@ scoped[LaurentPolynomial] notation:9000 R "[T;T⁻¹]" => LaurentPolynomial R open LaurentPolynomial --- Porting note: `ext` no longer applies `Finsupp.ext` automatically @[ext] theorem LaurentPolynomial.ext [Semiring R] {p q : R[T;T⁻¹]} (h : ∀ a, p a = q a) : p = q := Finsupp.ext h @@ -206,20 +205,19 @@ theorem _root_.Polynomial.toLaurent_X : (toLaurent Polynomial.X : R[T;T⁻¹]) = have : (Polynomial.X : R[X]) = monomial 1 1 := by simp [← C_mul_X_pow_eq_monomial] simp [this, Polynomial.toLaurent_C_mul_T] --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem _root_.Polynomial.toLaurent_one : (Polynomial.toLaurent : R[X] → R[T;T⁻¹]) 1 = 1 := map_one Polynomial.toLaurent --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem _root_.Polynomial.toLaurent_C_mul_eq (r : R) (f : R[X]) : toLaurent (Polynomial.C r * f) = C r * toLaurent f := by simp only [_root_.map_mul, Polynomial.toLaurent_C] --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem _root_.Polynomial.toLaurent_X_pow (n : ℕ) : toLaurent (X ^ n : R[X]) = T n := by simp only [map_pow, Polynomial.toLaurent_X, T_pow, mul_one] --- @[simp] -- Porting note (#10618): simp can prove this theorem _root_.Polynomial.toLaurent_C_mul_X_pow (n : ℕ) (r : R) : toLaurent (Polynomial.C r * X ^ n) = C r * T n := by simp only [_root_.map_mul, Polynomial.toLaurent_C, Polynomial.toLaurent_X_pow] @@ -278,7 +276,7 @@ protected theorem induction_on' {M : R[T;T⁻¹] → Prop} (p : R[T;T⁻¹]) exact (mul_one _).symm theorem commute_T (n : ℤ) (f : R[T;T⁻¹]) : Commute (T n) f := - f.induction_on' (fun p q Tp Tq => Commute.add_right Tp Tq) fun m a => + f.induction_on' (fun _ _ Tp Tq => Commute.add_right Tp Tq) fun m a => show T n * _ = _ by rw [T, T, ← single_eq_C, single_mul_single, single_mul_single, single_mul_single] simp [add_comm] @@ -297,7 +295,7 @@ def trunc : R[T;T⁻¹] →+ R[X] := theorem trunc_C_mul_T (n : ℤ) (r : R) : trunc (C r * T n) = ite (0 ≤ n) (monomial n.toNat r) 0 := by apply (toFinsuppIso R).injective rw [← single_eq_C_mul_T, trunc, AddMonoidHom.coe_comp, Function.comp_apply] - -- Porting note (#10691): was `rw` + -- Porting note (#11224): was `rw` erw [comapDomain.addMonoidHom_apply Int.ofNat_injective] rw [toFinsuppIso_apply] -- Porting note: rewrote proof below relative to mathlib3. @@ -492,7 +490,7 @@ variable [CommSemiring R] instance algebraPolynomial (R : Type*) [CommSemiring R] : Algebra R[X] R[T;T⁻¹] := { Polynomial.toLaurent with commutes' := fun f l => by simp [mul_comm] - smul_def' := fun f l => rfl } + smul_def' := fun _ _ => rfl } theorem algebraMap_X_pow (n : ℕ) : algebraMap R[X] R[T;T⁻¹] (X ^ n) = T n := Polynomial.toLaurent_X_pow n diff --git a/Mathlib/Algebra/Polynomial/Mirror.lean b/Mathlib/Algebra/Polynomial/Mirror.lean index 542e5670d1017..9f3b754cd0a0a 100644 --- a/Mathlib/Algebra/Polynomial/Mirror.lean +++ b/Mathlib/Algebra/Polynomial/Mirror.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ import Mathlib.Algebra.BigOperators.NatAntidiagonal -import Mathlib.Algebra.Polynomial.RingDivision +import Mathlib.Algebra.Polynomial.Reverse /-! # "Mirror" of a univariate polynomial @@ -139,7 +139,7 @@ theorem mirror_leadingCoeff : p.mirror.leadingCoeff = p.trailingCoeff := by rw [← p.mirror_mirror, mirror_trailingCoeff, p.mirror_mirror] theorem coeff_mul_mirror : - (p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun n => (· ^ 2) := by + (p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun _ => (· ^ 2) := by rw [coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk] refine (Finset.sum_congr rfl fun n hn => ?_).trans diff --git a/Mathlib/Algebra/Polynomial/Module/AEval.lean b/Mathlib/Algebra/Polynomial/Module/AEval.lean index 17b934cb8564e..b9ebc29dbacfa 100644 --- a/Mathlib/Algebra/Polynomial/Module/AEval.lean +++ b/Mathlib/Algebra/Polynomial/Module/AEval.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Richard M. Hill. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Richard M. Hill -/ +import Mathlib.Algebra.Module.Submodule.Invariant import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.RingTheory.Finiteness @@ -94,6 +95,15 @@ def _root_.LinearMap.ofAEval {N} [AddCommMonoid N] [Module R N] [Module R[X] N] LinearMap.comp_apply, LinearEquiv.coe_toLinearMap] at h ⊢ simp_rw [pow_succ, ← mul_assoc, mul_smul _ X, ← hf, ← of_symm_X_smul, ← h] +/-- Construct an `R[X]`-linear equivalence out of `AEval R M a` from a `R`-linear map out of `M`. -/ +def _root_.LinearEquiv.ofAEval {N} [AddCommMonoid N] [Module R N] [Module R[X] N] + [IsScalarTower R R[X] N] (f : M ≃ₗ[R] N) (hf : ∀ m : M, f (a • m) = (X : R[X]) • f m) : + AEval R M a ≃ₗ[R[X]] N where + __ := LinearMap.ofAEval a f hf + invFun := (of R M a) ∘ f.symm + left_inv x := by simp [LinearMap.ofAEval] + right_inv x := by simp [LinearMap.ofAEval] + lemma annihilator_eq_ker_aeval [FaithfulSMul A M] : annihilator R[X] (AEval R M a) = RingHom.ker (aeval a) := by ext p @@ -111,60 +121,51 @@ lemma annihilator_top_eq_ker_aeval [FaithfulSMul A M] : section Submodule -variable {p : Submodule R M} {q : Submodule R[X] <| AEval R M a} - -variable (R M) in -/-- We can turn an `R[X]`-submodule into an `R`-submodule by forgetting the action of `X`. -/ -def comapSubmodule : - CompleteLatticeHom (Submodule R[X] <| AEval R M a) (Submodule R M) := - (Submodule.orderIsoMapComap (of R M a)).symm.toCompleteLatticeHom.comp <| - Submodule.restrictScalarsLatticeHom R R[X] (AEval R M a) - -@[simp] lemma mem_comapSubmodule {x : M} : - x ∈ comapSubmodule R M a q ↔ of R M a x ∈ q := - Iff.rfl +variable (R M) -@[simp] lemma comapSubmodule_le_comap : - comapSubmodule R M a q ≤ (comapSubmodule R M a q).comap (Algebra.lsmul R R M a) := by - intro m hm - simpa only [Submodule.mem_comap, Algebra.lsmul_coe, mem_comapSubmodule, ← X_smul_of] using - q.smul_mem (X : R[X]) hm - -/-- An `R`-submodule which is stable under the action of `a` can be promoted to an -`R[X]`-submodule. -/ -def mapSubmodule (hp : p ≤ p.comap (Algebra.lsmul R R M a)) : Submodule R[X] <| AEval R M a := - { toAddSubmonoid := p.toAddSubmonoid.map (of R M a) - smul_mem' := by - rintro f - ⟨m : M, h : m ∈ p, rfl⟩ - simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup, AddSubmonoid.mem_map, - Submodule.mem_toAddSubmonoid] - exact ⟨aeval a f • m, aeval_apply_smul_mem_of_le_comap' h f a hp, of_aeval_smul a f m⟩ } - -variable (hp : p ≤ p.comap (Algebra.lsmul R R M a)) - -@[simp] lemma mem_mapSubmodule {m : AEval R M a} : - m ∈ mapSubmodule a hp ↔ (of R M a).symm m ∈ p := +/-- The natural order isomorphism between the two ways to represent invariant submodules. -/ +def mapSubmodule : + (Algebra.lsmul R R M a).invtSubmodule ≃o Submodule R[X] (AEval R M a) where + toFun p := + { toAddSubmonoid := (p : Submodule R M).toAddSubmonoid.map (of R M a) + smul_mem' := by + rintro f - ⟨m : M, h : m ∈ (p : Submodule R M), rfl⟩ + simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup, + AddSubmonoid.mem_map, Submodule.mem_toAddSubmonoid] + exact ⟨aeval a f • m, aeval_apply_smul_mem_of_le_comap' h f a p.2, of_aeval_smul a f m⟩ } + invFun q := ⟨(Submodule.orderIsoMapComap (of R M a)).symm (q.restrictScalars R), fun m hm ↦ by + simpa [← X_smul_of] using q.smul_mem (X : R[X]) hm⟩ + left_inv p := by ext; simp + right_inv q := by ext; aesop + map_rel_iff' {p p'} := ⟨fun h x hx ↦ by aesop, fun h x hx ↦ by aesop⟩ + +@[simp] lemma mem_mapSubmodule_apply {p : (Algebra.lsmul R R M a).invtSubmodule} {m : AEval R M a} : + m ∈ mapSubmodule R M a p ↔ (of R M a).symm m ∈ (p : Submodule R M) := ⟨fun ⟨_, hm, hm'⟩ ↦ hm'.symm ▸ hm, fun hm ↦ ⟨(of R M a).symm m, hm, rfl⟩⟩ -@[simp] lemma mapSubmodule_comapSubmodule (h := comapSubmodule_le_comap a) : - mapSubmodule a (p := comapSubmodule R M a q) h = q := by - ext; simp - -@[simp] lemma comapSubmodule_mapSubmodule : - comapSubmodule R M a (mapSubmodule a hp) = p := by - ext; simp - -variable (R M) - -lemma injective_comapSubmodule : Injective (comapSubmodule R M a) := by - intro q₁ q₂ hq - rw [← mapSubmodule_comapSubmodule (q := q₁), ← mapSubmodule_comapSubmodule (q := q₂)] - simp_rw [hq] +@[simp] lemma mem_mapSubmodule_symm_apply {q : Submodule R[X] (AEval R M a)} {m : M} : + m ∈ ((mapSubmodule R M a).symm q : Submodule R M) ↔ of R M a m ∈ q := + Iff.rfl -lemma range_comapSubmodule : - range (comapSubmodule R M a) = {p | p ≤ p.comap (Algebra.lsmul R R M a)} := - le_antisymm (fun _ ⟨_, hq⟩ ↦ hq ▸ comapSubmodule_le_comap a) - (fun _ hp ↦ ⟨mapSubmodule a hp, comapSubmodule_mapSubmodule a hp⟩) +variable {R M} +variable (p : Submodule R M) (hp : p ∈ (Algebra.lsmul R R M a).invtSubmodule) + +/-- The natural `R`-linear equivalence between the two ways to represent an invariant submodule. -/ +def equiv_mapSubmodule : + p ≃ₗ[R] mapSubmodule R M a ⟨p, hp⟩ where + toFun x := ⟨of R M a x, by simp⟩ + invFun x := ⟨((of R M _).symm (x : AEval R M a)), by obtain ⟨x, hx⟩ := x; simpa using hx⟩ + left_inv x := rfl + right_inv x := rfl + map_add' x y := rfl + map_smul' t x := rfl + +/-- The natural `R[X]`-linear equivalence between the two ways to represent an invariant submodule. +-/ +noncomputable def restrict_equiv_mapSubmodule : + (AEval R p <| (Algebra.lsmul R R M a).restrict hp) ≃ₗ[R[X]] mapSubmodule R M a ⟨p, hp⟩ := + LinearEquiv.ofAEval ((Algebra.lsmul R R M a).restrict hp) (equiv_mapSubmodule a p hp) + (fun x ↦ by simp [equiv_mapSubmodule, X_smul_of]) end Submodule diff --git a/Mathlib/Algebra/Polynomial/Module/Basic.lean b/Mathlib/Algebra/Polynomial/Module/Basic.lean index f21958832dbda..047d5c7f86864 100644 --- a/Mathlib/Algebra/Polynomial/Module/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Module/Basic.lean @@ -14,7 +14,7 @@ This is defined as a type alias `PolynomialModule R M := ℕ →₀ M`, since th module structures on `ℕ →₀ M` of interest. See the docstring of `PolynomialModule` for details. -/ universe u v -open Polynomial BigOperators +open Polynomial /-- The `R[X]`-module `M[X]` for an `R`-module `M`. This is isomorphic (as an `R`-module) to `M[X]` when `M` is a ring. @@ -57,7 +57,7 @@ instance instFunLike : FunLike (PolynomialModule R M) ℕ M := Finsupp.instFunLike instance : CoeFun (PolynomialModule R M) fun _ => ℕ → M := - Finsupp.instCoeFun + inferInstanceAs <| CoeFun (_ →₀ _) _ theorem zero_apply (i : ℕ) : (0 : PolynomialModule R M) i = 0 := Finsupp.zero_apply @@ -250,7 +250,7 @@ theorem map_smul (f : M →ₗ[R] M') (p : R[X]) (q : PolynomialModule R M) : @[simps! (config := .lemmasOnly)] def eval (r : R) : PolynomialModule R M →ₗ[R] M where toFun p := p.sum fun i m => r ^ i • m - map_add' x y := Finsupp.sum_add_index' (fun _ => smul_zero _) fun _ _ _ => smul_add _ _ _ + map_add' _ _ := Finsupp.sum_add_index' (fun _ => smul_zero _) fun _ _ _ => smul_add _ _ _ map_smul' s m := by refine (Finsupp.sum_smul_index' ?_).trans ?_ · exact fun i => smul_zero _ @@ -312,8 +312,7 @@ noncomputable def comp (p : R[X]) : PolynomialModule R M →ₗ[R] PolynomialMod LinearMap.comp ((eval p).restrictScalars R) (map R[X] (lsingle R 0)) theorem comp_single (p : R[X]) (i : ℕ) (m : M) : comp p (single R i m) = p ^ i • single R 0 m := by - rw [comp_apply] - erw [map_single, eval_single] + rw [comp_apply, map_single, eval_single] rfl theorem comp_eval (p : R[X]) (q : PolynomialModule R M) (r : R) : diff --git a/Mathlib/Algebra/Polynomial/Monic.lean b/Mathlib/Algebra/Polynomial/Monic.lean index eb0f0cf67b6b0..9b7ed2ba528e5 100644 --- a/Mathlib/Algebra/Polynomial/Monic.lean +++ b/Mathlib/Algebra/Polynomial/Monic.lean @@ -130,6 +130,19 @@ theorem Monic.of_mul_monic_right (hq : q.Monic) (hpq : (p * q).Monic) : p.Monic namespace Monic +lemma comp (hp : p.Monic) (hq : q.Monic) (h : q.natDegree ≠ 0) : (p.comp q).Monic := by + nontriviality R + have : (p.comp q).natDegree = p.natDegree * q.natDegree := + natDegree_comp_eq_of_mul_ne_zero <| by simp [hp.leadingCoeff, hq.leadingCoeff] + rw [Monic.def, Polynomial.leadingCoeff, this, coeff_comp_degree_mul_degree h, hp.leadingCoeff, + hq.leadingCoeff, one_pow, mul_one] + +lemma comp_X_add_C (hp : p.Monic) (r : R) : (p.comp (X + C r)).Monic := by + nontriviality R + refine hp.comp (monic_X_add_C _) fun ha ↦ ?_ + rw [natDegree_X_add_C] at ha + exact one_ne_zero ha + @[simp] theorem natDegree_eq_zero_iff_eq_one (hp : p.Monic) : p.natDegree = 0 ↔ p = 1 := by constructor <;> intro h @@ -262,6 +275,78 @@ theorem Monic.nextCoeff_prod (s : Finset ι) (f : ι → R[X]) (h : ∀ i ∈ s, nextCoeff (∏ i ∈ s, f i) = ∑ i ∈ s, nextCoeff (f i) := Monic.nextCoeff_multiset_prod s.1 f h +variable [NoZeroDivisors R] {p q : R[X]} + +lemma irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) : + Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by + refine + ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h => + ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg => + (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) ?_ ?_ ?_).symm.imp + (isUnit_of_mul_eq_one f _) + (isUnit_of_mul_eq_one g _)⟩⟩ + · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, mul_comm, ← hfg, ← Monic] + · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, ← hfg, ← Monic] + · rw [mul_mul_mul_comm, ← C_mul, ← leadingCoeff_mul, ← hfg, hp.leadingCoeff, C_1, mul_one, + mul_comm, ← hfg] + + +lemma Monic.irreducible_iff_natDegree (hp : p.Monic) : + Irreducible p ↔ + p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by + by_cases hp1 : p = 1; · simp [hp1] + rw [irreducible_of_monic hp hp1, and_iff_right hp1] + refine forall₄_congr fun a b ha hb => ?_ + rw [ha.natDegree_eq_zero_iff_eq_one, hb.natDegree_eq_zero_iff_eq_one] + +lemma Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧ + ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by + simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two] + apply and_congr_right' + constructor <;> intro h f g hf hg he <;> subst he + · rw [hf.natDegree_mul hg, add_le_add_iff_right] + exact fun ha => (h f g hf hg rfl).elim (ha.1.trans_le ha.2).ne' ha.1.ne' + · simp_rw [hf.natDegree_mul hg, pos_iff_ne_zero] at h + contrapose! h + obtain hl | hl := le_total f.natDegree g.natDegree + · exact ⟨g, f, hg, hf, mul_comm g f, h.1, add_le_add_left hl _⟩ + · exact ⟨f, g, hf, hg, rfl, h.2, add_le_add_right hl _⟩ + +/-- Alternate phrasing of `Polynomial.Monic.irreducible_iff_natDegree'` where we only have to check +one divisor at a time. -/ +lemma Monic.irreducible_iff_lt_natDegree_lt {p : R[X]} (hp : p.Monic) (hp1 : p ≠ 1) : + Irreducible p ↔ ∀ q, Monic q → natDegree q ∈ Finset.Ioc 0 (natDegree p / 2) → ¬ q ∣ p := by + rw [hp.irreducible_iff_natDegree', and_iff_right hp1] + constructor + · rintro h g hg hdg ⟨f, rfl⟩ + exact h f g (hg.of_mul_monic_left hp) hg (mul_comm f g) hdg + · rintro h f g - hg rfl hdg + exact h g hg hdg (dvd_mul_left g f) + +lemma Monic.not_irreducible_iff_exists_add_mul_eq_coeff (hm : p.Monic) (hnd : p.natDegree = 2) : + ¬Irreducible p ↔ ∃ c₁ c₂, p.coeff 0 = c₁ * c₂ ∧ p.coeff 1 = c₁ + c₂ := by + cases subsingleton_or_nontrivial R + · simp [natDegree_of_subsingleton] at hnd + rw [hm.irreducible_iff_natDegree', and_iff_right, hnd] + · push_neg + constructor + · rintro ⟨a, b, ha, hb, rfl, hdb⟩ + simp only [zero_lt_two, Nat.div_self, Nat.Ioc_succ_singleton, zero_add, mem_singleton] at hdb + have hda := hnd + rw [ha.natDegree_mul hb, hdb] at hda + use a.coeff 0, b.coeff 0, mul_coeff_zero a b + simpa only [nextCoeff, hnd, add_right_cancel hda, hdb] using ha.nextCoeff_mul hb + · rintro ⟨c₁, c₂, hmul, hadd⟩ + refine + ⟨X + C c₁, X + C c₂, monic_X_add_C _, monic_X_add_C _, ?_, ?_⟩ + · rw [p.as_sum_range_C_mul_X_pow, hnd, Finset.sum_range_succ, Finset.sum_range_succ, + Finset.sum_range_one, ← hnd, hm.coeff_natDegree, hnd, hmul, hadd, C_mul, C_add, C_1] + ring + · rw [mem_Ioc, natDegree_X_add_C _] + simp + · rintro rfl + simp [natDegree_one] at hnd + end CommSemiring section Semiring @@ -353,6 +438,9 @@ theorem not_isUnit_X_pow_sub_one (R : Type*) [CommRing R] [Nontrivial R] (n : apply hn rw [← @natDegree_one R, ← (monic_X_pow_sub_C _ hn).eq_one_of_isUnit h, natDegree_X_pow_sub_C] +lemma Monic.comp_X_sub_C {p : R[X]} (hp : p.Monic) (r : R) : (p.comp (X - C r)).Monic := by + simpa using hp.comp_X_add_C (-r) + theorem Monic.sub_of_left {p q : R[X]} (hp : Monic p) (hpq : degree q < degree p) : Monic (p - q) := by rw [sub_eq_add_neg] diff --git a/Mathlib/Algebra/Polynomial/Monomial.lean b/Mathlib/Algebra/Polynomial/Monomial.lean index 29b15cda6f45e..535103330d899 100644 --- a/Mathlib/Algebra/Polynomial/Monomial.lean +++ b/Mathlib/Algebra/Polynomial/Monomial.lean @@ -56,12 +56,9 @@ theorem ringHom_ext {S} [Semiring S] {f g : R[X] →+* S} (h₁ : ∀ a, f (C a) set f' := f.comp (toFinsuppIso R).symm.toRingHom with hf' set g' := g.comp (toFinsuppIso R).symm.toRingHom with hg' have A : f' = g' := by - -- Porting note: Was `ext; simp [..]; simpa [..] using h₂`. - ext : 1 - · ext - simp [f', g', h₁, RingEquiv.toRingHom_eq_coe] - · refine MonoidHom.ext_mnat ?_ - simpa [RingEquiv.toRingHom_eq_coe] using h₂ + ext + simp [f', g', h₁, RingEquiv.toRingHom_eq_coe] + simpa using h₂ have B : f = f'.comp (toFinsuppIso R) := by rw [hf', RingHom.comp_assoc] ext x diff --git a/Mathlib/Algebra/Polynomial/Reverse.lean b/Mathlib/Algebra/Polynomial/Reverse.lean index 2dba679853097..2d9684409878b 100644 --- a/Mathlib/Algebra/Polynomial/Reverse.lean +++ b/Mathlib/Algebra/Polynomial/Reverse.lean @@ -78,7 +78,6 @@ theorem revAt_add {N O n o : ℕ} (hn : n ≤ N) (ho : o ≤ O) : rw [add_assoc, add_left_comm n' o, ← add_assoc, revAt_le (le_add_right rfl.le)] repeat' rw [add_tsub_cancel_left] --- @[simp] -- Porting note (#10618): simp can prove this theorem revAt_zero (N : ℕ) : revAt N 0 = N := by simp /-- `reflect N f` is the polynomial such that `(reflect N f).coeff i = f.coeff (revAt N i)`. @@ -123,7 +122,6 @@ theorem reflect_C_mul (f : R[X]) (r : R) (N : ℕ) : reflect N (C r * f) = C r * ext simp only [coeff_reflect, coeff_C_mul] --- @[simp] -- Porting note (#10618): simp can prove this (once `reflect_monomial` is in simp scope) theorem reflect_C_mul_X_pow (N n : ℕ) {c : R} : reflect N (C c * X ^ n) = C c * X ^ revAt N n := by ext rw [reflect_C_mul, coeff_C_mul, coeff_C_mul, coeff_X_pow, coeff_reflect] @@ -149,8 +147,8 @@ theorem reflect_monomial (N n : ℕ) : reflect N ((X : R[X]) ^ n) = X ^ revAt N theorem reflect_mul_induction (cf cg : ℕ) : ∀ N O : ℕ, ∀ f g : R[X], - f.support.card ≤ cf.succ → - g.support.card ≤ cg.succ → + #f.support ≤ cf.succ → + #g.support ≤ cg.succ → f.natDegree ≤ N → g.natDegree ≤ O → reflect (N + O) (f * g) = reflect N f * reflect O g := by induction' cf with cf hcf diff --git a/Mathlib/Algebra/Polynomial/RingDivision.lean b/Mathlib/Algebra/Polynomial/RingDivision.lean index 87a240f259415..c557bfff9de6c 100644 --- a/Mathlib/Algebra/Polynomial/RingDivision.lean +++ b/Mathlib/Algebra/Polynomial/RingDivision.lean @@ -4,7 +4,6 @@ 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.BigOperators import Mathlib.Algebra.Polynomial.Degree.Lemmas import Mathlib.Algebra.Polynomial.Div @@ -27,26 +26,6 @@ universe u v w z variable {R : Type u} {S : Type v} {T : Type w} {a b : R} {n : ℕ} -section Semiring - -variable [Semiring R] {p q : R[X]} - -theorem Monic.comp (hp : p.Monic) (hq : q.Monic) (h : q.natDegree ≠ 0) : (p.comp q).Monic := by - nontriviality R - have : (p.comp q).natDegree = p.natDegree * q.natDegree := by - apply natDegree_comp_eq_of_mul_ne_zero - simp [hp.leadingCoeff, hq.leadingCoeff] - rw [Monic.def, Polynomial.leadingCoeff, this, coeff_comp_degree_mul_degree h, hp.leadingCoeff, - hq.leadingCoeff, one_pow, mul_one] - -theorem Monic.comp_X_add_C (hp : p.Monic) (r : R) : (p.comp (X + C r)).Monic := by - nontriviality R - refine hp.comp (monic_X_add_C _) fun ha => ?_ - rw [natDegree_X_add_C] at ha - exact one_ne_zero ha - -end Semiring - section CommRing variable [CommRing R] {p q : R[X]} @@ -63,26 +42,6 @@ theorem degree_pos_of_aeval_root [Algebra R S] {p : R[X]} (hp : p ≠ 0) {z : S} (inj : ∀ x : R, algebraMap R S x = 0 → x = 0) : 0 < p.degree := natDegree_pos_iff_degree_pos.mp (natDegree_pos_of_aeval_root hp hz inj) -theorem modByMonic_eq_of_dvd_sub (hq : q.Monic) {p₁ p₂ : R[X]} (h : q ∣ p₁ - p₂) : - p₁ %ₘ q = p₂ %ₘ q := by - nontriviality R - obtain ⟨f, sub_eq⟩ := h - refine (div_modByMonic_unique (p₂ /ₘ q + f) _ hq ⟨?_, degree_modByMonic_lt _ hq⟩).2 - rw [sub_eq_iff_eq_add.mp sub_eq, mul_add, ← add_assoc, modByMonic_add_div _ hq, add_comm] - -theorem add_modByMonic (p₁ p₂ : R[X]) : (p₁ + p₂) %ₘ q = p₁ %ₘ q + p₂ %ₘ q := by - by_cases hq : q.Monic - · cases' subsingleton_or_nontrivial R with hR hR - · simp only [eq_iff_true_of_subsingleton] - · exact - (div_modByMonic_unique (p₁ /ₘ q + p₂ /ₘ q) _ hq - ⟨by - rw [mul_add, add_left_comm, add_assoc, modByMonic_add_div _ hq, ← add_assoc, - add_comm (q * _), modByMonic_add_div _ hq], - (degree_add_le _ _).trans_lt - (max_lt (degree_modByMonic_lt _ hq) (degree_modByMonic_lt _ hq))⟩).2 - · simp_rw [modByMonic_eq_of_not_monic _ hq] - theorem smul_modByMonic (c : R) (p : R[X]) : c • p %ₘ q = c • (p %ₘ q) := by by_cases hq : q.Monic · cases' subsingleton_or_nontrivial R with hR hR @@ -100,12 +59,6 @@ def modByMonicHom (q : R[X]) : R[X] →ₗ[R] R[X] where map_add' := add_modByMonic map_smul' := smul_modByMonic -theorem neg_modByMonic (p mod : R[X]) : (-p) %ₘ mod = - (p %ₘ mod) := - (modByMonicHom mod).map_neg p - -theorem sub_modByMonic (a b mod : R[X]) : (a - b) %ₘ mod = a %ₘ mod - b %ₘ mod := - (modByMonicHom mod).map_sub a b - end section @@ -126,16 +79,6 @@ section NoZeroDivisors variable [Semiring R] [NoZeroDivisors R] {p q : R[X]} -instance : NoZeroDivisors R[X] where - eq_zero_or_eq_zero_of_mul_eq_zero h := by - rw [← leadingCoeff_eq_zero, ← leadingCoeff_eq_zero] - refine eq_zero_or_eq_zero_of_mul_eq_zero ?_ - rw [← leadingCoeff_zero, ← leadingCoeff_mul, h] - -theorem natDegree_mul (hp : p ≠ 0) (hq : q ≠ 0) : (p*q).natDegree = p.natDegree + q.natDegree := by - 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] - theorem trailingDegree_mul : (p * q).trailingDegree = p.trailingDegree + q.trailingDegree := by by_cases hp : p = 0 · rw [hp, zero_mul, trailingDegree_zero, top_add] @@ -145,345 +88,27 @@ theorem trailingDegree_mul : (p * q).trailingDegree = p.trailingDegree + q.trail trailingDegree_eq_natTrailingDegree (mul_ne_zero hp hq), natTrailingDegree_mul hp hq] apply WithTop.coe_add -@[simp] -theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by - classical - obtain rfl | hp := eq_or_ne p 0 - · obtain rfl | hn := eq_or_ne n 0 <;> simp [*] - exact natDegree_pow' <| by - rw [← leadingCoeff_pow, Ne, leadingCoeff_eq_zero]; exact pow_ne_zero _ hp - -theorem degree_le_mul_left (p : R[X]) (hq : q ≠ 0) : degree p ≤ degree (p * q) := by - classical - exact if hp : p = 0 then by simp only [hp, zero_mul, le_refl] - else by - rw [degree_mul, degree_eq_natDegree hp, degree_eq_natDegree hq] - exact WithBot.coe_le_coe.2 (Nat.le_add_right _ _) - -theorem natDegree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : p.natDegree ≤ q.natDegree := by - rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2 - rw [natDegree_mul h2.1 h2.2]; exact Nat.le_add_right _ _ - -theorem degree_le_of_dvd {p q : R[X]} (h1 : p ∣ q) (h2 : q ≠ 0) : degree p ≤ degree q := by - rcases h1 with ⟨q, rfl⟩; rw [mul_ne_zero_iff] at h2 - exact degree_le_mul_left p h2.2 - -theorem eq_zero_of_dvd_of_degree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : degree q < degree p) : - q = 0 := by - by_contra hc - exact (lt_iff_not_ge _ _).mp h₂ (degree_le_of_dvd h₁ hc) - -theorem eq_zero_of_dvd_of_natDegree_lt {p q : R[X]} (h₁ : p ∣ q) (h₂ : natDegree q < natDegree p) : - q = 0 := by - by_contra hc - exact (lt_iff_not_ge _ _).mp h₂ (natDegree_le_of_dvd h₁ hc) - -theorem not_dvd_of_degree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.degree < p.degree) : ¬p ∣ q := by - by_contra hcontra - exact h0 (eq_zero_of_dvd_of_degree_lt hcontra hl) - -theorem not_dvd_of_natDegree_lt {p q : R[X]} (h0 : q ≠ 0) (hl : q.natDegree < p.natDegree) : - ¬p ∣ q := by - by_contra hcontra - exact h0 (eq_zero_of_dvd_of_natDegree_lt hcontra hl) - -/-- This lemma is useful for working with the `intDegree` of a rational function. -/ -theorem natDegree_sub_eq_of_prod_eq {p₁ p₂ q₁ q₂ : R[X]} (hp₁ : p₁ ≠ 0) (hq₁ : q₁ ≠ 0) - (hp₂ : p₂ ≠ 0) (hq₂ : q₂ ≠ 0) (h_eq : p₁ * q₂ = p₂ * q₁) : - (p₁.natDegree : ℤ) - q₁.natDegree = (p₂.natDegree : ℤ) - q₂.natDegree := by - rw [sub_eq_sub_iff_add_eq_add] - norm_cast - rw [← natDegree_mul hp₁ hq₂, ← natDegree_mul hp₂ hq₁, h_eq] - -theorem natDegree_eq_zero_of_isUnit (h : IsUnit p) : natDegree p = 0 := by - nontriviality R - obtain ⟨q, hq⟩ := h.exists_right_inv - have := natDegree_mul (left_ne_zero_of_mul_eq_one hq) (right_ne_zero_of_mul_eq_one hq) - rw [hq, natDegree_one, eq_comm, add_eq_zero] at this - exact this.1 - -theorem degree_eq_zero_of_isUnit [Nontrivial R] (h : IsUnit p) : degree p = 0 := - (natDegree_eq_zero_iff_degree_le_zero.mp <| natDegree_eq_zero_of_isUnit h).antisymm - (zero_le_degree_iff.mpr h.ne_zero) - -@[simp] -theorem degree_coe_units [Nontrivial R] (u : R[X]ˣ) : degree (u : R[X]) = 0 := - degree_eq_zero_of_isUnit ⟨u, rfl⟩ - -/-- Characterization of a unit of a polynomial ring over an integral domain `R`. -See `Polynomial.isUnit_iff_coeff_isUnit_isNilpotent` when `R` is a commutative ring. -/ -theorem isUnit_iff : IsUnit p ↔ ∃ r : R, IsUnit r ∧ C r = p := - ⟨fun hp => - ⟨p.coeff 0, - let h := eq_C_of_natDegree_eq_zero (natDegree_eq_zero_of_isUnit hp) - ⟨isUnit_C.1 (h ▸ hp), h.symm⟩⟩, - fun ⟨_, hr, hrp⟩ => hrp ▸ isUnit_C.2 hr⟩ - -theorem not_isUnit_of_degree_pos (p : R[X]) - (hpl : 0 < p.degree) : ¬ IsUnit p := by - cases subsingleton_or_nontrivial R - · simp [Subsingleton.elim p 0] at hpl - intro h - simp [degree_eq_zero_of_isUnit h] at hpl - -theorem not_isUnit_of_natDegree_pos (p : R[X]) - (hpl : 0 < p.natDegree) : ¬ IsUnit p := - not_isUnit_of_degree_pos _ (natDegree_pos_iff_degree_pos.mp hpl) - -end NoZeroDivisors - -section NoZeroDivisors - -variable [CommSemiring R] [NoZeroDivisors R] {p q : R[X]} - -theorem irreducible_of_monic (hp : p.Monic) (hp1 : p ≠ 1) : - Irreducible p ↔ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f = 1 ∨ g = 1 := by - refine - ⟨fun h f g hf hg hp => (h.2 f g hp.symm).imp hf.eq_one_of_isUnit hg.eq_one_of_isUnit, fun h => - ⟨hp1 ∘ hp.eq_one_of_isUnit, fun f g hfg => - (h (g * C f.leadingCoeff) (f * C g.leadingCoeff) ?_ ?_ ?_).symm.imp - (isUnit_of_mul_eq_one f _) - (isUnit_of_mul_eq_one g _)⟩⟩ - · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, mul_comm, ← hfg, ← Monic] - · rwa [Monic, leadingCoeff_mul, leadingCoeff_C, ← leadingCoeff_mul, ← hfg, ← Monic] - · rw [mul_mul_mul_comm, ← C_mul, ← leadingCoeff_mul, ← hfg, hp.leadingCoeff, C_1, mul_one, - mul_comm, ← hfg] - -theorem Monic.irreducible_iff_natDegree (hp : p.Monic) : - Irreducible p ↔ - p ≠ 1 ∧ ∀ f g : R[X], f.Monic → g.Monic → f * g = p → f.natDegree = 0 ∨ g.natDegree = 0 := by - by_cases hp1 : p = 1; · simp [hp1] - rw [irreducible_of_monic hp hp1, and_iff_right hp1] - refine forall₄_congr fun a b ha hb => ?_ - rw [ha.natDegree_eq_zero_iff_eq_one, hb.natDegree_eq_zero_iff_eq_one] - -theorem Monic.irreducible_iff_natDegree' (hp : p.Monic) : Irreducible p ↔ p ≠ 1 ∧ - ∀ f g : R[X], f.Monic → g.Monic → f * g = p → g.natDegree ∉ Ioc 0 (p.natDegree / 2) := by - simp_rw [hp.irreducible_iff_natDegree, mem_Ioc, Nat.le_div_iff_mul_le zero_lt_two, mul_two] - apply and_congr_right' - constructor <;> intro h f g hf hg he <;> subst he - · rw [hf.natDegree_mul hg, add_le_add_iff_right] - exact fun ha => (h f g hf hg rfl).elim (ha.1.trans_le ha.2).ne' ha.1.ne' - · simp_rw [hf.natDegree_mul hg, pos_iff_ne_zero] at h - contrapose! h - obtain hl | hl := le_total f.natDegree g.natDegree - · exact ⟨g, f, hg, hf, mul_comm g f, h.1, add_le_add_left hl _⟩ - · exact ⟨f, g, hf, hg, rfl, h.2, add_le_add_right hl _⟩ - -/-- Alternate phrasing of `Polynomial.Monic.irreducible_iff_natDegree'` where we only have to check -one divisor at a time. -/ -theorem Monic.irreducible_iff_lt_natDegree_lt {p : R[X]} (hp : p.Monic) (hp1 : p ≠ 1) : - Irreducible p ↔ ∀ q, Monic q → natDegree q ∈ Finset.Ioc 0 (natDegree p / 2) → ¬ q ∣ p := by - rw [hp.irreducible_iff_natDegree', and_iff_right hp1] - constructor - · rintro h g hg hdg ⟨f, rfl⟩ - exact h f g (hg.of_mul_monic_left hp) hg (mul_comm f g) hdg - · rintro h f g - hg rfl hdg - exact h g hg hdg (dvd_mul_left g f) - -theorem Monic.not_irreducible_iff_exists_add_mul_eq_coeff (hm : p.Monic) (hnd : p.natDegree = 2) : - ¬Irreducible p ↔ ∃ c₁ c₂, p.coeff 0 = c₁ * c₂ ∧ p.coeff 1 = c₁ + c₂ := by - cases subsingleton_or_nontrivial R - · simp [natDegree_of_subsingleton] at hnd - rw [hm.irreducible_iff_natDegree', and_iff_right, hnd] - · push_neg - constructor - · rintro ⟨a, b, ha, hb, rfl, hdb⟩ - simp only [zero_lt_two, Nat.div_self, Nat.Ioc_succ_singleton, zero_add, mem_singleton] at hdb - have hda := hnd - rw [ha.natDegree_mul hb, hdb] at hda - use a.coeff 0, b.coeff 0, mul_coeff_zero a b - simpa only [nextCoeff, hnd, add_right_cancel hda, hdb] using ha.nextCoeff_mul hb - · rintro ⟨c₁, c₂, hmul, hadd⟩ - refine - ⟨X + C c₁, X + C c₂, monic_X_add_C _, monic_X_add_C _, ?_, ?_⟩ - · rw [p.as_sum_range_C_mul_X_pow, hnd, Finset.sum_range_succ, Finset.sum_range_succ, - Finset.sum_range_one, ← hnd, hm.coeff_natDegree, hnd, hmul, hadd, C_mul, C_add, C_1] - ring - · rw [mem_Ioc, natDegree_X_add_C _] - simp - · rintro rfl - simp [natDegree_one] at hnd - -theorem root_mul : IsRoot (p * q) a ↔ IsRoot p a ∨ IsRoot q a := by - simp_rw [IsRoot, eval_mul, mul_eq_zero] - -theorem root_or_root_of_root_mul (h : IsRoot (p * q) a) : IsRoot p a ∨ IsRoot q a := - root_mul.1 h - end NoZeroDivisors -section Ring - -variable [Ring R] [IsDomain R] {p q : R[X]} - -instance : IsDomain R[X] := - NoZeroDivisors.to_isDomain _ - -end Ring - -section CommSemiring - -variable [CommSemiring R] {a p : R[X]} - -section Monic - -variable (hp : p.Monic) -include hp - -theorem Monic.C_dvd_iff_isUnit {a : R} : C a ∣ p ↔ IsUnit a := - ⟨fun h => isUnit_iff_dvd_one.mpr <| - hp.coeff_natDegree ▸ (C_dvd_iff_dvd_coeff _ _).mp h p.natDegree, - fun ha => (ha.map C).dvd⟩ - -theorem Monic.natDegree_pos : 0 < natDegree p ↔ p ≠ 1 := - Nat.pos_iff_ne_zero.trans hp.natDegree_eq_zero.not - -theorem Monic.degree_pos : 0 < degree p ↔ p ≠ 1 := - natDegree_pos_iff_degree_pos.symm.trans hp.natDegree_pos - -theorem Monic.degree_pos_of_not_isUnit (hu : ¬IsUnit p) : 0 < degree p := - hp.degree_pos.mpr (fun hp' ↦ (hp' ▸ hu) isUnit_one) - -theorem Monic.natDegree_pos_of_not_isUnit (hu : ¬IsUnit p) : 0 < natDegree p := - hp.natDegree_pos.mpr (fun hp' ↦ (hp' ▸ hu) isUnit_one) - -theorem degree_pos_of_not_isUnit_of_dvd_monic (ha : ¬IsUnit a) (hap : a ∣ p) : 0 < degree a := by - contrapose! ha with h - rw [Polynomial.eq_C_of_degree_le_zero h] at hap ⊢ - simpa [hp.C_dvd_iff_isUnit, isUnit_C] using hap - -theorem natDegree_pos_of_not_isUnit_of_dvd_monic (ha : ¬IsUnit a) (hap : a ∣ p) : 0 < natDegree a := - natDegree_pos_iff_degree_pos.mpr <| degree_pos_of_not_isUnit_of_dvd_monic hp ha hap - -end Monic - -theorem eq_zero_of_mul_eq_zero_of_smul (P : R[X]) (h : ∀ r : R, r • P = 0 → r = 0) : - ∀ (Q : R[X]), P * Q = 0 → Q = 0 := by - intro Q hQ - suffices ∀ i, P.coeff i • Q = 0 by - rw [← leadingCoeff_eq_zero] - apply h - simpa [ext_iff, mul_comm Q.leadingCoeff] using fun i ↦ congr_arg (·.coeff Q.natDegree) (this i) - apply Nat.strong_decreasing_induction - · use P.natDegree - intro i hi - rw [coeff_eq_zero_of_natDegree_lt hi, zero_smul] - intro l IH - obtain _|hl := (natDegree_smul_le (P.coeff l) Q).lt_or_eq - · apply eq_zero_of_mul_eq_zero_of_smul _ h (P.coeff l • Q) - rw [smul_eq_C_mul, mul_left_comm, hQ, mul_zero] - suffices P.coeff l * Q.leadingCoeff = 0 by - rwa [← leadingCoeff_eq_zero, ← coeff_natDegree, coeff_smul, hl, coeff_natDegree, smul_eq_mul] - let m := Q.natDegree - suffices (P * Q).coeff (l + m) = P.coeff l * Q.leadingCoeff by rw [← this, hQ, coeff_zero] - rw [coeff_mul] - apply Finset.sum_eq_single (l, m) _ (by simp) - simp only [Finset.mem_antidiagonal, ne_eq, Prod.forall, Prod.mk.injEq, not_and] - intro i j hij H - obtain hi|rfl|hi := lt_trichotomy i l - · have hj : m < j := by omega - rw [coeff_eq_zero_of_natDegree_lt hj, mul_zero] - · omega - · rw [← coeff_C_mul, ← smul_eq_C_mul, IH _ hi, coeff_zero] -termination_by Q => Q.natDegree - -open nonZeroDivisors in -/-- *McCoy theorem*: a polynomial `P : R[X]` is a zerodivisor if and only if there is `a : R` -such that `a ≠ 0` and `a • P = 0`. -/ -theorem nmem_nonZeroDivisors_iff {P : R[X]} : P ∉ R[X]⁰ ↔ ∃ a : R, a ≠ 0 ∧ a • P = 0 := by - refine ⟨fun hP ↦ ?_, fun ⟨a, ha, h⟩ h1 ↦ ha <| C_eq_zero.1 <| (h1 _) <| smul_eq_C_mul a ▸ h⟩ - by_contra! h - obtain ⟨Q, hQ⟩ := _root_.nmem_nonZeroDivisors_iff.1 hP - refine hQ.2 (eq_zero_of_mul_eq_zero_of_smul P (fun a ha ↦ ?_) Q (mul_comm P _ ▸ hQ.1)) - contrapose! ha - exact h a ha - -open nonZeroDivisors in -protected lemma mem_nonZeroDivisors_iff {P : R[X]} : P ∈ R[X]⁰ ↔ ∀ a : R, a • P = 0 → a = 0 := by - simpa [not_imp_not] using (nmem_nonZeroDivisors_iff (P := P)).not - -end CommSemiring section CommRing variable [CommRing R] -/- Porting note: the ML3 proof no longer worked because of a conflict in the -inferred type and synthesized type for `DecidableRel` when using `Nat.le_find_iff` from -`Mathlib.Algebra.Polynomial.Div` After some discussion on [Zulip] -(https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/decidability.20leakage) -introduced `Polynomial.rootMultiplicity_eq_nat_find_of_nonzero` to contain the issue --/ -/-- The multiplicity of `a` as root of a nonzero polynomial `p` is at least `n` iff - `(X - a) ^ n` divides `p`. -/ -theorem le_rootMultiplicity_iff {p : R[X]} (p0 : p ≠ 0) {a : R} {n : ℕ} : - n ≤ rootMultiplicity a p ↔ (X - C a) ^ n ∣ p := by - classical - rw [rootMultiplicity_eq_nat_find_of_nonzero p0, @Nat.le_find_iff _ (_)] - simp_rw [Classical.not_not] - refine ⟨fun h => ?_, fun h m hm => (pow_dvd_pow _ hm).trans h⟩ - cases' n with n - · rw [pow_zero] - apply one_dvd - · exact h n n.lt_succ_self - -theorem rootMultiplicity_le_iff {p : R[X]} (p0 : p ≠ 0) (a : R) (n : ℕ) : - rootMultiplicity a p ≤ n ↔ ¬(X - C a) ^ (n + 1) ∣ p := by - rw [← (le_rootMultiplicity_iff p0).not, not_le, Nat.lt_add_one_iff] - -theorem pow_rootMultiplicity_not_dvd {p : R[X]} (p0 : p ≠ 0) (a : R) : - ¬(X - C a) ^ (rootMultiplicity a p + 1) ∣ p := by rw [← rootMultiplicity_le_iff p0] - -theorem X_sub_C_pow_dvd_iff {p : R[X]} {t : R} {n : ℕ} : - (X - C t) ^ n ∣ p ↔ X ^ n ∣ p.comp (X + C t) := by - convert (map_dvd_iff <| algEquivAevalXAddC t).symm using 2 - simp [C_eq_algebraMap] - -theorem comp_X_add_C_eq_zero_iff {p : R[X]} (t : R) : - p.comp (X + C t) = 0 ↔ p = 0 := AddEquivClass.map_eq_zero_iff (algEquivAevalXAddC t) - -theorem comp_X_add_C_ne_zero_iff {p : R[X]} (t : R) : - p.comp (X + C t) ≠ 0 ↔ p ≠ 0 := Iff.not <| comp_X_add_C_eq_zero_iff t - theorem rootMultiplicity_eq_rootMultiplicity {p : R[X]} {t : R} : p.rootMultiplicity t = (p.comp (X + C t)).rootMultiplicity 0 := by classical simp_rw [rootMultiplicity_eq_multiplicity, comp_X_add_C_eq_zero_iff] - congr; ext; congr 1 + congr 1 rw [C_0, sub_zero] - convert (multiplicity.multiplicity_map_eq <| algEquivAevalXAddC t).symm using 2 + convert (multiplicity_map_eq <| algEquivAevalXAddC t).symm using 2 simp [C_eq_algebraMap] -theorem rootMultiplicity_eq_natTrailingDegree' {p : R[X]} : - p.rootMultiplicity 0 = p.natTrailingDegree := by - by_cases h : p = 0 - · simp only [h, rootMultiplicity_zero, natTrailingDegree_zero] - refine le_antisymm ?_ ?_ - · rw [rootMultiplicity_le_iff h, map_zero, sub_zero, X_pow_dvd_iff, not_forall] - exact ⟨p.natTrailingDegree, - fun h' ↦ trailingCoeff_nonzero_iff_nonzero.2 h <| h' <| Nat.lt.base _⟩ - · rw [le_rootMultiplicity_iff h, map_zero, sub_zero, X_pow_dvd_iff] - exact fun _ ↦ coeff_eq_zero_of_lt_natTrailingDegree - +/-- See `Polynomial.rootMultiplicity_eq_natTrailingDegree'` for the special case of `t = 0`. -/ theorem rootMultiplicity_eq_natTrailingDegree {p : R[X]} {t : R} : p.rootMultiplicity t = (p.comp (X + C t)).natTrailingDegree := rootMultiplicity_eq_rootMultiplicity.trans rootMultiplicity_eq_natTrailingDegree' -theorem eval_divByMonic_eq_trailingCoeff_comp {p : R[X]} {t : R} : - (p /ₘ (X - C t) ^ p.rootMultiplicity t).eval t = (p.comp (X + C t)).trailingCoeff := by - obtain rfl | hp := eq_or_ne p 0 - · rw [zero_divByMonic, eval_zero, zero_comp, trailingCoeff_zero] - have mul_eq := p.pow_mul_divByMonic_rootMultiplicity_eq t - set m := p.rootMultiplicity t - set g := p /ₘ (X - C t) ^ m - have : (g.comp (X + C t)).coeff 0 = g.eval t := by - rw [coeff_zero_eq_eval_zero, eval_comp, eval_add, eval_X, eval_C, zero_add] - rw [← congr_arg (comp · <| X + C t) mul_eq, mul_comp, pow_comp, sub_comp, X_comp, C_comp, - add_sub_cancel_right, ← reverse_leadingCoeff, reverse_X_pow_mul, reverse_leadingCoeff, - trailingCoeff, Nat.le_zero.1 (natTrailingDegree_le_of_ne_zero <| - this ▸ eval_divByMonic_pow_rootMultiplicity_ne_zero t hp), this] - section nonZeroDivisors open scoped nonZeroDivisors @@ -527,17 +152,6 @@ theorem rootMultiplicity_X_sub_C [Nontrivial R] [DecidableEq R] {x y : R} : exact rootMultiplicity_X_sub_C_self exact rootMultiplicity_eq_zero (mt root_X_sub_C.mp (Ne.symm hxy)) -/-- The multiplicity of `p + q` is at least the minimum of the multiplicities. -/ -theorem rootMultiplicity_add {p q : R[X]} (a : R) (hzero : p + q ≠ 0) : - min (rootMultiplicity a p) (rootMultiplicity a q) ≤ rootMultiplicity a (p + q) := by - rw [le_rootMultiplicity_iff hzero] - exact min_pow_dvd_add (pow_rootMultiplicity_dvd p a) (pow_rootMultiplicity_dvd q a) - -theorem le_rootMultiplicity_mul {p q : R[X]} (x : R) (hpq : p * q ≠ 0) : - rootMultiplicity x p + rootMultiplicity x q ≤ rootMultiplicity x (p * q) := by - rw [le_rootMultiplicity_iff hpq, pow_add] - exact mul_dvd_mul (pow_rootMultiplicity_dvd p x) (pow_rootMultiplicity_dvd q x) - theorem rootMultiplicity_mul' {p q : R[X]} {x : R} (hpq : (p /ₘ (X - C x) ^ p.rootMultiplicity x).eval x * (q /ₘ (X - C x) ^ q.rootMultiplicity x).eval x ≠ 0) : @@ -545,18 +159,6 @@ theorem rootMultiplicity_mul' {p q : R[X]} {x : R} simp_rw [eval_divByMonic_eq_trailingCoeff_comp] at hpq simp_rw [rootMultiplicity_eq_natTrailingDegree, mul_comp, natTrailingDegree_mul' hpq] -theorem Monic.comp_X_sub_C {p : R[X]} (hp : p.Monic) (r : R) : (p.comp (X - C r)).Monic := by - simpa using hp.comp_X_add_C (-r) - -@[simp] -theorem comp_neg_X_leadingCoeff_eq (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] - theorem Monic.neg_one_pow_natDegree_mul_comp_neg_X {p : R[X]} (hp : p.Monic) : ((-1) ^ p.natDegree * p.comp (-X)).Monic := by simp only [Monic] @@ -570,101 +172,10 @@ theorem Monic.neg_one_pow_natDegree_mul_comp_neg_X {p : R[X]} (hp : p.Monic) : variable [IsDomain R] {p q : R[X]} -@[simp] -theorem natDegree_coe_units (u : R[X]ˣ) : natDegree (u : R[X]) = 0 := - natDegree_eq_of_degree_eq_some (degree_coe_units u) - -theorem coeff_coe_units_zero_ne_zero (u : R[X]ˣ) : coeff (u : R[X]) 0 ≠ 0 := by - conv in 0 => rw [← natDegree_coe_units u] - rw [← leadingCoeff, Ne, leadingCoeff_eq_zero] - exact Units.ne_zero _ - theorem degree_eq_degree_of_associated (h : Associated p q) : degree p = degree q := by let ⟨u, hu⟩ := h simp [hu.symm] -theorem degree_eq_one_of_irreducible_of_root (hi : Irreducible p) {x : R} (hx : IsRoot p x) : - degree p = 1 := - let ⟨g, hg⟩ := dvd_iff_isRoot.2 hx - have : IsUnit (X - C x) ∨ IsUnit g := hi.isUnit_or_isUnit hg - this.elim - (fun h => by - have h₁ : degree (X - C x) = 1 := degree_X_sub_C x - have h₂ : degree (X - C x) = 0 := degree_eq_zero_of_isUnit h - rw [h₁] at h₂; exact absurd h₂ (by decide)) - fun hgu => by rw [hg, degree_mul, degree_X_sub_C, degree_eq_zero_of_isUnit hgu, add_zero] - -/-- Division by a monic polynomial doesn't change the leading coefficient. -/ -theorem leadingCoeff_divByMonic_of_monic {R : Type u} [CommRing R] {p q : R[X]} (hmonic : q.Monic) - (hdegree : q.degree ≤ p.degree) : (p /ₘ q).leadingCoeff = p.leadingCoeff := by - nontriviality - have h : q.leadingCoeff * (p /ₘ q).leadingCoeff ≠ 0 := by - simpa [divByMonic_eq_zero_iff hmonic, hmonic.leadingCoeff, - Nat.WithBot.one_le_iff_zero_lt] using hdegree - nth_rw 2 [← modByMonic_add_div p hmonic] - rw [leadingCoeff_add_of_degree_lt, leadingCoeff_monic_mul hmonic] - rw [degree_mul' h, degree_add_divByMonic hmonic hdegree] - exact (degree_modByMonic_lt p hmonic).trans_le hdegree - -theorem leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) : - leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by - nontriviality - cases' hp.lt_or_lt with hd hd - · rw [degree_eq_bot.mp <| Nat.WithBot.lt_zero_iff.mp hd, zero_divByMonic] - refine leadingCoeff_divByMonic_of_monic (monic_X_sub_C a) ?_ - rwa [degree_X_sub_C, Nat.WithBot.one_le_iff_zero_lt] - -theorem eq_of_dvd_of_natDegree_le_of_leadingCoeff {p q : R[X]} (hpq : p ∣ q) - (h₁ : q.natDegree ≤ p.natDegree) (h₂ : p.leadingCoeff = q.leadingCoeff) : - p = q := by - by_cases hq : q = 0 - · rwa [hq, leadingCoeff_zero, leadingCoeff_eq_zero, ← hq] at h₂ - replace h₁ := (natDegree_le_of_dvd hpq hq).antisymm h₁ - obtain ⟨u, rfl⟩ := hpq - replace hq := mul_ne_zero_iff.mp hq - rw [natDegree_mul hq.1 hq.2, self_eq_add_right] at h₁ - rw [eq_C_of_natDegree_eq_zero h₁, leadingCoeff_mul, leadingCoeff_C, - eq_comm, mul_eq_left₀ (leadingCoeff_ne_zero.mpr hq.1)] at h₂ - rw [eq_C_of_natDegree_eq_zero h₁, h₂, map_one, mul_one] - -theorem associated_of_dvd_of_natDegree_le_of_leadingCoeff {p q : R[X]} (hpq : p ∣ q) - (h₁ : q.natDegree ≤ p.natDegree) (h₂ : q.leadingCoeff ∣ p.leadingCoeff) : - Associated p q := - have ⟨r, hr⟩ := hpq - have ⟨u, hu⟩ := associated_of_dvd_dvd ⟨leadingCoeff r, hr ▸ leadingCoeff_mul p r⟩ h₂ - ⟨Units.map C.toMonoidHom u, eq_of_dvd_of_natDegree_le_of_leadingCoeff - (by rwa [Units.mul_right_dvd]) (by simpa [natDegree_mul_C] using h₁) (by simpa using hu)⟩ - -theorem associated_of_dvd_of_natDegree_le {K} [Field K] {p q : K[X]} (hpq : p ∣ q) (hq : q ≠ 0) - (h₁ : q.natDegree ≤ p.natDegree) : Associated p q := - associated_of_dvd_of_natDegree_le_of_leadingCoeff hpq h₁ - (IsUnit.dvd (by rwa [← leadingCoeff_ne_zero, ← isUnit_iff_ne_zero] at hq)) - -theorem associated_of_dvd_of_degree_eq {K} [Field K] {p q : K[X]} (hpq : p ∣ q) - (h₁ : p.degree = q.degree) : Associated p q := - (Classical.em (q = 0)).elim (fun hq ↦ (show p = q by simpa [hq] using h₁) ▸ Associated.refl p) - (associated_of_dvd_of_natDegree_le hpq · (natDegree_le_natDegree h₁.ge)) - -theorem eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} - (hp : p.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : - q = C q.leadingCoeff * p := by - obtain ⟨r, hr⟩ := hdiv - obtain rfl | hq := eq_or_ne q 0; · simp - have rzero : r ≠ 0 := fun h => by simp [h, hq] at hr - rw [hr, natDegree_mul'] at hdeg; swap - · rw [hp.leadingCoeff, one_mul, leadingCoeff_ne_zero] - exact rzero - rw [mul_comm, @eq_C_of_natDegree_eq_zero _ _ r] at hr - · convert hr - convert leadingCoeff_C (coeff r 0) using 1 - rw [hr, leadingCoeff_mul_monic hp] - · exact (add_right_inj _).1 (le_antisymm hdeg <| Nat.le.intro rfl) - -theorem eq_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} (hp : p.Monic) - (hq : q.Monic) (hdiv : p ∣ q) (hdeg : q.natDegree ≤ p.natDegree) : q = p := by - convert eq_leadingCoeff_mul_of_monic_of_dvd_of_natDegree_le hp hdiv hdeg - rw [hq.leadingCoeff, C_1, one_mul] - theorem prime_X_sub_C (r : R) : Prime (X - C r) := ⟨X_sub_C_ne_zero r, not_isUnit_X_sub_C r, fun _ _ => by simp_rw [dvd_iff_isRoot, IsRoot.def, eval_mul, mul_eq_zero] @@ -687,31 +198,6 @@ theorem irreducible_X : Irreducible (X : R[X]) := theorem Monic.irreducible_of_degree_eq_one (hp1 : degree p = 1) (hm : Monic p) : Irreducible p := (hm.prime_of_degree_eq_one hp1).irreducible -@[simp] -theorem natDegree_multiset_prod_X_sub_C_eq_card (s : Multiset R) : - (s.map fun a => X - C a).prod.natDegree = Multiset.card s := by - rw [natDegree_multiset_prod_of_monic, Multiset.map_map] - · simp only [(· ∘ ·), natDegree_X_sub_C, Multiset.map_const', Multiset.sum_replicate, smul_eq_mul, - mul_one] - · exact Multiset.forall_mem_map_iff.2 fun a _ => monic_X_sub_C a - -theorem units_coeff_zero_smul (c : R[X]ˣ) (p : R[X]) : (c : R[X]).coeff 0 • p = c * p := by - rw [← Polynomial.C_mul', ← Polynomial.eq_C_of_degree_eq_zero (degree_coe_units c)] - -theorem comp_eq_zero_iff : p.comp q = 0 ↔ p = 0 ∨ p.eval (q.coeff 0) = 0 ∧ q = C (q.coeff 0) := by - constructor - · intro h - have key : p.natDegree = 0 ∨ q.natDegree = 0 := by - rw [← mul_eq_zero, ← natDegree_comp, h, natDegree_zero] - replace key := Or.imp eq_C_of_natDegree_eq_zero eq_C_of_natDegree_eq_zero key - cases' key with key key - · rw [key, C_comp] at h - exact Or.inl (key.trans h) - · rw [key, comp_C, C_eq_zero] at h - exact Or.inr ⟨h, key⟩ - · exact fun h => - Or.rec (fun h => by rw [h, zero_comp]) (fun h => by rw [h.2, comp_C, h.1, C_0]) h - lemma aeval_ne_zero_of_isCoprime {R} [CommSemiring R] [Nontrivial S] [Semiring S] [Algebra R S] {p q : R[X]} (h : IsCoprime p q) (s : S) : aeval s p ≠ 0 ∨ aeval s q ≠ 0 := by by_contra! hpq @@ -736,11 +222,12 @@ theorem rootMultiplicity_mul {p q : R[X]} {x : R} (hpq : p * q ≠ 0) : classical have hp : p ≠ 0 := left_ne_zero_of_mul hpq have hq : q ≠ 0 := right_ne_zero_of_mul hpq - rw [rootMultiplicity_eq_multiplicity (p * q), dif_neg hpq, rootMultiplicity_eq_multiplicity p, - dif_neg hp, rootMultiplicity_eq_multiplicity q, dif_neg hq, - multiplicity.mul' (prime_X_sub_C x)] + 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)] open Multiset in +set_option linter.unusedVariables false in theorem exists_multiset_roots [DecidableEq R] : ∀ {p : R[X]} (_ : p ≠ 0), ∃ s : Multiset R, (Multiset.card s : WithBot ℕ) ≤ degree p ∧ ∀ a, s.count a = rootMultiplicity a p @@ -751,6 +238,11 @@ theorem exists_multiset_roots [DecidableEq R] : have hpd : 0 < degree p := degree_pos_of_root hp hx have hd0 : p /ₘ (X - C x) ≠ 0 := fun h => by rw [← mul_divByMonic_eq_iff_isRoot.2 hx, h, mul_zero] at hp; exact hp rfl + #adaptation_note + /-- + Since https://github.com/leanprover/lean4/pull/5338, this is considered unused, + because it is only used in the decreasing_by clause. + -/ have wf : degree (p /ₘ (X - C x)) < degree p := degree_divByMonic_lt _ (monic_X_sub_C x) hp ((degree_X_sub_C x).symm ▸ by decide) let ⟨t, htd, htr⟩ := @exists_multiset_roots _ (p /ₘ (X - C x)) hd0 @@ -790,53 +282,4 @@ decreasing_by { end CommRing -section - -variable [Semiring R] [CommRing S] [IsDomain S] (φ : R →+* S) - -theorem isUnit_of_isUnit_leadingCoeff_of_isUnit_map {f : R[X]} (hf : IsUnit f.leadingCoeff) - (H : IsUnit (map φ f)) : IsUnit f := by - have dz := degree_eq_zero_of_isUnit H - rw [degree_map_eq_of_leadingCoeff_ne_zero] at dz - · rw [eq_C_of_degree_eq_zero dz] - refine IsUnit.map C ?_ - convert hf - change coeff f 0 = coeff f (natDegree f) - rw [(degree_eq_iff_natDegree_eq _).1 dz] - · rfl - rintro rfl - simp at H - · intro h - have u : IsUnit (φ f.leadingCoeff) := IsUnit.map φ hf - rw [h] at u - simp at u - -end - -section - -variable [CommRing R] [IsDomain R] [CommRing S] [IsDomain S] (φ : R →+* S) - -/-- A polynomial over an integral domain `R` is irreducible if it is monic and - irreducible after mapping into an integral domain `S`. - -A special case of this lemma is that a polynomial over `ℤ` is irreducible if - it is monic and irreducible over `ℤ/pℤ` for some prime `p`. --/ -theorem Monic.irreducible_of_irreducible_map (f : R[X]) (h_mon : Monic f) - (h_irr : Irreducible (Polynomial.map φ f)) : Irreducible f := by - refine ⟨h_irr.not_unit ∘ IsUnit.map (mapRingHom φ), fun a b h => ?_⟩ - dsimp [Monic] at h_mon - have q := (leadingCoeff_mul a b).symm - rw [← h, h_mon] at q - refine (h_irr.isUnit_or_isUnit <| - (congr_arg (Polynomial.map φ) h).trans (Polynomial.map_mul φ)).imp ?_ ?_ <;> - apply isUnit_of_isUnit_leadingCoeff_of_isUnit_map <;> - apply isUnit_of_mul_eq_one - · exact q - · rw [mul_comm] - exact q - -end - end Polynomial diff --git a/Mathlib/Algebra/Polynomial/Roots.lean b/Mathlib/Algebra/Polynomial/Roots.lean index 59f7f94c78993..3db1a24da52f9 100644 --- a/Mathlib/Algebra/Polynomial/Roots.lean +++ b/Mathlib/Algebra/Polynomial/Roots.lean @@ -3,7 +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, Johan Commelin -/ - +import Mathlib.Algebra.Polynomial.BigOperators import Mathlib.Algebra.Polynomial.RingDivision import Mathlib.RingTheory.Localization.FractionRing import Mathlib.SetTheory.Cardinal.Basic @@ -27,6 +27,8 @@ We define the multiset of roots of a polynomial, and prove basic results about i -/ +open Multiset Finset + noncomputable section namespace Polynomial @@ -41,8 +43,6 @@ variable [CommRing R] [IsDomain R] {p q : R[X]} section Roots -open Multiset Finset - /-- `roots p` noncomputably gives a multiset containing all the roots of `p`, including their multiplicities. -/ noncomputable def roots (p : R[X]) : Multiset R := @@ -117,7 +117,7 @@ lemma mem_roots_iff_aeval_eq_zero {x : R} (w : p ≠ 0) : x ∈ roots p ↔ aeva Algebra.id.map_eq_id, map_id] theorem card_le_degree_of_subset_roots {p : R[X]} {Z : Finset R} (h : Z.val ⊆ p.roots) : - Z.card ≤ p.natDegree := + #Z ≤ p.natDegree := (Multiset.card_le_card (Finset.val_le_iff_val_subset.2 h)).trans (Polynomial.card_roots' p) theorem finite_setOf_isRoot {p : R[X]} (hp : p ≠ 0) : Set.Finite { x | IsRoot p x } := by @@ -498,7 +498,7 @@ theorem bUnion_roots_finite {R S : Type*} [Semiring R] [CommRing S] [IsDomain S] · exact Set.image_subset_iff.2 fun f hf i _ => hf.2 i · refine fun x hx y hy hxy => (ext_iff_natDegree_le hx.1 hy.1).2 fun i hi => ?_ exact id congr_fun hxy ⟨i, Nat.lt_succ_of_le hi⟩) - fun i _ => Finset.finite_toSet _ + fun _ _ => Finset.finite_toSet _ theorem mem_rootSet' {p : T[X]} {S : Type*} [CommRing S] [IsDomain S] [Algebra T S] {a : S} : a ∈ p.rootSet S ↔ p.map (algebraMap T S) ≠ 0 ∧ aeval a p = 0 := by @@ -548,14 +548,14 @@ lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R] (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by classical by_contra hp - apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset)) + refine lt_irrefl #p.roots.toFinset ?_ calc - Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _ + #p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _ _ ≤ natDegree p := Polynomial.card_roots' p _ < Fintype.card ι := hcard _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm - _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range] - _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_ + _ = #(Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range] + _ ≤ #p.roots.toFinset := Finset.card_mono ?_ intro _ simp only [Finset.mem_image, Finset.mem_univ, true_and, Multiset.mem_toFinset, mem_roots', ne_eq, IsRoot.def, forall_exists_index, hp, not_false_eq_true] @@ -563,7 +563,7 @@ lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R] exact heval _ lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero' {R} [CommRing R] [IsDomain R] - (p : R[X]) (s : Finset R) (heval : ∀ i ∈ s, p.eval i = 0) (hcard : natDegree p < s.card) : + (p : R[X]) (s : Finset R) (heval : ∀ i ∈ s, p.eval i = 0) (hcard : natDegree p < #s) : p = 0 := eq_zero_of_natDegree_lt_card_of_eval_eq_zero p Subtype.val_injective (fun i : s ↦ heval i i.prop) (hcard.trans_eq (Fintype.card_coe s).symm) diff --git a/Mathlib/Algebra/Polynomial/Smeval.lean b/Mathlib/Algebra/Polynomial/Smeval.lean index d24a7089bfc93..912d3fa7ee49c 100644 --- a/Mathlib/Algebra/Polynomial/Smeval.lean +++ b/Mathlib/Algebra/Polynomial/Smeval.lean @@ -26,7 +26,8 @@ is a generalization of `Algebra.Polynomial.Eval`. * `smeval_monomial`: monomials evaluate as we expect. * `smeval_add`, `smeval_smul`: linearity of evaluation, given an `R`-module. * `smeval_mul`, `smeval_comp`: multiplicativity of evaluation, given power-associativity. -* `eval₂_eq_smeval`, `leval_eq_smeval.linearMap`, `aeval = smeval.algebraMap`, etc.: comparisons +* `eval₂_smulOneHom_eq_smeval`, `leval_eq_smeval.linearMap`, + `aeval_eq_smeval`, etc.: comparisons ## TODO @@ -64,12 +65,12 @@ theorem eval_eq_smeval : p.eval r = p.smeval r := by rw [eval_eq_sum, smeval_eq_sum] rfl -theorem eval₂_eq_smeval (R : Type*) [Semiring R] {S : Type*} [Semiring S] (f : R →+* S) (p : R[X]) - (x : S) : letI : Module R S := RingHom.toModule f - p.eval₂ f x = p.smeval x := by - letI : Module R S := RingHom.toModule f +theorem eval₂_smulOneHom_eq_smeval (R : Type*) [Semiring R] {S : Type*} [Semiring S] [Module R S] + [IsScalarTower R S S] (p : R[X]) (x : S) : + p.eval₂ RingHom.smulOneHom x = p.smeval x := by rw [smeval_eq_sum, eval₂_eq_sum] - rfl + congr 1 with e a + simp only [RingHom.smulOneHom_apply, smul_one_mul, smul_pow] variable (R) @@ -133,7 +134,7 @@ theorem smeval.linearMap_apply : smeval.linearMap R x p = p.smeval x := rfl theorem leval_coe_eq_smeval {R : Type*} [Semiring R] (r : R) : ⇑(leval r) = fun p => p.smeval r := by - rw [Function.funext_iff] + rw [funext_iff] intro rw [leval_apply, smeval_def, eval_eq_sum] rfl diff --git a/Mathlib/Algebra/Polynomial/Splits.lean b/Mathlib/Algebra/Polynomial/Splits.lean index 3b0f053ebb0ea..db9df3da20b50 100644 --- a/Mathlib/Algebra/Polynomial/Splits.lean +++ b/Mathlib/Algebra/Polynomial/Splits.lean @@ -139,6 +139,27 @@ theorem splits_X_pow (n : ℕ) : (X ^ n).Splits i := theorem splits_id_iff_splits {f : K[X]} : (f.map i).Splits (RingHom.id L) ↔ f.Splits i := by rw [splits_map_iff, RingHom.id_comp] +theorem Splits.comp_X_sub_C {i : L →+* F} (a : L) {f : L[X]} + (h : f.Splits i) : (f.comp (X - C a)).Splits i := by + cases h with + | inl h0 => + left + simp only [map_eq_zero] at h0 ⊢ + exact h0.symm ▸ zero_comp + | inr h => + right + intro g irr dvd + rw [map_comp, Polynomial.map_sub, map_X, map_C, dvd_comp_X_sub_C_iff] at dvd + have := h (irr.map (algEquivAevalXAddC _)) dvd + rw [degree_eq_natDegree irr.ne_zero] + rwa [algEquivAevalXAddC_apply, ← comp_eq_aeval, + degree_eq_natDegree (fun h => WithBot.bot_ne_one (h ▸ this)), + natDegree_comp, natDegree_X_add_C, mul_one] at this + +theorem Splits.comp_X_add_C {i : L →+* F} (a : L) {f : L[X]} + (h : f.Splits i) : (f.comp (X + C a)).Splits i := by + simpa only [map_neg, sub_neg_eq_add] using h.comp_X_sub_C (-a) + theorem exists_root_of_splits' {f : K[X]} (hs : Splits i f) (hf0 : degree (f.map i) ≠ 0) : ∃ x, eval₂ i x f = 0 := letI := Classical.decEq L @@ -370,7 +391,7 @@ theorem splits_of_exists_multiset {f : K[X]} {s : Multiset L} theorem splits_of_splits_id {f : K[X]} : Splits (RingHom.id K) f → Splits i f := UniqueFactorizationMonoid.induction_on_prime f (fun _ => splits_zero _) (fun _ hu _ => splits_of_degree_le_one _ ((isUnit_iff_degree_eq_zero.1 hu).symm ▸ by decide)) - fun a p ha0 hp ih hfi => + fun _ p ha0 hp ih hfi => splits_mul _ (splits_of_degree_eq_one _ ((splits_of_splits_mul _ (mul_ne_zero hp.1 ha0) hfi).1.def.resolve_left hp.1 hp.irreducible diff --git a/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean b/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean new file mode 100644 index 0000000000000..09b26c906942b --- /dev/null +++ b/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean @@ -0,0 +1,244 @@ +/- +Copyright (c) 2022 Yuyang Zhao. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yuyang Zhao +-/ +import Mathlib.Algebra.Polynomial.AlgebraMap +import Mathlib.Algebra.Polynomial.BigOperators +import Mathlib.Algebra.Polynomial.Degree.Lemmas +import Mathlib.Algebra.Polynomial.Derivative + +/-! +# Sum of iterated derivatives + +This file introduces `Polynomial.sumIDeriv`, the sum of the iterated derivatives of a polynomial, +as a linear map. This is used in particular in the proof of the Lindemann-Weierstrass theorem +(see #6718). + +## Main results + +* `Polynomial.sumIDeriv`: Sum of iterated derivatives of a polynomial, as a linear map +* `Polynomial.sumIDeriv_apply`, `Polynomial.sumIDeriv_apply_of_lt`, + `Polynomial.sumIDeriv_apply_of_le`: `Polynomial.sumIDeriv` expressed as a sum +* `Polynomial.sumIDeriv_C`, `Polynomial.sumIDeriv_X`: `Polynomial.sumIDeriv` applied to simple + polynomials +* `Polynomial.sumIDeriv_map`: `Polynomial.sumIDeriv` commutes with `Polynomial.map` +* `Polynomial.sumIDeriv_derivative`: `Polynomial.sumIDeriv` commutes with `Polynomial.derivative` +* `Polynomial.sumIDeriv_eq_self_add`: `sumIDeriv p = p + sumIDeriv (derivative p)` +* `Polynomial.exists_iterate_derivative_eq_factorial_smul`: the `k`'th iterated derivative of a + polynomial has a common factor `k!` +* `Polynomial.aeval_iterate_derivative_of_lt`, `Polynomial.aeval_iterate_derivative_self`, + `Polynomial.aeval_iterate_derivative_of_ge`: applying `Polynomial.aeval` to iterated derivatives +* `Polynomial.aeval_sumIDeriv`, `Polynomial.aeval_sumIDeriv_of_pos`: applying `Polynomial.aeval` to + `Polynomial.sumIDeriv` + +-/ + +open Finset +open scoped Nat + +namespace Polynomial + +variable {R S : Type*} + +section Semiring + +variable [Semiring R] [Semiring S] + +/-- +Sum of iterated derivatives of a polynomial, as a linear map + +This definition does not allow different weights for the derivatives. It is likely that it could be +extended to allow them, but this was not needed for the initial use case (the integration by part +of the integral $I_i$ in the +[Lindemann-Weierstrass](https://en.wikipedia.org/wiki/Lindemann%E2%80%93Weierstrass_theorem) +theorem). +-/ +noncomputable def sumIDeriv : R[X] →ₗ[R] R[X] := + Finsupp.lsum ℕ (fun _ ↦ LinearMap.id) ∘ₗ derivativeFinsupp + +theorem sumIDeriv_apply (p : R[X]) : + sumIDeriv p = ∑ i ∈ range (p.natDegree + 1), derivative^[i] p := by + dsimp [sumIDeriv] + exact Finsupp.sum_of_support_subset _ (by simp) _ (by simp) + +theorem sumIDeriv_apply_of_lt {p : R[X]} {n : ℕ} (hn : p.natDegree < n) : + sumIDeriv p = ∑ i ∈ range n, derivative^[i] p := by + dsimp [sumIDeriv] + exact Finsupp.sum_of_support_subset _ (by simp [hn]) _ (by simp) + +theorem sumIDeriv_apply_of_le {p : R[X]} {n : ℕ} (hn : p.natDegree ≤ n) : + sumIDeriv p = ∑ i ∈ range (n + 1), derivative^[i] p := by + dsimp [sumIDeriv] + exact Finsupp.sum_of_support_subset _ (by simp [Nat.lt_succ, hn]) _ (by simp) + +@[simp] +theorem sumIDeriv_C (a : R) : sumIDeriv (C a) = C a := by + rw [sumIDeriv_apply, natDegree_C, zero_add, sum_range_one, Function.iterate_zero_apply] + +@[simp] +theorem sumIDeriv_X : sumIDeriv X = X + C 1 := by + rw [sumIDeriv_apply, natDegree_X, sum_range_succ, sum_range_one, Function.iterate_zero_apply, + Function.iterate_one, derivative_X, eq_natCast, Nat.cast_one] + +@[simp] +theorem sumIDeriv_map (p : R[X]) (f : R →+* S) : + sumIDeriv (p.map f) = (sumIDeriv p).map f := by + let n := max (p.map f).natDegree p.natDegree + rw [sumIDeriv_apply_of_le (le_max_left _ _ : _ ≤ n)] + rw [sumIDeriv_apply_of_le (le_max_right _ _ : _ ≤ n)] + simp_rw [Polynomial.map_sum, iterate_derivative_map p f] + +theorem sumIDeriv_derivative (p : R[X]) : sumIDeriv (derivative p) = derivative (sumIDeriv p) := by + rw [sumIDeriv_apply_of_le ((natDegree_derivative_le p).trans tsub_le_self), sumIDeriv_apply, + derivative_sum] + simp_rw [← Function.iterate_succ_apply, Function.iterate_succ_apply'] + +theorem sumIDeriv_eq_self_add (p : R[X]) : sumIDeriv p = p + sumIDeriv (derivative p) := by + rw [sumIDeriv_derivative, sumIDeriv_apply, derivative_sum, sum_range_succ', sum_range_succ, + add_comm, ← add_zero (Finset.sum _ _)] + simp_rw [← Function.iterate_succ_apply' derivative, Nat.succ_eq_add_one, + Function.iterate_zero_apply, iterate_derivative_eq_zero (Nat.lt_succ_self _)] + +theorem exists_iterate_derivative_eq_factorial_smul (p : R[X]) (k : ℕ) : + ∃ gp : R[X], gp.natDegree ≤ p.natDegree - k ∧ derivative^[k] p = k ! • gp := by + refine ⟨_, (natDegree_sum_le _ _).trans ?_, iterate_derivative_eq_factorial_smul_sum p k⟩ + rw [fold_max_le] + refine ⟨Nat.zero_le _, fun i hi => ?_⟩ + dsimp only [Function.comp] + exact (natDegree_C_mul_le _ _).trans <| (natDegree_X_pow_le _).trans <| + (le_natDegree_of_mem_supp _ hi).trans <| natDegree_iterate_derivative _ _ + +end Semiring + +section CommSemiring + +variable [CommSemiring R] {A : Type*} [CommRing A] [Algebra R A] + +theorem aeval_iterate_derivative_of_lt (p : R[X]) (q : ℕ) (r : A) {p' : A[X]} + (hp : p.map (algebraMap R A) = (X - C r) ^ q * p') {k : ℕ} (hk : k < q) : + aeval r (derivative^[k] p) = 0 := by + have h (x) : (X - C r) ^ (q - (k - x)) = (X - C r) ^ 1 * (X - C r) ^ (q - (k - x) - 1) := by + rw [← pow_add, add_tsub_cancel_of_le] + rw [Nat.lt_iff_add_one_le] at hk + exact (le_tsub_of_add_le_left hk).trans (tsub_le_tsub_left (tsub_le_self : _ ≤ k) _) + rw [aeval_def, eval₂_eq_eval_map, ← iterate_derivative_map] + simp_rw [hp, iterate_derivative_mul, iterate_derivative_X_sub_pow, ← smul_mul_assoc, smul_smul, + h, ← mul_smul_comm, mul_assoc, ← mul_sum, eval_mul, pow_one, eval_sub, eval_X, eval_C, sub_self, + zero_mul] + +theorem aeval_iterate_derivative_self (p : R[X]) (q : ℕ) (r : A) {p' : A[X]} + (hp : p.map (algebraMap R A) = (X - C r) ^ q * p') : + aeval r (derivative^[q] p) = q ! • p'.eval r := by + have h (x) (h : 1 ≤ x) (h' : x ≤ q) : + (X - C r) ^ (q - (q - x)) = (X - C r) ^ 1 * (X - C r) ^ (q - (q - x) - 1) := by + rw [← pow_add, add_tsub_cancel_of_le] + rwa [tsub_tsub_cancel_of_le h'] + rw [aeval_def, eval₂_eq_eval_map, ← iterate_derivative_map] + simp_rw [hp, iterate_derivative_mul, iterate_derivative_X_sub_pow, ← smul_mul_assoc, smul_smul] + rw [sum_range_succ', Nat.choose_zero_right, one_mul, tsub_zero, Nat.descFactorial_self, tsub_self, + pow_zero, smul_mul_assoc, one_mul, Function.iterate_zero_apply, eval_add, eval_smul] + convert zero_add _ + rw [eval_finset_sum] + apply sum_eq_zero + intro x hx + rw [h (x + 1) le_add_self (Nat.add_one_le_iff.mpr (mem_range.mp hx)), pow_one, + eval_mul, eval_smul, eval_mul, eval_sub, eval_X, eval_C, sub_self, zero_mul, + smul_zero, zero_mul] + +variable (A) + +theorem aeval_iterate_derivative_of_ge (p : R[X]) (q : ℕ) {k : ℕ} (hk : q ≤ k) : + ∃ gp : R[X], gp.natDegree ≤ p.natDegree - k ∧ + ∀ r : A, aeval r (derivative^[k] p) = q ! • aeval r gp := by + obtain ⟨p', p'_le, hp'⟩ := exists_iterate_derivative_eq_factorial_smul p k + obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le hk + refine ⟨((q + k).descFactorial k : R[X]) * p', (natDegree_C_mul_le _ _).trans p'_le, fun r => ?_⟩ + simp_rw [hp', nsmul_eq_mul, map_mul, map_natCast, ← mul_assoc, ← Nat.cast_mul, + Nat.add_descFactorial_eq_ascFactorial, Nat.factorial_mul_ascFactorial] + +theorem aeval_sumIDeriv (p : R[X]) (q : ℕ) : + ∃ gp : R[X], gp.natDegree ≤ p.natDegree - q ∧ + ∀ (r : A) {p' : A[X]}, p.map (algebraMap R A) = (X - C r) ^ q * p' → + aeval r (sumIDeriv p) = q ! • aeval r gp := by + have h (k) : + ∃ gp : R[X], gp.natDegree ≤ p.natDegree - q ∧ + ∀ (r : A) {p' : A[X]}, p.map (algebraMap R A) = (X - C r) ^ q * p' → + aeval r (derivative^[k] p) = q ! • aeval r gp := by + cases lt_or_ge k q with + | inl hk => + use 0 + rw [natDegree_zero] + use Nat.zero_le _ + intro r p' hp + rw [map_zero, smul_zero, aeval_iterate_derivative_of_lt p q r hp hk] + | inr hk => + obtain ⟨gp, gp_le, h⟩ := aeval_iterate_derivative_of_ge A p q hk + exact ⟨gp, gp_le.trans (tsub_le_tsub_left hk _), fun r p' _ => h r⟩ + choose c h using h + choose c_le hc using h + refine ⟨(range (p.natDegree + 1)).sum c, ?_, ?_⟩ + · refine (natDegree_sum_le _ _).trans ?_ + rw [fold_max_le] + exact ⟨Nat.zero_le _, fun i _ => c_le i⟩ + intro r p' hp + rw [sumIDeriv_apply, map_sum]; simp_rw [hc _ r hp, map_sum, smul_sum] + +theorem aeval_sumIDeriv_of_pos [Nontrivial A] [NoZeroDivisors A] (p : R[X]) {q : ℕ} (hq : 0 < q) : + ∃ gp : R[X], gp.natDegree ≤ p.natDegree - q ∧ + ∀ (inj_amap : Function.Injective (algebraMap R A)) (r : A) {p' : A[X]}, + p.map (algebraMap R A) = (X - C r) ^ (q - 1) * p' → + aeval r (sumIDeriv p) = (q - 1)! • p'.eval r + q ! • aeval r gp := by + rcases eq_or_ne p 0 with (rfl | p0) + · use 0 + rw [natDegree_zero] + use Nat.zero_le _ + intro _ r p' hp + rw [map_zero, map_zero, smul_zero, add_zero] + rw [Polynomial.map_zero] at hp + replace hp := (mul_eq_zero.mp hp.symm).resolve_left ?_ + · rw [hp, eval_zero, smul_zero] + exact fun h => X_sub_C_ne_zero r (pow_eq_zero h) + let c k := if hk : q ≤ k then (aeval_iterate_derivative_of_ge A p q hk).choose else 0 + have c_le (k) : (c k).natDegree ≤ p.natDegree - k := by + dsimp only [c] + split_ifs with h + · exact (aeval_iterate_derivative_of_ge A p q h).choose_spec.1 + · rw [natDegree_zero]; exact Nat.zero_le _ + have hc (k) (hk : q ≤ k) : ∀ (r : A), aeval r (derivative^[k] p) = q ! • aeval r (c k) := by + simp_rw [c, dif_pos hk] + exact (aeval_iterate_derivative_of_ge A p q hk).choose_spec.2 + refine ⟨∑ x ∈ Ico q (p.natDegree + 1), c x, ?_, ?_⟩ + · refine (natDegree_sum_le _ _).trans ?_ + rw [fold_max_le] + exact ⟨Nat.zero_le _, fun i hi => (c_le i).trans (tsub_le_tsub_left (mem_Ico.mp hi).1 _)⟩ + intro inj_amap 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 [← 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)] + rw [sum_union, this, sum_range_succ] + · congr 2 + · apply sum_eq_zero + exact fun x hx => aeval_iterate_derivative_of_lt p _ r hp (mem_range.mp hx) + · rw [← aeval_iterate_derivative_self _ _ _ hp] + · rw [smul_sum, sum_congr rfl] + intro k hk + exact hc k (mem_Ico.mp hk).1 r + · rw [range_eq_Ico, disjoint_iff_inter_eq_empty, eq_empty_iff_forall_not_mem] + intro x hx + rw [mem_inter, mem_Ico, mem_Ico] at hx + exact hx.1.2.not_le hx.2.1 + +end CommSemiring + +end Polynomial diff --git a/Mathlib/Algebra/Polynomial/Taylor.lean b/Mathlib/Algebra/Polynomial/Taylor.lean index 4a89d16c0bea7..418f3fbd7124f 100644 --- a/Mathlib/Algebra/Polynomial/Taylor.lean +++ b/Mathlib/Algebra/Polynomial/Taylor.lean @@ -32,7 +32,7 @@ variable {R : Type*} [Semiring R] (r : R) (f : R[X]) /-- The Taylor expansion of a polynomial `f` at `r`. -/ def taylor (r : R) : R[X] →ₗ[R] R[X] where toFun f := f.comp (X + C r) - map_add' f g := add_comp + map_add' _ _ := add_comp map_smul' c f := by simp only [smul_eq_C_mul, C_mul_comp, RingHom.id_apply] theorem taylor_apply : taylor r f = f.comp (X + C r) := diff --git a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean index c21059979dbcf..b9f7798bd6c4c 100644 --- a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean +++ b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean @@ -5,6 +5,7 @@ Authors: Thomas Browning -/ import Mathlib.Algebra.Polynomial.Mirror import Mathlib.Data.Int.Order.Units +import Mathlib.RingTheory.Coprime.Basic /-! # Unit Trinomials @@ -128,7 +129,7 @@ theorem not_isUnit (hp : p.IsUnitTrinomial) : ¬IsUnit p := by ((trinomial_natDegree hkm hmn w.ne_zero).symm.trans (natDegree_eq_of_degree_eq_some (degree_eq_zero_of_isUnit h))) -theorem card_support_eq_three (hp : p.IsUnitTrinomial) : p.support.card = 3 := by +theorem card_support_eq_three (hp : p.IsUnitTrinomial) : #p.support = 3 := by obtain ⟨k, m, n, hkm, hmn, u, v, w, rfl⟩ := hp exact card_support_trinomial hkm hmn u.ne_zero v.ne_zero w.ne_zero @@ -155,7 +156,7 @@ theorem trailingCoeff_isUnit (hp : p.IsUnitTrinomial) : IsUnit p.trailingCoeff : end IsUnitTrinomial theorem isUnitTrinomial_iff : - p.IsUnitTrinomial ↔ p.support.card = 3 ∧ ∀ k ∈ p.support, IsUnit (p.coeff k) := by + p.IsUnitTrinomial ↔ #p.support = 3 ∧ ∀ k ∈ p.support, IsUnit (p.coeff k) := by refine ⟨fun hp => ⟨hp.card_support_eq_three, fun k => hp.coeff_isUnit⟩, fun hp => ?_⟩ obtain ⟨k, m, n, hkm, hmn, x, y, z, hx, hy, hz, rfl⟩ := card_support_eq_three.mp hp.1 rw [support_trinomial hkm hmn hx hy hz] at hp diff --git a/Mathlib/Algebra/Prime/Defs.lean b/Mathlib/Algebra/Prime/Defs.lean new file mode 100644 index 0000000000000..90165b72d0050 --- /dev/null +++ b/Mathlib/Algebra/Prime/Defs.lean @@ -0,0 +1,191 @@ +/- +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.GroupWithZero.Divisibility + +/-! +# Prime and irreducible elements. + +In this file we define the predicate `Prime p` +saying that an element of a commutative monoid with zero is prime. +Namely, `Prime p` means that `p` isn't zero, it isn't a unit, +and `p ∣ a * b → p ∣ a ∨ p ∣ b` for all `a`, `b`; + +In decomposition monoids (e.g., `ℕ`, `ℤ`), this predicate is equivalent to `Irreducible` +(see `irreducible_iff_prime`), however this is not true in general. + +## Main definitions + * `Prime`: a prime element of a commutative monoid with zero + * `Irreducible`: an irreducible element of a commutative monoid with zero + +## Main results + * `irreducible_iff_prime`: the two definitions are equivalent in a decomposition monoid. +-/ + +assert_not_exists OrderedCommMonoid +assert_not_exists Multiset + +variable {M N : Type*} + +section Prime + +variable [CommMonoidWithZero M] + +/-- An element `p` of a commutative monoid with zero (e.g., a ring) is called *prime*, +if it's not zero, not a unit, and `p ∣ a * b → p ∣ a ∨ p ∣ b` for all `a`, `b`. -/ +def Prime (p : M) : Prop := + p ≠ 0 ∧ ¬IsUnit p ∧ ∀ a b, p ∣ a * b → p ∣ a ∨ p ∣ b + +namespace Prime + +variable {p : M} (hp : Prime p) +include hp + +theorem ne_zero : p ≠ 0 := + hp.1 + +theorem not_unit : ¬IsUnit p := + hp.2.1 + +theorem not_dvd_one : ¬p ∣ 1 := + mt (isUnit_of_dvd_one ·) hp.not_unit + +theorem ne_one : p ≠ 1 := fun h => hp.2.1 (h.symm ▸ isUnit_one) + +theorem dvd_or_dvd {a b : M} (h : p ∣ a * b) : p ∣ a ∨ p ∣ b := + hp.2.2 a b h + +theorem dvd_mul {a b : M} : p ∣ a * b ↔ p ∣ a ∨ p ∣ b := + ⟨hp.dvd_or_dvd, (Or.elim · (dvd_mul_of_dvd_left · _) (dvd_mul_of_dvd_right · _))⟩ + +theorem isPrimal : IsPrimal p := fun _a _b dvd ↦ (hp.dvd_or_dvd dvd).elim + (fun h ↦ ⟨p, 1, h, one_dvd _, (mul_one p).symm⟩) fun h ↦ ⟨1, p, one_dvd _, h, (one_mul p).symm⟩ + +theorem not_dvd_mul {a b : M} (ha : ¬ p ∣ a) (hb : ¬ p ∣ b) : ¬ p ∣ a * b := + hp.dvd_mul.not.mpr <| not_or.mpr ⟨ha, hb⟩ + +theorem dvd_of_dvd_pow {a : M} {n : ℕ} (h : p ∣ a ^ n) : p ∣ a := by + induction n with + | zero => + rw [pow_zero] at h + have := isUnit_of_dvd_one h + have := not_unit hp + contradiction + | succ n ih => + rw [pow_succ'] at h + rcases dvd_or_dvd hp h with dvd_a | dvd_pow + · assumption + · exact ih dvd_pow + +theorem dvd_pow_iff_dvd {a : M} {n : ℕ} (hn : n ≠ 0) : p ∣ a ^ n ↔ p ∣ a := + ⟨hp.dvd_of_dvd_pow, (dvd_pow · hn)⟩ + +end Prime + +@[simp] +theorem not_prime_zero : ¬Prime (0 : M) := fun h => h.ne_zero rfl + +@[simp] +theorem not_prime_one : ¬Prime (1 : M) := fun h => h.not_unit isUnit_one + +end Prime + +/-- `Irreducible p` states that `p` is non-unit and only factors into units. + +We explicitly avoid stating that `p` is non-zero, this would require a semiring. Assuming only a +monoid allows us to reuse irreducible for associated elements. +-/ +structure Irreducible [Monoid M] (p : M) : Prop where + /-- `p` is not a unit -/ + not_unit : ¬IsUnit p + /-- if `p` factors then one factor is a unit -/ + isUnit_or_isUnit' : ∀ a b, p = a * b → IsUnit a ∨ IsUnit b + +namespace Irreducible + +theorem not_dvd_one [CommMonoid M] {p : M} (hp : Irreducible p) : ¬p ∣ 1 := + mt (isUnit_of_dvd_one ·) hp.not_unit + +theorem isUnit_or_isUnit [Monoid M] {p : M} (hp : Irreducible p) {a b : M} (h : p = a * b) : + IsUnit a ∨ IsUnit b := + hp.isUnit_or_isUnit' a b h + +end Irreducible + +theorem irreducible_iff [Monoid M] {p : M} : + Irreducible p ↔ ¬IsUnit p ∧ ∀ a b, p = a * b → IsUnit a ∨ IsUnit b := + ⟨fun h => ⟨h.1, h.2⟩, fun h => ⟨h.1, h.2⟩⟩ + +@[simp] +theorem not_irreducible_one [Monoid M] : ¬Irreducible (1 : M) := by simp [irreducible_iff] + +theorem Irreducible.ne_one [Monoid M] : ∀ {p : M}, Irreducible p → p ≠ 1 + | _, hp, rfl => not_irreducible_one hp + +@[simp] +theorem not_irreducible_zero [MonoidWithZero M] : ¬Irreducible (0 : M) + | ⟨hn0, h⟩ => + have : IsUnit (0 : M) ∨ IsUnit (0 : M) := h 0 0 (mul_zero 0).symm + this.elim hn0 hn0 + +theorem Irreducible.ne_zero [MonoidWithZero M] : ∀ {p : M}, Irreducible p → p ≠ 0 + | _, hp, rfl => not_irreducible_zero hp + +theorem of_irreducible_mul {M} [Monoid M] {x y : M} : Irreducible (x * y) → IsUnit x ∨ IsUnit y + | ⟨_, h⟩ => h _ _ rfl + +theorem irreducible_or_factor {M} [Monoid M] (x : M) (h : ¬IsUnit x) : + Irreducible x ∨ ∃ a b, ¬IsUnit a ∧ ¬IsUnit b ∧ a * b = x := by + haveI := Classical.dec + refine or_iff_not_imp_right.2 fun H => ?_ + simp? [h, irreducible_iff] at H ⊢ says + simp only [exists_and_left, not_exists, not_and, irreducible_iff, h, not_false_eq_true, + true_and] at H ⊢ + refine fun a b h => by_contradiction fun o => ?_ + simp? [not_or] at o says simp only [not_or] at o + exact H _ o.1 _ o.2 h.symm + +/-- If `p` and `q` are irreducible, then `p ∣ q` implies `q ∣ p`. -/ +theorem Irreducible.dvd_symm [Monoid M] {p q : M} (hp : Irreducible p) (hq : Irreducible q) : + p ∣ q → q ∣ p := by + rintro ⟨q', rfl⟩ + rw [IsUnit.mul_right_dvd (Or.resolve_left (of_irreducible_mul hq) hp.not_unit)] + +theorem Irreducible.dvd_comm [Monoid M] {p q : M} (hp : Irreducible p) (hq : Irreducible q) : + p ∣ q ↔ q ∣ p := + ⟨hp.dvd_symm hq, hq.dvd_symm hp⟩ + +section CommMonoidWithZero + +variable [CommMonoidWithZero M] + +theorem Irreducible.prime_of_isPrimal {a : M} + (irr : Irreducible a) (primal : IsPrimal a) : Prime a := + ⟨irr.ne_zero, irr.not_unit, fun a b dvd ↦ by + obtain ⟨d₁, d₂, h₁, h₂, rfl⟩ := primal dvd + exact (of_irreducible_mul irr).symm.imp (·.mul_right_dvd.mpr h₁) (·.mul_left_dvd.mpr h₂)⟩ + +theorem Irreducible.prime [DecompositionMonoid M] {a : M} (irr : Irreducible a) : Prime a := + irr.prime_of_isPrimal (DecompositionMonoid.primal a) + +end CommMonoidWithZero + +section CancelCommMonoidWithZero + +variable [CancelCommMonoidWithZero M] {a p : M} + +protected theorem Prime.irreducible (hp : Prime p) : Irreducible p := + ⟨hp.not_unit, fun a b ↦ by + rintro rfl + exact (hp.dvd_or_dvd dvd_rfl).symm.imp + (isUnit_of_dvd_one <| (mul_dvd_mul_iff_right <| right_ne_zero_of_mul hp.ne_zero).mp <| + dvd_mul_of_dvd_right · _) + (isUnit_of_dvd_one <| (mul_dvd_mul_iff_left <| left_ne_zero_of_mul hp.ne_zero).mp <| + dvd_mul_of_dvd_left · _)⟩ + +theorem irreducible_iff_prime [DecompositionMonoid M] {a : M} : Irreducible a ↔ Prime a := + ⟨Irreducible.prime, Prime.irreducible⟩ + +end CancelCommMonoidWithZero diff --git a/Mathlib/Algebra/Prime/Lemmas.lean b/Mathlib/Algebra/Prime/Lemmas.lean new file mode 100644 index 0000000000000..96ee461f3831f --- /dev/null +++ b/Mathlib/Algebra/Prime/Lemmas.lean @@ -0,0 +1,276 @@ +/- +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.Group.Commute.Units +import Mathlib.Algebra.Group.Even +import Mathlib.Algebra.Group.Units.Equiv +import Mathlib.Algebra.GroupWithZero.Hom +import Mathlib.Algebra.Prime.Defs +import Mathlib.Order.Lattice + +/-! +# Associated, prime, and irreducible elements. + +In this file we define the predicate `Prime p` +saying that an element of a commutative monoid with zero is prime. +Namely, `Prime p` means that `p` isn't zero, it isn't a unit, +and `p ∣ a * b → p ∣ a ∨ p ∣ b` for all `a`, `b`; + +In decomposition monoids (e.g., `ℕ`, `ℤ`), this predicate is equivalent to `Irreducible`, +however this is not true in general. + +We also define an equivalence relation `Associated` +saying that two elements of a monoid differ by a multiplication by a unit. +Then we show that the quotient type `Associates` is a monoid +and prove basic properties of this quotient. +-/ + +assert_not_exists OrderedCommMonoid +assert_not_exists Multiset + +variable {M N : Type*} + +section Prime + +variable [CommMonoidWithZero M] + +section Map + +variable [CommMonoidWithZero N] {F : Type*} {G : Type*} [FunLike F M N] +variable [MonoidWithZeroHomClass F M N] [FunLike G N M] [MulHomClass G N M] +variable (f : F) (g : G) {p : M} + +theorem comap_prime (hinv : ∀ a, g (f a : N) = a) (hp : Prime (f p)) : Prime p := + ⟨fun h => hp.1 <| by simp [h], fun h => hp.2.1 <| h.map f, fun a b h => by + refine + (hp.2.2 (f a) (f b) <| by + convert map_dvd f h + simp).imp + ?_ ?_ <;> + · intro h + convert ← map_dvd g h <;> apply hinv⟩ + +theorem MulEquiv.prime_iff (e : M ≃* N) : Prime p ↔ Prime (e p) := + ⟨fun h => (comap_prime e.symm e fun a => by simp) <| (e.symm_apply_apply p).substr h, + comap_prime e e.symm fun a => by simp⟩ + +end Map + +end Prime + +theorem Prime.left_dvd_or_dvd_right_of_dvd_mul [CancelCommMonoidWithZero M] {p : M} (hp : Prime p) + {a b : M} : a ∣ p * b → p ∣ a ∨ a ∣ b := by + rintro ⟨c, hc⟩ + rcases hp.2.2 a c (hc ▸ dvd_mul_right _ _) with (h | ⟨x, rfl⟩) + · exact Or.inl h + · rw [mul_left_comm, mul_right_inj' hp.ne_zero] at hc + exact Or.inr (hc.symm ▸ dvd_mul_right _ _) + +theorem Prime.pow_dvd_of_dvd_mul_left [CancelCommMonoidWithZero M] {p a b : M} (hp : Prime p) + (n : ℕ) (h : ¬p ∣ a) (h' : p ^ n ∣ a * b) : p ^ n ∣ b := by + induction n with + | zero => + rw [pow_zero] + exact one_dvd b + | succ n ih => + obtain ⟨c, rfl⟩ := ih (dvd_trans (pow_dvd_pow p n.le_succ) h') + rw [pow_succ] + apply mul_dvd_mul_left _ ((hp.dvd_or_dvd _).resolve_left h) + rwa [← mul_dvd_mul_iff_left (pow_ne_zero n hp.ne_zero), ← pow_succ, mul_left_comm] + +theorem Prime.pow_dvd_of_dvd_mul_right [CancelCommMonoidWithZero M] {p a b : M} (hp : Prime p) + (n : ℕ) (h : ¬p ∣ b) (h' : p ^ n ∣ a * b) : p ^ n ∣ a := by + rw [mul_comm] at h' + exact hp.pow_dvd_of_dvd_mul_left n h h' + +theorem Prime.dvd_of_pow_dvd_pow_mul_pow_of_square_not_dvd [CancelCommMonoidWithZero M] {p a b : M} + {n : ℕ} (hp : Prime p) (hpow : p ^ n.succ ∣ a ^ n.succ * b ^ n) (hb : ¬p ^ 2 ∣ b) : p ∣ a := by + -- Suppose `p ∣ b`, write `b = p * x` and `hy : a ^ n.succ * b ^ n = p ^ n.succ * y`. + rcases hp.dvd_or_dvd ((dvd_pow_self p (Nat.succ_ne_zero n)).trans hpow) with H | hbdiv + · exact hp.dvd_of_dvd_pow H + obtain ⟨x, rfl⟩ := hp.dvd_of_dvd_pow hbdiv + obtain ⟨y, hy⟩ := hpow + -- Then we can divide out a common factor of `p ^ n` from the equation `hy`. + have : a ^ n.succ * x ^ n = p * y := by + refine mul_left_cancel₀ (pow_ne_zero n hp.ne_zero) ?_ + rw [← mul_assoc _ p, ← pow_succ, ← hy, mul_pow, ← mul_assoc (a ^ n.succ), mul_comm _ (p ^ n), + mul_assoc] + -- So `p ∣ a` (and we're done) or `p ∣ x`, which can't be the case since it implies `p^2 ∣ b`. + refine hp.dvd_of_dvd_pow ((hp.dvd_or_dvd ⟨_, this⟩).resolve_right fun hdvdx => hb ?_) + obtain ⟨z, rfl⟩ := hp.dvd_of_dvd_pow hdvdx + rw [pow_two, ← mul_assoc] + exact dvd_mul_right _ _ + +theorem prime_pow_succ_dvd_mul {M : Type*} [CancelCommMonoidWithZero M] {p x y : M} (h : Prime p) + {i : ℕ} (hxy : p ^ (i + 1) ∣ x * y) : p ^ (i + 1) ∣ x ∨ p ∣ y := by + rw [or_iff_not_imp_right] + intro hy + induction i generalizing x with + | zero => rw [pow_one] at hxy ⊢; exact (h.dvd_or_dvd hxy).resolve_right hy + | succ i ih => + rw [pow_succ'] at hxy ⊢ + obtain ⟨x', rfl⟩ := (h.dvd_or_dvd (dvd_of_mul_right_dvd hxy)).resolve_right hy + rw [mul_assoc] at hxy + exact mul_dvd_mul_left p (ih ((mul_dvd_mul_iff_left h.ne_zero).mp hxy)) + +theorem not_irreducible_pow {M} [Monoid M] {x : M} {n : ℕ} (hn : n ≠ 1) : + ¬ Irreducible (x ^ n) := by + cases n with + | zero => simp + | succ n => + intro ⟨h₁, h₂⟩ + have := h₂ _ _ (pow_succ _ _) + rw [isUnit_pow_iff (Nat.succ_ne_succ.mp hn), or_self] at this + exact h₁ (this.pow _) + +theorem Irreducible.of_map {F : Type*} [Monoid M] [Monoid N] [FunLike F M N] [MonoidHomClass F M N] + {f : F} [IsLocalHom f] {x} (hfx : Irreducible (f x)) : Irreducible x := + ⟨fun hu ↦ hfx.not_unit <| hu.map f, + by rintro p q rfl + exact (hfx.isUnit_or_isUnit <| map_mul f p q).imp (.of_map f _) (.of_map f _)⟩ + +section + +variable [Monoid M] + +theorem irreducible_units_mul (a : Mˣ) (b : M) : Irreducible (↑a * b) ↔ Irreducible b := by + simp only [irreducible_iff, Units.isUnit_units_mul, and_congr_right_iff] + refine fun _ => ⟨fun h A B HAB => ?_, fun h A B HAB => ?_⟩ + · rw [← a.isUnit_units_mul] + apply h + rw [mul_assoc, ← HAB] + · rw [← a⁻¹.isUnit_units_mul] + apply h + rw [mul_assoc, ← HAB, Units.inv_mul_cancel_left] + +theorem irreducible_isUnit_mul {a b : M} (h : IsUnit a) : Irreducible (a * b) ↔ Irreducible b := + let ⟨a, ha⟩ := h + ha ▸ irreducible_units_mul a b + +theorem irreducible_mul_units (a : Mˣ) (b : M) : Irreducible (b * ↑a) ↔ Irreducible b := by + simp only [irreducible_iff, Units.isUnit_mul_units, and_congr_right_iff] + refine fun _ => ⟨fun h A B HAB => ?_, fun h A B HAB => ?_⟩ + · rw [← Units.isUnit_mul_units B a] + apply h + rw [← mul_assoc, ← HAB] + · rw [← Units.isUnit_mul_units B a⁻¹] + apply h + rw [← mul_assoc, ← HAB, Units.mul_inv_cancel_right] + +theorem irreducible_mul_isUnit {a b : M} (h : IsUnit a) : Irreducible (b * a) ↔ Irreducible b := + let ⟨a, ha⟩ := h + ha ▸ irreducible_mul_units a b + +theorem irreducible_mul_iff {a b : M} : + Irreducible (a * b) ↔ Irreducible a ∧ IsUnit b ∨ Irreducible b ∧ IsUnit a := by + constructor + · refine fun h => Or.imp (fun h' => ⟨?_, h'⟩) (fun h' => ⟨?_, h'⟩) (h.isUnit_or_isUnit rfl).symm + · rwa [irreducible_mul_isUnit h'] at h + · rwa [irreducible_isUnit_mul h'] at h + · rintro (⟨ha, hb⟩ | ⟨hb, ha⟩) + · rwa [irreducible_mul_isUnit hb] + · rwa [irreducible_isUnit_mul ha] + +variable [Monoid N] {F : Type*} [EquivLike F M N] [MulEquivClass F M N] (f : F) + +open MulEquiv + +/-- +Irreducibility is preserved by multiplicative equivalences. +Note that surjective + local hom is not enough. Consider the additive monoids `M = ℕ ⊕ ℕ`, `N = ℕ`, +with a surjective local (additive) hom `f : M →+ N` sending `(m, n)` to `2m + n`. +It is local because the only add unit in `N` is `0`, with preimage `{(0, 0)}` also an add unit. +Then `x = (1, 0)` is irreducible in `M`, but `f x = 2 = 1 + 1` is not irreducible in `N`. +-/ +theorem Irreducible.map {x : M} (h : Irreducible x) : Irreducible (f x) := + ⟨fun g ↦ h.not_unit g.of_map, fun a b g ↦ + let f := MulEquivClass.toMulEquiv f + (h.isUnit_or_isUnit (symm_apply_apply f x ▸ map_mul f.symm a b ▸ congrArg f.symm g)).imp + (·.of_map) (·.of_map)⟩ + +theorem MulEquiv.irreducible_iff (f : F) {a : M} : + Irreducible (f a) ↔ Irreducible a := + ⟨Irreducible.of_map, Irreducible.map f⟩ + +end + +section CommMonoid + +variable [CommMonoid M] {a : M} + +theorem Irreducible.not_square (ha : Irreducible a) : ¬IsSquare a := by + rw [isSquare_iff_exists_sq] + rintro ⟨b, rfl⟩ + exact not_irreducible_pow (by decide) ha + +theorem IsSquare.not_irreducible (ha : IsSquare a) : ¬Irreducible a := fun h => h.not_square ha + +end CommMonoid + +section CancelCommMonoidWithZero + +variable [CancelCommMonoidWithZero M] {a p : M} + +theorem succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul (hp : Prime p) {a b : M} {k l : ℕ} : + p ^ k ∣ a → p ^ l ∣ b → p ^ (k + l + 1) ∣ a * b → p ^ (k + 1) ∣ a ∨ p ^ (l + 1) ∣ b := + fun ⟨x, hx⟩ ⟨y, hy⟩ ⟨z, hz⟩ => + have h : p ^ (k + l) * (x * y) = p ^ (k + l) * (p * z) := by + simpa [mul_comm, pow_add, hx, hy, mul_assoc, mul_left_comm] using hz + have hp0 : p ^ (k + l) ≠ 0 := pow_ne_zero _ hp.ne_zero + have hpd : p ∣ x * y := ⟨z, by rwa [mul_right_inj' hp0] at h⟩ + (hp.dvd_or_dvd hpd).elim + (fun ⟨d, hd⟩ => Or.inl ⟨d, by simp [*, pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩) + fun ⟨d, hd⟩ => Or.inr ⟨d, by simp [*, pow_succ, mul_comm, mul_left_comm, mul_assoc]⟩ + +theorem Prime.not_square (hp : Prime p) : ¬IsSquare p := + hp.irreducible.not_square + +theorem IsSquare.not_prime (ha : IsSquare a) : ¬Prime a := fun h => h.not_square ha + +theorem not_prime_pow {n : ℕ} (hn : n ≠ 1) : ¬Prime (a ^ n) := fun hp => + not_irreducible_pow hn hp.irreducible + +end CancelCommMonoidWithZero + +section CommMonoidWithZero + +theorem DvdNotUnit.isUnit_of_irreducible_right [CommMonoidWithZero M] {p q : M} + (h : DvdNotUnit p q) (hq : Irreducible q) : IsUnit p := by + obtain ⟨_, x, hx, hx'⟩ := h + exact Or.resolve_right ((irreducible_iff.1 hq).right p x hx') hx + +theorem not_irreducible_of_not_unit_dvdNotUnit [CommMonoidWithZero M] {p q : M} (hp : ¬IsUnit p) + (h : DvdNotUnit p q) : ¬Irreducible q := + mt h.isUnit_of_irreducible_right hp + +theorem DvdNotUnit.not_unit [CommMonoidWithZero M] {p q : M} (hp : DvdNotUnit p q) : ¬IsUnit q := by + obtain ⟨-, x, hx, rfl⟩ := hp + exact fun hc => hx (isUnit_iff_dvd_one.mpr (dvd_of_mul_left_dvd (isUnit_iff_dvd_one.mp hc))) + +end CommMonoidWithZero + +section CancelCommMonoidWithZero + +theorem DvdNotUnit.ne [CancelCommMonoidWithZero M] {p q : M} (h : DvdNotUnit p q) : p ≠ q := by + by_contra hcontra + obtain ⟨hp, x, hx', hx''⟩ := h + conv_lhs at hx'' => rw [← hcontra, ← mul_one p] + rw [(mul_left_cancel₀ hp hx'').symm] at hx' + exact hx' isUnit_one + +theorem pow_injective_of_not_isUnit [CancelCommMonoidWithZero M] {q : M} (hq : ¬IsUnit q) + (hq' : q ≠ 0) : Function.Injective fun n : ℕ => q ^ n := by + refine injective_of_lt_imp_ne fun n m h => DvdNotUnit.ne ⟨pow_ne_zero n hq', q ^ (m - n), ?_, ?_⟩ + · exact not_isUnit_of_not_isUnit_dvd hq (dvd_pow (dvd_refl _) (Nat.sub_pos_of_lt h).ne') + · exact (pow_mul_pow_sub q h.le).symm + +@[deprecated (since := "2024-09-22")] +alias pow_injective_of_not_unit := pow_injective_of_not_isUnit + +theorem pow_inj_of_not_isUnit [CancelCommMonoidWithZero M] {q : M} (hq : ¬IsUnit q) + (hq' : q ≠ 0) {m n : ℕ} : q ^ m = q ^ n ↔ m = n := + (pow_injective_of_not_isUnit hq hq').eq_iff + +end CancelCommMonoidWithZero diff --git a/Mathlib/Algebra/Quandle.lean b/Mathlib/Algebra/Quandle.lean index a3921e4072e72..d02c6b1972aa1 100644 --- a/Mathlib/Algebra/Quandle.lean +++ b/Mathlib/Algebra/Quandle.lean @@ -100,9 +100,9 @@ class Shelf (α : Type u) where A *unital shelf* is a shelf equipped with an element `1` such that, for all elements `x`, we have both `x ◃ 1` and `1 ◃ x` equal `x`. -/ -class UnitalShelf (α : Type u) extends Shelf α, One α := -(one_act : ∀ a : α, act 1 a = a) -(act_one : ∀ a : α, act a 1 = a) +class UnitalShelf (α : Type u) extends Shelf α, One α where + one_act : ∀ a : α, act 1 a = a + act_one : ∀ a : α, act a 1 = a /-- The type of homomorphisms between shelves. This is also the notion of rack and quandle homomorphisms. @@ -599,11 +599,11 @@ def EnvelGroup (R : Type*) [Rack R] := -- TODO: is there a non-invasive way of defining the instance directly? instance (R : Type*) [Rack R] : DivInvMonoid (EnvelGroup R) where mul a b := - Quotient.liftOn₂ a b (fun a b => ⟦PreEnvelGroup.mul a b⟧) fun a b a' b' ⟨ha⟩ ⟨hb⟩ => + Quotient.liftOn₂ a b (fun a b => ⟦PreEnvelGroup.mul a b⟧) fun _ _ _ _ ⟨ha⟩ ⟨hb⟩ => Quotient.sound (PreEnvelGroupRel'.congr_mul ha hb).rel one := ⟦unit⟧ inv a := - Quotient.liftOn a (fun a => ⟦PreEnvelGroup.inv a⟧) fun a a' ⟨ha⟩ => + Quotient.liftOn a (fun a => ⟦PreEnvelGroup.inv a⟧) fun _ _ ⟨ha⟩ => Quotient.sound (PreEnvelGroupRel'.congr_inv ha).rel mul_assoc a b c := Quotient.inductionOn₃ a b c fun a b c => Quotient.sound (PreEnvelGroupRel'.assoc a b c).rel @@ -643,9 +643,9 @@ open PreEnvelGroupRel' theorem well_def {R : Type*} [Rack R] {G : Type*} [Group G] (f : R →◃ Quandle.Conj G) : ∀ {a b : PreEnvelGroup R}, PreEnvelGroupRel' R a b → toEnvelGroup.mapAux f a = toEnvelGroup.mapAux f b - | a, _, PreEnvelGroupRel'.refl => rfl - | a, b, PreEnvelGroupRel'.symm h => (well_def f h).symm - | a, b, PreEnvelGroupRel'.trans hac hcb => Eq.trans (well_def f hac) (well_def f hcb) + | _, _, PreEnvelGroupRel'.refl => rfl + | _, _, PreEnvelGroupRel'.symm h => (well_def f h).symm + | _, _, PreEnvelGroupRel'.trans hac hcb => Eq.trans (well_def f hac) (well_def f hcb) | _, _, PreEnvelGroupRel'.congr_mul ha hb => by simp [toEnvelGroup.mapAux, well_def f ha, well_def f hb] | _, _, congr_inv ha => by simp [toEnvelGroup.mapAux, well_def f ha] @@ -664,7 +664,7 @@ def toEnvelGroup.map {R : Type*} [Rack R] {G : Type*} [Group G] : (R →◃ Quandle.Conj G) ≃ (EnvelGroup R →* G) where toFun f := { toFun := fun x => - Quotient.liftOn x (toEnvelGroup.mapAux f) fun a b ⟨hab⟩ => + Quotient.liftOn x (toEnvelGroup.mapAux f) fun _ _ ⟨hab⟩ => toEnvelGroup.mapAux.well_def f hab map_one' := by change Quotient.liftOn ⟦Rack.PreEnvelGroup.unit⟧ (toEnvelGroup.mapAux f) _ = 1 diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index f78db6c9f424a..6fe9d273656aa 100644 --- a/Mathlib/Algebra/Quaternion.lean +++ b/Mathlib/Algebra/Quaternion.lean @@ -7,7 +7,7 @@ import Mathlib.Algebra.Algebra.Equiv import Mathlib.LinearAlgebra.Dimension.StrongRankCondition import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.FreeModule.Finite.Basic -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic /-! # Quaternions @@ -1282,15 +1282,12 @@ instance instDivisionRing : DivisionRing ℍ[R] where nnqsmul_def q x := by rw [← coe_nnratCast, coe_mul_eq_smul]; ext <;> exact NNRat.smul_def _ _ qsmul_def q x := by rw [← coe_ratCast, coe_mul_eq_smul]; ext <;> exact Rat.smul_def _ _ ---@[simp] Porting note (#10618): `simp` can prove it theorem normSq_inv : normSq a⁻¹ = (normSq a)⁻¹ := map_inv₀ normSq _ ---@[simp] Porting note (#10618): `simp` can prove it theorem normSq_div : normSq (a / b) = normSq a / normSq b := map_div₀ normSq a b ---@[simp] Porting note (#10618): `simp` can prove it theorem normSq_zpow (z : ℤ) : normSq (a ^ z) = normSq a ^ z := map_zpow₀ normSq a z @@ -1330,7 +1327,6 @@ theorem mk_quaternionAlgebra_of_infinite [Infinite R] : #(ℍ[R,c₁,c₂]) = #R theorem mk_univ_quaternionAlgebra : #(Set.univ : Set ℍ[R,c₁,c₂]) = #R ^ 4 := by rw [mk_univ, mk_quaternionAlgebra] ---@[simp] Porting note (#10618): `simp` can prove it theorem mk_univ_quaternionAlgebra_of_infinite [Infinite R] : #(Set.univ : Set ℍ[R,c₁,c₂]) = #R := by rw [mk_univ_quaternionAlgebra, pow_four] @@ -1359,7 +1355,6 @@ theorem mk_quaternion_of_infinite [Infinite R] : #(ℍ[R]) = #R := mk_quaternionAlgebra_of_infinite _ _ /-- The cardinality of the quaternions, as a set. -/ ---@[simp] Porting note (#10618): `simp` can prove it theorem mk_univ_quaternion : #(Set.univ : Set ℍ[R]) = #R ^ 4 := mk_univ_quaternionAlgebra _ _ diff --git a/Mathlib/Algebra/Regular/Basic.lean b/Mathlib/Algebra/Regular/Basic.lean index 0a534b873b9c3..fd81ff23fd8c0 100644 --- a/Mathlib/Algebra/Regular/Basic.lean +++ b/Mathlib/Algebra/Regular/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ import Mathlib.Algebra.Group.Commute.Defs -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Defs import Mathlib.Algebra.GroupWithZero.Defs import Mathlib.Algebra.Order.Monoid.Unbundled.Basic import Mathlib.Tactic.NthRewrite diff --git a/Mathlib/Algebra/Regular/SMul.lean b/Mathlib/Algebra/Regular/SMul.lean index 5895185e0774c..3dfb2cff80cf0 100644 --- a/Mathlib/Algebra/Regular/SMul.lean +++ b/Mathlib/Algebra/Regular/SMul.lean @@ -162,8 +162,7 @@ end MonoidSMul section MonoidWithZero -variable [MonoidWithZero R] [MonoidWithZero S] [Zero M] [MulActionWithZero R M] - [MulActionWithZero R S] [MulActionWithZero S M] [IsScalarTower R S M] +variable [MonoidWithZero R] [Zero M] [MulActionWithZero R M] /-- The element `0` is `M`-regular if and only if `M` is trivial. -/ protected theorem subsingleton (h : IsSMulRegular M (0 : R)) : Subsingleton M := diff --git a/Mathlib/Algebra/Ring/Action/Basic.lean b/Mathlib/Algebra/Ring/Action/Basic.lean index d085e72efe2c3..d29c1984e45d9 100644 --- a/Mathlib/Algebra/Ring/Action/Basic.lean +++ b/Mathlib/Algebra/Ring/Action/Basic.lean @@ -3,7 +3,7 @@ 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.GroupWithZero.Action.Defs +import Mathlib.Algebra.GroupWithZero.Action.End import Mathlib.Algebra.Ring.Hom.Defs /-! @@ -46,7 +46,8 @@ variable (M N : Type*) [Monoid M] [Monoid N] variable (R : Type v) [Semiring R] -- note we could not use `extends` since these typeclasses are made with `old_structure_cmd` -instance (priority := 100) MulSemiringAction.toMulDistribMulAction [h : MulSemiringAction M R] : +instance (priority := 100) MulSemiringAction.toMulDistribMulAction + (M R) {_ : Monoid M} {_ : Semiring R} [h : MulSemiringAction M R] : MulDistribMulAction M R := { h with } diff --git a/Mathlib/Algebra/Ring/Action/Subobjects.lean b/Mathlib/Algebra/Ring/Action/Subobjects.lean index d2e0376c2b7b3..9a15aad35c85a 100644 --- a/Mathlib/Algebra/Ring/Action/Subobjects.lean +++ b/Mathlib/Algebra/Ring/Action/Subobjects.lean @@ -3,7 +3,7 @@ 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.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.Algebra.Group.Submonoid.DistribMulAction import Mathlib.Algebra.Ring.Action.Basic diff --git a/Mathlib/Algebra/Ring/AddAut.lean b/Mathlib/Algebra/Ring/AddAut.lean index f593f12d75bda..8a75d5e9bcde8 100644 --- a/Mathlib/Algebra/Ring/AddAut.lean +++ b/Mathlib/Algebra/Ring/AddAut.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.GroupWithZero.Action.Basic -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.GroupWithZero.Action.Units +import Mathlib.Algebra.Module.Opposite /-! # Multiplication on the left/right as additive automorphisms diff --git a/Mathlib/Algebra/Ring/BooleanRing.lean b/Mathlib/Algebra/Ring/BooleanRing.lean index f04b26d3b23f6..e88f282f73822 100644 --- a/Mathlib/Algebra/Ring/BooleanRing.lean +++ b/Mathlib/Algebra/Ring/BooleanRing.lean @@ -137,11 +137,9 @@ theorem toBoolAlg_ofBoolAlg (a : AsBoolAlg α) : toBoolAlg (ofBoolAlg a) = a := theorem ofBoolAlg_toBoolAlg (a : α) : ofBoolAlg (toBoolAlg a) = a := rfl --- Porting note (#10618): simp can prove this -- @[simp] theorem toBoolAlg_inj {a b : α} : toBoolAlg a = toBoolAlg b ↔ a = b := Iff.rfl --- Porting note (#10618): simp can prove this -- @[simp] theorem ofBoolAlg_inj {a b : AsBoolAlg α} : ofBoolAlg a = ofBoolAlg b ↔ a = b := Iff.rfl @@ -355,11 +353,9 @@ theorem toBoolRing_ofBoolRing (a : AsBoolRing α) : toBoolRing (ofBoolRing a) = theorem ofBoolRing_toBoolRing (a : α) : ofBoolRing (toBoolRing a) = a := rfl --- Porting note (#10618): simp can prove this -- @[simp] theorem toBoolRing_inj {a b : α} : toBoolRing a = toBoolRing b ↔ a = b := Iff.rfl --- Porting note (#10618): simp can prove this -- @[simp] theorem ofBoolRing_inj {a b : AsBoolRing α} : ofBoolRing a = ofBoolRing b ↔ a = b := Iff.rfl @@ -534,7 +530,7 @@ instance : BooleanRing Bool where left_distrib := and_xor_distrib_left right_distrib := and_xor_distrib_right mul_self := Bool.and_self - zero_mul a := rfl + zero_mul _ := rfl mul_zero a := by cases a <;> rfl nsmul := nsmulRec zsmul := zsmulRec diff --git a/Mathlib/Algebra/Ring/Centralizer.lean b/Mathlib/Algebra/Ring/Centralizer.lean index 51c57241c8cdc..1064da90c35ae 100644 --- a/Mathlib/Algebra/Ring/Centralizer.lean +++ b/Mathlib/Algebra/Ring/Centralizer.lean @@ -11,7 +11,7 @@ import Mathlib.Algebra.Ring.Defs -/ -variable {M : Type*} {S T : Set M} +variable {M : Type*} {S : Set M} namespace Set diff --git a/Mathlib/Algebra/Ring/CentroidHom.lean b/Mathlib/Algebra/Ring/CentroidHom.lean index 37a70431efb16..b1b90bb34b9d1 100644 --- a/Mathlib/Algebra/Ring/CentroidHom.lean +++ b/Mathlib/Algebra/Ring/CentroidHom.lean @@ -102,13 +102,6 @@ instance : CentroidHomClass (CentroidHom α) α where map_mul_right f := f.map_mul_right' -/-- Helper instance for when there's too many metavariables to apply `DFunLike.CoeFun` -directly. -/ -/- Porting note: Lean gave me `unknown constant 'DFunLike.CoeFun'` and says `CoeFun` is a type -mismatch, so I used `library_search`. -/ -instance : CoeFun (CentroidHom α) fun _ ↦ α → α := - inferInstanceAs (CoeFun (CentroidHom α) fun _ ↦ α → α) - -- Porting note: removed @[simp]; not in normal form. (`toAddMonoidHom_eq_coe` below ensures that -- the LHS simplifies to the RHS anyway.) theorem toFun_eq_coe {f : CentroidHom α} : f.toFun = f := rfl diff --git a/Mathlib/Algebra/Ring/Commute.lean b/Mathlib/Algebra/Ring/Commute.lean index 54cf0da485262..381b7109ee286 100644 --- a/Mathlib/Algebra/Ring/Commute.lean +++ b/Mathlib/Algebra/Ring/Commute.lean @@ -21,9 +21,9 @@ For the definitions of semirings and rings see `Mathlib.Algebra.Ring.Defs`. -/ -universe u v w x +universe u -variable {α : Type u} {β : Type v} {γ : Type w} {R : Type x} +variable {R : Type u} open Function @@ -77,13 +77,9 @@ section variable [MulOneClass R] [HasDistribNeg R] --- Porting note (#10618): no longer needs to be `@[simp]` since `simp` can prove it. --- @[simp] theorem neg_one_right (a : R) : Commute a (-1) := SemiconjBy.neg_one_right a --- Porting note (#10618): no longer needs to be `@[simp]` since `simp` can prove it. --- @[simp] theorem neg_one_left (a : R) : Commute (-1) a := SemiconjBy.neg_one_left a diff --git a/Mathlib/Algebra/Ring/CompTypeclasses.lean b/Mathlib/Algebra/Ring/CompTypeclasses.lean index e6fce8299f6a4..6aff4dd2a3908 100644 --- a/Mathlib/Algebra/Ring/CompTypeclasses.lean +++ b/Mathlib/Algebra/Ring/CompTypeclasses.lean @@ -81,22 +81,16 @@ class RingHomInvPair (σ : R₁ →+* R₂) (σ' : outParam (R₂ →+* R₁)) : /-- `σ'` is a left inverse of `σ'` -/ comp_eq₂ : σ.comp σ' = RingHom.id R₂ --- attribute [simp] RingHomInvPair.comp_eq Porting note (#10618): `simp` can prove it - --- attribute [simp] RingHomInvPair.comp_eq₂ Porting note (#10618): `simp` can prove it - variable {σ : R₁ →+* R₂} {σ' : R₂ →+* R₁} namespace RingHomInvPair variable [RingHomInvPair σ σ'] --- @[simp] Porting note (#10618): `simp` can prove it theorem comp_apply_eq {x : R₁} : σ' (σ x) = x := by rw [← RingHom.comp_apply, comp_eq] simp --- @[simp] Porting note (#10618): `simp` can prove it theorem comp_apply_eq₂ {x : R₂} : σ (σ' x) = x := by rw [← RingHom.comp_apply, comp_eq₂] simp @@ -156,9 +150,6 @@ theorem RingHom.surjective (σ : R₁ →+* R₂) [t : RingHomSurjective σ] : F namespace RingHomSurjective --- The linter gives a false positive, since `σ₂` is an out_param --- Porting note(#12094): removed nolint; dangerous_instance linter not ported yet --- @[nolint dangerous_instance] instance (priority := 100) invPair {σ₁ : R₁ →+* R₂} {σ₂ : R₂ →+* R₁} [RingHomInvPair σ₁ σ₂] : RingHomSurjective σ₁ := ⟨fun x => ⟨σ₂ x, RingHomInvPair.comp_apply_eq₂⟩⟩ diff --git a/Mathlib/Algebra/Ring/Defs.lean b/Mathlib/Algebra/Ring/Defs.lean index fda1ccb46d3f6..0fdf58f79d80f 100644 --- a/Mathlib/Algebra/Ring/Defs.lean +++ b/Mathlib/Algebra/Ring/Defs.lean @@ -45,9 +45,9 @@ assert_not_exists DivisionMonoid.toDivInvOneMonoid assert_not_exists mul_rotate -universe u v w x +universe u v -variable {α : Type u} {β : Type v} {γ : Type w} {R : Type x} +variable {α : Type u} {R : Type v} open Function @@ -178,34 +178,6 @@ theorem mul_two (n : α) : n * 2 = n + n := end NonAssocSemiring -@[to_additive] -theorem mul_ite {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) : - (a * if P then b else c) = if P then a * b else a * c := by split_ifs <;> rfl - -@[to_additive] -theorem ite_mul {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) : - (if P then a else b) * c = if P then a * c else b * c := by split_ifs <;> rfl - --- We make `mul_ite` and `ite_mul` simp lemmas, --- but not `add_ite` or `ite_add`. --- The problem we're trying to avoid is dealing with --- summations of the form `∑ x ∈ s, (f x + ite P 1 0)`, --- in which `add_ite` followed by `sum_ite` would needlessly slice up --- the `f x` terms according to whether `P` holds at `x`. --- There doesn't appear to be a corresponding difficulty so far with --- `mul_ite` and `ite_mul`. -attribute [simp] mul_ite ite_mul - -theorem ite_sub_ite {α} [Sub α] (P : Prop) [Decidable P] (a b c d : α) : - ((if P then a else b) - if P then c else d) = if P then a - c else b - d := by - split - repeat rfl - -theorem ite_add_ite {α} [Add α] (P : Prop) [Decidable P] (a b c d : α) : - ((if P then a else b) + if P then c else d) = if P then a + c else b + d := by - split - repeat rfl - section MulZeroClass variable [MulZeroClass α] (P Q : Prop) [Decidable P] [Decidable Q] (a b : α) diff --git a/Mathlib/Algebra/Ring/Divisibility/Basic.lean b/Mathlib/Algebra/Ring/Divisibility/Basic.lean index 5f1dd2b07ea5a..dbe11489b614e 100644 --- a/Mathlib/Algebra/Ring/Divisibility/Basic.lean +++ b/Mathlib/Algebra/Ring/Divisibility/Basic.lean @@ -58,7 +58,7 @@ end Semiring section NonUnitalCommSemiring -variable [NonUnitalCommSemiring α] [NonUnitalCommSemiring β] {a b c : α} +variable [NonUnitalCommSemiring α] theorem Dvd.dvd.linear_comb {d x y : α} (hdx : d ∣ x) (hdy : d ∣ y) (a b : α) : d ∣ a * x + b * y := dvd_add (hdx.mul_left a) (hdy.mul_left b) @@ -67,7 +67,7 @@ end NonUnitalCommSemiring section Semigroup -variable [Semigroup α] [HasDistribNeg α] {a b c : α} +variable [Semigroup α] [HasDistribNeg α] {a b : α} /-- An element `a` of a semigroup with a distributive negation divides the negation of an element `b` iff `a` divides `b`. -/ @@ -129,7 +129,7 @@ end NonUnitalRing section Ring -variable [Ring α] {a b c : α} +variable [Ring α] {a b : α} /-- An element a divides the sum a + b if and only if a divides b. -/ @[simp] @@ -155,7 +155,7 @@ end Ring section NonUnitalCommRing -variable [NonUnitalCommRing α] {a b c : α} +variable [NonUnitalCommRing α] theorem dvd_mul_sub_mul {k a b x y : α} (hab : k ∣ a - b) (hxy : k ∣ x - y) : k ∣ a * x - b * y := by diff --git a/Mathlib/Algebra/Ring/Equiv.lean b/Mathlib/Algebra/Ring/Equiv.lean index ae83ce7dd57b1..ff0a1107f04c7 100644 --- a/Mathlib/Algebra/Ring/Equiv.lean +++ b/Mathlib/Algebra/Ring/Equiv.lean @@ -5,7 +5,6 @@ Authors: Johannes Hölzl, Callum Sutton, Yury Kudryashov -/ import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Opposite -import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Algebra.GroupWithZero.InjSurj import Mathlib.Algebra.Ring.Hom.Defs import Mathlib.Logic.Equiv.Set @@ -606,7 +605,7 @@ section Ring variable [NonAssocRing R] [NonAssocRing S] (f : R ≃+* S) --- Porting note (#10618): `simp` can now prove that, so we remove the `@[simp]` tag +@[simp] theorem map_neg_one : f (-1) = -1 := f.map_one ▸ f.map_neg 1 @@ -734,12 +733,10 @@ theorem toMonoidHom_refl : (RingEquiv.refl R).toMonoidHom = MonoidHom.id R := theorem toAddMonoidHom_refl : (RingEquiv.refl R).toAddMonoidHom = AddMonoidHom.id R := rfl --- Porting note (#10618): Now other `simp` can do this, so removed `simp` attribute theorem toRingHom_apply_symm_toRingHom_apply (e : R ≃+* S) : ∀ y : S, e.toRingHom (e.symm.toRingHom y) = y := e.toEquiv.apply_symm_apply --- Porting note (#10618): Now other `simp` can do this, so removed `simp` attribute theorem symm_toRingHom_apply_toRingHom_apply (e : R ≃+* S) : ∀ x : R, e.symm.toRingHom (e.toRingHom x) = x := Equiv.symm_apply_apply e.toEquiv @@ -749,13 +746,11 @@ theorem toRingHom_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : (e₁.trans e₂).toRingHom = e₂.toRingHom.comp e₁.toRingHom := rfl --- Porting note (#10618): Now other `simp` can do this, so removed `simp` attribute theorem toRingHom_comp_symm_toRingHom (e : R ≃+* S) : e.toRingHom.comp e.symm.toRingHom = RingHom.id _ := by ext simp --- Porting note (#10618): Now other `simp` can do this, so removed `simp` attribute theorem symm_toRingHom_comp_toRingHom (e : R ≃+* S) : e.symm.toRingHom.comp e.toRingHom = RingHom.id _ := by ext @@ -805,9 +800,6 @@ protected theorem map_pow (f : R ≃+* S) (a) : ∀ n : ℕ, f (a ^ n) = f a ^ n end GroupPower -protected theorem isUnit_iff (f : R ≃+* S) {a} : IsUnit (f a) ↔ IsUnit a := - MulEquiv.map_isUnit_iff f - end RingEquiv namespace MulEquiv diff --git a/Mathlib/Algebra/Ring/Hom/Basic.lean b/Mathlib/Algebra/Ring/Hom/Basic.lean index 8fd264112dd85..354e0701e8d83 100644 --- a/Mathlib/Algebra/Ring/Hom/Basic.lean +++ b/Mathlib/Algebra/Ring/Hom/Basic.lean @@ -21,13 +21,13 @@ They could be moved to more natural homes. open Function -variable {F α β γ : Type*} +variable {α β : Type*} namespace RingHom section -variable {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} (f : α →+* β) {x y : α} +variable {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} (f : α →+* β) /-- `f : α →+* β` has a trivial codomain iff its range is `{0}`. -/ theorem codomain_trivial_iff_range_eq_singleton_zero : (0 : β) = 1 ↔ Set.range f = {0} := diff --git a/Mathlib/Algebra/Ring/Hom/Defs.lean b/Mathlib/Algebra/Ring/Hom/Defs.lean index 86672a2bb1c98..c03030622109a 100644 --- a/Mathlib/Algebra/Ring/Hom/Defs.lean +++ b/Mathlib/Algebra/Ring/Hom/Defs.lean @@ -258,7 +258,7 @@ instance : MonoidWithZero (α →ₙ+* α) where mul := comp mul_one := comp_id one_mul := id_comp - mul_assoc f g h := comp_assoc _ _ _ + mul_assoc _ _ _ := comp_assoc _ _ _ zero := 0 mul_zero := comp_zero zero_mul := zero_comp @@ -329,7 +329,7 @@ class RingHomClass (F : Type*) (α β : outParam Type*) variable [FunLike F α β] --- Porting note: marked `{}` rather than `[]` to prevent dangerous instances +-- See note [implicit instance arguments]. variable {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} [RingHomClass F α β] /-- Turn an element of a type `F` satisfying `RingHomClass F α β` into an actual @@ -595,9 +595,9 @@ lemma mul_def (f g : α →+* α) : f * g = f.comp g := rfl instance instMonoid : Monoid (α →+* α) where mul_one := comp_id one_mul := id_comp - mul_assoc f g h := comp_assoc _ _ _ + mul_assoc _ _ _ := comp_assoc _ _ _ npow n f := (npowRec n f).copy f^[n] <| by induction n <;> simp [npowRec, *] - npow_succ n f := DFunLike.coe_injective <| Function.iterate_succ _ _ + npow_succ _ _ := DFunLike.coe_injective <| Function.iterate_succ _ _ @[simp, norm_cast] lemma coe_pow (f : α →+* α) (n : ℕ) : ⇑(f ^ n) = f^[n] := rfl @@ -649,8 +649,7 @@ theorem coe_fn_mkRingHomOfMulSelfOfTwoNeZero (h h_two h_one) : (f.mkRingHomOfMulSelfOfTwoNeZero h h_two h_one : β → α) = f := rfl --- Porting note (#10618): `simp` can prove this --- @[simp] +@[simp] theorem coe_addMonoidHom_mkRingHomOfMulSelfOfTwoNeZero (h h_two h_one) : (f.mkRingHomOfMulSelfOfTwoNeZero h h_two h_one : β →+ α) = f := by ext diff --git a/Mathlib/Algebra/Ring/InjSurj.lean b/Mathlib/Algebra/Ring/InjSurj.lean index a16aaee0516ab..adfe2cb5d8a38 100644 --- a/Mathlib/Algebra/Ring/InjSurj.lean +++ b/Mathlib/Algebra/Ring/InjSurj.lean @@ -46,8 +46,8 @@ protected abbrev hasDistribNeg (f : β → α) (hf : Injective f) [Mul α] [HasD (neg : ∀ a, f (-a) = -f a) (mul : ∀ a b, f (a * b) = f a * f b) : HasDistribNeg β := { hf.involutiveNeg _ neg, ‹Mul β› with - neg_mul := fun x y => hf <| by erw [neg, mul, neg, neg_mul, mul], - mul_neg := fun x y => hf <| by erw [neg, mul, neg, mul_neg, mul] } + neg_mul := fun x y => hf <| by rw [neg, mul, neg, neg_mul, mul], + mul_neg := fun x y => hf <| by rw [neg, mul, neg, mul_neg, mul] } /-- Pullback a `NonUnitalNonAssocSemiring` instance along an injective function. -/ -- See note [reducible non-instances] @@ -226,8 +226,8 @@ preserves `-` and `*` from a type which has distributive negation. -/ protected abbrev hasDistribNeg [Mul α] [HasDistribNeg α] (neg : ∀ a, f (-a) = -f a) (mul : ∀ a b, f (a * b) = f a * f b) : HasDistribNeg β := { hf.involutiveNeg _ neg, ‹Mul β› with - neg_mul := hf.forall₂.2 fun x y => by erw [← neg, ← mul, neg_mul, neg, mul] - mul_neg := hf.forall₂.2 fun x y => by erw [← neg, ← mul, mul_neg, neg, mul] } + neg_mul := hf.forall₂.2 fun x y => by rw [← neg, ← mul, neg_mul, neg, mul] + mul_neg := hf.forall₂.2 fun x y => by rw [← neg, ← mul, mul_neg, neg, mul] } /-- Pushforward a `NonUnitalNonAssocSemiring` instance along a surjective function. See note [reducible non-instances]. -/ diff --git a/Mathlib/Algebra/Ring/Int.lean b/Mathlib/Algebra/Ring/Int.lean index 8fb0dd29430dc..348175c301b9b 100644 --- a/Mathlib/Algebra/Ring/Int.lean +++ b/Mathlib/Algebra/Ring/Int.lean @@ -166,25 +166,18 @@ lemma even_mul_succ_self (n : ℤ) : Even (n * (n + 1)) := by lemma even_mul_pred_self (n : ℤ) : Even (n * (n - 1)) := by simpa [even_mul, parity_simps] using n.even_or_odd --- Porting note (#10618): was simp. simp can prove this. -@[norm_cast] lemma odd_coe_nat (n : ℕ) : Odd (n : ℤ) ↔ Odd n := by +@[simp, norm_cast] lemma odd_coe_nat (n : ℕ) : Odd (n : ℤ) ↔ Odd n := by rw [← not_even_iff_odd, ← Nat.not_even_iff_odd, even_coe_nat] @[simp] lemma natAbs_even : Even n.natAbs ↔ Even n := by simp [even_iff_two_dvd, dvd_natAbs, natCast_dvd.symm] --- Porting note (#10618): was simp. simp can prove this. ---@[simp] +@[simp] lemma natAbs_odd : Odd n.natAbs ↔ Odd n := by rw [← not_even_iff_odd, ← Nat.not_even_iff_odd, natAbs_even] -alias ⟨_, _root_.Even.natAbs⟩ := natAbs_even - -alias ⟨_, _root_.Odd.natAbs⟩ := natAbs_odd - --- Porting note: "protected"-attribute not implemented yet. --- mathlib3 had: --- `attribute [protected] Even.natAbs Odd.natAbs` +protected alias ⟨_, _root_.Even.natAbs⟩ := natAbs_even +protected alias ⟨_, _root_.Odd.natAbs⟩ := natAbs_odd lemma four_dvd_add_or_sub_of_odd {a b : ℤ} (ha : Odd a) (hb : Odd b) : 4 ∣ a + b ∨ 4 ∣ a - b := by diff --git a/Mathlib/Algebra/Ring/NegOnePow.lean b/Mathlib/Algebra/Ring/NegOnePow.lean index 6696881dcbf2e..9f52047d0c32c 100644 --- a/Mathlib/Algebra/Ring/NegOnePow.lean +++ b/Mathlib/Algebra/Ring/NegOnePow.lean @@ -101,11 +101,17 @@ lemma negOnePow_eq_iff (n₁ n₂ : ℤ) : lemma negOnePow_mul_self (n : ℤ) : (n * n).negOnePow = n.negOnePow := by simpa [mul_sub, negOnePow_eq_iff] using n.even_mul_pred_self -lemma coe_negOnePow (K : Type*) (n : ℤ) [Field K] : n.negOnePow = (-1 : K) ^ n := by +lemma cast_negOnePow (K : Type*) (n : ℤ) [Field K] : n.negOnePow = (-1 : K) ^ n := by rcases even_or_odd' n with ⟨k, rfl | rfl⟩ - · rw [zpow_mul, zpow_ofNat] - simp + · simp [zpow_mul, zpow_ofNat] · rw [zpow_add_one₀ (by norm_num), zpow_mul, zpow_ofNat] simp +@[deprecated (since := "2024-10-20")] alias coe_negOnePow := cast_negOnePow + +lemma cast_negOnePow_natCast (R : Type*) [Ring R] (n : ℕ) : negOnePow n = (-1 : R) ^ n := by + obtain ⟨k, rfl | rfl⟩ := Nat.even_or_odd' n <;> simp [pow_succ, pow_mul] + +lemma coe_negOnePow_natCast (n : ℕ) : negOnePow n = (-1 : ℤ) ^ n := cast_negOnePow_natCast .. + end Int diff --git a/Mathlib/Algebra/Ring/Parity.lean b/Mathlib/Algebra/Ring/Parity.lean index 9205b9aeff65a..72fdec393def4 100644 --- a/Mathlib/Algebra/Ring/Parity.lean +++ b/Mathlib/Algebra/Ring/Parity.lean @@ -31,7 +31,7 @@ assert_not_exists OrderedRing open MulOpposite -variable {F α β R : Type*} +variable {F α β : Type*} section Monoid variable [Monoid α] [HasDistribNeg α] {n : ℕ} {a : α} @@ -156,7 +156,7 @@ lemma Odd.pow_add_pow_eq_zero [IsCancelAdd α] (hn : Odd n) (hab : a + b = 0) : end Semiring section Monoid -variable [Monoid α] [HasDistribNeg α] {a : α} {n : ℕ} +variable [Monoid α] [HasDistribNeg α] {n : ℕ} lemma Odd.neg_pow : Odd n → ∀ a : α, (-a) ^ n = -a ^ n := by rintro ⟨c, rfl⟩ a; simp_rw [pow_add, pow_mul, neg_sq, pow_one, mul_neg] @@ -168,11 +168,6 @@ end Monoid section Ring variable [Ring α] {a b : α} {n : ℕ} -/- Porting note (#10618): attribute `simp` removed based on linter report -simp can prove this: - by simp only [even_neg, even_two] --/ --- @[simp] lemma even_neg_two : Even (-2 : α) := by simp only [even_neg, even_two] lemma Odd.neg (hp : Odd a) : Odd (-a) := by @@ -183,11 +178,6 @@ lemma Odd.neg (hp : Odd a) : Odd (-a) := by @[simp] lemma odd_neg : Odd (-a) ↔ Odd a := ⟨fun h ↦ neg_neg a ▸ h.neg, Odd.neg⟩ -/- Porting note (#10618): attribute `simp` removed based on linter report -simp can prove this: - by simp only [odd_neg, odd_one] --/ --- @[simp] lemma odd_neg_one : Odd (-1 : α) := by simp lemma Odd.sub_even (ha : Odd a) (hb : Even b) : Odd (a - b) := by @@ -238,6 +228,9 @@ lemma even_xor_odd' (n : ℕ) : ∃ k, Xor' (n = 2 * k) (n = 2 * k + 1) := by · simpa only [← two_mul, eq_self_iff_true, xor_true] using (succ_ne_self (2 * k)).symm · simpa only [xor_true, xor_comm] using (succ_ne_self _) +lemma odd_add_one {n : ℕ} : Odd (n + 1) ↔ ¬ Odd n := by + rw [← not_even_iff_odd, Nat.even_add_one, not_even_iff_odd] + lemma mod_two_add_add_odd_mod_two (m : ℕ) {n : ℕ} (hn : Odd n) : m % 2 + (m + n) % 2 = 1 := ((even_or_odd m).elim fun hm ↦ by rw [even_iff.1 hm, odd_iff.1 (hm.add_odd hn)]) fun hm ↦ by rw [odd_iff.1 hm, even_iff.1 (hm.add_odd hn)] @@ -361,3 +354,32 @@ lemma neg_one_pow_eq_one_iff_even {R : Type*} [Monoid R] [HasDistribNeg R] {n : (h : (-1 : R) ≠ 1) : (-1 : R) ^ n = 1 ↔ Even n where mp h' := of_not_not fun hn ↦ h <| (not_even_iff_odd.1 hn).neg_one_pow.symm.trans h' mpr := Even.neg_one_pow + +section CharTwo + +-- We state the following theorems in terms of the slightly more general `2 = 0` hypothesis. + +variable {R : Type*} [AddMonoidWithOne R] + +private theorem natCast_eq_zero_or_one_of_two_eq_zero' (n : ℕ) (h : (2 : R) = 0) : + (Even n → (n : R) = 0) ∧ (Odd n → (n : R) = 1) := by + induction n using Nat.twoStepInduction with + | zero => simp + | one => simp + | more n _ _ => simpa [add_assoc, Nat.even_add_one, Nat.odd_add_one, h] + +theorem natCast_eq_zero_of_even_of_two_eq_zero {n : ℕ} (hn : Even n) (h : (2 : R) = 0) : + (n : R) = 0 := + (natCast_eq_zero_or_one_of_two_eq_zero' n h).1 hn + +theorem natCast_eq_one_of_odd_of_two_eq_zero {n : ℕ} (hn : Odd n) (h : (2 : R) = 0) : + (n : R) = 1 := + (natCast_eq_zero_or_one_of_two_eq_zero' n h).2 hn + +theorem natCast_eq_zero_or_one_of_two_eq_zero (n : ℕ) (h : (2 : R) = 0) : + (n : R) = 0 ∨ (n : R) = 1 := by + obtain hn | hn := Nat.even_or_odd n + · exact Or.inl <| natCast_eq_zero_of_even_of_two_eq_zero hn h + · exact Or.inr <| natCast_eq_one_of_odd_of_two_eq_zero hn h + +end CharTwo diff --git a/Mathlib/Algebra/Ring/Pi.lean b/Mathlib/Algebra/Ring/Pi.lean index 394051c18c7d9..4c20d456a41b7 100644 --- a/Mathlib/Algebra/Ring/Pi.lean +++ b/Mathlib/Algebra/Ring/Pi.lean @@ -25,8 +25,7 @@ variable {I : Type u} -- The indexing type variable {f : I → Type v} --- The family of types already equipped with instances -variable (x y : ∀ i, f i) (i : I) +variable (i : I) instance distrib [∀ i, Distrib <| f i] : Distrib (∀ i : I, f i) := { add := (· + ·) diff --git a/Mathlib/Algebra/Ring/Pointwise/Finset.lean b/Mathlib/Algebra/Ring/Pointwise/Finset.lean new file mode 100644 index 0000000000000..bd2a3b4e8a7f9 --- /dev/null +++ b/Mathlib/Algebra/Ring/Pointwise/Finset.lean @@ -0,0 +1,69 @@ +/- +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.Algebra.Group.Pointwise.Finset.Basic +import Mathlib.Algebra.Ring.Pointwise.Set + +/-! +# Pointwise operations of sets in a ring + +This file proves properties of pointwise operations of sets in a ring. + +## Tags + +set multiplication, set addition, pointwise addition, pointwise multiplication, +pointwise subtraction +-/ + +open scoped Pointwise + +namespace Finset +variable {α β : Type*} + +/-- `Finset α` has distributive negation if `α` has. -/ +protected def distribNeg [DecidableEq α] [Mul α] [HasDistribNeg α] : HasDistribNeg (Finset α) := + coe_injective.hasDistribNeg _ coe_neg coe_mul + +scoped[Pointwise] attribute [instance] Finset.distribNeg + +section Distrib +variable [DecidableEq α] [Distrib α] (s t u : Finset α) + +/-! +Note that `Finset α` is not a `Distrib` because `s * t + s * u` has cross terms that `s * (t + u)` +lacks. + +```lean +-- {10, 16, 18, 20, 8, 9} +#eval {1, 2} * ({3, 4} + {5, 6} : Finset ℕ) + +-- {10, 11, 12, 13, 14, 15, 16, 18, 20, 8, 9} +#eval ({1, 2} : Finset ℕ) * {3, 4} + {1, 2} * {5, 6} +``` +-/ + +lemma mul_add_subset : s * (t + u) ⊆ s * t + s * u := + image₂_distrib_subset_left mul_add + +lemma add_mul_subset : (s + t) * u ⊆ s * u + t * u := + image₂_distrib_subset_right add_mul + +end Distrib + +section Ring +variable [Ring α] [AddCommGroup β] [Module α β] [DecidableEq β] {s : Finset α} {t : Finset β} + {a : α} + +@[simp] +lemma neg_smul_finset : -a • t = -(a • t) := by + simp only [← image_smul, ← image_neg, image_image, neg_smul, Function.comp_def] + +@[simp] +protected lemma neg_smul [DecidableEq α] : -s • t = -(s • t) := by + simp_rw [← image_neg] + exact image₂_image_left_comm neg_smul + +end Ring +end Finset diff --git a/Mathlib/Algebra/Ring/Prod.lean b/Mathlib/Algebra/Ring/Prod.lean index 0f8d3362f0ae8..67ee0ebf5b125 100644 --- a/Mathlib/Algebra/Ring/Prod.lean +++ b/Mathlib/Algebra/Ring/Prod.lean @@ -23,7 +23,7 @@ trivial `simp` lemmas, and define the following operations on `RingHom`s and sim -/ -variable {α β R R' S S' T T' : Type*} +variable {R R' S S' T : Type*} namespace Prod @@ -314,7 +314,7 @@ def prodZeroRing : R ≃+* R × S where invFun := Prod.fst map_add' := by simp map_mul' := by simp - left_inv x := rfl + left_inv _ := rfl right_inv x := by cases x; simp [eq_iff_true_of_subsingleton] /-- A ring `R` is isomorphic to `S × R` when `S` is the zero ring -/ @@ -324,7 +324,7 @@ def zeroRingProd : R ≃+* S × R where invFun := Prod.snd map_add' := by simp map_mul' := by simp - left_inv x := rfl + left_inv _ := rfl right_inv x := by cases x; simp [eq_iff_true_of_subsingleton] end RingEquiv diff --git a/Mathlib/Algebra/Ring/Subring/Basic.lean b/Mathlib/Algebra/Ring/Subring/Basic.lean index 4d2d0317d2fcf..35a508fb82fb3 100644 --- a/Mathlib/Algebra/Ring/Subring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subring/Basic.lean @@ -6,6 +6,7 @@ Authors: Ashvni Narayanan import Mathlib.Algebra.Field.Defs import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.Algebra.Ring.Subsemiring.Basic +import Mathlib.RingTheory.NonUnitalSubring.Basic /-! # Subrings @@ -80,6 +81,9 @@ instance (priority := 100) SubringClass.addSubgroupClass (S : Type*) (R : Type u [SetLike S R] [Ring R] [h : SubringClass S R] : AddSubgroupClass S R := { h with } +instance (priority := 100) SubringClass.nonUnitalSubringClass (S : Type*) (R : Type u) + [SetLike S R] [Ring R] [SubringClass S R] : NonUnitalSubringClass S R where + variable [SetLike S R] [hSR : SubringClass S R] (s : S) @[aesop safe apply (rule_sets := [SetLike])] @@ -354,8 +358,6 @@ theorem coe_one : ((1 : s) : R) = 1 := theorem coe_pow (x : s) (n : ℕ) : ↑(x ^ n) = (x : R) ^ n := SubmonoidClass.coe_pow x n --- TODO: can be generalized to `AddSubmonoidClass` --- @[simp] -- Porting note (#10618): simp can prove this theorem coe_eq_zero_iff {x : s} : (x : R) = 0 ↔ x = 0 := ⟨fun h => Subtype.ext (Trans.trans h s.coe_zero.symm), fun h => h.symm ▸ s.coe_zero⟩ @@ -383,11 +385,11 @@ def subtype (s : Subring R) : s →+* R := theorem coeSubtype : ⇑s.subtype = ((↑) : s → R) := rfl -@[norm_cast] -- Porting note (#10618): simp can prove this (removed `@[simp]`) +@[norm_cast] theorem coe_natCast : ∀ n : ℕ, ((n : s) : R) = n := map_natCast s.subtype -@[norm_cast] -- Porting note (#10618): simp can prove this (removed `@[simp]`) +@[norm_cast] theorem coe_intCast : ∀ n : ℤ, ((n : s) : R) = n := map_intCast s.subtype @@ -662,15 +664,15 @@ variable {K : Type u} [DivisionRing K] instance instField : Field (center K) where inv a := ⟨a⁻¹, Set.inv_mem_center a.prop⟩ - mul_inv_cancel a ha := Subtype.ext <| mul_inv_cancel₀ <| Subtype.coe_injective.ne ha + mul_inv_cancel _ ha := Subtype.ext <| mul_inv_cancel₀ <| Subtype.coe_injective.ne ha div a b := ⟨a / b, Set.div_mem_center a.prop b.prop⟩ - div_eq_mul_inv a b := Subtype.ext <| div_eq_mul_inv _ _ + div_eq_mul_inv _ _ := Subtype.ext <| div_eq_mul_inv _ _ inv_zero := Subtype.ext inv_zero -- TODO: use a nicer defeq nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q x => rfl + qsmul_def := fun _ _ => rfl @[simp] theorem center.coe_inv (a : center K) : ((a⁻¹ : center K) : K) = (a : K)⁻¹ := @@ -754,105 +756,118 @@ theorem closure_eq_of_le {s : Set R} {t : Subring R} (h₁ : s ⊆ t) (h₂ : t of `s`, and is preserved under addition, negation, and multiplication, then `p` holds for all elements of the closure of `s`. -/ @[elab_as_elim] -theorem closure_induction {s : Set R} {p : R → Prop} {x} (h : x ∈ closure s) (Hs : ∀ x ∈ s, p x) - (zero : p 0) (one : p 1) (add : ∀ x y, p x → p y → p (x + y)) (neg : ∀ x : R, p x → p (-x)) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨⟨⟨⟨p, @mul⟩, one⟩, @add, zero⟩, @neg⟩).2 Hs h - -@[elab_as_elim] -theorem closure_induction' {s : Set R} {p : ∀ x, x ∈ closure s → Prop} - (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) +theorem closure_induction {s : Set R} {p : (x : R) → x ∈ closure s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_closure hx)) (zero : p 0 (zero_mem _)) (one : p 1 (one_mem _)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) (neg : ∀ x hx, p x hx → p (-x) (neg_mem hx)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) - {a : R} (ha : a ∈ closure s) : p a ha := by - refine Exists.elim ?_ fun (ha : a ∈ closure s) (hc : p a ha) => hc - refine - closure_induction ha (fun m hm => ⟨subset_closure hm, mem m hm⟩) ⟨zero_mem _, zero⟩ - ⟨one_mem _, one⟩ ?_ (fun x hx => hx.elim fun hx' hx => ⟨neg_mem hx', neg _ _ hx⟩) ?_ - · exact (fun x y hx hy => hx.elim fun hx' hx => hy.elim fun hy' hy => - ⟨add_mem hx' hy', add _ _ _ _ hx hy⟩) - · exact (fun x y hx hy => hx.elim fun hx' hx => hy.elim fun hy' hy => - ⟨mul_mem hx' hy', mul _ _ _ _ hx hy⟩) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + {x} (hx : x ∈ closure s) : p x hx := + let K : Subring R := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ + add_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, add _ _ _ _ hpx hpy⟩ + neg_mem' := fun ⟨_, hpx⟩ ↦ ⟨_, neg _ _ hpx⟩ + zero_mem' := ⟨_, zero⟩ + one_mem' := ⟨_, one⟩ } + closure_le (t := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction /-- An induction principle for closure membership, for predicates with two arguments. -/ @[elab_as_elim] -theorem closure_induction₂ {s : Set R} {p : R → R → Prop} {a b : R} (ha : a ∈ closure s) - (hb : b ∈ closure s) (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H0_left : ∀ x, p 0 x) - (H0_right : ∀ x, p x 0) (H1_left : ∀ x, p 1 x) (H1_right : ∀ x, p x 1) - (Hneg_left : ∀ x y, p x y → p (-x) y) (Hneg_right : ∀ x y, p x y → p x (-y)) - (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) : p a b := by - refine - closure_induction hb ?_ (H0_right _) (H1_right _) (Hadd_right a) (Hneg_right a) (Hmul_right a) - refine closure_induction ha Hs (fun x _ => H0_left x) (fun x _ => H1_left x) ?_ ?_ ?_ - · exact fun x y H₁ H₂ z zs => Hadd_left x y z (H₁ z zs) (H₂ z zs) - · exact fun x hx z zs => Hneg_left x z (hx z zs) - · exact fun x y H₁ H₂ z zs => Hmul_left x y z (H₁ z zs) (H₂ z zs) +theorem closure_induction₂ {s : Set R} {p : (x y : R) → x ∈ closure s → y ∈ closure s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (zero_left : ∀ x hx, p 0 x (zero_mem _) hx) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) + (neg_left : ∀ x y hx hy, p x y hx hy → p (-x) y (neg_mem hx) hy) + (neg_right : ∀ x y hx hy, p x y hx hy → p x (-y) hx (neg_mem hy)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + {x y : R} (hx : x ∈ closure s) (hy : y ∈ closure s) : + p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem_mem _ _ h hz + | zero => exact zero_left _ _ + | one => exact one_left _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | neg _ _ h => exact neg_left _ _ _ _ h + | zero => exact zero_right x hx + | one => exact one_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ + | neg _ _ h => exact neg_right _ _ _ _ h theorem mem_closure_iff {s : Set R} {x} : x ∈ closure s ↔ x ∈ AddSubgroup.closure (Submonoid.closure s : Set R) := - ⟨fun h => - closure_induction h (fun x hx => AddSubgroup.subset_closure <| Submonoid.subset_closure hx) - (AddSubgroup.zero_mem _) - (AddSubgroup.subset_closure (Submonoid.one_mem (Submonoid.closure s))) - (fun x y hx hy => AddSubgroup.add_mem _ hx hy) (fun x hx => AddSubgroup.neg_mem _ hx) - fun x y hx hy => - AddSubgroup.closure_induction hy - (fun q hq => - AddSubgroup.closure_induction hx - (fun p hp => AddSubgroup.subset_closure ((Submonoid.closure s).mul_mem hp hq)) - (by rw [zero_mul q]; apply AddSubgroup.zero_mem _) - (fun p₁ p₂ ihp₁ ihp₂ => by rw [add_mul p₁ p₂ q]; apply AddSubgroup.add_mem _ ihp₁ ihp₂) - fun x hx => by - have f : -x * q = -(x * q) := by simp - rw [f]; apply AddSubgroup.neg_mem _ hx) - (by rw [mul_zero x]; apply AddSubgroup.zero_mem _) - (fun q₁ q₂ ihq₁ ihq₂ => by rw [mul_add x q₁ q₂]; apply AddSubgroup.add_mem _ ihq₁ ihq₂) - fun z hz => by - have f : x * -z = -(x * z) := by simp - rw [f]; apply AddSubgroup.neg_mem _ hz, - fun h => - AddSubgroup.closure_induction (p := (· ∈ closure s)) h - (fun x hx => - Submonoid.closure_induction hx (fun x hx => subset_closure hx) (one_mem _) fun x y hx hy => - mul_mem hx hy) - (zero_mem _) (fun x y hx hy => add_mem hx hy) fun x hx => neg_mem hx⟩ + ⟨fun h => by + induction h using closure_induction with + | mem _ hx => exact AddSubgroup.subset_closure (Submonoid.subset_closure hx) + | zero => exact zero_mem _ + | one => exact AddSubgroup.subset_closure (one_mem _) + | add _ _ _ _ hx hy => exact add_mem hx hy + | neg _ _ hx => exact neg_mem hx + | mul _ _ _hx _hy hx hy => + clear _hx _hy + induction hx, hy using AddSubgroup.closure_induction₂ with + | mem _ _ hx hy => exact AddSubgroup.subset_closure (mul_mem hx hy) + | one_left => simpa using zero_mem _ + | one_right => simpa using zero_mem _ + | mul_left _ _ _ _ _ _ h₁ h₂ => simpa [add_mul] using add_mem h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => simpa [mul_add] using add_mem h₁ h₂ + | inv_left _ _ _ _ h => simpa [neg_mul] using neg_mem h + | inv_right _ _ _ _ h => simpa [mul_neg] using neg_mem h, + fun h => by + induction h using AddSubgroup.closure_induction with + | mem x hx => + induction hx using Submonoid.closure_induction with + | mem _ h => exact subset_closure h + | one => exact one_mem _ + | mul _ _ _ _ h₁ h₂ => exact mul_mem h₁ h₂ + | one => exact zero_mem _ + | mul _ _ _ _ h₁ h₂ => exact add_mem h₁ h₂ + | inv _ _ h => exact neg_mem h⟩ /-- If all elements of `s : Set A` commute pairwise, then `closure s` is a commutative ring. -/ def closureCommRingOfComm {s : Set R} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommRing (closure s) := { (closure s).toRing with - mul_comm := fun x y => by + mul_comm := fun ⟨x, hx⟩ ⟨y, hy⟩ => by ext - simp only [Subring.coe_mul] - refine - closure_induction₂ x.prop y.prop hcomm (fun x => by simp only [mul_zero, zero_mul]) - (fun x => by simp only [mul_zero, zero_mul]) (fun x => by simp only [mul_one, one_mul]) - (fun x => by simp only [mul_one, one_mul]) - (fun x y hxy => by simp only [mul_neg, neg_mul, hxy]) - (fun x y hxy => by simp only [mul_neg, neg_mul, hxy]) - (fun x₁ x₂ y h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x₁ x₂ y h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x₁ x₂ y h₁ h₂ => by rw [← mul_assoc, ← h₁, mul_assoc x₁ y x₂, ← h₂, mul_assoc]) - fun x₁ x₂ y h₁ h₂ => by rw [← mul_assoc, h₁, mul_assoc, h₂, ← mul_assoc] } - -theorem exists_list_of_mem_closure {s : Set R} {x : R} (h : x ∈ closure s) : - ∃ L : List (List R), (∀ t ∈ L, ∀ y ∈ t, y ∈ s ∨ y = (-1 : R)) ∧ (L.map List.prod).sum = x := - AddSubgroup.closure_induction (G := R) - (p := (∃ L : List (List R), (∀ t ∈ L, ∀ y ∈ t, y ∈ s ∨ y = -1) ∧ (L.map List.prod).sum = ·)) - (mem_closure_iff.1 h) - (fun x hx => - let ⟨l, hl, h⟩ := Submonoid.exists_list_of_mem_closure hx - ⟨[l], by simp [h]; clear_aux_decl; tauto⟩) - ⟨[], by simp⟩ - (fun x y ⟨l, hl1, hl2⟩ ⟨m, hm1, hm2⟩ => - ⟨l ++ m, fun t ht => (List.mem_append.1 ht).elim (hl1 t) (hm1 t), by simp [hl2, hm2]⟩) - fun x ⟨L, hL⟩ => - ⟨L.map (List.cons (-1)), + simp only [MulMemClass.mk_mul_mk] + induction hx, hy using closure_induction₂ with + | mem_mem x y hx hy => exact hcomm x hx y hy + | zero_left x _ => exact Commute.zero_left x + | zero_right x _ => exact Commute.zero_right x + | one_left x _ => exact Commute.one_left x + | one_right x _ => exact Commute.one_right x + | mul_left _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_left h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_right h₁ h₂ + | add_left _ _ _ _ _ _ h₁ h₂ => exact Commute.add_left h₁ h₂ + | add_right _ _ _ _ _ _ h₁ h₂ => exact Commute.add_right h₁ h₂ + | neg_left _ _ _ _ h => exact Commute.neg_left h + | neg_right _ _ _ _ h => exact Commute.neg_right h } + +theorem exists_list_of_mem_closure {s : Set R} {x : R} (hx : x ∈ closure s) : + ∃ L : List (List R), (∀ t ∈ L, ∀ y ∈ t, y ∈ s ∨ y = (-1 : R)) ∧ (L.map List.prod).sum = x := by + rw [mem_closure_iff] at hx + induction hx using AddSubgroup.closure_induction with + | mem _ hx => + obtain ⟨l, hl, h⟩ := Submonoid.exists_list_of_mem_closure hx + exact ⟨[l], by simp [h]; clear_aux_decl; tauto⟩ + | one => exact ⟨[], List.forall_mem_nil _, rfl⟩ + | mul _ _ _ _ hL hM => + obtain ⟨⟨L, HL1, HL2⟩, ⟨M, HM1, HM2⟩⟩ := And.intro hL hM + exact ⟨L ++ M, List.forall_mem_append.2 ⟨HL1, HM1⟩, by + rw [List.map_append, List.sum_append, HL2, HM2]⟩ + | inv _ _ hL => + obtain ⟨L, hL⟩ := hL + exact ⟨L.map (List.cons (-1)), List.forall_mem_map.2 fun j hj => List.forall_mem_cons.2 ⟨Or.inr rfl, hL.1 j hj⟩, hL.2 ▸ List.recOn L (by simp) @@ -1083,11 +1098,9 @@ def inclusion {S T : Subring R} (h : S ≤ T) : S →+* T := theorem range_subtype (s : Subring R) : s.subtype.range = s := SetLike.coe_injective <| (coe_rangeS _).trans Subtype.range_coe --- @[simp] -- Porting note (#10618): simp can prove this theorem range_fst : (fst R S).rangeS = ⊤ := (fst R S).rangeS_top_of_surjective <| Prod.fst_surjective --- @[simp] -- Porting note (#10618): simp can prove this theorem range_snd : (snd R S).rangeS = ⊤ := (snd R S).rangeS_top_of_surjective <| Prod.snd_surjective diff --git a/Mathlib/Algebra/Ring/Subring/Units.lean b/Mathlib/Algebra/Ring/Subring/Units.lean index 157cdab1d1c19..97205c69943ca 100644 --- a/Mathlib/Algebra/Ring/Subring/Units.lean +++ b/Mathlib/Algebra/Ring/Subring/Units.lean @@ -3,7 +3,8 @@ Copyright (c) 2021 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Defs +import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.Order.GroupWithZero.Submonoid import Mathlib.Algebra.Order.Ring.Defs diff --git a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean index f775d6a04fdda..589f27314eac8 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean @@ -27,7 +27,7 @@ section AddSubmonoidWithOneClass /-- `AddSubmonoidWithOneClass S R` says `S` is a type of subsets `s ≤ R` that contain `0`, `1`, and are closed under `(+)` -/ -class AddSubmonoidWithOneClass (S R : Type*) [AddMonoidWithOne R] +class AddSubmonoidWithOneClass (S : Type*) (R : outParam Type*) [AddMonoidWithOne R] [SetLike S R] extends AddSubmonoidClass S R, OneMemClass S R : Prop variable {S R : Type*} [AddMonoidWithOne R] [SetLike S R] (s : S) @@ -68,6 +68,11 @@ instance (priority := 100) SubsemiringClass.addSubmonoidWithOneClass (S : Type*) AddSubmonoidWithOneClass S R := { h with } +instance (priority := 100) SubsemiringClass.nonUnitalSubsemiringClass (S : Type*) + (R : Type u) [NonAssocSemiring R] [SetLike S R] [SubsemiringClass S R] : + NonUnitalSubsemiringClass S R where + mul_mem := mul_mem + variable [SetLike S R] [hSR : SubsemiringClass S R] (s : S) namespace SubsemiringClass @@ -147,7 +152,6 @@ instance : SubsemiringClass (Subsemiring R) R where theorem mem_toSubmonoid {s : Subsemiring R} {x : R} : x ∈ s.toSubmonoid ↔ x ∈ s := Iff.rfl --- `@[simp]` -- Porting note (#10618): simp can prove thisrove this theorem mem_carrier {s : Subsemiring R} {x : R} : x ∈ s.carrier ↔ x ∈ s := Iff.rfl @@ -741,61 +745,68 @@ theorem closure_addSubmonoid_closure {s : Set R} : of `s`, and is preserved under addition and multiplication, then `p` holds for all elements of the closure of `s`. -/ @[elab_as_elim] -theorem closure_induction {s : Set R} {p : R → Prop} {x} (h : x ∈ closure s) (mem : ∀ x ∈ s, p x) - (zero : p 0) (one : p 1) (add : ∀ x y, p x → p y → p (x + y)) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨⟨⟨p, @mul⟩, one⟩, @add, zero⟩).2 mem h - -@[elab_as_elim] -theorem closure_induction' {s : Set R} {p : ∀ x, x ∈ closure s → Prop} - (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) +theorem closure_induction {s : Set R} {p : (x : R) → x ∈ closure s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_closure hx)) (zero : p 0 (zero_mem _)) (one : p 1 (one_mem _)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) - {a : R} (ha : a ∈ closure s) : p a ha := by - refine Exists.elim ?_ fun (ha : a ∈ closure s) (hc : p a ha) => hc - refine - closure_induction ha (fun m hm => ⟨subset_closure hm, mem m hm⟩) ⟨zero_mem _, zero⟩ - ⟨one_mem _, one⟩ ?_ ?_ - · exact (fun x y hx hy => hx.elim fun hx' hx => hy.elim fun hy' hy => - ⟨add_mem hx' hy', add _ _ _ _ hx hy⟩) - · exact (fun x y hx hy => hx.elim fun hx' hx => hy.elim fun hy' hy => - ⟨mul_mem hx' hy', mul _ _ _ _ hx hy⟩) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + {x} (hx : x ∈ closure s) : p x hx := + let K : Subsemiring R := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ + add_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, add _ _ _ _ hpx hpy⟩ + one_mem' := ⟨_, one⟩ + zero_mem' := ⟨_, zero⟩ } + closure_le (t := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction /-- An induction principle for closure membership for predicates with two arguments. -/ @[elab_as_elim] -theorem closure_induction₂ {s : Set R} {p : R → R → Prop} {x} {y : R} (hx : x ∈ closure s) - (hy : y ∈ closure s) (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H0_left : ∀ x, p 0 x) - (H0_right : ∀ x, p x 0) (H1_left : ∀ x, p 1 x) (H1_right : ∀ x, p x 1) - (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) : p x y := - closure_induction hx - (fun x₁ x₁s => - closure_induction hy (Hs x₁ x₁s) (H0_right x₁) (H1_right x₁) (Hadd_right x₁) (Hmul_right x₁)) - (H0_left y) (H1_left y) (fun z z' => Hadd_left z z' y) fun z z' => Hmul_left z z' y +theorem closure_induction₂ {s : Set R} {p : (x y : R) → x ∈ closure s → y ∈ closure s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (zero_left : ∀ x hx, p 0 x (zero_mem _) hx) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + {x y : R} (hx : x ∈ closure s) (hy : y ∈ closure s) : + p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem_mem _ _ h hz + | zero => exact zero_left _ _ + | one => exact one_left _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | zero => exact zero_right x hx + | one => exact one_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ theorem mem_closure_iff_exists_list {R} [Semiring R] {s : Set R} {x} : x ∈ closure s ↔ ∃ L : List (List R), (∀ t ∈ L, ∀ y ∈ t, y ∈ s) ∧ (L.map List.prod).sum = x := by constructor · intro hx - -- Porting note: needed explicit `p` - let p : R → Prop := fun x => - ∃ (L : List (List R)), - (∀ (t : List R), t ∈ L → ∀ (y : R), y ∈ t → y ∈ s) ∧ (List.map List.prod L).sum = x - exact AddSubmonoid.closure_induction (p := p) (mem_closure_iff.1 hx) - (fun x hx => - suffices ∃ t : List R, (∀ y ∈ t, y ∈ s) ∧ t.prod = x from - let ⟨t, ht1, ht2⟩ := this - ⟨[t], List.forall_mem_singleton.2 ht1, by - rw [List.map_singleton, List.sum_singleton, ht2]⟩ - Submonoid.closure_induction hx - (fun x hx => ⟨[x], List.forall_mem_singleton.2 hx, List.prod_singleton⟩) - ⟨[], List.forall_mem_nil _, rfl⟩ fun x y ⟨t, ht1, ht2⟩ ⟨u, hu1, hu2⟩ => - ⟨t ++ u, List.forall_mem_append.2 ⟨ht1, hu1⟩, by rw [List.prod_append, ht2, hu2]⟩) - ⟨[], List.forall_mem_nil _, rfl⟩ fun x y ⟨L, HL1, HL2⟩ ⟨M, HM1, HM2⟩ => - ⟨L ++ M, List.forall_mem_append.2 ⟨HL1, HM1⟩, by + rw [mem_closure_iff] at hx + induction hx using AddSubmonoid.closure_induction with + | mem x hx => + suffices ∃ t : List R, (∀ y ∈ t, y ∈ s) ∧ t.prod = x from + let ⟨t, ht1, ht2⟩ := this + ⟨[t], List.forall_mem_singleton.2 ht1, by + rw [List.map_singleton, List.sum_singleton, ht2]⟩ + induction hx using Submonoid.closure_induction with + | mem x hx => exact ⟨[x], List.forall_mem_singleton.2 hx, List.prod_singleton⟩ + | one => exact ⟨[], List.forall_mem_nil _, rfl⟩ + | mul x y _ _ ht hu => + obtain ⟨⟨t, ht1, ht2⟩, ⟨u, hu1, hu2⟩⟩ := And.intro ht hu + exact ⟨t ++ u, List.forall_mem_append.2 ⟨ht1, hu1⟩, by rw [List.prod_append, ht2, hu2]⟩ + | one => exact ⟨[], List.forall_mem_nil _, rfl⟩ + | mul x y _ _ hL hM => + obtain ⟨⟨L, HL1, HL2⟩, ⟨M, HM1, HM2⟩⟩ := And.intro hL hM + exact ⟨L ++ M, List.forall_mem_append.2 ⟨HL1, HM1⟩, by rw [List.map_append, List.sum_append, HL2, HM2]⟩ · rintro ⟨L, HL1, HL2⟩ exact HL2 ▸ @@ -1195,17 +1206,19 @@ instance center.smulCommClass_right : SMulCommClass R' (center R') R' := def closureCommSemiringOfComm {s : Set R'} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommSemiring (closure s) := { (closure s).toSemiring with - mul_comm := fun x y => by + mul_comm := fun ⟨x, hx⟩ ⟨y, hy⟩ => by ext - simp only [Subsemiring.coe_mul] - refine - closure_induction₂ x.prop y.prop hcomm (fun x => by simp only [zero_mul, mul_zero]) - (fun x => by simp only [zero_mul, mul_zero]) (fun x => by simp only [one_mul, mul_one]) - (fun x => by simp only [one_mul, mul_one]) - (fun x y z h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x y z h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x y z h₁ h₂ => by rw [mul_assoc, h₂, ← mul_assoc, h₁, mul_assoc]) fun x y z h₁ h₂ => - by rw [← mul_assoc, h₁, mul_assoc, h₂, ← mul_assoc] } + simp only [MulMemClass.mk_mul_mk] + induction hx, hy using closure_induction₂ with + | mem_mem x y hx hy => exact hcomm x hx y hy + | zero_left x _ => exact Commute.zero_left x + | zero_right x _ => exact Commute.zero_right x + | one_left x _ => exact Commute.one_left x + | one_right x _ => exact Commute.one_right x + | mul_left _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_left h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_right h₁ h₂ + | add_left _ _ _ _ _ _ h₁ h₂ => exact Commute.add_left h₁ h₂ + | add_right _ _ _ _ _ _ h₁ h₂ => exact Commute.add_right h₁ h₂ } end Subsemiring diff --git a/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean b/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean index f709792084761..2b5aa3ce3ce5e 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean @@ -5,6 +5,7 @@ Authors: Jz Pan -/ import Mathlib.Algebra.Group.Submonoid.MulOpposite import Mathlib.Algebra.Ring.Subsemiring.Basic +import Mathlib.Algebra.Ring.Opposite /-! diff --git a/Mathlib/Algebra/Ring/WithAbs.lean b/Mathlib/Algebra/Ring/WithAbs.lean new file mode 100644 index 0000000000000..3b3fcb16224a3 --- /dev/null +++ b/Mathlib/Algebra/Ring/WithAbs.lean @@ -0,0 +1,100 @@ +/- +Copyright (c) 2024 Salvatore Mercuri. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Salvatore Mercuri +-/ +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Order.AbsoluteValue +import Mathlib.Analysis.Normed.Field.Basic + +/-! +# WithAbs + +`WithAbs v` is a type synonym for a semiring `R` which depends on an absolute value. The point of +this is to allow the type class inference system to handle multiple sources of instances that +arise from absolute values. See `NumberTheory.NumberField.Completion` for an example of this +being used to define Archimedean completions of a number field. + +## Main definitions + - `WithAbs` : type synonym for a semiring which depends on an absolute value. This is + a function that takes an absolute value on a semiring and returns the semiring. This can be used + 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`. +-/ +noncomputable section + +variable {R S K : Type*} [Semiring R] [OrderedSemiring S] [Field K] + +/-- Type synonym for a semiring which depends on an absolute value. This is a function that takes +an absolute value on a semiring and returns the semiring. We use this to assign and infer instances +on a semiring that depend on absolute values. -/ +@[nolint unusedArguments] +def WithAbs : AbsoluteValue R S → Type _ := fun _ => R + +namespace WithAbs + +variable (v : AbsoluteValue R ℝ) + +/-- Canonical equivalence between `WithAbs v` and `R`. -/ +def equiv : WithAbs v ≃ R := Equiv.refl (WithAbs v) + +instance instNonTrivial [Nontrivial R] : Nontrivial (WithAbs v) := inferInstanceAs (Nontrivial R) + +instance instUnique [Unique R] : Unique (WithAbs v) := inferInstanceAs (Unique R) + +instance instSemiring : Semiring (WithAbs v) := inferInstanceAs (Semiring R) + +instance instRing [Ring R] : Ring (WithAbs v) := inferInstanceAs (Ring R) + +instance instInhabited : Inhabited (WithAbs v) := ⟨0⟩ + +instance normedRing {R : Type*} [Ring R] (v : AbsoluteValue R ℝ) : NormedRing (WithAbs v) := + v.toNormedRing + +instance normedField (v : AbsoluteValue K ℝ) : NormedField (WithAbs v) := + v.toNormedField + +/-! `WithAbs.equiv` preserves the ring structure. -/ + +variable (x y : WithAbs v) (r s : R) +@[simp] +theorem equiv_zero : WithAbs.equiv v 0 = 0 := rfl + +@[simp] +theorem equiv_symm_zero : (WithAbs.equiv v).symm 0 = 0 := rfl + +@[simp] +theorem equiv_add : WithAbs.equiv v (x + y) = WithAbs.equiv v x + WithAbs.equiv v y := rfl + +@[simp] +theorem equiv_symm_add : + (WithAbs.equiv v).symm (r + s) = (WithAbs.equiv v).symm r + (WithAbs.equiv v).symm s := + rfl + +@[simp] +theorem equiv_sub [Ring R] : WithAbs.equiv v (x - y) = WithAbs.equiv v x - WithAbs.equiv v y := rfl + +@[simp] +theorem equiv_symm_sub [Ring R] : + (WithAbs.equiv v).symm (r - s) = (WithAbs.equiv v).symm r - (WithAbs.equiv v).symm s := + rfl + +@[simp] +theorem equiv_neg [Ring R] : WithAbs.equiv v (-x) = - WithAbs.equiv v x := rfl + +@[simp] +theorem equiv_symm_neg [Ring R] : (WithAbs.equiv v).symm (-r) = - (WithAbs.equiv v).symm r := rfl + +@[simp] +theorem equiv_mul : WithAbs.equiv v (x * y) = WithAbs.equiv v x * WithAbs.equiv v y := rfl + +@[simp] +theorem equiv_symm_mul : + (WithAbs.equiv v).symm (x * y) = (WithAbs.equiv v).symm x * (WithAbs.equiv v).symm y := + rfl + +/-- `WithAbs.equiv` as a ring equivalence. -/ +def ringEquiv : WithAbs v ≃+* R := RingEquiv.refl _ + +end WithAbs diff --git a/Mathlib/Algebra/RingQuot.lean b/Mathlib/Algebra/RingQuot.lean index 1da65c2031d8e..fb0556615bab7 100644 --- a/Mathlib/Algebra/RingQuot.lean +++ b/Mathlib/Algebra/RingQuot.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Mathlib.Algebra.Algebra.Hom -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Congruence.Basic +import Mathlib.RingTheory.Ideal.Quotient.Defs +import Mathlib.RingTheory.Ideal.Span /-! # Quotients of non-commutative rings @@ -440,7 +442,7 @@ factors uniquely through a morphism `RingQuot r →+* T`. irreducible_def lift {r : R → R → Prop} : { f : R →+* T // ∀ ⦃x y⦄, r x y → f x = f y } ≃ (RingQuot r →+* T) := { toFun := fun f ↦ preLift f.prop - invFun := fun F ↦ ⟨F.comp (mkRingHom r), fun x y h ↦ congr_arg F (mkRingHom_rel h)⟩ + invFun := fun F ↦ ⟨F.comp (mkRingHom r), fun _ _ h ↦ congr_arg F (mkRingHom_rel h)⟩ left_inv := fun f ↦ by ext simp only [preLift_def, mkRingHom_def, RingHom.coe_comp, RingHom.coe_mk, MonoidHom.coe_mk, @@ -464,7 +466,7 @@ theorem lift_unique (f : R →+* T) {r : R → R → Prop} (w : ∀ ⦃x y⦄, r simp [h] theorem eq_lift_comp_mkRingHom {r : R → R → Prop} (f : RingQuot r →+* T) : - f = lift ⟨f.comp (mkRingHom r), fun x y h ↦ congr_arg f (mkRingHom_rel h)⟩ := by + f = lift ⟨f.comp (mkRingHom r), fun _ _ h ↦ congr_arg f (mkRingHom_rel h)⟩ := by conv_lhs => rw [← lift.apply_symm_apply f] rw [lift_def] rfl @@ -495,15 +497,15 @@ theorem ringQuotToIdealQuotient_apply (r : B → B → Prop) (x : B) : def idealQuotientToRingQuot (r : B → B → Prop) : B ⧸ Ideal.ofRel r →+* RingQuot r := Ideal.Quotient.lift (Ideal.ofRel r) (mkRingHom r) (by - refine fun x h ↦ Submodule.span_induction h ?_ ?_ ?_ ?_ + refine fun x h ↦ Submodule.span_induction ?_ ?_ ?_ ?_ h · rintro y ⟨a, b, h, su⟩ symm at su rw [← sub_eq_iff_eq_add] at su rw [← su, RingHom.map_sub, mkRingHom_rel h, sub_self] · simp - · intro a b ha hb + · intro a b _ _ ha hb simp [ha, hb] - · intro a x hx + · intro a x _ hx simp [hx]) @[simp] @@ -619,7 +621,7 @@ theorem liftAlgHom_unique (f : A →ₐ[S] B) {s : A → A → Prop} (w : ∀ simp [h] theorem eq_liftAlgHom_comp_mkAlgHom {s : A → A → Prop} (f : RingQuot s →ₐ[S] B) : - f = liftAlgHom S ⟨f.comp (mkAlgHom S s), fun x y h ↦ congr_arg f (mkAlgHom_rel S h)⟩ := by + f = liftAlgHom S ⟨f.comp (mkAlgHom S s), fun _ _ h ↦ congr_arg f (mkAlgHom_rel S h)⟩ := by conv_lhs => rw [← (liftAlgHom S).apply_symm_apply f] rw [liftAlgHom] rfl diff --git a/Mathlib/Algebra/SMulWithZero.lean b/Mathlib/Algebra/SMulWithZero.lean index ae84ec92e750d..b897e154bd18f 100644 --- a/Mathlib/Algebra/SMulWithZero.lean +++ b/Mathlib/Algebra/SMulWithZero.lean @@ -126,7 +126,8 @@ class MulActionWithZero extends MulAction R M where zero_smul : ∀ m : M, (0 : R) • m = 0 -- see Note [lower instance priority] -instance (priority := 100) MulActionWithZero.toSMulWithZero [m : MulActionWithZero R M] : +instance (priority := 100) MulActionWithZero.toSMulWithZero + (R M) {_ : MonoidWithZero R} {_ : Zero M} [m : MulActionWithZero R M] : SMulWithZero R M := { m with } diff --git a/Mathlib/Algebra/Squarefree/Basic.lean b/Mathlib/Algebra/Squarefree/Basic.lean index 2ae3fd080cb05..c18ad3b0214ad 100644 --- a/Mathlib/Algebra/Squarefree/Basic.lean +++ b/Mathlib/Algebra/Squarefree/Basic.lean @@ -17,8 +17,8 @@ Results about squarefree natural numbers are proved in `Data.Nat.Squarefree`. - `Squarefree r` indicates that `r` is only divisible by `x * x` if `x` is a unit. ## Main Results - - `multiplicity.squarefree_iff_multiplicity_le_one`: `x` is `Squarefree` iff for every `y`, either - `multiplicity y x ≤ 1` or `IsUnit y`. + - `multiplicity.squarefree_iff_emultiplicity_le_one`: `x` is `Squarefree` iff for every `y`, either + `emultiplicity y x ≤ 1` or `IsUnit y`. - `UniqueFactorizationMonoid.squarefree_iff_nodup_factors`: A nonzero element `x` of a unique factorization monoid is squarefree iff `factors x` has no duplicate factors. @@ -42,7 +42,6 @@ theorem IsRelPrime.of_squarefree_mul [CommMonoid R] {m n : R} (h : Squarefree (m theorem IsUnit.squarefree [CommMonoid R] {x : R} (h : IsUnit x) : Squarefree x := fun _ hdvd => isUnit_of_mul_isUnit_left (isUnit_of_dvd_unit hdvd h) --- @[simp] -- Porting note (#10618): simp can prove this theorem squarefree_one [CommMonoid R] : Squarefree (1 : R) := isUnit_one.squarefree @@ -101,15 +100,15 @@ namespace multiplicity section CommMonoid -variable [CommMonoid R] [DecidableRel (Dvd.dvd : R → R → Prop)] +variable [CommMonoid R] -theorem squarefree_iff_multiplicity_le_one (r : R) : - Squarefree r ↔ ∀ x : R, multiplicity x r ≤ 1 ∨ IsUnit x := by +theorem squarefree_iff_emultiplicity_le_one (r : R) : + Squarefree r ↔ ∀ x : R, emultiplicity x r ≤ 1 ∨ IsUnit x := by refine forall_congr' fun a => ?_ - rw [← sq, pow_dvd_iff_le_multiplicity, or_iff_not_imp_left, not_le, imp_congr _ Iff.rfl] + rw [← sq, pow_dvd_iff_le_emultiplicity, or_iff_not_imp_left, not_le, imp_congr _ Iff.rfl] norm_cast rw [← one_add_one_eq_two] - simpa using PartENat.add_one_le_iff_lt (PartENat.natCast_ne_top 1) + exact Order.add_one_le_iff_of_not_isMax (by simp) end CommMonoid @@ -260,14 +259,14 @@ 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_multiplicity_le_one, Multiset.nodup_iff_count_le_one] + rw [multiplicity.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 · have ha := irreducible_of_normalized_factor _ hmem rcases h a with (h | h) · rw [← normalize_normalized_factor _ hmem] - rw [multiplicity_eq_count_normalizedFactors ha x0] at h + rw [emultiplicity_eq_count_normalizedFactors ha x0] at h assumption_mod_cast · have := ha.1 contradiction @@ -277,8 +276,8 @@ theorem squarefree_iff_nodup_normalizedFactors [NormalizationMonoid R] {x : R} rcases eq_or_ne a 0 with rfl | h0 · simp [x0] rcases WfDvdMonoid.exists_irreducible_factor hu h0 with ⟨b, hib, hdvd⟩ - apply le_trans (multiplicity.multiplicity_le_multiplicity_of_dvd_left hdvd) - rw [multiplicity_eq_count_normalizedFactors hib x0] + apply le_trans (emultiplicity_le_emultiplicity_of_dvd_left hdvd) + rw [emultiplicity_eq_count_normalizedFactors hib x0] exact_mod_cast h (normalize b) end UniqueFactorizationMonoid diff --git a/Mathlib/Algebra/Star/CHSH.lean b/Mathlib/Algebra/Star/CHSH.lean index 26fc0b59288bb..eedcf9c9f9801 100644 --- a/Mathlib/Algebra/Star/CHSH.lean +++ b/Mathlib/Algebra/Star/CHSH.lean @@ -5,6 +5,7 @@ Authors: Kim Morrison -/ import Mathlib.Algebra.CharP.Invertible import Mathlib.Algebra.Order.Star.Basic +import Mathlib.Algebra.Ring.Regular import Mathlib.Data.Real.Sqrt import Mathlib.Tactic.Polyrith diff --git a/Mathlib/Algebra/Star/CentroidHom.lean b/Mathlib/Algebra/Star/CentroidHom.lean index 219cabaedcbfd..8e07bcb8be477 100644 --- a/Mathlib/Algebra/Star/CentroidHom.lean +++ b/Mathlib/Algebra/Star/CentroidHom.lean @@ -43,7 +43,7 @@ instance : Star (CentroidHom α) where instance instStarAddMonoid : StarAddMonoid (CentroidHom α) where star_involutive f := ext (fun _ => by rw [star_apply, star_apply, star_star, star_star]) - star_add f g := ext fun _ => star_add _ _ + star_add _ _ := ext fun _ => star_add _ _ instance : Star (Subsemiring.center (CentroidHom α)) where star f := ⟨star (f : CentroidHom α), Subsemiring.mem_center_iff.mpr (fun g => ext (fun a => diff --git a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean index 61e7ac629195f..558c7dbee59ad 100644 --- a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean @@ -556,8 +556,8 @@ variable [IsScalarTower R A A] [SMulCommClass R A A] theorem star_adjoin_comm (s : Set A) : star (NonUnitalAlgebra.adjoin R s) = NonUnitalAlgebra.adjoin R (star s) := have this : - ∀ t : Set A, NonUnitalAlgebra.adjoin R (star t) ≤ star (NonUnitalAlgebra.adjoin R t) := fun t => - NonUnitalAlgebra.adjoin_le fun x hx => NonUnitalAlgebra.subset_adjoin R hx + ∀ t : Set A, NonUnitalAlgebra.adjoin R (star t) ≤ star (NonUnitalAlgebra.adjoin R t) := fun _ => + NonUnitalAlgebra.adjoin_le fun _ hx => NonUnitalAlgebra.subset_adjoin R hx le_antisymm (by simpa only [star_star] using NonUnitalSubalgebra.star_mono (this (star s))) (this s) @@ -645,18 +645,22 @@ theorem star_self_mem_adjoin_singleton (x : A) : star x ∈ adjoin R ({x} : Set star_mem <| self_mem_adjoin_singleton R x @[elab_as_elim] -lemma adjoin_induction' {s : Set A} {p : ∀ x, x ∈ adjoin R s → Prop} {a : A} - (ha : a ∈ adjoin R s) (mem : ∀ (x : A) (hx : x ∈ s), p x (subset_adjoin R s hx)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) - (zero : p 0 (zero_mem _)) (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) +lemma adjoin_induction {s : Set A} {p : (x : A) → x ∈ adjoin R s → Prop} + (mem : ∀ (x : A) (hx : x ∈ s), p x (subset_adjoin R s hx)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (zero : p 0 (zero_mem _)) (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) (smul : ∀ (r : R) x hx, p x hx → p (r • x) (SMulMemClass.smul_mem r hx)) - (star : ∀ x hx, p x hx → p (star x) (star_mem hx)) : p a ha := by - refine NonUnitalAlgebra.adjoin_induction' (fun x hx ↦ ?_) add zero mul smul ha + (star : ∀ x hx, p x hx → p (star x) (star_mem hx)) + {a : A} (ha : a ∈ adjoin R s) : p a ha := by + refine NonUnitalAlgebra.adjoin_induction (fun x hx ↦ ?_) add zero mul smul ha simp only [Set.mem_union, Set.mem_star] at hx obtain (hx | hx) := hx · exact mem x hx · simpa using star _ (NonUnitalAlgebra.subset_adjoin R (by simpa using Or.inl hx)) (mem _ hx) +@[deprecated adjoin_induction (since := "2024-10-10")] +alias adjoin_induction' := adjoin_induction + variable {R} protected theorem gc : GaloisConnection (adjoin R : Set A → NonUnitalStarSubalgebra R A) (↑) := by diff --git a/Mathlib/Algebra/Star/SelfAdjoint.lean b/Mathlib/Algebra/Star/SelfAdjoint.lean index 32776d896fc45..f2e5c48eb5513 100644 --- a/Mathlib/Algebra/Star/SelfAdjoint.lean +++ b/Mathlib/Algebra/Star/SelfAdjoint.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Frédéric Dupuis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Frédéric Dupuis -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.Star.Pi import Mathlib.Algebra.Star.Rat diff --git a/Mathlib/Algebra/Star/Subalgebra.lean b/Mathlib/Algebra/Star/Subalgebra.lean index 7d0b23cd8f043..b2c1cc0ea0538 100644 --- a/Mathlib/Algebra/Star/Subalgebra.lean +++ b/Mathlib/Algebra/Star/Subalgebra.lean @@ -73,7 +73,6 @@ instance algebra (s : StarSubalgebra R A) : Algebra R s := instance starModule (s : StarSubalgebra R A) : StarModule R s where star_smul r a := Subtype.ext (star_smul r (a : A)) -@[simp, nolint simpNF] -- porting note (#10618): `simpNF` says `simp` can prove this, but it can't theorem mem_carrier {s : StarSubalgebra R A} {x : A} : x ∈ s.carrier ↔ x ∈ s := Iff.rfl @@ -107,8 +106,7 @@ theorem toSubalgebra_le_iff {S₁ S₂ : StarSubalgebra R A} : equalities. -/ protected def copy (S : StarSubalgebra R A) (s : Set A) (hs : s = ↑S) : StarSubalgebra R A where toSubalgebra := Subalgebra.copy S.toSubalgebra s hs - star_mem' := @fun a ha => hs ▸ (S.star_mem' (by simpa [hs] using ha) : star a ∈ (S : Set A)) - -- Porting note: the old proof kept crashing Lean + star_mem' {a} ha := hs ▸ S.star_mem' (by simpa [hs] using ha) @[simp] theorem coe_copy (S : StarSubalgebra R A) (s : Set A) (hs : s = ↑S) : (S.copy s hs : Set A) = s := @@ -329,8 +327,8 @@ variable (R) /-- The star operation on `Subalgebra` commutes with `Algebra.adjoin`. -/ theorem star_adjoin_comm (s : Set A) : star (Algebra.adjoin R s) = Algebra.adjoin R (star s) := - have this : ∀ t : Set A, Algebra.adjoin R (star t) ≤ star (Algebra.adjoin R t) := fun t => - Algebra.adjoin_le fun x hx => Algebra.subset_adjoin hx + have this : ∀ t : Set A, Algebra.adjoin R (star t) ≤ star (Algebra.adjoin R t) := fun _ => + Algebra.adjoin_le fun _ hx => Algebra.subset_adjoin hx le_antisymm (by simpa only [star_star] using Subalgebra.star_mono (this (star s))) (this s) variable {R} @@ -440,56 +438,68 @@ theorem _root_.Subalgebra.starClosure_eq_adjoin (S : Subalgebra R A) : /-- If some predicate holds for all `x ∈ (s : Set A)` and this predicate is closed under the `algebraMap`, addition, multiplication and star operations, then it holds for `a ∈ adjoin R s`. -/ @[elab_as_elim] -theorem adjoin_induction {s : Set A} {p : A → Prop} {a : A} (h : a ∈ adjoin R s) - (mem : ∀ x : A, x ∈ s → p x) (algebraMap : ∀ r : R, p (algebraMap R A r)) - (add : ∀ x y : A, p x → p y → p (x + y)) (mul : ∀ x y : A, p x → p y → p (x * y)) - (star : ∀ x : A, p x → p (star x)) : p a := - Algebra.adjoin_induction h - (fun x hx => hx.elim (fun hx => mem x hx) fun hx => star_star x ▸ star _ (mem _ hx)) - algebraMap add mul +theorem adjoin_induction {s : Set A} {p : (x : A) → x ∈ adjoin R s → Prop} + (mem : ∀ (x) (h : x ∈ s), p x (subset_adjoin R s h)) + (algebraMap : ∀ r, p (_root_.algebraMap R _ r) (_root_.algebraMap_mem _ r)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + (star : ∀ x hx, p x hx → p (star x) (star_mem hx)) + {a : A} (ha : a ∈ adjoin R s) : p a ha := by + refine Algebra.adjoin_induction (fun x hx ↦ ?_) algebraMap add mul ha + simp only [Set.mem_union, Set.mem_star] at hx + obtain (hx | hx) := hx + · exact mem x hx + · simpa using star _ (Algebra.subset_adjoin (by simpa using Or.inl hx)) (mem _ hx) @[elab_as_elim] -theorem adjoin_induction₂ {s : Set A} {p : A → A → Prop} {a b : A} (ha : a ∈ adjoin R s) - (hb : b ∈ adjoin R s) (Hs : ∀ x : A, x ∈ s → ∀ y : A, y ∈ s → p x y) - (Halg : ∀ r₁ r₂ : R, p (algebraMap R A r₁) (algebraMap R A r₂)) - (Halg_left : ∀ (r : R) (x : A), x ∈ s → p (algebraMap R A r) x) - (Halg_right : ∀ (r : R) (x : A), x ∈ s → p x (algebraMap R A r)) - (Hadd_left : ∀ x₁ x₂ y : A, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂ : A, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y : A, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂ : A, p x y₁ → p x y₂ → p x (y₁ * y₂)) - (Hstar : ∀ x y : A, p x y → p (star x) (star y)) (Hstar_left : ∀ x y : A, p x y → p (star x) y) - (Hstar_right : ∀ x y : A, p x y → p x (star y)) : p a b := by - refine - Algebra.adjoin_induction₂ ha hb (fun x hx y hy => ?_) Halg (fun r x hx => ?_) (fun r x hx => ?_) - Hadd_left Hadd_right Hmul_left Hmul_right - · cases' hx with hx hx <;> cases' hy with hy hy - · exact Hs x hx y hy - · exact star_star y ▸ Hstar_right _ _ (Hs _ hx _ hy) - · exact star_star x ▸ Hstar_left _ _ (Hs _ hx _ hy) - · exact star_star x ▸ star_star y ▸ Hstar _ _ (Hs _ hx _ hy) - · cases' hx with hx hx - · exact Halg_left _ _ hx - · exact star_star x ▸ Hstar_right _ _ (Halg_left r _ hx) - · cases' hx with hx hx - · exact Halg_right _ _ hx - · exact star_star x ▸ Hstar_left _ _ (Halg_right r _ hx) +theorem adjoin_induction₂ {s : Set A} {p : (x y : A) → x ∈ adjoin R s → y ∈ adjoin R s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_adjoin R s hx) + (subset_adjoin R s hy)) + (algebraMap_both : ∀ r₁ r₂, p (algebraMap R A r₁) (algebraMap R A r₂) + (_root_.algebraMap_mem _ r₁) (_root_.algebraMap_mem _ r₂)) + (algebraMap_left : ∀ (r) (x) (hx : x ∈ s), p (algebraMap R A r) x (_root_.algebraMap_mem _ r) + (subset_adjoin R s hx)) + (algebraMap_right : ∀ (r) (x) (hx : x ∈ s), p x (algebraMap R A r) (subset_adjoin R s hx) + (_root_.algebraMap_mem _ r)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + (star_left : ∀ x y hx hy, p x y hx hy → p (star x) y (star_mem hx) hy) + (star_right : ∀ x y hx hy, p x y hx hy → p x (star y) hx (star_mem hy)) + {a b : A} (ha : a ∈ adjoin R s) (hb : b ∈ adjoin R s) : + p a b ha hb := by + induction hb using adjoin_induction with + | mem z hz => induction ha using adjoin_induction with + | mem _ h => exact mem_mem _ _ h hz + | algebraMap _ => exact algebraMap_left _ _ hz + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | star _ _ h => exact star_left _ _ _ _ h + | algebraMap r => + induction ha using adjoin_induction with + | mem _ h => exact algebraMap_right _ _ h + | algebraMap _ => exact algebraMap_both _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | star _ _ h => exact star_left _ _ _ _ h + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ + | star _ _ h => exact star_right _ _ _ _ h /-- The difference with `StarSubalgebra.adjoin_induction` is that this acts on the subtype. -/ @[elab_as_elim] -theorem adjoin_induction' {s : Set A} {p : adjoin R s → Prop} (a : adjoin R s) +theorem adjoin_induction_subtype {s : Set A} {p : adjoin R s → Prop} (a : adjoin R s) (mem : ∀ (x) (h : x ∈ s), p ⟨x, subset_adjoin R s h⟩) (algebraMap : ∀ r, p (algebraMap R _ r)) (add : ∀ x y, p x → p y → p (x + y)) (mul : ∀ x y, p x → p y → p (x * y)) (star : ∀ x, p x → p (star x)) : p a := Subtype.recOn a fun b hb => by - refine Exists.elim ?_ fun (hb : b ∈ adjoin R s) (hc : p ⟨b, hb⟩) => hc - refine adjoin_induction hb ?_ ?_ ?_ ?_ ?_ - exacts [fun x hx => ⟨subset_adjoin R s hx, mem x hx⟩, fun r => - ⟨StarSubalgebra.algebraMap_mem _ r, algebraMap r⟩, fun x y hx hy => - Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => ⟨add_mem hx' hy', add _ _ hx hy⟩, - fun x y hx hy => - Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => ⟨mul_mem hx' hy', mul _ _ hx hy⟩, - fun x hx => Exists.elim hx fun hx' hx => ⟨star_mem hx', star _ hx⟩] + induction hb using adjoin_induction with + | mem _ h => exact mem _ h + | algebraMap _ => exact algebraMap _ + | mul _ _ _ _ h₁ h₂ => exact mul _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add _ _ h₁ h₂ + | star _ _ h => exact star _ h variable (R) @@ -668,7 +678,7 @@ theorem ext_adjoin {s : Set A} [FunLike F (adjoin R s) B] [AlgHomClass F R (adjoin R s) B] [StarHomClass F (adjoin R s) B] {f g : F} (h : ∀ x : adjoin R s, (x : A) ∈ s → f x = g x) : f = g := by refine DFunLike.ext f g fun a => - adjoin_induction' (p := fun y => f y = g y) a (fun x hx => ?_) (fun r => ?_) + adjoin_induction_subtype (p := fun y => f y = g y) a (fun x hx => ?_) (fun r => ?_) (fun x y hx hy => ?_) (fun x y hx hy => ?_) fun x hx => ?_ · exact h ⟨x, subset_adjoin R s hx⟩ hx · simp only [AlgHomClass.commutes] @@ -688,10 +698,9 @@ theorem ext_adjoin_singleton {a : A} [FunLike F (adjoin R ({a} : Set A)) B] variable [FunLike F A B] [AlgHomClass F R A B] [StarHomClass F A B] (f g : F) /-- The equalizer of two star `R`-algebra homomorphisms. -/ -def equalizer : StarSubalgebra R A := - { toSubalgebra := AlgHom.equalizer (f : A →ₐ[R] B) g - star_mem' := @fun a (ha : f a = g a) => by simpa only [← map_star] using congrArg star ha } --- Porting note: much like `StarSubalgebra.copy` the old proof was broken and hard to fix +def equalizer : StarSubalgebra R A where + toSubalgebra := AlgHom.equalizer (f : A →ₐ[R] B) g + star_mem' {a} (ha : f a = g a) := by simpa only [← map_star] using congrArg star ha @[simp] theorem mem_equalizer (x : A) : x ∈ StarAlgHom.equalizer f g ↔ f x = g x := diff --git a/Mathlib/Algebra/Symmetrized.lean b/Mathlib/Algebra/Symmetrized.lean index f4dea0e4e8345..66841a63dca0e 100644 --- a/Mathlib/Algebra/Symmetrized.lean +++ b/Mathlib/Algebra/Symmetrized.lean @@ -95,11 +95,9 @@ theorem unsym_injective : Injective (unsym : αˢʸᵐ → α) := theorem unsym_surjective : Surjective (unsym : αˢʸᵐ → α) := unsym.surjective --- Porting note (#10618): @[simp] can prove this theorem sym_inj {a b : α} : sym a = sym b ↔ a = b := sym_injective.eq_iff --- Porting note (#10618): @[simp] can prove this theorem unsym_inj {a b : αˢʸᵐ} : unsym a = unsym b ↔ a = b := unsym_injective.eq_iff diff --git a/Mathlib/Algebra/TrivSqZeroExt.lean b/Mathlib/Algebra/TrivSqZeroExt.lean index 4eb552d919fc2..c40ab975c18d7 100644 --- a/Mathlib/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Algebra/TrivSqZeroExt.lean @@ -147,6 +147,12 @@ theorem snd_comp_inr [Zero R] : snd ∘ (inr : M → tsze R M) = id := end +theorem fst_surjective [Nonempty M] : Function.Surjective (fst : tsze R M → R) := + Prod.fst_surjective + +theorem snd_surjective [Nonempty R] : Function.Surjective (snd : tsze R M → M) := + Prod.snd_surjective + theorem inl_injective [Zero M] : Function.Injective (inl : R → tsze R M) := Function.LeftInverse.injective <| fst_inl _ @@ -226,6 +232,16 @@ instance module [Semiring S] [AddCommMonoid R] [AddCommMonoid M] [Module S R] [M Module S (tsze R M) := Prod.instModule +/-- The trivial square-zero extension is nontrivial if it is over a nontrivial ring. -/ +instance instNontrivial_of_left {R M : Type*} [Nontrivial R] [Nonempty M] : + Nontrivial (TrivSqZeroExt R M) := + fst_surjective.nontrivial + +/-- The trivial square-zero extension is nontrivial if it is over a nontrivial module. -/ +instance instNontrivial_of_right {R M : Type*} [Nonempty R] [Nontrivial M] : + Nontrivial (TrivSqZeroExt R M) := + snd_surjective.nontrivial + @[simp] theorem fst_zero [Zero R] [Zero M] : (0 : tsze R M).fst = 0 := rfl diff --git a/Mathlib/Algebra/Tropical/Basic.lean b/Mathlib/Algebra/Tropical/Basic.lean index 5454363d36711..5a22f3bbfe005 100644 --- a/Mathlib/Algebra/Tropical/Basic.lean +++ b/Mathlib/Algebra/Tropical/Basic.lean @@ -291,7 +291,6 @@ theorem add_eq_left_iff {x y : Tropical R} : x + y = x ↔ x ≤ y := by theorem add_eq_right_iff {x y : Tropical R} : x + y = y ↔ y ≤ x := by rw [trop_add_def, trop_eq_iff_eq_untrop, ← untrop_le_iff, min_eq_right_iff] --- Porting note (#10618): removing `simp`. `simp` can prove it theorem add_self (x : Tropical R) : x + x = x := untrop_injective (min_eq_right le_rfl) @@ -431,15 +430,15 @@ end Monoid section Distrib -instance covariant_mul [LE R] [Add R] [CovariantClass R R (· + ·) (· ≤ ·)] : - CovariantClass (Tropical R) (Tropical R) (· * ·) (· ≤ ·) := +instance mulLeftMono [LE R] [Add R] [AddLeftMono R] : + MulLeftMono (Tropical R) := ⟨fun _ y z h => add_le_add_left (show untrop y ≤ untrop z from h) _⟩ -instance covariant_swap_mul [LE R] [Add R] [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] : - CovariantClass (Tropical R) (Tropical R) (Function.swap (· * ·)) (· ≤ ·) := +instance mulRightMono [LE R] [Add R] [AddRightMono R] : + MulRightMono (Tropical R) := ⟨fun _ y z h => add_le_add_right (show untrop y ≤ untrop z from h) _⟩ -instance covariant_add [LinearOrder R] : CovariantClass (Tropical R) (Tropical R) (· + ·) (· ≤ ·) := +instance addLeftMono [LinearOrder R] : AddLeftMono (Tropical R) := ⟨fun x y z h => by rcases le_total x y with hx | hy · rw [add_eq_left hx, add_eq_left (hx.trans h)] @@ -448,17 +447,15 @@ instance covariant_add [LinearOrder R] : CovariantClass (Tropical R) (Tropical R · rwa [add_eq_left hx] · rwa [add_eq_right hx]⟩ -instance covariant_mul_lt [LT R] [Add R] [CovariantClass R R (· + ·) (· < ·)] : - CovariantClass (Tropical R) (Tropical R) (· * ·) (· < ·) := +instance mulLeftStrictMono [LT R] [Add R] [AddLeftStrictMono R] : + MulLeftStrictMono (Tropical R) := ⟨fun _ _ _ h => add_lt_add_left (untrop_lt_iff.2 h) _⟩ -instance covariant_swap_mul_lt [Preorder R] [Add R] - [CovariantClass R R (Function.swap (· + ·)) (· < ·)] : - CovariantClass (Tropical R) (Tropical R) (Function.swap (· * ·)) (· < ·) := +instance mulRightStrictMono [Preorder R] [Add R] [AddRightStrictMono R] : + MulRightStrictMono (Tropical R) := ⟨fun _ y z h => add_lt_add_right (show untrop y < untrop z from h) _⟩ -instance instDistribTropical [LinearOrder R] [Add R] [CovariantClass R R (· + ·) (· ≤ ·)] - [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] : +instance instDistribTropical [LinearOrder R] [Add R] [AddLeftMono R] [AddRightMono R] : Distrib (Tropical R) where mul := (· * ·) add := (· + ·) @@ -466,8 +463,8 @@ instance instDistribTropical [LinearOrder R] [Add R] [CovariantClass R R (· + right_distrib _ _ _ := untrop_injective (min_add_add_right _ _ _).symm @[simp] -theorem add_pow [LinearOrder R] [AddMonoid R] [CovariantClass R R (· + ·) (· ≤ ·)] - [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] (x y : Tropical R) (n : ℕ) : +theorem add_pow [LinearOrder R] [AddMonoid R] [AddLeftMono R] [AddRightMono R] + (x y : Tropical R) (n : ℕ) : (x + y) ^ n = x ^ n + y ^ n := by rcases le_total x y with h | h · rw [add_eq_left h, add_eq_left (pow_le_pow_left' h _)] @@ -497,7 +494,6 @@ theorem succ_nsmul {R} [LinearOrder R] [OrderTop R] (x : Tropical R) (n : ℕ) : -- Requires `zero_eq_bot` to be true -- lemma add_eq_zero_iff {a b : tropical R} : -- a + b = 1 ↔ a = 1 ∨ b = 1 := sorry --- Porting note (#10618): removing @[simp], `simp` can prove it theorem mul_eq_zero_iff {R : Type*} [LinearOrderedAddCommMonoid R] {a b : Tropical (WithTop R)} : a * b = 0 ↔ a = 0 ∨ b = 0 := by simp [← untrop_inj_iff, WithTop.add_eq_top] diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index 4b05220332013..05b089ff8be1f 100644 --- a/Mathlib/AlgebraicGeometry/AffineScheme.lean +++ b/Mathlib/AlgebraicGeometry/AffineScheme.lean @@ -8,6 +8,7 @@ import Mathlib.AlgebraicGeometry.Restrict import Mathlib.AlgebraicGeometry.Cover.Open import Mathlib.CategoryTheory.Limits.Opposites import Mathlib.RingTheory.Localization.InvSubmonoid +import Mathlib.RingTheory.RingHom.Surjective /-! # Affine schemes @@ -113,6 +114,25 @@ def arrowIsoSpecΓOfIsAffine {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Arrow.mk f ≅ Arrow.mk (Spec.map (Scheme.Γ.map f.op)) := Arrow.isoMk X.isoSpec Y.isoSpec (ΓSpec.adjunction.unit_naturality _) +/-- If `f : A ⟶ B` is a ring homomorphism, the corresponding arrow is isomorphic +to the arrow of the morphism induced on global sections by the map on prime spectra. -/ +def arrowIsoΓSpecOfIsAffine {A B : CommRingCat} (f : A ⟶ B) : + Arrow.mk f ≅ Arrow.mk ((Spec.map f).app ⊤) := + Arrow.isoMk (Scheme.ΓSpecIso _).symm (Scheme.ΓSpecIso _).symm + (Scheme.ΓSpecIso_inv_naturality f).symm + +theorem Scheme.isoSpec_Spec (R : CommRingCat.{u}) : + (Spec R).isoSpec = Scheme.Spec.mapIso (Scheme.ΓSpecIso R).op := + Iso.ext (SpecMap_ΓSpecIso_hom R).symm + +@[simp] theorem Scheme.isoSpec_Spec_hom (R : CommRingCat.{u}) : + (Spec R).isoSpec.hom = Spec.map (Scheme.ΓSpecIso R).hom := + (SpecMap_ΓSpecIso_hom R).symm + +@[simp] theorem Scheme.isoSpec_Spec_inv (R : CommRingCat.{u}) : + (Spec R).isoSpec.inv = Spec.map (Scheme.ΓSpecIso R).inv := + congr($(isoSpec_Spec R).inv) + namespace AffineScheme /-- The `Spec` functor into the category of affine schemes. -/ @@ -228,15 +248,15 @@ theorem iSup_affineOpens_eq_top (X : Scheme) : ⨆ i : X.affineOpens, (i : X.Ope exact isBasis_affine_open X theorem Scheme.map_PrimeSpectrum_basicOpen_of_affine - (X : Scheme) [IsAffine X] (f : Scheme.Γ.obj (op X)) : + (X : Scheme) [IsAffine X] (f : Γ(X, ⊤)) : X.isoSpec.hom ⁻¹ᵁ PrimeSpectrum.basicOpen f = X.basicOpen f := Scheme.toSpecΓ_preimage_basicOpen _ _ theorem isBasis_basicOpen (X : Scheme) [IsAffine X] : Opens.IsBasis (Set.range (X.basicOpen : Γ(X, ⊤) → X.Opens)) := by delta Opens.IsBasis - convert PrimeSpectrum.isBasis_basic_opens.inducing - (TopCat.homeoOfIso (Scheme.forgetToTop.mapIso X.isoSpec)).inducing using 1 + convert PrimeSpectrum.isBasis_basic_opens.isInducing + (TopCat.homeoOfIso (Scheme.forgetToTop.mapIso X.isoSpec)).isInducing using 1 ext simp only [Set.mem_image, exists_exists_eq_and] constructor @@ -247,49 +267,122 @@ theorem isBasis_basicOpen (X : Scheme) [IsAffine X] : refine ⟨_, ⟨x, rfl⟩, ?_⟩ exact congr_arg Opens.carrier (Scheme.toSpecΓ_preimage_basicOpen _ _).symm +/-- The canonical map `U ⟶ Spec Γ(X, U)` for an open `U ⊆ X`. -/ +noncomputable +def Scheme.Opens.toSpecΓ {X : Scheme.{u}} (U : X.Opens) : + U.toScheme ⟶ Spec Γ(X, U) := + U.toScheme.toSpecΓ ≫ Spec.map U.topIso.inv + namespace IsAffineOpen variable {X Y : Scheme.{u}} {U : X.Opens} (hU : IsAffineOpen U) (f : Γ(X, U)) +attribute [-simp] eqToHom_op in +/-- The isomorphism `U ≅ Spec Γ(X, U)` for an affine `U`. -/ +@[simps! (config := .lemmasOnly) inv] +def isoSpec : + ↑U ≅ Spec Γ(X, U) := + haveI : IsAffine U := hU + U.toScheme.isoSpec ≪≫ Scheme.Spec.mapIso U.topIso.symm.op + +lemma isoSpec_hom {X : Scheme.{u}} {U : X.Opens} (hU : IsAffineOpen U) : + hU.isoSpec.hom = U.toSpecΓ := rfl + +open LocalRing in +lemma isoSpec_hom_base_apply (x : U) : + hU.isoSpec.hom.base x = (Spec.map (X.presheaf.germ U x x.2)).base (closedPoint _) := by + dsimp [IsAffineOpen.isoSpec_hom, Scheme.isoSpec_hom, Scheme.toSpecΓ_base, Scheme.Opens.toSpecΓ] + rw [← Scheme.comp_base_apply, ← Spec.map_comp, + (Iso.eq_comp_inv _).mpr (Scheme.Opens.germ_stalkIso_hom U (V := ⊤) x trivial), + X.presheaf.germ_res_assoc, Spec.map_comp, Scheme.comp_base_apply] + congr 1 + exact LocalRing.comap_closedPoint (U.stalkIso x).inv + +lemma isoSpec_inv_app_top : + hU.isoSpec.inv.app ⊤ = U.topIso.hom ≫ (Scheme.ΓSpecIso Γ(X, U)).inv := by + simp only [Scheme.Opens.toScheme_presheaf_obj, isoSpec_inv, Scheme.isoSpec, asIso_inv, + Scheme.comp_coeBase, Opens.map_comp_obj, Opens.map_top, Scheme.comp_app, Scheme.inv_app_top, + Scheme.Opens.topIso_hom, Scheme.ΓSpecIso_inv_naturality, IsIso.inv_comp_eq] + rw [Scheme.toSpecΓ_app_top] + erw [Iso.hom_inv_id_assoc] + +lemma isoSpec_hom_app_top : + hU.isoSpec.hom.app ⊤ = (Scheme.ΓSpecIso Γ(X, U)).hom ≫ U.topIso.inv := by + have := congr(inv $hU.isoSpec_inv_app_top) + rw [IsIso.inv_comp, IsIso.Iso.inv_inv, IsIso.Iso.inv_hom] at this + have := (Scheme.Γ.map_inv hU.isoSpec.inv.op).trans this + rwa [← op_inv, IsIso.Iso.inv_inv] at this + /-- The open immersion `Spec Γ(X, U) ⟶ X` for an affine `U`. -/ def fromSpec : Spec Γ(X, U) ⟶ X := haveI : IsAffine U := hU - Spec.map (X.presheaf.map (eqToHom U.openEmbedding_obj_top.symm).op) ≫ - U.toScheme.isoSpec.inv ≫ U.ι + hU.isoSpec.inv ≫ U.ι instance isOpenImmersion_fromSpec : IsOpenImmersion hU.fromSpec := by delta fromSpec infer_instance +@[reassoc (attr := simp)] +lemma isoSpec_inv_ι : hU.isoSpec.inv ≫ U.ι = hU.fromSpec := rfl + @[simp] theorem range_fromSpec : - Set.range hU.fromSpec.1.base = (U : Set X) := by - delta IsAffineOpen.fromSpec; dsimp - rw [Function.comp_assoc, Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ] + Set.range hU.fromSpec.base = (U : Set X) := by + delta IsAffineOpen.fromSpec; dsimp [IsAffineOpen.isoSpec_inv] + rw [Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ] · exact Subtype.range_coe - erw [← coe_comp, ← TopCat.epi_iff_surjective] -- now `erw` after #13170 + rw [← coe_comp, ← TopCat.epi_iff_surjective] infer_instance @[simp] -theorem opensRange_fromSpec : Scheme.Hom.opensRange hU.fromSpec = U := Opens.ext (range_fromSpec hU) +theorem opensRange_fromSpec :hU.fromSpec.opensRange = U := Opens.ext (range_fromSpec hU) @[reassoc (attr := simp)] theorem map_fromSpec {V : X.Opens} (hV : IsAffineOpen V) (f : op U ⟶ op V) : Spec.map (X.presheaf.map f) ≫ hU.fromSpec = hV.fromSpec := by - have : IsAffine (X.restrictFunctor.obj U).left := hU + have : IsAffine U := hU haveI : IsAffine _ := hV conv_rhs => - rw [fromSpec, ← X.restrictFunctor_map_ofRestrict f.unop, ← Scheme.isoSpec_inv_naturality_assoc, - ← Spec.map_comp_assoc, Scheme.restrictFunctor_map_app, ← Functor.map_comp] - rw [fromSpec, ← Spec.map_comp_assoc, ← Functor.map_comp] + rw [fromSpec, ← X.homOfLE_ι (V := U) f.unop.le, isoSpec_inv, Category.assoc, + ← Scheme.isoSpec_inv_naturality_assoc, + ← Spec.map_comp_assoc, Scheme.homOfLE_app, ← Functor.map_comp] + rw [fromSpec, isoSpec_inv, Category.assoc, ← Spec.map_comp_assoc, ← Functor.map_comp] + rfl + +@[reassoc] +lemma Spec_map_appLE_fromSpec (f : X ⟶ Y) {V : X.Opens} {U : Y.Opens} + (hU : IsAffineOpen U) (hV : IsAffineOpen V) (i : V ≤ f ⁻¹ᵁ U) : + Spec.map (f.appLE U V i) ≫ hU.fromSpec = hV.fromSpec ≫ f := by + have : IsAffine U := hU + simp only [IsAffineOpen.fromSpec, Category.assoc, isoSpec_inv] + simp_rw [← Scheme.homOfLE_ι _ i] + rw [Category.assoc, ← morphismRestrict_ι, + ← Category.assoc _ (f ∣_ U) U.ι, ← @Scheme.isoSpec_inv_naturality_assoc, + ← Spec.map_comp_assoc, ← Spec.map_comp_assoc, Scheme.comp_app, morphismRestrict_app, + Scheme.homOfLE_app, Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map, + Scheme.Hom.appLE_map, Scheme.Hom.appLE_map, Scheme.Hom.map_appLE] + +lemma fromSpec_top [IsAffine X] : (isAffineOpen_top X).fromSpec = X.isoSpec.inv := by + rw [fromSpec, isoSpec_inv, Category.assoc, ← @Scheme.isoSpec_inv_naturality, Scheme.Opens.ι_app, + ← Spec.map_comp_assoc, ← X.presheaf.map_comp, ← op_comp, eqToHom_comp_homOfLE, + ← eqToHom_eq_homOfLE rfl, eqToHom_refl, op_id, X.presheaf.map_id, Spec.map_id, Category.id_comp] + +lemma fromSpec_app_of_le (V : X.Opens) (h : U ≤ V) : + hU.fromSpec.app V = X.presheaf.map (homOfLE h).op ≫ + (Scheme.ΓSpecIso Γ(X, U)).inv ≫ (Spec _).presheaf.map (homOfLE le_top).op := by + have : U.ι ⁻¹ᵁ V = ⊤ := eq_top_iff.mpr fun x _ ↦ h x.2 + rw [IsAffineOpen.fromSpec, Scheme.comp_app, Scheme.Opens.ι_app, Scheme.app_eq _ this, + IsAffineOpen.isoSpec_inv_app_top] + simp only [Scheme.Opens.toScheme_presheaf_map, Scheme.Opens.topIso_hom, + Category.assoc, ← X.presheaf.map_comp_assoc] rfl include hU in protected theorem isCompact : IsCompact (U : Set X) := by - convert @IsCompact.image _ _ _ _ Set.univ hU.fromSpec.1.base PrimeSpectrum.compactSpace.1 + convert @IsCompact.image _ _ _ _ Set.univ hU.fromSpec.base PrimeSpectrum.compactSpace.1 (by fun_prop) convert hU.range_fromSpec.symm exact Set.image_univ @@ -311,9 +404,9 @@ theorem _root_.AlgebraicGeometry.Scheme.Hom.isAffineOpen_iff_of_isOpenImmersion (f : AlgebraicGeometry.Scheme.Hom X Y) [H : IsOpenImmersion f] {U : X.Opens} : IsAffineOpen (f ''ᵁ U) ↔ IsAffineOpen U := by refine ⟨fun hU => @isAffine_of_isIso _ _ - (IsOpenImmersion.isoOfRangeEq (X.ofRestrict U.openEmbedding ≫ f) (Y.ofRestrict _) ?_).hom ?_ hU, - fun hU => hU.image_of_isOpenImmersion f⟩ - · erw [Scheme.comp_val_base, coe_comp, Set.range_comp] -- now `erw` after #13170 + (IsOpenImmersion.isoOfRangeEq (X.ofRestrict U.isOpenEmbedding ≫ f) (Y.ofRestrict _) ?_).hom + ?_ hU, fun hU => hU.image_of_isOpenImmersion f⟩ + · rw [Scheme.comp_base, coe_comp, Set.range_comp] dsimp [Opens.coe_inclusion', Scheme.restrict] erw [Subtype.range_coe, Subtype.range_coe] -- now `erw` after #13170 rfl @@ -354,22 +447,20 @@ theorem fromSpec_preimage_self : rw [Opens.map_coe, Opens.coe_top, ← hU.range_fromSpec, ← Set.image_univ] exact Set.preimage_image_eq _ PresheafedSpace.IsOpenImmersion.base_open.inj -theorem SpecΓIdentity_hom_app_fromSpec : +theorem ΓSpecIso_hom_fromSpec_app : (Scheme.ΓSpecIso Γ(X, U)).hom ≫ hU.fromSpec.app U = (Spec Γ(X, U)).presheaf.map (eqToHom hU.fromSpec_preimage_self).op := by - simp only [fromSpec, Scheme.isoSpec, asIso_inv, Scheme.comp_coeBase, Opens.map_comp_obj, - ΓSpecIso_obj_hom, Scheme.Opens.topIso_inv, Opens.map_top, Scheme.Opens.topIso_hom, - Scheme.comp_app, Scheme.Opens.ι_app_self, unop_op, Category.assoc, ← Functor.map_comp_assoc, ← - op_comp, eqToHom_trans, Scheme.Opens.eq_presheaf_map_eqToHom, Scheme.Hom.naturality_assoc, - Scheme.inv_app_top, IsIso.hom_inv_id_assoc] - simp only [eqToHom_op, eqToHom_map, Spec.map_eqToHom, eqToHom_unop, - Scheme.Spec_map_presheaf_map_eqToHom, eqToHom_trans] + simp only [fromSpec, Scheme.comp_coeBase, Opens.map_comp_obj, Scheme.comp_app, + Scheme.Opens.ι_app_self, eqToHom_op, Scheme.app_eq _ U.ι_preimage_self, + Scheme.Opens.toScheme_presheaf_map, eqToHom_unop, eqToHom_map U.ι.opensFunctor, Opens.map_top, + isoSpec_inv_app_top, Scheme.Opens.topIso_hom, Category.assoc, ← Functor.map_comp_assoc, + eqToHom_trans, eqToHom_refl, X.presheaf.map_id, Category.id_comp, Iso.hom_inv_id_assoc] @[elementwise] theorem fromSpec_app_self : hU.fromSpec.app U = (Scheme.ΓSpecIso Γ(X, U)).inv ≫ (Spec Γ(X, U)).presheaf.map (eqToHom hU.fromSpec_preimage_self).op := by - rw [← hU.SpecΓIdentity_hom_app_fromSpec, Iso.inv_hom_id_assoc] + rw [← hU.ΓSpecIso_hom_fromSpec_app, Iso.inv_hom_id_assoc] theorem fromSpec_preimage_basicOpen' : hU.fromSpec ⁻¹ᵁ X.basicOpen f = (Spec Γ(X, U)).basicOpen ((Scheme.ΓSpecIso Γ(X, U)).inv f) := by @@ -384,7 +475,7 @@ theorem fromSpec_image_basicOpen : hU.fromSpec ''ᵁ (PrimeSpectrum.basicOpen f) = X.basicOpen f := by rw [← hU.fromSpec_preimage_basicOpen] ext1 - change hU.fromSpec.val.base '' (hU.fromSpec.val.base ⁻¹' (X.basicOpen f : Set X)) = _ + change hU.fromSpec.base '' (hU.fromSpec.base ⁻¹' (X.basicOpen f : Set X)) = _ rw [Set.image_preimage_eq_inter_range, Set.inter_eq_left, hU.range_fromSpec] exact Scheme.basicOpen_le _ _ @@ -409,7 +500,7 @@ theorem ι_basicOpen_preimage (r : Γ(X, ⊤)) : IsAffineOpen ((X.basicOpen r).ι ⁻¹ᵁ U) := by apply (X.basicOpen r).ι.isAffineOpen_iff_of_isOpenImmersion.mp dsimp [Scheme.Hom.opensFunctor, LocallyRingedSpace.IsOpenImmersion.opensFunctor] - rw [Opens.functor_obj_map_obj, Opens.openEmbedding_obj_top, inf_comm, + rw [Opens.functor_obj_map_obj, Opens.isOpenEmbedding_obj_top, inf_comm, ← Scheme.basicOpen_res _ _ (homOfLE le_top).op] exact hU.basicOpen _ @@ -422,12 +513,12 @@ theorem exists_basicOpen_le {V : X.Opens} (x : V) (h : ↑x ∈ U) : ((Opens.map U.inclusion').obj V).isOpen have : U.ι ''ᵁ (U.toScheme.basicOpen r) = - X.basicOpen (X.presheaf.map (eqToHom U.openEmbedding_obj_top.symm).op r) := by + X.basicOpen (X.presheaf.map (eqToHom U.isOpenEmbedding_obj_top.symm).op r) := by refine (Scheme.image_basicOpen U.ι r).trans ?_ rw [Scheme.basicOpen_res_eq] simp only [Scheme.Opens.toScheme_presheaf_obj, Scheme.Opens.ι_appIso, Iso.refl_inv, CommRingCat.id_apply] - use X.presheaf.map (eqToHom U.openEmbedding_obj_top.symm).op r + use X.presheaf.map (eqToHom U.isOpenEmbedding_obj_top.symm).op r rw [← this] exact ⟨Set.image_subset_iff.mpr h₂, ⟨_, h⟩, h₁, rfl⟩ @@ -436,7 +527,7 @@ this is the canonical map `Γ(𝒪ₓ, D(f)) ⟶ Γ(Spec 𝒪ₓ(U), D(f))` This is an isomorphism, as witnessed by an `IsIso` instance. -/ def basicOpenSectionsToAffine : Γ(X, X.basicOpen f) ⟶ Γ(Spec Γ(X, U), PrimeSpectrum.basicOpen f) := - hU.fromSpec.1.c.app (op <| X.basicOpen f) ≫ + hU.fromSpec.c.app (op <| X.basicOpen f) ≫ (Spec Γ(X, U)).presheaf.map (eqToHom <| (hU.fromSpec_preimage_basicOpen f).symm).op instance basicOpenSectionsToAffine_isIso : @@ -491,7 +582,7 @@ theorem isLocalization_of_eq_basicOpen {V : X.Opens} (i : V ⟶ U) (e : V = X.ba instance _root_.AlgebraicGeometry.Γ_restrict_isLocalization (X : Scheme.{u}) [IsAffine X] (r : Γ(X, ⊤)) : IsLocalization.Away r Γ(X.basicOpen r, ⊤) := - (isAffineOpen_top X).isLocalization_of_eq_basicOpen r _ (Opens.openEmbedding_obj_top _) + (isAffineOpen_top X).isLocalization_of_eq_basicOpen r _ (Opens.isOpenEmbedding_obj_top _) include hU in theorem basicOpen_basicOpen_is_basicOpen (g : Γ(X, X.basicOpen f)) : @@ -524,30 +615,28 @@ theorem _root_.AlgebraicGeometry.exists_basicOpen_le_affine_inter /-- The prime ideal of `𝒪ₓ(U)` corresponding to a point `x : U`. -/ noncomputable def primeIdealOf (x : U) : PrimeSpectrum Γ(X, U) := - ((@Scheme.isoSpec U hU).hom ≫ - Spec.map (X.presheaf.map (eqToHom U.openEmbedding_obj_top).op)).1.base x + hU.isoSpec.hom.base x theorem fromSpec_primeIdealOf (x : U) : - hU.fromSpec.val.base (hU.primeIdealOf x) = x.1 := by + hU.fromSpec.base (hU.primeIdealOf x) = x.1 := by dsimp only [IsAffineOpen.fromSpec, Subtype.coe_mk, IsAffineOpen.primeIdealOf] - -- Porting note: in the porting note of `Scheme.comp_val_base`, it says that `elementwise` is - -- unnecessary, indeed, the linter did not like it, so I just use `elementwise_of%` instead of - -- adding the corresponding lemma in `Scheme.lean` file - erw [← elementwise_of% Scheme.comp_val_base] -- now `erw` after #13170 - simp only [Scheme.Opens.toScheme_presheaf_obj, Category.assoc, ← Spec.map_comp_assoc, - ← Functor.map_comp, ← op_comp, eqToHom_trans, eqToHom_refl, op_id, - CategoryTheory.Functor.map_id, Spec.map_id, Category.id_comp, Iso.hom_inv_id_assoc] - rfl -- `rfl` was not needed before #13170 - -theorem isLocalization_stalk' (y : PrimeSpectrum Γ(X, U)) (hy : hU.fromSpec.1.base y ∈ U) : + rw [← Scheme.comp_base_apply, Iso.hom_inv_id_assoc] + rfl + +open LocalRing in +theorem primeIdealOf_eq_map_closedPoint (x : U) : + hU.primeIdealOf x = (Spec.map (X.presheaf.germ _ x x.2)).base (closedPoint _) := + hU.isoSpec_hom_base_apply _ + +theorem isLocalization_stalk' (y : PrimeSpectrum Γ(X, U)) (hy : hU.fromSpec.base y ∈ U) : @IsLocalization.AtPrime (R := Γ(X, U)) - (S := X.presheaf.stalk <| hU.fromSpec.1.base y) _ _ + (S := X.presheaf.stalk <| hU.fromSpec.base y) _ _ ((TopCat.Presheaf.algebra_section_stalk X.presheaf _)) y.asIdeal _ := by apply (@IsLocalization.isLocalization_iff_of_ringEquiv (R := Γ(X, U)) - (S := X.presheaf.stalk (hU.fromSpec.1.base y)) _ y.asIdeal.primeCompl _ - (TopCat.Presheaf.algebra_section_stalk X.presheaf ⟨hU.fromSpec.1.base y, hy⟩) _ _ + (S := X.presheaf.stalk (hU.fromSpec.base y)) _ y.asIdeal.primeCompl _ + (TopCat.Presheaf.algebra_section_stalk X.presheaf ⟨hU.fromSpec.base y, hy⟩) _ _ (asIso <| hU.fromSpec.stalkMap y).commRingCatIsoToRingEquiv).mpr -- Porting note: need to know what the ring is and after convert, instead of equality -- we get an `iff`. @@ -556,8 +645,8 @@ theorem isLocalization_stalk' (y : PrimeSpectrum Γ(X, U)) (hy : hU.fromSpec.1.b rw [iff_iff_eq] congr 2 rw [RingHom.algebraMap_toAlgebra] - refine (PresheafedSpace.stalkMap_germ hU.fromSpec.1 _ ⟨_, hy⟩).trans ?_ - rw [← Scheme.Hom.app, IsAffineOpen.fromSpec_app_self, Category.assoc, TopCat.Presheaf.germ_res] + refine (Scheme.stalkMap_germ hU.fromSpec _ _ hy).trans ?_ + rw [IsAffineOpen.fromSpec_app_self, Category.assoc, TopCat.Presheaf.germ_res] rfl -- Porting note: I have split this into two lemmas @@ -565,11 +654,20 @@ theorem isLocalization_stalk (x : U) : IsLocalization.AtPrime (X.presheaf.stalk x) (hU.primeIdealOf x).asIdeal := by rcases x with ⟨x, hx⟩ set y := hU.primeIdealOf ⟨x, hx⟩ with hy - have : hU.fromSpec.val.base y = x := hy ▸ hU.fromSpec_primeIdealOf ⟨x, hx⟩ + have : hU.fromSpec.base y = x := hy ▸ hU.fromSpec_primeIdealOf ⟨x, hx⟩ clear_value y subst this exact hU.isLocalization_stalk' y hx +lemma stalkMap_injective (f : X ⟶ Y) {U : Opens Y} (hU : IsAffineOpen U) (x : X) + (hx : f.base x ∈ U) + (h : ∀ g, f.stalkMap x (Y.presheaf.germ U (f.base x) hx g) = 0 → + Y.presheaf.germ U (f.base x) hx g = 0) : + Function.Injective (f.stalkMap x) := by + letI := Y.presheaf.algebra_section_stalk ⟨f.base x, hx⟩ + apply (hU.isLocalization_stalk ⟨f.base x, hx⟩).injective_of_map_algebraMap_zero + exact h + /-- The basic open set of a section `f` on an affine open as an `X.affineOpens`. -/ @[simps] def _root_.AlgebraicGeometry.Scheme.affineBasicOpen @@ -585,11 +683,11 @@ theorem basicOpen_union_eq_self_iff (s : Set Γ(X, U)) : ⨆ f : s, X.basicOpen (f : Γ(X, U)) = U ↔ Ideal.span s = ⊤ := by trans ⋃ i : s, (PrimeSpectrum.basicOpen i.1).1 = Set.univ · trans - hU.fromSpec.1.base ⁻¹' (⨆ f : s, X.basicOpen (f : Γ(X, U))).1 = - hU.fromSpec.1.base ⁻¹' U.1 + hU.fromSpec.base ⁻¹' (⨆ f : s, X.basicOpen (f : Γ(X, U))).1 = + hU.fromSpec.base ⁻¹' U.1 · refine ⟨fun h => by rw [h], ?_⟩ intro h - apply_fun Set.image hU.fromSpec.1.base at h + apply_fun Set.image hU.fromSpec.base at h rw [Set.image_preimage_eq_inter_range, Set.image_preimage_eq_inter_range, hU.range_fromSpec] at h simp only [Set.inter_self, Opens.carrier_eq_coe, Set.inter_eq_right] at h @@ -620,6 +718,12 @@ theorem self_le_basicOpen_union_iff (s : Set Γ(X, U)) : end IsAffineOpen +lemma stalkMap_injective_of_isAffine {X Y : Scheme} (f : X ⟶ Y) [IsAffine Y] (x : X) + (h : ∀ g, f.stalkMap x (Y.presheaf.Γgerm (f.base x) g) = 0 → + Y.presheaf.Γgerm (f.base x) g = 0) : + Function.Injective (f.stalkMap x) := + (isAffineOpen_top Y).stalkMap_injective f x trivial h + /-- Given a spanning set of `Γ(X, U)`, the corresponding basic open sets cover `U`. See `IsAffineOpen.basicOpen_union_eq_self_iff` for the inverse direction for affine open sets. @@ -684,7 +788,7 @@ section ZeroLocus /-- On a locally ringed space `X`, the preimage of the zero locus of the prime spectrum of `Γ(X, ⊤)` under `toΓSpecFun` agrees with the associated zero locus on `X`. -/ lemma Scheme.toΓSpec_preimage_zeroLocus_eq {X : Scheme.{u}} (s : Set Γ(X, ⊤)) : - X.toSpecΓ.val.base ⁻¹' PrimeSpectrum.zeroLocus s = X.zeroLocus s := + X.toSpecΓ.base ⁻¹' PrimeSpectrum.zeroLocus s = X.zeroLocus s := LocallyRingedSpace.toΓSpec_preimage_zeroLocus_eq s open ConcreteCategory @@ -693,9 +797,9 @@ open ConcreteCategory is the zero locus in terms of the prime spectrum of `Γ(X, ⊤)`. -/ lemma Scheme.toΓSpec_image_zeroLocus_eq_of_isAffine {X : Scheme.{u}} [IsAffine X] (s : Set Γ(X, ⊤)) : - X.isoSpec.hom.val.base '' X.zeroLocus s = PrimeSpectrum.zeroLocus s := by + X.isoSpec.hom.base '' X.zeroLocus s = PrimeSpectrum.zeroLocus s := by erw [← X.toΓSpec_preimage_zeroLocus_eq, Set.image_preimage_eq] - exact (bijective_of_isIso X.isoSpec.hom.val.base).surjective + exact (bijective_of_isIso X.isoSpec.hom.base).surjective /-- If `X` is an affine scheme, every closed set of `X` is the zero locus of a set of global sections. -/ @@ -707,12 +811,115 @@ lemma Scheme.eq_zeroLocus_of_isClosed_of_isAffine (X : Scheme.{u}) [IsAffine X] obtain ⟨I, (hI : Z = _)⟩ := (PrimeSpectrum.isClosed_iff_zeroLocus_ideal _).mp hZ use I simp only [← Scheme.toΓSpec_preimage_zeroLocus_eq, ← hI, Z] - erw [Set.preimage_image_eq _ (bijective_of_isIso X.isoSpec.hom.val.base).injective] + erw [Set.preimage_image_eq _ (bijective_of_isIso X.isoSpec.hom.base).injective] · rintro ⟨I, rfl⟩ exact zeroLocus_isClosed X I.carrier end ZeroLocus +section Factorization + +variable {X : Scheme.{u}} {A : CommRingCat} + +/-- If `X ⟶ Spec A` is a morphism of schemes, then `Spec` of `A ⧸ specTargetImage f` +is the scheme-theoretic image of `f`. For this quotient as an object of `CommRingCat` see +`specTargetImage` below. -/ +def specTargetImageIdeal (f : X ⟶ Spec A) : Ideal A := + (RingHom.ker <| (((ΓSpec.adjunction).homEquiv X (op A)).symm f).unop) + +/-- If `X ⟶ Spec A` is a morphism of schemes, then `Spec` of `specTargetImage f` is the +scheme-theoretic image of `f` and `f` factors as +`specTargetImageFactorization f ≫ Spec.map (specTargetImageRingHom f)` +(see `specTargetImageFactorization_comp`). -/ +def specTargetImage (f : X ⟶ Spec A) : CommRingCat := + CommRingCat.of (A ⧸ specTargetImageIdeal f) + +/-- If `f : X ⟶ Spec A` is a morphism of schemes, then `f` factors via +the inclusion of `Spec (specTargetImage f)` into `X`. -/ +def specTargetImageFactorization (f : X ⟶ Spec A) : X ⟶ Spec (specTargetImage f) := + (ΓSpec.adjunction).homEquiv X (op <| specTargetImage f) (Opposite.op (RingHom.kerLift _)) + +/-- If `f : X ⟶ Spec A` is a morphism of schemes, the induced morphism on spectra of +`specTargetImageRingHom f` is the inclusion of the scheme-theoretic image of `f` into `Spec A`. -/ +def specTargetImageRingHom (f : X ⟶ Spec A) : A ⟶ specTargetImage f := + Ideal.Quotient.mk (specTargetImageIdeal f) + +variable (f : X ⟶ Spec A) + +lemma specTargetImageRingHom_surjective : Function.Surjective (specTargetImageRingHom f) := + Ideal.Quotient.mk_surjective + +lemma specTargetImageFactorization_app_injective : + Function.Injective <| (specTargetImageFactorization f).app ⊤ := by + let φ : A ⟶ Γ(X, ⊤) := (((ΓSpec.adjunction).homEquiv X (op A)).symm f).unop + let φ' : specTargetImage f ⟶ Scheme.Γ.obj (op X) := RingHom.kerLift φ + show Function.Injective <| ((ΓSpec.adjunction.homEquiv X _) φ'.op).app ⊤ + rw [ΓSpec_adjunction_homEquiv_eq] + apply (RingHom.kerLift_injective φ).comp + exact ((ConcreteCategory.isIso_iff_bijective (Scheme.ΓSpecIso _).hom).mp inferInstance).injective + +@[reassoc (attr := simp)] +lemma specTargetImageFactorization_comp : + specTargetImageFactorization f ≫ Spec.map (specTargetImageRingHom f) = f := by + let φ : A ⟶ Γ(X, ⊤) := (((ΓSpec.adjunction).homEquiv X (op A)).symm f).unop + let φ' : specTargetImage f ⟶ Scheme.Γ.obj (op X) := RingHom.kerLift φ + apply ((ΓSpec.adjunction).homEquiv X (op A)).symm.injective + apply Opposite.unop_injective + rw [Adjunction.homEquiv_naturality_left_symm, Adjunction.homEquiv_counit] + change (_ ≫ _) ≫ _ = φ + erw [← Spec_Γ_naturality] + rw [Category.assoc] + erw [ΓSpecIso_inv_ΓSpec_adjunction_homEquiv φ'] + ext a + apply RingHom.kerLift_mk + +open RingHom + +variable {Y : Scheme.{u}} [IsAffine Y] (f : X ⟶ Y) + +/-- The scheme-theoretic image of a morphism `f : X ⟶ Y` with affine target. +`f` factors as `affineTargetImageFactorization f ≫ affineTargetImageInclusion f` +(see `affineTargetImageFactorization_comp`). -/ +def affineTargetImage (f : X ⟶ Y) : Scheme.{u} := + Spec <| specTargetImage (f ≫ Y.isoSpec.hom) + +instance : IsAffine (affineTargetImage f) := inferInstanceAs <| IsAffine <| Spec _ + +/-- The inclusion of the scheme-theoretic image of a morphism with affine target. -/ +def affineTargetImageInclusion (f : X ⟶ Y) : affineTargetImage f ⟶ Y := + Spec.map (specTargetImageRingHom (f ≫ Y.isoSpec.hom)) ≫ Y.isoSpec.inv + +lemma affineTargetImageInclusion_app_surjective : + Function.Surjective <| (affineTargetImageInclusion f).app ⊤ := by + simp only [Scheme.comp_coeBase, Opens.map_comp_obj, Opens.map_top, Scheme.comp_app, + CommRingCat.coe_comp, affineTargetImageInclusion] + apply Function.Surjective.comp + · haveI : (toMorphismProperty (fun f ↦ Function.Surjective f)).RespectsIso := by + rw [← toMorphismProperty_respectsIso_iff] + exact surjective_respectsIso + exact (MorphismProperty.arrow_mk_iso_iff + (toMorphismProperty (fun f ↦ Function.Surjective f)) + (arrowIsoΓSpecOfIsAffine (specTargetImageRingHom (f ≫ Y.isoSpec.hom))).symm).mpr <| + specTargetImageRingHom_surjective (f ≫ Y.isoSpec.hom) + · apply Function.Bijective.surjective + apply ConcreteCategory.bijective_of_isIso + +/-- The induced morphism from `X` to the scheme-theoretic image +of a morphism `f : X ⟶ Y` with affine target. -/ +def affineTargetImageFactorization (f : X ⟶ Y) : X ⟶ affineTargetImage f := + specTargetImageFactorization (f ≫ Y.isoSpec.hom) + +lemma affineTargetImageFactorization_app_injective : + Function.Injective <| (affineTargetImageFactorization f).app ⊤ := + specTargetImageFactorization_app_injective (f ≫ Y.isoSpec.hom) + +@[reassoc (attr := simp)] +lemma affineTargetImageFactorization_comp : + affineTargetImageFactorization f ≫ affineTargetImageInclusion f = f := by + simp [affineTargetImageFactorization, affineTargetImageInclusion] + +end Factorization + section Stalks /-- Variant of `AlgebraicGeometry.localRingHom_comp_stalkIso` for `Spec.map`. -/ diff --git a/Mathlib/AlgebraicGeometry/Cover/Open.lean b/Mathlib/AlgebraicGeometry/Cover/Open.lean index 959dc19b68c73..32b601db856c3 100644 --- a/Mathlib/AlgebraicGeometry/Cover/Open.lean +++ b/Mathlib/AlgebraicGeometry/Cover/Open.lean @@ -49,7 +49,7 @@ structure OpenCover (X : Scheme.{u}) where /-- given a point of `x : X`, `f x` is the index of the subscheme which contains `x` -/ f : X → J /-- the subschemes covers `X` -/ - covers : ∀ x, x ∈ Set.range (map (f x)).1.base + covers : ∀ x, x ∈ Set.range (map (f x)).base /-- the embedding of subschemes are open immersions -/ IsOpen : ∀ x, IsOpenImmersion (map x) := by infer_instance @@ -65,7 +65,7 @@ def affineCover (X : Scheme.{u}) : OpenCover X where J := X obj x := Spec (X.local_affine x).choose_spec.choose map x := - ((X.local_affine x).choose_spec.choose_spec.some.inv ≫ X.toLocallyRingedSpace.ofRestrict _ : _) + ⟨(X.local_affine x).choose_spec.choose_spec.some.inv ≫ X.toLocallyRingedSpace.ofRestrict _⟩ f x := x covers := by intro x @@ -73,7 +73,7 @@ def affineCover (X : Scheme.{u}) : OpenCover X where rw [Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ] · erw [Subtype.range_coe_subtype] exact (X.local_affine x).choose.2 - erw [← TopCat.epi_iff_surjective] -- now `erw` after #13170 + rw [← TopCat.epi_iff_surjective] change Epi ((SheafedSpace.forget _).map (LocallyRingedSpace.forgetToSheafedSpace.map _)) infer_instance @@ -81,7 +81,7 @@ instance : Inhabited X.OpenCover := ⟨X.affineCover⟩ theorem OpenCover.iUnion_range {X : Scheme.{u}} (𝒰 : X.OpenCover) : - ⋃ i, Set.range (𝒰.map i).1.base = Set.univ := by + ⋃ i, Set.range (𝒰.map i).base = Set.univ := by rw [Set.eq_univ_iff_forall] intro x rw [Set.mem_iUnion] @@ -101,15 +101,15 @@ def OpenCover.bind (f : ∀ x : 𝒰.J, OpenCover (𝒰.obj x)) : OpenCover X wh f x := ⟨_, (f _).f (𝒰.covers x).choose⟩ covers x := by let y := (𝒰.covers x).choose - have hy : (𝒰.map (𝒰.f x)).val.base y = x := (𝒰.covers x).choose_spec + have hy : (𝒰.map (𝒰.f x)).base y = x := (𝒰.covers x).choose_spec rcases (f (𝒰.f x)).covers y with ⟨z, hz⟩ - change x ∈ Set.range ((f (𝒰.f x)).map ((f (𝒰.f x)).f y) ≫ 𝒰.map (𝒰.f x)).1.base + change x ∈ Set.range ((f (𝒰.f x)).map ((f (𝒰.f x)).f y) ≫ 𝒰.map (𝒰.f x)).base use z erw [comp_apply] - erw [hz, hy] -- now `erw` after #13170 + rw [hz, hy] -- Porting note: weirdly, even though no input is needed, `inferInstance` does not work -- `PresheafedSpace.IsOpenImmersion.comp` is marked as `instance` - IsOpen x := PresheafedSpace.IsOpenImmersion.comp _ _ + IsOpen _ := PresheafedSpace.IsOpenImmersion.comp _ _ /-- An isomorphism `X ⟶ Y` is an open cover of `Y`. -/ @[simps J obj map] @@ -133,10 +133,10 @@ def OpenCover.copy {X : Scheme.{u}} (𝒰 : OpenCover X) (J : Type*) (obj : J { J, obj, map f := fun x => e₁.symm (𝒰.f x) covers := fun x => by - rw [e₂, Scheme.comp_val_base, TopCat.coe_comp, Set.range_comp, Set.range_iff_surjective.mpr, + rw [e₂, Scheme.comp_base, TopCat.coe_comp, Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ, e₁.rightInverse_symm] · exact 𝒰.covers x - · erw [← TopCat.epi_iff_surjective]; infer_instance -- now `erw` after #13170 + · rw [← TopCat.epi_iff_surjective]; infer_instance -- Porting note: weirdly, even though no input is needed, `inferInstance` does not work -- `PresheafedSpace.IsOpenImmersion.comp` is marked as `instance` IsOpen := fun i => by rw [e₂]; exact PresheafedSpace.IsOpenImmersion.comp _ _ } @@ -168,16 +168,16 @@ def OpenCover.pullbackCover {X W : Scheme.{u}} (𝒰 : X.OpenCover) (f : W ⟶ X W.OpenCover where J := 𝒰.J obj x := pullback f (𝒰.map x) - map x := pullback.fst _ _ - f x := 𝒰.f (f.1.base x) + map _ := pullback.fst _ _ + f x := 𝒰.f (f.base x) covers x := by rw [← - show _ = (pullback.fst _ _ : pullback f (𝒰.map (𝒰.f (f.1.base x))) ⟶ _).1.base from - PreservesPullback.iso_hom_fst Scheme.forgetToTop f (𝒰.map (𝒰.f (f.1.base x)))] + show _ = (pullback.fst _ _ : pullback f (𝒰.map (𝒰.f (f.base x))) ⟶ _).base from + PreservesPullback.iso_hom_fst Scheme.forgetToTop f (𝒰.map (𝒰.f (f.base x)))] -- Porting note: `rw` to `erw` on this single lemma rw [TopCat.coe_comp, Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ, TopCat.pullback_fst_range] - · obtain ⟨y, h⟩ := 𝒰.covers (f.1.base x) + · obtain ⟨y, h⟩ := 𝒰.covers (f.base x) exact ⟨y, h.symm⟩ · rw [← TopCat.epi_iff_surjective]; infer_instance @@ -198,16 +198,16 @@ def OpenCover.pullbackCover' {X W : Scheme.{u}} (𝒰 : X.OpenCover) (f : W ⟶ W.OpenCover where J := 𝒰.J obj x := pullback (𝒰.map x) f - map x := pullback.snd _ _ - f x := 𝒰.f (f.1.base x) + map _ := pullback.snd _ _ + f x := 𝒰.f (f.base x) covers x := by rw [← - show _ = (pullback.snd (𝒰.map (𝒰.f (f.1.base x))) f).1.base from - PreservesPullback.iso_hom_snd Scheme.forgetToTop (𝒰.map (𝒰.f (f.1.base x))) f] + show _ = (pullback.snd (𝒰.map (𝒰.f (f.base x))) f).base from + PreservesPullback.iso_hom_snd Scheme.forgetToTop (𝒰.map (𝒰.f (f.base x))) f] -- Porting note: `rw` to `erw` on this single lemma rw [TopCat.coe_comp, Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ, TopCat.pullback_snd_range] - · obtain ⟨y, h⟩ := 𝒰.covers (f.1.base x) + · obtain ⟨y, h⟩ := 𝒰.covers (f.base x) exact ⟨y, h⟩ · rw [← TopCat.epi_iff_surjective]; infer_instance @@ -217,10 +217,10 @@ def OpenCover.pullbackCover' {X W : Scheme.{u}} (𝒰 : X.OpenCover) (f : W ⟶ def OpenCover.finiteSubcover {X : Scheme.{u}} (𝒰 : OpenCover X) [H : CompactSpace X] : OpenCover X := by have := - @CompactSpace.elim_nhds_subcover _ _ H (fun x : X => Set.range (𝒰.map (𝒰.f x)).1.base) + @CompactSpace.elim_nhds_subcover _ _ H (fun x : X => Set.range (𝒰.map (𝒰.f x)).base) fun x => (IsOpenImmersion.isOpen_range (𝒰.map (𝒰.f x))).mem_nhds (𝒰.covers x) let t := this.choose - have h : ∀ x : X, ∃ y : t, x ∈ Set.range (𝒰.map (𝒰.f y)).1.base := by + have h : ∀ x : X, ∃ y : t, x ∈ Set.range (𝒰.map (𝒰.f y)).base := by intro x have h' : x ∈ (⊤ : Set X) := trivial rw [← Classical.choose_spec this, Set.mem_iUnion] at h' @@ -248,8 +248,8 @@ theorem OpenCover.compactSpace {X : Scheme.{u}} (𝒰 : X.OpenCover) [Finite (TopCat.homeoOfIso (asIso (IsOpenImmersion.isoOfRangeEq (𝒰.map i) - (X.ofRestrict (Opens.openEmbedding ⟨_, (𝒰.IsOpen i).base_open.isOpen_range⟩)) - Subtype.range_coe.symm).hom.1.base)) + (X.ofRestrict (Opens.isOpenEmbedding ⟨_, (𝒰.IsOpen i).base_open.isOpen_range⟩)) + Subtype.range_coe.symm).hom.base)) /-- Given open covers `{ Uᵢ }` and `{ Uⱼ }`, we may form the open cover `{ Uᵢ ∩ Uⱼ }`. -/ def OpenCover.inter {X : Scheme.{u}} (𝒰₁ : Scheme.OpenCover.{v₁} X) @@ -261,7 +261,7 @@ def OpenCover.inter {X : Scheme.{u}} (𝒰₁ : Scheme.OpenCover.{v₁} X) covers x := by rw [IsOpenImmersion.range_pullback_to_base_of_left] exact ⟨𝒰₁.covers x, 𝒰₂.covers x⟩ - IsOpen x := inferInstance + IsOpen _ := inferInstance /-- An affine open cover of `X` consists of a family of open immersions into `X` from @@ -277,7 +277,7 @@ structure AffineOpenCover (X : Scheme.{u}) where /-- given a point of `x : X`, `f x` is the index of the subscheme which contains `x` -/ f : X → J /-- the subschemes covers `X` -/ - covers : ∀ x, x ∈ Set.range (map (f x)).1.base + covers : ∀ x, x ∈ Set.range (map (f x)).base /-- the embedding of subschemes are open immersions -/ IsOpen : ∀ x, IsOpenImmersion (map x) := by infer_instance @@ -372,13 +372,13 @@ attribute [instance] OpenCover.Hom.isOpen /-- The identity morphism in the category of open covers of a scheme. -/ def OpenCover.Hom.id {X : Scheme.{u}} (𝓤 : OpenCover.{v} X) : 𝓤.Hom 𝓤 where idx j := j - app j := 𝟙 _ + app _ := 𝟙 _ /-- The composition of two morphisms in the category of open covers of a scheme. -/ def OpenCover.Hom.comp {X : Scheme.{u}} {𝓤 𝓥 𝓦 : OpenCover.{v} X} (f : 𝓤.Hom 𝓥) (g : 𝓥.Hom 𝓦) : 𝓤.Hom 𝓦 where idx j := g.idx <| f.idx j - app j := f.app _ ≫ g.app _ + app _ := f.app _ ≫ g.app _ instance OpenCover.category {X : Scheme.{u}} : Category (OpenCover.{v} X) where Hom 𝓤 𝓥 := 𝓤.Hom 𝓥 @@ -462,7 +462,7 @@ def affineBasisCoverOfAffine (R : CommRingCat.{u}) : OpenCover (Spec R) where · exact trivial · -- Porting note: need more hand holding here because Lean knows that -- `CommRing.ofHom ...` is iso, but without `ofHom` Lean does not know what to do - change Epi (Spec.map (CommRingCat.ofHom (algebraMap _ _))).1.base + change Epi (Spec.map (CommRingCat.ofHom (algebraMap _ _))).base infer_instance IsOpen x := AlgebraicGeometry.Scheme.basic_open_isOpenImmersion x @@ -481,8 +481,8 @@ theorem affineBasisCover_obj (X : Scheme.{u}) (i : X.affineBasisCover.J) : theorem affineBasisCover_map_range (X : Scheme.{u}) (x : X) (r : (X.local_affine x).choose_spec.choose) : - Set.range (X.affineBasisCover.map ⟨x, r⟩).1.base = - (X.affineCover.map x).1.base '' (PrimeSpectrum.basicOpen r).1 := by + Set.range (X.affineBasisCover.map ⟨x, r⟩).base = + (X.affineCover.map x).base '' (PrimeSpectrum.basicOpen r).1 := by erw [coe_comp, Set.range_comp] -- Porting note: `congr` fails to see the goal is comparing image of the same function refine congr_arg (_ '' ·) ?_ @@ -491,19 +491,19 @@ theorem affineBasisCover_map_range (X : Scheme.{u}) (x : X) theorem affineBasisCover_is_basis (X : Scheme.{u}) : TopologicalSpace.IsTopologicalBasis {x : Set X | - ∃ a : X.affineBasisCover.J, x = Set.range (X.affineBasisCover.map a).1.base} := by + ∃ a : X.affineBasisCover.J, x = Set.range (X.affineBasisCover.map a).base} := by apply TopologicalSpace.isTopologicalBasis_of_isOpen_of_nhds · rintro _ ⟨a, rfl⟩ exact IsOpenImmersion.isOpen_range (X.affineBasisCover.map a) · rintro a U haU hU rcases X.affineCover.covers a with ⟨x, e⟩ - let U' := (X.affineCover.map (X.affineCover.f a)).1.base ⁻¹' U + let U' := (X.affineCover.map (X.affineCover.f a)).base ⁻¹' U have hxU' : x ∈ U' := by rw [← e] at haU; exact haU rcases PrimeSpectrum.isBasis_basic_opens.exists_subset_of_mem_open hxU' - ((X.affineCover.map (X.affineCover.f a)).1.base.continuous_toFun.isOpen_preimage _ + ((X.affineCover.map (X.affineCover.f a)).base.continuous_toFun.isOpen_preimage _ hU) with ⟨_, ⟨_, ⟨s, rfl⟩, rfl⟩, hxV, hVU⟩ - refine ⟨_, ⟨⟨_, s⟩, rfl⟩, ?_, ?_⟩ <;> erw [affineBasisCover_map_range] + refine ⟨_, ⟨⟨_, s⟩, rfl⟩, ?_, ?_⟩ <;> rw [affineBasisCover_map_range] · exact ⟨x, hxV, e⟩ · rw [Set.image_subset_iff]; exact hVU diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean index d3cc6dc2264fe..5a23dde317010 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean @@ -164,7 +164,6 @@ lemma irreducible_polynomial [IsDomain R] : Irreducible W.polynomial := by iterate 2 rw [degree_add_eq_right_of_degree_lt] <;> simp only [h] <;> decide iterate 2 rw [degree_add_eq_left_of_degree_lt] <;> simp only [h] <;> decide --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma evalEval_polynomial (x y : R) : W.polynomial.evalEval x y = y ^ 2 + W.a₁ * x * y + W.a₃ * y - (x ^ 3 + W.a₂ * x ^ 2 + W.a₄ * x + W.a₆) := by simp only [polynomial] @@ -183,7 +182,6 @@ lemma equation_iff' (x y : R) : W.Equation x y ↔ y ^ 2 + W.a₁ * x * y + W.a₃ * y - (x ^ 3 + W.a₂ * x ^ 2 + W.a₄ * x + W.a₆) = 0 := by rw [Equation, evalEval_polynomial] --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma equation_iff (x y : R) : W.Equation x y ↔ y ^ 2 + W.a₁ * x * y + W.a₃ * y = x ^ 3 + W.a₂ * x ^ 2 + W.a₄ * x + W.a₆ := by rw [equation_iff', sub_eq_zero] @@ -210,7 +208,6 @@ TODO: define this in terms of `Polynomial.derivative`. -/ noncomputable def polynomialX : R[X][Y] := C (C W.a₁) * Y - C (C 3 * X ^ 2 + C (2 * W.a₂) * X + C W.a₄) --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma evalEval_polynomialX (x y : R) : W.polynomialX.evalEval x y = W.a₁ * y - (3 * x ^ 2 + 2 * W.a₂ * x + W.a₄) := by simp only [polynomialX] @@ -226,7 +223,6 @@ TODO: define this in terms of `Polynomial.derivative`. -/ noncomputable def polynomialY : R[X][Y] := C (C 2) * Y + C (C W.a₁ * X + C W.a₃) --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma evalEval_polynomialY (x y : R) : W.polynomialY.evalEval x y = 2 * y + W.a₁ * x + W.a₃ := by simp only [polynomialY] @@ -256,7 +252,6 @@ lemma nonsingular_iff' (x y : R) : W.Nonsingular x y ↔ W.Equation x y ∧ (W.a₁ * y - (3 * x ^ 2 + 2 * W.a₂ * x + W.a₄) ≠ 0 ∨ 2 * y + W.a₁ * x + W.a₃ ≠ 0) := by rw [Nonsingular, equation_iff', evalEval_polynomialX, evalEval_polynomialY] --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma nonsingular_iff (x y : R) : W.Nonsingular x y ↔ W.Equation x y ∧ (W.a₁ * y ≠ 3 * x ^ 2 + 2 * W.a₂ * x + W.a₄ ∨ y ≠ -y - W.a₁ * x - W.a₃) := by rw [nonsingular_iff', sub_ne_zero, ← sub_ne_zero (a := y)] @@ -314,7 +309,6 @@ lemma negY_negY (x y : R) : W.negY x (W.negY x y) = y := by simp only [negY] ring1 --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma eval_negPolynomial (x y : R) : W.negPolynomial.evalEval x y = W.negY x y := by rw [negY, sub_sub, negPolynomial] eval_simp @@ -609,7 +603,6 @@ instance : Inhabited W.Point := instance : Zero W.Point := ⟨zero⟩ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma zero_def : (zero : W.Point) = 0 := rfl @@ -625,7 +618,6 @@ def neg : W.Point → W.Point instance : Neg W.Point := ⟨neg⟩ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma neg_def (P : W.Point) : P.neg = -P := rfl @@ -656,7 +648,6 @@ noncomputable def add : W.Point → W.Point → W.Point noncomputable instance instAddPoint : Add W.Point := ⟨add⟩ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma add_def (P Q : W.Point) : P.add Q = P + Q := rfl @@ -817,7 +808,6 @@ lemma baseChange_polynomial : (W.baseChange B).toAffine.polynomial = (W.baseChange A).toAffine.polynomial.map (mapRingHom f) := by rw [← map_polynomial, map_baseChange] -variable {g} in lemma baseChange_equation (hf : Function.Injective f) (x y : A) : (W.baseChange B).toAffine.Equation (f x) (f y) ↔ (W.baseChange A).toAffine.Equation x y := by erw [← map_equation _ hf, map_baseChange] diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean index 28d32c6a3fea5..d81a89407576b 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean @@ -213,7 +213,6 @@ section Ring /-! ### Ideals in the coordinate ring over a ring -/ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The class of the element $X - x$ in $R[W]$ for some $x \in R$. -/ noncomputable def XClass (x : R) : W.CoordinateRing := mk W <| C <| X - C x @@ -222,7 +221,6 @@ lemma XClass_ne_zero [Nontrivial R] (x : R) : XClass W x ≠ 0 := AdjoinRoot.mk_ne_zero_of_natDegree_lt W.monic_polynomial (C_ne_zero.mpr <| X_sub_C_ne_zero x) <| by rw [natDegree_polynomial, natDegree_C]; norm_num1 --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The class of the element $Y - y(X)$ in $R[W]$ for some $y(X) \in R[X]$. -/ noncomputable def YClass (y : R[X]) : W.CoordinateRing := mk W <| Y - C y @@ -235,17 +233,14 @@ lemma C_addPolynomial (x y L : R) : mk W (C <| W.addPolynomial x y L) = mk W ((Y - C (linePolynomial x y L)) * (W.negPolynomial - C (linePolynomial x y L))) := AdjoinRoot.mk_eq_mk.mpr ⟨1, by rw [W.C_addPolynomial, add_sub_cancel_left, mul_one]⟩ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The ideal $\langle X - x \rangle$ of $R[W]$ for some $x \in R$. -/ noncomputable def XIdeal (x : R) : Ideal W.CoordinateRing := span {XClass W x} --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The ideal $\langle Y - y(X) \rangle$ of $R[W]$ for some $y(X) \in R[X]$. -/ noncomputable def YIdeal (y : R[X]) : Ideal W.CoordinateRing := span {YClass W y} --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The ideal $\langle X - x, Y - y(X) \rangle$ of $R[W]$ for some $x \in R$ and $y(X) \in R[X]$. -/ noncomputable def XYIdeal (x : R) (y : R[X]) : Ideal W.CoordinateRing := span {XClass W x, YClass W y} @@ -387,7 +382,6 @@ lemma XYIdeal_mul_XYIdeal {x₁ x₂ y₁ y₂ : F} (h₁ : W.Equation x₁ y₁ C_simp ring1 --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The non-zero fractional ideal $\langle X - x, Y - y \rangle$ of $F(W)$ for some $x, y \in F$. -/ noncomputable def XYIdeal' {x y : F} (h : W.Nonsingular x y) : (FractionalIdeal W.CoordinateRing⁰ W.FunctionField)ˣ := @@ -518,7 +512,6 @@ noncomputable def toClass : W.Point →+ Additive (ClassGroup W.CoordinateRing) rw [add_of_imp h] exact (CoordinateRing.mk_XYIdeal'_mul_mk_XYIdeal' h₁ h₂ h).symm --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error lemma toClass_zero : toClass (0 : W.Point) = 0 := rfl diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/J.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/J.lean new file mode 100644 index 0000000000000..3a9bbae95d05d --- /dev/null +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/J.lean @@ -0,0 +1,350 @@ +/- +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.AlgebraicGeometry.EllipticCurve.NormalForms +import Mathlib.FieldTheory.IsSepClosed + +/-! + +# Further properties of j-invariants of elliptic curves + +This file states some further properties of j-invariants of elliptic curves. + +## 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 + over that field which change `E` into `E'`. + +-/ + +open WeierstrassCurve Polynomial + +variable {F : Type*} [Field F] [IsSepClosed F] + +namespace EllipticCurve + +variable (E E' : EllipticCurve F) + +section CharTwo + +variable [CharP F 2] + +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 + 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⟩ + ext + · simp_rw [variableChange_a₁, inv_one, Units.val_one, a₁_of_isCharTwoJNeZeroNF] + linear_combination s * CharP.cast_eq_zero F 2 + · simp_rw [variableChange_a₂, inv_one, Units.val_one, a₁_of_isCharTwoJNeZeroNF] + linear_combination -hs + E.a₂ * CharP.cast_eq_zero F 2 + · simp_rw [variableChange_a₃, inv_one, Units.val_one, a₃_of_isCharTwoJNeZeroNF] + ring1 + · simp_rw [variableChange_a₄, inv_one, Units.val_one, a₃_of_isCharTwoJNeZeroNF, + a₄_of_isCharTwoJNeZeroNF] + ring1 + · simp_rw [variableChange_a₆, inv_one, Units.val_one, heq] + ring1 + +private lemma exists_variableChange_of_char_two_of_j_eq_zero + [E.IsCharTwoJEqZeroNF] [E'.IsCharTwoJEqZeroNF] : + ∃ C : WeierstrassCurve.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 + rw [E'.coe_Δ', Δ_of_isCharTwoJEqZeroNF_of_char_two, pow_ne_zero_iff (Nat.succ_ne_zero _)] at ha₃' + haveI : NeZero (3 : F) := NeZero.mk <| by + rw [show (3 : F) = 1 by linear_combination CharP.cast_eq_zero F 2] + exact one_ne_zero + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₃ / E'.a₃) 3 + obtain ⟨s, hs⟩ := IsSepClosed.exists_root_C_mul_X_pow_add_C_mul_X_add_C' 2 4 + 1 _ (E.a₄ - u ^ 4 * E'.a₄) (by norm_num) (by norm_num) ha₃ + obtain ⟨t, ht⟩ := IsSepClosed.exists_root_C_mul_X_pow_add_C_mul_X_add_C' 2 2 + 1 _ (s ^ 6 + E.a₄ * s ^ 2 + E.a₆ - u ^ 6 * E'.a₆) (by norm_num) (by norm_num) ha₃ + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff three_ne_zero, hu, div_ne_zero_iff] + exact ⟨ha₃, ha₃'⟩ + use ⟨Units.mk0 u hu0, s ^ 2, s, t⟩ + ext + · simp_rw [variableChange_a₁, a₁_of_isCharTwoJEqZeroNF, + show (2 : F) = 0 from CharP.cast_eq_zero F 2] + ring1 + · simp_rw [variableChange_a₂, a₁_of_isCharTwoJEqZeroNF, a₂_of_isCharTwoJEqZeroNF, + show (3 : F) = 1 by linear_combination CharP.cast_eq_zero F 2] + ring1 + · simp_rw [variableChange_a₃, Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, + hu, a₁_of_isCharTwoJEqZeroNF, show (2 : F) = 0 from CharP.cast_eq_zero F 2] + field_simp + · field_simp [variableChange_a₄, a₁_of_isCharTwoJEqZeroNF, a₂_of_isCharTwoJEqZeroNF] + linear_combination hs + (s ^ 4 - s * t - E.a₃ * s) * CharP.cast_eq_zero F 2 + · field_simp [variableChange_a₄, a₁_of_isCharTwoJEqZeroNF, a₂_of_isCharTwoJEqZeroNF] + 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 + obtain ⟨C, _ | _⟩ := E.exists_variableChange_isCharTwoNF + · obtain ⟨C', _ | _⟩ := E'.exists_variableChange_isCharTwoNF + · simp_rw [← variableChange_j E C, ← variableChange_j E' C', + j_of_isCharTwoJNeZeroNF_of_char_two, one_div, inv_inj] at heq + 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] + · 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 + exact False.elim (h rfl) + · obtain ⟨C', _ | _⟩ := E'.exists_variableChange_isCharTwoNF + · 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 + exact False.elim (h rfl) + · obtain ⟨C'', hC⟩ := exists_variableChange_of_char_two_of_j_eq_zero + (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] + +end CharTwo + +section CharThree + +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 + 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 + obtain ⟨ha₂, ha₆⟩ := h + 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 + obtain ⟨ha₂', ha₆'⟩ := h + haveI : NeZero (2 : F) := NeZero.mk <| by + rw [show (2 : F) = -1 by linear_combination CharP.cast_eq_zero F 3, neg_ne_zero] + exact one_ne_zero + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₂ / E'.a₂) 2 + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff two_ne_zero, hu, div_ne_zero_iff] + exact ⟨ha₂, ha₂'⟩ + use ⟨Units.mk0 u hu0, 0, 0, 0⟩ + ext + · simp_rw [variableChange_a₁, a₁_of_isCharThreeJNeZeroNF] + ring1 + · simp_rw [variableChange_a₂, a₁_of_isCharThreeJNeZeroNF, Units.val_inv_eq_inv_val, + Units.val_mk0, inv_pow, inv_mul_eq_div, hu] + field_simp + · simp_rw [variableChange_a₃, a₁_of_isCharThreeJNeZeroNF, a₃_of_isCharThreeJNeZeroNF] + ring1 + · simp_rw [variableChange_a₄, a₁_of_isCharThreeJNeZeroNF, a₃_of_isCharThreeJNeZeroNF, + a₄_of_isCharThreeJNeZeroNF] + ring1 + · simp_rw [j_of_isCharThreeJNeZeroNF_of_char_three, div_eq_div_iff ha₆ ha₆'] at heq + simp_rw [variableChange_a₆, a₁_of_isCharThreeJNeZeroNF, a₃_of_isCharThreeJNeZeroNF, + a₄_of_isCharThreeJNeZeroNF, Units.val_inv_eq_inv_val, Units.val_mk0, + inv_pow, inv_mul_eq_div, pow_mul u 2 3, hu] + field_simp + linear_combination heq + +private lemma exists_variableChange_of_char_three_of_j_eq_zero + [E.IsShortNF] [E'.IsShortNF] : + ∃ C : WeierstrassCurve.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 + rw [E'.coe_Δ', Δ_of_isShortNF_of_char_three, neg_ne_zero, pow_ne_zero_iff three_ne_zero] at ha₄' + haveI : NeZero (4 : F) := NeZero.mk <| by + rw [show (4 : F) = 1 by linear_combination CharP.cast_eq_zero F 3] + exact one_ne_zero + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₄ / E'.a₄) 4 + obtain ⟨r, hr⟩ := IsSepClosed.exists_root_C_mul_X_pow_add_C_mul_X_add_C' 3 3 + 1 _ (E.a₆ - u ^ 6 * E'.a₆) (by norm_num) (by norm_num) ha₄ + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff four_ne_zero, hu, div_ne_zero_iff] + exact ⟨ha₄, ha₄'⟩ + use ⟨Units.mk0 u hu0, r, 0, 0⟩ + ext + · simp_rw [variableChange_a₁, a₁_of_isShortNF] + ring1 + · simp_rw [variableChange_a₂, a₁_of_isShortNF, a₂_of_isShortNF, + show (3 : F) = 0 from CharP.cast_eq_zero F 3] + ring1 + · simp_rw [variableChange_a₃, a₁_of_isShortNF, a₃_of_isShortNF] + ring1 + · simp_rw [variableChange_a₄, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, hu, + show (3 : F) = 0 from CharP.cast_eq_zero F 3] + field_simp + · simp_rw [variableChange_a₆, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div] + field_simp + linear_combination hr + +private lemma exists_variableChange_of_char_three (heq : E.j = E'.j) : + ∃ C : WeierstrassCurve.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] + · 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) + · obtain ⟨C', _ | _⟩ := E'.exists_variableChange_isCharThreeNF + · 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) + · obtain ⟨C'', hC⟩ := exists_variableChange_of_char_three_of_j_eq_zero + (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] + +end CharThree + +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 + 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 + haveI : NeZero (4 : F) := NeZero.mk <| by + have := pow_ne_zero 2 hchar2 + norm_num1 at this + exact this + haveI : NeZero (6 : F) := NeZero.mk <| by + have := mul_ne_zero hchar2 hchar3 + norm_num1 at this + exact this + letI : Invertible (2 : F) := invertibleOfNonzero hchar2 + letI : Invertible (3 : F) := invertibleOfNonzero hchar3 + wlog _ : E.IsShortNF generalizing E + · obtain ⟨C, hE⟩ := E.exists_variableChange_isShortNF + rw [← variableChange_j E C] at heq + obtain ⟨C', hC⟩ := this _ heq hE + exact ⟨C'.comp C, by rwa [variableChange_comp]⟩ + wlog _ : E'.IsShortNF generalizing E' + · obtain ⟨C, hE'⟩ := E'.exists_variableChange_isShortNF + 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]⟩ + 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 + letI : Invertible (47775744 : F) := invertibleOfNonzero <| by + have := mul_ne_zero (pow_ne_zero 16 hchar2) (pow_ne_zero 6 hchar3) + norm_num1 at this + exact this + rw [← mul_right_inj_of_invertible (47775744 : F)] + linear_combination heq + by_cases ha₄ : E.a₄ = 0 + · have ha₆ := E.Δ'.ne_zero + rw [coe_Δ', Δ_of_isShortNF, ha₄, zero_pow three_ne_zero, mul_zero, zero_add, ← mul_assoc, + mul_ne_zero_iff, pow_ne_zero_iff two_ne_zero] at ha₆ + replace ha₆ := ha₆.2 + have ha₄' : E'.a₄ = 0 := by + rw [ha₄, zero_pow three_ne_zero, zero_mul, zero_eq_mul] at heq + exact (pow_eq_zero_iff three_ne_zero).1 <| heq.resolve_right <| pow_ne_zero 2 ha₆ + have ha₆' := E'.Δ'.ne_zero + rw [coe_Δ', Δ_of_isShortNF, ha₄', zero_pow three_ne_zero, mul_zero, zero_add, ← mul_assoc, + mul_ne_zero_iff, pow_ne_zero_iff two_ne_zero] at ha₆' + replace ha₆' := ha₆'.2 + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₆ / E'.a₆) 6 + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff (Nat.succ_ne_zero 5), hu, div_ne_zero_iff] + exact ⟨ha₆, ha₆'⟩ + use ⟨Units.mk0 u hu0, 0, 0, 0⟩ + ext + · simp + · simp + · simp + · simp [ha₄, ha₄'] + · simp_rw [variableChange_a₆, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + ha₄, Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, hu] + field_simp + by_cases ha₆ : E.a₆ = 0 + · have ha₄ := E.Δ'.ne_zero + rw [coe_Δ', Δ_of_isShortNF, ha₆, zero_pow two_ne_zero, mul_zero, add_zero, ← mul_assoc, + mul_ne_zero_iff, pow_ne_zero_iff three_ne_zero] at ha₄ + replace ha₄ := ha₄.2 + have ha₆' : E'.a₆ = 0 := by + rw [ha₆, zero_pow two_ne_zero, mul_zero, mul_eq_zero] at heq + exact (pow_eq_zero_iff two_ne_zero).1 <| heq.resolve_left <| pow_ne_zero 3 ha₄ + have ha₄' := E'.Δ'.ne_zero + rw [coe_Δ', Δ_of_isShortNF, ha₆', zero_pow two_ne_zero, mul_zero, add_zero, ← mul_assoc, + mul_ne_zero_iff, pow_ne_zero_iff three_ne_zero] at ha₄' + replace ha₄' := ha₄'.2 + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₄ / E'.a₄) 4 + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff four_ne_zero, hu, div_ne_zero_iff] + exact ⟨ha₄, ha₄'⟩ + use ⟨Units.mk0 u hu0, 0, 0, 0⟩ + ext + · simp + · simp + · simp + · simp_rw [variableChange_a₄, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, hu] + field_simp + · simp [ha₆, ha₆'] + have ha₄' : E'.a₄ ≠ 0 := fun h ↦ by + rw [h, zero_pow three_ne_zero, zero_mul, mul_eq_zero, + pow_eq_zero_iff two_ne_zero, pow_eq_zero_iff three_ne_zero] at heq + simpa [E'.coe_Δ', Δ_of_isShortNF, h, heq.resolve_left ha₄] using E'.Δ'.ne_zero + have ha₆' : E'.a₆ ≠ 0 := fun h ↦ by + rw [h, zero_pow two_ne_zero, mul_zero, zero_eq_mul, + pow_eq_zero_iff two_ne_zero, pow_eq_zero_iff three_ne_zero] at heq + tauto + obtain ⟨u, hu⟩ := IsSepClosed.exists_pow_nat_eq (E.a₆ / E'.a₆ / (E.a₄ / E'.a₄)) 2 + have hu4 : u ^ 4 = E.a₄ / E'.a₄ := by + rw [pow_mul u 2 2, hu] + field_simp + linear_combination -heq + have hu6 : u ^ 6 = E.a₆ / E'.a₆ := by + rw [pow_mul u 2 3, hu] + field_simp + linear_combination -E.a₆ * E'.a₆ * heq + have hu0 : u ≠ 0 := by + rw [← pow_ne_zero_iff four_ne_zero, hu4, div_ne_zero_iff] + exact ⟨ha₄, ha₄'⟩ + use ⟨Units.mk0 u hu0, 0, 0, 0⟩ + ext + · simp + · simp + · simp + · simp_rw [variableChange_a₄, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, hu4] + field_simp + · simp_rw [variableChange_a₆, a₁_of_isShortNF, a₂_of_isShortNF, a₃_of_isShortNF, + Units.val_inv_eq_inv_val, Units.val_mk0, inv_pow, inv_mul_eq_div, hu6] + field_simp + +end CharNeTwoOrThree + +/-- If there are two 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 +one curve into another. -/ +theorem exists_variableChange_of_j_eq (heq : E.j = E'.j) : + ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + obtain ⟨p, _⟩ := CharP.exists F + by_cases hchar2 : p = 2 + · subst hchar2 + exact exists_variableChange_of_char_two _ _ heq + by_cases hchar3 : p = 3 + · subst hchar3 + exact exists_variableChange_of_char_three _ _ heq + exact exists_variableChange_of_char_ne_two_or_three _ _ hchar2 hchar3 heq + +end EllipticCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean index d0976e216dd81..e4838de2f5dd0 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean @@ -1169,7 +1169,7 @@ lemma add_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.add P Q = W'.dblXYZ P lemma add_smul_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) {u v : R} (hu : IsUnit u) (hv : IsUnit v) : W'.add (u • P) (v • Q) = u ^ 4 • W'.add P Q := by have smul : P ≈ Q ↔ u • P ≈ v • Q := by - erw [← Quotient.eq, ← Quotient.eq, smul_eq P hu, smul_eq Q hv] + erw [← Quotient.eq_iff_equiv, ← Quotient.eq_iff_equiv, smul_eq P hu, smul_eq Q hv] rfl rw [add_of_equiv <| smul.mp h, dblXYZ_smul, add_of_equiv h] @@ -1185,7 +1185,7 @@ lemma add_of_not_equiv {P Q : Fin 3 → R} (h : ¬P ≈ Q) : W'.add P Q = W'.add lemma add_smul_of_not_equiv {P Q : Fin 3 → R} (h : ¬P ≈ Q) {u v : R} (hu : IsUnit u) (hv : IsUnit v) : W'.add (u • P) (v • Q) = (u * v) ^ 2 • W'.add P Q := by have smul : P ≈ Q ↔ u • P ≈ v • Q := by - erw [← Quotient.eq, ← Quotient.eq, smul_eq P hu, smul_eq Q hv] + erw [← Quotient.eq_iff_equiv, ← Quotient.eq_iff_equiv, smul_eq P hu, smul_eq Q hv] rfl rw [add_of_not_equiv <| h.comp smul.mpr, addXYZ_smul, add_of_not_equiv h] diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean index 4cd462e78f355..23a9a69744985 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean @@ -156,7 +156,7 @@ end Quantity section VariableChange -variable [Invertible (2 : R)] +variable (E : EllipticCurve R) [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,6 +170,14 @@ 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 -/ @@ -258,7 +266,7 @@ end Quantity section VariableChange -variable [Invertible (2 : R)] [Invertible (3 : R)] +variable (E : EllipticCurve R) [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. @@ -274,6 +282,13 @@ 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 -/ @@ -405,6 +420,10 @@ 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, @@ -436,6 +455,14 @@ 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₂ @@ -447,6 +474,14 @@ 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 -/ @@ -663,6 +698,10 @@ 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, @@ -680,16 +719,18 @@ 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 -variable [DecidableEq F] +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 $Y^2 + a_3Y = X^3 + a_4X + a_6$ (`WeierstrassCurve.IsCharTwoJEqZeroNF`). -/ -def toCharTwoNF : VariableChange F := +def toCharTwoNF [DecidableEq F] : VariableChange F := if ha₁ : W.a₁ = 0 then W.toCharTwoJEqZeroNF else W.toCharTwoJNeZeroNF ha₁ -instance toCharTwoNF_spec : (W.variableChange W.toCharTwoNF).IsCharTwoNF := by +instance toCharTwoNF_spec [DecidableEq F] : (W.variableChange W.toCharTwoNF).IsCharTwoNF := by by_cases ha₁ : W.a₁ = 0 · rw [toCharTwoNF, dif_pos ha₁] haveI := W.toCharTwoJEqZeroNF_spec ha₁ @@ -699,8 +740,18 @@ instance toCharTwoNF_spec : (W.variableChange W.toCharTwoNF).IsCharTwoNF := by infer_instance theorem exists_variableChange_isCharTwoNF : - ∃ C : VariableChange F, (W.variableChange C).IsCharTwoNF := - ⟨_, W.toCharTwoNF_spec⟩ + ∃ C : VariableChange F, (W.variableChange C).IsCharTwoNF := by + 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 diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean index 3d4ea8337acc9..00a1a91f99235 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean @@ -14,7 +14,8 @@ import Mathlib.Tactic.LinearCombination' This file defines the type of points on a Weierstrass curve as a tuple, consisting of an equivalence class of triples up to scaling by a unit, satisfying a Weierstrass equation with a nonsingular -condition. +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. ## Mathematical background @@ -32,6 +33,7 @@ given by a tuple consisting of $[x:y:z]$ and the nonsingular condition on any re As in `Mathlib.AlgebraicGeometry.EllipticCurve.Affine`, the set of nonsingular rational points forms an abelian group under the same secant-and-tangent process, but the polynomials involved are homogeneous, and any instances of division become multiplication in the $Z$-coordinate. +Note that most computational proofs follow from their analogous proofs for affine coordinates. ## Main definitions @@ -39,10 +41,16 @@ homogeneous, and any instances of division become multiplication in the $Z$-coor * `WeierstrassCurve.Projective.toAffine`: the Weierstrass curve in affine coordinates. * `WeierstrassCurve.Projective.Nonsingular`: the nonsingular condition on a point representative. * `WeierstrassCurve.Projective.NonsingularLift`: the nonsingular condition on a point class. + * `WeierstrassCurve.Projective.neg`: the negation operation on a point representative. + * `WeierstrassCurve.Projective.negMap`: the negation operation on a point class. + * `WeierstrassCurve.Projective.add`: the addition operation on a point representative. + * `WeierstrassCurve.Projective.addMap`: the addition operation on a point class. ## Main statements * `WeierstrassCurve.Projective.polynomial_relation`: Euler's homogeneous function theorem. + * `WeierstrassCurve.Projective.nonsingular_neg`: negation preserves the nonsingular condition. + * `WeierstrassCurve.Projective.nonsingular_add`: addition preserves the nonsingular condition. ## Implementation notes @@ -138,6 +146,11 @@ lemma smul_equiv (P : Fin 3 → R) {u : R} (hu : IsUnit u) : u • P ≈ P := lemma smul_eq (P : Fin 3 → R) {u : R} (hu : IsUnit u) : (⟦u • P⟧ : PointClass R) = ⟦P⟧ := Quotient.eq.mpr <| smul_equiv P hu +lemma smul_equiv_smul (P Q : Fin 3 → R) {u v : R} (hu : IsUnit u) (hv : IsUnit v) : + u • P ≈ v • Q ↔ P ≈ Q := by + erw [← Quotient.eq_iff_equiv, ← Quotient.eq_iff_equiv, smul_eq P hu, smul_eq Q hv] + rfl + variable (W') in /-- The coercion to a Weierstrass curve in affine coordinates. -/ abbrev toAffine : Affine R := @@ -1163,4 +1176,271 @@ lemma addXYZ_of_Z_ne_zero {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equati end Addition +section Negation + +/-! ### Negation on point representatives -/ + +variable (W') in +/-- The negation of a point representative. -/ +def neg (P : Fin 3 → R) : Fin 3 → R := + ![P x, W'.negY P, P z] + +lemma neg_X (P : Fin 3 → R) : W'.neg P x = P x := + rfl + +lemma neg_Y (P : Fin 3 → R) : W'.neg P y = W'.negY P := + rfl + +lemma neg_Z (P : Fin 3 → R) : W'.neg P z = P z := + rfl + +lemma neg_smul (P : Fin 3 → R) (u : R) : W'.neg (u • P) = u • W'.neg P := by + simpa only [neg, negY_smul] using (smul_fin3 (W'.neg P) u).symm + +lemma neg_smul_equiv (P : Fin 3 → R) {u : R} (hu : IsUnit u) : W'.neg (u • P) ≈ W'.neg P := + ⟨hu.unit, (neg_smul ..).symm⟩ + +lemma neg_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.neg P ≈ W'.neg Q := by + rcases h with ⟨u, rfl⟩ + exact neg_smul_equiv Q u.isUnit + +lemma neg_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) (hPz : P z = 0) : + W'.neg P = -P y • ![0, 1, 0] := by + erw [neg, X_eq_zero_of_Z_eq_zero hP hPz, negY_of_Z_eq_zero hP hPz, hPz, smul_fin3, mul_zero, + mul_one] + +lemma neg_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + W.neg P = P z • ![P x / P z, W.toAffine.negY (P x / P z) (P y / P z), 1] := by + erw [neg, smul_fin3, mul_div_cancel₀ _ hPz, ← negY_of_Z_ne_zero hPz, mul_div_cancel₀ _ hPz, + mul_one] + +private lemma nonsingular_neg_of_Z_ne_zero {P : Fin 3 → F} (hP : W.Nonsingular P) (hPz : P z ≠ 0) : + W.Nonsingular ![P x / P z, W.toAffine.negY (P x / P z) (P y / P z), 1] := + (nonsingular_some ..).mpr <| Affine.nonsingular_neg <| (nonsingular_of_Z_ne_zero hPz).mp hP + +lemma nonsingular_neg {P : Fin 3 → F} (hP : W.Nonsingular P) : W.Nonsingular <| W.neg P := by + by_cases hPz : P z = 0 + · simp only [neg_of_Z_eq_zero hP.left hPz, nonsingular_smul _ (isUnit_Y_of_Z_eq_zero hP hPz).neg, + nonsingular_zero] + · simp only [neg_of_Z_ne_zero hPz, nonsingular_smul _ <| Ne.isUnit hPz, + nonsingular_neg_of_Z_ne_zero hP hPz] + +lemma addZ_neg (P : Fin 3 → R) : W'.addZ P (W'.neg P) = 0 := by + rw [addZ, neg_X, neg_Y, neg_Z, negY] + ring1 + +lemma addX_neg (P : Fin 3 → R) : W'.addX P (W'.neg P) = 0 := by + rw [addX, neg_X, neg_Y, neg_Z, negY] + ring1 + +lemma negAddY_neg {P : Fin 3 → R} (hP : W'.Equation P) : W'.negAddY P (W'.neg P) = W'.dblZ P := by + linear_combination (norm := (rw [negAddY, neg_X, neg_Y, neg_Z, dblZ, negY]; ring1)) + -3 * (P y - W'.negY P) * (equation_iff _).mp hP + +lemma addY_neg {P : Fin 3 → R} (hP : W'.Equation P) : W'.addY P (W'.neg P) = -W'.dblZ P := by + rw [addY, negY_eq, addX_neg, negAddY_neg hP, addZ_neg, mul_zero, sub_zero, mul_zero, sub_zero] + +lemma addXYZ_neg {P : Fin 3 → R} (hP : W'.Equation P) : + W'.addXYZ P (W'.neg P) = -W'.dblZ P • ![0, 1, 0] := by + erw [addXYZ, addX_neg, addY_neg hP, addZ_neg, smul_fin3, mul_zero, mul_one] + +variable (W') in +/-- The negation of a point class. If `P` is a point representative, +then `W'.negMap ⟦P⟧` is definitionally equivalent to `W'.neg P`. -/ +def negMap (P : PointClass R) : PointClass R := + P.map W'.neg fun _ _ => neg_equiv + +lemma negMap_eq (P : Fin 3 → R) : W'.negMap ⟦P⟧ = ⟦W'.neg P⟧ := + rfl + +lemma negMap_of_Z_eq_zero {P : Fin 3 → F} (hP : W.Nonsingular P) (hPz : P z = 0) : + W.negMap ⟦P⟧ = ⟦![0, 1, 0]⟧ := by + rw [negMap_eq, neg_of_Z_eq_zero hP.left hPz, smul_eq _ (isUnit_Y_of_Z_eq_zero hP hPz).neg] + +lemma negMap_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + W.negMap ⟦P⟧ = ⟦![P x / P z, W.toAffine.negY (P x / P z) (P y / P z), 1]⟧ := by + rw [negMap_eq, neg_of_Z_ne_zero hPz, smul_eq _ <| Ne.isUnit hPz] + +lemma nonsingularLift_negMap {P : PointClass F} (hP : W.NonsingularLift P) : + W.NonsingularLift <| W.negMap P := by + rcases P with ⟨_⟩ + exact nonsingular_neg hP + +end Negation + +section Addition + +/-! ### Addition on point representatives -/ + +open Classical in +variable (W') in +/-- The addition of two point representatives. -/ +noncomputable def add (P Q : Fin 3 → R) : Fin 3 → R := + if P ≈ Q then W'.dblXYZ P else W'.addXYZ P Q + +lemma add_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.add P Q = W'.dblXYZ P := + if_pos h + +lemma add_smul_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) {u v : R} (hu : IsUnit u) (hv : IsUnit v) : + W'.add (u • P) (v • Q) = u ^ 4 • W'.add P Q := by + rw [add_of_equiv <| (smul_equiv_smul P Q hu hv).mpr h, dblXYZ_smul, add_of_equiv h] + +lemma add_self (P : Fin 3 → R) : W'.add P P = W'.dblXYZ P := + add_of_equiv <| Setoid.refl _ + +lemma add_of_eq {P Q : Fin 3 → R} (h : P = Q) : W'.add P Q = W'.dblXYZ P := + h ▸ add_self P + +lemma add_of_not_equiv {P Q : Fin 3 → R} (h : ¬P ≈ Q) : W'.add P Q = W'.addXYZ P Q := + if_neg h + +lemma add_smul_of_not_equiv {P Q : Fin 3 → R} (h : ¬P ≈ Q) {u v : R} (hu : IsUnit u) + (hv : IsUnit v) : W'.add (u • P) (v • Q) = (u * v) ^ 2 • W'.add P Q := by + rw [add_of_not_equiv <| h.comp (smul_equiv_smul P Q hu hv).mp, addXYZ_smul, add_of_not_equiv h] + +lemma add_smul_equiv (P Q : Fin 3 → R) {u v : R} (hu : IsUnit u) (hv : IsUnit v) : + W'.add (u • P) (v • Q) ≈ W'.add P Q := by + by_cases h : P ≈ Q + · exact ⟨hu.unit ^ 4, by convert (add_smul_of_equiv h hu hv).symm⟩ + · exact ⟨(hu.unit * hv.unit) ^ 2, by convert (add_smul_of_not_equiv h hu hv).symm⟩ + +lemma add_equiv {P P' Q Q' : Fin 3 → R} (hP : P ≈ P') (hQ : Q ≈ Q') : + W'.add P Q ≈ W'.add P' Q' := by + rcases hP, hQ with ⟨⟨u, rfl⟩, ⟨v, rfl⟩⟩ + exact add_smul_equiv P' Q' u.isUnit v.isUnit + +lemma add_of_Z_eq_zero {P Q : Fin 3 → F} (hP : W.Nonsingular P) (hQ : W.Nonsingular Q) + (hPz : P z = 0) (hQz : Q z = 0) : W.add P Q = P y ^ 4 • ![0, 1, 0] := by + rw [add, if_pos <| equiv_of_Z_eq_zero hP hQ hPz hQz, dblXYZ_of_Z_eq_zero hP.left hPz] + +lemma add_of_Z_eq_zero_left [NoZeroDivisors R] {P Q : Fin 3 → R} (hP : W'.Equation P) + (hPz : P z = 0) (hQz : Q z ≠ 0) : W'.add P Q = (P y ^ 2 * Q z) • Q := by + rw [add, if_neg <| not_equiv_of_Z_eq_zero_left hPz hQz, addXYZ_of_Z_eq_zero_left hP hPz] + +lemma add_of_Z_eq_zero_right [NoZeroDivisors R] {P Q : Fin 3 → R} (hQ : W'.Equation Q) + (hPz : P z ≠ 0) (hQz : Q z = 0) : W'.add P Q = -(Q y ^ 2 * P z) • P := by + rw [add, if_neg <| not_equiv_of_Z_eq_zero_right hPz hQz, addXYZ_of_Z_eq_zero_right hQ hQz] + +lemma add_of_Y_eq {P Q : Fin 3 → F} (hP : W.Equation P) (hPz : P z ≠ 0) (hQz : Q z ≠ 0) + (hx : P x * Q z = Q x * P z) (hy : P y * Q z = Q y * P z) (hy' : P y * Q z = W.negY Q * P z) : + W.add P Q = W.dblU P • ![0, 1, 0] := by + rw [add, if_pos <| equiv_of_X_eq_of_Y_eq hPz hQz hx hy, dblXYZ_of_Y_eq hP hPz hQz hx hy hy'] + +lemma add_of_Y_ne {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0) + (hQz : Q z ≠ 0) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ Q y * P z) : + W.add P Q = addU P Q • ![0, 1, 0] := by + rw [add, if_neg <| not_equiv_of_Y_ne hy, addXYZ_of_X_eq hP hQ hPz hQz hx] + +lemma add_of_Y_ne' {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0) + (hQz : Q z ≠ 0) (hx : P x * Q z = Q x * P z) (hy : P y * Q z ≠ W.negY Q * P z) : + W.add P Q = W.dblZ P • + ![W.toAffine.addX (P x / P z) (Q x / Q z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), + W.toAffine.addY (P x / P z) (Q x / Q z) (P y / P z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), 1] := by + rw [add, if_pos <| equiv_of_X_eq_of_Y_eq hPz hQz hx <| Y_eq_of_Y_ne' hP hQ hPz hQz hx hy, + dblXYZ_of_Z_ne_zero hP hQ hPz hQz hx hy] + +lemma add_of_X_ne {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0) + (hQz : Q z ≠ 0) (hx : P x * Q z ≠ Q x * P z) : W.add P Q = W.addZ P Q • + ![W.toAffine.addX (P x / P z) (Q x / Q z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), + W.toAffine.addY (P x / P z) (Q x / Q z) (P y / P z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), 1] := by + rw [add, if_neg <| not_equiv_of_X_ne hx, addXYZ_of_Z_ne_zero hP hQ hPz hQz hx] + +private lemma nonsingular_add_of_Z_ne_zero {P Q : Fin 3 → F} (hP : W.Nonsingular P) + (hQ : W.Nonsingular Q) (hPz : P z ≠ 0) (hQz : Q z ≠ 0) + (hxy : P x * Q z = Q x * P z → P y * Q z ≠ W.negY Q * P z) : W.Nonsingular + ![W.toAffine.addX (P x / P z) (Q x / Q z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), + W.toAffine.addY (P x / P z) (Q x / Q z) (P y / P z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), 1] := + (nonsingular_some ..).mpr <| Affine.nonsingular_add ((nonsingular_of_Z_ne_zero hPz).mp hP) + ((nonsingular_of_Z_ne_zero hQz).mp hQ) (by rwa [← X_eq_iff hPz hQz, ne_eq, ← Y_eq_iff' hPz hQz]) + +lemma nonsingular_add {P Q : Fin 3 → F} (hP : W.Nonsingular P) (hQ : W.Nonsingular Q) : + W.Nonsingular <| W.add P Q := by + by_cases hPz : P z = 0 + · by_cases hQz : Q z = 0 + · simp only [add_of_Z_eq_zero hP hQ hPz hQz, + nonsingular_smul _ <| (isUnit_Y_of_Z_eq_zero hP hPz).pow 4, nonsingular_zero] + · simpa only [add_of_Z_eq_zero_left hP.left hPz hQz, + nonsingular_smul _ <| ((isUnit_Y_of_Z_eq_zero hP hPz).pow 2).mul <| Ne.isUnit hQz] + · by_cases hQz : Q z = 0 + · simpa only [add_of_Z_eq_zero_right hQ.left hPz hQz, + nonsingular_smul _ (((isUnit_Y_of_Z_eq_zero hQ hQz).pow 2).mul <| Ne.isUnit hPz).neg] + · by_cases hxy : P x * Q z = Q x * P z → P y * Q z ≠ W.negY Q * P z + · by_cases hx : P x * Q z = Q x * P z + · simp only [add_of_Y_ne' hP.left hQ.left hPz hQz hx <| hxy hx, + nonsingular_smul _ <| isUnit_dblZ_of_Y_ne' hP.left hQ.left hPz hQz hx <| hxy hx, + nonsingular_add_of_Z_ne_zero hP hQ hPz hQz hxy] + · simp only [add_of_X_ne hP.left hQ.left hPz hQz hx, + nonsingular_smul _ <| isUnit_addZ_of_X_ne hP.left hQ.left hx, + nonsingular_add_of_Z_ne_zero hP hQ hPz hQz hxy] + · rw [_root_.not_imp, not_ne_iff] at hxy + by_cases hy : P y * Q z = Q y * P z + · simp only [add_of_Y_eq hP.left hPz hQz hxy.left hy hxy.right, nonsingular_smul _ <| + isUnit_dblU_of_Y_eq hP hPz hQz hxy.left hy hxy.right, nonsingular_zero] + · simp only [add_of_Y_ne hP.left hQ.left hPz hQz hxy.left hy, + nonsingular_smul _ <| isUnit_addU_of_Y_ne hPz hQz hy, nonsingular_zero] + +variable (W') in +/-- The addition of two point classes. If `P` is a point representative, +then `W.addMap ⟦P⟧ ⟦Q⟧` is definitionally equivalent to `W.add P Q`. -/ +noncomputable def addMap (P Q : PointClass R) : PointClass R := + Quotient.map₂ W'.add (fun _ _ hP _ _ hQ => add_equiv hP hQ) P Q + +lemma addMap_eq (P Q : Fin 3 → R) : W'.addMap ⟦P⟧ ⟦Q⟧ = ⟦W'.add P Q⟧ := + rfl + +lemma addMap_of_Z_eq_zero_left {P : Fin 3 → F} {Q : PointClass F} (hP : W.Nonsingular P) + (hQ : W.NonsingularLift Q) (hPz : P z = 0) : W.addMap ⟦P⟧ Q = Q := by + rcases Q with ⟨Q⟩ + by_cases hQz : Q z = 0 + · erw [addMap_eq, add_of_Z_eq_zero hP hQ hPz hQz, + smul_eq _ <| (isUnit_Y_of_Z_eq_zero hP hPz).pow 4, Quotient.eq] + exact Setoid.symm <| equiv_zero_of_Z_eq_zero hQ hQz + · erw [addMap_eq, add_of_Z_eq_zero_left hP.left hPz hQz, + smul_eq _ <| ((isUnit_Y_of_Z_eq_zero hP hPz).pow 2).mul <| Ne.isUnit hQz] + rfl + +lemma addMap_of_Z_eq_zero_right {P : PointClass F} {Q : Fin 3 → F} (hP : W.NonsingularLift P) + (hQ : W.Nonsingular Q) (hQz : Q z = 0) : W.addMap P ⟦Q⟧ = P := by + rcases P with ⟨P⟩ + by_cases hPz : P z = 0 + · erw [addMap_eq, add_of_Z_eq_zero hP hQ hPz hQz, + smul_eq _ <| (isUnit_Y_of_Z_eq_zero hP hPz).pow 4, Quotient.eq] + exact Setoid.symm <| equiv_zero_of_Z_eq_zero hP hPz + · erw [addMap_eq, add_of_Z_eq_zero_right hQ.left hPz hQz, + smul_eq _ (((isUnit_Y_of_Z_eq_zero hQ hQz).pow 2).mul <| Ne.isUnit hPz).neg] + rfl + +lemma addMap_of_Y_eq {P Q : Fin 3 → F} (hP : W.Nonsingular P) (hQ : W.Equation Q) (hPz : P z ≠ 0) + (hQz : Q z ≠ 0) (hx : P x * Q z = Q x * P z) (hy' : P y * Q z = W.negY Q * P z) : + W.addMap ⟦P⟧ ⟦Q⟧ = ⟦![0, 1, 0]⟧ := by + by_cases hy : P y * Q z = Q y * P z + · rw [addMap_eq, add_of_Y_eq hP.left hPz hQz hx hy hy', + smul_eq _ <| isUnit_dblU_of_Y_eq hP hPz hQz hx hy hy'] + · rw [addMap_eq, add_of_Y_ne hP.left hQ hPz hQz hx hy, + smul_eq _ <| isUnit_addU_of_Y_ne hPz hQz hy] + +lemma addMap_of_Z_ne_zero {P Q : Fin 3 → F} (hP : W.Equation P) (hQ : W.Equation Q) (hPz : P z ≠ 0) + (hQz : Q z ≠ 0) (hxy : P x * Q z = Q x * P z → P y * Q z ≠ W.negY Q * P z) : W.addMap ⟦P⟧ ⟦Q⟧ = + ⟦![W.toAffine.addX (P x / P z) (Q x / Q z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), + W.toAffine.addY (P x / P z) (Q x / Q z) (P y / P z) + (W.toAffine.slope (P x / P z) (Q x / Q z) (P y / P z) (Q y / Q z)), 1]⟧ := by + by_cases hx : P x * Q z = Q x * P z + · rw [addMap_eq, add_of_Y_ne' hP hQ hPz hQz hx <| hxy hx, + smul_eq _ <| isUnit_dblZ_of_Y_ne' hP hQ hPz hQz hx <| hxy hx] + · rw [addMap_eq, add_of_X_ne hP hQ hPz hQz hx, smul_eq _ <| isUnit_addZ_of_X_ne hP hQ hx] + +lemma nonsingularLift_addMap {P Q : PointClass F} (hP : W.NonsingularLift P) + (hQ : W.NonsingularLift Q) : W.NonsingularLift <| W.addMap P Q := by + rcases P; rcases Q + exact nonsingular_add hP hQ + +end Addition + end WeierstrassCurve.Projective diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean index 8f77cea60aaad..77ea4968688e9 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean @@ -61,7 +61,7 @@ structure VariableChange (R : Type u) [CommRing R] where namespace VariableChange -variable (C C' C'' : VariableChange R) +variable (C C' : VariableChange R) /-- The identity linear change of variables given by the identity matrix. -/ def id : VariableChange R := diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean index 87e3695c1b4d9..9d730cf3c9239 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean @@ -103,22 +103,18 @@ section Quantity /-! ### Standard quantities -/ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `b₂` coefficient of a Weierstrass curve. -/ def b₂ : R := W.a₁ ^ 2 + 4 * W.a₂ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `b₄` coefficient of a Weierstrass curve. -/ def b₄ : R := 2 * W.a₄ + W.a₁ * W.a₃ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `b₆` coefficient of a Weierstrass curve. -/ def b₆ : R := W.a₃ ^ 2 + 4 * W.a₆ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `b₈` coefficient of a Weierstrass curve. -/ def b₈ : R := W.a₁ ^ 2 * W.a₆ + 4 * W.a₂ * W.a₆ - W.a₁ * W.a₃ * W.a₄ + W.a₂ * W.a₃ ^ 2 - W.a₄ ^ 2 @@ -127,17 +123,14 @@ lemma b_relation : 4 * W.b₈ = W.b₂ * W.b₆ - W.b₄ ^ 2 := by simp only [b₂, b₄, b₆, b₈] ring1 --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `c₄` coefficient of a Weierstrass curve. -/ def c₄ : R := W.b₂ ^ 2 - 24 * W.b₄ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The `c₆` coefficient of a Weierstrass curve. -/ def c₆ : R := -W.b₂ ^ 3 + 36 * W.b₂ * W.b₄ - 216 * W.b₆ --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The discriminant `Δ` of a Weierstrass curve. If `R` is a field, then this polynomial vanishes if and only if the cubic curve cut out by this equation is singular. Sometimes only defined up to sign in the literature; we choose the sign used by the LMFDB. For more discussion, see @@ -438,7 +431,6 @@ theorem ext {x y : EllipticCurve R} (h₁ : x.a₁ = y.a₁) (h₂ : x.a₂ = y. variable (E : EllipticCurve R) --- Porting note (#10619): removed `@[simp]` to avoid a `simpNF` linter error /-- The j-invariant `j` of an elliptic curve, which is invariant under isomorphisms over `R`. -/ def j : R := E.Δ'⁻¹ * E.c₄ ^ 3 diff --git a/Mathlib/AlgebraicGeometry/FunctionField.lean b/Mathlib/AlgebraicGeometry/FunctionField.lean index da34fe72ff8b1..6833058adc17f 100644 --- a/Mathlib/AlgebraicGeometry/FunctionField.lean +++ b/Mathlib/AlgebraicGeometry/FunctionField.lean @@ -36,9 +36,9 @@ noncomputable abbrev Scheme.functionField [IrreducibleSpace X] : CommRingCat := /-- The restriction map from a component to the function field. -/ noncomputable abbrev Scheme.germToFunctionField [IrreducibleSpace X] (U : X.Opens) [h : Nonempty U] : Γ(X, U) ⟶ X.functionField := - X.presheaf.germ - ⟨genericPoint X, - ((genericPoint_spec X).mem_open_set_iff U.isOpen).mpr (by simpa using h)⟩ + X.presheaf.germ U + (genericPoint X) + (((genericPoint_spec X).mem_open_set_iff U.isOpen).mpr (by simpa using h)) noncomputable instance [IrreducibleSpace X] (U : X.Opens) [Nonempty U] : Algebra Γ(X, U) X.functionField := @@ -47,39 +47,39 @@ noncomputable instance [IrreducibleSpace X] (U : X.Opens) [Nonempty U] : noncomputable instance [IsIntegral X] : Field X.functionField := by refine .ofIsUnitOrEqZero fun a ↦ ?_ obtain ⟨U, m, s, rfl⟩ := TopCat.Presheaf.germ_exist _ _ a - rw [or_iff_not_imp_right, ← (X.presheaf.germ ⟨_, m⟩).map_zero] + rw [or_iff_not_imp_right, ← (X.presheaf.germ _ _ m).map_zero] intro ha replace ha := ne_of_apply_ne _ ha have hs : genericPoint X ∈ RingedSpace.basicOpen _ s := by - rw [← SetLike.mem_coe, (genericPoint_spec X).mem_open_set_iff, Set.top_eq_univ, + rw [← SetLike.mem_coe, (genericPoint_spec X).mem_open_set_iff, Set.univ_inter, Set.nonempty_iff_ne_empty, Ne, ← Opens.coe_bot, ← SetLike.ext'_iff] · erw [basicOpen_eq_bot_iff] exact ha · exact (RingedSpace.basicOpen _ _).isOpen - have := (X.presheaf.germ ⟨_, hs⟩).isUnit_map (RingedSpace.isUnit_res_basicOpen _ s) + have := (X.presheaf.germ _ _ hs).isUnit_map (RingedSpace.isUnit_res_basicOpen _ s) rwa [TopCat.Presheaf.germ_res_apply] at this -theorem germ_injective_of_isIntegral [IsIntegral X] {U : X.Opens} (x : U) : - Function.Injective (X.presheaf.germ x) := by +theorem germ_injective_of_isIntegral [IsIntegral X] {U : X.Opens} (x : X) (hx : x ∈ U) : + Function.Injective (X.presheaf.germ U x hx) := by rw [injective_iff_map_eq_zero] intro y hy - rw [← (X.presheaf.germ x).map_zero] at hy - obtain ⟨W, hW, iU, iV, e⟩ := X.presheaf.germ_eq _ x.prop x.prop _ _ hy + rw [← (X.presheaf.germ U x hx).map_zero] at hy + obtain ⟨W, hW, iU, iV, e⟩ := X.presheaf.germ_eq _ hx hx _ _ hy cases Subsingleton.elim iU iV haveI : Nonempty W := ⟨⟨_, hW⟩⟩ exact map_injective_of_isIntegral X iU e theorem Scheme.germToFunctionField_injective [IsIntegral X] (U : X.Opens) [Nonempty U] : Function.Injective (X.germToFunctionField U) := - germ_injective_of_isIntegral _ _ + germ_injective_of_isIntegral _ _ _ theorem genericPoint_eq_of_isOpenImmersion {X Y : Scheme} (f : X ⟶ Y) [H : IsOpenImmersion f] [hX : IrreducibleSpace X] [IrreducibleSpace Y] : - f.1.base (genericPoint X) = genericPoint Y := by + f.base (genericPoint X) = genericPoint Y := by apply ((genericPoint_spec Y).eq _).symm - convert (genericPoint_spec X).image (show Continuous f.1.base by fun_prop) + convert (genericPoint_spec X).image (show Continuous f.base by fun_prop) symm - rw [eq_top_iff, Set.top_eq_univ, Set.top_eq_univ] + rw [← Set.univ_subset_iff] convert subset_closure_inter_of_isPreirreducible_of_isOpen _ H.base_open.isOpen_range _ · rw [Set.univ_inter, Set.image_univ] · apply PreirreducibleSpace.isPreirreducible_univ (X := Y) @@ -94,7 +94,7 @@ instance functionField_isScalarTower [IrreducibleSpace X] (U : X.Opens) (x : U) [Nonempty U] : IsScalarTower Γ(X, U) (X.presheaf.stalk x) X.functionField := by apply IsScalarTower.of_algebraMap_eq' simp_rw [RingHom.algebraMap_toAlgebra] - change _ = X.presheaf.germ x ≫ _ + change _ = X.presheaf.germ U x x.2 ≫ _ rw [X.presheaf.germ_stalkSpecializes] noncomputable instance (R : CommRingCat.{u}) [IsDomain R] : @@ -107,7 +107,7 @@ theorem genericPoint_eq_bot_of_affine (R : CommRingCat) [IsDomain R] : apply (genericPoint_spec (Spec R)).eq rw [isGenericPoint_def] rw [← PrimeSpectrum.zeroLocus_vanishingIdeal_eq_closure, PrimeSpectrum.vanishingIdeal_singleton] - rw [Set.top_eq_univ, ← PrimeSpectrum.zeroLocus_singleton_zero] + rw [← PrimeSpectrum.zeroLocus_singleton_zero] rfl instance functionField_isFractionRing_of_affine (R : CommRingCat.{u}) [IsDomain R] : @@ -135,7 +135,7 @@ theorem IsAffineOpen.primeIdealOf_genericPoint {X : Scheme} [IsIntegral X] {U : delta IsAffineOpen.primeIdealOf convert genericPoint_eq_of_isOpenImmersion - (U.toScheme.isoSpec.hom ≫ Spec.map (X.presheaf.map (eqToHom U.openEmbedding_obj_top).op)) + (U.toScheme.isoSpec.hom ≫ Spec.map (X.presheaf.map (eqToHom U.isOpenEmbedding_obj_top).op)) -- Porting note: this was `ext1` apply Subtype.ext exact (genericPoint_eq_of_isOpenImmersion U.ι).symm @@ -146,9 +146,10 @@ theorem functionField_isFractionRing_of_isAffineOpen [IsIntegral X] (U : X.Opens haveI : IsAffine _ := hU haveI : IsIntegral U := @isIntegral_of_isAffine_of_isDomain _ _ _ - (by rw [Scheme.Opens.toScheme_presheaf_obj, Opens.openEmbedding_obj_top]; infer_instance) + (by rw [Scheme.Opens.toScheme_presheaf_obj, Opens.isOpenEmbedding_obj_top]; infer_instance) delta IsFractionRing Scheme.functionField - convert hU.isLocalization_stalk ⟨genericPoint X, _⟩ using 1 + convert hU.isLocalization_stalk ⟨genericPoint X, + (((genericPoint_spec X).mem_open_set_iff U.isOpen).mpr (by simpa using ‹Nonempty U›))⟩ using 1 rw [hU.primeIdealOf_genericPoint, genericPoint_eq_bot_of_affine] ext; exact mem_nonZeroDivisors_iff_ne_zero diff --git a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean index 6e19f5f554874..577af21ca59d1 100644 --- a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean +++ b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean @@ -74,7 +74,10 @@ open in `X` defined by the same element (they are equal as sets). -/ theorem toΓSpec_preimage_basicOpen_eq (r : Γ.obj (op X)) : X.toΓSpecFun ⁻¹' (basicOpen r).1 = (X.toRingedSpace.basicOpen r).1 := by ext - erw [X.toRingedSpace.mem_top_basicOpen]; apply not_mem_prime_iff_unit_in_stalk + dsimp + simp only [Set.mem_preimage, SetLike.mem_coe] + rw [X.toRingedSpace.mem_top_basicOpen] + exact not_mem_prime_iff_unit_in_stalk .. /-- `toΓSpecFun` is continuous. -/ theorem toΓSpec_continuous : Continuous X.toΓSpecFun := by @@ -153,7 +156,7 @@ def toΓSpecCBasicOpens : naturality r s f := by apply (StructureSheaf.to_basicOpen_epi (Γ.obj (op X)) r.unop).1 simp only [← Category.assoc] - erw [X.toΓSpecCApp_spec r.unop] + rw [X.toΓSpecCApp_spec r.unop] convert X.toΓSpecCApp_spec s.unop symm apply X.presheaf.map_comp @@ -181,21 +184,18 @@ theorem toΓSpecSheafedSpace_app_eq : stalks (in `Spec Γ(X)` and in `X`). -/ theorem toStalk_stalkMap_toΓSpec (x : X) : toStalk _ _ ≫ X.toΓSpecSheafedSpace.stalkMap x = X.presheaf.Γgerm x := by - rw [PresheafedSpace.Hom.stalkMap] - erw [← toOpen_germ _ (basicOpen (1 : Γ.obj (op X))) - ⟨X.toΓSpecFun x, by rw [basicOpen_one]; trivial⟩] - rw [← Category.assoc, Category.assoc (toOpen _ _)] - erw [stalkFunctor_map_germ] - rw [← Category.assoc, toΓSpecSheafedSpace_app_spec, Γgerm] - rw [← stalkPushforward_germ _ X.toΓSpecBase X.presheaf ⊤] + rw [PresheafedSpace.Hom.stalkMap, + ← toOpen_germ _ (basicOpen (1 : Γ.obj (op X))) _ (by rw [basicOpen_one]; trivial), + ← Category.assoc, Category.assoc (toOpen _ _), stalkFunctor_map_germ, ← Category.assoc, + toΓSpecSheafedSpace_app_spec, Γgerm] + erw [← stalkPushforward_germ _ _ X.presheaf ⊤] congr 1 - change (X.toΓSpecBase _* X.presheaf).map le_top.hom.op ≫ _ = _ - apply germ_res + exact (X.toΓSpecBase _* X.presheaf).germ_res le_top.hom _ _ /-- The canonical morphism from `X` to the spectrum of its global sections. -/ -@[simps! val_base] +@[simps! base] def toΓSpec : X ⟶ Spec.locallyRingedSpaceObj (Γ.obj (op X)) where - val := X.toΓSpecSheafedSpace + __ := X.toΓSpecSheafedSpace prop := by intro x let p : PrimeSpectrum (Γ.obj (op X)) := X.toΓSpecFun x @@ -220,11 +220,11 @@ def toΓSpec : X ⟶ Spec.locallyRingedSpaceObj (Γ.obj (op X)) where of `Γ(X, ⊤)` under `toΓSpec` agrees with the associated zero locus on `X`. -/ lemma toΓSpec_preimage_zeroLocus_eq {X : LocallyRingedSpace.{u}} (s : Set (X.presheaf.obj (op ⊤))) : - X.toΓSpec.val.base ⁻¹' PrimeSpectrum.zeroLocus s = X.toRingedSpace.zeroLocus s := by + X.toΓSpec.base ⁻¹' PrimeSpectrum.zeroLocus s = X.toRingedSpace.zeroLocus s := by simp only [RingedSpace.zeroLocus] have (i : LocallyRingedSpace.Γ.obj (op X)) (_ : i ∈ s) : ((X.toRingedSpace.basicOpen i).carrier)ᶜ = - X.toΓSpec.val.base ⁻¹' (PrimeSpectrum.basicOpen i).carrierᶜ := by + X.toΓSpec.base ⁻¹' (PrimeSpectrum.basicOpen i).carrierᶜ := by symm erw [Set.preimage_compl, X.toΓSpec_preimage_basicOpen_eq i] erw [Set.iInter₂_congr this] @@ -235,28 +235,27 @@ lemma toΓSpec_preimage_zeroLocus_eq {X : LocallyRingedSpace.{u}} theorem comp_ring_hom_ext {X : LocallyRingedSpace.{u}} {R : CommRingCat.{u}} {f : R ⟶ Γ.obj (op X)} {β : X ⟶ Spec.locallyRingedSpaceObj R} - (w : X.toΓSpec.1.base ≫ (Spec.locallyRingedSpaceMap f).1.base = β.1.base) + (w : X.toΓSpec.base ≫ (Spec.locallyRingedSpaceMap f).base = β.base) (h : ∀ r : R, - f ≫ X.presheaf.map (homOfLE le_top : (Opens.map β.1.base).obj (basicOpen r) ⟶ _).op = - toOpen R (basicOpen r) ≫ β.1.c.app (op (basicOpen r))) : + f ≫ X.presheaf.map (homOfLE le_top : (Opens.map β.base).obj (basicOpen r) ⟶ _).op = + toOpen R (basicOpen r) ≫ β.c.app (op (basicOpen r))) : X.toΓSpec ≫ Spec.locallyRingedSpaceMap f = β := by ext1 -- Porting note: was `apply Spec.basicOpen_hom_ext` refine Spec.basicOpen_hom_ext w ?_ intro r U - rw [LocallyRingedSpace.comp_val_c_app] + rw [LocallyRingedSpace.comp_c_app] erw [toOpen_comp_comap_assoc] rw [Category.assoc] erw [toΓSpecSheafedSpace_app_spec, ← X.presheaf.map_comp] exact h r /-- `toSpecΓ _` is an isomorphism so these are mutually two-sided inverses. -/ -theorem Γ_Spec_left_triangle : toSpecΓ (Γ.obj (op X)) ≫ X.toΓSpec.1.c.app (op ⊤) = 𝟙 _ := by +theorem Γ_Spec_left_triangle : toSpecΓ (Γ.obj (op X)) ≫ X.toΓSpec.c.app (op ⊤) = 𝟙 _ := by unfold toSpecΓ - rw [← toOpen_res _ (basicOpen (1 : Γ.obj (op X))) ⊤ (eqToHom basicOpen_one.symm)] - erw [Category.assoc] - rw [NatTrans.naturality, ← Category.assoc] + rw [← toOpen_res _ (basicOpen (1 : Γ.obj (op X))) ⊤ (eqToHom basicOpen_one.symm), + Category.assoc, NatTrans.naturality, ← Category.assoc] erw [X.toΓSpecSheafedSpace_app_spec 1, ← Functor.map_comp] convert eqToHom_map X.presheaf _; rfl @@ -269,33 +268,22 @@ def identityToΓSpec : 𝟭 LocallyRingedSpace.{u} ⟶ Γ.rightOp ⋙ Spec.toLoc symm apply LocallyRingedSpace.comp_ring_hom_ext · ext1 x - dsimp only [Spec.topMap, LocallyRingedSpace.toΓSpecFun] - -- Porting note: Had to add the next four lines - rw [comp_apply] - dsimp [toΓSpecBase] - -- The next six lines were `rw [ContinuousMap.coe_mk, ContinuousMap.coe_mk]` before - -- leanprover/lean4#2644 - have : (ContinuousMap.mk (toΓSpecFun Y) (toΓSpec_continuous _)) (f.val.base x) - = toΓSpecFun Y (f.val.base x) := by rw [ContinuousMap.coe_mk] - erw [this] - have : (ContinuousMap.mk (toΓSpecFun X) (toΓSpec_continuous _)) x - = toΓSpecFun X x := by rw [ContinuousMap.coe_mk] - erw [this] + dsimp + show PrimeSpectrum.comap (f.c.app (op ⊤)) (X.toΓSpecFun x) = Y.toΓSpecFun (f.base x) dsimp [toΓSpecFun] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [← LocalRing.comap_closedPoint (f.stalkMap x), ← + rw [← LocalRing.comap_closedPoint (f.stalkMap x), ← PrimeSpectrum.comap_comp_apply, ← PrimeSpectrum.comap_comp_apply] congr 2 - exact (PresheafedSpace.stalkMap_germ f.1 ⊤ ⟨x, trivial⟩).symm + exact (PresheafedSpace.stalkMap_germ f.1 ⊤ x trivial).symm · intro r - rw [LocallyRingedSpace.comp_val_c_app, ← Category.assoc] - erw [Y.toΓSpecSheafedSpace_app_spec, f.1.c.naturality] + rw [LocallyRingedSpace.comp_c_app, ← Category.assoc] + erw [Y.toΓSpecSheafedSpace_app_spec, f.c.naturality] rfl namespace ΓSpec theorem left_triangle (X : LocallyRingedSpace) : - SpecΓIdentity.inv.app (Γ.obj (op X)) ≫ (identityToΓSpec.app X).val.c.app (op ⊤) = 𝟙 _ := + SpecΓIdentity.inv.app (Γ.obj (op X)) ≫ (identityToΓSpec.app X).c.app (op ⊤) = 𝟙 _ := X.Γ_Spec_left_triangle /-- `SpecΓIdentity` is iso so these are mutually two-sided inverses. -/ @@ -362,7 +350,7 @@ lemma toOpen_comp_locallyRingedSpaceAdjunction_homEquiv_app {X : LocallyRingedSpace} {R : Type u} [CommRing R] (f : Γ.rightOp.obj X ⟶ op (CommRingCat.of R)) (U) : StructureSheaf.toOpen R U.unop ≫ - (locallyRingedSpaceAdjunction.homEquiv X (op <| CommRingCat.of R) f).1.c.app U = + (locallyRingedSpaceAdjunction.homEquiv X (op <| CommRingCat.of R) f).c.app U = f.unop ≫ X.presheaf.map (homOfLE le_top).op := by rw [← StructureSheaf.toOpen_res _ _ _ (homOfLE le_top), Category.assoc, NatTrans.naturality _ (homOfLE (le_top (a := U.unop))).op, @@ -374,27 +362,25 @@ lemma toOpen_comp_locallyRingedSpaceAdjunction_homEquiv_app rfl /-- The adjunction `Γ ⊣ Spec` from `CommRingᵒᵖ` to `Scheme`. -/ -def adjunction : Scheme.Γ.rightOp ⊣ Scheme.Spec.{u} := - Adjunction.mk' { - homEquiv := fun X Y ↦ locallyRingedSpaceAdjunction.{u}.homEquiv X.toLocallyRingedSpace Y - unit := - { app := fun X ↦ locallyRingedSpaceAdjunction.{u}.unit.app X.toLocallyRingedSpace - naturality := fun _ _ f ↦ locallyRingedSpaceAdjunction.{u}.unit.naturality f } - counit := (NatIso.op Scheme.SpecΓIdentity.{u}).inv - homEquiv_unit := rfl - homEquiv_counit := rfl } +def adjunction : Scheme.Γ.rightOp ⊣ Scheme.Spec.{u} where + unit := + { app := fun X ↦ ⟨locallyRingedSpaceAdjunction.{u}.unit.app X.toLocallyRingedSpace⟩ + naturality := fun _ _ f ↦ + Scheme.Hom.ext' (locallyRingedSpaceAdjunction.{u}.unit.naturality f.toLRSHom) } + counit := (NatIso.op Scheme.SpecΓIdentity.{u}).inv + left_triangle_components Y := + locallyRingedSpaceAdjunction.left_triangle_components Y.toLocallyRingedSpace + right_triangle_components R := + Scheme.Hom.ext' <| locallyRingedSpaceAdjunction.right_triangle_components R theorem adjunction_homEquiv_apply {X : Scheme} {R : CommRingCatᵒᵖ} (f : (op <| Scheme.Γ.obj <| op X) ⟶ R) : - ΓSpec.adjunction.homEquiv X R f = locallyRingedSpaceAdjunction.homEquiv X.1 R f := rfl - -theorem adjunction_homEquiv (X : Scheme) (R : CommRingCatᵒᵖ) : - ΓSpec.adjunction.homEquiv X R = locallyRingedSpaceAdjunction.homEquiv X.1 R := rfl + ΓSpec.adjunction.homEquiv X R f = ⟨locallyRingedSpaceAdjunction.homEquiv X.1 R f⟩ := rfl theorem adjunction_homEquiv_symm_apply {X : Scheme} {R : CommRingCatᵒᵖ} (f : X ⟶ Scheme.Spec.obj R) : (ΓSpec.adjunction.homEquiv X R).symm f = - (locallyRingedSpaceAdjunction.homEquiv X.1 R).symm f := rfl + (locallyRingedSpaceAdjunction.homEquiv X.1 R).symm f.toLRSHom := rfl theorem adjunction_counit_app' {R : CommRingCatᵒᵖ} : ΓSpec.adjunction.counit.app R = locallyRingedSpaceAdjunction.counit.app R := rfl @@ -423,6 +409,10 @@ instance isIso_adjunction_counit : IsIso ΓSpec.adjunction.counit := by end ΓSpec +theorem Scheme.toSpecΓ_base (X : Scheme.{u}) (x) : + (Scheme.toSpecΓ X).base x = + (Spec.map (X.presheaf.germ ⊤ x trivial)).base (LocalRing.closedPoint _) := rfl + @[reassoc (attr := simp)] theorem Scheme.toSpecΓ_naturality {X Y : Scheme.{u}} (f : X ⟶ Y) : f ≫ Y.toSpecΓ = X.toSpecΓ ≫ Spec.map (f.app ⊤) := @@ -465,6 +455,16 @@ theorem toOpen_toSpecΓ_app {X : Scheme.{u}} (U) : dsimp exact Category.id_comp _ +lemma ΓSpecIso_inv_ΓSpec_adjunction_homEquiv {X : Scheme.{u}} {B : CommRingCat} (φ : B ⟶ Γ(X, ⊤)) : + (Scheme.ΓSpecIso B).inv ≫ ((ΓSpec.adjunction.homEquiv X (op B)) φ.op).app ⊤ = φ := by + simp only [Adjunction.homEquiv_apply, Scheme.Spec_map, Opens.map_top, Scheme.comp_app] + simp + +lemma ΓSpec_adjunction_homEquiv_eq {X : Scheme.{u}} {B : CommRingCat} (φ : B ⟶ Γ(X, ⊤)) : + (((ΓSpec.adjunction.homEquiv X (op B)) φ.op).app ⊤) = (Scheme.ΓSpecIso B).hom ≫ φ := by + simp_rw [← ΓSpecIso_inv_ΓSpec_adjunction_homEquiv φ] + simp + theorem ΓSpecIso_obj_hom {X : Scheme.{u}} (U : X.Opens) : (Scheme.ΓSpecIso Γ(X, U)).hom = (Spec.map U.topIso.inv).app ⊤ ≫ U.toScheme.toSpecΓ.app ⊤ ≫ U.topIso.hom := by simp diff --git a/Mathlib/AlgebraicGeometry/Gluing.lean b/Mathlib/AlgebraicGeometry/Gluing.lean index 2abed533825f0..c38450ee48155 100644 --- a/Mathlib/AlgebraicGeometry/Gluing.lean +++ b/Mathlib/AlgebraicGeometry/Gluing.lean @@ -123,9 +123,8 @@ def gluedScheme : Scheme := by D.toLocallyRingedSpaceGlueData.toGlueData.glued intro x obtain ⟨i, y, rfl⟩ := D.toLocallyRingedSpaceGlueData.ι_jointly_surjective x - refine ⟨?_, ?_ ≫ D.toLocallyRingedSpaceGlueData.toGlueData.ι i, ?_⟩ - swap - · exact (D.U i).affineCover.map y + refine ⟨_, ((D.U i).affineCover.map y).toLRSHom ≫ + D.toLocallyRingedSpaceGlueData.toGlueData.ι i, ?_⟩ constructor · erw [TopCat.coe_comp, Set.range_comp] -- now `erw` after #13170 refine Set.mem_image_of_mem _ ?_ @@ -157,14 +156,15 @@ abbrev isoLocallyRingedSpace : 𝖣.gluedIso forgetToLocallyRingedSpace theorem ι_isoLocallyRingedSpace_inv (i : D.J) : - D.toLocallyRingedSpaceGlueData.toGlueData.ι i ≫ D.isoLocallyRingedSpace.inv = 𝖣.ι i := + D.toLocallyRingedSpaceGlueData.toGlueData.ι i ≫ + D.isoLocallyRingedSpace.inv = (𝖣.ι i).toLRSHom := 𝖣.ι_gluedIso_inv forgetToLocallyRingedSpace i instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by - rw [← D.ι_isoLocallyRingedSpace_inv]; infer_instance + rw [IsOpenImmersion, ← D.ι_isoLocallyRingedSpace_inv]; infer_instance theorem ι_jointly_surjective (x : 𝖣.glued.carrier) : - ∃ (i : D.J) (y : (D.U i).carrier), (D.ι i).1.base y = x := + ∃ (i : D.J) (y : (D.U i).carrier), (D.ι i).base y = x := 𝖣.ι_jointly_surjective (forgetToTop ⋙ forget TopCat) x -- Porting note: promote to higher priority to short circuit simplifier @@ -206,40 +206,38 @@ def isoCarrier : @[simp] theorem ι_isoCarrier_inv (i : D.J) : - (D_).ι i ≫ D.isoCarrier.inv = (D.ι i).1.base := by + (D_).ι i ≫ D.isoCarrier.inv = (D.ι i).base := by delta isoCarrier rw [Iso.trans_inv, GlueData.ι_gluedIso_inv_assoc, Functor.mapIso_inv, Iso.trans_inv, Functor.mapIso_inv, Iso.trans_inv, SheafedSpace.forgetToPresheafedSpace_map, forget_map, - forget_map, ← comp_base, ← Category.assoc, + forget_map, ← PresheafedSpace.comp_base, ← Category.assoc, D.toLocallyRingedSpaceGlueData.toSheafedSpaceGlueData.ι_isoPresheafedSpace_inv i] erw [← Category.assoc, D.toLocallyRingedSpaceGlueData.ι_isoSheafedSpace_inv i] - change (_ ≫ D.isoLocallyRingedSpace.inv).1.base = _ + change (_ ≫ D.isoLocallyRingedSpace.inv).base = _ rw [D.ι_isoLocallyRingedSpace_inv i] /-- An equivalence relation on `Σ i, D.U i` that holds iff `𝖣 .ι i x = 𝖣 .ι j y`. See `AlgebraicGeometry.Scheme.GlueData.ι_eq_iff`. -/ def Rel (a b : Σ i, ((D.U i).carrier : Type _)) : Prop := a = b ∨ - ∃ x : (D.V (a.1, b.1)).carrier, (D.f _ _).1.base x = a.2 ∧ (D.t _ _ ≫ D.f _ _).1.base x = b.2 + ∃ x : (D.V (a.1, b.1)).carrier, (D.f _ _).base x = a.2 ∧ (D.t _ _ ≫ D.f _ _).base x = b.2 theorem ι_eq_iff (i j : D.J) (x : (D.U i).carrier) (y : (D.U j).carrier) : - (𝖣.ι i).1.base x = (𝖣.ι j).1.base y ↔ D.Rel ⟨i, x⟩ ⟨j, y⟩ := by + (𝖣.ι i).base x = (𝖣.ι j).base y ↔ D.Rel ⟨i, x⟩ ⟨j, y⟩ := by refine Iff.trans ?_ (TopCat.GlueData.ι_eq_iff_rel D.toLocallyRingedSpaceGlueData.toSheafedSpaceGlueData.toPresheafedSpaceGlueData.toTopGlueData i j x y) - rw [← ((TopCat.mono_iff_injective D.isoCarrier.inv).mp _).eq_iff] - · erw [← comp_apply] -- now `erw` after #13170 - simp_rw [← D.ι_isoCarrier_inv] + rw [← ((TopCat.mono_iff_injective D.isoCarrier.inv).mp _).eq_iff, ← comp_apply] + · simp_rw [← D.ι_isoCarrier_inv] rfl -- `rfl` was not needed before #13170 · infer_instance -theorem isOpen_iff (U : Set D.glued.carrier) : IsOpen U ↔ ∀ i, IsOpen ((D.ι i).1.base ⁻¹' U) := by - rw [← (TopCat.homeoOfIso D.isoCarrier.symm).isOpen_preimage] - rw [TopCat.GlueData.isOpen_iff] +theorem isOpen_iff (U : Set D.glued.carrier) : IsOpen U ↔ ∀ i, IsOpen ((D.ι i).base ⁻¹' U) := by + rw [← (TopCat.homeoOfIso D.isoCarrier.symm).isOpen_preimage, TopCat.GlueData.isOpen_iff] apply forall_congr' intro i - erw [← Set.preimage_comp, ← ι_isoCarrier_inv] + rw [← Set.preimage_comp, ← ι_isoCarrier_inv] rfl /-- The open cover of the glued space given by the glue data. -/ @@ -315,15 +313,15 @@ def gluedCover : Scheme.GlueData.{u} where J := 𝒰.J U := 𝒰.obj V := fun ⟨x, y⟩ => pullback (𝒰.map x) (𝒰.map y) - f x y := pullback.fst _ _ - f_id x := inferInstance - t x y := (pullbackSymmetry _ _).hom + f _ _ := pullback.fst _ _ + f_id _ := inferInstance + t _ _ := (pullbackSymmetry _ _).hom t_id x := by simp t' x y z := gluedCoverT' 𝒰 x y z t_fac x y z := by apply pullback.hom_ext <;> simp -- The `cocycle` field could have been `by tidy` but lean timeouts. cocycle x y z := glued_cover_cocycle 𝒰 x y z - f_open x := inferInstance + f_open _ := inferInstance /-- The canonical morphism from the gluing of an open cover of `X` into `X`. This is an isomorphism, as witnessed by an `IsIso` instance. -/ @@ -338,13 +336,13 @@ def fromGlued : 𝒰.gluedCover.glued ⟶ X := by theorem ι_fromGlued (x : 𝒰.J) : 𝒰.gluedCover.ι x ≫ 𝒰.fromGlued = 𝒰.map x := Multicoequalizer.π_desc _ _ _ _ _ -theorem fromGlued_injective : Function.Injective 𝒰.fromGlued.1.base := by +theorem fromGlued_injective : Function.Injective 𝒰.fromGlued.base := by intro x y h obtain ⟨i, x, rfl⟩ := 𝒰.gluedCover.ι_jointly_surjective x obtain ⟨j, y, rfl⟩ := 𝒰.gluedCover.ι_jointly_surjective y - erw [← comp_apply, ← comp_apply] at h -- now `erw` after #13170 - simp_rw [← SheafedSpace.comp_base, ← LocallyRingedSpace.comp_val] at h - erw [ι_fromGlued, ι_fromGlued] at h + rw [← comp_apply, ← comp_apply] at h + simp_rw [← Scheme.comp_base] at h + rw [ι_fromGlued, ι_fromGlued] at h let e := (TopCat.pullbackConeIsLimit _ _).conePointUniqueUpToIso (isLimitOfHasPullbackOfPreservesLimit Scheme.forgetToTop (𝒰.map i) (𝒰.map j)) @@ -365,12 +363,12 @@ instance fromGlued_stalk_iso (x : 𝒰.gluedCover.glued.carrier) : rw [this] infer_instance -theorem fromGlued_open_map : IsOpenMap 𝒰.fromGlued.1.base := by +theorem fromGlued_open_map : IsOpenMap 𝒰.fromGlued.base := by intro U hU rw [isOpen_iff_forall_mem_open] intro x hx rw [𝒰.gluedCover.isOpen_iff] at hU - use 𝒰.fromGlued.val.base '' U ∩ Set.range (𝒰.map (𝒰.f x)).1.base + use 𝒰.fromGlued.base '' U ∩ Set.range (𝒰.map (𝒰.f x)).base use Set.inter_subset_left constructor · rw [← Set.image_preimage_eq_inter_range] @@ -381,27 +379,30 @@ theorem fromGlued_open_map : IsOpenMap 𝒰.fromGlued.1.base := by exact Set.preimage_image_eq _ 𝒰.fromGlued_injective · exact ⟨hx, 𝒰.covers x⟩ -theorem fromGlued_openEmbedding : OpenEmbedding 𝒰.fromGlued.1.base := - openEmbedding_of_continuous_injective_open +theorem fromGlued_isOpenEmbedding : IsOpenEmbedding 𝒰.fromGlued.base := + isOpenEmbedding_of_continuous_injective_open (by fun_prop) 𝒰.fromGlued_injective 𝒰.fromGlued_open_map -instance : Epi 𝒰.fromGlued.val.base := by +@[deprecated (since := "2024-10-18")] +alias fromGlued_openEmbedding := fromGlued_isOpenEmbedding + +instance : Epi 𝒰.fromGlued.base := by rw [TopCat.epi_iff_surjective] intro x obtain ⟨y, h⟩ := 𝒰.covers x - use (𝒰.gluedCover.ι (𝒰.f x)).1.base y - erw [← comp_apply] -- now `erw` after #13170 + use (𝒰.gluedCover.ι (𝒰.f x)).base y + rw [← comp_apply] rw [← 𝒰.ι_fromGlued (𝒰.f x)] at h exact h instance fromGlued_open_immersion : IsOpenImmersion 𝒰.fromGlued := - IsOpenImmersion.of_stalk_iso _ 𝒰.fromGlued_openEmbedding + IsOpenImmersion.of_stalk_iso _ 𝒰.fromGlued_isOpenEmbedding instance : IsIso 𝒰.fromGlued := let F := Scheme.forgetToLocallyRingedSpace ⋙ LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forgetToPresheafedSpace have : IsIso (F.map (fromGlued 𝒰)) := by - change @IsIso (PresheafedSpace _) _ _ _ 𝒰.fromGlued.val + change IsIso 𝒰.fromGlued.toPshHom apply PresheafedSpace.IsOpenImmersion.to_iso isIso_of_reflects_iso _ F diff --git a/Mathlib/AlgebraicGeometry/GluingOneHypercover.lean b/Mathlib/AlgebraicGeometry/GluingOneHypercover.lean index 57c59570b18b7..374d5034df6eb 100644 --- a/Mathlib/AlgebraicGeometry/GluingOneHypercover.lean +++ b/Mathlib/AlgebraicGeometry/GluingOneHypercover.lean @@ -42,7 +42,7 @@ noncomputable def oneHypercover : Scheme.zariskiTopology.OneHypercover D.glued w I₁ _ _ := PUnit Y i₁ i₂ _ := D.V (i₁, i₂) p₁ i₁ i₂ _ := D.f i₁ i₂ - p₂ i₁ i₂ j := D.t i₁ i₂ ≫ D.f i₂ i₁ + p₂ i₁ i₂ _ := D.t i₁ i₂ ≫ D.f i₂ i₁ w i₁ i₂ _ := by simp only [Category.assoc, Scheme.GlueData.glue_condition] mem₀ := by refine zariskiTopology.superset_covering ?_ (zariskiTopology_openCover D.openCover) diff --git a/Mathlib/AlgebraicGeometry/Limits.lean b/Mathlib/AlgebraicGeometry/Limits.lean index 903e50c8aefa6..1480c9d5d315f 100644 --- a/Mathlib/AlgebraicGeometry/Limits.lean +++ b/Mathlib/AlgebraicGeometry/Limits.lean @@ -53,13 +53,11 @@ section Initial @[simps] def Scheme.emptyTo (X : Scheme.{u}) : ∅ ⟶ X := ⟨{ base := ⟨fun x => PEmpty.elim x, by fun_prop⟩ - c := { app := fun U => CommRingCat.punitIsTerminal.from _ } }, fun x => PEmpty.elim x⟩ + c := { app := fun _ => CommRingCat.punitIsTerminal.from _ } }, fun x => PEmpty.elim x⟩ @[ext] theorem Scheme.empty_ext {X : Scheme.{u}} (f g : ∅ ⟶ X) : f = g := - -- Porting note (#11041): `ext` regression - LocallyRingedSpace.Hom.ext <| PresheafedSpace.ext _ _ (by ext a; exact PEmpty.elim a) <| - NatTrans.ext <| funext fun a => by aesop_cat + Scheme.Hom.ext' (Subsingleton.elim (α := ∅ ⟶ _) _ _) theorem Scheme.eq_emptyTo {X : Scheme.{u}} (f : ∅ ⟶ X) : f = Scheme.emptyTo X := Scheme.empty_ext f (Scheme.emptyTo X) @@ -89,8 +87,8 @@ instance (priority := 100) isOpenImmersion_of_isEmpty {X Y : Scheme} (f : X ⟶ instance (priority := 100) isIso_of_isEmpty {X Y : Scheme} (f : X ⟶ Y) [IsEmpty Y] : IsIso f := by - haveI : IsEmpty X := f.1.base.1.isEmpty - have : Epi f.1.base := by + haveI : IsEmpty X := f.base.1.isEmpty + have : Epi f.base := by rw [TopCat.epi_iff_surjective]; rintro (x : Y) exact isEmptyElim x apply IsOpenImmersion.to_iso @@ -110,7 +108,7 @@ instance : HasInitial Scheme.{u} := hasInitial_of_unique ∅ instance initial_isEmpty : IsEmpty (⊥_ Scheme) := - ⟨fun x => ((initial.to Scheme.empty : _).1.base x).elim⟩ + ⟨fun x => ((initial.to Scheme.empty : _).base x).elim⟩ theorem isAffineOpen_bot (X : Scheme) : IsAffineOpen (⊥ : X.Opens) := @isAffine_of_isEmpty _ (inferInstanceAs (IsEmpty (∅ : Set X))) @@ -242,7 +240,7 @@ instance (i) : IsOpenImmersion (Sigma.ι f i) := by infer_instance lemma sigmaι_eq_iff (i j : ι) (x y) : - (Sigma.ι f i).1.base x = (Sigma.ι f j).1.base y ↔ + (Sigma.ι f i).base x = (Sigma.ι f j).base y ↔ (Sigma.mk i x : Σ i, f i) = Sigma.mk j y := by constructor · intro H @@ -252,7 +250,7 @@ lemma sigmaι_eq_iff (i j : ι) (x y) : by_cases h : i = j · subst h simp only [Sigma.mk.inj_iff, heq_eq_eq, true_and] - exact ((disjointGlueData f).ι i).openEmbedding.inj H + exact ((disjointGlueData f).ι i).isOpenEmbedding.inj H · obtain (e | ⟨z, _⟩) := (Scheme.GlueData.ι_eq_iff _ _ _ _ _).mp H · exact (h (Sigma.mk.inj_iff.mp e).1).elim · simp only [disjointGlueData_J, disjointGlueData_V, h, ↓reduceIte] at z @@ -269,10 +267,10 @@ lemma disjoint_opensRange_sigmaι (i j : ι) (h : i ≠ j) : obtain ⟨rfl⟩ := (sigmaι_eq_iff _ _ _ _ _).mp hy cases h rfl -lemma exists_sigmaι_eq (x : (∐ f : _)) : ∃ i y, (Sigma.ι f i).1.base y = x := by - obtain ⟨i, y, e⟩ := (disjointGlueData f).ι_jointly_surjective ((sigmaIsoGlued f).hom.1.base x) - refine ⟨i, y, (sigmaIsoGlued f).hom.openEmbedding.inj ?_⟩ - rwa [← Scheme.comp_val_base_apply, ι_sigmaIsoGlued_hom] +lemma exists_sigmaι_eq (x : (∐ f : _)) : ∃ i y, (Sigma.ι f i).base y = x := by + obtain ⟨i, y, e⟩ := (disjointGlueData f).ι_jointly_surjective ((sigmaIsoGlued f).hom.base x) + refine ⟨i, y, (sigmaIsoGlued f).hom.isOpenEmbedding.inj ?_⟩ + rwa [← Scheme.comp_base_apply, ι_sigmaIsoGlued_hom] lemma iSup_opensRange_sigmaι : ⨆ i, (Sigma.ι f i).opensRange = ⊤ := eq_top_iff.mpr fun x ↦ by simpa using exists_sigmaι_eq f x @@ -295,7 +293,7 @@ def sigmaMk : (Σ i, f i) ≃ₜ (∐ f : _) := @[simp] lemma sigmaMk_mk (i) (x : f i) : - sigmaMk f (.mk i x) = (Sigma.ι f i).1.base x := by + sigmaMk f (.mk i x) = (Sigma.ι f i).base x := by show ((TopCat.sigmaCofan (fun x ↦ (f x).toTopCat)).inj i ≫ (colimit.isoColimitCocone ⟨_, TopCat.sigmaCofanIsColimit _⟩).inv ≫ _) x = Scheme.forgetToTop.map (Sigma.ι f i) x @@ -324,8 +322,8 @@ instance : IsOpenImmersion (coprod.inr : Y ⟶ X ⨿ Y) := by rw [← ι_right_coprodIsoSigma_inv]; infer_instance lemma isCompl_range_inl_inr : - IsCompl (Set.range (coprod.inl : X ⟶ X ⨿ Y).1.base) - (Set.range (coprod.inr : Y ⟶ X ⨿ Y).1.base) := + IsCompl (Set.range (coprod.inl : X ⟶ X ⨿ Y).base) + (Set.range (coprod.inr : Y ⟶ X ⨿ Y).base) := ((TopCat.binaryCofan_isColimit_iff _).mp ⟨mapIsColimitOfPreservesOfIsColimit Scheme.forgetToTop _ _ (coprodIsCoprod X Y)⟩).2.2 @@ -343,7 +341,7 @@ def coprodMk : X ⊕ Y ≃ₜ (X ⨿ Y : Scheme.{u}) := @[simp] lemma coprodMk_inl (x : X) : - coprodMk X Y (.inl x) = (coprod.inl : X ⟶ X ⨿ Y).1.base x := by + coprodMk X Y (.inl x) = (coprod.inl : X ⟶ X ⨿ Y).base x := by show ((TopCat.binaryCofan X Y).inl ≫ (colimit.isoColimitCocone ⟨_, TopCat.binaryCofanIsColimit _ _⟩).inv ≫ _) x = Scheme.forgetToTop.map coprod.inl x @@ -353,7 +351,7 @@ lemma coprodMk_inl (x : X) : @[simp] lemma coprodMk_inr (x : Y) : - coprodMk X Y (.inr x) = (coprod.inr : Y ⟶ X ⨿ Y).1.base x := by + coprodMk X Y (.inr x) = (coprod.inr : Y ⟶ X ⨿ Y).base x := by show ((TopCat.binaryCofan X Y).inr ≫ (colimit.isoColimitCocone ⟨_, TopCat.binaryCofanIsColimit _ _⟩).inv ≫ _) x = Scheme.forgetToTop.map coprod.inr x @@ -397,10 +395,10 @@ lemma coprodSpec_inr : coprod.inr ≫ coprodSpec R S = coprod.inr_desc _ _ lemma coprodSpec_coprodMk (x) : - (coprodSpec R S).1.base (coprodMk _ _ x) = (PrimeSpectrum.primeSpectrumProd R S).symm x := by + (coprodSpec R S).base (coprodMk _ _ x) = (PrimeSpectrum.primeSpectrumProd R S).symm x := by apply PrimeSpectrum.ext obtain (x | x) := x <;> - simp only [coprodMk_inl, coprodMk_inr, ← Scheme.comp_val_base_apply, + simp only [coprodMk_inl, coprodMk_inr, ← Scheme.comp_base_apply, coprodSpec, coprod.inl_desc, coprod.inr_desc] · show Ideal.comap _ _ = x.asIdeal.prod ⊤ ext; simp [Ideal.prod, CommRingCat.ofHom] @@ -408,7 +406,7 @@ lemma coprodSpec_coprodMk (x) : ext; simp [Ideal.prod, CommRingCat.ofHom] lemma coprodSpec_apply (x) : - (coprodSpec R S).1.base x = (PrimeSpectrum.primeSpectrumProd R S).symm + (coprodSpec R S).base x = (PrimeSpectrum.primeSpectrumProd R S).symm ((coprodMk (Spec (.of R)) (Spec (.of S))).symm x) := by rw [← coprodSpec_coprodMk, Homeomorph.apply_symm_apply] @@ -467,7 +465,7 @@ noncomputable instance : PreservesColimitsOfShape (Discrete PEmpty.{1}) Scheme.Spec := by have : IsEmpty (Scheme.Spec.obj (⊥_ CommRingCatᵒᵖ)) := @Function.isEmpty _ _ spec_punit_isEmpty (Scheme.Spec.mapIso - (initialIsoIsInitial (initialOpOfTerminal CommRingCat.punitIsTerminal))).hom.1.base + (initialIsoIsInitial (initialOpOfTerminal CommRingCat.punitIsTerminal))).hom.base have := preservesInitialOfIso Scheme.Spec (asIso (initial.to _)) exact preservesColimitsOfShapePemptyOfPreservesInitial _ diff --git a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean index b3aa7de64c852..d14b580db3d1a 100644 --- a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean +++ b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean @@ -22,6 +22,8 @@ such that `M^~(U)` is the set of dependent functions that are locally fractions. * `ModuleCat.tildeInType` : `M^~` as a sheaf of types groups. * `ModuleCat.tilde` : `M^~` as a sheaf of `𝒪_{Spec R}`-modules. +* `ModuleCat.tilde.stalkIso`: The isomorphism of `R`-modules from the stalk of `M^~` at `x` to +the localization of `M` at the prime ideal corresponding to `x`. ## Technical note @@ -57,7 +59,7 @@ def isFraction {U : Opens (PrimeSpectrum R)} (f : ∀ 𝔭 : U, Localizations M The property of a function `f : ∏_{x ∈ U}, Mₓ` being a fraction is stable under restriction. -/ def isFractionPrelocal : PrelocalPredicate (Localizations M) where - pred {U} f := isFraction M f + pred {_} f := isFraction M f res := by rintro V U i f ⟨m, s, w⟩; exact ⟨m, s, fun x => w (i x)⟩ /-- @@ -219,7 +221,7 @@ If `x` is a point of `Spec R`, this is the morphism of `R`-modules from `M` to t -/ noncomputable def toStalk (x : PrimeSpectrum.Top R) : ModuleCat.of R M ⟶ TopCat.Presheaf.stalk (tildeInModuleCat M) x := - (toOpen M ⊤ ≫ TopCat.Presheaf.germ (tildeInModuleCat M) ⟨x, by trivial⟩) + (toOpen M ⊤ ≫ TopCat.Presheaf.germ (tildeInModuleCat M) ⊤ x (by trivial)) open LocalizedModule TopCat.Presheaf in lemma isUnit_toStalk (x : PrimeSpectrum.Top R) (r : x.asIdeal.primeCompl) : @@ -229,7 +231,7 @@ lemma isUnit_toStalk (x : PrimeSpectrum.Top R) (r : x.asIdeal.primeCompl) : smul_stalk_no_nonzero_divisor M r st h, fun st ↦ ?_⟩ obtain ⟨U, mem, s, rfl⟩ := germ_exist (F := M.tildeInModuleCat) x st let O := U ⊓ (PrimeSpectrum.basicOpen r) - refine ⟨germ M.tildeInModuleCat (⟨x, ⟨mem, r.2⟩⟩ : O) + refine ⟨germ M.tildeInModuleCat O x ⟨mem, r.2⟩ ⟨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 @@ -252,6 +254,144 @@ noncomputable def localizationToStalk (x : PrimeSpectrum.Top R) : (TopCat.Presheaf.stalk (tildeInModuleCat M) x) := LocalizedModule.lift _ (toStalk M x) <| isUnit_toStalk M x + +/-- The ring homomorphism that takes a section of the structure sheaf of `R` on the open set `U`, +implemented as a subtype of dependent functions to localizations at prime ideals, and evaluates +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 + +/-- +The morphism of `R`-modules from the stalk of `M^~` at `x` to the localization of `M` at the +prime ideal of `R` corresponding to `x`. +-/ +noncomputable def stalkToFiberLinearMap (x : PrimeSpectrum.Top R) : + (tildeInModuleCat M).stalk x ⟶ + ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) := + Limits.colimit.desc ((OpenNhds.inclusion x).op ⋙ (tildeInModuleCat M)) + { pt := _ + ι := + { app := fun U => openToLocalization M ((OpenNhds.inclusion _).obj U.unop) x U.unop.2 } } + +@[simp] +theorem germ_comp_stalkToFiberLinearMap (U : Opens (PrimeSpectrum.Top R)) (x) (hx : x ∈ U) : + (tildeInModuleCat M).germ U x hx ≫ stalkToFiberLinearMap M x = + openToLocalization M U x hx := + Limits.colimit.ι_desc _ _ + +@[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 + (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 + +@[reassoc (attr := simp), elementwise (attr := simp)] +theorem toOpen_germ (U : Opens (PrimeSpectrum.Top R)) (x) (hx : x ∈ U) : + toOpen M U ≫ M.tildeInModuleCat.germ U x hx = toStalk M x := by + rw [← toOpen_res M ⊤ U (homOfLE le_top : U ⟶ ⊤), Category.assoc, Presheaf.germ_res]; rfl + +@[reassoc (attr := simp)] +theorem toStalk_comp_stalkToFiberLinearMap (x : PrimeSpectrum.Top R) : + toStalk M x ≫ stalkToFiberLinearMap M x = + 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) = + LocalizedModule.mk m 1 := + LinearMap.ext_iff.1 (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` +that is invertible on `U` (i.e. does not belong to any prime ideal corresponding to a point +in `U`), this is `m / r` seen as a section of `M^~` over `U`. +-/ +def const (m : M) (r : R) (U : Opens (PrimeSpectrum.Top R)) + (hu : ∀ x ∈ U, r ∈ (x : PrimeSpectrum.Top R).asIdeal.primeCompl) : + (tildeInModuleCat M).obj (op U) := + ⟨fun x => LocalizedModule.mk m ⟨r, hu x x.2⟩, fun x => + ⟨U, x.2, 𝟙 _, m, r, fun y => ⟨hu _ y.2, by + simpa only [LocalizedModule.mkLinearMap_apply, LocalizedModule.smul'_mk, + LocalizedModule.mk_eq] using ⟨1, by simp⟩⟩⟩⟩ + +@[simp] +theorem const_apply (m : M) (r : R) (U : Opens (PrimeSpectrum.Top R)) + (hu : ∀ x ∈ U, r ∈ (x : PrimeSpectrum.Top R).asIdeal.primeCompl) (x : U) : + (const M m r U hu).1 x = LocalizedModule.mk m ⟨r, hu x x.2⟩ := + rfl + +theorem exists_const (U) (s : (tildeInModuleCat M).obj (op U)) (x : PrimeSpectrum.Top R) + (hx : x ∈ U) : + ∃ (V : Opens (PrimeSpectrum.Top R)) (_ : x ∈ V) (i : V ⟶ U) (f : M) (g : R) (hg : _), + const M f g V hg = (tildeInModuleCat M).map i.op s := + let ⟨V, hxV, iVU, f, g, hfg⟩ := s.2 ⟨x, hx⟩ + ⟨V, hxV, iVU, f, g, fun y hyV => (hfg ⟨y, hyV⟩).1, Subtype.eq <| funext fun y => by + obtain ⟨h1, (h2 : g • s.1 ⟨y, _⟩ = LocalizedModule.mk f 1)⟩ := hfg y + exact show LocalizedModule.mk f ⟨g, by exact h1⟩ = s.1 (iVU y) by + set x := s.1 (iVU y); change g • x = _ at h2; clear_value x + induction x using LocalizedModule.induction_on with + | h a b => + rw [LocalizedModule.smul'_mk, LocalizedModule.mk_eq] at h2 + obtain ⟨c, hc⟩ := h2 + exact LocalizedModule.mk_eq.mpr ⟨c, by simpa using hc.symm⟩⟩ + +@[simp] +theorem res_const (f : M) (g : R) (U hu V hv i) : + (tildeInModuleCat M).map i (const M f g U hu) = const M f g V hv := + rfl + +@[simp] +theorem localizationToStalk_mk (x : PrimeSpectrum.Top R) (f : M) (s : x.asIdeal.primeCompl) : + localizationToStalk M x (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 + erw [← LinearMap.mul_apply] + simp only [IsUnit.mul_val_inv, LinearMap.one_apply, Module.algebraMap_end_apply] + show (M.tildeInModuleCat.germ ⊤ x ⟨⟩) ((toOpen M ⊤) f) = _ + rw [← map_smul] + fapply TopCat.Presheaf.germ_ext (W := PrimeSpectrum.basicOpen s.1) (hxW := s.2) + · exact homOfLE le_top + · exact 𝟙 _ + refine Subtype.eq <| funext fun y => show LocalizedModule.mk f 1 = _ from ?_ + show LocalizedModule.mk f 1 = s.1 • LocalizedModule.mk f _ + rw [LocalizedModule.smul'_mk, LocalizedModule.mk_eq] + exact ⟨1, by simp⟩ + +/-- +The isomorphism of `R`-modules from the stalk of `M^~` at `x` to the localization of `M` at the +prime ideal corresponding to `x`. +-/ +@[simps] +noncomputable def stalkIso (x : PrimeSpectrum.Top R) : + TopCat.Presheaf.stalk (tildeInModuleCat M) x ≅ + 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 + show localizationToStalk M x (stalkToFiberLinearMap M x (M.tildeInModuleCat.germ U x hxU s)) = + M.tildeInModuleCat.germ U x hxU s + rw [stalkToFiberLinearMap_germ] + obtain ⟨V, hxV, iVU, f, g, (hg : V ≤ PrimeSpectrum.basicOpen _), hs⟩ := + 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) + +instance (x : PrimeSpectrum.Top R) : + IsLocalizedModule x.asIdeal.primeCompl (toStalk M x) := 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] + erw [LocalizedModule.lift_comp] + end Tilde end ModuleCat diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean index c990b0ee818d7..10ec1471d5adb 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean @@ -45,7 +45,7 @@ the preimage of any affine open subset of `Y` is affine. -/ class IsAffineHom {X Y : Scheme} (f : X ⟶ Y) : Prop where isAffine_preimage : ∀ U : Y.Opens, IsAffineOpen U → IsAffineOpen (f ⁻¹ᵁ U) -lemma isAffineOpen.preimage {X Y : Scheme} {U : Y.Opens} (hU : IsAffineOpen U) +lemma IsAffineOpen.preimage {X Y : Scheme} {U : Y.Opens} (hU : IsAffineOpen U) (f : X ⟶ Y) [IsAffineHom f] : IsAffineOpen (f ⁻¹ᵁ U) := IsAffineHom.isAffine_preimage _ hU @@ -66,7 +66,7 @@ instance (priority := 900) [IsAffineHom f] : QuasiCompact f := instance [IsAffineHom f] [IsAffineHom g] : IsAffineHom (f ≫ g) := by constructor intros U hU - rw [Scheme.comp_val_base, Opens.map_comp_obj] + rw [Scheme.comp_base, Opens.map_comp_obj] apply IsAffineHom.isAffine_preimage apply IsAffineHom.isAffine_preimage exact hU @@ -129,7 +129,7 @@ lemma isAffine_of_isAffineOpen_basicOpen (s : Set Γ(X, ⊤)) refine IsIso.comp_isIso' ?_ inferInstance convert isIso_ΓSpec_adjunction_unit_app_basicOpen i.1 using 0 refine congr(IsIso ((ΓSpec.adjunction.unit.app X).app $(?_))) - rw [Opens.openEmbedding_obj_top] + rw [Opens.isOpenEmbedding_obj_top] /-- If `s` is a spanning set of `Γ(X, U)`, such that each `X.basicOpen i` is affine, then `U` is also @@ -158,7 +158,7 @@ instance : HasAffineProperty @IsAffineHom fun X _ _ _ ↦ IsAffine X where rw [Scheme.preimage_basicOpen] exact (isAffineOpen_top X).basicOpen _ · intro X Y _ f S hS hS' - apply_fun Ideal.map (f.1.c.app (op ⊤)) at hS + apply_fun Ideal.map (f.app ⊤) at hS rw [Ideal.map_span, Ideal.map_top] at hS apply isAffine_of_isAffineOpen_basicOpen _ hS have : ∀ i : S, IsAffineOpen (f⁻¹ᵁ Y.basicOpen i.1) := hS' diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean index 9b5b16f7d5f16..50efd7b087298 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean @@ -137,7 +137,7 @@ protected lemma mk' {P : MorphismProperty Scheme} [P.RespectsIso] the target. -/ instance inf (P Q : MorphismProperty Scheme) [IsLocalAtTarget P] [IsLocalAtTarget Q] : IsLocalAtTarget (P ⊓ Q) where - iff_of_openCover' {X Y} f 𝒰 := + iff_of_openCover' {_ _} f 𝒰 := ⟨fun h i ↦ ⟨(iff_of_openCover' f 𝒰).mp h.left i, (iff_of_openCover' f 𝒰).mp h.right i⟩, fun h ↦ ⟨(iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).left), (iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).right)⟩⟩ @@ -222,7 +222,7 @@ protected lemma mk' {P : MorphismProperty Scheme} [P.RespectsIso] the target. -/ instance inf (P Q : MorphismProperty Scheme) [IsLocalAtSource P] [IsLocalAtSource Q] : IsLocalAtSource (P ⊓ Q) where - iff_of_openCover' {X Y} f 𝒰 := + iff_of_openCover' {_ _} f 𝒰 := ⟨fun h i ↦ ⟨(iff_of_openCover' f 𝒰).mp h.left i, (iff_of_openCover' f 𝒰).mp h.right i⟩, fun h ↦ ⟨(iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).left), (iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).right)⟩⟩ @@ -234,6 +234,11 @@ lemma comp {UX : Scheme.{u}} (H : P f) (i : UX ⟶ X) [IsOpenImmersion i] : P (i ≫ f) := (iff_of_openCover' f (X.affineCover.add i)).mp H .none +/-- If `P` is local at the source, then it respects composition on the left with open immersions. -/ +instance respectsLeft_isOpenImmersion {P : MorphismProperty Scheme} + [IsLocalAtSource P] : P.RespectsLeft @IsOpenImmersion where + precomp i _ _ hf := IsLocalAtSource.comp hf i + lemma of_iSup_eq_top {ι} (U : ι → X.Opens) (hU : iSup U = ⊤) (H : ∀ i, P ((U i).ι ≫ f)) : P f := by refine (iff_of_openCover' f @@ -270,6 +275,32 @@ lemma isLocalAtTarget [P.IsMultiplicative] · exact hP _ _ · exact fun H ↦ P.comp_mem _ _ H (of_isOpenImmersion _) +section IsLocalAtSourceAndTarget + +/-- If `P` is local at the source and the target, then restriction on both source and target +preserves `P`. -/ +lemma resLE [IsLocalAtTarget P] {U : Y.Opens} {V : X.Opens} (e : V ≤ f ⁻¹ᵁ U) + (hf : P f) : P (f.resLE U V e) := + IsLocalAtSource.comp (IsLocalAtTarget.restrict hf U) _ + +/-- If `P` is local at the source, local at the target and is stable under post-composition with +open immersions, then `P` can be checked locally around points. -/ +lemma iff_exists_resLE [IsLocalAtTarget P] [P.RespectsRight @IsOpenImmersion] : + P f ↔ ∀ x : X, ∃ (U : Y.Opens) (V : X.Opens) (_ : x ∈ V.1) (e : V ≤ f ⁻¹ᵁ U), + P (f.resLE U V e) := by + refine ⟨fun hf x ↦ ⟨⊤, ⊤, trivial, by simp, resLE _ hf⟩, fun hf ↦ ?_⟩ + choose U V hxU e hf using hf + rw [IsLocalAtSource.iff_of_iSup_eq_top (fun x : X ↦ V x) (P := P)] + · intro x + rw [← Scheme.Hom.resLE_comp_ι _ (e x)] + exact MorphismProperty.RespectsRight.postcomp (Q := @IsOpenImmersion) _ inferInstance _ (hf x) + · rw [eq_top_iff] + rintro x - + simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe] + use x, hxU x + +end IsLocalAtSourceAndTarget + end IsLocalAtSource /-- An `AffineTargetMorphismProperty` is a class of morphisms from an arbitrary scheme into an @@ -323,7 +354,7 @@ theorem arrow_mk_iso_iff theorem respectsIso_mk {P : AffineTargetMorphismProperty} (h₁ : ∀ {X Y Z} (e : X ≅ Y) (f : Y ⟶ Z) [IsAffine Z], P f → P (e.hom ≫ f)) - (h₂ : ∀ {X Y Z} (e : Y ≅ Z) (f : X ⟶ Y) [h : IsAffine Y], + (h₂ : ∀ {X Y Z} (e : Y ≅ Z) (f : X ⟶ Y) [IsAffine Y], P f → @P _ _ (f ≫ e.hom) (isAffine_of_isIso e.inv)) : P.toProperty.RespectsIso := by apply MorphismProperty.RespectsIso.mk @@ -406,7 +437,7 @@ instance (P : AffineTargetMorphismProperty) [P.toProperty.RespectsIso] : rintro ⟨U, hU : IsAffineOpen U⟩; dsimp haveI : IsAffine _ := hU.preimage_of_isIso e.hom rw [morphismRestrict_comp, P.cancel_right_of_respectsIso] - exact H ⟨(Opens.map e.hom.val.base).obj U, hU.preimage_of_isIso e.hom⟩ + exact H ⟨(Opens.map e.hom.base).obj U, hU.preimage_of_isIso e.hom⟩ /-- `HasAffineProperty P Q` is a type class asserting that `P` is local at the target, and over affine diff --git a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean index e0f201805fa3b..52833da5d26b8 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean @@ -3,8 +3,12 @@ Copyright (c) 2023 Jonas van der Schaaf. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston, Christian Merten, Jonas van der Schaaf -/ -import Mathlib.AlgebraicGeometry.Morphisms.QuasiCompact -import Mathlib.AlgebraicGeometry.Morphisms.Preimmersion +import Mathlib.AlgebraicGeometry.Morphisms.Affine +import Mathlib.AlgebraicGeometry.Morphisms.RingHomProperties +import Mathlib.AlgebraicGeometry.Morphisms.FiniteType +import Mathlib.AlgebraicGeometry.Morphisms.IsIso +import Mathlib.AlgebraicGeometry.ResidueField +import Mathlib.AlgebraicGeometry.Properties /-! @@ -19,8 +23,6 @@ is a closed immersion and the induced morphisms of stalks are all surjective. ## TODO -* Show closed immersions of affines are induced by surjective ring maps -* Show closed immersions are stable under pullback * Show closed immersions are precisely the proper monomorphisms * Define closed immersions of locally ringed spaces, where we also assume that the kernel of `O_X → f_*O_Y` is locally generated by sections as an `O_X`-module, and relate it to this file. See @@ -30,7 +32,7 @@ is a closed immersion and the induced morphisms of stalks are all surjective. universe v u -open CategoryTheory +open CategoryTheory TopologicalSpace Opposite namespace AlgebraicGeometry @@ -38,28 +40,33 @@ namespace AlgebraicGeometry topological map is a closed embedding and the induced stalk maps are surjective. -/ @[mk_iff] class IsClosedImmersion {X Y : Scheme} (f : X ⟶ Y) : Prop where - base_closed : ClosedEmbedding f.1.base + base_closed : IsClosedEmbedding f.base surj_on_stalks : ∀ x, Function.Surjective (f.stalkMap x) +lemma Scheme.Hom.isClosedEmbedding {X Y : Scheme} (f : X.Hom Y) + [IsClosedImmersion f] : IsClosedEmbedding f.base := + IsClosedImmersion.base_closed + namespace IsClosedImmersion -lemma closedEmbedding {X Y : Scheme} (f : X ⟶ Y) - [IsClosedImmersion f] : ClosedEmbedding f.1.base := - IsClosedImmersion.base_closed +@[deprecated (since := "2024-10-24")] +alias isClosedEmbedding := Scheme.Hom.isClosedEmbedding +@[deprecated (since := "2024-10-20")] +alias closedEmbedding := isClosedEmbedding -lemma eq_inf : @IsClosedImmersion = (topologically ClosedEmbedding) ⊓ +lemma eq_inf : @IsClosedImmersion = (topologically IsClosedEmbedding) ⊓ stalkwise (fun f ↦ Function.Surjective f) := by ext X Y f rw [isClosedImmersion_iff] rfl lemma iff_isPreimmersion {X Y : Scheme} {f : X ⟶ Y} : - IsClosedImmersion f ↔ IsPreimmersion f ∧ IsClosed (Set.range f.1.base) := by - rw [and_comm, isClosedImmersion_iff, isPreimmersion_iff, ← and_assoc, closedEmbedding_iff, - @and_comm (Embedding _)] + IsClosedImmersion f ↔ IsPreimmersion f ∧ IsClosed (Set.range f.base) := by + rw [and_comm, isClosedImmersion_iff, isPreimmersion_iff, ← and_assoc, isClosedEmbedding_iff, + @and_comm (IsEmbedding _)] lemma of_isPreimmersion {X Y : Scheme} (f : X ⟶ Y) [IsPreimmersion f] - (hf : IsClosed (Set.range f.1.base)) : IsClosedImmersion f := + (hf : IsClosed (Set.range f.base)) : IsClosedImmersion f := iff_isPreimmersion.mpr ⟨‹_›, hf⟩ instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsClosedImmersion f] : IsPreimmersion f := @@ -67,7 +74,7 @@ instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsClosedImmersion f] : /-- Isomorphisms are closed immersions. -/ instance {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : IsClosedImmersion f where - base_closed := Homeomorph.closedEmbedding <| TopCat.homeoOfIso (asIso f.1.base) + base_closed := Homeomorph.isClosedEmbedding <| TopCat.homeoOfIso (asIso f.base) surj_on_stalks := fun _ ↦ (ConcreteCategory.bijective_of_isIso _).2 instance : MorphismProperty.IsMultiplicative @IsClosedImmersion where @@ -75,7 +82,7 @@ instance : MorphismProperty.IsMultiplicative @IsClosedImmersion where comp_mem {X Y Z} f g hf hg := by refine ⟨hg.base_closed.comp hf.base_closed, fun x ↦ ?_⟩ rw [Scheme.stalkMap_comp] - exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.1.1 x)) + exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.base x)) /-- Composition of closed immersions is a closed immersion. -/ instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsClosedImmersion f] @@ -91,7 +98,7 @@ instance respectsIso : MorphismProperty.RespectsIso @IsClosedImmersion := by closed immersion. -/ theorem spec_of_surjective {R S : CommRingCat} (f : R ⟶ S) (h : Function.Surjective f) : IsClosedImmersion (Spec.map f) where - base_closed := PrimeSpectrum.closedEmbedding_comap_of_surjective _ _ h + base_closed := PrimeSpectrum.isClosedEmbedding_comap_of_surjective _ _ h surj_on_stalks x := by haveI : (RingHom.toMorphismProperty (fun f ↦ Function.Surjective f)).RespectsIso := by rw [← RingHom.toMorphismProperty_respectsIso_iff] @@ -110,35 +117,218 @@ instance spec_of_quotient_mk {R : CommRingCat.{u}} (I : Ideal R) : /-- Any morphism between affine schemes that is surjective on global sections is a closed immersion. -/ lemma of_surjective_of_isAffine {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Y) - (h : Function.Surjective (Scheme.Γ.map f.op)) : IsClosedImmersion f := by + (h : Function.Surjective (f.app ⊤)) : IsClosedImmersion f := by rw [MorphismProperty.arrow_mk_iso_iff @IsClosedImmersion (arrowIsoSpecΓOfIsAffine f)] apply spec_of_surjective exact h -/-- If `f ≫ g` is a closed immersion, then `f` is a closed immersion. -/ -theorem of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsClosedImmersion g] +/-- +If `f ≫ g` and `g` are closed immersions, then `f` is a closed immersion. +Also see `IsClosedImmersion.of_comp` for the general version +where `g` is only required to be separated. +-/ +theorem of_comp_isClosedImmersion {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsClosedImmersion g] [IsClosedImmersion (f ≫ g)] : IsClosedImmersion f where base_closed := by - have h := closedEmbedding (f ≫ g) - rw [Scheme.comp_val_base] at h - apply closedEmbedding_of_continuous_injective_closed (Scheme.Hom.continuous f) - · exact Function.Injective.of_comp h.inj - · intro Z hZ - rw [ClosedEmbedding.closed_iff_image_closed (closedEmbedding g), - ← Set.image_comp] - exact ClosedEmbedding.isClosedMap h _ hZ + have h := (f ≫ g).isClosedEmbedding + simp only [Scheme.comp_coeBase, TopCat.coe_comp] at h + refine .of_continuous_injective_isClosedMap (Scheme.Hom.continuous f) h.inj.of_comp ?_ + intro Z hZ + rw [IsClosedEmbedding.closed_iff_image_closed g.isClosedEmbedding, + ← Set.image_comp] + exact h.isClosedMap _ hZ surj_on_stalks x := by have h := (f ≫ g).stalkMap_surjective x - simp_rw [Scheme.comp_val, Scheme.stalkMap_comp] at h + simp_rw [Scheme.stalkMap_comp] at h exact Function.Surjective.of_comp h +instance Spec_map_residue {X : Scheme.{u}} (x) : IsClosedImmersion (Spec.map (X.residue x)) := + IsClosedImmersion.spec_of_surjective (X.residue x) + Ideal.Quotient.mk_surjective + instance {X Y : Scheme} (f : X ⟶ Y) [IsClosedImmersion f] : QuasiCompact f where isCompact_preimage _ _ hU' := base_closed.isCompact_preimage hU' end IsClosedImmersion +section Affine + +variable {X Y : Scheme.{u}} [IsAffine Y] {f : X ⟶ Y} + +open IsClosedImmersion LocallyRingedSpace + +/-- If `f : X ⟶ Y` is a morphism of schemes with quasi-compact source and affine target, `f` +has a closed image and `f` induces an injection on global sections, then +`f` is surjective. -/ +lemma surjective_of_isClosed_range_of_injective [CompactSpace X] + (hfcl : IsClosed (Set.range f.base)) (hfinj : Function.Injective (f.app ⊤)) : + Function.Surjective f.base := by + obtain ⟨I, hI⟩ := (Scheme.eq_zeroLocus_of_isClosed_of_isAffine Y (Set.range f.base)).mp hfcl + let 𝒰 : X.OpenCover := X.affineCover.finiteSubcover + haveI (i : 𝒰.J) : IsAffine (𝒰.obj i) := Scheme.isAffine_affineCover X _ + apply Set.range_iff_surjective.mp + apply hI ▸ (Scheme.zeroLocus_eq_top_iff_subset_nilradical _).mpr + intro s hs + simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup, + Submodule.mem_toAddSubmonoid, SetLike.mem_coe, mem_nilradical, ← IsNilpotent.map_iff hfinj] + refine Scheme.isNilpotent_of_isNilpotent_cover _ 𝒰 (fun i ↦ ?_) + rw [Scheme.isNilpotent_iff_basicOpen_eq_bot] + rw [Scheme.basicOpen_eq_bot_iff_forall_evaluation_eq_zero] + intro x + suffices h : f.base ((𝒰.map i).base x.val) ∉ Y.basicOpen s by + erw [← Scheme.Γevaluation_naturality_apply (𝒰.map i ≫ f)] + simpa only [Scheme.comp_base, TopCat.coe_comp, Function.comp_apply, + Scheme.residueFieldMap_comp, CommRingCat.comp_apply, map_eq_zero, + Scheme.evaluation_eq_zero_iff_not_mem_basicOpen] + exact (Y.mem_zeroLocus_iff I _).mp (hI ▸ Set.mem_range_self ((𝒰.map i).base x.val)) s hs + +/-- If `f : X ⟶ Y` is open, injective, `X` is quasi-compact and `Y` is affine, then `f` is stalkwise +injective if it is injective on global sections. -/ +lemma stalkMap_injective_of_isOpenMap_of_injective [CompactSpace X] + (hfopen : IsOpenMap f.base) (hfinj₁ : Function.Injective f.base) + (hfinj₂ : Function.Injective (f.app ⊤)) (x : X) : + Function.Injective (f.stalkMap x) := by + let φ : Γ(Y, ⊤) ⟶ Γ(X, ⊤) := f.app ⊤ + let 𝒰 : X.OpenCover := X.affineCover.finiteSubcover + have (i : 𝒰.J) : IsAffine (𝒰.obj i) := Scheme.isAffine_affineCover X _ + let res (i : 𝒰.J) : Γ(X, ⊤) ⟶ Γ(𝒰.obj i, ⊤) := (𝒰.map i).app ⊤ + refine stalkMap_injective_of_isAffine _ _ (fun (g : Γ(Y, ⊤)) h ↦ ?_) + rw [TopCat.Presheaf.Γgerm, Scheme.stalkMap_germ_apply] at h + obtain ⟨U, w, (hx : x ∈ U), hg⟩ := + X.toRingedSpace.exists_res_eq_zero_of_germ_eq_zero ⊤ (φ g) ⟨x, trivial⟩ h + obtain ⟨_, ⟨s, rfl⟩, hyv, bsle⟩ := Opens.isBasis_iff_nbhd.mp (isBasis_basicOpen Y) + (show f.base x ∈ ⟨f.base '' U.carrier, hfopen U.carrier U.is_open'⟩ from ⟨x, by simpa⟩) + let W (i : 𝒰.J) : TopologicalSpace.Opens (𝒰.obj i) := (𝒰.obj i).basicOpen ((res i) (φ s)) + have hwle (i : 𝒰.J) : W i ≤ (𝒰.map i)⁻¹ᵁ U := by + show ((𝒰.obj i).basicOpen ((𝒰.map i ≫ f).app ⊤ s)) ≤ _ + rw [← Scheme.preimage_basicOpen, Scheme.comp_coeBase, Opens.map_comp_obj] + refine Scheme.Hom.preimage_le_preimage_of_le _ + (le_trans (f.preimage_le_preimage_of_le bsle) (le_of_eq ?_)) + simp [Set.preimage_image_eq _ hfinj₁] + have h0 (i : 𝒰.J) : (𝒰.map i).appLE _ (W i) (by simp) (φ g) = 0 := by + rw [← Scheme.Hom.appLE_map _ _ (homOfLE <| hwle i).op, ← Scheme.Hom.map_appLE _ le_rfl w.op] + simp only [CommRingCat.coe_comp_of, RingHom.coe_comp, Function.comp_apply] + erw [hg] + simp only [map_zero] + have h1 (i : 𝒰.J) : ∃ n, (res i) (φ (s ^ n * g)) = 0 := by + obtain ⟨n, hn⟩ := exists_of_res_zero_of_qcqs_of_top (s := ((res i) (φ s))) (h0 i) + exact ⟨n, by rwa [map_mul, map_mul, map_pow, map_pow]⟩ + have h2 : ∃ n, ∀ i, (res i) (φ (s ^ n * g)) = 0 := by + choose fn hfn using h1 + refine ⟨Finset.sup Finset.univ fn, fun i ↦ ?_⟩ + rw [map_mul, map_pow, map_mul, map_pow] + simp only [map_mul, map_pow, map_mul, map_pow] at hfn + apply pow_mul_eq_zero_of_le (Finset.le_sup (Finset.mem_univ i)) (hfn i) + obtain ⟨n, hn⟩ := h2 + apply germ_eq_zero_of_pow_mul_eq_zero (U := ⊤) ⟨f.base x, trivial⟩ hyv + rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero] at hfinj₂ + exact hfinj₂ _ (Scheme.zero_of_zero_cover _ _ hn) + +namespace IsClosedImmersion + +/-- If `f` is a closed immersion with affine target such that the induced map on global +sections is injective, `f` is an isomorphism. -/ +theorem isIso_of_injective_of_isAffine [IsClosedImmersion f] + (hf : Function.Injective (f.app ⊤)) : IsIso f := (isIso_iff_stalk_iso f).mpr <| + have : CompactSpace X := f.isClosedEmbedding.compactSpace + have hiso : IsIso f.base := TopCat.isIso_of_bijective_of_isClosedMap _ + ⟨f.isClosedEmbedding.inj, + surjective_of_isClosed_range_of_injective f.isClosedEmbedding.isClosed_range hf⟩ + (f.isClosedEmbedding.isClosedMap) + ⟨hiso, fun x ↦ (ConcreteCategory.isIso_iff_bijective _).mpr + ⟨stalkMap_injective_of_isOpenMap_of_injective ((TopCat.homeoOfIso (asIso f.base)).isOpenMap) + f.isClosedEmbedding.inj hf _, f.stalkMap_surjective x⟩⟩ + +variable (f) + +/-- If `f` is a closed immersion with affine target, the source is affine and +the induced map on global sections is surjective. -/ +theorem isAffine_surjective_of_isAffine [IsClosedImmersion f] : + IsAffine X ∧ Function.Surjective (f.app ⊤) := by + haveI i : IsClosedImmersion f := inferInstance + rw [← affineTargetImageFactorization_comp f] at i ⊢ + haveI := of_surjective_of_isAffine (affineTargetImageInclusion f) + (affineTargetImageInclusion_app_surjective f) + haveI := IsClosedImmersion.of_comp_isClosedImmersion (affineTargetImageFactorization f) + (affineTargetImageInclusion f) + haveI := isIso_of_injective_of_isAffine (affineTargetImageFactorization_app_injective f) + exact ⟨isAffine_of_isIso (affineTargetImageFactorization f), + (ConcreteCategory.bijective_of_isIso + ((affineTargetImageFactorization f).app ⊤)).surjective.comp <| + affineTargetImageInclusion_app_surjective f⟩ + +end IsClosedImmersion + +end Affine + /-- Being a closed immersion is local at the target. -/ instance IsClosedImmersion.isLocalAtTarget : IsLocalAtTarget @IsClosedImmersion := eq_inf ▸ inferInstance +/-- On morphisms with affine target, being a closed immersion is precisely having affine source +and being surjective on global sections. -/ +instance IsClosedImmersion.hasAffineProperty : HasAffineProperty @IsClosedImmersion + (fun X Y f ↦ IsAffine X ∧ Function.Surjective (f.app ⊤)) := by + convert HasAffineProperty.of_isLocalAtTarget @IsClosedImmersion + refine ⟨fun ⟨h₁, h₂⟩ ↦ of_surjective_of_isAffine _ h₂, by apply isAffine_surjective_of_isAffine⟩ + +instance (priority := 900) {X Y : Scheme.{u}} (f : X ⟶ Y) [h : IsClosedImmersion f] : + IsAffineHom f := by + wlog hY : IsAffine Y + · rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := @IsAffineHom) _ + (iSup_affineOpens_eq_top Y)] + intro U + have H : IsClosedImmersion (f ∣_ U) := IsLocalAtTarget.restrict h U + exact this _ U.2 + rw [HasAffineProperty.iff_of_isAffine (P := @IsAffineHom)] + exact (IsClosedImmersion.isAffine_surjective_of_isAffine f).1 + +/-- Being a closed immersion is stable under base change. -/ +lemma IsClosedImmersion.stableUnderBaseChange : + MorphismProperty.StableUnderBaseChange @IsClosedImmersion := by + apply HasAffineProperty.stableUnderBaseChange + haveI := HasAffineProperty.isLocal_affineProperty @IsClosedImmersion + apply AffineTargetMorphismProperty.StableUnderBaseChange.mk + intro X Y S _ _ f g ⟨ha, hsurj⟩ + exact ⟨inferInstance, RingHom.surjective_stableUnderBaseChange.pullback_fst_app_top _ + RingHom.surjective_respectsIso f _ hsurj⟩ + +/-- Closed immersions are locally of finite type. -/ +instance (priority := 900) {X Y : Scheme.{u}} (f : X ⟶ Y) [h : IsClosedImmersion f] : + LocallyOfFiniteType f := by + wlog hY : IsAffine Y + · rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := @LocallyOfFiniteType) _ + (iSup_affineOpens_eq_top Y)] + intro U + have H : IsClosedImmersion (f ∣_ U) := IsLocalAtTarget.restrict h U + exact this _ U.2 + obtain ⟨_, hf⟩ := h.isAffine_surjective_of_isAffine + rw [HasRingHomProperty.iff_of_isAffine (P := @LocallyOfFiniteType)] + exact RingHom.FiniteType.of_surjective (Scheme.Hom.app f ⊤) hf + +/-- A surjective closed immersion is an isomorphism when the target is reduced. -/ +lemma isIso_of_isClosedImmersion_of_surjective {X Y : Scheme.{u}} (f : X ⟶ Y) + [IsClosedImmersion f] [Surjective f] [IsReduced Y] : + IsIso f := by + wlog hY : IsAffine Y + · refine (IsLocalAtTarget.iff_of_openCover (P := .isomorphisms Scheme) Y.affineCover).mpr ?_ + intro i + apply (config := { allowSynthFailures := true }) this + · exact IsClosedImmersion.stableUnderBaseChange.snd _ _ inferInstance + · exact IsLocalAtTarget.of_isPullback (.of_hasPullback f (Y.affineCover.map i)) ‹_› + · exact isReduced_of_isOpenImmersion (Y.affineCover.map i) + · infer_instance + apply IsClosedImmersion.isIso_of_injective_of_isAffine + obtain ⟨hX, hf⟩ := HasAffineProperty.iff_of_isAffine.mp ‹IsClosedImmersion f› + let φ := f.app ⊤ + suffices RingHom.ker φ ≤ nilradical _ by + rwa [nilradical_eq_zero, Submodule.zero_eq_bot, le_bot_iff, + ← RingHom.injective_iff_ker_eq_bot] at this + refine (PrimeSpectrum.zeroLocus_eq_top_iff _).mp ?_ + rw [← range_specComap_of_surjective _ _ hf, Set.top_eq_univ, Set.range_iff_surjective] + have : Surjective (Spec.map (f.app ⊤)) := + (MorphismProperty.arrow_mk_iso_iff @Surjective (arrowIsoSpecΓOfIsAffine f)).mp + (inferInstanceAs (Surjective f)) + exact this.1 + end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean index 878d9b451bd27..1f5c0124ef2b8 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean @@ -123,7 +123,7 @@ instance HasAffineProperty.diagonal_affineProperty_isLocal {Q : AffineTargetMorphismProperty} [Q.IsLocal] : Q.diagonal.IsLocal where respectsIso := inferInstance - to_basicOpen {X Y} _ f r hf := + to_basicOpen {_ Y} _ f r hf := diagonal_of_diagonal_of_isPullback (targetAffineLocally Q) (isPullback_morphismRestrict f (Y.basicOpen r)).flip ((diagonal_iff (targetAffineLocally Q)).mp hf) @@ -165,17 +165,15 @@ theorem universally_isLocalAtTarget (P : MorphismProperty Scheme) apply hP₂ _ (fun i ↦ i₂ ⁻¹ᵁ U i) · rw [← top_le_iff] at hU ⊢ rintro x - - simpa using @hU (i₂.1.base x) trivial + simpa using @hU (i₂.base x) trivial · rintro i - refine H _ ((X'.restrictIsoOfEq ?_).hom ≫ i₁ ∣_ _) (i₂ ∣_ _) _ ?_ + refine H _ ((X'.isoOfEq ?_).hom ≫ i₁ ∣_ _) (i₂ ∣_ _) _ ?_ · exact congr($(h.1.1) ⁻¹ᵁ U i) · rw [← (isPullback_morphismRestrict f _).paste_vert_iff] - · simp only [Scheme.restrictIsoOfEq, Category.assoc, morphismRestrict_ι, - IsOpenImmersion.isoOfRangeEq_hom_fac_assoc] + · simp only [Category.assoc, morphismRestrict_ι, Scheme.isoOfEq_hom_ι_assoc] exact (isPullback_morphismRestrict f' (i₂ ⁻¹ᵁ U i)).paste_vert h · rw [← cancel_mono (Scheme.Opens.ι _)] - simp [IsOpenImmersion.isoOfRangeEq_hom_fac_assoc, Scheme.restrictIsoOfEq, - morphismRestrict_ι_assoc, h.1.1] + simp [morphismRestrict_ι_assoc, h.1.1] end Universally @@ -184,7 +182,7 @@ section Topologically /-- `topologically P` holds for a morphism if the underlying topological map satisfies `P`. -/ def topologically (P : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (_ : α → β), Prop) : - MorphismProperty Scheme.{u} := fun _ _ f => P f.1.base + MorphismProperty Scheme.{u} := fun _ _ f => P f.base variable (P : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (_ : α → β), Prop) @@ -205,7 +203,7 @@ lemma topologically_iso_le MorphismProperty.isomorphisms Scheme ≤ (topologically P) := by intro X Y e (he : IsIso e) have : IsIso e := he - exact hP (TopCat.homeoOfIso (asIso e.val.base)) + exact hP (TopCat.homeoOfIso (asIso e.base)) /-- If a property of maps of topological spaces is satisfied by homeomorphisms and is stable under composition, the induced property on schemes respects isomorphisms. -/ @@ -222,21 +220,35 @@ lemma topologically_respectsIso we may check the corresponding properties on topological spaces. -/ lemma topologically_isLocalAtTarget [(topologically P).RespectsIso] - (hP₂ : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (f : α → β) (s : Set β), - P f → P (s.restrictPreimage f)) + (hP₂ : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (f : α → β) (s : Set β) + (_ : Continuous f) (_ : IsOpen s), P f → P (s.restrictPreimage f)) (hP₃ : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (f : α → β) {ι : Type u} (U : ι → TopologicalSpace.Opens β) (_ : iSup U = ⊤) (_ : Continuous f), (∀ i, P ((U i).carrier.restrictPreimage f)) → P f) : IsLocalAtTarget (topologically P) := by apply IsLocalAtTarget.mk' · intro X Y f U hf - simp_rw [topologically, morphismRestrict_val_base] - exact hP₂ f.val.base U.carrier hf + simp_rw [topologically, morphismRestrict_base] + exact hP₂ f.base U.carrier f.base.2 U.2 hf · intro X Y f ι U hU hf - apply hP₃ f.val.base U hU f.val.base.continuous fun i ↦ ?_ - rw [← morphismRestrict_val_base] + apply hP₃ f.base U hU f.base.continuous fun i ↦ ?_ + rw [← morphismRestrict_base] exact hf i +/-- A variant of `topologically_isLocalAtTarget` +that takes one iff statement instead of two implications. -/ +lemma topologically_isLocalAtTarget' + [(topologically P).RespectsIso] + (hP : ∀ {α β : Type u} [TopologicalSpace α] [TopologicalSpace β] (f : α → β) {ι : Type u} + (U : ι → TopologicalSpace.Opens β) (_ : iSup U = ⊤) (_ : Continuous f), + P f ↔ (∀ i, P ((U i).carrier.restrictPreimage f))) : + IsLocalAtTarget (topologically P) := by + refine topologically_isLocalAtTarget P ?_ (fun f _ U hU hU' ↦ (hP f U hU hU').mpr) + introv hf hs H + refine by simpa using (hP f (![⊤, Opens.mk s hs] ∘ Equiv.ulift) ?_ hf).mp H ⟨1⟩ + rw [← top_le_iff] + exact le_iSup (![⊤, Opens.mk s hs] ∘ Equiv.ulift) ⟨0⟩ + end Topologically /-- `stalkwise P` holds for a morphism if all stalks satisfy `P`. -/ @@ -255,8 +267,8 @@ lemma stalkwise_respectsIso (hP : RingHom.RespectsIso P) : simp only [stalkwise, Scheme.comp_coeBase, TopCat.coe_comp, Function.comp_apply] intro x rw [Scheme.stalkMap_comp] - exact (RingHom.RespectsIso.cancel_right_isIso hP _ _).mpr <| hf (e.val.base x) - postcomp {X Y Z} e (he : IsIso e) f hf := by + exact (RingHom.RespectsIso.cancel_right_isIso hP _ _).mpr <| hf (e.base x) + postcomp {X Y Z} e (he : IsIso _) f hf := by simp only [stalkwise, Scheme.comp_coeBase, TopCat.coe_comp, Function.comp_apply] intro x rw [Scheme.stalkMap_comp] @@ -273,7 +285,7 @@ lemma stalkwiseIsLocalAtTarget_of_respectsIso (hP : RingHom.RespectsIso P) : apply ((RingHom.toMorphismProperty P).arrow_mk_iso_iff <| morphismRestrictStalkMap f U x).mpr <| hf _ · intro X Y f ι U hU hf x - have hy : f.val.base x ∈ iSup U := by rw [hU]; trivial + have hy : f.base x ∈ iSup U := by rw [hU]; trivial obtain ⟨i, hi⟩ := Opens.mem_iSup.mp hy exact ((RingHom.toMorphismProperty P).arrow_mk_iso_iff <| morphismRestrictStalkMap f (U i) ⟨x, hi⟩).mp <| hf i ⟨x, hi⟩ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean index 4424a0eed0994..a5bbcc0abb5f2 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean @@ -57,7 +57,10 @@ instance locallyOfFiniteType_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) theorem locallyOfFiniteType_of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [LocallyOfFiniteType (f ≫ g)] : LocallyOfFiniteType f := - HasRingHomProperty.of_comp (fun f g ↦ RingHom.FiniteType.of_comp_finiteType) ‹_› + HasRingHomProperty.of_comp (fun _ _ ↦ RingHom.FiniteType.of_comp_finiteType) ‹_› + +instance : MorphismProperty.IsMultiplicative @LocallyOfFiniteType where + id_mem _ := inferInstance open scoped TensorProduct in lemma locallyOfFiniteType_stableUnderBaseChange : diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean new file mode 100644 index 0000000000000..981632ad5cb3f --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean @@ -0,0 +1,167 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.Preimmersion +import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion + +/-! + +# Immersions of schemes + +A morphism of schemes `f : X ⟶ Y` is an immersion if the underlying map of topological spaces +is a locally closed embedding, and the induced morphisms of stalks are all surjective. This is true +if and only if it can be factored into a closed immersion followed by an open immersion. + +# Main result +- `isImmersion_iff_exists`: + A morphism is a (locally-closed) immersion if and only if it can be factored into + a closed immersion followed by a (dominant) open immersion. + + +## TODO + +* Show that diagonal morphisms are immersions + +-/ + +universe v u + +open CategoryTheory + +namespace AlgebraicGeometry + +variable {X Y : Scheme.{u}} (f : X ⟶ Y) + +/-- A morphism of schemes `f : X ⟶ Y` is an immersion if +1. the underlying map of topological spaces is an embedding +2. the range of the map is locally closed +3. the induced morphisms of stalks are all surjective. -/ +@[mk_iff] +class IsImmersion (f : X ⟶ Y) extends IsPreimmersion f : Prop where + isLocallyClosed_range : IsLocallyClosed (Set.range f.base) + +lemma Scheme.Hom.isLocallyClosed_range (f : X.Hom Y) [IsImmersion f] : + IsLocallyClosed (Set.range f.base) := + IsImmersion.isLocallyClosed_range + +/-- +Given an immersion `f : X ⟶ Y`, this is the biggest open set `U ⊆ Y` containing the image of `X` +such that `X` is closed in `U`. +-/ +def Scheme.Hom.coborderRange (f : X.Hom Y) [IsImmersion f] : Y.Opens := + ⟨coborder (Set.range f.base), f.isLocallyClosed_range.isOpen_coborder⟩ + +/-- +The first part of the factorization of an immersion `f : X ⟶ Y` to a closed immersion +`f.liftCoborder : X ⟶ f.coborderRange` and a dominant open immersion `f.coborderRange.ι`. +-/ +noncomputable +def Scheme.Hom.liftCoborder (f : X.Hom Y) [IsImmersion f] : X ⟶ f.coborderRange := + IsOpenImmersion.lift f.coborderRange.ι f (by simpa using subset_coborder) + +/-- +Any (locally-closed) immersion can be factored into +a closed immersion followed by a (dominant) open immersion. +-/ +@[reassoc (attr := simp)] +lemma Scheme.Hom.liftCoborder_ι (f : X.Hom Y) [IsImmersion f] : + f.liftCoborder ≫ f.coborderRange.ι = f := + IsOpenImmersion.lift_fac _ _ _ + +instance [IsImmersion f] : IsClosedImmersion f.liftCoborder := by + have : IsPreimmersion (f.liftCoborder ≫ f.coborderRange.ι) := by + simp only [Scheme.Hom.liftCoborder_ι]; infer_instance + have : IsPreimmersion f.liftCoborder := .of_comp f.liftCoborder f.coborderRange.ι + refine .of_isPreimmersion _ ?_ + convert isClosed_preimage_val_coborder + apply Set.image_injective.mpr f.coborderRange.ι.isEmbedding.inj + rw [← Set.range_comp, ← TopCat.coe_comp, ← Scheme.comp_base, f.liftCoborder_ι] + exact (Set.image_preimage_eq_of_subset (by simpa using subset_coborder)).symm + +instance [IsImmersion f] : IsDominant f.coborderRange.ι := by + rw [isDominant_iff, DenseRange, Scheme.Opens.range_ι] + exact dense_coborder + +lemma isImmersion_eq_inf : @IsImmersion = (@IsPreimmersion ⊓ + topologically fun {X Y} _ _ f ↦ IsLocallyClosed (Set.range f) : MorphismProperty Scheme) := by + ext; exact isImmersion_iff _ + +namespace IsImmersion + +instance : IsLocalAtTarget @IsImmersion := by + suffices IsLocalAtTarget (topologically fun {X Y} _ _ f ↦ IsLocallyClosed (Set.range f)) from + isImmersion_eq_inf ▸ inferInstance + apply (config := { allowSynthFailures := true }) topologically_isLocalAtTarget' + · refine { precomp := ?_, postcomp := ?_ } + · intro X Y Z i hi f hf + replace hi : IsIso i := hi + show IsLocallyClosed _ + simpa only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp, + Set.range_iff_surjective.mpr i.surjective, Set.image_univ] + · intro X Y Z i hi f hf + replace hi : IsIso i := hi + show IsLocallyClosed _ + simp only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp] + refine hf.image i.homeomorph.isInducing ?_ + rw [Set.range_iff_surjective.mpr i.surjective] + exact isOpen_univ.isLocallyClosed + · simp_rw [Set.range_restrictPreimage] + exact fun _ _ _ e _ ↦ isLocallyClosed_iff_coe_preimage_of_iSup_eq_top e _ + +instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsOpenImmersion f] : IsImmersion f where + isLocallyClosed_range := f.isOpenEmbedding.2.isLocallyClosed + +instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsClosedImmersion f] : IsImmersion f where + isLocallyClosed_range := f.isClosedEmbedding.2.isLocallyClosed + +instance : MorphismProperty.IsMultiplicative @IsImmersion where + id_mem _ := inferInstance + comp_mem {X Y Z} f g hf hg := by + refine { __ := inferInstanceAs (IsPreimmersion (f ≫ g)), isLocallyClosed_range := ?_ } + simp only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp] + exact f.isLocallyClosed_range.image g.isEmbedding.isInducing g.isLocallyClosed_range + +instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsImmersion f] + [IsImmersion g] : IsImmersion (f ≫ g) := + MorphismProperty.IsStableUnderComposition.comp_mem f g inferInstance inferInstance + +variable {f} in +/-- +A morphism is a (locally-closed) immersion if and only if it can be factored into +a closed immersion followed by an open immersion. +-/ +lemma isImmersion_iff_exists : IsImmersion f ↔ ∃ (Z : Scheme) (g₁ : X ⟶ Z) (g₂ : Z ⟶ Y), + IsClosedImmersion g₁ ∧ IsOpenImmersion g₂ ∧ g₁ ≫ g₂ = f := + ⟨fun _ ↦ ⟨_, f.liftCoborder, f.coborderRange.ι, inferInstance, inferInstance, f.liftCoborder_ι⟩, + fun ⟨_, _, _, _, _, e⟩ ↦ e ▸ inferInstance⟩ + +theorem of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsImmersion g] + [IsImmersion (f ≫ g)] : IsImmersion f where + __ := IsPreimmersion.of_comp f g + isLocallyClosed_range := by + rw [← Set.preimage_image_eq (Set.range _) g.isEmbedding.inj] + have := (f ≫ g).isLocallyClosed_range.preimage g.base.2 + simpa only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp] using this + +theorem comp_iff {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsImmersion g] : + IsImmersion (f ≫ g) ↔ IsImmersion f := + ⟨fun _ ↦ of_comp f g, fun _ ↦ inferInstance⟩ + +lemma stableUnderBaseChange : MorphismProperty.StableUnderBaseChange @IsImmersion := by + intros X Y Y' S f g f' g' H hg + let Z := Limits.pullback f g.coborderRange.ι + let e : Y' ⟶ Z := Limits.pullback.lift g' (f' ≫ g.liftCoborder) (by simpa using H.w.symm) + have : IsClosedImmersion e := by + have := (IsPullback.paste_horiz_iff (.of_hasPullback f g.coborderRange.ι) + (show e ≫ Limits.pullback.snd _ _ = _ from Limits.pullback.lift_snd _ _ _)).mp ?_ + · exact IsClosedImmersion.stableUnderBaseChange this.flip inferInstance + · simpa [e] using H.flip + rw [← Limits.pullback.lift_fst (f := f) (g := g.coborderRange.ι) g' (f' ≫ g.liftCoborder) + (by simpa using H.w.symm)] + infer_instance + +end IsImmersion + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean b/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean index 8626fd8f7cf5f..6f9ee9c19b6e8 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean @@ -30,13 +30,13 @@ lemma isomorphisms_eq_stalkwise : congr 1 ext X Y f exact ⟨fun H ↦ inferInstanceAs (IsIso (TopCat.isoOfHomeo - (H.1.1.toHomeomeomorph_of_surjective H.2)).hom), fun (_ : IsIso f.1.base) ↦ - let e := (TopCat.homeoOfIso <| asIso f.1.base); ⟨e.openEmbedding, e.surjective⟩⟩ + (H.1.1.toHomeomorph_of_surjective H.2)).hom), fun (_ : IsIso f.base) ↦ + let e := (TopCat.homeoOfIso <| asIso f.base); ⟨e.isOpenEmbedding, e.surjective⟩⟩ instance : IsLocalAtTarget (isomorphisms Scheme) := isomorphisms_eq_isOpenImmersion_inf_surjective ▸ inferInstance -instance : HasAffineProperty (isomorphisms Scheme) fun X Y f _ ↦ IsAffine X ∧ IsIso (f.app ⊤) := by +instance : HasAffineProperty (isomorphisms Scheme) fun X _ f _ ↦ IsAffine X ∧ IsIso (f.app ⊤) := by convert HasAffineProperty.of_isLocalAtTarget (isomorphisms Scheme) with X Y f hY exact ⟨fun ⟨_, _⟩ ↦ (arrow_mk_iso_iff (isomorphisms _) (arrowIsoSpecΓOfIsAffine f)).mpr (inferInstanceAs (IsIso (Spec.map (f.app ⊤)))), diff --git a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean index 8c02123e45620..1a4868bc3510b 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean @@ -29,13 +29,13 @@ namespace AlgebraicGeometry variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) theorem isOpenImmersion_iff_stalk {f : X ⟶ Y} : IsOpenImmersion f ↔ - OpenEmbedding f.1.base ∧ ∀ x, IsIso (f.stalkMap x) := by + IsOpenEmbedding f.base ∧ ∀ x, IsIso (f.stalkMap x) := by constructor · intro h; exact ⟨h.1, inferInstance⟩ · rintro ⟨h₁, h₂⟩; exact IsOpenImmersion.of_stalk_iso f h₁ theorem isOpenImmersion_eq_inf : - @IsOpenImmersion = (topologically OpenEmbedding) ⊓ + @IsOpenImmersion = (topologically IsOpenEmbedding) ⊓ stalkwise (fun f ↦ Function.Bijective f) := by ext exact isOpenImmersion_iff_stalk.trans @@ -43,7 +43,7 @@ theorem isOpenImmersion_eq_inf : instance isOpenImmersion_isStableUnderComposition : MorphismProperty.IsStableUnderComposition @IsOpenImmersion where - comp_mem f g _ _ := LocallyRingedSpace.IsOpenImmersion.comp f g + comp_mem f g _ _ := LocallyRingedSpace.IsOpenImmersion.comp f.toLRSHom g.toLRSHom instance isOpenImmersion_respectsIso : MorphismProperty.RespectsIso @IsOpenImmersion := by apply MorphismProperty.respectsIso_of_isStableUnderComposition @@ -56,7 +56,8 @@ instance : IsLocalAtTarget (stalkwise (fun f ↦ Function.Bijective f)) := by rw [RingHom.toMorphismProperty_respectsIso_iff] convert (inferInstanceAs (MorphismProperty.isomorphisms CommRingCat).RespectsIso) ext - exact (ConcreteCategory.isIso_iff_bijective _).symm + -- Regression in #17583: have to specify C explicitly below. + exact (ConcreteCategory.isIso_iff_bijective (C := CommRingCat) _).symm instance isOpenImmersion_isLocalAtTarget : IsLocalAtTarget @IsOpenImmersion := isOpenImmersion_eq_inf ▸ inferInstance diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean index b9472fc3ea550..1cf0aeb9c2a52 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean @@ -5,6 +5,7 @@ Authors: Andrew Yang -/ import Mathlib.AlgebraicGeometry.Morphisms.UnderlyingMap import Mathlib.RingTheory.RingHom.Surjective +import Mathlib.RingTheory.SurjectiveOnStalks /-! @@ -33,18 +34,21 @@ namespace AlgebraicGeometry topological spaces is an embedding and the induced morphisms of stalks are all surjective. -/ @[mk_iff] class IsPreimmersion {X Y : Scheme} (f : X ⟶ Y) : Prop where - base_embedding : Embedding f.1.base + base_embedding : IsEmbedding f.base surj_on_stalks : ∀ x, Function.Surjective (f.stalkMap x) -lemma Scheme.Hom.embedding {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] : Embedding f.1.base := +lemma Scheme.Hom.isEmbedding {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] : IsEmbedding f.base := IsPreimmersion.base_embedding +@[deprecated (since := "2024-10-26")] +alias Scheme.Hom.embedding := Scheme.Hom.isEmbedding + lemma Scheme.Hom.stalkMap_surjective {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] (x) : Function.Surjective (f.stalkMap x) := IsPreimmersion.surj_on_stalks x lemma isPreimmersion_eq_inf : - @IsPreimmersion = topologically Embedding ⊓ stalkwise (Function.Surjective ·) := by + @IsPreimmersion = topologically IsEmbedding ⊓ stalkwise (Function.Surjective ·) := by ext rw [isPreimmersion_iff] rfl @@ -60,7 +64,7 @@ instance : IsLocalAtTarget @IsPreimmersion := isPreimmersion_eq_inf ▸ inferInstance instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsOpenImmersion f] : IsPreimmersion f where - base_embedding := f.openEmbedding.toEmbedding + base_embedding := f.isOpenEmbedding.isEmbedding surj_on_stalks _ := (ConcreteCategory.bijective_of_isIso _).2 instance : MorphismProperty.IsMultiplicative @IsPreimmersion where @@ -68,7 +72,7 @@ instance : MorphismProperty.IsMultiplicative @IsPreimmersion where comp_mem {X Y Z} f g hf hg := by refine ⟨hg.base_embedding.comp hf.base_embedding, fun x ↦ ?_⟩ rw [Scheme.stalkMap_comp] - exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.1.1 x)) + exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.base x)) instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsPreimmersion f] [IsPreimmersion g] : IsPreimmersion (f ≫ g) := @@ -78,14 +82,14 @@ instance (priority := 900) {X Y} (f : X ⟶ Y) [IsPreimmersion f] : Mono f := by refine (Scheme.forgetToLocallyRingedSpace ⋙ LocallyRingedSpace.forgetToSheafedSpace).mono_of_mono_map ?_ apply SheafedSpace.mono_of_base_injective_of_stalk_epi - · exact f.embedding.inj + · exact f.isEmbedding.inj · exact fun x ↦ ConcreteCategory.epi_of_surjective _ (f.stalkMap_surjective x) theorem of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsPreimmersion g] [IsPreimmersion (f ≫ g)] : IsPreimmersion f where base_embedding := by - have h := (f ≫ g).embedding - rwa [← g.embedding.of_comp_iff] + have h := (f ≫ g).isEmbedding + rwa [← g.isEmbedding.of_comp_iff] surj_on_stalks x := by have h := (f ≫ g).stalkMap_surjective x rw [Scheme.stalkMap_comp] at h @@ -95,6 +99,32 @@ theorem comp_iff {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsPreimmersion g] IsPreimmersion (f ≫ g) ↔ IsPreimmersion f := ⟨fun _ ↦ of_comp f g, fun _ ↦ inferInstance⟩ +lemma Spec_map_iff {R S : CommRingCat.{u}} (f : R ⟶ S) : + IsPreimmersion (Spec.map f) ↔ IsEmbedding (PrimeSpectrum.comap f) ∧ f.SurjectiveOnStalks := by + haveI : (RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).RespectsIso := by + rw [← RingHom.toMorphismProperty_respectsIso_iff] + exact RingHom.surjective_respectsIso + refine ⟨fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩, fun ⟨h₁, h₂⟩ ↦ ⟨h₁, fun (x : PrimeSpectrum S) ↦ ?_⟩⟩ + · intro p hp + let e := Scheme.arrowStalkMapSpecIso f ⟨p, hp⟩ + apply ((RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).arrow_mk_iso_iff e).mp + exact h₂ ⟨p, hp⟩ + · let e := Scheme.arrowStalkMapSpecIso f x + apply ((RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).arrow_mk_iso_iff e).mpr + exact h₂ x.asIdeal x.isPrime + +lemma mk_Spec_map {R S : CommRingCat.{u}} {f : R ⟶ S} + (h₁ : IsEmbedding (PrimeSpectrum.comap f)) (h₂ : f.SurjectiveOnStalks) : + IsPreimmersion (Spec.map f) := + (Spec_map_iff f).mpr ⟨h₁, h₂⟩ + +lemma of_isLocalization {R S : Type u} [CommRing R] (M : Submonoid R) [CommRing S] + [Algebra R S] [IsLocalization M S] : + IsPreimmersion (Spec.map (CommRingCat.ofHom <| algebraMap R S)) := + IsPreimmersion.mk_Spec_map + (PrimeSpectrum.localization_comap_isEmbedding (R := R) S M) + (RingHom.surjectiveOnStalks_of_isLocalization (M := M) S) + end IsPreimmersion end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean b/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean new file mode 100644 index 0000000000000..b54565bfb3af8 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean @@ -0,0 +1,69 @@ +/- +Copyright (c) 2024 Christian Merten, Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten, Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.Separated +import Mathlib.AlgebraicGeometry.Morphisms.UniversallyClosed +import Mathlib.AlgebraicGeometry.Morphisms.FiniteType + +/-! + +# Proper morphisms + +A morphism of schemes is proper if it is separated, universally closed and (locally) of finite type. +Note that we don't require quasi-compact, since this is implied by universally closed (TODO). + +-/ + + +noncomputable section + +open CategoryTheory + +universe u + +namespace AlgebraicGeometry + +variable {X Y : Scheme.{u}} (f : X ⟶ Y) + +/-- A morphism is proper if it is separated, universally closed and locally of finite type. -/ +@[mk_iff] +class IsProper extends IsSeparated f, UniversallyClosed f, LocallyOfFiniteType f : Prop where + +lemma isProper_eq : @IsProper = + (@IsSeparated ⊓ @UniversallyClosed : MorphismProperty Scheme) ⊓ @LocallyOfFiniteType := by + ext X Y f + rw [isProper_iff, ← and_assoc] + rfl + +namespace IsProper + +instance : MorphismProperty.RespectsIso @IsProper := by + rw [isProper_eq] + infer_instance + +instance stableUnderComposition : MorphismProperty.IsStableUnderComposition @IsProper := by + rw [isProper_eq] + infer_instance + +instance : MorphismProperty.IsMultiplicative @IsProper := by + rw [isProper_eq] + infer_instance + +instance (priority := 900) [IsClosedImmersion f] : IsProper f where + +lemma stableUnderBaseChange : MorphismProperty.StableUnderBaseChange @IsProper := by + rw [isProper_eq] + exact MorphismProperty.StableUnderBaseChange.inf + (MorphismProperty.StableUnderBaseChange.inf + IsSeparated.stableUnderBaseChange universallyClosed_stableUnderBaseChange) + locallyOfFiniteType_stableUnderBaseChange + +instance : IsLocalAtTarget @IsProper := by + rw [isProper_eq] + infer_instance + +end IsProper + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean index cf3a6124cc51f..13bfe53b9c827 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean @@ -38,26 +38,26 @@ of quasi-compact open sets are quasi-compact. @[mk_iff] class QuasiCompact (f : X ⟶ Y) : Prop where /-- Preimage of compact open set under a quasi-compact morphism between schemes is compact. -/ - isCompact_preimage : ∀ U : Set Y, IsOpen U → IsCompact U → IsCompact (f.1.base ⁻¹' U) + isCompact_preimage : ∀ U : Set Y, IsOpen U → IsCompact U → IsCompact (f.base ⁻¹' U) -theorem quasiCompact_iff_spectral : QuasiCompact f ↔ IsSpectralMap f.1.base := +theorem quasiCompact_iff_spectral : QuasiCompact f ↔ IsSpectralMap f.base := ⟨fun ⟨h⟩ => ⟨by fun_prop, h⟩, fun h => ⟨h.2⟩⟩ instance (priority := 900) quasiCompact_of_isIso {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : QuasiCompact f := by constructor intro U _ hU' - convert hU'.image (inv f.1.base).continuous_toFun using 1 + convert hU'.image (inv f.base).continuous_toFun using 1 rw [Set.image_eq_preimage_of_inverse] · delta Function.LeftInverse - exact IsIso.inv_hom_id_apply f.1.base - · exact IsIso.hom_inv_id_apply f.1.base + exact IsIso.inv_hom_id_apply f.base + · exact IsIso.hom_inv_id_apply f.base instance quasiCompact_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [QuasiCompact f] [QuasiCompact g] : QuasiCompact (f ≫ g) := by constructor intro U hU hU' - rw [Scheme.comp_val_base, TopCat.coe_comp, Set.preimage_comp] + rw [Scheme.comp_base, TopCat.coe_comp, Set.preimage_comp] apply QuasiCompact.isCompact_preimage · exact Continuous.isOpen_preimage (by fun_prop) _ hU apply QuasiCompact.isCompact_preimage <;> assumption @@ -126,9 +126,9 @@ instance : HasAffineProperty @QuasiCompact (fun X _ _ _ ↦ CompactSpace X) wher isLocal_affineProperty := by constructor · apply AffineTargetMorphismProperty.respectsIso_mk <;> rintro X Y Z e _ _ H - exacts [@Homeomorph.compactSpace _ _ _ _ H (TopCat.homeoOfIso (asIso e.inv.1.base)), H] + exacts [@Homeomorph.compactSpace _ _ _ _ H (TopCat.homeoOfIso (asIso e.inv.base)), H] · introv _ H - change CompactSpace ((Opens.map f.val.base).obj (Y.basicOpen r)) + change CompactSpace ((Opens.map f.base).obj (Y.basicOpen r)) rw [Scheme.preimage_basicOpen f r] erw [← isCompact_iff_compactSpace] rw [← isCompact_univ_iff] at H @@ -137,7 +137,7 @@ instance : HasAffineProperty @QuasiCompact (fun X _ _ _ ↦ CompactSpace X) wher · rintro X Y H f S hS hS' rw [← IsAffineOpen.basicOpen_union_eq_self_iff] at hS · rw [← isCompact_univ_iff] - change IsCompact ((Opens.map f.val.base).obj ⊤).1 + change IsCompact ((Opens.map f.base).obj ⊤).1 rw [← hS] dsimp [Opens.map] simp only [Opens.iSup_mk, Opens.coe_mk, Set.preimage_iUnion] @@ -272,6 +272,13 @@ lemma Scheme.isNilpotent_iff_basicOpen_eq_bot_of_isCompact {X : Scheme.{u}} rw [mul_one] at hn use n +/-- A global section of a quasi-compact scheme is nilpotent if and only if its associated +basic open is empty. -/ +lemma Scheme.isNilpotent_iff_basicOpen_eq_bot {X : Scheme.{u}} + [CompactSpace X] (f : Γ(X, ⊤)) : + IsNilpotent f ↔ X.basicOpen f = ⊥ := + isNilpotent_iff_basicOpen_eq_bot_of_isCompact (U := ⊤) (CompactSpace.isCompact_univ) f + /-- The zero locus of a set of sections over a compact open of a scheme is `X` if and only if `s` is contained in the nilradical of `Γ(X, U)`. -/ lemma Scheme.zeroLocus_eq_top_iff_subset_nilradical_of_isCompact {X : Scheme.{u}} {U : X.Opens} @@ -280,4 +287,11 @@ lemma Scheme.zeroLocus_eq_top_iff_subset_nilradical_of_isCompact {X : Scheme.{u} simp [Scheme.zeroLocus_def, ← Scheme.isNilpotent_iff_basicOpen_eq_bot_of_isCompact hU, ← mem_nilradical, Set.subset_def] +/-- The zero locus of a set of sections over a compact open of a scheme is `X` if and only if +`s` is contained in the nilradical of `Γ(X, U)`. -/ +lemma Scheme.zeroLocus_eq_top_iff_subset_nilradical {X : Scheme.{u}} + [CompactSpace X] (s : Set Γ(X, ⊤)) : + X.zeroLocus s = ⊤ ↔ s ⊆ nilradical Γ(X, ⊤) := + zeroLocus_eq_top_iff_subset_nilradical_of_isCompact (U := ⊤) (CompactSpace.isCompact_univ) s + end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean index fc114dd60f6a8..76731289cf0e1 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean @@ -85,7 +85,7 @@ theorem quasiCompact_affineProperty_iff_quasiSeparatedSpace {X Y : Scheme} [IsAf let g : pullback U.1.ι V.1.ι ⟶ X := pullback.fst _ _ ≫ U.1.ι -- Porting note: `inferInstance` does not work here have : IsOpenImmersion g := PresheafedSpace.IsOpenImmersion.comp _ _ - have e := Homeomorph.ofEmbedding _ this.base_open.toEmbedding + have e := Homeomorph.ofIsEmbedding _ this.base_open.isEmbedding rw [IsOpenImmersion.range_pullback_to_base_of_left] at e erw [Subtype.range_coe, Subtype.range_coe] at e rw [isCompact_iff_compactSpace] @@ -94,7 +94,7 @@ theorem quasiCompact_affineProperty_iff_quasiSeparatedSpace {X Y : Scheme} [IsAf let g : pullback f₁ f₂ ⟶ X := pullback.fst _ _ ≫ f₁ -- Porting note: `inferInstance` does not work here have : IsOpenImmersion g := PresheafedSpace.IsOpenImmersion.comp _ _ - have e := Homeomorph.ofEmbedding _ this.base_open.toEmbedding + have e := Homeomorph.ofIsEmbedding _ this.base_open.isEmbedding rw [IsOpenImmersion.range_pullback_to_base_of_left] at e simp_rw [isCompact_iff_compactSpace] at H exact @@ -247,7 +247,7 @@ theorem exists_eq_pow_mul_of_isCompact_of_isQuasiSeparated (X : Scheme.{u}) (U : use 0, f refine @Subsingleton.elim _ (CommRingCat.subsingleton_of_isTerminal (X.sheaf.isTerminalOfEqEmpty ?_)) _ _ - erw [eq_bot_iff] + rw [eq_bot_iff] exact X.basicOpen_le f · -- Given `f : 𝒪(S ∪ U), x : 𝒪(X_f)`, we need to show that `f ^ n * x` is the restriction of -- some `y : 𝒪(S ∪ U)` for some `n : ℕ`. @@ -275,13 +275,13 @@ theorem exists_eq_pow_mul_of_isCompact_of_isQuasiSeparated (X : Scheme.{u}) (U : have hs₁ : ∀ i : s, i.1.1 ≤ S := by intro i; change (i : X.Opens) ≤ S refine le_trans ?_ (inf_le_left (b := U.1)) - erw [hs] + rw [hs] -- Porting note: have to add argument explicitly exact @le_iSup X.Opens s _ (fun (i : s) => (i : X.Opens)) i have hs₂ : ∀ i : s, i.1.1 ≤ U.1 := by intro i; change (i : X.Opens) ≤ U refine le_trans ?_ (inf_le_right (a := S)) - erw [hs] + rw [hs] -- Porting note: have to add argument explicitly exact @le_iSup X.Opens s _ (fun (i : s) => (i : X.Opens)) i -- On each affine open in the intersection, we have `f ^ (n + n₂) * y₁ = f ^ (n + n₁) * y₂` @@ -297,7 +297,7 @@ theorem exists_eq_pow_mul_of_isCompact_of_isQuasiSeparated (X : Scheme.{u}) (U : X.presheaf.map (homOfLE <| inf_le_right).op (X.presheaf.map (homOfLE le_sup_right).op f ^ (Finset.univ.sup n + n₁) * y₂) := by fapply X.sheaf.eq_of_locally_eq' fun i : s => i.1.1 - · refine fun i => homOfLE ?_; erw [hs] + · refine fun i => homOfLE ?_; rw [hs] -- Porting note: have to add argument explicitly exact @le_iSup X.Opens s _ (fun (i : s) => (i : X.Opens)) i · exact le_of_eq hs @@ -347,11 +347,37 @@ theorem is_localization_basicOpen_of_qcqs {X : Scheme} {U : X.Opens} (hU : IsCom refine ⟨⟨_, n, rfl⟩, ?_⟩ simpa [mul_comm z] using e +lemma exists_of_res_eq_of_qcqs {X : Scheme.{u}} {U : TopologicalSpace.Opens X} + (hU : IsCompact U.carrier) (hU' : IsQuasiSeparated U.carrier) + {f g s : Γ(X, U)} (hfg : f |_ X.basicOpen s = g |_ X.basicOpen s) : + ∃ n, s ^ n * f = s ^ n * g := by + obtain ⟨n, hc⟩ := (is_localization_basicOpen_of_qcqs hU hU' s).exists_of_eq s hfg + use n + +lemma exists_of_res_eq_of_qcqs_of_top {X : Scheme.{u}} [CompactSpace X] [QuasiSeparatedSpace X] + {f g s : Γ(X, ⊤)} (hfg : f |_ X.basicOpen s = g |_ X.basicOpen s) : + ∃ n, s ^ n * f = s ^ n * g := + exists_of_res_eq_of_qcqs (U := ⊤) CompactSpace.isCompact_univ isQuasiSeparated_univ hfg + +lemma exists_of_res_zero_of_qcqs {X : Scheme.{u}} {U : TopologicalSpace.Opens X} + (hU : IsCompact U.carrier) (hU' : IsQuasiSeparated U.carrier) + {f s : Γ(X, U)} (hf : f |_ X.basicOpen s = 0) : + ∃ n, s ^ n * f = 0 := by + suffices h : ∃ n, s ^ n * f = s ^ n * 0 by + simpa using h + apply exists_of_res_eq_of_qcqs hU hU' + simpa + +lemma exists_of_res_zero_of_qcqs_of_top {X : Scheme} [CompactSpace X] [QuasiSeparatedSpace X] + {f s : Γ(X, ⊤)} (hf : f |_ X.basicOpen s = 0) : + ∃ n, s ^ n * f = 0 := + exists_of_res_zero_of_qcqs (U := ⊤) CompactSpace.isCompact_univ isQuasiSeparated_univ hf + /-- If `U` is qcqs, then `Γ(X, D(f)) ≃ Γ(X, U)_f` for every `f : Γ(X, U)`. This is known as the **Qcqs lemma** in [R. Vakil, *The rising sea*][RisingSea]. -/ theorem isIso_ΓSpec_adjunction_unit_app_basicOpen {X : Scheme} [CompactSpace X] [QuasiSeparatedSpace X] (f : X.presheaf.obj (op ⊤)) : - IsIso ((ΓSpec.adjunction.unit.app X).val.c.app (op (PrimeSpectrum.basicOpen f))) := by + IsIso ((ΓSpec.adjunction.unit.app X).c.app (op (PrimeSpectrum.basicOpen f))) := by refine @IsIso.of_isIso_comp_right _ _ _ _ _ _ (X.presheaf.map (eqToHom (Scheme.toSpecΓ_preimage_basicOpen _ _).symm).op) _ ?_ rw [ConcreteCategory.isIso_iff_bijective, CommRingCat.forget_map] diff --git a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean index 1a867be2b4d2a..06f83cb90fe8a 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean @@ -5,6 +5,7 @@ Authors: Andrew Yang -/ import Mathlib.AlgebraicGeometry.Morphisms.Basic import Mathlib.RingTheory.LocalProperties.Basic +import Mathlib.RingTheory.RingHom.Locally /-! @@ -162,6 +163,63 @@ theorem sourceAffineLocally_isLocal (h₁ : RingHom.RespectsIso P) rwa [IsAffineOpen.appLE_eq_away_map f (isAffineOpen_top Y) U.2, ← h₁.is_localization_away_iff] at this +open RingHom + +variable {P} {X Y : Scheme.{u}} {f : X ⟶ Y} + +/-- If `P` holds for `f` over affine opens `U₂` of `Y` and `V₂` of `X` and `U₁` (resp. `V₁`) are +open affine neighborhoods of `x` (resp. `f.base x`), then `P` also holds for `f` +over some basic open of `U₁` (resp. `V₁`). -/ +lemma exists_basicOpen_le_appLE_of_appLE_of_isAffine + (hPa : StableUnderCompositionWithLocalizationAway P) (hPl : LocalizationPreserves P) + (x : X) (U₁ : Y.affineOpens) (U₂ : Y.affineOpens) (V₁ : X.affineOpens) (V₂ : X.affineOpens) + (hx₁ : x ∈ V₁.1) (hx₂ : x ∈ V₂.1) (e₂ : V₂.1 ≤ f ⁻¹ᵁ U₂.1) (h₂ : P (f.appLE U₂ V₂ e₂)) + (hfx₁ : f.base x ∈ U₁.1) : + ∃ (r : Γ(Y, U₁)) (s : Γ(X, V₁)) (_ : x ∈ X.basicOpen s) + (e : X.basicOpen s ≤ f ⁻¹ᵁ Y.basicOpen r), P (f.appLE (Y.basicOpen r) (X.basicOpen s) e) := by + obtain ⟨r, r', hBrr', hBfx⟩ := exists_basicOpen_le_affine_inter U₁.2 U₂.2 (f.base x) + ⟨hfx₁, e₂ hx₂⟩ + have ha : IsAffineOpen (X.basicOpen (f.appLE U₂ V₂ e₂ r')) := V₂.2.basicOpen _ + have hxa : x ∈ X.basicOpen (f.appLE U₂ V₂ e₂ r') := by + simpa [Scheme.Hom.appLE, ← Scheme.preimage_basicOpen] using And.intro hx₂ (hBrr' ▸ hBfx) + obtain ⟨s, s', hBss', hBx⟩ := exists_basicOpen_le_affine_inter V₁.2 ha x ⟨hx₁, hxa⟩ + haveI := V₂.2.isLocalization_basicOpen (f.appLE U₂ V₂ e₂ r') + haveI := U₂.2.isLocalization_basicOpen r' + haveI := ha.isLocalization_basicOpen s' + have ers : X.basicOpen s ≤ f ⁻¹ᵁ Y.basicOpen r := by + rw [hBss', hBrr'] + apply le_trans (X.basicOpen_le _) + simp [Scheme.Hom.appLE] + have heq : f.appLE (Y.basicOpen r') (X.basicOpen s') (hBrr' ▸ hBss' ▸ ers) = + f.appLE (Y.basicOpen r') (X.basicOpen (f.appLE U₂ V₂ e₂ r')) (by simp [Scheme.Hom.appLE]) ≫ + algebraMap _ _ := by + simp only [Scheme.Hom.appLE, homOfLE_leOfHom, CommRingCat.comp_apply, Category.assoc] + congr + apply X.presheaf.map_comp + refine ⟨r, s, hBx, ers, ?_⟩ + · rw [f.appLE_congr _ hBrr' hBss' P, heq] + apply hPa.left _ s' _ + rw [U₂.2.appLE_eq_away_map f V₂.2] + exact hPl.away _ h₂ + +/-- If `P` holds for `f` over affine opens `U₂` of `Y` and `V₂` of `X` and `U₁` (resp. `V₁`) are +open neighborhoods of `x` (resp. `f.base x`), then `P` also holds for `f` over some affine open +`U'` of `Y` (resp. `V'` of `X`) that is contained in `U₁` (resp. `V₁`). -/ +lemma exists_affineOpens_le_appLE_of_appLE + (hPa : StableUnderCompositionWithLocalizationAway P) (hPl : LocalizationPreserves P) + (x : X) (U₁ : Y.Opens) (U₂ : Y.affineOpens) (V₁ : X.Opens) (V₂ : X.affineOpens) + (hx₁ : x ∈ V₁) (hx₂ : x ∈ V₂.1) (e₂ : V₂.1 ≤ f ⁻¹ᵁ U₂.1) (h₂ : P (f.appLE U₂ V₂ e₂)) + (hfx₁ : f.base x ∈ U₁.1) : + ∃ (U' : Y.affineOpens) (V' : X.affineOpens) (_ : U'.1 ≤ U₁) (_ : V'.1 ≤ V₁) (_ : x ∈ V'.1) + (e : V'.1 ≤ f⁻¹ᵁ U'.1), P (f.appLE U' V' e) := by + obtain ⟨r, hBr, hBfx⟩ := U₂.2.exists_basicOpen_le ⟨f.base x, hfx₁⟩ (e₂ hx₂) + obtain ⟨s, hBs, hBx⟩ := V₂.2.exists_basicOpen_le ⟨x, hx₁⟩ hx₂ + obtain ⟨r', s', hBx', e', hf'⟩ := exists_basicOpen_le_appLE_of_appLE_of_isAffine hPa hPl x + ⟨Y.basicOpen r, U₂.2.basicOpen _⟩ U₂ ⟨X.basicOpen s, V₂.2.basicOpen _⟩ V₂ hBx hx₂ e₂ h₂ hBfx + exact ⟨⟨Y.basicOpen r', (U₂.2.basicOpen _).basicOpen _⟩, + ⟨X.basicOpen s', (V₂.2.basicOpen _).basicOpen _⟩, le_trans (Y.basicOpen_le _) hBr, + le_trans (X.basicOpen_le _) hBs, hBx', e', hf'⟩ + end affineLocally /-- @@ -182,6 +240,17 @@ namespace HasRingHomProperty variable (P : MorphismProperty Scheme.{u}) {Q} [HasRingHomProperty P Q] variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) +lemma copy {P' : MorphismProperty Scheme.{u}} + {Q' : ∀ {R S : Type u} [CommRing R] [CommRing S], (R →+* S) → Prop} + (e : P = P') (e' : ∀ {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S), Q f ↔ Q' f) : + HasRingHomProperty P' Q' := by + subst e + have heq : @Q = @Q' := by + ext R S _ _ f + exact (e' f) + rw [← heq] + infer_instance + lemma eq_affineLocally : P = affineLocally Q := eq_affineLocally' @[local instance] @@ -192,6 +261,9 @@ lemma HasAffineProperty : HasAffineProperty P (sourceAffineLocally Q) where (isLocal_ringHomProperty P).ofLocalizationSpan eq_targetAffineLocally' := eq_affineLocally P +/- This is only `inferInstance` because of the `@[local instance]` on `HasAffineProperty` above. -/ +instance (priority := 900) : IsLocalAtTarget P := inferInstance + theorem appLE (H : P f) (U : Y.affineOpens) (V : X.affineOpens) (e) : Q (f.appLE U V e) := by rw [eq_affineLocally P, affineLocally_iff_affineOpens_le] at H exact H _ _ _ @@ -365,6 +437,114 @@ lemma stableUnderBaseChange (hP : RingHom.StableUnderBaseChange Q) : P.StableUnd rw [iff_of_isAffine (P := P)] at H ⊢ exact hP.pullback_fst_app_top _ (isLocal_ringHomProperty P).respectsIso _ _ H +include Q in +private lemma respects_isOpenImmersion_aux {X Y : Scheme.{u}} [IsAffine Y] {U : Y.Opens} + (f : X ⟶ U.toScheme) (hf : P f) : P (f ≫ U.ι) := by + wlog hYa : ∃ (a : Γ(Y, ⊤)), U = Y.basicOpen a generalizing X Y + · obtain ⟨(Us : Set Y.Opens), hUs, heq⟩ := Opens.isBasis_iff_cover.mp (isBasis_basicOpen Y) U + let V (s : Us) : X.Opens := f ⁻¹ᵁ U.ι ⁻¹ᵁ s + rw [IsLocalAtSource.iff_of_iSup_eq_top (P := P) V] + · intro s + let f' : (V s).toScheme ⟶ U.ι ⁻¹ᵁ s := f ∣_ U.ι ⁻¹ᵁ s + have hf' : P f' := IsLocalAtTarget.restrict hf _ + let e : (U.ι ⁻¹ᵁ s).toScheme ≅ s := IsOpenImmersion.isoOfRangeEq ((U.ι ⁻¹ᵁ s).ι ≫ U.ι) s.1.ι + (by simpa [Set.range_comp, Set.image_preimage_eq_iff, heq] using le_sSup s.2) + have heq : (V s).ι ≫ f ≫ U.ι = f' ≫ e.hom ≫ s.1.ι := by + simp only [IsOpenImmersion.isoOfRangeEq_hom_fac, f', e, morphismRestrict_ι_assoc] + rw [heq, ← Category.assoc] + refine this _ ?_ ?_ + · rwa [P.cancel_right_of_respectsIso] + · obtain ⟨a, ha⟩ := hUs s.2 + use a, ha.symm + · apply f.preimage_iSup_eq_top + apply U.ι.image_injective + simp only [U.ι.image_iSup, U.ι.image_preimage_eq_opensRange_inter, Scheme.Opens.opensRange_ι] + conv_rhs => rw [Scheme.Hom.image_top_eq_opensRange, Scheme.Opens.opensRange_ι, heq] + ext : 1 + have (i : Us) : U ⊓ i.1 = i.1 := by simp [heq, le_sSup i.property] + simp [this] + obtain ⟨a, rfl⟩ := hYa + wlog hX : IsAffine X generalizing X Y + · rw [IsLocalAtSource.iff_of_iSup_eq_top (P := P) _ (iSup_affineOpens_eq_top _)] + intro V + rw [← Category.assoc] + exact this _ _ (IsLocalAtSource.comp hf _) V.2 + rw [HasRingHomProperty.iff_of_isAffine (P := P)] at hf ⊢ + exact (isLocal_ringHomProperty P).StableUnderCompositionWithLocalizationAway.right _ a _ hf + +/-- Any property of scheme morphisms induced by a property of ring homomorphisms is stable +under composition with open immersions. -/ +instance respects_isOpenImmersion : P.Respects @IsOpenImmersion where + postcomp {X Y Z} i hi f hf := by + wlog hZ : IsAffine Z generalizing X Y Z + · rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := P) _ (iSup_affineOpens_eq_top _)] + intro U + rw [morphismRestrict_comp] + exact this _ inferInstance _ (IsLocalAtTarget.restrict hf _) U.2 + let e : Y ≅ i.opensRange.toScheme := IsOpenImmersion.isoOfRangeEq i i.opensRange.ι (by simp) + rw [show f ≫ i = f ≫ e.hom ≫ i.opensRange.ι by simp [e], ← Category.assoc] + exact respects_isOpenImmersion_aux _ (by rwa [P.cancel_right_of_respectsIso]) + +open RingHom + +omit [HasRingHomProperty P Q] in +/-- If `P` is induced by `Locally Q`, it suffices to check `Q` on affine open sets locally around +points of the source. -/ +lemma iff_exists_appLE_locally (hQi : RespectsIso Q) [HasRingHomProperty P (Locally Q)] : + P f ↔ ∀ (x : X), ∃ (U : Y.affineOpens) (V : X.affineOpens) (_ : x ∈ V.1) (e : V.1 ≤ f ⁻¹ᵁ U.1), + Q (f.appLE U V e) := by + refine ⟨fun hf x ↦ ?_, fun hf ↦ (IsLocalAtSource.iff_exists_resLE (P := P)).mpr <| fun x ↦ ?_⟩ + · obtain ⟨U, hU, hfx, _⟩ := Opens.isBasis_iff_nbhd.mp (isBasis_affine_open Y) + (Opens.mem_top <| f.base x) + obtain ⟨V, hV, hx, e⟩ := Opens.isBasis_iff_nbhd.mp (isBasis_affine_open X) + (show x ∈ f ⁻¹ᵁ U from hfx) + simp_rw [HasRingHomProperty.iff_appLE (P := P), locally_iff_isLocalization hQi] at hf + obtain ⟨s, hs, hfs⟩ := hf ⟨U, hU⟩ ⟨V, hV⟩ e + apply iSup_basicOpen_of_span_eq_top at hs + have : x ∈ (⨆ i ∈ s, X.basicOpen i) := hs.symm ▸ hx + have : ∃ r ∈ s, x ∈ X.basicOpen r := by simpa using this + obtain ⟨r, hr, hrs⟩ := this + refine ⟨⟨U, hU⟩, ⟨X.basicOpen r, hV.basicOpen r⟩, hrs, (X.basicOpen_le r).trans e, ?_⟩ + rw [← f.appLE_map e (homOfLE (X.basicOpen_le r)).op] + haveI : IsLocalization.Away r Γ(X, X.basicOpen r) := hV.isLocalization_basicOpen r + exact hfs r hr _ + · obtain ⟨U, V, hxV, e, hf⟩ := hf x + use U, V, hxV, e + simp only [iff_of_isAffine (P := P), Scheme.Hom.appLE, homOfLE_leOfHom] at hf ⊢ + haveI : (toMorphismProperty (Locally Q)).RespectsIso := toMorphismProperty_respectsIso_iff.mp <| + (isLocal_ringHomProperty P).respectsIso + exact (MorphismProperty.arrow_mk_iso_iff (toMorphismProperty (Locally Q)) + (arrowResLEAppIso f U V e)).mpr (locally_of hQi _ hf) + +/-- `P` can be checked locally around points of the source. -/ +lemma iff_exists_appLE : P f ↔ + ∀ (x : X), ∃ (U : Y.affineOpens) (V : X.affineOpens) (_ : x ∈ V.1) (e : V.1 ≤ f ⁻¹ᵁ U.1), + Q (f.appLE U V e) := by + haveI inst : HasRingHomProperty P Q := inferInstance + haveI : HasRingHomProperty P (Locally Q) := by + apply @copy (P' := P) (Q := Q) (Q' := Locally Q) + · infer_instance + · rfl + · intro R S _ _ f + exact (locally_iff_of_localizationSpanTarget (isLocal_ringHomProperty P).respectsIso + (isLocal_ringHomProperty P).OfLocalizationSpanTarget _).symm + rw [iff_exists_appLE_locally (P := P) ] + haveI : HasRingHomProperty P Q := inst + apply (isLocal_ringHomProperty P (Q := Q)).respectsIso + +omit [HasRingHomProperty P Q] in +lemma locally_of_iff (hQl : LocalizationPreserves Q) + (hQa : StableUnderCompositionWithLocalizationAway Q) + (h : ∀ {X Y : Scheme.{u}} (f : X ⟶ Y), P f ↔ + ∀ (x : X), ∃ (U : Y.affineOpens) (V : X.affineOpens) (_ : x ∈ V.1) (e : V.1 ≤ f ⁻¹ᵁ U.1), + Q (f.appLE U V e)) : HasRingHomProperty P (Locally Q) where + isLocal_ringHomProperty := locally_propertyIsLocal hQl hQa + eq_affineLocally' := by + haveI : HasRingHomProperty (affineLocally (Locally Q)) (Locally Q) := + ⟨locally_propertyIsLocal hQl hQa, rfl⟩ + ext X Y f + rw [h, iff_exists_appLE_locally (P := affineLocally (Locally Q)) hQa.respectsIso] + end HasRingHomProperty end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean index 5831774a682e8..42ba861f7546f 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean @@ -1,12 +1,12 @@ /- Copyright (c) 2024 Christian Merten. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Christian Merten +Authors: Christian Merten, Andrew Yang -/ import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion -import Mathlib.AlgebraicGeometry.Morphisms.QuasiSeparated -import Mathlib.AlgebraicGeometry.Pullbacks -import Mathlib.CategoryTheory.MorphismProperty.Limits +import Mathlib.CategoryTheory.Limits.Constructions.Over.Basic +import Mathlib.CategoryTheory.Limits.Constructions.Over.Products +import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Equalizer /-! @@ -14,13 +14,11 @@ import Mathlib.CategoryTheory.MorphismProperty.Limits A morphism of schemes is separated if its diagonal morphism is a closed immmersion. -## TODO - -- Show separated is stable under composition and base change (this is immediate if - we show that closed immersions are stable under base change). -- Show separated is local at the target. -- Show affine morphisms are separated. - +## Main definitions +- `AlgebraicGeometry.IsSeparated`: The class of separated morphisms. +- `AlgebraicGeometry.Scheme.IsSeparated`: The class of separated schemes. +- `AlgebraicGeometry.IsSeparated.hasAffineProperty`: + A morphism is separated iff the preimage of affine opens are separated schemes. -/ @@ -34,7 +32,7 @@ open scoped AlgebraicGeometry namespace AlgebraicGeometry -variable {X Y : Scheme.{u}} (f : X ⟶ Y) +variable {W X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) /-- A morphism is separated if the diagonal map is a closed immersion. -/ @[mk_iff] @@ -60,6 +58,154 @@ instance : MorphismProperty.RespectsIso @IsSeparated := by instance (priority := 900) [IsSeparated f] : QuasiSeparated f where +instance stableUnderComposition : MorphismProperty.IsStableUnderComposition @IsSeparated := by + rw [isSeparated_eq_diagonal_isClosedImmersion] + exact MorphismProperty.diagonal_isStableUnderComposition IsClosedImmersion.stableUnderBaseChange + +instance [IsSeparated f] [IsSeparated g] : IsSeparated (f ≫ g) := + stableUnderComposition.comp_mem f g inferInstance inferInstance + +instance : MorphismProperty.IsMultiplicative @IsSeparated where + id_mem _ := inferInstance + +lemma stableUnderBaseChange : MorphismProperty.StableUnderBaseChange @IsSeparated := by + rw [isSeparated_eq_diagonal_isClosedImmersion] + exact MorphismProperty.StableUnderBaseChange.diagonal IsClosedImmersion.stableUnderBaseChange + +instance : IsLocalAtTarget @IsSeparated := by + rw [isSeparated_eq_diagonal_isClosedImmersion] + infer_instance + +instance (R S : CommRingCat.{u}) (f : R ⟶ S) : IsSeparated (Spec.map f) := by + constructor + letI := f.toAlgebra + show IsClosedImmersion (Limits.pullback.diagonal (Spec.map (CommRingCat.ofHom (algebraMap R S)))) + rw [diagonal_Spec_map, MorphismProperty.cancel_right_of_respectsIso @IsClosedImmersion] + exact .spec_of_surjective _ fun x ↦ ⟨.tmul R 1 x, + (Algebra.TensorProduct.lmul'_apply_tmul (R := R) (S := S) 1 x).trans (one_mul x)⟩ + +@[instance 100] +lemma of_isAffineHom [h : IsAffineHom f] : IsSeparated f := by + wlog hY : IsAffine Y + · rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := @IsSeparated) _ + (iSup_affineOpens_eq_top Y)] + intro U + have H : IsAffineHom (f ∣_ U) := IsLocalAtTarget.restrict h U + exact this _ U.2 + have : IsAffine X := HasAffineProperty.iff_of_isAffine.mp h + rw [MorphismProperty.arrow_mk_iso_iff @IsSeparated (arrowIsoSpecΓOfIsAffine f)] + infer_instance + +instance {S T : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) (i : S ⟶ T) [IsSeparated i] : + IsClosedImmersion (pullback.mapDesc f g i) := + IsClosedImmersion.stableUnderBaseChange (pullback_map_diagonal_isPullback f g i) + inferInstance + +/-- Given `f : X ⟶ Y` and `g : Y ⟶ Z` such that `g` is separated, the induced map +`X ⟶ X ×[Z] Y` is a closed immersion. -/ +instance [IsSeparated g] : + IsClosedImmersion (pullback.lift (𝟙 _) f (Category.id_comp (f ≫ g))) := by + rw [← MorphismProperty.cancel_left_of_respectsIso @IsClosedImmersion (pullback.fst f (𝟙 Y))] + rw [← MorphismProperty.cancel_right_of_respectsIso @IsClosedImmersion _ + (pullback.congrHom rfl (Category.id_comp g)).inv] + convert (inferInstanceAs <| IsClosedImmersion (pullback.mapDesc f (𝟙 _) g)) using 1 + ext : 1 <;> simp [pullback.condition] + end IsSeparated +lemma IsClosedImmersion.of_comp [IsClosedImmersion (f ≫ g)] [IsSeparated g] : + IsClosedImmersion f := by + rw [← pullback.lift_snd (𝟙 _) f (Category.id_comp (f ≫ g))] + have := IsClosedImmersion.stableUnderBaseChange.snd (f ≫ g) g inferInstance + infer_instance + +lemma IsSeparated.of_comp [IsSeparated (f ≫ g)] : IsSeparated f := by + have := IsSeparated.diagonal_isClosedImmersion (f := f ≫ g) + rw [pullback.diagonal_comp] at this + exact ⟨@IsClosedImmersion.of_comp _ _ _ _ _ this inferInstance⟩ + +lemma IsSeparated.comp_iff [IsSeparated g] : IsSeparated (f ≫ g) ↔ IsSeparated f := + ⟨fun _ ↦ .of_comp f g, fun _ ↦ inferInstance⟩ + +@[stacks 01KM] +instance isClosedImmersion_equalizer_ι_left {S : Scheme} {X Y : Over S} [IsSeparated Y.hom] + (f g : X ⟶ Y) : IsClosedImmersion (equalizer.ι f g).left := by + refine IsClosedImmersion.stableUnderBaseChange + ((Limits.isPullback_equalizer_prod f g).map (Over.forget _)).flip ?_ + rw [← MorphismProperty.cancel_right_of_respectsIso @IsClosedImmersion _ + (Over.prodLeftIsoPullback Y Y).hom] + convert (inferInstanceAs (IsClosedImmersion (pullback.diagonal Y.hom))) + ext1 <;> simp [← Over.comp_left] + +/-- +Suppose `X` is a reduced scheme and that `f g : X ⟶ Y` agree over some separated `Y ⟶ Z`. +Then `f = g` if `ι ≫ f = ι ≫ g` for some dominant `ι`. +-/ +lemma ext_of_isDominant_of_isSeparated [IsReduced X] {f g : X ⟶ Y} + (s : Y ⟶ Z) [IsSeparated s] (h : f ≫ s = g ≫ s) + (ι : W ⟶ X) [IsDominant ι] (hU : ι ≫ f = ι ≫ g) : f = g := by + let X' : Over Z := Over.mk (f ≫ s) + let Y' : Over Z := Over.mk s + let U' : Over Z := Over.mk (ι ≫ f ≫ s) + let f' : X' ⟶ Y' := Over.homMk f + let g' : X' ⟶ Y' := Over.homMk g + let ι' : U' ⟶ X' := Over.homMk ι + have : IsSeparated Y'.hom := ‹_› + have : IsDominant (equalizer.ι f' g').left := by + apply (config := { allowSynthFailures := true }) IsDominant.of_comp (equalizer.lift ι' ?_).left + · rwa [← Over.comp_left, equalizer.lift_ι] + · ext1; exact hU + have : Surjective (equalizer.ι f' g').left := + surjective_of_isDominant_of_isClosed_range _ IsClosedImmersion.base_closed.2 + have := isIso_of_isClosedImmersion_of_surjective (Y := X) (equalizer.ι f' g').left + rw [← cancel_epi (equalizer.ι f' g').left] + exact congr($(equalizer.condition f' g').left) + +namespace Scheme + +/-- A scheme `X` is separated if it is separated over `⊤_ Scheme`. -/ +@[mk_iff] +protected class IsSeparated (X : Scheme.{u}) : Prop where + isSeparated_terminal_from : IsSeparated (terminal.from X) + +attribute [instance] IsSeparated.isSeparated_terminal_from + +lemma isSeparated_iff_isClosedImmersion_prod_lift {X : Scheme.{u}} : + X.IsSeparated ↔ IsClosedImmersion (prod.lift (𝟙 X) (𝟙 X)) := by + rw [isSeparated_iff, AlgebraicGeometry.isSeparated_iff, iff_iff_eq, + ← MorphismProperty.cancel_right_of_respectsIso @IsClosedImmersion _ (prodIsoPullback X X).hom] + congr + ext : 1 <;> simp + +instance [X.IsSeparated] : IsClosedImmersion (prod.lift (𝟙 X) (𝟙 X)) := by + rwa [← isSeparated_iff_isClosedImmersion_prod_lift] + +instance (priority := 900) {X : Scheme.{u}} [IsAffine X] : X.IsSeparated := ⟨inferInstance⟩ + +instance (priority := 900) [X.IsSeparated] : IsSeparated f := by + apply (config := { allowSynthFailures := true }) @IsSeparated.of_comp (g := terminal.from Y) + rw [terminal.comp_from] + infer_instance + +instance (f g : X ⟶ Y) [Y.IsSeparated] : IsClosedImmersion (Limits.equalizer.ι f g) := + IsClosedImmersion.stableUnderBaseChange (isPullback_equalizer_prod f g).flip inferInstance + +end Scheme + +instance IsSeparated.hasAffineProperty : + HasAffineProperty @IsSeparated fun X _ _ _ ↦ X.IsSeparated := by + convert HasAffineProperty.of_isLocalAtTarget @IsSeparated with X Y f hY + rw [Scheme.isSeparated_iff, ← terminal.comp_from f, IsSeparated.comp_iff] + rfl + +/-- +Suppose `f g : X ⟶ Y` where `X` is a reduced scheme and `Y` is a separated scheme. +Then `f = g` if `ι ≫ f = ι ≫ g` for some dominant `ι`. + +Also see `ext_of_isDominant_of_isSeparated` for the general version over arbitrary bases. +-/ +lemma ext_of_isDominant [IsReduced X] {f g : X ⟶ Y} [Y.IsSeparated] + (ι : W ⟶ X) [IsDominant ι] (hU : ι ≫ f = ι ≫ g) : f = g := + ext_of_isDominant_of_isSeparated (Limits.terminal.from _) (Limits.terminal.hom_ext _ _) ι hU + end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Smooth.lean b/Mathlib/AlgebraicGeometry/Morphisms/Smooth.lean new file mode 100644 index 0000000000000..31d2f234dbb6d --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/Smooth.lean @@ -0,0 +1,167 @@ +/- +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.Morphisms.RingHomProperties +import Mathlib.RingTheory.RingHom.StandardSmooth + +/-! + +# Smooth morphisms + +A morphism of schemes `f : X ⟶ Y` is smooth (of relative dimension `n`) if for each `x : X` there +exists an affine open neighborhood `V` of `x` and an affine open neighborhood `U` of +`f.base x` with `V ≤ f ⁻¹ᵁ U` such that the induced map `Γ(Y, U) ⟶ Γ(X, V)` is +standard smooth (of relative dimension `n`). + +In other words, smooth (resp. smooth of relative dimension `n`) for scheme morphisms is associated +to the property of ring homomorphisms `Locally IsStandardSmooth` +(resp. `Locally (IsStandardSmoothOfRelativeDimension n)`). + +## Implementation details + +- Our definition is equivalent to defining `IsSmooth` as the associated scheme morphism property of +the property of ring maps induced by `Algebra.Smooth`. The equivalence will follow from the +equivalence of `Locally IsStandardSmooth` and `Algebra.IsSmooth`, but the latter is a (hard) TODO. + +The reason why we choose the definition via `IsStandardSmooth`, is because verifying that +`Algebra.IsSmooth` is local in the sense of `RingHom.PropertyIsLocal` is a (hard) TODO. + +- The definition `RingHom.IsStandardSmooth` depends on universe levels for the generators and +relations. For morphisms of schemes we set both to `0` to avoid unnecessary complications. + +## Notes + +This contribution was created as part of the AIM workshop "Formalizing algebraic geometry" in +June 2024. + +-/ + + +noncomputable section + +open CategoryTheory + +universe t w v u + +namespace AlgebraicGeometry + +open RingHom + +variable (n m : ℕ) {X Y : Scheme.{u}} (f : X ⟶ Y) + +/-- +A morphism of schemes `f : X ⟶ Y` is smooth if for each `x : X` there +exists an affine open neighborhood `V` of `x` and an affine open neighborhood `U` of +`f.base x` with `V ≤ f ⁻¹ᵁ U` such that the induced map `Γ(Y, U) ⟶ Γ(X, V)` is +standard smooth. +-/ +@[mk_iff] +class IsSmooth : Prop where + exists_isStandardSmooth : ∀ (x : X), ∃ (U : Y.affineOpens) (V : X.affineOpens) (_ : x ∈ V.1) + (e : V.1 ≤ f ⁻¹ᵁ U.1), IsStandardSmooth.{0, 0} (f.appLE U V e) + +/-- The property of scheme morphisms `IsSmooth` is associated with the ring +homomorphism property `Locally IsStandardSmooth.{0, 0}`. -/ +instance : HasRingHomProperty @IsSmooth (Locally IsStandardSmooth.{0, 0}) := by + apply HasRingHomProperty.locally_of_iff + · exact isStandardSmooth_localizationPreserves + · exact isStandardSmooth_stableUnderCompositionWithLocalizationAway + · intro X Y f + rw [isSmooth_iff] + +/-- Being smooth is stable under composition. -/ +instance : MorphismProperty.IsStableUnderComposition @IsSmooth := + HasRingHomProperty.stableUnderComposition <| locally_stableUnderComposition + isStandardSmooth_respectsIso isStandardSmooth_localizationPreserves + isStandardSmooth_stableUnderComposition + +/-- The composition of smooth morphisms is smooth. -/ +instance isSmooth_comp {Z : Scheme.{u}} (g : Y ⟶ Z) [IsSmooth f] [IsSmooth g] : + IsSmooth (f ≫ g) := + MorphismProperty.comp_mem _ f g ‹IsSmooth f› ‹IsSmooth g› + +/-- Smooth of relative dimension `n` is stable under base change. -/ +lemma isSmooth_stableUnderBaseChange : MorphismProperty.StableUnderBaseChange @IsSmooth := + HasRingHomProperty.stableUnderBaseChange <| locally_stableUnderBaseChange + isStandardSmooth_respectsIso isStandardSmooth_stableUnderBaseChange + +/-- +A morphism of schemes `f : X ⟶ Y` is smooth of relative dimension `n` if for each `x : X` there +exists an affine open neighborhood `V` of `x` and an affine open neighborhood `U` of +`f.base x` with `V ≤ f ⁻¹ᵁ U` such that the induced map `Γ(Y, U) ⟶ Γ(X, V)` is +standard smooth of relative dimension `n`. +-/ +@[mk_iff] +class IsSmoothOfRelativeDimension : Prop where + exists_isStandardSmoothOfRelativeDimension : ∀ (x : X), ∃ (U : Y.affineOpens) + (V : X.affineOpens) (_ : x ∈ V.1) (e : V.1 ≤ f ⁻¹ᵁ U.1), + IsStandardSmoothOfRelativeDimension.{0, 0} n (f.appLE U V e) + +/-- If `f` is smooth of any relative dimension, it is smooth. -/ +lemma IsSmoothOfRelativeDimension.isSmooth [IsSmoothOfRelativeDimension n f] : IsSmooth f where + exists_isStandardSmooth x := by + obtain ⟨U, V, hx, e, hf⟩ := exists_isStandardSmoothOfRelativeDimension (n := n) (f := f) x + exact ⟨U, V, hx, e, hf.isStandardSmooth⟩ + +/-- The property of scheme morphisms `IsSmoothOfRelativeDimension n` is associated with the ring +homomorphism property `Locally (IsStandardSmoothOfRelativeDimension.{0, 0} n)`. -/ +instance : HasRingHomProperty (@IsSmoothOfRelativeDimension n) + (Locally (IsStandardSmoothOfRelativeDimension.{0, 0} n)) := by + apply HasRingHomProperty.locally_of_iff + · exact isStandardSmoothOfRelativeDimension_localizationPreserves n + · exact isStandardSmoothOfRelativeDimension_stableUnderCompositionWithLocalizationAway n + · intro X Y f + rw [isSmoothOfRelativeDimension_iff] + +/-- Smooth of relative dimension `n` is stable under base change. -/ +lemma isSmoothOfRelativeDimension_stableUnderBaseChange : + MorphismProperty.StableUnderBaseChange (@IsSmoothOfRelativeDimension n) := + HasRingHomProperty.stableUnderBaseChange <| locally_stableUnderBaseChange + isStandardSmoothOfRelativeDimension_respectsIso + (isStandardSmoothOfRelativeDimension_stableUnderBaseChange n) + +/-- Open immersions are smooth of relative dimension `0`. -/ +instance (priority := 900) [IsOpenImmersion f] : IsSmoothOfRelativeDimension 0 f := + HasRingHomProperty.of_isOpenImmersion + (locally_holdsForLocalizationAway <| + isStandardSmoothOfRelativeDimension_holdsForLocalizationAway).containsIdentities + +/-- Open immersions are smooth. -/ +instance (priority := 900) [IsOpenImmersion f] : IsSmooth f := + IsSmoothOfRelativeDimension.isSmooth 0 f + +/-- If `f` is smooth of relative dimension `n` and `g` is smooth of relative dimension +`m`, then `f ≫ g` is smooth of relative dimension `n + m`. -/ +instance isSmoothOfRelativeDimension_comp {Z : Scheme.{u}} (g : Y ⟶ Z) + [hf : IsSmoothOfRelativeDimension n f] [hg : IsSmoothOfRelativeDimension m g] : + IsSmoothOfRelativeDimension (n + m) (f ≫ g) where + exists_isStandardSmoothOfRelativeDimension x := by + obtain ⟨U₂, V₂, hfx₂, e₂, hf₂⟩ := hg.exists_isStandardSmoothOfRelativeDimension (f.base x) + obtain ⟨U₁', V₁', hx₁', e₁', hf₁'⟩ := hf.exists_isStandardSmoothOfRelativeDimension x + obtain ⟨r, s, hx₁, e₁, hf₁⟩ := exists_basicOpen_le_appLE_of_appLE_of_isAffine + (isStandardSmoothOfRelativeDimension_stableUnderCompositionWithLocalizationAway n) + (isStandardSmoothOfRelativeDimension_localizationPreserves n) + x V₂ U₁' V₁' V₁' hx₁' hx₁' e₁' hf₁' hfx₂ + have e : X.basicOpen s ≤ (f ≫ g) ⁻¹ᵁ U₂ := + le_trans e₁ <| f.preimage_le_preimage_of_le <| le_trans (Y.basicOpen_le r) e₂ + have heq : (f ≫ g).appLE U₂ (X.basicOpen s) e = g.appLE U₂ V₂ e₂ ≫ + algebraMap Γ(Y, V₂) Γ(Y, Y.basicOpen r) ≫ f.appLE (Y.basicOpen r) (X.basicOpen s) e₁ := by + rw [RingHom.algebraMap_toAlgebra, g.appLE_map_assoc, Scheme.appLE_comp_appLE] + refine ⟨U₂, ⟨X.basicOpen s, V₁'.2.basicOpen s⟩, hx₁, e, heq ▸ ?_⟩ + apply IsStandardSmoothOfRelativeDimension.comp ?_ hf₂ + haveI : IsLocalization.Away r Γ(Y, Y.basicOpen r) := V₂.2.isLocalization_basicOpen r + exact (isStandardSmoothOfRelativeDimension_stableUnderCompositionWithLocalizationAway n).right + _ r _ hf₁ + +instance {Z : Scheme.{u}} (g : Y ⟶ Z) [IsSmoothOfRelativeDimension 0 f] + [IsSmoothOfRelativeDimension 0 g] : + IsSmoothOfRelativeDimension 0 (f ≫ g) := + inferInstanceAs <| IsSmoothOfRelativeDimension (0 + 0) (f ≫ g) + +/-- Smooth of relative dimension `0` is stable under composition. -/ +instance : MorphismProperty.IsStableUnderComposition (@IsSmoothOfRelativeDimension 0) where + comp_mem _ _ _ _ := inferInstance + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean index b2c7a9ad87681..eb093308cb69e 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean @@ -17,9 +17,10 @@ of the underlying map of topological spaces, including - `Surjective` - `IsOpenMap` - `IsClosedMap` -- `Embedding` -- `OpenEmbedding` -- `ClosedEmbedding` +- `IsEmbedding` +- `IsOpenEmbedding` +- `IsClosedEmbedding` +- `DenseRange` (`IsDominant`) -/ @@ -37,7 +38,7 @@ instance : MorphismProperty.RespectsIso (topologically Function.Injective) := topologically_respectsIso _ (fun e ↦ e.injective) (fun _ _ hf hg ↦ hg.comp hf) instance injective_isLocalAtTarget : IsLocalAtTarget (topologically Function.Injective) := by - refine topologically_isLocalAtTarget _ (fun _ s h ↦ h.restrictPreimage s) + refine topologically_isLocalAtTarget _ (fun _ s _ _ h ↦ h.restrictPreimage s) fun f ι U H _ hf x₁ x₂ e ↦ ?_ obtain ⟨i, hxi⟩ : ∃ i, f x₁ ∈ U i := by simpa using congr(f x₁ ∈ $H) exact congr(($(@hf i ⟨x₁, hxi⟩ ⟨x₂, show f x₂ ∈ U i from e ▸ hxi⟩ (Subtype.ext e))).1) @@ -51,12 +52,12 @@ variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) /-- A morphism of schemes is surjective if the underlying map is. -/ @[mk_iff] class Surjective : Prop where - surj : Function.Surjective f.1.base + surj : Function.Surjective f.base lemma surjective_eq_topologically : @Surjective = topologically Function.Surjective := by ext; exact surjective_iff _ -lemma Scheme.Hom.surjective (f : X.Hom Y) [Surjective f] : Function.Surjective f.1.base := +lemma Scheme.Hom.surjective (f : X.Hom Y) [Surjective f] : Function.Surjective f.base := Surjective.surj instance (priority := 100) [IsIso f] : Surjective f := ⟨f.homeomorph.surjective⟩ @@ -64,7 +65,7 @@ instance (priority := 100) [IsIso f] : Surjective f := ⟨f.homeomorph.surjectiv instance [Surjective f] [Surjective g] : Surjective (f ≫ g) := ⟨g.surjective.comp f.surjective⟩ lemma Surjective.of_comp [Surjective (f ≫ g)] : Surjective g where - surj := Function.Surjective.of_comp (g := f.1.base) (f ≫ g).surjective + surj := Function.Surjective.of_comp (g := f.base) (f ≫ g).surjective lemma Surjective.comp_iff [Surjective f] : Surjective (f ≫ g) ↔ Surjective g := ⟨fun _ ↦ of_comp f g, fun _ ↦ inferInstance⟩ @@ -76,7 +77,8 @@ instance : MorphismProperty.RespectsIso @Surjective := instance surjective_isLocalAtTarget : IsLocalAtTarget @Surjective := by have : MorphismProperty.RespectsIso @Surjective := inferInstance rw [surjective_eq_topologically] at this ⊢ - refine topologically_isLocalAtTarget _ (fun _ s h ↦ h.restrictPreimage s) fun f ι U H _ hf x ↦ ?_ + refine topologically_isLocalAtTarget _ (fun _ s _ _ h ↦ h.restrictPreimage s) ?_ + intro α β _ _ f ι U H _ hf x obtain ⟨i, hxi⟩ : ∃ i, x ∈ U i := by simpa using congr(x ∈ $H) obtain ⟨⟨y, _⟩, hy⟩ := hf i ⟨x, hxi⟩ exact ⟨y, congr(($hy).1)⟩ @@ -89,9 +91,7 @@ instance : (topologically IsOpenMap).RespectsIso := topologically_respectsIso _ (fun e ↦ e.isOpenMap) (fun _ _ hf hg ↦ hg.comp hf) instance isOpenMap_isLocalAtTarget : IsLocalAtTarget (topologically IsOpenMap) := - topologically_isLocalAtTarget _ - (fun _ s hf ↦ hf.restrictPreimage s) - (fun _ _ _ hU _ hf ↦ (isOpenMap_iff_isOpenMap_of_iSup_eq_top hU).mpr hf) + topologically_isLocalAtTarget' _ fun _ _ _ hU _ ↦ isOpenMap_iff_isOpenMap_of_iSup_eq_top hU end IsOpenMap @@ -101,46 +101,94 @@ instance : (topologically IsClosedMap).RespectsIso := topologically_respectsIso _ (fun e ↦ e.isClosedMap) (fun _ _ hf hg ↦ hg.comp hf) instance isClosedMap_isLocalAtTarget : IsLocalAtTarget (topologically IsClosedMap) := - topologically_isLocalAtTarget _ - (fun _ s hf ↦ hf.restrictPreimage s) - (fun _ _ _ hU _ hf ↦ (isClosedMap_iff_isClosedMap_of_iSup_eq_top hU).mpr hf) + topologically_isLocalAtTarget' _ fun _ _ _ hU _ ↦ isClosedMap_iff_isClosedMap_of_iSup_eq_top hU end IsClosedMap -section Embedding +section IsEmbedding -instance : (topologically Embedding).RespectsIso := - topologically_respectsIso _ (fun e ↦ e.embedding) (fun _ _ hf hg ↦ hg.comp hf) +instance : (topologically IsEmbedding).RespectsIso := + topologically_respectsIso _ (fun e ↦ e.isEmbedding) (fun _ _ hf hg ↦ hg.comp hf) -instance embedding_isLocalAtTarget : IsLocalAtTarget (topologically Embedding) := - topologically_isLocalAtTarget _ - (fun _ s hf ↦ hf.restrictPreimage s) - (fun _ _ _ hU hfcont hf ↦ (embedding_iff_embedding_of_iSup_eq_top hU hfcont).mpr hf) +instance isEmbedding_isLocalAtTarget : IsLocalAtTarget (topologically IsEmbedding) := + topologically_isLocalAtTarget' _ fun _ _ _ ↦ isEmbedding_iff_of_iSup_eq_top -end Embedding +end IsEmbedding -section OpenEmbedding +section IsOpenEmbedding -instance : (topologically OpenEmbedding).RespectsIso := - topologically_respectsIso _ (fun e ↦ e.openEmbedding) (fun _ _ hf hg ↦ hg.comp hf) +instance : (topologically IsOpenEmbedding).RespectsIso := + topologically_respectsIso _ (fun e ↦ e.isOpenEmbedding) (fun _ _ hf hg ↦ hg.comp hf) -instance openEmbedding_isLocalAtTarget : IsLocalAtTarget (topologically OpenEmbedding) := - topologically_isLocalAtTarget _ - (fun _ s hf ↦ hf.restrictPreimage s) - (fun _ _ _ hU hfcont hf ↦ (openEmbedding_iff_openEmbedding_of_iSup_eq_top hU hfcont).mpr hf) +instance isOpenEmbedding_isLocalAtTarget : IsLocalAtTarget (topologically IsOpenEmbedding) := + topologically_isLocalAtTarget' _ fun _ _ _ ↦ isOpenEmbedding_iff_isOpenEmbedding_of_iSup_eq_top -end OpenEmbedding +end IsOpenEmbedding -section ClosedEmbedding +section IsClosedEmbedding -instance : (topologically ClosedEmbedding).RespectsIso := - topologically_respectsIso _ (fun e ↦ e.closedEmbedding) (fun _ _ hf hg ↦ hg.comp hf) +instance : (topologically IsClosedEmbedding).RespectsIso := + topologically_respectsIso _ (fun e ↦ e.isClosedEmbedding) (fun _ _ hf hg ↦ hg.comp hf) -instance closedEmbedding_isLocalAtTarget : IsLocalAtTarget (topologically ClosedEmbedding) := - topologically_isLocalAtTarget _ - (fun _ s hf ↦ hf.restrictPreimage s) - (fun _ _ _ hU hfcont hf ↦ (closedEmbedding_iff_closedEmbedding_of_iSup_eq_top hU hfcont).mpr hf) +instance isClosedEmbedding_isLocalAtTarget : IsLocalAtTarget (topologically IsClosedEmbedding) := + topologically_isLocalAtTarget' _ + fun _ _ _ ↦ isClosedEmbedding_iff_isClosedEmbedding_of_iSup_eq_top -end ClosedEmbedding +end IsClosedEmbedding + +section IsDominant + +variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) + +/-- A morphism of schemes is dominant if the underlying map has dense range. -/ +@[mk_iff] +class IsDominant : Prop where + denseRange : DenseRange f.base + +lemma dominant_eq_topologically : + @IsDominant = topologically DenseRange := by ext; exact isDominant_iff _ + +lemma Scheme.Hom.denseRange (f : X.Hom Y) [IsDominant f] : DenseRange f.base := + IsDominant.denseRange + +instance (priority := 100) [Surjective f] : IsDominant f := ⟨f.surjective.denseRange⟩ + +instance [IsDominant f] [IsDominant g] : IsDominant (f ≫ g) := + ⟨g.denseRange.comp f.denseRange g.base.2⟩ + +instance : MorphismProperty.IsMultiplicative @IsDominant where + id_mem := fun _ ↦ inferInstance + comp_mem := fun _ _ _ _ ↦ inferInstance + +lemma IsDominant.of_comp [H : IsDominant (f ≫ g)] : IsDominant g := by + rw [isDominant_iff, denseRange_iff_closure_range, ← Set.univ_subset_iff] at H ⊢ + exact H.trans (closure_mono (Set.range_comp_subset_range f.base g.base)) + +lemma IsDominant.comp_iff [IsDominant f] : IsDominant (f ≫ g) ↔ IsDominant g := + ⟨fun _ ↦ of_comp f g, fun _ ↦ inferInstance⟩ + +instance IsDominant.respectsIso : MorphismProperty.RespectsIso @IsDominant := + MorphismProperty.respectsIso_of_isStableUnderComposition fun _ _ f (_ : IsIso f) ↦ inferInstance + +instance IsDominant.isLocalAtTarget : IsLocalAtTarget @IsDominant := + have : MorphismProperty.RespectsIso (topologically DenseRange) := + dominant_eq_topologically ▸ IsDominant.respectsIso + dominant_eq_topologically ▸ topologically_isLocalAtTarget' DenseRange + fun _ _ _ hU _ ↦ denseRange_iff_denseRange_of_iSup_eq_top hU + +lemma surjective_of_isDominant_of_isClosed_range (f : X ⟶ Y) [IsDominant f] + (hf : IsClosed (Set.range f.base)) : + Surjective f := + ⟨by rw [← Set.range_iff_surjective, ← hf.closure_eq, f.denseRange.closure_range]⟩ + +lemma IsDominant.of_comp_of_isOpenImmersion + (f : X ⟶ Y) (g : Y ⟶ Z) [H : IsDominant (f ≫ g)] [IsOpenImmersion g] : + IsDominant f := by + rw [isDominant_iff, DenseRange] at H ⊢ + simp only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp] at H + convert H.preimage g.isOpenEmbedding.isOpenMap using 1 + rw [Set.preimage_image_eq _ g.isOpenEmbedding.inj] + +end IsDominant end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean index 3e0a0c0b91874..166651638bcaa 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.AlgebraicGeometry.Morphisms.Constructors +import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion import Mathlib.Topology.LocalAtTarget /-! @@ -40,6 +40,13 @@ class UniversallyClosed (f : X ⟶ Y) : Prop where theorem universallyClosed_eq : @UniversallyClosed = universally (topologically @IsClosedMap) := by ext X Y f; rw [universallyClosed_iff] +instance (priority := 900) [IsClosedImmersion f] : UniversallyClosed f := by + rw [universallyClosed_eq] + intro X' Y' i₁ i₂ f' hf + have hf' : IsClosedImmersion f' := + IsClosedImmersion.stableUnderBaseChange hf.flip inferInstance + exact hf'.base_closed.isClosedMap + theorem universallyClosed_respectsIso : RespectsIso @UniversallyClosed := universallyClosed_eq.symm ▸ universally_respectsIso (topologically @IsClosedMap) @@ -48,7 +55,7 @@ theorem universallyClosed_stableUnderBaseChange : StableUnderBaseChange @Univers instance isClosedMap_isStableUnderComposition : IsStableUnderComposition (topologically @IsClosedMap) where - comp_mem f g hf hg := IsClosedMap.comp (f := f.1.base) (g := g.1.base) hg hf + comp_mem f g hf hg := IsClosedMap.comp (f := f.base) (g := g.base) hg hf instance universallyClosed_isStableUnderComposition : IsStableUnderComposition @UniversallyClosed := by @@ -59,6 +66,9 @@ instance universallyClosedTypeComp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [hf : UniversallyClosed f] [hg : UniversallyClosed g] : UniversallyClosed (f ≫ g) := comp_mem _ _ _ hf hg +instance : MorphismProperty.IsMultiplicative @UniversallyClosed where + id_mem _ := inferInstance + instance universallyClosed_fst {X Y Z : Scheme} (f : X ⟶ Z) (g : Y ⟶ Z) [hg : UniversallyClosed g] : UniversallyClosed (pullback.fst f g) := universallyClosed_stableUnderBaseChange.fst f g hg @@ -71,7 +81,7 @@ instance universallyClosed_isLocalAtTarget : IsLocalAtTarget @UniversallyClosed rw [universallyClosed_eq] apply universally_isLocalAtTarget intro X Y f ι U hU H - simp_rw [topologically, morphismRestrict_val_base] at H + simp_rw [topologically, morphismRestrict_base] at H exact (isClosedMap_iff_isClosedMap_of_iSup_eq_top hU).mpr H end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Noetherian.lean b/Mathlib/AlgebraicGeometry/Noetherian.lean index 5b47926dddcf1..9eb7613b9f00b 100644 --- a/Mathlib/AlgebraicGeometry/Noetherian.lean +++ b/Mathlib/AlgebraicGeometry/Noetherian.lean @@ -199,7 +199,7 @@ instance (priority := 100) {Z : Scheme} [IsLocallyNoetherian X] apply (quasiCompact_iff_forall_affine f).mpr intro U hU rw [Opens.map_coe, ← Set.preimage_inter_range] - apply f.openEmbedding.toInducing.isCompact_preimage' + apply f.isOpenEmbedding.isInducing.isCompact_preimage' · apply (noetherianSpace_set_iff _).mp · convert noetherianSpace_of_isAffineOpen U hU apply IsLocallyNoetherian.component_noetherian ⟨U, hU⟩ @@ -213,7 +213,7 @@ instance (priority := 100) IsLocallyNoetherian.quasiSeparatedSpace [IsLocallyNoe QuasiSeparatedSpace X := by apply (quasiSeparatedSpace_iff_affine X).mpr intro U V - have hInd := U.2.fromSpec.openEmbedding.toInducing + have hInd := U.2.fromSpec.isOpenEmbedding.isInducing apply (hInd.isCompact_preimage_iff ?_).mp · rw [← Set.preimage_inter_range, IsAffineOpen.range_fromSpec, Set.inter_comm] apply hInd.isCompact_preimage' @@ -274,7 +274,7 @@ instance (priority := 100) IsNoetherian.noetherianSpace [IsNoetherian X] : apply TopologicalSpace.noetherian_univ_iff.mp let 𝒰 := X.affineCover.finiteSubcover rw [← 𝒰.iUnion_range] - suffices ∀ i : 𝒰.J, NoetherianSpace (Set.range <| (𝒰.map i).val.base) by + suffices ∀ i : 𝒰.J, NoetherianSpace (Set.range <| (𝒰.map i).base) by apply NoetherianSpace.iUnion intro i have : IsAffine (𝒰.obj i) := by diff --git a/Mathlib/AlgebraicGeometry/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/OpenImmersion.lean index 70d24f7442e9b..bc36b58d339d1 100644 --- a/Mathlib/AlgebraicGeometry/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/OpenImmersion.lean @@ -31,11 +31,11 @@ variable {C : Type u} [Category.{v} C] of LocallyRingedSpaces -/ abbrev IsOpenImmersion {X Y : Scheme.{u}} (f : X ⟶ Y) : Prop := - LocallyRingedSpace.IsOpenImmersion f + LocallyRingedSpace.IsOpenImmersion f.toLRSHom instance IsOpenImmersion.comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) [IsOpenImmersion f] [IsOpenImmersion g] : IsOpenImmersion (f ≫ g) := -LocallyRingedSpace.IsOpenImmersion.comp f g +LocallyRingedSpace.IsOpenImmersion.comp f.toLRSHom g.toLRSHom namespace LocallyRingedSpace.IsOpenImmersion @@ -45,7 +45,7 @@ protected def scheme (X : LocallyRingedSpace.{u}) (h : ∀ x : X, ∃ (R : CommRingCat) (f : Spec.toLocallyRingedSpace.obj (op R) ⟶ X), - (x ∈ Set.range f.1.base : _) ∧ LocallyRingedSpace.IsOpenImmersion f) : + (x ∈ Set.range f.base : _) ∧ LocallyRingedSpace.IsOpenImmersion f) : Scheme where toLocallyRingedSpace := X local_affine := by @@ -56,12 +56,12 @@ protected def scheme (X : LocallyRingedSpace.{u}) refine SheafedSpace.forgetToPresheafedSpace.preimageIso ?_ apply PresheafedSpace.IsOpenImmersion.isoOfRangeEq (PresheafedSpace.ofRestrict _ _) f.1 · exact Subtype.range_coe_subtype - · exact Opens.openEmbedding _ -- Porting note (#11187): was `infer_instance` + · exact Opens.isOpenEmbedding _ -- Porting note (#11187): was `infer_instance` end LocallyRingedSpace.IsOpenImmersion theorem IsOpenImmersion.isOpen_range {X Y : Scheme.{u}} (f : X ⟶ Y) [H : IsOpenImmersion f] : - IsOpen (Set.range f.1.base) := + IsOpen (Set.range f.base) := H.base_open.isOpen_range @[deprecated (since := "2024-03-17")] @@ -71,24 +71,27 @@ namespace Scheme.Hom variable {X Y : Scheme.{u}} (f : Scheme.Hom X Y) [H : IsOpenImmersion f] -theorem openEmbedding : OpenEmbedding f.1.base := +theorem isOpenEmbedding : IsOpenEmbedding f.base := H.base_open +@[deprecated (since := "2024-10-18")] +alias openEmbedding := isOpenEmbedding + /-- The image of an open immersion as an open set. -/ @[simps] def opensRange : Y.Opens := - ⟨_, f.openEmbedding.isOpen_range⟩ + ⟨_, f.isOpenEmbedding.isOpen_range⟩ /-- The functor `opens X ⥤ opens Y` associated with an open immersion `f : X ⟶ Y`. -/ abbrev opensFunctor : X.Opens ⥤ Y.Opens := - LocallyRingedSpace.IsOpenImmersion.opensFunctor f + LocallyRingedSpace.IsOpenImmersion.opensFunctor f.toLRSHom /-- `f ''ᵁ U` is notation for the image (as an open set) of `U` under an open immersion `f`. -/ scoped[AlgebraicGeometry] notation3:90 f:91 " ''ᵁ " U:90 => (Scheme.Hom.opensFunctor f).obj U lemma image_le_image_of_le {U V : X.Opens} (e : U ≤ V) : f ''ᵁ U ≤ f ''ᵁ V := by rintro a ⟨u, hu, rfl⟩ - exact Set.mem_image_of_mem (⇑f.val.base) (e hu) + exact Set.mem_image_of_mem (⇑f.base) (e hu) @[simp] lemma opensFunctor_map_homOfLE {U V : X.Opens} (e : U ≤ V) : @@ -103,7 +106,7 @@ lemma image_top_eq_opensRange : f ''ᵁ ⊤ = f.opensRange := by @[simp] lemma preimage_image_eq (U : X.Opens) : f ⁻¹ᵁ f ''ᵁ U = U := by apply Opens.ext - simp [Set.preimage_image_eq _ f.openEmbedding.inj] + simp [Set.preimage_image_eq _ f.isOpenEmbedding.inj] lemma image_le_image_iff (f : X ⟶ Y) [IsOpenImmersion f] (U U' : X.Opens) : f ''ᵁ U ≤ f ''ᵁ U' ↔ U ≤ U' := by @@ -115,9 +118,23 @@ lemma image_preimage_eq_opensRange_inter (U : Y.Opens) : f ''ᵁ f ⁻¹ᵁ U = apply Opens.ext simp [Set.image_preimage_eq_range_inter] +lemma image_injective : Function.Injective (f ''ᵁ ·) := by + intro U V hUV + simpa using congrArg (f ⁻¹ᵁ ·) hUV + +lemma image_iSup {ι : Sort*} (s : ι → X.Opens) : + (f ''ᵁ ⨆ (i : ι), s i) = ⨆ (i : ι), f ''ᵁ s i := by + ext : 1 + simp [Set.image_iUnion] + +lemma image_iSup₂ {ι : Sort*} {κ : ι → Sort*} (s : (i : ι) → κ i → X.Opens) : + (f ''ᵁ ⨆ (i : ι), ⨆ (j : κ i), s i j) = ⨆ (i : ι), ⨆ (j : κ i), f ''ᵁ s i j := by + ext : 1 + simp [Set.image_iUnion₂] + /-- The isomorphism `Γ(Y, f(U)) ≅ Γ(X, U)` induced by an open immersion `f : X ⟶ Y`. -/ def appIso (U) : Γ(Y, f ''ᵁ U) ≅ Γ(X, U) := - (asIso <| LocallyRingedSpace.IsOpenImmersion.invApp f U).symm + (asIso <| LocallyRingedSpace.IsOpenImmersion.invApp f.toLRSHom U).symm @[reassoc (attr := simp)] theorem appIso_inv_naturality {U V : X.Opens} (i : op U ⟶ op V) : @@ -128,7 +145,7 @@ theorem appIso_inv_naturality {U V : X.Opens} (i : op U ⟶ op V) : theorem appIso_hom (U) : (f.appIso U).hom = f.app (f ''ᵁ U) ≫ X.presheaf.map (eqToHom (preimage_image_eq f U).symm).op := - (PresheafedSpace.IsOpenImmersion.inv_invApp f.1 U).trans (by rw [eqToHom_op]) + (PresheafedSpace.IsOpenImmersion.inv_invApp f.toPshHom U).trans (by rw [eqToHom_op]) theorem appIso_hom' (U) : (f.appIso U).hom = f.appLE (f ''ᵁ U) U (preimage_image_eq f U).ge := @@ -137,7 +154,7 @@ theorem appIso_hom' (U) : @[reassoc (attr := simp)] theorem app_appIso_inv (U) : f.app U ≫ (f.appIso (f ⁻¹ᵁ U)).inv = - Y.presheaf.map (homOfLE (Set.image_preimage_subset f.1.base U.1)).op := + Y.presheaf.map (homOfLE (Set.image_preimage_subset f.base U.1)).op := PresheafedSpace.IsOpenImmersion.app_invApp _ _ /-- A variant of `app_invApp` that gives an `eqToHom` instead of `homOfLE`. -/ @@ -180,7 +197,7 @@ def IsOpenImmersion.opensEquiv {X Y : Scheme.{u}} (f : X ⟶ Y) [IsOpenImmersion X.Opens ≃ { U : Y.Opens // U ≤ f.opensRange } where toFun U := ⟨f ''ᵁ U, Set.image_subset_range _ _⟩ invFun U := f ⁻¹ᵁ U - left_inv _ := Opens.ext (Set.preimage_image_eq _ f.openEmbedding.inj) + left_inv _ := Opens.ext (Set.preimage_image_eq _ f.isOpenEmbedding.inj) right_inv U := Subtype.ext (Opens.ext (Set.image_preimage_eq_of_subset U.2)) namespace Scheme @@ -188,7 +205,7 @@ namespace Scheme instance basic_open_isOpenImmersion {R : CommRingCat.{u}} (f : R) : IsOpenImmersion (Spec.map (CommRingCat.ofHom (algebraMap R (Localization.Away f)))) := by apply SheafedSpace.IsOpenImmersion.of_stalk_iso (H := ?_) - · exact (PrimeSpectrum.localization_away_openEmbedding (Localization.Away f) f : _) + · exact (PrimeSpectrum.localization_away_isOpenEmbedding (Localization.Away f) f : _) · intro x exact Spec_map_localization_isIso R (Submonoid.powers f) x @@ -213,19 +230,18 @@ lemma _root_.AlgebraicGeometry.IsOpenImmersion.of_isLocalization {R S} [CommRing theorem exists_affine_mem_range_and_range_subset {X : Scheme.{u}} {x : X} {U : X.Opens} (hxU : x ∈ U) : ∃ (R : CommRingCat) (f : Spec R ⟶ X), - IsOpenImmersion f ∧ x ∈ Set.range f.1.base ∧ Set.range f.1.base ⊆ U := by + IsOpenImmersion f ∧ x ∈ Set.range f.base ∧ Set.range f.base ⊆ U := by obtain ⟨⟨V, hxV⟩, R, ⟨e⟩⟩ := X.2 x - have : e.hom.1.base ⟨x, hxV⟩ ∈ (Opens.map (e.inv.1.base ≫ V.inclusion')).obj U := - show ((e.hom ≫ e.inv).1.base ⟨x, hxV⟩).1 ∈ U from e.hom_inv_id ▸ hxU + have : e.hom.base ⟨x, hxV⟩ ∈ (Opens.map (e.inv.base ≫ V.inclusion')).obj U := + show ((e.hom ≫ e.inv).base ⟨x, hxV⟩).1 ∈ U from e.hom_inv_id ▸ hxU obtain ⟨_, ⟨_, ⟨r : R, rfl⟩, rfl⟩, hr, hr'⟩ := PrimeSpectrum.isBasis_basic_opens.exists_subset_of_mem_open this (Opens.is_open' _) let f : Spec (CommRingCat.of (Localization.Away r)) ⟶ X := - Spec.map (CommRingCat.ofHom (algebraMap R (Localization.Away r))) ≫ (e.inv ≫ X.ofRestrict _ : _) + Spec.map (CommRingCat.ofHom (algebraMap R (Localization.Away r))) ≫ ⟨e.inv ≫ X.ofRestrict _⟩ refine ⟨.of (Localization.Away r), f, inferInstance, ?_⟩ - rw [Scheme.comp_val_base, LocallyRingedSpace.comp_val, SheafedSpace.comp_base, TopCat.coe_comp, - Set.range_comp] + rw [Scheme.comp_base, TopCat.coe_comp, Set.range_comp] erw [PrimeSpectrum.localization_away_comap_range (Localization.Away r) r] - exact ⟨⟨_, hr, congr(($(e.hom_inv_id).1.base ⟨x, hxV⟩).1)⟩, Set.image_subset_iff.mpr hr'⟩ + exact ⟨⟨_, hr, congr(($(e.hom_inv_id).base ⟨x, hxV⟩).1)⟩, Set.image_subset_iff.mpr hr'⟩ end Scheme @@ -255,10 +271,10 @@ theorem toScheme_toLocallyRingedSpace : upgrade it into a morphism of Schemes. -/ def toSchemeHom : toScheme Y f ⟶ Y := - toLocallyRingedSpaceHom _ f + ⟨toLocallyRingedSpaceHom _ f⟩ @[simp] -theorem toSchemeHom_val : (toSchemeHom Y f).val = f := +theorem toSchemeHom_toPshHom : (toSchemeHom Y f).toPshHom = f := rfl instance toSchemeHom_isOpenImmersion : AlgebraicGeometry.IsOpenImmersion (toSchemeHom Y f) := @@ -269,9 +285,9 @@ theorem scheme_eq_of_locallyRingedSpace_eq {X Y : Scheme.{u}} cases X; cases Y; congr theorem scheme_toScheme {X Y : Scheme.{u}} (f : X ⟶ Y) [AlgebraicGeometry.IsOpenImmersion f] : - toScheme Y f.1 = X := by + toScheme Y f.toPshHom = X := by apply scheme_eq_of_locallyRingedSpace_eq - exact locallyRingedSpace_toLocallyRingedSpace f + exact locallyRingedSpace_toLocallyRingedSpace f.toLRSHom end ToScheme @@ -279,7 +295,7 @@ end PresheafedSpace.IsOpenImmersion section Restrict -variable {U : TopCat.{u}} (X : Scheme.{u}) {f : U ⟶ TopCat.of X} (h : OpenEmbedding f) +variable {U : TopCat.{u}} (X : Scheme.{u}) {f : U ⟶ TopCat.of X} (h : IsOpenEmbedding f) /-- The restriction of a Scheme along an open embedding. -/ @[simps! (config := .lemmasOnly) carrier, simps! presheaf_obj] @@ -291,14 +307,14 @@ lemma Scheme.restrict_toPresheafedSpace : (X.restrict h).toPresheafedSpace = X.toPresheafedSpace.restrict h := rfl /-- The canonical map from the restriction to the subspace. -/ -@[simps! val_base, simps! (config := .lemmasOnly) val_c_app] +@[simps! toLRSHom_base, simps! (config := .lemmasOnly) toLRSHom_c_app] def Scheme.ofRestrict : X.restrict h ⟶ X := - X.toLocallyRingedSpace.ofRestrict h + ⟨X.toLocallyRingedSpace.ofRestrict h⟩ @[simp] lemma Scheme.ofRestrict_app (V) : (X.ofRestrict h).app V = X.presheaf.map (h.isOpenMap.adjunction.counit.app V).op := - Scheme.ofRestrict_val_c_app X h (op V) + Scheme.ofRestrict_toLRSHom_c_app X h (op V) instance IsOpenImmersion.ofRestrict : IsOpenImmersion (X.ofRestrict h) := show PresheafedSpace.IsOpenImmersion (X.toPresheafedSpace.ofRestrict h) by infer_instance @@ -330,35 +346,44 @@ variable {X Y Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) variable [H : IsOpenImmersion f] instance (priority := 100) of_isIso [IsIso g] : IsOpenImmersion g := - @LocallyRingedSpace.IsOpenImmersion.of_isIso _ _ _ - (show IsIso ((inducedFunctor _).map g) by infer_instance) + LocallyRingedSpace.IsOpenImmersion.of_isIso _ -theorem to_iso {X Y : Scheme.{u}} (f : X ⟶ Y) [h : IsOpenImmersion f] [Epi f.1.base] : IsIso f := +theorem to_iso {X Y : Scheme.{u}} (f : X ⟶ Y) [h : IsOpenImmersion f] [Epi f.base] : IsIso f := @isIso_of_reflects_iso _ _ _ _ _ _ f (Scheme.forgetToLocallyRingedSpace ⋙ LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forgetToPresheafedSpace) - (@PresheafedSpace.IsOpenImmersion.to_iso _ _ _ _ f.1 h _) _ + (@PresheafedSpace.IsOpenImmersion.to_iso _ _ _ _ f.toPshHom h _) _ -theorem of_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) (hf : OpenEmbedding f.1.base) +theorem of_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) (hf : IsOpenEmbedding f.base) [∀ x, IsIso (f.stalkMap x)] : IsOpenImmersion f := - haveI (x : X) : IsIso (f.val.stalkMap x) := inferInstanceAs <| IsIso (f.stalkMap x) - SheafedSpace.IsOpenImmersion.of_stalk_iso f.1 hf + haveI (x : X) : IsIso (f.toShHom.stalkMap x) := inferInstanceAs <| IsIso (f.stalkMap x) + SheafedSpace.IsOpenImmersion.of_stalk_iso f.toShHom hf instance stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) [IsOpenImmersion f] (x : X) : IsIso (f.stalkMap x) := - inferInstanceAs <| IsIso (f.val.stalkMap x) + inferInstanceAs <| IsIso (f.toLRSHom.stalkMap x) + +lemma of_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) [IsOpenImmersion g] + [IsOpenImmersion (f ≫ g)] : IsOpenImmersion f := + haveI (x : X) : IsIso (f.stalkMap x) := + haveI : IsIso (g.stalkMap (f.base x) ≫ f.stalkMap x) := by + rw [← Scheme.stalkMap_comp] + infer_instance + IsIso.of_isIso_comp_left (f := g.stalkMap (f.base x)) _ + IsOpenImmersion.of_stalk_iso _ <| + IsOpenEmbedding.of_comp _ (Scheme.Hom.isOpenEmbedding g) (Scheme.Hom.isOpenEmbedding (f ≫ g)) theorem iff_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) : - IsOpenImmersion f ↔ OpenEmbedding f.1.base ∧ ∀ x, IsIso (f.stalkMap x) := - ⟨fun H => ⟨H.1, fun x ↦ inferInstanceAs <| IsIso (f.val.stalkMap x)⟩, + IsOpenImmersion f ↔ IsOpenEmbedding f.base ∧ ∀ x, IsIso (f.stalkMap x) := + ⟨fun H => ⟨H.1, fun x ↦ inferInstanceAs <| IsIso (f.toPshHom.stalkMap x)⟩, fun ⟨h₁, h₂⟩ => @IsOpenImmersion.of_stalk_iso _ _ f h₁ h₂⟩ theorem _root_.AlgebraicGeometry.isIso_iff_isOpenImmersion {X Y : Scheme.{u}} (f : X ⟶ Y) : - IsIso f ↔ IsOpenImmersion f ∧ Epi f.1.base := + IsIso f ↔ IsOpenImmersion f ∧ Epi f.base := ⟨fun _ => ⟨inferInstance, inferInstance⟩, fun ⟨h₁, h₂⟩ => @IsOpenImmersion.to_iso _ _ f h₁ h₂⟩ theorem _root_.AlgebraicGeometry.isIso_iff_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) : - IsIso f ↔ IsIso f.1.base ∧ ∀ x, IsIso (f.stalkMap x) := by + IsIso f ↔ IsIso f.base ∧ ∀ x, IsIso (f.stalkMap x) := by rw [isIso_iff_isOpenImmersion, IsOpenImmersion.iff_stalk_iso, and_comm, ← and_assoc] refine and_congr ⟨?_, ?_⟩ Iff.rfl · rintro ⟨h₁, h₂⟩ @@ -369,16 +394,18 @@ theorem _root_.AlgebraicGeometry.isIso_iff_stalk_iso {X Y : Scheme.{u}} (f : X (Equiv.ofBijective _ ⟨h₂.inj, (TopCat.epi_iff_surjective _).mp h₁⟩) h₂.continuous h₂.isOpenMap)).hom infer_instance - · intro H; exact ⟨inferInstance, (TopCat.homeoOfIso (asIso f.1.base)).openEmbedding⟩ + · intro H; exact ⟨inferInstance, (TopCat.homeoOfIso (asIso f.base)).isOpenEmbedding⟩ /-- An open immersion induces an isomorphism from the domain onto the image -/ -def isoRestrict : X ≅ (Z.restrict H.base_open : _) where - __ := (LocallyRingedSpace.IsOpenImmersion.isoRestrict f) +def isoRestrict : X ≅ (Z.restrict H.base_open : _) := + Scheme.fullyFaithfulForgetToLocallyRingedSpace.preimageIso + (LocallyRingedSpace.IsOpenImmersion.isoRestrict f.toLRSHom) local notation "forget" => Scheme.forgetToLocallyRingedSpace instance mono : Mono f := - (inducedFunctor _).mono_of_mono_map (show @Mono LocallyRingedSpace _ _ _ f by infer_instance) + Scheme.forgetToLocallyRingedSpace.mono_of_mono_map + (show Mono f.toLRSHom by infer_instance) instance forget_map_isOpenImmersion : LocallyRingedSpace.IsOpenImmersion ((forget).map f) := ⟨H.base_open, H.c_iso⟩ @@ -406,12 +433,12 @@ instance hasLimit_cospan_forget_of_right' : instance forgetCreatesPullbackOfLeft : CreatesLimit (cospan f g) forget := createsLimitOfFullyFaithfulOfIso - (PresheafedSpace.IsOpenImmersion.toScheme Y (@pullback.snd LocallyRingedSpace _ _ _ _ f g _).1) + (PresheafedSpace.IsOpenImmersion.toScheme Y (pullback.snd f.toLRSHom g.toLRSHom).toShHom) (eqToIso (by simp) ≪≫ HasLimit.isoOfNatIso (diagramIsoCospan _).symm) instance forgetCreatesPullbackOfRight : CreatesLimit (cospan g f) forget := createsLimitOfFullyFaithfulOfIso - (PresheafedSpace.IsOpenImmersion.toScheme Y (@pullback.fst LocallyRingedSpace _ _ _ _ g f _).1) + (PresheafedSpace.IsOpenImmersion.toScheme Y (pullback.fst g.toLRSHom f.toLRSHom).1) (eqToIso (by simp) ≪≫ HasLimit.isoOfNatIso (diagramIsoCospan _).symm) instance forgetPreservesOfLeft : PreservesLimit (cospan f g) forget := @@ -429,8 +456,8 @@ instance hasPullback_of_right : HasPullback g f := instance pullback_snd_of_left : IsOpenImmersion (pullback.snd f g) := by have := PreservesPullback.iso_hom_snd forget f g dsimp only [Scheme.forgetToLocallyRingedSpace, inducedFunctor_map] at this - rw [← this] change LocallyRingedSpace.IsOpenImmersion _ + rw [← this] infer_instance instance pullback_fst_of_right : IsOpenImmersion (pullback.fst g f) := by @@ -460,11 +487,11 @@ instance forgetToTopPreservesOfRight : PreservesLimit (cospan g f) Scheme.forget preservesPullbackSymmetry _ _ _ theorem range_pullback_snd_of_left : - Set.range (pullback.snd f g).1.base = (g ⁻¹ᵁ f.opensRange).1 := by - rw [← show _ = (pullback.snd f g).1.base from + Set.range (pullback.snd f g).base = (g ⁻¹ᵁ f.opensRange).1 := by + rw [← show _ = (pullback.snd f g).base from PreservesPullback.iso_hom_snd Scheme.forgetToTop f g, TopCat.coe_comp, Set.range_comp, - Set.range_iff_surjective.mpr, ← @Set.preimage_univ _ _ (pullback.fst f.1.base g.1.base)] - -- Porting note (#10691): was `rw` + Set.range_iff_surjective.mpr, ← @Set.preimage_univ _ _ (pullback.fst f.base g.base)] + -- Porting note (#11224): was `rw` · erw [TopCat.pullback_snd_image_fst_preimage] rw [Set.image_univ] rfl @@ -476,12 +503,12 @@ theorem opensRange_pullback_snd_of_left : Opens.ext (range_pullback_snd_of_left f g) theorem range_pullback_fst_of_right : - Set.range (pullback.fst g f).1.base = - ((Opens.map g.1.base).obj ⟨Set.range f.1.base, H.base_open.isOpen_range⟩).1 := by - rw [← show _ = (pullback.fst g f).1.base from + Set.range (pullback.fst g f).base = + ((Opens.map g.base).obj ⟨Set.range f.base, H.base_open.isOpen_range⟩).1 := by + rw [← show _ = (pullback.fst g f).base from PreservesPullback.iso_hom_fst Scheme.forgetToTop g f, TopCat.coe_comp, Set.range_comp, - Set.range_iff_surjective.mpr, ← @Set.preimage_univ _ _ (pullback.snd g.1.base f.1.base)] - -- Porting note (#10691): was `rw` + Set.range_iff_surjective.mpr, ← @Set.preimage_univ _ _ (pullback.snd g.base f.base)] + -- Porting note (#11224): was `rw` · erw [TopCat.pullback_fst_image_snd_preimage] rw [Set.image_univ] rfl @@ -493,16 +520,16 @@ theorem opensRange_pullback_fst_of_right : Opens.ext (range_pullback_fst_of_right f g) theorem range_pullback_to_base_of_left : - Set.range (pullback.fst f g ≫ f).1.base = - Set.range f.1.base ∩ Set.range g.1.base := by - rw [pullback.condition, Scheme.comp_val_base, TopCat.coe_comp, Set.range_comp, + Set.range (pullback.fst f g ≫ f).base = + Set.range f.base ∩ Set.range g.base := by + rw [pullback.condition, Scheme.comp_base, TopCat.coe_comp, Set.range_comp, range_pullback_snd_of_left, Opens.carrier_eq_coe, Opens.map_obj, Opens.coe_mk, Set.image_preimage_eq_inter_range, Opens.carrier_eq_coe, Scheme.Hom.opensRange_coe] theorem range_pullback_to_base_of_right : - Set.range (pullback.fst g f ≫ g).1.base = - Set.range g.1.base ∩ Set.range f.1.base := by - rw [Scheme.comp_val_base, TopCat.coe_comp, Set.range_comp, range_pullback_fst_of_right, + Set.range (pullback.fst g f ≫ g).base = + Set.range g.base ∩ Set.range f.base := by + rw [Scheme.comp_base, TopCat.coe_comp, Set.range_comp, range_pullback_fst_of_right, Opens.map_obj, Opens.carrier_eq_coe, Opens.coe_mk, Set.image_preimage_eq_inter_range, Set.inter_comm] @@ -511,19 +538,20 @@ For an open immersion `f : X ⟶ Z`, given any morphism of schemes `g : Y ⟶ Z` image is contained in the image of `f`, we can lift this morphism to a unique `Y ⟶ X` that commutes with these maps. -/ -def lift (H' : Set.range g.1.base ⊆ Set.range f.1.base) : Y ⟶ X := - LocallyRingedSpace.IsOpenImmersion.lift f g H' +def lift (H' : Set.range g.base ⊆ Set.range f.base) : Y ⟶ X := + ⟨LocallyRingedSpace.IsOpenImmersion.lift f.toLRSHom g.toLRSHom H'⟩ @[simp, reassoc] -theorem lift_fac (H' : Set.range g.1.base ⊆ Set.range f.1.base) : lift f g H' ≫ f = g := - LocallyRingedSpace.IsOpenImmersion.lift_fac f g H' +theorem lift_fac (H' : Set.range g.base ⊆ Set.range f.base) : lift f g H' ≫ f = g := + Scheme.Hom.ext' <| LocallyRingedSpace.IsOpenImmersion.lift_fac f.toLRSHom g.toLRSHom H' -theorem lift_uniq (H' : Set.range g.1.base ⊆ Set.range f.1.base) (l : Y ⟶ X) (hl : l ≫ f = g) : +theorem lift_uniq (H' : Set.range g.base ⊆ Set.range f.base) (l : Y ⟶ X) (hl : l ≫ f = g) : l = lift f g H' := - LocallyRingedSpace.IsOpenImmersion.lift_uniq f g H' l hl + Scheme.Hom.ext' <| LocallyRingedSpace.IsOpenImmersion.lift_uniq + f.toLRSHom g.toLRSHom H' l.toLRSHom congr(($hl).toLRSHom) /-- Two open immersions with equal range are isomorphic. -/ -def isoOfRangeEq [IsOpenImmersion g] (e : Set.range f.1.base = Set.range g.1.base) : X ≅ Y where +def isoOfRangeEq [IsOpenImmersion g] (e : Set.range f.base = Set.range g.base) : X ≅ Y where hom := lift g f (le_of_eq e) inv := lift f g (le_of_eq e.symm) hom_inv_id := by rw [← cancel_mono f]; simp @@ -531,13 +559,13 @@ def isoOfRangeEq [IsOpenImmersion g] (e : Set.range f.1.base = Set.range g.1.bas @[simp, reassoc] lemma isoOfRangeEq_hom_fac {X Y Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) - [IsOpenImmersion f] [IsOpenImmersion g] (e : Set.range f.1.base = Set.range g.1.base) : + [IsOpenImmersion f] [IsOpenImmersion g] (e : Set.range f.base = Set.range g.base) : (isoOfRangeEq f g e).hom ≫ g = f := lift_fac _ _ (le_of_eq e) @[simp, reassoc] lemma isoOfRangeEq_inv_fac {X Y Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) - [IsOpenImmersion f] [IsOpenImmersion g] (e : Set.range f.1.base = Set.range g.1.base) : + [IsOpenImmersion f] [IsOpenImmersion g] (e : Set.range f.base = Set.range g.base) : (isoOfRangeEq f g e).inv ≫ f = g := lift_fac _ _ (le_of_eq e.symm) @@ -545,7 +573,7 @@ theorem app_eq_invApp_app_of_comp_eq_aux {X Y U : Scheme.{u}} (f : Y ⟶ U) (g : (H : fg = f ≫ g) [h : IsOpenImmersion g] (V : U.Opens) : f ⁻¹ᵁ V = fg ⁻¹ᵁ (g ''ᵁ V) := by subst H - rw [Scheme.comp_val_base, Opens.map_comp_obj] + rw [Scheme.comp_base, Opens.map_comp_obj] congr 1 ext1 exact (Set.preimage_image_eq _ h.base_open.inj).symm @@ -600,6 +628,12 @@ def ΓIsoTop {X Y : Scheme.{u}} (f : X ⟶ Y) [IsOpenImmersion f] : Γ(X, ⊤) ≅ Γ(Y, f.opensRange) := (f.appIso ⊤).symm ≪≫ Y.presheaf.mapIso (eqToIso f.image_top_eq_opensRange.symm).op +instance {Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) [IsOpenImmersion f] + (H' : Set.range g.base ⊆ Set.range f.base) [IsOpenImmersion g] : + IsOpenImmersion (IsOpenImmersion.lift f g H') := + haveI : IsOpenImmersion (IsOpenImmersion.lift f g H' ≫ f) := by simpa + IsOpenImmersion.of_comp _ f + end IsOpenImmersion namespace Scheme diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean index c12db5f61af3a..73be6978660ac 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean @@ -10,6 +10,7 @@ import Mathlib.RingTheory.Ideal.MinimalPrime import Mathlib.RingTheory.Ideal.Over import Mathlib.RingTheory.Localization.Away.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs +import Mathlib.RingTheory.LocalRing.RingHom.Basic /-! # The Zariski topology on the prime spectrum of a commutative (semi)ring @@ -105,6 +106,12 @@ theorem isRadical_vanishingIdeal (s : Set (PrimeSpectrum R)) : (vanishingIdeal s vanishingIdeal_zeroLocus_eq_radical] apply Ideal.radical_isRadical +theorem zeroLocus_eq_iff {I J : Ideal R} : + zeroLocus (I : Set R) = zeroLocus J ↔ I.radical = J.radical := by + constructor + · intro h; simp_rw [← vanishingIdeal_zeroLocus_eq_radical, h] + · intro h; rw [← zeroLocus_radical, h, zeroLocus_radical] + theorem vanishingIdeal_anti_mono_iff {s t : Set (PrimeSpectrum R)} (ht : IsClosed t) : s ⊆ t ↔ vanishingIdeal t ≤ vanishingIdeal s := ⟨vanishingIdeal_anti_mono, fun h => by @@ -243,8 +250,8 @@ theorem comap_injective_of_surjective (f : R →+* S) (hf : Function.Surjective variable (S) -theorem localization_comap_inducing [Algebra R S] (M : Submonoid R) [IsLocalization M S] : - Inducing (comap (algebraMap R S)) := by +theorem localization_comap_isInducing [Algebra R S] (M : Submonoid R) [IsLocalization M S] : + IsInducing (comap (algebraMap R S)) := by refine ⟨TopologicalSpace.ext_isClosed fun Z ↦ ?_⟩ simp_rw [isClosed_induced_iff, isClosed_iff_zeroLocus, @eq_comm _ _ (zeroLocus _), exists_exists_eq_and, preimage_comap_zeroLocus] @@ -255,13 +262,19 @@ theorem localization_comap_inducing [Algebra R S] (M : Submonoid R) [IsLocalizat · rintro ⟨s, rfl⟩ exact ⟨_, rfl⟩ +@[deprecated (since := "2024-10-28")] +alias localization_comap_inducing := localization_comap_isInducing + theorem localization_comap_injective [Algebra R S] (M : Submonoid R) [IsLocalization M S] : Function.Injective (comap (algebraMap R S)) := fun _ _ h => localization_specComap_injective S M h -theorem localization_comap_embedding [Algebra R S] (M : Submonoid R) [IsLocalization M S] : - Embedding (comap (algebraMap R S)) := - ⟨localization_comap_inducing S M, localization_comap_injective S M⟩ +theorem localization_comap_isEmbedding [Algebra R S] (M : Submonoid R) [IsLocalization M S] : + IsEmbedding (comap (algebraMap R S)) := + ⟨localization_comap_isInducing S M, localization_comap_injective S M⟩ + +@[deprecated (since := "2024-10-26")] +alias localization_comap_embedding := localization_comap_isEmbedding theorem localization_comap_range [Algebra R S] (M : Submonoid R) [IsLocalization M S] : Set.range (comap (algebraMap R S)) = { p | Disjoint (M : Set R) p.asIdeal } := @@ -269,13 +282,10 @@ theorem localization_comap_range [Algebra R S] (M : Submonoid R) [IsLocalization open Function RingHom -theorem comap_inducing_of_surjective (hf : Surjective f) : Inducing (comap f) where - induced := by - set_option tactic.skipAssignedInstances false in - simp_rw [TopologicalSpace.ext_iff, ← isClosed_compl_iff, - ← @isClosed_compl_iff (PrimeSpectrum S) - ((TopologicalSpace.induced (comap f) zariskiTopology)), isClosed_induced_iff, - isClosed_iff_zeroLocus] +theorem comap_isInducing_of_surjective (hf : Surjective f) : IsInducing (comap f) where + eq_induced := by + simp only [TopologicalSpace.ext_iff, ← isClosed_compl_iff, isClosed_iff_zeroLocus, + isClosed_induced_iff] refine fun s => ⟨fun ⟨F, hF⟩ => ⟨zeroLocus (f ⁻¹' F), ⟨f ⁻¹' F, rfl⟩, by @@ -284,6 +294,9 @@ theorem comap_inducing_of_surjective (hf : Surjective f) : Inducing (comap f) wh rintro ⟨-, ⟨F, rfl⟩, hF⟩ exact ⟨f '' F, hF.symm.trans (preimage_comap_zeroLocus f F)⟩ +@[deprecated (since := "2024-10-28")] +alias comap_inducing_of_surjective := comap_isInducing_of_surjective + end Comap end CommSemiRing @@ -325,10 +338,13 @@ theorem isClosed_range_comap_of_surjective (hf : Surjective f) : rw [range_comap_of_surjective _ f hf] exact isClosed_zeroLocus _ -theorem closedEmbedding_comap_of_surjective (hf : Surjective f) : ClosedEmbedding (comap f) := - { induced := (comap_inducing_of_surjective S f hf).induced - inj := comap_injective_of_surjective f hf - isClosed_range := isClosed_range_comap_of_surjective S f hf } +lemma isClosedEmbedding_comap_of_surjective (hf : Surjective f) : IsClosedEmbedding (comap f) where + toIsInducing := comap_isInducing_of_surjective S f hf + inj := comap_injective_of_surjective f hf + isClosed_range := isClosed_range_comap_of_surjective S f hf + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_comap_of_surjective := isClosedEmbedding_comap_of_surjective end SpecOfSurjective @@ -349,18 +365,19 @@ to the disjoint union of `PrimeSpectrum R` and `PrimeSpectrum S`. -/ noncomputable def primeSpectrumProdHomeo : PrimeSpectrum (R × S) ≃ₜ PrimeSpectrum R ⊕ PrimeSpectrum S := by - refine ((primeSpectrumProd R S).symm.toHomeomorphOfInducing ?_).symm - refine (closedEmbedding_of_continuous_injective_closed ?_ (Equiv.injective _) ?_).toInducing + refine ((primeSpectrumProd R S).symm.toHomeomorphOfIsInducing ?_).symm + refine (IsClosedEmbedding.of_continuous_injective_isClosedMap ?_ + (Equiv.injective _) ?_).isInducing · rw [continuous_sum_dom] simp only [Function.comp_def, primeSpectrumProd_symm_inl, primeSpectrumProd_symm_inr] exact ⟨(comap _).2, (comap _).2⟩ · rw [isClosedMap_sum] constructor · simp_rw [primeSpectrumProd_symm_inl] - refine (closedEmbedding_comap_of_surjective _ _ ?_).isClosedMap + refine (isClosedEmbedding_comap_of_surjective _ _ ?_).isClosedMap exact Prod.fst_surjective · simp_rw [primeSpectrumProd_symm_inr] - refine (closedEmbedding_comap_of_surjective _ _ ?_).isClosedMap + refine (isClosedEmbedding_comap_of_surjective _ _ ?_).isClosedMap exact Prod.snd_surjective end SpecProd @@ -456,12 +473,15 @@ theorem localization_away_comap_range (S : Type v) [CommSemiring S] [Algebra R S · rintro h₁ _ ⟨⟨n, rfl⟩, h₃⟩ exact h₁ (x.2.mem_of_pow_mem _ h₃) -theorem localization_away_openEmbedding (S : Type v) [CommSemiring S] [Algebra R S] (r : R) - [IsLocalization.Away r S] : OpenEmbedding (comap (algebraMap R S)) := - { toEmbedding := localization_comap_embedding S (Submonoid.powers r) - isOpen_range := by - rw [localization_away_comap_range S r] - exact isOpen_basicOpen } +theorem localization_away_isOpenEmbedding (S : Type v) [CommSemiring S] [Algebra R S] (r : R) + [IsLocalization.Away r S] : IsOpenEmbedding (comap (algebraMap R S)) where + toIsEmbedding := localization_comap_isEmbedding S (Submonoid.powers r) + isOpen_range := by + rw [localization_away_comap_range S r] + exact isOpen_basicOpen + +@[deprecated (since := "2024-10-18")] +alias localization_away_openEmbedding := localization_away_isOpenEmbedding theorem isCompact_basicOpen (f : R) : IsCompact (basicOpen f : Set (PrimeSpectrum R)) := by rw [← localization_away_comap_range (Localization (Submonoid.powers f))] @@ -537,6 +557,85 @@ protected def pointsEquivIrreducibleCloseds : map_rel_iff' {p q} := (RelIso.symm irreducibleSetEquivPoints).map_rel_iff.trans (le_iff_specializes p q).symm +/-- Also see `PrimeSpectrum.isClosed_singleton_iff_isMaximal` -/ +lemma isMax_iff {x : PrimeSpectrum R} : + IsMax x ↔ x.asIdeal.IsMaximal := by + refine ⟨fun hx ↦ ⟨⟨x.2.ne_top, fun I hI ↦ ?_⟩⟩, fun hx y e ↦ (hx.eq_of_le y.2.ne_top e).ge⟩ + by_contra e + obtain ⟨m, hm, hm'⟩ := Ideal.exists_le_maximal I e + exact hx.not_lt (show x < ⟨m, hm.isPrime⟩ from hI.trans_le hm') + +lemma stableUnderSpecialization_singleton {x : PrimeSpectrum R} : + StableUnderSpecialization {x} ↔ x.asIdeal.IsMaximal := by + simp_rw [← isMax_iff, StableUnderSpecialization, ← le_iff_specializes, Set.mem_singleton_iff, + @forall_comm _ (_ = _), forall_eq] + exact ⟨fun H a h ↦ (H a h).le, fun H a h ↦ le_antisymm (H h) h⟩ + +lemma isMin_iff {x : PrimeSpectrum R} : + IsMin x ↔ x.asIdeal ∈ minimalPrimes R := by + show IsMin _ ↔ Minimal (fun q : Ideal R ↦ q.IsPrime ∧ ⊥ ≤ q) _ + simp only [IsMin, Minimal, x.2, bot_le, and_self, and_true, true_and] + exact ⟨fun H y hy e ↦ @H ⟨y, hy⟩ e, fun H y e ↦ H y.2 e⟩ + +lemma stableUnderGeneralization_singleton {x : PrimeSpectrum R} : + StableUnderGeneralization {x} ↔ x.asIdeal ∈ minimalPrimes R := by + simp_rw [← isMin_iff, StableUnderGeneralization, ← le_iff_specializes, Set.mem_singleton_iff, + @forall_comm _ (_ = _), forall_eq] + exact ⟨fun H a h ↦ (H a h).ge, fun H a h ↦ le_antisymm h (H h)⟩ + +lemma isCompact_isOpen_iff {s : Set (PrimeSpectrum R)} : + IsCompact s ∧ IsOpen s ↔ ∃ t : Finset R, (zeroLocus t)ᶜ = s := by + rw [isCompact_open_iff_eq_finite_iUnion_of_isTopologicalBasis _ + isTopologicalBasis_basic_opens isCompact_basicOpen] + simp only [basicOpen_eq_zeroLocus_compl, ← Set.compl_iInter₂, ← zeroLocus_iUnion₂, + Set.biUnion_of_singleton] + exact ⟨fun ⟨s, hs, e⟩ ↦ ⟨hs.toFinset, by simpa using e.symm⟩, + fun ⟨s, e⟩ ↦ ⟨s, s.finite_toSet, by simpa using e.symm⟩⟩ + +lemma isCompact_isOpen_iff_ideal {s : Set (PrimeSpectrum R)} : + IsCompact s ∧ IsOpen s ↔ + ∃ I : Ideal R, I.FG ∧ (PrimeSpectrum.zeroLocus (I : Set R))ᶜ = s := by + rw [isCompact_isOpen_iff] + exact ⟨fun ⟨s, e⟩ ↦ ⟨.span s, ⟨s, rfl⟩, by simpa using e⟩, + fun ⟨I, ⟨s, hs⟩, e⟩ ↦ ⟨s, by simpa [hs.symm] using e⟩⟩ + +lemma exists_idempotent_basicOpen_eq_of_is_clopen {s : Set (PrimeSpectrum R)} + (hs : IsClopen s) : ∃ e : R, IsIdempotentElem e ∧ s = basicOpen e := by + cases subsingleton_or_nontrivial R + · exact ⟨0, Subsingleton.elim _ _, Subsingleton.elim _ _⟩ + obtain ⟨I, hI, hI'⟩ := isCompact_isOpen_iff_ideal.mp ⟨hs.1.isCompact, hs.2⟩ + obtain ⟨J, hJ, hJ'⟩ := isCompact_isOpen_iff_ideal.mp + ⟨hs.2.isClosed_compl.isCompact, hs.1.isOpen_compl⟩ + simp only [compl_eq_iff_isCompl, ← eq_compl_iff_isCompl, compl_compl] at hI' hJ' + have : I * J ≤ nilradical R := by + refine Ideal.radical_le_radical_iff.mp (le_of_eq ?_) + rw [← zeroLocus_eq_iff, Ideal.zero_eq_bot, zeroLocus_bot, + zeroLocus_mul, hI', hJ', Set.compl_union_self] + obtain ⟨n, hn⟩ := Ideal.exists_pow_le_of_le_radical_of_fg this (Submodule.FG.mul hI hJ) + have hnz : n ≠ 0 := by rintro rfl; simp at hn + rw [mul_pow, Ideal.zero_eq_bot] at hn + have : I ^ n ⊔ J ^ n = ⊤ := by + rw [eq_top_iff, ← Ideal.span_pow_eq_top (I ∪ J : Set R) _ n, Ideal.span_le, Set.image_union, + Set.union_subset_iff] + constructor + · rintro _ ⟨x, hx, rfl⟩; exact Ideal.mem_sup_left (Ideal.pow_mem_pow hx n) + · rintro _ ⟨x, hx, rfl⟩; exact Ideal.mem_sup_right (Ideal.pow_mem_pow hx n) + · rw [Ideal.span_union, Ideal.span_eq, Ideal.span_eq, ← zeroLocus_empty_iff_eq_top, + zeroLocus_sup, hI', hJ', Set.compl_inter_self] + rw [Ideal.eq_top_iff_one, Submodule.mem_sup] at this + obtain ⟨x, hx, y, hy, e⟩ := this + refine ⟨x, ?_, subset_antisymm ?_ ?_⟩ + · replace e := congr(x * $e) + rwa [mul_add, hn (Ideal.mul_mem_mul hx hy), add_zero, mul_one] at e + · rw [PrimeSpectrum.basicOpen_eq_zeroLocus_compl, Set.subset_compl_iff_disjoint_left, + Set.disjoint_iff_inter_eq_empty, ← hJ', ← zeroLocus_span, + ← zeroLocus_sup, zeroLocus_empty_iff_eq_top, + Ideal.eq_top_iff_one, ← e] + exact Submodule.add_mem_sup (Ideal.subset_span (Set.mem_singleton _)) (Ideal.pow_le_self hnz hy) + · rw [PrimeSpectrum.basicOpen_eq_zeroLocus_compl, Set.compl_subset_comm, ← hI'] + exact PrimeSpectrum.zeroLocus_anti_mono + (Set.singleton_subset_iff.mpr <| Ideal.pow_le_self hnz hx) + section LocalizationAtMinimal variable {I : Ideal R} [hI : I.IsPrime] @@ -623,17 +722,20 @@ def closedPoint : PrimeSpectrum R := variable {R} -theorem isLocalRingHom_iff_comap_closedPoint {S : Type v} [CommSemiring S] [LocalRing S] - (f : R →+* S) : IsLocalRingHom f ↔ PrimeSpectrum.comap f (closedPoint S) = closedPoint R := by +theorem isLocalHom_iff_comap_closedPoint {S : Type v} [CommSemiring S] [LocalRing S] + (f : R →+* S) : IsLocalHom f ↔ PrimeSpectrum.comap f (closedPoint S) = closedPoint R := by -- Porting note: inline `this` does **not** work have := (local_hom_TFAE f).out 0 4 rw [this, PrimeSpectrum.ext_iff] rfl +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_iff_comap_closedPoint := isLocalHom_iff_comap_closedPoint + @[simp] theorem comap_closedPoint {S : Type v} [CommSemiring S] [LocalRing S] (f : R →+* S) - [IsLocalRingHom f] : PrimeSpectrum.comap f (closedPoint S) = closedPoint R := - (isLocalRingHom_iff_comap_closedPoint f).mp inferInstance + [IsLocalHom f] : PrimeSpectrum.comap f (closedPoint S) = closedPoint R := + (isLocalHom_iff_comap_closedPoint f).mp inferInstance theorem specializes_closedPoint (x : PrimeSpectrum R) : x ⤳ closedPoint R := (PrimeSpectrum.le_iff_specializes _ _).mp (LocalRing.le_maximalIdeal x.2.1) @@ -646,6 +748,10 @@ theorem closedPoint_mem_iff (U : TopologicalSpace.Opens <| PrimeSpectrum R) : · rintro rfl trivial +lemma closed_point_mem_iff {U : TopologicalSpace.Opens (PrimeSpectrum R)} : + closedPoint R ∈ U ↔ U = ⊤ := + ⟨(eq_top_iff.mpr fun x _ ↦ (specializes_closedPoint x).mem_open U.2 ·), (· ▸ trivial)⟩ + @[simp] theorem PrimeSpectrum.comap_residue (T : Type u) [CommRing T] [LocalRing T] (x : PrimeSpectrum (ResidueField T)) : PrimeSpectrum.comap (residue T) x = closedPoint T := by @@ -663,3 +769,41 @@ theorem PrimeSpectrum.topologicalKrullDim_eq_ringKrullDim [CommRing R] : (PrimeSpectrum.pointsEquivIrreducibleCloseds R).symm end KrullDimension + +section Idempotent + +variable {R} [CommRing R] + +lemma PrimeSpectrum.basicOpen_eq_zeroLocus_of_isIdempotentElem + (e : R) (he : IsIdempotentElem e) : + basicOpen e = zeroLocus {1 - e} := by + ext p + suffices e ∉ p.asIdeal ↔ 1 - e ∈ p.asIdeal by simpa + constructor + · refine (p.2.mem_or_mem_of_mul_eq_zero ?_).resolve_left + rw [mul_sub, mul_one, he.eq, sub_self] + · refine fun h₁ h₂ ↦ p.2.1 ?_ + rw [Ideal.eq_top_iff_one, ← sub_add_cancel 1 e] + exact add_mem h₁ h₂ + +lemma PrimeSpectrum.zeroLocus_eq_basicOpen_of_isIdempotentElem + (e : R) (he : IsIdempotentElem e) : + zeroLocus {e} = basicOpen (1 - e) := by + rw [basicOpen_eq_zeroLocus_of_isIdempotentElem _ he.one_sub, sub_sub_cancel] + +lemma PrimeSpectrum.isClopen_iff {s : Set (PrimeSpectrum R)} : + IsClopen s ↔ ∃ e : R, IsIdempotentElem e ∧ s = basicOpen e := by + refine ⟨PrimeSpectrum.exists_idempotent_basicOpen_eq_of_is_clopen, ?_⟩ + rintro ⟨e, he, rfl⟩ + refine ⟨?_, (basicOpen e).2⟩ + rw [PrimeSpectrum.basicOpen_eq_zeroLocus_of_isIdempotentElem e he] + exact isClosed_zeroLocus _ + +lemma PrimeSpectrum.isClopen_iff_zeroLocus {s : Set (PrimeSpectrum R)} : + IsClopen s ↔ ∃ e : R, IsIdempotentElem e ∧ s = zeroLocus {e} := by + rw [isClopen_iff] + refine ⟨fun ⟨e, he, h⟩ ↦ ⟨1 - e, he.one_sub, + h.trans (basicOpen_eq_zeroLocus_of_isIdempotentElem e he)⟩, fun ⟨e, he, h⟩ ↦ + ⟨1 - e, he.one_sub, h.trans (zeroLocus_eq_basicOpen_of_isIdempotentElem e he)⟩⟩ + +end Idempotent diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean new file mode 100644 index 0000000000000..920ac15a81fe7 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean @@ -0,0 +1,82 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.PrimeSpectrum.Noetherian +import Mathlib.RingTheory.Jacobson + +/-! +# The prime spectrum of a jacobson ring + +## Main results +- `PrimeSpectrum.exists_isClosed_singleton_of_isJacobson`: + The spectrum of a jacobson ring is a jacobson space. +- `PrimeSpectrum.isOpen_singleton_tfae_of_isNoetherian_of_isJacobson`: + If `R` is both noetherian and jacobson, then the following are equivalent for `x : Spec R`: + 1. `{x}` is open (i.e. `x` is an isolated point) + 2. `{x}` is clopen + 3. `{x}` is both closed and stable under generalization + (i.e. `x` is both a minimal prime and a maximal ideal) +-/ + +open Ideal + +variable {R : Type*} [CommRing R] [IsJacobson R] + +namespace PrimeSpectrum + +lemma exists_isClosed_singleton_of_isJacobson + (s : (Set (PrimeSpectrum R))) (hs : IsOpen s) (hs' : s.Nonempty) : + ∃ x ∈ s, IsClosed {x} := by + simp_rw [isClosed_singleton_iff_isMaximal] + obtain ⟨I, hI'⟩ := (isClosed_iff_zeroLocus_ideal _).mp hs.isClosed_compl + simp_rw [← @Set.not_mem_compl_iff _ s, hI', mem_zeroLocus] + have := hs'.ne_empty + contrapose! this + simp_rw [not_imp_not] at this + rw [← Set.compl_univ, eq_compl_comm, hI', eq_comm, ← zeroLocus_bot, + zeroLocus_eq_iff, Ideal.radical_eq_jacobson, Ideal.radical_eq_jacobson] + refine le_antisymm (le_sInf ?_) (Ideal.jacobson_mono bot_le) + rintro x ⟨-, hx⟩ + exact sInf_le ⟨this ⟨x, hx.isPrime⟩ hx, hx⟩ + +/-- +If `R` is both noetherian and jacobson, then the following are equivalent for `x : Spec R`: +1. `{x}` is open (i.e. `x` is an isolated point) +2. `{x}` is clopen +3. `{x}` is both closed and stable under generalization + (i.e. `x` is both a minimal prime and a maximal ideal) +-/ +lemma isOpen_singleton_tfae_of_isNoetherian_of_isJacobson + [IsNoetherianRing R] (x : PrimeSpectrum R) : + List.TFAE [IsOpen {x}, IsClopen {x}, IsClosed {x} ∧ StableUnderGeneralization {x}] := by + tfae_have 1 → 2 + · intro h + obtain ⟨y, rfl : y = x, h'⟩ := exists_isClosed_singleton_of_isJacobson _ h + ⟨x, Set.mem_singleton x⟩ + exact ⟨h', h⟩ + tfae_have 2 → 3 + · exact fun h ↦ ⟨h.isClosed, h.isOpen.stableUnderGeneralization⟩ + tfae_have 3 → 1 + · intro ⟨h₁, h₂⟩ + rw [isClosed_singleton_iff_isMaximal, ← isMax_iff] at h₁ + suffices {x} = (⋃ p ∈ { p : PrimeSpectrum R | IsMin p ∧ p ≠ x }, closure {p})ᶜ by + rw [this, isOpen_compl_iff] + refine Set.Finite.isClosed_biUnion ?_ (fun _ _ ↦ isClosed_closure) + exact (finite_setOf_isMin R).subset fun x h ↦ h.1 + ext p + simp only [Set.mem_singleton_iff, ne_eq, Set.mem_setOf_eq, Set.compl_iUnion, Set.mem_iInter, + Set.mem_compl_iff, and_imp, ← specializes_iff_mem_closure, ← le_iff_specializes, + not_imp_not] + constructor + · rintro rfl _ _ + rw [stableUnderGeneralization_singleton, ← isMin_iff] at h₂ + exact h₂.eq_of_le + · intros hp + apply h₁.eq_of_ge + obtain ⟨q, hq, hq'⟩ := Ideal.exists_minimalPrimes_le (J := p.asIdeal) bot_le + exact (hp ⟨q, hq.1.1⟩ (isMin_iff.mpr hq) hq').ge.trans hq' + tfae_finish + +end PrimeSpectrum diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean index 1e92a49a98670..54db36be2f8f2 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean @@ -19,13 +19,19 @@ open TopologicalSpace variable (R : Type u) [CommRing R] [IsNoetherianRing R] -instance : NoetherianSpace (PrimeSpectrum R) := by - apply ((noetherianSpace_TFAE <| PrimeSpectrum R).out 0 1).mpr - exact (closedsEmbedding R).dual.wellFounded IsWellFounded.wf +instance : NoetherianSpace (PrimeSpectrum R) := + ((noetherianSpace_TFAE <| PrimeSpectrum R).out 0 1).mpr (closedsEmbedding R).dual.wellFoundedLT lemma _root_.minimalPrimes.finite_of_isNoetherianRing : (minimalPrimes R).Finite := minimalPrimes.equivIrreducibleComponents R |>.set_finite_iff |>.mpr NoetherianSpace.finite_irreducibleComponents +lemma finite_setOf_isMin : + {x : PrimeSpectrum R | IsMin x }.Finite := by + have : Function.Injective (asIdeal (R := R)) := @PrimeSpectrum.ext _ _ + refine Set.Finite.of_finite_image (f := asIdeal) ?_ this.injOn + simp_rw [isMin_iff] + exact (minimalPrimes.finite_of_isNoetherianRing R).subset (Set.image_preimage_subset _ _) + end PrimeSpectrum diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/TensorProduct.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/TensorProduct.lean index c13845fdd8fb9..457e6d0a254f5 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/TensorProduct.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/TensorProduct.lean @@ -11,7 +11,7 @@ import Mathlib.AlgebraicGeometry.PrimeSpectrum.Basic # Lemmas regarding the prime spectrum of tensor products ## Main result -- `PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks`: +- `PrimeSpectrum.isEmbedding_tensorProductTo_of_surjectiveOnStalks`: If `R →+* T` is surjective on stalks (see Mathlib/RingTheory/SurjectiveOnStalks.lean), then `Spec(S ⊗[R] T) → Spec S × Spec T` is a topological embedding (where `Spec S × Spec T` is the cartesian product with the product topology). @@ -34,7 +34,7 @@ lemma PrimeSpectrum.continuous_tensorProductTo : Continuous (tensorProductTo R S variable (hRT : (algebraMap R T).SurjectiveOnStalks) include hRT -lemma PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks_aux +lemma PrimeSpectrum.isEmbedding_tensorProductTo_of_surjectiveOnStalks_aux (p₁ p₂ : PrimeSpectrum (S ⊗[R] T)) (h : tensorProductTo R S T p₁ = tensorProductTo R S T p₂) : p₁ ≤ p₂ := by @@ -55,11 +55,11 @@ lemma PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks_aux rwa [show p₁.asIdeal.comap (algebraMap S (S ⊗[R] T)) = p₂.asIdeal.comap _ from congr($h.1.1)] exact p₁.asIdeal.primeCompl.mul_mem h₄ h₃ h₁ -lemma PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks : - Embedding (tensorProductTo R S T) := by +lemma PrimeSpectrum.isEmbedding_tensorProductTo_of_surjectiveOnStalks : + IsEmbedding (tensorProductTo R S T) := by refine ⟨?_, fun p₁ p₂ e ↦ - (embedding_tensorProductTo_of_surjectiveOnStalks_aux R S T hRT p₁ p₂ e).antisymm - (embedding_tensorProductTo_of_surjectiveOnStalks_aux R S T hRT p₂ p₁ e.symm)⟩ + (isEmbedding_tensorProductTo_of_surjectiveOnStalks_aux R S T hRT p₁ p₂ e).antisymm + (isEmbedding_tensorProductTo_of_surjectiveOnStalks_aux R S T hRT p₂ p₁ e.symm)⟩ let g : T →+* S ⊗[R] T := Algebra.TensorProduct.includeRight.toRingHom refine ⟨(continuous_tensorProductTo ..).le_induced.antisymm (isBasis_basic_opens.le_iff.mpr ?_)⟩ rintro _ ⟨f, rfl⟩ @@ -77,3 +77,7 @@ lemma PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks : rw [Algebra.TensorProduct.tmul_mul_tmul, mul_one, one_mul, ← e] exact J.asIdeal.primeCompl.mul_mem ht hJ rwa [J.isPrime.mul_mem_iff_mem_or_mem.not, not_or] at this + +@[deprecated (since := "2024-10-26")] +alias PrimeSpectrum.embedding_tensorProductTo_of_surjectiveOnStalks := + PrimeSpectrum.isEmbedding_tensorProductTo_of_surjectiveOnStalks diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean index 938d2b0845645..dae30030d3507 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean @@ -122,12 +122,13 @@ local notation3 "Proj.T" => PresheafedSpace.carrier <| SheafedSpace.toPresheafed /-- `Proj` restrict to some open set -/ macro "Proj| " U:term : term => - `((Proj.toLocallyRingedSpace 𝒜).restrict (Opens.openEmbedding (X := Proj.T) ($U : Opens Proj.T))) + `((Proj.toLocallyRingedSpace 𝒜).restrict + (Opens.isOpenEmbedding (X := Proj.T) ($U : Opens Proj.T))) /-- the underlying topological space of `Proj` restricted to some open set -/ local notation "Proj.T| " U => PresheafedSpace.carrier <| SheafedSpace.toPresheafedSpace <| LocallyRingedSpace.toSheafedSpace - <| (LocallyRingedSpace.restrict Proj (Opens.openEmbedding (X := Proj.T) (U : Opens Proj.T))) + <| (LocallyRingedSpace.restrict Proj (Opens.isOpenEmbedding (X := Proj.T) (U : Opens Proj.T))) /-- basic open sets in `Proj` -/ local notation "pbo " x => ProjectiveSpectrum.basicOpen 𝒜 x @@ -294,12 +295,7 @@ theorem mem_carrier_iff_of_mem (hm : 0 < m) (q : Spec.T A⁰_ f) (a : A) {n} (hn trans (HomogeneousLocalization.mk ⟨m * n, ⟨proj 𝒜 n a ^ m, by rw [← smul_eq_mul]; mem_tac⟩, ⟨f ^ n, by rw [mul_comm]; mem_tac⟩, ⟨_, rfl⟩⟩ : A⁰_ f) ∈ q.asIdeal · refine ⟨fun h ↦ h n, fun h i ↦ if hi : i = n then hi ▸ h else ?_⟩ - #adaptation_note - /-- - After https://github.com/leanprover/lean4/pull/5376 - we need to specify the implicit arguments by `inferInstance`. - -/ - convert @zero_mem _ _ inferInstance inferInstance _ q.asIdeal + convert zero_mem q.asIdeal apply HomogeneousLocalization.val_injective simp only [proj_apply, decompose_of_mem_ne _ hn (Ne.symm hi), zero_pow hm.ne', HomogeneousLocalization.val_mk, Localization.mk_zero, HomogeneousLocalization.val_zero] @@ -407,7 +403,7 @@ theorem carrier.smul_mem (c x : A) (hx : x ∈ carrier f_deg q) : c • x ∈ ca HomogeneousLocalization.val_mul, HomogeneousLocalization.val_mk, HomogeneousLocalization.val_mk] · simp_rw [mul_pow]; rw [Localization.mk_mul] - · congr; erw [← pow_add, Nat.add_sub_of_le h] + · congr; rw [← pow_add, Nat.add_sub_of_le h] · apply Ideal.mul_mem_left (α := A⁰_ f) _ _ (hx _) rw [(_ : m • n = _)] · mem_tac @@ -459,7 +455,7 @@ theorem carrier.asIdeal.ne_top : carrier.asIdeal f_deg hm q ≠ ⊤ := fun rid = theorem carrier.asIdeal.prime : (carrier.asIdeal f_deg hm q).IsPrime := (carrier.asIdeal.homogeneous f_deg hm q).isPrime_of_homogeneous_mem_or_mem (carrier.asIdeal.ne_top f_deg hm q) fun {x y} ⟨nx, hnx⟩ ⟨ny, hny⟩ hxy => - show (∀ i, _ ∈ _) ∨ ∀ i, _ ∈ _ by + show (∀ _, _ ∈ _) ∨ ∀ _, _ ∈ _ by rw [← and_forall_ne nx, and_iff_left, ← and_forall_ne ny, and_iff_left] · apply q.2.mem_or_mem; convert hxy (nx + ny) using 1 dsimp @@ -599,9 +595,9 @@ def awayToSection (f) : CommRingCat.of (A⁰_ f) ⟶ (structureSheaf 𝒜).1.obj map_zero' := by ext; simp only [map_zero, HomogeneousLocalization.val_zero, Proj.zero_apply] map_one' := by ext; simp only [map_one, HomogeneousLocalization.val_one, Proj.one_apply] -lemma awayToSection_germ (f x) : - awayToSection 𝒜 f ≫ (structureSheaf 𝒜).presheaf.germ x = - (HomogeneousLocalization.mapId 𝒜 (Submonoid.powers_le.mpr x.2)) ≫ +lemma awayToSection_germ (f x hx) : + awayToSection 𝒜 f ≫ (structureSheaf 𝒜).presheaf.germ _ x hx = + (HomogeneousLocalization.mapId 𝒜 (Submonoid.powers_le.mpr hx)) ≫ (Proj.stalkIso' 𝒜 x).toCommRingCatIso.inv := by ext z apply (Proj.stalkIso' 𝒜 x).eq_symm_apply.mpr @@ -615,13 +611,13 @@ Mathematically, the map is the same as `awayToSection`. -/ def awayToΓ (f) : CommRingCat.of (A⁰_ f) ⟶ LocallyRingedSpace.Γ.obj (op <| Proj| pbo f) := awayToSection 𝒜 f ≫ (ProjectiveSpectrum.Proj.structureSheaf 𝒜).1.map - (homOfLE (Opens.openEmbedding_obj_top _).le).op + (homOfLE (Opens.isOpenEmbedding_obj_top _).le).op lemma awayToΓ_ΓToStalk (f) (x) : awayToΓ 𝒜 f ≫ (Proj| pbo f).presheaf.Γgerm x = HomogeneousLocalization.mapId 𝒜 (Submonoid.powers_le.mpr x.2) ≫ (Proj.stalkIso' 𝒜 x.1).toCommRingCatIso.inv ≫ - ((Proj.toLocallyRingedSpace 𝒜).restrictStalkIso (Opens.openEmbedding _) x).inv := by + ((Proj.toLocallyRingedSpace 𝒜).restrictStalkIso (Opens.isOpenEmbedding _) x).inv := by rw [awayToΓ, Category.assoc, ← Category.assoc _ (Iso.inv _), Iso.eq_comp_inv, Category.assoc, Category.assoc, Presheaf.Γgerm] rw [LocallyRingedSpace.restrictStalkIso_hom_eq_germ] @@ -640,17 +636,17 @@ def toSpec (f) : (Proj| pbo f) ⟶ Spec (A⁰_ f) := open HomogeneousLocalization LocalRing lemma toSpec_base_apply_eq_comap {f} (x : Proj| pbo f) : - (toSpec 𝒜 f).1.base x = PrimeSpectrum.comap (mapId 𝒜 (Submonoid.powers_le.mpr x.2)) + (toSpec 𝒜 f).base x = PrimeSpectrum.comap (mapId 𝒜 (Submonoid.powers_le.mpr x.2)) (closedPoint (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal)) := by show PrimeSpectrum.comap (awayToΓ 𝒜 f ≫ (Proj| pbo f).presheaf.Γgerm x) (LocalRing.closedPoint ((Proj| pbo f).presheaf.stalk x)) = _ rw [awayToΓ_ΓToStalk, CommRingCat.comp_eq_ring_hom_comp, PrimeSpectrum.comap_comp] exact congr(PrimeSpectrum.comap _ $(@LocalRing.comap_closedPoint (HomogeneousLocalization.AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) _ _ - ((Proj| pbo f).presheaf.stalk x) _ _ _ (isLocalRingHom_of_isIso _))) + ((Proj| pbo f).presheaf.stalk x) _ _ _ (isLocalHom_of_isIso _))) lemma toSpec_base_apply_eq {f} (x : Proj| pbo f) : - (toSpec 𝒜 f).1.base x = ProjIsoSpecTopComponent.toSpec 𝒜 f x := + (toSpec 𝒜 f).base x = ProjIsoSpecTopComponent.toSpec 𝒜 f x := toSpec_base_apply_eq_comap 𝒜 x |>.trans <| PrimeSpectrum.ext <| Ideal.ext fun z => show ¬ IsUnit _ ↔ z ∈ ProjIsoSpecTopComponent.ToSpec.carrier _ by obtain ⟨z, rfl⟩ := z.mk_surjective @@ -661,19 +657,19 @@ lemma toSpec_base_apply_eq {f} (x : Proj| pbo f) : exact not_not lemma toSpec_base_isIso {f} {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : - IsIso (toSpec 𝒜 f).1.base := by + IsIso (toSpec 𝒜 f).base := by convert (projIsoSpecTopComponent f_deg hm).isIso_hom exact DFunLike.ext _ _ <| toSpec_base_apply_eq 𝒜 lemma mk_mem_toSpec_base_apply {f} (x : Proj| pbo f) (z : NumDenSameDeg 𝒜 (.powers f)) : - HomogeneousLocalization.mk z ∈ ((toSpec 𝒜 f).1.base x).asIdeal ↔ + HomogeneousLocalization.mk z ∈ ((toSpec 𝒜 f).base x).asIdeal ↔ z.num.1 ∈ x.1.asHomogeneousIdeal := (toSpec_base_apply_eq 𝒜 x).symm ▸ ProjIsoSpecTopComponent.ToSpec.mk_mem_carrier _ _ lemma toSpec_preimage_basicOpen {f} (t : NumDenSameDeg 𝒜 (.powers f)) : - (Opens.map (toSpec 𝒜 f).1.base).obj (sbo (.mk t)) = + (Opens.map (toSpec 𝒜 f).base).obj (sbo (.mk t)) = Opens.comap ⟨_, continuous_subtype_val⟩ (pbo t.num.1) := Opens.ext <| Opens.map_coe _ _ ▸ by convert (ProjIsoSpecTopComponent.ToSpec.preimage_basicOpen f t) @@ -681,7 +677,7 @@ lemma toSpec_preimage_basicOpen {f} @[reassoc] lemma toOpen_toSpec_val_c_app (f) (U) : - StructureSheaf.toOpen (A⁰_ f) U.unop ≫ (toSpec 𝒜 f).val.c.app U = + StructureSheaf.toOpen (A⁰_ f) U.unop ≫ (toSpec 𝒜 f).c.app U = awayToΓ 𝒜 f ≫ (Proj| pbo f).presheaf.map (homOfLE le_top).op := Eq.trans (by congr) <| ΓSpec.toOpen_comp_locallyRingedSpaceAdjunction_homEquiv_app _ U @@ -690,9 +686,9 @@ lemma toStalk_stalkMap_toSpec (f) (x) : StructureSheaf.toStalk _ _ ≫ (toSpec 𝒜 f).stalkMap x = awayToΓ 𝒜 f ≫ (Proj| pbo f).presheaf.Γgerm x := by rw [StructureSheaf.toStalk, Category.assoc] - simp_rw [CommRingCat.coe_of] - erw [PresheafedSpace.stalkMap_germ'] - rw [toOpen_toSpec_val_c_app_assoc, Presheaf.germ_res] + simp_rw [CommRingCat.coe_of, ← Spec.locallyRingedSpaceObj_presheaf'] + rw [LocallyRingedSpace.stalkMap_germ (toSpec 𝒜 f), + toOpen_toSpec_val_c_app_assoc, Presheaf.germ_res] rfl /-- @@ -702,7 +698,7 @@ of `A⁰_f` at `φ(x)` where `φ : Proj|D(f) ⟶ Spec A⁰_f` is the morphism of constructed as above. -/ lemma isLocalization_atPrime (f) (x : pbo f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : - @IsLocalization (Away 𝒜 f) _ ((toSpec 𝒜 f).1.base x).asIdeal.primeCompl + @IsLocalization (Away 𝒜 f) _ ((toSpec 𝒜 f).base x).asIdeal.primeCompl (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) _ (mapId 𝒜 (Submonoid.powers_le.mpr x.2)).toAlgebra := by letI : Algebra (Away 𝒜 f) (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) := @@ -760,46 +756,46 @@ stalk of `Spec A⁰_ f` at `y` is isomorphic to `A⁰ₓ` where `y` is the point to `x`. -/ def specStalkEquiv (f) (x : pbo f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : - (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).1.base x) ≅ + (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).base x) ≅ CommRingCat.of (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) := letI : Algebra (Away 𝒜 f) (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) := (mapId 𝒜 (Submonoid.powers_le.mpr x.2)).toAlgebra haveI := isLocalization_atPrime 𝒜 f x f_deg hm (IsLocalization.algEquiv (R := A⁰_ f) - (M := ((toSpec 𝒜 f).1.base x).asIdeal.primeCompl) - (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).1.base x)) + (M := ((toSpec 𝒜 f).base x).asIdeal.primeCompl) + (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).base x)) (Q := AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal)).toRingEquiv.toCommRingCatIso lemma toStalk_specStalkEquiv (f) (x : pbo f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : - StructureSheaf.toStalk (A⁰_ f) ((toSpec 𝒜 f).1.base x) ≫ (specStalkEquiv 𝒜 f x f_deg hm).hom = + StructureSheaf.toStalk (A⁰_ f) ((toSpec 𝒜 f).base x) ≫ (specStalkEquiv 𝒜 f x f_deg hm).hom = (mapId _ <| Submonoid.powers_le.mpr x.2 : (A⁰_ f) →+* AtPrime 𝒜 x.1.1.toIdeal) := letI : Algebra (Away 𝒜 f) (AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal) := (mapId 𝒜 (Submonoid.powers_le.mpr x.2)).toAlgebra letI := isLocalization_atPrime 𝒜 f x f_deg hm (IsLocalization.algEquiv (R := A⁰_ f) - (M := ((toSpec 𝒜 f).1.base x).asIdeal.primeCompl) - (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).1.base x)) + (M := ((toSpec 𝒜 f).base x).asIdeal.primeCompl) + (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).base x)) (Q := AtPrime 𝒜 x.1.asHomogeneousIdeal.toIdeal)).toAlgHom.comp_algebraMap lemma stalkMap_toSpec (f) (x : pbo f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : (toSpec 𝒜 f).stalkMap x = (specStalkEquiv 𝒜 f x f_deg hm).hom ≫ (Proj.stalkIso' 𝒜 x.1).toCommRingCatIso.inv ≫ - ((Proj.toLocallyRingedSpace 𝒜).restrictStalkIso (Opens.openEmbedding _) x).inv := - IsLocalization.ringHom_ext (R := A⁰_ f) ((toSpec 𝒜 f).1.base x).asIdeal.primeCompl - (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).1.base x)) <| + ((Proj.toLocallyRingedSpace 𝒜).restrictStalkIso (Opens.isOpenEmbedding _) x).inv := + IsLocalization.ringHom_ext (R := A⁰_ f) ((toSpec 𝒜 f).base x).asIdeal.primeCompl + (S := (Spec.structureSheaf (A⁰_ f)).presheaf.stalk ((toSpec 𝒜 f).base x)) <| (toStalk_stalkMap_toSpec _ _ _).trans <| by rw [awayToΓ_ΓToStalk, ← toStalk_specStalkEquiv, Category.assoc]; rfl lemma isIso_toSpec (f) {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : IsIso (toSpec 𝒜 f) := by - haveI : IsIso (toSpec 𝒜 f).1.base := toSpec_base_isIso 𝒜 f_deg hm + haveI : IsIso (toSpec 𝒜 f).base := toSpec_base_isIso 𝒜 f_deg hm haveI (x) : IsIso ((toSpec 𝒜 f).stalkMap x) := by rw [stalkMap_toSpec 𝒜 f x f_deg hm]; infer_instance haveI : LocallyRingedSpace.IsOpenImmersion (toSpec 𝒜 f) := LocallyRingedSpace.IsOpenImmersion.of_stalk_iso (toSpec 𝒜 f) - (TopCat.homeoOfIso (asIso <| (toSpec 𝒜 f).1.base)).openEmbedding + (TopCat.homeoOfIso (asIso <| (toSpec 𝒜 f).base)).isOpenEmbedding exact LocallyRingedSpace.IsOpenImmersion.to_iso _ end ProjectiveSpectrum.Proj diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean index 747ed8efb6ca5..adedf076c90dc 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean @@ -180,9 +180,9 @@ def structurePresheafInCommRing : Presheaf CommRingCat (ProjectiveSpectrum.top map i := { toFun := (structureSheafInType 𝒜).1.map i map_zero' := rfl - map_add' := fun x y => rfl + map_add' := fun _ _ => rfl map_one' := rfl - map_mul' := fun x y => rfl } + map_mul' := fun _ _ => rfl } -- These lemmas have always been bad (#7657), but leanprover/lean4#2644 made `simp` start noticing attribute [nolint simpNF] @@ -192,7 +192,7 @@ attribute [nolint simpNF] valued structure presheaf. -/ def structurePresheafCompForget : structurePresheafInCommRing 𝒜 ⋙ forget CommRingCat ≅ (structureSheafInType 𝒜).1 := - NatIso.ofComponents (fun U => Iso.refl _) (by aesop_cat) + NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) end ProjectiveSpectrum.StructureSheaf @@ -260,22 +260,19 @@ def stalkToFiberRingHom (x : ProjectiveSpectrum.top 𝒜) : openToLocalization 𝒜 ((OpenNhds.inclusion _).obj U.unop) x U.unop.2 } } @[simp] -theorem germ_comp_stalkToFiberRingHom (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : U) : - (Proj.structureSheaf 𝒜).presheaf.germ x ≫ stalkToFiberRingHom 𝒜 x = - openToLocalization 𝒜 U x x.2 := +theorem germ_comp_stalkToFiberRingHom + (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : ProjectiveSpectrum.top 𝒜) (hx : x ∈ U) : + (Proj.structureSheaf 𝒜).presheaf.germ U x hx ≫ stalkToFiberRingHom 𝒜 x = + openToLocalization 𝒜 U x hx := Limits.colimit.ι_desc _ _ @[simp] -theorem stalkToFiberRingHom_germ' (U : Opens (ProjectiveSpectrum.top 𝒜)) +theorem stalkToFiberRingHom_germ (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : ProjectiveSpectrum.top 𝒜) (hx : x ∈ U) (s : (Proj.structureSheaf 𝒜).1.obj (op U)) : - stalkToFiberRingHom 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ ⟨x, hx⟩ s) = (s.1 ⟨x, hx⟩ : _) := - RingHom.ext_iff.1 (germ_comp_stalkToFiberRingHom 𝒜 U ⟨x, hx⟩ : _) s + stalkToFiberRingHom 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ _ x hx s) = s.1 ⟨x, hx⟩ := + RingHom.ext_iff.1 (germ_comp_stalkToFiberRingHom 𝒜 U x hx) s -@[simp] -theorem stalkToFiberRingHom_germ (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : U) - (s : (Proj.structureSheaf 𝒜).1.obj (op U)) : - stalkToFiberRingHom 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ x s) = s.1 x := - stalkToFiberRingHom_germ' 𝒜 U _ _ _ +@[deprecated (since := "2024-07-30")] alias stalkToFiberRingHom_germ' := stalkToFiberRingHom_germ theorem mem_basicOpen_den (x : ProjectiveSpectrum.top 𝒜) (f : HomogeneousLocalization.NumDenSameDeg 𝒜 x.asHomogeneousIdeal.toIdeal.primeCompl) : @@ -300,7 +297,7 @@ stalk at `x` obtained by `sectionInBasicOpen`. This is the inverse of `stalkToFi -/ def homogeneousLocalizationToStalk (x : ProjectiveSpectrum.top 𝒜) (y : at x) : (Proj.structureSheaf 𝒜).presheaf.stalk x := Quotient.liftOn' y (fun f => - (Proj.structureSheaf 𝒜).presheaf.germ ⟨x, mem_basicOpen_den _ x f⟩ (sectionInBasicOpen _ x f)) + (Proj.structureSheaf 𝒜).presheaf.germ _ x (mem_basicOpen_den _ x f) (sectionInBasicOpen _ x f)) fun f g (e : f.embedding = g.embedding) ↦ by simp only [HomogeneousLocalization.NumDenSameDeg.embedding, Localization.mk_eq_mk', IsLocalization.mk'_eq_iff_eq, @@ -325,7 +322,7 @@ lemma homogeneousLocalizationToStalk_stalkToFiberRingHom (x z) : obtain ⟨U, hxU, s, rfl⟩ := (Proj.structureSheaf 𝒜).presheaf.germ_exist x z obtain ⟨V, hxV, i, n, a, b, h, e⟩ := s.2 ⟨x, hxU⟩ simp only at e - rw [stalkToFiberRingHom_germ', homogeneousLocalizationToStalk, e ⟨x, hxV⟩, Quotient.liftOn'_mk''] + rw [stalkToFiberRingHom_germ, homogeneousLocalizationToStalk, e ⟨x, hxV⟩, Quotient.liftOn'_mk''] refine Presheaf.germ_ext _ V hxV (by exact homOfLE <| fun _ h' ↦ h ⟨_, h'⟩) i ?_ apply Subtype.ext ext ⟨t, ht⟩ @@ -337,7 +334,7 @@ lemma stalkToFiberRingHom_homogeneousLocalizationToStalk (x z) : stalkToFiberRingHom 𝒜 x (homogeneousLocalizationToStalk 𝒜 x z) = z := by obtain ⟨z, rfl⟩ := Quotient.surjective_Quotient_mk'' z rw [homogeneousLocalizationToStalk, Quotient.liftOn'_mk'', - stalkToFiberRingHom_germ', sectionInBasicOpen] + stalkToFiberRingHom_germ, sectionInBasicOpen] /-- Using `homogeneousLocalizationToStalk`, we construct a ring isomorphism between stalk at `x` and homogeneous localization at `x` for any point `x` in `Proj`. -/ @@ -349,21 +346,17 @@ def Proj.stalkIso' (x : ProjectiveSpectrum.top 𝒜) : right_inv := stalkToFiberRingHom_homogeneousLocalizationToStalk 𝒜 x @[simp] -theorem Proj.stalkIso'_germ' (U : Opens (ProjectiveSpectrum.top 𝒜)) +theorem Proj.stalkIso'_germ (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : ProjectiveSpectrum.top 𝒜) (hx : x ∈ U) (s : (Proj.structureSheaf 𝒜).1.obj (op U)) : - Proj.stalkIso' 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ ⟨x, hx⟩ s) = (s.1 ⟨x, hx⟩ : _) := - stalkToFiberRingHom_germ' 𝒜 U x hx s + Proj.stalkIso' 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ _ x hx s) = s.1 ⟨x, hx⟩ := + stalkToFiberRingHom_germ 𝒜 U x hx s -@[simp] -theorem Proj.stalkIso'_germ (U : Opens (ProjectiveSpectrum.top 𝒜)) (x : U) - (s : (Proj.structureSheaf 𝒜).1.obj (op U)) : - Proj.stalkIso' 𝒜 x ((Proj.structureSheaf 𝒜).presheaf.germ x s) = s.1 x := - stalkToFiberRingHom_germ' 𝒜 U x x.2 s +@[deprecated (since := "2024-07-30")] alias Proj.stalkIso'_germ' := Proj.stalkIso'_germ @[simp] theorem Proj.stalkIso'_symm_mk (x) (f) : - (Proj.stalkIso' 𝒜 x).symm (.mk f) = (Proj.structureSheaf 𝒜).presheaf.germ - ⟨x, mem_basicOpen_den _ x f⟩ (sectionInBasicOpen _ x f) := rfl + (Proj.stalkIso' 𝒜 x).symm (.mk f) = (Proj.structureSheaf 𝒜).presheaf.germ _ + x (mem_basicOpen_den _ x f) (sectionInBasicOpen _ x f) := rfl /-- `Proj` of a graded ring as a `LocallyRingedSpace`-/ def Proj.toLocallyRingedSpace : LocallyRingedSpace := diff --git a/Mathlib/AlgebraicGeometry/Properties.lean b/Mathlib/AlgebraicGeometry/Properties.lean index 70e632782f02a..4fb6a8f489f90 100644 --- a/Mathlib/AlgebraicGeometry/Properties.lean +++ b/Mathlib/AlgebraicGeometry/Properties.lean @@ -29,20 +29,18 @@ namespace AlgebraicGeometry variable (X : Scheme) -instance : T0Space X := by - refine T0Space.of_open_cover fun x => ?_ - obtain ⟨U, R, ⟨e⟩⟩ := X.local_affine x - let e' : U.1 ≃ₜ PrimeSpectrum R := - homeoOfIso ((LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forget _).mapIso e) - exact ⟨U.1.1, U.2, U.1.2, e'.embedding.t0Space⟩ +instance : T0Space X := + T0Space.of_open_cover fun x => ⟨_, X.affineCover.covers x, + (X.affineCover.map x).opensRange.2, IsEmbedding.t0Space (Y := PrimeSpectrum _) + (isAffineOpen_opensRange (X.affineCover.map x)).isoSpec.schemeIsoToHomeo.isEmbedding⟩ instance : QuasiSober X := by apply (config := { allowSynthFailures := true }) - quasiSober_of_open_cover (Set.range fun x => Set.range <| (X.affineCover.map x).1.base) + quasiSober_of_open_cover (Set.range fun x => Set.range <| (X.affineCover.map x).base) · rintro ⟨_, i, rfl⟩; exact (X.affineCover.IsOpen i).base_open.isOpen_range · rintro ⟨_, i, rfl⟩ - exact @OpenEmbedding.quasiSober _ _ _ _ _ (Homeomorph.ofEmbedding _ - (X.affineCover.IsOpen i).base_open.toEmbedding).symm.openEmbedding PrimeSpectrum.quasiSober + exact @IsOpenEmbedding.quasiSober _ _ _ _ _ (Homeomorph.ofIsEmbedding _ + (X.affineCover.IsOpen i).base_open.isEmbedding).symm.isOpenEmbedding PrimeSpectrum.quasiSober · rw [Set.top_eq_univ, Set.sUnion_range, Set.eq_univ_iff_forall] intro x; exact ⟨_, ⟨_, rfl⟩, X.affineCover.covers x⟩ @@ -56,9 +54,9 @@ theorem isReduced_of_isReduced_stalk [∀ x : X, _root_.IsReduced (X.presheaf.st IsReduced X := by refine ⟨fun U => ⟨fun s hs => ?_⟩⟩ apply Presheaf.section_ext X.sheaf U s 0 - intro x + intro x hx rw [RingHom.map_zero] - change X.presheaf.germ x s = 0 + change X.presheaf.germ U x hx s = 0 exact (hs.map _).eq_zero instance isReduced_stalk_of_isReduced [IsReduced X] (x : X) : @@ -66,12 +64,11 @@ instance isReduced_stalk_of_isReduced [IsReduced X] (x : X) : constructor rintro g ⟨n, e⟩ obtain ⟨U, hxU, s, rfl⟩ := X.presheaf.germ_exist x g - rw [← map_pow, ← map_zero (X.presheaf.germ ⟨x, hxU⟩)] at e + rw [← map_pow, ← map_zero (X.presheaf.germ _ x hxU)] at e obtain ⟨V, hxV, iU, iV, e'⟩ := X.presheaf.germ_eq x hxU hxU _ 0 e rw [map_pow, map_zero] at e' replace e' := (IsNilpotent.mk _ _ e').eq_zero (R := Γ(X, V)) - erw [← ConcreteCategory.congr_hom (X.presheaf.germ_res iU ⟨x, hxV⟩) s] - rw [comp_apply, e', map_zero] + rw [← X.presheaf.germ_res iU x hxV, comp_apply, e', map_zero] theorem isReduced_of_isOpenImmersion {X Y : Scheme} (f : X ⟶ Y) [H : IsOpenImmersion f] [IsReduced Y] : IsReduced X := by @@ -114,8 +111,7 @@ theorem reduce_to_affine_global (P : ∀ {X : Scheme} (_ : X.Opens), Prop) (h₁ : ∀ (X : Scheme) (U : X.Opens), (∀ x : U, ∃ (V : _) (_ : x.1 ∈ V) (_ : V ⟶ U), P V) → P U) (h₂ : ∀ (X Y) (f : X ⟶ Y) [hf : IsOpenImmersion f], - ∃ (U : Set X) (V : Set Y) (hU : U = ⊤) (hV : V = Set.range f.1.base), - P ⟨U, hU.symm ▸ isOpen_univ⟩ → P ⟨V, hV.symm ▸ hf.base_open.isOpen_range⟩) + ∃ (U : X.Opens) (V : Y.Opens), U = ⊤ ∧ V = f.opensRange ∧ (P U → P V)) (h₃ : ∀ R : CommRingCat, P (X := Spec R) ⊤) : P U := by apply h₁ intro x @@ -130,7 +126,7 @@ theorem reduce_to_affine_global (P : ∀ {X : Scheme} (_ : X.Opens), Prop) theorem reduce_to_affine_nbhd (P : ∀ (X : Scheme) (_ : X), Prop) (h₁ : ∀ R x, P (Spec R) x) - (h₂ : ∀ {X Y} (f : X ⟶ Y) [IsOpenImmersion f] (x : X), P X x → P Y (f.1.base x)) : + (h₂ : ∀ {X Y} (f : X ⟶ Y) [IsOpenImmersion f] (x : X), P X x → P Y (f.base x)) : ∀ (X : Scheme) (x : X), P X x := by intro X x obtain ⟨y, e⟩ := X.affineCover.covers x @@ -141,28 +137,26 @@ theorem reduce_to_affine_nbhd (P : ∀ (X : Scheme) (_ : X), Prop) theorem eq_zero_of_basicOpen_eq_bot {X : Scheme} [hX : IsReduced X] {U : X.Opens} (s : Γ(X, U)) (hs : X.basicOpen s = ⊥) : s = 0 := by apply TopCat.Presheaf.section_ext X.sheaf U - intro x + intro x hx rw [RingHom.map_zero] + show X.presheaf.germ U x hx s = 0 induction U using reduce_to_affine_global generalizing hX with - | h₁ X U hx => - obtain ⟨V, hx, i, H⟩ := hx x + | h₁ X U H => + obtain ⟨V, hx, i, H⟩ := H ⟨x, hx⟩ specialize H (X.presheaf.map i.op s) - erw [Scheme.basicOpen_res] at H - rw [hs] at H - specialize H (inf_bot_eq _) ⟨x, hx⟩ - erw [TopCat.Presheaf.germ_res_apply] at H + rw [Scheme.basicOpen_res, hs] at H + specialize H (inf_bot_eq _) x hx + rw [TopCat.Presheaf.germ_res_apply] at H exact H | h₂ X Y f => - have e : f.val.base ⁻¹' Set.range ↑f.val.base = Set.univ := by - rw [← Set.image_univ, Set.preimage_image_eq _ ‹IsOpenImmersion f›.base_open.inj] - refine ⟨_, _, e, rfl, ?_⟩ - rintro H hX s hs ⟨_, x, rfl⟩ + refine ⟨f ⁻¹ᵁ f.opensRange, f.opensRange, by ext1; simp, rfl, ?_⟩ + rintro H hX s hs _ ⟨x, rfl⟩ haveI := isReduced_of_isOpenImmersion f - specialize H (f.app _ s) _ ⟨x, by rw [Opens.mem_mk, e]; trivial⟩ + specialize H (f.app _ s) _ x ⟨x, rfl⟩ · rw [← Scheme.preimage_basicOpen, hs]; ext1; simp [Opens.map] - · erw [← PresheafedSpace.stalkMap_germ_apply f.1 ⟨_, _⟩ ⟨x, _⟩] at H + · rw [← Scheme.stalkMap_germ_apply f ⟨_, _⟩ x] at H apply_fun inv <| f.stalkMap x at H - erw [CategoryTheory.IsIso.hom_inv_id_apply, map_zero] at H + rw [CategoryTheory.IsIso.hom_inv_id_apply, map_zero] at H exact H | h₃ R => rw [basicOpen_eq_of_affine', PrimeSpectrum.basicOpen_eq_bot_iff] at hs @@ -239,13 +233,11 @@ theorem isIntegral_of_irreducibleSpace_of_isReduced [IsReduced X] [H : Irreducib refine ⟨fun {a b} e => ?_⟩ simp_rw [← basicOpen_eq_bot_iff, ← Opens.not_nonempty_iff_eq_bot] by_contra! h - obtain ⟨_, ⟨x, hx₁, rfl⟩, ⟨x, hx₂, e'⟩⟩ := + obtain ⟨x, ⟨hxU, hx₁⟩, _, hx₂⟩ := nonempty_preirreducible_inter (X.basicOpen a).2 (X.basicOpen b).2 h.1 h.2 - replace e' := Subtype.eq e' - subst e' - replace e := congr_arg (X.presheaf.germ x) e + replace e := congr_arg (X.presheaf.germ U x hxU) e rw [RingHom.map_mul, RingHom.map_zero] at e - refine zero_ne_one' (X.presheaf.stalk x.1) (isUnit_zero_iff.1 ?_) + refine zero_ne_one' (X.presheaf.stalk x) (isUnit_zero_iff.1 ?_) convert hx₁.mul hx₂ exact e.symm exact NoZeroDivisors.to_isDomain _ diff --git a/Mathlib/AlgebraicGeometry/Pullbacks.lean b/Mathlib/AlgebraicGeometry/Pullbacks.lean index 1b43cf9c18bfd..712933f44210e 100644 --- a/Mathlib/AlgebraicGeometry/Pullbacks.lean +++ b/Mathlib/AlgebraicGeometry/Pullbacks.lean @@ -197,8 +197,8 @@ def gluing : Scheme.GlueData.{u} where U i := pullback (𝒰.map i ≫ f) g V := fun ⟨i, j⟩ => v 𝒰 f g i j -- `p⁻¹(Uᵢ ∩ Uⱼ)` where `p : Uᵢ ×[Z] Y ⟶ Uᵢ ⟶ X`. - f i j := pullback.fst _ _ - f_id i := inferInstance + f _ _ := pullback.fst _ _ + f_id _ := inferInstance f_open := inferInstance t i j := t 𝒰 f g i j t_id i := t_id 𝒰 f g i @@ -503,12 +503,12 @@ def openCoverOfLeftRight (𝒰X : X.OpenCover) (𝒰Y : Y.OpenCover) (f : X ⟶ def openCoverOfBase' (𝒰 : OpenCover Z) (f : X ⟶ Z) (g : Y ⟶ Z) : OpenCover (pullback f g) := by apply (openCoverOfLeft (𝒰.pullbackCover f) f g).bind intro i - have := PullbackCone.flipIsLimit <| - pasteVertIsPullback rfl (pullbackIsPullback g (𝒰.map i)) - (pullbackIsPullback (pullback.snd g (𝒰.map i)) (pullback.snd f (𝒰.map i))) + haveI := ((IsPullback.of_hasPullback (pullback.snd g (𝒰.map i)) + (pullback.snd f (𝒰.map i))).paste_horiz (IsPullback.of_hasPullback _ _)).flip refine @openCoverOfIsIso _ _ - (f := (pullbackSymmetry _ _).hom ≫ (limit.isoLimitCone ⟨_, this⟩).inv ≫ + (f := (pullbackSymmetry (pullback.snd f (𝒰.map i)) (pullback.snd g (𝒰.map i))).hom ≫ + (limit.isoLimitCone ⟨_, this.isLimit⟩).inv ≫ pullback.map _ _ _ _ (𝟙 _) (𝟙 _) (𝟙 _) ?_ ?_) inferInstance · simp [← pullback.condition] · simp only [Category.comp_id, Category.id_comp] @@ -528,12 +528,12 @@ def openCoverOfBase (𝒰 : OpenCover Z) (f : X ⟶ Z) (g : Y ⟶ Z) : OpenCover ((Equiv.prodPUnit 𝒰.J).symm.trans (Equiv.sigmaEquivProd 𝒰.J PUnit).symm) fun _ => Iso.refl _ intro i rw [Iso.refl_hom, Category.id_comp, openCoverOfBase'_map] - apply pullback.hom_ext <;> dsimp <;> - · simp only [limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, Category.assoc, - limit.lift_π_assoc, cospan_left, Category.comp_id, limit.isoLimitCone_inv_π, - limit.isoLimitCone_inv_π_assoc, PullbackCone.flip_pt, PullbackCone.π_app_left, - PullbackCone.π_app_right, PullbackCone.flip_fst, PullbackCone.flip_snd, - pullbackSymmetry_hom_comp_snd_assoc, pullbackSymmetry_hom_comp_fst_assoc] + ext : 1 <;> + · simp only [limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, Equiv.trans_apply, + Equiv.prodPUnit_symm_apply, Category.assoc, limit.lift_π_assoc, cospan_left, Category.comp_id, + limit.isoLimitCone_inv_π_assoc, PullbackCone.π_app_left, IsPullback.cone_fst, + pullbackSymmetry_hom_comp_snd_assoc, limit.isoLimitCone_inv_π, + PullbackCone.π_app_right, IsPullback.cone_snd, pullbackSymmetry_hom_comp_fst_assoc] rfl end Pullback @@ -565,6 +565,7 @@ def pullbackSpecIso : letI H := IsLimit.equivIsoLimit (PullbackCone.eta _) (PushoutCocone.isColimitEquivIsLimitOp _ (CommRingCat.pushoutCoconeIsColimit R S T)) limit.isoLimitCone ⟨_, isLimitPullbackConeMapOfIsLimit Scheme.Spec _ H⟩ + /-- The composition of the inverse of the isomorphism `pullbackSepcIso R S T` (from the pullback of `Spec S ⟶ Spec R` and `Spec T ⟶ Spec R` to `Spec (S ⊗[R] T)`) with the first projection is @@ -575,6 +576,7 @@ the morphism `Spec (S ⊗[R] T) ⟶ Spec S` obtained by applying `Spec.map` to t lemma pullbackSpecIso_inv_fst : (pullbackSpecIso R S T).inv ≫ pullback.fst _ _ = Spec.map (ofHom includeLeftRingHom) := limit.isoLimitCone_inv_π _ _ + /-- The composition of the inverse of the isomorphism `pullbackSepcIso R S T` (from the pullback of `Spec S ⟶ Spec R` and `Spec T ⟶ Spec R` to `Spec (S ⊗[R] T)`) with the second projection is @@ -586,6 +588,7 @@ lemma pullbackSpecIso_inv_snd : (pullbackSpecIso R S T).inv ≫ pullback.snd _ _ = Spec.map (ofHom (R := T) (S := S ⊗[R] T) (toRingHom includeRight)) := limit.isoLimitCone_inv_π _ _ + /-- The composition of the isomorphism `pullbackSepcIso R S T` (from the pullback of `Spec S ⟶ Spec R` and `Spec T ⟶ Spec R` to `Spec (S ⊗[R] T)`) with the morphism @@ -596,6 +599,7 @@ is the first projection. lemma pullbackSpecIso_hom_fst : (pullbackSpecIso R S T).hom ≫ Spec.map (ofHom includeLeftRingHom) = pullback.fst _ _ := by rw [← pullbackSpecIso_inv_fst, Iso.hom_inv_id_assoc] + /-- The composition of the isomorphism `pullbackSepcIso R S T` (from the pullback of `Spec S ⟶ Spec R` and `Spec T ⟶ Spec R` to `Spec (S ⊗[R] T)`) with the morphism @@ -607,6 +611,15 @@ lemma pullbackSpecIso_hom_snd : (pullbackSpecIso R S T).hom ≫ Spec.map (ofHom (toRingHom includeRight)) = pullback.snd _ _ := by rw [← pullbackSpecIso_inv_snd, Iso.hom_inv_id_assoc] +lemma diagonal_Spec_map : + pullback.diagonal (Spec.map (CommRingCat.ofHom (algebraMap R S))) = + Spec.map (CommRingCat.ofHom (Algebra.TensorProduct.lmul' R : S ⊗[R] S →ₐ[R] S).toRingHom) ≫ + (pullbackSpecIso R S S).inv := by + ext1 <;> simp only [pullback.diagonal_fst, pullback.diagonal_snd, ← Spec.map_comp, ← Spec.map_id, + AlgHom.toRingHom_eq_coe, Category.assoc, pullbackSpecIso_inv_fst, pullbackSpecIso_inv_snd] + · congr 1; ext x; show x = Algebra.TensorProduct.lmul' R (S := S) (x ⊗ₜ[R] 1); simp + · congr 1; ext x; show x = Algebra.TensorProduct.lmul' R (S := S) (1 ⊗ₜ[R] x); simp + end Spec diff --git a/Mathlib/AlgebraicGeometry/RationalMap.lean b/Mathlib/AlgebraicGeometry/RationalMap.lean new file mode 100644 index 0000000000000..aca42607f4a77 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/RationalMap.lean @@ -0,0 +1,333 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.SpreadingOut +import Mathlib.AlgebraicGeometry.FunctionField +/-! + +# Rational maps between schemes + +## Main definitions + +* `AlgebraicGeometry.Scheme.PartialMap`: A partial map from `X` to `Y` (`X.PartialMap Y`) is + a morphism into `Y` defined on a dense open subscheme of `X`. +* `AlgebraicGeometry.Scheme.PartialMap.equiv`: + Two partial maps are equivalent if they are equal on a dense open subscheme. +* `AlgebraicGeometry.Scheme.RationalMap`: + A rational map from `X` to `Y` (`X ⤏ Y`) is an equivalence class of partial maps. +* `AlgebraicGeometry.Scheme.RationalMap.equivFunctionField`: + Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and `X` is integral, + `S`-morphisms `Spec K(X) ⟶ Y` correspond bijectively to `S`-rational maps from `X` to `Y`. + +-/ + +universe u + +open CategoryTheory hiding Quotient + +namespace AlgebraicGeometry + +variable {X Y Z S : Scheme.{u}} (sX : X ⟶ S) (sY : Y ⟶ S) + +namespace Scheme + +/-- +A partial map from `X` to `Y` (`X.PartialMap Y`) is a morphism into `Y` +defined on a dense open subscheme of `X`. +-/ +structure PartialMap (X Y : Scheme.{u}) where + /-- The domain of definition of a partial map. -/ + domain : X.Opens + dense_domain : Dense (domain : Set X) + /-- The underlying morphism of a partial map. -/ + hom : ↑domain ⟶ Y + +namespace PartialMap + +lemma ext_iff (f g : X.PartialMap Y) : + f = g ↔ ∃ e : f.domain = g.domain, f.hom = (X.isoOfEq e).hom ≫ g.hom := by + constructor + · rintro rfl + simp only [exists_true_left, Scheme.isoOfEq_rfl, Iso.refl_hom, Category.id_comp] + · obtain ⟨U, hU, f⟩ := f + obtain ⟨V, hV, g⟩ := g + rintro ⟨rfl : U = V, e⟩ + congr 1 + simpa using e + +@[ext] +lemma ext (f g : X.PartialMap Y) (e : f.domain = g.domain) + (H : f.hom = (X.isoOfEq e).hom ≫ g.hom) : f = g := by + rw [ext_iff] + exact ⟨e, H⟩ + +/-- The restriction of a partial map to a smaller domain. -/ +@[simps hom, simps (config := .lemmasOnly) domain] +noncomputable +def restrict (f : X.PartialMap Y) (U : X.Opens) + (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : X.PartialMap Y where + domain := U + dense_domain := hU + hom := X.homOfLE hU' ≫ f.hom + +@[simp] +lemma restrict_id (f : X.PartialMap Y) : f.restrict f.domain f.dense_domain le_rfl = f := by + ext1 <;> simp [restrict_domain] + +lemma restrict_id_hom (f : X.PartialMap Y) : + (f.restrict f.domain f.dense_domain le_rfl).hom = f.hom := by + simp + +@[simp] +lemma restrict_restrict (f : X.PartialMap Y) + (U : X.Opens) (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) + (V : X.Opens) (hV : Dense (V : Set X)) (hV' : V ≤ U) : + (f.restrict U hU hU').restrict V hV hV' = f.restrict V hV (hV'.trans hU') := by + ext1 <;> simp [restrict_domain] + +lemma restrict_restrict_hom (f : X.PartialMap Y) + (U : X.Opens) (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) + (V : X.Opens) (hV : Dense (V : Set X)) (hV' : V ≤ U) : + ((f.restrict U hU hU').restrict V hV hV').hom = (f.restrict V hV (hV'.trans hU')).hom := by + simp + +/-- The composition of a partial map and a morphism on the right. -/ +@[simps] +def compHom (f : X.PartialMap Y) (g : Y ⟶ Z) : X.PartialMap Z where + domain := f.domain + dense_domain := f.dense_domain + hom := f.hom ≫ g + +/-- A scheme morphism as a partial map. -/ +@[simps] +def _root_.AlgebraicGeometry.Scheme.Hom.toPartialMap (f : X.Hom Y) : + X.PartialMap Y := ⟨⊤, dense_univ, X.topIso.hom ≫ f⟩ + +/-- If `x` is in the domain of a partial map `f`, then `f` restricts to a map from `Spec 𝒪_x`. -/ +noncomputable +def fromSpecStalkOfMem (f : X.PartialMap Y) {x} (hx : x ∈ f.domain) : + Spec (X.presheaf.stalk x) ⟶ Y := + f.domain.fromSpecStalkOfMem x hx ≫ f.hom + +/-- A partial map restricts to a map from `Spec K(X)`. -/ +noncomputable +abbrev fromFunctionField [IrreducibleSpace X] (f : X.PartialMap Y) : + Spec X.functionField ⟶ Y := + f.fromSpecStalkOfMem + ((genericPoint_specializes _).mem_open f.domain.2 f.dense_domain.nonempty.choose_spec) + +lemma fromSpecStalkOfMem_restrict (f : X.PartialMap Y) + {U : X.Opens} (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) {x} (hx : x ∈ U) : + (f.restrict U hU hU').fromSpecStalkOfMem hx = f.fromSpecStalkOfMem (hU' hx) := by + dsimp only [fromSpecStalkOfMem, restrict, Scheme.Opens.fromSpecStalkOfMem] + have e : ⟨x, hU' hx⟩ = (X.homOfLE hU').base ⟨x, hx⟩ := by + rw [Scheme.homOfLE_base] + rfl + rw [Category.assoc, ← Spec_map_stalkMap_fromSpecStalk_assoc, + ← Spec_map_stalkSpecializes_fromSpecStalk (Inseparable.of_eq e).specializes, + ← TopCat.Presheaf.stalkCongr_inv _ (Inseparable.of_eq e)] + simp only [← Category.assoc, ← Spec.map_comp] + congr 3 + rw [Iso.eq_inv_comp, ← Category.assoc, IsIso.comp_inv_eq, IsIso.eq_inv_comp, + stalkMap_congr_hom _ _ (X.homOfLE_ι hU').symm] + simp only [restrictFunctor_obj_left, homOfLE_leOfHom, TopCat.Presheaf.stalkCongr_hom] + rw [← stalkSpecializes_stalkMap_assoc, stalkMap_comp] + +lemma fromFunctionField_restrict (f : X.PartialMap Y) [IrreducibleSpace X] + {U : X.Opens} (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : + (f.restrict U hU hU').fromFunctionField = f.fromFunctionField := + fromSpecStalkOfMem_restrict f _ _ _ + +/-- +Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and +`X` is irreducible germ-injective at `x` (e.g. when `X` is integral), +any `S`-morphism `Spec 𝒪ₓ ⟶ Y` spreads out to a partial map from `X` to `Y`. +-/ +noncomputable +def ofFromSpecStalk [IrreducibleSpace X] [LocallyOfFiniteType sY] {x : X} [X.IsGermInjectiveAt x] + (φ : Spec (X.presheaf.stalk x) ⟶ Y) (h : φ ≫ sY = X.fromSpecStalk x ≫ sX) : X.PartialMap Y where + hom := (spread_out_of_isGermInjective' sX sY φ h).choose_spec.choose_spec.choose + dense_domain := (spread_out_of_isGermInjective' sX sY φ h).choose.2.dense + ⟨_, (spread_out_of_isGermInjective' sX sY φ h).choose_spec.choose⟩ + +lemma ofFromSpecStalk_comp [IrreducibleSpace X] [LocallyOfFiniteType sY] + {x : X} [X.IsGermInjectiveAt x] (φ : Spec (X.presheaf.stalk x) ⟶ Y) + (h : φ ≫ sY = X.fromSpecStalk x ≫ sX) : + (ofFromSpecStalk sX sY φ h).hom ≫ sY = (ofFromSpecStalk sX sY φ h).domain.ι ≫ sX := + (spread_out_of_isGermInjective' sX sY φ h).choose_spec.choose_spec.choose_spec.2 + +lemma mem_domain_ofFromSpecStalk [IrreducibleSpace X] [LocallyOfFiniteType sY] + {x : X} [X.IsGermInjectiveAt x] (φ : Spec (X.presheaf.stalk x) ⟶ Y) + (h : φ ≫ sY = X.fromSpecStalk x ≫ sX) : x ∈ (ofFromSpecStalk sX sY φ h).domain := + (spread_out_of_isGermInjective' sX sY φ h).choose_spec.choose + +lemma fromSpecStalkOfMem_ofFromSpecStalk [IrreducibleSpace X] [LocallyOfFiniteType sY] + {x : X} [X.IsGermInjectiveAt x] (φ : Spec (X.presheaf.stalk x) ⟶ Y) + (h : φ ≫ sY = X.fromSpecStalk x ≫ sX) : + (ofFromSpecStalk sX sY φ h).fromSpecStalkOfMem (mem_domain_ofFromSpecStalk sX sY φ h) = φ := + (spread_out_of_isGermInjective' sX sY φ h).choose_spec.choose_spec.choose_spec.1.symm + +@[simp] +lemma fromSpecStalkOfMem_compHom (f : X.PartialMap Y) (g : Y ⟶ Z) (x) (hx) : + (f.compHom g).fromSpecStalkOfMem (x := x) hx = f.fromSpecStalkOfMem hx ≫ g := by + simp [fromSpecStalkOfMem] + +@[simp] +lemma fromSpecStalkOfMem_toPartialMap (f : X ⟶ Y) (x) : + f.toPartialMap.fromSpecStalkOfMem (x := x) trivial = X.fromSpecStalk x ≫ f := by + simp [fromSpecStalkOfMem] + +/-- Two partial maps are equivalent if they are equal on a dense open subscheme. -/ +protected noncomputable +def equiv (f g : X.PartialMap Y) : Prop := + ∃ (W : X.Opens) (hW : Dense (W : Set X)) (hWl : W ≤ f.domain) (hWr : W ≤ g.domain), + (f.restrict W hW hWl).hom = (g.restrict W hW hWr).hom + +lemma equivalence_rel : Equivalence (@Scheme.PartialMap.equiv X Y) where + refl f := ⟨f.domain, f.dense_domain, by simp⟩ + symm {f g} := by + intro ⟨W, hW, hWl, hWr, e⟩ + exact ⟨W, hW, hWr, hWl, e.symm⟩ + trans {f g h} := by + intro ⟨W₁, hW₁, hW₁l, hW₁r, e₁⟩ ⟨W₂, hW₂, hW₂l, hW₂r, e₂⟩ + refine ⟨W₁ ⊓ W₂, hW₁.inter_of_isOpen_left hW₂ W₁.2, inf_le_left.trans hW₁l, + inf_le_right.trans hW₂r, ?_⟩ + dsimp at e₁ e₂ + simp only [restrict_domain, restrict_hom, restrictFunctor_obj_left, homOfLE_leOfHom, + ← X.homOfLE_homOfLE (U := W₁ ⊓ W₂) inf_le_left hW₁l, Functor.map_comp, Over.comp_left, + Category.assoc, e₁, ← X.homOfLE_homOfLE (U := W₁ ⊓ W₂) inf_le_right hW₂r, ← e₂] + simp only [homOfLE_homOfLE_assoc] + +instance : Setoid (X.PartialMap Y) := ⟨@PartialMap.equiv X Y, equivalence_rel⟩ + +lemma restrict_equiv (f : X.PartialMap Y) (U : X.Opens) + (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : (f.restrict U hU hU').equiv f := + ⟨U, hU, le_rfl, hU', by simp⟩ + +lemma equiv_of_fromSpecStalkOfMem_eq [IrreducibleSpace X] + {x : X} [X.IsGermInjectiveAt x] (f g : X.PartialMap Y) + (hxf : x ∈ f.domain) (hxg : x ∈ g.domain) + (H : f.fromSpecStalkOfMem hxf = g.fromSpecStalkOfMem hxg) : f.equiv g := by + have hdense : Dense ((f.domain ⊓ g.domain) : Set X) := + f.dense_domain.inter_of_isOpen_left g.dense_domain f.domain.2 + have := (isGermInjectiveAt_iff_of_isOpenImmersion (f := (f.domain ⊓ g.domain).ι) + (x := ⟨x, hxf, hxg⟩)).mp ‹_› + have := spread_out_unique_of_isGermInjective' (X := (f.domain ⊓ g.domain).toScheme) + (X.homOfLE inf_le_left ≫ f.hom) (X.homOfLE inf_le_right ≫ g.hom) (x := ⟨x, hxf, hxg⟩) ?_ + · obtain ⟨U, hxU, e⟩ := this + refine ⟨(f.domain ⊓ g.domain).ι ''ᵁ U, ((f.domain ⊓ g.domain).ι ''ᵁ U).2.dense + ⟨_, ⟨_, hxU, rfl⟩⟩, + ((Set.image_subset_range _ _).trans_eq (Subtype.range_val)).trans inf_le_left, + ((Set.image_subset_range _ _).trans_eq (Subtype.range_val)).trans inf_le_right, ?_⟩ + rw [← cancel_epi (Scheme.Hom.isoImage _ _).hom] + simp only [TopologicalSpace.Opens.carrier_eq_coe, IsOpenMap.functor_obj_coe, + TopologicalSpace.Opens.coe_inf, restrict_hom, ← Category.assoc] at e ⊢ + convert e using 2 <;> rw [← cancel_mono (Scheme.Opens.ι _)] <;> simp + · rw [← f.fromSpecStalkOfMem_restrict hdense inf_le_left ⟨hxf, hxg⟩, + ← g.fromSpecStalkOfMem_restrict hdense inf_le_right ⟨hxf, hxg⟩] at H + simpa only [fromSpecStalkOfMem, restrict_domain, Opens.fromSpecStalkOfMem, Spec.map_inv, + restrict_hom, Category.assoc, IsIso.eq_inv_comp, IsIso.hom_inv_id_assoc] using H + +end PartialMap + +/-- A rational map from `X` to `Y` (`X ⤏ Y`) is an equivalence class of partial maps, +where two partial maps are equivalent if they are equal on a dense open subscheme. -/ +def RationalMap (X Y : Scheme.{u}) : Type u := + @Quotient (X.PartialMap Y) inferInstance + +/-- The notation for rational maps. -/ +scoped[AlgebraicGeometry] infix:10 " ⤏ " => Scheme.RationalMap + +/-- A partial map as a rational map. -/ +def PartialMap.toRationalMap (f : X.PartialMap Y) : X ⤏ Y := Quotient.mk _ f + +/-- A scheme morphism as a rational map. -/ +abbrev Hom.toRationalMap (f : X.Hom Y) : X ⤏ Y := f.toPartialMap.toRationalMap + +lemma PartialMap.toRationalMap_surjective : Function.Surjective (@toRationalMap X Y) := + Quotient.exists_rep + +lemma RationalMap.exists_rep (f : X ⤏ Y) : ∃ g : X.PartialMap Y, g.toRationalMap = f := + Quotient.exists_rep f + +lemma PartialMap.toRationalMap_eq_iff {f g : X.PartialMap Y} : + f.toRationalMap = g.toRationalMap ↔ f.equiv g := + Quotient.eq + +@[simp] +lemma PartialMap.restrict_toRationalMap (f : X.PartialMap Y) (U : X.Opens) + (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : + (f.restrict U hU hU').toRationalMap = f.toRationalMap := + toRationalMap_eq_iff.mpr (f.restrict_equiv U hU hU') + +/-- The composition of a rational map and a morphism on the right. -/ +def RationalMap.compHom (f : X ⤏ Y) (g : Y ⟶ Z) : X ⤏ Z := by + refine Quotient.map (PartialMap.compHom · g) ?_ f + intro f₁ f₂ ⟨W, hW, hWl, hWr, e⟩ + refine ⟨W, hW, hWl, hWr, ?_⟩ + simp only [PartialMap.restrict_domain, PartialMap.restrict_hom, PartialMap.compHom_domain, + PartialMap.compHom_hom] at e ⊢ + rw [reassoc_of% e] + +@[simp] +lemma RationalMap.compHom_toRationalMap (f : X.PartialMap Y) (g : Y ⟶ Z) : + (f.compHom g).toRationalMap = f.toRationalMap.compHom g := rfl + +/-- A rational map restricts to a map from `Spec K(X)`. -/ +noncomputable +def RationalMap.fromFunctionField [IrreducibleSpace X] (f : X ⤏ Y) : + Spec X.functionField ⟶ Y := by + refine Quotient.lift PartialMap.fromFunctionField ?_ f + intro f g ⟨W, hW, hWl, hWr, e⟩ + have : f.restrict W hW hWl = g.restrict W hW hWr := by ext1; rfl; rw [e]; simp + rw [← f.fromFunctionField_restrict hW hWl, this, g.fromFunctionField_restrict] + +@[simp] +lemma RationalMap.fromFunctionField_toRationalMap [IrreducibleSpace X] (f : X.PartialMap Y) : + f.toRationalMap.fromFunctionField = f.fromFunctionField := rfl + +/-- +Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and `X` is integral, +any `S`-morphism `Spec K(X) ⟶ Y` spreads out to a rational map from `X` to `Y`. +-/ +noncomputable +def RationalMap.ofFunctionField [IsIntegral X] [LocallyOfFiniteType sY] + (f : Spec X.functionField ⟶ Y) (h : f ≫ sY = X.fromSpecStalk _ ≫ sX) : X ⤏ Y := + (PartialMap.ofFromSpecStalk sX sY f h).toRationalMap + +lemma RationalMap.fromFunctionField_ofFunctionField [IsIntegral X] [LocallyOfFiniteType sY] + (f : Spec X.functionField ⟶ Y) (h : f ≫ sY = X.fromSpecStalk _ ≫ sX) : + (ofFunctionField sX sY f h).fromFunctionField = f := + PartialMap.fromSpecStalkOfMem_ofFromSpecStalk sX sY _ _ + +lemma RationalMap.eq_of_fromFunctionField_eq [IsIntegral X] (f g : X.RationalMap Y) + (H : f.fromFunctionField = g.fromFunctionField) : f = g := by + obtain ⟨f, rfl⟩ := f.exists_rep + obtain ⟨g, rfl⟩ := g.exists_rep + refine PartialMap.toRationalMap_eq_iff.mpr ?_ + exact PartialMap.equiv_of_fromSpecStalkOfMem_eq _ _ _ _ H + +/-- +Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and `X` is integral, +`S`-morphisms `Spec K(X) ⟶ Y` correspond bijectively to `S`-rational maps from `X` to `Y`. +-/ +noncomputable +def RationalMap.equivFunctionField [IsIntegral X] [LocallyOfFiniteType sY] : + { f : Spec X.functionField ⟶ Y // f ≫ sY = X.fromSpecStalk _ ≫ sX } ≃ + { f : X ⤏ Y // f.compHom sY = sX.toRationalMap } where + toFun f := ⟨.ofFunctionField sX sY f f.2, PartialMap.toRationalMap_eq_iff.mpr + ⟨_, PartialMap.dense_domain _, le_rfl, le_top, by simp [PartialMap.ofFromSpecStalk_comp]⟩⟩ + invFun f := ⟨f.1.fromFunctionField, by + obtain ⟨f, hf⟩ := f + obtain ⟨f, rfl⟩ := f.exists_rep + simpa [fromFunctionField_toRationalMap] using congr(RationalMap.fromFunctionField $hf)⟩ + left_inv f := Subtype.ext (RationalMap.fromFunctionField_ofFunctionField _ _ _ _) + right_inv f := Subtype.ext (RationalMap.eq_of_fromFunctionField_eq + (ofFunctionField sX sY f.1.fromFunctionField _) f + (RationalMap.fromFunctionField_ofFunctionField _ _ _ _)) + +end Scheme + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/ResidueField.lean b/Mathlib/AlgebraicGeometry/ResidueField.lean index f192506ed485b..4b64608218fcd 100644 --- a/Mathlib/AlgebraicGeometry/ResidueField.lean +++ b/Mathlib/AlgebraicGeometry/ResidueField.lean @@ -3,8 +3,8 @@ Copyright (c) 2024 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.Geometry.RingedSpace.LocallyRingedSpace.ResidueField import Mathlib.AlgebraicGeometry.Stalk +import Mathlib.Geometry.RingedSpace.LocallyRingedSpace.ResidueField /-! @@ -20,12 +20,15 @@ The following are in the `AlgebraicGeometry.Scheme` namespace: - `AlgebraicGeometry.Scheme.Hom.residueFieldMap`: A morphism of schemes induce a homomorphism of residue fields. - `AlgebraicGeometry.Scheme.fromSpecResidueField`: The canonical map `Spec κ(x) ⟶ X`. +- `AlgebraicGeometry.Scheme.SpecToEquivOfField`: morphisms `Spec K ⟶ X` for a field `K` correspond + to pairs of `x : X` with embedding `κ(x) ⟶ K`. + -/ universe u -open CategoryTheory TopologicalSpace Opposite +open CategoryTheory TopologicalSpace Opposite LocalRing noncomputable section @@ -45,12 +48,38 @@ instance (x : X) : Field (X.residueField x) := def residue (X : Scheme.{u}) (x) : X.presheaf.stalk x ⟶ X.residueField x := LocalRing.residue _ +/-- See `AlgebraicGeometry.IsClosedImmersion.Spec_map_residue` for the stronger result that +`Spec.map (X.residue x)` is a closed immersion. -/ +instance {X : Scheme.{u}} (x) : IsPreimmersion (Spec.map (X.residue x)) := + IsPreimmersion.mk_Spec_map + (PrimeSpectrum.isClosedEmbedding_comap_of_surjective _ _ + Ideal.Quotient.mk_surjective).isEmbedding + (RingHom.surjectiveOnStalks_of_surjective (Ideal.Quotient.mk_surjective)) + +@[simp] +lemma Spec_map_residue_apply {X : Scheme.{u}} (x : X) (s : Spec (X.residueField x)) : + (Spec.map (X.residue x)).base s = closedPoint (X.presheaf.stalk x) := + LocalRing.PrimeSpectrum.comap_residue _ s + lemma residue_surjective (X : Scheme.{u}) (x) : Function.Surjective (X.residue x) := Ideal.Quotient.mk_surjective instance (X : Scheme.{u}) (x) : Epi (X.residue x) := ConcreteCategory.epi_of_surjective _ (X.residue_surjective x) +/-- If `K` is a field and `f : 𝒪_{X, x} ⟶ K` is a ring map, then this is the induced +map `κ(x) ⟶ K`. -/ +def descResidueField {K : Type u} [Field K] {X : Scheme.{u}} {x : X} + (f : X.presheaf.stalk x ⟶ .of K) [IsLocalHom f] : + X.residueField x ⟶ .of K := + LocalRing.ResidueField.lift (S := K) f + +@[reassoc (attr := simp)] +lemma residue_descResidueField {K : Type u} [Field K] {X : Scheme.{u}} {x} + (f : X.presheaf.stalk x ⟶ .of K) [IsLocalHom f] : + X.residue x ≫ X.descResidueField f = f := + RingHom.ext fun _ ↦ rfl + /-- If `U` is an open of `X` containing `x`, we have a canonical ring map from the sections over `U` to the residue field of `x`. @@ -59,10 +88,10 @@ If we interpret sections over `U` as functions of `X` defined on `U`, then this corresponds to evaluation at `x`. -/ def evaluation (U : X.Opens) (x : X) (hx : x ∈ U) : Γ(X, U) ⟶ X.residueField x := - X.presheaf.germ ⟨x, hx⟩ ≫ X.residue _ + X.presheaf.germ U x hx ≫ X.residue _ @[reassoc] -lemma germ_residue (x : U) : X.presheaf.germ x ≫ X.residue x.1 = X.evaluation U x x.2 := rfl +lemma germ_residue (x hx) : X.presheaf.germ U x hx ≫ X.residue x = X.evaluation U x hx := rfl /-- The global evaluation map from `Γ(X, ⊤)` to the residue field at `x`. -/ abbrev Γevaluation (x : X) : Γ(X, ⊤) ⟶ X.residueField x := @@ -77,19 +106,21 @@ lemma evaluation_ne_zero_iff_mem_basicOpen (x : X) (hx : x ∈ U) (f : Γ(X, U)) X.evaluation U x hx f ≠ 0 ↔ x ∈ X.basicOpen f := by simp -variable {X Y : Scheme.{u}} (f : X ⟶ Y) +lemma basicOpen_eq_bot_iff_forall_evaluation_eq_zero (f : X.presheaf.obj (op U)) : + X.basicOpen f = ⊥ ↔ ∀ (x : U), X.evaluation U x x.property f = 0 := + X.toLocallyRingedSpace.basicOpen_eq_bot_iff_forall_evaluation_eq_zero f -instance (x) : IsLocalRingHom (f.stalkMap x) := inferInstanceAs (IsLocalRingHom (f.val.stalkMap x)) +variable {X Y : Scheme.{u}} (f : X ⟶ Y) /-- If `X ⟶ Y` is a morphism of locally ringed spaces and `x` a point of `X`, we obtain a morphism of residue fields in the other direction. -/ def Hom.residueFieldMap (f : X.Hom Y) (x : X) : - Y.residueField (f.val.base x) ⟶ X.residueField x := + Y.residueField (f.base x) ⟶ X.residueField x := LocalRing.ResidueField.map (f.stalkMap x) @[reassoc] lemma residue_residueFieldMap (x : X) : - Y.residue (f.val.base x) ≫ f.residueFieldMap x = f.stalkMap x ≫ X.residue x := by + Y.residue (f.base x) ≫ f.residueFieldMap x = f.stalkMap x ≫ X.residue x := by simp [Hom.residueFieldMap] rfl @@ -100,19 +131,30 @@ lemma residueFieldMap_id (x : X) : @[simp] lemma residueFieldMap_comp {Z : Scheme.{u}} (g : Y ⟶ Z) (x : X) : - (f ≫ g).residueFieldMap x = g.residueFieldMap (f.val.base x) ≫ f.residueFieldMap x := + (f ≫ g).residueFieldMap x = g.residueFieldMap (f.base x) ≫ f.residueFieldMap x := LocallyRingedSpace.residueFieldMap_comp _ _ _ @[reassoc] -lemma evaluation_naturality {V : Opens Y} (x : X) (hx : f.val.base x ∈ V) : - Y.evaluation V (f.val.base x) hx ≫ f.residueFieldMap x = +lemma evaluation_naturality {V : Opens Y} (x : X) (hx : f.base x ∈ V) : + Y.evaluation V (f.base x) hx ≫ f.residueFieldMap x = f.app V ≫ X.evaluation (f ⁻¹ᵁ V) x hx := - LocallyRingedSpace.evaluation_naturality f ⟨x, hx⟩ + LocallyRingedSpace.evaluation_naturality f.1 ⟨x, hx⟩ -lemma evaluation_naturality_apply {V : Opens Y} (x : X) (hx : f.val.base x ∈ V) (s) : - f.residueFieldMap x (Y.evaluation V (f.val.base x) hx s) = +lemma evaluation_naturality_apply {V : Opens Y} (x : X) (hx : f.base x ∈ V) (s) : + f.residueFieldMap x (Y.evaluation V (f.base x) hx s) = X.evaluation (f ⁻¹ᵁ V) x hx (f.app V s) := - LocallyRingedSpace.evaluation_naturality_apply f ⟨x, hx⟩ s + LocallyRingedSpace.evaluation_naturality_apply f.1 ⟨x, hx⟩ s + +@[reassoc] +lemma Γevaluation_naturality (x : X) : + Y.Γevaluation (f.base x) ≫ f.residueFieldMap x = + f.c.app (op ⊤) ≫ X.Γevaluation x := + LocallyRingedSpace.Γevaluation_naturality f.toLRSHom x + +lemma Γevaluation_naturality_apply (x : X) (a : Y.presheaf.obj (op ⊤)) : + f.residueFieldMap x (Y.Γevaluation (f.base x) a) = + X.Γevaluation x (f.c.app (op ⊤) a) := + LocallyRingedSpace.Γevaluation_naturality_apply f.toLRSHom x a instance [IsOpenImmersion f] (x) : IsIso (f.residueFieldMap x) := (LocalRing.ResidueField.mapEquiv @@ -158,6 +200,10 @@ lemma residue_residueFieldCongr (X : Scheme) {x y : X} (h : x = y) : subst h simp +lemma Hom.residueFieldMap_congr {f g : X ⟶ Y} (e : f = g) (x : X) : + f.residueFieldMap x = (Y.residueFieldCongr (by subst e; rfl)).hom ≫ g.residueFieldMap x := by + subst e; simp + end congr section fromResidueField @@ -165,7 +211,12 @@ section fromResidueField /-- The canonical map `Spec κ(x) ⟶ X`. -/ def fromSpecResidueField (X : Scheme) (x : X) : Spec (X.residueField x) ⟶ X := - Spec.map (CommRingCat.ofHom (X.residue x)) ≫ X.fromSpecStalk x + Spec.map (X.residue x) ≫ X.fromSpecStalk x + +instance {X : Scheme.{u}} (x : X) : IsPreimmersion (X.fromSpecResidueField x) := by + dsimp only [Scheme.fromSpecResidueField] + rw [IsPreimmersion.comp_iff] + infer_instance @[reassoc (attr := simp)] lemma residueFieldCongr_fromSpecResidueField {x y : X} (h : x = y) : @@ -173,8 +224,73 @@ lemma residueFieldCongr_fromSpecResidueField {x y : X} (h : x = y) : X.fromSpecResidueField _ := by subst h; simp +@[reassoc] +lemma Hom.Spec_map_residueFieldMap_fromSpecResidueField (x : X) : + Spec.map (f.residueFieldMap x) ≫ Y.fromSpecResidueField _ = + X.fromSpecResidueField x ≫ f := by + dsimp only [fromSpecResidueField] + rw [Category.assoc, ← Spec_map_stalkMap_fromSpecStalk, ← Spec.map_comp_assoc, + ← Spec.map_comp_assoc] + rfl + +@[simp] +lemma fromSpecResidueField_apply (x : X.carrier) (s : Spec (X.residueField x)) : + (X.fromSpecResidueField x).base s = x := by + simp [fromSpecResidueField] + +lemma range_fromSpecResidueField (x : X.carrier) : + Set.range (X.fromSpecResidueField x).base = {x} := by + ext s + simp only [Set.mem_range, fromSpecResidueField_apply, Set.mem_singleton_iff, eq_comm (a := s)] + constructor + · rintro ⟨-, h⟩ + exact h + · rintro rfl + exact ⟨closedPoint (X.residueField x), rfl⟩ + +lemma descResidueField_fromSpecResidueField {K : Type*} [Field K] (X : Scheme) {x} + (f : X.presheaf.stalk x ⟶ .of K) [IsLocalHom f] : + Spec.map (X.descResidueField f) ≫ + X.fromSpecResidueField x = Spec.map f ≫ X.fromSpecStalk x := by + simp [fromSpecResidueField, ← Spec.map_comp_assoc] + +lemma descResidueField_stalkClosedPointTo_fromSpecResidueField + (K : Type u) [Field K] (X : Scheme.{u}) (f : Spec (.of K) ⟶ X) : + Spec.map (X.descResidueField (Scheme.stalkClosedPointTo f)) ≫ + X.fromSpecResidueField (f.base (closedPoint K)) = f := by + erw [X.descResidueField_fromSpecResidueField] + rw [Scheme.Spec_stalkClosedPointTo_fromSpecStalk] + end fromResidueField +/-- A helper lemma to work with `AlgebraicGeometry.Scheme.SpecToEquivOfField`. -/ +lemma SpecToEquivOfField_eq_iff {K : Type*} [Field K] {X : Scheme} + {f₁ f₂ : Σ x : X.carrier, X.residueField x ⟶ .of K} : + f₁ = f₂ ↔ ∃ e : f₁.1 = f₂.1, f₁.2 = (X.residueFieldCongr e).hom ≫ f₂.2 := by + constructor + · rintro rfl + simp + · obtain ⟨f, _⟩ := f₁ + obtain ⟨g, _⟩ := f₂ + rintro ⟨(rfl : f = g), h⟩ + simpa + +/-- For a field `K` and a scheme `X`, the morphisms `Spec K ⟶ X` bijectively correspond +to pairs of points `x` of `X` and embeddings `κ(x) ⟶ K`. -/ +def SpecToEquivOfField (K : Type u) [Field K] (X : Scheme.{u}) : + (Spec (.of K) ⟶ X) ≃ Σ x, X.residueField x ⟶ .of K where + toFun f := + ⟨_, X.descResidueField (Scheme.stalkClosedPointTo f)⟩ + invFun xf := Spec.map xf.2 ≫ X.fromSpecResidueField xf.1 + left_inv := Scheme.descResidueField_stalkClosedPointTo_fromSpecResidueField K X + right_inv f := by + rw [SpecToEquivOfField_eq_iff] + simp only [CommRingCat.coe_of, Scheme.comp_coeBase, TopCat.coe_comp, Function.comp_apply, + Scheme.fromSpecResidueField_apply, exists_true_left] + rw [← Spec.map_inj, Spec.map_comp, ← cancel_mono (X.fromSpecResidueField _)] + erw [Scheme.descResidueField_stalkClosedPointTo_fromSpecResidueField] + simp + end Scheme end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Restrict.lean b/Mathlib/AlgebraicGeometry/Restrict.lean index 489e0dc07ca6a..d58abb51d96f0 100644 --- a/Mathlib/AlgebraicGeometry/Restrict.lean +++ b/Mathlib/AlgebraicGeometry/Restrict.lean @@ -41,12 +41,12 @@ namespace Scheme.Opens /-- Open subset of a scheme as a scheme. -/ @[coe] def toScheme {X : Scheme.{u}} (U : X.Opens) : Scheme.{u} := - X.restrict U.openEmbedding + X.restrict U.isOpenEmbedding instance : CoeOut X.Opens Scheme := ⟨toScheme⟩ /-- The restriction of a scheme to an open subset. -/ -@[simps! val_base_apply] +@[simps! base_apply] def ι : ↑U ⟶ X := X.ofRestrict _ instance : IsOpenImmersion U.ι := inferInstanceAs (IsOpenImmersion (X.ofRestrict _)) @@ -81,11 +81,11 @@ lemma opensRange_ι : U.ι.opensRange = U := Opens.ext Subtype.range_val @[simp] -lemma range_ι : Set.range U.ι.val.base = U := +lemma range_ι : Set.range U.ι.base = U := Subtype.range_val lemma ι_image_top : U.ι ''ᵁ ⊤ = U := - U.openEmbedding_obj_top + U.isOpenEmbedding_obj_top lemma ι_image_le (W : U.toScheme.Opens) : U.ι ''ᵁ W ≤ U := by simp_rw [← U.ι_image_top] @@ -105,7 +105,7 @@ lemma ι_app_self : U.ι.app U = X.presheaf.map (eqToHom (X := U.ι ''ᵁ _) (by lemma eq_presheaf_map_eqToHom {V W : Opens U} (e : U.ι ''ᵁ V = U.ι ''ᵁ W) : X.presheaf.map (eqToHom e).op = - U.toScheme.presheaf.map (eqToHom <| U.openEmbedding.functor_obj_injective e).op := rfl + U.toScheme.presheaf.map (eqToHom <| U.isOpenEmbedding.functor_obj_injective e).op := rfl @[simp] lemma nonempty_iff : Nonempty U.toScheme ↔ (U : Set X).Nonempty := by @@ -121,27 +121,20 @@ def topIso : Γ(U, ⊤) ≅ Γ(X, U) := /-- The stalks of an open subscheme are isomorphic to the stalks of the original scheme. -/ def stalkIso {X : Scheme.{u}} (U : X.Opens) (x : U) : U.toScheme.presheaf.stalk x ≅ X.presheaf.stalk x.1 := - X.restrictStalkIso (Opens.openEmbedding _) _ + X.restrictStalkIso (Opens.isOpenEmbedding _) _ @[reassoc (attr := simp)] lemma germ_stalkIso_hom {X : Scheme.{u}} (U : X.Opens) - {V : U.toScheme.Opens} (x : V) : - U.toScheme.presheaf.germ x ≫ (U.stalkIso x.1).hom = - X.presheaf.germ ⟨x.1.1, show x.1.1 ∈ U.ι ''ᵁ V from ⟨x.1, x.2, rfl⟩⟩ := - PresheafedSpace.restrictStalkIso_hom_eq_germ _ U.openEmbedding _ _ _ + {V : U.toScheme.Opens} (x : U) (hx : x ∈ V) : + U.toScheme.presheaf.germ V x hx ≫ (U.stalkIso x).hom = + X.presheaf.germ (U.ι ''ᵁ V) x.1 ⟨x, hx, rfl⟩ := + PresheafedSpace.restrictStalkIso_hom_eq_germ _ U.isOpenEmbedding _ _ _ -@[reassoc (attr := simp)] -lemma germ_stalkIso_hom' {X : Scheme.{u}} (U : X.Opens) - {V : TopologicalSpace.Opens U} (x : U) (hx : x ∈ V) : - U.toScheme.presheaf.germ ⟨x, hx⟩ ≫ (U.stalkIso x).hom = - X.presheaf.germ ⟨x.1, show x.1 ∈ U.ι ''ᵁ V from ⟨x, hx, rfl⟩⟩ := - PresheafedSpace.restrictStalkIso_hom_eq_germ _ U.openEmbedding _ _ _ - -@[simp, reassoc] +@[reassoc] lemma germ_stalkIso_inv {X : Scheme.{u}} (U : X.Opens) (V : U.toScheme.Opens) (x : U) - (hx : x ∈ V) : X.presheaf.germ ⟨x.val, show x.val ∈ U.ι ''ᵁ V from ⟨x, hx, rfl⟩⟩ ≫ - (U.stalkIso x).inv = U.toScheme.presheaf.germ ⟨x, hx⟩ := - PresheafedSpace.restrictStalkIso_inv_eq_germ X.toPresheafedSpace U.openEmbedding V x hx + (hx : x ∈ V) : X.presheaf.germ (U.ι ''ᵁ V) x ⟨x, hx, rfl⟩ ≫ + (U.stalkIso x).inv = U.toScheme.presheaf.germ V x hx := + PresheafedSpace.restrictStalkIso_inv_eq_germ X.toPresheafedSpace U.isOpenEmbedding V x hx end Scheme.Opens @@ -173,46 +166,95 @@ instance ΓRestrictAlgebra {X : Scheme.{u}} (U : X.Opens) : Algebra (Γ(X, ⊤)) Γ(U, ⊤) := (U.ι.app ⊤).toAlgebra -lemma Scheme.map_basicOpen' (r : Γ(U, ⊤)) : - U.ι ''ᵁ (U.toScheme.basicOpen r) = X.basicOpen - (X.presheaf.map (eqToHom U.openEmbedding_obj_top.symm).op r) := by - refine (Scheme.image_basicOpen (X.ofRestrict U.openEmbedding) r).trans ?_ - erw [← Scheme.basicOpen_res_eq _ _ (eqToHom U.openEmbedding_obj_top).op] +lemma Scheme.map_basicOpen (r : Γ(U, ⊤)) : + U.ι ''ᵁ U.toScheme.basicOpen r = X.basicOpen + (X.presheaf.map (eqToHom U.isOpenEmbedding_obj_top.symm).op r) := by + refine (Scheme.image_basicOpen (X.ofRestrict U.isOpenEmbedding) r).trans ?_ + rw [← Scheme.basicOpen_res_eq _ _ (eqToHom U.isOpenEmbedding_obj_top).op] rw [← comp_apply, ← CategoryTheory.Functor.map_comp, ← op_comp, eqToHom_trans, eqToHom_refl, op_id, CategoryTheory.Functor.map_id] congr exact PresheafedSpace.IsOpenImmersion.ofRestrict_invApp _ _ _ +@[deprecated (since := "2024-10-23")] alias Scheme.map_basicOpen' := Scheme.map_basicOpen + lemma Scheme.Opens.ι_image_basicOpen (r : Γ(U, ⊤)) : - U.ι ''ᵁ (U.toScheme.basicOpen r) = X.basicOpen r := by - rw [Scheme.map_basicOpen', Scheme.basicOpen_res_eq] + U.ι ''ᵁ U.toScheme.basicOpen r = X.basicOpen r := by + rw [Scheme.map_basicOpen, Scheme.basicOpen_res_eq] lemma Scheme.map_basicOpen_map (r : Γ(X, U)) : U.ι ''ᵁ (U.toScheme.basicOpen <| U.topIso.inv r) = X.basicOpen r := by simp only [Scheme.Opens.toScheme_presheaf_obj] - rw [Scheme.map_basicOpen', Scheme.basicOpen_res_eq, Scheme.Opens.topIso_inv, + rw [Scheme.map_basicOpen, Scheme.basicOpen_res_eq, Scheme.Opens.topIso_inv, Scheme.basicOpen_res_eq X] +/-- If `U ≤ V`, then `U` is also a subscheme of `V`. -/ +protected noncomputable +def Scheme.homOfLE (X : Scheme.{u}) {U V : X.Opens} (e : U ≤ V) : (U : Scheme.{u}) ⟶ V := + IsOpenImmersion.lift V.ι U.ι (by simpa using e) + +@[reassoc (attr := simp)] +lemma Scheme.homOfLE_ι (X : Scheme.{u}) {U V : X.Opens} (e : U ≤ V) : + X.homOfLE e ≫ V.ι = U.ι := + IsOpenImmersion.lift_fac _ _ _ + +@[simp] +lemma Scheme.homOfLE_rfl (X : Scheme.{u}) (U : X.Opens) : X.homOfLE (refl U) = 𝟙 _ := by + rw [← cancel_mono U.ι, Scheme.homOfLE_ι, Category.id_comp] + +@[reassoc (attr := simp)] +lemma Scheme.homOfLE_homOfLE (X : Scheme.{u}) {U V W : X.Opens} (e₁ : U ≤ V) (e₂ : V ≤ W) : + X.homOfLE e₁ ≫ X.homOfLE e₂ = X.homOfLE (e₁.trans e₂) := by + rw [← cancel_mono W.ι, Category.assoc, Scheme.homOfLE_ι, Scheme.homOfLE_ι, Scheme.homOfLE_ι] + +theorem Scheme.homOfLE_base {U V : X.Opens} (e : U ≤ V) : + (X.homOfLE e).base = (Opens.toTopCat _).map (homOfLE e) := by + ext a; refine Subtype.ext ?_ -- Porting note: `ext` did not pick up `Subtype.ext` + exact congr($(X.homOfLE_ι e).base a) + +@[simp] +theorem Scheme.homOfLE_apply {U V : X.Opens} (e : U ≤ V) (x : U) : + ((X.homOfLE e).base x).1 = x := by + rw [homOfLE_base] + rfl + +theorem Scheme.ι_image_homOfLE_le_ι_image {U V : X.Opens} (e : U ≤ V) (W : Opens V) : + U.ι ''ᵁ (X.homOfLE e ⁻¹ᵁ W) ≤ V.ι ''ᵁ W := by + simp only [← SetLike.coe_subset_coe, IsOpenMap.functor_obj_coe, Set.image_subset_iff, + Scheme.homOfLE_base, Opens.map_coe, Opens.inclusion'_apply] + rintro _ h + exact ⟨_, h, rfl⟩ + +@[simp] +theorem Scheme.homOfLE_app {U V : X.Opens} (e : U ≤ V) (W : Opens V) : + (X.homOfLE e).app W = + X.presheaf.map (homOfLE <| X.ι_image_homOfLE_le_ι_image e W).op := by + have e₁ := Scheme.congr_app (X.homOfLE_ι e) (V.ι ''ᵁ W) + have : V.ι ⁻¹ᵁ V.ι ''ᵁ W = W := W.map_functor_eq (U := V) + have e₂ := (X.homOfLE e).naturality (eqToIso this).hom.op + have e₃ := e₂.symm.trans e₁ + dsimp at e₃ ⊢ + rw [← IsIso.eq_comp_inv, ← Functor.map_inv, ← Functor.map_comp] at e₃ + rw [e₃, ← Functor.map_comp] + congr 1 + +instance (X : Scheme.{u}) {U V : X.Opens} (e : U ≤ V) : IsOpenImmersion (X.homOfLE e) := by + delta Scheme.homOfLE + infer_instance + -- Porting note: `simps` can't synthesize `obj_left, obj_hom, mapLeft` variable (X) in /-- The functor taking open subsets of `X` to open subschemes of `X`. -/ -- @[simps obj_left obj_hom mapLeft] def Scheme.restrictFunctor : X.Opens ⥤ Over X where obj U := Over.mk U.ι - map {U V} i := - Over.homMk - (IsOpenImmersion.lift V.ι U.ι <| by simpa using i.le) - (IsOpenImmersion.lift_fac _ _ _) + map {U V} i := Over.homMk (X.homOfLE i.le) (by simp) map_id U := by ext1 - dsimp only [Over.homMk_left, Over.id_left] - rw [← cancel_mono U.ι, Category.id_comp, - IsOpenImmersion.lift_fac] + exact Scheme.homOfLE_rfl _ _ map_comp {U V W} i j := by ext1 - dsimp only [Over.homMk_left, Over.comp_left] - rw [← cancel_mono W.ι, Category.assoc] - iterate 3 rw [IsOpenImmersion.lift_fac] + exact (X.homOfLE_homOfLE i.le j.le).symm @[simp] lemma Scheme.restrictFunctor_obj_left (U : X.Opens) : (X.restrictFunctor.obj U).left = U := rfl @@ -220,52 +262,32 @@ def Scheme.restrictFunctor : X.Opens ⥤ Over X where @[simp] lemma Scheme.restrictFunctor_obj_hom (U : X.Opens) : (X.restrictFunctor.obj U).hom = U.ι := rfl -/-- This is not a `simp` lemma, as `(X.restricFunctor.map i).left` is used as the `simp` -normal-form for the induced morphism `U.toScheme ⟶ V.toScheme`. -/ +@[simp] lemma Scheme.restrictFunctor_map_left {U V : X.Opens} (i : U ⟶ V) : - (X.restrictFunctor.map i).left = IsOpenImmersion.lift (V.ι) U.ι (by simpa using i.le) := rfl + (X.restrictFunctor.map i).left = (X.homOfLE i.le) := rfl --- Porting note: the `by ...` used to be automatically done by unification magic -@[reassoc] -theorem Scheme.restrictFunctor_map_ofRestrict {U V : X.Opens} (i : U ⟶ V) : - (X.restrictFunctor.map i).1 ≫ V.ι = U.ι := - IsOpenImmersion.lift_fac _ _ (by simpa using i.le) - -theorem Scheme.restrictFunctor_map_base {U V : X.Opens} (i : U ⟶ V) : - (X.restrictFunctor.map i).1.val.base = (Opens.toTopCat _).map i := by - ext a; refine Subtype.ext ?_ -- Porting note: `ext` did not pick up `Subtype.ext` - exact (congr_arg (fun f : X.restrict U.openEmbedding ⟶ X => f.val.base a) - (X.restrictFunctor_map_ofRestrict i)) - -theorem Scheme.restrictFunctor_map_app_aux {U V : X.Opens} (i : U ⟶ V) (W : Opens V) : - U.ι ''ᵁ ((X.restrictFunctor.map i).1 ⁻¹ᵁ W) ≤ V.ι ''ᵁ W := by - simp only [← SetLike.coe_subset_coe, IsOpenMap.functor_obj_coe, Set.image_subset_iff, - Scheme.restrictFunctor_map_base, Opens.map_coe, Opens.inclusion'_apply] - rintro _ h - exact ⟨_, h, rfl⟩ +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictFunctor_map_ofRestrict := Scheme.homOfLE_ι +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictFunctor_map_ofRestrict_assoc := Scheme.homOfLE_ι_assoc -theorem Scheme.restrictFunctor_map_app {U V : X.Opens} (i : U ⟶ V) (W : Opens V) : - (X.restrictFunctor.map i).1.app W = - X.presheaf.map (homOfLE <| X.restrictFunctor_map_app_aux i W).op := by - have e₁ := Scheme.congr_app (X.restrictFunctor_map_ofRestrict i) (V.ι ''ᵁ W) - have : V.ι ⁻¹ᵁ V.ι ''ᵁ W = W := W.map_functor_eq (U := V) - have e₂ := (X.restrictFunctor.map i).1.naturality (eqToIso this).hom.op - have e₃ := e₂.symm.trans e₁ - dsimp at e₃ ⊢ - rw [← IsIso.eq_comp_inv, ← Functor.map_inv, ← Functor.map_comp] at e₃ - rw [e₃, ← Functor.map_comp] - congr 1 +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictFunctor_map_base := Scheme.homOfLE_base +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictFunctor_map_app_aux := Scheme.ι_image_homOfLE_le_ι_image +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictFunctor_map_app := Scheme.homOfLE_app /-- The functor that restricts to open subschemes and then takes global section is isomorphic to the structure sheaf. -/ @[simps!] def Scheme.restrictFunctorΓ : X.restrictFunctor.op ⋙ (Over.forget X).op ⋙ Scheme.Γ ≅ X.presheaf := NatIso.ofComponents - (fun U => X.presheaf.mapIso ((eqToIso (unop U).openEmbedding_obj_top).symm.op : _)) + (fun U => X.presheaf.mapIso ((eqToIso (unop U).isOpenEmbedding_obj_top).symm.op : _)) (by intro U V i dsimp - rw [X.restrictFunctor_map_app, ← Functor.map_comp, ← Functor.map_comp] + rw [X.homOfLE_app, ← Functor.map_comp, ← Functor.map_comp] congr 1) /-- `X ∣_ U ∣_ V` is isomorphic to `X ∣_ V ∣_ U` -/ @@ -275,39 +297,97 @@ def Scheme.restrictRestrictComm (X : Scheme.{u}) (U V : X.Opens) : IsOpenImmersion.isoOfRangeEq (Opens.ι _ ≫ U.ι) (Opens.ι _ ≫ V.ι) <| by simp [Set.image_preimage_eq_inter_range, Set.inter_comm (U : Set X), Set.range_comp] -/-- If `V` is an open subset of `U`, then `X ∣_ U ∣_ V` is isomorphic to `X ∣_ V`. -/ +/-- If `f : X ⟶ Y` is an open immersion, then for any `U : X.Opens`, +we have the isomorphism `U ≅ f ''ᵁ U`. -/ noncomputable -def Scheme.restrictRestrict (X : Scheme.{u}) (U : X.Opens) (V : U.toScheme.Opens) : - V.toScheme ≅ U.ι ''ᵁ V := - IsOpenImmersion.isoOfRangeEq (Opens.ι _ ≫ U.ι) (Opens.ι _) (by simp [Set.range_comp]) +def Scheme.Hom.isoImage + {X Y : Scheme.{u}} (f : X.Hom Y) [IsOpenImmersion f] (U : X.Opens) : + U.toScheme ≅ f ''ᵁ U := + IsOpenImmersion.isoOfRangeEq (Opens.ι _ ≫ f) (Opens.ι _) (by simp [Set.range_comp]) -@[simp, reassoc] -lemma Scheme.restrictRestrict_hom_restrict (X : Scheme.{u}) (U : X.Opens) - (V : U.toScheme.Opens) : - (X.restrictRestrict U V).hom ≫ Opens.ι _ = V.ι ≫ U.ι := +@[reassoc (attr := simp)] +lemma Scheme.Hom.isoImage_hom_ι + {X Y : Scheme.{u}} (f : X ⟶ Y) [IsOpenImmersion f] (U : X.Opens) : + (f.isoImage U).hom ≫ (f ''ᵁ U).ι = U.ι ≫ f := IsOpenImmersion.isoOfRangeEq_hom_fac _ _ _ -@[simp, reassoc] -lemma Scheme.restrictRestrict_inv_restrict_restrict (X : Scheme.{u}) (U : X.Opens) - (V : U.toScheme.Opens) : - (X.restrictRestrict U V).inv ≫ V.ι ≫ U.ι = Opens.ι _ := +@[reassoc (attr := simp)] +lemma Scheme.Hom.isoImage_inv_ι + {X Y : Scheme.{u}} (f : X ⟶ Y) [IsOpenImmersion f] (U : X.Opens) : + (f.isoImage U).inv ≫ U.ι ≫ f = (f ''ᵁ U).ι := IsOpenImmersion.isoOfRangeEq_inv_fac _ _ _ +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictRestrict := Scheme.Hom.isoImage +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictRestrict_hom_restrict := Scheme.Hom.isoImage_hom_ι +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictRestrict_inv_restrict_restrict := Scheme.Hom.isoImage_inv_ι +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictRestrict_hom_restrict_assoc := Scheme.Hom.isoImage_hom_ι_assoc +@[deprecated (since := "2024-10-20")] +alias Scheme.restrictRestrict_inv_restrict_restrict_assoc := Scheme.Hom.isoImage_inv_ι_assoc + +/-- `(⊤ : X.Opens)` as a scheme is isomorphic to `X`. -/ +@[simps hom] +def Scheme.topIso (X : Scheme) : ↑(⊤ : X.Opens) ≅ X where + hom := Scheme.Opens.ι _ + inv := ⟨X.restrictTopIso.inv⟩ + hom_inv_id := Hom.ext' X.restrictTopIso.hom_inv_id + inv_hom_id := Hom.ext' X.restrictTopIso.inv_hom_id + +@[reassoc (attr := simp)] +lemma Scheme.toIso_inv_ι (X : Scheme.{u}) : X.topIso.inv ≫ Opens.ι _ = 𝟙 _ := + X.topIso.inv_hom_id + +@[reassoc (attr := simp)] +lemma Scheme.ι_toIso_inv (X : Scheme.{u}) : Opens.ι _ ≫ X.topIso.inv = 𝟙 _ := + X.topIso.hom_inv_id + /-- If `U = V`, then `X ∣_ U` is isomorphic to `X ∣_ V`. -/ noncomputable -def Scheme.restrictIsoOfEq (X : Scheme.{u}) {U V : X.Opens} (e : U = V) : +def Scheme.isoOfEq (X : Scheme.{u}) {U V : X.Opens} (e : U = V) : (U : Scheme.{u}) ≅ V := - IsOpenImmersion.isoOfRangeEq U.ι (V.ι) (by rw [e]) + IsOpenImmersion.isoOfRangeEq U.ι V.ι (by rw [e]) + +@[reassoc (attr := simp)] +lemma Scheme.isoOfEq_hom_ι (X : Scheme.{u}) {U V : X.Opens} (e : U = V) : + (X.isoOfEq e).hom ≫ V.ι = U.ι := + IsOpenImmersion.isoOfRangeEq_hom_fac _ _ _ + +@[reassoc (attr := simp)] +lemma Scheme.isoOfEq_inv_ι (X : Scheme.{u}) {U V : X.Opens} (e : U = V) : + (X.isoOfEq e).inv ≫ U.ι = V.ι := + IsOpenImmersion.isoOfRangeEq_inv_fac _ _ _ + +@[simp] +lemma Scheme.isoOfEq_rfl (X : Scheme.{u}) (U : X.Opens) : X.isoOfEq (refl U) = Iso.refl _ := by + ext1 + rw [← cancel_mono U.ι, Scheme.isoOfEq_hom_ι, Iso.refl_hom, Category.id_comp] + +@[deprecated (since := "2024-10-20")] alias Scheme.restrictIsoOfEq := Scheme.isoOfEq end /-- The restriction of an isomorphism onto an open set. -/ -noncomputable abbrev Scheme.restrictMapIso {X Y : Scheme.{u}} (f : X ⟶ Y) [IsIso f] +noncomputable def Scheme.Hom.preimageIso {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := Scheme) f] (U : Y.Opens) : (f ⁻¹ᵁ U).toScheme ≅ U := by apply IsOpenImmersion.isoOfRangeEq (f := (f ⁻¹ᵁ U).ι ≫ f) U.ι _ dsimp rw [Set.range_comp, Opens.range_ι, Opens.range_ι] - refine @Set.image_preimage_eq _ _ f.val.base U.1 f.homeomorph.surjective + refine @Set.image_preimage_eq _ _ f.base U.1 f.homeomorph.surjective + +@[reassoc (attr := simp)] +lemma Scheme.Hom.preimageIso_hom_ι {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := Scheme) f] + (U : Y.Opens) : (f.preimageIso U).hom ≫ U.ι = (f ⁻¹ᵁ U).ι ≫ f := + IsOpenImmersion.isoOfRangeEq_hom_fac _ _ _ + +@[reassoc (attr := simp)] +lemma Scheme.Hom.preimageIso_inv_ι {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := Scheme) f] + (U : Y.Opens) : (f.preimageIso U).inv ≫ (f ⁻¹ᵁ U).ι ≫ f = U.ι := + IsOpenImmersion.isoOfRangeEq_inv_fac _ _ _ + +@[deprecated (since := "2024-10-20")] alias Scheme.restrictMapIso := Scheme.Hom.preimageIso section MorphismRestrict @@ -322,11 +402,16 @@ theorem pullbackRestrictIsoRestrict_inv_fst {X Y : Scheme.{u}} (f : X ⟶ Y) (U (pullbackRestrictIsoRestrict f U).inv ≫ pullback.fst f _ = (f ⁻¹ᵁ U).ι := by delta pullbackRestrictIsoRestrict; simp -@[simp, reassoc] -theorem pullbackRestrictIsoRestrict_hom_restrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : +@[reassoc (attr := simp)] +theorem pullbackRestrictIsoRestrict_hom_ι {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : (pullbackRestrictIsoRestrict f U).hom ≫ (f ⁻¹ᵁ U).ι = pullback.fst f _ := by delta pullbackRestrictIsoRestrict; simp +@[deprecated (since := "2024-10-20")] +alias pullbackRestrictIsoRestrict_hom_restrict := pullbackRestrictIsoRestrict_hom_ι +@[deprecated (since := "2024-10-20")] +alias pullbackRestrictIsoRestrict_hom_restrict_assoc := pullbackRestrictIsoRestrict_hom_ι_assoc + /-- The restriction of a morphism `X ⟶ Y` onto `X |_{f ⁻¹ U} ⟶ Y |_ U`. -/ def morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : (f ⁻¹ᵁ U).toScheme ⟶ U := (pullbackRestrictIsoRestrict f U).inv ≫ pullback.snd _ _ @@ -334,12 +419,12 @@ def morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : (f ⁻¹ /-- the notation for restricting a morphism of scheme to an open subset of the target scheme -/ infixl:85 " ∣_ " => morphismRestrict -@[simp, reassoc] +@[reassoc (attr := simp)] theorem pullbackRestrictIsoRestrict_hom_morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : (pullbackRestrictIsoRestrict f U).hom ≫ f ∣_ U = pullback.snd _ _ := Iso.hom_inv_id_assoc _ _ -@[simp, reassoc] +@[reassoc (attr := simp)] theorem morphismRestrict_ι {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : (f ∣_ U) ≫ U.ι = (f ⁻¹ᵁ U).ι ≫ f := by delta morphismRestrict @@ -351,7 +436,7 @@ theorem isPullback_morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Open rw [← Category.id_comp f] refine (IsPullback.of_horiz_isIso ⟨?_⟩).paste_horiz - (IsPullback.of_hasPullback f (Y.ofRestrict U.openEmbedding)).flip + (IsPullback.of_hasPullback f (Y.ofRestrict U.isOpenEmbedding)).flip -- Porting note: changed `rw` to `erw` erw [pullbackRestrictIsoRestrict_inv_fst]; rw [Category.comp_id] @@ -377,12 +462,12 @@ instance {X Y : Scheme.{u}} (f : X ⟶ Y) [IsIso f] (U : Y.Opens) : IsIso (f ∣ delta morphismRestrict; infer_instance theorem morphismRestrict_base_coe {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (x) : - @Coe.coe U Y (⟨fun x => x.1⟩) ((f ∣_ U).val.base x) = f.val.base x.1 := - congr_arg (fun f => PresheafedSpace.Hom.base (LocallyRingedSpace.Hom.val f) x) + @Coe.coe U Y (⟨fun x => x.1⟩) ((f ∣_ U).base x) = f.base x.1 := + congr_arg (fun f => (Scheme.Hom.toLRSHom f).base x) (morphismRestrict_ι f U) -theorem morphismRestrict_val_base {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : - ⇑(f ∣_ U).val.base = U.1.restrictPreimage f.val.base := +theorem morphismRestrict_base {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : + ⇑(f ∣_ U).base = U.1.restrictPreimage f.base := funext fun x => Subtype.ext (morphismRestrict_base_coe f U x) theorem image_morphismRestrict_preimage {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : Opens U) : @@ -390,18 +475,18 @@ theorem image_morphismRestrict_preimage {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y. ext1 ext x constructor - · rintro ⟨⟨x, hx⟩, hx' : (f ∣_ U).val.base _ ∈ V, rfl⟩ + · rintro ⟨⟨x, hx⟩, hx' : (f ∣_ U).base _ ∈ V, rfl⟩ refine ⟨⟨_, hx⟩, ?_, rfl⟩ -- Porting note: this rewrite was not necessary rw [SetLike.mem_coe] convert hx' - -- Porting note: `ext1` is not compiling + -- Porting note (#11041): `ext1` is not compiling refine Subtype.ext ?_ exact (morphismRestrict_base_coe f U ⟨x, hx⟩).symm · rintro ⟨⟨x, hx⟩, hx' : _ ∈ V.1, rfl : x = _⟩ - refine ⟨⟨_, hx⟩, (?_ : (f ∣_ U).val.base ⟨x, hx⟩ ∈ V.1), rfl⟩ + refine ⟨⟨_, hx⟩, (?_ : (f ∣_ U).base ⟨x, hx⟩ ∈ V.1), rfl⟩ convert hx' - -- Porting note: `ext1` is compiling + -- Porting note (#11041): `ext1` is compiling refine Subtype.ext ?_ exact morphismRestrict_base_coe f U ⟨x, hx⟩ @@ -437,8 +522,8 @@ theorem morphismRestrict_appLE {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V theorem Γ_map_morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : Scheme.Γ.map (f ∣_ U).op = - Y.presheaf.map (eqToHom U.openEmbedding_obj_top.symm).op ≫ - f.app U ≫ X.presheaf.map (eqToHom (f ⁻¹ᵁ U).openEmbedding_obj_top).op := by + Y.presheaf.map (eqToHom U.isOpenEmbedding_obj_top.symm).op ≫ + f.app U ≫ X.presheaf.map (eqToHom (f ⁻¹ᵁ U).isOpenEmbedding_obj_top).op := by rw [Scheme.Γ_map_op, morphismRestrict_app f U ⊤, f.naturality_assoc, ← X.presheaf.map_comp] rfl @@ -458,7 +543,7 @@ def morphismRestrictOpensRange rw [Iso.trans_hom, asIso_hom, ← Iso.comp_inv_eq, ← cancel_mono g, Arrow.mk_hom, Arrow.mk_hom, Category.assoc, Category.assoc, Category.assoc, IsOpenImmersion.isoOfRangeEq_inv_fac, ← pullback.condition, morphismRestrict_ι, - pullbackRestrictIsoRestrict_hom_restrict_assoc, pullback.lift_fst_assoc, Category.comp_id] + pullbackRestrictIsoRestrict_hom_ι_assoc, pullback.lift_fst_assoc, Category.comp_id] /-- The restrictions onto two equal open sets are isomorphic. This currently has bad defeqs when unfolded, but it should not matter for now. Replace this definition if better defeqs are needed. -/ @@ -469,27 +554,26 @@ def morphismRestrictEq {X Y : Scheme.{u}} (f : X ⟶ Y) {U V : Y.Opens} (e : U = /-- Restricting a morphism twice is isomorphic to one restriction. -/ def morphismRestrictRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : U.toScheme.Opens) : Arrow.mk (f ∣_ U ∣_ V) ≅ Arrow.mk (f ∣_ U.ι ''ᵁ V) := by - refine Arrow.isoMk' _ _ (Scheme.restrictRestrict _ _ _ ≪≫ Scheme.restrictIsoOfEq _ ?_) - (Scheme.restrictRestrict _ _ _) ?_ + refine Arrow.isoMk' _ _ ((Scheme.Opens.ι _).isoImage _ ≪≫ Scheme.isoOfEq _ ?_) + ((Scheme.Opens.ι _).isoImage _) ?_ · ext x simp only [IsOpenMap.functor_obj_coe, Opens.coe_inclusion', - Opens.map_coe, Set.mem_image, Set.mem_preimage, SetLike.mem_coe, morphismRestrict_val_base] + Opens.map_coe, Set.mem_image, Set.mem_preimage, SetLike.mem_coe, morphismRestrict_base] constructor · rintro ⟨⟨a, h₁⟩, h₂, rfl⟩ exact ⟨_, h₂, rfl⟩ · rintro ⟨⟨a, h₁⟩, h₂, rfl : a = _⟩ exact ⟨⟨x, h₁⟩, h₂, rfl⟩ · rw [← cancel_mono (Scheme.Opens.ι _), Iso.trans_hom, Category.assoc, Category.assoc, - Category.assoc, morphismRestrict_ι, Scheme.restrictIsoOfEq, - IsOpenImmersion.isoOfRangeEq_hom_fac_assoc, - Scheme.restrictRestrict_hom_restrict_assoc, - Scheme.restrictRestrict_hom_restrict, + Category.assoc, morphismRestrict_ι, Scheme.isoOfEq_hom_ι_assoc, + Scheme.Hom.isoImage_hom_ι_assoc, + Scheme.Hom.isoImage_hom_ι, morphismRestrict_ι_assoc, morphismRestrict_ι] /-- Restricting a morphism twice onto a basic open set is isomorphic to one restriction. -/ def morphismRestrictRestrictBasicOpen {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (r : Γ(Y, U)) : Arrow.mk (f ∣_ U ∣_ - U.toScheme.basicOpen (Y.presheaf.map (eqToHom U.openEmbedding_obj_top).op r)) ≅ + U.toScheme.basicOpen (Y.presheaf.map (eqToHom U.isOpenEmbedding_obj_top).op r)) ≅ Arrow.mk (f ∣_ Y.basicOpen r) := by refine morphismRestrictRestrict _ _ _ ≪≫ morphismRestrictEq _ ?_ have e := Scheme.preimage_basicOpen U.ι r @@ -508,13 +592,13 @@ def morphismRestrictRestrictBasicOpen {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Op -/ def morphismRestrictStalkMap {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (x) : Arrow.mk ((f ∣_ U).stalkMap x) ≅ Arrow.mk (f.stalkMap x.1) := Arrow.isoMk' _ _ - (U.stalkIso ((f ∣_ U).1.base x) ≪≫ + (U.stalkIso ((f ∣_ U).base x) ≪≫ (TopCat.Presheaf.stalkCongr _ <| Inseparable.of_eq <| morphismRestrict_base_coe f U x)) ((f ⁻¹ᵁ U).stalkIso x) <| by apply TopCat.Presheaf.stalk_hom_ext intro V hxV change ↑(f ⁻¹ᵁ U) at x - simp [Scheme.stalkMap_germ'_assoc, Scheme.Hom.appLE] + simp [Scheme.stalkMap_germ_assoc, Scheme.Hom.appLE] instance {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) [IsOpenImmersion f] : IsOpenImmersion (f ∣_ U) := by @@ -527,36 +611,36 @@ namespace Scheme.Hom /-- The restriction of a morphism `f : X ⟶ Y` to open sets on the source and target. -/ def resLE (f : Hom X Y) (U : Y.Opens) (V : X.Opens) (e : V ≤ f ⁻¹ᵁ U) : V.toScheme ⟶ U.toScheme := - (X.restrictFunctor.map (homOfLE e)).left ≫ f ∣_ U + X.homOfLE e ≫ f ∣_ U variable (f : X ⟶ Y) {U U' : Y.Opens} {V V' : X.Opens} (e : V ≤ f ⁻¹ᵁ U) lemma resLE_eq_morphismRestrict : f.resLE U (f ⁻¹ᵁ U) le_rfl = f ∣_ U := by - simp [Scheme.Hom.resLE] + simp [resLE] -lemma resLE_id (i : V ⟶ V') : resLE (𝟙 X) V' V i.le = (X.restrictFunctor.map i).left := by - simp only [resLE, id_val_base, morphismRestrict_id, Category.comp_id] +lemma resLE_id (i : V ≤ V') : resLE (𝟙 X) V' V i = X.homOfLE i := by + simp only [resLE, morphismRestrict_id] rfl @[reassoc (attr := simp)] lemma resLE_comp_ι : f.resLE U V e ≫ U.ι = V.ι ≫ f := by - simp [resLE, restrictFunctor_map_ofRestrict_assoc] + simp [resLE] @[reassoc] lemma resLE_comp_resLE {Z : Scheme.{u}} (g : Y ⟶ Z) {W : Z.Opens} (e') : f.resLE U V e ≫ g.resLE W U e' = (f ≫ g).resLE W V - (e.trans ((Opens.map f.val.base).map (homOfLE e')).le) := by + (e.trans ((Opens.map f.base).map (homOfLE e')).le) := by simp [← cancel_mono W.ι] @[reassoc (attr := simp)] -lemma map_resLE (i : V' ⟶ V) : - (X.restrictFunctor.map i).left ≫ f.resLE U V e = f.resLE U V' (i.le.trans e) := by +lemma map_resLE (i : V' ≤ V) : + X.homOfLE i ≫ f.resLE U V e = f.resLE U V' (i.trans e) := by simp_rw [← resLE_id, resLE_comp_resLE, Category.id_comp] @[reassoc (attr := simp)] -lemma resLE_map (i : U ⟶ U') : - f.resLE U V e ≫ (Y.restrictFunctor.map i).left = - f.resLE U' V (e.trans ((Opens.map f.1.base).map i).le) := by +lemma resLE_map (i : U ≤ U') : + f.resLE U V e ≫ Y.homOfLE i = + f.resLE U' V (e.trans ((Opens.map f.base).map i.hom).le) := by simp_rw [← resLE_id, resLE_comp_resLE, Category.comp_id] lemma resLE_congr (e₁ : U = U') (e₂ : V = V') (P : MorphismProperty Scheme.{u}) : @@ -577,12 +661,10 @@ lemma resLE_appLE {U : Y.Opens} {V : X.Opens} (e : V ≤ f ⁻¹ᵁ U) (O : U.toScheme.Opens) (W : V.toScheme.Opens) (e' : W ≤ resLE f U V e ⁻¹ᵁ O) : (f.resLE U V e).appLE O W e' = f.appLE (U.ι ''ᵁ O) (V.ι ''ᵁ W) ((le_preimage_resLE_iff f e O W).mp e') := by - simp only [Scheme.Hom.appLE, Scheme.Hom.resLE, Scheme.restrictFunctor_map_left, Opens.map_coe, - id_eq, Scheme.comp_app, morphismRestrict_app', Category.assoc, IsOpenImmersion.lift_app, - Scheme.Opens.ι_appIso, Scheme.Opens.ι_app, Scheme.Opens.toScheme_presheaf_map, Category.assoc] + simp only [appLE, resLE, comp_coeBase, Opens.map_comp_obj, comp_app, morphismRestrict_app', + homOfLE_leOfHom, homOfLE_app, Category.assoc, Opens.toScheme_presheaf_map, Quiver.Hom.unop_op, + opensFunctor_map_homOfLE] rw [← X.presheaf.map_comp, ← X.presheaf.map_comp] - erw [Category.id_comp] - rw [← X.presheaf.map_comp] rfl end Scheme.Hom @@ -611,6 +693,6 @@ def Scheme.OpenCover.restrict {X : Scheme.{u}} (𝒰 : X.OpenCover) (U : Opens X rw [← cancel_mono U.ι] simp only [morphismRestrict_ι, pullbackCover_J, Equiv.refl_apply, pullbackCover_obj, pullbackCover_map, Category.assoc, pullback.condition] - erw [IsOpenImmersion.isoOfRangeEq_hom_fac_assoc] + rw [IsOpenImmersion.isoOfRangeEq_hom_fac_assoc] end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Scheme.lean b/Mathlib/AlgebraicGeometry/Scheme.lean index 97a64d277db0a..18cc563e90561 100644 --- a/Mathlib/AlgebraicGeometry/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/Scheme.lean @@ -46,7 +46,7 @@ structure Scheme extends LocallyRingedSpace where ∀ x : toLocallyRingedSpace, ∃ (U : OpenNhds x) (R : CommRingCat), Nonempty - (toLocallyRingedSpace.restrict U.openEmbedding ≅ Spec.toLocallyRingedSpace.obj (op R)) + (toLocallyRingedSpace.restrict U.isOpenEmbedding ≅ Spec.toLocallyRingedSpace.obj (op R)) namespace Scheme @@ -57,20 +57,31 @@ instance : CoeSort Scheme Type* where abbrev Opens (X : Scheme) : Type* := TopologicalSpace.Opens X /-- A morphism between schemes is a morphism between the underlying locally ringed spaces. -/ --- @[nolint has_nonempty_instance] -- Porting note(#5171): linter not ported yet -def Hom (X Y : Scheme) : Type* := - X.toLocallyRingedSpace ⟶ Y.toLocallyRingedSpace +structure Hom (X Y : Scheme) extends X.toLocallyRingedSpace.Hom Y.toLocallyRingedSpace where + +/-- Cast a morphism of schemes into morphisms of local ringed spaces. -/ +abbrev Hom.toLRSHom {X Y : Scheme.{u}} (f : X.Hom Y) : + X.toLocallyRingedSpace ⟶ Y.toLocallyRingedSpace := + f.toHom_1 + +/-- See Note [custom simps projection] -/ +def Hom.Simps.toLRSHom {X Y : Scheme.{u}} (f : X.Hom Y) : + X.toLocallyRingedSpace ⟶ Y.toLocallyRingedSpace := + f.toLRSHom + +initialize_simps_projections Hom (toHom_1 → toLRSHom) /-- Schemes are a full subcategory of locally ringed spaces. -/ -instance : Category Scheme := - { InducedCategory.category Scheme.toLocallyRingedSpace with Hom := Hom } +instance : Category Scheme where + id X := Hom.mk (𝟙 X.toLocallyRingedSpace) + comp f g := Hom.mk (f.toLRSHom ≫ g.toLRSHom) -/-- `f ⁻¹ᵁ U` is notation for `(Opens.map f.1.base).obj U`, +/-- `f ⁻¹ᵁ U` is notation for `(Opens.map f.base).obj U`, the preimage of an open set `U` under `f`. -/ scoped[AlgebraicGeometry] notation3:90 f:91 " ⁻¹ᵁ " U:90 => @Prefunctor.obj (Scheme.Opens _) _ (Scheme.Opens _) _ - (Opens.map (f : LocallyRingedSpace.Hom _ _).val.base).toPrefunctor U + (Opens.map (f : Scheme.Hom _ _).base).toPrefunctor U /-- `Γ(X, U)` is notation for `X.presheaf.obj (op U)`. -/ scoped[AlgebraicGeometry] notation3 "Γ(" X ", " U ")" => @@ -82,7 +93,7 @@ instance {X : Scheme.{u}} : Subsingleton Γ(X, ⊥) := CommRingCat.subsingleton_of_isTerminal X.sheaf.isTerminalOfEmpty @[continuity, fun_prop] -lemma Hom.continuous {X Y : Scheme} (f : X ⟶ Y) : Continuous f.1.base := f.1.base.2 +lemma Hom.continuous {X Y : Scheme} (f : X ⟶ Y) : Continuous f.base := f.base.2 /-- The structure sheaf of a scheme. -/ protected abbrev sheaf (X : Scheme) := @@ -95,12 +106,12 @@ variable {X Y : Scheme.{u}} (f : Hom X Y) {U U' : Y.Opens} {V V' : X.Opens} /-- Given a morphism of schemes `f : X ⟶ Y`, and open `U ⊆ Y`, this is the induced map `Γ(Y, U) ⟶ Γ(X, f ⁻¹ᵁ U)`. -/ abbrev app (U : Y.Opens) : Γ(Y, U) ⟶ Γ(X, f ⁻¹ᵁ U) := - f.1.c.app (op U) + f.c.app (op U) @[reassoc] lemma naturality (i : op U' ⟶ op U) : - Y.presheaf.map i ≫ f.app U = f.app U' ≫ X.presheaf.map ((Opens.map f.1.base).map i.unop).op := - f.1.c.naturality i + Y.presheaf.map i ≫ f.app U = f.app U' ≫ X.presheaf.map ((Opens.map f.base).map i.unop).op := + f.c.naturality i /-- Given a morphism of schemes `f : X ⟶ Y`, and open sets `U ⊆ Y`, `V ⊆ f ⁻¹' U`, this is the induced map `Γ(Y, U) ⟶ Γ(X, V)`. -/ @@ -121,7 +132,7 @@ lemma appLE_map' (e : V ≤ f ⁻¹ᵁ U) (i : V = V') : @[reassoc (attr := simp)] lemma map_appLE (e : V ≤ f ⁻¹ᵁ U) (i : op U' ⟶ op U) : Y.presheaf.map i ≫ f.appLE U V e = - f.appLE U' V (e.trans ((Opens.map f.1.base).map i.unop).le) := by + f.appLE U' V (e.trans ((Opens.map f.base).map i.unop).le) := by rw [Hom.appLE, f.naturality_assoc, ← Functor.map_comp] rfl @@ -143,22 +154,23 @@ lemma appLE_congr (e : V ≤ f ⁻¹ᵁ U) (e₁ : U = U') (e₂ : V = V') P (f.appLE U V e) ↔ P (f.appLE U' V' (e₁ ▸ e₂ ▸ e)) := by subst e₁; subst e₂; rfl -/-- An isomorphism of schemes induces a homeomorphism of the underlying topological spaces. -/ -noncomputable def homeomorph [IsIso f] : X ≃ₜ Y := - TopCat.homeoOfIso (asIso <| f.val.base) - -/-- A morphism of schemes `f : X ⟶ Y` induces a local ring homomorphis from `Y.presheaf.stalk (f x)` -to `X.presheaf.stalk x` for any `x : X`. -/ -def stalkMap (x : X) : Y.presheaf.stalk (f.val.base x) ⟶ X.presheaf.stalk x := - f.val.stalkMap x +/-- A morphism of schemes `f : X ⟶ Y` induces a local ring homomorphism from +`Y.presheaf.stalk (f x)` to `X.presheaf.stalk x` for any `x : X`. -/ +def stalkMap (x : X) : Y.presheaf.stalk (f.base x) ⟶ X.presheaf.stalk x := + f.toLRSHom.stalkMap x @[ext (iff := false)] -protected lemma ext {f g : X ⟶ Y} (h_base : f.1.base = g.1.base) +protected lemma ext {f g : X ⟶ Y} (h_base : f.base = g.base) (h_app : ∀ U, f.app U ≫ X.presheaf.map - (eqToHom congr((Opens.map $h_base.symm).obj U)).op = g.app U) : f = g := - LocallyRingedSpace.Hom.ext <| SheafedSpace.ext _ _ h_base + (eqToHom congr((Opens.map $h_base.symm).obj U)).op = g.app U) : f = g := by + cases f; cases g; congr 1 + exact LocallyRingedSpace.Hom.ext' <| SheafedSpace.ext _ _ h_base (TopCat.Presheaf.ext fun U ↦ by simpa using h_app U) +/-- An alternative ext lemma for scheme morphisms. -/ +protected lemma ext' {f g : X ⟶ Y} (h : f.toLRSHom = g.toLRSHom) : f = g := by + cases f; cases g; congr 1 + lemma preimage_iSup {ι} (U : ι → Opens Y) : f ⁻¹ᵁ iSup U = ⨆ i, f ⁻¹ᵁ U i := Opens.ext (by simp) @@ -177,27 +189,38 @@ lemma preimage_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (U) : /-- The forgetful functor from `Scheme` to `LocallyRingedSpace`. -/ @[simps!] -def forgetToLocallyRingedSpace : Scheme ⥤ LocallyRingedSpace := - inducedFunctor _ --- deriving Full, Faithful -- Porting note: no delta derive handler, see https://github.com/leanprover-community/mathlib4/issues/5020 +def forgetToLocallyRingedSpace : Scheme ⥤ LocallyRingedSpace where + obj := toLocallyRingedSpace + map := Hom.toLRSHom /-- The forget functor `Scheme ⥤ LocallyRingedSpace` is fully faithful. -/ -@[simps!] +@[simps preimage_toLRSHom] def fullyFaithfulForgetToLocallyRingedSpace : - forgetToLocallyRingedSpace.FullyFaithful := - fullyFaithfulInducedFunctor _ + forgetToLocallyRingedSpace.FullyFaithful where + preimage := Hom.mk instance : forgetToLocallyRingedSpace.Full := - InducedCategory.full _ + fullyFaithfulForgetToLocallyRingedSpace.full instance : forgetToLocallyRingedSpace.Faithful := - InducedCategory.faithful _ + fullyFaithfulForgetToLocallyRingedSpace.faithful /-- The forgetful functor from `Scheme` to `TopCat`. -/ @[simps!] def forgetToTop : Scheme ⥤ TopCat := Scheme.forgetToLocallyRingedSpace ⋙ LocallyRingedSpace.forgetToTop +/-- An isomorphism of schemes induces a homeomorphism of the underlying topological spaces. -/ +noncomputable def homeoOfIso {X Y : Scheme.{u}} (e : X ≅ Y) : X ≃ₜ Y := + TopCat.homeoOfIso (forgetToTop.mapIso e) + +alias _root_.CategoryTheory.Iso.schemeIsoToHomeo := homeoOfIso + +/-- An isomorphism of schemes induces a homeomorphism of the underlying topological spaces. -/ +noncomputable def Hom.homeomorph {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := Scheme) f] : + X ≃ₜ Y := + (asIso f).schemeIsoToHomeo + -- Porting note: Lean seems not able to find this coercion any more instance hasCoeToTopCat : CoeOut Scheme TopCat where coe X := X.carrier @@ -208,7 +231,7 @@ unif_hint forgetToTop_obj_eq_coe (X : Scheme) where ⊢ forgetToTop.obj X ≟ (X : TopCat) @[simp] -theorem id_val_base (X : Scheme) : (𝟙 X : _).1.base = 𝟙 _ := +theorem id.base (X : Scheme) : (𝟙 X : _).base = 𝟙 _ := rfl @[simp] @@ -216,22 +239,23 @@ theorem id_app {X : Scheme} (U : X.Opens) : (𝟙 X : _).app U = 𝟙 _ := rfl @[reassoc] -theorem comp_val {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g).val = f.val ≫ g.val := +theorem comp_toLRSHom {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).toLRSHom = f.toLRSHom ≫ g.toLRSHom := rfl @[simp, reassoc] -- reassoc lemma does not need `simp` theorem comp_coeBase {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : - (f ≫ g).val.base = f.val.base ≫ g.val.base := + (f ≫ g).base = f.base ≫ g.base := rfl -- Porting note: removed elementwise attribute, as generated lemmas were trivial. @[reassoc] -theorem comp_val_base {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : - (f ≫ g).val.base = f.val.base ≫ g.val.base := +theorem comp_base {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).base = f.base ≫ g.base := rfl -theorem comp_val_base_apply {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : - (f ≫ g).val.base x = g.val.base (f.val.base x) := by +theorem comp_base_apply {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : + (f ≫ g).base x = g.base (f.base x) := by simp @[simp, reassoc] -- reassoc lemma does not need `simp` @@ -244,7 +268,7 @@ theorem comp_app {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) (U) : theorem appLE_comp_appLE {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) (U V W e₁ e₂) : g.appLE U V e₁ ≫ f.appLE V W e₂ = - (f ≫ g).appLE U W (e₂.trans ((Opens.map f.1.base).map (homOfLE e₁)).le) := by + (f ≫ g).appLE U W (e₂.trans ((Opens.map f.base).map (homOfLE e₁)).le) := by dsimp [Hom.appLE] rw [Category.assoc, f.naturality_assoc, ← Functor.map_comp] rfl @@ -262,8 +286,8 @@ theorem app_eq {X Y : Scheme} (f : X ⟶ Y) {U V : Y.Opens} (e : U = V) : f.app U = Y.presheaf.map (eqToHom e.symm).op ≫ f.app V ≫ - X.presheaf.map (eqToHom (congr_arg (Opens.map f.val.base).obj e)).op := by - rw [← IsIso.inv_comp_eq, ← Functor.map_inv, f.val.c.naturality] + X.presheaf.map (eqToHom (congr_arg (Opens.map f.base).obj e)).op := by + rw [← IsIso.inv_comp_eq, ← Functor.map_inv, f.naturality] cases e rfl @@ -276,21 +300,20 @@ lemma presheaf_map_eqToHom_op (X : Scheme) (U V : X.Opens) (i : U = V) : X.presheaf.map (eqToHom i).op = eqToHom (i ▸ rfl) := by rw [eqToHom_op, eqToHom_map] -instance is_locallyRingedSpace_iso {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : - @IsIso LocallyRingedSpace _ _ _ f := +instance is_locallyRingedSpace_iso {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : IsIso f.toLRSHom := forgetToLocallyRingedSpace.map_isIso f -instance val_base_isIso {X Y : Scheme.{u}} (f : X ⟶ Y) [IsIso f] : IsIso f.1.base := +instance base_isIso {X Y : Scheme.{u}} (f : X ⟶ Y) [IsIso f] : IsIso f.base := Scheme.forgetToTop.map_isIso f -- Porting note: need an extra instance here. -instance {X Y : Scheme} (f : X ⟶ Y) [IsIso f] (U) : IsIso (f.val.c.app U) := - haveI := PresheafedSpace.c_isIso_of_iso f.val - NatIso.isIso_app_of_isIso _ _ +instance {X Y : Scheme} (f : X ⟶ Y) [IsIso f] (U) : IsIso (f.c.app U) := + haveI := PresheafedSpace.c_isIso_of_iso f.toPshHom + NatIso.isIso_app_of_isIso f.c _ instance {X Y : Scheme} (f : X ⟶ Y) [IsIso f] (U) : IsIso (f.app U) := - haveI := PresheafedSpace.c_isIso_of_iso f.val - NatIso.isIso_app_of_isIso _ _ + haveI := PresheafedSpace.c_isIso_of_iso f.toPshHom + NatIso.isIso_app_of_isIso f.c _ @[simp] theorem inv_app {X Y : Scheme} (f : X ⟶ Y) [IsIso f] (U : X.Opens) : @@ -318,16 +341,16 @@ theorem Spec_toLocallyRingedSpace (R : CommRingCat) : /-- The induced map of a ring homomorphism on the ring spectra, as a morphism of schemes. -/ def Spec.map {R S : CommRingCat} (f : R ⟶ S) : Spec S ⟶ Spec R := - (Spec.locallyRingedSpaceMap f : Spec.locallyRingedSpaceObj S ⟶ Spec.locallyRingedSpaceObj R) + ⟨Spec.locallyRingedSpaceMap f⟩ @[simp] theorem Spec.map_id (R : CommRingCat) : Spec.map (𝟙 R) = 𝟙 (Spec R) := - Spec.locallyRingedSpaceMap_id R + Scheme.Hom.ext' <| Spec.locallyRingedSpaceMap_id R @[reassoc, simp] theorem Spec.map_comp {R S T : CommRingCat} (f : R ⟶ S) (g : S ⟶ T) : Spec.map (f ≫ g) = Spec.map g ≫ Spec.map f := - Spec.locallyRingedSpaceMap_comp f g + Scheme.Hom.ext' <| Spec.locallyRingedSpaceMap_comp f g /-- The spectrum, as a contravariant functor from commutative rings to schemes. -/ @[simps] @@ -358,7 +381,7 @@ variable {R S : CommRingCat.{u}} (f : R ⟶ S) lemma Spec_carrier (R : CommRingCat.{u}) : (Spec R).carrier = PrimeSpectrum R := rfl lemma Spec_sheaf (R : CommRingCat.{u}) : (Spec R).sheaf = Spec.structureSheaf R := rfl lemma Spec_presheaf (R : CommRingCat.{u}) : (Spec R).presheaf = (Spec.structureSheaf R).1 := rfl -lemma Spec.map_base : (Spec.map f).1.base = PrimeSpectrum.comap f := rfl +lemma Spec.map_base : (Spec.map f).base = PrimeSpectrum.comap f := rfl lemma Spec.map_app (U) : (Spec.map f).app U = StructureSheaf.comap f U (Spec.map f ⁻¹ᵁ U) le_rfl := rfl @@ -388,9 +411,9 @@ instance : Inhabited Scheme := /-- The global sections, notated Gamma. -/ def Γ : Schemeᵒᵖ ⥤ CommRingCat := - (inducedFunctor Scheme.toLocallyRingedSpace).op ⋙ LocallyRingedSpace.Γ + Scheme.forgetToLocallyRingedSpace.op ⋙ LocallyRingedSpace.Γ -theorem Γ_def : Γ = (inducedFunctor Scheme.toLocallyRingedSpace).op ⋙ LocallyRingedSpace.Γ := +theorem Γ_def : Γ = Scheme.forgetToLocallyRingedSpace.op ⋙ LocallyRingedSpace.Γ := rfl @[simp] @@ -450,22 +473,24 @@ variable (X : Scheme) {V U : X.Opens} (f g : Γ(X, U)) def basicOpen : X.Opens := X.toLocallyRingedSpace.toRingedSpace.basicOpen f +theorem mem_basicOpen (x : X) (hx : x ∈ U) : + x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ U x hx f) := + RingedSpace.mem_basicOpen _ _ _ _ + +/-- A variant of `mem_basicOpen` for bundled `x : U`. -/ @[simp] -theorem mem_basicOpen (x : U) : ↑x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ x f) := - RingedSpace.mem_basicOpen _ _ _ +theorem mem_basicOpen' (x : U) : ↑x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ U x x.2 f) := + RingedSpace.mem_basicOpen _ _ _ _ -theorem mem_basicOpen_top' {U : X.Opens} (f : Γ(X, U)) (x : X) : - x ∈ X.basicOpen f ↔ ∃ (m : x ∈ U), IsUnit (X.presheaf.germ (⟨x, m⟩ : U) f) := by - fconstructor - · rintro ⟨y, hy1, rfl⟩ - exact ⟨y.2, hy1⟩ - · rintro ⟨m, hm⟩ - exact ⟨⟨x, m⟩, hm, rfl⟩ +/-- A variant of `mem_basicOpen` without the `x ∈ U` assumption. -/ +theorem mem_basicOpen'' {U : X.Opens} (f : Γ(X, U)) (x : X) : + x ∈ X.basicOpen f ↔ ∃ (m : x ∈ U), IsUnit (X.presheaf.germ U x m f) := + Iff.rfl @[simp] theorem mem_basicOpen_top (f : Γ(X, ⊤)) (x : X) : - x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ (⟨x, trivial⟩ : (⊤ : Opens _)) f) := - RingedSpace.mem_basicOpen _ f ⟨x, trivial⟩ + x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ ⊤ x trivial f) := + RingedSpace.mem_top_basicOpen _ f x @[simp] theorem basicOpen_res (i : op U ⟶ op V) : X.basicOpen (X.presheaf.map i f) = V ⊓ X.basicOpen f := @@ -489,7 +514,7 @@ lemma basicOpen_restrict (i : V ⟶ U) (f : Γ(X, U)) : @[simp] theorem preimage_basicOpen {X Y : Scheme.{u}} (f : X ⟶ Y) {U : Y.Opens} (r : Γ(Y, U)) : f ⁻¹ᵁ (Y.basicOpen r) = X.basicOpen (f.app U r) := - LocallyRingedSpace.preimage_basicOpen f r + LocallyRingedSpace.preimage_basicOpen f.toLRSHom r lemma basicOpen_appLE {X Y : Scheme.{u}} (f : X ⟶ Y) (U : X.Opens) (V : Y.Opens) (e : U ≤ f ⁻¹ᵁ V) (s : Γ(Y, V)) : X.basicOpen (f.appLE V U e s) = U ⊓ f ⁻¹ᵁ (Y.basicOpen s) := by @@ -558,7 +583,7 @@ theorem basicOpen_eq_of_affine {R : CommRingCat} (f : R) : ext x simp only [SetLike.mem_coe, Scheme.mem_basicOpen_top, Opens.coe_top] suffices IsUnit (StructureSheaf.toStalk R x f) ↔ f ∉ PrimeSpectrum.asIdeal x by exact this - erw [← isUnit_map_iff (StructureSheaf.stalkToFiberRingHom R x), + rw [← isUnit_map_iff (StructureSheaf.stalkToFiberRingHom R x), StructureSheaf.stalkToFiberRingHom_toStalk] exact (IsLocalization.AtPrime.isUnit_to_map_iff (Localization.AtPrime (PrimeSpectrum.asIdeal x)) @@ -579,26 +604,34 @@ theorem Scheme.Spec_map_presheaf_map_eqToHom {X : Scheme} {U V : X.Opens} (h : U refine (Scheme.congr_app this _).trans ?_ simp [eqToHom_map] +lemma germ_eq_zero_of_pow_mul_eq_zero {X : Scheme.{u}} {U : Opens X} (x : U) {f s : Γ(X, U)} + (hx : x.val ∈ X.basicOpen s) {n : ℕ} (hf : s ^ n * f = 0) : X.presheaf.germ U x x.2 f = 0 := by + rw [Scheme.mem_basicOpen] at hx + have hu : IsUnit (X.presheaf.germ _ x x.2 (s ^ n)) := by + rw [map_pow] + exact IsUnit.pow n hx + rw [← hu.mul_right_eq_zero, ← map_mul, hf, map_zero] + @[reassoc (attr := simp)] -lemma Scheme.iso_hom_val_base_inv_val_base {X Y : Scheme.{u}} (e : X ≅ Y) : - e.hom.val.base ≫ e.inv.val.base = 𝟙 _ := - LocallyRingedSpace.iso_hom_val_base_inv_val_base (Scheme.forgetToLocallyRingedSpace.mapIso e) +lemma Scheme.iso_hom_base_inv_base {X Y : Scheme.{u}} (e : X ≅ Y) : + e.hom.base ≫ e.inv.base = 𝟙 _ := + LocallyRingedSpace.iso_hom_base_inv_base (Scheme.forgetToLocallyRingedSpace.mapIso e) @[simp] -lemma Scheme.iso_hom_val_base_inv_val_base_apply {X Y : Scheme.{u}} (e : X ≅ Y) (x : X) : - (e.inv.val.base (e.hom.val.base x)) = x := by - show (e.hom.val.base ≫ e.inv.val.base) x = 𝟙 X.toPresheafedSpace x +lemma Scheme.iso_hom_base_inv_base_apply {X Y : Scheme.{u}} (e : X ≅ Y) (x : X) : + (e.inv.base (e.hom.base x)) = x := by + show (e.hom.base ≫ e.inv.base) x = 𝟙 X.toPresheafedSpace x simp @[reassoc (attr := simp)] -lemma Scheme.iso_inv_val_base_hom_val_base {X Y : Scheme.{u}} (e : X ≅ Y) : - e.inv.val.base ≫ e.hom.val.base = 𝟙 _ := - LocallyRingedSpace.iso_inv_val_base_hom_val_base (Scheme.forgetToLocallyRingedSpace.mapIso e) +lemma Scheme.iso_inv_base_hom_base {X Y : Scheme.{u}} (e : X ≅ Y) : + e.inv.base ≫ e.hom.base = 𝟙 _ := + LocallyRingedSpace.iso_inv_base_hom_base (Scheme.forgetToLocallyRingedSpace.mapIso e) @[simp] -lemma Scheme.iso_inv_val_base_hom_val_base_apply {X Y : Scheme.{u}} (e : X ≅ Y) (y : Y) : - (e.hom.val.base (e.inv.val.base y)) = y := by - show (e.inv.val.base ≫ e.hom.val.base) y = 𝟙 Y.toPresheafedSpace y +lemma Scheme.iso_inv_base_hom_base_apply {X Y : Scheme.{u}} (e : X ≅ Y) (y : Y) : + (e.hom.base (e.inv.base y)) = y := by + show (e.inv.base ≫ e.hom.base) y = 𝟙 Y.toPresheafedSpace y simp section Stalks @@ -607,23 +640,26 @@ namespace Scheme variable {X Y : Scheme.{u}} (f : X ⟶ Y) +instance (x) : IsLocalHom (f.stalkMap x) := + f.prop x + @[simp] lemma stalkMap_id (X : Scheme.{u}) (x : X) : (𝟙 X : X ⟶ X).stalkMap x = 𝟙 (X.presheaf.stalk x) := PresheafedSpace.stalkMap.id _ x lemma stalkMap_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : - (f ≫ g : X ⟶ Z).stalkMap x = g.stalkMap (f.val.base x) ≫ f.stalkMap x := - PresheafedSpace.stalkMap.comp f.val g.val x + (f ≫ g : X ⟶ Z).stalkMap x = g.stalkMap (f.base x) ≫ f.stalkMap x := + PresheafedSpace.stalkMap.comp f.toPshHom g.toPshHom x @[reassoc] lemma stalkSpecializes_stalkMap (x x' : X) - (h : x ⤳ x') : Y.presheaf.stalkSpecializes (f.val.base.map_specializes h) ≫ f.stalkMap x = + (h : x ⤳ x') : Y.presheaf.stalkSpecializes (f.base.map_specializes h) ≫ f.stalkMap x = f.stalkMap x' ≫ X.presheaf.stalkSpecializes h := - PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.val h + PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.toPshHom h lemma stalkSpecializes_stalkMap_apply (x x' : X) (h : x ⤳ x') (y) : - f.stalkMap x (Y.presheaf.stalkSpecializes (f.val.base.map_specializes h) y) = + f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.map_specializes h) y) = (X.presheaf.stalkSpecializes h (f.stalkMap x' y)) := DFunLike.congr_fun (stalkSpecializes_stalkMap f x x' h) y @@ -631,68 +667,68 @@ lemma stalkSpecializes_stalkMap_apply (x x' : X) (h : x ⤳ x') (y) : lemma stalkMap_congr (f g : X ⟶ Y) (hfg : f = g) (x x' : X) (hxx' : x = x') : f.stalkMap x ≫ (X.presheaf.stalkCongr (.of_eq hxx')).hom = (Y.presheaf.stalkCongr (.of_eq <| hfg ▸ hxx' ▸ rfl)).hom ≫ g.stalkMap x' := - LocallyRingedSpace.stalkMap_congr f g hfg x x' hxx' + LocallyRingedSpace.stalkMap_congr f.toLRSHom g.toLRSHom congr(($hfg).toLRSHom) x x' hxx' @[reassoc] lemma stalkMap_congr_hom (f g : X ⟶ Y) (hfg : f = g) (x : X) : f.stalkMap x = (Y.presheaf.stalkCongr (.of_eq <| hfg ▸ rfl)).hom ≫ g.stalkMap x := - LocallyRingedSpace.stalkMap_congr_hom f g hfg x + LocallyRingedSpace.stalkMap_congr_hom f.toLRSHom g.toLRSHom congr(($hfg).toLRSHom) x @[reassoc] lemma stalkMap_congr_point (x x' : X) (hxx' : x = x') : f.stalkMap x ≫ (X.presheaf.stalkCongr (.of_eq hxx')).hom = (Y.presheaf.stalkCongr (.of_eq <| hxx' ▸ rfl)).hom ≫ f.stalkMap x' := - LocallyRingedSpace.stalkMap_congr_point f x x' hxx' + LocallyRingedSpace.stalkMap_congr_point f.toLRSHom x x' hxx' @[reassoc (attr := simp)] lemma stalkMap_hom_inv (e : X ≅ Y) (y : Y) : - e.hom.stalkMap (e.inv.val.base y) ≫ e.inv.stalkMap y = + e.hom.stalkMap (e.inv.base y) ≫ e.inv.stalkMap y = (Y.presheaf.stalkCongr (.of_eq (by simp))).hom := LocallyRingedSpace.stalkMap_hom_inv (forgetToLocallyRingedSpace.mapIso e) y @[simp] lemma stalkMap_hom_inv_apply (e : X ≅ Y) (y : Y) (z) : - e.inv.stalkMap y (e.hom.stalkMap (e.inv.val.base y) z) = + e.inv.stalkMap y (e.hom.stalkMap (e.inv.base y) z) = (Y.presheaf.stalkCongr (.of_eq (by simp))).hom z := DFunLike.congr_fun (stalkMap_hom_inv e y) z @[reassoc (attr := simp)] lemma stalkMap_inv_hom (e : X ≅ Y) (x : X) : - e.inv.stalkMap (e.hom.val.base x) ≫ e.hom.stalkMap x = + e.inv.stalkMap (e.hom.base x) ≫ e.hom.stalkMap x = (X.presheaf.stalkCongr (.of_eq (by simp))).hom := LocallyRingedSpace.stalkMap_inv_hom (forgetToLocallyRingedSpace.mapIso e) x @[simp] lemma stalkMap_inv_hom_apply (e : X ≅ Y) (x : X) (y) : - e.hom.stalkMap x (e.inv.stalkMap (e.hom.val.base x) y) = + e.hom.stalkMap x (e.inv.stalkMap (e.hom.base x) y) = (X.presheaf.stalkCongr (.of_eq (by simp))).hom y := DFunLike.congr_fun (stalkMap_inv_hom e x) y -@[reassoc] -lemma stalkMap_germ (U : Y.Opens) (x : f ⁻¹ᵁ U) : - Y.presheaf.germ ⟨f.val.base x.val, x.property⟩ ≫ f.stalkMap x = - f.app U ≫ X.presheaf.germ x := - PresheafedSpace.stalkMap_germ f.val U x - -lemma stalkMap_germ_apply (U : Y.Opens) (x : f ⁻¹ᵁ U) (y) : - f.stalkMap x.val (Y.presheaf.germ ⟨f.val.base x.val, x.property⟩ y) = - X.presheaf.germ x (f.val.c.app (op U) y) := - PresheafedSpace.stalkMap_germ_apply f.val U x y - @[reassoc (attr := simp)] -lemma stalkMap_germ' (U : Y.Opens) (x : X) (hx : f.val.base x ∈ U) : - Y.presheaf.germ ⟨f.val.base x, hx⟩ ≫ f.stalkMap x = - f.app U ≫ X.presheaf.germ (U := f⁻¹ᵁ U) ⟨x, hx⟩ := - PresheafedSpace.stalkMap_germ' f.val U x hx +lemma stalkMap_germ (U : Y.Opens) (x : X) (hx : f.base x ∈ U) : + Y.presheaf.germ U (f.base x) hx ≫ f.stalkMap x = + f.app U ≫ X.presheaf.germ (f ⁻¹ᵁ U) x hx := + PresheafedSpace.stalkMap_germ f.toPshHom U x hx @[simp] -lemma stalkMap_germ'_apply (U : Y.Opens) (x : X) (hx : f.val.base x ∈ U) (y) : - f.stalkMap x (Y.presheaf.germ ⟨f.val.base x, hx⟩ y) = - X.presheaf.germ (U := (Opens.map f.val.base).obj U) ⟨x, hx⟩ (f.val.c.app (op U) y) := - PresheafedSpace.stalkMap_germ_apply f.val U ⟨x, hx⟩ y +lemma stalkMap_germ_apply (U : Y.Opens) (x : X) (hx : f.base x ∈ U) (y) : + f.stalkMap x (Y.presheaf.germ _ (f.base x) hx y) = + X.presheaf.germ (f ⁻¹ᵁ U) x hx (f.app U y) := + PresheafedSpace.stalkMap_germ_apply f.toPshHom U x hx y end Scheme end Stalks +section LocalRing + +open LocalRing + +@[simp] +lemma Spec_closedPoint {R S : CommRingCat} [LocalRing R] [LocalRing S] + {f : R ⟶ S} [IsLocalHom f] : (Spec.map f).base (closedPoint S) = closedPoint R := + LocalRing.comap_closedPoint f + +end LocalRing + end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Sites/BigZariski.lean b/Mathlib/AlgebraicGeometry/Sites/BigZariski.lean index c96f49a5dbd35..854935ddae1df 100644 --- a/Mathlib/AlgebraicGeometry/Sites/BigZariski.lean +++ b/Mathlib/AlgebraicGeometry/Sites/BigZariski.lean @@ -38,7 +38,7 @@ namespace Scheme /-- The Zariski pretopology on the category of schemes. -/ def zariskiPretopology : Pretopology (Scheme.{u}) where coverings Y S := ∃ (U : OpenCover.{u} Y), S = Presieve.ofArrows U.obj U.map - has_isos Y X f _ := ⟨openCoverOfIsIso f, (Presieve.ofArrows_pUnit _).symm⟩ + has_isos _ _ f _ := ⟨openCoverOfIsIso f, (Presieve.ofArrows_pUnit _).symm⟩ pullbacks := by rintro Y X f _ ⟨U, rfl⟩ exact ⟨U.pullbackCover' f, (Presieve.ofArrows_pullback _ _ _).symm⟩ diff --git a/Mathlib/AlgebraicGeometry/Spec.lean b/Mathlib/AlgebraicGeometry/Spec.lean index 3a10a69127f49..4d4595fade0bd 100644 --- a/Mathlib/AlgebraicGeometry/Spec.lean +++ b/Mathlib/AlgebraicGeometry/Spec.lean @@ -78,7 +78,7 @@ theorem Spec.topMap_comp {R S T : CommRingCat.{u}} (f : R ⟶ S) (g : S ⟶ T) : @[simps! obj map] def Spec.toTop : CommRingCat.{u}ᵒᵖ ⥤ TopCat where obj R := Spec.topObj (unop R) - map {R S} f := Spec.topMap f.unop + map {_ _} f := Spec.topMap f.unop /-- The spectrum of a commutative ring, as a `SheafedSpace`. -/ @@ -90,7 +90,7 @@ def Spec.sheafedSpaceObj (R : CommRingCat.{u}) : SheafedSpace CommRingCat where /-- The induced map of a ring homomorphism on the ring spectra, as a morphism of sheafed spaces. -/ -@[simps] +@[simps base c_app] def Spec.sheafedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : Spec.sheafedSpaceObj S ⟶ Spec.sheafedSpaceObj R where base := Spec.topMap f @@ -196,9 +196,11 @@ lemma Spec.locallyRingedSpaceObj_presheaf_map' (R : Type u) [CommRing R] {U V} ( theorem stalkMap_toStalk {R S : CommRingCat.{u}} (f : R ⟶ S) (p : PrimeSpectrum S) : toStalk R (PrimeSpectrum.comap f p) ≫ (Spec.sheafedSpaceMap f).stalkMap p = f ≫ toStalk S p := by - erw [← toOpen_germ S ⊤ ⟨p, trivial⟩, ← toOpen_germ R ⊤ ⟨PrimeSpectrum.comap f p, trivial⟩, - Category.assoc, PresheafedSpace.stalkMap_germ (Spec.sheafedSpaceMap f) ⊤ ⟨p, trivial⟩, - Spec.sheafedSpaceMap_c_app, toOpen_comp_comap_assoc] + rw [← toOpen_germ S ⊤ p trivial, ← toOpen_germ R ⊤ (PrimeSpectrum.comap f p) trivial, + Category.assoc] + erw [PresheafedSpace.stalkMap_germ (Spec.sheafedSpaceMap f) ⊤ p trivial] + rw [Spec.sheafedSpaceMap_c_app] + erw [toOpen_comp_comap_assoc] rfl /-- Under the isomorphisms `stalkIso`, the map `stalkMap (Spec.sheafedSpaceMap f) p` corresponds @@ -224,11 +226,11 @@ theorem localRingHom_comp_stalkIso {R S : CommRingCat.{u}} (f : R ⟶ S) (p : Pr /-- The induced map of a ring homomorphism on the prime spectra, as a morphism of locally ringed spaces. -/ -@[simps] +@[simps toShHom] def Spec.locallyRingedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : Spec.locallyRingedSpaceObj S ⟶ Spec.locallyRingedSpaceObj R := LocallyRingedSpace.Hom.mk (Spec.sheafedSpaceMap f) fun p => - IsLocalRingHom.mk fun a ha => by + IsLocalHom.mk fun a ha => by -- Here, we are showing that the map on prime spectra induced by `f` is really a morphism of -- *locally* ringed spaces, i.e. that the induced map on the stalks is a local ring -- homomorphism. @@ -238,7 +240,7 @@ def Spec.locallyRingedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : erw [← localRingHom_comp_stalkIso_apply] at ha replace ha := (isUnit_map_iff (stalkIso S p).inv _).mp ha -- Porting note: `f` had to be made explicit - replace ha := IsLocalRingHom.map_nonunit + replace ha := IsLocalHom.map_nonunit (f := (Localization.localRingHom (PrimeSpectrum.comap f p).asIdeal p.asIdeal f _)) _ ha convert RingHom.isUnit_map (stalkIso R (PrimeSpectrum.comap f p)).inv ha erw [← comp_apply, show stalkToFiberRingHom R _ = (stalkIso _ _).hom from rfl, @@ -247,14 +249,14 @@ def Spec.locallyRingedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : @[simp] theorem Spec.locallyRingedSpaceMap_id (R : CommRingCat.{u}) : Spec.locallyRingedSpaceMap (𝟙 R) = 𝟙 (Spec.locallyRingedSpaceObj R) := - LocallyRingedSpace.Hom.ext <| by - rw [Spec.locallyRingedSpaceMap_val, Spec.sheafedSpaceMap_id]; rfl + LocallyRingedSpace.Hom.ext' <| by + rw [Spec.locallyRingedSpaceMap_toShHom, Spec.sheafedSpaceMap_id]; rfl theorem Spec.locallyRingedSpaceMap_comp {R S T : CommRingCat.{u}} (f : R ⟶ S) (g : S ⟶ T) : Spec.locallyRingedSpaceMap (f ≫ g) = Spec.locallyRingedSpaceMap g ≫ Spec.locallyRingedSpaceMap f := - LocallyRingedSpace.Hom.ext <| by - rw [Spec.locallyRingedSpaceMap_val, Spec.sheafedSpaceMap_comp]; rfl + LocallyRingedSpace.Hom.ext' <| by + rw [Spec.locallyRingedSpaceMap_toShHom, Spec.sheafedSpaceMap_comp]; rfl /-- Spec, as a contravariant functor from commutative rings to locally ringed spaces. -/ @@ -283,7 +285,7 @@ instance isIso_toSpecΓ (R : CommRingCat.{u}) : IsIso (toSpecΓ R) := by @[reassoc] theorem Spec_Γ_naturality {R S : CommRingCat.{u}} (f : R ⟶ S) : f ≫ toSpecΓ S = toSpecΓ R ≫ Γ.map (Spec.toLocallyRingedSpace.map f.op).op := by - -- Porting note: `ext` failed to pick up one of the three lemmas + -- Porting note (#11041): `ext` failed to pick up one of the three lemmas refine RingHom.ext fun x => Subtype.ext <| funext fun x' => ?_; symm apply Localization.localRingHom_to_map @@ -322,16 +324,14 @@ This is shown to be the localization at `p` in `isLocalizedModule_toPushforwardS -/ def toPushforwardStalk : S ⟶ (Spec.topMap f _* (structureSheaf S).1).stalk p := StructureSheaf.toOpen S ⊤ ≫ - @TopCat.Presheaf.germ _ _ _ _ (Spec.topMap f _* (structureSheaf S).1) ⊤ ⟨p, trivial⟩ + @TopCat.Presheaf.germ _ _ _ _ (Spec.topMap f _* (structureSheaf S).1) ⊤ p trivial @[reassoc] theorem toPushforwardStalk_comp : f ≫ StructureSheaf.toPushforwardStalk f p = StructureSheaf.toStalk R p ≫ (TopCat.Presheaf.stalkFunctor _ _).map (Spec.sheafedSpaceMap f).c := by - rw [StructureSheaf.toStalk] - erw [Category.assoc] - rw [TopCat.Presheaf.stalkFunctor_map_germ] + rw [StructureSheaf.toStalk, Category.assoc, TopCat.Presheaf.stalkFunctor_map_germ] exact Spec_Γ_naturality_assoc f _ instance : Algebra R ((Spec.topMap f _* (structureSheaf S).1).stalk p) := @@ -364,9 +364,9 @@ theorem isLocalizedModule_toPushforwardStalkAlgHom_aux (y) : change PrimeSpectrum.basicOpen r ≤ U at hrU replace e := ((Spec.topMap (algebraMap R S) _* (structureSheaf S).1).germ_res_apply (homOfLE hrU) - ⟨p, hpr⟩ _).trans e + p hpr _).trans e set s' := (Spec.topMap (algebraMap R S) _* (structureSheaf S).1).map (homOfLE hrU).op s with h - replace e : ((Spec.topMap (algebraMap R S) _* (structureSheaf S).val).germ ⟨p, hpr⟩) s' = y := by + replace e : ((Spec.topMap (algebraMap R S) _* (structureSheaf S).val).germ _ p hpr) s' = y := by rw [h]; exact e clear_value s'; clear! U obtain ⟨⟨s, ⟨_, n, rfl⟩⟩, hsn⟩ := @@ -377,10 +377,10 @@ theorem isLocalizedModule_toPushforwardStalkAlgHom_aux (y) : comp_apply, comp_apply] iterate 2 erw [← (Spec.topMap (algebraMap R S) _* (structureSheaf S).1).germ_res_apply (homOfLE le_top) - ⟨p, hpr⟩] + p hpr] rw [← e] -- Porting note: without this `change`, Lean doesn't know how to rewrite `map_mul` - let f := TopCat.Presheaf.germ (Spec.topMap (algebraMap R S) _* (structureSheaf S).val) ⟨p, hpr⟩ + let f := TopCat.Presheaf.germ (Spec.topMap (algebraMap R S) _* (structureSheaf S).val) _ p hpr change f _ * f _ = f _ rw [← map_mul, mul_comm] dsimp only [Subtype.coe_mk] at hsn @@ -400,7 +400,7 @@ instance isLocalizedModule_toPushforwardStalkAlgHom : toPushforwardStalk] at hx -- Porting note: this `change` is manually rewriting `comp_apply` change _ = (TopCat.Presheaf.germ (Spec.topMap (algebraMap ↑R ↑S) _* (structureSheaf ↑S).val) - (⟨p, trivial⟩ : (⊤ : TopologicalSpace.Opens (PrimeSpectrum R))) (toOpen S ⊤ 0)) at hx + ⊤ p trivial (toOpen S ⊤ 0)) at hx rw [map_zero] at hx change (forget CommRingCat).map _ _ = (forget _).map _ _ at hx obtain ⟨U, hpU, i₁, i₂, e⟩ := TopCat.Presheaf.germ_eq _ _ _ _ _ _ hx diff --git a/Mathlib/AlgebraicGeometry/SpreadingOut.lean b/Mathlib/AlgebraicGeometry/SpreadingOut.lean new file mode 100644 index 0000000000000..444d5fba1c84f --- /dev/null +++ b/Mathlib/AlgebraicGeometry/SpreadingOut.lean @@ -0,0 +1,373 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.FiniteType +import Mathlib.AlgebraicGeometry.Noetherian +import Mathlib.AlgebraicGeometry.Stalk +import Mathlib.AlgebraicGeometry.Properties + +/-! +# Spreading out morphisms + +Under certain conditions, a morphism on stalks `Spec 𝒪_{X, x} ⟶ Spec 𝒪_{Y, y}` can be spread +out into a neighborhood of `x`. + +## Main result +Given `S`-schemes `X Y` and points `x : X` `y : Y` over `s : S`. +Suppose we have the following diagram of `S`-schemes +``` +Spec 𝒪_{X, x} ⟶ X + | + Spec(φ) + ↓ +Spec 𝒪_{Y, y} ⟶ Y +``` +We would like to spread `Spec(φ)` out to an `S`-morphism on an open subscheme `U ⊆ X` +``` +Spec 𝒪_{X, x} ⟶ U ⊆ X + | | + Spec(φ) | + ↓ ↓ +Spec 𝒪_{Y, y} ⟶ Y +``` +- `AlgebraicGeometry.spread_out_unique_of_isGermInjective`: + The lift is "unique" if the germ map is injective at `x`. +- `AlgebraicGeometry.spread_out_of_isGermInjective`: + The lift exists if `Y` is locally of finite type and the germ map is injective at `x`. + +## TODO + +Show that certain morphism properties can also be spread out. + +-/ + +universe u + +open CategoryTheory + +namespace AlgebraicGeometry + +variable {X Y S : Scheme.{u}} (f : X ⟶ Y) (sX : X ⟶ S) (sY : Y ⟶ S) (e : f ≫ sY = sX) +variable {R A : CommRingCat.{u}} + +/-- The germ map at `x` is injective if there exists some affine `U ∋ x` + such that the map `Γ(X, U) ⟶ X_x` is injective -/ +class Scheme.IsGermInjectiveAt (X : Scheme.{u}) (x : X) : Prop where + cond : ∃ (U : X.Opens) (hx : x ∈ U), IsAffineOpen U ∧ Function.Injective (X.presheaf.germ U x hx) + +lemma injective_germ_basicOpen (U : X.Opens) (hU : IsAffineOpen U) + (x : X) (hx : x ∈ U) (f : Γ(X, U)) + (hf : x ∈ X.basicOpen f) + (H : Function.Injective (X.presheaf.germ U x hx)) : + Function.Injective (X.presheaf.germ (X.basicOpen f) x hf) := by + rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero] at H ⊢ + intros t ht + have := hU.isLocalization_basicOpen f + obtain ⟨t, s, rfl⟩ := IsLocalization.mk'_surjective (.powers f) t + rw [← RingHom.mem_ker, IsLocalization.mk'_eq_mul_mk'_one, Ideal.mul_unit_mem_iff_mem, + RingHom.mem_ker, RingHom.algebraMap_toAlgebra, X.presheaf.germ_res_apply] at ht + swap; · exact @isUnit_of_invertible _ _ _ (@IsLocalization.invertible_mk'_one ..) + rw [H _ ht, IsLocalization.mk'_zero] + +lemma Scheme.exists_germ_injective (X : Scheme.{u}) (x : X) [X.IsGermInjectiveAt x] : + ∃ (U : X.Opens) (hx : x ∈ U), + IsAffineOpen U ∧ Function.Injective (X.presheaf.germ U x hx) := + Scheme.IsGermInjectiveAt.cond + +lemma Scheme.exists_le_and_germ_injective (X : Scheme.{u}) (x : X) [X.IsGermInjectiveAt x] + (V : X.Opens) (hxV : x ∈ V) : + ∃ (U : X.Opens) (hx : x ∈ U), + IsAffineOpen U ∧ U ≤ V ∧ Function.Injective (X.presheaf.germ U x hx) := by + obtain ⟨U, hx, hU, H⟩ := Scheme.IsGermInjectiveAt.cond (x := x) + obtain ⟨f, hf, hxf⟩ := hU.exists_basicOpen_le ⟨x, hxV⟩ hx + exact ⟨X.basicOpen f, hxf, hU.basicOpen f, hf, injective_germ_basicOpen U hU x hx f hxf H⟩ + +instance (x : X) [X.IsGermInjectiveAt x] [IsOpenImmersion f] : + Y.IsGermInjectiveAt (f.base x) := by + obtain ⟨U, hxU, hU, H⟩ := X.exists_germ_injective x + refine ⟨⟨f ''ᵁ U, ⟨x, hxU, rfl⟩, hU.image_of_isOpenImmersion f, ?_⟩⟩ + refine ((MorphismProperty.injective CommRingCat).cancel_right_of_respectsIso _ + (f.stalkMap x)).mp ?_ + refine ((MorphismProperty.injective CommRingCat).cancel_left_of_respectsIso + (f.appIso U).inv _).mp ?_ + simpa + +variable {f} in +lemma isGermInjectiveAt_iff_of_isOpenImmersion {x : X} [IsOpenImmersion f]: + Y.IsGermInjectiveAt (f.base x) ↔ X.IsGermInjectiveAt x := by + refine ⟨fun H ↦ ?_, fun _ ↦ inferInstance⟩ + obtain ⟨U, hxU, hU, hU', H⟩ := + Y.exists_le_and_germ_injective (f.base x) (V := f.opensRange) ⟨x, rfl⟩ + obtain ⟨V, hV⟩ := (IsOpenImmersion.affineOpensEquiv f).surjective ⟨⟨U, hU⟩, hU'⟩ + obtain rfl : f ''ᵁ V = U := Subtype.eq_iff.mp (Subtype.eq_iff.mp hV) + obtain ⟨y, hy, e : f.base y = f.base x⟩ := hxU + obtain rfl := f.isOpenEmbedding.inj e + refine ⟨V, hy, V.2, ?_⟩ + replace H := ((MorphismProperty.injective CommRingCat).cancel_right_of_respectsIso _ + (f.stalkMap y)).mpr H + replace H := ((MorphismProperty.injective CommRingCat).cancel_left_of_respectsIso + (f.appIso V).inv _).mpr H + simpa using H + +/-- +The class of schemes such that for each `x : X`, +`Γ(X, U) ⟶ X_x` is injective for some affine `U` containing `x`. + +This is typically satisfied when `X` is integral or locally noetherian. +-/ +abbrev Scheme.IsGermInjective (X : Scheme.{u}) := ∀ x : X, X.IsGermInjectiveAt x + +lemma Scheme.IsGermInjective.of_openCover + {X : Scheme.{u}} (𝒰 : X.OpenCover) [∀ i, (𝒰.obj i).IsGermInjective] : X.IsGermInjective := by + intro x + rw [← (𝒰.covers x).choose_spec] + infer_instance + +protected +lemma Scheme.IsGermInjective.Spec + (H : ∀ I : Ideal R, I.IsPrime → ∃ f : R, f ∉ I ∧ ∀ (x y : R) + (_ : y * x = 0) (_ : y ∉ I), ∃ n, f ^ n * x = 0) : (Spec R).IsGermInjective := by + refine fun p ↦ ⟨?_⟩ + obtain ⟨f, hf, H⟩ := H p.asIdeal p.2 + refine ⟨PrimeSpectrum.basicOpen f, hf, ?_, ?_⟩ + · rw [← basicOpen_eq_of_affine] + exact (isAffineOpen_top (Spec R)).basicOpen _ + rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero] + intro x hx + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective + (S := ((Spec.structureSheaf R).val.obj (.op <| PrimeSpectrum.basicOpen f))) (.powers f) x + rw [← RingHom.mem_ker, IsLocalization.mk'_eq_mul_mk'_one, Ideal.mul_unit_mem_iff_mem, + RingHom.mem_ker, RingHom.algebraMap_toAlgebra] at hx + swap; · exact @isUnit_of_invertible _ _ _ (@IsLocalization.invertible_mk'_one ..) + erw [StructureSheaf.germ_toOpen] at hx + obtain ⟨⟨y, hy⟩, hy'⟩ := (IsLocalization.map_eq_zero_iff p.asIdeal.primeCompl + ((Spec.structureSheaf R).presheaf.stalk p) _).mp hx + obtain ⟨n, hn⟩ := H x y hy' hy + refine (@IsLocalization.mk'_eq_zero_iff ..).mpr ?_ + exact ⟨⟨_, n, rfl⟩, hn⟩ + +instance (priority := 100) [IsIntegral X] : X.IsGermInjective := by + refine fun x ↦ ⟨⟨(X.affineCover.map x).opensRange, X.affineCover.covers x, + (isAffineOpen_opensRange (X.affineCover.map x)), ?_⟩⟩ + have : Nonempty (X.affineCover.map x).opensRange := ⟨⟨_, X.affineCover.covers x⟩⟩ + have := (isAffineOpen_opensRange (X.affineCover.map x)).isLocalization_stalk + ⟨_, X.affineCover.covers x⟩ + exact @IsLocalization.injective _ _ _ _ _ (show _ from _) this + (Ideal.primeCompl_le_nonZeroDivisors _) + +instance (priority := 100) [IsLocallyNoetherian X] : X.IsGermInjective := by + suffices ∀ (R : CommRingCat.{u}) (_ : IsNoetherianRing R), (Spec R).IsGermInjective by + refine @Scheme.IsGermInjective.of_openCover _ (X.affineOpenCover.openCover) (fun i ↦ this _ ?_) + have := isLocallyNoetherian_of_isOpenImmersion (X.affineOpenCover.map i) + infer_instance + refine fun R hR ↦ Scheme.IsGermInjective.Spec fun I hI ↦ ?_ + let J := RingHom.ker <| algebraMap R (Localization.AtPrime I) + have hJ (x) : x ∈ J ↔ ∃ y : I.primeCompl, y * x = 0 := + IsLocalization.map_eq_zero_iff I.primeCompl _ x + choose f hf using fun x ↦ (hJ x).mp + obtain ⟨s, hs⟩ := (isNoetherianRing_iff_ideal_fg R).mp ‹_› J + have hs' : (s : Set R) ⊆ J := hs ▸ Ideal.subset_span + refine ⟨_, (s.attach.prod fun x ↦ f x (hs' x.2)).2, fun x y e hy ↦ ⟨1, ?_⟩⟩ + rw [pow_one, mul_comm, ← smul_eq_mul, ← Submodule.mem_annihilator_span_singleton] + refine SetLike.le_def.mp ?_ ((hJ x).mpr ⟨⟨y, hy⟩, e⟩) + rw [← hs, Ideal.span_le] + intro i hi + rw [SetLike.mem_coe, Submodule.mem_annihilator_span_singleton, smul_eq_mul, + mul_comm, ← smul_eq_mul, ← Submodule.mem_annihilator_span_singleton, Submonoid.coe_finset_prod] + refine Ideal.mem_of_dvd _ (Finset.dvd_prod_of_mem _ (s.mem_attach ⟨i, hi⟩)) ?_ + rw [Submodule.mem_annihilator_span_singleton, smul_eq_mul] + exact hf i _ + +/-- +Let `x : X` and `f g : X ⟶ Y` be two morphisms such that `f x = g x`. +If `f` and `g` agree on the stalk of `x`, then they agree on an open neighborhood of `x`, +provided `X` is "germ-injective" at `x` (e.g. when it's integral or locally noetherian). + +TODO: The condition on `X` is unnecessary when `Y` is locally of finite type. +-/ +@[stacks 0BX6] +lemma spread_out_unique_of_isGermInjective {x : X} [X.IsGermInjectiveAt x] + (f g : X ⟶ Y) (e : f.base x = g.base x) + (H : f.stalkMap x = + Y.presheaf.stalkSpecializes (Inseparable.of_eq e.symm).specializes ≫ g.stalkMap x) : + ∃ (U : X.Opens), x ∈ U ∧ U.ι ≫ f = U.ι ≫ g := by + obtain ⟨_, ⟨V : Y.Opens, hV, rfl⟩, hxV, -⟩ := + (isBasis_affine_open Y).exists_subset_of_mem_open (Set.mem_univ (f.base x)) isOpen_univ + have hxV' : g.base x ∈ V := e ▸ hxV + obtain ⟨U, hxU, _, hUV, HU⟩ := X.exists_le_and_germ_injective x (f ⁻¹ᵁ V ⊓ g ⁻¹ᵁ V) ⟨hxV, hxV'⟩ + refine ⟨U, hxU, ?_⟩ + rw [← Scheme.Hom.resLE_comp_ι _ (hUV.trans inf_le_left), + ← Scheme.Hom.resLE_comp_ι _ (hUV.trans inf_le_right)] + congr 1 + have : IsAffine V := hV + suffices ∀ (U₀ V₀) (eU : U = U₀) (eV : V = V₀), + f.appLE V₀ U₀ (eU ▸ eV ▸ hUV.trans inf_le_left) = + g.appLE V₀ U₀ (eU ▸ eV ▸ hUV.trans inf_le_right) by + rw [← cancel_mono V.toScheme.isoSpec.hom] + simp only [Scheme.isoSpec, asIso_hom, Scheme.toSpecΓ_naturality, + Scheme.Hom.app_eq_appLE, Scheme.Hom.resLE_appLE] + congr 2 + apply this <;> simp + rintro U V rfl rfl + have := ConcreteCategory.mono_of_injective _ HU + rw [← cancel_mono (X.presheaf.germ U x hxU)] + simp only [Scheme.Hom.appLE, Category.assoc, X.presheaf.germ_res', ← Scheme.stalkMap_germ, H] + simp only [TopCat.Presheaf.germ_stalkSpecializes_assoc, Scheme.stalkMap_germ] + +/-- +A variant of `spread_out_unique_of_isGermInjective` +whose condition is an equality of scheme morphisms instead of ring homomorphisms. +-/ +lemma spread_out_unique_of_isGermInjective' {x : X} [X.IsGermInjectiveAt x] + (f g : X ⟶ Y) + (e : X.fromSpecStalk x ≫ f = X.fromSpecStalk x ≫ g) : + ∃ (U : X.Opens), x ∈ U ∧ U.ι ≫ f = U.ι ≫ g := by + fapply spread_out_unique_of_isGermInjective + · simpa using congr(($e).base (LocalRing.closedPoint _)) + · apply Spec.map_injective + rw [← cancel_mono (Y.fromSpecStalk _)] + simpa [Scheme.Spec_map_stalkSpecializes_fromSpecStalk] + +lemma exists_lift_of_germInjective_aux {U : X.Opens} {x : X} (hxU) + (φ : A ⟶ X.presheaf.stalk x) (φRA : R ⟶ A) (φRX : R ⟶ Γ(X, U)) + (hφRA : RingHom.FiniteType φRA) + (e : φRA ≫ φ = φRX ≫ X.presheaf.germ U x hxU) : + ∃ (V : X.Opens) (hxV : x ∈ V), + V ≤ U ∧ RingHom.range φ ≤ RingHom.range (X.presheaf.germ V x hxV) := by + letI := φRA.toAlgebra + obtain ⟨s, hs⟩ := hφRA + choose W hxW f hf using fun t ↦ X.presheaf.germ_exist x (φ t) + have H : x ∈ s.inf W ⊓ U := by + rw [← SetLike.mem_coe, TopologicalSpace.Opens.coe_inf, TopologicalSpace.Opens.coe_finset_inf] + exact ⟨by simpa using fun x _ ↦ hxW x, hxU⟩ + refine ⟨s.inf W ⊓ U, H, inf_le_right, ?_⟩ + letI := φRX.toAlgebra + letI := (φRX ≫ X.presheaf.germ U x hxU).toAlgebra + letI := (φRX ≫ X.presheaf.map (homOfLE (inf_le_right (a := s.inf W))).op).toAlgebra + let φ' : A →ₐ[R] X.presheaf.stalk x := { φ with commutes' := DFunLike.congr_fun e } + let ψ : Γ(X, s.inf W ⊓ U) →ₐ[R] X.presheaf.stalk x := + { X.presheaf.germ _ x H with commutes' := fun x ↦ X.presheaf.germ_res_apply _ _ _ _ } + show AlgHom.range φ' ≤ AlgHom.range ψ + rw [← Algebra.map_top, ← hs, AlgHom.map_adjoin, Algebra.adjoin_le_iff] + rintro _ ⟨i, hi, rfl : φ i = _⟩ + refine ⟨X.presheaf.map (homOfLE (inf_le_left.trans (Finset.inf_le hi))).op (f i), ?_⟩ + exact (X.presheaf.germ_res_apply _ _ _ _).trans (hf _) + +/-- +Suppose `X` is a scheme, `x : X` such that the germ map at `x` is (locally) injective, +and `U` is a neighborhood of `x`. +Given a commutative diagram of `CommRingCat` +``` +R ⟶ Γ(X, U) +↓ ↓ +A ⟶ 𝒪_{X, x} +``` +such that `R` is of finite type over `A`, we may lift `A ⟶ 𝒪_{X, x}` to some `A ⟶ Γ(X, V)`. +-/ +lemma exists_lift_of_germInjective {x : X} [X.IsGermInjectiveAt x] {U : X.Opens} (hxU : x ∈ U) + (φ : A ⟶ X.presheaf.stalk x) (φRA : R ⟶ A) (φRX : R ⟶ Γ(X, U)) + (hφRA : RingHom.FiniteType φRA) + (e : φRA ≫ φ = φRX ≫ X.presheaf.germ U x hxU) : + ∃ (V : X.Opens) (hxV : x ∈ V) (φ' : A ⟶ Γ(X, V)) (i : V ≤ U), IsAffineOpen V ∧ + φ = φ' ≫ X.presheaf.germ V x hxV ∧ φRX ≫ X.presheaf.map i.hom.op = φRA ≫ φ' := by + obtain ⟨V, hxV, iVU, hV⟩ := exists_lift_of_germInjective_aux hxU φ φRA φRX hφRA e + obtain ⟨V', hxV', hV', iV'V, H⟩ := X.exists_le_and_germ_injective x V hxV + let f := X.presheaf.germ V' x hxV' + have hf' : RingHom.range (X.presheaf.germ V x hxV) ≤ RingHom.range f := by + rw [← X.presheaf.germ_res iV'V.hom _ hxV'] + exact Set.range_comp_subset_range (X.presheaf.map iV'V.hom.op) f + let e := RingEquiv.ofLeftInverse H.hasLeftInverse.choose_spec + refine ⟨V', hxV', CommRingCat.ofHom (e.symm.toRingHom.comp + (φ.codRestrict _ (fun x ↦ hf' (hV ⟨x, rfl⟩)))), iV'V.trans iVU, hV', ?_, ?_⟩ + · ext a + show φ a = (e (e.symm _)).1 + simp only [RingEquiv.apply_symm_apply] + rfl + · ext a + apply e.injective + show e _ = e (e.symm _) + rw [RingEquiv.apply_symm_apply] + ext + show X.presheaf.germ _ _ _ (X.presheaf.map _ _) = (φRA ≫ φ) a + rw [X.presheaf.germ_res_apply, ‹φRA ≫ φ = _›] + rfl + +/-- +Given `S`-schemes `X Y` and points `x : X` `y : Y` over `s : S`. +Suppose we have the following diagram of `S`-schemes +``` +Spec 𝒪_{X, x} ⟶ X + | + Spec(φ) + ↓ +Spec 𝒪_{Y, y} ⟶ Y +``` +Then the map `Spec(φ)` spreads out to an `S`-morphism on an open subscheme `U ⊆ X`, +``` +Spec 𝒪_{X, x} ⟶ U ⊆ X + | | + Spec(φ) | + ↓ ↓ +Spec 𝒪_{Y, y} ⟶ Y +``` +provided that `Y` is locally of finite type over `S` and +`X` is "germ-injective" at `x` (e.g. when it's integral or locally noetherian). + +TODO: The condition on `X` is unnecessary when `Y` is locally of finite presentation. +-/ +@[stacks 0BX6] +lemma spread_out_of_isGermInjective [LocallyOfFiniteType sY] {x : X} [X.IsGermInjectiveAt x] {y : Y} + (e : sX.base x = sY.base y) (φ : Y.presheaf.stalk y ⟶ X.presheaf.stalk x) + (h : sY.stalkMap y ≫ φ = + S.presheaf.stalkSpecializes (Inseparable.of_eq e).specializes ≫ sX.stalkMap x) : + ∃ (U : X.Opens) (hxU : x ∈ U) (f : U.toScheme ⟶ Y), + Spec.map φ ≫ Y.fromSpecStalk y = U.fromSpecStalkOfMem x hxU ≫ f ∧ + f ≫ sY = U.ι ≫ sX := by + obtain ⟨_, ⟨U, hU, rfl⟩, hxU, -⟩ := + (isBasis_affine_open S).exists_subset_of_mem_open (Set.mem_univ (sX.base x)) isOpen_univ + have hyU : sY.base y ∈ U := e ▸ hxU + obtain ⟨_, ⟨V : Y.Opens, hV, rfl⟩, hyV, iVU⟩ := + (isBasis_affine_open Y).exists_subset_of_mem_open hyU (sY ⁻¹ᵁ U).2 + have : sY.appLE U V iVU ≫ Y.presheaf.germ V y hyV ≫ φ = + sX.app U ≫ X.presheaf.germ (sX ⁻¹ᵁ U) x hxU := by + rw [Scheme.Hom.appLE, Category.assoc, Y.presheaf.germ_res_assoc, + ← Scheme.stalkMap_germ_assoc, h] + simp + obtain ⟨W, hxW, φ', i, hW, h₁, h₂⟩ := + exists_lift_of_germInjective (R := Γ(S, U)) (A := Γ(Y, V)) (U := sX ⁻¹ᵁ U) (x := x) hxU + (Y.presheaf.germ _ y hyV ≫ φ) (sY.appLE U V iVU) (sX.app U) + (LocallyOfFiniteType.finiteType_of_affine_subset ⟨_, hU⟩ ⟨_, hV⟩ _) this + refine ⟨W, hxW, W.toSpecΓ ≫ Spec.map φ' ≫ hV.fromSpec, ?_, ?_⟩ + · rw [W.fromSpecStalkOfMem_toSpecΓ_assoc x hxW, ← Spec.map_comp_assoc, ← h₁, + Spec.map_comp, Category.assoc, ← IsAffineOpen.fromSpecStalk, + IsAffineOpen.fromSpecStalk_eq_fromSpecStalk] + · simp only [Category.assoc, IsAffineOpen.isoSpec_inv_ι_assoc] + rw [← IsAffineOpen.Spec_map_appLE_fromSpec sY hU hV iVU, ← Spec.map_comp_assoc, ← h₂, + ← Scheme.Hom.appLE, ← hW.isoSpec_hom, IsAffineOpen.Spec_map_appLE_fromSpec sX hU hW i, + ← Iso.eq_inv_comp, IsAffineOpen.isoSpec_inv_ι_assoc] + +/-- +Given `S`-schemes `X Y`, a point `x : X`, and a `S`-morphism `φ : Spec 𝒪_{X, x} ⟶ Y`, +we may spread it out to an `S`-morphism `f : U ⟶ Y` +provided that `Y` is locally of finite type over `S` and +`X` is "germ-injective" at `x` (e.g. when it's integral or locally noetherian). + +TODO: The condition on `X` is unnecessary when `Y` is locally of finite presentation. +-/ +lemma spread_out_of_isGermInjective' [LocallyOfFiniteType sY] {x : X} [X.IsGermInjectiveAt x] + (φ : Spec (X.presheaf.stalk x) ⟶ Y) + (h : φ ≫ sY = X.fromSpecStalk x ≫ sX) : + ∃ (U : X.Opens) (hxU : x ∈ U) (f : U.toScheme ⟶ Y), + φ = U.fromSpecStalkOfMem x hxU ≫ f ∧ f ≫ sY = U.ι ≫ sX := by + have := spread_out_of_isGermInjective sX sY ?_ (Scheme.stalkClosedPointTo φ) ?_ + · simpa only [Scheme.Spec_stalkClosedPointTo_fromSpecStalk] using this + · rw [← Scheme.comp_base_apply, h, Scheme.comp_base_apply, Scheme.fromSpecStalk_closedPoint] + · apply Spec.map_injective + rw [← cancel_mono (S.fromSpecStalk _)] + simpa only [Spec.map_comp, Category.assoc, Scheme.Spec_map_stalkMap_fromSpecStalk, + Scheme.Spec_stalkClosedPointTo_fromSpecStalk_assoc, + Scheme.Spec_map_stalkSpecializes_fromSpecStalk] + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Stalk.lean b/Mathlib/AlgebraicGeometry/Stalk.lean index f1b9f8a1215c8..2b8464b6a9804 100644 --- a/Mathlib/AlgebraicGeometry/Stalk.lean +++ b/Mathlib/AlgebraicGeometry/Stalk.lean @@ -4,18 +4,30 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang, Fangming Li -/ import Mathlib.AlgebraicGeometry.AffineScheme +import Mathlib.AlgebraicGeometry.Morphisms.Preimmersion /-! # Stalks of a Scheme -Given a scheme `X` and a point `x : X`, `AlgebraicGeometry.Scheme.fromSpecStalk X x` is the -canonical scheme morphism from `Spec(O_x)` to `X`. This is helpful for constructing the canonical -map from the spectrum of the residue field of a point to the original scheme. +## Main definitions and results + +- `AlgebraicGeometry.Scheme.fromSpecStalk`: The canonical morphism `Spec 𝒪_{X, x} ⟶ X`. +- `AlgebraicGeometry.Scheme.range_fromSpecStalk`: The range of the map `Spec 𝒪_{X, x} ⟶ X` is + exactly the `y`s that specialize to `x`. +- `AlgebraicGeometry.SpecToEquivOfLocalRing`: + Given a local ring `R` and scheme `X`, morphisms `Spec R ⟶ X` corresponds to pairs + `(x, f)` where `x : X` and `f : 𝒪_{X, x} ⟶ R` is a local ring homomorphism. -/ namespace AlgebraicGeometry -open CategoryTheory Opposite TopologicalSpace +open CategoryTheory Opposite TopologicalSpace LocalRing + +universe u + +variable {X Y : Scheme.{u}} (f : X ⟶ Y) {U V : X.Opens} (hU : IsAffineOpen U) (hV : IsAffineOpen V) + +section fromSpecStalk /-- A morphism from `Spec(O_x)` to `X`, which is defined with the help of an affine open @@ -24,26 +36,25 @@ neighborhood `U` of `x`. noncomputable def IsAffineOpen.fromSpecStalk {X : Scheme} {U : X.Opens} (hU : IsAffineOpen U) {x : X} (hxU : x ∈ U) : Spec (X.presheaf.stalk x) ⟶ X := - Spec.map (X.presheaf.germ ⟨x, hxU⟩) ≫ hU.fromSpec + Spec.map (X.presheaf.germ _ x hxU) ≫ hU.fromSpec /-- The morphism from `Spec(O_x)` to `X` given by `IsAffineOpen.fromSpec` does not depend on the affine open neighborhood of `x` we choose. -/ -theorem IsAffineOpen.fromSpecStalk_eq {X : Scheme} (x : X) {U V : X.Opens} - (hU : IsAffineOpen U) (hV : IsAffineOpen V) (hxU : x ∈ U) (hxV : x ∈ V) : +theorem IsAffineOpen.fromSpecStalk_eq (x : X) (hxU : x ∈ U) (hxV : x ∈ V) : hU.fromSpecStalk hxU = hV.fromSpecStalk hxV := by obtain ⟨U', h₁, h₂, h₃ : U' ≤ U ⊓ V⟩ := Opens.isBasis_iff_nbhd.mp (isBasis_affine_open X) (show x ∈ U ⊓ V from ⟨hxU, hxV⟩) transitivity fromSpecStalk h₁ h₂ · delta fromSpecStalk rw [← hU.map_fromSpec h₁ (homOfLE <| h₃.trans inf_le_left).op] - erw [← Scheme.Spec_map (X.presheaf.map _).op, ← Scheme.Spec_map (X.presheaf.germ ⟨x, h₂⟩).op] + erw [← Scheme.Spec_map (X.presheaf.map _).op, ← Scheme.Spec_map (X.presheaf.germ _ x h₂).op] rw [← Functor.map_comp_assoc, ← op_comp, TopCat.Presheaf.germ_res, Scheme.Spec_map, Quiver.Hom.unop_op] · delta fromSpecStalk rw [← hV.map_fromSpec h₁ (homOfLE <| h₃.trans inf_le_right).op] - erw [← Scheme.Spec_map (X.presheaf.map _).op, ← Scheme.Spec_map (X.presheaf.germ ⟨x, h₂⟩).op] + erw [← Scheme.Spec_map (X.presheaf.map _).op, ← Scheme.Spec_map (X.presheaf.germ _ x h₂).op] rw [← Functor.map_comp_assoc, ← op_comp, TopCat.Presheaf.germ_res, Scheme.Spec_map, Quiver.Hom.unop_op] @@ -51,12 +62,294 @@ theorem IsAffineOpen.fromSpecStalk_eq {X : Scheme} (x : X) {U V : X.Opens} If `x` is a point of `X`, this is the canonical morphism from `Spec(O_x)` to `X`. -/ noncomputable def Scheme.fromSpecStalk (X : Scheme) (x : X) : - Scheme.Spec.obj (op (X.presheaf.stalk x)) ⟶ X := + Spec (X.presheaf.stalk x) ⟶ X := (isAffineOpen_opensRange (X.affineOpenCover.map x)).fromSpecStalk (X.affineOpenCover.covers x) @[simp] -theorem IsAffineOpen.fromSpecStalk_eq_fromSpecStalk - {X : Scheme} {U : X.Opens} (hU : IsAffineOpen U) {x : X} (hxU : x ∈ U) : +theorem IsAffineOpen.fromSpecStalk_eq_fromSpecStalk {x : X} (hxU : x ∈ U) : hU.fromSpecStalk hxU = X.fromSpecStalk x := fromSpecStalk_eq .. +instance IsAffineOpen.fromSpecStalk_isPreimmersion {X : Scheme.{u}} {U : Opens X} + (hU : IsAffineOpen U) (x : X) (hx : x ∈ U) : IsPreimmersion (hU.fromSpecStalk hx) := by + dsimp [IsAffineOpen.fromSpecStalk] + haveI : IsPreimmersion (Spec.map (X.presheaf.germ U x hx)) := + letI : Algebra Γ(X, U) (X.presheaf.stalk x) := (X.presheaf.germ U x hx).toAlgebra + haveI := hU.isLocalization_stalk ⟨x, hx⟩ + IsPreimmersion.of_isLocalization (R := Γ(X, U)) (S := X.presheaf.stalk x) + (hU.primeIdealOf ⟨x, hx⟩).asIdeal.primeCompl + apply IsPreimmersion.comp + +instance {X : Scheme.{u}} (x : X) : IsPreimmersion (X.fromSpecStalk x) := + IsAffineOpen.fromSpecStalk_isPreimmersion _ _ _ + +lemma IsAffineOpen.fromSpecStalk_closedPoint {U : Opens X} (hU : IsAffineOpen U) + {x : X} (hxU : x ∈ U) : + (hU.fromSpecStalk hxU).base (closedPoint (X.presheaf.stalk x)) = x := by + rw [IsAffineOpen.fromSpecStalk, Scheme.comp_base_apply] + rw [← hU.primeIdealOf_eq_map_closedPoint ⟨x, hxU⟩, hU.fromSpec_primeIdealOf ⟨x, hxU⟩] + +namespace Scheme + +@[simp] +lemma fromSpecStalk_closedPoint {x : X} : + (X.fromSpecStalk x).base (closedPoint (X.presheaf.stalk x)) = x := + IsAffineOpen.fromSpecStalk_closedPoint _ _ + +lemma fromSpecStalk_app {x : X} (hxU : x ∈ U) : + (X.fromSpecStalk x).app U = + X.presheaf.germ U x hxU ≫ + (ΓSpecIso (X.presheaf.stalk x)).inv ≫ + (Spec (X.presheaf.stalk x)).presheaf.map (homOfLE le_top).op := by + obtain ⟨_, ⟨V : X.Opens, hV, rfl⟩, hxV, hVU⟩ := (isBasis_affine_open X).exists_subset_of_mem_open + hxU U.2 + rw [← hV.fromSpecStalk_eq_fromSpecStalk hxV, IsAffineOpen.fromSpecStalk, Scheme.comp_app, + hV.fromSpec_app_of_le _ hVU, ← X.presheaf.germ_res (homOfLE hVU) x hxV] + simp [Category.assoc, ← ΓSpecIso_inv_naturality_assoc] + +@[reassoc] +lemma Spec_map_stalkSpecializes_fromSpecStalk {x y : X} (h : x ⤳ y) : + Spec.map (X.presheaf.stalkSpecializes h) ≫ X.fromSpecStalk y = X.fromSpecStalk x := by + obtain ⟨_, ⟨U, hU, rfl⟩, hyU, -⟩ := + (isBasis_affine_open X).exists_subset_of_mem_open (Set.mem_univ y) isOpen_univ + have hxU : x ∈ U := h.mem_open U.2 hyU + rw [← hU.fromSpecStalk_eq_fromSpecStalk hyU, ← hU.fromSpecStalk_eq_fromSpecStalk hxU, + IsAffineOpen.fromSpecStalk, IsAffineOpen.fromSpecStalk, ← Category.assoc, ← Spec.map_comp, + TopCat.Presheaf.germ_stalkSpecializes] + +@[reassoc (attr := simp)] +lemma Spec_map_stalkMap_fromSpecStalk {x} : + Spec.map (f.stalkMap x) ≫ Y.fromSpecStalk _ = X.fromSpecStalk x ≫ f := by + obtain ⟨_, ⟨U, hU, rfl⟩, hxU, -⟩ := (isBasis_affine_open Y).exists_subset_of_mem_open + (Set.mem_univ (f.base x)) isOpen_univ + obtain ⟨_, ⟨V, hV, rfl⟩, hxV, hVU⟩ := (isBasis_affine_open X).exists_subset_of_mem_open + hxU (f ⁻¹ᵁ U).2 + rw [← hU.fromSpecStalk_eq_fromSpecStalk hxU, ← hV.fromSpecStalk_eq_fromSpecStalk hxV, + IsAffineOpen.fromSpecStalk, ← Spec.map_comp_assoc, Scheme.stalkMap_germ f _ x hxU, + IsAffineOpen.fromSpecStalk, Spec.map_comp_assoc, ← X.presheaf.germ_res (homOfLE hVU) x hxV, + Spec.map_comp_assoc, Category.assoc, ← Spec.map_comp_assoc (f.app _), + Hom.app_eq_appLE, Hom.appLE_map, IsAffineOpen.Spec_map_appLE_fromSpec] + +lemma Spec_fromSpecStalk (R : CommRingCat) (x) : + (Spec R).fromSpecStalk x = + Spec.map ((ΓSpecIso R).inv ≫ (Spec R).presheaf.germ ⊤ x trivial) := by + rw [← (isAffineOpen_top (Spec R)).fromSpecStalk_eq_fromSpecStalk (x := x) trivial, + IsAffineOpen.fromSpecStalk, IsAffineOpen.fromSpec_top, isoSpec_Spec_inv, + ← Spec.map_comp] + +-- This is not a simp lemma to respect the abstraction boundaries +/-- A variant of `Spec_fromSpecStalk` that breaks abstraction boundaries. -/ +lemma Spec_fromSpecStalk' (R : CommRingCat) (x) : + (Spec R).fromSpecStalk x = Spec.map (StructureSheaf.toStalk R _) := + Spec_fromSpecStalk _ _ + +@[stacks 01J7] +lemma range_fromSpecStalk {x : X} : + Set.range (X.fromSpecStalk x).base = { y | y ⤳ x } := by + ext y + constructor + · rintro ⟨y, rfl⟩ + exact ((LocalRing.specializes_closedPoint y).map (X.fromSpecStalk x).base.2).trans + (specializes_of_eq fromSpecStalk_closedPoint) + · rintro (hy : y ⤳ x) + have := fromSpecStalk_closedPoint (x := y) + rw [← Spec_map_stalkSpecializes_fromSpecStalk hy] at this + exact ⟨_, this⟩ + +/-- The canonical map `Spec 𝒪_{X, x} ⟶ U` given `x ∈ U ⊆ X`. -/ +noncomputable +def Opens.fromSpecStalkOfMem {X : Scheme.{u}} (U : X.Opens) (x : X) (hxU : x ∈ U) : + Spec (X.presheaf.stalk x) ⟶ U := + Spec.map (inv (U.ι.stalkMap ⟨x, hxU⟩)) ≫ U.toScheme.fromSpecStalk ⟨x, hxU⟩ + +@[reassoc (attr := simp)] +lemma Opens.fromSpecStalkOfMem_ι {X : Scheme.{u}} (U : X.Opens) (x : X) (hxU : x ∈ U) : + U.fromSpecStalkOfMem x hxU ≫ U.ι = X.fromSpecStalk x := by + simp only [Opens.fromSpecStalkOfMem, Spec.map_inv, Category.assoc, IsIso.inv_comp_eq] + exact (Scheme.Spec_map_stalkMap_fromSpecStalk U.ι (x := ⟨x, hxU⟩)).symm + +@[reassoc] +lemma fromSpecStalk_toSpecΓ (X : Scheme.{u}) (x : X) : + X.fromSpecStalk x ≫ X.toSpecΓ = Spec.map (X.presheaf.germ ⊤ x trivial) := by + rw [Scheme.toSpecΓ_naturality, ← SpecMap_ΓSpecIso_hom, ← Spec.map_comp, + @Scheme.fromSpecStalk_app X ⊤ _ trivial] + simp + +@[reassoc (attr := simp)] +lemma Opens.fromSpecStalkOfMem_toSpecΓ {X : Scheme.{u}} (U : X.Opens) (x : X) (hxU : x ∈ U) : + U.fromSpecStalkOfMem x hxU ≫ U.toSpecΓ = Spec.map (X.presheaf.germ U x hxU) := by + rw [fromSpecStalkOfMem, Opens.toSpecΓ, Category.assoc, fromSpecStalk_toSpecΓ_assoc, + ← Spec.map_comp, ← Spec.map_comp] + congr 1 + rw [IsIso.comp_inv_eq, Iso.inv_comp_eq] + erw [stalkMap_germ U.ι U ⟨x, hxU⟩] + rw [Opens.ι_app, Opens.topIso_hom, ← Functor.map_comp_assoc] + exact (U.toScheme.presheaf.germ_res (homOfLE le_top) ⟨x, hxU⟩ (U := U.ι ⁻¹ᵁ U) hxU).symm + +end Scheme + +end fromSpecStalk + +variable (R : CommRingCat.{u}) [LocalRing R] + +section stalkClosedPointIso + +/-- For a local ring `(R, 𝔪)`, +this is the isomorphism between the stalk of `Spec R` at `𝔪` and `R`. -/ +noncomputable +def stalkClosedPointIso : + (Spec R).presheaf.stalk (closedPoint R) ≅ R := + StructureSheaf.stalkIso _ _ ≪≫ (IsLocalization.atUnits R + (closedPoint R).asIdeal.primeCompl fun _ ↦ not_not.mp).toRingEquiv.toCommRingCatIso.symm + +lemma stalkClosedPointIso_inv : + (stalkClosedPointIso R).inv = StructureSheaf.toStalk R _ := by + ext x + exact StructureSheaf.localizationToStalk_of _ _ _ + +lemma ΓSpecIso_hom_stalkClosedPointIso_inv : + (Scheme.ΓSpecIso R).hom ≫ (stalkClosedPointIso R).inv = + (Spec R).presheaf.germ ⊤ (closedPoint _) trivial := by + rw [stalkClosedPointIso_inv, ← Iso.eq_inv_comp] + rfl + +@[reassoc (attr := simp)] +lemma germ_stalkClosedPointIso_hom : + (Spec R).presheaf.germ ⊤ (closedPoint _) trivial ≫ (stalkClosedPointIso R).hom = + (Scheme.ΓSpecIso R).hom := by + rw [← ΓSpecIso_hom_stalkClosedPointIso_inv, Category.assoc, Iso.inv_hom_id, Category.comp_id] + +lemma Spec_stalkClosedPointIso : + Spec.map (stalkClosedPointIso R).inv = (Spec R).fromSpecStalk (closedPoint R) := by + rw [stalkClosedPointIso_inv, Scheme.Spec_fromSpecStalk'] + +end stalkClosedPointIso + +section stalkClosedPointTo + +variable {R} (f : Spec R ⟶ X) + +namespace Scheme + +/-- +Given a local ring `(R, 𝔪)` and a morphism `f : Spec R ⟶ X`, +they induce a (local) ring homomorphism `φ : 𝒪_{X, f 𝔪} ⟶ R`. + +This is inverse to `φ ↦ Spec.map φ ≫ X.fromSpecStalk (f 𝔪)`. See `SpecToEquivOfLocalRing`. +-/ +noncomputable +def stalkClosedPointTo : + X.presheaf.stalk (f.base (closedPoint R)) ⟶ R := + f.stalkMap (closedPoint R) ≫ (stalkClosedPointIso R).hom + +instance isLocalHom_stalkClosedPointTo : + IsLocalHom (stalkClosedPointTo f) := + inferInstanceAs <| IsLocalHom (f.stalkMap (closedPoint R) ≫ (stalkClosedPointIso R).hom) + +lemma preimage_eq_top_of_closedPoint_mem + {U : Opens X} (hU : f.base (closedPoint R) ∈ U) : f ⁻¹ᵁ U = ⊤ := + LocalRing.closed_point_mem_iff.mp hU + +lemma stalkClosedPointTo_comp (g : X ⟶ Y) : + stalkClosedPointTo (f ≫ g) = g.stalkMap _ ≫ stalkClosedPointTo f := by + rw [stalkClosedPointTo, Scheme.stalkMap_comp] + exact Category.assoc _ _ _ + +lemma germ_stalkClosedPointTo_Spec {R S : CommRingCat} [LocalRing S] (φ : R ⟶ S): + (Spec R).presheaf.germ ⊤ _ trivial ≫ stalkClosedPointTo (Spec.map φ) = + (ΓSpecIso R).hom ≫ φ := by + rw [stalkClosedPointTo, Scheme.stalkMap_germ_assoc, ← Iso.inv_comp_eq, + ← ΓSpecIso_inv_naturality_assoc] + simp_rw [Opens.map_top] + rw [germ_stalkClosedPointIso_hom, Iso.inv_hom_id, Category.comp_id] + +@[reassoc] +lemma germ_stalkClosedPointTo (U : Opens X) (hU : f.base (closedPoint R) ∈ U) : + X.presheaf.germ U _ hU ≫ stalkClosedPointTo f = f.app U ≫ + ((Spec R).presheaf.mapIso (eqToIso (preimage_eq_top_of_closedPoint_mem f hU).symm).op ≪≫ + ΓSpecIso R).hom := by + rw [stalkClosedPointTo, Scheme.stalkMap_germ_assoc, Iso.trans_hom] + congr 1 + rw [← Iso.eq_comp_inv, Category.assoc, ΓSpecIso_hom_stalkClosedPointIso_inv] + simp only [TopCat.Presheaf.pushforward_obj_obj, Functor.mapIso_hom, Iso.op_hom, eqToIso.hom, + TopCat.Presheaf.germ_res] + +@[reassoc] +lemma germ_stalkClosedPointTo_Spec_fromSpecStalk + {x : X} (f : X.presheaf.stalk x ⟶ R) [IsLocalHom f] (U : Opens X) (hU) : + X.presheaf.germ U _ hU ≫ stalkClosedPointTo (Spec.map f ≫ X.fromSpecStalk x) = + X.presheaf.germ U x (by simpa using hU) ≫ f := by + have : (Spec.map f ≫ X.fromSpecStalk x).base (closedPoint R) = x := by + rw [comp_base_apply, Spec_closedPoint, fromSpecStalk_closedPoint] + have : x ∈ U := this ▸ hU + simp only [TopCat.Presheaf.stalkCongr_hom, TopCat.Presheaf.germ_stalkSpecializes_assoc, + germ_stalkClosedPointTo, comp_app, + fromSpecStalk_app (X := X) (x := x) this, Category.assoc, Iso.trans_hom, + Functor.mapIso_hom, Hom.naturality_assoc, ← Functor.map_comp_assoc, + (Spec.map f).app_eq_appLE, Hom.appLE_map_assoc, Hom.map_appLE_assoc] + simp_rw [← Opens.map_top (Spec.map f).base] + rw [← (Spec.map f).app_eq_appLE, ΓSpecIso_naturality, Iso.inv_hom_id_assoc] + +lemma stalkClosedPointTo_fromSpecStalk (x : X) : + stalkClosedPointTo (X.fromSpecStalk x) = + (X.presheaf.stalkCongr (by rw [fromSpecStalk_closedPoint]; rfl)).hom := by + refine TopCat.Presheaf.stalk_hom_ext _ fun U hxU ↦ ?_ + simp only [TopCat.Presheaf.stalkCongr_hom, TopCat.Presheaf.germ_stalkSpecializes, id_eq] + have : X.fromSpecStalk x = Spec.map (𝟙 (X.presheaf.stalk x)) ≫ X.fromSpecStalk x := by simp + convert germ_stalkClosedPointTo_Spec_fromSpecStalk (𝟙 (X.presheaf.stalk x)) U hxU + +@[reassoc] +lemma Spec_stalkClosedPointTo_fromSpecStalk : + Spec.map (stalkClosedPointTo f) ≫ X.fromSpecStalk _ = f := by + obtain ⟨_, ⟨U, hU, rfl⟩, hxU, -⟩ := (isBasis_affine_open X).exists_subset_of_mem_open + (Set.mem_univ (f.base (closedPoint R))) isOpen_univ + have := IsAffineOpen.Spec_map_appLE_fromSpec f hU (isAffineOpen_top _) + (preimage_eq_top_of_closedPoint_mem f hxU).ge + rw [IsAffineOpen.fromSpec_top, Iso.eq_inv_comp, isoSpec_Spec_hom] at this + rw [← hU.fromSpecStalk_eq_fromSpecStalk hxU, IsAffineOpen.fromSpecStalk, ← Spec.map_comp_assoc, + germ_stalkClosedPointTo] + simpa only [Iso.trans_hom, Functor.mapIso_hom, Iso.op_hom, Category.assoc, + Hom.app_eq_appLE, Hom.appLE_map_assoc, Spec.map_comp_assoc] + +end Scheme + +end stalkClosedPointTo + +variable {R} + +omit [LocalRing R] in +/-- useful lemma for applications of `SpecToEquivOfLocalRing` -/ +lemma SpecToEquivOfLocalRing_eq_iff + {f₁ f₂ : Σ x, { f : X.presheaf.stalk x ⟶ R // IsLocalHom f }} : + f₁ = f₂ ↔ ∃ h₁ : f₁.1 = f₂.1, f₁.2.1 = + (X.presheaf.stalkCongr (by rw [h₁]; rfl)).hom ≫ f₂.2.1 := by + constructor + · rintro rfl; simp + · obtain ⟨x₁, ⟨f₁, h₁⟩⟩ := f₁ + obtain ⟨x₂, ⟨f₂, h₂⟩⟩ := f₂ + rintro ⟨rfl : x₁ = x₂, e : f₁ = _⟩ + simp [e] + +variable (X R) + +/-- +Given a local ring `R` and scheme `X`, morphisms `Spec R ⟶ X` corresponds to pairs +`(x, f)` where `x : X` and `f : 𝒪_{X, x} ⟶ R` is a local ring homomorphism. +-/ +@[simps] +noncomputable +def SpecToEquivOfLocalRing : + (Spec R ⟶ X) ≃ Σ x, { f : X.presheaf.stalk x ⟶ R // IsLocalHom f } where + toFun f := ⟨f.base (closedPoint R), Scheme.stalkClosedPointTo f, inferInstance⟩ + invFun xf := Spec.map xf.2.1 ≫ X.fromSpecStalk xf.1 + left_inv := Scheme.Spec_stalkClosedPointTo_fromSpecStalk + right_inv xf := by + obtain ⟨x, ⟨f, hf⟩⟩ := xf + symm + refine SpecToEquivOfLocalRing_eq_iff.mpr ⟨?_, ?_⟩ + · simp only [Scheme.comp_coeBase, TopCat.coe_comp, Function.comp_apply, Spec_closedPoint, + Scheme.fromSpecStalk_closedPoint] + · refine TopCat.Presheaf.stalk_hom_ext _ fun U hxU ↦ ?_ + simp only [Scheme.germ_stalkClosedPointTo_Spec_fromSpecStalk, + TopCat.Presheaf.stalkCongr_hom, TopCat.Presheaf.germ_stalkSpecializes_assoc] + end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/StructureSheaf.lean b/Mathlib/AlgebraicGeometry/StructureSheaf.lean index 6d18e0fcb5c9f..6d0abf3ae594a 100644 --- a/Mathlib/AlgebraicGeometry/StructureSheaf.lean +++ b/Mathlib/AlgebraicGeometry/StructureSheaf.lean @@ -117,7 +117,7 @@ variable (R) in the sense that if it holds on `U` it holds on any open subset `V` of `U`. -/ def isFractionPrelocal : PrelocalPredicate (Localizations R) where - pred {U} f := IsFraction f + pred {_} f := IsFraction f res := by rintro V U i f ⟨r, s, w⟩; exact ⟨r, s, fun x => w (i x)⟩ /-- We will define the structure sheaf as @@ -174,7 +174,7 @@ def sectionsSubring (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) : fconstructor · intro H; cases y.1.isPrime.mem_or_mem H <;> contradiction · simp only [add_mul, RingHom.map_add, Pi.add_apply, RingHom.map_mul] - erw [← wa, ← wb] + rw [← wa, ← wb] simp only [mul_assoc] congr 2 rw [mul_comm] @@ -187,7 +187,7 @@ def sectionsSubring (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) : fconstructor · exact nm · simp only [RingHom.map_neg, Pi.neg_apply] - erw [← w] + rw [← w] simp only [neg_mul] mul_mem' := by intro a b ha hb x @@ -200,7 +200,7 @@ def sectionsSubring (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) : fconstructor · intro H; cases y.1.isPrime.mem_or_mem H <;> contradiction · simp only [Pi.mul_apply, RingHom.map_mul] - erw [← wa, ← wb] + rw [← wa, ← wb] simp only [mul_left_comm, mul_assoc, mul_comm] end StructureSheaf @@ -225,12 +225,12 @@ structure presheaf. @[simps] def structurePresheafInCommRing : Presheaf CommRingCat (PrimeSpectrum.Top R) where obj U := CommRingCat.of ((structureSheafInType R).1.obj U) - map {U V} i := + map {_ _} i := { toFun := (structureSheafInType R).1.map i map_zero' := rfl - map_add' := fun x y => rfl + map_add' := fun _ _ => rfl map_one' := rfl - map_mul' := fun x y => rfl } + map_mul' := fun _ _ => rfl } -- These lemmas have always been bad (#7657), but leanprover/lean4#2644 made `simp` start noticing attribute [nolint simpNF] AlgebraicGeometry.structurePresheafInCommRing_map_apply @@ -240,7 +240,7 @@ with the `Type` valued structure presheaf. -/ def structurePresheafCompForget : structurePresheafInCommRing R ⋙ forget CommRingCat ≅ (structureSheafInType R).1 := - NatIso.ofComponents fun U => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ open TopCat.Presheaf @@ -300,7 +300,8 @@ def const (f g : R) (U : Opens (PrimeSpectrum.Top R)) @[simp] theorem const_apply (f g : R) (U : Opens (PrimeSpectrum.Top R)) (hu : ∀ x ∈ U, g ∈ (x : PrimeSpectrum.Top R).asIdeal.primeCompl) (x : U) : - (const R f g U hu).1 x = IsLocalization.mk' _ f ⟨g, hu x x.2⟩ := + (const R f g U hu).1 x = + IsLocalization.mk' (Localization.AtPrime x.1.asIdeal) f ⟨g, hu x x.2⟩ := rfl theorem const_apply' (f g : R) (U : Opens (PrimeSpectrum.Top R)) @@ -377,13 +378,13 @@ a section of the structure sheaf. -/ def toOpen (U : Opens (PrimeSpectrum.Top R)) : CommRingCat.of R ⟶ (structureSheaf R).1.obj (op U) where toFun f := - ⟨fun x => algebraMap R _ f, fun x => + ⟨fun _ => algebraMap R _ f, fun x => ⟨U, x.2, 𝟙 _, f, 1, fun y => ⟨(Ideal.ne_top_iff_one _).1 y.1.2.1, by rw [RingHom.map_one, mul_one]⟩⟩⟩ - map_one' := Subtype.eq <| funext fun x => RingHom.map_one _ - map_mul' f g := Subtype.eq <| funext fun x => RingHom.map_mul _ _ _ - map_zero' := Subtype.eq <| funext fun x => RingHom.map_zero _ - map_add' f g := Subtype.eq <| funext fun x => RingHom.map_add _ _ _ + map_one' := Subtype.eq <| funext fun _ => RingHom.map_one _ + map_mul' _ _ := Subtype.eq <| funext fun _ => RingHom.map_mul _ _ _ + map_zero' := Subtype.eq <| funext fun _ => RingHom.map_zero _ + map_add' _ _ := Subtype.eq <| funext fun _ => RingHom.map_add _ _ _ @[simp] theorem toOpen_res (U V : Opens (PrimeSpectrum.Top R)) (i : V ⟶ U) : @@ -402,30 +403,32 @@ theorem toOpen_eq_const (U : Opens (PrimeSpectrum.Top R)) (f : R) : /-- The canonical ring homomorphism interpreting an element of `R` as an element of the stalk of `structureSheaf R` at `x`. -/ def toStalk (x : PrimeSpectrum.Top R) : CommRingCat.of R ⟶ (structureSheaf R).presheaf.stalk x := - (toOpen R ⊤ ≫ (structureSheaf R).presheaf.germ ⟨x, by trivial⟩) + (toOpen R ⊤ ≫ (structureSheaf R).presheaf.germ _ x (by trivial)) @[simp] -theorem toOpen_germ (U : Opens (PrimeSpectrum.Top R)) (x : U) : - toOpen R U ≫ (structureSheaf R).presheaf.germ x = toStalk R x := by +theorem toOpen_germ (U : Opens (PrimeSpectrum.Top R)) (x : PrimeSpectrum.Top R) (hx : x ∈ U) : + toOpen R U ≫ (structureSheaf R).presheaf.germ U x hx = toStalk R x := by rw [← toOpen_res R ⊤ U (homOfLE le_top : U ⟶ ⊤), Category.assoc, Presheaf.germ_res]; rfl @[simp] -theorem germ_toOpen (U : Opens (PrimeSpectrum.Top R)) (x : U) (f : R) : - (structureSheaf R).presheaf.germ x (toOpen R U f) = toStalk R x f := by rw [← toOpen_germ]; rfl +theorem germ_toOpen + (U : Opens (PrimeSpectrum.Top R)) (x : PrimeSpectrum.Top R) (hx : x ∈ U) (f : R) : + (structureSheaf R).presheaf.germ U x hx (toOpen R U f) = toStalk R x f := by + rw [← toOpen_germ]; rfl -theorem germ_to_top (x : PrimeSpectrum.Top R) (f : R) : - (structureSheaf R).presheaf.germ (⟨x, trivial⟩ : (⊤ : Opens (PrimeSpectrum.Top R))) - (toOpen R ⊤ f) = - toStalk R x f := +theorem toOpen_Γgerm_apply (x : PrimeSpectrum.Top R) (f : R) : + (structureSheaf R).presheaf.Γgerm x (toOpen R ⊤ f) = toStalk R x f := rfl +@[deprecated (since := "2024-07-30")] alias germ_to_top := toOpen_Γgerm_apply + theorem isUnit_to_basicOpen_self (f : R) : IsUnit (toOpen R (PrimeSpectrum.basicOpen f) f) := isUnit_of_mul_eq_one _ (const R 1 f (PrimeSpectrum.basicOpen f) fun _ => id) <| by rw [toOpen_eq_const, const_mul_rev] theorem isUnit_toStalk (x : PrimeSpectrum.Top R) (f : x.asIdeal.primeCompl) : IsUnit (toStalk R x (f : R)) := by - erw [← germ_toOpen R (PrimeSpectrum.basicOpen (f : R)) ⟨x, f.2⟩ (f : R)] + rw [← germ_toOpen R (PrimeSpectrum.basicOpen (f : R)) x f.2 (f : R)] exact RingHom.isUnit_map _ (isUnit_to_basicOpen_self R f) /-- The canonical ring homomorphism from the localization of `R` at `p` to the stalk @@ -442,11 +445,11 @@ theorem localizationToStalk_of (x : PrimeSpectrum.Top R) (f : R) : @[simp] theorem localizationToStalk_mk' (x : PrimeSpectrum.Top R) (f : R) (s : x.asIdeal.primeCompl) : localizationToStalk R x (IsLocalization.mk' (Localization.AtPrime x.asIdeal) f s) = - (structureSheaf R).presheaf.germ (⟨x, s.2⟩ : PrimeSpectrum.basicOpen (s : R)) + (structureSheaf R).presheaf.germ (PrimeSpectrum.basicOpen (s : R)) x s.2 (const R f s (PrimeSpectrum.basicOpen s) fun _ => id) := (IsLocalization.lift_mk'_spec (S := Localization.AtPrime x.asIdeal) _ _ _ _).2 <| by - erw [← germ_toOpen R (PrimeSpectrum.basicOpen s) ⟨x, s.2⟩, - ← germ_toOpen R (PrimeSpectrum.basicOpen s) ⟨x, s.2⟩, ← RingHom.map_mul, toOpen_eq_const, + rw [← germ_toOpen R (PrimeSpectrum.basicOpen s) x s.2, + ← germ_toOpen R (PrimeSpectrum.basicOpen s) x s.2, ← RingHom.map_mul, toOpen_eq_const, toOpen_eq_const, const_mul_cancel'] /-- The ring homomorphism that takes a section of the structure sheaf of `R` on the open set `U`, @@ -484,27 +487,25 @@ def stalkToFiberRingHom (x : PrimeSpectrum.Top R) : openToLocalization R ((OpenNhds.inclusion _).obj (unop U)) x (unop U).2 } } @[simp] -theorem germ_comp_stalkToFiberRingHom (U : Opens (PrimeSpectrum.Top R)) (x : U) : - (structureSheaf R).presheaf.germ x ≫ stalkToFiberRingHom R x = openToLocalization R U x x.2 := +theorem germ_comp_stalkToFiberRingHom + (U : Opens (PrimeSpectrum.Top R)) (x : PrimeSpectrum.Top R) (hx : x ∈ U) : + (structureSheaf R).presheaf.germ U x hx ≫ stalkToFiberRingHom R x = + openToLocalization R U x hx := Limits.colimit.ι_desc _ _ @[simp] -theorem stalkToFiberRingHom_germ' (U : Opens (PrimeSpectrum.Top R)) (x : PrimeSpectrum.Top R) - (hx : x ∈ U) (s : (structureSheaf R).1.obj (op U)) : - stalkToFiberRingHom R x ((structureSheaf R).presheaf.germ ⟨x, hx⟩ s) = (s.1 ⟨x, hx⟩ : _) := - RingHom.ext_iff.1 (germ_comp_stalkToFiberRingHom R U ⟨x, hx⟩ : _) s +theorem stalkToFiberRingHom_germ (U : Opens (PrimeSpectrum.Top R)) + (x : PrimeSpectrum.Top R) (hx : x ∈ U) (s : (structureSheaf R).1.obj (op U)) : + stalkToFiberRingHom R x ((structureSheaf R).presheaf.germ U x hx s) = s.1 ⟨x, hx⟩ := + RingHom.ext_iff.mp (germ_comp_stalkToFiberRingHom R U x hx) s -@[simp] -theorem stalkToFiberRingHom_germ (U : Opens (PrimeSpectrum.Top R)) (x : U) - (s : (structureSheaf R).1.obj (op U)) : - stalkToFiberRingHom R x ((structureSheaf R).presheaf.germ x s) = s.1 x := by - cases x; exact stalkToFiberRingHom_germ' R U _ _ _ +@[deprecated (since := "2024-07-30")] alias stalkToFiberRingHom_germ' := stalkToFiberRingHom_germ @[simp] theorem toStalk_comp_stalkToFiberRingHom (x : PrimeSpectrum.Top R) : -- Porting note: now `algebraMap _ _` needs to be explicitly typed toStalk R x ≫ stalkToFiberRingHom R x = algebraMap R (Localization.AtPrime x.asIdeal) := by - erw [toStalk, Category.assoc, germ_comp_stalkToFiberRingHom]; rfl + rw [toStalk, Category.assoc, germ_comp_stalkToFiberRingHom]; rfl @[simp] theorem stalkToFiberRingHom_toStalk (x : PrimeSpectrum.Top R) (f : R) : @@ -521,31 +522,35 @@ def stalkIso (x : PrimeSpectrum.Top R) : inv := localizationToStalk R x hom_inv_id := by ext U hxU s - -- Note: this `simp` was longer, but the line below had to become an `erw` - simp only [Category.comp_id] - erw [comp_apply, comp_apply, stalkToFiberRingHom_germ'] + dsimp only [Category.comp_id, CommRingCat.forget_obj, + CommRingCat.coe_of, CommRingCat.comp_apply] + rw [stalkToFiberRingHom_germ] obtain ⟨V, hxV, iVU, f, g, (hg : V ≤ PrimeSpectrum.basicOpen _), hs⟩ := exists_const _ _ s x hxU - erw [← res_apply R U V iVU s ⟨x, hxV⟩, ← hs, const_apply, localizationToStalk_mk'] + rw [← res_apply R U V iVU s ⟨x, hxV⟩, ← hs, const_apply, localizationToStalk_mk'] refine (structureSheaf R).presheaf.germ_ext V hxV (homOfLE hg) iVU ?_ - dsimp - erw [← hs, res_const'] + rw [← hs, res_const'] inv_hom_id := @IsLocalization.ringHom_ext R _ x.asIdeal.primeCompl (Localization.AtPrime x.asIdeal) _ _ (Localization.AtPrime x.asIdeal) _ _ (RingHom.comp (stalkToFiberRingHom R x) (localizationToStalk R x)) (RingHom.id (Localization.AtPrime _)) <| by ext f - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - rw [RingHom.comp_apply, RingHom.comp_apply]; erw [localizationToStalk_of, - stalkToFiberRingHom_toStalk]; rw [RingHom.comp_apply, RingHom.id_apply] + rw [RingHom.comp_apply, RingHom.comp_apply, localizationToStalk_of, + stalkToFiberRingHom_toStalk, RingHom.comp_apply, RingHom.id_apply] instance (x : PrimeSpectrum R) : IsIso (stalkToFiberRingHom R x) := (stalkIso R x).isIso_hom +instance (x : PrimeSpectrum R) : IsLocalHom (stalkToFiberRingHom R x) := + isLocalHom_of_isIso _ + instance (x : PrimeSpectrum R) : IsIso (localizationToStalk R x) := (stalkIso R x).isIso_inv +instance (x : PrimeSpectrum R) : IsLocalHom (localizationToStalk R x) := + isLocalHom_of_isIso _ + @[simp, reassoc] theorem stalkToFiberRingHom_localizationToStalk (x : PrimeSpectrum.Top R) : stalkToFiberRingHom R x ≫ localizationToStalk R x = 𝟙 _ := @@ -565,10 +570,9 @@ def toBasicOpen (f : R) : @[simp] theorem toBasicOpen_mk' (s f : R) (g : Submonoid.powers s) : toBasicOpen R s (IsLocalization.mk' (Localization.Away s) f g) = - const R f g (PrimeSpectrum.basicOpen s) fun x hx => Submonoid.powers_le.2 hx g.2 := + const R f g (PrimeSpectrum.basicOpen s) fun _ hx => Submonoid.powers_le.2 hx g.2 := (IsLocalization.lift_mk'_spec _ _ _ _).2 <| by - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [toOpen_eq_const, toOpen_eq_const]; rw [const_mul_cancel'] + rw [toOpen_eq_const, toOpen_eq_const, const_mul_cancel'] @[simp] theorem localization_toBasicOpen (f : R) : @@ -609,9 +613,7 @@ theorem toBasicOpen_injective (f : R) : Function.Injective (toBasicOpen R f) := rw [PrimeSpectrum.mem_zeroLocus, Set.not_subset] have := congr_fun (congr_arg Subtype.val h_eq) ⟨p, hfp⟩ dsimp at this - -- Porting note: need to tell Lean what `S` is and need to change to `erw` - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [IsLocalization.eq (S := Localization.AtPrime p.asIdeal)] at this + rw [IsLocalization.eq (S := Localization.AtPrime p.asIdeal)] at this cases' this with r hr exact ⟨r.1, hr, r.2⟩ @@ -622,7 +624,7 @@ Every section can locally be represented on basic opens `basicOpen g` as a fract theorem locally_const_basicOpen (U : Opens (PrimeSpectrum.Top R)) (s : (structureSheaf R).1.obj (op U)) (x : U) : ∃ (f g : R) (i : PrimeSpectrum.basicOpen g ⟶ U), x.1 ∈ PrimeSpectrum.basicOpen g ∧ - (const R f g (PrimeSpectrum.basicOpen g) fun y hy => hy) = + (const R f g (PrimeSpectrum.basicOpen g) fun _ hy => hy) = (structureSheaf R).1.map i.op s := by -- First, any section `s` can be represented as a fraction `f/g` on some open neighborhood of `x` -- and we may pass to a `basicOpen h`, since these form a basis @@ -669,14 +671,14 @@ theorem normalize_finite_fraction_representation (U : Opens (PrimeSpectrum.Top R (h_cover : U ≤ ⨆ i ∈ t, PrimeSpectrum.basicOpen (h i)) (hs : ∀ i : ι, - (const R (a i) (h i) (PrimeSpectrum.basicOpen (h i)) fun y hy => hy) = + (const R (a i) (h i) (PrimeSpectrum.basicOpen (h i)) fun _ hy => hy) = (structureSheaf R).1.map (iDh i).op s) : ∃ (a' h' : ι → R) (iDh' : ∀ i : ι, PrimeSpectrum.basicOpen (h' i) ⟶ U), (U ≤ ⨆ i ∈ t, PrimeSpectrum.basicOpen (h' i)) ∧ (∀ (i) (_ : i ∈ t) (j) (_ : j ∈ t), a' i * h' j = h' i * a' j) ∧ ∀ i ∈ t, (structureSheaf R).1.map (iDh' i).op s = - const R (a' i) (h' i) (PrimeSpectrum.basicOpen (h' i)) fun y hy => hy := by + const R (a' i) (h' i) (PrimeSpectrum.basicOpen (h' i)) fun _ hy => hy := by -- First we show that the fractions `(a i * h j) / (h i * h j)` and `(h i * a j) / (h i * h j)` -- coincide in the localization of `R` at `h i * h j` have fractions_eq : @@ -876,7 +878,7 @@ instance IsLocalization.to_stalk (p : PrimeSpectrum R) : rw [stalkAlgebra_map] congr 1 change toStalk R p = _ ≫ (stalkIso R p).inv - erw [Iso.eq_comp_inv] + rw [Iso.eq_comp_inv] exact toStalk_comp_stalkToFiberRingHom R p instance openAlgebra (U : (Opens (PrimeSpectrum R))ᵒᵖ) : Algebra R ((structureSheaf R).val.obj U) := @@ -1059,9 +1061,7 @@ theorem comap_const (f : R →+* S) (U : Opens (PrimeSpectrum.Top R)) const S (f a) (f b) V fun p hpV => hb (PrimeSpectrum.comap f p) (hUV hpV) := Subtype.eq <| funext fun p => by - rw [comap_apply, const_apply, const_apply] - erw [Localization.localRingHom_mk'] - rfl + rw [comap_apply, const_apply, const_apply, Localization.localRingHom_mk'] /-- For an inclusion `i : V ⟶ U` between open sets of the prime spectrum of `R`, the comap of the identity from OO_X(U) to OO_X(V) equals as the restriction map of the structure sheaf. @@ -1070,7 +1070,7 @@ This is a generalization of the fact that, for fixed `U`, the comap of the ident to OO_X(U) is the identity. -/ theorem comap_id_eq_map (U V : Opens (PrimeSpectrum.Top R)) (iVU : V ⟶ U) : - (comap (RingHom.id R) U V fun p hpV => leOfHom iVU <| hpV) = + (comap (RingHom.id R) U V fun _ hpV => leOfHom iVU <| hpV) = (structureSheaf R).1.map iVU.op := RingHom.ext fun s => Subtype.eq <| funext fun p => by rw [comap_apply] @@ -1095,7 +1095,7 @@ are not definitionally equal. theorem comap_id {U V : Opens (PrimeSpectrum.Top R)} (hUV : U = V) : (comap (RingHom.id R) U V fun p hpV => by rwa [hUV, PrimeSpectrum.comap_id]) = eqToHom (show (structureSheaf R).1.obj (op U) = _ by rw [hUV]) := by - erw [comap_id_eq_map U V (eqToHom hUV.symm), eqToHom_op, eqToHom_map] + rw [comap_id_eq_map U V (eqToHom hUV.symm), eqToHom_op, eqToHom_map] @[simp] theorem comap_id' (U : Opens (PrimeSpectrum.Top R)) : @@ -1111,7 +1111,7 @@ theorem comap_comp (f : R →+* S) (g : S →+* P) (U : Opens (PrimeSpectrum.Top Subtype.eq <| funext fun p => by rw [comap_apply] - erw [Localization.localRingHom_comp _ (PrimeSpectrum.comap g p.1).asIdeal] <;> + rw [Localization.localRingHom_comp _ (PrimeSpectrum.comap g p.1).asIdeal] <;> -- refl works here, because `PrimeSpectrum.comap (g.comp f) p` is defeq to -- `PrimeSpectrum.comap f (PrimeSpectrum.comap g p)` rfl diff --git a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean index de7b73ca2ffc3..25c2c3588b0e9 100644 --- a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean +++ b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean @@ -255,7 +255,7 @@ def inclusionOfMooreComplexMap (X : SimplicialObject A) : rw [Fin.sum_univ_succ, Fintype.sum_eq_zero] swap · intro j - rw [NormalizedMooreComplex.objX, comp_zsmul, + rw [NormalizedMooreComplex.objX_add_one, comp_zsmul, ← factorThru_arrow _ _ (finset_inf_arrow_factors Finset.univ _ _ (Finset.mem_univ j)), Category.assoc, kernelSubobject_arrow_comp, comp_zero, smul_zero] -- finally, we study the remaining term which is induced by X.δ 0 diff --git a/Mathlib/AlgebraicTopology/CechNerve.lean b/Mathlib/AlgebraicTopology/CechNerve.lean index 0f3fe3235d5db..b6270d870a146 100644 --- a/Mathlib/AlgebraicTopology/CechNerve.lean +++ b/Mathlib/AlgebraicTopology/CechNerve.lean @@ -67,7 +67,7 @@ def mapCechNerve {f g : Arrow C} def augmentedCechNerve : SimplicialObject.Augmented C where left := f.cechNerve right := f.right - hom := { app := fun i => WidePullback.base _ } + hom := { app := fun _ => WidePullback.base _ } /-- The morphism between augmented Čech nerve associated to a morphism of arrows. -/ @[simps] @@ -142,7 +142,7 @@ def cechNerveEquiv (X : SimplicialObject.Augmented C) (F : Arrow C) : intro A ext · dsimp - erw [WidePullback.lift_π] + rw [WidePullback.lift_π] nth_rw 2 [← Category.id_comp A.left] congr 1 convert X.left.map_id _ @@ -193,7 +193,7 @@ def cechConerve : CosimplicialObject C where map {x y} g := by refine WidePushout.desc (WidePushout.head _) (fun i => (@WidePushout.ι _ _ _ _ _ (fun _ => f.hom) (_) (g.toOrderHom i))) (fun j => ?_) - erw [← WidePushout.arrow_ι] + rw [← WidePushout.arrow_ι] /-- The morphism between Čech conerves associated to a morphism of arrows. -/ @[simps] @@ -211,7 +211,7 @@ def augmentedCechConerve : CosimplicialObject.Augmented C where left := f.left right := f.cechConerve hom := - { app := fun i => (WidePushout.head _ : f.left ⟶ _) } + { app := fun _ => (WidePushout.head _ : f.left ⟶ _) } /-- The morphism between augmented Čech conerves associated to a morphism of arrows. -/ @[simps] @@ -308,7 +308,7 @@ def cechConerveEquiv (F : Arrow C) (X : CosimplicialObject.Augmented C) : ext · rfl · dsimp - erw [WidePushout.ι_desc] + rw [WidePushout.ι_desc] nth_rw 2 [← Category.comp_id A.right] congr 1 convert X.right.map_id _ @@ -357,7 +357,7 @@ def wideCospan.limitCone [Finite ι] (X : C) : LimitCone (wideCospan ι X) where subsingleton } } isLimit := { lift := fun s => Limits.Pi.lift fun j => s.π.app (some j) - fac := fun s j => Option.casesOn j (by subsingleton) fun j => limit.lift_π _ _ + fac := fun s j => Option.casesOn j (by subsingleton) fun _ => limit.lift_π _ _ uniq := fun s f h => by dsimp ext j @@ -405,7 +405,7 @@ lemma wideCospan.limitIsoPi_hom_comp_pi [Finite ι] (X : C) (j : ι) : naturally isomorphic to a simplicial object sending `[n]` to `Xⁿ⁺¹` (when `C` is `G-Set`, this is `EG`, the universal cover of the classifying space of `G`. -/ def iso (X : C) : (Arrow.mk (terminal.from X)).cechNerve ≅ cechNerveTerminalFrom X := - NatIso.ofComponents (fun m => wideCospan.limitIsoPi _ _) (fun {m n} f => by + NatIso.ofComponents (fun _ => wideCospan.limitIsoPi _ _) (fun {m n} f => by dsimp only [cechNerveTerminalFrom, Arrow.cechNerve] ext ⟨j⟩ simp only [Category.assoc, limit.lift_π, Fan.mk_π_app] diff --git a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean index 91df76ad66660..b6025650b82bb 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean @@ -32,7 +32,7 @@ variable {C : Type*} [Category C] [Preadditive C] [HasFiniteCoproducts C] /-- The isomorphism `(Γ₀.splitting K).nondegComplex ≅ K` for all `K : ChainComplex C ℕ`. -/ @[simps!] def Γ₀NondegComplexIso (K : ChainComplex C ℕ) : (Γ₀.splitting K).nondegComplex ≅ K := - HomologicalComplex.Hom.isoOfComponents (fun n => Iso.refl _) + HomologicalComplex.Hom.isoOfComponents (fun _ => Iso.refl _) (by rintro _ n (rfl : n + 1 = _) dsimp @@ -101,9 +101,6 @@ theorem N₁Γ₀_inv_app_f_f (K : ChainComplex C ℕ) (n : ℕ) : rw [N₁Γ₀_inv_app] apply id_comp --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] N₁Γ₀ - /-- Compatibility isomorphism between `toKaroubi _ ⋙ Γ₂ ⋙ N₂` and `Γ₀ ⋙ N₁` which are functors `ChainComplex C ℕ ⥤ Karoubi (ChainComplex C ℕ)`. -/ def N₂Γ₂ToKaroubiIso : toKaroubi (ChainComplex C ℕ) ⋙ Γ₂ ⋙ N₂ ≅ Γ₀ ⋙ N₁ := @@ -142,9 +139,6 @@ lemma N₂Γ₂ToKaroubiIso_inv_app (X : ChainComplex C ℕ) : rw [Splitting.ι_desc] erw [comp_id, id_comp] --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] N₂Γ₂ToKaroubiIso - /-- The counit isomorphism of the Dold-Kan equivalence for additive categories. -/ def N₂Γ₂ : Γ₂ ⋙ N₂ ≅ 𝟭 (Karoubi (ChainComplex C ℕ)) := ((whiskeringLeft _ _ _).obj (toKaroubi (ChainComplex C ℕ))).preimageIso @@ -173,9 +167,6 @@ lemma whiskerLeft_toKaroubi_N₂Γ₂_hom : dsimp only [whiskeringLeft, N₂Γ₂, Functor.preimageIso] at h ⊢ exact h --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] N₂Γ₂ - theorem N₂Γ₂_compatible_with_N₁Γ₀ (K : ChainComplex C ℕ) : N₂Γ₂.hom.app ((toKaroubi _).obj K) = N₂Γ₂ToKaroubiIso.hom.app K ≫ N₁Γ₀.hom.app K := congr_app whiskerLeft_toKaroubi_N₂Γ₂_hom K diff --git a/Mathlib/AlgebraicTopology/DoldKan/Homotopies.lean b/Mathlib/AlgebraicTopology/DoldKan/Homotopies.lean index bbb305c218ea0..1c3db5df719f3 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Homotopies.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Homotopies.lean @@ -151,7 +151,7 @@ theorem hσ'_naturality (q : ℕ) (n m : ℕ) (hnm : c.Rel m n) {X Y : Simplicia /-- For each q, `Hσ q` is a natural transformation. -/ def natTransHσ (q : ℕ) : alternatingFaceMapComplex C ⟶ alternatingFaceMapComplex C where - app X := Hσ q + app _ := Hσ q naturality _ _ f := by unfold Hσ rw [nullHomotopicMap'_comp, comp_nullHomotopicMap'] diff --git a/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean b/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean index 1e25732cfa533..a62ceb55bcb32 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean @@ -157,9 +157,6 @@ def natTrans : (N₁ : SimplicialObject C ⥤ _) ⋙ Γ₂ ⟶ toKaroubi _ where HomologicalComplex.comp_f, AlternatingFaceMapComplex.map_f, PInfty_f_naturality_assoc, NatTrans.naturality, Splitting.IndexSet.id_fst, unop_op, len_mk] --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] natTrans - end Γ₂N₁ -- Porting note: removed @[simps] attribute because it was creating timeouts @@ -177,9 +174,6 @@ lemma Γ₂N₂ToKaroubiIso_inv_app (X : SimplicialObject C) : Γ₂N₂ToKaroubiIso.inv.app X = Γ₂.map (toKaroubiCompN₂IsoN₁.inv.app X) := by simp [Γ₂N₂ToKaroubiIso] --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] Γ₂N₂ToKaroubiIso - namespace Γ₂N₂ /-- The natural transformation `N₂ ⋙ Γ₂ ⟶ 𝟭 (SimplicialObject C)`. -/ @@ -194,9 +188,6 @@ theorem natTrans_app_f_app (P : Karoubi (SimplicialObject C)) : dsimp only [natTrans] simp only [whiskeringLeft_obj_preimage_app, Functor.id_map, assoc] --- Porting note (#10694): added to speed up elaboration -attribute [irreducible] natTrans - end Γ₂N₂ theorem compatibility_Γ₂N₁_Γ₂N₂_natTrans (X : SimplicialObject C) : diff --git a/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean b/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean index 43aa24e304f15..cff0ffb6de103 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean @@ -142,7 +142,7 @@ def N₁_iso_normalizedMooreComplex_comp_toKaroubi : N₁ ≅ normalizedMooreCom PInftyToNormalizedMooreComplex_comp_inclusionOfMooreComplexMap, inclusionOfMooreComplexMap_comp_PInfty] dsimp only [Functor.comp_obj, toKaroubi] - erw [id_comp] + rw [id_comp] end DoldKan diff --git a/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean b/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean index f9d67b69c0cf5..1640f26ee2f41 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean @@ -179,7 +179,7 @@ theorem karoubi_PInfty_f {Y : Karoubi (SimplicialObject C)} (n : ℕ) : ((𝟙 (karoubiFunctorCategoryEmbedding SimplexCategoryᵒᵖ C)) ◫ (natTransPInfty_f (Karoubi C) n)) Y dsimp [natTransPInfty_f] at h₁₄ - erw [id_comp, id_comp, comp_id, comp_id] at h₁₄ + rw [id_comp, id_comp, comp_id, comp_id] at h₁₄ -- We use the three equalities h₃₂, h₄₃, h₁₄. rw [← h₃₂, ← h₄₃, h₁₄] simp only [KaroubiFunctorCategoryEmbedding.map_app_f, Karoubi.decompId_p_f, diff --git a/Mathlib/AlgebraicTopology/DoldKan/Projections.lean b/Mathlib/AlgebraicTopology/DoldKan/Projections.lean index 6802bb367805a..36a1005cae771 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Projections.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Projections.lean @@ -147,7 +147,7 @@ theorem Q_idem (q : ℕ) : (Q q : K[X] ⟶ K[X]) ≫ Q q = Q q := by /-- For each `q`, `P q` is a natural transformation. -/ @[simps] def natTransP (q : ℕ) : alternatingFaceMapComplex C ⟶ alternatingFaceMapComplex C where - app X := P q + app _ := P q naturality _ _ f := by induction' q with q hq · dsimp [alternatingFaceMapComplex] @@ -172,7 +172,7 @@ theorem Q_f_naturality (q n : ℕ) {X Y : SimplicialObject C} (f : X ⟶ Y) : /-- For each `q`, `Q q` is a natural transformation. -/ @[simps] def natTransQ (q : ℕ) : alternatingFaceMapComplex C ⟶ alternatingFaceMapComplex C where - app X := Q q + app _ := Q q theorem map_P {D : Type*} [Category D] [Preadditive D] (G : C ⥤ D) [G.Additive] (X : SimplicialObject C) (q n : ℕ) : diff --git a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean index 7cf65c0fc934b..1a0800fec44ea 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean @@ -229,7 +229,7 @@ noncomputable def nondegComplexFunctor : Split C ⥤ ChainComplex C ℕ where apply S₁.s.hom_ext' intro A dsimp [alternatingFaceMapComplex] - erw [cofan_inj_naturality_symm_assoc Φ A] + rw [cofan_inj_naturality_symm_assoc Φ A] by_cases h : A.EqId · dsimp at h subst h diff --git a/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean b/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean index 4610e95420a71..383f0ae621d5f 100644 --- a/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean +++ b/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.AlgebraicTopology.AlternatingFaceMapComplex -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic import Mathlib.AlgebraicTopology.CechNerve import Mathlib.Algebra.Homology.Homotopy import Mathlib.Tactic.FinCases @@ -181,7 +181,7 @@ open SSet.standardSimplex in protected noncomputable def extraDegeneracy (Δ : SimplexCategory) : SimplicialObject.Augmented.ExtraDegeneracy (standardSimplex.obj Δ) where s' _ := objMk (OrderHom.const _ 0) - s n f := (objEquiv _ _).symm + s _ f := (objEquiv _ _).symm (shift (objEquiv _ _ f)) s'_comp_ε := by dsimp diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean index 2a8bb0c418f7e..441b8fdab6dd2 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean @@ -20,9 +20,9 @@ group of `x`. open CategoryTheory -universe u v +universe u -variable {X : Type u} {Y : Type v} [TopologicalSpace X] [TopologicalSpace Y] +variable {X : Type u} [TopologicalSpace X] variable {x₀ x₁ : X} noncomputable section @@ -299,14 +299,14 @@ attribute [local instance] Path.Homotopic.setoid instance : CategoryTheory.Groupoid (FundamentalGroupoid X) where Hom x y := Path.Homotopic.Quotient x.as y.as id x := ⟦Path.refl x.as⟧ - comp {x y z} := Path.Homotopic.Quotient.comp - id_comp {x y} f := + comp {_ _ _} := Path.Homotopic.Quotient.comp + id_comp {x _} f := Quotient.inductionOn f fun a => show ⟦(Path.refl x.as).trans a⟧ = ⟦a⟧ from Quotient.sound ⟨Path.Homotopy.reflTrans a⟩ - comp_id {x y} f := + comp_id {_ y} f := Quotient.inductionOn f fun a => show ⟦a.trans (Path.refl y.as)⟧ = ⟦a⟧ from Quotient.sound ⟨Path.Homotopy.transRefl a⟩ - assoc {w x y z} f g h := + assoc {_ _ _ _} f g h := Quotient.inductionOn₃ f g h fun p q r => show ⟦(p.trans q).trans r⟧ = ⟦p.trans (q.trans r)⟧ from Quotient.sound ⟨Path.Homotopy.transAssoc p q r⟩ @@ -318,11 +318,11 @@ instance : CategoryTheory.Groupoid (FundamentalGroupoid X) where rw [Quotient.eq] exact ⟨h.symm₂⟩) p - inv_comp {x y} f := + inv_comp {_ y} f := Quotient.inductionOn f fun a => show ⟦a.symm.trans a⟧ = ⟦Path.refl y.as⟧ from Quotient.sound ⟨(Path.Homotopy.reflSymmTrans a).symm⟩ - comp_inv {x y} f := + comp_inv {x _} f := Quotient.inductionOn f fun a => show ⟦a.trans a.symm⟧ = ⟦Path.refl x.as⟧ from Quotient.sound ⟨(Path.Homotopy.reflTransSymm a).symm⟩ @@ -337,7 +337,7 @@ def fundamentalGroupoidFunctor : TopCat ⥤ CategoryTheory.Grpd where map f := { obj := fun x => ⟨f x.as⟩ map := fun {X Y} p => by exact Path.Homotopic.Quotient.mapFn p f - map_id := fun X => rfl + map_id := fun _ => rfl map_comp := fun {x y z} p q => by refine Quotient.inductionOn₂ p q fun a b => ?_ simp only [comp_eq, ← Path.Homotopic.map_lift, ← Path.Homotopic.comp_lift, Path.map_trans] } diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/FundamentalGroup.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/FundamentalGroup.lean index b1c4b82e4469b..e5d2e226cd519 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/FundamentalGroup.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/FundamentalGroup.lean @@ -17,9 +17,9 @@ of `x` i.e. the group with elements being loops based at `x` (quotiented by homo -/ -universe u v +universe u -variable {X : Type u} {Y : Type v} [TopologicalSpace X] [TopologicalSpace Y] +variable {X : Type u} [TopologicalSpace X] variable {x₀ x₁ : X} noncomputable section diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean index 667572acea631..e6ebf8e4a8192 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean @@ -150,14 +150,14 @@ def prodToProdTop : πₓ A × πₓ B ⥤ πₓ (TopCat.of (A × B)) where obj g := ⟨g.fst.as, g.snd.as⟩ map {x y} p := match x, y, p with - | (x₀, x₁), (y₀, y₁), (p₀, p₁) => @Path.Homotopic.prod _ _ (_) (_) _ _ _ _ p₀ p₁ + | (_, _), (_, _), (p₀, p₁) => @Path.Homotopic.prod _ _ (_) (_) _ _ _ _ p₀ p₁ map_id := by rintro ⟨x₀, x₁⟩ simp only [CategoryTheory.prod_id, FundamentalGroupoid.id_eq_path_refl] rfl map_comp {x y z} f g := match x, y, z, f, g with - | (x₀, x₁), (y₀, y₁), (z₀, z₁), (f₀, f₁), (g₀, g₁) => + | (_, _), (_, _), (_, _), (f₀, f₁), (g₀, g₁) => (Path.Homotopic.comp_prod_eq_prod_comp f₀ f₁ g₀ g₁).symm theorem prodToProdTop_map {x₀ x₁ : πₓ A} {y₀ y₁ : πₓ B} (p₀ : x₀ ⟶ x₁) (p₁ : y₀ ⟶ y₁) : diff --git a/Mathlib/AlgebraicTopology/MooreComplex.lean b/Mathlib/AlgebraicTopology/MooreComplex.lean index 5ab0ded88a8b6..0ce1710a542c8 100644 --- a/Mathlib/AlgebraicTopology/MooreComplex.lean +++ b/Mathlib/AlgebraicTopology/MooreComplex.lean @@ -59,16 +59,13 @@ def objX : ∀ n : ℕ, Subobject (X.obj (op (SimplexCategory.mk n))) | 0 => ⊤ | n + 1 => Finset.univ.inf fun k : Fin (n + 1) => kernelSubobject (X.δ k.succ) -theorem objX_zero : objX X 0 = ⊤ := +@[simp] theorem objX_zero : objX X 0 = ⊤ := rfl -theorem objX_add_one (n) : +@[simp] theorem objX_add_one (n) : objX X (n + 1) = Finset.univ.inf fun k : Fin (n + 1) => kernelSubobject (X.δ k.succ) := rfl -attribute [eqns objX_zero objX_add_one] objX -attribute [simp] objX - /-- The differentials in the normalized Moore complex. -/ @[simp] diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index e72f2e8cd7bec..72bc3cc192913 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean @@ -131,7 +131,7 @@ end Hom instance smallCategory : SmallCategory.{0} SimplexCategory where Hom n m := SimplexCategory.Hom n m - id m := SimplexCategory.Hom.id _ + id _ := SimplexCategory.Hom.id _ comp f g := SimplexCategory.Hom.comp g f @[simp] @@ -142,7 +142,6 @@ lemma id_toOrderHom (a : SimplexCategory) : lemma comp_toOrderHom {a b c : SimplexCategory} (f : a ⟶ b) (g : b ⟶ c) : (f ≫ g).toOrderHom = g.toOrderHom.comp f.toOrderHom := rfl --- Porting note: added because `Hom.ext'` is not triggered automatically @[ext] theorem Hom.ext {a b : SimplexCategory} (f g : a ⟶ b) : f.toOrderHom = g.toOrderHom → f = g := @@ -165,6 +164,43 @@ theorem const_comp (x : SimplexCategory) {y z : SimplexCategory} const x y i ≫ f = const x z (f.toOrderHom i) := rfl +theorem const_fac_thru_zero (n m : SimplexCategory) (i : Fin (m.len + 1)) : + const n m i = const n [0] 0 ≫ SimplexCategory.const [0] m i := by + rw [const_comp]; rfl + +theorem eq_const_of_zero {n : SimplexCategory} (f : ([0] : SimplexCategory) ⟶ n) : + f = const _ n (f.toOrderHom 0) := by + ext x; match x with | 0 => rfl + +theorem exists_eq_const_of_zero {n : SimplexCategory} (f : ([0] : SimplexCategory) ⟶ n) : + ∃ a, f = const _ n a := ⟨_, eq_const_of_zero _⟩ + +theorem eq_const_to_zero {n : SimplexCategory} (f : n ⟶ [0]) : + f = const n _ 0 := by + ext : 3 + apply @Subsingleton.elim (Fin 1) + +theorem eq_of_one_to_one (f : ([1] : SimplexCategory) ⟶ [1]) : + (∃ a, f = const [1] _ a) ∨ f = 𝟙 _ := by + match e0 : f.toOrderHom 0, e1 : f.toOrderHom 1 with + | 0, 0 | 1, 1 => + refine .inl ⟨f.toOrderHom 0, ?_⟩ + ext i : 3 + match i with + | 0 => rfl + | 1 => exact e1.trans e0.symm + | 0, 1 => + right + ext i : 3 + match i with + | 0 => exact e0 + | 1 => exact e1 + | 1, 0 => + have := f.toOrderHom.monotone (by decide : (0 : Fin 2) ≤ 1) + rw [e0, e1] at this + exact Not.elim (by decide) this + + /-- Make a morphism `[n] ⟶ [m]` from a monotone map between fin's. This is useful for constructing morphisms between `[n]` directly without identifying `n` with `[n].len`. @@ -173,6 +209,36 @@ without identifying `n` with `[n].len`. def mkHom {n m : ℕ} (f : Fin (n + 1) →o Fin (m + 1)) : ([n] : SimplexCategory) ⟶ [m] := SimplexCategory.Hom.mk f +/-- The morphism `[1] ⟶ [n]` that picks out a specified `h : i ≤ j` in `Fin (n+1)`.-/ +def mkOfLe {n} (i j : Fin (n+1)) (h : i ≤ j) : ([1] : SimplexCategory) ⟶ [n] := + SimplexCategory.mkHom { + toFun := fun | 0 => i | 1 => j + monotone' := fun + | 0, 0, _ | 1, 1, _ => le_rfl + | 0, 1, _ => h + } + +/-- The morphism `[1] ⟶ [n]` that picks out the arrow `i ⟶ i+1` in `Fin (n+1)`.-/ +def mkOfSucc {n} (i : Fin n) : ([1] : SimplexCategory) ⟶ [n] := + SimplexCategory.mkHom { + toFun := fun | 0 => i.castSucc | 1 => i.succ + monotone' := fun + | 0, 0, _ | 1, 1, _ => le_rfl + | 0, 1, _ => Fin.castSucc_le_succ i + } + +/-- The morphism `[2] ⟶ [n]` that picks out a specified composite of morphisms in `Fin (n+1)`.-/ +def mkOfLeComp {n} (i j k : Fin (n + 1)) (h₁ : i ≤ j) (h₂ : j ≤ k) : + ([2] : SimplexCategory) ⟶ [n] := + SimplexCategory.mkHom { + toFun := fun | 0 => i | 1 => j | 2 => k + monotone' := fun + | 0, 0, _ | 1, 1, _ | 2, 2, _ => le_rfl + | 0, 1, _ => h₁ + | 1, 2, _ => h₂ + | 0, 2, _ => Fin.le_trans h₁ h₂ + } + instance (Δ : SimplexCategory) : Subsingleton (Δ ⟶ [0]) where allEq f g := by ext : 3; apply Subsingleton.elim (α := Fin 1) @@ -400,6 +466,40 @@ lemma factor_δ_spec {m n : ℕ} (f : ([m] : SimplexCategory) ⟶ [n+1]) (j : Fi · rwa [succ_le_castSucc_iff, lt_pred_iff] rw [succ_pred] + +theorem eq_of_one_to_two (f : ([1] : SimplexCategory) ⟶ [2]) : + f = (δ (n := 1) 0) ∨ f = (δ (n := 1) 1) ∨ f = (δ (n := 1) 2) ∨ + ∃ a, f = SimplexCategory.const _ _ a := by + have : f.toOrderHom 0 ≤ f.toOrderHom 1 := f.toOrderHom.monotone (by decide : (0 : Fin 2) ≤ 1) + match e0 : f.toOrderHom 0, e1 : f.toOrderHom 1 with + | 1, 2 => + left + ext i : 3 + match i with + | 0 => exact e0 + | 1 => exact e1 + | 0, 2 => + right; left + ext i : 3 + match i with + | 0 => exact e0 + | 1 => exact e1 + | 0, 1 => + right; right; left + ext i : 3 + match i with + | 0 => exact e0 + | 1 => exact e1 + | 0, 0 | 1, 1 | 2, 2 => + right; right; right; use f.toOrderHom 0 + ext i : 3 + match i with + | 0 => rfl + | 1 => exact e1.trans e0.symm + | 1, 0 | 2, 0 | 2, 1 => + rw [e0, e1] at this + exact Not.elim (by decide) this + end Generators section Skeleton @@ -490,6 +590,14 @@ def inclusion {n : ℕ} : SimplexCategory.Truncated n ⥤ SimplexCategory := instance (n : ℕ) : (inclusion : Truncated n ⥤ _).Full := FullSubcategory.full _ instance (n : ℕ) : (inclusion : Truncated n ⥤ _).Faithful := FullSubcategory.faithful _ +/-- A proof that the full subcategory inclusion is fully faithful.-/ +noncomputable def inclusion.fullyFaithful (n : ℕ) : + (inclusion : Truncated n ⥤ _).op.FullyFaithful := Functor.FullyFaithful.ofFullyFaithful _ + +@[ext] +theorem Hom.ext {n} {a b : Truncated n} (f g : a ⟶ b) : + f.toOrderHom = g.toOrderHom → f = g := SimplexCategory.Hom.ext _ _ + end Truncated section Concrete @@ -630,7 +738,7 @@ theorem eq_σ_comp_of_not_injective' {n : ℕ} {Δ' : SimplexCategory} (θ : mk dsimp rw [Fin.predAbove_of_le_castSucc i x h'] dsimp [δ] - erw [Fin.succAbove_of_castSucc_lt _ _ _] + rw [Fin.succAbove_of_castSucc_lt _ _ _] · rw [Fin.castSucc_castPred] · exact (Fin.castSucc_lt_succ_iff.mpr h') · simp only [not_le] at h' @@ -645,10 +753,10 @@ theorem eq_σ_comp_of_not_injective' {n : ℕ} {Δ' : SimplexCategory} (θ : mk refine hi.symm.trans ?_ congr 1 dsimp [δ] - erw [Fin.succAbove_of_castSucc_lt i.succ] + rw [Fin.succAbove_of_castSucc_lt i.succ] exact Fin.lt_succ · dsimp [δ] - erw [Fin.succAbove_of_le_castSucc i.succ _] + rw [Fin.succAbove_of_le_castSucc i.succ _] simp only [Fin.lt_iff_val_lt_val, Fin.le_iff_val_le_val, Fin.val_succ, Fin.coe_castSucc, Nat.lt_succ_iff, Fin.ext_iff] at h' h'' ⊢ cases' Nat.le.dest h' with c hc @@ -693,18 +801,17 @@ theorem eq_comp_δ_of_not_surjective' {n : ℕ} {Δ : SimplexCategory} (θ : Δ simp only [len_mk, Category.assoc, comp_toOrderHom, OrderHom.comp_coe, Function.comp_apply] by_cases h' : θ.toOrderHom x ≤ i · simp only [σ, mkHom, Hom.toOrderHom_mk, OrderHom.coe_mk] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [Fin.predAbove_of_le_castSucc _ _ (by rwa [Fin.castSucc_castPred])] + rw [Fin.predAbove_of_le_castSucc _ _ (by rwa [Fin.castSucc_castPred])] dsimp [δ] - erw [Fin.succAbove_of_castSucc_lt i] + rw [Fin.succAbove_of_castSucc_lt i] · rw [Fin.castSucc_castPred] · rw [(hi x).le_iff_lt] at h' exact h' · simp only [not_le] at h' dsimp [σ, δ] - erw [Fin.predAbove_of_castSucc_lt _ _ (by rwa [Fin.castSucc_castPred])] + rw [Fin.predAbove_of_castSucc_lt _ _ (by rwa [Fin.castSucc_castPred])] rw [Fin.succAbove_of_le_castSucc i _] - · erw [Fin.succ_pred] + · rw [Fin.succ_pred] · exact Nat.le_sub_one_of_lt (Fin.lt_iff_val_lt_val.mp h') · obtain rfl := le_antisymm (Fin.le_last i) (not_lt.mp h) use θ ≫ σ (Fin.last _) diff --git a/Mathlib/AlgebraicTopology/SimplicialCategory/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialCategory/Basic.lean index 7611deaafc8d6..88f5cb27d8813 100644 --- a/Mathlib/AlgebraicTopology/SimplicialCategory/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplicialCategory/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.AlgebraicTopology.SimplicialSet.Monoidal -import Mathlib.CategoryTheory.Enriched.Basic +import Mathlib.CategoryTheory.Enriched.Ordinary /-! # Simplicial categories @@ -42,13 +42,7 @@ variable (C : Type u) [Category.{v} C] /-- A simplicial category is a category `C` that is enriched over the category of simplicial sets in such a way that morphisms in `C` identify to the `0`-simplices of the enriched hom. -/ -class SimplicialCategory extends EnrichedCategory SSet.{v} C where - /-- morphisms identify to `0`-simplices of the enriched hom -/ - homEquiv (K L : C) : (K ⟶ L) ≃ (𝟙_ SSet.{v} ⟶ EnrichedCategory.Hom K L) - homEquiv_id (K : C) : homEquiv K K (𝟙 K) = eId SSet K := by aesop_cat - homEquiv_comp {K L M : C} (f : K ⟶ L) (g : L ⟶ M) : - homEquiv K M (f ≫ g) = (λ_ _).inv ≫ (homEquiv K L f ⊗ homEquiv L M g) ≫ - eComp SSet K L M := by aesop_cat +abbrev SimplicialCategory := EnrichedOrdinaryCategory SSet.{v} C namespace SimplicialCategory @@ -57,7 +51,7 @@ variable [SimplicialCategory C] variable {C} /-- Abbreviation for the enriched hom of a simplicial category. -/ -abbrev sHom (K L : C) : SSet.{v} := EnrichedCategory.Hom K L +abbrev sHom (K L : C) : SSet.{v} := K ⟶[SSet] L /-- Abbreviation for the enriched composition in a simplicial category. -/ abbrev sHomComp (K L M : C) : sHom K L ⊗ sHom L M ⟶ sHom K M := eComp SSet K L M @@ -65,58 +59,11 @@ abbrev sHomComp (K L M : C) : sHom K L ⊗ sHom L M ⟶ sHom K M := eComp SSet K /-- The bijection `(K ⟶ L) ≃ sHom K L _[0]` for all objects `K` and `L` in a simplicial category. -/ def homEquiv' (K L : C) : (K ⟶ L) ≃ sHom K L _[0] := - (homEquiv K L).trans (sHom K L).unitHomEquiv - -/-- The morphism `sHom K' L ⟶ sHom K L` induced by a morphism `K ⟶ K'`. -/ -noncomputable def sHomWhiskerRight {K K' : C} (f : K ⟶ K') (L : C) : - sHom K' L ⟶ sHom K L := - (λ_ _).inv ≫ homEquiv K K' f ▷ _ ≫ sHomComp K K' L - -@[simp] -lemma sHomWhiskerRight_id (K L : C) : sHomWhiskerRight (𝟙 K) L = 𝟙 _ := by - simp [sHomWhiskerRight, homEquiv_id] - -@[simp, reassoc] -lemma sHomWhiskerRight_comp {K K' K'' : C} (f : K ⟶ K') (f' : K' ⟶ K'') (L : C) : - sHomWhiskerRight (f ≫ f') L = sHomWhiskerRight f' L ≫ sHomWhiskerRight f L := by - dsimp [sHomWhiskerRight] - simp only [assoc, homEquiv_comp, comp_whiskerRight, leftUnitor_inv_whiskerRight, ← e_assoc'] - rfl - -/-- The morphism `sHom K L ⟶ sHom K L'` induced by a morphism `L ⟶ L'`. -/ -noncomputable def sHomWhiskerLeft (K : C) {L L' : C} (g : L ⟶ L') : - sHom K L ⟶ sHom K L' := - (ρ_ _).inv ≫ _ ◁ homEquiv L L' g ≫ sHomComp K L L' - -@[simp] -lemma sHomWhiskerLeft_id (K L : C) : sHomWhiskerLeft K (𝟙 L) = 𝟙 _ := by - simp [sHomWhiskerLeft, homEquiv_id] - -@[simp, reassoc] -lemma sHomWhiskerLeft_comp (K : C) {L L' L'' : C} (g : L ⟶ L') (g' : L' ⟶ L'') : - sHomWhiskerLeft K (g ≫ g') = sHomWhiskerLeft K g ≫ sHomWhiskerLeft K g' := by - dsimp [sHomWhiskerLeft] - simp only [homEquiv_comp, MonoidalCategory.whiskerLeft_comp, assoc, ← e_assoc] - rfl - -@[reassoc] -lemma sHom_whisker_exchange {K K' L L' : C} (f : K ⟶ K') (g : L ⟶ L') : - sHomWhiskerLeft K' g ≫ sHomWhiskerRight f L' = - sHomWhiskerRight f L ≫ sHomWhiskerLeft K g := - ((ρ_ _).inv ≫ _ ◁ homEquiv L L' g ≫ (λ_ _).inv ≫ homEquiv K K' f ▷ _) ≫= - (e_assoc SSet.{v} K K' L L').symm - -attribute [local simp] sHom_whisker_exchange + (eHomEquiv SSet).trans (sHom K L).unitHomEquiv variable (C) in /-- The bifunctor `Cᵒᵖ ⥤ C ⥤ SSet.{v}` which sends `K : Cᵒᵖ` and `L : C` to `sHom K.unop L`. -/ -@[simps] -noncomputable def sHomFunctor : Cᵒᵖ ⥤ C ⥤ SSet.{v} where - obj K := - { obj := fun L => sHom K.unop L - map := fun φ => sHomWhiskerLeft K.unop φ } - map φ := - { app := fun L => sHomWhiskerRight φ.unop L } +noncomputable abbrev sHomFunctor : Cᵒᵖ ⥤ C ⥤ SSet.{v} := eHomFunctor _ _ end SimplicialCategory diff --git a/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean b/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean index 966e00873375e..2dde40d7ea1e5 100644 --- a/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean @@ -31,7 +31,7 @@ noncomputable instance : EnrichedCategory SSet.{v} (SimplicialObject D) := inferInstanceAs (EnrichedCategory (_ ⥤ Type v) (_ ⥤ D)) noncomputable instance : SimplicialCategory (SimplicialObject D) where - homEquiv K L := Functor.natTransEquiv.symm + homEquiv := Functor.natTransEquiv.symm noncomputable instance : SimplicialCategory SSet.{v} := inferInstanceAs (SimplicialCategory (SimplicialObject (Type v))) diff --git a/Mathlib/AlgebraicTopology/SimplicialObject.lean b/Mathlib/AlgebraicTopology/SimplicialObject.lean index ea02f63a11c95..d99137665f53d 100644 --- a/Mathlib/AlgebraicTopology/SimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SimplicialObject.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Kim Morrison, Adam Topaz -/ import Mathlib.AlgebraicTopology.SimplexCategory +import Mathlib.CategoryTheory.Adjunction.Reflective import Mathlib.CategoryTheory.Comma.Arrow +import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Opposites @@ -23,7 +25,7 @@ open Opposite open CategoryTheory -open CategoryTheory.Limits +open CategoryTheory.Limits CategoryTheory.Functor universe v u v' u' @@ -241,13 +243,103 @@ variable {C} end Truncated -section Skeleton +section Truncation -/-- The skeleton functor from simplicial objects to truncated simplicial objects. -/ -def sk (n : ℕ) : SimplicialObject C ⥤ SimplicialObject.Truncated C n := +/-- The truncation functor from simplicial objects to truncated simplicial objects. -/ +def truncation (n : ℕ) : SimplicialObject C ⥤ SimplicialObject.Truncated C n := (whiskeringLeft _ _ _).obj SimplexCategory.Truncated.inclusion.op -end Skeleton +end Truncation + + +noncomputable section + +/-- The n-skeleton as a functor `SimplicialObject.Truncated C n ⥤ SimplicialObject C`. -/ +protected abbrev Truncated.sk (n : ℕ) [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasLeftKanExtension F] : + SimplicialObject.Truncated C n ⥤ SimplicialObject C := + lan (SimplexCategory.Truncated.inclusion.op) + +/-- The n-coskeleton as a functor `SimplicialObject.Truncated C n ⥤ SimplicialObject C`. -/ +protected abbrev Truncated.cosk (n : ℕ) [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasRightKanExtension F] : + SimplicialObject.Truncated C n ⥤ SimplicialObject C := + ran (SimplexCategory.Truncated.inclusion.op) + +/-- The n-skeleton as an endofunctor on `SimplicialObject C`. -/ +abbrev sk (n : ℕ) [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasLeftKanExtension F] : + SimplicialObject C ⥤ SimplicialObject C := truncation n ⋙ Truncated.sk n + +/-- The n-coskeleton as an endofunctor on `SimplicialObject C`. -/ +abbrev cosk (n : ℕ) [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasRightKanExtension F] : + SimplicialObject C ⥤ SimplicialObject C := truncation n ⋙ Truncated.cosk n + +end + +section adjunctions +/- When the left and right Kan extensions exist, `Truncated.sk n` and `Truncated.cosk n` +respectively define left and right adjoints to `truncation n`.-/ + + +variable (n : ℕ) +variable [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasRightKanExtension F] +variable [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasLeftKanExtension F] + +/-- The adjunction between the n-skeleton and n-truncation.-/ +noncomputable def skAdj : Truncated.sk (C := C) n ⊣ truncation n := + lanAdjunction _ _ + +/-- The adjunction between n-truncation and the n-coskeleton.-/ +noncomputable def coskAdj : truncation (C := C) n ⊣ Truncated.cosk n := + ranAdjunction _ _ + +namespace Truncated +/- When the left and right Kan extensions exist and are pointwise Kan extensions, +`skAdj n` and `coskAdj n` are respectively coreflective and reflective.-/ + +variable [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasPointwiseRightKanExtension F] +variable [∀ (F : (SimplexCategory.Truncated n)ᵒᵖ ⥤ C), + SimplexCategory.Truncated.inclusion.op.HasPointwiseLeftKanExtension F] + +instance cosk_reflective : IsIso (coskAdj (C := C) n).counit := + reflective' SimplexCategory.Truncated.inclusion.op + +instance sk_coreflective : IsIso (skAdj (C := C) n).unit := + coreflective' SimplexCategory.Truncated.inclusion.op + +/-- Since `Truncated.inclusion` is fully faithful, so is right Kan extension along it.-/ +noncomputable def cosk.fullyFaithful : + (Truncated.cosk (C := C) n).FullyFaithful := by + apply Adjunction.fullyFaithfulROfIsIsoCounit (coskAdj n) + +instance cosk.full : (Truncated.cosk (C := C) n).Full := FullyFaithful.full (cosk.fullyFaithful _) + +instance cosk.faithful : (Truncated.cosk (C := C) n).Faithful := + FullyFaithful.faithful (cosk.fullyFaithful _) + +noncomputable instance coskAdj.reflective : Reflective (Truncated.cosk (C := C) n) := + Reflective.mk (truncation _) (coskAdj _) + +/-- Since `Truncated.inclusion` is fully faithful, so is left Kan extension along it.-/ +noncomputable def sk.fullyFaithful : (Truncated.sk (C := C) n).FullyFaithful := + Adjunction.fullyFaithfulLOfIsIsoUnit (skAdj n) + +instance sk.full : (Truncated.sk (C := C) n).Full := FullyFaithful.full (sk.fullyFaithful _) + +instance sk.faithful : (Truncated.sk (C := C) n).Faithful := + FullyFaithful.faithful (sk.fullyFaithful _) + +noncomputable instance skAdj.coreflective : Coreflective (Truncated.sk (C := C) n) := + Coreflective.mk (truncation _) (skAdj _) + +end Truncated + +end adjunctions variable (C) @@ -354,7 +446,7 @@ def augment (X : SimplicialObject C) (X₀ : C) (f : X _[0] ⟶ X₀) left := X right := X₀ hom := - { app := fun i => X.map (SimplexCategory.const _ _ 0).op ≫ f + { app := fun _ => X.map (SimplexCategory.const _ _ 0).op ≫ f naturality := by intro i j g dsimp @@ -576,13 +668,13 @@ variable {C} end Truncated -section Skeleton +section Truncation -/-- The skeleton functor from cosimplicial objects to truncated cosimplicial objects. -/ -def sk (n : ℕ) : CosimplicialObject C ⥤ CosimplicialObject.Truncated C n := +/-- The truncation functor from cosimplicial objects to truncated cosimplicial objects. -/ +def truncation (n : ℕ) : CosimplicialObject C ⥤ CosimplicialObject.Truncated C n := (whiskeringLeft _ _ _).obj SimplexCategory.Truncated.inclusion -end Skeleton +end Truncation variable (C) @@ -683,7 +775,7 @@ def augment (X : CosimplicialObject C) (X₀ : C) (f : X₀ ⟶ X.obj [0]) left := X₀ right := X hom := - { app := fun i => f ≫ X.map (SimplexCategory.const _ _ 0) + { app := fun _ => f ≫ X.map (SimplexCategory.const _ _ 0) naturality := by intro i j g dsimp diff --git a/Mathlib/AlgebraicTopology/SimplicialSet.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean similarity index 80% rename from Mathlib/AlgebraicTopology/SimplicialSet.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean index a8198f848a6c7..814de7455bce4 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean @@ -33,7 +33,7 @@ a morphism `Δ[n] ⟶ ∂Δ[n]`. universe v u -open CategoryTheory CategoryTheory.Limits +open CategoryTheory CategoryTheory.Limits CategoryTheory.Functor open Simplicial @@ -57,7 +57,6 @@ instance hasColimits : HasColimits SSet := by dsimp only [SSet] infer_instance --- Porting note (#5229): added an `ext` lemma. @[ext] lemma hom_ext {X Y : SSet} {f g : X ⟶ Y} (w : ∀ n, f.app n = g.app n) : f = g := SimplicialObject.hom_ext _ _ w @@ -164,6 +163,13 @@ def boundary (n : ℕ) : SSet.{u} where /-- The boundary `∂Δ[n]` of the `n`-th standard simplex -/ scoped[Simplicial] notation3 "∂Δ[" n "]" => SSet.boundary n +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{ α : Δ[n].obj m // _ }`. +-/ +set_option linter.unusedVariables false in /-- The inclusion of the boundary of the `n`-th standard simplex into that standard simplex. -/ def boundaryInclusion (n : ℕ) : ∂Δ[n] ⟶ Δ[n] where app m (α : { α : Δ[n].obj m // _ }) := α @@ -184,6 +190,13 @@ def horn (n : ℕ) (i : Fin (n + 1)) : SSet where /-- The `i`-th horn `Λ[n, i]` of the standard `n`-simplex -/ scoped[Simplicial] notation3 "Λ[" n ", " i "]" => SSet.horn (n : ℕ) i +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{ α : Δ[n].obj m // _ }`. +-/ +set_option linter.unusedVariables false in /-- The inclusion of the `i`-th horn of the `n`-th standard simplex into that standard simplex. -/ def hornInclusion (n : ℕ) (i : Fin (n + 1)) : Λ[n, i] ⟶ Δ[n] where app m (α : { α : Δ[n].obj m // _ }) := α @@ -208,8 +221,7 @@ def const (n : ℕ) (i k : Fin (n+3)) (m : SimplexCategoryᵒᵖ) : Λ[n+2, i].o This edge only exists if `{i, a, b}` has cardinality less than `n`. -/ @[simps] -def edge (n : ℕ) (i a b : Fin (n+1)) (hab : a ≤ b) (H : Finset.card {i, a, b} ≤ n) : - Λ[n, i] _[1] := by +def edge (n : ℕ) (i a b : Fin (n+1)) (hab : a ≤ b) (H : #{i, a, b} ≤ n) : Λ[n, i] _[1] := by refine ⟨standardSimplex.edge n a b hab, ?range⟩ case range => suffices ∃ x, ¬i = x ∧ ¬a = x ∧ ¬b = x by @@ -303,7 +315,7 @@ lemma hom_ext {n : ℕ} {i : Fin (n+2)} {S : SSet} (σ₁ σ₂ : Λ[n+1, i] ⟶ have H₁ := congrFun (σ₁.naturality (factor_δ f' j).op) (face i j hji) have H₂ := congrFun (σ₂.naturality (factor_δ f' j).op) (face i j hji) dsimp at H₁ H₂ - erw [H, H₁, H₂, h _ hji] + rw [H, H₁, H₂, h _ hji] end horn @@ -335,18 +347,90 @@ instance Truncated.hasColimits {n : ℕ} : HasColimits (Truncated n) := by dsimp only [Truncated] infer_instance --- Porting note (#5229): added an `ext` lemma. +/-- The ulift functor `SSet.Truncated.{u} ⥤ SSet.Truncated.{max u v}` on truncated +simplicial sets. -/ +def Truncated.uliftFunctor (k : ℕ) : SSet.Truncated.{u} k ⥤ SSet.Truncated.{max u v} k := + (whiskeringRight _ _ _).obj CategoryTheory.uliftFunctor.{v, u} + @[ext] lemma Truncated.hom_ext {n : ℕ} {X Y : Truncated n} {f g : X ⟶ Y} (w : ∀ n, f.app n = g.app n) : f = g := NatTrans.ext (funext w) -/-- The skeleton functor on simplicial sets. -/ -def sk (n : ℕ) : SSet ⥤ SSet.Truncated n := - SimplicialObject.sk n +/-- The truncation functor on simplicial sets. -/ +abbrev truncation (n : ℕ) : SSet ⥤ SSet.Truncated n := SimplicialObject.truncation n instance {n} : Inhabited (SSet.Truncated n) := - ⟨(sk n).obj <| Δ[0]⟩ + ⟨(truncation n).obj <| Δ[0]⟩ + + +open SimplexCategory + +noncomputable section + +/-- The n-skeleton as a functor `SSet.Truncated n ⥤ SSet`. -/ +protected abbrev Truncated.sk (n : ℕ) : SSet.Truncated n ⥤ SSet.{u} := + SimplicialObject.Truncated.sk n + +/-- The n-coskeleton as a functor `SSet.Truncated n ⥤ SSet`. -/ +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 + +/-- The n-coskeleton as an endofunctor on `SSet`. -/ +abbrev cosk (n : ℕ) : SSet ⥤ SSet := SimplicialObject.cosk n + +end + +section adjunctions + +/-- The adjunction between the n-skeleton and n-truncation.-/ +noncomputable def skAdj (n : ℕ) : Truncated.sk n ⊣ truncation.{u} n := + SimplicialObject.skAdj n + +/-- The adjunction between n-truncation and the n-coskeleton.-/ +noncomputable def coskAdj (n : ℕ) : truncation.{u} n ⊣ Truncated.cosk n := + SimplicialObject.coskAdj n + +namespace Truncated + +instance cosk_reflective (n) : IsIso (coskAdj n).counit := + SimplicialObject.Truncated.cosk_reflective n + +instance sk_coreflective (n) : IsIso (skAdj n).unit := + SimplicialObject.Truncated.sk_coreflective n + +/-- Since `Truncated.inclusion` is fully faithful, so is right Kan extension along it.-/ +noncomputable def cosk.fullyFaithful (n) : + (Truncated.cosk n).FullyFaithful := + SimplicialObject.Truncated.cosk.fullyFaithful n + +instance cosk.full (n) : (Truncated.cosk n).Full := + SimplicialObject.Truncated.cosk.full n + +instance cosk.faithful (n) : (Truncated.cosk n).Faithful := + SimplicialObject.Truncated.cosk.faithful n + +noncomputable instance coskAdj.reflective (n) : Reflective (Truncated.cosk n) := + SimplicialObject.Truncated.coskAdj.reflective n + +/-- Since `Truncated.inclusion` is fully faithful, so is left Kan extension along it.-/ +noncomputable def sk.fullyFaithful (n) : + (Truncated.sk n).FullyFaithful := SimplicialObject.Truncated.sk.fullyFaithful n + +instance sk.full (n) : (Truncated.sk n).Full := SimplicialObject.Truncated.sk.full n + +instance sk.faithful (n) : (Truncated.sk n).Faithful := + SimplicialObject.Truncated.sk.faithful n + +noncomputable instance skAdj.coreflective (n) : Coreflective (Truncated.sk n) := + SimplicialObject.Truncated.skAdj.coreflective n + +end Truncated + +end adjunctions /-- The category of augmented simplicial sets, as a particular case of augmented simplicial objects. -/ @@ -364,7 +448,7 @@ noncomputable def standardSimplex : SimplexCategory ⥤ SSet.Augmented.{u} where obj Δ := { left := SSet.standardSimplex.obj Δ right := terminal _ - hom := { app := fun Δ' => terminal.from _ } } + hom := { app := fun _ => terminal.from _ } } map θ := { left := SSet.standardSimplex.map θ right := terminal.from _ } diff --git a/Mathlib/AlgebraicTopology/KanComplex.lean b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean similarity index 95% rename from Mathlib/AlgebraicTopology/KanComplex.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean index 73a6d4e026c32..531bc99ebc39c 100644 --- a/Mathlib/AlgebraicTopology/KanComplex.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic /-! # Kan complexes diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean index 0c12ff6bec5e4..fbee414ae5bd4 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean @@ -3,7 +3,7 @@ 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, Jack McKoen -/ -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic import Mathlib.CategoryTheory.ChosenFiniteProducts.FunctorCategory import Mathlib.CategoryTheory.Monoidal.Types.Basic diff --git a/Mathlib/AlgebraicTopology/Nerve.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean similarity index 92% rename from Mathlib/AlgebraicTopology/Nerve.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean index 611b1fea9cd22..c82254637aaf3 100644 --- a/Mathlib/AlgebraicTopology/Nerve.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Joël Riou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic import Mathlib.CategoryTheory.ComposableArrows /-! @@ -39,7 +39,7 @@ instance {C : Type*} [Category C] {Δ : SimplexCategoryᵒᵖ} : Category ((nerv @[simps] def nerveFunctor : Cat ⥤ SSet where obj C := nerve C - map F := { app := fun Δ => (F.mapComposableArrows _).obj } + map F := { app := fun _ => (F.mapComposableArrows _).obj } namespace Nerve diff --git a/Mathlib/AlgebraicTopology/Quasicategory.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean similarity index 97% rename from Mathlib/AlgebraicTopology/Quasicategory.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean index a2590b4c956f6..381e65660f632 100644 --- a/Mathlib/AlgebraicTopology/Quasicategory.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.AlgebraicTopology.KanComplex +import Mathlib.AlgebraicTopology.SimplicialSet.KanComplex /-! # Quasicategories diff --git a/Mathlib/AlgebraicTopology/SingularSet.lean b/Mathlib/AlgebraicTopology/SingularSet.lean index bc3d246833408..d97397b1c6019 100644 --- a/Mathlib/AlgebraicTopology/SingularSet.lean +++ b/Mathlib/AlgebraicTopology/SingularSet.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Kim Morrison, Adam Topaz -/ -import Mathlib.AlgebraicTopology.SimplicialSet +import Mathlib.AlgebraicTopology.SimplicialSet.Basic import Mathlib.AlgebraicTopology.TopologicalSimplex import Mathlib.CategoryTheory.Limits.Presheaf import Mathlib.Topology.Category.TopCat.Limits.Basic diff --git a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean index 447b1a9770800..7d8574e79627f 100644 --- a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean @@ -241,7 +241,7 @@ def φ (f : X ⟶ Y) (n : ℕ) : s.N n ⟶ Y _[n] := theorem cofan_inj_comp_app (f : X ⟶ Y) {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : (s.cofan Δ).inj A ≫ f.app Δ = s.φ f A.1.unop.len ≫ Y.map A.e.op := by simp only [cofan_inj_eq_assoc, φ, assoc] - erw [NatTrans.naturality] + rw [NatTrans.naturality] theorem hom_ext' {Z : C} {Δ : SimplexCategoryᵒᵖ} (f g : X.obj Δ ⟶ Z) (h : ∀ A : IndexSet Δ, (s.cofan Δ).inj A ≫ f = (s.cofan Δ).inj A ≫ g) : f = g := @@ -339,7 +339,7 @@ instance : Category (Split C) where Hom := Split.Hom id S := { F := 𝟙 _ - f := fun n => 𝟙 _ } + f := fun _ => 𝟙 _ } comp Φ₁₂ Φ₂₃ := { F := Φ₁₂.F ≫ Φ₂₃.F f := fun n => Φ₁₂.f n ≫ Φ₂₃.f n @@ -351,7 +351,6 @@ variable {C} namespace Split --- Porting note: added as `Hom.ext` is not triggered automatically @[ext] theorem hom_ext {S₁ S₂ : Split C} (Φ₁ Φ₂ : S₁ ⟶ S₂) (h : ∀ n : ℕ, Φ₁.f n = Φ₂.f n) : Φ₁ = Φ₂ := Hom.ext _ _ h @@ -383,7 +382,7 @@ theorem comp_f {S₁ S₂ S₃ : Split C} (Φ₁₂ : S₁ ⟶ S₂) (Φ₂₃ : theorem cofan_inj_naturality_symm {S₁ S₂ : Split C} (Φ : S₁ ⟶ S₂) {Δ : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) : (S₁.s.cofan Δ).inj A ≫ Φ.F.app Δ = Φ.f A.1.unop.len ≫ (S₂.s.cofan Δ).inj A := by - erw [S₁.s.cofan_inj_eq, S₂.s.cofan_inj_eq, assoc, Φ.F.naturality, ← Φ.comm_assoc] + rw [S₁.s.cofan_inj_eq, S₂.s.cofan_inj_eq, assoc, Φ.F.naturality, ← Φ.comm_assoc] variable (C) diff --git a/Mathlib/Analysis/Analytic/Basic.lean b/Mathlib/Analysis/Analytic/Basic.lean index cd994fb7364b8..b04809638446e 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.lean @@ -292,7 +292,7 @@ theorem radius_eq_top_iff_summable_norm (p : FormalMultilinearSeries 𝕜 E F) : /-- If the radius of `p` is positive, then `‖pₙ‖` grows at most geometrically. -/ theorem le_mul_pow_of_radius_pos (p : FormalMultilinearSeries 𝕜 E F) (h : 0 < p.radius) : - ∃ (C r : _) (hC : 0 < C) (_ : 0 < r), ∀ n, ‖p n‖ ≤ C * r ^ n := by + ∃ (C r : _) (_ : 0 < C) (_ : 0 < r), ∀ n, ‖p n‖ ≤ C * r ^ n := by rcases ENNReal.lt_iff_exists_nnreal_btwn.1 h with ⟨r, r0, rlt⟩ have rpos : 0 < (r : ℝ) := by simp [ENNReal.coe_pos.1 r0] rcases norm_le_div_pow_of_pos_of_lt_radius p rpos rlt with ⟨C, Cpos, hCp⟩ @@ -638,7 +638,7 @@ theorem HasFPowerSeriesWithinOnBall.coeff_zero (hf : HasFPowerSeriesWithinOnBall (v : Fin 0 → E) : pf 0 v = f x := by have v_eq : v = fun i => 0 := Subsingleton.elim _ _ have zero_mem : (0 : E) ∈ EMetric.ball (0 : E) r := by simp [hf.r_pos] - have : ∀ i, i ≠ 0 → (pf i fun j => 0) = 0 := by + have : ∀ i, i ≠ 0 → (pf i fun _ => 0) = 0 := by intro i hi have : 0 < i := pos_iff_ne_zero.2 hi exact ContinuousMultilinearMap.map_coord_zero _ (⟨0, this⟩ : Fin i) rfl @@ -890,7 +890,7 @@ theorem HasFPowerSeriesWithinOnBall.tendsto_partialSum_prod {y : E} simp only [FormalMultilinearSeries.partialSum] abel _ ≤ ‖p.partialSum k z - p.partialSum k y‖ + ‖∑ i ∈ Ico k n, p i (fun _ ↦ z)‖ - + ‖- ∑ i ∈ Ico k n, p i (fun _ ↦ y)‖ := norm_add₃_le _ _ _ + + ‖- ∑ i ∈ Ico k n, p i (fun _ ↦ y)‖ := norm_add₃_le _ ≤ ε / 4 + ε / 4 + ε / 4 := by gcongr · exact I _ h'z @@ -1244,7 +1244,7 @@ protected theorem HasFPowerSeriesOnBall.continuousOn (hf : HasFPowerSeriesOnBall protected theorem HasFPowerSeriesWithinOnBall.continuousWithinAt_insert (hf : HasFPowerSeriesWithinOnBall f p s x r) : ContinuousWithinAt f (insert x s) x := by - apply (hf.continuousOn.continuousWithinAt (x := x) (by simp [hf.r_pos])).mono_of_mem + apply (hf.continuousOn.continuousWithinAt (x := x) (by simp [hf.r_pos])).mono_of_mem_nhdsWithin exact inter_mem_nhdsWithin _ (EMetric.ball_mem_nhds x hf.r_pos) protected theorem HasFPowerSeriesWithinOnBall.continuousWithinAt diff --git a/Mathlib/Analysis/Analytic/CPolynomial.lean b/Mathlib/Analysis/Analytic/CPolynomial.lean index 9576f0b22c613..263a5246c148b 100644 --- a/Mathlib/Analysis/Analytic/CPolynomial.lean +++ b/Mathlib/Analysis/Analytic/CPolynomial.lean @@ -567,7 +567,7 @@ open FormalMultilinearSeries protected theorem hasFiniteFPowerSeriesOnBall : HasFiniteFPowerSeriesOnBall f f.toFormalMultilinearSeries 0 (Fintype.card ι + 1) ⊤ := - .mk' (fun m hm ↦ dif_neg (Nat.succ_le_iff.mp hm).ne) ENNReal.zero_lt_top fun y _ ↦ by + .mk' (fun _ hm ↦ dif_neg (Nat.succ_le_iff.mp hm).ne) ENNReal.zero_lt_top fun y _ ↦ by rw [Finset.sum_eq_single_of_mem _ (Finset.self_mem_range_succ _), zero_add] · rw [toFormalMultilinearSeries, dif_pos rfl]; rfl · intro m _ ne; rw [toFormalMultilinearSeries, dif_neg ne.symm]; rfl diff --git a/Mathlib/Analysis/Analytic/ChangeOrigin.lean b/Mathlib/Analysis/Analytic/ChangeOrigin.lean index 1658276bf5b4a..ff6fdee77e8d2 100644 --- a/Mathlib/Analysis/Analytic/ChangeOrigin.lean +++ b/Mathlib/Analysis/Analytic/ChangeOrigin.lean @@ -60,7 +60,7 @@ p (k + l) (s.piecewise (fun _ ↦ x) (fun _ ↦ y))` def changeOriginSeriesTerm (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) : E[×l]→L[𝕜] E[×k]→L[𝕜] F := let a := ContinuousMultilinearMap.curryFinFinset 𝕜 E F hs - (by erw [Finset.card_compl, Fintype.card_fin, hs, add_tsub_cancel_right]) + (by rw [Finset.card_compl, Fintype.card_fin, hs, add_tsub_cancel_right]) a (p (k + l)) theorem changeOriginSeriesTerm_apply (k l : ℕ) (s : Finset (Fin (k + l))) (hs : s.card = l) diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index c73176c9a5ec5..e439182fb3de1 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -186,7 +186,7 @@ def compAlongComposition {n : ℕ} (p : FormalMultilinearSeries 𝕜 E F) (c : C simp only [applyComposition_update, ContinuousMultilinearMap.map_smul] cont := f.cont.comp <| - continuous_pi fun i => (coe_continuous _).comp <| continuous_pi fun j => continuous_apply _ + continuous_pi fun _ => (coe_continuous _).comp <| continuous_pi fun _ => continuous_apply _ @[simp] theorem compAlongComposition_apply {n : ℕ} (p : FormalMultilinearSeries 𝕜 E F) (c : Composition n) diff --git a/Mathlib/Analysis/Analytic/Constructions.lean b/Mathlib/Analysis/Analytic/Constructions.lean index 42de038a5780f..c3c7fe59dc3a5 100644 --- a/Mathlib/Analysis/Analytic/Constructions.lean +++ b/Mathlib/Analysis/Analytic/Constructions.lean @@ -38,7 +38,7 @@ variable {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A] theorem hasFPowerSeriesOnBall_const {c : F} {e : E} : HasFPowerSeriesOnBall (fun _ => c) (constFormalMultilinearSeries 𝕜 E c) e ⊤ := by - refine ⟨by simp, WithTop.zero_lt_top, fun _ => hasSum_single 0 fun n hn => ?_⟩ + refine ⟨by simp, WithTop.top_pos, fun _ => hasSum_single 0 fun n hn => ?_⟩ simp [constFormalMultilinearSeries_apply hn] theorem hasFPowerSeriesAt_const {c : F} {e : E} : @@ -456,7 +456,7 @@ lemma HasFPowerSeriesWithinOnBall.pi apply FormalMultilinearSeries.le_radius_pi (fun i ↦ ?_) exact (hf i).r_le r_pos := hr - hasSum {y} m hy := Pi.hasSum.2 (fun i ↦ (hf i).hasSum m hy) + hasSum {_} m hy := Pi.hasSum.2 (fun i ↦ (hf i).hasSum m hy) lemma hasFPowerSeriesWithinOnBall_pi_iff (hr : 0 < r) : HasFPowerSeriesWithinOnBall (fun x ↦ (f · x)) (FormalMultilinearSeries.pi p) s e r diff --git a/Mathlib/Analysis/Analytic/Inverse.lean b/Mathlib/Analysis/Analytic/Inverse.lean index eadc577c91124..4b94111adff37 100644 --- a/Mathlib/Analysis/Analytic/Inverse.lean +++ b/Mathlib/Analysis/Analytic/Inverse.lean @@ -5,6 +5,7 @@ Authors: Sébastien Gouëzel -/ import Mathlib.Analysis.Analytic.Composition import Mathlib.Analysis.Analytic.Linear +import Mathlib.Tactic.Positivity.Finset /-! @@ -272,7 +273,7 @@ theorem rightInv_coeff (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] congr (config := { closePost := false }) 1 ext v have N : 0 < n + 2 := by norm_num - have : ((p 1) fun i : Fin 1 => 0) = 0 := ContinuousMultilinearMap.map_zero _ + have : ((p 1) fun _ : Fin 1 => 0) = 0 := ContinuousMultilinearMap.map_zero _ simp [comp_rightInv_aux1 N, lt_irrefl n, this, comp_rightInv_aux2, -Set.toFinset_setOf] /-! ### Coincidence of the left and the right inverse -/ @@ -630,10 +631,10 @@ lemma HasFPowerSeriesAt.eventually_hasSum_of_comp {f : E → F} {g : F → G} simp only [id_eq, eventually_atTop, ge_iff_le] rcases mem_nhds_iff.1 hu with ⟨v, vu, v_open, hv⟩ obtain ⟨a₀, b₀, hab⟩ : ∃ a₀ b₀, ∀ (a b : ℕ), a₀ ≤ a → b₀ ≤ b → - q.partialSum a (p.partialSum b y - (p 0) fun x ↦ 0) ∈ v := by + q.partialSum a (p.partialSum b y - (p 0) fun _ ↦ 0) ∈ v := by simpa using hy (v_open.mem_nhds hv) refine ⟨a₀, fun a ha ↦ ?_⟩ - have : Tendsto (fun b ↦ q.partialSum a (p.partialSum b y - (p 0) fun x ↦ 0)) atTop + have : Tendsto (fun b ↦ q.partialSum a (p.partialSum b y - (p 0) fun _ ↦ 0)) atTop (𝓝 (q.partialSum a (f (x + y) - f x))) := by have : ContinuousAt (q.partialSum a) (f (x + y) - f x) := (partialSum_continuous q a).continuousAt diff --git a/Mathlib/Analysis/Analytic/Linear.lean b/Mathlib/Analysis/Analytic/Linear.lean index e527cda45057c..bd405daef5895 100644 --- a/Mathlib/Analysis/Analytic/Linear.lean +++ b/Mathlib/Analysis/Analytic/Linear.lean @@ -77,30 +77,26 @@ def fpowerSeriesBilinear (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : Formal | 2 => f.uncurryBilinear | _ => 0 +@[simp] theorem fpowerSeriesBilinear_apply_zero (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : fpowerSeriesBilinear f x 0 = ContinuousMultilinearMap.uncurry0 𝕜 _ (f x.1 x.2) := rfl +@[simp] theorem fpowerSeriesBilinear_apply_one (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : fpowerSeriesBilinear f x 1 = (continuousMultilinearCurryFin1 𝕜 (E × F) G).symm (f.deriv₂ x) := rfl +@[simp] theorem fpowerSeriesBilinear_apply_two (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : fpowerSeriesBilinear f x 2 = f.uncurryBilinear := rfl +@[simp] theorem fpowerSeriesBilinear_apply_add_three (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) (n) : fpowerSeriesBilinear f x (n + 3) = 0 := rfl -attribute - [eqns - fpowerSeriesBilinear_apply_zero - fpowerSeriesBilinear_apply_one - fpowerSeriesBilinear_apply_two - fpowerSeriesBilinear_apply_add_three] fpowerSeriesBilinear -attribute [simp] fpowerSeriesBilinear - @[simp] theorem fpowerSeriesBilinear_radius (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : (f.fpowerSeriesBilinear x).radius = ∞ := diff --git a/Mathlib/Analysis/Analytic/OfScalars.lean b/Mathlib/Analysis/Analytic/OfScalars.lean new file mode 100644 index 0000000000000..531079814dcc6 --- /dev/null +++ b/Mathlib/Analysis/Analytic/OfScalars.lean @@ -0,0 +1,131 @@ +/- +Copyright (c) 2024 Edward Watine. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Edward Watine +-/ +import Mathlib.Analysis.Analytic.Basic + + +/-! +# Scalar series + +This file contains API for analytic functions `∑ cᵢ • xⁱ` defined in terms of scalars +`c₀, c₁, c₂, …`. +## Main definitions / results: + * `FormalMultilinearSeries.ofScalars`: the formal power series `∑ cᵢ • xⁱ`. + * `FormalMultilinearSeries.ofScalars_radius_eq_of_tendsto`: the ratio test for an analytic function + defined in terms of a formal power series `∑ cᵢ • xⁱ`. +-/ + +namespace FormalMultilinearSeries + +section Field + +variable {𝕜 : Type*} (E : Type*) [Field 𝕜] [Ring E] [Algebra 𝕜 E] [TopologicalSpace E] + [TopologicalRing E] (c : ℕ → 𝕜) + +/-- Formal power series of `∑ cᵢ • xⁱ` for some scalar field `𝕜` and ring algebra `E`-/ +def ofScalars : FormalMultilinearSeries 𝕜 E E := + fun n ↦ c n • ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n E + +variable {E} + +/-- The sum of the formal power series. Takes the value `0` outside the radius of convergence. -/ +noncomputable def ofScalarsSum (x : E) := (ofScalars E c).sum x + +theorem ofScalars_apply_eq (x : E) (n : ℕ) : + ofScalars E c n (fun _ ↦ x) = c n • x ^ n := by + simp [ofScalars] + +/-- This naming follows the convention of `NormedSpace.expSeries_apply_eq'`. -/ +theorem ofScalars_apply_eq' (x : E) : + (fun n ↦ ofScalars E c n (fun _ ↦ x)) = fun n ↦ c n • x ^ n := by + simp [ofScalars] + +theorem ofScalars_sum_eq (x : E) : ofScalarsSum c x = + ∑' n, c n • x ^ n := tsum_congr fun n => ofScalars_apply_eq c x n + +theorem ofScalarsSum_eq_tsum : ofScalarsSum c = + fun (x : E) => ∑' n : ℕ, c n • x ^ n := funext (ofScalars_sum_eq c) + +@[simp] +theorem ofScalars_op [T2Space E] (x : E) : + ofScalarsSum c (MulOpposite.op x) = MulOpposite.op (ofScalarsSum c x) := by + simp [ofScalars, ofScalars_sum_eq, ← MulOpposite.op_pow, ← MulOpposite.op_smul, tsum_op] + +@[simp] +theorem ofScalars_unop [T2Space E] (x : Eᵐᵒᵖ) : + ofScalarsSum c (MulOpposite.unop x) = MulOpposite.unop (ofScalarsSum c x) := by + simp [ofScalars, ofScalars_sum_eq, ← MulOpposite.unop_pow, ← MulOpposite.unop_smul, tsum_unop] + +@[simp] +theorem ofScalars_eq_zero [Nontrivial E] (n : ℕ) : ofScalars E c n = 0 ↔ c n = 0 := by + rw [ofScalars, smul_eq_zero (c := c n) (x := ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n E)] + refine or_iff_left (ContinuousMultilinearMap.ext_iff.1.mt <| not_forall_of_exists_not ?_) + use fun _ ↦ 1 + simp + +end Field + +section Normed + +open Filter +open scoped Topology + +variable {𝕜 : Type*} (E : Type*) [NontriviallyNormedField 𝕜] [NormedRing E] + [NormedAlgebra 𝕜 E] (c : ℕ → 𝕜) (n : ℕ) + +theorem ofScalars_norm_eq_mul : + ‖ofScalars E c n‖ = ‖c n‖ * ‖ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n E‖ := by + rw [ofScalars, norm_smul (c n) (ContinuousMultilinearMap.mkPiAlgebraFin 𝕜 n E)] + +theorem ofScalars_norm_le (hn : n > 0) : ‖ofScalars E c n‖ ≤ ‖c n‖ := by + simp only [ofScalars_norm_eq_mul] + exact (mul_le_of_le_one_right (norm_nonneg _) + (ContinuousMultilinearMap.norm_mkPiAlgebraFin_le_of_pos hn)) + +@[simp] +theorem ofScalars_norm [NormOneClass E] : ‖ofScalars E c n‖ = ‖c n‖ := by + simp [ofScalars_norm_eq_mul] + +/-- The radius of convergence of a scalar series is the inverse of the ratio of the norms of the +coefficients. -/ +theorem ofScalars_radius_eq_inv_of_tendsto [NormOneClass E] {r : NNReal} (hr : r ≠ 0) + (hc : Tendsto (fun n ↦ ‖c n.succ‖ / ‖c n‖) atTop (𝓝 r)) : + (ofScalars E c).radius = ENNReal.ofNNReal r⁻¹ := by + have hc' {r' : NNReal} (hr' : (r' : ℝ) ≠ 0) : + Tendsto (fun n ↦ ‖‖ofScalars E c (n + 1)‖ * r' ^ (n + 1)‖ / + ‖‖ofScalars E c n‖ * r' ^ n‖) atTop (𝓝 ↑(r' * r)) := by + simp_rw [norm_mul, norm_norm, ofScalars_norm, mul_div_mul_comm, ← norm_div, pow_succ, + mul_div_right_comm, div_self (pow_ne_zero _ hr'), one_mul, norm_div, NNReal.norm_eq] + exact mul_comm r' r ▸ Filter.Tendsto.mul hc tendsto_const_nhds + apply le_antisymm <;> refine ENNReal.le_of_forall_nnreal_lt (fun r' hr' ↦ ?_) + · rw [ENNReal.coe_le_coe, NNReal.le_inv_iff_mul_le hr] + have := FormalMultilinearSeries.summable_norm_mul_pow _ hr' + contrapose! this + have hrz : (r' : ℝ) ≠ 0 := by aesop + apply not_summable_of_ratio_test_tendsto_gt_one this + exact hc' (by aesop) + · rw [ENNReal.coe_lt_coe, NNReal.lt_inv_iff_mul_lt hr] at hr' + by_cases hrz : r' = 0 + · simp [hrz] + · apply FormalMultilinearSeries.le_radius_of_summable_norm + refine summable_of_ratio_test_tendsto_lt_one hr' ?_ <| hc' (NNReal.coe_ne_zero.2 hrz) + refine (Tendsto.eventually_ne hc (NNReal.coe_ne_zero.2 hr)).mp (Eventually.of_forall ?_) + simp_rw [div_ne_zero_iff, ofScalars_norm, mul_ne_zero_iff] + aesop + +/-- A convenience lemma restating the result of `ofScalars_radius_eq_inv_of_tendsto` under +the inverse ratio. -/ +theorem ofScalars_radius_eq_of_tendsto [NormOneClass E] {r : NNReal} (hr : r ≠ 0) + (hc : Tendsto (fun n ↦ ‖c n‖ / ‖c n.succ‖) atTop (𝓝 r)) : + (ofScalars E c).radius = ENNReal.ofNNReal r := by + suffices Tendsto (fun n ↦ ‖c n.succ‖ / ‖c n‖) atTop (𝓝 r⁻¹) by + convert ofScalars_radius_eq_inv_of_tendsto E c (inv_ne_zero hr) this + simp + convert (continuousAt_inv₀ <| NNReal.coe_ne_zero.mpr hr).tendsto.comp hc + simp + +end Normed + +end FormalMultilinearSeries diff --git a/Mathlib/Analysis/Analytic/Within.lean b/Mathlib/Analysis/Analytic/Within.lean index 7703eb9524ef0..b9f6a8bda1b70 100644 --- a/Mathlib/Analysis/Analytic/Within.lean +++ b/Mathlib/Analysis/Analytic/Within.lean @@ -113,6 +113,7 @@ result for `AnalyticOn`, as this requires a bit more work to show that local ext be stitched together. -/ +set_option linter.style.multiGoal false in /-- `f` has power series `p` at `x` iff some local extension of `f` has that series -/ lemma hasFPowerSeriesWithinOnBall_iff_exists_hasFPowerSeriesOnBall [CompleteSpace F] {f : E → F} {p : FormalMultilinearSeries 𝕜 E F} {s : Set E} {x : E} {r : ℝ≥0∞} : diff --git a/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean b/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean index 42aba8ff24d51..d0a29face182e 100644 --- a/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean +++ b/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean @@ -171,7 +171,7 @@ open Asymptotics section NormedField -variable {α β : Type*} [NormedField β] {t u v w : α → β} {l : Filter α} +variable {α β : Type*} [NormedField β] {u v : α → β} {l : Filter α} theorem isEquivalent_iff_exists_eq_mul : u ~[l] v ↔ ∃ (φ : α → β) (_ : Tendsto φ l (𝓝 1)), u =ᶠ[l] φ * v := by diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 040386d779755..2ac86221aead4 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -251,7 +251,7 @@ theorem isLittleO_iff_nat_mul_le_aux (h₀ : (∀ x, 0 ≤ ‖f x‖) ∨ ∀ x, rcases exists_nat_gt ε⁻¹ with ⟨n, hn⟩ have hn₀ : (0 : ℝ) < n := (inv_pos.2 ε0).trans hn refine ((isBigOWith_inv hn₀).2 (H n)).bound.mono fun x hfg => ?_ - refine hfg.trans (mul_le_mul_of_nonneg_right (inv_le_of_inv_le ε0 hn.le) ?_) + refine hfg.trans (mul_le_mul_of_nonneg_right (inv_le_of_inv_le₀ ε0 hn.le) ?_) refine h₀.elim (fun hf => nonneg_of_mul_nonneg_right ((hf x).trans hfg) ?_) fun h => h x exact inv_pos.2 hn₀ @@ -1450,7 +1450,7 @@ theorem IsBigOWith.inv_rev {f : α → 𝕜} {g : α → 𝕜'} (h : IsBigOWith rcases eq_or_ne (f x) 0 with hx | hx · simp only [hx, h₀ hx, inv_zero, norm_zero, mul_zero, le_rfl] · have hc : 0 < c := pos_of_mul_pos_left ((norm_pos_iff.2 hx).trans_le hle) (norm_nonneg _) - replace hle := inv_le_inv_of_le (norm_pos_iff.2 hx) hle + replace hle := inv_anti₀ (norm_pos_iff.2 hx) hle simpa only [norm_inv, mul_inv, ← div_eq_inv_mul, div_le_iff₀ hc] using hle theorem IsBigO.inv_rev {f : α → 𝕜} {g : α → 𝕜'} (h : f =O[l] g) @@ -1822,7 +1822,7 @@ theorem IsBigOWith.right_le_sub_of_lt_one {f₁ f₂ : α → E'} (h : IsBigOWit theorem IsBigOWith.right_le_add_of_lt_one {f₁ f₂ : α → E'} (h : IsBigOWith c l f₁ f₂) (hc : c < 1) : IsBigOWith (1 / (1 - c)) l f₂ fun x => f₁ x + f₂ x := - (h.neg_right.right_le_sub_of_lt_one hc).neg_right.of_neg_left.congr rfl (fun x ↦ rfl) fun x ↦ by + (h.neg_right.right_le_sub_of_lt_one hc).neg_right.of_neg_left.congr rfl (fun _ ↦ rfl) fun x ↦ by rw [neg_sub, sub_neg_eq_add] @[deprecated (since := "2024-01-31")] @@ -1872,7 +1872,7 @@ theorem isBigO_nat_atTop_iff {f : ℕ → E''} {g : ℕ → F''} (h : ∀ x, g x theorem isBigO_one_nat_atTop_iff {f : ℕ → E''} : f =O[atTop] (fun _n => 1 : ℕ → ℝ) ↔ ∃ C, ∀ n, ‖f n‖ ≤ C := - Iff.trans (isBigO_nat_atTop_iff fun n h => (one_ne_zero h).elim) <| by + Iff.trans (isBigO_nat_atTop_iff fun _ h => (one_ne_zero h).elim) <| by simp only [norm_one, mul_one] theorem isBigOWith_pi {ι : Type*} [Fintype ι] {E' : ι → Type*} [∀ i, NormedAddCommGroup (E' i)] @@ -1958,8 +1958,8 @@ theorem isBigOWith_congr (e : PartialHomeomorph α β) {b : β} (hb : b ∈ e.ta rwa [ContinuousAt, e.rightInvOn hb] at this, fun h => (h.comp_tendsto (e.continuousAt_symm hb)).congr' rfl - ((e.eventually_right_inverse hb).mono fun x hx => congr_arg f hx) - ((e.eventually_right_inverse hb).mono fun x hx => congr_arg g hx)⟩ + ((e.eventually_right_inverse hb).mono fun _ hx => congr_arg f hx) + ((e.eventually_right_inverse hb).mono fun _ hx => congr_arg g hx)⟩ /-- Transfer `IsBigO` over a `PartialHomeomorph`. -/ theorem isBigO_congr (e : PartialHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} @@ -2048,4 +2048,12 @@ end IsBigORev end ContinuousOn +/-- The (scalar) product of a sequence that tends to zero with a bounded one also tends to zero. -/ +lemma NormedField.tendsto_zero_smul_of_tendsto_zero_of_bounded {ι 𝕜 𝔸 : Type*} + [NormedDivisionRing 𝕜] [NormedAddCommGroup 𝔸] [Module 𝕜 𝔸] [BoundedSMul 𝕜 𝔸] {l : Filter ι} + {ε : ι → 𝕜} {f : ι → 𝔸} (hε : Tendsto ε l (𝓝 0)) (hf : IsBoundedUnder (· ≤ ·) l (norm ∘ f)) : + Tendsto (ε • f) l (𝓝 0) := by + rw [← isLittleO_one_iff 𝕜] at hε ⊢ + simpa using IsLittleO.smul_isBigO hε (hf.isBigO_const (one_ne_zero : (1 : 𝕜) ≠ 0)) + set_option linter.style.longFile 2200 diff --git a/Mathlib/Analysis/BoxIntegral/Basic.lean b/Mathlib/Analysis/BoxIntegral/Basic.lean index e9d54c402baef..44c6028cdd79d 100644 --- a/Mathlib/Analysis/BoxIntegral/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Basic.lean @@ -512,8 +512,8 @@ theorem dist_integralSum_sum_integral_le_of_memBaseSet_of_iUnion_eq (h : Integra -- Let us prove that the distance is less than or equal to `ε + δ` for all positive `δ`. refine le_of_forall_pos_le_add fun δ δ0 => ?_ -- First we choose some constants. - set δ' : ℝ := δ / (π₀.boxes.card + 1) - have H0 : 0 < (π₀.boxes.card + 1 : ℝ) := Nat.cast_add_one_pos _ + set δ' : ℝ := δ / (#π₀.boxes + 1) + have H0 : 0 < (#π₀.boxes + 1 : ℝ) := Nat.cast_add_one_pos _ have δ'0 : 0 < δ' := div_pos δ0 H0 set C := max π₀.distortion π₀.compl.distortion /- Next we choose a tagged partition of each `J ∈ π₀` such that the integral sum of `f` over this @@ -665,7 +665,7 @@ theorem integrable_of_bounded_and_ae_continuousWithinAt [CompleteSpace E] {I : B let t₂ (J : Box ι) : ℝⁿ := (π₂.infPrepartition π₁.toPrepartition).tag J let B := (π₁.toPrepartition ⊓ π₂.toPrepartition).boxes classical - let B' := B.filter (fun J ↦ J.toSet ⊆ U) + let B' := {J ∈ B | J.toSet ⊆ U} have hB' : B' ⊆ B := B.filter_subset (fun J ↦ J.toSet ⊆ U) have μJ_ne_top : ∀ J ∈ B, μ J ≠ ⊤ := fun J hJ ↦ lt_top_iff_ne_top.1 <| lt_of_le_of_lt (μ.mono (Prepartition.le_of_mem' _ J hJ)) μI @@ -795,7 +795,7 @@ theorem HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (hl : l.bRiemann = /- For the boxes such that `π.tag J ∈ s`, we use the fact that at most `2 ^ #ι` boxes have the same tag. -/ specialize hlH hsne - have : ∀ J ∈ π.boxes.filter fun J => π.tag J ∈ s, + have : ∀ J ∈ {J ∈ π.boxes | π.tag J ∈ s}, dist (vol J (f <| π.tag J)) (g J) ≤ εs (π.tag J) := fun J hJ ↦ by rw [Finset.mem_filter] at hJ; cases' hJ with hJ hJs refine Hδ₁ c _ ⟨π.tag_mem_Icc _, hJs⟩ _ (hεs0 _) _ (π.le_of_mem' _ hJ) ?_ @@ -815,9 +815,9 @@ theorem HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (hl : l.bRiemann = In this case the estimate is straightforward. -/ -- Porting note: avoided strange elaboration issues by rewriting using `calc` calc - dist (∑ J ∈ π.boxes.filter (¬tag π · ∈ s), vol J (f (tag π J))) - (∑ J ∈ π.boxes.filter (¬tag π · ∈ s), g J) - ≤ ∑ J ∈ π.boxes.filter (¬tag π · ∈ s), ε' * B J := dist_sum_sum_le_of_le _ fun J hJ ↦ by + dist (∑ J ∈ π.boxes with ¬tag π J ∈ s, vol J (f (tag π J))) + (∑ J ∈ π.boxes with ¬tag π J ∈ s, g J) + ≤ ∑ J ∈ π.boxes with ¬tag π J ∈ s, ε' * B J := dist_sum_sum_le_of_le _ fun J hJ ↦ by rw [Finset.mem_filter] at hJ; cases' hJ with hJ hJs refine Hδ₂ c _ ⟨π.tag_mem_Icc _, hJs⟩ _ ε'0 _ (π.le_of_mem' _ hJ) ?_ (fun hH => hπδ.2 hH J hJ) fun hD => (Finset.le_sup hJ).trans (hπδ.3 hD) @@ -872,11 +872,11 @@ less than or equal to `ε * B J`. Then `f` is McShane integrable on `I` with integral `g I`. -/ theorem HasIntegral.mcShane_of_forall_isLittleO (B : ι →ᵇᵃ[I] ℝ) (hB0 : ∀ J, 0 ≤ B J) - (g : ι →ᵇᵃ[I] F) (H : ∀ (c : ℝ≥0), ∀ x ∈ Box.Icc I, ∀ ε > (0 : ℝ), ∃ δ > 0, ∀ J ≤ I, + (g : ι →ᵇᵃ[I] F) (H : ∀ (_ : ℝ≥0), ∀ x ∈ Box.Icc I, ∀ ε > (0 : ℝ), ∃ δ > 0, ∀ J ≤ I, Box.Icc J ⊆ Metric.closedBall x δ → dist (vol J (f x)) (g J) ≤ ε * B J) : HasIntegral I McShane f vol (g I) := (HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (l := McShane) rfl B hB0 g ∅ countable_empty - (fun ⟨_x, hx⟩ => hx.elim) fun c x hx => hx.2.elim) <| by + (fun ⟨_x, hx⟩ => hx.elim) fun _ _ hx => hx.2.elim) <| by simpa only [McShane, Bool.coe_sort_false, false_imp_iff, true_imp_iff, diff_empty] using H end BoxIntegral diff --git a/Mathlib/Analysis/BoxIntegral/Integrability.lean b/Mathlib/Analysis/BoxIntegral/Integrability.lean index eaf2f17700f98..a8a89c7794886 100644 --- a/Mathlib/Analysis/BoxIntegral/Integrability.lean +++ b/Mathlib/Analysis/BoxIntegral/Integrability.lean @@ -321,7 +321,8 @@ theorem AEContinuous.hasBoxIntegral [CompleteSpace E] {f : (ι → ℝ) → E} ( constructor · let v := {x : (ι → ℝ) | ContinuousAt f x} have : AEStronglyMeasurable f (μ.restrict v) := - (ContinuousAt.continuousOn fun _ h ↦ h).aestronglyMeasurable (measurableSet_of_continuousAt f) + (continuousOn_of_forall_continuousAt fun _ h ↦ h).aestronglyMeasurable + (measurableSet_of_continuousAt f) refine this.mono_measure (Measure.le_iff.2 fun s hs ↦ ?_) repeat rw [μ.restrict_apply hs] apply le_of_le_of_eq <| μ.mono s.inter_subset_left diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean b/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean index a82e54fd54bb5..f82d7bce340fe 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean @@ -57,7 +57,7 @@ namespace BoxAdditiveMap open Box Prepartition Finset -variable {N : Type*} [AddCommMonoid M] [AddCommMonoid N] {I₀ : WithTop (Box ι)} {I J : Box ι} +variable {N : Type*} [AddCommMonoid M] [AddCommMonoid N] {I₀ : WithTop (Box ι)} {I : Box ι} {i : ι} instance : FunLike (ι →ᵇᵃ[I₀] M) (Box ι) M where @@ -72,7 +72,6 @@ theorem coe_mk (f h) : ⇑(mk f h : ι →ᵇᵃ[I₀] M) = f := rfl theorem coe_injective : Injective fun (f : ι →ᵇᵃ[I₀] M) x => f x := DFunLike.coe_injective --- Porting note (#10618): was @[simp], now can be proved by `simp` theorem coe_inj {f g : ι →ᵇᵃ[I₀] M} : (f : Box ι → M) = g ↔ f = g := DFunLike.coe_fn_eq theorem sum_partition_boxes (f : ι →ᵇᵃ[I₀] M) (hI : ↑I ≤ I₀) {π : Prepartition I} diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean index 788c55499703d..1686d1eac27e6 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean @@ -113,9 +113,9 @@ instance : LE (Prepartition I) := instance partialOrder : PartialOrder (Prepartition I) where le := (· ≤ ·) - le_refl π I hI := ⟨I, hI, le_rfl⟩ - le_trans π₁ π₂ π₃ h₁₂ h₂₃ I₁ hI₁ := - let ⟨I₂, hI₂, hI₁₂⟩ := h₁₂ hI₁ + le_refl _ I hI := ⟨I, hI, le_rfl⟩ + le_trans _ _ _ h₁₂ h₂₃ _ hI₁ := + let ⟨_, hI₂, hI₁₂⟩ := h₁₂ hI₁ let ⟨I₃, hI₃, hI₂₃⟩ := h₂₃ hI₂ ⟨I₃, hI₃, hI₁₂.trans hI₂₃⟩ le_antisymm := by @@ -129,7 +129,7 @@ instance partialOrder : PartialOrder (Prepartition I) where instance : OrderTop (Prepartition I) where top := single I I le_rfl - le_top π J hJ := ⟨I, by simp, π.le_of_mem hJ⟩ + le_top π _ hJ := ⟨I, by simp, π.le_of_mem hJ⟩ instance : OrderBot (Prepartition I) where bot := ⟨∅, @@ -177,7 +177,7 @@ theorem injOn_setOf_mem_Icc_setOf_lower_eq (x : ι → ℝ) : /-- The set of boxes of a prepartition that contain `x` in their closures has cardinality at most `2 ^ Fintype.card ι`. -/ theorem card_filter_mem_Icc_le [Fintype ι] (x : ι → ℝ) : - (π.boxes.filter fun J : Box ι => x ∈ Box.Icc J).card ≤ 2 ^ Fintype.card ι := by + #{J ∈ π.boxes | x ∈ Box.Icc J} ≤ 2 ^ Fintype.card ι := by rw [← Fintype.card_set] refine Finset.card_le_card_of_injOn (fun J : Box ι => { i | J.lower i = x i }) (fun _ _ => Finset.mem_univ _) ?_ @@ -517,7 +517,7 @@ instance : SemilatticeInf (Prepartition I) := /-- The prepartition with boxes `{J ∈ π | p J}`. -/ @[simps] def filter (π : Prepartition I) (p : Box ι → Prop) : Prepartition I where - boxes := π.boxes.filter p + boxes := {J ∈ π.boxes | p J} le_of_mem' _ hJ := π.le_of_mem (mem_filter.1 hJ).1 pairwiseDisjoint _ h₁ _ h₂ := π.disjoint_coe_of_mem (mem_filter.1 h₁).1 (mem_filter.1 h₂).1 @@ -558,11 +558,11 @@ theorem sum_fiberwise {α M} [AddCommMonoid M] (π : Prepartition I) (f : Box ι @[simps] def disjUnion (π₁ π₂ : Prepartition I) (h : Disjoint π₁.iUnion π₂.iUnion) : Prepartition I where boxes := π₁.boxes ∪ π₂.boxes - le_of_mem' J hJ := (Finset.mem_union.1 hJ).elim π₁.le_of_mem π₂.le_of_mem + le_of_mem' _ hJ := (Finset.mem_union.1 hJ).elim π₁.le_of_mem π₂.le_of_mem pairwiseDisjoint := suffices ∀ J₁ ∈ π₁, ∀ J₂ ∈ π₂, J₁ ≠ J₂ → Disjoint (J₁ : Set (ι → ℝ)) J₂ by simpa [pairwise_union_of_symmetric (symmetric_disjoint.comap _), pairwiseDisjoint] - fun J₁ h₁ J₂ h₂ _ => h.mono (π₁.subset_iUnion h₁) (π₂.subset_iUnion h₂) + fun _ h₁ _ h₂ _ => h.mono (π₁.subset_iUnion h₁) (π₂.subset_iUnion h₂) @[simp] theorem mem_disjUnion (H : Disjoint π₁.iUnion π₂.iUnion) : diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Split.lean b/Mathlib/Analysis/BoxIntegral/Partition/Split.lean index 06363982a7538..3e39d436eeb97 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Split.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Split.lean @@ -78,7 +78,7 @@ theorem splitLower_eq_self : I.splitLower i x = I ↔ I.upper i ≤ x := by theorem splitLower_def [DecidableEq ι] {i x} (h : x ∈ Ioo (I.lower i) (I.upper i)) (h' : ∀ j, I.lower j < update I.upper i x j := (forall_update_iff I.upper fun j y => I.lower j < y).2 - ⟨h.1, fun j _ => I.lower_lt_upper _⟩) : + ⟨h.1, fun _ _ => I.lower_lt_upper _⟩) : I.splitLower i x = (⟨I.lower, update I.upper i x, h'⟩ : Box ι) := by simp (config := { unfoldPartialApp := true }) only [splitLower, mk'_eq_coe, min_eq_left h.2.le, update, and_self] @@ -114,7 +114,7 @@ theorem splitUpper_eq_self : I.splitUpper i x = I ↔ x ≤ I.lower i := by theorem splitUpper_def [DecidableEq ι] {i x} (h : x ∈ Ioo (I.lower i) (I.upper i)) (h' : ∀ j, update I.lower i x j < I.upper j := (forall_update_iff I.lower fun j y => y < I.upper j).2 - ⟨h.2, fun j _ => I.lower_lt_upper _⟩) : + ⟨h.2, fun _ _ => I.lower_lt_upper _⟩) : I.splitUpper i x = (⟨update I.lower i x, I.upper, h'⟩ : Box ι) := by simp (config := { unfoldPartialApp := true }) only [splitUpper, mk'_eq_coe, max_eq_left h.1.le, update, and_self] diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean index 967500dc84169..9710dd56108b3 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean @@ -25,10 +25,8 @@ rectangular box, box partition noncomputable section +open Finset Function ENNReal NNReal Set open scoped Classical -open ENNReal NNReal - -open Set Function namespace BoxIntegral @@ -204,10 +202,9 @@ theorem isHenstock_biUnionTagged {π : Prepartition I} {πi : ∀ J, TaggedPrepa /-- In a Henstock prepartition, there are at most `2 ^ Fintype.card ι` boxes with a given tag. -/ theorem IsHenstock.card_filter_tag_eq_le [Fintype ι] (h : π.IsHenstock) (x : ι → ℝ) : - (π.boxes.filter fun J => π.tag J = x).card ≤ 2 ^ Fintype.card ι := + #{J ∈ π.boxes | π.tag J = x} ≤ 2 ^ Fintype.card ι := calc - (π.boxes.filter fun J => π.tag J = x).card ≤ - (π.boxes.filter fun J : Box ι => x ∈ Box.Icc J).card := by + #{J ∈ π.boxes | π.tag J = x} ≤ #{J ∈ π.boxes | x ∈ Box.Icc J} := by refine Finset.card_le_card fun J hJ => ?_ rw [Finset.mem_filter] at hJ ⊢; rcases hJ with ⟨hJ, rfl⟩ exact ⟨hJ, h J hJ⟩ diff --git a/Mathlib/Analysis/CStarAlgebra/ApproximateUnit.lean b/Mathlib/Analysis/CStarAlgebra/ApproximateUnit.lean new file mode 100644 index 0000000000000..89f1b4ea09125 --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ApproximateUnit.lean @@ -0,0 +1,107 @@ +/- +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.CStarAlgebra.ContinuousFunctionalCalculus.Order +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Isometric +import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Rpow + +/-! # Positive contractions in a C⋆-algebra form an approximate unit + +This file will show (although it does not yet) that the collection of positive contractions (of norm +strictly less than one) in a possibly non-unital C⋆-algebra form an approximate unit. The key step +is to show that this set is directed using the continuous functional calculus applied with the +functions `fun x : ℝ≥0, 1 - (1 + x)⁻¹` and `fun x : ℝ≥0, x * (1 - x)⁻¹`, which are inverses on +the interval `{x : ℝ≥0 | x < 1}`. + +## Main declarations + ++ `CFC.monotoneOn_one_sub_one_add_inv`: the function `f := fun x : ℝ≥0, 1 - (1 + x)⁻¹` is + *operator monotone* on `Set.Ici (0 : A)` (i.e., `cfcₙ f` is monotone on `{x : A | 0 ≤ x}`). ++ `Set.InvOn.one_sub_one_add_inv`: the functions `f := fun x : ℝ≥0, 1 - (1 + x)⁻¹` and + `g := fun x : ℝ≥0, x * (1 - x)⁻¹` are inverses on `{x : ℝ≥0 | x < 1}`. ++ `CStarAlgebra.directedOn_nonneg_ball`: the set `{x : A | 0 ≤ x} ∩ Metric.ball 0 1` is directed. + +## TODO + ++ Prove the approximate identity result by following Ken Davidson's proof in + "C*-Algebras by Example" + +-/ + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +local notation "σₙ" => quasispectrum +local notation "σ" => spectrum + +open Unitization NNReal CStarAlgebra + +variable [PartialOrder A] [StarOrderedRing A] + +lemma CFC.monotoneOn_one_sub_one_add_inv : + MonotoneOn (cfcₙ (fun x : ℝ≥0 ↦ 1 - (1 + x)⁻¹)) (Set.Ici (0 : A)) := by + intro a ha b hb hab + simp only [Set.mem_Ici] at ha hb + rw [← inr_le_iff .., nnreal_cfcₙ_eq_cfc_inr a _, nnreal_cfcₙ_eq_cfc_inr b _] + rw [← inr_le_iff a b (.of_nonneg ha) (.of_nonneg hb)] at hab + rw [← inr_nonneg_iff] at ha hb + have h_cfc_one_sub (c : A⁺¹) (hc : 0 ≤ c := by cfc_tac) : + cfc (fun x : ℝ≥0 ↦ 1 - (1 + x)⁻¹) c = 1 - cfc (·⁻¹ : ℝ≥0 → ℝ≥0) (1 + c) := by + rw [cfc_tsub _ _ _ (fun x _ ↦ by simp) (hg := by fun_prop (disch := intro _ _; positivity)), + cfc_const_one ℝ≥0 c, cfc_comp' (·⁻¹) (1 + ·) c ?_, cfc_add .., cfc_const_one ℝ≥0 c, + cfc_id' ℝ≥0 c] + exact continuousOn_id.inv₀ (Set.forall_mem_image.mpr fun x _ ↦ by dsimp only [id]; positivity) + rw [h_cfc_one_sub (a : A⁺¹), h_cfc_one_sub (b : A⁺¹)] + gcongr + rw [← CFC.rpow_neg_one_eq_cfc_inv, ← CFC.rpow_neg_one_eq_cfc_inv] + exact rpow_neg_one_le_rpow_neg_one (add_nonneg zero_le_one ha) (by gcongr) <| + isUnit_of_le isUnit_one zero_le_one <| le_add_of_nonneg_right ha + +lemma Set.InvOn.one_sub_one_add_inv : Set.InvOn (fun x ↦ 1 - (1 + x)⁻¹) (fun x ↦ x * (1 - x)⁻¹) + {x : ℝ≥0 | x < 1} {x : ℝ≥0 | x < 1} := by + have : (fun x : ℝ≥0 ↦ x * (1 + x)⁻¹) = fun x ↦ 1 - (1 + x)⁻¹ := by + ext x : 1 + field_simp + simp [tsub_mul, inv_mul_cancel₀] + rw [← this] + constructor <;> intro x (hx : x < 1) + · have : 0 < 1 - x := tsub_pos_of_lt hx + field_simp [tsub_add_cancel_of_le hx.le, tsub_tsub_cancel_of_le hx.le] + · field_simp [mul_tsub] + +lemma norm_cfcₙ_one_sub_one_add_inv_lt_one (a : A) : + ‖cfcₙ (fun x : ℝ≥0 ↦ 1 - (1 + x)⁻¹) a‖ < 1 := + nnnorm_cfcₙ_nnreal_lt fun x _ ↦ tsub_lt_self zero_lt_one (by positivity) + +-- the calls to `fun_prop` with a discharger set off the linter +set_option linter.style.multiGoal false in +lemma CStarAlgebra.directedOn_nonneg_ball : + DirectedOn (· ≤ ·) ({x : A | 0 ≤ x} ∩ Metric.ball 0 1) := by + let f : ℝ≥0 → ℝ≥0 := fun x => 1 - (1 + x)⁻¹ + let g : ℝ≥0 → ℝ≥0 := fun x => x * (1 - x)⁻¹ + suffices ∀ a b : A, 0 ≤ a → 0 ≤ b → ‖a‖ < 1 → ‖b‖ < 1 → + a ≤ cfcₙ f (cfcₙ g a + cfcₙ g b) by + rintro a ⟨(ha₁ : 0 ≤ a), ha₂⟩ b ⟨(hb₁ : 0 ≤ b), hb₂⟩ + simp only [Metric.mem_ball, dist_zero_right] at ha₂ hb₂ + refine ⟨cfcₙ f (cfcₙ g a + cfcₙ g b), ⟨by simp, ?_⟩, ?_, ?_⟩ + · simpa only [Metric.mem_ball, dist_zero_right] using norm_cfcₙ_one_sub_one_add_inv_lt_one _ + · exact this a b ha₁ hb₁ ha₂ hb₂ + · exact add_comm (cfcₙ g a) (cfcₙ g b) ▸ this b a hb₁ ha₁ hb₂ ha₂ + rintro a b ha₁ - ha₂ - + calc + a = cfcₙ (f ∘ g) a := by + conv_lhs => rw [← cfcₙ_id ℝ≥0 a] + refine cfcₙ_congr (Set.InvOn.one_sub_one_add_inv.1.eqOn.symm.mono fun x hx ↦ ?_) + exact lt_of_le_of_lt (le_nnnorm_of_mem_quasispectrum hx) ha₂ + _ = cfcₙ f (cfcₙ g a) := by + rw [cfcₙ_comp f g a ?_ (by simp [f, tsub_self]) ?_ (by simp [g]) ha₁] + · fun_prop (disch := intro _ _; positivity) + · have (x) (hx : x ∈ σₙ ℝ≥0 a) : 1 - x ≠ 0 := by + refine tsub_pos_of_lt ?_ |>.ne' + exact lt_of_le_of_lt (le_nnnorm_of_mem_quasispectrum hx) ha₂ + fun_prop (disch := assumption) + _ ≤ cfcₙ f (cfcₙ g a + cfcₙ g b) := by + have hab' : cfcₙ g a ≤ cfcₙ g a + cfcₙ g b := le_add_of_nonneg_right cfcₙ_nonneg_of_predicate + exact CFC.monotoneOn_one_sub_one_add_inv cfcₙ_nonneg_of_predicate + (cfcₙ_nonneg_of_predicate.trans hab') hab' diff --git a/Mathlib/Analysis/CStarAlgebra/Classes.lean b/Mathlib/Analysis/CStarAlgebra/Classes.lean new file mode 100644 index 0000000000000..274d602111ef5 --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/Classes.lean @@ -0,0 +1,104 @@ +/- +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.Complex.Basic +import Mathlib.Algebra.Star.NonUnitalSubalgebra + +/-! # Classes of C⋆-algebras + +This file defines classes for complex C⋆-algebras. These are (unital or non-unital, commutative or +noncommutative) Banach algebra over `ℂ` with an antimultiplicative conjugate-linear involution +(`star`) satisfying the C⋆-identity `∥star x * x∥ = ∥x∥ ^ 2`. + +## Notes + +These classes are not defined in `Mathlib.Analysis.CStarAlgebra.Basic` because they require +heavier imports. + +-/ + +/-- The class of non-unital (complex) C⋆-algebras. -/ +class NonUnitalCStarAlgebra (A : Type*) extends NonUnitalNormedRing A, StarRing A, CompleteSpace A, + CStarRing A, NormedSpace ℂ A, IsScalarTower ℂ A A, SMulCommClass ℂ A A, StarModule ℂ A where + +/-- The class of non-unital commutative (complex) C⋆-algebras. -/ +class NonUnitalCommCStarAlgebra (A : Type*) extends + NonUnitalNormedCommRing A, NonUnitalCStarAlgebra A + +/-- The class of unital (complex) C⋆-algebras. -/ +class CStarAlgebra (A : Type*) extends NormedRing A, StarRing A, CompleteSpace A, CStarRing A, + NormedAlgebra ℂ A, StarModule ℂ A where + +/-- The class of unital commutative (complex) C⋆-algebras. -/ +class CommCStarAlgebra (A : Type*) extends NormedCommRing A, CStarAlgebra A + +instance (priority := 100) CStarAlgebra.toNonUnitalCStarAlgebra (A : Type*) [CStarAlgebra A] : + NonUnitalCStarAlgebra A where + +instance (priority := 100) CommCStarAlgebra.toNonUnitalCommCStarAlgebra (A : Type*) + [CommCStarAlgebra A] : NonUnitalCommCStarAlgebra A where + +noncomputable instance StarSubalgebra.cstarAlgebra {S A : Type*} [CStarAlgebra A] + [SetLike S A] [SubringClass S A] [SMulMemClass S ℂ A] [StarMemClass S A] + (s : S) [h_closed : IsClosed (s : Set A)] : CStarAlgebra s where + toCompleteSpace := h_closed.completeSpace_coe + norm_mul_self_le x := CStarRing.norm_star_mul_self (x := (x : A)) |>.symm.le + +noncomputable instance StarSubalgebra.commCStarAlgebra {S A : Type*} [CommCStarAlgebra A] + [SetLike S A] [SubringClass S A] [SMulMemClass S ℂ A] [StarMemClass S A] + (s : S) [h_closed : IsClosed (s : Set A)] : CommCStarAlgebra s where + toCompleteSpace := h_closed.completeSpace_coe + norm_mul_self_le x := CStarRing.norm_star_mul_self (x := (x : A)) |>.symm.le + mul_comm _ _ := Subtype.ext <| mul_comm _ _ + +noncomputable instance NonUnitalStarSubalgebra.nonUnitalCStarAlgebra {S A : Type*} + [NonUnitalCStarAlgebra A] [SetLike S A] [NonUnitalSubringClass S A] [SMulMemClass S ℂ A] + [StarMemClass S A] (s : S) [h_closed : IsClosed (s : Set A)] : NonUnitalCStarAlgebra s where + toCompleteSpace := h_closed.completeSpace_coe + norm_mul_self_le x := CStarRing.norm_star_mul_self (x := (x : A)) |>.symm.le + +noncomputable instance NonUnitalStarSubalgebra.nonUnitalCommCStarAlgebra {S A : Type*} + [NonUnitalCommCStarAlgebra A] [SetLike S A] [NonUnitalSubringClass S A] [SMulMemClass S ℂ A] + [StarMemClass S A] (s : S) [h_closed : IsClosed (s : Set A)] : NonUnitalCommCStarAlgebra s where + toCompleteSpace := h_closed.completeSpace_coe + norm_mul_self_le x := CStarRing.norm_star_mul_self (x := (x : A)) |>.symm.le + mul_comm _ _ := Subtype.ext <| mul_comm _ _ + +noncomputable instance : CommCStarAlgebra ℂ where + mul_comm := mul_comm + +section Pi + +variable {ι : Type*} {A : ι → Type*} [Fintype ι] + +instance [(i : ι) → NonUnitalCStarAlgebra (A i)] : NonUnitalCStarAlgebra (Π i, A i) where + +instance [(i : ι) → NonUnitalCommCStarAlgebra (A i)] : NonUnitalCommCStarAlgebra (Π i, A i) where + mul_comm := mul_comm + +noncomputable instance [(i : ι) → CStarAlgebra (A i)] : CStarAlgebra (Π i, A i) where + +noncomputable instance [(i : ι) → CommCStarAlgebra (A i)] : CommCStarAlgebra (Π i, A i) where + mul_comm := mul_comm + +end Pi + +section Prod + +variable {A B : Type*} + +instance [NonUnitalCStarAlgebra A] [NonUnitalCStarAlgebra B] : NonUnitalCStarAlgebra (A × B) where + +instance [NonUnitalCommCStarAlgebra A] [NonUnitalCommCStarAlgebra B] : + NonUnitalCommCStarAlgebra (A × B) where + mul_comm := mul_comm + +noncomputable instance [CStarAlgebra A] [CStarAlgebra B] : CStarAlgebra (A × B) where + +noncomputable instance [CommCStarAlgebra A] [CommCStarAlgebra B] : CommCStarAlgebra (A × B) where + mul_comm := mul_comm + +end Prod diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean index 073d532f7a479..ddf5ca62ce95f 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean @@ -48,8 +48,7 @@ open scoped Pointwise ENNReal NNReal ComplexOrder open WeakDual WeakDual.CharacterSpace elementalStarAlgebra -variable {A : Type*} [NormedRing A] [NormedAlgebra ℂ A] -variable [StarRing A] [CStarRing A] [StarModule ℂ A] +variable {A : Type*} [CStarAlgebra A] instance {R A : Type*} [CommRing R] [StarRing R] [NormedRing A] [Algebra R A] [StarRing A] [ContinuousStar A] [StarModule R A] (a : A) [IsStarNormal a] : @@ -57,7 +56,10 @@ instance {R A : Type*} [CommRing R] [StarRing R] [NormedRing A] [Algebra R A] [S { SubringClass.toNormedRing (elementalStarAlgebra R a) with mul_comm := mul_comm } -variable [CompleteSpace A] (a : A) [IsStarNormal a] (S : StarSubalgebra ℂ A) +noncomputable instance (a : A) [IsStarNormal a] : CommCStarAlgebra (elementalStarAlgebra ℂ a) where + mul_comm := mul_comm + +variable (a : A) [IsStarNormal a] /-- The natural map from `characterSpace ℂ (elementalStarAlgebra ℂ x)` to `spectrum ℂ x` given by evaluating `φ` at `x`. This is essentially just evaluation of the `gelfandTransform` of `x`, diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean index 180ca90ca5288..4a903ec4b4fda 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean @@ -78,16 +78,16 @@ noncomputable def cfcₙAux : C(σₙ 𝕜 a, 𝕜)₀ →⋆ₙₐ[𝕜] A⁺¹ lemma cfcₙAux_id : cfcₙAux hp₁ a ha (ContinuousMapZero.id rfl) = a := cfcHom_id (hp₁.mpr ha) open Unitization in -lemma closedEmbedding_cfcₙAux : ClosedEmbedding (cfcₙAux hp₁ a ha) := by +lemma isClosedEmbedding_cfcₙAux : IsClosedEmbedding (cfcₙAux hp₁ a ha) := by simp only [cfcₙAux, NonUnitalStarAlgHom.coe_comp] - refine ((cfcHom_closedEmbedding (hp₁.mpr ha)).comp ?_).comp - ContinuousMapZero.closedEmbedding_toContinuousMap + refine ((cfcHom_isClosedEmbedding (hp₁.mpr ha)).comp ?_).comp + ContinuousMapZero.isClosedEmbedding_toContinuousMap let e : C(σₙ 𝕜 a, 𝕜) ≃ₜ C(σ 𝕜 (a : A⁺¹), 𝕜) := - { (Homeomorph.compStarAlgEquiv' 𝕜 𝕜 <| .setCongr <| - (quasispectrum_eq_spectrum_inr' 𝕜 𝕜 a).symm) with - continuous_toFun := ContinuousMap.continuous_comp_left _ - continuous_invFun := ContinuousMap.continuous_comp_left _ } - exact e.closedEmbedding + (Homeomorph.setCongr (quasispectrum_eq_spectrum_inr' 𝕜 𝕜 a)).arrowCongr (.refl _) + exact e.isClosedEmbedding + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_cfcₙAux := isClosedEmbedding_cfcₙAux lemma spec_cfcₙAux (f : C(σₙ 𝕜 a, 𝕜)₀) : σ 𝕜 (cfcₙAux hp₁ a ha f) = Set.range f := by rw [cfcₙAux, NonUnitalStarAlgHom.comp_assoc, NonUnitalStarAlgHom.comp_apply] @@ -103,7 +103,7 @@ variable [CompleteSpace A] lemma cfcₙAux_mem_range_inr (f : C(σₙ 𝕜 a, 𝕜)₀) : cfcₙAux hp₁ a ha f ∈ NonUnitalStarAlgHom.range (Unitization.inrNonUnitalStarAlgHom 𝕜 A) := by - have h₁ := (closedEmbedding_cfcₙAux hp₁ a ha).continuous.range_subset_closure_image_dense + have h₁ := (isClosedEmbedding_cfcₙAux hp₁ a ha).continuous.range_subset_closure_image_dense (ContinuousMapZero.adjoin_id_dense (s := σₙ 𝕜 a) rfl) ⟨f, rfl⟩ rw [← SetLike.mem_coe] refine closure_minimal ?_ ?_ h₁ @@ -133,11 +133,11 @@ theorem RCLike.nonUnitalContinuousFunctionalCalculus : have coe_ψ (f : C(σₙ 𝕜 a, 𝕜)₀) : ψ f = cfcₙAux hp₁ a ha f := congr_arg Subtype.val <| (inrRangeEquiv 𝕜 A).apply_symm_apply ⟨cfcₙAux hp₁ a ha f, cfcₙAux_mem_range_inr hp₁ a ha f⟩ - refine ⟨ψ, ?closedEmbedding, ?map_id, fun f ↦ ?map_spec, fun f ↦ ?isStarNormal⟩ - case closedEmbedding => - apply isometry_inr (𝕜 := 𝕜) (A := A) |>.closedEmbedding |>.of_comp_iff.mp + refine ⟨ψ, ?isClosedEmbedding, ?map_id, fun f ↦ ?map_spec, fun f ↦ ?isStarNormal⟩ + case isClosedEmbedding => + apply isometry_inr (𝕜 := 𝕜) (A := A) |>.isClosedEmbedding |>.of_comp_iff.mp have : inr ∘ ψ = cfcₙAux hp₁ a ha := by ext1; rw [Function.comp_apply, coe_ψ] - exact this ▸ closedEmbedding_cfcₙAux hp₁ a ha + exact this ▸ isClosedEmbedding_cfcₙAux hp₁ a ha case map_id => exact inr_injective (R := 𝕜) <| coe_ψ _ ▸ cfcₙAux_id hp₁ a ha case map_spec => exact quasispectrum_eq_spectrum_inr' 𝕜 𝕜 (ψ f) ▸ coe_ψ _ ▸ spec_cfcₙAux hp₁ a ha f @@ -151,19 +151,15 @@ end RCLike section Normal -instance IsStarNormal.instContinuousFunctionalCalculus {A : Type*} [NormedRing A] [StarRing A] - [CStarRing A] [CompleteSpace A] [NormedAlgebra ℂ A] [StarModule ℂ A] : +instance IsStarNormal.instContinuousFunctionalCalculus {A : Type*} [CStarAlgebra A] : ContinuousFunctionalCalculus ℂ (IsStarNormal : A → Prop) where predicate_zero := isStarNormal_zero + spectrum_nonempty a _ := spectrum.nonempty a exists_cfc_of_predicate a ha := by refine ⟨(elementalStarAlgebra ℂ a).subtype.comp <| continuousFunctionalCalculus a, ?hom_closedEmbedding, ?hom_id, ?hom_map_spectrum, ?predicate_hom⟩ case hom_closedEmbedding => - -- note: Lean should find these for `StarAlgEquiv.isometry`, but it doesn't and so we - -- provide them manually. - have : SMulCommClass ℂ C(σ ℂ a, ℂ) C(σ ℂ a, ℂ) := Algebra.to_smulCommClass (A := C(σ ℂ a, ℂ)) - have : IsScalarTower ℂ C(σ ℂ a, ℂ) C(σ ℂ a, ℂ) := IsScalarTower.right (A := C(σ ℂ a, ℂ)) - exact Isometry.closedEmbedding <| + exact Isometry.isClosedEmbedding <| isometry_subtype_coe.comp <| StarAlgEquiv.isometry (continuousFunctionalCalculus a) case hom_id => exact congr_arg Subtype.val <| continuousFunctionalCalculus_map_id a case hom_map_spectrum => @@ -173,12 +169,30 @@ instance IsStarNormal.instContinuousFunctionalCalculus {A : Type*} [NormedRing A AlgEquiv.spectrum_eq (continuousFunctionalCalculus a), ContinuousMap.spectrum_eq_range] case predicate_hom => exact fun f ↦ ⟨by rw [← map_star]; exact Commute.all (star f) f |>.map _⟩ -instance IsStarNormal.instNonUnitalContinuousFunctionalCalculus {A : Type*} [NonUnitalNormedRing A] - [StarRing A] [CStarRing A] [CompleteSpace A] [NormedSpace ℂ A] [IsScalarTower ℂ A A] - [SMulCommClass ℂ A A] [StarModule ℂ A] : - NonUnitalContinuousFunctionalCalculus ℂ (IsStarNormal : A → Prop) := +lemma cfcHom_eq_of_isStarNormal {A : Type*} [CStarAlgebra A] (a : A) [ha : IsStarNormal a] : + cfcHom ha = (elementalStarAlgebra ℂ a).subtype.comp (continuousFunctionalCalculus a) := by + refine cfcHom_eq_of_continuous_of_map_id ha _ ?_ ?_ + · exact continuous_subtype_val.comp <| + (StarAlgEquiv.isometry (continuousFunctionalCalculus a)).continuous + · simp [continuousFunctionalCalculus_map_id a] + +instance IsStarNormal.instNonUnitalContinuousFunctionalCalculus {A : Type*} + [NonUnitalCStarAlgebra A] : NonUnitalContinuousFunctionalCalculus ℂ (IsStarNormal : A → Prop) := RCLike.nonUnitalContinuousFunctionalCalculus Unitization.isStarNormal_inr +open Unitization CStarAlgebra in +lemma inr_comp_cfcₙHom_eq_cfcₙAux {A : Type*} [NonUnitalCStarAlgebra A] (a : A) + [ha : IsStarNormal a] : (inrNonUnitalStarAlgHom ℂ A).comp (cfcₙHom ha) = + cfcₙAux (isStarNormal_inr (R := ℂ) (A := A)) a ha := by + have h (a : A) := isStarNormal_inr (R := ℂ) (A := A) (a := a) + refine @UniqueNonUnitalContinuousFunctionalCalculus.eq_of_continuous_of_map_id + _ _ _ _ _ _ _ _ _ _ _ inferInstance inferInstance _ (σₙ ℂ a) _ _ rfl _ _ ?_ ?_ ?_ + · show Continuous (fun f ↦ (cfcₙHom ha f : A⁺¹)); fun_prop + · exact isClosedEmbedding_cfcₙAux @(h) a ha |>.continuous + · trans (a : A⁺¹) + · congrm(inr $(cfcₙHom_id ha)) + · exact cfcₙAux_id @(h) a ha |>.symm + end Normal /-! @@ -371,8 +385,7 @@ section SpectrumRestricts open NNReal ENNReal -variable {A : Type*} [NormedRing A] [StarRing A] [CStarRing A] [CompleteSpace A] -variable [NormedAlgebra ℂ A] [StarModule ℂ A] +variable {A : Type*} [CStarAlgebra A] lemma SpectrumRestricts.nnreal_iff_nnnorm {a : A} {t : ℝ≥0} (ha : IsSelfAdjoint a) (ht : ‖a‖₊ ≤ t) : SpectrumRestricts a ContinuousMap.realToNNReal ↔ ‖algebraMap ℝ A t - a‖₊ ≤ t := by @@ -491,21 +504,19 @@ end SpectrumRestricts section NonnegSpectrumClass -variable {A : Type*} [NormedRing A] [CompleteSpace A] -variable [PartialOrder A] [StarRing A] [StarOrderedRing A] [CStarRing A] -variable [NormedAlgebra ℂ A] [StarModule ℂ A] +variable {A : Type*} [CStarAlgebra A] [PartialOrder A] [StarOrderedRing A] instance CStarAlgebra.instNonnegSpectrumClass : NonnegSpectrumClass ℝ A := .of_spectrum_nonneg fun a ha ↦ by rw [StarOrderedRing.nonneg_iff] at ha - induction ha using AddSubmonoid.closure_induction' with + induction ha using AddSubmonoid.closure_induction with | mem x hx => obtain ⟨b, rfl⟩ := hx exact spectrum_star_mul_self_nonneg | one => nontriviality A simp - | mul x x_mem y y_mem hx hy => + | mul x y x_mem y_mem hx hy => rw [← SpectrumRestricts.nnreal_iff] at hx hy ⊢ rw [← StarOrderedRing.nonneg_iff] at x_mem y_mem exact hx.nnreal_add (.of_nonneg x_mem) (.of_nonneg y_mem) hy @@ -522,8 +533,7 @@ end NonnegSpectrumClass section SpectralOrder -variable (A : Type*) [NormedRing A] [CompleteSpace A] [StarRing A] [CStarRing A] -variable [NormedAlgebra ℂ A] [StarModule ℂ A] +variable (A : Type*) [CStarAlgebra A] /-- The partial order on a unital C⋆-algebra defined by `x ≤ y` if and only if `y - x` is selfadjoint and has nonnegative spectrum. @@ -557,7 +567,7 @@ lemma CStarAlgebra.spectralOrderedRing : @StarOrderedRing A _ (CStarAlgebra.spec · rintro ⟨p, hp, rfl⟩ suffices IsSelfAdjoint p ∧ SpectrumRestricts p ContinuousMap.realToNNReal from ⟨by simpa using this.1, by simpa using this.2⟩ - induction hp using AddSubmonoid.closure_induction' with + induction hp using AddSubmonoid.closure_induction with | mem x hx => obtain ⟨s, rfl⟩ := hx refine ⟨IsSelfAdjoint.star_mul_self s, ?_⟩ @@ -567,23 +577,22 @@ lemma CStarAlgebra.spectralOrderedRing : @StarOrderedRing A _ (CStarAlgebra.spec rw [SpectrumRestricts.nnreal_iff] nontriviality A simp - | mul x _ y _ hx hy => + | mul x y _ _ hx hy => exact ⟨hx.1.add hy.1, hx.2.nnreal_add hx.1 hy.1 hy.2⟩ } end SpectralOrder section NonnegSpectrumClass -variable {A : Type*} [NonUnitalNormedRing A] [CompleteSpace A] -variable [PartialOrder A] [StarRing A] [StarOrderedRing A] [CStarRing A] -variable [NormedSpace ℂ A] [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] [StarModule ℂ A] +variable {A : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] [StarOrderedRing A] +open scoped CStarAlgebra in instance CStarAlgebra.instNonnegSpectrumClass' : NonnegSpectrumClass ℝ A where quasispectrum_nonneg_of_nonneg a ha := by rw [Unitization.quasispectrum_eq_spectrum_inr' _ ℂ] -- should this actually be an instance on the `Unitization`? (probably scoped) - let _ := CStarAlgebra.spectralOrder (Unitization ℂ A) - have := CStarAlgebra.spectralOrderedRing (Unitization ℂ A) + let _ := CStarAlgebra.spectralOrder A⁺¹ + have := CStarAlgebra.spectralOrderedRing A⁺¹ apply spectrum_nonneg_of_nonneg rw [StarOrderedRing.nonneg_iff] at ha ⊢ have := AddSubmonoid.mem_map_of_mem (Unitization.inrNonUnitalStarAlgHom ℂ A) ha @@ -685,4 +694,43 @@ lemma cfcₙ_nnreal_eq_real {a : A} (f : ℝ≥0 → ℝ≥0) (ha : 0 ≤ a := b end NNRealEqRealNonUnital +section cfc_inr + +open CStarAlgebra + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +open scoped NonUnitalContinuousFunctionalCalculus in +/-- This lemma requires a lot from type class synthesis, and so one should instead favor the bespoke +versions for `ℝ≥0`, `ℝ`, and `ℂ`. -/ +lemma Unitization.cfcₙ_eq_cfc_inr {R : Type*} [Semifield R] [StarRing R] [MetricSpace R] + [TopologicalSemiring R] [ContinuousStar R] [Module R A] [IsScalarTower R A A] + [SMulCommClass R A A] [CompleteSpace R] [Algebra R ℂ] [IsScalarTower R ℂ A] + {p : A → Prop} {p' : A⁺¹ → Prop} [NonUnitalContinuousFunctionalCalculus R p] + [ContinuousFunctionalCalculus R p'] + [UniqueNonUnitalContinuousFunctionalCalculus R (Unitization ℂ A)] + (hp : ∀ {a : A}, p' (a : A⁺¹) ↔ p a) (a : A) (f : R → R) (hf₀ : f 0 = 0 := by cfc_zero_tac) : + cfcₙ f a = cfc f (a : A⁺¹) := by + by_cases h : ContinuousOn f (σₙ R a) ∧ p a + · obtain ⟨hf, ha⟩ := h + rw [← cfcₙ_eq_cfc (quasispectrum_inr_eq R ℂ a ▸ hf)] + exact (inrNonUnitalStarAlgHom ℂ A).map_cfcₙ f a + · obtain (hf | ha) := not_and_or.mp h + · rw [cfcₙ_apply_of_not_continuousOn a hf, inr_zero, + cfc_apply_of_not_continuousOn _ (quasispectrum_eq_spectrum_inr' R ℂ a ▸ hf)] + · rw [cfcₙ_apply_of_not_predicate a ha, inr_zero, + cfc_apply_of_not_predicate _ (not_iff_not.mpr hp |>.mpr ha)] + +lemma Unitization.complex_cfcₙ_eq_cfc_inr (a : A) (f : ℂ → ℂ) (hf₀ : f 0 = 0 := by cfc_zero_tac) : + cfcₙ f a = cfc f (a : A⁺¹) := + Unitization.cfcₙ_eq_cfc_inr isStarNormal_inr .. + +/-- note: the version for `ℝ≥0`, `Unization.nnreal_cfcₙ_eq_cfc_inr`, can be found in +`Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Order` -/ +lemma Unitization.real_cfcₙ_eq_cfc_inr (a : A) (f : ℝ → ℝ) (hf₀ : f 0 = 0 := by cfc_zero_tac) : + cfcₙ f a = cfc f (a : A⁺¹) := + Unitization.cfcₙ_eq_cfc_inr isSelfAdjoint_inr .. + +end cfc_inr + end diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean index f56a3cf3d1927..c895c51d26c6a 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean @@ -141,7 +141,7 @@ lemma cfcₙ_integral' [TopologicalSpace X] [OpensMeasurableSpace X] (f : X → refine cfcₙ_integral f bound a ?_ hf₂ ?_ hbound hbound_finite_integral · exact (continuousOn_iff_continuous_restrict.mpr <| hf.uncurry_left ·) · let g := ((↑) : C(quasispectrum 𝕜 a, 𝕜)₀ → C(quasispectrum 𝕜 a, 𝕜)) - refine (Inducing.continuous_iff (g := g) ((inducing_iff g).mpr rfl)).mpr ?_ + refine ((isInducing_iff g).mpr rfl).continuous_iff.mpr ?_ exact ContinuousMap.curry ⟨_, hf⟩ |>.continuous end nonunital diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Isometric.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Isometric.lean new file mode 100644 index 0000000000000..142e51cfa4b72 --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Isometric.lean @@ -0,0 +1,561 @@ +/- +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.CStarAlgebra.ContinuousFunctionalCalculus.Instances + +/-! # Isometric continuous functional calculus + +This file adds a class for an *isometric* continuous functional calculus. This is separate from the +usual `ContinuousFunctionalCalculus` class because we prefer not to require a metric (or a norm) on +the algebra for reasons discussed in the module documentation for that file. + +Of course, with a metric on the algebra and an isometric continuous functional calculus, the +algebra must *be* a C⋆-algebra already. As such, it may seem like this class is not useful. However, +the main purpose is to allow for the continuous functional calculus to be a isometric for the other +scalar rings `ℝ` and `ℝ≥0` too. +-/ + +local notation "σ" => spectrum +local notation "σₙ" => quasispectrum + +/-! ### Isometric continuous functional calculus for unital algebras -/ +section Unital + +/-- An extension of the `ContinuousFunctionalCalculus` requiring that `cfcHom` is an isometry. -/ +class IsometricContinuousFunctionalCalculus (R A : Type*) (p : outParam (A → Prop)) + [CommSemiring R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] + [Ring A] [StarRing A] [MetricSpace A] [Algebra R A] + extends ContinuousFunctionalCalculus R p : Prop where + isometric (a : A) (ha : p a) : Isometry (cfcHom ha (R := R)) + +section MetricSpace + +open scoped ContinuousFunctionalCalculus + +lemma isometry_cfcHom {R A : Type*} {p : outParam (A → Prop)} [CommSemiring R] [StarRing R] + [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] [Ring A] [StarRing A] + [MetricSpace A] [Algebra R A] [IsometricContinuousFunctionalCalculus R A p] + (a : A) (ha : p a := by cfc_tac) : + Isometry (cfcHom (show p a from ha) (R := R)) := + IsometricContinuousFunctionalCalculus.isometric a ha + +end MetricSpace + +section NormedRing + +open scoped ContinuousFunctionalCalculus + +variable {𝕜 A : Type*} {p : outParam (A → Prop)} +variable [RCLike 𝕜] [NormedRing A] [StarRing A] [NormedAlgebra 𝕜 A] +variable [IsometricContinuousFunctionalCalculus 𝕜 A p] + +lemma norm_cfcHom (a : A) (f : C(σ 𝕜 a, 𝕜)) (ha : p a := by cfc_tac) : + ‖cfcHom (show p a from ha) f‖ = ‖f‖ := by + refine isometry_cfcHom a |>.norm_map_of_map_zero (map_zero _) f + +lemma nnnorm_cfcHom (a : A) (f : C(σ 𝕜 a, 𝕜)) (ha : p a := by cfc_tac) : + ‖cfcHom (show p a from ha) f‖₊ = ‖f‖₊ := + Subtype.ext <| norm_cfcHom a f ha + +lemma IsGreatest.norm_cfc [Nontrivial A] (f : 𝕜 → 𝕜) (a : A) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + IsGreatest ((fun x ↦ ‖f x‖) '' spectrum 𝕜 a) ‖cfc f a‖ := by + obtain ⟨x, hx⟩ := ContinuousFunctionalCalculus.isCompact_spectrum a + |>.image_of_continuousOn hf.norm |>.exists_isGreatest <| + (ContinuousFunctionalCalculus.spectrum_nonempty a ha).image _ + obtain ⟨x, hx', rfl⟩ := hx.1 + convert hx + rw [cfc_apply f a, norm_cfcHom a _] + apply le_antisymm + · apply ContinuousMap.norm_le _ (norm_nonneg _) |>.mpr + rintro ⟨y, hy⟩ + exact hx.2 ⟨y, hy, rfl⟩ + · exact le_trans (by simp) <| ContinuousMap.norm_coe_le_norm _ (⟨x, hx'⟩ : σ 𝕜 a) + +lemma IsGreatest.nnnorm_cfc [Nontrivial A] (f : 𝕜 → 𝕜) (a : A) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + IsGreatest ((fun x ↦ ‖f x‖₊) '' σ 𝕜 a) ‖cfc f a‖₊ := by + convert Real.toNNReal_mono.map_isGreatest (.norm_cfc f a) + all_goals simp [Set.image_image, norm_toNNReal] + +lemma norm_apply_le_norm_cfc (f : 𝕜 → 𝕜) (a : A) ⦃x : 𝕜⦄ (hx : x ∈ σ 𝕜 a) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + ‖f x‖ ≤ ‖cfc f a‖ := by + revert hx + nontriviality A + exact (IsGreatest.norm_cfc f a hf ha |>.2 ⟨x, ·, rfl⟩) + +lemma nnnorm_apply_le_nnnorm_cfc (f : 𝕜 → 𝕜) (a : A) ⦃x : 𝕜⦄ (hx : x ∈ σ 𝕜 a) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + ‖f x‖₊ ≤ ‖cfc f a‖₊ := + norm_apply_le_norm_cfc f a hx + +lemma norm_cfc_le {f : 𝕜 → 𝕜} {a : A} {c : ℝ} (hc : 0 ≤ c) (h : ∀ x ∈ σ 𝕜 a, ‖f x‖ ≤ c) : + ‖cfc f a‖ ≤ c := by + obtain (_ | _) := subsingleton_or_nontrivial A + · simpa [Subsingleton.elim (cfc f a) 0] + · refine cfc_cases (‖·‖ ≤ c) a f (by simpa) fun hf ha ↦ ?_ + simp only [← cfc_apply f a, isLUB_le_iff (IsGreatest.norm_cfc f a hf ha |>.isLUB)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma norm_cfc_le_iff (f : 𝕜 → 𝕜) (a : A) {c : ℝ} (hc : 0 ≤ c) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) + (ha : p a := by cfc_tac) : ‖cfc f a‖ ≤ c ↔ ∀ x ∈ σ 𝕜 a, ‖f x‖ ≤ c := + ⟨fun h _ hx ↦ norm_apply_le_norm_cfc f a hx hf ha |>.trans h, norm_cfc_le hc⟩ + +lemma norm_cfc_lt {f : 𝕜 → 𝕜} {a : A} {c : ℝ} (hc : 0 < c) (h : ∀ x ∈ σ 𝕜 a, ‖f x‖ < c) : + ‖cfc f a‖ < c := by + obtain (_ | _) := subsingleton_or_nontrivial A + · simpa [Subsingleton.elim (cfc f a) 0] + · refine cfc_cases (‖·‖ < c) a f (by simpa) fun hf ha ↦ ?_ + simp only [← cfc_apply f a, (IsGreatest.norm_cfc f a hf ha |>.lt_iff)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma norm_cfc_lt_iff (f : 𝕜 → 𝕜) (a : A) {c : ℝ} (hc : 0 < c) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) + (ha : p a := by cfc_tac) : ‖cfc f a‖ < c ↔ ∀ x ∈ σ 𝕜 a, ‖f x‖ < c := + ⟨fun h _ hx ↦ norm_apply_le_norm_cfc f a hx hf ha |>.trans_lt h, norm_cfc_lt hc⟩ + +open NNReal + +lemma nnnorm_cfc_le {f : 𝕜 → 𝕜} {a : A} (c : ℝ≥0) (h : ∀ x ∈ σ 𝕜 a, ‖f x‖₊ ≤ c) : + ‖cfc f a‖₊ ≤ c := + norm_cfc_le c.2 h + +lemma nnnorm_cfc_le_iff (f : 𝕜 → 𝕜) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) + (ha : p a := by cfc_tac) : ‖cfc f a‖₊ ≤ c ↔ ∀ x ∈ σ 𝕜 a, ‖f x‖₊ ≤ c := + norm_cfc_le_iff f a c.2 + +lemma nnnorm_cfc_lt {f : 𝕜 → 𝕜} {a : A} {c : ℝ≥0} (hc : 0 < c) (h : ∀ x ∈ σ 𝕜 a, ‖f x‖₊ < c) : + ‖cfc f a‖₊ < c := + norm_cfc_lt hc h + +lemma nnnorm_cfc_lt_iff (f : 𝕜 → 𝕜) (a : A) {c : ℝ≥0} (hc : 0 < c) + (hf : ContinuousOn f (σ 𝕜 a) := by cfc_cont_tac) + (ha : p a := by cfc_tac) : ‖cfc f a‖₊ < c ↔ ∀ x ∈ σ 𝕜 a, ‖f x‖₊ < c := + norm_cfc_lt_iff f a hc + +end NormedRing + +namespace SpectrumRestricts + +variable {R S A : Type*} {p q : A → Prop} +variable [Semifield R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] +variable [Semifield S] [StarRing S] [MetricSpace S] [TopologicalSemiring S] [ContinuousStar S] +variable [Ring A] [StarRing A] [Algebra S A] +variable [Algebra R S] [Algebra R A] [IsScalarTower R S A] [StarModule R S] [ContinuousSMul R S] +variable [MetricSpace A] [IsometricContinuousFunctionalCalculus S A q] +variable [CompleteSpace R] [UniqueContinuousFunctionalCalculus R A] + +open scoped ContinuousFunctionalCalculus in +protected theorem isometric_cfc (f : C(S, R)) (halg : Isometry (algebraMap R S)) (h0 : p 0) + (h : ∀ a, p a ↔ q a ∧ SpectrumRestricts a f) : + IsometricContinuousFunctionalCalculus R A p where + toContinuousFunctionalCalculus := SpectrumRestricts.cfc f halg.isUniformEmbedding h0 h + isometric a ha := by + obtain ⟨ha', haf⟩ := h a |>.mp ha + have _inst (a : A) : CompactSpace (σ R a) := by + rw [← isCompact_iff_compactSpace, ← spectrum.preimage_algebraMap S] + exact halg.isClosedEmbedding.isCompact_preimage <| + ContinuousFunctionalCalculus.isCompact_spectrum a + have := SpectrumRestricts.cfc f halg.isUniformEmbedding h0 h + rw [cfcHom_eq_restrict f halg.isUniformEmbedding ha ha' haf] + refine .of_dist_eq fun g₁ g₂ ↦ ?_ + simp only [starAlgHom_apply, isometry_cfcHom a ha' |>.dist_eq] + refine le_antisymm ?_ ?_ + all_goals refine ContinuousMap.dist_le dist_nonneg |>.mpr fun x ↦ ?_ + · simpa [halg.dist_eq] using ContinuousMap.dist_apply_le_dist _ + · let x' : σ S a := Subtype.map (algebraMap R S) (fun _ ↦ spectrum.algebraMap_mem S) x + apply le_of_eq_of_le ?_ <| ContinuousMap.dist_apply_le_dist x' + simp only [ContinuousMap.comp_apply, ContinuousMap.coe_mk, StarAlgHom.ofId_apply, + halg.dist_eq, x'] + congr! + all_goals ext; exact haf.left_inv _ |>.symm + +end SpectrumRestricts + +end Unital + +/-! ### Isometric continuous functional calculus for non-unital algebras -/ + +section NonUnital + +/-- An extension of the `NonUnitalContinuousFunctionalCalculus` requiring that `cfcₙHom` is an +isometry. -/ +class NonUnitalIsometricContinuousFunctionalCalculus (R A : Type*) (p : outParam (A → Prop)) + [CommSemiring R] [Nontrivial R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] + [ContinuousStar R] [NonUnitalRing A] [StarRing A] [MetricSpace A] [Module R A] + [IsScalarTower R A A] [SMulCommClass R A A] + extends NonUnitalContinuousFunctionalCalculus R p : Prop where + isometric (a : A) (ha : p a) : Isometry (cfcₙHom ha (R := R)) + +section MetricSpace + +variable {R A : Type*} {p : outParam (A → Prop)} +variable [CommSemiring R] [Nontrivial R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] +variable [ContinuousStar R] +variable [NonUnitalRing A] [StarRing A] [MetricSpace A] [Module R A] +variable [IsScalarTower R A A] [SMulCommClass R A A] + +open scoped NonUnitalContinuousFunctionalCalculus + +variable [NonUnitalIsometricContinuousFunctionalCalculus R A p] + +lemma isometry_cfcₙHom (a : A) (ha : p a := by cfc_tac) : + Isometry (cfcₙHom (show p a from ha) (R := R)) := + NonUnitalIsometricContinuousFunctionalCalculus.isometric a ha + +end MetricSpace + +section NormedRing + +variable {𝕜 A : Type*} {p : outParam (A → Prop)} +variable [RCLike 𝕜] [NonUnitalNormedRing A] [StarRing A] [NormedSpace 𝕜 A] [IsScalarTower 𝕜 A A] +variable [SMulCommClass 𝕜 A A] +variable [NonUnitalIsometricContinuousFunctionalCalculus 𝕜 A p] + +open NonUnitalIsometricContinuousFunctionalCalculus +open scoped ContinuousMapZero NonUnitalContinuousFunctionalCalculus + +lemma norm_cfcₙHom (a : A) (f : C(σₙ 𝕜 a, 𝕜)₀) (ha : p a := by cfc_tac) : + ‖cfcₙHom (show p a from ha) f‖ = ‖f‖ := by + refine isometry_cfcₙHom a |>.norm_map_of_map_zero (map_zero _) f + +lemma nnnorm_cfcₙHom (a : A) (f : C(σₙ 𝕜 a, 𝕜)₀) (ha : p a := by cfc_tac) : + ‖cfcₙHom (show p a from ha) f‖₊ = ‖f‖₊ := + Subtype.ext <| norm_cfcₙHom a f ha + +lemma IsGreatest.norm_cfcₙ (f : 𝕜 → 𝕜) (a : A) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : IsGreatest ((fun x ↦ ‖f x‖) '' σₙ 𝕜 a) ‖cfcₙ f a‖ := by + obtain ⟨x, hx⟩ := NonUnitalContinuousFunctionalCalculus.isCompact_quasispectrum a + |>.image_of_continuousOn hf.norm |>.exists_isGreatest <| + (quasispectrum.nonempty 𝕜 a).image _ + obtain ⟨x, hx', rfl⟩ := hx.1 + convert hx + rw [cfcₙ_apply f a, norm_cfcₙHom a _] + apply le_antisymm + · apply ContinuousMap.norm_le _ (norm_nonneg _) |>.mpr + rintro ⟨y, hy⟩ + exact hx.2 ⟨y, hy, rfl⟩ + · exact le_trans (by simp) <| ContinuousMap.norm_coe_le_norm _ (⟨x, hx'⟩ : σₙ 𝕜 a) + +lemma IsGreatest.nnnorm_cfcₙ (f : 𝕜 → 𝕜) (a : A) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : IsGreatest ((fun x ↦ ‖f x‖₊) '' σₙ 𝕜 a) ‖cfcₙ f a‖₊ := by + convert Real.toNNReal_mono.map_isGreatest (.norm_cfcₙ f a) + all_goals simp [Set.image_image, norm_toNNReal] + +lemma norm_apply_le_norm_cfcₙ (f : 𝕜 → 𝕜) (a : A) ⦃x : 𝕜⦄ (hx : x ∈ σₙ 𝕜 a) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖f x‖ ≤ ‖cfcₙ f a‖ := + IsGreatest.norm_cfcₙ f a hf hf₀ ha |>.2 ⟨x, hx, rfl⟩ + +lemma nnnorm_apply_le_nnnorm_cfcₙ (f : 𝕜 → 𝕜) (a : A) ⦃x : 𝕜⦄ (hx : x ∈ σₙ 𝕜 a) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖f x‖₊ ≤ ‖cfcₙ f a‖₊ := + IsGreatest.nnnorm_cfcₙ f a hf hf₀ ha |>.2 ⟨x, hx, rfl⟩ + +lemma norm_cfcₙ_le {f : 𝕜 → 𝕜} {a : A} {c : ℝ} (h : ∀ x ∈ σₙ 𝕜 a, ‖f x‖ ≤ c) : + ‖cfcₙ f a‖ ≤ c := by + refine cfcₙ_cases (‖·‖ ≤ c) a f ?_ fun hf hf0 ha ↦ ?_ + · simpa using (norm_nonneg _).trans <| h 0 (quasispectrum.zero_mem 𝕜 a) + · simp only [← cfcₙ_apply f a, isLUB_le_iff (IsGreatest.norm_cfcₙ f a hf hf0 ha |>.isLUB)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma norm_cfcₙ_le_iff (f : 𝕜 → 𝕜) (a : A) (c : ℝ) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖cfcₙ f a‖ ≤ c ↔ ∀ x ∈ σₙ 𝕜 a, ‖f x‖ ≤ c := + ⟨fun h _ hx ↦ norm_apply_le_norm_cfcₙ f a hx hf hf₀ ha |>.trans h, norm_cfcₙ_le⟩ + +lemma norm_cfcₙ_lt {f : 𝕜 → 𝕜} {a : A} {c : ℝ} (h : ∀ x ∈ σₙ 𝕜 a, ‖f x‖ < c) : + ‖cfcₙ f a‖ < c := by + refine cfcₙ_cases (‖·‖ < c) a f ?_ fun hf hf0 ha ↦ ?_ + · simpa using (norm_nonneg _).trans_lt <| h 0 (quasispectrum.zero_mem 𝕜 a) + · simp only [← cfcₙ_apply f a, (IsGreatest.norm_cfcₙ f a hf hf0 ha |>.lt_iff)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma norm_cfcₙ_lt_iff (f : 𝕜 → 𝕜) (a : A) (c : ℝ) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖cfcₙ f a‖ < c ↔ ∀ x ∈ σₙ 𝕜 a, ‖f x‖ < c := + ⟨fun h _ hx ↦ norm_apply_le_norm_cfcₙ f a hx hf hf₀ ha |>.trans_lt h, norm_cfcₙ_lt⟩ + +open NNReal + +lemma nnnorm_cfcₙ_le {f : 𝕜 → 𝕜} {a : A} {c : ℝ≥0} (h : ∀ x ∈ σₙ 𝕜 a, ‖f x‖₊ ≤ c) : + ‖cfcₙ f a‖₊ ≤ c := + norm_cfcₙ_le h + +lemma nnnorm_cfcₙ_le_iff (f : 𝕜 → 𝕜) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖cfcₙ f a‖₊ ≤ c ↔ ∀ x ∈ σₙ 𝕜 a, ‖f x‖₊ ≤ c := + norm_cfcₙ_le_iff f a c.1 hf hf₀ ha + +lemma nnnorm_cfcₙ_lt {f : 𝕜 → 𝕜} {a : A} {c : ℝ≥0} (h : ∀ x ∈ σₙ 𝕜 a, ‖f x‖₊ < c) : + ‖cfcₙ f a‖₊ < c := + norm_cfcₙ_lt h + +lemma nnnorm_cfcₙ_lt_iff (f : 𝕜 → 𝕜) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σₙ 𝕜 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : p a := by cfc_tac) : ‖cfcₙ f a‖₊ < c ↔ ∀ x ∈ σₙ 𝕜 a, ‖f x‖₊ < c := + norm_cfcₙ_lt_iff f a c.1 hf hf₀ ha + +end NormedRing + +namespace QuasispectrumRestricts + +open NonUnitalIsometricContinuousFunctionalCalculus + +variable {R S A : Type*} {p q : A → Prop} +variable [Semifield R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] +variable [Field S] [StarRing S] [MetricSpace S] [TopologicalRing S] [ContinuousStar S] +variable [NonUnitalRing A] [StarRing A] [Module S A] [IsScalarTower S A A] +variable [SMulCommClass S A A] +variable [Algebra R S] [Module R A] [IsScalarTower R S A] [StarModule R S] [ContinuousSMul R S] +variable [IsScalarTower R A A] [SMulCommClass R A A] +variable [MetricSpace A] [NonUnitalIsometricContinuousFunctionalCalculus S A q] +variable [CompleteSpace R] [UniqueNonUnitalContinuousFunctionalCalculus R A] + +open scoped NonUnitalContinuousFunctionalCalculus in +protected theorem isometric_cfc (f : C(S, R)) (halg : Isometry (algebraMap R S)) (h0 : p 0) + (h : ∀ a, p a ↔ q a ∧ QuasispectrumRestricts a f) : + NonUnitalIsometricContinuousFunctionalCalculus R A p where + toNonUnitalContinuousFunctionalCalculus := QuasispectrumRestricts.cfc f + halg.isUniformEmbedding h0 h + isometric a ha := by + obtain ⟨ha', haf⟩ := h a |>.mp ha + have _inst (a : A) : CompactSpace (σₙ R a) := by + rw [← isCompact_iff_compactSpace, ← quasispectrum.preimage_algebraMap S] + exact halg.isClosedEmbedding.isCompact_preimage <| + NonUnitalContinuousFunctionalCalculus.isCompact_quasispectrum a + have := QuasispectrumRestricts.cfc f halg.isUniformEmbedding h0 h + rw [cfcₙHom_eq_restrict f halg.isUniformEmbedding ha ha' haf] + refine .of_dist_eq fun g₁ g₂ ↦ ?_ + simp only [nonUnitalStarAlgHom_apply, isometry_cfcₙHom a ha' |>.dist_eq] + refine le_antisymm ?_ ?_ + all_goals refine ContinuousMap.dist_le dist_nonneg |>.mpr fun x ↦ ?_ + · simpa [halg.dist_eq] using ContinuousMap.dist_apply_le_dist _ + · let x' : σₙ S a := Subtype.map (algebraMap R S) (fun _ ↦ quasispectrum.algebraMap_mem S) x + apply le_of_eq_of_le ?_ <| ContinuousMap.dist_apply_le_dist x' + simp only [ContinuousMap.coe_coe, ContinuousMapZero.comp_apply, ContinuousMapZero.coe_mk, + ContinuousMap.coe_mk, StarAlgHom.ofId_apply, halg.dist_eq, x'] + congr! 2 + all_goals ext; exact haf.left_inv _ |>.symm + +end QuasispectrumRestricts + +end NonUnital + +/-! ### Instances of isometric continuous functional calculi -/ + +section Instances + +section Unital + +section Complex + +variable {A : Type*} [CStarAlgebra A] + +instance IsStarNormal.instIsometricContinuousFunctionalCalculus : + IsometricContinuousFunctionalCalculus ℂ A IsStarNormal where + isometric a ha := by + rw [cfcHom_eq_of_isStarNormal] + exact isometry_subtype_coe.comp <| StarAlgEquiv.isometry (continuousFunctionalCalculus a) + +instance IsSelfAdjoint.instIsometricContinuousFunctionalCalculus : + IsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint := + SpectrumRestricts.isometric_cfc Complex.reCLM Complex.isometry_ofReal (.zero _) + fun _ ↦ isSelfAdjoint_iff_isStarNormal_and_spectrumRestricts + +end Complex + +section NNReal + +variable {A : Type*} [NormedRing A] [PartialOrder A] [StarRing A] [StarOrderedRing A] +variable [NormedAlgebra ℝ A] [IsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint] +variable [NonnegSpectrumClass ℝ A] [UniqueContinuousFunctionalCalculus ℝ A] + +open NNReal in +instance Nonneg.instIsometricContinuousFunctionalCalculus : + IsometricContinuousFunctionalCalculus ℝ≥0 A (0 ≤ ·) := + SpectrumRestricts.isometric_cfc (q := IsSelfAdjoint) ContinuousMap.realToNNReal + isometry_subtype_coe le_rfl (fun _ ↦ nonneg_iff_isSelfAdjoint_and_spectrumRestricts) + +end NNReal + +end Unital + +section NonUnital + +section Complex + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +open Unitization + + +open ContinuousMapZero in +instance IsStarNormal.instNonUnitalIsometricContinuousFunctionalCalculus : + NonUnitalIsometricContinuousFunctionalCalculus ℂ A IsStarNormal where + isometric a ha := by + refine AddMonoidHomClass.isometry_of_norm _ fun f ↦ ?_ + rw [← norm_inr (𝕜 := ℂ), ← inrNonUnitalStarAlgHom_apply, ← NonUnitalStarAlgHom.comp_apply, + inr_comp_cfcₙHom_eq_cfcₙAux a, cfcₙAux] + simp only [NonUnitalStarAlgHom.comp_assoc, NonUnitalStarAlgHom.comp_apply, + toContinuousMapHom_apply, NonUnitalStarAlgHom.coe_coe] + rw [norm_cfcHom (a : Unitization ℂ A), StarAlgEquiv.norm_map] + rfl + +instance IsSelfAdjoint.instNonUnitalIsometricContinuousFunctionalCalculus : + NonUnitalIsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint := + QuasispectrumRestricts.isometric_cfc Complex.reCLM Complex.isometry_ofReal (.zero _) + fun _ ↦ isSelfAdjoint_iff_isStarNormal_and_quasispectrumRestricts + +end Complex + +section NNReal + +variable {A : Type*} [NonUnitalNormedRing A] [PartialOrder A] [StarRing A] [StarOrderedRing A] +variable [NormedSpace ℝ A] [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] +variable [NonUnitalIsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint] +variable [NonnegSpectrumClass ℝ A] [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + +open NNReal in +instance Nonneg.instNonUnitalIsometricContinuousFunctionalCalculus : + NonUnitalIsometricContinuousFunctionalCalculus ℝ≥0 A (0 ≤ ·) := + QuasispectrumRestricts.isometric_cfc (q := IsSelfAdjoint) ContinuousMap.realToNNReal + isometry_subtype_coe le_rfl (fun _ ↦ nonneg_iff_isSelfAdjoint_and_quasispectrumRestricts) + +end NNReal + +end NonUnital + +end Instances + +/-! ### Properties specific to `ℝ≥0` -/ + +section NNReal + +open NNReal + +section Unital + +variable {A : Type*} [NormedRing A] [StarRing A] [NormedAlgebra ℝ A] [PartialOrder A] +variable [StarOrderedRing A] [IsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint] +variable [NonnegSpectrumClass ℝ A] [UniqueContinuousFunctionalCalculus ℝ A] + +lemma IsGreatest.nnnorm_cfc_nnreal [Nontrivial A] (f : ℝ≥0 → ℝ≥0) (a : A) + (hf : ContinuousOn f (σ ℝ≥0 a) := by cfc_cont_tac) (ha : 0 ≤ a := by cfc_tac) : + IsGreatest (f '' σ ℝ≥0 a) ‖cfc f a‖₊ := by + rw [cfc_nnreal_eq_real] + obtain ⟨-, ha'⟩ := nonneg_iff_isSelfAdjoint_and_spectrumRestricts.mp ha + convert IsGreatest.nnnorm_cfc (fun x : ℝ ↦ (f x.toNNReal : ℝ)) a ?hf_cont + case hf_cont => exact continuous_subtype_val.comp_continuousOn <| + ContinuousOn.comp ‹_› continuous_real_toNNReal.continuousOn <| ha'.image ▸ Set.mapsTo_image .. + ext x + constructor + all_goals rintro ⟨x, hx, rfl⟩ + · exact ⟨x, spectrum.algebraMap_mem ℝ hx, by simp⟩ + · exact ⟨x.toNNReal, ha'.apply_mem hx, by simp⟩ + +lemma apply_le_nnnorm_cfc_nnreal (f : ℝ≥0 → ℝ≥0) (a : A) ⦃x : ℝ≥0⦄ (hx : x ∈ σ ℝ≥0 a) + (hf : ContinuousOn f (σ ℝ≥0 a) := by cfc_cont_tac) (ha : 0 ≤ a := by cfc_tac) : + f x ≤ ‖cfc f a‖₊ := by + revert hx + nontriviality A + exact (IsGreatest.nnnorm_cfc_nnreal f a hf ha |>.2 ⟨x, ·, rfl⟩) + +lemma nnnorm_cfc_nnreal_le {f : ℝ≥0 → ℝ≥0} {a : A} {c : ℝ≥0} (h : ∀ x ∈ σ ℝ≥0 a, f x ≤ c) : + ‖cfc f a‖₊ ≤ c := by + obtain (_ | _) := subsingleton_or_nontrivial A + · rw [Subsingleton.elim (cfc f a) 0] + simp + · refine cfc_cases (‖·‖₊ ≤ c) a f (by simp) fun hf ha ↦ ?_ + simp only [← cfc_apply f a, isLUB_le_iff (IsGreatest.nnnorm_cfc_nnreal f a hf ha |>.isLUB)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma nnnorm_cfc_nnreal_le_iff (f : ℝ≥0 → ℝ≥0) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σ ℝ≥0 a) := by cfc_cont_tac) + (ha : 0 ≤ a := by cfc_tac) : ‖cfc f a‖₊ ≤ c ↔ ∀ x ∈ σ ℝ≥0 a, f x ≤ c := + ⟨fun h _ hx ↦ apply_le_nnnorm_cfc_nnreal f a hx hf ha |>.trans h, nnnorm_cfc_nnreal_le⟩ + +lemma nnnorm_cfc_nnreal_lt {f : ℝ≥0 → ℝ≥0} {a : A} {c : ℝ≥0} (hc : 0 < c) + (h : ∀ x ∈ σ ℝ≥0 a, f x < c) : ‖cfc f a‖₊ < c := by + obtain (_ | _) := subsingleton_or_nontrivial A + · rw [Subsingleton.elim (cfc f a) 0] + simpa + · refine cfc_cases (‖·‖₊ < c) a f (by simpa) fun hf ha ↦ ?_ + simp only [← cfc_apply f a, (IsGreatest.nnnorm_cfc_nnreal f a hf ha |>.lt_iff)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma nnnorm_cfc_nnreal_lt_iff (f : ℝ≥0 → ℝ≥0) (a : A) {c : ℝ≥0} (hc : 0 < c) + (hf : ContinuousOn f (σ ℝ≥0 a) := by cfc_cont_tac) + (ha : 0 ≤ a := by cfc_tac) : ‖cfc f a‖₊ < c ↔ ∀ x ∈ σ ℝ≥0 a, f x < c := + ⟨fun h _ hx ↦ apply_le_nnnorm_cfc_nnreal f a hx hf ha |>.trans_lt h, nnnorm_cfc_nnreal_lt hc⟩ + +end Unital + +section NonUnital + +variable {A : Type*} [NonUnitalNormedRing A] [StarRing A] [NormedSpace ℝ A] +variable [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] [PartialOrder A] +variable [StarOrderedRing A] [NonUnitalIsometricContinuousFunctionalCalculus ℝ A IsSelfAdjoint] +variable [NonnegSpectrumClass ℝ A] [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + +lemma IsGreatest.nnnorm_cfcₙ_nnreal (f : ℝ≥0 → ℝ≥0) (a : A) + (hf : ContinuousOn f (σₙ ℝ≥0 a) := by cfc_cont_tac) (hf0 : f 0 = 0 := by cfc_zero_tac) + (ha : 0 ≤ a := by cfc_tac) : IsGreatest (f '' σₙ ℝ≥0 a) ‖cfcₙ f a‖₊ := by + rw [cfcₙ_nnreal_eq_real] + obtain ⟨-, ha'⟩ := nonneg_iff_isSelfAdjoint_and_quasispectrumRestricts.mp ha + convert IsGreatest.nnnorm_cfcₙ (fun x : ℝ ↦ (f x.toNNReal : ℝ)) a ?hf_cont (by simpa) + case hf_cont => exact continuous_subtype_val.comp_continuousOn <| + ContinuousOn.comp ‹_› continuous_real_toNNReal.continuousOn <| ha'.image ▸ Set.mapsTo_image .. + ext x + constructor + all_goals rintro ⟨x, hx, rfl⟩ + · exact ⟨x, quasispectrum.algebraMap_mem ℝ hx, by simp⟩ + · exact ⟨x.toNNReal, ha'.apply_mem hx, by simp⟩ + +lemma apply_le_nnnorm_cfcₙ_nnreal (f : ℝ≥0 → ℝ≥0) (a : A) ⦃x : ℝ≥0⦄ (hx : x ∈ σₙ ℝ≥0 a) + (hf : ContinuousOn f (σₙ ℝ≥0 a) := by cfc_cont_tac) (hf0 : f 0 = 0 := by cfc_zero_tac) + (ha : 0 ≤ a := by cfc_tac) : f x ≤ ‖cfcₙ f a‖₊ := by + revert hx + exact (IsGreatest.nnnorm_cfcₙ_nnreal f a hf hf0 ha |>.2 ⟨x, ·, rfl⟩) + +lemma nnnorm_cfcₙ_nnreal_le {f : ℝ≥0 → ℝ≥0} {a : A} {c : ℝ≥0} (h : ∀ x ∈ σₙ ℝ≥0 a, f x ≤ c) : + ‖cfcₙ f a‖₊ ≤ c := by + refine cfcₙ_cases (‖·‖₊ ≤ c) a f (by simp) fun hf hf0 ha ↦ ?_ + simp only [← cfcₙ_apply f a, isLUB_le_iff (IsGreatest.nnnorm_cfcₙ_nnreal f a hf hf0 ha |>.isLUB)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma nnnorm_cfcₙ_nnreal_le_iff (f : ℝ≥0 → ℝ≥0) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σₙ ℝ≥0 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : 0 ≤ a := by cfc_tac) : ‖cfcₙ f a‖₊ ≤ c ↔ ∀ x ∈ σₙ ℝ≥0 a, f x ≤ c := + ⟨fun h _ hx ↦ apply_le_nnnorm_cfcₙ_nnreal f a hx hf hf₀ ha |>.trans h, nnnorm_cfcₙ_nnreal_le⟩ + +lemma nnnorm_cfcₙ_nnreal_lt {f : ℝ≥0 → ℝ≥0} {a : A} {c : ℝ≥0} (h : ∀ x ∈ σₙ ℝ≥0 a, f x < c) : + ‖cfcₙ f a‖₊ < c := by + refine cfcₙ_cases (‖·‖₊ < c) a f ?_ fun hf hf0 ha ↦ ?_ + · simpa using zero_le (f 0) |>.trans_lt <| h 0 (quasispectrum.zero_mem ℝ≥0 _) + · simp only [← cfcₙ_apply f a, (IsGreatest.nnnorm_cfcₙ_nnreal f a hf hf0 ha |>.lt_iff)] + rintro - ⟨x, hx, rfl⟩ + exact h x hx + +lemma nnnorm_cfcₙ_nnreal_lt_iff (f : ℝ≥0 → ℝ≥0) (a : A) (c : ℝ≥0) + (hf : ContinuousOn f (σₙ ℝ≥0 a) := by cfc_cont_tac) (hf₀ : f 0 = 0 := by cfc_zero_tac) + (ha : 0 ≤ a := by cfc_tac) : ‖cfcₙ f a‖₊ < c ↔ ∀ x ∈ σₙ ℝ≥0 a, f x < c := + ⟨fun h _ hx ↦ apply_le_nnnorm_cfcₙ_nnreal f a hx hf hf₀ ha |>.trans_lt h, nnnorm_cfcₙ_nnreal_lt⟩ + +end NonUnital + +end NNReal diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean index a298ba04ac176..3d40d1c59a022 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean @@ -73,11 +73,16 @@ class NonUnitalContinuousFunctionalCalculus (R : Type*) {A : Type*} (p : outPara [ContinuousStar R] [NonUnitalRing A] [StarRing A] [TopologicalSpace A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] : Prop where predicate_zero : p 0 + [compactSpace_quasispectrum : ∀ a : A, CompactSpace (σₙ R a)] exists_cfc_of_predicate : ∀ a, p a → ∃ φ : C(σₙ R a, R)₀ →⋆ₙₐ[R] A, - ClosedEmbedding φ ∧ φ ⟨(ContinuousMap.id R).restrict <| σₙ R a, rfl⟩ = a ∧ + IsClosedEmbedding φ ∧ φ ⟨(ContinuousMap.id R).restrict <| σₙ R a, rfl⟩ = a ∧ (∀ f, σₙ R (φ f) = Set.range f) ∧ ∀ f, p (φ f) --- TODO: try to unify with the unital version. The `ℝ≥0` case makes it tricky. +-- this instance should not be activated everywhere but it is useful when developing generic API +-- for the continuous functional calculus +scoped[NonUnitalContinuousFunctionalCalculus] +attribute [instance] NonUnitalContinuousFunctionalCalculus.compactSpace_quasispectrum + /-- A class guaranteeing that the non-unital continuous functional calculus is uniquely determined by the properties that it is a continuous non-unital star algebra homomorphism mapping the (restriction of) the identity to `a`. This is the necessary tool used to establish `cfcₙHom_comp` @@ -101,6 +106,11 @@ variable [TopologicalSemiring R] [ContinuousStar R] [NonUnitalRing A] [StarRing variable [TopologicalSpace A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] variable [instCFCₙ : NonUnitalContinuousFunctionalCalculus R p] +include instCFCₙ in +lemma NonUnitalContinuousFunctionalCalculus.isCompact_quasispectrum (a : A) : + IsCompact (σₙ R a) := + isCompact_iff_compactSpace.mpr inferInstance + lemma NonUnitalStarAlgHom.ext_continuousMap [UniqueNonUnitalContinuousFunctionalCalculus R A] (a : A) (φ ψ : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) (hφ : Continuous φ) (hψ : Continuous ψ) (h : φ ⟨.restrict (σₙ R a) <| .id R, rfl⟩ = ψ ⟨.restrict (σₙ R a) <| .id R, rfl⟩) : @@ -123,13 +133,16 @@ the user should instead prefer `cfcₙ` over `cfcₙHom`. noncomputable def cfcₙHom : C(σₙ R a, R)₀ →⋆ₙₐ[R] A := (NonUnitalContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose -lemma cfcₙHom_closedEmbedding : - ClosedEmbedding <| (cfcₙHom ha : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) := +lemma cfcₙHom_isClosedEmbedding : + IsClosedEmbedding <| (cfcₙHom ha : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) := (NonUnitalContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.1 +@[deprecated (since := "2024-10-20")] +alias cfcₙHom_closedEmbedding := cfcₙHom_isClosedEmbedding + @[fun_prop] lemma cfcₙHom_continuous : Continuous (cfcₙHom ha : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) := - cfcₙHom_closedEmbedding ha |>.continuous + cfcₙHom_isClosedEmbedding ha |>.continuous lemma cfcₙHom_id : cfcₙHom ha ⟨(ContinuousMap.id R).restrict <| σₙ R a, rfl⟩ = a := @@ -147,7 +160,7 @@ lemma cfcₙHom_predicate (f : C(σₙ R a, R)₀) : lemma cfcₙHom_eq_of_continuous_of_map_id [UniqueNonUnitalContinuousFunctionalCalculus R A] (φ : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) (hφ₁ : Continuous φ) (hφ₂ : φ ⟨.restrict (σₙ R a) <| .id R, rfl⟩ = a) : cfcₙHom ha = φ := - (cfcₙHom ha).ext_continuousMap a φ (cfcₙHom_closedEmbedding ha).continuous hφ₁ <| by + (cfcₙHom ha).ext_continuousMap a φ (cfcₙHom_isClosedEmbedding ha).continuous hφ₁ <| by rw [cfcₙHom_id ha, hφ₂] theorem cfcₙHom_comp [UniqueNonUnitalContinuousFunctionalCalculus R A] (f : C(σₙ R a, R)₀) @@ -164,8 +177,8 @@ theorem cfcₙHom_comp [UniqueNonUnitalContinuousFunctionalCalculus R A] (f : C( let φ : C(σₙ R (cfcₙHom ha f), R)₀ →⋆ₙₐ[R] A := (cfcₙHom ha).comp ψ suffices cfcₙHom (cfcₙHom_predicate ha f) = φ from DFunLike.congr_fun this.symm g refine cfcₙHom_eq_of_continuous_of_map_id (cfcₙHom_predicate ha f) φ ?_ ?_ - · refine (cfcₙHom_closedEmbedding ha).continuous.comp <| continuous_induced_rng.mpr ?_ - exact f'.toContinuousMap.continuous_comp_left.comp continuous_induced_dom + · refine (cfcₙHom_isClosedEmbedding ha).continuous.comp <| continuous_induced_rng.mpr ?_ + exact f'.toContinuousMap.continuous_precomp.comp continuous_induced_dom · simp only [φ, ψ, NonUnitalStarAlgHom.comp_apply, NonUnitalStarAlgHom.coe_mk', NonUnitalAlgHom.coe_mk] congr @@ -182,7 +195,7 @@ noncomputable def cfcₙL {a : A} (ha : p a) : C(σₙ R a, R)₀ →L[R] A := { cfcₙHom ha with toFun := cfcₙHom ha map_smul' := map_smul _ - cont := (cfcₙHom_closedEmbedding ha).continuous } + cont := (cfcₙHom_isClosedEmbedding ha).continuous } end cfcₙL @@ -259,6 +272,11 @@ lemma cfcₙ_cases (P : A → Prop) (a : A) (f : R → R) (h₀ : P 0) · rwa [cfcₙ_apply_of_not_map_zero _ h] · rwa [cfcₙ_apply_of_not_predicate _ h] +lemma cfcₙ_commute_cfcₙ (f g : R → R) (a : A) : Commute (cfcₙ f a) (cfcₙ g a) := by + refine cfcₙ_cases (fun x ↦ Commute x (cfcₙ g a)) a f (by simp) fun hf hf0 ha ↦ ?_ + refine cfcₙ_cases (fun x ↦ Commute _ x) a g (by simp) fun hg hg0 _ ↦ ?_ + exact Commute.all _ _ |>.map _ + variable (R) in include ha in lemma cfcₙ_id : cfcₙ (id : R → R) a = a := @@ -301,7 +319,7 @@ lemma eqOn_of_cfcₙ_eq_cfcₙ {f g : R → R} {a : A} (h : cfcₙ f a = cfcₙ (hg : ContinuousOn g (σₙ R a) := by cfc_cont_tac) (hg0 : g 0 = 0 := by cfc_zero_tac) : (σₙ R a).EqOn f g := by rw [cfcₙ_apply f a, cfcₙ_apply g a] at h - have := (cfcₙHom_closedEmbedding (show p a from ha) (R := R)).inj h + have := (cfcₙHom_isClosedEmbedding (show p a from ha) (R := R)).inj h intro x hx congrm($(this) ⟨x, hx⟩) @@ -640,6 +658,50 @@ end Ring end Order +/-! ### `cfcₙHom` on a superset of the quasispectrum -/ + +section Superset + +open ContinuousMapZero + +variable {R A : Type*} {p : A → Prop} [CommSemiring R] [Nontrivial R] [StarRing R] + [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] [NonUnitalRing A] [StarRing A] + [TopologicalSpace A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] + [instCFCₙ : NonUnitalContinuousFunctionalCalculus R p] + +/-- The composition of `cfcₙHom` with the natural embedding `C(s, R)₀ → C(quasispectrum R a, R)₀` +whenever `quasispectrum R a ⊆ s`. + +This is sometimes necessary in order to consider the same continuous functions applied to multiple +distinct elements, with the added constraint that `cfcₙ` does not suffice. This can occur, for +example, if it is necessary to use uniqueness of this continuous functional calculus. A practical +example can be found in the proof of `CFC.posPart_negPart_unique`. -/ +@[simps!] +noncomputable def cfcₙHomSuperset {a : A} (ha : p a) {s : Set R} (hs : σₙ R a ⊆ s) : + letI : Zero s := ⟨0, hs (quasispectrum.zero_mem R a)⟩ + C(s, R)₀ →⋆ₙₐ[R] A := + letI : Zero s := ⟨0, hs (quasispectrum.zero_mem R a)⟩ + cfcₙHom ha (R := R) |>.comp <| ContinuousMapZero.nonUnitalStarAlgHom_precomp R <| + ⟨⟨_, continuous_id.subtype_map hs⟩, rfl⟩ + +lemma cfcₙHomSuperset_continuous {a : A} (ha : p a) {s : Set R} (hs : σₙ R a ⊆ s) : + Continuous (cfcₙHomSuperset ha hs) := + letI : Zero s := ⟨0, hs (quasispectrum.zero_mem R a)⟩ + (cfcₙHom_continuous ha).comp <| ContinuousMapZero.continuous_comp_left _ + +lemma cfcₙHomSuperset_id {a : A} (ha : p a) {s : Set R} (hs : σₙ R a ⊆ s) : + letI : Zero s := ⟨0, hs (quasispectrum.zero_mem R a)⟩ + cfcₙHomSuperset ha hs ⟨.restrict s <| .id R, rfl⟩ = a := + cfcₙHom_id ha + +/-- this version uses `ContinuousMapZero.id`. -/ +lemma cfcₙHomSuperset_id' {a : A} (ha : p a) {s : Set R} (hs : σₙ R a ⊆ s) : + letI : Zero s := ⟨0, hs (quasispectrum.zero_mem R a)⟩ + cfcₙHomSuperset ha hs (.id rfl) = a := + cfcₙHom_id ha + +end Superset + /-! ### Obtain a non-unital continuous functional calculus from a unital one -/ section UnitalToNonUnital @@ -685,14 +747,17 @@ lemma cfcₙHom_of_cfcHom_map_quasispectrum {a : A} (ha : p a) : simp only [Set.mem_singleton_iff] at hx ⊢ rw [show x = 0 from Subtype.val_injective hx, map_zero] -variable [CompleteSpace R] [h_cpct : ∀ a : A, CompactSpace (spectrum R a)] +variable [CompleteSpace R] + +-- gives access to the `ContinuousFunctionalCalculus.compactSpace_spectrum` instance +open scoped ContinuousFunctionalCalculus -lemma closedEmbedding_cfcₙHom_of_cfcHom {a : A} (ha : p a) : - ClosedEmbedding (cfcₙHom_of_cfcHom R ha) := by +lemma isClosedEmbedding_cfcₙHom_of_cfcHom {a : A} (ha : p a) : + IsClosedEmbedding (cfcₙHom_of_cfcHom R ha) := by let f : C(spectrum R a, σₙ R a) := ⟨_, continuous_inclusion <| spectrum_subset_quasispectrum R a⟩ - refine (cfcHom_closedEmbedding ha).comp <| - (UniformInducing.isUniformEmbedding ⟨?_⟩).toClosedEmbedding + refine (cfcHom_isClosedEmbedding ha).comp <| + (IsUniformInducing.isUniformEmbedding ⟨?_⟩).toIsClosedEmbedding have := uniformSpace_eq_inf_precomp_of_cover (β := R) f (0 : C(Unit, σₙ R a)) (map_continuous f).isProperMap (map_continuous 0).isProperMap <| by simp only [← Subtype.val_injective.image_injective.eq_iff, f, ContinuousMap.coe_mk, @@ -707,26 +772,30 @@ lemma closedEmbedding_cfcₙHom_of_cfcHom {a : A} (ha : p a) : convert Filter.comap_const_of_mem this with ⟨u, v⟩ <;> ext ⟨x, rfl⟩ <;> [exact map_zero u; exact map_zero v] +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_cfcₙHom_of_cfcHom := isClosedEmbedding_cfcₙHom_of_cfcHom + instance ContinuousFunctionalCalculus.toNonUnital : NonUnitalContinuousFunctionalCalculus R p where predicate_zero := cfc_predicate_zero R + compactSpace_quasispectrum a := by + have h_cpct : CompactSpace (spectrum R a) := inferInstance + simp only [← isCompact_iff_compactSpace, quasispectrum_eq_spectrum_union_zero] at h_cpct ⊢ + exact h_cpct |>.union isCompact_singleton exists_cfc_of_predicate _ ha := ⟨cfcₙHom_of_cfcHom R ha, - closedEmbedding_cfcₙHom_of_cfcHom ha, + isClosedEmbedding_cfcₙHom_of_cfcHom ha, cfcHom_id ha, cfcₙHom_of_cfcHom_map_quasispectrum ha, fun _ ↦ cfcHom_predicate ha _⟩ +open scoped NonUnitalContinuousFunctionalCalculus in lemma cfcₙHom_eq_cfcₙHom_of_cfcHom [UniqueNonUnitalContinuousFunctionalCalculus R A] {a : A} (ha : p a) : cfcₙHom (R := R) ha = cfcₙHom_of_cfcHom R ha := by - have h_cpct' : CompactSpace (σₙ R a) := by - specialize h_cpct a - simp_rw [← isCompact_iff_compactSpace, quasispectrum_eq_spectrum_union_zero] at h_cpct ⊢ - exact h_cpct.union isCompact_singleton refine UniqueNonUnitalContinuousFunctionalCalculus.eq_of_continuous_of_map_id (σₙ R a) ?_ _ _ ?_ ?_ ?_ · simp - · exact (cfcₙHom_closedEmbedding (R := R) ha).continuous - · exact (closedEmbedding_cfcₙHom_of_cfcHom ha).continuous + · exact (cfcₙHom_isClosedEmbedding (R := R) ha).continuous + · exact (isClosedEmbedding_cfcₙHom_of_cfcHom ha).continuous · simpa only [cfcₙHom_id (R := R) ha] using (cfcHom_id ha).symm /-- When `cfc` is applied to a function that maps zero to zero, it is equivalent to using diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean index 8536353d9475b..bb02c5b46fae0 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean @@ -14,7 +14,7 @@ import Mathlib.Topology.ContinuousMap.StarOrdered This file contains various basic facts about star-ordered rings (i.e. mainly C⋆-algebras) that depend on the continuous functional calculus. -We also put an order instance on `Unitization ℂ A` when `A` is a C⋆-algebra via +We also put an order instance on `A⁺¹ := Unitization ℂ A` when `A` is a C⋆-algebra via the spectral order. ## Main theorems @@ -35,30 +35,66 @@ the spectral order. continuous functional calculus, normal, selfadjoint -/ -open scoped NNReal +open scoped NNReal CStarAlgebra + +local notation "σₙ" => quasispectrum + +theorem cfc_tsub {A : Type*} [TopologicalSpace A] [Ring A] [PartialOrder A] [StarRing A] + [StarOrderedRing A] [Algebra ℝ A] [TopologicalRing A] + [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + [UniqueContinuousFunctionalCalculus ℝ A] [NonnegSpectrumClass ℝ A] (f g : ℝ≥0 → ℝ≥0) + (a : A) (hfg : ∀ x ∈ spectrum ℝ≥0 a, g x ≤ f x) (ha : 0 ≤ a := by cfc_tac) + (hf : ContinuousOn f (spectrum ℝ≥0 a) := by cfc_cont_tac) + (hg : ContinuousOn g (spectrum ℝ≥0 a) := by cfc_cont_tac) : + cfc (fun x ↦ f x - g x) a = cfc f a - cfc g a := by + have ha' := SpectrumRestricts.nnreal_of_nonneg ha + have : (spectrum ℝ a).EqOn (fun x ↦ ((f x.toNNReal - g x.toNNReal : ℝ≥0) : ℝ)) + (fun x ↦ f x.toNNReal - g x.toNNReal) := + fun x hx ↦ NNReal.coe_sub <| hfg _ <| ha'.apply_mem hx + rw [cfc_nnreal_eq_real, cfc_nnreal_eq_real, cfc_nnreal_eq_real, cfc_congr this] + refine cfc_sub _ _ a ?_ ?_ + all_goals + exact continuous_subtype_val.comp_continuousOn <| + ContinuousOn.comp ‹_› continuous_real_toNNReal.continuousOn <| ha'.image ▸ Set.mapsTo_image .. + +theorem cfcₙ_tsub {A : Type*} [TopologicalSpace A] [NonUnitalRing A] [PartialOrder A] [StarRing A] + [StarOrderedRing A] [Module ℝ A] [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] [TopologicalRing A] + [NonUnitalContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] [NonnegSpectrumClass ℝ A] (f g : ℝ≥0 → ℝ≥0) + (a : A) (hfg : ∀ x ∈ σₙ ℝ≥0 a, g x ≤ f x) (ha : 0 ≤ a := by cfc_tac) + (hf : ContinuousOn f (σₙ ℝ≥0 a) := by cfc_cont_tac) (hf0 : f 0 = 0 := by cfc_zero_tac) + (hg : ContinuousOn g (σₙ ℝ≥0 a) := by cfc_cont_tac) (hg0 : g 0 = 0 := by cfc_zero_tac) : + cfcₙ (fun x ↦ f x - g x) a = cfcₙ f a - cfcₙ g a := by + have ha' := QuasispectrumRestricts.nnreal_of_nonneg ha + have : (σₙ ℝ a).EqOn (fun x ↦ ((f x.toNNReal - g x.toNNReal : ℝ≥0) : ℝ)) + (fun x ↦ f x.toNNReal - g x.toNNReal) := + fun x hx ↦ NNReal.coe_sub <| hfg _ <| ha'.apply_mem hx + rw [cfcₙ_nnreal_eq_real, cfcₙ_nnreal_eq_real, cfcₙ_nnreal_eq_real, cfcₙ_congr this] + refine cfcₙ_sub _ _ a ?_ (by simpa) ?_ + all_goals + exact continuous_subtype_val.comp_continuousOn <| + ContinuousOn.comp ‹_› continuous_real_toNNReal.continuousOn <| ha'.image ▸ Set.mapsTo_image .. namespace Unitization -variable {A : Type*} [NonUnitalNormedRing A] [CompleteSpace A] - [PartialOrder A] [StarRing A] [StarOrderedRing A] [CStarRing A] [NormedSpace ℂ A] [StarModule ℂ A] - [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] +variable {A : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] [StarOrderedRing A] -instance instPartialOrder : PartialOrder (Unitization ℂ A) := +instance instPartialOrder : PartialOrder A⁺¹ := CStarAlgebra.spectralOrder _ -instance instStarOrderedRing : StarOrderedRing (Unitization ℂ A) := +instance instStarOrderedRing : StarOrderedRing A⁺¹ := CStarAlgebra.spectralOrderedRing _ lemma inr_le_iff (a b : A) (ha : IsSelfAdjoint a := by cfc_tac) (hb : IsSelfAdjoint b := by cfc_tac) : - (a : Unitization ℂ A) ≤ (b : Unitization ℂ A) ↔ a ≤ b := by + (a : A⁺¹) ≤ (b : A⁺¹) ↔ a ≤ b := by -- TODO: prove the more general result for star monomorphisms and use it here. rw [← sub_nonneg, ← sub_nonneg (a := b), StarOrderedRing.nonneg_iff_spectrum_nonneg (R := ℝ) _, ← inr_sub ℂ b a, ← Unitization.quasispectrum_eq_spectrum_inr' ℝ ℂ] exact StarOrderedRing.nonneg_iff_quasispectrum_nonneg _ |>.symm @[simp, norm_cast] -lemma inr_nonneg_iff {a : A} : 0 ≤ (a : Unitization ℂ A) ↔ 0 ≤ a := by +lemma inr_nonneg_iff {a : A} : 0 ≤ (a : A⁺¹) ↔ 0 ≤ a := by by_cases ha : IsSelfAdjoint a · exact inr_zero ℂ (A := A) ▸ inr_le_iff 0 a · refine ⟨?_, ?_⟩ @@ -66,6 +102,10 @@ lemma inr_nonneg_iff {a : A} : 0 ≤ (a : Unitization ℂ A) ↔ 0 ≤ a := by · exact isSelfAdjoint_inr (R := ℂ) |>.mp <| .of_nonneg h · exact .of_nonneg h +lemma nnreal_cfcₙ_eq_cfc_inr (a : A) (f : ℝ≥0 → ℝ≥0) + (hf₀ : f 0 = 0 := by cfc_zero_tac) : cfcₙ f a = cfc f (a : A⁺¹) := + cfcₙ_eq_cfc_inr inr_nonneg_iff .. + end Unitization /-- `cfc_le_iff` only applies to a scalar ring where `R` is an actual `Ring`, and not a `Semiring`. @@ -85,26 +125,25 @@ lemma cfc_nnreal_le_iff {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] [ rw [cfc_nnreal_eq_real, cfc_nnreal_eq_real, cfc_le_iff ..] simp [NNReal.coe_le_coe, ← ha_spec.image] +open ContinuousFunctionalCalculus in /-- In a unital `ℝ`-algebra `A` with a continuous functional calculus, an element `a : A` is larger than some `algebraMap ℝ A r` if and only if every element of the `ℝ`-spectrum is nonnegative. -/ lemma CFC.exists_pos_algebraMap_le_iff {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] - [PartialOrder A] [StarOrderedRing A] [Algebra ℝ A] [NonnegSpectrumClass ℝ A] + [PartialOrder A] [StarOrderedRing A] [Algebra ℝ A] [NonnegSpectrumClass ℝ A] [Nontrivial A] [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] - {a : A} [CompactSpace (spectrum ℝ a)] - (h_non : (spectrum ℝ a).Nonempty) (ha : IsSelfAdjoint a := by cfc_tac) : + {a : A} (ha : IsSelfAdjoint a := by cfc_tac) : (∃ r > 0, algebraMap ℝ A r ≤ a) ↔ (∀ x ∈ spectrum ℝ a, 0 < x) := by have h_cpct : IsCompact (spectrum ℝ a) := isCompact_iff_compactSpace.mpr inferInstance simp_rw [algebraMap_le_iff_le_spectrum (a := a)] refine ⟨?_, fun h ↦ ?_⟩ · rintro ⟨r, hr, hr_le⟩ exact (hr.trans_le <| hr_le · ·) - · obtain ⟨r, hr, hr_min⟩ := h_cpct.exists_isMinOn h_non continuousOn_id + · obtain ⟨r, hr, hr_min⟩ := h_cpct.exists_isMinOn (spectrum_nonempty ℝ a ha) continuousOn_id exact ⟨r, h _ hr, hr_min⟩ section CStar_unital -variable {A : Type*} [NormedRing A] [StarRing A] [CStarRing A] [CompleteSpace A] -variable [NormedAlgebra ℂ A] [StarModule ℂ A] +variable {A : Type*} [CStarAlgebra A] section StarOrderedRing @@ -218,10 +257,8 @@ lemma CStarAlgebra.isUnit_of_le {a b : A} (h₀ : IsUnit a) (ha : 0 ≤ a := by rw [← spectrum.zero_not_mem_iff ℝ≥0] at h₀ ⊢ nontriviality A have hb := (show 0 ≤ a from ha).trans hab - have ha' := IsSelfAdjoint.of_nonneg ha |>.spectrum_nonempty - have hb' := IsSelfAdjoint.of_nonneg hb |>.spectrum_nonempty rw [zero_not_mem_iff, SpectrumRestricts.nnreal_lt_iff (.nnreal_of_nonneg ‹_›), - NNReal.coe_zero, ← CFC.exists_pos_algebraMap_le_iff ‹_›] at h₀ ⊢ + NNReal.coe_zero, ← CFC.exists_pos_algebraMap_le_iff] at h₀ ⊢ peel h₀ with r hr _ exact this.trans hab @@ -319,9 +356,7 @@ end CStar_unital section CStar_nonunital -variable {A : Type*} [NonUnitalNormedRing A] [CompleteSpace A] [PartialOrder A] [StarRing A] - [StarOrderedRing A] [CStarRing A] [NormedSpace ℂ A] [StarModule ℂ A] - [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] +variable {A : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] [StarOrderedRing A] namespace CStarAlgebra @@ -333,7 +368,7 @@ instance instNonnegSpectrumClassComplexNonUnital : NonnegSpectrumClass ℂ A whe lemma norm_le_norm_of_nonneg_of_le {a b : A} (ha : 0 ≤ a := by cfc_tac) (hab : a ≤ b) : ‖a‖ ≤ ‖b‖ := by - suffices ∀ a b : Unitization ℂ A, 0 ≤ a → a ≤ b → ‖a‖ ≤ ‖b‖ by + suffices ∀ a b : A⁺¹, 0 ≤ a → a ≤ b → ‖a‖ ≤ ‖b‖ by have hb := ha.trans hab simpa only [ge_iff_le, Unitization.norm_inr] using this a b (by simpa) (by rwa [Unitization.inr_le_iff a b]) @@ -351,14 +386,18 @@ lemma norm_le_norm_of_nonneg_of_le {a b : A} (ha : 0 ≤ a := by cfc_tac) (hab : rw [cfc_le_iff id (fun _ => ‖b‖) a] at h₂ exact h₂ ‖a‖ <| norm_mem_spectrum_of_nonneg ha +theorem nnnorm_le_nnnorm_of_nonneg_of_le {a : A} {b : A} (ha : 0 ≤ a := by cfc_tac) (hab : a ≤ b) : + ‖a‖₊ ≤ ‖b‖₊ := + norm_le_norm_of_nonneg_of_le ha hab + lemma conjugate_le_norm_smul {a b : A} (hb : IsSelfAdjoint b := by cfc_tac) : star a * b * a ≤ ‖b‖ • (star a * a) := by - suffices ∀ a b : Unitization ℂ A, IsSelfAdjoint b → star a * b * a ≤ ‖b‖ • (star a * a) by + suffices ∀ a b : A⁺¹, IsSelfAdjoint b → star a * b * a ≤ ‖b‖ • (star a * a) by rw [← Unitization.inr_le_iff _ _ (by aesop) ((IsSelfAdjoint.all _).smul (.star_mul_self a))] simpa [Unitization.norm_inr] using this a b <| hb.inr ℂ intro a b hb calc - star a * b * a ≤ star a * (algebraMap ℝ (Unitization ℂ A) ‖b‖) * a := + star a * b * a ≤ star a * (algebraMap ℝ A⁺¹ ‖b‖) * a := conjugate_le_conjugate hb.le_algebraMap_norm_self _ _ = ‖b‖ • (star a * a) := by simp [Algebra.algebraMap_eq_smul_one] @@ -371,9 +410,9 @@ lemma conjugate_le_norm_smul' {a b : A} (hb : IsSelfAdjoint b := by cfc_tac) : /-- The set of nonnegative elements in a C⋆-algebra is closed. -/ lemma isClosed_nonneg : IsClosed {a : A | 0 ≤ a} := by - suffices IsClosed {a : Unitization ℂ A | 0 ≤ a} by - rw [Unitization.isometry_inr (𝕜 := ℂ) |>.closedEmbedding.closed_iff_image_closed] - convert this.inter <| (Unitization.isometry_inr (𝕜 := ℂ)).closedEmbedding.isClosed_range + suffices IsClosed {a : A⁺¹ | 0 ≤ a} by + rw [Unitization.isometry_inr (𝕜 := ℂ) |>.isClosedEmbedding.closed_iff_image_closed] + convert this.inter <| (Unitization.isometry_inr (𝕜 := ℂ)).isClosedEmbedding.isClosed_range ext a simp only [Set.mem_image, Set.mem_setOf_eq, Set.mem_inter_iff, Set.mem_range, ← exists_and_left] congr! 2 with x @@ -386,3 +425,35 @@ lemma isClosed_nonneg : IsClosed {a : A | 0 ≤ a} := by end CStarAlgebra end CStar_nonunital + +section Pow + +namespace CStarAlgebra + +variable {A : Type*} [CStarAlgebra A] [PartialOrder A] [StarOrderedRing A] + +lemma pow_nonneg {a : A} (ha : 0 ≤ a := by cfc_tac) (n : ℕ) : 0 ≤ a ^ n := by + rw [← cfc_pow_id (R := ℝ≥0) a] + exact cfc_nonneg_of_predicate + +lemma pow_monotone {a : A} (ha : 1 ≤ a) : Monotone (a ^ · : ℕ → A) := by + have ha' : 0 ≤ a := zero_le_one.trans ha + intro n m hnm + simp only + rw [← cfc_pow_id (R := ℝ) a, ← cfc_pow_id (R := ℝ) a, cfc_le_iff ..] + rw [CFC.one_le_iff (R := ℝ) a] at ha + peel ha with x hx _ + exact pow_le_pow_right₀ (ha x hx) hnm + +lemma pow_antitone {a : A} (ha₀ : 0 ≤ a := by cfc_tac) (ha₁ : a ≤ 1) : + Antitone (a ^ · : ℕ → A) := by + intro n m hnm + simp only + rw [← cfc_pow_id (R := ℝ) a, ← cfc_pow_id (R := ℝ) a, cfc_le_iff ..] + rw [CFC.le_one_iff (R := ℝ) a] at ha₁ + peel ha₁ with x hx _ + exact pow_le_pow_of_le_one (spectrum_nonneg_of_nonneg ha₀ hx) (ha₁ x hx) hnm + +end CStarAlgebra + +end Pow diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/PosPart.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/PosPart.lean new file mode 100644 index 0000000000000..396d6e6043dca --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/PosPart.lean @@ -0,0 +1,228 @@ +/- +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.Topology.ContinuousMap.StarOrdered +import Mathlib.Analysis.InnerProductSpace.Basic +import Mathlib.Topology.ContinuousMap.StoneWeierstrass +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital + +/-! # The positive (and negative) parts of a selfadjoint element in a C⋆-algebra + +This file defines the positive and negative parts of a selfadjoint element in a C⋆-algebra via +the continuous functional calculus and develops the basic API, including the uniqueness of the +positive and negative parts. +-/ + +variable {A : Type*} [NonUnitalRing A] [Module ℝ A] [SMulCommClass ℝ A A] [IsScalarTower ℝ A A] +variable [StarRing A] [TopologicalSpace A] +variable [NonUnitalContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + +namespace CStarAlgebra + +noncomputable instance : PosPart A where + posPart := cfcₙ (·⁺ : ℝ → ℝ) + +noncomputable instance : NegPart A where + negPart := cfcₙ (·⁻ : ℝ → ℝ) + +end CStarAlgebra + +namespace CFC + +lemma posPart_def (a : A) : a⁺ = cfcₙ (·⁺ : ℝ → ℝ) a := rfl + +lemma negPart_def (a : A) : a⁻ = cfcₙ (·⁻ : ℝ → ℝ) a := rfl + +@[simp] +lemma posPart_mul_negPart (a : A) : a⁺ * a⁻ = 0 := by + rw [posPart_def, negPart_def] + by_cases ha : IsSelfAdjoint a + · rw [← cfcₙ_mul _ _, ← cfcₙ_zero ℝ a] + refine cfcₙ_congr (fun x _ ↦ ?_) + simp only [_root_.posPart_def, _root_.negPart_def] + simpa using le_total x 0 + · simp [cfcₙ_apply_of_not_predicate a ha] + +@[simp] +lemma negPart_mul_posPart (a : A) : a⁻ * a⁺ = 0 := by + rw [posPart_def, negPart_def] + by_cases ha : IsSelfAdjoint a + · rw [← cfcₙ_mul _ _, ← cfcₙ_zero ℝ a] + refine cfcₙ_congr (fun x _ ↦ ?_) + simp only [_root_.posPart_def, _root_.negPart_def] + simpa using le_total 0 x + · simp [cfcₙ_apply_of_not_predicate a ha] + +lemma posPart_sub_negPart (a : A) (ha : IsSelfAdjoint a := by cfc_tac) : a⁺ - a⁻ = a := by + rw [posPart_def, negPart_def] + rw [← cfcₙ_sub _ _] + conv_rhs => rw [← cfcₙ_id ℝ a] + congr! 2 with + exact _root_.posPart_sub_negPart _ + +section Unique + +variable [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + +@[simp] +lemma posPart_neg (a : A) : (-a)⁺ = a⁻ := by + by_cases ha : IsSelfAdjoint a + · rw [posPart_def, negPart_def, ← cfcₙ_comp_neg _ _] + congr! 2 + · have ha' : ¬ IsSelfAdjoint (-a) := fun h ↦ ha (by simpa using h.neg) + rw [posPart_def, negPart_def, cfcₙ_apply_of_not_predicate a ha, + cfcₙ_apply_of_not_predicate _ ha'] + +@[simp] +lemma negPart_neg (a : A) : (-a)⁻ = a⁺ := by + rw [← eq_comm, ← sub_eq_zero, ← posPart_neg, neg_neg, sub_self] + +end Unique + +variable [PartialOrder A] [StarOrderedRing A] + +@[aesop norm apply (rule_sets := [CStarAlgebra])] +lemma posPart_nonneg (a : A) : + 0 ≤ a⁺ := + cfcₙ_nonneg (fun x _ ↦ by positivity) + +@[aesop norm apply (rule_sets := [CStarAlgebra])] +lemma negPart_nonneg (a : A) : + 0 ≤ a⁻ := + cfcₙ_nonneg (fun x _ ↦ by positivity) + +variable [NonnegSpectrumClass ℝ A] + +lemma eq_posPart_iff (a : A) : a = a⁺ ↔ 0 ≤ a := by + refine ⟨fun ha ↦ ha ▸ posPart_nonneg a, fun ha ↦ ?_⟩ + conv_lhs => 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) : + a⁻ = 0 ↔ 0 ≤ a := by + rw [← eq_posPart_iff] + nth_rw 2 [← posPart_sub_negPart a] + simp + +lemma eq_negPart_iff (a : A) : a = -a⁻ ↔ a ≤ 0 := by + refine ⟨fun ha ↦ by rw [ha, neg_nonpos]; exact negPart_nonneg a, fun ha ↦ ?_⟩ + rw [← neg_nonneg] at ha + rw [negPart_def, ← cfcₙ_neg] + have _ : IsSelfAdjoint a := neg_neg a ▸ (IsSelfAdjoint.neg <| .of_nonneg ha) + conv_lhs => rw [← cfcₙ_id ℝ a] + refine cfcₙ_congr fun x hx ↦ ?_ + rw [Unitization.quasispectrum_eq_spectrum_inr ℝ, ← neg_neg x, ← Set.mem_neg, + spectrum.neg_eq, ← Unitization.inr_neg, ← Unitization.quasispectrum_eq_spectrum_inr ℝ] at hx + 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) : + a⁺ = 0 ↔ a ≤ 0 := by + rw [← eq_negPart_iff] + nth_rw 2 [← posPart_sub_negPart a] + simp + +local notation "σₙ" => quasispectrum + +open ContinuousMapZero + +variable [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] +variable [TopologicalRing A] [T2Space A] + +open NonUnitalContinuousFunctionalCalculus in +/-- The positive and negative parts of a selfadjoint element `a` are unique. That is, if +`a = b - c` is the difference of nonnegative elements whose product is zero, then these are +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 + /- 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 + `a = b - c`. -/ + /- `a`, `b`, `-c` are selfadjoint. -/ + have hb' : IsSelfAdjoint b := .of_nonneg hb + have hc' : IsSelfAdjoint (-c) := .neg <| .of_nonneg hc + have ha : IsSelfAdjoint a := habc ▸ hb'.sub <| .of_nonneg hc + /- 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 + /- `s := σₙ ℝ a ∪ σₙ ℝ b ∪ σₙ ℝ (-c)` is compact and each of these sets are subsets of `s`. + Moreover, `0 ∈ s`. -/ + let s := σₙ ℝ a ∪ σₙ ℝ b ∪ σₙ ℝ (-c) + have hs : CompactSpace s := by + refine isCompact_iff_compactSpace.mp <| (IsCompact.union ?_ ?_).union ?_ + 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⟩ + 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). -/ + have mul₁ (f g : C(s, ℝ)₀) : + (cfcₙHomSuperset hb' hbs f) * (cfcₙHomSuperset hc' hcs g) = 0 := by + refine f.nonUnitalStarAlgHom_apply_mul_eq_zero s0 _ _ ?id ?star_id + (cfcₙHomSuperset_continuous hb' hbs) + case' star_id => rw [star_trivial] + 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] + 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 + agrees with the star homomorphism `cfcₙ · a : C(s, ℝ)₀ →⋆ₙₐ[ℝ] A` since + `cfcₙ id a = a = b - c = cfcₙ id b + cfcₙ id (-c)`. -/ + let ψ : C(s, ℝ)₀ →⋆ₙₐ[ℝ] A := + { (cfcₙHomSuperset hb' hbs : C(s, ℝ)₀ →ₗ[ℝ] A) + (cfcₙHomSuperset hc' hcs : C(s, ℝ)₀ →ₗ[ℝ] A) + with + 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] + 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) + /- 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`, + respectively, since `0 ≤ b` and `-c ≤ 0`. -/ + let f : C(s, ℝ)₀ := ⟨⟨(·⁺), by fun_prop⟩, by simp [s0]⟩ + 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 + calc + b = cfcₙ (id : ℝ → ℝ) b + cfcₙ (0 : ℝ → ℝ) (-c) := by simp [cfcₙ_id ℝ b] + _ = _ := by + congr! 1 + 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] + · exact quasispectrum_nonneg_of_nonneg b hb x.val x.property + · obtain ⟨x, hx⟩ := x + simp only [← neg_nonneg] + rw [Unitization.quasispectrum_eq_spectrum_inr ℝ (-c), Unitization.inr_neg, + ← spectrum.neg_eq, Set.mem_neg, ← Unitization.quasispectrum_eq_spectrum_inr ℝ c] + at hx + exact quasispectrum_nonneg_of_nonneg c hc _ hx + _ = _ := key.symm + _ = a⁺ := by + refine cfcₙ_congr fun x hx ↦ ?_ + lift x to σₙ ℝ a using hx + simp [Subtype.val_injective.extend_apply, f] + +end CFC diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean index cf36028a7922e..195b717b64044 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean @@ -82,14 +82,17 @@ lemma starAlgHom_id {a : A} {φ : C(spectrum S a, S) →⋆ₐ[S] A} {f : C(S, R variable [TopologicalSpace A] [ContinuousFunctionalCalculus S q] variable [CompleteSpace R] -lemma closedEmbedding_starAlgHom {a : A} {φ : C(spectrum S a, S) →⋆ₐ[S] A} - (hφ : ClosedEmbedding φ) {f : C(S, R)} (h : SpectrumRestricts a f) +lemma isClosedEmbedding_starAlgHom {a : A} {φ : C(spectrum S a, S) →⋆ₐ[S] A} + (hφ : IsClosedEmbedding φ) {f : C(S, R)} (h : SpectrumRestricts a f) (halg : IsUniformEmbedding (algebraMap R S)) : - ClosedEmbedding (h.starAlgHom φ) := - hφ.comp <| IsUniformEmbedding.toClosedEmbedding <| .comp + IsClosedEmbedding (h.starAlgHom φ) := + hφ.comp <| IsUniformEmbedding.toIsClosedEmbedding <| .comp (ContinuousMap.isUniformEmbedding_comp _ halg) (UniformEquiv.arrowCongr h.homeomorph.symm (.refl _) |>.isUniformEmbedding) +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_starAlgHom := isClosedEmbedding_starAlgHom + /-- Given a `ContinuousFunctionalCalculus S q`. If we form the predicate `p` for `a : A` characterized by: `q a` and the spectrum of `a` restricts to the scalar subring `R` via `f : C(S, R)`, then we can get a restricted functional calculus @@ -98,12 +101,18 @@ protected theorem cfc (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) (h : ∀ a, p a ↔ q a ∧ SpectrumRestricts a f) : ContinuousFunctionalCalculus R p where predicate_zero := h0 + spectrum_nonempty a ha := ((h a).mp ha).2.image ▸ + (ContinuousFunctionalCalculus.spectrum_nonempty a ((h a).mp ha).1 |>.image f) + compactSpace_spectrum a := by + have := ContinuousFunctionalCalculus.compactSpace_spectrum (R := S) a + rw [← isCompact_iff_compactSpace] at this ⊢ + simpa using halg.toIsClosedEmbedding.isCompact_preimage this exists_cfc_of_predicate a ha := by refine ⟨((h a).mp ha).2.starAlgHom (cfcHom ((h a).mp ha).1 (R := S)), - ?hom_closedEmbedding, ?hom_id, ?hom_map_spectrum, ?predicate_hom⟩ - case hom_closedEmbedding => - exact ((h a).mp ha).2.closedEmbedding_starAlgHom - (cfcHom_closedEmbedding ((h a).mp ha).1) halg + ?hom_isClosedEmbedding, ?hom_id, ?hom_map_spectrum, ?predicate_hom⟩ + case hom_isClosedEmbedding => + exact ((h a).mp ha).2.isClosedEmbedding_starAlgHom + (cfcHom_isClosedEmbedding ((h a).mp ha).1) halg case hom_id => exact ((h a).mp ha).2.starAlgHom_id <| cfcHom_id ((h a).mp ha).1 case hom_map_spectrum => intro g @@ -137,7 +146,7 @@ lemma cfcHom_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R {a : A} (hpa : p a) (hqa : q a) (h : SpectrumRestricts a f) : cfcHom hpa = h.starAlgHom (cfcHom hqa) := by apply cfcHom_eq_of_continuous_of_map_id - · exact h.closedEmbedding_starAlgHom (cfcHom_closedEmbedding hqa) halg |>.continuous + · exact h.isClosedEmbedding_starAlgHom (cfcHom_isClosedEmbedding hqa) halg |>.continuous · exact h.starAlgHom_id (cfcHom_id hqa) lemma cfc_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) {a : A} (hpa : p a) @@ -151,9 +160,9 @@ lemma cfc_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) simp [Function.comp, Subtype.val_injective.extend_apply] · have : ¬ ContinuousOn (fun x ↦ algebraMap R S (g (f x)) : S → S) (spectrum S a) := by refine fun hg' ↦ hg ?_ - rw [halg.embedding.continuousOn_iff] - simpa [halg.embedding.continuousOn_iff, Function.comp_def, h.left_inv _] using - hg'.comp halg.embedding.continuous.continuousOn (fun _ : R ↦ spectrum.algebraMap_mem S) + rw [halg.isEmbedding.continuousOn_iff] + simpa [halg.isEmbedding.continuousOn_iff, Function.comp_def, h.left_inv _] using + hg'.comp halg.isEmbedding.continuous.continuousOn (fun _ : R ↦ spectrum.algebraMap_mem S) rw [cfc_apply_of_not_continuousOn a hg, cfc_apply_of_not_continuousOn a this] end SpectrumRestricts @@ -216,15 +225,18 @@ lemma nonUnitalStarAlgHom_id {a : A} {φ : C(σₙ S a, S)₀ →⋆ₙₐ[S] A} variable [TopologicalSpace A] [NonUnitalContinuousFunctionalCalculus S q] variable [CompleteSpace R] -lemma closedEmbedding_nonUnitalStarAlgHom {a : A} {φ : C(σₙ S a, S)₀ →⋆ₙₐ[S] A} - (hφ : ClosedEmbedding φ) {f : C(S, R)} (h : QuasispectrumRestricts a f) +lemma isClosedEmbedding_nonUnitalStarAlgHom {a : A} {φ : C(σₙ S a, S)₀ →⋆ₙₐ[S] A} + (hφ : IsClosedEmbedding φ) {f : C(S, R)} (h : QuasispectrumRestricts a f) (halg : IsUniformEmbedding (algebraMap R S)) : - ClosedEmbedding (h.nonUnitalStarAlgHom φ) := by + IsClosedEmbedding (h.nonUnitalStarAlgHom φ) := by have : h.homeomorph.symm 0 = 0 := Subtype.ext (map_zero <| algebraMap _ _) - refine hφ.comp <| IsUniformEmbedding.toClosedEmbedding <| .comp + refine hφ.comp <| IsUniformEmbedding.toIsClosedEmbedding <| .comp (ContinuousMapZero.isUniformEmbedding_comp _ halg) (UniformEquiv.arrowCongrLeft₀ h.homeomorph.symm this |>.isUniformEmbedding) +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_nonUnitalStarAlgHom := isClosedEmbedding_nonUnitalStarAlgHom + variable [IsScalarTower R A A] [SMulCommClass R A A] /-- Given a `NonUnitalContinuousFunctionalCalculus S q`. If we form the predicate `p` for `a : A` @@ -235,12 +247,16 @@ protected theorem cfc (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) (h : ∀ a, p a ↔ q a ∧ QuasispectrumRestricts a f) : NonUnitalContinuousFunctionalCalculus R p where predicate_zero := h0 + compactSpace_quasispectrum a := by + have := NonUnitalContinuousFunctionalCalculus.compactSpace_quasispectrum (R := S) a + rw [← isCompact_iff_compactSpace] at this ⊢ + simpa using halg.toIsClosedEmbedding.isCompact_preimage this exists_cfc_of_predicate a ha := by refine ⟨((h a).mp ha).2.nonUnitalStarAlgHom (cfcₙHom ((h a).mp ha).1 (R := S)), - ?hom_closedEmbedding, ?hom_id, ?hom_map_spectrum, ?predicate_hom⟩ - case hom_closedEmbedding => - exact ((h a).mp ha).2.closedEmbedding_nonUnitalStarAlgHom - (cfcₙHom_closedEmbedding ((h a).mp ha).1) halg + ?hom_isClosedEmbedding, ?hom_id, ?hom_map_spectrum, ?predicate_hom⟩ + case hom_isClosedEmbedding => + exact ((h a).mp ha).2.isClosedEmbedding_nonUnitalStarAlgHom + (cfcₙHom_isClosedEmbedding ((h a).mp ha).1) halg case hom_id => exact ((h a).mp ha).2.nonUnitalStarAlgHom_id <| cfcₙHom_id ((h a).mp ha).1 case hom_map_spectrum => intro g @@ -279,7 +295,7 @@ lemma cfcₙHom_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap (hpa : p a) (hqa : q a) (h : QuasispectrumRestricts a f) : cfcₙHom hpa = h.nonUnitalStarAlgHom (cfcₙHom hqa) := by apply cfcₙHom_eq_of_continuous_of_map_id - · exact h.closedEmbedding_nonUnitalStarAlgHom (cfcₙHom_closedEmbedding hqa) halg |>.continuous + · exact h.isClosedEmbedding_nonUnitalStarAlgHom (cfcₙHom_isClosedEmbedding hqa) halg |>.continuous · exact h.nonUnitalStarAlgHom_id (cfcₙHom_id hqa) lemma cfcₙ_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R S)) {a : A} @@ -296,9 +312,9 @@ lemma cfcₙ_eq_restrict (f : C(S, R)) (halg : IsUniformEmbedding (algebraMap R obtain (hg | hg) := hg · have : ¬ ContinuousOn (fun x ↦ algebraMap R S (g (f x)) : S → S) (σₙ S a) := by refine fun hg' ↦ hg ?_ - rw [halg.embedding.continuousOn_iff] - simpa [halg.embedding.continuousOn_iff, Function.comp_def, h.left_inv _] using - hg'.comp halg.embedding.continuous.continuousOn + rw [halg.isEmbedding.continuousOn_iff] + simpa [halg.isEmbedding.continuousOn_iff, Function.comp_def, h.left_inv _] using + hg'.comp halg.isEmbedding.continuous.continuousOn (fun _ : R ↦ quasispectrum.algebraMap_mem S) rw [cfcₙ_apply_of_not_continuousOn a hg, cfcₙ_apply_of_not_continuousOn a this] · rw [cfcₙ_apply_of_not_map_zero a hg, cfcₙ_apply_of_not_map_zero a (by simpa [h.map_zero])] diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean index 155a1b6dd519c..0643b90789114 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean @@ -33,7 +33,7 @@ variable {𝕜 A : Type*} [RCLike 𝕜] theorem RCLike.uniqueContinuousFunctionalCalculus_of_compactSpace_spectrum [TopologicalSpace A] [T2Space A] [Ring A] [StarRing A] [Algebra 𝕜 A] [h : ∀ a : A, CompactSpace (spectrum 𝕜 a)] : UniqueContinuousFunctionalCalculus 𝕜 A where - eq_of_continuous_of_map_id s hs φ ψ hφ hψ h := + eq_of_continuous_of_map_id s _ φ ψ hφ hψ h := ContinuousMap.starAlgHom_ext_map_X hφ hψ <| by convert h using 1 all_goals exact congr_arg _ (by ext; simp) @@ -56,7 +56,7 @@ namespace ContinuousMap noncomputable def toNNReal (f : C(X, ℝ)) : C(X, ℝ≥0) := .realToNNReal |>.comp f @[fun_prop] -lemma continuous_toNNReal : Continuous (toNNReal (X := X)) := continuous_comp _ +lemma continuous_toNNReal : Continuous (toNNReal (X := X)) := continuous_postcomp _ @[simp] lemma toNNReal_apply (f : C(X, ℝ)) (x : X) : f.toNNReal x = (f x).toNNReal := rfl @@ -169,7 +169,7 @@ instance NNReal.instUniqueContinuousFunctionalCalculus [UniqueContinuousFunction have : CompactSpace (spectrum ℝ a) := UniqueContinuousFunctionalCalculus.compactSpace_spectrum a rw [← isCompact_iff_compactSpace] at * rw [← spectrum.preimage_algebraMap ℝ] - exact closedEmbedding_subtype_val isClosed_nonneg |>.isCompact_preimage <| by assumption + exact isClosed_nonneg.isClosedEmbedding_subtypeVal.isCompact_preimage <| by assumption eq_of_continuous_of_map_id s hs φ ψ hφ hψ h := by let s' : Set ℝ := (↑) '' s let e : s ≃ₜ s' := @@ -187,7 +187,7 @@ instance NNReal.instUniqueContinuousFunctionalCalculus [UniqueContinuousFunction Continuous ξ' ∧ ξ' (.restrict s' <| .id ℝ) = ξ (.restrict s <| .id ℝ≥0)) := by intro ξ' refine ⟨ξ.continuous_realContinuousMapOfNNReal hξ |>.comp <| - ContinuousMap.continuous_comp_left _, ?_⟩ + ContinuousMap.continuous_precomp _, ?_⟩ exact ξ.realContinuousMapOfNNReal_apply_comp_toReal (.restrict s <| .id ℝ≥0) obtain ⟨hφ', hφ_id⟩ := this φ hφ obtain ⟨hψ', hψ_id⟩ := this ψ hψ @@ -249,7 +249,7 @@ lemma toNNReal_apply (f : C(X, ℝ)₀) (x : X) : f.toNNReal x = Real.toNNReal ( lemma continuous_toNNReal : Continuous (toNNReal (X := X)) := by rw [continuous_induced_rng] convert_to Continuous (ContinuousMap.toNNReal ∘ ((↑) : C(X, ℝ)₀ → C(X, ℝ))) using 1 - exact ContinuousMap.continuous_comp _ |>.comp continuous_induced_dom + exact ContinuousMap.continuous_postcomp _ |>.comp continuous_induced_dom lemma toContinuousMapHom_toNNReal (f : C(X, ℝ)₀) : (toContinuousMapHom (X := X) (R := ℝ) f).toNNReal = @@ -376,7 +376,7 @@ instance NNReal.instUniqueNonUnitalContinuousFunctionalCalculus UniqueNonUnitalContinuousFunctionalCalculus.compactSpace_quasispectrum a rw [← isCompact_iff_compactSpace] at * rw [← quasispectrum.preimage_algebraMap ℝ] - exact closedEmbedding_subtype_val isClosed_nonneg |>.isCompact_preimage <| by assumption + exact isClosed_nonneg.isClosedEmbedding_subtypeVal.isCompact_preimage <| by assumption eq_of_continuous_of_map_id s hs _inst h0 φ ψ hφ hψ h := by let s' : Set ℝ := (↑) '' s let e : s ≃ₜ s' := @@ -401,7 +401,7 @@ instance NNReal.instUniqueNonUnitalContinuousFunctionalCalculus intro ξ' refine ⟨ξ.continuous_realContinuousMapZeroOfNNReal hξ |>.comp <| ?_, ?_⟩ · rw [continuous_induced_rng] - exact ContinuousMap.continuous_comp_left _ |>.comp continuous_induced_dom + exact ContinuousMap.continuous_precomp _ |>.comp continuous_induced_dom · exact ξ.realContinuousMapZeroOfNNReal_apply_comp_toReal (.id h0) obtain ⟨hφ', hφ_id⟩ := this φ hφ obtain ⟨hψ', hψ_id⟩ := this ψ hψ diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean index 8b6473cba0de3..6e8de01f4cc2d 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean @@ -162,10 +162,17 @@ class ContinuousFunctionalCalculus (R : Type*) {A : Type*} (p : outParam (A → [CommSemiring R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] [Ring A] [StarRing A] [TopologicalSpace A] [Algebra R A] : Prop where predicate_zero : p 0 + [compactSpace_spectrum (a : A) : CompactSpace (spectrum R a)] + spectrum_nonempty [Nontrivial A] (a : A) (ha : p a) : (spectrum R a).Nonempty exists_cfc_of_predicate : ∀ a, p a → ∃ φ : C(spectrum R a, R) →⋆ₐ[R] A, - ClosedEmbedding φ ∧ φ ((ContinuousMap.id R).restrict <| spectrum R a) = a ∧ + IsClosedEmbedding φ ∧ φ ((ContinuousMap.id R).restrict <| spectrum R a) = a ∧ (∀ f, spectrum R (φ f) = Set.range f) ∧ ∀ f, p (φ f) +-- this instance should not be activated everywhere but it is useful when developing generic API +-- for the continuous functional calculus +scoped[ContinuousFunctionalCalculus] +attribute [instance] ContinuousFunctionalCalculus.compactSpace_spectrum + /-- A class guaranteeing that the continuous functional calculus is uniquely determined by the properties that it is a continuous star algebra homomorphism mapping the (restriction of) the identity to `a`. This is the necessary tool used to establish `cfcHom_comp` and the more common @@ -193,6 +200,11 @@ variable {R A : Type*} {p : A → Prop} [CommSemiring R] [StarRing R] [MetricSpa variable [TopologicalSemiring R] [ContinuousStar R] [TopologicalSpace A] [Ring A] [StarRing A] variable [Algebra R A] [instCFC : ContinuousFunctionalCalculus R p] +include instCFC in +lemma ContinuousFunctionalCalculus.isCompact_spectrum (a : A) : + IsCompact (spectrum R a) := + isCompact_iff_compactSpace.mpr inferInstance + lemma StarAlgHom.ext_continuousMap [UniqueContinuousFunctionalCalculus R A] (a : A) (φ ψ : C(spectrum R a, R) →⋆ₐ[R] A) (hφ : Continuous φ) (hψ : Continuous ψ) (h : φ (.restrict (spectrum R a) <| .id R) = ψ (.restrict (spectrum R a) <| .id R)) : @@ -221,13 +233,16 @@ user should instead prefer `cfc` over `cfcHom`. noncomputable def cfcHom : C(spectrum R a, R) →⋆ₐ[R] A := (ContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose -lemma cfcHom_closedEmbedding : - ClosedEmbedding <| (cfcHom ha : C(spectrum R a, R) →⋆ₐ[R] A) := +lemma cfcHom_isClosedEmbedding : + IsClosedEmbedding <| (cfcHom ha : C(spectrum R a, R) →⋆ₐ[R] A) := (ContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.1 +@[deprecated (since := "2024-10-20")] +alias cfcHom_closedEmbedding := cfcHom_isClosedEmbedding + @[fun_prop] lemma cfcHom_continuous : Continuous (cfcHom ha : C(spectrum R a, R) →⋆ₐ[R] A) := - cfcHom_closedEmbedding ha |>.continuous + cfcHom_isClosedEmbedding ha |>.continuous lemma cfcHom_id : cfcHom ha ((ContinuousMap.id R).restrict <| spectrum R a) = a := @@ -245,7 +260,7 @@ lemma cfcHom_predicate (f : C(spectrum R a, R)) : lemma cfcHom_eq_of_continuous_of_map_id [UniqueContinuousFunctionalCalculus R A] (φ : C(spectrum R a, R) →⋆ₐ[R] A) (hφ₁ : Continuous φ) (hφ₂ : φ (.restrict (spectrum R a) <| .id R) = a) : cfcHom ha = φ := - (cfcHom ha).ext_continuousMap a φ (cfcHom_closedEmbedding ha).continuous hφ₁ <| by + (cfcHom ha).ext_continuousMap a φ (cfcHom_isClosedEmbedding ha).continuous hφ₁ <| by rw [cfcHom_id ha, hφ₂] theorem cfcHom_comp [UniqueContinuousFunctionalCalculus R A] (f : C(spectrum R a, R)) @@ -256,7 +271,7 @@ theorem cfcHom_comp [UniqueContinuousFunctionalCalculus R A] (f : C(spectrum R a (cfcHom ha).comp <| ContinuousMap.compStarAlgHom' R R f' suffices cfcHom (cfcHom_predicate ha f) = φ from DFunLike.congr_fun this.symm g refine cfcHom_eq_of_continuous_of_map_id (cfcHom_predicate ha f) φ ?_ ?_ - · exact (cfcHom_closedEmbedding ha).continuous.comp f'.continuous_comp_left + · exact (cfcHom_isClosedEmbedding ha).continuous.comp f'.continuous_precomp · simp only [φ, StarAlgHom.comp_apply, ContinuousMap.compStarAlgHom'_apply] congr ext x @@ -272,7 +287,7 @@ noncomputable def cfcL {a : A} (ha : p a) : C(spectrum R a, R) →L[R] A := { cfcHom ha with toFun := cfcHom ha map_smul' := map_smul _ - cont := (cfcHom_closedEmbedding ha).continuous } + cont := (cfcHom_isClosedEmbedding ha).continuous } end cfcL @@ -341,6 +356,11 @@ lemma cfc_cases (P : A → Prop) (a : A) (f : R → R) (h₀ : P 0) · rwa [cfc_apply_of_not_predicate _ h] · rwa [cfc_apply_of_not_continuousOn _ h] +lemma cfc_commute_cfc (f g : R → R) (a : A) : Commute (cfc f a) (cfc g a) := by + refine cfc_cases (fun x ↦ Commute x (cfc g a)) a f (by simp) fun hf ha ↦ ?_ + refine cfc_cases (fun x ↦ Commute _ x) a g (by simp) fun hg _ ↦ ?_ + exact Commute.all _ _ |>.map _ + variable (R) in lemma cfc_id (ha : p a := by cfc_tac) : cfc (id : R → R) a = a := cfc_apply (id : R → R) a ▸ cfcHom_id (p := p) ha @@ -391,7 +411,7 @@ lemma eqOn_of_cfc_eq_cfc {f g : R → R} {a : A} (h : cfc f a = cfc g a) (hg : ContinuousOn g (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : (spectrum R a).EqOn f g := by rw [cfc_apply f a, cfc_apply g a] at h - have := (cfcHom_closedEmbedding (show p a from ha) (R := R)).inj h + have := (cfcHom_isClosedEmbedding (show p a from ha) (R := R)).inj h intro x hx congrm($(this) ⟨x, hx⟩) @@ -1014,3 +1034,32 @@ lemma CFC.one_le_iff (a : A) (ha : p a := by cfc_tac) : end Ring end Order + +/-! ### `cfcHom` on a superset of the spectrum -/ + +section Superset + +variable {R A : Type*} {p : A → Prop} [CommSemiring R] [StarRing R] + [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] [Ring A] [StarRing A] + [TopologicalSpace A] [Algebra R A] [instCFC : ContinuousFunctionalCalculus R p] + +/-- The composition of `cfcHom` with the natural embedding `C(s, R) → C(spectrum R a, R)` +whenever `spectrum R a ⊆ s`. + +This is sometimes necessary in order to consider the same continuous functions applied to multiple +distinct elements, with the added constraint that `cfc` does not suffice. This can occur, for +example, if it is necessary to use uniqueness of this continuous functional calculus. -/ +@[simps!] +noncomputable def cfcHomSuperset {a : A} (ha : p a) {s : Set R} (hs : spectrum R a ⊆ s) : + C(s, R) →⋆ₐ[R] A := + cfcHom ha |>.comp <| ContinuousMap.compStarAlgHom' R R <| ⟨_, continuous_id.subtype_map hs⟩ + +lemma cfcHomSuperset_continuous {a : A} (ha : p a) {s : Set R} (hs : spectrum R a ⊆ s) : + Continuous (cfcHomSuperset ha hs) := + (cfcHom_continuous ha).comp <| ContinuousMap.continuous_precomp _ + +lemma cfcHomSuperset_id {a : A} (ha : p a) {s : Set R} (hs : spectrum R a ⊆ s) : + cfcHomSuperset ha hs (.restrict s <| .id R) = a := + cfcHom_id ha + +end Superset diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousLinearMap.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousLinearMap.lean new file mode 100644 index 0000000000000..e1a7aacd09ffa --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousLinearMap.lean @@ -0,0 +1,17 @@ +/- +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.CStarAlgebra.Classes +import Mathlib.Analysis.InnerProductSpace.Adjoint + +/-! # `E →L[ℂ] E` as a C⋆-algebra + +We place this here because, for reasons related to the import hierarchy, it should not be placed +in earlier files. +-/ + +noncomputable +instance {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℂ E] [CompleteSpace E] : + CStarAlgebra (E →L[ℂ] E) where diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousMap.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousMap.lean new file mode 100644 index 0000000000000..a0c67afc5074e --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousMap.lean @@ -0,0 +1,61 @@ +/- +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.CStarAlgebra.Classes +import Mathlib.Topology.ContinuousMap.Compact +import Mathlib.Topology.ContinuousMap.ZeroAtInfty + +/-! # C⋆-algebras of continuous functions + +We place these here because, for reasons related to the import hierarchy, they cannot be placed in +earlier files. +-/ + +variable {α A : Type*} +noncomputable section + +namespace BoundedContinuousFunction + +variable [TopologicalSpace α] + +instance [NonUnitalCStarAlgebra A] : NonUnitalCStarAlgebra (α →ᵇ A) where + +instance [NonUnitalCommCStarAlgebra A] : NonUnitalCommCStarAlgebra (α →ᵇ A) where + mul_comm := mul_comm + +instance [CStarAlgebra A] : CStarAlgebra (α →ᵇ A) where + +instance [CommCStarAlgebra A] : CommCStarAlgebra (α →ᵇ A) where + mul_comm := mul_comm + +end BoundedContinuousFunction + +namespace ContinuousMap + +variable [TopologicalSpace α] [CompactSpace α] + +instance [NonUnitalCStarAlgebra A] : NonUnitalCStarAlgebra C(α, A) where + +instance [NonUnitalCommCStarAlgebra A] : NonUnitalCommCStarAlgebra C(α, A) where + mul_comm := mul_comm + +instance [CStarAlgebra A] : CStarAlgebra C(α, A) where + +instance [CommCStarAlgebra A] : CommCStarAlgebra C(α, A) where + mul_comm := mul_comm + +end ContinuousMap + +namespace ZeroAtInftyContinuousMap + +open ZeroAtInfty + +instance [TopologicalSpace α] [NonUnitalCStarAlgebra A] : NonUnitalCStarAlgebra C₀(α, A) where + +instance [TopologicalSpace α] [NonUnitalCommCStarAlgebra A] : + NonUnitalCommCStarAlgebra C₀(α, A) where + mul_comm := mul_comm + +end ZeroAtInftyContinuousMap diff --git a/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean b/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean index af17ea013e3fc..88aeab7e08956 100644 --- a/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean +++ b/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ import Mathlib.Analysis.CStarAlgebra.Spectrum +import Mathlib.Analysis.CStarAlgebra.ContinuousMap import Mathlib.Analysis.Normed.Group.Quotient import Mathlib.Analysis.Normed.Algebra.Basic import Mathlib.Topology.ContinuousMap.Units @@ -124,8 +125,7 @@ end ComplexBanachAlgebra section ComplexCStarAlgebra -variable {A : Type*} [NormedCommRing A] [NormedAlgebra ℂ A] [CompleteSpace A] -variable [StarRing A] [CStarRing A] [StarModule ℂ A] +variable {A : Type*} [CommCStarAlgebra A] theorem gelfandTransform_map_star (a : A) : gelfandTransform ℂ A (star a) = star (gelfandTransform ℂ A a) := @@ -170,7 +170,7 @@ theorem gelfandTransform_bijective : Function.Bijective (gelfandTransform ℂ A) points in `C(characterSpace ℂ A, ℂ)` and is closed under `star`. -/ have h : rng.topologicalClosure = rng := le_antisymm (StarSubalgebra.topologicalClosure_minimal le_rfl - (gelfandTransform_isometry A).closedEmbedding.isClosed_range) + (gelfandTransform_isometry A).isClosedEmbedding.isClosed_range) (StarSubalgebra.le_topologicalClosure _) refine h ▸ ContinuousMap.starSubalgebra_topologicalClosure_eq_top_of_separatesPoints _ (fun _ _ => ?_) @@ -258,9 +258,7 @@ V V B --- η B ---> C(characterSpace ℂ B, ℂ) ``` -/ -theorem gelfandStarTransform_naturality {A B : Type*} [NormedCommRing A] [NormedAlgebra ℂ A] - [CompleteSpace A] [StarRing A] [CStarRing A] [StarModule ℂ A] [NormedCommRing B] - [NormedAlgebra ℂ B] [CompleteSpace B] [StarRing B] [CStarRing B] [StarModule ℂ B] +theorem gelfandStarTransform_naturality {A B : Type*} [CommCStarAlgebra A] [CommCStarAlgebra B] (φ : A →⋆ₐ[ℂ] B) : (gelfandStarTransform B : _ →⋆ₐ[ℂ] _).comp φ = (compContinuousMap φ |>.compStarAlgHom' ℂ ℂ).comp (gelfandStarTransform A : _ →⋆ₐ[ℂ] _) := by diff --git a/Mathlib/Analysis/CStarAlgebra/Hom.lean b/Mathlib/Analysis/CStarAlgebra/Hom.lean index 1f062615cf409..86e747a27affb 100644 --- a/Mathlib/Analysis/CStarAlgebra/Hom.lean +++ b/Mathlib/Analysis/CStarAlgebra/Hom.lean @@ -17,11 +17,7 @@ Here we collect properties of C⋆-algebra homomorphisms. -/ open CStarAlgebra in -lemma IsSelfAdjoint.map_spectrum_real {F A B : Type*} - [NormedRing A] [CompleteSpace A] [StarRing A] [CStarRing A] - [NormedAlgebra ℂ A] [StarModule ℂ A] - [NormedRing B] [CompleteSpace B] [StarRing B] [CStarRing B] - [NormedAlgebra ℂ B] [StarModule ℂ B] +lemma IsSelfAdjoint.map_spectrum_real {F A B : Type*} [CStarAlgebra A] [CStarAlgebra B] [FunLike F A B] [AlgHomClass F ℂ A B] [StarHomClass F A B] {a : A} (ha : IsSelfAdjoint a) (φ : F) (hφ : Function.Injective φ) : spectrum ℝ (φ a) = spectrum ℝ a := by @@ -48,11 +44,7 @@ lemma IsSelfAdjoint.map_spectrum_real {F A B : Type*} namespace NonUnitalStarAlgHom -variable {F A B : Type*} -variable [NonUnitalNormedRing A] [CompleteSpace A] [StarRing A] [CStarRing A] -variable [NormedSpace ℂ A] [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] [StarModule ℂ A] -variable [NonUnitalNormedRing B] [CompleteSpace B] [StarRing B] [CStarRing B] -variable [NormedSpace ℂ B] [IsScalarTower ℂ B B] [SMulCommClass ℂ B B] [StarModule ℂ B] +variable {F A B : Type*} [NonUnitalCStarAlgebra A] [NonUnitalCStarAlgebra B] variable [FunLike F A B] [NonUnitalAlgHomClass F ℂ A B] [StarHomClass F A B] open CStarAlgebra Unitization in diff --git a/Mathlib/Analysis/CStarAlgebra/Matrix.lean b/Mathlib/Analysis/CStarAlgebra/Matrix.lean index 49e853c8a1438..0920e15274028 100644 --- a/Mathlib/Analysis/CStarAlgebra/Matrix.lean +++ b/Mathlib/Analysis/CStarAlgebra/Matrix.lean @@ -148,7 +148,7 @@ def instL2OpMetricSpace : MetricSpace (Matrix m n 𝕜) := by letI normed_add_comm_group : NormedAddCommGroup (Matrix m n 𝕜) := { l2OpNormedAddCommGroupAux.replaceTopology <| (toEuclideanLin (𝕜 := 𝕜) (m := m) (n := n)).trans toContinuousLinearMap - |>.toContinuousLinearEquiv.toHomeomorph.inducing.induced with + |>.toContinuousLinearEquiv.toHomeomorph.isInducing.eq_induced with norm := l2OpNormedAddCommGroupAux.norm dist_eq := l2OpNormedAddCommGroupAux.dist_eq } exact normed_add_comm_group.replaceUniformity <| by diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean b/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean index a2bc174a1c07d..37189e81c7d40 100644 --- a/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean +++ b/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean @@ -60,13 +60,13 @@ open CStarModule CStarRing namespace WithCStarModule -variable {A : Type*} [NonUnitalNormedRing A] [StarRing A] [NormedSpace ℂ A] [PartialOrder A] +variable {A : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] /-! ## A C⋆-algebra as a C⋆-module over itself -/ section Self -variable [CStarRing A] [StarOrderedRing A] [SMulCommClass ℂ A A] +variable [StarOrderedRing A] /-- Reinterpret a C⋆-algebra `A` as a `CStarModule` over itself. -/ instance : CStarModule A A where @@ -112,7 +112,7 @@ lemma prod_norm_le_norm_add (x : C⋆ᵐᵒᵈ (E × F)) : ‖x‖ ≤ ‖x.1‖ _ ≤ ‖x.1‖ ^ 2 + 2 * ‖x.1‖ * ‖x.2‖ + ‖x.2‖ ^ 2 := by gcongr; positivity _ = (‖x.1‖ + ‖x.2‖) ^ 2 := by ring -variable [StarModule ℂ A] [StarOrderedRing A] +variable [StarOrderedRing A] noncomputable instance : CStarModule A (C⋆ᵐᵒᵈ (E × F)) where inner x y := inner x.1 y.1 + inner x.2 y.2 @@ -133,8 +133,6 @@ noncomputable instance : CStarModule A (C⋆ᵐᵒᵈ (E × F)) where lemma prod_inner (x y : C⋆ᵐᵒᵈ (E × F)) : ⟪x, y⟫_A = ⟪x.1, y.1⟫_A + ⟪x.2, y.2⟫_A := rfl -variable [CStarRing A] [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] [CompleteSpace A] - lemma max_le_prod_norm (x : C⋆ᵐᵒᵈ (E × F)) : max ‖x.1‖ ‖x.2‖ ≤ ‖x‖ := by rw [prod_norm] simp only [equiv_fst, norm_eq_sqrt_norm_inner_self (E := E), @@ -214,7 +212,7 @@ lemma pi_norm_le_sum_norm (x : C⋆ᵐᵒᵈ (Π i, E i)) : ‖x‖ ≤ ∑ i, _ = ∑ i, ‖x i‖ ^ 2 := by simp only [norm_sq_eq] _ ≤ (∑ i, ‖x i‖) ^ 2 := sum_sq_le_sq_sum_of_nonneg (fun _ _ ↦ norm_nonneg _) -variable [StarModule ℂ A] [StarOrderedRing A] +variable [StarOrderedRing A] open Finset in noncomputable instance : CStarModule A (C⋆ᵐᵒᵈ (Π i, E i)) where @@ -247,8 +245,6 @@ lemma inner_single_right [DecidableEq ι] (x : C⋆ᵐᵒᵈ (Π i, E i)) {i : rw [Finset.sum_eq_single i] all_goals simp_all -variable [CStarRing A] [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] [CompleteSpace A] - @[simp] lemma norm_single [DecidableEq ι] (i : ι) (y : E i) : ‖equiv _ |>.symm <| Pi.single i y‖ = ‖y‖ := by diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean index a94e81711816a..4abfbcecbf696 100644 --- a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean +++ b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean @@ -153,8 +153,8 @@ end general section norm -variable {A E : Type*} [NonUnitalNormedRing A] [StarRing A] [PartialOrder A] - [AddCommGroup E] [NormedSpace ℂ A] [Module ℂ E] [SMul Aᵐᵒᵖ E] [Norm E] [CStarModule A E] +variable {A E : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] [AddCommGroup E] + [Module ℂ E] [SMul Aᵐᵒᵖ E] [Norm E] [CStarModule A E] local notation "⟪" x ", " y "⟫" => inner (𝕜 := A) x y @@ -177,8 +177,6 @@ protected lemma norm_pos {x : E} (hx : x ≠ 0) : 0 < ‖x‖ := by rw [inner_self] at H exact hx H -variable [StarModule ℂ A] - protected lemma norm_zero : ‖(0 : E)‖ = 0 := by simp [norm_eq_sqrt_norm_inner_self] lemma norm_zero_iff (x : E) : ‖x‖ = 0 ↔ x = 0 := @@ -187,12 +185,11 @@ lemma norm_zero_iff (x : E) : ‖x‖ = 0 ↔ x = 0 := end -variable [CStarRing A] [StarOrderedRing A] [StarModule ℂ A] - [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] +variable [StarOrderedRing A] open scoped InnerProductSpace in /-- The C⋆-algebra-valued Cauchy-Schwarz inequality for Hilbert C⋆-modules. -/ -lemma inner_mul_inner_swap_le [CompleteSpace A] {x y : E} : ⟪y, x⟫ * ⟪x, y⟫ ≤ ‖x‖ ^ 2 • ⟪y, y⟫ := by +lemma inner_mul_inner_swap_le {x y : E} : ⟪y, x⟫ * ⟪x, y⟫ ≤ ‖x‖ ^ 2 • ⟪y, y⟫ := by rcases eq_or_ne x 0 with h|h · simp [h, CStarModule.norm_zero (E := E)] · have h₁ : ∀ (a : A), @@ -222,7 +219,7 @@ lemma inner_mul_inner_swap_le [CompleteSpace A] {x y : E} : ⟪y, x⟫ * ⟪x, y open scoped InnerProductSpace in variable (E) in /-- The Cauchy-Schwarz inequality for Hilbert C⋆-modules. -/ -lemma norm_inner_le [CompleteSpace A] {x y : E} : ‖⟪x, y⟫‖ ≤ ‖x‖ * ‖y‖ := by +lemma norm_inner_le {x y : E} : ‖⟪x, y⟫‖ ≤ ‖x‖ * ‖y‖ := by have := calc ‖⟪x, y⟫‖ ^ 2 = ‖⟪y, x⟫ * ⟪x, y⟫‖ := by rw [← star_inner x, CStarRing.norm_star_mul_self, pow_two] _ ≤ ‖‖x‖^ 2 • ⟪y, y⟫‖ := by @@ -236,12 +233,13 @@ lemma norm_inner_le [CompleteSpace A] {x y : E} : ‖⟪x, y⟫‖ ≤ ‖x‖ * refine (pow_le_pow_iff_left (R := ℝ) (norm_nonneg ⟪x, y⟫_A) ?_ (by norm_num)).mp this exact mul_nonneg CStarModule.norm_nonneg CStarModule.norm_nonneg -protected lemma norm_triangle [CompleteSpace A] (x y : E) : ‖x + y‖ ≤ ‖x‖ + ‖y‖ := by +include A in +protected lemma norm_triangle (x y : E) : ‖x + y‖ ≤ ‖x‖ + ‖y‖ := by have h : ‖x + y‖ ^ 2 ≤ (‖x‖ + ‖y‖) ^ 2 := by calc _ ≤ ‖⟪x, x⟫ + ⟪y, x⟫‖ + ‖⟪x, y⟫‖ + ‖⟪y, y⟫‖ := by simp only [norm_eq_sqrt_norm_inner_self, inner_add_right, inner_add_left, ← add_assoc, norm_nonneg, Real.sq_sqrt] - exact norm_add₃_le _ _ _ + exact norm_add₃_le _ ≤ ‖⟪x, x⟫‖ + ‖⟪y, x⟫‖ + ‖⟪x, y⟫‖ + ‖⟪y, y⟫‖ := by gcongr; exact norm_add_le _ _ _ ≤ ‖⟪x, x⟫‖ + ‖y‖ * ‖x‖ + ‖x‖ * ‖y‖ + ‖⟪y, y⟫‖ := by gcongr <;> exact norm_inner_le E _ = ‖x‖ ^ 2 + ‖y‖ * ‖x‖ + ‖x‖ * ‖y‖ + ‖y‖ ^ 2 := by @@ -250,21 +248,22 @@ protected lemma norm_triangle [CompleteSpace A] (x y : E) : ‖x + y‖ ≤ ‖x refine (pow_le_pow_iff_left CStarModule.norm_nonneg ?_ (by norm_num)).mp h exact add_nonneg CStarModule.norm_nonneg CStarModule.norm_nonneg +include A in /-- This allows us to get `NormedAddCommGroup` and `NormedSpace` instances on `E` via `NormedAddCommGroup.ofCore` and `NormedSpace.ofCore`. -/ -lemma normedSpaceCore [CompleteSpace A] : NormedSpace.Core ℂ E where - norm_nonneg x := CStarModule.norm_nonneg +lemma normedSpaceCore : NormedSpace.Core ℂ E where + norm_nonneg _ := CStarModule.norm_nonneg norm_eq_zero_iff x := norm_zero_iff x norm_smul c x := by simp [norm_eq_sqrt_norm_inner_self, norm_smul, ← mul_assoc] norm_triangle x y := CStarModule.norm_triangle x y /-- This is not listed as an instance because we often want to replace the topology, uniformity and bornology instead of inheriting them from the norm. -/ -abbrev normedAddCommGroup [CompleteSpace A] : NormedAddCommGroup E := +abbrev normedAddCommGroup : NormedAddCommGroup E := NormedAddCommGroup.ofCore CStarModule.normedSpaceCore open scoped InnerProductSpace in -lemma norm_eq_csSup [CompleteSpace A] (v : E) : +lemma norm_eq_csSup (v : E) : ‖v‖ = sSup { ‖⟪w, v⟫_A‖ | (w : E) (_ : ‖w‖ ≤ 1) } := by let instNACG : NormedAddCommGroup E := NormedAddCommGroup.ofCore normedSpaceCore let instNS : NormedSpace ℂ E := .ofCore normedSpaceCore @@ -286,10 +285,8 @@ open scoped InnerProductSpace `NormedAddCommGroup` and `NormedSpace` instances via `CStarModule.normedSpaceCore`, especially by using `NormedAddCommGroup.ofCoreReplaceAll` and `NormedSpace.ofCore`. See `Analysis.CStarAlgebra.Module.Constructions` for examples. -/ -variable {A E : Type*} [NonUnitalNormedRing A] [StarRing A] [CStarRing A] [PartialOrder A] - [StarOrderedRing A] [NormedSpace ℂ A] [SMul Aᵐᵒᵖ E] [CompleteSpace A] - [NormedAddCommGroup E] [NormedSpace ℂ E] [StarModule ℂ A] [CStarModule A E] [IsScalarTower ℂ A A] - [SMulCommClass ℂ A A] +variable {A E : Type*} [NonUnitalCStarAlgebra A] [PartialOrder A] [StarOrderedRing A] [SMul Aᵐᵒᵖ E] + [NormedAddCommGroup E] [NormedSpace ℂ E] [CStarModule A E] /-- The function `⟨x, y⟩ ↦ ⟪x, y⟫` bundled as a continuous sesquilinear map. -/ noncomputable def innerSL : E →L⋆[ℂ] E →L[ℂ] A := diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean b/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean index afee7eea2b49e..82554bb415dee 100644 --- a/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean +++ b/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean @@ -167,7 +167,8 @@ instance [u : UniformSpace E] : UniformSpace (C⋆ᵐᵒᵈ E) := u.comap <| equ instance [Bornology E] : Bornology (C⋆ᵐᵒᵈ E) := Bornology.induced <| equiv E /-- `WithCStarModule.equiv` as a uniform equivalence between `C⋆ᵐᵒᵈ E` and `E`. -/ -def uniformEquiv [UniformSpace E] : C⋆ᵐᵒᵈ E ≃ᵤ E := equiv E |>.toUniformEquivOfUniformInducing ⟨rfl⟩ +def uniformEquiv [UniformSpace E] : C⋆ᵐᵒᵈ E ≃ᵤ E := + equiv E |>.toUniformEquivOfIsUniformInducing ⟨rfl⟩ instance [UniformSpace E] [CompleteSpace E] : CompleteSpace (C⋆ᵐᵒᵈ E) := uniformEquiv.completeSpace_iff.mpr inferInstance diff --git a/Mathlib/Analysis/CStarAlgebra/Multiplier.lean b/Mathlib/Analysis/CStarAlgebra/Multiplier.lean index d9c622e26c2c4..2bba23247166b 100644 --- a/Mathlib/Analysis/CStarAlgebra/Multiplier.lean +++ b/Mathlib/Analysis/CStarAlgebra/Multiplier.lean @@ -5,6 +5,7 @@ Authors: Jireh Loreaux, Jon Bannon -/ import Mathlib.Analysis.NormedSpace.OperatorNorm.Completeness import Mathlib.Analysis.CStarAlgebra.Unitization +import Mathlib.Analysis.CStarAlgebra.Classes import Mathlib.Analysis.SpecialFunctions.Pow.NNReal /-! @@ -363,7 +364,7 @@ instance instAlgebra : Algebra 𝕜 𝓜(𝕜, A) where simp_rw [Prod.algebraMap_apply, Algebra.algebraMap_eq_smul_one, smul_apply, one_apply, mul_smul_comm, smul_mul_assoc] } map_one' := ext (𝕜 := 𝕜) (A := A) _ _ <| map_one <| algebraMap 𝕜 ((A →L[𝕜] A) × (A →L[𝕜] A)) - map_mul' k₁ k₂ := + map_mul' _ _ := ext (𝕜 := 𝕜) (A := A) _ _ <| Prod.ext (map_mul (algebraMap 𝕜 (A →L[𝕜] A)) _ _) ((map_mul (algebraMap 𝕜 (A →L[𝕜] A)) _ _).trans (Algebra.commutes _ _)) @@ -542,7 +543,7 @@ theorem isUniformEmbedding_toProdMulOpposite : alias uniformEmbedding_toProdMulOpposite := isUniformEmbedding_toProdMulOpposite instance [CompleteSpace A] : CompleteSpace 𝓜(𝕜, A) := by - rw [completeSpace_iff_isComplete_range isUniformEmbedding_toProdMulOpposite.toUniformInducing] + rw [completeSpace_iff_isComplete_range isUniformEmbedding_toProdMulOpposite.isUniformInducing] apply IsClosed.isComplete simp only [range_toProdMulOpposite, Set.setOf_forall] refine isClosed_iInter fun x => isClosed_iInter fun y => isClosed_eq ?_ ?_ @@ -667,4 +668,6 @@ instance instCStarRing : CStarRing 𝓜(𝕜, A) where end DenselyNormed +noncomputable instance {A : Type*} [NonUnitalCStarAlgebra A] : CStarAlgebra 𝓜(ℂ, A) where + end DoubleCentralizer diff --git a/Mathlib/Analysis/CStarAlgebra/Spectrum.lean b/Mathlib/Analysis/CStarAlgebra/Spectrum.lean index 337a423b3d120..87f11464c1150 100644 --- a/Mathlib/Analysis/CStarAlgebra/Spectrum.lean +++ b/Mathlib/Analysis/CStarAlgebra/Spectrum.lean @@ -78,7 +78,7 @@ theorem unitary.spectrum_subset_circle (u : unitary E) : rw [← inv_inv (unitary.toUnits u), ← spectrum.map_inv, Set.mem_inv] at hk have : ‖k‖⁻¹ ≤ ‖(↑(unitary.toUnits u)⁻¹ : E)‖ := by simpa only [norm_inv] using norm_le_norm_of_mem hk - simpa using inv_le_of_inv_le (norm_pos_iff.mpr hnk) this + simpa using inv_le_of_inv_le₀ (norm_pos_iff.mpr hnk) this theorem spectrum.subset_circle_of_unitary {u : E} (h : u ∈ unitary E) : spectrum 𝕜 u ⊆ Metric.sphere 0 1 := @@ -86,12 +86,21 @@ theorem spectrum.subset_circle_of_unitary {u : E} (h : u ∈ unitary E) : end UnitarySpectrum +section Quasispectrum + +open scoped NNReal in +lemma CStarAlgebra.le_nnnorm_of_mem_quasispectrum {A : Type*} [NonUnitalCStarAlgebra A] + {a : A} {x : ℝ≥0} (hx : x ∈ quasispectrum ℝ≥0 a) : x ≤ ‖a‖₊ := by + rw [Unitization.quasispectrum_eq_spectrum_inr' ℝ≥0 ℂ] at hx + simpa [Unitization.nnnorm_inr] using spectrum.le_nnnorm_of_mem hx + +end Quasispectrum + section ComplexScalars open Complex -variable {A : Type*} [NormedRing A] [NormedAlgebra ℂ A] [CompleteSpace A] [StarRing A] - [CStarRing A] +variable {A : Type*} [CStarAlgebra A] local notation "↑ₐ" => algebraMap ℂ A @@ -178,7 +187,7 @@ lemma IsSelfAdjoint.isConnected_spectrum_compl {a : A} (ha : IsSelfAdjoint a) : case nonempty => have := Filter.NeBot.nonempty_of_mem inferInstance <| Filter.mem_map.mp <| Complex.isometry_ofReal.antilipschitz.tendsto_cobounded (spectrum.isBounded a |>.compl) - exact this.image Complex.ofReal' |>.mono <| by simp + exact this.image Complex.ofReal |>.mono <| by simp case' upper => apply Complex.isConnected_of_upperHalfPlane ?_ <| Set.inter_subset_right case' lower => apply Complex.isConnected_of_lowerHalfPlane ?_ <| Set.inter_subset_right all_goals @@ -221,11 +230,7 @@ end ComplexScalars namespace NonUnitalStarAlgHom -variable {F A B : Type*} -variable [NonUnitalNormedRing A] [CompleteSpace A] [StarRing A] [CStarRing A] -variable [NormedSpace ℂ A] [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] [StarModule ℂ A] -variable [NonUnitalNormedRing B] [CompleteSpace B] [StarRing B] [CStarRing B] -variable [NormedSpace ℂ B] [IsScalarTower ℂ B B] [SMulCommClass ℂ B B] [StarModule ℂ B] +variable {F A B : Type*} [NonUnitalCStarAlgebra A] [NonUnitalCStarAlgebra B] variable [FunLike F A B] [NonUnitalAlgHomClass F ℂ A B] [StarHomClass F A B] open Unitization @@ -240,7 +245,6 @@ lemma nnnorm_apply_le (φ : F) (a : A) : ‖φ a‖₊ ≤ ‖a‖₊ := by exact this <| .star_mul_self x intro s hs suffices this : spectralRadius ℂ (ψ s) ≤ spectralRadius ℂ s by - -- changing the order of `rw`s below runs into https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/weird.20type.20class.20synthesis.20error/near/421224482 rwa [(hs.map ψ).spectralRadius_eq_nnnorm, hs.spectralRadius_eq_nnnorm, coe_le_coe] at this exact iSup_le_iSup_of_subset (AlgHom.spectrum_apply_subset ψ s) @@ -263,10 +267,7 @@ end NonUnitalStarAlgHom namespace StarAlgEquiv -variable {F A B : Type*} [NonUnitalNormedRing A] [NormedSpace ℂ A] [SMulCommClass ℂ A A] -variable [IsScalarTower ℂ A A] [CompleteSpace A] [StarRing A] [CStarRing A] [StarModule ℂ A] -variable [NonUnitalNormedRing B] [NormedSpace ℂ B] [SMulCommClass ℂ B B] [IsScalarTower ℂ B B] -variable [CompleteSpace B] [StarRing B] [CStarRing B] [StarModule ℂ B] [EquivLike F A B] +variable {F A B : Type*} [NonUnitalCStarAlgebra A] [NonUnitalCStarAlgebra B] [EquivLike F A B] variable [NonUnitalAlgEquivClass F ℂ A B] [StarHomClass F A B] lemma nnnorm_map (φ : F) (a : A) : ‖φ a‖₊ = ‖a‖₊ := @@ -289,8 +290,7 @@ open ContinuousMap Complex open scoped ComplexStarModule -variable {F A : Type*} [NormedRing A] [NormedAlgebra ℂ A] [CompleteSpace A] [StarRing A] - [CStarRing A] [StarModule ℂ A] [FunLike F A ℂ] [hF : AlgHomClass F ℂ A ℂ] +variable {F A : Type*} [CStarAlgebra A] [FunLike F A ℂ] [hF : AlgHomClass F ℂ A ℂ] /-- This instance is provided instead of `StarHomClass` to avoid type class inference loops. See note [lower instance priority] -/ diff --git a/Mathlib/Analysis/CStarAlgebra/Unitization.lean b/Mathlib/Analysis/CStarAlgebra/Unitization.lean index 7a5bdee2eef6e..0c5534a194ce1 100644 --- a/Mathlib/Analysis/CStarAlgebra/Unitization.lean +++ b/Mathlib/Analysis/CStarAlgebra/Unitization.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Jireh Loreaux. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ -import Mathlib.Analysis.CStarAlgebra.Basic +import Mathlib.Analysis.CStarAlgebra.Classes import Mathlib.Analysis.Normed.Algebra.Unitization /-! # The minimal unitization of a C⋆-algebra @@ -30,10 +30,13 @@ variable [NormedSpace 𝕜 E] [IsScalarTower 𝕜 E E] [SMulCommClass 𝕜 E E] lemma opNorm_mul_flip_apply (a : E) : ‖(mul 𝕜 E).flip a‖ = ‖a‖ := by refine le_antisymm (opNorm_le_bound _ (norm_nonneg _) fun b => by simpa only [mul_comm] using norm_mul_le b a) ?_ - suffices ‖mul 𝕜 E (star a)‖ ≤ ‖(mul 𝕜 E).flip a‖ by simpa using this + suffices ‖mul 𝕜 E (star a)‖ ≤ ‖(mul 𝕜 E).flip a‖ by + simpa only [ge_iff_le, opNorm_mul_apply, norm_star] using this refine opNorm_le_bound _ (norm_nonneg _) fun b => ?_ - calc ‖mul 𝕜 E (star a) b‖ = ‖(mul 𝕜 E).flip a (star b)‖ := by simpa using norm_star (star b * a) - _ ≤ ‖(mul 𝕜 E).flip a‖ * ‖b‖ := by simpa using le_opNorm ((mul 𝕜 E).flip a) (star b) + calc ‖mul 𝕜 E (star a) b‖ = ‖(mul 𝕜 E).flip a (star b)‖ := by + simpa only [mul_apply', flip_apply, star_mul, star_star] using norm_star (star b * a) + _ ≤ ‖(mul 𝕜 E).flip a‖ * ‖b‖ := by + simpa only [flip_apply, mul_apply', norm_star] using le_opNorm ((mul 𝕜 E).flip a) (star b) @[deprecated (since := "2024-02-02")] alias op_norm_mul_flip_apply := opNorm_mul_flip_apply @@ -171,4 +174,15 @@ instance Unitization.instCStarRing : CStarRing (Unitization 𝕜 E) where · replace h := (not_le.mp h).le rw [sq, sq, sup_eq_left.mpr h, sup_eq_left.mpr (mul_self_le_mul_self (norm_nonneg _) h)] +/-- The minimal unitization (over `ℂ`) of a C⋆-algebra, equipped with the C⋆-norm. When `A` is +unital, `A⁺¹ ≃⋆ₐ[ℂ] (ℂ × A)`. -/ +scoped[CStarAlgebra] postfix:max "⁺¹" => Unitization ℂ + +noncomputable instance Unitization.instCStarAlgebra {A : Type*} [NonUnitalCStarAlgebra A] : + CStarAlgebra (Unitization ℂ A) where + +noncomputable instance Unitization.instCommCStarAlgebra {A : Type*} [NonUnitalCommCStarAlgebra A] : + CommCStarAlgebra (Unitization ℂ A) where + mul_comm := mul_comm + end CStarProperty diff --git a/Mathlib/Analysis/CStarAlgebra/lpSpace.lean b/Mathlib/Analysis/CStarAlgebra/lpSpace.lean new file mode 100644 index 0000000000000..26dd3dc11170c --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/lpSpace.lean @@ -0,0 +1,35 @@ +/- +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.CStarAlgebra.Classes +import Mathlib.Analysis.Normed.Lp.lpSpace + +/-! # `lp ∞ A` as a C⋆-algebra + +We place these here because, for reasons related to the import hierarchy, they should not be placed +in earlier files. +-/ +open scoped ENNReal + +noncomputable section + +variable {I : Type*} {A : I → Type*} + +instance [∀ i, NonUnitalCStarAlgebra (A i)] : NonUnitalCStarAlgebra (lp A ∞) where + +instance [∀ i, NonUnitalCommCStarAlgebra (A i)] : NonUnitalCommCStarAlgebra (lp A ∞) where + mul_comm := mul_comm + +-- it's slightly weird that we need the `Nontrivial` instance here +-- it's because we have no way to say that `‖(1 : A i)‖` is uniformly bounded as a type class +-- aside from `∀ i, NormOneClass (A i)`, this holds automatically for C⋆-algebras though. +instance [∀ i, Nontrivial (A i)] [∀ i, CStarAlgebra (A i)] : NormedRing (lp A ∞) where + dist_eq := dist_eq_norm + norm_mul := norm_mul_le + +instance [∀ i, Nontrivial (A i)] [∀ i, CommCStarAlgebra (A i)] : CommCStarAlgebra (lp A ∞) where + mul_comm := mul_comm + +end diff --git a/Mathlib/Analysis/Calculus/BumpFunction/InnerProduct.lean b/Mathlib/Analysis/Calculus/BumpFunction/InnerProduct.lean index c5c01358f8747..c501d76685ccc 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/InnerProduct.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/InnerProduct.lean @@ -45,7 +45,7 @@ noncomputable def ContDiffBumpBase.ofInnerProductSpace : ContDiffBumpBase E wher · refine smoothTransition.contDiffAt.comp _ (ContDiffAt.div ?_ ?_ hR.ne') · exact contDiffAt_fst.sub (contDiffAt_snd.norm ℝ hx) · exact contDiffAt_fst.sub contDiffAt_const - eq_one R hR x hx := smoothTransition.one_of_one_le <| (one_le_div <| sub_pos.2 hR).2 <| + eq_one _ hR _ hx := smoothTransition.one_of_one_le <| (one_le_div <| sub_pos.2 hR).2 <| sub_le_sub_left hx _ support R hR := by ext x diff --git a/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean index a61f635da6766..fd3e53a98f231 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean @@ -97,7 +97,7 @@ variable (μ) theorem measure_closedBall_le_integral : (μ (closedBall c f.rIn)).toReal ≤ ∫ x, f x ∂μ := by calc (μ (closedBall c f.rIn)).toReal = ∫ x in closedBall c f.rIn, 1 ∂μ := by simp - _ = ∫ x in closedBall c f.rIn, f x ∂μ := setIntegral_congr measurableSet_closedBall + _ = ∫ x in closedBall c f.rIn, f x ∂μ := setIntegral_congr_fun measurableSet_closedBall (fun x hx ↦ (one_of_mem_closedBall f hx).symm) _ ≤ ∫ x, f x ∂μ := setIntegral_le_integral f.integrable (Eventually.of_forall (fun x ↦ f.nonneg)) diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index f9cc1aee3a4f1..bb56618def758 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -38,7 +38,7 @@ open scoped NNReal Nat local notation "∞" => (⊤ : ℕ∞) -universe u v w uD uE uF uG +universe u uE uF uG attribute [local instance 1001] NormedAddCommGroup.toAddCommGroup NormedSpace.toModule' AddCommGroup.toAddCommMonoid @@ -47,11 +47,11 @@ open Set Fin Filter Function open scoped Topology -variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {D : Type uD} [NormedAddCommGroup D] - [NormedSpace 𝕜 D] {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type uG} [NormedAddCommGroup G] [NormedSpace 𝕜 G] - {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] {s s₁ t u : Set E} {f f₁ : E → F} - {g : F → G} {x x₀ : E} {c : F} {b : E × F → G} {m n : ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} + {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] {s t : Set E} {f : E → F} + {g : F → G} {x x₀ : E} {b : E × F → G} {m n : ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} /-! ### Constants -/ @@ -135,6 +135,9 @@ theorem iteratedFDeriv_const_of_ne {n : ℕ} (hn : n ≠ 0) (c : F) : funext fun x ↦ by simpa [← iteratedFDerivWithin_univ] using iteratedFDerivWithin_const_of_ne hn c uniqueDiffOn_univ (mem_univ x) +theorem contDiffWithinAt_singleton : ContDiffWithinAt 𝕜 n f {x} x := + (contDiffWithinAt_const (c := f x)).congr (by simp) rfl + /-! ### Smoothness of linear functions -/ /-- Unbundled bounded linear functions are `C^∞`. @@ -571,7 +574,7 @@ private theorem ContDiffOn.comp_same_univ {Eu : Type u} [NormedAddCommGroup Eu] /-- 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) - (hf : ContDiffOn 𝕜 n f s) (st : s ⊆ f ⁻¹' t) : ContDiffOn 𝕜 n (g ∘ f) s := by + (hf : ContDiffOn 𝕜 n f s) (st : MapsTo f s t) : ContDiffOn 𝕜 n (g ∘ f) s := by /- we lift all the spaces to a common universe, as we have already proved the result in this situation. -/ let Eu : Type max uE uF uG := ULift.{max uF uG} E @@ -601,14 +604,26 @@ theorem ContDiffOn.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F} (hg rwa [this, isoE.contDiffOn_comp_iff, isoG.symm.comp_contDiffOn_iff] at main /-- 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) +theorem ContDiffOn.comp_inter + {s : Set E} {t : Set F} {g : F → G} {f : E → F} (hg : ContDiffOn 𝕜 n g t) (hf : ContDiffOn 𝕜 n f s) : ContDiffOn 𝕜 n (g ∘ f) (s ∩ f ⁻¹' t) := hg.comp (hf.mono inter_subset_left) inter_subset_right +@[deprecated (since := "2024-10-30")] alias ContDiffOn.comp' := ContDiffOn.comp_inter + /-- The composition of a `C^n` function on a domain with a `C^n` function is `C^n`. -/ theorem ContDiff.comp_contDiffOn {s : Set E} {g : F → G} {f : E → F} (hg : ContDiff 𝕜 n g) (hf : ContDiffOn 𝕜 n f s) : ContDiffOn 𝕜 n (g ∘ f) s := - (contDiffOn_univ.2 hg).comp hf subset_preimage_univ + (contDiffOn_univ.2 hg).comp hf (mapsTo_univ _ _) + +theorem ContDiffOn.comp_contDiff {s : Set F} {g : F → G} {f : E → F} (hg : ContDiffOn 𝕜 n g s) + (hf : ContDiff 𝕜 n f) (hs : ∀ x, f x ∈ s) : ContDiff 𝕜 n (g ∘ f) := by + rw [← contDiffOn_univ] at * + exact hg.comp hf fun x _ => hs x + +theorem ContDiffOn.image_comp_contDiff {s : Set E} {g : F → G} {f : E → F} + (hg : ContDiffOn 𝕜 n g (f '' s)) (hf : ContDiff 𝕜 n f) : ContDiffOn 𝕜 n (g ∘ f) s := + hg.comp hf.contDiffOn (s.mapsTo_image f) /-- The composition of `C^n` functions is `C^n`. -/ theorem ContDiff.comp {g : F → G} {f : E → F} (hg : ContDiff 𝕜 n g) (hf : ContDiff 𝕜 n f) : @@ -617,7 +632,7 @@ theorem ContDiff.comp {g : F → G} {f : E → F} (hg : ContDiff 𝕜 n g) (hf : /-- The composition of `C^n` functions at points in domains is `C^n`. -/ 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 : s ⊆ f ⁻¹' t) : + (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 hg.contDiffOn hm with ⟨u, u_nhd, _, hu⟩ @@ -625,44 +640,92 @@ theorem ContDiffWithinAt.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F have xmem : x ∈ f ⁻¹' u ∩ v := ⟨(mem_of_mem_nhdsWithin (mem_insert (f x) _) u_nhd : _), mem_of_mem_nhdsWithin (mem_insert x s) v_nhd⟩ - have : f ⁻¹' u ∈ 𝓝[insert x s] x := by - apply hf.continuousWithinAt.insert_self.preimage_mem_nhdsWithin' + have hmem : f ⁻¹' u ∈ 𝓝[insert x s] x := by + apply hf.continuousWithinAt.insert.preimage_mem_nhdsWithin' apply nhdsWithin_mono _ _ u_nhd rw [image_insert_eq] exact insert_subset_insert (image_subset_iff.mpr st) - have Z := - (hu.comp (hv.mono inter_subset_right) inter_subset_left).contDiffWithinAt - xmem m le_rfl + have : MapsTo f (f ⁻¹' u ∩ v) u := inter_subset_left + have Z := (hu.comp (hv.mono inter_subset_right) this).contDiffWithinAt xmem m le_rfl have : 𝓝[f ⁻¹' u ∩ v] x = 𝓝[insert x s] x := by have A : f ⁻¹' u ∩ v = insert x s ∩ (f ⁻¹' u ∩ v) := by apply Subset.antisymm _ inter_subset_right rintro y ⟨hy1, hy2⟩ simpa only [mem_inter_iff, mem_preimage, hy2, and_true, true_and, vs hy2] using hy1 rw [A, ← nhdsWithin_restrict''] - exact Filter.inter_mem this v_nhd + exact Filter.inter_mem hmem v_nhd rwa [insert_eq_of_mem xmem, this] at Z + +/-- The composition of `C^n` functions at points in domains is `C^n`. -/ +theorem ContDiffWithinAt.comp_of_eq {s : Set E} {t : Set F} {g : F → G} {f : E → F} {y : F} (x : E) + (hg : ContDiffWithinAt 𝕜 n g t y) (hf : ContDiffWithinAt 𝕜 n f s x) (st : MapsTo f s t) + (hy : f x = y) : + ContDiffWithinAt 𝕜 n (g ∘ f) s x := by + subst hy; exact hg.comp x hf st + /-- The composition of `C^n` functions at points in domains is `C^n`, with a weaker condition on `s` and `t`. -/ -theorem ContDiffWithinAt.comp_of_mem {s : Set E} {t : Set F} {g : F → G} {f : E → F} (x : E) +theorem ContDiffWithinAt.comp_of_mem_nhdsWithin_image + {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) (hs : t ∈ 𝓝[f '' s] f x) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := - (hg.mono_of_mem hs).comp x hf (subset_preimage_image f s) + (hg.mono_of_mem_nhdsWithin hs).comp x hf (subset_preimage_image f s) + +@[deprecated (since := "2024-10-18")] +alias ContDiffWithinAt.comp_of_mem := ContDiffWithinAt.comp_of_mem_nhdsWithin_image + +/-- The composition of `C^n` functions at points in domains is `C^n`, + with a weaker condition on `s` and `t`. -/ +theorem ContDiffWithinAt.comp_of_mem_nhdsWithin_image_of_eq + {s : Set E} {t : Set F} {g : F → G} {f : E → F} {y : F} (x : E) + (hg : ContDiffWithinAt 𝕜 n g t y) (hf : ContDiffWithinAt 𝕜 n f s x) + (hs : t ∈ 𝓝[f '' s] f x) (hy : f x = y) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := by + subst hy; exact hg.comp_of_mem_nhdsWithin_image x hf hs /-- The composition of `C^n` functions at points in domains is `C^n`. -/ -theorem ContDiffWithinAt.comp' {s : Set E} {t : Set F} {g : F → G} {f : E → F} (x : E) +theorem ContDiffWithinAt.comp_inter {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) : ContDiffWithinAt 𝕜 n (g ∘ f) (s ∩ f ⁻¹' t) x := hg.comp x (hf.mono inter_subset_left) inter_subset_right -theorem ContDiffAt.comp_contDiffWithinAt {n} (x : E) (hg : ContDiffAt 𝕜 n g (f x)) +/-- The composition of `C^n` functions at points in domains is `C^n`. -/ +theorem ContDiffWithinAt.comp_inter_of_eq {s : Set E} {t : Set F} {g : F → G} {f : E → F} {y : F} + (x : E) (hg : ContDiffWithinAt 𝕜 n g t y) (hf : ContDiffWithinAt 𝕜 n f s x) (hy : f x = y) : + ContDiffWithinAt 𝕜 n (g ∘ f) (s ∩ f ⁻¹' t) x := by + subst hy; exact hg.comp_inter x hf + +/-- The composition of `C^n` functions at points in domains is `C^n`, + with a weaker condition on `s` and `t`. -/ +theorem ContDiffWithinAt.comp_of_preimage_mem_nhdsWithin + {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) + (hs : f ⁻¹' t ∈ 𝓝[s] x) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := + (hg.comp_inter x hf).mono_of_mem_nhdsWithin (inter_mem self_mem_nhdsWithin hs) + +@[deprecated (since := "2024-10-18")] +alias ContDiffWithinAt.comp' := ContDiffWithinAt.comp_inter + +/-- The composition of `C^n` functions at points in domains is `C^n`, + with a weaker condition on `s` and `t`. -/ +theorem ContDiffWithinAt.comp_of_preimage_mem_nhdsWithin_of_eq + {s : Set E} {t : Set F} {g : F → G} {f : E → F} {y : F} (x : E) + (hg : ContDiffWithinAt 𝕜 n g t y) (hf : ContDiffWithinAt 𝕜 n f s x) + (hs : f ⁻¹' t ∈ 𝓝[s] x) (hy : f x = y) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := by + subst hy; exact hg.comp_of_preimage_mem_nhdsWithin x hf hs + +theorem ContDiffAt.comp_contDiffWithinAt (x : E) (hg : ContDiffAt 𝕜 n g (f x)) (hf : ContDiffWithinAt 𝕜 n f s x) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := hg.comp x hf (mapsTo_univ _ _) +theorem ContDiffAt.comp_contDiffWithinAt_of_eq {y : F} (x : E) (hg : ContDiffAt 𝕜 n g y) + (hf : ContDiffWithinAt 𝕜 n f s x) (hy : f x = y) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := by + subst hy; exact hg.comp_contDiffWithinAt x hf + /-- The composition of `C^n` functions at points is `C^n`. -/ nonrec theorem ContDiffAt.comp (x : E) (hg : ContDiffAt 𝕜 n g (f x)) (hf : ContDiffAt 𝕜 n f x) : ContDiffAt 𝕜 n (g ∘ f) x := - hg.comp x hf subset_preimage_univ + hg.comp x hf (mapsTo_univ _ _) theorem ContDiff.comp_contDiffWithinAt {g : F → G} {f : E → F} (h : ContDiff 𝕜 n g) (hf : ContDiffWithinAt 𝕜 n f t x) : ContDiffWithinAt 𝕜 n (g ∘ f) t x := @@ -767,29 +830,70 @@ theorem contDiffWithinAt_snd {s : Set (E × F)} {p : E × F} : section NAry -variable {E₁ E₂ E₃ E₄ : Type*} +variable {E₁ E₂ E₃ : Type*} variable [NormedAddCommGroup E₁] [NormedAddCommGroup E₂] [NormedAddCommGroup E₃] - [NormedAddCommGroup E₄] [NormedSpace 𝕜 E₁] [NormedSpace 𝕜 E₂] [NormedSpace 𝕜 E₃] - [NormedSpace 𝕜 E₄] + [NormedSpace 𝕜 E₁] [NormedSpace 𝕜 E₂] [NormedSpace 𝕜 E₃] theorem ContDiff.comp₂ {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} (hg : ContDiff 𝕜 n g) (hf₁ : ContDiff 𝕜 n f₁) (hf₂ : ContDiff 𝕜 n f₂) : ContDiff 𝕜 n fun x => g (f₁ x, f₂ x) := hg.comp <| hf₁.prod hf₂ -theorem ContDiff.comp₃ {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f₂ : F → E₂} {f₃ : F → E₃} - (hg : ContDiff 𝕜 n g) (hf₁ : ContDiff 𝕜 n f₁) (hf₂ : ContDiff 𝕜 n f₂) (hf₃ : ContDiff 𝕜 n f₃) : - ContDiff 𝕜 n fun x => g (f₁ x, f₂ x, f₃ x) := - hg.comp₂ hf₁ <| hf₂.prod hf₃ +theorem ContDiffAt.comp₂ {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} {x : F} + (hg : ContDiffAt 𝕜 n g (f₁ x, f₂ x)) + (hf₁ : ContDiffAt 𝕜 n f₁ x) (hf₂ : ContDiffAt 𝕜 n f₂ x) : + ContDiffAt 𝕜 n (fun x => g (f₁ x, f₂ x)) x := + hg.comp x (hf₁.prod hf₂) -theorem ContDiff.comp_contDiff_on₂ {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} {s : Set F} +theorem ContDiffAt.comp₂_contDiffWithinAt {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} + {s : Set F} {x : F} (hg : ContDiffAt 𝕜 n g (f₁ x, f₂ x)) + (hf₁ : ContDiffWithinAt 𝕜 n f₁ s x) (hf₂ : ContDiffWithinAt 𝕜 n f₂ s x) : + ContDiffWithinAt 𝕜 n (fun x => g (f₁ x, f₂ x)) s x := + hg.comp_contDiffWithinAt x (hf₁.prod hf₂) + +@[deprecated (since := "2024-10-30")] +alias ContDiffAt.comp_contDiffWithinAt₂ := ContDiffAt.comp₂_contDiffWithinAt + +theorem ContDiff.comp₂_contDiffAt {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} {x : F} + (hg : ContDiff 𝕜 n g) (hf₁ : ContDiffAt 𝕜 n f₁ x) (hf₂ : ContDiffAt 𝕜 n f₂ x) : + ContDiffAt 𝕜 n (fun x => g (f₁ x, f₂ x)) x := + hg.contDiffAt.comp₂ hf₁ hf₂ + +@[deprecated (since := "2024-10-30")] +alias ContDiff.comp_contDiffAt₂ := ContDiff.comp₂_contDiffAt + +theorem ContDiff.comp₂_contDiffWithinAt {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} + {s : Set F} {x : F} (hg : ContDiff 𝕜 n g) + (hf₁ : ContDiffWithinAt 𝕜 n f₁ s x) (hf₂ : ContDiffWithinAt 𝕜 n f₂ s x) : + ContDiffWithinAt 𝕜 n (fun x => g (f₁ x, f₂ x)) s x := + hg.contDiffAt.comp_contDiffWithinAt x (hf₁.prod hf₂) + +@[deprecated (since := "2024-10-30")] +alias ContDiff.comp_contDiffWithinAt₂ := ContDiff.comp₂_contDiffWithinAt + +theorem ContDiff.comp₂_contDiffOn {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} {s : Set F} (hg : ContDiff 𝕜 n g) (hf₁ : ContDiffOn 𝕜 n f₁ s) (hf₂ : ContDiffOn 𝕜 n f₂ s) : ContDiffOn 𝕜 n (fun x => g (f₁ x, f₂ x)) s := hg.comp_contDiffOn <| hf₁.prod hf₂ -theorem ContDiff.comp_contDiff_on₃ {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f₂ : F → E₂} {f₃ : F → E₃} +@[deprecated (since := "2024-10-10")] alias ContDiff.comp_contDiff_on₂ := ContDiff.comp₂_contDiffOn + +@[deprecated (since := "2024-10-30")] +alias ContDiff.comp_contDiffOn₂ := ContDiff.comp₂_contDiffOn + +theorem ContDiff.comp₃ {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f₂ : F → E₂} {f₃ : F → E₃} + (hg : ContDiff 𝕜 n g) (hf₁ : ContDiff 𝕜 n f₁) (hf₂ : ContDiff 𝕜 n f₂) (hf₃ : ContDiff 𝕜 n f₃) : + ContDiff 𝕜 n fun x => g (f₁ x, f₂ x, f₃ x) := + hg.comp₂ hf₁ <| hf₂.prod hf₃ + +theorem ContDiff.comp₃_contDiffOn {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f₂ : F → E₂} {f₃ : F → E₃} {s : Set F} (hg : ContDiff 𝕜 n g) (hf₁ : ContDiffOn 𝕜 n f₁ s) (hf₂ : ContDiffOn 𝕜 n f₂ s) (hf₃ : ContDiffOn 𝕜 n f₃ s) : ContDiffOn 𝕜 n (fun x => g (f₁ x, f₂ x, f₃ x)) s := - hg.comp_contDiff_on₂ hf₁ <| hf₂.prod hf₃ + hg.comp₂_contDiffOn hf₁ <| hf₂.prod hf₃ + +@[deprecated (since := "2024-10-10")] alias ContDiff.comp_contDiff_on₃ := ContDiff.comp₃_contDiffOn + +@[deprecated (since := "2024-10-30")] +alias ContDiff.comp_contDiffOn₃ := ContDiff.comp₃_contDiffOn end NAry @@ -802,22 +906,54 @@ theorem ContDiff.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F} theorem ContDiffOn.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F} {s : Set X} (hg : ContDiffOn 𝕜 n g s) (hf : ContDiffOn 𝕜 n f s) : ContDiffOn 𝕜 n (fun x => (g x).comp (f x)) s := - (isBoundedBilinearMap_comp (𝕜 := 𝕜) (E := E) (F := F) (G := G)).contDiff.comp_contDiff_on₂ hg hf + (isBoundedBilinearMap_comp (E := E) (F := F) (G := G)).contDiff.comp₂_contDiffOn hg hf + +theorem ContDiffAt.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F} {x : X} + (hg : ContDiffAt 𝕜 n g x) (hf : ContDiffAt 𝕜 n f x) : + ContDiffAt 𝕜 n (fun x => (g x).comp (f x)) x := + (isBoundedBilinearMap_comp (E := E) (G := G)).contDiff.comp₂_contDiffAt hg hf -theorem ContDiff.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} (hf : ContDiff 𝕜 n f) +theorem ContDiffWithinAt.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F} {s : Set X} {x : X} + (hg : ContDiffWithinAt 𝕜 n g s x) (hf : ContDiffWithinAt 𝕜 n f s x) : + ContDiffWithinAt 𝕜 n (fun x => (g x).comp (f x)) s x := + (isBoundedBilinearMap_comp (E := E) (G := G)).contDiff.comp₂_contDiffWithinAt hg hf + +theorem ContDiff.clm_apply {f : E → F →L[𝕜] G} {g : E → F} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) : ContDiff 𝕜 n fun x => (f x) (g x) := isBoundedBilinearMap_apply.contDiff.comp₂ hf hg -theorem ContDiffOn.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} (hf : ContDiffOn 𝕜 n f s) +theorem ContDiffOn.clm_apply {f : E → F →L[𝕜] G} {g : E → F} (hf : ContDiffOn 𝕜 n f s) (hg : ContDiffOn 𝕜 n g s) : ContDiffOn 𝕜 n (fun x => (f x) (g x)) s := - isBoundedBilinearMap_apply.contDiff.comp_contDiff_on₂ hf hg + isBoundedBilinearMap_apply.contDiff.comp₂_contDiffOn hf hg + +theorem ContDiffAt.clm_apply {f : E → F →L[𝕜] G} {g : E → F} (hf : ContDiffAt 𝕜 n f x) + (hg : ContDiffAt 𝕜 n g x) : ContDiffAt 𝕜 n (fun x => (f x) (g x)) x := + isBoundedBilinearMap_apply.contDiff.comp₂_contDiffAt hf hg + +theorem ContDiffWithinAt.clm_apply {f : E → F →L[𝕜] G} {g : E → F} + (hf : ContDiffWithinAt 𝕜 n f s x) (hg : ContDiffWithinAt 𝕜 n g s x) : + ContDiffWithinAt 𝕜 n (fun x => (f x) (g x)) s x := + isBoundedBilinearMap_apply.contDiff.comp₂_contDiffWithinAt hf hg -- Porting note: In Lean 3 we had to give implicit arguments in proofs like the following, -- to speed up elaboration. In Lean 4 this isn't necessary anymore. -theorem ContDiff.smulRight {f : E → F →L[𝕜] 𝕜} {g : E → G} {n : ℕ∞} (hf : ContDiff 𝕜 n f) +theorem ContDiff.smulRight {f : E → F →L[𝕜] 𝕜} {g : E → G} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) : ContDiff 𝕜 n fun x => (f x).smulRight (g x) := isBoundedBilinearMap_smulRight.contDiff.comp₂ hf hg +theorem ContDiffOn.smulRight {f : E → F →L[𝕜] 𝕜} {g : E → G} (hf : ContDiffOn 𝕜 n f s) + (hg : ContDiffOn 𝕜 n g s) : ContDiffOn 𝕜 n (fun x => (f x).smulRight (g x)) s := + (isBoundedBilinearMap_smulRight (E := F)).contDiff.comp₂_contDiffOn hf hg + +theorem ContDiffAt.smulRight {f : E → F →L[𝕜] 𝕜} {g : E → G} (hf : ContDiffAt 𝕜 n f x) + (hg : ContDiffAt 𝕜 n g x) : ContDiffAt 𝕜 n (fun x => (f x).smulRight (g x)) x := + (isBoundedBilinearMap_smulRight (E := F)).contDiff.comp₂_contDiffAt hf hg + +theorem ContDiffWithinAt.smulRight {f : E → F →L[𝕜] 𝕜} {g : E → G} + (hf : ContDiffWithinAt 𝕜 n f s x) (hg : ContDiffWithinAt 𝕜 n g s x) : + ContDiffWithinAt 𝕜 n (fun x => (f x).smulRight (g x)) s x := + (isBoundedBilinearMap_smulRight (E := F)).contDiff.comp₂_contDiffWithinAt hf hg + end SpecificBilinearMaps section ClmApplyConst @@ -908,7 +1044,8 @@ theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F refine this.comp _ (hasFDerivAt_prod_mk_right _ _).hasFDerivWithinAt ?_ exact mapsTo'.mpr (image_prod_mk_subset_prod_right hz.2) · exact (hf'.continuousLinearMap_comp <| (ContinuousLinearMap.compL 𝕜 F (E × F) G).flip - (ContinuousLinearMap.inr 𝕜 E F)).comp_of_mem x₀ (contDiffWithinAt_id.prod hg) hst + (ContinuousLinearMap.inr 𝕜 E F)).comp_of_mem_nhdsWithin_image x₀ + (contDiffWithinAt_id.prod hg) hst /-- The most general lemma stating that `x ↦ fderivWithin 𝕜 (f x) t (g x)` is `C^n` at a point within a set. @@ -972,6 +1109,16 @@ theorem ContDiffWithinAt.fderivWithin_right (hf : ContDiffWithinAt 𝕜 n f s x (ContDiffWithinAt.comp (x₀, x₀) hf contDiffWithinAt_snd <| prod_subset_preimage_snd s s) contDiffWithinAt_id hs hmn hx₀s (by rw [preimage_id']) +/-- `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} + (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₀ := + ContDiffWithinAt.fderivWithin_apply + (ContDiffWithinAt.comp (x₀, x₀) hf contDiffWithinAt_snd <| prod_subset_preimage_snd s s) + contDiffWithinAt_id hk hs hmn hx₀s (by rw [preimage_id']) + -- TODO: can we make a version of `ContDiffWithinAt.fderivWithin` for iterated derivatives? theorem ContDiffWithinAt.iteratedFderivWithin_right {i : ℕ} (hf : ContDiffWithinAt 𝕜 n f s x₀) (hs : UniqueDiffOn 𝕜 s) (hmn : (m + i : ℕ∞) ≤ n) (hx₀s : x₀ ∈ s) : @@ -1557,9 +1704,8 @@ end prodMap section AlgebraInverse -variable (𝕜) {R : Type*} [NormedRing R] --- Porting note: this couldn't be on the same line as the binder type update of `𝕜` -variable [NormedAlgebra 𝕜 R] +variable (𝕜) +variable {R : Type*} [NormedRing R] [NormedAlgebra 𝕜 R] open NormedRing ContinuousLinearMap Ring @@ -1771,7 +1917,7 @@ def restrContDiff (f : PartialHomeomorph E F) (n : ℕ) : PartialHomeomorph E F haveI H : f.IsImage {x | ContDiffAt 𝕜 n f x ∧ ContDiffAt 𝕜 n f.symm (f x)} {y | ContDiffAt 𝕜 n f.symm y ∧ ContDiffAt 𝕜 n f (f.symm y)} := fun x hx ↦ by simp [hx, and_comm] - H.restr <| isOpen_iff_mem_nhds.2 fun x ⟨hxs, hxf, hxf'⟩ ↦ + H.restr <| isOpen_iff_mem_nhds.2 fun _ ⟨hxs, hxf, hxf'⟩ ↦ inter_mem (f.open_source.mem_nhds hxs) <| hxf.eventually.and <| f.continuousAt hxs hxf'.eventually diff --git a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean index 75f2e43860603..2cc7ceb76bf43 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean @@ -107,10 +107,10 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_aux {Du Eu (hs y hy) rw [← norm_iteratedFDerivWithin_fderivWithin hs hx, J] have A : ContDiffOn 𝕜 n (fun y => B.precompR Du (f y) (fderivWithin 𝕜 g s y)) s := - (B.precompR Du).isBoundedBilinearMap.contDiff.comp_contDiff_on₂ + (B.precompR Du).isBoundedBilinearMap.contDiff.comp₂_contDiffOn (hf.of_le (Nat.cast_le.2 (Nat.le_succ n))) (hg.fderivWithin hs In) have A' : ContDiffOn 𝕜 n (fun y => B.precompL Du (fderivWithin 𝕜 f s y) (g y)) s := - (B.precompL Du).isBoundedBilinearMap.contDiff.comp_contDiff_on₂ (hf.fderivWithin hs In) + (B.precompL Du).isBoundedBilinearMap.contDiff.comp₂_contDiffOn (hf.fderivWithin hs In) (hg.of_le (Nat.cast_le.2 (Nat.le_succ n))) rw [iteratedFDerivWithin_add_apply' A A' hs hx] apply (norm_add_le _ _).trans ((add_le_add I1 I2).trans (le_of_eq ?_)) @@ -449,7 +449,7 @@ theorem norm_iteratedFDerivWithin_comp_le_aux {Fu Gu : Type u} [NormedAddCommGro exact Nat.add_sub_of_le (Finset.mem_range_succ_iff.1 hi) _ ≤ ∑ i ∈ Finset.range (n + 1), (n ! : ℝ) * 1 * C * D ^ (n + 1) * 1 := by gcongr with i - apply inv_le_one + apply inv_le_one_of_one_le₀ simpa only [Nat.one_le_cast] using (n - i).factorial_pos _ = (n + 1)! * C * D ^ (n + 1) := by simp only [mul_assoc, mul_one, Finset.sum_const, Finset.card_range, nsmul_eq_mul, diff --git a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean index ff7ff85e3d49e..bd9eaa1126d55 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean @@ -148,7 +148,7 @@ theorem ContDiffWithinAt.continuousWithinAt (h : ContDiffWithinAt 𝕜 n f s x) ContinuousWithinAt f s x := by rcases h 0 bot_le with ⟨u, hu, p, H⟩ rw [mem_nhdsWithin_insert] at hu - exact (H.continuousOn.continuousWithinAt hu.1).mono_of_mem hu.2 + 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 => @@ -156,49 +156,96 @@ theorem ContDiffWithinAt.congr_of_eventuallyEq (h : ContDiffWithinAt 𝕜 n f s ⟨{ 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 := + ⟨fun H ↦ H.congr_of_eventuallyEq h₁.symm hx.symm, fun H ↦ H.congr_of_eventuallyEq h₁ hx⟩ + +@[deprecated (since := "2024-10-18")] +alias Filter.EventuallyEq.contDiffWithinAt_iff := Filter.EventuallyEq.congr_contDiffWithinAt + theorem ContDiffWithinAt.congr_of_eventuallyEq_insert (h : ContDiffWithinAt 𝕜 n f s x) (h₁ : f₁ =ᶠ[𝓝[insert x s] x] f) : ContDiffWithinAt 𝕜 n f₁ s x := h.congr_of_eventuallyEq (nhdsWithin_mono x (subset_insert x s) h₁) (mem_of_mem_nhdsWithin (mem_insert x s) h₁ : _) -theorem ContDiffWithinAt.congr_of_eventually_eq' (h : ContDiffWithinAt 𝕜 n f s x) +theorem Filter.EventuallyEq.congr_contDiffWithinAt_of_insert (h₁ : f₁ =ᶠ[𝓝[insert x s] x] f) : + ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := + ⟨fun H ↦ H.congr_of_eventuallyEq_insert h₁.symm, fun H ↦ H.congr_of_eventuallyEq_insert h₁⟩ + +theorem ContDiffWithinAt.congr_of_eventuallyEq_of_mem (h : ContDiffWithinAt 𝕜 n f s x) (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : x ∈ s) : ContDiffWithinAt 𝕜 n f₁ s x := h.congr_of_eventuallyEq h₁ <| h₁.self_of_nhdsWithin hx -theorem Filter.EventuallyEq.contDiffWithinAt_iff (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : +@[deprecated (since := "2024-10-18")] +alias ContDiffWithinAt.congr_of_eventually_eq' := ContDiffWithinAt.congr_of_eventuallyEq_of_mem + +theorem Filter.EventuallyEq.congr_contDiffWithinAt_of_mem (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : x ∈ s): ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := - ⟨fun H => ContDiffWithinAt.congr_of_eventuallyEq H h₁.symm hx.symm, fun H => - H.congr_of_eventuallyEq h₁ hx⟩ + ⟨fun H ↦ H.congr_of_eventuallyEq_of_mem h₁.symm hx, fun H ↦ H.congr_of_eventuallyEq_of_mem h₁ hx⟩ theorem ContDiffWithinAt.congr (h : ContDiffWithinAt 𝕜 n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : ContDiffWithinAt 𝕜 n f₁ s x := h.congr_of_eventuallyEq (Filter.eventuallyEq_of_mem self_mem_nhdsWithin h₁) hx -theorem ContDiffWithinAt.congr' (h : ContDiffWithinAt 𝕜 n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) +theorem contDiffWithinAt_congr (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : + ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := + ⟨fun h' ↦ h'.congr (fun x hx ↦ (h₁ x hx).symm) hx.symm, fun h' ↦ h'.congr h₁ hx⟩ + +theorem ContDiffWithinAt.congr_of_mem (h : ContDiffWithinAt 𝕜 n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : x ∈ s) : ContDiffWithinAt 𝕜 n f₁ s x := h.congr h₁ (h₁ _ hx) -theorem ContDiffWithinAt.mono_of_mem (h : ContDiffWithinAt 𝕜 n f s x) {t : Set E} +@[deprecated (since := "2024-10-18")] +alias ContDiffWithinAt.congr' := ContDiffWithinAt.congr_of_mem + +theorem contDiffWithinAt_congr_of_mem (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : x ∈ s) : + ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := + contDiffWithinAt_congr h₁ (h₁ x hx) + +theorem ContDiffWithinAt.congr_of_insert (h : ContDiffWithinAt 𝕜 n f s x) + (h₁ : ∀ y ∈ insert x s, f₁ y = f y) : ContDiffWithinAt 𝕜 n f₁ s x := + h.congr (fun y hy ↦ h₁ y (mem_insert_of_mem _ hy)) (h₁ x (mem_insert _ _)) + +theorem contDiffWithinAt_congr_of_insert (h₁ : ∀ y ∈ insert x s, f₁ y = f y) : + ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := + contDiffWithinAt_congr (fun y hy ↦ h₁ y (mem_insert_of_mem _ hy)) (h₁ x (mem_insert _ _)) + +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⟩ +@[deprecated (since := "2024-10-30")] +alias ContDiffWithinAt.mono_of_mem := ContDiffWithinAt.mono_of_mem_nhdsWithin + theorem ContDiffWithinAt.mono (h : ContDiffWithinAt 𝕜 n f s x) {t : Set E} (hst : t ⊆ s) : ContDiffWithinAt 𝕜 n f t x := - h.mono_of_mem <| Filter.mem_of_superset self_mem_nhdsWithin hst + h.mono_of_mem_nhdsWithin <| Filter.mem_of_superset self_mem_nhdsWithin hst + +theorem ContDiffWithinAt.congr_mono + (h : ContDiffWithinAt 𝕜 n f s x) (h' : EqOn f₁ f s₁) (h₁ : s₁ ⊆ s) (hx : f₁ x = f x) : + ContDiffWithinAt 𝕜 n f₁ s₁ x := + (h.mono h₁).congr h' hx -theorem ContDiffWithinAt.congr_nhds (h : ContDiffWithinAt 𝕜 n f s x) {t : Set E} - (hst : 𝓝[s] x = 𝓝[t] x) : ContDiffWithinAt 𝕜 n f t x := - h.mono_of_mem <| hst ▸ self_mem_nhdsWithin +theorem ContDiffWithinAt.congr_set (h : ContDiffWithinAt 𝕜 n f s x) {t : Set E} + (hst : s =ᶠ[𝓝 x] t) : ContDiffWithinAt 𝕜 n f t x := by + rw [← nhdsWithin_eq_iff_eventuallyEq] at hst + apply h.mono_of_mem_nhdsWithin <| hst ▸ self_mem_nhdsWithin -theorem contDiffWithinAt_congr_nhds {t : Set E} (hst : 𝓝[s] x = 𝓝[t] x) : +@[deprecated (since := "2024-10-23")] +alias ContDiffWithinAt.congr_nhds := ContDiffWithinAt.congr_set + +theorem contDiffWithinAt_congr_set {t : Set E} (hst : s =ᶠ[𝓝 x] t) : ContDiffWithinAt 𝕜 n f s x ↔ ContDiffWithinAt 𝕜 n f t x := - ⟨fun h => h.congr_nhds hst, fun h => h.congr_nhds hst.symm⟩ + ⟨fun h => h.congr_set hst, fun h => h.congr_set hst.symm⟩ + +@[deprecated (since := "2024-10-23")] +alias contDiffWithinAt_congr_nhds := contDiffWithinAt_congr_set theorem contDiffWithinAt_inter' (h : t ∈ 𝓝[s] x) : ContDiffWithinAt 𝕜 n f (s ∩ t) x ↔ ContDiffWithinAt 𝕜 n f s x := - contDiffWithinAt_congr_nhds <| Eq.symm <| nhdsWithin_restrict'' _ h + contDiffWithinAt_congr_set (mem_nhdsWithin_iff_eventuallyEq.1 h).symm theorem contDiffWithinAt_inter (h : t ∈ 𝓝 x) : ContDiffWithinAt 𝕜 n f (s ∩ t) x ↔ ContDiffWithinAt 𝕜 n f s x := @@ -220,9 +267,13 @@ protected theorem ContDiffWithinAt.insert (h : ContDiffWithinAt 𝕜 n f s x) : ContDiffWithinAt 𝕜 n f (insert x s) x := h.insert' +theorem contDiffWithinAt_diff_singleton {y : E} : + ContDiffWithinAt 𝕜 n f (s \ {y}) x ↔ ContDiffWithinAt 𝕜 n f s x := by + rw [← contDiffWithinAt_insert, insert_diff_singleton, contDiffWithinAt_insert] + /-- If a function is `C^n` within a set at a point, with `n ≥ 1`, then it is differentiable within this set at this point. -/ -theorem ContDiffWithinAt.differentiable_within_at' (h : ContDiffWithinAt 𝕜 n f s x) (hn : 1 ≤ n) : +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 mem_nhdsWithin.1 hu with ⟨t, t_open, xt, tu⟩ @@ -230,9 +281,12 @@ theorem ContDiffWithinAt.differentiable_within_at' (h : ContDiffWithinAt 𝕜 n exact (differentiableWithinAt_inter (IsOpen.mem_nhds t_open xt)).1 <| ((H.mono tu).differentiableOn le_rfl) x ⟨mem_insert x s, xt⟩ +@[deprecated (since := "2024-10-10")] +alias ContDiffWithinAt.differentiable_within_at' := ContDiffWithinAt.differentiableWithinAt' + theorem ContDiffWithinAt.differentiableWithinAt (h : ContDiffWithinAt 𝕜 n f s x) (hn : 1 ≤ n) : DifferentiableWithinAt 𝕜 f s x := - (h.differentiable_within_at' hn).mono (subset_insert x s) + (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 : ℕ} : @@ -298,7 +352,7 @@ theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt' {n : ℕ} : · refine ((huf' y <| hwu hy).mono hwu).mono_of_mem ?_ 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_mono _ (subset_insert _ _) hu) + · exact hf'.mono_of_mem_nhdsWithin (nhdsWithin_mono _ (subset_insert _ _) hu) · rw [← contDiffWithinAt_insert, contDiffWithinAt_succ_iff_hasFDerivWithinAt, insert_eq_of_mem (mem_insert _ _)] rintro ⟨u, hu, hus, f', huf', hf'⟩ @@ -343,12 +397,23 @@ theorem ContDiffWithinAt.contDiffOn {m : ℕ} (hm : (m : ℕ∞) ≤ n) (h : Con let ⟨_u, uo, xu, h⟩ := h.contDiffOn' hm ⟨_, inter_mem_nhdsWithin _ (uo.mem_nhds xu), inter_subset_left, h⟩ +/-- 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 : ℕ} : + 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⟩ + 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) : ∀ᶠ y in 𝓝[insert x s] x, ContDiffWithinAt 𝕜 n f s y := by rcases h.contDiffOn le_rfl with ⟨u, hu, _, hd⟩ have : ∀ᶠ y : E in 𝓝[insert x s] x, u ∈ 𝓝[insert x s] y ∧ y ∈ u := - (eventually_nhdsWithin_nhdsWithin.2 hu).and hu - refine this.mono fun y hy => (hd y hy.2).mono_of_mem ?_ + (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 => @@ -565,7 +630,7 @@ theorem contDiffOn_succ_iff_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : 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_eventually_eq' _ hx + 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 => ?_ @@ -580,7 +645,7 @@ theorem contDiffOn_succ_iff_hasFDerivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) refine ⟨fun h => ⟨fderivWithin 𝕜 f s, h.2, fun x hx => (h.1 x hx).hasFDerivWithinAt⟩, fun h => ?_⟩ rcases h with ⟨f', h1, h2⟩ refine ⟨fun x hx => (h2 x hx).differentiableWithinAt, fun x hx => ?_⟩ - exact (h1 x hx).congr' (fun y hy => (h2 y hy).fderivWithin (hs y hy)) hx + exact (h1 x hx).congr_of_mem (fun y hy => (h2 y hy).fderivWithin (hs y hy)) hx /-- 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`. -/ @@ -659,13 +724,21 @@ theorem ContDiffAt.contDiffWithinAt (h : ContDiffAt 𝕜 n f x) : ContDiffWithin theorem ContDiffWithinAt.contDiffAt (h : ContDiffWithinAt 𝕜 n f s x) (hx : s ∈ 𝓝 x) : ContDiffAt 𝕜 n f x := by rwa [ContDiffAt, ← contDiffWithinAt_inter hx, univ_inter] +theorem contDiffWithinAt_iff_contDiffAt (h : s ∈ 𝓝 x) : + ContDiffWithinAt 𝕜 n f s x ↔ ContDiffAt 𝕜 n f x := by + rw [← univ_inter s, contDiffWithinAt_inter h, contDiffWithinAt_univ] + +theorem IsOpen.contDiffOn_iff (hs : IsOpen s) : + ContDiffOn 𝕜 n f s ↔ ∀ ⦃a⦄, a ∈ s → ContDiffAt 𝕜 n f a := + forall₂_congr fun _ => contDiffWithinAt_iff_contDiffAt ∘ hs.mem_nhds + theorem ContDiffOn.contDiffAt (h : ContDiffOn 𝕜 n f s) (hx : s ∈ 𝓝 x) : ContDiffAt 𝕜 n f x := (h _ (mem_of_mem_nhds hx)).contDiffAt hx theorem ContDiffAt.congr_of_eventuallyEq (h : ContDiffAt 𝕜 n f x) (hg : f₁ =ᶠ[𝓝 x] f) : ContDiffAt 𝕜 n f₁ x := - h.congr_of_eventually_eq' (by rwa [nhdsWithin_univ]) (mem_univ x) + h.congr_of_eventuallyEq_of_mem (by rwa [nhdsWithin_univ]) (mem_univ x) theorem ContDiffAt.of_le (h : ContDiffAt 𝕜 n f x) (hmn : m ≤ n) : ContDiffAt 𝕜 m f x := ContDiffWithinAt.of_le h hmn @@ -673,6 +746,11 @@ 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 +@[simp] +theorem contDiffWithinAt_compl_self : + ContDiffWithinAt 𝕜 n f {x}ᶜ x ↔ ContDiffAt 𝕜 n f x := by + rw [compl_eq_univ_diff, contDiffWithinAt_diff_singleton, contDiffWithinAt_univ] + /-- If a function is `C^n` with `n ≥ 1` at a point, then it is differentiable there. -/ theorem ContDiffAt.differentiableAt (h : ContDiffAt 𝕜 n f x) (hn : 1 ≤ n) : DifferentiableAt 𝕜 f x := by diff --git a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean index bce65e8bbdf7d..6bc8d6009890d 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean @@ -18,7 +18,7 @@ arbitrary choice in the definition. We also define a predicate `HasFTaylorSeriesUpTo` (and its localized version `HasFTaylorSeriesUpToOn`), saying that a sequence of multilinear maps is *a* sequence of -derivatives of `f`. Contrary to `iteratedFDerivWithin`, it accomodates well the +derivatives of `f`. Contrary to `iteratedFDerivWithin`, it accommodates well the non-uniqueness of derivatives. ## Main definitions and results diff --git a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean index 5b3ed3d9a9e4f..e5d673c7ffac0 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean @@ -14,11 +14,12 @@ import Mathlib.Analysis.Normed.Module.FiniteDimension noncomputable section -universe uD uE uF uG +universe uD uE uF -variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {D : Type uD} [NormedAddCommGroup D] - [NormedSpace 𝕜 D] {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} - [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type uG} [NormedAddCommGroup G] [NormedSpace 𝕜 G] +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {D : Type uD} [NormedAddCommGroup D] [NormedSpace 𝕜 D] + {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] /-! ### Finite dimensional results -/ @@ -29,17 +30,17 @@ open Function Module variable [CompleteSpace 𝕜] /-- A family of continuous linear maps is `C^n` on `s` if all its applications are. -/ -theorem contDiffOn_clm_apply {n : ℕ∞} {f : E → F →L[𝕜] G} {s : Set E} [FiniteDimensional 𝕜 F] : +theorem contDiffOn_clm_apply {n : ℕ∞} {f : D → E →L[𝕜] F} {s : Set D} [FiniteDimensional 𝕜 E] : ContDiffOn 𝕜 n f s ↔ ∀ y, ContDiffOn 𝕜 n (fun x => f x y) s := by refine ⟨fun h y => h.clm_apply contDiffOn_const, fun h => ?_⟩ - let d := finrank 𝕜 F + let d := finrank 𝕜 E have hd : d = finrank 𝕜 (Fin d → 𝕜) := (finrank_fin_fun 𝕜).symm let e₁ := ContinuousLinearEquiv.ofFinrankEq hd - let e₂ := (e₁.arrowCongr (1 : G ≃L[𝕜] G)).trans (ContinuousLinearEquiv.piRing (Fin d)) + let e₂ := (e₁.arrowCongr (1 : F ≃L[𝕜] F)).trans (ContinuousLinearEquiv.piRing (Fin d)) rw [← id_comp f, ← e₂.symm_comp_self] exact e₂.symm.contDiff.comp_contDiffOn (contDiffOn_pi.mpr fun i => h _) -theorem contDiff_clm_apply_iff {n : ℕ∞} {f : E → F →L[𝕜] G} [FiniteDimensional 𝕜 F] : +theorem contDiff_clm_apply_iff {n : ℕ∞} {f : D → E →L[𝕜] F} [FiniteDimensional 𝕜 E] : ContDiff 𝕜 n f ↔ ∀ y, ContDiff 𝕜 n fun x => f x y := by simp_rw [← contDiffOn_univ, contDiffOn_clm_apply] @@ -52,16 +53,16 @@ often requires an inconvenient need to generalize `F`, which results in universe (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 𝕜 E] {n : ℕ} {f : E → F} : +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 rw [contDiff_succ_iff_fderiv, contDiff_clm_apply_iff] -theorem contDiffOn_succ_of_fderiv_apply [FiniteDimensional 𝕜 E] {n : ℕ} {f : E → F} {s : Set E} +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) : ContDiffOn 𝕜 (n + 1 : ℕ) f s := contDiffOn_succ_of_fderivWithin hf <| contDiffOn_clm_apply.mpr h -theorem contDiffOn_succ_iff_fderiv_apply [FiniteDimensional 𝕜 E] {n : ℕ} {f : E → F} {s : Set E} +theorem contDiffOn_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} {s : Set D} (hs : UniqueDiffOn 𝕜 s) : ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ DifferentiableOn 𝕜 f s ∧ ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s := by diff --git a/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean b/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean new file mode 100644 index 0000000000000..4c99b51e455ba --- /dev/null +++ b/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean @@ -0,0 +1,41 @@ +/- +Copyright (c) 2022 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker, Eric Wieser +-/ +import Mathlib.Analysis.Calculus.ContDiff.Basic +import Mathlib.Analysis.Normed.Lp.PiLp + +/-! +# Derivatives on `WithLp` +-/ + +section PiLp + +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} + +theorem contDiffWithinAt_piLp {n : ℕ∞} : + 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 : ℕ∞} : + 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 : ℕ∞} : + 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 + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_contDiff_iff, contDiff_pi] + rfl + +end PiLp diff --git a/Mathlib/Analysis/Calculus/Deriv/Abs.lean b/Mathlib/Analysis/Calculus/Deriv/Abs.lean index 55365ae78213a..a5f01ae326dcf 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Abs.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Abs.lean @@ -10,7 +10,7 @@ import Mathlib.Analysis.InnerProductSpace.Calculus # Derivative of the absolute value This file compiles basic derivability properties of the absolute value, and is largely inspired -from `Mathlib.Analysis.InnerProductSpace.Calculus`, which is the analoguous file for norms derived +from `Mathlib.Analysis.InnerProductSpace.Calculus`, which is the analogous file for norms derived from an inner product space. ## Tags @@ -21,7 +21,7 @@ absolute value, derivative open Filter Real Set variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] -variable {n : ℕ∞} {f g : E → ℝ} {f' : E →L[ℝ] ℝ} {s : Set E} {x : E} +variable {n : ℕ∞} {f : E → ℝ} {f' : E →L[ℝ] ℝ} {s : Set E} {x : E} theorem contDiffAt_abs {x : ℝ} (hx : x ≠ 0) : ContDiffAt ℝ n (|·|) x := contDiffAt_norm ℝ hx diff --git a/Mathlib/Analysis/Calculus/Deriv/Basic.lean b/Mathlib/Analysis/Calculus/Deriv/Basic.lean index 5ed888191d0e0..91f89a76a1777 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Basic.lean @@ -97,7 +97,6 @@ open ContinuousLinearMap (smulRight smulRight_one_eq_iff) variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] /-- `f` has the derivative `f'` at the point `x` as `x` goes along the filter `L`. @@ -142,7 +141,7 @@ If the derivative exists (i.e., `∃ f', HasDerivAt f f' x`), then def deriv (f : 𝕜 → F) (x : 𝕜) := fderiv 𝕜 f x 1 -variable {f f₀ f₁ g : 𝕜 → F} +variable {f f₀ f₁ : 𝕜 → F} variable {f' f₀' f₁' g' : F} variable {x : 𝕜} variable {s t : Set 𝕜} diff --git a/Mathlib/Analysis/Calculus/Deriv/Comp.lean b/Mathlib/Analysis/Calculus/Deriv/Comp.lean index bb0e4bdc37b52..b57c7cc2a7dcf 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Comp.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Comp.lean @@ -43,11 +43,11 @@ open ContinuousLinearMap (smulRight smulRight_one_eq_iff) variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} +variable {f : 𝕜 → F} +variable {f' : F} variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {s : Set 𝕜} +variable {L : Filter 𝕜} section Composition @@ -65,8 +65,8 @@ usual multiplication in `comp` lemmas. /- For composition lemmas, we put x explicit to help the elaborator, as otherwise Lean tends to get confused since there are too many possibilities for composition -/ variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] [NormedSpace 𝕜' F] - [IsScalarTower 𝕜 𝕜' F] {s' t' : Set 𝕜'} {h : 𝕜 → 𝕜'} {h₁ : 𝕜 → 𝕜} {h₂ : 𝕜' → 𝕜'} {h' h₂' : 𝕜'} - {h₁' : 𝕜} {g₁ : 𝕜' → F} {g₁' : F} {L' : Filter 𝕜'} {y : 𝕜'} (x) + [IsScalarTower 𝕜 𝕜' F] {s' t' : Set 𝕜'} {h : 𝕜 → 𝕜'} {h₂ : 𝕜' → 𝕜'} {h' h₂' : 𝕜'} + {g₁ : 𝕜' → F} {g₁' : F} {L' : Filter 𝕜'} {y : 𝕜'} (x) theorem HasDerivAtFilter.scomp (hg : HasDerivAtFilter g₁ g₁' (h x) L') (hh : HasDerivAtFilter h h' x L) (hL : Tendsto h L L') : diff --git a/Mathlib/Analysis/Calculus/Deriv/Inv.lean b/Mathlib/Analysis/Calculus/Deriv/Inv.lean index 8687b3af9373d..045ec40200bc6 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inv.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inv.lean @@ -21,21 +21,14 @@ derivative -/ -universe u v w +universe u -open scoped Classical Topology ENNReal +open scoped Topology open Filter Asymptotics Set -open ContinuousLinearMap (smulRight smulRight_one_eq_iff) +open ContinuousLinearMap (smulRight) -variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] -variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} -variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L : Filter 𝕜} +variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {x : 𝕜} {s : Set 𝕜} section Inverse @@ -101,7 +94,7 @@ theorem fderivWithin_inv (x_ne_zero : x ≠ 0) (hxs : UniqueDiffWithinAt 𝕜 s rw [DifferentiableAt.fderivWithin (differentiableAt_inv x_ne_zero) hxs] exact fderiv_inv -variable {c : 𝕜 → 𝕜} {h : E → 𝕜} {c' : 𝕜} {z : E} {S : Set E} +variable {c : 𝕜 → 𝕜} {c' : 𝕜} theorem HasDerivWithinAt.inv (hc : HasDerivWithinAt c c' s x) (hx : c x ≠ 0) : HasDerivWithinAt (fun y => (c y)⁻¹) (-c' / c x ^ 2) s x := by diff --git a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean index 424877d8f983b..226fea832b664 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean @@ -22,19 +22,16 @@ derivative, inverse function -/ -universe u v w +universe u v -open scoped Classical Topology ENNReal -open Filter Asymptotics Set +open scoped Topology +open Filter Set variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} +variable {f : 𝕜 → F} +variable {f' : F} variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} theorem HasStrictDerivAt.hasStrictFDerivAt_equiv {f : 𝕜 → 𝕜} {f' x : 𝕜} (hf : HasStrictDerivAt f f' x) (hf' : f' ≠ 0) : diff --git a/Mathlib/Analysis/Calculus/Deriv/Mul.lean b/Mathlib/Analysis/Calculus/Deriv/Mul.lean index 64628ceb448d0..b7b58303ed4e3 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Mul.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Mul.lean @@ -34,11 +34,11 @@ variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} +variable {f : 𝕜 → F} +variable {f' : F} variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {s : Set 𝕜} +variable {L : Filter 𝕜} /-! ### Derivative of bilinear maps -/ @@ -169,7 +169,6 @@ lemma deriv_const_smul' {f : 𝕜 → F} {x : 𝕜} {R : Type*} [Field R] [Modul · simp only [zero_smul, deriv_const'] · have H : ¬DifferentiableAt 𝕜 (fun y ↦ c • f y) x := by contrapose! hf - change DifferentiableAt 𝕜 (fun y ↦ f y) x conv => enter [2, y]; rw [← inv_smul_smul₀ hc (f y)] exact DifferentiableAt.const_smul hf c⁻¹ rw [deriv_zero_of_not_differentiableAt hf, deriv_zero_of_not_differentiableAt H, smul_zero] @@ -322,24 +321,28 @@ theorem derivWithin_finset_prod (hxs : UniqueDiffWithinAt 𝕜 s x) end HasDeriv variable {ι : Type*} {𝔸' : Type*} [NormedCommRing 𝔸'] [NormedAlgebra 𝕜 𝔸'] - {u : Finset ι} {f : ι → 𝕜 → 𝔸'} {f' : ι → 𝔸'} + {u : Finset ι} {f : ι → 𝕜 → 𝔸'} +@[fun_prop] theorem DifferentiableAt.finset_prod (hd : ∀ i ∈ u, DifferentiableAt 𝕜 (f i) x) : DifferentiableAt 𝕜 (∏ i ∈ u, f i ·) x := by classical exact (HasDerivAt.finset_prod (fun i hi ↦ DifferentiableAt.hasDerivAt (hd i hi))).differentiableAt +@[fun_prop] theorem DifferentiableWithinAt.finset_prod (hd : ∀ i ∈ u, DifferentiableWithinAt 𝕜 (f i) s x) : DifferentiableWithinAt 𝕜 (∏ i ∈ u, f i ·) s x := by classical exact (HasDerivWithinAt.finset_prod (fun i hi ↦ DifferentiableWithinAt.hasDerivWithinAt (hd i hi))).differentiableWithinAt +@[fun_prop] theorem DifferentiableOn.finset_prod (hd : ∀ i ∈ u, DifferentiableOn 𝕜 (f i) s) : DifferentiableOn 𝕜 (∏ i ∈ u, f i ·) s := fun x hx ↦ .finset_prod (fun i hi ↦ hd i hi x hx) +@[fun_prop] theorem Differentiable.finset_prod (hd : ∀ i ∈ u, Differentiable 𝕜 (f i)) : Differentiable 𝕜 (∏ i ∈ u, f i ·) := fun x ↦ .finset_prod (fun i hi ↦ hd i hi x) @@ -348,7 +351,7 @@ end Prod section Div -variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] {c d : 𝕜 → 𝕜'} {c' d' : 𝕜'} +variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] {c : 𝕜 → 𝕜'} {c' : 𝕜'} theorem HasDerivAt.div_const (hc : HasDerivAt c c' x) (d : 𝕜') : HasDerivAt (fun x => c x / d) (c' / d) x := by @@ -362,19 +365,21 @@ theorem HasStrictDerivAt.div_const (hc : HasStrictDerivAt c c' x) (d : 𝕜') : HasStrictDerivAt (fun x => c x / d) (c' / d) x := by simpa only [div_eq_mul_inv] using hc.mul_const d⁻¹ +@[fun_prop] theorem DifferentiableWithinAt.div_const (hc : DifferentiableWithinAt 𝕜 c s x) (d : 𝕜') : DifferentiableWithinAt 𝕜 (fun x => c x / d) s x := (hc.hasDerivWithinAt.div_const _).differentiableWithinAt -@[simp] +@[simp, fun_prop] theorem DifferentiableAt.div_const (hc : DifferentiableAt 𝕜 c x) (d : 𝕜') : DifferentiableAt 𝕜 (fun x => c x / d) x := (hc.hasDerivAt.div_const _).differentiableAt +@[fun_prop] theorem DifferentiableOn.div_const (hc : DifferentiableOn 𝕜 c s) (d : 𝕜') : DifferentiableOn 𝕜 (fun x => c x / d) s := fun x hx => (hc x hx).div_const d -@[simp] +@[simp, fun_prop] theorem Differentiable.div_const (hc : Differentiable 𝕜 c) (d : 𝕜') : Differentiable 𝕜 fun x => c x / d := fun x => (hc x).div_const d diff --git a/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean b/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean index 3174575fb194d..1e4623488005d 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean @@ -28,21 +28,13 @@ derivative, polynomial -/ -universe u v w +universe u -open scoped Topology Filter ENNReal Polynomial -open Set +open scoped Polynomial -open ContinuousLinearMap (smulRight smulRight_one_eq_iff) +open ContinuousLinearMap (smulRight) -variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] -variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} -variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {x : 𝕜} {s : Set 𝕜} namespace Polynomial diff --git a/Mathlib/Analysis/Calculus/Deriv/Pow.lean b/Mathlib/Analysis/Calculus/Deriv/Pow.lean index 91052a01837fb..07f1c232737a5 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Pow.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Pow.lean @@ -19,21 +19,9 @@ For a more detailed overview of one-dimensional derivatives in mathlib, see the derivative, power -/ -universe u v w +universe u -open scoped Classical -open Topology Filter ENNReal - -open Filter Asymptotics Set - -variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] -variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} -variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {x : 𝕜} {s : Set 𝕜} /-! ### Derivative of `x ↦ x^n` for `n : ℕ` -/ diff --git a/Mathlib/Analysis/Calculus/Deriv/Prod.lean b/Mathlib/Analysis/Calculus/Deriv/Prod.lean index b0640b705f958..dfd2e896128ad 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Prod.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Prod.lean @@ -29,12 +29,7 @@ open Filter Asymptotics Set variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} -variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {f₁ : 𝕜 → F} {f₁' : F} {x : 𝕜} {s : Set 𝕜} {L : Filter 𝕜} section CartesianProduct diff --git a/Mathlib/Analysis/Calculus/Deriv/Slope.lean b/Mathlib/Analysis/Calculus/Deriv/Slope.lean index 6ffd40c200519..546d82ea875e7 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Slope.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Slope.lean @@ -25,23 +25,20 @@ derivative, slope -/ -universe u v w +universe u v -noncomputable section +open scoped Topology -open Topology Filter TopologicalSpace -open Filter Set +open Filter TopologicalSpace Set section NormedField variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type w} [NormedAddCommGroup E] [NormedSpace 𝕜 E] -variable {f f₀ f₁ g : 𝕜 → F} -variable {f' f₀' f₁' g' : F} +variable {f : 𝕜 → F} +variable {f' : F} variable {x : 𝕜} -variable {s t : Set 𝕜} -variable {L L₁ L₂ : Filter 𝕜} +variable {s : Set 𝕜} /-- If the domain has dimension one, then Fréchet derivative is equivalent to the classical definition with a limit. In this version we have to take the limit along the subset `-{x}`, diff --git a/Mathlib/Analysis/Calculus/FDeriv/Add.lean b/Mathlib/Analysis/Calculus/FDeriv/Add.lean index 18d203c64bd48..f68849f4601a0 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Add.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Add.lean @@ -21,10 +21,9 @@ This file contains the usual formulas (and existence assertions) for the derivat -/ -open Filter Asymptotics ContinuousLinearMap Set Metric +open Filter Asymptotics ContinuousLinearMap open scoped Classical -open Topology NNReal Filter Asymptotics ENNReal noncomputable section @@ -33,14 +32,11 @@ section variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] -variable {f f₀ f₁ g : E → F} -variable {f' f₀' f₁' g' : E →L[𝕜] F} -variable (e : E →L[𝕜] F) +variable {f g : E → F} +variable {f' g' : E →L[𝕜] F} variable {x : E} -variable {s t : Set E} -variable {L L₁ L₂ : Filter E} +variable {s : Set E} +variable {L : Filter E} section ConstSMul diff --git a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean index 80735fc0538cf..4a3807f990caf 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean @@ -333,7 +333,7 @@ theorem HasFPowerSeriesWithinOnBall.hasSum_derivSeries_of_hasFDerivWithinAt let F' := UniformSpace.Completion F let a : F →L[𝕜] F' := UniformSpace.Completion.toComplL let b : (E →L[𝕜] F) →ₗᵢ[𝕜] (E →L[𝕜] F') := UniformSpace.Completion.toComplₗᵢ.postcomp - rw [← b.embedding.hasSum_iff] + rw [← b.isEmbedding.hasSum_iff] have : HasFPowerSeriesWithinOnBall (a ∘ f) (a.compFormalMultilinearSeries p) s x r := a.comp_hasFPowerSeriesWithinOnBall h have Z := (this.fderivWithin hu).hasSum h'y (by simpa [edist_eq_coe_nnnorm] using hy) @@ -619,7 +619,7 @@ theorem changeOrigin_toFormalMultilinearSeries [DecidableEq ι] : rw [card_compl, Fintype.card_fin, Finset.card_singleton, Nat.add_sub_cancel_left]⟩) · use fun _ _ ↦ (singleton_injective <| compl_injective <| Subtype.ext_iff.mp ·) intro ⟨s, hs⟩ - have h : sᶜ.card = 1 := by rw [card_compl, hs, Fintype.card_fin, Nat.add_sub_cancel] + have h : #sᶜ = 1 := by rw [card_compl, hs, Fintype.card_fin, Nat.add_sub_cancel] obtain ⟨a, ha⟩ := card_eq_one.mp h exact ⟨a, Subtype.ext (compl_eq_comm.mp ha)⟩ rw [Function.comp_apply, Subtype.coe_mk, compl_singleton, piecewise_erase_univ, diff --git a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean index f156437148642..824f27bba58d2 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean @@ -741,6 +741,7 @@ end Continuous section congr /-! ### congr properties of the derivative -/ + theorem hasFDerivWithinAt_congr_set' (y : E) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) : HasFDerivWithinAt f f' s x ↔ HasFDerivWithinAt f f' t x := calc @@ -895,7 +896,7 @@ theorem Filter.EventuallyEq.fderivWithin_eq (hs : f₁ =ᶠ[𝓝[s] x] f) (hx : theorem Filter.EventuallyEq.fderivWithin' (hs : f₁ =ᶠ[𝓝[s] x] f) (ht : t ⊆ s) : fderivWithin 𝕜 f₁ t =ᶠ[𝓝[s] x] fderivWithin 𝕜 f t := - (eventually_nhdsWithin_nhdsWithin.2 hs).mp <| + (eventually_eventually_nhdsWithin.2 hs).mp <| eventually_mem_nhdsWithin.mono fun _y hys hs => EventuallyEq.fderivWithin_eq (hs.filter_mono <| nhdsWithin_mono _ ht) (hs.self_of_nhdsWithin hys) diff --git a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean index b5afecc0aa536..b16d9f55939ba 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean @@ -16,9 +16,7 @@ bounded bilinear maps. -/ -open Filter Asymptotics ContinuousLinearMap Set Metric -open scoped Classical -open Topology NNReal Asymptotics ENNReal +open Asymptotics Topology noncomputable section @@ -29,12 +27,6 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] -variable {f f₀ f₁ g : E → F} -variable {f' f₀' f₁' g' : E →L[𝕜] F} -variable (e : E →L[𝕜] F) -variable {x : E} -variable {s t : Set E} -variable {L L₁ L₂ : Filter E} section BilinearMap diff --git a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean index 410d6d1cf3e69..f67a44873f801 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean @@ -84,11 +84,14 @@ theorem HasFDerivAt.comp_hasFDerivWithinAt {g : F → G} {g' : F →L[𝕜] G} hg.comp x hf hf.continuousWithinAt @[fun_prop] -theorem HasFDerivWithinAt.comp_of_mem {g : F → G} {g' : F →L[𝕜] G} {t : Set F} +theorem HasFDerivWithinAt.comp_of_tendsto {g : F → G} {g' : F →L[𝕜] G} {t : Set F} (hg : HasFDerivWithinAt g g' t (f x)) (hf : HasFDerivWithinAt f f' s x) (hst : Tendsto f (𝓝[s] x) (𝓝[t] f x)) : HasFDerivWithinAt (g ∘ f) (g'.comp f') s x := HasFDerivAtFilter.comp x hg hf hst +@[deprecated (since := "2024-10-18")] +alias HasFDerivWithinAt.comp_of_mem := HasFDerivWithinAt.comp_of_tendsto + /-- The chain rule. -/ @[fun_prop] theorem HasFDerivAt.comp {g : F → G} {g' : F →L[𝕜] G} (hg : HasFDerivAt g g' (f x)) diff --git a/Mathlib/Analysis/Calculus/FDeriv/Linear.lean b/Mathlib/Analysis/Calculus/FDeriv/Linear.lean index eba65ff473261..a705e49b74306 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Linear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Linear.lean @@ -17,26 +17,18 @@ bounded linear maps. -/ -open Filter Asymptotics ContinuousLinearMap Set Metric - -open scoped Classical -open Topology NNReal Filter Asymptotics ENNReal - -noncomputable section +open Asymptotics section variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] -variable {f f₀ f₁ g : E → F} -variable {f' f₀' f₁' g' : E →L[𝕜] F} +variable {f : E → F} variable (e : E →L[𝕜] F) variable {x : E} -variable {s t : Set E} -variable {L L₁ L₂ : Filter E} +variable {s : Set E} +variable {L : Filter E} section ContinuousLinearMap diff --git a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean index 28e1539f0e516..04a77dce02ef7 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean @@ -259,7 +259,7 @@ theorem D_subset_differentiable_set {K : Set (E →L[𝕜] F)} (hK : IsComplete ‖L e p q - L e p r + (L e p r - L e' p' r) + (L e' p' r - L e' p' q')‖ := by congr 1; abel _ ≤ ‖L e p q - L e p r‖ + ‖L e p r - L e' p' r‖ + ‖L e' p' r - L e' p' q'‖ := - norm_add₃_le _ _ _ + norm_add₃_le _ ≤ 4 * ‖c‖ * (1 / 2) ^ e + 4 * ‖c‖ * (1 / 2) ^ e + 4 * ‖c‖ * (1 / 2) ^ e := by gcongr _ = 12 * ‖c‖ * (1 / 2) ^ e := by ring /- For definiteness, use `L0 e = L e (n e) (n e)`, to have a single sequence. We claim that this @@ -592,7 +592,6 @@ theorem D_subset_differentiable_set {K : Set F} (hK : IsComplete K) : _ ≤ ‖L e p q - L e p r‖ + ‖L e p r - L e' p' r‖ + ‖L e' p' r - L e' p' q'‖ := (le_trans (norm_add_le _ _) (add_le_add_right (norm_add_le _ _) _)) _ ≤ 4 * (1 / 2) ^ e + 4 * (1 / 2) ^ e + 4 * (1 / 2) ^ e := by gcongr - -- Porting note: proof was `by apply_rules [add_le_add]` _ = 12 * (1 / 2) ^ e := by ring /- For definiteness, use `L0 e = L e (n e) (n e)`, to have a single sequence. We claim that this @@ -788,7 +787,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [LocallyCompactSpace E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {α : Type*} [TopologicalSpace α] - {f : α → E → F} (K : Set (E →L[𝕜] F)) + {f : α → E → F} namespace FDerivMeasurableAux @@ -844,7 +843,7 @@ lemma isOpen_A_with_param {r s : ℝ} (hf : Continuous f.uncurry) (L : E →L[ calc ‖f a' z - f a' y - (L z - L y)‖ = ‖(f a' z - f a z) + (f a y - f a' y) + (f a z - f a y - (L z - L y))‖ := by congr; abel - _ ≤ ‖f a' z - f a z‖ + ‖f a y - f a' y‖ + ‖f a z - f a y - (L z - L y)‖ := norm_add₃_le _ _ _ + _ ≤ ‖f a' z - f a z‖ + ‖f a y - f a' y‖ + ‖f a z - f a y - (L z - L y)‖ := norm_add₃_le _ ≤ ε + ε + b := by gcongr · rw [← dist_eq_norm] diff --git a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean index 990bb02bd9599..a33ed2ab821e1 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean @@ -21,10 +21,7 @@ This file contains the usual formulas (and existence assertions) for the derivat -/ -open scoped Classical -open Filter Asymptotics ContinuousLinearMap Set Metric Topology NNReal ENNReal - -noncomputable section +open Asymptotics ContinuousLinearMap Topology section @@ -32,13 +29,10 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] -variable {f f₀ f₁ g : E → F} -variable {f' f₀' f₁' g' : E →L[𝕜] F} -variable (e : E →L[𝕜] F) +variable {f : E → F} +variable {f' : E →L[𝕜] F} variable {x : E} -variable {s t : Set E} -variable {L L₁ L₂ : Filter E} +variable {s : Set E} section CLMCompApply diff --git a/Mathlib/Analysis/Calculus/FDeriv/Norm.lean b/Mathlib/Analysis/Calculus/FDeriv/Norm.lean new file mode 100644 index 0000000000000..b43a36ea81d3a --- /dev/null +++ b/Mathlib/Analysis/Calculus/FDeriv/Norm.lean @@ -0,0 +1,200 @@ +/- +Copyright (c) 2024 Etienne Marion. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Etienne Marion +-/ +import Mathlib.Analysis.Calculus.Deriv.Abs +import Mathlib.Analysis.Calculus.LineDeriv.Basic + +/-! +# Differentiability of the norm in a real normed vector space + +This file provides basic results about the differentiability of the norm in a real vector space. +Most are of the following kind: if the norm has some differentiability property +(`DifferentiableAt`, `ContDiffAt`, `HasStrictFDerivAt`, `HasFDerivAt`) at `x`, then so it has +at `t • x` when `t ≠ 0`. + +## Main statements + +* `ContDiffAt.contDiffAt_norm_smul`: If the norm is continuously differentiable up to order `n` + at `x`, then so it is at `t • x` when `t ≠ 0`. +* `differentiableAt_norm_smul`: If `t ≠ 0`, the norm is differentiable at `x` if and only if + it is at `t • x`. +* `HasFDerivAt.hasFDerivAt_norm_smul`: If the norm has a Fréchet derivative `f` at `x` and `t ≠ 0`, + then it has `(SignType t) • f` as a Fréchet derivative at `t · x`. +* `fderiv_norm_smul` : `fderiv ℝ (‖·‖) (t • x) = (SignType.sign t : ℝ) • (fderiv ℝ (‖·‖) x)`, + this holds without any differentiability assumptions. +* `DifferentiableAt.fderiv_norm_self`: if the norm is differentiable at `x`, + then `fderiv ℝ (‖·‖) x x = ‖x‖`. +* `norm_fderiv_norm`: if the norm is differentiable at `x` then the operator norm of its derivative + is `1` (on a non trivial space). + +## Tags + +differentiability, norm + +-/ + +open ContinuousLinearMap Filter NNReal Real Set + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] +variable {n : ℕ∞} {f : E →L[ℝ] ℝ} {x : E} {t : ℝ} + +variable (E) in +theorem not_differentiableAt_norm_zero [Nontrivial E] : + ¬DifferentiableAt ℝ (‖·‖) (0 : E) := by + obtain ⟨x, hx⟩ := NormedSpace.exists_lt_norm ℝ E 0 + intro h + have : DifferentiableAt ℝ (fun t : ℝ ↦ ‖t • x‖) 0 := DifferentiableAt.comp _ (by simpa) (by simp) + have : DifferentiableAt ℝ (|·|) (0 : ℝ) := by + simp_rw [norm_smul, norm_eq_abs] at this + have aux : abs = fun t ↦ (1 / ‖x‖) * (|t| * ‖x‖) := by field_simp + rw [aux] + exact this.const_mul _ + exact not_differentiableAt_abs_zero this + +theorem ContDiffAt.contDiffAt_norm_smul (ht : t ≠ 0) (h : ContDiffAt ℝ n (‖·‖) x) : + ContDiffAt ℝ n (‖·‖) (t • x) := by + have h1 : ContDiffAt ℝ n (fun y ↦ t⁻¹ • y) (t • x) := (contDiff_const_smul t⁻¹).contDiffAt + have h2 : ContDiffAt ℝ n (fun y ↦ |t| * ‖y‖) x := h.const_smul |t| + conv at h2 => enter [4]; rw [← one_smul ℝ x, ← inv_mul_cancel₀ ht, mul_smul] + convert h2.comp (t • x) h1 using 1 + ext y + simp only [Function.comp_apply] + rw [norm_smul, ← mul_assoc, norm_eq_abs, ← abs_mul, mul_inv_cancel₀ ht, abs_one, one_mul] + +theorem contDiffAt_norm_smul_iff (ht : t ≠ 0) : + ContDiffAt ℝ n (‖·‖) x ↔ ContDiffAt ℝ n (‖·‖) (t • x) where + mp h := h.contDiffAt_norm_smul ht + mpr hd := by + convert hd.contDiffAt_norm_smul (inv_ne_zero ht) + rw [smul_smul, inv_mul_cancel₀ ht, one_smul] + +theorem ContDiffAt.contDiffAt_norm_of_smul (h : ContDiffAt ℝ n (‖·‖) (t • x)) : + ContDiffAt ℝ n (‖·‖) x := by + obtain rfl | hn : n = 0 ∨ 1 ≤ n := by + rw [← ENat.lt_one_iff_eq_zero] + exact lt_or_le .. + · rw [contDiffAt_zero] + exact ⟨univ, univ_mem, continuous_norm.continuousOn⟩ + obtain rfl | ht := eq_or_ne t 0 + · by_cases hE : Nontrivial E + · rw [zero_smul] at h + exact (mt (ContDiffAt.differentiableAt · hn)) (not_differentiableAt_norm_zero E) h |>.elim + · rw [not_nontrivial_iff_subsingleton] at hE + rw [eq_const_of_subsingleton (‖·‖) 0] + exact contDiffAt_const + · exact contDiffAt_norm_smul_iff ht |>.2 h + +theorem HasStrictFDerivAt.hasStrictFDerivAt_norm_smul + (ht : t ≠ 0) (h : HasStrictFDerivAt (‖·‖) f x) : + HasStrictFDerivAt (‖·‖) ((SignType.sign t : ℝ) • f) (t • x) := by + have h1 : HasStrictFDerivAt (fun y ↦ t⁻¹ • y) (t⁻¹ • ContinuousLinearMap.id ℝ E) (t • x) := + hasStrictFDerivAt_id (t • x) |>.const_smul t⁻¹ + have h2 : HasStrictFDerivAt (fun y ↦ |t| * ‖y‖) (|t| • f) x := h.const_smul |t| + conv at h2 => enter [3]; rw [← one_smul ℝ x, ← inv_mul_cancel₀ ht, mul_smul] + convert h2.comp (t • x) h1 with y + · rw [norm_smul, ← mul_assoc, norm_eq_abs, ← abs_mul, mul_inv_cancel₀ ht, abs_one, one_mul] + ext y + simp only [coe_smul', Pi.smul_apply, smul_eq_mul, comp_smulₛₗ, map_inv₀, RingHom.id_apply, + comp_id] + rw [eq_inv_mul_iff_mul_eq₀ ht, ← mul_assoc, self_mul_sign] + +theorem HasStrictFDerivAt.hasStrictDerivAt_norm_smul_neg + (ht : t < 0) (h : HasStrictFDerivAt (‖·‖) f x) : + HasStrictFDerivAt (‖·‖) (-f) (t • x) := by + simpa [ht] using h.hasStrictFDerivAt_norm_smul ht.ne + +theorem HasStrictFDerivAt.hasStrictDerivAt_norm_smul_pos + (ht : 0 < t) (h : HasStrictFDerivAt (‖·‖) f x) : + HasStrictFDerivAt (‖·‖) f (t • x) := by + simpa [ht] using h.hasStrictFDerivAt_norm_smul ht.ne' + +theorem HasFDerivAt.hasFDerivAt_norm_smul + (ht : t ≠ 0) (h : HasFDerivAt (‖·‖) f x) : + HasFDerivAt (‖·‖) ((SignType.sign t : ℝ) • f) (t • x) := by + have h1 : HasFDerivAt (fun y ↦ t⁻¹ • y) (t⁻¹ • ContinuousLinearMap.id ℝ E) (t • x) := + hasFDerivAt_id (t • x) |>.const_smul t⁻¹ + have h2 : HasFDerivAt (fun y ↦ |t| * ‖y‖) (|t| • f) x := h.const_smul |t| + conv at h2 => enter [3]; rw [← one_smul ℝ x, ← inv_mul_cancel₀ ht, mul_smul] + convert h2.comp (t • x) h1 using 2 with y + · simp only [Function.comp_apply] + rw [norm_smul, ← mul_assoc, norm_eq_abs, ← abs_mul, mul_inv_cancel₀ ht, abs_one, one_mul] + · ext y + simp only [coe_smul', Pi.smul_apply, smul_eq_mul, comp_smulₛₗ, map_inv₀, RingHom.id_apply, + comp_id] + rw [eq_inv_mul_iff_mul_eq₀ ht, ← mul_assoc, self_mul_sign] + +theorem HasFDerivAt.hasFDerivAt_norm_smul_neg + (ht : t < 0) (h : HasFDerivAt (‖·‖) f x) : + HasFDerivAt (‖·‖) (-f) (t • x) := by + simpa [ht] using h.hasFDerivAt_norm_smul ht.ne + +theorem HasFDerivAt.hasFDerivAt_norm_smul_pos + (ht : 0 < t) (h : HasFDerivAt (‖·‖) f x) : + HasFDerivAt (‖·‖) f (t • x) := by + simpa [ht] using h.hasFDerivAt_norm_smul ht.ne' + +theorem differentiableAt_norm_smul (ht : t ≠ 0) : + DifferentiableAt ℝ (‖·‖) x ↔ DifferentiableAt ℝ (‖·‖) (t • x) where + mp hd := (hd.hasFDerivAt.hasFDerivAt_norm_smul ht).differentiableAt + mpr hd := by + convert (hd.hasFDerivAt.hasFDerivAt_norm_smul (inv_ne_zero ht)).differentiableAt + rw [smul_smul, inv_mul_cancel₀ ht, one_smul] + +theorem DifferentiableAt.differentiableAt_norm_of_smul (h : DifferentiableAt ℝ (‖·‖) (t • x)) : + DifferentiableAt ℝ (‖·‖) x := by + obtain rfl | ht := eq_or_ne t 0 + · by_cases hE : Nontrivial E + · rw [zero_smul] at h + exact not_differentiableAt_norm_zero E h |>.elim + · rw [not_nontrivial_iff_subsingleton] at hE + exact (hasFDerivAt_of_subsingleton _ _).differentiableAt + · exact differentiableAt_norm_smul ht |>.2 h + +theorem DifferentiableAt.fderiv_norm_self {x : E} (h : DifferentiableAt ℝ (‖·‖) x) : + fderiv ℝ (‖·‖) x x = ‖x‖ := by + rw [← h.lineDeriv_eq_fderiv, lineDeriv] + have this (t : ℝ) : ‖x + t • x‖ = |1 + t| * ‖x‖ := by + rw [← norm_eq_abs, ← norm_smul, add_smul, one_smul] + simp_rw [this] + rw [deriv_mul_const] + · conv_lhs => enter [1, 1]; change _root_.abs ∘ (fun t ↦ 1 + t) + rw [deriv.comp, deriv_abs, deriv_const_add] + · simp + · exact differentiableAt_abs (by norm_num) + · exact differentiableAt_id.const_add _ + · exact (differentiableAt_abs (by norm_num)).comp _ (differentiableAt_id.const_add _) + +variable (x t) in +theorem fderiv_norm_smul : + fderiv ℝ (‖·‖) (t • x) = (SignType.sign t : ℝ) • (fderiv ℝ (‖·‖) x) := by + by_cases hE : Nontrivial E + · by_cases hd : DifferentiableAt ℝ (‖·‖) x + · obtain rfl | ht := eq_or_ne t 0 + · simp only [zero_smul, _root_.sign_zero, SignType.coe_zero] + exact fderiv_zero_of_not_differentiableAt <| not_differentiableAt_norm_zero E + · rw [(hd.hasFDerivAt.hasFDerivAt_norm_smul ht).fderiv] + · rw [fderiv_zero_of_not_differentiableAt hd, fderiv_zero_of_not_differentiableAt] + · simp + · exact mt DifferentiableAt.differentiableAt_norm_of_smul hd + · rw [not_nontrivial_iff_subsingleton] at hE + simp_rw [(hasFDerivAt_of_subsingleton _ _).fderiv, smul_zero] + +theorem fderiv_norm_smul_pos (ht : 0 < t) : + fderiv ℝ (‖·‖) (t • x) = fderiv ℝ (‖·‖) x := by + simp [fderiv_norm_smul, ht] + +theorem fderiv_norm_smul_neg (ht : t < 0) : + fderiv ℝ (‖·‖) (t • x) = -fderiv ℝ (‖·‖) x := by + simp [fderiv_norm_smul, ht] + +theorem norm_fderiv_norm [Nontrivial E] (h : DifferentiableAt ℝ (‖·‖) x) : + ‖fderiv ℝ (‖·‖) x‖ = 1 := by + have : x ≠ 0 := fun hx ↦ not_differentiableAt_norm_zero E (hx ▸ h) + refine le_antisymm (NNReal.coe_one ▸ norm_fderiv_le_of_lipschitz ℝ lipschitzWith_one_norm) ?_ + apply le_of_mul_le_mul_right _ (norm_pos_iff.2 this) + calc + 1 * ‖x‖ = fderiv ℝ (‖·‖) x x := by rw [one_mul, h.fderiv_norm_self] + _ ≤ ‖fderiv ℝ (‖·‖) x x‖ := le_norm_self _ + _ ≤ ‖fderiv ℝ (‖·‖) x‖ * ‖x‖ := le_opNorm _ _ diff --git a/Mathlib/Analysis/Calculus/FDeriv/Pi.lean b/Mathlib/Analysis/Calculus/FDeriv/Pi.lean index f985ae505ea08..fdc2b96749939 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Pi.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Pi.lean @@ -11,7 +11,6 @@ import Mathlib.Analysis.Calculus.FDeriv.Add variable {𝕜 ι : Type*} [DecidableEq ι] [Fintype ι] [NontriviallyNormedField 𝕜] variable {E : ι → Type*} [∀ i, NormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)] -variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] @[fun_prop] theorem hasFDerivAt_update (x : ∀ i, E i) {i : ι} (y : E i) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Star.lean b/Mathlib/Analysis/Calculus/FDeriv/Star.lean index 48f652a8dd13d..933c9c2c4fdc1 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Star.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Star.lean @@ -27,7 +27,7 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [StarAddMonoid F] [NormedSpace 𝕜 F] [StarModule 𝕜 F] [ContinuousStar F] -variable {f : E → F} {f' : E →L[𝕜] F} (e : E →L[𝕜] F) {x : E} {s : Set E} {L : Filter E} +variable {f : E → F} {f' : E →L[𝕜] F} {x : E} {s : Set E} {L : Filter E} @[fun_prop] theorem HasStrictFDerivAt.star (h : HasStrictFDerivAt f f' x) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/WithLp.lean b/Mathlib/Analysis/Calculus/FDeriv/WithLp.lean new file mode 100644 index 0000000000000..1953b606870a9 --- /dev/null +++ b/Mathlib/Analysis/Calculus/FDeriv/WithLp.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2022 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker, Eric Wieser +-/ +import Mathlib.Analysis.Calculus.FDeriv.Prod +import Mathlib.Analysis.Calculus.FDeriv.Equiv +import Mathlib.Analysis.Normed.Lp.PiLp + + +/-! +# Derivatives on `WithLp` +-/ + +section PiLp + +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} + +theorem differentiableWithinAt_piLp : + DifferentiableWithinAt 𝕜 f t y ↔ ∀ i, DifferentiableWithinAt 𝕜 (fun x => f x i) t y := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_differentiableWithinAt_iff, + differentiableWithinAt_pi] + rfl + +theorem differentiableAt_piLp : + DifferentiableAt 𝕜 f y ↔ ∀ i, DifferentiableAt 𝕜 (fun x => f x i) y := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_differentiableAt_iff, differentiableAt_pi] + rfl + +theorem differentiableOn_piLp : + DifferentiableOn 𝕜 f t ↔ ∀ i, DifferentiableOn 𝕜 (fun x => f x i) t := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_differentiableOn_iff, differentiableOn_pi] + rfl + +theorem differentiable_piLp : Differentiable 𝕜 f ↔ ∀ i, Differentiable 𝕜 fun x => f x i := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_differentiable_iff, differentiable_pi] + rfl + +theorem hasStrictFDerivAt_piLp : + HasStrictFDerivAt f f' y ↔ + ∀ i, HasStrictFDerivAt (fun x => f x i) (PiLp.proj _ _ i ∘L f') y := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_hasStrictFDerivAt_iff, hasStrictFDerivAt_pi'] + rfl + +theorem hasFDerivWithinAt_piLp : + HasFDerivWithinAt f f' t y ↔ + ∀ i, HasFDerivWithinAt (fun x => f x i) (PiLp.proj _ _ i ∘L f') t y := by + rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_hasFDerivWithinAt_iff, hasFDerivWithinAt_pi'] + rfl + +end PiLp diff --git a/Mathlib/Analysis/Calculus/FirstDerivativeTest.lean b/Mathlib/Analysis/Calculus/FirstDerivativeTest.lean new file mode 100644 index 0000000000000..381835d729b57 --- /dev/null +++ b/Mathlib/Analysis/Calculus/FirstDerivativeTest.lean @@ -0,0 +1,114 @@ +/- +Copyright (c) 2024 Bjørn Kjos-Hanssen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bjørn Kjos-Hanssen, Patrick Massot, Floris van Doorn +-/ +import Mathlib.Analysis.Calculus.MeanValue +import Mathlib.Topology.Order.OrderClosedExtr +/-! +# The First-Derivative Test + +We prove the first-derivative test in the strong form given on [Wikipedia](https://en.wikipedia.org/wiki/Derivative_test#First-derivative_test). + +The test is proved over the real numbers ℝ +using `monotoneOn_of_deriv_nonneg` from [Mathlib.Analysis.Calculus.MeanValue]. + +## Main results + +* `isLocalMax_of_deriv_Ioo`: Suppose `f` is a real-valued function of a real variable + defined on some interval containing the point `a`. + Further suppose that `f` is continuous at `a` and differentiable on some open interval + containing `a`, except possibly at `a` itself. + + If there exists a positive number `r > 0` such that for every `x` in `(a − r, a)` + we have `f′(x) ≥ 0`, and for every `x` in `(a, a + r)` we have `f′(x) ≤ 0`, + then `f` has a local maximum at `a`. + +* `isLocalMin_of_deriv_Ioo`: The dual of `first_derivative_max`, for minima. + +* `isLocalMax_of_deriv`: 1st derivative test for maxima using filters. + +* `isLocalMin_of_deriv`: 1st derivative test for minima using filters. + +## Tags + +derivative test, calculus +-/ + +open Set Topology + + + /-- The First-Derivative Test from calculus, maxima version. + Suppose `a < b < c`, `f : ℝ → ℝ` is continuous at `b`, + the derivative `f'` is nonnegative on `(a,b)`, and + the derivative `f'` is nonpositive on `(b,c)`. Then `f` has a local maximum at `a`. -/ +lemma isLocalMax_of_deriv_Ioo {f : ℝ → ℝ} {a b c : ℝ} (g₀ : a < b) (g₁ : b < c) + (h : ContinuousAt f b) + (hd₀ : DifferentiableOn ℝ f (Ioo a b)) + (hd₁ : DifferentiableOn ℝ f (Ioo b c)) + (h₀ : ∀ x ∈ Ioo a b, 0 ≤ deriv f x) + (h₁ : ∀ x ∈ Ioo b c, deriv f x ≤ 0) : IsLocalMax f b := + have hIoc : ContinuousOn f (Ioc a b) := + Ioo_union_right g₀ ▸ hd₀.continuousOn.union_continuousAt (isOpen_Ioo (a := a) (b := b)) + (by simp_all) + have hIco : ContinuousOn f (Ico b c) := + Ioo_union_left g₁ ▸ hd₁.continuousOn.union_continuousAt (isOpen_Ioo (a := b) (b := c)) + (by simp_all) + isLocalMax_of_mono_anti g₀ g₁ + (monotoneOn_of_deriv_nonneg (convex_Ioc a b) hIoc (by simp_all) (by simp_all)) + (antitoneOn_of_deriv_nonpos (convex_Ico b c) hIco (by simp_all) (by simp_all)) + + +/-- The First-Derivative Test from calculus, minima version. -/ +lemma isLocalMin_of_deriv_Ioo {f : ℝ → ℝ} {a b c : ℝ} + (g₀ : a < b) (g₁ : b < c) (h : ContinuousAt f b) + (hd₀ : DifferentiableOn ℝ f (Ioo a b)) (hd₁ : DifferentiableOn ℝ f (Ioo b c)) + (h₀ : ∀ x ∈ Ioo a b, deriv f x ≤ 0) + (h₁ : ∀ x ∈ Ioo b c, 0 ≤ deriv f x) : IsLocalMin f b := by + have := isLocalMax_of_deriv_Ioo (f := -f) g₀ g₁ + (by simp_all) hd₀.neg hd₁.neg + (fun x hx => deriv.neg (f := f) ▸ Left.nonneg_neg_iff.mpr <|h₀ x hx) + (fun x hx => deriv.neg (f := f) ▸ Left.neg_nonpos_iff.mpr <|h₁ x hx) + exact (neg_neg f) ▸ IsLocalMax.neg this + + /-- The First-Derivative Test from calculus, maxima version, + expressed in terms of left and right filters. -/ +lemma isLocalMax_of_deriv' {f : ℝ → ℝ} {b : ℝ} (h : ContinuousAt f b) + (hd₀ : ∀ᶠ x in 𝓝[<] b, DifferentiableAt ℝ f x) (hd₁ : ∀ᶠ x in 𝓝[>] b, DifferentiableAt ℝ f x) + (h₀ : ∀ᶠ x in 𝓝[<] b, 0 ≤ deriv f x) (h₁ : ∀ᶠ x in 𝓝[>] b, deriv f x ≤ 0) : + IsLocalMax f b := by + obtain ⟨a,ha⟩ := (nhdsWithin_Iio_basis' ⟨b - 1, sub_one_lt b⟩).eventually_iff.mp <| hd₀.and h₀ + obtain ⟨c,hc⟩ := (nhdsWithin_Ioi_basis' ⟨b + 1, lt_add_one b⟩).eventually_iff.mp <| hd₁.and h₁ + exact isLocalMax_of_deriv_Ioo ha.1 hc.1 h + (fun _ hx => (ha.2 hx).1.differentiableWithinAt) + (fun _ hx => (hc.2 hx).1.differentiableWithinAt) + (fun _ hx => (ha.2 hx).2) (fun x hx => (hc.2 hx).2) + + /-- The First-Derivative Test from calculus, minima version, + expressed in terms of left and right filters. -/ +lemma isLocalMin_of_deriv' {f : ℝ → ℝ} {b : ℝ} (h : ContinuousAt f b) + (hd₀ : ∀ᶠ x in 𝓝[<] b, DifferentiableAt ℝ f x) (hd₁ : ∀ᶠ x in 𝓝[>] b, DifferentiableAt ℝ f x) + (h₀ : ∀ᶠ x in 𝓝[<] b, deriv f x ≤ 0) (h₁ : ∀ᶠ x in 𝓝[>] b, deriv f x ≥ 0) : + IsLocalMin f b := by + obtain ⟨a,ha⟩ := (nhdsWithin_Iio_basis' ⟨b - 1, sub_one_lt b⟩).eventually_iff.mp <| hd₀.and h₀ + obtain ⟨c,hc⟩ := (nhdsWithin_Ioi_basis' ⟨b + 1, lt_add_one b⟩).eventually_iff.mp <| hd₁.and h₁ + exact isLocalMin_of_deriv_Ioo ha.1 hc.1 h + (fun _ hx => (ha.2 hx).1.differentiableWithinAt) + (fun _ hx => (hc.2 hx).1.differentiableWithinAt) + (fun _ hx => (ha.2 hx).2) (fun x hx => (hc.2 hx).2) + +/-- The First Derivative test, maximum version. -/ +theorem isLocalMax_of_deriv {f : ℝ → ℝ} {b : ℝ} (h : ContinuousAt f b) + (hd : ∀ᶠ x in 𝓝[≠] b, DifferentiableAt ℝ f x) + (h₀ : ∀ᶠ x in 𝓝[<] b, 0 ≤ deriv f x) (h₁ : ∀ᶠ x in 𝓝[>] b, deriv f x ≤ 0) : + IsLocalMax f b := + isLocalMax_of_deriv' h + (nhds_left'_le_nhds_ne _ (by tauto)) (nhds_right'_le_nhds_ne _ (by tauto)) h₀ h₁ + +/-- The First Derivative test, minimum version. -/ +theorem isLocalMin_of_deriv {f : ℝ → ℝ} {b : ℝ} (h : ContinuousAt f b) + (hd : ∀ᶠ x in 𝓝[≠] b, DifferentiableAt ℝ f x) + (h₀ : ∀ᶠ x in 𝓝[<] b, deriv f x ≤ 0) (h₁ : ∀ᶠ x in 𝓝[>] b, 0 ≤ deriv f x) : + IsLocalMin f b := + isLocalMin_of_deriv' h + (nhds_left'_le_nhds_ne _ (by tauto)) (nhds_right'_le_nhds_ne _ (by tauto)) h₀ h₁ diff --git a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean index 06d42a093e031..7de7ac1214369 100644 --- a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean +++ b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean @@ -360,21 +360,20 @@ def fpowerSeries (f : E →L[𝕜] F) (x : E) : FormalMultilinearSeries 𝕜 E F | 1 => (continuousMultilinearCurryFin1 𝕜 E F).symm f | _ => 0 +@[simp] theorem fpowerSeries_apply_zero (f : E →L[𝕜] F) (x : E) : f.fpowerSeries x 0 = ContinuousMultilinearMap.uncurry0 𝕜 _ (f x) := rfl +@[simp] theorem fpowerSeries_apply_one (f : E →L[𝕜] F) (x : E) : f.fpowerSeries x 1 = (continuousMultilinearCurryFin1 𝕜 E F).symm f := rfl +@[simp] theorem fpowerSeries_apply_add_two (f : E →L[𝕜] F) (x : E) (n : ℕ) : f.fpowerSeries x (n + 2) = 0 := rfl -attribute - [eqns fpowerSeries_apply_zero fpowerSeries_apply_one fpowerSeries_apply_add_two] fpowerSeries -attribute [simp] fpowerSeries - end ContinuousLinearMap end Linear diff --git a/Mathlib/Analysis/Calculus/Gradient/Basic.lean b/Mathlib/Analysis/Calculus/Gradient/Basic.lean index 558b091cb21ac..5ebf3d941d6a8 100644 --- a/Mathlib/Analysis/Calculus/Gradient/Basic.lean +++ b/Mathlib/Analysis/Calculus/Gradient/Basic.lean @@ -252,7 +252,7 @@ section congr /-! ### Congruence properties of the Gradient -/ -variable {f₀ f₁ : F → 𝕜} {f₀' f₁' : F} {x₀ x₁ : F} {s₀ s₁ t : Set F} {L₀ L₁ : Filter F} +variable {f₀ f₁ : F → 𝕜} {f₀' f₁' : F} {t : Set F} theorem Filter.EventuallyEq.hasGradientAtFilter_iff (h₀ : f₀ =ᶠ[L] f₁) (hx : f₀ x = f₁ x) (h₁ : f₀' = f₁') : HasGradientAtFilter f₀ f₀' x L ↔ HasGradientAtFilter f₁ f₁' x L := diff --git a/Mathlib/Analysis/Calculus/Implicit.lean b/Mathlib/Analysis/Calculus/Implicit.lean index 2e323d8872a82..01a204f86c4db 100644 --- a/Mathlib/Analysis/Calculus/Implicit.lean +++ b/Mathlib/Analysis/Calculus/Implicit.lean @@ -190,11 +190,7 @@ theorem implicitFunction_hasStrictFDerivAt (g'inv : G →L[𝕜] E) convert this.comp (φ.rightFun φ.pt) ((hasStrictFDerivAt_const _ _).prod (hasStrictFDerivAt_id _)) -- Porting note: added parentheses to help `simp` simp only [ContinuousLinearMap.ext_iff, (ContinuousLinearMap.comp_apply)] at hg'inv hg'invf ⊢ - -- porting note (#10745): was `simp [ContinuousLinearEquiv.eq_symm_apply]`; - -- both `simp` and `rw` fail here, `erw` works - intro x - erw [ContinuousLinearEquiv.eq_symm_apply] - simp [*] + simp [ContinuousLinearEquiv.eq_symm_apply, *] end ImplicitFunctionData diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean index 67b3db1e4cd80..b23236aaf0baf 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean @@ -52,8 +52,6 @@ noncomputable section variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] variable {ε : ℝ} open Filter Metric Set diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean index 43a83ae9b58a1..b77357845f02b 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean @@ -47,9 +47,6 @@ noncomputable section variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] -variable {ε : ℝ} open Asymptotics Filter Metric Set diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean index f5790c73a631f..9fcaa3d13a0cc 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean @@ -47,7 +47,6 @@ open Filter Asymptotics Set variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] /-- The `n`-th iterated derivative of a function from `𝕜` to `F`, as a function from `𝕜` to `F`. -/ def iteratedDeriv (n : ℕ) (f : 𝕜 → F) (x : 𝕜) : F := @@ -166,7 +165,7 @@ theorem iteratedDerivWithin_succ {x : 𝕜} (hxs : UniqueDiffWithinAt 𝕜 s x) rw [iteratedDerivWithin_eq_iteratedFDerivWithin, iteratedFDerivWithin_succ_apply_left, iteratedFDerivWithin_eq_equiv_comp, LinearIsometryEquiv.comp_fderivWithin _ hxs, derivWithin] change ((ContinuousMultilinearMap.mkPiRing 𝕜 (Fin n) ((fderivWithin 𝕜 - (iteratedDerivWithin n f s) s x : 𝕜 → F) 1) : (Fin n → 𝕜) → F) fun i : Fin n => 1) = + (iteratedDerivWithin n f s) s x : 𝕜 → F) 1) : (Fin n → 𝕜) → F) fun _ : Fin n => 1) = (fderivWithin 𝕜 (iteratedDerivWithin n f s) s x : 𝕜 → F) 1 simp diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean index 9b8588e207bce..0a4e4120acb15 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean @@ -15,6 +15,8 @@ This file contains a number of further results on `iteratedDerivWithin` that nee than are available in `Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean`. -/ +section one_dimensional + variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] @@ -123,3 +125,43 @@ lemma iteratedDeriv_comp_neg (n : ℕ) (f : 𝕜 → F) (a : 𝕜) : rw [iteratedDeriv_succ, iteratedDeriv_succ, ih', pow_succ', neg_mul, one_mul, deriv_comp_neg (f := fun x ↦ (-1 : 𝕜) ^ n • iteratedDeriv n f x), deriv_const_smul', neg_smul] + +open Topology in +lemma Filter.EventuallyEq.iteratedDeriv_eq (n : ℕ) {f g : 𝕜 → F} {x : 𝕜} (hfg : f =ᶠ[𝓝 x] g) : + iteratedDeriv n f x = iteratedDeriv n g x := by + simp only [← iteratedDerivWithin_univ, iteratedDerivWithin_eq_iteratedFDerivWithin] + rw [(hfg.filter_mono nhdsWithin_le_nhds).iteratedFDerivWithin_eq hfg.eq_of_nhds n] + +lemma Set.EqOn.iteratedDeriv_of_isOpen (hfg : Set.EqOn f g s) (hs : IsOpen s) (n : ℕ) : + Set.EqOn (iteratedDeriv n f) (iteratedDeriv n g) s := by + refine fun x hx ↦ Filter.EventuallyEq.iteratedDeriv_eq n ?_ + filter_upwards [IsOpen.mem_nhds hs hx] with a ha + exact hfg ha + +end one_dimensional + +/-! +### Invariance of iterated derivatives under translation +-/ + +section shift_invariance + +variable {𝕜 F} [NontriviallyNormedField 𝕜] [NormedAddCommGroup F] [NormedSpace 𝕜 F] + +/-- The iterated derivative commutes with shifting the function by a constant on the left. -/ +lemma iteratedDeriv_comp_const_add (n : ℕ) (f : 𝕜 → F) (s : 𝕜) : + iteratedDeriv n (fun z ↦ f (s + z)) = fun t ↦ iteratedDeriv n f (s + t) := by + induction n with + | zero => simp only [iteratedDeriv_zero] + | succ n IH => + simpa only [iteratedDeriv_succ, IH] using funext <| deriv_comp_const_add _ s + +/-- The iterated derivative commutes with shifting the function by a constant on the right. -/ +lemma iteratedDeriv_comp_add_const (n : ℕ) (f : 𝕜 → F) (s : 𝕜) : + iteratedDeriv n (fun z ↦ f (z + s)) = fun t ↦ iteratedDeriv n f (t + s) := by + induction n with + | zero => simp only [iteratedDeriv_zero] + | succ n IH => + simpa only [iteratedDeriv_succ, IH] using funext <| deriv_comp_add_const _ s + +end shift_invariance diff --git a/Mathlib/Analysis/Calculus/LHopital.lean b/Mathlib/Analysis/Calculus/LHopital.lean index 653749f47e528..f1e691d8342cf 100644 --- a/Mathlib/Analysis/Calculus/LHopital.lean +++ b/Mathlib/Analysis/Calculus/LHopital.lean @@ -143,7 +143,7 @@ theorem lhopital_zero_atTop_on_Ioi (hff' : ∀ x ∈ Ioi a, HasDerivAt f (f' x) ⟨lt_of_le_of_lt (le_max_left a 0) (lt_one_add _), lt_of_le_of_lt (le_max_right a 0) (lt_one_add _)⟩⟩ have fact1 : ∀ x : ℝ, x ∈ Ioo 0 a'⁻¹ → x ≠ 0 := fun _ hx => (ne_of_lt hx.1).symm - have fact2 : ∀ x ∈ Ioo 0 a'⁻¹, a < x⁻¹ := fun _ hx => lt_trans haa' ((lt_inv ha' hx.1).mpr hx.2) + have fact2 (x) (hx : x ∈ Ioo 0 a'⁻¹) : a < x⁻¹ := lt_trans haa' ((lt_inv_comm₀ ha' hx.1).mpr hx.2) have hdnf : ∀ x ∈ Ioo 0 a'⁻¹, HasDerivAt (f ∘ Inv.inv) (f' x⁻¹ * -(x ^ 2)⁻¹) x := fun x hx => comp x (hff' x⁻¹ <| fact2 x hx) (hasDerivAt_inv <| fact1 x hx) have hdng : ∀ x ∈ Ioo 0 a'⁻¹, HasDerivAt (g ∘ Inv.inv) (g' x⁻¹ * -(x ^ 2)⁻¹) x := fun x hx => @@ -161,7 +161,7 @@ theorem lhopital_zero_atTop_on_Ioi (hff' : ∀ x ∈ Ioi a, HasDerivAt f (f' x) intro x hx unfold Function.comp simp only - erw [mul_div_mul_right] + rw [mul_div_mul_right] exact neg_ne_zero.mpr (inv_ne_zero <| pow_ne_zero _ <| ne_of_gt hx)) have := this.comp tendsto_inv_atTop_zero' unfold Function.comp at this diff --git a/Mathlib/Analysis/Calculus/LagrangeMultipliers.lean b/Mathlib/Analysis/Calculus/LagrangeMultipliers.lean index faa6e1df7770b..64e2efb39c875 100644 --- a/Mathlib/Analysis/Calculus/LagrangeMultipliers.lean +++ b/Mathlib/Analysis/Calculus/LagrangeMultipliers.lean @@ -106,7 +106,7 @@ theorem IsLocalExtrOn.exists_multipliers_of_hasStrictFDerivAt {ι : Type*} [Fint ∃ (Λ : ι → ℝ) (Λ₀ : ℝ), (Λ, Λ₀) ≠ 0 ∧ (∑ i, Λ i • f' i) + Λ₀ • φ' = 0 := by letI := Classical.decEq ι replace hextr : IsLocalExtrOn φ {x | (fun i => f i x) = fun i => f i x₀} x₀ := by - simpa only [Function.funext_iff] using hextr + simpa only [funext_iff] using hextr rcases hextr.exists_linear_map_of_hasStrictFDerivAt (hasStrictFDerivAt_pi.2 fun i => hf' i) hφ' with ⟨Λ, Λ₀, h0, hsum⟩ @@ -132,5 +132,5 @@ theorem IsLocalExtrOn.linear_dependent_of_hasStrictFDerivAt {ι : Type*} [Finite rcases hextr.exists_multipliers_of_hasStrictFDerivAt hf' hφ' with ⟨Λ, Λ₀, hΛ, hΛf⟩ refine ⟨Option.elim' Λ₀ Λ, ?_, ?_⟩ · simpa [add_comm] using hΛf - · simpa only [Function.funext_iff, not_and_or, or_comm, Option.exists, Prod.mk_eq_zero, Ne, + · simpa only [funext_iff, not_and_or, or_comm, Option.exists, Prod.mk_eq_zero, Ne, not_forall] using hΛ diff --git a/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean b/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean index c3b79965c35ff..b675314ee9710 100644 --- a/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean @@ -176,7 +176,7 @@ theorem LineDifferentiableWithinAt.mono (h : LineDifferentiableWithinAt 𝕜 f t theorem HasLineDerivWithinAt.congr_mono (h : HasLineDerivWithinAt 𝕜 f f' s x v) (ht : EqOn f₁ f t) (hx : f₁ x = f x) (h₁ : t ⊆ s) : HasLineDerivWithinAt 𝕜 f₁ f' t x v := - HasDerivWithinAt.congr_mono h (fun y hy ↦ ht hy) (by simpa using hx) (preimage_mono h₁) + HasDerivWithinAt.congr_mono h (fun _ hy ↦ ht hy) (by simpa using hx) (preimage_mono h₁) theorem HasLineDerivWithinAt.congr (h : HasLineDerivWithinAt 𝕜 f f' s x v) (hs : EqOn f₁ f s) (hx : f₁ x = f x) : HasLineDerivWithinAt 𝕜 f₁ f' s x v := @@ -199,7 +199,7 @@ theorem LineDifferentiableWithinAt.congr (h : LineDifferentiableWithinAt 𝕜 f theorem lineDerivWithin_congr (hs : EqOn f₁ f s) (hx : f₁ x = f x) : lineDerivWithin 𝕜 f₁ s x v = lineDerivWithin 𝕜 f s x v := - derivWithin_congr (fun y hy ↦ hs hy) (by simpa using hx) + derivWithin_congr (fun _ hy ↦ hs hy) (by simpa using hx) theorem lineDerivWithin_congr' (hs : EqOn f₁ f s) (hx : x ∈ s) : lineDerivWithin 𝕜 f₁ s x v = lineDerivWithin 𝕜 f s x v := @@ -475,7 +475,7 @@ section CompRight variable {E : Type*} [AddCommGroup E] [Module 𝕜 E] {E' : Type*} [AddCommGroup E'] [Module 𝕜 E'] - {f : E → F} {f' : F} {x v : E'} {L : E' →ₗ[𝕜] E} + {f : E → F} {f' : F} {x : E'} {L : E' →ₗ[𝕜] E} theorem HasLineDerivAt.of_comp {v : E'} (hf : HasLineDerivAt 𝕜 (f ∘ L) f' x v) : HasLineDerivAt 𝕜 f f' (L x) (L v) := by diff --git a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean index 81863eb235bbc..21a62a2741891 100644 --- a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean +++ b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean @@ -130,7 +130,7 @@ theorem integral_bilinear_hasLineDerivAt_right_eq_neg_left_of_integrable -∫ (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] - have hL : ClosedEmbedding L.symm := L.symm.toHomeomorph.closedEmbedding + 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 diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean index 062cf3b3b7880..0713f40546373 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean @@ -59,14 +59,14 @@ theorem card_roots_le_derivative (p : ℝ[X]) : Multiset.card p.roots = ∑ x ∈ p.roots.toFinset, p.roots.count x := (Multiset.toFinset_sum_count_eq _).symm _ = ∑ x ∈ p.roots.toFinset, (p.roots.count x - 1 + 1) := - (Eq.symm <| Finset.sum_congr rfl fun x hx => tsub_add_cancel_of_le <| + (Eq.symm <| Finset.sum_congr rfl fun _ hx => tsub_add_cancel_of_le <| Nat.succ_le_iff.2 <| Multiset.count_pos.2 <| Multiset.mem_toFinset.1 hx) _ = (∑ x ∈ p.roots.toFinset, (p.rootMultiplicity x - 1)) + p.roots.toFinset.card := by simp only [Finset.sum_add_distrib, Finset.card_eq_sum_ones, count_roots] _ ≤ (∑ x ∈ p.roots.toFinset, p.derivative.rootMultiplicity x) + ((p.derivative.roots.toFinset \ p.roots.toFinset).card + 1) := (add_le_add - (Finset.sum_le_sum fun x _ => rootMultiplicity_sub_one_le_derivative_rootMultiplicity _ _) + (Finset.sum_le_sum fun _ _ => rootMultiplicity_sub_one_le_derivative_rootMultiplicity _ _) p.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ) _ ≤ (∑ x ∈ p.roots.toFinset, p.derivative.roots.count x) + ((∑ x ∈ p.derivative.roots.toFinset \ p.roots.toFinset, diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean b/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean index bd4dace2f8094..ef3e8f191d380 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Anatole Dedecker -/ import Mathlib.Analysis.Calculus.LocalExtr.Basic -import Mathlib.Topology.Algebra.Order.Rolle +import Mathlib.Topology.Order.Rolle /-! # Rolle's Theorem diff --git a/Mathlib/Analysis/Calculus/LogDeriv.lean b/Mathlib/Analysis/Calculus/LogDeriv.lean index 525cbcab01852..7b8a8970a06f3 100644 --- a/Mathlib/Analysis/Calculus/LogDeriv.lean +++ b/Mathlib/Analysis/Calculus/LogDeriv.lean @@ -17,7 +17,7 @@ noncomputable section open Filter Function -open scoped Topology BigOperators Classical +open scoped Topology Classical variable {𝕜 𝕜': Type*} [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] @@ -50,6 +50,13 @@ theorem logDeriv_mul {f g : 𝕜 → 𝕜'} (x : 𝕜) (hf : f x ≠ 0) (hg : g simp only [logDeriv_apply, deriv_mul hdf hdg] field_simp [mul_comm] +theorem logDeriv_div {f g : 𝕜 → 𝕜'} (x : 𝕜) (hf : f x ≠ 0) (hg : g x ≠ 0) + (hdf : DifferentiableAt 𝕜 f x) (hdg : DifferentiableAt 𝕜 g x) : + logDeriv (fun z => f z / g z) x = logDeriv f x - logDeriv g x := by + simp only [logDeriv_apply, deriv_div hdf hdg] + field_simp [mul_comm] + ring + theorem logDeriv_mul_const {f : 𝕜 → 𝕜'} (x : 𝕜) (a : 𝕜') (ha : a ≠ 0): logDeriv (fun z => f z * a) x = logDeriv f x := by simp only [logDeriv_apply, deriv_mul_const_field, mul_div_mul_right _ _ ha] @@ -102,4 +109,3 @@ theorem logDeriv_comp {f : 𝕜' → 𝕜'} {g : 𝕜 → 𝕜'} {x : 𝕜} (hf (hg : DifferentiableAt 𝕜 g x) : logDeriv (f ∘ g) x = logDeriv f (g x) * deriv g x := by simp only [logDeriv, Pi.div_apply, deriv.comp _ hf hg, comp_apply] ring - diff --git a/Mathlib/Analysis/Calculus/MeanValue.lean b/Mathlib/Analysis/Calculus/MeanValue.lean index 703da3c9d5c78..b386d402623c8 100644 --- a/Mathlib/Analysis/Calculus/MeanValue.lean +++ b/Mathlib/Analysis/Calculus/MeanValue.lean @@ -808,7 +808,7 @@ theorem not_differentiableWithinAt_of_deriv_tendsto_atTop_Ioi (f : ℝ → ℝ) exact differentiableWithinAt_of_derivWithin_ne_zero this have hcont_Ioc : ∀ z ∈ Ioc a b, ContinuousWithinAt f (Icc a b) z := by intro z hz'' - refine (hdiff'.continuousOn z hz'').mono_of_mem ?_ + refine (hdiff'.continuousOn z hz'').mono_of_mem_nhdsWithin ?_ have hfinal : 𝓝[Ioc a b] z = 𝓝[Icc a b] z := by refine nhdsWithin_eq_nhdsWithin' (s := Ioi a) (Ioi_mem_nhds hz''.1) ?_ simp only [Ioc_inter_Ioi, le_refl, sup_of_le_left] @@ -1039,14 +1039,14 @@ of the real line. If `f` is differentiable on the interior of `D` and `f'` is no lemma monotoneOn_of_hasDerivWithinAt_nonneg {D : Set ℝ} (hD : Convex ℝ D) {f f' : ℝ → ℝ} (hf : ContinuousOn f D) (hf' : ∀ x ∈ interior D, HasDerivWithinAt f (f' x) (interior D) x) (hf'₀ : ∀ x ∈ interior D, 0 ≤ f' x) : MonotoneOn f D := - monotoneOn_of_deriv_nonneg hD hf (fun x hx ↦ (hf' _ hx).differentiableWithinAt) fun x hx ↦ by + monotoneOn_of_deriv_nonneg hD hf (fun _ hx ↦ (hf' _ hx).differentiableWithinAt) fun x hx ↦ by rw [deriv_eqOn isOpen_interior hf' hx]; exact hf'₀ _ hx /-- Let `f : ℝ → ℝ` be a differentiable function. If `f'` is nonnegative, then `f` is a monotone function. -/ lemma monotone_of_hasDerivAt_nonneg {f f' : ℝ → ℝ} (hf : ∀ x, HasDerivAt f (f' x) x) (hf' : 0 ≤ f') : Monotone f := - monotone_of_deriv_nonneg (fun x ↦ (hf _).differentiableAt) fun x ↦ by + monotone_of_deriv_nonneg (fun _ ↦ (hf _).differentiableAt) fun x ↦ by rw [(hf _).deriv]; exact hf' _ /-- Let `f` be a function continuous on a convex (or, equivalently, connected) subset `D` @@ -1114,14 +1114,14 @@ of the real line. If `f` is differentiable on the interior of `D` and `f'` is no lemma antitoneOn_of_hasDerivWithinAt_nonpos {D : Set ℝ} (hD : Convex ℝ D) {f f' : ℝ → ℝ} (hf : ContinuousOn f D) (hf' : ∀ x ∈ interior D, HasDerivWithinAt f (f' x) (interior D) x) (hf'₀ : ∀ x ∈ interior D, f' x ≤ 0) : AntitoneOn f D := - antitoneOn_of_deriv_nonpos hD hf (fun x hx ↦ (hf' _ hx).differentiableWithinAt) fun x hx ↦ by + antitoneOn_of_deriv_nonpos hD hf (fun _ hx ↦ (hf' _ hx).differentiableWithinAt) fun x hx ↦ by rw [deriv_eqOn isOpen_interior hf' hx]; exact hf'₀ _ hx /-- Let `f : ℝ → ℝ` be a differentiable function. If `f'` is nonpositive, then `f` is an antitone function. -/ lemma antitone_of_hasDerivAt_nonpos {f f' : ℝ → ℝ} (hf : ∀ x, HasDerivAt f (f' x) x) (hf' : f' ≤ 0) : Antitone f := - antitone_of_deriv_nonpos (fun x ↦ (hf _).differentiableAt) fun x ↦ by + antitone_of_deriv_nonpos (fun _ ↦ (hf _).differentiableAt) fun x ↦ by rw [(hf _).deriv]; exact hf' _ /-! ### Functions `f : E → ℝ` -/ diff --git a/Mathlib/Analysis/Calculus/Rademacher.lean b/Mathlib/Analysis/Calculus/Rademacher.lean index 260a55686a38c..28ad0559741a1 100644 --- a/Mathlib/Analysis/Calculus/Rademacher.lean +++ b/Mathlib/Analysis/Calculus/Rademacher.lean @@ -298,7 +298,7 @@ theorem hasFderivAt_of_hasLineDerivAt_of_closure _ = ‖(f (x + ρ • w) - f (x + ρ • y)) + (ρ • L y - ρ • L w) + (f (x + ρ • y) - f x - ρ • L y)‖ := by congr; abel _ ≤ ‖f (x + ρ • w) - f (x + ρ • y)‖ + ‖ρ • L y - ρ • L w‖ - + ‖f (x + ρ • y) - f x - ρ • L y‖ := norm_add₃_le _ _ _ + + ‖f (x + ρ • y) - f x - ρ • L y‖ := norm_add₃_le _ ≤ C * ‖(x + ρ • w) - (x + ρ • y)‖ + ρ * (‖L‖ * ‖y - w‖) + δ * ρ := by gcongr · exact hf.norm_sub_le _ _ @@ -386,3 +386,18 @@ theorem LipschitzWith.ae_differentiableAt {f : E → F} (h : LipschitzWith C f) ∀ᵐ x ∂μ, DifferentiableAt ℝ f x := by rw [← lipschitzOnWith_univ] at h simpa [differentiableWithinAt_univ] using h.ae_differentiableWithinAt_of_mem + +/-- In a real finite-dimensional normed vector space, + the norm is almost everywhere differentiable. -/ +theorem ae_differentiableAt_norm : + ∀ᵐ x ∂μ, DifferentiableAt ℝ (‖·‖) x := lipschitzWith_one_norm.ae_differentiableAt + +omit [MeasurableSpace E] in +/-- In a real finite-dimensional normed vector space, + the set of points where the norm is differentiable at is dense. -/ +theorem dense_differentiableAt_norm : + Dense {x : E | DifferentiableAt ℝ (‖·‖) x} := + let _ : MeasurableSpace E := borel E + have _ : BorelSpace E := ⟨rfl⟩ + let w := Basis.ofVectorSpace ℝ E + MeasureTheory.Measure.dense_of_ae (ae_differentiableAt_norm (μ := w.addHaar)) diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index 53b15bc072b28..f3ac765b70a30 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -81,7 +81,7 @@ theorem mem_tangentConeAt_of_pow_smul {r : 𝕜} (hr₀ : r ≠ 0) (hr : ‖r‖ (hs : ∀ᶠ n : ℕ in atTop, x + r ^ n • y ∈ s) : y ∈ tangentConeAt 𝕜 s x := by refine ⟨fun n ↦ (r ^ n)⁻¹, fun n ↦ r ^ n • y, hs, ?_, ?_⟩ · simp only [norm_inv, norm_pow, ← inv_pow] - exact tendsto_pow_atTop_atTop_of_one_lt <| one_lt_inv (norm_pos_iff.2 hr₀) hr + exact tendsto_pow_atTop_atTop_of_one_lt <| (one_lt_inv₀ (norm_pos_iff.2 hr₀)).2 hr · simp only [inv_smul_smul₀ (pow_ne_zero _ hr₀), tendsto_const_nhds] theorem tangentCone_univ : tangentConeAt 𝕜 univ x = univ := diff --git a/Mathlib/Analysis/Complex/AbelLimit.lean b/Mathlib/Analysis/Complex/AbelLimit.lean index 167aa0434d806..25d7f649514c6 100644 --- a/Mathlib/Analysis/Complex/AbelLimit.lean +++ b/Mathlib/Analysis/Complex/AbelLimit.lean @@ -6,6 +6,7 @@ Authors: Jeremy Tan import Mathlib.Analysis.Complex.Basic import Mathlib.Analysis.SpecificLimits.Normed import Mathlib.Tactic.Peel +import Mathlib.Tactic.Positivity.Finset /-! # Abel's limit theorem @@ -55,9 +56,9 @@ theorem stolzSet_empty {M : ℝ} (hM : M ≤ 1) : stolzSet M = ∅ := by _ ≤ _ := norm_sub_norm_le _ _ theorem nhdsWithin_lt_le_nhdsWithin_stolzSet {M : ℝ} (hM : 1 < M) : - (𝓝[<] 1).map ofReal' ≤ 𝓝[stolzSet M] 1 := by + (𝓝[<] 1).map ofReal ≤ 𝓝[stolzSet M] 1 := by rw [← tendsto_id'] - refine tendsto_map' <| tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within ofReal' + refine tendsto_map' <| tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within ofReal (tendsto_nhdsWithin_of_tendsto_nhds <| ofRealCLM.continuous.tendsto' 1 1 rfl) ?_ simp only [eventually_iff, norm_eq_abs, abs_ofReal, abs_lt, mem_nhdsWithin] refine ⟨Set.Ioo 0 2, isOpen_Ioo, by norm_num, fun x hx ↦ ?_⟩ @@ -241,7 +242,7 @@ theorem tendsto_tsum_powerSeries_nhdsWithin_stolzCone theorem tendsto_tsum_powerSeries_nhdsWithin_lt (h : Tendsto (fun n ↦ ∑ i ∈ range n, f i) atTop (𝓝 l)) : - Tendsto (fun z ↦ ∑' n, f n * z ^ n) ((𝓝[<] 1).map ofReal') (𝓝 l) := + Tendsto (fun z ↦ ∑' n, f n * z ^ n) ((𝓝[<] 1).map ofReal) (𝓝 l) := (tendsto_tsum_powerSeries_nhdsWithin_stolzSet (M := 2) h).mono_left (nhdsWithin_lt_le_nhdsWithin_stolzSet one_lt_two) @@ -258,7 +259,7 @@ is continuous at 1 when approaching 1 from the left. -/ theorem tendsto_tsum_powerSeries_nhdsWithin_lt (h : Tendsto (fun n ↦ ∑ i ∈ range n, f i) atTop (𝓝 l)) : Tendsto (fun x ↦ ∑' n, f n * x ^ n) (𝓝[<] 1) (𝓝 l) := by - have m : (𝓝 l).map ofReal' ≤ 𝓝 ↑l := ofRealCLM.continuous.tendsto l + have m : (𝓝 l).map ofReal ≤ 𝓝 ↑l := ofRealCLM.continuous.tendsto l replace h := (tendsto_map.comp h).mono_right m rw [Function.comp_def] at h push_cast at h diff --git a/Mathlib/Analysis/Complex/Basic.lean b/Mathlib/Analysis/Complex/Basic.lean index b2b77580329f5..eefdc2d5f0b00 100644 --- a/Mathlib/Analysis/Complex/Basic.lean +++ b/Mathlib/Analysis/Complex/Basic.lean @@ -358,12 +358,19 @@ theorem isometry_ofReal : Isometry ((↑) : ℝ → ℂ) := theorem continuous_ofReal : Continuous ((↑) : ℝ → ℂ) := ofRealLI.continuous +theorem isUniformEmbedding_ofReal : IsUniformEmbedding ((↑) : ℝ → ℂ) := + ofRealLI.isometry.isUniformEmbedding + +theorem _root_.Filter.tendsto_ofReal_iff {α : Type*} {l : Filter α} {f : α → ℝ} {x : ℝ} : + Tendsto (fun x ↦ (f x : ℂ)) l (𝓝 (x : ℂ)) ↔ Tendsto f l (𝓝 x) := + isUniformEmbedding_ofReal.toIsClosedEmbedding.tendsto_nhds_iff.symm + lemma _root_.Filter.Tendsto.ofReal {α : Type*} {l : Filter α} {f : α → ℝ} {x : ℝ} (hf : Tendsto f l (𝓝 x)) : Tendsto (fun x ↦ (f x : ℂ)) l (𝓝 (x : ℂ)) := - (continuous_ofReal.tendsto _).comp hf + tendsto_ofReal_iff.mpr hf /-- The only continuous ring homomorphism from `ℝ` to `ℂ` is the identity. -/ -theorem ringHom_eq_ofReal_of_continuous {f : ℝ →+* ℂ} (h : Continuous f) : f = Complex.ofReal := by +theorem ringHom_eq_ofReal_of_continuous {f : ℝ →+* ℂ} (h : Continuous f) : f = ofRealHom := by convert congr_arg AlgHom.toRingHom <| Subsingleton.elim (AlgHom.mk' f <| map_real_smul f h) (Algebra.ofId ℝ ℂ) @@ -598,10 +605,10 @@ theorem ofReal_tsum (f : α → ℝ) : (↑(∑' a, f a) : ℂ) = ∑' a, ↑(f RCLike.ofReal_tsum _ _ theorem hasSum_re {f : α → ℂ} {x : ℂ} (h : HasSum f x) : HasSum (fun x => (f x).re) x.re := - RCLike.hasSum_re _ h + RCLike.hasSum_re ℂ h theorem hasSum_im {f : α → ℂ} {x : ℂ} (h : HasSum f x) : HasSum (fun x => (f x).im) x.im := - RCLike.hasSum_im _ h + RCLike.hasSum_im ℂ h theorem re_tsum {f : α → ℂ} (h : Summable f) : (∑' a, f a).re = ∑' a, (f a).re := RCLike.re_tsum _ h diff --git a/Mathlib/Analysis/Complex/Conformal.lean b/Mathlib/Analysis/Complex/Conformal.lean index 9c3c4ee064bd1..2163c30f6ec46 100644 --- a/Mathlib/Analysis/Complex/Conformal.lean +++ b/Mathlib/Analysis/Complex/Conformal.lean @@ -41,8 +41,7 @@ theorem isConformalMap_conj : IsConformalMap (conjLIE : ℂ →L[ℝ] ℂ) := section ConformalIntoComplexNormed -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [NormedSpace ℂ E] {z : ℂ} - {g : ℂ →L[ℝ] E} {f : ℂ → E} +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [NormedSpace ℂ E] theorem isConformalMap_complex_linear {map : ℂ →L[ℂ] E} (nonzero : map ≠ 0) : IsConformalMap (map.restrictScalars ℝ) := by @@ -70,7 +69,7 @@ section ConformalIntoComplexPlane open ContinuousLinearMap -variable {f : ℂ → ℂ} {z : ℂ} {g : ℂ →L[ℝ] ℂ} +variable {g : ℂ →L[ℝ] ℂ} theorem IsConformalMap.is_complex_or_conj_linear (h : IsConformalMap g) : (∃ map : ℂ →L[ℂ] ℂ, map.restrictScalars ℝ = g) ∨ diff --git a/Mathlib/Analysis/Complex/OpenMapping.lean b/Mathlib/Analysis/Complex/OpenMapping.lean index c37d82d1058c9..b926e8a60be91 100644 --- a/Mathlib/Analysis/Complex/OpenMapping.lean +++ b/Mathlib/Analysis/Complex/OpenMapping.lean @@ -36,7 +36,7 @@ open Set Filter Metric Complex open scoped Topology variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {U : Set E} {f : ℂ → ℂ} {g : E → ℂ} - {z₀ w : ℂ} {ε r m : ℝ} + {z₀ : ℂ} {ε r : ℝ} /-- If the modulus of a holomorphic function `f` is bounded below by `ε` on a circle, then its range contains a disk of radius `ε / 2`. -/ diff --git a/Mathlib/Analysis/Complex/Positivity.lean b/Mathlib/Analysis/Complex/Positivity.lean new file mode 100644 index 0000000000000..140e3a84386ff --- /dev/null +++ b/Mathlib/Analysis/Complex/Positivity.lean @@ -0,0 +1,81 @@ +/- +Copyright (c) 2024 Michael Stoll. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Stoll +-/ +import Mathlib.Analysis.Complex.TaylorSeries + +/-! +# Nonnegativity of values of holomorphic functions + +We show that if `f` is holomorphic on an open disk `B(c,r)` and all iterated derivatives of `f` +at `c` are nonnegative real, then `f z ≥ 0` for all `z ≥ c` in the disk; see +`DifferentiableOn.nonneg_of_iteratedDeriv_nonneg`. We also provide a +variant `Differentiable.nonneg_of_iteratedDeriv_nonneg` for entire functions and versions +showing `f z ≥ f c` when all iterated derivatives except `f` itseld are nonnegative. +-/ + +open Complex + +open scoped ComplexOrder + +namespace DifferentiableOn + +/-- A function that is holomorphic on the open disk around `c` with radius `r` and whose iterated +derivatives at `c` are all nonnegative real has nonnegative real values on `c + [0,r)`. -/ +theorem nonneg_of_iteratedDeriv_nonneg {f : ℂ → ℂ} {c : ℂ} {r : ℝ} + (hf : DifferentiableOn ℂ f (Metric.ball c r)) (h : ∀ n, 0 ≤ iteratedDeriv n f c) ⦃z : ℂ⦄ + (hz₁ : c ≤ z) (hz₂ : z ∈ Metric.ball c r): + 0 ≤ f z := by + have H := taylorSeries_eq_on_ball' hz₂ hf + rw [← sub_nonneg] at hz₁ + have hz' := eq_re_of_ofReal_le hz₁ + rw [hz'] at hz₁ H + refine H ▸ tsum_nonneg fun n ↦ ?_ + rw [← ofReal_natCast, ← ofReal_pow, ← ofReal_inv, eq_re_of_ofReal_le (h n), ← ofReal_mul, + ← ofReal_mul] + norm_cast at hz₁ ⊢ + have := zero_re ▸ (Complex.le_def.mp (h n)).1 + positivity + +end DifferentiableOn + +namespace Differentiable + +/-- An entire function whose iterated derivatives at `c` are all nonnegative real has nonnegative +real values on `c + ℝ≥0`. -/ +theorem nonneg_of_iteratedDeriv_nonneg {f : ℂ → ℂ} (hf : Differentiable ℂ f) {c : ℂ} + (h : ∀ n, 0 ≤ iteratedDeriv n f c) ⦃z : ℂ⦄ (hz : c ≤ z) : + 0 ≤ f z := by + refine hf.differentiableOn.nonneg_of_iteratedDeriv_nonneg (r := (z - c).re + 1) h hz ?_ + rw [← sub_nonneg] at hz + rw [Metric.mem_ball, dist_eq, eq_re_of_ofReal_le hz] + simpa only [Complex.abs_of_nonneg (nonneg_iff.mp hz).1] using lt_add_one _ + +/-- An entire function whose iterated derivatives at `c` are all nonnegative real (except +possibly the value itself) has values of the form `f c + nonneg. real` on the set `c + ℝ≥0`. -/ +theorem apply_le_of_iteratedDeriv_nonneg {f : ℂ → ℂ} {c : ℂ} (hf : Differentiable ℂ f) + (h : ∀ n ≠ 0, 0 ≤ iteratedDeriv n f c) ⦃z : ℂ⦄ (hz : c ≤ z) : + f c ≤ f z := by + have h' (n : ℕ) : 0 ≤ iteratedDeriv n (f · - f c) c := by + cases n with + | zero => simp only [iteratedDeriv_zero, sub_self, le_refl] + | succ n => + specialize h (n + 1) n.succ_ne_zero + rw [iteratedDeriv_succ'] at h ⊢ + rwa [funext fun x ↦ deriv_sub_const (f := f) (x := x) (f c)] + exact sub_nonneg.mp <| nonneg_of_iteratedDeriv_nonneg (hf.sub_const _) h' hz + +/-- An entire function whose iterated derivatives at `c` are all real with alternating signs +(except possibly the value itself) has values of the form `f c + nonneg. real` along the +set `c - ℝ≥0`. -/ +theorem apply_le_of_iteratedDeriv_alternating {f : ℂ → ℂ} {c : ℂ} (hf : Differentiable ℂ f) + (h : ∀ n ≠ 0, 0 ≤ (-1) ^ n * iteratedDeriv n f c) ⦃z : ℂ⦄ (hz : z ≤ c) : + f c ≤ f z := by + convert apply_le_of_iteratedDeriv_nonneg (f := fun z ↦ f (-z)) + (hf.comp <| differentiable_neg) (fun n hn ↦ ?_) (neg_le_neg_iff.mpr hz) using 1 + · simp only [neg_neg] + · simp only [neg_neg] + · simpa only [iteratedDeriv_comp_neg, neg_neg, smul_eq_mul] using h n hn + +end Differentiable diff --git a/Mathlib/Analysis/Complex/ReImTopology.lean b/Mathlib/Analysis/Complex/ReImTopology.lean index b9eac29a030c2..b157ee0e81a04 100644 --- a/Mathlib/Analysis/Complex/ReImTopology.lean +++ b/Mathlib/Analysis/Complex/ReImTopology.lean @@ -18,7 +18,7 @@ Each statement about `Complex.re` listed below has a counterpart about `Complex. * `Complex.isHomeomorphicTrivialFiberBundle_re`: `Complex.re` turns `ℂ` into a trivial topological fiber bundle over `ℝ`; -* `Complex.isOpenMap_re`, `Complex.quotientMap_re`: in particular, `Complex.re` is an open map +* `Complex.isOpenMap_re`, `Complex.isQuotientMap_re`: in particular, `Complex.re` is an open map and is a quotient map; * `Complex.interior_preimage_re`, `Complex.closure_preimage_re`, `Complex.frontier_preimage_re`: formulas for `interior (Complex.re ⁻¹' s)` etc; @@ -52,11 +52,17 @@ theorem isOpenMap_re : IsOpenMap re := theorem isOpenMap_im : IsOpenMap im := isHomeomorphicTrivialFiberBundle_im.isOpenMap_proj -theorem quotientMap_re : QuotientMap re := - isHomeomorphicTrivialFiberBundle_re.quotientMap_proj +theorem isQuotientMap_re : IsQuotientMap re := + isHomeomorphicTrivialFiberBundle_re.isQuotientMap_proj -theorem quotientMap_im : QuotientMap im := - isHomeomorphicTrivialFiberBundle_im.quotientMap_proj +@[deprecated (since := "2024-10-22")] +alias quotientMap_re := isQuotientMap_re + +theorem isQuotientMap_im : IsQuotientMap im := + isHomeomorphicTrivialFiberBundle_im.isQuotientMap_proj + +@[deprecated (since := "2024-10-22")] +alias quotientMap_im := isQuotientMap_im theorem interior_preimage_re (s : Set ℝ) : interior (re ⁻¹' s) = re ⁻¹' interior s := (isOpenMap_re.preimage_interior_eq_interior_preimage continuous_re _).symm diff --git a/Mathlib/Analysis/Complex/RemovableSingularity.lean b/Mathlib/Analysis/Complex/RemovableSingularity.lean index 9702422a17c49..b6d73c9132378 100644 --- a/Mathlib/Analysis/Complex/RemovableSingularity.lean +++ b/Mathlib/Analysis/Complex/RemovableSingularity.lean @@ -48,7 +48,7 @@ theorem differentiableOn_compl_singleton_and_continuousAt_iff {f : ℂ → E} {s rcases eq_or_ne x c with (rfl | hne) · refine (analyticAt_of_differentiable_on_punctured_nhds_of_continuousAt ?_ hc).differentiableAt.differentiableWithinAt - refine eventually_nhdsWithin_iff.2 ((eventually_mem_nhds.2 hs).mono fun z hz hzx => ?_) + refine eventually_nhdsWithin_iff.2 ((eventually_mem_nhds_iff.2 hs).mono fun z hz hzx => ?_) exact hd.differentiableAt (inter_mem hz (isOpen_ne.mem_nhds hzx)) · simpa only [DifferentiableWithinAt, HasFDerivWithinAt, hne.nhdsWithin_diff_singleton] using hd x ⟨hx, hne⟩ diff --git a/Mathlib/Analysis/Complex/Schwarz.lean b/Mathlib/Analysis/Complex/Schwarz.lean index 4c91fb9c0f890..9b43623115be1 100644 --- a/Mathlib/Analysis/Complex/Schwarz.lean +++ b/Mathlib/Analysis/Complex/Schwarz.lean @@ -56,7 +56,7 @@ namespace Complex section Space -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {R R₁ R₂ : ℝ} {f : ℂ → E} +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {R₁ R₂ : ℝ} {f : ℂ → E} {c z z₀ : ℂ} /-- An auxiliary lemma for `Complex.norm_dslope_le_div_of_mapsTo_ball`. -/ diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean index f9c084804d861..303996fd5e2dd 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean @@ -400,7 +400,7 @@ section PosRealAction instance posRealAction : MulAction { x : ℝ // 0 < x } ℍ where smul x z := mk ((x : ℝ) • (z : ℂ)) <| by simpa using mul_pos x.2 z.2 - one_smul z := Subtype.ext <| one_smul _ _ + one_smul _ := Subtype.ext <| one_smul _ _ mul_smul x y z := Subtype.ext <| mul_smul (x : ℝ) y (z : ℂ) variable (x : { x : ℝ // 0 < x }) (z : ℍ) diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean index f3d8eacb2243d..aede75f666ab9 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ import Mathlib.Analysis.Complex.UpperHalfPlane.Topology +import Mathlib.Geometry.Manifold.ContMDiff.Atlas import Mathlib.Geometry.Manifold.MFDeriv.Basic /-! @@ -18,10 +19,10 @@ open scoped UpperHalfPlane Manifold namespace UpperHalfPlane noncomputable instance : ChartedSpace ℂ ℍ := - UpperHalfPlane.openEmbedding_coe.singletonChartedSpace + UpperHalfPlane.isOpenEmbedding_coe.singletonChartedSpace instance : SmoothManifoldWithCorners 𝓘(ℂ) ℍ := - UpperHalfPlane.openEmbedding_coe.singleton_smoothManifoldWithCorners 𝓘(ℂ) + UpperHalfPlane.isOpenEmbedding_coe.singleton_smoothManifoldWithCorners /-- The inclusion map `ℍ → ℂ` is a smooth map of manifolds. -/ theorem smooth_coe : Smooth 𝓘(ℂ) 𝓘(ℂ) ((↑) : ℍ → ℂ) := fun _ => contMDiffAt_extChartAt diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean index 256120e306349..be1afc071e685 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean @@ -29,7 +29,7 @@ open scoped UpperHalfPlane ComplexConjugate NNReal Topology MatrixGroups open Set Metric Filter Real -variable {z w : ℍ} {r R : ℝ} +variable {z w : ℍ} {r : ℝ} namespace UpperHalfPlane @@ -300,7 +300,7 @@ theorem image_coe_sphere (z : ℍ) (r : ℝ) : instance : ProperSpace ℍ := by refine ⟨fun z r => ?_⟩ - rw [inducing_subtype_val.isCompact_iff (f := ((↑) : ℍ → ℂ)), image_coe_closedBall] + rw [IsInducing.subtypeVal.isCompact_iff (f := ((↑) : ℍ → ℂ)), image_coe_closedBall] apply isCompact_closedBall theorem isometry_vertical_line (a : ℝ) : Isometry fun y => mk ⟨a, exp y⟩ (exp_pos y) := by diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean index 3c32e2e099f23..c2fe2e71fcdfa 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean @@ -30,14 +30,20 @@ namespace UpperHalfPlane instance : TopologicalSpace ℍ := instTopologicalSpaceSubtype -theorem openEmbedding_coe : OpenEmbedding ((↑) : ℍ → ℂ) := - IsOpen.openEmbedding_subtype_val <| isOpen_lt continuous_const Complex.continuous_im +theorem isOpenEmbedding_coe : IsOpenEmbedding ((↑) : ℍ → ℂ) := + IsOpen.isOpenEmbedding_subtypeVal <| isOpen_lt continuous_const Complex.continuous_im -theorem embedding_coe : Embedding ((↑) : ℍ → ℂ) := - embedding_subtype_val +@[deprecated (since := "2024-10-18")] +alias openEmbedding_coe := isOpenEmbedding_coe + +theorem isEmbedding_coe : IsEmbedding ((↑) : ℍ → ℂ) := + IsEmbedding.subtypeVal + +@[deprecated (since := "2024-10-26")] +alias embedding_coe := isEmbedding_coe theorem continuous_coe : Continuous ((↑) : ℍ → ℂ) := - embedding_coe.continuous + isEmbedding_coe.continuous theorem continuous_re : Continuous re := Complex.continuous_re.comp continuous_coe @@ -55,8 +61,7 @@ instance : T4Space ℍ := inferInstance instance : ContractibleSpace ℍ := (convex_halfspace_im_gt 0).contractibleSpace ⟨I, one_pos.trans_eq I_im.symm⟩ -instance : LocPathConnectedSpace ℍ := - locPathConnected_of_isOpen <| isOpen_lt continuous_const Complex.continuous_im +instance : LocPathConnectedSpace ℍ := isOpenEmbedding_coe.locPathConnectedSpace instance : NoncompactSpace ℍ := by refine ⟨fun h => ?_⟩ @@ -66,7 +71,7 @@ instance : NoncompactSpace ℍ := by exact absurd ((this 0).1 (@left_mem_Ici ℝ _ 0)) (@lt_irrefl ℝ _ 0) instance : LocallyCompactSpace ℍ := - openEmbedding_coe.locallyCompactSpace + isOpenEmbedding_coe.locallyCompactSpace section strips @@ -119,13 +124,13 @@ theorem ModularGroup_T_zpow_mem_verticalStrip (z : ℍ) {N : ℕ} (hn : 0 < N) : end strips /-- A continuous section `ℂ → ℍ` of the natural inclusion map, bundled as a `PartialHomeomorph`. -/ -def ofComplex : PartialHomeomorph ℂ ℍ := (openEmbedding_coe.toPartialHomeomorph _).symm +def ofComplex : PartialHomeomorph ℂ ℍ := (isOpenEmbedding_coe.toPartialHomeomorph _).symm /-- Extend a function on `ℍ` arbitrarily to a function on all of `ℂ`. -/ scoped notation "↑ₕ" f => f ∘ ofComplex lemma ofComplex_apply (z : ℍ) : ofComplex (z : ℂ) = z := - OpenEmbedding.toPartialHomeomorph_left_inv .. + IsOpenEmbedding.toPartialHomeomorph_left_inv .. lemma ofComplex_apply_eq_ite (w : ℂ) : ofComplex w = if hw : 0 < w.im then ⟨w, hw⟩ else Classical.choice inferInstance := by diff --git a/Mathlib/Analysis/Convex/Basic.lean b/Mathlib/Analysis/Convex/Basic.lean index 1eb8cdb030baa..4f249aa4e3023 100644 --- a/Mathlib/Analysis/Convex/Basic.lean +++ b/Mathlib/Analysis/Convex/Basic.lean @@ -76,7 +76,7 @@ theorem convex_iff_pointwise_add_subset : (by rintro hA a b ha hb hab w ⟨au, ⟨u, hu, rfl⟩, bv, ⟨v, hv, rfl⟩, rfl⟩ exact hA hu hv ha hb hab) - fun h x hx y hy a b ha hb hab => (h ha hb hab) (Set.add_mem_add ⟨_, hx, rfl⟩ ⟨_, hy, rfl⟩) + fun h _ hx _ hy _ _ ha hb hab => (h ha hb hab) (Set.add_mem_add ⟨_, hx, rfl⟩ ⟨_, hy, rfl⟩) alias ⟨Convex.set_combo_subset, _⟩ := convex_iff_pointwise_add_subset @@ -505,7 +505,8 @@ theorem convex_iff_div : theorem Convex.mem_smul_of_zero_mem (h : Convex 𝕜 s) {x : E} (zero_mem : (0 : E) ∈ s) (hx : x ∈ s) {t : 𝕜} (ht : 1 ≤ t) : x ∈ t • s := by rw [mem_smul_set_iff_inv_smul_mem₀ (zero_lt_one.trans_le ht).ne'] - exact h.smul_mem_of_zero_mem zero_mem hx ⟨inv_nonneg.2 (zero_le_one.trans ht), inv_le_one ht⟩ + exact h.smul_mem_of_zero_mem zero_mem hx + ⟨inv_nonneg.2 (zero_le_one.trans ht), inv_le_one_of_one_le₀ ht⟩ theorem Convex.exists_mem_add_smul_eq (h : Convex 𝕜 s) {x y : E} {p q : 𝕜} (hx : x ∈ s) (hy : y ∈ s) (hp : 0 ≤ p) (hq : 0 ≤ q) : ∃ z ∈ s, (p + q) • z = p • x + q • y := by @@ -604,7 +605,8 @@ theorem convex_stdSimplex : Convex 𝕜 (stdSimplex 𝕜 ι) := by lemma stdSimplex_of_isEmpty_index [IsEmpty ι] [Nontrivial 𝕜] : stdSimplex 𝕜 ι = ∅ := eq_empty_of_forall_not_mem <| by rintro f ⟨-, hf⟩; simp at hf -lemma stdSimplex_unique [Unique ι] : stdSimplex 𝕜 ι = {fun _ ↦ 1} := by +lemma stdSimplex_unique [Nonempty ι] [Subsingleton ι] : stdSimplex 𝕜 ι = {fun _ ↦ 1} := by + cases nonempty_unique ι refine eq_singleton_iff_unique_mem.2 ⟨⟨fun _ ↦ zero_le_one, Fintype.sum_unique _⟩, ?_⟩ rintro f ⟨-, hf⟩ rw [Fintype.sum_unique] at hf @@ -653,7 +655,7 @@ def stdSimplexEquivIcc : stdSimplex 𝕜 (Fin 2) ≃ Icc (0 : 𝕜) 1 where calc (1 : 𝕜) - f.1 0 = f.1 0 + f.1 1 - f.1 0 := by rw [← Fin.sum_univ_two f.1, f.2.2] _ = f.1 1 := add_sub_cancel_left _ _ - right_inv x := Subtype.eq rfl + right_inv _ := Subtype.eq rfl end OrderedRing diff --git a/Mathlib/Analysis/Convex/Between.lean b/Mathlib/Analysis/Convex/Between.lean index 69429999e97e5..d1be44a83c178 100644 --- a/Mathlib/Analysis/Convex/Between.lean +++ b/Mathlib/Analysis/Convex/Between.lean @@ -5,6 +5,7 @@ Authors: Joseph Myers -/ import Mathlib.Algebra.CharP.Invertible import Mathlib.Algebra.Order.Interval.Set.Group +import Mathlib.Analysis.Convex.Basic import Mathlib.Analysis.Convex.Segment import Mathlib.LinearAlgebra.AffineSpace.FiniteDimensional import Mathlib.Tactic.FieldSimp @@ -128,6 +129,14 @@ variable {R} lemma mem_segment_iff_wbtw {x y z : V} : y ∈ segment R x z ↔ Wbtw R x y z := by rw [Wbtw, affineSegment_eq_segment] +alias ⟨_, Wbtw.mem_segment⟩ := mem_segment_iff_wbtw + +lemma Convex.mem_of_wbtw {p₀ p₁ p₂ : V} {s : Set V} (hs : Convex R s) (h₀₁₂ : Wbtw R p₀ p₁ p₂) + (h₀ : p₀ ∈ s) (h₂ : p₂ ∈ s) : p₁ ∈ s := hs.segment_subset h₀ h₂ h₀₁₂.mem_segment + +lemma AffineSubspace.mem_of_wbtw {s : AffineSubspace R P} {x y z : P} (hxyz : Wbtw R x y z) + (hx : x ∈ s) (hz : z ∈ s) : y ∈ s := by obtain ⟨ε, -, rfl⟩ := hxyz; exact lineMap_mem _ hx hz + theorem Wbtw.map {x y z : P} (h : Wbtw R x y z) (f : P →ᵃ[R] P') : Wbtw R (f x) (f y) (f z) := by rw [Wbtw, ← affineSegment_image] exact Set.mem_image_of_mem _ h @@ -574,7 +583,7 @@ end LinearOrderedRing section LinearOrderedField -variable [LinearOrderedField R] [AddCommGroup V] [Module R V] [AddTorsor V P] +variable [LinearOrderedField R] [AddCommGroup V] [Module R V] [AddTorsor V P] {x y z : P} variable {R} theorem wbtw_iff_left_eq_or_right_mem_image_Ici {x y z : P} : @@ -583,14 +592,14 @@ theorem wbtw_iff_left_eq_or_right_mem_image_Ici {x y z : P} : · rcases h with ⟨r, ⟨hr0, hr1⟩, rfl⟩ rcases hr0.lt_or_eq with (hr0' | rfl) · rw [Set.mem_image] - refine Or.inr ⟨r⁻¹, one_le_inv hr0' hr1, ?_⟩ + refine .inr ⟨r⁻¹, (one_le_inv₀ hr0').2 hr1, ?_⟩ simp only [lineMap_apply, smul_smul, vadd_vsub] rw [inv_mul_cancel₀ hr0'.ne', one_smul, vsub_vadd] · simp · rcases h with (rfl | ⟨r, ⟨hr, rfl⟩⟩) · exact wbtw_self_left _ _ _ · rw [Set.mem_Ici] at hr - refine ⟨r⁻¹, ⟨inv_nonneg.2 (zero_le_one.trans hr), inv_le_one hr⟩, ?_⟩ + refine ⟨r⁻¹, ⟨inv_nonneg.2 (zero_le_one.trans hr), inv_le_one_of_one_le₀ hr⟩, ?_⟩ simp only [lineMap_apply, smul_smul, vadd_vsub] rw [inv_mul_cancel₀ (one_pos.trans_le hr).ne', one_smul, vsub_vadd] @@ -653,6 +662,12 @@ theorem Sbtw.left_mem_image_Ioi {x y z : P} (h : Sbtw R x y z) : theorem Sbtw.left_mem_affineSpan {x y z : P} (h : Sbtw R x y z) : x ∈ line[R, z, y] := h.symm.right_mem_affineSpan +lemma AffineSubspace.right_mem_of_wbtw {s : AffineSubspace R P} (hxyz : Wbtw R x y z) (hx : x ∈ s) + (hy : y ∈ s) (hxy : x ≠ y) : z ∈ s := by + obtain ⟨ε, -, rfl⟩ := hxyz + have hε : ε ≠ 0 := by rintro rfl; simp at hxy + simpa [hε] using lineMap_mem ε⁻¹ hx hy + theorem wbtw_smul_vadd_smul_vadd_of_nonneg_of_le (x : P) (v : V) {r₁ r₂ : R} (hr₁ : 0 ≤ r₁) (hr₂ : r₁ ≤ r₂) : Wbtw R x (r₁ • v +ᵥ x) (r₂ • v +ᵥ x) := by refine ⟨r₁ / r₂, ⟨div_nonneg hr₁ (hr₁.trans hr₂), div_le_one_of_le₀ hr₂ (hr₁.trans hr₂)⟩, ?_⟩ diff --git a/Mathlib/Analysis/Convex/Birkhoff.lean b/Mathlib/Analysis/Convex/Birkhoff.lean new file mode 100644 index 0000000000000..702bc496c5a0d --- /dev/null +++ b/Mathlib/Analysis/Convex/Birkhoff.lean @@ -0,0 +1,172 @@ +/- +Copyright (c) 2024 Bhavik Mehta. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bhavik Mehta +-/ + +import Mathlib.Analysis.Convex.Combination +import Mathlib.Combinatorics.Hall.Basic +import Mathlib.Data.Matrix.DoublyStochastic +import Mathlib.Tactic.Linarith + +/-! +# Birkhoff's theorem + +## Main statements + +* `doublyStochastic_eq_sum_perm`: If `M` is a doubly stochastic matrix, then it is a convex + combination of permutation matrices. +* `doublyStochastic_eq_convexHull_perm`: The set of doubly stochastic matrices is the convex hull + of the permutation matrices. + +## TODO + +* Show that the extreme points of doubly stochastic matrices are the permutation matrices. +* Show that for `x y : n → R`, `x` is majorized by `y` if and only if there is a doubly stochastic + matrix `M` such that `M *ᵥ y = x`. + +## Tags + +Doubly stochastic, Birkhoff's theorem, Birkhoff-von Neumann theorem +-/ + +open Finset Function Matrix + +variable {R n : Type*} [Fintype n] [DecidableEq n] + +section LinearOrderedSemifield + +variable [LinearOrderedSemifield R] {M : Matrix n n R} + +/-- +If M is a positive scalar multiple of a doubly stochastic matrix, then there is a permutation matrix +whose support is contained in the support of M. +-/ +private lemma exists_perm_eq_zero_implies_eq_zero [Nonempty n] {s : R} (hs : 0 < s) + (hM : ∃ M' ∈ doublyStochastic R n, M = s • M') : + ∃ σ : Equiv.Perm n, ∀ i j, M i j = 0 → σ.permMatrix R i j = 0 := by + 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 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] + suffices #A * s ≤ #(A.biUnion f) * s by exact_mod_cast le_of_mul_le_mul_right this hs + rw [← h₁, ← h₂] + trans ∑ i ∈ A, ∑ j ∈ A.biUnion f, M i j + · refine sum_le_sum fun i hi => ?_ + exact sum_le_sum_of_subset_of_nonneg (subset_biUnion_of_mem f hi) (by simp [*]) + · exact sum_le_sum_of_subset_of_nonneg (by simp) fun _ _ _ => sum_nonneg fun j _ => hM.1 _ _ + obtain ⟨g, hg, hg'⟩ := (all_card_le_biUnion_card_iff_exists_injective f).1 hf + rw [Finite.injective_iff_bijective] at hg + refine ⟨Equiv.ofBijective g hg, fun i j hij => ?_⟩ + simp only [PEquiv.toMatrix_apply, Option.mem_def, ite_eq_right_iff, one_ne_zero, imp_false, + Equiv.toPEquiv_apply, Equiv.ofBijective_apply, Option.some.injEq] + rintro rfl + simpa [f, hij] using hg' i + +end LinearOrderedSemifield + +section LinearOrderedField + +variable [LinearOrderedField R] {M : Matrix n n R} + +/-- +If M is a scalar multiple of a doubly stochastic matrix, then it is a conical combination of +permutation matrices. This is most useful when M is a doubly stochastic matrix, in which case +the combination is convex. + +This particular formulation is chosen to make the inductive step easier: we no longer need to +rescale each time a permutation matrix is subtracted. +-/ +private lemma doublyStochastic_sum_perm_aux (M : Matrix n n R) + (s : R) (hs : 0 ≤ s) + (hM : ∃ M' ∈ doublyStochastic R n, M = s • M') : + ∃ w : Equiv.Perm n → R, (∀ σ, 0 ≤ w σ) ∧ ∑ σ, w σ • σ.permMatrix R = M := by + rcases isEmpty_or_nonempty n + case inl => exact ⟨1, by simp, Subsingleton.elim _ _⟩ + set d : ℕ := #{i : n × n | M i.1 i.2 ≠ 0} with ← hd + clear_value d + induction d using Nat.strongRecOn generalizing M s + case ind d ih => + rcases eq_or_lt_of_le hs with rfl | hs' + case inl => + use 0 + simp only [zero_smul, exists_and_right] at hM + simp [hM] + obtain ⟨σ, hσ⟩ := exists_perm_eq_zero_implies_eq_zero hs' hM + obtain ⟨i, hi, hi'⟩ := exists_min_image _ (fun i => M i (σ i)) univ_nonempty + rw [exists_mem_doublyStochastic_eq_smul_iff hs] at hM + let N : Matrix n n R := M - M i (σ i) • σ.permMatrix R + have hMi' : 0 < M i (σ i) := (hM.1 _ _).lt_of_ne' fun h => by + simpa [Equiv.toPEquiv_apply] using hσ _ _ h + let s' : R := s - M i (σ i) + have hs' : 0 ≤ s' := by + simp only [s', sub_nonneg, ← hM.2.1 i] + exact single_le_sum (fun j _ => hM.1 i j) (by simp) + have : ∃ M' ∈ doublyStochastic R n, N = s' • M' := by + rw [exists_mem_doublyStochastic_eq_smul_iff hs'] + 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]⟩ + split + case isTrue h => exact (hi' i' (by simp)).trans_eq (by rw [h]) + case isFalse h => exact hM.1 _ _ + have hd' : #{i : n × n | N i.1 i.2 ≠ 0} < d := by + rw [← hd] + refine card_lt_card ?_ + rw [ssubset_iff_of_subset (monotone_filter_right _ _)] + · simp only [ne_eq, mem_filter, mem_univ, true_and, Decidable.not_not, Prod.exists] + refine ⟨i, σ i, hMi'.ne', ?_⟩ + simp [N, Equiv.toPEquiv_apply] + · rintro ⟨i', j'⟩ hN' hM' + dsimp at hN' hM' + simp only [sub_apply, hM', smul_apply, PEquiv.toMatrix_apply, Equiv.toPEquiv_apply, + Option.mem_def, Option.some.injEq, smul_eq_mul, mul_ite, mul_one, mul_zero, zero_sub, + neg_eq_zero, ite_eq_right_iff, Classical.not_imp, N] at hN' + obtain ⟨rfl, _⟩ := hN' + linarith [hi' i' (by simp)] + obtain ⟨w, hw, hw'⟩ := ih _ hd' _ s' hs' this rfl + refine ⟨w + fun σ' => if σ' = σ then M i (σ i) else 0, ?_⟩ + simp only [Pi.add_apply, add_smul, sum_add_distrib, hw', ite_smul, zero_smul, + sum_ite_eq', mem_univ, ↓reduceIte, N, sub_add_cancel, and_true] + intro σ' + split <;> simp [add_nonneg, hw, hM.1] + +/-- +If M is a doubly stochastic matrix, then it is an convex combination of permutation matrices. Note +`doublyStochastic_eq_convexHull_permMatrix` shows `doublyStochastic n` is exactly the convex hull of +the permutation matrices, and this lemma is instead most useful for accessing the coefficients of +each permutation matrices directly. +-/ +lemma exists_eq_sum_perm_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) : + ∃ w : Equiv.Perm n → R, (∀ σ, 0 ≤ w σ) ∧ ∑ σ, w σ = 1 ∧ ∑ σ, w σ • σ.permMatrix R = M := by + rcases isEmpty_or_nonempty n + case inl => exact ⟨fun _ => 1, by simp, by simp, Subsingleton.elim _ _⟩ + obtain ⟨w, hw1, hw3⟩ := doublyStochastic_sum_perm_aux M 1 (by simp) ⟨M, hM, by simp⟩ + refine ⟨w, hw1, ?_, hw3⟩ + inhabit n + have : ∑ j, ∑ σ : Equiv.Perm n, w σ • σ.permMatrix R default j = 1 := by + simp only [← smul_apply (m := n), ← Finset.sum_apply, hw3] + rw [sum_row_of_mem_doublyStochastic hM] + simpa [sum_comm (γ := n), Equiv.toPEquiv_apply] using this + +/-- +**Birkhoff's theorem** +The set of doubly stochastic matrices is the convex hull of the permutation matrices. Note +`exists_eq_sum_perm_of_mem_doublyStochastic` gives a convex weighting of each permutation matrix +directly. To show `doublyStochastic n` is convex, use `convex_doublyStochastic`. +-/ +theorem doublyStochastic_eq_convexHull_permMatrix : + doublyStochastic R n = convexHull R {σ.permMatrix R | σ : Equiv.Perm n} := by + refine (convexHull_min ?g1 convex_doublyStochastic).antisymm' fun M hM => ?g2 + case g1 => + rintro x ⟨h, rfl⟩ + exact permMatrix_mem_doublyStochastic + case g2 => + obtain ⟨w, hw1, hw2, hw3⟩ := exists_eq_sum_perm_of_mem_doublyStochastic hM + exact mem_convexHull_of_exists_fintype w (·.permMatrix R) hw1 hw2 (by simp) hw3 + +end LinearOrderedField diff --git a/Mathlib/Analysis/Convex/Body.lean b/Mathlib/Analysis/Convex/Body.lean index 219c7807cb05d..db92e77472f19 100644 --- a/Mathlib/Analysis/Convex/Body.lean +++ b/Mathlib/Analysis/Convex/Body.lean @@ -181,7 +181,7 @@ noncomputable instance : PseudoMetricSpace (ConvexBody V) where dist K L := Metric.hausdorffDist (K : Set V) L dist_self _ := Metric.hausdorffDist_self_zero dist_comm _ _ := Metric.hausdorffDist_comm - dist_triangle K L M := Metric.hausdorffDist_triangle hausdorffEdist_ne_top + dist_triangle _ _ _ := Metric.hausdorffDist_triangle hausdorffEdist_ne_top @[simp, norm_cast] theorem hausdorffDist_coe : Metric.hausdorffDist (K : Set V) L = dist K L := diff --git a/Mathlib/Analysis/Convex/Caratheodory.lean b/Mathlib/Analysis/Convex/Caratheodory.lean index 5d81223dc517b..59b4f09c6a3ec 100644 --- a/Mathlib/Analysis/Convex/Caratheodory.lean +++ b/Mathlib/Analysis/Convex/Caratheodory.lean @@ -55,7 +55,7 @@ theorem mem_convexHull_erase [DecidableEq E] {t : Finset E} (h : ¬AffineIndepen obtain ⟨g, gcombo, gsum, gpos⟩ := exists_nontrivial_relation_sum_zero_of_not_affine_ind h replace gpos := exists_pos_of_sum_zero_of_exists_nonzero g gsum gpos clear h - let s := @Finset.filter _ (fun z => 0 < g z) (fun _ => LinearOrder.decidableLT _ _) t + let s := {z ∈ t | 0 < g z} obtain ⟨i₀, mem, w⟩ : ∃ i₀ ∈ s, ∀ i ∈ s, f i₀ / g i₀ ≤ f i / g i := by apply s.exists_min_image fun z => f z / g z obtain ⟨x, hx, hgx⟩ : ∃ x ∈ t, 0 < g x := gpos @@ -117,13 +117,13 @@ theorem minCardFinsetOfMemConvexHull_nonempty : (minCardFinsetOfMemConvexHull hx exact ⟨x, mem_minCardFinsetOfMemConvexHull hx⟩ theorem minCardFinsetOfMemConvexHull_card_le_card {t : Finset E} (ht₁ : ↑t ⊆ s) - (ht₂ : x ∈ convexHull 𝕜 (t : Set E)) : (minCardFinsetOfMemConvexHull hx).card ≤ t.card := + (ht₂ : x ∈ convexHull 𝕜 (t : Set E)) : #(minCardFinsetOfMemConvexHull hx) ≤ #t := Function.argminOn_le _ _ _ (by exact ⟨ht₁, ht₂⟩) theorem affineIndependent_minCardFinsetOfMemConvexHull : AffineIndependent 𝕜 ((↑) : minCardFinsetOfMemConvexHull hx → E) := by - let k := (minCardFinsetOfMemConvexHull hx).card - 1 - have hk : (minCardFinsetOfMemConvexHull hx).card = k + 1 := + let k := #(minCardFinsetOfMemConvexHull hx) - 1 + have hk : #(minCardFinsetOfMemConvexHull hx) = k + 1 := (Nat.succ_pred_eq_of_pos (Finset.card_pos.mpr (minCardFinsetOfMemConvexHull_nonempty hx))).symm classical by_contra h @@ -133,7 +133,7 @@ theorem affineIndependent_minCardFinsetOfMemConvexHull : (minCardFinsetOfMemConvexHull_subseteq hx)) hp rw [← not_lt] at contra apply contra - erw [card_erase_of_mem p.2, hk] + rw [card_erase_of_mem p.2, hk] exact lt_add_one _ end Caratheodory @@ -142,7 +142,7 @@ variable {s : Set E} /-- **Carathéodory's convexity theorem** -/ theorem convexHull_eq_union : convexHull 𝕜 s = - ⋃ (t : Finset E) (hss : ↑t ⊆ s) (hai : AffineIndependent 𝕜 ((↑) : t → E)), convexHull 𝕜 ↑t := by + ⋃ (t : Finset E) (_ : ↑t ⊆ s) (_ : AffineIndependent 𝕜 ((↑) : t → E)), convexHull 𝕜 ↑t := by apply Set.Subset.antisymm · intro x hx simp only [exists_prop, Set.mem_iUnion] @@ -163,7 +163,7 @@ theorem eq_pos_convex_span_of_mem_convexHull {x : E} (hx : x ∈ convexHull 𝕜 obtain ⟨t, ht₁, ht₂, ht₃⟩ := hx simp only [t.convexHull_eq, exists_prop, Set.mem_setOf_eq] at ht₃ obtain ⟨w, hw₁, hw₂, hw₃⟩ := ht₃ - let t' := t.filter fun i => w i ≠ 0 + let t' := {i ∈ t | w i ≠ 0} refine ⟨t', t'.fintypeCoeSort, ((↑) : t' → E), w ∘ ((↑) : t' → E), ?_, ?_, ?_, ?_, ?_⟩ · rw [Subtype.range_coe_subtype] exact Subset.trans (Finset.filter_subset _ t) ht₁ @@ -172,7 +172,7 @@ theorem eq_pos_convex_span_of_mem_convexHull {x : E} (hx : x ∈ convexHull 𝕜 (hw₁ _ (Finset.mem_filter.mp i.2).1).lt_of_ne (Finset.mem_filter.mp i.property).2.symm · erw [Finset.sum_attach, Finset.sum_filter_ne_zero, hw₂] · change (∑ i ∈ t'.attach, (fun e => w e • e) ↑i) = x - erw [Finset.sum_attach (f := fun e => w e • e), Finset.sum_filter_of_ne] + rw [Finset.sum_attach (f := fun e => w e • e), Finset.sum_filter_of_ne] · rw [t.centerMass_eq_of_sum_1 id hw₂] at hw₃ exact hw₃ · intro e _ hwe contra diff --git a/Mathlib/Analysis/Convex/Combination.lean b/Mathlib/Analysis/Convex/Combination.lean index 399464ada7406..6fe599b4f51f7 100644 --- a/Mathlib/Analysis/Convex/Combination.lean +++ b/Mathlib/Analysis/Convex/Combination.lean @@ -124,8 +124,7 @@ theorem Finset.centerMass_subset {t' : Finset ι} (ht : t ⊆ t') (h : ∀ i ∈ intro i hit' hit rw [h i hit' hit, zero_smul, smul_zero] -theorem Finset.centerMass_filter_ne_zero : - (t.filter fun i => w i ≠ 0).centerMass w z = t.centerMass w z := +theorem Finset.centerMass_filter_ne_zero : {i ∈ t | w i ≠ 0}.centerMass w z = t.centerMass w z := Finset.centerMass_subset z (filter_subset _ _) fun i hit hit' => by simpa only [hit, mem_filter, true_and, Ne, Classical.not_not] using hit' @@ -264,7 +263,7 @@ theorem Finset.centroid_mem_convexHull (s : Finset E) (hs : s.Nonempty) : rw [s.centroid_eq_centerMass hs] apply s.centerMass_id_mem_convexHull · simp only [inv_nonneg, imp_true_iff, Nat.cast_nonneg, Finset.centroidWeights_apply] - · have hs_card : (s.card : R) ≠ 0 := by simp [Finset.nonempty_iff_ne_empty.mp hs] + · have hs_card : (#s : R) ≠ 0 := by simp [Finset.nonempty_iff_ne_empty.mp hs] simp only [hs_card, Finset.sum_const, nsmul_eq_mul, mul_inv_cancel₀, Ne, not_false_iff, Finset.centroidWeights_apply, zero_lt_one] @@ -390,7 +389,7 @@ theorem Set.Finite.convexHull_eq {s : Set E} (hs : s.Finite) : convexHull R s = /-- A weak version of Carathéodory's theorem. -/ theorem convexHull_eq_union_convexHull_finite_subsets (s : Set E) : - convexHull R s = ⋃ (t : Finset E) (w : ↑t ⊆ s), convexHull R ↑t := by + convexHull R s = ⋃ (t : Finset E) (_ : ↑t ⊆ s), convexHull R ↑t := by refine Subset.antisymm ?_ ?_ · rw [_root_.convexHull_eq] rintro x ⟨ι, t, w, z, hw₀, hw₁, hz, rfl⟩ diff --git a/Mathlib/Analysis/Convex/Cone/Extension.lean b/Mathlib/Analysis/Convex/Cone/Extension.lean index 0e1685f92d6f4..31d7448ecb98e 100644 --- a/Mathlib/Analysis/Convex/Cone/Extension.lean +++ b/Mathlib/Analysis/Convex/Cone/Extension.lean @@ -88,7 +88,7 @@ theorem step (nonneg : ∀ x : f.domain, (x : E) ∈ s → 0 ≤ f x) rcases mem_sup.1 hz with ⟨x, hx, y', hy', rfl⟩ rcases mem_span_singleton.1 hy' with ⟨r, rfl⟩ simp only [Subtype.coe_mk] at hzs - erw [LinearPMap.supSpanSingleton_apply_mk _ _ _ _ _ hx, smul_neg, ← sub_eq_add_neg, sub_nonneg] + rw [LinearPMap.supSpanSingleton_apply_mk _ _ _ _ _ hx, smul_neg, ← sub_eq_add_neg, sub_nonneg] rcases lt_trichotomy r 0 with (hr | hr | hr) · have : -(r⁻¹ • x) - y ∈ s := by rwa [← s.smul_mem_iff (neg_pos.2 hr), smul_sub, smul_neg, neg_smul, neg_neg, smul_smul, diff --git a/Mathlib/Analysis/Convex/Cone/InnerDual.lean b/Mathlib/Analysis/Convex/Cone/InnerDual.lean index 8bf4feeae7d46..466d181b61ba0 100644 --- a/Mathlib/Analysis/Convex/Cone/InnerDual.lean +++ b/Mathlib/Analysis/Convex/Cone/InnerDual.lean @@ -32,8 +32,6 @@ open Set LinearMap open scoped Classical open Pointwise -variable {𝕜 E F G : Type*} - /-! ### The dual cone -/ diff --git a/Mathlib/Analysis/Convex/EGauge.lean b/Mathlib/Analysis/Convex/EGauge.lean index 0fc1a2b1524c1..dacb554ee7505 100644 --- a/Mathlib/Analysis/Convex/EGauge.lean +++ b/Mathlib/Analysis/Convex/EGauge.lean @@ -65,8 +65,7 @@ end SMul section SMulZero -variable (𝕜 : Type*) [NNNorm 𝕜] [Nonempty 𝕜] {E : Type*} [Zero E] [SMulZeroClass 𝕜 E] - {c : 𝕜} {s t : Set E} {x : E} {r : ℝ≥0∞} +variable (𝕜 : Type*) [NNNorm 𝕜] [Nonempty 𝕜] {E : Type*} [Zero E] [SMulZeroClass 𝕜 E] {x : E} @[simp] lemma egauge_zero_left_eq_top : egauge 𝕜 0 x = ∞ ↔ x ≠ 0 := by simp [egauge_eq_top] @@ -77,8 +76,8 @@ end SMulZero section Module -variable {𝕜 : Type*} [NormedDivisionRing 𝕜] {α E : Type*} [AddCommGroup E] [Module 𝕜 E] - {c : 𝕜} {s t : Set E} {x y : E} {r : ℝ≥0∞} +variable {𝕜 : Type*} [NormedDivisionRing 𝕜] {E : Type*} [AddCommGroup E] [Module 𝕜 E] + {c : 𝕜} {s : Set E} {x : E} /-- If `c • x ∈ s` and `c ≠ 0`, then `egauge 𝕜 s x` is at most `((‖c‖₊⁻¹ : ℝ≥0) : ℝ≥0∞). @@ -159,8 +158,7 @@ end Module section SeminormedAddCommGroup -variable (𝕜 : Type*) [NormedField 𝕜] {α E : Type*} - [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] {c : 𝕜} {s t : Set E} {x y : E} +variable (𝕜 : Type*) [NormedField 𝕜] {E : Type*} [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] lemma div_le_egauge_closedBall (r : ℝ≥0) (x : E) : ‖x‖₊ / r ≤ egauge 𝕜 (closedBall 0 r) x := by rw [le_egauge_iff] @@ -183,8 +181,8 @@ end SeminormedAddCommGroup section SeminormedAddCommGroup -variable {𝕜 : Type*} [NormedField 𝕜] {α E : Type*} - [NormedAddCommGroup E] [NormedSpace 𝕜 E] {c : 𝕜} {s t : Set E} {x y : E} {r : ℝ≥0} +variable {𝕜 : Type*} [NormedField 𝕜] {E : Type*} + [NormedAddCommGroup E] [NormedSpace 𝕜 E] {c : 𝕜} {x : E} {r : ℝ≥0} lemma egauge_ball_le_of_one_lt_norm (hc : 1 < ‖c‖) (h₀ : r ≠ 0 ∨ x ≠ 0) : egauge 𝕜 (ball 0 r) x ≤ ‖c‖₊ * ‖x‖₊ / r := by diff --git a/Mathlib/Analysis/Convex/Gauge.lean b/Mathlib/Analysis/Convex/Gauge.lean index 7338a929f1f82..5ecb5e8b2c4cd 100644 --- a/Mathlib/Analysis/Convex/Gauge.lean +++ b/Mathlib/Analysis/Convex/Gauge.lean @@ -201,7 +201,7 @@ theorem Convex.gauge_le (hs : Convex ℝ s) (h₀ : (0 : E) ∈ s) (absorbs : Ab exact eq_empty_iff_forall_not_mem.2 fun x hx => ha <| (gauge_nonneg _).trans hx theorem Balanced.starConvex (hs : Balanced ℝ s) : StarConvex ℝ 0 s := - starConvex_zero_iff.2 fun x hx a ha₀ ha₁ => + starConvex_zero_iff.2 fun _ hx a ha₀ ha₁ => hs _ (by rwa [Real.norm_of_nonneg ha₀]) (smul_mem_smul_set hx) theorem le_gauge_of_not_mem (hs₀ : StarConvex ℝ 0 s) (hs₂ : Absorbs ℝ s {x}) (hx : x ∉ a • s) : @@ -316,7 +316,7 @@ theorem comap_gauge_nhds_zero_le (ha : Absorbent ℝ s) (hb : Bornology.IsVonNBo rcases (hb hu).exists_pos with ⟨r, hr₀, hr⟩ filter_upwards [preimage_mem_comap (gt_mem_nhds (inv_pos.2 hr₀))] with x (hx : gauge s x < r⁻¹) rcases exists_lt_of_gauge_lt ha hx with ⟨c, hc₀, hcr, y, hy, rfl⟩ - have hrc := (lt_inv hr₀ hc₀).2 hcr + have hrc := (lt_inv_comm₀ hr₀ hc₀).2 hcr rcases hr c⁻¹ (hrc.le.trans (le_abs_self _)) hy with ⟨z, hz, rfl⟩ simpa only [smul_inv_smul₀ hc₀.ne'] diff --git a/Mathlib/Analysis/Convex/Hull.lean b/Mathlib/Analysis/Convex/Hull.lean index 996ebbb415ab1..846de50849e76 100644 --- a/Mathlib/Analysis/Convex/Hull.lean +++ b/Mathlib/Analysis/Convex/Hull.lean @@ -148,6 +148,11 @@ theorem LinearMap.image_convexHull (f : E →ₗ[𝕜] F) (s : Set E) : f '' convexHull 𝕜 s = convexHull 𝕜 (f '' s) := f.isLinear.image_convexHull s +theorem convexHull_add_subset {s t : Set E} : + convexHull 𝕜 (s + t) ⊆ convexHull 𝕜 s + convexHull 𝕜 t := + convexHull_min (add_subset_add (subset_convexHull _ _) (subset_convexHull _ _)) + (Convex.add (convex_convexHull 𝕜 s) (convex_convexHull 𝕜 t)) + end AddCommMonoid end OrderedSemiring diff --git a/Mathlib/Analysis/Convex/Integral.lean b/Mathlib/Analysis/Convex/Integral.lean index dd75c412a4ffc..7d933906dae1b 100644 --- a/Mathlib/Analysis/Convex/Integral.lean +++ b/Mathlib/Analysis/Convex/Integral.lean @@ -39,9 +39,8 @@ open MeasureTheory MeasureTheory.Measure Metric Set Filter TopologicalSpace Func open scoped Topology ENNReal Convex -variable {α E F : Type*} {m0 : MeasurableSpace α} [NormedAddCommGroup E] [NormedSpace ℝ E] - [CompleteSpace E] [NormedAddCommGroup F] [NormedSpace ℝ F] [CompleteSpace F] {μ : Measure α} - {s : Set E} {t : Set α} {f : α → E} {g : E → ℝ} {C : ℝ} +variable {α E : Type*} {m0 : MeasurableSpace α} [NormedAddCommGroup E] [NormedSpace ℝ E] + [CompleteSpace E] {μ : Measure α} {s : Set E} {t : Set α} {f : α → E} {g : E → ℝ} {C : ℝ} /-! ### Non-strict Jensen's inequality diff --git a/Mathlib/Analysis/Convex/Intrinsic.lean b/Mathlib/Analysis/Convex/Intrinsic.lean index 82cc1b1b0da2d..1706893f1b382 100644 --- a/Mathlib/Analysis/Convex/Intrinsic.lean +++ b/Mathlib/Analysis/Convex/Intrinsic.lean @@ -176,11 +176,11 @@ theorem intrinsicFrontier_union_intrinsicInterior (s : Set P) : theorem isClosed_intrinsicClosure (hs : IsClosed (affineSpan 𝕜 s : Set P)) : IsClosed (intrinsicClosure 𝕜 s) := - (closedEmbedding_subtype_val hs).isClosedMap _ isClosed_closure + hs.isClosedEmbedding_subtypeVal.isClosedMap _ isClosed_closure theorem isClosed_intrinsicFrontier (hs : IsClosed (affineSpan 𝕜 s : Set P)) : IsClosed (intrinsicFrontier 𝕜 s) := - (closedEmbedding_subtype_val hs).isClosedMap _ isClosed_frontier + hs.isClosedEmbedding_subtypeVal.isClosedMap _ isClosed_frontier @[simp] theorem affineSpan_intrinsicClosure (s : Set P) : diff --git a/Mathlib/Analysis/Convex/Jensen.lean b/Mathlib/Analysis/Convex/Jensen.lean index 93f195e014393..90692868f122b 100644 --- a/Mathlib/Analysis/Convex/Jensen.lean +++ b/Mathlib/Analysis/Convex/Jensen.lean @@ -271,8 +271,8 @@ lemma ConvexOn.exists_ge_of_centerMass {t : Finset ι} (h : ConvexOn 𝕜 s f) ∃ i ∈ t, f (t.centerMass w p) ≤ f (p i) := by set y := t.centerMass w p -- TODO: can `rsuffices` be used to write the `exact` first, then the proof of this obtain? - obtain ⟨i, hi, hfi⟩ : ∃ i ∈ t.filter fun i => w i ≠ 0, w i • f y ≤ w i • (f ∘ p) i := by - have hw' : (0 : 𝕜) < ∑ i ∈ filter (fun i => w i ≠ 0) t, w i := by rwa [sum_filter_ne_zero] + obtain ⟨i, hi, hfi⟩ : ∃ i ∈ {i ∈ t | w i ≠ 0}, w i • f y ≤ w i • (f ∘ p) i := by + have hw' : (0 : 𝕜) < ∑ i ∈ t with w i ≠ 0, w i := by rwa [sum_filter_ne_zero] refine exists_le_of_sum_le (nonempty_of_sum_ne_zero hw'.ne') ?_ rw [← sum_smul, ← smul_le_smul_iff_of_pos_left (inv_pos.2 hw'), inv_smul_smul₀ hw'.ne', ← centerMass, centerMass_filter_ne_zero] diff --git a/Mathlib/Analysis/Convex/Join.lean b/Mathlib/Analysis/Convex/Join.lean index 590ebaa4aa614..c2dba9ce9162e 100644 --- a/Mathlib/Analysis/Convex/Join.lean +++ b/Mathlib/Analysis/Convex/Join.lean @@ -59,7 +59,6 @@ theorem convexJoin_singleton_left (t : Set E) (x : E) : theorem convexJoin_singleton_right (s : Set E) (y : E) : convexJoin 𝕜 s {y} = ⋃ x ∈ s, segment 𝕜 x y := by simp [convexJoin] --- Porting note (#10618): simp can prove it theorem convexJoin_singletons (x : E) : convexJoin 𝕜 {x} {y} = segment 𝕜 x y := by simp @[simp] diff --git a/Mathlib/Analysis/Convex/Normed.lean b/Mathlib/Analysis/Convex/Normed.lean index bfb9ac2e29cd3..fae3e58b55f18 100644 --- a/Mathlib/Analysis/Convex/Normed.lean +++ b/Mathlib/Analysis/Convex/Normed.lean @@ -112,7 +112,7 @@ instance (priority := 100) NormedSpace.instPathConnectedSpace : PathConnectedSpa TopologicalAddGroup.pathConnectedSpace instance (priority := 100) NormedSpace.instLocPathConnectedSpace : LocPathConnectedSpace E := - locPathConnected_of_bases (fun x => Metric.nhds_basis_ball) fun x r r_pos => + .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) : diff --git a/Mathlib/Analysis/Convex/Radon.lean b/Mathlib/Analysis/Convex/Radon.lean index f297649b6f470..21470d3e027c9 100644 --- a/Mathlib/Analysis/Convex/Radon.lean +++ b/Mathlib/Analysis/Convex/Radon.lean @@ -6,7 +6,7 @@ Authors: Vasily Nesterov import Mathlib.Analysis.Convex.Combination import Mathlib.Data.Set.Card import Mathlib.LinearAlgebra.AffineSpace.FiniteDimensional -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Radon's theorem on convex sets @@ -41,8 +41,8 @@ theorem radon_partition {f : ι → E} (h : ¬ AffineIndependent 𝕜 f) : rw [affineIndependent_iff] at h push_neg at h obtain ⟨s, w, h_wsum, h_vsum, nonzero_w_index, h1, h2⟩ := h - let I : Finset ι := s.filter fun i ↦ 0 ≤ w i - let J : Finset ι := s.filter fun i ↦ w i < 0 + let I : Finset ι := {i ∈ s | 0 ≤ w i} + let J : Finset ι := {i ∈ s | w i < 0} let p : E := centerMass I w f -- point of intersection have hJI : ∑ j ∈ J, w j + ∑ i ∈ I, w i = 0 := by simpa only [h_wsum, not_lt] using sum_filter_add_sum_filter_not s (fun i ↦ w i < 0) w @@ -66,8 +66,8 @@ open Module /-- Corner case for `helly_theorem'`. -/ private lemma helly_theorem_corner {F : ι → Set E} {s : Finset ι} - (h_card_small : s.card ≤ finrank 𝕜 E + 1) - (h_inter : ∀ I ⊆ s, I.card ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : + (h_card_small : #s ≤ finrank 𝕜 E + 1) + (h_inter : ∀ I ⊆ s, #I ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i ∈ s, F i).Nonempty := h_inter s (by simp) h_card_small variable [FiniteDimensional 𝕜 E] @@ -78,12 +78,12 @@ If `F` is a finite family of convex sets in a vector space of finite dimension ` `k ≤ d + 1` sets of `F` intersect nontrivially, then all sets of `F` intersect nontrivially. -/ theorem helly_theorem' {F : ι → Set E} {s : Finset ι} (h_convex : ∀ i ∈ s, Convex 𝕜 (F i)) - (h_inter : ∀ I ⊆ s, I.card ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : + (h_inter : ∀ I ⊆ s, #I ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i ∈ s, F i).Nonempty := by classical - obtain h_card | h_card := lt_or_le s.card (finrank 𝕜 E + 1) + obtain h_card | h_card := lt_or_le #s (finrank 𝕜 E + 1) · exact helly_theorem_corner (le_of_lt h_card) h_inter - generalize hn : s.card = n + generalize hn : #s = n rw [hn] at h_card induction' n, h_card using Nat.le_induction with k h_card hk generalizing ι · exact helly_theorem_corner (le_of_eq hn) h_inter @@ -137,9 +137,9 @@ theorem helly_theorem' {F : ι → Set E} {s : Finset ι} If `F` is a family of `n` convex sets in a vector space of finite dimension `d`, with `n ≥ d + 1`, and any `d + 1` sets of `F` intersect nontrivially, then all sets of `F` intersect nontrivially. -/ theorem helly_theorem {F : ι → Set E} {s : Finset ι} - (h_card : finrank 𝕜 E + 1 ≤ s.card) + (h_card : finrank 𝕜 E + 1 ≤ #s) (h_convex : ∀ i ∈ s, Convex 𝕜 (F i)) - (h_inter : ∀ I ⊆ s, I.card = finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : + (h_inter : ∀ I ⊆ s, #I = finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i ∈ s, F i).Nonempty := by apply helly_theorem' h_convex intro I hI_ss hI_card @@ -153,7 +153,7 @@ If `F` is a finite set of convex sets in a vector space of finite dimension `d`, sets from `F` intersect nontrivially, then all sets from `F` intersect nontrivially. -/ theorem helly_theorem_set' {F : Finset (Set E)} (h_convex : ∀ X ∈ F, Convex 𝕜 X) - (h_inter : ∀ G : Finset (Set E), G ⊆ F → G.card ≤ finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : + (h_inter : ∀ G : Finset (Set E), G ⊆ F → #G ≤ finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : (⋂₀ (F : Set (Set E))).Nonempty := by classical -- for DecidableEq, required for the family version rw [show ⋂₀ F = ⋂ X ∈ F, (X : Set E) by ext; simp] @@ -168,9 +168,9 @@ If `F` is a finite set of convex sets in a vector space of finite dimension `d`, and any `d + 1` sets from `F` intersect nontrivially, then all sets from `F` intersect nontrivially. -/ theorem helly_theorem_set {F : Finset (Set E)} - (h_card : finrank 𝕜 E + 1 ≤ F.card) + (h_card : finrank 𝕜 E + 1 ≤ #F) (h_convex : ∀ X ∈ F, Convex 𝕜 X) - (h_inter : ∀ G : Finset (Set E), G ⊆ F → G.card = finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : + (h_inter : ∀ G : Finset (Set E), G ⊆ F → #G = finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : (⋂₀ (F : Set (Set E))).Nonempty := by apply helly_theorem_set' h_convex intro I hI_ss hI_card @@ -185,7 +185,7 @@ If `F` is a family of compact convex sets in a vector space of finite dimension `k ≤ 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_convex : ∀ i, Convex 𝕜 (F i)) (h_compact : ∀ i, IsCompact (F i)) - (h_inter : ∀ I : Finset ι, I.card ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : + (h_inter : ∀ I : Finset ι, #I ≤ finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i, F i).Nonempty := by classical /- If `ι` is empty the statement is trivial. -/ @@ -214,11 +214,11 @@ 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_convex : ∀ i, Convex 𝕜 (F i)) (h_compact : ∀ i, IsCompact (F i)) - (h_inter : ∀ I : Finset ι, I.card = finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : + (h_inter : ∀ I : Finset ι, #I = finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i, F i).Nonempty := by apply helly_theorem_compact' h_convex h_compact intro I hI_card - have hJ : ∃ J : Finset ι, I ⊆ J ∧ J.card = finrank 𝕜 E + 1 := by + have hJ : ∃ J : Finset ι, I ⊆ J ∧ #J = finrank 𝕜 E + 1 := by by_cases h : Infinite ι · exact Infinite.exists_superset_card_eq _ _ hI_card · have : Finite ι := Finite.of_not_infinite h @@ -236,7 +236,7 @@ If `F` is a set of compact convex sets in a vector space of finite dimension `d` `k ≤ d + 1` sets from `F` intersect nontrivially, then all sets from `F` intersect nontrivially. -/ theorem helly_theorem_set_compact' [TopologicalSpace E] [T2Space E] {F : Set (Set E)} (h_convex : ∀ X ∈ F, Convex 𝕜 X) (h_compact : ∀ X ∈ F, IsCompact X) - (h_inter : ∀ G : Finset (Set E), (G : Set (Set E)) ⊆ F → G.card ≤ finrank 𝕜 E + 1 → + (h_inter : ∀ G : Finset (Set E), (G : Set (Set E)) ⊆ F → #G ≤ finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : (⋂₀ (F : Set (Set E))).Nonempty := by classical -- for DecidableEq, required for the family version @@ -259,7 +259,7 @@ then all sets from `F` intersect nontrivially. -/ theorem helly_theorem_set_compact [TopologicalSpace E] [T2Space E] {F : Set (Set E)} (h_card : finrank 𝕜 E + 1 ≤ F.encard) (h_convex : ∀ X ∈ F, Convex 𝕜 X) (h_compact : ∀ X ∈ F, IsCompact X) - (h_inter : ∀ G : Finset (Set E), (G : Set (Set E)) ⊆ F → G.card = finrank 𝕜 E + 1 → + (h_inter : ∀ G : Finset (Set E), (G : Set (Set E)) ⊆ F → #G = finrank 𝕜 E + 1 → (⋂₀ G : Set E).Nonempty) : (⋂₀ (F : Set (Set E))).Nonempty := by apply helly_theorem_set_compact' h_convex h_compact diff --git a/Mathlib/Analysis/Convex/Segment.lean b/Mathlib/Analysis/Convex/Segment.lean index 9f5026dbeb8cc..1c4e577df9e16 100644 --- a/Mathlib/Analysis/Convex/Segment.lean +++ b/Mathlib/Analysis/Convex/Segment.lean @@ -171,14 +171,14 @@ end DenselyOrdered theorem segment_eq_image (x y : E) : [x -[𝕜] y] = (fun θ : 𝕜 => (1 - θ) • x + θ • y) '' Icc (0 : 𝕜) 1 := - Set.ext fun z => + Set.ext fun _ => ⟨fun ⟨a, b, ha, hb, hab, hz⟩ => ⟨b, ⟨hb, hab ▸ le_add_of_nonneg_left ha⟩, hab ▸ hz ▸ by simp only [add_sub_cancel_right]⟩, fun ⟨θ, ⟨hθ₀, hθ₁⟩, hz⟩ => ⟨1 - θ, θ, sub_nonneg.2 hθ₁, hθ₀, sub_add_cancel _ _, hz⟩⟩ theorem openSegment_eq_image (x y : E) : openSegment 𝕜 x y = (fun θ : 𝕜 => (1 - θ) • x + θ • y) '' Ioo (0 : 𝕜) 1 := - Set.ext fun z => + Set.ext fun _ => ⟨fun ⟨a, b, ha, hb, hab, hz⟩ => ⟨b, ⟨hb, hab ▸ lt_add_of_pos_left _ ha⟩, hab ▸ hz ▸ by simp only [add_sub_cancel_right]⟩, fun ⟨θ, ⟨hθ₀, hθ₁⟩, hz⟩ => ⟨1 - θ, θ, sub_pos.2 hθ₁, hθ₀, sub_add_cancel _ _, hz⟩⟩ diff --git a/Mathlib/Analysis/Convex/Side.lean b/Mathlib/Analysis/Convex/Side.lean index 45bc7d0036eb8..9504c21166ab9 100644 --- a/Mathlib/Analysis/Convex/Side.lean +++ b/Mathlib/Analysis/Convex/Side.lean @@ -345,7 +345,6 @@ end StrictOrderedCommRing section LinearOrderedField variable [LinearOrderedField R] [AddCommGroup V] [Module R V] [AddTorsor V P] -variable [AddCommGroup V'] [Module R V'] [AddTorsor V' P'] @[simp] theorem wOppSide_self_iff {s : AffineSubspace R P} {x : P} : s.WOppSide x x ↔ x ∈ s := by diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean index 9d5442089d921..981b12a32e26c 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean @@ -96,7 +96,7 @@ theorem strictConvexOn_zpow {m : ℤ} (hm₀ : m ≠ 0) (hm₁ : m ≠ 1) : intro x hx rw [mem_Ioi] at hx rw [iter_deriv_zpow] - refine mul_pos ?_ (zpow_pos_of_pos hx _) + refine mul_pos ?_ (zpow_pos hx _) norm_cast refine int_prod_range_pos (by decide) fun hm => ?_ rw [← Finset.coe_Ico] at hm diff --git a/Mathlib/Analysis/Convex/Star.lean b/Mathlib/Analysis/Convex/Star.lean index 35d31a5d32be1..ad0ee8acf1ca5 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -386,7 +386,7 @@ theorem starConvex_iff_div : StarConvex 𝕜 x s ↔ ∀ ⦃y⦄, y ∈ s → theorem StarConvex.mem_smul (hs : StarConvex 𝕜 0 s) (hx : x ∈ s) {t : 𝕜} (ht : 1 ≤ t) : x ∈ t • s := by rw [mem_smul_set_iff_inv_smul_mem₀ (zero_lt_one.trans_le ht).ne'] - exact hs.smul_mem hx (by positivity) (inv_le_one ht) + exact hs.smul_mem hx (by positivity) (inv_le_one_of_one_le₀ ht) end AddCommGroup diff --git a/Mathlib/Analysis/Convex/Strict.lean b/Mathlib/Analysis/Convex/Strict.lean index 43a8732b0e6d3..1eabcd86ec380 100644 --- a/Mathlib/Analysis/Convex/Strict.lean +++ b/Mathlib/Analysis/Convex/Strict.lean @@ -365,7 +365,7 @@ theorem strictConvex_iff_div : theorem StrictConvex.mem_smul_of_zero_mem (hs : StrictConvex 𝕜 s) (zero_mem : (0 : E) ∈ s) (hx : x ∈ s) (hx₀ : x ≠ 0) {t : 𝕜} (ht : 1 < t) : x ∈ t • interior s := by rw [mem_smul_set_iff_inv_smul_mem₀ (by positivity)] - exact hs.smul_mem_of_zero_mem zero_mem hx hx₀ (by positivity) (inv_lt_one ht) + exact hs.smul_mem_of_zero_mem zero_mem hx hx₀ (by positivity) (inv_lt_one_of_one_lt₀ ht) end AddCommGroup diff --git a/Mathlib/Analysis/Convex/Strong.lean b/Mathlib/Analysis/Convex/Strong.lean index f0301456bebd8..64d17ed42cec3 100644 --- a/Mathlib/Analysis/Convex/Strong.lean +++ b/Mathlib/Analysis/Convex/Strong.lean @@ -27,7 +27,7 @@ open Real variable {E : Type*} [NormedAddCommGroup E] section NormedSpace -variable [NormedSpace ℝ E] {φ ψ : ℝ → ℝ} {s : Set E} {a b m : ℝ} {x y : E} {f g : E → ℝ} +variable [NormedSpace ℝ E] {φ ψ : ℝ → ℝ} {s : Set E} {m : ℝ} {f g : E → ℝ} /-- A function `f` from a real normed space is uniformly convex with modulus `φ` if `f (t • x + (1 - t) • y) ≤ t • f x + (1 - t) • f y - t * (1 - t) * φ ‖x - y‖` for all `t ∈ [0, 1]`. @@ -145,7 +145,7 @@ nonrec lemma StrongConcaveOn.strictConcaveOn (hf : StrongConcaveOn s m f) (hm : end NormedSpace section InnerProductSpace -variable [InnerProductSpace ℝ E] {φ ψ : ℝ → ℝ} {s : Set E} {a b m : ℝ} {x y : E} {f : E → ℝ} +variable [InnerProductSpace ℝ E] {s : Set E} {a b m : ℝ} {x y : E} {f : E → ℝ} private lemma aux_sub (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : a * (f x - m / (2 : ℝ) * ‖x‖ ^ 2) + b * (f y - m / (2 : ℝ) * ‖y‖ ^ 2) + diff --git a/Mathlib/Analysis/Convex/TotallyBounded.lean b/Mathlib/Analysis/Convex/TotallyBounded.lean new file mode 100644 index 0000000000000..f4215b59bc3cf --- /dev/null +++ b/Mathlib/Analysis/Convex/TotallyBounded.lean @@ -0,0 +1,52 @@ +/- +Copyright (c) 2024 Christopher Hoskin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christopher Hoskin +-/ + +import Mathlib.Topology.UniformSpace.Cauchy +import Mathlib.Analysis.Convex.Hull +import Mathlib.Topology.Algebra.UniformGroup.Basic +import Mathlib.Topology.Algebra.Module.LocallyConvex + +/-! +# Totally Bounded sets and Convex Hulls + +## Main statements + +- `totallyBounded_convexHull` The convex hull of a totally bounded set is totally bounded. + +## References + +* [Bourbaki, *Topological Vector Spaces*][bourbaki1987] + +## Tags + +convex, totally bounded +-/ + +open Set Pointwise + +variable (E : Type*) {s : Set E} +variable [AddCommGroup E] [Module ℝ E] +variable [UniformSpace E] [UniformAddGroup E] [lcs : LocallyConvexSpace ℝ E] [ContinuousSMul ℝ E] + +theorem totallyBounded_convexHull (hs : TotallyBounded s) : + TotallyBounded (convexHull ℝ s) := by + rw [totallyBounded_iff_subset_finite_iUnion_nhds_zero] + intro U hU + obtain ⟨W, hW₁, hW₂⟩ := exists_nhds_zero_half hU + obtain ⟨V, ⟨hV₁, hV₂, hV₃⟩⟩ := (locallyConvexSpace_iff_exists_convex_subset_zero ℝ E).mp lcs W hW₁ + obtain ⟨t, ⟨htf, hts⟩⟩ := (totallyBounded_iff_subset_finite_iUnion_nhds_zero.mp hs) _ hV₁ + obtain ⟨t', ⟨htf', hts'⟩⟩ := (totallyBounded_iff_subset_finite_iUnion_nhds_zero.mp + (IsCompact.totallyBounded (Finite.isCompact_convexHull htf)) _ hV₁) + use t', htf' + simp only [iUnion_vadd_set, vadd_eq_add] at hts hts' ⊢ + calc convexHull ℝ s + _ ⊆ convexHull ℝ (t + V) := convexHull_mono hts + _ ⊆ convexHull ℝ t + convexHull ℝ V := convexHull_add_subset + _ = convexHull ℝ t + V := by rw [hV₂.convexHull_eq] + _ ⊆ t' + V + V := add_subset_add_right hts' + _ = t' + (V + V) := by rw [add_assoc] + _ ⊆ t' + (W + W) := add_subset_add_left (add_subset_add hV₃ hV₃) + _ ⊆ t' + U := add_subset_add_left (add_subset_iff.mpr hW₂) diff --git a/Mathlib/Analysis/Convex/Uniform.lean b/Mathlib/Analysis/Convex/Uniform.lean index c57da9a0c876f..152127c0a4736 100644 --- a/Mathlib/Analysis/Convex/Uniform.lean +++ b/Mathlib/Analysis/Convex/Uniform.lean @@ -72,7 +72,8 @@ theorem exists_forall_closed_ball_dist_add_le_two_sub (hε : 0 < ε) : have h₂ : ∀ z : E, ‖z‖ ≤ 1 → 1 - δ' ≤ ‖z‖ → ‖‖z‖⁻¹ • z - z‖ ≤ δ' := by rintro z hz hδz nth_rw 3 [← one_smul ℝ z] - rwa [← sub_smul, norm_smul_of_nonneg (sub_nonneg_of_le <| one_le_inv (hδ'.trans_le hδz) hz), + rwa [← sub_smul, + norm_smul_of_nonneg (sub_nonneg_of_le <| (one_le_inv₀ (hδ'.trans_le hδz)).2 hz), sub_mul, inv_mul_cancel₀ (hδ'.trans_le hδz).ne', one_mul, sub_le_comm] set x' := ‖x‖⁻¹ • x set y' := ‖y‖⁻¹ • y @@ -86,12 +87,12 @@ theorem exists_forall_closed_ball_dist_add_le_two_sub (hε : 0 < ε) : _ ≤ _ := by have : ∀ x' y', x - y = x' - y' + (x - x') + (y' - y) := fun _ _ => by abel rw [sub_le_iff_le_add, norm_sub_rev _ x, ← add_assoc, this] - exact norm_add₃_le _ _ _ + exact norm_add₃_le calc ‖x + y‖ ≤ ‖x' + y'‖ + ‖x' - x‖ + ‖y' - y‖ := by have : ∀ x' y', x + y = x' + y' + (x - x') + (y - y') := fun _ _ => by abel rw [norm_sub_rev, norm_sub_rev y', this] - exact norm_add₃_le _ _ _ + exact norm_add₃_le _ ≤ 2 - δ + δ' + δ' := (add_le_add_three (h (h₁ _ hx') (h₁ _ hy') hxy') (h₂ _ hx hx'.le) (h₂ _ hy hy'.le)) _ ≤ 2 - δ' := by diff --git a/Mathlib/Analysis/Convolution.lean b/Mathlib/Analysis/Convolution.lean index 55806cb2f24fa..13bd14577f345 100644 --- a/Mathlib/Analysis/Convolution.lean +++ b/Mathlib/Analysis/Convolution.lean @@ -5,7 +5,7 @@ Authors: Floris van Doorn -/ import Mathlib.Analysis.Calculus.ContDiff.Basic import Mathlib.Analysis.Calculus.ParametricIntegral -import Mathlib.MeasureTheory.Constructions.Prod.Integral +import Mathlib.MeasureTheory.Integral.Prod import Mathlib.MeasureTheory.Function.LocallyIntegrable import Mathlib.MeasureTheory.Group.Integral import Mathlib.MeasureTheory.Group.Prod @@ -580,7 +580,7 @@ theorem continuousOn_convolution_right_with_param {g : P → G → E'} {s : Set apply hgs p _ hp contrapose! hy exact ⟨y - x, by simpa using hy, x, hx, by simp⟩ - apply ContinuousWithinAt.mono_of_mem (B (q₀, x₀) ⟨hq₀, mem_of_mem_nhds ht⟩) + apply ContinuousWithinAt.mono_of_mem_nhdsWithin (B (q₀, x₀) ⟨hq₀, mem_of_mem_nhds ht⟩) exact mem_nhdsWithin_prod_iff.2 ⟨s, self_mem_nhdsWithin, t, nhdsWithin_le_nhds ht, Subset.rfl⟩ /-- The convolution `f * g` is continuous if `f` is locally integrable and `g` is continuous and @@ -1239,7 +1239,7 @@ theorem contDiffOn_convolution_right_with_param {f : G → E} {n : ℕ∞} (L : ((ContinuousLinearEquiv.arrowCongr isoE' isoF).symm : (E' →L[𝕜] F) →L[𝕜] eE' →L[𝕜] eF) L let R := fun q : eP × eG => (ef ⋆[eL, eμ] eg q.1) q.2 have R_contdiff : ContDiffOn 𝕜 n R ((isoP ⁻¹' s) ×ˢ univ) := by - have hek : IsCompact (isoG ⁻¹' k) := isoG.toHomeomorph.closedEmbedding.isCompact_preimage hk + have hek : IsCompact (isoG ⁻¹' k) := isoG.toHomeomorph.isClosedEmbedding.isCompact_preimage hk have hes : IsOpen (isoP ⁻¹' s) := isoP.continuous.isOpen_preimage _ hs refine contDiffOn_convolution_right_with_param_aux eL hes hek ?_ ?_ ?_ · intro p x hp hx @@ -1264,9 +1264,9 @@ theorem contDiffOn_convolution_right_with_param {f : G → E} {n : ℕ∞} (L : simp only [LinearIsometryEquiv.coe_coe, (· ∘ ·), ContinuousLinearEquiv.prod_symm, ContinuousLinearEquiv.prod_apply] simp only [R, convolution, coe_comp', ContinuousLinearEquiv.coe_coe, (· ∘ ·)] - rw [ClosedEmbedding.integral_map, ← isoF.integral_comp_comm] + rw [IsClosedEmbedding.integral_map, ← isoF.integral_comp_comm] · rfl - · exact isoG.symm.toHomeomorph.closedEmbedding + · exact isoG.symm.toHomeomorph.isClosedEmbedding simp_rw [this] at A exact A diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index 4e015c579727c..bededfafb1458 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -90,10 +90,6 @@ instance instFunLike : FunLike 𝓢(E, F) E F where coe f := f.toFun coe_injective' f g h := by cases f; cases g; congr -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun`. -/ -instance instCoeFun : CoeFun 𝓢(E, F) fun _ => E → F := - DFunLike.hasCoeToFun - /-- All derivatives of a Schwartz function are rapidly decaying. -/ theorem decay (f : 𝓢(E, F)) (k n : ℕ) : ∃ C : ℝ, 0 < C ∧ ∀ x, ‖x‖ ^ k * ‖iteratedFDeriv ℝ n f x‖ ≤ C := by @@ -139,7 +135,7 @@ theorem isBigO_cocompact_zpow_neg_nat (k : ℕ) : refine ⟨d, Filter.Eventually.filter_mono Filter.cocompact_le_cofinite ?_⟩ refine (Filter.eventually_cofinite_ne 0).mono fun x hx => ?_ rw [Real.norm_of_nonneg (zpow_nonneg (norm_nonneg _) _), zpow_neg, ← div_eq_mul_inv, le_div_iff₀'] - exacts [hd' x, zpow_pos_of_pos (norm_pos_iff.mpr hx) _] + exacts [hd' x, zpow_pos (norm_pos_iff.mpr hx) _] theorem isBigO_cocompact_rpow [ProperSpace E] (s : ℝ) : f =O[cocompact E] fun x => ‖x‖ ^ s := by @@ -579,7 +575,7 @@ open MeasureTheory Module /-- A measure `μ` has temperate growth if there is an `n : ℕ` such that `(1 + ‖x‖) ^ (- n)` is `μ`-integrable. -/ -class _root_.MeasureTheory.Measure.HasTemperateGrowth (μ : Measure D) : Prop := +class _root_.MeasureTheory.Measure.HasTemperateGrowth (μ : Measure D) : Prop where exists_integrable : ∃ (n : ℕ), Integrable (fun x ↦ (1 + ‖x‖) ^ (- (n : ℝ))) μ open Classical in @@ -823,9 +819,7 @@ section Comp variable (𝕜) variable [RCLike 𝕜] variable [NormedAddCommGroup D] [NormedSpace ℝ D] -variable [NormedAddCommGroup G] [NormedSpace ℝ G] variable [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] -variable [NormedSpace 𝕜 G] [SMulCommClass ℝ 𝕜 G] /-- Composition with a function on the right is a continuous linear map on Schwartz space provided that the function is temperate and growths polynomially near infinity. -/ @@ -956,7 +950,7 @@ theorem fderivCLM_apply (f : 𝓢(E, F)) (x : E) : fderivCLM 𝕜 f x = fderiv /-- The 1-dimensional derivative on Schwartz space as a continuous `𝕜`-linear map. -/ def derivCLM : 𝓢(ℝ, F) →L[𝕜] 𝓢(ℝ, F) := - mkCLM (fun f => deriv f) (fun f g _ => deriv_add f.differentiableAt g.differentiableAt) + 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⟩ => ⟨{⟨k, n + 1⟩}, 1, zero_le_one, fun f x => by diff --git a/Mathlib/Analysis/Fourier/AddCircle.lean b/Mathlib/Analysis/Fourier/AddCircle.lean index 7ca64c6a78543..6a5971c612314 100644 --- a/Mathlib/Analysis/Fourier/AddCircle.lean +++ b/Mathlib/Analysis/Fourier/AddCircle.lean @@ -107,7 +107,7 @@ def fourier (n : ℤ) : C(AddCircle T, ℂ) where theorem fourier_apply {n : ℤ} {x : AddCircle T} : fourier n x = toCircle (n • x :) := rfl --- @[simp] -- Porting note: simp normal form is `fourier_coe_apply'` +-- simp normal form is `fourier_coe_apply'` theorem fourier_coe_apply {n : ℤ} {x : ℝ} : fourier n (x : AddCircle T) = Complex.exp (2 * π * Complex.I * n * x / T) := by rw [fourier_apply, ← QuotientAddGroup.mk_zsmul, toCircle, Function.Periodic.lift_coe, @@ -121,7 +121,7 @@ theorem fourier_coe_apply' {n : ℤ} {x : ℝ} : toCircle (n • (x : AddCircle T) :) = Complex.exp (2 * π * Complex.I * n * x / T) := by rw [← fourier_apply]; exact fourier_coe_apply --- @[simp] -- Porting note: simp normal form is `fourier_zero'` +-- simp normal form is `fourier_zero'` theorem fourier_zero {x : AddCircle T} : fourier 0 x = 1 := by induction x using QuotientAddGroup.induction_on simp only [fourier_coe_apply] @@ -132,15 +132,14 @@ theorem fourier_zero' {x : AddCircle T} : @toCircle T 0 = (1 : ℂ) := by have : fourier 0 x = @toCircle T 0 := by rw [fourier_apply, zero_smul] rw [← this]; exact fourier_zero --- @[simp] -- Porting note: simp normal form is *also* `fourier_zero'` +-- simp normal form is *also* `fourier_zero'` theorem fourier_eval_zero (n : ℤ) : fourier n (0 : AddCircle T) = 1 := by rw [← QuotientAddGroup.mk_zero, fourier_coe_apply, Complex.ofReal_zero, mul_zero, zero_div, Complex.exp_zero] --- @[simp] -- Porting note (#10618): simp can prove this theorem fourier_one {x : AddCircle T} : fourier 1 x = toCircle x := by rw [fourier_apply, one_zsmul] --- @[simp] -- Porting note: simp normal form is `fourier_neg'` +-- simp normal form is `fourier_neg'` theorem fourier_neg {n : ℤ} {x : AddCircle T} : fourier (-n) x = conj (fourier n x) := by induction x using QuotientAddGroup.induction_on simp_rw [fourier_apply, toCircle] @@ -152,7 +151,7 @@ theorem fourier_neg {n : ℤ} {x : AddCircle T} : fourier (-n) x = conj (fourier theorem fourier_neg' {n : ℤ} {x : AddCircle T} : @toCircle T (-(n • x)) = conj (fourier n x) := by rw [← neg_smul, ← fourier_apply]; exact fourier_neg --- @[simp] -- Porting note: simp normal form is `fourier_add'` +-- simp normal form is `fourier_add'` theorem fourier_add {m n : ℤ} {x : AddCircle T} : fourier (m+n) x = fourier m x * fourier n x := by simp_rw [fourier_apply, add_zsmul, toCircle_add, Circle.coe_mul] @@ -196,9 +195,9 @@ theorem fourierSubalgebra_coe : apply adjoin_eq_span_of_subset refine Subset.trans ?_ Submodule.subset_span intro x hx - refine Submonoid.closure_induction hx (fun _ => id) ⟨0, ?_⟩ ?_ + refine Submonoid.closure_induction (fun _ => id) ⟨0, ?_⟩ ?_ hx · ext1 z; exact fourier_zero - · rintro _ _ ⟨m, rfl⟩ ⟨n, rfl⟩ + · rintro - - - - ⟨m, rfl⟩ ⟨n, rfl⟩ refine ⟨m + n, ?_⟩ ext1 z exact fourier_add @@ -315,7 +314,7 @@ theorem fourierCoeffOn_eq_integral {a b : ℝ} (f : ℝ → E) (n : ℤ) (hab : rw [fourierCoeffOn, fourierCoeff_eq_intervalIntegral _ _ a, add_sub, add_sub_cancel_left] congr 1 simp_rw [intervalIntegral.integral_of_le hab.le] - refine setIntegral_congr measurableSet_Ioc fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioc fun x hx => ?_ rw [liftIoc_coe_apply] rwa [add_sub, add_sub_cancel_left] @@ -344,7 +343,7 @@ theorem fourierCoeff_liftIco_eq {a : ℝ} (f : ℝ → ℂ) (n : ℤ) : congr 1 simp_rw [intervalIntegral.integral_of_le (lt_add_of_pos_right a hT.out).le] iterate 2 rw [integral_Ioc_eq_integral_Ioo] - refine setIntegral_congr measurableSet_Ioo fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioo fun x hx => ?_ rw [liftIco_coe_apply (Ioo_subset_Ico_self hx)] end fourierCoeff diff --git a/Mathlib/Analysis/Fourier/FourierTransform.lean b/Mathlib/Analysis/Fourier/FourierTransform.lean index 8a1b83c8d5e3e..a5d1ddb0067c9 100644 --- a/Mathlib/Analysis/Fourier/FourierTransform.lean +++ b/Mathlib/Analysis/Fourier/FourierTransform.lean @@ -3,13 +3,13 @@ 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.Algebra.Group.AddChar import Mathlib.Analysis.Complex.Circle import Mathlib.MeasureTheory.Group.Integral +import Mathlib.MeasureTheory.Integral.Prod import Mathlib.MeasureTheory.Integral.SetIntegral -import Mathlib.MeasureTheory.Measure.Haar.OfBasis -import Mathlib.MeasureTheory.Constructions.Prod.Integral import Mathlib.MeasureTheory.Measure.Haar.InnerProductSpace -import Mathlib.Algebra.Group.AddChar +import Mathlib.MeasureTheory.Measure.Haar.OfBasis /-! # The Fourier transform diff --git a/Mathlib/Analysis/Fourier/ZMod.lean b/Mathlib/Analysis/Fourier/ZMod.lean index 4fad478f0bc2c..ae3c4f996bbcc 100644 --- a/Mathlib/Analysis/Fourier/ZMod.lean +++ b/Mathlib/Analysis/Fourier/ZMod.lean @@ -201,9 +201,9 @@ end ZMod namespace DirichletCharacter -variable {N : ℕ} [NeZero N] (χ : DirichletCharacter ℂ N) +variable {N : ℕ} [NeZero N] -lemma fourierTransform_eq_gaussSum_mulShift (k : ZMod N) : +lemma fourierTransform_eq_gaussSum_mulShift (χ : DirichletCharacter ℂ N) (k : ZMod N) : 𝓕 χ k = gaussSum χ (stdAddChar.mulShift (-k)) := by simp only [dft_apply, smul_eq_mul] congr 1 with j @@ -211,7 +211,8 @@ lemma fourierTransform_eq_gaussSum_mulShift (k : ZMod N) : /-- For a primitive Dirichlet character `χ`, the Fourier transform of `χ` is a constant multiple of `χ⁻¹` (and the constant is essentially the Gauss sum). -/ -lemma fourierTransform_eq_inv_mul_gaussSum (k : ZMod N) (hχ : IsPrimitive χ) : +lemma IsPrimitive.fourierTransform_eq_inv_mul_gaussSum {χ : DirichletCharacter ℂ N} + (hχ : IsPrimitive χ) (k : ZMod N) : 𝓕 χ k = χ⁻¹ (-k) * gaussSum χ stdAddChar := by rw [fourierTransform_eq_gaussSum_mulShift, gaussSum_mulShift_of_isPrimitive _ hχ] diff --git a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean index 5e1e46a1e699c..39402193d24a1 100644 --- a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean +++ b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean @@ -334,7 +334,7 @@ theorem lintegral_pow_le_pow_lintegral_fderiv_aux [Fintype ι] _ ≤ ∫⁻ xᵢ in Iic (x i), ‖deriv (u ∘ update x i) xᵢ‖₊ := by apply le_trans (by simp) (HasCompactSupport.ennnorm_le_lintegral_Ici_deriv _ _ _) · exact hu.comp (by convert contDiff_update 1 x i) - · exact h2u.comp_closedEmbedding (closedEmbedding_update x i) + · exact h2u.comp_isClosedEmbedding (isClosedEmbedding_update x i) _ ≤ ∫⁻ xᵢ, (‖fderiv ℝ u (update x i xᵢ)‖₊ : ℝ≥0∞) := ?_ gcongr with y; swap · exact Measure.restrict_le_self @@ -489,7 +489,7 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_eq_inner {u : E → F'} have : 0 < p⁻¹ - (n : ℝ)⁻¹ := NNReal.coe_lt_coe.mpr (pos_iff_ne_zero.mpr (inv_ne_zero hp'0)) |>.trans_eq hp' rwa [NNReal.coe_inv, sub_pos, - inv_lt_inv _ (zero_lt_one.trans_le (NNReal.coe_le_coe.mpr hp))] at this + inv_lt_inv₀ _ (zero_lt_one.trans_le (NNReal.coe_le_coe.mpr hp))] at this exact_mod_cast hn have h0n : 2 ≤ n := Nat.succ_le_of_lt <| Nat.one_lt_cast.mp <| hp.trans_lt h2p have hn : NNReal.IsConjExponent n n' := .conjExponent (by norm_cast) @@ -514,7 +514,7 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_eq_inner {u : E → F'} have h0p' : p' ≠ 0 := by suffices 0 < (p' : ℝ) from (show 0 < p' from this) |>.ne' rw [← inv_pos, hp', sub_pos] - exact inv_lt_inv_of_lt hq.pos h2p + exact inv_strictAnti₀ hq.pos h2p have h2q : 1 / n' - 1 / q = 1 / p' := by simp_rw (config := {zeta := false}) [one_div, hp'] rw [← hq.one_sub_inv, ← hn.coe.one_sub_inv, sub_sub_sub_cancel_left] @@ -535,9 +535,9 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_eq_inner {u : E → F'} by_cases h3u : ∫⁻ x, ‖u x‖₊ ^ (p' : ℝ) ∂μ = 0 · rw [eLpNorm_nnreal_eq_lintegral h0p', h3u, ENNReal.zero_rpow_of_pos] <;> positivity have h4u : ∫⁻ x, ‖u x‖₊ ^ (p' : ℝ) ∂μ ≠ ∞ := by - refine lintegral_rpow_nnnorm_lt_top_of_eLpNorm'_lt_top (pos_iff_ne_zero.mpr h0p') ?_ |>.ne - dsimp only - rw [NNReal.val_eq_coe, ← eLpNorm_nnreal_eq_eLpNorm' h0p'] + refine lintegral_rpow_nnnorm_lt_top_of_eLpNorm'_lt_top + ((NNReal.coe_pos.trans pos_iff_ne_zero).mpr h0p') ?_ |>.ne + rw [← eLpNorm_nnreal_eq_eLpNorm' h0p'] exact hu.continuous.memℒp_of_hasCompactSupport (μ := μ) h2u |>.eLpNorm_lt_top have h5u : (∫⁻ x, ‖u x‖₊ ^ (p' : ℝ) ∂μ) ^ (1 / q) ≠ 0 := ENNReal.rpow_pos (pos_iff_ne_zero.mpr h3u) h4u |>.ne' @@ -684,7 +684,7 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_le [FiniteDimensional ℝ F] have : (q : ℝ≥0∞) ≤ p' := by have H : (p' : ℝ)⁻¹ ≤ (↑q)⁻¹ := trans hp' hpq norm_cast at H ⊢ - rwa [inv_le_inv] at H + rwa [inv_le_inv₀] at H · dsimp have : 0 < p⁻¹ - (finrank ℝ E : ℝ≥0)⁻¹ := by simp only [tsub_pos_iff_lt] diff --git a/Mathlib/Analysis/Hofer.lean b/Mathlib/Analysis/Hofer.lean index 3224c5efddfd7..8d5fda97eb89e 100644 --- a/Mathlib/Analysis/Hofer.lean +++ b/Mathlib/Analysis/Hofer.lean @@ -35,7 +35,7 @@ theorem hofer {X : Type*} [MetricSpace X] [CompleteSpace X] (x : X) (ε : ℝ) ( ∃ y, d x' y ≤ ε / 2 ^ k ∧ 2 * ϕ x' < ϕ y := by intro k x' push_neg at H - have := H (ε / 2 ^ k) (by positivity) x' (by simp [ε_pos.le, one_le_two]) + have := H (ε / 2 ^ k) (by positivity) x' (div_le_self ε_pos.le <| one_le_pow₀ one_le_two) simpa [reformulation] using this haveI : Nonempty X := ⟨x⟩ choose! F hF using H diff --git a/Mathlib/Analysis/InnerProductSpace/Adjoint.lean b/Mathlib/Analysis/InnerProductSpace/Adjoint.lean index d70316a5027b3..0537bba885e12 100644 --- a/Mathlib/Analysis/InnerProductSpace/Adjoint.lean +++ b/Mathlib/Analysis/InnerProductSpace/Adjoint.lean @@ -215,6 +215,8 @@ theorem norm_adjoint_comp_self (A : E →L[𝕜] F) : simp_rw [mul_assoc, Real.sqrt_mul (norm_nonneg _) (‖x‖ * ‖x‖), Real.sqrt_mul_self (norm_nonneg x)] +/-- The C⋆-algebra instance when `𝕜 := ℂ` can be found in +`Analysis.CStarAlgebra.ContinuousLinearMap`. -/ instance : CStarRing (E →L[𝕜] E) where norm_mul_self_le x := le_of_eq <| Eq.symm <| norm_adjoint_comp_self x @@ -528,8 +530,8 @@ noncomputable def linearIsometryEquiv : unitary (H →L[𝕜] H) ≃* (H ≃ₗ inv_val := by ext; simp } exact IsUnit.mem_unitary_of_star_mul_self ⟨e', rfl⟩ <| (e : H →L[𝕜] H).norm_map_iff_adjoint_comp_self.mp e.norm_map } - left_inv u := Subtype.ext rfl - right_inv e := LinearIsometryEquiv.ext fun x ↦ rfl + left_inv _ := Subtype.ext rfl + right_inv _ := LinearIsometryEquiv.ext fun _ ↦ rfl map_mul' u v := by ext; rfl @[simp] diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index d4672630df1ed..6862b4376ce2a 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -470,7 +470,7 @@ def toNormedAddCommGroup : NormedAddCommGroup F := simp only [← inner_self_eq_norm_mul_norm, inner_add_add_self, mul_add, mul_comm, map_add] linarith exact nonneg_le_nonneg_of_sq_le_sq (add_nonneg (sqrt_nonneg _) (sqrt_nonneg _)) this - eq_zero_of_map_eq_zero' := fun x hx => + eq_zero_of_map_eq_zero' := fun _ hx => normSq_eq_zero.1 <| (sqrt_eq_zero inner_self_nonneg).1 hx } attribute [local instance] toNormedAddCommGroup @@ -2040,7 +2040,7 @@ theorem OrthogonalFamily.inner_right_dfinsupp ⟪V i v, l.sum fun j => V j⟫ = l.sum fun j => fun w => ⟪V i v, V j w⟫ := DFinsupp.inner_sum (fun j => V j) l (V i v) _ = l.sum fun j => fun w => ite (i = j) ⟪V i v, V j w⟫ 0 := - (congr_arg l.sum <| funext fun j => funext <| hV.eq_ite v) + (congr_arg l.sum <| funext fun _ => funext <| hV.eq_ite v) _ = ⟪v, l i⟫ := by simp only [DFinsupp.sum, Submodule.coe_inner, Finset.sum_ite_eq, ite_eq_left_iff, DFinsupp.mem_support_toFun] @@ -2240,7 +2240,7 @@ def InnerProductSpace.rclikeToReal : InnerProductSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 E with norm_sq_eq_inner := norm_sq_eq_inner - conj_symm := fun x y => inner_re_symm _ _ + conj_symm := fun _ _ => inner_re_symm _ _ add_left := fun x y z => by change re ⟪x + y, z⟫ = re ⟪x, z⟫ + re ⟪y, z⟫ simp only [inner_add_left, map_add] @@ -2368,6 +2368,33 @@ theorem ContinuousLinearMap.reApplyInnerSelf_smul (T : E →L[𝕜] E) (x : E) { end ReApplyInnerSelf_Seminormed +section SeparationQuotient +variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] + +theorem Inseparable.inner_eq_inner {x₁ x₂ y₁ y₂ : E} + (hx : Inseparable x₁ x₂) (hy : Inseparable y₁ y₂) : + inner x₁ y₁ = (inner x₂ y₂ : 𝕜) := + ((hx.prod hy).map continuous_inner).eq + +namespace SeparationQuotient + +instance : Inner 𝕜 (SeparationQuotient E) where + inner := SeparationQuotient.lift₂ Inner.inner fun _ _ _ _ => Inseparable.inner_eq_inner + +@[simp] +theorem inner_mk_mk (x y : E) : + inner (mk x) (mk y) = (inner x y : 𝕜) := rfl + +instance : InnerProductSpace 𝕜 (SeparationQuotient E) where + norm_sq_eq_inner := Quotient.ind norm_sq_eq_inner + conj_symm := Quotient.ind₂ inner_conj_symm + add_left := Quotient.ind fun x => Quotient.ind₂ <| inner_add_left x + smul_left := Quotient.ind₂ inner_smul_left + +end SeparationQuotient + +end SeparationQuotient + section UniformSpace.Completion variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] diff --git a/Mathlib/Analysis/InnerProductSpace/Calculus.lean b/Mathlib/Analysis/InnerProductSpace/Calculus.lean index 44808e4d72423..018aa26547ec5 100644 --- a/Mathlib/Analysis/InnerProductSpace/Calculus.lean +++ b/Mathlib/Analysis/InnerProductSpace/Calculus.lean @@ -6,6 +6,8 @@ Authors: Yury Kudryashov import Mathlib.Analysis.InnerProductSpace.PiL2 import Mathlib.Analysis.SpecialFunctions.Sqrt import Mathlib.Analysis.NormedSpace.HomeomorphBall +import Mathlib.Analysis.Calculus.ContDiff.WithLp +import Mathlib.Analysis.Calculus.FDeriv.WithLp /-! # Calculus in inner product spaces @@ -264,60 +266,52 @@ end DerivInner section PiLike +/-! ### Convenience aliases of `PiLp` lemmas for `EuclideanSpace` -/ + open ContinuousLinearMap variable {𝕜 ι H : Type*} [RCLike 𝕜] [NormedAddCommGroup H] [NormedSpace 𝕜 H] [Fintype ι] {f : H → EuclideanSpace 𝕜 ι} {f' : H →L[𝕜] EuclideanSpace 𝕜 ι} {t : Set H} {y : H} theorem differentiableWithinAt_euclidean : - DifferentiableWithinAt 𝕜 f t y ↔ ∀ i, DifferentiableWithinAt 𝕜 (fun x => f x i) t y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_differentiableWithinAt_iff, differentiableWithinAt_pi] - rfl + DifferentiableWithinAt 𝕜 f t y ↔ ∀ i, DifferentiableWithinAt 𝕜 (fun x => f x i) t y := + differentiableWithinAt_piLp _ theorem differentiableAt_euclidean : - DifferentiableAt 𝕜 f y ↔ ∀ i, DifferentiableAt 𝕜 (fun x => f x i) y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_differentiableAt_iff, differentiableAt_pi] - rfl + DifferentiableAt 𝕜 f y ↔ ∀ i, DifferentiableAt 𝕜 (fun x => f x i) y := + differentiableAt_piLp _ theorem differentiableOn_euclidean : - DifferentiableOn 𝕜 f t ↔ ∀ i, DifferentiableOn 𝕜 (fun x => f x i) t := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_differentiableOn_iff, differentiableOn_pi] - rfl + DifferentiableOn 𝕜 f t ↔ ∀ i, DifferentiableOn 𝕜 (fun x => f x i) t := + differentiableOn_piLp _ -theorem differentiable_euclidean : Differentiable 𝕜 f ↔ ∀ i, Differentiable 𝕜 fun x => f x i := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_differentiable_iff, differentiable_pi] - rfl +theorem differentiable_euclidean : Differentiable 𝕜 f ↔ ∀ i, Differentiable 𝕜 fun x => f x i := + differentiable_piLp _ theorem hasStrictFDerivAt_euclidean : HasStrictFDerivAt f f' y ↔ - ∀ i, HasStrictFDerivAt (fun x => f x i) (EuclideanSpace.proj i ∘L f') y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_hasStrictFDerivAt_iff, hasStrictFDerivAt_pi'] - rfl + ∀ i, HasStrictFDerivAt (fun x => f x i) (PiLp.proj _ _ i ∘L f') y := + hasStrictFDerivAt_piLp _ theorem hasFDerivWithinAt_euclidean : HasFDerivWithinAt f f' t y ↔ - ∀ i, HasFDerivWithinAt (fun x => f x i) (EuclideanSpace.proj i ∘L f') t y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_hasFDerivWithinAt_iff, hasFDerivWithinAt_pi'] - rfl + ∀ i, HasFDerivWithinAt (fun x => f x i) (PiLp.proj _ _ i ∘L f') t y := + hasFDerivWithinAt_piLp _ theorem contDiffWithinAt_euclidean {n : ℕ∞} : - ContDiffWithinAt 𝕜 n f t y ↔ ∀ i, ContDiffWithinAt 𝕜 n (fun x => f x i) t y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_contDiffWithinAt_iff, contDiffWithinAt_pi] - rfl + ContDiffWithinAt 𝕜 n f t y ↔ ∀ i, ContDiffWithinAt 𝕜 n (fun x => f x i) t y := + contDiffWithinAt_piLp _ theorem contDiffAt_euclidean {n : ℕ∞} : - ContDiffAt 𝕜 n f y ↔ ∀ i, ContDiffAt 𝕜 n (fun x => f x i) y := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_contDiffAt_iff, contDiffAt_pi] - rfl + ContDiffAt 𝕜 n f y ↔ ∀ i, ContDiffAt 𝕜 n (fun x => f x i) y := + contDiffAt_piLp _ theorem contDiffOn_euclidean {n : ℕ∞} : - ContDiffOn 𝕜 n f t ↔ ∀ i, ContDiffOn 𝕜 n (fun x => f x i) t := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_contDiffOn_iff, contDiffOn_pi] - rfl + 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 := by - rw [← (EuclideanSpace.equiv ι 𝕜).comp_contDiff_iff, contDiff_pi] - rfl +theorem contDiff_euclidean {n : ℕ∞} : ContDiff 𝕜 n f ↔ ∀ i, ContDiff 𝕜 n fun x => f x i := + contDiff_piLp _ end PiLike diff --git a/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean b/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean index 4ab4ac3e7b9f6..8d89fc6d5f0b7 100644 --- a/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean +++ b/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean @@ -52,7 +52,7 @@ open RCLike open scoped ComplexConjugate Classical -variable {𝕜 E F G : Type*} [RCLike 𝕜] +variable {𝕜 E F : Type*} [RCLike 𝕜] variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] variable [NormedAddCommGroup F] [InnerProductSpace 𝕜 F] @@ -103,7 +103,7 @@ variable (hT : Dense (T.domain : Set E)) /-- The unique continuous extension of the operator `adjointDomainMkCLM` to `E`. -/ def adjointDomainMkCLMExtend (y : T.adjointDomain) : E →L[𝕜] 𝕜 := (T.adjointDomainMkCLM y).extend (Submodule.subtypeL T.domain) hT.denseRange_val - isUniformEmbedding_subtype_val.toUniformInducing + isUniformEmbedding_subtype_val.isUniformInducing @[simp] theorem adjointDomainMkCLMExtend_apply (y : T.adjointDomain) (x : T.domain) : diff --git a/Mathlib/Analysis/InnerProductSpace/OfNorm.lean b/Mathlib/Analysis/InnerProductSpace/OfNorm.lean index e2e23c0b46a9d..b62522a0e45d6 100644 --- a/Mathlib/Analysis/InnerProductSpace/OfNorm.lean +++ b/Mathlib/Analysis/InnerProductSpace/OfNorm.lean @@ -194,7 +194,7 @@ private theorem rat_prop (r : ℚ) : innerProp' E (r : 𝕜) := by private theorem real_prop (r : ℝ) : innerProp' E (r : 𝕜) := by intro x y revert r - rw [← Function.funext_iff] + rw [← funext_iff] refine Rat.isDenseEmbedding_coe_real.dense.equalizer ?_ ?_ (funext fun X => ?_) · exact (continuous_ofReal.smul continuous_const).inner_ continuous_const · exact (continuous_conj.comp continuous_ofReal).mul continuous_const diff --git a/Mathlib/Analysis/InnerProductSpace/PiL2.lean b/Mathlib/Analysis/InnerProductSpace/PiL2.lean index 5fb4aa1c20293..3a77d1f7c5328 100644 --- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean +++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean @@ -200,18 +200,11 @@ abbrev EuclideanSpace.equiv : EuclideanSpace 𝕜 ι ≃L[𝕜] ι → 𝕜 := variable {ι 𝕜} --- TODO : This should be generalized to `PiLp`. /-- The projection on the `i`-th coordinate of `EuclideanSpace 𝕜 ι`, as a linear map. -/ -@[simps!] -def EuclideanSpace.projₗ (i : ι) : EuclideanSpace 𝕜 ι →ₗ[𝕜] 𝕜 := - (LinearMap.proj i).comp (WithLp.linearEquiv 2 𝕜 (ι → 𝕜) : EuclideanSpace 𝕜 ι →ₗ[𝕜] ι → 𝕜) +abbrev EuclideanSpace.projₗ (i : ι) : EuclideanSpace 𝕜 ι →ₗ[𝕜] 𝕜 := PiLp.projₗ _ _ i --- TODO : This should be generalized to `PiLp`. -/-- The projection on the `i`-th coordinate of `EuclideanSpace 𝕜 ι`, -as a continuous linear map. -/ -@[simps! apply coe] -def EuclideanSpace.proj (i : ι) : EuclideanSpace 𝕜 ι →L[𝕜] 𝕜 := - ⟨EuclideanSpace.projₗ i, continuous_apply i⟩ +/-- The projection on the `i`-th coordinate of `EuclideanSpace 𝕜 ι`, as a continuous linear map. -/ +abbrev EuclideanSpace.proj (i : ι) : EuclideanSpace 𝕜 ι →L[𝕜] 𝕜 := PiLp.proj _ _ i section DecEq @@ -306,7 +299,6 @@ theorem repr_injective : cases g congr --- Porting note: `CoeFun` → `FunLike` /-- `b i` is the `i`th basis vector. -/ instance instFunLike : FunLike (OrthonormalBasis ι 𝕜 E) ι E where coe b i := by classical exact b.repr.symm (EuclideanSpace.single i (1 : 𝕜)) diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index 17223b1faf998..6edcc178e0c8e 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -621,7 +621,6 @@ section reflection variable [HasOrthogonalProjection K] --- Porting note: `bit0` is deprecated. /-- Auxiliary definition for `reflection`: the reflection as a linear equivalence. -/ def reflectionLinearEquiv : E ≃ₗ[𝕜] E := LinearEquiv.ofInvolutive @@ -863,12 +862,13 @@ theorem orthogonalProjection_orthogonalProjection_of_le {U V : Submodule 𝕜 E} /-- Given a monotone family `U` of complete submodules of `E` and a fixed `x : E`, the orthogonal projection of `x` on `U i` tends to the orthogonal projection of `x` on `(⨆ i, U i).topologicalClosure` along `atTop`. -/ -theorem orthogonalProjection_tendsto_closure_iSup [CompleteSpace E] {ι : Type*} [SemilatticeSup ι] - (U : ι → Submodule 𝕜 E) [∀ i, CompleteSpace (U i)] (hU : Monotone U) (x : E) : +theorem orthogonalProjection_tendsto_closure_iSup {ι : Type*} [Preorder ι] + (U : ι → Submodule 𝕜 E) [∀ i, HasOrthogonalProjection (U i)] + [HasOrthogonalProjection (⨆ i, U i).topologicalClosure] (hU : Monotone U) (x : E) : Filter.Tendsto (fun i => (orthogonalProjection (U i) x : E)) atTop (𝓝 (orthogonalProjection (⨆ i, U i).topologicalClosure x : E)) := by - cases isEmpty_or_nonempty ι - · exact tendsto_of_isEmpty + refine .of_neBot_imp fun h ↦ ?_ + cases atTop_neBot_iff.mp h let y := (orthogonalProjection (⨆ i, U i).topologicalClosure x : E) have proj_x : ∀ i, orthogonalProjection (U i) x = orthogonalProjection (U i) y := fun i => (orthogonalProjection_orthogonalProjection_of_le @@ -890,14 +890,15 @@ theorem orthogonalProjection_tendsto_closure_iSup [CompleteSpace E] {ι : Type*} /-- Given a monotone family `U` of complete submodules of `E` with dense span supremum, and a fixed `x : E`, the orthogonal projection of `x` on `U i` tends to `x` along `at_top`. -/ -theorem orthogonalProjection_tendsto_self [CompleteSpace E] {ι : Type*} [SemilatticeSup ι] - (U : ι → Submodule 𝕜 E) [∀ t, CompleteSpace (U t)] (hU : Monotone U) (x : E) +theorem orthogonalProjection_tendsto_self {ι : Type*} [Preorder ι] + (U : ι → Submodule 𝕜 E) [∀ t, HasOrthogonalProjection (U t)] (hU : Monotone U) (x : E) (hU' : ⊤ ≤ (⨆ t, U t).topologicalClosure) : Filter.Tendsto (fun t => (orthogonalProjection (U t) x : E)) atTop (𝓝 x) := by - rw [← eq_top_iff] at hU' + have : HasOrthogonalProjection (⨆ i, U i).topologicalClosure := by + rw [top_unique hU'] + infer_instance convert orthogonalProjection_tendsto_closure_iSup U hU x - rw [orthogonalProjection_eq_self_iff.mpr _] - rw [hU'] + rw [eq_comm, orthogonalProjection_eq_self_iff, top_unique hU'] trivial /-- The orthogonal complement satisfies `Kᗮᗮᗮ = Kᗮ`. -/ diff --git a/Mathlib/Analysis/InnerProductSpace/StarOrder.lean b/Mathlib/Analysis/InnerProductSpace/StarOrder.lean index 7ed9ab6de0e4b..371413581895d 100644 --- a/Mathlib/Analysis/InnerProductSpace/StarOrder.lean +++ b/Mathlib/Analysis/InnerProductSpace/StarOrder.lean @@ -5,6 +5,7 @@ Authors: Jireh Loreaux -/ import Mathlib.Analysis.InnerProductSpace.Positive import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances +import Mathlib.Analysis.CStarAlgebra.ContinuousLinearMap /-! # Continuous linear maps on a Hilbert space are a `StarOrderedRing` @@ -63,12 +64,12 @@ lemma instStarOrderedRingRCLike exact AddSubmonoid.subset_closure ⟨p, by simp only [hp₁.star_eq, sq]⟩ · rintro ⟨p, hp, rfl⟩ rw [le_def, add_sub_cancel_left] - induction hp using AddSubmonoid.closure_induction' with + induction hp using AddSubmonoid.closure_induction with | mem _ hf => obtain ⟨f, rfl⟩ := hf simpa using ContinuousLinearMap.IsPositive.adjoint_conj isPositive_one f | one => exact isPositive_zero - | mul f _ g _ hf hg => exact hf.add hg + | mul f g _ _ hf hg => exact hf.add hg instance instStarOrderedRing {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] : StarOrderedRing (H →L[ℂ] H) := diff --git a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean index 9acf7b33a0635..2fcd08ccaa66d 100644 --- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean +++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean @@ -38,11 +38,8 @@ open ComplexConjugate section Seminormed -variable {𝕜 E E' F G : Type*} [RCLike 𝕜] +variable {𝕜 E : Type*} [RCLike 𝕜] variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] -variable [SeminormedAddCommGroup F] [InnerProductSpace 𝕜 F] -variable [SeminormedAddCommGroup G] [InnerProductSpace 𝕜 G] -variable [SeminormedAddCommGroup E'] [InnerProductSpace ℝ E'] local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y @@ -189,11 +186,8 @@ end Seminormed section Normed -variable {𝕜 E E' F G : Type*} [RCLike 𝕜] +variable {𝕜 E : Type*} [RCLike 𝕜] variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] -variable [NormedAddCommGroup F] [InnerProductSpace 𝕜 F] -variable [NormedAddCommGroup G] [InnerProductSpace 𝕜 G] -variable [NormedAddCommGroup E'] [InnerProductSpace ℝ E'] local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y diff --git a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean index 329dd441e2adc..a68bcb961c62e 100644 --- a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean +++ b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean @@ -260,7 +260,6 @@ theorem rightAngleRotation_symm : rw [rightAngleRotation] exact LinearIsometryEquiv.toLinearIsometry_injective rfl --- @[simp] -- Porting note (#10618): simp already proves this theorem inner_rightAngleRotation_self (x : E) : ⟪J x, x⟫ = 0 := by simp theorem inner_rightAngleRotation_swap (x y : E) : ⟪x, J y⟫ = -⟪J x, y⟫ := by simp @@ -279,7 +278,6 @@ theorem areaForm_rightAngleRotation_left (x y : E) : ω (J x) y = -⟪x, y⟫ := theorem areaForm_rightAngleRotation_right (x y : E) : ω x (J y) = ⟪x, y⟫ := by rw [← o.inner_rightAngleRotation_left, o.inner_comp_rightAngleRotation] --- @[simp] -- Porting note (#10618): simp already proves this theorem areaForm_comp_rightAngleRotation (x y : E) : ω (J x) (J y) = ω x y := by simp @[simp] diff --git a/Mathlib/Analysis/InnerProductSpace/l2Space.lean b/Mathlib/Analysis/InnerProductSpace/l2Space.lean index 9eb925f593b03..54a08fc3d190b 100644 --- a/Mathlib/Analysis/InnerProductSpace/l2Space.lean +++ b/Mathlib/Analysis/InnerProductSpace/l2Space.lean @@ -249,7 +249,7 @@ protected theorem range_linearIsometry [∀ i, CompleteSpace (G i)] : rintro i x ⟨x, rfl⟩ use lp.single 2 i x exact hV.linearIsometry_apply_single x - exact hV.linearIsometry.isometry.uniformInducing.isComplete_range.isClosed + exact hV.linearIsometry.isometry.isUniformInducing.isComplete_range.isClosed end OrthogonalFamily diff --git a/Mathlib/Analysis/LocallyConvex/AbsConvex.lean b/Mathlib/Analysis/LocallyConvex/AbsConvex.lean index 5cf175db643ff..f7f1bf219971d 100644 --- a/Mathlib/Analysis/LocallyConvex/AbsConvex.lean +++ b/Mathlib/Analysis/LocallyConvex/AbsConvex.lean @@ -6,27 +6,38 @@ Authors: Moritz Doll import Mathlib.Analysis.LocallyConvex.BalancedCoreHull import Mathlib.Analysis.LocallyConvex.WithSeminorms import Mathlib.Analysis.Convex.Gauge +import Mathlib.Analysis.Convex.TotallyBounded /-! # Absolutely convex sets -A set is called absolutely convex or disked if it is convex and balanced. -The importance of absolutely convex sets comes from the fact that every locally convex +A set `s` in an commutative monoid `E` is called absolutely convex or disked if it is convex and +balanced. The importance of absolutely convex sets comes from the fact that every locally convex topological vector space has a basis consisting of absolutely convex sets. ## Main definitions +* `absConvexHull`: the absolutely convex hull of a set `s` is the smallest absolutely convex set + containing `s`. * `gaugeSeminormFamily`: the seminorm family induced by all open absolutely convex neighborhoods of zero. ## Main statements +* `absConvexHull_eq_convexHull_balancedHull`: when the locally convex space is a module, the + absolutely convex hull of a set `s` equals the convex hull of the balanced hull of `s`. +* `convexHull_union_neg_eq_absConvexHull`: the convex hull of `s ∪ -s` is the absolute convex hull + of `s`. * `with_gaugeSeminormFamily`: the topology of a locally convex space is induced by the family `gaugeSeminormFamily`. -## TODO +## Implementation notes -* Define the disked hull +Mathlib's definition of `Convex` requires the scalars to be an `OrderedSemiring` whereas the +definition of `Balanced` requires the scalars to be a `SeminormedRing`. Mathlib doesn't currently +have a concept of a semi-normed ordered ring, so we define a set as `AbsConvex` if it is balanced +over a `SeminormedRing` `𝕜` and convex over `ℝ`, assuming `IsScalarTower ℝ 𝕜 E` and +`SMulCommClass ℝ 𝕜 E` where required. ## Tags @@ -38,17 +49,115 @@ open NormedField Set open NNReal Pointwise Topology -variable {𝕜 E F G ι : Type*} +variable {𝕜 E : Type*} + +section AbsolutelyConvex + +variable (𝕜) [SeminormedRing 𝕜] [SMul 𝕜 E] [SMul ℝ E] [AddCommMonoid E] +/-- A set is absolutely convex if it is balanced and convex. Mathlib's definition of `Convex` +requires the scalars to be an `OrderedSemiring` whereas the definition of `Balanced` requires the +scalars to be a `SeminormedRing`. Mathlib doesn't currently have a concept of a semi-normed ordered +ring, so we define a set as `AbsConvex` if it is balanced over a `SeminormedRing` `𝕜` and convex +over `ℝ`. -/ +def AbsConvex (s : Set E) : Prop := Balanced 𝕜 s ∧ Convex ℝ s + +variable {𝕜} + +theorem AbsConvex.empty : AbsConvex 𝕜 (∅ : Set E) := ⟨balanced_empty, convex_empty⟩ + +theorem AbsConvex.univ : AbsConvex 𝕜 (univ : Set E) := ⟨balanced_univ, convex_univ⟩ + +theorem AbsConvex.inter {s t : Set E} (hs : AbsConvex 𝕜 s) (ht : AbsConvex 𝕜 t) : + AbsConvex 𝕜 (s ∩ t) := ⟨hs.1.inter ht.1, hs.2.inter ht.2⟩ + +theorem AbsConvex.sInter {S : Set (Set E)} (h : ∀ s ∈ S, AbsConvex 𝕜 s) : AbsConvex 𝕜 (⋂₀ S) := + ⟨.sInter fun s hs => (h s hs).1, convex_sInter fun s hs => (h s hs).2⟩ + +theorem AbsConvex.iInter {ι : Sort*} {s : ι → Set E} (h : ∀ i, AbsConvex 𝕜 (s i)) : + AbsConvex 𝕜 (⋂ i, s i) := + sInter_range s ▸ AbsConvex.sInter <| forall_mem_range.2 h + +variable (𝕜) + +/-- The absolute convex hull of a set `s` is the minimal absolute convex set that includes `s`. -/ +@[simps! isClosed] +def absConvexHull : ClosureOperator (Set E) := + .ofCompletePred (AbsConvex 𝕜) fun _ ↦ .sInter + +variable {𝕜} {s : Set E} + +theorem subset_absConvexHull : s ⊆ absConvexHull 𝕜 s := + (absConvexHull 𝕜).le_closure s + +theorem absConvex_absConvexHull : AbsConvex 𝕜 (absConvexHull 𝕜 s) := + (absConvexHull 𝕜).isClosed_closure s + +theorem balanced_absConvexHull : Balanced 𝕜 (absConvexHull 𝕜 s) := + absConvex_absConvexHull.1 + +theorem convex_absConvexHull : Convex ℝ (absConvexHull 𝕜 s) := + absConvex_absConvexHull.2 + +variable (𝕜 s) in +theorem absConvexHull_eq_iInter : + absConvexHull 𝕜 s = ⋂ (t : Set E) (_ : s ⊆ t) (_ : AbsConvex 𝕜 t), t := by + simp [absConvexHull, iInter_subtype, iInter_and] + +variable {t : Set E} {x : E} + +theorem mem_absConvexHull_iff : x ∈ absConvexHull 𝕜 s ↔ ∀ t, s ⊆ t → AbsConvex 𝕜 t → x ∈ t := by + simp_rw [absConvexHull_eq_iInter, mem_iInter] + +theorem absConvexHull_min : s ⊆ t → AbsConvex 𝕜 t → absConvexHull 𝕜 s ⊆ t := + (absConvexHull 𝕜).closure_min + +theorem AbsConvex.absConvexHull_subset_iff (ht : AbsConvex 𝕜 t) : absConvexHull 𝕜 s ⊆ t ↔ s ⊆ t := + (show (absConvexHull 𝕜).IsClosed t from ht).closure_le_iff + +@[mono, gcongr] +theorem absConvexHull_mono (hst : s ⊆ t) : absConvexHull 𝕜 s ⊆ absConvexHull 𝕜 t := + (absConvexHull 𝕜).monotone hst + +lemma absConvexHull_eq_self : absConvexHull 𝕜 s = s ↔ AbsConvex 𝕜 s := + (absConvexHull 𝕜).isClosed_iff.symm + +alias ⟨_, AbsConvex.absConvexHull_eq⟩ := absConvexHull_eq_self + +@[simp] +theorem absConvexHull_univ : absConvexHull 𝕜 (univ : Set E) = univ := + ClosureOperator.closure_top (absConvexHull 𝕜) + +@[simp] +theorem absConvexHull_empty : absConvexHull 𝕜 (∅ : Set E) = ∅ := + AbsConvex.empty.absConvexHull_eq + +@[simp] +theorem absConvexHull_eq_empty : absConvexHull 𝕜 s = ∅ ↔ s = ∅ := by + constructor + · intro h + rw [← Set.subset_empty_iff, ← h] + exact subset_absConvexHull + · rintro rfl + exact absConvexHull_empty + +@[simp] +theorem absConvexHull_nonempty : (absConvexHull 𝕜 s).Nonempty ↔ s.Nonempty := by + rw [nonempty_iff_ne_empty, nonempty_iff_ne_empty, Ne, Ne] + exact not_congr absConvexHull_eq_empty + +protected alias ⟨_, Set.Nonempty.absConvexHull⟩ := absConvexHull_nonempty + +end AbsolutelyConvex section NontriviallyNormedField -variable (𝕜 E) {s : Set E} +variable (𝕜 E) variable [NontriviallyNormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] variable [Module ℝ E] [SMulCommClass ℝ 𝕜 E] variable [TopologicalSpace E] [LocallyConvexSpace ℝ E] [ContinuousSMul 𝕜 E] -theorem nhds_basis_abs_convex : - (𝓝 (0 : E)).HasBasis (fun s : Set E => s ∈ 𝓝 (0 : E) ∧ Balanced 𝕜 s ∧ Convex ℝ s) id := by +theorem nhds_hasBasis_absConvex : + (𝓝 (0 : E)).HasBasis (fun s : Set E => s ∈ 𝓝 (0 : E) ∧ AbsConvex 𝕜 s) id := by refine (LocallyConvexSpace.convex_basis_zero ℝ E).to_hasBasis (fun s hs => ?_) fun s hs => ⟨s, ⟨hs.1, hs.2.2⟩, rfl.subset⟩ @@ -59,9 +168,9 @@ theorem nhds_basis_abs_convex : variable [ContinuousSMul ℝ E] [TopologicalAddGroup E] -theorem nhds_basis_abs_convex_open : - (𝓝 (0 : E)).HasBasis (fun s => (0 : E) ∈ s ∧ IsOpen s ∧ Balanced 𝕜 s ∧ Convex ℝ s) id := by - refine (nhds_basis_abs_convex 𝕜 E).to_hasBasis ?_ ?_ +theorem nhds_hasBasis_absConvex_open : + (𝓝 (0 : E)).HasBasis (fun s => (0 : E) ∈ s ∧ IsOpen s ∧ AbsConvex 𝕜 s) id := by + refine (nhds_hasBasis_absConvex 𝕜 E).to_hasBasis ?_ ?_ · rintro s ⟨hs_nhds, hs_balanced, hs_convex⟩ refine ⟨interior s, ?_, interior_subset⟩ exact @@ -72,6 +181,78 @@ theorem nhds_basis_abs_convex_open : end NontriviallyNormedField +section + +variable (𝕜) [NontriviallyNormedField 𝕜] +variable [AddCommGroup E] [Module ℝ E] [Module 𝕜 E] + +theorem absConvexHull_add_subset {s t : Set E} : + absConvexHull 𝕜 (s + t) ⊆ absConvexHull 𝕜 s + absConvexHull 𝕜 t := + absConvexHull_min (add_subset_add subset_absConvexHull subset_absConvexHull) + ⟨Balanced.add balanced_absConvexHull balanced_absConvexHull, + Convex.add convex_absConvexHull convex_absConvexHull⟩ + +theorem absConvexHull_eq_convexHull_balancedHull [SMulCommClass ℝ 𝕜 E] {s : Set E} : + absConvexHull 𝕜 s = convexHull ℝ (balancedHull 𝕜 s) := le_antisymm + (absConvexHull_min + ((subset_convexHull ℝ s).trans (convexHull_mono (subset_balancedHull 𝕜))) + ⟨Balanced.convexHull (balancedHull.balanced s), convex_convexHull ..⟩) + (convexHull_min (balanced_absConvexHull.balancedHull_subset_of_subset subset_absConvexHull) + convex_absConvexHull) + +/-- In general, equality doesn't hold here - e.g. consider `s := {(-1, 1), (1, 1)}` in `ℝ²`. -/ +theorem balancedHull_convexHull_subseteq_absConvexHull {s : Set E} : + balancedHull 𝕜 (convexHull ℝ s) ⊆ absConvexHull 𝕜 s := + balanced_absConvexHull.balancedHull_subset_of_subset + (convexHull_min subset_absConvexHull convex_absConvexHull) + +end + +section + +variable [AddCommGroup E] [Module ℝ E] + +lemma balancedHull_subset_convexHull_union_neg {s : Set E} : + balancedHull ℝ s ⊆ convexHull ℝ (s ∪ -s) := by + intro a ha + obtain ⟨r, hr, y, hy, rfl⟩ := mem_balancedHull_iff.1 ha + apply segment_subset_convexHull (mem_union_left (-s) hy) (mem_union_right _ (neg_mem_neg.mpr hy)) + refine ⟨(1 + r)/2, (1 - r)/2, ?_, ?_⟩ + · rw [← zero_div 2] + exact (div_le_div_right zero_lt_two).mpr (neg_le_iff_add_nonneg'.mp (neg_le_of_abs_le hr)) + · constructor + · rw [← zero_div 2] + exact (div_le_div_right zero_lt_two).mpr (sub_nonneg_of_le (le_of_max_le_left hr)) + · constructor + · ring_nf + · rw [smul_neg, ← sub_eq_add_neg, ← sub_smul] + apply congrFun (congrArg HSMul.hSMul _) y + ring_nf + +@[simp] +theorem convexHull_union_neg_eq_absConvexHull {s : Set E} : + convexHull ℝ (s ∪ -s) = absConvexHull ℝ s := by + rw [absConvexHull_eq_convexHull_balancedHull] + exact le_antisymm (convexHull_mono (union_subset (subset_balancedHull ℝ) + (fun _ _ => by rw [mem_balancedHull_iff]; use -1; aesop))) + (by + rw [← Convex.convexHull_eq (convex_convexHull ℝ (s ∪ -s))] + exact convexHull_mono balancedHull_subset_convexHull_union_neg) + +variable (E 𝕜) {s : Set E} +variable [NontriviallyNormedField 𝕜] [Module 𝕜 E] [SMulCommClass ℝ 𝕜 E] +variable [UniformSpace E] [UniformAddGroup E] [lcs : LocallyConvexSpace ℝ E] [ContinuousSMul ℝ E] + +-- TVS II.25 Prop3 +theorem totallyBounded_absConvexHull (hs : TotallyBounded s) : + TotallyBounded (absConvexHull ℝ s) := by + rw [← convexHull_union_neg_eq_absConvexHull] + apply totallyBounded_convexHull + rw [totallyBounded_union] + exact ⟨hs, totallyBounded_neg hs⟩ + +end + section AbsolutelyConvexSets variable [TopologicalSpace E] [AddCommMonoid E] [Zero E] [SeminormedRing 𝕜] @@ -80,7 +261,7 @@ variable (𝕜 E) /-- The type of absolutely convex open sets. -/ def AbsConvexOpenSets := - { s : Set E // (0 : E) ∈ s ∧ IsOpen s ∧ Balanced 𝕜 s ∧ Convex ℝ s } + { s : Set E // (0 : E) ∈ s ∧ IsOpen s ∧ AbsConvex 𝕜 s } noncomputable instance AbsConvexOpenSets.instCoeTC : CoeTC (AbsConvexOpenSets 𝕜 E) (Set E) := ⟨Subtype.val⟩ @@ -139,7 +320,7 @@ variable [SMulCommClass ℝ 𝕜 E] [LocallyConvexSpace ℝ E] /-- The topology of a locally convex space is induced by the gauge seminorm family. -/ theorem with_gaugeSeminormFamily : WithSeminorms (gaugeSeminormFamily 𝕜 E) := by refine SeminormFamily.withSeminorms_of_hasBasis _ ?_ - refine (nhds_basis_abs_convex_open 𝕜 E).to_hasBasis (fun s hs => ?_) fun s hs => ?_ + refine (nhds_hasBasis_absConvex_open 𝕜 E).to_hasBasis (fun s hs => ?_) fun s hs => ?_ · refine ⟨s, ⟨?_, rfl.subset⟩⟩ convert (gaugeSeminormFamily _ _).basisSets_singleton_mem ⟨s, hs⟩ one_pos rw [gaugeSeminormFamily_ball, Subtype.coe_mk] @@ -152,7 +333,7 @@ theorem with_gaugeSeminormFamily : WithSeminorms (gaugeSeminormFamily 𝕜 E) := ⟨mem_iInter₂.mpr fun _ _ => by simp [Seminorm.mem_ball_zero, hr], isOpen_biInter_finset fun S _ => ?_, balanced_iInter₂ fun _ _ => Seminorm.balanced_ball_zero _ _, - convex_iInter₂ fun _ _ => Seminorm.convex_ball _ _ _⟩ + convex_iInter₂ fun _ _ => Seminorm.convex_ball ..⟩ -- The only nontrivial part is to show that the ball is open have hr' : r = ‖(r : 𝕜)‖ * 1 := by simp [abs_of_pos hr] have hr'' : (r : 𝕜) ≠ 0 := by simp [hr.ne'] diff --git a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean index 850c1e5f491d0..bf2b65c776bf0 100644 --- a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean +++ b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean @@ -104,6 +104,14 @@ theorem Balanced.balancedHull_subset_of_subset (ht : Balanced 𝕜 t) (h : s ⊆ obtain ⟨r, hr, y, hy, rfl⟩ := mem_balancedHull_iff.1 hx exact ht.smul_mem hr (h hy) +@[mono, gcongr] +theorem balancedHull_mono (hst : s ⊆ t) : balancedHull 𝕜 s ⊆ balancedHull 𝕜 t := by + intro x hx + rw [mem_balancedHull_iff] at * + obtain ⟨r, hr₁, hr₂⟩ := hx + use r + exact ⟨hr₁, smul_set_mono hst hr₂⟩ + end SMul section Module @@ -133,6 +141,12 @@ theorem balancedHull.balanced (s : Set E) : Balanced 𝕜 (balancedHull 𝕜 s) rw [← smul_assoc] at hx exact ⟨a • r, (SeminormedRing.norm_mul _ _).trans (mul_le_one₀ ha (norm_nonneg r) hr), hx⟩ +open Balanced in +theorem balancedHull_add_subset [NormOneClass 𝕜] {t : Set E} : + balancedHull 𝕜 (s + t) ⊆ balancedHull 𝕜 s + balancedHull 𝕜 t := + balancedHull_subset_of_subset (add (balancedHull.balanced _) (balancedHull.balanced _)) + (add_subset_add (subset_balancedHull _) (subset_balancedHull _)) + end Module end SeminormedRing @@ -158,7 +172,7 @@ theorem balancedCoreAux_balanced (h0 : (0 : E) ∈ balancedCoreAux 𝕜 s) : intro r hr have h'' : 1 ≤ ‖a⁻¹ • r‖ := by rw [norm_smul, norm_inv] - exact one_le_mul_of_one_le_of_one_le (one_le_inv (norm_pos_iff.mpr h) ha) hr + exact one_le_mul_of_one_le_of_one_le ((one_le_inv₀ (norm_pos_iff.mpr h)).2 ha) hr have h' := hy (a⁻¹ • r) h'' rwa [smul_assoc, mem_inv_smul_set_iff₀ h] at h' @@ -167,7 +181,7 @@ theorem balancedCoreAux_maximal (h : t ⊆ s) (ht : Balanced 𝕜 t) : t ⊆ bal rw [mem_smul_set_iff_inv_smul_mem₀ (norm_pos_iff.mp <| zero_lt_one.trans_le hr)] refine h (ht.smul_mem ?_ hx) rw [norm_inv] - exact inv_le_one hr + exact inv_le_one_of_one_le₀ hr theorem balancedCore_subset_balancedCoreAux : balancedCore 𝕜 s ⊆ balancedCoreAux 𝕜 s := balancedCoreAux_maximal (balancedCore_subset s) (balancedCore_balanced s) @@ -185,7 +199,7 @@ theorem subset_balancedCore (ht : (0 : E) ∈ t) (hst : ∀ a : 𝕜, ‖a‖ rw [subset_set_smul_iff₀ (norm_pos_iff.mp <| zero_lt_one.trans_le ha)] apply hst rw [norm_inv] - exact inv_le_one ha + exact inv_le_one_of_one_le₀ ha end NormedField diff --git a/Mathlib/Analysis/LocallyConvex/Basic.lean b/Mathlib/Analysis/LocallyConvex/Basic.lean index 4b242d6809928..ffe0e4d997485 100644 --- a/Mathlib/Analysis/LocallyConvex/Basic.lean +++ b/Mathlib/Analysis/LocallyConvex/Basic.lean @@ -50,7 +50,7 @@ variable [SeminormedRing 𝕜] section SMul -variable [SMul 𝕜 E] {s t u v A B : Set E} +variable [SMul 𝕜 E] {s A B : Set E} variable (𝕜) /-- A set `A` is balanced if `a • A` is contained in `A` whenever `a` has norm at most `1`. -/ @@ -95,6 +95,9 @@ theorem balanced_iUnion₂ {f : ∀ i, κ i → Set E} (h : ∀ i j, Balanced Balanced 𝕜 (⋃ (i) (j), f i j) := balanced_iUnion fun _ => balanced_iUnion <| h _ +theorem Balanced.sInter {S : Set (Set E)} (h : ∀ s ∈ S, Balanced 𝕜 s) : Balanced 𝕜 (⋂₀ S) := + fun _ _ => (smul_set_sInter_subset ..).trans (fun _ _ => by aesop) + theorem balanced_iInter {f : ι → Set E} (h : ∀ i, Balanced 𝕜 (f i)) : Balanced 𝕜 (⋂ i, f i) := fun _a ha => (smul_set_iInter_subset _ _).trans <| iInter_mono fun _ => h _ _ ha @@ -111,7 +114,7 @@ end SMul section Module -variable [AddCommGroup E] [Module 𝕜 E] {s s₁ s₂ t t₁ t₂ : Set E} +variable [AddCommGroup E] [Module 𝕜 E] {s t : Set E} theorem Balanced.neg : Balanced 𝕜 s → Balanced 𝕜 (-s) := forall₂_imp fun _ _ h => (smul_set_neg _ _).subset.trans <| neg_subset_neg.2 h @@ -142,7 +145,7 @@ end SeminormedRing section NormedDivisionRing -variable [NormedDivisionRing 𝕜] [AddCommGroup E] [Module 𝕜 E] {s t : Set E} {x : E} {a b : 𝕜} +variable [NormedDivisionRing 𝕜] [AddCommGroup E] [Module 𝕜 E] {s t : Set E} theorem absorbs_iff_eventually_nhdsWithin_zero : Absorbs 𝕜 s t ↔ ∀ᶠ c : 𝕜 in 𝓝[≠] 0, MapsTo (c • ·) t s := by @@ -172,7 +175,7 @@ end NormedDivisionRing section NormedField variable [NormedField 𝕜] [NormedRing 𝕝] [NormedSpace 𝕜 𝕝] [AddCommGroup E] [Module 𝕜 E] - [SMulWithZero 𝕝 E] [IsScalarTower 𝕜 𝕝 E] {s t u v A B : Set E} {x : E} {a b : 𝕜} + [SMulWithZero 𝕝 E] [IsScalarTower 𝕜 𝕝 E] {s A : Set E} {x : E} {a b : 𝕜} /-- Scalar multiplication (by possibly different types) of a balanced set is monotone. -/ theorem Balanced.smul_mono (hs : Balanced 𝕝 s) {a : 𝕝} {b : 𝕜} (h : ‖a‖ ≤ ‖b‖) : a • s ⊆ b • s := by diff --git a/Mathlib/Analysis/LocallyConvex/Bounded.lean b/Mathlib/Analysis/LocallyConvex/Bounded.lean index 9463b8d6760d7..a3904e3c612c7 100644 --- a/Mathlib/Analysis/LocallyConvex/Bounded.lean +++ b/Mathlib/Analysis/LocallyConvex/Bounded.lean @@ -7,8 +7,9 @@ import Mathlib.GroupTheory.GroupAction.Pointwise import Mathlib.Analysis.LocallyConvex.Basic import Mathlib.Analysis.LocallyConvex.BalancedCoreHull import Mathlib.Analysis.Seminorm +import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.Topology.Bornology.Basic -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Topology.Algebra.UniformGroup.Basic import Mathlib.Topology.UniformSpace.Cauchy import Mathlib.Topology.Algebra.Module.Basic @@ -41,7 +42,7 @@ von Neumann-bounded sets. -/ -variable {𝕜 𝕜' E E' F ι : Type*} +variable {𝕜 𝕜' E F ι : Type*} open Set Filter Function open scoped Topology Pointwise @@ -198,7 +199,7 @@ theorem IsVonNBounded.image {σ : 𝕜₁ →+* 𝕜₂} [RingHomSurjective σ] (hs : IsVonNBounded 𝕜₁ s) (f : E →SL[σ] F) : IsVonNBounded 𝕜₂ (f '' s) := by have σ_iso : Isometry σ := AddMonoidHomClass.isometry_of_norm σ fun x => RingHomIsometric.is_iso have : map σ (𝓝 0) = 𝓝 0 := by - rw [σ_iso.embedding.map_nhds_eq, σ.surjective.range_eq, nhdsWithin_univ, map_zero] + rw [σ_iso.isEmbedding.map_nhds_eq, σ.surjective.range_eq, nhdsWithin_univ, map_zero] have hf₀ : Tendsto f (𝓝 0) (𝓝 0) := f.continuous.tendsto' 0 0 (map_zero f) simp only [isVonNBounded_iff_tendsto_smallSets_nhds, ← this, tendsto_map'_iff] at hs ⊢ simpa only [comp_def, image_smul_setₛₗ _ _ σ f] using hf₀.image_smallSets.comp hs @@ -244,7 +245,7 @@ theorem isVonNBounded_of_smul_tendsto_zero {ε : ι → 𝕜} {l : Filter ι} [l theorem isVonNBounded_iff_smul_tendsto_zero {ε : ι → 𝕜} {l : Filter ι} [l.NeBot] (hε : Tendsto ε l (𝓝[≠] 0)) {S : Set E} : IsVonNBounded 𝕜 S ↔ ∀ x : ι → E, (∀ n, x n ∈ S) → Tendsto (ε • x) l (𝓝 0) := - ⟨fun hS x hxS => hS.smul_tendsto_zero (Eventually.of_forall hxS) (le_trans hε nhdsWithin_le_nhds), + ⟨fun hS _ hxS => hS.smul_tendsto_zero (Eventually.of_forall hxS) (le_trans hε nhdsWithin_le_nhds), isVonNBounded_of_smul_tendsto_zero (by exact hε self_mem_nhdsWithin)⟩ end sequence diff --git a/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean b/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean index a61d1ac3cdcf5..d1b8d23fb2ca3 100644 --- a/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean +++ b/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean @@ -109,7 +109,7 @@ theorem LinearMap.continuousAt_zero_of_locally_bounded (f : E →ₛₗ[σ] F) refine (bE1 (n + 1)).2.smul_mem ?_ hx have h' : 0 < (n : ℝ) + 1 := n.cast_add_one_pos rw [norm_inv, ← Nat.cast_one, ← Nat.cast_add, RCLike.norm_natCast, Nat.cast_add, - Nat.cast_one, inv_le h' zero_lt_one] + Nat.cast_one, inv_le_comm₀ h' zero_lt_one] simp intro n hn -- The converse direction follows from continuity of the scalar multiplication diff --git a/Mathlib/Analysis/LocallyConvex/WeakDual.lean b/Mathlib/Analysis/LocallyConvex/WeakDual.lean index 13d4746c6c707..9e7b880fc4e4d 100644 --- a/Mathlib/Analysis/LocallyConvex/WeakDual.lean +++ b/Mathlib/Analysis/LocallyConvex/WeakDual.lean @@ -38,7 +38,7 @@ weak dual, seminorm -/ -variable {𝕜 E F ι : Type*} +variable {𝕜 E F : Type*} open Topology @@ -84,57 +84,24 @@ end BilinForm section Topology variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] -variable [Nonempty ι] -variable {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} - -theorem LinearMap.hasBasis_weakBilin (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : - (𝓝 (0 : WeakBilin B)).HasBasis B.toSeminormFamily.basisSets _root_.id := by - let p := B.toSeminormFamily - rw [nhds_induced, nhds_pi] - simp only [map_zero, LinearMap.zero_apply] - have h := @Metric.nhds_basis_ball 𝕜 _ 0 - have h' := Filter.hasBasis_pi fun _ : F => h - have h'' := Filter.HasBasis.comap (fun x y => B x y) h' - refine h''.to_hasBasis ?_ ?_ - · rintro (U : Set F × (F → ℝ)) hU - cases' hU with hU₁ hU₂ - simp only [_root_.id] - let U' := hU₁.toFinset - by_cases hU₃ : U.fst.Nonempty - · have hU₃' : U'.Nonempty := hU₁.toFinset_nonempty.mpr hU₃ - refine ⟨(U'.sup p).ball 0 <| U'.inf' hU₃' U.snd, p.basisSets_mem _ <| - (Finset.lt_inf'_iff _).2 fun y hy => hU₂ y <| hU₁.mem_toFinset.mp hy, fun x hx y hy => ?_⟩ - simp only [Set.mem_preimage, Set.mem_pi, mem_ball_zero_iff] - rw [Seminorm.mem_ball_zero] at hx - rw [← LinearMap.toSeminormFamily_apply] - have hyU' : y ∈ U' := (Set.Finite.mem_toFinset hU₁).mpr hy - have hp : p y ≤ U'.sup p := Finset.le_sup hyU' - refine lt_of_le_of_lt (hp x) (lt_of_lt_of_le hx ?_) - exact Finset.inf'_le _ hyU' - rw [Set.not_nonempty_iff_eq_empty.mp hU₃] - simp only [Set.empty_pi, Set.preimage_univ, Set.subset_univ, and_true] - exact Exists.intro ((p 0).ball 0 1) (p.basisSets_singleton_mem 0 one_pos) - rintro U (hU : U ∈ p.basisSets) - rw [SeminormFamily.basisSets_iff] at hU - rcases hU with ⟨s, r, hr, hU⟩ - rw [hU] - refine ⟨(s, fun _ => r), ⟨by simp only [s.finite_toSet], fun y _ => hr⟩, fun x hx => ?_⟩ - simp only [Set.mem_preimage, Set.mem_pi, Finset.mem_coe, mem_ball_zero_iff] at hx - simp only [_root_.id, Seminorm.mem_ball, sub_zero] - refine Seminorm.finset_sup_apply_lt hr fun y hy => ?_ - rw [LinearMap.toSeminormFamily_apply] - exact hx y hy theorem LinearMap.weakBilin_withSeminorms (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : WithSeminorms (LinearMap.toSeminormFamily B : F → Seminorm 𝕜 (WeakBilin B)) := - SeminormFamily.withSeminorms_of_hasBasis _ B.hasBasis_weakBilin + let e : F ≃ (Σ _ : F, Fin 1) := .symm <| .sigmaUnique _ _ + have : Nonempty (Σ _ : F, Fin 1) := e.symm.nonempty + withSeminorms_induced (withSeminorms_pi (fun _ ↦ norm_withSeminorms 𝕜 𝕜)) + (LinearMap.ltoFun 𝕜 F 𝕜 ∘ₗ B : (WeakBilin B) →ₗ[𝕜] (F → 𝕜)) |>.congr_equiv e + +theorem LinearMap.hasBasis_weakBilin (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : + (𝓝 (0 : WeakBilin B)).HasBasis B.toSeminormFamily.basisSets _root_.id := + LinearMap.weakBilin_withSeminorms B |>.hasBasis end Topology section LocallyConvex variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] -variable [Nonempty ι] [NormedSpace ℝ 𝕜] [Module ℝ E] [IsScalarTower ℝ 𝕜 E] +variable [NormedSpace ℝ 𝕜] [Module ℝ E] [IsScalarTower ℝ 𝕜 E] instance WeakBilin.locallyConvexSpace {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} : LocallyConvexSpace ℝ (WeakBilin B) := diff --git a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean index b4165a1a77053..03f93e0ed2cb9 100644 --- a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean +++ b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean @@ -648,7 +648,7 @@ protected theorem _root_.WithSeminorms.equicontinuous_TFAE {κ : Type*} theorem _root_.WithSeminorms.uniformEquicontinuous_iff_exists_continuous_seminorm {κ : Type*} {q : SeminormFamily 𝕜₂ F ι'} [UniformSpace E] [UniformAddGroup E] [u : UniformSpace F] - [hu : UniformAddGroup F] (hq : WithSeminorms q) [ContinuousSMul 𝕜 E] + [UniformAddGroup F] (hq : WithSeminorms q) [ContinuousSMul 𝕜 E] (f : κ → E →ₛₗ[σ₁₂] F) : UniformEquicontinuous ((↑) ∘ f) ↔ ∀ i, ∃ p : Seminorm 𝕜 E, Continuous p ∧ ∀ k, (q i).comp (f k) ≤ p := @@ -656,7 +656,7 @@ theorem _root_.WithSeminorms.uniformEquicontinuous_iff_exists_continuous_seminor theorem _root_.WithSeminorms.uniformEquicontinuous_iff_bddAbove_and_continuous_iSup {κ : Type*} {q : SeminormFamily 𝕜₂ F ι'} [UniformSpace E] [UniformAddGroup E] [u : UniformSpace F] - [hu : UniformAddGroup F] (hq : WithSeminorms q) [ContinuousSMul 𝕜 E] + [UniformAddGroup F] (hq : WithSeminorms q) [ContinuousSMul 𝕜 E] (f : κ → E →ₛₗ[σ₁₂] F) : UniformEquicontinuous ((↑) ∘ f) ↔ ∀ i, BddAbove (range fun k ↦ (q i).comp (f k)) ∧ @@ -865,11 +865,14 @@ theorem LinearMap.withSeminorms_induced [hι : Nonempty ι] {q : SeminormFamily refine iInf_congr fun i => ?_ exact Filter.comap_comap -theorem Inducing.withSeminorms [hι : Nonempty ι] {q : SeminormFamily 𝕜₂ F ι} (hq : WithSeminorms q) - [TopologicalSpace E] {f : E →ₛₗ[σ₁₂] F} (hf : Inducing f) : WithSeminorms (q.comp f) := by - rw [hf.induced] +lemma IsInducing.withSeminorms [hι : Nonempty ι] {q : SeminormFamily 𝕜₂ F ι} + (hq : WithSeminorms q) [TopologicalSpace E] {f : E →ₛₗ[σ₁₂] F} (hf : IsInducing f) : + WithSeminorms (q.comp f) := by + rw [hf.eq_induced] exact f.withSeminorms_induced hq +@[deprecated (since := "2024-10-28")] alias Inducing.withSeminorms := IsInducing.withSeminorms + /-- (Disjoint) union of seminorm families. -/ protected def SeminormFamily.sigma {κ : ι → Type*} (p : (i : ι) → SeminormFamily 𝕜 E (κ i)) : SeminormFamily 𝕜 E ((i : ι) × κ i) := @@ -877,13 +880,22 @@ protected def SeminormFamily.sigma {κ : ι → Type*} (p : (i : ι) → Seminor theorem withSeminorms_iInf {κ : ι → Type*} [Nonempty ((i : ι) × κ i)] [∀ i, Nonempty (κ i)] {p : (i : ι) → SeminormFamily 𝕜 E (κ i)} {t : ι → TopologicalSpace E} - [∀ i, @TopologicalAddGroup E (t i) _] (hp : ∀ i, WithSeminorms (topology := t i) (p i)) : + (hp : ∀ i, WithSeminorms (topology := t i) (p i)) : WithSeminorms (topology := ⨅ i, t i) (SeminormFamily.sigma p) := by - have : @TopologicalAddGroup E (⨅ i, t i) _ := topologicalAddGroup_iInf (fun i ↦ inferInstance) + have : ∀ i, @TopologicalAddGroup E (t i) _ := + fun i ↦ @WithSeminorms.topologicalAddGroup _ _ _ _ _ _ _ (t i) _ (hp i) + have : @TopologicalAddGroup E (⨅ i, t i) _ := topologicalAddGroup_iInf inferInstance simp_rw [@SeminormFamily.withSeminorms_iff_topologicalSpace_eq_iInf _ _ _ _ _ _ _ (_)] at hp ⊢ rw [iInf_sigma] exact iInf_congr hp +theorem withSeminorms_pi {κ : ι → Type*} {E : ι → Type*} + [∀ i, AddCommGroup (E i)] [∀ i, Module 𝕜 (E i)] [∀ i, TopologicalSpace (E i)] + [Nonempty ((i : ι) × κ i)] [∀ i, Nonempty (κ i)] {p : (i : ι) → SeminormFamily 𝕜 (E i) (κ i)} + (hp : ∀ i, WithSeminorms (p i)) : + WithSeminorms (SeminormFamily.sigma (fun i ↦ (p i).comp (LinearMap.proj i))) := + withSeminorms_iInf fun i ↦ (LinearMap.proj i).withSeminorms_induced (hp i) + end TopologicalConstructions section TopologicalProperties diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index d8e1833217bd0..d75d457d35cf7 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -272,11 +272,11 @@ theorem harm_mean_le_geom_mean_weighted (w z : ι → ℝ) (hs : s.Nonempty) (hw have s_pos : 0 < ∑ i in s, w i * (z i)⁻¹ := sum_pos (fun i hi => mul_pos (hw i hi) (inv_pos.2 (hz i hi))) hs norm_num at this - rw [← inv_le_inv s_pos p_pos] at this + rw [← inv_le_inv₀ s_pos p_pos] at this apply le_trans this have p_pos₂ : 0 < (∏ i in s, (z i) ^ w i)⁻¹ := inv_pos.2 (prod_pos fun i hi => rpow_pos_of_pos ((hz i hi)) _ ) - rw [← inv_inv (∏ i in s, z i ^ w i), inv_le_inv p_pos p_pos₂, ← Finset.prod_inv_distrib] + rw [← inv_inv (∏ i in s, z i ^ w i), inv_le_inv₀ p_pos p_pos₂, ← Finset.prod_inv_distrib] gcongr · exact fun i hi ↦ inv_nonneg.mpr (Real.rpow_nonneg (le_of_lt (hz i hi)) _) · rw [Real.inv_rpow]; apply fun i hi ↦ le_of_lt (hz i hi); assumption @@ -494,7 +494,7 @@ theorem inner_le_Lp_mul_Lq_hasSum {f g : ι → ℝ≥0} {A B : ℝ≥0} {p q : sum of the `p`-th powers of `f i`. Version for sums over finite sets, with `ℝ≥0`-valued functions. -/ theorem rpow_sum_le_const_mul_sum_rpow (f : ι → ℝ≥0) {p : ℝ} (hp : 1 ≤ p) : - (∑ i ∈ s, f i) ^ p ≤ (card s : ℝ≥0) ^ (p - 1) * ∑ i ∈ s, f i ^ p := by + (∑ i ∈ s, f i) ^ p ≤ (#s : ℝ≥0) ^ (p - 1) * ∑ i ∈ s, f i ^ p := by cases' eq_or_lt_of_le hp with hp hp · simp [← hp] let q : ℝ := p / (p - 1) @@ -620,7 +620,7 @@ theorem inner_le_Lp_mul_Lq (hpq : IsConjExponent p q) : /-- For `1 ≤ p`, the `p`-th power of the sum of `f i` is bounded above by a constant times the sum of the `p`-th powers of `f i`. Version for sums over finite sets, with `ℝ`-valued functions. -/ theorem rpow_sum_le_const_mul_sum_rpow (hp : 1 ≤ p) : - (∑ i ∈ s, |f i|) ^ p ≤ (card s : ℝ) ^ (p - 1) * ∑ i ∈ s, |f i| ^ p := by + (∑ i ∈ s, |f i|) ^ p ≤ (#s : ℝ) ^ (p - 1) * ∑ i ∈ s, |f i| ^ p := by have := NNReal.coe_le_coe.2 (NNReal.rpow_sum_le_const_mul_sum_rpow s (fun i => ⟨_, abs_nonneg (f i)⟩) hp) @@ -722,7 +722,7 @@ theorem inner_le_Lp_mul_Lq_hasSum_of_nonneg (hpq : p.IsConjExponent q) {A B : sum of the `p`-th powers of `f i`. Version for sums over finite sets, with nonnegative `ℝ`-valued functions. -/ theorem rpow_sum_le_const_mul_sum_rpow_of_nonneg (hp : 1 ≤ p) (hf : ∀ i ∈ s, 0 ≤ f i) : - (∑ i ∈ s, f i) ^ p ≤ (card s : ℝ) ^ (p - 1) * ∑ i ∈ s, f i ^ p := by + (∑ i ∈ s, f i) ^ p ≤ (#s : ℝ) ^ (p - 1) * ∑ i ∈ s, f i ^ p := by convert rpow_sum_le_const_mul_sum_rpow s f hp using 2 <;> apply sum_congr rfl <;> intro i hi <;> simp only [abs_of_nonneg, hf i hi] @@ -821,7 +821,7 @@ lemma inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) obtain rfl | hp := hp.eq_or_lt · simp have hp₀ : 0 < p := by positivity - have hp₁ : p⁻¹ < 1 := inv_lt_one hp + have hp₁ : p⁻¹ < 1 := inv_lt_one_of_one_lt₀ hp by_cases H : (∑ i ∈ s, w i) ^ (1 - p⁻¹) = 0 ∨ (∑ i ∈ s, w i * f i ^ p) ^ p⁻¹ = 0 · replace H : (∀ i ∈ s, w i = 0) ∨ ∀ i ∈ s, w i = 0 ∨ f i = 0 := by simpa [hp₀, hp₁, hp₀.not_lt, hp₁.not_lt, sum_eq_zero_iff_of_nonneg] using H diff --git a/Mathlib/Analysis/MellinInversion.lean b/Mathlib/Analysis/MellinInversion.lean index c9680254f0421..758a80e2575a8 100644 --- a/Mathlib/Analysis/MellinInversion.lean +++ b/Mathlib/Analysis/MellinInversion.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Lawrence Wu -/ import Mathlib.Analysis.Fourier.Inversion +import Mathlib.Analysis.MellinTransform /-! # Mellin inversion formula diff --git a/Mathlib/Analysis/MellinTransform.lean b/Mathlib/Analysis/MellinTransform.lean index 6712829f036dc..8effebaeff182 100644 --- a/Mathlib/Analysis/MellinTransform.lean +++ b/Mathlib/Analysis/MellinTransform.lean @@ -96,7 +96,7 @@ def mellinInv (σ : ℝ) (f : ℂ → E) (x : ℝ) : E := -- next few lemmas don't require convergence of the Mellin transform (they are just 0 = 0 otherwise) theorem mellin_cpow_smul (f : ℝ → E) (s a : ℂ) : mellin (fun t => (t : ℂ) ^ a • f t) s = mellin f (s + a) := by - refine setIntegral_congr measurableSet_Ioi fun t ht => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun t ht => ?_ simp_rw [← sub_add_eq_add_sub, cpow_add _ _ (ofReal_ne_zero.2 <| ne_of_gt ht), mul_smul] theorem mellin_const_smul (f : ℝ → E) (s : ℂ) {𝕜 : Type*} [NontriviallyNormedField 𝕜] @@ -116,7 +116,7 @@ theorem mellin_comp_rpow (f : ℝ → E) (s : ℂ) (a : ℝ) : · simp [integral, mellin, hE] simp_rw [mellin] conv_rhs => rw [← integral_comp_rpow_Ioi _ ha, ← integral_smul] - refine setIntegral_congr measurableSet_Ioi fun t ht => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun t ht => ?_ dsimp only rw [← mul_smul, ← mul_assoc, inv_mul_cancel₀ (mt abs_eq_zero.1 ha), one_mul, ← smul_assoc, real_smul] @@ -135,7 +135,7 @@ theorem mellin_comp_mul_left (f : ℝ → E) (s : ℂ) {a : ℝ} (ha : 0 < a) : (by ring : 1 - s = -(s - 1)), cpow_neg, inv_mul_cancel_left₀] rw [Ne, cpow_eq_zero_iff, ofReal_eq_zero, not_and_or] exact Or.inl ha.ne' - rw [setIntegral_congr measurableSet_Ioi this, integral_smul, + rw [setIntegral_congr_fun measurableSet_Ioi this, integral_smul, integral_comp_mul_left_Ioi (fun u ↦ (u : ℂ) ^ (s - 1) • f u) _ ha, mul_zero, ← Complex.coe_smul, ← mul_smul, sub_eq_add_neg, cpow_add _ _ (ofReal_ne_zero.mpr ha.ne'), cpow_one, ofReal_inv, @@ -179,7 +179,8 @@ theorem mellin_convergent_iff_norm [NormedSpace ℂ E] {f : ℝ → E} {T : Set IntegrableOn (fun t : ℝ => (t : ℂ) ^ (s - 1) • f t) T ↔ IntegrableOn (fun t : ℝ => t ^ (s.re - 1) * ‖f t‖) T := by have : AEStronglyMeasurable (fun t : ℝ => (t : ℂ) ^ (s - 1) • f t) (volume.restrict T) := by - refine ((ContinuousAt.continuousOn ?_).aestronglyMeasurable hT').smul (hfc.mono_set hT) + refine ((continuousOn_of_forall_continuousAt ?_).aestronglyMeasurable hT').smul + (hfc.mono_set hT) exact fun t ht => continuousAt_ofReal_cpow_const _ _ (Or.inr <| ne_of_gt (hT ht)) rw [IntegrableOn, ← integrable_norm_iff this, ← IntegrableOn] refine integrableOn_congr_fun (fun t ht => ?_) hT' @@ -197,7 +198,8 @@ theorem mellin_convergent_top_of_isBigO {f : ℝ → ℝ} have he' : 0 < max e 1 := zero_lt_one.trans_le (le_max_right _ _) refine ⟨max e 1, he', ?_, ?_⟩ · refine AEStronglyMeasurable.mul ?_ (hfc.mono_set (Ioi_subset_Ioi he'.le)) - refine (ContinuousAt.continuousOn fun t ht => ?_).aestronglyMeasurable measurableSet_Ioi + refine (continuousOn_of_forall_continuousAt fun t ht => ?_).aestronglyMeasurable + measurableSet_Ioi exact continuousAt_rpow_const _ _ (Or.inl <| (he'.trans ht).ne') · have : ∀ᵐ t : ℝ ∂volume.restrict (Ioi <| max e 1), ‖t ^ (s - 1) * f t‖ ≤ t ^ (s - 1 + -a) * d := by @@ -221,7 +223,8 @@ theorem mellin_convergent_zero_of_isBigO {b : ℝ} {f : ℝ → ℝ} obtain ⟨ε, hε, hε'⟩ := hd' refine ⟨ε, hε, integrableOn_Ioc_iff_integrableOn_Ioo.mpr ⟨?_, ?_⟩⟩ · refine AEStronglyMeasurable.mul ?_ (hfc.mono_set Ioo_subset_Ioi_self) - refine (ContinuousAt.continuousOn fun t ht => ?_).aestronglyMeasurable measurableSet_Ioo + refine (continuousOn_of_forall_continuousAt fun t ht => ?_).aestronglyMeasurable + measurableSet_Ioo exact continuousAt_rpow_const _ _ (Or.inl ht.1.ne') · apply HasFiniteIntegral.mono' · show HasFiniteIntegral (fun t => d * t ^ (s - b - 1)) _ @@ -258,7 +261,8 @@ theorem mellin_convergent_of_isBigO_scalar {a b : ℝ} {f : ℝ → ℝ} {s : refine (hfc.continuousOn_mul ?_ isOpen_Ioi.isLocallyClosed).integrableOn_compact_subset (fun t ht => (hc2.trans_le ht.1 : 0 < t)) isCompact_Icc - exact ContinuousAt.continuousOn fun t ht => continuousAt_rpow_const _ _ <| Or.inl <| ne_of_gt ht + exact continuousOn_of_forall_continuousAt + fun t ht ↦ continuousAt_rpow_const _ _ <| Or.inl <| ne_of_gt ht theorem mellinConvergent_of_isBigO_rpow [NormedSpace ℂ E] {a b : ℝ} {f : ℝ → E} {s : ℂ} (hfc : LocallyIntegrableOn f <| Ioi 0) (hf_top : f =O[atTop] (· ^ (-a))) @@ -321,14 +325,14 @@ theorem mellin_hasDerivAt_of_isBigO_rpow [NormedSpace ℂ E] {a b : ℝ} have h1 : ∀ᶠ z : ℂ in 𝓝 s, AEStronglyMeasurable (F z) (volume.restrict <| Ioi 0) := by refine Eventually.of_forall fun z => AEStronglyMeasurable.smul ?_ hfc.aestronglyMeasurable refine ContinuousOn.aestronglyMeasurable ?_ measurableSet_Ioi - refine ContinuousAt.continuousOn fun t ht => ?_ + refine continuousOn_of_forall_continuousAt fun t ht => ?_ exact continuousAt_ofReal_cpow_const _ _ (Or.inr <| ne_of_gt ht) have h2 : IntegrableOn (F s) (Ioi (0 : ℝ)) := by exact mellinConvergent_of_isBigO_rpow hfc hf_top hs_top hf_bot hs_bot have h3 : AEStronglyMeasurable (F' s) (volume.restrict <| Ioi 0) := by apply LocallyIntegrableOn.aestronglyMeasurable refine hfc.continuousOn_smul isOpen_Ioi.isLocallyClosed - ((ContinuousAt.continuousOn fun t ht => ?_).mul ?_) + ((continuousOn_of_forall_continuousAt fun t ht => ?_).mul ?_) · exact continuousAt_ofReal_cpow_const _ _ (Or.inr <| ne_of_gt ht) · refine continuous_ofReal.comp_continuousOn ?_ exact continuousOn_log.mono (subset_compl_singleton_iff.mpr not_mem_Ioi_self) diff --git a/Mathlib/Analysis/Normed/Affine/AddTorsor.lean b/Mathlib/Analysis/Normed/Affine/AddTorsor.lean index 2e2257c96f378..f785e2f32a0bc 100644 --- a/Mathlib/Analysis/Normed/Affine/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Affine/AddTorsor.lean @@ -9,6 +9,7 @@ import Mathlib.Analysis.Normed.Group.AddTorsor import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace import Mathlib.Topology.Instances.RealVectorSpace + /-! # Torsors of normed space actions. @@ -22,7 +23,7 @@ open NNReal Topology open Filter -variable {α V P W Q : Type*} [SeminormedAddCommGroup V] [PseudoMetricSpace P] [NormedAddTorsor V P] +variable {V P W Q : Type*} [SeminormedAddCommGroup V] [PseudoMetricSpace P] [NormedAddTorsor V P] [NormedAddCommGroup W] [MetricSpace Q] [NormedAddTorsor W Q] section NormedSpace diff --git a/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean b/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean index 5e63c0037ade0..7491177284cf8 100644 --- a/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean +++ b/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean @@ -220,7 +220,7 @@ def toConstProdContinuousLinearMap : (V →ᴬ[𝕜] W) ≃ₗᵢ[𝕜] W × (V right_inv := by rintro ⟨v, f⟩; ext <;> simp map_add' _ _ := rfl map_smul' _ _ := rfl - norm_map' f := rfl + norm_map' _ := rfl @[simp] theorem toConstProdContinuousLinearMap_fst (f : V →ᴬ[𝕜] W) : diff --git a/Mathlib/Analysis/Normed/Affine/Isometry.lean b/Mathlib/Analysis/Normed/Affine/Isometry.lean index 67f6a72b44673..d6db878a74fdd 100644 --- a/Mathlib/Analysis/Normed/Affine/Isometry.lean +++ b/Mathlib/Analysis/Normed/Affine/Isometry.lean @@ -541,7 +541,6 @@ protected theorem injective : Injective e := protected theorem surjective : Surjective e := e.1.surjective --- @[simp] Porting note (#10618): simp can prove this theorem map_eq_iff {x y : P} : e x = e y ↔ x = y := e.injective.eq_iff diff --git a/Mathlib/Analysis/Normed/Affine/MazurUlam.lean b/Mathlib/Analysis/Normed/Affine/MazurUlam.lean index b3a9fcf2d073a..3f25c5ae3d8b8 100644 --- a/Mathlib/Analysis/Normed/Affine/MazurUlam.lean +++ b/Mathlib/Analysis/Normed/Affine/MazurUlam.lean @@ -53,7 +53,7 @@ theorem midpoint_fixed {x y : PE} : calc dist (e z) z ≤ dist (e z) x + dist x z := dist_triangle (e z) x z _ = dist (e x) (e z) + dist x z := by rw [hx, dist_comm] - _ = dist x z + dist x z := by erw [e.dist_eq x z] + _ = dist x z + dist x z := by rw [e.dist_eq x z] -- On the other hand, consider the map `f : (E ≃ᵢ E) → (E ≃ᵢ E)` -- sending each `e` to `R ∘ e⁻¹ ∘ R ∘ e`, where `R` is the point reflection in the -- midpoint `z` of `[x, y]`. diff --git a/Mathlib/Analysis/Normed/Algebra/Exponential.lean b/Mathlib/Analysis/Normed/Algebra/Exponential.lean index e211c1cfd4a8d..a417ad5c90908 100644 --- a/Mathlib/Analysis/Normed/Algebra/Exponential.lean +++ b/Mathlib/Analysis/Normed/Algebra/Exponential.lean @@ -386,7 +386,7 @@ theorem expSeries_radius_eq_top : (expSeries 𝕂 𝔸).radius = ∞ := by theorem expSeries_radius_pos : 0 < (expSeries 𝕂 𝔸).radius := by rw [expSeries_radius_eq_top] - exact WithTop.zero_lt_top + exact WithTop.top_pos variable {𝕂 𝔸 𝔹} @@ -470,7 +470,7 @@ commute then `NormedSpace.exp 𝕂 (∑ i, f i) = ∏ i, NormedSpace.exp 𝕂 (f theorem exp_sum_of_commute {ι} (s : Finset ι) (f : ι → 𝔸) (h : (s : Set ι).Pairwise fun i j => Commute (f i) (f j)) : exp 𝕂 (∑ i ∈ s, f i) = - s.noncommProd (fun i => exp 𝕂 (f i)) fun i hi j hj _ => (h.of_refl hi hj).exp 𝕂 := by + s.noncommProd (fun i => exp 𝕂 (f i)) fun _ hi _ hj _ => (h.of_refl hi hj).exp 𝕂 := by classical induction' s using Finset.induction_on with a s ha ih · simp diff --git a/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean b/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean index a481e6f7c4823..497cbcfabba71 100644 --- a/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean +++ b/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean @@ -64,7 +64,7 @@ open scoped Matrix open NormedSpace -- For `exp`. -variable (𝕂 : Type*) {m n p : Type*} {n' : m → Type*} {𝔸 : Type*} +variable (𝕂 : Type*) {m n : Type*} {n' : m → Type*} {𝔸 : Type*} namespace Matrix @@ -114,8 +114,8 @@ end Topological section Normed -variable [RCLike 𝕂] [Fintype m] [DecidableEq m] [Fintype n] [DecidableEq n] [∀ i, Fintype (n' i)] - [∀ i, DecidableEq (n' i)] [NormedRing 𝔸] [NormedAlgebra 𝕂 𝔸] [CompleteSpace 𝔸] +variable [RCLike 𝕂] [Fintype m] [DecidableEq m] + [NormedRing 𝔸] [NormedAlgebra 𝕂 𝔸] [CompleteSpace 𝔸] nonrec theorem exp_add_of_commute (A B : Matrix m m 𝔸) (h : Commute A B) : exp 𝕂 (A + B) = exp 𝕂 A * exp 𝕂 B := by @@ -127,7 +127,7 @@ nonrec theorem exp_add_of_commute (A B : Matrix m m 𝔸) (h : Commute A B) : nonrec theorem exp_sum_of_commute {ι} (s : Finset ι) (f : ι → Matrix m m 𝔸) (h : (s : Set ι).Pairwise fun i j => Commute (f i) (f j)) : exp 𝕂 (∑ i ∈ s, f i) = - s.noncommProd (fun i => exp 𝕂 (f i)) fun i hi j hj _ => (h.of_refl hi hj).exp 𝕂 := by + s.noncommProd (fun i => exp 𝕂 (f i)) fun _ hi _ hj _ => (h.of_refl hi hj).exp 𝕂 := by letI : SeminormedRing (Matrix m m 𝔸) := Matrix.linftyOpSemiNormedRing letI : NormedRing (Matrix m m 𝔸) := Matrix.linftyOpNormedRing letI : NormedAlgebra 𝕂 (Matrix m m 𝔸) := Matrix.linftyOpNormedAlgebra @@ -160,8 +160,8 @@ end Normed section NormedComm -variable [RCLike 𝕂] [Fintype m] [DecidableEq m] [Fintype n] [DecidableEq n] [∀ i, Fintype (n' i)] - [∀ i, DecidableEq (n' i)] [NormedCommRing 𝔸] [NormedAlgebra 𝕂 𝔸] [CompleteSpace 𝔸] +variable [RCLike 𝕂] [Fintype m] [DecidableEq m] + [NormedCommRing 𝔸] [NormedAlgebra 𝕂 𝔸] [CompleteSpace 𝔸] theorem exp_neg (A : Matrix m m 𝔸) : exp 𝕂 (-A) = (exp 𝕂 A)⁻¹ := by rw [nonsing_inv_eq_ring_inverse] diff --git a/Mathlib/Analysis/Normed/Algebra/Norm.lean b/Mathlib/Analysis/Normed/Algebra/Norm.lean index eb815ac91298e..715ad8694cf6f 100644 --- a/Mathlib/Analysis/Normed/Algebra/Norm.lean +++ b/Mathlib/Analysis/Normed/Algebra/Norm.lean @@ -70,10 +70,6 @@ instance algebraNormClass : AlgebraNormClass (AlgebraNorm R S) R S where eq_zero_of_map_eq_zero f := f.eq_zero_of_map_eq_zero' _ map_smul_eq_mul f := f.smul' -/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`. -/ -instance : CoeFun (AlgebraNorm R S) fun _ => S → ℝ := - DFunLike.hasCoeToFun - theorem toFun_eq_coe (p : AlgebraNorm R S) : p.toFun = p := rfl @[ext] @@ -160,10 +156,6 @@ instance mulAlgebraNormClass : MulAlgebraNormClass (MulAlgebraNorm R S) R S wher eq_zero_of_map_eq_zero f := f.eq_zero_of_map_eq_zero' _ map_smul_eq_mul f := f.smul' -/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`. -/ -instance : CoeFun (MulAlgebraNorm R S) fun _ => S → ℝ := - DFunLike.hasCoeToFun - theorem toFun_eq_coe (p : MulAlgebraNorm R S) : p.toFun = p := rfl @[ext] diff --git a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean index fa49b3701161c..6c924b2091498 100644 --- a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean +++ b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean @@ -133,7 +133,7 @@ instance instCompactSpaceNNReal {A : Type*} [NormedRing A] [NormedAlgebra ℝ A] (a : A) [CompactSpace (spectrum ℝ a)] : CompactSpace (spectrum ℝ≥0 a) := by rw [← isCompact_iff_compactSpace] at * rw [← preimage_algebraMap ℝ] - exact closedEmbedding_subtype_val isClosed_nonneg |>.isCompact_preimage <| by assumption + exact isClosed_nonneg.isClosedEmbedding_subtypeVal.isCompact_preimage <| by assumption section QuasispectrumCompact @@ -154,10 +154,27 @@ instance _root_.quasispectrum.instCompactSpaceNNReal [NormedSpace ℝ B] [IsScal CompactSpace (quasispectrum ℝ≥0 a) := by rw [← isCompact_iff_compactSpace] at * rw [← quasispectrum.preimage_algebraMap ℝ] - exact closedEmbedding_subtype_val isClosed_nonneg |>.isCompact_preimage <| by assumption + exact isClosed_nonneg.isClosedEmbedding_subtypeVal.isCompact_preimage <| by assumption end QuasispectrumCompact +section NNReal + +open NNReal + +variable {A : Type*} [NormedRing A] [NormedAlgebra ℝ A] [CompleteSpace A] [NormOneClass A] + +theorem le_nnnorm_of_mem {a : A} {r : ℝ≥0} (hr : r ∈ spectrum ℝ≥0 a) : + r ≤ ‖a‖₊ := calc + r ≤ ‖(r : ℝ)‖ := Real.le_norm_self _ + _ ≤ ‖a‖ := norm_le_norm_of_mem hr + +theorem coe_le_norm_of_mem {a : A} {r : ℝ≥0} (hr : r ∈ spectrum ℝ≥0 a) : + r ≤ ‖a‖ := + coe_mono <| le_nnnorm_of_mem hr + +end NNReal + theorem spectralRadius_le_nnnorm [NormOneClass A] (a : A) : spectralRadius 𝕜 a ≤ ‖a‖₊ := by refine iSup₂_le fun k hk => ?_ exact mod_cast norm_le_norm_of_mem hk @@ -552,8 +569,8 @@ def equivAlgHom : characterSpace 𝕜 A ≃ (A →ₐ[𝕜] 𝕜) where invFun f := { val := f.toContinuousLinearMap property := by rw [eq_set_map_one_map_mul]; exact ⟨map_one f, map_mul f⟩ } - left_inv f := Subtype.ext <| ContinuousLinearMap.ext fun x => rfl - right_inv f := AlgHom.ext fun x => rfl + left_inv _ := Subtype.ext <| ContinuousLinearMap.ext fun _ => rfl + right_inv _ := AlgHom.ext fun _ => rfl @[simp] theorem equivAlgHom_coe (f : characterSpace 𝕜 A) : ⇑(equivAlgHom f) = f := diff --git a/Mathlib/Analysis/Normed/Algebra/TrivSqZeroExt.lean b/Mathlib/Analysis/Normed/Algebra/TrivSqZeroExt.lean index 5a779b0580765..c3e4233f09ac9 100644 --- a/Mathlib/Analysis/Normed/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Analysis/Normed/Algebra/TrivSqZeroExt.lean @@ -115,7 +115,7 @@ variable [T2Space R] [T2Space M] theorem exp_def_of_smul_comm (x : tsze R M) (hx : MulOpposite.op x.fst • x.snd = x.fst • x.snd) : exp 𝕜 x = inl (exp 𝕜 x.fst) + inr (exp 𝕜 x.fst • x.snd) := by simp_rw [exp, FormalMultilinearSeries.sum] - by_cases h : Summable (fun (n : ℕ) => (expSeries 𝕜 R n) fun x_1 ↦ fst x) + by_cases h : Summable (fun (n : ℕ) => (expSeries 𝕜 R n) fun _ ↦ fst x) · refine (hasSum_expSeries_of_smul_comm 𝕜 x hx ?_).tsum_eq exact h.hasSum · rw [tsum_eq_zero_of_not_summable h, zero_smul, inr_zero, inl_zero, zero_add, @@ -264,10 +264,8 @@ noncomputable section Normed section Ring -variable [NormedCommRing S] [NormedRing R] [NormedAddCommGroup M] -variable [Algebra S R] [Module S M] [Module R M] [Module Rᵐᵒᵖ M] -variable [BoundedSMul S R] [BoundedSMul S M] [BoundedSMul R M] [BoundedSMul Rᵐᵒᵖ M] -variable [SMulCommClass R Rᵐᵒᵖ M] [IsScalarTower S R M] [IsScalarTower S Rᵐᵒᵖ M] +variable [NormedRing R] [NormedAddCommGroup M] [Module R M] [Module Rᵐᵒᵖ M] +variable [BoundedSMul R M] [BoundedSMul Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] instance instL1NormedAddCommGroup : NormedAddCommGroup (tsze R M) := inferInstanceAs <| NormedAddCommGroup (WithLp 1 <| R × M) diff --git a/Mathlib/Analysis/Normed/Algebra/Unitization.lean b/Mathlib/Analysis/Normed/Algebra/Unitization.lean index 19b11e9819409..8212d68f7249e 100644 --- a/Mathlib/Analysis/Normed/Algebra/Unitization.lean +++ b/Mathlib/Analysis/Normed/Algebra/Unitization.lean @@ -184,8 +184,8 @@ open scoped Uniformity Topology theorem uniformity_eq_aux : 𝓤[instUniformSpaceProd.comap <| addEquiv 𝕜 A] = 𝓤 (Unitization 𝕜 A) := by - have key : UniformInducing (addEquiv 𝕜 A) := - antilipschitzWith_addEquiv.uniformInducing lipschitzWith_addEquiv.uniformContinuous + have key : IsUniformInducing (addEquiv 𝕜 A) := + antilipschitzWith_addEquiv.isUniformInducing lipschitzWith_addEquiv.uniformContinuous rw [← key.comap_uniformity] rfl @@ -202,7 +202,7 @@ instance instUniformSpace : UniformSpace (Unitization 𝕜 A) := /-- The natural equivalence between `Unitization 𝕜 A` and `𝕜 × A` as a uniform equivalence. -/ def uniformEquivProd : (Unitization 𝕜 A) ≃ᵤ (𝕜 × A) := - Equiv.toUniformEquivOfUniformInducing (addEquiv 𝕜 A) ⟨rfl⟩ + Equiv.toUniformEquivOfIsUniformInducing (addEquiv 𝕜 A) ⟨rfl⟩ /-- The bornology on `Unitization 𝕜 A` is inherited from `𝕜 × A`. -/ instance instBornology : Bornology (Unitization 𝕜 A) := @@ -256,6 +256,10 @@ lemma nnnorm_inr (a : A) : ‖(a : Unitization 𝕜 A)‖₊ = ‖a‖₊ := lemma isometry_inr : Isometry ((↑) : A → Unitization 𝕜 A) := AddMonoidHomClass.isometry_of_norm (inrNonUnitalAlgHom 𝕜 A) norm_inr +@[fun_prop] +theorem continuous_inr : Continuous (inr : A → Unitization 𝕜 A) := + isometry_inr.continuous + lemma dist_inr (a b : A) : dist (a : Unitization 𝕜 A) (b : Unitization 𝕜 A) = dist a b := isometry_inr.dist_eq a b diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean index cb044efa45b52..909825a58911d 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -5,6 +5,7 @@ Authors: Patrick Massot, Johannes Hölzl -/ import Mathlib.Algebra.Algebra.NonUnitalSubalgebra import Mathlib.Algebra.Algebra.Subalgebra.Basic +import Mathlib.Algebra.Field.Subfield import Mathlib.Analysis.Normed.Group.Constructions import Mathlib.Analysis.Normed.Group.Submodule import Mathlib.Data.Set.Pointwise.Interval @@ -17,6 +18,11 @@ definitions. Some useful results that relate the topology of the normed field to the discrete topology include: * `norm_eq_one_iff_ne_zero_of_discrete` + +Methods for constructing a normed ring/field instance from a given real absolute value on a +ring/field are given in: +* AbsoluteValue.toNormedRing +* AbsoluteValue.toNormedField -/ -- Guard against import creep. @@ -212,7 +218,7 @@ instance MulOpposite.normOneClass [SeminormedAddCommGroup α] [One α] [NormOneC section NonUnitalSeminormedRing -variable [NonUnitalSeminormedRing α] +variable [NonUnitalSeminormedRing α] {a a₁ a₂ b c : α} theorem norm_mul_le (a b : α) : ‖a * b‖ ≤ ‖a‖ * ‖b‖ := NonUnitalSeminormedRing.norm_mul _ _ @@ -221,6 +227,17 @@ theorem nnnorm_mul_le (a b : α) : ‖a * b‖₊ ≤ ‖a‖₊ * ‖b‖₊ := simpa only [← norm_toNNReal, ← Real.toNNReal_mul (norm_nonneg _)] using Real.toNNReal_mono (norm_mul_le _ _) +lemma norm_mul_le_of_le {r₁ r₂ : ℝ} (h₁ : ‖a₁‖ ≤ r₁) (h₂ : ‖a₂‖ ≤ r₂) : ‖a₁ * a₂‖ ≤ r₁ * r₂ := + (norm_mul_le ..).trans <| mul_le_mul h₁ h₂ (norm_nonneg _) ((norm_nonneg _).trans h₁) + +lemma nnnorm_mul_le_of_le {r₁ r₂ : ℝ≥0} (h₁ : ‖a₁‖₊ ≤ r₁) (h₂ : ‖a₂‖₊ ≤ r₂) : + ‖a₁ * a₂‖₊ ≤ r₁ * r₂ := (nnnorm_mul_le ..).trans <| mul_le_mul' h₁ h₂ + +lemma norm_mul₃_le : ‖a * b * c‖ ≤ ‖a‖ * ‖b‖ * ‖c‖ := norm_mul_le_of_le (norm_mul_le ..) le_rfl + +lemma nnnorm_mul₃_le : ‖a * b * c‖₊ ≤ ‖a‖₊ * ‖b‖₊ * ‖c‖₊ := + nnnorm_mul_le_of_le (norm_mul_le ..) le_rfl + theorem one_le_norm_one (β) [NormedRing β] [Nontrivial β] : 1 ≤ ‖(1 : β)‖ := (le_mul_iff_one_le_left <| norm_pos_iff.mpr (one_ne_zero : (1 : β) ≠ 0)).mp (by simpa only [mul_one] using norm_mul_le (1 : β) 1) @@ -443,6 +460,23 @@ lemma nnnorm_sub_mul_le (ha : ‖a‖₊ ≤ 1) : ‖c - a * b‖₊ ≤ ‖c - chord length is a metric on the unit complex numbers. -/ lemma nnnorm_sub_mul_le' (hb : ‖b‖₊ ≤ 1) : ‖c - a * b‖₊ ≤ ‖1 - a‖₊ + ‖c - b‖₊ := norm_sub_mul_le' hb +lemma norm_commutator_units_sub_one_le (a b : αˣ) : + ‖(a * b * a⁻¹ * b⁻¹).val - 1‖ ≤ 2 * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ * ‖a.val - 1‖ * ‖b.val - 1‖ := + calc + ‖(a * b * a⁻¹ * b⁻¹).val - 1‖ = ‖(a * b - b * a) * a⁻¹.val * b⁻¹.val‖ := by simp [sub_mul, *] + _ ≤ ‖(a * b - b * a : α)‖ * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ := norm_mul₃_le + _ = ‖(a - 1 : α) * (b - 1) - (b - 1) * (a - 1)‖ * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ := by + simp_rw [sub_one_mul, mul_sub_one]; abel_nf + _ ≤ (‖(a - 1 : α) * (b - 1)‖ + ‖(b - 1 : α) * (a - 1)‖) * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ := by + gcongr; exact norm_sub_le .. + _ ≤ (‖a.val - 1‖ * ‖b.val - 1‖ + ‖b.val - 1‖ * ‖a.val - 1‖) * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ := by + gcongr <;> exact norm_mul_le .. + _ = 2 * ‖a⁻¹.val‖ * ‖b⁻¹.val‖ * ‖a.val - 1‖ * ‖b.val - 1‖ := by ring + +lemma nnnorm_commutator_units_sub_one_le (a b : αˣ) : + ‖(a * b * a⁻¹ * b⁻¹).val - 1‖₊ ≤ 2 * ‖a⁻¹.val‖₊ * ‖b⁻¹.val‖₊ * ‖a.val - 1‖₊ * ‖b.val - 1‖₊ := by + simpa using norm_commutator_units_sub_one_le a b + /-- A homomorphism `f` between semi_normed_rings is bounded if there exists a positive constant `C` such that for all `x` in `α`, `norm (f x) ≤ C * norm x`. -/ def RingHom.IsBounded {α : Type*} [SeminormedRing α] {β : Type*} [SeminormedRing β] @@ -602,7 +636,7 @@ end NormedCommRing section NormedDivisionRing -variable [NormedDivisionRing α] {a : α} +variable [NormedDivisionRing α] {a b : α} @[simp] theorem norm_mul (a b : α) : ‖a * b‖ = ‖a‖ * ‖b‖ := @@ -684,6 +718,14 @@ theorem nndist_inv_inv₀ {z w : α} (hz : z ≠ 0) (hw : w ≠ 0) : nndist z⁻¹ w⁻¹ = nndist z w / (‖z‖₊ * ‖w‖₊) := NNReal.eq <| dist_inv_inv₀ hz hw +lemma norm_commutator_sub_one_le (ha : a ≠ 0) (hb : b ≠ 0) : + ‖a * b * a⁻¹ * b⁻¹ - 1‖ ≤ 2 * ‖a‖⁻¹ * ‖b‖⁻¹ * ‖a - 1‖ * ‖b - 1‖ := by + simpa using norm_commutator_units_sub_one_le (.mk0 a ha) (.mk0 b hb) + +lemma nnnorm_commutator_sub_one_le (ha : a ≠ 0) (hb : b ≠ 0) : + ‖a * b * a⁻¹ * b⁻¹ - 1‖₊ ≤ 2 * ‖a‖₊⁻¹ * ‖b‖₊⁻¹ * ‖a - 1‖₊ * ‖b - 1‖₊ := by + simpa using nnnorm_commutator_units_sub_one_le (.mk0 a ha) (.mk0 b hb) + namespace NormedDivisionRing section Discrete @@ -701,7 +743,7 @@ lemma norm_eq_one_iff_ne_zero_of_discrete {x : 𝕜} : ‖x‖ = 1 ↔ x ≠ 0 : · push_neg at h rcases h.eq_or_lt with h|h · rw [h] - replace h := norm_inv x ▸ inv_lt_one h + replace h := norm_inv x ▸ inv_lt_one_of_one_lt₀ h rw [← inv_inj, inv_one, ← norm_inv] exact H (by simpa) h' h obtain ⟨k, hk⟩ : ∃ k : ℕ, ‖x‖ ^ k < ε := exists_pow_lt_of_lt_one εpos h @@ -850,7 +892,7 @@ def NontriviallyNormedField.ofNormNeOne {𝕜 : Type*} [h' : NormedField 𝕜] rcases hx1.lt_or_lt with hlt | hlt · use x⁻¹ rw [norm_inv] - exact one_lt_inv (norm_pos_iff.2 hx) hlt + exact (one_lt_inv₀ (norm_pos_iff.2 hx)).2 hlt · exact ⟨x, hlt⟩ instance Real.normedCommRing : NormedCommRing ℝ := @@ -881,7 +923,6 @@ namespace NNReal open NNReal --- porting note (#10618): removed `@[simp]` because `simp` can prove this theorem norm_eq (x : ℝ≥0) : ‖(x : ℝ)‖ = x := by rw [Real.norm_eq_abs, x.abs_eq] @[simp] @@ -899,16 +940,16 @@ theorem nnnorm_norm [SeminormedAddCommGroup α] (a : α) : ‖‖a‖‖₊ = rw [Real.nnnorm_of_nonneg (norm_nonneg a)]; rfl /-- A restatement of `MetricSpace.tendsto_atTop` in terms of the norm. -/ -theorem NormedAddCommGroup.tendsto_atTop [Nonempty α] [SemilatticeSup α] {β : Type*} - [SeminormedAddCommGroup β] {f : α → β} {b : β} : +theorem NormedAddCommGroup.tendsto_atTop [Nonempty α] [Preorder α] [IsDirected α (· ≤ ·)] + {β : Type*} [SeminormedAddCommGroup β] {f : α → β} {b : β} : Tendsto f atTop (𝓝 b) ↔ ∀ ε, 0 < ε → ∃ N, ∀ n, N ≤ n → ‖f n - b‖ < ε := (atTop_basis.tendsto_iff Metric.nhds_basis_ball).trans (by simp [dist_eq_norm]) /-- A variant of `NormedAddCommGroup.tendsto_atTop` that uses `∃ N, ∀ n > N, ...` rather than `∃ N, ∀ n ≥ N, ...` -/ -theorem NormedAddCommGroup.tendsto_atTop' [Nonempty α] [SemilatticeSup α] [NoMaxOrder α] - {β : Type*} [SeminormedAddCommGroup β] {f : α → β} {b : β} : +theorem NormedAddCommGroup.tendsto_atTop' [Nonempty α] [Preorder α] [IsDirected α (· ≤ ·)] + [NoMaxOrder α] {β : Type*} [SeminormedAddCommGroup β] {f : α → β} {b : β} : Tendsto f atTop (𝓝 b) ↔ ∀ ε, 0 < ε → ∃ N, ∀ n, N < n → ‖f n - b‖ < ε := (atTop_basis_Ioi.tendsto_iff Metric.nhds_basis_ball).trans (by simp [dist_eq_norm]) @@ -1054,3 +1095,38 @@ instance toNormedCommRing [NormedCommRing R] [SubringClass S R] (s : S) : Normed { SubringClass.toNormedRing s with mul_comm := mul_comm } end SubringClass + +namespace SubfieldClass + +variable {S F : Type*} [SetLike S F] + +/-- +If `s` is a subfield of a normed field `F`, then `s` is equipped with an induced normed +field structure. +-/ +instance toNormedField [NormedField F] [SubfieldClass S F] (s : S) : NormedField s := + NormedField.induced s F (SubringClass.subtype s) Subtype.val_injective + +end SubfieldClass + +namespace AbsoluteValue + +/-- A real absolute value on a ring determines a `NormedRing` structure. -/ +noncomputable def toNormedRing {R : Type*} [Ring R] (v : AbsoluteValue R ℝ) : NormedRing R where + norm := v + dist_eq _ _ := rfl + dist_self x := by simp only [sub_self, MulHom.toFun_eq_coe, AbsoluteValue.coe_toMulHom, map_zero] + dist_comm := v.map_sub + dist_triangle := v.sub_le + edist_dist x y := rfl + norm_mul x y := (v.map_mul x y).le + eq_of_dist_eq_zero := by simp only [MulHom.toFun_eq_coe, AbsoluteValue.coe_toMulHom, + AbsoluteValue.map_sub_eq_zero_iff, imp_self, implies_true] + +/-- A real absolute value on a field determines a `NormedField` structure. -/ +noncomputable def toNormedField {K : Type*} [Field K] (v : AbsoluteValue K ℝ) : NormedField K where + toField := inferInstanceAs (Field K) + __ := v.toNormedRing + norm_mul' := v.map_mul + +end AbsoluteValue diff --git a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean index 720c5451551ec..195aa8c9adc27 100644 --- a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean +++ b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean @@ -164,3 +164,10 @@ theorem hasSum_sum_range_mul_of_summable_norm' {f g : ℕ → R} exact tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm' hf h'f hg h'g end Nat + +lemma summable_of_absolute_convergence_real {f : ℕ → ℝ} : + (∃ r, Tendsto (fun n ↦ ∑ i ∈ range n, |f i|) atTop (𝓝 r)) → Summable f + | ⟨r, hr⟩ => by + refine .of_norm ⟨r, (hasSum_iff_tendsto_nat_of_nonneg ?_ _).2 ?_⟩ + · exact fun i ↦ norm_nonneg _ + · simpa only using hr diff --git a/Mathlib/Analysis/Normed/Field/Lemmas.lean b/Mathlib/Analysis/Normed/Field/Lemmas.lean index 7b97a37837eb7..e22f72874193c 100644 --- a/Mathlib/Analysis/Normed/Field/Lemmas.lean +++ b/Mathlib/Analysis/Normed/Field/Lemmas.lean @@ -148,7 +148,7 @@ instance Pi.normedCommutativeRing {π : ι → Type*} [Fintype ι] [∀ i, Norme end NormedCommRing -- see Note [lower instance priority] -instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing α] : +instance (priority := 100) NonUnitalSeminormedRing.toContinuousMul [NonUnitalSeminormedRing α] : ContinuousMul α := ⟨continuous_iff_continuousAt.2 fun x => tendsto_iff_norm_sub_tendsto_zero.2 <| by @@ -157,8 +157,7 @@ instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing intro e calc ‖e.1 * e.2 - x.1 * x.2‖ ≤ ‖e.1 * (e.2 - x.2) + (e.1 - x.1) * x.2‖ := by - rw [_root_.mul_sub, _root_.sub_mul, sub_add_sub_cancel] - -- Porting note: `ENNReal.{mul_sub, sub_mul}` should be protected + rw [mul_sub, sub_mul, sub_add_sub_cancel] _ ≤ ‖e.1‖ * ‖e.2 - x.2‖ + ‖e.1 - x.1‖ * ‖x.2‖ := norm_add_le_of_le (norm_mul_le _ _) (norm_mul_le _ _) refine squeeze_zero (fun e => norm_nonneg _) this ?_ @@ -174,9 +173,37 @@ instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing -- see Note [lower instance priority] /-- A seminormed ring is a topological ring. -/ -instance (priority := 100) semi_normed_top_ring [NonUnitalSeminormedRing α] : +instance (priority := 100) NonUnitalSeminormedRing.toTopologicalRing [NonUnitalSeminormedRing α] : TopologicalRing α where +namespace SeparationQuotient + +instance [NonUnitalSeminormedRing α] : NonUnitalNormedRing (SeparationQuotient α) where + __ : NonUnitalRing (SeparationQuotient α) := inferInstance + __ : NormedAddCommGroup (SeparationQuotient α) := inferInstance + norm_mul := Quotient.ind₂ norm_mul_le + +instance [NonUnitalSeminormedCommRing α] : NonUnitalNormedCommRing (SeparationQuotient α) where + __ : NonUnitalCommRing (SeparationQuotient α) := inferInstance + __ : NormedAddCommGroup (SeparationQuotient α) := inferInstance + norm_mul := Quotient.ind₂ norm_mul_le + +instance [SeminormedRing α] : NormedRing (SeparationQuotient α) where + __ : Ring (SeparationQuotient α) := inferInstance + __ : NormedAddCommGroup (SeparationQuotient α) := inferInstance + norm_mul := Quotient.ind₂ norm_mul_le + +instance [SeminormedCommRing α] : NormedCommRing (SeparationQuotient α) where + __ : CommRing (SeparationQuotient α) := inferInstance + __ : NormedAddCommGroup (SeparationQuotient α) := inferInstance + norm_mul := Quotient.ind₂ norm_mul_le + +instance [SeminormedAddCommGroup α] [One α] [NormOneClass α] : + NormOneClass (SeparationQuotient α) where + norm_one := norm_one (α := α) + +end SeparationQuotient + section NormedDivisionRing variable [NormedDivisionRing α] {a : α} @@ -269,9 +296,8 @@ instance (priority := 100) NormedDivisionRing.to_hasContinuousInv₀ : HasContin have e0 : e ≠ 0 := norm_pos_iff.1 (ε0.trans he) calc ‖e⁻¹ - r⁻¹‖ = ‖r‖⁻¹ * ‖r - e‖ * ‖e‖⁻¹ := by - rw [← norm_inv, ← norm_inv, ← norm_mul, ← norm_mul, _root_.mul_sub, _root_.sub_mul, + rw [← norm_inv, ← norm_inv, ← norm_mul, ← norm_mul, mul_sub, sub_mul, mul_assoc _ e, inv_mul_cancel₀ r0, mul_inv_cancel₀ e0, one_mul, mul_one] - -- Porting note: `ENNReal.{mul_sub, sub_mul}` should be `protected` _ = ‖r - e‖ / ‖r‖ / ‖e‖ := by field_simp [mul_comm] _ ≤ ‖r - e‖ / ‖r‖ / ε := by gcongr refine squeeze_zero' (Eventually.of_forall fun _ => norm_nonneg _) this ?_ @@ -292,6 +318,19 @@ example [Monoid β] (φ : β →* α) {x : β} {k : ℕ+} (h : x ^ (k : ℕ) = 1 @[simp] lemma AddChar.norm_apply {G : Type*} [AddLeftCancelMonoid G] [Finite G] (ψ : AddChar G α) (x : G) : ‖ψ x‖ = 1 := (ψ.toMonoidHom.isOfFinOrder <| isOfFinOrder_of_finite _).norm_eq_one +lemma NormedField.tendsto_norm_inverse_nhdsWithin_0_atTop : + Tendsto (fun x : α ↦ ‖x⁻¹‖) (𝓝[≠] 0) atTop := + (tendsto_inv_zero_atTop.comp tendsto_norm_zero').congr fun x ↦ (norm_inv x).symm + +lemma NormedField.tendsto_norm_zpow_nhdsWithin_0_atTop {m : ℤ} (hm : m < 0) : + Tendsto (fun x : α ↦ ‖x ^ m‖) (𝓝[≠] 0) atTop := by + obtain ⟨m, rfl⟩ := neg_surjective m + rw [neg_lt_zero] at hm + lift m to ℕ using hm.le + rw [Int.natCast_pos] at hm + simp only [norm_pow, zpow_neg, zpow_natCast, ← inv_pow] + exact (tendsto_pow_atTop hm.ne').comp NormedField.tendsto_norm_inverse_nhdsWithin_0_atTop + end NormedDivisionRing namespace NormedField @@ -333,6 +372,22 @@ theorem denseRange_nnnorm : DenseRange (nnnorm : α → ℝ≥0) := end Densely +section NontriviallyNormedField +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {n : ℤ} {x : 𝕜} + +@[simp] +protected lemma continuousAt_zpow : ContinuousAt (fun x ↦ x ^ n) x ↔ x ≠ 0 ∨ 0 ≤ n := by + refine ⟨?_, continuousAt_zpow₀ _ _⟩ + contrapose! + rintro ⟨rfl, hm⟩ hc + exact not_tendsto_atTop_of_tendsto_nhds (hc.tendsto.mono_left nhdsWithin_le_nhds).norm + (tendsto_norm_zpow_nhdsWithin_0_atTop hm) + +@[simp] +protected lemma continuousAt_inv : ContinuousAt Inv.inv x ↔ x ≠ 0 := by + simpa using NormedField.continuousAt_zpow (n := -1) (x := x) + +end NontriviallyNormedField end NormedField namespace NNReal diff --git a/Mathlib/Analysis/Normed/Field/Ultra.lean b/Mathlib/Analysis/Normed/Field/Ultra.lean new file mode 100644 index 0000000000000..fcc35e4331ce7 --- /dev/null +++ b/Mathlib/Analysis/Normed/Field/Ultra.lean @@ -0,0 +1,132 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Group.Ultra +import Mathlib.Data.Nat.Choose.Sum + +/-! +## Sufficient conditions to have an ultrametric norm on a division ring + +This file provides ways of constructing an instance of `IsUltrametricDist` based on +facts about the existing norm. + +## Main results + +* `isUltrametricDist_of_forall_norm_natCast_le_one`: a norm in a division ring is ultrametric + if the norm of the image of a natural is less than or equal to one + +## Implementation details + +The proof relies on a bounded-from-above argument. The main result has a longer proof +to be able to be applied in noncommutative division rings. + +## Tags + +ultrametric, nonarchimedean +-/ +open Metric NNReal + +namespace IsUltrametricDist + +section sufficient + +variable {R : Type*} [NormedDivisionRing R] + +lemma isUltrametricDist_of_forall_norm_add_one_le_max_norm_one + (h : ∀ x : R, ‖x + 1‖ ≤ max ‖x‖ 1) : IsUltrametricDist R := by + refine isUltrametricDist_of_forall_norm_add_le_max_norm (fun x y ↦ ?_) + rcases eq_or_ne y 0 with rfl | hy + · simpa only [add_zero] using le_max_left _ _ + · have p : 0 < ‖y‖ := norm_pos_iff.mpr hy + simpa only [div_add_one hy, norm_div, div_le_iff₀ p, max_mul_of_nonneg _ _ p.le, one_mul, + div_mul_cancel₀ _ p.ne'] using h (x / y) + +lemma isUltrametricDist_of_forall_norm_add_one_of_norm_le_one + (h : ∀ x : R, ‖x‖ ≤ 1 → ‖x + 1‖ ≤ 1) : IsUltrametricDist R := by + refine isUltrametricDist_of_forall_norm_add_one_le_max_norm_one fun x ↦ ?_ + rcases le_or_lt ‖x‖ 1 with H|H + · exact (h _ H).trans (le_max_right _ _) + · suffices ‖x + 1‖ ≤ ‖x‖ from this.trans (le_max_left _ _) + rw [← div_le_div_right (c := ‖x‖) (H.trans' zero_lt_one), div_self (H.trans' zero_lt_one).ne', + ← norm_div, add_div, div_self (by simpa using (H.trans' zero_lt_one)), add_comm] + apply h + simp [inv_le_one_iff₀, H.le] + +lemma isUltrametricDist_of_forall_norm_sub_one_of_norm_le_one + (h : ∀ x : R, ‖x‖ ≤ 1 → ‖x - 1‖ ≤ 1) : IsUltrametricDist R := by + have (x : R) (hx : ‖x‖ ≤ 1) : ‖x + 1‖ ≤ 1 := by + simpa only [← neg_add', norm_neg] using h (-x) (norm_neg x ▸ hx) + exact isUltrametricDist_of_forall_norm_add_one_of_norm_le_one this + +/-- This technical lemma is used in the proof of +`isUltrametricDist_of_forall_norm_natCast_le_one`. -/ +lemma isUltrametricDist_of_forall_pow_norm_le_nsmul_pow_max_one_norm + (h : ∀ (x : R) (m : ℕ), ‖x + 1‖ ^ m ≤ (m + 1) • max 1 (‖x‖ ^ m)) : + IsUltrametricDist R := by + -- it will suffice to prove that `‖x + 1‖ ≤ max 1 ‖x‖` + refine isUltrametricDist_of_forall_norm_add_one_le_max_norm_one fun x ↦ ?_ + -- Morally, we want to deduce this from the hypothesis `h` by taking an `m`-th root and showing + -- that `(m + 1) ^ (1 / m)` gets arbitrarily close to 1, although we will formalise this in a way + -- that avoids explicitly mentioning `m`-th roots. + -- First note it suffices to show that `‖x + 1‖ ≤ a` for all `a : ℝ` with `max ‖x‖ 1 < a`. + rw [max_comm] + refine le_of_forall_le_of_dense fun a ha ↦ ?_ + have ha' : 1 < a := (max_lt_iff.mp ha).left + -- `max 1 ‖x‖ < a`, so there must be some `m : ℕ` such that `m + 1 < (a / max 1 ‖x‖) ^ m` + -- by the virtue of exponential growth being faster than linear growth + obtain ⟨m, hm⟩ : ∃ m : ℕ, ((m + 1) : ℕ) < (a / (max 1 ‖x‖)) ^ m := by + apply_mod_cast Real.exists_natCast_add_one_lt_pow_of_one_lt + rwa [one_lt_div (by positivity)] + -- and we rearrange again to get `(m + 1) • max 1 ‖x‖ ^ m < a ^ m` + rw [div_pow, lt_div_iff₀ (by positivity), ← nsmul_eq_mul] at hm + -- which squeezes down to get our `‖x + 1‖ ≤ a` using our to-be-proven hypothesis of + -- `‖x + 1‖ ^ m ≤ (m + 1) • max 1 ‖x‖ ^ m`, so we're done + -- we can distribute powers into the right term of `max` + have hp : max 1 ‖x‖ ^ m = max 1 (‖x‖ ^ m) := by + have : MonotoneOn (fun a : ℝ ↦ a ^ m) (Set.Ici _) := fun a h b _ h' ↦ pow_le_pow_left h h' _ + rw [this.map_max zero_le_one (norm_nonneg x), one_pow] + rw [hp] at hm + refine le_of_pow_le_pow_left (fun h ↦ ?_) (zero_lt_one.trans ha').le ((h _ _).trans hm.le) + simp only [h, zero_add, pow_zero, max_self, one_smul, lt_self_iff_false] at hm + +/-- To prove that a normed division ring is nonarchimedean, it suffices to prove that the norm +of the image of any natural is less than or equal to one. -/ +lemma isUltrametricDist_of_forall_norm_natCast_le_one + (h : ∀ n : ℕ, ‖(n : R)‖ ≤ 1) : IsUltrametricDist R := by + -- from a previous lemma, suffices to prove that for all `m`, we have + -- `‖x + 1‖ ^ m ≤ (m + 1) • max 1 ‖x‖ ^ m` + refine isUltrametricDist_of_forall_pow_norm_le_nsmul_pow_max_one_norm (fun x m ↦ ?_) + -- we first use our hypothesis about the norm of naturals to have that multiplication by + -- naturals keeps the norm small + replace h (x : R) (n : ℕ) : ‖n • x‖ ≤ ‖x‖ := by + rw [nsmul_eq_mul, norm_mul] + rcases (norm_nonneg x).eq_or_lt with hx | hx + · simp only [← hx, mul_zero, le_refl] + · simpa only [mul_le_iff_le_one_left hx] using h _ + -- we expand the LHS using the binomial theorem, and apply the hypothesis to bound each term by + -- a power of ‖x‖ + transitivity ∑ k ∈ Finset.range (m + 1), ‖x‖ ^ k + · simpa only [← norm_pow, (Commute.one_right x).add_pow, one_pow, mul_one, nsmul_eq_mul, + Nat.cast_comm] using (norm_sum_le _ _).trans (Finset.sum_le_sum fun _ _ ↦ h _ _) + -- the nature of the norm means that one of `1` and `‖x‖ ^ m` is the largest of the two, so the + -- other terms in the binomial expansion are bounded by the max of these, and the number of terms + -- in the sum is precisely `m + 1` + rw [← Finset.card_range (m + 1), ← Finset.sum_const, Finset.card_range] + rcases max_cases 1 (‖x‖ ^ m) with (⟨hm, hx⟩|⟨hm, hx⟩) <;> rw [hm] <;> + -- which we show by comparing the terms in the sum one by one + refine Finset.sum_le_sum fun i hi ↦ ?_ + · rcases eq_or_ne m 0 with rfl | hm + · simp only [pow_zero, le_refl, + show i = 0 by simpa only [zero_add, Finset.range_one, Finset.mem_singleton] using hi] + · rw [pow_le_one_iff_of_nonneg (norm_nonneg _) hm] at hx + exact pow_le_one₀ (norm_nonneg _) hx + · refine pow_le_pow_right₀ ?_ (by simpa only [Finset.mem_range, Nat.lt_succ] using hi) + contrapose! hx + exact pow_le_one₀ (norm_nonneg _) hx.le + +end sufficient + +end IsUltrametricDist diff --git a/Mathlib/Analysis/Normed/Group/AddTorsor.lean b/Mathlib/Analysis/Normed/Group/AddTorsor.lean index c4b97754790bb..e3a3f8109709e 100644 --- a/Mathlib/Analysis/Normed/Group/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Group/AddTorsor.lean @@ -44,8 +44,7 @@ variable {α V P W Q : Type*} [SeminormedAddCommGroup V] [PseudoMetricSpace P] [ instance (priority := 100) NormedAddTorsor.to_isometricVAdd : IsometricVAdd V P := ⟨fun c => Isometry.of_dist_eq fun x y => by - -- porting note (#10745): was `simp [NormedAddTorsor.dist_eq_norm']` - rw [NormedAddTorsor.dist_eq_norm', NormedAddTorsor.dist_eq_norm', vadd_vsub_vadd_cancel_left]⟩ + simp [NormedAddTorsor.dist_eq_norm']⟩ /-- A `SeminormedAddCommGroup` is a `NormedAddTorsor` over itself. -/ instance (priority := 100) SeminormedAddCommGroup.toNormedAddTorsor : NormedAddTorsor V V where @@ -99,8 +98,7 @@ theorem nndist_vadd_cancel_right (v₁ v₂ : V) (x : P) : nndist (v₁ +ᵥ x) @[simp] theorem dist_vadd_left (v : V) (x : P) : dist (v +ᵥ x) x = ‖v‖ := by - -- porting note (#10745): was `simp [dist_eq_norm_vsub V _ x]` - rw [dist_eq_norm_vsub V _ x, vadd_vsub] + simp [dist_eq_norm_vsub V _ x] @[simp] theorem nndist_vadd_left (v : V) (x : P) : nndist (v +ᵥ x) x = ‖v‖₊ := diff --git a/Mathlib/Analysis/Normed/Group/BallSphere.lean b/Mathlib/Analysis/Normed/Group/BallSphere.lean index 09505d665f7de..a861ce39e6bba 100644 --- a/Mathlib/Analysis/Normed/Group/BallSphere.lean +++ b/Mathlib/Analysis/Normed/Group/BallSphere.lean @@ -27,8 +27,7 @@ instance : InvolutiveNeg (sphere (0 : E) r) where theorem coe_neg_sphere {r : ℝ} (v : sphere (0 : E) r) : ↑(-v) = (-v : E) := rfl -instance : ContinuousNeg (sphere (0 : E) r) := - Inducing.continuousNeg inducing_subtype_val fun _ => rfl +instance : ContinuousNeg (sphere (0 : E) r) := IsInducing.subtypeVal.continuousNeg fun _ => rfl /-- We equip the ball, in a seminormed group, with a formal operation of negation, namely the antipodal map. -/ @@ -38,8 +37,7 @@ instance {r : ℝ} : InvolutiveNeg (ball (0 : E) r) where @[simp] theorem coe_neg_ball {r : ℝ} (v : ball (0 : E) r) : ↑(-v) = (-v : E) := rfl -instance : ContinuousNeg (ball (0 : E) r) := - Inducing.continuousNeg inducing_subtype_val fun _ => rfl +instance : ContinuousNeg (ball (0 : E) r) := IsInducing.subtypeVal.continuousNeg fun _ => rfl /-- We equip the closed ball, in a seminormed group, with a formal operation of negation, namely the antipodal map. -/ @@ -49,5 +47,4 @@ instance {r : ℝ} : InvolutiveNeg (closedBall (0 : E) r) where @[simp] theorem coe_neg_closedBall {r : ℝ} (v : closedBall (0 : E) r) : ↑(-v) = (-v : E) := rfl -instance : ContinuousNeg (closedBall (0 : E) r) := - Inducing.continuousNeg inducing_subtype_val fun _ => rfl +instance : ContinuousNeg (closedBall (0 : E) r) := IsInducing.subtypeVal.continuousNeg fun _ => rfl diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 1eba1978859f4..70148a77d3bea 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -285,7 +285,7 @@ existing `UniformSpace` instance on `E`)."] abbrev GroupSeminorm.toSeminormedGroup [Group E] (f : GroupSeminorm E) : SeminormedGroup E where dist x y := f (x / y) norm := f - dist_eq x y := rfl + dist_eq _ _ := rfl dist_self x := by simp only [div_self', map_one_eq_zero] dist_triangle := le_map_div_add_map_div f dist_comm := map_div_rev f @@ -338,7 +338,7 @@ abbrev GroupNorm.toNormedCommGroup [CommGroup E] (f : GroupNorm E) : NormedCommG section SeminormedGroup variable [SeminormedGroup E] [SeminormedGroup F] [SeminormedGroup G] {s : Set E} - {a a₁ a₂ b b₁ b₂ : E} {r r₁ r₂ : ℝ} + {a a₁ a₂ b b₁ b₂ c : E} {r r₁ r₂ : ℝ} @[to_additive] theorem dist_eq_norm_div (a b : E) : dist a b = ‖a / b‖ := @@ -387,13 +387,14 @@ theorem dist_mulIndicator (s t : Set α) (f : α → E) (x : α) : theorem norm_mul_le' (a b : E) : ‖a * b‖ ≤ ‖a‖ + ‖b‖ := by simpa [dist_eq_norm_div] using dist_triangle a 1 b⁻¹ -@[to_additive] -theorem norm_mul_le_of_le (h₁ : ‖a₁‖ ≤ r₁) (h₂ : ‖a₂‖ ≤ r₂) : ‖a₁ * a₂‖ ≤ r₁ + r₂ := +/-- **Triangle inequality** for the norm. -/ +@[to_additive norm_add_le_of_le "**Triangle inequality** for the norm."] +theorem norm_mul_le_of_le' (h₁ : ‖a₁‖ ≤ r₁) (h₂ : ‖a₂‖ ≤ r₂) : ‖a₁ * a₂‖ ≤ r₁ + r₂ := (norm_mul_le' a₁ a₂).trans <| add_le_add h₁ h₂ -@[to_additive norm_add₃_le] -theorem norm_mul₃_le (a b c : E) : ‖a * b * c‖ ≤ ‖a‖ + ‖b‖ + ‖c‖ := - norm_mul_le_of_le (norm_mul_le' _ _) le_rfl +/-- **Triangle inequality** for the norm. -/ +@[to_additive norm_add₃_le "**Triangle inequality** for the norm."] +lemma norm_mul₃_le' : ‖a * b * c‖ ≤ ‖a‖ + ‖b‖ + ‖c‖ := norm_mul_le_of_le' (norm_mul_le' _ _) le_rfl @[to_additive] lemma norm_div_le_norm_div_add_norm_div (a b c : E) : ‖a / c‖ ≤ ‖a / b‖ + ‖b / c‖ := by @@ -515,14 +516,14 @@ theorem mem_ball_iff_norm'' : b ∈ ball a r ↔ ‖b / a‖ < r := by rw [mem_b @[to_additive mem_ball_iff_norm'] theorem mem_ball_iff_norm''' : b ∈ ball a r ↔ ‖a / b‖ < r := by rw [mem_ball', dist_eq_norm_div] -@[to_additive] -- Porting note (#10618): `simp` can prove it +@[to_additive] theorem mem_ball_one_iff : a ∈ ball (1 : E) r ↔ ‖a‖ < r := by rw [mem_ball, dist_one_right] @[to_additive mem_closedBall_iff_norm] theorem mem_closedBall_iff_norm'' : b ∈ closedBall a r ↔ ‖b / a‖ ≤ r := by rw [mem_closedBall, dist_eq_norm_div] -@[to_additive] -- Porting note (#10618): `simp` can prove it +@[to_additive] theorem mem_closedBall_one_iff : a ∈ closedBall (1 : E) r ↔ ‖a‖ ≤ r := by rw [mem_closedBall, dist_one_right] @@ -635,6 +636,13 @@ theorem nndist_eq_nnnorm_div (a b : E) : nndist a b = ‖a / b‖₊ := alias nndist_eq_nnnorm := nndist_eq_nnnorm_sub +@[to_additive (attr := simp)] +theorem nndist_one_right (a : E) : nndist a 1 = ‖a‖₊ := by simp [nndist_eq_nnnorm_div] + +@[to_additive (attr := simp)] +theorem edist_one_right (a : E) : edist a 1 = ‖a‖₊ := by + rw [edist_nndist, nndist_one_right] + @[to_additive (attr := simp) nnnorm_zero] theorem nnnorm_one' : ‖(1 : E)‖₊ = 0 := NNReal.eq norm_one' @@ -653,6 +661,13 @@ theorem nnnorm_mul_le' (a b : E) : ‖a * b‖₊ ≤ ‖a‖₊ + ‖b‖₊ := theorem nnnorm_inv' (a : E) : ‖a⁻¹‖₊ = ‖a‖₊ := NNReal.eq <| norm_inv' a +@[to_additive (attr := simp)] +theorem nndist_one_left (a : E) : nndist 1 a = ‖a‖₊ := by simp [nndist_eq_nnnorm_div] + +@[to_additive (attr := simp)] +theorem edist_one_left (a : E) : edist 1 a = ‖a‖₊ := by + rw [edist_nndist, nndist_one_left] + open scoped symmDiff in @[to_additive] theorem nndist_mulIndicator (s t : Set α) (f : α → E) (x : α) : @@ -758,7 +773,8 @@ theorem tendsto_norm_div_self (x : E) : Tendsto (fun a => ‖a / x‖) (𝓝 x) theorem tendsto_norm' {x : E} : Tendsto (fun a => ‖a‖) (𝓝 x) (𝓝 ‖x‖) := by simpa using tendsto_id.dist (tendsto_const_nhds : Tendsto (fun _a => (1 : E)) _ _) -@[to_additive] +/-- See `tendsto_norm_one` for a version with pointed neighborhoods. -/ +@[to_additive "See `tendsto_norm_zero` for a version with pointed neighborhoods."] theorem tendsto_norm_one : Tendsto (fun a : E => ‖a‖) (𝓝 1) (𝓝 0) := by simpa using tendsto_norm_div_self (1 : E) @@ -770,6 +786,16 @@ theorem continuous_norm' : Continuous fun a : E => ‖a‖ := by theorem continuous_nnnorm' : Continuous fun a : E => ‖a‖₊ := continuous_norm'.subtype_mk _ +set_option linter.docPrime false in +@[to_additive Inseparable.norm_eq_norm] +theorem Inseparable.norm_eq_norm' {u v : E} (h : Inseparable u v) : ‖u‖ = ‖v‖ := + h.map continuous_norm' |>.eq + +set_option linter.docPrime false in +@[to_additive Inseparable.nnnorm_eq_nnnorm] +theorem Inseparable.nnnorm_eq_nnnorm' {u v : E} (h : Inseparable u v) : ‖u‖₊ = ‖v‖₊ := + h.map continuous_nnnorm' |>.eq + @[to_additive] theorem mem_closure_one_iff_norm {x : E} : x ∈ closure ({1} : Set E) ↔ ‖x‖ = 0 := by rw [← closedBall_zero', mem_closedBall_one_iff, (norm_nonneg' x).le_iff_eq] @@ -1025,7 +1051,7 @@ theorem norm_pow_le_mul_norm (n : ℕ) (a : E) : ‖a ^ n‖ ≤ n * ‖a‖ := induction n with | zero => simp | succ n ih => - simpa only [pow_succ, Nat.cast_succ, add_mul, one_mul] using norm_mul_le_of_le ih le_rfl + simpa only [pow_succ, Nat.cast_succ, add_mul, one_mul] using norm_mul_le_of_le' ih le_rfl @[to_additive nnnorm_nsmul_le] theorem nnnorm_pow_le_mul_norm (n : ℕ) (a : E) : ‖a ^ n‖₊ ≤ n * ‖a‖₊ := by @@ -1047,20 +1073,19 @@ theorem pow_mem_ball {n : ℕ} (hn : 0 < n) (h : a ∈ ball b r) : a ^ n ∈ bal rw [nsmul_eq_mul] nlinarith -@[to_additive] -- Porting note (#10618): `simp` can prove this +@[to_additive] theorem mul_mem_closedBall_mul_iff {c : E} : a * c ∈ closedBall (b * c) r ↔ a ∈ closedBall b r := by simp only [mem_closedBall, dist_eq_norm_div, mul_div_mul_right_eq_div] -@[to_additive] -- Porting note (#10618): `simp` can prove this +@[to_additive] theorem mul_mem_ball_mul_iff {c : E} : a * c ∈ ball (b * c) r ↔ a ∈ ball b r := by simp only [mem_ball, dist_eq_norm_div, mul_div_mul_right_eq_div] @[to_additive] theorem smul_closedBall'' : a • closedBall b r = closedBall (a • b) r := by ext - simp [mem_closedBall, Set.mem_smul_set, dist_eq_norm_div, _root_.div_eq_inv_mul, ← + simp [mem_closedBall, Set.mem_smul_set, dist_eq_norm_div, div_eq_inv_mul, ← eq_inv_mul_iff_mul_eq, mul_assoc] - -- Porting note: `ENNReal.div_eq_inv_mul` should be `protected`? @[to_additive] theorem smul_ball'' : a • ball b r = ball (a • b) r := by @@ -1247,6 +1272,14 @@ alias ⟨eq_of_norm_div_eq_zero, _⟩ := norm_div_eq_zero_iff attribute [to_additive] eq_of_norm_div_eq_zero +@[to_additive] +theorem eq_one_or_norm_pos (a : E) : a = 1 ∨ 0 < ‖a‖ := by + simpa [eq_comm] using (norm_nonneg' a).eq_or_lt + +@[to_additive] +theorem eq_one_or_nnnorm_pos (a : E) : a = 1 ∨ 0 < ‖a‖₊ := + eq_one_or_norm_pos a + @[to_additive (attr := simp) nnnorm_eq_zero] theorem nnnorm_eq_zero' : ‖a‖₊ = 0 ↔ a = 1 := by rw [← NNReal.coe_eq_zero, coe_nnnorm', norm_eq_zero''] @@ -1258,6 +1291,11 @@ theorem nnnorm_ne_zero_iff' : ‖a‖₊ ≠ 0 ↔ a ≠ 1 := @[to_additive (attr := simp) nnnorm_pos] lemma nnnorm_pos' : 0 < ‖a‖₊ ↔ a ≠ 1 := pos_iff_ne_zero.trans nnnorm_ne_zero_iff' +/-- See `tendsto_norm_one` for a version with full neighborhoods. -/ +@[to_additive "See `tendsto_norm_zero` for a version with full neighborhoods."] +lemma tendsto_norm_one' : Tendsto (norm : E → ℝ) (𝓝[≠] 1) (𝓝[>] 0) := + tendsto_norm_one.inf <| tendsto_principal_principal.2 fun _ hx ↦ norm_pos_iff''.2 hx + @[to_additive] theorem tendsto_norm_div_self_punctured_nhds (a : E) : Tendsto (fun x => ‖x / a‖) (𝓝[≠] a) (𝓝[>] 0) := @@ -1389,3 +1427,5 @@ instance (priority := 75) normedCommGroup [NormedCommGroup E] {S : Type*} [SetLi NormedCommGroup.induced _ _ (SubgroupClass.subtype s) Subtype.coe_injective end SubgroupClass + +lemma tendsto_norm_atTop_atTop : Tendsto (norm : ℝ → ℝ) atTop atTop := tendsto_abs_atTop_atTop diff --git a/Mathlib/Analysis/Normed/Group/Bounded.lean b/Mathlib/Analysis/Normed/Group/Bounded.lean index 329d2bfa734ce..bd28a0b52f340 100644 --- a/Mathlib/Analysis/Normed/Group/Bounded.lean +++ b/Mathlib/Analysis/Normed/Group/Bounded.lean @@ -161,8 +161,6 @@ lemma HasCompactMulSupport.exists_pos_le_norm [One E] (hf : HasCompactMulSupport obtain ⟨K, ⟨hK1, hK2⟩⟩ := exists_compact_iff_hasCompactMulSupport.mpr hf obtain ⟨S, hS, hS'⟩ := hK1.isBounded.exists_pos_norm_le refine ⟨S + 1, by positivity, fun x hx => hK2 x ((mt <| hS' x) ?_)⟩ - -- Porting note: `ENNReal.add_lt_add` should be `protected`? - -- [context: we used `_root_.add_lt_add` in a previous version of this proof] contrapose! hx exact lt_add_of_le_of_pos hx zero_lt_one diff --git a/Mathlib/Analysis/Normed/Group/Hom.lean b/Mathlib/Analysis/Normed/Group/Hom.lean index 36439765ebe21..7cde007647e8d 100644 --- a/Mathlib/Analysis/Normed/Group/Hom.lean +++ b/Mathlib/Analysis/Normed/Group/Hom.lean @@ -630,7 +630,7 @@ variable {V W V₁ V₂ V₃ : Type*} [SeminormedAddCommGroup V] [SeminormedAddC @[simps!] def incl (s : AddSubgroup V) : NormedAddGroupHom s V where toFun := (Subtype.val : s → V) - map_add' v w := AddSubgroup.coe_add _ _ _ + map_add' _ _ := AddSubgroup.coe_add _ _ _ bound' := ⟨1, fun v => by rw [one_mul, AddSubgroup.coe_norm]⟩ theorem norm_incl {V' : AddSubgroup V} (x : V') : ‖incl _ x‖ = ‖x‖ := diff --git a/Mathlib/Analysis/Normed/Group/Pointwise.lean b/Mathlib/Analysis/Normed/Group/Pointwise.lean index ae8862a8aa948..8d853167e1370 100644 --- a/Mathlib/Analysis/Normed/Group/Pointwise.lean +++ b/Mathlib/Analysis/Normed/Group/Pointwise.lean @@ -22,7 +22,7 @@ variable {E : Type*} section SeminormedGroup -variable [SeminormedGroup E] {ε δ : ℝ} {s t : Set E} {x y : E} +variable [SeminormedGroup E] {s t : Set E} -- note: we can't use `LipschitzOnWith.isBounded_image2` here without adding `[IsometricSMul E E]` @[to_additive] @@ -31,7 +31,7 @@ theorem Bornology.IsBounded.mul (hs : IsBounded s) (ht : IsBounded t) : IsBounde obtain ⟨Rt, hRt⟩ : ∃ R, ∀ x ∈ t, ‖x‖ ≤ R := ht.exists_norm_le' refine isBounded_iff_forall_norm_le'.2 ⟨Rs + Rt, ?_⟩ rintro z ⟨x, hx, y, hy, rfl⟩ - exact norm_mul_le_of_le (hRs x hx) (hRt y hy) + exact norm_mul_le_of_le' (hRs x hx) (hRt y hy) @[to_additive] theorem Bornology.IsBounded.of_mul (hst : IsBounded (s * t)) : IsBounded s ∨ IsBounded t := @@ -50,7 +50,7 @@ end SeminormedGroup section SeminormedCommGroup -variable [SeminormedCommGroup E] {ε δ : ℝ} {s t : Set E} {x y : E} +variable [SeminormedCommGroup E] {δ : ℝ} {s : Set E} {x y : E} section EMetric @@ -73,7 +73,7 @@ theorem ediam_mul_le (x y : Set E) : EMetric.diam (x * y) ≤ EMetric.diam x + E end EMetric -variable (ε δ s t x y) +variable (δ s x y) @[to_additive (attr := simp)] theorem inv_thickening : (thickening δ s)⁻¹ = thickening δ s⁻¹ := by @@ -188,7 +188,7 @@ theorem ball_mul : ball x δ * s = x • thickening δ s := by rw [mul_comm, mul @[to_additive (attr := simp)] theorem ball_div : ball x δ / s = x • thickening δ s⁻¹ := by simp [div_eq_mul_inv] -variable {ε δ s t x y} +variable {δ s x y} @[to_additive] theorem IsCompact.mul_closedBall_one (hs : IsCompact s) (hδ : 0 ≤ δ) : diff --git a/Mathlib/Analysis/Normed/Group/Quotient.lean b/Mathlib/Analysis/Normed/Group/Quotient.lean index 9acc022a5fcfb..f4f3b11f8e753 100644 --- a/Mathlib/Analysis/Normed/Group/Quotient.lean +++ b/Mathlib/Analysis/Normed/Group/Quotient.lean @@ -5,7 +5,7 @@ Authors: Patrick Massot, Riccardo Brasca -/ import Mathlib.Analysis.Normed.Module.Basic import Mathlib.Analysis.Normed.Group.Hom -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.Topology.MetricSpace.HausdorffDistance /-! diff --git a/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean b/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean index f63a09356056d..40b402cc07b73 100644 --- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean +++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp.lean @@ -112,8 +112,7 @@ theorem iso_isometry_of_normNoninc {V W : SemiNormedGrp} (i : V ≅ W) (h1 : i.h intro v apply le_antisymm (h1 v) calc - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - ‖v‖ = ‖i.inv (i.hom v)‖ := by erw [Iso.hom_inv_id_apply] + ‖v‖ = ‖i.inv (i.hom v)‖ := by rw [Iso.hom_inv_id_apply] _ ≤ ‖i.hom v‖ := h2 _ end SemiNormedGrp @@ -132,7 +131,7 @@ instance : CoeSort SemiNormedGrp₁ Type* where instance : LargeCategory.{u} SemiNormedGrp₁ where Hom X Y := { f : NormedAddGroupHom X Y // f.NormNoninc } id X := ⟨NormedAddGroupHom.id X, NormedAddGroupHom.NormNoninc.id⟩ - comp {X Y Z} f g := ⟨g.1.comp f.1, g.2.comp f.2⟩ + comp {_ _ _} f g := ⟨g.1.comp f.1, g.2.comp f.2⟩ -- Porting note (#10754): added instance instance instFunLike (X Y : SemiNormedGrp₁) : FunLike (X ⟶ Y) X Y where diff --git a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean index ffdb4b1697738..4fe5df1db1b36 100644 --- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean +++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean @@ -94,20 +94,15 @@ instance : Preadditive SemiNormedGrp.{u} where -- Porting note: failing simps probably due to instance synthesis issues with concrete -- cats; see the gymnastics below for what used to be -- simp only [add_apply, comp_apply. map_add] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - rw [NormedAddGroupHom.add_apply]; erw [CategoryTheory.comp_apply, CategoryTheory.comp_apply, + rw [NormedAddGroupHom.add_apply, CategoryTheory.comp_apply, CategoryTheory.comp_apply, CategoryTheory.comp_apply, @NormedAddGroupHom.add_apply _ _ (_) (_)] convert map_add g (f x) (f' x) comp_add _ _ _ _ _ _ := by ext -- Porting note: failing simps probably due to instance synthesis issues with concrete -- cats; see the gymnastics below for what used to be - -- simp only [add_apply, comp_apply. map_add] - rw [NormedAddGroupHom.add_apply] - -- This used to be a single `rw`, but we need `erw` after leanprover/lean4#2644 - erw [CategoryTheory.comp_apply, CategoryTheory.comp_apply, + rw [NormedAddGroupHom.add_apply, CategoryTheory.comp_apply, CategoryTheory.comp_apply, CategoryTheory.comp_apply, @NormedAddGroupHom.add_apply _ _ (_) (_)] - rfl instance : Functor.Additive completion where map_add := NormedAddGroupHom.completion_add _ _ diff --git a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean index e5aff9ade9489..01fad0a4ff9d9 100644 --- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean +++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Kernels.lean @@ -78,7 +78,7 @@ instance : HasCokernels SemiNormedGrp₁.{u} where simp -- This used to be the end of the proof before leanprover/lean4#2644 erw [zero_apply]) - fun s m w => + fun _ _ w => Subtype.eq (NormedAddGroupHom.lift_unique f.1.range _ _ _ (congr_arg Subtype.val w : _)) } @@ -123,7 +123,7 @@ instance hasLimit_parallelPair {V W : SemiNormedGrp.{u}} (f g : V ⟶ W) : NormedAddGroupHom.ker.lift (Fork.ι c) _ <| show NormedAddGroupHom.compHom (f - g) c.ι = 0 by rw [AddMonoidHom.map_sub, AddMonoidHom.sub_apply, sub_eq_zero]; exact c.condition) - (fun c => NormedAddGroupHom.ker.incl_comp_lift _ _ _) fun c g h => by + (fun _ => NormedAddGroupHom.ker.incl_comp_lift _ _ _) fun c g h => by -- Porting note: the `simp_rw` was `rw [← h]` but motive is not type correct in mathlib4 ext x; dsimp; simp_rw [← h]; rfl} @@ -145,14 +145,12 @@ def cokernelCocone {X Y : SemiNormedGrp.{u}} (f : X ⟶ Y) : Cofork f 0 := ext a simp only [comp_apply, Limits.zero_comp] -- Porting note: `simp` not firing on the below - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [comp_apply, NormedAddGroupHom.zero_apply] + rw [comp_apply, NormedAddGroupHom.zero_apply] -- Porting note: Lean 3 didn't need this instance letI : SeminormedAddCommGroup ((forget SemiNormedGrp).obj Y) := (inferInstance : SeminormedAddCommGroup Y) -- Porting note: again simp doesn't seem to be firing in the below line - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [← NormedAddGroupHom.mem_ker, f.range.ker_normedMk, f.mem_range] + rw [← NormedAddGroupHom.mem_ker, f.range.ker_normedMk, f.mem_range] -- This used to be `simp only [exists_apply_eq_apply]` before leanprover/lean4#2644 convert exists_apply_eq_apply f a) @@ -181,7 +179,7 @@ def isColimitCokernelCocone {X Y : SemiNormedGrp.{u}} (f : X ⟶ Y) : simp -- This used to be the end of the proof before leanprover/lean4#2644 erw [zero_apply]) - fun s m w => NormedAddGroupHom.lift_unique f.range _ _ _ w + fun _ _ w => NormedAddGroupHom.lift_unique f.range _ _ _ w instance : HasCokernels SemiNormedGrp.{u} where has_colimit f := @@ -351,8 +349,8 @@ theorem ExplicitCoker.map_desc {A B C D B' D' : SemiNormedGrp.{u}} (h' : fbb' ≫ g = fbd ≫ fdd') : explicitCokernelDesc condb ≫ g = explicitCokernel.map h ≫ explicitCokernelDesc condd := by delta explicitCokernel.map - simp [← cancel_epi (explicitCokernelπ fab), ← Category.assoc, Category.assoc, - explicitCokernelπ_desc, h'] + simp only [← Category.assoc, ← cancel_epi (explicitCokernelπ fab)] + simp [Category.assoc, explicitCokernelπ_desc, h'] end ExplicitCokernel diff --git a/Mathlib/Analysis/Normed/Group/Seminorm.lean b/Mathlib/Analysis/Normed/Group/Seminorm.lean index 06d80361d16b3..73c549f43211b 100644 --- a/Mathlib/Analysis/Normed/Group/Seminorm.lean +++ b/Mathlib/Analysis/Normed/Group/Seminorm.lean @@ -3,7 +3,8 @@ Copyright (c) 2022 María Inés de Frutos-Fernández, Yaël Dillies. All rights Released under Apache 2.0 license as described in the file LICENSE. Authors: María Inés de Frutos-Fernández, Yaël Dillies -/ -import Mathlib.Data.NNReal.Basic +import Mathlib.Data.NNReal.Defs +import Mathlib.Order.ConditionallyCompleteLattice.Group import Mathlib.Tactic.GCongr.CoreAttrs /-! @@ -145,7 +146,7 @@ end NonarchAddGroupSeminormClass instance (priority := 100) NonarchAddGroupSeminormClass.toAddGroupSeminormClass [FunLike F E ℝ] [AddGroup E] [NonarchAddGroupSeminormClass F E] : AddGroupSeminormClass F E ℝ := { ‹NonarchAddGroupSeminormClass F E› with - map_add_le_add := fun f x y => + map_add_le_add := fun f _ _ => haveI h_nonneg : ∀ a, 0 ≤ f a := by intro a rw [← NonarchAddGroupSeminormClass.map_zero f, ← sub_self a] @@ -181,12 +182,6 @@ instance groupSeminormClass : GroupSeminormClass (GroupSeminorm E) E ℝ where map_mul_le_add f := f.mul_le' map_inv_eq_map f := f.inv' -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun`. -/ -@[to_additive "Helper instance for when there's too many metavariables to apply -`DFunLike.hasCoeToFun`. "] -instance : CoeFun (GroupSeminorm E) fun _ => E → ℝ := - ⟨DFunLike.coe⟩ - @[to_additive (attr := simp)] theorem toFun_eq_coe : p.toFun = p := rfl @@ -346,7 +341,7 @@ noncomputable instance : Inf (GroupSeminorm E) := map_one' := ciInf_eq_of_forall_ge_of_forall_gt_exists_lt -- Porting note: replace `add_nonneg` with `positivity` once we have the extension - (fun x => add_nonneg (apply_nonneg _ _) (apply_nonneg _ _)) fun r hr => + (fun _ => add_nonneg (apply_nonneg _ _) (apply_nonneg _ _)) fun r hr => ⟨1, by rwa [div_one, map_one_eq_zero p, map_one_eq_zero q, add_zero]⟩ mul_le' := fun x y => le_ciInf_add_ciInf fun u v => by @@ -370,8 +365,8 @@ noncomputable instance : Lattice (GroupSeminorm E) := inf_le_right := fun p q x => ciInf_le_of_le mul_bddBelow_range_add (1 : E) <| by simpa only [div_one x, map_one_eq_zero p, zero_add (q x)] using le_rfl - le_inf := fun a b c hb hc x => - le_ciInf fun u => (le_map_add_map_div a _ _).trans <| add_le_add (hb _) (hc _) } + le_inf := fun a _ _ hb hc _ => + le_ciInf fun _ => (le_map_add_map_div a _ _).trans <| add_le_add (hb _) (hc _) } end CommGroup @@ -427,7 +422,7 @@ theorem smul_sup (r : R) (p q : AddGroupSeminorm E) : r • (p ⊔ q) = r • p have Real.smul_max : ∀ x y : ℝ, r • max x y = max (r • x) (r • y) := fun x y => by simpa only [← smul_eq_mul, ← NNReal.smul_def, smul_one_smul ℝ≥0 r (_ : ℝ)] using mul_max_of_nonneg x y (r • (1 : ℝ≥0) : ℝ≥0).coe_nonneg - ext fun x => Real.smul_max _ _ + ext fun _ => Real.smul_max _ _ end AddGroupSeminorm @@ -447,10 +442,6 @@ instance nonarchAddGroupSeminormClass : map_zero f := f.map_zero' map_neg_eq_map' f := f.neg' -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun`. -/ -instance : CoeFun (NonarchAddGroupSeminorm E) fun _ => E → ℝ := - ⟨DFunLike.coe⟩ - -- Porting note: `simpNF` said the left hand side simplified to this @[simp] theorem toZeroHom_eq_coe : ⇑p.toZeroHom = p := by @@ -483,7 +474,7 @@ instance : Zero (NonarchAddGroupSeminorm E) := ⟨{ toFun := 0 map_zero' := Pi.zero_apply _ add_le_max' := fun r s => by simp only [Pi.zero_apply]; rw [max_eq_right]; rfl - neg' := fun x => rfl }⟩ + neg' := fun _ => rfl }⟩ @[simp, norm_cast] theorem coe_zero : ⇑(0 : NonarchAddGroupSeminorm E) = 0 := @@ -588,7 +579,7 @@ theorem smul_sup (r : R) (p q : GroupSeminorm E) : r • (p ⊔ q) = r • p ⊔ have Real.smul_max : ∀ x y : ℝ, r • max x y = max (r • x) (r • y) := fun x y => by simpa only [← smul_eq_mul, ← NNReal.smul_def, smul_one_smul ℝ≥0 r (_ : ℝ)] using mul_max_of_nonneg x y (r • (1 : ℝ≥0) : ℝ≥0).coe_nonneg - ext fun x => Real.smul_max _ _ + ext fun _ => Real.smul_max _ _ end GroupSeminorm @@ -642,7 +633,7 @@ theorem smul_sup (r : R) (p q : NonarchAddGroupSeminorm E) : r • (p ⊔ q) = r have Real.smul_max : ∀ x y : ℝ, r • max x y = max (r • x) (r • y) := fun x y => by simpa only [← smul_eq_mul, ← NNReal.smul_def, smul_one_smul ℝ≥0 r (_ : ℝ)] using mul_max_of_nonneg x y (r • (1 : ℝ≥0) : ℝ≥0).coe_nonneg - ext fun x => Real.smul_max _ _ + ext fun _ => Real.smul_max _ _ end NonarchAddGroupSeminorm @@ -667,13 +658,6 @@ instance groupNormClass : GroupNormClass (GroupNorm E) E ℝ where map_inv_eq_map f := f.inv' eq_one_of_map_eq_zero f := f.eq_one_of_map_eq_zero' _ -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun` -directly. -/ -@[to_additive "Helper instance for when there's too many metavariables to apply -`DFunLike.hasCoeToFun` directly. "] -instance : CoeFun (GroupNorm E) fun _ => E → ℝ := - DFunLike.hasCoeToFun - -- Porting note: `simpNF` told me the left-hand side simplified to this @[to_additive (attr := simp)] theorem toGroupSeminorm_eq_coe : ⇑p.toGroupSeminorm = p := @@ -799,10 +783,6 @@ instance nonarchAddGroupNormClass : NonarchAddGroupNormClass (NonarchAddGroupNor map_neg_eq_map' f := f.neg' eq_zero_of_map_eq_zero f := f.eq_zero_of_map_eq_zero' _ -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun`. -/ -noncomputable instance : CoeFun (NonarchAddGroupNorm E) fun _ => E → ℝ := - DFunLike.hasCoeToFun - -- Porting note: `simpNF` told me the left-hand side simplified to this @[simp] theorem toNonarchAddGroupSeminorm_eq_coe : ⇑p.toNonarchAddGroupSeminorm = p := diff --git a/Mathlib/Analysis/Normed/Group/Ultra.lean b/Mathlib/Analysis/Normed/Group/Ultra.lean index 8e83b3535e430..44bfd92a9f0fe 100644 --- a/Mathlib/Analysis/Normed/Group/Ultra.lean +++ b/Mathlib/Analysis/Normed/Group/Ultra.lean @@ -6,6 +6,8 @@ Authors: Yakov Pechersky, David Loeffler import Mathlib.Analysis.Normed.Group.Uniform import Mathlib.Topology.Algebra.Nonarchimedean.Basic import Mathlib.Topology.MetricSpace.Ultra.Basic +import Mathlib.Topology.Algebra.InfiniteSum.Group +import Mathlib.Topology.Algebra.Order.LiminfLimsup /-! # Ultrametric norms @@ -235,6 +237,92 @@ lemma norm_prod_le_of_forall_le_of_nonneg {s : Finset ι} {f : ι → M} {C : lift C to NNReal using h_nonneg exact nnnorm_prod_le_of_forall_le hC +/-- +Given a function `f : ι → M` and a nonempty finite set `t ⊆ ι`, we can always find `i ∈ t` such that +`‖∏ j in t, f j‖ ≤ ‖f i‖`. +-/ +@[to_additive "Given a function `f : ι → M` and a nonempty finite set `t ⊆ ι`, we can always find +`i ∈ t` such that `‖∑ j in t, f j‖ ≤ ‖f i‖`."] +theorem exists_norm_finset_prod_le_of_nonempty {t : Finset ι} (ht : t.Nonempty) (f : ι → M) : + ∃ i ∈ t, ‖∏ j in t, f j‖ ≤ ‖f i‖ := + match t.exists_mem_eq_sup' ht (‖f ·‖) with + |⟨j, hj, hj'⟩ => ⟨j, hj, (ht.norm_prod_le_sup'_norm f).trans (le_of_eq hj')⟩ + +/-- +Given a function `f : ι → M` and a finite set `t ⊆ ι`, we can always find `i : ι`, belonging to `t` +if `t` is nonempty, such that `‖∏ j in t, f j‖ ≤ ‖f i‖`. +-/ +@[to_additive "Given a function `f : ι → M` and a finite set `t ⊆ ι`, we can always find `i : ι`, +belonging to `t` if `t` is nonempty, such that `‖∑ j in t, f j‖ ≤ ‖f i‖`."] +theorem exists_norm_finset_prod_le (t : Finset ι) [Nonempty ι] (f : ι → M) : + ∃ i : ι, (t.Nonempty → i ∈ t) ∧ ‖∏ j in t, f j‖ ≤ ‖f i‖ := by + rcases t.eq_empty_or_nonempty with rfl | ht + · simp + exact (fun ⟨i, h, h'⟩ => ⟨i, fun _ ↦ h, h'⟩) <| exists_norm_finset_prod_le_of_nonempty ht f + +/-- +Given a function `f : ι → M` and a multiset `t : Multiset ι`, we can always find `i : ι`, belonging +to `t` if `t` is nonempty, such that `‖(s.map f).prod‖ ≤ ‖f i‖`. +-/ +@[to_additive "Given a function `f : ι → M` and a multiset `t : Multiset ι`, we can always find +`i : ι`, belonging to `t` if `t` is nonempty, such that `‖(s.map f).sum‖ ≤ ‖f i‖`."] +theorem exists_norm_multiset_prod_le (s : Multiset ι) [Nonempty ι] {f : ι → M} : + ∃ i : ι, (s ≠ 0 → i ∈ s) ∧ ‖(s.map f).prod‖ ≤ ‖f i‖ := by + inhabit ι + induction s using Multiset.induction_on with + | empty => simp + | @cons a t hM => + obtain ⟨M, hMs, hM⟩ := hM + by_cases hMa : ‖f M‖ ≤ ‖f a‖ + · refine ⟨a, by simp, ?_⟩ + · rw [Multiset.map_cons, Multiset.prod_cons] + exact le_trans (norm_mul_le_max _ _) (max_le (le_refl _) (le_trans hM hMa)) + · rw [not_le] at hMa + rcases eq_or_ne t 0 with rfl|ht + · exact ⟨a, by simp, by simp⟩ + · refine ⟨M, ?_, ?_⟩ + · simp [hMs ht] + rw [Multiset.map_cons, Multiset.prod_cons] + exact le_trans (norm_mul_le_max _ _) (max_le hMa.le hM) + +@[to_additive] +lemma norm_tprod_le (f : ι → M) : ‖∏' i, f i‖ ≤ ⨆ i, ‖f i‖ := by + rcases isEmpty_or_nonempty ι with hι | hι + · -- Silly case #1 : the index type is empty + simp only [tprod_empty, norm_one', Real.iSup_of_isEmpty, le_refl] + by_cases h : Multipliable f; swap + · -- Silly case #2 : the product is divergent + rw [tprod_eq_one_of_not_multipliable h, norm_one'] + by_cases h_bd : BddAbove (Set.range fun i ↦ ‖f i‖) + · exact le_ciSup_of_le h_bd hι.some (norm_nonneg' _) + · rw [Real.iSup_of_not_bddAbove h_bd] + -- now the interesting case + have h_bd : BddAbove (Set.range fun i ↦ ‖f i‖) := + h.tendsto_cofinite_one.norm'.bddAbove_range_of_cofinite + refine le_of_tendsto' h.hasProd.norm' (fun s ↦ norm_prod_le_of_forall_le_of_nonneg ?_ ?_) + · exact le_ciSup_of_le h_bd hι.some (norm_nonneg' _) + · exact fun i _ ↦ le_ciSup h_bd i + +@[to_additive] +lemma nnnorm_tprod_le (f : ι → M) : ‖∏' i, f i‖₊ ≤ ⨆ i, ‖f i‖₊ := by + simpa only [← NNReal.coe_le_coe, coe_nnnorm', coe_iSup] using norm_tprod_le f + +@[to_additive] +lemma norm_tprod_le_of_forall_le [Nonempty ι] {f : ι → M} {C : ℝ} (h : ∀ i, ‖f i‖ ≤ C) : + ‖∏' i, f i‖ ≤ C := + (norm_tprod_le f).trans (ciSup_le h) + +@[to_additive] +lemma norm_tprod_le_of_forall_le_of_nonneg {f : ι → M} {C : ℝ} (hC : 0 ≤ C) (h : ∀ i, ‖f i‖ ≤ C) : + ‖∏' i, f i‖ ≤ C := by + rcases isEmpty_or_nonempty ι + · simpa only [tprod_empty, norm_one'] using hC + · exact norm_tprod_le_of_forall_le h + +@[to_additive] +lemma nnnorm_tprod_le_of_forall_le {f : ι → M} {C : ℝ≥0} (h : ∀ i, ‖f i‖₊ ≤ C) : ‖∏' i, f i‖₊ ≤ C := + (nnnorm_tprod_le f).trans (ciSup_le' h) + end CommGroup end IsUltrametricDist diff --git a/Mathlib/Analysis/Normed/Group/Uniform.lean b/Mathlib/Analysis/Normed/Group/Uniform.lean index 7ec9757016b86..7032cf8728ebe 100644 --- a/Mathlib/Analysis/Normed/Group/Uniform.lean +++ b/Mathlib/Analysis/Normed/Group/Uniform.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Johannes Hölzl, Yaël Dillies -/ -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Topology.Algebra.UniformGroup.Basic import Mathlib.Topology.MetricSpace.Algebra import Mathlib.Topology.MetricSpace.IsometricSMul import Mathlib.Analysis.Normed.Group.Basic @@ -191,13 +191,11 @@ theorem dist_self_mul_right (a b : E) : dist a (a * b) = ‖b‖ := by theorem dist_self_mul_left (a b : E) : dist (a * b) a = ‖b‖ := by rw [dist_comm, dist_self_mul_right] -@[to_additive (attr := simp 1001)] --- porting note (#10618): increase priority because `simp` can prove this +@[to_additive (attr := simp 1001)] -- Increase priority because `simp` can prove this theorem dist_self_div_right (a b : E) : dist a (a / b) = ‖b‖ := by rw [div_eq_mul_inv, dist_self_mul_right, norm_inv'] -@[to_additive (attr := simp 1001)] --- porting note (#10618): increase priority because `simp` can prove this +@[to_additive (attr := simp 1001)] -- Increase priority because `simp` can prove this theorem dist_self_div_left (a b : E) : dist (a / b) a = ‖b‖ := by rw [dist_comm, dist_self_div_right] @@ -327,8 +325,7 @@ theorem mul_lipschitzWith (hf : AntilipschitzWith Kf f) (hg : LipschitzWith Kg g refine AntilipschitzWith.of_le_mul_dist fun x y => ?_ rw [NNReal.coe_inv, ← _root_.div_eq_inv_mul] rw [le_div_iff₀ (NNReal.coe_pos.2 <| tsub_pos_iff_lt.2 hK)] - rw [mul_comm, NNReal.coe_sub hK.le, _root_.sub_mul] - -- Porting note: `ENNReal.sub_mul` should be `protected`? + rw [mul_comm, NNReal.coe_sub hK.le, sub_mul] calc ↑Kf⁻¹ * dist x y - Kg * dist x y ≤ dist (f x) (f y) - dist (g x) (g y) := sub_le_sub (hf.mul_le_dist x y) (hg.dist_le_mul x y) @@ -365,6 +362,29 @@ instance (priority := 100) SeminormedCommGroup.to_uniformGroup : UniformGroup E instance (priority := 100) SeminormedCommGroup.toTopologicalGroup : TopologicalGroup E := inferInstance +/-! ### SeparationQuotient -/ + +namespace SeparationQuotient + +@[to_additive instNorm] +instance instMulNorm : Norm (SeparationQuotient E) where + norm := lift Norm.norm fun _ _ h => h.norm_eq_norm' + +set_option linter.docPrime false in +@[to_additive (attr := simp) norm_mk] +theorem norm_mk' (p : E) : ‖mk p‖ = ‖p‖ := rfl + +@[to_additive] +instance : NormedCommGroup (SeparationQuotient E) where + __ : CommGroup (SeparationQuotient E) := instCommGroup + dist_eq := Quotient.ind₂ dist_eq_norm_div + +set_option linter.docPrime false in +@[to_additive (attr := simp) nnnorm_mk] +theorem nnnorm_mk' (p : E) : ‖mk p‖₊ = ‖p‖₊ := rfl + +end SeparationQuotient + @[to_additive] theorem cauchySeq_prod_of_eventually_eq {u v : ℕ → E} {N : ℕ} (huv : ∀ n ≥ N, u n = v n) (hv : CauchySeq fun n => ∏ k ∈ range (n + 1), v k) : diff --git a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean index 144ad83e536db..013c08de891cd 100644 --- a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean +++ b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean @@ -152,7 +152,7 @@ dependencies. -/ /-- The canonical map between `lp (fun _ : α ↦ E) ∞` and `α →ᵇ E` as a `LinearIsometryEquiv`. -/ noncomputable def lpBCFₗᵢ : lp (fun _ : α ↦ E) ∞ ≃ₗᵢ[𝕜] α →ᵇ E := { AddEquiv.lpBCF with - map_smul' := fun k f ↦ rfl + map_smul' := fun _ _ ↦ rfl norm_map' := fun f ↦ by simp only [norm_eq_iSup_norm, lp.norm_eq_ciSup]; rfl } @[deprecated (since := "2024-03-16")] alias lpBcfₗᵢ := lpBCFₗᵢ diff --git a/Mathlib/Analysis/Normed/Lp/PiLp.lean b/Mathlib/Analysis/Normed/Lp/PiLp.lean index cff87b17991f8..3b9cc58963b91 100644 --- a/Mathlib/Analysis/Normed/Lp/PiLp.lean +++ b/Mathlib/Analysis/Normed/Lp/PiLp.lean @@ -91,7 +91,7 @@ section /- Register simplification lemmas for the applications of `PiLp` elements, as the usual lemmas for Pi types will not trigger. -/ variable {𝕜 p α} -variable [SeminormedRing 𝕜] [∀ i, SeminormedAddCommGroup (β i)] +variable [Semiring 𝕜] [∀ i, SeminormedAddCommGroup (β i)] variable [∀ i, Module 𝕜 (β i)] (c : 𝕜) variable (x y : PiLp p β) (i : ι) @@ -121,6 +121,13 @@ theorem smul_apply : (c • x) i = c • x i := @[simp] theorem neg_apply : (-x) i = -x i := rfl + +variable (p) in +/-- The projection on the `i`-th coordinate of `WithLp p (∀ i, α i)`, as a linear map. -/ +@[simps!] +def projₗ (i : ι) : PiLp p β →ₗ[𝕜] β i := + (LinearMap.proj i : (∀ i, β i) →ₗ[𝕜] β i) ∘ₗ (WithLp.linearEquiv p 𝕜 (∀ i, β i)).toLinearMap + end /-! Note that the unapplied versions of these lemmas are deliberately omitted, as they break @@ -413,8 +420,8 @@ theorem antilipschitzWith_equiv_aux : rw [this, ENNReal.coe_rpow_of_nonneg _ nonneg] theorem aux_uniformity_eq : 𝓤 (PiLp p β) = 𝓤[Pi.uniformSpace _] := by - have A : UniformInducing (WithLp.equiv p (∀ i, β i)) := - (antilipschitzWith_equiv_aux p β).uniformInducing + have A : IsUniformInducing (WithLp.equiv p (∀ i, β i)) := + (antilipschitzWith_equiv_aux p β).isUniformInducing (lipschitzWith_equiv_aux p β).uniformContinuous have : (fun x : PiLp p β × PiLp p β => (WithLp.equiv p _ x.fst, WithLp.equiv p _ x.snd)) = id := by ext i <;> rfl @@ -740,7 +747,7 @@ def _root_.LinearIsometryEquiv.piLpCurry : toLinearEquiv := WithLp.linearEquiv _ _ _ ≪≫ₗ LinearEquiv.piCurry 𝕜 α - ≪≫ₗ (LinearEquiv.piCongrRight fun i => (WithLp.linearEquiv _ _ _).symm) + ≪≫ₗ (LinearEquiv.piCongrRight fun _ => (WithLp.linearEquiv _ _ _).symm) ≪≫ₗ (WithLp.linearEquiv _ _ _).symm norm_map' := (WithLp.equiv p _).symm.surjective.forall.2 fun x => by simp_rw [← coe_nnnorm, NNReal.coe_inj] @@ -825,7 +832,6 @@ theorem edist_equiv_symm_single_same (i : ι) (b₁ b₂ : β i) : ((WithLp.equiv p (∀ i, β i)).symm (Pi.single i b₁)) ((WithLp.equiv p (∀ i, β i)).symm (Pi.single i b₂)) = edist b₁ b₂ := by - -- Porting note: was `simpa using` simp only [edist_nndist, nndist_equiv_symm_single_same p β i b₁ b₂] end Single @@ -892,6 +898,13 @@ protected def continuousLinearEquiv : PiLp p β ≃L[𝕜] ∀ i, β i where continuous_toFun := continuous_equiv _ _ continuous_invFun := continuous_equiv_symm _ _ +variable {𝕜} in +/-- The projection on the `i`-th coordinate of `PiLp p β`, as a continuous linear map. -/ +@[simps!] +def proj (i : ι) : PiLp p β →L[𝕜] β i where + __ := projₗ p β i + cont := continuous_apply i + end Fintype section Basis diff --git a/Mathlib/Analysis/Normed/Lp/ProdLp.lean b/Mathlib/Analysis/Normed/Lp/ProdLp.lean index 9cc05f4783196..79bc09e27b3bf 100644 --- a/Mathlib/Analysis/Normed/Lp/ProdLp.lean +++ b/Mathlib/Analysis/Normed/Lp/ProdLp.lean @@ -155,7 +155,6 @@ instance instProdEDist : EDist (WithLp p (α × β)) where (edist f.fst g.fst ^ p.toReal + edist f.snd g.snd ^ p.toReal) ^ (1 / p.toReal) variable {p α β} -variable (x y : WithLp p (α × β)) (x' : α × β) @[simp] theorem prod_edist_eq_card (f g : WithLp 0 (α × β)) : @@ -424,8 +423,8 @@ theorem prod_antilipschitzWith_equiv_aux [PseudoEMetricSpace α] [PseudoEMetricS theorem prod_aux_uniformity_eq [PseudoEMetricSpace α] [PseudoEMetricSpace β] : 𝓤 (WithLp p (α × β)) = 𝓤[instUniformSpaceProd] := by - have A : UniformInducing (WithLp.equiv p (α × β)) := - (prod_antilipschitzWith_equiv_aux p α β).uniformInducing + have A : IsUniformInducing (WithLp.equiv p (α × β)) := + (prod_antilipschitzWith_equiv_aux p α β).isUniformInducing (prod_lipschitzWith_equiv_aux p α β).uniformContinuous have : (fun x : WithLp p (α × β) × WithLp p (α × β) => ((WithLp.equiv p (α × β)) x.fst, (WithLp.equiv p (α × β)) x.snd)) = id := by diff --git a/Mathlib/Analysis/Normed/Lp/lpSpace.lean b/Mathlib/Analysis/Normed/Lp/lpSpace.lean index dfe8bef80fdec..e9bce7f9e90db 100644 --- a/Mathlib/Analysis/Normed/Lp/lpSpace.lean +++ b/Mathlib/Analysis/Normed/Lp/lpSpace.lean @@ -336,7 +336,6 @@ theorem coeFn_neg (f : lp E p) : ⇑(-f) = -f := theorem coeFn_add (f g : lp E p) : ⇑(f + g) = f + g := rfl --- porting note (#10618): removed `@[simp]` because `simp` can prove this theorem coeFn_sum {ι : Type*} (f : ι → lp E p) (s : Finset ι) : ⇑(∑ i ∈ s, f i) = ∑ i ∈ s, ⇑(f i) := by simp @@ -471,7 +470,7 @@ instance normedAddCommGroup [hp : Fact (1 ≤ p)] : NormedAddCommGroup (lp E p) intro i gcongr apply norm_add_le - eq_zero_of_map_eq_zero' := fun f => norm_eq_zero_iff.1 } + eq_zero_of_map_eq_zero' := fun _ => norm_eq_zero_iff.1 } -- TODO: define an `ENNReal` version of `IsConjExponent`, and then express this inequality -- in a better version which also covers the case `p = 1, q = ∞`. @@ -737,6 +736,10 @@ instance nonUnitalNormedRing : NonUnitalNormedRing (lp B ∞) := mul_le_mul (lp.norm_apply_le_norm ENNReal.top_ne_zero f i) (lp.norm_apply_le_norm ENNReal.top_ne_zero g i) (norm_nonneg _) (norm_nonneg _) } +instance nonUnitalNormedCommRing {B : I → Type*} [∀ i, NonUnitalNormedCommRing (B i)] : + NonUnitalNormedCommRing (lp B ∞) where + mul_comm _ _ := ext <| mul_comm .. + -- we also want a `NonUnitalNormedCommRing` instance, but this has to wait for mathlib3 #13719 instance infty_isScalarTower {𝕜} [NormedRing 𝕜] [∀ i, Module 𝕜 (B i)] [∀ i, BoundedSMul 𝕜 (B i)] [∀ i, IsScalarTower 𝕜 (B i) (B i)] : IsScalarTower 𝕜 (lp B ∞) (lp B ∞) := @@ -841,12 +844,8 @@ section NormedCommRing variable {I : Type*} {B : I → Type*} [∀ i, NormedCommRing (B i)] [∀ i, NormOneClass (B i)] -instance inftyCommRing : CommRing (lp B ∞) := - { lp.inftyRing with - mul_comm := fun f g => by ext; simp only [lp.infty_coeFn_mul, Pi.mul_apply, mul_comm] } - -instance inftyNormedCommRing : NormedCommRing (lp B ∞) := - { lp.inftyCommRing, lp.inftyNormedRing with } +instance inftyNormedCommRing : NormedCommRing (lp B ∞) where + mul_comm := mul_comm end NormedCommRing diff --git a/Mathlib/Analysis/Normed/Module/Basic.lean b/Mathlib/Analysis/Normed/Module/Basic.lean index b35a5c4e3baf1..09973f5989c6d 100644 --- a/Mathlib/Analysis/Normed/Module/Basic.lean +++ b/Mathlib/Analysis/Normed/Module/Basic.lean @@ -119,6 +119,9 @@ instance Pi.normedSpace {ι : Type*} {E : ι → Type*} [Fintype ι] [∀ i, Sem NNReal.mul_finset_sup] exact Finset.sup_mono_fun fun _ _ => norm_smul_le a _ +instance SeparationQuotient.instNormedSpace : NormedSpace 𝕜 (SeparationQuotient E) where + norm_smul_le := norm_smul_le + instance MulOpposite.instNormedSpace : NormedSpace 𝕜 Eᵐᵒᵖ where norm_smul_le _ x := norm_smul_le _ x.unop @@ -225,8 +228,8 @@ protected theorem NormedSpace.noncompactSpace : NoncompactSpace E := by exact ⟨fun h ↦ NormedSpace.unbounded_univ 𝕜 E h.isBounded⟩ · push_neg at H rcases exists_ne (0 : E) with ⟨x, hx⟩ - suffices ClosedEmbedding (Infinite.natEmbedding 𝕜 · • x) from this.noncompactSpace - refine closedEmbedding_of_pairwise_le_dist (norm_pos_iff.2 hx) fun k n hne ↦ ?_ + suffices IsClosedEmbedding (Infinite.natEmbedding 𝕜 · • x) from this.noncompactSpace + refine isClosedEmbedding_of_pairwise_le_dist (norm_pos_iff.2 hx) fun k n hne ↦ ?_ simp only [dist_eq_norm, ← sub_smul, norm_smul] rw [H, one_mul] rwa [sub_ne_zero, (Embedding.injective _).ne_iff] @@ -348,6 +351,10 @@ instance Pi.normedAlgebra {ι : Type*} {E : ι → Type*} [Fintype ι] [∀ i, S variable [SeminormedRing E] [NormedAlgebra 𝕜 E] +instance SeparationQuotient.instNormedAlgebra : NormedAlgebra 𝕜 (SeparationQuotient E) where + __ : NormedSpace 𝕜 (SeparationQuotient E) := inferInstance + __ : Algebra 𝕜 (SeparationQuotient E) := inferInstance + instance MulOpposite.instNormedAlgebra {E : Type*} [SeminormedRing E] [NormedAlgebra 𝕜 E] : NormedAlgebra 𝕜 Eᵐᵒᵖ where __ := instAlgebra diff --git a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean index 4735888f210dd..34b802ea77856 100644 --- a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean +++ b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean @@ -519,8 +519,8 @@ lemma ProperSpace.of_locallyCompact_module [Nontrivial E] [LocallyCompactSpace E have : LocallyCompactSpace 𝕜 := by obtain ⟨v, hv⟩ : ∃ v : E, v ≠ 0 := exists_ne 0 let L : 𝕜 → E := fun t ↦ t • v - have : ClosedEmbedding L := closedEmbedding_smul_left hv - apply ClosedEmbedding.locallyCompactSpace this + have : IsClosedEmbedding L := isClosedEmbedding_smul_left hv + apply IsClosedEmbedding.locallyCompactSpace this .of_locallyCompactSpace 𝕜 @[deprecated (since := "2024-01-31")] diff --git a/Mathlib/Analysis/Normed/Module/Span.lean b/Mathlib/Analysis/Normed/Module/Span.lean index 2996a80f34809..cbb4571a230b6 100644 --- a/Mathlib/Analysis/Normed/Module/Span.lean +++ b/Mathlib/Analysis/Normed/Module/Span.lean @@ -7,6 +7,7 @@ Authors: Moritz Doll import Mathlib.Analysis.Normed.Operator.LinearIsometry import Mathlib.Analysis.Normed.Operator.ContinuousLinearMap import Mathlib.Analysis.Normed.Module.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # The span of a single vector diff --git a/Mathlib/Analysis/Normed/Module/WeakDual.lean b/Mathlib/Analysis/Normed/Module/WeakDual.lean index 9eceea12586f7..a5798eaf704c2 100644 --- a/Mathlib/Analysis/Normed/Module/WeakDual.lean +++ b/Mathlib/Analysis/Normed/Module/WeakDual.lean @@ -198,7 +198,7 @@ theorem isClosed_image_coe_of_bounded_of_closed {s : Set (WeakDual 𝕜 E)} theorem isCompact_of_bounded_of_closed [ProperSpace 𝕜] {s : Set (WeakDual 𝕜 E)} (hb : IsBounded (Dual.toWeakDual ⁻¹' s)) (hc : IsClosed s) : IsCompact s := - (Embedding.isCompact_iff DFunLike.coe_injective.embedding_induced).mpr <| + DFunLike.coe_injective.isEmbedding_induced.isCompact_iff.mpr <| ContinuousLinearMap.isCompact_image_coe_of_bounded_of_closed_image hb <| isClosed_image_coe_of_bounded_of_closed hb hc diff --git a/Mathlib/Analysis/Normed/Operator/Banach.lean b/Mathlib/Analysis/Normed/Operator/Banach.lean index 8561d451ba771..b98dc85ceda60 100644 --- a/Mathlib/Analysis/Normed/Operator/Banach.lean +++ b/Mathlib/Analysis/Normed/Operator/Banach.lean @@ -249,8 +249,11 @@ protected theorem isOpenMap (surj : Surjective f) : IsOpenMap f := by exact Set.mem_image_of_mem _ (hε this) -protected theorem quotientMap (surj : Surjective f) : QuotientMap f := - (f.isOpenMap surj).to_quotientMap f.continuous surj +theorem isQuotientMap (surj : Surjective f) : IsQuotientMap f := + (f.isOpenMap surj).isQuotientMap f.continuous surj + +@[deprecated (since := "2024-10-22")] +alias quotientMap := isQuotientMap end @@ -531,7 +534,7 @@ section BijectivityCriteria namespace ContinuousLinearMap -variable {σ : 𝕜 →+* 𝕜'} {σ' : 𝕜' →+* 𝕜} [RingHomInvPair σ σ'] {f : E →SL[σ] F} +variable {σ : 𝕜 →+* 𝕜'} {σ' : 𝕜' →+* 𝕜} [RingHomInvPair σ σ'] variable {F : Type u_4} [NormedAddCommGroup F] [NormedSpace 𝕜' F] variable [CompleteSpace E] diff --git a/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean b/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean index 4d0fea4e147c4..39c1d73dc03d4 100644 --- a/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean +++ b/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean @@ -145,7 +145,7 @@ theorem comp {g : F → G} (hg : IsBoundedLinearMap 𝕜 g) (hf : IsBoundedLinea protected theorem tendsto (x : E) (hf : IsBoundedLinearMap 𝕜 f) : Tendsto f (𝓝 x) (𝓝 (f x)) := let ⟨hf, M, _, hM⟩ := hf tendsto_iff_norm_sub_tendsto_zero.2 <| - squeeze_zero (fun e => norm_nonneg _) + squeeze_zero (fun _ => norm_nonneg _) (fun e => calc ‖f e - f x‖ = ‖hf.mk' f (e - x)‖ := by rw [(hf.mk' _).map_sub e x]; rfl diff --git a/Mathlib/Analysis/Normed/Operator/Compact.lean b/Mathlib/Analysis/Normed/Operator/Compact.lean index ee6b5ed2c85f7..da69e15c03410 100644 --- a/Mathlib/Analysis/Normed/Operator/Compact.lean +++ b/Mathlib/Analysis/Normed/Operator/Compact.lean @@ -68,7 +68,7 @@ section Characterizations section -variable {R₁ R₂ : Type*} [Semiring R₁] [Semiring R₂] {σ₁₂ : R₁ →+* R₂} {M₁ M₂ : Type*} +variable {R₁ : Type*} [Semiring R₁] {M₁ M₂ : Type*} [TopologicalSpace M₁] [AddCommMonoid M₁] [TopologicalSpace M₂] theorem isCompactOperator_iff_exists_mem_nhds_image_subset_compact (f : M₁ → M₂) : @@ -112,7 +112,7 @@ end Bounded section NormedSpace variable {𝕜₁ 𝕜₂ : Type*} [NontriviallyNormedField 𝕜₁] [SeminormedRing 𝕜₂] {σ₁₂ : 𝕜₁ →+* 𝕜₂} - {M₁ M₂ M₃ : Type*} [SeminormedAddCommGroup M₁] [TopologicalSpace M₂] [AddCommMonoid M₂] + {M₁ M₂ : Type*} [SeminormedAddCommGroup M₁] [TopologicalSpace M₂] [AddCommMonoid M₂] [NormedSpace 𝕜₁ M₁] [Module 𝕜₂ M₂] theorem IsCompactOperator.image_subset_compact_of_bounded [ContinuousConstSMul 𝕜₂ M₂] @@ -178,10 +178,10 @@ end Characterizations section Operations -variable {R₁ R₂ R₃ R₄ : Type*} [Semiring R₁] [Semiring R₂] [CommSemiring R₃] [CommSemiring R₄] - {σ₁₂ : R₁ →+* R₂} {σ₁₄ : R₁ →+* R₄} {σ₃₄ : R₃ →+* R₄} {M₁ M₂ M₃ M₄ : Type*} [TopologicalSpace M₁] - [AddCommMonoid M₁] [TopologicalSpace M₂] [AddCommMonoid M₂] [TopologicalSpace M₃] - [AddCommGroup M₃] [TopologicalSpace M₄] [AddCommGroup M₄] +variable {R₁ R₄ : Type*} [Semiring R₁] [CommSemiring R₄] + {σ₁₄ : R₁ →+* R₄} {M₁ M₂ M₄ : Type*} [TopologicalSpace M₁] + [AddCommMonoid M₁] [TopologicalSpace M₂] [AddCommMonoid M₂] + [TopologicalSpace M₄] [AddCommGroup M₄] theorem IsCompactOperator.smul {S : Type*} [Monoid S] [DistribMulAction S M₂] [ContinuousConstSMul S M₂] {f : M₁ → M₂} (hf : IsCompactOperator f) (c : S) : @@ -247,24 +247,24 @@ end Comp section CodRestrict -variable {R₁ R₂ : Type*} [Semiring R₁] [Semiring R₂] {σ₁₂ : R₁ →+* R₂} {M₁ M₂ : Type*} - [TopologicalSpace M₁] [TopologicalSpace M₂] [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R₁ M₁] +variable {R₂ : Type*} [Semiring R₂] {M₁ M₂ : Type*} + [TopologicalSpace M₁] [TopologicalSpace M₂] [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R₂ M₂] theorem IsCompactOperator.codRestrict {f : M₁ → M₂} (hf : IsCompactOperator f) {V : Submodule R₂ M₂} (hV : ∀ x, f x ∈ V) (h_closed : IsClosed (V : Set M₂)) : IsCompactOperator (Set.codRestrict f V hV) := let ⟨_, hK, hKf⟩ := hf - ⟨_, (closedEmbedding_subtype_val h_closed).isCompact_preimage hK, hKf⟩ + ⟨_, h_closed.isClosedEmbedding_subtypeVal.isCompact_preimage hK, hKf⟩ end CodRestrict section Restrict -variable {R₁ R₂ R₃ : Type*} [Semiring R₁] [Semiring R₂] [Semiring R₃] {σ₁₂ : R₁ →+* R₂} - {σ₂₃ : R₂ →+* R₃} {M₁ M₂ M₃ : Type*} [TopologicalSpace M₁] [UniformSpace M₂] - [TopologicalSpace M₃] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] [Module R₁ M₁] - [Module R₂ M₂] [Module R₃ M₃] +variable {R₁ R₂ : Type*} [Semiring R₁] [Semiring R₂] {σ₁₂ : R₁ →+* R₂} + {M₁ M₂ : Type*} [TopologicalSpace M₁] [UniformSpace M₂] + [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R₁ M₁] + [Module R₂ M₂] /-- If a compact operator preserves a closed submodule, its restriction to that submodule is compact. diff --git a/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean b/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean index 64c5ba0eb60b5..8b61db66f18eb 100644 --- a/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean +++ b/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean @@ -5,6 +5,7 @@ Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo -/ import Mathlib.Analysis.Normed.Group.Uniform import Mathlib.Analysis.Normed.MulAction +import Mathlib.LinearAlgebra.DFinsupp import Mathlib.Topology.Algebra.Module.Basic /-! # Constructions of continuous linear maps between (semi-)normed spaces diff --git a/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean b/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean index 77c5f4cf43a72..41a382610b103 100644 --- a/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean +++ b/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean @@ -7,8 +7,9 @@ import Mathlib.Algebra.Star.Basic import Mathlib.Analysis.Normed.Group.Constructions import Mathlib.Analysis.Normed.Group.Submodule import Mathlib.Analysis.Normed.Group.Uniform -import Mathlib.Topology.Algebra.Module.Basic import Mathlib.LinearAlgebra.Basis.Defs +import Mathlib.LinearAlgebra.DFinsupp +import Mathlib.Topology.Algebra.Module.Basic /-! # (Semi-)linear isometries @@ -170,27 +171,21 @@ theorem ext {f g : E →ₛₗᵢ[σ₁₂] E₂} (h : ∀ x, f x = g x) : f = g variable [FunLike 𝓕 E E₂] --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_zero : f 0 = 0 := f.toLinearMap.map_zero --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_add (x y : E) : f (x + y) = f x + f y := f.toLinearMap.map_add x y --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_neg (x : E) : f (-x) = -f x := f.toLinearMap.map_neg x --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_sub (x y : E) : f (x - y) = f x - f y := f.toLinearMap.map_sub x y --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_smulₛₗ (c : R) (x : E) : f (c • x) = σ₁₂ c • f x := f.toLinearMap.map_smulₛₗ c x --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_smul [Module R E₂] (f : E →ₗᵢ[R] E₂) (c : R) (x : E) : f (c • x) = c • f x := f.toLinearMap.map_smul c x @@ -205,12 +200,15 @@ theorem nnnorm_map (x : E) : ‖f x‖₊ = ‖x‖₊ := protected theorem isometry : Isometry f := AddMonoidHomClass.isometry_of_norm f.toLinearMap (norm_map _) -protected lemma embedding (f : F →ₛₗᵢ[σ₁₂] E₂) : Embedding f := f.isometry.embedding +lemma isEmbedding (f : F →ₛₗᵢ[σ₁₂] E₂) : IsEmbedding f := f.isometry.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding -- Should be `@[simp]` but it doesn't fire due to `lean4#3107`. theorem isComplete_image_iff [SemilinearIsometryClass 𝓕 σ₁₂ E E₂] (f : 𝓕) {s : Set E} : IsComplete (f '' s) ↔ IsComplete s := - _root_.isComplete_image_iff (SemilinearIsometryClass.isometry f).uniformInducing + _root_.isComplete_image_iff (SemilinearIsometryClass.isometry f).isUniformInducing @[simp] -- Should be replaced with `LinearIsometry.isComplete_image_iff` when `lean4#3107` is fixed. theorem isComplete_image_iff' (f : LinearIsometry σ₁₂ E E₂) {s : Set E} : @@ -486,9 +484,12 @@ instance instSemilinearIsometryEquivClass : map_smulₛₗ e := map_smulₛₗ e.toLinearEquiv norm_map e := e.norm_map' --- TODO: Shouldn't these `CoeFun` instances be scrapped? -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun` -directly. -/ +/-- Shortcut instance, saving 8.5% of compilation time in +`Mathlib.Analysis.InnerProductSpace.Adjoint`. + +(This instance was pinpointed by benchmarks; we didn't do an in depth investigation why it is +specifically needed.) +-/ instance instCoeFun : CoeFun (E ≃ₛₗᵢ[σ₁₂] E₂) fun _ ↦ E → E₂ := ⟨DFunLike.coe⟩ theorem coe_injective : @Function.Injective (E ≃ₛₗᵢ[σ₁₂] E₂) (E → E₂) (↑) := @@ -637,7 +638,6 @@ theorem apply_symm_apply (x : E₂) : e (e.symm x) = x := theorem symm_apply_apply (x : E) : e.symm (e x) = x := e.toLinearEquiv.symm_apply_apply x --- @[simp] -- Porting note (#10618): simp can prove this theorem map_eq_zero_iff {x : E} : e x = 0 ↔ x = 0 := e.toLinearEquiv.map_eq_zero_iff @@ -801,23 +801,18 @@ theorem coe_coe : ⇑(e : E ≃SL[σ₁₂] E₂) = e := theorem coe_coe'' : ⇑(e : E →SL[σ₁₂] E₂) = e := rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem map_zero : e 0 = 0 := e.1.map_zero --- @[simp] -- Porting note (#10618): simp can prove this theorem map_add (x y : E) : e (x + y) = e x + e y := e.1.map_add x y --- @[simp] -- Porting note (#10618): simp can prove this theorem map_sub (x y : E) : e (x - y) = e x - e y := e.1.map_sub x y --- @[simp] -- Porting note (#10618): simp can prove this theorem map_smulₛₗ (c : R) (x : E) : e (c • x) = σ₁₂ c • e x := e.1.map_smulₛₗ c x --- @[simp] -- Porting note (#10618): simp can prove this theorem map_smul [Module R E₂] {e : E ≃ₗᵢ[R] E₂} (c : R) (x : E) : e (c • x) = c • e x := e.1.map_smul c x @@ -842,7 +837,6 @@ protected theorem injective : Injective e := protected theorem surjective : Surjective e := e.1.surjective --- @[simp] -- Porting note (#10618): simp can prove this theorem map_eq_iff {x y : E} : e x = e y ↔ x = y := e.injective.eq_iff @@ -954,16 +948,12 @@ variable (R E E₂ E₃) /-- The natural equivalence `(E × E₂) × E₃ ≃ E × (E₂ × E₃)` is a linear isometry. -/ def prodAssoc [Module R E₂] [Module R E₃] : (E × E₂) × E₃ ≃ₗᵢ[R] E × E₂ × E₃ := - { Equiv.prodAssoc E E₂ E₃ with - toFun := Equiv.prodAssoc E E₂ E₃ - invFun := (Equiv.prodAssoc E E₂ E₃).symm - map_add' := by simp [-_root_.map_add] -- Fix timeout from #8386 - map_smul' := by -- was `by simp` before #6057 caused that to time out. - rintro m ⟨⟨e, f⟩, g⟩ - simp only [Prod.smul_mk, Equiv.prodAssoc_apply, RingHom.id_apply] + { LinearEquiv.prodAssoc R E E₂ E₃ with norm_map' := by rintro ⟨⟨e, f⟩, g⟩ - simp only [LinearEquiv.coe_mk, Equiv.prodAssoc_apply, Prod.norm_def, max_assoc] } + simp only [LinearEquiv.prodAssoc_apply, AddEquiv.toEquiv_eq_coe, + Equiv.toFun_as_coe, EquivLike.coe_coe, AddEquiv.coe_prodAssoc, + Equiv.prodAssoc_apply, Prod.norm_def, max_assoc] } @[simp] theorem coe_prodAssoc [Module R E₂] [Module R E₃] : diff --git a/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean b/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean index 45dfa1892cbcc..52bae3c5d3cee 100644 --- a/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean +++ b/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean @@ -172,10 +172,13 @@ lemma continuous_of_dual_apply_continuous {α : Type*} [TopologicalSpace α] {g (h : ∀ x (y : F⋆), Continuous fun a => y (g a x)) : Continuous g := continuous_induced_rng.2 (continuous_pi_iff.mpr fun p => h p.1 p.2) -lemma embedding_inducingFn : Embedding (inducingFn 𝕜 E F) := by - refine Function.Injective.embedding_induced fun A B hAB => ?_ +lemma isEmbedding_inducingFn : IsEmbedding (inducingFn 𝕜 E F) := by + refine Function.Injective.isEmbedding_induced fun A B hAB => ?_ rw [ContinuousLinearMapWOT.ext_dual_iff] - simpa [Function.funext_iff] using hAB + simpa [funext_iff] using hAB + +@[deprecated (since := "2024-10-26")] +alias embedding_inducingFn := isEmbedding_inducingFn open Filter in /-- The defining property of the weak operator topology: a function `f` tends to @@ -186,14 +189,14 @@ lemma tendsto_iff_forall_dual_apply_tendsto {α : Type*} {l : Filter α} {f : α have hmain : (∀ x (y : F⋆), Tendsto (fun a => y (f a x)) l (𝓝 (y (A x)))) ↔ ∀ (p : E × F⋆), Tendsto (fun a => p.2 (f a p.1)) l (𝓝 (p.2 (A p.1))) := ⟨fun h p => h p.1 p.2, fun h x y => h ⟨x, y⟩⟩ - rw [hmain, ← tendsto_pi_nhds, Embedding.tendsto_nhds_iff embedding_inducingFn] + rw [hmain, ← tendsto_pi_nhds, isEmbedding_inducingFn.tendsto_nhds_iff] rfl lemma le_nhds_iff_forall_dual_apply_le_nhds {l : Filter (E →WOT[𝕜] F)} {A : E →WOT[𝕜] F} : l ≤ 𝓝 A ↔ ∀ x (y : F⋆), l.map (fun T => y (T x)) ≤ 𝓝 (y (A x)) := tendsto_iff_forall_dual_apply_tendsto (f := id) -instance instT3Space : T3Space (E →WOT[𝕜] F) := embedding_inducingFn.t3Space +instance instT3Space : T3Space (E →WOT[𝕜] F) := isEmbedding_inducingFn.t3Space instance instContinuousAdd : ContinuousAdd (E →WOT[𝕜] F) := .induced (inducingFn 𝕜 E F) instance instContinuousNeg : ContinuousNeg (E →WOT[𝕜] F) := .induced (inducingFn 𝕜 E F) diff --git a/Mathlib/Analysis/Normed/Order/Lattice.lean b/Mathlib/Analysis/Normed/Order/Lattice.lean index b9217fe0951e2..de21daec89f71 100644 --- a/Mathlib/Analysis/Normed/Order/Lattice.lean +++ b/Mathlib/Analysis/Normed/Order/Lattice.lean @@ -185,8 +185,10 @@ lemma lipschitzWith_posPart : LipschitzWith 1 (posPart : α → α) := lemma lipschitzWith_negPart : LipschitzWith 1 (negPart : α → α) := by simpa [Function.comp] using lipschitzWith_posPart.comp LipschitzWith.id.neg +@[fun_prop] lemma continuous_posPart : Continuous (posPart : α → α) := lipschitzWith_posPart.continuous +@[fun_prop] lemma continuous_negPart : Continuous (negPart : α → α) := lipschitzWith_negPart.continuous lemma isClosed_nonneg : IsClosed {x : α | 0 ≤ x} := by diff --git a/Mathlib/Analysis/Normed/Order/UpperLower.lean b/Mathlib/Analysis/Normed/Order/UpperLower.lean index b30f015561105..8c260c437ed28 100644 --- a/Mathlib/Analysis/Normed/Order/UpperLower.lean +++ b/Mathlib/Analysis/Normed/Order/UpperLower.lean @@ -114,7 +114,7 @@ theorem IsLowerSet.mem_interior_of_forall_lt (hs : IsLowerSet s) (hx : x ∈ clo end Finite section Fintype -variable [Fintype ι] {s t : Set (ι → ℝ)} {a₁ a₂ b₁ b₂ x y : ι → ℝ} {δ : ℝ} +variable [Fintype ι] {s : Set (ι → ℝ)} {a₁ a₂ b₁ b₂ x y : ι → ℝ} {δ : ℝ} -- TODO: Generalise those lemmas so that they also apply to `ℝ` and `EuclideanSpace ι ℝ` lemma dist_inf_sup_pi (x y : ι → ℝ) : dist (x ⊓ y) (x ⊔ y) = dist x y := by @@ -184,7 +184,7 @@ theorem IsLowerSet.exists_subset_ball (hs : IsLowerSet s) (hx : x ∈ closure s) end Fintype section Finite -variable [Finite ι] {s t : Set (ι → ℝ)} {a₁ a₂ b₁ b₂ x y : ι → ℝ} {δ : ℝ} +variable [Finite ι] {s : Set (ι → ℝ)} /-! #### Note diff --git a/Mathlib/Analysis/Normed/Ring/IsPowMulFaithful.lean b/Mathlib/Analysis/Normed/Ring/IsPowMulFaithful.lean index 615d91284df1a..f460ba8405dda 100644 --- a/Mathlib/Analysis/Normed/Ring/IsPowMulFaithful.lean +++ b/Mathlib/Analysis/Normed/Ring/IsPowMulFaithful.lean @@ -58,7 +58,7 @@ theorem contraction_of_isPowMul {α β : Type*} [SeminormedRing α] [SeminormedR contraction_of_isPowMul_of_boundedWrt (SeminormedRing.toRingSeminorm α) hβ hf x /-- Given two power-multiplicative ring seminorms `f, g` on `α`, if `f` is bounded by a positive - multiple of `g` and viceversa, then `f = g`. -/ + multiple of `g` and vice versa, then `f = g`. -/ theorem eq_seminorms {F : Type*} {α : outParam (Type*)} [Ring α] [FunLike F α ℝ] [RingSeminormClass F α ℝ] {f g : F} (hfpm : IsPowMul f) (hgpm : IsPowMul g) (hfg : ∃ (r : ℝ) (_ : 0 < r), ∀ a : α, f a ≤ r * g a) diff --git a/Mathlib/Analysis/Normed/Ring/Seminorm.lean b/Mathlib/Analysis/Normed/Ring/Seminorm.lean index 650ace74daac1..5fdaed6043d37 100644 --- a/Mathlib/Analysis/Normed/Ring/Seminorm.lean +++ b/Mathlib/Analysis/Normed/Ring/Seminorm.lean @@ -39,7 +39,7 @@ ring_seminorm, ring_norm open NNReal -variable {F R S : Type*} (x y : R) (r : ℝ) +variable {R : Type*} /-- A seminorm on a ring `R` is a function `f : R → ℝ` that preserves zero, takes nonnegative values, is subadditive and submultiplicative and such that `f (-x) = f x` for all `x ∈ R`. -/ @@ -421,3 +421,13 @@ def NormedField.toMulRingNorm (R : Type*) [NormedField R] : MulRingNorm R where map_mul' := norm_mul neg' := norm_neg eq_zero_of_map_eq_zero' x hx := by rw [← norm_eq_zero]; exact hx + +/-- Triangle inequality for `MulRingNorm` applied to a list. -/ +lemma mulRingNorm_sum_le_sum_mulRingNorm {R : Type*} [NonAssocRing R] (l : List R) + (f : MulRingNorm R) : f l.sum ≤ (l.map f).sum := by + induction l with + | nil => simp only [List.sum_nil, map_zero, List.map_nil, le_refl] + | cons head tail ih => + simp only [List.sum_cons, List.map_cons] + calc f (head + List.sum tail) ≤ f head + f (List.sum tail) := by apply f.add_le' + _ ≤ f head + List.sum (List.map f tail) := by simp only [add_le_add_iff_left, ih] diff --git a/Mathlib/Analysis/Normed/Ring/Units.lean b/Mathlib/Analysis/Normed/Ring/Units.lean index 6a9faca97ff80..0a9b5ef97d8a5 100644 --- a/Mathlib/Analysis/Normed/Ring/Units.lean +++ b/Mathlib/Analysis/Normed/Ring/Units.lean @@ -3,8 +3,9 @@ Copyright (c) 2020 Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ -import Mathlib.Topology.Algebra.Ring.Ideal import Mathlib.Analysis.SpecificLimits.Normed +import Mathlib.Topology.Algebra.Ring.Ideal +import Mathlib.RingTheory.Ideal.Basic /-! # The group of units of a complete normed ring @@ -145,7 +146,7 @@ theorem inverse_one_sub_norm : (fun t : R => inverse (1 - t)) =O[𝓝 0] (fun _t have := tsum_geometric_le_of_norm_lt_one t ht' have : (1 - ‖t‖)⁻¹ ≤ 2 := by rw [← inv_inv (2 : ℝ)] - refine inv_le_inv_of_le (by norm_num) ?_ + refine inv_anti₀ (by norm_num) ?_ have : (2 : ℝ)⁻¹ + (2 : ℝ)⁻¹ = 1 := by ring linarith linarith @@ -200,15 +201,18 @@ open MulOpposite Filter NormedRing /-- In a normed ring with summable geometric series, the coercion from `Rˣ` (equipped with the induced topology from the embedding in `R × R`) to `R` is an open embedding. -/ -theorem openEmbedding_val : OpenEmbedding (val : Rˣ → R) where - toEmbedding := embedding_val_mk' +theorem isOpenEmbedding_val : IsOpenEmbedding (val : Rˣ → R) where + toIsEmbedding := isEmbedding_val_mk' (fun _ ⟨u, hu⟩ ↦ hu ▸ (inverse_continuousAt u).continuousWithinAt) Ring.inverse_unit isOpen_range := Units.isOpen +@[deprecated (since := "2024-10-18")] +alias openEmbedding_val := isOpenEmbedding_val + /-- In a normed ring with summable geometric series, the coercion from `Rˣ` (equipped with the induced topology from the embedding in `R × R`) to `R` is an open map. -/ theorem isOpenMap_val : IsOpenMap (val : Rˣ → R) := - openEmbedding_val.isOpenMap + isOpenEmbedding_val.isOpenMap end Units diff --git a/Mathlib/Analysis/NormedSpace/BallAction.lean b/Mathlib/Analysis/NormedSpace/BallAction.lean index 262d4babb606c..2f484459d1044 100644 --- a/Mathlib/Analysis/NormedSpace/BallAction.lean +++ b/Mathlib/Analysis/NormedSpace/BallAction.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov, Heather Macbeth -/ import Mathlib.Analysis.Normed.Field.UnitBall import Mathlib.Analysis.Normed.Module.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # Multiplicative actions of/on balls and spheres @@ -31,8 +32,8 @@ instance mulActionClosedBallBall : MulAction (closedBall (0 : 𝕜) 1) (ball (0 simpa only [norm_smul, one_mul] using mul_lt_mul' (mem_closedBall_zero_iff.1 c.2) (mem_ball_zero_iff.1 x.2) (norm_nonneg _) one_pos⟩ - one_smul x := Subtype.ext <| one_smul 𝕜 _ - mul_smul c₁ c₂ x := Subtype.ext <| mul_smul _ _ _ + one_smul _c₂ := Subtype.ext <| one_smul 𝕜 _ + mul_smul _ _ _ := Subtype.ext <| mul_smul _ _ _ instance continuousSMul_closedBall_ball : ContinuousSMul (closedBall (0 : 𝕜) 1) (ball (0 : E) r) := ⟨(continuous_subtype_val.fst'.smul continuous_subtype_val.snd').subtype_mk _⟩ @@ -45,8 +46,8 @@ instance mulActionClosedBallClosedBall : simpa only [norm_smul, one_mul] using mul_le_mul (mem_closedBall_zero_iff.1 c.2) (mem_closedBall_zero_iff.1 x.2) (norm_nonneg _) zero_le_one⟩ - one_smul x := Subtype.ext <| one_smul 𝕜 _ - mul_smul c₁ c₂ x := Subtype.ext <| mul_smul _ _ _ + one_smul _ := Subtype.ext <| one_smul 𝕜 _ + mul_smul _ _ _ := Subtype.ext <| mul_smul _ _ _ instance continuousSMul_closedBall_closedBall : ContinuousSMul (closedBall (0 : 𝕜) 1) (closedBall (0 : E) r) := @@ -79,8 +80,8 @@ instance mulActionSphereSphere : MulAction (sphere (0 : 𝕜) 1) (sphere (0 : E) mem_sphere_zero_iff_norm.2 <| by rw [norm_smul, mem_sphere_zero_iff_norm.1 c.coe_prop, mem_sphere_zero_iff_norm.1 x.coe_prop, one_mul]⟩ - one_smul x := Subtype.ext <| one_smul _ _ - mul_smul c₁ c₂ x := Subtype.ext <| mul_smul _ _ _ + one_smul _ := Subtype.ext <| one_smul _ _ + mul_smul _ _ _ := Subtype.ext <| mul_smul _ _ _ instance continuousSMul_sphere_sphere : ContinuousSMul (sphere (0 : 𝕜) 1) (sphere (0 : E) r) := ⟨(continuous_subtype_val.fst'.smul continuous_subtype_val.snd').subtype_mk _⟩ diff --git a/Mathlib/Analysis/NormedSpace/ConformalLinearMap.lean b/Mathlib/Analysis/NormedSpace/ConformalLinearMap.lean index d73ac04e060f8..068091b76b338 100644 --- a/Mathlib/Analysis/NormedSpace/ConformalLinearMap.lean +++ b/Mathlib/Analysis/NormedSpace/ConformalLinearMap.lean @@ -5,6 +5,7 @@ Authors: Yourong Zang -/ import Mathlib.Analysis.Normed.Module.Basic import Mathlib.Analysis.Normed.Operator.LinearIsometry +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # Conformal Linear Maps diff --git a/Mathlib/Analysis/NormedSpace/ENorm.lean b/Mathlib/Analysis/NormedSpace/ENorm.lean index 48c17b7994ce9..5f64698d8c8c7 100644 --- a/Mathlib/Analysis/NormedSpace/ENorm.lean +++ b/Mathlib/Analysis/NormedSpace/ENorm.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Analysis.Normed.Module.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # Extended norm @@ -109,9 +110,9 @@ theorem map_sub_le (x y : V) : e (x - y) ≤ e x + e y := instance partialOrder : PartialOrder (ENorm 𝕜 V) where le e₁ e₂ := ∀ x, e₁ x ≤ e₂ x - le_refl e x := le_rfl - le_trans e₁ e₂ e₃ h₁₂ h₂₃ x := le_trans (h₁₂ x) (h₂₃ x) - le_antisymm e₁ e₂ h₁₂ h₂₁ := ext fun x => le_antisymm (h₁₂ x) (h₂₁ x) + le_refl _ _ := le_rfl + le_trans _ _ _ h₁₂ h₂₃ x := le_trans (h₁₂ x) (h₂₃ x) + le_antisymm _ _ h₁₂ h₂₁ := ext fun x => le_antisymm (h₁₂ x) (h₂₁ x) /-- The `ENorm` sending each non-zero vector to infinity. -/ noncomputable instance : Top (ENorm 𝕜 V) := @@ -146,14 +147,14 @@ noncomputable instance : SemilatticeSup (ENorm 𝕜 V) := lt := (· < ·) sup := fun e₁ e₂ => { toFun := fun x => max (e₁ x) (e₂ x) - eq_zero' := fun x h => e₁.eq_zero_iff.1 (ENNReal.max_eq_zero_iff.1 h).1 - map_add_le' := fun x y => + eq_zero' := fun _ h => e₁.eq_zero_iff.1 (ENNReal.max_eq_zero_iff.1 h).1 + map_add_le' := fun _ _ => max_le (le_trans (e₁.map_add_le _ _) <| add_le_add (le_max_left _ _) (le_max_left _ _)) (le_trans (e₂.map_add_le _ _) <| add_le_add (le_max_right _ _) (le_max_right _ _)) map_smul_le' := fun c x => le_of_eq <| by simp only [map_smul, ENNReal.mul_max] } - le_sup_left := fun e₁ e₂ x => le_max_left _ _ - le_sup_right := fun e₁ e₂ x => le_max_right _ _ - sup_le := fun e₁ e₂ e₃ h₁ h₂ x => max_le (h₁ x) (h₂ x) } + le_sup_left := fun _ _ _ => le_max_left _ _ + le_sup_right := fun _ _ _ => le_max_right _ _ + sup_le := fun _ _ _ h₁ h₂ x => max_le (h₁ x) (h₂ x) } @[simp, norm_cast] theorem coe_max (e₁ e₂ : ENorm 𝕜 V) : ⇑(e₁ ⊔ e₂) = fun x => max (e₁ x) (e₂ x) := diff --git a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean index af94c78f743e0..b63ecf7d25efc 100644 --- a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean +++ b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean @@ -26,7 +26,7 @@ equivalences acts transitively on the set of nonzero vectors. registers that continuous linear forms on `E` separate points of `E`. -/ @[mk_iff separatingDual_def] class SeparatingDual (R V : Type*) [Ring R] [AddCommGroup V] [TopologicalSpace V] - [TopologicalSpace R] [Module R V] : Prop := + [TopologicalSpace R] [Module R V] : Prop where /-- Any nonzero vector can be mapped by a continuous linear map to a nonzero scalar. -/ exists_ne_zero' : ∀ (x : V), x ≠ 0 → ∃ f : V →L[R] R, f x ≠ 0 diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean index 4b87da345fe31..2b7591e8a0600 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean @@ -80,16 +80,19 @@ variable {𝕜 ι : Type*} {E : ι → Type*} {F : Type*} [NormedField 𝕜] [Finite ι] [∀ i, SeminormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)] [TopologicalSpace F] [AddCommGroup F] [TopologicalAddGroup F] [Module 𝕜 F] -/-- Applying a multilinear map to a vector is continuous in both coordinates. -/ -theorem ContinuousMultilinearMap.continuous_eval : - Continuous fun p : ContinuousMultilinearMap 𝕜 E F × ∀ i, E i => p.1 p.2 := by - cases nonempty_fintype ι - let _ := TopologicalAddGroup.toUniformSpace F - have := comm_topologicalAddGroup_is_uniform (G := F) - refine (UniformOnFun.continuousOn_eval₂ fun m ↦ ?_).comp_continuous - (embedding_toUniformOnFun.continuous.prodMap continuous_id) fun (f, x) ↦ f.cont.continuousAt - exact ⟨ball m 1, NormedSpace.isVonNBounded_of_isBounded _ isBounded_ball, - ball_mem_nhds _ one_pos⟩ +instance ContinuousMultilinearMap.instContinuousEval : + ContinuousEval (ContinuousMultilinearMap 𝕜 E F) (Π i, E i) F where + continuous_eval := by + cases nonempty_fintype ι + let _ := TopologicalAddGroup.toUniformSpace F + have := comm_topologicalAddGroup_is_uniform (G := F) + refine (UniformOnFun.continuousOn_eval₂ fun m ↦ ?_).comp_continuous + (isEmbedding_toUniformOnFun.continuous.prodMap continuous_id) fun (f, x) ↦ f.cont.continuousAt + exact ⟨ball m 1, NormedSpace.isVonNBounded_of_isBounded _ isBounded_ball, + ball_mem_nhds _ one_pos⟩ + +@[deprecated (since := "2024-10-05")] +protected alias ContinuousMultilinearMap.continuous_eval := continuous_eval namespace ContinuousLinearMap @@ -97,8 +100,8 @@ variable {G : Type*} [AddCommGroup G] [TopologicalSpace G] [Module 𝕜 G] [Cont (f : G →L[𝕜] ContinuousMultilinearMap 𝕜 E F) lemma continuous_uncurry_of_multilinear : - Continuous (fun (p : G × (Π i, E i)) ↦ f p.1 p.2) := - ContinuousMultilinearMap.continuous_eval.comp <| .prodMap (map_continuous f) continuous_id + Continuous (fun (p : G × (Π i, E i)) ↦ f p.1 p.2) := by + fun_prop lemma continuousOn_uncurry_of_multilinear {s} : ContinuousOn (fun (p : G × (Π i, E i)) ↦ f p.1 p.2) s := @@ -304,7 +307,7 @@ theorem coe_mkContinuous (C : ℝ) (H : ∀ m, ‖f m‖ ≤ C * ∏ i, ‖m i the other coordinates, then the resulting restricted function satisfies an inequality `‖f.restr v‖ ≤ C * ‖z‖^(n-k) * Π ‖v i‖` if the original function satisfies `‖f v‖ ≤ C * Π ‖v i‖`. -/ theorem restr_norm_le {k n : ℕ} (f : (MultilinearMap 𝕜 (fun _ : Fin n => G) G' : _)) - (s : Finset (Fin n)) (hk : s.card = k) (z : G) {C : ℝ} (H : ∀ m, ‖f m‖ ≤ C * ∏ i, ‖m i‖) + (s : Finset (Fin n)) (hk : #s = k) (z : G) {C : ℝ} (H : ∀ m, ‖f m‖ ≤ C * ∏ i, ‖m i‖) (v : Fin k → G) : ‖f.restr s hk z v‖ ≤ C * ‖z‖ ^ (n - k) * ∏ i, ‖v i‖ := by rw [mul_right_comm, mul_assoc] convert H _ using 2 @@ -648,8 +651,8 @@ def prodL : invFun f := ((ContinuousLinearMap.fst 𝕜 G G').compContinuousMultilinearMap f, (ContinuousLinearMap.snd 𝕜 G G').compContinuousMultilinearMap f) - map_add' f g := rfl - map_smul' c f := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl left_inv f := by ext <;> rfl right_inv f := by ext <;> rfl norm_map' f := opNorm_prod f.1 f.2 @@ -729,12 +732,12 @@ namespace ContinuousMultilinearMap these variables, and fixing the other ones equal to a given value `z`. It is denoted by `f.restr s hk z`, where `hk` is a proof that the cardinality of `s` is `k`. The implicit identification between `Fin k` and `s` that we use is the canonical (increasing) bijection. -/ -def restr {k n : ℕ} (f : (G[×n]→L[𝕜] G' : _)) (s : Finset (Fin n)) (hk : s.card = k) (z : G) : +def restr {k n : ℕ} (f : (G[×n]→L[𝕜] G' : _)) (s : Finset (Fin n)) (hk : #s = k) (z : G) : G[×k]→L[𝕜] G' := (f.toMultilinearMap.restr s hk z).mkContinuous (‖f‖ * ‖z‖ ^ (n - k)) fun _ => MultilinearMap.restr_norm_le _ _ _ _ f.le_opNorm _ -theorem norm_restr {k n : ℕ} (f : G[×n]→L[𝕜] G') (s : Finset (Fin n)) (hk : s.card = k) (z : G) : +theorem norm_restr {k n : ℕ} (f : G[×n]→L[𝕜] G') (s : Finset (Fin n)) (hk : #s = k) (z : G) : ‖f.restr s hk z‖ ≤ ‖f‖ * ‖z‖ ^ (n - k) := by apply MultilinearMap.mkContinuous_norm_le exact mul_nonneg (norm_nonneg _) (pow_nonneg (norm_nonneg _) _) @@ -873,7 +876,7 @@ ones. We register this bijection as a linear isometry in `ContinuousMultilinearMap.piFieldEquiv`. -/ protected def piFieldEquiv : G ≃ₗᵢ[𝕜] ContinuousMultilinearMap 𝕜 (fun _ : ι => 𝕜) G where toFun z := ContinuousMultilinearMap.mkPiRing 𝕜 ι z - invFun f := f fun i => 1 + invFun f := f fun _ => 1 map_add' z z' := by ext m simp [smul_add] @@ -902,7 +905,7 @@ variable (𝕜 E G G') def compContinuousMultilinearMapL : (G →L[𝕜] G') →L[𝕜] ContinuousMultilinearMap 𝕜 E G →L[𝕜] ContinuousMultilinearMap 𝕜 E G' := LinearMap.mkContinuous₂ - (LinearMap.mk₂ 𝕜 compContinuousMultilinearMap (fun f₁ f₂ g => rfl) (fun c f g => rfl) + (LinearMap.mk₂ 𝕜 compContinuousMultilinearMap (fun _ _ _ => rfl) (fun _ _ _ => rfl) (fun f g₁ g₂ => by ext1; apply f.map_add) (fun c f g => by ext1; simp)) 1 diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean index 433b3db5d9d54..3e81916160893 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Curry.lean @@ -169,8 +169,8 @@ def continuousMultilinearCurryLeftEquiv : Ei 0 →L[𝕜] ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei i.succ) G := LinearIsometryEquiv.ofBounds { toFun := ContinuousMultilinearMap.curryLeft - map_add' := fun f₁ f₂ => rfl - map_smul' := fun c f => rfl + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl invFun := ContinuousLinearMap.uncurryLeft left_inv := ContinuousMultilinearMap.uncurry_curryLeft right_inv := ContinuousLinearMap.curry_uncurryLeft } @@ -283,8 +283,8 @@ def continuousMultilinearCurryRightEquiv : ContinuousMultilinearMap 𝕜 (fun i : Fin n => Ei <| castSucc i) (Ei (last n) →L[𝕜] G) := LinearIsometryEquiv.ofBounds { toFun := ContinuousMultilinearMap.curryRight - map_add' := fun f₁ f₂ => rfl - map_smul' := fun c f => rfl + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl invFun := ContinuousMultilinearMap.uncurryRight left_inv := ContinuousMultilinearMap.uncurry_curryRight right_inv := ContinuousMultilinearMap.curry_uncurryRight } @@ -560,7 +560,7 @@ variable (𝕜 G G') {k l : ℕ} {s : Finset (Fin n)} `l`, then the space of continuous multilinear maps `G [×n]→L[𝕜] G'` of `n` variables is isomorphic to the space of continuous multilinear maps `G [×k]→L[𝕜] G [×l]→L[𝕜] G'` of `k` variables taking values in the space of continuous multilinear maps of `l` variables. -/ -def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) (hl : sᶜ.card = l) : +def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) : (G[×n]→L[𝕜] G') ≃ₗᵢ[𝕜] G[×k]→L[𝕜] G[×l]→L[𝕜] G' := (domDomCongrₗᵢ 𝕜 G G' (finSumEquivOfFinset hk hl).symm).trans (currySumEquiv 𝕜 (Fin k) (Fin l) G G') @@ -568,33 +568,31 @@ def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) (hl : s variable {𝕜 G G'} @[simp] -theorem curryFinFinset_apply (hk : s.card = k) (hl : sᶜ.card = l) (f : G[×n]→L[𝕜] G') +theorem curryFinFinset_apply (hk : #s = k) (hl : #sᶜ = l) (f : G[×n]→L[𝕜] G') (mk : Fin k → G) (ml : Fin l → G) : curryFinFinset 𝕜 G G' hk hl f mk ml = f fun i => Sum.elim mk ml ((finSumEquivOfFinset hk hl).symm i) := rfl @[simp] -theorem curryFinFinset_symm_apply (hk : s.card = k) (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply (hk : #s = k) (hl : #sᶜ = l) (f : G[×k]→L[𝕜] G[×l]→L[𝕜] G') (m : Fin n → G) : (curryFinFinset 𝕜 G G' hk hl).symm f m = f (fun i => m <| finSumEquivOfFinset hk hl (Sum.inl i)) fun i => m <| finSumEquivOfFinset hk hl (Sum.inr i) := rfl --- @[simp] -- Porting note (#10618): simp removed: simp can reduce LHS -theorem curryFinFinset_symm_apply_piecewise_const (hk : s.card = k) (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply_piecewise_const (hk : #s = k) (hl : #sᶜ = l) (f : G[×k]→L[𝕜] G[×l]→L[𝕜] G') (x y : G) : (curryFinFinset 𝕜 G G' hk hl).symm f (s.piecewise (fun _ => x) fun _ => y) = f (fun _ => x) fun _ => y := MultilinearMap.curryFinFinset_symm_apply_piecewise_const hk hl _ x y @[simp] -theorem curryFinFinset_symm_apply_const (hk : s.card = k) (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply_const (hk : #s = k) (hl : #sᶜ = l) (f : G[×k]→L[𝕜] G[×l]→L[𝕜] G') (x : G) : ((curryFinFinset 𝕜 G G' hk hl).symm f fun _ => x) = f (fun _ => x) fun _ => x := rfl --- @[simp] -- Porting note (#10618): simp removed: simp can reduce LHS -theorem curryFinFinset_apply_const (hk : s.card = k) (hl : sᶜ.card = l) (f : G[×n]→L[𝕜] G') +theorem curryFinFinset_apply_const (hk : #s = k) (hl : #sᶜ = l) (f : G[×n]→L[𝕜] G') (x y : G) : (curryFinFinset 𝕜 G G' hk hl f (fun _ => x) fun _ => y) = f (s.piecewise (fun _ => x) fun _ => y) := by refine (curryFinFinset_symm_apply_piecewise_const hk hl _ _ _).symm.trans ?_ diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean index c0c4cc0b30b0d..34ac1d9ef91a5 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean @@ -33,17 +33,17 @@ open Filter hiding map_smul open scoped NNReal Topology Uniformity -- the `ₗ` subscript variables are for special cases about linear (as opposed to semilinear) maps -variable {𝕜 𝕜₂ 𝕜₃ E Eₗ F Fₗ G Gₗ 𝓕 : Type*} +variable {𝕜 𝕜₂ 𝕜₃ E F Fₗ G 𝓕 : Type*} section SemiNormed open Metric ContinuousLinearMap -variable [SeminormedAddCommGroup E] [SeminormedAddCommGroup Eₗ] [SeminormedAddCommGroup F] - [SeminormedAddCommGroup Fₗ] [SeminormedAddCommGroup G] [SeminormedAddCommGroup Gₗ] +variable [SeminormedAddCommGroup E] [SeminormedAddCommGroup F] [SeminormedAddCommGroup Fₗ] + [SeminormedAddCommGroup G] variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] - [NormedSpace 𝕜 E] [NormedSpace 𝕜 Eₗ] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜 Fₗ] [NormedSpace 𝕜₃ G] + [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜 Fₗ] [NormedSpace 𝕜₃ G] {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} {σ₁₃ : 𝕜 →+* 𝕜₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] variable [FunLike 𝓕 E F] @@ -56,7 +56,7 @@ theorem norm_image_of_norm_zero [SemilinearMapClass 𝓕 σ₁₂ E F] (f : 𝓕 section -variable [RingHomIsometric σ₁₂] [RingHomIsometric σ₂₃] +variable [RingHomIsometric σ₁₂] theorem SemilinearMapClass.bound_of_shell_semi_normed [SemilinearMapClass 𝓕 σ₁₂ E F] (f : 𝓕) {ε C : ℝ} (ε_pos : 0 < ε) {c : 𝕜} (hc : 1 < ‖c‖) @@ -264,7 +264,7 @@ theorem opNorm_le_of_shell' {f : E →SL[σ₁₂] F} {ε C : ℝ} (ε_pos : 0 < · refine opNorm_le_of_ball ε_pos hC fun x hx => hf x ?_ ?_ · simp [h0] · rwa [ball_zero_eq] at hx - · rw [← inv_inv c, norm_inv, inv_lt_one_iff_of_pos (norm_pos_iff.2 <| inv_ne_zero h0)] at hc + · rw [← inv_inv c, norm_inv, inv_lt_one₀ (norm_pos_iff.2 <| inv_ne_zero h0)] at hc refine opNorm_le_of_shell ε_pos hC hc ?_ rwa [norm_inv, div_eq_mul_inv, inv_inv] diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean index 9c9517852f03e..4043b6833c43d 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean @@ -20,13 +20,12 @@ open Filter hiding map_smul open scoped NNReal Topology Uniformity -- the `ₗ` subscript variables are for special cases about linear (as opposed to semilinear) maps -variable {𝕜 𝕜₂ 𝕜₃ E Eₗ F Fₗ G Gₗ 𝓕 : Type*} -variable [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedAddCommGroup G] - [NormedAddCommGroup Fₗ] +variable {𝕜 𝕜₂ E F Fₗ : Type*} +variable [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedAddCommGroup Fₗ] -variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] - [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜₃ G] [NormedSpace 𝕜 Fₗ] (c : 𝕜) - {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} (f g : E →SL[σ₁₂] F) (x y z : E) +variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] + [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜 Fₗ] + {σ₁₂ : 𝕜 →+* 𝕜₂} (f g : E →SL[σ₁₂] F) namespace ContinuousLinearMap @@ -181,7 +180,7 @@ variable [CompleteSpace F] (e : E →L[𝕜] Fₗ) (h_dense : DenseRange e) section -variable (h_e : UniformInducing e) +variable (h_e : IsUniformInducing e) /-- Extension of a continuous linear map `f : E →SL[σ₁₂] F`, with `E` a normed space and `F` a complete normed space, along a uniform and dense embedding `e : E →L[𝕜] Fₗ`. -/ @@ -230,7 +229,7 @@ variable {N : ℝ≥0} (h_e : ∀ x, ‖x‖ ≤ N * ‖e x‖) [RingHomIsometri /-- If a dense embedding `e : E →L[𝕜] G` expands the norm by a constant factor `N⁻¹`, then the norm of the extension of `f` along `e` is bounded by `N * ‖f‖`. -/ theorem opNorm_extend_le : - ‖f.extend e h_dense (isUniformEmbedding_of_bound _ h_e).toUniformInducing‖ ≤ N * ‖f‖ := by + ‖f.extend e h_dense (isUniformEmbedding_of_bound _ h_e).isUniformInducing‖ ≤ N * ‖f‖ := by -- Add `opNorm_le_of_dense`? refine opNorm_le_bound _ ?_ (isClosed_property h_dense (isClosed_le ?_ ?_) fun x ↦ ?_) · cases le_total 0 N with diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Mul.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Mul.lean index 9eae72e5fb45b..25796540eece9 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Mul.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Mul.lean @@ -121,7 +121,7 @@ examples. Any algebra with an approximate identity (e.g., $$L^1$$) is also regul This is a useful class because it gives rise to a nice norm on the unitization; in particular it is a C⋆-norm when the norm on `A` is a C⋆-norm. -/ -class _root_.RegularNormedAlgebra : Prop := +class _root_.RegularNormedAlgebra : Prop where /-- The left regular representation of the algebra on itself is an isometry. -/ isometry_mul' : Isometry (mul 𝕜 𝕜') @@ -239,7 +239,7 @@ section Normed namespace ContinuousLinearMap -variable [NormedAddCommGroup E] [NormedSpace 𝕜 E] (c : 𝕜) +variable [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable (𝕜) (𝕜' : Type*) section diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean index 253805834044d..082320dd797e2 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean @@ -16,12 +16,10 @@ underlying space has a norm (rather than just a seminorm). suppress_compilation -open Bornology -open Filter hiding map_smul -open scoped NNReal Topology Uniformity +open scoped NNReal Topology -- the `ₗ` subscript variables are for special cases about linear (as opposed to semilinear) maps -variable {𝕜 𝕜₂ 𝕜₃ E Eₗ F Fₗ G Gₗ 𝓕 : Type*} +variable {𝕜 𝕜₂ 𝕜₃ E F Fₗ G : Type*} section Normed @@ -34,8 +32,8 @@ open Metric ContinuousLinearMap section variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] - [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜₃ G] [NormedSpace 𝕜 Fₗ] (c : 𝕜) - {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} (f g : E →SL[σ₁₂] F) (x y z : E) + [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜₃ G] [NormedSpace 𝕜 Fₗ] + {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} (f : E →SL[σ₁₂] F) namespace LinearMap @@ -141,10 +139,13 @@ variable (f) /-- If a continuous linear map is a topology embedding, then it is expands the distances by a positive factor. -/ -theorem antilipschitz_of_embedding (f : E →L[𝕜] Fₗ) (hf : Embedding f) : +theorem antilipschitz_of_isEmbedding (f : E →L[𝕜] Fₗ) (hf : IsEmbedding f) : ∃ K, AntilipschitzWith K f := f.toLinearMap.antilipschitz_of_comap_nhds_le <| map_zero f ▸ (hf.nhds_eq_comap 0).ge +@[deprecated (since := "2024-10-26")] +alias antilipschitz_of_embedding := antilipschitz_of_isEmbedding + end OpNorm end ContinuousLinearMap @@ -181,8 +182,8 @@ end namespace ContinuousLinearMap variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] - [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜₃ G] [NormedSpace 𝕜 Fₗ] (c : 𝕜) - {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} + [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] [NormedSpace 𝕜₃ G] [NormedSpace 𝕜 Fₗ] + {σ₂₃ : 𝕜₂ →+* 𝕜₃} variable {𝕜₂' : Type*} [NontriviallyNormedField 𝕜₂'] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕜₂' F'] {σ₂' : 𝕜₂' →+* 𝕜₂} {σ₂'' : 𝕜₂ →+* 𝕜₂'} {σ₂₃' : 𝕜₂' →+* 𝕜₃} @@ -229,8 +230,7 @@ end ContinuousLinearMap namespace Submodule -variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] - [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] {σ₁₂ : 𝕜 →+* 𝕜₂} +variable [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 E] theorem norm_subtypeL (K : Submodule 𝕜 E) [Nontrivial K] : ‖K.subtypeL‖ = 1 := K.subtypeₗᵢ.norm_toContinuousLinearMap @@ -239,7 +239,7 @@ end Submodule namespace ContinuousLinearEquiv -variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NontriviallyNormedField 𝕜₃] +variable [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜₂] [NormedSpace 𝕜 E] [NormedSpace 𝕜₂ F] {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₁ : 𝕜₂ →+* 𝕜} [RingHomInvPair σ₁₂ σ₂₁] [RingHomInvPair σ₂₁ σ₁₂] diff --git a/Mathlib/Analysis/NormedSpace/PiTensorProduct/ProjectiveSeminorm.lean b/Mathlib/Analysis/NormedSpace/PiTensorProduct/ProjectiveSeminorm.lean index ec8cbeca4457f..edb1a33efca0f 100644 --- a/Mathlib/Analysis/NormedSpace/PiTensorProduct/ProjectiveSeminorm.lean +++ b/Mathlib/Analysis/NormedSpace/PiTensorProduct/ProjectiveSeminorm.lean @@ -40,7 +40,6 @@ universe uι u𝕜 uE uF variable {ι : Type uι} [Fintype ι] variable {𝕜 : Type u𝕜} [NontriviallyNormedField 𝕜] variable {E : ι → Type uE} [∀ i, SeminormedAddCommGroup (E i)] -variable {F : Type uF} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] open scoped TensorProduct diff --git a/Mathlib/Analysis/NormedSpace/Real.lean b/Mathlib/Analysis/NormedSpace/Real.lean index 3106fe40f746a..09c0aa69993d6 100644 --- a/Mathlib/Analysis/NormedSpace/Real.lean +++ b/Mathlib/Analysis/NormedSpace/Real.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Patrick Massot, Eric Wieser, Yaël Dillies -/ import Mathlib.Analysis.Normed.Module.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.Topology.Algebra.Module.Basic /-! diff --git a/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean b/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean index fd8a5748ac567..c0c9a90640f7c 100644 --- a/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean +++ b/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Analysis.Normed.Module.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # Homeomorphism between a normed space and sphere times `(0, +∞)` diff --git a/Mathlib/Analysis/ODE/Gronwall.lean b/Mathlib/Analysis/ODE/Gronwall.lean index f45756db1a781..dd27e37df8326 100644 --- a/Mathlib/Analysis/ODE/Gronwall.lean +++ b/Mathlib/Analysis/ODE/Gronwall.lean @@ -30,8 +30,7 @@ Sec. 4.5][HubbardWest-ode], where `norm_le_gronwallBound_of_norm_deriv_right_le` open Metric Set Asymptotics Filter Real open scoped Topology NNReal -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {F : Type*} [NormedAddCommGroup F] - [NormedSpace ℝ F] +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] /-! ### Technical lemmas about `gronwallBound` -/ @@ -312,20 +311,20 @@ theorem ODE_solution_unique_of_mem_Ioo · 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 - (ContinuousAt.continuousOn fun _ ht'' ↦ (hf _ <| hss ht'').1.continuousAt) + (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) - (ContinuousAt.continuousOn fun _ ht'' ↦ (hg _ <| hss ht'').1.continuousAt) + (continuousOn_of_forall_continuousAt fun _ ht'' ↦ (hg _ <| hss ht'').1.continuousAt) (fun _ ht'' ↦ (hg _ <| hss <| Ioc_subset_Icc_self ht'').1.hasDerivWithinAt) (fun _ ht'' ↦ (hg _ <| hss <| Ioc_subset_Icc_self ht'').2) heq ⟨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 - (ContinuousAt.continuousOn fun _ ht'' ↦ (hf _ <| hss ht'').1.continuousAt) + (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) - (ContinuousAt.continuousOn fun _ ht'' ↦ (hg _ <| hss ht'').1.continuousAt) + (continuousOn_of_forall_continuousAt fun _ ht'' ↦ (hg _ <| hss ht'').1.continuousAt) (fun _ ht'' ↦ (hg _ <| hss <| Ico_subset_Icc_self ht'').1.hasDerivWithinAt) (fun _ ht'' ↦ (hg _ <| hss <| Ico_subset_Icc_self ht'').2) heq ⟨h, le_rfl⟩ diff --git a/Mathlib/Analysis/ODE/PicardLindelof.lean b/Mathlib/Analysis/ODE/PicardLindelof.lean index e7bb6f5aa0859..bf6d91625d9e7 100644 --- a/Mathlib/Analysis/ODE/PicardLindelof.lean +++ b/Mathlib/Analysis/ODE/PicardLindelof.lean @@ -81,9 +81,9 @@ instance : Inhabited (PicardLindelof E) := ⟨⟨0, 0, 0, ⟨0, le_rfl, le_rfl⟩, 0, 0, 0, 0, { ht₀ := by rw [Subtype.coe_mk, Icc_self]; exact mem_singleton _ hR := le_rfl - lipschitz := fun t _ => (LipschitzWith.const 0).lipschitzOnWith + lipschitz := fun _ _ => (LipschitzWith.const 0).lipschitzOnWith cont := fun _ _ => by simpa only [Pi.zero_apply] using continuousOn_const - norm_le := fun t _ x _ => norm_zero.le + norm_le := fun _ _ _ _ => norm_zero.le C_mul_le_R := (zero_mul _).le }⟩⟩ theorem tMin_le_tMax : v.tMin ≤ v.tMax := @@ -170,9 +170,12 @@ def toContinuousMap : v.FunSpace ↪ C(Icc v.tMin v.tMax, E) := instance : MetricSpace v.FunSpace := MetricSpace.induced toContinuousMap toContinuousMap.injective inferInstance -theorem uniformInducing_toContinuousMap : UniformInducing (@toContinuousMap _ _ _ v) := +theorem isUniformInducing_toContinuousMap : IsUniformInducing (@toContinuousMap _ _ _ v) := ⟨rfl⟩ +@[deprecated (since := "2024-10-05")] +alias uniformInducing_toContinuousMap := isUniformInducing_toContinuousMap + theorem range_toContinuousMap : range toContinuousMap = {f : C(Icc v.tMin v.tMax, E) | f v.t₀ = v.x₀ ∧ LipschitzWith v.C f} := by @@ -217,13 +220,13 @@ theorem dist_le_of_forall {f₁ f₂ : FunSpace v} {d : ℝ} (h : ∀ t, dist (f v.nonempty_Icc.to_subtype).2 h instance [CompleteSpace E] : CompleteSpace v.FunSpace := by - refine (completeSpace_iff_isComplete_range uniformInducing_toContinuousMap).2 + refine (completeSpace_iff_isComplete_range isUniformInducing_toContinuousMap).2 (IsClosed.isComplete ?_) rw [range_toContinuousMap, setOf_and] - refine (isClosed_eq (ContinuousMap.continuous_eval_const _) continuous_const).inter ?_ + refine (isClosed_eq (continuous_eval_const _) continuous_const).inter ?_ have : IsClosed {f : Icc v.tMin v.tMax → E | LipschitzWith v.C f} := isClosed_setOf_lipschitzWith v.C - exact this.preimage ContinuousMap.continuous_coe + exact this.preimage continuous_coeFun theorem intervalIntegrable_vComp (t₁ t₂ : ℝ) : IntervalIntegrable f.vComp volume t₁ t₂ := f.continuous_vComp.intervalIntegrable _ _ diff --git a/Mathlib/Analysis/Oscillation.lean b/Mathlib/Analysis/Oscillation.lean index c6327e3b9a059..a9e4ec628acf0 100644 --- a/Mathlib/Analysis/Oscillation.lean +++ b/Mathlib/Analysis/Oscillation.lean @@ -52,7 +52,7 @@ namespace ContinuousWithinAt theorem oscillationWithin_eq_zero [TopologicalSpace E] {f : E → F} {D : Set E} {x : E} (hf : ContinuousWithinAt f D x) : oscillationWithin f D x = 0 := by - refine le_antisymm (le_of_forall_pos_le_add fun ε hε _ ↦ ?_) (zero_le _) + refine le_antisymm (_root_.le_of_forall_pos_le_add fun ε hε ↦ ?_) (zero_le _) rw [zero_add] have : ball (f x) (ε / 2) ∈ (𝓝[D] x).map f := hf <| ball_mem_nhds _ (by simp [ne_of_gt hε]) refine (biInf_le diam this).trans (le_of_le_of_eq diam_ball ?_) @@ -107,7 +107,7 @@ theorem uniform_oscillationWithin (comp : IsCompact K) (hK : ∀ x ∈ K, oscill ⟨ENNReal.ofReal ((a - r) / 2), by simp [ar], ?_⟩ refine fun y hy ↦ ⟨a - (a - r) / 2, by linarith, le_trans (diam_mono (image_mono fun z hz ↦ ?_)) ha⟩ - refine ⟨lt_of_le_of_lt (edist_triangle z y x) (lt_of_lt_of_eq (add_lt_add hz.1 hy) ?_), + refine ⟨lt_of_le_of_lt (edist_triangle z y x) (lt_of_lt_of_eq (ENNReal.add_lt_add hz.1 hy) ?_), hz.2⟩ rw [← ofReal_add (by linarith) (by linarith), sub_add_cancel] have S_cover : K ⊆ ⋃ r > 0, S r := by diff --git a/Mathlib/Analysis/PSeries.lean b/Mathlib/Analysis/PSeries.lean index 1f09446ae9b7c..a0365a83cfc7b 100644 --- a/Mathlib/Analysis/PSeries.lean +++ b/Mathlib/Analysis/PSeries.lean @@ -283,7 +283,7 @@ theorem summable_nat_rpow_inv {p : ℝ} : (eventually_cofinite_ne 0)).exists apply hk₀ rw [← pos_iff_ne_zero, ← @Nat.cast_pos ℝ] at hk₀ - simpa [inv_lt_one_iff_of_pos (rpow_pos_of_pos hk₀ _), one_lt_rpow_iff_of_pos hk₀, hp, + simpa [inv_lt_one₀ (rpow_pos_of_pos hk₀ _), one_lt_rpow_iff_of_pos hk₀, hp, hp.not_lt, hk₀] using hk₁ @[simp] diff --git a/Mathlib/Analysis/Quaternion.lean b/Mathlib/Analysis/Quaternion.lean index 3466df2251849..8319c5915f21a 100644 --- a/Mathlib/Analysis/Quaternion.lean +++ b/Mathlib/Analysis/Quaternion.lean @@ -50,8 +50,8 @@ noncomputable instance : NormedAddCommGroup ℍ := @InnerProductSpace.Core.toNormedAddCommGroup ℝ ℍ _ _ _ { toInner := inferInstance conj_symm := fun x y => by simp [inner_def, mul_comm] - nonneg_re := fun x => normSq_nonneg - definite := fun x => normSq_eq_zero.1 + nonneg_re := fun _ => normSq_nonneg + definite := fun _ => normSq_eq_zero.1 add_left := fun x y z => by simp only [inner_def, add_mul, add_re] smul_left := fun x y r => by simp [inner_def] } diff --git a/Mathlib/Analysis/RCLike/Basic.lean b/Mathlib/Analysis/RCLike/Basic.lean index 43c7971fb36a0..0600c19d1b79e 100644 --- a/Mathlib/Analysis/RCLike/Basic.lean +++ b/Mathlib/Analysis/RCLike/Basic.lean @@ -10,6 +10,7 @@ import Mathlib.Algebra.Order.Star.Basic import Mathlib.Analysis.CStarAlgebra.Basic import Mathlib.Analysis.Normed.Operator.ContinuousLinearMap import Mathlib.Data.Real.Sqrt +import Mathlib.LinearAlgebra.Basis.VectorSpace /-! # `RCLike`: a typeclass for ℝ or ℂ @@ -38,7 +39,7 @@ in `Mathlib/Data/Nat/Cast/Defs.lean`. See also Note [coercion into rings] for mo In addition, several lemmas need to be set at priority 900 to make sure that they do not override their counterparts in `Mathlib/Analysis/Complex/Basic.lean` (which causes linter errors). -A few lemmas requiring heavier imports are in `Mathlib/Data/RCLike/Lemmas.lean`. +A few lemmas requiring heavier imports are in `Mathlib/Analysis/RCLike/Lemmas.lean`. -/ open Fintype @@ -262,7 +263,7 @@ theorem I_im (z : K) : im z * im (I : K) = im z := @[simp, rclike_simps] theorem I_im' (z : K) : im (I : K) * im z = im z := by rw [mul_comm, I_im] -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem I_mul_re (z : K) : re (I * z) = -im z := by simp only [I_re, zero_sub, I_im', zero_mul, mul_re] @@ -298,7 +299,7 @@ theorem conj_nat_cast (n : ℕ) : conj (n : K) = n := map_natCast _ _ theorem conj_ofNat (n : ℕ) [n.AtLeastTwo] : conj (no_index (OfNat.ofNat n : K)) = OfNat.ofNat n := map_ofNat _ _ -@[rclike_simps] -- Porting note (#10618): was a `simp` but `simp` can prove it +@[rclike_simps, simp] theorem conj_neg_I : conj (-I) = (I : K) := by rw [map_neg, conj_I, neg_neg] theorem conj_eq_re_sub_im (z : K) : conj z = re z - im z * I := @@ -394,7 +395,7 @@ theorem normSq_one : normSq (1 : K) = 1 := theorem normSq_nonneg (z : K) : 0 ≤ normSq z := add_nonneg (mul_self_nonneg _) (mul_self_nonneg _) -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem normSq_eq_zero {z : K} : normSq z = 0 ↔ z = 0 := map_eq_zero _ @@ -409,7 +410,7 @@ theorem normSq_neg (z : K) : normSq (-z) = normSq z := by simp only [normSq_eq_d theorem normSq_conj (z : K) : normSq (conj z) = normSq z := by simp only [normSq_apply, neg_mul, mul_neg, neg_neg, rclike_simps] -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem normSq_mul (z w : K) : normSq (z * w) = normSq z * normSq w := map_mul _ z w @@ -466,7 +467,7 @@ theorem div_im (z w : K) : im (z / w) = im z * re w / normSq w - re z * im w / n simp only [div_eq_mul_inv, mul_assoc, sub_eq_add_neg, add_comm, neg_mul, mul_neg, map_neg, rclike_simps] -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem conj_inv (x : K) : conj x⁻¹ = (conj x)⁻¹ := star_inv' _ @@ -506,11 +507,11 @@ theorem inv_I : (I : K)⁻¹ = -I := by @[simp, rclike_simps] theorem div_I (z : K) : z / I = -(z * I) := by rw [div_eq_mul_inv, inv_I, mul_neg] -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem normSq_inv (z : K) : normSq z⁻¹ = (normSq z)⁻¹ := map_inv₀ normSq z -@[rclike_simps] -- porting note (#10618): was `simp` +@[rclike_simps] -- porting note (#11119): was `simp` theorem normSq_div (z w : K) : normSq (z / w) = normSq z / normSq w := map_div₀ normSq z w @@ -693,11 +694,11 @@ theorem norm_sq_re_conj_add (x : K) : ‖conj x + x‖ ^ 2 = re (conj x + x) ^ 2 /-! ### Cauchy sequences -/ -theorem isCauSeq_re (f : CauSeq K norm) : IsCauSeq abs fun n => re (f n) := fun ε ε0 => +theorem isCauSeq_re (f : CauSeq K norm) : IsCauSeq abs fun n => re (f n) := fun _ ε0 => (f.cauchy ε0).imp fun i H j ij => lt_of_le_of_lt (by simpa only [map_sub] using abs_re_le_norm (f j - f i)) (H _ ij) -theorem isCauSeq_im (f : CauSeq K norm) : IsCauSeq abs fun n => im (f n) := fun ε ε0 => +theorem isCauSeq_im (f : CauSeq K norm) : IsCauSeq abs fun n => im (f n) := fun _ ε0 => (f.cauchy ε0).imp fun i H j ij => lt_of_le_of_lt (by simpa only [map_sub] using abs_im_le_norm (f j - f i)) (H _ ij) @@ -725,8 +726,8 @@ noncomputable instance Real.instRCLike : RCLike ℝ where I_mul_I_ax := Or.intro_left _ rfl re_add_im_ax z := by simp only [add_zero, mul_zero, Algebra.id.map_eq_id, RingHom.id_apply, AddMonoidHom.id_apply] - ofReal_re_ax f := rfl - ofReal_im_ax r := rfl + ofReal_re_ax _ := rfl + ofReal_im_ax _ := rfl mul_re_ax z w := by simp only [sub_zero, mul_zero, AddMonoidHom.zero_apply, AddMonoidHom.id_apply] mul_im_ax z w := by simp only [add_zero, zero_mul, mul_zero, AddMonoidHom.zero_apply] conj_re_ax z := by simp only [starRingEnd_apply, star_id_of_comm] @@ -858,7 +859,7 @@ scoped[ComplexOrder] attribute [instance] RCLike.toOrderedSMul lemma _root_.StarModule.instOrderedSMul {A : Type*} [NonUnitalRing A] [StarRing A] [PartialOrder A] [StarOrderedRing A] [Module K A] [StarModule K A] [IsScalarTower K A A] [SMulCommClass K A A] : OrderedSMul K A where - smul_lt_smul_of_pos {x y c} hxy hc := StarModule.smul_lt_smul_of_pos hxy hc + smul_lt_smul_of_pos {_ _ _} hxy hc := StarModule.smul_lt_smul_of_pos hxy hc lt_of_smul_lt_smul_of_pos {x y c} hxy hc := by have : c⁻¹ • c • x < c⁻¹ • c • y := StarModule.smul_lt_smul_of_pos hxy (RCLike.inv_pos_of_pos hc) @@ -871,6 +872,20 @@ instance {A : Type*} [NonUnitalRing A] [StarRing A] [PartialOrder A] [StarOrdere scoped[ComplexOrder] attribute [instance] StarModule.instOrderedSMul +theorem ofReal_mul_pos_iff (x : ℝ) (z : K) : + 0 < x * z ↔ (x < 0 ∧ z < 0) ∨ (0 < x ∧ 0 < z) := by + simp only [pos_iff (K := K), neg_iff (K := K), re_ofReal_mul, im_ofReal_mul] + obtain hx | hx | hx := lt_trichotomy x 0 + · simp only [mul_pos_iff, not_lt_of_gt hx, false_and, hx, true_and, false_or, mul_eq_zero, hx.ne, + or_false] + · simp only [hx, zero_mul, lt_self_iff_false, false_and, false_or] + · simp only [mul_pos_iff, hx, true_and, not_lt_of_gt hx, false_and, or_false, mul_eq_zero, + hx.ne', false_or] + +theorem ofReal_mul_neg_iff (x : ℝ) (z : K) : + x * z < 0 ↔ (x < 0 ∧ 0 < z) ∨ (0 < x ∧ z < 0) := by + simpa only [mul_neg, neg_pos, neg_neg_iff_pos] using ofReal_mul_pos_iff x (-z) + end Order section CleanupLemmas @@ -1086,7 +1101,7 @@ section /-- A mixin over a normed field, saying that the norm field structure is the same as `ℝ` or `ℂ`. To endow such a field with a compatible `RCLike` structure in a proof, use `letI := IsRCLikeNormedField.rclike 𝕜`.-/ -class IsRCLikeNormedField (𝕜 : Type*) [hk : NormedField 𝕜] : Prop := +class IsRCLikeNormedField (𝕜 : Type*) [hk : NormedField 𝕜] : Prop where out : ∃ h : RCLike 𝕜, hk = h.toNormedField instance (priority := 100) (𝕜 : Type*) [h : RCLike 𝕜] : IsRCLikeNormedField 𝕜 := ⟨⟨h, rfl⟩⟩ diff --git a/Mathlib/Analysis/RCLike/Inner.lean b/Mathlib/Analysis/RCLike/Inner.lean new file mode 100644 index 0000000000000..4136cd8069e82 --- /dev/null +++ b/Mathlib/Analysis/RCLike/Inner.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2023 Yaël Dilies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dilies +-/ +import Mathlib.Analysis.InnerProductSpace.PiL2 + +/-! +# L2 inner product of finite sequences + +This file defines the weighted L2 inner product of functions `f g : ι → R` where `ι` is a fintype as +`∑ i, conj (f i) * g i`. This convention (conjugation on the left) matches the inner product coming +from `RCLike.innerProductSpace`. + +## TODO + +* Build a non-instance `InnerProductSpace` from `wInner`. +* `cWeight` is a poor name. Can we find better? It doesn't hugely matter for typing, since it's + hidden behind the `⟪f, g⟫ₙ_[𝕝] `notation, but it does show up in lemma names + `⟪f, g⟫_[𝕝, cWeight]` is called `wInner_cWeight`. Maybe we should introduce some naming + convention, similarly to `MeasureTheory.average`? +-/ + +open Finset Function Real +open scoped BigOperators ComplexConjugate ComplexOrder ENNReal NNReal NNRat + +variable {ι κ 𝕜 : Type*} {E : ι → Type*} [Fintype ι] + +namespace RCLike +variable [RCLike 𝕜] + +section Pi +variable [∀ i, SeminormedAddCommGroup (E i)] [∀ i, InnerProductSpace 𝕜 (E i)] {w : ι → ℝ} + +/-- Weighted inner product giving rise to the L2 norm. -/ +def wInner (w : ι → ℝ) (f g : ∀ i, E i) : 𝕜 := ∑ i, w i • inner (f i) (g i) + +/-- The weight function making `wInner` into the compact inner product. -/ +noncomputable abbrev cWeight : ι → ℝ := Function.const _ (Fintype.card ι)⁻¹ + +@[inherit_doc] notation "⟪" f ", " g "⟫_[" 𝕝 ", " w "]" => wInner (𝕜 := 𝕝) w f g + +/-- Discrete inner product giving rise to the discrete L2 norm. -/ +notation "⟪" f ", " g "⟫_[" 𝕝 "]" => ⟪f, g⟫_[𝕝, 1] + +/-- Compact inner product giving rise to the compact L2 norm. -/ +notation "⟪" f ", " g "⟫ₙ_[" 𝕝 "]" => ⟪f, g⟫_[𝕝, cWeight] + +lemma wInner_cWeight_eq_smul_wInner_one (f g : ∀ i, E i) : + ⟪f, g⟫ₙ_[𝕜] = (Fintype.card ι : ℚ≥0)⁻¹ • ⟪f, g⟫_[𝕜] := by + simp [wInner, smul_sum, ← NNRat.cast_smul_eq_nnqsmul ℝ] + +@[simp] lemma conj_wInner_symm (w : ι → ℝ) (f g : ∀ i, E i) : + conj ⟪f, g⟫_[𝕜, w] = ⟪g, f⟫_[𝕜, w] := by + simp [wInner, map_sum, inner_conj_symm, rclike_simps] + +@[simp] lemma wInner_zero_left (w : ι → ℝ) (g : ∀ i, E i) : ⟪0, g⟫_[𝕜, w] = 0 := by simp [wInner] +@[simp] lemma wInner_zero_right (w : ι → ℝ) (f : ∀ i, E i) : ⟪f, 0⟫_[𝕜, w] = 0 := by simp [wInner] + +lemma wInner_add_left (w : ι → ℝ) (f₁ f₂ g : ∀ i, E i) : + ⟪f₁ + f₂, g⟫_[𝕜, w] = ⟪f₁, g⟫_[𝕜, w] + ⟪f₂, g⟫_[𝕜, w] := by + simp [wInner, inner_add_left, smul_add, sum_add_distrib] + +lemma wInner_add_right (w : ι → ℝ) (f g₁ g₂ : ∀ i, E i) : + ⟪f, g₁ + g₂⟫_[𝕜, w] = ⟪f, g₁⟫_[𝕜, w] + ⟪f, g₂⟫_[𝕜, w] := by + simp [wInner, inner_add_right, smul_add, sum_add_distrib] + +@[simp] lemma wInner_neg_left (w : ι → ℝ) (f g : ∀ i, E i) : ⟪-f, g⟫_[𝕜, w] = -⟪f, g⟫_[𝕜, w] := by + simp [wInner] + +@[simp] lemma wInner_neg_right (w : ι → ℝ) (f g : ∀ i, E i) : ⟪f, -g⟫_[𝕜, w] = -⟪f, g⟫_[𝕜, w] := by + simp [wInner] + +lemma wInner_sub_left (w : ι → ℝ) (f₁ f₂ g : ∀ i, E i) : + ⟪f₁ - f₂, g⟫_[𝕜, w] = ⟪f₁, g⟫_[𝕜, w] - ⟪f₂, g⟫_[𝕜, w] := by + simp_rw [sub_eq_add_neg, wInner_add_left, wInner_neg_left] + +lemma wInner_sub_right (w : ι → ℝ) (f g₁ g₂ : ∀ i, E i) : + ⟪f, g₁ - g₂⟫_[𝕜, w] = ⟪f, g₁⟫_[𝕜, w] - ⟪f, g₂⟫_[𝕜, w] := by + simp_rw [sub_eq_add_neg, wInner_add_right, wInner_neg_right] + +@[simp] lemma wInner_of_isEmpty [IsEmpty ι] (w : ι → ℝ) (f g : ∀ i, E i) : ⟪f, g⟫_[𝕜, w] = 0 := by + simp [Subsingleton.elim f 0] + +lemma wInner_smul_left {𝕝 : Type*} [CommSemiring 𝕝] [StarRing 𝕝] [Algebra 𝕝 𝕜] [StarModule 𝕝 𝕜] + [SMulCommClass ℝ 𝕝 𝕜] [∀ i, Module 𝕝 (E i)] [∀ i, IsScalarTower 𝕝 𝕜 (E i)] (c : 𝕝) + (w : ι → ℝ) (f g : ∀ i, E i) : ⟪c • f, g⟫_[𝕜, w] = star c • ⟪f, g⟫_[𝕜, w] := by + simp_rw [wInner, Pi.smul_apply, inner_smul_left_eq_star_smul, starRingEnd_apply, smul_sum, + smul_comm (w _)] + +lemma wInner_smul_right {𝕝 : Type*} [CommSemiring 𝕝] [StarRing 𝕝] [Algebra 𝕝 𝕜] [StarModule 𝕝 𝕜] + [SMulCommClass ℝ 𝕝 𝕜] [∀ i, Module 𝕝 (E i)] [∀ i, IsScalarTower 𝕝 𝕜 (E i)] (c : 𝕝) + (w : ι → ℝ) (f g : ∀ i, E i) : ⟪f, c • g⟫_[𝕜, w] = c • ⟪f, g⟫_[𝕜, w] := by + simp_rw [wInner, Pi.smul_apply, inner_smul_right_eq_smul, smul_sum, smul_comm] + +lemma mul_wInner_left (c : 𝕜) (w : ι → ℝ) (f g : ∀ i, E i) : + c * ⟪f, g⟫_[𝕜, w] = ⟪star c • f, g⟫_[𝕜, w] := by rw [wInner_smul_left, star_star, smul_eq_mul] + +lemma wInner_one_eq_sum (f g : ∀ i, E i) : ⟪f, g⟫_[𝕜] = ∑ i, inner (f i) (g i) := by simp [wInner] +lemma wInner_cWeight_eq_expect (f g : ∀ i, E i) : ⟪f, g⟫ₙ_[𝕜] = 𝔼 i, inner (f i) (g i) := by + simp [wInner, expect, smul_sum, ← NNRat.cast_smul_eq_nnqsmul ℝ] + +end Pi + +section Function +variable {w : ι → ℝ} {f g : ι → 𝕜} + +lemma wInner_const_left (a : 𝕜) (f : ι → 𝕜) : + ⟪const _ a, f⟫_[𝕜, w] = conj a * ∑ i, w i • f i := by simp [wInner, const_apply, mul_sum] + +lemma wInner_const_right (f : ι → 𝕜) (a : 𝕜) : + ⟪f, const _ a⟫_[𝕜, w] = (∑ i, w i • conj (f i)) * a := by simp [wInner, const_apply, sum_mul] + +@[simp] lemma wInner_one_const_left (a : 𝕜) (f : ι → 𝕜) : + ⟪const _ a, f⟫_[𝕜] = conj a * ∑ i, f i := by simp [wInner_one_eq_sum, mul_sum] + +@[simp] lemma wInner_one_const_right (f : ι → 𝕜) (a : 𝕜) : + ⟪f, const _ a⟫_[𝕜] = (∑ i, conj (f i)) * a := by simp [wInner_one_eq_sum, sum_mul] + +@[simp] lemma wInner_cWeight_const_left (a : 𝕜) (f : ι → 𝕜) : + ⟪const _ a, f⟫ₙ_[𝕜] = conj a * 𝔼 i, f i := by simp [wInner_cWeight_eq_expect, mul_expect] + +@[simp] lemma wInner_cWeight_const_right (f : ι → 𝕜) (a : 𝕜) : + ⟪f, const _ a⟫ₙ_[𝕜] = (𝔼 i, conj (f i)) * a := by simp [wInner_cWeight_eq_expect, expect_mul] + +lemma wInner_one_eq_inner (f g : ι → 𝕜) : + ⟪f, g⟫_[𝕜, 1] = inner ((WithLp.equiv 2 _).symm f) ((WithLp.equiv 2 _).symm g) := by + simp [wInner] + +lemma inner_eq_wInner_one (f g : PiLp 2 fun _i : ι ↦ 𝕜) : + inner f g = ⟪WithLp.equiv 2 _ f, WithLp.equiv 2 _ g⟫_[𝕜, 1] := by simp [wInner] + +lemma linearIndependent_of_ne_zero_of_wInner_one_eq_zero {f : κ → ι → 𝕜} (hf : ∀ k, f k ≠ 0) + (hinner : Pairwise fun k₁ k₂ ↦ ⟪f k₁, f k₂⟫_[𝕜] = 0) : LinearIndependent 𝕜 f := by + simp_rw [wInner_one_eq_inner] at hinner + have := linearIndependent_of_ne_zero_of_inner_eq_zero ?_ hinner + exacts [this, hf] + +lemma linearIndependent_of_ne_zero_of_wInner_cWeight_eq_zero {f : κ → ι → 𝕜} (hf : ∀ k, f k ≠ 0) + (hinner : Pairwise fun k₁ k₂ ↦ ⟪f k₁, f k₂⟫ₙ_[𝕜] = 0) : LinearIndependent 𝕜 f := by + cases isEmpty_or_nonempty ι + · have : IsEmpty κ := ⟨fun k ↦ hf k <| Subsingleton.elim ..⟩ + exact linearIndependent_empty_type + · exact linearIndependent_of_ne_zero_of_wInner_one_eq_zero hf <| by + simpa [wInner_cWeight_eq_smul_wInner_one, ← NNRat.cast_smul_eq_nnqsmul 𝕜] using hinner + +lemma wInner_nonneg (hw : 0 ≤ w) (hf : 0 ≤ f) (hg : 0 ≤ g) : 0 ≤ ⟪f, g⟫_[𝕜, w] := + sum_nonneg fun _ _ ↦ smul_nonneg (hw _) <| mul_nonneg (star_nonneg_iff.2 (hf _)) (hg _) + +lemma norm_wInner_le (hw : 0 ≤ w) : ‖⟪f, g⟫_[𝕜, w]‖ ≤ ⟪fun i ↦ ‖f i‖, fun i ↦ ‖g i‖⟫_[ℝ, w] := + (norm_sum_le ..).trans_eq <| sum_congr rfl fun i _ ↦ by + simp [Algebra.smul_def, norm_mul, abs_of_nonneg (hw i)] + +end Function + +section Real +variable {w f g : ι → ℝ} + +lemma abs_wInner_le (hw : 0 ≤ w) : |⟪f, g⟫_[ℝ, w]| ≤ ⟪|f|, |g|⟫_[ℝ, w] := by + simpa using norm_wInner_le (𝕜 := ℝ) hw + +end Real +end RCLike diff --git a/Mathlib/Analysis/RCLike/Lemmas.lean b/Mathlib/Analysis/RCLike/Lemmas.lean index 9c307a9be695f..0603a4fda4c16 100644 --- a/Mathlib/Analysis/RCLike/Lemmas.lean +++ b/Mathlib/Analysis/RCLike/Lemmas.lean @@ -31,8 +31,6 @@ This instance generates a type-class problem with a metavariable `?m` that shoul `RCLike ?m`. Since this can only be satisfied by `ℝ` or `ℂ`, this does not cause problems. -/ /-- An `RCLike` field is finite-dimensional over `ℝ`, since it is spanned by `{1, I}`. -/ --- Porting note(#12094): removed nolint; dangerous_instance linter not ported yet --- @[nolint dangerous_instance] instance rclike_to_real : FiniteDimensional ℝ K := ⟨{1, I}, by suffices ∀ x : K, ∃ a b : ℝ, a • 1 + b • I = x by diff --git a/Mathlib/Analysis/Seminorm.lean b/Mathlib/Analysis/Seminorm.lean index c59be01c21689..d042eab14c553 100644 --- a/Mathlib/Analysis/Seminorm.lean +++ b/Mathlib/Analysis/Seminorm.lean @@ -38,7 +38,7 @@ open NormedField Set Filter open scoped NNReal Pointwise Topology Uniformity -variable {R R' 𝕜 𝕜₂ 𝕜₃ 𝕝 E E₂ E₃ F G ι : Type*} +variable {R R' 𝕜 𝕜₂ 𝕜₃ 𝕝 E E₂ E₃ F ι : Type*} /-- A seminorm on a module over a normed ring is a function to the reals that is positive semidefinite, positive homogeneous, and subadditive. -/ @@ -61,9 +61,6 @@ class SeminormClass (F : Type*) (𝕜 E : outParam Type*) [SeminormedRing 𝕜] export SeminormClass (map_smul_eq_mul) --- Porting note: dangerous instances no longer exist --- attribute [nolint dangerousInstance] SeminormClass.toAddGroupSeminormClass - section Of /-- Alternative constructor for a `Seminorm` on an `AddCommGroup E` that is a module over a @@ -141,7 +138,7 @@ theorem zero_apply (x : E) : (0 : Seminorm 𝕜 E) x = 0 := instance : Inhabited (Seminorm 𝕜 E) := ⟨0⟩ -variable (p : Seminorm 𝕜 E) (c : 𝕜) (x y : E) (r : ℝ) +variable (p : Seminorm 𝕜 E) (x : E) (r : ℝ) /-- Any action on `ℝ` which factors through `ℝ≥0` applies to a seminorm. -/ instance instSMul [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] : SMul R (Seminorm 𝕜 E) where @@ -231,7 +228,7 @@ theorem smul_sup [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r have real.smul_max : ∀ x y : ℝ, r • max x y = max (r • x) (r • y) := fun x y => by simpa only [← smul_eq_mul, ← NNReal.smul_def, smul_one_smul ℝ≥0 r (_ : ℝ)] using mul_max_of_nonneg x y (r • (1 : ℝ≥0) : ℝ≥0).coe_nonneg - ext fun x => real.smul_max _ _ + ext fun _ => real.smul_max _ _ instance instPartialOrder : PartialOrder (Seminorm 𝕜 E) := PartialOrder.lift _ DFunLike.coe_injective @@ -264,8 +261,7 @@ variable {σ₁₂ : 𝕜 →+* 𝕜₂} [RingHomIsometric σ₁₂] variable {σ₂₃ : 𝕜₂ →+* 𝕜₃} [RingHomIsometric σ₂₃] variable {σ₁₃ : 𝕜 →+* 𝕜₃} [RingHomIsometric σ₁₃] variable [AddCommGroup E] [AddCommGroup E₂] [AddCommGroup E₃] -variable [AddCommGroup F] [AddCommGroup G] -variable [Module 𝕜 E] [Module 𝕜₂ E₂] [Module 𝕜₃ E₃] [Module 𝕜 F] [Module 𝕜 G] +variable [Module 𝕜 E] [Module 𝕜₂ E₂] [Module 𝕜₃ E₃] -- Porting note: even though this instance is found immediately by typeclass search, -- it seems to be needed below!? @@ -462,8 +458,8 @@ noncomputable instance instLattice : Lattice (Seminorm 𝕜 E) := inf_le_right := fun p q x => ciInf_le_of_le bddBelow_range_add 0 <| by simp only [sub_self, map_zero, zero_add, sub_zero]; rfl - le_inf := fun a b c hab hac x => - le_ciInf fun u => (le_map_add_map_sub a _ _).trans <| add_le_add (hab _) (hac _) } + le_inf := fun a _ _ hab hac _ => + le_ciInf fun _ => (le_map_add_map_sub a _ _).trans <| add_le_add (hab _) (hac _) } theorem smul_inf [SMul R ℝ] [SMul R ℝ≥0] [IsScalarTower R ℝ≥0 ℝ] (r : R) (p q : Seminorm 𝕜 E) : r • (p ⊓ q) = r • p ⊓ r • q := by @@ -533,7 +529,7 @@ protected theorem coe_sSup_eq' {s : Set <| Seminorm 𝕜 E} protected theorem bddAbove_iff {s : Set <| Seminorm 𝕜 E} : BddAbove s ↔ BddAbove ((↑) '' s : Set (E → ℝ)) := - ⟨fun ⟨q, hq⟩ => ⟨q, forall_mem_image.2 fun p hp => hq hp⟩, fun H => + ⟨fun ⟨q, hq⟩ => ⟨q, forall_mem_image.2 fun _ hp => hq hp⟩, fun H => ⟨sSup s, fun p hp x => by dsimp rw [Seminorm.coe_sSup_eq' H, iSup_apply] @@ -870,8 +866,7 @@ end SeminormedRing section NormedField -variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] (p : Seminorm 𝕜 E) {A B : Set E} {a : 𝕜} - {r : ℝ} {x : E} +variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] (p : Seminorm 𝕜 E) {r : ℝ} {x : E} theorem closedBall_iSup {ι : Sort*} {p : ι → Seminorm 𝕜 E} (hp : BddAbove (range p)) (e : E) {r : ℝ} (hr : 0 < r) : closedBall (⨆ i, p i) e r = ⋂ i, closedBall (p i) e r := by @@ -1190,7 +1185,7 @@ lemma rescale_to_shell_zpow (p : Seminorm 𝕜 E) {c : 𝕜} (hc : 1 < ‖c‖) · show ε / ‖c‖ ≤ p (c ^ (-(n + 1)) • x) rw [zpow_neg, div_le_iff₀ cpos, map_smul_eq_mul, norm_inv, norm_zpow, zpow_add₀ (ne_of_gt cpos), zpow_one, mul_inv_rev, mul_comm, ← mul_assoc, ← mul_assoc, mul_inv_cancel₀ (ne_of_gt cpos), - one_mul, ← div_eq_inv_mul, le_div_iff₀ (zpow_pos_of_pos cpos _), mul_comm] + one_mul, ← div_eq_inv_mul, le_div_iff₀ (zpow_pos cpos _), mul_comm] exact (le_div_iff₀ εpos).1 hn.1 · show ‖(c ^ (-(n + 1)))‖⁻¹ ≤ ε⁻¹ * ‖c‖ * p x have : ε⁻¹ * ‖c‖ * p x = ε⁻¹ * p x * ‖c‖ := by ring diff --git a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean index 50a7c0ab65155..a38081bf15582 100644 --- a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean +++ b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ +import Mathlib.Algebra.Order.Field.Power import Mathlib.Analysis.SpecificLimits.Basic import Mathlib.RingTheory.Polynomial.Bernstein import Mathlib.Topology.ContinuousMap.Polynomial diff --git a/Mathlib/Analysis/SpecialFunctions/BinaryEntropy.lean b/Mathlib/Analysis/SpecialFunctions/BinaryEntropy.lean index 402c63a136cb7..c74cbff25c9e5 100644 --- a/Mathlib/Analysis/SpecialFunctions/BinaryEntropy.lean +++ b/Mathlib/Analysis/SpecialFunctions/BinaryEntropy.lean @@ -80,8 +80,8 @@ lemma binEntropy_two_inv_add (p : ℝ) : binEntropy (2⁻¹ + p) = binEntropy (2 lemma binEntropy_pos (hp₀ : 0 < p) (hp₁ : p < 1) : 0 < binEntropy p := by unfold binEntropy have : 0 < 1 - p := sub_pos.2 hp₁ - have : 0 < log p⁻¹ := log_pos <| one_lt_inv hp₀ hp₁ - have : 0 < log (1 - p)⁻¹ := log_pos <| one_lt_inv ‹_› (sub_lt_self _ hp₀) + have : 0 < log p⁻¹ := log_pos <| (one_lt_inv₀ hp₀).2 hp₁ + have : 0 < log (1 - p)⁻¹ := log_pos <| (one_lt_inv₀ ‹_›).2 (sub_lt_self _ hp₀) positivity lemma binEntropy_nonneg (hp₀ : 0 ≤ p) (hp₁ : p ≤ 1) : 0 ≤ binEntropy p := by @@ -397,7 +397,7 @@ lemma qaryEntropy_strictAntiOn (qLe2 : 2 ≤ q) : · exact qaryEntropy_continuous.continuousOn · intro p hp have : 2 ≤ (q : ℝ) := Nat.ofNat_le_cast.mpr qLe2 - have qinv_lt_1 : (q : ℝ)⁻¹ < 1 := inv_lt_one (by linarith) + have qinv_lt_1 : (q : ℝ)⁻¹ < 1 := inv_lt_one_of_one_lt₀ (by linarith) have zero_lt_1_sub_p : 0 < 1 - p := by simp_all only [sub_pos, hp.2, interior_Icc, mem_Ioo] simp only [one_div, interior_Icc, mem_Ioo] at hp rw [deriv_qaryEntropy (by linarith)] diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean index b7b5fa601494d..0086e643a19b8 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean @@ -597,7 +597,7 @@ theorem continuousAt_arg_coe_angle (h : x ≠ 0) : ContinuousAt ((↑) ∘ arg : by_cases hs : x ∈ slitPlane · exact Real.Angle.continuous_coe.continuousAt.comp (continuousAt_arg hs) · rw [← Function.comp_id (((↑) : ℝ → Real.Angle) ∘ arg), - (Function.funext_iff.2 fun _ => (neg_neg _).symm : (id : ℂ → ℂ) = Neg.neg ∘ Neg.neg), ← + (funext_iff.2 fun _ => (neg_neg _).symm : (id : ℂ → ℂ) = Neg.neg ∘ Neg.neg), ← Function.comp_assoc] refine ContinuousAt.comp ?_ continuous_neg.continuousAt suffices ContinuousAt (Function.update (((↑) ∘ arg) ∘ Neg.neg : ℂ → Real.Angle) 0 π) (-x) by diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean index 7d994e5d897af..d5f625bba8628 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean @@ -31,7 +31,7 @@ namespace Complex lemma continuousOn_one_add_mul_inv {z : ℂ} (hz : 1 + z ∈ slitPlane) : ContinuousOn (fun t : ℝ ↦ (1 + t • z)⁻¹) (Set.Icc 0 1) := ContinuousOn.inv₀ (by fun_prop) - (fun t ht ↦ slitPlane_ne_zero <| StarConvex.add_smul_mem starConvex_one_slitPlane hz ht.1 ht.2) + (fun _ ht ↦ slitPlane_ne_zero <| StarConvex.add_smul_mem starConvex_one_slitPlane hz ht.1 ht.2) open intervalIntegral in /-- Represent `log (1 + z)` as an integral over the unit interval -/ @@ -110,7 +110,7 @@ lemma norm_one_add_mul_inv_le {t : ℝ} (ht : t ∈ Set.Icc 0 1) {z : ℂ} (hz : ‖(1 + t * z)⁻¹‖ ≤ (1 - ‖z‖)⁻¹ := by rw [Set.mem_Icc] at ht rw [norm_inv, norm_eq_abs] - refine inv_le_inv_of_le (by linarith) ?_ + refine inv_anti₀ (by linarith) ?_ calc 1 - ‖z‖ _ ≤ 1 - t * ‖z‖ := by nlinarith [norm_nonneg z] diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean index f92d4934e22ec..40f804326f3c6 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean @@ -43,8 +43,8 @@ noncomputable def expPartialHomeomorph : PartialHomeomorph ℂ ℂ := map_target' := fun z h => by simp only [mem_setOf, log_im, mem_Ioo, neg_pi_lt_arg, arg_lt_pi_iff, true_and] exact h.imp_left le_of_lt - left_inv' := fun x hx => log_exp hx.1 (le_of_lt hx.2) - right_inv' := fun x hx => exp_log <| slitPlane_ne_zero hx } + left_inv' := fun _ hx => log_exp hx.1 (le_of_lt hx.2) + right_inv' := fun _ hx => exp_log <| slitPlane_ne_zero hx } continuous_exp.continuousOn isOpenMap_exp (isOpen_Ioo.preimage continuous_im) theorem hasStrictDerivAt_log {x : ℂ} (h : x ∈ slitPlane) : HasStrictDerivAt log x⁻¹ x := diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean index 8c7bd3f605070..27a9142d793a9 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean @@ -64,7 +64,7 @@ variable {𝕜 : Type*} {A : Type*} [RCLike 𝕜] {p : A → Prop} [NormedRing A lemma exp_eq_normedSpace_exp {a : A} (ha : p a := by cfc_tac) : cfc (exp 𝕜 : 𝕜 → 𝕜) a = exp 𝕜 a := by conv_rhs => rw [← cfc_id 𝕜 a ha, cfc_apply id a ha] - have h := (cfcHom_closedEmbedding (R := 𝕜) (show p a from ha)).continuous + have h := (cfcHom_isClosedEmbedding (R := 𝕜) (show p a from ha)).continuous have _ : ContinuousOn (exp 𝕜) (spectrum 𝕜 a) := exp_continuous.continuousOn simp_rw [← map_exp 𝕜 _ h, cfc_apply (exp 𝕜) a ha] congr 1 @@ -95,8 +95,7 @@ end RealNormed section ComplexNormed variable {A : Type*} {p : A → Prop} [NormedRing A] [StarRing A] - [TopologicalRing A] [NormedAlgebra ℂ A] [CompleteSpace A] - [ContinuousFunctionalCalculus ℂ p] + [NormedAlgebra ℂ A] [CompleteSpace A] [ContinuousFunctionalCalculus ℂ p] lemma complex_exp_eq_normedSpace_exp {a : A} (ha : p a := by cfc_tac) : cfc Complex.exp a = exp ℂ a := diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean index 9fcf8e77c60a6..00bb998dcc04b 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean @@ -5,8 +5,8 @@ Authors: Frédéric Dupuis -/ import Mathlib.Analysis.SpecialFunctions.Pow.Real -import Mathlib.Analysis.Normed.Algebra.Spectrum import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital +import Mathlib.Analysis.SpecialFunctions.Pow.Continuity /-! # Real powers defined via the continuous functional calculus @@ -287,6 +287,11 @@ lemma rpow_neg_one_eq_inv (a : Aˣ) (ha : (0 : A) ≤ a := by cfc_tac) : refine a.inv_eq_of_mul_eq_one_left ?_ |>.symm simpa [rpow_one (a : A)] using rpow_neg_mul_rpow 1 (spectrum.zero_not_mem ℝ≥0 a.isUnit) +lemma rpow_neg_one_eq_cfc_inv {A : Type*} [PartialOrder A] [NormedRing A] [StarRing A] + [NormedAlgebra ℝ A] [ContinuousFunctionalCalculus ℝ≥0 ((0 : A) ≤ ·)] (a : A) : + a ^ (-1 : ℝ) = cfc (·⁻¹ : ℝ≥0 → ℝ≥0) a := + cfc_congr fun x _ ↦ NNReal.rpow_neg_one x + lemma rpow_neg [UniqueContinuousFunctionalCalculus ℝ≥0 A] (a : Aˣ) (x : ℝ) (ha' : (0 : A) ≤ a := by cfc_tac) : (a : A) ^ (-x) = (↑a⁻¹ : A) ^ x := by suffices h₁ : ContinuousOn (fun z ↦ z ^ x) (Inv.inv '' (spectrum ℝ≥0 (a : A))) by @@ -306,8 +311,10 @@ lemma rpow_intCast (a : Aˣ) (n : ℤ) (ha : (0 : A) ≤ a := by cfc_tac) : section unital_vs_nonunital -variable [∀ (a : A), CompactSpace (spectrum ℝ a)] - [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] +variable [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + +-- provides instance `ContinuousFunctionalCalculus.compactSpace_spectrum` +open scoped ContinuousFunctionalCalculus lemma nnrpow_eq_rpow {a : A} {x : ℝ≥0} (hx : 0 < x) : a ^ x = a ^ (x : ℝ) := by rw [nnrpow_def (A := A), rpow_def, cfcₙ_eq_cfc] diff --git a/Mathlib/Analysis/SpecialFunctions/Exp.lean b/Mathlib/Analysis/SpecialFunctions/Exp.lean index 8d018a967ecb0..bd9a8f4a616de 100644 --- a/Mathlib/Analysis/SpecialFunctions/Exp.lean +++ b/Mathlib/Analysis/SpecialFunctions/Exp.lean @@ -369,16 +369,19 @@ theorem tendsto_exp_comp_nhds_zero {f : α → ℝ} : Tendsto (fun x => exp (f x)) l (𝓝 0) ↔ Tendsto f l atBot := by simp_rw [← comp_apply (f := exp), ← tendsto_comap_iff, comap_exp_nhds_zero] -theorem openEmbedding_exp : OpenEmbedding exp := - isOpen_Ioi.openEmbedding_subtype_val.comp expOrderIso.toHomeomorph.openEmbedding +theorem isOpenEmbedding_exp : IsOpenEmbedding exp := + isOpen_Ioi.isOpenEmbedding_subtypeVal.comp expOrderIso.toHomeomorph.isOpenEmbedding + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_exp := isOpenEmbedding_exp @[simp] theorem map_exp_nhds (x : ℝ) : map exp (𝓝 x) = 𝓝 (exp x) := - openEmbedding_exp.map_nhds_eq x + isOpenEmbedding_exp.map_nhds_eq x @[simp] theorem comap_exp_nhds_exp (x : ℝ) : comap exp (𝓝 (exp x)) = 𝓝 x := - (openEmbedding_exp.nhds_eq_comap x).symm + (isOpenEmbedding_exp.nhds_eq_comap x).symm theorem isLittleO_pow_exp_atTop {n : ℕ} : (fun x : ℝ => x ^ n) =o[atTop] Real.exp := by simpa [isLittleO_iff_tendsto fun x hx => ((exp_pos x).ne' hx).elim] using @@ -387,7 +390,7 @@ theorem isLittleO_pow_exp_atTop {n : ℕ} : (fun x : ℝ => x ^ n) =o[atTop] Rea @[simp] theorem isBigO_exp_comp_exp_comp {f g : α → ℝ} : ((fun x => exp (f x)) =O[l] fun x => exp (g x)) ↔ IsBoundedUnder (· ≤ ·) l (f - g) := - Iff.trans (isBigO_iff_isBoundedUnder_le_div <| Eventually.of_forall fun x => exp_ne_zero _) <| by + Iff.trans (isBigO_iff_isBoundedUnder_le_div <| Eventually.of_forall fun _ => exp_ne_zero _) <| by simp only [norm_eq_abs, abs_exp, ← exp_sub, isBoundedUnder_le_exp_comp, Pi.sub_def] @[simp] @@ -403,8 +406,6 @@ theorem isLittleO_exp_comp_exp_comp {f g : α → ℝ} : simp only [isLittleO_iff_tendsto, exp_ne_zero, ← exp_sub, ← tendsto_neg_atTop_iff, false_imp_iff, imp_true_iff, tendsto_exp_comp_nhds_zero, neg_sub] --- Porting note (#10618): @[simp] can prove: by simp only [@Asymptotics.isLittleO_one_left_iff, --- Real.norm_eq_abs, Real.abs_exp, @Real.tendsto_exp_comp_atTop] theorem isLittleO_one_exp_comp {f : α → ℝ} : ((fun _ => 1 : α → ℝ) =o[l] fun x => exp (f x)) ↔ Tendsto f l atTop := by simp only [← exp_zero, isLittleO_exp_comp_exp_comp, sub_zero] diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean index 86b3f777ce844..d8f00d79a6694 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 David Loeffler. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Loeffler -/ +import Mathlib.Analysis.SpecialFunctions.ImproperIntegrals import Mathlib.MeasureTheory.Integral.ExpDecay -import Mathlib.Analysis.MellinTransform /-! # The Gamma function @@ -24,15 +24,12 @@ set it to be `0` by convention.) * `Complex.Gamma_eq_integral`: for `0 < re s`, `Γ(s)` agrees with Euler's integral. * `Complex.Gamma_add_one`: for all `s : ℂ` with `s ≠ 0`, we have `Γ (s + 1) = s Γ(s)`. * `Complex.Gamma_nat_eq_factorial`: for all `n : ℕ` we have `Γ (n + 1) = n!`. -* `Complex.differentiableAt_Gamma`: `Γ` is complex-differentiable at all `s : ℂ` with - `s ∉ {-n : n ∈ ℕ}`. ## Gamma function: main statements (real case) * `Real.Gamma`: the `Γ` function (of a real variable). * Real counterparts of all the properties of the complex Gamma function listed above: - `Real.Gamma_eq_integral`, `Real.Gamma_add_one`, `Real.Gamma_nat_eq_factorial`, - `Real.differentiableAt_Gamma`. + `Real.Gamma_eq_integral`, `Real.Gamma_add_one`, `Real.Gamma_nat_eq_factorial`. ## Tags @@ -92,7 +89,7 @@ theorem GammaIntegral_convergent {s : ℂ} (hs : 0 < s.re) : constructor · refine ContinuousOn.aestronglyMeasurable ?_ measurableSet_Ioi apply (continuous_ofReal.comp continuous_neg.rexp).continuousOn.mul - apply ContinuousAt.continuousOn + apply continuousOn_of_forall_continuousAt intro x hx have : ContinuousAt (fun x : ℂ => x ^ (s - 1)) ↑x := continuousAt_cpow_const <| ofReal_mem_slitPlane.2 hx @@ -115,7 +112,7 @@ def GammaIntegral (s : ℂ) : ℂ := theorem GammaIntegral_conj (s : ℂ) : GammaIntegral (conj s) = conj (GammaIntegral s) := by rw [GammaIntegral, GammaIntegral, ← integral_conj] - refine setIntegral_congr measurableSet_Ioi fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun x hx => ?_ dsimp only rw [RingHom.map_mul, conj_ofReal, cpow_def_of_ne_zero (ofReal_ne_zero.mpr (ne_of_gt hx)), cpow_def_of_ne_zero (ofReal_ne_zero.mpr (ne_of_gt hx)), ← exp_conj, RingHom.map_mul, ← @@ -123,10 +120,10 @@ theorem GammaIntegral_conj (s : ℂ) : GammaIntegral (conj s) = conj (GammaInteg theorem GammaIntegral_ofReal (s : ℝ) : GammaIntegral ↑s = ↑(∫ x : ℝ in Ioi 0, Real.exp (-x) * x ^ (s - 1)) := by - have : ∀ r : ℝ, Complex.ofReal' r = @RCLike.ofReal ℂ _ r := fun r => rfl + have : ∀ r : ℝ, Complex.ofReal r = @RCLike.ofReal ℂ _ r := fun r => rfl rw [GammaIntegral] conv_rhs => rw [this, ← _root_.integral_ofReal] - refine setIntegral_congr measurableSet_Ioi ?_ + refine setIntegral_congr_fun measurableSet_Ioi ?_ intro x hx; dsimp only conv_rhs => rw [← this] rw [ofReal_mul, ofReal_cpow (mem_Ioi.mp hx).le] @@ -173,7 +170,7 @@ private theorem Gamma_integrand_deriv_integrable_B {s : ℂ} (hs : 0 < s.re) {Y constructor · refine (continuousOn_const.mul ?_).aestronglyMeasurable measurableSet_Ioc apply (continuous_ofReal.comp continuous_neg.rexp).continuousOn.mul - apply ContinuousAt.continuousOn + apply continuousOn_of_forall_continuousAt intro x hx refine (?_ : ContinuousAt (fun x : ℂ => x ^ (s - 1)) _).comp continuous_ofReal.continuousAt exact continuousAt_cpow_const <| ofReal_mem_slitPlane.2 hx.1 @@ -377,7 +374,7 @@ lemma integral_cpow_mul_exp_neg_mul_Ioi {a : ℂ} {r : ℝ} (ha : 0 < a.re) (hr rw [← cpow_add _ _ (one_div_ne_zero <| ofReal_ne_zero.mpr hr.ne'), add_sub_cancel] calc _ = ∫ (t : ℝ) in Ioi 0, (1 / r) ^ (a - 1) * (r * t) ^ (a - 1) * exp (-(r * t)) := by - refine MeasureTheory.setIntegral_congr measurableSet_Ioi (fun x hx ↦ ?_) + refine MeasureTheory.setIntegral_congr_fun measurableSet_Ioi (fun x hx ↦ ?_) rw [mem_Ioi] at hx rw [mul_cpow_ofReal_nonneg hr.le hx.le, ← mul_assoc, one_div, ← ofReal_inv, ← mul_cpow_ofReal_nonneg (inv_pos.mpr hr).le hr.le, ← ofReal_mul r⁻¹, @@ -395,79 +392,6 @@ lemma integral_cpow_mul_exp_neg_mul_Ioi {a : ℂ} {r : ℝ} (ha : 0 < a.re) (hr end GammaDef -/-! Now check that the `Γ` function is differentiable, wherever this makes sense. -/ - - -section GammaHasDeriv - -/-- Rewrite the Gamma integral as an example of a Mellin transform. -/ -theorem GammaIntegral_eq_mellin : GammaIntegral = mellin fun x => ↑(Real.exp (-x)) := - funext fun s => by simp only [mellin, GammaIntegral, smul_eq_mul, mul_comm] - -/-- The derivative of the `Γ` integral, at any `s ∈ ℂ` with `1 < re s`, is given by the Mellin -transform of `log t * exp (-t)`. -/ -theorem hasDerivAt_GammaIntegral {s : ℂ} (hs : 0 < s.re) : - HasDerivAt GammaIntegral (∫ t : ℝ in Ioi 0, t ^ (s - 1) * (Real.log t * Real.exp (-t))) s := by - rw [GammaIntegral_eq_mellin] - convert (mellin_hasDerivAt_of_isBigO_rpow (E := ℂ) _ _ (lt_add_one _) _ hs).2 - · refine (Continuous.continuousOn ?_).locallyIntegrableOn measurableSet_Ioi - exact continuous_ofReal.comp (Real.continuous_exp.comp continuous_neg) - · rw [← isBigO_norm_left] - simp_rw [Complex.norm_eq_abs, abs_ofReal, ← Real.norm_eq_abs, isBigO_norm_left] - simpa only [neg_one_mul] using (isLittleO_exp_neg_mul_rpow_atTop zero_lt_one _).isBigO - · simp_rw [neg_zero, rpow_zero] - refine isBigO_const_of_tendsto (?_ : Tendsto _ _ (𝓝 (1 : ℂ))) one_ne_zero - rw [(by simp : (1 : ℂ) = Real.exp (-0))] - exact (continuous_ofReal.comp (Real.continuous_exp.comp continuous_neg)).continuousWithinAt - -theorem differentiableAt_GammaAux (s : ℂ) (n : ℕ) (h1 : 1 - s.re < n) (h2 : ∀ m : ℕ, s ≠ -m) : - DifferentiableAt ℂ (GammaAux n) s := by - induction' n with n hn generalizing s - · refine (hasDerivAt_GammaIntegral ?_).differentiableAt - rw [Nat.cast_zero] at h1; linarith - · dsimp only [GammaAux] - specialize hn (s + 1) - have a : 1 - (s + 1).re < ↑n := by - rw [Nat.cast_succ] at h1; rw [Complex.add_re, Complex.one_re]; linarith - have b : ∀ m : ℕ, s + 1 ≠ -m := by - intro m; have := h2 (1 + m) - contrapose! this - rw [← eq_sub_iff_add_eq] at this - simpa using this - refine DifferentiableAt.div (DifferentiableAt.comp _ (hn a b) ?_) ?_ ?_ - · rw [differentiableAt_add_const_iff (1 : ℂ)]; exact differentiableAt_id - · exact differentiableAt_id - · simpa using h2 0 - -theorem differentiableAt_Gamma (s : ℂ) (hs : ∀ m : ℕ, s ≠ -m) : DifferentiableAt ℂ Gamma s := by - let n := ⌊1 - s.re⌋₊ + 1 - have hn : 1 - s.re < n := mod_cast Nat.lt_floor_add_one (1 - s.re) - apply (differentiableAt_GammaAux s n hn hs).congr_of_eventuallyEq - let S := {t : ℂ | 1 - t.re < n} - have : S ∈ 𝓝 s := by - rw [mem_nhds_iff]; use S - refine ⟨Subset.rfl, ?_, hn⟩ - have : S = re ⁻¹' Ioi (1 - n : ℝ) := by - ext; rw [preimage, Ioi, mem_setOf_eq, mem_setOf_eq, mem_setOf_eq]; exact sub_lt_comm - rw [this] - exact Continuous.isOpen_preimage continuous_re _ isOpen_Ioi - apply eventuallyEq_of_mem this - intro t ht; rw [mem_setOf_eq] at ht - apply Gamma_eq_GammaAux; linarith - -end GammaHasDeriv - -/-- At `s = 0`, the Gamma function has a simple pole with residue 1. -/ -theorem tendsto_self_mul_Gamma_nhds_zero : Tendsto (fun z : ℂ => z * Gamma z) (𝓝[≠] 0) (𝓝 1) := by - rw [show 𝓝 (1 : ℂ) = 𝓝 (Gamma (0 + 1)) by simp only [zero_add, Complex.Gamma_one]] - convert (Tendsto.mono_left _ nhdsWithin_le_nhds).congr' - (eventuallyEq_of_mem self_mem_nhdsWithin Complex.Gamma_add_one) using 1 - refine ContinuousAt.comp (g := Gamma) ?_ (continuous_id.add continuous_const).continuousAt - refine (Complex.differentiableAt_Gamma _ fun m => ?_).continuousAt - rw [zero_add, ← ofReal_natCast, ← ofReal_neg, ← ofReal_one, Ne, ofReal_inj] - refine (lt_of_le_of_lt ?_ zero_lt_one).ne' - exact neg_nonpos.mpr (Nat.cast_nonneg _) - end Complex namespace Real @@ -484,10 +408,10 @@ theorem Gamma_eq_integral {s : ℝ} (hs : 0 < s) : simp_rw [← Complex.ofReal_one, ← Complex.ofReal_sub] suffices ∫ x : ℝ in Ioi 0, ↑(exp (-x)) * (x : ℂ) ^ ((s - 1 : ℝ) : ℂ) = ∫ x : ℝ in Ioi 0, ((exp (-x) * x ^ (s - 1) : ℝ) : ℂ) by - have cc : ∀ r : ℝ, Complex.ofReal' r = @RCLike.ofReal ℂ _ r := fun r => rfl + have cc : ∀ r : ℝ, Complex.ofReal r = @RCLike.ofReal ℂ _ r := fun r => rfl conv_lhs => rw [this]; enter [1, 2, x]; rw [cc] rw [_root_.integral_ofReal, ← cc, Complex.ofReal_re] - refine setIntegral_congr measurableSet_Ioi fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun x hx => ?_ push_cast rw [Complex.ofReal_cpow (le_of_lt hx)] push_cast; rfl @@ -551,7 +475,7 @@ lemma integral_rpow_mul_exp_neg_mul_Ioi {a r : ℝ} (ha : 0 < a) (hr : 0 < r) : ∫ t : ℝ in Ioi 0, t ^ (a - 1) * exp (-(r * t)) = (1 / r) ^ a * Gamma a := by rw [← ofReal_inj, ofReal_mul, ← Gamma_ofReal, ofReal_cpow (by positivity), ofReal_div] convert integral_cpow_mul_exp_neg_mul_Ioi (by rwa [ofReal_re] : 0 < (a : ℂ).re) hr - refine _root_.integral_ofReal.symm.trans <| setIntegral_congr measurableSet_Ioi (fun t ht ↦ ?_) + refine integral_ofReal.symm.trans <| setIntegral_congr_fun measurableSet_Ioi (fun t ht ↦ ?_) norm_cast simp_rw [← ofReal_cpow ht.le, RCLike.ofReal_mul, coe_algebraMap] @@ -606,9 +530,4 @@ theorem Gamma_ne_zero {s : ℝ} (hs : ∀ m : ℕ, s ≠ -m) : Gamma s ≠ 0 := theorem Gamma_eq_zero_iff (s : ℝ) : Gamma s = 0 ↔ ∃ m : ℕ, s = -m := ⟨by contrapose!; exact Gamma_ne_zero, by rintro ⟨m, rfl⟩; exact Gamma_neg_nat_eq_zero m⟩ -theorem differentiableAt_Gamma {s : ℝ} (hs : ∀ m : ℕ, s ≠ -m) : DifferentiableAt ℝ Gamma s := by - refine (Complex.differentiableAt_Gamma _ ?_).hasDerivAt.real_of_complex.differentiableAt - simp_rw [← Complex.ofReal_natCast, ← Complex.ofReal_neg, Ne, Complex.ofReal_inj] - exact hs - end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean index f449779354eda..f74f354ce98b3 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean @@ -62,7 +62,7 @@ theorem betaIntegral_convergent_left {u : ℂ} (hu : 0 < re u) (v : ℂ) : apply IntervalIntegrable.mul_continuousOn · refine intervalIntegral.intervalIntegrable_cpow' ?_ rwa [sub_re, one_re, ← zero_sub, sub_lt_sub_iff_right] - · apply ContinuousAt.continuousOn + · apply continuousOn_of_forall_continuousAt intro x hx rw [uIcc_of_le (by positivity : (0 : ℝ) ≤ 1 / 2)] at hx apply ContinuousAt.cpow @@ -114,7 +114,7 @@ theorem betaIntegral_scaled (s t : ℂ) {a : ℝ} (ha : 0 < a) : rw [A, mul_assoc, ← intervalIntegral.integral_const_mul, ← real_smul, ← zero_div a, ← div_self ha.ne', ← intervalIntegral.integral_comp_div _ ha.ne', zero_div] simp_rw [intervalIntegral.integral_of_le ha.le] - refine setIntegral_congr measurableSet_Ioc fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioc fun x hx => ?_ rw [mul_mul_mul_comm] congr 1 · rw [← mul_cpow_ofReal_nonneg ha.le (div_pos hx.1 ha).le, ofReal_div, mul_div_cancel₀ _ ha'] @@ -134,7 +134,7 @@ theorem Gamma_mul_Gamma_eq_betaIntegral {s t : ℂ} (hs : 0 < re s) (ht : 0 < re have hst : 0 < re (s + t) := by rw [add_re]; exact add_pos hs ht rw [Gamma_eq_integral hs, Gamma_eq_integral ht, Gamma_eq_integral hst, GammaIntegral, GammaIntegral, GammaIntegral, ← conv_int, ← integral_mul_right (betaIntegral _ _)] - refine setIntegral_congr measurableSet_Ioi fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun x hx => ?_ rw [mul_assoc, ← betaIntegral_scaled s t hx, ← intervalIntegral.integral_const_mul] congr 1 with y : 1 push_cast @@ -151,7 +151,8 @@ theorem betaIntegral_recurrence {u v : ℂ} (hu : 0 < re u) (hv : 0 < re v) : have hu' : 0 < re (u + 1) := by rw [add_re, one_re]; positivity have hv' : 0 < re (v + 1) := by rw [add_re, one_re]; positivity have hc : ContinuousOn F (Icc 0 1) := by - refine (ContinuousAt.continuousOn fun x hx => ?_).mul (ContinuousAt.continuousOn fun x hx => ?_) + refine (continuousOn_of_forall_continuousAt fun x hx => ?_).mul + (continuousOn_of_forall_continuousAt fun x hx => ?_) · refine (continuousAt_cpow_const_of_re_pos (Or.inl ?_) hu).comp continuous_ofReal.continuousAt rw [ofReal_re]; exact hx.1 · refine (continuousAt_cpow_const_of_re_pos (Or.inl ?_) hv).comp @@ -259,7 +260,7 @@ theorem GammaSeq_eq_approx_Gamma_integral {s : ℂ} (hs : 0 < re s) {n : ℕ} (h ← intervalIntegral.integral_const_mul, ← intervalIntegral.integral_const_mul] swap; · exact Nat.cast_ne_zero.mpr hn simp_rw [intervalIntegral.integral_of_le zero_le_one] - refine setIntegral_congr measurableSet_Ioc fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioc fun x hx => ?_ push_cast have hn' : (n : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr hn have A : (n : ℂ) ^ s = (n : ℂ) ^ (s - 1) * n := by diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean index f3bd9a9a2e9a4..86a1929d236cc 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean @@ -3,6 +3,7 @@ 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.Gamma.Deriv import Mathlib.Analysis.SpecialFunctions.Gaussian.GaussianIntegral /-! # Convexity properties of the Gamma function @@ -85,7 +86,7 @@ theorem Gamma_mul_add_mul_le_rpow_Gamma_mul_rpow_Gamma {s t a b : ℝ} (hs : 0 < congr 1 exact (norm_of_nonneg (posf _ _ x hx)).symm · refine ContinuousOn.aestronglyMeasurable ?_ measurableSet_Ioi - refine (Continuous.continuousOn ?_).mul (ContinuousAt.continuousOn fun x hx => ?_) + refine (Continuous.continuousOn ?_).mul (continuousOn_of_forall_continuousAt fun x hx => ?_) · exact continuous_exp.comp (continuous_const.mul continuous_id') · exact continuousAt_rpow_const _ _ (Or.inl (mem_Ioi.mp hx).ne') -- now apply Hölder: @@ -94,7 +95,7 @@ theorem Gamma_mul_add_mul_le_rpow_Gamma_mul_rpow_Gamma {s t a b : ℝ} (hs : 0 < MeasureTheory.integral_mul_le_Lp_mul_Lq_of_nonneg e (posf' a s) (posf' b t) (f_mem_Lp ha hs) (f_mem_Lp hb ht) using 1 - · refine setIntegral_congr measurableSet_Ioi fun x hx => ?_ + · refine setIntegral_congr_fun measurableSet_Ioi fun x hx => ?_ dsimp only have A : exp (-x) = exp (-a * x) * exp (-b * x) := by rw [← exp_add, ← add_mul, ← neg_add, hab, neg_one_mul] @@ -103,7 +104,7 @@ theorem Gamma_mul_add_mul_le_rpow_Gamma_mul_rpow_Gamma {s t a b : ℝ} (hs : 0 < rw [A, B] ring · rw [one_div_one_div, one_div_one_div] - congr 2 <;> exact setIntegral_congr measurableSet_Ioi fun x hx => fpow (by assumption) _ hx + congr 2 <;> exact setIntegral_congr_fun measurableSet_Ioi fun x hx => fpow (by assumption) _ hx theorem convexOn_log_Gamma : ConvexOn ℝ (Ioi 0) (log ∘ Gamma) := by refine convexOn_iff_forall_pos.mpr ⟨convex_Ioi _, fun x hx y hy a b ha hb hab => ?_⟩ diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Deriv.lean new file mode 100644 index 0000000000000..8488967aba430 --- /dev/null +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Deriv.lean @@ -0,0 +1,117 @@ +/- +Copyright (c) 2022 David Loeffler. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: David Loeffler +-/ +import Mathlib.Analysis.MellinTransform +import Mathlib.Analysis.SpecialFunctions.Gamma.Basic + +/-! +# Derivative of the Gamma function + +This file shows that the (complex) `Γ` function is complex-differentiable at all `s : ℂ` with +`s ∉ {-n : n ∈ ℕ}`, as well as the real counterpart. + +## Main results + +* `Complex.differentiableAt_Gamma`: `Γ` is complex-differentiable at all `s : ℂ` with + `s ∉ {-n : n ∈ ℕ}`. +* `Real.differentiableAt_Gamma`: `Γ` is real-differentiable at all `s : ℝ` with + `s ∉ {-n : n ∈ ℕ}`. + +## Tags + +Gamma +-/ + + +noncomputable section + +open Filter Set Real Asymptotics +open scoped Topology + +namespace Complex + +/-! Now check that the `Γ` function is differentiable, wherever this makes sense. -/ + + +section GammaHasDeriv + +/-- Rewrite the Gamma integral as an example of a Mellin transform. -/ +theorem GammaIntegral_eq_mellin : GammaIntegral = mellin fun x => ↑(Real.exp (-x)) := + funext fun s => by simp only [mellin, GammaIntegral, smul_eq_mul, mul_comm] + +/-- The derivative of the `Γ` integral, at any `s ∈ ℂ` with `1 < re s`, is given by the Mellin +transform of `log t * exp (-t)`. -/ +theorem hasDerivAt_GammaIntegral {s : ℂ} (hs : 0 < s.re) : + HasDerivAt GammaIntegral (∫ t : ℝ in Ioi 0, t ^ (s - 1) * (Real.log t * Real.exp (-t))) s := by + rw [GammaIntegral_eq_mellin] + convert (mellin_hasDerivAt_of_isBigO_rpow (E := ℂ) _ _ (lt_add_one _) _ hs).2 + · refine (Continuous.continuousOn ?_).locallyIntegrableOn measurableSet_Ioi + exact continuous_ofReal.comp (Real.continuous_exp.comp continuous_neg) + · rw [← isBigO_norm_left] + simp_rw [Complex.norm_eq_abs, abs_ofReal, ← Real.norm_eq_abs, isBigO_norm_left] + simpa only [neg_one_mul] using (isLittleO_exp_neg_mul_rpow_atTop zero_lt_one _).isBigO + · simp_rw [neg_zero, rpow_zero] + refine isBigO_const_of_tendsto (?_ : Tendsto _ _ (𝓝 (1 : ℂ))) one_ne_zero + rw [(by simp : (1 : ℂ) = Real.exp (-0))] + exact (continuous_ofReal.comp (Real.continuous_exp.comp continuous_neg)).continuousWithinAt + +theorem differentiableAt_GammaAux (s : ℂ) (n : ℕ) (h1 : 1 - s.re < n) (h2 : ∀ m : ℕ, s ≠ -m) : + DifferentiableAt ℂ (GammaAux n) s := by + induction' n with n hn generalizing s + · refine (hasDerivAt_GammaIntegral ?_).differentiableAt + rw [Nat.cast_zero] at h1; linarith + · dsimp only [GammaAux] + specialize hn (s + 1) + have a : 1 - (s + 1).re < ↑n := by + rw [Nat.cast_succ] at h1; rw [Complex.add_re, Complex.one_re]; linarith + have b : ∀ m : ℕ, s + 1 ≠ -m := by + intro m; have := h2 (1 + m) + contrapose! this + rw [← eq_sub_iff_add_eq] at this + simpa using this + refine DifferentiableAt.div (DifferentiableAt.comp _ (hn a b) ?_) ?_ ?_ + · rw [differentiableAt_add_const_iff (1 : ℂ)]; exact differentiableAt_id + · exact differentiableAt_id + · simpa using h2 0 + +theorem differentiableAt_Gamma (s : ℂ) (hs : ∀ m : ℕ, s ≠ -m) : DifferentiableAt ℂ Gamma s := by + let n := ⌊1 - s.re⌋₊ + 1 + have hn : 1 - s.re < n := mod_cast Nat.lt_floor_add_one (1 - s.re) + apply (differentiableAt_GammaAux s n hn hs).congr_of_eventuallyEq + let S := {t : ℂ | 1 - t.re < n} + have : S ∈ 𝓝 s := by + rw [mem_nhds_iff]; use S + refine ⟨Subset.rfl, ?_, hn⟩ + have : S = re ⁻¹' Ioi (1 - n : ℝ) := by + ext; rw [preimage, Ioi, mem_setOf_eq, mem_setOf_eq, mem_setOf_eq]; exact sub_lt_comm + rw [this] + exact Continuous.isOpen_preimage continuous_re _ isOpen_Ioi + apply eventuallyEq_of_mem this + intro t ht; rw [mem_setOf_eq] at ht + apply Gamma_eq_GammaAux; linarith + +end GammaHasDeriv + +/-- At `s = 0`, the Gamma function has a simple pole with residue 1. -/ +theorem tendsto_self_mul_Gamma_nhds_zero : Tendsto (fun z : ℂ => z * Gamma z) (𝓝[≠] 0) (𝓝 1) := by + rw [show 𝓝 (1 : ℂ) = 𝓝 (Gamma (0 + 1)) by simp only [zero_add, Complex.Gamma_one]] + convert (Tendsto.mono_left _ nhdsWithin_le_nhds).congr' + (eventuallyEq_of_mem self_mem_nhdsWithin Complex.Gamma_add_one) using 1 + refine ContinuousAt.comp (g := Gamma) ?_ (continuous_id.add continuous_const).continuousAt + refine (Complex.differentiableAt_Gamma _ fun m => ?_).continuousAt + rw [zero_add, ← ofReal_natCast, ← ofReal_neg, ← ofReal_one, Ne, ofReal_inj] + refine (lt_of_le_of_lt ?_ zero_lt_one).ne' + exact neg_nonpos.mpr (Nat.cast_nonneg _) + +end Complex + +namespace Real + +theorem differentiableAt_Gamma {s : ℝ} (hs : ∀ m : ℕ, s ≠ -m) : DifferentiableAt ℝ Gamma s := by + refine (Complex.differentiableAt_Gamma _ ?_).hasDerivAt.real_of_complex.differentiableAt + simp_rw [← Complex.ofReal_natCast, ← Complex.ofReal_neg, Ne, Complex.ofReal_inj] + exact hs + +end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean index 163d700eb16bb..89196d228c27b 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean @@ -259,10 +259,10 @@ theorem integral_gaussian_complex {b : ℂ} (hb : 0 < re b) : (convex_halfspace_re_gt 0).isPreconnected.eq_of_sq_eq ?_ ?_ (fun c hc => ?_) (fun {c} hc => ?_) (by simp : 0 < re (1 : ℂ)) ?_ hb · -- integral is continuous - exact ContinuousAt.continuousOn continuousAt_gaussian_integral + exact continuousOn_of_forall_continuousAt continuousAt_gaussian_integral · -- `(π / b) ^ (1 / 2 : ℂ)` is continuous refine - ContinuousAt.continuousOn fun b hb => + continuousOn_of_forall_continuousAt fun b hb => (continuousAt_cpow_const (Or.inl ?_)).comp (continuousAt_const.div continuousAt_id (nv hb)) rw [div_re, ofReal_im, ofReal_re, zero_mul, zero_div, add_zero] exact div_pos (mul_pos pi_pos hb) (normSq_pos.mpr (nv hb)) @@ -335,7 +335,7 @@ theorem Real.Gamma_one_half_eq : Real.Gamma (1 / 2) = √π := by rw [Gamma_eq_integral one_half_pos, ← integral_comp_rpow_Ioi_of_pos zero_lt_two] convert congr_arg (fun x : ℝ => 2 * x) (integral_gaussian_Ioi 1) using 1 · rw [← integral_mul_left] - refine setIntegral_congr measurableSet_Ioi fun x hx => ?_ + refine setIntegral_congr_fun measurableSet_Ioi fun x hx => ?_ dsimp only have : (x ^ (2 : ℝ)) ^ (1 / (2 : ℝ) - 1) = x⁻¹ := by rw [← rpow_mul (le_of_lt hx)] diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean index 8347a8e9d6908..d543c9e1d418b 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean @@ -29,8 +29,6 @@ noncomputable section section GaussianPoisson -variable {E : Type*} [NormedAddCommGroup E] - /-! First we show that Gaussian-type functions have rapid decay along `cocompact ℝ`. -/ lemma rexp_neg_quadratic_isLittleO_rpow_atTop {a : ℝ} (ha : a < 0) (b s : ℝ) : diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index 31f51791cdb31..f1b7032f2b0b7 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -43,7 +43,7 @@ namespace intervalIntegral open MeasureTheory -variable {f : ℝ → ℝ} {μ ν : Measure ℝ} [IsLocallyFiniteMeasure μ] (c d : ℝ) +variable {f : ℝ → ℝ} {μ : Measure ℝ} [IsLocallyFiniteMeasure μ] (c d : ℝ) /-! ### Interval integrability -/ @@ -115,7 +115,7 @@ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, IntervalIntegrable (fun x : ℝ => (x : ℂ) ^ r) μ a b := by by_cases h2 : (0 : ℝ) ∉ [[a, b]] · -- Easy case #1: 0 ∉ [a, b] -- use continuity. - refine (ContinuousAt.continuousOn fun x hx => ?_).intervalIntegrable + refine (continuousOn_of_forall_continuousAt fun x hx => ?_).intervalIntegrable exact Complex.continuousAt_ofReal_cpow_const _ _ (Or.inr <| ne_of_mem_of_not_mem hx h2) rw [eq_false h2, or_false] at h rcases lt_or_eq_of_le h with (h' | h') @@ -124,7 +124,7 @@ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, -- Now the hard case: re r = 0 and 0 is in the interval. refine (IntervalIntegrable.intervalIntegrable_norm_iff ?_).mp ?_ · refine (measurable_of_continuousOn_compl_singleton (0 : ℝ) ?_).aestronglyMeasurable - exact ContinuousAt.continuousOn fun x hx => + exact continuousOn_of_forall_continuousAt fun x hx => Complex.continuousAt_ofReal_cpow_const x r (Or.inr hx) -- reduce to case of integral over `[0, c]` suffices ∀ c : ℝ, IntervalIntegrable (fun x : ℝ => ‖(x : ℂ) ^ r‖) μ 0 c from @@ -175,7 +175,7 @@ theorem intervalIntegrable_cpow' {r : ℂ} (h : -1 < r.re) : rw [Complex.norm_eq_abs, Complex.abs_cpow_eq_rpow_re_of_pos hx.1] · exact measurableSet_uIoc · refine ContinuousOn.aestronglyMeasurable ?_ measurableSet_uIoc - refine ContinuousAt.continuousOn fun x hx => ?_ + refine continuousOn_of_forall_continuousAt fun x hx => ?_ rw [uIoc_of_le hc] at hx refine (continuousAt_cpow_const (Or.inl ?_)).comp Complex.continuous_ofReal.continuousAt rw [Complex.ofReal_re] @@ -206,7 +206,6 @@ theorem integrableOn_Ioo_cpow_iff {s : ℂ} {t : ℝ} (ht : 0 < t) : theorem intervalIntegrable_id : IntervalIntegrable (fun x => x) μ a b := continuous_id.intervalIntegrable a b --- @[simp] -- Porting note (#10618): simp can prove this theorem intervalIntegrable_const : IntervalIntegrable (fun _ => c) μ a b := continuous_const.intervalIntegrable a b @@ -409,7 +408,6 @@ theorem integral_id : ∫ x in a..b, x = (b ^ 2 - a ^ 2) / 2 := by norm_num at this exact this --- @[simp] -- Porting note (#10618): simp can prove this theorem integral_one : (∫ _ in a..b, (1 : ℝ)) = b - a := by simp only [mul_one, smul_eq_mul, integral_const] diff --git a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean index 5b9cbab201ab2..52481419b2ca5 100644 --- a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean +++ b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean @@ -126,7 +126,7 @@ theorem finite_integral_one_add_norm {r : ℝ} (hnr : (finrank ℝ E : ℝ) < r) -- The integral over the constant zero function is finite: rw [setLIntegral_congr_fun measurableSet_Ioi (ae_of_all volume <| h_int''), lintegral_const 0, zero_mul] - exact WithTop.zero_lt_top + exact WithTop.top_pos theorem integrable_one_add_norm {r : ℝ} (hnr : (finrank ℝ E : ℝ) < r) : Integrable (fun x ↦ (1 + ‖x‖) ^ (-r)) μ := by diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index c5f7769a08f9d..ccc7141a90155 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -301,7 +301,7 @@ theorem abs_log_mul_self_lt (x : ℝ) (h1 : 0 < x) (h2 : x ≤ 1) : |log x * x| refine mul_nonneg ?_ h1.le rw [← log_inv] apply log_nonneg - rw [← le_inv h1 zero_lt_one, inv_one] + rw [← le_inv_comm₀ h1 zero_lt_one, inv_one] exact h2 rw [← abs_of_nonneg aux, neg_mul, abs_neg] at this exact this diff --git a/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLogExp.lean b/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLogExp.lean index 27f458ecd81d8..187db68d382a6 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLogExp.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLogExp.lean @@ -12,7 +12,7 @@ import Mathlib.Topology.MetricSpace.Polish # Properties of the extended logarithm and exponential We prove that `log` and `exp` define order isomorphisms between `ℝ≥0∞` and `EReal`. -## Main Definitions +## Main DefinitionsP - `ENNReal.logOrderIso`: The order isomorphism between `ℝ≥0∞` and `EReal` defined by `log` and `exp`. - `EReal.expOrderIso`: The order isomorphism between `EReal` and `ℝ≥0∞` defined by `exp` @@ -134,6 +134,4 @@ end Measurability end ENNReal -instance : PolishSpace EReal := - ClosedEmbedding.polishSpace ⟨ENNReal.logOrderIso.symm.toHomeomorph.embedding, - ENNReal.logOrderIso.symm.toHomeomorph.range_coe ▸ isClosed_univ⟩ +instance : PolishSpace EReal := ENNReal.logOrderIso.symm.toHomeomorph.isClosedEmbedding.polishSpace diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean index c7eaabb0c3580..5aa71529e87e1 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean @@ -25,8 +25,6 @@ noncomputable section namespace Real -variable {x y : ℝ} - theorem log_mul_self_monotoneOn : MonotoneOn (fun x : ℝ => log x * x) { x | 1 ≤ x } := by -- TODO: can be strengthened to exp (-1) ≤ x simp only [MonotoneOn, mem_setOf_eq] diff --git a/Mathlib/Analysis/SpecialFunctions/OrdinaryHypergeometric.lean b/Mathlib/Analysis/SpecialFunctions/OrdinaryHypergeometric.lean new file mode 100644 index 0000000000000..bbbd460e9abe3 --- /dev/null +++ b/Mathlib/Analysis/SpecialFunctions/OrdinaryHypergeometric.lean @@ -0,0 +1,209 @@ +/- +Copyright (c) 2024 Edward Watine. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Edward Watine +-/ +import Mathlib.Analysis.Analytic.OfScalars +import Mathlib.Analysis.SpecificLimits.RCLike + +/-! +# Ordinary hypergeometric function in a Banach algebra + +In this file, we define `ordinaryHypergeometric`, the _ordinary_ or _Gaussian_ hypergeometric +function in a topological algebra `𝔸` over a field `𝕂` given by: $$ +_2\mathrm{F}_1(a\ b\ c : \mathbb{K}, x : \mathbb{A}) = \sum_{n=0}^{\infty}\frac{(a)_n(b)_n}{(c)_n} +\frac{x^n}{n!} \,, +$$ +with $(a)_n$ is the ascending Pochhammer symbol (see `ascPochhammer`). + +This file contains the basic definitions over a general field `𝕂` and notation for `₂F₁`, +as well as showing that terms of the series are zero if any of the `(a b c : 𝕂)` are sufficiently +large non-positive integers, rendering the series finite. In this file "sufficiently large" means +that `-n < a` for the `n`-th term, and similarly for `b` and `c`. + +- `ordinaryHypergeometricSeries` is the `FormalMultilinearSeries` given above for some `(a b c : 𝕂)` +- `ordinaryHypergeometric` is the sum of the series for some `(x : 𝔸)` +- `ordinaryHypergeometricSeries_eq_zero_of_nonpos_int` shows that the `n`-th term of the series is +zero if any of the parameters are sufficiently large non-positive integers + +## `[RCLike 𝕂]` + +If we have `[RCLike 𝕂]`, then we show that the latter result is an iff, and hence prove that the +radius of convergence of the series is unity if the series is infinite, or `⊤` otherwise. + +- `ordinaryHypergeometricSeries_eq_zero_iff` is iff variant of +`ordinaryHypergeometricSeries_eq_zero_of_nonpos_int` +- `ordinaryHypergeometricSeries_radius_eq_one` proves that the radius of convergence of the +`ordinaryHypergeometricSeries` is unity under non-trivial parameters + +## Notation + +`₂F₁` is notation for `ordinaryHypergeometric`. + +## References + +See . + +## Tags + +hypergeometric, gaussian, ordinary +-/ + +open Nat FormalMultilinearSeries + +section Field + +variable {𝕂 : Type*} (𝔸 : Type*) [Field 𝕂] [Ring 𝔸] [Algebra 𝕂 𝔸] [TopologicalSpace 𝔸] + [TopologicalRing 𝔸] + +/-- The coefficients in the ordinary hypergeometric sum. -/ +noncomputable abbrev ordinaryHypergeometricCoefficient (a b c : 𝕂) (n : ℕ) := ((n !⁻¹ : 𝕂) * + (ascPochhammer 𝕂 n).eval a * (ascPochhammer 𝕂 n).eval b * ((ascPochhammer 𝕂 n).eval c)⁻¹) + +/-- `ordinaryHypergeometricSeries 𝔸 (a b c : 𝕂)` is a `FormalMultilinearSeries`. +Its sum is the `ordinaryHypergeometric` map. -/ +noncomputable def ordinaryHypergeometricSeries (a b c : 𝕂) : FormalMultilinearSeries 𝕂 𝔸 𝔸 := + ofScalars 𝔸 (ordinaryHypergeometricCoefficient a b c) + +variable {𝔸} (a b c : 𝕂) + +/-- `ordinaryHypergeometric (a b c : 𝕂) : 𝔸 → 𝔸` is the ordinary hypergeometric map, defined as the +sum of the `FormalMultilinearSeries` `ordinaryHypergeometricSeries 𝔸 a b c`. + +Note that this takes the junk value `0` outside the radius of convergence. +-/ +noncomputable def ordinaryHypergeometric (x : 𝔸) : 𝔸 := + (ordinaryHypergeometricSeries 𝔸 a b c).sum x + +@[inherit_doc] +notation "₂F₁" => ordinaryHypergeometric + +theorem ordinaryHypergeometricSeries_apply_eq (x : 𝔸) (n : ℕ) : + (ordinaryHypergeometricSeries 𝔸 a b c n fun _ => x) = + ((n !⁻¹ : 𝕂) * (ascPochhammer 𝕂 n).eval a * (ascPochhammer 𝕂 n).eval b * + ((ascPochhammer 𝕂 n).eval c)⁻¹ ) • x ^ n := by + rw [ordinaryHypergeometricSeries, ofScalars_apply_eq] + +/-- This naming follows the convention of `NormedSpace.expSeries_apply_eq'`. -/ +theorem ordinaryHypergeometricSeries_apply_eq' (x : 𝔸) : + (fun n => ordinaryHypergeometricSeries 𝔸 a b c n fun _ => x) = + fun n => ((n !⁻¹ : 𝕂) * (ascPochhammer 𝕂 n).eval a * (ascPochhammer 𝕂 n).eval b * + ((ascPochhammer 𝕂 n).eval c)⁻¹ ) • x ^ n := by + rw [ordinaryHypergeometricSeries, ofScalars_apply_eq'] + +theorem ordinaryHypergeometric_sum_eq (x : 𝔸) : (ordinaryHypergeometricSeries 𝔸 a b c).sum x = + ∑' n : ℕ, ((n !⁻¹ : 𝕂) * (ascPochhammer 𝕂 n).eval a * (ascPochhammer 𝕂 n).eval b * + ((ascPochhammer 𝕂 n).eval c)⁻¹ ) • x ^ n := + tsum_congr fun n => ordinaryHypergeometricSeries_apply_eq a b c x n + +theorem ordinaryHypergeometric_eq_tsum : ₂F₁ a b c = + fun (x : 𝔸) => ∑' n : ℕ, ((n !⁻¹ : 𝕂) * (ascPochhammer 𝕂 n).eval a * + (ascPochhammer 𝕂 n).eval b * ((ascPochhammer 𝕂 n).eval c)⁻¹ ) • x ^ n := + funext (ordinaryHypergeometric_sum_eq a b c) + +theorem ordinaryHypergeometricSeries_apply_zero (n : ℕ) : + (ordinaryHypergeometricSeries 𝔸 a b c n fun _ => 0) = Pi.single (f := fun _ => 𝔸) 0 1 n := by + rw [ordinaryHypergeometricSeries, ofScalars_apply_eq, ordinaryHypergeometricCoefficient] + cases n <;> simp + +@[simp] +theorem ordinaryHypergeometric_zero : ₂F₁ a b c (0 : 𝔸) = 1 := by + simp [ordinaryHypergeometric_eq_tsum, ← ordinaryHypergeometricSeries_apply_eq, + ordinaryHypergeometricSeries_apply_zero] + +theorem ordinaryHypergeometricSeries_symm : + ordinaryHypergeometricSeries 𝔸 a b c = ordinaryHypergeometricSeries 𝔸 b a c := by + unfold ordinaryHypergeometricSeries ordinaryHypergeometricCoefficient + simp [mul_assoc, mul_left_comm] + +/-- If any parameter to the series is a sufficiently large nonpositive integer, then the series +term is zero. -/ +lemma ordinaryHypergeometricSeries_eq_zero_of_neg_nat {n k : ℕ} (habc : k = -a ∨ k = -b ∨ k = -c) + (hk : k < n) : ordinaryHypergeometricSeries 𝔸 a b c n = 0 := by + rw [ordinaryHypergeometricSeries, ofScalars] + rcases habc with h | h | h + all_goals + ext + simp [(ascPochhammer_eval_eq_zero_iff n _).2 ⟨k, hk, h⟩] + +end Field + +section RCLike + +open Asymptotics Filter Real Set Nat + +open scoped Topology + +variable {𝕂 : Type*} (𝔸 : Type*) [RCLike 𝕂] [NormedDivisionRing 𝔸] [NormedAlgebra 𝕂 𝔸] + (a b c : 𝕂) + +theorem ordinaryHypergeometric_radius_top_of_neg_nat₁ {k : ℕ} : + (ordinaryHypergeometricSeries 𝔸 (-(k : 𝕂)) b c).radius = ⊤ := by + refine FormalMultilinearSeries.radius_eq_top_of_forall_image_add_eq_zero _ (1 + k) fun n ↦ ?_ + exact ordinaryHypergeometricSeries_eq_zero_of_neg_nat (-(k : 𝕂)) b c (by aesop) (by omega) + +theorem ordinaryHypergeometric_radius_top_of_neg_nat₂ {k : ℕ} : + (ordinaryHypergeometricSeries 𝔸 a (-(k : 𝕂)) c).radius = ⊤ := by + rw [ordinaryHypergeometricSeries_symm] + exact ordinaryHypergeometric_radius_top_of_neg_nat₁ 𝔸 a c + +theorem ordinaryHypergeometric_radius_top_of_neg_nat₃ {k : ℕ} : + (ordinaryHypergeometricSeries 𝔸 a b (-(k : 𝕂))).radius = ⊤ := by + refine FormalMultilinearSeries.radius_eq_top_of_forall_image_add_eq_zero _ (1 + k) fun n ↦ ?_ + exact ordinaryHypergeometricSeries_eq_zero_of_neg_nat a b (-(k : 𝕂)) (by aesop) (by omega) + +/-- An iff variation on `ordinaryHypergeometricSeries_eq_zero_of_nonpos_int` for `[RCLike 𝕂]`. -/ +lemma ordinaryHypergeometricSeries_eq_zero_iff (n : ℕ) : + ordinaryHypergeometricSeries 𝔸 a b c n = 0 ↔ ∃ k < n, k = -a ∨ k = -b ∨ k = -c := by + refine ⟨fun h ↦ ?_, fun zero ↦ ?_⟩ + · rw [ordinaryHypergeometricSeries, ofScalars_eq_zero] at h + simp only [_root_.mul_eq_zero, inv_eq_zero] at h + rcases h with ((hn | h) | h) | h + · simp [Nat.factorial_ne_zero] at hn + all_goals + obtain ⟨kn, hkn, hn⟩ := (ascPochhammer_eval_eq_zero_iff _ _).1 h + exact ⟨kn, hkn, by tauto⟩ + · obtain ⟨_, h, hn⟩ := zero + exact ordinaryHypergeometricSeries_eq_zero_of_neg_nat a b c hn h + +theorem ordinaryHypergeometricSeries_norm_div_succ_norm (n : ℕ) + (habc : ∀ kn < n, (↑kn ≠ -a ∧ ↑kn ≠ -b ∧ ↑kn ≠ -c)) : + ‖ordinaryHypergeometricCoefficient a b c n‖ / ‖ordinaryHypergeometricCoefficient a b c n.succ‖ + = ‖a + n‖⁻¹ * ‖b + n‖⁻¹ * ‖c + n‖ * ‖1 + (n : 𝕂)‖ := by + simp only [mul_inv_rev, factorial_succ, cast_mul, cast_add, + cast_one, ascPochhammer_succ_eval, norm_mul, norm_inv] + calc + _ = ‖Polynomial.eval a (ascPochhammer 𝕂 n)‖ * ‖Polynomial.eval a (ascPochhammer 𝕂 n)‖⁻¹ * + ‖Polynomial.eval b (ascPochhammer 𝕂 n)‖ * ‖Polynomial.eval b (ascPochhammer 𝕂 n)‖⁻¹ * + ‖Polynomial.eval c (ascPochhammer 𝕂 n)‖⁻¹⁻¹ * ‖Polynomial.eval c (ascPochhammer 𝕂 n)‖⁻¹ * + ‖(n ! : 𝕂)‖⁻¹⁻¹ * ‖(n ! : 𝕂)‖⁻¹ * ‖a + n‖⁻¹ * ‖b + n‖⁻¹ * ‖c + n‖⁻¹⁻¹ * + ‖1 + (n : 𝕂)‖⁻¹⁻¹ := by ring_nf + _ = _ := by + simp only [inv_inv] + repeat rw [DivisionRing.mul_inv_cancel, one_mul] + all_goals + rw [norm_ne_zero_iff] + any_goals + apply (ascPochhammer_eval_eq_zero_iff n _).not.2 + push_neg + exact fun kn hkn ↦ by simp [habc kn hkn] + exact cast_ne_zero.2 (factorial_ne_zero n) + +/-- The radius of convergence of `ordinaryHypergeometricSeries` is unity if none of the parameters +are non-positive integers. -/ +theorem ordinaryHypergeometricSeries_radius_eq_one + (habc : ∀ kn : ℕ, ↑kn ≠ -a ∧ ↑kn ≠ -b ∧ ↑kn ≠ -c) : + (ordinaryHypergeometricSeries 𝔸 a b c).radius = 1 := by + convert ofScalars_radius_eq_of_tendsto 𝔸 _ one_ne_zero ?_ + suffices Tendsto (fun k : ℕ ↦ (a + k)⁻¹ * (b + k)⁻¹ * (c + k) * ((1 : 𝕂) + k)) atTop (𝓝 1) by + simp_rw [ordinaryHypergeometricSeries_norm_div_succ_norm a b c _ (fun n _ ↦ habc n)] + simp [← norm_mul, ← norm_inv] + convert Filter.Tendsto.norm this + exact norm_one.symm + have (k : ℕ) : (a + k)⁻¹ * (b + k)⁻¹ * (c + k) * ((1 : 𝕂) + k) = + (c + k) / (a + k) * ((1 + k) / (b + k)) := by field_simp + simp_rw [this] + apply (mul_one (1 : 𝕂)) ▸ Filter.Tendsto.mul <;> + convert RCLike.tendsto_add_mul_div_add_mul_atTop_nhds _ _ (1 : 𝕂) one_ne_zero <;> simp + +end RCLike diff --git a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean index 62dafde2c1433..46513cef6be86 100644 --- a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean +++ b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean @@ -135,13 +135,13 @@ theorem integral_comp_polarCoord_symm {E : Type*} [NormedAddCommGroup E] [Normed symm calc ∫ p, f p = ∫ p in polarCoord.source, f p := by - rw [← integral_univ] - apply setIntegral_congr_set_ae + rw [← setIntegral_univ] + apply setIntegral_congr_set exact polarCoord_source_ae_eq_univ.symm _ = ∫ p in polarCoord.target, abs (B p).det • f (polarCoord.symm p) := by apply integral_target_eq_integral_abs_det_fderiv_smul volume A _ = ∫ p in polarCoord.target, p.1 • f (polarCoord.symm p) := by - apply setIntegral_congr polarCoord.open_target.measurableSet fun x hx => ?_ + apply setIntegral_congr_fun polarCoord.open_target.measurableSet fun x hx => ?_ rw [B_det, abs_of_pos] exact hx.1 diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean index 95944cd30ee97..46b43a71b54e1 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean @@ -190,7 +190,7 @@ theorem isTheta_exp_arg_mul_im (hl : IsBoundedUnder (· ≤ ·) l fun x => |(g x refine Real.isTheta_exp_comp_one.2 ⟨π * b, ?_⟩ rw [eventually_map] at hb ⊢ refine hb.mono fun x hx => ?_ - erw [abs_mul] + rw [abs_mul] exact mul_le_mul (abs_arg_le_pi _) hx (abs_nonneg _) Real.pi_pos.le theorem isBigO_cpow_rpow (hl : IsBoundedUnder (· ≤ ·) l fun x => |(g x).im|) : @@ -198,7 +198,7 @@ theorem isBigO_cpow_rpow (hl : IsBoundedUnder (· ≤ ·) l fun x => |(g x).im|) calc (fun x => f x ^ g x) =O[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re / Real.exp (arg (f x) * im (g x))) := - isBigO_of_le _ fun x => (abs_cpow_le _ _).trans (le_abs_self _) + isBigO_of_le _ fun _ => (abs_cpow_le _ _).trans (le_abs_self _) _ =Θ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re / (1 : ℝ)) := ((isTheta_refl _ _).div (isTheta_exp_arg_mul_im hl)) _ =ᶠ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re) := by @@ -211,7 +211,7 @@ theorem isTheta_cpow_rpow (hl_im : IsBoundedUnder (· ≤ ·) l fun x => |(g x). calc (fun x => f x ^ g x) =Θ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re / Real.exp (arg (f x) * im (g x))) := - isTheta_of_norm_eventuallyEq' <| hl.mono fun x => abs_cpow_of_imp + isTheta_of_norm_eventuallyEq' <| hl.mono fun _ => abs_cpow_of_imp _ =Θ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re / (1 : ℝ)) := ((isTheta_refl _ _).div (isTheta_exp_arg_mul_im hl_im)) _ =ᶠ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re) := by @@ -282,7 +282,7 @@ open Asymptotics /-- `x ^ s = o(exp(b * x))` as `x → ∞` for any real `s` and positive `b`. -/ theorem isLittleO_rpow_exp_pos_mul_atTop (s : ℝ) {b : ℝ} (hb : 0 < b) : (fun x : ℝ => x ^ s) =o[atTop] fun x => exp (b * x) := - isLittleO_of_tendsto (fun x h => absurd h (exp_pos _).ne') <| by + isLittleO_of_tendsto (fun _ h => absurd h (exp_pos _).ne') <| by simpa only [div_eq_mul_inv, exp_neg, neg_mul] using tendsto_rpow_mul_exp_neg_mul_atTop_nhds_zero s b hb diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean index 841d4fc4de757..e0046de2ae680 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean @@ -136,6 +136,10 @@ theorem ContinuousOn.cpow_const {b : ℂ} (hf : ContinuousOn f s) (h : ∀ a : α, a ∈ s → f a ∈ slitPlane) : ContinuousOn (fun x => f x ^ b) s := hf.cpow continuousOn_const h +@[fun_prop] +lemma continuous_const_cpow (z : ℂ) [NeZero z] : Continuous fun s : ℂ ↦ z ^ s := + continuous_id.const_cpow (.inl <| NeZero.ne z) + end CpowLimits section RpowLimits diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean index 02967ef06b371..7d78453430c3a 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean @@ -130,6 +130,16 @@ theorem Differentiable.const_cpow (hf : Differentiable ℂ f) (h0 : c ≠ 0 ∨ ∀ x, f x ≠ 0) : Differentiable ℂ (fun x ↦ c ^ f x) := fun x ↦ (hf x).const_cpow (h0.imp_right fun h ↦ h x) +@[fun_prop] +lemma differentiable_const_cpow_of_neZero (z : ℂ) [NeZero z] : + Differentiable ℂ fun s : ℂ ↦ z ^ s := + differentiable_id.const_cpow (.inl <| NeZero.ne z) + +@[fun_prop] +lemma differentiableAt_const_cpow_of_neZero (z : ℂ) [NeZero z] (t : ℂ) : + DifferentiableAt ℂ (fun s : ℂ ↦ z ^ s) t := + differentiableAt_id.const_cpow (.inl <| NeZero.ne z) + end fderiv section deriv diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean index d2306464d57ff..acdcc41b5be97 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean @@ -79,7 +79,7 @@ theorem one_rpow (x : ℝ) : (1 : ℝ≥0) ^ x = 1 := NNReal.eq <| Real.one_rpow _ theorem rpow_add {x : ℝ≥0} (hx : x ≠ 0) (y z : ℝ) : x ^ (y + z) = x ^ y * x ^ z := - NNReal.eq <| Real.rpow_add (pos_iff_ne_zero.2 hx) _ _ + NNReal.eq <| Real.rpow_add ((NNReal.coe_pos.trans pos_iff_ne_zero).mpr hx) _ _ theorem rpow_add' (h : y + z ≠ 0) (x : ℝ≥0) : x ^ (y + z) = x ^ y * x ^ z := NNReal.eq <| Real.rpow_add' x.2 h @@ -146,7 +146,7 @@ lemma rpow_mul_intCast (x : ℝ≥0) (y : ℝ) (n : ℤ) : x ^ (y * n) = (x ^ y) theorem rpow_neg_one (x : ℝ≥0) : x ^ (-1 : ℝ) = x⁻¹ := by simp [rpow_neg] theorem rpow_sub {x : ℝ≥0} (hx : x ≠ 0) (y z : ℝ) : x ^ (y - z) = x ^ y / x ^ z := - NNReal.eq <| Real.rpow_sub (pos_iff_ne_zero.2 hx) y z + NNReal.eq <| Real.rpow_sub ((NNReal.coe_pos.trans pos_iff_ne_zero).mpr hx) y z theorem rpow_sub' (h : y - z ≠ 0) (x : ℝ≥0) : x ^ (y - z) = x ^ y / x ^ z := NNReal.eq <| Real.rpow_sub' x.2 h diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean index 80400c08a6e5d..a2e922b310ba9 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean @@ -528,13 +528,13 @@ theorem monotoneOn_rpow_Ici_of_exponent_nonneg {r : ℝ} (hr : 0 ≤ r) : lemma rpow_lt_rpow_of_neg (hx : 0 < x) (hxy : x < y) (hz : z < 0) : y ^ z < x ^ z := by have := hx.trans hxy - rw [← inv_lt_inv, ← rpow_neg, ← rpow_neg] + rw [← inv_lt_inv₀, ← rpow_neg, ← rpow_neg] on_goal 1 => refine rpow_lt_rpow ?_ hxy (neg_pos.2 hz) all_goals positivity lemma rpow_le_rpow_of_nonpos (hx : 0 < x) (hxy : x ≤ y) (hz : z ≤ 0) : y ^ z ≤ x ^ z := by have := hx.trans_le hxy - rw [← inv_le_inv, ← rpow_neg, ← rpow_neg] + rw [← inv_le_inv₀, ← rpow_neg, ← rpow_neg] on_goal 1 => refine rpow_le_rpow ?_ hxy (neg_nonneg.2 hz) all_goals positivity @@ -592,7 +592,7 @@ theorem rpow_lt_rpow_of_exponent_neg {x y z : ℝ} (hy : 0 < y) (hxy : y < x) (h x ^ z < y ^ z := by have hx : 0 < x := hy.trans hxy rw [← neg_neg z, Real.rpow_neg (le_of_lt hx) (-z), Real.rpow_neg (le_of_lt hy) (-z), - inv_lt_inv (rpow_pos_of_pos hx _) (rpow_pos_of_pos hy _)] + inv_lt_inv₀ (rpow_pos_of_pos hx _) (rpow_pos_of_pos hy _)] exact Real.rpow_lt_rpow (by positivity) hxy <| neg_pos_of_neg hz theorem strictAntiOn_rpow_Ioi_of_exponent_neg {r : ℝ} (hr : r < 0) : @@ -997,6 +997,13 @@ lemma abs_cpow_inv_two_im (x : ℂ) : |(x ^ (2⁻¹ : ℂ)).im| = sqrt ((abs x - ← Real.sqrt_eq_rpow, _root_.abs_mul, _root_.abs_of_nonneg (sqrt_nonneg _), abs_sin_half, ← sqrt_mul (abs.nonneg _), ← mul_div_assoc, mul_sub, mul_one, abs_mul_cos_arg] +open scoped ComplexOrder in +lemma inv_natCast_cpow_ofReal_pos {n : ℕ} (hn : n ≠ 0) (x : ℝ) : + 0 < ((n : ℂ) ^ (x : ℂ))⁻¹ := by + refine RCLike.inv_pos_of_pos ?_ + rw [show (n : ℂ) ^ (x : ℂ) = (n : ℝ) ^ (x : ℂ) from rfl, ← ofReal_cpow n.cast_nonneg'] + positivity + end Complex section Tactics @@ -1040,6 +1047,14 @@ theorem isRat_rpow_neg {a b : ℝ} {nb : ℕ} IsRat (a ^ b) num den := by rwa [pb.out, Real.rpow_intCast] +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + /-- Evaluates expressions of the form `a ^ b` when `a` and `b` are both reals. -/ @[norm_num (_ : ℝ) ^ (_ : ℝ)] def evalRPow : NormNumExt where eval {u α} e := do diff --git a/Mathlib/Analysis/SpecialFunctions/Stirling.lean b/Mathlib/Analysis/SpecialFunctions/Stirling.lean index a1b4c1c5dd12d..35d9ac4c47d5b 100644 --- a/Mathlib/Analysis/SpecialFunctions/Stirling.lean +++ b/Mathlib/Analysis/SpecialFunctions/Stirling.lean @@ -102,12 +102,12 @@ theorem log_stirlingSeq_diff_le_geo_sum (n : ℕ) : · simp_rw [← _root_.pow_succ'] at this exact this rw [one_div, inv_pow] - exact inv_lt_one (one_lt_pow₀ ((lt_add_iff_pos_left 1).mpr <| by positivity) two_ne_zero) + exact inv_lt_one_of_one_lt₀ (one_lt_pow₀ (lt_add_of_pos_left _ <| by positivity) two_ne_zero) have hab (k : ℕ) : (1 : ℝ) / (2 * ↑(k + 1) + 1) * ((1 / (2 * ↑(n + 1) + 1)) ^ 2) ^ ↑(k + 1) ≤ (((1 : ℝ) / (2 * ↑(n + 1) + 1)) ^ 2) ^ ↑(k + 1) := by refine mul_le_of_le_one_left (pow_nonneg h_nonneg ↑(k + 1)) ?_ rw [one_div] - exact inv_le_one (le_add_of_nonneg_left <| by positivity) + exact inv_le_one_of_one_le₀ (le_add_of_nonneg_left <| by positivity) exact hasSum_le hab (log_stirlingSeq_diff_hasSum n) g /-- We have the bound `log (stirlingSeq n) - log (stirlingSeq (n+1))` ≤ 1/(4 n^2) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean index c5ed691712471..37eff150ed843 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean @@ -127,11 +127,9 @@ theorem two_nsmul_coe_div_two (θ : ℝ) : (2 : ℕ) • (↑(θ / 2) : Angle) = theorem two_zsmul_coe_div_two (θ : ℝ) : (2 : ℤ) • (↑(θ / 2) : Angle) = θ := by rw [← coe_zsmul, two_zsmul, add_halves] --- Porting note (#10618): @[simp] can prove it theorem two_nsmul_neg_pi_div_two : (2 : ℕ) • (↑(-π / 2) : Angle) = π := by rw [two_nsmul_coe_div_two, coe_neg, neg_coe_pi] --- Porting note (#10618): @[simp] can prove it theorem two_zsmul_neg_pi_div_two : (2 : ℤ) • (↑(-π / 2) : Angle) = π := by rw [two_zsmul, ← two_nsmul, two_nsmul_neg_pi_div_two] @@ -303,7 +301,6 @@ theorem sin_eq_iff_eq_or_add_eq_pi {θ ψ : Angle} : sin θ = sin ψ ↔ θ = ψ @[simp] theorem sin_zero : sin (0 : Angle) = 0 := by rw [← coe_zero, sin_coe, Real.sin_zero] --- Porting note (#10618): @[simp] can prove it theorem sin_coe_pi : sin (π : Angle) = 0 := by rw [sin_coe, Real.sin_pi] theorem sin_eq_zero_iff {θ : Angle} : sin θ = 0 ↔ θ = 0 ∨ θ = π := by @@ -335,7 +332,6 @@ theorem sin_sub_pi (θ : Angle) : sin (θ - π) = -sin θ := @[simp] theorem cos_zero : cos (0 : Angle) = 1 := by rw [← coe_zero, cos_coe, Real.cos_zero] --- Porting note (#10618): @[simp] can prove it theorem cos_coe_pi : cos (π : Angle) = -1 := by rw [cos_coe, Real.cos_pi] @[simp] @@ -658,7 +654,6 @@ theorem tan_coe (x : ℝ) : tan (x : Angle) = Real.tan x := by @[simp] theorem tan_zero : tan (0 : Angle) = 0 := by rw [← coe_zero, tan_coe, Real.tan_zero] --- Porting note (#10618): @[simp] can now prove it theorem tan_coe_pi : tan (π : Angle) = 0 := by rw [tan_coe, Real.tan_pi] theorem tan_periodic : Function.Periodic tan (π : Angle) := by @@ -877,7 +872,7 @@ theorem continuousAt_sign {θ : Angle} (h0 : θ ≠ 0) (hpi : θ ≠ π) : Conti theorem _root_.ContinuousOn.angle_sign_comp {α : Type*} [TopologicalSpace α] {f : α → Angle} {s : Set α} (hf : ContinuousOn f s) (hs : ∀ z ∈ s, f z ≠ 0 ∧ f z ≠ π) : ContinuousOn (sign ∘ f) s := by - refine (ContinuousAt.continuousOn fun θ hθ => ?_).comp hf (Set.mapsTo_image f s) + refine (continuousOn_of_forall_continuousAt fun θ hθ => ?_).comp hf (Set.mapsTo_image f s) obtain ⟨z, hz, rfl⟩ := hθ exact continuousAt_sign (hs _ hz).1 (hs _ hz).2 diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean index ee71f3e92b789..6919f9dcbb728 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean @@ -228,7 +228,7 @@ theorem arctan_add_eq_add_pi {x y : ℝ} (h : 1 < x * y) (hx : 0 < x) : have hy : 0 < y := by have := mul_pos_iff.mp (zero_lt_one.trans h) simpa [hx, hx.asymm] - have k := arctan_add (mul_inv x y ▸ inv_lt_one h) + have k := arctan_add (mul_inv x y ▸ inv_lt_one_of_one_lt₀ h) rw [arctan_inv_of_pos hx, arctan_inv_of_pos hy, show _ + _ = π - (arctan x + arctan y) by ring, sub_eq_iff_eq_add, ← sub_eq_iff_eq_add', sub_eq_add_neg, ← arctan_neg, add_comm] at k convert k.symm using 3 diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean index ff16ee4d5471a..4c002f27c027e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean @@ -280,19 +280,19 @@ theorem sin_int_mul_two_pi_sub (x : ℝ) (n : ℤ) : sin (n * (2 * π) - x) = -s sin_neg x ▸ sin_periodic.int_mul_sub_eq n theorem sin_add_int_mul_pi (x : ℝ) (n : ℤ) : sin (x + n * π) = (-1) ^ n * sin x := - n.coe_negOnePow ℝ ▸ sin_antiperiodic.add_int_mul_eq n + n.cast_negOnePow ℝ ▸ sin_antiperiodic.add_int_mul_eq n theorem sin_add_nat_mul_pi (x : ℝ) (n : ℕ) : sin (x + n * π) = (-1) ^ n * sin x := sin_antiperiodic.add_nat_mul_eq n theorem sin_sub_int_mul_pi (x : ℝ) (n : ℤ) : sin (x - n * π) = (-1) ^ n * sin x := - n.coe_negOnePow ℝ ▸ sin_antiperiodic.sub_int_mul_eq n + n.cast_negOnePow ℝ ▸ sin_antiperiodic.sub_int_mul_eq n theorem sin_sub_nat_mul_pi (x : ℝ) (n : ℕ) : sin (x - n * π) = (-1) ^ n * sin x := sin_antiperiodic.sub_nat_mul_eq n theorem sin_int_mul_pi_sub (x : ℝ) (n : ℤ) : sin (n * π - x) = -((-1) ^ n * sin x) := by - simpa only [sin_neg, mul_neg, Int.coe_negOnePow] using sin_antiperiodic.int_mul_sub_eq n + simpa only [sin_neg, mul_neg, Int.cast_negOnePow] using sin_antiperiodic.int_mul_sub_eq n theorem sin_nat_mul_pi_sub (x : ℝ) (n : ℕ) : sin (n * π - x) = -((-1) ^ n * sin x) := by simpa only [sin_neg, mul_neg] using sin_antiperiodic.nat_mul_sub_eq n @@ -363,36 +363,32 @@ theorem cos_int_mul_two_pi_sub (x : ℝ) (n : ℤ) : cos (n * (2 * π) - x) = co cos_neg x ▸ cos_periodic.int_mul_sub_eq n theorem cos_add_int_mul_pi (x : ℝ) (n : ℤ) : cos (x + n * π) = (-1) ^ n * cos x := - n.coe_negOnePow ℝ ▸ cos_antiperiodic.add_int_mul_eq n + n.cast_negOnePow ℝ ▸ cos_antiperiodic.add_int_mul_eq n theorem cos_add_nat_mul_pi (x : ℝ) (n : ℕ) : cos (x + n * π) = (-1) ^ n * cos x := cos_antiperiodic.add_nat_mul_eq n theorem cos_sub_int_mul_pi (x : ℝ) (n : ℤ) : cos (x - n * π) = (-1) ^ n * cos x := - n.coe_negOnePow ℝ ▸ cos_antiperiodic.sub_int_mul_eq n + n.cast_negOnePow ℝ ▸ cos_antiperiodic.sub_int_mul_eq n theorem cos_sub_nat_mul_pi (x : ℝ) (n : ℕ) : cos (x - n * π) = (-1) ^ n * cos x := cos_antiperiodic.sub_nat_mul_eq n theorem cos_int_mul_pi_sub (x : ℝ) (n : ℤ) : cos (n * π - x) = (-1) ^ n * cos x := - n.coe_negOnePow ℝ ▸ cos_neg x ▸ cos_antiperiodic.int_mul_sub_eq n + n.cast_negOnePow ℝ ▸ cos_neg x ▸ cos_antiperiodic.int_mul_sub_eq n theorem cos_nat_mul_pi_sub (x : ℝ) (n : ℕ) : cos (n * π - x) = (-1) ^ n * cos x := cos_neg x ▸ cos_antiperiodic.nat_mul_sub_eq n --- Porting note (#10618): was @[simp], but simp can prove it theorem cos_nat_mul_two_pi_add_pi (n : ℕ) : cos (n * (2 * π) + π) = -1 := by simpa only [cos_zero] using (cos_periodic.nat_mul n).add_antiperiod_eq cos_antiperiodic --- Porting note (#10618): was @[simp], but simp can prove it theorem cos_int_mul_two_pi_add_pi (n : ℤ) : cos (n * (2 * π) + π) = -1 := by simpa only [cos_zero] using (cos_periodic.int_mul n).add_antiperiod_eq cos_antiperiodic --- Porting note (#10618): was @[simp], but simp can prove it theorem cos_nat_mul_two_pi_sub_pi (n : ℕ) : cos (n * (2 * π) - π) = -1 := by simpa only [cos_zero] using (cos_periodic.nat_mul n).sub_antiperiod_eq cos_antiperiodic --- Porting note (#10618): was @[simp], but simp can prove it theorem cos_int_mul_two_pi_sub_pi (n : ℤ) : cos (n * (2 * π) - π) = -1 := by simpa only [cos_zero] using (cos_periodic.int_mul n).sub_antiperiod_eq cos_antiperiodic @@ -502,7 +498,7 @@ theorem sin_eq_zero_iff {x : ℝ} : sin x = 0 ↔ ∃ n : ℤ, (n : ℝ) * π = le_of_not_gt fun h₃ => (sin_pos_of_pos_of_lt_pi h₃ (Int.sub_floor_div_mul_lt _ pi_pos)).ne (by simp [sub_eq_add_neg, sin_add, h, sin_int_mul_pi]))⟩, - fun ⟨n, hn⟩ => hn ▸ sin_int_mul_pi _⟩ + fun ⟨_, hn⟩ => hn ▸ sin_int_mul_pi _⟩ theorem sin_ne_zero_iff {x : ℝ} : sin x ≠ 0 ↔ ∀ n : ℤ, (n : ℝ) * π ≠ x := by rw [← not_exists, not_iff_not, sin_eq_zero_iff] @@ -524,7 +520,7 @@ theorem cos_eq_one_iff (x : ℝ) : cos x = 1 ↔ ∃ n : ℤ, (n : ℝ) * (2 * mul_comm (2 : ℤ), Int.cast_mul, mul_assoc, Int.cast_two] at hn rw [← hn, cos_int_mul_two_pi_add_pi] at h exact absurd h (by norm_num)⟩, - fun ⟨n, hn⟩ => hn ▸ cos_int_mul_two_pi _⟩ + fun ⟨_, hn⟩ => hn ▸ cos_int_mul_two_pi _⟩ theorem cos_eq_one_iff_of_lt_of_lt {x : ℝ} (hx₁ : -(2 * π) < x) (hx₂ : x < 2 * π) : cos x = 1 ↔ x = 0 := diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean index e8e17232197f1..f3a9858bddf37 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean @@ -192,7 +192,7 @@ theorem lt_tan {x : ℝ} (h1 : 0 < x) (h2 : x < π / 2) : x < tan x := by apply lt_of_le_of_ne y.cos_sq_le_one rw [cos_sq'] simpa only [Ne, sub_eq_self, sq_eq_zero_iff] using (sin_pos hy).ne' - rwa [lt_inv, inv_one] + rwa [lt_inv_comm₀, inv_one] · exact zero_lt_one simpa only [sq, mul_self_pos] using this.ne' have mono := strictMonoOn_of_deriv_pos (convex_Ico 0 (π / 2)) tan_minus_id_cts deriv_pos diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Cotangent.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Cotangent.lean index d9d5e56fb97ef..1db8bfb1259ff 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Cotangent.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Cotangent.lean @@ -11,9 +11,9 @@ import Mathlib.Analysis.Complex.UpperHalfPlane.Exp This file contains lemmas about the cotangent function, including useful series expansions. -/ -open Real Complex BigOperators Filter +open Real Complex -open scoped UpperHalfPlane Topology +open scoped UpperHalfPlane lemma Complex.cot_eq_exp_ratio (z : ℂ) : cot z = (Complex.exp (2 * I * z) + 1) / (I * (1 - Complex.exp (2 * I * z))) := by diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean index e11d7973f3b2c..862ffd739dff4 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean @@ -45,8 +45,10 @@ theorem contDiff_sin {n} : ContDiff ℂ n sin := (((contDiff_neg.mul contDiff_const).cexp.sub (contDiff_id.mul contDiff_const).cexp).mul contDiff_const).div_const _ +@[fun_prop] theorem differentiable_sin : Differentiable ℂ sin := fun x => (hasDerivAt_sin x).differentiableAt +@[fun_prop] theorem differentiableAt_sin {x : ℂ} : DifferentiableAt ℂ sin x := differentiable_sin x @@ -70,8 +72,10 @@ theorem hasDerivAt_cos (x : ℂ) : HasDerivAt cos (-sin x) x := theorem contDiff_cos {n} : ContDiff ℂ n cos := ((contDiff_id.mul contDiff_const).cexp.add (contDiff_neg.mul contDiff_const).cexp).div_const _ +@[fun_prop] theorem differentiable_cos : Differentiable ℂ cos := fun x => (hasDerivAt_cos x).differentiableAt +@[fun_prop] theorem differentiableAt_cos {x : ℂ} : DifferentiableAt ℂ cos x := differentiable_cos x @@ -98,8 +102,10 @@ theorem hasDerivAt_sinh (x : ℂ) : HasDerivAt sinh (cosh x) x := theorem contDiff_sinh {n} : ContDiff ℂ n sinh := (contDiff_exp.sub contDiff_neg.cexp).div_const _ +@[fun_prop] theorem differentiable_sinh : Differentiable ℂ sinh := fun x => (hasDerivAt_sinh x).differentiableAt +@[fun_prop] theorem differentiableAt_sinh {x : ℂ} : DifferentiableAt ℂ sinh x := differentiable_sinh x @@ -123,8 +129,10 @@ theorem hasDerivAt_cosh (x : ℂ) : HasDerivAt cosh (sinh x) x := theorem contDiff_cosh {n} : ContDiff ℂ n cosh := (contDiff_exp.add contDiff_neg.cexp).div_const _ +@[fun_prop] theorem differentiable_cosh : Differentiable ℂ cosh := fun x => (hasDerivAt_cosh x).differentiableAt +@[fun_prop] theorem differentiableAt_cosh {x : ℂ} : DifferentiableAt ℂ cosh x := differentiable_cosh x @@ -482,8 +490,10 @@ theorem hasDerivAt_sin (x : ℝ) : HasDerivAt sin (cos x) x := theorem contDiff_sin {n} : ContDiff ℝ n sin := Complex.contDiff_sin.real_of_complex +@[fun_prop] theorem differentiable_sin : Differentiable ℝ sin := fun x => (hasDerivAt_sin x).differentiableAt +@[fun_prop] theorem differentiableAt_sin : DifferentiableAt ℝ sin x := differentiable_sin x @@ -500,8 +510,10 @@ theorem hasDerivAt_cos (x : ℝ) : HasDerivAt cos (-sin x) x := theorem contDiff_cos {n} : ContDiff ℝ n cos := Complex.contDiff_cos.real_of_complex +@[fun_prop] theorem differentiable_cos : Differentiable ℝ cos := fun x => (hasDerivAt_cos x).differentiableAt +@[fun_prop] theorem differentiableAt_cos : DifferentiableAt ℝ cos x := differentiable_cos x @@ -521,8 +533,10 @@ theorem hasDerivAt_sinh (x : ℝ) : HasDerivAt sinh (cosh x) x := theorem contDiff_sinh {n} : ContDiff ℝ n sinh := Complex.contDiff_sinh.real_of_complex +@[fun_prop] theorem differentiable_sinh : Differentiable ℝ sinh := fun x => (hasDerivAt_sinh x).differentiableAt +@[fun_prop] theorem differentiableAt_sinh : DifferentiableAt ℝ sinh x := differentiable_sinh x @@ -539,8 +553,10 @@ theorem hasDerivAt_cosh (x : ℝ) : HasDerivAt cosh (sinh x) x := theorem contDiff_cosh {n} : ContDiff ℝ n cosh := Complex.contDiff_cosh.real_of_complex +@[fun_prop] theorem differentiable_cosh : Differentiable ℝ cosh := fun x => (hasDerivAt_cosh x).differentiableAt +@[fun_prop] theorem differentiableAt_cosh : DifferentiableAt ℝ cosh x := differentiable_cosh x diff --git a/Mathlib/Analysis/SpecificLimits/Basic.lean b/Mathlib/Analysis/SpecificLimits/Basic.lean index 22f9e6116a899..e06aef0a9c56a 100644 --- a/Mathlib/Analysis/SpecificLimits/Basic.lean +++ b/Mathlib/Analysis/SpecificLimits/Basic.lean @@ -114,6 +114,53 @@ theorem tendsto_natCast_div_add_atTop {𝕜 : Type*} [DivisionRing 𝕜] [Topolo intros simp_all only [comp_apply, map_inv₀, map_natCast] +/-- For any positive `m : ℕ`, `((n % m : ℕ) : ℝ) / (n : ℝ)` tends to `0` as `n` tends to `∞`. -/ +theorem tendsto_mod_div_atTop_nhds_zero_nat {m : ℕ} (hm : 0 < m) : + Tendsto (fun n : ℕ => ((n % m : ℕ) : ℝ) / (n : ℝ)) atTop (𝓝 0) := by + have h0 : ∀ᶠ n : ℕ in atTop, 0 ≤ (fun n : ℕ => ((n % m : ℕ) : ℝ)) n := by aesop + exact tendsto_bdd_div_atTop_nhds_zero h0 + (.of_forall (fun n ↦ cast_le.mpr (mod_lt n hm).le)) tendsto_natCast_atTop_atTop + +theorem Filter.EventuallyEq.div_mul_cancel {α G : Type*} [GroupWithZero G] {f g : α → G} + {l : Filter α} (hg : Tendsto g l (𝓟 {0}ᶜ)) : (fun x ↦ f x / g x * g x) =ᶠ[l] fun x ↦ f x := by + filter_upwards [hg.le_comap <| preimage_mem_comap (m := g) (mem_principal_self {0}ᶜ)] with x hx + aesop + +/-- If `g` tends to `∞`, then eventually for all `x` we have `(f x / g x) * g x = f x`. -/ +theorem Filter.EventuallyEq.div_mul_cancel_atTop {α K : Type*} [LinearOrderedSemifield K] + {f g : α → K} {l : Filter α} (hg : Tendsto g l atTop) : + (fun x ↦ f x / g x * g x) =ᶠ[l] fun x ↦ f x := + div_mul_cancel <| hg.mono_right <| le_principal_iff.mpr <| + mem_of_superset (Ioi_mem_atTop 0) <| by aesop + +/-- If when `x` tends to `∞`, `g` tends to `∞` and `f x / g x` tends to a positive + constant, then `f` tends to `∞`. -/ +theorem Tendsto.num {α K : Type*} [LinearOrderedField K] [TopologicalSpace K] [OrderTopology K] + {f g : α → K} {l : Filter α} (hg : Tendsto g l atTop) {a : K} (ha : 0 < a) + (hlim : Tendsto (fun x => f x / g x) l (𝓝 a)) : + Tendsto f l atTop := + Tendsto.congr' (EventuallyEq.div_mul_cancel_atTop hg) (Tendsto.mul_atTop ha hlim hg) + +/-- If when `x` tends to `∞`, `g` tends to `∞` and `f x / g x` tends to a positive + constant, then `f` tends to `∞`. -/ +theorem Tendsto.den {α K : Type*} [LinearOrderedField K] [TopologicalSpace K] [OrderTopology K] + [ContinuousInv K] {f g : α → K} {l : Filter α} (hf : Tendsto f l atTop) {a : K} (ha : 0 < a) + (hlim : Tendsto (fun x => f x / g x) l (𝓝 a)) : + Tendsto g l atTop := by + have hlim' : Tendsto (fun x => g x / f x) l (𝓝 a⁻¹) := by + simp_rw [← inv_div (f _)] + exact Filter.Tendsto.inv (f := fun x => f x / g x) hlim + apply Tendsto.congr' (EventuallyEq.div_mul_cancel_atTop hf) + (Tendsto.mul_atTop (inv_pos_of_pos ha) hlim' hf) + +/-- If when `x` tends to `∞`, `f x / g x` tends to a positive constant, then `f` tends to `∞` if + and only if `g` tends to `∞`. -/ +theorem Tendsto.num_atTop_iff_den_atTop {α K : Type*} [LinearOrderedField K] [TopologicalSpace K] + [OrderTopology K] [ContinuousInv K] {f g : α → K} {l : Filter α} {a : K} (ha : 0 < a) + (hlim : Tendsto (fun x => f x / g x) l (𝓝 a)) : + Tendsto f l atTop ↔ Tendsto g l atTop := + ⟨fun hf ↦ Tendsto.den hf ha hlim, fun hg ↦ Tendsto.num hg ha hlim⟩ + /-! ### Powers -/ @@ -137,7 +184,7 @@ theorem tendsto_pow_atTop_nhds_zero_of_lt_one {𝕜 : Type*} [LinearOrderedField (fun hr ↦ (tendsto_add_atTop_iff_nat 1).mp <| by simp [_root_.pow_succ, ← hr, tendsto_const_nhds]) (fun hr ↦ - have := one_lt_inv hr h₂ |> tendsto_pow_atTop_atTop_of_one_lt + have := (one_lt_inv₀ hr).2 h₂ |> tendsto_pow_atTop_atTop_of_one_lt (tendsto_inv_atTop_zero.comp this).congr fun n ↦ by simp) @[deprecated (since := "2024-01-31")] alias tendsto_pow_atTop_nhds_0_of_lt_1 := tendsto_pow_atTop_nhds_zero_of_lt_one diff --git a/Mathlib/Analysis/SpecificLimits/FloorPow.lean b/Mathlib/Analysis/SpecificLimits/FloorPow.lean index e3bb53507d60d..6d020f15e36d5 100644 --- a/Mathlib/Analysis/SpecificLimits/FloorPow.lean +++ b/Mathlib/Analysis/SpecificLimits/FloorPow.lean @@ -216,20 +216,20 @@ theorem tendsto_div_of_monotone_of_tendsto_div_floor_pow (u : ℕ → ℝ) (l : /-- The sum of `1/(c^i)^2` above a threshold `j` is comparable to `1/j^2`, up to a multiplicative constant. -/ theorem sum_div_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc : 1 < c) : - (∑ i ∈ (range N).filter (j < c ^ ·), (1 : ℝ) / (c ^ i) ^ 2) ≤ c ^ 3 * (c - 1)⁻¹ / j ^ 2 := by + (∑ i ∈ range N with j < c ^ i, (1 : ℝ) / (c ^ i) ^ 2) ≤ c ^ 3 * (c - 1)⁻¹ / j ^ 2 := by have cpos : 0 < c := zero_lt_one.trans hc have A : (0 : ℝ) < c⁻¹ ^ 2 := sq_pos_of_pos (inv_pos.2 cpos) have B : c ^ 2 * ((1 : ℝ) - c⁻¹ ^ 2)⁻¹ ≤ c ^ 3 * (c - 1)⁻¹ := by rw [← div_eq_mul_inv, ← div_eq_mul_inv, div_le_div_iff _ (sub_pos.2 hc)] swap - · exact sub_pos.2 (pow_lt_one₀ (inv_nonneg.2 cpos.le) (inv_lt_one hc) two_ne_zero) + · exact sub_pos.2 (pow_lt_one₀ (inv_nonneg.2 cpos.le) (inv_lt_one_of_one_lt₀ hc) two_ne_zero) have : c ^ 3 = c ^ 2 * c := by ring simp only [mul_sub, this, mul_one, inv_pow, sub_le_sub_iff_left] rw [mul_assoc, mul_comm c, ← mul_assoc, mul_inv_cancel₀ (sq_pos_of_pos cpos).ne', one_mul] simpa using pow_right_mono₀ hc.le one_le_two - have C : c⁻¹ ^ 2 < 1 := pow_lt_one₀ (inv_nonneg.2 cpos.le) (inv_lt_one hc) two_ne_zero + have C : c⁻¹ ^ 2 < 1 := pow_lt_one₀ (inv_nonneg.2 cpos.le) (inv_lt_one_of_one_lt₀ hc) two_ne_zero calc - (∑ i ∈ (range N).filter (j < c ^ ·), (1 : ℝ) / (c ^ i) ^ 2) ≤ + (∑ i ∈ range N with j < c ^ i, (1 : ℝ) / (c ^ i) ^ 2) ≤ ∑ i ∈ Ico ⌊Real.log j / Real.log c⌋₊ N, (1 : ℝ) / (c ^ i) ^ 2 := by refine sum_le_sum_of_subset_of_nonneg (fun i hi ↦ ?_) (by intros; positivity) simp only [mem_filter, mem_range] at hi @@ -276,17 +276,16 @@ theorem mul_pow_le_nat_floor_pow {c : ℝ} (hc : 1 < c) (i : ℕ) : (1 - c⁻¹) /-- The sum of `1/⌊c^i⌋₊^2` above a threshold `j` is comparable to `1/j^2`, up to a multiplicative constant. -/ theorem sum_div_nat_floor_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc : 1 < c) : - (∑ i ∈ (range N).filter (j < ⌊c ^ ·⌋₊), (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2) ≤ + (∑ i ∈ range N with j < ⌊c ^ i⌋₊, (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2) ≤ c ^ 5 * (c - 1)⁻¹ ^ 3 / j ^ 2 := by have cpos : 0 < c := zero_lt_one.trans hc - have A : 0 < 1 - c⁻¹ := sub_pos.2 (inv_lt_one hc) + have A : 0 < 1 - c⁻¹ := sub_pos.2 (inv_lt_one_of_one_lt₀ hc) calc - (∑ i ∈ (range N).filter (j < ⌊c ^ ·⌋₊), (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2) ≤ - ∑ i ∈ (range N).filter (j < c ^ ·), (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2 := by - apply sum_le_sum_of_subset_of_nonneg - · exact monotone_filter_right _ fun k hk ↦ hk.trans_le <| Nat.floor_le (by positivity) - · intros; positivity - _ ≤ ∑ i ∈ (range N).filter (j < c ^ ·), (1 - c⁻¹)⁻¹ ^ 2 * ((1 : ℝ) / (c ^ i) ^ 2) := by + (∑ i ∈ range N with j < ⌊c ^ i⌋₊, (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2) ≤ + ∑ i ∈ range N with j < c ^ i, (1 : ℝ) / (⌊c ^ i⌋₊ : ℝ) ^ 2 := by + gcongr + exact fun k hk ↦ hk.trans_le <| Nat.floor_le (by positivity) + _ ≤ ∑ i ∈ range N with j < c ^ i, (1 - c⁻¹)⁻¹ ^ 2 * ((1 : ℝ) / (c ^ i) ^ 2) := by refine sum_le_sum fun i _hi => ?_ rw [mul_div_assoc', mul_one, div_le_div_iff]; rotate_left · apply sq_pos_of_pos diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index b8e9194a32b88..0486eff13103d 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker, Sébastien Gouëzel, Yury Kudryashov, Dylan MacKenzie, Patrick Massot -/ import Mathlib.Algebra.BigOperators.Module -import Mathlib.Algebra.Order.Field.Basic +import Mathlib.Algebra.Order.Field.Power +import Mathlib.Algebra.Polynomial.Monic import Mathlib.Analysis.Asymptotics.Asymptotics import Mathlib.Analysis.Normed.Field.InfiniteSum import Mathlib.Analysis.Normed.Module.Basic @@ -26,62 +27,10 @@ noncomputable section open Set Function Filter Finset Metric Asymptotics Topology Nat NNReal ENNReal -variable {α β ι : Type*} - -theorem tendsto_norm_atTop_atTop : Tendsto (norm : ℝ → ℝ) atTop atTop := - tendsto_abs_atTop_atTop - -theorem summable_of_absolute_convergence_real {f : ℕ → ℝ} : - (∃ r, Tendsto (fun n ↦ ∑ i ∈ range n, |f i|) atTop (𝓝 r)) → Summable f - | ⟨r, hr⟩ => by - refine .of_norm ⟨r, (hasSum_iff_tendsto_nat_of_nonneg ?_ _).2 ?_⟩ - · exact fun i ↦ norm_nonneg _ - · simpa only using hr +variable {α : Type*} /-! ### Powers -/ - -theorem tendsto_norm_zero' {𝕜 : Type*} [NormedAddCommGroup 𝕜] : - Tendsto (norm : 𝕜 → ℝ) (𝓝[≠] 0) (𝓝[>] 0) := - tendsto_norm_zero.inf <| tendsto_principal_principal.2 fun _ hx ↦ norm_pos_iff.2 hx - -namespace NormedField - -theorem tendsto_norm_inverse_nhdsWithin_0_atTop {𝕜 : Type*} [NormedDivisionRing 𝕜] : - Tendsto (fun x : 𝕜 ↦ ‖x⁻¹‖) (𝓝[≠] 0) atTop := - (tendsto_inv_zero_atTop.comp tendsto_norm_zero').congr fun x ↦ (norm_inv x).symm - -theorem tendsto_norm_zpow_nhdsWithin_0_atTop {𝕜 : Type*} [NormedDivisionRing 𝕜] {m : ℤ} - (hm : m < 0) : - Tendsto (fun x : 𝕜 ↦ ‖x ^ m‖) (𝓝[≠] 0) atTop := by - rcases neg_surjective m with ⟨m, rfl⟩ - rw [neg_lt_zero] at hm; lift m to ℕ using hm.le; rw [Int.natCast_pos] at hm - simp only [norm_pow, zpow_neg, zpow_natCast, ← inv_pow] - exact (tendsto_pow_atTop hm.ne').comp NormedField.tendsto_norm_inverse_nhdsWithin_0_atTop - -/-- The (scalar) product of a sequence that tends to zero with a bounded one also tends to zero. -/ -theorem tendsto_zero_smul_of_tendsto_zero_of_bounded {ι 𝕜 𝔸 : Type*} [NormedDivisionRing 𝕜] - [NormedAddCommGroup 𝔸] [Module 𝕜 𝔸] [BoundedSMul 𝕜 𝔸] {l : Filter ι} {ε : ι → 𝕜} {f : ι → 𝔸} - (hε : Tendsto ε l (𝓝 0)) (hf : Filter.IsBoundedUnder (· ≤ ·) l (norm ∘ f)) : - Tendsto (ε • f) l (𝓝 0) := by - rw [← isLittleO_one_iff 𝕜] at hε ⊢ - simpa using IsLittleO.smul_isBigO hε (hf.isBigO_const (one_ne_zero : (1 : 𝕜) ≠ 0)) - -@[simp] -theorem continuousAt_zpow {𝕜 : Type*} [NontriviallyNormedField 𝕜] {m : ℤ} {x : 𝕜} : - ContinuousAt (fun x ↦ x ^ m) x ↔ x ≠ 0 ∨ 0 ≤ m := by - refine ⟨?_, continuousAt_zpow₀ _ _⟩ - contrapose!; rintro ⟨rfl, hm⟩ hc - exact not_tendsto_atTop_of_tendsto_nhds (hc.tendsto.mono_left nhdsWithin_le_nhds).norm - (tendsto_norm_zpow_nhdsWithin_0_atTop hm) - -@[simp] -theorem continuousAt_inv {𝕜 : Type*} [NontriviallyNormedField 𝕜] {x : 𝕜} : - ContinuousAt Inv.inv x ↔ x ≠ 0 := by - simpa [(zero_lt_one' ℤ).not_le] using @continuousAt_zpow _ _ (-1) x - -end NormedField - theorem isLittleO_pow_pow_of_lt_left {r₁ r₂ : ℝ} (h₁ : 0 ≤ r₁) (h₂ : r₁ < r₂) : (fun n : ℕ ↦ r₁ ^ n) =o[atTop] fun n ↦ r₂ ^ n := have H : 0 < r₂ := h₁.trans_lt h₂ @@ -210,7 +159,7 @@ theorem tendsto_pow_const_mul_const_pow_of_abs_lt_one (k : ℕ) {r : ℝ} (hr : by_cases h0 : r = 0 · exact tendsto_const_nhds.congr' (mem_atTop_sets.2 ⟨1, fun n hn ↦ by simp [zero_lt_one.trans_le hn |>.ne', h0]⟩) - have hr' : 1 < |r|⁻¹ := one_lt_inv (abs_pos.2 h0) hr + have hr' : 1 < |r|⁻¹ := (one_lt_inv₀ (abs_pos.2 h0)).2 hr rw [tendsto_zero_iff_norm_tendsto_zero] simpa [div_eq_mul_inv] using tendsto_pow_const_div_const_pow_of_one_lt k hr' @@ -252,7 +201,7 @@ alias tendsto_pow_atTop_nhds_0_of_abs_lt_1 := tendsto_pow_atTop_nhds_zero_of_abs /-- A normed ring has summable geometric series if, for all `ξ` of norm `< 1`, the geometric series `∑ ξ ^ n` converges. This holds both in complete normed rings and in normed fields, providing a convenient abstraction of these two classes to avoid repeating the same proofs. -/ -class HasSummableGeomSeries (K : Type*) [NormedRing K] : Prop := +class HasSummableGeomSeries (K : Type*) [NormedRing K] : Prop where summable_geometric_of_norm_lt_one : ∀ (ξ : K), ‖ξ‖ < 1 → Summable (fun n ↦ ξ ^ n) lemma summable_geometric_of_norm_lt_one {K : Type*} [NormedRing K] [HasSummableGeomSeries K] diff --git a/Mathlib/Analysis/SpecificLimits/RCLike.lean b/Mathlib/Analysis/SpecificLimits/RCLike.lean index 287d854e7d39d..0207c4041ec9f 100644 --- a/Mathlib/Analysis/SpecificLimits/RCLike.lean +++ b/Mathlib/Analysis/SpecificLimits/RCLike.lean @@ -22,3 +22,18 @@ theorem RCLike.tendsto_inverse_atTop_nhds_zero_nat : simp @[deprecated (since := "2024-01-16")] alias RCLike.tendsto_inverse_atTop_nhds_0_nat := RCLike.tendsto_inverse_atTop_nhds_zero_nat + +variable {𝕜} + +theorem RCLike.tendsto_add_mul_div_add_mul_atTop_nhds (a b c : 𝕜) {d : 𝕜} (hd : d ≠ 0) : + Tendsto (fun k : ℕ ↦ (a + c * k) / (b + d * k)) atTop (𝓝 (c / d)) := by + apply Filter.Tendsto.congr' + case f₁ => exact fun k ↦ (a * (↑k)⁻¹ + c) / (b * (↑k)⁻¹ + d) + · refine (eventually_ne_atTop 0).mp (Eventually.of_forall ?_) + intro h hx + field_simp [hx] + · apply Filter.Tendsto.div _ _ hd + all_goals + apply zero_add (_ : 𝕜) ▸ Filter.Tendsto.add_const _ _ + apply mul_zero (_ : 𝕜) ▸ Filter.Tendsto.const_mul _ _ + exact RCLike.tendsto_inverse_atTop_nhds_zero_nat 𝕜 diff --git a/Mathlib/Analysis/Subadditive.lean b/Mathlib/Analysis/Subadditive.lean index 8b9b5336d51ef..7c69384f24472 100644 --- a/Mathlib/Analysis/Subadditive.lean +++ b/Mathlib/Analysis/Subadditive.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.Instances.Real import Mathlib.Order.Filter.AtTopBot.Archimedean +import Mathlib.Topology.Instances.Real /-! # Convergence of subadditive sequences diff --git a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean b/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean index 0d05481d7f037..4bf4e8678ab11 100644 --- a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean +++ b/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean @@ -3,9 +3,8 @@ Copyright (c) 2022 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ +import Mathlib.Analysis.CStarAlgebra.ContinuousLinearMap import Mathlib.Analysis.Normed.Module.Dual -import Mathlib.Analysis.Complex.Basic -import Mathlib.Analysis.InnerProductSpace.Adjoint /-! # Von Neumann algebras @@ -39,8 +38,7 @@ One the other hand, not picking one means that the weak-* topology (which depends on a choice of predual) must be defined using the choice, and we may be unhappy with the resulting opaqueness of the definition. -/ -class WStarAlgebra (M : Type u) [NormedRing M] [StarRing M] [CStarRing M] [Module ℂ M] - [NormedAlgebra ℂ M] [StarModule ℂ M] : Prop where +class WStarAlgebra (M : Type u) [CStarAlgebra M] : Prop where /-- There is a Banach space `X` whose dual is isometrically (conjugate-linearly) isomorphic to the `WStarAlgebra`. -/ exists_predual : diff --git a/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean index ff25be4567c6f..84eda8c006ac2 100644 --- a/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean +++ b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Isaac Hernando, Coleton Kotch, Adam Topaz -/ -import Mathlib.CategoryTheory.Limits.Filtered -import Mathlib.CategoryTheory.Limits.Preserves.Finite +import Mathlib.CategoryTheory.Limits.Constructions.Filtered +import Mathlib.CategoryTheory.Limits.Shapes.Biproducts +import Mathlib.CategoryTheory.Limits.Preserves.FunctorCategory /-! @@ -20,6 +21,10 @@ basic facts about them. - `AB5` -- an abelian category satisfies `AB5` provided that filtered colimits are exact. - The duals of the above definitions, called `AB4Star` and `AB5Star`. +## Theorems + +- The implication from `AB5` to `AB4` is established in `AB4.ofAB5`. + ## Remarks For `AB4` and `AB5`, we only require left exactness as right exactness is automatic. @@ -42,10 +47,12 @@ namespace CategoryTheory open Limits -universe v v' u u' +universe v v' u u' w variable (C : Type u) [Category.{v} C] +attribute [local instance] hasCoproducts_of_finite_and_filtered + /-- A category `C` which has coproducts is said to have `AB4` provided that coproducts are exact. @@ -90,4 +97,32 @@ class AB5Star [HasCofilteredLimits C] where attribute [instance] AB5Star.preservesFiniteColimits +noncomputable section + +open CoproductsFromFiniteFiltered + +variable {α : Type w} +variable [HasZeroMorphisms C] [HasFiniteBiproducts C] [HasFiniteLimits C] + +instance preservesFiniteLimitsLiftToFinset : PreservesFiniteLimits (liftToFinset C α) := + preservesFiniteLimitsOfEvaluation _ fun I => + letI : PreservesFiniteLimits (colim (J := Discrete I) (C := C)) := + preservesFiniteLimitsOfNatIso HasBiproductsOfShape.colimIsoLim.symm + letI : PreservesFiniteLimits ((whiskeringLeft (Discrete I) (Discrete α) C).obj + (Discrete.functor fun x ↦ ↑x)) := + ⟨fun J _ _ => whiskeringLeftPreservesLimitsOfShape J _⟩ + letI : PreservesFiniteLimits ((whiskeringLeft (Discrete I) (Discrete α) C).obj + (Discrete.functor (·.val)) ⋙ colim) := + compPreservesFiniteLimits _ _ + preservesFiniteLimitsOfNatIso (liftToFinsetEvaluationIso I).symm + +/-- A category with finite biproducts and finite limits is AB4 if it is AB5. -/ +def AB4.ofAB5 [HasFiniteCoproducts C] [HasFilteredColimits C] [AB5 C] : AB4 C where + preservesFiniteLimits J := + letI : PreservesFiniteLimits (liftToFinset C J ⋙ colim) := + compPreservesFiniteLimits _ _ + preservesFiniteLimitsOfNatIso (liftToFinsetColimIso) + +end + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Abelian/Images.lean b/Mathlib/CategoryTheory/Abelian/Images.lean index c753cc0c81887..1bed70213ca90 100644 --- a/Mathlib/CategoryTheory/Abelian/Images.lean +++ b/Mathlib/CategoryTheory/Abelian/Images.lean @@ -49,7 +49,6 @@ protected abbrev image.ι : Abelian.image f ⟶ Q := protected abbrev factorThruImage : P ⟶ Abelian.image f := kernel.lift (cokernel.π f) f <| cokernel.condition f --- Porting note (#10618): simp can prove this and reassoc version, removed tags /-- `f` factors through its image via the canonical morphism `p`. -/ protected theorem image.fac : Abelian.factorThruImage f ≫ image.ι f = f := kernel.lift_ι _ _ _ diff --git a/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean b/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean index 675ab43cfcce7..1473b0ef27413 100644 --- a/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean +++ b/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean @@ -65,7 +65,7 @@ lemma exact₀ {Z : C} (I : InjectiveResolution Z) : def descFOne {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y) (J : InjectiveResolution Z) : J.cocomplex.X 1 ⟶ I.cocomplex.X 1 := J.exact₀.descToInjective (descFZero f I J ≫ I.cocomplex.d 0 1) - (by dsimp; simp [← assoc, assoc, descFZero]) + (by dsimp; simp only [← assoc, descFZero]; simp [assoc]) @[simp] theorem descFOne_zero_comm {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y) diff --git a/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean b/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean index 680956963fe88..8f4d7dda4a14c 100644 --- a/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean +++ b/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean @@ -232,12 +232,12 @@ instance epi_r {A : C} : Epi (r A) := by let hp1 : IsLimit (KernelFork.ofι (prod.lift (𝟙 A) (0 : A ⟶ A)) hlp) := by refine Fork.IsLimit.mk _ (fun s => Fork.ι s ≫ Limits.prod.fst) ?_ ?_ · intro s - apply prod.hom_ext <;> simp + apply Limits.prod.hom_ext <;> simp · intro s m h haveI : Mono (prod.lift (𝟙 A) (0 : A ⟶ A)) := mono_of_mono_fac (prod.lift_fst _ _) apply (cancel_mono (prod.lift (𝟙 A) (0 : A ⟶ A))).1 convert h - apply prod.hom_ext <;> simp + apply Limits.prod.hom_ext <;> simp let hp2 : IsColimit (CokernelCofork.ofπ (Limits.prod.snd : A ⨯ A ⟶ A) hlp) := epiIsCokernelOfKernel _ hp1 apply NormalMonoCategory.epi_of_zero_cancel @@ -265,7 +265,6 @@ abbrev σ {A : C} : A ⨯ A ⟶ A := end --- Porting note (#10618): simp can prove these @[reassoc] theorem diag_σ {X : C} : diag X ≫ σ = 0 := by rw [cokernel.condition_assoc, zero_comp] diff --git a/Mathlib/CategoryTheory/Abelian/Opposite.lean b/Mathlib/CategoryTheory/Abelian/Opposite.lean index e862e8a81c331..d0af389e041d3 100644 --- a/Mathlib/CategoryTheory/Abelian/Opposite.lean +++ b/Mathlib/CategoryTheory/Abelian/Opposite.lean @@ -151,7 +151,7 @@ theorem image_ι_op_comp_imageUnopOp_hom : Quiver.Hom.op_unop, cokernelIsoOfEq_hom_comp_desc_assoc, cokernel.π_desc_assoc, cokernel.π_desc] simp only [eqToHom_refl] - erw [IsIso.inv_id, Category.id_comp] + rw [IsIso.inv_id, Category.id_comp] theorem imageUnopOp_hom_comp_image_ι : (imageUnopOp g).hom ≫ image.ι g = (factorThruImage g.unop).op := by diff --git a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean index ee32d7d2f7666..7bb3ceaced8e1 100644 --- a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean +++ b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean @@ -198,7 +198,7 @@ attribute [local instance] HasBinaryBiproducts.of_hasBinaryProducts /-- The arrows pseudo-equal to a zero morphism are precisely the zero morphisms. -/ theorem pseudoZero_aux {P : C} (Q : C) (f : Over P) : f ≈ (0 : Q ⟶ P) ↔ f.hom = 0 := - ⟨fun ⟨R, p, q, ep, _, comm⟩ => zero_of_epi_comp p (by simp [comm]), fun hf => + ⟨fun ⟨R, p, q, _, _, comm⟩ => zero_of_epi_comp p (by simp [comm]), fun hf => ⟨biprod f.1 Q, biprod.fst, biprod.snd, inferInstance, inferInstance, by rw [hf, Over.coe_hom, HasZeroMorphisms.comp_zero, HasZeroMorphisms.comp_zero]⟩⟩ @@ -258,12 +258,6 @@ theorem zero_morphism_ext {P Q : C} (f : P ⟶ Q) : (∀ a, f a = 0) → f = 0 : theorem zero_morphism_ext' {P Q : C} (f : P ⟶ Q) : (∀ a, f a = 0) → 0 = f := Eq.symm ∘ zero_morphism_ext f --- Porting note: these are no longer valid as `ext` lemmas. --- scoped[Pseudoelement] --- attribute [ext] --- CategoryTheory.Abelian.Pseudoelement.zero_morphism_ext --- CategoryTheory.Abelian.Pseudoelement.zero_morphism_ext' - theorem eq_zero_iff {P Q : C} (f : P ⟶ Q) : f = 0 ↔ ∀ a, f a = 0 := ⟨fun h a => by simp [h], zero_morphism_ext _⟩ diff --git a/Mathlib/CategoryTheory/Adhesive.lean b/Mathlib/CategoryTheory/Adhesive.lean index 159adb085741e..51235c1937b60 100644 --- a/Mathlib/CategoryTheory/Adhesive.lean +++ b/Mathlib/CategoryTheory/Adhesive.lean @@ -133,7 +133,7 @@ theorem is_coprod_iff_isPushout {X E Y YE : C} (c : BinaryCofan X E) (hc : IsCol · intro s m e₁ e₂ apply PushoutCocone.IsColimit.hom_ext H.isColimit · symm; exact (H.isColimit.fac _ WalkingSpan.left).trans e₂.symm - · erw [H.isColimit.fac _ WalkingSpan.right] + · rw [H.isColimit.fac _ WalkingSpan.right] apply BinaryCofan.IsColimit.hom_ext hc · erw [hc.fac, ← H.w_assoc, e₂]; rfl · refine ((Category.assoc _ _ _).symm.trans e₁).trans ?_; symm; exact hc.fac _ _ diff --git a/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean b/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean index 3d5e083b0ab9b..6d42354bbaaa3 100644 --- a/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean +++ b/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta -/ +import Mathlib.CategoryTheory.Comma.StructuredArrow.Small import Mathlib.CategoryTheory.Generator import Mathlib.CategoryTheory.Limits.ConeCategory import Mathlib.CategoryTheory.Limits.Constructions.WeaklyInitial diff --git a/Mathlib/CategoryTheory/Adjunction/Basic.lean b/Mathlib/CategoryTheory/Adjunction/Basic.lean index 3d9c1506b6275..6d43fa6f5d71a 100644 --- a/Mathlib/CategoryTheory/Adjunction/Basic.lean +++ b/Mathlib/CategoryTheory/Adjunction/Basic.lean @@ -151,7 +151,7 @@ namespace Adjunction attribute [reassoc (attr := simp)] left_triangle_components right_triangle_components /-- The hom set equivalence associated to an adjunction. -/ -@[simps] +@[simps (config := .lemmasOnly)] def homEquiv {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) (X : C) (Y : D) : (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y) where toFun := fun f => adj.unit.app X ≫ G.map f @@ -161,11 +161,23 @@ def homEquiv {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) (X : C) (Y : D) : rw [F.map_comp, assoc, ← Functor.comp_map, adj.counit.naturality, ← assoc] simp right_inv := fun g => by - simp [← assoc, ← Functor.comp_map, ← adj.unit.naturality, assoc] + simp only [Functor.comp_obj, Functor.map_comp] + rw [← assoc, ← Functor.comp_map, ← adj.unit.naturality] + simp alias homEquiv_unit := homEquiv_apply alias homEquiv_counit := homEquiv_symm_apply -attribute [simp] homEquiv_unit homEquiv_counit + +end Adjunction + +-- These lemmas are not global simp lemmas because certain adjunctions +-- are constructed using `Adjunction.mkOfHomEquiv`, and we certainly +-- do not want `dsimp` to apply `homEquiv_unit` or `homEquiv_counit` +-- in that case. However, when proving general API results about adjunctions, +-- it may be advisable to add a local simp attribute to these lemmas. +attribute [local simp] Adjunction.homEquiv_unit Adjunction.homEquiv_counit + +namespace Adjunction section @@ -267,6 +279,20 @@ theorem eq_homEquiv_apply {A : C} {B : D} (f : F.obj A ⟶ B) (g : A ⟶ G.obj B g = adj.homEquiv A B f ↔ (adj.homEquiv A B).symm g = f := eq_unit_comp_map_iff adj f g +/-- If `adj : F ⊣ G`, and `X : C`, then `F.obj X` corepresents `Y ↦ (X ⟶ G.obj Y)`-/ +@[simps] +def corepresentableBy (X : C) : + (G ⋙ coyoneda.obj (Opposite.op X)).CorepresentableBy (F.obj X) where + homEquiv := adj.homEquiv _ _ + homEquiv_comp := by aesop_cat + +/-- If `adj : F ⊣ G`, and `Y : D`, then `G.obj Y` represents `X ↦ (F.obj X ⟶ Y)`-/ +@[simps] +def representableBy (Y : D) : + (F.op ⋙ yoneda.obj Y).RepresentableBy (G.obj Y) where + homEquiv := (adj.homEquiv _ _).symm + homEquiv_comp := by aesop_cat + end end Adjunction @@ -289,12 +315,6 @@ structure CoreHomEquivUnitCounit (F : C ⥤ D) (G : D ⥤ C) where /-- The relationship between the counit and hom set equivalence of an adjunction -/ homEquiv_counit : ∀ {X Y g}, (homEquiv X Y).symm g = F.map g ≫ counit.app Y := by aesop_cat -namespace CoreHomEquivUnitCounit - -attribute [simp] homEquiv_unit homEquiv_counit - -end CoreHomEquivUnitCounit - /-- This is an auxiliary data structure useful for constructing adjunctions. See `Adjunction.mkOfHomEquiv`. This structure won't typically be used anywhere else. @@ -363,6 +383,8 @@ end CoreUnitCounit variable {F : C ⥤ D} {G : D ⥤ C} +attribute [local simp] CoreHomEquivUnitCounit.homEquiv_unit CoreHomEquivUnitCounit.homEquiv_counit + /-- Construct an adjunction from the data of a `CoreHomEquivUnitCounit`, i.e. a hom set equivalence, unit and counit natural transformations together with proofs of the equalities @@ -401,6 +423,7 @@ def mkOfHomEquiv (adj : CoreHomEquiv F G) : F ⊣ G := homEquiv_unit := fun {X Y f} => by simp [← adj.homEquiv_naturality_right] homEquiv_counit := fun {X Y f} => by simp [← adj.homEquiv_naturality_left_symm] } +@[simp] lemma mkOfHomEquiv_homEquiv (adj : CoreHomEquiv F G) : (mkOfHomEquiv adj).homEquiv = adj.homEquiv := by ext X Y g diff --git a/Mathlib/CategoryTheory/Adjunction/Comma.lean b/Mathlib/CategoryTheory/Adjunction/Comma.lean index b74e9b326b43d..4147a489b5b31 100644 --- a/Mathlib/CategoryTheory/Adjunction/Comma.lean +++ b/Mathlib/CategoryTheory/Adjunction/Comma.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta -/ +import Mathlib.CategoryTheory.Limits.Shapes.Terminal import Mathlib.CategoryTheory.Adjunction.Basic -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic import Mathlib.CategoryTheory.PUnit /-! @@ -125,6 +126,8 @@ section variable {F : C ⥤ D} +attribute [local simp] Adjunction.homEquiv_unit Adjunction.homEquiv_counit + /-- Given a left adjoint to `G`, we can construct an initial object in each structured arrow category on `G`. -/ def mkInitialOfLeftAdjoint (h : F ⊣ G) (A : C) : diff --git a/Mathlib/CategoryTheory/Adjunction/Evaluation.lean b/Mathlib/CategoryTheory/Adjunction/Evaluation.lean index 9fa052e5ca51b..2336e9442f689 100644 --- a/Mathlib/CategoryTheory/Adjunction/Evaluation.lean +++ b/Mathlib/CategoryTheory/Adjunction/Evaluation.lean @@ -19,9 +19,10 @@ namespace CategoryTheory open CategoryTheory.Limits -universe v₁ v₂ u₁ u₂ +universe v₁ v₂ v₃ u₁ u₂ u₃ variable {C : Type u₁} [Category.{v₁} C] (D : Type u₂) [Category.{v₂} D] + (E : Type u₃) [Category.{v₃} E] noncomputable section @@ -36,7 +37,7 @@ def evaluationLeftAdjoint (c : C) : D ⥤ C ⥤ D where { obj := fun t => ∐ fun _ : c ⟶ t => d map := fun f => Sigma.desc fun g => (Sigma.ι fun _ => d) <| g ≫ f} map {_ d₂} f := - { app := fun e => Sigma.desc fun h => f ≫ Sigma.ι (fun _ => d₂) h + { app := fun _ => Sigma.desc fun h => f ≫ Sigma.ι (fun _ => d₂) h naturality := by intros dsimp @@ -50,7 +51,7 @@ def evaluationAdjunctionRight (c : C) : evaluationLeftAdjoint D c ⊣ (evaluatio { homEquiv := fun d F => { toFun := fun f => Sigma.ι (fun _ => d) (𝟙 _) ≫ f.app c invFun := fun f => - { app := fun e => Sigma.desc fun h => f ≫ F.map h + { app := fun _ => Sigma.desc fun h => f ≫ F.map h naturality := by intros dsimp @@ -73,7 +74,7 @@ def evaluationAdjunctionRight (c : C) : evaluationLeftAdjoint D c ⊣ (evaluatio instance evaluationIsRightAdjoint (c : C) : ((evaluation _ D).obj c).IsRightAdjoint := ⟨_, ⟨evaluationAdjunctionRight _ _⟩⟩ -/-- See also the file `CategoryTheory.Limits.FunctorCategoryEpiMono` +/-- See also the file `CategoryTheory.Limits.FunctorCategory.EpiMono` for a similar result under a `HasPullbacks` assumption. -/ theorem NatTrans.mono_iff_mono_app' {F G : C ⥤ D} (η : F ⟶ G) : Mono η ↔ ∀ c, Mono (η.app c) := by constructor @@ -95,7 +96,7 @@ def evaluationRightAdjoint (c : C) : D ⥤ C ⥤ D where { obj := fun t => ∏ᶜ fun _ : t ⟶ c => d map := fun f => Pi.lift fun g => Pi.π _ <| f ≫ g } map f := - { app := fun t => Pi.lift fun g => Pi.π _ g ≫ f + { app := fun _ => Pi.lift fun g => Pi.π _ g ≫ f naturality := by intros dsimp @@ -108,7 +109,7 @@ def evaluationAdjunctionLeft (c : C) : (evaluation _ _).obj c ⊣ evaluationRigh Adjunction.mkOfHomEquiv { homEquiv := fun F d => { toFun := fun f => - { app := fun t => Pi.lift fun g => F.map g ≫ f + { app := fun _ => Pi.lift fun g => F.map g ≫ f naturality := by intros dsimp @@ -130,8 +131,7 @@ def evaluationAdjunctionLeft (c : C) : (evaluation _ _).obj c ⊣ evaluationRigh instance evaluationIsLeftAdjoint (c : C) : ((evaluation _ D).obj c).IsLeftAdjoint := ⟨_, ⟨evaluationAdjunctionLeft _ _⟩⟩ - -/-- See also the file `CategoryTheory.Limits.FunctorCategoryEpiMono` +/-- See also the file `CategoryTheory.Limits.FunctorCategory.EpiMono` for a similar result under a `HasPushouts` assumption. -/ theorem NatTrans.epi_iff_epi_app' {F G : C ⥤ D} (η : F ⟶ G) : Epi η ↔ ∀ c, Epi (η.app c) := by constructor diff --git a/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean b/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean index 2bdec90917b38..7c789d7c00fcf 100644 --- a/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean +++ b/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean @@ -40,6 +40,8 @@ open Category open Opposite +attribute [local simp] Adjunction.homEquiv_unit Adjunction.homEquiv_counit + variable {C : Type u₁} [Category.{v₁} C] variable {D : Type u₂} [Category.{v₂} D] variable {L : C ⥤ D} {R : D ⥤ C} (h : L ⊣ R) @@ -128,7 +130,7 @@ lemma full_L_of_isSplitEpi_unit_app [∀ X, IsSplitEpi (h.unit.app X)] : L.Full /-- If the unit is an isomorphism, then the left adjoint is fully faithful. -/ noncomputable def fullyFaithfulLOfIsIsoUnit [IsIso h.unit] : L.FullyFaithful where - preimage {X Y} f := h.homEquiv _ (L.obj Y) f ≫ inv (h.unit.app Y) + preimage {_ Y} f := h.homEquiv _ (L.obj Y) f ≫ inv (h.unit.app Y) /-- If each component of the counit is an epimorphism, then the right adjoint is faithful. -/ lemma faithful_R_of_epi_counit_app [∀ X, Epi (h.counit.app X)] : R.Faithful where diff --git a/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean b/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean index e4d139ca0cb2b..f6b0b6a9aedb8 100644 --- a/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean +++ b/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean @@ -122,6 +122,13 @@ variable [HasReflexiveCoequalizers A] noncomputable def constructLeftAdjointObj (Y : B) : A := coequalizer (F'.map (U.map (adj₁.counit.app Y))) (otherMap _ _ adj₁ adj₂ Y) +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{ z : F.obj (U.obj X) ⟶ R.obj Y // _ }`. +-/ +set_option linter.unusedVariables false in /-- The homset equivalence which helps show that `R` is a right adjoint. -/ @[simps!] -- Porting note: Originally `@[simps (config := { rhsMd := semireducible })]` noncomputable def constructLeftAdjointEquiv [∀ X : B, RegularEpi (adj₁.counit.app X)] (Y : A) @@ -150,6 +157,8 @@ noncomputable def constructLeftAdjointEquiv [∀ X : B, RegularEpi (adj₁.couni apply eq_comm _ ≃ (X ⟶ R.obj Y) := (Cofork.IsColimit.homIso (counitCoequalises adj₁ X) _).symm +attribute [local simp] Adjunction.homEquiv_counit + /-- Construct the left adjoint to `R`, with object map `constructLeftAdjointObj`. -/ noncomputable def constructLeftAdjoint [∀ X : B, RegularEpi (adj₁.counit.app X)] : B ⥤ A := by refine Adjunction.leftAdjointOfEquiv (fun X Y => constructLeftAdjointEquiv R _ adj₁ adj₂ Y X) ?_ diff --git a/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean b/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean index 3d3893abeac50..83076882dba44 100644 --- a/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean +++ b/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean @@ -152,6 +152,7 @@ noncomputable def constructRightAdjoint [∀ X : B, RegularMono (adj₁.unit.app rw [constructRightAdjointEquiv_symm_apply, constructRightAdjointEquiv_symm_apply, Equiv.symm_apply_eq, Subtype.ext_iff] dsimp + simp only [Adjunction.homEquiv_unit, Adjunction.homEquiv_counit] erw [Fork.IsLimit.homIso_natural, Fork.IsLimit.homIso_natural] simp only [Fork.ofι_pt, Functor.map_comp, assoc, limit.cone_x] erw [adj₂.homEquiv_naturality_left, Equiv.rightInverse_symm] diff --git a/Mathlib/CategoryTheory/Adjunction/Limits.lean b/Mathlib/CategoryTheory/Adjunction/Limits.lean index 6a2f33e8ce6ad..f57ec0e073cee 100644 --- a/Mathlib/CategoryTheory/Adjunction/Limits.lean +++ b/Mathlib/CategoryTheory/Adjunction/Limits.lean @@ -296,6 +296,8 @@ end ArbitraryUniverse variable {C : Type u₁} [Category.{v₀} C] {D : Type u₂} [Category.{v₀} D] {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) +attribute [local simp] homEquiv_unit homEquiv_counit + -- Note: this is natural in K, but we do not yet have the tools to formulate that. /-- When `F ⊣ G`, the functor associating to each `Y` the cocones over `K ⋙ F` with cone point `Y` diff --git a/Mathlib/CategoryTheory/Adjunction/Opposites.lean b/Mathlib/CategoryTheory/Adjunction/Opposites.lean index f4362585c27a4..615dd8ae5d899 100644 --- a/Mathlib/CategoryTheory/Adjunction/Opposites.lean +++ b/Mathlib/CategoryTheory/Adjunction/Opposites.lean @@ -27,6 +27,8 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] namespace CategoryTheory.Adjunction +attribute [local simp] homEquiv_unit homEquiv_counit + /-- If `G.op` is adjoint to `F.op` then `F` is adjoint to `G`. -/ @[simps! unit_app counit_app] def adjointOfOpAdjointOp (F : C ⥤ D) (G : D ⥤ C) (h : G.op ⊣ F.op) : F ⊣ G := diff --git a/Mathlib/CategoryTheory/Adjunction/PartialAdjoint.lean b/Mathlib/CategoryTheory/Adjunction/PartialAdjoint.lean new file mode 100644 index 0000000000000..80ce40cc477e2 --- /dev/null +++ b/Mathlib/CategoryTheory/Adjunction/PartialAdjoint.lean @@ -0,0 +1,182 @@ +/- +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.Adjunction.Basic +import Mathlib.CategoryTheory.Limits.HasLimits +import Mathlib.CategoryTheory.Yoneda +import Mathlib.Order.CompleteLattice + +/-! +# Domain of definition of the partial left adjoint + +Given a functor `F : D ⥤ C`, we define a functor +`F.partialLeftAdjoint : F.PartialLeftAdjointSource ⥤ D` which is +defined on the full subcategory of `C` consisting of those objects `X : C` +such that `F ⋙ coyoneda.obj (op X) : D ⥤ Type _` is corepresentable. +We have a natural bijection +`(F.partialLeftAdjoint.obj X ⟶ Y) ≃ (X.obj ⟶ F.obj Y)` +that is similar to what we would expect for the image of the object `X` +by the left adjoint of `F`, if such an adjoint existed. + +Indeed, if the predicate `F.LeftAdjointObjIsDefined` which defines +the `F.PartialLeftAdjointSource` holds for all +objects `X : C`, then `F` has a left adjoint. + +When colimits indexed by a category `J` exist in `D`, we show that +the predicate `F.LeftAdjointObjIsDefined` is stable under colimits indexed by `J`. + +## TODO +* consider dualizing the results to right adjoints + +-/ + +universe v₁ v₂ u₁ u₂ + +namespace CategoryTheory + +namespace Functor + +open Category Opposite Limits + +variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] (F : D ⥤ C) + +/-- Given a functor `F : D ⥤ C`, this is a predicate on objects `X : C` corresponding +to the domain of definition of the (partial) left adjoint of `F`. -/ +def LeftAdjointObjIsDefined (X : C) : Prop := IsCorepresentable (F ⋙ coyoneda.obj (op X)) + +lemma leftAdjointObjIsDefined_iff (X : C) : + F.LeftAdjointObjIsDefined X ↔ IsCorepresentable (F ⋙ coyoneda.obj (op X)) := by rfl + +variable {F} in +lemma leftAdjointObjIsDefined_of_adjunction {G : C ⥤ D} (adj : G ⊣ F) (X : C) : + F.LeftAdjointObjIsDefined X := + (adj.corepresentableBy X).isCorepresentable + +/-- The full subcategory where `F.partialLeftAdjoint` shall be defined. -/ +abbrev PartialLeftAdjointSource := FullSubcategory F.LeftAdjointObjIsDefined + +instance (X : F.PartialLeftAdjointSource) : + IsCorepresentable (F ⋙ coyoneda.obj (op X.obj)) := X.property + +/-- Given `F : D ⥤ C`, this is `F.partialLeftAdjoint` on objects: it sends +`X : C` such that `F.LeftAdjointObjIsDefined X` holds to an object of `D` +which represents the functor `F ⋙ coyoneda.obj (op X.obj)`. -/ +noncomputable def partialLeftAdjointObj (X : F.PartialLeftAdjointSource) : D := + (F ⋙ coyoneda.obj (op X.obj)).coreprX + +/-- Given `F : D ⥤ C`, this is the canonical bijection +`(F.partialLeftAdjointObj X ⟶ Y) ≃ (X.obj ⟶ F.obj Y)` +for all `X : F.PartialLeftAdjointSource` and `Y : D`. -/ +noncomputable def partialLeftAdjointHomEquiv {X : F.PartialLeftAdjointSource} {Y : D} : + (F.partialLeftAdjointObj X ⟶ Y) ≃ (X.obj ⟶ F.obj Y) := + (F ⋙ coyoneda.obj (op X.obj)).corepresentableBy.homEquiv + +lemma partialLeftAdjointHomEquiv_comp {X : F.PartialLeftAdjointSource} {Y Y' : D} + (f : F.partialLeftAdjointObj X ⟶ Y) (g : Y ⟶ Y') : + F.partialLeftAdjointHomEquiv (f ≫ g) = + F.partialLeftAdjointHomEquiv f ≫ F.map g := by + apply CorepresentableBy.homEquiv_comp + +/-- Given `F : D ⥤ C`, this is `F.partialLeftAdjoint` on morphisms. -/ +noncomputable def partialLeftAdjointMap {X Y : F.PartialLeftAdjointSource} + (f : X ⟶ Y) : F.partialLeftAdjointObj X ⟶ F.partialLeftAdjointObj Y := + F.partialLeftAdjointHomEquiv.symm (f ≫ F.partialLeftAdjointHomEquiv (𝟙 _)) + +@[simp] +lemma partialLeftAdjointHomEquiv_map {X Y : F.PartialLeftAdjointSource} + (f : X ⟶ Y) : + F.partialLeftAdjointHomEquiv (F.partialLeftAdjointMap f) = + by exact f ≫ F.partialLeftAdjointHomEquiv (𝟙 _) := by + simp [partialLeftAdjointMap] + +lemma partialLeftAdjointHomEquiv_map_comp {X X' : F.PartialLeftAdjointSource} {Y : D} + (f : X ⟶ X') (g : F.partialLeftAdjointObj X' ⟶ Y) : + F.partialLeftAdjointHomEquiv (F.partialLeftAdjointMap f ≫ g) = + by exact f ≫ F.partialLeftAdjointHomEquiv g := by + rw [partialLeftAdjointHomEquiv_comp, partialLeftAdjointHomEquiv_map, assoc, + ← partialLeftAdjointHomEquiv_comp, id_comp] + +/-- Given `F : D ⥤ C`, this is the partial adjoint functor `F.PartialLeftAdjointSource ⥤ D`. -/ +@[simps] +noncomputable def partialLeftAdjoint : F.PartialLeftAdjointSource ⥤ D where + obj := F.partialLeftAdjointObj + map := F.partialLeftAdjointMap + map_id X := by + apply F.partialLeftAdjointHomEquiv.injective + dsimp + rw [partialLeftAdjointHomEquiv_map] + erw [id_comp] + map_comp {X Y Z} f g := by + apply F.partialLeftAdjointHomEquiv.injective + dsimp + rw [partialLeftAdjointHomEquiv_map, partialLeftAdjointHomEquiv_comp, + partialLeftAdjointHomEquiv_map, assoc] + erw [assoc] + rw [← F.partialLeftAdjointHomEquiv_comp, id_comp, + partialLeftAdjointHomEquiv_map] + +variable {F} + +lemma isRightAdjoint_of_leftAdjointObjIsDefined_eq_top + (h : F.LeftAdjointObjIsDefined = ⊤) : F.IsRightAdjoint := by + replace h : ∀ X, IsCorepresentable (F ⋙ coyoneda.obj (op X)) := fun X ↦ by + simp only [← leftAdjointObjIsDefined_iff, h, Pi.top_apply, Prop.top_eq_true] + exact (Adjunction.adjunctionOfEquivLeft + (fun X Y ↦ (F ⋙ coyoneda.obj (op X)).corepresentableBy.homEquiv) + (fun X Y Y' g f ↦ by apply CorepresentableBy.homEquiv_comp)).isRightAdjoint + +variable (F) in +lemma isRightAdjoint_iff_leftAdjointObjIsDefined_eq_top : + F.IsRightAdjoint ↔ F.LeftAdjointObjIsDefined = ⊤ := by + refine ⟨fun h ↦ ?_, isRightAdjoint_of_leftAdjointObjIsDefined_eq_top⟩ + ext X + simpa only [Pi.top_apply, Prop.top_eq_true, iff_true] + using leftAdjointObjIsDefined_of_adjunction (Adjunction.ofIsRightAdjoint F) X + +/-- Auxiliary definition for `leftAdjointObjIsDefined_of_isColimit`. -/ +noncomputable def corepresentableByCompCoyonedaObjOfIsColimit {J : Type*} [Category J] + {R : J ⥤ F.PartialLeftAdjointSource} + {c : Cocone (R ⋙ fullSubcategoryInclusion _)} (hc : IsColimit c) + {c' : Cocone (R ⋙ F.partialLeftAdjoint)} (hc' : IsColimit c') : + (F ⋙ coyoneda.obj (op c.pt)).CorepresentableBy c'.pt where + homEquiv {Y} := + { toFun := fun f ↦ hc.desc (Cocone.mk _ + { app := fun j ↦ F.partialLeftAdjointHomEquiv (c'.ι.app j ≫ f) + naturality := fun j j' φ ↦ by + dsimp + rw [comp_id, ← c'.w φ, ← partialLeftAdjointHomEquiv_map_comp, assoc] + dsimp }) + invFun := fun g ↦ hc'.desc (Cocone.mk _ + { app := fun j ↦ F.partialLeftAdjointHomEquiv.symm (c.ι.app j ≫ g) + naturality := fun j j' φ ↦ by + apply F.partialLeftAdjointHomEquiv.injective + have := c.w φ + dsimp at this ⊢ + rw [comp_id, Equiv.apply_symm_apply, partialLeftAdjointHomEquiv_map_comp, + Equiv.apply_symm_apply, reassoc_of% this] }) + left_inv := fun f ↦ hc'.hom_ext (fun j ↦ by simp) + right_inv := fun g ↦ hc.hom_ext (fun j ↦ by simp) } + homEquiv_comp {Y Y'} g f := hc.hom_ext (fun j ↦ by + dsimp + simp only [IsColimit.fac, IsColimit.fac_assoc, partialLeftAdjointHomEquiv_comp, + F.map_comp, assoc] ) + +lemma leftAdjointObjIsDefined_of_isColimit {J : Type*} [Category J] {R : J ⥤ C} {c : Cocone R} + (hc : IsColimit c) [HasColimitsOfShape J D] + (h : ∀ (j : J), F.LeftAdjointObjIsDefined (R.obj j)) : + F.LeftAdjointObjIsDefined c.pt := + (corepresentableByCompCoyonedaObjOfIsColimit + (R := FullSubcategory.lift _ R h) hc (colimit.isColimit _)).isCorepresentable + +lemma leftAdjointObjIsDefined_colimit {J : Type*} [Category J] (R : J ⥤ C) + [HasColimit R] [HasColimitsOfShape J D] + (h : ∀ (j : J), F.LeftAdjointObjIsDefined (R.obj j)) : + F.LeftAdjointObjIsDefined (colimit R) := + leftAdjointObjIsDefined_of_isColimit (colimit.isColimit R) h + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Adjunction/Reflective.lean b/Mathlib/CategoryTheory/Adjunction/Reflective.lean index 2ddd0414b0f2f..1c0c1c350dd0c 100644 --- a/Mathlib/CategoryTheory/Adjunction/Reflective.lean +++ b/Mathlib/CategoryTheory/Adjunction/Reflective.lean @@ -113,7 +113,7 @@ def unitCompPartialBijectiveAux [Reflective i] (A : C) (B : D) : theorem unitCompPartialBijectiveAux_symm_apply [Reflective i] {A : C} {B : D} (f : i.obj ((reflector i).obj A) ⟶ i.obj B) : (unitCompPartialBijectiveAux _ _).symm f = (reflectorAdjunction i).unit.app A ≫ f := by - simp [unitCompPartialBijectiveAux] + simp [unitCompPartialBijectiveAux, Adjunction.homEquiv_unit] /-- If `i` has a reflector `L`, then the function `(i.obj (L.obj A) ⟶ B) → (A ⟶ B)` given by precomposing with `η.app A` is a bijection provided `B` is in the essential image of `i`. diff --git a/Mathlib/CategoryTheory/Adjunction/Restrict.lean b/Mathlib/CategoryTheory/Adjunction/Restrict.lean index d3e8258ab5062..af50916ad19c8 100644 --- a/Mathlib/CategoryTheory/Adjunction/Restrict.lean +++ b/Mathlib/CategoryTheory/Adjunction/Restrict.lean @@ -27,6 +27,8 @@ variable {iC : C ⥤ C'} {iD : D ⥤ D'} {L' : C' ⥤ D'} {R' : D' ⥤ C'} (adj : L' ⊣ R') (hiC : iC.FullyFaithful) (hiD : iD.FullyFaithful) {L : C ⥤ D} {R : D ⥤ C} (comm1 : iC ⋙ L' ≅ L ⋙ iD) (comm2 : iD ⋙ R' ≅ R ⋙ iC) +attribute [local simp] homEquiv_unit homEquiv_counit + /-- If `C` is a full subcategory of `C'` and `D` is a full subcategory of `D'`, then we can restrict an adjunction `L' ⊣ R'` where `L' : C' ⥤ D'` and `R' : D' ⥤ C'` to `C` and `D`. The construction here is slightly more general, in that `C` is required only to have a full and diff --git a/Mathlib/CategoryTheory/Adjunction/Unique.lean b/Mathlib/CategoryTheory/Adjunction/Unique.lean index 9c4b07886fc7d..ec1dcbe176388 100644 --- a/Mathlib/CategoryTheory/Adjunction/Unique.lean +++ b/Mathlib/CategoryTheory/Adjunction/Unique.lean @@ -26,11 +26,12 @@ variable {C D : Type*} [Category C] [Category D] namespace CategoryTheory.Adjunction +attribute [local simp] homEquiv_unit homEquiv_counit + /-- If `F` and `F'` are both left adjoint to `G`, then they are naturally isomorphic. -/ def leftAdjointUniq {F F' : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F' ⊣ G) : F ≅ F' := ((conjugateIsoEquiv adj1 adj2).symm (Iso.refl G)).symm --- Porting note (#10618): removed simp as simp can prove this theorem homEquiv_leftAdjointUniq_hom_app {F F' : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F' ⊣ G) (x : C) : adj1.homEquiv _ _ ((leftAdjointUniq adj1 adj2).hom.app x) = adj2.unit.app x := by simp [leftAdjointUniq] @@ -94,7 +95,6 @@ theorem leftAdjointUniq_refl {F : C ⥤ D} {G : D ⥤ C} (adj1 : F ⊣ G) : def rightAdjointUniq {F : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F ⊣ G') : G ≅ G' := conjugateIsoEquiv adj1 adj2 (Iso.refl _) --- Porting note (#10618): simp can prove this theorem homEquiv_symm_rightAdjointUniq_hom_app {F : C ⥤ D} {G G' : D ⥤ C} (adj1 : F ⊣ G) (adj2 : F ⊣ G') (x : D) : (adj2.homEquiv _ _).symm ((rightAdjointUniq adj1 adj2).hom.app x) = adj1.counit.app x := by diff --git a/Mathlib/CategoryTheory/Bicategory/Coherence.lean b/Mathlib/CategoryTheory/Bicategory/Coherence.lean index 8721c45df98f3..b1191ecc4f21c 100644 --- a/Mathlib/CategoryTheory/Bicategory/Coherence.lean +++ b/Mathlib/CategoryTheory/Bicategory/Coherence.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno, Junyan Xu -/ -import Mathlib.CategoryTheory.PathCategory +import Mathlib.CategoryTheory.PathCategory.Basic import Mathlib.CategoryTheory.Functor.FullyFaithful import Mathlib.CategoryTheory.Bicategory.Free import Mathlib.CategoryTheory.Bicategory.LocallyDiscrete @@ -187,7 +187,7 @@ def normalize (B : Type u) [Quiver.{v + 1} B] : obj a := ⟨a⟩ map f := ⟨normalizeAux nil f⟩ map₂ η := eqToHom <| Discrete.ext <| normalizeAux_congr nil η - mapId a := eqToIso <| Discrete.ext rfl + mapId _ := eqToIso <| Discrete.ext rfl mapComp f g := eqToIso <| Discrete.ext <| normalizeAux_nil_comp f g /-- Auxiliary definition for `normalizeEquiv`. -/ @@ -232,7 +232,7 @@ def inclusion (B : Type u) [Quiver.{v + 1} B] : Pseudofunctor (LocallyDiscrete (Paths B)) (FreeBicategory B) := { -- All the conditions for 2-morphisms are trivial thanks to the coherence theorem! preinclusion B with - mapId := fun a => Iso.refl _ + mapId := fun _ => Iso.refl _ mapComp := fun f g => inclusionMapCompAux f.as g.as } end FreeBicategory diff --git a/Mathlib/CategoryTheory/Bicategory/End.lean b/Mathlib/CategoryTheory/Bicategory/End.lean index 8210d2a2cdcd0..a231874f15b0d 100644 --- a/Mathlib/CategoryTheory/Bicategory/End.lean +++ b/Mathlib/CategoryTheory/Bicategory/End.lean @@ -36,8 +36,8 @@ open Bicategory attribute [local simp] EndMonoidal in instance (X : C) : MonoidalCategory (EndMonoidal X) where tensorObj f g := f ≫ g - whiskerLeft {f g h} η := f ◁ η - whiskerRight {f g} η h := η ▷ h + whiskerLeft {f _ _} η := f ◁ η + whiskerRight {_ _} η h := η ▷ h tensorUnit := 𝟙 _ associator f g h := α_ f g h leftUnitor f := λ_ f diff --git a/Mathlib/CategoryTheory/Bicategory/Extension.lean b/Mathlib/CategoryTheory/Bicategory/Extension.lean index 898bc3c43dd3e..5f371e5ffbfee 100644 --- a/Mathlib/CategoryTheory/Bicategory/Extension.lean +++ b/Mathlib/CategoryTheory/Bicategory/Extension.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ import Mathlib.CategoryTheory.Bicategory.Basic -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic /-! # Extensions and lifts in bicategories diff --git a/Mathlib/CategoryTheory/Bicategory/Free.lean b/Mathlib/CategoryTheory/Bicategory/Free.lean index e423dd24b31be..8241aa309f05e 100644 --- a/Mathlib/CategoryTheory/Bicategory/Free.lean +++ b/Mathlib/CategoryTheory/Bicategory/Free.lean @@ -148,7 +148,7 @@ end instance homCategory (a b : FreeBicategory B) : Category (a ⟶ b) where Hom f g := Quot (@Rel _ _ a b f g) id f := Quot.mk Rel (Hom₂.id f) - comp := @fun f g h => Quot.map₂ Hom₂.vcomp Rel.vcomp_right Rel.vcomp_left + comp := @fun _ _ _ => Quot.map₂ Hom₂.vcomp Rel.vcomp_right Rel.vcomp_left id_comp := by rintro f g ⟨η⟩ exact Quot.sound (Rel.id_comp η) @@ -162,19 +162,19 @@ instance homCategory (a b : FreeBicategory B) : Category (a ⟶ b) where /-- Bicategory structure on the free bicategory. -/ instance bicategory : Bicategory (FreeBicategory B) where homCategory := @fun (a b : B) => FreeBicategory.homCategory a b - whiskerLeft := @fun a b c f g h η => Quot.map (Hom₂.whisker_left f) (Rel.whisker_left f g h) η - whiskerLeft_id := @fun a b c f g => Quot.sound (Rel.whisker_left_id f g) - associator := @fun a b c d f g h => + whiskerLeft := @fun _ _ _ f g h η => Quot.map (Hom₂.whisker_left f) (Rel.whisker_left f g h) η + whiskerLeft_id := @fun _ _ _ f g => Quot.sound (Rel.whisker_left_id f g) + associator := @fun _ _ _ _ f g h => { hom := Quot.mk Rel (Hom₂.associator f g h) inv := Quot.mk Rel (Hom₂.associator_inv f g h) hom_inv_id := Quot.sound (Rel.associator_hom_inv f g h) inv_hom_id := Quot.sound (Rel.associator_inv_hom f g h) } - leftUnitor := @fun a b f => + leftUnitor := @fun _ _ f => { hom := Quot.mk Rel (Hom₂.left_unitor f) inv := Quot.mk Rel (Hom₂.left_unitor_inv f) hom_inv_id := Quot.sound (Rel.left_unitor_hom_inv f) inv_hom_id := Quot.sound (Rel.left_unitor_inv_hom f) } - rightUnitor := @fun a b f => + rightUnitor := @fun _ _ f => { hom := Quot.mk Rel (Hom₂.right_unitor f) inv := Quot.mk Rel (Hom₂.right_unitor_inv f) hom_inv_id := Quot.sound (Rel.right_unitor_hom_inv f) @@ -188,8 +188,8 @@ instance bicategory : Bicategory (FreeBicategory B) where comp_whiskerLeft := by rintro a b c d f g h h' ⟨η⟩ exact Quot.sound (Rel.comp_whisker_left f g η) - whiskerRight := @fun a b c f g η h => Quot.map (Hom₂.whisker_right h) (Rel.whisker_right f g h) η - id_whiskerRight := @fun a b c f g => Quot.sound (Rel.id_whisker_right f g) + whiskerRight := @fun _ _ _ f g η h => Quot.map (Hom₂.whisker_right h) (Rel.whisker_right f g h) η + id_whiskerRight := @fun _ _ _ f g => Quot.sound (Rel.id_whisker_right f g) comp_whiskerRight := by rintro a b c f g h ⟨η⟩ ⟨θ⟩ i exact Quot.sound (Rel.comp_whisker_right i η θ) @@ -205,8 +205,8 @@ instance bicategory : Bicategory (FreeBicategory B) where whisker_exchange := by rintro a b c f g h i ⟨η⟩ ⟨θ⟩ exact Quot.sound (Rel.whisker_exchange η θ) - pentagon := @fun a b c d e f g h i => Quot.sound (Rel.pentagon f g h i) - triangle := @fun a b c f g => Quot.sound (Rel.triangle f g) + pentagon := @fun _ _ _ _ _ f g h i => Quot.sound (Rel.pentagon f g h i) + triangle := @fun _ _ _ f g => Quot.sound (Rel.triangle f g) variable {a b c d : FreeBicategory B} @@ -327,9 +327,9 @@ theorem liftHom₂_congr {a b : FreeBicategory B} {f g : a ⟶ b} {η θ : Hom def lift : Pseudofunctor (FreeBicategory B) C where obj := F.obj map := liftHom F - mapId a := Iso.refl _ - mapComp f g := Iso.refl _ - map₂ := Quot.lift (liftHom₂ F) fun η θ H => liftHom₂_congr F H + mapId _ := Iso.refl _ + mapComp _ _ := Iso.refl _ + map₂ := Quot.lift (liftHom₂ F) fun _ _ H => liftHom₂_congr F H -- Porting note: We'd really prefer not to be doing this by hand. -- in mathlib3 `tidy` did these inductions for us. map₂_comp := by diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/LocallyDiscrete.lean b/Mathlib/CategoryTheory/Bicategory/Functor/LocallyDiscrete.lean new file mode 100644 index 0000000000000..592c7e48b5551 --- /dev/null +++ b/Mathlib/CategoryTheory/Bicategory/Functor/LocallyDiscrete.lean @@ -0,0 +1,157 @@ +/- +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.Bicategory.Functor.Pseudofunctor +import Mathlib.CategoryTheory.Bicategory.LocallyDiscrete + +/-! +# Pseudofunctors from locally discrete bicategories + +This file provides various ways of constructing pseudofunctors from locally discrete +bicategories. + +Firstly, we define the constructors `pseudofunctorOfIsLocallyDiscrete` and +`oplaxFunctorOfIsLocallyDiscrete` for defining pseudofunctors and oplax functors +from a locally discrete bicategories. In this situation, we do not need to care about +the field `map₂`, because all the `2`-morphisms in `B` are identities. + +We also define a specialized constructor `LocallyDiscrete.mkPseudofunctor` when +the source bicategory is of the form `B := LocallyDiscrete B₀` for a category `B₀`. + +We also prove that a functor `F : I ⥤ B` with `B` a strict bicategory can be promoted +to a pseudofunctor (or oplax functor) (`Functor.toPseudofunctor`) with domain +`LocallyDiscrete I`. + +-/ + +namespace CategoryTheory + +open Bicategory + +/-- Constructor for pseudofunctors from a locally discrete bicategory. In that +case, we do not need to provide the `map₂` field of pseudofunctors. -/ +@[simps obj map mapId mapComp] +def pseudofunctorOfIsLocallyDiscrete + {B C : Type*} [Bicategory B] [IsLocallyDiscrete B] [Bicategory C] + (obj : B → C) + (map : ∀ {b b' : B}, (b ⟶ b') → (obj b ⟶ obj b')) + (mapId : ∀ (b : B), map (𝟙 b) ≅ 𝟙 _) + (mapComp : ∀ {b₀ b₁ b₂ : B} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂), map (f ≫ g) ≅ map f ≫ map g) + (map₂_associator : ∀ {b₀ b₁ b₂ b₃ : B} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂) (h : b₂ ⟶ b₃), + (mapComp (f ≫ g) h).hom ≫ + (mapComp f g).hom ▷ map h ≫ (α_ (map f) (map g) (map h)).hom ≫ + map f ◁ (mapComp g h).inv ≫ (mapComp f (g ≫ h)).inv = eqToHom (by simp) := by aesop_cat) + (map₂_left_unitor : ∀ {b₀ b₁ : B} (f : b₀ ⟶ b₁), + (mapComp (𝟙 b₀) f).hom ≫ (mapId b₀).hom ▷ map f ≫ (λ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) + (map₂_right_unitor : ∀ {b₀ b₁ : B} (f : b₀ ⟶ b₁), + (mapComp f (𝟙 b₁)).hom ≫ map f ◁ (mapId b₁).hom ≫ (ρ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) : + Pseudofunctor B C where + obj := obj + map := map + map₂ φ := eqToHom (by + obtain rfl := obj_ext_of_isDiscrete φ + dsimp) + mapId := mapId + mapComp := mapComp + map₂_whisker_left _ _ _ η := by + obtain rfl := obj_ext_of_isDiscrete η + simp + map₂_whisker_right η _ := by + obtain rfl := obj_ext_of_isDiscrete η + simp + +/-- Constructor for oplax functors from a locally discrete bicategory. In that +case, we do not need to provide the `map₂` field of oplax functors. -/ +@[simps obj map mapId mapComp] +def oplaxFunctorOfIsLocallyDiscrete + {B C : Type*} [Bicategory B] [IsLocallyDiscrete B] [Bicategory C] + (obj : B → C) + (map : ∀ {b b' : B}, (b ⟶ b') → (obj b ⟶ obj b')) + (mapId : ∀ (b : B), map (𝟙 b) ⟶ 𝟙 _) + (mapComp : ∀ {b₀ b₁ b₂ : B} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂), map (f ≫ g) ⟶ map f ≫ map g) + (map₂_associator : ∀ {b₀ b₁ b₂ b₃ : B} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂) (h : b₂ ⟶ b₃), + eqToHom (by simp) ≫ mapComp f (g ≫ h) ≫ map f ◁ mapComp g h = + mapComp (f ≫ g) h ≫ mapComp f g ▷ map h ≫ (α_ (map f) (map g) (map h)).hom := by + aesop_cat) + (map₂_left_unitor : ∀ {b₀ b₁ : B} (f : b₀ ⟶ b₁), + mapComp (𝟙 b₀) f ≫ mapId b₀ ▷ map f ≫ (λ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) + (map₂_right_unitor : ∀ {b₀ b₁ : B} (f : b₀ ⟶ b₁), + mapComp f (𝟙 b₁) ≫ map f ◁ mapId b₁ ≫ (ρ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) : + OplaxFunctor B C where + obj := obj + map := map + map₂ φ := eqToHom (by + obtain rfl := obj_ext_of_isDiscrete φ + dsimp) + mapId := mapId + mapComp := mapComp + mapComp_naturality_left η := by + obtain rfl := obj_ext_of_isDiscrete η + simp + mapComp_naturality_right _ _ _ η := by + obtain rfl := obj_ext_of_isDiscrete η + simp + +section + +variable {I B : Type*} [Category I] [Bicategory B] [Strict B] (F : I ⥤ B) + +attribute [local simp] + Strict.leftUnitor_eqToIso Strict.rightUnitor_eqToIso Strict.associator_eqToIso + +/-- +If `B` is a strict bicategory and `I` is a (1-)category, any functor (of 1-categories) `I ⥤ B` can +be promoted to a pseudofunctor from `LocallyDiscrete I` to `B`. +-/ +@[simps! obj map mapId mapComp] +def Functor.toPseudoFunctor : Pseudofunctor (LocallyDiscrete I) B := + pseudofunctorOfIsLocallyDiscrete + (fun ⟨X⟩ ↦ F.obj X) (fun ⟨f⟩ ↦ F.map f) + (fun ⟨X⟩ ↦ eqToIso (by simp)) (fun f g ↦ eqToIso (by simp)) + +/-- +If `B` is a strict bicategory and `I` is a (1-)category, any functor (of 1-categories) `I ⥤ B` can +be promoted to an oplax functor from `LocallyDiscrete I` to `B`. +-/ +@[simps! obj map mapId mapComp] +def Functor.toOplaxFunctor : OplaxFunctor (LocallyDiscrete I) B := + oplaxFunctorOfIsLocallyDiscrete + (fun ⟨X⟩ ↦ F.obj X) (fun ⟨f⟩ ↦ F.map f) + (fun ⟨X⟩ ↦ eqToHom (by simp)) (fun f g ↦ eqToHom (by simp)) + +end + +namespace LocallyDiscrete + +/-- Constructor for pseudofunctors from a locally discrete bicategory. In that +case, we do not need to provide the `map₂` field of pseudofunctors. -/ +@[simps! obj map mapId mapComp] +def mkPseudofunctor {B₀ C : Type*} [Category B₀] [Bicategory C] + (obj : B₀ → C) + (map : ∀ {b b' : B₀}, (b ⟶ b') → (obj b ⟶ obj b')) + (mapId : ∀ (b : B₀), map (𝟙 b) ≅ 𝟙 _) + (mapComp : ∀ {b₀ b₁ b₂ : B₀} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂), map (f ≫ g) ≅ map f ≫ map g) + (map₂_associator : ∀ {b₀ b₁ b₂ b₃ : B₀} (f : b₀ ⟶ b₁) (g : b₁ ⟶ b₂) (h : b₂ ⟶ b₃), + (mapComp (f ≫ g) h).hom ≫ + (mapComp f g).hom ▷ map h ≫ (α_ (map f) (map g) (map h)).hom ≫ + map f ◁ (mapComp g h).inv ≫ (mapComp f (g ≫ h)).inv = eqToHom (by simp) := by aesop_cat) + (map₂_left_unitor : ∀ {b₀ b₁ : B₀} (f : b₀ ⟶ b₁), + (mapComp (𝟙 b₀) f).hom ≫ (mapId b₀).hom ▷ map f ≫ (λ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) + (map₂_right_unitor : ∀ {b₀ b₁ : B₀} (f : b₀ ⟶ b₁), + (mapComp f (𝟙 b₁)).hom ≫ map f ◁ (mapId b₁).hom ≫ (ρ_ (map f)).hom = eqToHom (by simp) := by + aesop_cat) : + Pseudofunctor (LocallyDiscrete B₀) C := + pseudofunctorOfIsLocallyDiscrete (fun b ↦ obj b.as) (fun f ↦ map f.as) + (fun _ ↦ mapId _) (fun _ _ ↦ mapComp _ _) (fun _ _ _ ↦ map₂_associator _ _ _) + (fun _ ↦ map₂_left_unitor _) (fun _ ↦ map₂_right_unitor _) + +end LocallyDiscrete + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean index 5cace28c07436..f7bb524702e5c 100644 --- a/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean +++ b/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean @@ -76,8 +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 -variable (F : PrelaxFunctorStruct B C) - -- 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` diff --git a/Mathlib/CategoryTheory/Bicategory/FunctorBicategory.lean b/Mathlib/CategoryTheory/Bicategory/FunctorBicategory/Oplax.lean similarity index 88% rename from Mathlib/CategoryTheory/Bicategory/FunctorBicategory.lean rename to Mathlib/CategoryTheory/Bicategory/FunctorBicategory/Oplax.lean index 121c253c24500..02482d12bfd09 100644 --- a/Mathlib/CategoryTheory/Bicategory/FunctorBicategory.lean +++ b/Mathlib/CategoryTheory/Bicategory/FunctorBicategory/Oplax.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ -import Mathlib.CategoryTheory.Bicategory.NaturalTransformation.Oplax +import Mathlib.CategoryTheory.Bicategory.Modification.Oplax /-! # The bicategory of oplax functors between two bicategories @@ -17,7 +17,7 @@ Given bicategories `B` and `C`, we give a bicategory structure on `OplaxFunctor namespace CategoryTheory -open Category Bicategory +open Category Bicategory Oplax open scoped Bicategory @@ -72,11 +72,11 @@ variable (B C) -- Porting note: verified that projections are correct and changed @[simps] to @[simps!] @[simps!] instance OplaxFunctor.bicategory : Bicategory (OplaxFunctor B C) where - whiskerLeft {F G H} η _ _ Γ := OplaxNatTrans.whiskerLeft η Γ - whiskerRight {F G H} _ _ Γ η := OplaxNatTrans.whiskerRight Γ η - associator {F G H} I := OplaxNatTrans.associator - leftUnitor {F G} := OplaxNatTrans.leftUnitor - rightUnitor {F G} := OplaxNatTrans.rightUnitor + whiskerLeft {_ _ _} η _ _ Γ := OplaxNatTrans.whiskerLeft η Γ + whiskerRight {_ _ _} _ _ Γ η := OplaxNatTrans.whiskerRight Γ η + associator {_ _ _} _ := OplaxNatTrans.associator + leftUnitor {_ _} := OplaxNatTrans.leftUnitor + rightUnitor {_ _} := OplaxNatTrans.rightUnitor whisker_exchange {a b c f g h i} η θ := by ext exact whisker_exchange _ _ diff --git a/Mathlib/CategoryTheory/Bicategory/Grothendieck.lean b/Mathlib/CategoryTheory/Bicategory/Grothendieck.lean new file mode 100644 index 0000000000000..efb94ebc6c24a --- /dev/null +++ b/Mathlib/CategoryTheory/Bicategory/Grothendieck.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2024 Calle Sönne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Calle Sönne +-/ + +import Mathlib.CategoryTheory.Bicategory.LocallyDiscrete +import Mathlib.CategoryTheory.Bicategory.Functor.Pseudofunctor + +/-! +# The Grothendieck construction + +Given a category `𝒮` and any pseudofunctor `F` from `𝒮ᵒᵖ` to `Cat`, we associate to it a category +`∫ F`, equipped with a functor `∫ F ⥤ 𝒮`. + +The category `∫ F` is defined as follows: +* Objects: pairs `(S, a)` where `S` is an object of the base category and `a` is an object of the + category `F(S)`. +* Morphisms: morphisms `(R, b) ⟶ (S, a)` are defined as pairs `(f, h)` where `f : R ⟶ S` is a + morphism in `𝒮` and `h : b ⟶ F(f)(a)` + +The projection functor `∫ F ⥤ 𝒮` is then given by projecting to the first factors, i.e. +* On objects, it sends `(S, a)` to `S` +* On morphisms, it sends `(f, h)` to `f` + +## References +[Vistoli2008] "Notes on Grothendieck Topologies, Fibered Categories and Descent Theory" by +Angelo Vistoli +-/ + +namespace CategoryTheory + +universe w v₁ v₂ v₃ u₁ u₂ u₃ + +open CategoryTheory Functor Category Opposite Discrete Bicategory + +variable {𝒮 : Type u₁} [Category.{v₁} 𝒮] {F : Pseudofunctor (LocallyDiscrete 𝒮ᵒᵖ) Cat.{v₂, u₂}} + +/-- The type of objects in the fibered category associated to a presheaf valued in types. -/ +@[ext] +structure Pseudofunctor.Grothendieck (F : Pseudofunctor (LocallyDiscrete 𝒮ᵒᵖ) Cat.{v₂, u₂}) where + /-- The underlying object in the base category. -/ + base : 𝒮 + /-- The object in the fiber of the base object. -/ + fiber : F.obj ⟨op base⟩ + +namespace Pseudofunctor.Grothendieck + +/-- Notation for the Grothendieck category associated to a pseudofunctor `F`. -/ +scoped prefix:75 "∫ " => Pseudofunctor.Grothendieck + +/-- A morphism in the Grothendieck category `F : C ⥤ Cat` consists of +`base : X.base ⟶ Y.base` and `f.fiber : (F.map base).obj X.fiber ⟶ Y.fiber`. +-/ +structure Hom (X Y : ∫ F) where + /-- The morphism between base objects. -/ + base : X.base ⟶ Y.base + /-- The morphism in the fiber over the domain. -/ + fiber : X.fiber ⟶ (F.map base.op.toLoc).obj Y.fiber + +@[simps!] +instance categoryStruct : CategoryStruct (∫ F) where + Hom X Y := Hom X Y + id X := { + base := 𝟙 X.base + fiber := (F.mapId ⟨op X.base⟩).inv.app X.fiber } + comp {_ _ Z} f g := { + base := f.base ≫ g.base + fiber := f.fiber ≫ (F.map f.base.op.toLoc).map g.fiber ≫ + (F.mapComp g.base.op.toLoc f.base.op.toLoc).inv.app Z.fiber } + +section + +variable {a b : ∫ F} + +@[ext (iff := false)] +lemma Hom.ext (f g : a ⟶ b) (hfg₁ : f.base = g.base) + (hfg₂ : f.fiber = g.fiber ≫ eqToHom (hfg₁ ▸ rfl)) : f = g := by + cases f; cases g + congr + dsimp at hfg₁ + rw [← conj_eqToHom_iff_heq _ _ rfl (hfg₁ ▸ rfl)] + simpa only [eqToHom_refl, id_comp] using hfg₂ + +lemma Hom.ext_iff (f g : a ⟶ b) : + f = g ↔ ∃ (hfg : f.base = g.base), f.fiber = g.fiber ≫ eqToHom (hfg ▸ rfl) where + mp hfg := ⟨by rw [hfg], by simp [hfg]⟩ + mpr := fun ⟨hfg₁, hfg₂⟩ => Hom.ext f g hfg₁ hfg₂ + +lemma Hom.congr {a b : ∫ F} {f g : a ⟶ b} (h : f = g) : + f.fiber = g.fiber ≫ eqToHom (h ▸ rfl) := by + simp [h] + +end + +/-- The category structure on `∫ F`. -/ +instance category : Category (∫ F) where + toCategoryStruct := Pseudofunctor.Grothendieck.categoryStruct + id_comp {a b} f := by + ext + · simp + · simp [F.mapComp_id_right_inv_app, Strict.rightUnitor_eqToIso, ← NatTrans.naturality_assoc] + comp_id {a b} f := by + ext + · simp + · simp [F.mapComp_id_left_inv_app, ← Functor.map_comp_assoc, Strict.leftUnitor_eqToIso] + assoc f g h := by + ext + · simp + · simp [← NatTrans.naturality_assoc, F.mapComp_assoc_right_inv_app, Strict.associator_eqToIso] + +variable (F) + +/-- The projection `∫ F ⥤ 𝒮` given by projecting both objects and homs to the first +factor. -/ +@[simps] +def forget : ∫ F ⥤ 𝒮 where + obj X := X.base + map f := f.base + +end Pseudofunctor.Grothendieck + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Bicategory/Kan/HasKan.lean b/Mathlib/CategoryTheory/Bicategory/Kan/HasKan.lean index e81755e4324af..40043a409ecfe 100644 --- a/Mathlib/CategoryTheory/Bicategory/Kan/HasKan.lean +++ b/Mathlib/CategoryTheory/Bicategory/Kan/HasKan.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ +import Mathlib.CategoryTheory.Limits.Shapes.Terminal import Mathlib.CategoryTheory.Bicategory.Kan.IsKan /-! diff --git a/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean b/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean index 3ddbc22d951aa..7db3d423d41ad 100644 --- a/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean +++ b/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno, Calle Sönne -/ import Mathlib.CategoryTheory.DiscreteCategory -import Mathlib.CategoryTheory.Bicategory.Functor.Pseudofunctor +import Mathlib.CategoryTheory.Bicategory.Functor.Prelax import Mathlib.CategoryTheory.Bicategory.Strict /-! @@ -21,8 +21,6 @@ namespace CategoryTheory open Bicategory Discrete -open Bicategory - universe w₂ w₁ v₂ v₁ v u₂ u₁ u section @@ -94,46 +92,17 @@ variable [Category.{v} C] equalities between 1-morphisms. -/ instance locallyDiscreteBicategory : Bicategory (LocallyDiscrete C) where - whiskerLeft f g h η := eqToHom (congr_arg₂ (· ≫ ·) rfl (LocallyDiscrete.eq_of_hom η)) - whiskerRight η h := eqToHom (congr_arg₂ (· ≫ ·) (LocallyDiscrete.eq_of_hom η) rfl) + whiskerLeft _ _ _ η := eqToHom (congr_arg₂ (· ≫ ·) rfl (LocallyDiscrete.eq_of_hom η)) + whiskerRight η _ := eqToHom (congr_arg₂ (· ≫ ·) (LocallyDiscrete.eq_of_hom η) rfl) associator f g h := eqToIso <| by apply Discrete.ext; simp leftUnitor f := eqToIso <| by apply Discrete.ext; simp rightUnitor f := eqToIso <| by apply Discrete.ext; simp /-- A locally discrete bicategory is strict. -/ instance locallyDiscreteBicategory.strict : Strict (LocallyDiscrete C) where - id_comp f := Discrete.ext (Category.id_comp _) - comp_id f := Discrete.ext (Category.comp_id _) - assoc f g h := Discrete.ext (Category.assoc _ _ _) - -attribute [local simp] - Strict.leftUnitor_eqToIso Strict.rightUnitor_eqToIso Strict.associator_eqToIso - -variable {I : Type u₁} [Category.{v₁} I] {B : Type u₂} [Bicategory.{w₂, v₂} B] [Strict B] - -/-- -If `B` is a strict bicategory and `I` is a (1-)category, any functor (of 1-categories) `I ⥤ B` can -be promoted to a pseudofunctor from `LocallyDiscrete I` to `B`. --/ -@[simps] -def Functor.toPseudoFunctor (F : I ⥤ B) : Pseudofunctor (LocallyDiscrete I) B where - obj i := F.obj i.as - map f := F.map f.as - map₂ η := eqToHom (congr_arg _ (LocallyDiscrete.eq_of_hom η)) - mapId i := eqToIso (F.map_id i.as) - mapComp f g := eqToIso (F.map_comp f.as g.as) - -/-- -If `B` is a strict bicategory and `I` is a (1-)category, any functor (of 1-categories) `I ⥤ B` can -be promoted to an oplax functor from `LocallyDiscrete I` to `B`. --/ -@[simps] -def Functor.toOplaxFunctor (F : I ⥤ B) : OplaxFunctor (LocallyDiscrete I) B where - obj i := F.obj i.as - map f := F.map f.as - map₂ η := eqToHom (congr_arg _ (LocallyDiscrete.eq_of_hom η)) - mapId i := eqToHom (F.map_id i.as) - mapComp f g := eqToHom (F.map_comp f.as g.as) + id_comp _ := Discrete.ext (Category.id_comp _) + comp_id _ := Discrete.ext (Category.comp_id _) + assoc _ _ _ := Discrete.ext (Category.assoc _ _ _) end @@ -148,6 +117,21 @@ lemma PrelaxFunctor.map₂_eqToHom (F : PrelaxFunctor B C) {a b : B} {f g : a end +namespace Bicategory + +/-- A bicategory is locally discrete if the categories of 1-morphisms are discrete. -/ +abbrev IsLocallyDiscrete (B : Type*) [Bicategory B] := ∀ (b c : B), IsDiscrete (b ⟶ c) + +instance (C : Type*) [Category C] : IsLocallyDiscrete (LocallyDiscrete C) := + fun _ _ ↦ Discrete.isDiscrete _ + +instance (B : Type*) [Bicategory B] [IsLocallyDiscrete B] : Strict B where + id_comp f := obj_ext_of_isDiscrete (leftUnitor f).hom + comp_id f := obj_ext_of_isDiscrete (rightUnitor f).hom + assoc f g h := obj_ext_of_isDiscrete (associator f g h).hom + +end Bicategory + end CategoryTheory section diff --git a/Mathlib/CategoryTheory/Bicategory/Modification/Oplax.lean b/Mathlib/CategoryTheory/Bicategory/Modification/Oplax.lean new file mode 100644 index 0000000000000..88fc6d73f8f0f --- /dev/null +++ b/Mathlib/CategoryTheory/Bicategory/Modification/Oplax.lean @@ -0,0 +1,134 @@ +/- +Copyright (c) 2024 Calle Sönne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yuma Mizuno, Calle Sönne +-/ + +import Mathlib.CategoryTheory.Bicategory.NaturalTransformation.Oplax + +/-! +# Modifications between oplax transformations + +A modification `Γ` between oplax transformations `η` and `θ` consists of a family of +2-morphisms `Γ.app a : η.app a ⟶ θ.app a`, which satisfies the equation +`(F.map f ◁ app b) ≫ θ.naturality f = η.naturality f ≫ (app a ▷ G.map f)` +for each 1-morphism `f : a ⟶ b`. + +## Main definitions + +* `Modification η θ` : modifications between oplax transformations `η` and `θ` +* `Modification.vcomp η θ` : the vertical composition of oplax transformations `η` + and `θ` +* `OplaxTrans.category F G` : the category structure on the oplax transformations + between `F` and `G` + +-/ + +namespace CategoryTheory.Oplax + +open Category Bicategory + +universe w₁ w₂ v₁ v₂ u₁ u₂ + +variable {B : Type u₁} [Bicategory.{w₁, v₁} B] {C : Type u₂} [Bicategory.{w₂, v₂} C] + {F G : OplaxFunctor B C} (η θ : F ⟶ G) + +variable {F G : OplaxFunctor B C} + +/-- A modification `Γ` between oplax natural transformations `η` and `θ` consists of a family of +2-morphisms `Γ.app a : η.app a ⟶ θ.app a`, which satisfies the equation +`(F.map f ◁ app b) ≫ θ.naturality f = η.naturality f ≫ (app a ▷ G.map f)` +for each 1-morphism `f : a ⟶ b`. +-/ +@[ext] +structure Modification (η θ : F ⟶ G) where + /-- The underlying family of 2-morphism. -/ + app (a : B) : η.app a ⟶ θ.app a + /-- The naturality condition. -/ + naturality : + ∀ {a b : B} (f : a ⟶ b), + F.map f ◁ app b ≫ θ.naturality f = η.naturality f ≫ app a ▷ G.map f := by + aesop_cat + +attribute [reassoc (attr := simp)] Modification.naturality + +variable {η θ ι : F ⟶ G} + +namespace Modification + +variable (η) + +/-- The identity modification. -/ +@[simps] +def id : Modification η η where app a := 𝟙 (η.app a) + +instance : Inhabited (Modification η η) := + ⟨Modification.id η⟩ + +variable {η} + +section + +variable (Γ : Modification η θ) {a b c : B} {a' : C} + +@[reassoc (attr := simp)] +theorem whiskerLeft_naturality (f : a' ⟶ F.obj b) (g : b ⟶ c) : + f ◁ F.map g ◁ Γ.app c ≫ f ◁ θ.naturality g = f ◁ η.naturality g ≫ f ◁ Γ.app b ▷ G.map g := by + simp_rw [← Bicategory.whiskerLeft_comp, naturality] + +@[reassoc (attr := simp)] +theorem whiskerRight_naturality (f : a ⟶ b) (g : G.obj b ⟶ a') : + F.map f ◁ Γ.app b ▷ g ≫ (α_ _ _ _).inv ≫ θ.naturality f ▷ g = + (α_ _ _ _).inv ≫ η.naturality f ▷ g ≫ Γ.app a ▷ G.map f ▷ g := by + simp_rw [associator_inv_naturality_middle_assoc, ← comp_whiskerRight, naturality] + +end + +/-- Vertical composition of modifications. -/ +@[simps] +def vcomp (Γ : Modification η θ) (Δ : Modification θ ι) : Modification η ι where + app a := Γ.app a ≫ Δ.app a + +end Modification + +/-- Category structure on the oplax natural transformations between OplaxFunctors. -/ +@[simps] +instance category (F G : OplaxFunctor B C) : Category (F ⟶ G) where + Hom := Modification + id := Modification.id + comp := Modification.vcomp + +@[ext] +lemma ext {F G : OplaxFunctor B C} {α β : F ⟶ G} {m n : α ⟶ β} (w : ∀ b, m.app b = n.app b) : + m = n := by + apply Modification.ext + ext + apply w + +/-- Version of `Modification.id_app` using category notation -/ +@[simp] +lemma Modification.id_app' {X : B} {F G : OplaxFunctor B C} (α : F ⟶ G) : + Modification.app (𝟙 α) X = 𝟙 (α.app X) := rfl + +/-- Version of `Modification.comp_app` using category notation -/ +@[simp] +lemma Modification.comp_app' {X : B} {F G : OplaxFunctor B C} {α β γ : F ⟶ G} + (m : α ⟶ β) (n : β ⟶ γ) : (m ≫ n).app X = m.app X ≫ n.app X := + rfl + +/-- Construct a modification isomorphism between oplax natural transformations +by giving object level isomorphisms, and checking naturality only in the forward direction. +-/ +@[simps] +def ModificationIso.ofComponents (app : ∀ a, η.app a ≅ θ.app a) + (naturality : + ∀ {a b} (f : a ⟶ b), + F.map f ◁ (app b).hom ≫ θ.naturality f = η.naturality f ≫ (app a).hom ▷ G.map f) : + η ≅ θ where + hom := { app := fun a => (app a).hom } + inv := + { app := fun a => (app a).inv + naturality := fun {a b} f => by + simpa using congr_arg (fun f => _ ◁ (app b).inv ≫ f ≫ (app a).inv ▷ _) (naturality f).symm } + +end CategoryTheory.Oplax diff --git a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean index d6c4159d767cf..0d8ff2f83325f 100644 --- a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean +++ b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean @@ -77,7 +77,7 @@ variable (F : OplaxFunctor B C) @[simps] def id : OplaxNatTrans F F where app a := 𝟙 (F.obj a) - naturality {a b} f := (ρ_ (F.map f)).hom ≫ (λ_ (F.map f)).inv + naturality {_ _} f := (ρ_ (F.map f)).hom ≫ (λ_ (F.map f)).inv instance : Inhabited (OplaxNatTrans F F) := ⟨id F⟩ @@ -174,111 +174,6 @@ instance : CategoryStruct (OplaxFunctor B C) where end -section - -variable {F G : OplaxFunctor B C} - -/-- A modification `Γ` between oplax natural transformations `η` and `θ` consists of a family of -2-morphisms `Γ.app a : η.app a ⟶ θ.app a`, which satisfies the equation -`(F.map f ◁ app b) ≫ θ.naturality f = η.naturality f ≫ (app a ▷ G.map f)` -for each 1-morphism `f : a ⟶ b`. --/ -@[ext] -structure Modification (η θ : F ⟶ G) where - app (a : B) : η.app a ⟶ θ.app a - naturality : - ∀ {a b : B} (f : a ⟶ b), - F.map f ◁ app b ≫ θ.naturality f = η.naturality f ≫ app a ▷ G.map f := by - aesop_cat - -attribute [nolint docBlame] CategoryTheory.OplaxNatTrans.Modification.app - CategoryTheory.OplaxNatTrans.Modification.naturality - -/- Porting note: removed primes from field names and removed `restate_axiom` since that is no longer - needed in Lean 4 -/ - -attribute [reassoc (attr := simp)] Modification.naturality - -variable {η θ ι : F ⟶ G} - -namespace Modification - -variable (η) - -/-- The identity modification. -/ -@[simps] -def id : Modification η η where app a := 𝟙 (η.app a) - -instance : Inhabited (Modification η η) := - ⟨Modification.id η⟩ - -variable {η} - -section - -variable (Γ : Modification η θ) {a b c : B} {a' : C} - -@[reassoc (attr := simp)] -theorem whiskerLeft_naturality (f : a' ⟶ F.obj b) (g : b ⟶ c) : - f ◁ F.map g ◁ Γ.app c ≫ f ◁ θ.naturality g = f ◁ η.naturality g ≫ f ◁ Γ.app b ▷ G.map g := by - simp_rw [← Bicategory.whiskerLeft_comp, naturality] - -@[reassoc (attr := simp)] -theorem whiskerRight_naturality (f : a ⟶ b) (g : G.obj b ⟶ a') : - F.map f ◁ Γ.app b ▷ g ≫ (α_ _ _ _).inv ≫ θ.naturality f ▷ g = - (α_ _ _ _).inv ≫ η.naturality f ▷ g ≫ Γ.app a ▷ G.map f ▷ g := by - simp_rw [associator_inv_naturality_middle_assoc, ← comp_whiskerRight, naturality] - -end - -/-- Vertical composition of modifications. -/ -@[simps] -def vcomp (Γ : Modification η θ) (Δ : Modification θ ι) : Modification η ι where - app a := Γ.app a ≫ Δ.app a - -end Modification - -/-- Category structure on the oplax natural transformations between OplaxFunctors. -/ -@[simps] -instance category (F G : OplaxFunctor B C) : Category (F ⟶ G) where - Hom := Modification - id := Modification.id - comp := Modification.vcomp - --- Porting note: duplicating the `ext` lemma. -@[ext] -lemma ext {F G : OplaxFunctor B C} {α β : F ⟶ G} {m n : α ⟶ β} (w : ∀ b, m.app b = n.app b) : - m = n := by - apply Modification.ext - ext - apply w - -@[simp] -lemma Modification.id_app' {X : B} {F G : OplaxFunctor B C} (α : F ⟶ G) : - Modification.app (𝟙 α) X = 𝟙 (α.app X) := rfl - -@[simp] -lemma Modification.comp_app' {X : B} {F G : OplaxFunctor B C} {α β γ : F ⟶ G} - (m : α ⟶ β) (n : β ⟶ γ) : (m ≫ n).app X = m.app X ≫ n.app X := - rfl - -/-- Construct a modification isomorphism between oplax natural transformations -by giving object level isomorphisms, and checking naturality only in the forward direction. --/ -@[simps] -def ModificationIso.ofComponents (app : ∀ a, η.app a ≅ θ.app a) - (naturality : - ∀ {a b} (f : a ⟶ b), - F.map f ◁ (app b).hom ≫ θ.naturality f = η.naturality f ≫ (app a).hom ▷ G.map f) : - η ≅ θ where - hom := { app := fun a => (app a).hom } - inv := - { app := fun a => (app a).inv - naturality := fun {a b} f => by - simpa using congr_arg (fun f => _ ◁ (app b).inv ≫ f ≫ (app a).inv ▷ _) (naturality f).symm } - -end - /-- A structure on an Oplax natural transformation that promotes it to a strong natural transformation. diff --git a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean index 28d84af3a9c06..d118ec2577a11 100644 --- a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean +++ b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean @@ -108,7 +108,7 @@ naturality 2-cell is an isomorphism. -/ noncomputable def mkOfOplax' {F G : OplaxFunctor B C} (η : OplaxNatTrans F G) [∀ a b (f : a ⟶ b), IsIso (η.naturality f)] : StrongOplaxNatTrans F G where app := η.app - naturality := fun f => asIso (η.naturality _) + naturality := fun _ => asIso (η.naturality _) variable (F : OplaxFunctor B C) diff --git a/Mathlib/CategoryTheory/Bicategory/SingleObj.lean b/Mathlib/CategoryTheory/Bicategory/SingleObj.lean index 73341c73d8e16..5a01fd30b13ce 100644 --- a/Mathlib/CategoryTheory/Bicategory/SingleObj.lean +++ b/Mathlib/CategoryTheory/Bicategory/SingleObj.lean @@ -50,7 +50,7 @@ instance : Bicategory (MonoidalSingleObj C) where Hom _ _ := C id _ := 𝟙_ C comp X Y := tensorObj X Y - whiskerLeft X Y Z f := X ◁ f + whiskerLeft X _ _ f := X ◁ f whiskerRight f Z := f ▷ Z associator X Y Z := α_ X Y Z leftUnitor X := λ_ X @@ -75,7 +75,7 @@ def endMonoidalStarFunctor : MonoidalFunctor (EndMonoidal (MonoidalSingleObj.sta obj X := X map f := f ε := 𝟙 _ - μ X Y := 𝟙 _ + μ _ _ := 𝟙 _ /-- The equivalence between the endomorphisms of the single object when we promote a monoidal category to a single object bicategory, diff --git a/Mathlib/CategoryTheory/Category/Bipointed.lean b/Mathlib/CategoryTheory/Category/Bipointed.lean index d6bd45ad2304f..b8a57ae187af4 100644 --- a/Mathlib/CategoryTheory/Category/Bipointed.lean +++ b/Mathlib/CategoryTheory/Category/Bipointed.lean @@ -20,9 +20,6 @@ open CategoryTheory universe u -variable {α β : Type*} - - /-- The category of bipointed types. -/ structure Bipointed : Type (u + 1) where /-- The underlying type of a bipointed type. -/ @@ -194,7 +191,7 @@ def pointedToBipointedFstBipointedToPointedFstAdjunction : cases x · exact f.map_snd.symm · rfl - right_inv := fun f => Pointed.Hom.ext rfl } + right_inv := fun _ => Pointed.Hom.ext rfl } homEquiv_naturality_left_symm := fun f g => by apply Bipointed.Hom.ext funext x @@ -214,7 +211,7 @@ def pointedToBipointedSndBipointedToPointedSndAdjunction : cases x · exact f.map_fst.symm · rfl - right_inv := fun f => Pointed.Hom.ext rfl } + right_inv := fun _ => Pointed.Hom.ext rfl } homEquiv_naturality_left_symm := fun f g => by apply Bipointed.Hom.ext funext x diff --git a/Mathlib/CategoryTheory/Category/Cat.lean b/Mathlib/CategoryTheory/Category/Cat.lean index 9838804baf16f..7d16c775e8b1d 100644 --- a/Mathlib/CategoryTheory/Category/Cat.lean +++ b/Mathlib/CategoryTheory/Category/Cat.lean @@ -56,13 +56,13 @@ instance bicategory : Bicategory.{max v u, max v u} Cat.{v, u} where id C := 𝟭 C comp F G := F ⋙ G homCategory := fun _ _ => Functor.category - whiskerLeft {C} {D} {E} F G H η := whiskerLeft F η - whiskerRight {C} {D} {E} F G η H := whiskerRight η H - associator {A} {B} {C} D := Functor.associator - leftUnitor {A} B := Functor.leftUnitor - rightUnitor {A} B := Functor.rightUnitor - pentagon := fun {A} {B} {C} {D} {E}=> Functor.pentagon - triangle {A} {B} {C} := Functor.triangle + whiskerLeft {_} {_} {_} F _ _ η := whiskerLeft F η + whiskerRight {_} {_} {_} _ _ η H := whiskerRight η H + associator {_} {_} {_} _ := Functor.associator + leftUnitor {_} _ := Functor.leftUnitor + rightUnitor {_} _ := Functor.rightUnitor + pentagon := fun {_} {_} {_} {_} {_}=> Functor.pentagon + triangle {_} {_} {_} := Functor.triangle /-- `Cat` is a strict bicategory. -/ instance bicategory.strict : Bicategory.Strict Cat.{v, u} where diff --git a/Mathlib/CategoryTheory/Category/Cat/Limit.lean b/Mathlib/CategoryTheory/Category/Cat/Limit.lean index 8fb276edac4be..92300512f30e6 100644 --- a/Mathlib/CategoryTheory/Category/Cat/Limit.lean +++ b/Mathlib/CategoryTheory/Category/Cat/Limit.lean @@ -59,7 +59,7 @@ def homDiagram {F : J ⥤ Cat.{v, v}} (X Y : limit (F ⋙ Cat.objects.{v, v})) : @[simps] instance (F : J ⥤ Cat.{v, v}) : Category (limit (F ⋙ Cat.objects)) where Hom X Y := limit (homDiagram X Y) - id X := Types.Limit.mk.{v, v} (homDiagram X X) (fun j => 𝟙 _) fun j j' f => by simp + id X := Types.Limit.mk.{v, v} (homDiagram X X) (fun _ => 𝟙 _) fun j j' f => by simp comp {X Y Z} f g := Types.Limit.mk.{v, v} (homDiagram X Z) (fun j => limit.π (homDiagram X Y) j f ≫ limit.π (homDiagram Y Z) j g) fun j j' h => by @@ -84,7 +84,7 @@ def limitCone (F : J ⥤ Cat.{v, v}) : Cone F where { app := fun j => { obj := limit.π (F ⋙ Cat.objects) j map := fun f => limit.π (homDiagram _ _) j f } - naturality := fun j j' f => + naturality := fun _ _ f => CategoryTheory.Functor.ext (fun X => (congr_fun (limit.w (F ⋙ Cat.objects) f) X).symm) fun X Y h => (congr_fun (limit.w (homDiagram X Y) f) h).symm } diff --git a/Mathlib/CategoryTheory/Category/PartialFun.lean b/Mathlib/CategoryTheory/Category/PartialFun.lean index 0ed2b108fb523..f0a25329d70db 100644 --- a/Mathlib/CategoryTheory/Category/PartialFun.lean +++ b/Mathlib/CategoryTheory/Category/PartialFun.lean @@ -30,8 +30,6 @@ open CategoryTheory Option universe u -variable {α β : Type*} - /-- The category of types equipped with partial functions. -/ def PartialFun : Type _ := Type* @@ -87,8 +85,8 @@ This is the computable part of the equivalence `PartialFunEquivPointed`. -/ def pointedToPartialFun : Pointed.{u} ⥤ PartialFun where obj X := { x : X // x ≠ X.point } map f := PFun.toSubtype _ f.toFun ∘ Subtype.val - map_id X := - PFun.ext fun a b => + map_id _ := + PFun.ext fun _ b => PFun.mem_toSubtype_iff (b := b).trans (Subtype.coe_inj.trans Part.mem_some_iff.symm) map_comp f g := by -- Porting note: the proof was changed because the original mathlib3 proof no longer works @@ -125,7 +123,7 @@ noncomputable def partialFunEquivPointed : PartialFun.{u} ≌ Pointed where unitIso := NatIso.ofComponents (fun X => PartialFun.Iso.mk { toFun := fun a => ⟨some a, some_ne_none a⟩ invFun := fun a => Option.get _ (Option.ne_none_iff_isSome.1 a.2) - left_inv := fun a => Option.get_some _ _ + left_inv := fun _ => Option.get_some _ _ right_inv := fun a => by simp only [some_get, Subtype.coe_eta] }) fun f => PFun.ext fun a b => by @@ -166,7 +164,7 @@ adding a point. -/ noncomputable def typeToPartialFunIsoPartialFunToPointed : typeToPartialFun ⋙ partialFunToPointed ≅ typeToPointed := NatIso.ofComponents - (fun X => + (fun _ => { hom := ⟨id, rfl⟩ inv := ⟨id, rfl⟩ hom_inv_id := rfl diff --git a/Mathlib/CategoryTheory/Category/Pointed.lean b/Mathlib/CategoryTheory/Category/Pointed.lean index a1f720281f992..d36dd860e3be1 100644 --- a/Mathlib/CategoryTheory/Category/Pointed.lean +++ b/Mathlib/CategoryTheory/Category/Pointed.lean @@ -22,22 +22,17 @@ open CategoryTheory universe u -variable {α β : Type*} - /-- The category of pointed types. -/ structure Pointed : Type (u + 1) where /-- the underlying type -/ - X : Type u + protected X : Type u /-- the distinguished element -/ point : X namespace Pointed instance : CoeSort Pointed Type* := - ⟨X⟩ - --- Porting note: protected attribute does not work ---attribute [protected] Pointed.X + ⟨Pointed.X⟩ /-- Turns a point into a pointed type. -/ def of {X : Type*} (point : X) : Pointed := @@ -124,7 +119,7 @@ def typeToPointedForgetAdjunction : typeToPointed ⊣ forget Pointed := cases x · exact f.map_point.symm · rfl - right_inv := fun f => funext fun _ => rfl } + right_inv := fun _ => funext fun _ => rfl } homEquiv_naturality_left_symm := fun f g => by apply Pointed.Hom.ext funext x diff --git a/Mathlib/CategoryTheory/Category/Quiv.lean b/Mathlib/CategoryTheory/Category/Quiv.lean index be83ad9b038c2..b8ad841e24d51 100644 --- a/Mathlib/CategoryTheory/Category/Quiv.lean +++ b/Mathlib/CategoryTheory/Category/Quiv.lean @@ -5,7 +5,7 @@ Authors: Kim Morrison -/ import Mathlib.CategoryTheory.Adjunction.Basic import Mathlib.CategoryTheory.Category.Cat -import Mathlib.CategoryTheory.PathCategory +import Mathlib.CategoryTheory.PathCategory.Basic /-! # The category of quivers diff --git a/Mathlib/CategoryTheory/Category/RelCat.lean b/Mathlib/CategoryTheory/Category/RelCat.lean index 7136d606db093..ae907547bf19b 100644 --- a/Mathlib/CategoryTheory/Category/RelCat.lean +++ b/Mathlib/CategoryTheory/Category/RelCat.lean @@ -37,7 +37,7 @@ instance RelCat.inhabited : Inhabited RelCat := by unfold RelCat; infer_instance /-- The category of types with binary relations as morphisms. -/ instance rel : LargeCategory RelCat where Hom X Y := X → Y → Prop - id X x y := x = y + id _ x y := x = y comp f g x z := ∃ y, f x y ∧ g y z @@ -121,7 +121,7 @@ open Opposite /-- The argument-swap isomorphism from `RelCat` to its opposite. -/ def opFunctor : RelCat ⥤ RelCatᵒᵖ where obj X := op X - map {X Y} r := op (fun y x => r x y) + map {_ _} r := op (fun y x => r x y) map_id X := by congr simp only [unop_op, RelCat.Hom.rel_id] @@ -137,7 +137,7 @@ def opFunctor : RelCat ⥤ RelCatᵒᵖ where /-- The other direction of `opFunctor`. -/ def unopFunctor : RelCatᵒᵖ ⥤ RelCat where obj X := unop X - map {X Y} r x y := unop r y x + map {_ _} r x y := unop r y x map_id X := by dsimp ext x y diff --git a/Mathlib/CategoryTheory/Category/TwoP.lean b/Mathlib/CategoryTheory/Category/TwoP.lean index 9a4f129f06e4e..49fda51da739c 100644 --- a/Mathlib/CategoryTheory/Category/TwoP.lean +++ b/Mathlib/CategoryTheory/Category/TwoP.lean @@ -141,7 +141,7 @@ noncomputable def pointedToTwoPFstForgetCompBipointedToPointedFstAdjunction : cases x · exact f.map_snd.symm · rfl - right_inv := fun f => Pointed.Hom.ext rfl } + right_inv := fun _ => Pointed.Hom.ext rfl } homEquiv_naturality_left_symm := fun f g => by apply Bipointed.Hom.ext funext x @@ -160,7 +160,7 @@ noncomputable def pointedToTwoPSndForgetCompBipointedToPointedSndAdjunction : cases x · exact f.map_fst.symm · rfl - right_inv := fun f => Pointed.Hom.ext rfl } + right_inv := fun _ => Pointed.Hom.ext rfl } homEquiv_naturality_left_symm := fun f g => by apply Bipointed.Hom.ext funext x diff --git a/Mathlib/CategoryTheory/Category/ULift.lean b/Mathlib/CategoryTheory/Category/ULift.lean index 9752f42a1cf1e..f70fe083dec2f 100644 --- a/Mathlib/CategoryTheory/Category/ULift.lean +++ b/Mathlib/CategoryTheory/Category/ULift.lean @@ -66,12 +66,12 @@ def ULift.equivalence : C ≌ ULift.{u₂} C where inv := 𝟙 _ } counitIso := { hom := - { app := fun X => 𝟙 _ + { app := fun _ => 𝟙 _ naturality := fun X Y f => by change f ≫ 𝟙 _ = 𝟙 _ ≫ f simp } inv := - { app := fun X => 𝟙 _ + { app := fun _ => 𝟙 _ naturality := fun X Y f => by change f ≫ 𝟙 _ = 𝟙 _ ≫ f simp } @@ -118,7 +118,7 @@ theorem objUp_objDown {C} (A : ULiftHom C) : ULiftHom.objUp A.objDown = A := instance ULiftHom.category : Category.{max v₂ v₁} (ULiftHom.{v₂} C) where Hom A B := ULift.{v₂} <| A.objDown ⟶ B.objDown - id A := ⟨𝟙 _⟩ + id _ := ⟨𝟙 _⟩ comp f g := ⟨f.down ≫ g.down⟩ /-- One half of the quivalence between `C` and `ULiftHom C`. -/ @@ -137,8 +137,8 @@ def ULiftHom.down : ULiftHom C ⥤ C where def ULiftHom.equiv : C ≌ ULiftHom C where functor := ULiftHom.up inverse := ULiftHom.down - unitIso := NatIso.ofComponents fun A => eqToIso rfl - counitIso := NatIso.ofComponents fun A => eqToIso rfl + unitIso := NatIso.ofComponents fun _ => eqToIso rfl + counitIso := NatIso.ofComponents fun _ => eqToIso rfl end ULiftHom /- Porting note: we want to keep around the category instance on `D` @@ -159,7 +159,7 @@ def AsSmall.{w, v, u} (D : Type u) [Category.{v} D] := ULift.{max w v} D instance : SmallCategory (AsSmall.{w₁} C) where Hom X Y := ULift.{max w₁ u₁} <| X.down ⟶ Y.down - id X := ⟨𝟙 _⟩ + id _ := ⟨𝟙 _⟩ comp f g := ⟨f.down ≫ g.down⟩ /-- One half of the equivalence between `C` and `AsSmall C`. -/ @@ -179,8 +179,8 @@ def AsSmall.down : AsSmall C ⥤ C where def AsSmall.equiv : C ≌ AsSmall C where functor := AsSmall.up inverse := AsSmall.down - unitIso := NatIso.ofComponents fun X => eqToIso rfl - counitIso := NatIso.ofComponents fun X => eqToIso <| ULift.ext _ _ rfl + unitIso := NatIso.ofComponents fun _ => eqToIso rfl + counitIso := NatIso.ofComponents fun _ => eqToIso <| ULift.ext _ _ rfl instance [Inhabited C] : Inhabited (AsSmall C) := ⟨⟨default⟩⟩ diff --git a/Mathlib/CategoryTheory/ChosenFiniteProducts.lean b/Mathlib/CategoryTheory/ChosenFiniteProducts.lean index 94e7ecaf158cf..13bd59c64fac4 100644 --- a/Mathlib/CategoryTheory/ChosenFiniteProducts.lean +++ b/Mathlib/CategoryTheory/ChosenFiniteProducts.lean @@ -1,10 +1,11 @@ /- Copyright (c) 2024 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Adam Topaz +Authors: Adam Topaz, Robin Carlier -/ import Mathlib.CategoryTheory.Monoidal.OfChosenFiniteProducts.Symmetric import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts +import Mathlib.CategoryTheory.Limits.Preserves.Shapes.BinaryProducts /-! # Categories with chosen finite products @@ -28,7 +29,7 @@ binary product and `𝟙_ C` for the explicit terminal object. namespace CategoryTheory -universe v u +universe v v₁ v₂ u u₁ u₂ /-- An instance of `ChosenFiniteProducts C` bundles an explicit choice of a binary @@ -103,6 +104,14 @@ lemma lift_fst {T X Y : C} (f : T ⟶ X) (g : T ⟶ Y) : lift f g ≫ fst _ _ = lemma lift_snd {T X Y : C} (f : T ⟶ X) (g : T ⟶ Y) : lift f g ≫ snd _ _ = g := by simp [lift, snd] +instance mono_lift_of_mono_left {W X Y : C} (f : W ⟶ X) (g : W ⟶ Y) + [Mono f] : Mono (lift f g) := + mono_of_mono_fac <| lift_fst _ _ + +instance mono_lift_of_mono_right {W X Y : C} (f : W ⟶ X) (g : W ⟶ Y) + [Mono g] : Mono (lift f g) := + mono_of_mono_fac <| lift_snd _ _ + @[ext 1050] lemma hom_ext {T X Y : C} (f g : T ⟶ X ⊗ Y) (h_fst : f ≫ fst _ _ = g ≫ fst _ _) @@ -110,6 +119,15 @@ lemma hom_ext {T X Y : C} (f g : T ⟶ X ⊗ Y) f = g := (product X Y).isLimit.hom_ext fun ⟨j⟩ => j.recOn h_fst h_snd +-- Similarly to `CategoryTheory.Limits.prod.comp_lift`, we do not make the `assoc` version a simp +-- lemma +@[reassoc, simp] +lemma comp_lift {V W X Y : C} (f : V ⟶ W) (g : W ⟶ X) (h : W ⟶ Y) : + f ≫ lift g h = lift (f ≫ g) (f ≫ h) := by ext <;> simp + +@[simp] +lemma lift_fst_snd {X Y : C} : lift (fst X Y) (snd X Y) = 𝟙 (X ⊗ Y) := by ext <;> simp + @[reassoc (attr := simp)] lemma tensorHom_fst {X₁ X₂ Y₁ Y₂ : C} (f : X₁ ⟶ X₂) (g : Y₁ ⟶ Y₂) : (f ⊗ g) ≫ fst _ _ = fst _ _ ≫ f := lift_fst _ _ @@ -118,6 +136,14 @@ lemma tensorHom_fst {X₁ X₂ Y₁ Y₂ : C} (f : X₁ ⟶ X₂) (g : Y₁ ⟶ lemma tensorHom_snd {X₁ X₂ Y₁ Y₂ : C} (f : X₁ ⟶ X₂) (g : Y₁ ⟶ Y₂) : (f ⊗ g) ≫ snd _ _ = snd _ _ ≫ g := lift_snd _ _ +@[reassoc (attr := simp)] +lemma lift_map {V W X Y Z : C} (f : V ⟶ W) (g : V ⟶ X) (h : W ⟶ Y) (k : X ⟶ Z) : + lift f g ≫ (h ⊗ k) = lift (f ≫ h) (g ≫ k) := by ext <;> simp + +@[simp] +lemma lift_fst_comp_snd_comp {W X Y Z : C} (g : W ⟶ X) (g' : Y ⟶ Z) : + lift (fst _ _ ≫ g) (snd _ _ ≫ g') = g ⊗ g' := by ext <;> simp + @[reassoc (attr := simp)] lemma whiskerLeft_fst (X : C) {Y₁ Y₂ : C} (g : Y₁ ⟶ Y₂) : (X ◁ g) ≫ fst _ _ = fst _ _ := @@ -170,6 +196,22 @@ lemma associator_inv_fst_snd (X Y Z : C) : lemma associator_inv_snd (X Y Z : C) : (α_ X Y Z).inv ≫ snd _ _ = snd _ _ ≫ snd _ _ := lift_snd _ _ +@[reassoc (attr := simp)] +lemma leftUnitor_inv_fst (X : C) : + (λ_ X).inv ≫ fst _ _ = toUnit _ := toUnit_unique _ _ + +@[reassoc (attr := simp)] +lemma leftUnitor_inv_snd (X : C) : + (λ_ X).inv ≫ snd _ _ = 𝟙 X := lift_snd _ _ + +@[reassoc (attr := simp)] +lemma rightUnitor_inv_fst (X : C) : + (ρ_ X).inv ≫ fst _ _ = 𝟙 X := lift_fst _ _ + +@[reassoc (attr := simp)] +lemma rightUnitor_inv_snd (X : C) : + (ρ_ X).inv ≫ snd _ _ = toUnit _ := toUnit_unique _ _ + /-- Construct an instance of `ChosenFiniteProducts C` given an instance of `HasFiniteProducts C`. -/ @@ -184,9 +226,312 @@ instance (priority := 100) : Limits.HasFiniteProducts C := letI : ∀ (X Y : C), Limits.HasLimit (Limits.pair X Y) := fun _ _ => .mk <| ChosenFiniteProducts.product _ _ letI : Limits.HasBinaryProducts C := Limits.hasBinaryProducts_of_hasLimit_pair _ - letI : Limits.HasTerminal C := Limits.hasTerminal_of_unique (𝟙_ _) + letI : Limits.HasTerminal C := Limits.hasTerminal_of_unique (𝟙_ C) hasFiniteProducts_of_has_binary_and_terminal +section ChosenFiniteProductsComparison + +variable {D : Type u₁} [Category.{v₁} D] [ChosenFiniteProducts D] (F : C ⥤ D) + +section terminalComparison + +/-- When `C` and `D` have chosen finite products and `F : C ⥤ D` is any functor, +`terminalComparison F` is the unique map `F (𝟙_ C) ⟶ 𝟙_ D`. -/ +abbrev terminalComparison : F.obj (𝟙_ C) ⟶ 𝟙_ D := toUnit _ + +@[reassoc (attr := simp)] +lemma map_toUnit_comp_terminalCompariso (A : C) : + F.map (toUnit A) ≫ terminalComparison F = toUnit _ := toUnit_unique _ _ + +open Limits + +/-- If `terminalComparison F` is an Iso, then `F` preserves terminal objects. -/ +noncomputable def preservesLimitEmptyOfIsIsoTerminalComparison [IsIso (terminalComparison F)] : + PreservesLimit (Functor.empty.{0} C) F := by + apply preservesLimitOfPreservesLimitCone terminal.isLimit + apply isLimitChangeEmptyCone D terminal.isLimit + exact asIso (terminalComparison F)|>.symm + +/-- If `F` preserves terminal objects, then `terminalComparison F` is an isomorphism. -/ +def preservesTerminalIso [h : PreservesLimit (Functor.empty.{0} C) F] : F.obj (𝟙_ C) ≅ 𝟙_ D := + (isLimitChangeEmptyCone D (h.preserves terminal.isLimit) (asEmptyCone (F.obj (𝟙_ C))) + (Iso.refl _)).conePointUniqueUpToIso terminal.isLimit + +@[simp] +lemma preservesTerminalIso_hom [PreservesLimit (Functor.empty.{0} C) F] : + (preservesTerminalIso F).hom = terminalComparison F := toUnit_unique _ _ + +instance terminalComparison_isIso_of_preservesLimits [PreservesLimit (Functor.empty.{0} C) F] : + IsIso (terminalComparison F) := by + rw [← preservesTerminalIso_hom] + infer_instance + +end terminalComparison + +section prodComparison + +variable (A B : C) + +/-- When `C` and `D` have chosen finite products and `F : C ⥤ D` is any functor, +`prodComparison F A B` is the canonical comparison morphism from `F (A ⊗ B)` to `F(A) ⊗ F(B)`. -/ +def prodComparison (A B : C) : F.obj (A ⊗ B) ⟶ F.obj A ⊗ F.obj B := + lift (F.map (fst A B)) (F.map (snd A B)) + +@[reassoc (attr := simp)] +theorem prodComparison_fst : prodComparison F A B ≫ fst _ _ = F.map (fst A B) := + lift_fst _ _ + +@[reassoc (attr := simp)] +theorem prodComparison_snd : prodComparison F A B ≫ snd _ _ = F.map (snd A B) := + lift_snd _ _ + +@[reassoc (attr := simp)] +theorem inv_prodComparison_map_fst [IsIso (prodComparison F A B)] : + inv (prodComparison F A B) ≫ F.map (fst _ _) = fst _ _ := by simp [IsIso.inv_comp_eq] + +@[reassoc (attr := simp)] +theorem inv_prodComparison_map_snd [IsIso (prodComparison F A B)] : + inv (prodComparison F A B) ≫ F.map (snd _ _) = snd _ _ := by simp [IsIso.inv_comp_eq] + +variable {A B} {A' B' : C} + +/-- Naturality of the `prodComparison` morphism in both arguments. -/ +@[reassoc] +theorem prodComparison_natural (f : A ⟶ A') (g : B ⟶ B') : + F.map (f ⊗ g) ≫ prodComparison F A' B' = + prodComparison F A B ≫ (F.map f ⊗ F.map g) := by + apply hom_ext <;> + simp only [Category.assoc, prodComparison_fst, tensorHom_fst, prodComparison_fst_assoc, + prodComparison_snd, tensorHom_snd, prodComparison_snd_assoc, ← F.map_comp] + +/-- Naturality of the `prodComparison` morphism in the right argument. -/ +@[reassoc] +theorem prodComparison_natural_whiskerLeft (g : B ⟶ B') : + F.map (A ◁ g) ≫ prodComparison F A B' = + prodComparison F A B ≫ (F.obj A ◁ F.map g) := by + rw [← id_tensorHom, prodComparison_natural, Functor.map_id] + rfl + +/-- Naturality of the `prodComparison` morphism in the left argument. -/ +@[reassoc] +theorem prodComparison_natural_whiskerRight (f : A ⟶ A') : + F.map (f ▷ B) ≫ prodComparison F A' B = + prodComparison F A B ≫ (F.map f ▷ F.obj B) := by + rw [← tensorHom_id, prodComparison_natural, Functor.map_id] + rfl + +section +variable [IsIso (prodComparison F A B)] + +/-- If the product comparison morphism is an iso, its inverse is natural in both argument. -/ +@[reassoc] +theorem prodComparison_inv_natural (f : A ⟶ A') (g : B ⟶ B') [IsIso (prodComparison F A' B')] : + inv (prodComparison F A B) ≫ F.map (f ⊗ g) = + (F.map f ⊗ F.map g) ≫ inv (prodComparison F A' B') := by + rw [IsIso.eq_comp_inv, Category.assoc, IsIso.inv_comp_eq, prodComparison_natural] + +/-- If the product comparison morphism is an iso, its inverse is natural in the right argument. -/ +@[reassoc] +theorem prodComparison_inv_natural_whiskerLeft (g : B ⟶ B') [IsIso (prodComparison F A B')] : + inv (prodComparison F A B) ≫ F.map (A ◁ g) = + (F.obj A ◁ F.map g) ≫ inv (prodComparison F A B') := by + rw [IsIso.eq_comp_inv, Category.assoc, IsIso.inv_comp_eq, prodComparison_natural_whiskerLeft] + +/-- If the product comparison morphism is an iso, its inverse is natural in the left argument. -/ +@[reassoc] +theorem prodComparison_inv_natural_whiskerRight (f : A ⟶ A') [IsIso (prodComparison F A' B)] : + inv (prodComparison F A B) ≫ F.map (f ▷ B) = + (F.map f ▷ F.obj B) ≫ inv (prodComparison F A' B) := by + rw [IsIso.eq_comp_inv, Category.assoc, IsIso.inv_comp_eq, prodComparison_natural_whiskerRight] + +end + +theorem prodComparison_comp {E : Type u₂} [Category.{v₂} E] [ChosenFiniteProducts E] (G : D ⥤ E) : + prodComparison (F ⋙ G) A B = + G.map (prodComparison F A B) ≫ prodComparison G (F.obj A) (F.obj B) := by + unfold prodComparison + ext <;> simp [← G.map_comp] + +@[simp] +lemma prodComparison_id : + prodComparison (𝟭 C) A B = 𝟙 (A ⊗ B) := lift_fst_snd + +/-- The product comparison morphism from `F(A ⊗ -)` to `FA ⊗ F-`, whose components are given by +`prodComparison`. -/ +@[simps] +def prodComparisonNatTrans (A : C) : + (curriedTensor C).obj A ⋙ F ⟶ F ⋙ (curriedTensor D).obj (F.obj A) where + app B := prodComparison F A B + naturality x y f := by + apply hom_ext <;> + simp only [Functor.comp_obj, curriedTensor_obj_obj, + Functor.comp_map, curriedTensor_obj_map, Category.assoc, prodComparison_fst, whiskerLeft_fst, + prodComparison_snd, prodComparison_snd_assoc, whiskerLeft_snd, ← F.map_comp] + +theorem prodComparisonNatTrans_comp {E : Type u₂} [Category.{v₂} E] [ChosenFiniteProducts E] + (G : D ⥤ E) : prodComparisonNatTrans (F ⋙ G) A = + whiskerRight (prodComparisonNatTrans F A) G ≫ + whiskerLeft F (prodComparisonNatTrans G (F.obj A)) := by ext; simp [prodComparison_comp] + +@[simp] +lemma prodComparisonNatTrans_id : + prodComparisonNatTrans (𝟭 C) A = 𝟙 _ := by ext; simp + +/-- The product comparison morphism from `F(- ⊗ -)` to `F- ⊗ F-`, whose components are given by +`prodComparison`. -/ +@[simps] +def prodComparisonBifunctorNatTrans : + curriedTensor C ⋙ (whiskeringRight _ _ _).obj F ⟶ + F ⋙ curriedTensor D ⋙ (whiskeringLeft _ _ _).obj F where + app A := prodComparisonNatTrans F A + naturality x y f := by + ext z + apply hom_ext <;> simp [← Functor.map_comp] + +variable {E : Type u₂} [Category.{v₂} E] + [ChosenFiniteProducts E] (G : D ⥤ E) + +theorem prodComparisonBifunctorNatTrans_comp {E : Type u₂} [Category.{v₂} E] + [ChosenFiniteProducts E] (G : D ⥤ E) : prodComparisonBifunctorNatTrans (F ⋙ G) = + whiskerRight (prodComparisonBifunctorNatTrans F) ((whiskeringRight _ _ _).obj G) ≫ + whiskerLeft F (whiskerRight (prodComparisonBifunctorNatTrans G) + ((whiskeringLeft _ _ _).obj F)) := by ext; simp [prodComparison_comp] + +instance (A : C) [∀ B, IsIso (prodComparison F A B)] : IsIso (prodComparisonNatTrans F A) := by + letI : ∀ X, IsIso ((prodComparisonNatTrans F A).app X) := by assumption + apply NatIso.isIso_of_isIso_app + +instance [∀ A B, IsIso (prodComparison F A B)] : IsIso (prodComparisonBifunctorNatTrans F) := by + letI : ∀ X, IsIso ((prodComparisonBifunctorNatTrans F).app X) := + fun _ ↦ by dsimp; apply NatIso.isIso_of_isIso_app + apply NatIso.isIso_of_isIso_app + +open Limits +section PreservesLimitPairs + +section +variable (A B) +variable [PreservesLimit (pair A B) F] + +/-- If `F` preserves the limit of the pair `(A, B)`, then the binary fan given by +`(F.map fst A B, F.map (snd A B))` is a limit cone. -/ +def isLimitChosenFiniteProductsOfPreservesLimits : + IsLimit <| BinaryFan.mk (F.map (fst A B)) (F.map (snd A B)) := + mapIsLimitOfPreservesOfIsLimit F (fst _ _) (snd _ _) <| + (product A B).isLimit.ofIsoLimit <| isoBinaryFanMk (product A B).cone + +/-- If `F` preserves the limit of the pair `(A, B)`, then `prodComparison F A B` is an isomorphism. +-/ +def prodComparisonIso : F.obj (A ⊗ B) ≅ F.obj A ⊗ F.obj B := + IsLimit.conePointUniqueUpToIso (isLimitChosenFiniteProductsOfPreservesLimits F A B) + (product _ _).isLimit + +@[simp] +lemma prodComparisonIso_hom : (prodComparisonIso F A B).hom = prodComparison F A B := by + rfl + +instance isIso_prodComparison_of_preservesLimit_pair : IsIso (prodComparison F A B) := by + rw [← prodComparisonIso_hom] + infer_instance + +end + +/-- The natural isomorphism `F(A ⊗ -) ≅ FA ⊗ F-`, provided each `prodComparison F A B` is an +isomorphism (as `B` changes). -/ +@[simps! hom inv] +noncomputable def prodComparisonNatIso (A : C) [∀ B, PreservesLimit (pair A B) F] : + (curriedTensor C).obj A ⋙ F ≅ F ⋙ (curriedTensor D).obj (F.obj A) := + asIso (prodComparisonNatTrans F A) + +/-- The natural isomorphism of bifunctors `F(- ⊗ -) ≅ F- ⊗ F-`, provided each +`prodComparison F A B` is an isomorphism. -/ +@[simps! hom inv] +noncomputable def prodComparisonBifunctorNatIso [∀ A B, PreservesLimit (pair A B) F] : + curriedTensor C ⋙ (whiskeringRight _ _ _).obj F ≅ + F ⋙ curriedTensor D ⋙ (whiskeringLeft _ _ _).obj F := + asIso (prodComparisonBifunctorNatTrans F) + +end PreservesLimitPairs + +section ProdComparisonIso + +/-- If `prodComparison F A B` is an isomorphism, then `F` preserves the limit of `pair A B`. -/ +noncomputable def preservesLimitPairOfIsIsoProdComparison (A B : C) [IsIso (prodComparison F A B)] : + PreservesLimit (pair A B) F := by + apply preservesLimitOfPreservesLimitCone (product A B).isLimit + refine IsLimit.equivOfNatIsoOfIso (pairComp A B F) _ + ((product (F.obj A) (F.obj B)).cone.extend (prodComparison F A B)) + (BinaryFan.ext (by exact Iso.refl _) ?_ ?_) |>.invFun + (IsLimit.extendIso _ (product (F.obj A) (F.obj B)).isLimit) + · dsimp only [BinaryFan.fst] + simp [pairComp, prodComparison, lift, fst] + · dsimp only [BinaryFan.snd] + simp [pairComp, prodComparison, lift, snd] + + /-- If `prodComparison F A B` is an isomorphism for all `A B` then `F` preserves limits of shape +`Discrete (WalkingPair)`. -/ +noncomputable def preservesLimitsOfShapeDiscreteWalkingPairOfIsoProdComparison + [∀ A B, IsIso (prodComparison F A B)] : PreservesLimitsOfShape (Discrete WalkingPair) F := by + constructor + intro K + refine @preservesLimitOfIsoDiagram _ _ _ _ _ _ _ _ _ (diagramIsoPair K).symm ?_ + apply preservesLimitPairOfIsIsoProdComparison + +end ProdComparisonIso + +end prodComparison + +end ChosenFiniteProductsComparison + end ChosenFiniteProducts +open Limits MonoidalCategory ChosenFiniteProducts + +variable {C : Type u} [Category.{v} C] [ChosenFiniteProducts C] + {D : Type u₁} [Category.{v₁} D] [ChosenFiniteProducts D] (F : C ⥤ D) + +/-- Any functor between categories with chosen finite products induces an oplax monoial functor. -/ +@[simps] +def Functor.toOplaxMonoidalFunctorOfChosenFiniteProducts : OplaxMonoidalFunctor C D where + toFunctor := F + η := terminalComparison F + δ X Y := prodComparison F X Y + δ_natural_left {X Y} f X' := by + symm; simpa using ChosenFiniteProducts.prodComparison_natural F f (𝟙 X') + δ_natural_right {X Y} X' g := by + symm; simpa using ChosenFiniteProducts.prodComparison_natural F (𝟙 X') g + associativity X Y Z := by + apply hom_ext + case' h_snd => apply hom_ext + all_goals simp [← Functor.map_comp] + left_unitality X := by + apply hom_ext + · exact toUnit_unique _ _ + · simp only [leftUnitor_inv_snd, Category.assoc, whiskerRight_snd, + ChosenFiniteProducts.prodComparison_snd, ← F.map_comp, F.map_id] + right_unitality X := by + apply hom_ext + · simp only [rightUnitor_inv_fst, Category.assoc, whiskerLeft_fst, + ChosenFiniteProducts.prodComparison_fst, ← F.map_comp, F.map_id] + · exact toUnit_unique _ _ + +variable [PreservesLimit (Functor.empty.{0} C) F] + [PreservesLimitsOfShape (Discrete WalkingPair) F] + +instance : IsIso F.toOplaxMonoidalFunctorOfChosenFiniteProducts.η := + terminalComparison_isIso_of_preservesLimits F + +instance (A B : C) : IsIso (F.toOplaxMonoidalFunctorOfChosenFiniteProducts.δ A B) := + isIso_prodComparison_of_preservesLimit_pair F A B + +/-- If `F` preserves finite products, the oplax monoidal functor +`F.toOplaxMonoidalFunctorOfChosenFiniteProducts` can be promoted to a strong monoidal functor. -/ +@[simps!] +noncomputable def Functor.toMonoidalFunctorOfChosenFiniteProducts : MonoidalFunctor C D := + MonoidalFunctor.fromOplaxMonoidalFunctor + (toOplaxMonoidalFunctorOfChosenFiniteProducts F) + +instance [F.IsEquivalence] : F.toMonoidalFunctorOfChosenFiniteProducts.IsEquivalence := by + assumption + end CategoryTheory diff --git a/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean b/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean index c95c9da1f310e..3a4eaa80fc91f 100644 --- a/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean @@ -50,7 +50,7 @@ def fst : chosenProd F₁ F₂ ⟶ F₁ where /-- The second projection `chosenProd F₁ F₂ ⟶ F₂`. -/ @[simps] def snd : chosenProd F₁ F₂ ⟶ F₂ where - app j := ChosenFiniteProducts.snd _ _ + app _ := ChosenFiniteProducts.snd _ _ /-- `Functor.chosenProd F₁ F₂` is a binary product of `F₁` and `F₂`. -/ noncomputable def isLimit : IsLimit (BinaryFan.mk (fst F₁ F₂) (snd F₁ F₂)) := @@ -151,6 +151,15 @@ lemma associator_inv_app (F₁ F₂ F₃ : J ⥤ C) (j : J) : (α_ F₁ F₂ F₃).inv.app j = (α_ _ _ _).inv := by rw [← cancel_mono ((α_ _ _ _).hom), Iso.inv_hom_id, ← associator_hom_app, Iso.inv_hom_id_app] +noncomputable instance {K : Type*} [Category K] [HasColimitsOfShape K C] + [∀ X : C, PreservesColimitsOfShape K (tensorLeft X)] {F : J ⥤ C} : + PreservesColimitsOfShape K (tensorLeft F) := by + apply preservesColimitsOfShapeOfEvaluation + intro k + haveI : tensorLeft F ⋙ (evaluation J C).obj k ≅ (evaluation J C).obj k ⋙ tensorLeft (F.obj k) := + NatIso.ofComponents (fun _ ↦ Iso.refl _) + exact preservesColimitsOfShapeOfNatIso this.symm + end Monoidal end Functor diff --git a/Mathlib/CategoryTheory/Closed/Enrichment.lean b/Mathlib/CategoryTheory/Closed/Enrichment.lean new file mode 100644 index 0000000000000..1d263f92528ed --- /dev/null +++ b/Mathlib/CategoryTheory/Closed/Enrichment.lean @@ -0,0 +1,41 @@ +/- +Copyright (c) 2024 Daniel Carranza. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Daniel Carranza +-/ +import Mathlib.CategoryTheory.Enriched.Basic +import Mathlib.CategoryTheory.Closed.Monoidal + +/-! +# A closed monoidal category is enriched in itself + +From the data of a closed monoidal category `C`, we define a `C`-category structure for `C`. +where the hom-object is given by the internal hom (coming from the closed structure). + +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`). + +All structure field values are defined in `Closed/Monoidal`. + +-/ + +universe u v + +namespace CategoryTheory + +namespace MonoidalClosed + +variable {C : Type u} [Category.{v} C] [MonoidalCategory C] [MonoidalClosed C] + +/-- For `C` closed monoidal, build an instance of `C` as a `C`-category -/ +scoped instance : EnrichedCategory C C where + Hom x := (ihom x).obj + id _ := id _ + comp _ _ _ := comp _ _ _ + assoc _ _ _ _ := assoc _ _ _ _ + +end MonoidalClosed + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Closed/Functor.lean b/Mathlib/CategoryTheory/Closed/Functor.lean index c0348d31a52bf..a725454594c48 100644 --- a/Mathlib/CategoryTheory/Closed/Functor.lean +++ b/Mathlib/CategoryTheory/Closed/Functor.lean @@ -79,14 +79,14 @@ theorem expComparison_ev (A B : C) : Limits.prod.map (𝟙 (F.obj A)) ((expComparison F A).app B) ≫ (exp.ev (F.obj A)).app (F.obj B) = inv (prodComparison F _ _) ≫ F.map ((exp.ev _).app _) := by convert mateEquiv_counit _ _ (prodComparisonNatIso F A).inv B using 2 - apply IsIso.inv_eq_of_hom_inv_id -- Porting note: was `ext` + apply IsIso.inv_eq_of_hom_inv_id -- Porting note (#11041): was `ext` simp only [Limits.prodComparisonNatIso_inv, asIso_inv, NatIso.isIso_inv_app, IsIso.hom_inv_id] theorem coev_expComparison (A B : C) : F.map ((exp.coev A).app B) ≫ (expComparison F A).app (A ⨯ B) = (exp.coev _).app (F.obj B) ≫ (exp (F.obj A)).map (inv (prodComparison F A B)) := by convert unit_mateEquiv _ _ (prodComparisonNatIso F A).inv B using 3 - apply IsIso.inv_eq_of_hom_inv_id -- Porting note: was `ext` + apply IsIso.inv_eq_of_hom_inv_id -- Porting note (#11041): was `ext` dsimp simp diff --git a/Mathlib/CategoryTheory/Closed/FunctorCategory/Complete.lean b/Mathlib/CategoryTheory/Closed/FunctorCategory/Complete.lean new file mode 100644 index 0000000000000..41c13c797d0be --- /dev/null +++ b/Mathlib/CategoryTheory/Closed/FunctorCategory/Complete.lean @@ -0,0 +1,75 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.CategoryTheory.Adjunction.Lifting.Right +import Mathlib.CategoryTheory.Closed.FunctorCategory.Groupoid +import Mathlib.CategoryTheory.Groupoid.Discrete +import Mathlib.CategoryTheory.Limits.Preserves.FunctorCategory +import Mathlib.CategoryTheory.Monad.Comonadicity +/-! + +# Functors into a complete monoidal closed category form a monoidal closed category. + +TODO (in progress by Joël Riou): make a more explicit construction of the internal hom in functor +categories. +-/ + +universe v₁ v₂ u₁ u₂ + +open CategoryTheory MonoidalCategory MonoidalClosed Limits + +noncomputable section + +namespace CategoryTheory.Functor + +section +variable (I : Type u₂) [Category.{v₂} I] + +private abbrev incl : Discrete I ⥤ I := Discrete.functor id + +variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory C] [MonoidalClosed C] + +variable [∀ (F : Discrete I ⥤ C), (Discrete.functor id).HasRightKanExtension F] +-- is also implied by: `[HasLimitsOfSize.{u₂, max u₂ v₂} C]` + +instance : ReflectsIsomorphisms <| (whiskeringLeft _ _ C).obj (incl I) where + reflects f h := by + simp only [NatTrans.isIso_iff_isIso_app] at * + intro X + exact h ⟨X⟩ + +variable [HasLimitsOfShape WalkingParallelPair C] + +instance : Comonad.PreservesLimitOfIsCoreflexivePair ((whiskeringLeft _ _ C).obj (incl I)) := + ⟨inferInstance⟩ + +instance : ComonadicLeftAdjoint ((whiskeringLeft _ _ C).obj (incl I)) := + Comonad.comonadicOfHasPreservesCoreflexiveEqualizersOfReflectsIsomorphisms + ((incl I).ranAdjunction C) + +instance (F : I ⥤ C) : IsLeftAdjoint (tensorLeft (incl I ⋙ F)) := + (ihom.adjunction (incl I ⋙ F)).isLeftAdjoint + +/-- Auxiliary definition for `functorCategoryMonoidalClosed` -/ +def functorCategoryClosed (F : I ⥤ C) : Closed F := + have := (ihom.adjunction (incl I ⋙ F)).isLeftAdjoint + have := isLeftAdjoint_square_lift_comonadic (tensorLeft F) ((whiskeringLeft _ _ C).obj (incl I)) + ((whiskeringLeft _ _ C).obj (incl I)) (tensorLeft (incl I ⋙ F)) (Iso.refl _) + { rightAdj := (tensorLeft F).rightAdjoint + adj := Adjunction.ofIsLeftAdjoint (tensorLeft F) } + +/-- +Assuming the existence of certain limits, functors into a monoidal closed category form a +monoidal closed category. + +Note: this is defined completely abstractly, and does not have any good definitional properties. +See the TODO in the module docstring. +-/ +def functorCategoryMonoidalClosed : MonoidalClosed (I ⥤ C) where + closed F := functorCategoryClosed I C F + +end + +end CategoryTheory.Functor diff --git a/Mathlib/CategoryTheory/Closed/FunctorCategory.lean b/Mathlib/CategoryTheory/Closed/FunctorCategory/Groupoid.lean similarity index 100% rename from Mathlib/CategoryTheory/Closed/FunctorCategory.lean rename to Mathlib/CategoryTheory/Closed/FunctorCategory/Groupoid.lean diff --git a/Mathlib/CategoryTheory/Closed/Ideal.lean b/Mathlib/CategoryTheory/Closed/Ideal.lean index da5c0efda1a01..aea4dfe3a8e28 100644 --- a/Mathlib/CategoryTheory/Closed/Ideal.lean +++ b/Mathlib/CategoryTheory/Closed/Ideal.lean @@ -202,9 +202,9 @@ theorem bijection_symm_apply_id (A B : C) : -- Porting note: added dsimp only [Functor.comp_obj] rw [prod.comp_lift_assoc, prod.lift_snd, prod.lift_fst_assoc, prod.lift_fst_comp_snd_comp, - ← Adjunction.eq_unit_comp_map_iff, Iso.comp_inv_eq, assoc] + Adjunction.homEquiv_counit, ← Adjunction.eq_unit_comp_map_iff, Iso.comp_inv_eq, assoc] rw [PreservesLimitPair.iso_hom i ((reflector i).obj A) ((reflector i).obj B)] - apply prod.hom_ext + apply Limits.prod.hom_ext · rw [Limits.prod.map_fst, assoc, assoc, prodComparison_fst, ← i.map_comp, prodComparison_fst] apply (reflectorAdjunction i).unit.naturality · rw [Limits.prod.map_snd, assoc, assoc, prodComparison_snd, ← i.map_comp, prodComparison_snd] @@ -217,7 +217,8 @@ theorem bijection_natural (A B : C) (X X' : D) (f : (reflector i).obj (A ⨯ B) erw [homEquiv_symm_apply_eq, homEquiv_symm_apply_eq, homEquiv_apply_eq, homEquiv_apply_eq, homEquiv_symm_apply_eq, homEquiv_symm_apply_eq, homEquiv_apply_eq, homEquiv_apply_eq] apply i.map_injective - rw [Functor.FullyFaithful.map_preimage, i.map_comp] + rw [Functor.FullyFaithful.map_preimage, i.map_comp, + Adjunction.homEquiv_unit, Adjunction.homEquiv_unit] simp only [comp_id, Functor.map_comp, Functor.FullyFaithful.map_preimage, assoc] rw [← assoc, ← assoc, curry_natural_right _ (i.map g), unitCompPartialBijective_natural, uncurry_natural_right, ← assoc, curry_natural_right, diff --git a/Mathlib/CategoryTheory/Closed/Monoidal.lean b/Mathlib/CategoryTheory/Closed/Monoidal.lean index 43af4d461c0de..fd270e7d51120 100644 --- a/Mathlib/CategoryTheory/Closed/Monoidal.lean +++ b/Mathlib/CategoryTheory/Closed/Monoidal.lean @@ -304,6 +304,89 @@ theorem ofEquiv_uncurry_def {X Y Z : C} : end OfEquiv +-- A closed monoidal category C is always enriched over itself. +-- This section contains the necessary definitions and equalities to endow C with +-- the structure of a C-category, while the instance itself is defined in `Closed/Enrichment`. +-- In particular, we only assume the necessary instances of `Closed x`, rather than assuming +-- C comes with an instance of `MonoidalClosed` +section Enriched + +/-- The C-identity morphism + `𝟙_ C ⟶ hom(x, x)` +used to equip `C` with the structure of a `C`-category -/ +def id (x : C) [Closed x] : 𝟙_ C ⟶ (ihom x).obj x := curry (ρ_ x).hom + +/-- The *uncurried* composition morphism + `x ⊗ (hom(x, y) ⊗ hom(y, z)) ⟶ (x ⊗ hom(x, y)) ⊗ hom(y, z) ⟶ y ⊗ hom(y, z) ⟶ z`. +The `C`-composition morphism will be defined as the adjoint transpose of this map. -/ +def compTranspose (x y z : C) [Closed x] [Closed y] : x ⊗ (ihom x).obj y ⊗ (ihom y).obj z ⟶ z := + (α_ x ((ihom x).obj y) ((ihom y).obj z)).inv ≫ + (ihom.ev x).app y ▷ ((ihom y).obj z) ≫ (ihom.ev y).app z + +/-- The `C`-composition morphism + `hom(x, y) ⊗ hom(y, z) ⟶ hom(x, z)` +used to equip `C` with the structure of a `C`-category -/ +def comp (x y z : C) [Closed x] [Closed y] : (ihom x).obj y ⊗ (ihom y).obj z ⟶ (ihom x).obj z := + curry (compTranspose x y z) + +/-- Unfold the definition of `id`. +This exists to streamline the proofs of `MonoidalClosed.id_comp` and `MonoidalClosed.comp_id` -/ +lemma id_eq (x : C) [Closed x] : id x = curry (ρ_ x).hom := rfl + +/-- Unfold the definition of `compTranspose`. +This exists to streamline the proof of `MonoidalClosed.assoc` -/ +lemma compTranspose_eq (x y z : C) [Closed x] [Closed y] : + compTranspose x y z = (α_ _ _ _).inv ≫ (ihom.ev x).app y ▷ _ ≫ (ihom.ev y).app z := + rfl + +/-- Unfold the definition of `comp`. +This exists to streamline the proof of `MonoidalClosed.assoc` -/ +lemma comp_eq (x y z : C) [Closed x] [Closed y] : comp x y z = curry (compTranspose x y z) := rfl + +/-! +The proofs of associativity and unitality use the following outline: + 1. Take adjoint transpose on each side of the equality (uncurry_injective) + 2. Do whatever rewrites/simps are necessary to apply uncurry_curry + 3. Conclude with simp +-/ + +/-- Left unitality of the enriched structure -/ +@[reassoc (attr := simp)] +lemma id_comp (x y : C) [Closed x] : + (λ_ ((ihom x).obj y)).inv ≫ id x ▷ _ ≫ comp x x y = 𝟙 _:= by + apply uncurry_injective + rw [uncurry_natural_left, uncurry_natural_left, comp_eq, uncurry_curry, id_eq, compTranspose_eq, + associator_inv_naturality_middle_assoc, ← comp_whiskerRight_assoc, ← uncurry_eq, + uncurry_curry, triangle_assoc_comp_right_assoc, whiskerLeft_inv_hom_assoc, + uncurry_id_eq_ev _ _] + +/-- Right unitality of the enriched structure -/ +@[reassoc (attr := simp)] +lemma comp_id (x y : C) [Closed x] [Closed y] : + (ρ_ ((ihom x).obj y)).inv ≫ _ ◁ id y ≫ comp x y y = 𝟙 _ := by + apply uncurry_injective + rw [uncurry_natural_left, uncurry_natural_left, comp_eq, uncurry_curry, compTranspose_eq, + associator_inv_naturality_right_assoc, ← rightUnitor_tensor_inv_assoc, + whisker_exchange_assoc, ← rightUnitor_inv_naturality_assoc, ← uncurry_id_eq_ev y y] + simp only [Functor.id_obj] + rw [← uncurry_natural_left] + simp [id_eq, uncurry_id_eq_ev] + +/-- Associativity of the enriched structure -/ +@[reassoc] +lemma assoc (w x y z : C) [Closed w] [Closed x] [Closed y] : + (α_ _ _ _).inv ≫ comp w x y ▷ _ ≫ comp w y z = _ ◁ comp x y z ≫ comp w x z := by + apply uncurry_injective + simp only [uncurry_natural_left, comp_eq] + rw [uncurry_curry, uncurry_curry]; simp only [compTranspose_eq, Category.assoc] + rw [associator_inv_naturality_middle_assoc, ← comp_whiskerRight_assoc]; dsimp + rw [← uncurry_eq, uncurry_curry, associator_inv_naturality_right_assoc, whisker_exchange_assoc, + ← uncurry_eq, uncurry_curry] + simp only [comp_whiskerRight, tensorLeft_obj, Category.assoc, pentagon_inv_assoc, + whiskerRight_tensor, Iso.hom_inv_id_assoc] + +end Enriched + end MonoidalClosed attribute [nolint simpNF] CategoryTheory.MonoidalClosed.homEquiv_apply_eq CategoryTheory.MonoidalClosed.homEquiv_symm_apply_eq diff --git a/Mathlib/CategoryTheory/Closed/Types.lean b/Mathlib/CategoryTheory/Closed/Types.lean index 503e71b9441cf..ec79009ce8968 100644 --- a/Mathlib/CategoryTheory/Closed/Types.lean +++ b/Mathlib/CategoryTheory/Closed/Types.lean @@ -34,7 +34,7 @@ for any `X : Type v₁`. -/ def Types.binaryProductAdjunction (X : Type v₁) : Limits.Types.binaryProductFunctor.obj X ⊣ coyoneda.obj (Opposite.op X) where unit := { app := fun Z (z : Z) x => ⟨x, z⟩ } - counit := { app := fun Z xf => xf.2 xf.1 } + counit := { app := fun _ xf => xf.2 xf.1 } instance (X : Type v₁) : (Types.binaryProductFunctor.obj X).IsLeftAdjoint := ⟨_, ⟨Types.binaryProductAdjunction X⟩⟩ diff --git a/Mathlib/CategoryTheory/Closed/Zero.lean b/Mathlib/CategoryTheory/Closed/Zero.lean index 459ba941f8d89..7931f396900e3 100644 --- a/Mathlib/CategoryTheory/Closed/Zero.lean +++ b/Mathlib/CategoryTheory/Closed/Zero.lean @@ -61,7 +61,7 @@ def equivPUnit [HasZeroObject C] : C ≌ Discrete PUnit.{w + 1} where (fun X => { hom := default inv := default }) - fun f => Subsingleton.elim _ _ + fun _ => Subsingleton.elim _ _ counitIso := Functor.punitExt _ _ end CategoryTheory diff --git a/Mathlib/CategoryTheory/CofilteredSystem.lean b/Mathlib/CategoryTheory/CofilteredSystem.lean index 2424d1f7ae761..fba99256f7078 100644 --- a/Mathlib/CategoryTheory/CofilteredSystem.lean +++ b/Mathlib/CategoryTheory/CofilteredSystem.lean @@ -272,7 +272,7 @@ instance toEventualRanges_finite [∀ j, Finite (F.obj j)] : ∀ j, Finite (F.to def toEventualRangesSectionsEquiv : F.toEventualRanges.sections ≃ F.sections where toFun s := ⟨_, fun f => Subtype.coe_inj.2 <| s.prop f⟩ invFun s := - ⟨fun j => ⟨_, mem_iInter₂.2 fun i f => ⟨_, s.prop f⟩⟩, fun f => Subtype.ext <| s.prop f⟩ + ⟨fun _ => ⟨_, mem_iInter₂.2 fun _ f => ⟨_, s.prop f⟩⟩, fun f => Subtype.ext <| s.prop f⟩ left_inv _ := by ext rfl diff --git a/Mathlib/CategoryTheory/CommSq.lean b/Mathlib/CategoryTheory/CommSq.lean index f40df65859a4d..fedadf5d16091 100644 --- a/Mathlib/CategoryTheory/CommSq.lean +++ b/Mathlib/CategoryTheory/CommSq.lean @@ -109,6 +109,19 @@ lemma vert_comp {W X Y Y' Z Z' : C} {f : W ⟶ X} {g : W ⟶ Y} {g' : Y ⟶ Y'} CommSq f (g ≫ g') (h ≫ h') i' := flip (horiz_comp (flip hsq₁) (flip hsq₂)) + +section + +variable {W X Y : C} + +theorem eq_of_mono {f : W ⟶ X} {g : W ⟶ X} {i : X ⟶ Y} [Mono i] (sq : CommSq f g i i) : f = g := + (cancel_mono i).1 sq.w + +theorem eq_of_epi {f : W ⟶ X} {h : X ⟶ Y} {i : X ⟶ Y} [Epi f] (sq : CommSq f f h i) : h = i := + (cancel_epi f).1 sq.w + +end + end CommSq namespace Functor diff --git a/Mathlib/CategoryTheory/Comma/Arrow.lean b/Mathlib/CategoryTheory/Comma/Arrow.lean index 972c94b207848..4abf32df55770 100644 --- a/Mathlib/CategoryTheory/Comma/Arrow.lean +++ b/Mathlib/CategoryTheory/Comma/Arrow.lean @@ -88,7 +88,6 @@ theorem mk_injective (A B : T) : theorem mk_inj (A B : T) {f g : A ⟶ B} : Arrow.mk f = Arrow.mk g ↔ f = g := (mk_injective A B).eq_iff -/- Porting note: was marked as dangerous instance so changed from `Coe` to `CoeOut` -/ instance {X Y : T} : CoeOut (X ⟶ Y) (Arrow T) where coe := mk @@ -152,7 +151,7 @@ theorem hom.congr_right {f g : Arrow T} {φ₁ φ₂ : f ⟶ g} (h : φ₁ = φ theorem iso_w {f g : Arrow T} (e : f ≅ g) : g.hom = e.inv.left ≫ f.hom ≫ e.hom.right := by have eq := Arrow.hom.congr_right e.inv_hom_id rw [Arrow.comp_right, Arrow.id_right] at eq - erw [Arrow.w_assoc, eq, Category.comp_id] + rw [Arrow.w_assoc, eq, Category.comp_id] theorem iso_w' {W X Y Z : T} {f : W ⟶ X} {g : Y ⟶ Z} (e : Arrow.mk f ≅ Arrow.mk g) : g = e.inv.left ≫ f ≫ e.hom.right := @@ -184,11 +183,9 @@ theorem inv_left [IsIso sq] : (inv sq).left = inv sq.left := theorem inv_right [IsIso sq] : (inv sq).right = inv sq.right := IsIso.eq_inv_of_hom_inv_id <| by rw [← Comma.comp_right, IsIso.hom_inv_id, id_right] -/- Porting note (#10618): simp can prove this so removed @[simp] -/ theorem left_hom_inv_right [IsIso sq] : sq.left ≫ g.hom ≫ inv sq.right = f.hom := by simp only [← Category.assoc, IsIso.comp_inv_eq, w] --- simp proves this theorem inv_left_hom_right [IsIso sq] : inv sq.left ≫ f.hom ≫ sq.right = g.hom := by simp only [w, IsIso.inv_comp_eq] diff --git a/Mathlib/CategoryTheory/Comma/Basic.lean b/Mathlib/CategoryTheory/Comma/Basic.lean index c88e7997a1eeb..654d109cac4f1 100644 --- a/Mathlib/CategoryTheory/Comma/Basic.lean +++ b/Mathlib/CategoryTheory/Comma/Basic.lean @@ -106,8 +106,6 @@ section variable {X Y Z : Comma L R} {f : X ⟶ Y} {g : Y ⟶ Z} --- Porting note: this lemma was added because `CommaMorphism.ext` --- was not triggered automatically @[ext] lemma hom_ext (f g : X ⟶ Y) (h₁ : f.left = g.left) (h₂ : f.right = g.right) : f = g := CommaMorphism.ext h₁ h₂ @@ -165,6 +163,34 @@ theorem eqToHom_right (X Y : Comma L R) (H : X = Y) : section +variable {L R} {X Y : Comma L R} (e : X ⟶ Y) + +instance [IsIso e] : IsIso e.left := + (Comma.fst L R).map_isIso e + +instance [IsIso e] : IsIso e.right := + (Comma.snd L R).map_isIso e + +@[simp] +lemma inv_left [IsIso e] : (inv e).left = inv e.left := by + apply IsIso.eq_inv_of_hom_inv_id + rw [← Comma.comp_left, IsIso.hom_inv_id, id_left] + +@[simp] +lemma inv_right [IsIso e] : (inv e).right = inv e.right := by + apply IsIso.eq_inv_of_hom_inv_id + rw [← Comma.comp_right, IsIso.hom_inv_id, id_right] + +lemma left_hom_inv_right [IsIso e] : L.map (e.left) ≫ Y.hom ≫ R.map (inv e.right) = X.hom := by + simp + +lemma inv_left_hom_right [IsIso e] : L.map (inv e.left) ≫ X.hom ≫ R.map e.right = Y.hom := by + simp + +end + +section + variable {L₁ L₂ L₃ : A ⥤ T} {R₁ R₂ R₃ : B ⥤ T} /-- Extract the isomorphism between the left objects from an isomorphism in the comma category. -/ @@ -363,7 +389,7 @@ end section -variable {C : Type u₄} [Category.{v₄} C] {D : Type u₅} [Category.{v₅} D] +variable {C : Type u₄} [Category.{v₄} C] /-- The functor `(F ⋙ L, R) ⥤ (L, R)` -/ @[simps] diff --git a/Mathlib/CategoryTheory/Comma/Over.lean b/Mathlib/CategoryTheory/Comma/Over.lean index 3e27eb8b7b4b1..e37bf7ec99866 100644 --- a/Mathlib/CategoryTheory/Comma/Over.lean +++ b/Mathlib/CategoryTheory/Comma/Over.lean @@ -3,10 +3,8 @@ Copyright (c) 2019 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Bhavik Mehta -/ -import Mathlib.CategoryTheory.Comma.StructuredArrow -import Mathlib.CategoryTheory.PUnit -import Mathlib.CategoryTheory.Functor.ReflectsIso -import Mathlib.CategoryTheory.Functor.EpiMono +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic +import Mathlib.CategoryTheory.Category.Cat /-! # Over and under categories @@ -59,7 +57,7 @@ theorem OverMorphism.ext {X : T} {U V : Over X} {f g : U ⟶ V} (h : f.left = g. congr simp only [eq_iff_true_of_subsingleton] --- @[simp] : Porting note (#10618): simp can prove this +@[simp] theorem over_right (U : Over X) : U.right = ⟨⟨⟩⟩ := by simp only @[simp] @@ -369,7 +367,7 @@ theorem UnderMorphism.ext {X : T} {U V : Under X} {f g : U ⟶ V} (h : f.right = let ⟨_,b,_⟩ := f; let ⟨_,e,_⟩ := g congr; simp only [eq_iff_true_of_subsingleton] --- @[simp] Porting note (#10618): simp can prove this +@[simp] theorem under_left (U : Under X) : U.left = ⟨⟨⟩⟩ := by simp only @[simp] @@ -675,7 +673,7 @@ def ofStructuredArrowProjEquivalence (F : D ⥤ T) (Y : T) (X : D) : counitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) /-- The canonical functor from the structured arrow category on the diagonal functor -`T ⥤ T × T` to the the structured arrow category on `Under.forget`. -/ +`T ⥤ T × T` to the structured arrow category on `Under.forget`. -/ @[simps!] def ofDiagEquivalence.functor (X : T × T) : StructuredArrow X (Functor.diag _) ⥤ StructuredArrow X.2 (Under.forget X.1) := @@ -741,7 +739,7 @@ def ofCostructuredArrowProjEquivalence (F : T ⥤ D) (Y : D) (X : T) : counitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) /-- The canonical functor from the costructured arrow category on the diagonal functor -`T ⥤ T × T` to the the costructured arrow category on `Under.forget`. -/ +`T ⥤ T × T` to the costructured arrow category on `Under.forget`. -/ @[simps!] def ofDiagEquivalence.functor (X : T × T) : CostructuredArrow (Functor.diag _) X ⥤ CostructuredArrow (Over.forget X.1) X.2 := diff --git a/Mathlib/CategoryTheory/Comma/Presheaf.lean b/Mathlib/CategoryTheory/Comma/Presheaf/Basic.lean similarity index 85% rename from Mathlib/CategoryTheory/Comma/Presheaf.lean rename to Mathlib/CategoryTheory/Comma/Presheaf/Basic.lean index 671b3ef28ec5f..56df6eace290c 100644 --- a/Mathlib/CategoryTheory/Comma/Presheaf.lean +++ b/Mathlib/CategoryTheory/Comma/Presheaf/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel -/ +import Mathlib.CategoryTheory.HomCongr import Mathlib.CategoryTheory.Comma.Over import Mathlib.Tactic.CategoryTheory.Elementwise @@ -207,7 +208,7 @@ def restrictedYonedaObj {F : Cᵒᵖ ⥤ Type v} (η : F ⟶ A) : @[simps] def restrictedYonedaObjMap₁ {F G : Cᵒᵖ ⥤ Type v} {η : F ⟶ A} {μ : G ⟶ A} (ε : F ⟶ G) (hε : ε ≫ μ = η) : restrictedYonedaObj η ⟶ restrictedYonedaObj μ where - app s u := u.map₁ ε hε + app _ u := u.map₁ ε hε /-- This is basically just `yoneda : Over A ⥤ (Over A)ᵒᵖ ⥤ Type (max u v)` restricted in the second argument along the forgetful functor `CostructuredArrow yoneda A ⥤ Over A`, but done in a way @@ -227,7 +228,7 @@ def restrictedYoneda (A : Cᵒᵖ ⥤ Type v) : Over A ⥤ (CostructuredArrow yo def toOverYonedaCompRestrictedYoneda (A : Cᵒᵖ ⥤ Type v) : CostructuredArrow.toOver yoneda A ⋙ restrictedYoneda A ≅ yoneda := NatIso.ofComponents - (fun s => NatIso.ofComponents (fun t => OverArrows.costructuredArrowIso _ _) (by aesop_cat)) + (fun s => NatIso.ofComponents (fun _ => OverArrows.costructuredArrowIso _ _) (by aesop_cat)) (by aesop_cat) /-! ### Construction of the backward functor `((CostructuredArrow yoneda A)ᵒᵖ ⥤ Type v) ⥤ Over A` -/ @@ -379,7 +380,7 @@ def yonedaCollectionPresheaf (A : Cᵒᵖ ⥤ Type v) (F : (CostructuredArrow yo @[simps] def yonedaCollectionPresheafMap₁ {F G : (CostructuredArrow yoneda A)ᵒᵖ ⥤ Type v} (η : F ⟶ G) : yonedaCollectionPresheaf A F ⟶ yonedaCollectionPresheaf A G where - app X := YonedaCollection.map₁ η + app _ := YonedaCollection.map₁ η naturality := by intros ext @@ -396,7 +397,7 @@ def yonedaCollectionFunctor (A : Cᵒᵖ ⥤ Type v) : @[simps] def yonedaCollectionPresheafToA (F : (CostructuredArrow yoneda A)ᵒᵖ ⥤ Type v) : yonedaCollectionPresheaf A F ⟶ A where - app X := YonedaCollection.yonedaEquivFst + app _ := YonedaCollection.yonedaEquivFst /-- This is the reverse direction of the equivalence we're constructing. -/ @[simps! obj map] @@ -572,4 +573,72 @@ def CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow (A : Cᵒᵖ CostructuredArrow.toOver yoneda A ⋙ (overEquivPresheafCostructuredArrow A).functor ≅ yoneda := toOverYonedaCompRestrictedYoneda A +/-- This isomorphism says that hom-sets in the category `Over A` for a presheaf `A` where the domain + is of the form `(CostructuredArrow.toOver yoneda A).obj X` can instead be interpreted as + hom-sets in the category `(CostructuredArrow yoneda A)ᵒᵖ ⥤ Type v` where the domain is of the + form `yoneda.obj X` after adjusting the codomain accordingly. This is desirable because in the + latter case the Yoneda lemma can be applied. -/ +def CostructuredArrow.toOverCompYoneda (A : Cᵒᵖ ⥤ Type v) (T : Over A) : + (CostructuredArrow.toOver yoneda A).op ⋙ yoneda.obj T ≅ + yoneda.op ⋙ yoneda.obj ((overEquivPresheafCostructuredArrow A).functor.obj T) := + NatIso.ofComponents (fun X => + (overEquivPresheafCostructuredArrow A).fullyFaithfulFunctor.homEquiv.toIso ≪≫ + (Iso.homCongr + ((CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).app X.unop) + (Iso.refl _)).toIso) + (by aesop_cat) + +@[simp] +theorem CostructuredArrow.overEquivPresheafCostructuredArrow_inverse_map_toOverCompYoneda + {A : Cᵒᵖ ⥤ Type v} {T : Over A} {X : CostructuredArrow yoneda A} + (f : (CostructuredArrow.toOver yoneda A).obj X ⟶ T) : + (overEquivPresheafCostructuredArrow A).inverse.map + (((CostructuredArrow.toOverCompYoneda A T).hom.app (op X) f)) = + (CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).isoCompInverse.inv.app X ≫ + f ≫ (overEquivPresheafCostructuredArrow A).unit.app T := by + simp [CostructuredArrow.toOverCompYoneda] + +@[simp] +theorem CostructuredArrow.overEquivPresheafCostructuredArrow_functor_map_toOverCompYoneda + {A : Cᵒᵖ ⥤ Type v} {T : Over A} {X : CostructuredArrow yoneda A} + (f : yoneda.obj X ⟶ (overEquivPresheafCostructuredArrow A).functor.obj T) : + (overEquivPresheafCostructuredArrow A).functor.map + (((CostructuredArrow.toOverCompYoneda A T).inv.app (op X) f)) = + (CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).hom.app X ≫ f := by + simp [CostructuredArrow.toOverCompYoneda] + +/-- This isomorphism says that hom-sets in the category `Over A` for a presheaf `A` where the domain + is of the form `(CostructuredArrow.toOver yoneda A).obj X` can instead be interpreted as + hom-sets in the category `(CostructuredArrow yoneda A)ᵒᵖ ⥤ Type v` where the domain is of the + form `yoneda.obj X` after adjusting the codomain accordingly. This is desirable because in the + latter case the Yoneda lemma can be applied. -/ +def CostructuredArrow.toOverCompCoyoneda (A : Cᵒᵖ ⥤ Type v) : + (CostructuredArrow.toOver yoneda A).op ⋙ coyoneda ≅ + yoneda.op ⋙ coyoneda ⋙ + (whiskeringLeft _ _ _).obj (overEquivPresheafCostructuredArrow A).functor := + NatIso.ofComponents (fun X => NatIso.ofComponents (fun Y => + (overEquivPresheafCostructuredArrow A).fullyFaithfulFunctor.homEquiv.toIso ≪≫ + (Iso.homCongr + ((CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).app X.unop) + (Iso.refl _)).toIso)) (by aesop_cat) + +@[simp] +theorem CostructuredArrow.overEquivPresheafCostructuredArrow_inverse_map_toOverCompCoyoneda + {A : Cᵒᵖ ⥤ Type v} {T : Over A} {X : CostructuredArrow yoneda A} + (f : (CostructuredArrow.toOver yoneda A).obj X ⟶ T) : + (overEquivPresheafCostructuredArrow A).inverse.map + (((CostructuredArrow.toOverCompCoyoneda A).hom.app (op X)).app T f) = + (CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).isoCompInverse.inv.app X ≫ + f ≫ (overEquivPresheafCostructuredArrow A).unit.app T := by + simp [CostructuredArrow.toOverCompCoyoneda] + +@[simp] +theorem CostructuredArrow.overEquivPresheafCostructuredArrow_functor_map_toOverCompCoyoneda + {A : Cᵒᵖ ⥤ Type v} {T : Over A} {X : CostructuredArrow yoneda A} + (f : yoneda.obj X ⟶ (overEquivPresheafCostructuredArrow A).functor.obj T) : + (overEquivPresheafCostructuredArrow A).functor.map + (((CostructuredArrow.toOverCompCoyoneda A).inv.app (op X)).app T f) = + (CostructuredArrow.toOverCompOverEquivPresheafCostructuredArrow A).hom.app X ≫ f := by + simp [CostructuredArrow.toOverCompCoyoneda] + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/Presheaf/Colimit.lean b/Mathlib/CategoryTheory/Comma/Presheaf/Colimit.lean new file mode 100644 index 0000000000000..11c42fe3b5cb7 --- /dev/null +++ b/Mathlib/CategoryTheory/Comma/Presheaf/Colimit.lean @@ -0,0 +1,59 @@ +/- +Copyright (c) 2024 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.CategoryTheory.Comma.Presheaf.Basic +import Mathlib.CategoryTheory.Limits.Preserves.Yoneda +import Mathlib.CategoryTheory.Limits.Over + +/-! +# Relative Yoneda preserves certain colimits + +In this file we turn the statement `yonedaYonedaColimit` from +`CategoryTheory.Limits.Preserves.Yoneda` from a functor `F : J ⥤ Cᵒᵖ ⥤ Type v` into a statement +about families of presheaves over `A`, i.e., functors `F : J ⥤ Over A`. +-/ + +namespace CategoryTheory + +open Category Opposite Limits + +universe w v u + +variable {C : Type u} [Category.{v} C] {A : Cᵒᵖ ⥤ Type v} + + +variable {J : Type v} [SmallCategory J] {A : Cᵒᵖ ⥤ Type v} (F : J ⥤ Over A) + +-- We introduce some local notation to reduce visual noise in the following proof +local notation "E" => Equivalence.functor (overEquivPresheafCostructuredArrow A) +local notation "E.obj" => + Prefunctor.obj (Functor.toPrefunctor (Equivalence.functor (overEquivPresheafCostructuredArrow A))) + +/-- Naturally in `X`, we have `Hom(YX, colim_i Fi) ≅ colim_i Hom(YX, Fi)`, where `Y` is the + "Yoneda embedding" `CostructuredArrow.toOver yoneda A`. This is a relative version of + `yonedaYonedaColimit`. -/ +noncomputable def CostructuredArrow.toOverCompYonedaColimit : + (CostructuredArrow.toOver yoneda A).op ⋙ yoneda.obj (colimit F) ≅ + (CostructuredArrow.toOver yoneda A).op ⋙ colimit (F ⋙ yoneda) := calc + (CostructuredArrow.toOver yoneda A).op ⋙ yoneda.obj (colimit F) + ≅ yoneda.op ⋙ yoneda.obj (E.obj (colimit F)) := + CostructuredArrow.toOverCompYoneda A _ + _ ≅ yoneda.op ⋙ yoneda.obj (colimit (F ⋙ E)) := + isoWhiskerLeft yoneda.op (yoneda.mapIso (preservesColimitIso _ F)) + _ ≅ yoneda.op ⋙ colimit ((F ⋙ E) ⋙ yoneda) := + yonedaYonedaColimit _ + _ ≅ yoneda.op ⋙ ((F ⋙ E) ⋙ yoneda).flip ⋙ colim := + isoWhiskerLeft _ (colimitIsoFlipCompColim _) + _ ≅ (yoneda.op ⋙ coyoneda ⋙ (whiskeringLeft _ _ _).obj E) ⋙ + (whiskeringLeft _ _ _).obj F ⋙ colim := + Iso.refl _ + _ ≅ (CostructuredArrow.toOver yoneda A).op ⋙ coyoneda ⋙ (whiskeringLeft _ _ _).obj F ⋙ colim := + isoWhiskerRight (CostructuredArrow.toOverCompCoyoneda _).symm _ + _ ≅ (CostructuredArrow.toOver yoneda A).op ⋙ (F ⋙ yoneda).flip ⋙ colim := + Iso.refl _ + _ ≅ (CostructuredArrow.toOver yoneda A).op ⋙ colimit (F ⋙ yoneda) := + isoWhiskerLeft _ (colimitIsoFlipCompColim _).symm + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/StructuredArrow.lean b/Mathlib/CategoryTheory/Comma/StructuredArrow/Basic.lean similarity index 97% rename from Mathlib/CategoryTheory/Comma/StructuredArrow.lean rename to Mathlib/CategoryTheory/Comma/StructuredArrow/Basic.lean index 3ee2b719536a8..7e4231ecc0c06 100644 --- a/Mathlib/CategoryTheory/Comma/StructuredArrow.lean +++ b/Mathlib/CategoryTheory/Comma/StructuredArrow/Basic.lean @@ -5,9 +5,7 @@ Authors: Adam Topaz, Kim Morrison -/ import Mathlib.CategoryTheory.Comma.Basic import Mathlib.CategoryTheory.PUnit -import Mathlib.CategoryTheory.Limits.Shapes.Terminal -import Mathlib.CategoryTheory.EssentiallySmall -import Mathlib.Logic.Small.Set +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal /-! # The category of "structured arrows" @@ -51,8 +49,6 @@ def proj (S : D) (T : C ⥤ D) : StructuredArrow S T ⥤ C := variable {S S' S'' : D} {Y Y' Y'' : C} {T T' : C ⥤ D} --- Porting note (#5229): this lemma was added because `Comma.hom_ext` --- was not triggered automatically @[ext] lemma hom_ext {X Y : StructuredArrow S T} (f g : X ⟶ Y) (h : f.right = g.right) : f = g := CommaMorphism.ext (Subsingleton.elim _ _) h @@ -333,13 +329,6 @@ noncomputable instance isEquivalenceMap₂ end -instance small_proj_preimage_of_locallySmall {𝒢 : Set C} [Small.{v₁} 𝒢] [LocallySmall.{v₁} D] : - Small.{v₁} ((proj S T).obj ⁻¹' 𝒢) := by - suffices (proj S T).obj ⁻¹' 𝒢 = Set.range fun f : ΣG : 𝒢, S ⟶ T.obj G => mk f.2 by - rw [this] - infer_instance - exact Set.ext fun X => ⟨fun h => ⟨⟨⟨_, h⟩, X.hom⟩, (eq_mk _).symm⟩, by aesop_cat⟩ - /-- A structured arrow is called universal if it is initial. -/ abbrev IsUniversal (f : StructuredArrow S T) := IsInitial f @@ -400,8 +389,6 @@ def proj (S : C ⥤ D) (T : D) : CostructuredArrow S T ⥤ C := variable {T T' T'' : D} {Y Y' Y'' : C} {S S' : C ⥤ D} --- Porting note (#5229): this lemma was added because `Comma.hom_ext` --- was not triggered automatically @[ext] lemma hom_ext {X Y : CostructuredArrow S T} (f g : X ⟶ Y) (h : f.left = g.left) : f = g := CommaMorphism.ext h (Subsingleton.elim _ _) @@ -678,13 +665,6 @@ noncomputable instance isEquivalenceMap₂ end -instance small_proj_preimage_of_locallySmall {𝒢 : Set C} [Small.{v₁} 𝒢] [LocallySmall.{v₁} D] : - Small.{v₁} ((proj S T).obj ⁻¹' 𝒢) := by - suffices (proj S T).obj ⁻¹' 𝒢 = Set.range fun f : ΣG : 𝒢, S.obj G ⟶ T => mk f.2 by - rw [this] - infer_instance - exact Set.ext fun X => ⟨fun h => ⟨⟨⟨_, h⟩, X.hom⟩, (eq_mk _).symm⟩, by aesop_cat⟩ - /-- A costructured arrow is called universal if it is terminal. -/ abbrev IsUniversal (f : CostructuredArrow S T) := IsTerminal f diff --git a/Mathlib/CategoryTheory/Comma/StructuredArrow/Functor.lean b/Mathlib/CategoryTheory/Comma/StructuredArrow/Functor.lean new file mode 100644 index 0000000000000..0930021c209e0 --- /dev/null +++ b/Mathlib/CategoryTheory/Comma/StructuredArrow/Functor.lean @@ -0,0 +1,79 @@ +/- +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.Comma.StructuredArrow.Basic +import Mathlib.CategoryTheory.Grothendieck + +/-! +# Structured Arrow Categories as strict functor to Cat + +Forming a structured arrow category `StructuredArrow d T` with `d : D` and `T : C ⥤ D` is strictly +functorial in `S`, inducing a functor `Dᵒᵖ ⥤ Cat`. This file constructs said functor and proves +that, in the dual case, we can precompose it with another functor `L : E ⥤ D` to obtain a category +equivalent to `Comma L T`. +-/ + +namespace CategoryTheory + +universe v₁ v₂ v₃ v₄ u₁ u₂ u₃ u₄ + +variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] + +namespace StructuredArrow + +/-- The structured arrow category `StructuredArrow d T` depends on the chosen domain `d : D` in a +functorial way, inducing a functor `Dᵒᵖ ⥤ Cat`. -/ +@[simps] +def functor (T : C ⥤ D) : Dᵒᵖ ⥤ Cat where + obj d := .of <| StructuredArrow d.unop T + map f := map f.unop + map_id d := Functor.ext (fun ⟨_, _, _⟩ => by simp [CostructuredArrow.map, Comma.mapRight]) + map_comp f g := Functor.ext (fun _ => by simp [CostructuredArrow.map, Comma.mapRight]) + +end StructuredArrow + +namespace CostructuredArrow + +/-- The costructured arrow category `CostructuredArrow T d` depends on the chosen codomain `d : D` +in a functorial way, inducing a functor `D ⥤ Cat`. -/ +@[simps] +def functor (T : C ⥤ D) : D ⥤ Cat where + obj d := .of <| CostructuredArrow T d + map f := CostructuredArrow.map f + map_id d := Functor.ext (fun ⟨_, _, _⟩ => by simp [CostructuredArrow.map, Comma.mapRight]) + map_comp f g := Functor.ext (fun _ => by simp [CostructuredArrow.map, Comma.mapRight]) + +variable {E : Type u₃} [Category.{v₃} E] +variable (L : C ⥤ D) (R : E ⥤ D) + +/-- The functor used to establish the equivalence `grothendieckPrecompFunctorEquivalence` between +the Grothendieck construction on `CostructuredArrow.functor` and the comma category. -/ +@[simps] +def grothendieckPrecompFunctorToComma : Grothendieck (R ⋙ functor L) ⥤ Comma L R where + obj P := ⟨P.fiber.left, P.base, P.fiber.hom⟩ + map f := ⟨f.fiber.left, f.base, by simp⟩ + +/-- The inverse functor used to establish the equivalence `grothendieckPrecompFunctorEquivalence` +between the Grothendieck construction on `CostructuredArrow.functor` and the comma category. -/ +@[simps] +def commaToGrothendieckPrecompFunctor : Comma L R ⥤ Grothendieck (R ⋙ functor L) where + obj X := ⟨X.right, mk X.hom⟩ + map f := ⟨f.right, homMk f.left⟩ + map_id X := Grothendieck.ext _ _ rfl (by simp) + map_comp f g := Grothendieck.ext _ _ rfl (by simp) + +/-- For `L : C ⥤ D`, taking the Grothendieck construction of `CostructuredArrow.functor L` +precomposed with another functor `R : E ⥤ D` results in a category which is equivalent to +the comma category `Comma L R`. -/ +@[simps] +def grothendieckPrecompFunctorEquivalence : Grothendieck (R ⋙ functor L) ≌ Comma L R where + functor := grothendieckPrecompFunctorToComma _ _ + inverse := commaToGrothendieckPrecompFunctor _ _ + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) + counitIso := NatIso.ofComponents (fun _ => Iso.refl _) + +end CostructuredArrow + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/StructuredArrow/Small.lean b/Mathlib/CategoryTheory/Comma/StructuredArrow/Small.lean new file mode 100644 index 0000000000000..a31121a52e88a --- /dev/null +++ b/Mathlib/CategoryTheory/Comma/StructuredArrow/Small.lean @@ -0,0 +1,50 @@ +/- +Copyright (c) 2022 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic +import Mathlib.CategoryTheory.EssentiallySmall +import Mathlib.Logic.Small.Set + +/-! +# Small sets in the category of structured arrows + +Here we prove a technical result about small sets in the category of structured arrows that will +be used in the proof of the Special Adjoint Functor Theorem. +-/ + +namespace CategoryTheory + +-- morphism levels before object levels. See note [CategoryTheory universes]. +universe v₁ v₂ u₁ u₂ + +variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] + +namespace StructuredArrow + +variable {S : D} {T : C ⥤ D} + +instance small_proj_preimage_of_locallySmall {𝒢 : Set C} [Small.{v₁} 𝒢] [LocallySmall.{v₁} D] : + Small.{v₁} ((proj S T).obj ⁻¹' 𝒢) := by + suffices (proj S T).obj ⁻¹' 𝒢 = Set.range fun f : ΣG : 𝒢, S ⟶ T.obj G => mk f.2 by + rw [this] + infer_instance + exact Set.ext fun X => ⟨fun h => ⟨⟨⟨_, h⟩, X.hom⟩, (eq_mk _).symm⟩, by aesop_cat⟩ + +end StructuredArrow + +namespace CostructuredArrow + +variable {S : C ⥤ D} {T : D} + +instance small_proj_preimage_of_locallySmall {𝒢 : Set C} [Small.{v₁} 𝒢] [LocallySmall.{v₁} D] : + Small.{v₁} ((proj S T).obj ⁻¹' 𝒢) := by + suffices (proj S T).obj ⁻¹' 𝒢 = Set.range fun f : ΣG : 𝒢, S.obj G ⟶ T => mk f.2 by + rw [this] + infer_instance + exact Set.ext fun X => ⟨fun h => ⟨⟨⟨_, h⟩, X.hom⟩, (eq_mk _).symm⟩, by aesop_cat⟩ + +end CostructuredArrow + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/ComposableArrows.lean b/Mathlib/CategoryTheory/ComposableArrows.lean index d0547116852eb..0fcf2d10bbac5 100644 --- a/Mathlib/CategoryTheory/ComposableArrows.lean +++ b/Mathlib/CategoryTheory/ComposableArrows.lean @@ -212,7 +212,7 @@ lemma ext {F G : ComposableArrows C n} (h : ∀ i, F.obj i = G.obj i) (w : ∀ (i : ℕ) (hi : i < n), F.map' i (i + 1) = eqToHom (h _) ≫ G.map' i (i + 1) ≫ eqToHom (h _).symm) : F = G := Functor.ext_of_iso - (isoMk (fun i => eqToIso (h i)) (fun i hi => by simp [w i hi])) h (fun i => rfl) + (isoMk (fun i => eqToIso (h i)) (fun i hi => by simp [w i hi])) h (fun _ => rfl) /-- Constructor for morphisms in `ComposableArrows C 0`. -/ @[simps!] @@ -450,7 +450,7 @@ def whiskerLeftFunctor (Φ : Fin (n + 1) ⥤ Fin (m + 1)) : @[simps] def _root_.Fin.succFunctor (n : ℕ) : Fin n ⥤ Fin (n + 1) where obj i := i.succ - map {i j} hij := homOfLE (Fin.succ_le_succ_iff.2 (leOfHom hij)) + map {_ _} hij := homOfLE (Fin.succ_le_succ_iff.2 (leOfHom hij)) /-- The functor `ComposableArrows C (n + 1) ⥤ ComposableArrows C n` which forgets the first arrow. -/ @@ -550,14 +550,14 @@ lemma ext_succ {F G : ComposableArrows C (n + 1)} (h₀ : F.obj' 0 = G.obj' 0) exact Functor.ext_of_iso (isoMkSucc (eqToIso h₀) (eqToIso h) (by rw [w] dsimp [app'] - erw [eqToHom_app, assoc, assoc, eqToHom_trans, eqToHom_refl, comp_id])) this (by + rw [eqToHom_app, assoc, assoc, eqToHom_trans, eqToHom_refl, comp_id])) this (by rintro ⟨i, hi⟩ dsimp cases' i with i · erw [homMkSucc_app_zero] - · erw [homMkSucc_app_succ] + · rw [homMkSucc_app_succ] dsimp [app'] - erw [eqToHom_app]) + rw [eqToHom_app]) lemma precomp_surjective (F : ComposableArrows C (n + 1)) : ∃ (F₀ : ComposableArrows C n) (X₀ : C) (f₀ : X₀ ⟶ F₀.left), F = F₀.precomp f₀ := diff --git a/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean b/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean index 7293c742fab92..9c4cd7abf9e84 100644 --- a/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean +++ b/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean @@ -74,6 +74,12 @@ instance concreteCategory : ConcreteCategory.{u} (Bundled c) where map_comp := fun f g => by dsimp; erw [𝒞.comp_toFun];rfl } forget_faithful := { map_injective := by (intros; apply 𝒞.hom_ext) } +/-- This unification hint helps `rw` to figure out how to apply statements about abstract +concrete categories to specific concrete categories. Crucially, it fires also at `reducible` +levels so `rw` can use it (and we don't have to use `erw`). -/ +unif_hint (C : Bundled c) where + ⊢ (CategoryTheory.forget (Bundled c)).obj C =?= Bundled.α C + variable {hom} attribute [local instance] ConcreteCategory.instFunLike @@ -106,10 +112,10 @@ end This is useful for building categories such as `CommMonCat` from `MonCat`. -/ def map (F : ∀ {α}, d α → c α) : BundledHom (MapHom hom @F) where - toFun α β {iα} {iβ} f := 𝒞.toFun (F iα) (F iβ) f - id α {iα} := 𝒞.id (F iα) - comp := @fun α β γ iα iβ iγ f g => 𝒞.comp (F iα) (F iβ) (F iγ) f g - hom_ext := @fun α β iα iβ f g h => 𝒞.hom_ext (F iα) (F iβ) h + toFun _ _ {iα} {iβ} f := 𝒞.toFun (F iα) (F iβ) f + id _ {iα} := 𝒞.id (F iα) + comp := @fun _ _ _ iα iβ iγ f g => 𝒞.comp (F iα) (F iβ) (F iγ) f g + hom_ext := @fun _ _ iα iβ _ _ h => 𝒞.hom_ext (F iα) (F iβ) h section @@ -134,7 +140,7 @@ instance forget₂ (F : ∀ {α}, d α → c α) [ParentProjection @F] : HasForget₂ (Bundled d) (Bundled c) where forget₂ := { obj := fun X => ⟨X, F X.2⟩ - map := @fun X Y f => f } + map := @fun _ _ f => f } instance forget₂_full (F : ∀ {α}, d α → c α) [ParentProjection @F] : Functor.Full (CategoryTheory.forget₂ (Bundled d) (Bundled c)) where diff --git a/Mathlib/CategoryTheory/Conj.lean b/Mathlib/CategoryTheory/Conj.lean index 5246270f857c8..e0598514c3486 100644 --- a/Mathlib/CategoryTheory/Conj.lean +++ b/Mathlib/CategoryTheory/Conj.lean @@ -63,7 +63,7 @@ theorem symm_self_conj (f : End X) : α.symm.conj (α.conj f) = f := by theorem self_symm_conj (f : End Y) : α.conj (α.symm.conj f) = f := α.symm.symm_self_conj f -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ +@[simp] theorem conj_pow (f : End X) (n : ℕ) : α.conj (f ^ n) = α.conj f ^ n := α.conj.toMonoidHom.map_pow f n @@ -83,7 +83,7 @@ theorem trans_conjAut {Z : C} (β : Y ≅ Z) (f : Aut X) : (α ≪≫ β).conjAut f = β.conjAut (α.conjAut f) := by simp only [conjAut_apply, Iso.trans_symm, Iso.trans_assoc] -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ +@[simp] theorem conjAut_mul (f g : Aut X) : α.conjAut (f * g) = α.conjAut f * α.conjAut g := map_mul α.conjAut f g @@ -91,11 +91,11 @@ theorem conjAut_mul (f g : Aut X) : α.conjAut (f * g) = α.conjAut f * α.conjA theorem conjAut_trans (f g : Aut X) : α.conjAut (f ≪≫ g) = α.conjAut f ≪≫ α.conjAut g := conjAut_mul α g f -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ +@[simp] theorem conjAut_pow (f : Aut X) (n : ℕ) : α.conjAut (f ^ n) = α.conjAut f ^ n := map_pow α.conjAut f n -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ +@[simp] theorem conjAut_zpow (f : Aut X) (n : ℤ) : α.conjAut (f ^ n) = α.conjAut f ^ n := map_zpow α.conjAut f n diff --git a/Mathlib/CategoryTheory/Core.lean b/Mathlib/CategoryTheory/Core.lean index e7b1e69ea7ddc..46edfe5dbabf7 100644 --- a/Mathlib/CategoryTheory/Core.lean +++ b/Mathlib/CategoryTheory/Core.lean @@ -39,7 +39,7 @@ instance coreCategory : Groupoid.{v₁} (Core C) where Hom (X Y : C) := X ≅ Y id (X : C) := Iso.refl X comp f g := Iso.trans f g - inv {X Y} f := Iso.symm f + inv {_ _} f := Iso.symm f namespace Core diff --git a/Mathlib/CategoryTheory/Dialectica/Basic.lean b/Mathlib/CategoryTheory/Dialectica/Basic.lean index 37bab00c84ac7..5a3a8b031e0f8 100644 --- a/Mathlib/CategoryTheory/Dialectica/Basic.lean +++ b/Mathlib/CategoryTheory/Dialectica/Basic.lean @@ -92,7 +92,7 @@ instance : Category (Dial C) where F := π₂ le := by simp } - comp {X Y Z} (F G : Dial.Hom ..) := { + comp {_ _ _} (F G : Dial.Hom ..) := { f := F.f ≫ G.f F := π(π₁, prod.map F.f (𝟙 _) ≫ G.F) ≫ F.F le := comp_le_lemma F G diff --git a/Mathlib/CategoryTheory/DifferentialObject.lean b/Mathlib/CategoryTheory/DifferentialObject.lean index b5463218d54bf..a4cb04addaf1f 100644 --- a/Mathlib/CategoryTheory/DifferentialObject.lean +++ b/Mathlib/CategoryTheory/DifferentialObject.lean @@ -256,7 +256,7 @@ nonrec def shiftFunctorAdd (m n : S) : · dsimp rw [← cancel_epi ((shiftFunctorAdd C m n).inv.app X.obj)] simp only [Category.assoc, Iso.inv_hom_id_app_assoc] - erw [← NatTrans.naturality_assoc] + rw [← NatTrans.naturality_assoc] dsimp simp only [Functor.map_comp, Category.assoc, shiftFunctorComm_hom_app_comp_shift_shiftFunctorAdd_hom_app 1 m n X.obj, diff --git a/Mathlib/CategoryTheory/DiscreteCategory.lean b/Mathlib/CategoryTheory/DiscreteCategory.lean index 59798018c9623..1d28f0410aa9e 100644 --- a/Mathlib/CategoryTheory/DiscreteCategory.lean +++ b/Mathlib/CategoryTheory/DiscreteCategory.lean @@ -73,7 +73,7 @@ See -/ instance discreteCategory (α : Type u₁) : SmallCategory (Discrete α) where Hom X Y := ULift (PLift (X.as = Y.as)) - id X := ULift.up (PLift.up rfl) + id _ := ULift.up (PLift.up rfl) comp {X Y Z} g f := by cases X cases Y @@ -188,7 +188,7 @@ composition of two discrete functors. @[simps!] def functorComp {I : Type u₁} {J : Type u₁'} (f : J → C) (g : I → J) : Discrete.functor (f ∘ g) ≅ Discrete.functor (Discrete.mk ∘ g) ⋙ Discrete.functor f := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- For functors out of a discrete category, a natural transformation is just a collection of maps, @@ -272,8 +272,8 @@ protected def opposite (α : Type u₁) : (Discrete α)ᵒᵖ ≌ Discrete α := let F : Discrete α ⥤ (Discrete α)ᵒᵖ := Discrete.functor fun x => op (Discrete.mk x) { functor := F.leftOp inverse := F - unitIso := NatIso.ofComponents fun ⟨X⟩ => Iso.refl _ - counitIso := Discrete.natIso fun ⟨X⟩ => Iso.refl _ } + unitIso := NatIso.ofComponents fun ⟨_⟩ => Iso.refl _ + counitIso := Discrete.natIso fun ⟨_⟩ => Iso.refl _ } variable {C : Type u₂} [Category.{v₂} C] @@ -297,11 +297,31 @@ def piEquivalenceFunctorDiscrete (J : Type u₂) (C : Type u₁) [Category.{v₁ { obj := fun F j => F.obj ⟨j⟩ map := fun f j => f.app ⟨j⟩ } unitIso := Iso.refl _ - counitIso := NatIso.ofComponents (fun F => (NatIso.ofComponents (fun j => Iso.refl _) + counitIso := NatIso.ofComponents (fun F => (NatIso.ofComponents (fun _ => Iso.refl _) (by rintro ⟨x⟩ ⟨y⟩ f obtain rfl : x = y := Discrete.eq_of_hom f obtain rfl : f = 𝟙 _ := rfl simp))) (by aesop_cat) +/-- A category is discrete when there is at most one morphism between two objects, +in which case they are equal. -/ +class IsDiscrete (C : Type*) [Category C] : Prop where + subsingleton (X Y : C) : Subsingleton (X ⟶ Y) := by infer_instance + eq_of_hom {X Y : C} (f : X ⟶ Y) : X = Y + +attribute [instance] IsDiscrete.subsingleton + +lemma obj_ext_of_isDiscrete {C : Type*} [Category C] [IsDiscrete C] + {X Y : C} (f : X ⟶ Y) : X = Y := IsDiscrete.eq_of_hom f + +instance Discrete.isDiscrete (C : Type*) : IsDiscrete (Discrete C) where + eq_of_hom := by rintro ⟨_⟩ ⟨_⟩ ⟨⟨rfl⟩⟩; rfl + +instance (C : Type*) [Category C] [IsDiscrete C] : IsDiscrete Cᵒᵖ where + eq_of_hom := by + rintro ⟨_⟩ ⟨_⟩ ⟨f⟩ + obtain rfl := obj_ext_of_isDiscrete f + rfl + end CategoryTheory diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean b/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean index 4259ae6bf495b..926d6cb6a6e7a 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean @@ -255,11 +255,11 @@ def EffectiveEpiFamilyStruct.reindex (e : α' ≃ α) (P : EffectiveEpiFamilyStruct (fun a => X (e a)) (fun a => π (e a))) : EffectiveEpiFamilyStruct X π where - desc := fun f h => P.desc (fun a => f _) (fun a₁ a₂ => h _ _) + desc := fun f h => P.desc (fun _ => f _) (fun _ _ => h _ _) fac _ _ a := by obtain ⟨a,rfl⟩ := e.surjective a apply P.fac - uniq _ _ m hm := P.uniq _ _ _ fun a => hm _ + uniq _ _ _ hm := P.uniq _ _ _ fun _ => hm _ /-- Reindex the indexing type of an effective epi family. diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean b/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean index a8b4353556eb6..6632acca21b41 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean @@ -32,7 +32,9 @@ def effectiveEpiFamilyStructCompOfEffectiveEpiSplitEpi' {α : Type*} {B : C} {X desc e w := EffectiveEpiFamily.desc _ f (fun a ↦ i a ≫ e a) fun a₁ a₂ g₁ g₂ _ ↦ (by simp only [← Category.assoc] apply w _ _ (g₁ ≫ i a₁) (g₂ ≫ i a₂) - simpa [← Category.assoc, Category.assoc, hi]) + simp only [Category.assoc, hi] + simp only [← Category.assoc, hi] + simpa) fac e w a := by simp only [Category.assoc, EffectiveEpiFamily.fac] rw [← Category.id_comp (e a), ← Category.assoc, ← Category.assoc] @@ -81,7 +83,7 @@ noncomputable def effectiveEpiFamilyStructOfComp {C : Type*} [Category C] fac {W} φ h i := by dsimp rw [← cancel_epi (g i), ← assoc, EffectiveEpiFamily.fac _ (fun i => g i ≫ f i)] - uniq {W} φ h m hm := EffectiveEpiFamily.uniq _ (fun i => g i ≫ f i) _ _ _ + uniq {W} φ _ m hm := EffectiveEpiFamily.uniq _ (fun i => g i ≫ f i) _ _ _ (fun i => by rw [assoc, hm]) lemma effectiveEpiFamily_of_effectiveEpi_epi_comp {α : Type*} {B : C} {X Y : α → C} diff --git a/Mathlib/CategoryTheory/Elements.lean b/Mathlib/CategoryTheory/Elements.lean index 3269eddc6bd86..7d85416b30755 100644 --- a/Mathlib/CategoryTheory/Elements.lean +++ b/Mathlib/CategoryTheory/Elements.lean @@ -3,9 +3,8 @@ Copyright (c) 2019 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.CategoryTheory.Comma.StructuredArrow -import Mathlib.CategoryTheory.Groupoid -import Mathlib.CategoryTheory.PUnit +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic +import Mathlib.CategoryTheory.Category.Cat /-! # The category of elements @@ -47,7 +46,6 @@ def Functor.Elements (F : C ⥤ Type w) := /-- Constructor for the type `F.Elements` when `F` is a functor to types. -/ abbrev Functor.elementsMk (F : C ⥤ Type w) (X : C) (x : F.obj X) : F.Elements := ⟨X, x⟩ --- Porting note: added because Sigma.ext would be triggered automatically lemma Functor.Elements.ext {F : C ⥤ Type w} (x y : F.Elements) (h₁ : x.fst = y.fst) (h₂ : F.map (eqToHom h₁) x.snd = y.snd) : x = y := by cases x @@ -223,9 +221,9 @@ def fromCostructuredArrow (F : Cᵒᵖ ⥤ Type v) : (CostructuredArrow yoneda F Category.comp_id, yoneda_obj_map] have : yoneda.map f.unop.left ≫ (unop X).hom = (unop Y).hom := by convert f.unop.3 - erw [← this] + rw [← this] simp only [yoneda_map_app, FunctorToTypes.comp] - erw [Category.id_comp]⟩ + rw [Category.id_comp]⟩ @[simp] theorem fromCostructuredArrow_obj_mk (F : Cᵒᵖ ⥤ Type v) {X : C} (f : yoneda.obj X ⟶ F) : diff --git a/Mathlib/CategoryTheory/Endofunctor/Algebra.lean b/Mathlib/CategoryTheory/Endofunctor/Algebra.lean index 59d61ad43c4c1..1b53aa148eb3a 100644 --- a/Mathlib/CategoryTheory/Endofunctor/Algebra.lean +++ b/Mathlib/CategoryTheory/Endofunctor/Algebra.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Joseph Hua. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison, Bhavik Mehta, Johan Commelin, Reid Barton, Robert Y. Lewis, Joseph Hua -/ -import Mathlib.CategoryTheory.Limits.Shapes.Terminal +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal /-! diff --git a/Mathlib/CategoryTheory/Endomorphism.lean b/Mathlib/CategoryTheory/Endomorphism.lean index 93109c730da29..0ab626814ae99 100644 --- a/Mathlib/CategoryTheory/Endomorphism.lean +++ b/Mathlib/CategoryTheory/Endomorphism.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov, Kim Morrison, Simon Hudon -/ import Mathlib.Algebra.Group.Action.Defs import Mathlib.Algebra.Group.Equiv.Basic -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Algebra.Group.Units.Hom import Mathlib.CategoryTheory.Groupoid import Mathlib.CategoryTheory.Opposites @@ -114,7 +114,6 @@ def Aut (X : C) := X ≅ X namespace Aut --- Porting note: added because `Iso.ext` is not triggered automatically @[ext] lemma ext {X : C} {φ₁ φ₂ : Aut X} (h : φ₁.hom = φ₂.hom) : φ₁ = φ₂ := Iso.ext h @@ -140,8 +139,8 @@ are (multiplicatively) equivalent to automorphisms of that object. def unitsEndEquivAut : (End X)ˣ ≃* Aut X where toFun f := ⟨f.1, f.2, f.4, f.3⟩ invFun f := ⟨f.1, f.2, f.4, f.3⟩ - left_inv := fun ⟨f₁, f₂, f₃, f₄⟩ => rfl - right_inv := fun ⟨f₁, f₂, f₃, f₄⟩ => rfl + left_inv := fun ⟨_, _, _, _⟩ => rfl + right_inv := fun ⟨_, _, _, _⟩ => rfl map_mul' f g := by cases f; cases g; rfl /-- The inclusion of `Aut X` to `End X` as a monoid homomorphism. -/ diff --git a/Mathlib/CategoryTheory/Enriched/Basic.lean b/Mathlib/CategoryTheory/Enriched/Basic.lean index f8f9518c24feb..36747f57c3e68 100644 --- a/Mathlib/CategoryTheory/Enriched/Basic.lean +++ b/Mathlib/CategoryTheory/Enriched/Basic.lean @@ -30,7 +30,7 @@ We verify that when `V = Type v`, all these notion reduce to the usual ones. -/ -universe w v u₁ u₂ u₃ +universe w w' v v' u₁ u₂ u₃ noncomputable section @@ -94,7 +94,7 @@ theorem e_assoc' (W X Y Z : C) : section -variable {V} {W : Type v} [Category.{w} W] [MonoidalCategory W] +variable {V} {W : Type v'} [Category.{w'} W] [MonoidalCategory W] -- Porting note: removed `@[nolint hasNonemptyInstance]` /-- A type synonym for `C`, which should come equipped with a `V`-enriched category structure. @@ -147,7 +147,7 @@ def enrichedCategoryTypeOfCategory (C : Type u₁) [𝒞 : Category.{v} C] : EnrichedCategory (Type v) C where Hom := 𝒞.Hom id X _ := 𝟙 X - comp X Y Z p := p.1 ≫ p.2 + comp _ _ _ p := p.1 ≫ p.2 id_comp X Y := by ext; simp comp_id X Y := by ext; simp assoc W X Y Z := by ext ⟨f, g, h⟩; simp @@ -163,7 +163,7 @@ def enrichedCategoryTypeEquivCategory (C : Type u₁) : section -variable {W : Type (v + 1)} [Category.{v} W] [MonoidalCategory W] [EnrichedCategory W C] +variable {W : Type v} [Category.{w} W] [MonoidalCategory W] [EnrichedCategory W C] -- Porting note(#5171): removed `@[nolint has_nonempty_instance]` /-- A type synonym for `C`, which should come equipped with a `V`-enriched category structure. @@ -184,7 +184,7 @@ For `V = Algebra R`, the usual forgetful functor is coyoneda of `R[X]`, not of ` (Perhaps we should have a typeclass for this situation: `ConcreteMonoidal`?) -/ @[nolint unusedArguments] -def ForgetEnrichment (W : Type (v + 1)) [Category.{v} W] [MonoidalCategory W] (C : Type u₁) +def ForgetEnrichment (W : Type v) [Category.{w} W] [MonoidalCategory W] (C : Type u₁) [EnrichedCategory W C] := C @@ -208,7 +208,7 @@ theorem ForgetEnrichment.of_to (X : ForgetEnrichment W C) : rfl instance categoryForgetEnrichment : Category (ForgetEnrichment W C) := by - let I : EnrichedCategory (Type v) (TransportEnrichment (coyonedaTensorUnit W) C) := + let I : EnrichedCategory (Type w) (TransportEnrichment (coyonedaTensorUnit W) C) := inferInstance exact enrichedCategoryTypeEquivCategory C I @@ -281,7 +281,7 @@ attribute [reassoc (attr := simp)] EnrichedFunctor.map_comp @[simps] def EnrichedFunctor.id (C : Type u₁) [EnrichedCategory V C] : EnrichedFunctor V C C where obj X := X - map X Y := 𝟙 _ + map _ _ := 𝟙 _ instance : Inhabited (EnrichedFunctor V C C) := ⟨EnrichedFunctor.id V C⟩ @@ -292,7 +292,7 @@ def EnrichedFunctor.comp {C : Type u₁} {D : Type u₂} {E : Type u₃} [Enrich [EnrichedCategory V D] [EnrichedCategory V E] (F : EnrichedFunctor V C D) (G : EnrichedFunctor V D E) : EnrichedFunctor V C E where obj X := G.obj (F.obj X) - map X Y := F.map _ _ ≫ G.map _ _ + map _ _ := F.map _ _ ≫ G.map _ _ section @@ -419,7 +419,7 @@ def enrichedFunctorTypeEquivFunctor {C : Type u₁} [𝒞 : EnrichedCategory (Ty map_comp := fun f g => congr_fun (F.map_comp _ _ _) ⟨f, g⟩ } invFun F := { obj := fun X => F.obj X - map := fun X Y f => F.map f + map := fun _ _ f => F.map f map_id := fun X => by ext ⟨⟩; exact F.map_id X map_comp := fun X Y Z => by ext ⟨f, g⟩; exact F.map_comp f g } left_inv _ := rfl diff --git a/Mathlib/CategoryTheory/Enriched/Ordinary.lean b/Mathlib/CategoryTheory/Enriched/Ordinary.lean new file mode 100644 index 0000000000000..e7081037f3137 --- /dev/null +++ b/Mathlib/CategoryTheory/Enriched/Ordinary.lean @@ -0,0 +1,138 @@ +/- +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.Enriched.Basic +import Mathlib.CategoryTheory.Monoidal.Types.Coyoneda + +/-! +# Enriched ordinary categories + +If `V` is a monoidal category, a `V`-enriched category `C` does not need +to be a category. However, when we have both `Category C` and `EnrichedCategory V C`, +we may require that the type of morphisms `X ⟶ Y` in `C` identify to +`𝟙_ V ⟶ EnrichedCategory.Hom X Y`. This data shall be packaged in the +typeclass `EnrichedOrdinaryCategory V C`. + +In particular, if `C` is a `V`-enriched category, it is shown that +the "underlying" category `ForgetEnrichment V C` is equipped with a +`EnrichedOrdinaryCategory V C` instance. + +Simplicial categories are implemented in `AlgebraicTopology.SimplicialCategory.Basic` +using an abbreviation for `EnrichedOrdinaryCategory SSet C`. + +-/ + +universe v' v u u' + +open CategoryTheory Category MonoidalCategory + +namespace CategoryTheory + +variable (V : Type u') [Category.{v'} V] [MonoidalCategory V] + (C : Type u) [Category.{v} C] + +/-- An enriched ordinary category is a category `C` that is also enriched +over a category `V` in such a way that morphisms `X ⟶ Y` in `C` identify +to morphisms `𝟙_ V ⟶ (X ⟶[V] Y)` in `V`. -/ +class EnrichedOrdinaryCategory extends EnrichedCategory V C where + /-- morphisms `X ⟶ Y` in the category identify morphisms + `𝟙_ V ⟶ (X ⟶[V] Y)` in `V` -/ + homEquiv {X Y : C} : (X ⟶ Y) ≃ (𝟙_ V ⟶ (X ⟶[V] Y)) + homEquiv_id (X : C) : homEquiv (𝟙 X) = eId V X := by aesop_cat + homEquiv_comp {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) : + homEquiv (f ≫ g) = (λ_ _).inv ≫ (homEquiv f ⊗ homEquiv g) ≫ + eComp V X Y Z := by aesop_cat + +variable [EnrichedOrdinaryCategory V C] {C} + +/-- The bijection `(X ⟶ Y) ≃ (𝟙_ V ⟶ (X ⟶[V] Y))` given by a +`EnrichedOrdinaryCategory` instance. -/ +def eHomEquiv {X Y : C} : (X ⟶ Y) ≃ (𝟙_ V ⟶ (X ⟶[V] Y)) := + EnrichedOrdinaryCategory.homEquiv + +@[simp] +lemma eHomEquiv_id (X : C) : eHomEquiv V (𝟙 X) = eId V X := + EnrichedOrdinaryCategory.homEquiv_id _ + +@[reassoc] +lemma eHomEquiv_comp {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) : + eHomEquiv V (f ≫ g) = (λ_ _).inv ≫ (eHomEquiv V f ⊗ eHomEquiv V g) ≫ eComp V X Y Z := + EnrichedOrdinaryCategory.homEquiv_comp _ _ + +/-- The morphism `(X' ⟶[V] Y) ⟶ (X ⟶[V] Y)` induced by a morphism `X ⟶ X'`. -/ +noncomputable def eHomWhiskerRight {X X' : C} (f : X ⟶ X') (Y : C) : + (X' ⟶[V] Y) ⟶ (X ⟶[V] Y) := + (λ_ _).inv ≫ eHomEquiv V f ▷ _ ≫ eComp V X X' Y + +@[simp] +lemma eHomWhiskerRight_id (X Y : C) : eHomWhiskerRight V (𝟙 X) Y = 𝟙 _ := by + simp [eHomWhiskerRight] + +@[simp, reassoc] +lemma eHomWhiskerRight_comp {X X' X'' : C} (f : X ⟶ X') (f' : X' ⟶ X'') (Y : C) : + eHomWhiskerRight V (f ≫ f') Y = eHomWhiskerRight V f' Y ≫ eHomWhiskerRight V f Y := by + dsimp [eHomWhiskerRight] + rw [assoc, assoc, eHomEquiv_comp, comp_whiskerRight_assoc, comp_whiskerRight_assoc, ← e_assoc', + tensorHom_def', comp_whiskerRight_assoc, id_whiskerLeft, comp_whiskerRight_assoc, + ← comp_whiskerRight_assoc, Iso.inv_hom_id, id_whiskerRight_assoc, + comp_whiskerRight_assoc, leftUnitor_inv_whiskerRight_assoc, + ← associator_inv_naturality_left_assoc, Iso.inv_hom_id_assoc, + ← whisker_exchange_assoc, id_whiskerLeft_assoc, Iso.inv_hom_id_assoc] + +/-- The morphism `(X ⟶[V] Y) ⟶ (X ⟶[V] Y')` induced by a morphism `Y ⟶ Y'`. -/ +noncomputable def eHomWhiskerLeft (X : C) {Y Y' : C} (g : Y ⟶ Y') : + (X ⟶[V] Y) ⟶ (X ⟶[V] Y') := + (ρ_ _).inv ≫ _ ◁ eHomEquiv V g ≫ eComp V X Y Y' + +@[simp] +lemma eHomWhiskerLeft_id (X Y : C) : eHomWhiskerLeft V X (𝟙 Y) = 𝟙 _ := by + simp [eHomWhiskerLeft] + +@[simp, reassoc] +lemma eHomWhiskerLeft_comp (X : C) {Y Y' Y'' : C} (g : Y ⟶ Y') (g' : Y' ⟶ Y'') : + eHomWhiskerLeft V X (g ≫ g') = eHomWhiskerLeft V X g ≫ eHomWhiskerLeft V X g' := by + dsimp [eHomWhiskerLeft] + rw [assoc, assoc, eHomEquiv_comp, MonoidalCategory.whiskerLeft_comp_assoc, + MonoidalCategory.whiskerLeft_comp_assoc, ← e_assoc, tensorHom_def, + MonoidalCategory.whiskerRight_id_assoc, MonoidalCategory.whiskerLeft_comp_assoc, + MonoidalCategory.whiskerLeft_comp_assoc, MonoidalCategory.whiskerLeft_comp_assoc, + whiskerLeft_rightUnitor_assoc, whiskerLeft_rightUnitor_inv_assoc, + triangle_assoc_comp_left_inv_assoc, MonoidalCategory.whiskerRight_id_assoc, + Iso.hom_inv_id_assoc, Iso.inv_hom_id_assoc, + associator_inv_naturality_right_assoc, Iso.hom_inv_id_assoc, + whisker_exchange_assoc, MonoidalCategory.whiskerRight_id_assoc, Iso.inv_hom_id_assoc] + +@[reassoc] +lemma eHom_whisker_exchange {X X' Y Y' : C} (f : X ⟶ X') (g : Y ⟶ Y') : + eHomWhiskerLeft V X' g ≫ eHomWhiskerRight V f Y' = + eHomWhiskerRight V f Y ≫ eHomWhiskerLeft V X g := by + dsimp [eHomWhiskerLeft, eHomWhiskerRight] + rw [assoc, assoc, assoc, assoc, leftUnitor_inv_naturality_assoc, + whisker_exchange_assoc, ← e_assoc, leftUnitor_tensor_inv_assoc, + associator_inv_naturality_left_assoc, Iso.hom_inv_id_assoc, + ← comp_whiskerRight_assoc, whisker_exchange_assoc, + MonoidalCategory.whiskerRight_id_assoc, assoc, Iso.inv_hom_id_assoc, + whisker_exchange_assoc, MonoidalCategory.whiskerRight_id_assoc, Iso.inv_hom_id_assoc] + +attribute [local simp] eHom_whisker_exchange + +variable (C) in +/-- The bifunctor `Cᵒᵖ ⥤ C ⥤ V` which sends `X : Cᵒᵖ` and `Y : C` to `X ⟶[V] Y`. -/ +@[simps] +noncomputable def eHomFunctor : Cᵒᵖ ⥤ C ⥤ V where + obj X := + { obj := fun Y => X.unop ⟶[V] Y + map := fun φ => eHomWhiskerLeft V X.unop φ } + map φ := + { app := fun Y => eHomWhiskerRight V φ.unop Y } + +instance ForgetEnrichment.EnrichedOrdinaryCategory {D : Type*} [EnrichedCategory V D] : + EnrichedOrdinaryCategory V (ForgetEnrichment V D) where + toEnrichedCategory := inferInstanceAs (EnrichedCategory V D) + homEquiv := Equiv.refl _ + homEquiv_id _ := Category.id_comp _ + homEquiv_comp _ _ := Category.assoc _ _ _ + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/EpiMono.lean b/Mathlib/CategoryTheory/EpiMono.lean index 13cfd3e4ad1b3..8c8f738cc3b9f 100644 --- a/Mathlib/CategoryTheory/EpiMono.lean +++ b/Mathlib/CategoryTheory/EpiMono.lean @@ -38,7 +38,6 @@ such that `f ≫ retraction f = 𝟙 X`. Every split monomorphism is a monomorphism. -/ /- Porting note(#5171): removed @[nolint has_nonempty_instance] -/ -/- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule -/ @[ext, aesop apply safe (rule_sets := [CategoryTheory])] structure SplitMono {X Y : C} (f : X ⟶ Y) where /-- The map splitting `f` -/ @@ -64,7 +63,6 @@ such that `section_ f ≫ f = 𝟙 Y`. Every split epimorphism is an epimorphism. -/ /- Porting note(#5171): removed @[nolint has_nonempty_instance] -/ -/- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule -/ @[ext, aesop apply safe (rule_sets := [CategoryTheory])] structure SplitEpi {X Y : C} (f : X ⟶ Y) where /-- The map splitting `f` -/ diff --git a/Mathlib/CategoryTheory/Equivalence.lean b/Mathlib/CategoryTheory/Equivalence.lean index 0f2676be1e1e8..f6f45ef4bd954 100644 --- a/Mathlib/CategoryTheory/Equivalence.lean +++ b/Mathlib/CategoryTheory/Equivalence.lean @@ -320,19 +320,26 @@ theorem invFunIdAssoc_inv_app (e : C ≌ D) (F : D ⥤ E) (X : D) : /-- If `C` is equivalent to `D`, then `C ⥤ E` is equivalent to `D ⥤ E`. -/ @[simps! functor inverse unitIso counitIso] -def congrLeft (e : C ≌ D) : C ⥤ E ≌ D ⥤ E := - Equivalence.mk ((whiskeringLeft _ _ _).obj e.inverse) ((whiskeringLeft _ _ _).obj e.functor) - (NatIso.ofComponents fun F => (e.funInvIdAssoc F).symm) - (NatIso.ofComponents fun F => e.invFunIdAssoc F) +def congrLeft (e : C ≌ D) : C ⥤ E ≌ D ⥤ E where + functor := (whiskeringLeft _ _ _).obj e.inverse + inverse := (whiskeringLeft _ _ _).obj e.functor + unitIso := (NatIso.ofComponents fun F => (e.funInvIdAssoc F).symm) + counitIso := (NatIso.ofComponents fun F => e.invFunIdAssoc F) + functor_unitIso_comp F := by + ext X + dsimp + simp only [funInvIdAssoc_inv_app, id_obj, comp_obj, invFunIdAssoc_hom_app, + Functor.comp_map, ← F.map_comp, unit_inverse_comp, map_id] /-- If `C` is equivalent to `D`, then `E ⥤ C` is equivalent to `E ⥤ D`. -/ @[simps! functor inverse unitIso counitIso] -def congrRight (e : C ≌ D) : E ⥤ C ≌ E ⥤ D := - Equivalence.mk ((whiskeringRight _ _ _).obj e.functor) ((whiskeringRight _ _ _).obj e.inverse) - (NatIso.ofComponents - fun F => F.rightUnitor.symm ≪≫ isoWhiskerLeft F e.unitIso ≪≫ Functor.associator _ _ _) - (NatIso.ofComponents - fun F => Functor.associator _ _ _ ≪≫ isoWhiskerLeft F e.counitIso ≪≫ F.rightUnitor) +def congrRight (e : C ≌ D) : E ⥤ C ≌ E ⥤ D where + functor := (whiskeringRight _ _ _).obj e.functor + inverse := (whiskeringRight _ _ _).obj e.inverse + unitIso := NatIso.ofComponents + fun F => F.rightUnitor.symm ≪≫ isoWhiskerLeft F e.unitIso ≪≫ Functor.associator _ _ _ + counitIso := NatIso.ofComponents + fun F => Functor.associator _ _ _ ≪≫ isoWhiskerLeft F e.counitIso ≪≫ F.rightUnitor section CancellationLemmas diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean index 94619f08a21bb..356d1d299a513 100644 --- a/Mathlib/CategoryTheory/Extensive.lean +++ b/Mathlib/CategoryTheory/Extensive.lean @@ -294,9 +294,9 @@ noncomputable def finitaryExtensiveTopCatAux (Z : TopCat.{u}) · rintro _ ⟨x, rfl⟩; exact ⟨PUnit.unit, x.2.symm⟩ · rintro x ⟨⟨⟩, hx⟩; refine ⟨⟨⟨x, PUnit.unit⟩, hx.symm⟩, rfl⟩ refine ((TopCat.binaryCofan_isColimit_iff _).mpr ⟨?_, ?_, ?_⟩).some - · refine ⟨(Homeomorph.prodPUnit Z).embedding.comp embedding_subtype_val, ?_⟩ + · refine ⟨(Homeomorph.prodPUnit Z).isEmbedding.comp .subtypeVal, ?_⟩ convert f.2.1 _ isOpen_range_inl - · refine ⟨(Homeomorph.prodPUnit Z).embedding.comp embedding_subtype_val, ?_⟩ + · refine ⟨(Homeomorph.prodPUnit Z).isEmbedding.comp .subtypeVal, ?_⟩ convert f.2.1 _ isOpen_range_inr · convert Set.isCompl_range_inl_range_inr.preimage f @@ -321,7 +321,7 @@ instance finitaryExtensive_TopCat : FinitaryExtensive TopCat.{u} := by refine ⟨⟨l, ?_⟩, ContinuousMap.ext fun a => (hl a).symm, TopCat.isTerminalPUnit.hom_ext _ _, fun {l'} h₁ _ => ContinuousMap.ext fun x => hl' x (l' x) (ConcreteCategory.congr_hom h₁ x).symm⟩ - apply (embedding_inl (X := X') (Y := Y')).toInducing.continuous_iff.mpr + apply (IsEmbedding.inl (X := X') (Y := Y')).isInducing.continuous_iff.mpr convert s.fst.2 using 1 exact (funext hl).symm · refine ⟨⟨hαY.symm⟩, ⟨PullbackCone.isLimitAux' _ ?_⟩⟩ @@ -338,7 +338,7 @@ instance finitaryExtensive_TopCat : FinitaryExtensive TopCat.{u} := by refine ⟨⟨l, ?_⟩, ContinuousMap.ext fun a => (hl a).symm, TopCat.isTerminalPUnit.hom_ext _ _, fun {l'} h₁ _ => ContinuousMap.ext fun x => hl' x (l' x) (ConcreteCategory.congr_hom h₁ x).symm⟩ - apply (embedding_inr (X := X') (Y := Y')).toInducing.continuous_iff.mpr + apply (IsEmbedding.inr (X := X') (Y := Y')).isInducing.continuous_iff.mpr convert s.fst.2 using 1 exact (funext hl).symm · intro Z f diff --git a/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean b/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean index bfcd82955db95..5319308872660 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean @@ -279,11 +279,11 @@ instance bicategory : Bicategory (BasedCategory.{v₂, u₂} 𝒮) where id 𝒳 := 𝟭 𝒳 comp F G := F ⋙ G homCategory 𝒳 𝒴 := homCategory 𝒳 𝒴 - whiskerLeft {𝒳 𝒴 𝒵} F {G H} α := whiskerLeft F α - whiskerRight {𝒳 𝒴 𝒵} F G α H := whiskerRight α H - associator F G H := BasedNatIso.id _ - leftUnitor {𝒳 𝒴} F := BasedNatIso.id F - rightUnitor {𝒳 𝒴} F := BasedNatIso.id F + whiskerLeft {_ _ _} F {_ _} α := whiskerLeft F α + whiskerRight {_ _ _} _ _ α H := whiskerRight α H + associator _ _ _ := BasedNatIso.id _ + leftUnitor {_ _} F := BasedNatIso.id F + rightUnitor {_ _} F := BasedNatIso.id F /-- The bicategory structure on `BasedCategory.{v₂, u₂} 𝒮` is strict. -/ instance : Bicategory.Strict (BasedCategory.{v₂, u₂} 𝒮) where diff --git a/Mathlib/CategoryTheory/FiberedCategory/Fiber.lean b/Mathlib/CategoryTheory/FiberedCategory/Fiber.lean new file mode 100644 index 0000000000000..94cfb1727d195 --- /dev/null +++ b/Mathlib/CategoryTheory/FiberedCategory/Fiber.lean @@ -0,0 +1,127 @@ +/- +Copyright (c) 2024 Calle Sönne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Calle Sönne, Paul Lezeau +-/ + +import Mathlib.CategoryTheory.FiberedCategory.HomLift +import Mathlib.CategoryTheory.Functor.Const + +/-! + +# Fibers of a functors + +In this file we define, for a functor `p : 𝒳 ⥤ 𝒴`, the fiber categories `Fiber p S` for every +`S : 𝒮` as follows +- An object in `Fiber p S` is a pair `(a, ha)` where `a : 𝒳` and `ha : p.obj a = S`. +- A morphism in `Fiber p S` is a morphism `φ : a ⟶ b` in 𝒳 such that `p.map φ = 𝟙 S`. + +For any category `C` equipped with a functor `F : C ⥤ 𝒳` such that `F ⋙ p` is constant at `S`, +we define a functor `inducedFunctor : C ⥤ Fiber p S` that `F` factors through. +-/ + +universe v₁ u₁ v₂ u₂ v₃ u₃ + +namespace CategoryTheory + +open IsHomLift + +namespace Functor + +variable {𝒮 : Type u₁} {𝒳 : Type u₂} [Category.{v₁} 𝒮] [Category.{v₂} 𝒳] + +/-- `Fiber p S` is the type of elements of `𝒳` mapping to `S` via `p`. -/ +def Fiber (p : 𝒳 ⥤ 𝒮) (S : 𝒮) := { a : 𝒳 // p.obj a = S } + +namespace Fiber + +variable {p : 𝒳 ⥤ 𝒮} {S : 𝒮} + +/-- `Fiber p S` has the structure of a category with morphisms being those lying over `𝟙 S`. -/ +instance fiberCategory : Category (Fiber p S) where + Hom a b := {φ : a.1 ⟶ b.1 // IsHomLift p (𝟙 S) φ} + id a := ⟨𝟙 a.1, IsHomLift.id a.2⟩ + comp φ ψ := ⟨φ.val ≫ ψ.val, by have := φ.2; have := ψ.2; infer_instance⟩ + +/-- The functor including `Fiber p S` into `𝒳`. -/ +def fiberInclusion : Fiber p S ⥤ 𝒳 where + obj a := a.1 + map φ := φ.1 + +instance {a b : Fiber p S} (φ : a ⟶ b) : IsHomLift p (𝟙 S) (fiberInclusion.map φ) := φ.2 + +@[ext] +lemma hom_ext {a b : Fiber p S} {φ ψ : a ⟶ b} + (h : fiberInclusion.map φ = fiberInclusion.map ψ) : φ = ψ := + Subtype.ext h + +instance : (fiberInclusion : Fiber p S ⥤ _).Faithful where + +/-- For fixed `S : 𝒮` this is the natural isomorphism between `fiberInclusion ⋙ p` and the constant +function valued at `S`. -/ +@[simps!] +def fiberInclusionCompIsoConst : fiberInclusion ⋙ p ≅ (const (Fiber p S)).obj S := + NatIso.ofComponents (fun X ↦ eqToIso X.2) + (fun φ ↦ by simp [IsHomLift.fac' p (𝟙 S) (fiberInclusion.map φ)]) + +lemma fiberInclusion_comp_eq_const : fiberInclusion ⋙ p = (const (Fiber p S)).obj S := + Functor.ext (fun x ↦ x.2) (fun _ _ φ ↦ IsHomLift.fac' p (𝟙 S) (fiberInclusion.map φ)) + +/-- The object of the fiber over `S` corresponding to a `a : 𝒳` such that `p(a) = S`. -/ +def mk {p : 𝒳 ⥤ 𝒮} {S : 𝒮} {a : 𝒳} (ha : p.obj a = S) : Fiber p S := ⟨a, ha⟩ + +@[simp] +lemma fiberInclusion_mk {p : 𝒳 ⥤ 𝒮} {S : 𝒮} {a : 𝒳} (ha : p.obj a = S) : + fiberInclusion.obj (mk ha) = a := + rfl + +/-- The morphism in the fiber over `S` corresponding to a morphism in `𝒳` lifting `𝟙 S`. -/ +def homMk (p : 𝒳 ⥤ 𝒮) (S : 𝒮) {a b : 𝒳} (φ : a ⟶ b) [IsHomLift p (𝟙 S) φ] : + mk (domain_eq p (𝟙 S) φ) ⟶ mk (codomain_eq p (𝟙 S) φ) := + ⟨φ, inferInstance⟩ + +@[simp] +lemma fiberInclusion_homMk (p : 𝒳 ⥤ 𝒮) (S : 𝒮) {a b : 𝒳} (φ : a ⟶ b) [IsHomLift p (𝟙 S) φ] : + fiberInclusion.map (homMk p S φ) = φ := + rfl + +@[simp] +lemma homMk_id (p : 𝒳 ⥤ 𝒮) (S : 𝒮) (a : 𝒳) [IsHomLift p (𝟙 S) (𝟙 a)] : + homMk p S (𝟙 a) = 𝟙 (mk (domain_eq p (𝟙 S) (𝟙 a))) := + rfl + +@[simp] +lemma homMk_comp {a b c : 𝒳} (φ : a ⟶ b) (ψ : b ⟶ c) [IsHomLift p (𝟙 S) φ] + [IsHomLift p (𝟙 S) ψ] : homMk p S φ ≫ homMk p S ψ = homMk p S (φ ≫ ψ) := + rfl + +section + +variable {p : 𝒳 ⥤ 𝒮} {S : 𝒮} {C : Type u₃} [Category.{v₃} C] {F : C ⥤ 𝒳} + (hF : F ⋙ p = (const C).obj S) + +/-- Given a functor `F : C ⥤ 𝒳` such that `F ⋙ p` is constant at some `S : 𝒮`, then +we get an induced functor `C ⥤ Fiber p S` that `F` factors through. -/ +@[simps] +def inducedFunctor : C ⥤ Fiber p S where + obj x := ⟨F.obj x, by simp only [← comp_obj, hF, const_obj_obj]⟩ + map φ := ⟨F.map φ, of_commsq _ _ _ _ _ <| by simpa using (eqToIso hF).hom.naturality φ⟩ + +@[simp] +lemma inducedFunctor_map {X Y : C} (f : X ⟶ Y) : + fiberInclusion.map ((inducedFunctor hF).map f) = F.map f := rfl + +/-- Given a functor `F : C ⥤ 𝒳` such that `F ⋙ p` is constant at some `S : 𝒮`, then +we get a natural isomorphism between `inducedFunctor _ ⋙ fiberInclusion` and `F`. -/ +@[simps!] +def inducedFunctorCompIsoSelf : (inducedFunctor hF) ⋙ fiberInclusion ≅ F := Iso.refl _ + +lemma inducedFunctor_comp : (inducedFunctor hF) ⋙ fiberInclusion = F := rfl + +end + +end Fiber + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean b/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean index 8de8bf2c92401..5d64e6e16c258 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean @@ -106,12 +106,16 @@ lemma of_fac' {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (ha : p.obj obtain rfl : f = p.map φ := by simpa using h.symm infer_instance -lemma of_commSq {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (ha : p.obj a = R) (hb : p.obj b = S) - (h : CommSq (p.map φ) (eqToHom ha) (eqToHom hb) f) : p.IsHomLift f φ := by +lemma of_commsq {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (ha : p.obj a = R) (hb : p.obj b = S) + (h : p.map φ ≫ eqToHom hb = (eqToHom ha) ≫ f) : p.IsHomLift f φ := by subst ha hb - obtain rfl : f = p.map φ := by simpa using h.1.symm + obtain rfl : f = p.map φ := by simpa using h.symm infer_instance +lemma of_commSq {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (ha : p.obj a = R) (hb : p.obj b = S) + (h : CommSq (p.map φ) (eqToHom ha) (eqToHom hb) f) : p.IsHomLift f φ := + of_commsq p f φ ha hb h.1 + instance comp {R S T : 𝒮} {a b c : 𝒳} (f : R ⟶ S) (g : S ⟶ T) (φ : a ⟶ b) (ψ : b ⟶ c) [p.IsHomLift f φ] [p.IsHomLift g ψ] : p.IsHomLift (f ≫ g) (φ ≫ ψ) := by apply of_commSq @@ -180,25 +184,25 @@ instance lift_comp_eqToHom {R S S' : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a lemma comp_eqToHom_lift_iff {R S : 𝒮} {a' a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (h : a' = a) : p.IsHomLift f (eqToHom h ≫ φ) ↔ p.IsHomLift f φ where mp hφ' := by subst h; simpa using hφ' - mpr hφ := inferInstance + mpr _ := inferInstance @[simp] lemma eqToHom_comp_lift_iff {R S : 𝒮} {a b b' : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (h : b = b') : p.IsHomLift f (φ ≫ eqToHom h) ↔ p.IsHomLift f φ where mp hφ' := by subst h; simpa using hφ' - mpr hφ := inferInstance + mpr _ := inferInstance @[simp] lemma lift_eqToHom_comp_iff {R' R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (h : R' = R) : p.IsHomLift (eqToHom h ≫ f) φ ↔ p.IsHomLift f φ where mp hφ' := by subst h; simpa using hφ' - mpr hφ := inferInstance + mpr _ := inferInstance @[simp] lemma lift_comp_eqToHom_iff {R S S' : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) (h : S = S') : p.IsHomLift (f ≫ eqToHom h) φ ↔ p.IsHomLift f φ where mp := fun hφ' => by subst h; simpa using hφ' - mpr := fun hφ => inferInstance + mpr := fun _ => inferInstance section diff --git a/Mathlib/CategoryTheory/Filtered/Basic.lean b/Mathlib/CategoryTheory/Filtered/Basic.lean index 688a1d9ce43a8..16dc0ee0d321c 100644 --- a/Mathlib/CategoryTheory/Filtered/Basic.lean +++ b/Mathlib/CategoryTheory/Filtered/Basic.lean @@ -540,7 +540,7 @@ example (α : Type u) [SemilatticeInf α] [OrderBot α] : IsCofiltered α := by example (α : Type u) [SemilatticeInf α] [OrderTop α] : IsCofiltered α := by infer_instance instance : IsCofiltered (Discrete PUnit) where - cone_objs X Y := ⟨⟨PUnit.unit⟩, ⟨⟨by trivial⟩⟩, ⟨⟨by subsingleton⟩⟩, trivial⟩ + cone_objs _ Y := ⟨⟨PUnit.unit⟩, ⟨⟨by trivial⟩⟩, ⟨⟨by subsingleton⟩⟩, trivial⟩ cone_maps X Y f g := ⟨⟨PUnit.unit⟩, ⟨⟨by trivial⟩⟩, by apply ULift.ext subsingleton⟩ diff --git a/Mathlib/CategoryTheory/FinCategory/AsType.lean b/Mathlib/CategoryTheory/FinCategory/AsType.lean index 1ba7c2d3cd220..dafd99f417b23 100644 --- a/Mathlib/CategoryTheory/FinCategory/AsType.lean +++ b/Mathlib/CategoryTheory/FinCategory/AsType.lean @@ -43,7 +43,7 @@ abbrev AsType : Type := @[simps (config := .lemmasOnly) id comp] noncomputable instance categoryAsType : SmallCategory (AsType α) where Hom i j := Fin (Fintype.card (@Quiver.Hom (ObjAsType α) _ i j)) - id i := Fintype.equivFin _ (𝟙 _) + id _ := Fintype.equivFin _ (𝟙 _) comp f g := Fintype.equivFin _ ((Fintype.equivFin _).symm f ≫ (Fintype.equivFin _).symm g) attribute [local simp] categoryAsType_id categoryAsType_comp @@ -52,13 +52,13 @@ attribute [local simp] categoryAsType_id categoryAsType_comp @[simps] noncomputable def asTypeToObjAsType : AsType α ⥤ ObjAsType α where obj := id - map {X Y} := (Fintype.equivFin _).symm + map {_ _} := (Fintype.equivFin _).symm /-- The "identity" functor from `ObjAsType α` to `AsType α`. -/ @[simps] noncomputable def objAsTypeToAsType : ObjAsType α ⥤ AsType α where obj := id - map {X Y} := Fintype.equivFin _ + map {_ _} := Fintype.equivFin _ /-- The constructed category (`AsType α`) is equivalent to `ObjAsType α`. -/ noncomputable def asTypeEquivObjAsType : AsType α ≌ ObjAsType α where diff --git a/Mathlib/CategoryTheory/FintypeCat.lean b/Mathlib/CategoryTheory/FintypeCat.lean index 30efd8e330d9f..519fda3a21f04 100644 --- a/Mathlib/CategoryTheory/FintypeCat.lean +++ b/Mathlib/CategoryTheory/FintypeCat.lean @@ -6,7 +6,7 @@ Authors: Bhavik Mehta, Adam Topaz import Mathlib.CategoryTheory.ConcreteCategory.Basic import Mathlib.CategoryTheory.Endomorphism import Mathlib.CategoryTheory.Skeletal -import Mathlib.Data.Finite.Basic +import Mathlib.Data.Finite.Prod /-! # The category of finite types. diff --git a/Mathlib/CategoryTheory/Functor/Category.lean b/Mathlib/CategoryTheory/Functor/Category.lean index e1f0445ab692b..7a1687ae5667d 100644 --- a/Mathlib/CategoryTheory/Functor/Category.lean +++ b/Mathlib/CategoryTheory/Functor/Category.lean @@ -48,10 +48,6 @@ instance Functor.category : Category.{max u₁ v₂} (C ⥤ D) where namespace NatTrans --- Porting note: the behaviour of `ext` has changed here. --- We need to provide a copy of the `NatTrans.ext` lemma, --- written in terms of `F ⟶ G` rather than `NatTrans F G`, --- or `ext` will not retrieve it from the cache. @[ext] theorem ext' {α β : F ⟶ G} (w : α.app = β.app) : α = β := NatTrans.ext w diff --git a/Mathlib/CategoryTheory/Functor/Const.lean b/Mathlib/CategoryTheory/Functor/Const.lean index 5c783b8742f00..ba2d6a7b37e98 100644 --- a/Mathlib/CategoryTheory/Functor/Const.lean +++ b/Mathlib/CategoryTheory/Functor/Const.lean @@ -47,16 +47,16 @@ is (naturally isomorphic to) the opposite of the constant functor `J ⥤ C` send -/ @[simps] def opObjOp (X : C) : (const Jᵒᵖ).obj (op X) ≅ ((const J).obj X).op where - hom := { app := fun j => 𝟙 _ } - inv := { app := fun j => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } /-- The constant functor `Jᵒᵖ ⥤ C` sending everything to `unop X` is (naturally isomorphic to) the opposite of the constant functor `J ⥤ Cᵒᵖ` sending everything to `X`. -/ def opObjUnop (X : Cᵒᵖ) : (const Jᵒᵖ).obj (unop X) ≅ ((const J).obj X).leftOp where - hom := { app := fun j => 𝟙 _ } - inv := { app := fun j => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } -- Lean needs some help with universes here. @[simp] @@ -96,9 +96,16 @@ instance [Nonempty J] : Faithful (const J : C ⥤ J ⥤ C) where def compConstIso (F : C ⥤ D) : F ⋙ Functor.const J ≅ Functor.const J ⋙ (whiskeringRight J C D).obj F := NatIso.ofComponents - (fun X => NatIso.ofComponents (fun j => Iso.refl _) (by aesop_cat)) + (fun X => NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat)) (by aesop_cat) +/-- The canonical isomorphism +`const D ⋙ (whiskeringLeft J _ _).obj F ≅ const J`.-/ +@[simps!] +def constCompWhiskeringLeftIso (F : J ⥤ D) : + const D ⋙ (whiskeringLeft J D C).obj F ≅ const J := + NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _ + end end CategoryTheory.Functor diff --git a/Mathlib/CategoryTheory/Functor/Currying.lean b/Mathlib/CategoryTheory/Functor/Currying.lean index e130aedb422c8..5c8021e9a84c0 100644 --- a/Mathlib/CategoryTheory/Functor/Currying.lean +++ b/Mathlib/CategoryTheory/Functor/Currying.lean @@ -91,13 +91,13 @@ def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E where /-- `F.flip` is isomorphic to uncurrying `F`, swapping the variables, and currying. -/ @[simps!] def flipIsoCurrySwapUncurry (F : C ⥤ D ⥤ E) : F.flip ≅ curry.obj (Prod.swap _ _ ⋙ uncurry.obj F) := - NatIso.ofComponents fun d => NatIso.ofComponents fun c => Iso.refl _ + NatIso.ofComponents fun d => NatIso.ofComponents fun _ => Iso.refl _ /-- The uncurrying of `F.flip` is isomorphic to swapping the factors followed by the uncurrying of `F`. -/ @[simps!] def uncurryObjFlip (F : C ⥤ D ⥤ E) : uncurry.obj F.flip ≅ Prod.swap _ _ ⋙ uncurry.obj F := - NatIso.ofComponents fun p => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ variable (B C D E) diff --git a/Mathlib/CategoryTheory/Functor/EpiMono.lean b/Mathlib/CategoryTheory/Functor/EpiMono.lean index 428607bf319fa..b5e733749ce52 100644 --- a/Mathlib/CategoryTheory/Functor/EpiMono.lean +++ b/Mathlib/CategoryTheory/Functor/EpiMono.lean @@ -170,13 +170,13 @@ instance (priority := 100) preservesMonomorphisms_of_isRightAdjoint (F : C ⥤ D instance (priority := 100) reflectsMonomorphisms_of_faithful (F : C ⥤ D) [Faithful F] : ReflectsMonomorphisms F where - reflects {X} {Y} f hf := + reflects {X} {Y} f _ := ⟨fun {Z} g h hgh => F.map_injective ((cancel_mono (F.map f)).1 (by rw [← F.map_comp, hgh, F.map_comp]))⟩ instance (priority := 100) reflectsEpimorphisms_of_faithful (F : C ⥤ D) [Faithful F] : ReflectsEpimorphisms F where - reflects {X} {Y} f hf := + reflects {X} {Y} f _ := ⟨fun {Z} g h hgh => F.map_injective ((cancel_epi (F.map f)).1 (by rw [← F.map_comp, hgh, F.map_comp]))⟩ @@ -253,8 +253,8 @@ namespace CategoryTheory.Adjunction variable {C D : Type*} [Category C] [Category D] {F : C ⥤ D} {F' : D ⥤ C} {A B : C} -theorem strongEpi_map_of_strongEpi (adj : F ⊣ F') (f : A ⟶ B) [h₁ : F'.PreservesMonomorphisms] - [h₂ : F.PreservesEpimorphisms] [StrongEpi f] : StrongEpi (F.map f) := +theorem strongEpi_map_of_strongEpi (adj : F ⊣ F') (f : A ⟶ B) [F'.PreservesMonomorphisms] + [F.PreservesEpimorphisms] [StrongEpi f] : StrongEpi (F.map f) := ⟨inferInstance, fun X Y Z => by intro rw [adj.hasLiftingProperty_iff] diff --git a/Mathlib/CategoryTheory/Functor/Flat.lean b/Mathlib/CategoryTheory/Functor/Flat.lean index 81deab9624ac3..01a05f0a295f2 100644 --- a/Mathlib/CategoryTheory/Functor/Flat.lean +++ b/Mathlib/CategoryTheory/Functor/Flat.lean @@ -125,7 +125,7 @@ noncomputable def lift : s.pt ⟶ F.obj c.pt := (F.map <| hc.lift <| (Cones.postcompose - ({ app := fun X => 𝟙 _ } : + ({ app := fun _ => 𝟙 _ } : (s.toStructuredArrow ⋙ pre s.pt K F) ⋙ proj s.pt F ⟶ K)).obj <| (StructuredArrow.proj s.pt F).mapCone s') @@ -275,7 +275,7 @@ noncomputable instance lanPreservesFiniteLimitsOfPreservesFiniteLimits (F : C theorem flat_iff_lan_flat (F : C ⥤ D) : RepresentablyFlat F ↔ RepresentablyFlat (F.op.lan : _ ⥤ Dᵒᵖ ⥤ Type u₁) := - ⟨fun H => inferInstance, fun H => by + ⟨fun _ => inferInstance, fun H => by haveI := preservesFiniteLimitsOfFlat (F.op.lan : _ ⥤ Dᵒᵖ ⥤ Type u₁) haveI : PreservesFiniteLimits F := by apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁} diff --git a/Mathlib/CategoryTheory/Functor/FunctorHom.lean b/Mathlib/CategoryTheory/Functor/FunctorHom.lean index bd8ab6a9e031e..3f4312c687eaa 100644 --- a/Mathlib/CategoryTheory/Functor/FunctorHom.lean +++ b/Mathlib/CategoryTheory/Functor/FunctorHom.lean @@ -203,6 +203,6 @@ lemma associator_hom_apply (K L M N : C ⥤ D) {X : C} noncomputable instance : EnrichedCategory (C ⥤ Type max v' v u) (C ⥤ D) where Hom := functorHom id F := natTransEquiv.symm (𝟙 F) - comp F G H := { app := fun X ⟨f, g⟩ => f.comp g } + comp F G H := { app := fun _ ⟨f, g⟩ => f.comp g } end CategoryTheory.Enriched.Functor diff --git a/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean b/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean index fe8433c905fb7..8998a80ca9e01 100644 --- a/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean +++ b/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean @@ -22,7 +22,7 @@ right Kan extension along `L`. namespace CategoryTheory -open Category +open Category Limits namespace Functor @@ -56,6 +56,28 @@ noncomputable def isPointwiseLeftKanExtensionLanUnit (LeftExtension.mk _ (L.lanUnit.app F)).IsPointwiseLeftKanExtension := isPointwiseLeftKanExtensionOfIsLeftKanExtension (F := F) _ (L.lanUnit.app F) +/-- If a left Kan extension is pointwise, then evaluating it at an object is isomorphic to +taking a colimit. -/ +noncomputable def lanObjObjIsoColimit (F : C ⥤ H) [HasPointwiseLeftKanExtension L F] (X : D) : + (L.lan.obj F).obj X ≅ Limits.colimit (CostructuredArrow.proj L X ⋙ F) := + LeftExtension.IsPointwiseLeftKanExtensionAt.isoColimit (F := F) + (isPointwiseLeftKanExtensionLanUnit L F X) + +@[reassoc (attr := simp)] +lemma ι_lanObjObjIsoColimit_inv + (F : C ⥤ H) [HasPointwiseLeftKanExtension L F] (X : D) (f : CostructuredArrow L X) : + Limits.colimit.ι _ f ≫ (L.lanObjObjIsoColimit F X).inv = + (L.lanUnit.app F).app f.left ≫ (L.lan.obj F).map f.hom := by + simp [lanObjObjIsoColimit, lanUnit] + +@[reassoc (attr := simp)] +lemma ι_lanObjObjIsoColimit_hom + (F : C ⥤ H) [HasPointwiseLeftKanExtension L F] (X : D) (f : CostructuredArrow L X) : + (L.lanUnit.app F).app f.left ≫ (L.lan.obj F).map f.hom ≫ (L.lanObjObjIsoColimit F X).hom = + Limits.colimit.ι (CostructuredArrow.proj L X ⋙ F) f := + LeftExtension.IsPointwiseLeftKanExtensionAt.ι_isoColimit_hom (F := F) + (isPointwiseLeftKanExtensionLanUnit L F X) f + variable (H) in /-- The left Kan extension functor `L.Lan` is left adjoint to the precomposition by `L`. -/ @@ -100,6 +122,20 @@ lemma isIso_lanAdjunction_counit_app_iff (G : D ⥤ H) : IsIso ((L.lanAdjunction H).counit.app G) ↔ G.IsLeftKanExtension (𝟙 (L ⋙ G)) := (isLeftKanExtension_iff_isIso _ (L.lanUnit.app (L ⋙ G)) _ (by simp)).symm +/-- Composing the left Kan extension of `L : C ⥤ D` with `colim` on shapes `D` is isomorphic +to `colim` on shapes `C`. -/ +@[simps!] +noncomputable def lanCompColimIso (L : C ⥤ D) [∀ (G : C ⥤ H), L.HasLeftKanExtension G] + [HasColimitsOfShape C H] [HasColimitsOfShape D H] : L.lan ⋙ colim ≅ colim (C := H) := + Iso.symm <| NatIso.ofComponents + (fun G ↦ (colimitIsoOfIsLeftKanExtension _ (L.lanUnit.app G)).symm) + (fun f ↦ colimit.hom_ext (fun i ↦ by + dsimp + rw [ι_colimMap_assoc, ι_colimitIsoOfIsLeftKanExtension_inv, + ι_colimitIsoOfIsLeftKanExtension_inv_assoc, ι_colimMap, ← assoc, ← assoc] + congr 1 + exact congr_app (L.lanUnit.naturality f) i)) + end section @@ -162,6 +198,28 @@ noncomputable def isPointwiseRightKanExtensionRanCounit (RightExtension.mk _ (L.ranCounit.app F)).IsPointwiseRightKanExtension := isPointwiseRightKanExtensionOfIsRightKanExtension (F := F) _ (L.ranCounit.app F) +/-- If a right Kan extension is pointwise, then evaluating it at an object is isomorphic to +taking a limit. -/ +noncomputable def ranObjObjIsoLimit (F : C ⥤ H) [HasPointwiseRightKanExtension L F] (X : D) : + (L.ran.obj F).obj X ≅ Limits.limit (StructuredArrow.proj X L ⋙ F) := + RightExtension.IsPointwiseRightKanExtensionAt.isoLimit (F := F) + (isPointwiseRightKanExtensionRanCounit L F X) + +@[reassoc (attr := simp)] +lemma ranObjObjIsoLimit_hom_π + (F : C ⥤ H) [HasPointwiseRightKanExtension L F] (X : D) (f : StructuredArrow X L) : + (L.ranObjObjIsoLimit F X).hom ≫ Limits.limit.π _ f = + (L.ran.obj F).map f.hom ≫ (L.ranCounit.app F).app f.right := by + simp [ranObjObjIsoLimit, ran, ranCounit] + +@[reassoc (attr := simp)] +lemma ranObjObjIsoLimit_inv_π + (F : C ⥤ H) [HasPointwiseRightKanExtension L F] (X : D) (f : StructuredArrow X L) : + (L.ranObjObjIsoLimit F X).inv ≫ (L.ran.obj F).map f.hom ≫ (L.ranCounit.app F).app f.right = + Limits.limit.π _ f := + RightExtension.IsPointwiseRightKanExtensionAt.isoLimit_inv_π (F := F) + (isPointwiseRightKanExtensionRanCounit L F X) f + variable (H) in /-- The right Kan extension functor `L.ran` is right adjoint to the precomposition by `L`. -/ @@ -207,6 +265,20 @@ lemma isIso_ranAdjunction_unit_app_iff (G : D ⥤ H) : IsIso ((L.ranAdjunction H).unit.app G) ↔ G.IsRightKanExtension (𝟙 (L ⋙ G)) := (isRightKanExtension_iff_isIso _ (L.ranCounit.app (L ⋙ G)) _ (by simp)).symm +/-- Composing the right Kan extension of `L : C ⥤ D` with `lim` on shapes `D` is isomorphic +to `lim` on shapes `C`. -/ +@[simps!] +noncomputable def ranCompLimIso (L : C ⥤ D) [∀ (G : C ⥤ H), L.HasRightKanExtension G] + [HasLimitsOfShape C H] [HasLimitsOfShape D H] : L.ran ⋙ lim ≅ lim (C := H) := + NatIso.ofComponents + (fun G ↦ limitIsoOfIsRightKanExtension _ (L.ranCounit.app G)) + (fun f ↦ limit.hom_ext (fun i ↦ by + dsimp + rw [assoc, assoc, limMap_π, limitIsoOfIsRightKanExtension_hom_π_assoc, + limitIsoOfIsRightKanExtension_hom_π, limMap_π_assoc] + congr 1 + exact congr_app (L.ranCounit.naturality f) i)) + end section diff --git a/Mathlib/CategoryTheory/Functor/KanExtension/Basic.lean b/Mathlib/CategoryTheory/Functor/KanExtension/Basic.lean index 32996f6d67fcb..4ea68229bb26b 100644 --- a/Mathlib/CategoryTheory/Functor/KanExtension/Basic.lean +++ b/Mathlib/CategoryTheory/Functor/KanExtension/Basic.lean @@ -3,7 +3,7 @@ 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.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic import Mathlib.CategoryTheory.Limits.Shapes.Equivalence import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Terminal @@ -36,8 +36,7 @@ open Category Limits namespace Functor -variable {C C' H H' D D' : Type*} [Category C] [Category C'] [Category H] [Category H'] - [Category D] [Category D'] +variable {C C' H D D' : Type*} [Category C] [Category C'] [Category H] [Category D] [Category D'] /-- Given two functors `L : C ⥤ D` and `F : C ⥤ H`, this is the category of functors `F' : H ⥤ D` equipped with a natural transformation `L ⋙ F' ⟶ F`. -/ @@ -545,6 +544,106 @@ lemma isRightKanExtension_iff_of_iso₂ {F₁' F₂' : D ⥤ H} (α₁ : L ⋙ F end +section Colimit + +variable (F' : D ⥤ H) {L : C ⥤ D} {F : C ⥤ H} (α : F ⟶ L ⋙ F') [F'.IsLeftKanExtension α] + +/-- Construct a cocone for a left Kan extension `F' : D ⥤ H` of `F : C ⥤ H` along a functor +`L : C ⥤ D` given a cocone for `F`. -/ +@[simps] +noncomputable def coconeOfIsLeftKanExtension (c : Cocone F) : Cocone F' where + pt := c.pt + ι := F'.descOfIsLeftKanExtension α _ c.ι + +/-- If `c` is a colimit cocone for a functor `F : C ⥤ H` and `α : F ⟶ L ⋙ F'` is the unit of any +left Kan extension `F' : D ⥤ H` of `F` along `L : C ⥤ D`, then `coconeOfIsLeftKanExtension α c` is +a colimit cocone, too. -/ +@[simps] +def isColimitCoconeOfIsLeftKanExtension {c : Cocone F} (hc : IsColimit c) : + IsColimit (F'.coconeOfIsLeftKanExtension α c) where + desc s := hc.desc (Cocone.mk _ (α ≫ whiskerLeft L s.ι)) + fac s := by + have : F'.descOfIsLeftKanExtension α ((const D).obj c.pt) c.ι ≫ + (Functor.const _).map (hc.desc (Cocone.mk _ (α ≫ whiskerLeft L s.ι))) = s.ι := + F'.hom_ext_of_isLeftKanExtension α _ _ (by aesop_cat) + exact congr_app this + uniq s m hm := hc.hom_ext (fun j ↦ by + have := hm (L.obj j) + nth_rw 1 [← F'.descOfIsLeftKanExtension_fac_app α ((const D).obj c.pt)] + dsimp at this ⊢ + rw [assoc, this, IsColimit.fac, NatTrans.comp_app, whiskerLeft_app]) + +variable [HasColimit F] [HasColimit F'] + +/-- If `F' : D ⥤ H` is a left Kan extension of `F : C ⥤ H` along `L : C ⥤ D`, the colimit over `F'` +is isomorphic to the colimit over `F`. -/ +noncomputable def colimitIsoOfIsLeftKanExtension : colimit F' ≅ colimit F := + IsColimit.coconePointUniqueUpToIso (colimit.isColimit F') + (F'.isColimitCoconeOfIsLeftKanExtension α (colimit.isColimit F)) + +@[reassoc (attr := simp)] +lemma ι_colimitIsoOfIsLeftKanExtension_hom (i : C) : + α.app i ≫ colimit.ι F' (L.obj i) ≫ (F'.colimitIsoOfIsLeftKanExtension α).hom = + colimit.ι F i := by + simp [colimitIsoOfIsLeftKanExtension] + +@[reassoc (attr := simp)] +lemma ι_colimitIsoOfIsLeftKanExtension_inv (i : C) : + colimit.ι F i ≫ (F'.colimitIsoOfIsLeftKanExtension α).inv = + α.app i ≫ colimit.ι F' (L.obj i) := by + rw [Iso.comp_inv_eq, assoc, ι_colimitIsoOfIsLeftKanExtension_hom] + +end Colimit + +section Limit + +variable (F' : D ⥤ H) {L : C ⥤ D} {F : C ⥤ H} (α : L ⋙ F' ⟶ F) [F'.IsRightKanExtension α] + +/-- Construct a cone for a right Kan extension `F' : D ⥤ H` of `F : C ⥤ H` along a functor +`L : C ⥤ D` given a cone for `F`. -/ +@[simps] +noncomputable def coneOfIsRightKanExtension (c : Cone F) : Cone F' where + pt := c.pt + π := F'.liftOfIsRightKanExtension α _ c.π + +/-- If `c` is a limit cone for a functor `F : C ⥤ H` and `α : L ⋙ F' ⟶ F` is the counit of any +right Kan extension `F' : D ⥤ H` of `F` along `L : C ⥤ D`, then `coneOfIsRightKanExtension α c` is +a limit cone, too. -/ +@[simps] +def isLimitConeOfIsRightKanExtension {c : Cone F} (hc : IsLimit c) : + IsLimit (F'.coneOfIsRightKanExtension α c) where + lift s := hc.lift (Cone.mk _ (whiskerLeft L s.π ≫ α)) + fac s := by + have : (Functor.const _).map (hc.lift (Cone.mk _ (whiskerLeft L s.π ≫ α))) ≫ + F'.liftOfIsRightKanExtension α ((const D).obj c.pt) c.π = s.π := + F'.hom_ext_of_isRightKanExtension α _ _ (by aesop_cat) + exact congr_app this + uniq s m hm := hc.hom_ext (fun j ↦ by + have := hm (L.obj j) + nth_rw 1 [← F'.liftOfIsRightKanExtension_fac_app α ((const D).obj c.pt)] + dsimp at this ⊢ + rw [← assoc, this, IsLimit.fac, NatTrans.comp_app, whiskerLeft_app]) + +variable [HasLimit F] [HasLimit F'] + +/-- If `F' : D ⥤ H` is a right Kan extension of `F : C ⥤ H` along `L : C ⥤ D`, the limit over `F'` +is isomorphic to the limit over `F`. -/ +noncomputable def limitIsoOfIsRightKanExtension : limit F' ≅ limit F := + IsLimit.conePointUniqueUpToIso (limit.isLimit F') + (F'.isLimitConeOfIsRightKanExtension α (limit.isLimit F)) + +@[reassoc (attr := simp)] +lemma limitIsoOfIsRightKanExtension_inv_π (i : C) : + (F'.limitIsoOfIsRightKanExtension α).inv ≫ limit.π F' (L.obj i) ≫ α.app i = limit.π F i := by + simp [limitIsoOfIsRightKanExtension] + +@[reassoc (attr := simp)] +lemma limitIsoOfIsRightKanExtension_hom_π (i : C) : + (F'.limitIsoOfIsRightKanExtension α).hom ≫ limit.π F i = limit.π F' (L.obj i) ≫ α.app i := by + rw [← Iso.eq_inv_comp, limitIsoOfIsRightKanExtension_inv_π] + +end Limit + end Functor end CategoryTheory diff --git a/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean b/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean index 9d4cb7a6c2ea1..a1a044d1a3846 100644 --- a/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean +++ b/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean @@ -98,6 +98,30 @@ lemma IsPointwiseLeftKanExtensionAt.isIso_hom_app IsIso (E.hom.app X) := by simpa using h.isIso_ι_app_of_isTerminal _ CostructuredArrow.mkIdTerminal +namespace IsPointwiseLeftKanExtensionAt + +variable {E} {Y : D} (h : E.IsPointwiseLeftKanExtensionAt Y) + [HasColimit (CostructuredArrow.proj L Y ⋙ F)] + +/-- A pointwise left Kan extension of `F` along `L` applied to an object `Y` is isomorphic to +`colimit (CostructuredArrow.proj L Y ⋙ F)`. -/ +noncomputable def isoColimit : + E.right.obj Y ≅ colimit (CostructuredArrow.proj L Y ⋙ F) := + h.coconePointUniqueUpToIso (colimit.isColimit _) + +@[reassoc (attr := simp)] +lemma ι_isoColimit_inv (g : CostructuredArrow L Y) : + colimit.ι _ g ≫ h.isoColimit.inv = E.hom.app g.left ≫ E.right.map g.hom := + IsColimit.comp_coconePointUniqueUpToIso_inv _ _ _ + +@[reassoc (attr := simp)] +lemma ι_isoColimit_hom (g : CostructuredArrow L Y) : + E.hom.app g.left ≫ E.right.map g.hom ≫ h.isoColimit.hom = + colimit.ι (CostructuredArrow.proj L Y ⋙ F) g := by + simpa using h.comp_coconePointUniqueUpToIso_hom (colimit.isColimit _) g + +end IsPointwiseLeftKanExtensionAt + /-- A left extension `E : LeftExtension L F` is a pointwise left Kan extension when it is a pointwise left Kan extension at any object. -/ abbrev IsPointwiseLeftKanExtension := ∀ (Y : D), E.IsPointwiseLeftKanExtensionAt Y @@ -211,6 +235,30 @@ lemma IsPointwiseRightKanExtensionAt.isIso_hom_app IsIso (E.hom.app X) := by simpa using h.isIso_π_app_of_isInitial _ StructuredArrow.mkIdInitial +namespace IsPointwiseRightKanExtensionAt + +variable {E} {Y : D} (h : E.IsPointwiseRightKanExtensionAt Y) + [HasLimit (StructuredArrow.proj Y L ⋙ F)] + +/-- A pointwise right Kan extension of `F` along `L` applied to an object `Y` is isomorphic to +`limit (StructuredArrow.proj Y L ⋙ F)`. -/ +noncomputable def isoLimit : + E.left.obj Y ≅ limit (StructuredArrow.proj Y L ⋙ F) := + h.conePointUniqueUpToIso (limit.isLimit _) + +@[reassoc (attr := simp)] +lemma isoLimit_hom_π (g : StructuredArrow Y L) : + h.isoLimit.hom ≫ limit.π _ g = E.left.map g.hom ≫ E.hom.app g.right := + IsLimit.conePointUniqueUpToIso_hom_comp _ _ _ + +@[reassoc (attr := simp)] +lemma isoLimit_inv_π (g : StructuredArrow Y L) : + h.isoLimit.inv ≫ E.left.map g.hom ≫ E.hom.app g.right = + limit.π (StructuredArrow.proj Y L ⋙ F) g := by + simpa using h.conePointUniqueUpToIso_inv_comp (limit.isLimit _) g + +end IsPointwiseRightKanExtensionAt + /-- A right extension `E : RightExtension L F` is a pointwise right Kan extension when it is a pointwise right Kan extension at any object. -/ abbrev IsPointwiseRightKanExtension := ∀ (Y : D), E.IsPointwiseRightKanExtensionAt Y diff --git a/Mathlib/CategoryTheory/Functor/OfSequence.lean b/Mathlib/CategoryTheory/Functor/OfSequence.lean index ef7b877cddbf6..ba70972cf1661 100644 --- a/Mathlib/CategoryTheory/Functor/OfSequence.lean +++ b/Mathlib/CategoryTheory/Functor/OfSequence.lean @@ -18,6 +18,9 @@ We also provide a constructor `NatTrans.ofSequence` for natural transformations between functors `ℕ ⥤ C` which allows to check the naturality condition only for morphisms `n ⟶ n + 1`. +The duals of the above for functors `ℕᵒᵖ ⥤ C` are given by `Functor.ofOpSequence` and +`NatTrans.ofOpSequence`. + -/ namespace CategoryTheory @@ -43,7 +46,7 @@ def map : ∀ {X : ℕ → C} (_ : ∀ n, X n ⟶ X (n + 1)) (i j : ℕ), i ≤ | _, _, 0, 0 => fun _ ↦ 𝟙 _ | _, f, 0, 1 => fun _ ↦ f 0 | _, f, 0, l + 1 => fun _ ↦ f 0 ≫ map (fun n ↦ f (n + 1)) 0 l (by omega) - | _, _, k + 1, 0 => nofun + | _, _, _ + 1, 0 => nofun | _, f, k + 1, l + 1 => fun _ ↦ map (fun n ↦ f (n + 1)) k l (by omega) lemma map_id (i : ℕ) : map f i i (by omega) = 𝟙 _ := by @@ -144,4 +147,45 @@ def ofSequence : F ⟶ G where end NatTrans +namespace Functor + +variable {X : ℕ → C} (f : ∀ n, X (n + 1) ⟶ X n) + +/-- The functor `ℕᵒᵖ ⥤ C` constructed from a sequence of +morphisms `f : X (n + 1) ⟶ X n` for all `n : ℕ`. -/ +@[simps! obj] +def ofOpSequence : ℕᵒᵖ ⥤ C := (ofSequence (fun n ↦ (f n).op)).leftOp + +-- `ofOpSequence` has good definitional properties when applied to explicit natural numbers +example : (ofOpSequence f).map (homOfLE (show 5 ≤ 5 by omega)).op = 𝟙 _ := rfl +example : (ofOpSequence f).map (homOfLE (show 0 ≤ 3 by omega)).op = (f 2 ≫ f 1) ≫ f 0 := rfl +example : (ofOpSequence f).map (homOfLE (show 3 ≤ 7 by omega)).op = + ((f 6 ≫ f 5) ≫ f 4) ≫ f 3 := rfl + +@[simp] +lemma ofOpSequence_map_homOfLE_succ (n : ℕ) : + (ofOpSequence f).map (homOfLE (Nat.le_add_right n 1)).op = f n := by + simp [ofOpSequence] + +end Functor + +namespace NatTrans + +variable {F G : ℕᵒᵖ ⥤ C} (app : ∀ (n : ℕ), F.obj ⟨n⟩ ⟶ G.obj ⟨n⟩) + (naturality : ∀ (n : ℕ), F.map (homOfLE (n.le_add_right 1)).op ≫ app n = + app (n + 1) ≫ G.map (homOfLE (n.le_add_right 1)).op) + +/-- Constructor for natural transformations `F ⟶ G` in `ℕᵒᵖ ⥤ C` which takes as inputs +the morphisms `F.obj ⟨n⟩ ⟶ G.obj ⟨n⟩` for all `n : ℕ` and the naturality condition only +for morphisms of the form `n ⟶ n + 1`. -/ +@[simps!] +def ofOpSequence : F ⟶ G where + app n := app n.unop + naturality _ _ f := by + let φ : G.rightOp ⟶ F.rightOp := ofSequence (fun n ↦ (app n).op) + (fun n ↦ Quiver.Hom.unop_inj (naturality n).symm) + exact Quiver.Hom.op_inj (φ.naturality f.unop).symm + +end NatTrans + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Functor/Trifunctor.lean b/Mathlib/CategoryTheory/Functor/Trifunctor.lean index 14409f1efe904..f1293cf7bb221 100644 --- a/Mathlib/CategoryTheory/Functor/Trifunctor.lean +++ b/Mathlib/CategoryTheory/Functor/Trifunctor.lean @@ -31,7 +31,7 @@ variable (F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂) (G : C₁₂ ⥤ C₃ ⥤ C₄) def bifunctorComp₁₂Obj (X₁ : C₁) : C₂ ⥤ C₃ ⥤ C₄ where obj X₂ := { obj := fun X₃ => (G.obj ((F₁₂.obj X₁).obj X₂)).obj X₃ - map := fun {X₃ Y₃} φ => (G.obj ((F₁₂.obj X₁).obj X₂)).map φ } + map := fun {_ _} φ => (G.obj ((F₁₂.obj X₁).obj X₂)).map φ } map {X₂ Y₂} φ := { app := fun X₃ => (G.map ((F₁₂.obj X₁).map φ)).app X₃ } @@ -59,7 +59,7 @@ variable (F : C₁ ⥤ C₂₃ ⥤ C₄) (G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃) def bifunctorComp₂₃Obj (X₁ : C₁) : C₂ ⥤ C₃ ⥤ C₄ where obj X₂ := { obj := fun X₃ => (F.obj X₁).obj ((G₂₃.obj X₂).obj X₃) - map := fun {X₃ Y₃} φ => (F.obj X₁).map ((G₂₃.obj X₂).map φ) } + map := fun {_ _} φ => (F.obj X₁).map ((G₂₃.obj X₂).map φ) } map {X₂ Y₂} φ := { app := fun X₃ => (F.obj X₁).map ((G₂₃.map φ).app X₃) naturality := fun {X₃ Y₃} φ => by diff --git a/Mathlib/CategoryTheory/Galois/Basic.lean b/Mathlib/CategoryTheory/Galois/Basic.lean index a0cd79ac0d2fe..131a2e864a5bb 100644 --- a/Mathlib/CategoryTheory/Galois/Basic.lean +++ b/Mathlib/CategoryTheory/Galois/Basic.lean @@ -149,7 +149,7 @@ noncomputable instance {G : Type*} [Group G] [Finite G] : instance : ReflectsMonomorphisms F := ReflectsMonomorphisms.mk <| by intro X Y f _ haveI : IsIso (pullback.fst (F.map f) (F.map f)) := - fst_iso_of_mono_eq (F.map f) + isIso_fst_of_mono (F.map f) haveI : IsIso (F.map (pullback.fst f f)) := by rw [← PreservesPullback.iso_hom_fst] exact IsIso.comp_isIso @@ -172,7 +172,7 @@ section then `F ⋙ E` is again a fiber functor. -/ noncomputable def compRight (E : FintypeCat.{w} ⥤ FintypeCat.{t}) [E.IsEquivalence] : FiberFunctor (F ⋙ E) where - preservesQuotientsByFiniteGroups G := compPreservesColimitsOfShape F E + preservesQuotientsByFiniteGroups _ := compPreservesColimitsOfShape F E end diff --git a/Mathlib/CategoryTheory/Galois/Decomposition.lean b/Mathlib/CategoryTheory/Galois/Decomposition.lean index 367dfd4597ae6..7b77438602714 100644 --- a/Mathlib/CategoryTheory/Galois/Decomposition.lean +++ b/Mathlib/CategoryTheory/Galois/Decomposition.lean @@ -5,6 +5,7 @@ Authors: Christian Merten -/ import Mathlib.CategoryTheory.Galois.GaloisObjects import Mathlib.CategoryTheory.Limits.Shapes.CombinedProducts +import Mathlib.Data.Finite.Sum /-! # Decomposition of objects into connected components and applications diff --git a/Mathlib/CategoryTheory/Galois/Examples.lean b/Mathlib/CategoryTheory/Galois/Examples.lean index a3bbd1400e05c..f52783a0ae08a 100644 --- a/Mathlib/CategoryTheory/Galois/Examples.lean +++ b/Mathlib/CategoryTheory/Galois/Examples.lean @@ -79,8 +79,8 @@ noncomputable instance : PreservesFiniteLimits (forget (Action FintypeCat (MonCa /-- The category of finite `G`-sets is a `PreGaloisCategory`. -/ instance : PreGaloisCategory (Action FintypeCat (MonCat.of G)) where - hasQuotientsByFiniteGroups G _ _ := inferInstance - monoInducesIsoOnDirectSummand {X Y} i h := + hasQuotientsByFiniteGroups _ _ _ := inferInstance + monoInducesIsoOnDirectSummand {_ _} i _ := ⟨Action.imageComplement G i, Action.imageComplementIncl G i, ⟨isColimitOfReflects (Action.forget _ _ ⋙ FintypeCat.incl) <| (isColimitMapCoconeBinaryCofanEquiv (forget _) i _).symm @@ -90,7 +90,7 @@ instance : PreGaloisCategory (Action FintypeCat (MonCat.of G)) where noncomputable instance : FiberFunctor (Action.forget FintypeCat (MonCat.of G)) where preservesFiniteCoproducts := ⟨fun _ _ ↦ inferInstance⟩ preservesQuotientsByFiniteGroups _ _ _ := inferInstance - reflectsIsos := ⟨fun f (h : IsIso f.hom) => inferInstance⟩ + reflectsIsos := ⟨fun f (_ : IsIso f.hom) => inferInstance⟩ /-- The forgetful functor from finite `G`-sets to sets is a `FiberFunctor`. -/ noncomputable instance : FiberFunctor (forget₂ (Action FintypeCat (MonCat.of G)) FintypeCat) := diff --git a/Mathlib/CategoryTheory/Galois/GaloisObjects.lean b/Mathlib/CategoryTheory/Galois/GaloisObjects.lean index 25fbc42d60592..9c838d2ad07d4 100644 --- a/Mathlib/CategoryTheory/Galois/GaloisObjects.lean +++ b/Mathlib/CategoryTheory/Galois/GaloisObjects.lean @@ -7,6 +7,7 @@ import Mathlib.CategoryTheory.Galois.Basic import Mathlib.CategoryTheory.Limits.FintypeCat import Mathlib.CategoryTheory.Limits.Preserves.Limits import Mathlib.CategoryTheory.Limits.Shapes.SingleObj +import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.Logic.Equiv.TransferInstance /-! diff --git a/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean b/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean index f5398eaad344f..0e137b3d0c354 100644 --- a/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean +++ b/Mathlib/CategoryTheory/Galois/IsFundamentalgroup.lean @@ -219,7 +219,7 @@ variable (G : Type*) [Group G] [∀ (X : C), MulAction G (F.obj X)] /-- A compact, topological group `G` with a natural action on `F.obj X` for each `X : C` is a fundamental group of `F`, if `G` acts transitively on the fibers of Galois objects, -the action on `F.obj X` is continuous for all `X : C` and the only trivally acting element of `G` +the action on `F.obj X` is continuous for all `X : C` and the only trivially acting element of `G` is the identity. -/ class IsFundamentalGroup [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G] extends IsNaturalSMul F G : Prop where @@ -242,7 +242,7 @@ variable [FiberFunctor F] /-- `Aut F` is a fundamental group for `F`. -/ instance : IsFundamentalGroup F (Aut F) where - naturality g X Y f x := (FunctorToFintypeCat.naturality F F g.hom f x).symm + naturality g _ _ f x := (FunctorToFintypeCat.naturality F F g.hom f x).symm transitive_of_isGalois X := FiberFunctor.isPretransitive_of_isConnected F X continuous_smul X := continuousSMul_aut_fiber F X non_trivial' g h := by diff --git a/Mathlib/CategoryTheory/Galois/Prorepresentability.lean b/Mathlib/CategoryTheory/Galois/Prorepresentability.lean index e848bbc5c6d75..fba4b027d12de 100644 --- a/Mathlib/CategoryTheory/Galois/Prorepresentability.lean +++ b/Mathlib/CategoryTheory/Galois/Prorepresentability.lean @@ -373,7 +373,7 @@ lemma endMulEquivAutGalois_pi (f : End F) (A : PointedGaloisObject F) : /-- Any endomorphism of a fiber functor is a unit. -/ theorem FibreFunctor.end_isUnit (f : End F) : IsUnit f := - (MulEquiv.map_isUnit_iff (endMulEquivAutGalois F)).mp + (isUnit_map_iff (endMulEquivAutGalois F) _).mp (Group.isUnit ((endMulEquivAutGalois F) f)) /-- Any endomorphism of a fiber functor is an isomorphism. -/ diff --git a/Mathlib/CategoryTheory/Galois/Topology.lean b/Mathlib/CategoryTheory/Galois/Topology.lean index 62e4145b36bc7..c6d5daaba842b 100644 --- a/Mathlib/CategoryTheory/Galois/Topology.lean +++ b/Mathlib/CategoryTheory/Galois/Topology.lean @@ -69,7 +69,7 @@ lemma autEmbedding_range : ext a simp only [Set.mem_range, id_obj, Set.mem_iInter, Set.mem_setOf_eq] refine ⟨fun ⟨σ, h⟩ i ↦ h.symm ▸ σ.hom.naturality i.hom, fun h ↦ ?_⟩ - · use NatIso.ofComponents (fun X => a X) (fun {X Y} f ↦ h ⟨X, Y, f⟩) + · use NatIso.ofComponents a (fun {X Y} f ↦ h ⟨X, Y, f⟩) rfl /-- The image of `Aut F` in `∀ X, Aut (F.obj X)` is closed. -/ @@ -79,26 +79,28 @@ lemma autEmbedding_range_isClosed : IsClosed (Set.range (autEmbedding F)) := by · fun_prop · fun_prop -lemma autEmbedding_closedEmbedding : ClosedEmbedding (autEmbedding F) where - induced := rfl +lemma autEmbedding_isClosedEmbedding : IsClosedEmbedding (autEmbedding F) where + eq_induced := rfl inj := autEmbedding_injective F isClosed_range := autEmbedding_range_isClosed F -instance : CompactSpace (Aut F) := ClosedEmbedding.compactSpace (autEmbedding_closedEmbedding F) +@[deprecated (since := "2024-10-20")] +alias autEmbedding_closedEmbedding := autEmbedding_isClosedEmbedding + +instance : CompactSpace (Aut F) := IsClosedEmbedding.compactSpace (autEmbedding_isClosedEmbedding F) instance : T2Space (Aut F) := T2Space.of_injective_continuous (autEmbedding_injective F) continuous_induced_dom instance : TotallyDisconnectedSpace (Aut F) := - (Embedding.isTotallyDisconnected_range (autEmbedding_closedEmbedding F).embedding).mp + (autEmbedding_isClosedEmbedding F).isEmbedding.isTotallyDisconnected_range.mp (isTotallyDisconnected_of_totallyDisconnectedSpace _) instance : ContinuousMul (Aut F) := - Inducing.continuousMul (autEmbedding F) - (autEmbedding_closedEmbedding F).toInducing + (autEmbedding_isClosedEmbedding F).isInducing.continuousMul (autEmbedding F) instance : ContinuousInv (Aut F) := - Inducing.continuousInv (autEmbedding_closedEmbedding F).toInducing (fun _ ↦ rfl) + (autEmbedding_isClosedEmbedding F).isInducing.continuousInv fun _ ↦ rfl instance : TopologicalGroup (Aut F) := ⟨⟩ diff --git a/Mathlib/CategoryTheory/Generator.lean b/Mathlib/CategoryTheory/Generator.lean index bd219bca91faa..91d5fd9417252 100644 --- a/Mathlib/CategoryTheory/Generator.lean +++ b/Mathlib/CategoryTheory/Generator.lean @@ -395,7 +395,7 @@ theorem isSeparator_def (G : C) : hG _ _ fun H hH h => by obtain rfl := Set.mem_singleton_iff.1 hH exact hfg h, - fun hG X Y f g hfg => hG _ _ fun h => hfg _ (Set.mem_singleton _) _⟩ + fun hG _ _ _ _ hfg => hG _ _ fun _ => hfg _ (Set.mem_singleton _) _⟩ theorem IsSeparator.def {G : C} : IsSeparator G → ∀ ⦃X Y : C⦄ (f g : X ⟶ Y), (∀ h : G ⟶ X, h ≫ f = h ≫ g) → f = g := @@ -407,7 +407,7 @@ theorem isCoseparator_def (G : C) : hG _ _ fun H hH h => by obtain rfl := Set.mem_singleton_iff.1 hH exact hfg h, - fun hG X Y f g hfg => hG _ _ fun h => hfg _ (Set.mem_singleton _) _⟩ + fun hG _ _ _ _ hfg => hG _ _ fun _ => hfg _ (Set.mem_singleton _) _⟩ theorem IsCoseparator.def {G : C} : IsCoseparator G → ∀ ⦃X Y : C⦄ (f g : X ⟶ Y), (∀ h : Y ⟶ G, f ≫ h = g ≫ h) → f = g := @@ -419,7 +419,7 @@ theorem isDetector_def (G : C) : hG _ fun H hH h => by obtain rfl := Set.mem_singleton_iff.1 hH exact hf h, - fun hG X Y f hf => hG _ fun h => hf _ (Set.mem_singleton _) _⟩ + fun hG _ _ _ hf => hG _ fun _ => hf _ (Set.mem_singleton _) _⟩ theorem IsDetector.def {G : C} : IsDetector G → ∀ ⦃X Y : C⦄ (f : X ⟶ Y), (∀ h : G ⟶ Y, ∃! h', h' ≫ f = h) → IsIso f := @@ -431,7 +431,7 @@ theorem isCodetector_def (G : C) : hG _ fun H hH h => by obtain rfl := Set.mem_singleton_iff.1 hH exact hf h, - fun hG X Y f hf => hG _ fun h => hf _ (Set.mem_singleton _) _⟩ + fun hG _ _ _ hf => hG _ fun _ => hf _ (Set.mem_singleton _) _⟩ theorem IsCodetector.def {G : C} : IsCodetector G → ∀ ⦃X Y : C⦄ (f : X ⟶ Y), (∀ h : X ⟶ G, ∃! h', f ≫ h' = h) → IsIso f := @@ -509,7 +509,7 @@ theorem isCoseparator_prod (G H : C) [HasBinaryProduct G H] : refine ⟨fun h X Y u v huv => ?_, fun h => (isCoseparator_def _).2 fun X Y u v huv => h _ _ fun Z hZ g => ?_⟩ - · refine h.def _ _ fun g => prod.hom_ext ?_ ?_ + · refine h.def _ _ fun g => Limits.prod.hom_ext ?_ ?_ · simpa using huv G (by simp) (g ≫ Limits.prod.fst) · simpa using huv H (by simp) (g ≫ Limits.prod.snd) · simp only [Set.mem_insert_iff, Set.mem_singleton_iff] at hZ diff --git a/Mathlib/CategoryTheory/GlueData.lean b/Mathlib/CategoryTheory/GlueData.lean index 826e0567ead86..433fa5d3d835c 100644 --- a/Mathlib/CategoryTheory/GlueData.lean +++ b/Mathlib/CategoryTheory/GlueData.lean @@ -231,8 +231,8 @@ def mapGlueData : GlueData C' where U i := F.obj (D.U i) V i := F.obj (D.V i) f i j := F.map (D.f i j) - f_mono i j := preserves_mono_of_preservesLimit _ _ - f_id i := inferInstance + f_mono _ _ := preserves_mono_of_preservesLimit _ _ + f_id _ := inferInstance t i j := F.map (D.t i j) t_id i := by simp [D.t_id i] @@ -251,8 +251,8 @@ def diagramIso : D.diagram.multispan ⋙ F ≅ (D.mapGlueData F).diagram.multisp NatIso.ofComponents (fun x => match x with - | WalkingMultispan.left a => Iso.refl _ - | WalkingMultispan.right b => Iso.refl _) + | WalkingMultispan.left _ => Iso.refl _ + | WalkingMultispan.right _ => Iso.refl _) (by rintro (⟨_, _⟩ | _) _ (_ | _ | _) · erw [Category.comp_id, Category.id_comp, Functor.map_id] @@ -318,7 +318,7 @@ def gluedIso : F.obj D.glued ≅ (D.mapGlueData F).glued := @[reassoc (attr := simp)] theorem ι_gluedIso_hom (i : D.J) : F.map (D.ι i) ≫ (D.gluedIso F).hom = (D.mapGlueData F).ι i := by haveI : HasColimit (MultispanIndex.multispan (diagram (mapGlueData D F))) := inferInstance - erw [ι_preservesColimitsIso_hom_assoc] + erw [ι_preservesColimitIso_hom_assoc] rw [HasColimit.isoOfNatIso_ι_hom] erw [Category.id_comp] rfl diff --git a/Mathlib/CategoryTheory/GradedObject.lean b/Mathlib/CategoryTheory/GradedObject.lean index c3fd1e2c4e0aa..b5344653826c9 100644 --- a/Mathlib/CategoryTheory/GradedObject.lean +++ b/Mathlib/CategoryTheory/GradedObject.lean @@ -158,7 +158,7 @@ abbrev comap {I J : Type*} (h : J → I) : GradedObject I C ⥤ GradedObject J C -- Porting note: added to ease the port, this is a special case of `Functor.eqToHom_proj` @[simp] theorem eqToHom_proj {I : Type*} {x x' : GradedObject I C} (h : x = x') (i : I) : - (eqToHom h : x ⟶ x') i = eqToHom (Function.funext_iff.mp h i) := by + (eqToHom h : x ⟶ x') i = eqToHom (funext_iff.mp h i) := by subst h rfl diff --git a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean index 1c901601ac535..3950b5d3d1b1a 100644 --- a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean @@ -42,7 +42,7 @@ def mapTrifunctorObj {I₁ : Type*} (X₁ : GradedObject I₁ C₁) (I₂ I₃ : GradedObject I₂ C₂ ⥤ GradedObject I₃ C₃ ⥤ GradedObject (I₁ × I₂ × I₃) C₄ where obj X₂ := { obj := fun X₃ x => ((F.obj (X₁ x.1)).obj (X₂ x.2.1)).obj (X₃ x.2.2) - map := fun {X₃ Y₃} φ x => ((F.obj (X₁ x.1)).obj (X₂ x.2.1)).map (φ x.2.2) } + map := fun {_ _} φ x => ((F.obj (X₁ x.1)).obj (X₂ x.2.1)).map (φ x.2.2) } map {X₂ Y₂} φ := { app := fun X₃ x => ((F.obj (X₁ x.1)).map (φ x.2.1)).app (X₃ x.2.2) } @@ -77,7 +77,7 @@ def mapTrifunctorMapNatTrans (α : F ⟶ F') (I₁ I₂ I₃ : Type*) : mapTrifunctor F I₁ I₂ I₃ ⟶ mapTrifunctor F' I₁ I₂ I₃ where app X₁ := { app := fun X₂ => - { app := fun X₃ i => ((α.app _).app _).app _ } + { app := fun _ _ => ((α.app _).app _).app _ } naturality := fun {X₂ Y₂} φ => by ext X₃ ⟨i₁, i₂, i₃⟩ dsimp @@ -184,7 +184,7 @@ noncomputable def mapTrifunctorMapFunctorObj (X₁ : GradedObject I₁ C₁) GradedObject I₂ C₂ ⥤ GradedObject I₃ C₃ ⥤ GradedObject J C₄ where obj X₂ := { obj := fun X₃ => mapTrifunctorMapObj F p X₁ X₂ X₃ - map := fun {X₃ Y₃} φ => mapTrifunctorMapMap F p (𝟙 X₁) (𝟙 X₂) φ + map := fun {_ _} φ => mapTrifunctorMapMap F p (𝟙 X₁) (𝟙 X₂) φ map_id := fun X₃ => by dsimp ext j i₁ i₂ i₃ h @@ -215,11 +215,6 @@ noncomputable def mapTrifunctorMapFunctorObj (X₁ : GradedObject I₁ C₁) NatTrans.id_app, categoryOfGradedObjects_comp, Functor.map_comp, NatTrans.comp_app, id_comp, assoc, ι_mapTrifunctorMapMap_assoc] -#adaptation_note -/-- -At nightly-2024-08-08 we needed to significantly increase the maxHeartbeats here. --/ -set_option maxHeartbeats 800000 in /-- Given a trifunctor `F : C₁ ⥤ C₂ ⥤ C₃ ⥤ C₄` and a map `p : I₁ × I₂ × I₃ → J`, this is the functor `GradedObject I₁ C₁ ⥤ GradedObject I₂ C₂ ⥤ GradedObject I₃ C₃ ⥤ GradedObject J C₄` @@ -259,7 +254,7 @@ variable (F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂) (G : C₁₂ ⥤ C₃ ⥤ C₄) /-- Given a map `r : I₁ × I₂ × I₃ → J`, a `BifunctorComp₁₂IndexData r` consists of the data of a type `I₁₂`, maps `p : I₁ × I₂ → I₁₂` and `q : I₁₂ × I₃ → J`, such that `r` is obtained by composition of `p` and `q`. -/ -structure BifunctorComp₁₂IndexData := +structure BifunctorComp₁₂IndexData where /-- an auxiliary type -/ I₁₂ : Type* /-- a map `I₁ × I₂ → I₁₂` -/ @@ -439,7 +434,7 @@ variable (F : C₁ ⥤ C₂₃ ⥤ C₄) (G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃) /-- Given a map `r : I₁ × I₂ × I₃ → J`, a `BifunctorComp₂₃IndexData r` consists of the data of a type `I₂₃`, maps `p : I₂ × I₃ → I₂₃` and `q : I₁ × I₂₃ → J`, such that `r` is obtained by composition of `p` and `q`. -/ -structure BifunctorComp₂₃IndexData := +structure BifunctorComp₂₃IndexData where /-- an auxiliary type -/ I₂₃ : Type* /-- a map `I₂ × I₃ → I₂₃` -/ diff --git a/Mathlib/CategoryTheory/GradedObject/Unitor.lean b/Mathlib/CategoryTheory/GradedObject/Unitor.lean index 265f2b3635c67..b3491e4f57a7d 100644 --- a/Mathlib/CategoryTheory/GradedObject/Unitor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Unitor.lean @@ -124,8 +124,8 @@ lemma mapBifunctorLeftUnitor_inv_naturality : rw [mapBifunctorLeftUnitor_inv_apply, mapBifunctorLeftUnitor_inv_apply, assoc, assoc, ι_mapBifunctorMapMap] dsimp - rw [Functor.map_id, NatTrans.id_app, id_comp] - erw [← NatTrans.naturality_assoc, ← NatTrans.naturality_assoc] + rw [Functor.map_id, NatTrans.id_app, id_comp, ← NatTrans.naturality_assoc, + ← NatTrans.naturality_assoc] rfl @[reassoc] @@ -230,7 +230,7 @@ lemma mapBifunctorRightUnitor_inv_apply (j : J) : e.inv.app (X j) ≫ (F.obj (X j)).map (singleObjApplyIso (0 : I) Y).inv ≫ ιMapBifunctorMapObj F p X ((single₀ I).obj Y) j 0 j (hp j) := rfl -variable {Y Y'} +variable {Y} @[reassoc] lemma mapBifunctorRightUnitor_inv_naturality : @@ -242,7 +242,7 @@ lemma mapBifunctorRightUnitor_inv_naturality : ι_mapBifunctorMapMap] dsimp rw [Functor.map_id, id_comp, NatTrans.naturality_assoc] - erw [← NatTrans.naturality_assoc] + erw [← NatTrans.naturality_assoc e.inv] rfl @[reassoc] diff --git a/Mathlib/CategoryTheory/Grothendieck.lean b/Mathlib/CategoryTheory/Grothendieck.lean index 59e0d242c7d00..a6af93f1d5667 100644 --- a/Mathlib/CategoryTheory/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Grothendieck.lean @@ -94,7 +94,6 @@ instance (X : Grothendieck F) : Inhabited (Hom X X) := /-- Composition of morphisms in the Grothendieck category. -/ -@[simps] def comp {X Y Z : Grothendieck F} (f : Hom X Y) (g : Hom Y Z) : Hom X Z where base := f.base ≫ g.base fiber := @@ -105,18 +104,18 @@ attribute [local simp] eqToHom_map instance : Category (Grothendieck F) where Hom X Y := Grothendieck.Hom X Y id X := Grothendieck.id X - comp := @fun X Y Z f g => Grothendieck.comp f g + comp := @fun _ _ _ f g => Grothendieck.comp f g comp_id := @fun X Y f => by dsimp; ext - · simp - · dsimp + · simp [comp] + · dsimp [comp] rw [← NatIso.naturality_2 (eqToIso (F.map_id Y.base)) f.fiber] simp - id_comp := @fun X Y f => by dsimp; ext <;> simp + id_comp := @fun X Y f => by dsimp; ext <;> simp [comp] assoc := @fun W X Y Z f g h => by dsimp; ext - · simp - · dsimp + · simp [comp] + · dsimp [comp] rw [← NatIso.naturality_2 (eqToIso (F.map_comp _ _)) f.fiber] simp @@ -126,11 +125,16 @@ theorem id_fiber' (X : Grothendieck F) : id_fiber X @[simp] -theorem comp_fiber' {X Y Z : Grothendieck F} (f : X ⟶ Y) (g : Y ⟶ Z) : +theorem comp_base {X Y Z : Grothendieck F} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).base = f.base ≫ g.base := + rfl + +@[simp] +theorem comp_fiber {X Y Z : Grothendieck F} (f : X ⟶ Y) (g : Y ⟶ Z) : Hom.fiber (f ≫ g) = eqToHom (by erw [Functor.map_comp, Functor.comp_obj]) ≫ (F.map g.base).map f.fiber ≫ g.fiber := - comp_fiber f g + rfl theorem congr {X Y : Grothendieck F} {f g : X ⟶ Y} (h : f = g) : @@ -147,7 +151,7 @@ variable (F) @[simps!] def forget : Grothendieck F ⥤ C where obj X := X.1 - map := @fun X Y f => f.1 + map := @fun _ _ f => f.1 end @@ -170,7 +174,7 @@ def map (α : F ⟶ G) : Grothendieck F ⥤ Grothendieck G where map_comp {X Y Z} f g := by dsimp congr 1 - simp only [comp_fiber' f g, ← Category.assoc, Functor.map_comp, eqToHom_map] + simp only [comp_fiber f g, ← Category.assoc, Functor.map_comp, eqToHom_map] congr 1 simp only [Cat.eqToHom_app, Cat.comp_obj, eqToHom_trans, eqToHom_map, Category.assoc] erw [Functor.congr_hom (α.naturality g.base).symm f.fiber] @@ -225,7 +229,7 @@ universe v over category `Over E`. -/ def functor {E : Cat.{v,u}} : (E ⥤ Cat.{v,u}) ⥤ Over (T := Cat.{v,u}) E where obj F := Over.mk (X := E) (Y := Cat.of (Grothendieck F)) (Grothendieck.forget F) - map {F G} α := Over.homMk (X:= E) (Grothendieck.map α) Grothendieck.functor_comp_forget + map {_ _} α := Over.homMk (X:= E) (Grothendieck.map α) Grothendieck.functor_comp_forget map_id F := by ext exact Grothendieck.map_id_eq (F := F) @@ -292,6 +296,16 @@ def grothendieckTypeToCat : Grothendieck (G ⋙ typeToCat) ≌ G.Elements where simp rfl +variable (F) in +/-- Applying a functor `G : D ⥤ C` to the base of the Grothendieck construction induces a functor +`Grothendieck (G ⋙ F) ⥤ Grothendieck F`. -/ +@[simps] +def pre (G : D ⥤ C) : Grothendieck (G ⋙ F) ⥤ Grothendieck F where + obj X := ⟨G.obj X.base, X.fiber⟩ + map f := ⟨G.map f.base, f.fiber⟩ + map_id X := Grothendieck.ext _ _ (G.map_id _) (by simp) + map_comp f g := Grothendieck.ext _ _ (G.map_comp _ _) (by simp) + end Grothendieck end CategoryTheory diff --git a/Mathlib/CategoryTheory/Groupoid.lean b/Mathlib/CategoryTheory/Groupoid.lean index 4799bc3879317..a880d7c21b5a3 100644 --- a/Mathlib/CategoryTheory/Groupoid.lean +++ b/Mathlib/CategoryTheory/Groupoid.lean @@ -96,8 +96,8 @@ variable (X Y) def Groupoid.isoEquivHom : (X ≅ Y) ≃ (X ⟶ Y) where toFun := Iso.hom invFun f := ⟨f, Groupoid.inv f, (by aesop_cat), (by aesop_cat)⟩ - left_inv i := Iso.ext rfl - right_inv f := rfl + left_inv _ := Iso.ext rfl + right_inv _ := rfl variable (C) @@ -105,7 +105,7 @@ variable (C) @[simps] noncomputable def Groupoid.invFunctor : C ⥤ Cᵒᵖ where obj := Opposite.op - map {X Y} f := (inv f).op + map {_ _} f := (inv f).op end diff --git a/Mathlib/CategoryTheory/Groupoid/Discrete.lean b/Mathlib/CategoryTheory/Groupoid/Discrete.lean new file mode 100644 index 0000000000000..ffface4377069 --- /dev/null +++ b/Mathlib/CategoryTheory/Groupoid/Discrete.lean @@ -0,0 +1,19 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.CategoryTheory.Groupoid +import Mathlib.CategoryTheory.DiscreteCategory +/-! + +# Discrete categories are groupoids +-/ + +namespace CategoryTheory + +variable {C : Type*} [Category C] + +instance : Groupoid (Discrete C) := { inv := fun h ↦ ⟨⟨h.1.1.symm⟩⟩ } + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean b/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean index 79f597c240e2e..7b6b62d4ce4c8 100644 --- a/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean +++ b/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémi Bottinelli -/ import Mathlib.CategoryTheory.Groupoid -import Mathlib.CategoryTheory.PathCategory +import Mathlib.CategoryTheory.PathCategory.Basic /-! # Free groupoid on a quiver diff --git a/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean b/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean index 54c934333769c..dcc019f7b9497 100644 --- a/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean +++ b/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Rémi Bottinelli. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémi Bottinelli, Junyan Xu -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.CategoryTheory.Groupoid.VertexGroup import Mathlib.CategoryTheory.Groupoid.Basic import Mathlib.CategoryTheory.Groupoid @@ -221,13 +221,13 @@ instance : CompleteLattice (Subgroupoid C) := refine fun s => ⟨fun S Ss F => ?_, fun T Tl F fT => ?_⟩ <;> simp only [mem_sInf] exacts [fun hp => hp S Ss, fun S Ss => Tl Ss fT]) with bot := ⊥ - bot_le := fun S => empty_subset _ + bot_le := fun _ => empty_subset _ top := ⊤ - le_top := fun S => subset_univ _ + le_top := fun _ => subset_univ _ inf := (· ⊓ ·) - le_inf := fun R S T RS RT _ pR => ⟨RS pR, RT pR⟩ - inf_le_left := fun R S _ => And.left - inf_le_right := fun R S _ => And.right } + le_inf := fun _ _ _ RS RT _ pR => ⟨RS pR, RT pR⟩ + inf_le_left := fun _ _ _ => And.left + inf_le_right := fun _ _ _ => And.right } theorem le_objs {S T : Subgroupoid C} (h : S ≤ T) : S.objs ⊆ T.objs := fun s ⟨γ, hγ⟩ => ⟨γ, @h ⟨s, s, γ⟩ hγ⟩ diff --git a/Mathlib/CategoryTheory/Groupoid/VertexGroup.lean b/Mathlib/CategoryTheory/Groupoid/VertexGroup.lean index 31aaca1e47820..42789d4d9d7d6 100644 --- a/Mathlib/CategoryTheory/Groupoid/VertexGroup.lean +++ b/Mathlib/CategoryTheory/Groupoid/VertexGroup.lean @@ -5,7 +5,7 @@ Authors: Rémi Bottinelli -/ import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.CategoryTheory.Groupoid -import Mathlib.CategoryTheory.PathCategory +import Mathlib.CategoryTheory.PathCategory.Basic import Mathlib.Combinatorics.Quiver.Path /-! diff --git a/Mathlib/CategoryTheory/GuitartExact/Basic.lean b/Mathlib/CategoryTheory/GuitartExact/Basic.lean index c87d10938f0ce..cb64500850d99 100644 --- a/Mathlib/CategoryTheory/GuitartExact/Basic.lean +++ b/Mathlib/CategoryTheory/GuitartExact/Basic.lean @@ -215,8 +215,8 @@ def costructuredArrowDownwardsPrecomp dsimp rw [← CostructuredArrow.w φ, structuredArrowDownwards_map] rfl) - map_id A := rfl - map_comp φ φ' := rfl + map_id _ := rfl + map_comp _ _ := rfl end diff --git a/Mathlib/CategoryTheory/HomCongr.lean b/Mathlib/CategoryTheory/HomCongr.lean index ac21e83f53176..f2619de2c30f1 100644 --- a/Mathlib/CategoryTheory/HomCongr.lean +++ b/Mathlib/CategoryTheory/HomCongr.lean @@ -46,10 +46,8 @@ def homCongr {X Y X₁ Y₁ : C} (α : X ≅ X₁) (β : Y ≅ Y₁) : (X ⟶ Y) theorem homCongr_comp {X Y Z X₁ Y₁ Z₁ : C} (α : X ≅ X₁) (β : Y ≅ Y₁) (γ : Z ≅ Z₁) (f : X ⟶ Y) (g : Y ⟶ Z) : α.homCongr γ (f ≫ g) = α.homCongr β f ≫ β.homCongr γ g := by simp -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ theorem homCongr_refl {X Y : C} (f : X ⟶ Y) : (Iso.refl X).homCongr (Iso.refl Y) f = f := by simp -/- Porting note (#10618): removed `@[simp]`; simp can prove this -/ theorem homCongr_trans {X₁ Y₁ X₂ Y₂ X₃ Y₃ : C} (α₁ : X₁ ≅ X₂) (β₁ : Y₁ ≅ Y₂) (α₂ : X₂ ≅ X₃) (β₂ : Y₂ ≅ Y₃) (f : X₁ ⟶ Y₁) : (α₁ ≪≫ α₂).homCongr (β₁ ≪≫ β₂) f = (α₁.homCongr β₁).trans (α₂.homCongr β₂) f := by simp diff --git a/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean index b1b1f5f30c036..aa1af4a9269f3 100644 --- a/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean +++ b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean @@ -94,7 +94,7 @@ def obj (P : Karoubi (J ⥤ C)) : J ⥤ Karoubi C where simp only [NatTrans.naturality, assoc] have h := congr_app P.idem j rw [NatTrans.comp_app] at h - erw [reassoc_of% h, reassoc_of% h] } + rw [reassoc_of% h, reassoc_of% h] } /-- Tautological action on maps of the functor `Karoubi (J ⥤ C) ⥤ (J ⥤ Karoubi C)`. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean b/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean index 4c4de5bce5d99..e227d08f5cbc7 100644 --- a/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean +++ b/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean @@ -106,11 +106,6 @@ def functorExtension₁CompWhiskeringLeftToKaroubiIso : (fun {X Y} f => by aesop_cat)) (by aesop_cat) -#adaptation_note -/-- -At nightly-2024-08-08 we needed to increase the maxHeartbeats here. --/ -set_option maxHeartbeats 400000 in /-- The counit isomorphism of the equivalence `(C ⥤ Karoubi D) ≌ (Karoubi C ⥤ Karoubi D)`. -/ def KaroubiUniversal₁.counitIso : (whiskeringLeft C (Karoubi C) (Karoubi D)).obj (toKaroubi C) ⋙ functorExtension₁ C D ≅ 𝟭 _ := diff --git a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean index 121e9a8862368..b08afa205a73a 100644 --- a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean +++ b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean @@ -101,7 +101,6 @@ theorem hom_ext_iff {P Q : Karoubi C} {f g : P ⟶ Q} : f = g ↔ f.f = g.f := b rw [h] · apply Hom.ext --- Porting note: added because `Hom.ext` is not triggered automatically @[ext] theorem hom_ext {P Q : Karoubi C} (f g : P ⟶ Q) (h : f.f = g.f) : f = g := by simpa [hom_ext_iff] using h @@ -248,12 +247,12 @@ variable {C} /-- The split mono which appears in the factorisation `decompId P`. -/ @[simps] def decompId_i (P : Karoubi C) : P ⟶ P.X := - ⟨P.p, by erw [coe_p, comp_id, P.idem]⟩ + ⟨P.p, by rw [coe_p, comp_id, P.idem]⟩ /-- The split epi which appears in the factorisation `decompId P`. -/ @[simps] def decompId_p (P : Karoubi C) : (P.X : Karoubi C) ⟶ P := - ⟨P.p, by erw [coe_p, id_comp, P.idem]⟩ + ⟨P.p, by rw [coe_p, id_comp, P.idem]⟩ /-- The formal direct factor of `P.X` given by the idempotent `P.p` in the category `C` is actually a direct factor in the category `Karoubi C`. -/ diff --git a/Mathlib/CategoryTheory/IsConnected.lean b/Mathlib/CategoryTheory/IsConnected.lean index 4f4fd20d39dbe..96bb16ce5927a 100644 --- a/Mathlib/CategoryTheory/IsConnected.lean +++ b/Mathlib/CategoryTheory/IsConnected.lean @@ -42,7 +42,7 @@ category is preserved by the functor `(X × -)`. This appears in `CategoryTheory -/ -universe v₁ v₂ u₁ u₂ +universe w₁ w₂ v₁ v₂ u₁ u₂ noncomputable section @@ -91,7 +91,7 @@ private def liftToDiscrete {α : Type u₂} (F : J ⥤ Discrete α) : J ⥤ Disc /-- Implementation detail of `isoConstant`. -/ private def factorThroughDiscrete {α : Type u₂} (F : J ⥤ Discrete α) : liftToDiscrete F ⋙ Discrete.functor F.obj ≅ F := - NatIso.ofComponents (fun j => eqToIso Function.apply_invFun_apply) (by aesop_cat) + NatIso.ofComponents (fun _ => eqToIso Function.apply_invFun_apply) (by aesop_cat) end IsPreconnected.IsoConstantAux @@ -102,7 +102,7 @@ def isoConstant [IsPreconnected J] {α : Type u₂} (F : J ⥤ Discrete α) (j : F ≅ (Functor.const J).obj (F.obj j) := (IsPreconnected.IsoConstantAux.factorThroughDiscrete F).symm ≪≫ isoWhiskerRight (IsPreconnected.iso_constant _ j).some _ - ≪≫ NatIso.ofComponents (fun j' => eqToIso Function.apply_invFun_apply) (by aesop_cat) + ≪≫ NatIso.ofComponents (fun _ => eqToIso Function.apply_invFun_apply) (by aesop_cat) /-- If `J` is connected, any functor to a discrete category is constant on objects. The converse is given in `IsConnected.of_any_functor_const_on_obj`. @@ -225,7 +225,7 @@ theorem isPreconnected_of_equivalent {K : Type u₂} [Category.{v₂} K] [IsPrec isoWhiskerLeft e.inverse (isoConstant (e.functor ⋙ F) (e.inverse.obj k)) _ ≅ e.inverse ⋙ (Functor.const J).obj (F.obj k) := isoWhiskerLeft _ ((F ⋙ Functor.const J).mapIso (e.counitIso.app k)) - _ ≅ (Functor.const K).obj (F.obj k) := NatIso.ofComponents fun X => Iso.refl _⟩ + _ ≅ (Functor.const K).obj (F.obj k) := NatIso.ofComponents fun _ => Iso.refl _⟩ lemma isPreconnected_iff_of_equivalence {K : Type u₂} [Category.{v₂} K] (e : J ≌ K) : IsPreconnected J ↔ IsPreconnected K := @@ -324,12 +324,19 @@ def Zigzag.setoid (J : Type u₂) [Category.{v₁} J] : Setoid J where r := Zigzag iseqv := zigzag_equivalence +/-- If there is a zigzag from `j₁` to `j₂`, then there is a zigzag from `F j₁` to +`F j₂` as long as `F` is a prefunctor. +-/ +theorem zigzag_prefunctor_obj_of_zigzag (F : J ⥤q K) {j₁ j₂ : J} (h : Zigzag j₁ j₂) : + Zigzag (F.obj j₁) (F.obj j₂) := + h.lift _ fun _ _ => Or.imp (Nonempty.map fun f => F.map f) (Nonempty.map fun f => F.map f) + /-- If there is a zigzag from `j₁` to `j₂`, then there is a zigzag from `F j₁` to `F j₂` as long as `F` is a functor. -/ theorem zigzag_obj_of_zigzag (F : J ⥤ K) {j₁ j₂ : J} (h : Zigzag j₁ j₂) : Zigzag (F.obj j₁) (F.obj j₂) := - h.lift _ fun _ _ => Or.imp (Nonempty.map fun f => F.map f) (Nonempty.map fun f => F.map f) + zigzag_prefunctor_obj_of_zigzag F.toPrefunctor h /-- A Zag in a discrete category entails an equality of its extremities -/ lemma eq_of_zag (X) {a b : Discrete X} (h : Zag a b) : a.as = b.as := @@ -412,7 +419,7 @@ def discreteIsConnectedEquivPUnit {α : Type u₁} [IsConnected (Discrete α)] : unitIso := isoConstant _ (Classical.arbitrary _) counitIso := Functor.punitExt _ _ } -variable {C : Type u₂} [Category.{u₁} C] +variable {C : Type w₂} [Category.{w₁} C] /-- For objects `X Y : C`, any natural transformation `α : const X ⟶ const Y` from a connected category must be constant. diff --git a/Mathlib/CategoryTheory/Iso.lean b/Mathlib/CategoryTheory/Iso.lean index 8d7ad6c8ea53a..6e0dd598bc818 100644 --- a/Mathlib/CategoryTheory/Iso.lean +++ b/Mathlib/CategoryTheory/Iso.lean @@ -305,7 +305,6 @@ instance (priority := 100) mono_of_iso (f : X ⟶ Y) [IsIso f] : Mono f where rw [← Category.comp_id g, ← Category.comp_id h, ← IsIso.hom_inv_id f, ← Category.assoc, w, ← Category.assoc] --- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule @[aesop apply safe (rule_sets := [CategoryTheory])] theorem inv_eq_of_hom_inv_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (hom_inv_id : f ≫ g = 𝟙 X) : inv f = g := by @@ -317,7 +316,6 @@ theorem inv_eq_of_inv_hom_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (inv_hom_id : apply (cancel_mono f).mp simp [inv_hom_id] --- Porting note: `@[ext]` used to accept lemmas like this. @[aesop apply safe (rule_sets := [CategoryTheory])] theorem eq_inv_of_hom_inv_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (hom_inv_id : f ≫ g = 𝟙 X) : g = inv f := @@ -332,7 +330,7 @@ instance id (X : C) : IsIso (𝟙 X) := ⟨⟨𝟙 X, by simp⟩⟩ @[deprecated (since := "2024-05-15")] alias of_iso := CategoryTheory.Iso.isIso_hom @[deprecated (since := "2024-05-15")] alias of_iso_inv := CategoryTheory.Iso.isIso_inv -variable {f g : X ⟶ Y} {h : Y ⟶ Z} +variable {f : X ⟶ Y} {h : Y ⟶ Z} instance inv_isIso [IsIso f] : IsIso (inv f) := (asIso f).isIso_inv @@ -419,7 +417,7 @@ open IsIso theorem eq_of_inv_eq_inv {f g : X ⟶ Y} [IsIso f] [IsIso g] (p : inv f = inv g) : f = g := by apply (cancel_epi (inv f)).1 - erw [inv_hom_id, p, inv_hom_id] + rw [inv_hom_id, p, inv_hom_id] theorem IsIso.inv_eq_inv {f g : X ⟶ Y} [IsIso f] [IsIso g] : inv f = inv g ↔ f = g := Iso.inv_eq_inv (asIso f) (asIso g) @@ -446,12 +444,10 @@ theorem isIso_of_comp_hom_eq_id (g : X ⟶ Y) [IsIso g] {f : Y ⟶ X} (h : f ≫ namespace Iso --- Porting note: `@[ext]` used to accept lemmas like this. @[aesop apply safe (rule_sets := [CategoryTheory])] theorem inv_ext {f : X ≅ Y} {g : Y ⟶ X} (hom_inv_id : f.hom ≫ g = 𝟙 X) : f.inv = g := ((hom_comp_eq_id f).1 hom_inv_id).symm --- Porting note: `@[ext]` used to accept lemmas like this. @[aesop apply safe (rule_sets := [CategoryTheory])] theorem inv_ext' {f : X ≅ Y} {g : Y ⟶ X} (hom_inv_id : f.hom ≫ g = 𝟙 X) : g = f.inv := (hom_comp_eq_id f).1 hom_inv_id @@ -509,7 +505,7 @@ theorem cancel_iso_inv_right_assoc {W X X' Y Z : C} (f : W ⟶ X) (g : X ⟶ Y) section -variable {D E : Type*} [Category D] [Category E] {X Y : C} (e : X ≅ Y) +variable {D : Type*} [Category D] {X Y : C} (e : X ≅ Y) @[reassoc (attr := simp)] lemma map_hom_inv_id (F : C ⥤ D) : diff --git a/Mathlib/CategoryTheory/IsomorphismClasses.lean b/Mathlib/CategoryTheory/IsomorphismClasses.lean index 847b0684305c1..d14b1824f039d 100644 --- a/Mathlib/CategoryTheory/IsomorphismClasses.lean +++ b/Mathlib/CategoryTheory/IsomorphismClasses.lean @@ -39,7 +39,7 @@ end Category -/ def isomorphismClasses : Cat.{v, u} ⥤ Type u where obj C := Quotient (isIsomorphicSetoid C.α) - map {C D} F := Quot.map F.obj fun X Y ⟨f⟩ => ⟨F.mapIso f⟩ + map {_ _} F := Quot.map F.obj fun _ _ ⟨f⟩ => ⟨F.mapIso f⟩ map_id {C} := by -- Porting note: this used to be `tidy` dsimp; apply funext; intro x apply @Quot.recOn _ _ _ x diff --git a/Mathlib/CategoryTheory/Limits/Comma.lean b/Mathlib/CategoryTheory/Limits/Comma.lean index a54e3c6a62630..f67006d4500bf 100644 --- a/Mathlib/CategoryTheory/Limits/Comma.lean +++ b/Mathlib/CategoryTheory/Limits/Comma.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta -/ import Mathlib.CategoryTheory.Comma.Arrow -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.Over import Mathlib.CategoryTheory.Limits.Constructions.EpiMono import Mathlib.CategoryTheory.Limits.Creates import Mathlib.CategoryTheory.Limits.Unit @@ -225,6 +225,10 @@ namespace CostructuredArrow variable {G : A ⥤ T} {X : T} (F : J ⥤ CostructuredArrow G X) +instance hasTerminal [G.Faithful] [G.Full] {Y : A} : + HasTerminal (CostructuredArrow G (G.obj Y)) := + CostructuredArrow.mkIdTerminal.hasTerminal + instance hasColimit [i₁ : HasColimit (F ⋙ proj G X)] [i₂ : PreservesColimit (F ⋙ proj G X) G] : HasColimit F := by haveI : HasColimit (F ⋙ Comma.fst G (Functor.fromPUnit X)) := i₁ @@ -262,4 +266,10 @@ theorem epi_iff_epi_left [HasPushouts A] [PreservesColimitsOfShape WalkingSpan G end CostructuredArrow +namespace Over + +instance {X : T} : HasTerminal (Over X) := CostructuredArrow.hasTerminal + +end Over + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/ConeCategory.lean b/Mathlib/CategoryTheory/Limits/ConeCategory.lean index dd971c3b5c792..f7427f3b61376 100644 --- a/Mathlib/CategoryTheory/Limits/ConeCategory.lean +++ b/Mathlib/CategoryTheory/Limits/ConeCategory.lean @@ -145,12 +145,12 @@ def Cone.equivCostructuredArrow (F : J ⥤ C) : Cone F ≌ CostructuredArrow (co functor := Cone.toCostructuredArrow F inverse := Cone.fromCostructuredArrow F unitIso := NatIso.ofComponents Cones.eta - counitIso := NatIso.ofComponents fun c => (CostructuredArrow.eta _).symm + counitIso := NatIso.ofComponents fun _ => (CostructuredArrow.eta _).symm /-- A cone is a limit cone iff it is terminal. -/ def Cone.isLimitEquivIsTerminal {F : J ⥤ C} (c : Cone F) : IsLimit c ≃ IsTerminal c := IsLimit.isoUniqueConeMorphism.toEquiv.trans - { toFun := fun h => IsTerminal.ofUnique _ + { toFun := fun _ => IsTerminal.ofUnique _ invFun := fun h s => ⟨⟨IsTerminal.from h s⟩, fun a => IsTerminal.hom_ext h a _⟩ left_inv := by aesop_cat right_inv := by aesop_cat } @@ -304,12 +304,12 @@ def Cocone.equivStructuredArrow (F : J ⥤ C) : Cocone F ≌ StructuredArrow F ( functor := Cocone.toStructuredArrow F inverse := Cocone.fromStructuredArrow F unitIso := NatIso.ofComponents Cocones.eta - counitIso := NatIso.ofComponents fun c => (StructuredArrow.eta _).symm + counitIso := NatIso.ofComponents fun _ => (StructuredArrow.eta _).symm /-- A cocone is a colimit cocone iff it is initial. -/ def Cocone.isColimitEquivIsInitial {F : J ⥤ C} (c : Cocone F) : IsColimit c ≃ IsInitial c := IsColimit.isoUniqueCoconeMorphism.toEquiv.trans - { toFun := fun h => IsInitial.ofUnique _ + { toFun := fun _ => IsInitial.ofUnique _ invFun := fun h s => ⟨⟨IsInitial.to h s⟩, fun a => IsInitial.hom_ext h a _⟩ left_inv := by aesop_cat right_inv := by aesop_cat } diff --git a/Mathlib/CategoryTheory/Limits/Cones.lean b/Mathlib/CategoryTheory/Limits/Cones.lean index 157d042f4667c..6fee46c53e64c 100644 --- a/Mathlib/CategoryTheory/Limits/Cones.lean +++ b/Mathlib/CategoryTheory/Limits/Cones.lean @@ -162,7 +162,7 @@ instance inhabitedCocone (F : Discrete PUnit ⥤ C) : Inhabited (Cocone F) := } }⟩ -@[reassoc] -- @[simp] -- Porting note (#10618): simp can prove this +@[reassoc] theorem Cocone.w {F : J ⥤ C} (c : Cocone F) {j j' : J} (f : j ⟶ j') : F.map f ≫ c.ι.app j' = c.ι.app j := by rw [c.ι.naturality f] @@ -195,7 +195,7 @@ def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where /-- A map to the vertex of a cone naturally induces a cone by composition. -/ @[simps] def extensions (c : Cone F) : yoneda.obj c.pt ⋙ uliftFunctor.{u₁} ⟶ F.cones where - app X f := (const J).map f.down ≫ c.π + app _ f := (const J).map f.down ≫ c.π /-- A map to the vertex of a cone induces a cone by composition. -/ @[simps] @@ -231,7 +231,7 @@ def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where /-- A map from the vertex of a cocone naturally induces a cocone by composition. -/ @[simps] def extensions (c : Cocone F) : coyoneda.obj (op c.pt) ⋙ uliftFunctor.{u₁} ⟶ F.cocones where - app X f := c.ι ≫ (const J).map f.down + app _ f := c.ι ≫ (const J).map f.down /-- A map from the vertex of a cocone induces a cocone by composition. -/ @[simps] @@ -283,7 +283,6 @@ namespace Cones /-- To give an isomorphism between cones, it suffices to give an isomorphism between their vertices which commutes with the cone maps. -/ --- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule @[aesop apply safe (rule_sets := [CategoryTheory]), simps] def ext {c c' : Cone F} (φ : c.pt ≅ c'.pt) (w : ∀ j, c.π.app j = φ.hom ≫ c'.π.app j := by aesop_cat) : c ≅ c' where @@ -484,7 +483,6 @@ namespace Cocones /-- To give an isomorphism between cocones, it suffices to give an isomorphism between their vertices which commutes with the cocone maps. -/ --- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule @[aesop apply safe (rule_sets := [CategoryTheory]), simps] def ext {c c' : Cocone F} (φ : c.pt ≅ c'.pt) (w : ∀ j, c.ι.app j ≫ φ.hom = c'.ι.app j := by aesop_cat) : c ≅ c' where diff --git a/Mathlib/CategoryTheory/Limits/Connected.lean b/Mathlib/CategoryTheory/Limits/Connected.lean index bdf8561e455a9..712b12fbf1148 100644 --- a/Mathlib/CategoryTheory/Limits/Connected.lean +++ b/Mathlib/CategoryTheory/Limits/Connected.lean @@ -64,12 +64,12 @@ namespace ProdPreservesConnectedLimits /-- (Impl). The obvious natural transformation from (X × K -) to K. -/ @[simps] -def γ₂ {K : J ⥤ C} (X : C) : K ⋙ prod.functor.obj X ⟶ K where app Y := Limits.prod.snd +def γ₂ {K : J ⥤ C} (X : C) : K ⋙ prod.functor.obj X ⟶ K where app _ := Limits.prod.snd /-- (Impl). The obvious natural transformation from (X × K -) to X -/ @[simps] def γ₁ {K : J ⥤ C} (X : C) : K ⋙ prod.functor.obj X ⟶ (Functor.const J).obj X where - app Y := Limits.prod.fst + app _ := Limits.prod.fst /-- (Impl). Given a cone for (X × K -), produce a cone for K using the natural transformation `γ₂` -/ @@ -95,12 +95,12 @@ noncomputable def prodPreservesConnectedLimits [IsConnected J] (X : C) : { lift := fun s => prod.lift (s.π.app (Classical.arbitrary _) ≫ Limits.prod.fst) (l.lift (forgetCone s)) fac := fun s j => by - apply prod.hom_ext + apply Limits.prod.hom_ext · erw [assoc, limMap_π, comp_id, limit.lift_π] exact (nat_trans_from_is_connected (s.π ≫ γ₁ X) j (Classical.arbitrary _)).symm · simp [← l.fac (forgetCone s) j] uniq := fun s m L => by - apply prod.hom_ext + apply Limits.prod.hom_ext · erw [limit.lift_π, ← L (Classical.arbitrary J), assoc, limMap_π, comp_id] rfl · rw [limit.lift_π] diff --git a/Mathlib/CategoryTheory/Limits/Constructions/BinaryProducts.lean b/Mathlib/CategoryTheory/Limits/Constructions/BinaryProducts.lean index 9f345d49e3cf5..3278a8a966db7 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/BinaryProducts.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/BinaryProducts.lean @@ -33,7 +33,7 @@ def isBinaryProductOfIsTerminalIsPullback (F : Discrete WalkingPair ⥤ C) (c : lift s := hc.lift (PullbackCone.mk (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _)) - fac s j := + fac _ j := Discrete.casesOn j fun j => WalkingPair.casesOn j (hc.fac _ WalkingCospan.left) (hc.fac _ WalkingCospan.right) uniq s m J := by @@ -109,6 +109,26 @@ noncomputable def prodIsoPullback [HasTerminal C] [HasPullbacks C] (X Y : C) [HasBinaryProduct X Y] : X ⨯ Y ≅ pullback (terminal.from X) (terminal.from Y) := limit.isoLimitCone (limitConeOfTerminalAndPullbacks _) +@[reassoc (attr := simp)] +lemma prodIsoPullback_hom_fst [HasTerminal C] [HasPullbacks C] (X Y : C) + [HasBinaryProduct X Y] : (prodIsoPullback X Y).hom ≫ pullback.fst _ _ = prod.fst := + limit.isoLimitCone_hom_π (limitConeOfTerminalAndPullbacks _) ⟨.left⟩ + +@[reassoc (attr := simp)] +lemma prodIsoPullback_hom_snd [HasTerminal C] [HasPullbacks C] (X Y : C) + [HasBinaryProduct X Y] : (prodIsoPullback X Y).hom ≫ pullback.snd _ _ = prod.snd := + limit.isoLimitCone_hom_π (limitConeOfTerminalAndPullbacks _) ⟨.right⟩ + +@[reassoc (attr := simp)] +lemma prodIsoPullback_inv_fst [HasTerminal C] [HasPullbacks C] (X Y : C) + [HasBinaryProduct X Y] : (prodIsoPullback X Y).inv ≫ prod.fst = pullback.fst _ _ := + limit.isoLimitCone_inv_π (limitConeOfTerminalAndPullbacks _) ⟨.left⟩ + +@[reassoc (attr := simp)] +lemma prodIsoPullback_inv_snd [HasTerminal C] [HasPullbacks C] (X Y : C) + [HasBinaryProduct X Y] : (prodIsoPullback X Y).inv ≫ prod.snd = pullback.snd _ _ := + limit.isoLimitCone_inv_π (limitConeOfTerminalAndPullbacks _) ⟨.right⟩ + /-- If a cospan is the pushout cospan under the initial object, then it is a binary coproduct. -/ def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : Cocone F) {X : C} (hX : IsInitial X) (f : X ⟶ F.obj ⟨WalkingPair.left⟩) (g : X ⟶ F.obj ⟨WalkingPair.right⟩) @@ -120,7 +140,7 @@ def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : desc s := hc.desc (PushoutCocone.mk (s.ι.app ⟨WalkingPair.left⟩) (s.ι.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _)) - fac s j := + fac _ j := Discrete.casesOn j fun j => WalkingPair.casesOn j (hc.fac _ WalkingSpan.left) (hc.fac _ WalkingSpan.right) uniq s m J := by @@ -194,3 +214,23 @@ a coproduct of objects `X` and `Y` is isomorphic to a pushout. -/ noncomputable def coprodIsoPushout [HasInitial C] [HasPushouts C] (X Y : C) [HasBinaryCoproduct X Y] : X ⨿ Y ≅ pushout (initial.to X) (initial.to Y) := colimit.isoColimitCocone (colimitCoconeOfInitialAndPushouts _) + +@[reassoc (attr := simp)] +lemma inl_coprodIsoPushout_hom [HasInitial C] [HasPushouts C] (X Y : C) + [HasBinaryCoproduct X Y] : coprod.inl ≫ (coprodIsoPushout X Y).hom = pushout.inl _ _ := + colimit.isoColimitCocone_ι_hom (colimitCoconeOfInitialAndPushouts _) _ + +@[reassoc (attr := simp)] +lemma inr_coprodIsoPushout_hom [HasInitial C] [HasPushouts C] (X Y : C) + [HasBinaryCoproduct X Y] : coprod.inr ≫ (coprodIsoPushout X Y).hom = pushout.inr _ _ := + colimit.isoColimitCocone_ι_hom (colimitCoconeOfInitialAndPushouts _) _ + +@[reassoc (attr := simp)] +lemma inl_coprodIsoPushout_inv [HasInitial C] [HasPushouts C] (X Y : C) + [HasBinaryCoproduct X Y] : pushout.inl _ _ ≫ (coprodIsoPushout X Y).inv = coprod.inl := + colimit.isoColimitCocone_ι_inv (colimitCoconeOfInitialAndPushouts (pair X Y)) ⟨.left⟩ + +@[reassoc (attr := simp)] +lemma inr_coprodIsoPushout_inv [HasInitial C] [HasPushouts C] (X Y : C) + [HasBinaryCoproduct X Y] : pushout.inr _ _ ≫ (coprodIsoPushout X Y).inv = coprod.inr := + colimit.isoColimitCocone_ι_inv (colimitCoconeOfInitialAndPushouts (pair X Y)) ⟨.right⟩ diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean b/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean index 38bfd50516c2a..e7e1a5ed68f8b 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean @@ -58,7 +58,7 @@ def liftToFinsetColimitCocone [HasFilteredColimitsOfSize.{w, w} C] (F : Discrete { desc := fun s => colimit.desc (liftToFinsetObj F) { pt := s.pt - ι := { app := fun t => Sigma.desc fun x => s.ι.app x } } + ι := { app := fun _ => Sigma.desc fun x => s.ι.app x } } uniq := fun s m h => by apply colimit.hom_ext rintro t @@ -104,6 +104,8 @@ theorem has_limits_of_finite_and_cofiltered [HasFiniteLimits C] namespace CoproductsFromFiniteFiltered +section + variable [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C] attribute [local instance] hasCoproducts_of_finite_and_filtered @@ -130,6 +132,16 @@ def liftToFinsetColimIso : liftToFinset C α ⋙ colim ≅ colim := Discrete.natTrans_app, liftToFinsetColimIso_aux, liftToFinsetColimIso_aux_assoc, ι_colimMap]) +end + +/-- `liftToFinset`, when composed with the evaluation functor, results in the whiskering composed +with `colim`. -/ +def liftToFinsetEvaluationIso [HasFiniteCoproducts C] (I : Finset (Discrete α)) : + liftToFinset C α ⋙ (evaluation _ _).obj I ≅ + (whiskeringLeft _ _ _).obj (Discrete.functor (·.val)) ⋙ colim (J := Discrete I) := + NatIso.ofComponents (fun _ => HasColimit.isoOfNatIso (Discrete.natIso fun _ => Iso.refl _)) + fun _ => by dsimp; ext; simp + end CoproductsFromFiniteFiltered end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean index 5cf6eebed9923..bd52c4c1ea3b7 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean @@ -55,7 +55,7 @@ def buildLimit (i : Fork s t) : Cone F where pt := i.pt π := - { app := fun j => i.ι ≫ c₁.π.app ⟨_⟩ + { app := fun _ => i.ι ≫ c₁.π.app ⟨_⟩ naturality := fun j₁ j₂ f => by dsimp rw [Category.id_comp, Category.assoc, ← hs ⟨⟨_, _⟩, f⟩, i.condition_assoc, ht] } @@ -264,7 +264,7 @@ def buildColimit (i : Cofork s t) : Cocone F where pt := i.pt ι := - { app := fun j => c₂.ι.app ⟨_⟩ ≫ i.π + { app := fun _ => c₂.ι.app ⟨_⟩ ≫ i.π naturality := fun j₁ j₂ f => by dsimp have reassoced (f : (p : J × J) × (p.fst ⟶ p.snd)) {W : C} {h : _ ⟶ W} : diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean b/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean index 82bae7cbbc52d..18e56b5731467 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean @@ -15,14 +15,14 @@ any connected limit which `C` has. -/ -universe v u +universe v' u' v u -- morphism levels before object levels. See note [CategoryTheory universes]. noncomputable section open CategoryTheory CategoryTheory.Limits -variable {J : Type v} [SmallCategory J] +variable {J : Type u'} [Category.{v'} J] variable {C : Type u} [Category.{v} C] variable {X : C} diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Over/Products.lean b/Mathlib/CategoryTheory/Limits/Constructions/Over/Products.lean index 873dd0fc1eda0..33d22f9978ac8 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/Over/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/Over/Products.lean @@ -3,9 +3,7 @@ Copyright (c) 2018 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Reid Barton, Bhavik Mehta -/ -import Mathlib.CategoryTheory.Comma.Over -import Mathlib.CategoryTheory.Limits.Shapes.WidePullbacks -import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts +import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq /-! # Products in the over category @@ -166,4 +164,46 @@ theorem over_hasTerminal (B : C) : HasTerminal (Over B) where dsimp at this rwa [Category.comp_id, Category.comp_id] at this } } +section BinaryProduct + +variable {X : C} {Y Z : Over X} + +open Limits + +lemma isPullback_of_binaryFan_isLimit (c : BinaryFan Y Z) (hc : IsLimit c) : + IsPullback c.fst.left c.snd.left Y.hom Z.hom := + ⟨by simp, ⟨((IsLimit.postcomposeHomEquiv (diagramIsoCospan _) _).symm + ((IsLimit.ofConeEquiv (ConstructProducts.conesEquiv X _).symm).symm hc)).ofIsoLimit + (PullbackCone.isoMk _)⟩⟩ + +variable (Y Z) [HasPullback Y.hom Z.hom] [HasBinaryProduct Y Z] + +/-- The product of `Y` and `Z` in `Over X` is isomorpic to `Y ×ₓ Z`. -/ +noncomputable +def prodLeftIsoPullback : + (Y ⨯ Z).left ≅ pullback Y.hom Z.hom := + (Over.isPullback_of_binaryFan_isLimit _ (prodIsProd Y Z)).isoPullback + +@[reassoc (attr := simp)] +lemma prodLeftIsoPullback_hom_fst : + (prodLeftIsoPullback Y Z).hom ≫ pullback.fst _ _ = (prod.fst (X := Y)).left := + IsPullback.isoPullback_hom_fst _ + +@[reassoc (attr := simp)] +lemma prodLeftIsoPullback_hom_snd : + (prodLeftIsoPullback Y Z).hom ≫ pullback.snd _ _ = (prod.snd (X := Y)).left := + IsPullback.isoPullback_hom_snd _ + +@[reassoc (attr := simp)] +lemma prodLeftIsoPullback_inv_fst : + (prodLeftIsoPullback Y Z).inv ≫ (prod.fst (X := Y)).left = pullback.fst _ _ := + IsPullback.isoPullback_inv_fst _ + +@[reassoc (attr := simp)] +lemma prodLeftIsoPullback_inv_snd : + (prodLeftIsoPullback Y Z).inv ≫ (prod.snd (X := Y)).left = pullback.snd _ _ := + IsPullback.isoPullback_inv_snd _ + +end BinaryProduct + end CategoryTheory.Over diff --git a/Mathlib/CategoryTheory/Limits/Elements.lean b/Mathlib/CategoryTheory/Limits/Elements.lean index 84963f2bacdff..bea7b175e4f22 100644 --- a/Mathlib/CategoryTheory/Limits/Elements.lean +++ b/Mathlib/CategoryTheory/Limits/Elements.lean @@ -53,7 +53,7 @@ lemma map_lift_mapCone (c : Cone F) : A.map (limit.lift (F ⋙ π A) ((π A).mapCone c)) c.pt.snd = liftedConeElement F := by apply (preservesLimitIso A (F ⋙ π A)).toEquiv.injective ext i - have h₁ := congrFun (preservesLimitsIso_hom_π A (F ⋙ π A) i) + have h₁ := congrFun (preservesLimitIso_hom_π A (F ⋙ π A) i) (A.map (limit.lift (F ⋙ π A) ((π A).mapCone c)) c.pt.snd) have h₂ := (c.π.app i).property simp_all [← FunctorToTypes.map_comp_apply, liftedConeElement] @@ -62,7 +62,7 @@ lemma map_lift_mapCone (c : Cone F) : lemma map_π_liftedConeElement (i : I) : A.map (limit.π (F ⋙ π A) i) (liftedConeElement F) = (F.obj i).snd := by have := congrFun - (preservesLimitsIso_inv_π A (F ⋙ π A) i) (liftedConeElement' F) + (preservesLimitIso_inv_π A (F ⋙ π A) i) (liftedConeElement' F) simp_all [liftedConeElement] /-- (implementation) The constructured limit cone. -/ diff --git a/Mathlib/CategoryTheory/Limits/Final.lean b/Mathlib/CategoryTheory/Limits/Final.lean index 64975ca699d17..2cd80eb36a4f4 100644 --- a/Mathlib/CategoryTheory/Limits/Final.lean +++ b/Mathlib/CategoryTheory/Limits/Final.lean @@ -3,13 +3,14 @@ Copyright (c) 2020 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic import Mathlib.CategoryTheory.IsConnected import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Terminal import Mathlib.CategoryTheory.Limits.Shapes.Types import Mathlib.CategoryTheory.Filtered.Basic import Mathlib.CategoryTheory.Limits.Yoneda import Mathlib.CategoryTheory.PUnit +import Mathlib.CategoryTheory.Grothendieck /-! # Final and initial functors @@ -36,7 +37,7 @@ This readily implies 2., as `comp_hasColimit`, `hasColimit_of_comp`, and `colimi From 2. we can specialize to `G = coyoneda.obj (op d)` to obtain 3., as `colimitCompCoyonedaIso`. -From 3., we prove 1. directly in `cofinal_of_colimit_comp_coyoneda_iso_pUnit`. +From 3., we prove 1. directly in `final_of_colimit_comp_coyoneda_iso_pUnit`. Dually, we prove that if a functor `F : C ⥤ D` is initial, then any functor `G : D ⥤ E` has a limit if and only if `F ⋙ G` does, and these limits are isomorphic via `limit.pre G F`. @@ -116,6 +117,8 @@ theorem initial_of_final_op (F : C ⥤ D) [Final F.op] : Initial F := @isConnected_of_isConnected_op _ _ (isConnected_of_equivalent (costructuredArrowOpEquivalence F d).symm) } +attribute [local simp] Adjunction.homEquiv_unit Adjunction.homEquiv_counit + /-- If a functor `R : D ⥤ C` is a right adjoint, it is final. -/ theorem final_of_adjunction {L : C ⥤ D} {R : D ⥤ C} (adj : L ⊣ R) : Final R := { out := fun c => @@ -170,13 +173,13 @@ instance (d : D) : Nonempty (StructuredArrow d F) := variable {E : Type u₃} [Category.{v₃} E] (G : D ⥤ E) /-- -When `F : C ⥤ D` is cofinal, we denote by `lift F d` an arbitrary choice of object in `C` such that +When `F : C ⥤ D` is final, we denote by `lift F d` an arbitrary choice of object in `C` such that there exists a morphism `d ⟶ F.obj (lift F d)`. -/ def lift (d : D) : C := (Classical.arbitrary (StructuredArrow d F)).right -/-- When `F : C ⥤ D` is cofinal, we denote by `homToLift` an arbitrary choice of morphism +/-- When `F : C ⥤ D` is final, we denote by `homToLift` an arbitrary choice of morphism `d ⟶ F.obj (lift F d)`. -/ def homToLift (d : D) : d ⟶ F.obj (lift F d) := @@ -238,6 +241,17 @@ def extendCocone : Cocone (F ⋙ G) ⥤ Cocone G where · rw [← Functor.map_comp_assoc] } } map f := { hom := f.hom } +/-- Alternative equational lemma for `(extendCocone c).ι.app` in case a lift of the object +is given explicitly. -/ +lemma extendCocone_obj_ι_app' (c : Cocone (F ⋙ G)) {X : D} {Y : C} (f : X ⟶ F.obj Y) : + (extendCocone.obj c).ι.app X = G.map f ≫ c.ι.app Y := by + apply induction (k₀ := f) (z := rfl) F fun Z g => + G.map g ≫ c.ι.app Z = G.map f ≫ c.ι.app Y + · intro _ _ _ _ _ h₁ h₂ + simp [← h₁, ← Functor.comp_map, c.ι.naturality, h₂] + · intro _ _ _ _ _ h₁ h₂ + simp [← h₂, ← h₁, ← Functor.comp_map, c.ι.naturality] + @[simp] theorem colimit_cocone_comp_aux (s : Cocone (F ⋙ G)) (j : C) : G.map (homToLift F (F.obj j)) ≫ s.ι.app (lift F (F.obj j)) = s.ι.app j := by @@ -256,7 +270,7 @@ theorem colimit_cocone_comp_aux (s : Cocone (F ⋙ G)) (j : C) : variable (F G) -/-- If `F` is cofinal, +/-- If `F` is final, the category of cocones on `F ⋙ G` is equivalent to the category of cocones on `G`, for any `G : D ⥤ E`. -/ @@ -269,13 +283,13 @@ def coconesEquiv : Cocone (F ⋙ G) ≌ Cocone G where variable {G} -/-- When `F : C ⥤ D` is cofinal, and `t : Cocone G` for some `G : D ⥤ E`, +/-- When `F : C ⥤ D` is final, and `t : Cocone G` for some `G : D ⥤ E`, `t.whisker F` is a colimit cocone exactly when `t` is. -/ def isColimitWhiskerEquiv (t : Cocone G) : IsColimit (t.whisker F) ≃ IsColimit t := IsColimit.ofCoconeEquiv (coconesEquiv F G).symm -/-- When `F` is cofinal, and `t : Cocone (F ⋙ G)`, +/-- When `F` is final, and `t : Cocone (F ⋙ G)`, `extendCocone.obj t` is a colimit cocone exactly when `t` is. -/ def isColimitExtendCoconeEquiv (t : Cocone (F ⋙ G)) : @@ -301,14 +315,26 @@ section variable (G) -/-- When `F : C ⥤ D` is cofinal, and `G : D ⥤ E` has a colimit, then `F ⋙ G` has a colimit also and +/-- When `F : C ⥤ D` is final, and `G : D ⥤ E` has a colimit, then `F ⋙ G` has a colimit also and `colimit (F ⋙ G) ≅ colimit G` https://stacks.math.columbia.edu/tag/04E7 -/ +@[simps! (config := .lemmasOnly)] def colimitIso [HasColimit G] : colimit (F ⋙ G) ≅ colimit G := asIso (colimit.pre G F) +/-- A pointfree version of `colimitIso`, stating that whiskering by `F` followed by taking the +colimit is isomorpic to taking the colimit on the codomain of `F`. -/ +def colimIso [HasColimitsOfShape D E] [HasColimitsOfShape C E] : + (whiskeringLeft _ _ _).obj F ⋙ colim ≅ colim (J := D) (C := E) := + NatIso.ofComponents (fun G => colimitIso F G) fun f => by + simp only [comp_obj, whiskeringLeft_obj_obj, colim_obj, comp_map, whiskeringLeft_obj_map, + colim_map, colimitIso_hom] + ext + simp only [comp_obj, ι_colimMap_assoc, whiskerLeft_app, colimit.ι_pre, colimit.ι_pre_assoc, + ι_colimMap] + end /-- Given a colimit cocone over `F ⋙ G` we can construct a colimit cocone over `G`. -/ @@ -317,7 +343,7 @@ def colimitCoconeOfComp (t : ColimitCocone (F ⋙ G)) : ColimitCocone G where cocone := extendCocone.obj t.cocone isColimit := (isColimitExtendCoconeEquiv F _).symm t.isColimit -/-- When `F` is cofinal, and `F ⋙ G` has a colimit, then `G` has a colimit also. +/-- When `F` is final, and `F ⋙ G` has a colimit, then `G` has a colimit also. We can't make this an instance, because `F` is not determined by the goal. (Even if this weren't a problem, it would cause a loop with `comp_hasColimit`.) @@ -329,24 +355,6 @@ include F in theorem hasColimitsOfShape_of_final [HasColimitsOfShape C E] : HasColimitsOfShape D E where has_colimit := fun _ => hasColimit_of_comp F -section - --- Porting note: this instance does not seem to be found automatically ---attribute [local instance] hasColimit_of_comp - -/-- When `F` is cofinal, and `F ⋙ G` has a colimit, then `G` has a colimit also and -`colimit (F ⋙ G) ≅ colimit G` - -https://stacks.math.columbia.edu/tag/04E7 --/ -def colimitIso' [HasColimit (F ⋙ G)] : - haveI : HasColimit G := hasColimit_of_comp F - colimit (F ⋙ G) ≅ colimit G := - haveI : HasColimit G := hasColimit_of_comp F - asIso (colimit.pre G F) - -end - end Final end ArbitraryUniverse @@ -379,9 +387,9 @@ theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ end Final -/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is cofinal. +/-- If `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` for all `d : D`, then `F` is final. -/ -theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit +theorem final_of_colimit_comp_coyoneda_iso_pUnit (I : ∀ d, colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit) : Final F := ⟨fun d => by have : Nonempty (StructuredArrow d F) := by @@ -399,18 +407,18 @@ theorem cofinal_of_colimit_comp_coyoneda_iso_pUnit clear e y₁ y₂ exact Final.zigzag_of_eqvGen_quot_rel t⟩ -/-- A variant of `cofinal_of_colimit_comp_coyoneda_iso_pUnit` where we bind the various claims +/-- A variant of `final_of_colimit_comp_coyoneda_iso_pUnit` where we bind the various claims about `colimit (F ⋙ coyoneda.obj (Opposite.op d))` for each `d : D` into a single claim about the presheaf `colimit (F ⋙ yoneda)`. -/ -theorem cofinal_of_isTerminal_colimit_comp_yoneda +theorem final_of_isTerminal_colimit_comp_yoneda (h : IsTerminal (colimit (F ⋙ yoneda))) : Final F := by - refine cofinal_of_colimit_comp_coyoneda_iso_pUnit _ (fun d => ?_) + refine final_of_colimit_comp_coyoneda_iso_pUnit _ (fun d => ?_) refine Types.isTerminalEquivIsoPUnit _ ?_ let b := IsTerminal.isTerminalObj ((evaluation _ _).obj (Opposite.op d)) _ h exact b.ofIso <| preservesColimitIso ((evaluation _ _).obj (Opposite.op d)) (F ⋙ yoneda) /-- If the universal morphism `colimit (F ⋙ coyoneda.obj (op d)) ⟶ colimit (coyoneda.obj (op d))` -is an isomorphism (as it always is when `F` is cofinal), +is an isomorphism (as it always is when `F` is final), then `colimit (F ⋙ coyoneda.obj (op d)) ≅ PUnit` (simply because `colimit (coyoneda.obj (op d)) ≅ PUnit`). -/ @@ -426,7 +434,7 @@ variable {C : Type v} [Category.{v} C] {D : Type v} [Category.{v} D] (F : C ⥤ theorem final_iff_isIso_colimit_pre : Final F ↔ ∀ G : D ⥤ Type v, IsIso (colimit.pre G F) := ⟨fun _ => inferInstance, - fun _ => cofinal_of_colimit_comp_coyoneda_iso_pUnit _ fun _ => Final.colimitCompCoyonedaIso _ _⟩ + fun _ => final_of_colimit_comp_coyoneda_iso_pUnit _ fun _ => Final.colimitCompCoyonedaIso _ _⟩ end SmallCategory @@ -511,6 +519,17 @@ def extendCone : Cone (F ⋙ G) ⥤ Cone G where · rw [← Functor.map_comp] } } map f := { hom := f.hom } +/-- Alternative equational lemma for `(extendCone c).π.app` in case a lift of the object +is given explicitly. -/ +lemma extendCone_obj_π_app' (c : Cone (F ⋙ G)) {X : C} {Y : D} (f : F.obj X ⟶ Y) : + (extendCone.obj c).π.app Y = c.π.app X ≫ G.map f := by + apply induction (k₀ := f) (z := rfl) F fun Z g => + c.π.app Z ≫ G.map g = c.π.app X ≫ G.map f + · intro _ _ _ _ _ h₁ h₂ + simp [← h₂, ← h₁, ← Functor.comp_map, c.π.naturality] + · intro _ _ _ _ _ h₁ h₂ + simp [← h₁, ← Functor.comp_map, c.π.naturality, h₂] + @[simp] theorem limit_cone_comp_aux (s : Cone (F ⋙ G)) (j : C) : s.π.app (lift F (F.obj j)) ≫ G.map (homToLift F (F.obj j)) = s.π.app j := by @@ -578,9 +597,20 @@ variable (G) https://stacks.math.columbia.edu/tag/04E7 -/ +@[simps! (config := .lemmasOnly)] def limitIso [HasLimit G] : limit (F ⋙ G) ≅ limit G := (asIso (limit.pre G F)).symm +/-- A pointfree version of `limitIso`, stating that whiskering by `F` followed by taking the +limit is isomorpic to taking the limit on the codomain of `F`. -/ +def limIso [HasLimitsOfShape D E] [HasLimitsOfShape C E] : + (whiskeringLeft _ _ _).obj F ⋙ lim ≅ lim (J := D) (C := E) := + Iso.symm <| NatIso.ofComponents (fun G => (limitIso F G).symm) fun f => by + simp only [comp_obj, whiskeringLeft_obj_obj, lim_obj, comp_map, whiskeringLeft_obj_map, lim_map, + Iso.symm_hom, limitIso_inv] + ext + simp + end /-- Given a limit cone over `F ⋙ G` we can construct a limit cone over `G`. -/ @@ -601,24 +631,6 @@ include F in theorem hasLimitsOfShape_of_initial [HasLimitsOfShape C E] : HasLimitsOfShape D E where has_limit := fun _ => hasLimit_of_comp F -section - --- Porting note: this instance does not seem to be found automatically --- attribute [local instance] hasLimit_of_comp - -/-- When `F` is initial, and `F ⋙ G` has a limit, then `G` has a limit also and -`limit (F ⋙ G) ≅ limit G` - -https://stacks.math.columbia.edu/tag/04E7 --/ -def limitIso' [HasLimit (F ⋙ G)] : - haveI : HasLimit G := hasLimit_of_comp F - limit (F ⋙ G) ≅ limit G := - haveI : HasLimit G := hasLimit_of_comp F - (asIso (limit.pre G F)).symm - -end - end Initial section @@ -837,4 +849,46 @@ instance CostructuredArrow.initial_pre (T : C ⥤ D) [Initial T] (S : D ⥤ E) ( end +section Grothendieck + +variable {C : Type u₁} [Category.{v₁} C] +variable {D : Type u₂} [Category.{v₂} D] +variable (F : D ⥤ Cat) (G : C ⥤ D) + +open Functor + +/-- A prefunctor mapping structured arrows on `G` to structured arrows on `pre F G` with their +action on fibers being the identity. -/ +def Grothendieck.structuredArrowToStructuredArrowPre (d : D) (f : F.obj d) : + StructuredArrow d G ⥤q StructuredArrow ⟨d, f⟩ (pre F G) where + obj := fun X => StructuredArrow.mk (Y := ⟨X.right, (F.map X.hom).obj f⟩) + (Grothendieck.Hom.mk (by exact X.hom) (by dsimp; exact 𝟙 _)) + map := fun g => StructuredArrow.homMk + (Grothendieck.Hom.mk (by exact g.right) + (eqToHom (by dsimp; rw [← StructuredArrow.w g, map_comp, Cat.comp_obj]))) + (by simp only [StructuredArrow.mk_right] + apply Grothendieck.ext <;> simp) + +instance Grothendieck.final_pre [hG : Final G] : (Grothendieck.pre F G).Final := by + constructor + rintro ⟨d, f⟩ + let ⟨u, c, g⟩ : Nonempty (StructuredArrow d G) := inferInstance + letI : Nonempty (StructuredArrow ⟨d, f⟩ (pre F G)) := + ⟨u, ⟨c, (F.map g).obj f⟩, ⟨(by exact g), (by exact 𝟙 _)⟩⟩ + apply zigzag_isConnected + rintro ⟨⟨⟨⟩⟩, ⟨bi, fi⟩, ⟨gbi, gfi⟩⟩ ⟨⟨⟨⟩⟩, ⟨bj, fj⟩, ⟨gbj, gfj⟩⟩ + dsimp at fj fi gfi gbi gbj gfj + apply Zigzag.trans (j₂ := StructuredArrow.mk (Y := ⟨bi, ((F.map gbi).obj f)⟩) + (Grothendieck.Hom.mk gbi (𝟙 _))) + (.of_zag (.inr ⟨StructuredArrow.homMk (Grothendieck.Hom.mk (by dsimp; exact 𝟙 _) + (eqToHom (by simp) ≫ gfi)) (by apply Grothendieck.ext <;> simp)⟩)) + refine Zigzag.trans (j₂ := StructuredArrow.mk (Y := ⟨bj, ((F.map gbj).obj f)⟩) + (Grothendieck.Hom.mk gbj (𝟙 _))) ?_ + (.of_zag (.inl ⟨StructuredArrow.homMk (Grothendieck.Hom.mk (by dsimp; exact 𝟙 _) + (eqToHom (by simp) ≫ gfj)) (by apply Grothendieck.ext <;> simp)⟩)) + exact zigzag_prefunctor_obj_of_zigzag (Grothendieck.structuredArrowToStructuredArrowPre F G d f) + (isPreconnected_zigzag (.mk gbi) (.mk gbj)) + +end Grothendieck + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/FinallySmall.lean b/Mathlib/CategoryTheory/Limits/FinallySmall.lean index 90703593a078a..3613b80d171c2 100644 --- a/Mathlib/CategoryTheory/Limits/FinallySmall.lean +++ b/Mathlib/CategoryTheory/Limits/FinallySmall.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel -/ +import Mathlib.Logic.Small.Set import Mathlib.CategoryTheory.Filtered.Final /-! diff --git a/Mathlib/CategoryTheory/Limits/FintypeCat.lean b/Mathlib/CategoryTheory/Limits/FintypeCat.lean index db0a572fc3b92..d856af586c75e 100644 --- a/Mathlib/CategoryTheory/Limits/FintypeCat.lean +++ b/Mathlib/CategoryTheory/Limits/FintypeCat.lean @@ -7,6 +7,8 @@ import Mathlib.CategoryTheory.FintypeCat import Mathlib.CategoryTheory.Limits.Preserves.Finite import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Products import Mathlib.CategoryTheory.Limits.Shapes.Types +import Mathlib.Data.Finite.Prod +import Mathlib.Data.Finite.Sigma /-! # (Co)limits in the category of finite types diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean index 0b2e0d72e2f6e..86b8cb71e4d54 100644 --- a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean +++ b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean @@ -236,6 +236,29 @@ theorem limit_obj_ext {H : J ⥤ K ⥤ C} [HasLimitsOfShape J C] {k : K} {W : C} ext j simpa using w j +/-- Taking a limit after whiskering by `G` is the same as using `G` and then taking a limit. -/ +def limitCompWhiskeringLeftIsoCompLimit (F : J ⥤ K ⥤ C) (G : D ⥤ K) [HasLimitsOfShape J C] : + limit (F ⋙ (whiskeringLeft _ _ _).obj G) ≅ G ⋙ limit F := + NatIso.ofComponents (fun j => + limitObjIsoLimitCompEvaluation (F ⋙ (whiskeringLeft _ _ _).obj G) j ≪≫ + HasLimit.isoOfNatIso (isoWhiskerLeft F (whiskeringLeftCompEvaluation G j)) ≪≫ + (limitObjIsoLimitCompEvaluation F (G.obj j)).symm) + +@[reassoc (attr := simp)] +theorem limitCompWhiskeringLeftIsoCompLimit_hom_whiskerLeft_π (F : J ⥤ K ⥤ C) (G : D ⥤ K) + [HasLimitsOfShape J C] (j : J) : + (limitCompWhiskeringLeftIsoCompLimit F G).hom ≫ whiskerLeft G (limit.π F j) = + limit.π (F ⋙ (whiskeringLeft _ _ _).obj G) j := by + ext d + simp [limitCompWhiskeringLeftIsoCompLimit] + +@[reassoc (attr := simp)] +theorem limitCompWhiskeringLeftIsoCompLimit_inv_π (F : J ⥤ K ⥤ C) (G : D ⥤ K) + [HasLimitsOfShape J C] (j : J) : + (limitCompWhiskeringLeftIsoCompLimit F G).inv ≫ limit.π (F ⋙ (whiskeringLeft _ _ _).obj G) j = + whiskerLeft G (limit.π F j) := by + simp [Iso.inv_comp_eq] + instance hasColimitCompEvaluation (F : J ⥤ K ⥤ C) (k : K) [HasColimit (F.flip.obj k)] : HasColimit (F ⋙ (evaluation _ _).obj k) := hasColimitOfIso (F := F.flip.obj k) (Iso.refl _) @@ -302,6 +325,29 @@ theorem colimit_obj_ext {H : J ⥤ K ⥤ C} [HasColimitsOfShape J C] {k : K} {W ext j simpa using w j +/-- Taking a colimit after whiskering by `G` is the same as using `G` and then taking a colimit. -/ +def colimitCompWhiskeringLeftIsoCompColimit (F : J ⥤ K ⥤ C) (G : D ⥤ K) [HasColimitsOfShape J C] : + colimit (F ⋙ (whiskeringLeft _ _ _).obj G) ≅ G ⋙ colimit F := + NatIso.ofComponents (fun j => + colimitObjIsoColimitCompEvaluation (F ⋙ (whiskeringLeft _ _ _).obj G) j ≪≫ + HasColimit.isoOfNatIso (isoWhiskerLeft F (whiskeringLeftCompEvaluation G j)) ≪≫ + (colimitObjIsoColimitCompEvaluation F (G.obj j)).symm) + +@[reassoc (attr := simp)] +theorem ι_colimitCompWhiskeringLeftIsoCompColimit_hom (F : J ⥤ K ⥤ C) (G : D ⥤ K) + [HasColimitsOfShape J C] (j : J) : + colimit.ι (F ⋙ (whiskeringLeft _ _ _).obj G) j ≫ + (colimitCompWhiskeringLeftIsoCompColimit F G).hom = whiskerLeft G (colimit.ι F j) := by + ext d + simp [colimitCompWhiskeringLeftIsoCompColimit] + +@[reassoc (attr := simp)] +theorem whiskerLeft_ι_colimitCompWhiskeringLeftIsoCompColimit_inv (F : J ⥤ K ⥤ C) (G : D ⥤ K) + [HasColimitsOfShape J C] (j : J) : + whiskerLeft G (colimit.ι F j) ≫ (colimitCompWhiskeringLeftIsoCompColimit F G).inv = + colimit.ι (F ⋙ (whiskeringLeft _ _ _).obj G) j := by + simp [Iso.comp_inv_eq] + instance evaluationPreservesLimits [HasLimits C] (k : K) : PreservesLimits ((evaluation K C).obj k) where preservesLimitsOfShape {_} _𝒥 := inferInstance @@ -399,7 +445,7 @@ def colimitIsoFlipCompColim [HasColimitsOfShape J C] (F : J ⥤ K ⥤ C) : colim /-- A variant of `colimit_iso_flip_comp_colim` where the arguments of `F` are flipped. -/ @[simps!] def colimitFlipIsoCompColim [HasColimitsOfShape J C] (F : K ⥤ J ⥤ C) : colimit F.flip ≅ F ⋙ colim := - let f := fun k => + let f := fun _ => colimitObjIsoColimitCompEvaluation _ _ ≪≫ HasColimit.isoOfNatIso (flipCompEvaluation _ _) NatIso.ofComponents f diff --git a/Mathlib/CategoryTheory/Limits/HasLimits.lean b/Mathlib/CategoryTheory/Limits/HasLimits.lean index 5478f806f7e4b..06940a016159d 100644 --- a/Mathlib/CategoryTheory/Limits/HasLimits.lean +++ b/Mathlib/CategoryTheory/Limits/HasLimits.lean @@ -494,10 +494,10 @@ def constLimAdj : (const J : C ⥤ J ⥤ C) ⊣ lim := Adjunction.mk' { homEquiv := fun c g ↦ { toFun := fun f => limit.lift _ ⟨c, f⟩ invFun := fun f => - { app := fun j => f ≫ limit.π _ _ } + { app := fun _ => f ≫ limit.π _ _ } left_inv := by aesop_cat right_inv := by aesop_cat } - unit := { app := fun c => limit.lift _ ⟨_, 𝟙 _⟩ } + unit := { app := fun _ => limit.lift _ ⟨_, 𝟙 _⟩ } counit := { app := fun g => { app := limit.π _ } } } instance : IsRightAdjoint (lim : (J ⥤ C) ⥤ C) := @@ -539,7 +539,7 @@ def isLimitConeOfAdj (F : J ⥤ C) : have eq := NatTrans.congr_app (adj.counit.naturality s.π) j have eq' := NatTrans.congr_app (adj.left_triangle_components s.pt) j dsimp at eq eq' ⊢ - rw [assoc, eq, reassoc_of% eq'] + rw [adj.homEquiv_unit, assoc, eq, reassoc_of% eq'] uniq s m hm := (adj.homEquiv _ _).symm.injective (by ext j; simpa using hm j) end Adjunction @@ -1030,7 +1030,7 @@ def colimConstAdj : (colim : (J ⥤ C) ⥤ C) ⊣ const J := Adjunction.mk' { left_inv := by aesop_cat right_inv := by aesop_cat } unit := { app := fun g => { app := colimit.ι _ } } - counit := { app := fun c => colimit.desc _ ⟨_, 𝟙 _⟩ } } + counit := { app := fun _ => colimit.desc _ ⟨_, 𝟙 _⟩ } } instance : IsLeftAdjoint (colim : (J ⥤ C) ⥤ C) := ⟨_, ⟨colimConstAdj⟩⟩ diff --git a/Mathlib/CategoryTheory/Limits/IndYoneda.lean b/Mathlib/CategoryTheory/Limits/IndYoneda.lean index 99842d2a0d02f..07f8ecd466bc2 100644 --- a/Mathlib/CategoryTheory/Limits/IndYoneda.lean +++ b/Mathlib/CategoryTheory/Limits/IndYoneda.lean @@ -94,7 +94,7 @@ lemma coyonedaOpColimitIsoLimitCoyoneda_hom_comp_π (i : I) : (coyonedaOpColimitIsoLimitCoyoneda F).hom ≫ limit.π (F.op.comp coyoneda) ⟨i⟩ = coyoneda.map (colimit.ι F i).op := by simp only [coyonedaOpColimitIsoLimitCoyoneda, Functor.mapIso_symm, - Iso.trans_hom, Iso.symm_hom, Functor.mapIso_inv, Category.assoc, preservesLimitsIso_hom_π, + Iso.trans_hom, Iso.symm_hom, Functor.mapIso_inv, Category.assoc, preservesLimitIso_hom_π, ← Functor.map_comp, limitOpIsoOpColimit_inv_comp_π] @[reassoc (attr := simp)] @@ -142,7 +142,7 @@ lemma coyonedaOpColimitIsoLimitCoyoneda'_hom_comp_π (i : I) : (coyonedaOpColimitIsoLimitCoyoneda' F).hom ≫ limit.π (F.rightOp ⋙ coyoneda) i = coyoneda.map (colimit.ι F ⟨i⟩).op := by simp only [coyonedaOpColimitIsoLimitCoyoneda', Functor.mapIso_symm, Iso.trans_hom, Iso.symm_hom, - Functor.mapIso_inv, Category.assoc, preservesLimitsIso_hom_π, ← Functor.map_comp, + Functor.mapIso_inv, Category.assoc, preservesLimitIso_hom_π, ← Functor.map_comp, limitRightOpIsoOpColimit_inv_comp_π] @[reassoc (attr := simp)] diff --git a/Mathlib/CategoryTheory/Limits/Indization/FilteredColimits.lean b/Mathlib/CategoryTheory/Limits/Indization/FilteredColimits.lean new file mode 100644 index 0000000000000..84bc8acad8947 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Indization/FilteredColimits.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2024 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.CategoryTheory.Comma.Presheaf.Colimit +import Mathlib.CategoryTheory.Limits.Filtered +import Mathlib.CategoryTheory.Limits.FilteredColimitCommutesFiniteLimit +import Mathlib.CategoryTheory.Limits.FunctorToTypes +import Mathlib.CategoryTheory.Limits.Indization.IndObject +import Mathlib.Logic.Small.Set + +/-! +# Ind-objects are closed under filtered colimits + +We show that if `F : I ⥤ Cᵒᵖ ⥤ Type v` is a functor such that `I` is small and filtered and +`F.obj i` is an ind-object for all `i`, then `colimit F` is also an ind-object. + +Our proof is a slight variant of the proof given in Kashiwara-Schapira. + +## References +* [M. Kashiwara, P. Schapira, *Categories and Sheaves*][Kashiwara2006], Theorem 6.1.8 +-/ + +universe v u + +namespace CategoryTheory.Limits + +open CategoryTheory CategoryTheory.CostructuredArrow + +variable {C : Type u} [Category.{v} C] + +namespace IndizationClosedUnderFilteredColimitsAux + +variable {I : Type v} [SmallCategory I] (F : I ⥤ Cᵒᵖ ⥤ Type v) + + +section Interchange + +/-! +We start by stating the key interchange property `exists_nonempty_limit_obj_of_isColimit`. It +consists of pulling out a colimit out of a hom functor and interchanging a filtered colimit with +a finite limit. +-/ + +variable {J : Type v} [SmallCategory J] [FinCategory J] + +variable (G : J ⥤ CostructuredArrow yoneda (colimit F)) + +-- We introduce notation for the functor `J ⥤ Over (colimit F)` induced by `G`. +local notation "𝒢" => Functor.op G ⋙ Functor.op (toOver yoneda (colimit F)) + +variable {K : Type v} [SmallCategory K] (H : K ⥤ Over (colimit F)) + +/-- (implementation) Pulling out a colimit out of a hom functor is one half of the key lemma. Note + that all of the heavy lifting actually happens in `CostructuredArrow.toOverCompYonedaColimit` + and `yonedaYonedaColimit`. -/ +noncomputable def compYonedaColimitIsoColimitCompYoneda : + 𝒢 ⋙ yoneda.obj (colimit H) ≅ colimit (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢) := calc + 𝒢 ⋙ yoneda.obj (colimit H) ≅ 𝒢 ⋙ colimit (H ⋙ yoneda) := + isoWhiskerLeft G.op (toOverCompYonedaColimit H) + _ ≅ 𝒢 ⋙ (H ⋙ yoneda).flip ⋙ colim := isoWhiskerLeft _ (colimitIsoFlipCompColim _) + _ ≅ (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢).flip ⋙ colim := Iso.refl _ + _ ≅ colimit (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢) := (colimitIsoFlipCompColim _).symm + +theorem exists_nonempty_limit_obj_of_colimit [IsFiltered K] + (h : Nonempty <| limit <| 𝒢 ⋙ yoneda.obj (colimit H)) : + ∃ k, Nonempty <| limit <| 𝒢 ⋙ yoneda.obj (H.obj k) := by + obtain ⟨t⟩ := h + let t₂ := limMap (compYonedaColimitIsoColimitCompYoneda F G H).hom t + let t₃ := (colimitLimitIso (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢).flip).inv t₂ + obtain ⟨k, y, -⟩ := Types.jointly_surjective'.{v, max u v} t₃ + refine ⟨k, ⟨?_⟩⟩ + let z := (limitObjIsoLimitCompEvaluation (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢).flip k).hom y + let y := flipCompEvaluation (H ⋙ yoneda ⋙ (whiskeringLeft _ _ _).obj 𝒢) k + exact (lim.mapIso y).hom z + +theorem exists_nonempty_limit_obj_of_isColimit [IsFiltered K] {c : Cocone H} (hc : IsColimit c) + (T : Over (colimit F)) (hT : c.pt ≅ T) + (h : Nonempty <| limit <| 𝒢 ⋙ yoneda.obj T) : + ∃ k, Nonempty <| limit <| 𝒢 ⋙ yoneda.obj (H.obj k) := by + refine exists_nonempty_limit_obj_of_colimit F G H ?_ + suffices T ≅ colimit H from Nonempty.map (lim.map (whiskerLeft 𝒢 (yoneda.map this.hom))) h + refine hT.symm ≪≫ IsColimit.coconePointUniqueUpToIso hc (colimit.isColimit _) + +end Interchange + +theorem isFiltered [IsFiltered I] (hF : ∀ i, IsIndObject (F.obj i)) : + IsFiltered (CostructuredArrow yoneda (colimit F)) := by + -- It suffices to show that for any functor `G : J ⥤ CostructuredArrow yoneda (colimit F)` with + -- `J` finite there is some `X` such that the set + -- `lim Hom_{CostructuredArrow yoneda (colimit F)}(G·, X)` is nonempty. + refine IsFiltered.iff_nonempty_limit.mpr (fun {J _ _} G => ?_) + + -- We begin by remarking that `lim Hom_{Over (colimit F)}(yG·, 𝟙 (colimit F))` is nonempty, + -- simply because `𝟙 (colimit F)` is the terminal object. Here `y` is the functor + -- `CostructuredArrow yoneda (colimit F) ⥤ Over (colimit F)` induced by `yoneda`. + have h₁ : Nonempty (limit (G.op ⋙ (toOver _ _).op ⋙ yoneda.obj (Over.mk (𝟙 (colimit F))))) := + ⟨Types.Limit.mk _ (fun j => Over.mkIdTerminal.from _) (by simp)⟩ + + -- `𝟙 (colimit F)` is the colimit of the diagram in `Over (colimit F)` given by the arrows of + -- the form `Fi ⟶ colimit F`. Thus, pulling the colimit out of the hom functor and commuting + -- the finite limit with the filtered colimit, we obtain + -- `lim_j Hom_{Over (colimit F)}(yGj, 𝟙 (colimit F)) ≅` + -- `colim_i lim_j Hom_{Over (colimit F)}(yGj, colimit.ι F i)`, and so we find `i` such that + -- the limit is non-empty. + obtain ⟨i, hi⟩ := exists_nonempty_limit_obj_of_isColimit F G _ + (colimit.isColimitToOver F) _ (Iso.refl _) h₁ + + -- `F.obj i` is a small filtered colimit of representables, say of the functor `H : K ⥤ C`, so + -- `𝟙 (F.obj i)` is the colimit of the arrows of the form `yHk ⟶ Fi` in `Over Fi`. + -- Then `colimit.ι F i` is the colimit of the arrows of the form + -- `H.obj F ⟶ F.obj i ⟶ colimit F` in `Over (colimit F)`. + obtain ⟨⟨P⟩⟩ := hF i + let hc : IsColimit ((Over.map (colimit.ι F i)).mapCocone P.cocone.toOver) := + isColimitOfPreserves (Over.map _) (Over.isColimitToOver P.coconeIsColimit) + + -- Again, we pull the colimit out of the hom functor and commute limit and colimit to obtain + -- `lim_j Hom_{Over (colimit F)}(yGj, colimit.ι F i) ≅` + -- `colim_k lim_j Hom_{Over (colimit F)}(yGj, yHk)`, and so we find `k` such that the limit + -- is non-empty. + obtain ⟨k, hk⟩ : ∃ k, Nonempty (limit (G.op ⋙ (toOver yoneda (colimit F)).op ⋙ + yoneda.obj ((toOver yoneda (colimit F)).obj <| + (pre P.F yoneda (colimit F)).obj <| (map (colimit.ι F i)).obj <| mk _))) := + exists_nonempty_limit_obj_of_isColimit F G _ hc _ (Iso.refl _) hi + + have htO : (toOver yoneda (colimit F)).FullyFaithful := .ofFullyFaithful _ + -- Since the inclusion `y : CostructuredArrow yoneda (colimit F) ⥤ Over (colimit F)` is fully + -- faithful, `lim_j Hom_{Over (colimit F)}(yGj, yHk) ≅` + -- `lim_j Hom_{CostructuredArrow yoneda (colimit F)}(Gj, Hk)` and so `Hk` is the object we're + -- looking for. + let q := htO.homNatIsoMaxRight + obtain ⟨t'⟩ := Nonempty.map (limMap (isoWhiskerLeft G.op (q _)).hom) hk + exact ⟨_, ⟨((preservesLimitIso uliftFunctor.{u, v} _).inv t').down⟩⟩ + +end IndizationClosedUnderFilteredColimitsAux + +theorem isIndObject_colimit (I : Type v) [SmallCategory I] [IsFiltered I] + (F : I ⥤ Cᵒᵖ ⥤ Type v) (hF : ∀ i, IsIndObject (F.obj i)) : IsIndObject (colimit F) := by + have : IsFiltered (CostructuredArrow yoneda (colimit F)) := + IndizationClosedUnderFilteredColimitsAux.isFiltered F hF + refine (isIndObject_iff _).mpr ⟨this, ?_⟩ + + -- It remains to show that `CostructuredArrow yoneda (colimit F)` is finally small. Because we + -- have already shown it is filtered, it suffices to exhibit a small weakly terminal set. For this + -- we use that all the `CostructuredArrow yoneda (F.obj i)` have small weakly terminal sets. + have : ∀ i, ∃ (s : Set (CostructuredArrow yoneda (F.obj i))) (_ : Small.{v} s), + ∀ i, ∃ j ∈ s, Nonempty (i ⟶ j) := + fun i => (hF i).finallySmall.exists_small_weakly_terminal_set + choose s hs j hjs hj using this + refine finallySmall_of_small_weakly_terminal_set + (⋃ i, (map (colimit.ι F i)).obj '' (s i)) (fun A => ?_) + obtain ⟨i, y, hy⟩ := FunctorToTypes.jointly_surjective'.{v, v} F _ (yonedaEquiv A.hom) + let y' : CostructuredArrow yoneda (F.obj i) := mk (yonedaEquiv.symm y) + obtain ⟨x⟩ := hj _ y' + refine ⟨(map (colimit.ι F i)).obj (j i y'), ?_, ⟨?_⟩⟩ + · simp only [Set.mem_iUnion, Set.mem_image] + exact ⟨i, j i y', hjs _ _, rfl⟩ + · refine ?_ ≫ (map (colimit.ι F i)).map x + refine homMk (𝟙 A.left) (yonedaEquiv.injective ?_) + simp [-EmbeddingLike.apply_eq_iff_eq, hy, yonedaEquiv_comp, y'] + +end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Indization/IndObject.lean b/Mathlib/CategoryTheory/Limits/Indization/IndObject.lean index 737104b5fb924..e51a540125e55 100644 --- a/Mathlib/CategoryTheory/Limits/Indization/IndObject.lean +++ b/Mathlib/CategoryTheory/Limits/Indization/IndObject.lean @@ -107,10 +107,10 @@ instance : P.toCostructuredArrow.Final := def yoneda (X : C) : IndObjectPresentation (yoneda.obj X) where I := Discrete PUnit.{v + 1} F := Functor.fromPUnit X - ι := { app := fun s => 𝟙 _ } + ι := { app := fun _ => 𝟙 _ } isColimit := { desc := fun s => s.ι.app ⟨PUnit.unit⟩ - uniq := fun s m h => h ⟨PUnit.unit⟩ } + uniq := fun _ _ h => h ⟨PUnit.unit⟩ } end IndObjectPresentation diff --git a/Mathlib/CategoryTheory/Limits/IsConnected.lean b/Mathlib/CategoryTheory/Limits/IsConnected.lean index a0e0dd26b49f2..97d144d9c19bb 100644 --- a/Mathlib/CategoryTheory/Limits/IsConnected.lean +++ b/Mathlib/CategoryTheory/Limits/IsConnected.lean @@ -50,7 +50,7 @@ def constPUnitFunctor : C ⥤ Type w := (Functor.const C).obj PUnit.{w + 1} @[simps] def pUnitCocone : Cocone (constPUnitFunctor.{w} C) where pt := PUnit - ι := { app := fun X => id } + ι := { app := fun _ => id } /-- If `C` is connected, the cocone on `constPUnitFunctor` with cone point `PUnit` is a colimit cocone. -/ diff --git a/Mathlib/CategoryTheory/Limits/IsLimit.lean b/Mathlib/CategoryTheory/Limits/IsLimit.lean index 76802822f383d..663c41495a819 100644 --- a/Mathlib/CategoryTheory/Limits/IsLimit.lean +++ b/Mathlib/CategoryTheory/Limits/IsLimit.lean @@ -191,7 +191,7 @@ variable {t : Cone F} theorem hom_lift (h : IsLimit t) {W : C} (m : W ⟶ t.pt) : m = h.lift { pt := W, π := { app := fun b => m ≫ t.π.app b } } := - h.uniq { pt := W, π := { app := fun b => m ≫ t.π.app b } } m fun b => rfl + h.uniq { pt := W, π := { app := fun b => m ≫ t.π.app b } } m fun _ => rfl /-- Two morphisms into a limit are equal if their compositions with each cone morphism are equal. -/ diff --git a/Mathlib/CategoryTheory/Limits/Lattice.lean b/Mathlib/CategoryTheory/Limits/Lattice.lean index ccf7e6cf11624..4e07dc534469f 100644 --- a/Mathlib/CategoryTheory/Limits/Lattice.lean +++ b/Mathlib/CategoryTheory/Limits/Lattice.lean @@ -32,7 +32,7 @@ variable {J : Type w} [SmallCategory J] [FinCategory J] def finiteLimitCone [SemilatticeInf α] [OrderTop α] (F : J ⥤ α) : LimitCone F where cone := { pt := Finset.univ.inf F.obj - π := { app := fun j => homOfLE (Finset.inf_le (Fintype.complete _)) } } + π := { app := fun _ => homOfLE (Finset.inf_le (Fintype.complete _)) } } isLimit := { lift := fun s => homOfLE (Finset.le_inf fun j _ => (s.π.app j).down.down) } /-- @@ -41,7 +41,7 @@ The colimit cocone over any functor from a finite diagram into a `SemilatticeSup def finiteColimitCocone [SemilatticeSup α] [OrderBot α] (F : J ⥤ α) : ColimitCocone F where cocone := { pt := Finset.univ.sup F.obj - ι := { app := fun i => homOfLE (Finset.le_sup (Fintype.complete _)) } } + ι := { app := fun _ => homOfLE (Finset.le_sup (Fintype.complete _)) } } isColimit := { desc := fun s => homOfLE (Finset.sup_le fun j _ => (s.ι.app j).down.down) } -- see Note [lower instance priority] @@ -170,7 +170,7 @@ variable {J : Type u} [SmallCategory J] def limitCone (F : J ⥤ α) : LimitCone F where cone := { pt := iInf F.obj - π := { app := fun j => homOfLE (CompleteLattice.sInf_le _ _ (Set.mem_range_self _)) } } + π := { app := fun _ => homOfLE (CompleteLattice.sInf_le _ _ (Set.mem_range_self _)) } } isLimit := { lift := fun s => homOfLE (CompleteLattice.le_sInf _ _ (by rintro _ ⟨j, rfl⟩; exact (s.π.app j).le)) } @@ -180,7 +180,7 @@ def limitCone (F : J ⥤ α) : LimitCone F where def colimitCocone (F : J ⥤ α) : ColimitCocone F where cocone := { pt := iSup F.obj - ι := { app := fun j => homOfLE (CompleteLattice.le_sSup _ _ (Set.mem_range_self _)) } } + ι := { app := fun _ => homOfLE (CompleteLattice.le_sSup _ _ (Set.mem_range_self _)) } } isColimit := { desc := fun s => homOfLE (CompleteLattice.sSup_le _ _ (by rintro _ ⟨j, rfl⟩; exact (s.ι.app j).le)) } diff --git a/Mathlib/CategoryTheory/Limits/MorphismProperty.lean b/Mathlib/CategoryTheory/Limits/MorphismProperty.lean new file mode 100644 index 0000000000000..a54a535246793 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/MorphismProperty.lean @@ -0,0 +1,159 @@ +/- +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.CategoryTheory.Limits.Comma +import Mathlib.CategoryTheory.Limits.Constructions.Over.Basic +import Mathlib.CategoryTheory.Limits.FullSubcategory +import Mathlib.CategoryTheory.MorphismProperty.Comma +import Mathlib.CategoryTheory.MorphismProperty.Limits + +/-! +# (Co)limits in subcategories of comma categories defined by morphism properties + +-/ + +namespace CategoryTheory + +open Limits MorphismProperty.Comma + +variable {T : Type*} [Category T] (P : MorphismProperty T) + +namespace MorphismProperty.Comma + +variable {A B J : Type*} [Category A] [Category B] [Category J] {L : A ⥤ T} {R : B ⥤ T} +variable (D : J ⥤ P.Comma L R ⊤ ⊤) + +/-- If `P` is closed under limits of shape `J` in `Comma L R`, then when `D` has +a limit in `Comma L R`, the forgetful functor creates this limit. -/ +noncomputable def forgetCreatesLimitOfClosed + (h : ClosedUnderLimitsOfShape J (fun f : Comma L R ↦ P f.hom)) + [HasLimit (D ⋙ forget L R P ⊤ ⊤)] : + CreatesLimit D (forget L R P ⊤ ⊤) := + createsLimitOfFullyFaithfulOfIso + (⟨limit (D ⋙ forget L R P ⊤ ⊤), h.limit fun j ↦ (D.obj j).prop⟩) + (Iso.refl _) + +/-- If `Comma L R` has limits of shape `J` and `Comma L R` is closed under limits of shape +`J`, then `forget L R P ⊤ ⊤` creates limits of shape `J`. -/ +noncomputable def forgetCreatesLimitsOfShapeOfClosed [HasLimitsOfShape J (Comma L R)] + (h : ClosedUnderLimitsOfShape J (fun f : Comma L R ↦ P f.hom)) : + CreatesLimitsOfShape J (forget L R P ⊤ ⊤) where + CreatesLimit := forgetCreatesLimitOfClosed _ _ h + +lemma hasLimit_of_closedUnderLimitsOfShape + (h : ClosedUnderLimitsOfShape J (fun f : Comma L R ↦ P f.hom)) + [HasLimit (D ⋙ forget L R P ⊤ ⊤)] : + HasLimit D := + haveI : CreatesLimit D (forget L R P ⊤ ⊤) := forgetCreatesLimitOfClosed _ D h + hasLimit_of_created D (forget L R P ⊤ ⊤) + +lemma hasLimitsOfShape_of_closedUnderLimitsOfShape [HasLimitsOfShape J (Comma L R)] + (h : ClosedUnderLimitsOfShape J (fun f : Comma L R ↦ P f.hom)) : + HasLimitsOfShape J (P.Comma L R ⊤ ⊤) where + has_limit _ := hasLimit_of_closedUnderLimitsOfShape _ _ h + +end MorphismProperty.Comma + +section + +variable {A : Type*} [Category A] {L : A ⥤ T} + +lemma CostructuredArrow.closedUnderLimitsOfShape_discrete_empty [L.Faithful] [L.Full] {Y : A} + [P.ContainsIdentities] [P.RespectsIso] : + ClosedUnderLimitsOfShape (Discrete PEmpty.{1}) + (fun f : CostructuredArrow L (L.obj Y) ↦ P f.hom) := by + rintro D c hc - + have : D = Functor.empty _ := Functor.empty_ext' _ _ + subst this + let e : c.pt ≅ CostructuredArrow.mk (𝟙 (L.obj Y)) := + hc.conePointUniqueUpToIso CostructuredArrow.mkIdTerminal + rw [P.costructuredArrow_iso_iff e] + simpa using P.id_mem (L.obj Y) + +end + +section + +variable {X : T} + +lemma Over.closedUnderLimitsOfShape_discrete_empty [P.ContainsIdentities] [P.RespectsIso] : + ClosedUnderLimitsOfShape (Discrete PEmpty.{1}) (fun f : Over X ↦ P f.hom) := + CostructuredArrow.closedUnderLimitsOfShape_discrete_empty P + +/-- Let `P` be stable under composition and base change. If `P` satisfies cancellation on the right, +the subcategory of `Over X` defined by `P` is closed under pullbacks. + +Without the cancellation property, this does not in general. Consider for example +`P = Function.Surjective` on `Type`. -/ +lemma Over.closedUnderLimitsOfShape_pullback [HasPullbacks T] + [P.IsStableUnderComposition] (hP : P.StableUnderBaseChange) + (of_postcomp : ∀ {X Y Z : T} {f : X ⟶ Y} (g : Y ⟶ Z), P g → P (f ≫ g) → P f) : + ClosedUnderLimitsOfShape WalkingCospan (fun f : Over X ↦ P f.hom) := by + intro D c hc hf + have h : IsPullback (c.π.app .left).left (c.π.app .right).left (D.map WalkingCospan.Hom.inl).left + (D.map WalkingCospan.Hom.inr).left := IsPullback.of_isLimit_cone <| + Limits.isLimitOfPreserves (CategoryTheory.Over.forget X) hc + rw [show c.pt.hom = (c.π.app .left).left ≫ (D.obj .left).hom by simp] + apply P.comp_mem _ _ (hP h.flip ?_) (hf _) + exact of_postcomp (D.obj WalkingCospan.one).hom (hf .one) (by simpa using hf .right) + +end + +namespace MorphismProperty.Over + +variable (X : T) + +noncomputable instance [P.ContainsIdentities] [P.RespectsIso] : + CreatesLimitsOfShape (Discrete PEmpty.{1}) (Over.forget P ⊤ X) := + haveI : HasLimitsOfShape (Discrete PEmpty.{1}) (Comma (𝟭 T) (Functor.fromPUnit X)) := by + show HasLimitsOfShape _ (Over X) + infer_instance + forgetCreatesLimitsOfShapeOfClosed P + (Over.closedUnderLimitsOfShape_discrete_empty _) + +variable {X} in +instance [P.ContainsIdentities] (Y : P.Over ⊤ X) : + Unique (Y ⟶ Over.mk ⊤ (𝟙 X) (P.id_mem X)) where + default := Over.homMk Y.hom + uniq a := by + ext + · simp only [mk_left, Hom.hom_left, homMk_hom, Over.homMk_left] + rw [← Over.w a.hom] + simp only [mk_left, Functor.const_obj_obj, Hom.hom_left, mk_hom, Category.comp_id] + · rfl + +/-- `X ⟶ X` is the terminal object of `P.Over ⊤ X`. -/ +def mkIdTerminal [P.ContainsIdentities] : + IsTerminal (Over.mk ⊤ (𝟙 X) (P.id_mem X)) := + IsTerminal.ofUnique _ + +instance [P.ContainsIdentities] : HasTerminal (P.Over ⊤ X) := + let h : IsTerminal (Over.mk ⊤ (𝟙 X) (P.id_mem X)) := Over.mkIdTerminal P X + h.hasTerminal + +/-- If `P` is stable under composition, base change and satisfies post-cancellation, +`Over.forget P ⊤ X` creates pullbacks. -/ +noncomputable def createsLimitsOfShape_walkingCospan [HasPullbacks T] + [P.IsStableUnderComposition] (hP : P.StableUnderBaseChange) + (of_postcomp : ∀ {X Y Z : T} {f : X ⟶ Y} (g : Y ⟶ Z), P g → P (f ≫ g) → P f) : + CreatesLimitsOfShape WalkingCospan (Over.forget P ⊤ X) := + haveI : HasLimitsOfShape WalkingCospan (Comma (𝟭 T) (Functor.fromPUnit X)) := + inferInstanceAs <| HasLimitsOfShape WalkingCospan (Over X) + forgetCreatesLimitsOfShapeOfClosed P + (Over.closedUnderLimitsOfShape_pullback P hP of_postcomp) + +/-- If `P` is stable under composition, base change and satisfies post-cancellation, +`P.Over ⊤ X` has pullbacks -/ +lemma hasPullbacks [HasPullbacks T] [P.IsStableUnderComposition] (hP : P.StableUnderBaseChange) + (of_postcomp : ∀ {X Y Z : T} {f : X ⟶ Y} (g : Y ⟶ Z), P g → P (f ≫ g) → P f) : + HasPullbacks (P.Over ⊤ X) := + haveI : HasLimitsOfShape WalkingCospan (Comma (𝟭 T) (Functor.fromPUnit X)) := + inferInstanceAs <| HasLimitsOfShape WalkingCospan (Over X) + hasLimitsOfShape_of_closedUnderLimitsOfShape P + (Over.closedUnderLimitsOfShape_pullback P hP of_postcomp) + +end MorphismProperty.Over + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Opposites.lean b/Mathlib/CategoryTheory/Limits/Opposites.lean index a988e6bc1335d..f53eb0808b891 100644 --- a/Mathlib/CategoryTheory/Limits/Opposites.lean +++ b/Mathlib/CategoryTheory/Limits/Opposites.lean @@ -635,11 +635,9 @@ def unop {X Y Z : Cᵒᵖ} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : ((Cocones.precompose (opCospan f.unop g.unop).hom).obj (Cocone.whisker walkingCospanOpEquiv.functor c)) --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem unop_fst {X Y Z : Cᵒᵖ} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : c.unop.fst = c.inl.unop := by simp --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem unop_snd {X Y Z : Cᵒᵖ} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : c.unop.snd = c.inr.unop := by aesop_cat @@ -650,11 +648,9 @@ def op {X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : Pullbac (Cones.postcompose (cospanOp f g).symm.hom).obj (Cone.whisker walkingSpanOpEquiv.inverse (Cocone.op c)) --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem op_fst {X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : c.op.fst = c.inl.op := by aesop_cat --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem op_snd {X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : c.op.snd = c.inr.op := by aesop_cat @@ -671,11 +667,9 @@ def unop {X Y Z : Cᵒᵖ} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : ((Cones.postcompose (opSpan f.unop g.unop).symm.hom).obj (Cone.whisker walkingSpanOpEquiv.functor c)) --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem unop_inl {X Y Z : Cᵒᵖ} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : c.unop.inl = c.fst.unop := by aesop_cat --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem unop_inr {X Y Z : Cᵒᵖ} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : c.unop.inr = c.snd.unop := by aesop_cat @@ -685,11 +679,9 @@ def op {X Y Z : C} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : PushoutC (Cocones.precompose (spanOp f g).hom).obj (Cocone.whisker walkingCospanOpEquiv.inverse (Cone.op c)) --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem op_inl {X Y Z : C} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : c.op.inl = c.fst.op := by aesop_cat --- Porting note (#10618): removed simp attribute as the equality can already be obtained by simp theorem op_inr {X Y Z : C} {f : X ⟶ Z} {g : Y ⟶ Z} (c : PullbackCone f g) : c.op.inr = c.snd.op := by aesop_cat @@ -849,7 +841,7 @@ def CokernelCofork.IsColimit.ofπOp {X Y Q : C} (p : Y ⟶ Q) {f : X ⟶ Y} IsLimit (KernelFork.ofι p.op (show p.op ≫ f.op = 0 by rw [← op_comp, w, op_zero])) := KernelFork.IsLimit.ofι _ _ (fun x hx => (h.desc (CokernelCofork.ofπ x.unop (Quiver.Hom.op_inj hx))).op) - (fun x hx => Quiver.Hom.unop_inj (Cofork.IsColimit.π_desc h)) + (fun _ _ => Quiver.Hom.unop_inj (Cofork.IsColimit.π_desc h)) (fun x hx b hb => Quiver.Hom.unop_inj (Cofork.IsColimit.hom_ext h (by simpa only [Quiver.Hom.unop_op, Cofork.IsColimit.π_desc] using Quiver.Hom.op_inj hb))) @@ -860,7 +852,7 @@ def CokernelCofork.IsColimit.ofπUnop {X Y Q : Cᵒᵖ} (p : Y ⟶ Q) {f : X ⟶ IsLimit (KernelFork.ofι p.unop (show p.unop ≫ f.unop = 0 by rw [← unop_comp, w, unop_zero])) := KernelFork.IsLimit.ofι _ _ (fun x hx => (h.desc (CokernelCofork.ofπ x.op (Quiver.Hom.unop_inj hx))).unop) - (fun x hx => Quiver.Hom.op_inj (Cofork.IsColimit.π_desc h)) + (fun _ _ => Quiver.Hom.op_inj (Cofork.IsColimit.π_desc h)) (fun x hx b hb => Quiver.Hom.op_inj (Cofork.IsColimit.hom_ext h (by simpa only [Quiver.Hom.op_unop, Cofork.IsColimit.π_desc] using Quiver.Hom.unop_inj hb))) @@ -871,7 +863,7 @@ def KernelFork.IsLimit.ofιOp {K X Y : C} (i : K ⟶ X) {f : X ⟶ Y} (show f.op ≫ i.op = 0 by rw [← op_comp, w, op_zero])) := CokernelCofork.IsColimit.ofπ _ _ (fun x hx => (h.lift (KernelFork.ofι x.unop (Quiver.Hom.op_inj hx))).op) - (fun x hx => Quiver.Hom.unop_inj (Fork.IsLimit.lift_ι h)) + (fun _ _ => Quiver.Hom.unop_inj (Fork.IsLimit.lift_ι h)) (fun x hx b hb => Quiver.Hom.unop_inj (Fork.IsLimit.hom_ext h (by simpa only [Quiver.Hom.unop_op, Fork.IsLimit.lift_ι] using Quiver.Hom.op_inj hb))) @@ -883,7 +875,7 @@ def KernelFork.IsLimit.ofιUnop {K X Y : Cᵒᵖ} (i : K ⟶ X) {f : X ⟶ Y} (show f.unop ≫ i.unop = 0 by rw [← unop_comp, w, unop_zero])) := CokernelCofork.IsColimit.ofπ _ _ (fun x hx => (h.lift (KernelFork.ofι x.op (Quiver.Hom.unop_inj hx))).unop) - (fun x hx => Quiver.Hom.op_inj (Fork.IsLimit.lift_ι h)) + (fun _ _ => Quiver.Hom.op_inj (Fork.IsLimit.lift_ι h)) (fun x hx b hb => Quiver.Hom.op_inj (Fork.IsLimit.hom_ext h (by simpa only [Quiver.Hom.op_unop, Fork.IsLimit.lift_ι] using Quiver.Hom.unop_inj hb))) diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean index 0926bbae01d71..f5abc3a11449f 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean @@ -145,7 +145,7 @@ instance idPreservesLimits : PreservesLimitsOfSize.{w', w} (𝟭 C) where { preservesLimit := fun {K} => ⟨fun {c} h => - ⟨fun s => h.lift ⟨s.pt, fun j => s.π.app j, fun j j' f => s.π.naturality f⟩, by + ⟨fun s => h.lift ⟨s.pt, fun j => s.π.app j, fun _ _ f => s.π.naturality f⟩, by cases K; rcases c with ⟨_, _, _⟩; intro s j; cases s; exact h.fac _ j, by cases K; rcases c with ⟨_, _, _⟩; intro s m w; rcases s with ⟨_, _, _⟩; exact h.uniq _ m w⟩⟩ } @@ -155,7 +155,7 @@ instance idPreservesColimits : PreservesColimitsOfSize.{w', w} (𝟭 C) where { preservesColimit := fun {K} => ⟨fun {c} h => - ⟨fun s => h.desc ⟨s.pt, fun j => s.ι.app j, fun j j' f => s.ι.naturality f⟩, by + ⟨fun s => h.desc ⟨s.pt, fun j => s.ι.app j, fun _ _ f => s.ι.naturality f⟩, by cases K; rcases c with ⟨_, _, _⟩; intro s j; cases s; exact h.fac _ j, by cases K; rcases c with ⟨_, _, _⟩; intro s m w; rcases s with ⟨_, _, _⟩; exact h.uniq _ m w⟩⟩ } @@ -451,7 +451,7 @@ instance idReflectsLimits : ReflectsLimitsOfSize.{w, w'} (𝟭 C) where { reflectsLimit := fun {K} => ⟨fun {c} h => - ⟨fun s => h.lift ⟨s.pt, fun j => s.π.app j, fun j j' f => s.π.naturality f⟩, by + ⟨fun s => h.lift ⟨s.pt, fun j => s.π.app j, fun _ _ f => s.π.naturality f⟩, by cases K; rcases c with ⟨_, _, _⟩; intro s j; cases s; exact h.fac _ j, by cases K; rcases c with ⟨_, _, _⟩; intro s m w; rcases s with ⟨_, _, _⟩; exact h.uniq _ m w⟩⟩ } @@ -461,7 +461,7 @@ instance idReflectsColimits : ReflectsColimitsOfSize.{w, w'} (𝟭 C) where { reflectsColimit := fun {K} => ⟨fun {c} h => - ⟨fun s => h.desc ⟨s.pt, fun j => s.ι.app j, fun j j' f => s.ι.naturality f⟩, by + ⟨fun s => h.desc ⟨s.pt, fun j => s.ι.app j, fun _ _ f => s.ι.naturality f⟩, by cases K; rcases c with ⟨_, _, _⟩; intro s j; cases s; exact h.fac _ j, by cases K; rcases c with ⟨_, _, _⟩; intro s m w; rcases s with ⟨_, _, _⟩; exact h.uniq _ m w⟩⟩ } @@ -707,7 +707,7 @@ instance fullyFaithfulReflectsLimits [F.Full] [F.Faithful] : ReflectsLimitsOfSiz reflectsLimitsOfShape {J} 𝒥₁ := { reflectsLimit := fun {K} => { reflects := fun {c} t => - (IsLimit.mkConeMorphism fun s => + (IsLimit.mkConeMorphism fun _ => (Cones.functoriality K F).preimage (t.liftConeMorphism _)) <| by apply fun s m => (Cones.functoriality K F).map_injective _ intro s m @@ -720,7 +720,7 @@ instance fullyFaithfulReflectsColimits [F.Full] [F.Faithful] : reflectsColimitsOfShape {J} 𝒥₁ := { reflectsColimit := fun {K} => { reflects := fun {c} t => - (IsColimit.mkCoconeMorphism fun s => + (IsColimit.mkCoconeMorphism fun _ => (Cocones.functoriality K F).preimage (t.descCoconeMorphism _)) <| by apply fun s m => (Cocones.functoriality K F).map_injective _ intro s m diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean b/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean index 932826e7f60e0..d1ad0cedcd3f6 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean @@ -11,8 +11,6 @@ import Mathlib.CategoryTheory.Filtered.Basic Typically forgetful functors from algebraic categories preserve filtered colimits (although not general colimits). See e.g. `Algebra/Category/MonCat/FilteredColimits`. -## Future work -This could be generalised to allow diagrams in lower universes. -/ @@ -22,7 +20,7 @@ open CategoryTheory.Functor namespace CategoryTheory.Limits -universe v u₁ u₂ u₃ +universe w' w₂' w w₂ v u₁ u₂ u₃ -- declare the `v`'s first; see `CategoryTheory.Category` for an explanation variable {C : Type u₁} [Category.{v} C] @@ -30,39 +28,236 @@ variable {D : Type u₂} [Category.{v} D] variable {E : Type u₃} [Category.{v} E] variable {J : Type v} [SmallCategory J] {K : J ⥤ C} +section FilteredColimits + +section Preserves + +-- This should be used with explicit universe variables. +/-- `PreservesFilteredColimitsOfSize.{w', w} F` means that `F` sends all colimit cocones over any +filtered diagram `J ⥤ C` to colimit cocones, where `J : Type w` with `[Category.{w'} J]`. -/ +@[nolint checkUnivs, pp_with_univ] +class PreservesFilteredColimitsOfSize (F : C ⥤ D) where + preserves_filtered_colimits : + ∀ (J : Type w) [Category.{w'} J] [IsFiltered J], PreservesColimitsOfShape J F + /-- A functor is said to preserve filtered colimits, if it preserves all colimits of shape `J`, where -`J` is a filtered category. +`J` is a filtered category which is small relative to the universe in which morphisms of the source +live. -/ -class PreservesFilteredColimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) where - preserves_filtered_colimits : - ∀ (J : Type v) [SmallCategory J] [IsFiltered J], PreservesColimitsOfShape J F +abbrev PreservesFilteredColimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) := + PreservesFilteredColimitsOfSize.{v, v} F -attribute [instance 100] PreservesFilteredColimits.preserves_filtered_colimits +attribute [instance 100] PreservesFilteredColimitsOfSize.preserves_filtered_colimits instance (priority := 100) PreservesColimits.preservesFilteredColimits (F : C ⥤ D) - [PreservesColimits F] : PreservesFilteredColimits F where + [PreservesColimitsOfSize.{w, w'} F] : PreservesFilteredColimitsOfSize.{w, w'} F where preserves_filtered_colimits _ := inferInstance -instance compPreservesFilteredColimits (F : C ⥤ D) (G : D ⥤ E) [PreservesFilteredColimits F] - [PreservesFilteredColimits G] : PreservesFilteredColimits (F ⋙ G) where +instance compPreservesFilteredColimits (F : C ⥤ D) (G : D ⥤ E) + [PreservesFilteredColimitsOfSize.{w, w'} F] [PreservesFilteredColimitsOfSize.{w, w'} G] : + PreservesFilteredColimitsOfSize.{w, w'} (F ⋙ G) where preserves_filtered_colimits _ := inferInstance -/-- A functor is said to preserve cofiltered limits, if it preserves all limits of shape `J`, where -`J` is a cofiltered category. +/-- A functor preserving larger filtered colimits also preserves smaller filtered colimits. -/ +noncomputable def preservesFilteredColimitsOfSizeOfUnivLE (F : C ⥤ D) [UnivLE.{w, w'}] + [UnivLE.{w₂, w₂'}] [PreservesFilteredColimitsOfSize.{w', w₂'} F] : + PreservesFilteredColimitsOfSize.{w, w₂} F where + preserves_filtered_colimits J _ _ := by + let e := ((ShrinkHoms.equivalence J).trans <| Shrink.equivalence _).symm + haveI := IsFiltered.of_equivalence e.symm + exact preservesColimitsOfShapeOfEquiv e F + +/-- +`PreservesFilteredColimitsOfSizeShrink.{w, w'} F` tries to obtain +`PreservesFilteredColimitsOfSize.{w, w'} F` from some other `PreservesFilteredColimitsOfSize F`. +-/ +noncomputable def preservesFilteredColimitsOfSizeShrink (F : C ⥤ D) + [PreservesFilteredColimitsOfSize.{max w w₂, max w' w₂'} F] : + PreservesFilteredColimitsOfSize.{w, w'} F := + preservesFilteredColimitsOfSizeOfUnivLE.{max w w₂, max w' w₂'} F + +/-- +Preserving filtered colimits at any universe implies preserving filtered colimits at universe `0`. +-/ +noncomputable def preservesSmallestFilteredColimitsOfPreservesFilteredColimits (F : C ⥤ D) + [PreservesFilteredColimitsOfSize.{w', w} F] : PreservesFilteredColimitsOfSize.{0, 0} F := + preservesFilteredColimitsOfSizeShrink F + +end Preserves + +section Reflects + +-- This should be used with explicit universe variables. +/-- `ReflectsFilteredColimitsOfSize.{w', w} F` means that whenever the image of a filtered cocone +under `F` is a colimit cocone, the original cocone was already a colimit. -/ +@[nolint checkUnivs, pp_with_univ] +class ReflectsFilteredColimitsOfSize (F : C ⥤ D) where + reflects_filtered_colimits : + ∀ (J : Type w) [Category.{w'} J] [IsFiltered J], ReflectsColimitsOfShape J F + +/-- +A functor is said to reflect filtered colimits, if it reflects all colimits of shape `J`, where +`J` is a filtered category which is small relative to the universe in which morphisms of the source +live. +-/ +abbrev ReflectsFilteredColimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) := + ReflectsFilteredColimitsOfSize.{v, v} F + +attribute [instance 100] ReflectsFilteredColimitsOfSize.reflects_filtered_colimits + +instance (priority := 100) ReflectsColimits.reflectsFilteredColimits (F : C ⥤ D) + [ReflectsColimitsOfSize.{w, w'} F] : ReflectsFilteredColimitsOfSize.{w, w'} F where + reflects_filtered_colimits _ := inferInstance + +instance compReflectsFilteredColimits (F : C ⥤ D) (G : D ⥤ E) + [ReflectsFilteredColimitsOfSize.{w, w'} F] [ReflectsFilteredColimitsOfSize.{w, w'} G] : + ReflectsFilteredColimitsOfSize.{w, w'} (F ⋙ G) where + reflects_filtered_colimits _ := inferInstance + +/-- A functor reflecting larger filtered colimits also reflects smaller filtered colimits. -/ +noncomputable def reflectsFilteredColimitsOfSizeOfUnivLE (F : C ⥤ D) [UnivLE.{w, w'}] + [UnivLE.{w₂, w₂'}] [ReflectsFilteredColimitsOfSize.{w', w₂'} F] : + ReflectsFilteredColimitsOfSize.{w, w₂} F where + reflects_filtered_colimits J _ _ := by + let e := ((ShrinkHoms.equivalence J).trans <| Shrink.equivalence _).symm + haveI := IsFiltered.of_equivalence e.symm + exact reflectsColimitsOfShapeOfEquiv e F + +/-- +`ReflectsFilteredColimitsOfSizeShrink.{w, w'} F` tries to obtain +`ReflectsFilteredColimitsOfSize.{w, w'} F` from some other `ReflectsFilteredColimitsOfSize F`. -/ -class PreservesCofilteredLimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) where +noncomputable def reflectsFilteredColimitsOfSizeShrink (F : C ⥤ D) + [ReflectsFilteredColimitsOfSize.{max w w₂, max w' w₂'} F] : + ReflectsFilteredColimitsOfSize.{w, w'} F := + reflectsFilteredColimitsOfSizeOfUnivLE.{max w w₂, max w' w₂'} F + +/-- +Reflecting filtered colimits at any universe implies reflecting filtered colimits at universe `0`. +-/ +noncomputable def reflectsSmallestFilteredColimitsOfReflectsFilteredColimits (F : C ⥤ D) + [ReflectsFilteredColimitsOfSize.{w', w} F] : ReflectsFilteredColimitsOfSize.{0, 0} F := + reflectsFilteredColimitsOfSizeShrink F + +end Reflects + +end FilteredColimits + +section CofilteredLimits + +section Preserves + +-- This should be used with explicit universe variables. +/-- `PreservesCofilteredLimitsOfSize.{w', w} F` means that `F` sends all limit cones over any +cofiltered diagram `J ⥤ C` to limit cones, where `J : Type w` with `[Category.{w'} J]`. -/ +@[nolint checkUnivs, pp_with_univ] +class PreservesCofilteredLimitsOfSize (F : C ⥤ D) where preserves_cofiltered_limits : - ∀ (J : Type v) [SmallCategory J] [IsCofiltered J], PreservesLimitsOfShape J F + ∀ (J : Type w) [Category.{w'} J] [IsCofiltered J], PreservesLimitsOfShape J F + +/-- +A functor is said to preserve cofiltered limits, if it preserves all limits of shape `J`, where +`J` is a cofiltered category which is small relative to the universe in which morphisms of the +source live. +-/ +abbrev PreservesCofilteredLimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) := + PreservesCofilteredLimitsOfSize.{v, v} F -attribute [instance 100] PreservesCofilteredLimits.preserves_cofiltered_limits +attribute [instance 100] PreservesCofilteredLimitsOfSize.preserves_cofiltered_limits instance (priority := 100) PreservesLimits.preservesCofilteredLimits (F : C ⥤ D) - [PreservesLimits F] : PreservesCofilteredLimits F where + [PreservesLimitsOfSize.{w, w'} F] : PreservesCofilteredLimitsOfSize.{w, w'} F where preserves_cofiltered_limits _ := inferInstance -instance compPreservesCofilteredLimits (F : C ⥤ D) (G : D ⥤ E) [PreservesCofilteredLimits F] - [PreservesCofilteredLimits G] : PreservesCofilteredLimits (F ⋙ G) where +instance compPreservesCofilteredLimits (F : C ⥤ D) (G : D ⥤ E) + [PreservesCofilteredLimitsOfSize.{w, w'} F] [PreservesCofilteredLimitsOfSize.{w, w'} G] : + PreservesCofilteredLimitsOfSize.{w, w'} (F ⋙ G) where preserves_cofiltered_limits _ := inferInstance +/-- A functor preserving larger cofiltered limits also preserves smaller cofiltered limits. -/ +noncomputable def preservesCofilteredLimitsOfSizeOfUnivLE (F : C ⥤ D) [UnivLE.{w, w'}] + [UnivLE.{w₂, w₂'}] [PreservesCofilteredLimitsOfSize.{w', w₂'} F] : + PreservesCofilteredLimitsOfSize.{w, w₂} F where + preserves_cofiltered_limits J _ _ := by + let e := ((ShrinkHoms.equivalence J).trans <| Shrink.equivalence _).symm + haveI := IsCofiltered.of_equivalence e.symm + exact preservesLimitsOfShapeOfEquiv e F + +/-- +`PreservesCofilteredLimitsOfSizeShrink.{w, w'} F` tries to obtain +`PreservesCofilteredLimitsOfSize.{w, w'} F` from some other `PreservesCofilteredLimitsOfSize F`. +-/ +noncomputable def preservesCofilteredLimitsOfSizeShrink (F : C ⥤ D) + [PreservesCofilteredLimitsOfSize.{max w w₂, max w' w₂'} F] : + PreservesCofilteredLimitsOfSize.{w, w'} F := + preservesCofilteredLimitsOfSizeOfUnivLE.{max w w₂, max w' w₂'} F + +/-- +Preserving cofiltered limits at any universe implies preserving cofiltered limits at universe `0`. +-/ +noncomputable def preservesSmallestCofilteredLimitsOfPreservesCofilteredLimits (F : C ⥤ D) + [PreservesCofilteredLimitsOfSize.{w', w} F] : PreservesCofilteredLimitsOfSize.{0, 0} F := + preservesCofilteredLimitsOfSizeShrink F + +end Preserves + +section Reflects + +-- This should be used with explicit universe variables. +/-- `ReflectsCofilteredLimitsOfSize.{w', w} F` means that whenever the image of a cofiltered cone +under `F` is a limit cone, the original cone was already a limit. -/ +@[nolint checkUnivs, pp_with_univ] +class ReflectsCofilteredLimitsOfSize (F : C ⥤ D) where + reflects_cofiltered_limits : + ∀ (J : Type w) [Category.{w'} J] [IsCofiltered J], ReflectsLimitsOfShape J F + +/-- +A functor is said to reflect cofiltered limits, if it reflects all limits of shape `J`, where +`J` is a cofiltered category which is small relative to the universe in which morphisms of the +source live. +-/ +abbrev ReflectsCofilteredLimits (F : C ⥤ D) : Type max u₁ u₂ (v + 1) := + ReflectsCofilteredLimitsOfSize.{v, v} F + +attribute [instance 100] ReflectsCofilteredLimitsOfSize.reflects_cofiltered_limits + +instance (priority := 100) ReflectsLimits.reflectsCofilteredLimits (F : C ⥤ D) + [ReflectsLimitsOfSize.{w, w'} F] : ReflectsCofilteredLimitsOfSize.{w, w'} F where + reflects_cofiltered_limits _ := inferInstance + +instance compReflectsCofilteredLimits (F : C ⥤ D) (G : D ⥤ E) + [ReflectsCofilteredLimitsOfSize.{w, w'} F] [ReflectsCofilteredLimitsOfSize.{w, w'} G] : + ReflectsCofilteredLimitsOfSize.{w, w'} (F ⋙ G) where + reflects_cofiltered_limits _ := inferInstance + +/-- A functor reflecting larger cofiltered limits also reflects smaller cofiltered limits. -/ +noncomputable def reflectsCofilteredLimitsOfSizeOfUnivLE (F : C ⥤ D) [UnivLE.{w, w'}] + [UnivLE.{w₂, w₂'}] [ReflectsCofilteredLimitsOfSize.{w', w₂'} F] : + ReflectsCofilteredLimitsOfSize.{w, w₂} F where + reflects_cofiltered_limits J _ _ := by + let e := ((ShrinkHoms.equivalence J).trans <| Shrink.equivalence _).symm + haveI := IsCofiltered.of_equivalence e.symm + exact reflectsLimitsOfShapeOfEquiv e F + +/-- +`ReflectsCofilteredLimitsOfSizeShrink.{w, w'} F` tries to obtain +`ReflectsCofilteredLimitsOfSize.{w, w'} F` from some other `ReflectsCofilteredLimitsOfSize F`. +-/ +noncomputable def reflectsCofilteredLimitsOfSizeShrink (F : C ⥤ D) + [ReflectsCofilteredLimitsOfSize.{max w w₂, max w' w₂'} F] : + ReflectsCofilteredLimitsOfSize.{w, w'} F := + reflectsCofilteredLimitsOfSizeOfUnivLE.{max w w₂, max w' w₂'} F + +/-- +Reflecting cofiltered limits at any universe implies reflecting cofiltered limits at universe `0`. +-/ +noncomputable def reflectsSmallestCofilteredLimitsOfReflectsCofilteredLimits (F : C ⥤ D) + [ReflectsCofilteredLimitsOfSize.{w', w} F] : ReflectsCofilteredLimitsOfSize.{0, 0} F := + reflectsCofilteredLimitsOfSizeShrink F + +end Reflects + +end CofilteredLimits + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean b/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean index 0d33dbbf72e5a..23b061baf7be2 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean @@ -29,7 +29,7 @@ https://ncatlab.org/nlab/show/commutativity+of+limits+and+colimits#preservation_ -/ -universe w w' v₁ v₂ u u₂ +universe w w' v v₁ v₂ v₃ u u₁ u₂ u₃ noncomputable section @@ -37,6 +37,8 @@ namespace CategoryTheory open Category Limits +section + variable {C : Type u} [Category.{v₁} C] variable {D : Type u₂} [Category.{u} D] variable {E : Type u} [Category.{v₂} E] @@ -71,15 +73,25 @@ def FunctorCategory.prodPreservesColimits [HasBinaryProducts D] [HasColimits D] · intro G G' apply prodComparison_natural ((evaluation C D).obj k) (𝟙 F) } ) } -instance whiskeringLeftPreservesLimits [HasLimits D] (F : C ⥤ E) : - PreservesLimits ((whiskeringLeft C E D).obj F) := - ⟨fun {J} [hJ : Category J] => - ⟨fun {K} => - ⟨fun c {hc} => by - apply evaluationJointlyReflectsLimits - intro Y - change IsLimit (((evaluation E D).obj (F.obj Y)).mapCone c) - exact PreservesLimit.preserves hc⟩⟩⟩ +end + +variable {C : Type u₁} [Category.{v₁} C] +variable {D : Type u₂} [Category.{v₂} D] +variable {E : Type u₃} [Category.{v₃} E] + +instance whiskeringLeftPreservesLimitsOfShape (J : Type u) [Category.{v} J] + [HasLimitsOfShape J D] (F : C ⥤ E) : + PreservesLimitsOfShape J ((whiskeringLeft C E D).obj F) := + ⟨fun {K} => + ⟨fun c {hc} => by + apply evaluationJointlyReflectsLimits + intro Y + change IsLimit (((evaluation E D).obj (F.obj Y)).mapCone c) + exact PreservesLimit.preserves hc⟩⟩ + +instance whiskeringLeftPreservesLimits [HasLimitsOfSize.{w} D] (F : C ⥤ E) : + PreservesLimitsOfSize.{w, w'} ((whiskeringLeft C E D).obj F) := + ⟨fun {J} _ => whiskeringLeftPreservesLimitsOfShape J F⟩ instance whiskeringRightPreservesLimitsOfShape {C : Type*} [Category C] {D : Type*} [Category D] {E : Type*} [Category E] {J : Type*} [Category J] diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean b/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean index 37599d523f5f6..ac77b2c0bcd51 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Limits.lean @@ -50,22 +50,29 @@ def preservesLimitIso : G.obj (limit F) ≅ limit (F ⋙ G) := (PreservesLimit.preserves (limit.isLimit _)).conePointUniqueUpToIso (limit.isLimit _) @[reassoc (attr := simp)] -theorem preservesLimitsIso_hom_π (j) : +theorem preservesLimitIso_hom_π (j) : (preservesLimitIso G F).hom ≫ limit.π _ j = G.map (limit.π F j) := IsLimit.conePointUniqueUpToIso_hom_comp _ _ j +@[deprecated (since := "2024-10-27")] alias preservesLimitsIso_hom_π := preservesLimitIso_hom_π + @[reassoc (attr := simp)] -theorem preservesLimitsIso_inv_π (j) : +theorem preservesLimitIso_inv_π (j) : (preservesLimitIso G F).inv ≫ G.map (limit.π F j) = limit.π _ j := IsLimit.conePointUniqueUpToIso_inv_comp _ _ j +@[deprecated (since := "2024-10-27")] alias preservesLimitsIso_inv_π := preservesLimitIso_inv_π + @[reassoc (attr := simp)] -theorem lift_comp_preservesLimitsIso_hom (t : Cone F) : +theorem lift_comp_preservesLimitIso_hom (t : Cone F) : G.map (limit.lift _ t) ≫ (preservesLimitIso G F).hom = limit.lift (F ⋙ G) (G.mapCone _) := by ext simp [← G.map_comp] +@[deprecated (since := "2024-10-27")] +alias lift_comp_preservesLimitsIso_hom := lift_comp_preservesLimitIso_hom + instance : IsIso (limit.post F G) := show IsIso (preservesLimitIso G F).hom from inferInstance @@ -80,8 +87,8 @@ def preservesLimitNatIso : lim ⋙ G ≅ (whiskeringRight J C D).obj G ⋙ lim : intro _ _ f apply limit.hom_ext; intro j dsimp - simp only [preservesLimitsIso_hom_π, whiskerRight_app, limMap_π, Category.assoc, - preservesLimitsIso_hom_π_assoc, ← G.map_comp]) + simp only [preservesLimitIso_hom_π, whiskerRight_app, limMap_π, Category.assoc, + preservesLimitIso_hom_π_assoc, ← G.map_comp]) end @@ -117,22 +124,31 @@ def preservesColimitIso : G.obj (colimit F) ≅ colimit (F ⋙ G) := (PreservesColimit.preserves (colimit.isColimit _)).coconePointUniqueUpToIso (colimit.isColimit _) @[reassoc (attr := simp)] -theorem ι_preservesColimitsIso_inv (j : J) : +theorem ι_preservesColimitIso_inv (j : J) : colimit.ι _ j ≫ (preservesColimitIso G F).inv = G.map (colimit.ι F j) := IsColimit.comp_coconePointUniqueUpToIso_inv _ (colimit.isColimit (F ⋙ G)) j +@[deprecated (since := "2024-10-27")] +alias ι_preservesColimitsIso_inv := ι_preservesColimitIso_inv + @[reassoc (attr := simp)] -theorem ι_preservesColimitsIso_hom (j : J) : +theorem ι_preservesColimitIso_hom (j : J) : G.map (colimit.ι F j) ≫ (preservesColimitIso G F).hom = colimit.ι (F ⋙ G) j := (PreservesColimit.preserves (colimit.isColimit _)).comp_coconePointUniqueUpToIso_hom _ j +@[deprecated (since := "2024-10-27")] +alias ι_preservesColimitsIso_hom := ι_preservesColimitIso_hom + @[reassoc (attr := simp)] -theorem preservesColimitsIso_inv_comp_desc (t : Cocone F) : +theorem preservesColimitIso_inv_comp_desc (t : Cocone F) : (preservesColimitIso G F).inv ≫ G.map (colimit.desc _ t) = colimit.desc _ (G.mapCocone t) := by ext simp [← G.map_comp] +@[deprecated (since := "2024-10-27")] +alias preservesColimitsIso_inv_comp_desc := preservesColimitIso_inv_comp_desc + instance : IsIso (colimit.post F G) := show IsIso (preservesColimitIso G F).inv from inferInstance @@ -148,10 +164,10 @@ def preservesColimitNatIso : colim ⋙ G ≅ (whiskeringRight J C D).obj G ⋙ c rw [← Iso.inv_comp_eq, ← Category.assoc, ← Iso.eq_comp_inv] apply colimit.hom_ext; intro j dsimp - erw [ι_colimMap_assoc] - simp only [ι_preservesColimitsIso_inv, whiskerRight_app, Category.assoc, - ι_preservesColimitsIso_inv_assoc, ← G.map_comp] - erw [ι_colimMap]) + rw [ι_colimMap_assoc] + simp only [ι_preservesColimitIso_inv, whiskerRight_app, Category.assoc, + ι_preservesColimitIso_inv_assoc, ← G.map_comp] + rw [ι_colimMap]) end diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Opposites.lean b/Mathlib/CategoryTheory/Limits/Preserves/Opposites.lean index d56a29ad3be6d..323fb438c4e70 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Opposites.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Opposites.lean @@ -7,7 +7,7 @@ import Mathlib.CategoryTheory.Limits.Opposites import Mathlib.CategoryTheory.Limits.Preserves.Finite /-! -# Limit preservation properties of `functor.op` and related constructions +# Limit preservation properties of `Functor.op` and related constructions We formulate conditions about `F` which imply that `F.op`, `F.unop`, `F.leftOp` and `F.rightOp` preserve certain (co)limits. diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Zero.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Zero.lean index f13d94165852e..1b3b19cbe4153 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Zero.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Zero.lean @@ -178,13 +178,13 @@ variable [HasZeroObject D] [HasZeroMorphisms D] /-- A zero functor preserves limits. -/ def preservesLimitsOfShapeOfIsZero : PreservesLimitsOfShape J G where - preservesLimit {K} := ⟨fun hc => by + preservesLimit {K} := ⟨fun _ => by rw [Functor.isZero_iff] at hG exact IsLimit.ofIsZero _ ((K ⋙ G).isZero (fun X ↦ hG _)) (hG _)⟩ /-- A zero functor preserves colimits. -/ def preservesColimitsOfShapeOfIsZero : PreservesColimitsOfShape J G where - preservesColimit {K} := ⟨fun hc => by + preservesColimit {K} := ⟨fun _ => by rw [Functor.isZero_iff] at hG exact IsColimit.ofIsZero _ ((K ⋙ G).isZero (fun X ↦ hG _)) (hG _)⟩ diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean b/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean new file mode 100644 index 0000000000000..dabe16ad73949 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2024 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.CategoryTheory.Limits.Preserves.Ulift +import Mathlib.CategoryTheory.Limits.FunctorToTypes + +/-! +# Yoneda preserves certain colimits + +Given a bifunctor `F : J ⥤ Cᵒᵖ ⥤ Type v`, we prove the isomorphism +`Hom(YX, colim_j F(j, -)) ≅ colim_j Hom(YX, F(j, -))`, where `Y` is the Yoneda embedding. + +We state this in two ways. One is functorial in `X` and stated as a natural isomorphism of functors +`yoneda.op ⋙ yoneda.obj (colimit F) ≅ yoneda.op ⋙ colimit (F ⋙ yoneda)`, and from this we +deduce the more traditional preservation statement +`PreservesColimit F (coyoneda.obj (op (yoneda.obj X)))`. + +The proof combines the Yoneda lemma with the fact that colimits in functor categories are computed +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`. + +-/ + +universe v₁ v₂ v₃ u₁ u₂ u₃ + +namespace CategoryTheory + +open CategoryTheory.Limits Opposite + +variable {C : Type u₁} [Category.{v₁} C] + +variable {J : Type u₂} [Category.{v₂} J] [HasColimitsOfShape J (Type v₁)] + [HasColimitsOfShape J (Type (max u₁ v₁))] (F : J ⥤ Cᵒᵖ ⥤ Type v₁) + +/-- Naturally in `X`, we have `Hom(YX, colim_i Fi) ≅ colim_i Hom(YX, Fi)`. -/ +noncomputable def yonedaYonedaColimit : + yoneda.op ⋙ yoneda.obj (colimit F) ≅ yoneda.op ⋙ colimit (F ⋙ yoneda) := calc + yoneda.op ⋙ yoneda.obj (colimit F) + ≅ colimit F ⋙ uliftFunctor.{u₁} := yonedaOpCompYonedaObj (colimit F) + _ ≅ F.flip ⋙ colim ⋙ uliftFunctor.{u₁} := + isoWhiskerRight (colimitIsoFlipCompColim F) uliftFunctor.{u₁} + _ ≅ F.flip ⋙ (whiskeringRight _ _ _).obj uliftFunctor.{u₁} ⋙ colim := + isoWhiskerLeft F.flip (preservesColimitNatIso uliftFunctor.{u₁}) + _ ≅ (yoneda.op ⋙ coyoneda ⋙ (whiskeringLeft _ _ _).obj F) ⋙ colim := isoWhiskerRight + (isoWhiskerRight largeCurriedYonedaLemma.symm ((whiskeringLeft _ _ _).obj F)) colim + _ ≅ yoneda.op ⋙ colimit (F ⋙ yoneda) := + isoWhiskerLeft yoneda.op (colimitIsoFlipCompColim (F ⋙ yoneda)).symm + +theorem yonedaYonedaColimit_app_inv {X : C} : ((yonedaYonedaColimit F).app (op X)).inv = + (colimitObjIsoColimitCompEvaluation _ _).hom ≫ + (colimit.post F (coyoneda.obj (op (yoneda.obj X)))) := by + dsimp [yonedaYonedaColimit] + simp only [Category.id_comp, Iso.cancel_iso_hom_left] + apply colimit.hom_ext + intro j + rw [colimit.ι_post, ι_colimMap_assoc] + simp only [← CategoryTheory.Functor.assoc, comp_evaluation] + rw [ι_preservesColimitIso_inv_assoc, ← Functor.map_comp_assoc] + simp only [← comp_evaluation] + rw [colimitObjIsoColimitCompEvaluation_ι_inv, whiskerLeft_app] + ext η Y f + simp [largeCurriedYonedaLemma, yonedaOpCompYonedaObj, FunctorToTypes.colimit.map_ι_apply, + map_yonedaEquiv] + +noncomputable instance {X : C} : PreservesColimit F (coyoneda.obj (op (yoneda.obj X))) := by + suffices IsIso (colimit.post F (coyoneda.obj (op (yoneda.obj X)))) from + preservesColimitOfIsIsoPost _ _ + suffices colimit.post F (coyoneda.obj (op (yoneda.obj X))) = + (colimitObjIsoColimitCompEvaluation _ _).inv ≫ ((yonedaYonedaColimit F).app (op X)).inv from + this ▸ inferInstance + rw [yonedaYonedaColimit_app_inv, Iso.inv_hom_id_assoc] + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Presheaf.lean b/Mathlib/CategoryTheory/Limits/Presheaf.lean index d7b3844ba9d24..ca7b9175b9037 100644 --- a/Mathlib/CategoryTheory/Limits/Presheaf.lean +++ b/Mathlib/CategoryTheory/Limits/Presheaf.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Joël Riou -/ -import Mathlib.CategoryTheory.Comma.Presheaf +import Mathlib.CategoryTheory.Comma.Presheaf.Basic import Mathlib.CategoryTheory.Elements import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction import Mathlib.CategoryTheory.Limits.Final @@ -74,7 +74,7 @@ def restrictedYonedaHomEquiv' (P : Cᵒᵖ ⥤ Type v₁) (E : ℰ) : (Functor.const (CostructuredArrow yoneda P)).obj E) ≃ (P ⟶ (restrictedYoneda A).obj E) where toFun f := - { app := fun X x => f.app (CostructuredArrow.mk (yonedaEquiv.symm x)) + { app := fun _ x => f.app (CostructuredArrow.mk (yonedaEquiv.symm x)) naturality := fun {X₁ X₂} φ => by ext x let ψ : CostructuredArrow.mk (yonedaEquiv.symm (P.toPrefunctor.map φ x)) ⟶ @@ -202,8 +202,7 @@ noncomputable def coconeOfRepresentable (P : Cᵒᵖ ⥤ Type v₁) : { app := fun x => yonedaEquiv.symm x.unop.2 naturality := fun {x₁ x₂} f => by dsimp - rw [comp_id] - erw [← yonedaEquiv_symm_map] + rw [comp_id, ← yonedaEquiv_symm_map] congr 1 rw [f.unop.2] } @@ -560,7 +559,7 @@ variable {I : Type v₁} [SmallCategory I] (F : I ⥤ C) Proposition 2.6.3(ii) in [Kashiwara2006] -/ theorem final_toCostructuredArrow_comp_pre {c : Cocone (F ⋙ yoneda)} (hc : IsColimit c) : Functor.Final (c.toCostructuredArrow ⋙ CostructuredArrow.pre F yoneda c.pt) := by - apply Functor.cofinal_of_isTerminal_colimit_comp_yoneda + apply Functor.final_of_isTerminal_colimit_comp_yoneda suffices IsTerminal (colimit ((c.toCostructuredArrow ⋙ CostructuredArrow.pre F yoneda c.pt) ⋙ CostructuredArrow.toOver yoneda c.pt)) by diff --git a/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean index 4ea865a6b1d0d..3cf40588ccb09 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean @@ -29,9 +29,7 @@ braiding and associating isomorphisms, and the product comparison morphism. -/ -noncomputable section - -universe v u u₂ +universe v v₁ u u₁ u₂ open CategoryTheory @@ -48,8 +46,12 @@ open WalkingPair /-- The equivalence swapping left and right. -/ def WalkingPair.swap : WalkingPair ≃ WalkingPair where - toFun j := WalkingPair.recOn j right left - invFun j := WalkingPair.recOn j right left + toFun j := match j with + | left => right + | right => left + invFun j := match j with + | left => right + | right => left left_inv j := by cases j; repeat rfl right_inv j := by cases j; repeat rfl @@ -72,7 +74,9 @@ theorem WalkingPair.swap_symm_apply_ff : WalkingPair.swap.symm right = left := /-- An equivalence from `WalkingPair` to `Bool`, sometimes useful when reindexing limits. -/ def WalkingPair.equivBool : WalkingPair ≃ Bool where - toFun j := WalkingPair.recOn j true false + toFun j := match j with + | left => true + | right => false -- to match equiv.sum_equiv_sigma_bool invFun b := Bool.recOn b right left left_inv j := by cases j; repeat rfl @@ -132,7 +136,9 @@ attribute [local aesop safe tactic (rule_sets := [CategoryTheory])] /-- The natural transformation between two functors out of the walking pair, specified by its components. -/ def mapPair : F ⟶ G where - app j := Discrete.recOn j fun j => WalkingPair.casesOn j f g + app j := match j with + | ⟨left⟩ => f + | ⟨right⟩ => g naturality := fun ⟨X⟩ ⟨Y⟩ ⟨⟨u⟩⟩ => by aesop_cat @[simp] @@ -147,7 +153,9 @@ theorem mapPair_right : (mapPair f g).app ⟨right⟩ = g := components. -/ @[simps!] def mapPairIso (f : F.obj ⟨left⟩ ≅ G.obj ⟨left⟩) (g : F.obj ⟨right⟩ ≅ G.obj ⟨right⟩) : F ≅ G := - NatIso.ofComponents (fun j => Discrete.recOn j fun j => WalkingPair.casesOn j f g) + NatIso.ofComponents (fun j ↦ match j with + | ⟨left⟩ => f + | ⟨right⟩ => g) (fun ⟨⟨u⟩⟩ => by aesop_cat) end @@ -160,7 +168,7 @@ def diagramIsoPair (F : Discrete WalkingPair ⥤ C) : section -variable {D : Type u} [Category.{v} D] +variable {D : Type u₁} [Category.{v₁} D] /-- The natural isomorphism between `pair X Y ⋙ F` and `pair (F.obj X) (F.obj Y)`. -/ def pairComp (X Y : C) (F : C ⥤ D) : pair X Y ⋙ F ≅ pair (F.obj X) (F.obj Y) := @@ -188,6 +196,12 @@ theorem BinaryFan.π_app_left {X Y : C} (s : BinaryFan X Y) : s.π.app ⟨Walkin theorem BinaryFan.π_app_right {X Y : C} (s : BinaryFan X Y) : s.π.app ⟨WalkingPair.right⟩ = s.snd := rfl +/-- Constructs an isomorphism of `BinaryFan`s out of an isomorphism of the tips that commutes with +the projections. -/ +def BinaryFan.ext {A B : C} {c c' : BinaryFan A B} (e : c.pt ≅ c'.pt) + (h₁ : c.fst = e.hom ≫ c'.fst) (h₂ : c.snd = e.hom ≫ c'.snd) : c ≅ c' := + Cones.ext e (fun j => by rcases j with ⟨⟨⟩⟩ <;> assumption) + /-- A convenient way to show that a binary fan is a limit. -/ def BinaryFan.IsLimit.mk {X Y : C} (s : BinaryFan X Y) (lift : ∀ {T : C} (_ : T ⟶ X) (_ : T ⟶ Y), T ⟶ s.pt) @@ -202,7 +216,7 @@ def BinaryFan.IsLimit.mk {X Y : C} (s : BinaryFan X Y) rintro t (rfl | rfl) · exact hl₁ _ _ · exact hl₂ _ _) - fun t m h => uniq _ _ _ (h ⟨WalkingPair.left⟩) (h ⟨WalkingPair.right⟩) + fun _ _ h => uniq _ _ _ (h ⟨WalkingPair.left⟩) (h ⟨WalkingPair.right⟩) theorem BinaryFan.IsLimit.hom_ext {W X Y : C} {s : BinaryFan X Y} (h : IsLimit s) {f g : W ⟶ s.pt} (h₁ : f ≫ s.fst = g ≫ s.fst) (h₂ : f ≫ s.snd = g ≫ s.snd) : f = g := @@ -217,6 +231,12 @@ abbrev BinaryCofan.inl {X Y : C} (s : BinaryCofan X Y) := s.ι.app ⟨WalkingPai /-- The second inclusion of a binary cofan. -/ abbrev BinaryCofan.inr {X Y : C} (s : BinaryCofan X Y) := s.ι.app ⟨WalkingPair.right⟩ +/-- Constructs an isomorphism of `BinaryCofan`s out of an isomorphism of the tips that commutes with +the injections. -/ +def BinaryCofan.ext {A B : C} {c c' : BinaryCofan A B} (e : c.pt ≅ c'.pt) + (h₁ : c.inl ≫ e.hom = c'.inl) (h₂ : c.inr ≫ e.hom = c'.inr) : c ≅ c' := + Cocones.ext e (fun j => by rcases j with ⟨⟨⟩⟩ <;> assumption) + @[simp] theorem BinaryCofan.ι_app_left {X Y : C} (s : BinaryCofan X Y) : s.ι.app ⟨WalkingPair.left⟩ = s.inl := rfl @@ -239,7 +259,7 @@ def BinaryCofan.IsColimit.mk {X Y : C} (s : BinaryCofan X Y) rintro t (rfl | rfl) · exact hd₁ _ _ · exact hd₂ _ _) - fun t m h => uniq _ _ _ (h ⟨WalkingPair.left⟩) (h ⟨WalkingPair.right⟩) + fun _ _ h => uniq _ _ _ (h ⟨WalkingPair.left⟩) (h ⟨WalkingPair.right⟩) theorem BinaryCofan.IsColimit.hom_ext {W X Y : C} {s : BinaryCofan X Y} (h : IsColimit s) {f g : s.pt ⟶ W} (h₁ : s.inl ≫ f = s.inl ≫ g) (h₂ : s.inr ≫ f = s.inr ≫ g) : f = g := @@ -461,12 +481,12 @@ abbrev HasBinaryCoproduct (X Y : C) := /-- If we have a product of `X` and `Y`, we can access it using `prod X Y` or `X ⨯ Y`. -/ -abbrev prod (X Y : C) [HasBinaryProduct X Y] := +noncomputable abbrev prod (X Y : C) [HasBinaryProduct X Y] := limit (pair X Y) /-- If we have a coproduct of `X` and `Y`, we can access it using `coprod X Y` or `X ⨿ Y`. -/ -abbrev coprod (X Y : C) [HasBinaryCoproduct X Y] := +noncomputable abbrev coprod (X Y : C) [HasBinaryCoproduct X Y] := colimit (pair X Y) /-- Notation for the product -/ @@ -476,23 +496,23 @@ notation:20 X " ⨯ " Y:20 => prod X Y notation:20 X " ⨿ " Y:20 => coprod X Y /-- The projection map to the first component of the product. -/ -abbrev prod.fst {X Y : C} [HasBinaryProduct X Y] : X ⨯ Y ⟶ X := +noncomputable abbrev prod.fst {X Y : C} [HasBinaryProduct X Y] : X ⨯ Y ⟶ X := limit.π (pair X Y) ⟨WalkingPair.left⟩ /-- The projection map to the second component of the product. -/ -abbrev prod.snd {X Y : C} [HasBinaryProduct X Y] : X ⨯ Y ⟶ Y := +noncomputable abbrev prod.snd {X Y : C} [HasBinaryProduct X Y] : X ⨯ Y ⟶ Y := limit.π (pair X Y) ⟨WalkingPair.right⟩ /-- The inclusion map from the first component of the coproduct. -/ -abbrev coprod.inl {X Y : C} [HasBinaryCoproduct X Y] : X ⟶ X ⨿ Y := +noncomputable abbrev coprod.inl {X Y : C} [HasBinaryCoproduct X Y] : X ⟶ X ⨿ Y := colimit.ι (pair X Y) ⟨WalkingPair.left⟩ /-- The inclusion map from the second component of the coproduct. -/ -abbrev coprod.inr {X Y : C} [HasBinaryCoproduct X Y] : Y ⟶ X ⨿ Y := +noncomputable abbrev coprod.inr {X Y : C} [HasBinaryCoproduct X Y] : Y ⟶ X ⨿ Y := colimit.ι (pair X Y) ⟨WalkingPair.right⟩ /-- The binary fan constructed from the projection maps is a limit. -/ -def prodIsProd (X Y : C) [HasBinaryProduct X Y] : +noncomputable def prodIsProd (X Y : C) [HasBinaryProduct X Y] : IsLimit (BinaryFan.mk (prod.fst : X ⨯ Y ⟶ X) prod.snd) := (limit.isLimit _).ofIsoLimit (Cones.ext (Iso.refl _) (fun ⟨u⟩ => by cases u @@ -501,7 +521,7 @@ def prodIsProd (X Y : C) [HasBinaryProduct X Y] : )) /-- The binary cofan constructed from the coprojection maps is a colimit. -/ -def coprodIsCoprod (X Y : C) [HasBinaryCoproduct X Y] : +noncomputable def coprodIsCoprod (X Y : C) [HasBinaryCoproduct X Y] : IsColimit (BinaryCofan.mk (coprod.inl : X ⟶ X ⨿ Y) coprod.inr) := (colimit.isColimit _).ofIsoColimit (Cocones.ext (Iso.refl _) (fun ⟨u⟩ => by cases u @@ -521,29 +541,29 @@ theorem coprod.hom_ext {W X Y : C} [HasBinaryCoproduct X Y] {f g : X ⨿ Y ⟶ W /-- If the product of `X` and `Y` exists, then every pair of morphisms `f : W ⟶ X` and `g : W ⟶ Y` induces a morphism `prod.lift f g : W ⟶ X ⨯ Y`. -/ -abbrev prod.lift {W X Y : C} [HasBinaryProduct X Y] (f : W ⟶ X) (g : W ⟶ Y) : W ⟶ X ⨯ Y := +noncomputable abbrev prod.lift {W X Y : C} [HasBinaryProduct X Y] + (f : W ⟶ X) (g : W ⟶ Y) : W ⟶ X ⨯ Y := limit.lift _ (BinaryFan.mk f g) /-- diagonal arrow of the binary product in the category `fam I` -/ -abbrev diag (X : C) [HasBinaryProduct X X] : X ⟶ X ⨯ X := +noncomputable abbrev diag (X : C) [HasBinaryProduct X X] : X ⟶ X ⨯ X := prod.lift (𝟙 _) (𝟙 _) /-- If the coproduct of `X` and `Y` exists, then every pair of morphisms `f : X ⟶ W` and `g : Y ⟶ W` induces a morphism `coprod.desc f g : X ⨿ Y ⟶ W`. -/ -abbrev coprod.desc {W X Y : C} [HasBinaryCoproduct X Y] (f : X ⟶ W) (g : Y ⟶ W) : X ⨿ Y ⟶ W := +noncomputable abbrev coprod.desc {W X Y : C} [HasBinaryCoproduct X Y] + (f : X ⟶ W) (g : Y ⟶ W) : X ⨿ Y ⟶ W := colimit.desc _ (BinaryCofan.mk f g) /-- codiagonal arrow of the binary coproduct -/ -abbrev codiag (X : C) [HasBinaryCoproduct X X] : X ⨿ X ⟶ X := +noncomputable abbrev codiag (X : C) [HasBinaryCoproduct X X] : X ⨿ X ⟶ X := coprod.desc (𝟙 _) (𝟙 _) --- Porting note (#10618): simp removes as simp can prove this @[reassoc] theorem prod.lift_fst {W X Y : C} [HasBinaryProduct X Y] (f : W ⟶ X) (g : W ⟶ Y) : prod.lift f g ≫ prod.fst = f := limit.lift_π _ _ --- Porting note (#10618): simp removes as simp can prove this @[reassoc] theorem prod.lift_snd {W X Y : C} [HasBinaryProduct X Y] (f : W ⟶ X) (g : W ⟶ Y) : prod.lift f g ≫ prod.snd = g := @@ -581,30 +601,30 @@ instance coprod.epi_desc_of_epi_right {W X Y : C} [HasBinaryCoproduct X Y] (f : /-- If the product of `X` and `Y` exists, then every pair of morphisms `f : W ⟶ X` and `g : W ⟶ Y` induces a morphism `l : W ⟶ X ⨯ Y` satisfying `l ≫ Prod.fst = f` and `l ≫ Prod.snd = g`. -/ -def prod.lift' {W X Y : C} [HasBinaryProduct X Y] (f : W ⟶ X) (g : W ⟶ Y) : +noncomputable def prod.lift' {W X Y : C} [HasBinaryProduct X Y] (f : W ⟶ X) (g : W ⟶ Y) : { l : W ⟶ X ⨯ Y // l ≫ prod.fst = f ∧ l ≫ prod.snd = g } := ⟨prod.lift f g, prod.lift_fst _ _, prod.lift_snd _ _⟩ /-- If the coproduct of `X` and `Y` exists, then every pair of morphisms `f : X ⟶ W` and `g : Y ⟶ W` induces a morphism `l : X ⨿ Y ⟶ W` satisfying `coprod.inl ≫ l = f` and `coprod.inr ≫ l = g`. -/ -def coprod.desc' {W X Y : C} [HasBinaryCoproduct X Y] (f : X ⟶ W) (g : Y ⟶ W) : +noncomputable def coprod.desc' {W X Y : C} [HasBinaryCoproduct X Y] (f : X ⟶ W) (g : Y ⟶ W) : { l : X ⨿ Y ⟶ W // coprod.inl ≫ l = f ∧ coprod.inr ≫ l = g } := ⟨coprod.desc f g, coprod.inl_desc _ _, coprod.inr_desc _ _⟩ /-- If the products `W ⨯ X` and `Y ⨯ Z` exist, then every pair of morphisms `f : W ⟶ Y` and `g : X ⟶ Z` induces a morphism `prod.map f g : W ⨯ X ⟶ Y ⨯ Z`. -/ -def prod.map {W X Y Z : C} [HasBinaryProduct W X] [HasBinaryProduct Y Z] (f : W ⟶ Y) (g : X ⟶ Z) : - W ⨯ X ⟶ Y ⨯ Z := +noncomputable def prod.map {W X Y Z : C} [HasBinaryProduct W X] [HasBinaryProduct Y Z] + (f : W ⟶ Y) (g : X ⟶ Z) : W ⨯ X ⟶ Y ⨯ Z := limMap (mapPair f g) /-- If the coproducts `W ⨿ X` and `Y ⨿ Z` exist, then every pair of morphisms `f : W ⟶ Y` and `g : W ⟶ Z` induces a morphism `coprod.map f g : W ⨿ X ⟶ Y ⨿ Z`. -/ -def coprod.map {W X Y Z : C} [HasBinaryCoproduct W X] [HasBinaryCoproduct Y Z] (f : W ⟶ Y) - (g : X ⟶ Z) : W ⨿ X ⟶ Y ⨿ Z := +noncomputable def coprod.map {W X Y Z : C} [HasBinaryCoproduct W X] [HasBinaryCoproduct Y Z] + (f : W ⟶ Y) (g : X ⟶ Z) : W ⨿ X ⟶ Y ⨿ Z := colimMap (mapPair f g) -section ProdLemmas +noncomputable section ProdLemmas -- Making the reassoc version of this a simp lemma seems to be more harmful than helpful. @[reassoc, simp] @@ -688,15 +708,15 @@ instance prod.map_mono {C : Type*} [Category C] {W X Y Z : C} (f : W ⟶ Y) (g : · rw [← cancel_mono g] simpa using congr_arg (fun f => f ≫ prod.snd) h⟩ -@[reassoc] -- Porting note (#10618): simp can prove these +@[reassoc] theorem prod.diag_map {X Y : C} (f : X ⟶ Y) [HasBinaryProduct X X] [HasBinaryProduct Y Y] : diag X ≫ prod.map f f = f ≫ diag Y := by simp -@[reassoc] -- Porting note (#10618): simp can prove these +@[reassoc] theorem prod.diag_map_fst_snd {X Y : C} [HasBinaryProduct X Y] [HasBinaryProduct (X ⨯ Y) (X ⨯ Y)] : diag (X ⨯ Y) ≫ prod.map prod.fst prod.snd = 𝟙 (X ⨯ Y) := by simp -@[reassoc] -- Porting note (#10618): simp can prove these +@[reassoc] theorem prod.diag_map_fst_snd_comp [HasLimitsOfShape (Discrete WalkingPair) C] {X X' Y Y' : C} (g : X ⟶ Y) (g' : X' ⟶ Y') : diag (X ⨯ X') ≫ prod.map (prod.fst ≫ g) (prod.snd ≫ g') = prod.map g g' := by simp @@ -706,7 +726,7 @@ instance {X : C} [HasBinaryProduct X X] : IsSplitMono (diag X) := end ProdLemmas -section CoprodLemmas +noncomputable section CoprodLemmas -- @[reassoc (attr := simp)] @[simp] -- Porting note: removing reassoc tag since result is not hygienic (two h's) @@ -847,7 +867,7 @@ theorem hasBinaryCoproducts_of_hasColimit_pair [∀ {X Y : C}, HasColimit (pair HasBinaryCoproducts C := { has_colimit := fun F => hasColimitOfIso (diagramIsoPair F) } -section +noncomputable section variable {C} @@ -938,7 +958,7 @@ theorem prod.triangle [HasBinaryProducts C] (X Y : C) : end -section +noncomputable section variable {C} variable [HasBinaryCoproducts C] @@ -1001,7 +1021,7 @@ theorem coprod.triangle (X Y : C) : end -section ProdFunctor +noncomputable section ProdFunctor -- Porting note (#10754): added category instance as it did not propagate variable {C} [Category.{v} C] [HasBinaryProducts C] @@ -1011,7 +1031,7 @@ variable {C} [Category.{v} C] [HasBinaryProducts C] def prod.functor : C ⥤ C ⥤ C where obj X := { obj := fun Y => X ⨯ Y - map := fun {Y Z} => prod.map (𝟙 X) } + map := fun {_ _} => prod.map (𝟙 X) } map f := { app := fun T => prod.map f (𝟙 T) } @@ -1022,7 +1042,7 @@ def prod.functorLeftComp (X Y : C) : end ProdFunctor -section CoprodFunctor +noncomputable section CoprodFunctor -- Porting note (#10754): added category instance as it did not propagate variable {C} [Category.{v} C] [HasBinaryCoproducts C] @@ -1032,7 +1052,7 @@ variable {C} [Category.{v} C] [HasBinaryCoproducts C] def coprod.functor : C ⥤ C ⥤ C where obj X := { obj := fun Y => X ⨿ Y - map := fun {Y Z} => coprod.map (𝟙 X) } + map := fun {_ _} => coprod.map (𝟙 X) } map f := { app := fun T => coprod.map f (𝟙 T) } /-- The coproduct functor can be decomposed. -/ @@ -1042,7 +1062,7 @@ def coprod.functorLeftComp (X Y : C) : end CoprodFunctor -section ProdComparison +noncomputable section ProdComparison universe w w' u₃ @@ -1126,7 +1146,7 @@ theorem prodComparison_comp : end ProdComparison -section CoprodComparison +noncomputable section CoprodComparison universe w @@ -1208,13 +1228,15 @@ variable {C : Type u} [Category.{v} C] /-- Auxiliary definition for `Over.coprod`. -/ @[simps] -def Over.coprodObj [HasBinaryCoproducts C] {A : C} : Over A → Over A ⥤ Over A := fun f => +noncomputable def Over.coprodObj [HasBinaryCoproducts C] {A : C} : + Over A → Over A ⥤ Over A := + fun f => { obj := fun g => Over.mk (coprod.desc f.hom g.hom) map := fun k => Over.homMk (coprod.map (𝟙 _) k.left) } /-- A category with binary coproducts has a functorial `sup` operation on over categories. -/ @[simps] -def Over.coprod [HasBinaryCoproducts C] {A : C} : Over A ⥤ Over A ⥤ Over A where +noncomputable def Over.coprod [HasBinaryCoproducts C] {A : C} : Over A ⥤ Over A ⥤ Over A where obj f := Over.coprodObj f map k := { app := fun g => Over.homMk (coprod.map k.left (𝟙 _)) (by diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean index c5ab7690aefbc..89b2d0b933bb6 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean @@ -122,7 +122,6 @@ namespace Bicones /-- To give an isomorphism between cocones, it suffices to give an isomorphism between their vertices which commutes with the cocone maps. -/ --- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule @[aesop apply safe (rule_sets := [CategoryTheory]), simps] def ext {c c' : Bicone F} (φ : c.pt ≅ c'.pt) (wι : ∀ j, c.ι j ≫ φ.hom = c'.ι j := by aesop_cat) @@ -176,7 +175,7 @@ attribute [local aesop safe cases (rule_sets := [CategoryTheory])] Eq /-- Extract the cone from a bicone. -/ def toConeFunctor : Bicone F ⥤ Cone (Discrete.functor F) where obj B := { pt := B.pt, π := { app := fun j => B.π j.as } } - map {X Y} F := { hom := F.hom, w := fun _ => F.wπ _ } + map {_ _} F := { hom := F.hom, w := fun _ => F.wπ _ } /-- A shorthand for `toConeFunctor.obj` -/ abbrev toCone (B : Bicone F) : Cone (Discrete.functor F) := toConeFunctor.obj B @@ -197,7 +196,7 @@ theorem toCone_proj (B : Bicone F) (j : J) : Fan.proj B.toCone j = B.π j := rfl /-- Extract the cocone from a bicone. -/ def toCoconeFunctor : Bicone F ⥤ Cocone (Discrete.functor F) where obj B := { pt := B.pt, ι := { app := fun j => B.ι j.as } } - map {X Y} F := { hom := F.hom, w := fun _ => F.wι _ } + map {_ _} F := { hom := F.hom, w := fun _ => F.wι _ } /-- A shorthand for `toCoconeFunctor.obj` -/ abbrev toCocone (B : Bicone F) : Cocone (Discrete.functor F) := toCoconeFunctor.obj B @@ -251,8 +250,7 @@ structure IsBilimit {F : J → C} (B : Bicone F) where attribute [inherit_doc IsBilimit] IsBilimit.isLimit IsBilimit.isColimit --- Porting note (#10618): simp can prove this, linter doesn't notice it is removed -attribute [-simp, nolint simpNF] IsBilimit.mk.injEq +attribute [simp] IsBilimit.mk.injEq attribute [local ext] Bicone.IsBilimit @@ -756,7 +754,7 @@ theorem biproduct.toSubtype_eq_desc [DecidablePred p] : biproduct.desc fun j => if h : p j then biproduct.ι (Subtype.restrict p f) ⟨j, h⟩ else 0 := biproduct.hom_ext' _ _ (by simp) -@[reassoc] -- Porting note (#10618): simp can prove both versions +@[reassoc] theorem biproduct.ι_toSubtype_subtype (j : Subtype p) : biproduct.ι f j ≫ biproduct.toSubtype f p = biproduct.ι (Subtype.restrict p f) j := by ext @@ -859,10 +857,10 @@ def kernelForkBiproductToSubtype (p : Set K) : ext j k simp only [Category.assoc, biproduct.ι_fromSubtype_assoc, biproduct.ι_toSubtype_assoc, comp_zero, zero_comp] - erw [dif_neg k.2] + rw [dif_neg k.2] simp only [zero_comp]) isLimit := - KernelFork.IsLimit.ofι _ _ (fun {W} g _ => g ≫ biproduct.toSubtype f pᶜ) + KernelFork.IsLimit.ofι _ _ (fun {_} g _ => g ≫ biproduct.toSubtype f pᶜ) (by intro W' g' w ext j @@ -898,7 +896,7 @@ def cokernelCoforkBiproductFromSubtype (p : Set K) : · simp only [zero_comp] · exact not_not.mpr k.2) isColimit := - CokernelCofork.IsColimit.ofπ _ _ (fun {W} g _ => biproduct.fromSubtype f pᶜ ≫ g) + CokernelCofork.IsColimit.ofπ _ _ (fun {_} g _ => biproduct.fromSubtype f pᶜ ≫ g) (by intro W g' w ext j @@ -1028,12 +1026,12 @@ instance (priority := 100) hasZeroObject_of_hasFiniteBiproducts [HasFiniteBiprod section -variable {C} [Unique J] (f : J → C) +variable {C} attribute [local simp] eq_iff_true_of_subsingleton in /-- The limit bicone for the biproduct over an index type with exactly one term. -/ @[simps] -def limitBiconeOfUnique : LimitBicone f where +def limitBiconeOfUnique [Unique J] (f : J → C) : LimitBicone f where bicone := { pt := f default π := fun j => eqToHom (by congr; rw [← Unique.uniq] ) @@ -1042,12 +1040,13 @@ def limitBiconeOfUnique : LimitBicone f where { isLimit := (limitConeOfUnique f).isLimit isColimit := (colimitCoconeOfUnique f).isColimit } -instance (priority := 100) hasBiproduct_unique : HasBiproduct f := - HasBiproduct.mk (limitBiconeOfUnique f) +instance (priority := 100) hasBiproduct_unique [Subsingleton J] [Nonempty J] (f : J → C) : + HasBiproduct f := + let ⟨_⟩ := nonempty_unique J; .mk (limitBiconeOfUnique f) /-- A biproduct over an index type with exactly one term is just the object over that term. -/ @[simps!] -def biproductUniqueIso : ⨁ f ≅ f default := +def biproductUniqueIso [Unique J] (f : J → C) : ⨁ f ≅ f default := (biproduct.uniqueUpToIso _ (limitBiconeOfUnique f).isBilimit).symm end @@ -1118,7 +1117,6 @@ namespace BinaryBicones /-- To give an isomorphism between cocones, it suffices to give an isomorphism between their vertices which commutes with the cocone maps. -/ --- Porting note: `@[ext]` used to accept lemmas like this. Now we add an aesop rule @[aesop apply safe (rule_sets := [CategoryTheory]), simps] def ext {P Q : C} {c c' : BinaryBicone P Q} (φ : c.pt ≅ c'.pt) (winl : c.inl ≫ φ.hom = c'.inl := by aesop_cat) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean b/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean index 3388588964ed5..d16936f661fa4 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean @@ -31,7 +31,7 @@ wide-pullbacks, wide-pushouts, multiequalizers and cokernels. -/ -universe w v u t r +universe w w' v u t r namespace CategoryTheory.Limits.Concrete @@ -247,9 +247,9 @@ end WidePullback section Multiequalizer -variable [ConcreteCategory.{max w v} C] +variable [ConcreteCategory.{max w w' v} C] -theorem multiequalizer_ext {I : MulticospanIndex.{w} C} [HasMultiequalizer I] +theorem multiequalizer_ext {I : MulticospanIndex.{w, w'} C} [HasMultiequalizer I] [PreservesLimit I.multicospan (forget C)] (x y : ↑(multiequalizer I)) (h : ∀ t : I.L, Multiequalizer.ι I t x = Multiequalizer.ι I t y) : x = y := by apply Concrete.limit_ext @@ -259,11 +259,11 @@ theorem multiequalizer_ext {I : MulticospanIndex.{w} C} [HasMultiequalizer I] simp [h] /-- An auxiliary equivalence to be used in `multiequalizerEquiv` below. -/ -def multiequalizerEquivAux (I : MulticospanIndex C) : +def multiequalizerEquivAux (I : MulticospanIndex.{w, w'} C) : (I.multicospan ⋙ forget C).sections ≃ { x : ∀ i : I.L, I.left i // ∀ i : I.R, I.fst i (x _) = I.snd i (x _) } where toFun x := - ⟨fun i => x.1 (WalkingMulticospan.left _), fun i => by + ⟨fun _ => x.1 (WalkingMulticospan.left _), fun i => by have a := x.2 (WalkingMulticospan.Hom.fst i) have b := x.2 (WalkingMulticospan.Hom.snd i) rw [← b] at a @@ -271,7 +271,7 @@ def multiequalizerEquivAux (I : MulticospanIndex C) : invFun x := { val := fun j => match j with - | WalkingMulticospan.left a => x.1 _ + | WalkingMulticospan.left _ => x.1 _ | WalkingMulticospan.right b => I.fst b (x.1 _) property := by rintro (a | b) (a' | b') (f | f | f) @@ -292,17 +292,17 @@ def multiequalizerEquivAux (I : MulticospanIndex C) : /-- The equivalence between the noncomputable multiequalizer and the concrete multiequalizer. -/ -noncomputable def multiequalizerEquiv (I : MulticospanIndex.{w} C) [HasMultiequalizer I] +noncomputable def multiequalizerEquiv (I : MulticospanIndex.{w, w'} C) [HasMultiequalizer I] [PreservesLimit I.multicospan (forget C)] : (multiequalizer I : C) ≃ { x : ∀ i : I.L, I.left i // ∀ i : I.R, I.fst i (x _) = I.snd i (x _) } := letI h1 := limit.isLimit I.multicospan letI h2 := isLimitOfPreserves (forget C) h1 - letI E := h2.conePointUniqueUpToIso (Types.limitConeIsLimit.{w, v} _) - Equiv.trans E.toEquiv (Concrete.multiequalizerEquivAux.{w, v} I) + letI E := h2.conePointUniqueUpToIso (Types.limitConeIsLimit.{max w w', v} _) + Equiv.trans E.toEquiv (Concrete.multiequalizerEquivAux I) @[simp] -theorem multiequalizerEquiv_apply (I : MulticospanIndex.{w} C) [HasMultiequalizer I] +theorem multiequalizerEquiv_apply (I : MulticospanIndex.{w, w'} C) [HasMultiequalizer I] [PreservesLimit I.multicospan (forget C)] (x : ↑(multiequalizer I)) (i : I.L) : ((Concrete.multiequalizerEquiv I) x : ∀ i : I.L, I.left i) i = Multiequalizer.ι I i x := rfl diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Connected.lean b/Mathlib/CategoryTheory/Limits/Shapes/Connected.lean new file mode 100644 index 0000000000000..1755d71662292 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Shapes/Connected.lean @@ -0,0 +1,35 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.CategoryTheory.IsConnected +import Mathlib.CategoryTheory.Limits.Shapes.WidePullbacks + +/-! + +# Connected shapes + +In this file we prove that various shapes are connected. + +-/ + +namespace CategoryTheory + +open Limits + +instance {J} : IsConnected (WidePullbackShape J) := by + apply IsConnected.of_constant_of_preserves_morphisms + intros α F H + suffices ∀ i, F i = F none from fun j j' ↦ (this j).trans (this j').symm + rintro ⟨⟩ + exacts [rfl, H (.term _)] + +instance {J} : IsConnected (WidePushoutShape J) := by + apply IsConnected.of_constant_of_preserves_morphisms + intros α F H + suffices ∀ i, F i = F none from fun j j' ↦ (this j).trans (this j').symm + rintro ⟨⟩ + exacts [rfl, (H (.init _)).symm] + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Shapes/End.lean b/Mathlib/CategoryTheory/Limits/Shapes/End.lean new file mode 100644 index 0000000000000..adb6b6d7c0166 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Shapes/End.lean @@ -0,0 +1,147 @@ +/- +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.Limits.Shapes.Multiequalizer + +/-! +# Ends and coends + +In this file, given a functor `F : Jᵒᵖ ⥤ J ⥤ C`, we define its end `end_ F`, +which is a suitable multiequalizer of the objects `(F.obj (op j)).obj j` for all `j : J`. +For this shape of limits, cones are named wedges: the corresponding type is `Wedge F`. + +## References +* https://ncatlab.org/nlab/show/end + +## TODO + +* define coends + +-/ + +universe v v' u u' + +namespace CategoryTheory + +open Opposite + +namespace Limits + +variable {J : Type u} [Category.{v} J] {C : Type u'} [Category.{v'} C] + (F : Jᵒᵖ ⥤ J ⥤ C) + +/-- Given `F : Jᵒᵖ ⥤ J ⥤ C`, this is the multicospan index which shall be used +to define the end of `F`. -/ +@[simps] +def multicospanIndexEnd : MulticospanIndex C where + L := J + R := Arrow J + fstTo f := f.left + sndTo f := f.right + left j := (F.obj (op j)).obj j + right f := (F.obj (op f.left)).obj f.right + fst f := (F.obj (op f.left)).map f.hom + snd f := (F.map f.hom.op).app f.right + +/-- Given `F : Jᵒᵖ ⥤ J ⥤ C`, a wedge for `F` is a type of cones (specifically +the type of multiforks for `multicospanIndexEnd F`): +the point of universal of these wedges shall be the end of `F`. -/ +abbrev Wedge := Multifork (multicospanIndexEnd F) + +namespace Wedge + +variable {F} + +section Constructor + +variable (pt : C) (π : ∀ (j : J), pt ⟶ (F.obj (op j)).obj j) + (hπ : ∀ ⦃i j : J⦄ (f : i ⟶ j), π i ≫ (F.obj (op i)).map f = π j ≫ (F.map f.op).app j) + +/-- Constructor for wedges. -/ +@[simps! pt] +abbrev mk : Wedge F := + Multifork.ofι _ pt π (fun f ↦ hπ f.hom) + +@[simp] +lemma mk_ι (j : J) : (mk pt π hπ).ι j = π j := rfl + +end Constructor + +@[reassoc] +lemma condition (c : Wedge F) {i j : J} (f : i ⟶ j) : + c.ι i ≫ (F.obj (op i)).map f = c.ι j ≫ (F.map f.op).app j := + Multifork.condition c (Arrow.mk f) + +namespace IsLimit + +variable {c : Wedge F} (hc : IsLimit c) + +lemma hom_ext (hc : IsLimit c) {X : C} {f g : X ⟶ c.pt} (h : ∀ j, f ≫ c.ι j = g ≫ c.ι j) : + f = g := + Multifork.IsLimit.hom_ext hc h + +/-- Construct a morphism to the end from its universal property. -/ +def lift (hc : IsLimit c) {X : C} (f : ∀ j, X ⟶ (F.obj (op j)).obj j) + (hf : ∀ ⦃i j : J⦄ (g : i ⟶ j), f i ≫ (F.obj (op i)).map g = f j ≫ (F.map g.op).app j) : + X ⟶ c.pt := + Multifork.IsLimit.lift hc f (fun _ ↦ hf _) + +@[reassoc (attr := simp)] +lemma lift_ι (hc : IsLimit c) {X : C} (f : ∀ j, X ⟶ (F.obj (op j)).obj j) + (hf : ∀ ⦃i j : J⦄ (g : i ⟶ j), f i ≫ (F.obj (op i)).map g = f j ≫ (F.map g.op).app j) (j : J) : + lift hc f hf ≫ c.ι j = f j := by + apply IsLimit.fac + + +end IsLimit + +end Wedge + +section End + +/-- Given `F : Jᵒᵖ ⥤ J ⥤ C`, this property asserts the existence of the end of `F`. -/ +abbrev HasEnd := HasMultiequalizer (multicospanIndexEnd F) + +variable [HasEnd F] + +/-- The end of a functor `F : Jᵒᵖ ⥤ J ⥤ C`. -/ +noncomputable def end_ : C := multiequalizer (multicospanIndexEnd F) + +/-- Given `F : Jᵒᵖ ⥤ J ⥤ C`, this is the projection `end_ F ⟶ (F.obj (op j)).obj j` +for any `j : J`. -/ +noncomputable def end_.π (j : J) : end_ F ⟶ (F.obj (op j)).obj j := Multiequalizer.ι _ _ + +@[reassoc] +lemma end_.condition {i j : J} (f : i ⟶ j) : + π F i ≫ (F.obj (op i)).map f = π F j ≫ (F.map f.op).app j := by + apply Wedge.condition + +variable {F} + +@[ext] +lemma hom_ext {X : C} {f g : X ⟶ end_ F} (h : ∀ j, f ≫ end_.π F j = g ≫ end_.π F j) : + f = g := + Multiequalizer.hom_ext _ _ _ (fun _ ↦ h _) + +section + +variable {X : C} (f : ∀ j, X ⟶ (F.obj (op j)).obj j) + (hf : ∀ ⦃i j : J⦄ (g : i ⟶ j), f i ≫ (F.obj (op i)).map g = f j ≫ (F.map g.op).app j) + +/-- Constructor for morphisms to the end of a functor. -/ +noncomputable def end_.lift : X ⟶ end_ F := + Wedge.IsLimit.lift (limit.isLimit _) f hf + +@[reassoc (attr := simp)] +lemma end_.lift_π (j : J) : lift f hf ≫ π F j = f j := by + apply IsLimit.fac + +end + +end End + +end Limits + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean index 05a92677fd909..36a0a6e065433 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean @@ -494,8 +494,8 @@ def Fork.IsLimit.homIso {X Y : C} {f g : X ⟶ Y} {t : Fork f g} (ht : IsLimit t (Z ⟶ t.pt) ≃ { h : Z ⟶ X // h ≫ f = h ≫ g } where toFun k := ⟨k ≫ t.ι, by simp only [Category.assoc, t.condition]⟩ invFun h := (Fork.IsLimit.lift' ht _ h.prop).1 - left_inv k := Fork.IsLimit.hom_ext ht (Fork.IsLimit.lift' _ _ _).prop - right_inv h := Subtype.ext (Fork.IsLimit.lift' ht _ _).prop + left_inv _ := Fork.IsLimit.hom_ext ht (Fork.IsLimit.lift' _ _ _).prop + right_inv _ := Subtype.ext (Fork.IsLimit.lift' ht _ _).prop /-- The bijection of `Fork.IsLimit.homIso` is natural in `Z`. -/ theorem Fork.IsLimit.homIso_natural {X Y : C} {f g : X ⟶ Y} {t : Fork f g} (ht : IsLimit t) @@ -513,8 +513,8 @@ def Cofork.IsColimit.homIso {X Y : C} {f g : X ⟶ Y} {t : Cofork f g} (ht : IsC (t.pt ⟶ Z) ≃ { h : Y ⟶ Z // f ≫ h = g ≫ h } where toFun k := ⟨t.π ≫ k, by simp only [← Category.assoc, t.condition]⟩ invFun h := (Cofork.IsColimit.desc' ht _ h.prop).1 - left_inv k := Cofork.IsColimit.hom_ext ht (Cofork.IsColimit.desc' _ _ _).prop - right_inv h := Subtype.ext (Cofork.IsColimit.desc' ht _ _).prop + left_inv _ := Cofork.IsColimit.hom_ext ht (Cofork.IsColimit.desc' _ _ _).prop + right_inv _ := Subtype.ext (Cofork.IsColimit.desc' ht _ _).prop /-- The bijection of `Cofork.IsColimit.homIso` is natural in `Z`. -/ theorem Cofork.IsColimit.homIso_natural {X Y : C} {f g : X ⟶ Y} {t : Cofork f g} {Z Z' : C} @@ -719,7 +719,6 @@ variable {f g} noncomputable abbrev equalizer.lift {W : C} (k : W ⟶ X) (h : k ≫ f = k ≫ g) : W ⟶ equalizer f g := limit.lift (parallelPair f g) (Fork.ofι k h) --- Porting note (#10618): removed simp since simp can prove this and the reassoc version @[reassoc] theorem equalizer.lift_ι {W : C} (k : W ⟶ X) (h : k ≫ f = k ≫ g) : equalizer.lift k h ≫ equalizer.ι f g = k := @@ -767,7 +766,7 @@ def idFork (h : f = g) : Fork f g := /-- The identity on `X` is an equalizer of `(f, g)`, if `f = g`. -/ def isLimitIdFork (h : f = g) : IsLimit (idFork h) := - Fork.IsLimit.mk _ (fun s => Fork.ι s) (fun s => Category.comp_id _) fun s m h => by + Fork.IsLimit.mk _ (fun s => Fork.ι s) (fun _ => Category.comp_id _) fun s m h => by convert h exact (Category.comp_id _).symm @@ -850,7 +849,6 @@ noncomputable abbrev coequalizer.cofork : Cofork f g := theorem coequalizer.cofork_π : (coequalizer.cofork f g).π = coequalizer.π f g := rfl --- Porting note (#10618): simp can prove this, simp removed theorem coequalizer.cofork_ι_app_one : (coequalizer.cofork f g).ι.app one = coequalizer.π f g := rfl @@ -871,7 +869,6 @@ noncomputable abbrev coequalizer.desc {W : C} (k : Y ⟶ W) (h : f ≫ k = g ≫ coequalizer f g ⟶ W := colimit.desc (parallelPair f g) (Cofork.ofπ k h) --- Porting note (#10618): removing simp since simp can prove this and reassoc version @[reassoc] theorem coequalizer.π_desc {W : C} (k : Y ⟶ W) (h : f ≫ k = g ≫ k) : coequalizer.π f g ≫ coequalizer.desc k h = k := @@ -927,7 +924,7 @@ def idCofork (h : f = g) : Cofork f g := /-- The identity on `Y` is a coequalizer of `(f, g)`, where `f = g`. -/ def isColimitIdCofork (h : f = g) : IsColimit (idCofork h) := - Cofork.IsColimit.mk _ (fun s => Cofork.π s) (fun s => Category.id_comp _) fun s m h => by + Cofork.IsColimit.mk _ (fun s => Cofork.π s) (fun _ => Category.id_comp _) fun s m h => by convert h exact (Category.id_comp _).symm diff --git a/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean b/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean index 812d28171a0d8..14a8a0a386b6a 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean @@ -239,13 +239,14 @@ instance hasColimitsOfShape_widePushoutShape (J : Type) [Finite J] [HasFiniteWid /-- Finite wide pullbacks are finite limits, so if `C` has all finite limits, it also has finite wide pullbacks -/ -theorem hasFiniteWidePullbacks_of_hasFiniteLimits [HasFiniteLimits C] : HasFiniteWidePullbacks C := +instance (priority := 900) hasFiniteWidePullbacks_of_hasFiniteLimits [HasFiniteLimits C] : + HasFiniteWidePullbacks C := ⟨fun J _ => by cases nonempty_fintype J; exact HasFiniteLimits.out _⟩ /-- Finite wide pushouts are finite colimits, so if `C` has all finite colimits, it also has finite wide pushouts -/ -theorem hasFiniteWidePushouts_of_has_finite_limits [HasFiniteColimits C] : +instance (priority := 900) hasFiniteWidePushouts_of_has_finite_limits [HasFiniteColimits C] : HasFiniteWidePushouts C := ⟨fun J _ => by cases nonempty_fintype J; exact HasFiniteColimits.out _⟩ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Images.lean b/Mathlib/CategoryTheory/Limits/Shapes/Images.lean index 10e2d68009de0..fec3f30cad1ff 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Images.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Images.lean @@ -756,7 +756,7 @@ end HasImageMap section -variable (C) [Category.{v} C] [HasImages C] +variable (C) [HasImages C] /-- If a category `has_image_maps`, then all commutative squares induce morphisms on images. -/ class HasImageMaps : Prop where @@ -830,7 +830,7 @@ end StrongEpiMonoFactorisation section HasStrongEpiImages -variable (C) [Category.{v} C] [HasImages C] +variable (C) [HasImages C] /-- A category has strong epi images if it has all images and `factorThruImage f` is a strong epimorphism for all `f`. -/ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean b/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean new file mode 100644 index 0000000000000..7ceb4a6aeb551 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean @@ -0,0 +1,438 @@ +/- +Copyright (c) 2019 Kim Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison, Bhavik Mehta +-/ +import Mathlib.CategoryTheory.PEmpty +import Mathlib.CategoryTheory.Limits.IsLimit +import Mathlib.CategoryTheory.EpiMono +import Mathlib.CategoryTheory.Category.Preorder + +/-! +# Initial and terminal objects in a category. + +In this file we define the predicates `IsTerminal` and `IsInitial` as well as the class +`InitialMonoClass`. + +The classes `HasTerminal` and `HasInitial` and the associated notations for terminal and inital +objects are defined in `Terminal.lean`. + +## References +* [Stacks: Initial and final objects](https://stacks.math.columbia.edu/tag/002B) +-/ + +assert_not_exists CategoryTheory.Limits.HasLimit + +noncomputable section + +universe w w' v v₁ v₂ u u₁ u₂ + +open CategoryTheory + +namespace CategoryTheory.Limits + +variable {C : Type u₁} [Category.{v₁} C] + +/-- Construct a cone for the empty diagram given an object. -/ +@[simps] +def asEmptyCone (X : C) : Cone (Functor.empty.{0} C) := + { pt := X + π := + { app := by aesop_cat } } + +/-- Construct a cocone for the empty diagram given an object. -/ +@[simps] +def asEmptyCocone (X : C) : Cocone (Functor.empty.{0} C) := + { pt := X + ι := + { app := by aesop_cat } } + +/-- `X` is terminal if the cone it induces on the empty diagram is limiting. -/ +abbrev IsTerminal (X : C) := + IsLimit (asEmptyCone X) + +/-- `X` is initial if the cocone it induces on the empty diagram is colimiting. -/ +abbrev IsInitial (X : C) := + IsColimit (asEmptyCocone X) + +/-- An object `Y` is terminal iff for every `X` there is a unique morphism `X ⟶ Y`. -/ +def isTerminalEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (Y : C) : + IsLimit (⟨Y, by aesop_cat, by aesop_cat⟩ : Cone F) ≃ ∀ X : C, Unique (X ⟶ Y) where + toFun t X := + { default := t.lift ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ + uniq := fun f => + t.uniq ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ f (by aesop_cat) } + invFun u := + { lift := fun s => (u s.pt).default + uniq := fun s _ _ => (u s.pt).2 _ } + left_inv := by dsimp [Function.LeftInverse]; intro x; simp only [eq_iff_true_of_subsingleton] + right_inv := by + dsimp [Function.RightInverse,Function.LeftInverse] + intro u; funext X; simp only + +/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y` + (as an instance). -/ +def IsTerminal.ofUnique (Y : C) [h : ∀ X : C, Unique (X ⟶ Y)] : IsTerminal Y where + lift s := (h s.pt).default + fac := fun _ ⟨j⟩ => j.elim + +/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y` + (as explicit arguments). -/ +def IsTerminal.ofUniqueHom {Y : C} (h : ∀ X : C, X ⟶ Y) (uniq : ∀ (X : C) (m : X ⟶ Y), m = h X) : + IsTerminal Y := + have : ∀ X : C, Unique (X ⟶ Y) := fun X ↦ ⟨⟨h X⟩, uniq X⟩ + IsTerminal.ofUnique Y + +/-- If `α` is a preorder with top, then `⊤` is a terminal object. -/ +def isTerminalTop {α : Type*} [Preorder α] [OrderTop α] : IsTerminal (⊤ : α) := + IsTerminal.ofUnique _ + +/-- Transport a term of type `IsTerminal` across an isomorphism. -/ +def IsTerminal.ofIso {Y Z : C} (hY : IsTerminal Y) (i : Y ≅ Z) : IsTerminal Z := + IsLimit.ofIsoLimit hY + { hom := { hom := i.hom } + inv := { hom := i.inv } } + +/-- If `X` and `Y` are isomorphic, then `X` is terminal iff `Y` is. -/ +def IsTerminal.equivOfIso {X Y : C} (e : X ≅ Y) : + IsTerminal X ≃ IsTerminal Y where + toFun h := IsTerminal.ofIso h e + invFun h := IsTerminal.ofIso h e.symm + left_inv _ := Subsingleton.elim _ _ + right_inv _ := Subsingleton.elim _ _ + +/-- An object `X` is initial iff for every `Y` there is a unique morphism `X ⟶ Y`. -/ +def isInitialEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (X : C) : + IsColimit (⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ : Cocone F) ≃ ∀ Y : C, Unique (X ⟶ Y) where + toFun t X := + { default := t.desc ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ + uniq := fun f => t.uniq ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ f (by aesop_cat) } + invFun u := + { desc := fun s => (u s.pt).default + uniq := fun s _ _ => (u s.pt).2 _ } + left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] + right_inv := by + dsimp [Function.RightInverse,Function.LeftInverse] + intro; funext; simp only + +/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y` + (as an instance). -/ +def IsInitial.ofUnique (X : C) [h : ∀ Y : C, Unique (X ⟶ Y)] : IsInitial X where + desc s := (h s.pt).default + fac := fun _ ⟨j⟩ => j.elim + +/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y` + (as explicit arguments). -/ +def IsInitial.ofUniqueHom {X : C} (h : ∀ Y : C, X ⟶ Y) (uniq : ∀ (Y : C) (m : X ⟶ Y), m = h Y) : + IsInitial X := + have : ∀ Y : C, Unique (X ⟶ Y) := fun Y ↦ ⟨⟨h Y⟩, uniq Y⟩ + IsInitial.ofUnique X + +/-- If `α` is a preorder with bot, then `⊥` is an initial object. -/ +def isInitialBot {α : Type*} [Preorder α] [OrderBot α] : IsInitial (⊥ : α) := + IsInitial.ofUnique _ + +/-- Transport a term of type `is_initial` across an isomorphism. -/ +def IsInitial.ofIso {X Y : C} (hX : IsInitial X) (i : X ≅ Y) : IsInitial Y := + IsColimit.ofIsoColimit hX + { hom := { hom := i.hom } + inv := { hom := i.inv } } + +/-- If `X` and `Y` are isomorphic, then `X` is initial iff `Y` is. -/ +def IsInitial.equivOfIso {X Y : C} (e : X ≅ Y) : + IsInitial X ≃ IsInitial Y where + toFun h := IsInitial.ofIso h e + invFun h := IsInitial.ofIso h e.symm + left_inv _ := Subsingleton.elim _ _ + right_inv _ := Subsingleton.elim _ _ + +/-- Give the morphism to a terminal object from any other. -/ +def IsTerminal.from {X : C} (t : IsTerminal X) (Y : C) : Y ⟶ X := + t.lift (asEmptyCone Y) + +/-- Any two morphisms to a terminal object are equal. -/ +theorem IsTerminal.hom_ext {X Y : C} (t : IsTerminal X) (f g : Y ⟶ X) : f = g := + IsLimit.hom_ext t (by aesop_cat) + +@[simp] +theorem IsTerminal.comp_from {Z : C} (t : IsTerminal Z) {X Y : C} (f : X ⟶ Y) : + f ≫ t.from Y = t.from X := + t.hom_ext _ _ + +@[simp] +theorem IsTerminal.from_self {X : C} (t : IsTerminal X) : t.from X = 𝟙 X := + t.hom_ext _ _ + +/-- Give the morphism from an initial object to any other. -/ +def IsInitial.to {X : C} (t : IsInitial X) (Y : C) : X ⟶ Y := + t.desc (asEmptyCocone Y) + +/-- Any two morphisms from an initial object are equal. -/ +theorem IsInitial.hom_ext {X Y : C} (t : IsInitial X) (f g : X ⟶ Y) : f = g := + IsColimit.hom_ext t (by aesop_cat) + +@[simp] +theorem IsInitial.to_comp {X : C} (t : IsInitial X) {Y Z : C} (f : Y ⟶ Z) : t.to Y ≫ f = t.to Z := + t.hom_ext _ _ + +@[simp] +theorem IsInitial.to_self {X : C} (t : IsInitial X) : t.to X = 𝟙 X := + t.hom_ext _ _ + +/-- Any morphism from a terminal object is split mono. -/ +theorem IsTerminal.isSplitMono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : IsSplitMono f := + IsSplitMono.mk' ⟨t.from _, t.hom_ext _ _⟩ + +/-- Any morphism to an initial object is split epi. -/ +theorem IsInitial.isSplitEpi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : IsSplitEpi f := + IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩ + +/-- Any morphism from a terminal object is mono. -/ +theorem IsTerminal.mono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : Mono f := by + haveI := t.isSplitMono_from f; infer_instance + +/-- Any morphism to an initial object is epi. -/ +theorem IsInitial.epi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : Epi f := by + haveI := t.isSplitEpi_to f; infer_instance + +/-- If `T` and `T'` are terminal, they are isomorphic. -/ +@[simps] +def IsTerminal.uniqueUpToIso {T T' : C} (hT : IsTerminal T) (hT' : IsTerminal T') : T ≅ T' where + hom := hT'.from _ + inv := hT.from _ + +/-- If `I` and `I'` are initial, they are isomorphic. -/ +@[simps] +def IsInitial.uniqueUpToIso {I I' : C} (hI : IsInitial I) (hI' : IsInitial I') : I ≅ I' where + hom := hI.to _ + inv := hI'.to _ + +variable (C) + +section Univ + +variable (X : C) {F₁ : Discrete.{w} PEmpty ⥤ C} {F₂ : Discrete.{w'} PEmpty ⥤ C} + +/-- Being terminal is independent of the empty diagram, its universe, and the cone over it, + as long as the cone points are isomorphic. -/ +def isLimitChangeEmptyCone {c₁ : Cone F₁} (hl : IsLimit c₁) (c₂ : Cone F₂) (hi : c₁.pt ≅ c₂.pt) : + IsLimit c₂ where + lift c := hl.lift ⟨c.pt, by aesop_cat, by aesop_cat⟩ ≫ hi.hom + uniq c f _ := by + dsimp + rw [← hl.uniq _ (f ≫ hi.inv) _] + · simp only [Category.assoc, Iso.inv_hom_id, Category.comp_id] + · aesop_cat + +/-- Replacing an empty cone in `IsLimit` by another with the same cone point + is an equivalence. -/ +def isLimitEmptyConeEquiv (c₁ : Cone F₁) (c₂ : Cone F₂) (h : c₁.pt ≅ c₂.pt) : + IsLimit c₁ ≃ IsLimit c₂ where + toFun hl := isLimitChangeEmptyCone C hl c₂ h + invFun hl := isLimitChangeEmptyCone C hl c₁ h.symm + left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] + right_inv := by + dsimp [Function.LeftInverse,Function.RightInverse]; intro + simp only [eq_iff_true_of_subsingleton] + +/-- Being initial is independent of the empty diagram, its universe, and the cocone over it, + as long as the cocone points are isomorphic. -/ +def isColimitChangeEmptyCocone {c₁ : Cocone F₁} (hl : IsColimit c₁) (c₂ : Cocone F₂) + (hi : c₁.pt ≅ c₂.pt) : IsColimit c₂ where + desc c := hi.inv ≫ hl.desc ⟨c.pt, by aesop_cat, by aesop_cat⟩ + uniq c f _ := by + dsimp + rw [← hl.uniq _ (hi.hom ≫ f) _] + · simp only [Iso.inv_hom_id_assoc] + · aesop_cat + +/-- Replacing an empty cocone in `IsColimit` by another with the same cocone point + is an equivalence. -/ +def isColimitEmptyCoconeEquiv (c₁ : Cocone F₁) (c₂ : Cocone F₂) (h : c₁.pt ≅ c₂.pt) : + IsColimit c₁ ≃ IsColimit c₂ where + toFun hl := isColimitChangeEmptyCocone C hl c₂ h + invFun hl := isColimitChangeEmptyCocone C hl c₁ h.symm + left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] + right_inv := by + dsimp [Function.LeftInverse,Function.RightInverse]; intro + simp only [eq_iff_true_of_subsingleton] + +end Univ + +section + +variable {C} + +/-- An initial object is terminal in the opposite category. -/ +def terminalOpOfInitial {X : C} (t : IsInitial X) : IsTerminal (Opposite.op X) where + lift s := (t.to s.pt.unop).op + uniq _ _ _ := Quiver.Hom.unop_inj (t.hom_ext _ _) + +/-- An initial object in the opposite category is terminal in the original category. -/ +def terminalUnopOfInitial {X : Cᵒᵖ} (t : IsInitial X) : IsTerminal X.unop where + lift s := (t.to (Opposite.op s.pt)).unop + uniq _ _ _ := Quiver.Hom.op_inj (t.hom_ext _ _) + +/-- A terminal object is initial in the opposite category. -/ +def initialOpOfTerminal {X : C} (t : IsTerminal X) : IsInitial (Opposite.op X) where + desc s := (t.from s.pt.unop).op + uniq _ _ _ := Quiver.Hom.unop_inj (t.hom_ext _ _) + +/-- A terminal object in the opposite category is initial in the original category. -/ +def initialUnopOfTerminal {X : Cᵒᵖ} (t : IsTerminal X) : IsInitial X.unop where + desc s := (t.from (Opposite.op s.pt)).unop + uniq _ _ _ := Quiver.Hom.op_inj (t.hom_ext _ _) + +/-- A category is an `InitialMonoClass` if the canonical morphism of an initial object is a +monomorphism. In practice, this is most useful when given an arbitrary morphism out of the chosen +initial object, see `initial.mono_from`. +Given a terminal object, this is equivalent to the assumption that the unique morphism from initial +to terminal is a monomorphism, which is the second of Freyd's axioms for an AT category. + +TODO: This is a condition satisfied by categories with zero objects and morphisms. +-/ +class InitialMonoClass (C : Type u₁) [Category.{v₁} C] : Prop where + /-- The map from the (any as stated) initial object to any other object is a + monomorphism -/ + isInitial_mono_from : ∀ {I} (X : C) (hI : IsInitial I), Mono (hI.to X) + +theorem IsInitial.mono_from [InitialMonoClass C] {I} {X : C} (hI : IsInitial I) (f : I ⟶ X) : + Mono f := by + rw [hI.hom_ext f (hI.to X)] + apply InitialMonoClass.isInitial_mono_from + +/-- To show a category is an `InitialMonoClass` it suffices to give an initial object such that +every morphism out of it is a monomorphism. -/ +theorem InitialMonoClass.of_isInitial {I : C} (hI : IsInitial I) (h : ∀ X, Mono (hI.to X)) : + InitialMonoClass C where + isInitial_mono_from {I'} X hI' := by + rw [hI'.hom_ext (hI'.to X) ((hI'.uniqueUpToIso hI).hom ≫ hI.to X)] + apply mono_comp + +/-- To show a category is an `InitialMonoClass` it suffices to show the unique morphism from an +initial object to a terminal object is a monomorphism. -/ +theorem InitialMonoClass.of_isTerminal {I T : C} (hI : IsInitial I) (hT : IsTerminal T) + (_ : Mono (hI.to T)) : InitialMonoClass C := + InitialMonoClass.of_isInitial hI fun X => mono_of_mono_fac (hI.hom_ext (_ ≫ hT.from X) (hI.to T)) + +section Comparison + +variable {D : Type u₂} [Category.{v₂} D] (G : C ⥤ D) + +end Comparison + +variable {J : Type u} [Category.{v} J] + +/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cone for `J`. +In `limitOfDiagramInitial` we show it is a limit cone. -/ +@[simps] +def coneOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : Cone F where + pt := F.obj X + π := + { app := fun j => F.map (tX.to j) + naturality := fun j j' k => by + dsimp + rw [← F.map_comp, Category.id_comp, tX.hom_ext (tX.to j ≫ k) (tX.to j')] } + +/-- From a functor `F : J ⥤ C`, given an initial object of `J`, show the cone +`coneOfDiagramInitial` is a limit. -/ +def limitOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : + IsLimit (coneOfDiagramInitial tX F) where + lift s := s.π.app X + uniq s m w := by + conv_lhs => dsimp + simp_rw [← w X, coneOfDiagramInitial_π_app, tX.hom_ext (tX.to X) (𝟙 _)] + simp + +/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cone for `J`, +provided that the morphisms in the diagram are isomorphisms. +In `limitOfDiagramTerminal` we show it is a limit cone. -/ +@[simps] +def coneOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) + [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cone F where + pt := F.obj X + π := + { app := fun _ => inv (F.map (hX.from _)) + naturality := by + intro i j f + dsimp + simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.id_comp, ← F.map_comp, + hX.hom_ext (hX.from i) (f ≫ hX.from j)] } + +/-- From a functor `F : J ⥤ C`, given a terminal object of `J` and that the morphisms in the +diagram are isomorphisms, show the cone `coneOfDiagramTerminal` is a limit. -/ +def limitOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) + [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsLimit (coneOfDiagramTerminal hX F) where + lift S := S.π.app _ + +/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cocone for `J`. +In `colimitOfDiagramTerminal` we show it is a colimit cocone. -/ +@[simps] +def coconeOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : Cocone F where + pt := F.obj X + ι := + { app := fun j => F.map (tX.from j) + naturality := fun j j' k => by + dsimp + rw [← F.map_comp, Category.comp_id, tX.hom_ext (k ≫ tX.from j') (tX.from j)] } + +/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, show the cocone +`coconeOfDiagramTerminal` is a colimit. -/ +def colimitOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : + IsColimit (coconeOfDiagramTerminal tX F) where + desc s := s.ι.app X + uniq s m w := by + conv_rhs => dsimp -- Porting note: why do I need this much firepower? + rw [← w X, coconeOfDiagramTerminal_ι_app, tX.hom_ext (tX.from X) (𝟙 _)] + simp + +lemma IsColimit.isIso_ι_app_of_isTerminal {F : J ⥤ C} {c : Cocone F} (hc : IsColimit c) + (X : J) (hX : IsTerminal X) : + IsIso (c.ι.app X) := by + change IsIso (coconePointUniqueUpToIso (colimitOfDiagramTerminal hX F) hc).hom + infer_instance + +/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cocone for `J`, +provided that the morphisms in the diagram are isomorphisms. +In `colimitOfDiagramInitial` we show it is a colimit cocone. -/ +@[simps] +def coconeOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) + [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cocone F where + pt := F.obj X + ι := + { app := fun _ => inv (F.map (hX.to _)) + naturality := by + intro i j f + dsimp + simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.comp_id, ← F.map_comp, + hX.hom_ext (hX.to i ≫ f) (hX.to j)] } + +/-- From a functor `F : J ⥤ C`, given an initial object of `J` and that the morphisms in the +diagram are isomorphisms, show the cone `coconeOfDiagramInitial` is a colimit. -/ +def colimitOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) + [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsColimit (coconeOfDiagramInitial hX F) where + desc S := S.ι.app _ + +lemma IsLimit.isIso_π_app_of_isInitial {F : J ⥤ C} {c : Cone F} (hc : IsLimit c) + (X : J) (hX : IsInitial X) : + IsIso (c.π.app X) := by + change IsIso (conePointUniqueUpToIso hc (limitOfDiagramInitial hX F)).hom + infer_instance + +/-- Any morphism between terminal objects is an isomorphism. -/ +lemma isIso_of_isTerminal {X Y : C} (hX : IsTerminal X) (hY : IsTerminal Y) (f : X ⟶ Y) : + IsIso f := by + refine ⟨⟨IsTerminal.from hX Y, ?_⟩⟩ + simp only [IsTerminal.comp_from, IsTerminal.from_self, true_and] + apply IsTerminal.hom_ext hY + +/-- Any morphism between initial objects is an isomorphism. -/ +lemma isIso_of_isInitial {X Y : C} (hX : IsInitial X) (hY : IsInitial Y) (f : X ⟶ Y) : + IsIso f := by + refine ⟨⟨IsInitial.to hY X, ?_⟩⟩ + simp only [IsInitial.to_comp, IsInitial.to_self, and_true] + apply IsInitial.hom_ext hX + +end + +end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean index c05a2ec92eaab..f03cd551569a5 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean @@ -79,9 +79,8 @@ variable {f} @[reassoc (attr := simp)] theorem KernelFork.condition (s : KernelFork f) : Fork.ι s ≫ f = 0 := by - erw [Fork.condition, HasZeroMorphisms.comp_zero] + rw [Fork.condition, HasZeroMorphisms.comp_zero] --- Porting note (#10618): simp can prove this, removed simp tag theorem KernelFork.app_one (s : KernelFork f) : s.π.app one = 0 := by simp [Fork.app_one_eq_ι_comp_right] @@ -154,7 +153,7 @@ def KernelFork.IsLimit.ofι {W : C} (g : W ⟶ X) (eq : g ≫ f = 0) def KernelFork.IsLimit.ofι' {X Y K : C} {f : X ⟶ Y} (i : K ⟶ X) (w : i ≫ f = 0) (h : ∀ {A : C} (k : A ⟶ X) (_ : k ≫ f = 0), { l : A ⟶ K // l ≫ i = k}) [hi : Mono i] : IsLimit (KernelFork.ofι i w) := - ofι _ _ (fun {A} k hk => (h k hk).1) (fun {A} k hk => (h k hk).2) (fun {A} k hk m hm => by + ofι _ _ (fun {_} k hk => (h k hk).1) (fun {_} k hk => (h k hk).2) (fun {A} k hk m hm => by rw [← cancel_mono i, (h k hk).2, hm]) /-- Every kernel of `f` induces a kernel of `f ≫ g` if `g` is mono. -/ @@ -188,7 +187,7 @@ def KernelFork.IsLimit.ofId {X Y : C} (f : X ⟶ Y) (hf : f = 0) : /-- Any zero object identifies to the kernel of a given monomorphisms. -/ def KernelFork.IsLimit.ofMonoOfIsZero {X Y : C} {f : X ⟶ Y} (c : KernelFork f) (hf : Mono f) (h : IsZero c.pt) : IsLimit c := - isLimitAux _ (fun s => 0) (fun s => by rw [zero_comp, ← cancel_mono f, zero_comp, s.condition]) + isLimitAux _ (fun _ => 0) (fun s => by rw [zero_comp, ← cancel_mono f, zero_comp, s.condition]) (fun _ _ _ => h.eq_of_tgt _ _) lemma KernelFork.IsLimit.isIso_ι {X Y : C} {f : X ⟶ Y} (c : KernelFork f) @@ -429,13 +428,13 @@ open ZeroObject /-- The morphism from the zero object determines a cone on a kernel diagram -/ def kernel.zeroKernelFork : KernelFork f where pt := 0 - π := { app := fun j => 0 } + π := { app := fun _ => 0 } /-- The map from the zero object is a kernel of a monomorphism -/ def kernel.isLimitConeZeroCone [Mono f] : IsLimit (kernel.zeroKernelFork f) := - Fork.IsLimit.mk _ (fun s => 0) + Fork.IsLimit.mk _ (fun _ => 0) (fun s => by - erw [zero_comp] + rw [zero_comp] refine (zero_of_comp_mono f ?_).symm exact KernelFork.condition _) fun _ _ _ => zero_of_to_zero _ @@ -453,7 +452,7 @@ theorem kernel.ι_of_mono [HasKernel f] [Mono f] : kernel.ι f = 0 := def zeroKernelOfCancelZero {X Y : C} (f : X ⟶ Y) (hf : ∀ (Z : C) (g : Z ⟶ X) (_ : g ≫ f = 0), g = 0) : IsLimit (KernelFork.ofι (0 : 0 ⟶ X) (show 0 ≫ f = 0 by simp)) := - Fork.IsLimit.mk _ (fun s => 0) (fun s => by rw [hf _ _ (KernelFork.condition s), zero_comp]) + Fork.IsLimit.mk _ (fun _ => 0) (fun s => by rw [hf _ _ (KernelFork.condition s), zero_comp]) fun s m _ => by dsimp; apply HasZeroObject.to_zero_ext end HasZeroObject @@ -516,7 +515,6 @@ variable {f} theorem CokernelCofork.condition (s : CokernelCofork f) : f ≫ s.π = 0 := by rw [Cofork.condition, zero_comp] --- Porting note (#10618): simp can prove this, removed simp tag theorem CokernelCofork.π_eq_zero (s : CokernelCofork f) : s.ι.app zero = 0 := by simp [Cofork.app_zero_eq_comp_π_right] @@ -574,7 +572,7 @@ def CokernelCofork.IsColimit.ofπ {Z : C} (g : Y ⟶ Z) (eq : f ≫ g = 0) def CokernelCofork.IsColimit.ofπ' {X Y Q : C} {f : X ⟶ Y} (p : Y ⟶ Q) (w : f ≫ p = 0) (h : ∀ {A : C} (k : Y ⟶ A) (_ : f ≫ k = 0), { l : Q ⟶ A // p ≫ l = k}) [hp : Epi p] : IsColimit (CokernelCofork.ofπ p w) := - ofπ _ _ (fun {A} k hk => (h k hk).1) (fun {A} k hk => (h k hk).2) (fun {A} k hk m hm => by + ofπ _ _ (fun {_} k hk => (h k hk).1) (fun {_} k hk => (h k hk).2) (fun {A} k hk m hm => by rw [← cancel_epi p, (h k hk).2, hm]) /-- Every cokernel of `f` induces a cokernel of `g ≫ f` if `g` is epi. -/ @@ -620,7 +618,7 @@ def CokernelCofork.IsColimit.ofId {X Y : C} (f : X ⟶ Y) (hf : f = 0) : /-- Any zero object identifies to the cokernel of a given epimorphisms. -/ def CokernelCofork.IsColimit.ofEpiOfIsZero {X Y : C} {f : X ⟶ Y} (c : CokernelCofork f) (hf : Epi f) (h : IsZero c.pt) : IsColimit c := - isColimitAux _ (fun s => 0) (fun s => by rw [comp_zero, ← cancel_epi f, comp_zero, s.condition]) + isColimitAux _ (fun _ => 0) (fun s => by rw [comp_zero, ← cancel_epi f, comp_zero, s.condition]) (fun _ _ _ => h.eq_of_src _ _) lemma CokernelCofork.IsColimit.isIso_π {X Y : C} {f : X ⟶ Y} (c : CokernelCofork f) @@ -882,11 +880,11 @@ open ZeroObject /-- The morphism to the zero object determines a cocone on a cokernel diagram -/ def cokernel.zeroCokernelCofork : CokernelCofork f where pt := 0 - ι := { app := fun j => 0 } + ι := { app := fun _ => 0 } /-- The morphism to the zero object is a cokernel of an epimorphism -/ def cokernel.isColimitCoconeZeroCocone [Epi f] : IsColimit (cokernel.zeroCokernelCofork f) := - Cofork.IsColimit.mk _ (fun s => 0) + Cofork.IsColimit.mk _ (fun _ => 0) (fun s => by erw [zero_comp] refine (zero_of_epi_comp f ?_).symm @@ -978,7 +976,7 @@ instance cokernel.of_kernel_of_mono [HasKernel f] [HasCokernel (kernel.ι f)] [M def zeroCokernelOfZeroCancel {X Y : C} (f : X ⟶ Y) (hf : ∀ (Z : C) (g : Y ⟶ Z) (_ : f ≫ g = 0), g = 0) : IsColimit (CokernelCofork.ofπ (0 : Y ⟶ 0) (show f ≫ 0 = 0 by simp)) := - Cofork.IsColimit.mk _ (fun s => 0) + Cofork.IsColimit.mk _ (fun _ => 0) (fun s => by rw [hf _ _ (CokernelCofork.condition s), comp_zero]) fun s m _ => by apply HasZeroObject.from_zero_ext diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean b/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean index 3b1dc95db77ed..a8f12eea475ca 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean @@ -31,29 +31,29 @@ namespace CategoryTheory.Limits open CategoryTheory -universe w v u +universe w w' v u /-- The type underlying the multiequalizer diagram. -/ --@[nolint unused_arguments] -inductive WalkingMulticospan {L R : Type w} (fst snd : R → L) : Type w +inductive WalkingMulticospan {L : Type w} {R : Type w'} (fst snd : R → L) : Type max w w' | left : L → WalkingMulticospan fst snd | right : R → WalkingMulticospan fst snd /-- The type underlying the multiecoqualizer diagram. -/ --@[nolint unused_arguments] -inductive WalkingMultispan {L R : Type w} (fst snd : L → R) : Type w +inductive WalkingMultispan {L : Type w} {R : Type w'} (fst snd : L → R) : Type max w w' | left : L → WalkingMultispan fst snd | right : R → WalkingMultispan fst snd namespace WalkingMulticospan -variable {L R : Type w} {fst snd : R → L} +variable {L : Type w} {R : Type w'} {fst snd : R → L} instance [Inhabited L] : Inhabited (WalkingMulticospan fst snd) := ⟨left default⟩ /-- Morphisms for `WalkingMulticospan`. -/ -inductive Hom : ∀ _ _ : WalkingMulticospan fst snd, Type w +inductive Hom : ∀ _ _ : WalkingMulticospan fst snd, Type max w w' | id (A) : Hom A A | fst (b) : Hom (left (fst b)) (right b) | snd (b) : Hom (left (snd b)) (right b) @@ -94,13 +94,13 @@ end WalkingMulticospan namespace WalkingMultispan -variable {L R : Type v} {fst snd : L → R} +variable {L : Type w} {R : Type w'} {fst snd : L → R} instance [Inhabited L] : Inhabited (WalkingMultispan fst snd) := ⟨left default⟩ /-- Morphisms for `WalkingMultispan`. -/ -inductive Hom : ∀ _ _ : WalkingMultispan fst snd, Type v +inductive Hom : ∀ _ _ : WalkingMultispan fst snd, Type max w w' | id (A) : Hom A A | fst (a) : Hom (left a) (right (fst a)) | snd (a) : Hom (left a) (right (snd a)) @@ -139,10 +139,11 @@ lemma Hom.comp_eq_comp {X Y Z : WalkingMultispan fst snd} end WalkingMultispan /-- This is a structure encapsulating the data necessary to define a `Multicospan`. -/ --- Porting note(#5171): linter not ported yet --- @[nolint has_nonempty_instance] +-- Porting note(#5171): has_nonempty_instance linter not ported yet +@[nolint checkUnivs] structure MulticospanIndex (C : Type u) [Category.{v} C] where - (L R : Type w) + (L : Type w) + (R : Type w') (fstTo sndTo : R → L) left : L → C right : R → C @@ -150,10 +151,11 @@ structure MulticospanIndex (C : Type u) [Category.{v} C] where snd : ∀ b, left (sndTo b) ⟶ right b /-- This is a structure encapsulating the data necessary to define a `Multispan`. -/ --- Porting note(#5171): linter not ported yet --- @[nolint has_nonempty_instance] +-- Porting note(#5171): has_nonempty_instance linter not ported yet +@[nolint checkUnivs] structure MultispanIndex (C : Type u) [Category.{v} C] where - (L R : Type w) + (L : Type w) + (R : Type w') (fstFrom sndFrom : L → R) left : L → C right : R → C @@ -162,7 +164,7 @@ structure MultispanIndex (C : Type u) [Category.{v} C] where namespace MulticospanIndex -variable {C : Type u} [Category.{v} C] (I : MulticospanIndex.{w} C) +variable {C : Type u} [Category.{v} C] (I : MulticospanIndex.{w, w'} C) /-- The multicospan associated to `I : MulticospanIndex`. -/ @[simps] @@ -210,7 +212,7 @@ end MulticospanIndex namespace MultispanIndex -variable {C : Type u} [Category.{v} C] (I : MultispanIndex.{w} C) +variable {C : Type u} [Category.{v} C] (I : MultispanIndex.{w, w'} C) /-- The multispan associated to `I : MultispanIndex`. -/ def multispan : WalkingMultispan I.fstFrom I.sndFrom ⥤ C where @@ -276,18 +278,18 @@ variable {C : Type u} [Category.{v} C] /-- A multifork is a cone over a multicospan. -/ -- Porting note(#5171): linter not ported yet -- @[nolint has_nonempty_instance] -abbrev Multifork (I : MulticospanIndex.{w} C) := +abbrev Multifork (I : MulticospanIndex.{w, w'} C) := Cone I.multicospan /-- A multicofork is a cocone over a multispan. -/ -- Porting note(#5171): linter not ported yet -- @[nolint has_nonempty_instance] -abbrev Multicofork (I : MultispanIndex.{w} C) := +abbrev Multicofork (I : MultispanIndex.{w, w'} C) := Cocone I.multispan namespace Multifork -variable {I : MulticospanIndex.{w} C} (K : Multifork I) +variable {I : MulticospanIndex.{w, w'} C} (K : Multifork I) /-- The maps from the cone point of a multifork to the objects on the left. -/ def ι (a : I.L) : K.pt ⟶ I.left a := @@ -315,13 +317,13 @@ theorem hom_comp_ι (K₁ K₂ : Multifork I) (f : K₁ ⟶ K₂) (j : I.L) : f. /-- Construct a multifork using a collection `ι` of morphisms. -/ @[simps] -def ofι (I : MulticospanIndex.{w} C) (P : C) (ι : ∀ a, P ⟶ I.left a) +def ofι (I : MulticospanIndex.{w, w'} C) (P : C) (ι : ∀ a, P ⟶ I.left a) (w : ∀ b, ι (I.fstTo b) ≫ I.fst b = ι (I.sndTo b) ≫ I.snd b) : Multifork I where pt := P π := { app := fun x => match x with - | WalkingMulticospan.left a => ι _ + | WalkingMulticospan.left _ => ι _ | WalkingMulticospan.right b => ι (I.fstTo b) ≫ I.fst b naturality := by rintro (_ | _) (_ | _) (_ | _ | _) <;> @@ -415,8 +417,8 @@ noncomputable def ofPiFork (c : Fork I.fstPiMap I.sndPiMap) : Multifork I where π := { app := fun x => match x with - | WalkingMulticospan.left a => c.ι ≫ Pi.π _ _ - | WalkingMulticospan.right b => c.ι ≫ I.fstPiMap ≫ Pi.π _ _ + | WalkingMulticospan.left _ => c.ι ≫ Pi.π _ _ + | WalkingMulticospan.right _ => c.ι ≫ I.fstPiMap ≫ Pi.π _ _ naturality := by rintro (_ | _) (_ | _) (_ | _ | _) · simp @@ -438,7 +440,7 @@ end Multifork namespace MulticospanIndex -variable (I : MulticospanIndex.{w} C) [HasProduct I.left] [HasProduct I.right] +variable (I : MulticospanIndex.{w, w'} C) [HasProduct I.left] [HasProduct I.right] --attribute [local tidy] tactic.case_bash @@ -485,7 +487,7 @@ end MulticospanIndex namespace Multicofork -variable {I : MultispanIndex.{w} C} (K : Multicofork I) +variable {I : MultispanIndex.{w, w'} C} (K : Multicofork I) /-- The maps to the cocone point of a multicofork from the objects on the right. -/ def π (b : I.R) : I.right b ⟶ K.pt := @@ -511,14 +513,14 @@ lemma π_comp_hom (K₁ K₂ : Multicofork I) (f : K₁ ⟶ K₂) (b : I.R) : K /-- Construct a multicofork using a collection `π` of morphisms. -/ @[simps] -def ofπ (I : MultispanIndex.{w} C) (P : C) (π : ∀ b, I.right b ⟶ P) +def ofπ (I : MultispanIndex.{w, w'} C) (P : C) (π : ∀ b, I.right b ⟶ P) (w : ∀ a, I.fst a ≫ π (I.fstFrom a) = I.snd a ≫ π (I.sndFrom a)) : Multicofork I where pt := P ι := { app := fun x => match x with | WalkingMultispan.left a => I.fst a ≫ π _ - | WalkingMultispan.right b => π _ + | WalkingMultispan.right _ => π _ naturality := by rintro (_ | _) (_ | _) (_ | _ | _) <;> dsimp <;> simp only [Functor.map_id, MultispanIndex.multispan_obj_left, @@ -614,7 +616,7 @@ end Multicofork namespace MultispanIndex -variable (I : MultispanIndex.{w} C) [HasCoproduct I.left] [HasCoproduct I.right] +variable (I : MultispanIndex.{w, w'} C) [HasCoproduct I.left] [HasCoproduct I.right] --attribute [local tidy] tactic.case_bash @@ -662,7 +664,7 @@ noncomputable def multicoforkEquivSigmaCofork : counitIso := NatIso.ofComponents fun K => Cofork.ext (Iso.refl _) (by - -- Porting note: in mathlib3 this was just `ext` and I don't know why it's not here + -- Porting note (#11041): in mathlib3 this was just `ext` and I don't know why it's not here apply Limits.colimit.hom_ext rintro ⟨j⟩ dsimp @@ -673,27 +675,27 @@ end MultispanIndex /-- For `I : MulticospanIndex C`, we say that it has a multiequalizer if the associated multicospan has a limit. -/ -abbrev HasMultiequalizer (I : MulticospanIndex.{w} C) := +abbrev HasMultiequalizer (I : MulticospanIndex.{w, w'} C) := HasLimit I.multicospan noncomputable section /-- The multiequalizer of `I : MulticospanIndex C`. -/ -abbrev multiequalizer (I : MulticospanIndex.{w} C) [HasMultiequalizer I] : C := +abbrev multiequalizer (I : MulticospanIndex.{w, w'} C) [HasMultiequalizer I] : C := limit I.multicospan /-- For `I : MultispanIndex C`, we say that it has a multicoequalizer if the associated multicospan has a limit. -/ -abbrev HasMulticoequalizer (I : MultispanIndex.{w} C) := +abbrev HasMulticoequalizer (I : MultispanIndex.{w, w'} C) := HasColimit I.multispan /-- The multiecoqualizer of `I : MultispanIndex C`. -/ -abbrev multicoequalizer (I : MultispanIndex.{w} C) [HasMulticoequalizer I] : C := +abbrev multicoequalizer (I : MultispanIndex.{w, w'} C) [HasMulticoequalizer I] : C := colimit I.multispan namespace Multiequalizer -variable (I : MulticospanIndex.{w} C) [HasMultiequalizer I] +variable (I : MulticospanIndex.{w, w'} C) [HasMultiequalizer I] /-- The canonical map from the multiequalizer to the objects on the left. -/ abbrev ι (a : I.L) : multiequalizer I ⟶ I.left a := @@ -722,7 +724,7 @@ abbrev lift (W : C) (k : ∀ a, W ⟶ I.left a) (h : ∀ b, k (I.fstTo b) ≫ I.fst b = k (I.sndTo b) ≫ I.snd b) : W ⟶ multiequalizer I := limit.lift _ (Multifork.ofι I _ k h) -@[reassoc] -- Porting note (#10618): simp can prove this, removed attribute +@[reassoc] theorem lift_ι (W : C) (k : ∀ a, W ⟶ I.left a) (h : ∀ b, k (I.fstTo b) ≫ I.fst b = k (I.sndTo b) ≫ I.snd b) (a) : Multiequalizer.lift I _ k h ≫ Multiequalizer.ι I a = k _ := @@ -758,7 +760,7 @@ end Multiequalizer namespace Multicoequalizer -variable (I : MultispanIndex.{w} C) [HasMulticoequalizer I] +variable (I : MultispanIndex.{w, w'} C) [HasMulticoequalizer I] /-- The canonical map from the multiequalizer to the objects on the left. -/ abbrev π (b : I.R) : I.right b ⟶ multicoequalizer I := @@ -792,7 +794,7 @@ abbrev desc (W : C) (k : ∀ b, I.right b ⟶ W) (h : ∀ a, I.fst a ≫ k (I.fstFrom a) = I.snd a ≫ k (I.sndFrom a)) : multicoequalizer I ⟶ W := colimit.desc _ (Multicofork.ofπ I _ k h) -@[reassoc] -- Porting note (#10618): simp can prove this, removed attribute +@[reassoc] theorem π_desc (W : C) (k : ∀ b, I.right b ⟶ W) (h : ∀ a, I.fst a ≫ k (I.fstFrom a) = I.snd a ≫ k (I.sndFrom a)) (b) : Multicoequalizer.π I b ≫ Multicoequalizer.desc I _ k h = k _ := diff --git a/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Equalizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Equalizers.lean index c71d6af56f0d8..67d189d906d5d 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Equalizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/NormalMono/Equalizers.lean @@ -55,7 +55,7 @@ def pullback_of_mono {X Y Z : C} (a : X ⟶ Z) (b : Y ⟶ Z) [Mono a] [Mono b] : PullbackCone.IsLimit.mk _ (fun s => kernel.lift (prod.lift f g) (PullbackCone.snd s ≫ b) <| - prod.hom_ext + Limits.prod.hom_ext (calc ((PullbackCone.snd s ≫ b) ≫ prod.lift f g) ≫ Limits.prod.fst = PullbackCone.snd s ≫ b ≫ f := by simp only [prod.lift_fst, Category.assoc] @@ -125,7 +125,7 @@ def hasLimit_parallelPair {X Y : C} (f g : X ⟶ Y) : HasLimit (parallelPair f g Fork.IsLimit.mk _ (fun s => pullback.lift (Fork.ι s) (Fork.ι s) <| - prod.hom_ext (by simp only [prod.lift_fst, Category.assoc]) + Limits.prod.hom_ext (by simp only [prod.lift_fst, Category.assoc]) (by simp only [prod.comp_lift, Fork.condition s])) (fun s => by simp) fun s m h => pullback.hom_ext (by simpa only [pullback.lift_fst] using h) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean index aa816cb1ee4da..fd6ac675d5b40 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean @@ -245,6 +245,12 @@ theorem Pi.lift_π {β : Type w} {f : β → C} [HasProduct f] {P : C} (p : ∀ Pi.lift p ≫ Pi.π f b = p b := by simp only [limit.lift_π, Fan.mk_pt, Fan.mk_π_app] +/-- A version of `Cones.ext` for `Fan`s. -/ +@[simps!] +def Fan.ext {f : β → C} {c₁ c₂ : Fan f} (e : c₁.pt ≅ c₂.pt) + (w : ∀ (b : β), c₁.proj b = e.hom ≫ c₂.proj b := by aesop_cat) : c₁ ≅ c₂ := + Cones.ext e (fun ⟨j⟩ => w j) + /-- A collection of morphisms `f b ⟶ P` induces a morphism `∐ f ⟶ P`. -/ abbrev Sigma.desc {f : β → C} [HasCoproduct f] {P : C} (p : ∀ b, f b ⟶ P) : ∐ f ⟶ P := colimit.desc _ (Cofan.mk P p) @@ -661,11 +667,9 @@ theorem hasProducts_of_limit_fans (lf : ∀ {J : Type w} (f : J → C), Fan f) section Unique -variable [Unique β] (f : β → C) - /-- The limit cone for the product over an index type with exactly one term. -/ @[simps] -def limitConeOfUnique : LimitCone (Discrete.functor f) where +def limitConeOfUnique [Unique β] (f : β → C) : LimitCone (Discrete.functor f) where cone := { pt := f default π := Discrete.natTrans (fun ⟨j⟩ => eqToHom (by @@ -682,17 +686,18 @@ def limitConeOfUnique : LimitCone (Discrete.functor f) where specialize w default simpa using w } -instance (priority := 100) hasProduct_unique : HasProduct f := - HasLimit.mk (limitConeOfUnique f) +instance (priority := 100) hasProduct_unique [Nonempty β] [Subsingleton β] (f : β → C) : + HasProduct f := + let ⟨_⟩ := nonempty_unique β; HasLimit.mk (limitConeOfUnique f) /-- A product over an index type with exactly one term is just the object over that term. -/ @[simps!] -def productUniqueIso : ∏ᶜ f ≅ f default := +def productUniqueIso [Unique β] (f : β → C) : ∏ᶜ f ≅ f default := IsLimit.conePointUniqueUpToIso (limit.isLimit _) (limitConeOfUnique f).isLimit /-- The colimit cocone for the coproduct over an index type with exactly one term. -/ @[simps] -def colimitCoconeOfUnique : ColimitCocone (Discrete.functor f) where +def colimitCoconeOfUnique [Unique β] (f : β → C) : ColimitCocone (Discrete.functor f) where cocone := { pt := f default ι := Discrete.natTrans (fun ⟨j⟩ => eqToHom (by @@ -710,12 +715,13 @@ def colimitCoconeOfUnique : ColimitCocone (Discrete.functor f) where erw [Category.id_comp] at w exact w } -instance (priority := 100) hasCoproduct_unique : HasCoproduct f := - HasColimit.mk (colimitCoconeOfUnique f) +instance (priority := 100) hasCoproduct_unique [Nonempty β] [Subsingleton β] (f : β → C) : + HasCoproduct f := + let ⟨_⟩ := nonempty_unique β; HasColimit.mk (colimitCoconeOfUnique f) /-- A coproduct over an index type with exactly one term is just the object over that term. -/ @[simps!] -def coproductUniqueIso : ∐ f ≅ f default := +def coproductUniqueIso [Unique β] (f : β → C) : ∐ f ≅ f default := IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) (colimitCoconeOfUnique f).isColimit end Unique diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean index 541f09bc26155..795528a7feb85 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean @@ -21,7 +21,7 @@ universe w v₁ v₂ v u u₂ namespace CategoryTheory.Limits -variable {C : Type u} [Category.{v} C] {W X Y Z : C} +variable {C : Type u} [Category.{v} C] section PullbackAssoc diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean index 423fed53f4080..ff8b0b942c59c 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean @@ -3,12 +3,9 @@ Copyright (c) 2022 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison, Joël Riou, Calle Sönne -/ -import Mathlib.CategoryTheory.CommSq -import Mathlib.CategoryTheory.Limits.Opposites -import Mathlib.CategoryTheory.Limits.Shapes.Biproducts -import Mathlib.CategoryTheory.Limits.Shapes.ZeroMorphisms -import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts + import Mathlib.CategoryTheory.Limits.Constructions.ZeroObjects +import Mathlib.CategoryTheory.Limits.Shapes.Biproducts import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Pasting /-! @@ -23,7 +20,7 @@ We provide another API for pullbacks and pushouts. snd f | | v v - Y ---g---> Zfst + Y ---g---> Z ``` is a pullback square. @@ -231,6 +228,13 @@ theorem of_isLimit' (w : CommSq fst snd f g) (h : Limits.IsLimit w.cone) : IsPullback fst snd f g := of_isLimit h +/-- Variant of `of_isLimit` for an arbitrary cone on a diagram `WalkingCospan ⥤ C`. -/ +lemma of_isLimit_cone {D : WalkingCospan ⥤ C} {c : Cone D} (hc : IsLimit c) : + IsPullback (c.π.app .left) (c.π.app .right) (D.map WalkingCospan.Hom.inl) + (D.map WalkingCospan.Hom.inr) where + w := by simp_rw [Cone.w] + isLimit' := ⟨IsLimit.equivOfNatIsoOfIso _ _ _ (PullbackCone.isoMk c) hc⟩ + /-- The pullback provided by `HasPullback f g` fits into an `IsPullback`. -/ theorem of_hasPullback (f : X ⟶ Z) (g : Y ⟶ Z) [HasPullback f g] : IsPullback (pullback.fst f g) (pullback.snd f g) f g := @@ -270,7 +274,7 @@ theorem of_hasBinaryProduct [HasBinaryProduct X Y] [HasZeroObject C] [HasZeroMor section -variable {P': C} {fst' : P' ⟶ X} {snd' : P' ⟶ Y} +variable {P' : C} {fst' : P' ⟶ X} {snd' : P' ⟶ Y} /-- Any object at the top left of a pullback square is isomorphic to the object at the top left of any other pullback square with the same cospan. -/ @@ -362,6 +366,18 @@ lemma of_iso (h : IsPullback fst snd f g) rw [← reassoc_of% commfst, e₂.hom_inv_id, Category.comp_id] · change snd = e₁.hom ≫ snd' ≫ e₃.inv rw [← reassoc_of% commsnd, e₃.hom_inv_id, Category.comp_id]))⟩ +section + +variable {P X Y : C} {fst : P ⟶ X} {snd : P ⟶ X} {f : X ⟶ Y} [Mono f] + +lemma isIso_fst_of_mono (h : IsPullback fst snd f f) : IsIso fst := + h.cone.isIso_fst_of_mono_of_isLimit h.isLimit + +lemma isIso_snd_iso_of_mono {P X Y : C} {fst : P ⟶ X} {snd : P ⟶ X} {f : X ⟶ Y} [Mono f] + (h : IsPullback fst snd f f) : IsIso snd := + h.cone.isIso_snd_of_mono_of_isLimit h.isLimit + +end end IsPullback @@ -419,6 +435,13 @@ theorem of_isColimit' (w : CommSq f g inl inr) (h : Limits.IsColimit w.cocone) : IsPushout f g inl inr := of_isColimit h +/-- Variant of `of_isColimit` for an arbitrary cocone on a diagram `WalkingSpan ⥤ C`. -/ +lemma of_isColimit_cocone {D : WalkingSpan ⥤ C} {c : Cocone D} (hc : IsColimit c) : + IsPushout (D.map WalkingSpan.Hom.fst) (D.map WalkingSpan.Hom.snd) + (c.ι.app .left) (c.ι.app .right) where + w := by simp_rw [Cocone.w] + isColimit' := ⟨IsColimit.equivOfNatIsoOfIso _ _ _ (PushoutCocone.isoMk c) hc⟩ + /-- The pushout provided by `HasPushout f g` fits into an `IsPushout`. -/ theorem of_hasPushout (f : Z ⟶ X) (g : Z ⟶ Y) [HasPushout f g] : IsPushout f g (pushout.inl f g) (pushout.inr f g) := @@ -540,6 +563,18 @@ lemma of_iso (h : IsPushout f g inl inr) (IsColimit.ofIsoColimit h.isColimit (PushoutCocone.ext e₄ comminl comminr))⟩ +section + +variable {P X Y : C} {inl : X ⟶ P} {inr : X ⟶ P} {f : Y ⟶ X} [Epi f] + +lemma isIso_inl_iso_of_epi (h : IsPushout f f inl inr) : IsIso inl := + h.cocone.isIso_inl_of_epi_of_isColimit h.isColimit + +lemma isIso_inr_iso_of_epi (h : IsPushout f f inl inr) : IsIso inr := + h.cocone.isIso_inr_of_epi_of_isColimit h.isColimit + +end + end IsPushout namespace IsPullback @@ -563,7 +598,7 @@ open ZeroObject theorem zero_left (X : C) : IsPullback (0 : 0 ⟶ X) (0 : (0 : C) ⟶ 0) (𝟙 X) (0 : 0 ⟶ X) := { w := by simp isLimit' := - ⟨{ lift := fun s => 0 + ⟨{ lift := fun _ => 0 fac := fun s => by simpa [eq_iff_true_of_subsingleton] using @PullbackCone.equalizer_ext _ _ _ _ _ _ _ s _ 0 (𝟙 _) @@ -865,7 +900,7 @@ open ZeroObject theorem zero_right (X : C) : IsPushout (0 : X ⟶ 0) (𝟙 X) (0 : (0 : C) ⟶ 0) (0 : X ⟶ 0) := { w := by simp isColimit' := - ⟨{ desc := fun s => 0 + ⟨{ desc := fun _ => 0 fac := fun s => by have c := @PushoutCocone.coequalizer_ext _ _ _ _ _ _ _ s _ 0 (𝟙 _) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Equalizer.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Equalizer.lean new file mode 100644 index 0000000000000..acd890c5e85aa --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Equalizer.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq + +/-! +# Equalizers as pullbacks of products + +Also see `CategoryTheory.Limits.Constructions.Equalizers` for very similar results. + +-/ + +universe v u + +namespace CategoryTheory.Limits + +variable {C : Type u} [Category.{v} C] {X Y : C} (f g : X ⟶ Y) + +/-- The equalizer of `f g : X ⟶ Y` is the pullback of the diagonal map `Y ⟶ Y × Y` +along the map `(f, g) : X ⟶ Y × Y`. -/ +lemma isPullback_equalizer_prod [HasEqualizer f g] [HasBinaryProduct Y Y] : + IsPullback (equalizer.ι f g) (equalizer.ι f g ≫ f) (prod.lift f g) (prod.lift (𝟙 _) (𝟙 _)) := by + refine ⟨⟨by ext <;> simp [equalizer.condition f g]⟩, ⟨PullbackCone.IsLimit.mk _ ?_ ?_ ?_ ?_⟩⟩ + · refine fun s ↦ equalizer.lift s.fst ?_ + have H₁ : s.fst ≫ f = s.snd := by simpa using congr($s.condition ≫ prod.fst) + have H₂ : s.fst ≫ g = s.snd := by simpa using congr($s.condition ≫ prod.snd) + exact H₁.trans H₂.symm + · exact fun s ↦ by simp + · exact fun s ↦ by simpa using congr($s.condition ≫ prod.fst) + · exact fun s m hm _ ↦ by ext; simp [*] + +/-- The coequalizer of `f g : X ⟶ Y` is the pushout of the diagonal map `X ⨿ X ⟶ X` +along the map `(f, g) : X ⨿ X ⟶ Y`. -/ +lemma isPushout_coequalizer_coprod [HasCoequalizer f g] [HasBinaryCoproduct X X] : + IsPushout (coprod.desc f g) (coprod.desc (𝟙 _) (𝟙 _)) + (coequalizer.π f g) (f ≫ coequalizer.π f g) := by + refine ⟨⟨by ext <;> simp [coequalizer.condition f g]⟩, ⟨PushoutCocone.IsColimit.mk _ ?_ ?_ ?_ ?_⟩⟩ + · refine fun s ↦ coequalizer.desc s.inl ?_ + have H₁ : f ≫ s.inl = s.inr := by simpa using congr(coprod.inl ≫ $s.condition) + have H₂ : g ≫ s.inl = s.inr := by simpa using congr(coprod.inr ≫ $s.condition) + exact H₁.trans H₂.symm + · exact fun s ↦ by simp + · exact fun s ↦ by simpa using congr(coprod.inl ≫ $s.condition) + · exact fun s m hm _ ↦ by ext; simp [*] + +end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean index f6455c517bc0b..7a97bde56f6a0 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean @@ -150,33 +150,27 @@ theorem PullbackCone.fst_limit_cone {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) [Has theorem PullbackCone.snd_limit_cone {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) [HasLimit (cospan f g)] : PullbackCone.snd (limit.cone (cospan f g)) = pullback.snd f g := rfl --- Porting note (#10618): simp can prove this; removed simp theorem PushoutCocone.inl_colimit_cocone {X Y Z : C} (f : Z ⟶ X) (g : Z ⟶ Y) [HasColimit (span f g)] : PushoutCocone.inl (colimit.cocone (span f g)) = pushout.inl _ _ := rfl --- Porting note (#10618): simp can prove this; removed simp theorem PushoutCocone.inr_colimit_cocone {X Y Z : C} (f : Z ⟶ X) (g : Z ⟶ Y) [HasColimit (span f g)] : PushoutCocone.inr (colimit.cocone (span f g)) = pushout.inr _ _ := rfl --- Porting note (#10618): simp can prove this and reassoced version; removed simp @[reassoc] theorem pullback.lift_fst {W X Y Z : C} {f : X ⟶ Z} {g : Y ⟶ Z} [HasPullback f g] (h : W ⟶ X) (k : W ⟶ Y) (w : h ≫ f = k ≫ g) : pullback.lift h k w ≫ pullback.fst f g = h := limit.lift_π _ _ --- Porting note (#10618): simp can prove this and reassoced version; removed simp @[reassoc] theorem pullback.lift_snd {W X Y Z : C} {f : X ⟶ Z} {g : Y ⟶ Z} [HasPullback f g] (h : W ⟶ X) (k : W ⟶ Y) (w : h ≫ f = k ≫ g) : pullback.lift h k w ≫ pullback.snd f g = k := limit.lift_π _ _ --- Porting note (#10618): simp can prove this and reassoced version; removed simp @[reassoc] theorem pushout.inl_desc {W X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} [HasPushout f g] (h : Y ⟶ W) (k : Z ⟶ W) (w : f ≫ h = g ≫ k) : pushout.inl _ _ ≫ pushout.desc h k w = h := colimit.ι_desc _ _ --- Porting note (#10618): simp can prove this and reassoced version; removed simp @[reassoc] theorem pushout.inr_desc {W X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} [HasPushout f g] (h : Y ⟶ W) (k : Z ⟶ W) (w : f ≫ h = g ≫ k) : pushout.inr _ _ ≫ pushout.desc h k w = k := diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean index 3007f243e923c..e55cb3b880356 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean @@ -42,7 +42,6 @@ theorem pullbackConeOfLeftIso_fst : (pullbackConeOfLeftIso f g).fst = g ≫ inv @[simp] theorem pullbackConeOfLeftIso_snd : (pullbackConeOfLeftIso f g).snd = 𝟙 _ := rfl --- Porting note (#10618): simp can prove this; removed simp theorem pullbackConeOfLeftIso_π_app_none : (pullbackConeOfLeftIso f g).π.app none = g := by simp @[simp] @@ -93,7 +92,6 @@ theorem pullbackConeOfRightIso_fst : (pullbackConeOfRightIso f g).fst = 𝟙 _ : @[simp] theorem pullbackConeOfRightIso_snd : (pullbackConeOfRightIso f g).snd = f ≫ inv g := rfl --- Porting note (#10618): simp can prove this; removed simps theorem pullbackConeOfRightIso_π_app_none : (pullbackConeOfRightIso f g).π.app none = f := by simp @[simp] @@ -145,7 +143,6 @@ theorem pushoutCoconeOfLeftIso_inl : (pushoutCoconeOfLeftIso f g).inl = inv f @[simp] theorem pushoutCoconeOfLeftIso_inr : (pushoutCoconeOfLeftIso f g).inr = 𝟙 _ := rfl --- Porting note (#10618): simp can prove this; removed simp theorem pushoutCoconeOfLeftIso_ι_app_none : (pushoutCoconeOfLeftIso f g).ι.app none = g := by simp @@ -197,7 +194,6 @@ theorem pushoutCoconeOfRightIso_inl : (pushoutCoconeOfRightIso f g).inl = 𝟙 _ @[simp] theorem pushoutCoconeOfRightIso_inr : (pushoutCoconeOfRightIso f g).inr = inv g ≫ f := rfl --- Porting note (#10618): simp can prove this; removed simp theorem pushoutCoconeOfRightIso_ι_app_none : (pushoutCoconeOfRightIso f g).ι.app none = f := by simp diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean index 5393b03bb61a3..5b6bfbf8ab8b4 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean @@ -62,7 +62,7 @@ The pullback cone `(𝟙 X, 𝟙 X)` for the pair `(f, f)` is a limit if `f` is shown in `mono_of_pullback_is_id`. -/ def isLimitMkIdId (f : X ⟶ Y) [Mono f] : IsLimit (mk (𝟙 X) (𝟙 X) rfl : PullbackCone f f) := - IsLimit.mk _ (fun s => s.fst) (fun s => Category.comp_id _) + IsLimit.mk _ (fun s => s.fst) (fun _ => Category.comp_id _) (fun s => by rw [← cancel_mono f, Category.comp_id, s.condition]) fun s m m₁ _ => by simpa using m₁ @@ -191,30 +191,42 @@ section open WalkingCospan -variable (f : X ⟶ Y) +variable (f : X ⟶ Y) [Mono f] -instance has_kernel_pair_of_mono [Mono f] : HasPullback f f := +instance has_kernel_pair_of_mono : HasPullback f f := ⟨⟨⟨_, PullbackCone.isLimitMkIdId f⟩⟩⟩ -theorem fst_eq_snd_of_mono_eq [Mono f] : pullback.fst f f = pullback.snd f f := - ((PullbackCone.isLimitMkIdId f).fac (getLimitCone (cospan f f)).cone left).symm.trans - ((PullbackCone.isLimitMkIdId f).fac (getLimitCone (cospan f f)).cone right : _) +theorem PullbackCone.fst_eq_snd_of_mono_eq {f : X ⟶ Y} [Mono f] (t : PullbackCone f f) : + t.fst = t.snd := + (cancel_mono f).1 t.condition + +theorem fst_eq_snd_of_mono_eq : pullback.fst f f = pullback.snd f f := + PullbackCone.fst_eq_snd_of_mono_eq (getLimitCone (cospan f f)).cone @[simp] -theorem pullbackSymmetry_hom_of_mono_eq [Mono f] : (pullbackSymmetry f f).hom = 𝟙 _ := by +theorem pullbackSymmetry_hom_of_mono_eq : (pullbackSymmetry f f).hom = 𝟙 _ := by ext · simp [fst_eq_snd_of_mono_eq] · simp [fst_eq_snd_of_mono_eq] -instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst f f) := by - refine ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), ?_, by simp⟩⟩ - ext +variable {f} in +lemma PullbackCone.isIso_fst_of_mono_of_isLimit {t : PullbackCone f f} (ht : IsLimit t) : + IsIso t.fst := by + refine ⟨⟨PullbackCone.IsLimit.lift ht (𝟙 _) (𝟙 _) (by simp), ?_, by simp⟩⟩ + apply PullbackCone.IsLimit.hom_ext ht · simp · simp [fst_eq_snd_of_mono_eq] -instance snd_iso_of_mono_eq [Mono f] : IsIso (pullback.snd f f) := - fst_eq_snd_of_mono_eq f ▸ fst_iso_of_mono_eq f +variable {f} in +lemma PullbackCone.isIso_snd_of_mono_of_isLimit {t : PullbackCone f f} (ht : IsLimit t) : + IsIso t.snd := + t.fst_eq_snd_of_mono_eq ▸ t.isIso_fst_of_mono_of_isLimit ht + +instance isIso_fst_of_mono : IsIso (pullback.fst f f) := + PullbackCone.isIso_fst_of_mono_of_isLimit (getLimitCone (cospan f f)).isLimit +instance isIso_snd_of_mono : IsIso (pullback.snd f f) := + PullbackCone.isIso_snd_of_mono_of_isLimit (getLimitCone (cospan f f)).isLimit end namespace PushoutCocone @@ -234,7 +246,7 @@ The pushout cocone `(𝟙 X, 𝟙 X)` for the pair `(f, f)` is a colimit if `f` shown in `epi_of_isColimit_mk_id_id`. -/ def isColimitMkIdId (f : X ⟶ Y) [Epi f] : IsColimit (mk (𝟙 Y) (𝟙 Y) rfl : PushoutCocone f f) := - IsColimit.mk _ (fun s => s.inl) (fun s => Category.id_comp _) + IsColimit.mk _ (fun s => s.inl) (fun _ => Category.id_comp _) (fun s => by rw [← cancel_epi f, Category.id_comp, s.condition]) fun s m m₁ _ => by simpa using m₁ @@ -357,27 +369,40 @@ section open WalkingSpan -variable (f : X ⟶ Y) +variable (f : X ⟶ Y) [Epi f] -instance has_cokernel_pair_of_epi [Epi f] : HasPushout f f := +instance has_cokernel_pair_of_epi : HasPushout f f := ⟨⟨⟨_, PushoutCocone.isColimitMkIdId f⟩⟩⟩ -theorem inl_eq_inr_of_epi_eq [Epi f] : (pushout.inl _ _ : _ ⟶ pushout f f) = pushout.inr _ _ := - ((PushoutCocone.isColimitMkIdId f).fac (getColimitCocone (span f f)).cocone left).symm.trans - ((PushoutCocone.isColimitMkIdId f).fac (getColimitCocone (span f f)).cocone right : _) +theorem PushoutCocone.inl_eq_inr_of_epi_eq {f : X ⟶ Y} [Epi f] (t : PushoutCocone f f) : + t.inl = t.inr := + (cancel_epi f).1 t.condition + +theorem inl_eq_inr_of_epi_eq : pushout.inl f f = pushout.inr f f := + PushoutCocone.inl_eq_inr_of_epi_eq (getColimitCocone (span f f)).cocone @[simp] -theorem pullback_symmetry_hom_of_epi_eq [Epi f] : (pushoutSymmetry f f).hom = 𝟙 _ := by +theorem pullback_symmetry_hom_of_epi_eq : (pushoutSymmetry f f).hom = 𝟙 _ := by ext <;> simp [inl_eq_inr_of_epi_eq] -instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl _ _ : _ ⟶ pushout f f) := by - refine ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by simp, ?_⟩⟩ - apply pushout.hom_ext +variable {f} in +lemma PushoutCocone.isIso_inl_of_epi_of_isColimit {t : PushoutCocone f f} (ht : IsColimit t) : + IsIso t.inl := by + refine ⟨⟨PushoutCocone.IsColimit.desc ht (𝟙 _) (𝟙 _) (by simp), by simp, ?_⟩⟩ + apply PushoutCocone.IsColimit.hom_ext ht · simp · simp [inl_eq_inr_of_epi_eq] -instance inr_iso_of_epi_eq [Epi f] : IsIso (pushout.inr f f) := - inl_eq_inr_of_epi_eq f ▸ inl_iso_of_epi_eq f +variable {f} in +lemma PushoutCocone.isIso_inr_of_epi_of_isColimit {t : PushoutCocone f f} (ht : IsColimit t) : + IsIso t.inr := + t.inl_eq_inr_of_epi_eq ▸ t.isIso_inl_of_epi_of_isColimit ht + +instance isIso_inl_of_epi : IsIso (pushout.inl f f) := + PushoutCocone.isIso_inl_of_epi_of_isColimit (getColimitCocone (span f f)).isColimit + +instance isIso_inr_of_epi : IsIso (pushout.inr f f) := + PushoutCocone.isIso_inr_of_epi_of_isColimit (getColimitCocone (span f f)).isColimit end diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean b/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean index 7a9ccc2d5140d..abcc9d116cda0 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean @@ -1,29 +1,52 @@ /- Copyright (c) 2020 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Bhavik Mehta +Authors: Bhavik Mehta, Robin Carlier -/ +import Mathlib.CategoryTheory.Limits.Final import Mathlib.CategoryTheory.Limits.Shapes.Equalizers import Mathlib.CategoryTheory.Limits.Shapes.KernelPair /-! # Reflexive coequalizers -We define reflexive pairs as a pair of morphisms which have a common section. We say a category has -reflexive coequalizers if it has coequalizers of all reflexive pairs. -Reflexive coequalizers often enjoy nicer properties than general coequalizers, and feature heavily -in some versions of the monadicity theorem. +This file deals with reflexive pairs, which are pairs of morphisms with a common section. + +A reflexive coequalizer is a coequalizer of such a pair. These kind of coequalizers often enjoy +nicer properties than general coequalizers, and feature heavily in some versions of the monadicity +theorem. We also give some examples of reflexive pairs: for an adjunction `F ⊣ G` with counit `ε`, the pair `(FGε_B, ε_FGB)` is reflexive. If a pair `f,g` is a kernel pair for some morphism, then it is reflexive. +## Main definitions + +* `IsReflexivePair` is the predicate that f and g have a common section. +* `WalkingReflexivePair` is the diagram indexing pairs with a common section. +* A `reflexiveCofork` is a cocone on a diagram indexed by `WalkingReflexivePair`. +* `WalkingReflexivePair.inclusionWalkingReflexivePair` is the inclustion functor from + `WalkingParallelPair` to `WalkingReflexivePair`. It acts on reflexive pairs as forgetting + the common section. +* `HasReflexiveCoequalizers` is the predicate that a category has all colimits of reflexive pairs. +* `reflexiveCoequalizerIsoCoequalizer`: an isomorphism promoting the coequalizer of a reflexive pair + to the colimit of a diagram out of the walking reflexive pair. + +## Main statements + +* `IsKernelPair.isReflexivePair`: A kernel pair is a reflexive pair +* `WalkingParallelPair.inclusionWalkingReflexivePair_final`: The inclusion functor is final. +* `hasReflexiveCoequalizers_iff`: A category has coequalizers of reflexive pairs if and only iff it + has all colimits of shape `WalkingReflexivePair`. + # TODO * If `C` has binary coproducts and reflexive coequalizers, then it has all coequalizers. * If `T` is a monad on cocomplete category `C`, then `Algebra T` is cocomplete iff it has reflexive coequalizers. * If `C` is locally cartesian closed and has reflexive coequalizers, then it has images: in fact regular epi (and hence strong epi) images. +* Bundle the reflexive pairs of kernel pairs and of adjunction as functors out of the walking + reflexive pair. -/ @@ -148,6 +171,481 @@ instance (priority := 100) hasCoreflexiveEqualizers_of_hasEqualizers [HasEqualiz end Limits -open Limits +end CategoryTheory + +namespace CategoryTheory + +universe v v₂ u u₂ + +namespace Limits + +/-- The type of objects for the diagram indexing reflexive (co)equalizers -/ +inductive WalkingReflexivePair : Type where + | zero + | one + deriving DecidableEq, Inhabited + +open WalkingReflexivePair + +namespace WalkingReflexivePair + +/-- The type of morphisms for the diagram indexing reflexive (co)equalizers -/ +inductive Hom : (WalkingReflexivePair → WalkingReflexivePair → Type) + | left : Hom one zero + | right : Hom one zero + | reflexion : Hom zero one + | leftCompReflexion : Hom one one + | rightCompReflexion : Hom one one + | id (X : WalkingReflexivePair) : Hom X X + deriving DecidableEq + +attribute [-simp, nolint simpNF] Hom.id.sizeOf_spec +attribute [-simp, nolint simpNF] Hom.leftCompReflexion.sizeOf_spec +attribute [-simp, nolint simpNF] Hom.rightCompReflexion.sizeOf_spec + +/-- Composition of morphisms in the diagram indexing reflexive (co)equalizers -/ +def Hom.comp : + ∀ { X Y Z : WalkingReflexivePair } (_ : Hom X Y) + (_ : Hom Y Z), Hom X Z + | _, _, _, id _, h => h + | _, _, _, h, id _ => h + | _, _, _, reflexion, left => id zero + | _, _, _, reflexion, right => id zero + | _, _, _, reflexion, rightCompReflexion => reflexion + | _, _, _, reflexion, leftCompReflexion => reflexion + | _, _, _, left, reflexion => leftCompReflexion + | _, _, _, right, reflexion => rightCompReflexion + | _, _, _, rightCompReflexion, rightCompReflexion => rightCompReflexion + | _, _, _, rightCompReflexion, leftCompReflexion => rightCompReflexion + | _, _, _, rightCompReflexion, right => right + | _, _, _, rightCompReflexion, left => right + | _, _, _, leftCompReflexion, left => left + | _, _, _, leftCompReflexion, right => left + | _, _, _, leftCompReflexion, rightCompReflexion => leftCompReflexion + | _, _, _, leftCompReflexion, leftCompReflexion => leftCompReflexion + +instance category : SmallCategory WalkingReflexivePair where + Hom := Hom + id := Hom.id + comp := Hom.comp + comp_id := by intro _ _ f; cases f <;> rfl + id_comp := by intro _ _ f; cases f <;> rfl + assoc := by intro _ _ _ _ f g h; cases f <;> cases g <;> cases h <;> rfl + +open Hom + +@[simp] +lemma Hom.id_eq (X : WalkingReflexivePair) : + Hom.id X = 𝟙 X := by rfl + +@[reassoc (attr := simp)] +lemma reflexion_comp_left : reflexion ≫ left = 𝟙 zero := rfl + +@[reassoc (attr := simp)] +lemma reflexion_comp_right : reflexion ≫ right = 𝟙 zero := rfl + +@[simp] +lemma leftCompReflexion_eq : leftCompReflexion = (left ≫ reflexion : one ⟶ one) := rfl + +@[simp] +lemma rightCompReflexion_eq : rightCompReflexion = (right ≫ reflexion : one ⟶ one) := rfl + +section FunctorsOutOfWalkingReflexivePair + +variable {C : Type u} [Category.{v} C] + +@[reassoc (attr := simp)] +lemma map_reflexion_comp_map_left (F : WalkingReflexivePair ⥤ C) : + F.map reflexion ≫ F.map left = 𝟙 (F.obj zero) := by + rw [← F.map_comp, reflexion_comp_left, F.map_id] + +@[reassoc (attr := simp)] +lemma map_reflexion_comp_map_right (F : WalkingReflexivePair ⥤ C) : + F.map reflexion ≫ F.map right = 𝟙 (F.obj zero) := by + rw [← F.map_comp, reflexion_comp_right, F.map_id] + +end FunctorsOutOfWalkingReflexivePair + +end WalkingReflexivePair + +namespace WalkingParallelPair + +/-- The inclusion functor forgetting the common section -/ +@[simps!] +def inclusionWalkingReflexivePair : WalkingParallelPair ⥤ WalkingReflexivePair where + obj := fun x => match x with + | one => WalkingReflexivePair.zero + | zero => WalkingReflexivePair.one + map := fun f => match f with + | .left => WalkingReflexivePair.Hom.left + | .right => WalkingReflexivePair.Hom.right + | .id _ => WalkingReflexivePair.Hom.id _ + map_comp := by + intro _ _ _ f g; cases f <;> cases g <;> rfl + +variable {C : Type u} [Category.{v} C] + +instance (X : WalkingReflexivePair) : + Nonempty (StructuredArrow X inclusionWalkingReflexivePair) := by + cases X with + | zero => exact ⟨StructuredArrow.mk (Y := one) (𝟙 _)⟩ + | one => exact ⟨StructuredArrow.mk (Y := zero) (𝟙 _)⟩ + +open WalkingReflexivePair.Hom in +instance (X : WalkingReflexivePair) : + IsConnected (StructuredArrow X inclusionWalkingReflexivePair) := by + cases X with + | zero => + refine IsConnected.of_induct (j₀ := StructuredArrow.mk (Y := one) (𝟙 _)) ?_ + rintro p h₁ h₂ ⟨⟨⟨⟩⟩, (_ | _), ⟨_⟩⟩ + · exact (h₂ (StructuredArrow.homMk .left)).2 h₁ + · exact h₁ + | one => + refine IsConnected.of_induct (j₀ := StructuredArrow.mk (Y := zero) (𝟙 _)) + (fun p h₁ h₂ ↦ ?_) + have hₗ : StructuredArrow.mk left ∈ p := (h₂ (StructuredArrow.homMk .left)).1 h₁ + have hᵣ : StructuredArrow.mk right ∈ p := (h₂ (StructuredArrow.homMk .right)).1 h₁ + rintro ⟨⟨⟨⟩⟩, (_ | _), ⟨_⟩⟩ + · exact (h₂ (StructuredArrow.homMk .left)).2 hₗ + · exact (h₂ (StructuredArrow.homMk .right)).2 hᵣ + all_goals assumption + +/-- The inclusion functor is a final functor -/ +instance inclusionWalkingReflexivePair_final : Functor.Final inclusionWalkingReflexivePair where + out := inferInstance + +end WalkingParallelPair + +end Limits + +namespace Limits + +open WalkingReflexivePair + +variable {C : Type u} [Category.{v} C] + +variable {A B : C} + +/-- Bundle the data of a parallel pair along with a common section as a functor out of the walking +reflexive pair -/ +def reflexivePair (f g : A ⟶ B) (s : B ⟶ A) + (sl : s ≫ f = 𝟙 B := by aesop_cat) (sr : s ≫ g = 𝟙 B := by aesop_cat) : + (WalkingReflexivePair ⥤ C) where + obj x := + match x with + | zero => B + | one => A + map h := + match h with + | .id _ => 𝟙 _ + | .left => f + | .right => g + | .reflexion => s + | .rightCompReflexion => g ≫ s + | .leftCompReflexion => f ≫ s + map_comp := by + rintro _ _ _ ⟨⟩ g <;> cases g <;> + simp only [Category.id_comp, Category.comp_id, Category.assoc, sl, sr, + reassoc_of% sl, reassoc_of% sr] <;> rfl + +section + +variable {A B : C} +variable (f g : A ⟶ B) (s : B ⟶ A) {sl : s ≫ f = 𝟙 B} {sr : s ≫ g = 𝟙 B} + +@[simp] lemma reflexivePair_obj_zero : (reflexivePair f g s sl sr).obj zero = B := rfl + +@[simp] lemma reflexivePair_obj_one : (reflexivePair f g s sl sr).obj one = A := rfl + +@[simp] lemma reflexivePair_map_right : (reflexivePair f g s sl sr).map .left = f := rfl + +@[simp] lemma reflexivePair_map_left : (reflexivePair f g s sl sr).map .right = g := rfl + +@[simp] lemma reflexivePair_map_reflexion : (reflexivePair f g s sl sr).map .reflexion = s := rfl + +end + +/-- (Noncomputably) bundle the data of a reflexive pair as a functor out of the walking reflexive +pair -/ +noncomputable def ofIsReflexivePair (f g : A ⟶ B) [IsReflexivePair f g] : + WalkingReflexivePair ⥤ C := reflexivePair f g (commonSection f g) + +@[simp] +lemma ofIsReflexivePair_map_left (f g : A ⟶ B) [IsReflexivePair f g] : + (ofIsReflexivePair f g).map .left = f := rfl + +@[simp] +lemma ofIsReflexivePair_map_right (f g : A ⟶ B) [IsReflexivePair f g] : + (ofIsReflexivePair f g).map .right = g := rfl + +/-- The natural isomorphism between the diagram obtained by forgetting the reflexion of +`ofIsReflexivePair f g` and the original parallel pair. -/ +noncomputable def inclusionWalkingReflexivePairOfIsReflexivePairIso + (f g : A ⟶ B) [IsReflexivePair f g] : + WalkingParallelPair.inclusionWalkingReflexivePair ⋙ (ofIsReflexivePair f g) ≅ + parallelPair f g := + diagramIsoParallelPair _ + +end Limits + +namespace Limits + +variable {C : Type u} [Category.{v} C] + +namespace reflexivePair + +open WalkingReflexivePair WalkingReflexivePair.Hom + +section +section NatTrans + +variable {F G : WalkingReflexivePair ⥤ C} + (e₀ : F.obj zero ⟶ G.obj zero) (e₁ : F.obj one ⟶ G.obj one) + (h₁ : F.map left ≫ e₀ = e₁ ≫ G.map left := by aesop_cat) + (h₂ : F.map right ≫ e₀ = e₁ ≫ G.map right := by aesop_cat) + (h₃ : F.map reflexion ≫ e₁ = e₀ ≫ G.map reflexion := by aesop_cat) + +/-- A constructor for natural transformations between functors from `WalkingReflexivePair`. -/ +def mkNatTrans : F ⟶ G where + app := fun x ↦ match x with + | zero => e₀ + | one => e₁ + naturality _ _ f := by + cases f + all_goals + dsimp + simp only [Functor.map_id, Category.id_comp, Category.comp_id, + Functor.map_comp, h₁, h₂, h₃, reassoc_of% h₁, reassoc_of% h₂, + reflexivePair_map_reflexion, reflexivePair_map_left, reflexivePair_map_right, + Category.assoc] + +@[simp] +lemma mkNatTrans_app_zero : (mkNatTrans e₀ e₁ h₁ h₂ h₃).app zero = e₀ := rfl + +@[simp] +lemma mkNatTrans_app_one : (mkNatTrans e₀ e₁ h₁ h₂ h₃).app one = e₁ := rfl + +end NatTrans +section NatIso + +variable {F G : WalkingReflexivePair ⥤ C} +/-- Constructor for natural isomorphisms between functors out of `WalkingReflexivePair`. -/ +@[simps!] +def mkNatIso (e₀ : F.obj zero ≅ G.obj zero) (e₁ : F.obj one ≅ G.obj one) + (h₁ : F.map left ≫ e₀.hom = e₁.hom ≫ G.map left := by aesop_cat) + (h₂ : F.map right ≫ e₀.hom = e₁.hom ≫ G.map right := by aesop_cat) + (h₃ : F.map reflexion ≫ e₁.hom = e₀.hom ≫ G.map reflexion := by aesop_cat) : + F ≅ G where + hom := mkNatTrans e₀.hom e₁.hom + inv := mkNatTrans e₀.inv e₁.inv + (by rw [← cancel_epi e₁.hom, e₁.hom_inv_id_assoc, ← reassoc_of% h₁, e₀.hom_inv_id, + Category.comp_id]) + (by rw [← cancel_epi e₁.hom, e₁.hom_inv_id_assoc, ← reassoc_of% h₂, e₀.hom_inv_id, + Category.comp_id]) + (by rw [← cancel_epi e₀.hom, e₀.hom_inv_id_assoc, ← reassoc_of% h₃, e₁.hom_inv_id, + Category.comp_id]) + hom_inv_id := by ext x; cases x <;> simp + inv_hom_id := by ext x; cases x <;> simp + +variable (F) + +/-- Every functor out of `WalkingReflexivePair` is isomorphic to the `reflexivePair` given by +its components -/ +@[simps!] +def diagramIsoReflexivePair : + F ≅ reflexivePair (F.map left) (F.map right) (F.map reflexion) := + mkNatIso (Iso.refl _) (Iso.refl _) + +end NatIso + +/-- A `reflexivePair` composed with a functor is isomorphic to the `reflexivePair` obtained by +applying the functor at each map. -/ +@[simps!] +def compRightIso {D : Type u₂} [Category.{v₂} D] {A B : C} + (f g : A ⟶ B) (s : B ⟶ A) (sl : s ≫ f = 𝟙 B) (sr : s ≫ g = 𝟙 B) (F : C ⥤ D) : + (reflexivePair f g s sl sr) ⋙ F ≅ reflexivePair (F.map f) (F.map g) (F.map s) + (by simp only [← Functor.map_comp, sl, Functor.map_id]) + (by simp only [← Functor.map_comp, sr, Functor.map_id]) := + mkNatIso (Iso.refl _) (Iso.refl _) + +lemma whiskerRightMkNatTrans {F G : WalkingReflexivePair ⥤ C} + (e₀ : F.obj zero ⟶ G.obj zero) (e₁ : F.obj one ⟶ G.obj one) + {h₁ : F.map left ≫ e₀ = e₁ ≫ G.map left} + {h₂ : F.map right ≫ e₀ = e₁ ≫ G.map right} + {h₃ : F.map reflexion ≫ e₁ = e₀ ≫ G.map reflexion} + {D : Type u₂} [Category.{v₂} D] (H : C ⥤ D) : + whiskerRight (mkNatTrans e₀ e₁ : F ⟶ G) H = + mkNatTrans (H.map e₀) (H.map e₁) + (by simp only [Functor.comp_obj, Functor.comp_map, ← Functor.map_comp, h₁]) + (by simp only [Functor.comp_obj, Functor.comp_map, ← Functor.map_comp, h₂]) + (by simp only [Functor.comp_obj, Functor.comp_map, ← Functor.map_comp, h₃]) := by + ext x; cases x <;> simp + +end + +/-- Any functor out of the WalkingReflexivePair yields a reflexive pair -/ +instance to_isReflexivePair {F : WalkingReflexivePair ⥤ C} : + IsReflexivePair (F.map .left) (F.map .right) := + ⟨F.map .reflexion, map_reflexion_comp_map_left F, map_reflexion_comp_map_right F⟩ + +end reflexivePair + +/-- A `ReflexiveCofork` is a cocone over a `WalkingReflexivePair`-shaped diagram. -/ +abbrev ReflexiveCofork (F : WalkingReflexivePair ⥤ C) := Cocone F + +namespace ReflexiveCofork + +open WalkingReflexivePair WalkingReflexivePair.Hom + +variable {F : WalkingReflexivePair ⥤ C} + +/-- The tail morphism of a reflexive cofork. -/ +abbrev π (G : ReflexiveCofork F) : F.obj zero ⟶ G.pt := G.ι.app zero + +/-- Constructor for `ReflexiveCofork` -/ +@[simps pt] +def mk {X : C} (π : F.obj zero ⟶ X) (h : F.map left ≫ π = F.map right ≫ π) : + ReflexiveCofork F where + pt := X + ι := reflexivePair.mkNatTrans π (F.map left ≫ π) + +@[simp] +lemma mk_π {X : C} (π : F.obj zero ⟶ X) (h : F.map left ≫ π = F.map right ≫ π) : + (mk π h).π = π := rfl + +lemma condition (G : ReflexiveCofork F) : F.map left ≫ G.π = F.map right ≫ G.π := by + rw [Cocone.w G left, Cocone.w G right] + +@[simp] +lemma app_one_eq_π (G : ReflexiveCofork F) : G.ι.app zero = G.π := rfl + +/-- The underlying `Cofork` of a `ReflexiveCofork`. -/ +abbrev toCofork (G : ReflexiveCofork F) : Cofork (F.map left) (F.map right) := + Cofork.ofπ G.π (by simp) + +end ReflexiveCofork + +noncomputable section +open WalkingReflexivePair WalkingReflexivePair.Hom + +variable (F : WalkingReflexivePair ⥤ C) + +/-- Forgetting the reflexion yields an equivalence between cocones over a bundled reflexive pair and +coforks on the underlying parallel pair. -/ +@[simps! functor_obj_pt inverse_obj_pt] +def reflexiveCoforkEquivCofork : + ReflexiveCofork F ≌ Cofork (F.map left) (F.map right) := + (Functor.Final.coconesEquiv _ F).symm.trans (Cocones.precomposeEquivalence + (diagramIsoParallelPair (WalkingParallelPair.inclusionWalkingReflexivePair ⋙ F))).symm + +@[simp] +lemma reflexiveCoforkEquivCofork_functor_obj_π (G : ReflexiveCofork F) : + ((reflexiveCoforkEquivCofork F).functor.obj G).π = G.π := by + dsimp [reflexiveCoforkEquivCofork] + rw [ReflexiveCofork.π, Cofork.π] + aesop_cat + +@[simp] +lemma reflexiveCoforkEquivCofork_inverse_obj_π + (G : Cofork (F.map left) (F.map right)) : + ((reflexiveCoforkEquivCofork F).inverse.obj G).π = G.π := by + dsimp only [reflexiveCoforkEquivCofork, Equivalence.symm, Equivalence.trans, + ReflexiveCofork.π, Cocones.precomposeEquivalence, Cocones.precompose, + Functor.comp, Functor.Final.coconesEquiv] + rw [Functor.Final.extendCocone_obj_ι_app' (Y := .one) (f := 𝟙 zero)] + simp + +/-- The equivalence between reflexive coforks and coforks sends a reflexive cofork to its underlying +cofork. -/ +def reflexiveCoforkEquivCoforkObjIso (G : ReflexiveCofork F) : + (reflexiveCoforkEquivCofork F).functor.obj G ≅ G.toCofork := + Cofork.ext (Iso.refl _) + (by simp [reflexiveCoforkEquivCofork, Cofork.π]) + +lemma hasReflexiveCoequalizer_iff_hasCoequalizer : + HasColimit F ↔ HasCoequalizer (F.map left) (F.map right) := by + simpa only [hasColimit_iff_hasInitial_cocone] + using Equivalence.hasInitial_iff (reflexiveCoforkEquivCofork F) + +instance reflexivePair_hasColimit_of_hasCoequalizer + [h : HasCoequalizer (F.map left) (F.map right)] : HasColimit F := + hasReflexiveCoequalizer_iff_hasCoequalizer _|>.mpr h + +/-- A reflexive cofork is a colimit cocone if and only if the underlying cofork is. -/ +def ReflexiveCofork.isColimitEquiv (G : ReflexiveCofork F) : + IsColimit (G.toCofork) ≃ IsColimit G := + IsColimit.equivIsoColimit (reflexiveCoforkEquivCoforkObjIso F G).symm|>.trans <| + (IsColimit.precomposeHomEquiv (diagramIsoParallelPair _).symm (G.whisker _)).trans <| + Functor.Final.isColimitWhiskerEquiv _ _ + +section + +variable [HasCoequalizer (F.map left) (F.map right)] + +/-- The colimit of a functor out of the walking reflexive pair is the same as the colimit of the +underlying parallel pair. -/ +def reflexiveCoequalizerIsoCoequalizer : + colimit F ≅ coequalizer (F.map left) (F.map right) := + ((ReflexiveCofork.isColimitEquiv _ _).symm (colimit.isColimit F)).coconePointUniqueUpToIso + (colimit.isColimit _) + +@[reassoc (attr := simp)] +lemma ι_reflexiveCoequalizerIsoCoequalizer_hom : + colimit.ι F zero ≫ (reflexiveCoequalizerIsoCoequalizer F).hom = + coequalizer.π (F.map left) (F.map right) := + IsColimit.comp_coconePointUniqueUpToIso_hom + ((ReflexiveCofork.isColimitEquiv F _).symm _) _ WalkingParallelPair.one + +@[reassoc (attr := simp)] +lemma π_reflexiveCoequalizerIsoCoequalizer_inv : + coequalizer.π _ _ ≫ (reflexiveCoequalizerIsoCoequalizer F).inv = colimit.ι F _ := by + rw [reflexiveCoequalizerIsoCoequalizer] + simp only [colimit.comp_coconePointUniqueUpToIso_inv, Cofork.ofπ_pt, colimit.cocone_x, + Cofork.ofπ_ι_app, colimit.cocone_ι] + +end + +variable {A B : C} {f g : A ⟶ B} [IsReflexivePair f g] [h : HasCoequalizer f g] + +instance ofIsReflexivePair_hasColimit_of_hasCoequalizer : + HasColimit (ofIsReflexivePair f g) := + hasReflexiveCoequalizer_iff_hasCoequalizer _|>.mpr h + +/-- The coequalizer of a reflexive pair can be promoted to the colimit of a diagram out of the +walking reflexive pair -/ +def colimitOfIsReflexivePairIsoCoequalizer : + colimit (ofIsReflexivePair f g) ≅ coequalizer f g := + @reflexiveCoequalizerIsoCoequalizer _ _ (ofIsReflexivePair f g) h + + +@[reassoc (attr := simp)] +lemma ι_colimitOfIsReflexivePairIsoCoequalizer_hom : + colimit.ι (ofIsReflexivePair f g) zero ≫ colimitOfIsReflexivePairIsoCoequalizer.hom = + coequalizer.π f g := @ι_reflexiveCoequalizerIsoCoequalizer_hom _ _ _ h + +@[reassoc (attr := simp)] +lemma π_colimitOfIsReflexivePairIsoCoequalizer_inv : + coequalizer.π f g ≫ colimitOfIsReflexivePairIsoCoequalizer.inv = + colimit.ι (ofIsReflexivePair f g) zero := + @π_reflexiveCoequalizerIsoCoequalizer_inv _ _ (ofIsReflexivePair f g) h + +end +end Limits + +namespace Limits + +open WalkingReflexivePair + +variable {C : Type u} [Category.{v} C] + +/-- A category has coequalizers of reflexive pairs if and only if it has all colimits indexed by the +walking reflexive pair. -/ +theorem hasReflexiveCoequalizers_iff : + HasColimitsOfShape WalkingReflexivePair C ↔ HasReflexiveCoequalizers C := + ⟨fun _ ↦ ⟨fun _ _ f g _ ↦ (hasReflexiveCoequalizer_iff_hasCoequalizer + (reflexivePair f g (commonSection f g))).1 inferInstance⟩, + fun _ ↦ ⟨inferInstance⟩⟩ + +end Limits end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean b/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean index e501871d0f757..be69100920eef 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean @@ -5,7 +5,8 @@ Authors: Christian Merten -/ import Mathlib.CategoryTheory.Limits.Types import Mathlib.CategoryTheory.SingleObj -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Data.Setoid.Basic +import Mathlib.GroupTheory.GroupAction.Defs /-! # (Co)limits of functors out of `SingleObj M` @@ -75,7 +76,7 @@ variable {G : Type v} [Group G] (J : SingleObj G ⥤ Type u) equivalent to the `MulAction.orbitRel` equivalence relation on `J.obj (SingleObj.star G)`. -/ lemma Types.Quot.Rel.iff_orbitRel (x y : J.obj (SingleObj.star G)) : Types.Quot.Rel J ⟨SingleObj.star G, x⟩ ⟨SingleObj.star G, y⟩ - ↔ Setoid.Rel (MulAction.orbitRel G (J.obj (SingleObj.star G))) x y := by + ↔ MulAction.orbitRel G (J.obj (SingleObj.star G)) x y := by have h (g : G) : y = g • x ↔ g • x = y := ⟨symm, symm⟩ conv => rhs; rw [Setoid.comm'] show (∃ g : G, y = g • x) ↔ (∃ g : G, g • x = y) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean b/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean index ba11c501a2ea9..2abdbdfda2ec4 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean @@ -125,12 +125,12 @@ theorem strongMono_of_strongMono [StrongMono (f ≫ g)] : StrongMono f := /-- An isomorphism is in particular a strong epimorphism. -/ instance (priority := 100) strongEpi_of_isIso [IsIso f] : StrongEpi f where epi := by infer_instance - llp {X Y} z := HasLiftingProperty.of_left_iso _ _ + llp {_ _} _ := HasLiftingProperty.of_left_iso _ _ /-- An isomorphism is in particular a strong monomorphism. -/ instance (priority := 100) strongMono_of_isIso [IsIso f] : StrongMono f where mono := by infer_instance - rlp {X Y} z := HasLiftingProperty.of_right_iso _ _ + rlp {_ _} _ := HasLiftingProperty.of_right_iso _ _ theorem StrongEpi.of_arrow_iso {A B A' B' : C} {f : A ⟶ B} {g : A' ⟶ B'} (e : Arrow.mk f ≅ Arrow.mk g) [h : StrongEpi f] : StrongEpi g := diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean b/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean index 37a4e622da924..d24c05e73cd2c 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean @@ -3,10 +3,8 @@ Copyright (c) 2019 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison, Bhavik Mehta -/ -import Mathlib.CategoryTheory.PEmpty +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal import Mathlib.CategoryTheory.Limits.HasLimits -import Mathlib.CategoryTheory.EpiMono -import Mathlib.CategoryTheory.Category.Preorder /-! # Initial and terminal objects in a category. @@ -26,180 +24,6 @@ namespace CategoryTheory.Limits variable {C : Type u₁} [Category.{v₁} C] -/-- Construct a cone for the empty diagram given an object. -/ -@[simps] -def asEmptyCone (X : C) : Cone (Functor.empty.{0} C) := - { pt := X - π := - { app := by aesop_cat } } - -/-- Construct a cocone for the empty diagram given an object. -/ -@[simps] -def asEmptyCocone (X : C) : Cocone (Functor.empty.{0} C) := - { pt := X - ι := - { app := by aesop_cat } } - -/-- `X` is terminal if the cone it induces on the empty diagram is limiting. -/ -abbrev IsTerminal (X : C) := - IsLimit (asEmptyCone X) - -/-- `X` is initial if the cocone it induces on the empty diagram is colimiting. -/ -abbrev IsInitial (X : C) := - IsColimit (asEmptyCocone X) - -/-- An object `Y` is terminal iff for every `X` there is a unique morphism `X ⟶ Y`. -/ -def isTerminalEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (Y : C) : - IsLimit (⟨Y, by aesop_cat, by aesop_cat⟩ : Cone F) ≃ ∀ X : C, Unique (X ⟶ Y) where - toFun t X := - { default := t.lift ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ - uniq := fun f => - t.uniq ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ f (by aesop_cat) } - invFun u := - { lift := fun s => (u s.pt).default - uniq := fun s _ _ => (u s.pt).2 _ } - left_inv := by dsimp [Function.LeftInverse]; intro x; simp only [eq_iff_true_of_subsingleton] - right_inv := by - dsimp [Function.RightInverse,Function.LeftInverse] - intro u; funext X; simp only - -/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y` - (as an instance). -/ -def IsTerminal.ofUnique (Y : C) [h : ∀ X : C, Unique (X ⟶ Y)] : IsTerminal Y where - lift s := (h s.pt).default - fac := fun _ ⟨j⟩ => j.elim - -/-- An object `Y` is terminal if for every `X` there is a unique morphism `X ⟶ Y` - (as explicit arguments). -/ -def IsTerminal.ofUniqueHom {Y : C} (h : ∀ X : C, X ⟶ Y) (uniq : ∀ (X : C) (m : X ⟶ Y), m = h X) : - IsTerminal Y := - have : ∀ X : C, Unique (X ⟶ Y) := fun X ↦ ⟨⟨h X⟩, uniq X⟩ - IsTerminal.ofUnique Y - -/-- If `α` is a preorder with top, then `⊤` is a terminal object. -/ -def isTerminalTop {α : Type*} [Preorder α] [OrderTop α] : IsTerminal (⊤ : α) := - IsTerminal.ofUnique _ - -/-- Transport a term of type `IsTerminal` across an isomorphism. -/ -def IsTerminal.ofIso {Y Z : C} (hY : IsTerminal Y) (i : Y ≅ Z) : IsTerminal Z := - IsLimit.ofIsoLimit hY - { hom := { hom := i.hom } - inv := { hom := i.inv } } - -/-- If `X` and `Y` are isomorphic, then `X` is terminal iff `Y` is. -/ -def IsTerminal.equivOfIso {X Y : C} (e : X ≅ Y) : - IsTerminal X ≃ IsTerminal Y where - toFun h := IsTerminal.ofIso h e - invFun h := IsTerminal.ofIso h e.symm - left_inv _ := Subsingleton.elim _ _ - right_inv _ := Subsingleton.elim _ _ - -/-- An object `X` is initial iff for every `Y` there is a unique morphism `X ⟶ Y`. -/ -def isInitialEquivUnique (F : Discrete.{0} PEmpty.{1} ⥤ C) (X : C) : - IsColimit (⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ : Cocone F) ≃ ∀ Y : C, Unique (X ⟶ Y) where - toFun t X := - { default := t.desc ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ - uniq := fun f => t.uniq ⟨X, ⟨by aesop_cat, by aesop_cat⟩⟩ f (by aesop_cat) } - invFun u := - { desc := fun s => (u s.pt).default - uniq := fun s _ _ => (u s.pt).2 _ } - left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] - right_inv := by - dsimp [Function.RightInverse,Function.LeftInverse] - intro; funext; simp only - -/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y` - (as an instance). -/ -def IsInitial.ofUnique (X : C) [h : ∀ Y : C, Unique (X ⟶ Y)] : IsInitial X where - desc s := (h s.pt).default - fac := fun _ ⟨j⟩ => j.elim - -/-- An object `X` is initial if for every `Y` there is a unique morphism `X ⟶ Y` - (as explicit arguments). -/ -def IsInitial.ofUniqueHom {X : C} (h : ∀ Y : C, X ⟶ Y) (uniq : ∀ (Y : C) (m : X ⟶ Y), m = h Y) : - IsInitial X := - have : ∀ Y : C, Unique (X ⟶ Y) := fun Y ↦ ⟨⟨h Y⟩, uniq Y⟩ - IsInitial.ofUnique X - -/-- If `α` is a preorder with bot, then `⊥` is an initial object. -/ -def isInitialBot {α : Type*} [Preorder α] [OrderBot α] : IsInitial (⊥ : α) := - IsInitial.ofUnique _ - -/-- Transport a term of type `is_initial` across an isomorphism. -/ -def IsInitial.ofIso {X Y : C} (hX : IsInitial X) (i : X ≅ Y) : IsInitial Y := - IsColimit.ofIsoColimit hX - { hom := { hom := i.hom } - inv := { hom := i.inv } } - -/-- If `X` and `Y` are isomorphic, then `X` is initial iff `Y` is. -/ -def IsInitial.equivOfIso {X Y : C} (e : X ≅ Y) : - IsInitial X ≃ IsInitial Y where - toFun h := IsInitial.ofIso h e - invFun h := IsInitial.ofIso h e.symm - left_inv _ := Subsingleton.elim _ _ - right_inv _ := Subsingleton.elim _ _ - -/-- Give the morphism to a terminal object from any other. -/ -def IsTerminal.from {X : C} (t : IsTerminal X) (Y : C) : Y ⟶ X := - t.lift (asEmptyCone Y) - -/-- Any two morphisms to a terminal object are equal. -/ -theorem IsTerminal.hom_ext {X Y : C} (t : IsTerminal X) (f g : Y ⟶ X) : f = g := - IsLimit.hom_ext t (by aesop_cat) - -@[simp] -theorem IsTerminal.comp_from {Z : C} (t : IsTerminal Z) {X Y : C} (f : X ⟶ Y) : - f ≫ t.from Y = t.from X := - t.hom_ext _ _ - -@[simp] -theorem IsTerminal.from_self {X : C} (t : IsTerminal X) : t.from X = 𝟙 X := - t.hom_ext _ _ - -/-- Give the morphism from an initial object to any other. -/ -def IsInitial.to {X : C} (t : IsInitial X) (Y : C) : X ⟶ Y := - t.desc (asEmptyCocone Y) - -/-- Any two morphisms from an initial object are equal. -/ -theorem IsInitial.hom_ext {X Y : C} (t : IsInitial X) (f g : X ⟶ Y) : f = g := - IsColimit.hom_ext t (by aesop_cat) - -@[simp] -theorem IsInitial.to_comp {X : C} (t : IsInitial X) {Y Z : C} (f : Y ⟶ Z) : t.to Y ≫ f = t.to Z := - t.hom_ext _ _ - -@[simp] -theorem IsInitial.to_self {X : C} (t : IsInitial X) : t.to X = 𝟙 X := - t.hom_ext _ _ - -/-- Any morphism from a terminal object is split mono. -/ -theorem IsTerminal.isSplitMono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : IsSplitMono f := - IsSplitMono.mk' ⟨t.from _, t.hom_ext _ _⟩ - -/-- Any morphism to an initial object is split epi. -/ -theorem IsInitial.isSplitEpi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : IsSplitEpi f := - IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩ - -/-- Any morphism from a terminal object is mono. -/ -theorem IsTerminal.mono_from {X Y : C} (t : IsTerminal X) (f : X ⟶ Y) : Mono f := by - haveI := t.isSplitMono_from f; infer_instance - -/-- Any morphism to an initial object is epi. -/ -theorem IsInitial.epi_to {X Y : C} (t : IsInitial X) (f : Y ⟶ X) : Epi f := by - haveI := t.isSplitEpi_to f; infer_instance - -/-- If `T` and `T'` are terminal, they are isomorphic. -/ -@[simps] -def IsTerminal.uniqueUpToIso {T T' : C} (hT : IsTerminal T) (hT' : IsTerminal T') : T ≅ T' where - hom := hT'.from _ - inv := hT.from _ - -/-- If `I` and `I'` are initial, they are isomorphic. -/ -@[simps] -def IsInitial.uniqueUpToIso {I I' : C} (hI : IsInitial I) (hI' : IsInitial I') : I ≅ I' where - hom := hI.to _ - inv := hI'.to _ - variable (C) /-- A category has a terminal object if it has a limit over the empty diagram. @@ -218,28 +42,6 @@ section Univ variable (X : C) {F₁ : Discrete.{w} PEmpty ⥤ C} {F₂ : Discrete.{w'} PEmpty ⥤ C} -/-- Being terminal is independent of the empty diagram, its universe, and the cone over it, - as long as the cone points are isomorphic. -/ -def isLimitChangeEmptyCone {c₁ : Cone F₁} (hl : IsLimit c₁) (c₂ : Cone F₂) (hi : c₁.pt ≅ c₂.pt) : - IsLimit c₂ where - lift c := hl.lift ⟨c.pt, by aesop_cat, by aesop_cat⟩ ≫ hi.hom - uniq c f _ := by - dsimp - rw [← hl.uniq _ (f ≫ hi.inv) _] - · simp only [Category.assoc, Iso.inv_hom_id, Category.comp_id] - · aesop_cat - -/-- Replacing an empty cone in `IsLimit` by another with the same cone point - is an equivalence. -/ -def isLimitEmptyConeEquiv (c₁ : Cone F₁) (c₂ : Cone F₂) (h : c₁.pt ≅ c₂.pt) : - IsLimit c₁ ≃ IsLimit c₂ where - toFun hl := isLimitChangeEmptyCone C hl c₂ h - invFun hl := isLimitChangeEmptyCone C hl c₁ h.symm - left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] - right_inv := by - dsimp [Function.LeftInverse,Function.RightInverse]; intro - simp only [eq_iff_true_of_subsingleton] - theorem hasTerminalChangeDiagram (h : HasLimit F₁) : HasLimit F₂ := ⟨⟨⟨⟨limit F₁, by aesop_cat, by aesop_cat⟩, isLimitChangeEmptyCone C (limit.isLimit F₁) _ (eqToIso rfl)⟩⟩⟩ @@ -248,28 +50,6 @@ theorem hasTerminalChangeUniverse [h : HasLimitsOfShape (Discrete.{w} PEmpty) C] HasLimitsOfShape (Discrete.{w'} PEmpty) C where has_limit _ := hasTerminalChangeDiagram C (h.1 (Functor.empty C)) -/-- Being initial is independent of the empty diagram, its universe, and the cocone over it, - as long as the cocone points are isomorphic. -/ -def isColimitChangeEmptyCocone {c₁ : Cocone F₁} (hl : IsColimit c₁) (c₂ : Cocone F₂) - (hi : c₁.pt ≅ c₂.pt) : IsColimit c₂ where - desc c := hi.inv ≫ hl.desc ⟨c.pt, by aesop_cat, by aesop_cat⟩ - uniq c f _ := by - dsimp - rw [← hl.uniq _ (hi.hom ≫ f) _] - · simp only [Iso.inv_hom_id_assoc] - · aesop_cat - -/-- Replacing an empty cocone in `IsColimit` by another with the same cocone point - is an equivalence. -/ -def isColimitEmptyCoconeEquiv (c₁ : Cocone F₁) (c₂ : Cocone F₂) (h : c₁.pt ≅ c₂.pt) : - IsColimit c₁ ≃ IsColimit c₂ where - toFun hl := isColimitChangeEmptyCocone C hl c₂ h - invFun hl := isColimitChangeEmptyCocone C hl c₁ h.symm - left_inv := by dsimp [Function.LeftInverse]; intro; simp only [eq_iff_true_of_subsingleton] - right_inv := by - dsimp [Function.LeftInverse,Function.RightInverse]; intro - simp only [eq_iff_true_of_subsingleton] - theorem hasInitialChangeDiagram (h : HasColimit F₁) : HasColimit F₂ := ⟨⟨⟨⟨colimit F₁, by aesop_cat, by aesop_cat⟩, isColimitChangeEmptyCocone C (colimit.isColimit F₁) _ (eqToIso rfl)⟩⟩⟩ @@ -306,8 +86,10 @@ variable {C} /-- We can more explicitly show that a category has a terminal object by specifying the object, and showing there is a unique morphism to it from any other object. -/ -theorem hasTerminal_of_unique (X : C) [h : ∀ Y : C, Unique (Y ⟶ X)] : HasTerminal C := - { has_limit := fun F => HasLimit.mk ⟨_, (isTerminalEquivUnique F X).invFun h⟩ } +theorem hasTerminal_of_unique (X : C) [∀ Y, Nonempty (Y ⟶ X)] [∀ Y, Subsingleton (Y ⟶ X)] : + HasTerminal C where + has_limit F := .mk ⟨_, (isTerminalEquivUnique F X).invFun fun _ ↦ + ⟨Classical.inhabited_of_nonempty', (Subsingleton.elim · _)⟩⟩ theorem IsTerminal.hasTerminal {X : C} (h : IsTerminal X) : HasTerminal C := { has_limit := fun F => HasLimit.mk ⟨⟨X, by aesop_cat, by aesop_cat⟩, @@ -315,8 +97,10 @@ theorem IsTerminal.hasTerminal {X : C} (h : IsTerminal X) : HasTerminal C := /-- We can more explicitly show that a category has an initial object by specifying the object, and showing there is a unique morphism from it to any other object. -/ -theorem hasInitial_of_unique (X : C) [h : ∀ Y : C, Unique (X ⟶ Y)] : HasInitial C := - { has_colimit := fun F => HasColimit.mk ⟨_, (isInitialEquivUnique F X).invFun h⟩ } +theorem hasInitial_of_unique (X : C) [∀ Y, Nonempty (X ⟶ Y)] [∀ Y, Subsingleton (X ⟶ Y)] : + HasInitial C where + has_colimit F := .mk ⟨_, (isInitialEquivUnique F X).invFun fun _ ↦ + ⟨Classical.inhabited_of_nonempty', (Subsingleton.elim · _)⟩⟩ theorem IsInitial.hasInitial {X : C} (h : IsInitial X) : HasInitial C where has_colimit F := @@ -332,11 +116,11 @@ abbrev initial.to [HasInitial C] (P : C) : ⊥_ C ⟶ P := /-- A terminal object is terminal. -/ def terminalIsTerminal [HasTerminal C] : IsTerminal (⊤_ C) where - lift s := terminal.from _ + lift _ := terminal.from _ /-- An initial object is initial. -/ def initialIsInitial [HasInitial C] : IsInitial (⊥_ C) where - desc s := initial.to _ + desc _ := initial.to _ instance uniqueToTerminal [HasTerminal C] (P : C) : Unique (P ⟶ ⊤_ C) := isTerminalEquivUnique _ (⊤_ C) terminalIsTerminal P @@ -375,26 +159,6 @@ instance terminal.isSplitMono_from {Y : C} [HasTerminal C] (f : ⊤_ C ⟶ Y) : instance initial.isSplitEpi_to {Y : C} [HasInitial C] (f : Y ⟶ ⊥_ C) : IsSplitEpi f := IsInitial.isSplitEpi_to initialIsInitial _ -/-- An initial object is terminal in the opposite category. -/ -def terminalOpOfInitial {X : C} (t : IsInitial X) : IsTerminal (Opposite.op X) where - lift s := (t.to s.pt.unop).op - uniq s m _ := Quiver.Hom.unop_inj (t.hom_ext _ _) - -/-- An initial object in the opposite category is terminal in the original category. -/ -def terminalUnopOfInitial {X : Cᵒᵖ} (t : IsInitial X) : IsTerminal X.unop where - lift s := (t.to (Opposite.op s.pt)).unop - uniq s m _ := Quiver.Hom.op_inj (t.hom_ext _ _) - -/-- A terminal object is initial in the opposite category. -/ -def initialOpOfTerminal {X : C} (t : IsTerminal X) : IsInitial (Opposite.op X) where - desc s := (t.from s.pt.unop).op - uniq s m _ := Quiver.Hom.unop_inj (t.hom_ext _ _) - -/-- A terminal object in the opposite category is initial in the original category. -/ -def initialUnopOfTerminal {X : Cᵒᵖ} (t : IsTerminal X) : IsInitial X.unop where - desc s := (t.from (Opposite.op s.pt)).unop - uniq s m _ := Quiver.Hom.op_inj (t.hom_ext _ _) - instance hasInitial_op_of_hasTerminal [HasTerminal C] : HasInitial Cᵒᵖ := (initialOpOfTerminal terminalIsTerminal).hasInitial @@ -413,7 +177,7 @@ instance {J : Type*} [Category J] {C : Type*} [Category C] [HasTerminal C] : { cone := { pt := ⊤_ C π := { app := fun _ => terminal.from _ } } - isLimit := { lift := fun s => terminal.from _ } } + isLimit := { lift := fun _ => terminal.from _ } } /-- The limit of the constant `⊤_ C` functor is `⊤_ C`. -/ @[simps hom] @@ -423,7 +187,7 @@ def limitConstTerminal {J : Type*} [Category J] {C : Type*} [Category C] [HasTer inv := limit.lift ((CategoryTheory.Functor.const J).obj (⊤_ C)) { pt := ⊤_ C - π := { app := fun j => terminal.from _ } } + π := { app := fun _ => terminal.from _ } } @[reassoc (attr := simp)] theorem limitConstTerminal_inv_π {J : Type*} [Category J] {C : Type*} [Category C] [HasTerminal C] @@ -437,7 +201,7 @@ instance {J : Type*} [Category J] {C : Type*} [Category C] [HasInitial C] : { cocone := { pt := ⊥_ C ι := { app := fun _ => initial.to _ } } - isColimit := { desc := fun s => initial.to _ } } + isColimit := { desc := fun _ => initial.to _ } } /-- The colimit of the constant `⊥_ C` functor is `⊥_ C`. -/ @[simps inv] @@ -446,7 +210,7 @@ def colimitConstInitial {J : Type*} [Category J] {C : Type*} [Category C] [HasIn hom := colimit.desc ((CategoryTheory.Functor.const J).obj (⊥_ C)) { pt := ⊥_ C - ι := { app := fun j => initial.to _ } } + ι := { app := fun _ => initial.to _ } } inv := initial.to _ @[reassoc (attr := simp)] @@ -455,48 +219,16 @@ theorem ι_colimitConstInitial_hom {J : Type*} [Category J] {C : Type*} [Categor colimit.ι ((CategoryTheory.Functor.const J).obj (⊥_ C)) j ≫ colimitConstInitial.hom = initial.to _ := by aesop_cat -/-- A category is an `InitialMonoClass` if the canonical morphism of an initial object is a -monomorphism. In practice, this is most useful when given an arbitrary morphism out of the chosen -initial object, see `initial.mono_from`. -Given a terminal object, this is equivalent to the assumption that the unique morphism from initial -to terminal is a monomorphism, which is the second of Freyd's axioms for an AT category. - -TODO: This is a condition satisfied by categories with zero objects and morphisms. --/ -class InitialMonoClass (C : Type u₁) [Category.{v₁} C] : Prop where - /-- The map from the (any as stated) initial object to any other object is a - monomorphism -/ - isInitial_mono_from : ∀ {I} (X : C) (hI : IsInitial I), Mono (hI.to X) - -theorem IsInitial.mono_from [InitialMonoClass C] {I} {X : C} (hI : IsInitial I) (f : I ⟶ X) : - Mono f := by - rw [hI.hom_ext f (hI.to X)] - apply InitialMonoClass.isInitial_mono_from - instance (priority := 100) initial.mono_from [HasInitial C] [InitialMonoClass C] (X : C) (f : ⊥_ C ⟶ X) : Mono f := initialIsInitial.mono_from f -/-- To show a category is an `InitialMonoClass` it suffices to give an initial object such that -every morphism out of it is a monomorphism. -/ -theorem InitialMonoClass.of_isInitial {I : C} (hI : IsInitial I) (h : ∀ X, Mono (hI.to X)) : - InitialMonoClass C where - isInitial_mono_from {I'} X hI' := by - rw [hI'.hom_ext (hI'.to X) ((hI'.uniqueUpToIso hI).hom ≫ hI.to X)] - apply mono_comp - /-- To show a category is an `InitialMonoClass` it suffices to show every morphism out of the initial object is a monomorphism. -/ theorem InitialMonoClass.of_initial [HasInitial C] (h : ∀ X : C, Mono (initial.to X)) : InitialMonoClass C := InitialMonoClass.of_isInitial initialIsInitial h -/-- To show a category is an `InitialMonoClass` it suffices to show the unique morphism from an -initial object to a terminal object is a monomorphism. -/ -theorem InitialMonoClass.of_isTerminal {I T : C} (hI : IsInitial I) (hT : IsTerminal T) - (_ : Mono (hI.to T)) : InitialMonoClass C := - InitialMonoClass.of_isInitial hI fun X => mono_of_mono_fac (hI.hom_ext (_ ≫ hT.from X) (hI.to T)) - /-- To show a category is an `InitialMonoClass` it suffices to show the unique morphism from the initial object to a terminal object is a monomorphism. -/ theorem InitialMonoClass.of_terminal [HasInitial C] [HasTerminal C] (h : Mono (initial.to (⊤_ C))) : @@ -527,27 +259,6 @@ end Comparison variable {J : Type u} [Category.{v} J] -/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cone for `J`. -In `limitOfDiagramInitial` we show it is a limit cone. -/ -@[simps] -def coneOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : Cone F where - pt := F.obj X - π := - { app := fun j => F.map (tX.to j) - naturality := fun j j' k => by - dsimp - rw [← F.map_comp, Category.id_comp, tX.hom_ext (tX.to j ≫ k) (tX.to j')] } - -/-- From a functor `F : J ⥤ C`, given an initial object of `J`, show the cone -`coneOfDiagramInitial` is a limit. -/ -def limitOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : - IsLimit (coneOfDiagramInitial tX F) where - lift s := s.π.app X - uniq s m w := by - conv_lhs => dsimp - simp_rw [← w X, coneOfDiagramInitial_π_app, tX.hom_ext (tX.to X) (𝟙 _)] - simp - instance hasLimit_of_domain_hasInitial [HasInitial J] {F : J ⥤ C} : HasLimit F := HasLimit.mk { cone := _, isLimit := limitOfDiagramInitial (initialIsInitial) F } @@ -558,27 +269,6 @@ to the limit of `F`. -/ abbrev limitOfInitial (F : J ⥤ C) [HasInitial J] : limit F ≅ F.obj (⊥_ J) := IsLimit.conePointUniqueUpToIso (limit.isLimit _) (limitOfDiagramInitial initialIsInitial F) -/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cone for `J`, -provided that the morphisms in the diagram are isomorphisms. -In `limitOfDiagramTerminal` we show it is a limit cone. -/ -@[simps] -def coneOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) - [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cone F where - pt := F.obj X - π := - { app := fun i => inv (F.map (hX.from _)) - naturality := by - intro i j f - dsimp - simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.id_comp, ← F.map_comp, - hX.hom_ext (hX.from i) (f ≫ hX.from j)] } - -/-- From a functor `F : J ⥤ C`, given a terminal object of `J` and that the morphisms in the -diagram are isomorphisms, show the cone `coneOfDiagramTerminal` is a limit. -/ -def limitOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) - [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsLimit (coneOfDiagramTerminal hX F) where - lift S := S.π.app _ - instance hasLimit_of_domain_hasTerminal [HasTerminal J] {F : J ⥤ C} [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : HasLimit F := HasLimit.mk { cone := _, isLimit := limitOfDiagramTerminal (terminalIsTerminal) F } @@ -590,36 +280,9 @@ abbrev limitOfTerminal (F : J ⥤ C) [HasTerminal J] [∀ (i j : J) (f : i ⟶ j limit F ≅ F.obj (⊤_ J) := IsLimit.conePointUniqueUpToIso (limit.isLimit _) (limitOfDiagramTerminal terminalIsTerminal F) -/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, construct a cocone for `J`. -In `colimitOfDiagramTerminal` we show it is a colimit cocone. -/ -@[simps] -def coconeOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : Cocone F where - pt := F.obj X - ι := - { app := fun j => F.map (tX.from j) - naturality := fun j j' k => by - dsimp - rw [← F.map_comp, Category.comp_id, tX.hom_ext (k ≫ tX.from j') (tX.from j)] } - -/-- From a functor `F : J ⥤ C`, given a terminal object of `J`, show the cocone -`coconeOfDiagramTerminal` is a colimit. -/ -def colimitOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : - IsColimit (coconeOfDiagramTerminal tX F) where - desc s := s.ι.app X - uniq s m w := by - conv_rhs => dsimp -- Porting note: why do I need this much firepower? - rw [← w X, coconeOfDiagramTerminal_ι_app, tX.hom_ext (tX.from X) (𝟙 _)] - simp - instance hasColimit_of_domain_hasTerminal [HasTerminal J] {F : J ⥤ C} : HasColimit F := HasColimit.mk { cocone := _, isColimit := colimitOfDiagramTerminal (terminalIsTerminal) F } -lemma IsColimit.isIso_ι_app_of_isTerminal {F : J ⥤ C} {c : Cocone F} (hc : IsColimit c) - (X : J) (hX : IsTerminal X) : - IsIso (c.ι.app X) := by - change IsIso (coconePointUniqueUpToIso (colimitOfDiagramTerminal hX F) hc).hom - infer_instance - -- This is reducible to allow usage of lemmas about `cocone_point_unique_up_to_iso`. /-- For a functor `F : J ⥤ C`, if `J` has a terminal object then the image of it is isomorphic to the colimit of `F`. -/ @@ -627,37 +290,10 @@ abbrev colimitOfTerminal (F : J ⥤ C) [HasTerminal J] : colimit F ≅ F.obj ( IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) (colimitOfDiagramTerminal terminalIsTerminal F) -/-- From a functor `F : J ⥤ C`, given an initial object of `J`, construct a cocone for `J`, -provided that the morphisms in the diagram are isomorphisms. -In `colimitOfDiagramInitial` we show it is a colimit cocone. -/ -@[simps] -def coconeOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) - [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : Cocone F where - pt := F.obj X - ι := - { app := fun i => inv (F.map (hX.to _)) - naturality := by - intro i j f - dsimp - simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.comp_id, ← F.map_comp, - hX.hom_ext (hX.to i ≫ f) (hX.to j)] } - -/-- From a functor `F : J ⥤ C`, given an initial object of `J` and that the morphisms in the -diagram are isomorphisms, show the cone `coconeOfDiagramInitial` is a colimit. -/ -def colimitOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) - [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : IsColimit (coconeOfDiagramInitial hX F) where - desc S := S.ι.app _ - instance hasColimit_of_domain_hasInitial [HasInitial J] {F : J ⥤ C} [∀ (i j : J) (f : i ⟶ j), IsIso (F.map f)] : HasColimit F := HasColimit.mk { cocone := _, isColimit := colimitOfDiagramInitial (initialIsInitial) F } -lemma IsLimit.isIso_π_app_of_isInitial {F : J ⥤ C} {c : Cone F} (hc : IsLimit c) - (X : J) (hX : IsInitial X) : - IsIso (c.π.app X) := by - change IsIso (conePointUniqueUpToIso hc (limitOfDiagramInitial hX F)).hom - infer_instance - -- This is reducible to allow usage of lemmas about `cocone_point_unique_up_to_iso`. /-- For a functor `F : J ⥤ C`, if `J` has an initial object and all the morphisms in the diagram are isomorphisms, then the image of the initial object is isomorphic to the colimit of `F`. -/ @@ -706,20 +342,6 @@ instance isIso_ι_initial [HasInitial J] (F : J ⥤ C) [∀ (i j : J) (f : i ⟶ IsIso (colimit.ι F (⊥_ J)) := isIso_ι_of_isInitial initialIsInitial F -/-- Any morphism between terminal objects is an isomorphism. -/ -lemma isIso_of_isTerminal {X Y : C} (hX : IsTerminal X) (hY : IsTerminal Y) (f : X ⟶ Y) : - IsIso f := by - refine ⟨⟨IsTerminal.from hX Y, ?_⟩⟩ - simp only [IsTerminal.comp_from, IsTerminal.from_self, true_and] - apply IsTerminal.hom_ext hY - -/-- Any morphism between initial objects is an isomorphism. -/ -lemma isIso_of_isInitial {X Y : C} (hX : IsInitial X) (hY : IsInitial Y) (f : X ⟶ Y) : - IsIso f := by - refine ⟨⟨IsInitial.to hY X, ?_⟩⟩ - simp only [IsInitial.to_comp, IsInitial.to_self, and_true] - apply IsInitial.hom_ext hX - end end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Types.lean b/Mathlib/CategoryTheory/Limits/Shapes/Types.lean index 5f9021a6e2f50..f0c5334a88559 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Types.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Types.lean @@ -216,7 +216,7 @@ theorem binaryProductIso_inv_comp_snd (X Y : Type u) : def binaryProductFunctor : Type u ⥤ Type u ⥤ Type u where obj X := { obj := fun Y => X × Y - map := fun { Y₁ Y₂} f => (binaryProductLimit X Y₂).lift + map := fun { _ Y₂} f => (binaryProductLimit X Y₂).lift (BinaryFan.mk _root_.Prod.fst (_root_.Prod.snd ≫ f)) } map {X₁ X₂} f := { app := fun Y => @@ -346,7 +346,7 @@ def productLimitCone {J : Type v} (F : J → TypeMax.{v, u}) : π := Discrete.natTrans (fun ⟨j⟩ f => f j) } isLimit := { lift := fun s x j => s.π.app ⟨j⟩ x - uniq := fun s m w => funext fun x => funext fun j => (congr_fun (w ⟨j⟩) x : _) } + uniq := fun _ _ w => funext fun x => funext fun j => (congr_fun (w ⟨j⟩) x : _) } /-- The categorical product in `TypeMax.{v, u}` is the type theoretic product `Π j, F j`. -/ noncomputable def productIso {J : Type v} (F : J → TypeMax.{v, u}) : ∏ᶜ F ≅ ∀ j, F j := @@ -524,8 +524,8 @@ def coequalizerColimit : Limits.ColimitCocone (parallelPair f g) where (fun a b (h : CoequalizerRel f g a b) => by cases h apply congr_fun s.condition)) - (fun s => rfl) - (fun s m hm => funext (fun x => Quot.inductionOn x (congr_fun hm))) + (fun _ => rfl) + (fun _ _ hm => funext (fun x => Quot.inductionOn x (congr_fun hm))) /-- If `π : Y ⟶ Z` is an equalizer for `(f, g)`, and `U ⊆ Y` such that `f ⁻¹' U = g ⁻¹' U`, then `π ⁻¹' (π '' U) = U`. @@ -613,7 +613,7 @@ def pullbackLimitCone (f : X ⟶ Z) (g : Y ⟶ Z) : Limits.LimitCone (cospan f g cone := pullbackCone f g isLimit := PullbackCone.isLimitAux _ (fun s x => ⟨⟨s.fst x, s.snd x⟩, congr_fun s.condition x⟩) - (by aesop) (by aesop) fun s m w => + (by aesop) (by aesop) fun _ _ w => funext fun x => Subtype.ext <| Prod.ext (congr_fun (w WalkingCospan.left) x) (congr_fun (w WalkingCospan.right) x) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean index 6193cbb5c6587..e8a53e2075d20 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean @@ -329,8 +329,8 @@ def Trident.IsLimit.homIso [Nonempty J] {t : Trident f} (ht : IsLimit t) (Z : C) (Z ⟶ t.pt) ≃ { h : Z ⟶ X // ∀ j₁ j₂, h ≫ f j₁ = h ≫ f j₂ } where toFun k := ⟨k ≫ t.ι, by simp⟩ invFun h := (Trident.IsLimit.lift' ht _ h.prop).1 - left_inv k := Trident.IsLimit.hom_ext ht (Trident.IsLimit.lift' _ _ _).prop - right_inv h := Subtype.ext (Trident.IsLimit.lift' ht _ _).prop + left_inv _ := Trident.IsLimit.hom_ext ht (Trident.IsLimit.lift' _ _ _).prop + right_inv _ := Subtype.ext (Trident.IsLimit.lift' ht _ _).prop /-- The bijection of `Trident.IsLimit.homIso` is natural in `Z`. -/ theorem Trident.IsLimit.homIso_natural [Nonempty J] {t : Trident f} (ht : IsLimit t) {Z Z' : C} @@ -349,8 +349,8 @@ def Cotrident.IsColimit.homIso [Nonempty J] {t : Cotrident f} (ht : IsColimit t) (t.pt ⟶ Z) ≃ { h : Y ⟶ Z // ∀ j₁ j₂, f j₁ ≫ h = f j₂ ≫ h } where toFun k := ⟨t.π ≫ k, by simp⟩ invFun h := (Cotrident.IsColimit.desc' ht _ h.prop).1 - left_inv k := Cotrident.IsColimit.hom_ext ht (Cotrident.IsColimit.desc' _ _ _).prop - right_inv h := Subtype.ext (Cotrident.IsColimit.desc' ht _ _).prop + left_inv _ := Cotrident.IsColimit.hom_ext ht (Cotrident.IsColimit.desc' _ _ _).prop + right_inv _ := Subtype.ext (Cotrident.IsColimit.desc' ht _ _).prop /-- The bijection of `Cotrident.IsColimit.homIso` is natural in `Z`. -/ theorem Cotrident.IsColimit.homIso_natural [Nonempty J] {t : Cotrident f} {Z Z' : C} (q : Z ⟶ Z') diff --git a/Mathlib/CategoryTheory/Limits/Shapes/WidePullbacks.lean b/Mathlib/CategoryTheory/Limits/Shapes/WidePullbacks.lean index 9d41486241eb2..4670206841758 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/WidePullbacks.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/WidePullbacks.lean @@ -311,12 +311,10 @@ noncomputable abbrev lift {X : C} (f : X ⟶ B) (fs : ∀ j : J, X ⟶ objs j) variable (arrows) variable {X : C} (f : X ⟶ B) (fs : ∀ j : J, X ⟶ objs j) (w : ∀ j, fs j ≫ arrows j = f) --- Porting note (#10618): simp can prove this so removed simp attribute @[reassoc] theorem lift_π (j : J) : lift f fs w ≫ π arrows j = fs _ := by simp only [limit.lift_π, WidePullbackShape.mkCone_pt, WidePullbackShape.mkCone_π_app] --- Porting note (#10618): simp can prove this so removed simp attribute @[reassoc] theorem lift_base : lift f fs w ≫ base arrows = f := by simp only [limit.lift_π, WidePullbackShape.mkCone_pt, WidePullbackShape.mkCone_π_app] @@ -378,12 +376,10 @@ noncomputable abbrev desc {X : C} (f : B ⟶ X) (fs : ∀ j : J, objs j ⟶ X) variable (arrows) variable {X : C} (f : B ⟶ X) (fs : ∀ j : J, objs j ⟶ X) (w : ∀ j, arrows j ≫ fs j = f) --- Porting note (#10618): simp can prove this so removed simp attribute @[reassoc] theorem ι_desc (j : J) : ι arrows j ≫ desc f fs w = fs _ := by simp only [colimit.ι_desc, WidePushoutShape.mkCocone_pt, WidePushoutShape.mkCocone_ι_app] --- Porting note (#10618): simp can prove this so removed simp attribute @[reassoc] theorem head_desc : head arrows ≫ desc f fs w = f := by simp only [colimit.ι_desc, WidePushoutShape.mkCocone_pt, WidePushoutShape.mkCocone_ι_app] @@ -461,22 +457,22 @@ def widePushoutShapeUnop : (WidePushoutShape J)ᵒᵖ ⥤ WidePullbackShape J := /-- The inverse of the unit isomorphism of the equivalence `widePushoutShapeOpEquiv : (WidePushoutShape J)ᵒᵖ ≌ WidePullbackShape J` -/ def widePushoutShapeOpUnop : widePushoutShapeUnop J ⋙ widePullbackShapeOp J ≅ 𝟭 _ := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The counit isomorphism of the equivalence `widePullbackShapeOpEquiv : (WidePullbackShape J)ᵒᵖ ≌ WidePushoutShape J` -/ def widePushoutShapeUnopOp : widePushoutShapeOp J ⋙ widePullbackShapeUnop J ≅ 𝟭 _ := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The inverse of the unit isomorphism of the equivalence `widePullbackShapeOpEquiv : (WidePullbackShape J)ᵒᵖ ≌ WidePushoutShape J` -/ def widePullbackShapeOpUnop : widePullbackShapeUnop J ⋙ widePushoutShapeOp J ≅ 𝟭 _ := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The counit isomorphism of the equivalence `widePushoutShapeOpEquiv : (WidePushoutShape J)ᵒᵖ ≌ WidePullbackShape J` -/ def widePullbackShapeUnopOp : widePullbackShapeOp J ⋙ widePushoutShapeUnop J ≅ 𝟭 _ := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The duality equivalence `(WidePushoutShape J)ᵒᵖ ≌ WidePullbackShape J` -/ @[simps] diff --git a/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean b/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean index 259375ddca69a..baf5c502afa9e 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean @@ -144,7 +144,7 @@ section variable [HasZeroMorphisms D] instance : HasZeroMorphisms (C ⥤ D) where - zero F G := ⟨{ app := fun X => 0 }⟩ + zero F G := ⟨{ app := fun _ => 0 }⟩ comp_zero := fun η H => by ext X; dsimp; apply comp_zero zero_comp := fun F {G H} η => by @@ -252,7 +252,7 @@ open ZeroObject code should generally ask for an instance of `HasZeroMorphisms` separately, even if it already asks for an instance of `HasZeroObjects`. -/ def zeroMorphismsOfZeroObject : HasZeroMorphisms C where - zero X Y := { zero := (default : X ⟶ 0) ≫ default } + zero X _ := { zero := (default : X ⟶ 0) ≫ default } zero_comp X {Y Z} f := by change ((default : X ⟶ 0) ≫ default) ≫ f = (default : X ⟶ 0) ≫ default rw [Category.assoc] @@ -378,14 +378,14 @@ theorem idZeroEquivIsoZero_apply_inv (X : C) (h : 𝟙 X = 0) : ((idZeroEquivIso /-- If `0 : X ⟶ Y` is a monomorphism, then `X ≅ 0`. -/ @[simps] -def isoZeroOfMonoZero {X Y : C} (h : Mono (0 : X ⟶ Y)) : X ≅ 0 where +def isoZeroOfMonoZero {X Y : C} (_ : Mono (0 : X ⟶ Y)) : X ≅ 0 where hom := 0 inv := 0 hom_inv_id := (cancel_mono (0 : X ⟶ Y)).mp (by simp) /-- If `0 : X ⟶ Y` is an epimorphism, then `Y ≅ 0`. -/ @[simps] -def isoZeroOfEpiZero {X Y : C} (h : Epi (0 : X ⟶ Y)) : Y ≅ 0 where +def isoZeroOfEpiZero {X Y : C} (_ : Epi (0 : X ⟶ Y)) : Y ≅ 0 where hom := 0 inv := 0 hom_inv_id := (cancel_epi (0 : X ⟶ Y)).mp (by simp) @@ -523,7 +523,7 @@ def monoFactorisationZero (X Y : C) : MonoFactorisation (0 : X ⟶ Y) where -/ def imageFactorisationZero (X Y : C) : ImageFactorisation (0 : X ⟶ Y) where F := monoFactorisationZero X Y - isImage := { lift := fun F' => 0 } + isImage := { lift := fun _ => 0 } instance hasImage_zero {X Y : C} : HasImage (0 : X ⟶ Y) := HasImage.mk <| imageFactorisationZero _ _ diff --git a/Mathlib/CategoryTheory/Limits/Sifted.lean b/Mathlib/CategoryTheory/Limits/Sifted.lean new file mode 100644 index 0000000000000..8f5721d4f8dae --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Sifted.lean @@ -0,0 +1,104 @@ +/- +Copyright (c) 2024 Robin Carlier. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Carlier +-/ +import Mathlib.CategoryTheory.Limits.Final +/-! +# Sifted categories + +A category `C` is sifted if `C` is nonempty and the diagonal functor `C ⥤ C × C` is final. +Sifted categories can be characterized as those such that the colimit functor `(C ⥤ Type) ⥤ Type ` +preserves finite products. + +## Main results +- `isSifted_of_hasBinaryCoproducts_and_nonempty`: A nonempty category with binary coproducts is + sifted. + +## References +- [nLab, *Sifted category*](https://ncatlab.org/nlab/show/sifted+category) +- [*Algebraic Theories*, Chapter 2.][Adamek_Rosicky_Vitale_2010] +-/ + +universe w v v₁ u u₁ + +namespace CategoryTheory + +open Limits Functor + +section + +variable (C : Type u) [Category.{v} C] + +/-- A category `C` `IsSiftedOrEmpty` if the diagonal functor `C ⥤ C × C` is final. -/ +abbrev IsSiftedOrEmpty : Prop := Final (diag C) + +/-- A category `C` `IsSfited` if +1. the diagonal functor `C ⥤ C × C` is final. +2. there exists some object. -/ +class IsSifted extends IsSiftedOrEmpty C : Prop where + [nonempty : Nonempty C] + +attribute [instance] IsSifted.nonempty + +namespace IsSifted + +variable {C} + +/-- Being sifted is preserved by equivalences of categories -/ +lemma isSifted_of_equiv [IsSifted C] {D : Type u₁} [Category.{v₁} D] (e : D ≌ C) : IsSifted D := + letI : Final (diag D) := by + letI : D × D ≌ C × C:= Equivalence.prod e e + have sq : (e.inverse ⋙ diag D ⋙ this.functor ≅ diag C) := + NatIso.ofComponents (fun c ↦ by dsimp [this] + exact Iso.prod (e.counitIso.app c) (e.counitIso.app c)) + apply_rules [final_iff_comp_equivalence _ this.functor|>.mpr, + final_iff_final_comp e.inverse _ |>.mpr, final_of_natIso sq.symm] + letI : _root_.Nonempty D := ⟨e.inverse.obj (_root_.Nonempty.some IsSifted.nonempty)⟩ + ⟨⟩ + +/-- In particular a category is sifted iff and only if it is so when viewed as a small category -/ +lemma isSifted_iff_asSmallIsSifted : IsSifted C ↔ IsSifted (AsSmall.{w} C) where + mp _ := isSifted_of_equiv AsSmall.equiv.symm + mpr _ := isSifted_of_equiv AsSmall.equiv + +/-- A sifted category is connected. -/ +instance [IsSifted C] : IsConnected C := + isConnected_of_zigzag + (by intro c₁ c₂ + have X : StructuredArrow (c₁, c₂) (diag C) := + letI S : Final (diag C) := by infer_instance + Nonempty.some (S.out (c₁, c₂)).is_nonempty + use [X.right, c₂] + constructor + · constructor + · exact Zag.of_hom X.hom.fst + · simp + exact Zag.of_inv X.hom.snd + · rfl) + +/-- A category with binary coproducts is sifted or empty. -/ +instance [HasBinaryCoproducts C] : IsSiftedOrEmpty C := by + constructor + rintro ⟨c₁, c₂⟩ + haveI : _root_.Nonempty <| StructuredArrow (c₁,c₂) (diag C) := + ⟨.mk ((coprod.inl : c₁ ⟶ c₁ ⨿ c₂), (coprod.inr : c₂ ⟶ c₁ ⨿ c₂))⟩ + apply isConnected_of_zigzag + rintro ⟨_, c, f⟩ ⟨_, c', g⟩ + dsimp only [const_obj_obj, diag_obj, prod_Hom] at f g + use [.mk ((coprod.inl : c₁ ⟶ c₁ ⨿ c₂), (coprod.inr : c₂ ⟶ c₁ ⨿ c₂)), .mk (g.fst, g.snd)] + simp only [colimit.cocone_x, diag_obj, Prod.mk.eta, List.chain_cons, List.Chain.nil, and_true, + ne_eq, reduceCtorEq, not_false_eq_true, List.getLast_cons, List.cons_ne_self, + List.getLast_singleton] + exact ⟨⟨Zag.of_inv <| StructuredArrow.homMk <| coprod.desc f.fst f.snd, + Zag.of_hom <| StructuredArrow.homMk <| coprod.desc g.fst g.snd⟩, rfl⟩ + +/-- A nonempty category with binary coproducts is sifted. -/ +instance isSifted_of_hasBinaryCoproducts_and_nonempty [_root_.Nonempty C] [HasBinaryCoproducts C] : + IsSifted C where + +end IsSifted + +end + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Types.lean b/Mathlib/CategoryTheory/Limits/Types.lean index cfa274313257e..e278c77547635 100644 --- a/Mathlib/CategoryTheory/Limits/Types.lean +++ b/Mathlib/CategoryTheory/Limits/Types.lean @@ -632,9 +632,9 @@ instance : HasImageMaps (Type u) where have p := st.w replace p := congr_fun p (Classical.choose x.2) simp only [Functor.id_obj, Functor.id_map, types_comp_apply] at p - erw [p, Classical.choose_spec x.2]⟩⟩) rfl + rw [p, Classical.choose_spec x.2]⟩⟩) rfl -variable {F : ℕᵒᵖ ⥤ Type u} {c : Cone F} (hc : IsLimit c) +variable {F : ℕᵒᵖ ⥤ Type u} {c : Cone F} (hF : ∀ n, Function.Surjective (F.map (homOfLE (Nat.le_succ n)).op)) private noncomputable def limitOfSurjectionsSurjective.preimage diff --git a/Mathlib/CategoryTheory/Limits/VanKampen.lean b/Mathlib/CategoryTheory/Limits/VanKampen.lean index fc1ab0865d6d2..429dea9a1687b 100644 --- a/Mathlib/CategoryTheory/Limits/VanKampen.lean +++ b/Mathlib/CategoryTheory/Limits/VanKampen.lean @@ -701,7 +701,7 @@ theorem isVanKampenColimit_extendCofan {n : ℕ} (f : Fin (n + 1) → C) rotate_left · ext ⟨j⟩ dsimp - erw [colimit.ι_desc] -- Why? + rw [colimit.ι_desc] rfl simpa [Functor.const_obj_obj, Discrete.functor_obj, extendCofan_pt, extendCofan_ι_app, Fin.cases_succ, BinaryCofan.mk_pt, colimit.cocone_x, Cofan.mk_pt, Cofan.mk_ι_app, diff --git a/Mathlib/CategoryTheory/Limits/Yoneda.lean b/Mathlib/CategoryTheory/Limits/Yoneda.lean index 2442748a1c2e5..ed9f8ff3d339e 100644 --- a/Mathlib/CategoryTheory/Limits/Yoneda.lean +++ b/Mathlib/CategoryTheory/Limits/Yoneda.lean @@ -113,7 +113,7 @@ def yonedaJointlyReflectsLimits (F : J ⥤ Cᵒᵖ) (c : Cone F) application of `yoneda.obj X` for all `X : C`. -/ noncomputable def Limits.Cocone.isColimitYonedaEquiv {F : J ⥤ C} (c : Cocone F) : IsColimit c ≃ ∀ (X : C), IsLimit ((yoneda.obj X).mapCone c.op) where - toFun h X := isLimitOfPreserves _ h.op + toFun h _ := isLimitOfPreserves _ h.op invFun h := IsLimit.unop (yonedaJointlyReflectsLimits _ _ h) left_inv _ := Subsingleton.elim _ _ right_inv _ := by ext; apply Subsingleton.elim @@ -154,7 +154,7 @@ def coyonedaJointlyReflectsLimits (F : J ⥤ C) (c : Cone F) /-- A cone is limit iff it is so after the application of `coyoneda.obj X` for all `X : Cᵒᵖ`. -/ noncomputable def Limits.Cone.isLimitCoyonedaEquiv {F : J ⥤ C} (c : Cone F) : IsLimit c ≃ ∀ (X : Cᵒᵖ), IsLimit ((coyoneda.obj X).mapCone c) where - toFun h X := isLimitOfPreserves _ h + toFun h _ := isLimitOfPreserves _ h invFun h := coyonedaJointlyReflectsLimits _ _ h left_inv _ := Subsingleton.elim _ _ right_inv _ := by ext; apply Subsingleton.elim diff --git a/Mathlib/CategoryTheory/Linear/Basic.lean b/Mathlib/CategoryTheory/Linear/Basic.lean index 5f724dcf36cb9..b4d90d75d19a2 100644 --- a/Mathlib/CategoryTheory/Linear/Basic.lean +++ b/Mathlib/CategoryTheory/Linear/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Mathlib.Algebra.Algebra.Defs +import Mathlib.Algebra.Group.Invertible.Defs import Mathlib.Algebra.Module.Equiv.Defs import Mathlib.CategoryTheory.Preadditive.Basic diff --git a/Mathlib/CategoryTheory/Linear/FunctorCategory.lean b/Mathlib/CategoryTheory/Linear/FunctorCategory.lean index 54207426b1605..2796d5a4a8b9b 100644 --- a/Mathlib/CategoryTheory/Linear/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Linear/FunctorCategory.lean @@ -21,11 +21,6 @@ open CategoryTheory.Limits Linear variable {R : Type*} [Semiring R] variable {C D : Type*} [Category C] [Category D] [Preadditive D] [Linear R D] -#adaptation_note -/-- -At nightly-2024-08-08 we needed to significantly increase the maxHeartbeats here. --/ -set_option maxHeartbeats 800000 in instance functorCategoryLinear : Linear R (C ⥤ D) where homModule F G := { smul := fun r α => diff --git a/Mathlib/CategoryTheory/Linear/Yoneda.lean b/Mathlib/CategoryTheory/Linear/Yoneda.lean index 4836d3c76a695..ee468da7d7708 100644 --- a/Mathlib/CategoryTheory/Linear/Yoneda.lean +++ b/Mathlib/CategoryTheory/Linear/Yoneda.lean @@ -28,7 +28,7 @@ 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.ofHom` in the definition of `linearYoneda` +-- 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`, @@ -38,9 +38,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.ofHom (Linear.leftComp R _ f.unop) } + map := fun f => ModuleCat.asHom (Linear.leftComp R _ f.unop) } map {X₁ X₂} f := - { app := fun Y => @ModuleCat.ofHom R _ (Y.unop ⟶ X₁) (Y.unop ⟶ X₂) _ _ _ _ + { app := fun Y => @ModuleCat.asHom R _ (Y.unop ⟶ X₁) (Y.unop ⟶ X₂) _ _ _ _ (Linear.rightComp R _ f) } /-- The Yoneda embedding for `R`-linear categories `C`, @@ -50,9 +50,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.ofHom (Linear.rightComp R _ f) } + map := fun f => ModuleCat.asHom (Linear.rightComp R _ f) } map {Y₁ Y₂} f := - { app := fun X => @ModuleCat.ofHom R _ (unop Y₁ ⟶ X) (unop Y₂ ⟶ X) _ _ _ _ + { app := fun X => @ModuleCat.asHom 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/Bousfield.lean b/Mathlib/CategoryTheory/Localization/Bousfield.lean index 1dd1de3c1799e..209e43b314608 100644 --- a/Mathlib/CategoryTheory/Localization/Bousfield.lean +++ b/Mathlib/CategoryTheory/Localization/Bousfield.lean @@ -112,6 +112,7 @@ lemma W_adj_unit_app (X : D) : W (· ∈ Set.range F.obj) (adj.unit.app X) := by rintro _ ⟨Y, rfl⟩ convert ((Functor.FullyFaithful.ofFullyFaithful F).homEquiv.symm.trans (adj.homEquiv X Y)).bijective using 1 + dsimp [Adjunction.homEquiv] aesop lemma W_iff_isIso_map {X Y : D} (f : X ⟶ Y) : diff --git a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean index a46ca7ab8e22f..ab6a1a44daa7d 100644 --- a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean +++ b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean @@ -433,7 +433,7 @@ namespace Localization noncomputable instance : Category (Localization W) where Hom X Y := Localization.Hom W X Y - id X := Localization.Hom.mk (ofHom W (𝟙 _)) + id _ := Localization.Hom.mk (ofHom W (𝟙 _)) comp f g := f.comp g comp_id := by rintro (X Y : C) f @@ -500,7 +500,7 @@ lemma homMk_comp_homMk {X Y Z : C} (z₁ : W.LeftFraction X Y) (z₂ : W.LeftFra (z₃ : W.LeftFraction z₁.Y' z₂.Y') (h₃ : z₂.f ≫ z₃.s = z₁.s ≫ z₃.f) : homMk z₁ ≫ homMk z₂ = homMk (z₁.comp₀ z₂ z₃) := by change Hom.comp _ _ = _ - erw [Hom.comp_eq, comp_eq z₁ z₂ z₃ h₃] + rw [Hom.comp_eq, comp_eq z₁ z₂ z₃ h₃] lemma homMk_eq_of_leftFractionRel {X Y : C} (z₁ z₂ : W.LeftFraction X Y) (h : LeftFractionRel z₁ z₂) : @@ -581,7 +581,7 @@ when `W` has a left calculus of fractions. -/ noncomputable def lift (F : C ⥤ E) (hF : W.IsInvertedBy F) : Localization W ⥤ E where obj X := F.obj X - map {X Y : C} f := f.map F hF + map {_ _ : C} f := f.map F hF map_id := by intro (X : C) dsimp @@ -605,7 +605,7 @@ noncomputable def lift (F : C ⥤ E) (hF : W.IsInvertedBy F) : rw [F.map_comp, F.map_comp, map_comp_map_s_assoc] lemma fac (F : C ⥤ E) (hF : W.IsInvertedBy F) : Q W ⋙ lift F hF = F := - Functor.ext (fun X => rfl) (fun X Y f => by + Functor.ext (fun _ => rfl) (fun X Y f => by dsimp [lift] rw [Q_map, Hom.map_mk, id_comp, comp_id, map_ofHom]) diff --git a/Mathlib/CategoryTheory/Localization/Composition.lean b/Mathlib/CategoryTheory/Localization/Composition.lean index e89a94183c8dd..0c3a841aa980e 100644 --- a/Mathlib/CategoryTheory/Localization/Composition.lean +++ b/Mathlib/CategoryTheory/Localization/Composition.lean @@ -42,7 +42,7 @@ def StrictUniversalPropertyFixedTarget.comp refine MorphismProperty.IsInvertedBy.of_le _ _ _ ?_ hW₂₃ simpa only [MorphismProperty.IsInvertedBy.map_iff, h₁.fac F] using hF) fac F hF := by rw [Functor.assoc, h₂.fac, h₁.fac] - uniq F₁ F₂ h := h₂.uniq _ _ (h₁.uniq _ _ (by simpa only [Functor.assoc] using h)) + uniq _ _ h := h₂.uniq _ _ (h₁.uniq _ _ (by simpa only [Functor.assoc] using h)) end Localization diff --git a/Mathlib/CategoryTheory/Localization/Construction.lean b/Mathlib/CategoryTheory/Localization/Construction.lean index 67313fe467484..464e45092daf6 100644 --- a/Mathlib/CategoryTheory/Localization/Construction.lean +++ b/Mathlib/CategoryTheory/Localization/Construction.lean @@ -163,7 +163,7 @@ def lift : W.Localization ⥤ D := @[simp] theorem fac : W.Q ⋙ lift G hG = G := - Functor.ext (fun X => rfl) + Functor.ext (fun _ => rfl) (by intro X Y f simp only [Functor.comp_map, eqToHom_refl, comp_id, id_comp] @@ -197,7 +197,7 @@ localization with respect to a morphism_property `W` -/ def objEquiv : C ≃ W.Localization where toFun := W.Q.obj invFun X := X.as.obj - left_inv X := rfl + left_inv _ := rfl right_inv := by rintro ⟨⟨X⟩⟩ rfl diff --git a/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean b/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean index c0f59f13389ca..a0c71108f57aa 100644 --- a/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean +++ b/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean @@ -128,7 +128,7 @@ lemma isEquivalence_iff : G.IsEquivalence ↔ G'.IsEquivalence := end /-- Condition that a `LocalizerMorphism` induces an equivalence on the localized categories -/ -class IsLocalizedEquivalence : Prop := +class IsLocalizedEquivalence : Prop where /-- the induced functor on the constructed localized categories is an equivalence -/ isEquivalence : (Φ.localizedFunctor W₁.Q W₂.Q).IsEquivalence diff --git a/Mathlib/CategoryTheory/Localization/Predicate.lean b/Mathlib/CategoryTheory/Localization/Predicate.lean index dd06454204670..b56d44cf24b6c 100644 --- a/Mathlib/CategoryTheory/Localization/Predicate.lean +++ b/Mathlib/CategoryTheory/Localization/Predicate.lean @@ -95,7 +95,7 @@ of the localization. -/ @[simps] def strictUniversalPropertyFixedTargetId (hW : W ≤ MorphismProperty.isomorphisms C) : StrictUniversalPropertyFixedTarget (𝟭 C) W E where - inverts X Y f hf := hW f hf + inverts _ _ f hf := hW f hf lift F _ := F fac F hF := by cases F diff --git a/Mathlib/CategoryTheory/Localization/SmallHom.lean b/Mathlib/CategoryTheory/Localization/SmallHom.lean index aa27e2567dea6..bb6cb9ad83759 100644 --- a/Mathlib/CategoryTheory/Localization/SmallHom.lean +++ b/Mathlib/CategoryTheory/Localization/SmallHom.lean @@ -249,11 +249,7 @@ lemma equiv_smallHomMap (G : D₁ ⥤ D₂) (e : Φ.functor ⋙ L₂ ≅ L₁ have hγ : ∀ (X : C₁), γ.hom.app (W₁.Q.obj X) = E₂.map (β.inv.app X) ≫ α₂.hom.app (Φ.functor.obj X) ≫ e.hom.app X ≫ G.map (α₁.inv.app X) := fun X ↦ by - dsimp [γ] - rw [liftNatTrans_app] - dsimp - rw [id_comp, id_comp, comp_id] - erw [id_comp, comp_id] + simp [γ, id_comp, comp_id] simp only [Functor.map_comp, assoc] erw [← NatIso.naturality_1 γ] simp only [Functor.comp_map, ← cancel_epi (e.inv.app X), ← cancel_epi (G.map (α₁.hom.app X)), diff --git a/Mathlib/CategoryTheory/Localization/StructuredArrow.lean b/Mathlib/CategoryTheory/Localization/StructuredArrow.lean index 91c9d508c56f6..96c0af25daccb 100644 --- a/Mathlib/CategoryTheory/Localization/StructuredArrow.lean +++ b/Mathlib/CategoryTheory/Localization/StructuredArrow.lean @@ -5,7 +5,7 @@ Authors: Joël Riou -/ import Mathlib.CategoryTheory.Localization.HomEquiv import Mathlib.CategoryTheory.Localization.Opposite -import Mathlib.CategoryTheory.Comma.StructuredArrow +import Mathlib.CategoryTheory.Comma.StructuredArrow.Basic /-! # Induction principles for structured and costructured arrows diff --git a/Mathlib/CategoryTheory/Monad/Adjunction.lean b/Mathlib/CategoryTheory/Monad/Adjunction.lean index ebd45343a99da..7c5e8d990bb5a 100644 --- a/Mathlib/CategoryTheory/Monad/Adjunction.lean +++ b/Mathlib/CategoryTheory/Monad/Adjunction.lean @@ -76,12 +76,12 @@ def toComonad (h : L ⊣ R) : Comonad D where /-- The monad induced by the Eilenberg-Moore adjunction is the original monad. -/ @[simps!] def adjToMonadIso (T : Monad C) : T.adj.toMonad ≅ T := - MonadIso.mk (NatIso.ofComponents fun X => Iso.refl _) + MonadIso.mk (NatIso.ofComponents fun _ => Iso.refl _) /-- The comonad induced by the Eilenberg-Moore adjunction is the original comonad. -/ @[simps!] def adjToComonadIso (G : Comonad C) : G.adj.toComonad ≅ G := - ComonadIso.mk (NatIso.ofComponents fun X => Iso.refl _) + ComonadIso.mk (NatIso.ofComponents fun _ => Iso.refl _) /-- Given an adjunction `L ⊣ R`, if `L ⋙ R` is abstractly isomorphic to the identity functor, then the @@ -165,8 +165,8 @@ def Monad.comparison (h : L ⊣ R) : D ⥤ h.toMonad.Algebra where -/ @[simps] def Monad.comparisonForget (h : L ⊣ R) : Monad.comparison h ⋙ h.toMonad.forget ≅ R where - hom := { app := fun X => 𝟙 _ } - inv := { app := fun X => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } theorem Monad.left_comparison (h : L ⊣ R) : L ⋙ Monad.comparison h = h.toMonad.free := rfl @@ -210,8 +210,8 @@ def Comonad.comparison (h : L ⊣ R) : C ⥤ h.toComonad.Coalgebra where @[simps] def Comonad.comparisonForget {L : C ⥤ D} {R : D ⥤ C} (h : L ⊣ R) : Comonad.comparison h ⋙ h.toComonad.forget ≅ L where - hom := { app := fun X => 𝟙 _ } - inv := { app := fun X => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } theorem Comonad.left_comparison (h : L ⊣ R) : R ⋙ Comonad.comparison h = h.toComonad.cofree := rfl diff --git a/Mathlib/CategoryTheory/Monad/Basic.lean b/Mathlib/CategoryTheory/Monad/Basic.lean index 6a82f3d208edd..9fe82e5aa7b80 100644 --- a/Mathlib/CategoryTheory/Monad/Basic.lean +++ b/Mathlib/CategoryTheory/Monad/Basic.lean @@ -353,4 +353,32 @@ def transport {F : C ⥤ C} (T : Comonad C) (i : (T : C ⥤ C) ≅ F) : Comonad end Comonad +namespace Monad + +lemma map_unit_app (T : Monad C) (X : C) [IsIso T.μ] : + T.map (T.η.app X) = T.η.app (T.obj X) := by + simp [← cancel_mono (T.μ.app _)] + +lemma isSplitMono_iff_isIso_unit (T : Monad C) (X : C) [IsIso T.μ] : + IsSplitMono (T.η.app X) ↔ IsIso (T.η.app X) := by + refine ⟨fun _ ↦ ⟨retraction (T.η.app X), by simp, ?_⟩, fun _ ↦ inferInstance⟩ + erw [← map_id, ← IsSplitMono.id (T.η.app X), map_comp, T.map_unit_app X, T.η.naturality] + rfl + +end Monad + +namespace Comonad + +lemma map_counit_app (T : Comonad C) (X : C) [IsIso T.δ] : + T.map (T.ε.app X) = T.ε.app (T.obj X) := by + simp [← cancel_epi (T.δ.app _)] + +lemma isSplitEpi_iff_isIso_counit (T : Comonad C) (X : C) [IsIso T.δ] : + IsSplitEpi (T.ε.app X) ↔ IsIso (T.ε.app X) := by + refine ⟨fun _ ↦ ⟨section_ (T.ε.app X), ?_, by simp⟩, fun _ ↦ inferInstance⟩ + erw [← map_id, ← IsSplitEpi.id (T.ε.app X), map_comp, T.map_counit_app X, T.ε.naturality] + rfl + +end Comonad + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monad/Comonadicity.lean b/Mathlib/CategoryTheory/Monad/Comonadicity.lean index 7aeb43cea5361..2649f2cfb69b3 100644 --- a/Mathlib/CategoryTheory/Monad/Comonadicity.lean +++ b/Mathlib/CategoryTheory/Monad/Comonadicity.lean @@ -117,7 +117,7 @@ def rightAdjointComparison · apply comparisonRightAdjointHomEquiv · intro A B B' g h apply equalizer.hom_ext - simp + simp [Adjunction.homEquiv_unit] /-- Provided we have the appropriate equalizers, we have an adjunction to the comparison functor. -/ @@ -161,7 +161,7 @@ theorem comparisonAdjunction_counit_f (adj.unit.app (G.obj A.A))] (A : adj.toComonad.Coalgebra) : ((comparisonAdjunction adj).counit.app A).f = (beckEqualizer A).lift (counitFork A) := by - simp + simp [Adjunction.homEquiv_counit] variable (adj) @@ -205,7 +205,7 @@ theorem comparisonAdjunction_unit_app change equalizer.lift ((adj.homEquiv B _) (𝟙 _)) _ ≫ equalizer.ι _ _ = equalizer.lift _ _ ≫ equalizer.ι _ _ - simp + simp [Adjunction.homEquiv_unit] end ComonadicityInternal diff --git a/Mathlib/CategoryTheory/Monad/Kleisli.lean b/Mathlib/CategoryTheory/Monad/Kleisli.lean index 7b0bfe3c11446..e432473e5223b 100644 --- a/Mathlib/CategoryTheory/Monad/Kleisli.lean +++ b/Mathlib/CategoryTheory/Monad/Kleisli.lean @@ -44,7 +44,7 @@ instance [Inhabited C] (T : Monad C) : Inhabited (Kleisli T) := instance category : Category (Kleisli T) where Hom := fun X Y : C => X ⟶ (T : C ⥤ C).obj Y id X := T.η.app X - comp {X} {Y} {Z} f g := f ≫ (T : C ⥤ C).map g ≫ T.μ.app Z + comp {_} {_} {Z} f g := f ≫ (T : C ⥤ C).map g ≫ T.μ.app Z id_comp {X} {Y} f := by dsimp -- Porting note: unfold comp rw [← T.η.naturality_assoc f, T.left_unit] @@ -70,12 +70,12 @@ def toKleisli : C ⥤ Kleisli T where def fromKleisli : Kleisli T ⥤ C where obj X := T.obj X map {_} {Y} f := T.map f ≫ T.μ.app Y - map_id X := T.right_unit _ + map_id _ := T.right_unit _ map_comp {X} {Y} {Z} f g := by -- Porting note: hack for missing unfold_projs tactic change T.map (f ≫ T.map g ≫ T.μ.app Z) ≫ T.μ.app Z = _ simp only [Functor.map_comp, Category.assoc] - erw [← T.μ.naturality_assoc g, T.assoc] + rw [← T.μ.naturality_assoc g, T.assoc] rfl /-- The Kleisli adjunction which gives rise to the monad `(T, η_ T, μ_ T)`. @@ -92,7 +92,7 @@ def adj : toKleisli T ⊣ fromKleisli T := /-- The composition of the adjunction gives the original functor. -/ def toKleisliCompFromKleisliIsoSelf : toKleisli T ⋙ fromKleisli T ≅ T := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ end Adjunction @@ -116,7 +116,7 @@ instance [Inhabited C] (U : Comonad C) : Inhabited (Cokleisli U) := instance category : Category (Cokleisli U) where Hom := fun X Y : C => (U : C ⥤ C).obj X ⟶ Y id X := U.ε.app X - comp {X} {Y} {Z} f g := U.δ.app X ≫ (U : C ⥤ C).map f ≫ g + comp {X} {_} {_} f g := U.δ.app X ≫ (U : C ⥤ C).map f ≫ g id_comp f := by dsimp; rw [U.right_counit_assoc] assoc {X} {Y} {Z} {W} f g h := by -- Porting note: working around lack of unfold_projs @@ -143,7 +143,7 @@ def toCokleisli : C ⥤ Cokleisli U where def fromCokleisli : Cokleisli U ⥤ C where obj X := U.obj X map {X} {_} f := U.δ.app X ≫ U.map f - map_id X := U.right_counit _ + map_id _ := U.right_counit _ map_comp {X} {Y} {_} f g := by -- Porting note: working around lack of unfold_projs change U.δ.app X ≫ U.map (U.δ.app X ≫ U.map f ≫ g) = @@ -159,12 +159,12 @@ def adj : fromCokleisli U ⊣ toCokleisli U := homEquiv_naturality_right := fun {X} {Y} {_} f g => by -- Porting note: working around lack of unfold_projs change f ≫ g = U.δ.app X ≫ U.map f ≫ U.ε.app Y ≫ g - erw [← Category.assoc (U.map f), U.ε.naturality]; dsimp + rw [← Category.assoc (U.map f), U.ε.naturality]; dsimp simp only [← Category.assoc, Comonad.left_counit, Category.id_comp] } /-- The composition of the adjunction gives the original functor. -/ def toCokleisliCompFromCokleisliIsoSelf : toCokleisli U ⋙ fromCokleisli U ≅ U := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ end Adjunction diff --git a/Mathlib/CategoryTheory/Monad/Limits.lean b/Mathlib/CategoryTheory/Monad/Limits.lean index 1e1128d105453..11d531a830a9b 100644 --- a/Mathlib/CategoryTheory/Monad/Limits.lean +++ b/Mathlib/CategoryTheory/Monad/Limits.lean @@ -5,7 +5,7 @@ Authors: Kim Morrison, Bhavik Mehta, Jack McKoen -/ import Mathlib.CategoryTheory.Monad.Adjunction import Mathlib.CategoryTheory.Adjunction.Limits -import Mathlib.CategoryTheory.Limits.Shapes.Terminal +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal /-! # Limits and colimits in the category of (co)algebras diff --git a/Mathlib/CategoryTheory/Monad/Monadicity.lean b/Mathlib/CategoryTheory/Monad/Monadicity.lean index 5dbca1937d5e9..329b6f0907bb9 100644 --- a/Mathlib/CategoryTheory/Monad/Monadicity.lean +++ b/Mathlib/CategoryTheory/Monad/Monadicity.lean @@ -79,6 +79,13 @@ def comparisonLeftAdjointObj (A : adj.toMonad.Algebra) [HasCoequalizer (F.map A.a) (adj.counit.app _)] : D := coequalizer (F.map A.a) (adj.counit.app _) +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{ f : F.obj A.A ⟶ B // _ }`. +-/ +set_option linter.unusedVariables false in /-- We have a bijection of homsets which will be used to construct the left adjoint to the comparison functor. @@ -123,7 +130,7 @@ def leftAdjointComparison -- `Category.assoc`. -- dsimp [comparisonLeftAdjointHomEquiv] -- rw [← adj.homEquiv_naturality_right, Category.assoc] - simp [Cofork.IsColimit.homIso] + simp [Cofork.IsColimit.homIso, Adjunction.homEquiv_unit] /-- Provided we have the appropriate coequalizers, we have an adjunction to the comparison functor. -/ @@ -218,7 +225,7 @@ theorem comparisonAdjunction_counit_app change coequalizer.π _ _ ≫ coequalizer.desc ((adj.homEquiv _ B).symm (𝟙 _)) _ = coequalizer.π _ _ ≫ coequalizer.desc _ _ - simp + simp [Adjunction.homEquiv_counit] end MonadicityInternal diff --git a/Mathlib/CategoryTheory/Monad/Products.lean b/Mathlib/CategoryTheory/Monad/Products.lean index e7991fb4ef4d1..16ba3d6f08034 100644 --- a/Mathlib/CategoryTheory/Monad/Products.lean +++ b/Mathlib/CategoryTheory/Monad/Products.lean @@ -41,8 +41,8 @@ variable [HasBinaryProducts C] @[simps!] def prodComonad : Comonad C where toFunctor := prod.functor.obj X - ε := { app := fun Y => Limits.prod.snd } - δ := { app := fun Y => prod.lift Limits.prod.fst (𝟙 _) } + ε := { app := fun _ => Limits.prod.snd } + δ := { app := fun _ => prod.lift Limits.prod.fst (𝟙 _) } /-- The forward direction of the equivalence from coalgebras for the product comonad to the over category. @@ -73,7 +73,7 @@ def coalgebraEquivOver : Coalgebra (prodComonad X) ≌ Over X where functor := coalgebraToOver X inverse := overToCoalgebra X unitIso := NatIso.ofComponents fun A => - Coalgebra.isoMk (Iso.refl _) (prod.hom_ext (by simp) (by simpa using A.counit)) + Coalgebra.isoMk (Iso.refl _) (Limits.prod.hom_ext (by simp) (by simpa using A.counit)) counitIso := NatIso.ofComponents fun f => Over.isoMk (Iso.refl _) end @@ -88,8 +88,8 @@ variable [HasBinaryCoproducts C] @[simps!] def coprodMonad : Monad C where toFunctor := coprod.functor.obj X - η := { app := fun Y => coprod.inr } - μ := { app := fun Y => coprod.desc coprod.inl (𝟙 _) } + η := { app := fun _ => coprod.inr } + μ := { app := fun _ => coprod.desc coprod.inl (𝟙 _) } /-- The forward direction of the equivalence from algebras for the coproduct monad to the under category. diff --git a/Mathlib/CategoryTheory/Monad/Types.lean b/Mathlib/CategoryTheory/Monad/Types.lean index 2dc1cadcd2fa9..cddd9633c3ae8 100644 --- a/Mathlib/CategoryTheory/Monad/Types.lean +++ b/Mathlib/CategoryTheory/Monad/Types.lean @@ -34,7 +34,7 @@ variable (m : Type u → Type u) [_root_.Monad m] [LawfulMonad m] @[simps!] def ofTypeMonad : Monad (Type u) where toFunctor := ofTypeFunctor m - η := ⟨@pure m _, fun α β f => funext fun x => (LawfulApplicative.map_pure f x).symm⟩ + η := ⟨@pure m _, fun _ _ f => funext fun x => (LawfulApplicative.map_pure f x).symm⟩ μ := ⟨@joinM m _, fun α β (f : α → β) => funext fun a => by apply joinM_map_map⟩ assoc α := funext fun a => by apply joinM_map_joinM left_unit α := funext fun a => by apply joinM_pure @@ -48,7 +48,7 @@ def eq : KleisliCat m ≌ Kleisli (ofTypeMonad m) where functor := { obj := fun X => X map := fun f => f - map_id := fun X => rfl + map_id := fun _ => rfl map_comp := fun f g => by --unfold_projs funext t @@ -59,7 +59,7 @@ def eq : KleisliCat m ≌ Kleisli (ofTypeMonad m) where inverse := { obj := fun X => X map := fun f => f - map_id := fun X => rfl + map_id := fun _ => rfl map_comp := fun f g => by --unfold_projs -- Porting note: Need these instances for some lemmas below. diff --git a/Mathlib/CategoryTheory/Monoidal/Bimod.lean b/Mathlib/CategoryTheory/Monoidal/Bimod.lean index b4118c7d293bf..6182c9de23c17 100644 --- a/Mathlib/CategoryTheory/Monoidal/Bimod.lean +++ b/Mathlib/CategoryTheory/Monoidal/Bimod.lean @@ -120,7 +120,6 @@ instance : Category (Bimod A B) where id := id' comp f g := comp f g --- Porting note: added because `Hom.ext` is not triggered automatically @[ext] lemma hom_ext {M N : Bimod A B} (f g : M ⟶ N) (h : f.hom = g.hom) : f = g := Hom.ext h diff --git a/Mathlib/CategoryTheory/Monoidal/Bimon_.lean b/Mathlib/CategoryTheory/Monoidal/Bimon_.lean index 109f528c80123..2819cdeb108e5 100644 --- a/Mathlib/CategoryTheory/Monoidal/Bimon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Bimon_.lean @@ -29,7 +29,50 @@ universe v₁ v₂ u₁ u₂ u open CategoryTheory MonoidalCategory -variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] [BraidedCategory C] +variable {C : Type u₁} [Category.{v₁} C] [MonoidalCategory.{v₁} C] [BraidedCategory C] + +open scoped Mon_Class Comon_Class + +/-- +A bimonoid object in a braided category `C` is a object that is simultaneously monoid and comonoid +objects, and structure morphisms of them satisfy appropriate consistency conditions. +-/ +class Bimon_Class (M : C) extends Mon_Class M, Comon_Class M where + /- For the names of the conditions below, the unprimed names are reserved for the version where + the argument `M` is explicit. -/ + mul_comul' : μ[M] ≫ Δ[M] = (Δ[M] ⊗ Δ[M]) ≫ tensor_μ M M M M ≫ (μ[M] ⊗ μ[M]) := by aesop_cat + one_comul' : η[M] ≫ Δ[M] = η[M ⊗ M] := by aesop_cat + mul_counit' : μ[M] ≫ ε[M] = ε[M ⊗ M] := by aesop_cat + one_counit' : η[M] ≫ ε[M] = 𝟙 (𝟙_ C) := by aesop_cat + +namespace Bimon_Class + +/- The simp attribute is reserved for the unprimed versions. -/ +attribute [reassoc] mul_comul' one_comul' mul_counit' one_counit' + +variable (M : C) [Bimon_Class M] + +@[reassoc (attr := simp)] +theorem mul_comul (M : C) [Bimon_Class M] : + μ[M] ≫ Δ[M] = (Δ[M] ⊗ Δ[M]) ≫ tensor_μ M M M M ≫ (μ[M] ⊗ μ[M]) := + mul_comul' + +@[reassoc (attr := simp)] +theorem one_comul (M : C) [Bimon_Class M] : η[M] ≫ Δ[M] = η[M ⊗ M] := one_comul' + +@[reassoc (attr := simp)] +theorem mul_counit (M : C) [Bimon_Class M] : μ[M] ≫ ε[M] = ε[M ⊗ M] := mul_counit' + +@[reassoc (attr := simp)] +theorem one_counit (M : C) [Bimon_Class M] : η[M] ≫ ε[M] = 𝟙 (𝟙_ C) := one_counit' + +end Bimon_Class + +/-- The property that a morphism between bimonoid objects is a bimonoid morphism. -/ +class IsBimon_Hom {M N : C} [Bimon_Class M] [Bimon_Class N] (f : M ⟶ N) extends + IsMon_Hom f, IsComon_Hom f : Prop + +variable (C) /-- A bimonoid object in a braided category `C` is a comonoid object in the (monoidal) @@ -66,10 +109,6 @@ def toComon_ : Bimon_ C ⥤ Comon_ C := (Mon_.forgetMonoidal C).toOplaxMonoidalF @[simp] theorem toComon_forget : toComon_ C ⋙ Comon_.forget C = forget C := rfl --- TODO: the `set_option` is not strictly necessary, but the declaration is just a heartbeat --- away from using too many heartbeats. Squeezing `(d)simp` improves the situation, but pulls --- out too many lemmas -set_option maxHeartbeats 400000 in /-- The object level part of the forward direction of `Comon_ (Mon_ C) ≌ Mon_ (Comon_ C)` -/ def toMon_Comon_obj (M : Bimon_ C) : Mon_ (Comon_ C) where X := (toComon_ C).obj M diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean index ecac5bcd3be12..ee91313dea7f3 100644 --- a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean +++ b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean @@ -399,7 +399,6 @@ def comp (F : LaxBraidedFunctor C D) (G : LaxBraidedFunctor D E) : LaxBraidedFun instance categoryLaxBraidedFunctor : Category (LaxBraidedFunctor C D) := InducedCategory.category LaxBraidedFunctor.toLaxMonoidalFunctor --- Porting note: added, as `MonoidalNatTrans.ext` does not apply to morphisms. @[ext] lemma ext' {F G : LaxBraidedFunctor C D} {α β : F ⟶ G} (w : ∀ X : C, α.app X = β.app X) : α = β := MonoidalNatTrans.ext (funext w) @@ -463,7 +462,6 @@ def comp (F : BraidedFunctor C D) (G : BraidedFunctor D E) : BraidedFunctor C E instance categoryBraidedFunctor : Category (BraidedFunctor C D) := InducedCategory.category BraidedFunctor.toMonoidalFunctor --- Porting note: added, as `MonoidalNatTrans.ext` does not apply to morphisms. @[ext] lemma ext' {F G : BraidedFunctor C D} {α β : F ⟶ G} (w : ∀ X : C, α.app X = β.app X) : α = β := MonoidalNatTrans.ext (funext w) diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Reflection.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Reflection.lean new file mode 100644 index 0000000000000..665358fbb9504 --- /dev/null +++ b/Mathlib/CategoryTheory/Monoidal/Braided/Reflection.lean @@ -0,0 +1,233 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.CategoryTheory.Adjunction.Restrict +import Mathlib.CategoryTheory.Closed.Monoidal +import Mathlib.CategoryTheory.Monad.Adjunction +import Mathlib.CategoryTheory.Monoidal.Braided.Basic +import Mathlib.Tactic.TFAE +/-! + +# Day's reflection theorem + +Let `D` be a symmetric monoidal closed category and let `C` be a reflective subcategory. Day's +reflection theorem proves the equivalence of four conditions, which are all of the form that a +map obtained by acting on the unit of the reflective adjunction, with the internal hom and +tensor functors, is an isomorphism. + +Suppose that `C` is itself monoidal and that the reflector is a monoidal functor. Then we can +apply Day's reflection theorem to prove that `C` is also closed monoidal. + +## References + +- We follow the proof on nLab, see https://ncatlab.org/nlab/show/Day%27s+reflection+theorem. +- The original paper is [day1972] *A reflection theorem for closed categories*, by Day, 1972. +-/ + +open CategoryTheory Category MonoidalCategory MonoidalClosed BraidedCategory Functor + +namespace CategoryTheory.Monoidal.Reflective + +variable {C D : Type*} [Category C] [Category D] + +variable [MonoidalCategory D] [SymmetricCategory D] [MonoidalClosed D] + +section +variable {R : C ⥤ D} [R.Faithful] [R.Full] {L : D ⥤ C} (adj : L ⊣ R) + +/-- The uncurried retraction of the unit in the proof of `4 → 1` in `day_reflection` below. -/ +private noncomputable def adjRetractionAux + (c : C) (d : D) [IsIso (L.map (adj.unit.app ((ihom d).obj (R.obj c)) ⊗ adj.unit.app d))] : + d ⊗ ((L ⋙ R).obj ((ihom d).obj (R.obj c))) ⟶ (R.obj c) := + (β_ _ _).hom ≫ (_ ◁ adj.unit.app _) ≫ adj.unit.app _ ≫ + R.map (inv (L.map (adj.unit.app _ ⊗ adj.unit.app _))) ≫ (L ⋙ R).map (β_ _ _).hom ≫ + (L ⋙ R).map ((ihom.ev _).app _) ≫ inv (adj.unit.app _) + +/-- The retraction of the unit in the proof of `4 → 1` in `day_reflection` below. -/ +private noncomputable def adjRetraction (c : C) (d : D) + [IsIso (L.map (adj.unit.app ((ihom d).obj (R.obj c)) ⊗ adj.unit.app d))] : + (L ⋙ R).obj ((ihom d).obj (R.obj c)) ⟶ ((ihom d).obj (R.obj c)) := + curry <| adjRetractionAux adj c d + +private lemma adjRetraction_is_retraction (c : C) (d : D) + [IsIso (L.map (adj.unit.app ((ihom d).obj (R.obj c)) ⊗ adj.unit.app d))] : + adj.unit.app ((ihom d).obj (R.obj c)) ≫ adjRetraction adj c d = 𝟙 _ := by + suffices (_ ◁ adj.unit.app _) ≫ adjRetractionAux adj c d = (ihom.ev _).app _ by + simp only [id_obj, comp_obj, adjRetraction, ← curry_natural_left, this] + simp [curry_eq] + simp only [id_obj, comp_obj, adjRetractionAux, Functor.map_inv, Functor.comp_map, + braiding_naturality_right_assoc] + slice_lhs 2 3 => + simp only [← id_tensorHom, ← tensorHom_id, ← tensor_comp, Category.id_comp, Category.comp_id] + slice_lhs 2 4 => + rw [← adj.unit_naturality_assoc] + simp + +attribute [local simp] Adjunction.homEquiv_unit Adjunction.homEquiv_counit + +/-- +Day's reflection theorem. + +Let `D` be a symmetric monoidal closed category and let `C` be a reflective subcategory. Denote by +`R : C ⥤ D` the inclusion functor and by `L : D ⥤ C` the reflector. Let `u` denote the unit of the +adjunction `L ⊣ R`. Denote the internal hom by `[-,-]`. The following are equivalent: + +1. `u : [d, Rc] ⟶ RL[d, Rc]` is an isomorphism, +2. `[u, 𝟙] : [RLd, Rc] ⟶ [d, Rc]` is an isomorphism, +3. `L(u ▷ d') : L(d ⊗ d') ⟶ L(RLd ⊗ d')` is an isomorphism, +4. `L(u ⊗ u) : L(d ⊗ d') ⟶ L(RLd ⊗ RLd')` is an isomorphism, + +where `c, d, d'` are arbitrary objects of `C`/`D`, quantified over separately in each condition. +-/ +theorem isIso_tfae : List.TFAE + [ ∀ (c : C) (d : D), IsIso (adj.unit.app ((ihom d).obj (R.obj c))) + , ∀ (c : C) (d : D), IsIso ((pre (adj.unit.app d)).app (R.obj c)) + , ∀ (d d' : D), IsIso (L.map ((adj.unit.app d) ▷ d')) + , ∀ (d d' : D), IsIso (L.map ((adj.unit.app d) ⊗ (adj.unit.app d')))] := by + tfae_have 3 → 4 + · intro h + -- We can commute the tensor product in the condition that `L.map ((adj.unit.app d) ▷ d')` is + -- an isomorphism: + have h' : ∀ d d', IsIso (L.map (d ◁ (adj.unit.app d'))) := by + intro d d' + have := braiding_naturality (𝟙 d) (adj.unit.app d') + rw [← Iso.eq_comp_inv, id_tensorHom] at this + rw [this] + simp only [map_comp, id_obj, comp_obj, tensorHom_id, Category.assoc] + infer_instance + intro d d' + -- We then write the tensor product of the two units as the composition of the whiskered units, + -- and conclude. + have : (adj.unit.app d) ⊗ (adj.unit.app d') = + (adj.unit.app d ▷ d') ≫ (((L ⋙ R).obj _) ◁ adj.unit.app d') := by + simp [← tensorHom_id, ← id_tensorHom, ← tensor_comp] + rw [this, map_comp] + infer_instance + tfae_have 4 → 1 + · intros + -- It is enough to show that the unit is a split monomorphism, and the retraction is given + -- by `adjRetraction` above. + let _ : Reflective R := { L := L, adj := adj } + have : IsIso adj.toMonad.μ := μ_iso_of_reflective (R := R) + erw [← adj.toMonad.isSplitMono_iff_isIso_unit] + exact ⟨⟨adjRetraction adj _ _, adjRetraction_is_retraction adj _ _⟩⟩ + tfae_have 1 → 3 + · intro h d d' + rw [isIso_iff_isIso_coyoneda_map] + intro c + -- `w₁, w₃, w₄` are the three stacked commutative squares in the proof on nLab: + have w₁ : (coyoneda.map (L.map (adj.unit.app d ▷ d')).op).app c = (adj.homEquiv _ _).symm ∘ + (coyoneda.map (adj.unit.app d ▷ d').op).app (R.obj c) ∘ adj.homEquiv _ _ := by ext; simp + rw [w₁, isIso_iff_bijective] + simp only [comp_obj, coyoneda_obj_obj, id_obj, EquivLike.comp_bijective, + EquivLike.bijective_comp] + -- We commute the tensor product using the auxiliary commutative square `w₂`. + have w₂ : ((coyoneda.map (adj.unit.app d ▷ d').op).app (R.obj c)) = + ((yoneda.obj (R.obj c)).mapIso (β_ _ _)).hom ∘ + ((coyoneda.map (d' ◁ adj.unit.app d).op).app (R.obj c)) ∘ + ((yoneda.obj (R.obj c)).mapIso (β_ _ _)).hom := by ext; simp + rw [w₂, ← types_comp, ← types_comp, ← isIso_iff_bijective] + refine IsIso.comp_isIso' (IsIso.comp_isIso' inferInstance ?_) inferInstance + have w₃ : ((coyoneda.map (d' ◁ adj.unit.app d).op).app (R.obj c)) = + ((ihom.adjunction d').homEquiv _ _).symm ∘ + ((coyoneda.map (adj.unit.app _).op).app _) ∘ (ihom.adjunction d').homEquiv _ _ := by + ext + simp only [id_obj, op_tensorObj, coyoneda_obj_obj, unop_tensorObj, comp_obj, + coyoneda_map_app, Quiver.Hom.unop_op, Function.comp_apply, + Adjunction.homEquiv_unit, Adjunction.homEquiv_counit] + simp + rw [w₃, isIso_iff_bijective] + simp only [comp_obj, op_tensorObj, coyoneda_obj_obj, unop_tensorObj, id_obj, + yoneda_obj_obj, tensorLeft_obj, EquivLike.comp_bijective, EquivLike.bijective_comp] + have w₄ : (coyoneda.map (adj.unit.app d).op).app ((ihom d').obj (R.obj c)) ≫ + (coyoneda.obj ⟨d⟩).map (adj.unit.app ((ihom d').obj (R.obj c))) = + (coyoneda.obj ⟨(L ⋙ R).obj d⟩).map (adj.unit.app ((ihom d').obj (R.obj c))) ≫ + (coyoneda.map (adj.unit.app d).op).app _ := by simp + rw [← isIso_iff_bijective] + suffices IsIso ((coyoneda.map (adj.unit.app d).op).app ((ihom d').obj (R.obj c)) ≫ + (coyoneda.obj ⟨d⟩).map (adj.unit.app ((ihom d').obj (R.obj c)))) from + IsIso.of_isIso_comp_right _ ((coyoneda.obj ⟨d⟩).map (adj.unit.app ((ihom d').obj (R.obj c)))) + rw [w₄] + refine IsIso.comp_isIso' inferInstance ?_ + constructor + -- We give the inverse of the bottom map in the stack of commutative squares: + refine ⟨fun f ↦ R.map ((adj.homEquiv _ _).symm f), ?_, by ext; simp⟩ + ext f + simp only [comp_obj, coyoneda_obj_obj, id_obj, Adjunction.homEquiv_counit, + map_comp, types_comp_apply, coyoneda_map_app, Quiver.Hom.unop_op, Category.assoc, + types_id_apply] + have : f = R.map (R.preimage f) := by simp + rw [this] + simp [← map_comp, ← map_comp_assoc, -map_preimage] + tfae_have 2 ↔ 3 + · conv => lhs; intro c d; rw [isIso_iff_isIso_yoneda_map] + conv => rhs; intro d d'; rw [isIso_iff_isIso_coyoneda_map] + -- bring the quantifiers out of the `↔`: + rw [forall_swap]; apply forall_congr'; intro d + rw [forall_swap]; apply forall₂_congr; intro d' c + -- `w₁, w₂,` are the two stacked commutative squares in the proof on nLab: + have w₁ : ((coyoneda.map (L.map (adj.unit.app d ▷ d')).op).app c) = + (adj.homEquiv _ _).symm ∘ + (coyoneda.map (adj.unit.app d ▷ d').op).app (R.obj c) ∘ + (adj.homEquiv _ _) := by ext; simp + have w₂ : ((yoneda.map ((pre (adj.unit.app d)).app (R.obj c))).app ⟨d'⟩) = + ((ihom.adjunction d).homEquiv _ _) ∘ + ((coyoneda.map (adj.unit.app d ▷ d').op).app (R.obj c)) ∘ + ((ihom.adjunction ((L ⋙ R).obj d)).homEquiv _ _).symm := by + rw [← Function.comp_assoc, ((ihom.adjunction ((L ⋙ R).obj d)).homEquiv _ _).eq_comp_symm] + ext + simp only [id_obj, yoneda_obj_obj, comp_obj, Function.comp_apply, + yoneda_map_app, op_tensorObj, coyoneda_obj_obj, unop_tensorObj, op_whiskerRight, + coyoneda_map_app, unop_whiskerRight, Quiver.Hom.unop_op] + rw [Adjunction.homEquiv_unit, Adjunction.homEquiv_unit] + simp + rw [w₂, w₁, isIso_iff_bijective, isIso_iff_bijective] + simp + tfae_finish + +end + +section +variable [MonoidalCategory C] +variable {L : MonoidalFunctor D C} {R : C ⥤ D} [R.Faithful] [R.Full] (adj : L.toFunctor ⊣ R) + +instance (d d' : D) : IsIso (L.map ((adj.unit.app d) ⊗ (adj.unit.app d'))) := by + have := L.μ_natural (adj.unit.app d) (adj.unit.app d') + change _ = (asIso _).hom ≫ _ at this + rw [← Iso.inv_comp_eq] at this + rw [← this] + infer_instance + +instance (c : C) (d : D) : IsIso (adj.unit.app ((ihom d).obj (R.obj c))) := by + revert c d + rw [((isIso_tfae adj).out 0 3:)] + intro d d' + infer_instance + +/-- Auxiliary definition for `monoidalClosed`. -/ +noncomputable def closed (c : C) : Closed c where + rightAdj := R ⋙ (ihom (R.obj c)) ⋙ L.toFunctor + adj := by + refine ((ihom.adjunction (R.obj c)).comp adj).restrictFullyFaithful + (FullyFaithful.ofFullyFaithful R) + (FullyFaithful.id _) ?_ ?_ + · refine NatIso.ofComponents (fun _ ↦ ?_) (fun _ ↦ ?_) + · exact (asIso (L.μ _ _)).symm ≪≫ asIso ((adj.counit.app _) ⊗ (adj.counit.app _)) + · simp only [comp_obj, id_obj, Functor.comp_map, tensorLeft_map, Iso.trans_hom, Iso.symm_hom, + asIso_inv, asIso_hom, Functor.id_map, Category.assoc, IsIso.eq_inv_comp] + rw [← L.μ_natural_right_assoc] + simp [← id_tensorHom, ← tensor_comp] + · exact NatIso.ofComponents (fun _ ↦ asIso (adj.unit.app ((ihom _).obj _))) + +/-- +Given a reflective functor `R : C ⥤ D` with a monoidal left adjoint, such that `D` is symmetric +monoidal closed, then `C` is monoidal closed. +-/ +noncomputable def monoidalClosed : MonoidalClosed C where + closed c := closed adj c + +end + +end CategoryTheory.Monoidal.Reflective diff --git a/Mathlib/CategoryTheory/Monoidal/Cartesian/Comon_.lean b/Mathlib/CategoryTheory/Monoidal/Cartesian/Comon_.lean index 371f989126f86..0f5506988110d 100644 --- a/Mathlib/CategoryTheory/Monoidal/Cartesian/Comon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Cartesian/Comon_.lean @@ -61,4 +61,4 @@ to the category itself, via the forgetful functor. functor := Comon_.forget C inverse := cartesianComon_ C unitIso := NatIso.ofComponents (fun A => iso_cartesianComon_ A) - counitIso := NatIso.ofComponents (fun X => Iso.refl _) + counitIso := NatIso.ofComponents (fun _ => Iso.refl _) diff --git a/Mathlib/CategoryTheory/Monoidal/Center.lean b/Mathlib/CategoryTheory/Monoidal/Center.lean index 5eab3c67802ba..3e6f4d3046f5a 100644 --- a/Mathlib/CategoryTheory/Monoidal/Center.lean +++ b/Mathlib/CategoryTheory/Monoidal/Center.lean @@ -278,7 +278,7 @@ theorem associator_hom_f (X Y Z : Center C) : Hom.f (α_ X Y Z).hom = (α_ X.1 Y @[simp] theorem associator_inv_f (X Y Z : Center C) : Hom.f (α_ X Y Z).inv = (α_ X.1 Y.1 Z.1).inv := by - apply Iso.inv_ext' -- Porting note: Originally `ext` + apply Iso.inv_ext' -- Porting note (#11041): Originally `ext` rw [← associator_hom_f, ← comp_f, Iso.hom_inv_id]; rfl @[simp] @@ -287,7 +287,7 @@ theorem leftUnitor_hom_f (X : Center C) : Hom.f (λ_ X).hom = (λ_ X.1).hom := @[simp] theorem leftUnitor_inv_f (X : Center C) : Hom.f (λ_ X).inv = (λ_ X.1).inv := by - apply Iso.inv_ext' -- Porting note: Originally `ext` + apply Iso.inv_ext' -- Porting note (#11041): Originally `ext` rw [← leftUnitor_hom_f, ← comp_f, Iso.hom_inv_id]; rfl @[simp] @@ -296,7 +296,7 @@ theorem rightUnitor_hom_f (X : Center C) : Hom.f (ρ_ X).hom = (ρ_ X.1).hom := @[simp] theorem rightUnitor_inv_f (X : Center C) : Hom.f (ρ_ X).inv = (ρ_ X.1).inv := by - apply Iso.inv_ext' -- Porting note: Originally `ext` + apply Iso.inv_ext' -- Porting note (#11041): Originally `ext` rw [← rightUnitor_hom_f, ← comp_f, Iso.hom_inv_id]; rfl end diff --git a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean index b8a3c549ea911..95ff7663a6476 100644 --- a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean @@ -50,8 +50,6 @@ theorem comp_hom {R S T : CommMon_ C} (f : R ⟶ S) (g : S ⟶ T) : Mon_.Hom.hom (f ≫ g) = f.hom ≫ g.hom := rfl --- Porting note (#5229): added because `Mon_.Hom.ext` is not triggered automatically --- for morphisms in `CommMon_ C` @[ext] lemma hom_ext {A B : CommMon_ C} (f g : A ⟶ B) (h : f.hom = g.hom) : f = g := Mon_.Hom.ext h diff --git a/Mathlib/CategoryTheory/Monoidal/Comon_.lean b/Mathlib/CategoryTheory/Monoidal/Comon_.lean index 61c63c58ac902..ac2283e8e7402 100644 --- a/Mathlib/CategoryTheory/Monoidal/Comon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Comon_.lean @@ -29,7 +29,58 @@ universe v₁ v₂ u₁ u₂ u open CategoryTheory MonoidalCategory -variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] +variable {C : Type u₁} [Category.{v₁} C] [MonoidalCategory.{v₁} C] + +/-- A comonoid object internal to a monoidal category. + +When the monoidal category is preadditive, this is also sometimes called a "coalgebra object". +-/ +class Comon_Class (X : C) where + /-- The counit morphism of a comonoid object. -/ + counit : X ⟶ 𝟙_ C + /-- The comultiplication morphism of a comonoid object. -/ + comul : X ⟶ X ⊗ X + /- For the names of the conditions below, the unprimed names are reserved for the version where + the argument `X` is explicit. -/ + counit_comul' : comul ≫ counit ▷ X = (λ_ X).inv := by aesop_cat + comul_counit' : comul ≫ X ◁ counit = (ρ_ X).inv := by aesop_cat + comul_assoc' : comul ≫ X ◁ comul = comul ≫ (comul ▷ X) ≫ (α_ X X X).hom := by aesop_cat + +namespace Comon_Class + +@[inherit_doc] scoped notation "Δ" => Comon_Class.comul +@[inherit_doc] scoped notation "Δ["M"]" => Comon_Class.comul (X := M) +@[inherit_doc] scoped notation "ε" => Comon_Class.counit +@[inherit_doc] scoped notation "ε["M"]" => Comon_Class.counit (X := M) + +/- The simp attribute is reserved for the unprimed versions. -/ +attribute [reassoc] counit_comul' comul_counit' comul_assoc' + +@[reassoc (attr := simp)] +theorem counit_comul (X : C) [Comon_Class X] : Δ ≫ ε ▷ X = (λ_ X).inv := counit_comul' + +@[reassoc (attr := simp)] +theorem comul_counit (X : C) [Comon_Class X] : Δ ≫ X ◁ ε = (ρ_ X).inv := comul_counit' + +@[reassoc (attr := simp)] +theorem comul_assoc (X : C) [Comon_Class X] : + Δ ≫ X ◁ Δ = Δ ≫ Δ ▷ X ≫ (α_ X X X).hom := + comul_assoc' + +end Comon_Class + +open scoped Comon_Class + +variable {M N : C} [Comon_Class M] [Comon_Class N] + +/-- The property that a morphism between comonoid objects is a comonoid morphism. -/ +class IsComon_Hom (f : M ⟶ N) : Prop where + hom_counit : f ≫ ε = ε := by aesop_cat + hom_comul : f ≫ Δ = Δ ≫ (f ⊗ f) := by aesop_cat + +attribute [reassoc (attr := simp)] IsComon_Hom.hom_counit IsComon_Hom.hom_comul + +variable (C) /-- A comonoid object internal to a monoidal category. @@ -52,6 +103,24 @@ attribute [reassoc (attr := simp)] Comon_.comul_assoc namespace Comon_ +variable {C} + +/-- Construct an object of `Comon_ C` from an object `X : C` and `Comon_Class X` instance. -/ +@[simps] +def mk' (X : C) [Comon_Class X] : Comon_ C where + X := X + counit := ε + comul := Δ + +instance {M : Comon_ C} : Comon_Class M.X where + counit := M.counit + comul := M.comul + counit_comul' := M.counit_comul + comul_counit' := M.comul_counit + comul_assoc' := M.comul_assoc + +variable (C) + /-- The trivial comonoid object. We later show this is terminal in `Comon_ C`. -/ @[simps] @@ -251,6 +320,9 @@ variable [BraidedCategory C] theorem tensorObj_X (A B : Comon_ C) : (A ⊗ B).X = A.X ⊗ B.X := rfl +instance (A B : C) [Comon_Class A] [Comon_Class B] : Comon_Class (A ⊗ B) := + inferInstanceAs <| Comon_Class (Comon_.mk' A ⊗ Comon_.mk' B).X + theorem tensorObj_counit (A B : Comon_ C) : (A ⊗ B).counit = (A.counit ⊗ B.counit) ≫ (λ_ _).hom := rfl @@ -281,8 +353,8 @@ theorem tensorObj_comul (A B : Comon_ C) : /-- The forgetful functor from `Comon_ C` to `C` is monoidal when `C` is braided monoidal. -/ def forgetMonoidal : MonoidalFunctor (Comon_ C) C := { forget C with - ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + «ε» := 𝟙 _ + μ := fun _ _ => 𝟙 _ } @[simp] theorem forgetMonoidal_toFunctor : (forgetMonoidal C).toFunctor = forget C := rfl @[simp] theorem forgetMonoidal_ε : (forgetMonoidal C).ε = 𝟙 (𝟙_ C) := rfl diff --git a/Mathlib/CategoryTheory/Monoidal/Discrete.lean b/Mathlib/CategoryTheory/Monoidal/Discrete.lean index 9ff8e09d5151e..5cd7283da6587 100644 --- a/Mathlib/CategoryTheory/Monoidal/Discrete.lean +++ b/Mathlib/CategoryTheory/Monoidal/Discrete.lean @@ -32,7 +32,7 @@ instance Discrete.monoidal : MonoidalCategory (Discrete M) where tensorHom f g := eqToHom (by dsimp; rw [eq_of_hom f, eq_of_hom g]) leftUnitor X := Discrete.eqToIso (one_mul X.as) rightUnitor X := Discrete.eqToIso (mul_one X.as) - associator X Y Z := Discrete.eqToIso (mul_assoc _ _ _) + associator _ _ _ := Discrete.eqToIso (mul_assoc _ _ _) @[to_additive (attr := simp) Discrete.addMonoidal_tensorUnit_as] lemma Discrete.monoidal_tensorUnit_as : (𝟙_ (Discrete M)).as = 1 := rfl @@ -62,7 +62,7 @@ variable {K : Type u} [Monoid K] def Discrete.monoidalFunctorComp (F : M →* N) (G : N →* K) : Discrete.monoidalFunctor F ⊗⋙ Discrete.monoidalFunctor G ≅ Discrete.monoidalFunctor (G.comp F) where - hom := { app := fun X => 𝟙 _ } - inv := { app := fun X => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean index dede6e2f54295..0b89555d628e9 100644 --- a/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean +++ b/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean @@ -158,7 +158,7 @@ instance : MonoidalCategory (F C) where tensorHom_def := by rintro W X Y Z ⟨f⟩ ⟨g⟩ exact Quotient.sound (tensorHom_def _ _) - tensor_id X Y := Quot.sound tensor_id + tensor_id _ _ := Quot.sound tensor_id tensor_comp := @fun X₁ Y₁ Z₁ X₂ Y₂ Z₂ => by rintro ⟨f₁⟩ ⟨f₂⟩ ⟨g₁⟩ ⟨g₂⟩ exact Quotient.sound (tensor_comp _ _ _ _) @@ -179,8 +179,8 @@ instance : MonoidalCategory (F C) where rightUnitor_naturality := @fun X Y => by rintro ⟨f⟩ exact Quotient.sound (ρ_naturality _) - pentagon W X Y Z := Quotient.sound pentagon - triangle X Y := Quotient.sound triangle + pentagon _ _ _ _ := Quotient.sound pentagon + triangle _ _ := Quotient.sound triangle @[simp] theorem mk_comp {X Y Z : F C} (f : X ⟶ᵐ Y) (g : Y ⟶ᵐ Z) : @@ -366,7 +366,7 @@ def project : MonoidalFunctor (F C) D where -- In any case I don't understand why we need to specify `using Quotient.recOn`. map_comp := by rintro _ _ _ ⟨_⟩ ⟨_⟩; rfl ε := 𝟙 _ - μ X Y := 𝟙 _ + μ _ _ := 𝟙 _ μ_natural_left := fun f _ => by induction' f using Quotient.recOn · dsimp diff --git a/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean b/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean index 267ea5f8e51c9..2a14ad4a827e9 100644 --- a/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean +++ b/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean @@ -161,7 +161,7 @@ def fullNormalize : F C ⥤ N C where @[simp] def tensorFunc : F C ⥤ N C ⥤ F C where obj X := Discrete.functor fun n => inclusion.obj ⟨n⟩ ⊗ X - map f := Discrete.natTrans (fun n => _ ◁ f) + map f := Discrete.natTrans (fun _ => _ ◁ f) theorem tensorFunc_map_app {X Y : F C} (f : X ⟶ Y) (n) : ((tensorFunc C).map f).app n = _ ◁ f := rfl @@ -197,7 +197,7 @@ def normalizeIsoApp' : theorem normalizeIsoApp_eq : ∀ (X : F C) (n : N C), normalizeIsoApp C X n = normalizeIsoApp' C X n.as - | of X, _ => rfl + | of _, _ => rfl | unit, _ => rfl | tensor X Y, n => by rw [normalizeIsoApp, normalizeIsoApp'] diff --git a/Mathlib/CategoryTheory/Monoidal/Functor.lean b/Mathlib/CategoryTheory/Monoidal/Functor.lean index 1cd5fbc682a6c..4f367c8c6a40a 100644 --- a/Mathlib/CategoryTheory/Monoidal/Functor.lean +++ b/Mathlib/CategoryTheory/Monoidal/Functor.lean @@ -309,6 +309,27 @@ noncomputable def MonoidalFunctor.toOplaxMonoidalFunctor (F : MonoidalFunctor C rw [← F.map_comp, Iso.hom_inv_id, F.map_id] simp } +/-- Construct a (strong) monoidal functor out of an oplax monoidal functor whose tensorators and +unitors are isomorphisms -/ +@[simps] +noncomputable def MonoidalFunctor.fromOplaxMonoidalFunctor (F : OplaxMonoidalFunctor C D) + [IsIso F.η] [∀ (X Y : C), IsIso (F.δ X Y)] : MonoidalFunctor C D := + { F with + ε := inv F.η + μ := fun X Y => inv (F.δ X Y) + associativity := by + intro X Y Z + rw [← inv_whiskerRight, IsIso.inv_comp_eq, IsIso.inv_comp_eq] + simp + left_unitality := by + intro X + rw [← inv_whiskerRight, ← IsIso.inv_comp_eq] + simp + right_unitality := by + intro X + rw [← inv_whiskerLeft, ← IsIso.inv_comp_eq] + simp } + end open MonoidalCategory @@ -322,7 +343,7 @@ variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] def id : LaxMonoidalFunctor.{v₁, v₁} C C := { 𝟭 C with ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + μ := fun _ _ => 𝟙 _ } instance : Inhabited (LaxMonoidalFunctor C C) := ⟨id C⟩ @@ -338,7 +359,7 @@ variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] def id : OplaxMonoidalFunctor.{v₁, v₁} C C := { 𝟭 C with η := 𝟙 _ - δ := fun X Y => 𝟙 _ } + δ := fun _ _ => 𝟙 _ } instance : Inhabited (OplaxMonoidalFunctor C C) := ⟨id C⟩ @@ -457,7 +478,7 @@ variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] def id : MonoidalFunctor.{v₁, v₁} C C := { 𝟭 C with ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + μ := fun _ _ => 𝟙 _ } instance : Inhabited (MonoidalFunctor C C) := ⟨id C⟩ @@ -558,7 +579,7 @@ variable (C) def diag : MonoidalFunctor C (C × C) := { Functor.diag C with ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + μ := fun _ _ => 𝟙 _ } end MonoidalFunctor @@ -715,10 +736,12 @@ noncomputable def monoidalAdjoint : instance [F.IsEquivalence] : IsIso (monoidalAdjoint F h).ε := by dsimp + rw [Adjunction.homEquiv_unit] infer_instance instance (X Y : D) [F.IsEquivalence] : IsIso ((monoidalAdjoint F h).μ X Y) := by dsimp + rw [Adjunction.homEquiv_unit] infer_instance /-- If a monoidal functor `F` is an equivalence of categories then its inverse is also monoidal. -/ diff --git a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean index 5a69edb48708b..e06040b2769af 100644 --- a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean @@ -165,7 +165,7 @@ the natural pointwise monoidal structure on the functor category `C ⥤ D` is also braided. -/ instance functorCategoryBraided : BraidedCategory (C ⥤ D) where - braiding F G := NatIso.ofComponents fun X => β_ _ _ + braiding F G := NatIso.ofComponents fun _ => β_ _ _ hexagon_forward F G H := by ext X; apply hexagon_forward hexagon_reverse F G H := by ext X; apply hexagon_reverse diff --git a/Mathlib/CategoryTheory/Monoidal/Functorial.lean b/Mathlib/CategoryTheory/Monoidal/Functorial.lean index 5f9d7be6fbb24..652d56766ced5 100644 --- a/Mathlib/CategoryTheory/Monoidal/Functorial.lean +++ b/Mathlib/CategoryTheory/Monoidal/Functorial.lean @@ -132,7 +132,7 @@ section instance laxMonoidalId : LaxMonoidal.{v₁, v₁} (id : C → C) where ε := 𝟙 _ - μ X Y := 𝟙 _ + μ _ _ := 𝟙 _ end diff --git a/Mathlib/CategoryTheory/Monoidal/Hopf_.lean b/Mathlib/CategoryTheory/Monoidal/Hopf_.lean index 4bf50784e7cc7..e9e5220ef1ddc 100644 --- a/Mathlib/CategoryTheory/Monoidal/Hopf_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Hopf_.lean @@ -22,7 +22,40 @@ universe v₁ v₂ u₁ u₂ u open CategoryTheory MonoidalCategory -variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] [BraidedCategory C] +variable {C : Type u₁} [Category.{v₁} C] [MonoidalCategory.{v₁} C] [BraidedCategory C] + +open scoped Mon_Class Comon_Class + +/-- +A Hopf monoid in a braided category `C` is a bimonoid object in `C` equipped with an antipode. +-/ +class Hopf_Class (X : C) extends Bimon_Class X where + /-- The antipode is an endomorphism of the underlying object of the Hopf monoid. -/ + antipode : X ⟶ X + /- For the names of the conditions below, the unprimed names are reserved for the version where + the argument `X` is explicit. -/ + antipode_left' : Δ ≫ antipode ▷ X ≫ μ = ε ≫ η := by aesop_cat + antipode_right' : Δ ≫ X ◁ antipode ≫ μ = ε ≫ η := by aesop_cat + +namespace Hopf_Class + +@[inherit_doc] scoped notation "𝒮" => Hopf_Class.antipode +@[inherit_doc] scoped notation "𝒮["X"]" => Hopf_Class.antipode (X := X) + +/- The simp attribute is reserved for the unprimed versions. -/ +attribute [reassoc] antipode_left' antipode_right' + +/-- The object is provided as an explicit argument. -/ +@[reassoc (attr := simp)] +theorem antipode_left (X : C) [Hopf_Class X] : Δ ≫ 𝒮 ▷ X ≫ μ = ε ≫ η := antipode_left' + +/-- The object is provided as an explicit argument. -/ +@[reassoc (attr := simp)] +theorem antipode_right (X : C) [Hopf_Class X] : Δ ≫ X ◁ 𝒮 ≫ μ = ε ≫ η := antipode_right' + +end Hopf_Class + +variable (C) /-- A Hopf monoid in a braided category `C` is a bimonoid object in `C` equipped with an antipode. diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean index 6d90406b86532..6678552572fca 100644 --- a/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean @@ -86,7 +86,7 @@ def inverse : (C ⥤ Mon_ D) ⥤ Mon_ (C ⥤ D) where map α := { hom := { app := fun X => (α.app X).hom - naturality := fun X Y f => congr_arg Mon_.Hom.hom (α.naturality f) } } + naturality := fun _ _ f => congr_arg Mon_.Hom.hom (α.naturality f) } } /-- The unit for the equivalence `Mon_ (C ⥤ D) ≌ C ⥤ Mon_ D`. -/ @@ -170,7 +170,7 @@ private def inverse : (C ⥤ Comon_ D) ⥤ Comon_ (C ⥤ D) where map α := { hom := { app := fun X => (α.app X).hom - naturality := fun X Y f => congr_arg Comon_.Hom.hom (α.naturality f) } + naturality := fun _ _ f => congr_arg Comon_.Hom.hom (α.naturality f) } hom_counit := by ext x; dsimp; rw [(α.app x).hom_counit] hom_comul := by ext x; dsimp; rw [(α.app x).hom_comul] } diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean index 2e6df6e377f89..65be75a189756 100644 --- a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean +++ b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean @@ -88,7 +88,7 @@ theorem algebraMap (A : Mon_ (ModuleCat.{u} R)) (r : R) : algebraMap R A.X r = A @[simps!] def functor : Mon_ (ModuleCat.{u} R) ⥤ AlgebraCat R where obj A := AlgebraCat.of R A.X - map {A B} f := + map {_ _} f := { f.hom.toAddMonoidHom with toFun := f.hom map_one' := LinearMap.congr_fun f.one_hom (1 : R) @@ -103,7 +103,7 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where one := Algebra.linearMap R A mul := LinearMap.mul' R A one_mul := by - -- Porting note: `ext` did not pick up `TensorProduct.ext` + -- Porting note (#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 leanprover/lean4#2644 erw [compr₂_apply, compr₂_apply, CategoryTheory.comp_apply] @@ -116,7 +116,7 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where erw [LinearMap.mul'_apply, MonoidalCategory.leftUnitor_hom_apply, ← Algebra.smul_def] erw [id_apply] mul_one := by - -- Porting note: `ext` did not pick up `TensorProduct.ext` + -- Porting note (#11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext <| LinearMap.ext fun x => LinearMap.ext_ring ?_ -- Porting note: this `dsimp` does nothing -- dsimp only [AlgebraCat.id_apply, TensorProduct.mk_apply, Algebra.linearMap_apply, @@ -131,11 +131,11 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where erw [id_apply] mul_assoc := by set_option tactic.skipAssignedInstances false in - -- Porting note: `ext` did not pick up `TensorProduct.ext` + -- Porting note (#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 [AlgebraCat.id_apply, TensorProduct.mk_apply, LinearMap.compr₂_apply, - Function.comp_apply, ModuleCat.MonoidalCategory.hom_apply, AlgebraCat.coe_comp, + Function.comp_apply, ModuleCat.MonoidalCategory.tensorHom_tmul, AlgebraCat.coe_comp, MonoidalCategory.associator_hom_apply] rw [compr₂_apply, compr₂_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 @@ -173,20 +173,20 @@ def monModuleEquivalenceAlgebra : Mon_ (ModuleCat.{u} R) ≌ AlgebraCat R where { hom := { hom := { toFun := _root_.id - map_add' := fun x y => rfl - map_smul' := fun r a => rfl } + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl } mul_hom := by - -- Porting note: `ext` did not pick up `TensorProduct.ext` + -- Porting note (#11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext ?_ dsimp at * rfl } inv := { hom := { toFun := _root_.id - map_add' := fun x y => rfl - map_smul' := fun r a => rfl } + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl } mul_hom := by - -- Porting note: `ext` did not pick up `TensorProduct.ext` + -- Porting note (#11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext ?_ dsimp at * rfl } }) @@ -196,17 +196,17 @@ def monModuleEquivalenceAlgebra : Mon_ (ModuleCat.{u} R) ≌ AlgebraCat R where { hom := { toFun := _root_.id map_zero' := rfl - map_add' := fun x y => rfl + map_add' := fun _ _ => rfl map_one' := (algebraMap R A).map_one map_mul' := fun x y => @LinearMap.mul'_apply R _ _ _ _ _ _ x y - commutes' := fun r => rfl } + commutes' := fun _ => rfl } inv := { toFun := _root_.id map_zero' := rfl - map_add' := fun x y => rfl + map_add' := fun _ _ => rfl map_one' := (algebraMap R A).map_one.symm map_mul' := fun x y => (@LinearMap.mul'_apply R _ _ _ _ _ _ x y).symm - commutes' := fun r => rfl } }) + commutes' := fun _ => rfl } }) -- These lemmas have always been bad (#7657), but leanprover/lean4#2644 made `simp` start noticing attribute [nolint simpNF] ModuleCat.MonModuleEquivalenceAlgebra.functor_map_apply @@ -221,11 +221,11 @@ def monModuleEquivalenceAlgebraForget : (fun A => { hom := { toFun := _root_.id - map_add' := fun x y => rfl - map_smul' := fun c x => rfl } + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl } inv := { toFun := _root_.id - map_add' := fun x y => rfl - map_smul' := fun c x => rfl } }) + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl } }) end ModuleCat diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean index 00d58af2f33d2..35b5ae5310477 100644 --- a/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean +++ b/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean @@ -73,11 +73,11 @@ noncomputable def monTypeEquivalenceMon : Mon_ (Type u) ≌ MonCat.{u} where { hom := { toFun := id map_one' := rfl - map_mul' := fun x y => rfl } + map_mul' := fun _ _ => rfl } inv := { toFun := id map_one' := rfl - map_mul' := fun x y => rfl } }) + map_mul' := fun _ _ => rfl } }) (by aesop_cat) /-- The equivalence `Mon_ (Type u) ≌ MonCat.{u}` @@ -85,7 +85,7 @@ is naturally compatible with the forgetful functors to `Type u`. -/ noncomputable def monTypeEquivalenceMonForget : MonTypeEquivalenceMon.functor ⋙ forget MonCat ≅ Mon_.forget (Type u) := - NatIso.ofComponents (fun A => Iso.refl _) (by aesop_cat) + NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) noncomputable instance monTypeInhabited : Inhabited (Mon_ (Type u)) := ⟨MonTypeEquivalenceMon.inverse.obj (MonCat.of PUnit)⟩ @@ -134,11 +134,11 @@ noncomputable def commMonTypeEquivalenceCommMon : CommMon_ (Type u) ≌ CommMonC { hom := { toFun := id map_one' := rfl - map_mul' := fun x y => rfl } + map_mul' := fun _ _ => rfl } inv := { toFun := id map_one' := rfl - map_mul' := fun x y => rfl } }) + map_mul' := fun _ _ => rfl } }) (by aesop_cat) /-- The equivalences `Mon_ (Type u) ≌ MonCat.{u}` and `CommMon_ (Type u) ≌ CommMonCat.{u}` @@ -147,7 +147,7 @@ are naturally compatible with the forgetful functors to `MonCat` and `Mon_ (Type noncomputable def commMonTypeEquivalenceCommMonForget : CommMonTypeEquivalenceCommMon.functor ⋙ forget₂ CommMonCat MonCat ≅ CommMon_.forget₂Mon_ (Type u) ⋙ MonTypeEquivalenceMon.functor := - NatIso.ofComponents (fun A => Iso.refl _) (by aesop_cat) + NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) noncomputable instance commMonTypeInhabited : Inhabited (CommMon_ (Type u)) := ⟨CommMonTypeEquivalenceCommMon.inverse.obj (CommMonCat.of PUnit)⟩ diff --git a/Mathlib/CategoryTheory/Monoidal/Limits.lean b/Mathlib/CategoryTheory/Monoidal/Limits.lean index e13b3fa646109..aaf3b03b9b353 100644 --- a/Mathlib/CategoryTheory/Monoidal/Limits.lean +++ b/Mathlib/CategoryTheory/Monoidal/Limits.lean @@ -49,7 +49,7 @@ instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F := .ofTensorH (ε := limit.lift _ { pt := _ - π := { app := fun j => 𝟙 _ } }) + π := { app := fun _ => 𝟙 _ } }) (μ := fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G @@ -122,7 +122,7 @@ theorem limLax_ε : (@limLax J _ C _ _ _).ε = limit.lift _ { pt := _ - π := { app := fun j => 𝟙 _ } } := + π := { app := fun _ => 𝟙 _ } } := rfl @[simp] diff --git a/Mathlib/CategoryTheory/Monoidal/Mod_.lean b/Mathlib/CategoryTheory/Monoidal/Mod_.lean index bee5d1a324c2f..ec6327ca22917 100644 --- a/Mathlib/CategoryTheory/Monoidal/Mod_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Mod_.lean @@ -57,7 +57,6 @@ instance : Category (Mod_ A) where id := id comp f g := comp f g --- Porting note (#5229): added because `Hom.ext` is not triggered automatically @[ext] lemma hom_ext {M N : Mod_ A} (f₁ f₂ : M ⟶ N) (h : f₁.hom = f₂.hom) : f₁ = f₂ := Hom.ext h diff --git a/Mathlib/CategoryTheory/Monoidal/Mon_.lean b/Mathlib/CategoryTheory/Monoidal/Mon_.lean index 2202d88535f6a..52b4de6677a39 100644 --- a/Mathlib/CategoryTheory/Monoidal/Mon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Mon_.lean @@ -23,7 +23,60 @@ universe v₁ v₂ u₁ u₂ u open CategoryTheory MonoidalCategory -variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] +variable {C : Type u₁} [Category.{v₁} C] [MonoidalCategory.{v₁} C] + +/-- A monoid object internal to a monoidal category. + +When the monoidal category is preadditive, this is also sometimes called an "algebra object". +-/ +class Mon_Class (X : C) where + /-- The unit morphism of a monoid object. -/ + one : 𝟙_ C ⟶ X + /-- The multiplication morphism of a monoid object. -/ + mul : X ⊗ X ⟶ X + /- For the names of the conditions below, the unprimed names are reserved for the version where + the argument `X` is explicit. -/ + one_mul' : one ▷ X ≫ mul = (λ_ X).hom := by aesop_cat + mul_one' : X ◁ one ≫ mul = (ρ_ X).hom := by aesop_cat + -- Obviously there is some flexibility stating this axiom. + -- This one has left- and right-hand sides matching the statement of `Monoid.mul_assoc`, + -- and chooses to place the associator on the right-hand side. + -- The heuristic is that unitors and associators "don't have much weight". + mul_assoc' : (mul ▷ X) ≫ mul = (α_ X X X).hom ≫ (X ◁ mul) ≫ mul := by aesop_cat + +namespace Mon_Class + +@[inherit_doc] scoped notation "μ" => Mon_Class.mul +@[inherit_doc] scoped notation "μ["M"]" => Mon_Class.mul (X := M) +@[inherit_doc] scoped notation "η" => Mon_Class.one +@[inherit_doc] scoped notation "η["M"]" => Mon_Class.one (X := M) + +/- The simp attribute is reserved for the unprimed versions. -/ +attribute [reassoc] one_mul' mul_one' mul_assoc' + +@[reassoc (attr := simp)] +theorem one_mul (X : C) [Mon_Class X] : η ▷ X ≫ μ = (λ_ X).hom := one_mul' + +@[reassoc (attr := simp)] +theorem mul_one (X : C) [Mon_Class X] : X ◁ η ≫ μ = (ρ_ X).hom := mul_one' + +@[reassoc (attr := simp)] +theorem mul_assoc (X : C) [Mon_Class X] : μ ▷ X ≫ μ = (α_ X X X).hom ≫ X ◁ μ ≫ μ := mul_assoc' + +end Mon_Class + +open scoped Mon_Class + +variable {M N : C} [Mon_Class M] [Mon_Class N] + +/-- The property that a morphism between monoid objects is a monoid morphism. -/ +class IsMon_Hom (f : M ⟶ N) : Prop where + one_hom : η ≫ f = η := by aesop_cat + mul_hom : μ ≫ f = (f ⊗ f) ≫ μ := by aesop_cat + +attribute [reassoc (attr := simp)] IsMon_Hom.one_hom IsMon_Hom.mul_hom + +variable (C) /-- A monoid object internal to a monoidal category. @@ -50,6 +103,24 @@ attribute [reassoc (attr := simp)] Mon_.mul_assoc namespace Mon_ +variable {C} + +/-- Construct an object of `Mon_ C` from an object `X : C` and `Mon_Class X` instance. -/ +@[simps] +def mk' (X : C) [Mon_Class X] : Mon_ C where + X := X + one := η + mul := μ + +instance {M : Mon_ C} : Mon_Class M.X where + one := M.one + mul := M.mul + one_mul' := M.one_mul + mul_one' := M.mul_one + mul_assoc' := M.mul_assoc + +variable (C) + /-- The trivial monoid object. We later show this is initial in `Mon_ C`. -/ @[simps] @@ -104,7 +175,6 @@ instance : Category (Mon_ C) where id := id comp f g := comp f g --- Porting note: added, as `Hom.ext` does not apply to a morphism. @[ext] lemma ext {X Y : Mon_ C} {f g : X ⟶ Y} (w : f.hom = g.hom) : f = g := Hom.ext w @@ -236,7 +306,7 @@ def monToLaxMonoidal : Mon_ C ⥤ LaxMonoidalFunctor (Discrete PUnit.{u + 1}) C { obj := fun _ => A.X map := fun _ => 𝟙 _ ε := A.one - μ := fun _ _ => A.mul } + «μ» := fun _ _ => A.mul } map f := { app := fun _ => f.hom } @@ -497,13 +567,17 @@ theorem tensor_mul (M N : Mon_ C) : (M ⊗ N).mul = instance monMonoidal : MonoidalCategory (Mon_ C) where tensorHom_def := by intros; ext; simp [tensorHom_def] +@[simps!] +instance {M N : C} [Mon_Class M] [Mon_Class N] : Mon_Class (M ⊗ N) := + inferInstanceAs <| Mon_Class (Mon_.mk' M ⊗ Mon_.mk' N).X + variable (C) /-- The forgetful functor from `Mon_ C` to `C` is monoidal when `C` is braided monoidal. -/ def forgetMonoidal : MonoidalFunctor (Mon_ C) C := { forget C with ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + «μ» := fun _ _ => 𝟙 _ } @[simp] theorem forgetMonoidal_toFunctor : (forgetMonoidal C).toFunctor = forget C := rfl @[simp] theorem forgetMonoidal_ε : (forgetMonoidal C).ε = 𝟙 (𝟙_ C) := rfl diff --git a/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean b/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean index 37d92020f5dfd..eb01593defb37 100644 --- a/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean +++ b/Mathlib/CategoryTheory/Monoidal/NaturalTransformation.lean @@ -81,7 +81,6 @@ theorem comp_toNatTrans_lax {F G H : LaxMonoidalFunctor C D} {α : F ⟶ G} {β instance categoryMonoidalFunctor : Category (MonoidalFunctor C D) := InducedCategory.category MonoidalFunctor.toLaxMonoidalFunctor --- Porting note: added, as `MonoidalNatTrans.ext` does not apply to morphisms. @[ext] lemma ext' {F G : LaxMonoidalFunctor C D} {α β : F ⟶ G} (w : ∀ X : C, α.app X = β.app X) : α = β := MonoidalNatTrans.ext (funext w) @@ -172,6 +171,7 @@ def monoidalUnit : F.map_tensor, IsIso.hom_inv_id_assoc, ← tensor_comp_assoc, Adjunction.left_triangle_components, tensorHom_id, id_whiskerRight, IsIso.inv_hom_id, map_id] + unit := by simp [Adjunction.homEquiv_unit] /-- The unit of a adjunction can be upgraded to a monoidal natural transformation. -/ @[simps] @@ -189,7 +189,8 @@ def monoidalCounit : unit := by have eq := h.counit.naturality F.ε dsimp at eq ⊢ - rw [map_inv, map_comp, assoc, assoc, map_inv, ← cancel_mono F.ε, assoc, assoc, assoc, ← eq, + rw [Adjunction.homEquiv_unit, map_inv, map_comp, assoc, assoc, map_inv, + ← cancel_mono F.ε, assoc, assoc, assoc, ← eq, IsIso.inv_hom_id_assoc, Adjunction.left_triangle_components, comp_id, id_comp] instance [F.IsEquivalence] : IsIso (monoidalUnit F h) := by diff --git a/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean b/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean index 5395fd61f0a08..9e49dda0d93bf 100644 --- a/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean +++ b/Mathlib/CategoryTheory/Monoidal/OfHasFiniteProducts.lean @@ -46,8 +46,8 @@ section def monoidalOfHasFiniteProducts [HasTerminal C] [HasBinaryProducts C] : MonoidalCategory C := letI : MonoidalCategoryStruct C := { tensorObj := fun X Y ↦ X ⨯ Y - whiskerLeft := fun X _ _ g ↦ Limits.prod.map (𝟙 _) g - whiskerRight := fun {_ _} f Y ↦ Limits.prod.map f (𝟙 _) + whiskerLeft := fun _ _ _ g ↦ Limits.prod.map (𝟙 _) g + whiskerRight := fun {_ _} f _ ↦ Limits.prod.map f (𝟙 _) tensorHom := fun f g ↦ Limits.prod.map f g tensorUnit := ⊤_ C associator := prod.associator @@ -73,7 +73,7 @@ open scoped MonoidalCategory @[ext] theorem tensor_ext {X Y Z : C} (f g : X ⟶ Y ⊗ Z) (w₁ : f ≫ prod.fst = g ≫ prod.fst) (w₂ : f ≫ prod.snd = g ≫ prod.snd) : f = g := - prod.hom_ext w₁ w₂ + Limits.prod.hom_ext w₁ w₂ @[simp] theorem tensorUnit : 𝟙_ C = ⊤_ C := rfl @@ -168,8 +168,8 @@ section def monoidalOfHasFiniteCoproducts [HasInitial C] [HasBinaryCoproducts C] : MonoidalCategory C := letI : MonoidalCategoryStruct C := { tensorObj := fun X Y ↦ X ⨿ Y - whiskerLeft := fun X _ _ g ↦ Limits.coprod.map (𝟙 _) g - whiskerRight := fun {_ _} f Y ↦ Limits.coprod.map f (𝟙 _) + whiskerLeft := fun _ _ _ g ↦ Limits.coprod.map (𝟙 _) g + whiskerRight := fun {_ _} f _ ↦ Limits.coprod.map f (𝟙 _) tensorHom := fun f g ↦ Limits.coprod.map f g tensorUnit := ⊥_ C associator := coprod.associator @@ -297,13 +297,13 @@ def Functor.toMonoidalFunctorOfHasFiniteProducts : MonoidalFunctor C D where dsimp simp only [prod.map_map_assoc, IsIso.hom_inv_id, Category.comp_id, prod.map_id_id, Category.id_comp, IsIso.eq_inv_comp] - erw [prod.map_snd, Category.comp_id, prodComparison_snd] + rw [prod.map_snd, Category.comp_id, prodComparison_snd] right_unitality X := by rw [← cancel_epi (prod.map (𝟙 (F.obj X)) (terminalComparison F))] dsimp simp only [prod.map_map_assoc, Category.comp_id, IsIso.hom_inv_id, prod.map_id_id, Category.id_comp, IsIso.eq_inv_comp] - erw [prod.map_fst, Category.comp_id, prodComparison_fst] + rw [prod.map_fst, Category.comp_id, prodComparison_fst] instance [F.IsEquivalence] : F.toMonoidalFunctorOfHasFiniteProducts.IsEquivalence := by assumption diff --git a/Mathlib/CategoryTheory/Monoidal/Opposite.lean b/Mathlib/CategoryTheory/Monoidal/Opposite.lean index 3866aa1f3735a..e1d90560271b1 100644 --- a/Mathlib/CategoryTheory/Monoidal/Opposite.lean +++ b/Mathlib/CategoryTheory/Monoidal/Opposite.lean @@ -152,7 +152,7 @@ instance monoidalCategoryOp : MonoidalCategory Cᵒᵖ where whiskerLeft X _ _ f := (X.unop ◁ f.unop).op whiskerRight f X := (f.unop ▷ X.unop).op tensorHom f g := (f.unop ⊗ g.unop).op - tensorHom_def f g := Quiver.Hom.unop_inj (tensorHom_def' _ _) + tensorHom_def _ _ := Quiver.Hom.unop_inj (tensorHom_def' _ _) tensorUnit := op (𝟙_ C) associator X Y Z := (α_ (unop X) (unop Y) (unop Z)).symm.op leftUnitor X := (λ_ (unop X)).symm.op @@ -231,7 +231,7 @@ instance monoidalCategoryMop : MonoidalCategory Cᴹᵒᵖ where whiskerLeft X _ _ f := (f.unmop ▷ X.unmop).mop whiskerRight f X := (X.unmop ◁ f.unmop).mop tensorHom f g := (g.unmop ⊗ f.unmop).mop - tensorHom_def f g := Quiver.Hom.unmop_inj (tensorHom_def' _ _) + tensorHom_def _ _ := Quiver.Hom.unmop_inj (tensorHom_def' _ _) tensorUnit := mop (𝟙_ C) associator X Y Z := (α_ (unmop Z) (unmop Y) (unmop X)).symm.mop leftUnitor X := (ρ_ (unmop X)).mop diff --git a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean index 7133ba4faabc0..96881368dc909 100644 --- a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean +++ b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean @@ -178,7 +178,7 @@ theorem biproduct_ι_comp_leftDistributor_inv {J : Type} [Fintype J] (X : C) (f theorem leftDistributor_assoc {J : Type} [Fintype J] (X Y : C) (f : J → C) : (asIso (𝟙 X) ⊗ leftDistributor Y f) ≪≫ leftDistributor X _ = - (α_ X Y (⨁ f)).symm ≪≫ leftDistributor (X ⊗ Y) f ≪≫ biproduct.mapIso fun j => α_ X Y _ := by + (α_ X Y (⨁ f)).symm ≪≫ leftDistributor (X ⊗ Y) f ≪≫ biproduct.mapIso fun _ => α_ X Y _ := by ext simp only [Category.comp_id, Category.assoc, eqToHom_refl, Iso.trans_hom, Iso.symm_hom, asIso_hom, comp_zero, comp_dite, Preadditive.sum_comp, Preadditive.comp_sum, tensor_sum, @@ -234,7 +234,7 @@ theorem biproduct_ι_comp_rightDistributor_inv {J : Type} [Fintype J] (f : J → theorem rightDistributor_assoc {J : Type} [Fintype J] (f : J → C) (X Y : C) : (rightDistributor f X ⊗ asIso (𝟙 Y)) ≪≫ rightDistributor _ Y = - α_ (⨁ f) X Y ≪≫ rightDistributor f (X ⊗ Y) ≪≫ biproduct.mapIso fun j => (α_ _ X Y).symm := by + α_ (⨁ f) X Y ≪≫ rightDistributor f (X ⊗ Y) ≪≫ biproduct.mapIso fun _ => (α_ _ X Y).symm := by ext simp only [Category.comp_id, Category.assoc, eqToHom_refl, Iso.symm_hom, Iso.trans_hom, asIso_hom, comp_zero, comp_dite, Preadditive.sum_comp, Preadditive.comp_sum, sum_tensor, @@ -250,7 +250,7 @@ theorem leftDistributor_rightDistributor_assoc {J : Type _} [Fintype J] (leftDistributor X f ⊗ asIso (𝟙 Y)) ≪≫ rightDistributor _ Y = α_ X (⨁ f) Y ≪≫ (asIso (𝟙 X) ⊗ rightDistributor _ Y) ≪≫ - leftDistributor X _ ≪≫ biproduct.mapIso fun j => (α_ _ _ _).symm := by + leftDistributor X _ ≪≫ biproduct.mapIso fun _ => (α_ _ _ _).symm := by ext simp only [Category.comp_id, Category.assoc, eqToHom_refl, Iso.symm_hom, Iso.trans_hom, asIso_hom, comp_zero, comp_dite, Preadditive.sum_comp, Preadditive.comp_sum, sum_tensor, diff --git a/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean index f520a501aff97..99fcf06d2a3da 100644 --- a/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean @@ -30,7 +30,7 @@ instance functorHasRightDual [RightRigidCategory D] (F : C ⥤ D) : HasRightDual map_comp := fun f g => by simp [comp_rightAdjointMate] } exact := { evaluation' := - { app := fun X => ε_ _ _ + { app := fun _ => ε_ _ _ naturality := fun X Y f => by dsimp rw [Category.comp_id, Functor.map_inv, ← id_tensor_comp_tensor_id, Category.assoc, @@ -38,7 +38,7 @@ instance functorHasRightDual [RightRigidCategory D] (F : C ⥤ D) : HasRightDual rightAdjointMate_comp_evaluation, ← MonoidalCategory.whiskerLeft_comp_assoc, IsIso.hom_inv_id, MonoidalCategory.whiskerLeft_id, Category.id_comp] } coevaluation' := - { app := fun X => η_ _ _ + { app := fun _ => η_ _ _ naturality := fun X Y f => by dsimp rw [Functor.map_inv, Category.id_comp, ← id_tensor_comp_tensor_id, @@ -55,12 +55,12 @@ instance functorHasLeftDual [LeftRigidCategory D] (F : C ⥤ D) : HasLeftDual F map_comp := fun f g => by simp [comp_leftAdjointMate] } exact := { evaluation' := - { app := fun X => ε_ _ _ + { app := fun _ => ε_ _ _ naturality := fun X Y f => by dsimp simp [tensorHom_def, leftAdjointMate_comp_evaluation] } coevaluation' := - { app := fun X => η_ _ _ + { app := fun _ => η_ _ _ naturality := fun X Y f => by dsimp simp [tensorHom_def, coevaluation_comp_leftAdjointMate_assoc] } } diff --git a/Mathlib/CategoryTheory/Monoidal/Subcategory.lean b/Mathlib/CategoryTheory/Monoidal/Subcategory.lean index 5e77ff34ecfb7..c9d7bd3fe9312 100644 --- a/Mathlib/CategoryTheory/Monoidal/Subcategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/Subcategory.lean @@ -64,7 +64,7 @@ When `P` is a monoidal predicate, the full subcategory for `P` inherits the mono -/ instance fullMonoidalSubcategory : MonoidalCategory (FullSubcategory P) := Monoidal.induced (fullSubcategoryInclusion P) - { μIso := fun X Y => eqToIso rfl + { μIso := fun _ _ => eqToIso rfl εIso := eqToIso rfl } /-- The forgetful monoidal functor from a full monoidal subcategory into the original category @@ -74,7 +74,7 @@ instance fullMonoidalSubcategory : MonoidalCategory (FullSubcategory P) := def fullMonoidalSubcategoryInclusion : MonoidalFunctor (FullSubcategory P) C where toFunctor := fullSubcategoryInclusion P ε := 𝟙 _ - μ X Y := 𝟙 _ + μ _ _ := 𝟙 _ instance fullMonoidalSubcategory.full : (fullMonoidalSubcategoryInclusion P).Full := FullSubcategory.full P @@ -116,7 +116,7 @@ def fullMonoidalSubcategory.map (h : ∀ ⦃X⦄, P X → P' X) : MonoidalFunctor (FullSubcategory P) (FullSubcategory P') where toFunctor := FullSubcategory.map h ε := 𝟙 _ - μ X Y := 𝟙 _ + μ _ _ := 𝟙 _ instance fullMonoidalSubcategory.map_full (h : ∀ ⦃X⦄, P X → P' X) : (fullMonoidalSubcategory.map h).Full where @@ -200,10 +200,10 @@ instance fullMonoidalClosedSubcategory : MonoidalClosed (FullSubcategory P) wher adj := { unit := { app := fun Y => (ihom.coev X.1).app Y.1 - naturality := fun Y Z f => ihom.coev_naturality X.1 f } + naturality := fun _ _ f => ihom.coev_naturality X.1 f } counit := { app := fun Y => (ihom.ev X.1).app Y.1 - naturality := fun Y Z f => ihom.ev_naturality X.1 f } + naturality := fun _ _ f => ihom.ev_naturality X.1 f } left_triangle_components := fun X ↦ by simp [FullSubcategory.comp_def, FullSubcategory.id_def] right_triangle_components := fun Y ↦ diff --git a/Mathlib/CategoryTheory/Monoidal/Transport.lean b/Mathlib/CategoryTheory/Monoidal/Transport.lean index 19d755f6f034b..bda1093a68af0 100644 --- a/Mathlib/CategoryTheory/Monoidal/Transport.lean +++ b/Mathlib/CategoryTheory/Monoidal/Transport.lean @@ -160,7 +160,7 @@ attribute [local simp] transportStruct in def transport (e : C ≌ D) : MonoidalCategory.{v₂} D := letI : MonoidalCategoryStruct.{v₂} D := transportStruct e induced e.inverse - { μIso := fun X Y => e.unitIso.app _ + { μIso := fun _ _ => e.unitIso.app _ εIso := e.unitIso.app _ } /-- A type synonym for `D`, which will carry the transported monoidal structure. -/ diff --git a/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean b/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean index 475acc453b566..bcc39bf0542db 100644 --- a/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean +++ b/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean @@ -30,7 +30,7 @@ def coyonedaTensorUnit (C : Type u) [Category.{v} C] [MonoidalCategory C] : LaxMonoidalFunctor C (Type v) := .ofTensorHom (F := coyoneda.obj (op (𝟙_ C))) (ε := fun _p => 𝟙 _) - (μ := fun X Y p => (λ_ (𝟙_ C)).inv ≫ (p.1 ⊗ p.2)) + (μ := fun _ _ p => (λ_ (𝟙_ C)).inv ≫ (p.1 ⊗ p.2)) (μ_natural := by aesop_cat) (associativity := fun X Y Z => by ext ⟨⟨f, g⟩, h⟩; dsimp at f g h diff --git a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean index 0a3a382da8016..cf9f01545d900 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.CategoryTheory.Comma.Arrow -import Mathlib.CategoryTheory.Pi.Basic import Mathlib.Order.CompleteBooleanAlgebra /-! @@ -196,10 +195,14 @@ theorem cancel_right_of_respectsIso (P : MorphismProperty C) [hP : RespectsIso P (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : P (f ≫ g) ↔ P f := ⟨fun h => by simpa using RespectsIso.postcomp P (inv g) (f ≫ g) h, RespectsIso.postcomp P g f⟩ +lemma comma_iso_iff (P : MorphismProperty C) [P.RespectsIso] {A B : Type*} [Category A] [Category B] + {L : A ⥤ C} {R : B ⥤ C} {f g : Comma L R} (e : f ≅ g) : + P f.hom ↔ P g.hom := by + simp [← Comma.inv_left_hom_right e.hom, cancel_left_of_respectsIso, cancel_right_of_respectsIso] + theorem arrow_iso_iff (P : MorphismProperty C) [RespectsIso P] {f g : Arrow C} - (e : f ≅ g) : P f.hom ↔ P g.hom := by - simp [← Arrow.inv_left_hom_right e.hom, cancel_left_of_respectsIso, - cancel_right_of_respectsIso] + (e : f ≅ g) : P f.hom ↔ P g.hom := + P.comma_iso_iff e theorem arrow_mk_iso_iff (P : MorphismProperty C) [RespectsIso P] {W X Y Z : C} {f : W ⟶ X} {g : Y ⟶ Z} (e : Arrow.mk f ≅ Arrow.mk g) : P f ↔ P g := diff --git a/Mathlib/CategoryTheory/MorphismProperty/Comma.lean b/Mathlib/CategoryTheory/MorphismProperty/Comma.lean new file mode 100644 index 0000000000000..0662c8046f120 --- /dev/null +++ b/Mathlib/CategoryTheory/MorphismProperty/Comma.lean @@ -0,0 +1,292 @@ +/- +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.CategoryTheory.Comma.Over +import Mathlib.CategoryTheory.MorphismProperty.Composition + +/-! +# Subcategories of comma categories defined by morphism properties + +Given functors `L : A ⥤ T` and `R : B ⥤ T` and morphism properties `P`, `Q` and `W` +on `T`, A` and `B` respectively, we define the subcategory `P.Comma L R Q W` of +`Comma L R` where + +- objects are objects of `Comma L R` with the structural morphism satisfying `P`, and +- morphisms are morphisms of `Comma L R` where the left morphism satisfies `Q` and the + right morphism satisfies `W`. + +For an object `X : T`, this specializes to `P.Over Q X` which is the subcategory of `Over X` +where the structural morphism satisfies `P` and where the horizontal morphisms satisfy `Q`. +Common examples of the latter are e.g. the category of schemes étale (finite, affine, etc.) +over a base `X`. Here `Q = ⊤`. + +## Implementation details + +- We provide the general constructor `P.Comma L R Q W` to obtain `Over X` and `Under X` as + special cases of the more general setup. + +- Most results are developed only in the case where `Q = ⊤` and `W = ⊤`, but the definition + is setup in the general case to allow for a later generalization if needed. + +-/ + +namespace CategoryTheory.MorphismProperty + +open Limits + +section Comma + +variable {A : Type*} [Category A] {B : Type*} [Category B] {T : Type*} [Category T] + (L : A ⥤ T) (R : B ⥤ T) + +lemma costructuredArrow_iso_iff (P : MorphismProperty T) [P.RespectsIso] + {L : A ⥤ T} {X : T} {f g : CostructuredArrow L X} (e : f ≅ g) : + P f.hom ↔ P g.hom := + P.comma_iso_iff e + +lemma over_iso_iff (P : MorphismProperty T) [P.RespectsIso] {X : T} {f g : Over X} (e : f ≅ g) : + P f.hom ↔ P g.hom := + P.comma_iso_iff e + +variable (P : MorphismProperty T) (Q : MorphismProperty A) (W : MorphismProperty B) + +/-- `P.Comma L R Q W` is the subcategory of `Comma L R` consisting of +objects `X : Comma L R` where `X.hom` satisfies `P`. The morphisms are given by +morphisms in `Comma L R` where the left one satisfies `Q` and the right one satisfies `W`. -/ +@[ext] +protected structure Comma (Q : MorphismProperty A) (W : MorphismProperty B) extends Comma L R where + prop : P toComma.hom + +namespace Comma + +variable {L R P Q W} + +/-- A morphism in `P.Comma L R Q W` is a morphism in `Comma L R` where the left +hom satisfies `Q` and the right one satisfies `W`. -/ +@[ext] +structure Hom (X Y : P.Comma L R Q W) extends CommaMorphism X.toComma Y.toComma where + prop_hom_left : Q toCommaMorphism.left + prop_hom_right : W toCommaMorphism.right + +/-- The underlying morphism of objects in `Comma L R`. -/ +abbrev Hom.hom {X Y : P.Comma L R Q W} (f : Comma.Hom X Y) : X.toComma ⟶ Y.toComma := + f.toCommaMorphism + +@[simp, nolint simpVarHead] +lemma Hom.hom_mk {X Y : P.Comma L R Q W} + (f : CommaMorphism X.toComma Y.toComma) (hf) (hg) : + Comma.Hom.hom ⟨f, hf, hg⟩ = f := rfl + +@[simp] +lemma Hom.hom_left {X Y : P.Comma L R Q W} (f : Comma.Hom X Y) : f.hom.left = f.left := rfl + +@[simp] +lemma Hom.hom_right {X Y : P.Comma L R Q W} (f : Comma.Hom X Y) : f.hom.right = f.right := rfl + +/-- See Note [custom simps projection] -/ +def Hom.Simps.hom {X Y : P.Comma L R Q W} (f : X.Hom Y) : + X.toComma ⟶ Y.toComma := + f.hom + +initialize_simps_projections Comma.Hom (toCommaMorphism → hom) + +/-- The identity morphism of an object in `P.Comma L R Q W`. -/ +@[simps] +def id [Q.ContainsIdentities] [W.ContainsIdentities] (X : P.Comma L R Q W) : Comma.Hom X X where + left := 𝟙 X.left + prop_hom_left := Q.id_mem X.toComma.left + prop_hom_right := W.id_mem X.toComma.right + +/-- Composition of morphisms in `P.Comma L R Q W`. -/ +@[simps] +def Hom.comp [Q.IsStableUnderComposition] [W.IsStableUnderComposition] {X Y Z : P.Comma L R Q W} + (f : Comma.Hom X Y) (g : Comma.Hom Y Z) : + Comma.Hom X Z where + left := f.left ≫ g.left + right := f.right ≫ g.right + prop_hom_left := Q.comp_mem _ _ f.prop_hom_left g.prop_hom_left + prop_hom_right := W.comp_mem _ _ f.prop_hom_right g.prop_hom_right + +variable [Q.IsMultiplicative] [W.IsMultiplicative] + +variable (L R P Q W) in +instance : Category (P.Comma L R Q W) where + Hom X Y := X.Hom Y + id X := X.id + comp f g := f.comp g + +/-- Alternative `ext` lemma for `Comma.Hom`. -/ +@[ext] +lemma Hom.ext' {X Y : P.Comma L R Q W} {f g : X ⟶ Y} (h : f.hom = g.hom) : + f = g := Comma.Hom.ext + (congrArg CommaMorphism.left h) + (congrArg CommaMorphism.right h) + +@[simp] +lemma id_hom (X : P.Comma L R Q W) : (𝟙 X : X ⟶ X).hom = 𝟙 X.toComma := rfl + +@[simp] +lemma comp_hom {X Y Z : P.Comma L R Q W} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).hom = f.hom ≫ g.hom := rfl + +/-- If `i` is an isomorphism in `Comma L R`, it is also a morphism in `P.Comma L R Q W`. -/ +@[simps hom] +def homFromCommaOfIsIso [Q.RespectsIso] [W.RespectsIso] {X Y : P.Comma L R Q W} + (i : X.toComma ⟶ Y.toComma) [IsIso i] : + X ⟶ Y where + __ := i + prop_hom_left := Q.of_isIso i.left + prop_hom_right := W.of_isIso i.right + +instance [Q.RespectsIso] [W.RespectsIso] {X Y : P.Comma L R Q W} (i : X.toComma ⟶ Y.toComma) + [IsIso i] : IsIso (homFromCommaOfIsIso i) := by + constructor + use homFromCommaOfIsIso (inv i) + constructor <;> ext : 1 <;> simp + +/-- Any isomorphism between objects of `P.Comma L R Q W` in `Comma L R` is also an isomorphism +in `P.Comma L R Q W`. -/ +@[simps] +def isoFromComma [Q.RespectsIso] [W.RespectsIso] {X Y : P.Comma L R Q W} + (i : X.toComma ≅ Y.toComma) : X ≅ Y where + hom := homFromCommaOfIsIso i.hom + inv := homFromCommaOfIsIso i.inv + +/-- Constructor for isomorphisms in `P.Comma L R Q W` from isomorphisms of the left and right +components and naturality in the forward direction. -/ +@[simps!] +def isoMk [Q.RespectsIso] [W.RespectsIso] {X Y : P.Comma L R Q W} (l : X.left ≅ Y.left) + (r : X.right ≅ Y.right) (h : L.map l.hom ≫ Y.hom = X.hom ≫ R.map r.hom := by aesop_cat) : + X ≅ Y := + isoFromComma (CategoryTheory.Comma.isoMk l r h) + +variable (L R P Q W) + +/-- The forgetful functor. -/ +@[simps] +def forget : P.Comma L R Q W ⥤ Comma L R where + obj X := X.toComma + map f := f.hom + +instance : (forget L R P Q W).Faithful where + map_injective := Comma.Hom.ext' + +variable {L R P Q W} + +instance {X Y : P.Comma L R Q W} (f : X ⟶ Y) [IsIso f] : IsIso f.hom := + (forget L R P Q W).map_isIso f + +lemma hom_homFromCommaOfIsIso [Q.RespectsIso] [W.RespectsIso] {X Y : P.Comma L R Q W} + (i : X ⟶ Y) [IsIso i.hom] : + homFromCommaOfIsIso i.hom = i := + rfl + +lemma inv_hom {X Y : P.Comma L R Q W} (f : X ⟶ Y) [IsIso f] : (inv f).hom = inv f.hom := by + apply IsIso.eq_inv_of_hom_inv_id + rw [← comp_hom, IsIso.hom_inv_id, id_hom] + +variable (L R P Q W) + +instance [Q.RespectsIso] [W.RespectsIso] : (forget L R P Q W).ReflectsIsomorphisms where + reflects f hf := by + simp only [forget_obj, forget_map] at hf + rw [← hom_homFromCommaOfIsIso f] + infer_instance + +/-- The forgetful functor from the full subcategory of `Comma L R` defined by `P` is +fully faithful. -/ +def forgetFullyFaithful : (forget L R P ⊤ ⊤).FullyFaithful where + preimage {X Y} f := ⟨f, trivial, trivial⟩ + +instance : (forget L R P ⊤ ⊤).Full := + Functor.FullyFaithful.full (forgetFullyFaithful L R P) + +end Comma + +end Comma + +section Over + +variable {T : Type*} [Category T] (P Q : MorphismProperty T) (X : T) [Q.IsMultiplicative] + +/-- Given a morphism property `P` on a category `C` and an object `X : C`, this is the +subcategory of `Over X` defined by `P` where morphisms satisfy `Q`. -/ +protected abbrev Over : Type _ := + P.Comma (Functor.id T) (Functor.fromPUnit.{0} X) Q ⊤ + +/-- The forgetful functor from the full subcategory of `Over X` defined by `P` to `Over X`. -/ +protected abbrev Over.forget : P.Over Q X ⥤ Over X := + Comma.forget (Functor.id T) (Functor.fromPUnit.{0} X) P Q ⊤ + +variable {P Q X} + +/-- Construct a morphism in `P.Over Q X` from a morphism in `Over.X`. -/ +@[simps hom] +def Over.Hom.mk {A B : P.Over Q X} (f : A.toComma ⟶ B.toComma) (hf : Q f.left) : A ⟶ B where + __ := f + prop_hom_left := hf + prop_hom_right := trivial + +variable (Q) in +/-- Make an object of `P.Over Q X` from a morphism `f : A ⟶ X` and a proof of `P f`. -/ +@[simps hom left] +protected def Over.mk {A : T} (f : A ⟶ X) (hf : P f) : P.Over Q X where + left := A + right := ⟨⟨⟩⟩ + hom := f + prop := hf + +/-- Make a morphism in `P.Over Q X` from a morphism in `T` with compatibilities. -/ +@[simps hom] +protected def Over.homMk {A B : P.Over Q X} (f : A.left ⟶ B.left) + (w : f ≫ B.hom = A.hom := by aesop_cat) (hf : Q f := by trivial) : A ⟶ B where + __ := CategoryTheory.Over.homMk f w + prop_hom_left := hf + prop_hom_right := trivial + +end Over + +section Under + +variable {T : Type*} [Category T] (P Q : MorphismProperty T) (X : T) [Q.IsMultiplicative] + +/-- Given a morphism property `P` on a category `C` and an object `X : C`, this is the +subcategory of `Under X` defined by `P` where morphisms satisfy `Q`. -/ +protected abbrev Under : Type _ := + P.Comma (Functor.fromPUnit.{0} X) (Functor.id T) ⊤ Q + +/-- The forgetful functor from the full subcategory of `Under X` defined by `P` to `Under X`. -/ +protected abbrev Under.forget : P.Under Q X ⥤ Under X := + Comma.forget (Functor.fromPUnit.{0} X) (Functor.id T) P ⊤ Q + +variable {P Q X} + +/-- Construct a morphism in `P.Under Q X` from a morphism in `Under.X`. -/ +@[simps hom] +def Under.Hom.mk {A B : P.Under Q X} (f : A.toComma ⟶ B.toComma) (hf : Q f.right) : A ⟶ B where + __ := f + prop_hom_left := trivial + prop_hom_right := hf + +variable (Q) in +/-- Make an object of `P.Under Q X` from a morphism `f : A ⟶ X` and a proof of `P f`. -/ +@[simps hom left] +protected def Under.mk {A : T} (f : X ⟶ A) (hf : P f) : P.Under Q X where + left := ⟨⟨⟩⟩ + right := A + hom := f + prop := hf + +/-- Make a morphism in `P.Under Q X` from a morphism in `T` with compatibilities. -/ +@[simps hom] +protected def Under.homMk {A B : P.Under Q X} (f : A.right ⟶ B.right) + (w : A.hom ≫ f = B.hom := by aesop_cat) (hf : Q f := by trivial) : A ⟶ B where + __ := CategoryTheory.Under.homMk f w + prop_hom_left := trivial + prop_hom_right := hf + +end Under + +end CategoryTheory.MorphismProperty diff --git a/Mathlib/CategoryTheory/MorphismProperty/Composition.lean b/Mathlib/CategoryTheory/MorphismProperty/Composition.lean index 3595312f8c115..9ceb89d7018f0 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Composition.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Composition.lean @@ -24,7 +24,7 @@ namespace MorphismProperty variable {C : Type u} [Category.{v} C] {D : Type u'} [Category.{v'} D] /-- Typeclass expressing that a morphism property contain identities. -/ -class ContainsIdentities (W : MorphismProperty C) : Prop := +class ContainsIdentities (W : MorphismProperty C) : Prop where /-- for all `X : C`, the identity of `X` satisfies the morphism property -/ id_mem : ∀ (X : C), W (𝟙 X) @@ -49,6 +49,10 @@ instance inverseImage {P : MorphismProperty D} [P.ContainsIdentities] (F : C ⥤ (P.inverseImage F).ContainsIdentities where id_mem X := by simpa only [← F.map_id] using P.id_mem (F.obj X) +instance inf {P Q : MorphismProperty C} [P.ContainsIdentities] [Q.ContainsIdentities] : + (P ⊓ Q).ContainsIdentities where + id_mem X := ⟨P.id_mem X, Q.id_mem X⟩ + end ContainsIdentities instance Prod.containsIdentities {C₁ C₂ : Type*} [Category C₁] [Category C₂] @@ -61,9 +65,17 @@ instance Pi.containsIdentities {J : Type w} {C : J → Type u} (pi W).ContainsIdentities := ⟨fun _ _ => MorphismProperty.id_mem _ _⟩ +lemma of_isIso (P : MorphismProperty C) [P.ContainsIdentities] [P.RespectsIso] {X Y : C} (f : X ⟶ Y) + [IsIso f] : P f := + Category.id_comp f ▸ RespectsIso.postcomp P f (𝟙 X) (P.id_mem X) + +lemma isomorphisms_le_of_containsIdentities (P : MorphismProperty C) [P.ContainsIdentities] + [P.RespectsIso] : + isomorphisms C ≤ P := fun _ _ f (_ : IsIso f) ↦ P.of_isIso f + /-- A morphism property satisfies `IsStableUnderComposition` if the composition of two such morphisms still falls in the class. -/ -class IsStableUnderComposition (P : MorphismProperty C) : Prop := +class IsStableUnderComposition (P : MorphismProperty C) : Prop where comp_mem {X Y Z} (f : X ⟶ Y) (g : Y ⟶ Z) : P f → P g → P (f ≫ g) lemma comp_mem (W : MorphismProperty C) [W.IsStableUnderComposition] @@ -78,6 +90,11 @@ instance IsStableUnderComposition.unop {P : MorphismProperty Cᵒᵖ} [P.IsStabl P.unop.IsStableUnderComposition where comp_mem f g hf hg := P.comp_mem g.op f.op hg hf +instance IsStableUnderComposition.inf {P Q : MorphismProperty C} [P.IsStableUnderComposition] + [Q.IsStableUnderComposition] : + (P ⊓ Q).IsStableUnderComposition where + comp_mem f g hf hg := ⟨P.comp_mem f g hf.left hg.left, Q.comp_mem f g hf.right hg.right⟩ + /-- A morphism property is `StableUnderInverse` if the inverse of a morphism satisfying the property still falls in the class. -/ def StableUnderInverse (P : MorphismProperty C) : Prop := @@ -129,7 +146,7 @@ end naturalityProperty /-- A morphism property is multiplicative if it contains identities and is stable by composition. -/ class IsMultiplicative (W : MorphismProperty C) - extends W.ContainsIdentities, W.IsStableUnderComposition : Prop := + extends W.ContainsIdentities, W.IsStableUnderComposition : Prop namespace IsMultiplicative @@ -146,6 +163,10 @@ lemma of_op (W : MorphismProperty C) [IsMultiplicative W.op] : IsMultiplicative lemma of_unop (W : MorphismProperty Cᵒᵖ) [IsMultiplicative W.unop] : IsMultiplicative W := (inferInstance : IsMultiplicative W.unop.op) +instance : MorphismProperty.IsMultiplicative (⊤ : MorphismProperty C) where + comp_mem _ _ _ _ := trivial + id_mem _ := trivial + instance : (isomorphisms C).IsMultiplicative where id_mem _ := isomorphisms.infer_property _ comp_mem f g hf hg := by @@ -167,6 +188,9 @@ instance : (epimorphisms C).IsMultiplicative where instance {P : MorphismProperty D} [P.IsMultiplicative] (F : C ⥤ D) : (P.inverseImage F).IsMultiplicative where +instance inf {P Q : MorphismProperty C} [P.IsMultiplicative] [Q.IsMultiplicative] : + (P ⊓ Q).IsMultiplicative where + end IsMultiplicative /-- A class of morphisms `W` has the two-out-of-three property if whenever two out diff --git a/Mathlib/CategoryTheory/MorphismProperty/Concrete.lean b/Mathlib/CategoryTheory/MorphismProperty/Concrete.lean index 5b79e2725971f..f343d8580e654 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Concrete.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Concrete.lean @@ -126,7 +126,7 @@ def functorialSurjectiveInjectiveFactorizationData : ext x exact congr_fun φ.w x } p := - { app := fun f y => y.1 + { app := fun _ y => y.1 naturality := by intros; rfl; } fac := rfl hi := by diff --git a/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean b/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean index e4d78ec3864b8..a20da408bc49c 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean @@ -104,8 +104,6 @@ lemma FunctorsInverting.ext {W : MorphismProperty C} {F₁ F₂ : FunctorsInvert instance (W : MorphismProperty C) (D : Type*) [Category D] : Category (FunctorsInverting W D) := FullSubcategory.category _ --- Porting note (#5229): add another `@[ext]` lemma --- since `ext` can't see through the definition to use `NatTrans.ext`. @[ext] lemma FunctorsInverting.hom_ext {W : MorphismProperty C} {F₁ F₂ : FunctorsInverting W D} {α β : F₁ ⟶ F₂} (h : α.app = β.app) : α = β := diff --git a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean index e3c20a156e317..97d95f0510ebd 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean @@ -163,6 +163,16 @@ theorem StableUnderBaseChange.op {P : MorphismProperty C} (hP : StableUnderBaseC theorem StableUnderBaseChange.unop {P : MorphismProperty Cᵒᵖ} (hP : StableUnderBaseChange P) : StableUnderCobaseChange P.unop := fun _ _ _ _ _ _ _ _ sq hf => hP sq.op hf +lemma StableUnderBaseChange.inf {P Q : MorphismProperty C} (hP : StableUnderBaseChange P) + (hQ : StableUnderBaseChange Q) : + StableUnderBaseChange (P ⊓ Q) := + fun _ _ _ _ _ _ _ _ hp hg ↦ ⟨hP hp hg.left, hQ hp hg.right⟩ + +lemma StableUnderCobaseChange.inf {P Q : MorphismProperty C} (hP : StableUnderCobaseChange P) + (hQ : StableUnderCobaseChange Q) : + StableUnderCobaseChange (P ⊓ Q) := + fun _ _ _ _ _ _ _ _ hp hg ↦ ⟨hP hp hg.left, hQ hp hg.right⟩ + section variable (W : MorphismProperty C) @@ -190,7 +200,7 @@ abbrev IsStableUnderProductsOfShape (J : Type*) := W.IsStableUnderLimitsOfShape lemma IsStableUnderProductsOfShape.mk (J : Type*) [W.RespectsIso] [HasProductsOfShape J C] (hW : ∀ (X₁ X₂ : J → C) (f : ∀ j, X₁ j ⟶ X₂ j) (_ : ∀ (j : J), W (f j)), - W (Pi.map f)) : W.IsStableUnderProductsOfShape J := by + W (Limits.Pi.map f)) : W.IsStableUnderProductsOfShape J := by intro X₁ X₂ c₁ c₂ hc₁ hc₂ f hf let φ := fun j => f.app (Discrete.mk j) have hf' := hW _ _ φ (fun j => hf (Discrete.mk j)) @@ -203,7 +213,7 @@ lemma IsStableUnderProductsOfShape.mk (J : Type*) simp /-- The condition that a property of morphisms is stable by finite products. -/ -class IsStableUnderFiniteProducts : Prop := +class IsStableUnderFiniteProducts : Prop where isStableUnderProductsOfShape (J : Type) [Finite J] : W.IsStableUnderProductsOfShape J lemma isStableUnderProductsOfShape_of_isStableUnderFiniteProducts diff --git a/Mathlib/CategoryTheory/MorphismProperty/Representable.lean b/Mathlib/CategoryTheory/MorphismProperty/Representable.lean index 91bf09c44907e..df96aa39de010 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Representable.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Representable.lean @@ -12,7 +12,7 @@ import Mathlib.CategoryTheory.MorphismProperty.Limits In this file we define and develop basic results about relatively representable morphisms. -Classically, a morphism `f : X ⟶ Y` of presheaves is said to be representable if for any morphism +Classically, a morphism `f : F ⟶ G` of presheaves is said to be representable if for any morphism `g : yoneda.obj X ⟶ G`, there exists a pullback square of the following form ``` yoneda.obj Y --yoneda.map snd--> yoneda.obj X @@ -27,14 +27,13 @@ In this file, we define a notion of relative representability which works with r functor, and not just `yoneda`. The fact that a morphism `f : F ⟶ G` between presheaves is representable in the classical case will then be given by `yoneda.relativelyRepresentable f`. - - ## Main definitions + Throughout this file, `F : C ⥤ D` is a functor between categories `C` and `D`. -* We define `relativelyRepresentable` as a `MorphismProperty`. A morphism `f : X ⟶ Y` in `D` is - said to be relatively representable with respect to `F`, if for any `g : F.obj a ⟶ Y`, there - exists a pullback square of the following form +* `Functor.relativelyRepresentable`: A morphism `f : X ⟶ Y` in `D` is said to be relatively + representable with respect to `F`, if for any `g : F.obj a ⟶ Y`, there exists a pullback square + of the following form ``` F.obj b --F.map snd--> F.obj a | | @@ -44,6 +43,10 @@ Throughout this file, `F : C ⥤ D` is a functor between categories `C` and `D`. X ------- f --------> Y ``` +* `MorphismProperty.relative`: Given a morphism property `P` in `C`, a morphism `f : X ⟶ Y` in `D` + satisfies `P.relative F` if it is relatively representable and for any `g : F.obj a ⟶ Y`, the + property `P` holds for any represented pullback of `f` by `g`. + ## API Given `hf : relativelyRepresentable f`, with `f : X ⟶ Y` and `g : F.obj a ⟶ Y`, we provide: @@ -259,7 +262,8 @@ end /-- When `C` has pullbacks, then `F.map f` is representable with respect to `F` for any `f : a ⟶ b` in `C`. -/ -lemma map [Full F] [PreservesLimitsOfShape WalkingCospan F] [HasPullbacks C] {a b : C} (f : a ⟶ b) : +lemma map [Full F] [HasPullbacks C] {a b : C} (f : a ⟶ b) + [∀ c (g : c ⟶ b), PreservesLimit (cospan f g) F] : F.relativelyRepresentable (F.map f) := fun c g ↦ by obtain ⟨g, rfl⟩ := F.map_surjective g refine ⟨Limits.pullback f g, Limits.pullback.snd f g, F.map (Limits.pullback.fst f g), ?_⟩ @@ -288,4 +292,138 @@ instance respectsIso : RespectsIso F.relativelyRepresentable := end Functor.relativelyRepresentable +namespace MorphismProperty + +open Functor.relativelyRepresentable + +variable {X Y : D} (P : MorphismProperty C) + +/-- Given a morphism property `P` in a category `C`, a functor `F : C ⥤ D` and a morphism +`f : X ⟶ Y` in `D`. Then `f` satisfies the morphism property `P.relative` with respect to `F` iff: +* The morphism is representable with respect to `F` +* For any morphism `g : F.obj a ⟶ Y`, the property `P` holds for any represented pullback of + `f` by `g`. -/ +def relative : MorphismProperty D := + fun X Y f ↦ F.relativelyRepresentable f ∧ + ∀ ⦃a b : C⦄ (g : F.obj a ⟶ Y) (fst : F.obj b ⟶ X) (snd : b ⟶ a) + (_ : IsPullback fst (F.map snd) f g), P snd + +/-- Given a morphism property `P` in a category `C`, a morphism `f : F ⟶ G` of presheaves in the +category `Cᵒᵖ ⥤ Type v` satisfies the morphism property `P.presheaf` iff: +* The morphism is representable. +* For any morphism `g : F.obj a ⟶ G`, the property `P` holds for any represented pullback of + `f` by `g`. +This is implemented as a special case of the more general notion of `P.relative`, to the case when +the functor `F` is `yoneda`. -/ +abbrev presheaf : MorphismProperty (Cᵒᵖ ⥤ Type v₁) := P.relative yoneda + +variable {P} {F} + +/-- A morphism satisfying `P.relative` is representable. -/ +lemma relative.rep {f : X ⟶ Y} (hf : P.relative F f) : F.relativelyRepresentable f := + hf.1 + +lemma relative.property {f : X ⟶ Y} (hf : P.relative F f) : + ∀ ⦃a b : C⦄ (g : F.obj a ⟶ Y) (fst : F.obj b ⟶ X) (snd : b ⟶ a) + (_ : IsPullback fst (F.map snd) f g), P snd := + hf.2 + +lemma relative.property_snd {f : X ⟶ Y} (hf : P.relative F f) {a : C} (g : F.obj a ⟶ Y) : + P (hf.rep.snd g) := + hf.property g _ _ (hf.rep.isPullback g) + +/-- Given a morphism property `P` which respects isomorphisms, then to show that a morphism +`f : X ⟶ Y` satisfies `P.relative` it suffices to show that: +* The morphism is representable. +* For any morphism `g : F.obj a ⟶ G`, the property `P` holds for *some* represented pullback +of `f` by `g`. -/ +lemma relative.of_exists [F.Faithful] [F.Full] [P.RespectsIso] {f : X ⟶ Y} + (h₀ : ∀ ⦃a : C⦄ (g : F.obj a ⟶ Y), ∃ (b : C) (fst : F.obj b ⟶ X) (snd : b ⟶ a) + (_ : IsPullback fst (F.map snd) f g), P snd) : P.relative F f := by + refine ⟨fun a g ↦ ?_, fun a b g fst snd h ↦ ?_⟩ + all_goals obtain ⟨c, g_fst, g_snd, BC, H⟩ := h₀ g + · refine ⟨c, g_snd, g_fst, BC⟩ + · refine (P.arrow_mk_iso_iff ?_).2 H + exact Arrow.isoMk (F.preimageIso (h.isoIsPullback X (F.obj a) BC)) (Iso.refl _) + (F.map_injective (by simp)) + +lemma relative_of_snd [F.Faithful] [F.Full] [P.RespectsIso] {f : X ⟶ Y} + (hf : F.relativelyRepresentable f) (h : ∀ ⦃a : C⦄ (g : F.obj a ⟶ Y), P (hf.snd g)) : + P.relative F f := + relative.of_exists (fun _ g ↦ ⟨hf.pullback g, hf.fst g, hf.snd g, hf.isPullback g, h g⟩) + +/-- If `P : MorphismProperty C` is stable under base change, `F` is fully faithful and preserves +pullbacks, and `C` has all pullbacks, then for any `f : a ⟶ b` in `C`, `F.map f` satisfies +`P.relative` if `f` satisfies `P`. -/ +lemma relative_map [F.Faithful] [F.Full] [HasPullbacks C] (hP : StableUnderBaseChange P) + {a b : C} {f : a ⟶ b} [∀ c (g : c ⟶ b), PreservesLimit (cospan f g) F] + (hf : P f) : P.relative F (F.map f) := by + have := StableUnderBaseChange.respectsIso hP + apply relative.of_exists + intro Y' g + obtain ⟨g, rfl⟩ := F.map_surjective g + exact ⟨_, _, _, (IsPullback.of_hasPullback f g).map F, hP.snd _ _ hf⟩ + +lemma of_relative_map {a b : C} {f : a ⟶ b} (hf : P.relative F (F.map f)) : P f := + hf.property (𝟙 _) (𝟙 _) f (IsPullback.id_horiz (F.map f)) + +lemma relative_map_iff [F.Faithful] [F.Full] [PreservesLimitsOfShape WalkingCospan F] + [HasPullbacks C] (hP : StableUnderBaseChange P) {X Y : C} {f : X ⟶ Y} : + P.relative F (F.map f) ↔ P f := + ⟨fun hf ↦ of_relative_map hf, fun hf ↦ relative_map hP hf⟩ + +/-- If `P' : MorphismProperty C` is satisfied whenever `P` is, then also `P'.relative` is +satisfied whenever `P.relative` is. -/ +lemma relative_monotone {P' : MorphismProperty C} (h : P ≤ P') : + P.relative F ≤ P'.relative F := fun _ _ _ hf ↦ + ⟨hf.rep, fun _ _ g fst snd BC ↦ h _ (hf.property g fst snd BC)⟩ + +section + +variable (P) + +lemma relative_stableUnderBaseChange : StableUnderBaseChange (P.relative F) := + fun _ _ _ _ _ _ _ _ hfBC hg ↦ + ⟨stableUnderBaseChange F hfBC hg.rep, + fun _ _ _ _ _ BC ↦ hg.property _ _ _ (IsPullback.paste_horiz BC hfBC)⟩ + +instance relative_isStableUnderComposition [F.Faithful] [F.Full] [P.IsStableUnderComposition] : + IsStableUnderComposition (P.relative F) where + comp_mem {F G H} f g hf hg := by + refine ⟨comp_mem _ _ _ hf.1 hg.1, fun Z X p fst snd h ↦ ?_⟩ + rw [← hg.1.lift_snd (fst ≫ f) snd (by simpa using h.w)] + refine comp_mem _ _ _ (hf.property (hg.1.fst p) fst _ + (IsPullback.of_bot ?_ ?_ (hg.1.isPullback p))) (hg.property_snd p) + · rw [← Functor.map_comp, lift_snd] + exact h + · symm + apply hg.1.lift_fst + +instance relative_respectsIso : RespectsIso (P.relative F) := + (relative_stableUnderBaseChange P).respectsIso + +instance relative_isMultiplicative [F.Faithful] [F.Full] [P.IsMultiplicative] [P.RespectsIso] : + IsMultiplicative (P.relative F) where + id_mem X := relative.of_exists + (fun Y g ↦ ⟨Y, g, 𝟙 Y, by simpa using IsPullback.of_id_snd, id_mem _ _⟩) + +end + +/-- Morphisms satisfying `(monomorphism C).presheaf` are in particular monomorphisms. -/ +lemma presheaf_monomorphisms_le_monomorphisms : + (monomorphisms C).presheaf ≤ monomorphisms _ := fun F G f hf ↦ by + suffices ∀ {X : C} {a b : yoneda.obj X ⟶ F}, a ≫ f = b ≫ f → a = b from + ⟨fun _ _ h ↦ hom_ext_yoneda (fun _ _ ↦ this (by simp only [assoc, h]))⟩ + intro X a b h + /- It suffices to show that the lifts of `a` and `b` to morphisms + `X ⟶ hf.rep.pullback g` are equal, where `g = a ≫ f = a ≫ f`. -/ + suffices hf.rep.lift (g := a ≫ f) a (𝟙 X) (by simp) = + hf.rep.lift b (𝟙 X) (by simp [← h]) by + simpa using yoneda.congr_map this =≫ (hf.rep.fst (a ≫ f)) + -- This follows from the fact that the induced maps `hf.rep.pullback g ⟶ X` are mono. + have : Mono (hf.rep.snd (a ≫ f)) := hf.property_snd (a ≫ f) + simp only [← cancel_mono (hf.rep.snd (a ≫ f)), lift_snd] + +end MorphismProperty + end CategoryTheory diff --git a/Mathlib/CategoryTheory/NatTrans.lean b/Mathlib/CategoryTheory/NatTrans.lean index 0c12f372eaeac..af2c4079f9b36 100644 --- a/Mathlib/CategoryTheory/NatTrans.lean +++ b/Mathlib/CategoryTheory/NatTrans.lean @@ -72,7 +72,7 @@ open CategoryTheory.Functor section -variable {F G H I : C ⥤ D} +variable {F G H : C ⥤ D} /-- `vcomp α β` is the vertical compositions of natural transformations. -/ def vcomp (α : NatTrans F G) (β : NatTrans G H) : NatTrans F H where diff --git a/Mathlib/CategoryTheory/Opposites.lean b/Mathlib/CategoryTheory/Opposites.lean index 6d4f00e441da3..8cb8e3e027660 100644 --- a/Mathlib/CategoryTheory/Opposites.lean +++ b/Mathlib/CategoryTheory/Opposites.lean @@ -171,12 +171,12 @@ protected def unop (F : Cᵒᵖ ⥤ Dᵒᵖ) : C ⥤ D where /-- The isomorphism between `F.op.unop` and `F`. -/ @[simps!] def opUnopIso (F : C ⥤ D) : F.op.unop ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The isomorphism between `F.unop.op` and `F`. -/ @[simps!] def unopOpIso (F : Cᵒᵖ ⥤ Dᵒᵖ) : F.unop.op ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ variable (C D) @@ -187,7 +187,7 @@ def opHom : (C ⥤ D)ᵒᵖ ⥤ Cᵒᵖ ⥤ Dᵒᵖ where obj F := (unop F).op map α := { app := fun X => (α.unop.app (unop X)).op - naturality := fun X Y f => Quiver.Hom.unop_inj (α.unop.naturality f.unop).symm } + naturality := fun _ _ f => Quiver.Hom.unop_inj (α.unop.naturality f.unop).symm } /-- Take the "unopposite" of a functor is functorial. -/ @@ -197,7 +197,7 @@ def opInv : (Cᵒᵖ ⥤ Dᵒᵖ) ⥤ (C ⥤ D)ᵒᵖ where map α := Quiver.Hom.op { app := fun X => (α.app (op X)).unop - naturality := fun X Y f => Quiver.Hom.op_inj <| (α.naturality f.op).symm } + naturality := fun _ _ f => Quiver.Hom.op_inj <| (α.naturality f.op).symm } variable {C D} @@ -246,12 +246,12 @@ instance leftOp_full {F : C ⥤ Dᵒᵖ} [Full F] : Full F.leftOp where /-- The isomorphism between `F.leftOp.rightOp` and `F`. -/ @[simps!] def leftOpRightOpIso (F : C ⥤ Dᵒᵖ) : F.leftOp.rightOp ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The isomorphism between `F.rightOp.leftOp` and `F`. -/ @[simps!] def rightOpLeftOpIso (F : Cᵒᵖ ⥤ D) : F.rightOp.leftOp ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- Whenever possible, it is advisable to use the isomorphism `rightOpLeftOpIso` instead of this equality of functors. -/ @@ -363,7 +363,7 @@ taking `op` of each component gives a natural transformation `G.rightOp ⟶ F.ri -/ @[simps] protected def rightOp (α : F ⟶ G) : G.rightOp ⟶ F.rightOp where - app X := (α.app _).op + app _ := (α.app _).op naturality X Y f := Quiver.Hom.unop_inj (by simp) @[simp] diff --git a/Mathlib/CategoryTheory/PUnit.lean b/Mathlib/CategoryTheory/PUnit.lean index d3c89945af0f3..840d3c4759134 100644 --- a/Mathlib/CategoryTheory/PUnit.lean +++ b/Mathlib/CategoryTheory/PUnit.lean @@ -28,8 +28,6 @@ namespace Functor @[simps!] def star : C ⥤ Discrete PUnit.{w + 1} := (Functor.const _).obj ⟨⟨⟩⟩ --- Porting note (#10618): simp can simplify this -attribute [nolint simpNF] star_map_down_down variable {C} /-- Any two functors to `Discrete PUnit` are isomorphic. -/ @@ -55,7 +53,7 @@ def equiv : Discrete PUnit.{w + 1} ⥤ C ≌ C where { obj := fun F => F.obj ⟨⟨⟩⟩ map := fun θ => θ.app ⟨⟨⟩⟩ } inverse := Functor.const _ - unitIso := NatIso.ofComponents fun X => Discrete.natIso fun i => Iso.refl _ + unitIso := NatIso.ofComponents fun _ => Discrete.natIso fun _ => Iso.refl _ counitIso := NatIso.ofComponents Iso.refl end Functor diff --git a/Mathlib/CategoryTheory/PathCategory.lean b/Mathlib/CategoryTheory/PathCategory/Basic.lean similarity index 75% rename from Mathlib/CategoryTheory/PathCategory.lean rename to Mathlib/CategoryTheory/PathCategory/Basic.lean index 4f0b3ec849790..5901349a1ccbd 100644 --- a/Mathlib/CategoryTheory/PathCategory.lean +++ b/Mathlib/CategoryTheory/PathCategory/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2021 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kim Morrison +Authors: Kim Morrison, Robin Carlier -/ import Mathlib.CategoryTheory.EqToHom import Mathlib.CategoryTheory.Quotient @@ -37,7 +37,7 @@ namespace Paths instance categoryPaths : Category.{max u₁ v₁} (Paths V) where Hom := fun X Y : V => Quiver.Path X Y - id X := Quiver.Path.nil + id _ := Quiver.Path.nil comp f g := Quiver.Path.comp f g variable {V} @@ -49,6 +49,53 @@ def of : V ⥤q Paths V where obj X := X map f := f.toPath +/-- To prove a property on morphisms of a path category with given source `a`, it suffices to +prove it for the identity and prove that the property is preserved under composition on the right +with length 1 paths. -/ +lemma induction_fixed_source {a : Paths V} (P : ∀ {b : Paths V}, (a ⟶ b) → Prop) + (id : P (𝟙 a)) + (comp : ∀ {u v : V} (p : a ⟶ of.obj u) (q : u ⟶ v), P p → P (p ≫ of.map q)) : + ∀ {b : Paths V} (f : a ⟶ b), P f := by + intro _ f + induction f with + | nil => exact id + | cons _ w h => exact comp _ w h + +/-- To prove a property on morphisms of a path category with given target `b`, it suffices to prove +it for the identity and prove that the property is preserved under composition on the left +with length 1 paths. -/ +lemma induction_fixed_target {b : Paths V} (P : ∀ {a : Paths V}, (a ⟶ b) → Prop) + (id : P (𝟙 b)) + (comp : ∀ {u v : V} (p : of.obj v ⟶ b) (q : u ⟶ v), P p → P (of.map q ≫ p)) : + ∀ {a : Paths V} (f : a ⟶ b), P f := by + intro a f + generalize h : f.length = k + induction k generalizing f a with + | zero => cases f with + | nil => exact id + | cons _ _ => simp at h + | succ k h' => + obtain ⟨c, f, q, hq, rfl⟩ := f.eq_toPath_comp_of_length_eq_succ h + exact comp _ _ (h' _ hq) + +/-- To prove a property on morphisms of a path category, it suffices to prove it for the identity +and prove that the property is preserved under composition on the right with length 1 paths. -/ +lemma induction (P : ∀ {a b : Paths V}, (a ⟶ b) → Prop) + (id : ∀ {v : V}, P (𝟙 (of.obj v))) + (comp : ∀ {u v w : V} (p : of.obj u ⟶ of.obj v) (q : v ⟶ w), P p → P (p ≫ of.map q)) : + ∀ {a b : Paths V} (f : a ⟶ b), P f := + fun {_} ↦ induction_fixed_source _ id comp + +/-- To prove a property on morphisms of a path category, it suffices to prove it for the identity +and prove that the property is preserved under composition on the left with length 1 paths. -/ +lemma induction' (P : ∀ {a b : Paths V}, (a ⟶ b) → Prop) + (id : ∀ {v : V}, P (𝟙 (of.obj v))) + (comp : ∀ {u v w : V} (p : u ⟶ v) (q : of.obj v ⟶ of.obj w), P q → P (of.map p ≫ q)) : + ∀ {a b : Paths V} (f : a ⟶ b), P f := by + intro a b + revert a + exact induction_fixed_target (P := fun f ↦ P f) id (fun _ _ ↦ comp _ _) + attribute [local ext (iff := false)] Functor.ext /-- Any prefunctor from `V` lifts to a functor from `paths V` -/ @@ -57,7 +104,7 @@ def lift {C} [Category C] (φ : V ⥤q C) : Paths V ⥤ C where map {X} {Y} f := @Quiver.Path.rec V _ X (fun Y _ => φ.obj X ⟶ φ.obj Y) (𝟙 <| φ.obj X) (fun _ f ihp => ihp ≫ φ.map f) Y f - map_id X := rfl + map_id _ := rfl map_comp f g := by induction g with | nil => @@ -221,7 +268,7 @@ def quotientPathsEquiv : Quotient (pathsHomRel C) ≌ C where apply Quot.sound apply Quotient.CompClosure.of simp [Category.comp_id, Category.id_comp, pathsHomRel]) - counitIso := NatIso.ofComponents (fun X => Iso.refl _) (fun f => by simp [Quot.liftOn_mk]) + counitIso := NatIso.ofComponents (fun _ => Iso.refl _) (fun f => by simp [Quot.liftOn_mk]) functor_unitIso_comp X := by cases X simp only [pathsHomRel, pathComposition_obj, pathComposition_map, Functor.id_obj, diff --git a/Mathlib/CategoryTheory/PathCategory/MorphismProperty.lean b/Mathlib/CategoryTheory/PathCategory/MorphismProperty.lean new file mode 100644 index 0000000000000..91b603f5da11d --- /dev/null +++ b/Mathlib/CategoryTheory/PathCategory/MorphismProperty.lean @@ -0,0 +1,43 @@ +/- +Copyright (c) 2024 Robin Carlier. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robin Carlier +-/ +import Mathlib.CategoryTheory.PathCategory.Basic +import Mathlib.CategoryTheory.MorphismProperty.Basic + +/-! +# Properties of morphisms in a path category. + +We provide a formulation of induction principles for morphisms in a path category in terms of +`MorphismProperty`. This file is separate from `CategoryTheory.PathCategory.Basic` in order to +reduce transitive imports. -/ + + +universe v₁ u₁ + +namespace CategoryTheory.Paths + +variable (V : Type u₁) [Quiver.{v₁ + 1} V] + +/-- A reformulation of `CategoryTheory.Paths.induction` in terms of `MorphismProperty`. -/ +lemma morphismProperty_eq_top + (P : MorphismProperty (Paths V)) + (id : ∀ {v : V}, P (𝟙 (of.obj v))) + (comp : ∀ {u v w : V} (p : of.obj u ⟶ of.obj v) (q : v ⟶ w), P p → P (p ≫ of.map q)) : + P = ⊤ := by + ext; constructor + · simp + · exact fun _ ↦ induction (fun f ↦ P f) id comp _ + +/-- A reformulation of `CategoryTheory.Paths.induction'` in terms of `MorphismProperty`. -/ +lemma morphismProperty_eq_top' + (P : MorphismProperty (Paths V)) + (id : ∀ {v : V}, P (𝟙 (of.obj v))) + (comp : ∀ {u v w : V} (p : u ⟶ v) (q : of.obj v ⟶ of.obj w), P q → P (of.map p ≫ q)) : + P = ⊤ := by + ext; constructor + · simp + · exact fun _ ↦ induction' (fun f ↦ P f) id comp _ + +end CategoryTheory.Paths diff --git a/Mathlib/CategoryTheory/Pi/Basic.lean b/Mathlib/CategoryTheory/Pi/Basic.lean index 166b83c21ef2a..477e2fe2a21e5 100644 --- a/Mathlib/CategoryTheory/Pi/Basic.lean +++ b/Mathlib/CategoryTheory/Pi/Basic.lean @@ -49,7 +49,6 @@ theorem comp_apply {X Y Z : ∀ i, C i} (f : X ⟶ Y) (g : Y ⟶ Z) (i) : (f ≫ g : ∀ i, X i ⟶ Z i) i = f i ≫ g i := rfl --- Porting note: need to add an additional `ext` lemma. @[ext] lemma ext {X Y : ∀ i, C i} {f g : X ⟶ Y} (w : ∀ i, f i = g i) : f = g := funext (w ·) @@ -111,7 +110,7 @@ def comapComp (f : K → J) (g : J → I) : comap C g ⋙ comap (C ∘ g) f ≅ /-- The natural isomorphism between pulling back then evaluating, and just evaluating. -/ @[simps!] def comapEvalIsoEval (h : J → I) (j : J) : comap C h ⋙ eval (C ∘ h) j ≅ eval C (h j) := - NatIso.ofComponents (fun f => Iso.refl _) (by simp only [Iso.refl]; aesop_cat) + NatIso.ofComponents (fun _ => Iso.refl _) (by simp only [Iso.refl]; aesop_cat) end @@ -141,7 +140,7 @@ def sum : (∀ i, C i) ⥤ (∀ j, D j) ⥤ ∀ s : I ⊕ J, Sum.elim C D s wher match s with | .inl i => X i | .inr j => Y j - map := fun {Y} {Y'} f s => + map := fun {_} {_} f s => match s with | .inl i => 𝟙 (X i) | .inr j => f j } @@ -206,7 +205,7 @@ section EqToHom @[simp] theorem eqToHom_proj {x x' : ∀ i, C i} (h : x = x') (i : I) : - (eqToHom h : x ⟶ x') i = eqToHom (Function.funext_iff.mp h i) := by + (eqToHom h : x ⟶ x') i = eqToHom (funext_iff.mp h i) := by subst h rfl @@ -348,7 +347,7 @@ def Pi.optionEquivalence (C' : Option J → Type u₁) [∀ i, Category.{v₁} ( | some i => Prod.snd _ _ ⋙ (Pi.eval _ i)) unitIso := NatIso.pi' (fun i => match i with | none => Iso.refl _ - | some i => Iso.refl _) + | some _ => Iso.refl _) counitIso := by exact Iso.refl _ namespace Equivalence diff --git a/Mathlib/CategoryTheory/Preadditive/Basic.lean b/Mathlib/CategoryTheory/Preadditive/Basic.lean index 8df1e560ccfc4..0ddcb0081738b 100644 --- a/Mathlib/CategoryTheory/Preadditive/Basic.lean +++ b/Mathlib/CategoryTheory/Preadditive/Basic.lean @@ -5,7 +5,7 @@ Authors: Markus Himmel, Jakob von Raumer -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Group.Hom.Defs -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.End import Mathlib.CategoryTheory.Endomorphism import Mathlib.CategoryTheory.Limits.Shapes.Kernels diff --git a/Mathlib/CategoryTheory/Preadditive/EilenbergMoore.lean b/Mathlib/CategoryTheory/Preadditive/EilenbergMoore.lean index 6770c026e762f..f7dd3eabd7f76 100644 --- a/Mathlib/CategoryTheory/Preadditive/EilenbergMoore.lean +++ b/Mathlib/CategoryTheory/Preadditive/EilenbergMoore.lean @@ -78,7 +78,6 @@ instance Monad.algebraPreadditive : Preadditive (Monad.Algebra T) where zsmul_succ' := by intros ext - dsimp simp only [natCast_zsmul, succ_nsmul] rfl zsmul_neg' := by @@ -159,7 +158,6 @@ instance Comonad.coalgebraPreadditive : Preadditive (Comonad.Coalgebra U) where zsmul_succ' := by intros ext - dsimp simp only [natCast_zsmul, succ_nsmul] rfl zsmul_neg' := by diff --git a/Mathlib/CategoryTheory/Preadditive/EndoFunctor.lean b/Mathlib/CategoryTheory/Preadditive/EndoFunctor.lean index 006286e5be91c..f7fd470a65628 100644 --- a/Mathlib/CategoryTheory/Preadditive/EndoFunctor.lean +++ b/Mathlib/CategoryTheory/Preadditive/EndoFunctor.lean @@ -78,7 +78,6 @@ instance Endofunctor.algebraPreadditive : Preadditive (Endofunctor.Algebra F) wh zsmul_succ' := by intros apply Algebra.Hom.ext - dsimp simp only [natCast_zsmul, succ_nsmul] rfl zsmul_neg' := by @@ -156,7 +155,6 @@ instance Endofunctor.coalgebraPreadditive : Preadditive (Endofunctor.Coalgebra F zsmul_succ' := by intros apply Coalgebra.Hom.ext - dsimp simp only [natCast_zsmul, succ_nsmul] rfl zsmul_neg' := by diff --git a/Mathlib/CategoryTheory/Preadditive/FunctorCategory.lean b/Mathlib/CategoryTheory/Preadditive/FunctorCategory.lean index f1786b2cbca39..8df532c9e1251 100644 --- a/Mathlib/CategoryTheory/Preadditive/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Preadditive/FunctorCategory.lean @@ -20,7 +20,7 @@ open CategoryTheory.Limits Preadditive variable {C D : Type*} [Category C] [Category D] [Preadditive D] instance {F G : C ⥤ D} : Zero (F ⟶ G) where - zero := { app := fun X => 0 } + zero := { app := fun _ => 0 } instance {F G : C ⥤ D} : Add (F ⟶ G) where add α β := { app := fun X => α.app X + β.app X } diff --git a/Mathlib/CategoryTheory/Preadditive/Injective.lean b/Mathlib/CategoryTheory/Preadditive/Injective.lean index b5a5accf6ee7f..4ee0d211f19f3 100644 --- a/Mathlib/CategoryTheory/Preadditive/Injective.lean +++ b/Mathlib/CategoryTheory/Preadditive/Injective.lean @@ -108,7 +108,7 @@ instance (X : Type u₁) [Nonempty X] : Injective X where change dite (f y ∈ Set.range f) (fun h => g (Classical.choose h)) _ = _ split_ifs <;> rename_i h · rw [mono_iff_injective] at mono - erw [mono (Classical.choose_spec h)] + rw [mono (Classical.choose_spec h)] · exact False.elim (h ⟨y, rfl⟩)⟩ instance Type.enoughInjectives : EnoughInjectives (Type u₁) where @@ -187,7 +187,8 @@ variable {L : C ⥤ D} {R : D ⥤ C} [PreservesMonomorphisms L] theorem injective_of_adjoint (adj : L ⊣ R) (J : D) [Injective J] : Injective <| R.obj J := ⟨fun {A} {_} g f im => ⟨adj.homEquiv _ _ (factorThru ((adj.homEquiv A J).symm g) (L.map f)), - (adj.homEquiv _ _).symm.injective (by simp)⟩⟩ + (adj.homEquiv _ _).symm.injective + (by simp [Adjunction.homEquiv_unit, Adjunction.homEquiv_counit])⟩⟩ end Adjunction diff --git a/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean b/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean index 9f756b5cdb943..8744f1317727f 100644 --- a/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean +++ b/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean @@ -92,13 +92,11 @@ lemma exact_succ (n : ℕ) : theorem ι_f_succ (n : ℕ) : I.ι.f (n + 1) = 0 := (isZero_single_obj_X _ _ _ _ (by simp)).eq_of_src _ _ --- Porting note (#10618): removed @[simp] simp can prove this @[reassoc] theorem ι_f_zero_comp_complex_d : I.ι.f 0 ≫ I.cocomplex.d 0 1 = 0 := by simp --- Porting note (#10618): removed @[simp] simp can prove this theorem complex_d_comp (n : ℕ) : I.cocomplex.d n (n + 1) ≫ I.cocomplex.d (n + 1) (n + 2) = 0 := by simp diff --git a/Mathlib/CategoryTheory/Preadditive/Mat.lean b/Mathlib/CategoryTheory/Preadditive/Mat.lean index d3d9783dc37c7..8ab0b6f6a6063 100644 --- a/Mathlib/CategoryTheory/Preadditive/Mat.lean +++ b/Mathlib/CategoryTheory/Preadditive/Mat.lean @@ -105,7 +105,6 @@ instance : Category.{v₁} (Mat_ C) where simp_rw [Hom.comp, sum_comp, comp_sum, Category.assoc] rw [Finset.sum_comm] --- Porting note (#5229): added because `DMatrix.ext` is not triggered automatically @[ext] theorem hom_ext {M N : Mat_ C} (f g : M ⟶ N) (H : ∀ i j, f i j = g i j) : f = g := DMatrix.ext_iff.mp H @@ -298,8 +297,8 @@ variable {C} -/ @[simps] def isoBiproductEmbedding (M : Mat_ C) : M ≅ ⨁ fun i => (embedding C).obj (M.X i) where - hom := biproduct.lift fun i j k => if h : j = i then eqToHom (congr_arg M.X h) else 0 - inv := biproduct.desc fun i j k => if h : i = k then eqToHom (congr_arg M.X h) else 0 + hom := biproduct.lift fun i j _ => if h : j = i then eqToHom (congr_arg M.X h) else 0 + inv := biproduct.desc fun i _ k => if h : i = k then eqToHom (congr_arg M.X h) else 0 hom_inv_id := by simp only [biproduct.lift_desc] funext i j @@ -432,7 +431,6 @@ def liftUnique (F : C ⥤ D) [Functor.Additive F] (L : Mat_ C ⥤ D) [Functor.Ad dsimp simpa using α.hom.naturality (f j k) --- Porting note (#11182): removed @[ext] as the statement is not an equality -- TODO is there some uniqueness statement for the natural isomorphism in `liftUnique`? /-- Two additive functors `Mat_ C ⥤ D` are naturally isomorphic if their precompositions with `embedding C` are naturally isomorphic as functors `C ⥤ D`. -/ @@ -505,7 +503,6 @@ section variable {R : Type u} [Semiring R] --- Porting note (#5229): added because `Matrix.ext` is not triggered automatically @[ext] theorem hom_ext {X Y : Mat R} (f g : X ⟶ Y) (h : ∀ i j, f i j = g i j) : f = g := Matrix.ext_iff.mp h diff --git a/Mathlib/CategoryTheory/Preadditive/Projective.lean b/Mathlib/CategoryTheory/Preadditive/Projective.lean index e0900aad10375..c593644a263b3 100644 --- a/Mathlib/CategoryTheory/Preadditive/Projective.lean +++ b/Mathlib/CategoryTheory/Preadditive/Projective.lean @@ -92,8 +92,8 @@ instance zero_projective [HasZeroObject C] : Projective (0 : C) := end -theorem of_iso {P Q : C} (i : P ≅ Q) (hP : Projective P) : Projective Q where - factors f e e_epi := +theorem of_iso {P Q : C} (i : P ≅ Q) (_ : Projective P) : Projective Q where + factors f e _ := let ⟨f', hf'⟩ := Projective.factors (i.hom ≫ f) e ⟨i.inv ≫ f', by simp [hf']⟩ diff --git a/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean b/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean index 1447ce251a876..51a7ef3dae857 100644 --- a/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean +++ b/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean @@ -89,7 +89,6 @@ theorem complex_d_comp_π_f_zero : P.complex.d 1 0 ≫ P.π.f 0 = 0 := by rw [← P.π.comm 1 0, single_obj_d, comp_zero] --- Porting note (#10618): removed @[simp] simp can prove this theorem complex_d_succ_comp (n : ℕ) : P.complex.d n (n + 1) ≫ P.complex.d (n + 1) (n + 2) = 0 := by simp diff --git a/Mathlib/CategoryTheory/Preadditive/Schur.lean b/Mathlib/CategoryTheory/Preadditive/Schur.lean index 2fd3b980f6f59..9c571b370957f 100644 --- a/Mathlib/CategoryTheory/Preadditive/Schur.lean +++ b/Mathlib/CategoryTheory/Preadditive/Schur.lean @@ -66,9 +66,9 @@ noncomputable instance [HasKernels C] {X : C} [Simple X] : DivisionRing (End X) haveI := isIso_of_hom_simple hf exact IsIso.inv_hom_id f nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl open Module diff --git a/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean b/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean index 96b1f0270625c..1d23ec18a0866 100644 --- a/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean +++ b/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean @@ -39,10 +39,10 @@ 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.ofHom + map f := ModuleCat.asHom { toFun := fun g => f.unop ≫ g - map_add' := fun g g' => comp_add _ _ _ _ _ _ - map_smul' := fun r g => Eq.symm <| Category.assoc _ _ _ } + map_add' := fun _ _ => comp_add _ _ _ _ _ _ + map_smul' := fun _ _ => Eq.symm <| Category.assoc _ _ _ } /-- The Yoneda embedding for preadditive categories sends an object `Y` to the presheaf sending an object `X` to the group of morphisms `X ⟶ Y`. At each point, we get an additional `End Y`-module @@ -52,11 +52,11 @@ structure, see `preadditiveYonedaObj`. def preadditiveYoneda : C ⥤ Cᵒᵖ ⥤ AddCommGrp.{v} where obj Y := preadditiveYonedaObj Y ⋙ forget₂ _ _ map f := - { app := fun X => + { app := fun _ => { toFun := fun g => g ≫ f map_zero' := Limits.zero_comp - map_add' := fun g g' => add_comp _ _ _ _ _ _ } - naturality := fun X X' g => AddCommGrp.ext fun x => Category.assoc _ _ _ } + map_add' := fun _ _ => add_comp _ _ _ _ _ _ } + naturality := fun _ _ _ => AddCommGrp.ext fun _ => Category.assoc _ _ _ } map_id _ := by ext; dsimp; simp map_comp f g := by ext; dsimp; simp @@ -66,10 +66,10 @@ 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.ofHom + map f := ModuleCat.asHom { toFun := fun g => g ≫ f - map_add' := fun g g' => add_comp _ _ _ _ _ _ - map_smul' := fun r g => Category.assoc _ _ _ } + map_add' := fun _ _ => add_comp _ _ _ _ _ _ + map_smul' := fun _ _ => Category.assoc _ _ _ } /-- The Yoneda embedding for preadditive categories sends an object `X` to the copresheaf sending an object `Y` to the group of morphisms `X ⟶ Y`. At each point, we get an additional `End X`-module @@ -79,12 +79,12 @@ structure, see `preadditiveCoyonedaObj`. def preadditiveCoyoneda : Cᵒᵖ ⥤ C ⥤ AddCommGrp.{v} where obj X := preadditiveCoyonedaObj X ⋙ forget₂ _ _ map f := - { app := fun Y => + { app := fun _ => { toFun := fun g => f.unop ≫ g map_zero' := Limits.comp_zero - map_add' := fun g g' => comp_add _ _ _ _ _ _ } - naturality := fun Y Y' g => - AddCommGrp.ext fun x => Eq.symm <| Category.assoc _ _ _ } + map_add' := fun _ _ => comp_add _ _ _ _ _ _ } + naturality := fun _ _ _ => + AddCommGrp.ext fun _ => Eq.symm <| Category.assoc _ _ _ } map_id _ := by ext; dsimp; simp map_comp f g := by ext; dsimp; simp diff --git a/Mathlib/CategoryTheory/Products/Basic.lean b/Mathlib/CategoryTheory/Products/Basic.lean index 58958ff88a2de..3abbf24a0925d 100644 --- a/Mathlib/CategoryTheory/Products/Basic.lean +++ b/Mathlib/CategoryTheory/Products/Basic.lean @@ -45,6 +45,11 @@ instance prod : Category.{max v₁ v₂} (C × D) where id X := ⟨𝟙 X.1, 𝟙 X.2⟩ comp f g := (f.1 ≫ g.1, f.2 ≫ g.2) +@[ext] +lemma prod.hom_ext {X Y : C × D} {f g : X ⟶ Y} (h₁ : f.1 = g.1) (h₂ : f.2 = g.2) : f = g := by + dsimp + ext <;> assumption + /-- Two rfl lemmas that cannot be generated by `@[simps]`. -/ @[simp] theorem prod_id (X : C) (Y : D) : 𝟙 (X, Y) = (𝟙 X, 𝟙 Y) := @@ -171,9 +176,9 @@ def evaluation : C ⥤ (C ⥤ D) ⥤ D where obj X := { obj := fun F => F.obj X map := fun α => α.app X } - map {X} {Y} f := + map {_} {_} f := { app := fun F => F.map f - naturality := fun {F} {G} α => Eq.symm (α.naturality f) } + naturality := fun {_} {_} α => Eq.symm (α.naturality f) } /-- The "evaluation of `F` at `X`" functor, as a functor `C × (C ⥤ D) ⥤ D`. @@ -193,7 +198,7 @@ variable {C} /-- The constant functor followed by the evaluation functor is just the identity. -/ @[simps!] def Functor.constCompEvaluationObj (X : C) : Functor.const C ⋙ (evaluation C D).obj X ≅ 𝟭 D := - NatIso.ofComponents fun Y => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ end @@ -219,12 +224,12 @@ def prod' (F : A ⥤ B) (G : A ⥤ C) : A ⥤ B × C where /-- The product `F.prod' G` followed by projection on the first component is isomorphic to `F` -/ @[simps!] def prod'CompFst (F : A ⥤ B) (G : A ⥤ C) : F.prod' G ⋙ CategoryTheory.Prod.fst B C ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The product `F.prod' G` followed by projection on the second component is isomorphic to `G` -/ @[simps!] def prod'CompSnd (F : A ⥤ B) (G : A ⥤ C) : F.prod' G ⋙ CategoryTheory.Prod.snd B C ≅ G := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ section @@ -308,6 +313,32 @@ def compEvaluation (F : A ⥤ B ⥤ C) (b) : F ⋙ (evaluation _ _).obj b ≅ F. theorem comp_evaluation (F : A ⥤ B ⥤ C) (b) : F ⋙ (evaluation _ _).obj b = F.flip.obj b := rfl +/-- Whiskering by `F` and then evaluating at `a` is the same as evaluating at `F.obj a`. -/ +@[simps!] +def whiskeringLeftCompEvaluation (F : A ⥤ B) (a : A) : + (whiskeringLeft A B C).obj F ⋙ (evaluation A C).obj a ≅ (evaluation B C).obj (F.obj a) := + Iso.refl _ + +/-- Whiskering by `F` and then evaluating at `a` is the same as evaluating at `F.obj a`. -/ +@[simp] +theorem whiskeringLeft_comp_evaluation (F : A ⥤ B) (a : A) : + (whiskeringLeft A B C).obj F ⋙ (evaluation A C).obj a = (evaluation B C).obj (F.obj a) := + rfl + +/-- Whiskering by `F` and then evaluating at `a` is the same as evaluating at `F` and then +applying `F`. -/ +@[simps!] +def whiskeringRightCompEvaluation (F : B ⥤ C) (a : A) : + (whiskeringRight A B C).obj F ⋙ (evaluation _ _).obj a ≅ (evaluation _ _).obj a ⋙ F := + Iso.refl _ + +/-- Whiskering by `F` and then evaluating at `a` is the same as evaluating at `F` and then +applying `F`. -/ +@[simp] +theorem whiskeringRight_comp_evaluation (F : B ⥤ C) (a : A) : + (whiskeringRight A B C).obj F ⋙ (evaluation _ _).obj a = (evaluation _ _).obj a ⋙ F := + rfl + variable (A B C) /-- The forward direction for `functorProdFunctorEquiv` -/ diff --git a/Mathlib/CategoryTheory/Quotient.lean b/Mathlib/CategoryTheory/Quotient.lean index 5a1f9831b2055..2379d976800bc 100644 --- a/Mathlib/CategoryTheory/Quotient.lean +++ b/Mathlib/CategoryTheory/Quotient.lean @@ -188,7 +188,7 @@ lemma lift_unique' (F₁ F₂ : Quotient r ⥤ D) (h : functor r ⋙ F₁ = func /-- The original functor factors through the induced functor. -/ def lift.isLift : functor r ⋙ lift r F H ≅ F := - NatIso.ofComponents fun X ↦ Iso.refl _ + NatIso.ofComponents fun _ ↦ Iso.refl _ @[simp] theorem lift.isLift_hom (X : C) : (lift.isLift r F H).hom.app X = 𝟙 (F.obj X) := diff --git a/Mathlib/CategoryTheory/Shift/Basic.lean b/Mathlib/CategoryTheory/Shift/Basic.lean index c8b2f4ddfaec9..889c3bf069f82 100644 --- a/Mathlib/CategoryTheory/Shift/Basic.lean +++ b/Mathlib/CategoryTheory/Shift/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kim Morrison, Johan Commelin, Andrew Yang +Authors: Kim Morrison, Johan Commelin, Andrew Yang, Joël Riou -/ import Mathlib.Algebra.Group.Basic import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Zero @@ -487,6 +487,69 @@ theorem shift_shiftFunctorCompIsoId_neg_add_cancel_inv_app (n : A) (X : C) : end +section + +variable (A) + +lemma shiftFunctorCompIsoId_zero_zero_hom_app (X : C) : + (shiftFunctorCompIsoId C 0 0 (add_zero 0)).hom.app X = + ((shiftFunctorZero C A).hom.app X)⟦0⟧' ≫ (shiftFunctorZero C A).hom.app X := by + simp [shiftFunctorCompIsoId, shiftFunctorAdd'_zero_add_inv_app] + +lemma shiftFunctorCompIsoId_zero_zero_inv_app (X : C) : + (shiftFunctorCompIsoId C 0 0 (add_zero 0)).inv.app X = + (shiftFunctorZero C A).inv.app X ≫ ((shiftFunctorZero C A).inv.app X)⟦0⟧' := by + simp [shiftFunctorCompIsoId, shiftFunctorAdd'_zero_add_hom_app] + +end + +section + +variable (m n p m' n' p' : A) (hm : m' + m = 0) (hn : n' + n = 0) (hp : p' + p = 0) + (h : m + n = p) + +lemma shiftFunctorCompIsoId_add'_inv_app : + (shiftFunctorCompIsoId C p' p hp).inv.app X = + (shiftFunctorCompIsoId C n' n hn).inv.app X ≫ + (shiftFunctorCompIsoId C m' m hm).inv.app (X⟦n'⟧)⟦n⟧' ≫ + (shiftFunctorAdd' C m n p h).inv.app (X⟦n'⟧⟦m'⟧) ≫ + ((shiftFunctorAdd' C n' m' p' + (by rw [← add_left_inj p, hp, ← h, add_assoc, + ← add_assoc m', hm, zero_add, hn])).inv.app X)⟦p⟧' := by + dsimp [shiftFunctorCompIsoId] + simp only [Functor.map_comp, Category.assoc] + congr 1 + rw [← NatTrans.naturality] + dsimp + rw [← cancel_mono ((shiftFunctorAdd' C p' p 0 hp).inv.app X), Iso.hom_inv_id_app, + Category.assoc, Category.assoc, Category.assoc, Category.assoc, + ← shiftFunctorAdd'_assoc_inv_app p' m n n' p 0 + (by rw [← add_left_inj n, hn, add_assoc, h, hp]) h (by rw [add_assoc, h, hp]), + ← Functor.map_comp_assoc, ← Functor.map_comp_assoc, ← Functor.map_comp_assoc, + Category.assoc, Category.assoc, + shiftFunctorAdd'_assoc_inv_app n' m' m p' 0 n' _ _ + (by rw [add_assoc, hm, add_zero]), Iso.hom_inv_id_app_assoc, + ← shiftFunctorAdd'_add_zero_hom_app, Iso.hom_inv_id_app, + Functor.map_id, Category.id_comp, Iso.hom_inv_id_app] + +lemma shiftFunctorCompIsoId_add'_hom_app : + (shiftFunctorCompIsoId C p' p hp).hom.app X = + ((shiftFunctorAdd' C n' m' p' + (by rw [← add_left_inj p, hp, ← h, add_assoc, + ← add_assoc m', hm, zero_add, hn])).hom.app X)⟦p⟧' ≫ + (shiftFunctorAdd' C m n p h).hom.app (X⟦n'⟧⟦m'⟧) ≫ + (shiftFunctorCompIsoId C m' m hm).hom.app (X⟦n'⟧)⟦n⟧' ≫ + (shiftFunctorCompIsoId C n' n hn).hom.app X := by + rw [← cancel_mono ((shiftFunctorCompIsoId C p' p hp).inv.app X), Iso.hom_inv_id_app, + shiftFunctorCompIsoId_add'_inv_app m n p m' n' p' hm hn hp h, + Category.assoc, Category.assoc, Category.assoc, Iso.hom_inv_id_app_assoc, + ← Functor.map_comp_assoc, Iso.hom_inv_id_app] + dsimp + rw [Functor.map_id, Category.id_comp, Iso.hom_inv_id_app_assoc, + ← Functor.map_comp, Iso.hom_inv_id_app, Functor.map_id] + +end + open CategoryTheory.Limits variable [HasZeroMorphisms C] diff --git a/Mathlib/CategoryTheory/Shift/CommShift.lean b/Mathlib/CategoryTheory/Shift/CommShift.lean index 5f75457aa59db..62d33df9efcfe 100644 --- a/Mathlib/CategoryTheory/Shift/CommShift.lean +++ b/Mathlib/CategoryTheory/Shift/CommShift.lean @@ -149,7 +149,7 @@ namespace CommShift variable (C) in instance id : CommShift (𝟭 C) A where - iso := fun a => rightUnitor _ ≪≫ (leftUnitor _).symm + iso := fun _ => rightUnitor _ ≪≫ (leftUnitor _).symm instance comp [F.CommShift A] [G.CommShift A] : (F ⋙ G).CommShift A where iso a := (Functor.associator _ _ _).symm ≪≫ isoWhiskerRight (F.commShiftIso a) _ ≪≫ @@ -246,7 +246,7 @@ variable {C D E J : Type*} [Category C] [Category D] [Category E] [Category J] /-- If `τ : F₁ ⟶ F₂` is a natural transformation between two functors which commute with a shift by an additive monoid `A`, this typeclass asserts a compatibility of `τ` with these shifts. -/ -class CommShift : Prop := +class CommShift : Prop where comm' (a : A) : (F₁.commShiftIso a).hom ≫ whiskerRight τ _ = whiskerLeft _ τ ≫ (F₂.commShiftIso a).hom diff --git a/Mathlib/CategoryTheory/Shift/Localization.lean b/Mathlib/CategoryTheory/Shift/Localization.lean index 5e9f9b7a925b5..1f74884924d44 100644 --- a/Mathlib/CategoryTheory/Shift/Localization.lean +++ b/Mathlib/CategoryTheory/Shift/Localization.lean @@ -32,7 +32,7 @@ namespace MorphismProperty /-- A morphism property `W` on a category `C` is compatible with the shift by a monoid `A` when for all `a : A`, a morphism `f` belongs to `W` if and only if `f⟦a⟧'` does. -/ -class IsCompatibleWithShift : Prop := +class IsCompatibleWithShift : Prop where /-- the condition that for all `a : A`, the morphism property `W` is not changed when we take its inverse image by the shift functor by `a` -/ condition : ∀ (a : A), W.inverseImage (shiftFunctor C a) = W diff --git a/Mathlib/CategoryTheory/Shift/Quotient.lean b/Mathlib/CategoryTheory/Shift/Quotient.lean index d029cd486c714..f789f82c2883c 100644 --- a/Mathlib/CategoryTheory/Shift/Quotient.lean +++ b/Mathlib/CategoryTheory/Shift/Quotient.lean @@ -32,7 +32,7 @@ namespace HomRel /-- A relation on morphisms is compatible with the shift by a monoid `A` when the relation if preserved by the shift. -/ -class IsCompatibleWithShift : Prop := +class IsCompatibleWithShift : Prop where /-- the condition that the relation is preserved by the shift -/ condition : ∀ (a : A) ⦃X Y : C⦄ (f g : X ⟶ Y), r f g → r (f⟦a⟧') (g⟦a⟧') diff --git a/Mathlib/CategoryTheory/Shift/ShiftedHomOpposite.lean b/Mathlib/CategoryTheory/Shift/ShiftedHomOpposite.lean new file mode 100644 index 0000000000000..5f21658547de3 --- /dev/null +++ b/Mathlib/CategoryTheory/Shift/ShiftedHomOpposite.lean @@ -0,0 +1,155 @@ +/- +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.Triangulated.Opposite +import Mathlib.CategoryTheory.Shift.ShiftedHom + +/-! Shifted morphisms in the opposite category + +If `C` is a category equipped with a shift by `ℤ`, `X` and `Y` are objects +of `C`, and `n : ℤ`, we define a bijection +`ShiftedHom.opEquiv : ShiftedHom X Y n ≃ ShiftedHom (Opposite.op Y) (Opposite.op X) n`. +We also introduce `ShiftedHom.opEquiv'` which produces a bijection +`ShiftedHom X Y a' ≃ (Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦n⟧)` when `n + a = a'`. +The compatibilities that are obtained shall be used in order to study +the homological functor `preadditiveYoneda.obj B : Cᵒᵖ ⥤ Type _` when `B` is an object +in a pretriangulated category `C`. + +-/ + +namespace CategoryTheory + +open Category Pretriangulated.Opposite Pretriangulated + +variable {C : Type*} [Category C] [HasShift C ℤ] {X Y Z : C} + +namespace ShiftedHom + +/-- The bijection `ShiftedHom X Y n ≃ ShiftedHom (Opposite.op Y) (Opposite.op X) n` when +`n : ℤ`, and `X` and `Y` are objects of a category equipped with a shift by `ℤ`. -/ +noncomputable def opEquiv (n : ℤ) : + ShiftedHom X Y n ≃ ShiftedHom (Opposite.op Y) (Opposite.op X) n := + Quiver.Hom.opEquiv.trans + ((opShiftFunctorEquivalence C n).symm.toAdjunction.homEquiv (Opposite.op Y) (Opposite.op X)) + +lemma opEquiv_symm_apply {n : ℤ} (f : ShiftedHom (Opposite.op Y) (Opposite.op X) n) : + (opEquiv n).symm f = + ((opShiftFunctorEquivalence C n).unitIso.inv.app (Opposite.op X)).unop ≫ f.unop⟦n⟧' := by + rfl + +lemma opEquiv_symm_apply_comp {X Y : C} {a : ℤ} + (f : ShiftedHom (Opposite.op X) (Opposite.op Y) a) {b : ℤ} {Z : C} + (z : ShiftedHom X Z b) {c : ℤ} (h : b + a = c) : + ((ShiftedHom.opEquiv a).symm f).comp z h = + (ShiftedHom.opEquiv a).symm (z.op ≫ f) ≫ + (shiftFunctorAdd' C b a c h).inv.app Z := by + rw [ShiftedHom.opEquiv_symm_apply, ShiftedHom.opEquiv_symm_apply, + ShiftedHom.comp] + dsimp + simp only [assoc, Functor.map_comp] + +lemma opEquiv_symm_comp {a b : ℤ} + (f : ShiftedHom (Opposite.op Z) (Opposite.op Y) a) + (g : ShiftedHom (Opposite.op Y) (Opposite.op X) b) + {c : ℤ} (h : b + a = c) : + (opEquiv _).symm (f.comp g h) = + ((opEquiv _).symm g).comp ((opEquiv _).symm f) (by omega) := by + rw [opEquiv_symm_apply, opEquiv_symm_apply, + opShiftFunctorEquivalence_unitIso_inv_app_eq _ _ _ _ (show a + b = c by omega), comp, comp] + dsimp + rw [assoc, assoc, assoc, assoc, ← Functor.map_comp, ← unop_comp_assoc, + Iso.inv_hom_id_app] + dsimp + rw [assoc, id_comp, Functor.map_comp, ← NatTrans.naturality_assoc, + ← NatTrans.naturality, opEquiv_symm_apply] + dsimp + rw [← Functor.map_comp_assoc, ← Functor.map_comp_assoc, + ← Functor.map_comp_assoc] + rw [← unop_comp_assoc] + erw [← NatTrans.naturality] + rfl + +/-- The bijection `ShiftedHom X Y a' ≃ (Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦n⟧)` +when integers `n`, `a` and `a'` satisfy `n + a = a'`, and `X` and `Y` are objects +of a category equipped with a shift by `ℤ`. -/ +noncomputable def opEquiv' (n a a' : ℤ) (h : n + a = a') : + ShiftedHom X Y a' ≃ (Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦n⟧) := + ((shiftFunctorAdd' C a n a' (by omega)).symm.app Y).homToEquiv.symm.trans (opEquiv n) + +lemma opEquiv'_symm_apply {n a : ℤ} (f : Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦n⟧) + (a' : ℤ) (h : n + a = a') : + (opEquiv' n a a' h).symm f = + (opEquiv n).symm f ≫ (shiftFunctorAdd' C a n a' (by omega)).inv.app _ := + rfl + +lemma opEquiv'_apply {a' : ℤ} (f : ShiftedHom X Y a') (n a : ℤ) (h : n + a = a') : + opEquiv' n a a' h f = + opEquiv n (f ≫ (shiftFunctorAdd' C a n a' (by omega)).hom.app Y) := by + rfl + +lemma opEquiv'_symm_op_opShiftFunctorEquivalence_counitIso_inv_app_op_shift + {n m : ℤ} (f : ShiftedHom X Y n) (g : ShiftedHom Y Z m) + (q : ℤ) (hq : n + m = q) : + (opEquiv' n m q hq).symm + (g.op ≫ (opShiftFunctorEquivalence C n).counitIso.inv.app _ ≫ f.op⟦n⟧') = + f.comp g (by omega) := by + rw [opEquiv'_symm_apply, opEquiv_symm_apply] + dsimp [comp] + apply Quiver.Hom.op_inj + simp only [assoc, Functor.map_comp, op_comp, Quiver.Hom.op_unop, + opShiftFunctorEquivalence_unitIso_inv_naturality] + erw [(opShiftFunctorEquivalence C n).inverse_counitInv_comp_assoc (Opposite.op Y)] + +lemma opEquiv'_symm_comp (f : Y ⟶ X) {n a : ℤ} (x : Opposite.op (Z⟦a⟧) ⟶ (Opposite.op X⟦n⟧)) + (a' : ℤ) (h : n + a = a') : + (opEquiv' n a a' h).symm (x ≫ f.op⟦n⟧') = f ≫ (opEquiv' n a a' h).symm x := + Quiver.Hom.op_inj (by simp [opEquiv'_symm_apply, opEquiv_symm_apply]) + +lemma opEquiv'_zero_add_symm (a : ℤ) (f : Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦(0 : ℤ)⟧) : + (opEquiv' 0 a a (zero_add a)).symm f = + ((shiftFunctorZero Cᵒᵖ ℤ).hom.app _).unop ≫ f.unop := by + simp [opEquiv'_symm_apply, opEquiv_symm_apply, shiftFunctorAdd'_add_zero, + opShiftFunctorEquivalence_zero_unitIso_inv_app] + +lemma opEquiv'_add_symm (n m a a' a'' : ℤ) (ha' : n + a = a') (ha'' : m + a' = a'') + (x : (Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦m + n⟧)) : + (opEquiv' (m + n) a a'' (by omega)).symm x = + (opEquiv' m a' a'' ha'').symm ((opEquiv' n a a' ha').symm + (x ≫ (shiftFunctorAdd Cᵒᵖ m n).hom.app _)).op := by + simp only [opEquiv'_symm_apply, opEquiv_symm_apply, + opShiftFunctorEquivalence_unitIso_inv_app_eq _ _ _ _ (add_comm n m)] + dsimp + simp only [assoc, Functor.map_comp, ← shiftFunctorAdd'_eq_shiftFunctorAdd, + ← NatTrans.naturality_assoc, + shiftFunctorAdd'_assoc_inv_app a n m a' (m + n) a'' (by omega) (by omega) (by omega)] + rfl + +section Preadditive + +variable [Preadditive C] [∀ (n : ℤ), (shiftFunctor C n).Additive] + +@[simp] +lemma opEquiv_symm_add {n : ℤ} (x y : ShiftedHom (Opposite.op Y) (Opposite.op X) n) : + (opEquiv n).symm (x + y) = (opEquiv n).symm x + (opEquiv n).symm y := by + dsimp [opEquiv_symm_apply] + rw [← Preadditive.comp_add, ← Functor.map_add] + rfl + +@[simp] +lemma opEquiv'_symm_add {n a : ℤ} (x y : (Opposite.op (Y⟦a⟧) ⟶ (Opposite.op X)⟦n⟧)) + (a' : ℤ) (h : n + a = a') : + (opEquiv' n a a' h).symm (x + y) = + (opEquiv' n a a' h).symm x + (opEquiv' n a a' h).symm y := by + dsimp [opEquiv'] + erw [opEquiv_symm_add, Iso.homToEquiv_apply, Iso.homToEquiv_apply, Iso.homToEquiv_apply] + rw [Preadditive.add_comp] + rfl + +end Preadditive + +end ShiftedHom + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Shift/SingleFunctors.lean b/Mathlib/CategoryTheory/Shift/SingleFunctors.lean index 9b845c8a62a64..115e77228da25 100644 --- a/Mathlib/CategoryTheory/Shift/SingleFunctors.lean +++ b/Mathlib/CategoryTheory/Shift/SingleFunctors.lean @@ -118,7 +118,7 @@ attribute [local simp] comm comm_assoc /-- The identity morphism in `SingleFunctors C D A`. -/ @[simps] def id : Hom F F where - hom a := 𝟙 _ + hom _ := 𝟙 _ variable {F G H} @@ -168,7 +168,7 @@ variable (C D) @[simps] def evaluation (a : A) : SingleFunctors C D A ⥤ C ⥤ D where obj F := F.functor a - map {F G} φ := φ.hom a + map {_ _} φ := φ.hom a variable {C D} @@ -237,7 +237,7 @@ variable {C E' A} @[simps!] def postcompPostcompIso (G : D ⥤ E) (G' : E ⥤ E') [G.CommShift A] [G'.CommShift A] : (F.postcomp G).postcomp G' ≅ F.postcomp (G ⋙ G') := - isoMk (fun a => Functor.associator _ _ _) (fun n a a' ha' => by + isoMk (fun _ => Functor.associator _ _ _) (fun n a a' ha' => by ext X simp [Functor.commShiftIso_comp_inv_app]) diff --git a/Mathlib/CategoryTheory/Sigma/Basic.lean b/Mathlib/CategoryTheory/Sigma/Basic.lean index 6e1f7a6bfe594..d7550a04b3288 100644 --- a/Mathlib/CategoryTheory/Sigma/Basic.lean +++ b/Mathlib/CategoryTheory/Sigma/Basic.lean @@ -136,7 +136,7 @@ lemma desc_map_mk {i : I} (X Y : C i) (f : X ⟶ Y) : (desc F).map (SigmaHom.mk `F i`. -/ def inclDesc (i : I) : incl i ⋙ desc F ≅ F i := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ @[simp] lemma inclDesc_hom_app (i : I) (X : C i) : (inclDesc F i).hom.app X = 𝟙 ((F i).obj X) := @@ -202,7 +202,7 @@ variable (I) /-- The functor `Sigma.map` applied to the identity function is just the identity functor. -/ @[simps!] def mapId : map C (id : I → I) ≅ 𝟭 (Σi, C i) := - natIso fun i => NatIso.ofComponents fun X => Iso.refl _ + natIso fun i => NatIso.ofComponents fun _ => Iso.refl _ variable {I} {K : Type w₃} diff --git a/Mathlib/CategoryTheory/Sites/Canonical.lean b/Mathlib/CategoryTheory/Sites/Canonical.lean index ec5fdd447f5e9..a31fc323954e7 100644 --- a/Mathlib/CategoryTheory/Sites/Canonical.lean +++ b/Mathlib/CategoryTheory/Sites/Canonical.lean @@ -43,9 +43,7 @@ variable {C : Type u} [Category.{v} C] namespace Sheaf -variable {P : Cᵒᵖ ⥤ Type v} -variable {X Y : C} {S : Sieve X} {R : Presieve X} -variable (J J₂ : GrothendieckTopology C) +variable {P : Cᵒᵖ ⥤ Type v} {X : C} (J : GrothendieckTopology C) /-- To show `P` is a sheaf for the binding of `U` with `B`, it suffices to show that `P` is a sheaf for diff --git a/Mathlib/CategoryTheory/Sites/Closed.lean b/Mathlib/CategoryTheory/Sites/Closed.lean index fb3b323b44de0..49c58c3039641 100644 --- a/Mathlib/CategoryTheory/Sites/Closed.lean +++ b/Mathlib/CategoryTheory/Sites/Closed.lean @@ -269,7 +269,7 @@ def topologyOfClosureOperator (c : ∀ X : C, ClosureOperator (Sieve X)) The topology given by the closure operator `J.close` on a Grothendieck topology is the same as `J`. -/ theorem topologyOfClosureOperator_self : - (topologyOfClosureOperator J₁.closureOperator fun X Y => J₁.pullback_close) = J₁ := by + (topologyOfClosureOperator J₁.closureOperator fun _ _ => J₁.pullback_close) = J₁ := by ext X S apply GrothendieckTopology.close_eq_top_iff_mem diff --git a/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean b/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean index 8d46116dc8326..fa351aa7cb982 100644 --- a/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean +++ b/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean @@ -573,8 +573,8 @@ noncomputable def plusPlusAdjunction : plusPlusSheaf J D ⊣ sheafToPresheaf J D { homEquiv := fun P Q => { toFun := fun e => J.toSheafify P ≫ e.val invFun := fun e => ⟨J.sheafifyLift e Q.2⟩ - left_inv := fun e => Sheaf.Hom.ext <| (J.sheafifyLift_unique _ _ _ rfl).symm - right_inv := fun e => J.toSheafify_sheafifyLift _ _ } + left_inv := fun _ => Sheaf.Hom.ext <| (J.sheafifyLift_unique _ _ _ rfl).symm + right_inv := fun _ => J.toSheafify_sheafifyLift _ _ } homEquiv_naturality_left_symm := by intro P Q R η γ; ext1; dsimp; symm apply J.sheafifyMap_sheafifyLift diff --git a/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean b/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean index 46db78d658c1f..a300122560b4c 100644 --- a/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean +++ b/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean @@ -27,11 +27,6 @@ under equivalence of sheaf categories. * `Sheaf.isConstant_iff_forget` : Given a "forgetful" functor `U : D ⥤ B` a sheaf `F : Sheaf J D` is constant if and only if the sheaf given by postcomposition with `U` is constant. - -## Future work - -* (Dagur) Use `Sheaf.isConstant_iff_forget` to prove that a condensed module is discrete if and -only if its underlying condensed set is discrete. -/ namespace CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Coverage.lean b/Mathlib/CategoryTheory/Sites/Coverage.lean index 648975e7b07ec..666be866cab49 100644 --- a/Mathlib/CategoryTheory/Sites/Coverage.lean +++ b/Mathlib/CategoryTheory/Sites/Coverage.lean @@ -236,13 +236,13 @@ def toGrothendieck (K : Coverage C) : GrothendieckTopology C where intro Z g hg rw [← Sieve.pullback_comp] exact hS hg - transitive' X S hS R hR := .transitive _ _ _ hS hR + transitive' _ _ hS _ hR := .transitive _ _ _ hS hR instance : PartialOrder (Coverage C) where le A B := A.covering ≤ B.covering - le_refl A X := le_refl _ - le_trans A B C h1 h2 X := le_trans (h1 X) (h2 X) - le_antisymm A B h1 h2 := Coverage.ext <| funext <| + le_refl _ _ := le_refl _ + le_trans _ _ _ h1 h2 X := le_trans (h1 X) (h2 X) + le_antisymm _ _ h1 h2 := Coverage.ext <| funext <| fun X => le_antisymm (h1 X) (h2 X) variable (C) in diff --git a/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean b/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean index 3a67742995d2b..f0f3a969c4866 100644 --- a/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean +++ b/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean @@ -102,13 +102,13 @@ def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X) Cocone (Sieve.generateSingleton f).arrows.diagram := { pt := W ι := { - app := fun ⟨T,hT⟩ => hT.choose ≫ e + app := fun ⟨_,hT⟩ => hT.choose ≫ e naturality := by rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B) dsimp; simp only [← Category.assoc, Category.comp_id] apply h rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } } - { desc := fun {W} e h => Hf.desc (aux e h) + { desc := fun {_} e h => Hf.desc (aux e h) fac := by intro W e h dsimp @@ -214,14 +214,14 @@ def effectiveEpiFamilyStructOfIsColimit {B : C} {α : Type*} Cocone (Sieve.generateFamily X π).arrows.diagram := { pt := W ι := { - app := fun ⟨T,hT⟩ => hT.choose_spec.choose ≫ e hT.choose + app := fun ⟨_,hT⟩ => hT.choose_spec.choose ≫ e hT.choose naturality := by intro ⟨A,a,(g₁ : A.left ⟶ _),ha⟩ ⟨B,b,(g₂ : B.left ⟶ _),hb⟩ (q : A ⟶ B) dsimp; rw [Category.comp_id, ← Category.assoc] apply h; rw [Category.assoc] generalize_proofs h1 h2 h3 h4 rw [h2.choose_spec, h4.choose_spec, Over.w] } } - { desc := fun {W} e h => H.desc (aux e h) + { desc := fun {_} e h => H.desc (aux e h) fac := by intro W e h a dsimp diff --git a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean index 44e39a7bba0c9..c2a70eaeecba1 100644 --- a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean +++ b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean @@ -66,7 +66,7 @@ variable (P R) /-- Show that `FirstObj` is isomorphic to `FamilyOfElements`. -/ @[simps] def firstObjEqFamily : FirstObj P R ≅ R.FamilyOfElements P where - hom t Y f hf := Pi.π (fun f : ΣY, { f : Y ⟶ X // R f } => P.obj (op f.1)) ⟨_, _, hf⟩ t + hom t _ _ hf := Pi.π (fun f : ΣY, { f : Y ⟶ X // R f } => P.obj (op f.1)) ⟨_, _, hf⟩ t inv := Pi.lift fun f x => x _ f.2.2 instance : Inhabited (FirstObj P (⊥ : Presieve X)) := diff --git a/Mathlib/CategoryTheory/Sites/Equivalence.lean b/Mathlib/CategoryTheory/Sites/Equivalence.lean index 2408d76270ca3..de7ec32fc5e16 100644 --- a/Mathlib/CategoryTheory/Sites/Equivalence.lean +++ b/Mathlib/CategoryTheory/Sites/Equivalence.lean @@ -167,9 +167,6 @@ theorem hasSheafCompose : J.HasSheafCompose F where e.functor.op_comp_isSheaf _ _ ⟨_, hP'⟩ exact (Presheaf.isSheaf_of_iso_iff ((isoWhiskerRight e.op.unitIso.symm (P ⋙ F)))).mp hP' -variable [ConcreteCategory.{w} A] -variable {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) - end Equivalence variable (B : Type u₄) [Category.{v₄} B] (F : A ⥤ B) diff --git a/Mathlib/CategoryTheory/Sites/Grothendieck.lean b/Mathlib/CategoryTheory/Sites/Grothendieck.lean index 0d3552925cc54..c29e44a6f4bf3 100644 --- a/Mathlib/CategoryTheory/Sites/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Sites/Grothendieck.lean @@ -207,8 +207,8 @@ See [MM92] Chapter III, Section 2, example (a), or https://en.wikipedia.org/wiki/Grothendieck_topology#The_discrete_and_indiscrete_topologies -/ def trivial : GrothendieckTopology C where - sieves X := {⊤} - top_mem' X := rfl + sieves _ := {⊤} + top_mem' _ := rfl pullback_stable' X Y S f hf := by rw [Set.mem_singleton_iff] at hf ⊢ simp [hf] @@ -221,7 +221,7 @@ def trivial : GrothendieckTopology C where See https://en.wikipedia.org/wiki/Grothendieck_topology#The_discrete_and_indiscrete_topologies. -/ def discrete : GrothendieckTopology C where - sieves X := Set.univ + sieves _ := Set.univ top_mem' := by simp pullback_stable' X Y f := by simp transitive' := by simp @@ -241,9 +241,9 @@ theorem le_def {J₁ J₂ : GrothendieckTopology C} : J₁ ≤ J₂ ↔ (J₁ : /-- See -/ instance : PartialOrder (GrothendieckTopology C) := { instLEGrothendieckTopology with - le_refl := fun J₁ => le_def.mpr le_rfl - le_trans := fun J₁ J₂ J₃ h₁₂ h₂₃ => le_def.mpr (le_trans h₁₂ h₂₃) - le_antisymm := fun J₁ J₂ h₁₂ h₂₁ => GrothendieckTopology.ext (le_antisymm h₁₂ h₂₁) } + le_refl := fun _ => le_def.mpr le_rfl + le_trans := fun _ _ _ h₁₂ h₂₃ => le_def.mpr (le_trans h₁₂ h₂₃) + le_antisymm := fun _ _ h₁₂ h₂₁ => GrothendieckTopology.ext (le_antisymm h₁₂ h₂₁) } /-- See -/ instance : InfSet (GrothendieckTopology C) where @@ -260,6 +260,11 @@ instance : InfSet (GrothendieckTopology C) where apply J.transitive (hS _ ⟨⟨_, _, hJ, rfl⟩, rfl⟩) _ fun Y f hf => h hf _ ⟨⟨_, _, hJ, rfl⟩, rfl⟩ } +lemma mem_sInf (s : Set (GrothendieckTopology C)) {X : C} (S : Sieve X) : + S ∈ sInf s X ↔ ∀ t ∈ s, S ∈ t X := by + show S ∈ sInf (sieves '' s) X ↔ _ + simp + /-- See -/ theorem isGLB_sInf (s : Set (GrothendieckTopology C)) : IsGLB s (sInf s) := by refine @IsGLB.of_image _ _ _ _ sieves ?_ _ _ ?_ @@ -323,7 +328,7 @@ See https://ncatlab.org/nlab/show/dense+topology, or [MM92] Chapter III, Section -/ def dense : GrothendieckTopology C where sieves X S := ∀ {Y : C} (f : Y ⟶ X), ∃ (Z : _) (g : Z ⟶ Y), S (g ≫ f) - top_mem' X Y f := ⟨Y, 𝟙 Y, ⟨⟩⟩ + top_mem' _ Y _ := ⟨Y, 𝟙 Y, ⟨⟩⟩ pullback_stable' := by intro X Y S h H Z f rcases H (f ≫ h) with ⟨W, g, H'⟩ @@ -355,7 +360,7 @@ See https://ncatlab.org/nlab/show/atomic+site, or [MM92] Chapter III, Section 2, -/ def atomic (hro : RightOreCondition C) : GrothendieckTopology C where sieves X S := ∃ (Y : _) (f : Y ⟶ X), S f - top_mem' X := ⟨_, 𝟙 _, ⟨⟩⟩ + top_mem' _ := ⟨_, 𝟙 _, ⟨⟩⟩ pullback_stable' := by rintro X Y S h ⟨Z, f, hf⟩ rcases hro h f with ⟨W, g, k, comm⟩ @@ -394,15 +399,15 @@ theorem ext (S T : J.Cover X) (h : ∀ ⦃Y⦄ (f : Y ⟶ X), S f ↔ T f) : S = instance : OrderTop (J.Cover X) := { (inferInstance : Preorder (J.Cover X)) with top := ⟨⊤, J.top_mem _⟩ - le_top := fun S Y f _ => by tauto } + le_top := fun _ _ _ _ => by tauto } instance : SemilatticeInf (J.Cover X) := { (inferInstance : Preorder _) with inf := fun S T => ⟨S ⊓ T, J.intersection_covering S.condition T.condition⟩ - le_antisymm := fun S T h1 h2 => ext _ _ fun {Y} f => ⟨by apply h1, by apply h2⟩ - inf_le_left := fun S T Y f hf => hf.1 - inf_le_right := fun S T Y f hf => hf.2 - le_inf := fun S T W h1 h2 Y f h => ⟨h1 _ h, h2 _ h⟩ } + le_antisymm := fun _ _ h1 h2 => ext _ _ fun {Y} f => ⟨by apply h1, by apply h2⟩ + inf_le_left := fun _ _ _ _ hf => hf.1 + inf_le_right := fun _ _ _ _ hf => hf.2 + le_inf := fun _ _ _ h1 h2 _ _ h => ⟨h1 _ h, h2 _ h⟩ } instance : Inhabited (J.Cover X) := ⟨⊤⟩ diff --git a/Mathlib/CategoryTheory/Sites/InducedTopology.lean b/Mathlib/CategoryTheory/Sites/InducedTopology.lean index 718bea16efa74..c5be7f7e1ffda 100644 --- a/Mathlib/CategoryTheory/Sites/InducedTopology.lean +++ b/Mathlib/CategoryTheory/Sites/InducedTopology.lean @@ -66,7 +66,7 @@ then the set `{ T ∩ mor(C) | T ∈ K }` is a grothendieck topology of `C`. -/ @[simps] def inducedTopology : GrothendieckTopology C where - sieves X S := K _ (S.functorPushforward G) + sieves _ S := K _ (S.functorPushforward G) top_mem' X := by change K _ _ rw [Sieve.functorPushforward_top] diff --git a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean index 136e553138ef3..5e870d3f0cab6 100644 --- a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean +++ b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean @@ -440,7 +440,7 @@ def natTransEquivCompatibleFamily {P : Cᵒᵖ ⥤ Type v₁} : rw [← FunctorToTypes.naturality _ _ α g.op] rfl invFun t := - { app := fun Y f => t.1 _ f.2 + { app := fun _ f => t.1 _ f.2 naturality := fun Y Z g => by ext ⟨f, hf⟩ apply t.2.to_sieveCompatible _ } @@ -656,7 +656,7 @@ theorem isSheafFor_subsieve (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve (h : (S : Presieve X) ≤ R) (trans : ∀ ⦃Y⦄ (f : Y ⟶ X), IsSheafFor P (S.pullback f : Presieve Y)) : IsSheafFor P R := - isSheafFor_subsieve_aux P h (by simpa using trans (𝟙 _)) fun Y f _ => (trans f).isSeparatedFor + isSheafFor_subsieve_aux P h (by simpa using trans (𝟙 _)) fun _ f _ => (trans f).isSeparatedFor section Arrows diff --git a/Mathlib/CategoryTheory/Sites/Limits.lean b/Mathlib/CategoryTheory/Sites/Limits.lean index 1c38d0e033185..5e19d921a4291 100644 --- a/Mathlib/CategoryTheory/Sites/Limits.lean +++ b/Mathlib/CategoryTheory/Sites/Limits.lean @@ -138,7 +138,7 @@ theorem isSheaf_of_isLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPreshea instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) := createsLimitOfReflectsIso fun E hE => { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩, - ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext <| E.π.naturality _⟩⟩ + ⟨fun _ => ⟨E.π.app _⟩, fun _ _ _ => Sheaf.Hom.ext <| E.π.naturality _⟩⟩ validLift := Cones.ext (eqToIso rfl) fun j => by dsimp simp diff --git a/Mathlib/CategoryTheory/Sites/LocallyFullyFaithful.lean b/Mathlib/CategoryTheory/Sites/LocallyFullyFaithful.lean index 780045646d719..96bf30d33b13f 100644 --- a/Mathlib/CategoryTheory/Sites/LocallyFullyFaithful.lean +++ b/Mathlib/CategoryTheory/Sites/LocallyFullyFaithful.lean @@ -41,7 +41,7 @@ This is the image sieve of `f` under `yonedaMap G V` and hence the name. See `Functor.imageSieve_eq_imageSieve`. -/ def Functor.imageSieve {U V : C} (f : G.obj U ⟶ G.obj V) : Sieve U where - arrows Y i := ∃ l, G.map l = G.map i ≫ f + arrows _ i := ∃ l, G.map l = G.map i ≫ f downward_closed := by rintro Y₁ Y₂ i₁ ⟨l, hl⟩ i₂ exact ⟨i₂ ≫ l, by simp [hl]⟩ @@ -55,7 +55,7 @@ For two arrows `f₁ f₂ : U ⟶ V`, the arrows `i` such that `i ≫ f₁ = i -/ @[simps] def Sieve.equalizer {U V : C} (f₁ f₂ : U ⟶ V) : Sieve U where - arrows Y i := i ≫ f₁ = i ≫ f₂ + arrows _ i := i ≫ f₁ = i ≫ f₂ downward_closed := by aesop @[simp] diff --git a/Mathlib/CategoryTheory/Sites/LocallySurjective.lean b/Mathlib/CategoryTheory/Sites/LocallySurjective.lean index 06a7da7304b54..289d2db4e05a6 100644 --- a/Mathlib/CategoryTheory/Sites/LocallySurjective.lean +++ b/Mathlib/CategoryTheory/Sites/LocallySurjective.lean @@ -93,7 +93,7 @@ instance {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsLocallySurjective J f] : theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) : IsLocallySurjective J f ↔ (imagePresheaf (whiskerRight f (forget A))).sheafify J = ⊤ := by - simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj, + simp only [Subpresheaf.ext_iff, funext_iff, Set.ext_iff, top_subpresheaf_obj, Set.top_eq_univ, Set.mem_univ, iff_true] exact ⟨fun H _ => H.imageSieve_mem, fun H => ⟨H _⟩⟩ diff --git a/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean b/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean index c36e6664261b4..2d994cb919f36 100644 --- a/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean +++ b/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean @@ -3,10 +3,15 @@ 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.Category.Grp.Abelian import Mathlib.Algebra.Category.Grp.Adjunctions -import Mathlib.CategoryTheory.Sites.Adjunction +import Mathlib.Algebra.Homology.ShortComplex.ShortExact +import Mathlib.Algebra.Homology.Square +import Mathlib.CategoryTheory.Limits.FunctorCategory.EpiMono import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Square import Mathlib.CategoryTheory.Limits.Shapes.Types +import Mathlib.CategoryTheory.Sites.Abelian +import Mathlib.CategoryTheory.Sites.Adjunction import Mathlib.CategoryTheory.Sites.Sheafification /-! @@ -52,10 +57,10 @@ namespace CategoryTheory open Limits Opposite variable {C : Type u} [Category.{v} C] - {J : GrothendieckTopology C} [HasWeakSheafify J (Type v)] + {J : GrothendieckTopology C} -@[simp] lemma Sheaf.isPullback_square_op_map_yoneda_presheafToSheaf_yoneda_iff + [HasWeakSheafify J (Type v)] (F : Sheaf J (Type v)) (sq : Square C) : (sq.op.map ((yoneda ⋙ presheafToSheaf J _).op ⋙ yoneda.obj F)).IsPullback ↔ (sq.op.map F.val).IsPullback := by @@ -79,17 +84,23 @@ variable (J) topology consists of a commutative square `f₁₂ ≫ f₂₄ = f₁₃ ≫ f₃₄` in `C` such that `f₁₃` is a monomorphism and that the square becomes a pushout square in the category of sheaves of sets. -/ -structure MayerVietorisSquare extends Square C where +structure MayerVietorisSquare [HasWeakSheafify J (Type v)] extends Square C where mono_f₁₃ : Mono toSquare.f₁₃ := by infer_instance /-- the square becomes a pushout square in the category of sheaves of types -/ isPushout : (toSquare.map (yoneda ⋙ presheafToSheaf J _)).IsPushout namespace MayerVietorisSquare +attribute [instance] mono_f₁₃ + variable {J} +section + +variable [HasWeakSheafify J (Type v)] + /-- Constructor for Mayer-Vietoris squares taking as an input -a square `sq` such that `sq.f₂₄` is a mono and that for every +a square `sq` such that `sq.f₁₃` is a mono and that for every sheaf of types `F`, the square `sq.op.map F.val` is a pullback square. -/ @[simps toSquare] noncomputable def mk' (sq : Square C) [Mono sq.f₁₃] @@ -206,6 +217,50 @@ lemma sheafCondition_of_sheaf {A : Type u'} [Category.{v} A] (S.isPushout.op.map (yoneda.obj ⟨_, (isSheaf_iff_isSheaf_of_type _ _).2 (F.cond X.unop)⟩)) +end + +variable [HasWeakSheafify J (Type v)] [HasSheafify J AddCommGrp.{v}] + (S : J.MayerVietorisSquare) + +/-- The short complex of abelian sheaves +`ℤ[S.X₁] ⟶ ℤ[S.X₂] ⊞ ℤ[S.X₃] ⟶ ℤ[S.X₄]` +where the left map is a difference and the right map a sum. -/ +@[simps] +noncomputable def shortComplex : + ShortComplex (Sheaf J AddCommGrp.{v}) where + X₁ := (presheafToSheaf J _).obj (yoneda.obj S.X₁ ⋙ AddCommGrp.free) + X₂ := (presheafToSheaf J _).obj (yoneda.obj S.X₂ ⋙ AddCommGrp.free) ⊞ + (presheafToSheaf J _).obj (yoneda.obj S.X₃ ⋙ AddCommGrp.free) + X₃ := (presheafToSheaf J _).obj (yoneda.obj S.X₄ ⋙ AddCommGrp.free) + f := + biprod.lift + ((presheafToSheaf J _).map (whiskerRight (yoneda.map S.f₁₂) _)) + (-(presheafToSheaf J _).map (whiskerRight (yoneda.map S.f₁₃) _)) + g := + biprod.desc + ((presheafToSheaf J _).map (whiskerRight (yoneda.map S.f₂₄) _)) + ((presheafToSheaf J _).map (whiskerRight (yoneda.map S.f₃₄) _)) + zero := (S.map (yoneda ⋙ (whiskeringRight _ _ _).obj AddCommGrp.free ⋙ + presheafToSheaf J _)).cokernelCofork.condition + +instance : Mono S.shortComplex.f := by + have : Mono (S.shortComplex.f ≫ biprod.snd) := by + dsimp + simp only [biprod.lift_snd] + infer_instance + exact mono_of_mono _ biprod.snd + +instance : Epi S.shortComplex.g := + (S.shortComplex.exact_and_epi_g_iff_g_is_cokernel.2 + ⟨S.isPushoutAddCommGrpFreeSheaf.isColimitCokernelCofork⟩).2 + +lemma shortComplex_exact : S.shortComplex.Exact := + ShortComplex.exact_of_g_is_cokernel _ + S.isPushoutAddCommGrpFreeSheaf.isColimitCokernelCofork + +lemma shortComplex_shortExact : S.shortComplex.ShortExact where + exact := S.shortComplex_exact + end MayerVietorisSquare end GrothendieckTopology diff --git a/Mathlib/CategoryTheory/Sites/MorphismProperty.lean b/Mathlib/CategoryTheory/Sites/MorphismProperty.lean new file mode 100644 index 0000000000000..d840eb5deaf0f --- /dev/null +++ b/Mathlib/CategoryTheory/Sites/MorphismProperty.lean @@ -0,0 +1,66 @@ +/- +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.CategoryTheory.MorphismProperty.Limits +import Mathlib.CategoryTheory.Sites.Pretopology + +/-! +# The site induced by a morphism property + +Let `C` be a category with pullbacks and `P` be a multiplicative morphism property which is +stable under base change. Then `P` induces a pretopology, where coverings are given by presieves +whose elements satisfy `P`. + +Standard examples of pretopologies in algebraic geometry, such as the étale site, are obtained from +this construction by intersecting with the pretopology of surjective families. + +-/ + +namespace CategoryTheory + +open Limits + +variable {C : Type*} [Category C] [HasPullbacks C] + +namespace MorphismProperty + +/-- If `P` is a multiplicative morphism property which is stable under base change on a category +`C` with pullbacks, then `P` induces a pretopology, where coverings are given by presieves whose +elements satisfy `P`. -/ +def pretopology (P : MorphismProperty C) [P.IsMultiplicative] (hPb : P.StableUnderBaseChange) : + Pretopology C where + coverings X S := ∀ {Y : C} {f : Y ⟶ X}, S f → P f + has_isos X Y f h Z g hg := by + cases hg + haveI : P.RespectsIso := hPb.respectsIso + exact P.of_isIso f + pullbacks X Y f S hS Z g hg := by + obtain ⟨Z, g, hg⟩ := hg + apply hPb.snd g f (hS hg) + transitive X S Ti hS hTi Y f hf := by + obtain ⟨Z, g, h, H, H', rfl⟩ := hf + exact comp_mem _ _ _ (hTi h H H') (hS H) + +/-- To a morphism property `P` satisfying the conditions of `MorphismProperty.pretopology`, we +associate the Grothendieck topology generated by `P.pretopology`. -/ +abbrev grothendieckTopology (P : MorphismProperty C) [P.IsMultiplicative] + (hPb : P.StableUnderBaseChange) : GrothendieckTopology C := + (P.pretopology hPb).toGrothendieck + +variable {P Q : MorphismProperty C} + [P.IsMultiplicative] (hPb : P.StableUnderBaseChange) + [Q.IsMultiplicative] (hQb : Q.StableUnderBaseChange) + +lemma pretopology_le (hPQ : P ≤ Q) : P.pretopology hPb ≤ Q.pretopology hQb := + fun _ _ hS _ f hf ↦ hPQ f (hS hf) + +variable (P Q) in +lemma pretopology_inf : + (P ⊓ Q).pretopology (hPb.inf hQb) = P.pretopology hPb ⊓ Q.pretopology hQb := by + ext X S + exact ⟨fun hS ↦ ⟨fun hf ↦ (hS hf).left, fun hf ↦ (hS hf).right⟩, + fun h ↦ fun hf ↦ ⟨h.left hf, h.right hf⟩⟩ + +end CategoryTheory.MorphismProperty diff --git a/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean b/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean index 2f3b34ebb98a9..44a948a9222b1 100644 --- a/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean +++ b/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean @@ -99,14 +99,14 @@ lemma one_ev (i j : I) {T : C} (a : T ⟶ U i) (b : T ⟶ U j) : variable {G U} instance : Mul (OneCochain G U) where - mul γ₁ γ₂ := { ev := fun i j T a b ↦ γ₁.ev i j a b * γ₂.ev i j a b } + mul γ₁ γ₂ := { ev := fun i j _ a b ↦ γ₁.ev i j a b * γ₂.ev i j a b } @[simp] lemma mul_ev (γ₁ γ₂ : OneCochain G U) (i j : I) {T : C} (a : T ⟶ U i) (b : T ⟶ U j) : (γ₁ * γ₂).ev i j a b = γ₁.ev i j a b * γ₂.ev i j a b := rfl instance : Inv (OneCochain G U) where - inv γ := { ev := fun i j T a b ↦ (γ.ev i j a b) ⁻¹} + inv γ := { ev := fun i j _ a b ↦ (γ.ev i j a b) ⁻¹} @[simp] lemma inv_ev (γ : OneCochain G U) (i j : I) {T : C} (a : T ⟶ U i) (b : T ⟶ U j) : diff --git a/Mathlib/CategoryTheory/Sites/Over.lean b/Mathlib/CategoryTheory/Sites/Over.lean index e374b3c585bdf..f012575ed625c 100644 --- a/Mathlib/CategoryTheory/Sites/Over.lean +++ b/Mathlib/CategoryTheory/Sites/Over.lean @@ -139,7 +139,7 @@ lemma over_forget_coverPreserving (X : C) : lemma over_forget_compatiblePreserving (X : C) : CompatiblePreserving J (Over.forget X) where - compatible {F Z T x hx Y₁ Y₂ W f₁ f₂ g₁ g₂ hg₁ hg₂ h} := by + compatible {_ Z _ _ hx Y₁ Y₂ W f₁ f₂ g₁ g₂ hg₁ hg₂ h} := by let W' : Over X := Over.mk (f₁ ≫ Y₁.hom) let g₁' : W' ⟶ Y₁ := Over.homMk f₁ let g₂' : W' ⟶ Y₂ := Over.homMk f₂ (by simpa using h.symm =≫ Z.hom) @@ -168,7 +168,7 @@ lemma over_map_coverPreserving {X Y : C} (f : X ⟶ Y) : lemma over_map_compatiblePreserving {X Y : C} (f : X ⟶ Y) : CompatiblePreserving (J.over Y) (Over.map f) where - compatible {F Z T x hx Y₁ Y₂ W f₁ f₂ g₁ g₂ hg₁ hg₂ h} := by + compatible {F Z _ x hx Y₁ Y₂ W f₁ f₂ g₁ g₂ hg₁ hg₂ h} := by let W' : Over X := Over.mk (f₁.left ≫ Y₁.hom) let g₁' : W' ⟶ Y₁ := Over.homMk f₁.left let g₂' : W' ⟶ Y₂ := Over.homMk f₂.left diff --git a/Mathlib/CategoryTheory/Sites/Plus.lean b/Mathlib/CategoryTheory/Sites/Plus.lean index 9fe18afba43ba..f4a6a9467b839 100644 --- a/Mathlib/CategoryTheory/Sites/Plus.lean +++ b/Mathlib/CategoryTheory/Sites/Plus.lean @@ -39,7 +39,7 @@ variable (P : Cᵒᵖ ⥤ D) @[simps] def diagram (X : C) : (J.Cover X)ᵒᵖ ⥤ D where obj S := multiequalizer (S.unop.index P) - map {S T} f := + map {S _} f := Multiequalizer.lift _ _ (fun I => Multiequalizer.ι (S.unop.index P) (I.map f.unop)) (fun I => Multiequalizer.condition (S.unop.index P) (Cover.Relation.mk' (I.r.map f.unop))) @@ -56,7 +56,7 @@ between diagrams whose colimits define the values of `plus`. -/ @[simps] def diagramNatTrans {P Q : Cᵒᵖ ⥤ D} (η : P ⟶ Q) (X : C) : J.diagram P X ⟶ J.diagram Q X where app W := - Multiequalizer.lift _ _ (fun i => Multiequalizer.ι _ _ ≫ η.app _) (fun i => by + Multiequalizer.lift _ _ (fun _ => Multiequalizer.ι _ _ ≫ η.app _) (fun i => by dsimp only erw [Category.assoc, Category.assoc, ← η.naturality, ← η.naturality, Multiequalizer.condition_assoc] diff --git a/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean b/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean index ee99ef8e05d4a..010ddc167e260 100644 --- a/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean +++ b/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean @@ -8,7 +8,7 @@ import Mathlib.CategoryTheory.Sites.CompatibleSheafification import Mathlib.CategoryTheory.Sites.Whiskering import Mathlib.CategoryTheory.Sites.Sheafification -/-! # Functors which preserves sheafification +/-! # Functors which preserve sheafification In this file, given a Grothendieck topology `J` on `C` and `F : A ⥤ B`, we define a type class `J.PreservesSheafification F`. We say that `F` preserves @@ -20,7 +20,7 @@ this property for the map from any presheaf `P` to its associated sheaf, see In general, we define `Sheaf.composeAndSheafify J F : Sheaf J A ⥤ Sheaf J B` as the functor which sends a sheaf `G` to the sheafification of the composition `G.val ⋙ F`. -It `J.PreservesSheafification F`, we show that this functor can also be thought +If `J.PreservesSheafification F`, we show that this functor can also be thought of as the localization of the functor `_ ⋙ F` on presheaves: we construct an isomorphism `presheafToSheafCompComposeAndSheafifyIso` between `presheafToSheaf J A ⋙ Sheaf.composeAndSheafify J F` and @@ -29,7 +29,7 @@ as the localization of the functor `_ ⋙ F` on presheaves: we construct an isom Moreover, if we assume `J.HasSheafCompose F`, we obtain an isomorphism `sheafifyComposeIso J F P : sheafify J (P ⋙ F) ≅ sheafify J P ⋙ F`. -We show that under suitable assumptions, the forget functor from a concrete +We show that under suitable assumptions, the forgetful functor from a concrete category preserves sheafification; this holds more generally for functors between such concrete categories which commute both with suitable limits and colimits. @@ -170,7 +170,8 @@ lemma sheafComposeNatTrans_fac (P : Cᵒᵖ ⥤ A) : adj₂.unit.app (P ⋙ F) ≫ (sheafToPresheaf J B).map ((sheafComposeNatTrans J F adj₁ adj₂).app P) = whiskerRight (adj₁.unit.app P) F := by - simp [sheafComposeNatTrans, -sheafToPresheaf_obj, -sheafToPresheaf_map] + simp [sheafComposeNatTrans, -sheafToPresheaf_obj, -sheafToPresheaf_map, + Adjunction.homEquiv_counit] lemma sheafComposeNatTrans_app_uniq (P : Cᵒᵖ ⥤ A) (α : G₂.obj (P ⋙ F) ⟶ (sheafCompose J F).obj (G₁.obj P)) @@ -264,9 +265,8 @@ lemma sheafToPresheaf_map_sheafComposeNatTrans_eq_sheafifyCompIso_inv (P : Cᵒ rfl apply ((plusPlusAdjunction J E).homEquiv _ _).injective convert sheafComposeNatTrans_fac J F (plusPlusAdjunction J D) (plusPlusAdjunction J E) P - all_goals - dsimp [plusPlusAdjunction] - simp + dsimp [plusPlusAdjunction] + simp instance (P : Cᵒᵖ ⥤ D) : IsIso ((sheafComposeNatTrans J F (plusPlusAdjunction J D) (plusPlusAdjunction J E)).app P) := by diff --git a/Mathlib/CategoryTheory/Sites/Pretopology.lean b/Mathlib/CategoryTheory/Sites/Pretopology.lean index 8163bb4bac21b..972ef7c94b08d 100644 --- a/Mathlib/CategoryTheory/Sites/Pretopology.lean +++ b/Mathlib/CategoryTheory/Sites/Pretopology.lean @@ -83,11 +83,11 @@ variable (C) instance : PartialOrder (Pretopology C) := { Pretopology.LE with - le_refl := fun K => le_def.mpr le_rfl - le_trans := fun K₁ K₂ K₃ h₁₂ h₂₃ => le_def.mpr (le_trans h₁₂ h₂₃) - le_antisymm := fun K₁ K₂ h₁₂ h₂₁ => Pretopology.ext (le_antisymm h₁₂ h₂₁) } + le_refl := fun _ => le_def.mpr le_rfl + le_trans := fun _ _ _ h₁₂ h₂₃ => le_def.mpr (le_trans h₁₂ h₂₃) + le_antisymm := fun _ _ h₁₂ h₂₁ => Pretopology.ext (le_antisymm h₁₂ h₂₁) } -instance : OrderTop (Pretopology C) where +instance orderTop : OrderTop (Pretopology C) where top := { coverings := fun _ => Set.univ has_isos := fun _ _ _ _ => Set.mem_univ _ @@ -105,7 +105,7 @@ See , or [MM92] Chapter III, Section -/ def toGrothendieck (K : Pretopology C) : GrothendieckTopology C where sieves X S := ∃ R ∈ K X, R ≤ (S : Presieve _) - top_mem' X := ⟨Presieve.singleton (𝟙 _), K.has_isos _, fun _ _ _ => ⟨⟩⟩ + top_mem' _ := ⟨Presieve.singleton (𝟙 _), K.has_isos _, fun _ _ _ => ⟨⟩⟩ pullback_stable' X Y S g := by rintro ⟨R, hR, RS⟩ refine ⟨_, K.pullbacks g _ hR, ?_⟩ @@ -152,10 +152,14 @@ def gi : GaloisInsertion (toGrothendieck C) (ofGrothendieck C) where · rintro h X S ⟨R, hR, RS⟩ apply J.superset_covering _ (h _ hR) rwa [Sieve.giGenerate.gc] - le_l_u J X S hS := ⟨S, J.superset_covering (Sieve.le_generate S.arrows) hS, le_rfl⟩ + le_l_u J _ S hS := ⟨S, J.superset_covering (Sieve.le_generate S.arrows) hS, le_rfl⟩ choice x _ := toGrothendieck C x choice_eq _ _ := rfl +lemma mem_ofGrothendieck (t : GrothendieckTopology C) {X : C} (S : Presieve X) : + S ∈ ofGrothendieck C t X ↔ Sieve.generate S ∈ t X := + Iff.rfl + /-- The trivial pretopology, in which the coverings are exactly singleton isomorphisms. This topology is also known as the indiscrete, coarse, or chaotic topology. @@ -164,7 +168,7 @@ See -/ def trivial : Pretopology C where coverings X S := ∃ (Y : _) (f : Y ⟶ X) (_ : IsIso f), S = Presieve.singleton f - has_isos X Y f i := ⟨_, _, i, rfl⟩ + has_isos _ _ _ i := ⟨_, _, i, rfl⟩ pullbacks X Y f S := by rintro ⟨Z, g, i, rfl⟩ refine ⟨pullback g f, pullback.snd _ _, ?_, ?_⟩ @@ -179,7 +183,7 @@ def trivial : Pretopology C where rcases hS g (singleton_self g) with ⟨Y, f, i, hTi⟩ refine ⟨_, f ≫ g, ?_, ?_⟩ · infer_instance - -- Porting note: the next four lines were just "ext (W k)" + -- Porting note (#11041): the next four lines were just "ext (W k)" apply funext rintro W apply Set.ext @@ -194,7 +198,7 @@ def trivial : Pretopology C where rw [hTi] apply singleton.mk -instance : OrderBot (Pretopology C) where +instance orderBot : OrderBot (Pretopology C) where bot := trivial C bot_le K X R := by rintro ⟨Y, f, hf, rfl⟩ @@ -204,6 +208,64 @@ instance : OrderBot (Pretopology C) where theorem toGrothendieck_bot : toGrothendieck C ⊥ = ⊥ := (gi C).gc.l_bot +instance : InfSet (Pretopology C) where + sInf T := { + coverings := sInf (coverings '' T) + has_isos := fun X Y f _ ↦ by + simp only [sInf_apply, Set.iInf_eq_iInter, Set.iInter_coe_set, Set.mem_image, + Set.iInter_exists, + Set.biInter_and', Set.iInter_iInter_eq_right, Set.mem_iInter] + intro t _ + exact t.has_isos f + pullbacks := fun X Y f S hS ↦ by + simp only [sInf_apply, Set.iInf_eq_iInter, Set.iInter_coe_set, Set.mem_image, + Set.iInter_exists, Set.biInter_and', Set.iInter_iInter_eq_right, Set.mem_iInter] at hS ⊢ + intro t ht + exact t.pullbacks f S (hS t ht) + transitive := fun X S Ti hS hTi ↦ by + simp only [sInf_apply, Set.iInf_eq_iInter, Set.iInter_coe_set, Set.mem_image, + Set.iInter_exists, Set.biInter_and', Set.iInter_iInter_eq_right, Set.mem_iInter] at hS hTi ⊢ + intro t ht + exact t.transitive S Ti (hS t ht) (fun Y f H ↦ hTi f H t ht) + } + +lemma mem_sInf (T : Set (Pretopology C)) {X : C} (S : Presieve X) : + S ∈ sInf T X ↔ ∀ t ∈ T, S ∈ t X := by + show S ∈ sInf (Pretopology.coverings '' T) X ↔ _ + simp + +lemma sInf_ofGrothendieck (T : Set (GrothendieckTopology C)) : + ofGrothendieck C (sInf T) = sInf (ofGrothendieck C '' T) := by + ext X S + simp [mem_sInf, mem_ofGrothendieck, GrothendieckTopology.mem_sInf] + +lemma isGLB_sInf (T : Set (Pretopology C)) : IsGLB T (sInf T) := + IsGLB.of_image (f := coverings) Iff.rfl (_root_.isGLB_sInf _) + +/-- The complete lattice structure on pretopologies. This is induced by the `InfSet` instance, but +with good definitional equalities for `⊥`, `⊤` and `⊓`. -/ +instance : CompleteLattice (Pretopology C) where + __ := orderBot C + __ := orderTop C + inf t₁ t₂ := { + coverings := fun X ↦ t₁.coverings X ∩ t₂.coverings X + has_isos := fun _ _ f _ ↦ + ⟨t₁.has_isos f, t₂.has_isos f⟩ + pullbacks := fun _ _ f S hS ↦ + ⟨t₁.pullbacks f S hS.left, t₂.pullbacks f S hS.right⟩ + transitive := fun _ S Ti hS hTi ↦ + ⟨t₁.transitive S Ti hS.left (fun _ f H ↦ (hTi f H).left), + t₂.transitive S Ti hS.right (fun _ f H ↦ (hTi f H).right)⟩ + } + inf_le_left _ _ _ _ hS := hS.left + inf_le_right _ _ _ _ hS := hS.right + le_inf _ _ _ hts htr X _ hS := ⟨hts X hS, htr X hS⟩ + __ := completeLatticeOfInf _ (isGLB_sInf C) + +lemma mem_inf (t₁ t₂ : Pretopology C) {X : C} (S : Presieve X) : + S ∈ (t₁ ⊓ t₂) X ↔ S ∈ t₁ X ∧ S ∈ t₂ X := + Iff.rfl + end Pretopology end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Sheaf.lean b/Mathlib/CategoryTheory/Sites/Sheaf.lean index 80f0edcd7ebfb..10da297aaf6d1 100644 --- a/Mathlib/CategoryTheory/Sites/Sheaf.lean +++ b/Mathlib/CategoryTheory/Sites/Sheaf.lean @@ -97,7 +97,7 @@ def conesEquivSieveCompatibleFamily : (S.arrows.diagram.op ⋙ P).cones.obj E ≃ { x : FamilyOfElements (P ⋙ coyoneda.obj E) (S : Presieve X) // x.SieveCompatible } where toFun π := - ⟨fun Y f h => π.app (op ⟨Over.mk f, h⟩), fun X Y f g hf => by + ⟨fun _ f h => π.app (op ⟨Over.mk f, h⟩), fun X Y f g hf => by apply (id_comp _).symm.trans dsimp exact π.naturality (Quiver.Hom.op (Over.homMk _ (by rfl)))⟩ @@ -109,8 +109,8 @@ def conesEquivSieveCompatibleFamily : rw [id_comp] convert rfl rw [Over.w] } - left_inv π := rfl - right_inv x := rfl + left_inv _ := rfl + right_inv _ := rfl -- These lemmas have always been bad (#7657), but leanprover/lean4#2644 made `simp` start noticing attribute [nolint simpNF] CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily_apply_coe @@ -332,7 +332,6 @@ instance instCategorySheaf : Category (Sheaf J A) where instance (X : Sheaf J A) : Inhabited (Hom X X) := ⟨𝟙 X⟩ --- Porting note: added because `Sheaf.Hom.ext` was not triggered automatically @[ext] lemma hom_ext {X Y : Sheaf J A} (x y : X ⟶ Y) (h : x.val = y.val) : x = y := Sheaf.Hom.ext h @@ -419,8 +418,8 @@ def sheafEquivSheafOfTypes : Sheaf J (Type w) ≌ SheafOfTypes J where inverse := { obj := fun S => ⟨S.val, (isSheaf_iff_isSheaf_of_type _ _).2 S.2⟩ map := fun f => ⟨f.val⟩ } - unitIso := NatIso.ofComponents fun X => Iso.refl _ - counitIso := NatIso.ofComponents fun X => Iso.refl _ + unitIso := NatIso.ofComponents fun _ => Iso.refl _ + counitIso := NatIso.ofComponents fun _ => Iso.refl _ instance : Inhabited (Sheaf (⊥ : GrothendieckTopology C) (Type w)) := ⟨(sheafEquivSheafOfTypes _).inverse.obj default⟩ @@ -481,7 +480,7 @@ instance Sheaf.Hom.addCommGroup : AddCommGroup (P ⟶ Q) := (fun _ _ => by aesop_cat) (fun _ _ => by aesop_cat) instance : Preadditive (Sheaf J A) where - homGroup P Q := Sheaf.Hom.addCommGroup + homGroup _ _ := Sheaf.Hom.addCommGroup end Preadditive @@ -515,7 +514,7 @@ section MultiequalizerConditions /-- When `P` is a sheaf and `S` is a cover, the associated multifork is a limit. -/ def isLimitOfIsSheaf {X : C} (S : J.Cover X) (hP : IsSheaf J P) : IsLimit (S.multifork P) where - lift := fun E : Multifork _ => hP.amalgamate S (fun I => E.ι _) + lift := fun E : Multifork _ => hP.amalgamate S (fun _ => E.ι _) (fun _ _ r => E.condition ⟨_, _, r⟩) fac := by rintro (E : Multifork _) (a | b) diff --git a/Mathlib/CategoryTheory/Sites/SheafHom.lean b/Mathlib/CategoryTheory/Sites/SheafHom.lean index 196eeab7477ac..d49a0a625c7ff 100644 --- a/Mathlib/CategoryTheory/Sites/SheafHom.lean +++ b/Mathlib/CategoryTheory/Sites/SheafHom.lean @@ -84,7 +84,7 @@ def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where (Over.homMk f : Over.mk f ⟶ Over.mk (𝟙 X₁)).op) rw [← s.2 f.op, presheafHom_map_app_op_mk_id] rfl } - invFun f := ⟨fun X => whiskerLeft _ f, fun _ => rfl⟩ + invFun f := ⟨fun _ => whiskerLeft _ f, fun _ => rfl⟩ left_inv s := by dsimp ext ⟨X⟩ ⟨Y : Over X⟩ @@ -92,7 +92,7 @@ def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where dsimp at H ⊢ rw [← H] apply presheafHom_map_app_op_mk_id - right_inv f := rfl + right_inv _ := rfl variable {F G} diff --git a/Mathlib/CategoryTheory/Sites/Sieves.lean b/Mathlib/CategoryTheory/Sites/Sieves.lean index 172573aad9266..66591c5a8f117 100644 --- a/Mathlib/CategoryTheory/Sites/Sieves.lean +++ b/Mathlib/CategoryTheory/Sites/Sieves.lean @@ -3,6 +3,7 @@ Copyright (c) 2020 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Edward Ayers -/ +import Mathlib.Data.Set.Lattice import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback /-! @@ -130,7 +131,7 @@ theorem ofArrows_pUnit : (ofArrows _ fun _ : PUnit => f) = singleton f := by exact ofArrows.mk PUnit.unit theorem ofArrows_pullback [HasPullbacks C] {ι : Type*} (Z : ι → C) (g : ∀ i : ι, Z i ⟶ X) : - (ofArrows (fun i => pullback (g i) f) fun i => pullback.snd _ _) = + (ofArrows (fun i => pullback (g i) f) fun _ => pullback.snd _ _) = pullbackArrows f (ofArrows Z g) := by funext T ext h @@ -144,7 +145,7 @@ theorem ofArrows_pullback [HasPullbacks C] {ι : Type*} (Z : ι → C) (g : ∀ theorem ofArrows_bind {ι : Type*} (Z : ι → C) (g : ∀ i : ι, Z i ⟶ X) (j : ∀ ⦃Y⦄ (f : Y ⟶ X), ofArrows Z g f → Type*) (W : ∀ ⦃Y⦄ (f : Y ⟶ X) (H), j f H → C) (k : ∀ ⦃Y⦄ (f : Y ⟶ X) (H i), W f H i ⟶ Y) : - ((ofArrows Z g).bind fun Y f H => ofArrows (W f H) (k f H)) = + ((ofArrows Z g).bind fun _ f H => ofArrows (W f H) (k f H)) = ofArrows (fun i : Σi, j _ (ofArrows.mk i) => W (g i.1) _ i.2) fun ij => k (g ij.1) _ ij.2 ≫ g ij.1 := by funext Y @@ -267,7 +268,7 @@ open Lattice /-- The supremum of a collection of sieves: the union of them all. -/ protected def sup (𝒮 : Set (Sieve X)) : Sieve X where - arrows Y := { f | ∃ S ∈ 𝒮, Sieve.arrows S f } + arrows _ := { f | ∃ S ∈ 𝒮, Sieve.arrows S f } downward_closed {_ _ f} hf _ := by obtain ⟨S, hS, hf⟩ := hf exact ⟨S, hS, S.downward_closed hf _⟩ @@ -279,12 +280,12 @@ protected def inf (𝒮 : Set (Sieve X)) : Sieve X where /-- The union of two sieves is a sieve. -/ protected def union (S R : Sieve X) : Sieve X where - arrows Y f := S f ∨ R f + arrows _ f := S f ∨ R f downward_closed := by rintro _ _ _ (h | h) g <;> simp [h] /-- The intersection of two sieves is a sieve. -/ protected def inter (S R : Sieve X) : Sieve X where - arrows Y f := S f ∧ R f + arrows _ f := S f ∧ R f downward_closed := by rintro _ _ _ ⟨h₁, h₂⟩ g simp [h₁, h₂] @@ -294,9 +295,9 @@ We generate this directly rather than using the galois insertion for nicer defin -/ instance : CompleteLattice (Sieve X) where le S R := ∀ ⦃Y⦄ (f : Y ⟶ X), S f → R f - le_refl S f q := id - le_trans S₁ S₂ S₃ S₁₂ S₂₃ Y f h := S₂₃ _ (S₁₂ _ h) - le_antisymm S R p q := Sieve.ext fun Y f => ⟨p _, q _⟩ + le_refl _ _ _ := id + le_trans _ _ _ S₁₂ S₂₃ _ _ h := S₂₃ _ (S₁₂ _ h) + le_antisymm _ _ p q := Sieve.ext fun _ _ => ⟨p _, q _⟩ top := { arrows := fun _ => Set.univ downward_closed := fun _ _ => ⟨⟩ } @@ -307,8 +308,8 @@ instance : CompleteLattice (Sieve X) where inf := Sieve.inter sSup := Sieve.sup sInf := Sieve.inf - le_sSup 𝒮 S hS Y f hf := ⟨S, hS, hf⟩ - sSup_le := fun s a ha Y f ⟨b, hb, hf⟩ => (ha b hb) _ hf + le_sSup _ S hS _ _ hf := ⟨S, hS, hf⟩ + sSup_le := fun _ _ ha _ _ ⟨b, hb, hf⟩ => (ha b hb) _ hf sInf_le _ _ hS _ _ h := h _ hS le_sInf _ _ hS _ _ hf _ hR := hS _ hR _ hf le_sup_left _ _ _ _ := Or.inl @@ -362,7 +363,7 @@ produce a sieve on `X`. -/ @[simps] def bind (S : Presieve X) (R : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, S f → Sieve Y) : Sieve X where - arrows := S.bind fun Y f h => R h + arrows := S.bind fun _ _ h => R h downward_closed := by rintro Y Z f ⟨W, f, h, hh, hf, rfl⟩ g exact ⟨_, g ≫ f, _, hh, by simp [hf]⟩ @@ -370,7 +371,7 @@ def bind (S : Presieve X) (R : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, S f → Sieve Y) : open Order Lattice theorem generate_le_iff (R : Presieve X) (S : Sieve X) : generate R ≤ S ↔ R ≤ S := - ⟨fun H Y g hg => H _ ⟨_, 𝟙 _, _, hg, id_comp _⟩, fun ss Y f => by + ⟨fun H _ _ hg => H _ ⟨_, 𝟙 _, _, hg, id_comp _⟩, fun ss Y f => by rintro ⟨Z, f, g, hg, rfl⟩ exact S.downward_closed (ss Z hg) f⟩ @@ -470,7 +471,7 @@ lemma ofArrows_eq_ofObjects {X : C} (hX : IsTerminal X) That is, `Sieve.pullback S h := (≫ h) '⁻¹ S`. -/ @[simps] def pullback (h : Y ⟶ X) (S : Sieve X) : Sieve Y where - arrows Y sl := S (sl ≫ h) + arrows _ sl := S (sl ≫ h) downward_closed g := by simp [g] @[simp] @@ -506,7 +507,7 @@ factors through some `g : Z ⟶ Y` which is in `R`. -/ @[simps] def pushforward (f : Y ⟶ X) (R : Sieve Y) : Sieve X where - arrows Z gf := ∃ g, g ≫ f = gf ∧ R g + arrows _ gf := ∃ g, g ≫ f = gf ∧ R g downward_closed := fun ⟨j, k, z⟩ h => ⟨h ≫ j, by simp [k], by simp [z]⟩ theorem pushforward_apply_comp {R : Sieve Y} {Z : C} {g : Z ⟶ Y} (hg : R g) (f : Y ⟶ X) : @@ -767,11 +768,11 @@ def functor (S : Sieve X) : Cᵒᵖ ⥤ Type v₁ where presheaves. -/ @[simps] -def natTransOfLe {S T : Sieve X} (h : S ≤ T) : S.functor ⟶ T.functor where app Y f := ⟨f.1, h _ f.2⟩ +def natTransOfLe {S T : Sieve X} (h : S ≤ T) : S.functor ⟶ T.functor where app _ f := ⟨f.1, h _ f.2⟩ /-- The natural inclusion from the functor induced by a sieve to the yoneda embedding. -/ @[simps] -def functorInclusion (S : Sieve X) : S.functor ⟶ yoneda.obj X where app Y f := f.1 +def functorInclusion (S : Sieve X) : S.functor ⟶ yoneda.obj X where app _ f := f.1 theorem natTransOfLe_comm {S T : Sieve X} (h : S ≤ T) : natTransOfLe h ≫ functorInclusion _ = functorInclusion _ := @@ -806,7 +807,7 @@ theorem sieveOfSubfunctor_functorInclusion : sieveOfSubfunctor S.functorInclusio exact ⟨⟨_, hf⟩, rfl⟩ instance functorInclusion_top_isIso : IsIso (⊤ : Sieve X).functorInclusion := - ⟨⟨{ app := fun Y a => ⟨a, ⟨⟩⟩ }, rfl, rfl⟩⟩ + ⟨⟨{ app := fun _ a => ⟨a, ⟨⟩⟩ }, rfl, rfl⟩⟩ end Sieve diff --git a/Mathlib/CategoryTheory/Sites/Spaces.lean b/Mathlib/CategoryTheory/Sites/Spaces.lean index d5faa18723e48..c85c6bdae24c9 100644 --- a/Mathlib/CategoryTheory/Sites/Spaces.lean +++ b/Mathlib/CategoryTheory/Sites/Spaces.lean @@ -43,7 +43,7 @@ open CategoryTheory TopologicalSpace CategoryTheory.Limits /-- The Grothendieck topology associated to a topological space. -/ def grothendieckTopology : GrothendieckTopology (Opens T) where sieves X S := ∀ x ∈ X, ∃ (U : _) (f : U ⟶ X), S f ∧ x ∈ U - top_mem' X x hx := ⟨_, 𝟙 _, trivial, hx⟩ + top_mem' _ _ hx := ⟨_, 𝟙 _, trivial, hx⟩ pullback_stable' X Y S f hf y hy := by rcases hf y (f.le hy) with ⟨U, g, hg, hU⟩ refine ⟨U ⊓ Y, homOfLE inf_le_right, ?_, hU, hy⟩ @@ -56,7 +56,7 @@ def grothendieckTopology : GrothendieckTopology (Opens T) where /-- The Grothendieck pretopology associated to a topological space. -/ def pretopology : Pretopology (Opens T) where coverings X R := ∀ x ∈ X, ∃ (U : _) (f : U ⟶ X), R f ∧ x ∈ U - has_isos X Y f i x hx := ⟨_, _, Presieve.singleton_self _, (inv f).le hx⟩ + has_isos _ _ f _ _ hx := ⟨_, _, Presieve.singleton_self _, (inv f).le hx⟩ pullbacks X Y f S hS x hx := by rcases hS _ (f.le hx) with ⟨U, g, hg, hU⟩ refine ⟨_, _, Presieve.pullbackArrows.mk _ _ hg, ?_⟩ diff --git a/Mathlib/CategoryTheory/Sites/Subsheaf.lean b/Mathlib/CategoryTheory/Sites/Subsheaf.lean index 198726f465d9b..be30cc3fa8ebc 100644 --- a/Mathlib/CategoryTheory/Sites/Subsheaf.lean +++ b/Mathlib/CategoryTheory/Sites/Subsheaf.lean @@ -57,7 +57,7 @@ instance : PartialOrder (Subpresheaf F) := PartialOrder.lift Subpresheaf.obj (fun _ _ => Subpresheaf.ext) instance : Top (Subpresheaf F) := - ⟨⟨fun U => ⊤, @fun U V _ x _ => by aesop_cat⟩⟩ + ⟨⟨fun _ => ⊤, @fun U _ _ x _ => by aesop_cat⟩⟩ instance : Nonempty (Subpresheaf F) := inferInstance @@ -66,7 +66,7 @@ instance : Nonempty (Subpresheaf F) := @[simps!] def Subpresheaf.toPresheaf : Cᵒᵖ ⥤ Type w where obj U := G.obj U - map := @fun U V i x => ⟨F.map i x, G.map i x.prop⟩ + map := @fun _ _ i x => ⟨F.map i x, G.map i x.prop⟩ map_id X := by ext ⟨x, _⟩ dsimp @@ -81,7 +81,7 @@ instance {U} : CoeHead (G.toPresheaf.obj U) (F.obj U) where /-- The inclusion of a subpresheaf to the original presheaf. -/ @[simps] -def Subpresheaf.ι : G.toPresheaf ⟶ F where app U x := x +def Subpresheaf.ι : G.toPresheaf ⟶ F where app _ x := x instance : Mono G.ι := ⟨@fun _ _ _ e => @@ -255,7 +255,7 @@ theorem Subpresheaf.sheafify_sheafify (h : Presieve.IsSheaf J F) : /-- The lift of a presheaf morphism onto the sheafification subpresheaf. -/ noncomputable def Subpresheaf.sheafifyLift (f : G.toPresheaf ⟶ F') (h : Presieve.IsSheaf J F') : (G.sheafify J).toPresheaf ⟶ F' where - app U s := (h (G.sieveOfSection s.1) s.prop).amalgamate + app _ s := (h (G.sieveOfSection s.1) s.prop).amalgamate (_) ((G.family_of_elements_compatible s.1).compPresheafMap f) naturality := by intro U V i diff --git a/Mathlib/CategoryTheory/Sites/Types.lean b/Mathlib/CategoryTheory/Sites/Types.lean index fca7e5d973986..ecbb98c1d2d6f 100644 --- a/Mathlib/CategoryTheory/Sites/Types.lean +++ b/Mathlib/CategoryTheory/Sites/Types.lean @@ -48,7 +48,7 @@ theorem generate_discretePresieve_mem (α : Type u) : open Presieve theorem isSheaf_yoneda' {α : Type u} : IsSheaf typesGrothendieckTopology (yoneda.obj α) := - fun β S hs x hx => + fun β _ hs x hx => ⟨fun y => x _ (hs y) PUnit.unit, fun γ f h => funext fun z => by convert congr_fun (hx (𝟙 _) (fun _ => z) (hs <| f z) h rfl) PUnit.unit using 1, @@ -76,7 +76,7 @@ def eval (P : Type uᵒᵖ ⥤ Type u) (α : Type u) (s : P.obj (op α)) (x : α noncomputable def typesGlue (S : Type uᵒᵖ ⥤ Type u) (hs : IsSheaf typesGrothendieckTopology S) (α : Type u) (f : α → S.obj (op PUnit)) : S.obj (op α) := (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).amalgamate - (fun β g hg => S.map (↾fun _ => PUnit.unit).op <| f <| g <| Classical.choose hg) + (fun _ g hg => S.map (↾fun _ => PUnit.unit).op <| f <| g <| Classical.choose hg) fun β γ δ g₁ g₂ f₁ f₂ hf₁ hf₂ h => (hs.isSheafFor _ _ (generate_discretePresieve_mem δ)).isSeparatedFor.ext fun ε g ⟨x, _⟩ => by have : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂) := @@ -172,6 +172,6 @@ theorem typesGrothendieckTopology_eq_canonical : have : (fun _ => ULift.up true) = fun _ => ULift.up false := (hs PUnit fun _ => x).isSeparatedFor.ext fun β f hf => funext fun y => hsx.elim <| S.2 hf fun _ => y - simp [Function.funext_iff] at this + simp [funext_iff] at this end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Whiskering.lean b/Mathlib/CategoryTheory/Sites/Whiskering.lean index 17685ddf1e50a..5f9c74a7af9c3 100644 --- a/Mathlib/CategoryTheory/Sites/Whiskering.lean +++ b/Mathlib/CategoryTheory/Sites/Whiskering.lean @@ -75,7 +75,7 @@ If `η : F ⟶ G` is a natural transformation then we obtain a morphism of funct `sheafCompose J F ⟶ sheafCompose J G` by whiskering with `η` on the level of presheaves. -/ def sheafCompose_map : sheafCompose J F ⟶ sheafCompose J G where - app := fun X => .mk <| whiskerLeft _ η + app := fun _ => .mk <| whiskerLeft _ η @[simp] lemma sheafCompose_id : sheafCompose_map (F := F) J (𝟙 _) = 𝟙 _ := rfl @@ -97,8 +97,8 @@ def multicospanComp : (S.index (P ⋙ F)).multicospan ≅ (S.index P).multicospa NatIso.ofComponents (fun t => match t with - | WalkingMulticospan.left a => Iso.refl _ - | WalkingMulticospan.right b => Iso.refl _) + | WalkingMulticospan.left _ => Iso.refl _ + | WalkingMulticospan.right _ => Iso.refl _) (by rintro (a | b) (a | b) (f | f | f) all_goals aesop_cat) diff --git a/Mathlib/CategoryTheory/Skeletal.lean b/Mathlib/CategoryTheory/Skeletal.lean index 2ff548def5bb3..5bc475b804342 100644 --- a/Mathlib/CategoryTheory/Skeletal.lean +++ b/Mathlib/CategoryTheory/Skeletal.lean @@ -67,7 +67,7 @@ variable (C D) /-- Construct the skeleton category as the induced category on the isomorphism classes, and derive its category structure. -/ -def Skeleton : Type u₁ := InducedCategory C Quotient.out +def Skeleton : Type u₁ := InducedCategory (C := Quotient (isIsomorphicSetoid C)) C Quotient.out instance [Inhabited C] : Inhabited (Skeleton C) := ⟨⟦default⟧⟩ @@ -144,7 +144,7 @@ instance ThinSkeleton.preorder : Preorder (ThinSkeleton C) where le_refl := by refine Quotient.ind fun a => ?_ exact ⟨𝟙 _⟩ - le_trans a b c := Quotient.inductionOn₃ a b c fun A B C => Nonempty.map2 (· ≫ ·) + le_trans a b c := Quotient.inductionOn₃ a b c fun _ _ _ => Nonempty.map2 (· ≫ ·) /-- The functor from a category to its thin skeleton. -/ @[simps] @@ -171,8 +171,8 @@ variable {C} {D} /-- A functor `C ⥤ D` computably lowers to a functor `ThinSkeleton C ⥤ ThinSkeleton D`. -/ @[simps] def map (F : C ⥤ D) : ThinSkeleton C ⥤ ThinSkeleton D where - obj := Quotient.map F.obj fun X₁ X₂ ⟨hX⟩ => ⟨F.mapIso hX⟩ - map {X} {Y} := Quotient.recOnSubsingleton₂ X Y fun x y k => homOfLE (k.le.elim fun t => ⟨F.map t⟩) + obj := Quotient.map F.obj fun _ _ ⟨hX⟩ => ⟨F.mapIso hX⟩ + map {X} {Y} := Quotient.recOnSubsingleton₂ X Y fun _ _ k => homOfLE (k.le.elim fun t => ⟨F.map t⟩) theorem comp_toThinSkeleton (F : C ⥤ D) : F ⋙ toThinSkeleton D = toThinSkeleton C ⋙ map F := rfl @@ -205,7 +205,7 @@ def map₂Functor (F : C ⥤ D ⥤ E) : ThinSkeleton C → ThinSkeleton D ⥤ Th { obj := fun y => map₂ObjMap F x y map := fun {y₁} {y₂} => @Quotient.recOnSubsingleton C (isIsomorphicSetoid C) (fun x => (y₁ ⟶ y₂) → (map₂ObjMap F x y₁ ⟶ map₂ObjMap F x y₂)) _ x fun X - => Quotient.recOnSubsingleton₂ y₁ y₂ fun Y₁ Y₂ hY => + => Quotient.recOnSubsingleton₂ y₁ y₂ fun _ _ hY => homOfLE (hY.le.elim fun g => ⟨(F.obj X).map g⟩) } /-- This provides natural transformations `map₂Functor F x₁ ⟶ map₂Functor F x₂` given @@ -270,11 +270,11 @@ theorem skeletal : Skeletal (ThinSkeleton C) := fun X Y => theorem map_comp_eq (F : E ⥤ D) (G : D ⥤ C) : map (F ⋙ G) = map F ⋙ map G := Functor.eq_of_iso skeletal <| - NatIso.ofComponents fun X => Quotient.recOnSubsingleton X fun x => Iso.refl _ + NatIso.ofComponents fun X => Quotient.recOnSubsingleton X fun _ => Iso.refl _ theorem map_id_eq : map (𝟭 C) = 𝟭 (ThinSkeleton C) := Functor.eq_of_iso skeletal <| - NatIso.ofComponents fun X => Quotient.recOnSubsingleton X fun x => Iso.refl _ + NatIso.ofComponents fun X => Quotient.recOnSubsingleton X fun _ => Iso.refl _ theorem map_iso_eq {F₁ F₂ : D ⥤ C} (h : F₁ ≅ F₂) : map F₁ = map F₂ := Functor.eq_of_iso skeletal diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean similarity index 51% rename from Mathlib/CategoryTheory/SmallObject/Iteration.lean rename to Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean index a9470418b418d..9bcc16aca6810 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean @@ -5,7 +5,8 @@ Authors: Joël Riou -/ import Mathlib.CategoryTheory.Category.Preorder import Mathlib.CategoryTheory.Limits.IsLimit -import Mathlib.Order.IsWellOrderLimitElement +import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.SuccPred.Limit /-! # Transfinite iterations of a functor @@ -14,7 +15,7 @@ In this file, given a functor `Φ : C ⥤ C` and a natural transformation Given `j : J` where `J` is a well ordered set, we first introduce a category `Iteration ε j`. An object in this category consists of -a functor `F : { i // i ≤ j } ⥤ C ⥤ C` equipped with the data +a functor `F : Set.Iic j ⥤ C ⥤ C` equipped with the data which makes it the `i`th-iteration of `Φ` for all `i` such that `i ≤ j`. Under suitable assumptions on `C`, we shall show that this category `Iteration ε j` is equivalent to the punctual category (TODO). @@ -36,26 +37,25 @@ namespace CategoryTheory open Category Limits -variable {C : Type*} [Category C] {Φ : C ⥤ C} (ε : 𝟭 C ⟶ Φ) - {J : Type u} [LinearOrder J] +variable {C : Type*} [Category C] {Φ : C ⥤ C} (ε : 𝟭 C ⟶ Φ) {J : Type u} namespace Functor namespace Iteration -variable {j : J} (F : { i // i ≤ j } ⥤ C) +variable [Preorder J] {j : J} (F : Set.Iic j ⥤ C) -/-- The map `F.obj ⟨i, _⟩ ⟶ F.obj ⟨wellOrderSucc i, _⟩` when `F : { i // i ≤ j } ⥤ C` +/-- The map `F.obj ⟨i, _⟩ ⟶ F.obj ⟨Order.succ i, _⟩` when `F : Set.Iic j ⥤ C` and `i : J` is such that `i < j`. -/ -noncomputable abbrev mapSucc' [IsWellOrder J (· < ·)] (i : J) (hi : i < j) : - F.obj ⟨i, hi.le⟩ ⟶ F.obj ⟨wellOrderSucc i, wellOrderSucc_le hi⟩ := - F.map (homOfLE (by simpa only [Subtype.mk_le_mk] using self_le_wellOrderSucc i)) +noncomputable abbrev mapSucc' [SuccOrder J] (i : J) (hi : i < j) : + F.obj ⟨i, hi.le⟩ ⟶ F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ := + F.map <| homOfLE <| Subtype.mk_le_mk.2 <| Order.le_succ i variable {i : J} (hi : i ≤ j) -/-- The functor `{ k // k < i } ⥤ C` obtained by "restriction" of `F : { i // i ≤ j } ⥤ C` +/-- The functor `Set.Iio i ⥤ C` obtained by "restriction" of `F : Set.Iic j ⥤ C` when `i ≤ j`. -/ -def restrictionLT : { k // k < i } ⥤ C := +def restrictionLT : Set.Iio i ⥤ C := (monotone_inclusion_lt_le_of_le hi).functor ⋙ F @[simp] @@ -63,10 +63,10 @@ lemma restrictionLT_obj (k : J) (hk : k < i) : (restrictionLT F hi).obj ⟨k, hk⟩ = F.obj ⟨k, hk.le.trans hi⟩ := rfl @[simp] -lemma restrictionLT_map {k₁ k₂ : { k // k < i }} (φ : k₁ ⟶ k₂) : +lemma restrictionLT_map {k₁ k₂ : Set.Iio i} (φ : k₁ ⟶ k₂) : (restrictionLT F hi).map φ = F.map (homOfLE (by simpa using leOfHom φ)) := rfl -/-- Given `F : { i // i ≤ j } ⥤ C`, `i : J` such that `hi : i ≤ j`, this is the +/-- Given `F : Set.Iic j ⥤ C`, `i : J` such that `hi : i ≤ j`, this is the cocone consisting of all maps `F.obj ⟨k, hk⟩ ⟶ F.obj ⟨i, hi⟩` for `k : J` such that `k < i`. -/ @[simps] def coconeOfLE : Cocone (restrictionLT F hi) where @@ -76,31 +76,41 @@ def coconeOfLE : Cocone (restrictionLT F hi) where naturality := fun ⟨k₁, hk₁⟩ ⟨k₂, hk₂⟩ _ => by simp [comp_id, ← Functor.map_comp, homOfLE_comp] } -end Iteration +/-- The functor `Set.Iic i ⥤ C` obtained by "restriction" of `F : Set.Iic j ⥤ C` +when `i ≤ j`. -/ +def restrictionLE : Set.Iic i ⥤ C := + (monotone_inclusion_le_le_of_le hi).functor ⋙ F + +@[simp] +lemma restrictionLE_obj (k : J) (hk : k ≤ i) : + (restrictionLE F hi).obj ⟨k, hk⟩ = F.obj ⟨k, hk.trans hi⟩ := rfl -variable [IsWellOrder J (· < ·)] [OrderBot J] +@[simp] +lemma restrictionLE_map {k₁ k₂ : Set.Iic i} (φ : k₁ ⟶ k₂) : + (restrictionLE F hi).map φ = F.map (homOfLE (by simpa using leOfHom φ)) := rfl + +end Iteration /-- The category of `j`th iterations of a functor `Φ` equipped with a natural transformation `ε : 𝟭 C ⟶ Φ`. An object consists of the data of all iterations of `Φ` for `i : J` such that `i ≤ j` (this is the field `F`). Such objects are equipped with data and properties which characterizes the iterations up to a unique isomorphism for the three types of elements: `⊥`, successors, limit elements. -/ -structure Iteration (j : J) where +structure Iteration [Preorder J] [OrderBot J] [SuccOrder J] (j : J) where /-- The data of all `i`th iterations for `i : J` such that `i ≤ j`. -/ - F : { i // i ≤ j } ⥤ C ⥤ C + F : Set.Iic j ⥤ C ⥤ C /-- The zeroth iteration is the identity functor. -/ isoZero : F.obj ⟨⊥, bot_le⟩ ≅ 𝟭 C /-- The iteration on a successor element is obtained by composition of the previous iteration with `Φ`. -/ - isoSucc (i : J) (hi : i < j) : - F.obj ⟨wellOrderSucc i, wellOrderSucc_le hi⟩ ≅ F.obj ⟨i, hi.le⟩ ⋙ Φ + isoSucc (i : J) (hi : i < j) : F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ ≅ F.obj ⟨i, hi.le⟩ ⋙ Φ /-- The natural map from an iteration to its successor is induced by `ε`. -/ mapSucc'_eq (i : J) (hi : i < j) : Iteration.mapSucc' F i hi = whiskerLeft _ ε ≫ (isoSucc i hi).inv /-- If `i` is a limit element, the `i`th iteration is the colimit of `k`th iterations for `k < i`. -/ - isColimit (i : J) [IsWellOrderLimitElement i] (hi : i ≤ j) : - IsColimit (Iteration.coconeOfLE F hi) + isColimit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) : + IsColimit (Iteration.coconeOfLE F hij) namespace Iteration @@ -109,12 +119,12 @@ variable {j : J} section -variable (iter : Φ.Iteration ε j) +variable [Preorder J] [OrderBot J] [SuccOrder J] (iter : Φ.Iteration ε j) /-- For `iter : Φ.Iteration.ε j`, this is the map -`iter.F.obj ⟨i, _⟩ ⟶ iter.F.obj ⟨wellOrderSucc i, _⟩` if `i : J` is such that `i < j`. -/ +`iter.F.obj ⟨i, _⟩ ⟶ iter.F.obj ⟨Order.succ i, _⟩` if `i : J` is such that `i < j`. -/ noncomputable abbrev mapSucc (i : J) (hi : i < j) : - iter.F.obj ⟨i, hi.le⟩ ⟶ iter.F.obj ⟨wellOrderSucc i, wellOrderSucc_le hi⟩ := + iter.F.obj ⟨i, hi.le⟩ ⟶ iter.F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ := mapSucc' iter.F i hi lemma mapSucc_eq (i : J) (hi : i < j) : @@ -123,7 +133,9 @@ lemma mapSucc_eq (i : J) (hi : i < j) : end -variable (iter₁ iter₂ : Φ.Iteration ε j) +section + +variable [Preorder J] [OrderBot J] [SuccOrder J] (iter₁ iter₂ : Φ.Iteration ε j) /-- A morphism between two objects `iter₁` and `iter₂` in the category `Φ.Iteration ε j` of `j`th iterations of a functor `Φ` @@ -136,7 +148,7 @@ structure Hom where natTrans_app_zero : natTrans.app ⟨⊥, bot_le⟩ = iter₁.isoZero.hom ≫ iter₂.isoZero.inv := by aesop_cat natTrans_app_succ (i : J) (hi : i < j) : - natTrans.app ⟨wellOrderSucc i, wellOrderSucc_le hi⟩ = (iter₁.isoSucc i hi).hom ≫ + natTrans.app ⟨Order.succ i, Order.succ_le_of_lt hi⟩ = (iter₁.isoSucc i hi).hom ≫ whiskerRight (natTrans.app ⟨i, hi.le⟩) _ ≫ (iter₂.isoSucc i hi).inv := by aesop_cat namespace Hom @@ -172,17 +184,87 @@ instance : Category (Iteration ε j) where id := id comp := comp -instance : Subsingleton (iter₁ ⟶ iter₂) where - allEq f g := ext' (by - let P := fun (i : J) => ∀ (hi : i ≤ j), f.natTrans.app ⟨i, hi⟩ = g.natTrans.app ⟨i, hi⟩ - suffices ∀ (i : J), P i by +instance {J} {j : J} [PartialOrder J] [OrderBot J] [WellFoundedLT J] [SuccOrder J] + {iter₁ iter₂ : Iteration ε j} : + Subsingleton (iter₁ ⟶ iter₂) where + allEq f g := by + apply ext' + suffices ∀ i hi, f.natTrans.app ⟨i, hi⟩ = g.natTrans.app ⟨i, hi⟩ by ext ⟨i, hi⟩ : 2 apply this - refine fun _ => WellFoundedLT.induction _ (fun i hi hi' => ?_) - obtain rfl|⟨i, rfl, hi''⟩|_ := eq_bot_or_eq_succ_or_isWellOrderLimitElement i - · simp only [natTrans_app_zero] - · simp only [Hom.natTrans_app_succ _ i (lt_of_lt_of_le hi'' hi'), hi i hi''] - · exact (iter₁.isColimit i hi').hom_ext (fun ⟨k, hk⟩ => by simp [hi k hk])) + intro i + induction i using SuccOrder.limitRecOn with + | hm j H => + obtain rfl := H.eq_bot + simp [natTrans_app_zero] + | hs j H IH => + intro hj + simp [Hom.natTrans_app_succ, IH, (Order.lt_succ_of_not_isMax H).trans_le hj] + | hl j H IH => + refine fun hj ↦ (iter₁.isColimit j H hj).hom_ext ?_ + rintro ⟨k, hk⟩ + simp [IH k hk] + +end Hom + +@[simp] +lemma natTrans_id : Hom.natTrans (𝟙 iter₁) = 𝟙 _ := rfl + +variable {iter₁ iter₂} + +@[simp, reassoc] +lemma natTrans_comp {iter₃ : Iteration ε j} (φ : iter₁ ⟶ iter₂) (ψ : iter₂ ⟶ iter₃) : + (φ ≫ ψ).natTrans = φ.natTrans ≫ ψ.natTrans := rfl + +@[reassoc] +lemma natTrans_naturality (φ : iter₁ ⟶ iter₂) (i₁ i₂ : J) (h : i₁ ≤ i₂) (h' : i₂ ≤ j) : + iter₁.F.map (by exact homOfLE h) ≫ φ.natTrans.app ⟨i₂, h'⟩ = + φ.natTrans.app ⟨i₁, h.trans h'⟩ ≫ iter₂.F.map (by exact homOfLE h) := by + apply φ.natTrans.naturality + +variable (ε) in +/-- The evaluation functor `Iteration ε j ⥤ C ⥤ C` at `i : J` when `i ≤ j`. -/ +@[simps] +def eval {i : J} (hi : i ≤ j) : Iteration ε j ⥤ C ⥤ C where + obj iter := iter.F.obj ⟨i, hi⟩ + map φ := φ.natTrans.app _ + +/-- Given `iter : Iteration ε j` and `i : J` such that `i ≤ j`, this is the +induced element in `Iteration ε i`. -/ +@[simps F isoZero isoSucc] +def trunc (iter : Iteration ε j) {i : J} (hi : i ≤ j) : Iteration ε i where + F := restrictionLE (iter.F) hi + isoZero := iter.isoZero + isoSucc k hk := iter.isoSucc k (lt_of_lt_of_le hk hi) + mapSucc'_eq k hk := iter.mapSucc'_eq k (lt_of_lt_of_le hk hi) + isColimit k hk' hk := iter.isColimit k hk' (hk.trans hi) + +variable (ε) in +/-- The truncation functor `Iteration ε j ⥤ Iteration ε i` when `i ≤ j`. -/ +@[simps obj] +def truncFunctor {i : J} (hi : i ≤ j) : Iteration ε j ⥤ Iteration ε i where + obj iter := iter.trunc hi + map {iter₁ iter₂} φ := + { natTrans := whiskerLeft _ φ.natTrans + natTrans_app_succ := fun k hk => φ.natTrans_app_succ k (lt_of_lt_of_le hk hi) } + +@[simp] +lemma truncFunctor_map_natTrans_app + (φ : iter₁ ⟶ iter₂) {i : J} (hi : i ≤ j) (k : J) (hk : k ≤ i) : + ((truncFunctor ε hi).map φ).natTrans.app ⟨k, hk⟩ = + φ.natTrans.app ⟨k, hk.trans hi⟩ := rfl + +end + +namespace Hom + +variable [PartialOrder J] [OrderBot J] [SuccOrder J] [WellFoundedLT J] + (iter₁ iter₂ : Φ.Iteration ε j) + +lemma congr_app (φ φ' : iter₁ ⟶ iter₂) (i : J) (hi : i ≤ j) : + φ.natTrans.app ⟨i, hi⟩ = φ'.natTrans.app ⟨i, hi⟩ := by + obtain rfl := Subsingleton.elim φ φ' + rfl end Hom diff --git a/Mathlib/CategoryTheory/Subobject/Basic.lean b/Mathlib/CategoryTheory/Subobject/Basic.lean index 34c23433816f0..3afc05fb08654 100644 --- a/Mathlib/CategoryTheory/Subobject/Basic.lean +++ b/Mathlib/CategoryTheory/Subobject/Basic.lean @@ -255,21 +255,18 @@ theorem eq_of_comm {B : C} {X Y : Subobject B} (f : (X : C) ≅ (Y : C)) (w : f.hom ≫ Y.arrow = X.arrow) : X = Y := le_antisymm (le_of_comm f.hom w) <| le_of_comm f.inv <| f.inv_comp_eq.2 w.symm --- Porting note (#11182): removed @[ext] /-- To show that two subobjects are equal, it suffices to exhibit an isomorphism commuting with the arrows. -/ theorem eq_mk_of_comm {B A : C} {X : Subobject B} (f : A ⟶ B) [Mono f] (i : (X : C) ≅ A) (w : i.hom ≫ f = X.arrow) : X = mk f := eq_of_comm (i.trans (underlyingIso f).symm) <| by simp [w] --- Porting note (#11182): removed @[ext] /-- To show that two subobjects are equal, it suffices to exhibit an isomorphism commuting with the arrows. -/ theorem mk_eq_of_comm {B A : C} {X : Subobject B} (f : A ⟶ B) [Mono f] (i : A ≅ (X : C)) (w : i.hom ≫ X.arrow = f) : mk f = X := Eq.symm <| eq_mk_of_comm _ i.symm <| by rw [Iso.symm_hom, Iso.inv_comp_eq, w] --- Porting note (#11182): removed @[ext] /-- To show that two subobjects are equal, it suffices to exhibit an isomorphism commuting with the arrows. -/ theorem mk_eq_mk_of_comm {B A₁ A₂ : C} (f : A₁ ⟶ B) (g : A₂ ⟶ B) [Mono f] [Mono g] (i : A₁ ≅ A₂) diff --git a/Mathlib/CategoryTheory/Subobject/Comma.lean b/Mathlib/CategoryTheory/Subobject/Comma.lean index 790b33bdc54e1..222e850674550 100644 --- a/Mathlib/CategoryTheory/Subobject/Comma.lean +++ b/Mathlib/CategoryTheory/Subobject/Comma.lean @@ -94,7 +94,7 @@ def subobjectEquiv [HasLimits C] [PreservesLimits T] (A : StructuredArrow S T) : Subobject A ≃o { P : Subobject A.right // ∃ q, q ≫ T.map P.arrow = A.hom } where toFun P := ⟨projectSubobject P, projectSubobject_factors P⟩ invFun P := liftSubobject P.val P.prop.choose_spec - left_inv P := lift_projectSubobject _ _ + left_inv _ := lift_projectSubobject _ _ right_inv P := Subtype.ext (by simp only [liftSubobject, homMk_right, projectSubobject_mk, Subobject.mk_arrow, Subtype.coe_eta]) map_rel_iff' := by @@ -199,7 +199,7 @@ def quotientEquiv [HasColimits C] [PreservesColimits S] (A : CostructuredArrow S Subobject (op A) ≃o { P : Subobject (op A.left) // ∃ q, S.map P.arrow.unop ≫ q = A.hom } where toFun P := ⟨projectQuotient P, projectQuotient_factors P⟩ invFun P := liftQuotient P.val P.prop.choose_spec - left_inv P := lift_projectQuotient _ _ + left_inv _ := lift_projectQuotient _ _ right_inv P := Subtype.ext (by simp only [liftQuotient, Quiver.Hom.unop_op, homMk_left, Quiver.Hom.op_unop, projectQuotient_mk, Subobject.mk_arrow]) map_rel_iff' := by diff --git a/Mathlib/CategoryTheory/Subobject/Limits.lean b/Mathlib/CategoryTheory/Subobject/Limits.lean index 26f73bd07b7d2..32719bd80347c 100644 --- a/Mathlib/CategoryTheory/Subobject/Limits.lean +++ b/Mathlib/CategoryTheory/Subobject/Limits.lean @@ -212,7 +212,7 @@ instance kernelSubobject_comp_mono_isIso (f : X ⟶ Y) [HasKernel f] {Z : C} (h @[simps] def cokernelOrderHom [HasCokernels C] (X : C) : Subobject X →o (Subobject (op X))ᵒᵈ where toFun := - Subobject.lift (fun A f _ => Subobject.mk (cokernel.π f).op) + Subobject.lift (fun _ f _ => Subobject.mk (cokernel.π f).op) (by rintro A B f g hf hg i rfl refine Subobject.mk_eq_mk_of_comm _ _ (Iso.op ?_) (Quiver.Hom.unop_inj ?_) @@ -234,7 +234,7 @@ def cokernelOrderHom [HasCokernels C] (X : C) : Subobject X →o (Subobject (op @[simps] def kernelOrderHom [HasKernels C] (X : C) : (Subobject (op X))ᵒᵈ →o Subobject X where toFun := - Subobject.lift (fun A f _ => Subobject.mk (kernel.ι f.unop)) + Subobject.lift (fun _ f _ => Subobject.mk (kernel.ι f.unop)) (by rintro A B f g hf hg i rfl refine Subobject.mk_eq_mk_of_comm _ _ ?_ ?_ diff --git a/Mathlib/CategoryTheory/Subobject/MonoOver.lean b/Mathlib/CategoryTheory/Subobject/MonoOver.lean index e2cfc4d68b330..85e334fd857b6 100644 --- a/Mathlib/CategoryTheory/Subobject/MonoOver.lean +++ b/Mathlib/CategoryTheory/Subobject/MonoOver.lean @@ -355,7 +355,7 @@ def imageForgetAdj : image ⊣ forget X := e := k.left fac := Over.w k } · apply image.lift_fac - left_inv := fun k => Subsingleton.elim _ _ + left_inv := fun _ => Subsingleton.elim _ _ right_inv := fun k => by ext1 change factorThruImage _ ≫ image.lift _ = _ diff --git a/Mathlib/CategoryTheory/Subobject/Types.lean b/Mathlib/CategoryTheory/Subobject/Types.lean index cb2e06f94b8b1..9cc556ebe11f3 100644 --- a/Mathlib/CategoryTheory/Subobject/Types.lean +++ b/Mathlib/CategoryTheory/Subobject/Types.lean @@ -50,7 +50,7 @@ noncomputable def Types.monoOverEquivalenceSet (α : Type u) : MonoOver α ≌ S unitIso := NatIso.ofComponents fun f => MonoOver.isoMk (Equiv.ofInjective f.1.hom ((mono_iff_injective _).mp f.2)).toIso - counitIso := NatIso.ofComponents fun s => eqToIso Subtype.range_val + counitIso := NatIso.ofComponents fun _ => eqToIso Subtype.range_val instance : WellPowered (Type u) := wellPowered_of_essentiallySmall_monoOver fun α => diff --git a/Mathlib/CategoryTheory/Subterminal.lean b/Mathlib/CategoryTheory/Subterminal.lean index d4eee3243382b..3c93a95c72ddc 100644 --- a/Mathlib/CategoryTheory/Subterminal.lean +++ b/Mathlib/CategoryTheory/Subterminal.lean @@ -142,16 +142,16 @@ def subterminalsEquivMonoOverTerminal [HasTerminal C] : Subterminals C ≌ MonoO functor := { obj := fun X => ⟨Over.mk (terminal.from X.1), X.2.mono_terminal_from⟩ map := fun f => MonoOver.homMk f (by ext1 ⟨⟨⟩⟩) - map_id := fun X => rfl - map_comp := fun f g => rfl } + map_id := fun _ => rfl + map_comp := fun _ _ => rfl } inverse := { obj := fun X => ⟨X.obj.left, fun Z f g => by rw [← cancel_mono X.arrow] subsingleton⟩ map := fun f => f.1 - map_id := fun X => rfl - map_comp := fun f g => rfl } + map_id := fun _ => rfl + map_comp := fun _ _ => rfl } -- Porting note: the original definition was triggering a timeout, using `NatIso.ofComponents` -- in the definition of the natural isomorphisms makes the situation slightly better unitIso := NatIso.ofComponents (fun X => Iso.refl X) (by subsingleton) diff --git a/Mathlib/CategoryTheory/Sums/Basic.lean b/Mathlib/CategoryTheory/Sums/Basic.lean index 51c5a75bafa70..661d3f9c715c1 100644 --- a/Mathlib/CategoryTheory/Sums/Basic.lean +++ b/Mathlib/CategoryTheory/Sums/Basic.lean @@ -48,12 +48,12 @@ instance sum : Category.{v₁} (C ⊕ D) where | inr X => 𝟙 X comp {X Y Z} f g := match X, Y, Z, f, g with - | inl X, inl Y, inl Z, f, g => f ≫ g - | inr X, inr Y, inr Z, f, g => f ≫ g + | inl _, inl _, inl _, f, g => f ≫ g + | inr _, inr _, inr _, f, g => f ≫ g assoc {W X Y Z} f g h := match X, Y, Z, W with - | inl X, inl Y, inl Z, inl W => Category.assoc f g h - | inr X, inr Y, inr Z, inr W => Category.assoc f g h + | inl _, inl _, inl _, inl _ => Category.assoc f g h + | inr _, inr _, inr _, inr _ => Category.assoc f g h @[aesop norm -10 destruct (rule_sets := [CategoryTheory])] theorem hom_inl_inr_false {X : C} {Y : D} (f : Sum.inl X ⟶ Sum.inr Y) : False := by @@ -84,13 +84,13 @@ variable (C : Type u₁) [Category.{v₁} C] (D : Type u₁) [Category.{v₁} D] @[simps] def inl_ : C ⥤ C ⊕ D where obj X := inl X - map {X Y} f := f + map {_ _} f := f /-- `inr_` is the functor `X ↦ inr X`. -/ @[simps] def inr_ : D ⥤ C ⊕ D where obj X := inr X - map {X Y} f := f + map {_ _} f := f /- Porting note: `aesop_cat` not firing on `map_comp` where autotac in Lean 3 did but `map_id` was ok. -/ @@ -160,8 +160,8 @@ def sum (F : A ⥤ B) (G : C ⥤ D) : A ⊕ C ⥤ B ⊕ D where | inr X => inr (G.obj X) map {X Y} f := match X, Y, f with - | inl X, inl Y, f => F.map f - | inr X, inr Y, f => G.map f + | inl _, inl _, f => F.map f + | inr _, inr _, f => G.map f map_id {X} := by cases X <;> (erw [Functor.map_id]; rfl) map_comp {X Y Z} f g := match X, Y, Z, f, g with @@ -187,12 +187,12 @@ def sum' (F : A ⥤ C) (G : B ⥤ C) : A ⊕ B ⥤ C where /-- The sum `F.sum' G` precomposed with the left inclusion functor is isomorphic to `F` -/ @[simps!] def inlCompSum' (F : A ⥤ C) (G : B ⥤ C) : Sum.inl_ A B ⋙ F.sum' G ≅ F := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ /-- The sum `F.sum' G` precomposed with the right inclusion functor is isomorphic to `G` -/ @[simps!] def inrCompSum' (F : A ⥤ C) (G : B ⥤ C) : Sum.inr_ A B ⋙ F.sum' G ≅ G := - NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun _ => Iso.refl _ @[simp] theorem sum_obj_inl (F : A ⥤ B) (G : C ⥤ D) (a : A) : (F.sum G).obj (inl a) = inl (F.obj a) := diff --git a/Mathlib/CategoryTheory/Triangulated/Basic.lean b/Mathlib/CategoryTheory/Triangulated/Basic.lean index 308f5456a6a29..e76c664d5f1d3 100644 --- a/Mathlib/CategoryTheory/Triangulated/Basic.lean +++ b/Mathlib/CategoryTheory/Triangulated/Basic.lean @@ -260,9 +260,9 @@ variable {J : Type*} (T : J → Triangle C) /-- The product of a family of triangles. -/ @[simps!] def productTriangle : Triangle C := - Triangle.mk (Pi.map (fun j => (T j).mor₁)) - (Pi.map (fun j => (T j).mor₂)) - (Pi.map (fun j => (T j).mor₃) ≫ inv (piComparison _ _)) + Triangle.mk (Limits.Pi.map (fun j => (T j).mor₁)) + (Limits.Pi.map (fun j => (T j).mor₂)) + (Limits.Pi.map (fun j => (T j).mor₃) ≫ inv (piComparison _ _)) /-- A projection from the product of a family of triangles. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Triangulated/Functor.lean b/Mathlib/CategoryTheory/Triangulated/Functor.lean index 9507a7937e954..9837ef05680cf 100644 --- a/Mathlib/CategoryTheory/Triangulated/Functor.lean +++ b/Mathlib/CategoryTheory/Triangulated/Functor.lean @@ -71,11 +71,6 @@ section Additive variable [Preadditive C] [Preadditive D] [F.Additive] -#adaptation_note -/-- -At nightly-2024-08-08 we needed to increase the maxHeartbeats here. --/ -set_option maxHeartbeats 400000 in /-- The functor `F.mapTriangle` commutes with the shift. -/ noncomputable def mapTriangleCommShiftIso (n : ℤ) : Triangle.shiftFunctor C n ⋙ F.mapTriangle ≅ F.mapTriangle ⋙ Triangle.shiftFunctor D n := diff --git a/Mathlib/CategoryTheory/Triangulated/Opposite.lean b/Mathlib/CategoryTheory/Triangulated/Opposite.lean index 4de06f2ff9fb9..9e34b1cc2e37f 100644 --- a/Mathlib/CategoryTheory/Triangulated/Opposite.lean +++ b/Mathlib/CategoryTheory/Triangulated/Opposite.lean @@ -105,7 +105,7 @@ lemma shiftFunctorAdd'_op_hom_app (X : Cᵒᵖ) (a₁ a₂ a₃ : ℤ) (h : a₁ (shiftFunctor Cᵒᵖ a₂).map ((shiftFunctorOpIso C _ _ h₁).inv.app X) := by erw [@pullbackShiftFunctorAdd'_hom_app (OppositeShift C ℤ) _ _ _ _ _ _ _ X a₁ a₂ a₃ h b₁ b₂ b₃ (by dsimp; omega) (by dsimp; omega) (by dsimp; omega)] - erw [oppositeShiftFunctorAdd'_hom_app] + rw [oppositeShiftFunctorAdd'_hom_app] obtain rfl : b₁ = -a₁ := by omega obtain rfl : b₂ = -a₂ := by omega obtain rfl : b₃ = -a₃ := by omega @@ -130,8 +130,7 @@ lemma shiftFunctor_op_map (n m : ℤ) (hnm : n + m = 0) {K L : Cᵒᵖ} (φ : K (shiftFunctorOpIso C n m hnm).inv.app L := (NatIso.naturality_2 (shiftFunctorOpIso C n m hnm) φ).symm -variable (C) - +variable (C) in /-- The autoequivalence `Cᵒᵖ ≌ Cᵒᵖ` whose functor is `shiftFunctor Cᵒᵖ n` and whose inverse functor is `(shiftFunctor C n).op`. Do not unfold the definitions of the unit and counit isomorphisms: the compatibilities they satisfy are stated as separate lemmas. -/ @@ -177,7 +176,57 @@ lemma opShiftFunctorEquivalence_counitIso_inv_naturality (n : ℤ) {X Y : Cᵒ (opShiftFunctorEquivalence C n).counitIso.inv.app X ≫ f.unop⟦n⟧'.op⟦n⟧' := (opShiftFunctorEquivalence C n).counitIso.inv.naturality f -variable {C} +lemma opShiftFunctorEquivalence_zero_unitIso_hom_app (X : Cᵒᵖ) : + (opShiftFunctorEquivalence C 0).unitIso.hom.app X = + ((shiftFunctorZero C ℤ).hom.app X.unop).op ≫ + (((shiftFunctorZero Cᵒᵖ ℤ).inv.app X).unop⟦(0 : ℤ)⟧').op := by + apply Quiver.Hom.unop_inj + dsimp [opShiftFunctorEquivalence] + rw [shiftFunctorZero_op_inv_app, unop_comp, Quiver.Hom.unop_op, Functor.map_comp, + shiftFunctorCompIsoId_zero_zero_hom_app, assoc] + +lemma opShiftFunctorEquivalence_zero_unitIso_inv_app (X : Cᵒᵖ) : + (opShiftFunctorEquivalence C 0).unitIso.inv.app X = + (((shiftFunctorZero Cᵒᵖ ℤ).hom.app X).unop⟦(0 : ℤ)⟧').op ≫ + ((shiftFunctorZero C ℤ).inv.app X.unop).op := by + apply Quiver.Hom.unop_inj + dsimp [opShiftFunctorEquivalence] + rw [shiftFunctorZero_op_hom_app, unop_comp, Quiver.Hom.unop_op, Functor.map_comp, + shiftFunctorCompIsoId_zero_zero_inv_app, assoc] + +lemma opShiftFunctorEquivalence_unitIso_hom_app_eq (X : Cᵒᵖ) (m n p : ℤ) (h : m + n = p) : + (opShiftFunctorEquivalence C p).unitIso.hom.app X = + (opShiftFunctorEquivalence C n).unitIso.hom.app X ≫ + (((opShiftFunctorEquivalence C m).unitIso.hom.app (X⟦n⟧)).unop⟦n⟧').op ≫ + ((shiftFunctorAdd' C m n p h).hom.app _).op ≫ + (((shiftFunctorAdd' Cᵒᵖ n m p (by omega)).inv.app X).unop⟦p⟧').op := by + dsimp [opShiftFunctorEquivalence] + simp only [shiftFunctorAdd'_op_inv_app _ n m p (by omega) _ _ _ (add_neg_cancel n) + (add_neg_cancel m) (add_neg_cancel p), shiftFunctor_op_map _ _ (add_neg_cancel m), + Category.assoc, Iso.inv_hom_id_app_assoc] + erw [Functor.map_id, Functor.map_id, Functor.map_id, Functor.map_id, + id_comp, id_comp, id_comp, comp_id, comp_id] + dsimp + rw [comp_id, shiftFunctorCompIsoId_add'_hom_app _ _ _ _ _ _ + (neg_add_cancel m) (neg_add_cancel n) (neg_add_cancel p) h] + dsimp + rw [Category.assoc, Category.assoc] + rfl + +lemma opShiftFunctorEquivalence_unitIso_inv_app_eq (X : Cᵒᵖ) (m n p : ℤ) (h : m + n = p) : + (opShiftFunctorEquivalence C p).unitIso.inv.app X = + (((shiftFunctorAdd' Cᵒᵖ n m p (by omega)).hom.app X).unop⟦p⟧').op ≫ + ((shiftFunctorAdd' C m n p h).inv.app _).op ≫ + (((opShiftFunctorEquivalence C m).unitIso.inv.app (X⟦n⟧)).unop⟦n⟧').op ≫ + (opShiftFunctorEquivalence C n).unitIso.inv.app X := by + rw [← cancel_mono ((opShiftFunctorEquivalence C p).unitIso.hom.app X), Iso.inv_hom_id_app, + opShiftFunctorEquivalence_unitIso_hom_app_eq _ _ _ _ h, + Category.assoc, Category.assoc, Category.assoc, Iso.inv_hom_id_app_assoc] + apply Quiver.Hom.unop_inj + dsimp + simp only [Category.assoc, ← Functor.map_comp_assoc, Iso.hom_inv_id_app_assoc, + ← unop_comp, Iso.inv_hom_id_app, Functor.comp_obj, Functor.op_obj, unop_id, + Functor.map_id, id_comp, ← Functor.map_comp, Iso.hom_inv_id_app] lemma shift_unop_opShiftFunctorEquivalence_counitIso_inv_app (X : Cᵒᵖ) (n : ℤ) : ((opShiftFunctorEquivalence C n).counitIso.inv.app X).unop⟦n⟧' = diff --git a/Mathlib/CategoryTheory/Triangulated/Pretriangulated.lean b/Mathlib/CategoryTheory/Triangulated/Pretriangulated.lean index 091de90c8c3c1..c3b954b379632 100644 --- a/Mathlib/CategoryTheory/Triangulated/Pretriangulated.lean +++ b/Mathlib/CategoryTheory/Triangulated/Pretriangulated.lean @@ -563,7 +563,7 @@ lemma productTriangle_distinguished {J : Type*} (T : J → Triangle C) `φ'.hom₁` and `φ'.hom₂` are identities. Then, it suffices to show that `φ'.hom₃` is an isomorphism, which is achieved by using Yoneda's lemma and diagram chases. -/ - let f₁ := Pi.map (fun j => (T j).mor₁) + let f₁ := Limits.Pi.map (fun j => (T j).mor₁) obtain ⟨Z, f₂, f₃, hT'⟩ := distinguished_cocone_triangle f₁ let T' := Triangle.mk f₁ f₂ f₃ change T' ∈ distTriang C at hT' diff --git a/Mathlib/CategoryTheory/Triangulated/Yoneda.lean b/Mathlib/CategoryTheory/Triangulated/Yoneda.lean index 39ec3c60ebdb1..e136effd690d8 100644 --- a/Mathlib/CategoryTheory/Triangulated/Yoneda.lean +++ b/Mathlib/CategoryTheory/Triangulated/Yoneda.lean @@ -5,6 +5,7 @@ Authors: Joël Riou -/ import Mathlib.Algebra.Homology.ShortComplex.Ab import Mathlib.CategoryTheory.Preadditive.Yoneda.Basic +import Mathlib.CategoryTheory.Shift.ShiftedHomOpposite import Mathlib.CategoryTheory.Triangulated.HomologicalFunctor import Mathlib.CategoryTheory.Triangulated.Opposite @@ -23,7 +24,7 @@ variable {C : Type*} [Category C] [Preadditive C] [HasShift C ℤ] namespace CategoryTheory -open Limits Pretriangulated.Opposite +open Limits Opposite Pretriangulated.Opposite namespace Pretriangulated @@ -62,6 +63,43 @@ lemma preadditiveCoyoneda_homologySequenceδ_apply x ≫ T.mor₃⟦n₀⟧' ≫ (shiftFunctorAdd' C 1 n₀ n₁ (by omega)).inv.app _ := by apply Category.assoc +section + +variable [∀ (n : ℤ), (shiftFunctor C n).Additive] + +noncomputable instance (B : C) : (preadditiveYoneda.obj B).ShiftSequence ℤ where + sequence n := preadditiveYoneda.obj (B⟦n⟧) + isoZero := preadditiveYoneda.mapIso ((shiftFunctorZero C ℤ).app B) + shiftIso n a a' h := NatIso.ofComponents (fun A ↦ AddEquiv.toAddCommGrpIso + { toEquiv := Quiver.Hom.opEquiv.trans (ShiftedHom.opEquiv' n a a' h).symm + map_add' := fun _ _ ↦ ShiftedHom.opEquiv'_symm_add _ _ _ h }) + (by intros; ext; apply ShiftedHom.opEquiv'_symm_comp _ _ _ h) + shiftIso_zero a := by ext; apply ShiftedHom.opEquiv'_zero_add_symm + shiftIso_add n m a a' a'' ha' ha'' := by + ext _ x + exact ShiftedHom.opEquiv'_add_symm n m a a' a'' ha' ha'' x.op + +lemma preadditiveYoneda_shiftMap_apply (B : C) {X Y : Cᵒᵖ} (n : ℤ) (f : X ⟶ Y⟦n⟧) + (a a' : ℤ) (h : n + a = a') (z : X.unop ⟶ B⟦a⟧) : + (preadditiveYoneda.obj B).shiftMap f a a' h z = + ((ShiftedHom.opEquiv _).symm f).comp z (show a + n = a' by omega) := by + symm + apply ShiftedHom.opEquiv_symm_apply_comp + +lemma preadditiveYoneda_homologySequenceδ_apply + (T : Triangle C) (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) {B : C} (x : T.obj₁ ⟶ B⟦n₀⟧) : + (preadditiveYoneda.obj B).homologySequenceδ + ((triangleOpEquivalence _).functor.obj (op T)) n₀ n₁ h x = + T.mor₃ ≫ x⟦(1 : ℤ)⟧' ≫ (shiftFunctorAdd' C n₀ 1 n₁ h).inv.app B := by + simp only [Functor.homologySequenceδ, preadditiveYoneda_shiftMap_apply, + ShiftedHom.comp, ← Category.assoc] + congr 2 + apply (ShiftedHom.opEquiv _).injective + rw [Equiv.apply_symm_apply] + rfl + +end + end Pretriangulated end CategoryTheory diff --git a/Mathlib/CategoryTheory/Types.lean b/Mathlib/CategoryTheory/Types.lean index b2b29e06f39d9..01484dc45c6dc 100644 --- a/Mathlib/CategoryTheory/Types.lean +++ b/Mathlib/CategoryTheory/Types.lean @@ -41,7 +41,7 @@ universe v v' w u u' @[to_additive existing CategoryTheory.types] instance types : LargeCategory (Type u) where Hom a b := a → b - id a := id + id _ := id comp f g := g ∘ f theorem types_hom {α β : Type u} : (α ⟶ β) = (α → β) := @@ -117,7 +117,7 @@ lemma sections_property {F : J ⥤ Type w} (s : (F.sections : Type _)) s.property f lemma sections_ext_iff {F : J ⥤ Type w} {x y : F.sections} : x = y ↔ ∀ j, x.val j = y.val j := - Subtype.ext_iff.trans Function.funext_iff + Subtype.ext_iff.trans funext_iff variable (J) @@ -191,7 +191,7 @@ Write this as `uliftFunctor.{5, 2}` to get `Type 2 ⥤ Type 5`. @[pp_with_univ] def uliftFunctor : Type u ⥤ Type max u v where obj X := ULift.{v} X - map {X} {Y} f := fun x : ULift.{v} X => ULift.up (f x.down) + map {X} {_} f := fun x : ULift.{v} X => ULift.up (f x.down) @[simp] theorem uliftFunctor_obj {X : Type u} : uliftFunctor.obj.{v} X = ULift.{v} X := @@ -264,7 +264,7 @@ def ofTypeFunctor (m : Type u → Type v) [_root_.Functor m] [LawfulFunctor m] : map_id := fun α => by funext X; apply id_map /- Porting note: original proof is via `fun α => _root_.Functor.map_id` but I cannot get Lean to find this. Reproduced its original proof -/ - map_comp f g := funext fun a => LawfulFunctor.comp_map f g _ + map_comp f g := funext fun _ => LawfulFunctor.comp_map f g _ variable (m : Type u → Type v) [_root_.Functor m] [LawfulFunctor m] diff --git a/Mathlib/CategoryTheory/Widesubcategory.lean b/Mathlib/CategoryTheory/Widesubcategory.lean index e225caffbde77..ae12360cb74f5 100644 --- a/Mathlib/CategoryTheory/Widesubcategory.lean +++ b/Mathlib/CategoryTheory/Widesubcategory.lean @@ -55,13 +55,13 @@ instance InducedWideCategory.category : Category (InducedWideCategory D F P) where Hom X Y := {f : F X ⟶ F Y | P f} id X := ⟨𝟙 (F X), P.id_mem (F X)⟩ - comp {X Y Z} f g := ⟨f.1 ≫ g.1, P.comp_mem _ _ f.2 g.2⟩ + comp {_ _ _} f g := ⟨f.1 ≫ g.1, P.comp_mem _ _ f.2 g.2⟩ /-- The forgetful functor from an induced wide category to the original category. -/ @[simps] def wideInducedFunctor : InducedWideCategory D F P ⥤ D where obj := F - map {X Y} f := f.1 + map {_ _} f := f.1 /-- The induced functor `wideInducedFunctor F P : InducedWideCategory D F P ⥤ D` is faithful. -/ diff --git a/Mathlib/CategoryTheory/WithTerminal.lean b/Mathlib/CategoryTheory/WithTerminal.lean index 3c35d0efb590e..0b00c0e2f5d8f 100644 --- a/Mathlib/CategoryTheory/WithTerminal.lean +++ b/Mathlib/CategoryTheory/WithTerminal.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Tooby-Smith, Adam Topaz -/ -import Mathlib.CategoryTheory.Limits.Shapes.Terminal +import Mathlib.CategoryTheory.Limits.Shapes.IsTerminal import Mathlib.CategoryTheory.Bicategory.Functor.Pseudofunctor /-! @@ -91,7 +91,7 @@ attribute [nolint simpNF] comp.eq_4 instance : Category.{v} (WithTerminal C) where Hom X Y := Hom X Y - id X := id _ + id _ := id _ comp := comp assoc {a b c d} f g h := by -- Porting note: it would be nice to automate this away as well. @@ -133,7 +133,7 @@ def map {D : Type*} [Category D] (F : C ⥤ D) : WithTerminal C ⥤ WithTerminal | star => star map {X Y} f := match X, Y, f with - | of x, of y, f => F.map (down f) + | of _, of _, f => F.map (down f) | of _, star, _ => PUnit.unit | star, star, _ => PUnit.unit @@ -141,7 +141,7 @@ def map {D : Type*} [Category D] (F : C ⥤ D) : WithTerminal C ⥤ WithTerminal @[simps!] def mapId (C : Type*) [Category C] : map (𝟭 C) ≅ 𝟭 (WithTerminal C) := NatIso.ofComponents (fun X => match X with - | of x => Iso.refl _ + | of _ => Iso.refl _ | star => Iso.refl _) (by aesop_cat) /-- A natural isomorphism between the functor `map (F ⋙ G) ` and `map F ⋙ map G `. -/ @@ -149,7 +149,7 @@ def mapId (C : Type*) [Category C] : map (𝟭 C) ≅ 𝟭 (WithTerminal C) := def mapComp {D E : Type*} [Category D] [Category E] (F : C ⥤ D) (G : D ⥤ E) : map (F ⋙ G) ≅ map F ⋙ map G := NatIso.ofComponents (fun X => match X with - | of x => Iso.refl _ + | of _ => Iso.refl _ | star => Iso.refl _) (by aesop_cat) /-- From a natural transformation of functors `C ⥤ D`, the induced natural transformation @@ -285,7 +285,7 @@ def lift {D : Type*} [Category D] {Z : D} (F : C ⥤ D) (M : ∀ x : C, F.obj x | star => Z map {X Y} f := match X, Y, f with - | of x, of y, f => F.map (down f) + | of _, of _, f => F.map (down f) | of x, star, _ => M x | star, star, _ => 𝟙 Z @@ -293,8 +293,8 @@ def lift {D : Type*} [Category D] {Z : D} (F : C ⥤ D) (M : ∀ x : C, F.obj x @[simps!] def inclLift {D : Type*} [Category D] {Z : D} (F : C ⥤ D) (M : ∀ x : C, F.obj x ⟶ Z) (hM : ∀ (x y : C) (f : x ⟶ y), F.map f ≫ M y = M x) : incl ⋙ lift F M hM ≅ F where - hom := { app := fun X => 𝟙 _ } - inv := { app := fun X => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } /-- The isomorphism between `(lift F _ _).obj WithTerminal.star` with `Z`. -/ @[simps!] @@ -435,7 +435,7 @@ def map {D : Type*} [Category D] (F : C ⥤ D) : WithInitial C ⥤ WithInitial D | star => star map {X Y} f := match X, Y, f with - | of x, of y, f => F.map (down f) + | of _, of _, f => F.map (down f) | star, of _, _ => PUnit.unit | star, star, _ => PUnit.unit @@ -443,7 +443,7 @@ def map {D : Type*} [Category D] (F : C ⥤ D) : WithInitial C ⥤ WithInitial D @[simps!] def mapId (C : Type*) [Category C] : map (𝟭 C) ≅ 𝟭 (WithInitial C) := NatIso.ofComponents (fun X => match X with - | of x => Iso.refl _ + | of _ => Iso.refl _ | star => Iso.refl _) (by aesop_cat) /-- A natural isomorphism between the functor `map (F ⋙ G) ` and `map F ⋙ map G `. -/ @@ -451,7 +451,7 @@ def mapId (C : Type*) [Category C] : map (𝟭 C) ≅ 𝟭 (WithInitial C) := def mapComp {D E : Type*} [Category D] [Category E] (F : C ⥤ D) (G : D ⥤ E) : map (F ⋙ G) ≅ map F ⋙ map G := NatIso.ofComponents (fun X => match X with - | of x => Iso.refl _ + | of _ => Iso.refl _ | star => Iso.refl _) (by aesop_cat) /-- From a natural transformation of functors `C ⥤ D`, the induced natural transformation @@ -583,16 +583,16 @@ def lift {D : Type*} [Category D] {Z : D} (F : C ⥤ D) (M : ∀ x : C, Z ⟶ F. | star => Z map {X Y} f := match X, Y, f with - | of x, of y, f => F.map (down f) - | star, of x, _ => M _ + | of _, of _, f => F.map (down f) + | star, of _, _ => M _ | star, star, _ => 𝟙 _ /-- The isomorphism between `incl ⋙ lift F _ _` with `F`. -/ @[simps!] def inclLift {D : Type*} [Category D] {Z : D} (F : C ⥤ D) (M : ∀ x : C, Z ⟶ F.obj x) (hM : ∀ (x y : C) (f : x ⟶ y), M x ≫ F.map f = M y) : incl ⋙ lift F M hM ≅ F where - hom := { app := fun X => 𝟙 _ } - inv := { app := fun X => 𝟙 _ } + hom := { app := fun _ => 𝟙 _ } + inv := { app := fun _ => 𝟙 _ } /-- The isomorphism between `(lift F _ _).obj WithInitial.star` with `Z`. -/ @[simps!] diff --git a/Mathlib/CategoryTheory/Yoneda.lean b/Mathlib/CategoryTheory/Yoneda.lean index f06afc7170c1c..6f87fb13988bf 100644 --- a/Mathlib/CategoryTheory/Yoneda.lean +++ b/Mathlib/CategoryTheory/Yoneda.lean @@ -24,7 +24,7 @@ namespace CategoryTheory open Opposite -universe v v₁ u₁ u₂ +universe v v₁ v₂ u₁ u₂ -- morphism levels before object levels. See note [CategoryTheory universes]. variable {C : Type u₁} [Category.{v₁} C] @@ -39,7 +39,7 @@ def yoneda : C ⥤ Cᵒᵖ ⥤ Type v₁ where { obj := fun Y => unop Y ⟶ X map := fun f g => f.unop ≫ g } map f := - { app := fun Y g => g ≫ f } + { app := fun _ g => g ≫ f } /-- The co-Yoneda embedding, as a functor from `Cᵒᵖ` into co-presheaves on `C`. -/ @@ -49,7 +49,7 @@ def coyoneda : Cᵒᵖ ⥤ C ⥤ Type v₁ where { obj := fun Y => unop X ⟶ Y map := fun f g => g ≫ f } map f := - { app := fun Y g => f.unop ≫ g } + { app := fun _ g => f.unop ≫ g } namespace Yoneda @@ -399,7 +399,7 @@ and elements of `F.obj X`, without any universe switching. -/ def yonedaEquiv {X : C} {F : Cᵒᵖ ⥤ Type v₁} : (yoneda.obj X ⟶ F) ≃ F.obj (op X) where toFun η := η.app (op X) (𝟙 X) - invFun ξ := { app := fun Y f ↦ F.map f.op ξ } + invFun ξ := { app := fun _ f ↦ F.map f.op ξ } left_inv := by intro η ext Y f @@ -486,8 +486,6 @@ to `yoneda.op.obj X ⟶ F`, functorially in both `X` and `F`. def yonedaPairing : Cᵒᵖ × (Cᵒᵖ ⥤ Type v₁) ⥤ Type max u₁ v₁ := Functor.prod yoneda.op (𝟭 (Cᵒᵖ ⥤ Type v₁)) ⋙ Functor.hom (Cᵒᵖ ⥤ Type v₁) --- Porting note (#5229): we need to provide this `@[ext]` lemma separately, --- as `ext` will not look through the definition. @[ext] lemma yonedaPairingExt {X : Cᵒᵖ × (Cᵒᵖ ⥤ Type v₁)} {x y : (yonedaPairing C).obj X} (w : ∀ Y, x.app Y = y.app Y) : x = y := @@ -506,7 +504,7 @@ def yonedaCompUliftFunctorEquiv (F : Cᵒᵖ ⥤ Type max v₁ w) (X : C) : (yoneda.obj X ⋙ uliftFunctor ⟶ F) ≃ F.obj (op X) where toFun φ := φ.app (op X) (ULift.up (𝟙 _)) invFun f := - { app := fun Y x => F.map (ULift.down x).op f } + { app := fun _ x => F.map (ULift.down x).op f } left_inv φ := by ext Y f dsimp @@ -524,7 +522,7 @@ See . -/ def yonedaLemma : yonedaPairing C ≅ yonedaEvaluation C := NatIso.ofComponents - (fun X ↦ Equiv.toIso (yonedaEquiv.trans Equiv.ulift.symm)) + (fun _ ↦ Equiv.toIso (yonedaEquiv.trans Equiv.ulift.symm)) (by intro (X, F) (Y, G) f ext (a : yoneda.obj X.unop ⟶ F) apply ULift.ext @@ -539,7 +537,7 @@ variable {C} /-- The curried version of yoneda lemma when `C` is small. -/ def curriedYonedaLemma {C : Type u₁} [SmallCategory C] : (yoneda.op ⋙ coyoneda : Cᵒᵖ ⥤ (Cᵒᵖ ⥤ Type u₁) ⥤ Type u₁) ≅ evaluation Cᵒᵖ (Type u₁) := - NatIso.ofComponents (fun X ↦ NatIso.ofComponents (fun F ↦ Equiv.toIso yonedaEquiv)) (by + NatIso.ofComponents (fun X ↦ NatIso.ofComponents (fun _ ↦ Equiv.toIso yonedaEquiv)) (by intro X Y f ext a b dsimp [yonedaEquiv] @@ -551,7 +549,7 @@ def largeCurriedYonedaLemma {C : Type u₁} [Category.{v₁} C] : evaluation Cᵒᵖ (Type v₁) ⋙ (whiskeringRight _ _ _).obj uliftFunctor.{u₁} := NatIso.ofComponents (fun X => NatIso.ofComponents - (fun Y => Equiv.toIso <| yonedaEquiv.trans Equiv.ulift.symm) + (fun _ => Equiv.toIso <| yonedaEquiv.trans Equiv.ulift.symm) (by intros Y Z f ext g @@ -572,7 +570,7 @@ def yonedaOpCompYonedaObj {C : Type u₁} [Category.{v₁} C] (P : Cᵒᵖ ⥤ T def curriedYonedaLemma' {C : Type u₁} [SmallCategory C] : yoneda ⋙ (whiskeringLeft Cᵒᵖ (Cᵒᵖ ⥤ Type u₁)ᵒᵖ (Type u₁)).obj yoneda.op ≅ 𝟭 (Cᵒᵖ ⥤ Type u₁) := - NatIso.ofComponents (fun F ↦ NatIso.ofComponents (fun X ↦ Equiv.toIso yonedaEquiv) (by + NatIso.ofComponents (fun F ↦ NatIso.ofComponents (fun _ ↦ Equiv.toIso yonedaEquiv) (by intro X Y f ext a dsimp [yonedaEquiv] @@ -584,6 +582,19 @@ lemma isIso_of_yoneda_map_bijective {X Y : C} (f : X ⟶ Y) obtain ⟨g, hg : g ≫ f = 𝟙 Y⟩ := (hf Y).2 (𝟙 Y) exact ⟨g, (hf _).1 (by aesop_cat), hg⟩ +lemma isIso_iff_yoneda_map_bijective {X Y : C} (f : X ⟶ Y) : + IsIso f ↔ (∀ (T : C), Function.Bijective (fun (x : T ⟶ X) => x ≫ f)) := by + refine ⟨fun _ ↦ ?_, fun hf ↦ isIso_of_yoneda_map_bijective f hf⟩ + have : IsIso (yoneda.map f) := inferInstance + intro T + rw [← isIso_iff_bijective] + exact inferInstanceAs (IsIso ((yoneda.map f).app _)) + +lemma isIso_iff_isIso_yoneda_map {X Y : C} (f : X ⟶ Y) : + IsIso f ↔ ∀ c : C, IsIso ((yoneda.map f).app ⟨c⟩) := by + rw [isIso_iff_yoneda_map_bijective] + exact forall_congr' fun _ ↦ (isIso_iff_bijective _).symm + end YonedaLemma section CoyonedaLemma @@ -595,7 +606,7 @@ and elements of `F.obj X.unop`, without any universe switching. -/ def coyonedaEquiv {X : C} {F : C ⥤ Type v₁} : (coyoneda.obj (op X) ⟶ F) ≃ F.obj X where toFun η := η.app X (𝟙 X) - invFun ξ := { app := fun Y x ↦ F.map x ξ } + invFun ξ := { app := fun _ x ↦ F.map x ξ } left_inv := fun η ↦ by ext Y (x : X ⟶ Y) dsimp @@ -657,8 +668,6 @@ to `coyoneda.rightOp.obj X ⟶ F`, functorially in both `X` and `F`. def coyonedaPairing : C × (C ⥤ Type v₁) ⥤ Type max u₁ v₁ := Functor.prod coyoneda.rightOp (𝟭 (C ⥤ Type v₁)) ⋙ Functor.hom (C ⥤ Type v₁) --- Porting note (#5229): we need to provide this `@[ext]` lemma separately, --- as `ext` will not look through the definition. @[ext] lemma coyonedaPairingExt {X : C × (C ⥤ Type v₁)} {x y : (coyonedaPairing C).obj X} (w : ∀ Y, x.app Y = y.app Y) : x = y := @@ -677,7 +686,7 @@ def coyonedaCompUliftFunctorEquiv (F : C ⥤ Type max v₁ w) (X : Cᵒᵖ) : (coyoneda.obj X ⋙ uliftFunctor ⟶ F) ≃ F.obj X.unop where toFun φ := φ.app X.unop (ULift.up (𝟙 _)) invFun f := - { app := fun Y x => F.map (ULift.down x) f } + { app := fun _ x => F.map (ULift.down x) f } left_inv φ := by ext Y f dsimp @@ -695,7 +704,7 @@ See . -/ def coyonedaLemma : coyonedaPairing C ≅ coyonedaEvaluation C := NatIso.ofComponents - (fun X ↦ Equiv.toIso (coyonedaEquiv.trans Equiv.ulift.symm)) + (fun _ ↦ Equiv.toIso (coyonedaEquiv.trans Equiv.ulift.symm)) (by intro (X, F) (Y, G) f ext (a : coyoneda.obj (op X) ⟶ F) apply ULift.ext @@ -709,7 +718,7 @@ variable {C} /-- The curried version of coyoneda lemma when `C` is small. -/ def curriedCoyonedaLemma {C : Type u₁} [SmallCategory C] : coyoneda.rightOp ⋙ coyoneda ≅ evaluation C (Type u₁) := - NatIso.ofComponents (fun X ↦ NatIso.ofComponents (fun F ↦ Equiv.toIso coyonedaEquiv)) (by + NatIso.ofComponents (fun X ↦ NatIso.ofComponents (fun _ ↦ Equiv.toIso coyonedaEquiv)) (by intro X Y f ext a b simp [coyonedaEquiv, ← FunctorToTypes.naturality]) @@ -720,7 +729,7 @@ def largeCurriedCoyonedaLemma {C : Type u₁} [Category.{v₁} C] : evaluation C (Type v₁) ⋙ (whiskeringRight _ _ _).obj uliftFunctor.{u₁} := NatIso.ofComponents (fun X => NatIso.ofComponents - (fun Y => Equiv.toIso <| coyonedaEquiv.trans Equiv.ulift.symm) + (fun _ => Equiv.toIso <| coyonedaEquiv.trans Equiv.ulift.symm) (by intros Y Z f ext g @@ -741,7 +750,7 @@ def coyonedaCompYonedaObj {C : Type u₁} [Category.{v₁} C] (P : C ⥤ Type v def curriedCoyonedaLemma' {C : Type u₁} [SmallCategory C] : yoneda ⋙ (whiskeringLeft C (C ⥤ Type u₁)ᵒᵖ (Type u₁)).obj coyoneda.rightOp ≅ 𝟭 (C ⥤ Type u₁) := - NatIso.ofComponents (fun F ↦ NatIso.ofComponents (fun X ↦ Equiv.toIso coyonedaEquiv) (by + NatIso.ofComponents (fun F ↦ NatIso.ofComponents (fun _ ↦ Equiv.toIso coyonedaEquiv) (by intro X Y f ext a simp [coyonedaEquiv, ← FunctorToTypes.naturality])) @@ -753,6 +762,19 @@ lemma isIso_of_coyoneda_map_bijective {X Y : C} (f : X ⟶ Y) refine ⟨g, hg, (hf _).1 ?_⟩ simp only [Category.comp_id, ← Category.assoc, hg, Category.id_comp] +lemma isIso_iff_coyoneda_map_bijective {X Y : C} (f : X ⟶ Y) : + IsIso f ↔ (∀ (T : C), Function.Bijective (fun (x : Y ⟶ T) => f ≫ x)) := by + refine ⟨fun _ ↦ ?_, fun hf ↦ isIso_of_coyoneda_map_bijective f hf⟩ + have : IsIso (coyoneda.map f.op) := inferInstance + intro T + rw [← isIso_iff_bijective] + exact inferInstanceAs (IsIso ((coyoneda.map f.op).app _)) + +lemma isIso_iff_isIso_coyoneda_map {X Y : C} (f : X ⟶ Y) : + IsIso f ↔ ∀ c : C, IsIso ((coyoneda.map f.op).app c) := by + rw [isIso_iff_coyoneda_map_bijective] + exact forall_congr' fun _ ↦ (isIso_iff_bijective _).symm + end CoyonedaLemma section @@ -763,7 +785,7 @@ variable {D : Type*} [Category.{v₁} D] (F : C ⥤ D) /-- The natural transformation `yoneda.obj X ⟶ F.op ⋙ yoneda.obj (F.obj X)` when `F : C ⥤ D` and `X : C`. -/ def yonedaMap (X : C) : yoneda.obj X ⟶ F.op ⋙ yoneda.obj (F.obj X) where - app X f := F.map f + app _ f := F.map f @[simp] lemma yonedaMap_app_apply {Y : C} {X : Cᵒᵖ} (f : X.unop ⟶ Y) : @@ -771,4 +793,24 @@ lemma yonedaMap_app_apply {Y : C} {X : Cᵒᵖ} (f : X.unop ⟶ Y) : end +namespace Functor.FullyFaithful + +variable {C : Type u₁} [Category.{v₁} C] + +/-- `FullyFaithful.homEquiv` as a natural isomorphism. -/ +def homNatIso {D : Type u₂} [Category.{v₂} D] {F : C ⥤ D} (hF : F.FullyFaithful) (X : C) : + F.op ⋙ yoneda.obj (F.obj X) ⋙ uliftFunctor.{v₁} ≅ yoneda.obj X ⋙ uliftFunctor.{v₂} := + NatIso.ofComponents + (fun Y => Equiv.toIso (Equiv.ulift.trans <| hF.homEquiv.symm.trans Equiv.ulift.symm)) + (fun f => by ext; exact Equiv.ulift.injective (hF.map_injective (by simp))) + +/-- `FullyFaithful.homEquiv` as a natural isomorphism. -/ +def homNatIsoMaxRight {D : Type u₂} [Category.{max v₁ v₂} D] {F : C ⥤ D} (hF : F.FullyFaithful) + (X : C) : F.op ⋙ yoneda.obj (F.obj X) ≅ yoneda.obj X ⋙ uliftFunctor.{v₂} := + NatIso.ofComponents + (fun Y => Equiv.toIso (hF.homEquiv.symm.trans Equiv.ulift.symm)) + (fun f => by ext; exact Equiv.ulift.injective (hF.map_injective (by simp))) + +end Functor.FullyFaithful + end CategoryTheory diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean index 076f7c450bcde..b0e0d2360ce16 100644 --- a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean @@ -92,17 +92,16 @@ def box (n d : ℕ) : Finset (Fin n → ℕ) := theorem mem_box : x ∈ box n d ↔ ∀ i, x i < d := by simp only [box, Fintype.mem_piFinset, mem_range] @[simp] -theorem card_box : (box n d).card = d ^ n := by simp [box] +theorem card_box : #(box n d) = d ^ n := by simp [box] @[simp] theorem box_zero : box (n + 1) 0 = ∅ := by simp [box] /-- The intersection of the sphere of radius `√k` with the integer points in the positive quadrant. -/ -def sphere (n d k : ℕ) : Finset (Fin n → ℕ) := - (box n d).filter fun x => ∑ i, x i ^ 2 = k +def sphere (n d k : ℕ) : Finset (Fin n → ℕ) := {x ∈ box n d | ∑ i, x i ^ 2 = k} -theorem sphere_zero_subset : sphere n d 0 ⊆ 0 := fun x => by simp [sphere, Function.funext_iff] +theorem sphere_zero_subset : sphere n d 0 ⊆ 0 := fun x => by simp [sphere, funext_iff] @[simp] theorem sphere_zero_right (n k : ℕ) : sphere (n + 1) 0 k = ∅ := by simp [sphere] @@ -128,7 +127,6 @@ def map (d : ℕ) : (Fin n → ℕ) →+ ℕ where map_zero' := by simp_rw [Pi.zero_apply, zero_mul, sum_const_zero] map_add' a b := by simp_rw [Pi.add_apply, add_mul, sum_add_distrib] --- @[simp] -- Porting note (#10618): simp can prove this theorem map_zero (d : ℕ) (a : Fin 0 → ℕ) : map d a = 0 := by simp [map] theorem map_succ (a : Fin (n + 1) → ℕ) : @@ -204,7 +202,7 @@ theorem sum_lt : (∑ i : Fin n, d * (2 * d + 1) ^ (i : ℕ)) < (2 * d + 1) ^ n sum_eq.trans_lt <| (Nat.div_le_self _ 2).trans_lt <| pred_lt (pow_pos (succ_pos _) _).ne' theorem card_sphere_le_rothNumberNat (n d k : ℕ) : - (sphere n d k).card ≤ rothNumberNat ((2 * d - 1) ^ n) := by + #(sphere n d k) ≤ rothNumberNat ((2 * d - 1) ^ n) := by cases n · dsimp; refine (card_le_univ _).trans_eq ?_; rfl cases d @@ -229,7 +227,7 @@ that we then optimize by tweaking the parameters. The (almost) optimal parameter theorem exists_large_sphere_aux (n d : ℕ) : ∃ k ∈ range (n * (d - 1) ^ 2 + 1), - (↑(d ^ n) / ((n * (d - 1) ^ 2 :) + 1) : ℝ) ≤ (sphere n d k).card := by + (↑(d ^ n) / ((n * (d - 1) ^ 2 :) + 1) : ℝ) ≤ #(sphere n d k) := by refine exists_le_card_fiber_of_nsmul_le_card_of_maps_to (fun x hx => ?_) nonempty_range_succ ?_ · rw [mem_range, Nat.lt_succ_iff] exact sum_sq_le_of_mem_box hx @@ -238,7 +236,7 @@ theorem exists_large_sphere_aux (n d : ℕ) : ∃ k ∈ range (n * (d - 1) ^ 2 + exact (cast_add_one_pos _).ne' theorem exists_large_sphere (n d : ℕ) : - ∃ k, ((d ^ n :) / (n * d ^ 2 :) : ℝ) ≤ (sphere n d k).card := by + ∃ k, ((d ^ n :) / (n * d ^ 2 :) : ℝ) ≤ #(sphere n d k) := by obtain ⟨k, -, hk⟩ := exists_large_sphere_aux n d refine ⟨k, ?_⟩ obtain rfl | hn := n.eq_zero_or_pos diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean b/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean index 213220d6ea296..f374375f2d4a6 100644 --- a/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean +++ b/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean @@ -253,31 +253,31 @@ subset. The usual Roth number corresponds to `addRothNumber (Finset.range n)`, see `rothNumberNat`."] def mulRothNumber : Finset α →o ℕ := - ⟨fun s ↦ Nat.findGreatest (fun m ↦ ∃ t ⊆ s, t.card = m ∧ ThreeGPFree (t : Set α)) s.card, by + ⟨fun s ↦ Nat.findGreatest (fun m ↦ ∃ t ⊆ s, #t = m ∧ ThreeGPFree (t : Set α)) #s, by rintro t u htu refine Nat.findGreatest_mono (fun m => ?_) (card_le_card htu) rintro ⟨v, hvt, hv⟩ exact ⟨v, hvt.trans htu, hv⟩⟩ @[to_additive] -theorem mulRothNumber_le : mulRothNumber s ≤ s.card := Nat.findGreatest_le s.card +theorem mulRothNumber_le : mulRothNumber s ≤ #s := Nat.findGreatest_le #s @[to_additive] theorem mulRothNumber_spec : - ∃ t ⊆ s, t.card = mulRothNumber s ∧ ThreeGPFree (t : Set α) := - Nat.findGreatest_spec (P := fun m ↦ ∃ t ⊆ s, t.card = m ∧ ThreeGPFree (t : Set α)) + ∃ t ⊆ s, #t = mulRothNumber s ∧ ThreeGPFree (t : Set α) := + Nat.findGreatest_spec (P := fun m ↦ ∃ t ⊆ s, #t = m ∧ ThreeGPFree (t : Set α)) (Nat.zero_le _) ⟨∅, empty_subset _, card_empty, by norm_cast; exact threeGPFree_empty⟩ variable {s t} {n : ℕ} @[to_additive] theorem ThreeGPFree.le_mulRothNumber (hs : ThreeGPFree (s : Set α)) (h : s ⊆ t) : - s.card ≤ mulRothNumber t := + #s ≤ mulRothNumber t := Nat.le_findGreatest (card_le_card h) ⟨s, h, rfl, hs⟩ @[to_additive] theorem ThreeGPFree.mulRothNumber_eq (hs : ThreeGPFree (s : Set α)) : - mulRothNumber s = s.card := + mulRothNumber s = #s := (mulRothNumber_le _).antisymm <| hs.le_mulRothNumber <| Subset.refl _ @[to_additive (attr := simp)] @@ -295,9 +295,9 @@ theorem mulRothNumber_union_le (s t : Finset α) : mulRothNumber (s ∪ t) ≤ mulRothNumber s + mulRothNumber t := let ⟨u, hus, hcard, hu⟩ := mulRothNumber_spec (s ∪ t) calc - mulRothNumber (s ∪ t) = u.card := hcard.symm - _ = (u ∩ s ∪ u ∩ t).card := by rw [← inter_union_distrib_left, inter_eq_left.2 hus] - _ ≤ (u ∩ s).card + (u ∩ t).card := card_union_le _ _ + mulRothNumber (s ∪ t) = #u := hcard.symm + _ = #(u ∩ s ∪ u ∩ t) := by rw [← inter_union_distrib_left, inter_eq_left.2 hus] + _ ≤ #(u ∩ s) + #(u ∩ t) := card_union_le _ _ _ ≤ mulRothNumber s + mulRothNumber t := _root_.add_le_add ((hu.mono inter_subset_left).le_mulRothNumber inter_subset_right) ((hu.mono inter_subset_left).le_mulRothNumber inter_subset_right) @@ -407,13 +407,13 @@ theorem rothNumberNat_le (N : ℕ) : rothNumberNat N ≤ N := (addRothNumber_le _).trans (card_range _).le theorem rothNumberNat_spec (n : ℕ) : - ∃ t ⊆ range n, t.card = rothNumberNat n ∧ ThreeAPFree (t : Set ℕ) := + ∃ t ⊆ range n, #t = rothNumberNat n ∧ ThreeAPFree (t : Set ℕ) := addRothNumber_spec _ /-- A verbose specialization of `threeAPFree.le_addRothNumber`, sometimes convenient in practice. -/ theorem ThreeAPFree.le_rothNumberNat (s : Finset ℕ) (hs : ThreeAPFree (s : Set ℕ)) - (hsn : ∀ x ∈ s, x < n) (hsk : s.card = k) : k ≤ rothNumberNat n := + (hsn : ∀ x ∈ s, x < n) (hsk : #s = k) : k ≤ rothNumberNat n := hsk.ge.trans <| hs.le_addRothNumber fun x hx => mem_range.2 <| hsn x hx /-- The Roth number is a subadditive function. Note that by Fekete's lemma this shows that diff --git a/Mathlib/Combinatorics/Additive/Corner/Roth.lean b/Mathlib/Combinatorics/Additive/Corner/Roth.lean index 73840313536fa..a9dd4d09491e6 100644 --- a/Mathlib/Combinatorics/Additive/Corner/Roth.lean +++ b/Mathlib/Combinatorics/Additive/Corner/Roth.lean @@ -23,8 +23,7 @@ open Finset SimpleGraph TripartiteFromTriangles open Function hiding graph open Fintype (card) -variable {G : Type*} [AddCommGroup G] {A B : Finset (G × G)} - {a b c d x y : G} {n : ℕ} {ε : ℝ} +variable {G : Type*} [AddCommGroup G] {A : Finset (G × G)} {a b c : G} {n : ℕ} {ε : ℝ} namespace Corners @@ -40,7 +39,7 @@ private lemma mk_mem_triangleIndices : (a, b, c) ∈ triangleIndices A ↔ (a, b rintro ⟨_, _, h₁, rfl, rfl, h₂⟩ exact ⟨h₁, h₂⟩ -@[simp] private lemma card_triangleIndices : (triangleIndices A).card = A.card := card_map _ +@[simp] private lemma card_triangleIndices : #(triangleIndices A) = #A := card_map _ private instance triangleIndices.instExplicitDisjoint : ExplicitDisjoint (triangleIndices A) := by constructor @@ -55,7 +54,7 @@ private lemma noAccidental (hs : IsCornerFree (A : Set (G × G))) : simp only [mk_mem_triangleIndices] at ha hb hc exact .inl <| hs ⟨hc.1, hb.1, ha.1, hb.2.symm.trans ha.2⟩ -private lemma farFromTriangleFree_graph [Fintype G] [DecidableEq G] (hε : ε * card G ^ 2 ≤ A.card) : +private lemma farFromTriangleFree_graph [Fintype G] [DecidableEq G] (hε : ε * card G ^ 2 ≤ #A) : (graph <| triangleIndices A).FarFromTriangleFree (ε / 9) := by refine farFromTriangleFree _ ?_ simp_rw [card_triangleIndices, mul_comm_div, Nat.cast_pow, Nat.cast_add] @@ -79,7 +78,7 @@ noncomputable def cornersTheoremBound (ε : ℝ) : ℕ := ⌊(triangleRemovalBou The maximum density of a corner-free set in `G × G` goes to zero as `|G|` tends to infinity. -/ theorem corners_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε ≤ card G) - (A : Finset (G × G)) (hAε : ε * card G ^ 2 ≤ A.card) : ¬ IsCornerFree (A : Set (G × G)) := by + (A : Finset (G × G)) (hAε : ε * card G ^ 2 ≤ #A) : ¬ IsCornerFree (A : Set (G × G)) := by rintro hA rw [cornersTheoremBound, Nat.add_one_le_iff] at hG have hε₁ : ε ≤ 1 := by @@ -103,7 +102,7 @@ theorem corners_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε The maximum density of a corner-free set in `{1, ..., n} × {1, ..., n}` goes to zero as `n` tends to infinity. -/ theorem corners_theorem_nat (hε : 0 < ε) (hn : cornersTheoremBound (ε / 9) ≤ n) - (A : Finset (ℕ × ℕ)) (hAn : A ⊆ range n ×ˢ range n) (hAε : ε * n ^ 2 ≤ A.card) : + (A : Finset (ℕ × ℕ)) (hAn : A ⊆ range n ×ˢ range n) (hAε : ε * n ^ 2 ≤ #A) : ¬ IsCornerFree (A : Set (ℕ × ℕ)) := by rintro hA rw [← coe_subset, coe_product] at hAn @@ -128,7 +127,7 @@ theorem corners_theorem_nat (hε : 0 < ε) (hn : cornersTheoremBound (ε / 9) _ = ε / 9 * (2 * n + 1) ^ 2 := by simp _ ≤ ε / 9 * (2 * n + n) ^ 2 := by gcongr; simp; unfold cornersTheoremBound at hn; omega _ = ε * n ^ 2 := by ring - _ ≤ A.card := hAε + _ ≤ #A := hAε _ = _ := by rw [card_image_of_injOn] have : Set.InjOn Nat.cast (range n) := @@ -139,15 +138,15 @@ theorem corners_theorem_nat (hε : 0 < ε) (hn : cornersTheoremBound (ε / 9) The maximum density of a 3AP-free set in `G` goes to zero as `|G|` tends to infinity. -/ theorem roth_3ap_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε ≤ card G) - (A : Finset G) (hAε : ε * card G ≤ A.card) : ¬ ThreeAPFree (A : Set G) := by + (A : Finset G) (hAε : ε * card G ≤ #A) : ¬ ThreeAPFree (A : Set G) := by rintro hA classical let B : Finset (G × G) := univ.filter fun (x, y) ↦ y - x ∈ A - have : ε * card G ^ 2 ≤ B.card := by + have : ε * card G ^ 2 ≤ #B := by calc _ = card G * (ε * card G) := by ring - _ ≤ card G * A.card := by gcongr - _ = B.card := ?_ + _ ≤ card G * #A := by gcongr + _ = #B := ?_ norm_cast rw [← card_univ, ← card_product] exact card_equiv ((Equiv.refl _).prodShear fun a ↦ Equiv.addLeft a) (by simp [B]) @@ -164,7 +163,7 @@ theorem roth_3ap_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε The maximum density of a 3AP-free set in `{1, ..., n}` goes to zero as `n` tends to infinity. -/ theorem roth_3ap_theorem_nat (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound (ε / 3) ≤ n) - (A : Finset ℕ) (hAn : A ⊆ range n) (hAε : ε * n ≤ A.card) : ¬ ThreeAPFree (A : Set ℕ) := by + (A : Finset ℕ) (hAn : A ⊆ range n) (hAε : ε * n ≤ #A) : ¬ ThreeAPFree (A : Set ℕ) := by rintro hA rw [← coe_subset, coe_range] at hAn have : A = Fin.val '' (Nat.cast '' A : Set (Fin (2 * n).succ)) := by @@ -185,7 +184,7 @@ theorem roth_3ap_theorem_nat (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound _ = ε / 3 * (2 * n + 1) := by simp _ ≤ ε / 3 * (2 * n + n) := by gcongr; simp; unfold cornersTheoremBound at hG; omega _ = ε * n := by ring - _ ≤ A.card := hAε + _ ≤ #A := hAε _ = _ := by rw [card_image_of_injOn] exact (CharP.natCast_injOn_Iio (Fin (2 * n).succ) (2 * n).succ).mono <| hAn.trans <| by diff --git a/Mathlib/Combinatorics/Additive/DoublingConst.lean b/Mathlib/Combinatorics/Additive/DoublingConst.lean index f9f65e418d246..6d84686a188f8 100644 --- a/Mathlib/Combinatorics/Additive/DoublingConst.lean +++ b/Mathlib/Combinatorics/Additive/DoublingConst.lean @@ -5,9 +5,6 @@ Authors: Yaël Dillies -/ import Mathlib.Combinatorics.Additive.PluenneckeRuzsa import Mathlib.Data.Finset.Density -import Mathlib.Tactic.Positivity.Basic -import Mathlib.Tactic.Positivity.Finset -import Mathlib.Tactic.Ring /-! # Doubling and difference constants @@ -21,7 +18,6 @@ open scoped Pointwise namespace Finset section Group variable {G G' : Type*} [Group G] [AddGroup G'] [DecidableEq G] [DecidableEq G'] {A B : Finset G} - {a : G} /-- The doubling constant `σₘ[A, B]` of two finsets `A` and `B` in a group is `|A * B| / |A|`. @@ -30,7 +26,7 @@ The notation `σₘ[A, B]` is available in scope `Combinatorics.Additive`. -/ "The doubling constant `σ[A, B]` of two finsets `A` and `B` in a group is `|A + B| / |A|`. The notation `σ[A, B]` is available in scope `Combinatorics.Additive`."] -def mulConst (A B : Finset G) : ℚ≥0 := (A * B).card / A.card +def mulConst (A B : Finset G) : ℚ≥0 := #(A * B) / #A /-- The difference constant `δₘ[A, B]` of two finsets `A` and `B` in a group is `|A / B| / |A|`. @@ -39,7 +35,7 @@ The notation `δₘ[A, B]` is available in scope `Combinatorics.Additive`. -/ "The difference constant `σ[A, B]` of two finsets `A` and `B` in a group is `|A - B| / |A|`. The notation `δ[A, B]` is available in scope `Combinatorics.Additive`."] -def divConst (A B : Finset G) : ℚ≥0 := (A / B).card / A.card +def divConst (A B : Finset G) : ℚ≥0 := #(A / B) / #A /-- The doubling constant `σₘ[A, B]` of two finsets `A` and `B` in a group is `|A * B| / |A|`. -/ scoped[Combinatorics.Additive] notation3:max "σₘ[" A ", " B "]" => Finset.mulConst A B @@ -68,23 +64,23 @@ scoped[Combinatorics.Additive] notation3:max "δ[" A "]" => Finset.subConst A A open scoped Combinatorics.Additive @[to_additive (attr := simp) addConst_mul_card] -lemma mulConst_mul_card (A B : Finset G) : σₘ[A, B] * A.card = (A * B).card := by +lemma mulConst_mul_card (A B : Finset G) : σₘ[A, B] * #A = #(A * B) := by obtain rfl | hA := A.eq_empty_or_nonempty · simp · exact div_mul_cancel₀ _ (by positivity) @[to_additive (attr := simp) subConst_mul_card] -lemma divConst_mul_card (A B : Finset G) : δₘ[A, B] * A.card = (A / B).card := by +lemma divConst_mul_card (A B : Finset G) : δₘ[A, B] * #A = #(A / B) := by obtain rfl | hA := A.eq_empty_or_nonempty · simp · exact div_mul_cancel₀ _ (by positivity) @[to_additive (attr := simp) card_mul_addConst] -lemma card_mul_mulConst (A B : Finset G) : A.card * σₘ[A, B] = (A * B).card := by +lemma card_mul_mulConst (A B : Finset G) : #A * σₘ[A, B] = #(A * B) := by rw [mul_comm, mulConst_mul_card] @[to_additive (attr := simp) card_mul_subConst] -lemma card_mul_divConst (A B : Finset G) : A.card * δₘ[A, B] = (A / B).card := by +lemma card_mul_divConst (A B : Finset G) : #A * δₘ[A, B] = #(A / B) := by rw [mul_comm, divConst_mul_card] @[to_additive (attr := simp)] @@ -124,44 +120,44 @@ end Fintype variable {𝕜 : Type*} [Semifield 𝕜] [CharZero 𝕜] -lemma cast_addConst (A B : Finset G') : (σ[A, B] : 𝕜) = (A + B).card / A.card := by +lemma cast_addConst (A B : Finset G') : (σ[A, B] : 𝕜) = #(A + B) / #A := by simp [addConst] -lemma cast_subConst (A B : Finset G') : (δ[A, B] : 𝕜) = (A - B).card / A.card := by +lemma cast_subConst (A B : Finset G') : (δ[A, B] : 𝕜) = #(A - B) / #A := by simp [subConst] @[to_additive existing] -lemma cast_mulConst (A B : Finset G) : (σₘ[A, B] : 𝕜) = (A * B).card / A.card := by simp [mulConst] +lemma cast_mulConst (A B : Finset G) : (σₘ[A, B] : 𝕜) = #(A * B) / #A := by simp [mulConst] @[to_additive existing] -lemma cast_divConst (A B : Finset G) : (δₘ[A, B] : 𝕜) = (A / B).card / A.card := by simp [divConst] +lemma cast_divConst (A B : Finset G) : (δₘ[A, B] : 𝕜) = #(A / B) / #A := by simp [divConst] -lemma cast_addConst_mul_card (A B : Finset G') : (σ[A, B] * A.card : 𝕜) = (A + B).card := by +lemma cast_addConst_mul_card (A B : Finset G') : (σ[A, B] * #A : 𝕜) = #(A + B) := by norm_cast; exact addConst_mul_card _ _ -lemma cast_subConst_mul_card (A B : Finset G') : (δ[A, B] * A.card : 𝕜) = (A - B).card := by +lemma cast_subConst_mul_card (A B : Finset G') : (δ[A, B] * #A : 𝕜) = #(A - B) := by norm_cast; exact subConst_mul_card _ _ -lemma card_mul_cast_addConst (A B : Finset G') : (A.card * σ[A, B] : 𝕜) = (A + B).card := by +lemma card_mul_cast_addConst (A B : Finset G') : (#A * σ[A, B] : 𝕜) = #(A + B) := by norm_cast; exact card_mul_addConst _ _ -lemma card_mul_cast_subConst (A B : Finset G') : (A.card * δ[A, B] : 𝕜) = (A - B).card := by +lemma card_mul_cast_subConst (A B : Finset G') : (#A * δ[A, B] : 𝕜) = #(A - B) := by norm_cast; exact card_mul_subConst _ _ @[to_additive (attr := simp) existing cast_addConst_mul_card] -lemma cast_mulConst_mul_card (A B : Finset G) : (σₘ[A, B] * A.card : 𝕜) = (A * B).card := by +lemma cast_mulConst_mul_card (A B : Finset G) : (σₘ[A, B] * #A : 𝕜) = #(A * B) := by norm_cast; exact mulConst_mul_card _ _ @[to_additive (attr := simp) existing cast_subConst_mul_card] -lemma cast_divConst_mul_card (A B : Finset G) : (δₘ[A, B] * A.card : 𝕜) = (A / B).card := by +lemma cast_divConst_mul_card (A B : Finset G) : (δₘ[A, B] * #A : 𝕜) = #(A / B) := by norm_cast; exact divConst_mul_card _ _ @[to_additive (attr := simp) existing card_mul_cast_addConst] -lemma card_mul_cast_mulConst (A B : Finset G) : (A.card * σₘ[A, B] : 𝕜) = (A * B).card := by +lemma card_mul_cast_mulConst (A B : Finset G) : (#A * σₘ[A, B] : 𝕜) = #(A * B) := by norm_cast; exact card_mul_mulConst _ _ @[to_additive (attr := simp) existing card_mul_cast_subConst] -lemma card_mul_cast_divConst (A B : Finset G) : (A.card * δₘ[A, B] : 𝕜) = (A / B).card := by +lemma card_mul_cast_divConst (A B : Finset G) : (#A * δₘ[A, B] : 𝕜) = #(A / B) := by norm_cast; exact card_mul_divConst _ _ end Group @@ -169,7 +165,7 @@ end Group open scoped Combinatorics.Additive section CommGroup -variable {G : Type*} [CommGroup G] [DecidableEq G] {A B : Finset G} {a : G} +variable {G : Type*} [CommGroup G] [DecidableEq G] {A B : Finset G} @[to_additive (attr := simp)] lemma mulConst_inv_left (A B : Finset G) : σₘ[A⁻¹, B] = δₘ[A, B] := by @@ -189,10 +185,10 @@ This is a consequence of the Ruzsa triangle inequality."] lemma mulConst_le_divConst_sq : σₘ[A] ≤ δₘ[A] ^ 2 := by obtain rfl | hA' := A.eq_empty_or_nonempty · simp - refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < A.card * A.card) + refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < #A * #A) calc - _ = (A * A).card * (A.card : ℚ≥0) := by rw [← mul_assoc, mulConst_mul_card] - _ ≤ (A / A).card * (A / A).card := by norm_cast; exact ruzsa_triangle_inequality_mul_div_div .. + _ = #(A * A) * (#A : ℚ≥0) := by rw [← mul_assoc, mulConst_mul_card] + _ ≤ #(A / A) * #(A / A) := by norm_cast; exact ruzsa_triangle_inequality_mul_div_div .. _ = _ := by rw [← divConst_mul_card]; ring /-- If `A` has small doubling, then it has small difference, with the constant squared. @@ -205,10 +201,10 @@ This is a consequence of the Ruzsa triangle inequality."] lemma divConst_le_mulConst_sq : δₘ[A] ≤ σₘ[A] ^ 2 := by obtain rfl | hA' := A.eq_empty_or_nonempty · simp - refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < A.card * A.card) + refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < #A * #A) calc - _ = (A / A).card * (A.card : ℚ≥0) := by rw [← mul_assoc, divConst_mul_card] - _ ≤ (A * A).card * (A * A).card := by norm_cast; exact ruzsa_triangle_inequality_div_mul_mul .. + _ = #(A / A) * (#A : ℚ≥0) := by rw [← mul_assoc, divConst_mul_card] + _ ≤ #(A * A) * #(A * A) := by norm_cast; exact ruzsa_triangle_inequality_div_mul_mul .. _ = _ := by rw [← mulConst_mul_card]; ring end CommGroup diff --git a/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean b/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean index a3bad041f207e..f20bc9174d851 100644 --- a/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean +++ b/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean @@ -22,7 +22,6 @@ elements of sum zero. -/ open Finset MvPolynomial -open scoped BigOperators variable {ι : Type*} @@ -51,8 +50,8 @@ private lemma totalDegree_f₁_add_totalDegree_f₂ {a : ι → ZMod p} : Any sequence of `2 * p - 1` elements of `ZMod p` contains a subsequence of `p` elements whose sum is zero. -/ -private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : s.card = 2 * p - 1) : - ∃ t ⊆ s, t.card = p ∧ ∑ i ∈ t, a i = 0 := by +private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : #s = 2 * p - 1) : + ∃ t ⊆ s, #t = p ∧ ∑ i ∈ t, a i = 0 := by haveI : NeZero p := inferInstance classical -- Let `N` be the number of common roots of our polynomials `f₁` and `f₂` (`f s ff` and `f s tt`). @@ -70,7 +69,7 @@ private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : s.card = obtain ⟨x, hx⟩ := Fintype.exists_ne_of_one_lt_card ((Fact.out : p.Prime).one_lt.trans_le <| Nat.le_of_dvd hN₀ hpN) zero_sol -- This common root gives us the required subsequence, namely the `i ∈ s` such that `x i ≠ 0`. - refine ⟨(s.attach.filter fun a ↦ x.1 a ≠ 0).map ⟨(↑), Subtype.val_injective⟩, ?_, ?_, ?_⟩ + refine ⟨({a | x.1 a ≠ 0} : Finset _).map ⟨(↑), Subtype.val_injective⟩, ?_, ?_, ?_⟩ · simp (config := { contextual := true }) [subset_iff] -- From `f₁ x = 0`, we get that `p` divides the number of `a` such that `x a ≠ 0`. · rw [card_map] @@ -82,7 +81,7 @@ private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : s.card = · rw [← CharP.cast_eq_zero_iff (ZMod p), ← Finset.sum_boole] simpa only [f₁, map_sum, ZMod.pow_card_sub_one, map_pow, eval_X] using x.2.1 -- And it is at most `2 * p - 1`, so it must be `p`. - · rw [Finset.card_attach, hs] + · rw [univ_eq_attach, card_attach, hs] exact tsub_lt_self (mul_pos zero_lt_two (Fact.out : p.Prime).pos) zero_lt_one -- From `f₂ x = 0`, we get that `p` divides the sum of the `a ∈ s` such that `x a ≠ 0`. · simpa [f₂, ZMod.pow_card_sub_one, Finset.sum_filter] using x.2.2 @@ -91,8 +90,8 @@ private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : s.card = Any sequence of `2 * p - 1` elements of `ℤ` contains a subsequence of `p` elements whose sum is divisible by `p`. -/ -private theorem Int.erdos_ginzburg_ziv_prime (a : ι → ℤ) (hs : s.card = 2 * p - 1) : - ∃ t ⊆ s, t.card = p ∧ ↑p ∣ ∑ i ∈ t, a i := by +private theorem Int.erdos_ginzburg_ziv_prime (a : ι → ℤ) (hs : #s = 2 * p - 1) : + ∃ t ⊆ s, #t = p ∧ ↑p ∣ ∑ i ∈ t, a i := by simpa [← Int.cast_sum, ZMod.intCast_zmod_eq_zero_iff_dvd] using ZMod.erdos_ginzburg_ziv_prime (Int.cast ∘ a) hs @@ -105,8 +104,8 @@ variable {n : ℕ} {s : Finset ι} Any sequence of at least `2 * n - 1` elements of `ℤ` contains a subsequence of `n` elements whose sum is divisible by `n`. -/ -theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : - ∃ t ⊆ s, t.card = n ∧ ↑n ∣ ∑ i ∈ t, a i := by +theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ #s) : + ∃ t ⊆ s, #t = n ∧ ↑n ∣ ∑ i ∈ t, a i := by classical -- Do induction on the prime factorisation of `n`. Note that we will apply the induction -- hypothesis with `ι := Finset ι`, so we need to generalise. @@ -126,9 +125,9 @@ theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : -- these sets whose sum is divisible by `m * n`. | composite m hm ihm n hn ihn => -- First, show that it is enough to have those `2 * m - 1` sets. - suffices ∀ k ≤ 2 * m - 1, ∃ 𝒜 : Finset (Finset ι), 𝒜.card = k ∧ + suffices ∀ k ≤ 2 * m - 1, ∃ 𝒜 : Finset (Finset ι), #𝒜 = k ∧ (𝒜 : Set (Finset ι)).Pairwise _root_.Disjoint ∧ - ∀ ⦃t⦄, t ∈ 𝒜 → t ⊆ s ∧ t.card = n ∧ ↑n ∣ ∑ i ∈ t, a i by + ∀ ⦃t⦄, t ∈ 𝒜 → t ⊆ s ∧ #t = n ∧ ↑n ∣ ∑ i ∈ t, a i by -- Assume `𝒜` is a family of `2 * m - 1` sets, each of size `n` and sum divisible by `n`. obtain ⟨𝒜, h𝒜card, h𝒜disj, h𝒜⟩ := this _ le_rfl -- By induction hypothesis on `m`, find a subfamily `ℬ` of size `m` such that the sum over @@ -151,13 +150,13 @@ theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : obtain ⟨𝒜, h𝒜card, h𝒜disj, h𝒜⟩ := ih (Nat.le_of_succ_le hk) -- There are at least `2 * (m * n) - 1 - k * n ≥ 2 * m - 1` elements in `s` that have not been -- taken in any element of `𝒜`. - have : 2 * n - 1 ≤ (s \ 𝒜.biUnion id).card := by + have : 2 * n - 1 ≤ #(s \ 𝒜.biUnion id) := by calc _ ≤ (2 * m - k) * n - 1 := by gcongr; omega - _ = (2 * (m * n) - 1) - ∑ t ∈ 𝒜, t.card := by + _ = (2 * (m * n) - 1) - ∑ t ∈ 𝒜, #t := by rw [tsub_mul, mul_assoc, tsub_right_comm, sum_const_nat fun t ht ↦ (h𝒜 ht).2.1, h𝒜card] - _ ≤ s.card - (𝒜.biUnion id).card := by gcongr; exact card_biUnion_le - _ ≤ (s \ 𝒜.biUnion id).card := le_card_sdiff .. + _ ≤ #s - #(𝒜.biUnion id) := by gcongr; exact card_biUnion_le + _ ≤ #(s \ 𝒜.biUnion id) := le_card_sdiff .. -- So by the induction hypothesis on `n` we can find a new set `t` of size `n` and sum divisible -- by `n`. obtain ⟨t₀, ht₀, ht₀card, ht₀sum⟩ := ihn a this @@ -178,8 +177,8 @@ theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : Any sequence of at least `2 * n - 1` elements of `ZMod n` contains a subsequence of `n` elements whose sum is zero. -/ -theorem ZMod.erdos_ginzburg_ziv (a : ι → ZMod n) (hs : 2 * n - 1 ≤ s.card) : - ∃ t ⊆ s, t.card = n ∧ ∑ i ∈ t, a i = 0 := by +theorem ZMod.erdos_ginzburg_ziv (a : ι → ZMod n) (hs : 2 * n - 1 ≤ #s) : + ∃ t ⊆ s, #t = n ∧ ∑ i ∈ t, a i = 0 := by simpa [← ZMod.intCast_zmod_eq_zero_iff_dvd] using Int.erdos_ginzburg_ziv (ZMod.cast ∘ a) hs /-- The **Erdős–Ginzburg–Ziv theorem** for `ℤ` for multiset. diff --git a/Mathlib/Combinatorics/Additive/FreimanHom.lean b/Mathlib/Combinatorics/Additive/FreimanHom.lean index 01cf0ef4b01c3..dc169558a2b3a 100644 --- a/Mathlib/Combinatorics/Additive/FreimanHom.lean +++ b/Mathlib/Combinatorics/Additive/FreimanHom.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Algebra.BigOperators.Ring -import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.CharP.Basic import Mathlib.Algebra.Group.Pointwise.Set.Basic -import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.Order.BigOperators.Group.Multiset import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.ZMod.Defs @@ -147,7 +147,7 @@ lemma IsMulFreimanIso.mul_eq_mul (hf : IsMulFreimanIso 2 A B f) {a b c d : α} lemma isMulFreimanHom_two : IsMulFreimanHom 2 A B f ↔ MapsTo f A B ∧ ∀ a ∈ A, ∀ b ∈ A, ∀ c ∈ A, ∀ d ∈ A, a * b = c * d → f a * f b = f c * f d where - mp hf := ⟨hf.mapsTo, fun a ha b hb c hc d hd ↦ hf.mul_eq_mul ha hb hc hd⟩ + mp hf := ⟨hf.mapsTo, fun _ ha _ hb _ hc _ hd ↦ hf.mul_eq_mul ha hb hc hd⟩ mpr hf := ⟨hf.1, by aesop (add simp card_eq_two)⟩ /-- Characterisation of `2`-Freiman homs. -/ @@ -155,7 +155,7 @@ lemma isMulFreimanHom_two : lemma isMulFreimanIso_two : IsMulFreimanIso 2 A B f ↔ BijOn f A B ∧ ∀ a ∈ A, ∀ b ∈ A, ∀ c ∈ A, ∀ d ∈ A, f a * f b = f c * f d ↔ a * b = c * d where - mp hf := ⟨hf.bijOn, fun a ha b hb c hc d hd => hf.mul_eq_mul ha hb hc hd⟩ + mp hf := ⟨hf.bijOn, fun _ ha _ hb _ hc _ hd => hf.mul_eq_mul ha hb hc hd⟩ mpr hf := ⟨hf.1, by aesop (add simp card_eq_two)⟩ @[to_additive] lemma isMulFreimanHom_id (hA : A₁ ⊆ A₂) : IsMulFreimanHom n A₁ A₂ id where @@ -235,7 +235,7 @@ lemma isMulFreimanIso_empty : IsMulFreimanIso n (∅ : Set α) (∅ : Set β) f @[to_additive] lemma IsMulFreimanHom.mul (h₁ : IsMulFreimanHom n A B₁ f₁) (h₂ : IsMulFreimanHom n A B₂ f₂) : IsMulFreimanHom n A (B₁ * B₂) (f₁ * f₂) where -- TODO: Extract `Set.MapsTo.mul` from this proof - mapsTo a ha := mul_mem_mul (h₁.mapsTo ha) (h₂.mapsTo ha) + mapsTo _ ha := mul_mem_mul (h₁.mapsTo ha) (h₂.mapsTo ha) map_prod_eq_map_prod s t hsA htA hs ht h := by rw [Pi.mul_def, prod_map_mul, prod_map_mul, h₁.map_prod_eq_map_prod hsA htA hs ht h, h₂.map_prod_eq_map_prod hsA htA hs ht h] @@ -328,7 +328,7 @@ variable [CommMonoid α] [DivisionCommMonoid β] {A : Set α} {B : Set β} {f : @[to_additive] lemma IsMulFreimanHom.inv (hf : IsMulFreimanHom n A B f) : IsMulFreimanHom n A B⁻¹ f⁻¹ where -- TODO: Extract `Set.MapsTo.inv` from this proof - mapsTo a ha := inv_mem_inv.2 (hf.mapsTo ha) + mapsTo _ ha := inv_mem_inv.2 (hf.mapsTo ha) map_prod_eq_map_prod s t hsA htA hs ht h := by rw [Pi.inv_def, prod_map_inv, prod_map_inv, hf.map_prod_eq_map_prod hsA htA hs ht h] @@ -336,7 +336,7 @@ lemma IsMulFreimanHom.inv (hf : IsMulFreimanHom n A B f) : IsMulFreimanHom n A B {f₁ f₂ : α → β} (h₁ : IsMulFreimanHom n A B₁ f₁) (h₂ : IsMulFreimanHom n A B₂ f₂) : IsMulFreimanHom n A (B₁ / B₂) (f₁ / f₂) where -- TODO: Extract `Set.MapsTo.div` from this proof - mapsTo a ha := div_mem_div (h₁.mapsTo ha) (h₂.mapsTo ha) + mapsTo _ ha := div_mem_div (h₁.mapsTo ha) (h₂.mapsTo ha) map_prod_eq_map_prod s t hsA htA hs ht h := by rw [Pi.div_def, prod_map_div, prod_map_div, h₁.map_prod_eq_map_prod hsA htA hs ht h, h₂.map_prod_eq_map_prod hsA htA hs ht h] diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index ae04f34d67a52..94e3ef08335bd 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -8,7 +8,11 @@ import Mathlib.Algebra.Order.Field.Basic import Mathlib.Algebra.Order.Field.Rat import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Combinatorics.Enumerative.DoubleCounting +import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.GCongr +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Positivity.Finset +import Mathlib.Tactic.Ring /-! # The Plünnecke-Ruzsa inequality @@ -29,52 +33,94 @@ inequality. * [Terrence Tao, Van Vu, *Additive Combinatorics][tao-vu] -/ -open Nat +open MulOpposite Nat open scoped Pointwise namespace Finset +variable {G : Type*} [DecidableEq G] -variable {α : Type*} [CommGroup α] [DecidableEq α] {A B C : Finset α} +section Group +variable [Group G] {A B C : Finset G} + +/-! ### Noncommutative Ruzsa triangle inequality -/ /-- **Ruzsa's triangle inequality**. Division version. -/ @[to_additive "**Ruzsa's triangle inequality**. Subtraction version."] -theorem ruzsa_triangle_inequality_div_div_div (A B C : Finset α) : - (A / C).card * B.card ≤ (A / B).card * (B / C).card := by - rw [← card_product (A / B), ← mul_one ((A / B) ×ˢ (B / C)).card] - refine card_mul_le_card_mul (fun b ac ↦ ac.1 * ac.2 = b) (fun x hx ↦ ?_) +theorem ruzsa_triangle_inequality_div_div_div (A B C : Finset G) : + #(A / C) * #B ≤ #(A / B) * #(C / B) := by + rw [← card_product (A / B), ← mul_one #((A / B) ×ˢ (C / B))] + refine card_mul_le_card_mul (fun b (a, c) ↦ a / c = b) (fun x hx ↦ ?_) fun x _ ↦ card_le_one_iff.2 fun hu hv ↦ ((mem_bipartiteBelow _).1 hu).2.symm.trans ?_ · obtain ⟨a, ha, c, hc, rfl⟩ := mem_div.1 hx - refine card_le_card_of_injOn (fun b ↦ (a / b, b / c)) (fun b hb ↦ ?_) fun b₁ _ b₂ _ h ↦ ?_ + refine card_le_card_of_injOn (fun b ↦ (a / b, c / b)) (fun b hb ↦ ?_) fun b₁ _ b₂ _ h ↦ ?_ · rw [mem_bipartiteAbove] - exact ⟨mk_mem_product (div_mem_div ha hb) (div_mem_div hb hc), div_mul_div_cancel _ _ _⟩ + exact ⟨mk_mem_product (div_mem_div ha hb) (div_mem_div hc hb), div_div_div_cancel_right ..⟩ · exact div_right_injective (Prod.ext_iff.1 h).1 · exact ((mem_bipartiteBelow _).1 hv).2 +/-- **Ruzsa's triangle inequality**. Mulinv-mulinv-mulinv version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Addneg-addneg-addneg version."] +theorem ruzsa_triangle_inequality_mulInv_mulInv_mulInv (A B C : Finset G) : + #(A * C⁻¹) * #B ≤ #(A * B⁻¹) * #(C * B⁻¹) := by + simpa [div_eq_mul_inv] using ruzsa_triangle_inequality_div_div_div A B C + +/-- **Ruzsa's triangle inequality**. Invmul-invmul-invmul version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Negadd-negadd-negadd version."] +theorem ruzsa_triangle_inequality_invMul_invMul_invMul (A B C : Finset G) : + #B * #(A⁻¹ * C) ≤ #(B⁻¹ * A) * #(B⁻¹ * C) := by + simpa [mul_comm, div_eq_mul_inv, ← map_op_mul, ← map_op_inv] using + ruzsa_triangle_inequality_div_div_div (G := Gᵐᵒᵖ) (C.map opEquiv.toEmbedding) + (B.map opEquiv.toEmbedding) (A.map opEquiv.toEmbedding) + + /-- **Ruzsa's triangle inequality**. Div-mul-mul version. -/ @[to_additive "**Ruzsa's triangle inequality**. Sub-add-add version."] -theorem ruzsa_triangle_inequality_div_mul_mul (A B C : Finset α) : - (A / C).card * B.card ≤ (A * B).card * (B * C).card := by - rw [← div_inv_eq_mul, ← card_inv B, ← card_inv (B * C), mul_inv, ← div_eq_mul_inv] - exact ruzsa_triangle_inequality_div_div_div _ _ _ +theorem ruzsa_triangle_inequality_div_mul_mul (A B C : Finset G) : + #(A / C) * #B ≤ #(A * B) * #(C * B) := by + simpa using ruzsa_triangle_inequality_div_div_div A B⁻¹ C + +/-- **Ruzsa's triangle inequality**. Mulinv-mul-mul version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Addneg-add-add version."] +theorem ruzsa_triangle_inequality_mulInv_mul_mul (A B C : Finset G) : + #(A * C⁻¹) * #B ≤ #(A * B) * #(C * B) := by + simpa using ruzsa_triangle_inequality_mulInv_mulInv_mulInv A B⁻¹ C + +/-- **Ruzsa's triangle inequality**. Invmul-mul-mul version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Negadd-add-add version."] +theorem ruzsa_triangle_inequality_invMul_mul_mul (A B C : Finset G) : + #B * #(A⁻¹ * C) ≤ #(B * A) * #(B * C) := by + simpa using ruzsa_triangle_inequality_invMul_invMul_invMul A B⁻¹ C + /-- **Ruzsa's triangle inequality**. Mul-div-mul version. -/ @[to_additive "**Ruzsa's triangle inequality**. Add-sub-add version."] -theorem ruzsa_triangle_inequality_mul_div_mul (A B C : Finset α) : - (A * C).card * B.card ≤ (A / B).card * (B * C).card := by - rw [← div_inv_eq_mul, ← div_inv_eq_mul B] - exact ruzsa_triangle_inequality_div_div_div _ _ _ - -/-- **Ruzsa's triangle inequality**. Mul-mul-div version. -/ -@[to_additive "**Ruzsa's triangle inequality**. Add-add-sub version."] -theorem ruzsa_triangle_inequality_mul_mul_div (A B C : Finset α) : - (A * C).card * B.card ≤ (A * B).card * (B / C).card := by - rw [← div_inv_eq_mul, div_eq_mul_inv B] - exact ruzsa_triangle_inequality_div_mul_mul _ _ _ +theorem ruzsa_triangle_inequality_mul_div_mul (A B C : Finset G) : + #B * #(A * C) ≤ #(B / A) * #(B * C) := by + simpa [div_eq_mul_inv] using ruzsa_triangle_inequality_invMul_mul_mul A⁻¹ B C + +/-- **Ruzsa's triangle inequality**. Mul-mulinv-mul version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Add-addneg-add version."] +theorem ruzsa_triangle_inequality_mul_mulInv_mul (A B C : Finset G) : + #B * #(A * C) ≤ #(B * A⁻¹) * #(B * C) := by + simpa [div_eq_mul_inv] using ruzsa_triangle_inequality_mul_div_mul A B C + +/-- **Ruzsa's triangle inequality**. Mul-mul-invmul version. -/ +@[to_additive "**Ruzsa's triangle inequality**. Add-add-negadd version."] +theorem ruzsa_triangle_inequality_mul_mul_invMul (A B C : Finset G) : + #(A * C) * #B ≤ #(A * B) * #(C⁻¹ * B) := by + simpa using ruzsa_triangle_inequality_mulInv_mul_mul A B C⁻¹ + +end Group + +section CommGroup +variable [CommGroup G] {A B C : Finset G} + +/-! ### Plünnecke-Petridis inequality -/ @[to_additive] -theorem pluennecke_petridis_inequality_mul (C : Finset α) - (hA : ∀ A' ⊆ A, (A * B).card * A'.card ≤ (A' * B).card * A.card) : - (A * B * C).card * A.card ≤ (A * B).card * (A * C).card := by +theorem pluennecke_petridis_inequality_mul (C : Finset G) + (hA : ∀ A' ⊆ A, #(A * B) * #A' ≤ #(A' * B) * #A) : + #(A * B * C) * #A ≤ #(A * B) * #(A * C) := by induction' C using Finset.induction_on with x C _ ih · simp set A' := A ∩ (A * C / {x}) with hA' @@ -88,7 +134,7 @@ theorem pluennecke_petridis_inequality_mul (C : Finset α) exact mul_subset_mul_right inter_subset_right have h₂ : A' * B * {x} ⊆ A * B * {x} := mul_subset_mul_right (mul_subset_mul_right inter_subset_left) - have h₃ : (A * B * C').card ≤ (A * B * C).card + (A * B).card - (A' * B).card := by + have h₃ : #(A * B * C') ≤ #(A * B * C) + #(A * B) - #(A' * B) := by rw [h₁] refine (card_union_le _ _).trans_eq ?_ rw [card_sdiff h₂, ← add_tsub_assoc_of_le (card_le_card h₂), card_mul_singleton, @@ -97,35 +143,34 @@ theorem pluennecke_petridis_inequality_mul (C : Finset α) rw [tsub_mul, add_mul] refine (tsub_le_tsub (add_le_add_right ih _) <| hA _ inter_subset_left).trans_eq ?_ rw [← mul_add, ← mul_tsub, ← hA', hC', insert_eq, mul_union, ← card_mul_singleton A x, ← - card_mul_singleton A' x, add_comm (card _), h₀, + card_mul_singleton A' x, add_comm #_, h₀, eq_tsub_of_add_eq (card_union_add_card_inter _ _)] -/-! ### Sum triangle inequality -/ - +/-! ### Commutative Ruzsa triangle inequality -/ -- Auxiliary lemma for Ruzsa's triangle sum inequality, and the Plünnecke-Ruzsa inequality. @[to_additive] private theorem mul_aux (hA : A.Nonempty) (hAB : A ⊆ B) - (h : ∀ A' ∈ B.powerset.erase ∅, ((A * C).card : ℚ≥0) / ↑A.card ≤ (A' * C).card / ↑A'.card) : - ∀ A' ⊆ A, (A * C).card * A'.card ≤ (A' * C).card * A.card := by + (h : ∀ A' ∈ B.powerset.erase ∅, (#(A * C) : ℚ≥0) / #A ≤ #(A' * C) / #A') : + ∀ A' ⊆ A, #(A * C) * #A' ≤ #(A' * C) * #A := by rintro A' hAA' obtain rfl | hA' := A'.eq_empty_or_nonempty · simp - have hA₀ : (0 : ℚ≥0) < A.card := cast_pos.2 hA.card_pos - have hA₀' : (0 : ℚ≥0) < A'.card := cast_pos.2 hA'.card_pos + have hA₀ : (0 : ℚ≥0) < #A := cast_pos.2 hA.card_pos + have hA₀' : (0 : ℚ≥0) < #A' := cast_pos.2 hA'.card_pos exact mod_cast (div_le_div_iff hA₀ hA₀').1 (h _ <| mem_erase_of_ne_of_mem hA'.ne_empty <| mem_powerset.2 <| hAA'.trans hAB) /-- **Ruzsa's triangle inequality**. Multiplication version. -/ @[to_additive "**Ruzsa's triangle inequality**. Addition version."] -theorem ruzsa_triangle_inequality_mul_mul_mul (A B C : Finset α) : - (A * C).card * B.card ≤ (A * B).card * (B * C).card := by +theorem ruzsa_triangle_inequality_mul_mul_mul (A B C : Finset G) : + #(A * C) * #B ≤ #(A * B) * #(B * C) := by obtain rfl | hB := B.eq_empty_or_nonempty · simp have hB' : B ∈ B.powerset.erase ∅ := mem_erase_of_ne_of_mem hB.ne_empty (mem_powerset_self _) obtain ⟨U, hU, hUA⟩ := - exists_min_image (B.powerset.erase ∅) (fun U ↦ (U * A).card / U.card : _ → ℚ≥0) ⟨B, hB'⟩ + exists_min_image (B.powerset.erase ∅) (fun U ↦ #(U * A) / #U : _ → ℚ≥0) ⟨B, hB'⟩ rw [mem_erase, mem_powerset, ← nonempty_iff_ne_empty] at hU refine cast_le.1 (?_ : (_ : ℚ≥0) ≤ _) push_cast @@ -141,80 +186,80 @@ theorem ruzsa_triangle_inequality_mul_mul_mul (A B C : Finset α) : /-- **Ruzsa's triangle inequality**. Mul-div-div version. -/ @[to_additive "**Ruzsa's triangle inequality**. Add-sub-sub version."] -theorem ruzsa_triangle_inequality_mul_div_div (A B C : Finset α) : - (A * C).card * B.card ≤ (A / B).card * (B / C).card := by +theorem ruzsa_triangle_inequality_mul_div_div (A B C : Finset G) : + #(A * C) * #B ≤ #(A / B) * #(B / C) := by rw [div_eq_mul_inv, ← card_inv B, ← card_inv (B / C), inv_div', div_inv_eq_mul] exact ruzsa_triangle_inequality_mul_mul_mul _ _ _ /-- **Ruzsa's triangle inequality**. Div-mul-div version. -/ @[to_additive "**Ruzsa's triangle inequality**. Sub-add-sub version."] -theorem ruzsa_triangle_inequality_div_mul_div (A B C : Finset α) : - (A / C).card * B.card ≤ (A * B).card * (B / C).card := by +theorem ruzsa_triangle_inequality_div_mul_div (A B C : Finset G) : + #(A / C) * #B ≤ #(A * B) * #(B / C) := by rw [div_eq_mul_inv, div_eq_mul_inv] exact ruzsa_triangle_inequality_mul_mul_mul _ _ _ /-- **Ruzsa's triangle inequality**. Div-div-mul version. -/ @[to_additive "**Ruzsa's triangle inequality**. Sub-sub-add version."] -theorem card_div_mul_le_card_div_mul_card_mul (A B C : Finset α) : - (A / C).card * B.card ≤ (A / B).card * (B * C).card := by +theorem card_div_mul_le_card_div_mul_card_mul (A B C : Finset G) : + #(A / C) * #B ≤ #(A / B) * #(B * C) := by rw [← div_inv_eq_mul, div_eq_mul_inv] exact ruzsa_triangle_inequality_mul_div_div _ _ _ -- Auxiliary lemma towards the Plünnecke-Ruzsa inequality @[to_additive] -private lemma card_mul_pow_le (hAB : ∀ A' ⊆ A, (A * B).card * A'.card ≤ (A' * B).card * A.card) - (n : ℕ) : (A * B ^ n).card ≤ ((A * B).card / A.card : ℚ≥0) ^ n * A.card := by +private lemma card_mul_pow_le (hAB : ∀ A' ⊆ A, #(A * B) * #A' ≤ #(A' * B) * #A) (n : ℕ) : + #(A * B ^ n) ≤ (#(A * B) / #A : ℚ≥0) ^ n * #A := by obtain rfl | hA := A.eq_empty_or_nonempty · simp induction' n with n ih · simp - rw [_root_.pow_succ', ← mul_assoc, _root_.pow_succ', @mul_assoc ℚ≥0, ← mul_div_right_comm, - le_div_iff₀, ← cast_mul] - swap - · exact cast_pos.2 hA.card_pos - refine (Nat.cast_le.2 <| pluennecke_petridis_inequality_mul _ hAB).trans ?_ - rw [cast_mul] - gcongr + refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < #A) + calc + ((#(A * B ^ (n + 1))) * #A : ℚ≥0) + = #(A * B * B ^ n) * #A := by rw [_root_.pow_succ', ← mul_assoc] + _ ≤ #(A * B) * #(A * B ^ n) := mod_cast pluennecke_petridis_inequality_mul _ hAB + _ ≤ #(A * B) * ((#(A * B) / #A) ^ n * #A) := by gcongr + _ = (#(A * B) / #A) ^ (n + 1) * #A * #A := by field_simp; ring /-- The **Plünnecke-Ruzsa inequality**. Multiplication version. Note that this is genuinely harder than the division version because we cannot use a double counting argument. -/ @[to_additive "The **Plünnecke-Ruzsa inequality**. Addition version. Note that this is genuinely harder than the subtraction version because we cannot use a double counting argument."] -theorem pluennecke_ruzsa_inequality_pow_div_pow_mul (hA : A.Nonempty) (B : Finset α) (m n : ℕ) : - ((B ^ m / B ^ n).card) ≤ ((A * B).card / A.card : ℚ≥0) ^ (m + n) * A.card := by +theorem pluennecke_ruzsa_inequality_pow_div_pow_mul (hA : A.Nonempty) (B : Finset G) (m n : ℕ) : + #(B ^ m / B ^ n) ≤ (#(A * B) / #A : ℚ≥0) ^ (m + n) * #A := by have hA' : A ∈ A.powerset.erase ∅ := mem_erase_of_ne_of_mem hA.ne_empty (mem_powerset_self _) - obtain ⟨C, hC, hCA⟩ := - exists_min_image (A.powerset.erase ∅) (fun C ↦ (C * B).card / C.card : _ → ℚ≥0) ⟨A, hA'⟩ + obtain ⟨C, hC, hCmin⟩ := + exists_min_image (A.powerset.erase ∅) (fun C ↦ #(C * B) / #C : _ → ℚ≥0) ⟨A, hA'⟩ rw [mem_erase, mem_powerset, ← nonempty_iff_ne_empty] at hC - refine (_root_.mul_le_mul_right <| cast_pos.2 hC.1.card_pos).1 ?_ - norm_cast - refine (Nat.cast_le.2 <| ruzsa_triangle_inequality_div_mul_mul _ _ _).trans ?_ - push_cast - rw [mul_comm _ C] - refine (mul_le_mul (card_mul_pow_le (mul_aux hC.1 hC.2 hCA) _) - (card_mul_pow_le (mul_aux hC.1 hC.2 hCA) _) (zero_le _) (zero_le _)).trans ?_ - rw [mul_mul_mul_comm, ← pow_add, ← mul_assoc] - gcongr ((?_ ^ _) * Nat.cast ?_) * _ - · exact hCA _ hA' - · exact card_le_card hC.2 + obtain ⟨hC, hCA⟩ := hC + refine le_of_mul_le_mul_right ?_ (by positivity : (0 : ℚ≥0) < #C) + calc + (#(B ^ m / B ^ n) * #C : ℚ≥0) + ≤ #(B ^ m * C) * #(B ^ n * C) := mod_cast ruzsa_triangle_inequality_div_mul_mul .. + _ = #(C * B ^ m) * #(C * B ^ n) := by simp_rw [mul_comm] + _ ≤ ((#(C * B) / #C) ^ m * #C) * ((#(C * B) / #C : ℚ≥0) ^ n * #C) := by + gcongr <;> exact card_mul_pow_le (mul_aux hC hCA hCmin) _ + _ = (#(C * B) / #C) ^ (m + n) * #C * #C := by ring + _ ≤ (#(A * B) / #A) ^ (m + n) * #A * #C := by gcongr (?_ ^ _) * #?_ * _; exact hCmin _ hA' /-- The **Plünnecke-Ruzsa inequality**. Division version. -/ @[to_additive "The **Plünnecke-Ruzsa inequality**. Subtraction version."] -theorem pluennecke_ruzsa_inequality_pow_div_pow_div (hA : A.Nonempty) (B : Finset α) (m n : ℕ) : - (B ^ m / B ^ n).card ≤ ((A / B).card / A.card : ℚ≥0) ^ (m + n) * A.card := by +theorem pluennecke_ruzsa_inequality_pow_div_pow_div (hA : A.Nonempty) (B : Finset G) (m n : ℕ) : + #(B ^ m / B ^ n) ≤ (#(A / B) / #A : ℚ≥0) ^ (m + n) * #A := by rw [← card_inv, inv_div', ← inv_pow, ← inv_pow, div_eq_mul_inv A] exact pluennecke_ruzsa_inequality_pow_div_pow_mul hA _ _ _ /-- Special case of the **Plünnecke-Ruzsa inequality**. Multiplication version. -/ @[to_additive "Special case of the **Plünnecke-Ruzsa inequality**. Addition version."] -theorem pluennecke_ruzsa_inequality_pow_mul (hA : A.Nonempty) (B : Finset α) (n : ℕ) : - (B ^ n).card ≤ ((A * B).card / A.card : ℚ≥0) ^ n * A.card := by +theorem pluennecke_ruzsa_inequality_pow_mul (hA : A.Nonempty) (B : Finset G) (n : ℕ) : + #(B ^ n) ≤ (#(A * B) / #A : ℚ≥0) ^ n * #A := by simpa only [_root_.pow_zero, div_one] using pluennecke_ruzsa_inequality_pow_div_pow_mul hA _ _ 0 /-- Special case of the **Plünnecke-Ruzsa inequality**. Division version. -/ @[to_additive "Special case of the **Plünnecke-Ruzsa inequality**. Subtraction version."] -theorem pluennecke_ruzsa_inequality_pow_div (hA : A.Nonempty) (B : Finset α) (n : ℕ) : - (B ^ n).card ≤ ((A / B).card / A.card : ℚ≥0) ^ n * A.card := by +theorem pluennecke_ruzsa_inequality_pow_div (hA : A.Nonempty) (B : Finset G) (n : ℕ) : + #(B ^ n) ≤ (#(A / B) / #A : ℚ≥0) ^ n * #A := by simpa only [_root_.pow_zero, div_one] using pluennecke_ruzsa_inequality_pow_div_pow_div hA _ _ 0 +end CommGroup end Finset diff --git a/Mathlib/Combinatorics/Colex.lean b/Mathlib/Combinatorics/Colex.lean index 0d59516a64ae1..51ab9b09db4e7 100644 --- a/Mathlib/Combinatorics/Colex.lean +++ b/Mathlib/Combinatorics/Colex.lean @@ -65,7 +65,7 @@ namespace Finset /-- Type synonym of `Finset α` equipped with the colexicographic order rather than the inclusion order. -/ @[ext] -structure Colex (α) := +structure Colex (α) where /-- `toColex` is the "identity" function between `Finset α` and `Finset.Colex α`. -/ toColex :: /-- `ofColex` is the "identity" function between `Finset.Colex α` and `Finset α`. -/ @@ -102,7 +102,7 @@ instance instLE : LE (Colex α) where private lemma trans_aux (hst : toColex s ≤ toColex t) (htu : toColex t ≤ toColex u) (has : a ∈ s) (hat : a ∉ t) : ∃ b, b ∈ u ∧ b ∉ s ∧ a ≤ b := by classical - let s' : Finset α := s.filter fun b ↦ b ∉ t ∧ a ≤ b + let s' : Finset α := {b ∈ s | b ∉ t ∧ a ≤ b} have ⟨b, hb, hbmax⟩ := exists_maximal s' ⟨a, by simp [s', has, hat]⟩ simp only [s', mem_filter, and_imp] at hb hbmax have ⟨c, hct, hcs, hbc⟩ := hst hb.1 hb.2.1 @@ -120,8 +120,8 @@ private lemma antisymm_aux (hst : toColex s ≤ toColex t) (hts : toColex t ≤ exact hb₂ hb₁ instance instPartialOrder : PartialOrder (Colex α) where - le_refl s a ha ha' := (ha' ha).elim - le_antisymm s t hst hts := Colex.ext <| (antisymm_aux hst hts).antisymm (antisymm_aux hts hst) + le_refl _ _ ha ha' := (ha' ha).elim + le_antisymm _ _ hst hts := Colex.ext <| (antisymm_aux hst hts).antisymm (antisymm_aux hts hst) le_trans s t u hst htu a has hau := by by_cases hat : a ∈ ofColex t · have ⟨b, hbu, hbt, hab⟩ := htu hat hau @@ -338,10 +338,10 @@ lemma lt_iff_max'_mem {s t : Colex α} : rw [lt_iff_le_and_ne, le_iff_max'_mem]; aesop lemma lt_iff_exists_filter_lt : - toColex s < toColex t ↔ ∃ w ∈ t \ s, s.filter (w < ·) = t.filter (w < ·) := by + toColex s < toColex t ↔ ∃ w ∈ t \ s, {a ∈ s | w < a} = {a ∈ t | w < a} := by simp only [lt_iff_exists_forall_lt, mem_sdiff, filter_inj, and_assoc] refine ⟨fun h ↦ ?_, ?_⟩ - · let u := (t \ s).filter fun w ↦ ∀ a ∈ s, a ∉ t → a < w + · let u := {w ∈ t \ s | ∀ a ∈ s, a ∉ t → a < w} have mem_u {w : α} : w ∈ u ↔ w ∈ t ∧ w ∉ s ∧ ∀ a ∈ s, a ∉ t → a < w := by simp [u, and_assoc] have hu : u.Nonempty := h.imp fun _ ↦ mem_u.2 let m := max' _ hu @@ -355,8 +355,8 @@ lemma lt_iff_exists_filter_lt : by_contra! hwa exact hat <| (hw <| hwa.lt_of_ne <| ne_of_mem_of_not_mem hwt hat).1 has -/-- If `s ≤ t` in colex and `s.card ≤ t.card`, then `s \ {a} ≤ t \ {min t}` for any `a ∈ s`. -/ -lemma erase_le_erase_min' (hst : toColex s ≤ toColex t) (hcard : s.card ≤ t.card) (ha : a ∈ s) : +/-- If `s ≤ t` in colex and `#s ≤ #t`, then `s \ {a} ≤ t \ {min t}` for any `a ∈ s`. -/ +lemma erase_le_erase_min' (hst : toColex s ≤ toColex t) (hcard : #s ≤ #t) (ha : a ∈ s) : toColex (s.erase a) ≤ toColex (t.erase <| min' t <| card_pos.1 <| (card_pos.2 ⟨a, ha⟩).trans_le hcard) := by generalize_proofs ht @@ -434,7 +434,7 @@ end Fintype downwards closed with respect to colex among sets of size `r`. -/ def IsInitSeg (𝒜 : Finset (Finset α)) (r : ℕ) : Prop := (𝒜 : Set (Finset α)).Sized r ∧ - ∀ ⦃s t : Finset α⦄, s ∈ 𝒜 → toColex t < toColex s ∧ t.card = r → t ∈ 𝒜 + ∀ ⦃s t : Finset α⦄, s ∈ 𝒜 → toColex t < toColex s ∧ #t = r → t ∈ 𝒜 @[simp] lemma isInitSeg_empty : IsInitSeg (∅ : Finset (Finset α)) r := by simp [IsInitSeg] @@ -454,24 +454,23 @@ lemma IsInitSeg.total (h₁ : IsInitSeg 𝒜₁ r) (h₂ : IsInitSeg 𝒜₂ r) variable [Fintype α] -/-- The initial segment of the colexicographic order on sets with `s.card` elements and ending at +/-- The initial segment of the colexicographic order on sets with `#s` elements and ending at `s`. -/ -def initSeg (s : Finset α) : Finset (Finset α) := - univ.filter fun t ↦ s.card = t.card ∧ toColex t ≤ toColex s +def initSeg (s : Finset α) : Finset (Finset α) := {t | #s = #t ∧ toColex t ≤ toColex s} @[simp] -lemma mem_initSeg : t ∈ initSeg s ↔ s.card = t.card ∧ toColex t ≤ toColex s := by simp [initSeg] +lemma mem_initSeg : t ∈ initSeg s ↔ #s = #t ∧ toColex t ≤ toColex s := by simp [initSeg] lemma mem_initSeg_self : s ∈ initSeg s := by simp @[simp] lemma initSeg_nonempty : (initSeg s).Nonempty := ⟨s, mem_initSeg_self⟩ -lemma isInitSeg_initSeg : IsInitSeg (initSeg s) s.card := by +lemma isInitSeg_initSeg : IsInitSeg (initSeg s) #s := by refine ⟨fun t ht => (mem_initSeg.1 ht).1.symm, fun t₁ t₂ ht₁ ht₂ ↦ mem_initSeg.2 ⟨ht₂.2.symm, ?_⟩⟩ rw [mem_initSeg] at ht₁ exact ht₂.1.le.trans ht₁.2 lemma IsInitSeg.exists_initSeg (h𝒜 : IsInitSeg 𝒜 r) (h𝒜₀ : 𝒜.Nonempty) : - ∃ s : Finset α, s.card = r ∧ 𝒜 = initSeg s := by + ∃ s : Finset α, #s = r ∧ 𝒜 = initSeg s := by have hs := sup'_mem (ofColex ⁻¹' 𝒜) (LinearOrder.supClosed _) 𝒜 h𝒜₀ toColex (fun a ha ↦ by simpa using ha) refine ⟨_, h𝒜.1 hs, ?_⟩ @@ -487,7 +486,7 @@ lemma IsInitSeg.exists_initSeg (h𝒜 : IsInitSeg 𝒜 r) (h𝒜₀ : 𝒜.Nonem /-- Being a nonempty initial segment of colex is equivalent to being an `initSeg`. -/ lemma isInitSeg_iff_exists_initSeg : - IsInitSeg 𝒜 r ∧ 𝒜.Nonempty ↔ ∃ s : Finset α, s.card = r ∧ 𝒜 = initSeg s := by + IsInitSeg 𝒜 r ∧ 𝒜.Nonempty ↔ ∃ s : Finset α, #s = r ∧ 𝒜 = initSeg s := by refine ⟨fun h𝒜 ↦ h𝒜.1.exists_initSeg h𝒜.2, ?_⟩ rintro ⟨s, rfl, rfl⟩ exact ⟨isInitSeg_initSeg, initSeg_nonempty⟩ diff --git a/Mathlib/Combinatorics/Configuration.lean b/Mathlib/Combinatorics/Configuration.lean index a703f011ed4da..79f8392c7bf56 100644 --- a/Mathlib/Combinatorics/Configuration.lean +++ b/Mathlib/Combinatorics/Configuration.lean @@ -117,27 +117,27 @@ theorem Nondegenerate.exists_injective_of_card_le [Nondegenerate P L] [Fintype P (h : Fintype.card L ≤ Fintype.card P) : ∃ f : L → P, Function.Injective f ∧ ∀ l, f l ∉ l := by classical let t : L → Finset P := fun l => Set.toFinset { p | p ∉ l } - suffices ∀ s : Finset L, s.card ≤ (s.biUnion t).card by + suffices ∀ s : Finset L, #s ≤ (s.biUnion t).card by -- Hall's marriage theorem obtain ⟨f, hf1, hf2⟩ := (Finset.all_card_le_biUnion_card_iff_exists_injective t).mp this exact ⟨f, hf1, fun l => Set.mem_toFinset.mp (hf2 l)⟩ intro s - by_cases hs₀ : s.card = 0 - -- If `s = ∅`, then `s.card = 0 ≤ (s.bUnion t).card` + by_cases hs₀ : #s = 0 + -- If `s = ∅`, then `#s = 0 ≤ #(s.bUnion t)` · simp_rw [hs₀, zero_le] - by_cases hs₁ : s.card = 1 + by_cases hs₁ : #s = 1 -- If `s = {l}`, then pick a point `p ∉ l` · obtain ⟨l, rfl⟩ := Finset.card_eq_one.mp hs₁ obtain ⟨p, hl⟩ := exists_point (P := P) l rw [Finset.card_singleton, Finset.singleton_biUnion, Nat.one_le_iff_ne_zero] exact Finset.card_ne_zero_of_mem (Set.mem_toFinset.mpr hl) - suffices (s.biUnion t)ᶜ.card ≤ sᶜ.card by + suffices #(s.biUnion t)ᶜ ≤ #sᶜ by -- Rephrase in terms of complements (uses `h`) rw [Finset.card_compl, Finset.card_compl, tsub_le_iff_left] at this replace := h.trans this rwa [← add_tsub_assoc_of_le s.card_le_univ, le_tsub_iff_left (le_add_left s.card_le_univ), add_le_add_iff_right] at this - have hs₂ : (s.biUnion t)ᶜ.card ≤ 1 := by + have hs₂ : #(s.biUnion t)ᶜ ≤ 1 := by -- At most one line through two points of `s` refine Finset.card_le_one_iff.mpr @fun p₁ p₂ hp₁ hp₂ => ?_ simp_rw [t, Finset.mem_compl, Finset.mem_biUnion, not_exists, not_and, @@ -145,7 +145,7 @@ theorem Nondegenerate.exists_injective_of_card_le [Nondegenerate P L] [Fintype P obtain ⟨l₁, l₂, hl₁, hl₂, hl₃⟩ := Finset.one_lt_card_iff.mp (Nat.one_lt_iff_ne_zero_and_ne_one.mpr ⟨hs₀, hs₁⟩) exact (eq_or_eq (hp₁ l₁ hl₁) (hp₂ l₁ hl₁) (hp₁ l₂ hl₂) (hp₂ l₂ hl₂)).resolve_right hl₃ - by_cases hs₃ : sᶜ.card = 0 + by_cases hs₃ : #sᶜ = 0 · rw [hs₃, Nat.le_zero] rw [Finset.card_compl, tsub_eq_zero_iff_le, LE.le.le_iff_eq (Finset.card_le_univ _), eq_comm, Finset.card_eq_iff_eq_univ] at hs₃ ⊢ diff --git a/Mathlib/Combinatorics/Derangements/Exponential.lean b/Mathlib/Combinatorics/Derangements/Exponential.lean index 9ec2eea19d87f..f992a4f1c6ffb 100644 --- a/Mathlib/Combinatorics/Derangements/Exponential.lean +++ b/Mathlib/Combinatorics/Derangements/Exponential.lean @@ -5,7 +5,7 @@ Authors: Henry Swanson, Patrick Massot -/ import Mathlib.Analysis.SpecialFunctions.Exponential import Mathlib.Combinatorics.Derangements.Finite -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto /-! # Derangement exponential series diff --git a/Mathlib/Combinatorics/Digraph/Basic.lean b/Mathlib/Combinatorics/Digraph/Basic.lean index b6c97992885be..bc72f31b7b8b4 100644 --- a/Mathlib/Combinatorics/Digraph/Basic.lean +++ b/Mathlib/Combinatorics/Digraph/Basic.lean @@ -96,7 +96,7 @@ Any bipartite digraph may be regarded as a subgraph of one of these. def completeBipartiteGraph (V W : Type*) : Digraph (Sum V W) where Adj v w := v.isLeft ∧ w.isRight ∨ v.isRight ∧ w.isLeft -variable {ι : Sort*} {V W X : Type*} (G : Digraph V) (G' : Digraph W) {a b c u v w : V} +variable {ι : Sort*} {V : Type*} (G : Digraph V) {a b : V} theorem adj_injective : Injective (Adj : Digraph V → V → V → Prop) := fun _ _ ↦ Digraph.ext @@ -176,19 +176,19 @@ instance completeAtomicBooleanAlgebra : CompleteAtomicBooleanAlgebra (Digraph V) sdiff := (· \ ·) top := Digraph.completeDigraph V bot := Digraph.emptyDigraph V - le_top := fun x v w _ ↦ trivial - bot_le := fun x v w h ↦ h.elim - sdiff_eq := fun x y ↦ rfl - inf_compl_le_bot := fun G v w h ↦ absurd h.1 h.2 + le_top := fun _ _ _ _ ↦ trivial + bot_le := fun _ _ _ h ↦ h.elim + sdiff_eq := fun _ _ ↦ rfl + inf_compl_le_bot := fun _ _ _ h ↦ absurd h.1 h.2 top_le_sup_compl := fun G v w _ ↦ by tauto sSup := sSup - le_sSup := fun s G hG a b hab ↦ ⟨G, hG, hab⟩ + le_sSup := fun _ G hG _ _ hab ↦ ⟨G, hG, hab⟩ sSup_le := fun s G hG a b ↦ by rintro ⟨H, hH, hab⟩ exact hG _ hH hab sInf := sInf - sInf_le := fun s G hG a b hab ↦ hab hG - le_sInf := fun s G hG a b hab ↦ fun H hH ↦ hG _ hH hab + sInf_le := fun _ _ hG _ _ hab ↦ hab hG + le_sInf := fun _ _ hG _ _ hab ↦ fun _ hH ↦ hG _ hH hab iInf_iSup_eq := fun f ↦ by ext; simp [Classical.skolem] } @[simp] theorem top_adj (v w : V) : (⊤ : Digraph V).Adj v w := trivial diff --git a/Mathlib/Combinatorics/Enumerative/Catalan.lean b/Mathlib/Combinatorics/Enumerative/Catalan.lean index 0f5e376cda49f..c2ae512bb889f 100644 --- a/Mathlib/Combinatorics/Enumerative/Catalan.lean +++ b/Mathlib/Combinatorics/Enumerative/Catalan.lean @@ -186,7 +186,7 @@ theorem coe_treesOfNumNodesEq (n : ℕ) : ↑(treesOfNumNodesEq n) = { x : Tree Unit | x.numNodes = n } := Set.ext (by simp) -theorem treesOfNumNodesEq_card_eq_catalan (n : ℕ) : (treesOfNumNodesEq n).card = catalan n := by +theorem treesOfNumNodesEq_card_eq_catalan (n : ℕ) : #(treesOfNumNodesEq n) = catalan n := by induction' n using Nat.case_strong_induction_on with n ih · simp rw [treesOfNumNodesEq_succ, card_biUnion, catalan_succ'] diff --git a/Mathlib/Combinatorics/Enumerative/Composition.lean b/Mathlib/Combinatorics/Enumerative/Composition.lean index 917e4a7e41dbc..c825e38016f80 100644 --- a/Mathlib/Combinatorics/Enumerative/Composition.lean +++ b/Mathlib/Combinatorics/Enumerative/Composition.lean @@ -6,7 +6,6 @@ Authors: Sébastien Gouëzel import Mathlib.Algebra.BigOperators.Fin import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Data.Finset.Sort -import Mathlib.Data.Set.Subsingleton /-! # Compositions @@ -807,7 +806,7 @@ theorem card_boundaries_eq_succ_length : c.boundaries.card = c.length + 1 := theorem length_lt_card_boundaries : c.length < c.boundaries.card := by rw [c.card_boundaries_eq_succ_length] - exact lt_add_one _ + exact Nat.lt_add_one _ theorem lt_length (i : Fin c.length) : (i : ℕ) + 1 < c.boundaries.card := lt_tsub_iff_right.mp i.2 diff --git a/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean b/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean index 0264391a00385..9b6342a8abe9e 100644 --- a/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean +++ b/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean @@ -5,6 +5,7 @@ Authors: Yaël Dillies -/ import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Ring.Nat /-! # Double countings @@ -43,10 +44,10 @@ variable (r : α → β → Prop) (s : Finset α) (t : Finset β) (a : α) (b : [DecidablePred (r a)] [∀ a, Decidable (r a b)] {m n : ℕ} /-- Elements of `s` which are "below" `b` according to relation `r`. -/ -def bipartiteBelow : Finset α := s.filter fun a ↦ r a b +def bipartiteBelow : Finset α := {a ∈ s | r a b} /-- Elements of `t` which are "above" `a` according to relation `r`. -/ -def bipartiteAbove : Finset β := t.filter (r a) +def bipartiteAbove : Finset β := {b ∈ t | r a b} theorem bipartiteBelow_swap : t.bipartiteBelow (swap r) a = t.bipartiteAbove r a := rfl @@ -66,10 +67,16 @@ theorem mem_bipartiteBelow {a : α} : a ∈ s.bipartiteBelow r b ↔ a ∈ s ∧ @[simp] theorem mem_bipartiteAbove {b : β} : b ∈ t.bipartiteAbove r a ↔ b ∈ t ∧ r a b := mem_filter +@[to_additive] +theorem prod_prod_bipartiteAbove_eq_prod_prod_bipartiteBelow + [CommMonoid R] (f : α → β → R) [∀ a b, Decidable (r a b)] : + ∏ a ∈ s, ∏ b ∈ t.bipartiteAbove r a, f a b = ∏ b ∈ t, ∏ a ∈ s.bipartiteBelow r b, f a b := by + simp_rw [bipartiteAbove, bipartiteBelow, prod_filter] + exact prod_comm + theorem sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow [∀ a b, Decidable (r a b)] : - (∑ a ∈ s, (t.bipartiteAbove r a).card) = ∑ b ∈ t, (s.bipartiteBelow r b).card := by - simp_rw [card_eq_sum_ones, bipartiteAbove, bipartiteBelow, sum_filter] - exact sum_comm + (∑ a ∈ s, #(t.bipartiteAbove r a)) = ∑ b ∈ t, #(s.bipartiteBelow r b) := by + simp_rw [card_eq_sum_ones, sum_sum_bipartiteAbove_eq_sum_sum_bipartiteBelow] section OrderedSemiring variable [OrderedSemiring R] {m n : R} @@ -79,11 +86,11 @@ variable [OrderedSemiring R] {m n : R} Considering `r` as a bipartite graph, the LHS is a lower bound on the number of edges while the RHS is an upper bound. -/ theorem card_nsmul_le_card_nsmul [∀ a b, Decidable (r a b)] - (hm : ∀ a ∈ s, m ≤ (t.bipartiteAbove r a).card) - (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card ≤ n) : s.card • m ≤ t.card • n := + (hm : ∀ a ∈ s, m ≤ #(t.bipartiteAbove r a)) + (hn : ∀ b ∈ t, #(s.bipartiteBelow r b) ≤ n) : #s • m ≤ #t • n := calc - _ ≤ ∑ a in s, ((t.bipartiteAbove r a).card : R) := s.card_nsmul_le_sum _ _ hm - _ = ∑ b in t, ((s.bipartiteBelow r b).card : R) := by + _ ≤ ∑ a in s, (#(t.bipartiteAbove r a) : R) := s.card_nsmul_le_sum _ _ hm + _ = ∑ b in t, (#(s.bipartiteBelow r b) : R) := by norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] _ ≤ _ := t.sum_le_card_nsmul _ _ hn @@ -92,8 +99,8 @@ theorem card_nsmul_le_card_nsmul [∀ a b, Decidable (r a b)] Considering `r` as a bipartite graph, the LHS is a lower bound on the number of edges while the RHS is an upper bound. -/ theorem card_nsmul_le_card_nsmul' [∀ a b, Decidable (r a b)] - (hn : ∀ b ∈ t, n ≤ (s.bipartiteBelow r b).card) - (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card ≤ m) : t.card • n ≤ s.card • m := + (hn : ∀ b ∈ t, n ≤ #(s.bipartiteBelow r b)) + (hm : ∀ a ∈ s, #(t.bipartiteAbove r a) ≤ m) : #t • n ≤ #s • m := card_nsmul_le_card_nsmul (swap r) hn hm end OrderedSemiring @@ -107,12 +114,12 @@ variable [StrictOrderedSemiring R] (r : α → β → Prop) {s : Finset α} {t : Considering `r` as a bipartite graph, the LHS is a strict lower bound on the number of edges while the RHS is an upper bound. -/ theorem card_nsmul_lt_card_nsmul_of_lt_of_le [∀ a b, Decidable (r a b)] (hs : s.Nonempty) - (hm : ∀ a ∈ s, m < (t.bipartiteAbove r a).card) - (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card ≤ n) : s.card • m < t.card • n := + (hm : ∀ a ∈ s, m < #(t.bipartiteAbove r a)) + (hn : ∀ b ∈ t, #(s.bipartiteBelow r b) ≤ n) : #s • m < #t • n := calc _ = ∑ _a ∈ s, m := by rw [sum_const] - _ < ∑ a ∈ s, ((t.bipartiteAbove r a).card : R) := sum_lt_sum_of_nonempty hs hm - _ = ∑ b in t, ((s.bipartiteBelow r b).card : R) := by + _ < ∑ a ∈ s, (#(t.bipartiteAbove r a) : R) := sum_lt_sum_of_nonempty hs hm + _ = ∑ b in t, (#(s.bipartiteBelow r b) : R) := by norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] _ ≤ _ := t.sum_le_card_nsmul _ _ hn @@ -121,11 +128,11 @@ theorem card_nsmul_lt_card_nsmul_of_lt_of_le [∀ a b, Decidable (r a b)] (hs : Considering `r` as a bipartite graph, the LHS is a lower bound on the number of edges while the RHS is a strict upper bound. -/ theorem card_nsmul_lt_card_nsmul_of_le_of_lt [∀ a b, Decidable (r a b)] (ht : t.Nonempty) - (hm : ∀ a ∈ s, m ≤ (t.bipartiteAbove r a).card) - (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card < n) : s.card • m < t.card • n := + (hm : ∀ a ∈ s, m ≤ #(t.bipartiteAbove r a)) + (hn : ∀ b ∈ t, #(s.bipartiteBelow r b) < n) : #s • m < #t • n := calc - _ ≤ ∑ a in s, ((t.bipartiteAbove r a).card : R) := s.card_nsmul_le_sum _ _ hm - _ = ∑ b in t, ((s.bipartiteBelow r b).card : R) := by + _ ≤ ∑ a in s, (#(t.bipartiteAbove r a) : R) := s.card_nsmul_le_sum _ _ hm + _ = ∑ b in t, (#(s.bipartiteBelow r b) : R) := by norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] _ < ∑ _b ∈ t, n := sum_lt_sum_of_nonempty ht hn _ = _ := sum_const _ @@ -135,8 +142,8 @@ theorem card_nsmul_lt_card_nsmul_of_le_of_lt [∀ a b, Decidable (r a b)] (ht : Considering `r` as a bipartite graph, the LHS is a strict lower bound on the number of edges while the RHS is an upper bound. -/ theorem card_nsmul_lt_card_nsmul_of_lt_of_le' [∀ a b, Decidable (r a b)] (ht : t.Nonempty) - (hn : ∀ b ∈ t, n < (s.bipartiteBelow r b).card) - (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card ≤ m) : t.card • n < s.card • m := + (hn : ∀ b ∈ t, n < #(s.bipartiteBelow r b)) + (hm : ∀ a ∈ s, #(t.bipartiteAbove r a) ≤ m) : #t • n < #s • m := card_nsmul_lt_card_nsmul_of_lt_of_le (swap r) ht hn hm /-- **Double counting** argument. @@ -144,8 +151,8 @@ theorem card_nsmul_lt_card_nsmul_of_lt_of_le' [∀ a b, Decidable (r a b)] (ht : Considering `r` as a bipartite graph, the LHS is a lower bound on the number of edges while the RHS is a strict upper bound. -/ theorem card_nsmul_lt_card_nsmul_of_le_of_lt' [∀ a b, Decidable (r a b)] (hs : s.Nonempty) - (hn : ∀ b ∈ t, n ≤ (s.bipartiteBelow r b).card) - (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card < m) : t.card • n < s.card • m := + (hn : ∀ b ∈ t, n ≤ #(s.bipartiteBelow r b)) + (hm : ∀ a ∈ s, #(t.bipartiteAbove r a) < m) : #t • n < #s • m := card_nsmul_lt_card_nsmul_of_le_of_lt (swap r) hs hn hm end StrictOrderedSemiring @@ -155,25 +162,25 @@ end StrictOrderedSemiring Considering `r` as a bipartite graph, the LHS is a lower bound on the number of edges while the RHS is an upper bound. -/ theorem card_mul_le_card_mul [∀ a b, Decidable (r a b)] - (hm : ∀ a ∈ s, m ≤ (t.bipartiteAbove r a).card) - (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card ≤ n) : s.card * m ≤ t.card * n := + (hm : ∀ a ∈ s, m ≤ #(t.bipartiteAbove r a)) + (hn : ∀ b ∈ t, #(s.bipartiteBelow r b) ≤ n) : #s * m ≤ #t * n := card_nsmul_le_card_nsmul _ hm hn theorem card_mul_le_card_mul' [∀ a b, Decidable (r a b)] - (hn : ∀ b ∈ t, n ≤ (s.bipartiteBelow r b).card) - (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card ≤ m) : t.card * n ≤ s.card * m := + (hn : ∀ b ∈ t, n ≤ #(s.bipartiteBelow r b)) + (hm : ∀ a ∈ s, #(t.bipartiteAbove r a) ≤ m) : #t * n ≤ #s * m := card_nsmul_le_card_nsmul' _ hn hm theorem card_mul_eq_card_mul [∀ a b, Decidable (r a b)] - (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card = m) - (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card = n) : s.card * m = t.card * n := + (hm : ∀ a ∈ s, #(t.bipartiteAbove r a) = m) + (hn : ∀ b ∈ t, #(s.bipartiteBelow r b) = n) : #s * m = #t * n := (card_mul_le_card_mul _ (fun a ha ↦ (hm a ha).ge) fun b hb ↦ (hn b hb).le).antisymm <| card_mul_le_card_mul' _ (fun a ha ↦ (hn a ha).ge) fun b hb ↦ (hm b hb).le theorem card_le_card_of_forall_subsingleton (hs : ∀ a ∈ s, ∃ b, b ∈ t ∧ r a b) - (ht : ∀ b ∈ t, ({ a ∈ s | r a b } : Set α).Subsingleton) : s.card ≤ t.card := by + (ht : ∀ b ∈ t, ({ a ∈ s | r a b } : Set α).Subsingleton) : #s ≤ #t := by classical - rw [← mul_one s.card, ← mul_one t.card] + rw [← mul_one #s, ← mul_one #t] exact card_mul_le_card_mul r (fun a h ↦ card_pos.2 (by rw [← coe_nonempty, coe_bipartiteAbove] @@ -183,7 +190,7 @@ theorem card_le_card_of_forall_subsingleton (hs : ∀ a ∈ s, ∃ b, b ∈ t exact ht _ h)) theorem card_le_card_of_forall_subsingleton' (ht : ∀ b ∈ t, ∃ a, a ∈ s ∧ r a b) - (hs : ∀ a ∈ s, ({ b ∈ t | r a b } : Set β).Subsingleton) : t.card ≤ s.card := + (hs : ∀ a ∈ s, ({ b ∈ t | r a b } : Set β).Subsingleton) : #t ≤ #s := card_le_card_of_forall_subsingleton (swap r) ht hs end Bipartite @@ -198,10 +205,10 @@ variable [Fintype α] [Fintype β] {r : α → β → Prop} theorem card_le_card_of_leftTotal_unique (h₁ : LeftTotal r) (h₂ : LeftUnique r) : Fintype.card α ≤ Fintype.card β := - card_le_card_of_forall_subsingleton r (by simpa using h₁) fun b _ a₁ ha₁ a₂ ha₂ ↦ h₂ ha₁.2 ha₂.2 + card_le_card_of_forall_subsingleton r (by simpa using h₁) fun _ _ _ ha₁ _ ha₂ ↦ h₂ ha₁.2 ha₂.2 theorem card_le_card_of_rightTotal_unique (h₁ : RightTotal r) (h₂ : RightUnique r) : Fintype.card β ≤ Fintype.card α := - card_le_card_of_forall_subsingleton' r (by simpa using h₁) fun b _ a₁ ha₁ a₂ ha₂ ↦ h₂ ha₁.2 ha₂.2 + card_le_card_of_forall_subsingleton' r (by simpa using h₁) fun _ _ _ ha₁ _ ha₂ ↦ h₂ ha₁.2 ha₂.2 end Fintype diff --git a/Mathlib/Combinatorics/Enumerative/DyckWord.lean b/Mathlib/Combinatorics/Enumerative/DyckWord.lean index 220e3d4c4f141..5924d03e54bd1 100644 --- a/Mathlib/Combinatorics/Enumerative/DyckWord.lean +++ b/Mathlib/Combinatorics/Enumerative/DyckWord.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Jeremy Tan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Tan -/ -import Batteries.Data.List.Count import Mathlib.Combinatorics.Enumerative.Catalan import Mathlib.Tactic.Positivity @@ -406,8 +405,8 @@ section Order instance : Preorder DyckWord where le := Relation.ReflTransGen (fun p q ↦ p = q.insidePart ∨ p = q.outsidePart) - le_refl p := Relation.ReflTransGen.refl - le_trans p q r := Relation.ReflTransGen.trans + le_refl _ := Relation.ReflTransGen.refl + le_trans _ _ _ := Relation.ReflTransGen.trans lemma le_add_self (p q : DyckWord) : q ≤ p + q := by by_cases h : p = 0 diff --git a/Mathlib/Combinatorics/HalesJewett.lean b/Mathlib/Combinatorics/HalesJewett.lean index f02b849012141..76bb5d7812114 100644 --- a/Mathlib/Combinatorics/HalesJewett.lean +++ b/Mathlib/Combinatorics/HalesJewett.lean @@ -6,6 +6,7 @@ Authors: David Wärn import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Data.Fintype.Option import Mathlib.Data.Fintype.Shrink +import Mathlib.Data.Fintype.Sum /-! # The Hales-Jewett theorem @@ -137,7 +138,7 @@ variable {η' α' ι' : Type*} def reindex (l : Subspace η α ι) (eη : η ≃ η') (eα : α ≃ α') (eι : ι ≃ ι') : Subspace η' α' ι' where idxFun i := (l.idxFun <| eι.symm i).map eα eη proper e := (eι.exists_congr fun i ↦ by cases h : idxFun l i <;> - simp [*, Function.funext_iff, Equiv.eq_symm_apply]).1 <| l.proper <| eη.symm e + simp [*, funext_iff, Equiv.eq_symm_apply]).1 <| l.proper <| eη.symm e @[simp] lemma reindex_apply (l : Subspace η α ι) (eη : η ≃ η') (eα : α ≃ α') (eι : ι ≃ ι') (x i) : l.reindex eη eα eι x i = eα (l (eα.symm ∘ x ∘ eη) <| eι.symm i) := by diff --git a/Mathlib/Combinatorics/Hall/Basic.lean b/Mathlib/Combinatorics/Hall/Basic.lean index 52a8937ef3082..da15e7bee4a35 100644 --- a/Mathlib/Combinatorics/Hall/Basic.lean +++ b/Mathlib/Combinatorics/Hall/Basic.lean @@ -50,8 +50,7 @@ The core of this module is constructing the inverse system: for every finite sub Hall's Marriage Theorem, indexed families -/ - -open Finset CategoryTheory +open Finset Function CategoryTheory universe u v @@ -71,7 +70,7 @@ def hallMatchingsOn.restrict {ι : Type u} {α : Type v} (t : ι → Finset α) /-- When the Hall condition is satisfied, the set of matchings on a finite set is nonempty. This is where `Finset.all_card_le_biUnion_card_iff_existsInjective'` comes into the argument. -/ theorem hallMatchingsOn.nonempty {ι : Type u} {α : Type v} [DecidableEq α] (t : ι → Finset α) - (h : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) (ι' : Finset ι) : + (h : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) (ι' : Finset ι) : Nonempty (hallMatchingsOn t ι') := by classical refine ⟨Classical.indefiniteDescription _ ?_⟩ @@ -86,7 +85,7 @@ theorem hallMatchingsOn.nonempty {ι : Type u} {α : Type v} [DecidableEq α] (t def hallMatchingsFunctor {ι : Type u} {α : Type v} (t : ι → Finset α) : (Finset ι)ᵒᵖ ⥤ Type max u v where obj ι' := hallMatchingsOn t ι'.unop - map {ι' ι''} g f := hallMatchingsOn.restrict t (CategoryTheory.leOfHom g.unop) f + map {_ _} g f := hallMatchingsOn.restrict t (CategoryTheory.leOfHom g.unop) f instance hallMatchingsOn.finite {ι : Type u} {α : Type v} (t : ι → Finset α) (ι' : Finset ι) : Finite (hallMatchingsOn t ι') := by @@ -100,7 +99,7 @@ instance hallMatchingsOn.finite {ι : Type u} {α : Type v} (t : ι → Finset apply Finite.of_injective g intro f f' h ext a - rw [Function.funext_iff] at h + rw [funext_iff] at h simpa [g] using h a /-- This is the version of **Hall's Marriage Theorem** in terms of indexed @@ -115,7 +114,7 @@ which has the additional constraint that `ι` is a `Fintype`. -/ theorem Finset.all_card_le_biUnion_card_iff_exists_injective {ι : Type u} {α : Type v} [DecidableEq α] (t : ι → Finset α) : - (∀ s : Finset ι, s.card ≤ (s.biUnion t).card) ↔ + (∀ s : Finset ι, #s ≤ #(s.biUnion t)) ↔ ∃ f : ι → α, Function.Injective f ∧ ∀ x, f x ∈ t x := by constructor · intro h @@ -178,10 +177,10 @@ Note: if `[Fintype β]`, then there exist instances for `[∀ (a : α), Fintype -/ theorem Fintype.all_card_le_rel_image_card_iff_exists_injective {α : Type u} {β : Type v} [DecidableEq β] (r : α → β → Prop) [∀ a : α, Fintype (Rel.image r {a})] : - (∀ A : Finset α, A.card ≤ Fintype.card (Rel.image r A)) ↔ + (∀ A : Finset α, #A ≤ Fintype.card (Rel.image r A)) ↔ ∃ f : α → β, Function.Injective f ∧ ∀ x, r x (f x) := by let r' a := (Rel.image r {a}).toFinset - have h : ∀ A : Finset α, Fintype.card (Rel.image r A) = (A.biUnion r').card := by + have h : ∀ A : Finset α, Fintype.card (Rel.image r A) = #(A.biUnion r') := by intro A rw [← Set.toFinset_card] apply congr_arg @@ -203,11 +202,10 @@ rather than `Rel.image`. -/ theorem Fintype.all_card_le_filter_rel_iff_exists_injective {α : Type u} {β : Type v} [Fintype β] (r : α → β → Prop) [∀ a, DecidablePred (r a)] : - (∀ A : Finset α, A.card ≤ (univ.filter fun b : β => ∃ a ∈ A, r a b).card) ↔ - ∃ f : α → β, Function.Injective f ∧ ∀ x, r x (f x) := by + (∀ A : Finset α, #A ≤ #{b | ∃ a ∈ A, r a b}) ↔ ∃ f : α → β, Injective f ∧ ∀ x, r x (f x) := by haveI := Classical.decEq β - let r' a := univ.filter fun b => r a b - have h : ∀ A : Finset α, (univ.filter fun b : β => ∃ a ∈ A, r a b) = A.biUnion r' := by + let r' a : Finset β := {b | r a b} + have h : ∀ A : Finset α, ({b | ∃ a ∈ A, r a b} : Finset _) = A.biUnion r' := by intro A ext b simp [r'] diff --git a/Mathlib/Combinatorics/Hall/Finite.lean b/Mathlib/Combinatorics/Hall/Finite.lean index aadc2cf7010b8..a81d2cf78e3d0 100644 --- a/Mathlib/Combinatorics/Hall/Finite.lean +++ b/Mathlib/Combinatorics/Hall/Finite.lean @@ -46,13 +46,13 @@ section Fintype variable [Fintype ι] theorem hall_cond_of_erase {x : ι} (a : α) - (ha : ∀ s : Finset ι, s.Nonempty → s ≠ univ → s.card < (s.biUnion t).card) - (s' : Finset { x' : ι | x' ≠ x }) : s'.card ≤ (s'.biUnion fun x' => (t x').erase a).card := by + (ha : ∀ s : Finset ι, s.Nonempty → s ≠ univ → #s < #(s.biUnion t)) + (s' : Finset { x' : ι | x' ≠ x }) : #s' ≤ #(s'.biUnion fun x' => (t x').erase a) := by haveI := Classical.decEq ι specialize ha (s'.image fun z => z.1) rw [image_nonempty, Finset.card_image_of_injective s' Subtype.coe_injective] at ha by_cases he : s'.Nonempty - · have ha' : s'.card < (s'.biUnion fun x => t x).card := by + · have ha' : #s' < #(s'.biUnion fun x => t x) := by convert ha he fun h => by simpa [← h] using mem_univ x using 2 ext x simp only [mem_image, mem_biUnion, exists_prop, SetCoe.exists, exists_and_right, @@ -68,18 +68,18 @@ theorem hall_cond_of_erase {x : ι} (a : α) simp /-- First case of the inductive step: assuming that -`∀ (s : Finset ι), s.Nonempty → s ≠ univ → s.card < (s.biUnion t).card` +`∀ (s : Finset ι), s.Nonempty → s ≠ univ → #s < #(s.biUnion t)` and that the statement of **Hall's Marriage Theorem** is true for all `ι'` of cardinality ≤ `n`, then it is true for `ι` of cardinality `n + 1`. -/ theorem hall_hard_inductive_step_A {n : ℕ} (hn : Fintype.card ι = n + 1) - (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) + (ht : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) (ih : ∀ {ι' : Type u} [Fintype ι'] (t' : ι' → Finset α), Fintype.card ι' ≤ n → - (∀ s' : Finset ι', s'.card ≤ (s'.biUnion t').card) → + (∀ s' : Finset ι', #s' ≤ #(s'.biUnion t')) → ∃ f : ι' → α, Function.Injective f ∧ ∀ x, f x ∈ t' x) - (ha : ∀ s : Finset ι, s.Nonempty → s ≠ univ → s.card < (s.biUnion t).card) : + (ha : ∀ s : Finset ι, s.Nonempty → s ≠ univ → #s < #(s.biUnion t)) : ∃ f : ι → α, Function.Injective f ∧ ∀ x, f x ∈ t x := by haveI : Nonempty ι := Fintype.card_pos_iff.mp (hn.symm ▸ Nat.succ_pos _) haveI := Classical.decEq ι @@ -89,7 +89,7 @@ theorem hall_hard_inductive_step_A {n : ℕ} (hn : Fintype.card ι = n + 1) rw [← Finset.card_pos] calc 0 < 1 := Nat.one_pos - _ ≤ (Finset.biUnion {x} t).card := ht {x} + _ ≤ #(.biUnion {x} t) := ht {x} _ = (t x).card := by rw [Finset.singleton_biUnion] choose y hy using tx_ne @@ -118,8 +118,8 @@ theorem hall_hard_inductive_step_A {n : ℕ} (hn : Fintype.card ι = n + 1) exact hfr.2 theorem hall_cond_of_restrict {ι : Type u} {t : ι → Finset α} {s : Finset ι} - (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) (s' : Finset (s : Set ι)) : - s'.card ≤ (s'.biUnion fun a' => t a').card := by + (ht : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) (s' : Finset (s : Set ι)) : + #s' ≤ #(s'.biUnion fun a' => t a') := by classical rw [← card_image_of_injective s' Subtype.coe_injective] convert ht (s'.image fun z => z.1) using 1 @@ -128,15 +128,15 @@ theorem hall_cond_of_restrict {ι : Type u} {t : ι → Finset α} {s : Finset simp theorem hall_cond_of_compl {ι : Type u} {t : ι → Finset α} {s : Finset ι} - (hus : s.card = (s.biUnion t).card) (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) - (s' : Finset (sᶜ : Set ι)) : s'.card ≤ (s'.biUnion fun x' => t x' \ s.biUnion t).card := by + (hus : #s = #(s.biUnion t)) (ht : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) + (s' : Finset (sᶜ : Set ι)) : #s' ≤ #(s'.biUnion fun x' => t x' \ s.biUnion t) := by haveI := Classical.decEq ι have disj : Disjoint s (s'.image fun z => z.1) := by simp only [disjoint_left, not_exists, mem_image, exists_prop, SetCoe.exists, exists_and_right, exists_eq_right, Subtype.coe_mk] intro x hx hc _ exact absurd hx hc - have : s'.card = (s ∪ s'.image fun z => z.1).card - s.card := by + have : #s' = #(s ∪ s'.image fun z => z.1) - #s := by simp [disj, card_image_of_injective _ Subtype.coe_injective, Nat.add_sub_cancel_left] rw [this, hus] refine (Nat.sub_le_sub_right (ht _) _).trans ?_ @@ -152,18 +152,18 @@ theorem hall_cond_of_compl {ι : Type u} {t : ι → Finset α} {s : Finset ι} apply subset_union_left /-- Second case of the inductive step: assuming that -`∃ (s : Finset ι), s ≠ univ → s.card = (s.biUnion t).card` +`∃ (s : Finset ι), s ≠ univ → #s = #(s.biUnion t)` and that the statement of **Hall's Marriage Theorem** is true for all `ι'` of cardinality ≤ `n`, then it is true for `ι` of cardinality `n + 1`. -/ theorem hall_hard_inductive_step_B {n : ℕ} (hn : Fintype.card ι = n + 1) - (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) + (ht : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) (ih : ∀ {ι' : Type u} [Fintype ι'] (t' : ι' → Finset α), Fintype.card ι' ≤ n → - (∀ s' : Finset ι', s'.card ≤ (s'.biUnion t').card) → + (∀ s' : Finset ι', #s' ≤ #(s'.biUnion t')) → ∃ f : ι' → α, Function.Injective f ∧ ∀ x, f x ∈ t' x) - (s : Finset ι) (hs : s.Nonempty) (hns : s ≠ univ) (hus : s.card = (s.biUnion t).card) : + (s : Finset ι) (hs : s.Nonempty) (hns : s ≠ univ) (hus : #s = #(s.biUnion t)) : ∃ f : ι → α, Function.Injective f ∧ ∀ x, f x ∈ t x := by haveI := Classical.decEq ι -- Restrict to `s` @@ -171,7 +171,7 @@ theorem hall_hard_inductive_step_B {n : ℕ} (hn : Fintype.card ι = n + 1) have card_ι'_le : Fintype.card s ≤ n := by apply Nat.le_of_lt_succ calc - Fintype.card s = s.card := Fintype.card_coe _ + Fintype.card s = #s := Fintype.card_coe _ _ < Fintype.card ι := (card_lt_iff_ne_univ _).mpr hns _ = n.succ := hn let t' : s → Finset α := fun x' => t x' @@ -214,7 +214,7 @@ variable [Finite ι] /-- Here we combine the two inductive steps into a full strong induction proof, completing the proof the harder direction of **Hall's Marriage Theorem**. -/ -theorem hall_hard_inductive (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).card) : +theorem hall_hard_inductive (ht : ∀ s : Finset ι, #s ≤ #(s.biUnion t)) : ∃ f : ι → α, Function.Injective f ∧ ∀ x, f x ∈ t x := by cases nonempty_fintype ι induction' hn : Fintype.card ι using Nat.strong_induction_on with n ih generalizing ι @@ -222,11 +222,11 @@ theorem hall_hard_inductive (ht : ∀ s : Finset ι, s.card ≤ (s.biUnion t).ca · rw [Fintype.card_eq_zero_iff] at hn exact ⟨isEmptyElim, isEmptyElim, isEmptyElim⟩ · have ih' : ∀ (ι' : Type u) [Fintype ι'] (t' : ι' → Finset α), Fintype.card ι' ≤ n → - (∀ s' : Finset ι', s'.card ≤ (s'.biUnion t').card) → + (∀ s' : Finset ι', #s' ≤ #(s'.biUnion t')) → ∃ f : ι' → α, Function.Injective f ∧ ∀ x, f x ∈ t' x := by intro ι' _ _ hι' ht' exact ih _ (Nat.lt_succ_of_le hι') ht' _ rfl - by_cases h : ∀ s : Finset ι, s.Nonempty → s ≠ univ → s.card < (s.biUnion t).card + by_cases h : ∀ s : Finset ι, s.Nonempty → s ≠ univ → #s < #(s.biUnion t) · refine hall_hard_inductive_step_A hn ht (@fun ι' => ih' ι') h · push_neg at h rcases h with ⟨s, sne, snu, sle⟩ @@ -245,7 +245,7 @@ where the `Finite ι` constraint is removed. -/ theorem Finset.all_card_le_biUnion_card_iff_existsInjective' {ι α : Type*} [Finite ι] [DecidableEq α] (t : ι → Finset α) : - (∀ s : Finset ι, s.card ≤ (s.biUnion t).card) ↔ + (∀ s : Finset ι, #s ≤ #(s.biUnion t)) ↔ ∃ f : ι → α, Function.Injective f ∧ ∀ x, f x ∈ t x := by constructor · exact HallMarriageTheorem.hall_hard_inductive diff --git a/Mathlib/Combinatorics/Hindman.lean b/Mathlib/Combinatorics/Hindman.lean index 18555bba2e080..25e45662baf0d 100644 --- a/Mathlib/Combinatorics/Hindman.lean +++ b/Mathlib/Combinatorics/Hindman.lean @@ -66,8 +66,7 @@ def Ultrafilter.semigroup {M} [Semigroup M] : Semigroup (Ultrafilter M) := { Ultrafilter.mul with mul_assoc := fun U V W => Ultrafilter.coe_inj.mp <| - -- porting note (#11083): `simp` was slow to typecheck, replaced by `simp_rw` - Filter.ext' fun p => by simp_rw [Ultrafilter.eventually_mul, mul_assoc] } + Filter.ext' fun p => by simp [Ultrafilter.eventually_mul, mul_assoc] } attribute [local instance] Ultrafilter.semigroup Ultrafilter.addSemigroup diff --git a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean index 5063e0e98009e..956feba606f04 100644 --- a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean +++ b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean @@ -159,10 +159,10 @@ lemma Function.HasMaxCutProperty.forbids_commutativeFractionalPolymorphism rw [Fin.sum_univ_two', ← mcfab.left, ← two_nsmul] at contr have sharp : 2 • ((ω.tt ![![a, b], ![b, a]]).map (fun _ => f ![a, b])).sum < - 2 • ((ω.tt ![![a, b], ![b, a]]).map (fun r => f r)).sum := by + 2 • ((ω.tt ![![a, b], ![b, a]]).map f).sum := by have half_sharp : ((ω.tt ![![a, b], ![b, a]]).map (fun _ => f ![a, b])).sum < - ((ω.tt ![![a, b], ![b, a]]).map (fun r => f r)).sum := by + ((ω.tt ![![a, b], ![b, a]]).map f).sum := by apply Multiset.sum_lt_sum · intro r rin exact le_of_lt (mcfab.rows_lt_aux hab symmega rin) diff --git a/Mathlib/Combinatorics/Pigeonhole.lean b/Mathlib/Combinatorics/Pigeonhole.lean index 3811b73e8b204..fe51886fb9187 100644 --- a/Mathlib/Combinatorics/Pigeonhole.lean +++ b/Mathlib/Combinatorics/Pigeonhole.lean @@ -4,10 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller, Yury Kudryashov -/ import Mathlib.Algebra.Module.BigOperators -import Mathlib.Algebra.Module.Defs -import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.Nat.ModEq -import Mathlib.Data.Set.Finite /-! # Pigeonhole principles @@ -34,14 +32,14 @@ The versions vary by: * using a function between `Fintype`s or a function between possibly infinite types restricted to `Finset`s; -* counting pigeons by a general weight function (`∑ x ∈ s, w x`) or by heads (`Finset.card s`); +* counting pigeons by a general weight function (`∑ x ∈ s, w x`) or by heads (`#s`); * using strict or non-strict inequalities; * establishing upper or lower estimate on the number (or the total weight) of the pigeons in one pigeonhole; * in case when we count pigeons by some weight function `w` and consider a function `f` between `Finset`s `s` and `t`, we can either assume that each pigeon is in one of the pigeonholes (`∀ x ∈ s, f x ∈ t`), or assume that for `y ∉ t`, the total weight of the pigeons in this - pigeonhole `∑ x ∈ s.filter (fun x ↦ f x = y), w x` is nonpositive or nonnegative depending on + pigeonhole `∑ x ∈ s with f x = y, w x` is nonpositive or nonnegative depending on the inequality we are proving. Lemma names follow `mathlib` convention (e.g., @@ -82,15 +80,14 @@ variations of this theorem. The principle is formalized in the following way, see `Finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum`: if `f : α → β` is a function which maps all -elements of `s : Finset α` to `t : Finset β` and `card t • b < ∑ x ∈ s, w x`, where `w : α → M` is +elements of `s : Finset α` to `t : Finset β` and `#t • b < ∑ x ∈ s, w x`, where `w : α → M` is a weight function taking values in a `LinearOrderedCancelAddCommMonoid`, then for some `y ∈ t`, the sum of the weights of all `x ∈ s` such that `f x = y` is greater than `b`. There are a few bits we can change in this theorem: * reverse all inequalities, with obvious adjustments to the name; -* replace the assumption `∀ a ∈ s, f a ∈ t` with - `∀ y ∉ t, (∑ x ∈ s.filter (fun x ↦ f x = y), w x) ≤ 0`, +* replace the assumption `∀ a ∈ s, f a ∈ t` with `∀ y ∉ t, ∑ x ∈ s with f x = y, w x ≤ 0`, and replace `of_maps_to` with `of_sum_fiber_nonpos` in the name; * use non-strict inequalities assuming `t` is nonempty. @@ -111,7 +108,7 @@ if the total weight of a finite set of pigeons is greater than `n • b`, and th `n` pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is greater than `b`. -/ theorem exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum (hf : ∀ a ∈ s, f a ∈ t) - (hb : t.card • b < ∑ x ∈ s, w x) : ∃ y ∈ t, b < ∑ x ∈ s.filter fun x => f x = y, w x := + (hb : #t • b < ∑ x ∈ s, w x) : ∃ y ∈ t, b < ∑ x ∈ s with f x = y, w x := exists_lt_of_sum_lt <| by simpa only [sum_fiberwise_of_maps_to hf, sum_const] /-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version: @@ -119,7 +116,7 @@ if the total weight of a finite set of pigeons is less than `n • b`, and they pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is less than `b`. -/ theorem exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul (hf : ∀ a ∈ s, f a ∈ t) - (hb : ∑ x ∈ s, w x < t.card • b) : ∃ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x < b := + (hb : ∑ x ∈ s, w x < #t • b) : ∃ y ∈ t, ∑ x ∈ s with f x = y, w x < b := exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum (M := Mᵒᵈ) hf hb /-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version: @@ -128,13 +125,12 @@ pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons the then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is greater than `b`. -/ theorem exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum - (ht : ∀ y ∉ t, ∑ x ∈ s.filter fun x => f x = y, w x ≤ 0) - (hb : t.card • b < ∑ x ∈ s, w x) : ∃ y ∈ t, b < ∑ x ∈ s.filter fun x => f x = y, w x := + (ht : ∀ y ∉ t, ∑ x ∈ s with f x = y, w x ≤ 0) + (hb : #t • b < ∑ x ∈ s, w x) : ∃ y ∈ t, b < ∑ x ∈ s with f x = y, w x := exists_lt_of_sum_lt <| calc ∑ _y ∈ t, b < ∑ x ∈ s, w x := by simpa - _ ≤ ∑ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x := - sum_le_sum_fiberwise_of_sum_fiber_nonpos ht + _ ≤ ∑ y ∈ t, ∑ x ∈ s with f x = y, w x := sum_le_sum_fiberwise_of_sum_fiber_nonpos ht /-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version: if the total weight of a finite set of pigeons is less than `n • b`, they are sorted into some @@ -142,8 +138,8 @@ pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons the then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is less than `b`. -/ theorem exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul - (ht : ∀ y ∉ t, (0 : M) ≤ ∑ x ∈ s.filter fun x => f x = y, w x) - (hb : ∑ x ∈ s, w x < t.card • b) : ∃ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x < b := + (ht : ∀ y ∉ t, (0 : M) ≤ ∑ x ∈ s with f x = y, w x) (hb : ∑ x ∈ s, w x < #t • b) : + ∃ y ∈ t, ∑ x ∈ s with f x = y, w x < b := exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum (M := Mᵒᵈ) ht hb /-! @@ -156,7 +152,7 @@ version: if the total weight of a finite set of pigeons is greater than or equal they are sorted into `n > 0` pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is greater than or equal to `b`. -/ theorem exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty) - (hb : t.card • b ≤ ∑ x ∈ s, w x) : ∃ y ∈ t, b ≤ ∑ x ∈ s.filter fun x => f x = y, w x := + (hb : #t • b ≤ ∑ x ∈ s, w x) : ∃ y ∈ t, b ≤ ∑ x ∈ s with f x = y, w x := exists_le_of_sum_le ht <| by simpa only [sum_fiberwise_of_maps_to hf, sum_const] /-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality @@ -164,7 +160,7 @@ version: if the total weight of a finite set of pigeons is less than or equal to are sorted into `n > 0` pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is less than or equal to `b`. -/ theorem exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty) - (hb : ∑ x ∈ s, w x ≤ t.card • b) : ∃ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x ≤ b := + (hb : ∑ x ∈ s, w x ≤ #t • b) : ∃ y ∈ t, ∑ x ∈ s with f x = y, w x ≤ b := exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum (M := Mᵒᵈ) hf ht hb /-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality @@ -173,12 +169,12 @@ are sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total pigeons there is nonpositive, then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is greater than or equal to `b`. -/ theorem exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum - (hf : ∀ y ∉ t, ∑ x ∈ s.filter fun x => f x = y, w x ≤ 0) (ht : t.Nonempty) - (hb : t.card • b ≤ ∑ x ∈ s, w x) : ∃ y ∈ t, b ≤ ∑ x ∈ s.filter fun x => f x = y, w x := + (hf : ∀ y ∉ t, ∑ x ∈ s with f x = y, w x ≤ 0) (ht : t.Nonempty) + (hb : #t • b ≤ ∑ x ∈ s, w x) : ∃ y ∈ t, b ≤ ∑ x ∈ s with f x = y, w x := exists_le_of_sum_le ht <| calc ∑ _y ∈ t, b ≤ ∑ x ∈ s, w x := by simpa - _ ≤ ∑ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x := + _ ≤ ∑ y ∈ t, ∑ x ∈ s with f x = y, w x := sum_le_sum_fiberwise_of_sum_fiber_nonpos hf /-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality @@ -187,8 +183,8 @@ sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total weig there is nonnegative, then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is less than or equal to `b`. -/ theorem exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul - (hf : ∀ y ∉ t, (0 : M) ≤ ∑ x ∈ s.filter fun x => f x = y, w x) (ht : t.Nonempty) - (hb : ∑ x ∈ s, w x ≤ t.card • b) : ∃ y ∈ t, ∑ x ∈ s.filter fun x => f x = y, w x ≤ b := + (hf : ∀ y ∉ t, (0 : M) ≤ ∑ x ∈ s with f x = y, w x) (ht : t.Nonempty) + (hb : ∑ x ∈ s, w x ≤ #t • b) : ∃ y ∈ t, ∑ x ∈ s with f x = y, w x ≤ b := exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum (M := Mᵒᵈ) hf ht hb end @@ -216,7 +212,7 @@ So, we prove four theorems: `Finset.exists_lt_card_fiber_of_maps_to_of_mul_lt_ca /-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes. -/ theorem exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) - (ht : t.card • b < s.card) : ∃ y ∈ t, b < (s.filter fun x => f x = y).card := by + (ht : #t • b < #s) : ∃ y ∈ t, b < #{x ∈ s | f x = y} := by simp_rw [cast_card] at ht ⊢ exact exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum hf ht @@ -225,16 +221,16 @@ at least as many pigeons as the ceiling of the average number of pigeons across ("The maximum is at least the mean" specialized to integers.) More formally, given a function between finite sets `s` and `t` and a natural number `n` such that -`card t * n < card s`, there exists `y ∈ t` such that its preimage in `s` has more than `n` +`#t * n < #s`, there exists `y ∈ t` such that its preimage in `s` has more than `n` elements. -/ theorem exists_lt_card_fiber_of_mul_lt_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) - (hn : t.card * n < s.card) : ∃ y ∈ t, n < (s.filter fun x => f x = y).card := + (hn : #t * n < #s) : ∃ y ∈ t, n < #{x ∈ s | f x = y} := exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to hf hn /-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. -/ -theorem exists_card_fiber_lt_of_card_lt_nsmul (ht : ↑s.card < t.card • b) : - ∃ y ∈ t, ↑(s.filter fun x => f x = y).card < b := by +theorem exists_card_fiber_lt_of_card_lt_nsmul (ht : #s < #t • b) : + ∃ y ∈ t, #{x ∈ s | f x = y} < b := by simp_rw [cast_card] at ht ⊢ exact exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul @@ -245,35 +241,34 @@ at most as many pigeons as the floor of the average number of pigeons across all minimum is at most the mean" specialized to integers.) More formally, given a function `f`, a finite sets `s` in its domain, a finite set `t` in its -codomain, and a natural number `n` such that `card s < card t * n`, there exists `y ∈ t` such that +codomain, and a natural number `n` such that `#s < #t * n`, there exists `y ∈ t` such that its preimage in `s` has less than `n` elements. -/ -theorem exists_card_fiber_lt_of_card_lt_mul (hn : s.card < t.card * n) : - ∃ y ∈ t, (s.filter fun x => f x = y).card < n := +theorem exists_card_fiber_lt_of_card_lt_mul (hn : #s < #t * n) : ∃ y ∈ t, #{x ∈ s | f x = y} < n := exists_card_fiber_lt_of_card_lt_nsmul hn /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between -finite sets `s` and `t` and a number `b` such that `card t • b ≤ card s`, there exists `y ∈ t` such +finite sets `s` and `t` and a number `b` such that `#t • b ≤ #s`, there exists `y ∈ t` such that its preimage in `s` has at least `b` elements. See also `Finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to` for a stronger statement. -/ theorem exists_le_card_fiber_of_nsmul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty) - (hb : t.card • b ≤ s.card) : ∃ y ∈ t, b ≤ (s.filter fun x => f x = y).card := by + (hb : #t • b ≤ #s) : ∃ y ∈ t, b ≤ #{x ∈ s | f x = y} := by simp_rw [cast_card] at hb ⊢ exact exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum hf ht hb /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between -finite sets `s` and `t` and a natural number `b` such that `card t * n ≤ card s`, there exists +finite sets `s` and `t` and a natural number `b` such that `#t * n ≤ #s`, there exists `y ∈ t` such that its preimage in `s` has at least `n` elements. See also `Finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to` for a stronger statement. -/ theorem exists_le_card_fiber_of_mul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty) - (hn : t.card * n ≤ s.card) : ∃ y ∈ t, n ≤ (s.filter fun x => f x = y).card := + (hn : #t * n ≤ #s) : ∃ y ∈ t, n ≤ #{x ∈ s | f x = y} := exists_le_card_fiber_of_nsmul_le_card_of_maps_to hf ht hn /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a -finite sets `s` and `t`, and a number `b` such that `card s ≤ card t • b`, there exists `y ∈ t` such +finite sets `s` and `t`, and a number `b` such that `#s ≤ #t • b`, there exists `y ∈ t` such that its preimage in `s` has no more than `b` elements. See also `Finset.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/ -theorem exists_card_fiber_le_of_card_le_nsmul (ht : t.Nonempty) (hb : ↑s.card ≤ t.card • b) : - ∃ y ∈ t, ↑(s.filter fun x => f x = y).card ≤ b := by +theorem exists_card_fiber_le_of_card_le_nsmul (ht : t.Nonempty) (hb : #s ≤ #t • b) : + ∃ y ∈ t, #{x ∈ s | f x = y} ≤ b := by simp_rw [cast_card] at hb ⊢ refine exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul @@ -281,10 +276,10 @@ theorem exists_card_fiber_le_of_card_le_nsmul (ht : t.Nonempty) (hb : ↑s.card /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a finite sets `s` in its domain, a finite set `t` in its codomain, and a natural number `n` such that -`card s ≤ card t * n`, there exists `y ∈ t` such that its preimage in `s` has no more than `n` +`#s ≤ #t * n`, there exists `y ∈ t` such that its preimage in `s` has no more than `n` elements. See also `Finset.exists_card_fiber_lt_of_card_lt_mul` for a stronger statement. -/ -theorem exists_card_fiber_le_of_card_le_mul (ht : t.Nonempty) (hn : s.card ≤ t.card * n) : - ∃ y ∈ t, (s.filter fun x => f x = y).card ≤ n := +theorem exists_card_fiber_le_of_card_le_mul (ht : t.Nonempty) (hn : #s ≤ #t * n) : + ∃ y ∈ t, #{x ∈ s | f x = y} ≤ n := exists_card_fiber_le_of_card_le_nsmul ht hn end Finset @@ -311,7 +306,7 @@ holds, so we have four theorems instead of eight. -/ version: there is a pigeonhole with the total weight of pigeons in it greater than `b` provided that the total number of pigeonholes times `b` is less than the total weight of all pigeons. -/ theorem exists_lt_sum_fiber_of_nsmul_lt_sum (hb : card β • b < ∑ x, w x) : - ∃ y, b < ∑ x ∈ univ.filter fun x => f x = y, w x := + ∃ y, b < ∑ x with f x = y, w x := let ⟨y, _, hy⟩ := exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum (fun _ _ => mem_univ _) hb ⟨y, hy⟩ @@ -320,7 +315,7 @@ version: there is a pigeonhole with the total weight of pigeons in it greater th provided that the total number of pigeonholes times `b` is less than or equal to the total weight of all pigeons. -/ theorem exists_le_sum_fiber_of_nsmul_le_sum [Nonempty β] (hb : card β • b ≤ ∑ x, w x) : - ∃ y, b ≤ ∑ x ∈ univ.filter fun x => f x = y, w x := + ∃ y, b ≤ ∑ x with f x = y, w x := let ⟨y, _, hy⟩ := exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum (fun _ _ => mem_univ _) univ_nonempty hb ⟨y, hy⟩ @@ -329,7 +324,7 @@ theorem exists_le_sum_fiber_of_nsmul_le_sum [Nonempty β] (hb : card β • b version: there is a pigeonhole with the total weight of pigeons in it less than `b` provided that the total number of pigeonholes times `b` is greater than the total weight of all pigeons. -/ theorem exists_sum_fiber_lt_of_sum_lt_nsmul (hb : ∑ x, w x < card β • b) : - ∃ y, ∑ x ∈ univ.filter fun x => f x = y, w x < b := + ∃ y, ∑ x with f x = y, w x < b := exists_lt_sum_fiber_of_nsmul_lt_sum (M := Mᵒᵈ) _ hb /-- The pigeonhole principle for finitely many pigeons of different weights, non-strict inequality @@ -337,7 +332,7 @@ version: there is a pigeonhole with the total weight of pigeons in it less than provided that the total number of pigeonholes times `b` is greater than or equal to the total weight of all pigeons. -/ theorem exists_sum_fiber_le_of_sum_le_nsmul [Nonempty β] (hb : ∑ x, w x ≤ card β • b) : - ∃ y, ∑ x ∈ univ.filter fun x => f x = y, w x ≤ b := + ∃ y, ∑ x with f x = y, w x ≤ b := exists_le_sum_fiber_of_nsmul_le_sum (M := Mᵒᵈ) _ hb end @@ -348,7 +343,7 @@ variable [LinearOrderedCommSemiring M] with at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes. -/ theorem exists_lt_card_fiber_of_nsmul_lt_card (hb : card β • b < card α) : - ∃ y : β, b < (univ.filter fun x => f x = y).card := + ∃ y : β, b < #{x | f x = y} := let ⟨y, _, h⟩ := exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (fun _ _ => mem_univ _) hb ⟨y, h⟩ @@ -361,14 +356,14 @@ More formally, given a function `f` between finite types `α` and `β` and a num `card β * n < card α`, there exists an element `y : β` such that its preimage has more than `n` elements. -/ theorem exists_lt_card_fiber_of_mul_lt_card (hn : card β * n < card α) : - ∃ y : β, n < (univ.filter fun x => f x = y).card := + ∃ y : β, n < #{x | f x = y} := exists_lt_card_fiber_of_nsmul_lt_card _ hn /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole with at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. -/ theorem exists_card_fiber_lt_of_card_lt_nsmul (hb : ↑(card α) < card β • b) : - ∃ y : β, ↑(univ.filter fun x => f x = y).card < b := + ∃ y : β, #{x | f x = y} < b := let ⟨y, _, h⟩ := Finset.exists_card_fiber_lt_of_card_lt_nsmul (f := f) hb ⟨y, h⟩ @@ -381,7 +376,7 @@ More formally, given a function `f` between finite types `α` and `β` and a num `card α < card β * n`, there exists an element `y : β` such that its preimage has less than `n` elements. -/ theorem exists_card_fiber_lt_of_card_lt_mul (hn : card α < card β * n) : - ∃ y : β, (univ.filter fun x => f x = y).card < n := + ∃ y : β, #{x | f x = y} < n := exists_card_fiber_lt_of_card_lt_nsmul _ hn /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` @@ -389,7 +384,7 @@ between finite types `α` and `β` and a number `b` such that `card β • b ≤ element `y : β` such that its preimage has at least `b` elements. See also `Fintype.exists_lt_card_fiber_of_nsmul_lt_card` for a stronger statement. -/ theorem exists_le_card_fiber_of_nsmul_le_card [Nonempty β] (hb : card β • b ≤ card α) : - ∃ y : β, b ≤ (univ.filter fun x => f x = y).card := + ∃ y : β, b ≤ #{x | f x = y} := let ⟨y, _, h⟩ := exists_le_card_fiber_of_nsmul_le_card_of_maps_to (fun _ _ => mem_univ _) univ_nonempty hb ⟨y, h⟩ @@ -399,7 +394,7 @@ between finite types `α` and `β` and a number `n` such that `card β * n ≤ c element `y : β` such that its preimage has at least `n` elements. See also `Fintype.exists_lt_card_fiber_of_mul_lt_card` for a stronger statement. -/ theorem exists_le_card_fiber_of_mul_le_card [Nonempty β] (hn : card β * n ≤ card α) : - ∃ y : β, n ≤ (univ.filter fun x => f x = y).card := + ∃ y : β, n ≤ #{x | f x = y} := exists_le_card_fiber_of_nsmul_le_card _ hn /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` @@ -407,7 +402,7 @@ between finite types `α` and `β` and a number `b` such that `card α ≤ card element `y : β` such that its preimage has at most `b` elements. See also `Fintype.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/ theorem exists_card_fiber_le_of_card_le_nsmul [Nonempty β] (hb : ↑(card α) ≤ card β • b) : - ∃ y : β, ↑(univ.filter fun x => f x = y).card ≤ b := + ∃ y : β, #{x | f x = y} ≤ b := let ⟨y, _, h⟩ := Finset.exists_card_fiber_le_of_card_le_nsmul univ_nonempty hb ⟨y, h⟩ @@ -416,7 +411,7 @@ between finite types `α` and `β` and a number `n` such that `card α ≤ card element `y : β` such that its preimage has at most `n` elements. See also `Fintype.exists_card_fiber_lt_of_card_lt_mul` for a stronger statement. -/ theorem exists_card_fiber_le_of_card_le_mul [Nonempty β] (hn : card α ≤ card β * n) : - ∃ y : β, (univ.filter fun x => f x = y).card ≤ n := + ∃ y : β, #{x | f x = y} ≤ n := exists_card_fiber_le_of_card_le_nsmul _ hn end Fintype diff --git a/Mathlib/Combinatorics/Quiver/Basic.lean b/Mathlib/Combinatorics/Quiver/Basic.lean index f0f77f70aa4b7..78d2fbdeef06a 100644 --- a/Mathlib/Combinatorics/Quiver/Basic.lean +++ b/Mathlib/Combinatorics/Quiver/Basic.lean @@ -137,6 +137,15 @@ def Hom.op {V} [Quiver V] {X Y : V} (f : X ⟶ Y) : op Y ⟶ op X := ⟨f⟩ /-- Given an arrow in `Vᵒᵖ`, we can take the "unopposite" back in `V`. -/ def Hom.unop {V} [Quiver V] {X Y : Vᵒᵖ} (f : X ⟶ Y) : unop Y ⟶ unop X := Opposite.unop f +/-- The bijection `(X ⟶ Y) ≃ (op Y ⟶ op X)`. -/ +@[simps] +def Hom.opEquiv {V} [Quiver V] {X Y : V} : + (X ⟶ Y) ≃ (Opposite.op Y ⟶ Opposite.op X) where + toFun := Opposite.op + invFun := Opposite.unop + left_inv _ := rfl + right_inv _ := rfl + /-- A type synonym for a quiver with no arrows. -/ -- Porting note(#5171): this linter isn't ported yet. -- @[nolint has_nonempty_instance] diff --git a/Mathlib/Combinatorics/Quiver/Path.lean b/Mathlib/Combinatorics/Quiver/Path.lean index d87402e7fb551..39dbcf18bda83 100644 --- a/Mathlib/Combinatorics/Quiver/Path.lean +++ b/Mathlib/Combinatorics/Quiver/Path.lean @@ -72,6 +72,11 @@ theorem eq_of_length_zero (p : Path a b) (hzero : p.length = 0) : a = b := by · rfl · cases Nat.succ_ne_zero _ hzero +theorem eq_nil_of_length_zero (p : Path a a) (hzero : p.length = 0) : p = nil := by + cases p + · rfl + · simp at hzero + /-- Composition of paths. -/ def comp {a b : V} : ∀ {c}, Path a b → Path b c → Path a c | _, p, nil => p @@ -139,6 +144,22 @@ theorem comp_inj_left {p₁ p₂ : Path a b} {q : Path b c} : p₁.comp q = p₂ theorem comp_inj_right {p : Path a b} {q₁ q₂ : Path b c} : p.comp q₁ = p.comp q₂ ↔ q₁ = q₂ := p.comp_injective_right.eq_iff +lemma eq_toPath_comp_of_length_eq_succ (p : Path a b) {n : ℕ} + (hp : p.length = n + 1) : + ∃ (c : V) (f : a ⟶ c) (q : Quiver.Path c b) (_ : q.length = n), + p = f.toPath.comp q := by + induction p generalizing n with + | nil => simp at hp + | @cons c d p q h => + cases n + · rw [length_cons, Nat.zero_add, Nat.add_left_eq_self] at hp + obtain rfl := eq_of_length_zero p hp + obtain rfl := eq_nil_of_length_zero p hp + exact ⟨d, q, nil, rfl, rfl⟩ + · rw [length_cons, Nat.add_right_cancel_iff] at hp + obtain ⟨x, q'', p'', hl, rfl⟩ := h hp + exact ⟨x, q'', p''.cons q, by simpa, rfl⟩ + /-- Turn a path into a list. The list contains `a` at its head, but not `b` a priori. -/ @[simp] def toList : ∀ {b : V}, Path a b → List V diff --git a/Mathlib/Combinatorics/Schnirelmann.lean b/Mathlib/Combinatorics/Schnirelmann.lean index 266093dff23ab..537681ba1dae9 100644 --- a/Mathlib/Combinatorics/Schnirelmann.lean +++ b/Mathlib/Combinatorics/Schnirelmann.lean @@ -47,7 +47,7 @@ open Finset /-- The Schnirelmann density is defined as the infimum of |A ∩ {1, ..., n}| / n as n ranges over the positive naturals. -/ noncomputable def schnirelmannDensity (A : Set ℕ) [DecidablePred (· ∈ A)] : ℝ := - ⨅ n : {n : ℕ // 0 < n}, ((Ioc (0 : ℕ) n).filter (· ∈ A)).card / n + ⨅ n : {n : ℕ // 0 < n}, #{a ∈ Ioc 0 n | a ∈ A} / n section @@ -57,7 +57,7 @@ lemma schnirelmannDensity_nonneg : 0 ≤ schnirelmannDensity A := Real.iInf_nonneg (fun _ => by positivity) lemma schnirelmannDensity_le_div {n : ℕ} (hn : n ≠ 0) : - schnirelmannDensity A ≤ ((Ioc 0 n).filter (· ∈ A)).card / n := + schnirelmannDensity A ≤ #{a ∈ Ioc 0 n | a ∈ A} / n := ciInf_le ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩ (⟨n, hn.bot_lt⟩ : {n : ℕ // 0 < n}) /-- @@ -65,7 +65,7 @@ For any natural `n`, the Schnirelmann density multiplied by `n` is bounded by `| Note this property fails for the natural density. -/ lemma schnirelmannDensity_mul_le_card_filter {n : ℕ} : - schnirelmannDensity A * n ≤ ((Ioc 0 n).filter (· ∈ A)).card := by + schnirelmannDensity A * n ≤ #{a ∈ Ioc 0 n | a ∈ A} := by rcases eq_or_ne n 0 with rfl | hn · simp exact (le_div_iff₀ (by positivity)).1 (schnirelmannDensity_le_div hn) @@ -78,7 +78,7 @@ We provide `n` explicitly here to make this lemma more easily usable in `apply` This lemma is analogous to `ciInf_le_of_le`. -/ lemma schnirelmannDensity_le_of_le {x : ℝ} (n : ℕ) (hn : n ≠ 0) - (hx : ((Ioc 0 n).filter (· ∈ A)).card / n ≤ x) : schnirelmannDensity A ≤ x := + (hx : #{a ∈ Ioc 0 n | a ∈ A} / n ≤ x) : schnirelmannDensity A ≤ x := (schnirelmannDensity_le_div hn).trans hx lemma schnirelmannDensity_le_one : schnirelmannDensity A ≤ 1 := @@ -96,7 +96,7 @@ lemma schnirelmannDensity_le_of_not_mem {k : ℕ} (hk : k ∉ A) : rw [← one_div, one_sub_div (Nat.cast_pos.2 hk').ne'] gcongr rw [← Nat.cast_pred hk', Nat.cast_le] - suffices (Ioc 0 k).filter (· ∈ A) ⊆ Ioo 0 k from (card_le_card this).trans_eq (by simp) + suffices {a ∈ Ioc 0 k | a ∈ A} ⊆ Ioo 0 k from (card_le_card this).trans_eq (by simp) rw [← Ioo_insert_right hk', filter_insert, if_neg hk] exact filter_subset _ _ @@ -138,16 +138,16 @@ lemma schnirelmannDensity_eq_one_iff_of_zero_mem (hA : 0 ∈ A) : exact Set.subset_univ {0}ᶜ lemma le_schnirelmannDensity_iff {x : ℝ} : - x ≤ schnirelmannDensity A ↔ ∀ n : ℕ, 0 < n → x ≤ ((Ioc 0 n).filter (· ∈ A)).card / n := + x ≤ schnirelmannDensity A ↔ ∀ n : ℕ, 0 < n → x ≤ #{a ∈ Ioc 0 n | a ∈ A} / n := (le_ciInf_iff ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩).trans Subtype.forall lemma schnirelmannDensity_lt_iff {x : ℝ} : - schnirelmannDensity A < x ↔ ∃ n : ℕ, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < x := by + schnirelmannDensity A < x ↔ ∃ n : ℕ, 0 < n ∧ #{a ∈ Ioc 0 n | a ∈ A} / n < x := by rw [← not_le, le_schnirelmannDensity_iff]; simp lemma schnirelmannDensity_le_iff_forall {x : ℝ} : schnirelmannDensity A ≤ x ↔ - ∀ ε : ℝ, 0 < ε → ∃ n : ℕ, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < x + ε := by + ∀ ε : ℝ, 0 < ε → ∃ n : ℕ, 0 < n ∧ #{a ∈ Ioc 0 n | a ∈ A} / n < x + ε := by rw [le_iff_forall_pos_lt_add] simp only [schnirelmannDensity_lt_iff] @@ -175,7 +175,7 @@ If the Schnirelmann density is `0`, there is a positive natural for which Note this cannot be improved to `∃ᶠ n : ℕ in atTop`, as can be seen by `A = {1}ᶜ`. -/ lemma exists_of_schnirelmannDensity_eq_zero {ε : ℝ} (hε : 0 < ε) (hA : schnirelmannDensity A = 0) : - ∃ n, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < ε := by + ∃ n, 0 < n ∧ #{a ∈ Ioc 0 n | a ∈ A} / n < ε := by by_contra! h rw [← le_schnirelmannDensity_iff] at h linarith @@ -193,7 +193,7 @@ lemma schnirelmannDensity_finset (A : Finset ℕ) : schnirelmannDensity A = 0 := wlog hε₁ : ε ≤ 1 generalizing ε · obtain ⟨n, hn, hn'⟩ := this 1 zero_lt_one le_rfl exact ⟨n, hn, hn'.trans_le (le_of_not_le hε₁)⟩ - let n : ℕ := ⌊A.card / ε⌋₊ + 1 + let n : ℕ := ⌊#A / ε⌋₊ + 1 have hn : 0 < n := Nat.succ_pos _ use n, hn rw [div_lt_iff₀ (Nat.cast_pos.2 hn), ← div_lt_iff₀' hε, Nat.cast_add_one] @@ -236,7 +236,7 @@ lemma schnirelmannDensity_setOf_mod_eq_one {m : ℕ} (hm : m ≠ 1) : rw [le_schnirelmannDensity_iff] intro n hn simp only [Set.mem_setOf_eq] - have : (Icc 0 ((n - 1) / m)).image (· * m + 1) ⊆ (Ioc 0 n).filter (· % m = 1) := by + have : (Icc 0 ((n - 1) / m)).image (· * m + 1) ⊆ {x ∈ Ioc 0 n | x % m = 1} := by simp only [subset_iff, mem_image, forall_exists_index, mem_filter, mem_Ioc, mem_Icc, and_imp] rintro _ y _ hy' rfl have hm : 2 ≤ m := hm.lt_of_le' hm' diff --git a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean index ea08e4e2baeef..d2173e136b147 100644 --- a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean +++ b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean @@ -6,10 +6,8 @@ Authors: Yaël Dillies, Vladimir Ivanov import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Algebra.Order.Field.Basic import Mathlib.Data.Finset.Sups import Mathlib.Tactic.FieldSimp -import Mathlib.Tactic.Positivity.Basic import Mathlib.Tactic.Ring /-! @@ -71,11 +69,11 @@ private lemma binomial_sum_eq (h : n < m) : ring private lemma Fintype.sum_div_mul_card_choose_card : - ∑ s : Finset α, (card α / ((card α - s.card) * (card α).choose s.card) : ℚ) = + ∑ s : Finset α, (card α / ((card α - #s) * (card α).choose #s) : ℚ) = card α * ∑ k ∈ range (card α), (↑k)⁻¹ + 1 := by rw [← powerset_univ, powerset_card_disjiUnion, sum_disjiUnion] have : ∀ {x : ℕ}, ∀ s ∈ powersetCard x (univ : Finset α), - (card α / ((card α - Finset.card s) * (card α).choose (Finset.card s)) : ℚ) = + (card α / ((card α - #s) * (card α).choose #s) : ℚ) = card α / ((card α - x) * (card α).choose x) := by intros n s hs rw [mem_powersetCard_univ.1 hs] @@ -102,11 +100,9 @@ variable {α β : Type*} /-! ### Truncated supremum, truncated infimum -/ section SemilatticeSup -variable [SemilatticeSup α] [SemilatticeSup β] - [BoundedOrder β] {s t : Finset α} {a b : α} +variable [SemilatticeSup α] [SemilatticeSup β] [BoundedOrder β] {s t : Finset α} {a : α} -private lemma sup_aux [@DecidableRel α (· ≤ ·)] : - a ∈ lowerClosure s → (s.filter fun b ↦ 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 α] : @@ -117,10 +113,10 @@ variable [@DecidableRel α (· ≤ ·)] [OrderTop α] /-- The supremum of the elements of `s` less than `a` if there are some, otherwise `⊤`. -/ def truncatedSup (s : Finset α) (a : α) : α := - if h : a ∈ lowerClosure s then (s.filter fun b ↦ a ≤ b).sup' (sup_aux h) id else ⊤ + if h : a ∈ lowerClosure s then {b ∈ s | a ≤ b}.sup' (sup_aux h) id else ⊤ lemma truncatedSup_of_mem (h : a ∈ lowerClosure s) : - truncatedSup s a = (s.filter fun b ↦ a ≤ b).sup' (sup_aux h) id := dif_pos h + truncatedSup s a = {b ∈ s | a ≤ b}.sup' (sup_aux h) id := dif_pos h lemma truncatedSup_of_not_mem (h : a ∉ lowerClosure s) : truncatedSup s a = ⊤ := dif_neg h @@ -179,7 +175,7 @@ section SemilatticeInf variable [SemilatticeInf α] [SemilatticeInf β] [BoundedOrder β] [@DecidableRel β (· ≤ ·)] {s t : Finset α} {a : α} -private lemma inf_aux [@DecidableRel α (· ≤ ·)]: a ∈ upperClosure s → (s.filter (· ≤ 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 α] : @@ -190,10 +186,10 @@ variable [@DecidableRel α (· ≤ ·)] [BoundedOrder α] /-- The infimum of the elements of `s` less than `a` if there are some, otherwise `⊥`. -/ def truncatedInf (s : Finset α) (a : α) : α := - if h : a ∈ upperClosure s then (s.filter (· ≤ a)).inf' (inf_aux h) id else ⊥ + if h : a ∈ upperClosure s then {b ∈ s | b ≤ a}.inf' (inf_aux h) id else ⊥ lemma truncatedInf_of_mem (h : a ∈ upperClosure s) : - truncatedInf s a = (s.filter (· ≤ a)).inf' (inf_aux h) id := dif_pos h + truncatedInf s a = {b ∈ s | b ≤ a}.inf' (inf_aux h) id := dif_pos h lemma truncatedInf_of_not_mem (h : a ∉ upperClosure s) : truncatedInf s a = ⊥ := dif_neg h @@ -286,7 +282,7 @@ lemma truncatedInf_sups_of_not_mem (ha : a ∉ upperClosure s ⊔ upperClosure t end DistribLattice section BooleanAlgebra -variable [BooleanAlgebra α] [@DecidableRel α (· ≤ ·)] {s : Finset α} {a : α} +variable [BooleanAlgebra α] [@DecidableRel α (· ≤ ·)] @[simp] lemma compl_truncatedSup (s : Finset α) (a : α) : (truncatedSup s a)ᶜ = truncatedInf sᶜˢ aᶜ := map_truncatedSup (OrderIso.compl α) _ _ @@ -299,8 +295,8 @@ end BooleanAlgebra variable [DecidableEq α] [Fintype α] lemma card_truncatedSup_union_add_card_truncatedSup_infs (𝒜 ℬ : Finset (Finset α)) (s : Finset α) : - (truncatedSup (𝒜 ∪ ℬ) s).card + (truncatedSup (𝒜 ⊼ ℬ) s).card = - (truncatedSup 𝒜 s).card + (truncatedSup ℬ s).card := by + #(truncatedSup (𝒜 ∪ ℬ) s) + #(truncatedSup (𝒜 ⊼ ℬ) s) = + #(truncatedSup 𝒜 s) + #(truncatedSup ℬ s) := by by_cases h𝒜 : s ∈ lowerClosure (𝒜 : Set <| Finset α) <;> by_cases hℬ : s ∈ lowerClosure (ℬ : Set <| Finset α) · rw [truncatedSup_union h𝒜 hℬ, truncatedSup_infs h𝒜 hℬ] @@ -313,8 +309,8 @@ lemma card_truncatedSup_union_add_card_truncatedSup_infs (𝒜 ℬ : Finset (Fin truncatedSup_union_of_not_mem h𝒜 hℬ, truncatedSup_infs_of_not_mem fun h ↦ h𝒜 h.1] lemma card_truncatedInf_union_add_card_truncatedInf_sups (𝒜 ℬ : Finset (Finset α)) (s : Finset α) : - (truncatedInf (𝒜 ∪ ℬ) s).card + (truncatedInf (𝒜 ⊻ ℬ) s).card = - (truncatedInf 𝒜 s).card + (truncatedInf ℬ s).card := by + #(truncatedInf (𝒜 ∪ ℬ) s) + #(truncatedInf (𝒜 ⊻ ℬ) s) = + #(truncatedInf 𝒜 s) + #(truncatedInf ℬ s) := by by_cases h𝒜 : s ∈ upperClosure (𝒜 : Set <| Finset α) <;> by_cases hℬ : s ∈ upperClosure (ℬ : Set <| Finset α) · rw [truncatedInf_union h𝒜 hℬ, truncatedInf_sups h𝒜 hℬ] @@ -332,17 +328,17 @@ open Finset hiding card open Fintype Nat namespace AhlswedeZhang -variable {α : Type*} [Fintype α] [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s : Finset α} +variable {α : Type*} [Fintype α] [DecidableEq α] {𝒜 : Finset (Finset α)} {s : Finset α} /-- Weighted sum of the size of the truncated infima of a set family. Relevant to the Ahlswede-Zhang identity. -/ def infSum (𝒜 : Finset (Finset α)) : ℚ := - ∑ s, (truncatedInf 𝒜 s).card / (s.card * (card α).choose s.card) + ∑ s, #(truncatedInf 𝒜 s) / (#s * (card α).choose #s) /-- Weighted sum of the size of the truncated suprema of a set family. Relevant to the Ahlswede-Zhang identity. -/ def supSum (𝒜 : Finset (Finset α)) : ℚ := - ∑ s, (truncatedSup 𝒜 s).card / ((card α - s.card) * (card α).choose s.card) + ∑ s, #(truncatedSup 𝒜 s) / ((card α - #s) * (card α).choose #s) lemma supSum_union_add_supSum_infs (𝒜 ℬ : Finset (Finset α)) : supSum (𝒜 ∪ ℬ) + supSum (𝒜 ⊼ ℬ) = supSum 𝒜 + supSum ℬ := by @@ -359,9 +355,9 @@ lemma infSum_union_add_infSum_sups (𝒜 ℬ : Finset (Finset α)) : simp lemma IsAntichain.le_infSum (h𝒜 : IsAntichain (· ⊆ ·) (𝒜 : Set (Finset α))) (h𝒜₀ : ∅ ∉ 𝒜) : - ∑ s ∈ 𝒜, ((card α).choose s.card : ℚ)⁻¹ ≤ infSum 𝒜 := by + ∑ s ∈ 𝒜, ((card α).choose #s : ℚ)⁻¹ ≤ infSum 𝒜 := by calc - _ = ∑ s ∈ 𝒜, (truncatedInf 𝒜 s).card / (s.card * (card α).choose s.card : ℚ) := ?_ + _ = ∑ s ∈ 𝒜, #(truncatedInf 𝒜 s) / (#s * (card α).choose #s : ℚ) := ?_ _ ≤ _ := sum_le_univ_sum_of_nonneg fun s ↦ by positivity refine sum_congr rfl fun s hs ↦ ?_ rw [truncatedInf_of_isAntichain h𝒜 hs, div_mul_cancel_left₀] @@ -373,8 +369,8 @@ variable [Nonempty α] @[simp] lemma supSum_singleton (hs : s ≠ univ) : supSum ({s} : Finset (Finset α)) = card α * ∑ k ∈ range (card α), (k : ℚ)⁻¹ := by have : ∀ t : Finset α, - (card α - (truncatedSup {s} t).card : ℚ) / ((card α - t.card) * (card α).choose t.card) = - if t ⊆ s then (card α - s.card : ℚ) / ((card α - t.card) * (card α).choose t.card) else 0 := by + (card α - #(truncatedSup {s} t) : ℚ) / ((card α - #t) * (card α).choose #t) = + if t ⊆ s then (card α - #s : ℚ) / ((card α - #t) * (card α).choose #t) else 0 := by rintro t simp_rw [truncatedSup_singleton, le_iff_subset] split_ifs <;> simp [card_univ] @@ -384,7 +380,7 @@ variable [Nonempty α] sum_powerset, ← binomial_sum_eq ((card_lt_iff_ne_univ _).2 hs), eq_comm] refine sum_congr rfl fun n _ ↦ ?_ rw [mul_div_assoc, ← nsmul_eq_mul] - exact sum_powersetCard n s fun m ↦ (card α - s.card : ℚ) / ((card α - m) * (card α).choose m) + exact sum_powersetCard n s fun m ↦ (card α - #s : ℚ) / ((card α - m) * (card α).choose m) /-- The **Ahlswede-Zhang Identity**. -/ lemma infSum_compls_add_supSum (𝒜 : Finset (Finset α)) : diff --git a/Mathlib/Combinatorics/SetFamily/CauchyDavenport.lean b/Mathlib/Combinatorics/SetFamily/CauchyDavenport.lean index aed46e2c9d07d..9bd497ebf7c8b 100644 --- a/Mathlib/Combinatorics/SetFamily/CauchyDavenport.lean +++ b/Mathlib/Combinatorics/SetFamily/CauchyDavenport.lean @@ -71,27 +71,24 @@ variable [Group α] [DecidableEq α] {x y : Finset α × Finset α} {s t : Finse * or `|s₁ + t₁| = |s₂ + t₂|` and `|s₂| + |t₂| < |s₁| + |t₁|` * or `|s₁ + t₁| = |s₂ + t₂|` and `|s₁| + |t₁| = |s₂| + |t₂|` and `|s₁| < |s₂|`."] private def DevosMulRel : Finset α × Finset α → Finset α × Finset α → Prop := - Prod.Lex (· < ·) (Prod.Lex (· > ·) (· < ·)) on fun x ↦ - ((x.1 * x.2).card, x.1.card + x.2.card, x.1.card) + Prod.Lex (· < ·) (Prod.Lex (· > ·) (· < ·)) on fun x ↦ (#(x.1 * x.2), #x.1 + #x.2, #x.1) @[to_additive] private lemma devosMulRel_iff : DevosMulRel x y ↔ - (x.1 * x.2).card < (y.1 * y.2).card ∨ - (x.1 * x.2).card = (y.1 * y.2).card ∧ y.1.card + y.2.card < x.1.card + x.2.card ∨ - (x.1 * x.2).card = (y.1 * y.2).card ∧ - x.1.card + x.2.card = y.1.card + y.2.card ∧ x.1.card < y.1.card := by + #(x.1 * x.2) < #(y.1 * y.2) ∨ + #(x.1 * x.2) = #(y.1 * y.2) ∧ #y.1 + #y.2 < #x.1 + #x.2 ∨ + #(x.1 * x.2) = #(y.1 * y.2) ∧ #x.1 + #x.2 = #y.1 + #y.2 ∧ #x.1 < #y.1 := by simp [DevosMulRel, Prod.lex_iff, and_or_left] @[to_additive] -private lemma devosMulRel_of_le (mul : (x.1 * x.2).card ≤ (y.1 * y.2).card) - (hadd : y.1.card + y.2.card < x.1.card + x.2.card) : DevosMulRel x y := +private lemma devosMulRel_of_le (mul : #(x.1 * x.2) ≤ #(y.1 * y.2)) + (hadd : #y.1 + #y.2 < #x.1 + #x.2) : DevosMulRel x y := devosMulRel_iff.2 <| mul.lt_or_eq.imp_right fun h ↦ Or.inl ⟨h, hadd⟩ @[to_additive] -private lemma devosMulRel_of_le_of_le (mul : (x.1 * x.2).card ≤ (y.1 * y.2).card) - (hadd : y.1.card + y.2.card ≤ x.1.card + x.2.card) (hone : x.1.card < y.1.card) : - DevosMulRel x y := +private lemma devosMulRel_of_le_of_le (mul : #(x.1 * x.2) ≤ #(y.1 * y.2)) + (hadd : #y.1 + #y.2 ≤ #x.1 + #x.2) (hone : #x.1 < #y.1) : DevosMulRel x y := devosMulRel_iff.2 <| mul.lt_or_eq.imp_right fun h ↦ hadd.gt_or_eq.imp (And.intro h) fun h' ↦ ⟨h, h', hone⟩ @@ -113,20 +110,20 @@ subgroup. -/ `s + t` is lower-bounded by `|s| + |t| - 1` unless this quantity is greater than the size of the smallest subgroup."] lemma Finset.min_le_card_mul (hs : s.Nonempty) (ht : t.Nonempty) : - min (minOrder α) ↑(s.card + t.card - 1) ≤ (s * t).card := by + min (minOrder α) ↑(#s + #t - 1) ≤ #(s * t) := by -- Set up the induction on `x := (s, t)` along the `DevosMulRel` relation. set x := (s, t) with hx clear_value x simp only [Prod.ext_iff] at hx obtain ⟨rfl, rfl⟩ := hx refine wellFoundedOn_devosMulRel.induction (P := fun x : Finset α × Finset α ↦ - min (minOrder α) ↑(card x.1 + card x.2 - 1) ≤ card (x.1 * x.2)) ⟨hs, ht⟩ ?_ + min (minOrder α) ↑(#x.1 + #x.2 - 1) ≤ #(x.1 * x.2)) ⟨hs, ht⟩ ?_ clear! x rintro ⟨s, t⟩ ⟨hs, ht⟩ ih simp only [min_le_iff, tsub_le_iff_right, Prod.forall, Set.mem_setOf_eq, and_imp, Nat.cast_le] at * - -- If `t.card < s.card`, we're done by the induction hypothesis on `(t⁻¹, s⁻¹)`. - obtain hts | hst := lt_or_le t.card s.card + -- If `#t < #s`, we're done by the induction hypothesis on `(t⁻¹, s⁻¹)`. + obtain hts | hst := lt_or_le #t #s · simpa only [← mul_inv_rev, add_comm, card_inv] using ih _ _ ht.inv hs.inv (devosMulRel_iff.2 <| Or.inr <| Or.inr <| by @@ -159,7 +156,7 @@ lemma Finset.min_le_card_mul (hs : s.Nonempty) (ht : t.Nonempty) : simp [-coe_smul_finset] -- Else, we can transform `s`, `t` to `s'`, `t'` and `s''`, `t''`, such that one of `(s', t')` and -- `(s'', t'')` is strictly smaller than `(s, t)` according to `DevosMulRel`. - replace hsg : (s ∩ op g • s).card < s.card := card_lt_card ⟨inter_subset_left, fun h ↦ + replace hsg : #(s ∩ op g • s) < #s := card_lt_card ⟨inter_subset_left, fun h ↦ hsg <| eq_of_superset_of_card_ge (h.trans inter_subset_right) (card_smul_finset _ _).le⟩ replace aux1 := card_mono <| mulETransformLeft.fst_mul_snd_subset g (s, t) replace aux2 := card_mono <| mulETransformRight.fst_mul_snd_subset g (s, t) @@ -184,7 +181,7 @@ by `|s| + |t| - 1`. -/ @[to_additive "The **Cauchy-Davenport theorem** for torsion-free groups. The size of `s + t` is lower-bounded by `|s| + |t| - 1`."] lemma Monoid.IsTorsionFree.card_add_card_sub_one_le_card_mul (h : IsTorsionFree α) - (hs : s.Nonempty) (ht : t.Nonempty) : s.card + t.card - 1 ≤ (s * t).card := by + (hs : s.Nonempty) (ht : t.Nonempty) : #s + #t - 1 ≤ #(s * t) := by simpa only [h.minOrder, min_eq_right, le_top, Nat.cast_le] using Finset.min_le_card_mul hs ht end General @@ -194,7 +191,7 @@ end General /-- The **Cauchy-Davenport Theorem**. If `s`, `t` are nonempty sets in $$ℤ/pℤ$$, then the size of `s + t` is lower-bounded by `|s| + |t| - 1`, unless this quantity is greater than `p`. -/ lemma ZMod.min_le_card_add {p : ℕ} (hp : p.Prime) {s t : Finset (ZMod p)} (hs : s.Nonempty) - (ht : t.Nonempty) : min p (s.card + t.card - 1) ≤ (s + t).card := by + (ht : t.Nonempty) : min p (#s + #t - 1) ≤ #(s + t) := by simpa only [ZMod.minOrder_of_prime hp, min_le_iff, Nat.cast_le] using Finset.min_le_card_add hs ht /-! ### Linearly ordered cancellative semigroups -/ @@ -205,8 +202,8 @@ lemma ZMod.min_le_card_add {p : ℕ} (hp : p.Prime) {s t : Finset (ZMod p)} (hs "The **Cauchy-Davenport theorem** for linearly ordered additive cancellative semigroups. The size of `s + t` is lower-bounded by `|s| + |t| - 1`."] lemma Finset.card_add_card_sub_one_le_card_mul [LinearOrder α] [Semigroup α] [IsCancelMul α] - [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (swap (· * ·)) (· ≤ ·)] - {s t : Finset α} (hs : s.Nonempty) (ht : t.Nonempty) : s.card + t.card - 1 ≤ (s * t).card := by + [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), ← card_union_add_card_inter, ← card_singleton _, ← this, Nat.add_sub_cancel] diff --git a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean index 222c68d63fd87..6a0dbfd4822da 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean @@ -35,18 +35,17 @@ compression, down-compression -/ -variable {α : Type*} [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s : Finset α} {a : α} +variable {α : Type*} [DecidableEq α] {𝒜 : Finset (Finset α)} {s : Finset α} {a : α} namespace Finset /-- Elements of `𝒜` that do not contain `a`. -/ -def nonMemberSubfamily (a : α) (𝒜 : Finset (Finset α)) : Finset (Finset α) := - 𝒜.filter fun s => a ∉ s +def nonMemberSubfamily (a : α) (𝒜 : Finset (Finset α)) : Finset (Finset α) := {s ∈ 𝒜 | a ∉ s} /-- Image of the elements of `𝒜` which contain `a` under removing `a`. Finsets that do not contain `a` such that `insert a s ∈ 𝒜`. -/ def memberSubfamily (a : α) (𝒜 : Finset (Finset α)) : Finset (Finset α) := - (𝒜.filter fun s => a ∈ s).image fun s => erase s a + {s ∈ 𝒜 | a ∈ s}.image fun s => erase s a @[simp] theorem mem_nonMemberSubfamily : s ∈ 𝒜.nonMemberSubfamily a ↔ s ∈ 𝒜 ∧ a ∉ s := by @@ -79,7 +78,7 @@ theorem memberSubfamily_union (a : α) (𝒜 ℬ : Finset (Finset α)) : simp_rw [memberSubfamily, filter_union, image_union] theorem card_memberSubfamily_add_card_nonMemberSubfamily (a : α) (𝒜 : Finset (Finset α)) : - (𝒜.memberSubfamily a).card + (𝒜.nonMemberSubfamily a).card = 𝒜.card := by + #(𝒜.memberSubfamily a) + #(𝒜.nonMemberSubfamily a) = #𝒜 := by rw [memberSubfamily, nonMemberSubfamily, card_image_of_injOn] · conv_rhs => rw [← filter_card_add_filter_neg_card_eq_card (fun s => (a ∈ s))] · apply (erase_injOn' _).mono @@ -136,7 +135,7 @@ lemma memberSubfamily_image_insert (h𝒜 : ∀ s ∈ 𝒜, a ∉ s) : (ne_of_mem_of_not_mem' (mem_insert_self _ _) (not_mem_erase _ _)).symm] lemma image_insert_memberSubfamily (𝒜 : Finset (Finset α)) (a : α) : - (𝒜.memberSubfamily a).image (insert a) = 𝒜.filter (a ∈ ·) := by + (𝒜.memberSubfamily a).image (insert a) = {s ∈ 𝒜 | a ∈ s} := by ext s simp only [mem_memberSubfamily, mem_image, mem_filter] refine ⟨?_, fun ⟨hs, ha⟩ ↦ ⟨erase s a, ⟨?_, not_mem_erase _ _⟩, insert_erase ha⟩⟩ @@ -182,7 +181,7 @@ it suffices to prove it for * `ℬ ∪ 𝒞` assuming the property for `ℬ` and `𝒞`, where `a` is an element of the ground type and `ℬ`is a family of finsets not containing `a` and `𝒞` a family of finsets containing `a`. Note that instead of giving `ℬ` and `𝒞`, the `subfamily` case gives you `𝒜 = ℬ ∪ 𝒞`, so that - `ℬ = 𝒜.filter (a ∉ ·)` and `𝒞 = 𝒜.filter (a ∈ ·)`. + `ℬ = {s ∈ 𝒜 | a ∉ s}` and `𝒞 = {s ∈ 𝒜 | a ∈ s}`. This is a way of formalising induction on `n` where `𝒜` is a finset family on `n` elements. @@ -193,7 +192,7 @@ protected lemma family_induction_on {p : Finset (Finset α) → Prop} (image_insert : ∀ (a : α) ⦃𝒜 : Finset (Finset α)⦄, (∀ s ∈ 𝒜, a ∉ s) → p 𝒜 → p (𝒜.image <| insert a)) (subfamily : ∀ (a : α) ⦃𝒜 : Finset (Finset α)⦄, - p (𝒜.filter (a ∉ ·)) → p (𝒜.filter (a ∈ ·)) → p 𝒜) : p 𝒜 := by + p {s ∈ 𝒜 | a ∉ s} → p {s ∈ 𝒜 | a ∈ s} → p 𝒜) : p 𝒜 := by refine memberFamily_induction_on 𝒜 empty singleton_empty fun a 𝒜 h𝒜₀ h𝒜₁ ↦ subfamily a h𝒜₀ ?_ rw [← image_insert_memberSubfamily] exact image_insert _ (by simp) h𝒜₁ @@ -208,11 +207,8 @@ namespace Down /-- `a`-down-compressing `𝒜` means removing `a` from the elements of `𝒜` that contain it, when the resulting Finset is not already in `𝒜`. -/ def compression (a : α) (𝒜 : Finset (Finset α)) : Finset (Finset α) := - (𝒜.filter fun s => erase s a ∈ 𝒜).disjUnion - ((𝒜.image fun s => erase s a).filter fun s => s ∉ 𝒜) <| - disjoint_left.2 fun s h₁ h₂ => by - have := (mem_filter.1 h₂).2 - exact this (mem_filter.1 h₁).1 + {s ∈ 𝒜 | erase s a ∈ 𝒜}.disjUnion {s ∈ 𝒜.image fun s ↦ erase s a | s ∉ 𝒜} <| + disjoint_left.2 fun _s h₁ h₂ ↦ (mem_filter.1 h₂).2 (mem_filter.1 h₁).1 @[inherit_doc] scoped[FinsetFamily] notation "𝓓 " => Down.compression @@ -258,7 +254,7 @@ theorem compression_idem (a : α) (𝒜 : Finset (Finset α)) : 𝓓 a (𝓓 a /-- Down-compressing a family doesn't change its size. -/ @[simp] -theorem card_compression (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).card = 𝒜.card := by +theorem card_compression (a : α) (𝒜 : Finset (Finset α)) : #(𝓓 a 𝒜) = #𝒜 := by rw [compression, card_disjUnion, filter_image, card_image_of_injOn ((erase_injOn' _).mono fun s hs => _), ← card_union_of_disjoint] · conv_rhs => rw [← filter_union_filter_neg_eq (fun s => (erase s a ∈ 𝒜)) 𝒜] diff --git a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean index 8bfa4e268eb8a..cb2a27b1ef1eb 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean @@ -70,7 +70,7 @@ namespace UV section GeneralizedBooleanAlgebra variable [GeneralizedBooleanAlgebra α] [DecidableRel (@Disjoint α _ _)] - [DecidableRel ((· ≤ ·) : α → α → Prop)] {s : Finset α} {u v a b : α} + [DecidableRel ((· ≤ ·) : α → α → Prop)] {s : Finset α} {u v a : α} /-- UV-compressing `a` means removing `v` from it and adding `u` if `a` and `u` are disjoint and `v ≤ a` (it replaces the `v` part of `a` by the `u` part). Else, UV-compressing `a` doesn't do @@ -116,7 +116,7 @@ variable [DecidableEq α] /-- To UV-compress a set family, we compress each of its elements, except that we don't want to reduce the cardinality, so we keep all elements whose compression is already present. -/ def compression (u v : α) (s : Finset α) := - (s.filter (compress u v · ∈ s)) ∪ (s.image <| compress u v).filter (· ∉ s) + {a ∈ s | compress u v a ∈ s} ∪ {a ∈ s.image <| compress u v | a ∉ s} @[inherit_doc] scoped[FinsetFamily] notation "𝓒 " => UV.compression @@ -128,7 +128,7 @@ def IsCompressed (u v : α) (s : Finset α) := 𝓒 u v s = s /-- UV-compression is injective on the sets that are not UV-compressed. -/ -theorem compress_injOn : Set.InjOn (compress u v) ↑(s.filter (compress u v · ∉ s)) := by +theorem compress_injOn : Set.InjOn (compress u v) ↑{a ∈ s | compress u v a ∉ s} := by intro a ha b hb hab rw [mem_coe, mem_filter] at ha hb rw [compress] at ha hab @@ -162,7 +162,7 @@ theorem compression_self (u : α) (s : Finset α) : 𝓒 u u s = s := by theorem isCompressed_self (u : α) (s : Finset α) : IsCompressed u u s := compression_self u s theorem compress_disjoint : - Disjoint (s.filter (compress u v · ∈ s)) ((s.image <| compress u v).filter (· ∉ s)) := + Disjoint {a ∈ s | compress u v a ∈ s} {a ∈ s.image <| compress u v | a ∉ s} := disjoint_left.2 fun _a ha₁ ha₂ ↦ (mem_filter.1 ha₂).2 (mem_filter.1 ha₁).1 theorem compress_mem_compression (ha : a ∈ s) : compress u v a ∈ 𝓒 u v s := by @@ -184,14 +184,14 @@ theorem compress_mem_compression_of_mem_compression (ha : a ∈ 𝓒 u v s) : /-- Compressing a family is idempotent. -/ @[simp] theorem compression_idem (u v : α) (s : Finset α) : 𝓒 u v (𝓒 u v s) = 𝓒 u v s := by - have h : filter (compress u v · ∉ 𝓒 u v s) (𝓒 u v s) = ∅ := + have h : {a ∈ 𝓒 u v s | compress u v a ∉ 𝓒 u v s} = ∅ := filter_false_of_mem fun a ha h ↦ h <| compress_mem_compression_of_mem_compression ha rw [compression, filter_image, h, image_empty, ← h] exact filter_union_filter_neg_eq _ (compression u v s) /-- Compressing a family doesn't change its size. -/ @[simp] -theorem card_compression (u v : α) (s : Finset α) : (𝓒 u v s).card = s.card := by +theorem card_compression (u v : α) (s : Finset α) : #(𝓒 u v s) = #s := by rw [compression, card_union_of_disjoint compress_disjoint, filter_image, card_image_of_injOn compress_injOn, ← card_union_of_disjoint (disjoint_filter_filter_neg s _ _), filter_union_filter_neg_eq] @@ -265,17 +265,17 @@ end GeneralizedBooleanAlgebra open FinsetFamily -variable [DecidableEq α] {𝒜 : Finset (Finset α)} {u v a : Finset α} {r : ℕ} +variable [DecidableEq α] {𝒜 : Finset (Finset α)} {u v : Finset α} {r : ℕ} /-- Compressing a finset doesn't change its size. -/ -theorem card_compress (huv : u.card = v.card) (a : Finset α) : (compress u v a).card = a.card := by +theorem card_compress (huv : #u = #v) (a : Finset α) : #(compress u v a) = #a := by unfold compress split_ifs with h · rw [card_sdiff (h.2.trans le_sup_left), sup_eq_union, card_union_of_disjoint h.1.symm, huv, add_tsub_cancel_right] · rfl -lemma _root_.Set.Sized.uvCompression (huv : u.card = v.card) (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : +lemma _root_.Set.Sized.uvCompression (huv : #u = #v) (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : (𝓒 u v 𝒜 : Set (Finset α)).Sized r := by simp_rw [Set.Sized, mem_coe, mem_compression] rintro s (hs | ⟨huvt, t, ht, rfl⟩) @@ -397,7 +397,7 @@ such that `𝒜` is `(u.erase x, v.erase y)`-compressed. This is the key UV-comp Kruskal-Katona. -/ theorem card_shadow_compression_le (u v : Finset α) (huv : ∀ x ∈ u, ∃ y ∈ v, IsCompressed (u.erase x) (v.erase y) 𝒜) : - (∂ (𝓒 u v 𝒜)).card ≤ (∂ 𝒜).card := + #(∂ (𝓒 u v 𝒜)) ≤ #(∂ 𝒜) := (card_le_card <| shadow_compression_subset_compression_shadow _ _ huv).trans (card_compression _ _ _).le diff --git a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean index d3bd37943cd19..7e044d51a7439 100644 --- a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean +++ b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean @@ -7,7 +7,6 @@ import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Algebra.Order.Pi import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Data.Finset.Sups -import Mathlib.Data.Set.Subsingleton import Mathlib.Order.Birkhoff import Mathlib.Order.Booleanisation import Mathlib.Order.Sublattice @@ -59,8 +58,8 @@ open scoped FinsetFamily variable {α β : Type*} section Finset -variable [DecidableEq α] [LinearOrderedCommSemiring β] {𝒜 ℬ : Finset (Finset α)} - {a : α} {f f₁ f₂ f₃ f₄ g μ : Finset α → β} {s t u : Finset α} +variable [DecidableEq α] [LinearOrderedCommSemiring β] {𝒜 : Finset (Finset α)} + {a : α} {f f₁ f₂ f₃ f₄ : Finset α → β} {s t u : Finset α} /-- The `n = 1` case of the Ahlswede-Daykin inequality. Note that we can't just expand everything out and bound termwise since `c₀ * d₁` appears twice on the RHS of the assumptions while `c₁ * d₀` @@ -88,7 +87,7 @@ private lemma ineq [ExistsAddOfLE β] {a₀ a₁ b₀ b₁ c₀ c₁ d₀ d₁ : _ = (c₀ * d₁ + c₁ * d₀) * (c₀ * d₁) := by ring private def collapse (𝒜 : Finset (Finset α)) (a : α) (f : Finset α → β) (s : Finset α) : β := - ∑ t ∈ 𝒜.filter fun t ↦ t.erase a = s, f t + ∑ t ∈ 𝒜 with t.erase a = s, f t private lemma erase_eq_iff (hs : a ∉ s) : t.erase a = s ↔ t = s ∨ t = insert a s := by by_cases ht : a ∈ t <;> @@ -96,7 +95,7 @@ private lemma erase_eq_iff (hs : a ∉ s) : t.erase a = s ↔ t = s ∨ t = inse aesop private lemma filter_collapse_eq (ha : a ∉ s) (𝒜 : Finset (Finset α)) : - (𝒜.filter fun t ↦ t.erase a = s) = + {t ∈ 𝒜 | t.erase a = s} = if s ∈ 𝒜 then (if insert a s ∈ 𝒜 then {s, insert a s} else {s}) else @@ -305,7 +304,7 @@ lemma four_functions_theorem [DecidableEq α] (h₁ : 0 ≤ f₁) (h₂ : 0 ≤ /-- An inequality of Daykin. Interestingly, any lattice in which this inequality holds is distributive. -/ lemma Finset.le_card_infs_mul_card_sups [DecidableEq α] (s t : Finset α) : - s.card * t.card ≤ (s ⊼ t).card * (s ⊻ t).card := by + #s * #t ≤ #(s ⊼ t) * #(s ⊻ t) := by simpa using four_functions_theorem (1 : α → ℕ) 1 1 1 zero_le_one zero_le_one zero_le_one zero_le_one (fun _ _ ↦ le_rfl) s t @@ -354,7 +353,7 @@ variable [DecidableEq α] [GeneralizedBooleanAlgebra α] /-- A slight generalisation of the **Marica-Schönheim Inequality**. -/ lemma Finset.le_card_diffs_mul_card_diffs (s t : Finset α) : - s.card * t.card ≤ (s \\ t).card * (t \\ s).card := by + #s * #t ≤ #(s \\ t) * #(t \\ s) := by have : ∀ s t : Finset α, (s \\ t).map ⟨_, liftLatticeHom_injective⟩ = s.map ⟨_, liftLatticeHom_injective⟩ \\ t.map ⟨_, liftLatticeHom_injective⟩ := by rintro s t @@ -365,6 +364,6 @@ lemma Finset.le_card_diffs_mul_card_diffs (s t : Finset α) : (t.map ⟨_, liftLatticeHom_injective⟩)ᶜˢ /-- The **Marica-Schönheim Inequality**. -/ -lemma Finset.card_le_card_diffs (s : Finset α) : s.card ≤ (s \\ s).card := +lemma Finset.card_le_card_diffs (s : Finset α) : #s ≤ #(s \\ s) := le_of_pow_le_pow_left two_ne_zero (zero_le _) <| by simpa [← sq] using s.le_card_diffs_mul_card_diffs s diff --git a/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean b/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean index 2a5e38dc5b5f6..49205ae8ec3d0 100644 --- a/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean @@ -11,8 +11,8 @@ import Mathlib.Data.Fintype.Powerset /-! # Harris-Kleitman inequality -This file proves the Harris-Kleitman inequality. This relates `𝒜.card * ℬ.card` and -`2 ^ card α * (𝒜 ∩ ℬ).card` where `𝒜` and `ℬ` are upward- or downcard-closed finite families of +This file proves the Harris-Kleitman inequality. This relates `#𝒜 * #ℬ` and +`2 ^ card α * #(𝒜 ∩ ℬ)` where `𝒜` and `ℬ` are upward- or downcard-closed finite families of finsets. This can be interpreted as saying that any two lower sets (resp. any two upper sets) correlate in the uniform measure. @@ -49,7 +49,7 @@ theorem IsLowerSet.memberSubfamily_subset_nonMemberSubfamily (h : IsLowerSet ( /-- **Harris-Kleitman inequality**: Any two lower sets of finsets correlate. -/ theorem IsLowerSet.le_card_inter_finset' (h𝒜 : IsLowerSet (𝒜 : Set (Finset α))) (hℬ : IsLowerSet (ℬ : Set (Finset α))) (h𝒜s : ∀ t ∈ 𝒜, t ⊆ s) (hℬs : ∀ t ∈ ℬ, t ⊆ s) : - 𝒜.card * ℬ.card ≤ 2 ^ s.card * (𝒜 ∩ ℬ).card := by + #𝒜 * #ℬ ≤ 2 ^ #s * #(𝒜 ∩ ℬ) := by induction' s using Finset.induction with a s hs ih generalizing 𝒜 ℬ · simp_rw [subset_empty, ← subset_singleton_iff', subset_singleton_iff] at h𝒜s hℬs obtain rfl | rfl := h𝒜s @@ -89,13 +89,13 @@ variable [Fintype α] /-- **Harris-Kleitman inequality**: Any two lower sets of finsets correlate. -/ theorem IsLowerSet.le_card_inter_finset (h𝒜 : IsLowerSet (𝒜 : Set (Finset α))) - (hℬ : IsLowerSet (ℬ : Set (Finset α))) : 𝒜.card * ℬ.card ≤ 2 ^ Fintype.card α * (𝒜 ∩ ℬ).card := + (hℬ : IsLowerSet (ℬ : Set (Finset α))) : #𝒜 * #ℬ ≤ 2 ^ Fintype.card α * #(𝒜 ∩ ℬ) := h𝒜.le_card_inter_finset' hℬ (fun _ _ => subset_univ _) fun _ _ => subset_univ _ /-- **Harris-Kleitman inequality**: Upper sets and lower sets of finsets anticorrelate. -/ theorem IsUpperSet.card_inter_le_finset (h𝒜 : IsUpperSet (𝒜 : Set (Finset α))) (hℬ : IsLowerSet (ℬ : Set (Finset α))) : - 2 ^ Fintype.card α * (𝒜 ∩ ℬ).card ≤ 𝒜.card * ℬ.card := by + 2 ^ Fintype.card α * #(𝒜 ∩ ℬ) ≤ #𝒜 * #ℬ := by rw [← isLowerSet_compl, ← coe_compl] at h𝒜 have := h𝒜.le_card_inter_finset hℬ rwa [card_compl, Fintype.card_finset, tsub_mul, tsub_le_iff_tsub_le, ← mul_tsub, ← @@ -105,14 +105,14 @@ theorem IsUpperSet.card_inter_le_finset (h𝒜 : IsUpperSet (𝒜 : Set (Finset /-- **Harris-Kleitman inequality**: Lower sets and upper sets of finsets anticorrelate. -/ theorem IsLowerSet.card_inter_le_finset (h𝒜 : IsLowerSet (𝒜 : Set (Finset α))) (hℬ : IsUpperSet (ℬ : Set (Finset α))) : - 2 ^ Fintype.card α * (𝒜 ∩ ℬ).card ≤ 𝒜.card * ℬ.card := by - rw [inter_comm, mul_comm 𝒜.card] + 2 ^ Fintype.card α * #(𝒜 ∩ ℬ) ≤ #𝒜 * #ℬ := by + rw [inter_comm, mul_comm #𝒜] exact hℬ.card_inter_le_finset h𝒜 /-- **Harris-Kleitman inequality**: Any two upper sets of finsets correlate. -/ theorem IsUpperSet.le_card_inter_finset (h𝒜 : IsUpperSet (𝒜 : Set (Finset α))) (hℬ : IsUpperSet (ℬ : Set (Finset α))) : - 𝒜.card * ℬ.card ≤ 2 ^ Fintype.card α * (𝒜 ∩ ℬ).card := by + #𝒜 * #ℬ ≤ 2 ^ Fintype.card α * #(𝒜 ∩ ℬ) := by rw [← isLowerSet_compl, ← coe_compl] at h𝒜 have := h𝒜.card_inter_le_finset hℬ rwa [card_compl, Fintype.card_finset, tsub_mul, le_tsub_iff_le_tsub, ← mul_tsub, ← diff --git a/Mathlib/Combinatorics/SetFamily/Intersecting.lean b/Mathlib/Combinatorics/SetFamily/Intersecting.lean index 11d2839e67959..456e133bdb79d 100644 --- a/Mathlib/Combinatorics/SetFamily/Intersecting.lean +++ b/Mathlib/Combinatorics/SetFamily/Intersecting.lean @@ -141,7 +141,7 @@ theorem Intersecting.disjoint_map_compl {s : Finset α} (hs : (s : Set α).Inter exact hs.not_compl_mem hx' hx theorem Intersecting.card_le [Fintype α] {s : Finset α} (hs : (s : Set α).Intersecting) : - 2 * s.card ≤ Fintype.card α := by + 2 * #s ≤ Fintype.card α := by classical refine (s.disjUnion _ hs.disjoint_map_compl).card_le_univ.trans_eq' ?_ rw [Nat.two_mul, card_disjUnion, card_map] @@ -150,7 +150,7 @@ variable [Nontrivial α] [Fintype α] {s : Finset α} -- Note, this lemma is false when `α` has exactly one element and boring when `α` is empty. theorem Intersecting.is_max_iff_card_eq (hs : (s : Set α).Intersecting) : - (∀ t : Finset α, (t : Set α).Intersecting → s ⊆ t → s = t) ↔ 2 * s.card = Fintype.card α := by + (∀ t : Finset α, (t : Set α).Intersecting → s ⊆ t → s = t) ↔ 2 * #s = Fintype.card α := by classical refine ⟨fun h ↦ ?_, fun h t ht hst ↦ Finset.eq_of_subset_of_card_le hst <| Nat.le_of_mul_le_mul_left (ht.card_le.trans_eq h.symm) Nat.two_pos⟩ @@ -171,7 +171,7 @@ theorem Intersecting.is_max_iff_card_eq (hs : (s : Set α).Intersecting) : exact Finset.singleton_ne_empty _ (this <| Finset.empty_subset _).symm theorem Intersecting.exists_card_eq (hs : (s : Set α).Intersecting) : - ∃ t, s ⊆ t ∧ 2 * t.card = Fintype.card α ∧ (t : Set α).Intersecting := by + ∃ t, s ⊆ t ∧ 2 * #t = Fintype.card α ∧ (t : Set α).Intersecting := by have := hs.card_le rw [mul_comm, ← Nat.le_div_iff_mul_le' Nat.two_pos] at this revert hs diff --git a/Mathlib/Combinatorics/SetFamily/Kleitman.lean b/Mathlib/Combinatorics/SetFamily/Kleitman.lean index e534f30f51b45..dfb8f4f8241c7 100644 --- a/Mathlib/Combinatorics/SetFamily/Kleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/Kleitman.lean @@ -34,11 +34,11 @@ variable {ι α : Type*} [Fintype α] [DecidableEq α] [Nonempty α] each further intersecting family takes at most half of the sets that are in no previous family. -/ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finset (Finset α)) (hf : ∀ i ∈ s, (f i : Set (Finset α)).Intersecting) : - (s.biUnion f).card ≤ 2 ^ Fintype.card α - 2 ^ (Fintype.card α - s.card) := by + #(s.biUnion f) ≤ 2 ^ Fintype.card α - 2 ^ (Fintype.card α - #s) := by have : DecidableEq ι := by classical infer_instance - obtain hs | hs := le_total (Fintype.card α) s.card + obtain hs | hs := le_total (Fintype.card α) #s · rw [tsub_eq_zero_of_le hs, pow_zero] refine (card_le_card <| biUnion_subset.2 fun i hi a ha ↦ mem_compl.2 <| not_mem_singleton.2 <| (hf _ hi).ne_bot ha).trans_eq ?_ @@ -47,7 +47,7 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse · simp set f' : ι → Finset (Finset α) := fun j ↦ if hj : j ∈ cons i s hi then (hf j hj).exists_card_eq.choose else ∅ - have hf₁ : ∀ j, j ∈ cons i s hi → f j ⊆ f' j ∧ 2 * (f' j).card = + have hf₁ : ∀ j, j ∈ cons i s hi → f j ⊆ f' j ∧ 2 * #(f' j) = 2 ^ Fintype.card α ∧ (f' j : Set (Finset α)).Intersecting := by rintro j hj simp_rw [f', dif_pos hj, ← Fintype.card_finset] diff --git a/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean index 8b5ce0135fec7..edfdf5d218350 100644 --- a/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean +++ b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean @@ -5,6 +5,8 @@ Authors: Bhavik Mehta, Yaël Dillies -/ import Mathlib.Combinatorics.Colex import Mathlib.Combinatorics.SetFamily.Compression.UV +import Mathlib.Combinatorics.SetFamily.Intersecting +import Mathlib.Data.Finset.Fin /-! # Kruskal-Katona theorem @@ -50,7 +52,7 @@ open scoped FinsetFamily namespace Finset namespace Colex -variable {α : Type*} [LinearOrder α] {𝒜 𝒜₁ 𝒜₂ : Finset (Finset α)} {s t : Finset α} {r : ℕ} +variable {α : Type*} [LinearOrder α] {𝒜 : Finset (Finset α)} {s : Finset α} {r : ℕ} /-- This is important for iterating Kruskal-Katona: the shadow of an initial segment is also an initial segment. -/ @@ -78,8 +80,8 @@ lemma shadow_initSeg [Fintype α] (hs : s.Nonempty) : -- Assume first t < s - min s, and take k as the colex witness for this have hjk : j ≤ k := min'_le _ _ (mem_compl.2 ‹k ∉ t›) have : j ∉ t := mem_compl.1 (min'_mem _ _) - have hcard : card s = card (insert j t) := by - rw [card_insert_of_not_mem ‹j ∉ t›, ← ‹_ = card t›, card_erase_add_one (min'_mem _ _)] + have hcard : #s = #(insert j t) := by + rw [card_insert_of_not_mem ‹j ∉ t›, ← ‹_ = #t›, card_erase_add_one (min'_mem _ _)] refine ⟨j, ‹_›, hcard, ?_⟩ -- Cases on j < k or j = k obtain hjk | r₁ := hjk.lt_or_eq @@ -119,7 +121,7 @@ protected lemma IsInitSeg.shadow [Finite α] (h₁ : IsInitSeg 𝒜 r) : IsInitS end Colex open Finset Colex Nat UV -open scoped BigOperators FinsetFamily +open scoped FinsetFamily variable {α : Type*} [LinearOrder α] {s U V : Finset α} {n : ℕ} @@ -139,7 +141,7 @@ lemma toColex_compress_lt_toColex {hU : U.Nonempty} {hV : V.Nonempty} (h : max' /-- These are the compressions which we will apply to decrease the "measure" of a family of sets.-/ private def UsefulCompression (U V : Finset α) : Prop := - Disjoint U V ∧ U.card = V.card ∧ ∃ (HU : U.Nonempty) (HV : V.Nonempty), max' U HU < max' V HV + Disjoint U V ∧ #U = #V ∧ ∃ (HU : U.Nonempty) (HV : V.Nonempty), max' U HU < max' V HV private instance UsefulCompression.instDecidableRel : @DecidableRel (Finset α) UsefulCompression := fun _ _ ↦ inferInstanceAs (Decidable (_ ∧ _)) @@ -148,8 +150,8 @@ private instance UsefulCompression.instDecidableRel : @DecidableRel (Finset α) shadow. In particular, 'good' means it's useful, and every smaller compression won't make a difference. -/ private lemma compression_improved (𝒜 : Finset (Finset α)) (h₁ : UsefulCompression U V) - (h₂ : ∀ ⦃U₁ V₁⦄, UsefulCompression U₁ V₁ → U₁.card < U.card → IsCompressed U₁ V₁ 𝒜) : - (∂ (𝓒 U V 𝒜)).card ≤ (∂ 𝒜).card := by + (h₂ : ∀ ⦃U₁ V₁⦄, UsefulCompression U₁ V₁ → #U₁ < #U → IsCompressed U₁ V₁ 𝒜) : + #(∂ (𝓒 U V 𝒜)) ≤ #(∂ 𝒜) := by obtain ⟨UVd, same_size, hU, hV, max_lt⟩ := h₁ refine card_shadow_compression_le _ _ fun x Hx ↦ ⟨min' V hV, min'_mem _ _, ?_⟩ obtain hU' | hU' := eq_or_lt_of_le (succ_le_iff.2 hU.card_pos) @@ -174,7 +176,7 @@ lemma isInitSeg_of_compressed {ℬ : Finset (Finset α)} {r : ℕ} (h₁ : (ℬ rintro A B hA ⟨hBA, sizeA⟩ by_contra hB have hAB : A ≠ B := ne_of_mem_of_not_mem hA hB - have hAB' : A.card = B.card := (h₁ hA).trans sizeA.symm + have hAB' : #A = #B := (h₁ hA).trans sizeA.symm have hU : (A \ B).Nonempty := sdiff_nonempty.2 fun h ↦ hAB <| eq_of_subset_of_card_le h hAB'.ge have hV : (B \ A).Nonempty := sdiff_nonempty.2 fun h ↦ hAB.symm <| eq_of_subset_of_card_le h hAB'.le @@ -203,14 +205,14 @@ private lemma familyMeasure_compression_lt_familyMeasure {U V : Finset (Fin n)} {hV : V.Nonempty} (h : max' U hU < max' V hV) {𝒜 : Finset (Finset (Fin n))} (a : 𝓒 U V 𝒜 ≠ 𝒜) : familyMeasure (𝓒 U V 𝒜) < familyMeasure 𝒜 := by rw [compression] at a ⊢ - have q : ∀ Q ∈ 𝒜.filter fun A ↦ compress U V A ∉ 𝒜, compress U V Q ≠ Q := by + have q : ∀ Q ∈ {A ∈ 𝒜 | compress U V A ∉ 𝒜}, compress U V Q ≠ Q := by simp_rw [mem_filter] intro Q hQ h rw [h] at hQ exact hQ.2 hQ.1 - have uA : (𝒜.filter fun A => compress U V A ∈ 𝒜) ∪ 𝒜.filter (fun A ↦ compress U V A ∉ 𝒜) = 𝒜 := + have uA : {A ∈ 𝒜 | compress U V A ∈ 𝒜} ∪ {A ∈ 𝒜 | compress U V A ∉ 𝒜} = 𝒜 := filter_union_filter_neg_eq _ _ - have ne₂ : (𝒜.filter fun A ↦ compress U V A ∉ 𝒜).Nonempty := by + have ne₂ : {A ∈ 𝒜 | compress U V A ∉ 𝒜}.Nonempty := by refine nonempty_iff_ne_empty.2 fun z ↦ a ?_ rw [filter_image, z, image_empty, union_empty] rwa [z, union_empty] at uA @@ -229,12 +231,12 @@ we can't any more, which gives a set family which is fully compressed and has th want. -/ private lemma kruskal_katona_helper {r : ℕ} (𝒜 : Finset (Finset (Fin n))) (h : (𝒜 : Set (Finset (Fin n))).Sized r) : - ∃ ℬ : Finset (Finset (Fin n)), (∂ ℬ).card ≤ (∂ 𝒜).card ∧ 𝒜.card = ℬ.card ∧ + ∃ ℬ : Finset (Finset (Fin n)), #(∂ ℬ) ≤ #(∂ 𝒜) ∧ #𝒜 = #ℬ ∧ (ℬ : Set (Finset (Fin n))).Sized r ∧ ∀ U V, UsefulCompression U V → IsCompressed U V ℬ := by classical -- Are there any compressions we can make now? set usable : Finset (Finset (Fin n) × Finset (Fin n)) := - univ.filter fun t ↦ UsefulCompression t.1 t.2 ∧ ¬ IsCompressed t.1 t.2 𝒜 + {t | UsefulCompression t.1 t.2 ∧ ¬ IsCompressed t.1 t.2 𝒜} obtain husable | husable := usable.eq_empty_or_nonempty -- No. Then where we are is the required set family. · refine ⟨𝒜, le_rfl, rfl, h, fun U V hUV ↦ ?_⟩ @@ -242,13 +244,13 @@ private lemma kruskal_katona_helper {r : ℕ} (𝒜 : Finset (Finset (Fin n))) by_contra h exact husable ⟨U, V⟩ <| mem_filter.2 ⟨mem_univ _, hUV, h⟩ -- Yes. Then apply the smallest compression, then keep going - obtain ⟨⟨U, V⟩, hUV, t⟩ := exists_min_image usable (fun t ↦ t.1.card) husable + obtain ⟨⟨U, V⟩, hUV, t⟩ := exists_min_image usable (fun t ↦ #t.1) husable rw [mem_filter] at hUV - have h₂ : ∀ U₁ V₁, UsefulCompression U₁ V₁ → U₁.card < U.card → IsCompressed U₁ V₁ 𝒜 := by + have h₂ : ∀ U₁ V₁, UsefulCompression U₁ V₁ → #U₁ < #U → IsCompressed U₁ V₁ 𝒜 := by rintro U₁ V₁ huseful hUcard by_contra h exact hUcard.not_le <| t ⟨U₁, V₁⟩ <| mem_filter.2 ⟨mem_univ _, huseful, h⟩ - have p1 : (∂ (𝓒 U V 𝒜)).card ≤ (∂ 𝒜).card := compression_improved _ hUV.2.1 h₂ + have p1 : #(∂ (𝓒 U V 𝒜)) ≤ #(∂ 𝒜) := compression_improved _ hUV.2.1 h₂ obtain ⟨-, hUV', hu, hv, hmax⟩ := hUV.2.1 have := familyMeasure_compression_lt_familyMeasure hmax hUV.2.2 obtain ⟨t, q1, q2, q3, q4⟩ := UV.kruskal_katona_helper (𝓒 U V 𝒜) (h.uvCompression hUV') @@ -266,8 +268,8 @@ variable {r k i : ℕ} {𝒜 𝒞 : Finset <| Finset <| Fin n} Given a set family `𝒜` consisting of `r`-sets, and `𝒞` an initial segment of the colex order of the same size, the shadow of `𝒞` is smaller than the shadow of `𝒜`. In particular, this gives that the minimum shadow size is achieved by initial segments of colex. -/ -theorem kruskal_katona (h𝒜r : (𝒜 : Set (Finset (Fin n))).Sized r) (h𝒞𝒜 : 𝒞.card ≤ 𝒜.card) - (h𝒞 : IsInitSeg 𝒞 r) : (∂ 𝒞).card ≤ (∂ 𝒜).card := by +theorem kruskal_katona (h𝒜r : (𝒜 : Set (Finset (Fin n))).Sized r) (h𝒞𝒜 : #𝒞 ≤ #𝒜) + (h𝒞 : IsInitSeg 𝒞 r) : #(∂ 𝒞) ≤ #(∂ 𝒜) := by -- WLOG `|𝒜| = |𝒞|` obtain ⟨𝒜', h𝒜, h𝒜𝒞⟩ := exists_subset_card_eq h𝒞𝒜 -- By `kruskal_katona_helper`, we find a fully compressed family `ℬ` of the same size as `𝒜` @@ -276,19 +278,117 @@ theorem kruskal_katona (h𝒜r : (𝒜 : Set (Finset (Fin n))).Sized r) (h𝒞 -- This means that `ℬ` is an initial segment of the same size as `𝒞`. Hence they are equal and -- we are done. suffices ℬ = 𝒞 by subst 𝒞; exact hℬ𝒜.trans (by gcongr) - have hcard : card ℬ = card 𝒞 := h𝒜ℬ.symm.trans h𝒜𝒞 + have hcard : #ℬ = #𝒞 := h𝒜ℬ.symm.trans h𝒜𝒞 obtain h𝒞ℬ | hℬ𝒞 := h𝒞.total (UV.isInitSeg_of_compressed hℬr hℬ) · exact (eq_of_subset_of_card_le h𝒞ℬ hcard.le).symm · exact eq_of_subset_of_card_le hℬ𝒞 hcard.ge /-- An iterated form of the Kruskal-Katona theorem. In particular, the minimum possible iterated shadow size is attained by initial segments. -/ -theorem iterated_kk (h₁ : (𝒜 : Set (Finset (Fin n))).Sized r) (h₂ : 𝒞.card ≤ 𝒜.card) - (h₃ : IsInitSeg 𝒞 r) : (∂^[k] 𝒞).card ≤ (∂^[k] 𝒜).card := by +theorem iterated_kk (h₁ : (𝒜 : Set (Finset (Fin n))).Sized r) (h₂ : #𝒞 ≤ #𝒜) (h₃ : IsInitSeg 𝒞 r) : + #(∂^[k] 𝒞) ≤ #(∂^[k] 𝒜) := by induction' k with _k ih generalizing r 𝒜 𝒞 · simpa · refine ih h₁.shadow (kruskal_katona h₁ h₂ h₃) ?_ convert h₃.shadow +/-- The **Lovasz formulation of the Kruskal-Katona theorem**. + +If `|𝒜| ≥ k choose r`, (and everything in `𝒜` has size `r`) then the initial segment we compare to +is just all the subsets of `{0, ..., k - 1}` of size `r`. The `i`-th iterated shadow of this is all +the subsets of `{0, ..., k - 1}` of size `r - i`, so the `i`-th iterated shadow of `𝒜` has at least +`k.choose (r - i)` elements. -/ +theorem kruskal_katona_lovasz_form (hir : i ≤ r) (hrk : r ≤ k) (hkn : k ≤ n) + (h₁ : (𝒜 : Set (Finset (Fin n))).Sized r) (h₂ : k.choose r ≤ #𝒜) : + k.choose (r - i) ≤ #(∂^[i] 𝒜) := by + set range'k : Finset (Fin n) := + attachFin (range k) fun m ↦ by rw [mem_range]; apply forall_lt_iff_le.2 hkn + set 𝒞 : Finset (Finset (Fin n)) := powersetCard r range'k + have : (𝒞 : Set (Finset (Fin n))).Sized r := Set.sized_powersetCard _ _ + calc + k.choose (r - i) + _ = #(powersetCard (r - i) range'k) := by rw [card_powersetCard, card_attachFin, card_range] + _ = #(∂^[i] 𝒞) := by + congr! + ext B + rw [mem_powersetCard, mem_shadow_iterate_iff_exists_sdiff] + constructor + · rintro ⟨hBk, hB⟩ + have := exists_subsuperset_card_eq hBk (Nat.le_add_left _ i) <| by + rwa [hB, card_attachFin, card_range, ← Nat.add_sub_assoc hir, Nat.add_sub_cancel_left] + obtain ⟨C, BsubC, hCrange, hcard⟩ := this + rw [hB, ← Nat.add_sub_assoc hir, Nat.add_sub_cancel_left] at hcard + refine ⟨C, mem_powersetCard.2 ⟨hCrange, hcard⟩, BsubC, ?_⟩ + rw [card_sdiff BsubC, hcard, hB, Nat.sub_sub_self hir] + · rintro ⟨A, Ah, hBA, card_sdiff_i⟩ + rw [mem_powersetCard] at Ah + refine ⟨hBA.trans Ah.1, eq_tsub_of_add_eq ?_⟩ + rw [← Ah.2, ← card_sdiff_i, add_comm, card_sdiff_add_card_eq_card hBA] + _ ≤ #(∂ ^[i] 𝒜) := by + refine iterated_kk h₁ ?_ ⟨‹_›, ?_⟩ + · rwa [card_powersetCard, card_attachFin, card_range] + simp_rw [𝒞, mem_powersetCard] + rintro A B hA ⟨HB₁, HB₂⟩ + refine ⟨fun t ht ↦ ?_, ‹_›⟩ + rw [mem_attachFin, mem_range] + have : toColex (image Fin.val B) < toColex (image Fin.val A) := by + rwa [toColex_image_lt_toColex_image Fin.val_strictMono] + apply Colex.forall_lt_mono this.le _ t (mem_image.2 ⟨t, ht, rfl⟩) + simp_rw [mem_image] + rintro _ ⟨a, ha, hab⟩ + simpa [range'k, hab] using hA.1 ha + end KK + +/-- The **Erdős–Ko–Rado theorem**. + +The maximum size of an intersecting family in `α` where all sets have size `r` is bounded by +`(card α - 1).choose (r - 1)`. This bound is sharp. -/ +theorem erdos_ko_rado {𝒜 : Finset (Finset (Fin n))} {r : ℕ} + (h𝒜 : (𝒜 : Set (Finset (Fin n))).Intersecting) (h₂ : (𝒜 : Set (Finset (Fin n))).Sized r) + (h₃ : r ≤ n / 2) : + #𝒜 ≤ (n - 1).choose (r - 1) := by + -- Take care of the r=0 case first: it's not very interesting. + cases' Nat.eq_zero_or_pos r with b h1r + · convert Nat.zero_le _ + rw [Finset.card_eq_zero, eq_empty_iff_forall_not_mem] + refine fun A HA ↦ h𝒜 HA HA ?_ + rw [disjoint_self_iff_empty, ← Finset.card_eq_zero, ← b] + exact h₂ HA + refine le_of_not_lt fun size ↦ ?_ + -- Consider 𝒜ᶜˢ = {sᶜ | s ∈ 𝒜} + -- Its iterated shadow (∂^[n-2k] 𝒜ᶜˢ) is disjoint from 𝒜 by intersecting-ness + have : Disjoint 𝒜 (∂^[n - 2 * r] 𝒜ᶜˢ) := disjoint_right.2 fun A hAbar hA ↦ by + simp [mem_shadow_iterate_iff_exists_sdiff, mem_compls] at hAbar + obtain ⟨C, hC, hAC, _⟩ := hAbar + exact h𝒜 hA hC (disjoint_of_subset_left hAC disjoint_compl_right) + have : r ≤ n := h₃.trans (Nat.div_le_self n 2) + have : 1 ≤ n := ‹1 ≤ r›.trans ‹r ≤ n› + -- We know the size of 𝒜ᶜˢ since it's the same size as 𝒜 + have z : (n - 1).choose (n - r) < #𝒜ᶜˢ := by + rwa [card_compls, choose_symm_of_eq_add (tsub_add_tsub_cancel ‹r ≤ n› ‹1 ≤ r›).symm] + -- and everything in 𝒜ᶜˢ has size n-r. + have h𝒜bar : (𝒜ᶜˢ : Set (Finset (Fin n))).Sized (n - r) := by simpa using h₂.compls + have : n - 2 * r ≤ n - r := by + rw [tsub_le_tsub_iff_left ‹r ≤ n›] + exact Nat.le_mul_of_pos_left _ zero_lt_two + -- We can use the Lovasz form of Kruskal-Katona to get |∂^[n-2k] 𝒜ᶜˢ| ≥ (n-1) choose r + have kk := kruskal_katona_lovasz_form ‹n - 2 * r ≤ n - r› ((tsub_le_tsub_iff_left ‹1 ≤ n›).2 h1r) + tsub_le_self h𝒜bar z.le + have : n - r - (n - 2 * r) = r := by omega + rw [this] at kk + -- But this gives a contradiction: `n choose r < |𝒜| + |∂^[n-2k] 𝒜ᶜˢ|` + have : n.choose r < #(𝒜 ∪ ∂^[n - 2 * r] 𝒜ᶜˢ) := by + rw [card_union_of_disjoint ‹_›] + convert lt_of_le_of_lt (add_le_add_left kk _) (add_lt_add_right size _) using 1 + convert Nat.choose_succ_succ _ _ using 3 + all_goals rwa [Nat.sub_one, Nat.succ_pred_eq_of_pos] + apply this.not_le + convert Set.Sized.card_le _ + · rw [Fintype.card_fin] + rw [coe_union, Set.sized_union] + refine ⟨‹_›, ?_⟩ + convert h𝒜bar.shadow_iterate + omega + end Finset diff --git a/Mathlib/Combinatorics/SetFamily/LYM.lean b/Mathlib/Combinatorics/SetFamily/LYM.lean index 6b5887d58e1ee..4f771b1d44162 100644 --- a/Mathlib/Combinatorics/SetFamily/LYM.lean +++ b/Mathlib/Combinatorics/SetFamily/LYM.lean @@ -61,7 +61,7 @@ variable [DecidableEq α] [Fintype α] /-- The downward **local LYM inequality**, with cancelled denominators. `𝒜` takes up less of `α^(r)` (the finsets of card `r`) than `∂𝒜` takes up of `α^(r - 1)`. -/ theorem card_mul_le_card_shadow_mul (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : - 𝒜.card * r ≤ (∂ 𝒜).card * (Fintype.card α - r + 1) := by + #𝒜 * r ≤ #(∂ 𝒜) * (Fintype.card α - r + 1) := by let i : DecidableRel ((· ⊆ ·) : Finset α → Finset α → Prop) := fun _ _ => Classical.dec _ refine card_mul_le_card_mul' (· ⊆ ·) (fun s hs => ?_) (fun s hs => ?_) · rw [← h𝒜 hs, ← card_image_of_injOn s.erase_injOn] @@ -87,8 +87,8 @@ theorem card_mul_le_card_shadow_mul (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : /-- The downward **local LYM inequality**. `𝒜` takes up less of `α^(r)` (the finsets of card `r`) than `∂𝒜` takes up of `α^(r - 1)`. -/ theorem card_div_choose_le_card_shadow_div_choose (hr : r ≠ 0) - (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : (𝒜.card : 𝕜) / (Fintype.card α).choose r - ≤ (∂ 𝒜).card / (Fintype.card α).choose (r - 1) := by + (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : (#𝒜 : 𝕜) / (Fintype.card α).choose r + ≤ #(∂ 𝒜) / (Fintype.card α).choose (r - 1) := by obtain hr' | hr' := lt_or_le (Fintype.card α) r · rw [choose_eq_zero_of_lt hr', cast_zero, div_zero] exact div_nonneg (cast_nonneg _) (cast_nonneg _) @@ -122,7 +122,7 @@ def falling : Finset (Finset α) := variable {𝒜 k} {s : Finset α} -theorem mem_falling : s ∈ falling k 𝒜 ↔ (∃ t ∈ 𝒜, s ⊆ t) ∧ s.card = k := by +theorem mem_falling : s ∈ falling k 𝒜 ↔ (∃ t ∈ 𝒜, s ⊆ t) ∧ #s = k := by simp_rw [falling, mem_sup, mem_powersetCard] aesop @@ -169,7 +169,7 @@ theorem IsAntichain.disjoint_slice_shadow_falling {m n : ℕ} theorem le_card_falling_div_choose [Fintype α] (hk : k ≤ Fintype.card α) (h𝒜 : IsAntichain (· ⊆ ·) (𝒜 : Set (Finset α))) : (∑ r ∈ range (k + 1), - ((𝒜 # (Fintype.card α - r)).card : 𝕜) / (Fintype.card α).choose (Fintype.card α - r)) ≤ + (#(𝒜 # (Fintype.card α - r)) : 𝕜) / (Fintype.card α).choose (Fintype.card α - r)) ≤ (falling (Fintype.card α - k) 𝒜).card / (Fintype.card α).choose (Fintype.card α - k) := by induction' k with k ih · simp only [tsub_zero, cast_one, cast_le, sum_singleton, div_one, choose_self, range_one, @@ -188,13 +188,13 @@ theorem le_card_falling_div_choose [Fintype α] (hk : k ≤ Fintype.card α) end Falling -variable {𝒜 : Finset (Finset α)} {s : Finset α} {k : ℕ} +variable {𝒜 : Finset (Finset α)} /-- The **Lubell-Yamamoto-Meshalkin inequality**. If `𝒜` is an antichain, then the sum of the proportion of elements it takes from each layer is less than `1`. -/ theorem sum_card_slice_div_choose_le_one [Fintype α] (h𝒜 : IsAntichain (· ⊆ ·) (𝒜 : Set (Finset α))) : - (∑ r ∈ range (Fintype.card α + 1), ((𝒜 # r).card : 𝕜) / (Fintype.card α).choose r) ≤ 1 := by + (∑ r ∈ range (Fintype.card α + 1), (#(𝒜 # r) : 𝕜) / (Fintype.card α).choose r) ≤ 1 := by classical rw [← sum_flip] refine (le_card_falling_div_choose le_rfl h𝒜).trans ?_ @@ -213,10 +213,10 @@ end LYM maximal layer in `Finset α`. This precisely means that `Finset α` is a Sperner order. -/ theorem IsAntichain.sperner [Fintype α] {𝒜 : Finset (Finset α)} (h𝒜 : IsAntichain (· ⊆ ·) (𝒜 : Set (Finset α))) : - 𝒜.card ≤ (Fintype.card α).choose (Fintype.card α / 2) := by + #𝒜 ≤ (Fintype.card α).choose (Fintype.card α / 2) := by classical suffices (∑ r ∈ Iic (Fintype.card α), - ((𝒜 # r).card : ℚ) / (Fintype.card α).choose (Fintype.card α / 2)) ≤ 1 by + (#(𝒜 # r) : ℚ) / (Fintype.card α).choose (Fintype.card α / 2)) ≤ 1 by rw [← sum_div, ← Nat.cast_sum, div_le_one] at this · simp only [cast_le] at this rwa [sum_card_slice] at this diff --git a/Mathlib/Combinatorics/SetFamily/Shadow.lean b/Mathlib/Combinatorics/SetFamily/Shadow.lean index a3b293b819c4c..7e12901d9f2f6 100644 --- a/Mathlib/Combinatorics/SetFamily/Shadow.lean +++ b/Mathlib/Combinatorics/SetFamily/Shadow.lean @@ -97,7 +97,7 @@ theorem erase_mem_shadow (hs : s ∈ 𝒜) (ha : a ∈ s) : erase s a ∈ ∂ /-- `t ∈ ∂𝒜` iff `t` is exactly one element less than something from `𝒜`. See also `Finset.mem_shadow_iff_exists_mem_card_add_one`. -/ -lemma mem_shadow_iff_exists_sdiff : t ∈ ∂ 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ (s \ t).card = 1 := by +lemma mem_shadow_iff_exists_sdiff : t ∈ ∂ 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ #(s \ t) = 1 := by simp_rw [mem_shadow_iff, ← covBy_iff_card_sdiff_eq_one, covBy_iff_exists_erase] /-- `t` is in the shadow of `𝒜` iff we can add an element to it so that the resulting finset is in @@ -109,15 +109,14 @@ lemma mem_shadow_iff_insert_mem : t ∈ ∂ 𝒜 ↔ ∃ a ∉ t, insert a t ∈ /-- `s ∈ ∂ 𝒜` iff `s` is exactly one element less than something from `𝒜`. See also `Finset.mem_shadow_iff_exists_sdiff`. -/ -lemma mem_shadow_iff_exists_mem_card_add_one : - t ∈ ∂ 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ s.card = t.card + 1 := by +lemma mem_shadow_iff_exists_mem_card_add_one : t ∈ ∂ 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ #s = #t + 1 := by refine mem_shadow_iff_exists_sdiff.trans <| exists_congr fun t ↦ and_congr_right fun _ ↦ and_congr_right fun hst ↦ ?_ rw [card_sdiff hst, tsub_eq_iff_eq_add_of_le, add_comm] exact card_mono hst lemma mem_shadow_iterate_iff_exists_card : - t ∈ ∂^[k] 𝒜 ↔ ∃ u : Finset α, u.card = k ∧ Disjoint t u ∧ t ∪ u ∈ 𝒜 := by + t ∈ ∂^[k] 𝒜 ↔ ∃ u : Finset α, #u = k ∧ Disjoint t u ∧ t ∪ u ∈ 𝒜 := by induction' k with k ih generalizing t · simp set_option tactic.skipAssignedInstances false in @@ -127,7 +126,7 @@ lemma mem_shadow_iterate_iff_exists_card : /-- `t ∈ ∂^k 𝒜` iff `t` is exactly `k` elements less than something from `𝒜`. See also `Finset.mem_shadow_iff_exists_mem_card_add`. -/ -lemma mem_shadow_iterate_iff_exists_sdiff : t ∈ ∂^[k] 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ (s \ t).card = k := by +lemma mem_shadow_iterate_iff_exists_sdiff : t ∈ ∂^[k] 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ #(s \ t) = k := by rw [mem_shadow_iterate_iff_exists_card] constructor · rintro ⟨u, rfl, htu, hsuA⟩ @@ -140,7 +139,7 @@ lemma mem_shadow_iterate_iff_exists_sdiff : t ∈ ∂^[k] 𝒜 ↔ ∃ s ∈ See also `Finset.mem_shadow_iterate_iff_exists_sdiff`. -/ lemma mem_shadow_iterate_iff_exists_mem_card_add : - t ∈ ∂^[k] 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ s.card = t.card + k := by + t ∈ ∂^[k] 𝒜 ↔ ∃ s ∈ 𝒜, t ⊆ s ∧ #s = #t + k := by refine mem_shadow_iterate_iff_exists_sdiff.trans <| exists_congr fun t ↦ and_congr_right fun _ ↦ and_congr_right fun hst ↦ ?_ rw [card_sdiff hst, tsub_eq_iff_eq_add_of_le, add_comm] @@ -209,7 +208,7 @@ theorem insert_mem_upShadow (hs : s ∈ 𝒜) (ha : a ∉ s) : insert a s ∈ /-- `t` is in the upper shadow of `𝒜` iff `t` is exactly one element more than something from `𝒜`. See also `Finset.mem_upShadow_iff_exists_mem_card_add_one`. -/ -lemma mem_upShadow_iff_exists_sdiff : t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ (t \ s).card = 1 := by +lemma mem_upShadow_iff_exists_sdiff : t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ #(t \ s) = 1 := by simp_rw [mem_upShadow_iff, ← covBy_iff_card_sdiff_eq_one, covBy_iff_exists_insert] /-- `t` is in the upper shadow of `𝒜` iff we can remove an element from it so that the resulting @@ -222,14 +221,14 @@ lemma mem_upShadow_iff_erase_mem : t ∈ ∂⁺ 𝒜 ↔ ∃ a, a ∈ t ∧ eras See also `Finset.mem_upShadow_iff_exists_sdiff`. -/ lemma mem_upShadow_iff_exists_mem_card_add_one : - t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ t.card = s.card + 1 := by + t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ #t = #s + 1 := by refine mem_upShadow_iff_exists_sdiff.trans <| exists_congr fun t ↦ and_congr_right fun _ ↦ and_congr_right fun hst ↦ ?_ rw [card_sdiff hst, tsub_eq_iff_eq_add_of_le, add_comm] exact card_mono hst lemma mem_upShadow_iterate_iff_exists_card : - t ∈ ∂⁺^[k] 𝒜 ↔ ∃ u : Finset α, u.card = k ∧ u ⊆ t ∧ t \ u ∈ 𝒜 := by + t ∈ ∂⁺^[k] 𝒜 ↔ ∃ u : Finset α, #u = k ∧ u ⊆ t ∧ t \ u ∈ 𝒜 := by induction' k with k ih generalizing t · simp simp only [mem_upShadow_iff_erase_mem, ih, Function.iterate_succ_apply', card_eq_succ, @@ -244,8 +243,7 @@ lemma mem_upShadow_iterate_iff_exists_card : /-- `t` is in the upper shadow of `𝒜` iff `t` is exactly `k` elements less than something from `𝒜`. See also `Finset.mem_upShadow_iff_exists_mem_card_add`. -/ -lemma mem_upShadow_iterate_iff_exists_sdiff : - t ∈ ∂⁺^[k] 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ (t \ s).card = k := by +lemma mem_upShadow_iterate_iff_exists_sdiff : t ∈ ∂⁺^[k] 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ #(t \ s) = k := by rw [mem_upShadow_iterate_iff_exists_card] constructor · rintro ⟨u, rfl, hut, htu⟩ @@ -257,7 +255,7 @@ lemma mem_upShadow_iterate_iff_exists_sdiff : See also `Finset.mem_upShadow_iterate_iff_exists_sdiff`. -/ lemma mem_upShadow_iterate_iff_exists_mem_card_add : - t ∈ ∂⁺^[k] 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ t.card = s.card + k := by + t ∈ ∂⁺^[k] 𝒜 ↔ ∃ s ∈ 𝒜, s ⊆ t ∧ #t = #s + k := by refine mem_upShadow_iterate_iff_exists_sdiff.trans <| exists_congr fun t ↦ and_congr_right fun _ ↦ and_congr_right fun hst ↦ ?_ rw [card_sdiff hst, tsub_eq_iff_eq_add_of_le, add_comm] @@ -277,7 +275,7 @@ theorem exists_subset_of_mem_upShadow (hs : s ∈ ∂⁺ 𝒜) : ∃ t ∈ 𝒜, /-- `t ∈ ∂^k 𝒜` iff `t` is exactly `k` elements more than something in `𝒜`. -/ theorem mem_upShadow_iff_exists_mem_card_add : - s ∈ ∂⁺ ^[k] 𝒜 ↔ ∃ t ∈ 𝒜, t ⊆ s ∧ t.card + k = s.card := by + s ∈ ∂⁺ ^[k] 𝒜 ↔ ∃ t ∈ 𝒜, t ⊆ s ∧ #t + k = #s := by induction' k with k ih generalizing 𝒜 s · refine ⟨fun hs => ⟨s, hs, Subset.refl _, rfl⟩, ?_⟩ rintro ⟨t, ht, hst, hcard⟩ diff --git a/Mathlib/Combinatorics/SetFamily/Shatter.lean b/Mathlib/Combinatorics/SetFamily/Shatter.lean index 74f21f70fbc02..431e8c87971aa 100644 --- a/Mathlib/Combinatorics/SetFamily/Shatter.lean +++ b/Mathlib/Combinatorics/SetFamily/Shatter.lean @@ -28,7 +28,7 @@ This file defines the shattering property and VC-dimension of set families. open scoped FinsetFamily namespace Finset -variable {α : Type*} [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s t : Finset α} {a : α} {n : ℕ} +variable {α : Type*} [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s t : Finset α} {a : α} /-- A set family `𝒜` shatters a set `s` if all subsets of `s` can be obtained as the intersection of `s` and some element of the set family, and we denote this `𝒜.Shatters s`. We also say that `s` @@ -72,7 +72,8 @@ lemma univ_shatters [Fintype α] : univ.Shatters s := rw [shatters_iff, powerset_univ]; simp_rw [univ_inter, image_id'] /-- The set family of sets that are shattered by `𝒜`. -/ -def shatterer (𝒜 : Finset (Finset α)) : Finset (Finset α) := (𝒜.biUnion powerset).filter 𝒜.Shatters +def shatterer (𝒜 : Finset (Finset α)) : Finset (Finset α) := + {s ∈ 𝒜.biUnion powerset | 𝒜.Shatters s} @[simp] lemma mem_shatterer : s ∈ 𝒜.shatterer ↔ 𝒜.Shatters s := by refine mem_filter.trans <| and_iff_right_of_imp fun h ↦ ?_ @@ -106,15 +107,14 @@ private lemma aux (h : ∀ t ∈ 𝒜, a ∉ t) (ht : 𝒜.Shatters t) : a ∉ t obtain ⟨u, hu, htu⟩ := ht.exists_superset; exact not_mem_mono htu <| h u hu /-- Pajor's variant of the **Sauer-Shelah lemma**. -/ -lemma card_le_card_shatterer (𝒜 : Finset (Finset α)) : 𝒜.card ≤ 𝒜.shatterer.card := by +lemma card_le_card_shatterer (𝒜 : Finset (Finset α)) : #𝒜 ≤ #𝒜.shatterer := by refine memberFamily_induction_on 𝒜 ?_ ?_ ?_ · simp · rfl intros a 𝒜 ih₀ ih₁ set ℬ : Finset (Finset α) := ((memberSubfamily a 𝒜).shatterer ∩ (nonMemberSubfamily a 𝒜).shatterer).image (insert a) - have hℬ : - ℬ.card = ((memberSubfamily a 𝒜).shatterer ∩ (nonMemberSubfamily a 𝒜).shatterer).card := by + have hℬ : #ℬ = #((memberSubfamily a 𝒜).shatterer ∩ (nonMemberSubfamily a 𝒜).shatterer) := by refine card_image_of_injOn <| insert_erase_invOn.2.injOn.mono ?_ simp only [coe_inter, Set.subset_def, Set.mem_inter_iff, mem_coe, Set.mem_setOf_eq, and_imp, mem_shatterer] @@ -183,7 +183,7 @@ def vcDim (𝒜 : Finset (Finset α)) : ℕ := 𝒜.shatterer.sup card @[gcongr] lemma vcDim_mono (h𝒜ℬ : 𝒜 ⊆ ℬ) : 𝒜.vcDim ≤ ℬ.vcDim := by unfold vcDim; gcongr -lemma Shatters.card_le_vcDim (hs : 𝒜.Shatters s) : s.card ≤ 𝒜.vcDim := le_sup <| mem_shatterer.2 hs +lemma Shatters.card_le_vcDim (hs : 𝒜.Shatters s) : #s ≤ 𝒜.vcDim := le_sup <| mem_shatterer.2 hs /-- Down-compressing decreases the VC-dimension. -/ lemma vcDim_compress_le (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).vcDim ≤ 𝒜.vcDim := @@ -191,9 +191,9 @@ lemma vcDim_compress_le (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).vcD /-- The **Sauer-Shelah lemma**. -/ lemma card_shatterer_le_sum_vcDim [Fintype α] : - 𝒜.shatterer.card ≤ ∑ k ∈ Iic 𝒜.vcDim, (Fintype.card α).choose k := by + #𝒜.shatterer ≤ ∑ k ∈ Iic 𝒜.vcDim, (Fintype.card α).choose k := by simp_rw [← card_univ, ← card_powersetCard] - refine (card_le_card fun s hs ↦ mem_biUnion.2 ⟨card s, ?_⟩).trans card_biUnion_le + refine (card_le_card fun s hs ↦ mem_biUnion.2 ⟨#s, ?_⟩).trans card_biUnion_le exact ⟨mem_Iic.2 (mem_shatterer.1 hs).card_le_vcDim, mem_powersetCard_univ.2 rfl⟩ end Finset diff --git a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean index 338e9167ee4a1..21165320a0fc1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean @@ -40,7 +40,7 @@ open Matrix open Finset Matrix SimpleGraph -variable {V α β : Type*} +variable {V α : Type*} namespace Matrix @@ -231,7 +231,6 @@ theorem adjMatrix_mul_self_apply_self [NonAssocSemiring α] (i : V) : variable {G} --- @[simp] -- Porting note (#10618): simp can prove this theorem adjMatrix_mulVec_const_apply [NonAssocSemiring α] {a : α} {v : V} : (G.adjMatrix α *ᵥ Function.const _ a) v = G.degree v * a := by simp diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index fd971bdfc268e..40be1f3971a03 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -237,7 +237,7 @@ instance hasCompl : HasCompl (SimpleGraph V) where compl G := { Adj := fun v w => v ≠ w ∧ ¬G.Adj v w symm := fun v w ⟨hne, _⟩ => ⟨hne.symm, by rwa [adj_comm]⟩ - loopless := fun v ⟨hne, _⟩ => (hne rfl).elim } + loopless := fun _ ⟨hne, _⟩ => (hne rfl).elim } @[simp] theorem compl_adj (G : SimpleGraph V) (v w : V) : Gᶜ.Adj v w ↔ v ≠ w ∧ ¬G.Adj v w := @@ -256,7 +256,7 @@ theorem sdiff_adj (x y : SimpleGraph V) (v w : V) : (x \ y).Adj v w ↔ x.Adj v instance supSet : SupSet (SimpleGraph V) where sSup s := { Adj := fun a b => ∃ G ∈ s, Adj G a b - symm := fun a b => Exists.imp fun _ => And.imp_right Adj.symm + symm := fun _ _ => Exists.imp fun _ => And.imp_right Adj.symm loopless := by rintro a ⟨G, _, ha⟩ exact ha.ne rfl } @@ -308,26 +308,26 @@ instance completeAtomicBooleanAlgebra : CompleteAtomicBooleanAlgebra (SimpleGrap sdiff := (· \ ·) top := completeGraph V bot := emptyGraph V - le_top := fun x v w h => x.ne_of_adj h - bot_le := fun x v w h => h.elim + le_top := fun x _ _ h => x.ne_of_adj h + bot_le := fun _ _ _ h => h.elim sdiff_eq := fun x y => by ext v w refine ⟨fun h => ⟨h.1, ⟨?_, h.2⟩⟩, fun h => ⟨h.1, h.2.2⟩⟩ rintro rfl exact x.irrefl h.1 - inf_compl_le_bot := fun G v w h => False.elim <| h.2.2 h.1 + inf_compl_le_bot := fun _ _ _ h => False.elim <| h.2.2 h.1 top_le_sup_compl := fun G v w hvw => by by_cases h : G.Adj v w · exact Or.inl h · exact Or.inr ⟨hvw, h⟩ sSup := sSup - le_sSup := fun s G hG a b hab => ⟨G, hG, hab⟩ + le_sSup := fun _ G hG _ _ hab => ⟨G, hG, hab⟩ sSup_le := fun s G hG a b => by rintro ⟨H, hH, hab⟩ exact hG _ hH hab sInf := sInf - sInf_le := fun s G hG a b hab => hab.1 hG - le_sInf := fun s G hG a b hab => ⟨fun H hH => hG _ hH hab, hab.ne⟩ + sInf_le := fun _ _ hG _ _ hab => hab.1 hG + le_sInf := fun _ _ hG _ _ hab => ⟨fun _ hH => hG _ hH hab, hab.ne⟩ iInf_iSup_eq := fun f => by ext; simp [Classical.skolem] } @[simp] @@ -355,7 +355,7 @@ instance [Subsingleton V] : Unique (SimpleGraph V) where uniq G := by ext a b; have := Subsingleton.elim a b; simp [this] instance [Nontrivial V] : Nontrivial (SimpleGraph V) := - ⟨⟨⊥, ⊤, fun h ↦ not_subsingleton V ⟨by simpa only [← adj_inj, Function.funext_iff, bot_adj, + ⟨⟨⊥, ⊤, fun h ↦ not_subsingleton V ⟨by simpa only [← adj_inj, funext_iff, bot_adj, top_adj, ne_eq, eq_iff_iff, false_iff, not_not] using h⟩⟩⟩ section Decidable @@ -518,7 +518,7 @@ variable (G G₁ G₂) theorem edge_other_ne {e : Sym2 V} (he : e ∈ G.edgeSet) {v : V} (h : v ∈ e) : Sym2.Mem.other h ≠ v := by - erw [← Sym2.other_spec h, Sym2.eq_swap] at he + rw [← Sym2.other_spec h, Sym2.eq_swap] at he exact G.ne_of_adj he instance decidableMemEdgeSet [DecidableRel G.Adj] : DecidablePred (· ∈ G.edgeSet) := @@ -555,7 +555,7 @@ variable (s : Set (Sym2 V)) /-- `fromEdgeSet` constructs a `SimpleGraph` from a set of edges, without loops. -/ def fromEdgeSet : SimpleGraph V where Adj := Sym2.ToRel s ⊓ Ne - symm v w h := ⟨Sym2.toRel_symmetric s h.1, h.2.symm⟩ + symm _ _ h := ⟨Sym2.toRel_symmetric s h.1, h.2.symm⟩ @[simp] theorem fromEdgeSet_adj : (fromEdgeSet s).Adj v w ↔ s(v, w) ∈ s ∧ v ≠ w := @@ -709,7 +709,7 @@ theorem neighborSet_union_compl_neighborSet_eq (G : SimpleGraph V) (v : V) : theorem card_neighborSet_union_compl_neighborSet [Fintype V] (G : SimpleGraph V) (v : V) [Fintype (G.neighborSet v ∪ Gᶜ.neighborSet v : Set V)] : - (Set.toFinset (G.neighborSet v ∪ Gᶜ.neighborSet v)).card = Fintype.card V - 1 := by + #(G.neighborSet v ∪ Gᶜ.neighborSet v).toFinset = Fintype.card V - 1 := by classical simp_rw [neighborSet_union_compl_neighborSet_eq, Set.toFinset_compl, Finset.card_compl, Set.toFinset_card, Set.card_singleton] diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index 121f720ec7a12..99106b3256d7b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -72,11 +72,11 @@ theorem cycleGraph_zero_eq_top : cycleGraph 0 = ⊤ := Subsingleton.elim _ _ theorem cycleGraph_one_eq_top : cycleGraph 1 = ⊤ := Subsingleton.elim _ _ theorem cycleGraph_two_eq_top : cycleGraph 2 = ⊤ := by - simp only [SimpleGraph.ext_iff, Function.funext_iff] + simp only [SimpleGraph.ext_iff, funext_iff] decide theorem cycleGraph_three_eq_top : cycleGraph 3 = ⊤ := by - simp only [SimpleGraph.ext_iff, Function.funext_iff] + simp only [SimpleGraph.ext_iff, funext_iff] decide theorem cycleGraph_one_adj {u v : Fin 1} : ¬(cycleGraph 1).Adj u v := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index 4023561674eb6..fc597f6af613d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean @@ -140,8 +140,8 @@ theorem isClique_map_finset_iff_of_nontrivial (ht : t.Nontrivial) : simpa using hs.map (f := f) theorem isClique_map_finset_iff : - (G.map f).IsClique t ↔ t.card ≤ 1 ∨ ∃ (s : Finset α), G.IsClique s ∧ s.map f = t := by - obtain (ht | ht) := le_or_lt t.card 1 + (G.map f).IsClique t ↔ #t ≤ 1 ∨ ∃ (s : Finset α), G.IsClique s ∧ s.map f = t := by + obtain (ht | ht) := le_or_lt #t 1 · simp only [ht, true_or, iff_true] exact IsClique.of_subsingleton <| card_le_one.1 ht rw [isClique_map_finset_iff_of_nontrivial, ← not_lt] @@ -164,9 +164,9 @@ variable {n : ℕ} {s : Finset α} /-- An `n`-clique in a graph is a set of `n` vertices which are pairwise connected. -/ structure IsNClique (n : ℕ) (s : Finset α) : Prop where clique : G.IsClique s - card_eq : s.card = n + card_eq : #s = n -theorem isNClique_iff : G.IsNClique n s ↔ G.IsClique s ∧ s.card = n := +theorem isNClique_iff : G.IsNClique n s ↔ G.IsClique s ∧ #s = n := ⟨fun h ↦ ⟨h.1, h.2⟩, fun h ↦ ⟨h.1, h.2⟩⟩ instance [DecidableEq α] [DecidableRel G.Adj] {n : ℕ} {s : Finset α} : @@ -199,7 +199,7 @@ theorem isNClique_map_iff (hn : 1 < n) {t : Finset β} {f : α ↪ β} : simp [hs.card_eq, hs.clique] @[simp] -theorem isNClique_bot_iff : (⊥ : SimpleGraph α).IsNClique n s ↔ n ≤ 1 ∧ s.card = n := by +theorem isNClique_bot_iff : (⊥ : SimpleGraph α).IsNClique n s ↔ n ≤ 1 ∧ #s = n := by rw [isNClique_iff, isClique_bot_iff] refine and_congr_left ?_ rintro rfl @@ -286,7 +286,7 @@ noncomputable def topEmbeddingOfNotCliqueFree {n : ℕ} (h : ¬G.CliqueFree n) : (⊤ : SimpleGraph (Fin n)) ↪g G := by simp only [CliqueFree, isNClique_iff, isClique_iff_induce_eq, not_forall, Classical.not_not] at h obtain ⟨ha, hb⟩ := h.choose_spec - have : (⊤ : SimpleGraph (Fin h.choose.card)) ≃g (⊤ : SimpleGraph h.choose) := by + have : (⊤ : SimpleGraph (Fin #h.choose)) ≃g (⊤ : SimpleGraph h.choose) := by apply Iso.completeGraph simpa using (Fintype.equivFin h.choose).symm rw [← ha] at this @@ -446,7 +446,7 @@ theorem cliqueFreeOn_univ : G.CliqueFreeOn Set.univ n ↔ G.CliqueFree n := by protected theorem CliqueFree.cliqueFreeOn (hG : G.CliqueFree n) : G.CliqueFreeOn s n := fun _t _ ↦ hG _ -theorem cliqueFreeOn_of_card_lt {s : Finset α} (h : s.card < n) : G.CliqueFreeOn s n := +theorem cliqueFreeOn_of_card_lt {s : Finset α} (h : #s < n) : G.CliqueFreeOn s n := fun _t hts ht => h.not_le <| ht.2.symm.trans_le <| card_mono hts -- TODO: Restate using `SimpleGraph.IndepSet` once we have it @@ -548,8 +548,7 @@ section CliqueFinset variable [Fintype α] [DecidableEq α] [DecidableRel G.Adj] {n : ℕ} {a b c : α} {s : Finset α} /-- The `n`-cliques in a graph as a finset. -/ -def cliqueFinset (n : ℕ) : Finset (Finset α) := - univ.filter <| G.IsNClique n +def cliqueFinset (n : ℕ) : Finset (Finset α) := {s | G.IsNClique n s} variable {G} in @[simp] @@ -568,7 +567,7 @@ theorem cliqueFinset_eq_empty_iff : G.cliqueFinset n = ∅ ↔ G.CliqueFree n := protected alias ⟨_, CliqueFree.cliqueFinset⟩ := cliqueFinset_eq_empty_iff -theorem card_cliqueFinset_le : (G.cliqueFinset n).card ≤ (card α).choose n := by +theorem card_cliqueFinset_le : #(G.cliqueFinset n) ≤ (card α).choose n := by rw [← card_univ, ← card_powersetCard] refine card_mono fun s => ?_ simpa [mem_powersetCard_univ] using IsNClique.card_eq diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean index 51818e2375813..171bc81387364 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean @@ -21,14 +21,13 @@ can also be useful as a recursive description of this set when `V` is finite. TODO: should this be extended further? -/ -open Function +open Finset Function universe u v w namespace SimpleGraph -variable {V : Type u} {V' : Type v} {V'' : Type w} -variable (G : SimpleGraph V) (G' : SimpleGraph V') (G'' : SimpleGraph V'') +variable {V : Type u} (G : SimpleGraph V) /-! ### Walks of a given length -/ @@ -64,7 +63,7 @@ Note that `u` and `v` may be the same. -/ def walkLengthTwoEquivCommonNeighbors (u v : V) : {p : G.Walk u v // p.length = 2} ≃ G.commonNeighbors u v where toFun p := ⟨p.val.getVert 1, match p with - | ⟨.cons _ (.cons _ .nil), hp⟩ => ⟨‹G.Adj u _›, ‹G.Adj _ v›.symm⟩⟩ + | ⟨.cons _ (.cons _ .nil), _⟩ => ⟨‹G.Adj u _›, ‹G.Adj _ v›.symm⟩⟩ invFun w := ⟨w.prop.1.toWalk.concat w.prop.2.symm, rfl⟩ left_inv | ⟨.cons _ (.cons _ .nil), hp⟩ => by rfl right_inv _ := rfl @@ -152,7 +151,7 @@ theorem set_walk_length_toFinset_eq (n : ℕ) (u v : V) : /- See `SimpleGraph.adjMatrix_pow_apply_eq_card_walk` for the cardinality in terms of the `n`th power of the adjacency matrix. -/ theorem card_set_walk_length_eq (u v : V) (n : ℕ) : - Fintype.card {p : G.Walk u v | p.length = n} = (G.finsetWalkLength n u v).card := + Fintype.card {p : G.Walk u v | p.length = n} = #(G.finsetWalkLength n u v) := Fintype.card_ofFinset (G.finsetWalkLength n u v) fun p => by rw [← Finset.mem_coe, coe_finsetWalkLength_eq] @@ -165,7 +164,7 @@ instance fintypeSubtypeWalkLengthLT (u v : V) (n : ℕ) : Fintype {p : G.Walk u instance fintypeSetPathLength (u v : V) (n : ℕ) : Fintype {p : G.Walk u v | p.IsPath ∧ p.length = n} := - Fintype.ofFinset ((G.finsetWalkLength n u v).filter Walk.IsPath) <| by + Fintype.ofFinset {w ∈ G.finsetWalkLength n u v | w.IsPath} <| by simp [mem_finsetWalkLength_iff, and_comm] instance fintypeSubtypePathLength (u v : V) (n : ℕ) : @@ -174,7 +173,7 @@ instance fintypeSubtypePathLength (u v : V) (n : ℕ) : instance fintypeSetPathLengthLT (u v : V) (n : ℕ) : Fintype {p : G.Walk u v | p.IsPath ∧ p.length < n} := - Fintype.ofFinset ((G.finsetWalkLengthLT n u v).filter Walk.IsPath) <| by + Fintype.ofFinset {w ∈ G.finsetWalkLengthLT n u v | w.IsPath} <| by simp [mem_finsetWalkLengthLT_iff, and_comm] instance fintypeSubtypePathLengthLT (u v : V) (n : ℕ) : @@ -210,7 +209,6 @@ instance : Decidable G.Connected := by rw [connected_iff, ← Finset.univ_nonempty_iff] infer_instance -open Finset in instance Path.instFintype {u v : V} : Fintype (G.Path u v) where elems := (univ (α := { p : G.Walk u v | p.IsPath ∧ p.length < Fintype.card V })).map ⟨fun p ↦ { val := p.val, property := p.prop.left }, diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index 4b09938bdf173..5904dc6245e9b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -49,7 +49,7 @@ section DegreeSum variable [Fintype V] [DecidableRel G.Adj] theorem dart_fst_fiber [DecidableEq V] (v : V) : - (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by + ({d : G.Dart | d.fst = v} : Finset _) = univ.image (G.dartOfNeighborSet v) := by ext d simp only [mem_image, true_and, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true] constructor @@ -59,7 +59,7 @@ theorem dart_fst_fiber [DecidableEq V] (v : V) : rfl theorem dart_fst_fiber_card_eq_degree [DecidableEq V] (v : V) : - (univ.filter fun d : G.Dart => d.fst = v).card = G.degree v := by + #{d : G.Dart | d.fst = v} = G.degree v := by simpa only [dart_fst_fiber, Finset.card_univ, card_neighborSet_eq_degree] using card_image_of_injective univ (G.dartOfNeighborSet_injective v) @@ -71,13 +71,13 @@ theorem dart_card_eq_sum_degrees : Fintype.card G.Dart = ∑ v, G.degree v := by variable {G} theorem Dart.edge_fiber [DecidableEq V] (d : G.Dart) : - (univ.filter fun d' : G.Dart => d'.edge = d.edge) = {d, d.symm} := + ({d' : G.Dart | d'.edge = d.edge} : Finset _) = {d, d.symm} := Finset.ext fun d' => by simpa using dart_edge_eq_iff d' d variable (G) theorem dart_edge_fiber_card [DecidableEq V] (e : Sym2 V) (h : e ∈ G.edgeSet) : - (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by + #{d : G.Dart | d.edge = e} = 2 := by induction' e with v w let d : G.Dart := ⟨(v, w), h⟩ convert congr_arg card d.edge_fiber @@ -85,7 +85,7 @@ theorem dart_edge_fiber_card [DecidableEq V] (e : Sym2 V) (h : e ∈ G.edgeSet) rw [mem_singleton] exact d.symm_ne.symm -theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by +theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * #G.edgeFinset := by classical rw [← card_univ] rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h => @@ -97,11 +97,10 @@ theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.c /-- The degree-sum formula. This is also known as the handshaking lemma, which might more specifically refer to `SimpleGraph.even_card_odd_degree_vertices`. -/ -theorem sum_degrees_eq_twice_card_edges : ∑ v, G.degree v = 2 * G.edgeFinset.card := +theorem sum_degrees_eq_twice_card_edges : ∑ v, G.degree v = 2 * #G.edgeFinset := G.dart_card_eq_sum_degrees.symm.trans G.dart_card_eq_twice_card_edges -lemma two_mul_card_edgeFinset : - 2 * G.edgeFinset.card = (univ.filter fun (x, y) ↦ G.Adj x y).card := by +lemma two_mul_card_edgeFinset : 2 * #G.edgeFinset = #(univ.filter fun (x, y) ↦ G.Adj x y) := by rw [← dart_card_eq_twice_card_edges, ← card_univ] refine card_bij' (fun d _ ↦ (d.fst, d.snd)) (fun xy h ↦ ⟨xy, (mem_filter.1 h).2⟩) ?_ ?_ ?_ ?_ <;> simp @@ -110,7 +109,7 @@ end DegreeSum /-- The handshaking lemma. See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/ theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] : - Even (univ.filter fun v => Odd (G.degree v)).card := by + Even #{v | Odd (G.degree v)} := by classical have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges simp only [ZMod.natCast_self, zero_mul, Nat.cast_mul] at h @@ -126,10 +125,10 @@ theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] : trivial theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRel G.Adj] (v : V) - (h : Odd (G.degree v)) : Odd (univ.filter fun w => w ≠ v ∧ Odd (G.degree w)).card := by + (h : Odd (G.degree v)) : Odd #{w | w ≠ v ∧ Odd (G.degree w)} := by rcases G.even_card_odd_degree_vertices with ⟨k, hg⟩ have hk : 0 < k := by - have hh : (filter (fun v : V => Odd (G.degree v)) univ).Nonempty := by + have hh : Finset.Nonempty {v : V | Odd (G.degree v)} := by use v simp only [true_and, mem_filter, mem_univ] exact h @@ -150,7 +149,7 @@ theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] [DecidableRel G.Ad (h : Odd (G.degree v)) : ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by haveI := Classical.decEq V rcases G.odd_card_odd_degree_vertices_ne v h with ⟨k, hg⟩ - have hg' : (filter (fun w : V => w ≠ v ∧ Odd (G.degree w)) univ).card > 0 := by + have hg' : 0 < #{w | w ≠ v ∧ Odd (G.degree w)} := by rw [hg] apply Nat.succ_pos rcases card_pos.mp hg' with ⟨w, hw⟩ diff --git a/Mathlib/Combinatorics/SimpleGraph/Density.lean b/Mathlib/Combinatorics/SimpleGraph/Density.lean index f71bb81713dbb..487d1b1620a3e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Density.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Density.lean @@ -41,12 +41,10 @@ variable [LinearOrderedField 𝕜] (r : α → β → Prop) [∀ a, DecidablePre {t t₁ t₂ : Finset β} {a : α} {b : β} {δ : 𝕜} /-- Finset of edges of a relation between two finsets of vertices. -/ -def interedges (s : Finset α) (t : Finset β) : Finset (α × β) := - (s ×ˢ t).filter fun e ↦ r e.1 e.2 +def interedges (s : Finset α) (t : Finset β) : Finset (α × β) := {e ∈ s ×ˢ t | r e.1 e.2} /-- Edge density of a relation between two finsets of vertices. -/ -def edgeDensity (s : Finset α) (t : Finset β) : ℚ := - (interedges r s t).card / (s.card * t.card) +def edgeDensity (s : Finset α) (t : Finset β) : ℚ := #(interedges r s t) / (#s * #t) variable {r} @@ -68,7 +66,7 @@ theorem interedges_mono (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) : interedges r variable (r) theorem card_interedges_add_card_interedges_compl (s : Finset α) (t : Finset β) : - (interedges r s t).card + (interedges (fun x y ↦ ¬r x y) s t).card = s.card * t.card := by + #(interedges r s t) + #(interedges (fun x y ↦ ¬r x y) s t) = #s * #t := by classical rw [← card_product, interedges, interedges, ← card_union_of_disjoint, filter_union_filter_neg_eq] exact disjoint_filter.2 fun _ _ ↦ Classical.not_not.2 @@ -92,7 +90,7 @@ section DecidableEq variable [DecidableEq α] [DecidableEq β] lemma interedges_eq_biUnion : - interedges r s t = s.biUnion (fun x ↦ (t.filter (r x)).map ⟨(x, ·), Prod.mk.inj_left x⟩) := by + interedges r s t = s.biUnion fun x ↦ {y ∈ t | r x y}.map ⟨(x, ·), Prod.mk.inj_left x⟩ := by ext ⟨x, y⟩; simp [mem_interedges_iff] theorem interedges_biUnion_left (s : Finset ι) (t : Finset β) (f : ι → Finset α) : @@ -115,7 +113,7 @@ theorem interedges_biUnion (s : Finset ι) (t : Finset κ) (f : ι → Finset α end DecidableEq theorem card_interedges_le_mul (s : Finset α) (t : Finset β) : - (interedges r s t).card ≤ s.card * t.card := + #(interedges r s t) ≤ #s * #t := (card_filter_le _ _).trans (card_product _ _).le theorem edgeDensity_nonneg (s : Finset α) (t : Finset β) : 0 ≤ edgeDensity r s t := by @@ -141,14 +139,14 @@ theorem edgeDensity_empty_right (s : Finset α) : edgeDensity r s ∅ = 0 := by rw [edgeDensity, Finset.card_empty, Nat.cast_zero, mul_zero, div_zero] theorem card_interedges_finpartition_left [DecidableEq α] (P : Finpartition s) (t : Finset β) : - (interedges r s t).card = ∑ a ∈ P.parts, (interedges r a t).card := by + #(interedges r s t) = ∑ a ∈ P.parts, #(interedges r a t) := by classical simp_rw [← P.biUnion_parts, interedges_biUnion_left, id] rw [card_biUnion] exact fun x hx y hy h ↦ interedges_disjoint_left r (P.disjoint hx hy h) _ theorem card_interedges_finpartition_right [DecidableEq β] (s : Finset α) (P : Finpartition t) : - (interedges r s t).card = ∑ b ∈ P.parts, (interedges r s b).card := by + #(interedges r s t) = ∑ b ∈ P.parts, #(interedges r s b) := by classical simp_rw [← P.biUnion_parts, interedges_biUnion_right, id] rw [card_biUnion] @@ -156,22 +154,22 @@ theorem card_interedges_finpartition_right [DecidableEq β] (s : Finset α) (P : theorem card_interedges_finpartition [DecidableEq α] [DecidableEq β] (P : Finpartition s) (Q : Finpartition t) : - (interedges r s t).card = ∑ ab ∈ P.parts ×ˢ Q.parts, (interedges r ab.1 ab.2).card := by + #(interedges r s t) = ∑ ab ∈ P.parts ×ˢ Q.parts, #(interedges r ab.1 ab.2) := by rw [card_interedges_finpartition_left _ P, sum_product] congr; ext rw [card_interedges_finpartition_right] theorem mul_edgeDensity_le_edgeDensity (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (hs₂ : s₂.Nonempty) (ht₂ : t₂.Nonempty) : - (s₂.card : ℚ) / s₁.card * (t₂.card / t₁.card) * edgeDensity r s₂ t₂ ≤ edgeDensity r s₁ t₁ := by - have hst : (s₂.card : ℚ) * t₂.card ≠ 0 := by simp [hs₂.ne_empty, ht₂.ne_empty] + (#s₂ : ℚ) / #s₁ * (#t₂ / #t₁) * edgeDensity r s₂ t₂ ≤ edgeDensity r s₁ t₁ := by + have hst : (#s₂ : ℚ) * #t₂ ≠ 0 := by simp [hs₂.ne_empty, ht₂.ne_empty] rw [edgeDensity, edgeDensity, div_mul_div_comm, mul_comm, div_mul_div_cancel₀ hst] gcongr exact interedges_mono hs ht theorem edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (hs₂ : s₂.Nonempty) (ht₂ : t₂.Nonempty) : - edgeDensity r s₂ t₂ - edgeDensity r s₁ t₁ ≤ 1 - s₂.card / s₁.card * (t₂.card / t₁.card) := by + edgeDensity r s₂ t₂ - edgeDensity r s₁ t₁ ≤ 1 - #s₂ / #s₁ * (#t₂ / #t₁) := by refine (sub_le_sub_left (mul_edgeDensity_le_edgeDensity r hs ht hs₂ ht₂) _).trans ?_ refine le_trans ?_ (mul_le_of_le_one_right ?_ (edgeDensity_le_one r s₂ t₂)) · rw [sub_mul, one_mul] @@ -182,7 +180,7 @@ theorem edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t theorem abs_edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (hs₂ : s₂.Nonempty) (ht₂ : t₂.Nonempty) : - |edgeDensity r s₂ t₂ - edgeDensity r s₁ t₁| ≤ 1 - s₂.card / s₁.card * (t₂.card / t₁.card) := by + |edgeDensity r s₂ t₂ - edgeDensity r s₁ t₁| ≤ 1 - #s₂ / #s₁ * (#t₂ / #t₁) := by refine abs_sub_le_iff.2 ⟨edgeDensity_sub_edgeDensity_le_one_sub_mul r hs ht hs₂ ht₂, ?_⟩ rw [← add_sub_cancel_right (edgeDensity r s₁ t₁) (edgeDensity (fun x y ↦ ¬r x y) s₁ t₁), ← add_sub_cancel_right (edgeDensity r s₂ t₂) (edgeDensity (fun x y ↦ ¬r x y) s₂ t₂), @@ -191,8 +189,8 @@ theorem abs_edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht exact edgeDensity_sub_edgeDensity_le_one_sub_mul _ hs ht hs₂ ht₂ theorem abs_edgeDensity_sub_edgeDensity_le_two_mul_sub_sq (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) - (hδ₀ : 0 ≤ δ) (hδ₁ : δ < 1) (hs₂ : (1 - δ) * s₁.card ≤ s₂.card) - (ht₂ : (1 - δ) * t₁.card ≤ t₂.card) : + (hδ₀ : 0 ≤ δ) (hδ₁ : δ < 1) (hs₂ : (1 - δ) * #s₁ ≤ #s₂) + (ht₂ : (1 - δ) * #t₁ ≤ #t₂) : |(edgeDensity r s₂ t₂ : 𝕜) - edgeDensity r s₁ t₁| ≤ 2 * δ - δ ^ 2 := by have hδ' : 0 ≤ 2 * δ - δ ^ 2 := by rw [sub_nonneg, sq] @@ -222,7 +220,7 @@ theorem abs_edgeDensity_sub_edgeDensity_le_two_mul_sub_sq (hs : s₂ ⊆ s₁) ( /-- If `s₂ ⊆ s₁`, `t₂ ⊆ t₁` and they take up all but a `δ`-proportion, then the difference in edge densities is at most `2 * δ`. -/ theorem abs_edgeDensity_sub_edgeDensity_le_two_mul (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (hδ : 0 ≤ δ) - (hscard : (1 - δ) * s₁.card ≤ s₂.card) (htcard : (1 - δ) * t₁.card ≤ t₂.card) : + (hscard : (1 - δ) * #s₁ ≤ #s₂) (htcard : (1 - δ) * #t₁ ≤ #t₂) : |(edgeDensity r s₂ t₂ : 𝕜) - edgeDensity r s₁ t₁| ≤ 2 * δ := by cases' lt_or_le δ 1 with h h · exact (abs_edgeDensity_sub_edgeDensity_le_two_mul_sub_sq r hs ht hδ h hscard htcard).trans @@ -237,7 +235,7 @@ end Asymmetric section Symmetric -variable {r : α → α → Prop} [DecidableRel r] {s s₁ s₂ t t₁ t₂ : Finset α} {a b : α} +variable {r : α → α → Prop} [DecidableRel r] {s t : Finset α} {a b : α} @[simp] theorem swap_mem_interedges_iff (hr : Symmetric r) {x : α × α} : @@ -250,7 +248,7 @@ theorem mk_mem_interedges_comm (hr : Symmetric r) : @swap_mem_interedges_iff _ _ _ _ _ hr (b, a) theorem card_interedges_comm (hr : Symmetric r) (s t : Finset α) : - (interedges r s t).card = (interedges r t s).card := + #(interedges r s t) = #(interedges r t s) := Finset.card_bij (fun (x : α × α) _ ↦ x.swap) (fun _ ↦ (swap_mem_interedges_iff hr).2) (fun _ _ _ _ h ↦ Prod.swap_injective h) fun x h ↦ ⟨x.swap, (swap_mem_interedges_iff hr).2 h, x.swap_swap⟩ @@ -280,16 +278,12 @@ def interedges (s t : Finset α) : Finset (α × α) := def edgeDensity : Finset α → Finset α → ℚ := Rel.edgeDensity G.Adj -theorem interedges_def (s t : Finset α) : - G.interedges s t = (s ×ˢ t).filter fun e ↦ G.Adj e.1 e.2 := - rfl +lemma interedges_def (s t : Finset α) : G.interedges s t = {e ∈ s ×ˢ t | G.Adj e.1 e.2} := rfl -theorem edgeDensity_def (s t : Finset α) : - G.edgeDensity s t = (G.interedges s t).card / (s.card * t.card) := - rfl +lemma edgeDensity_def (s t : Finset α) : G.edgeDensity s t = #(G.interedges s t) / (#s * #t) := rfl theorem card_interedges_div_card (s t : Finset α) : - ((G.interedges s t).card : ℚ) / (s.card * t.card) = G.edgeDensity s t := + (#(G.interedges s t) : ℚ) / (#s * #t) = G.edgeDensity s t := rfl theorem mem_interedges_iff {x : α × α} : x ∈ G.interedges s t ↔ x.1 ∈ s ∧ x.2 ∈ t ∧ G.Adj x.1 x.2 := @@ -331,9 +325,9 @@ theorem interedges_biUnion (s : Finset ι) (t : Finset κ) (f : ι → Finset α Rel.interedges_biUnion _ _ _ _ _ theorem card_interedges_add_card_interedges_compl (h : Disjoint s t) : - (G.interedges s t).card + (Gᶜ.interedges s t).card = s.card * t.card := by + #(G.interedges s t) + #(Gᶜ.interedges s t) = #s * #t := by rw [← card_product, interedges_def, interedges_def] - have : ((s ×ˢ t).filter fun e ↦ Gᶜ.Adj e.1 e.2) = (s ×ˢ t).filter fun e ↦ ¬G.Adj e.1 e.2 := by + have : {e ∈ s ×ˢ t | Gᶜ.Adj e.1 e.2} = {e ∈ s ×ˢ t | ¬G.Adj e.1 e.2} := by refine filter_congr fun x hx ↦ ?_ rw [mem_product] at hx rw [compl_adj, and_iff_right (h.forall_ne_finset hx.1 hx.2)] @@ -349,7 +343,7 @@ theorem edgeDensity_add_edgeDensity_compl (hs : s.Nonempty) (ht : t.Nonempty) (h end DecidableEq -theorem card_interedges_le_mul (s t : Finset α) : (G.interedges s t).card ≤ s.card * t.card := +theorem card_interedges_le_mul (s t : Finset α) : #(G.interedges s t) ≤ #s * #t := Rel.card_interedges_le_mul _ _ _ theorem edgeDensity_nonneg (s t : Finset α) : 0 ≤ G.edgeDensity s t := diff --git a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean index e5a841272ed81..1f6be300ede03 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean @@ -17,7 +17,7 @@ assigning, to each finite set of vertices, the connected components of its compl universe u -variable {V : Type u} (G : SimpleGraph V) (K L L' M : Set V) +variable {V : Type u} (G : SimpleGraph V) (K L M : Set V) namespace SimpleGraph @@ -179,12 +179,12 @@ theorem hom_eq_iff_not_disjoint (C : G.ComponentCompl L) (h : K ⊆ L) (D : G.Co theorem hom_refl (C : G.ComponentCompl L) : C.hom (subset_refl L) = C := by change C.map _ = C - erw [induceHom_id G Lᶜ, ConnectedComponent.map_id] + rw [induceHom_id G Lᶜ, ConnectedComponent.map_id] theorem hom_trans (C : G.ComponentCompl L) (h : K ⊆ L) (h' : M ⊆ K) : C.hom (h'.trans h) = (C.hom h).hom h' := by change C.map _ = (C.map _).map _ - erw [ConnectedComponent.map_comp, induceHom_comp] + rw [ConnectedComponent.map_comp, induceHom_comp] rfl theorem hom_mk {v : V} (vnL : v ∉ L) (h : K ⊆ L) : diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index bab7f40b821df..e0611556ee07e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -101,27 +101,26 @@ lemma edgeFinset_eq_empty : G.edgeFinset = ∅ ↔ G = ⊥ := by lemma edgeFinset_nonempty : G.edgeFinset.Nonempty ↔ G ≠ ⊥ := by rw [Finset.nonempty_iff_ne_empty, edgeFinset_eq_empty.ne] -theorem edgeFinset_card : G.edgeFinset.card = Fintype.card G.edgeSet := +theorem edgeFinset_card : #G.edgeFinset = Fintype.card G.edgeSet := Set.toFinset_card _ @[simp] -theorem edgeSet_univ_card : (univ : Finset G.edgeSet).card = G.edgeFinset.card := +theorem edgeSet_univ_card : #(univ : Finset G.edgeSet) = #G.edgeFinset := Fintype.card_of_subtype G.edgeFinset fun _ => mem_edgeFinset variable [Fintype V] @[simp] theorem edgeFinset_top [DecidableEq V] : - (⊤ : SimpleGraph V).edgeFinset = univ.filter fun e => ¬e.IsDiag := by - rw [← coe_inj]; simp + (⊤ : SimpleGraph V).edgeFinset = ({e | ¬e.IsDiag} : Finset _) := by simp [← coe_inj] /-- The complete graph on `n` vertices has `n.choose 2` edges. -/ theorem card_edgeFinset_top_eq_card_choose_two [DecidableEq V] : - (⊤ : SimpleGraph V).edgeFinset.card = (Fintype.card V).choose 2 := by + #(⊤ : SimpleGraph V).edgeFinset = (Fintype.card V).choose 2 := by simp_rw [Set.toFinset_card, edgeSet_top, Set.coe_setOf, ← Sym2.card_subtype_not_diag] /-- Any graph on `n` vertices has at most `n.choose 2` edges. -/ -theorem card_edgeFinset_le_card_choose_two : G.edgeFinset.card ≤ (Fintype.card V).choose 2 := by +theorem card_edgeFinset_le_card_choose_two : #G.edgeFinset ≤ (Fintype.card V).choose 2 := by classical rw [← card_edgeFinset_top_eq_card_choose_two] exact card_le_card (edgeFinset_mono le_top) @@ -143,13 +142,13 @@ variable {𝕜 : Type*} [OrderedRing 𝕜] /-- A graph is `r`-*delete-far* from a property `p` if we must delete at least `r` edges from it to get a graph with the property `p`. -/ def DeleteFar (p : SimpleGraph V → Prop) (r : 𝕜) : Prop := - ∀ ⦃s⦄, s ⊆ G.edgeFinset → p (G.deleteEdges s) → r ≤ s.card + ∀ ⦃s⦄, s ⊆ G.edgeFinset → p (G.deleteEdges s) → r ≤ #s variable {G} theorem deleteFar_iff [Fintype (Sym2 V)] : G.DeleteFar p r ↔ ∀ ⦃H : SimpleGraph _⦄ [DecidableRel H.Adj], - H ≤ G → p H → r ≤ G.edgeFinset.card - H.edgeFinset.card := by + H ≤ G → p H → r ≤ #G.edgeFinset - #H.edgeFinset := by classical refine ⟨fun h H _ hHG hH ↦ ?_, fun h s hs hG ↦ ?_⟩ · have := h (sdiff_subset (t := H.edgeFinset)) @@ -203,15 +202,14 @@ theorem singleton_disjoint_neighborFinset : Disjoint {v} (G.neighborFinset v) := Finset.disjoint_singleton_left.mpr <| not_mem_neighborFinset_self _ _ /-- `G.degree v` is the number of vertices adjacent to `v`. -/ -def degree : ℕ := - (G.neighborFinset v).card +def degree : ℕ := #(G.neighborFinset v) -- Porting note: in Lean 3 we could do `simp [← degree]`, but that gives -- "invalid '←' modifier, 'SimpleGraph.degree' is a declaration name to be unfolded". -- In any case, having this lemma is good since there's no guarantee we won't still change -- the definition of `degree`. @[simp] -theorem card_neighborFinset_eq_degree : (G.neighborFinset v).card = G.degree v := rfl +theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rfl @[simp] theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := @@ -240,8 +238,7 @@ theorem card_incidenceSet_eq_degree [DecidableEq V] : simp @[simp] -theorem card_incidenceFinset_eq_degree [DecidableEq V] : - (G.incidenceFinset v).card = G.degree v := by +theorem card_incidenceFinset_eq_degree [DecidableEq V] : #(G.incidenceFinset v) = G.degree v := by rw [← G.card_incidenceSet_eq_degree] apply Set.toFinset_card @@ -251,7 +248,7 @@ theorem mem_incidenceFinset [DecidableEq V] (e : Sym2 V) : Set.mem_toFinset theorem incidenceFinset_eq_filter [DecidableEq V] [Fintype G.edgeSet] : - G.incidenceFinset v = G.edgeFinset.filter (v ∈ ·) := by + G.incidenceFinset v = {e ∈ G.edgeFinset | v ∈ e} := by ext e induction e simp [mk'_mem_incidenceSet_iff] @@ -294,9 +291,7 @@ instance neighborSetFintype [DecidableRel G.Adj] (v : V) : Fintype (G.neighborSe _ theorem neighborFinset_eq_filter {v : V} [DecidableRel G.Adj] : - G.neighborFinset v = Finset.univ.filter (G.Adj v) := by - ext - simp + G.neighborFinset v = ({w | G.Adj v w} : Finset _) := by ext; simp theorem neighborFinset_compl [DecidableEq V] [DecidableRel G.Adj] (v : V) : Gᶜ.neighborFinset v = (G.neighborFinset v)ᶜ \ {v} := by @@ -417,7 +412,7 @@ the best we can do in general. -/ theorem Adj.card_commonNeighbors_lt_degree {G : SimpleGraph V} [DecidableRel G.Adj] {v w : V} (h : G.Adj v w) : Fintype.card (G.commonNeighbors v w) < G.degree v := by classical - erw [← Set.toFinset_card] + rw [← Set.toFinset_card] apply Finset.card_lt_card rw [Finset.ssubset_iff] use w diff --git a/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean b/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean index 30662b99dcef9..57b96702dfdb7 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Rishi Mehta, Linus Sommer -/ import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Data.List.Count import Mathlib.Combinatorics.SimpleGraph.Path /-! @@ -51,7 +52,7 @@ lemma IsPath.isHamiltonian_iff (hp : p.IsPath) : p.IsHamiltonian ↔ ∀ w, w ⟨(·.mem_support), hp.isHamiltonian_of_mem⟩ section -variable [Fintype α] [Fintype β] +variable [Fintype α] /-- The support of a hamiltonian walk is the entire vertex set. -/ lemma IsHamiltonian.support_toFinset (hp : p.IsHamiltonian) : p.support.toFinset = Finset.univ := by @@ -66,7 +67,7 @@ lemma IsHamiltonian.length_eq (hp : p.IsHamiltonian) : p.length = Fintype.card end /-- A hamiltonian cycle is a cycle that visits every vertex once. -/ -structure IsHamiltonianCycle (p : G.Walk a a) extends p.IsCycle : Prop := +structure IsHamiltonianCycle (p : G.Walk a a) extends p.IsCycle : Prop where isHamiltonian_tail : p.tail.IsHamiltonian variable {p : G.Walk a a} @@ -78,9 +79,7 @@ lemma IsHamiltonianCycle.map {H : SimpleGraph β} (f : G →g H) (hf : Bijective (hp : p.IsHamiltonianCycle) : (p.map f).IsHamiltonianCycle where toIsCycle := hp.isCycle.map hf.injective isHamiltonian_tail := by - simp only [IsHamiltonian, support_tail, support_map, ne_eq, List.map_eq_nil_iff, support_ne_nil, - not_false_eq_true, List.count_tail, List.head_map, beq_iff_eq, hf.surjective.forall, - hf.injective, List.count_map_of_injective] + simp only [IsHamiltonian, hf.surjective.forall] intro x rcases p with (_ | ⟨y, p⟩) · cases hp.ne_nil rfl diff --git a/Mathlib/Combinatorics/SimpleGraph/Hasse.lean b/Mathlib/Combinatorics/SimpleGraph/Hasse.lean index 5e6d344ea80ad..3b51ad2f9fad4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Hasse.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Hasse.lean @@ -30,7 +30,7 @@ variable (α β : Type*) section Preorder -variable [Preorder α] [Preorder β] +variable [Preorder α] /-- The Hasse diagram of an order as a simple graph. The graph of the covering relation. -/ def hasse : SimpleGraph α where diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index 8a8ce3e22216a..d9c6f7e8c5a8d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -105,7 +105,7 @@ end MulZeroOneClass section NonAssocSemiring -variable [NonAssocSemiring R] {a b : α} {e : Sym2 α} +variable [NonAssocSemiring R] {a : α} {e : Sym2 α} theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Fintype (neighborSet G a)] : ∑ e, G.incMatrix R a e = G.degree a := by @@ -158,7 +158,7 @@ end NonAssocSemiring section Semiring -variable [Fintype (Sym2 α)] [Semiring R] {a b : α} {e : Sym2 α} +variable [Fintype (Sym2 α)] [Semiring R] {a b : α} theorem incMatrix_mul_transpose_apply_of_adj (h : G.Adj a b) : (G.incMatrix R * (G.incMatrix R)ᵀ) a b = (1 : R) := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index 93f6348a4d897..77a6eacef6ab1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -129,7 +129,7 @@ theorem comap_surjective (f : V ↪ W) : Function.Surjective (SimpleGraph.comap theorem map_le_iff_le_comap (f : V ↪ W) (G : SimpleGraph V) (G' : SimpleGraph W) : G.map f ≤ G' ↔ G ≤ G'.comap f := - ⟨fun h u v ha => h ⟨_, _, ha, rfl, rfl⟩, by + ⟨fun h _ _ ha => h ⟨_, _, ha, rfl, rfl⟩, by rintro h _ _ ⟨u, v, ha, rfl, rfl⟩ exact h ha⟩ diff --git a/Mathlib/Combinatorics/SimpleGraph/Operations.lean b/Mathlib/Combinatorics/SimpleGraph/Operations.lean index 814a10a5cc143..fea650ca66f09 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Operations.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Operations.lean @@ -34,7 +34,7 @@ variable {G} {W : Type*} {G' : SimpleGraph W} (f : G ≃g G') include f in theorem card_edgeFinset_eq [Fintype G.edgeSet] [Fintype G'.edgeSet] : - G.edgeFinset.card = G'.edgeFinset.card := by + #G.edgeFinset = #G'.edgeFinset := by apply Finset.card_eq_of_equiv simp only [Set.mem_toFinset] exact f.mapEdgeSet @@ -116,7 +116,7 @@ lemma disjoint_sdiff_neighborFinset_image : aesop theorem card_edgeFinset_replaceVertex_of_not_adj (hn : ¬G.Adj s t) : - (G.replaceVertex s t).edgeFinset.card = G.edgeFinset.card + G.degree s - G.degree t := by + #(G.replaceVertex s t).edgeFinset = #G.edgeFinset + G.degree s - G.degree t := by have inc : G.incidenceFinset t ⊆ G.edgeFinset := by simp [incidenceFinset, incidenceSet_subset] rw [G.edgeFinset_replaceVertex_of_not_adj hn, card_union_of_disjoint G.disjoint_sdiff_neighborFinset_image, card_sdiff inc, @@ -127,7 +127,7 @@ theorem card_edgeFinset_replaceVertex_of_not_adj (hn : ¬G.Adj s t) : aesop theorem card_edgeFinset_replaceVertex_of_adj (ha : G.Adj s t) : - (G.replaceVertex s t).edgeFinset.card = G.edgeFinset.card + G.degree s - G.degree t - 1 := by + #(G.replaceVertex s t).edgeFinset = #G.edgeFinset + G.degree s - G.degree t - 1 := by have inc : G.incidenceFinset t ⊆ G.edgeFinset := by simp [incidenceFinset, incidenceSet_subset] rw [G.edgeFinset_replaceVertex_of_adj ha, card_sdiff (by simp [ha]), card_union_of_disjoint G.disjoint_sdiff_neighborFinset_image, card_sdiff inc, @@ -180,7 +180,7 @@ theorem edgeFinset_sup_edge [Fintype (edgeSet (G ⊔ edge s t))] (hn : ¬G.Adj s simp_rw [edgeFinset, edge_edgeSet_of_ne h]; rfl theorem card_edgeFinset_sup_edge [Fintype (edgeSet (G ⊔ edge s t))] (hn : ¬G.Adj s t) (h : s ≠ t) : - (G ⊔ edge s t).edgeFinset.card = G.edgeFinset.card + 1 := by + #(G ⊔ edge s t).edgeFinset = #G.edgeFinset + 1 := by rw [G.edgeFinset_sup_edge hn h, card_cons] end AddEdge diff --git a/Mathlib/Combinatorics/SimpleGraph/Prod.lean b/Mathlib/Combinatorics/SimpleGraph/Prod.lean index df7d60cc174f7..e094ff9729ec2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Prod.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Prod.lean @@ -50,12 +50,10 @@ theorem boxProd_adj {x y : α × β} : (G □ H).Adj x y ↔ G.Adj x.1 y.1 ∧ x.2 = y.2 ∨ H.Adj x.2 y.2 ∧ x.1 = y.1 := Iff.rfl ---@[simp] Porting note (#10618): `simp` can prove theorem boxProd_adj_left {a₁ : α} {b : β} {a₂ : α} : (G □ H).Adj (a₁, b) (a₂, b) ↔ G.Adj a₁ a₂ := by simp only [boxProd_adj, and_true, SimpleGraph.irrefl, false_and, or_false] ---@[simp] Porting note (#10618): `simp` can prove theorem boxProd_adj_right {a : α} {b₁ b₂ : β} : (G □ H).Adj (a, b₁) (a, b₂) ↔ H.Adj b₁ b₂ := by simp only [boxProd_adj, SimpleGraph.irrefl, false_and, and_true, false_or] diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index 5ee0f683c85af..131989eef9048 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -40,7 +40,7 @@ def stepBound (n : ℕ) : ℕ := theorem le_stepBound : id ≤ stepBound := fun n => Nat.le_mul_of_pos_right _ <| pow_pos (by norm_num) n -theorem stepBound_mono : Monotone stepBound := fun a b h => +theorem stepBound_mono : Monotone stepBound := fun _ _ h => Nat.mul_le_mul h <| Nat.pow_le_pow_of_le_right (by norm_num) h theorem stepBound_pos_iff {n : ℕ} : 0 < stepBound n ↔ 0 < n := @@ -58,9 +58,9 @@ open SzemerediRegularity variable {α : Type*} [DecidableEq α] [Fintype α] {P : Finpartition (univ : Finset α)} {u : Finset α} {ε : ℝ} -local notation3 "m" => (card α / stepBound P.parts.card : ℕ) +local notation3 "m" => (card α / stepBound #P.parts : ℕ) -local notation3 "a" => (card α / P.parts.card - m * 4 ^ P.parts.card : ℕ) +local notation3 "a" => (card α / #P.parts - m * 4 ^ #P.parts : ℕ) namespace SzemerediRegularity.Positivity @@ -68,7 +68,7 @@ private theorem eps_pos {ε : ℝ} {n : ℕ} (h : 100 ≤ (4 : ℝ) ^ n * ε ^ 5 (Odd.pow_pos_iff (by decide)).mp (pos_of_mul_pos_right ((show 0 < (100 : ℝ) by norm_num).trans_le h) (by positivity)) -private theorem m_pos [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : 0 < m := +private theorem m_pos [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) : 0 < m := Nat.div_pos ((Nat.mul_le_mul_left _ <| Nat.pow_le_pow_left (by norm_num) _).trans hPα) <| stepBound_pos (P.parts_nonempty <| univ_nonempty.ne_empty).card_pos @@ -101,49 +101,48 @@ namespace SzemerediRegularity open scoped SzemerediRegularity.Positivity -theorem m_pos [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : 0 < m := by +theorem m_pos [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) : 0 < m := by sz_positivity theorem coe_m_add_one_pos : 0 < (m : ℝ) + 1 := by positivity -theorem one_le_m_coe [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : (1 : ℝ) ≤ m := +theorem one_le_m_coe [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) : (1 : ℝ) ≤ m := Nat.one_le_cast.2 <| m_pos hPα -theorem eps_pow_five_pos (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : ↑0 < ε ^ 5 := +theorem eps_pow_five_pos (hPε : 100 ≤ (4 : ℝ) ^ #P.parts * ε ^ 5) : ↑0 < ε ^ 5 := pos_of_mul_pos_right ((by norm_num : (0 : ℝ) < 100).trans_le hPε) <| pow_nonneg (by norm_num) _ -theorem eps_pos (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : 0 < ε := +theorem eps_pos (hPε : 100 ≤ (4 : ℝ) ^ #P.parts * ε ^ 5) : 0 < ε := (Odd.pow_pos_iff (by decide)).mp (eps_pow_five_pos hPε) -theorem hundred_div_ε_pow_five_le_m [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : 100 / ε ^ 5 ≤ m := +theorem hundred_div_ε_pow_five_le_m [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) + (hPε : 100 ≤ (4 : ℝ) ^ #P.parts * ε ^ 5) : 100 / ε ^ 5 ≤ m := (div_le_of_le_mul₀ (eps_pow_five_pos hPε).le (by positivity) hPε).trans <| by norm_cast rwa [Nat.le_div_iff_mul_le' (stepBound_pos (P.parts_nonempty <| univ_nonempty.ne_empty).card_pos), stepBound, mul_left_comm, ← mul_pow] -theorem hundred_le_m [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) (hε : ε ≤ 1) : 100 ≤ m := +theorem hundred_le_m [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) + (hPε : 100 ≤ (4 : ℝ) ^ #P.parts * ε ^ 5) (hε : ε ≤ 1) : 100 ≤ m := mod_cast (hundred_div_ε_pow_five_le_m hPα hPε).trans' (le_div_self (by norm_num) (by sz_positivity) <| pow_le_one₀ (by sz_positivity) hε) -theorem a_add_one_le_four_pow_parts_card : a + 1 ≤ 4 ^ P.parts.card := by - have h : 1 ≤ 4 ^ P.parts.card := one_le_pow₀ (by norm_num) +theorem a_add_one_le_four_pow_parts_card : a + 1 ≤ 4 ^ #P.parts := by + have h : 1 ≤ 4 ^ #P.parts := one_le_pow₀ (by norm_num) rw [stepBound, ← Nat.div_div_eq_div_mul] conv_rhs => rw [← Nat.sub_add_cancel h] rw [add_le_add_iff_right, tsub_le_iff_left, ← Nat.add_sub_assoc h] exact Nat.le_sub_one_of_lt (Nat.lt_div_mul_add h) -theorem card_aux₁ (hucard : u.card = m * 4 ^ P.parts.card + a) : - (4 ^ P.parts.card - a) * m + a * (m + 1) = u.card := by +theorem card_aux₁ (hucard : #u = m * 4 ^ #P.parts + a) : + (4 ^ #P.parts - a) * m + a * (m + 1) = #u := by rw [hucard, mul_add, mul_one, ← add_assoc, ← add_mul, Nat.sub_add_cancel ((Nat.le_succ _).trans a_add_one_le_four_pow_parts_card), mul_comm] -theorem card_aux₂ (hP : P.IsEquipartition) (hu : u ∈ P.parts) - (hucard : ¬u.card = m * 4 ^ P.parts.card + a) : - (4 ^ P.parts.card - (a + 1)) * m + (a + 1) * (m + 1) = u.card := by - have : m * 4 ^ P.parts.card ≤ card α / P.parts.card := by +theorem card_aux₂ (hP : P.IsEquipartition) (hu : u ∈ P.parts) (hucard : #u ≠ m * 4 ^ #P.parts + a) : + (4 ^ #P.parts - (a + 1)) * m + (a + 1) * (m + 1) = #u := by + have : m * 4 ^ #P.parts ≤ card α / #P.parts := by rw [stepBound, ← Nat.div_div_eq_div_mul] exact Nat.div_mul_le_self _ _ rw [Nat.add_sub_of_le this] at hucard @@ -152,7 +151,7 @@ theorem card_aux₂ (hP : P.IsEquipartition) (hu : u ∈ P.parts) Nat.add_sub_of_le this, card_univ] theorem pow_mul_m_le_card_part (hP : P.IsEquipartition) (hu : u ∈ P.parts) : - (4 : ℝ) ^ P.parts.card * m ≤ u.card := by + (4 : ℝ) ^ #P.parts * m ≤ #u := by norm_cast rw [stepBound, ← Nat.div_div_eq_div_mul] exact (Nat.mul_div_le _ _).trans (hP.average_le_card_part hu) @@ -197,38 +196,36 @@ theorem le_bound : l ≤ bound ε l := theorem bound_pos : 0 < bound ε l := (initialBound_pos ε l).trans_le <| initialBound_le_bound ε l -variable {ι 𝕜 : Type*} [LinearOrderedField 𝕜] (r : ι → ι → Prop) [DecidableRel r] {s t : Finset ι} - {x : 𝕜} +variable {ι 𝕜 : Type*} [LinearOrderedField 𝕜] {s t : Finset ι} {x : 𝕜} -theorem mul_sq_le_sum_sq (hst : s ⊆ t) (f : ι → 𝕜) (hs : x ^ 2 ≤ ((∑ i ∈ s, f i) / s.card) ^ 2) - (hs' : (s.card : 𝕜) ≠ 0) : (s.card : 𝕜) * x ^ 2 ≤ ∑ i ∈ t, f i ^ 2 := +theorem mul_sq_le_sum_sq (hst : s ⊆ t) (f : ι → 𝕜) (hs : x ^ 2 ≤ ((∑ i ∈ s, f i) / #s) ^ 2) + (hs' : (#s : 𝕜) ≠ 0) : (#s : 𝕜) * x ^ 2 ≤ ∑ i ∈ t, f i ^ 2 := (mul_le_mul_of_nonneg_left (hs.trans sum_div_card_sq_le_sum_sq_div_card) <| Nat.cast_nonneg _).trans <| (mul_div_cancel₀ _ hs').le.trans <| sum_le_sum_of_subset_of_nonneg hst fun _ _ _ => sq_nonneg _ theorem add_div_le_sum_sq_div_card (hst : s ⊆ t) (f : ι → 𝕜) (d : 𝕜) (hx : 0 ≤ x) - (hs : x ≤ |(∑ i ∈ s, f i) / s.card - (∑ i ∈ t, f i) / t.card|) - (ht : d ≤ ((∑ i ∈ t, f i) / t.card) ^ 2) : - d + s.card / t.card * x ^ 2 ≤ (∑ i ∈ t, f i ^ 2) / t.card := by - obtain hscard | hscard := (s.card.cast_nonneg : (0 : 𝕜) ≤ s.card).eq_or_lt + (hs : x ≤ |(∑ i ∈ s, f i) / #s - (∑ i ∈ t, f i) / #t|) (ht : d ≤ ((∑ i ∈ t, f i) / #t) ^ 2) : + d + #s / #t * x ^ 2 ≤ (∑ i ∈ t, f i ^ 2) / #t := by + obtain hscard | hscard := ((#s).cast_nonneg : (0 : 𝕜) ≤ #s).eq_or_lt · simpa [← hscard] using ht.trans sum_div_card_sq_le_sum_sq_div_card - have htcard : (0 : 𝕜) < t.card := hscard.trans_le (Nat.cast_le.2 (card_le_card hst)) - have h₁ : x ^ 2 ≤ ((∑ i ∈ s, f i) / s.card - (∑ i ∈ t, f i) / t.card) ^ 2 := + have htcard : (0 : 𝕜) < #t := hscard.trans_le (Nat.cast_le.2 (card_le_card hst)) + have h₁ : x ^ 2 ≤ ((∑ i ∈ s, f i) / #s - (∑ i ∈ t, f i) / #t) ^ 2 := sq_le_sq.2 (by rwa [abs_of_nonneg hx]) - have h₂ : x ^ 2 ≤ ((∑ i ∈ s, (f i - (∑ j ∈ t, f j) / t.card)) / s.card) ^ 2 := by + have h₂ : x ^ 2 ≤ ((∑ i ∈ s, (f i - (∑ j ∈ t, f j) / #t)) / #s) ^ 2 := by apply h₁.trans rw [sum_sub_distrib, sum_const, nsmul_eq_mul, sub_div, mul_div_cancel_left₀ _ hscard.ne'] apply (add_le_add_right ht _).trans rw [← mul_div_right_comm, le_div_iff₀ htcard, add_mul, div_mul_cancel₀ _ htcard.ne'] - have h₃ := mul_sq_le_sum_sq hst (fun i => (f i - (∑ j ∈ t, f j) / t.card)) h₂ hscard.ne' + have h₃ := mul_sq_le_sum_sq hst (fun i => (f i - (∑ j ∈ t, f j) / #t)) h₂ hscard.ne' apply (add_le_add_left h₃ _).trans -- Porting note: was - -- `simp [← mul_div_right_comm _ (t.card : 𝕜), sub_div' _ _ _ htcard.ne', ← sum_div, ← add_div,` + -- `simp [← mul_div_right_comm _ (#t : 𝕜), sub_div' _ _ _ htcard.ne', ← sum_div, ← add_div,` -- ` mul_pow, div_le_iff₀ (sq_pos_of_ne_zero htcard.ne'), sub_sq, sum_add_distrib, ← sum_mul,` -- ` ← mul_sum]` simp_rw [sub_div' _ _ _ htcard.ne'] conv_lhs => enter [2, 2, x]; rw [div_pow] - rw [div_pow, ← sum_div, ← mul_div_right_comm _ (t.card : 𝕜), ← add_div, + rw [div_pow, ← sum_div, ← mul_div_right_comm _ (#t : 𝕜), ← add_div, div_le_iff₀ (sq_pos_of_ne_zero htcard.ne')] simp_rw [sub_sq, sum_add_distrib, sum_const, nsmul_eq_mul, sum_sub_distrib, mul_pow, ← sum_mul, ← mul_sum, ← sum_mul] diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean index e9ac95f5e3f00..07a903fca9f50 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean @@ -44,7 +44,7 @@ variable {α : Type*} [Fintype α] [DecidableEq α] {P : Finpartition (univ : Fi (hP : P.IsEquipartition) (G : SimpleGraph α) [DecidableRel G.Adj] (ε : ℝ) {U : Finset α} (hU : U ∈ P.parts) (V : Finset α) -local notation3 "m" => (card α / stepBound P.parts.card : ℕ) +local notation3 "m" => (card α / stepBound #P.parts : ℕ) /-! ### Definitions @@ -56,16 +56,16 @@ contained in the corresponding witness of non-uniformity. /-- The portion of `SzemerediRegularity.increment` which partitions `U`. -/ noncomputable def chunk : Finpartition U := - if hUcard : U.card = m * 4 ^ P.parts.card + (card α / P.parts.card - m * 4 ^ P.parts.card) then + if hUcard : #U = m * 4 ^ #P.parts + (card α / #P.parts - m * 4 ^ #P.parts) then (atomise U <| P.nonuniformWitnesses G ε U).equitabilise <| card_aux₁ hUcard else (atomise U <| P.nonuniformWitnesses G ε U).equitabilise <| card_aux₂ hP hU hUcard -- `hP` and `hU` are used to get that `U` has size --- `m * 4 ^ P.parts.card + a or m * 4 ^ P.parts.card + a + 1` +-- `m * 4 ^ #P.parts + a or m * 4 ^ #P.parts + a + 1` /-- The portion of `SzemerediRegularity.chunk` which is contained in the witness of non-uniformity of `U` and `V`. -/ noncomputable def star (V : Finset α) : Finset (Finset α) := - (chunk hP G ε hU).parts.filter (· ⊆ G.nonuniformWitness ε U V) + {A ∈ (chunk hP G ε hU).parts | A ⊆ G.nonuniformWitness ε U V} /-! ### Density estimates @@ -85,14 +85,13 @@ theorem star_subset_chunk : star hP G ε hU V ⊆ (chunk hP G ε hU).parts := private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) (hUV : U ≠ V) (h₂ : ¬G.IsUniform ε U V) : - (G.nonuniformWitness ε U V \ (star hP G ε hU V).biUnion id).card ≤ - 2 ^ (P.parts.card - 1) * m := by + #(G.nonuniformWitness ε U V \ (star hP G ε hU V).biUnion id) ≤ 2 ^ (#P.parts - 1) * m := by have hX : G.nonuniformWitness ε U V ∈ P.nonuniformWitnesses G ε U := nonuniformWitness_mem_nonuniformWitnesses h₂ hV hUV have q : G.nonuniformWitness ε U V \ (star hP G ε hU V).biUnion id ⊆ - ((atomise U <| P.nonuniformWitnesses G ε U).parts.filter fun B => - B ⊆ G.nonuniformWitness ε U V ∧ B.Nonempty).biUnion - fun B => B \ ((chunk hP G ε hU).parts.filter (· ⊆ B)).biUnion id := by + {B ∈ (atomise U <| P.nonuniformWitnesses G ε U).parts | + B ⊆ G.nonuniformWitness ε U V ∧ B.Nonempty}.biUnion + fun B => B \ {A ∈ (chunk hP G ε hU).parts | A ⊆ B}.biUnion id := by intro x hx rw [← biUnion_filter_atomise hX (G.nonuniformWitness_subset h₂), star, mem_sdiff, mem_biUnion] at hx @@ -101,10 +100,10 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( obtain ⟨⟨B, hB₁, hB₂⟩, hx⟩ := hx exact ⟨B, hB₁, hB₂, fun A hA AB => hx A hA <| AB.trans hB₁.2.1⟩ apply (card_le_card q).trans (card_biUnion_le.trans _) - trans ∑ _i in (atomise U <| P.nonuniformWitnesses G ε U).parts.filter fun B => + trans ∑ B ∈ (atomise U <| P.nonuniformWitnesses G ε U).parts with B ⊆ G.nonuniformWitness ε U V ∧ B.Nonempty, m · suffices ∀ B ∈ (atomise U <| P.nonuniformWitnesses G ε U).parts, - (B \ ((chunk hP G ε hU).parts.filter (· ⊆ B)).biUnion id).card ≤ m by + #(B \ {A ∈ (chunk hP G ε hU).parts | A ⊆ B}.biUnion id) ≤ m by exact sum_le_sum fun B hB => this B <| filter_subset _ _ hB intro B hB unfold chunk @@ -118,43 +117,43 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( exact card_image_le.trans (card_le_card <| filter_subset _ _) private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ P.parts) - (hUV : U ≠ V) (hunif : ¬G.IsUniform ε U V) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hUV : U ≠ V) (hunif : ¬G.IsUniform ε U V) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) : - (1 - ε / 10) * (G.nonuniformWitness ε U V).card ≤ ((star hP G ε hU V).biUnion id).card := by - have hP₁ : 0 < P.parts.card := Finset.card_pos.2 ⟨_, hU⟩ - have : (↑2 ^ P.parts.card : ℝ) * m / (U.card * ε) ≤ ε / 10 := by + (1 - ε / 10) * #(G.nonuniformWitness ε U V) ≤ #((star hP G ε hU V).biUnion id) := by + have hP₁ : 0 < #P.parts := Finset.card_pos.2 ⟨_, hU⟩ + have : (↑2 ^ #P.parts : ℝ) * m / (#U * ε) ≤ ε / 10 := by rw [← div_div, div_le_iff₀'] swap · sz_positivity - refine le_of_mul_le_mul_left ?_ (pow_pos zero_lt_two P.parts.card) + refine le_of_mul_le_mul_left ?_ (pow_pos zero_lt_two #P.parts) calc - ↑2 ^ P.parts.card * ((↑2 ^ P.parts.card * m : ℝ) / U.card) = - ((2 : ℝ) * 2) ^ P.parts.card * m / U.card := by + ↑2 ^ #P.parts * ((↑2 ^ #P.parts * m : ℝ) / #U) = + ((2 : ℝ) * 2) ^ #P.parts * m / #U := by rw [mul_pow, ← mul_div_assoc, mul_assoc] - _ = ↑4 ^ P.parts.card * m / U.card := by norm_num + _ = ↑4 ^ #P.parts * m / #U := by norm_num _ ≤ 1 := div_le_one_of_le₀ (pow_mul_m_le_card_part hP hU) (cast_nonneg _) - _ ≤ ↑2 ^ P.parts.card * ε ^ 2 / 10 := by + _ ≤ ↑2 ^ #P.parts * ε ^ 2 / 10 := by refine (one_le_sq_iff <| by positivity).1 ?_ rw [div_pow, mul_pow, pow_right_comm, ← pow_mul ε, one_le_div (sq_pos_of_ne_zero <| by norm_num)] calc (↑10 ^ 2) = 100 := by norm_num - _ ≤ ↑4 ^ P.parts.card * ε ^ 5 := hPε - _ ≤ ↑4 ^ P.parts.card * ε ^ 4 := + _ ≤ ↑4 ^ #P.parts * ε ^ 5 := hPε + _ ≤ ↑4 ^ #P.parts * ε ^ 4 := (mul_le_mul_of_nonneg_left (pow_le_pow_of_le_one (by sz_positivity) hε₁ <| le_succ _) (by positivity)) - _ = (↑2 ^ 2) ^ P.parts.card * ε ^ (2 * 2) := by norm_num - _ = ↑2 ^ P.parts.card * (ε * (ε / 10)) := by rw [mul_div_assoc, sq, mul_div_assoc] + _ = (↑2 ^ 2) ^ #P.parts * ε ^ (2 * 2) := by norm_num + _ = ↑2 ^ #P.parts * (ε * (ε / 10)) := by rw [mul_div_assoc, sq, mul_div_assoc] calc - (↑1 - ε / 10) * (G.nonuniformWitness ε U V).card ≤ - (↑1 - ↑2 ^ P.parts.card * m / (U.card * ε)) * (G.nonuniformWitness ε U V).card := + (↑1 - ε / 10) * #(G.nonuniformWitness ε U V) ≤ + (↑1 - ↑2 ^ #P.parts * m / (#U * ε)) * #(G.nonuniformWitness ε U V) := mul_le_mul_of_nonneg_right (sub_le_sub_left this _) (cast_nonneg _) - _ = (G.nonuniformWitness ε U V).card - - ↑2 ^ P.parts.card * m / (U.card * ε) * (G.nonuniformWitness ε U V).card := by + _ = #(G.nonuniformWitness ε U V) - + ↑2 ^ #P.parts * m / (#U * ε) * #(G.nonuniformWitness ε U V) := by rw [sub_mul, one_mul] - _ ≤ (G.nonuniformWitness ε U V).card - ↑2 ^ (P.parts.card - 1) * m := by + _ ≤ #(G.nonuniformWitness ε U V) - ↑2 ^ (#P.parts - 1) * m := by refine sub_le_sub_left ?_ _ - have : (2 : ℝ) ^ P.parts.card = ↑2 ^ (P.parts.card - 1) * 2 := by + have : (2 : ℝ) ^ #P.parts = ↑2 ^ (#P.parts - 1) * 2 := by rw [← _root_.pow_succ, tsub_add_cancel_of_le (succ_le_iff.2 hP₁)] rw [← mul_div_right_comm, this, mul_right_comm _ (2 : ℝ), mul_assoc, le_div_iff₀] · refine mul_le_mul_of_nonneg_left ?_ (by positivity) @@ -162,7 +161,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ (le_mul_of_one_le_left (cast_nonneg _) one_le_two) have := Finset.card_pos.mpr (P.nonempty_of_mem_parts hU) sz_positivity - _ ≤ ((star hP G ε hU V).biUnion id).card := by + _ ≤ #((star hP G ε hU V).biUnion id) := by rw [sub_le_comm, ← cast_sub (card_le_card <| biUnion_star_subset_nonuniformWitness hP G ε hU V), ← card_sdiff (biUnion_star_subset_nonuniformWitness hP G ε hU V)] @@ -171,7 +170,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ /-! ### `chunk` -/ -theorem card_chunk (hm : m ≠ 0) : (chunk hP G ε hU).parts.card = 4 ^ P.parts.card := by +theorem card_chunk (hm : m ≠ 0) : #(chunk hP G ε hU).parts = 4 ^ #P.parts := by unfold chunk split_ifs · rw [card_parts_equitabilise _ _ hm, tsub_add_cancel_of_le] @@ -179,23 +178,23 @@ theorem card_chunk (hm : m ≠ 0) : (chunk hP G ε hU).parts.card = 4 ^ P.parts. · rw [card_parts_equitabilise _ _ hm, tsub_add_cancel_of_le a_add_one_le_four_pow_parts_card] theorem card_eq_of_mem_parts_chunk (hs : s ∈ (chunk hP G ε hU).parts) : - s.card = m ∨ s.card = m + 1 := by + #s = m ∨ #s = m + 1 := by unfold chunk at hs split_ifs at hs <;> exact card_eq_of_mem_parts_equitabilise hs -theorem m_le_card_of_mem_chunk_parts (hs : s ∈ (chunk hP G ε hU).parts) : m ≤ s.card := +theorem m_le_card_of_mem_chunk_parts (hs : s ∈ (chunk hP G ε hU).parts) : m ≤ #s := (card_eq_of_mem_parts_chunk hs).elim ge_of_eq fun i => by simp [i] -theorem card_le_m_add_one_of_mem_chunk_parts (hs : s ∈ (chunk hP G ε hU).parts) : s.card ≤ m + 1 := +theorem card_le_m_add_one_of_mem_chunk_parts (hs : s ∈ (chunk hP G ε hU).parts) : #s ≤ m + 1 := (card_eq_of_mem_parts_chunk hs).elim (fun i => by simp [i]) fun i => i.le theorem card_biUnion_star_le_m_add_one_card_star_mul : - (((star hP G ε hU V).biUnion id).card : ℝ) ≤ (star hP G ε hU V).card * (m + 1) := + (#((star hP G ε hU V).biUnion id) : ℝ) ≤ #(star hP G ε hU V) * (m + 1) := mod_cast card_biUnion_le_card_mul _ _ _ fun _ hs => card_le_m_add_one_of_mem_chunk_parts <| star_subset_chunk hs private theorem le_sum_card_subset_chunk_parts (h𝒜 : 𝒜 ⊆ (chunk hP G ε hU).parts) (hs : s ∈ 𝒜) : - (𝒜.card : ℝ) * s.card * (m / (m + 1)) ≤ (𝒜.sup id).card := by + (#𝒜 : ℝ) * #s * (m / (m + 1)) ≤ #(𝒜.sup id) := by rw [mul_div_assoc', div_le_iff₀ coe_m_add_one_pos, mul_right_comm] refine mul_le_mul ?_ ?_ (cast_nonneg _) (cast_nonneg _) · rw [← (ofSubset _ h𝒜 rfl).sum_card_parts, ofSubset_parts, ← cast_mul, cast_le] @@ -204,7 +203,7 @@ private theorem le_sum_card_subset_chunk_parts (h𝒜 : 𝒜 ⊆ (chunk hP G ε private theorem sum_card_subset_chunk_parts_le (m_pos : (0 : ℝ) < m) (h𝒜 : 𝒜 ⊆ (chunk hP G ε hU).parts) (hs : s ∈ 𝒜) : - ((𝒜.sup id).card : ℝ) ≤ 𝒜.card * s.card * ((m + 1) / m) := by + (#(𝒜.sup id) : ℝ) ≤ #𝒜 * #s * ((m + 1) / m) := by rw [sup_eq_biUnion, mul_div_assoc', le_div_iff₀ m_pos, mul_right_comm] refine mul_le_mul ?_ ?_ (cast_nonneg _) (by positivity) · norm_cast @@ -213,7 +212,7 @@ private theorem sum_card_subset_chunk_parts_le (m_pos : (0 : ℝ) < m) · exact mod_cast m_le_card_of_mem_chunk_parts (h𝒜 hs) private theorem one_sub_le_m_div_m_add_one_sq [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) : + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) : ↑1 - ε ^ 5 / ↑50 ≤ (m / (m + 1 : ℝ)) ^ 2 := by have : (m : ℝ) / (m + 1) = 1 - 1 / (m + 1) := by rw [one_sub_div coe_m_add_one_pos.ne', add_sub_cancel_right] @@ -227,7 +226,7 @@ private theorem one_sub_le_m_div_m_add_one_sq [Nonempty α] sz_positivity private theorem m_add_one_div_m_le_one_add [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) : ((m + 1 : ℝ) / m) ^ 2 ≤ ↑1 + ε ^ 5 / 49 := by rw [same_add_div] swap; · sz_positivity @@ -243,11 +242,11 @@ private theorem m_add_one_div_m_le_one_add [Nonempty α] exact (pow_le_one₀ (by sz_positivity) hε₁).trans (by norm_num) private theorem density_sub_eps_le_sum_density_div_card [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) {hU : U ∈ P.parts} {hV : V ∈ P.parts} {A B : Finset (Finset α)} (hA : A ⊆ (chunk hP G ε hU).parts) (hB : B ⊆ (chunk hP G ε hV).parts) : (G.edgeDensity (A.biUnion id) (B.biUnion id)) - ε ^ 5 / 50 ≤ - (∑ ab ∈ A.product B, (G.edgeDensity ab.1 ab.2 : ℝ)) / (A.card * B.card) := by + (∑ ab ∈ A.product B, (G.edgeDensity ab.1 ab.2 : ℝ)) / (#A * #B) := by have : ↑(G.edgeDensity (A.biUnion id) (B.biUnion id)) - ε ^ 5 / ↑50 ≤ (↑1 - ε ^ 5 / 50) * G.edgeDensity (A.biUnion id) (B.biUnion id) := by rw [sub_mul, one_mul, sub_le_sub_iff_left] @@ -266,7 +265,7 @@ private theorem density_sub_eps_le_sum_density_div_card [Nonempty α] apply sum_le_sum simp only [and_imp, Prod.forall, mem_product] rintro x y hx hy - rw [mul_mul_mul_comm, mul_comm (x.card : ℝ), mul_comm (y.card : ℝ), le_div_iff₀, mul_assoc] + rw [mul_mul_mul_comm, mul_comm (#x : ℝ), mul_comm (#y : ℝ), le_div_iff₀, mul_assoc] · refine mul_le_of_le_one_right (cast_nonneg _) ?_ rw [div_mul_eq_mul_div, ← mul_assoc, mul_assoc] refine div_le_one_of_le₀ ?_ (by positivity) @@ -281,10 +280,10 @@ private theorem density_sub_eps_le_sum_density_div_card [Nonempty α] exacts [⟨_, hx⟩, nonempty_of_mem_parts _ (hA hx), ⟨_, hy⟩, nonempty_of_mem_parts _ (hB hy)] private theorem sum_density_div_card_le_density_add_eps [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} {A B : Finset (Finset α)} (hA : A ⊆ (chunk hP G ε hU).parts) (hB : B ⊆ (chunk hP G ε hV).parts) : - (∑ ab ∈ A.product B, G.edgeDensity ab.1 ab.2 : ℝ) / (A.card * B.card) ≤ + (∑ ab ∈ A.product B, G.edgeDensity ab.1 ab.2 : ℝ) / (#A * #B) ≤ G.edgeDensity (A.biUnion id) (B.biUnion id) + ε ^ 5 / 49 := by have : (↑1 + ε ^ 5 / ↑49) * G.edgeDensity (A.biUnion id) (B.biUnion id) ≤ G.edgeDensity (A.biUnion id) (B.biUnion id) + ε ^ 5 / 49 := by @@ -303,7 +302,7 @@ private theorem sum_density_div_card_le_density_add_eps [Nonempty α] apply sum_le_sum simp only [and_imp, Prod.forall, mem_product, show A.product B = A ×ˢ B by rfl] intro x y hx hy - rw [mul_mul_mul_comm, mul_comm (x.card : ℝ), mul_comm (y.card : ℝ), div_le_iff₀, mul_assoc] + rw [mul_mul_mul_comm, mul_comm (#x : ℝ), mul_comm (#y : ℝ), div_le_iff₀, mul_assoc] · refine le_mul_of_one_le_right (cast_nonneg _) ?_ rw [div_mul_eq_mul_div, one_le_div] · refine le_trans ?_ (mul_le_mul_of_nonneg_right (m_add_one_div_m_le_one_add hPα hPε hε₁) ?_) @@ -319,28 +318,28 @@ private theorem sum_density_div_card_le_density_add_eps [Nonempty α] exacts [⟨_, hx⟩, nonempty_of_mem_parts _ (hA hx), ⟨_, hy⟩, nonempty_of_mem_parts _ (hB hy)] private theorem average_density_near_total_density [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} {A B : Finset (Finset α)} (hA : A ⊆ (chunk hP G ε hU).parts) (hB : B ⊆ (chunk hP G ε hV).parts) : - |(∑ ab ∈ A.product B, G.edgeDensity ab.1 ab.2 : ℝ) / (A.card * B.card) - + |(∑ ab ∈ A.product B, G.edgeDensity ab.1 ab.2 : ℝ) / (#A * #B) - G.edgeDensity (A.biUnion id) (B.biUnion id)| ≤ ε ^ 5 / 49 := by rw [abs_sub_le_iff] constructor · rw [sub_le_iff_le_add'] exact sum_density_div_card_le_density_add_eps hPα hPε hε₁ hA hB suffices (G.edgeDensity (A.biUnion id) (B.biUnion id) : ℝ) - - (∑ ab ∈ A.product B, (G.edgeDensity ab.1 ab.2 : ℝ)) / (A.card * B.card) ≤ ε ^ 5 / 50 by + (∑ ab ∈ A.product B, (G.edgeDensity ab.1 ab.2 : ℝ)) / (#A * #B) ≤ ε ^ 5 / 50 by apply this.trans gcongr <;> [sz_positivity; norm_num] rw [sub_le_iff_le_add, ← sub_le_iff_le_add'] apply density_sub_eps_le_sum_density_div_card hPα hPε hA hB private theorem edgeDensity_chunk_aux [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hU : U ∈ P.parts) (hV : V ∈ P.parts) : (G.edgeDensity U V : ℝ) ^ 2 - ε ^ 5 / ↑25 ≤ ((∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ)) / ↑16 ^ P.parts.card) ^ 2 := by + (G.edgeDensity ab.1 ab.2 : ℝ)) / ↑16 ^ #P.parts) ^ 2 := by obtain hGε | hGε := le_total (G.edgeDensity U V : ℝ) (ε ^ 5 / 50) · refine (sub_nonpos_of_le <| (sq_le ?_ ?_).trans <| hGε.trans ?_).trans (sq_nonneg _) · exact mod_cast G.edgeDensity_nonneg _ _ @@ -349,7 +348,7 @@ private theorem edgeDensity_chunk_aux [Nonempty α] rw [← sub_nonneg] at hGε have : ↑(G.edgeDensity U V) - ε ^ 5 / ↑50 ≤ (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ)) / ↑16 ^ P.parts.card := by + (G.edgeDensity ab.1 ab.2 : ℝ)) / ↑16 ^ #P.parts := by have rflU := Set.Subset.refl (chunk hP G ε hU).parts.toSet have rflV := Set.Subset.refl (chunk hP G ε hV).parts.toSet refine (le_trans ?_ <| density_sub_eps_le_sum_density_div_card hPα hPε rflU rflV).trans ?_ @@ -363,7 +362,7 @@ private theorem edgeDensity_chunk_aux [Nonempty α] show (2 : ℝ) / 50 = 25⁻¹ by norm_num] exact mul_le_of_le_one_right (by sz_positivity) (mod_cast G.edgeDensity_le_one _ _) -private theorem abs_density_star_sub_density_le_eps (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) +private theorem abs_density_star_sub_density_le_eps (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} (hUV' : U ≠ V) (hUV : ¬G.IsUniform ε U V) : |(G.edgeDensity ((star hP G ε hU V).biUnion id) ((star hP G ε hV U).biUnion id) : ℝ) - G.edgeDensity (G.nonuniformWitness ε U V) (G.nonuniformWitness ε V U)| ≤ ε / 5 := by @@ -375,33 +374,33 @@ private theorem abs_density_star_sub_density_le_eps (hPε : ↑100 ≤ ↑4 ^ P. hPε hε₁) using 1 linarith -private theorem eps_le_card_star_div [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) (hε₁ : ε ≤ 1) (hU : U ∈ P.parts) (hV : V ∈ P.parts) +private theorem eps_le_card_star_div [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) + (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) (hU : U ∈ P.parts) (hV : V ∈ P.parts) (hUV : U ≠ V) (hunif : ¬G.IsUniform ε U V) : - ↑4 / ↑5 * ε ≤ (star hP G ε hU V).card / ↑4 ^ P.parts.card := by - have hm : (0 : ℝ) ≤ 1 - (↑m)⁻¹ := sub_nonneg_of_le (inv_le_one <| one_le_m_coe hPα) + ↑4 / ↑5 * ε ≤ #(star hP G ε hU V) / ↑4 ^ #P.parts := by + have hm : (0 : ℝ) ≤ 1 - (↑m)⁻¹ := sub_nonneg_of_le (inv_le_one_of_one_le₀ <| one_le_m_coe hPα) have hε : 0 ≤ 1 - ε / 10 := sub_nonneg_of_le (div_le_one_of_le₀ (hε₁.trans <| by norm_num) <| by norm_num) have hε₀ : 0 < ε := by sz_positivity calc 4 / 5 * ε = (1 - 1 / 10) * (1 - 9⁻¹) * ε := by norm_num - _ ≤ (1 - ε / 10) * (1 - (↑m)⁻¹) * ((G.nonuniformWitness ε U V).card / U.card) := by + _ ≤ (1 - ε / 10) * (1 - (↑m)⁻¹) * (#(G.nonuniformWitness ε U V) / #U) := by gcongr exacts [mod_cast (show 9 ≤ 100 by norm_num).trans (hundred_le_m hPα hPε hε₁), (le_div_iff₀' <| cast_pos.2 (P.nonempty_of_mem_parts hU).card_pos).2 <| G.le_card_nonuniformWitness hunif] - _ = (1 - ε / 10) * (G.nonuniformWitness ε U V).card * ((1 - (↑m)⁻¹) / U.card) := by + _ = (1 - ε / 10) * #(G.nonuniformWitness ε U V) * ((1 - (↑m)⁻¹) / #U) := by rw [mul_assoc, mul_assoc, mul_div_left_comm] - _ ≤ ((star hP G ε hU V).biUnion id).card * ((1 - (↑m)⁻¹) / U.card) := + _ ≤ #((star hP G ε hU V).biUnion id) * ((1 - (↑m)⁻¹) / #U) := (mul_le_mul_of_nonneg_right (one_sub_eps_mul_card_nonuniformWitness_le_card_star hV hUV hunif hPε hε₁) (by positivity)) - _ ≤ (star hP G ε hU V).card * (m + 1) * ((1 - (↑m)⁻¹) / U.card) := + _ ≤ #(star hP G ε hU V) * (m + 1) * ((1 - (↑m)⁻¹) / #U) := (mul_le_mul_of_nonneg_right card_biUnion_star_le_m_add_one_card_star_mul (by positivity)) - _ ≤ (star hP G ε hU V).card * (m + ↑1) * ((↑1 - (↑m)⁻¹) / (↑4 ^ P.parts.card * m)) := + _ ≤ #(star hP G ε hU V) * (m + ↑1) * ((↑1 - (↑m)⁻¹) / (↑4 ^ #P.parts * m)) := (mul_le_mul_of_nonneg_left (div_le_div_of_nonneg_left hm (by sz_positivity) <| pow_mul_m_le_card_part hP hU) (by positivity)) - _ ≤ (star hP G ε hU V).card / ↑4 ^ P.parts.card := by - rw [mul_assoc, mul_comm ((4 : ℝ) ^ P.parts.card), ← div_div, ← mul_div_assoc, ← mul_comm_div] + _ ≤ #(star hP G ε hU V) / ↑4 ^ #P.parts := by + rw [mul_assoc, mul_comm ((4 : ℝ) ^ #P.parts), ← div_div, ← mul_div_assoc, ← mul_comm_div] refine mul_le_of_le_one_right (by positivity) ?_ have hm : (0 : ℝ) < m := by sz_positivity rw [mul_div_assoc', div_le_one hm, ← one_div, one_sub_div hm.ne', mul_div_assoc', @@ -417,20 +416,20 @@ Those inequalities are the end result of all this hard work. /-- Lower bound on the edge densities between non-uniform parts of `SzemerediRegularity.star`. -/ private theorem edgeDensity_star_not_uniform [Nonempty α] - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} (hUVne : U ≠ V) (hUV : ¬G.IsUniform ε U V) : ↑3 / ↑4 * ε ≤ |(∑ ab ∈ (star hP G ε hU V).product (star hP G ε hV U), (G.edgeDensity ab.1 ab.2 : ℝ)) / - ((star hP G ε hU V).card * (star hP G ε hV U).card) - + (#(star hP G ε hU V) * #(star hP G ε hV U)) - (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ)) / (16 : ℝ) ^ P.parts.card| := by + (G.edgeDensity ab.1 ab.2 : ℝ)) / (16 : ℝ) ^ #P.parts| := by rw [show (16 : ℝ) = ↑4 ^ 2 by norm_num, pow_right_comm, sq ((4 : ℝ) ^ _)] set p : ℝ := (∑ ab ∈ (star hP G ε hU V).product (star hP G ε hV U), (G.edgeDensity ab.1 ab.2 : ℝ)) / - ((star hP G ε hU V).card * (star hP G ε hV U).card) + (#(star hP G ε hU V) * #(star hP G ε hV U)) set q : ℝ := (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ)) / (↑4 ^ P.parts.card * ↑4 ^ P.parts.card) + (G.edgeDensity ab.1 ab.2 : ℝ)) / (↑4 ^ #P.parts * ↑4 ^ #P.parts) change _ ≤ |p - q| set r : ℝ := ↑(G.edgeDensity ((star hP G ε hU V).biUnion id) ((star hP G ε hV U).biUnion id)) set s : ℝ := ↑(G.edgeDensity (G.nonuniformWitness ε U V) (G.nonuniformWitness ε V U)) @@ -458,20 +457,20 @@ private theorem edgeDensity_star_not_uniform [Nonempty α] /-- Lower bound on the edge densities between non-uniform parts of `SzemerediRegularity.increment`. -/ -theorem edgeDensity_chunk_not_uniform [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} +theorem edgeDensity_chunk_not_uniform [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) + (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hε₁ : ε ≤ 1) {hU : U ∈ P.parts} {hV : V ∈ P.parts} (hUVne : U ≠ V) (hUV : ¬G.IsUniform ε U V) : (G.edgeDensity U V : ℝ) ^ 2 - ε ^ 5 / ↑25 + ε ^ 4 / ↑3 ≤ (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ P.parts.card := + (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ #P.parts := calc ↑(G.edgeDensity U V) ^ 2 - ε ^ 5 / 25 + ε ^ 4 / ↑3 ≤ ↑(G.edgeDensity U V) ^ 2 - ε ^ 5 / ↑25 + - (star hP G ε hU V).card * (star hP G ε hV U).card / ↑16 ^ P.parts.card * + #(star hP G ε hU V) * #(star hP G ε hV U) / ↑16 ^ #P.parts * (↑9 / ↑16) * ε ^ 2 := by apply add_le_add_left - have Ul : 4 / 5 * ε ≤ (star hP G ε hU V).card / _ := + have Ul : 4 / 5 * ε ≤ #(star hP G ε hU V) / _ := eps_le_card_star_div hPα hPε hε₁ hU hV hUVne hUV - have Vl : 4 / 5 * ε ≤ (star hP G ε hV U).card / _ := + have Vl : 4 / 5 * ε ≤ #(star hP G ε hV U) / _ := eps_le_card_star_div hPα hPε hε₁ hV hU hUVne.symm fun h => hUV h.symm rw [show (16 : ℝ) = ↑4 ^ 2 by norm_num, pow_right_comm, sq ((4 : ℝ) ^ _), ← _root_.div_mul_div_comm, mul_assoc] @@ -487,7 +486,7 @@ theorem edgeDensity_chunk_not_uniform [Nonempty α] (hPα : P.parts.card * 16 ^ · norm_num positivity _ ≤ (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ P.parts.card := by + (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ #P.parts := by have t : (star hP G ε hU V).product (star hP G ε hV U) ⊆ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts := product_subset_product star_subset_chunk star_subset_chunk @@ -510,14 +509,13 @@ theorem edgeDensity_chunk_not_uniform [Nonempty α] (hPα : P.parts.card * 16 ^ /-- Lower bound on the edge densities between parts of `SzemerediRegularity.increment`. This is the blanket lower bound used the uniform parts. -/ -theorem edgeDensity_chunk_uniform [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) (hU : U ∈ P.parts) (hV : V ∈ P.parts) : +theorem edgeDensity_chunk_uniform [Nonempty α] (hPα : #P.parts * 16 ^ #P.parts ≤ card α) + (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) (hU : U ∈ P.parts) (hV : V ∈ P.parts) : (G.edgeDensity U V : ℝ) ^ 2 - ε ^ 5 / ↑25 ≤ (∑ ab ∈ (chunk hP G ε hU).parts.product (chunk hP G ε hV).parts, - (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ P.parts.card := by + (G.edgeDensity ab.1 ab.2 : ℝ) ^ 2) / ↑16 ^ #P.parts := by apply (edgeDensity_chunk_aux (hP := hP) hPα hPε hU hV).trans - have key : ↑16 ^ P.parts.card = - (((chunk hP G ε hU).parts ×ˢ (chunk hP G ε hV).parts).card : ℝ) := by + have key : (16 : ℝ) ^ #P.parts = #((chunk hP G ε hU).parts ×ˢ (chunk hP G ε hV).parts) := by rw [card_product, cast_mul, card_chunk (m_pos hPα).ne', card_chunk (m_pos hPα).ne', ← cast_mul, ← mul_pow]; norm_cast simp_rw [key] diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean index 2691d38a6f4b2..2784e3dcc622c 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean @@ -5,7 +5,6 @@ Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Combinatorics.SimpleGraph.Density import Mathlib.Data.Rat.BigOperators @@ -34,7 +33,7 @@ namespace Finpartition /-- The energy of a partition, also known as index. Auxiliary quantity for Szemerédi's regularity lemma. -/ def energy : ℚ := - ((∑ uv ∈ P.parts.offDiag, G.edgeDensity uv.1 uv.2 ^ 2) : ℚ) / (P.parts.card : ℚ) ^ 2 + ((∑ uv ∈ P.parts.offDiag, G.edgeDensity uv.1 uv.2 ^ 2) : ℚ) / (#P.parts : ℚ) ^ 2 theorem energy_nonneg : 0 ≤ P.energy G := by exact div_nonneg (Finset.sum_nonneg fun _ _ => sq_nonneg _) <| sq_nonneg _ @@ -42,10 +41,10 @@ theorem energy_nonneg : 0 ≤ P.energy G := by theorem energy_le_one : P.energy G ≤ 1 := div_le_of_le_mul₀ (sq_nonneg _) zero_le_one <| calc - ∑ uv ∈ P.parts.offDiag, G.edgeDensity uv.1 uv.2 ^ 2 ≤ P.parts.offDiag.card • (1 : ℚ) := - sum_le_card_nsmul _ _ 1 fun uv _ => + ∑ uv ∈ P.parts.offDiag, G.edgeDensity uv.1 uv.2 ^ 2 ≤ #P.parts.offDiag • (1 : ℚ) := + sum_le_card_nsmul _ _ 1 fun _ _ => (sq_le_one_iff <| G.edgeDensity_nonneg _ _).2 <| G.edgeDensity_le_one _ _ - _ = P.parts.offDiag.card := Nat.smul_one_eq_cast _ + _ = #P.parts.offDiag := Nat.smul_one_eq_cast _ _ ≤ _ := by rw [offDiag_card, one_mul] norm_cast @@ -54,7 +53,7 @@ theorem energy_le_one : P.energy G ≤ 1 := @[simp, norm_cast] theorem coe_energy {𝕜 : Type*} [LinearOrderedField 𝕜] : (P.energy G : 𝕜) = - (∑ uv ∈ P.parts.offDiag, (G.edgeDensity uv.1 uv.2 : 𝕜) ^ 2) / (P.parts.card : 𝕜) ^ 2 := by + (∑ uv ∈ P.parts.offDiag, (G.edgeDensity uv.1 uv.2 : 𝕜) ^ 2) / (#P.parts : 𝕜) ^ 2 := by rw [energy]; norm_cast end Finpartition diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean index 96d140587f9cc..a5b1a55dfb92a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean @@ -32,16 +32,16 @@ namespace Finpartition variable {α : Type*} [DecidableEq α] {s t : Finset α} {m n a b : ℕ} {P : Finpartition s} -/-- Given a partition `P` of `s`, as well as a proof that `a * m + b * (m + 1) = s.card`, we can +/-- Given a partition `P` of `s`, as well as a proof that `a * m + b * (m + 1) = #s`, we can find a new partition `Q` of `s` where each part has size `m` or `m + 1`, every part of `P` is the union of parts of `Q` plus at most `m` extra elements, there are `b` parts of size `m + 1` and (provided `m > 0`, because a partition does not have parts of size `0`) there are `a` parts of size `m` and hence `a + b` parts in total. -/ -theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : +theorem equitabilise_aux (hs : a * m + b * (m + 1) = #s) : ∃ Q : Finpartition s, - (∀ x : Finset α, x ∈ Q.parts → x.card = m ∨ x.card = m + 1) ∧ - (∀ x, x ∈ P.parts → (x \ (Q.parts.filter fun y => y ⊆ x).biUnion id).card ≤ m) ∧ - (Q.parts.filter fun i => card i = m + 1).card = b := by + (∀ x : Finset α, x ∈ Q.parts → #x = m ∨ #x = m + 1) ∧ + (∀ x, x ∈ P.parts → #(x \ {y ∈ Q.parts | y ⊆ x}.biUnion id) ≤ m) ∧ + #{i ∈ Q.parts | #i = m + 1} = b := by -- Get rid of the easy case `m = 0` obtain rfl | m_pos := m.eq_zero_or_pos · refine ⟨⊥, by simp, ?_, by simpa [Finset.filter_true_of_mem] using hs.symm⟩ @@ -63,7 +63,7 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : set n := if 0 < a then m else m + 1 with hn -- Some easy facts about it obtain ⟨hn₀, hn₁, hn₂, hn₃⟩ : 0 < n ∧ n ≤ m + 1 ∧ n ≤ a * m + b * (m + 1) ∧ - ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = s.card - n := by + ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = #s - n := by rw [hn, ← hs] split_ifs with h <;> rw [tsub_mul, one_mul] · refine ⟨m_pos, le_succ _, le_add_right (Nat.le_mul_of_pos_left _ ‹0 < a›), ?_⟩ @@ -77,10 +77,10 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : least one part `u` of `P` has size `m + 1` (in which case we take `t` to be an arbitrary subset of `u` of size `n`). The rest of each branch is just tedious calculations to satisfy the induction hypothesis. -/ - by_cases h : ∀ u ∈ P.parts, card u < m + 1 + by_cases h : ∀ u ∈ P.parts, #u < m + 1 · obtain ⟨t, hts, htn⟩ := exists_subset_card_eq (hn₂.trans_eq hs) have ht : t.Nonempty := by rwa [← card_pos, htn] - have hcard : ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = (s \ t).card := by + have hcard : ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = #(s \ t) := by rw [card_sdiff ‹t ⊆ s›, htn, hn₃] obtain ⟨R, hR₁, _, hR₃⟩ := @ih (s \ t) (sdiff_ssubset hts ‹t.Nonempty›) (if 0 < a then a - 1 else a) @@ -99,7 +99,7 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : obtain ⟨u, hu₁, hu₂⟩ := h obtain ⟨t, htu, htn⟩ := exists_subset_card_eq (hn₁.trans hu₂) have ht : t.Nonempty := by rwa [← card_pos, htn] - have hcard : ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = (s \ t).card := by + have hcard : ite (0 < a) (a - 1) a * m + ite (0 < a) b (b - 1) * (m + 1) = #(s \ t) := by rw [card_sdiff (htu.trans <| P.le hu₁), htn, hn₃] obtain ⟨R, hR₁, hR₂, hR₃⟩ := @ih (s \ t) (sdiff_ssubset (htu.trans <| P.le hu₁) ht) (if 0 < a then a - 1 else a) @@ -136,9 +136,9 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : · rw [card_insert_of_not_mem, hR₃, if_neg h, Nat.sub_add_cancel (hab.resolve_left h)] intro H; exact ht.ne_empty (le_sdiff_iff.1 <| R.le <| filter_subset _ _ H) -variable (h : a * m + b * (m + 1) = s.card) +variable (h : a * m + b * (m + 1) = #s) -/-- Given a partition `P` of `s`, as well as a proof that `a * m + b * (m + 1) = s.card`, build a +/-- Given a partition `P` of `s`, as well as a proof that `a * m + b * (m + 1) = #s`, build a new partition `Q` of `s` where each part has size `m` or `m + 1`, every part of `P` is the union of parts of `Q` plus at most `m` extra elements, there are `b` parts of size `m + 1` and (provided `m > 0`, because a partition does not have parts of size `0`) there are `a` parts of size `m` and @@ -149,7 +149,7 @@ noncomputable def equitabilise : Finpartition s := variable {h} theorem card_eq_of_mem_parts_equitabilise : - t ∈ (P.equitabilise h).parts → t.card = m ∨ t.card = m + 1 := + t ∈ (P.equitabilise h).parts → #t = m ∨ #t = m + 1 := (P.equitabilise_aux h).choose_spec.1 _ theorem equitabilise_isEquipartition : (P.equitabilise h).IsEquipartition := @@ -157,18 +157,16 @@ theorem equitabilise_isEquipartition : (P.equitabilise h).IsEquipartition := variable (P h) -theorem card_filter_equitabilise_big : - ((P.equitabilise h).parts.filter fun u : Finset α => u.card = m + 1).card = b := +theorem card_filter_equitabilise_big : #{u ∈ (P.equitabilise h).parts | #u = m + 1} = b := (P.equitabilise_aux h).choose_spec.2.2 theorem card_filter_equitabilise_small (hm : m ≠ 0) : - ((P.equitabilise h).parts.filter fun u : Finset α => u.card = m).card = a := by + #{u ∈ (P.equitabilise h).parts | #u = m} = a := by refine (mul_eq_mul_right_iff.1 <| (add_left_inj (b * (m + 1))).1 ?_).resolve_right hm rw [h, ← (P.equitabilise h).sum_card_parts] have hunion : (P.equitabilise h).parts = - ((P.equitabilise h).parts.filter fun u => u.card = m) ∪ - (P.equitabilise h).parts.filter fun u => u.card = m + 1 := by + {u ∈ (P.equitabilise h).parts | #u = m} ∪ {u ∈ (P.equitabilise h).parts | #u = m + 1} := by rw [← filter_or, filter_true_of_mem] exact fun x => card_eq_of_mem_parts_equitabilise nth_rw 2 [hunion] @@ -179,23 +177,23 @@ theorem card_filter_equitabilise_small (hm : m ≠ 0) : apply succ_ne_self m _ exact (hb i h).symm.trans (ha i h) -theorem card_parts_equitabilise (hm : m ≠ 0) : (P.equitabilise h).parts.card = a + b := by +theorem card_parts_equitabilise (hm : m ≠ 0) : #(P.equitabilise h).parts = a + b := by rw [← filter_true_of_mem fun x => card_eq_of_mem_parts_equitabilise, filter_or, card_union_of_disjoint, P.card_filter_equitabilise_small _ hm, P.card_filter_equitabilise_big] -- Porting note (#11187): was `infer_instance` exact disjoint_filter.2 fun x _ h₀ h₁ => Nat.succ_ne_self m <| h₁.symm.trans h₀ theorem card_parts_equitabilise_subset_le : - t ∈ P.parts → (t \ ((P.equitabilise h).parts.filter fun u => u ⊆ t).biUnion id).card ≤ m := + t ∈ P.parts → #(t \ {u ∈ (P.equitabilise h).parts | u ⊆ t}.biUnion id) ≤ m := (Classical.choose_spec <| P.equitabilise_aux h).2.1 t variable (s) /-- We can find equipartitions of arbitrary size. -/ -theorem exists_equipartition_card_eq (hn : n ≠ 0) (hs : n ≤ s.card) : - ∃ P : Finpartition s, P.IsEquipartition ∧ P.parts.card = n := by +theorem exists_equipartition_card_eq (hn : n ≠ 0) (hs : n ≤ #s) : + ∃ P : Finpartition s, P.IsEquipartition ∧ #P.parts = n := by rw [← pos_iff_ne_zero] at hn - have : (n - s.card % n) * (s.card / n) + s.card % n * (s.card / n + 1) = s.card := by + have : (n - #s % n) * (#s / n) + #s % n * (#s / n + 1) = #s := by rw [tsub_mul, mul_add, ← add_assoc, tsub_add_cancel_of_le (Nat.mul_le_mul_right _ (mod_lt _ hn).le), mul_one, add_comm, mod_add_div] diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean index 4fe6e82a487fa..6f97ef8109a10 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean @@ -41,7 +41,7 @@ open scoped SzemerediRegularity.Positivity variable {α : Type*} [Fintype α] [DecidableEq α] {P : Finpartition (univ : Finset α)} (hP : P.IsEquipartition) (G : SimpleGraph α) [DecidableRel G.Adj] (ε : ℝ) -local notation3 "m" => (card α / stepBound P.parts.card : ℕ) +local notation3 "m" => (card α / stepBound #P.parts : ℕ) namespace SzemerediRegularity @@ -59,14 +59,14 @@ open Finpartition Finpartition.IsEquipartition variable {hP G ε} /-- The increment partition has a prescribed (very big) size in terms of the original partition. -/ -theorem card_increment (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPG : ¬P.IsUniform G ε) : - (increment hP G ε).parts.card = stepBound P.parts.card := by - have hPα' : stepBound P.parts.card ≤ card α := +theorem card_increment (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPG : ¬P.IsUniform G ε) : + #(increment hP G ε).parts = stepBound #P.parts := by + have hPα' : stepBound #P.parts ≤ card α := (mul_le_mul_left' (pow_le_pow_left' (by norm_num) _) _).trans hPα - have hPpos : 0 < stepBound P.parts.card := stepBound_pos (nonempty_of_not_uniform hPG).card_pos + have hPpos : 0 < stepBound #P.parts := stepBound_pos (nonempty_of_not_uniform hPG).card_pos rw [increment, card_bind] simp_rw [chunk, apply_dite Finpartition.parts, apply_dite card, sum_dite] - rw [sum_const_nat, sum_const_nat, card_attach, card_attach]; rotate_left + rw [sum_const_nat, sum_const_nat, univ_eq_attach, univ_eq_attach, card_attach, card_attach] any_goals exact fun x hx => card_parts_equitabilise _ _ (Nat.div_pos hPα' hPpos).ne' rw [Nat.sub_add_cancel a_add_one_le_four_pow_parts_card, Nat.sub_add_cancel ((Nat.le_succ _).trans a_add_one_le_four_pow_parts_card), ← add_mul] @@ -119,10 +119,10 @@ private lemma pairwiseDisjoint_distinctPairs : variable [Nonempty α] lemma le_sum_distinctPairs_edgeDensity_sq (x : {i // i ∈ P.parts.offDiag}) (hε₁ : ε ≤ 1) - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) : + (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPε : ↑100 ≤ ↑4 ^ #P.parts * ε ^ 5) : (G.edgeDensity x.1.1 x.1.2 : ℝ) ^ 2 + ((if G.IsUniform ε x.1.1 x.1.2 then 0 else ε ^ 4 / 3) - ε ^ 5 / 25) ≤ - (∑ i ∈ distinctPairs hP G ε x, G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ P.parts.card := by + (∑ i ∈ distinctPairs hP G ε x, G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ #P.parts := by rw [distinctPairs, ← add_sub_assoc, add_sub_right_comm] split_ifs with h · rw [add_zero] @@ -130,18 +130,18 @@ lemma le_sum_distinctPairs_edgeDensity_sq (x : {i // i ∈ P.parts.offDiag}) (h · exact edgeDensity_chunk_not_uniform hPα hPε hε₁ (mem_offDiag.1 x.2).2.2 h /-- The increment partition has energy greater than the original one by a known fixed amount. -/ -theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) - (hPε : 100 ≤ 4 ^ P.parts.card * ε ^ 5) (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) +theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ #P.parts) + (hPε : 100 ≤ 4 ^ #P.parts * ε ^ 5) (hPα : #P.parts * 16 ^ #P.parts ≤ card α) (hPG : ¬P.IsUniform G ε) (hε₀ : 0 ≤ ε) (hε₁ : ε ≤ 1) : ↑(P.energy G) + ε ^ 5 / 4 ≤ (increment hP G ε).energy G := by calc _ = (∑ x ∈ P.parts.offDiag, (G.edgeDensity x.1 x.2 : ℝ) ^ 2 + - P.parts.card ^ 2 * (ε ^ 5 / 4) : ℝ) / P.parts.card ^ 2 := by + #P.parts ^ 2 * (ε ^ 5 / 4) : ℝ) / #P.parts ^ 2 := by rw [coe_energy, add_div, mul_div_cancel_left₀]; positivity _ ≤ (∑ x ∈ P.parts.offDiag.attach, (∑ i ∈ distinctPairs hP G ε x, - G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ P.parts.card) / P.parts.card ^ 2 := ?_ + G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ #P.parts) / #P.parts ^ 2 := ?_ _ = (∑ x ∈ P.parts.offDiag.attach, ∑ i ∈ distinctPairs hP G ε x, - G.edgeDensity i.1 i.2 ^ 2 : ℝ) / (increment hP G ε).parts.card ^ 2 := by + G.edgeDensity i.1 i.2 ^ 2 : ℝ) / #(increment hP G ε).parts ^ 2 := by rw [card_increment hPα hPG, coe_stepBound, mul_pow, pow_right_comm, div_mul_eq_div_div_swap, ← sum_div]; norm_num _ ≤ _ := by @@ -153,7 +153,7 @@ theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) rw [Finpartition.IsUniform, not_le, mul_tsub, mul_one, ← offDiag_card] at hPG calc _ ≤ ∑ x ∈ P.parts.offDiag, (edgeDensity G x.1 x.2 : ℝ) ^ 2 + - ((nonUniforms P G ε).card * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := + (#(nonUniforms P G ε) * (ε ^ 4 / 3) - #P.parts.offDiag * (ε ^ 5 / 25)) := add_le_add_left ?_ _ _ = ∑ x ∈ P.parts.offDiag, ((G.edgeDensity x.1 x.2 : ℝ) ^ 2 + ((if G.IsUniform ε x.1 x.2 then (0 : ℝ) else ε ^ 4 / 3) - ε ^ 5 / 25) : ℝ) := by @@ -163,8 +163,8 @@ theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) _ = _ := (sum_attach ..).symm _ ≤ _ := sum_le_sum fun i _ ↦ le_sum_distinctPairs_edgeDensity_sq i hε₁ hPα hPε calc - _ = (6/7 * P.parts.card ^ 2) * ε ^ 5 * (7 / 24) := by ring - _ ≤ P.parts.offDiag.card * ε ^ 5 * (22 / 75) := by + _ = (6/7 * #P.parts ^ 2) * ε ^ 5 * (7 / 24) := by ring + _ ≤ #P.parts.offDiag * ε ^ 5 * (22 / 75) := by gcongr ?_ * _ * ?_ · rw [← mul_div_right_comm, div_le_iff₀ (by norm_num), offDiag_card] norm_cast @@ -172,7 +172,7 @@ theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) refine le_tsub_of_add_le_left ?_ nlinarith · norm_num - _ = (P.parts.offDiag.card * ε * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := by ring - _ ≤ ((nonUniforms P G ε).card * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := by gcongr + _ = (#P.parts.offDiag * ε * (ε ^ 4 / 3) - #P.parts.offDiag * (ε ^ 5 / 25)) := by ring + _ ≤ (#(nonUniforms P G ε) * (ε ^ 4 / 3) - #P.parts.offDiag * (ε ^ 5 / 25)) := by gcongr end SzemerediRegularity diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean index bee7ea6b54e48..dd9d05a8d0c75 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean @@ -71,7 +71,7 @@ variable {α : Type*} [DecidableEq α] [Fintype α] (G : SimpleGraph α) [Decida `ε`-uniform equipartition of bounded size (where the bound does not depend on the graph). -/ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : ∃ P : Finpartition univ, - P.IsEquipartition ∧ l ≤ P.parts.card ∧ P.parts.card ≤ bound ε l ∧ P.IsUniform G ε := by + P.IsEquipartition ∧ l ≤ #P.parts ∧ #P.parts ≤ bound ε l ∧ P.IsUniform G ε := by obtain hα | hα := le_total (card α) (bound ε l) -- If `card α ≤ bound ε l`, then the partition into singletons is acceptable. · refine ⟨⊥, bot_isEquipartition _, ?_⟩ @@ -79,7 +79,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : exact ⟨hl, hα, bot_isUniform _ hε⟩ -- Else, let's start from a dummy equipartition of size `initialBound ε l`. let t := initialBound ε l - have htα : t ≤ (univ : Finset α).card := + have htα : t ≤ #(univ : Finset α) := (initialBound_le_bound _ _).trans (by rwa [Finset.card_univ]) obtain ⟨dum, hdum₁, hdum₂⟩ := exists_equipartition_card_eq (univ : Finset α) (initialBound_pos _ _).ne' htα @@ -93,8 +93,8 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : have : Nonempty α := by rw [← Fintype.card_pos_iff] exact (bound_pos _ _).trans_le hα - suffices h : ∀ i, ∃ P : Finpartition (univ : Finset α), P.IsEquipartition ∧ t ≤ P.parts.card ∧ - P.parts.card ≤ stepBound^[i] t ∧ (P.IsUniform G ε ∨ ε ^ 5 / 4 * i ≤ P.energy G) by + suffices h : ∀ i, ∃ P : Finpartition (univ : Finset α), P.IsEquipartition ∧ t ≤ #P.parts ∧ + #P.parts ≤ stepBound^[i] t ∧ (P.IsUniform G ε ∨ ε ^ 5 / 4 * i ≤ P.energy G) by -- For `i > 4 / ε ^ 5` we know that the partition we get can't have energy `≥ ε ^ 5 / 4 * i > 1`, -- so it must instead be `ε`-uniform and we won. obtain ⟨P, hP₁, hP₂, hP₃, hP₄⟩ := h (⌊4 / ε ^ 5⌋₊ + 1) @@ -126,7 +126,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : -- Else, `P` must instead have energy at least `ε ^ 5 / 4 * i`. replace hP₄ := hP₄.resolve_left huniform -- We gather a few numerical facts. - have hεl' : 100 ≤ 4 ^ P.parts.card * ε ^ 5 := + have hεl' : 100 ≤ 4 ^ #P.parts * ε ^ 5 := (hundred_lt_pow_initialBound_mul hε l).le.trans (mul_le_mul_of_nonneg_right (pow_right_mono₀ (by norm_num) hP₂) <| by positivity) have hi : (i : ℝ) ≤ 4 / ε ^ 5 := by @@ -134,9 +134,9 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : rw [div_mul_eq_mul_div, div_le_iff₀ (show (0 : ℝ) < 4 by norm_num)] at hi norm_num at hi rwa [le_div_iff₀' (pow_pos hε _)] - have hsize : P.parts.card ≤ stepBound^[⌊4 / ε ^ 5⌋₊] t := + have hsize : #P.parts ≤ stepBound^[⌊4 / ε ^ 5⌋₊] t := hP₃.trans (monotone_iterate_of_id_le le_stepBound (Nat.le_floor hi) _) - have hPα : P.parts.card * 16 ^ P.parts.card ≤ card α := + have hPα : #P.parts * 16 ^ #P.parts ≤ card α := (Nat.mul_le_mul hsize (Nat.pow_le_pow_of_le_right (by norm_num) hsize)).trans hα -- We return the increment equipartition of `P`, which has energy `≥ ε ^ 5 / 4 * (i + 1)`. refine ⟨increment hP₁ G ε, increment_isEquipartition hP₁ G ε, ?_, ?_, Or.inr <| le_trans ?_ <| diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean index 572c8e65f679c..6d9c7efcbf156 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean @@ -55,8 +55,8 @@ variable (G : SimpleGraph α) [DecidableRel G.Adj] (ε : 𝕜) {s t : Finset α} to the density of any big enough pair of subsets. Intuitively, the edges between them are random-like. -/ def IsUniform (s t : Finset α) : Prop := - ∀ ⦃s'⦄, s' ⊆ s → ∀ ⦃t'⦄, t' ⊆ t → (s.card : 𝕜) * ε ≤ s'.card → - (t.card : 𝕜) * ε ≤ t'.card → |(G.edgeDensity s' t' : 𝕜) - (G.edgeDensity s t : 𝕜)| < ε + ∀ ⦃s'⦄, s' ⊆ s → ∀ ⦃t'⦄, t' ⊆ t → (#s : 𝕜) * ε ≤ #s' → + (#t : 𝕜) * ε ≤ #t' → |(G.edgeDensity s' t' : 𝕜) - (G.edgeDensity s t : 𝕜)| < ε variable {G ε} @@ -105,8 +105,8 @@ theorem not_isUniform_zero : ¬G.IsUniform (0 : 𝕜) s t := fun h => (abs_nonneg _).not_lt <| h (empty_subset _) (empty_subset _) (by simp) (by simp) theorem not_isUniform_iff : - ¬G.IsUniform ε s t ↔ ∃ s', s' ⊆ s ∧ ∃ t', t' ⊆ t ∧ ↑s.card * ε ≤ s'.card ∧ - ↑t.card * ε ≤ t'.card ∧ ε ≤ |G.edgeDensity s' t' - G.edgeDensity s t| := by + ¬G.IsUniform ε s t ↔ ∃ s', s' ⊆ s ∧ ∃ t', t' ⊆ t ∧ #s * ε ≤ #s' ∧ + #t * ε ≤ #t' ∧ ε ≤ |G.edgeDensity s' t' - G.edgeDensity s t| := by unfold IsUniform simp only [not_forall, not_lt, exists_prop, exists_and_left, Rat.cast_abs, Rat.cast_sub] @@ -128,7 +128,7 @@ theorem left_nonuniformWitnesses_subset (h : ¬G.IsUniform ε s t) : exact (not_isUniform_iff.1 h).choose_spec.1 theorem left_nonuniformWitnesses_card (h : ¬G.IsUniform ε s t) : - (s.card : 𝕜) * ε ≤ (G.nonuniformWitnesses ε s t).1.card := by + #s * ε ≤ #(G.nonuniformWitnesses ε s t).1 := by rw [nonuniformWitnesses, dif_pos h] exact (not_isUniform_iff.1 h).choose_spec.2.choose_spec.2.1 @@ -138,7 +138,7 @@ theorem right_nonuniformWitnesses_subset (h : ¬G.IsUniform ε s t) : exact (not_isUniform_iff.1 h).choose_spec.2.choose_spec.1 theorem right_nonuniformWitnesses_card (h : ¬G.IsUniform ε s t) : - (t.card : 𝕜) * ε ≤ (G.nonuniformWitnesses ε s t).2.card := by + #t * ε ≤ #(G.nonuniformWitnesses ε s t).2 := by rw [nonuniformWitnesses, dif_pos h] exact (not_isUniform_iff.1 h).choose_spec.2.choose_spec.2.2.1 @@ -162,7 +162,7 @@ theorem nonuniformWitness_subset (h : ¬G.IsUniform ε s t) : G.nonuniformWitnes · exact G.right_nonuniformWitnesses_subset fun i => h i.symm theorem le_card_nonuniformWitness (h : ¬G.IsUniform ε s t) : - (s.card : 𝕜) * ε ≤ (G.nonuniformWitness ε s t).card := by + #s * ε ≤ #(G.nonuniformWitness ε s t) := by unfold nonuniformWitness split_ifs · exact G.left_nonuniformWitnesses_card h @@ -224,7 +224,7 @@ theorem nonUniforms_bot (hε : 0 < ε) : (⊥ : Finpartition A).nonUniforms G ε /-- A finpartition of a graph's vertex set is `ε`-uniform (aka `ε`-regular) iff the proportion of its pairs of parts that are not `ε`-uniform is at most `ε`. -/ def IsUniform (ε : 𝕜) : Prop := - ((P.nonUniforms G ε).card : 𝕜) ≤ (P.parts.card * (P.parts.card - 1) : ℕ) * ε + (#(P.nonUniforms G ε) : 𝕜) ≤ (#P.parts * (#P.parts - 1) : ℕ) * ε lemma bot_isUniform (hε : 0 < ε) : (⊥ : Finpartition A).IsUniform G ε := by rw [Finpartition.IsUniform, Finpartition.card_bot, nonUniforms_bot _ hε, Finset.card_empty, @@ -252,7 +252,7 @@ variable (P G ε) (s : Finset α) /-- A choice of witnesses of non-uniformity among the parts of a finpartition. -/ noncomputable def nonuniformWitnesses : Finset (Finset α) := - (P.parts.filter fun t => s ≠ t ∧ ¬G.IsUniform ε s t).image (G.nonuniformWitness ε s) + {t ∈ P.parts | s ≠ t ∧ ¬G.IsUniform ε s t}.image (G.nonuniformWitness ε s) variable {P G ε s} {t : Finset α} @@ -265,11 +265,10 @@ theorem nonuniformWitness_mem_nonuniformWitnesses (h : ¬G.IsUniform ε s t) (ht open SimpleGraph in lemma IsEquipartition.card_interedges_sparsePairs_le' (hP : P.IsEquipartition) (hε : 0 ≤ ε) : - ((P.sparsePairs G ε).biUnion fun (U, V) ↦ G.interedges U V).card ≤ - ε * (A.card + P.parts.card) ^ 2 := by + #((P.sparsePairs G ε).biUnion fun (U, V) ↦ G.interedges U V) ≤ ε * (#A + #P.parts) ^ 2 := by calc - _ ≤ ∑ UV ∈ P.sparsePairs G ε, ((G.interedges UV.1 UV.2).card : 𝕜) := mod_cast card_biUnion_le - _ ≤ ∑ UV ∈ P.sparsePairs G ε, ε * (UV.1.card * UV.2.card) := ?_ + _ ≤ ∑ UV ∈ P.sparsePairs G ε, (#(G.interedges UV.1 UV.2) : 𝕜) := mod_cast card_biUnion_le + _ ≤ ∑ UV ∈ P.sparsePairs G ε, ε * (#UV.1 * #UV.2) := ?_ _ ≤ _ := sum_le_sum_of_subset_of_nonneg (filter_subset _ _) fun i _ _ ↦ by positivity _ = _ := (mul_sum _ _ _).symm _ ≤ _ := mul_le_mul_of_nonneg_left ?_ hε @@ -281,9 +280,9 @@ lemma IsEquipartition.card_interedges_sparsePairs_le' (hP : P.IsEquipartition) (Nat.cast_pos.2 (P.nonempty_of_mem_parts hUV.2.1).card_pos) norm_cast calc - (_ : ℕ) ≤ _ := sum_le_card_nsmul P.parts.offDiag (fun i ↦ i.1.card * i.2.card) - ((A.card / P.parts.card + 1)^2 : ℕ) ?_ - _ ≤ (P.parts.card * (A.card / P.parts.card) + P.parts.card) ^ 2 := ?_ + (_ : ℕ) ≤ _ := sum_le_card_nsmul P.parts.offDiag (fun i ↦ #i.1 * #i.2) + ((#A / #P.parts + 1)^2 : ℕ) ?_ + _ ≤ (#P.parts * (#A / #P.parts) + #P.parts) ^ 2 := ?_ _ ≤ _ := Nat.pow_le_pow_of_le_left (add_le_add_right (Nat.mul_div_le _ _) _) _ · simp only [Prod.forall, Finpartition.mk_mem_nonUniforms, and_imp, mem_offDiag, sq] rintro U V hU hV - @@ -293,10 +292,10 @@ lemma IsEquipartition.card_interedges_sparsePairs_le' (hP : P.IsEquipartition) exact Nat.sub_le _ _ lemma IsEquipartition.card_interedges_sparsePairs_le (hP : P.IsEquipartition) (hε : 0 ≤ ε) : - ((P.sparsePairs G ε).biUnion fun (U, V) ↦ G.interedges U V).card ≤ 4 * ε * A.card ^ 2 := by + #((P.sparsePairs G ε).biUnion fun (U, V) ↦ G.interedges U V) ≤ 4 * ε * #A ^ 2 := by calc _ ≤ _ := hP.card_interedges_sparsePairs_le' hε - _ ≤ ε * (A.card + A.card)^2 := by gcongr; exact P.card_parts_le_card + _ ≤ ε * (#A + #A)^2 := by gcongr; exact P.card_parts_le_card _ = _ := by ring private lemma aux {i j : ℕ} (hj : 0 < j) : j * (j - 1) * (i / j + 1) ^ 2 < (i + j) ^ 2 := by @@ -307,44 +306,44 @@ private lemma aux {i j : ℕ} (hj : 0 < j) : j * (j - 1) * (i / j + 1) ^ 2 < (i exact Nat.pow_le_pow_of_le_left (add_le_add_right (Nat.mul_div_le i j) _) _ lemma IsEquipartition.card_biUnion_offDiag_le' (hP : P.IsEquipartition) : - ((P.parts.biUnion offDiag).card : 𝕜) ≤ A.card * (A.card + P.parts.card) / P.parts.card := by + (#(P.parts.biUnion offDiag) : 𝕜) ≤ #A * (#A + #P.parts) / #P.parts := by obtain h | h := P.parts.eq_empty_or_nonempty · simp [h] calc - _ ≤ (P.parts.card : 𝕜) * (↑(A.card / P.parts.card) * ↑(A.card / P.parts.card + 1)) := + _ ≤ (#P.parts : 𝕜) * (↑(#A / #P.parts) * ↑(#A / #P.parts + 1)) := mod_cast card_biUnion_le_card_mul _ _ _ fun U hU ↦ ?_ - _ = P.parts.card * ↑(A.card / P.parts.card) * ↑(A.card / P.parts.card + 1) := by rw [mul_assoc] - _ ≤ A.card * (A.card / P.parts.card + 1) := + _ = #P.parts * ↑(#A / #P.parts) * ↑(#A / #P.parts + 1) := by rw [mul_assoc] + _ ≤ #A * (#A / #P.parts + 1) := mul_le_mul (mod_cast Nat.mul_div_le _ _) ?_ (by positivity) (by positivity) _ = _ := by rw [← div_add_same (mod_cast h.card_pos.ne'), mul_div_assoc] · simpa using Nat.cast_div_le - suffices (U.card - 1) * U.card ≤ A.card / P.parts.card * (A.card / P.parts.card + 1) by + suffices (#U - 1) * #U ≤ #A / #P.parts * (#A / #P.parts + 1) by rwa [Nat.mul_sub_right_distrib, one_mul, ← offDiag_card] at this have := hP.card_part_le_average_add_one hU refine Nat.mul_le_mul ((Nat.sub_le_sub_right this 1).trans ?_) this simp only [Nat.add_succ_sub_one, add_zero, card_univ, le_rfl] lemma IsEquipartition.card_biUnion_offDiag_le (hε : 0 < ε) (hP : P.IsEquipartition) - (hP' : 4 / ε ≤ P.parts.card) : (P.parts.biUnion offDiag).card ≤ ε / 2 * A.card ^ 2 := by + (hP' : 4 / ε ≤ #P.parts) : #(P.parts.biUnion offDiag) ≤ ε / 2 * #A ^ 2 := by obtain rfl | hA : A = ⊥ ∨ _ := A.eq_empty_or_nonempty · simp [Subsingleton.elim P ⊥] apply hP.card_biUnion_offDiag_le'.trans rw [div_le_iff₀ (Nat.cast_pos.2 (P.parts_nonempty hA.ne_empty).card_pos)] - have : (A.card : 𝕜) + P.parts.card ≤ 2 * A.card := by + have : (#A : 𝕜) + #P.parts ≤ 2 * #A := by rw [two_mul]; exact add_le_add_left (Nat.cast_le.2 P.card_parts_le_card) _ refine (mul_le_mul_of_nonneg_left this <| by positivity).trans ?_ - suffices 1 ≤ ε/4 * P.parts.card by + suffices 1 ≤ ε/4 * #P.parts by rw [mul_left_comm, ← sq] - convert mul_le_mul_of_nonneg_left this (mul_nonneg zero_le_two <| sq_nonneg (A.card : 𝕜)) + convert mul_le_mul_of_nonneg_left this (mul_nonneg zero_le_two <| sq_nonneg (#A : 𝕜)) using 1 <;> ring rwa [← div_le_iff₀', one_div_div] positivity lemma IsEquipartition.sum_nonUniforms_lt' (hA : A.Nonempty) (hε : 0 < ε) (hP : P.IsEquipartition) (hG : P.IsUniform G ε) : - ∑ i ∈ P.nonUniforms G ε, (i.1.card * i.2.card : 𝕜) < ε * (A.card + P.parts.card) ^ 2 := by + ∑ i ∈ P.nonUniforms G ε, (#i.1 * #i.2 : 𝕜) < ε * (#A + #P.parts) ^ 2 := by calc - _ ≤ (P.nonUniforms G ε).card • (↑(A.card / P.parts.card + 1) : 𝕜) ^ 2 := + _ ≤ #(P.nonUniforms G ε) • (↑(#A / #P.parts + 1) : 𝕜) ^ 2 := sum_le_card_nsmul _ _ _ ?_ _ = _ := nsmul_eq_mul _ _ _ ≤ _ := mul_le_mul_of_nonneg_right hG <| by positivity @@ -361,12 +360,12 @@ lemma IsEquipartition.sum_nonUniforms_lt' (hA : A.Nonempty) (hε : 0 < ε) (hP : lemma IsEquipartition.sum_nonUniforms_lt (hA : A.Nonempty) (hε : 0 < ε) (hP : P.IsEquipartition) (hG : P.IsUniform G ε) : - ((P.nonUniforms G ε).biUnion fun (U, V) ↦ U ×ˢ V).card < 4 * ε * A.card ^ 2 := by + #((P.nonUniforms G ε).biUnion fun (U, V) ↦ U ×ˢ V) < 4 * ε * #A ^ 2 := by calc - _ ≤ ∑ i ∈ P.nonUniforms G ε, (i.1.card * i.2.card : 𝕜) := by + _ ≤ ∑ i ∈ P.nonUniforms G ε, (#i.1 * #i.2 : 𝕜) := by norm_cast; simp_rw [← card_product]; exact card_biUnion_le _ < _ := hP.sum_nonUniforms_lt' hA hε hG - _ ≤ ε * (A.card + A.card) ^ 2 := by gcongr; exact P.card_parts_le_card + _ ≤ ε * (#A + #A) ^ 2 := by gcongr; exact P.card_parts_le_card _ = _ := by ring end Finpartition diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index 529afbfeaee47..8b0a0607d5484 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -57,7 +57,7 @@ for empty graphs, since there are no pairs of adjacent vertices. -/ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) 0 ℓ 0 where card := rfl regular := bot_degree - of_adj := fun v w h => h.elim + of_adj := fun _ _ h => h.elim of_not_adj := fun v w _h => by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] ext @@ -77,7 +77,7 @@ theorem IsSRGWith.top : of_not_adj := fun v w h h' => False.elim (h' ((top_adj v w).2 h)) theorem IsSRGWith.card_neighborFinset_union_eq {v w : V} (h : G.IsSRGWith n k ℓ μ) : - (G.neighborFinset v ∪ G.neighborFinset w).card = + #(G.neighborFinset v ∪ G.neighborFinset w) = 2 * k - Fintype.card (G.commonNeighbors v w) := by apply Nat.add_right_cancel (m := Fintype.card (G.commonNeighbors v w)) rw [Nat.sub_add_cancel, ← Set.toFinset_card] @@ -94,12 +94,12 @@ adjacent to either `v` or `w` when `¬G.Adj v w`. So it's the cardinality of `G.neighborSet v ∪ G.neighborSet w`. -/ theorem IsSRGWith.card_neighborFinset_union_of_not_adj {v w : V} (h : G.IsSRGWith n k ℓ μ) (hne : v ≠ w) (ha : ¬G.Adj v w) : - (G.neighborFinset v ∪ G.neighborFinset w).card = 2 * k - μ := by + #(G.neighborFinset v ∪ G.neighborFinset w) = 2 * k - μ := by rw [← h.of_not_adj hne ha] apply h.card_neighborFinset_union_eq theorem IsSRGWith.card_neighborFinset_union_of_adj {v w : V} (h : G.IsSRGWith n k ℓ μ) - (ha : G.Adj v w) : (G.neighborFinset v ∪ G.neighborFinset w).card = 2 * k - ℓ := by + (ha : G.Adj v w) : #(G.neighborFinset v ∪ G.neighborFinset w) = 2 * k - ℓ := by rw [← h.of_adj v w ha] apply h.card_neighborFinset_union_eq @@ -172,11 +172,7 @@ theorem IsSRGWith.param_eq · simp [h.compl.regular v] · intro w hw rw [mem_neighborFinset] at hw - simp_rw [bipartiteAbove] - -- This used to be part of the enclosing `simp_rw` chain, - -- but after leanprover/lean4#3124 it caused a maximum recursion depth error. - change Finset.card (filter (fun a => Adj G w a) _) = _ - simp_rw [← mem_neighborFinset, filter_mem_eq_inter] + simp_rw [bipartiteAbove, ← mem_neighborFinset, filter_mem_eq_inter] have s : {v} ⊆ G.neighborFinset w \ G.neighborFinset v := by rw [singleton_subset_iff, mem_sdiff, mem_neighborFinset] exact ⟨hw.symm, G.not_mem_neighborFinset_self v⟩ diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index c0cc9e7d6ca21..9d6763e5a5474 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -434,20 +434,20 @@ def completelyDistribLatticeMinimalAxioms : CompletelyDistribLattice.MinimalAxio inf := (· ⊓ ·) top := ⊤ bot := ⊥ - le_top := fun G' => ⟨Set.subset_univ _, fun a b => G'.adj_sub⟩ - bot_le := fun G' => ⟨Set.empty_subset _, fun a b => False.elim⟩ + le_top := fun G' => ⟨Set.subset_univ _, fun _ _ => G'.adj_sub⟩ + bot_le := fun _ => ⟨Set.empty_subset _, fun _ _ => False.elim⟩ sSup := sSup -- Porting note: needed `apply` here to modify elaboration; previously the term itself was fine. - le_sSup := fun s G' hG' => ⟨by apply Set.subset_iUnion₂ G' hG', fun a b hab => ⟨G', hG', hab⟩⟩ + le_sSup := fun s G' hG' => ⟨by apply Set.subset_iUnion₂ G' hG', fun _ _ hab => ⟨G', hG', hab⟩⟩ sSup_le := fun s G' hG' => - ⟨Set.iUnion₂_subset fun H hH => (hG' _ hH).1, by + ⟨Set.iUnion₂_subset fun _ hH => (hG' _ hH).1, by rintro a b ⟨H, hH, hab⟩ exact (hG' _ hH).2 hab⟩ sInf := sInf - sInf_le := fun s G' hG' => ⟨Set.iInter₂_subset G' hG', fun a b hab => hab.1 hG'⟩ - le_sInf := fun s G' hG' => - ⟨Set.subset_iInter₂ fun H hH => (hG' _ hH).1, fun a b hab => - ⟨fun H hH => (hG' _ hH).2 hab, G'.adj_sub hab⟩⟩ + sInf_le := fun _ G' hG' => ⟨Set.iInter₂_subset G' hG', fun _ _ hab => hab.1 hG'⟩ + le_sInf := fun _ G' hG' => + ⟨Set.subset_iInter₂ fun _ hH => (hG' _ hH).1, fun _ _ hab => + ⟨fun _ hH => (hG' _ hH).2 hab, G'.adj_sub hab⟩⟩ iInf_iSup_eq := fun f => Subgraph.ext (by simpa using iInf_iSup_eq) (by ext; simp [Classical.skolem]) } diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean index c3c8b49e6cd43..a5d36c33b508b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean @@ -133,19 +133,19 @@ alias ⟨EdgeDisjointTriangles.mem_sym2_subsingleton, _⟩ := variable [DecidableEq α] [Fintype α] [DecidableRel G.Adj] instance EdgeDisjointTriangles.instDecidable : Decidable G.EdgeDisjointTriangles := - decidable_of_iff ((G.cliqueFinset 3 : Set (Finset α)).Pairwise fun x y ↦ ((x ∩ y).card ≤ 1)) <| by + decidable_of_iff ((G.cliqueFinset 3 : Set (Finset α)).Pairwise fun x y ↦ (#(x ∩ y) ≤ 1)) <| by simp only [coe_cliqueFinset, EdgeDisjointTriangles, Finset.card_le_one, ← coe_inter]; rfl instance LocallyLinear.instDecidable : Decidable G.LocallyLinear := inferInstanceAs (Decidable (_ ∧ _)) lemma EdgeDisjointTriangles.card_edgeFinset_le (hG : G.EdgeDisjointTriangles) : - 3 * (G.cliqueFinset 3).card ≤ G.edgeFinset.card := by - rw [mul_comm, ← mul_one G.edgeFinset.card] + 3 * #(G.cliqueFinset 3) ≤ #G.edgeFinset := by + rw [mul_comm, ← mul_one #G.edgeFinset] refine card_mul_le_card_mul (fun s e ↦ e ∈ s.sym2) ?_ (fun e he ↦ ?_) · simp only [is3Clique_iff, mem_cliqueFinset_iff, mem_sym2_iff, forall_exists_index, and_imp] rintro _ a b c hab hac hbc rfl - have : Finset.card ({s(a, b), s(a, c), s(b, c)} : Finset (Sym2 α)) = 3 := by + have : #{s(a, b), s(a, c), s(b, c)} = 3 := by refine card_eq_three.2 ⟨_, _, _, ?_, ?_, ?_, rfl⟩ <;> simp [hab.ne, hac.ne, hbc.ne] rw [← this] refine card_mono ?_ @@ -155,9 +155,9 @@ lemma EdgeDisjointTriangles.card_edgeFinset_le (hG : G.EdgeDisjointTriangles) : using hG.mem_sym2_subsingleton (G.not_isDiag_of_mem_edgeSet <| mem_edgeFinset.1 he) lemma LocallyLinear.card_edgeFinset (hG : G.LocallyLinear) : - G.edgeFinset.card = 3 * (G.cliqueFinset 3).card := by + #G.edgeFinset = 3 * #(G.cliqueFinset 3) := by refine hG.edgeDisjointTriangles.card_edgeFinset_le.antisymm' ?_ - rw [← mul_comm, ← mul_one (Finset.card _)] + rw [← mul_comm, ← mul_one #_] refine card_mul_le_card_mul (fun e s ↦ e ∈ s.sym2) ?_ ?_ · simpa [Sym2.forall, Nat.one_le_iff_ne_zero, -Finset.card_eq_zero, Finset.card_ne_zero, Finset.Nonempty] @@ -165,7 +165,7 @@ lemma LocallyLinear.card_edgeFinset (hG : G.LocallyLinear) : simp only [mem_cliqueFinset_iff, is3Clique_iff, forall_exists_index, and_imp] rintro _ a b c hab hac hbc rfl calc - _ ≤ ({s(a, b), s(a, c), s(b, c)} : Finset _).card := card_le_card ?_ + _ ≤ #{s(a, b), s(a, c), s(b, c)} := card_le_card ?_ _ ≤ 3 := (card_insert_le _ _).trans (succ_le_succ <| (card_insert_le _ _).trans_eq <| by rw [card_singleton]) simp only [subset_iff, Sym2.forall, mem_sym2_iff, le_eq_subset, mem_bipartiteBelow, mem_insert, @@ -186,7 +186,7 @@ variable {G ε} theorem farFromTriangleFree_iff : G.FarFromTriangleFree ε ↔ ∀ ⦃H : SimpleGraph α⦄, [DecidableRel H.Adj] → H ≤ G → H.CliqueFree 3 → - ε * (card α ^ 2 : ℕ) ≤ G.edgeFinset.card - H.edgeFinset.card := deleteFar_iff + ε * (card α ^ 2 : ℕ) ≤ #G.edgeFinset - #H.edgeFinset := deleteFar_iff alias ⟨farFromTriangleFree.le_card_sub_card, _⟩ := farFromTriangleFree_iff @@ -198,7 +198,7 @@ section DecidableEq variable [DecidableEq α] theorem FarFromTriangleFree.cliqueFinset_nonempty' (hH : H ≤ G) (hG : G.FarFromTriangleFree ε) - (hcard : G.edgeFinset.card - H.edgeFinset.card < ε * (card α ^ 2 : ℕ)) : + (hcard : #G.edgeFinset - #H.edgeFinset < ε * (card α ^ 2 : ℕ)) : (H.cliqueFinset 3).Nonempty := nonempty_of_ne_empty <| cliqueFinset_eq_empty_iff.not.2 fun hH' => (hG.le_card_sub_card hH hH').not_lt hcard @@ -206,7 +206,7 @@ theorem FarFromTriangleFree.cliqueFinset_nonempty' (hH : H ≤ G) (hG : G.FarFro private lemma farFromTriangleFree_of_disjoint_triangles_aux {tris : Finset (Finset α)} (htris : tris ⊆ G.cliqueFinset 3) (pd : (tris : Set (Finset α)).Pairwise fun x y ↦ (x ∩ y : Set α).Subsingleton) (hHG : H ≤ G) - (hH : H.CliqueFree 3) : tris.card ≤ G.edgeFinset.card - H.edgeFinset.card := by + (hH : H.CliqueFree 3) : #tris ≤ #G.edgeFinset - #H.edgeFinset := by rw [← card_sdiff (edgeFinset_mono hHG), ← card_attach] by_contra! hG have ⦃t⦄ (ht : t ∈ tris) : @@ -234,7 +234,7 @@ triangle-free. -/ lemma farFromTriangleFree_of_disjoint_triangles (tris : Finset (Finset α)) (htris : tris ⊆ G.cliqueFinset 3) (pd : (tris : Set (Finset α)).Pairwise fun x y ↦ (x ∩ y : Set α).Subsingleton) - (tris_big : ε * (card α ^ 2 : ℕ) ≤ tris.card) : + (tris_big : ε * (card α ^ 2 : ℕ) ≤ #tris) : G.FarFromTriangleFree ε := by rw [farFromTriangleFree_iff] intros H _ hG hH @@ -243,7 +243,7 @@ lemma farFromTriangleFree_of_disjoint_triangles (tris : Finset (Finset α)) (Nat.cast_le.2 <| farFromTriangleFree_of_disjoint_triangles_aux htris pd hG hH) protected lemma EdgeDisjointTriangles.farFromTriangleFree (hG : G.EdgeDisjointTriangles) - (tris_big : ε * (card α ^ 2 : ℕ) ≤ (G.cliqueFinset 3).card) : + (tris_big : ε * (card α ^ 2 : ℕ) ≤ #(G.cliqueFinset 3)) : G.FarFromTriangleFree ε := farFromTriangleFree_of_disjoint_triangles _ Subset.rfl (by simpa using hG) tris_big @@ -258,16 +258,16 @@ lemma FarFromTriangleFree.lt_half (hG : G.FarFromTriangleFree ε) : ε < 2⁻¹ have hε₀ : 0 < ε := hε.trans_lt' (by norm_num) rw [inv_le_iff_one_le_mul₀ (zero_lt_two' 𝕜)] at hε calc - _ ≤ (G.edgeFinset.card : 𝕜) := by + _ ≤ (#G.edgeFinset : 𝕜) := by simpa using hG.le_card_sub_card bot_le (cliqueFree_bot (le_succ _)) - _ ≤ ε * 2 * (edgeFinset G).card := le_mul_of_one_le_left (by positivity) (by assumption) + _ ≤ ε * 2 * #G.edgeFinset := le_mul_of_one_le_left (by positivity) (by assumption) _ < ε * card α ^ 2 := ?_ rw [mul_assoc, mul_lt_mul_left hε₀] norm_cast calc _ ≤ 2 * (⊤ : SimpleGraph α).edgeFinset.card := by gcongr; exact le_top _ < card α ^ 2 := ?_ - rw [edgeFinset_top, filter_not, card_sdiff (subset_univ _), card_univ, Sym2.card,] + rw [edgeFinset_top, filter_not, card_sdiff (subset_univ _), card_univ, Sym2.card] simp_rw [choose_two_right, Nat.add_sub_cancel, Nat.mul_comm _ (card α), funext (propext <| Sym2.isDiag_iff_mem_range_diag ·), univ_filter_mem_range, mul_tsub, Nat.mul_div_cancel' (card α).even_mul_succ_self.two_dvd] @@ -276,7 +276,7 @@ lemma FarFromTriangleFree.lt_half (hG : G.FarFromTriangleFree ε) : ε < 2⁻¹ apply tsub_lt_self <;> positivity lemma FarFromTriangleFree.lt_one (hG : G.FarFromTriangleFree ε) : ε < 1 := - hG.lt_half.trans <| inv_lt_one one_lt_two + hG.lt_half.trans two_inv_lt_one theorem FarFromTriangleFree.nonpos (h₀ : G.FarFromTriangleFree ε) (h₁ : G.CliqueFree 3) : ε ≤ 0 := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean index f1687fb68c6d4..bff996c3fa38c 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean @@ -29,15 +29,15 @@ namespace SimpleGraph /-- The vertices of `s` whose density in `t` is `ε` less than expected. -/ private noncomputable def badVertices (ε : ℝ) (s t : Finset α) : Finset α := - s.filter fun x ↦ (t.filter <| G.Adj x).card < (G.edgeDensity s t - ε) * t.card + {x ∈ s | #{y ∈ t | G.Adj x y} < (G.edgeDensity s t - ε) * #t} private lemma card_interedges_badVertices_le : - (Rel.interedges G.Adj (badVertices G ε s t) t).card ≤ - (badVertices G ε s t).card * t.card * (G.edgeDensity s t - ε) := by + #(Rel.interedges G.Adj (badVertices G ε s t) t) ≤ + #(badVertices G ε s t) * #t * (G.edgeDensity s t - ε) := by classical refine (Nat.cast_le.2 <| (card_le_card <| subset_of_eq (Rel.interedges_eq_biUnion _)).trans card_biUnion_le).trans ?_ - simp_rw [Nat.cast_sum, card_map, ← nsmul_eq_mul, smul_mul_assoc, mul_comm (t.card : ℝ)] + simp_rw [Nat.cast_sum, card_map, ← nsmul_eq_mul, smul_mul_assoc, mul_comm (#t : ℝ)] exact sum_le_card_nsmul _ _ _ fun x hx ↦ (mem_filter.1 hx).2.le private lemma edgeDensity_badVertices_le (hε : 0 ≤ ε) (dst : 2 * ε ≤ G.edgeDensity s t) : @@ -49,7 +49,7 @@ private lemma edgeDensity_badVertices_le (hε : 0 ≤ ε) (dst : 2 * ε ≤ G.ed exact G.card_interedges_badVertices_le private lemma card_badVertices_le (dst : 2 * ε ≤ G.edgeDensity s t) (hst : G.IsUniform ε s t) : - (badVertices G ε s t).card ≤ s.card * ε := by + #(badVertices G ε s t) ≤ #s * ε := by have hε : ε ≤ 1 := (le_mul_of_one_le_of_le_of_nonneg (by norm_num) le_rfl hst.pos.le).trans (dst.trans <| by exact_mod_cast edgeDensity_le_one _ _ _) by_contra! h @@ -61,7 +61,7 @@ private lemma card_badVertices_le (dst : 2 * ε ≤ G.edgeDensity s t) (hst : G. /-- A subset of the triangles constructed in a weird way to make them easy to count. -/ private lemma triangle_split_helper [DecidableEq α] : (s \ (badVertices G ε s t ∪ badVertices G ε s u)).biUnion - (fun x ↦ (G.interedges (t.filter <| G.Adj x) (u.filter <| G.Adj x)).image (x, ·)) ⊆ + (fun x ↦ (G.interedges {y ∈ t | G.Adj x y} {y ∈ u | G.Adj x y}).image (x, ·)) ⊆ (s ×ˢ t ×ˢ u).filter (fun (x, y, z) ↦ G.Adj x y ∧ G.Adj x z ∧ G.Adj y z) := by rintro ⟨x, y, z⟩ simp only [mem_filter, mem_product, mem_biUnion, mem_sdiff, exists_prop, mem_union, @@ -72,19 +72,19 @@ private lemma triangle_split_helper [DecidableEq α] : private lemma good_vertices_triangle_card [DecidableEq α] (dst : 2 * ε ≤ G.edgeDensity s t) (dsu : 2 * ε ≤ G.edgeDensity s u) (dtu : 2 * ε ≤ G.edgeDensity t u) (utu : G.IsUniform ε t u) (x : α) (hx : x ∈ s \ (badVertices G ε s t ∪ badVertices G ε s u)) : - ε ^ 3 * t.card * u.card ≤ (((t.filter (G.Adj x) ×ˢ u.filter (G.Adj x)).filter - fun (y, z) ↦ G.Adj y z).image (x, ·)).card := by + ε ^ 3 * #t * #u ≤ #((({y ∈ t | G.Adj x y} ×ˢ {y ∈ u | G.Adj x y}).filter + fun (y, z) ↦ G.Adj y z).image (x, ·)) := by simp only [mem_sdiff, badVertices, mem_union, not_or, mem_filter, not_and_or, not_lt] at hx rw [← or_and_left, and_or_left] at hx simp only [false_or, and_not_self, mul_comm (_ - _)] at hx obtain ⟨-, hxY, hsu⟩ := hx - have hY : t.card * ε ≤ (filter (G.Adj x) t).card := + have hY : #t * ε ≤ #{y ∈ t | G.Adj x y} := (mul_le_mul_of_nonneg_left (by linarith) (Nat.cast_nonneg _)).trans hxY - have hZ : u.card * ε ≤ (filter (G.Adj x) u).card := + have hZ : #u * ε ≤ #{y ∈ u | G.Adj x y} := (mul_le_mul_of_nonneg_left (by linarith) (Nat.cast_nonneg _)).trans hsu rw [card_image_of_injective _ (Prod.mk.inj_left _)] have := utu (filter_subset (G.Adj x) _) (filter_subset (G.Adj x) _) hY hZ - have : ε ≤ G.edgeDensity (filter (G.Adj x) t) (filter (G.Adj x) u) := by + have : ε ≤ G.edgeDensity {y ∈ t | G.Adj x y} {y ∈ u | G.Adj x y} := by rw [abs_sub_lt_iff] at this; linarith rw [edgeDensity_def] at this push_cast at this @@ -101,11 +101,11 @@ lemma triangle_counting' (dst : 2 * ε ≤ G.edgeDensity s t) (hst : G.IsUniform ε s t) (dsu : 2 * ε ≤ G.edgeDensity s u) (usu : G.IsUniform ε s u) (dtu : 2 * ε ≤ G.edgeDensity t u) (utu : G.IsUniform ε t u) : - (1 - 2 * ε) * ε ^ 3 * s.card * t.card * u.card ≤ - ((s ×ˢ t ×ˢ u).filter fun (a, b, c) ↦ G.Adj a b ∧ G.Adj a c ∧ G.Adj b c).card := by + (1 - 2 * ε) * ε ^ 3 * #s * #t * #u ≤ + #((s ×ˢ t ×ˢ u).filter fun (a, b, c) ↦ G.Adj a b ∧ G.Adj a c ∧ G.Adj b c) := by classical - have h₁ : (badVertices G ε s t).card ≤ s.card * ε := G.card_badVertices_le dst hst - have h₂ : (badVertices G ε s u).card ≤ s.card * ε := G.card_badVertices_le dsu usu + have h₁ : #(badVertices G ε s t) ≤ #s * ε := G.card_badVertices_le dst hst + have h₂ : #(badVertices G ε s u) ≤ #s * ε := G.card_badVertices_le dsu usu let X' := s \ (badVertices G ε s t ∪ badVertices G ε s u) have : X'.biUnion _ ⊆ (s ×ˢ t ×ˢ u).filter fun (a, b, c) ↦ G.Adj a b ∧ G.Adj a c ∧ G.Adj b c := triangle_split_helper _ @@ -114,7 +114,7 @@ lemma triangle_counting' · apply le_trans _ (card_nsmul_le_sum X' _ _ <| G.good_vertices_triangle_card dst dsu dtu utu) rw [nsmul_eq_mul] have := hst.pos.le - suffices hX' : (1 - 2 * ε) * s.card ≤ X'.card by + suffices hX' : (1 - 2 * ε) * #s ≤ #X' by exact Eq.trans_le (by ring) (mul_le_mul_of_nonneg_right hX' <| by positivity) have i : badVertices G ε s t ∪ badVertices G ε s u ⊆ s := union_subset (filter_subset _ _) (filter_subset _ _) @@ -155,7 +155,7 @@ lemma triangle_counting (dst : 2 * ε ≤ G.edgeDensity s t) (ust : G.IsUniform ε s t) (hst : Disjoint s t) (dsu : 2 * ε ≤ G.edgeDensity s u) (usu : G.IsUniform ε s u) (hsu : Disjoint s u) (dtu : 2 * ε ≤ G.edgeDensity t u) (utu : G.IsUniform ε t u) (htu : Disjoint t u) : - (1 - 2 * ε) * ε ^ 3 * s.card * t.card * u.card ≤ (G.cliqueFinset 3).card := by + (1 - 2 * ε) * ε ^ 3 * #s * #t * #u ≤ #(G.cliqueFinset 3) := by apply (G.triangle_counting' dst ust dsu usu dtu utu).trans _ rw [Nat.cast_le] refine card_le_card_of_injOn (fun (x, y, z) ↦ {x, y, z}) ?_ ?_ diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean index c5d8d7059920e..b212ba252ae67 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean @@ -53,21 +53,21 @@ private lemma aux {n k : ℕ} (hk : 0 < k) (hn : k ≤ n) : n < 2 * k * (n / k) apply (mod_lt n hk).trans_le simpa using Nat.mul_le_mul_left k ((Nat.one_le_div_iff hk).2 hn) -private lemma card_bound (hP₁ : P.IsEquipartition) (hP₃ : P.parts.card ≤ bound (ε / 8) ⌈4/ε⌉₊) - (hX : s ∈ P.parts) : card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊ : ℝ) ≤ s.card := by +private lemma card_bound (hP₁ : P.IsEquipartition) (hP₃ : #P.parts ≤ bound (ε / 8) ⌈4/ε⌉₊) + (hX : s ∈ P.parts) : card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊ : ℝ) ≤ #s := by cases isEmpty_or_nonempty α · simp [Fintype.card_eq_zero] have := Finset.Nonempty.card_pos ⟨_, hX⟩ calc - _ ≤ card α / (2 * P.parts.card : ℝ) := by gcongr - _ ≤ ↑(card α / P.parts.card) := + _ ≤ card α / (2 * #P.parts : ℝ) := by gcongr + _ ≤ ↑(card α / #P.parts) := (div_le_iff₀' (by positivity)).2 <| mod_cast (aux ‹_› P.card_parts_le_card).le - _ ≤ (s.card : ℝ) := mod_cast hP₁.average_le_card_part hX + _ ≤ (#s : ℝ) := mod_cast hP₁.average_le_card_part hX private lemma triangle_removal_aux (hε : 0 < ε) (hP₁ : P.IsEquipartition) - (hP₃ : P.parts.card ≤ bound (ε / 8) ⌈4/ε⌉₊) + (hP₃ : #P.parts ≤ bound (ε / 8) ⌈4/ε⌉₊) (ht : t ∈ (G.regularityReduced P (ε/8) (ε/4)).cliqueFinset 3) : - triangleRemovalBound ε * card α ^ 3 ≤ (G.cliqueFinset 3).card := by + triangleRemovalBound ε * card α ^ 3 ≤ #(G.cliqueFinset 3) := by rw [mem_cliqueFinset_iff, is3Clique_iff] at ht obtain ⟨x, y, z, ⟨-, s, hX, Y, hY, xX, yY, nXY, uXY, dXY⟩, ⟨-, X', hX', Z, hZ, xX', zZ, nXZ, uXZ, dXZ⟩, @@ -87,28 +87,28 @@ private lemma triangle_removal_aux (hε : 0 < ε) (hP₁ : P.IsEquipartition) _ = (1 - 2 * (ε / 8)) * (ε / 8) ^ 3 * (card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) * (card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) * (card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) := by ring - _ ≤ (1 - 2 * (ε / 8)) * (ε / 8) ^ 3 * s.card * Y.card * Z.card := by + _ ≤ (1 - 2 * (ε / 8)) * (ε / 8) ^ 3 * #s * #Y * #Z := by gcongr <;> exact card_bound hP₁ hP₃ ‹_› _ ≤ _ := triangle_counting G (by rwa [that]) uXY dXY (by rwa [that]) uXZ dXZ (by rwa [that]) uYZ dYZ lemma regularityReduced_edges_card_aux [Nonempty α] (hε : 0 < ε) (hP : P.IsEquipartition) - (hPε : P.IsUniform G (ε/8)) (hP' : 4 / ε ≤ P.parts.card) : - 2 * (G.edgeFinset.card - (G.regularityReduced P (ε/8) (ε/4)).edgeFinset.card : ℝ) + (hPε : P.IsUniform G (ε/8)) (hP' : 4 / ε ≤ #P.parts) : + 2 * (#G.edgeFinset - #(G.regularityReduced P (ε/8) (ε/4)).edgeFinset : ℝ) < 2 * ε * (card α ^ 2 : ℕ) := by let A := (P.nonUniforms G (ε/8)).biUnion fun (U, V) ↦ U ×ˢ V let B := P.parts.biUnion offDiag let C := (P.sparsePairs G (ε/4)).biUnion fun (U, V) ↦ G.interedges U V calc - _ = ↑((univ ×ˢ univ).filter fun (x, y) ↦ - G.Adj x y ∧ ¬(G.regularityReduced P (ε / 8) (ε /4)).Adj x y).card := by + _ = (#((univ ×ˢ univ).filter fun (x, y) ↦ + G.Adj x y ∧ ¬(G.regularityReduced P (ε / 8) (ε /4)).Adj x y) : ℝ) := by rw [univ_product_univ, mul_sub, filter_and_not, cast_card_sdiff] · norm_cast rw [two_mul_card_edgeFinset, two_mul_card_edgeFinset] · exact monotone_filter_right _ fun xy hxy ↦ regularityReduced_le hxy - _ ≤ ((A ∪ B ∪ C).card : ℝ) := by gcongr; exact unreduced_edges_subset - _ ≤ ((A ∪ B).card + C.card : ℝ) := mod_cast (card_union_le _ _) - _ ≤ (A.card + B.card + C.card : ℝ) := by gcongr; exact mod_cast card_union_le _ _ + _ ≤ #(A ∪ B ∪ C) := by gcongr; exact unreduced_edges_subset + _ ≤ #(A ∪ B) + #C := mod_cast (card_union_le _ _) + _ ≤ #A + #B + #C := by gcongr; exact mod_cast card_union_le _ _ _ < 4 * (ε / 8) * card α ^ 2 + _ + _ := by gcongr; exact hP.sum_nonUniforms_lt univ_nonempty (by positivity) hPε _ ≤ _ + ε / 2 * card α ^ 2 + 4 * (ε / 4) * card α ^ 2 := by @@ -121,7 +121,7 @@ lemma regularityReduced_edges_card_aux [Nonempty α] (hε : 0 < ε) (hP : P.IsEq order of `(card α)^2`), then there were many triangles to start with (on the order of `(card α)^3`). -/ lemma FarFromTriangleFree.le_card_cliqueFinset (hG : G.FarFromTriangleFree ε) : - triangleRemovalBound ε * card α ^ 3 ≤ (G.cliqueFinset 3).card := by + triangleRemovalBound ε * card α ^ 3 ≤ #(G.cliqueFinset 3) := by cases isEmpty_or_nonempty α · simp [Fintype.card_eq_zero] obtain hε | hε := le_or_lt ε 0 @@ -135,7 +135,7 @@ lemma FarFromTriangleFree.le_card_cliqueFinset (hG : G.FarFromTriangleFree ε) : _ ≤ (1 : ℝ) := (triangleRemovalBound_mul_cube_lt hε).le _ ≤ _ := by simpa [one_le_iff_ne_zero] using (hG.cliqueFinset_nonempty hε).card_pos.ne' obtain ⟨P, hP₁, hP₂, hP₃, hP₄⟩ := szemeredi_regularity G (by positivity : 0 < ε / 8) hl' - have : 4/ε ≤ P.parts.card := hl.trans (cast_le.2 hP₂) + have : 4/ε ≤ #P.parts := hl.trans (cast_le.2 hP₂) have k := regularityReduced_edges_card_aux hε hP₁ hP₄ this rw [mul_assoc] at k replace k := lt_of_mul_lt_mul_left k zero_le_two @@ -144,9 +144,9 @@ lemma FarFromTriangleFree.le_card_cliqueFinset (hG : G.FarFromTriangleFree ε) : /-- **Triangle Removal Lemma**. If there are not too many triangles (on the order of `(card α)^3`) then they can all be removed by removing a few edges (on the order of `(card α)^2`). -/ -lemma triangle_removal (hG : (G.cliqueFinset 3).card < triangleRemovalBound ε * card α ^ 3) : +lemma triangle_removal (hG : #(G.cliqueFinset 3) < triangleRemovalBound ε * card α ^ 3) : ∃ G' ≤ G, ∃ _ : DecidableRel G'.Adj, - (G.edgeFinset.card - G'.edgeFinset.card : ℝ) < ε * (card α^2 : ℕ) ∧ G'.CliqueFree 3 := by + (#G.edgeFinset - #G'.edgeFinset : ℝ) < ε * (card α^2 : ℕ) ∧ G'.CliqueFree 3 := by by_contra! h refine hG.not_le (farFromTriangleFree_iff.2 ?_).le_card_cliqueFinset intros G' _ hG hG' diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean index 6bcfe21447840..3135218de5e3d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean @@ -216,11 +216,11 @@ lemma cliqueFinset_eq_image [NoAccidental t] : (graph t).cliqueFinset 3 = t.imag lemma cliqueFinset_eq_map [NoAccidental t] : (graph t).cliqueFinset 3 = t.map toTriangle := by simp [cliqueFinset_eq_image, map_eq_image] -@[simp] lemma card_triangles [NoAccidental t] : ((graph t).cliqueFinset 3).card = t.card := by +@[simp] lemma card_triangles [NoAccidental t] : #((graph t).cliqueFinset 3) = #t := by rw [cliqueFinset_eq_map, card_map] lemma farFromTriangleFree [ExplicitDisjoint t] {ε : 𝕜} - (ht : ε * ((Fintype.card α + Fintype.card β + Fintype.card γ) ^ 2 : ℕ) ≤ t.card) : + (ht : ε * ((Fintype.card α + Fintype.card β + Fintype.card γ) ^ 2 : ℕ) ≤ #t) : (graph t).FarFromTriangleFree ε := farFromTriangleFree_of_disjoint_triangles (t.map toTriangle) (map_subset_iff_subset_preimage.2 fun x hx ↦ by simpa using toTriangle_is3Clique hx) diff --git a/Mathlib/Combinatorics/SimpleGraph/Turan.lean b/Mathlib/Combinatorics/SimpleGraph/Turan.lean index 45760dc0bd670..bb502466b40b0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Turan.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Turan.lean @@ -49,7 +49,7 @@ variable (G) in the same vertex set has the same or fewer number of edges. -/ def IsTuranMaximal (r : ℕ) : Prop := G.CliqueFree (r + 1) ∧ ∀ (H : SimpleGraph V) [DecidableRel H.Adj], - H.CliqueFree (r + 1) → H.edgeFinset.card ≤ G.edgeFinset.card + H.CliqueFree (r + 1) → #H.edgeFinset ≤ #G.edgeFinset section Defs @@ -72,7 +72,7 @@ lemma turanGraph_zero : turanGraph n 0 = ⊤ := by @[simp] theorem turanGraph_eq_top : turanGraph n r = ⊤ ↔ r = 0 ∨ n ≤ r := by - simp_rw [SimpleGraph.ext_iff, Function.funext_iff, turanGraph, top_adj, eq_iff_iff, not_iff_not] + simp_rw [SimpleGraph.ext_iff, funext_iff, turanGraph, top_adj, eq_iff_iff, not_iff_not] refine ⟨fun h ↦ ?_, ?_⟩ · contrapose! h use ⟨0, (Nat.pos_of_ne_zero h.1).trans h.2⟩, ⟨r, h.2⟩ @@ -111,7 +111,7 @@ lemma exists_isTuranMaximal (hr : 0 < r): have cn : c.toFinset.Nonempty := ⟨⊥, by simp only [Set.toFinset_setOf, mem_filter, mem_univ, true_and, c] exact cliqueFree_bot (by omega)⟩ - obtain ⟨S, Sm, Sl⟩ := exists_max_image c.toFinset (·.edgeFinset.card) cn + obtain ⟨S, Sm, Sl⟩ := exists_max_image c.toFinset (#·.edgeFinset) cn use S, inferInstance rw [Set.mem_toFinset] at Sm refine ⟨Sm, fun I _ cf ↦ ?_⟩ @@ -195,11 +195,11 @@ lemma not_adj_iff_part_eq [DecidableEq V] : rw [fp.mem_part_iff_part_eq_part (mem_univ t) (mem_univ s), eq_comm] lemma degree_eq_card_sub_part_card [DecidableEq V] : - G.degree s = Fintype.card V - (h.finpartition.part s).card := + G.degree s = Fintype.card V - #(h.finpartition.part s) := calc - _ = (univ.filter (G.Adj s)).card := by + _ = #{t | G.Adj s t} := by simp [← card_neighborFinset_eq_degree, neighborFinset] - _ = Fintype.card V - (univ.filter (¬G.Adj s ·)).card := + _ = Fintype.card V - #{t | ¬G.Adj s t} := eq_tsub_of_add_eq (filter_card_add_filter_neg_card_eq_card _) _ = _ := by congr; ext; rw [mem_filter] @@ -224,13 +224,13 @@ theorem isEquipartition [DecidableEq V] : h.finpartition.IsEquipartition := by rw [hn] at ineq; omega rw [G.card_edgeFinset_replaceVertex_of_adj ha, degree_eq_card_sub_part_card h, small_eq, degree_eq_card_sub_part_card h, large_eq] - have : large.card ≤ Fintype.card V := by simpa using card_le_card large.subset_univ + have : #large ≤ Fintype.card V := by simpa using card_le_card large.subset_univ omega -lemma card_parts_le [DecidableEq V] : h.finpartition.parts.card ≤ r := by +lemma card_parts_le [DecidableEq V] : #h.finpartition.parts ≤ r := by by_contra! l obtain ⟨z, -, hz⟩ := h.finpartition.exists_subset_part_bijOn - have ncf : ¬G.CliqueFree z.card := by + have ncf : ¬G.CliqueFree #z := by refine IsNClique.not_cliqueFree ⟨fun v hv w hw hn ↦ ?_, rfl⟩ contrapose! hn exact hz.injOn hv hw (by rwa [← h.not_adj_iff_part_eq]) @@ -240,7 +240,7 @@ lemma card_parts_le [DecidableEq V] : h.finpartition.parts.card ≤ r := by /-- There are `min n r` parts in a graph on `n` vertices satisfying `G.IsTuranMaximal r`. `min` handles the `n < r` case, when `G` is complete but still `r + 1`-cliquefree for having insufficiently many vertices. -/ -theorem card_parts [DecidableEq V] : h.finpartition.parts.card = min (Fintype.card V) r := by +theorem card_parts [DecidableEq V] : #h.finpartition.parts = min (Fintype.card V) r := by set fp := h.finpartition apply le_antisymm (le_min fp.card_parts_le_card h.card_parts_le) by_contra! l @@ -255,7 +255,7 @@ theorem card_parts [DecidableEq V] : h.finpartition.parts.card = min (Fintype.ca intro z zc; push_neg; simp_rw [h.not_adj_iff_part_eq] exact exists_ne_map_eq_of_card_lt_of_maps_to (zc.symm ▸ l.2) fun a _ ↦ fp.part_mem (mem_univ a) use G ⊔ edge x y, inferInstance, cf.sup_edge x y - convert Nat.lt.base G.edgeFinset.card + convert Nat.lt.base #G.edgeFinset convert G.card_edgeFinset_sup_edge _ hn rwa [h.not_adj_iff_part_eq] diff --git a/Mathlib/Combinatorics/Young/SemistandardTableau.lean b/Mathlib/Combinatorics/Young/SemistandardTableau.lean index 1f4c8542dcbca..fac50829baf05 100644 --- a/Mathlib/Combinatorics/Young/SemistandardTableau.lean +++ b/Mathlib/Combinatorics/Young/SemistandardTableau.lean @@ -68,10 +68,6 @@ instance instFunLike {μ : YoungDiagram} : FunLike (SemistandardYoungTableau μ) cases T' congr -/-- Helper instance for when there's too many metavariables to apply `CoeFun.coe` directly. -/ -instance {μ : YoungDiagram} : CoeFun (SemistandardYoungTableau μ) fun _ ↦ ℕ → ℕ → ℕ := - inferInstance - @[simp] theorem to_fun_eq_coe {μ : YoungDiagram} {T : SemistandardYoungTableau μ} : T.entry = (T : ℕ → ℕ → ℕ) := diff --git a/Mathlib/Combinatorics/Young/YoungDiagram.lean b/Mathlib/Combinatorics/Young/YoungDiagram.lean index fad6a3949ea28..7bb1431dc4004 100644 --- a/Mathlib/Combinatorics/Young/YoungDiagram.lean +++ b/Mathlib/Combinatorics/Young/YoungDiagram.lean @@ -153,7 +153,6 @@ theorem cells_bot : (⊥ : YoungDiagram).cells = ∅ := rfl -- Porting note: removed `↑`, added `.cells` and changed proof --- @[simp] -- Porting note (#10618): simp can prove this @[norm_cast] theorem coe_bot : (⊥ : YoungDiagram).cells = (∅ : Set (ℕ × ℕ)) := by refine Set.eq_of_subset_of_subset ?_ ?_ diff --git a/Mathlib/Computability/Ackermann.lean b/Mathlib/Computability/Ackermann.lean index 211e594b14670..ace0d47e3ed95 100644 --- a/Mathlib/Computability/Ackermann.lean +++ b/Mathlib/Computability/Ackermann.lean @@ -175,7 +175,7 @@ theorem lt_ack_right (m n : ℕ) : n < ack m n := -- we reorder the arguments to appease the equation compiler private theorem ack_strict_mono_left' : ∀ {m₁ m₂} (n), m₁ < m₂ → ack m₁ n < ack m₂ n - | m, 0, n => fun h => (not_lt_zero m h).elim + | m, 0, _ => fun h => (not_lt_zero m h).elim | 0, m + 1, 0 => fun _h => by simpa using one_lt_ack_succ_right m 0 | 0, m + 1, n + 1 => fun h => by rw [ack_zero, ack_succ_succ] diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index 5f7d1c28e9623..9cfbcd713b62a 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -644,9 +644,9 @@ lemma eventually_atTop_sumTransform_le : _ ≤ u := by exact_mod_cast hu'.1 _ ≤ n ^ (p a b) * (∑ _u ∈ Finset.Ico (r i n) n, c₂ * g n / (r i n) ^ ((p a b) + 1)) := by gcongr with u hu; rw [Finset.mem_Ico] at hu; exact hu.1 - _ ≤ n ^ (p a b) * (Finset.Ico (r i n) n).card • (c₂ * g n / (r i n) ^ ((p a b) + 1)) := by + _ ≤ n ^ p a b * #(Ico (r i n) n) • (c₂ * g n / r i n ^ (p a b + 1)) := by gcongr; exact Finset.sum_le_card_nsmul _ _ _ (fun x _ => by rfl) - _ = n ^ (p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / (r i n) ^ ((p a b) + 1)) := by + _ = n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / r i n ^ (p a b + 1)) := by rw [nsmul_eq_mul, mul_assoc] _ = n ^ (p a b) * (n - r i n) * (c₂ * g n / (r i n) ^ ((p a b) + 1)) := by congr; rw [Nat.card_Ico, Nat.cast_sub (le_of_lt <| hr_lt_n i)] @@ -682,9 +682,9 @@ lemma eventually_atTop_sumTransform_le : _ ≤ u := by exact hu.1 exact rpow_le_rpow_of_exponent_nonpos (by positivity) (by exact_mod_cast (le_of_lt hu.2)) (le_of_lt hp) - _ ≤ n ^ (p a b) * (Finset.Ico (r i n) n).card • (c₂ * g n / n ^ ((p a b) + 1)) := by + _ ≤ n ^ p a b * #(Ico (r i n) n) • (c₂ * g n / n ^ (p a b + 1)) := by gcongr; exact Finset.sum_le_card_nsmul _ _ _ (fun x _ => by rfl) - _ = n ^ (p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / n ^ ((p a b) + 1)) := by + _ = n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / n ^ (p a b + 1)) := by rw [nsmul_eq_mul, mul_assoc] _ = n ^ (p a b) * (n - r i n) * (c₂ * g n / n ^ ((p a b) + 1)) := by congr; rw [Nat.card_Ico, Nat.cast_sub (le_of_lt <| hr_lt_n i)] @@ -729,9 +729,9 @@ lemma eventually_atTop_sumTransform_ge : positivity · rw [Finset.mem_Ico] at hu exact le_of_lt hu.2 - _ ≥ n ^ (p a b) * (Finset.Ico (r i n) n).card • (c₂ * g n / n ^ ((p a b) + 1)) := by + _ ≥ n ^ p a b * #(Ico (r i n) n) • (c₂ * g n / n ^ (p a b + 1)) := by gcongr; exact Finset.card_nsmul_le_sum _ _ _ (fun x _ => by rfl) - _ = n ^ (p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / n ^ ((p a b) + 1)) := by + _ = n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / n ^ (p a b + 1)) := by rw [nsmul_eq_mul, mul_assoc] _ = n ^ (p a b) * (n - r i n) * (c₂ * g n / n ^ ((p a b) + 1)) := by congr; rw [Nat.card_Ico, Nat.cast_sub (le_of_lt <| hr_lt_n i)] @@ -764,12 +764,12 @@ lemma eventually_atTop_sumTransform_ge : · rw [Finset.mem_Ico] at hu exact rpow_le_rpow_of_exponent_nonpos (by positivity) (by exact_mod_cast hu.1) (le_of_lt hp) - _ ≥ n ^ (p a b) * (Finset.Ico (r i n) n).card • (c₂ * g n / (r i n) ^ ((p a b) + 1)) := by + _ ≥ n ^ p a b * #(Ico (r i n) n) • (c₂ * g n / r i n ^ (p a b + 1)) := by gcongr; exact Finset.card_nsmul_le_sum _ _ _ (fun x _ => by rfl) - _ = n ^ (p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / (r i n) ^ ((p a b) + 1)) := by + _ = n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / r i n ^ (p a b + 1)) := by rw [nsmul_eq_mul, mul_assoc] - _ ≥ n ^ (p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / (c₁ * n) ^ ((p a b) + 1)) := by - gcongr n^(p a b) * (Finset.Ico (r i n) n).card * (c₂ * g n / ?_) + _ ≥ n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / (c₁ * n) ^ (p a b + 1)) := by + gcongr n ^ p a b * #(Ico (r i n) n) * (c₂ * g n / ?_) exact rpow_le_rpow_of_exponent_nonpos (by positivity) (hn₁ i) (le_of_lt hp) _ = n ^ (p a b) * (n - r i n) * (c₂ * g n / (c₁ * n) ^ ((p a b) + 1)) := by congr; rw [Nat.card_Ico, Nat.cast_sub (le_of_lt <| hr_lt_n i)] diff --git a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean index aace8634bc1a8..f9b3f66acc2b8 100644 --- a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean +++ b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean @@ -131,7 +131,7 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ refine hmain ⌊-logb 2 (x / x₀)⌋₊ x le_rfl ⟨?lb, ?ub⟩ case lb => rw [← le_div_iff₀ x₀_pos] - refine (logb_le_logb (b := 2) (by norm_num) (zpow_pos_of_pos (by norm_num) _) + refine (logb_le_logb (b := 2) (by norm_num) (zpow_pos (by norm_num) _) (by positivity)).mp ?_ rw [← rpow_intCast, logb_rpow (by norm_num) (by norm_num), ← neg_le_neg_iff] simp only [Int.cast_sub, Int.cast_neg, Int.cast_natCast, Int.cast_one, neg_sub, sub_neg_eq_add] @@ -140,7 +140,7 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ case ub => rw [← div_le_iff₀ x₀_pos] refine (logb_le_logb (b := 2) (by norm_num) (by positivity) - (zpow_pos_of_pos (by norm_num) _)).mp ?_ + (zpow_pos (by norm_num) _)).mp ?_ rw [← rpow_intCast, logb_rpow (by norm_num) (by norm_num), ← neg_le_neg_iff] simp only [Int.cast_neg, Int.cast_natCast, neg_neg] have : 0 ≤ -logb 2 (x / x₀) := by diff --git a/Mathlib/Computability/EpsilonNFA.lean b/Mathlib/Computability/EpsilonNFA.lean index 15f0b154b182a..63bf7127e644f 100644 --- a/Mathlib/Computability/EpsilonNFA.lean +++ b/Mathlib/Computability/EpsilonNFA.lean @@ -28,7 +28,7 @@ universe u v /-- An `εNFA` is a set of states (`σ`), a transition function from state to state labelled by the alphabet (`step`), a starting state (`start`) and a set of acceptance states (`accept`). Note the transition function sends a state to a `Set` of states and can make ε-transitions by - inputing `none`. + inputting `none`. Since this definition allows for Automata with infinite states, a `Fintype` instance must be supplied for true `εNFA`'s. -/ structure εNFA (α : Type u) (σ : Type v) where @@ -41,7 +41,7 @@ structure εNFA (α : Type u) (σ : Type v) where /-- Set of acceptance states. -/ accept : Set σ -variable {α : Type u} {σ σ' : Type v} (M : εNFA α σ) {S : Set σ} {x : List α} {s : σ} {a : α} +variable {α : Type u} {σ : Type v} (M : εNFA α σ) {S : Set σ} {s : σ} {a : α} namespace εNFA @@ -201,8 +201,6 @@ instance : One (εNFA α σ) := instance : Inhabited (εNFA α σ) := ⟨0⟩ -variable (P : εNFA α σ) (Q : εNFA α σ') - @[simp] theorem step_zero (s a) : (0 : εNFA α σ).step s a = ∅ := rfl diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index a2de5176d359b..0bce012c8ecc0 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -153,8 +153,7 @@ theorem ComputablePred.of_eq {α} [Primcodable α] {p q : α → Prop} (hp : Com namespace ComputablePred -variable {α : Type*} {σ : Type*} -variable [Primcodable α] [Primcodable σ] +variable {α : Type*} [Primcodable α] open Nat.Partrec (Code) @@ -162,7 +161,7 @@ open Nat.Partrec.Code Computable theorem computable_iff {p : α → Prop} : ComputablePred p ↔ ∃ f : α → Bool, Computable f ∧ p = fun a => (f a : Prop) := - ⟨fun ⟨D, h⟩ => ⟨_, h, funext fun a => propext (Bool.decide_iff _).symm⟩, by + ⟨fun ⟨_, h⟩ => ⟨_, h, funext fun _ => propext (Bool.decide_iff _).symm⟩, by rintro ⟨f, h, rfl⟩; exact ⟨by infer_instance, by simpa using h⟩⟩ protected theorem not {p : α → Prop} (hp : ComputablePred p) : ComputablePred fun a => ¬p a := by diff --git a/Mathlib/Computability/Language.lean b/Mathlib/Computability/Language.lean index a8779cd1c9283..4e40a3919b388 100644 --- a/Mathlib/Computability/Language.lean +++ b/Mathlib/Computability/Language.lean @@ -248,7 +248,7 @@ theorem one_add_kstar_mul_self_eq_kstar (l : Language α) : 1 + l∗ * l = l∗ instance : KleeneAlgebra (Language α) := { Language.instSemiring, Set.completeAtomicBooleanAlgebra with kstar := fun L ↦ L∗, - one_le_kstar := fun a l hl ↦ ⟨[], hl, by simp⟩, + one_le_kstar := fun a _ hl ↦ ⟨[], hl, by simp⟩, mul_kstar_le_kstar := fun a ↦ (one_add_self_mul_kstar_eq_kstar a).le.trans' le_sup_right, kstar_mul_le_kstar := fun a ↦ (one_add_kstar_mul_self_eq_kstar a).le.trans' le_sup_right, kstar_mul_le_self := fun l m h ↦ by diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 543c6f0ffa979..700990868e922 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -47,7 +47,7 @@ variable (H : ∃ n, true ∈ p n ∧ ∀ k < n, (p k).Dom) def rfindX : { n // true ∈ p n ∧ ∀ m < n, false ∈ p m } := suffices ∀ k, (∀ n < k, false ∈ p n) → { n // true ∈ p n ∧ ∀ m < n, false ∈ p m } from - this 0 fun n => (Nat.not_lt_zero _).elim + this 0 fun _ => (Nat.not_lt_zero _).elim @WellFounded.fix _ _ (lbp p) (wf_lbp p H) (by intro m IH al @@ -102,7 +102,7 @@ theorem mem_rfind {p : ℕ →. Bool} {n : ℕ} : theorem rfind_min' {p : ℕ → Bool} {m : ℕ} (pm : p m) : ∃ n ∈ rfind p, n ≤ m := have : true ∈ (p : ℕ →. Bool) m := ⟨trivial, pm⟩ - let ⟨n, hn⟩ := dom_iff_mem.1 <| (@rfind_dom p).2 ⟨m, this, fun {k} _ => ⟨⟩⟩ + let ⟨n, hn⟩ := dom_iff_mem.1 <| (@rfind_dom p).2 ⟨m, this, fun {_} _ => ⟨⟩⟩ ⟨n, hn, not_lt.1 fun h => by injection mem_unique this (rfind_min hn h)⟩ theorem rfind_zero_none (p : ℕ →. Bool) (p0 : p 0 = Part.none) : rfind p = Part.none := @@ -118,7 +118,7 @@ theorem rfindOpt_spec {α} {f : ℕ → Option α} {a} (h : a ∈ rfindOpt f) : ⟨n, mem_coe.1 h₂⟩ theorem rfindOpt_dom {α} {f : ℕ → Option α} : (rfindOpt f).Dom ↔ ∃ n a, a ∈ f n := - ⟨fun h => (rfindOpt_spec ⟨h, rfl⟩).imp fun n h => ⟨_, h⟩, fun h => by + ⟨fun h => (rfindOpt_spec ⟨h, rfl⟩).imp fun _ h => ⟨_, h⟩, fun h => by have h' : ∃ n, (f n).isSome := h.imp fun n => Option.isSome_iff_exists.2 have s := Nat.find_spec h' have fd : (rfind fun n => (f n).isSome).Dom := @@ -179,8 +179,8 @@ protected theorem some : Partrec some := of_primrec Primrec.id theorem none : Partrec fun _ => none := - (of_primrec (Nat.Primrec.const 1)).rfind.of_eq fun n => - eq_none_iff.2 fun a ⟨h, _⟩ => by simp at h + (of_primrec (Nat.Primrec.const 1)).rfind.of_eq fun _ => + eq_none_iff.2 fun _ ⟨h, _⟩ => by simp at h theorem prec' {f g h} (hf : Partrec f) (hg : Partrec g) (hh : Partrec h) : Partrec fun a => (f a).bind fun n => n.rec (g a) @@ -357,8 +357,7 @@ end Computable namespace Partrec -variable {α : Type*} {β : Type*} {γ : Type*} {σ : Type*} -variable [Primcodable α] [Primcodable β] [Primcodable γ] [Primcodable σ] +variable {α : Type*} {β : Type*} {σ : Type*} [Primcodable α] [Primcodable β] [Primcodable σ] open Computable @@ -469,8 +468,7 @@ end Computable₂ namespace Partrec -variable {α : Type*} {β : Type*} {γ : Type*} {σ : Type*} -variable [Primcodable α] [Primcodable β] [Primcodable γ] [Primcodable σ] +variable {α : Type*} {σ : Type*} [Primcodable α] [Primcodable σ] open Computable diff --git a/Mathlib/Computability/PartrecCode.lean b/Mathlib/Computability/PartrecCode.lean index 74b64e82859ab..723eb31bfc2be 100644 --- a/Mathlib/Computability/PartrecCode.lean +++ b/Mathlib/Computability/PartrecCode.lean @@ -109,7 +109,6 @@ protected def id : Code := def curry (c : Code) (n : ℕ) : Code := comp c (pair (Code.const n) Code.id) --- Porting note: `bit0` and `bit1` are deprecated. /-- An encoding of a `Nat.Partrec.Code` as a ℕ. -/ def encodeCode : Code → ℕ | zero => 0 @@ -492,7 +491,7 @@ instance : Membership (ℕ →. ℕ) Code := @[simp] theorem eval_const : ∀ n m, eval (Code.const n) m = Part.some n - | 0, m => rfl + | 0, _ => rfl | n + 1, m => by simp! [eval_const n m] @[simp] diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index 350ee120e6376..3defa207c49ee 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -619,7 +619,7 @@ protected theorem beq [DecidableEq α] : Primrec₂ (@BEq.beq α _) := have : PrimrecRel fun a b : ℕ => a = b := (PrimrecPred.and nat_le nat_le.swap).of_eq fun a => by simp [le_antisymm_iff] (this.comp₂ (Primrec.encode.comp₂ Primrec₂.left) (Primrec.encode.comp₂ Primrec₂.right)).of_eq - fun a b => encode_injective.eq_iff + fun _ _ => encode_injective.eq_iff protected theorem eq [DecidableEq α] : PrimrecRel (@Eq α) := Primrec.beq @@ -706,20 +706,12 @@ theorem nat_bodd : Primrec Nat.bodd := theorem nat_div2 : Primrec Nat.div2 := (nat_div.comp .id (const 2)).of_eq fun n => n.div2_val.symm --- Porting note: this is no longer used --- theorem nat_boddDiv2 : Primrec Nat.boddDiv2 := pair nat_bodd nat_div2 - --- Porting note: bit0 is deprecated theorem nat_double : Primrec (fun n : ℕ => 2 * n) := nat_mul.comp (const _) Primrec.id --- Porting note: bit1 is deprecated theorem nat_double_succ : Primrec (fun n : ℕ => 2 * n + 1) := nat_double |> Primrec.succ.comp --- Porting note: this is no longer used --- theorem nat_div_mod : Primrec₂ fun n k : ℕ => (n / k, n % k) := pair nat_div nat_mod - end Primrec section @@ -1097,7 +1089,7 @@ def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodab ⟨have : Primrec fun n => (@decode α _ n).bind fun a => Option.guard p a := option_bind .decode (option_guard (hp.comp snd).to₂ snd) nat_iff.1 <| (encode_iff.2 this).of_eq fun n => - show _ = encode ((@decode α _ n).bind fun a => _) by + show _ = encode ((@decode α _ n).bind fun _ => _) by cases' @decode α _ n with a; · rfl dsimp [Option.guard] by_cases h : p a <;> simp [h]; rfl⟩ @@ -1355,8 +1347,8 @@ theorem natPair : @Primrec' 2 fun v => v.head.pair v.tail.head := protected theorem encode : ∀ {n}, @Primrec' n encode | 0 => (const 0).of_eq fun v => by rw [v.eq_nil]; rfl - | n + 1 => - (succ.comp₁ _ (natPair.comp₂ _ head (tail Primrec'.encode))).of_eq fun ⟨a :: l, e⟩ => rfl + | _ + 1 => + (succ.comp₁ _ (natPair.comp₂ _ head (tail Primrec'.encode))).of_eq fun ⟨_ :: _, _⟩ => rfl theorem sqrt : @Primrec' 1 fun v => v.head.sqrt := by suffices H : ∀ n : ℕ, n.sqrt = diff --git a/Mathlib/Computability/Reduce.lean b/Mathlib/Computability/Reduce.lean index 753ba658feba9..4b09ff9c74119 100644 --- a/Mathlib/Computability/Reduce.lean +++ b/Mathlib/Computability/Reduce.lean @@ -106,8 +106,7 @@ theorem transitive_oneOneReducible {α} [Primcodable α] : Transitive (@OneOneRe namespace ComputablePred -variable {α : Type*} {β : Type*} {σ : Type*} -variable [Primcodable α] [Primcodable β] [Primcodable σ] +variable {α : Type*} {β : Type*} [Primcodable α] [Primcodable β] open Computable @@ -266,9 +265,7 @@ theorem disjoin_le {α β γ} [Primcodable α] [Primcodable β] [Primcodable γ] OneOneReducible.disjoin_right.to_many_one.trans h⟩, fun ⟨h₁, h₂⟩ => disjoin_manyOneReducible h₁ h₂⟩ -variable {α : Type u} [Primcodable α] [Inhabited α] -variable {β : Type v} [Primcodable β] [Inhabited β] -variable {γ : Type w} [Primcodable γ] [Inhabited γ] +variable {α : Type u} [Primcodable α] [Inhabited α] {β : Type v} [Primcodable β] [Inhabited β] /-- Computable and injective mapping of predicates to sets of natural numbers. -/ @@ -311,9 +308,7 @@ protected theorem ind_on {C : ManyOneDegree → Prop} (d : ManyOneDegree) (h : ∀ p : Set ℕ, C (of p)) : C d := Quotient.inductionOn' d h -/-- Lifts a function on sets of natural numbers to many-one degrees. --/ --- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type +/-- Lifts a function on sets of natural numbers to many-one degrees. -/ protected abbrev liftOn {φ} (d : ManyOneDegree) (f : Set ℕ → φ) (h : ∀ p q, ManyOneEquiv p q → f p = f q) : φ := Quotient.liftOn' d f h @@ -323,12 +318,11 @@ protected theorem liftOn_eq {φ} (p : Set ℕ) (f : Set ℕ → φ) (h : ∀ p q, ManyOneEquiv p q → f p = f q) : (of p).liftOn f h = f p := rfl -/-- Lifts a binary function on sets of natural numbers to many-one degrees. --/ -@[reducible, simp] -- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type +/-- Lifts a binary function on sets of natural numbers to many-one degrees. -/ +@[reducible, simp] protected def liftOn₂ {φ} (d₁ d₂ : ManyOneDegree) (f : Set ℕ → Set ℕ → φ) (h : ∀ p₁ p₂ q₁ q₂, ManyOneEquiv p₁ p₂ → ManyOneEquiv q₁ q₂ → f p₁ q₁ = f p₂ q₂) : φ := - d₁.liftOn (fun p => d₂.liftOn (f p) fun q₁ q₂ hq => h _ _ _ _ (by rfl) hq) + d₁.liftOn (fun p => d₂.liftOn (f p) fun _ _ hq => h _ _ _ _ (by rfl) hq) (by intro p₁ p₂ hp induction d₂ using ManyOneDegree.ind_on @@ -345,7 +339,6 @@ protected theorem liftOn₂_eq {φ} (p q : Set ℕ) (f : Set ℕ → Set ℕ → @[simp] theorem of_eq_of {p : α → Prop} {q : β → Prop} : of p = of q ↔ ManyOneEquiv p q := by rw [of, of, Quotient.eq''] - unfold Setoid.r simp instance instInhabited : Inhabited ManyOneDegree := diff --git a/Mathlib/Computability/RegularExpressions.lean b/Mathlib/Computability/RegularExpressions.lean index cbcdb86be9877..7835066c73ec1 100644 --- a/Mathlib/Computability/RegularExpressions.lean +++ b/Mathlib/Computability/RegularExpressions.lean @@ -373,7 +373,7 @@ protected theorem map_pow (f : α → β) (P : RegularExpression α) : theorem map_id : ∀ P : RegularExpression α, P.map id = P | 0 => rfl | 1 => rfl - | char a => rfl + | char _ => rfl | R + S => by simp_rw [map, map_id] | comp R S => by simp_rw [map, map_id]; rfl | star R => by simp_rw [map, map_id] @@ -384,7 +384,7 @@ theorem map_id : ∀ P : RegularExpression α, P.map id = P theorem map_map (g : β → γ) (f : α → β) : ∀ P : RegularExpression α, (P.map f).map g = P.map (g ∘ f) | 0 => rfl | 1 => rfl - | char a => rfl + | char _ => rfl | R + S => by simp only [map, Function.comp_apply, map_map] | comp R S => by simp only [map, Function.comp_apply, map_map] | star R => by simp only [map, Function.comp_apply, map_map] diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 79a322e54c754..440884be0810c 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -883,7 +883,7 @@ instance Λ'.instInhabited : Inhabited Λ' := instance Λ'.instDecidableEq : DecidableEq Λ' := fun a b => by induction a generalizing b <;> cases b <;> first | apply Decidable.isFalse; rintro ⟨⟨⟩⟩; done - | exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) + | exact decidable_of_iff' _ (by simp [funext_iff]; rfl) /-- The type of TM2 statements used by this machine. -/ def Stmt' := @@ -997,30 +997,34 @@ def tr : Λ' → Stmt' cond (natEnd s.iget) (Λ'.ret k) <| Λ'.clear natEnd main <| trNormal f (Cont'.fix f k) | Λ'.ret Cont'.halt => (load fun _ => none) <| halt -/- Porting note: The equation lemma of `tr` simplifies to `match` structures. To prevent this, -we replace equation lemmas of `tr`. -/ - +@[simp] theorem tr_move (p k₁ k₂ q) : tr (Λ'.move p k₁ k₂ q) = pop' k₁ (branch (fun s => s.elim true p) (goto fun _ => q) (push' k₂ <| goto fun _ => Λ'.move p k₁ k₂ q)) := rfl +@[simp] theorem tr_push (k f q) : tr (Λ'.push k f q) = branch (fun s => (f s).isSome) ((push k fun s => (f s).iget) <| goto fun _ => q) (goto fun _ => q) := rfl +@[simp] theorem tr_read (q) : tr (Λ'.read q) = goto q := rfl +@[simp] theorem tr_clear (p k q) : tr (Λ'.clear p k q) = pop' k (branch (fun s => s.elim true p) (goto fun _ => q) (goto fun _ => Λ'.clear p k q)) := rfl +@[simp] theorem tr_copy (q) : tr (Λ'.copy q) = pop' rev (branch Option.isSome (push' main <| push' stack <| goto fun _ => Λ'.copy q) (goto fun _ => q)) := rfl +@[simp] theorem tr_succ (q) : tr (Λ'.succ q) = pop' main (branch (fun s => s = some Γ'.bit1) ((push rev fun _ => Γ'.bit0) <| goto fun _ => Λ'.succ q) <| branch (fun s => s = some Γ'.cons) ((push main fun _ => Γ'.cons) <| (push main fun _ => Γ'.bit1) <| goto fun _ => unrev q) ((push main fun _ => Γ'.bit1) <| goto fun _ => unrev q)) := rfl +@[simp] theorem tr_pred (q₁ q₂) : tr (Λ'.pred q₁ q₂) = pop' main (branch (fun s => s = some Γ'.bit0) ((push rev fun _ => Γ'.bit1) <| goto fun _ => Λ'.pred q₁ q₂) <| branch (fun s => natEnd s.iget) (goto fun _ => q₁) @@ -1028,26 +1032,26 @@ theorem tr_pred (q₁ q₂) : tr (Λ'.pred q₁ q₂) = pop' main (branch (fun s branch (fun s => natEnd s.iget) (goto fun _ => unrev q₂) ((push rev fun _ => Γ'.bit0) <| goto fun _ => unrev q₂))) := rfl +@[simp] theorem tr_ret_cons₁ (fs k) : tr (Λ'.ret (Cont'.cons₁ fs k)) = goto fun _ => move₂ (fun _ => false) main aux <| move₂ (fun s => s = Γ'.consₗ) stack main <| move₂ (fun _ => false) aux stack <| trNormal fs (Cont'.cons₂ k) := rfl +@[simp] theorem tr_ret_cons₂ (k) : tr (Λ'.ret (Cont'.cons₂ k)) = goto fun _ => head stack <| Λ'.ret k := rfl +@[simp] theorem tr_ret_comp (f k) : tr (Λ'.ret (Cont'.comp f k)) = goto fun _ => trNormal f k := rfl +@[simp] theorem tr_ret_fix (f k) : tr (Λ'.ret (Cont'.fix f k)) = pop' main (goto fun s => cond (natEnd s.iget) (Λ'.ret k) <| Λ'.clear natEnd main <| trNormal f (Cont'.fix f k)) := rfl +@[simp] theorem tr_ret_halt : tr (Λ'.ret Cont'.halt) = (load fun _ => none) halt := rfl -attribute - [eqns tr_move tr_push tr_read tr_clear tr_copy tr_succ tr_pred tr_ret_cons₁ - tr_ret_cons₂ tr_ret_comp tr_ret_fix tr_ret_halt] tr -attribute [simp] tr - /-- Translating a `Cont` continuation to a `Cont'` continuation simply entails dropping all the data. This data is instead encoded in `trContStack` in the configuration. -/ def trCont : Cont → Cont' diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index 73b365b5200ee..a75fdceac64eb 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -60,12 +60,6 @@ Given these parameters, there are a few common structures for the model that ari assert_not_exists MonoidWithZero --- After https://github.com/leanprover/lean4/pull/4400 --- the simp normal forms for `List` lookup use the `GetElem` typeclass, rather than `List.get?`. --- This file has not been updated to reflect that change, so uses a number of deprecated lemmas. --- Updating this file to allow restoring the deprecation linter would be much appreciated. -set_option linter.deprecated false - open Mathlib (Vector) open Relation @@ -178,7 +172,6 @@ instance ListBlank.hasEmptyc {Γ} [Inhabited Γ] : EmptyCollection (ListBlank Γ /-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger precondition `BlankExtends` instead of `BlankRel`. -/ --- Porting note: Removed `@[elab_as_elim]` protected abbrev ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α) (H : ∀ a b, BlankExtends a b → f a = f b) : α := l.liftOn' f <| by rintro a b (h | h) <;> [exact H _ _ h; exact (H _ _ h).symm] @@ -263,8 +256,7 @@ def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by rw [List.getI_eq_default _ h] rcases le_or_lt _ n with h₂ | h₂ · rw [List.getI_eq_default _ h₂] - rw [List.getI_eq_get _ h₂, List.get_eq_getElem, List.getElem_append_right h, - List.getElem_replicate] + rw [List.getI_eq_getElem _ h₂, List.getElem_append_right h, List.getElem_replicate] @[simp] theorem ListBlank.nth_mk {Γ} [Inhabited Γ] (l : List Γ) (n : ℕ) : @@ -291,14 +283,13 @@ theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} : intro rw [H] refine Quotient.sound' (Or.inl ⟨l₂.length - l₁.length, ?_⟩) - refine List.ext_get ?_ fun i h h₂ ↦ Eq.symm ?_ + refine List.ext_getElem ?_ fun i h h₂ ↦ Eq.symm ?_ · simp only [Nat.add_sub_cancel' h, List.length_append, List.length_replicate] simp only [ListBlank.nth_mk] at H cases' lt_or_le i l₁.length with h' h' - · simp only [List.get_append _ h', List.get?_eq_get h, List.get?_eq_get h', - ← List.getI_eq_get _ h, ← List.getI_eq_get _ h', H] - · simp only [List.get_append_right' h', List.get_replicate, List.get?_eq_get h, - List.get?_len_le h', ← List.getI_eq_default _ h', H, List.getI_eq_get _ h] + · simp [h', List.getElem_append _ h₂, ← List.getI_eq_getElem _ h, ← List.getI_eq_getElem _ h', H] + · rw [List.getElem_append_right h', List.getElem_replicate, + ← List.getI_eq_default _ h', H, List.getI_eq_getElem _ h] /-- Apply a function to a value stored at the nth position of the list. -/ @[simp] @@ -381,10 +372,9 @@ theorem ListBlank.nth_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMa refine l.inductionOn fun l ↦ ?_ -- Porting note: Added `suffices` to get `simp` to work. suffices ((mk l).map f).nth n = f ((mk l).nth n) by exact this - simp only [List.get?_map, ListBlank.map_mk, ListBlank.nth_mk, List.getI_eq_iget_get?] - cases l.get? n - · exact f.2.symm - · rfl + simp only [ListBlank.map_mk, ListBlank.nth_mk, ← List.getD_default_eq_getI] + rw [← List.getD_map _ _ f] + simp /-- The `i`-th projection as a pointed map. -/ def proj {ι : Type*} {Γ : ι → Type*} [∀ i, Inhabited (Γ i)] (i : ι) : @@ -426,10 +416,10 @@ def ListBlank.bind {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (l : ListBlank Γ) (f (hf : ∃ n, f default = List.replicate n default) : ListBlank Γ' := by apply l.liftOn (fun l ↦ ListBlank.mk (List.bind l f)) rintro l _ ⟨i, rfl⟩; cases' hf with n e; refine Quotient.sound' (Or.inl ⟨i * n, ?_⟩) - rw [List.append_bind, mul_comm]; congr + rw [List.bind_append, mul_comm]; congr induction' i with i IH · rfl - simp only [IH, e, List.replicate_add, Nat.mul_succ, add_comm, List.replicate_succ, List.cons_bind] + simp only [IH, e, List.replicate_add, Nat.mul_succ, add_comm, List.replicate_succ, List.bind_cons] @[simp] theorem ListBlank.bind_mk {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (l : List Γ) (f : Γ → List Γ') (hf) : @@ -442,7 +432,7 @@ theorem ListBlank.cons_bind {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (a : Γ) (l refine l.inductionOn fun l ↦ ?_ -- Porting note: Added `suffices` to get `simp` to work. suffices ((mk l).cons a).bind f hf = ((mk l).bind f hf).append (f a) by exact this - simp only [ListBlank.append_mk, ListBlank.bind_mk, ListBlank.cons_mk, List.cons_bind] + simp only [ListBlank.append_mk, ListBlank.bind_mk, ListBlank.cons_mk, List.bind_cons] /-- The tape of a Turing machine is composed of a head element (which we imagine to be the current position of the head), together with two `ListBlank`s denoting the portions of the tape @@ -563,9 +553,9 @@ theorem Tape.mk'_nth_nat {Γ} [Inhabited Γ] (L R : ListBlank Γ) (n : ℕ) : @[simp] theorem Tape.move_left_nth {Γ} [Inhabited Γ] : ∀ (T : Tape Γ) (i : ℤ), (T.move Dir.left).nth i = T.nth (i - 1) - | ⟨_, L, _⟩, -(n + 1 : ℕ) => (ListBlank.nth_succ _ _).symm - | ⟨_, L, _⟩, 0 => (ListBlank.nth_zero _).symm - | ⟨a, L, R⟩, 1 => (ListBlank.nth_zero _).trans (ListBlank.head_cons _ _) + | ⟨_, _, _⟩, -(_ + 1 : ℕ) => (ListBlank.nth_succ _ _).symm + | ⟨_, _, _⟩, 0 => (ListBlank.nth_zero _).symm + | ⟨_, _, _⟩, 1 => (ListBlank.nth_zero _).trans (ListBlank.head_cons _ _) | ⟨a, L, R⟩, (n + 1 : ℕ) + 1 => by rw [add_sub_cancel_right] change (R.cons a).nth (n + 1) = R.nth n @@ -851,7 +841,7 @@ def FRespects {σ₁ σ₂} (f₂ : σ₂ → Option σ₂) (tr : σ₁ → σ theorem frespects_eq {σ₁ σ₂} {f₂ : σ₂ → Option σ₂} {tr : σ₁ → σ₂} {a₂ b₂} (h : f₂ a₂ = f₂ b₂) : ∀ {b₁}, FRespects f₂ tr a₂ b₁ ↔ FRespects f₂ tr b₂ b₁ - | some b₁ => reaches₁_eq h + | some _ => reaches₁_eq h | none => by unfold FRespects; rw [h] theorem fun_respects {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂} : @@ -2102,10 +2092,10 @@ namespace TM2to1 -- A displaced lemma proved in unnecessary generality theorem stk_nth_val {K : Type*} {Γ : K → Type*} {L : ListBlank (∀ k, Option (Γ k))} {k S} (n) (hL : ListBlank.map (proj k) L = ListBlank.mk (List.map some S).reverse) : - L.nth n k = S.reverse.get? n := by - rw [← proj_map_nth, hL, ← List.map_reverse, ListBlank.nth_mk, List.getI_eq_iget_get?, - List.get?_map] - cases S.reverse.get? n <;> rfl + L.nth n k = S.reverse[n]? := by + rw [← proj_map_nth, hL, ← List.map_reverse, ListBlank.nth_mk, + List.getI_eq_iget_getElem?, List.getElem?_map] + cases S.reverse[n]? <;> rfl variable {K : Type*} variable {Γ : K → Type*} @@ -2258,9 +2248,9 @@ def trInit (k : K) (L : List (Γ k)) : List Γ'₂₁ := theorem step_run {k : K} (q : Stmt₂) (v : σ) (S : ∀ k, List (Γ k)) : ∀ s : StAct₂ k, TM2.stepAux (stRun s q) v S = TM2.stepAux q (stVar v (S k) s) (update S k (stWrite v (S k) s)) - | StAct.push f => rfl + | StAct.push _ => rfl | StAct.peek f => by unfold stWrite; rw [Function.update_eq_self]; rfl - | StAct.pop f => rfl + | StAct.pop _ => rfl end @@ -2323,10 +2313,10 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S · subst k' split_ifs with h <;> simp only [List.reverse_cons, Function.update_same, ListBlank.nth_mk, List.map] - -- Porting note: `le_refl` is required. - · rw [List.getI_eq_get, List.get_append_right'] <;> - simp only [List.length_singleton, h, List.length_reverse, List.length_map, Nat.sub_self, - Fin.zero_eta, List.get_cons_zero, le_refl, List.length_append, Nat.lt_succ_self] + · rw [List.getI_eq_getElem _, List.getElem_append_right] <;> + simp only [List.length_append, List.length_reverse, List.length_map, ← h, + Nat.sub_self, List.length_singleton, List.getElem_singleton, + le_refl, Nat.lt_succ_self] rw [← proj_map_nth, hL, ListBlank.nth_mk] cases' lt_or_gt_of_ne h with h h · rw [List.getI_append] @@ -2343,7 +2333,7 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S cases e : S k; · rfl rw [List.length_cons, iterate_succ', Function.comp, Tape.move_right_left, Tape.move_right_n_head, Tape.mk'_nth_nat, addBottom_nth_snd, stk_nth_val _ (hL k), e, - List.reverse_cons, ← List.length_reverse, List.get?_concat_length] + List.reverse_cons, ← List.length_reverse, List.getElem?_concat_length] rfl | pop f => cases' e : S k with hd tl @@ -2358,8 +2348,8 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S Tape.mk'_nth_nat, Tape.write_move_right_n fun a : Γ' ↦ (a.1, update a.2 k none), addBottom_modifyNth fun a ↦ update a k none, addBottom_nth_snd, stk_nth_val _ (hL k), e, - show (List.cons hd tl).reverse.get? tl.length = some hd by - rw [List.reverse_cons, ← List.length_reverse, List.get?_concat_length], + show (List.cons hd tl).reverse[tl.length]? = some hd by + rw [List.reverse_cons, ← List.length_reverse, List.getElem?_concat_length], List.head?, List.tail]⟩ refine ListBlank.ext fun i ↦ ?_ rw [ListBlank.nth_map, ListBlank.nth_modifyNth, proj, PointedMap.mk_val] @@ -2412,7 +2402,7 @@ theorem tr_respects_aux₁ {k} (o q v) {S : List (Γ k)} {L : ListBlank (∀ k, rw [iterate_succ_apply'] simp only [TM1.step, TM1.stepAux, tr, Tape.mk'_nth_nat, Tape.move_right_n_head, addBottom_nth_snd, Option.mem_def] - rw [stk_nth_val _ hL, List.get?_eq_get] + rw [stk_nth_val _ hL, List.getElem?_eq_getElem] · rfl · rwa [List.length_reverse] @@ -2439,8 +2429,8 @@ 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.get?_len_le (le_of_eq (List.length_reverse _)), Option.isNone, cond, - hrun, TM1.stepAux] at this + stk_nth_val _ (hT k), List.getElem?_len_le (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⟩ rw [tr, TM1.stepAux, Tape.mk'_head, addBottom_head_fst] @@ -2475,18 +2465,18 @@ theorem trCfg_init (k) (L : List (Γ k)) : TrCfg (TM2.init k L) (TM1.init (trIni rw [(_ : TM1.init _ = _)] · refine ⟨ListBlank.mk (L.reverse.map fun a ↦ update default k (some a)), fun k' ↦ ?_⟩ refine ListBlank.ext fun i ↦ ?_ - rw [ListBlank.map_mk, ListBlank.nth_mk, List.getI_eq_iget_get?, List.map_map] + rw [ListBlank.map_mk, ListBlank.nth_mk, List.getI_eq_iget_getElem?, List.map_map] have : ((proj k').f ∘ fun a => update (β := fun k => Option (Γ k)) default k (some a)) = fun a => (proj k').f (update (β := fun k => Option (Γ k)) default k (some a)) := rfl - rw [this, List.get?_map, proj, PointedMap.mk_val] + rw [this, List.getElem?_map, proj, PointedMap.mk_val] simp only [] by_cases h : k' = k · subst k' simp only [Function.update_same] - rw [ListBlank.nth_mk, List.getI_eq_iget_get?, ← List.map_reverse, List.get?_map] + rw [ListBlank.nth_mk, List.getI_eq_iget_getElem?, ← List.map_reverse, List.getElem?_map] · simp only [Function.update_noteq h] - rw [ListBlank.nth_mk, List.getI_eq_iget_get?, List.map, List.reverse_nil] - cases L.reverse.get? i <;> rfl + rw [ListBlank.nth_mk, List.getI_eq_iget_getElem?, List.map, List.reverse_nil] + cases L.reverse[i]? <;> rfl · rw [trInit, TM1.init] congr <;> cases L.reverse <;> try rfl simp only [List.map_map, List.tail_cons, List.map] diff --git a/Mathlib/Condensed/Discrete/Basic.lean b/Mathlib/Condensed/Discrete/Basic.lean index d7964352317fa..72b29ed2500c3 100644 --- a/Mathlib/Condensed/Discrete/Basic.lean +++ b/Mathlib/Condensed/Discrete/Basic.lean @@ -19,6 +19,10 @@ In `Condensed.discreteUnderlyingAdj` we prove that this functor is left adjoint functor from `Condensed C` to `C`. We also give the variant `LightCondensed.discreteUnderlyingAdj` for light condensed objects. + +The file `Mathlib.Condensed.Discrete.Characterization` defines a predicate `IsDiscrete` on +condensed and and light condensed objects, and provides several conditions on a (light) condensed +set or module that characterize it as discrete. -/ universe u v w diff --git a/Mathlib/Condensed/Discrete/Characterization.lean b/Mathlib/Condensed/Discrete/Characterization.lean new file mode 100644 index 0000000000000..04c5cbbfc2c17 --- /dev/null +++ b/Mathlib/Condensed/Discrete/Characterization.lean @@ -0,0 +1,264 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.Condensed.Discrete.Colimit +import Mathlib.Condensed.Discrete.Module +/-! + +# Characterizing discrete condensed sets and `R`-modules. + +This file proves a characterization of discrete condensed sets, discrete condensed `R`-modules over +a ring `R`, discrete light condensed sets, and discrete light condensed `R`-modules over a ring `R`. +see `CondensedSet.isDiscrete_tfae`, `CondensedMod.isDiscrete_tfae`, `LightCondSet.isDiscrete_tfae`, +and `LightCondMod.isDiscrete_tfae`. + +Informally, we can say: The following conditions characterize a condensed set `X` as discrete +(`CondensedSet.isDiscrete_tfae`): + +1. There exists a set `X'` and an isomorphism `X ≅ cst X'`, where `cst X'` denotes the constant + sheaf on `X'`. +2. The counit induces an isomorphism `cst X(*) ⟶ X`. +3. There exists a set `X'` and an isomorphism `X ≅ LocallyConstant · X'`. +4. The counit induces an isomorphism `LocallyConstant · X(*) ⟶ X`. +5. For every profinite set `S = limᵢSᵢ`, the canonical map `colimᵢX(Sᵢ) ⟶ X(S)` is an isomorphism. + +The analogues for light condensed sets, condensed `R`-modules over any ring, and light +condensed `R`-modules are nearly identical (`CondensedMod.isDiscrete_tfae`, +`LightCondSet.isDiscrete_tfae`, and `LightCondMod.isDiscrete_tfae`). +-/ + +universe u + +open CategoryTheory Limits Functor FintypeCat + +attribute [local instance] ConcreteCategory.instFunLike + +namespace Condensed + +variable {C : Type*} [Category C] [HasWeakSheafify (coherentTopology CompHaus.{u}) C] + +/-- +A condensed object is *discrete* if it is constant as a sheaf, i.e. isomorphic to a constant sheaf. +-/ +abbrev IsDiscrete (X : Condensed.{u} C) := X.IsConstant (coherentTopology CompHaus) + +end Condensed + +namespace CondensedSet + +open CompHausLike.LocallyConstant + +lemma mem_locallyContant_essImage_of_isColimit_mapCocone (X : CondensedSet.{u}) + (h : ∀ S : Profinite.{u}, IsColimit <| + (profiniteToCompHaus.op ⋙ X.val).mapCocone S.asLimitCone.op) : + X ∈ CondensedSet.LocallyConstant.functor.essImage := by + let e : CondensedSet.{u} ≌ Sheaf (coherentTopology Profinite) _ := + (Condensed.ProfiniteCompHaus.equivalence (Type (u + 1))).symm + let i : (e.functor.obj X).val ≅ (e.functor.obj (LocallyConstant.functor.obj _)).val := + Condensed.isoLocallyConstantOfIsColimit _ h + exact ⟨_, ⟨e.functor.preimageIso ((sheafToPresheaf _ _).preimageIso i.symm)⟩⟩ + +/-- +`CondensedSet.LocallyConstant.functor` is left adjoint to the forgetful functor from condensed +sets to sets. +-/ +noncomputable abbrev LocallyConstant.adjunction : + CondensedSet.LocallyConstant.functor ⊣ Condensed.underlying (Type (u+1)) := + CompHausLike.LocallyConstant.adjunction _ _ + +open Condensed + +open CondensedSet.LocallyConstant List in +theorem isDiscrete_tfae (X : CondensedSet.{u}) : + TFAE + [ X.IsDiscrete + , IsIso ((Condensed.discreteUnderlyingAdj _).counit.app X) + , X ∈ (Condensed.discrete _).essImage + , X ∈ CondensedSet.LocallyConstant.functor.essImage + , IsIso (CondensedSet.LocallyConstant.adjunction.counit.app X) + , Sheaf.IsConstant (coherentTopology Profinite) + ((Condensed.ProfiniteCompHaus.equivalence _).inverse.obj X) + , ∀ S : Profinite.{u}, Nonempty + (IsColimit <| (profiniteToCompHaus.op ⋙ X.val).mapCocone S.asLimitCone.op) + ] := by + tfae_have 1 ↔ 2 := Sheaf.isConstant_iff_isIso_counit_app _ _ _ + tfae_have 1 ↔ 3 := ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + tfae_have 1 ↔ 4 := Sheaf.isConstant_iff_mem_essImage _ CompHaus.isTerminalPUnit adjunction _ + tfae_have 1 ↔ 5 := + have : functor.Faithful := inferInstance + have : functor.Full := inferInstance + -- These `have` statements above shouldn't be needed, but they are. + Sheaf.isConstant_iff_isIso_counit_app' _ CompHaus.isTerminalPUnit adjunction _ + tfae_have 1 ↔ 6 := + (Sheaf.isConstant_iff_of_equivalence (coherentTopology Profinite) + (coherentTopology CompHaus) profiniteToCompHaus Profinite.isTerminalPUnit + CompHaus.isTerminalPUnit _).symm + tfae_have 7 → 4 := fun h ↦ + mem_locallyContant_essImage_of_isColimit_mapCocone X (fun S ↦ (h S).some) + tfae_have 4 → 7 := fun ⟨Y, ⟨i⟩⟩ S ↦ + ⟨IsColimit.mapCoconeEquiv (isoWhiskerLeft profiniteToCompHaus.op + ((sheafToPresheaf _ _).mapIso i)) + (Condensed.isColimitLocallyConstantPresheafDiagram Y S)⟩ + tfae_finish + +end CondensedSet + +namespace CondensedMod + +variable (R : Type (u+1)) [Ring R] + +lemma isDiscrete_iff_isDiscrete_forget (M : CondensedMod R) : + M.IsDiscrete ↔ ((Condensed.forget R).obj M).IsDiscrete := + Sheaf.isConstant_iff_forget (coherentTopology CompHaus) + (forget (ModuleCat R)) M CompHaus.isTerminalPUnit + +instance : HasLimitsOfSize.{u, u+1} (ModuleCat.{u+1} R) := + hasLimitsOfSizeShrink.{u, u+1, u+1, u+1} _ + +open CondensedMod.LocallyConstant List in +theorem isDiscrete_tfae (M : CondensedMod.{u} R) : + TFAE + [ M.IsDiscrete + , IsIso ((Condensed.discreteUnderlyingAdj _).counit.app M) + , M ∈ (Condensed.discrete _).essImage + , M ∈ (CondensedMod.LocallyConstant.functor R).essImage + , IsIso ((CondensedMod.LocallyConstant.adjunction R).counit.app M) + , Sheaf.IsConstant (coherentTopology Profinite) + ((Condensed.ProfiniteCompHaus.equivalence _).inverse.obj M) + , ∀ S : Profinite.{u}, Nonempty + (IsColimit <| (profiniteToCompHaus.op ⋙ M.val).mapCocone S.asLimitCone.op) + ] := by + tfae_have 1 ↔ 2 := Sheaf.isConstant_iff_isIso_counit_app _ _ _ + tfae_have 1 ↔ 3 := ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + tfae_have 1 ↔ 4 := Sheaf.isConstant_iff_mem_essImage _ CompHaus.isTerminalPUnit (adjunction R) _ + tfae_have 1 ↔ 5 := + have : (functor R).Faithful := inferInstance + have : (functor R).Full := inferInstance + -- These `have` statements above shouldn't be needed, but they are. + Sheaf.isConstant_iff_isIso_counit_app' _ CompHaus.isTerminalPUnit (adjunction R) _ + tfae_have 1 ↔ 6 := + (Sheaf.isConstant_iff_of_equivalence (coherentTopology Profinite) + (coherentTopology CompHaus) profiniteToCompHaus Profinite.isTerminalPUnit + CompHaus.isTerminalPUnit _).symm + tfae_have 7 → 1 := by + intro h + rw [isDiscrete_iff_isDiscrete_forget, ((CondensedSet.isDiscrete_tfae _).out 0 6:)] + intro S + letI : PreservesFilteredColimitsOfSize.{u, u} (forget (ModuleCat R)) := + preservesFilteredColimitsOfSizeShrink.{u, u+1, u, u+1} _ + exact ⟨isColimitOfPreserves (forget (ModuleCat R)) (h S).some⟩ + tfae_have 1 → 7 := by + intro h S + rw [isDiscrete_iff_isDiscrete_forget, ((CondensedSet.isDiscrete_tfae _).out 0 6:)] at h + letI : ReflectsFilteredColimitsOfSize.{u, u} (forget (ModuleCat R)) := + reflectsFilteredColimitsOfSizeShrink.{u, u+1, u, u+1} _ + exact ⟨isColimitOfReflects (forget (ModuleCat R)) (h S).some⟩ + tfae_finish + +end CondensedMod + +namespace LightCondensed + +variable {C : Type*} [Category C] [HasWeakSheafify (coherentTopology LightProfinite.{u}) C] + +/-- +A light condensed object is *discrete* if it is constant as a sheaf, i.e. isomorphic to a constant +sheaf. +-/ +abbrev IsDiscrete (X : LightCondensed.{u} C) := X.IsConstant (coherentTopology LightProfinite) + +end LightCondensed + +namespace LightCondSet + +lemma mem_locallyContant_essImage_of_isColimit_mapCocone (X : LightCondSet.{u}) + (h : ∀ S : LightProfinite.{u}, IsColimit <| + X.val.mapCocone (coconeRightOpOfCone S.asLimitCone)) : + X ∈ LightCondSet.LocallyConstant.functor.essImage := by + let i : X.val ≅ (LightCondSet.LocallyConstant.functor.obj _).val := + LightCondensed.isoLocallyConstantOfIsColimit _ h + exact ⟨_, ⟨((sheafToPresheaf _ _).preimageIso i.symm)⟩⟩ + +/-- +`LightCondSet.LocallyConstant.functor` is left adjoint to the forgetful functor from light condensed +sets to sets. +-/ +noncomputable abbrev LocallyConstant.adjunction : + LightCondSet.LocallyConstant.functor ⊣ LightCondensed.underlying (Type u) := + CompHausLike.LocallyConstant.adjunction _ _ + +open LightCondSet.LocallyConstant List in +theorem isDiscrete_tfae (X : LightCondSet.{u}) : + TFAE + [ X.IsDiscrete + , IsIso ((LightCondensed.discreteUnderlyingAdj _).counit.app X) + , X ∈ (LightCondensed.discrete _).essImage + , X ∈ LightCondSet.LocallyConstant.functor.essImage + , IsIso (LightCondSet.LocallyConstant.adjunction.counit.app X) + , ∀ S : LightProfinite.{u}, Nonempty + (IsColimit <| X.val.mapCocone (coconeRightOpOfCone S.asLimitCone)) + ] := by + tfae_have 1 ↔ 2 := Sheaf.isConstant_iff_isIso_counit_app _ _ _ + tfae_have 1 ↔ 3 := ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + tfae_have 1 ↔ 4 := Sheaf.isConstant_iff_mem_essImage _ LightProfinite.isTerminalPUnit adjunction X + tfae_have 1 ↔ 5 := + have : functor.Faithful := inferInstance + have : functor.Full := inferInstance + -- These `have` statements above shouldn't be needed, but they are. + Sheaf.isConstant_iff_isIso_counit_app' _ LightProfinite.isTerminalPUnit adjunction X + tfae_have 6 → 4 := fun h ↦ + mem_locallyContant_essImage_of_isColimit_mapCocone X (fun S ↦ (h S).some) + tfae_have 4 → 6 := fun ⟨Y, ⟨i⟩⟩ S ↦ + ⟨IsColimit.mapCoconeEquiv ((sheafToPresheaf _ _).mapIso i) + (LightCondensed.isColimitLocallyConstantPresheafDiagram Y S)⟩ + tfae_finish + +end LightCondSet + +namespace LightCondMod + +variable (R : Type u) [Ring R] + +lemma isDiscrete_iff_isDiscrete_forget (M : LightCondMod R) : + M.IsDiscrete ↔ ((LightCondensed.forget R).obj M).IsDiscrete := + Sheaf.isConstant_iff_forget (coherentTopology LightProfinite) + (forget (ModuleCat R)) M LightProfinite.isTerminalPUnit + +open LightCondMod.LocallyConstant List in +theorem isDiscrete_tfae (M : LightCondMod.{u} R) : + TFAE + [ M.IsDiscrete + , IsIso ((LightCondensed.discreteUnderlyingAdj _).counit.app M) + , M ∈ (LightCondensed.discrete _).essImage + , M ∈ (LightCondMod.LocallyConstant.functor R).essImage + , IsIso ((LightCondMod.LocallyConstant.adjunction R).counit.app M) + , ∀ S : LightProfinite.{u}, Nonempty + (IsColimit <| M.val.mapCocone (coconeRightOpOfCone S.asLimitCone)) + ] := by + tfae_have 1 ↔ 2 := Sheaf.isConstant_iff_isIso_counit_app _ _ _ + tfae_have 1 ↔ 3 := ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + tfae_have 1 ↔ 4 := Sheaf.isConstant_iff_mem_essImage _ + LightProfinite.isTerminalPUnit (adjunction R) _ + tfae_have 1 ↔ 5 := + have : (functor R).Faithful := inferInstance + have : (functor R).Full := inferInstance + -- These `have` statements above shouldn't be needed, but they are. + Sheaf.isConstant_iff_isIso_counit_app' _ LightProfinite.isTerminalPUnit (adjunction R) _ + tfae_have 6 → 1 := by + intro h + rw [isDiscrete_iff_isDiscrete_forget, ((LightCondSet.isDiscrete_tfae _).out 0 5:)] + intro S + letI : PreservesFilteredColimitsOfSize.{0, 0} (forget (ModuleCat R)) := + preservesFilteredColimitsOfSizeShrink.{0, u, 0, u} _ + exact ⟨isColimitOfPreserves (forget (ModuleCat R)) (h S).some⟩ + tfae_have 1 → 6 := by + intro h S + rw [isDiscrete_iff_isDiscrete_forget, ((LightCondSet.isDiscrete_tfae _).out 0 5:)] at h + letI : ReflectsFilteredColimitsOfSize.{0, 0} (forget (ModuleCat R)) := + reflectsFilteredColimitsOfSizeShrink.{0, u, 0, u} _ + exact ⟨isColimitOfReflects (forget (ModuleCat R)) (h S).some⟩ + tfae_finish + +end LightCondMod diff --git a/Mathlib/Condensed/Discrete/Colimit.lean b/Mathlib/Condensed/Discrete/Colimit.lean new file mode 100644 index 0000000000000..9e6930f3aa849 --- /dev/null +++ b/Mathlib/Condensed/Discrete/Colimit.lean @@ -0,0 +1,566 @@ +/- +Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.Condensed.Discrete.LocallyConstant +import Mathlib.Condensed.Equivalence +import Mathlib.Topology.Category.LightProfinite.Extend +/-! + +# The condensed set given by left Kan extension from `FintypeCat` to `Profinite`. + +This file provides the necessary API to prove that a condensed set `X` is discrete if and only if +for every profinite set `S = limᵢSᵢ`, `X(S) ≅ colimᵢX(Sᵢ)`, and the analogous result for light +condensed sets. +-/ + +universe u + +noncomputable section + +open CategoryTheory Functor Limits FintypeCat CompHausLike.LocallyConstant + +attribute [local instance] ConcreteCategory.instFunLike + +namespace Condensed + +section LocallyConstantAsColimit + +variable {I : Type u} [Category.{u} I] [IsCofiltered I] {F : I ⥤ FintypeCat.{u}} + (c : Cone <| F ⋙ toProfinite) (X : Type (u+1)) + +/-- The presheaf on `Profinite` of locally constant functions to `X`. -/ +abbrev locallyConstantPresheaf : Profinite.{u}ᵒᵖ ⥤ Type (u+1) := + CompHausLike.LocallyConstant.functorToPresheaves.{u, u+1}.obj X + +/-- +The functor `locallyConstantPresheaf` takes cofiltered limits of finite sets with surjective +projection maps to colimits. +-/ +noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : + IsColimit <| (locallyConstantPresheaf X).mapCocone c.op := by + refine Types.FilteredColimit.isColimitOf _ _ ?_ ?_ + · intro (f : LocallyConstant c.pt X) + obtain ⟨j, h⟩ := Profinite.exists_locallyConstant.{_, u} c hc f + exact ⟨⟨j⟩, h⟩ + · intro ⟨i⟩ ⟨j⟩ (fi : LocallyConstant _ _) (fj : LocallyConstant _ _) + (h : fi.comap (c.π.app i) = fj.comap (c.π.app j)) + obtain ⟨k, ki, kj, _⟩ := IsCofilteredOrEmpty.cone_objs i j + refine ⟨⟨k⟩, ki.op, kj.op, ?_⟩ + dsimp + ext x + obtain ⟨x, hx⟩ := ((Profinite.epi_iff_surjective (c.π.app k)).mp inferInstance) x + rw [← hx] + change fi ((c.π.app k ≫ (F ⋙ toProfinite).map _) x) = + fj ((c.π.app k ≫ (F ⋙ toProfinite).map _) x) + have h := LocallyConstant.congr_fun h x + rwa [c.w, c.w] + +@[simp] +lemma isColimitLocallyConstantPresheaf_desc_apply (hc : IsLimit c) [∀ i, Epi (c.π.app i)] + (s : Cocone ((F ⋙ toProfinite).op ⋙ locallyConstantPresheaf X)) + (i : I) (f : LocallyConstant (toProfinite.obj (F.obj i)) X) : + (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app i)) = s.ι.app ⟨i⟩ f := by + change ((((locallyConstantPresheaf X).mapCocone c.op).ι.app ⟨i⟩) ≫ + (isColimitLocallyConstantPresheaf c X hc).desc s) _ = _ + rw [(isColimitLocallyConstantPresheaf c X hc).fac] + +/-- `isColimitLocallyConstantPresheaf` in the case of `S.asLimit`. -/ +noncomputable def isColimitLocallyConstantPresheafDiagram (S : Profinite) : + IsColimit <| (locallyConstantPresheaf X).mapCocone S.asLimitCone.op := + isColimitLocallyConstantPresheaf _ _ S.asLimit + +@[simp] +lemma isColimitLocallyConstantPresheafDiagram_desc_apply (S : Profinite) + (s : Cocone (S.diagram.op ⋙ locallyConstantPresheaf X)) + (i : DiscreteQuotient S) (f : LocallyConstant (S.diagram.obj i) X) : + (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app i)) = + s.ι.app ⟨i⟩ f := + isColimitLocallyConstantPresheaf_desc_apply S.asLimitCone X S.asLimit s i f + +end LocallyConstantAsColimit + +/-- +Given a presheaf `F` on `Profinite`, `lanPresheaf F` is the left Kan extension of its +restriction to finite sets along the inclusion functor of finite sets into `Profinite`. +-/ +abbrev lanPresheaf (F : Profinite.{u}ᵒᵖ ⥤ Type (u+1)) : Profinite.{u}ᵒᵖ ⥤ Type (u+1) := + pointwiseLeftKanExtension toProfinite.op (toProfinite.op ⋙ F) + +/-- +To presheaves on `Profinite` whose restrictions to finite sets are isomorphic have isomorphic left +Kan extensions. +-/ +def lanPresheafExt {F G : Profinite.{u}ᵒᵖ ⥤ Type (u+1)} + (i : toProfinite.op ⋙ F ≅ toProfinite.op ⋙ G) : lanPresheaf F ≅ lanPresheaf G := + leftKanExtensionUniqueOfIso _ (pointwiseLeftKanExtensionUnit _ _) i _ + (pointwiseLeftKanExtensionUnit _ _) + +@[simp] +lemma lanPresheafExt_hom {F G : Profinite.{u}ᵒᵖ ⥤ Type (u+1)} (S : Profinite.{u}ᵒᵖ) + (i : toProfinite.op ⋙ F ≅ toProfinite.op ⋙ G) : (lanPresheafExt i).hom.app S = + colimMap (whiskerLeft (CostructuredArrow.proj toProfinite.op S) i.hom) := by + simp only [lanPresheaf, pointwiseLeftKanExtension_obj, lanPresheafExt, + leftKanExtensionUniqueOfIso_hom, pointwiseLeftKanExtension_desc_app] + apply colimit.hom_ext + aesop + +@[simp] +lemma lanPresheafExt_inv {F G : Profinite.{u}ᵒᵖ ⥤ Type (u+1)} (S : Profinite.{u}ᵒᵖ) + (i : toProfinite.op ⋙ F ≅ toProfinite.op ⋙ G) : (lanPresheafExt i).inv.app S = + colimMap (whiskerLeft (CostructuredArrow.proj toProfinite.op S) i.inv) := by + simp only [lanPresheaf, pointwiseLeftKanExtension_obj, lanPresheafExt, + leftKanExtensionUniqueOfIso_inv, pointwiseLeftKanExtension_desc_app] + apply colimit.hom_ext + aesop + +variable {S : Profinite.{u}} {F : Profinite.{u}ᵒᵖ ⥤ Type (u+1)} + +instance : Final <| Profinite.Extend.functorOp S.asLimitCone := + Profinite.Extend.functorOp_final S.asLimitCone S.asLimit + +/-- +A presheaf, which takes a profinite set written as a cofiltered limit to the corresponding +colimit, agrees with the left Kan extension of its restriction. +-/ +def lanPresheafIso (hF : IsColimit <| F.mapCocone S.asLimitCone.op) : + (lanPresheaf F).obj ⟨S⟩ ≅ F.obj ⟨S⟩ := + (Functor.Final.colimitIso (Profinite.Extend.functorOp S.asLimitCone) _).symm ≪≫ + (colimit.isColimit _).coconePointUniqueUpToIso hF + +@[simp] +lemma lanPresheafIso_hom (hF : IsColimit <| F.mapCocone S.asLimitCone.op) : + (lanPresheafIso hF).hom = colimit.desc _ (Profinite.Extend.cocone _ _) := by + simp [lanPresheafIso, Final.colimitIso] + rfl + +/-- `lanPresheafIso` is natural in `S`. -/ +def lanPresheafNatIso (hF : ∀ S : Profinite, IsColimit <| F.mapCocone S.asLimitCone.op) : + lanPresheaf F ≅ F := + NatIso.ofComponents (fun ⟨S⟩ ↦ (lanPresheafIso (hF S))) + fun _ ↦ (by simpa using colimit.hom_ext fun _ ↦ (by simp)) + +@[simp] +lemma lanPresheafNatIso_hom_app (hF : ∀ S : Profinite, IsColimit <| F.mapCocone S.asLimitCone.op) + (S : Profiniteᵒᵖ) : (lanPresheafNatIso hF).hom.app S = + colimit.desc _ (Profinite.Extend.cocone _ _) := by + simp [lanPresheafNatIso] + +/-- +`lanPresheaf (locallyConstantPresheaf X)` is a sheaf for the coherent topology on `Profinite`. +-/ +def lanSheafProfinite (X : Type (u+1)) : Sheaf (coherentTopology Profinite.{u}) (Type (u+1)) where + val := lanPresheaf (locallyConstantPresheaf X) + cond := by + rw [Presheaf.isSheaf_of_iso_iff (lanPresheafNatIso + fun _ ↦ isColimitLocallyConstantPresheafDiagram _ _)] + exact ((CompHausLike.LocallyConstant.functor.{u, u+1} + (hs := fun _ _ _ ↦ ((Profinite.effectiveEpi_tfae _).out 0 2).mp)).obj X).cond + +/-- `lanPresheaf (locallyConstantPresheaf X)` as a condensed set. -/ +def lanCondensedSet (X : Type (u+1)) : CondensedSet.{u} := + (ProfiniteCompHaus.equivalence _).functor.obj (lanSheafProfinite X) + +variable (F : Profinite.{u}ᵒᵖ ⥤ Type (u+1)) + +/-- +The functor which takes a finite set to the set of maps into `F(*)` for a presheaf `F` on +`Profinite`. +-/ +@[simps] +def finYoneda : FintypeCat.{u}ᵒᵖ ⥤ Type (u+1) where + obj X := X.unop → F.obj (toProfinite.op.obj ⟨of PUnit.{u+1}⟩) + map f g := g ∘ f.unop + +/-- `locallyConstantPresheaf` restricted to finite sets is isomorphic to `finYoneda F`. -/ +@[simps! hom_app] +def locallyConstantIsoFinYoneda : + toProfinite.op ⋙ (locallyConstantPresheaf (F.obj (toProfinite.op.obj ⟨of PUnit.{u+1}⟩))) ≅ + finYoneda F := + NatIso.ofComponents fun Y ↦ { + hom := fun f ↦ f.1 + inv := fun f ↦ ⟨f, @IsLocallyConstant.of_discrete _ _ _ ⟨rfl⟩ _⟩ } + +/-- A finite set as a coproduct cocone in `Profinite` over itself. -/ +def fintypeCatAsCofan (X : Profinite) : + Cofan (fun (_ : X) ↦ (Profinite.of (PUnit.{u+1}))) := + Cofan.mk X (fun x ↦ (ContinuousMap.const _ x)) + +/-- A finite set is the coproduct of its points in `Profinite`. -/ +def fintypeCatAsCofanIsColimit (X : Profinite) [Fintype X] : + IsColimit (fintypeCatAsCofan X) := by + refine mkCofanColimit _ (fun t ↦ ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ + (fun _ _ h ↦ by ext x; exact ContinuousMap.congr_fun (h x) _) + · convert continuous_bot + exact (inferInstanceAs (DiscreteTopology X)).1 + · aesop + +variable [PreservesFiniteProducts F] + +noncomputable instance (X : Profinite) [Fintype X] : + PreservesLimitsOfShape (Discrete X) F := + let X' := (Countable.toSmall.{0} X).equiv_small.choose + let e : X ≃ X' := (Countable.toSmall X).equiv_small.choose_spec.some + have : Fintype X' := Fintype.ofEquiv X e + preservesLimitsOfShapeOfEquiv (Discrete.equivalence e.symm) F + +/-- Auxiliary definition for `isoFinYoneda`. -/ +def isoFinYonedaComponents (X : Profinite.{u}) [Fintype X] : + F.obj ⟨X⟩ ≅ (X → F.obj ⟨Profinite.of PUnit.{u+1}⟩) := + (isLimitFanMkObjOfIsLimit F _ _ + (Cofan.IsColimit.op (fintypeCatAsCofanIsColimit X))).conePointUniqueUpToIso + (Types.productLimitCone.{u, u+1} fun _ ↦ F.obj ⟨Profinite.of PUnit.{u+1}⟩).2 + +lemma isoFinYonedaComponents_hom_apply (X : Profinite.{u}) [Fintype X] (y : F.obj ⟨X⟩) (x : X) : + (isoFinYonedaComponents F X).hom y x = F.map ((Profinite.of PUnit.{u+1}).const x).op y := rfl + +lemma isoFinYonedaComponents_inv_comp {X Y : Profinite.{u}} [Fintype X] [Fintype Y] + (f : Y → F.obj ⟨Profinite.of PUnit⟩) (g : X ⟶ Y) : + (isoFinYonedaComponents F X).inv (f ∘ g) = F.map g.op ((isoFinYonedaComponents F Y).inv f) := by + apply injective_of_mono (isoFinYonedaComponents F X).hom + simp only [CategoryTheory.inv_hom_id_apply] + ext x + rw [isoFinYonedaComponents_hom_apply] + simp only [← FunctorToTypes.map_comp_apply, ← op_comp, CompHausLike.const_comp, + ← isoFinYonedaComponents_hom_apply, CategoryTheory.inv_hom_id_apply, Function.comp_apply] + +/-- +The restriction of a finite product preserving presheaf `F` on `Profinite` to the category of +finite sets is isomorphic to `finYoneda F`. +-/ +@[simps!] +def isoFinYoneda : toProfinite.op ⋙ F ≅ finYoneda F := + NatIso.ofComponents (fun X ↦ isoFinYonedaComponents F (toProfinite.obj X.unop)) fun _ ↦ by + simp only [comp_obj, op_obj, finYoneda_obj, Functor.comp_map, op_map] + ext + simp only [types_comp_apply, isoFinYonedaComponents_hom_apply, finYoneda_map, + op_obj, Function.comp_apply, ← FunctorToTypes.map_comp_apply] + rfl + +/-- +A presheaf `F`, which takes a profinite set written as a cofiltered limit to the corresponding +colimit, is isomorphic to the presheaf `LocallyConstant - F(*)`. +-/ +def isoLocallyConstantOfIsColimit + (hF : ∀ S : Profinite, IsColimit <| F.mapCocone S.asLimitCone.op) : + F ≅ (locallyConstantPresheaf (F.obj (toProfinite.op.obj ⟨of PUnit.{u+1}⟩))) := + (lanPresheafNatIso hF).symm ≪≫ + lanPresheafExt (isoFinYoneda F ≪≫ (locallyConstantIsoFinYoneda F).symm) ≪≫ + lanPresheafNatIso fun _ ↦ isColimitLocallyConstantPresheafDiagram _ _ + +lemma isoLocallyConstantOfIsColimit_inv (X : Profinite.{u}ᵒᵖ ⥤ Type (u+1)) + [PreservesFiniteProducts X] + (hX : ∀ S : Profinite.{u}, (IsColimit <| X.mapCocone S.asLimitCone.op)) : + (isoLocallyConstantOfIsColimit X hX).inv = + (CompHausLike.LocallyConstant.counitApp.{u, u+1} X) := by + dsimp [isoLocallyConstantOfIsColimit] + simp only [Category.assoc] + rw [Iso.inv_comp_eq] + ext S : 2 + apply colimit.hom_ext + intro ⟨Y, _, g⟩ + simp? [locallyConstantIsoFinYoneda, isoFinYoneda, counitApp] says + simp only [comp_obj, CostructuredArrow.proj_obj, op_obj, functorToPresheaves_obj_obj, + isoFinYoneda, locallyConstantIsoFinYoneda, finYoneda_obj, LocallyConstant.toFun_eq_coe, + NatTrans.comp_app, pointwiseLeftKanExtension_obj, lanPresheafExt_inv, Iso.trans_inv, + Iso.symm_inv, whiskerLeft_comp, lanPresheafNatIso_hom_app, Opposite.op_unop, colimit.map_desc, + id_eq, Functor.comp_map, op_map, colimit.ι_desc, Cocones.precompose_obj_pt, + Profinite.Extend.cocone_pt, Cocones.precompose_obj_ι, Category.assoc, const_obj_obj, + whiskerLeft_app, NatIso.ofComponents_hom_app, NatIso.ofComponents_inv_app, + Profinite.Extend.cocone_ι_app, counitApp, colimit.ι_desc_assoc] + erw [(counitApp.{u, u+1} X).naturality] + simp only [← Category.assoc] + congr + ext f + simp only [types_comp_apply, isoFinYoneda_inv_app, counitApp_app] + apply presheaf_ext.{u, u+1} (X := X) (Y := X) (f := f) + intro x + rw [incl_of_counitAppApp] + simp only [counitAppAppImage, CompHausLike.coe_of] + letI : Fintype (fiber.{u, u+1} f x) := + Fintype.ofInjective (sigmaIncl.{u, u+1} f x).1 Subtype.val_injective + apply injective_of_mono (isoFinYonedaComponents X (fiber.{u, u+1} f x)).hom + ext y + simp only [isoFinYonedaComponents_hom_apply, ← FunctorToTypes.map_comp_apply, ← op_comp] + rw [show (Profinite.of PUnit.{u+1}).const y ≫ IsTerminal.from _ (fiber f x) = 𝟙 _ from rfl] + simp only [op_comp, FunctorToTypes.map_comp_apply, op_id, FunctorToTypes.map_id_apply] + rw [← isoFinYonedaComponents_inv_comp X _ (sigmaIncl.{u, u+1} f x)] + simpa [← isoFinYonedaComponents_hom_apply] using x.map_eq_image f y + +end Condensed + +namespace LightCondensed + +section LocallyConstantAsColimit + +variable {F : ℕᵒᵖ ⥤ FintypeCat.{u}} (c : Cone <| F ⋙ toLightProfinite) (X : Type u) + +/-- The presheaf on `LightProfinite` of locally constant functions to `X`. -/ +abbrev locallyConstantPresheaf : LightProfiniteᵒᵖ ⥤ Type u := + CompHausLike.LocallyConstant.functorToPresheaves.{u, u}.obj X + +/-- +The functor `locallyConstantPresheaf` takes sequential limits of finite sets with surjective +projection maps to colimits. +-/ +noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : + IsColimit <| (locallyConstantPresheaf X).mapCocone c.op := by + refine Types.FilteredColimit.isColimitOf _ _ ?_ ?_ + · intro (f : LocallyConstant c.pt X) + obtain ⟨j, h⟩ := Profinite.exists_locallyConstant.{_, 0} (lightToProfinite.mapCone c) + (isLimitOfPreserves lightToProfinite hc) f + exact ⟨⟨j⟩, h⟩ + · intro ⟨i⟩ ⟨j⟩ (fi : LocallyConstant _ _) (fj : LocallyConstant _ _) + (h : fi.comap (c.π.app i) = fj.comap (c.π.app j)) + obtain ⟨k, ki, kj, _⟩ := IsCofilteredOrEmpty.cone_objs i j + refine ⟨⟨k⟩, ki.op, kj.op, ?_⟩ + dsimp + ext x + obtain ⟨x, hx⟩ := ((LightProfinite.epi_iff_surjective (c.π.app k)).mp inferInstance) x + rw [← hx] + change fi ((c.π.app k ≫ (F ⋙ toLightProfinite).map _) x) = + fj ((c.π.app k ≫ (F ⋙ toLightProfinite).map _) x) + have h := LocallyConstant.congr_fun h x + rwa [c.w, c.w] + +@[simp] +lemma isColimitLocallyConstantPresheaf_desc_apply (hc : IsLimit c) [∀ i, Epi (c.π.app i)] + (s : Cocone ((F ⋙ toLightProfinite).op ⋙ locallyConstantPresheaf X)) + (n : ℕᵒᵖ) (f : LocallyConstant (toLightProfinite.obj (F.obj n)) X) : + (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app n)) = s.ι.app ⟨n⟩ f := by + change ((((locallyConstantPresheaf X).mapCocone c.op).ι.app ⟨n⟩) ≫ + (isColimitLocallyConstantPresheaf c X hc).desc s) _ = _ + rw [(isColimitLocallyConstantPresheaf c X hc).fac] + +/-- `isColimitLocallyConstantPresheaf` in the case of `S.asLimit`. -/ +noncomputable def isColimitLocallyConstantPresheafDiagram (S : LightProfinite) : + IsColimit <| (locallyConstantPresheaf X).mapCocone (coconeRightOpOfCone S.asLimitCone) := + (Functor.Final.isColimitWhiskerEquiv (opOpEquivalence ℕ).inverse _).symm + (isColimitLocallyConstantPresheaf _ _ S.asLimit) + +@[simp] +lemma isColimitLocallyConstantPresheafDiagram_desc_apply (S : LightProfinite) + (s : Cocone (S.diagram.rightOp ⋙ locallyConstantPresheaf X)) + (n : ℕ) (f : LocallyConstant (S.diagram.obj ⟨n⟩) X) : + (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app ⟨n⟩)) = + s.ι.app n f := by + change ((((locallyConstantPresheaf X).mapCocone (coconeRightOpOfCone S.asLimitCone)).ι.app n) ≫ + (isColimitLocallyConstantPresheafDiagram X S).desc s) _ = _ + rw [(isColimitLocallyConstantPresheafDiagram X S).fac] + +end LocallyConstantAsColimit + +instance (S : LightProfinite.{u}ᵒᵖ) : + HasColimitsOfShape (CostructuredArrow toLightProfinite.op S) (Type u) := + hasColimitsOfShape_of_equivalence (asEquivalence (CostructuredArrow.pre Skeleton.incl.op _ S)) + +/-- +Given a presheaf `F` on `LightProfinite`, `lanPresheaf F` is the left Kan extension of its +restriction to finite sets along the inclusion functor of finite sets into `Profinite`. +-/ +abbrev lanPresheaf (F : LightProfinite.{u}ᵒᵖ ⥤ Type u) : LightProfinite.{u}ᵒᵖ ⥤ Type u := + pointwiseLeftKanExtension toLightProfinite.op (toLightProfinite.op ⋙ F) + +/-- +To presheaves on `LightProfinite` whose restrictions to finite sets are isomorphic have isomorphic +left Kan extensions. +-/ +def lanPresheafExt {F G : LightProfinite.{u}ᵒᵖ ⥤ Type u} + (i : toLightProfinite.op ⋙ F ≅ toLightProfinite.op ⋙ G) : lanPresheaf F ≅ lanPresheaf G := + leftKanExtensionUniqueOfIso _ (pointwiseLeftKanExtensionUnit _ _) i _ + (pointwiseLeftKanExtensionUnit _ _) + +@[simp] +lemma lanPresheafExt_hom {F G : LightProfinite.{u}ᵒᵖ ⥤ Type u} (S : LightProfinite.{u}ᵒᵖ) + (i : toLightProfinite.op ⋙ F ≅ toLightProfinite.op ⋙ G) : (lanPresheafExt i).hom.app S = + colimMap (whiskerLeft (CostructuredArrow.proj toLightProfinite.op S) i.hom) := by + simp only [lanPresheaf, pointwiseLeftKanExtension_obj, lanPresheafExt, + leftKanExtensionUniqueOfIso_hom, pointwiseLeftKanExtension_desc_app] + apply colimit.hom_ext + aesop + +@[simp] +lemma lanPresheafExt_inv {F G : LightProfinite.{u}ᵒᵖ ⥤ Type u} (S : LightProfinite.{u}ᵒᵖ) + (i : toLightProfinite.op ⋙ F ≅ toLightProfinite.op ⋙ G) : (lanPresheafExt i).inv.app S = + colimMap (whiskerLeft (CostructuredArrow.proj toLightProfinite.op S) i.inv) := by + simp only [lanPresheaf, pointwiseLeftKanExtension_obj, lanPresheafExt, + leftKanExtensionUniqueOfIso_inv, pointwiseLeftKanExtension_desc_app] + apply colimit.hom_ext + aesop + +variable {S : LightProfinite.{u}} {F : LightProfinite.{u}ᵒᵖ ⥤ Type u} + +instance : Final <| LightProfinite.Extend.functorOp S.asLimitCone := + LightProfinite.Extend.functorOp_final S.asLimitCone S.asLimit + +/-- +A presheaf, which takes a light profinite set written as a sequential limit to the corresponding +colimit, agrees with the left Kan extension of its restriction. +-/ +def lanPresheafIso (hF : IsColimit <| F.mapCocone (coconeRightOpOfCone S.asLimitCone)) : + (lanPresheaf F).obj ⟨S⟩ ≅ F.obj ⟨S⟩ := + (Functor.Final.colimitIso (LightProfinite.Extend.functorOp S.asLimitCone) _).symm ≪≫ + (colimit.isColimit _).coconePointUniqueUpToIso hF + +@[simp] +lemma lanPresheafIso_hom (hF : IsColimit <| F.mapCocone (coconeRightOpOfCone S.asLimitCone)) : + (lanPresheafIso hF).hom = colimit.desc _ (LightProfinite.Extend.cocone _ _) := by + simp [lanPresheafIso, Final.colimitIso] + rfl + +/-- `lanPresheafIso` is natural in `S`. -/ +def lanPresheafNatIso + (hF : ∀ S : LightProfinite, IsColimit <| F.mapCocone (coconeRightOpOfCone S.asLimitCone)) : + lanPresheaf F ≅ F := by + refine NatIso.ofComponents + (fun ⟨S⟩ ↦ (lanPresheafIso (hF S))) fun _ ↦ ?_ + simp only [lanPresheaf, pointwiseLeftKanExtension_obj, pointwiseLeftKanExtension_map, + lanPresheafIso_hom, Opposite.op_unop] + exact colimit.hom_ext fun _ ↦ (by simp) + +@[simp] +lemma lanPresheafNatIso_hom_app + (hF : ∀ S : LightProfinite, IsColimit <| F.mapCocone (coconeRightOpOfCone S.asLimitCone)) + (S : LightProfiniteᵒᵖ) : (lanPresheafNatIso hF).hom.app S = + colimit.desc _ (LightProfinite.Extend.cocone _ _) := by + simp [lanPresheafNatIso] + +/-- +`lanPresheaf (locallyConstantPresheaf X)` as a light condensed set. +-/ +def lanLightCondSet (X : Type u) : LightCondSet.{u} where + val := lanPresheaf (locallyConstantPresheaf X) + cond := by + rw [Presheaf.isSheaf_of_iso_iff (lanPresheafNatIso + fun _ ↦ isColimitLocallyConstantPresheafDiagram _ _)] + exact (CompHausLike.LocallyConstant.functor.{u, u} + (hs := fun _ _ _ ↦ ((LightProfinite.effectiveEpi_iff_surjective _).mp)).obj X).cond + +variable (F : LightProfinite.{u}ᵒᵖ ⥤ Type u) + +/-- +The functor which takes a finite set to the set of maps into `F(*)` for a presheaf `F` on +`LightProfinite`. +-/ +@[simps] +def finYoneda : FintypeCat.{u}ᵒᵖ ⥤ Type u where + obj X := X.unop → F.obj (toLightProfinite.op.obj ⟨of PUnit.{u+1}⟩) + map f g := g ∘ f.unop + +/-- `locallyConstantPresheaf` restricted to finite sets is isomorphic to `finYoneda F`. -/ +def locallyConstantIsoFinYoneda : toLightProfinite.op ⋙ + (locallyConstantPresheaf (F.obj (toLightProfinite.op.obj ⟨of PUnit.{u+1}⟩))) ≅ finYoneda F := + NatIso.ofComponents fun Y ↦ { + hom := fun f ↦ f.1 + inv := fun f ↦ ⟨f, @IsLocallyConstant.of_discrete _ _ _ ⟨rfl⟩ _⟩ } + +/-- A finite set as a coproduct cocone in `LightProfinite` over itself. -/ +def fintypeCatAsCofan (X : LightProfinite) : + Cofan (fun (_ : X) ↦ (LightProfinite.of (PUnit.{u+1}))) := + Cofan.mk X (fun x ↦ (ContinuousMap.const _ x)) + +/-- A finite set is the coproduct of its points in `LightProfinite`. -/ +def fintypeCatAsCofanIsColimit (X : LightProfinite) [Fintype X] : + IsColimit (fintypeCatAsCofan X) := by + refine mkCofanColimit _ (fun t ↦ ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ + (fun _ _ h ↦ by ext x; exact ContinuousMap.congr_fun (h x) _) + · convert continuous_bot + exact (inferInstanceAs (DiscreteTopology X)).1 + · aesop + +variable [PreservesFiniteProducts F] + +noncomputable instance (X : FintypeCat.{u}) : PreservesLimitsOfShape (Discrete X) F := + let X' := (Countable.toSmall.{0} X).equiv_small.choose + let e : X ≃ X' := (Countable.toSmall X).equiv_small.choose_spec.some + have : Fintype X' := Fintype.ofEquiv X e + preservesLimitsOfShapeOfEquiv (Discrete.equivalence e.symm) F + +/-- Auxiliary definition for `isoFinYoneda`. -/ +def isoFinYonedaComponents (X : LightProfinite.{u}) [Fintype X] : + F.obj ⟨X⟩ ≅ (X → F.obj ⟨LightProfinite.of PUnit.{u+1}⟩) := + (isLimitFanMkObjOfIsLimit F _ _ + (Cofan.IsColimit.op (fintypeCatAsCofanIsColimit X))).conePointUniqueUpToIso + (Types.productLimitCone.{u, u} fun _ ↦ F.obj ⟨LightProfinite.of PUnit.{u+1}⟩).2 + +lemma isoFinYonedaComponents_hom_apply (X : LightProfinite.{u}) [Fintype X] (y : F.obj ⟨X⟩) + (x : X) : (isoFinYonedaComponents F X).hom y x = + F.map ((LightProfinite.of PUnit.{u+1}).const x).op y := rfl + +lemma isoFinYonedaComponents_inv_comp {X Y : LightProfinite.{u}} [Fintype X] [Fintype Y] + (f : Y → F.obj ⟨LightProfinite.of PUnit⟩) (g : X ⟶ Y) : + (isoFinYonedaComponents F X).inv (f ∘ g) = F.map g.op ((isoFinYonedaComponents F Y).inv f) := by + apply injective_of_mono (isoFinYonedaComponents F X).hom + simp only [CategoryTheory.inv_hom_id_apply] + ext x + rw [isoFinYonedaComponents_hom_apply] + simp only [← FunctorToTypes.map_comp_apply, ← op_comp, CompHausLike.const_comp, + ← isoFinYonedaComponents_hom_apply, CategoryTheory.inv_hom_id_apply, Function.comp_apply] + +/-- +The restriction of a finite product preserving presheaf `F` on `Profinite` to the category of +finite sets is isomorphic to `finYoneda F`. +-/ +@[simps!] +def isoFinYoneda : toLightProfinite.op ⋙ F ≅ finYoneda F := + NatIso.ofComponents (fun X ↦ isoFinYonedaComponents F (toLightProfinite.obj X.unop)) fun _ ↦ by + simp only [comp_obj, op_obj, finYoneda_obj, Functor.comp_map, op_map] + ext + simp only [types_comp_apply, isoFinYonedaComponents_hom_apply, finYoneda_map, op_obj, + Function.comp_apply, Types.productLimitCone, const_obj_obj, fintypeCatAsCofan, Cofan.mk_pt, + cofan_mk_inj, Fan.mk_pt, Fan.mk_π_app, ← FunctorToTypes.map_comp_apply] + rfl + +/-- +A presheaf `F`, which takes a light profinite set written as a sequential limit to the corresponding +colimit, is isomorphic to the presheaf `LocallyConstant - F(*)`. +-/ +def isoLocallyConstantOfIsColimit (hF : ∀ S : LightProfinite, IsColimit <| + F.mapCocone (coconeRightOpOfCone S.asLimitCone)) : + F ≅ (locallyConstantPresheaf + (F.obj (toLightProfinite.op.obj ⟨of PUnit.{u+1}⟩))) := + (lanPresheafNatIso hF).symm ≪≫ + lanPresheafExt (isoFinYoneda F ≪≫ (locallyConstantIsoFinYoneda F).symm) ≪≫ + lanPresheafNatIso fun _ ↦ isColimitLocallyConstantPresheafDiagram _ _ + +lemma isoLocallyConstantOfIsColimit_inv (X : LightProfinite.{u}ᵒᵖ ⥤ Type u) + [PreservesFiniteProducts X] (hX : ∀ S : LightProfinite.{u}, (IsColimit <| + X.mapCocone (coconeRightOpOfCone S.asLimitCone))) : + (isoLocallyConstantOfIsColimit X hX).inv = + (CompHausLike.LocallyConstant.counitApp.{u, u} X) := by + dsimp [isoLocallyConstantOfIsColimit] + simp only [Category.assoc] + rw [Iso.inv_comp_eq] + ext S : 2 + apply colimit.hom_ext + intro ⟨Y, _, g⟩ + simp? [locallyConstantIsoFinYoneda, isoFinYoneda, counitApp] says + simp only [comp_obj, CostructuredArrow.proj_obj, op_obj, functorToPresheaves_obj_obj, + isoFinYoneda, locallyConstantIsoFinYoneda, finYoneda_obj, LocallyConstant.toFun_eq_coe, + NatTrans.comp_app, pointwiseLeftKanExtension_obj, lanPresheafExt_inv, Iso.trans_inv, + Iso.symm_inv, whiskerLeft_comp, lanPresheafNatIso_hom_app, Opposite.op_unop, colimit.map_desc, + id_eq, Functor.comp_map, op_map, colimit.ι_desc, Cocones.precompose_obj_pt, + LightProfinite.Extend.cocone_pt, Cocones.precompose_obj_ι, Category.assoc, const_obj_obj, + whiskerLeft_app, NatIso.ofComponents_hom_app, NatIso.ofComponents_inv_app, + LightProfinite.Extend.cocone_ι_app, counitApp, colimit.ι_desc_assoc] + erw [(counitApp.{u, u} X).naturality] + simp only [← Category.assoc] + congr + ext f + simp only [types_comp_apply, isoFinYoneda_inv_app, counitApp_app] + apply presheaf_ext.{u, u} (X := X) (Y := X) (f := f) + intro x + rw [incl_of_counitAppApp] + simp only [counitAppAppImage, CompHausLike.coe_of] + letI : Fintype (fiber.{u, u} f x) := + Fintype.ofInjective (sigmaIncl.{u, u} f x).1 Subtype.val_injective + apply injective_of_mono (isoFinYonedaComponents X (fiber.{u, u} f x)).hom + ext y + simp only [isoFinYonedaComponents_hom_apply, ← FunctorToTypes.map_comp_apply, ← op_comp] + rw [show (LightProfinite.of PUnit.{u+1}).const y ≫ IsTerminal.from _ (fiber f x) = 𝟙 _ from rfl] + simp only [op_comp, FunctorToTypes.map_comp_apply, op_id, FunctorToTypes.map_id_apply] + rw [← isoFinYonedaComponents_inv_comp X _ (sigmaIncl.{u, u} f x)] + simpa [← isoFinYonedaComponents_hom_apply] using x.map_eq_image f y + +end LightCondensed diff --git a/Mathlib/Condensed/Discrete/LocallyConstant.lean b/Mathlib/Condensed/Discrete/LocallyConstant.lean index ca028c4a70293..40b0e6e7d03a9 100644 --- a/Mathlib/Condensed/Discrete/LocallyConstant.lean +++ b/Mathlib/Condensed/Discrete/LocallyConstant.lean @@ -84,7 +84,7 @@ def functorToPresheaves : Type (max u w) ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ Typ obj X := { obj := fun ⟨S⟩ ↦ LocallyConstant S X map := fun f g ↦ g.comap f.unop } - map f := { app := fun S t ↦ t.map f } + map f := { app := fun _ t ↦ t.map f } /-- Locally constant maps are the same as continuous maps when the target is equipped with the discrete @@ -291,13 +291,13 @@ The unit of the adjunciton is given by mapping each element to the corresponding -/ @[simps] def unit : 𝟭 _ ⟶ functor P hs ⋙ (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ where - app X x := LocallyConstant.const _ x + app _ x := LocallyConstant.const _ x /-- The unit of the adjunction is an iso. -/ noncomputable def unitIso : 𝟭 (Type max u w) ≅ functor.{u, w} P hs ⋙ (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ where hom := unit P hs - inv := { app := fun X f ↦ f.toFun PUnit.unit } + inv := { app := fun _ f ↦ f.toFun PUnit.unit } lemma adjunction_left_triangle [HasExplicitFiniteCoproducts.{u} P] (X : Type max u w) : functorToPresheaves.{u, w}.map ((unit P hs).app X) ≫ diff --git a/Mathlib/Condensed/Discrete/Module.lean b/Mathlib/Condensed/Discrete/Module.lean index 3bcf129729c30..5657c6d51579e 100644 --- a/Mathlib/Condensed/Discrete/Module.lean +++ b/Mathlib/Condensed/Discrete/Module.lean @@ -92,7 +92,7 @@ instance (M : ModuleCat R) : IsIso ((forget R).map ((discreteUnderlyingAdj (ModuleCat R)).counit.app ((functor R).obj M))) := by dsimp [Condensed.forget, discreteUnderlyingAdj] rw [← constantSheafAdj_counit_w] - refine @IsIso.comp_isIso _ _ _ _ _ _ _ inferInstance ?_ + refine IsIso.comp_isIso' inferInstance ?_ have : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Faithful := inferInstanceAs (discrete _).Faithful have : (constantSheaf (coherentTopology CompHaus) (Type (u + 1))).Full := @@ -205,7 +205,7 @@ instance (M : ModuleCat R) : ((functor R).obj M))) := by dsimp [LightCondensed.forget, discreteUnderlyingAdj] rw [← constantSheafAdj_counit_w] - refine @IsIso.comp_isIso _ _ _ _ _ _ _ inferInstance ?_ + refine IsIso.comp_isIso' inferInstance ?_ have : (constantSheaf (coherentTopology LightProfinite) (Type u)).Faithful := inferInstanceAs (discrete _).Faithful have : (constantSheaf (coherentTopology LightProfinite) (Type u)).Full := diff --git a/Mathlib/Condensed/Functors.lean b/Mathlib/Condensed/Functors.lean index c83e320059c0d..0fe59dc5e8866 100644 --- a/Mathlib/Condensed/Functors.lean +++ b/Mathlib/Condensed/Functors.lean @@ -20,15 +20,6 @@ sets. * `compHausToCondensed : CompHaus.{u} ⥤ CondensedSet.{u}` is essentially the yoneda presheaf functor. We also define `profiniteToCondensed` and `stoneanToCondensed`. -TODO (Dagur): - -* Define the analogues of `compHausToCondensed` for sheaves on `Profinite` and `Stonean` and provide - the relevant isomorphisms with `profiniteToCondensed` and `stoneanToCondensed`. - -* Define the functor `Type (u+1) ⥤ CondensedSet.{u}` which takes a set `X` to the presheaf given by - mapping a compact Hausdorff space `S` to `LocallyConstant S X`, along with the isomorphism with - the functor that goes through `TopCat.{u+1}`. - -/ universe u v diff --git a/Mathlib/Condensed/Light/CartesianClosed.lean b/Mathlib/Condensed/Light/CartesianClosed.lean index 99af9b717d59a..4d443905053a2 100644 --- a/Mathlib/Condensed/Light/CartesianClosed.lean +++ b/Mathlib/Condensed/Light/CartesianClosed.lean @@ -17,6 +17,4 @@ noncomputable section open CategoryTheory -variable {C : Type u} [SmallCategory C] - instance : CartesianClosed (LightCondSet.{u}) := inferInstanceAs (CartesianClosed (Sheaf _ _)) diff --git a/Mathlib/Condensed/Light/Functors.lean b/Mathlib/Condensed/Light/Functors.lean index 7d58dbe10bb93..f8996768aa631 100644 --- a/Mathlib/Condensed/Light/Functors.lean +++ b/Mathlib/Condensed/Light/Functors.lean @@ -17,12 +17,6 @@ sets. * `lightProfiniteToLightCondSet : LightProfinite.{u} ⥤ LightCondSet.{u}` is the yoneda presheaf functor. -TODO (Dagur): - -* Define the functor `Type u ⥤ LightCondSet.{u}` which takes a set `X` to the presheaf given by - mapping a light profinite space `S` to `LocallyConstant S X`, along with the isomorphism with - the functor that goes through `TopCat.{u+1}`. - -/ universe u v diff --git a/Mathlib/Condensed/Light/TopCatAdjunction.lean b/Mathlib/Condensed/Light/TopCatAdjunction.lean index 5b6ffa2fd3fa4..3be36032d682c 100644 --- a/Mathlib/Condensed/Light/TopCatAdjunction.lean +++ b/Mathlib/Condensed/Light/TopCatAdjunction.lean @@ -28,16 +28,11 @@ namespace LightCondSet variable (X : LightCondSet.{u}) -/-- Auxiliary definition to define the topology on `X(*)` for a light condensed set `X`. -/ -private def _root_.LightProfinite.const (S : LightProfinite.{u}) (s : S) : - LightProfinite.of PUnit.{u+1} ⟶ S := - ContinuousMap.const _ s - /-- Auxiliary definition to define the topology on `X(*)` for a light condensed set `X`. -/ private def coinducingCoprod : (Σ (i : (S : LightProfinite.{u}) × X.val.obj ⟨S⟩), i.fst) → X.val.obj ⟨LightProfinite.of PUnit⟩ := - fun ⟨⟨S, i⟩, s⟩ ↦ X.val.map (S.const s).op i + fun ⟨⟨_, i⟩, s⟩ ↦ X.val.map ((of PUnit.{u+1}).const s).op i /-- Let `X` be a light condensed set. We define a topology on `X(*)` as the quotient topology of all the maps from light profinite sets `S` to `X(*)`, corresponding to elements of `X(S)`. @@ -67,10 +62,8 @@ def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where apply continuous_sigma intro ⟨S, x⟩ simp only [Function.comp_apply, coinducingCoprod] - have : (fun (a : S) ↦ f.val.app ⟨LightProfinite.of PUnit⟩ (X.val.map (S.const a).op x)) = - (fun (a : S) ↦ Y.val.map (S.const a).op (f.val.app ⟨S⟩ x)) := - funext fun a ↦ NatTrans.naturality_apply f.val (S.const a).op x - rw [this] + rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ + from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] exact continuous_coinducingCoprod _ _ /-- The functor `LightCondSet ⥤ TopCat` -/ @@ -104,7 +97,7 @@ lemma topCatAdjunctionCounit_bijective (X : TopCat.{u}) : def topCatAdjunctionUnit (X : LightCondSet.{u}) : X ⟶ X.toTopCat.toLightCondSet where val := { app := fun S x ↦ { - toFun := fun s ↦ X.val.map (S.unop.const s).op x + toFun := fun s ↦ X.val.map ((of PUnit.{u+1}).const s).op x continuous_toFun := by suffices ∀ (i : (T : LightProfinite.{u}) × X.val.obj ⟨T⟩), Continuous (fun (a : i.fst) ↦ X.coinducingCoprod ⟨i, a⟩) from this ⟨_, _⟩ diff --git a/Mathlib/Condensed/TopCatAdjunction.lean b/Mathlib/Condensed/TopCatAdjunction.lean index 732a1448149d9..b29f668f98484 100644 --- a/Mathlib/Condensed/TopCatAdjunction.lean +++ b/Mathlib/Condensed/TopCatAdjunction.lean @@ -19,20 +19,16 @@ The counit is an isomorphism for compactly generated spaces, and we conclude tha universe u -open Condensed CondensedSet CategoryTheory +open Condensed CondensedSet CategoryTheory CompHaus attribute [local instance] ConcreteCategory.instFunLike variable (X : CondensedSet.{u}) -/-- Auxiliary definition to define the topology on `X(*)` for a condensed set `X`. -/ -private def _root_.CompHaus.const (S : CompHaus.{u}) (s : S) : CompHaus.of PUnit.{u+1} ⟶ S := - ContinuousMap.const _ s - /-- Auxiliary definition to define the topology on `X(*)` for a condensed set `X`. -/ private def CondensedSet.coinducingCoprod : - (Σ (i : (S : CompHaus.{u}) × X.val.obj ⟨S⟩), i.fst) → X.val.obj ⟨CompHaus.of PUnit⟩ := - fun ⟨⟨S, i⟩, s⟩ ↦ X.val.map (S.const s).op i + (Σ (i : (S : CompHaus.{u}) × X.val.obj ⟨S⟩), i.fst) → X.val.obj ⟨of PUnit⟩ := + fun ⟨⟨_, i⟩, s⟩ ↦ X.val.map ((of PUnit.{u+1}).const s).op i /-- Let `X` be a condensed set. We define a topology on `X(*)` as the quotient topology of all the maps from compact Hausdorff `S` spaces to `X(*)`, corresponding to elements of `X(S)`. @@ -41,7 +37,7 @@ local instance : TopologicalSpace (X.val.obj ⟨CompHaus.of PUnit⟩) := TopologicalSpace.coinduced (coinducingCoprod X) inferInstance /-- The object part of the functor `CondensedSet ⥤ TopCat` -/ -def CondensedSet.toTopCat : TopCat.{u+1} := TopCat.of (X.val.obj ⟨CompHaus.of PUnit⟩) +def CondensedSet.toTopCat : TopCat.{u+1} := TopCat.of (X.val.obj ⟨of PUnit⟩) namespace CondensedSet @@ -57,16 +53,14 @@ variable {X} {Y : CondensedSet} (f : X ⟶ Y) /-- The map part of the functor `CondensedSet ⥤ TopCat` -/ @[simps] def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where - toFun := f.val.app ⟨CompHaus.of PUnit⟩ + toFun := f.val.app ⟨of PUnit⟩ continuous_toFun := by rw [continuous_coinduced_dom] apply continuous_sigma intro ⟨S, x⟩ simp only [Function.comp_apply, coinducingCoprod] - have : (fun (a : S) ↦ f.val.app ⟨CompHaus.of PUnit⟩ (X.val.map (S.const a).op x)) = - (fun (a : S) ↦ Y.val.map (S.const a).op (f.val.app ⟨S⟩ x)) := - funext fun a ↦ NatTrans.naturality_apply f.val (S.const a).op x - rw [this] + rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ + from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] exact continuous_coinducingCoprod Y _ end CondensedSet @@ -105,7 +99,7 @@ lemma topCatAdjunctionCounit_bijective (X : TopCat.{u+1}) : def topCatAdjunctionUnit (X : CondensedSet.{u}) : X ⟶ X.toTopCat.toCondensedSet where val := { app := fun S x ↦ { - toFun := fun s ↦ X.val.map (S.unop.const s).op x + toFun := fun s ↦ X.val.map ((of PUnit.{u+1}).const s).op x continuous_toFun := by suffices ∀ (i : (T : CompHaus.{u}) × X.val.obj ⟨T⟩), Continuous (fun (a : i.fst) ↦ X.coinducingCoprod ⟨i, a⟩) from this ⟨_, _⟩ diff --git a/Mathlib/Condensed/TopComparison.lean b/Mathlib/Condensed/TopComparison.lean index c8679d14fddbc..d0e30e97e7708 100644 --- a/Mathlib/Condensed/TopComparison.lean +++ b/Mathlib/Condensed/TopComparison.lean @@ -31,7 +31,7 @@ variable {C : Type u} [Category.{v} C] (G : C ⥤ TopCat.{w}) (X : Type w') [TopologicalSpace X] /-- -An auxiliary lemma to that allows us to use `QuotientMap.lift` in the proof of +An auxiliary lemma to that allows us to use `IsQuotientMap.lift` in the proof of `equalizerCondition_yonedaPresheaf`. -/ theorem factorsThrough_of_pullbackCondition {Z B : C} {π : Z ⟶ B} [HasPullback π π] @@ -50,7 +50,7 @@ theorem factorsThrough_of_pullbackCondition {Z B : C} {π : Z ⟶ B} [HasPullbac have h₂ : ∀ y, G.map (pullback.snd _ _) ((PreservesPullback.iso G π π).inv y) = pullback.snd (G.map π) (G.map π) y := by simp only [← PreservesPullback.iso_inv_snd]; intro y; rfl - erw [h₁, h₂, TopCat.pullbackIsoProdSubtype_inv_fst_apply, + rw [h₁, h₂, TopCat.pullbackIsoProdSubtype_inv_fst_apply, TopCat.pullbackIsoProdSubtype_inv_snd_apply] at ha' simpa using ha' @@ -61,7 +61,7 @@ condition which is required to be a sheaf for the regular topology. -/ theorem equalizerCondition_yonedaPresheaf [∀ (Z B : C) (π : Z ⟶ B) [EffectiveEpi π], PreservesLimit (cospan π π) G] - (hq : ∀ (Z B : C) (π : Z ⟶ B) [EffectiveEpi π], QuotientMap (G.map π)) : + (hq : ∀ (Z B : C) (π : Z ⟶ B) [EffectiveEpi π], IsQuotientMap (G.map π)) : EqualizerCondition (yonedaPresheaf G X) := by apply EqualizerCondition.mk intro Z B π _ _ @@ -113,7 +113,7 @@ def TopCat.toSheafCompHausLike : apply (config := { allowSynthFailures := true }) equalizerCondition_yonedaPresheaf (CompHausLike.compHausLikeToTop.{u} P) X intro Z B π he - apply QuotientMap.of_surjective_continuous (hs _ he) π.continuous + apply IsQuotientMap.of_surjective_continuous (hs _ he) π.continuous /-- `TopCat.toSheafCompHausLike` yields a functor from `TopCat.{max u w}` to diff --git a/Mathlib/Control/EquivFunctor.lean b/Mathlib/Control/EquivFunctor.lean index ecbf36b36a8a5..6b7e9c7c574e1 100644 --- a/Mathlib/Control/EquivFunctor.lean +++ b/Mathlib/Control/EquivFunctor.lean @@ -81,7 +81,7 @@ end instance (priority := 100) ofLawfulFunctor (f : Type u₀ → Type u₁) [Functor f] [LawfulFunctor f] : EquivFunctor f where - map {α β} e := Functor.map e + map {_ _} e := Functor.map e map_refl' α := by ext apply LawfulFunctor.id_map diff --git a/Mathlib/Control/EquivFunctor/Instances.lean b/Mathlib/Control/EquivFunctor/Instances.lean index 13987af2679b9..62f3c1590452d 100644 --- a/Mathlib/Control/EquivFunctor/Instances.lean +++ b/Mathlib/Control/EquivFunctor/Instances.lean @@ -38,6 +38,6 @@ instance EquivFunctorFinset : EquivFunctor Finset where simp [h'] instance EquivFunctorFintype : EquivFunctor Fintype where - map e s := Fintype.ofBijective e e.bijective + map e _ := Fintype.ofBijective e e.bijective map_refl' α := by ext; simp [eq_iff_true_of_subsingleton] map_trans' := by simp [eq_iff_true_of_subsingleton] diff --git a/Mathlib/Control/Fold.lean b/Mathlib/Control/Fold.lean index 71a4d437faaa3..62e4e80dddadb 100644 --- a/Mathlib/Control/Fold.lean +++ b/Mathlib/Control/Fold.lean @@ -239,7 +239,6 @@ theorem foldl.unop_ofFreeMonoid (f : β → α → β) (xs : FreeMonoid α) (a : unop (Foldl.ofFreeMonoid f xs) a = List.foldl f a (FreeMonoid.toList xs) := rfl -variable (m : Type u → Type u) [Monad m] [LawfulMonad m] variable {t : Type u → Type u} [Traversable t] [LawfulTraversable t] open LawfulTraversable @@ -302,9 +301,10 @@ theorem toList_spec (xs : t α) : toList xs = FreeMonoid.toList (foldMap FreeMon calc FreeMonoid.toList (foldMap FreeMonoid.of xs) = FreeMonoid.toList (foldMap FreeMonoid.of xs).reverse.reverse := by - simp only [List.reverse_reverse] - _ = FreeMonoid.toList (List.foldr cons [] (foldMap FreeMonoid.of xs).reverse).reverse := by - simp only [List.foldr_eta] + simp only [FreeMonoid.reverse_reverse] + _ = (List.foldr cons [] (foldMap FreeMonoid.of xs).toList.reverse).reverse := by + simp only [FreeMonoid.reverse_reverse, List.foldr_reverse, List.foldl_flip_cons_eq_append, + List.append_nil, List.reverse_reverse] _ = (unop (Foldl.ofFreeMonoid (flip cons) (foldMap FreeMonoid.of xs)) []).reverse := by #adaptation_note /-- nightly-2024-03-16: simp was simp [flip, List.foldr_reverse, Foldl.ofFreeMonoid, unop_op] -/ diff --git a/Mathlib/Control/Functor/Multivariate.lean b/Mathlib/Control/Functor/Multivariate.lean index 993d066487aa9..042f138715b1f 100644 --- a/Mathlib/Control/Functor/Multivariate.lean +++ b/Mathlib/Control/Functor/Multivariate.lean @@ -36,7 +36,7 @@ variable {n : ℕ} namespace MvFunctor -variable {α β γ : TypeVec.{u} n} {F : TypeVec.{u} n → Type v} [MvFunctor F] +variable {α β : TypeVec.{u} n} {F : TypeVec.{u} n → Type v} [MvFunctor F] /-- predicate lifting over multivariate functors -/ def LiftP {α : TypeVec n} (P : ∀ i, α i → Prop) (x : F α) : Prop := @@ -157,7 +157,7 @@ private def f : { p_1 : (α ::: β) i // PredLast α pp p_1 } | _, α, Fin2.fs i, x => ⟨x.val, cast (by simp only [PredLast]; erw [const_iff_true]) x.property⟩ - | _, α, Fin2.fz, x => ⟨x.val, x.property⟩ + | _, _, Fin2.fz, x => ⟨x.val, x.property⟩ private def g : ∀ n α, @@ -165,7 +165,7 @@ private def g : { p_1 // ofRepeat (PredLast' α pp i p_1) } | _, α, Fin2.fs i, x => ⟨x.val, cast (by simp only [PredLast]; erw [const_iff_true]) x.property⟩ - | _, α, Fin2.fz, x => ⟨x.val, x.property⟩ + | _, _, Fin2.fz, x => ⟨x.val, x.property⟩ theorem LiftP_PredLast_iff {β} (P : β → Prop) (x : F (α ::: β)) : LiftP' (PredLast' _ P) x ↔ LiftP (PredLast _ P) x := by @@ -191,7 +191,7 @@ private def f' : fun i : Fin2 (n + 1) => { p_1 : (α ::: β) i × _ // RelLast α rr p_1.fst p_1.snd } | _, α, Fin2.fs i, x => ⟨x.val, cast (by simp only [RelLast]; erw [repeatEq_iff_eq]) x.property⟩ - | _, α, Fin2.fz, x => ⟨x.val, x.property⟩ + | _, _, Fin2.fz, x => ⟨x.val, x.property⟩ private def g' : ∀ n α, @@ -200,7 +200,7 @@ private def g' : { p_1 : _ × _ // ofRepeat (RelLast' α rr i (TypeVec.prod.mk _ p_1.1 p_1.2)) } | _, α, Fin2.fs i, x => ⟨x.val, cast (by simp only [RelLast]; erw [repeatEq_iff_eq]) x.property⟩ - | _, α, Fin2.fz, x => ⟨x.val, x.property⟩ + | _, _, Fin2.fz, x => ⟨x.val, x.property⟩ theorem LiftR_RelLast_iff (x y : F (α ::: β)) : LiftR' (RelLast' _ rr) x y ↔ LiftR (RelLast (i := _) _ rr) x y := by diff --git a/Mathlib/Control/Monad/Cont.lean b/Mathlib/Control/Monad/Cont.lean index 4a719782d7e74..29ed930cc7cb5 100644 --- a/Mathlib/Control/Monad/Cont.lean +++ b/Mathlib/Control/Monad/Cont.lean @@ -49,7 +49,7 @@ namespace ContT export MonadCont (Label goto) -variable {r : Type u} {m : Type u → Type v} {α β γ ω : Type w} +variable {r : Type u} {m : Type u → Type v} {α β : Type w} def run : ContT r m α → (α → m r) → m r := id diff --git a/Mathlib/Control/Monad/Writer.lean b/Mathlib/Control/Monad/Writer.lean index fcbf590189c9f..a9b71af0c73a6 100644 --- a/Mathlib/Control/Monad/Writer.lean +++ b/Mathlib/Control/Monad/Writer.lean @@ -57,7 +57,7 @@ protected def runThe (ω : Type u) (cmd : WriterT ω M α) : M (α × ω) := cmd @[ext] protected theorem ext {ω : Type u} (x x' : WriterT ω M α) (h : x.run = x'.run) : x = x' := h -variable {ω : Type u} {α β : Type u} [Monad M] +variable [Monad M] /-- Creates an instance of `Monad`, with explicitly given `empty` and `append` operations. diff --git a/Mathlib/Control/Traversable/Basic.lean b/Mathlib/Control/Traversable/Basic.lean index 52d25c007718a..20827287d137a 100644 --- a/Mathlib/Control/Traversable/Basic.lean +++ b/Mathlib/Control/Traversable/Basic.lean @@ -61,8 +61,8 @@ universe u v w section ApplicativeTransformation -variable (F : Type u → Type v) [Applicative F] [LawfulApplicative F] -variable (G : Type u → Type w) [Applicative G] [LawfulApplicative G] +variable (F : Type u → Type v) [Applicative F] +variable (G : Type u → Type w) [Applicative G] /-- A transformation between applicative functors. It is a natural transformation such that `app` preserves the `Pure.pure` and @@ -144,7 +144,7 @@ end Preserves /-- The identity applicative transformation from an applicative functor to itself. -/ def idTransformation : ApplicativeTransformation F F where - app α := id + app _ := id preserves_pure' := by simp preserves_seq' x y := by simp @@ -158,7 +158,7 @@ variable {H : Type u → Type s} [Applicative H] /-- The composition of applicative transformations. -/ def comp (η' : ApplicativeTransformation G H) (η : ApplicativeTransformation F G) : ApplicativeTransformation F H where - app α x := η' (η x) + app _ x := η' (η x) -- Porting note: something has gone wrong with `simp [functor_norm]`, -- which should suffice for the next two. preserves_pure' x := by simp only [preserves_pure] @@ -204,8 +204,7 @@ export Traversable (traverse) section Functions variable {t : Type u → Type u} -variable {m : Type u → Type v} [Applicative m] -variable {α β : Type u} +variable {α : Type u} variable {f : Type u → Type u} [Applicative f] /-- A traversable functor commutes with all applicative functors. -/ @@ -250,8 +249,6 @@ instance : LawfulTraversable Id where section -variable {F : Type u → Type v} [Applicative F] - instance : Traversable Option := ⟨Option.traverse⟩ diff --git a/Mathlib/Control/Traversable/Lemmas.lean b/Mathlib/Control/Traversable/Lemmas.lean index a819b3a2c9d79..3b10199bdc92d 100644 --- a/Mathlib/Control/Traversable/Lemmas.lean +++ b/Mathlib/Control/Traversable/Lemmas.lean @@ -39,7 +39,6 @@ variable [Applicative F] [LawfulApplicative F] variable [Applicative G] [LawfulApplicative G] variable {α β γ : Type u} variable (g : α → F β) -variable (h : β → G γ) variable (f : β → γ) /-- The natural applicative transformation from the identity functor @@ -47,7 +46,7 @@ to `F`, defined by `pure : Π {α}, α → F α`. -/ def PureTransformation : ApplicativeTransformation Id F where app := @pure F _ - preserves_pure' x := rfl + preserves_pure' _ := rfl preserves_seq' f x := by simp only [map_pure, seq_pure] rfl diff --git a/Mathlib/Control/ULiftable.lean b/Mathlib/Control/ULiftable.lean index 50eae9d2f94a5..23f4e9733b8a4 100644 --- a/Mathlib/Control/ULiftable.lean +++ b/Mathlib/Control/ULiftable.lean @@ -93,12 +93,10 @@ def downMap {F : Type max u₀ v₀ → Type u₁} {G : Type u₀ → Type v₁} [Functor F] {α β} (f : α → β) (x : F α) : G β := down (Functor.map (ULift.up.{v₀} ∘ f) x : F (ULift β)) --- @[simp] -- Porting note (#10618): simp can prove this theorem up_down {f : Type u₀ → Type u₁} {g : Type max u₀ v₀ → Type v₁} [ULiftable f g] {α} (x : g (ULift.{v₀} α)) : up (down x : f α) = x := (ULiftable.congr Equiv.ulift.symm).right_inv _ --- @[simp] -- Porting note (#10618): simp can prove this theorem down_up {f : Type u₀ → Type u₁} {g : Type max u₀ v₀ → Type v₁} [ULiftable f g] {α} (x : f α) : down (up x : g (ULift.{v₀} α)) = x := (ULiftable.congr Equiv.ulift.symm).left_inv _ diff --git a/Mathlib/Data/Analysis/Filter.lean b/Mathlib/Data/Analysis/Filter.lean index aaae456a711cd..2664265881a85 100644 --- a/Mathlib/Data/Analysis/Filter.lean +++ b/Mathlib/Data/Analysis/Filter.lean @@ -113,8 +113,8 @@ def ofFilter (f : Filter α) : f.Realizer := { f := Subtype.val pt := ⟨univ, univ_mem⟩ inf := fun ⟨_, h₁⟩ ⟨_, h₂⟩ ↦ ⟨_, inter_mem h₁ h₂⟩ - inf_le_left := fun ⟨x, _⟩ ⟨y, _⟩ ↦ inter_subset_left - inf_le_right := fun ⟨x, _⟩ ⟨y, _⟩ ↦ inter_subset_right }, + inf_le_left := fun ⟨_, _⟩ ⟨_, _⟩ ↦ inter_subset_left + inf_le_right := fun ⟨_, _⟩ ⟨_, _⟩ ↦ inter_subset_right }, filter_eq <| Set.ext fun _ ↦ by simp [exists_mem_subset_iff]⟩ /-- Transfer a filter realizer to another realizer on a different base type. -/ diff --git a/Mathlib/Data/BitVec.lean b/Mathlib/Data/BitVec.lean index e3928ba4fb51c..3fb3407a84cb6 100644 --- a/Mathlib/Data/BitVec.lean +++ b/Mathlib/Data/BitVec.lean @@ -18,7 +18,7 @@ can either be PR'd to Lean, or kept downstream if it also relies on Mathlib. namespace BitVec -variable {w v : Nat} +variable {w : Nat} /-! ## Injectivity diff --git a/Mathlib/Data/Bool/Count.lean b/Mathlib/Data/Bool/Count.lean index 197ccefd5156d..8f71b21123ee0 100644 --- a/Mathlib/Data/Bool/Count.lean +++ b/Mathlib/Data/Bool/Count.lean @@ -40,7 +40,7 @@ theorem count_true_add_count_false (l : List Bool) : count true l + count false theorem Chain.count_not : ∀ {b : Bool} {l : List Bool}, Chain (· ≠ ·) b l → count (!b) l = count b l + length l % 2 - | b, [], _h => rfl + | _, [], _h => rfl | b, x :: l, h => by obtain rfl : b = !x := Bool.eq_not_iff.2 (rel_of_chain_cons h) rw [Bool.not_not, count_cons_self, count_cons_of_ne x.not_ne_self, diff --git a/Mathlib/Data/Complex/Abs.lean b/Mathlib/Data/Complex/Abs.lean index 8ca8f1fbe0ea6..99319c9d298b3 100644 --- a/Mathlib/Data/Complex/Abs.lean +++ b/Mathlib/Data/Complex/Abs.lean @@ -117,20 +117,13 @@ theorem range_abs : range Complex.abs = Ici 0 := theorem abs_conj (z : ℂ) : Complex.abs (conj z) = Complex.abs z := AbsTheory.abs_conj z --- Porting note (#10618): @[simp] can prove it now theorem abs_prod {ι : Type*} (s : Finset ι) (f : ι → ℂ) : Complex.abs (s.prod f) = s.prod fun I => Complex.abs (f I) := map_prod Complex.abs _ _ --- @[simp] -/- Porting note (#11119): `simp` attribute removed as linter reports this can be proved -by `simp only [@map_pow]` -/ theorem abs_pow (z : ℂ) (n : ℕ) : Complex.abs (z ^ n) = Complex.abs z ^ n := map_pow Complex.abs z n --- @[simp] -/- Porting note (#11119): `simp` attribute removed as linter reports this can be proved -by `simp only [@map_zpow₀]` -/ theorem abs_zpow (z : ℂ) (n : ℤ) : Complex.abs (z ^ n) = Complex.abs z ^ n := map_zpow₀ Complex.abs z n @@ -177,11 +170,6 @@ theorem abs_abs (z : ℂ) : |Complex.abs z| = Complex.abs z := theorem abs_le_abs_re_add_abs_im (z : ℂ) : Complex.abs z ≤ |z.re| + |z.im| := by simpa [re_add_im] using Complex.abs.add_le z.re (z.im * I) --- Porting note: added so `two_pos` in the next proof works --- TODO: move somewhere else -instance : NeZero (1 : ℝ) := - ⟨by apply one_ne_zero⟩ - theorem abs_le_sqrt_two_mul_max (z : ℂ) : Complex.abs z ≤ Real.sqrt 2 * max |z.re| |z.im| := by cases' z with x y simp only [abs_apply, normSq_mk, ← sq] @@ -226,7 +214,7 @@ theorem range_normSq : range normSq = Ici 0 := local notation "abs'" => _root_.abs -theorem isCauSeq_re (f : CauSeq ℂ Complex.abs) : IsCauSeq abs' fun n => (f n).re := fun ε ε0 => +theorem isCauSeq_re (f : CauSeq ℂ Complex.abs) : IsCauSeq abs' fun n => (f n).re := fun _ ε0 => (f.cauchy ε0).imp fun i H j ij => lt_of_le_of_lt (by simpa using abs_re_le_abs (f j - f i)) (H _ ij) @@ -257,7 +245,7 @@ theorem equiv_limAux (f : CauSeq ℂ Complex.abs) : (exists_forall_ge_and (CauSeq.equiv_lim ⟨_, isCauSeq_re f⟩ _ (half_pos ε0)) (CauSeq.equiv_lim ⟨_, isCauSeq_im f⟩ _ (half_pos ε0))).imp - fun i H j ij => by + fun _ H j ij => by cases' H _ ij with H₁ H₂ apply lt_of_le_of_lt (abs_le_abs_re_add_abs_im _) dsimp [limAux] at * @@ -276,13 +264,13 @@ theorem lim_eq_lim_im_add_lim_re (f : CauSeq ℂ Complex.abs) : f ≈ _ := equiv_limAux f _ = CauSeq.const Complex.abs (↑(lim (cauSeqRe f)) + ↑(lim (cauSeqIm f)) * I) := CauSeq.ext fun _ => - Complex.ext (by simp [limAux, cauSeqRe, ofReal']) (by simp [limAux, cauSeqIm, ofReal']) + Complex.ext (by simp [limAux, cauSeqRe, ofReal]) (by simp [limAux, cauSeqIm, ofReal]) theorem lim_re (f : CauSeq ℂ Complex.abs) : lim (cauSeqRe f) = (lim f).re := by - rw [lim_eq_lim_im_add_lim_re]; simp [ofReal'] + rw [lim_eq_lim_im_add_lim_re]; simp [ofReal] theorem lim_im (f : CauSeq ℂ Complex.abs) : lim (cauSeqIm f) = (lim f).im := by - rw [lim_eq_lim_im_add_lim_re]; simp [ofReal'] + rw [lim_eq_lim_im_add_lim_re]; simp [ofReal] theorem isCauSeq_conj (f : CauSeq ℂ Complex.abs) : IsCauSeq Complex.abs fun n => conj (f n) := fun ε ε0 => diff --git a/Mathlib/Data/Complex/Basic.lean b/Mathlib/Data/Complex/Basic.lean index bc2017ba047a1..57f5d7f916a1b 100644 --- a/Mathlib/Data/Complex/Basic.lean +++ b/Mathlib/Data/Complex/Basic.lean @@ -73,13 +73,14 @@ theorem range_im : range im = univ := im_surjective.range_eq -- Porting note: refactored instance to allow `norm_cast` to work -/-- The natural inclusion of the real numbers into the complex numbers. -The name `Complex.ofReal` is reserved for the bundled homomorphism. -/ +/-- The natural inclusion of the real numbers into the complex numbers. -/ @[coe] -def ofReal' (r : ℝ) : ℂ := +def ofReal (r : ℝ) : ℂ := ⟨r, 0⟩ instance : Coe ℝ ℂ := - ⟨ofReal'⟩ + ⟨ofReal⟩ + +@[deprecated (since := "2024-10-12")] alias ofReal' := ofReal @[simp, norm_cast] theorem ofReal_re (r : ℝ) : Complex.re (r : ℂ) = r := @@ -177,7 +178,7 @@ theorem add_im (z w : ℂ) : (z + w).im = z.im + w.im := @[simp, norm_cast] theorem ofReal_add (r s : ℝ) : ((r + s : ℝ) : ℂ) = r + s := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] -- replaced by `Complex.ofReal_ofNat` @@ -194,7 +195,7 @@ theorem neg_im (z : ℂ) : (-z).im = -z.im := @[simp, norm_cast] theorem ofReal_neg (r : ℝ) : ((-r : ℝ) : ℂ) = -r := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] instance : Sub ℂ := ⟨fun z w => ⟨z.re - w.re, z.im - w.im⟩⟩ @@ -212,14 +213,14 @@ theorem mul_im (z w : ℂ) : (z * w).im = z.re * w.im + z.im * w.re := @[simp, norm_cast] theorem ofReal_mul (r s : ℝ) : ((r * s : ℝ) : ℂ) = r * s := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] -theorem re_ofReal_mul (r : ℝ) (z : ℂ) : (r * z).re = r * z.re := by simp [ofReal'] +theorem re_ofReal_mul (r : ℝ) (z : ℂ) : (r * z).re = r * z.re := by simp [ofReal] -theorem im_ofReal_mul (r : ℝ) (z : ℂ) : (r * z).im = r * z.im := by simp [ofReal'] +theorem im_ofReal_mul (r : ℝ) (z : ℂ) : (r * z).im = r * z.im := by simp [ofReal] -lemma re_mul_ofReal (z : ℂ) (r : ℝ) : (z * r).re = z.re * r := by simp [ofReal'] -lemma im_mul_ofReal (z : ℂ) (r : ℝ) : (z * r).im = z.im * r := by simp [ofReal'] +lemma re_mul_ofReal (z : ℂ) (r : ℝ) : (z * r).re = z.re * r := by simp [ofReal] +lemma im_mul_ofReal (z : ℂ) (r : ℝ) : (z * r).im = z.im * r := by simp [ofReal] theorem ofReal_mul' (r : ℝ) (z : ℂ) : ↑r * z = ⟨r * z.re, r * z.im⟩ := ext (re_ofReal_mul _ _) (im_ofReal_mul _ _) @@ -249,11 +250,11 @@ theorem I_mul (z : ℂ) : I * z = ⟨-z.im, z.re⟩ := @[simp] lemma I_ne_zero : (I : ℂ) ≠ 0 := mt (congr_arg im) zero_ne_one.symm theorem mk_eq_add_mul_I (a b : ℝ) : Complex.mk a b = a + b * I := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] @[simp] theorem re_add_im (z : ℂ) : (z.re : ℂ) + z.im * I = z := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] theorem mul_I_re (z : ℂ) : (z * I).re = -z.im := by simp @@ -265,7 +266,7 @@ theorem I_mul_im (z : ℂ) : (I * z).im = z.re := by simp @[simp] theorem equivRealProd_symm_apply (p : ℝ × ℝ) : equivRealProd.symm p = p.1 + p.2 * I := by - ext <;> simp [Complex.equivRealProd, ofReal'] + ext <;> simp [Complex.equivRealProd, ofReal] /-- The natural `AddEquiv` from `ℂ` to `ℝ × ℝ`. -/ @[simps! (config := { simpRhs := true }) apply symm_apply_re symm_apply_im] @@ -329,8 +330,7 @@ instance addCommGroup : AddCommGroup ℂ := intros; ext <;> simp [AddMonoid.nsmul_succ, add_mul, add_comm, smul_re, smul_im] zsmul_succ' := by - intros; ext <;> simp [SubNegMonoid.zsmul_succ', add_mul, add_comm, - smul_re, smul_im] + intros; ext <;> simp [add_mul, smul_re, smul_im] zsmul_neg' := by intros; ext <;> simp [zsmul_neg', add_mul, smul_re, smul_im] add_assoc := by intros; ext <;> simp [add_assoc] @@ -415,16 +415,16 @@ end /-! ### Cast lemmas -/ -noncomputable instance instNNRatCast : NNRatCast ℂ where nnratCast q := ofReal' q -noncomputable instance instRatCast : RatCast ℂ where ratCast q := ofReal' q +noncomputable instance instNNRatCast : NNRatCast ℂ where nnratCast q := ofReal q +noncomputable instance instRatCast : RatCast ℂ where ratCast q := ofReal q -- See note [no_index around OfNat.ofNat] @[simp, norm_cast] lemma ofReal_ofNat (n : ℕ) [n.AtLeastTwo] : - ofReal' (no_index (OfNat.ofNat n)) = OfNat.ofNat n := rfl -@[simp, norm_cast] lemma ofReal_natCast (n : ℕ) : ofReal' n = n := rfl -@[simp, norm_cast] lemma ofReal_intCast (n : ℤ) : ofReal' n = n := rfl -@[simp, norm_cast] lemma ofReal_nnratCast (q : ℚ≥0) : ofReal' q = q := rfl -@[simp, norm_cast] lemma ofReal_ratCast (q : ℚ) : ofReal' q = q := rfl + ofReal (no_index (OfNat.ofNat n)) = OfNat.ofNat n := rfl +@[simp, norm_cast] lemma ofReal_natCast (n : ℕ) : ofReal n = n := rfl +@[simp, norm_cast] lemma ofReal_intCast (n : ℤ) : ofReal n = n := rfl +@[simp, norm_cast] lemma ofReal_nnratCast (q : ℚ≥0) : ofReal q = q := rfl +@[simp, norm_cast] lemma ofReal_ratCast (q : ℚ) : ofReal q = q := rfl @[deprecated (since := "2024-04-17")] alias ofReal_rat_cast := ofReal_ratCast @@ -506,7 +506,7 @@ theorem conj_eq_iff_real {z : ℂ} : conj z = z ↔ ∃ r : ℝ, z = r := rw [e, conj_ofReal]⟩ theorem conj_eq_iff_re {z : ℂ} : conj z = z ↔ (z.re : ℂ) = z := - conj_eq_iff_real.trans ⟨by rintro ⟨r, rfl⟩; simp [ofReal'], fun h => ⟨_, h.symm⟩⟩ + conj_eq_iff_real.trans ⟨by rintro ⟨r, rfl⟩; simp [ofReal], fun h => ⟨_, h.symm⟩⟩ theorem conj_eq_iff_im {z : ℂ} : conj z = z ↔ z.im = 0 := ⟨fun h => add_self_eq_zero.mp (neg_eq_iff_add_eq_zero.mp (congr_arg im h)), fun h => @@ -537,7 +537,7 @@ theorem normSq_apply (z : ℂ) : normSq z = z.re * z.re + z.im * z.im := @[simp] theorem normSq_ofReal (r : ℝ) : normSq r = r * r := by - simp [normSq, ofReal'] + simp [normSq, ofReal] @[simp] theorem normSq_natCast (n : ℕ) : normSq n = n * n := normSq_ofReal _ @@ -571,7 +571,7 @@ theorem normSq_add_mul_I (x y : ℝ) : normSq (x + y * I) = x ^ 2 + y ^ 2 := by rw [← mk_eq_add_mul_I, normSq_mk, sq, sq] theorem normSq_eq_conj_mul_self {z : ℂ} : (normSq z : ℂ) = conj z * z := by - ext <;> simp [normSq, mul_comm, ofReal'] + ext <;> simp [normSq, mul_comm, ofReal] -- @[simp] /- Porting note (#11119): `simp` attribute removed as linter reports this can be proved @@ -620,44 +620,43 @@ theorem im_sq_le_normSq (z : ℂ) : z.im * z.im ≤ normSq z := le_add_of_nonneg_left (mul_self_nonneg _) theorem mul_conj (z : ℂ) : z * conj z = normSq z := - Complex.ext_iff.2 <| by simp [normSq, mul_comm, sub_eq_neg_add, add_comm, ofReal'] + Complex.ext_iff.2 <| by simp [normSq, mul_comm, sub_eq_neg_add, add_comm, ofReal] theorem add_conj (z : ℂ) : z + conj z = (2 * z.re : ℝ) := - Complex.ext_iff.2 <| by simp [two_mul, ofReal'] + Complex.ext_iff.2 <| by simp [two_mul, ofReal] /-- The coercion `ℝ → ℂ` as a `RingHom`. -/ -def ofReal : ℝ →+* ℂ where +def ofRealHom : ℝ →+* ℂ where toFun x := (x : ℂ) map_one' := ofReal_one map_zero' := ofReal_zero map_mul' := ofReal_mul map_add' := ofReal_add -@[simp] -theorem ofReal_eq_coe (r : ℝ) : ofReal r = r := - rfl +@[simp] lemma ofRealHom_eq_coe (r : ℝ) : ofRealHom r = r := rfl variable {α : Type*} -@[simp] lemma ofReal_comp_add (f g : α → ℝ) : ofReal' ∘ (f + g) = ofReal' ∘ f + ofReal' ∘ g := - map_comp_add ofReal .. +@[simp] lemma ofReal_comp_add (f g : α → ℝ) : ofReal ∘ (f + g) = ofReal ∘ f + ofReal ∘ g := + map_comp_add ofRealHom .. -@[simp] lemma ofReal_comp_sub (f g : α → ℝ) : ofReal' ∘ (f - g) = ofReal' ∘ f - ofReal' ∘ g := - map_comp_sub ofReal .. +@[simp] lemma ofReal_comp_sub (f g : α → ℝ) : ofReal ∘ (f - g) = ofReal ∘ f - ofReal ∘ g := + map_comp_sub ofRealHom .. -@[simp] lemma ofReal_comp_neg (f : α → ℝ) : ofReal' ∘ (-f) = -(ofReal' ∘ f) := map_comp_neg ofReal _ +@[simp] lemma ofReal_comp_neg (f : α → ℝ) : ofReal ∘ (-f) = -(ofReal ∘ f) := + map_comp_neg ofRealHom _ -lemma ofReal_comp_nsmul (n : ℕ) (f : α → ℝ) : ofReal' ∘ (n • f) = n • (ofReal' ∘ f) := - map_comp_nsmul ofReal .. +lemma ofReal_comp_nsmul (n : ℕ) (f : α → ℝ) : ofReal ∘ (n • f) = n • (ofReal ∘ f) := + map_comp_nsmul ofRealHom .. -lemma ofReal_comp_zsmul (n : ℤ) (f : α → ℝ) : ofReal' ∘ (n • f) = n • (ofReal' ∘ f) := - map_comp_zsmul ofReal .. +lemma ofReal_comp_zsmul (n : ℤ) (f : α → ℝ) : ofReal ∘ (n • f) = n • (ofReal ∘ f) := + map_comp_zsmul ofRealHom .. -@[simp] lemma ofReal_comp_mul (f g : α → ℝ) : ofReal' ∘ (f * g) = ofReal' ∘ f * ofReal' ∘ g := - map_comp_mul ofReal .. +@[simp] lemma ofReal_comp_mul (f g : α → ℝ) : ofReal ∘ (f * g) = ofReal ∘ f * ofReal ∘ g := + map_comp_mul ofRealHom .. -@[simp] lemma ofReal_comp_pow (f : α → ℝ) (n : ℕ) : ofReal' ∘ (f ^ n) = (ofReal' ∘ f) ^ n := - map_comp_pow ofReal .. +@[simp] lemma ofReal_comp_pow (f : α → ℝ) (n : ℕ) : ofReal ∘ (f ^ n) = (ofReal ∘ f) ^ n := + map_comp_pow ofRealHom .. @[simp] theorem I_sq : I ^ 2 = -1 := by rw [sq, I_mul_I] @@ -675,14 +674,14 @@ theorem sub_im (z w : ℂ) : (z - w).im = z.im - w.im := @[simp, norm_cast] theorem ofReal_sub (r s : ℝ) : ((r - s : ℝ) : ℂ) = r - s := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] @[simp, norm_cast] theorem ofReal_pow (r : ℝ) (n : ℕ) : ((r ^ n : ℝ) : ℂ) = (r : ℂ) ^ n := by induction n <;> simp [*, ofReal_mul, pow_succ] theorem sub_conj (z : ℂ) : z - conj z = (2 * z.im : ℝ) * I := - Complex.ext_iff.2 <| by simp [two_mul, sub_eq_add_neg, ofReal'] + Complex.ext_iff.2 <| by simp [two_mul, sub_eq_add_neg, ofReal] theorem normSq_sub (z w : ℂ) : normSq (z - w) = normSq z + normSq w - 2 * (z * conj w).re := by rw [sub_eq_add_neg, normSq_add] @@ -699,14 +698,14 @@ theorem inv_def (z : ℂ) : z⁻¹ = conj z * ((normSq z)⁻¹ : ℝ) := rfl @[simp] -theorem inv_re (z : ℂ) : z⁻¹.re = z.re / normSq z := by simp [inv_def, division_def, ofReal'] +theorem inv_re (z : ℂ) : z⁻¹.re = z.re / normSq z := by simp [inv_def, division_def, ofReal] @[simp] -theorem inv_im (z : ℂ) : z⁻¹.im = -z.im / normSq z := by simp [inv_def, division_def, ofReal'] +theorem inv_im (z : ℂ) : z⁻¹.im = -z.im / normSq z := by simp [inv_def, division_def, ofReal] @[simp, norm_cast] theorem ofReal_inv (r : ℝ) : ((r⁻¹ : ℝ) : ℂ) = (r : ℂ)⁻¹ := - Complex.ext_iff.2 <| by simp [ofReal'] + Complex.ext_iff.2 <| by simp [ofReal] protected theorem inv_zero : (0⁻¹ : ℂ) = 0 := by rw [← ofReal_zero, ← ofReal_inv, inv_zero] @@ -736,21 +735,19 @@ noncomputable instance instField : Field ℂ where qsmul_def n z := Complex.ext_iff.2 <| by simp [Rat.smul_def, smul_re, smul_im] @[simp, norm_cast] -lemma ofReal_nnqsmul (q : ℚ≥0) (r : ℝ) : ofReal' (q • r) = q • r := by simp [NNRat.smul_def] +lemma ofReal_nnqsmul (q : ℚ≥0) (r : ℝ) : ofReal (q • r) = q • r := by simp [NNRat.smul_def] @[simp, norm_cast] -lemma ofReal_qsmul (q : ℚ) (r : ℝ) : ofReal' (q • r) = q • r := by simp [Rat.smul_def] +lemma ofReal_qsmul (q : ℚ) (r : ℝ) : ofReal (q • r) = q • r := by simp [Rat.smul_def] theorem conj_inv (x : ℂ) : conj x⁻¹ = (conj x)⁻¹ := star_inv' _ @[simp, norm_cast] -theorem ofReal_div (r s : ℝ) : ((r / s : ℝ) : ℂ) = r / s := - map_div₀ ofReal r s +theorem ofReal_div (r s : ℝ) : ((r / s : ℝ) : ℂ) = r / s := map_div₀ ofRealHom r s @[simp, norm_cast] -theorem ofReal_zpow (r : ℝ) (n : ℤ) : ((r ^ n : ℝ) : ℂ) = (r : ℂ) ^ n := - map_zpow₀ ofReal r n +theorem ofReal_zpow (r : ℝ) (n : ℤ) : ((r ^ n : ℝ) : ℂ) = (r : ℂ) ^ n := map_zpow₀ ofRealHom r n @[simp] theorem div_I (z : ℂ) : z / I = -(z * I) := diff --git a/Mathlib/Data/Complex/BigOperators.lean b/Mathlib/Data/Complex/BigOperators.lean index df65eec1fe310..02af83a94a767 100644 --- a/Mathlib/Data/Complex/BigOperators.lean +++ b/Mathlib/Data/Complex/BigOperators.lean @@ -19,15 +19,15 @@ variable {α : Type*} (s : Finset α) @[simp, norm_cast] theorem ofReal_prod (f : α → ℝ) : ((∏ i ∈ s, f i : ℝ) : ℂ) = ∏ i ∈ s, (f i : ℂ) := - map_prod ofReal _ _ + map_prod ofRealHom _ _ @[simp, norm_cast] theorem ofReal_sum (f : α → ℝ) : ((∑ i ∈ s, f i : ℝ) : ℂ) = ∑ i ∈ s, (f i : ℂ) := - map_sum ofReal _ _ + map_sum ofRealHom _ _ @[simp, norm_cast] lemma ofReal_expect (f : α → ℝ) : (𝔼 i ∈ s, f i : ℝ) = 𝔼 i ∈ s, (f i : ℂ) := - map_expect ofReal .. + map_expect ofRealHom .. @[simp, norm_cast] lemma ofReal_balance [Fintype α] (f : α → ℝ) (a : α) : diff --git a/Mathlib/Data/Complex/Cardinality.lean b/Mathlib/Data/Complex/Cardinality.lean index 342a61f0f8696..cb34948f1f671 100644 --- a/Mathlib/Data/Complex/Cardinality.lean +++ b/Mathlib/Data/Complex/Cardinality.lean @@ -24,7 +24,6 @@ theorem mk_complex : #ℂ = 𝔠 := by rw [mk_congr Complex.equivRealProd, mk_prod, lift_id, mk_real, continuum_mul_self] /-- The cardinality of the complex numbers, as a set. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem mk_univ_complex : #(Set.univ : Set ℂ) = 𝔠 := by rw [mk_univ, mk_complex] /-- The complex numbers are not countable. -/ diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index d6a37e2bade95..e5502836c9e2e 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -1061,10 +1061,9 @@ end Real namespace Complex theorem sum_div_factorial_le {α : Type*} [LinearOrderedField α] (n j : ℕ) (hn : 0 < n) : - (∑ m ∈ filter (fun k => n ≤ k) (range j), - (1 / m.factorial : α)) ≤ n.succ / (n.factorial * n) := + (∑ m ∈ range j with n ≤ m, (1 / m.factorial : α)) ≤ n.succ / (n.factorial * n) := calc - (∑ m ∈ filter (fun k => n ≤ k) (range j), (1 / m.factorial : α)) = + (∑ m ∈ range j with n ≤ m, (1 / m.factorial : α)) = ∑ m ∈ range (j - n), (1 / ((m + n).factorial : α)) := by refine sum_nbij' (· - n) (· + n) ?_ ?_ ?_ ?_ ?_ <;> simp (config := { contextual := true }) [lt_tsub_iff_right, tsub_add_cancel_of_le] @@ -1098,20 +1097,19 @@ theorem exp_bound {x : ℂ} (hx : abs x ≤ 1) {n : ℕ} (hn : 0 < n) : abs x ^ n * ((n.succ : ℝ) * (n.factorial * n : ℝ)⁻¹) rw [sum_range_sub_sum_range hj] calc - abs (∑ m ∈ (range j).filter fun k => n ≤ k, (x ^ m / m.factorial : ℂ)) = - abs (∑ m ∈ (range j).filter fun k => n ≤ k, - (x ^ n * (x ^ (m - n) / m.factorial) : ℂ)) := by + abs (∑ m ∈ range j with n ≤ m, (x ^ m / m.factorial : ℂ)) + = abs (∑ m ∈ range j with n ≤ m, (x ^ n * (x ^ (m - n) / m.factorial) : ℂ)) := by refine congr_arg abs (sum_congr rfl fun m hm => ?_) rw [mem_filter, mem_range] at hm rw [← mul_div_assoc, ← pow_add, add_tsub_cancel_of_le hm.2] - _ ≤ ∑ m ∈ filter (fun k => n ≤ k) (range j), abs (x ^ n * (x ^ (m - n) / m.factorial)) := - (IsAbsoluteValue.abv_sum Complex.abs _ _) - _ ≤ ∑ m ∈ filter (fun k => n ≤ k) (range j), abs x ^ n * (1 / m.factorial) := by + _ ≤ ∑ m ∈ range j with n ≤ m, abs (x ^ n * (x ^ (m - n) / m.factorial)) := + IsAbsoluteValue.abv_sum Complex.abs .. + _ ≤ ∑ m ∈ range j with n ≤ m, abs x ^ n * (1 / m.factorial) := by simp_rw [map_mul, map_pow, map_div₀, abs_natCast] gcongr rw [abv_pow abs] exact pow_le_one₀ (abs.nonneg _) hx - _ = abs x ^ n * ∑ m ∈ (range j).filter fun k => n ≤ k, (1 / m.factorial : ℝ) := by + _ = abs x ^ n * ∑ m ∈ range j with n ≤ m, (1 / m.factorial : ℝ) := by simp [abs_mul, abv_pow abs, abs_div, ← mul_sum] _ ≤ abs x ^ n * (n.succ * (n.factorial * n : ℝ)⁻¹) := by gcongr @@ -1395,7 +1393,8 @@ theorem exp_bound_div_one_sub_of_interval' {x : ℝ} (h1 : 0 < x) (h2 : x < 1) : -- Porting note: was `norm_num [Finset.sum] <;> nlinarith` -- This proof should be restored after the norm_num plugin for big operators is ported. -- (It may also need the positivity extensions in #3907.) - repeat erw [Finset.sum_range_succ] + erw [Finset.sum_range_succ] + repeat rw [Finset.sum_range_succ] norm_num [Nat.factorial] nlinarith _ < 1 / (1 - x) := by rw [lt_div_iff₀] <;> nlinarith @@ -1412,7 +1411,7 @@ theorem add_one_lt_exp {x : ℝ} (hx : x ≠ 0) : x + 1 < Real.exp x := by obtain h' | h' := le_or_lt 1 (-x) · linarith [x.exp_pos] have hx' : 0 < x + 1 := by linarith - simpa [add_comm, exp_neg, inv_lt_inv (exp_pos _) hx'] + simpa [add_comm, exp_neg, inv_lt_inv₀ (exp_pos _) hx'] using exp_bound_div_one_sub_of_interval' (neg_pos.2 hx) h' theorem add_one_le_exp (x : ℝ) : x + 1 ≤ Real.exp x := by diff --git a/Mathlib/Data/Complex/ExponentialBounds.lean b/Mathlib/Data/Complex/ExponentialBounds.lean index cb4022b3c3fe8..9531022b50196 100644 --- a/Mathlib/Data/Complex/ExponentialBounds.lean +++ b/Mathlib/Data/Complex/ExponentialBounds.lean @@ -36,16 +36,14 @@ theorem exp_one_lt_d9 : exp 1 < 2.7182818286 := lt_of_le_of_lt (sub_le_iff_le_add.1 (abs_sub_le_iff.1 exp_one_near_10).1) (by norm_num) theorem exp_neg_one_gt_d9 : 0.36787944116 < exp (-1) := by - rw [exp_neg, lt_inv _ (exp_pos _)] + rw [exp_neg, lt_inv_comm₀ _ (exp_pos _)] · refine lt_of_le_of_lt (sub_le_iff_le_add.1 (abs_sub_le_iff.1 exp_one_near_10).1) ?_ norm_num · norm_num theorem exp_neg_one_lt_d9 : exp (-1) < 0.3678794412 := by - rw [exp_neg, inv_lt (exp_pos _)] - · refine lt_of_lt_of_le ?_ (sub_le_comm.1 (abs_sub_le_iff.1 exp_one_near_10).2) - norm_num - · norm_num + rw [exp_neg, inv_lt_comm₀ (exp_pos _) (by norm_num)] + exact lt_of_lt_of_le (by norm_num) (sub_le_comm.1 (abs_sub_le_iff.1 exp_one_near_10).2) theorem log_two_near_10 : |log 2 - 287209 / 414355| ≤ 1 / 10 ^ 10 := by suffices |log 2 - 287209 / 414355| ≤ 1 / 17179869184 + (1 / 10 ^ 10 - 1 / 2 ^ 34) by diff --git a/Mathlib/Data/Complex/Module.lean b/Mathlib/Data/Complex/Module.lean index e8fc5c5c392dc..219999ee957ae 100644 --- a/Mathlib/Data/Complex/Module.lean +++ b/Mathlib/Data/Complex/Module.lean @@ -93,7 +93,7 @@ instance (priority := 100) instModule [Semiring R] [Module R ℝ] : Module R ℂ -- priority manually adjusted in #11980 instance (priority := 95) instAlgebraOfReal [CommSemiring R] [Algebra R ℝ] : Algebra R ℂ := - { Complex.ofReal.comp (algebraMap R ℝ) with + { Complex.ofRealHom.comp (algebraMap R ℝ) with smul := (· • ·) smul_def' := fun r x => by ext <;> simp [smul_re, smul_im, Algebra.smul_def] commutes' := fun r ⟨xr, xi⟩ => by ext <;> simp [smul_re, smul_im, Algebra.commutes] } @@ -313,7 +313,7 @@ def lift : { I' : A // I' * I' = -1 } ≃ (ℂ →ₐ[ℝ] A) where toFun I' := liftAux I' I'.prop invFun F := ⟨F I, by rw [← map_mul, I_mul_I, map_neg, map_one]⟩ left_inv I' := Subtype.ext <| liftAux_apply_I (I' : A) I'.prop - right_inv F := algHom_ext <| liftAux_apply_I _ _ + right_inv _ := algHom_ext <| liftAux_apply_I _ _ -- When applied to `Complex.I` itself, `lift` is the identity. @[simp] @@ -479,7 +479,7 @@ def Complex.selfAdjointEquiv : selfAdjoint ℂ ≃ₗ[ℝ] ℝ where toFun := fun z ↦ (z : ℂ).re invFun := fun x ↦ ⟨x, conj_ofReal x⟩ left_inv := fun z ↦ Subtype.ext <| conj_eq_iff_re.mp z.property.star_eq - right_inv := fun x ↦ rfl + right_inv := fun _ ↦ rfl map_add' := by simp map_smul' := by simp diff --git a/Mathlib/Data/Complex/Order.lean b/Mathlib/Data/Complex/Order.lean index a9bc019f2b0bf..9e641fe376939 100644 --- a/Mathlib/Data/Complex/Order.lean +++ b/Mathlib/Data/Complex/Order.lean @@ -38,9 +38,9 @@ protected def partialOrder : PartialOrder ℂ where dsimp rw [lt_iff_le_not_le] tauto - le_refl x := ⟨le_rfl, rfl⟩ - le_trans x y z h₁ h₂ := ⟨h₁.1.trans h₂.1, h₁.2.trans h₂.2⟩ - le_antisymm z w h₁ h₂ := ext (h₁.1.antisymm h₂.1) h₁.2 + le_refl _ := ⟨le_rfl, rfl⟩ + le_trans _ _ _ h₁ h₂ := ⟨h₁.1.trans h₂.1, h₁.2.trans h₂.2⟩ + le_antisymm _ _ h₁ h₂ := ext (h₁.1.antisymm h₂.1) h₁.2 namespace _root_.ComplexOrder @@ -63,11 +63,17 @@ theorem nonneg_iff {z : ℂ} : 0 ≤ z ↔ 0 ≤ z.re ∧ 0 = z.im := theorem pos_iff {z : ℂ} : 0 < z ↔ 0 < z.re ∧ 0 = z.im := lt_def +theorem nonpos_iff {z : ℂ} : z ≤ 0 ↔ z.re ≤ 0 ∧ z.im = 0 := + le_def + +theorem neg_iff {z : ℂ} : z < 0 ↔ z.re < 0 ∧ z.im = 0 := + lt_def + @[simp, norm_cast] -theorem real_le_real {x y : ℝ} : (x : ℂ) ≤ (y : ℂ) ↔ x ≤ y := by simp [le_def, ofReal'] +theorem real_le_real {x y : ℝ} : (x : ℂ) ≤ (y : ℂ) ↔ x ≤ y := by simp [le_def, ofReal] @[simp, norm_cast] -theorem real_lt_real {x y : ℝ} : (x : ℂ) < (y : ℂ) ↔ x < y := by simp [lt_def, ofReal'] +theorem real_lt_real {x y : ℝ} : (x : ℂ) < (y : ℂ) ↔ x < y := by simp [lt_def, ofReal] @[simp, norm_cast] theorem zero_le_real {x : ℝ} : (0 : ℂ) ≤ (x : ℂ) ↔ 0 ≤ x := @@ -106,9 +112,9 @@ lemma neg_re_eq_abs {z : ℂ} : -z.re = abs z ↔ z ≤ 0 := by @[simp] lemma re_eq_neg_abs {z : ℂ} : z.re = -abs z ↔ z ≤ 0 := by rw [← neg_eq_iff_eq_neg, neg_re_eq_abs] -lemma monotone_ofReal : Monotone ofReal' := by +lemma monotone_ofReal : Monotone ofReal := by intro x y hxy - simp only [ofReal_eq_coe, real_le_real, hxy] + simp only [ofRealHom_eq_coe, real_le_real, hxy] end Complex @@ -122,11 +128,11 @@ private alias ⟨_, ofReal_ne_zero_of_ne_zero⟩ := ofReal_ne_zero /-- Extension for the `positivity` tactic: `Complex.ofReal` is positive/nonnegative/nonzero if its input is. -/ -@[positivity Complex.ofReal' _, Complex.ofReal _] +@[positivity Complex.ofReal _, Complex.ofReal _] def evalComplexOfReal : PositivityExt where eval {u α} _ _ e := do -- TODO: Can we avoid duplicating the code? match u, α, e with - | 0, ~q(ℂ), ~q(Complex.ofReal' $a) => + | 0, ~q(ℂ), ~q(Complex.ofReal $a) => assumeInstancesCommute match ← core q(inferInstance) q(inferInstance) a with | .positive pa => return .positive q(ofReal_pos $pa) @@ -140,7 +146,7 @@ def evalComplexOfReal : PositivityExt where eval {u α} _ _ e := do | .nonnegative pa => return .nonnegative q(ofReal_nonneg $pa) | .nonzero pa => return .nonzero q(ofReal_ne_zero_of_ne_zero $pa) | _ => return .none - | _, _ => throwError "not Complex.ofReal'" + | _, _ => throwError "not Complex.ofReal" example (x : ℝ) (hx : 0 < x) : 0 < (x : ℂ) := by positivity example (x : ℝ) (hx : 0 ≤ x) : 0 ≤ (x : ℂ) := by positivity diff --git a/Mathlib/Data/Countable/Basic.lean b/Mathlib/Data/Countable/Basic.lean index 9b80d33df3f88..89694dd120b07 100644 --- a/Mathlib/Data/Countable/Basic.lean +++ b/Mathlib/Data/Countable/Basic.lean @@ -66,7 +66,7 @@ instance Sum.uncountable_inr [Uncountable β] : Uncountable (α ⊕ β) := inr_injective.uncountable instance Option.instCountable [Countable α] : Countable (Option α) := - Countable.of_equiv _ (Equiv.optionEquivSumPUnit.{_, 0} α).symm + Countable.of_equiv _ (Equiv.optionEquivSumPUnit.{0, _} α).symm instance WithTop.instCountable [Countable α] : Countable (WithTop α) := Option.instCountable instance WithBot.instCountable [Countable α] : Countable (WithBot α) := Option.instCountable diff --git a/Mathlib/Data/DFinsupp/Basic.lean b/Mathlib/Data/DFinsupp/Basic.lean index 11111a2e35ca6..c08ce66284b1d 100644 --- a/Mathlib/Data/DFinsupp/Basic.lean +++ b/Mathlib/Data/DFinsupp/Basic.lean @@ -17,7 +17,7 @@ import Mathlib.Order.ConditionallyCompleteLattice.Basic /-! # Dependent functions with finite support -For a non-dependent version see `data/finsupp.lean`. +For a non-dependent version see `Mathlib.Data.Finsupp.Defs`. ## Notation @@ -81,11 +81,6 @@ instance instDFunLike : DFunLike (Π₀ i, β i) ι β := congr subsingleton ⟩ -/-- Helper instance for when there are too many metavariables to apply `DFunLike.coeFunForall` -directly. -/ -instance : CoeFun (Π₀ i, β i) fun _ => ∀ i, β i := - inferInstance - @[simp] theorem toFun_eq_coe (f : Π₀ i, β i) : f.toFun = f := rfl @@ -131,7 +126,7 @@ theorem mapRange_apply (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) rfl @[simp] -theorem mapRange_id (h : ∀ i, id (0 : β₁ i) = 0 := fun i => rfl) (g : Π₀ i : ι, β₁ i) : +theorem mapRange_id (h : ∀ i, id (0 : β₁ i) = 0 := fun _ => rfl) (g : Π₀ i : ι, β₁ i) : mapRange (fun i => (id : β₁ i → β₁ i)) h g = g := by ext rfl @@ -559,7 +554,6 @@ theorem single_apply {i i' b} : theorem single_zero (i) : (single i 0 : Π₀ i, β i) = 0 := DFunLike.coe_injective <| Pi.single_zero _ --- @[simp] -- Porting note (#10618): simp can prove this theorem single_eq_same {i b} : (single i b : Π₀ i, β i) i = b := by simp only [single_apply, dite_eq_ite, ite_true] @@ -660,7 +654,6 @@ def erase (i : ι) (x : Π₀ i, β i) : Π₀ i, β i := theorem erase_apply {i j : ι} {f : Π₀ i, β i} : (f.erase i) j = if j = i then 0 else f j := rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem erase_same {i : ι} {f : Π₀ i, β i} : (f.erase i) i = 0 := by simp theorem erase_ne {i i' : ι} {f : Π₀ i, β i} (h : i' ≠ i) : (f.erase i) i' = f i' := by simp [h] @@ -1125,7 +1118,7 @@ theorem filter_def (f : Π₀ i, β i) : f.filter p = mk (f.support.filter p) fu ext i; by_cases h1 : p i <;> by_cases h2 : f i ≠ 0 <;> simp at h2 <;> simp [h1, h2] @[simp] -theorem support_filter (f : Π₀ i, β i) : (f.filter p).support = f.support.filter p := by +theorem support_filter (f : Π₀ i, β i) : (f.filter p).support = {x ∈ f.support | p x} := by ext i; by_cases h : p i <;> simp [h] theorem subtypeDomain_def (f : Π₀ i, β i) : @@ -1356,7 +1349,7 @@ theorem sigmaCurry_single [∀ i, DecidableEq (α i)] [∀ i j, Zero (δ i j)] /-- The natural map between `Π₀ i (j : α i), δ i j` and `Π₀ (i : Σ i, α i), δ i.1 i.2`, inverse of `curry`. -/ def sigmaUncurry [∀ i j, Zero (δ i j)] [DecidableEq ι] (f : Π₀ (i) (j), δ i j) : - Π₀ i : Σi, _, δ i.1 i.2 where + Π₀ i : Σ_, _, δ i.1 i.2 where toFun i := f i.1 i.2 support' := f.support'.bind fun s => @@ -1422,7 +1415,7 @@ theorem sigmaUncurry_single [∀ i j, Zero (δ i j)] [∀ i, DecidableEq (α i)] This is the dfinsupp version of `Equiv.piCurry`. -/ def sigmaCurryEquiv [∀ i j, Zero (δ i j)] [DecidableEq ι] : - (Π₀ i : Σi, _, δ i.1 i.2) ≃ Π₀ (i) (j), δ i j where + (Π₀ i : Σ_, _, δ i.1 i.2) ≃ Π₀ (i) (j), δ i j where toFun := sigmaCurry invFun := sigmaUncurry left_inv f := by @@ -1722,7 +1715,7 @@ theorem sumAddHom_comp_single [∀ i, AddZeroClass (β i)] [AddCommMonoid γ] (f theorem sumAddHom_apply [∀ i, AddZeroClass (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [AddCommMonoid γ] (φ : ∀ i, β i →+ γ) (f : Π₀ i, β i) : sumAddHom φ f = f.sum fun x => φ x := by rcases f with ⟨f, s, hf⟩ - change (∑ i ∈ _, _) = ∑ i ∈ Finset.filter _ _, _ + change (∑ i ∈ _, _) = ∑ i ∈ _ with _, _ rw [Finset.sum_filter, Finset.sum_congr rfl] intro i _ dsimp only [coe_mk', Subtype.coe_mk] at * @@ -1776,7 +1769,7 @@ theorem _root_.AddSubmonoid.mem_iSup_iff_exists_dfinsupp [AddCommMonoid γ] (S : /-- A variant of `AddSubmonoid.mem_iSup_iff_exists_dfinsupp` with the RHS fully unfolded. -/ theorem _root_.AddSubmonoid.mem_iSup_iff_exists_dfinsupp' [AddCommMonoid γ] (S : ι → AddSubmonoid γ) [∀ (i) (x : S i), Decidable (x ≠ 0)] (x : γ) : - x ∈ iSup S ↔ ∃ f : Π₀ i, S i, (f.sum fun i xi => ↑xi) = x := by + x ∈ iSup S ↔ ∃ f : Π₀ i, S i, (f.sum fun _ xi => ↑xi) = x := by rw [AddSubmonoid.mem_iSup_iff_exists_dfinsupp] simp_rw [sumAddHom_apply] rfl diff --git a/Mathlib/Data/DFinsupp/Interval.lean b/Mathlib/Data/DFinsupp/Interval.lean index 8588c90c87525..8cb45f7f31389 100644 --- a/Mathlib/Data/DFinsupp/Interval.lean +++ b/Mathlib/Data/DFinsupp/Interval.lean @@ -35,8 +35,7 @@ def dfinsupp (s : Finset ι) (t : ∀ i, Finset (α i)) : Finset (Π₀ i, α i) convert congr_fun h ⟨i, hi⟩⟩ @[simp] -theorem card_dfinsupp (s : Finset ι) (t : ∀ i, Finset (α i)) : - (s.dfinsupp t).card = ∏ i ∈ s, (t i).card := +theorem card_dfinsupp (s : Finset ι) (t : ∀ i, Finset (α i)) : #(s.dfinsupp t) = ∏ i ∈ s, #(t i) := (card_map _).trans <| card_pi _ _ variable [∀ i, DecidableEq (α i)] @@ -102,7 +101,6 @@ def rangeIcc (f g : Π₀ i, α i) : Π₀ i, Finset (α i) where (Multiset.not_mem_mono (Multiset.Le.subset <| Multiset.le_add_right _ _) h) have hg : g i = 0 := (gs.prop i).resolve_left (Multiset.not_mem_mono (Multiset.Le.subset <| Multiset.le_add_left _ _) h) - -- Porting note: was rw, but was rewriting under lambda, so changed to simp_rw simp_rw [hf, hg] exact Icc_self _⟩ @@ -135,7 +133,7 @@ theorem mem_pi {f : Π₀ i, Finset (α i)} {g : Π₀ i, α i} : g ∈ f.pi ↔ mem_dfinsupp_iff_of_support_subset <| Subset.refl _ @[simp] -theorem card_pi (f : Π₀ i, Finset (α i)) : f.pi.card = f.prod fun i => (f i).card := by +theorem card_pi (f : Π₀ i, Finset (α i)) : #f.pi = f.prod fun i ↦ #(f i) := by rw [pi, card_dfinsupp] exact Finset.prod_congr rfl fun i _ => by simp only [Pi.natCast_apply, Nat.cast_id] @@ -158,16 +156,16 @@ variable (f g : Π₀ i, α i) theorem Icc_eq : Icc f g = (f.support ∪ g.support).dfinsupp (f.rangeIcc g) := rfl -theorem card_Icc : (Icc f g).card = ∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card := +lemma card_Icc : #(Icc f g) = ∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i)) := card_dfinsupp _ _ -theorem card_Ico : (Ico f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 1 := by +lemma card_Ico : #(Ico f g) = (∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i))) - 1 := by rw [card_Ico_eq_card_Icc_sub_one, card_Icc] -theorem card_Ioc : (Ioc f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 1 := by +lemma card_Ioc : #(Ioc f g) = (∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i))) - 1 := by rw [card_Ioc_eq_card_Icc_sub_one, card_Icc] -theorem card_Ioo : (Ioo f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 2 := by +lemma card_Ioo : #(Ioo f g) = (∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i))) - 2 := by rw [card_Ioo_eq_card_Icc_sub_two, card_Icc] end PartialOrder @@ -176,7 +174,7 @@ section Lattice variable [DecidableEq ι] [∀ i, DecidableEq (α i)] [∀ i, Lattice (α i)] [∀ i, Zero (α i)] [∀ i, LocallyFiniteOrder (α i)] (f g : Π₀ i, α i) -theorem card_uIcc : (uIcc f g).card = ∏ i ∈ f.support ∪ g.support, (uIcc (f i) (g i)).card := by +lemma card_uIcc : #(uIcc f g) = ∏ i ∈ f.support ∪ g.support, #(uIcc (f i) (g i)) := by rw [← support_inf_union_support_sup]; exact card_Icc _ _ end Lattice @@ -187,11 +185,11 @@ variable [DecidableEq ι] [∀ i, DecidableEq (α i)] variable [∀ i, CanonicallyOrderedAddCommMonoid (α i)] [∀ i, LocallyFiniteOrder (α i)] variable (f : Π₀ i, α i) -theorem card_Iic : (Iic f).card = ∏ i ∈ f.support, (Iic (f i)).card := by +lemma card_Iic : #(Iic f) = ∏ i ∈ f.support, #(Iic (f i)) := by simp_rw [Iic_eq_Icc, card_Icc, DFinsupp.bot_eq_zero, support_zero, empty_union, zero_apply, bot_eq_zero] -theorem card_Iio : (Iio f).card = (∏ i ∈ f.support, (Iic (f i)).card) - 1 := by +lemma card_Iio : #(Iio f) = (∏ i ∈ f.support, #(Iic (f i))) - 1 := by rw [card_Iio_eq_card_Iic_sub_one, card_Iic] end CanonicallyOrdered diff --git a/Mathlib/Data/DFinsupp/Lex.lean b/Mathlib/Data/DFinsupp/Lex.lean index b0c8d8ea0b694..1b3888f712e29 100644 --- a/Mathlib/Data/DFinsupp/Lex.lean +++ b/Mathlib/Data/DFinsupp/Lex.lean @@ -136,37 +136,33 @@ section Covariants variable [LinearOrder ι] [∀ i, AddMonoid (α i)] [∀ i, LinearOrder (α i)] /-! We are about to sneak in a hypothesis that might appear to be too strong. -We assume `CovariantClass` with *strict* inequality `<` also when proving the one with the -*weak* inequality `≤`. This is actually necessary: addition on `Lex (Π₀ i, α i)` may fail to be -monotone, when it is "just" monotone on `α i`. -/ +We assume `AddLeftStrictMono` (covariant with *strict* inequality `<`) also when proving the one +with the *weak* inequality `≤`. This is actually necessary: addition on `Lex (Π₀ i, α i)` may fail +to be monotone, when it is "just" monotone on `α i`. -/ section Left -variable [∀ i, CovariantClass (α i) (α i) (· + ·) (· < ·)] +variable [∀ i, AddLeftStrictMono (α i)] -instance Lex.covariantClass_lt_left : - CovariantClass (Lex (Π₀ i, α i)) (Lex (Π₀ i, α i)) (· + ·) (· < ·) := +instance Lex.addLeftStrictMono : AddLeftStrictMono (Lex (Π₀ i, α i)) := ⟨fun _ _ _ ⟨a, lta, ha⟩ ↦ ⟨a, fun j ja ↦ congr_arg _ (lta j ja), add_lt_add_left ha _⟩⟩ -instance Lex.covariantClass_le_left : - CovariantClass (Lex (Π₀ i, α i)) (Lex (Π₀ i, α i)) (· + ·) (· ≤ ·) := - covariantClass_le_of_lt _ _ _ +instance Lex.addLeftMono : AddLeftMono (Lex (Π₀ i, α i)) := + addLeftMono_of_addLeftStrictMono _ end Left section Right -variable [∀ i, CovariantClass (α i) (α i) (Function.swap (· + ·)) (· < ·)] +variable [∀ i, AddRightStrictMono (α i)] -instance Lex.covariantClass_lt_right : - CovariantClass (Lex (Π₀ i, α i)) (Lex (Π₀ i, α i)) (Function.swap (· + ·)) (· < ·) := +instance Lex.addRightStrictMono : AddRightStrictMono (Lex (Π₀ i, α i)) := ⟨fun f _ _ ⟨a, lta, ha⟩ ↦ ⟨a, fun j ja ↦ congr_arg (· + ofLex f j) (lta j ja), add_lt_add_right ha _⟩⟩ -instance Lex.covariantClass_le_right : - CovariantClass (Lex (Π₀ i, α i)) (Lex (Π₀ i, α i)) (Function.swap (· + ·)) (· ≤ ·) := - covariantClass_le_of_lt _ _ _ +instance Lex.addRightMono : AddRightMono (Lex (Π₀ i, α i)) := + addRightMono_of_addRightStrictMono _ end Right diff --git a/Mathlib/Data/DFinsupp/Multiset.lean b/Mathlib/Data/DFinsupp/Multiset.lean index 949128cc0bccb..fe589464c5396 100644 --- a/Mathlib/Data/DFinsupp/Multiset.lean +++ b/Mathlib/Data/DFinsupp/Multiset.lean @@ -14,7 +14,7 @@ with `Multiset.toDFinsupp` the reverse equivalence. open Function -variable {α : Type*} {β : α → Type*} +variable {α : Type*} namespace DFinsupp @@ -22,7 +22,7 @@ namespace DFinsupp instance addZeroClass' {β} [AddZeroClass β] : AddZeroClass (Π₀ _ : α, β) := @DFinsupp.addZeroClass α (fun _ ↦ β) _ -variable [DecidableEq α] {s t : Multiset α} +variable [DecidableEq α] /-- A DFinsupp version of `Finsupp.toMultiset`. -/ def toMultiset : (Π₀ _ : α, ℕ) →+ Multiset α := diff --git a/Mathlib/Data/DFinsupp/Notation.lean b/Mathlib/Data/DFinsupp/Notation.lean index f4782385250a8..bdb9cdad1a53f 100644 --- a/Mathlib/Data/DFinsupp/Notation.lean +++ b/Mathlib/Data/DFinsupp/Notation.lean @@ -44,13 +44,13 @@ def elabUpdate₀ : Elab.Term.TermElab | _ => fun _ => Elab.throwUnsupportedSyntax /-- Unexpander for the `fun₀ | i => x` notation. -/ -@[app_unexpander Finsupp.single] +@[app_unexpander DFinsupp.single] def singleUnexpander : Lean.PrettyPrinter.Unexpander | `($_ $pat $val) => `(fun₀ | $pat => $val) | _ => throw () /-- Unexpander for the `fun₀ | i => x` notation. -/ -@[app_unexpander Finsupp.update] +@[app_unexpander DFinsupp.update] def updateUnexpander : Lean.PrettyPrinter.Unexpander | `($_ $f $pat $val) => match f with | `(fun₀ $xs:matchAlt*) => `(fun₀ $xs:matchAlt* | $pat => $val) @@ -68,9 +68,9 @@ unsafe instance {α : Type*} {β : α → Type*} [Repr α] [∀ i, Repr (β i)] if vals.length = 0 then "0" else - let ret := "fun₀" ++ - Std.Format.join (vals_dedup.map <| - fun a => f!" | " ++ a.1 ++ f!" => " ++ a.2) + let ret : Std.Format := f!"fun₀" ++ .nest 2 ( + .group (.join <| vals_dedup.map fun a => + .line ++ .group (f!"| {a.1} =>" ++ .line ++ a.2))) if p ≥ leadPrec then Format.paren ret else ret end DFinsupp diff --git a/Mathlib/Data/DFinsupp/Order.lean b/Mathlib/Data/DFinsupp/Order.lean index ebb4970f7a3ce..767a61edb7f6b 100644 --- a/Mathlib/Data/DFinsupp/Order.lean +++ b/Mathlib/Data/DFinsupp/Order.lean @@ -68,8 +68,8 @@ variable [∀ i, Preorder (α i)] {f g : Π₀ i, α i} instance : Preorder (Π₀ i, α i) := { (inferInstance : LE (DFinsupp α)) with - le_refl := fun f i ↦ le_rfl - le_trans := fun f g h hfg hgh i ↦ (hfg i).trans (hgh i) } + le_refl := fun _ _ ↦ le_rfl + le_trans := fun _ _ _ hfg hgh i ↦ (hfg i).trans (hgh i) } lemma lt_def : f < g ↔ f ≤ g ∧ ∃ i, f i < g i := Pi.lt_def @[simp, norm_cast] lemma coe_lt_coe : ⇑f < g ↔ f < g := Iff.rfl @@ -141,8 +141,8 @@ instance (α : ι → Type*) [∀ i, OrderedCancelAddCommMonoid (α i)] : { (inferInstance : OrderedAddCommMonoid (DFinsupp α)) with le_of_add_le_add_left := fun _ _ _ H i ↦ le_of_add_le_add_left (H i) } -instance [∀ i, OrderedAddCommMonoid (α i)] [∀ i, ContravariantClass (α i) (α i) (· + ·) (· ≤ ·)] : - ContravariantClass (Π₀ i, α i) (Π₀ i, α i) (· + ·) (· ≤ ·) := +instance [∀ i, OrderedAddCommMonoid (α i)] [∀ i, AddLeftReflectLE (α i)] : + AddLeftReflectLE (Π₀ i, α i) := ⟨fun _ _ _ H i ↦ le_of_add_le_add_left (H i)⟩ section Module diff --git a/Mathlib/Data/DFinsupp/WellFounded.lean b/Mathlib/Data/DFinsupp/WellFounded.lean index 4262697dac419..082f7478b3b5e 100644 --- a/Mathlib/Data/DFinsupp/WellFounded.lean +++ b/Mathlib/Data/DFinsupp/WellFounded.lean @@ -215,7 +215,7 @@ protected theorem DFinsupp.wellFoundedLT [∀ i, Zero (α i)] [∀ i, Preorder ( simp (config := { unfoldPartialApp := true }) only [Function.swap] -/ simp only [Function.swap_def] exact IsWellFounded.wf - refine Subrelation.wf (fun h => ?_) <| InvImage.wf (mapRange (fun i ↦ e i) fun _ ↦ rfl) this + refine Subrelation.wf (fun h => ?_) <| InvImage.wf (mapRange e fun _ ↦ rfl) this have := IsStrictOrder.swap (@WellOrderingRel ι) obtain ⟨i, he, hl⟩ := lex_lt_of_lt_of_preorder (Function.swap WellOrderingRel) h exact ⟨i, fun j hj ↦ Quot.sound (he j hj), hl⟩⟩ diff --git a/Mathlib/Data/DList/Basic.lean b/Mathlib/Data/DList/Basic.lean deleted file mode 100644 index 050f7d8838807..0000000000000 --- a/Mathlib/Data/DList/Basic.lean +++ /dev/null @@ -1,38 +0,0 @@ -/- -Copyright (c) 2018 Simon Hudon. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Simon Hudon --/ -import Mathlib.Data.DList.Defs -import Mathlib.Tactic.TypeStar - -/-! -# Difference list - -This file provides a few results about `DList`, which is defined in `Batteries`. - -A difference list is a function that, given a list, returns the original content of the -difference list prepended to the given list. It is useful to represent elements of a given type -as `a₁ + ... + aₙ` where `+ : α → α → α` is any operation, without actually computing. - -This structure supports `O(1)` `append` and `push` operations on lists, making it -useful for append-heavy uses such as logging and pretty printing. --/ - -namespace Batteries - -/-- Concatenates a list of difference lists to form a single difference list. Similar to -`List.join`. -/ -def DList.join {α : Type*} : List (DList α) → DList α - | [] => DList.empty - | x :: xs => x ++ DList.join xs - -@[simp] -theorem DList_singleton {α : Type*} {a : α} : DList.singleton a = DList.lazy_ofList [a] := - rfl - -@[simp] -theorem DList_lazy {α : Type*} {l : List α} : DList.lazy_ofList l = Batteries.DList.ofList l := - rfl - -end Batteries diff --git a/Mathlib/Data/DList/Defs.lean b/Mathlib/Data/DList/Defs.lean deleted file mode 100644 index 408fa448595bd..0000000000000 --- a/Mathlib/Data/DList/Defs.lean +++ /dev/null @@ -1,59 +0,0 @@ -/- -Copyright (c) 2017 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura --/ -import Batteries.Data.DList - -/-! -# Difference list - -This file provides a few results about `DList`, which is defined in `Batteries`. - -A difference list is a function that, given a list, returns the original content of the -difference list prepended to the given list. It is useful to represent elements of a given type -as `a₁ + ... + aₙ` where `+ : α → α → α` is any operation, without actually computing. - -This structure supports `O(1)` `append` and `push` operations on lists, making it -useful for append-heavy uses such as logging and pretty printing. --/ - -universe u - -namespace Batteries.DList - -open Function - -variable {α : Type u} - -/-- Convert a lazily-evaluated `List` to a `DList` -/ -def lazy_ofList (l : Thunk (List α)) : DList α := - ⟨fun xs => l.get ++ xs, fun t => by simp⟩ - -attribute [local simp] Function.comp - -attribute [local simp] ofList toList empty singleton cons push append - -theorem toList_ofList (l : List α) : DList.toList (DList.ofList l) = l := by - cases l; rfl; simp only [DList.toList, DList.ofList, List.cons_append, List.append_nil] - -theorem ofList_toList (l : DList α) : DList.ofList (DList.toList l) = l := by - obtain ⟨app, inv⟩ := l - simp only [ofList, toList, mk.injEq] - funext x - rw [(inv x)] - -theorem toList_empty : toList (@empty α) = [] := by simp - -theorem toList_singleton (x : α) : toList (singleton x) = [x] := by simp - -theorem toList_append (l₁ l₂ : DList α) : toList (l₁ ++ l₂) = toList l₁ ++ toList l₂ := by - obtain ⟨_, l₁_invariant⟩ := l₁; cases l₂; simp; rw [l₁_invariant] - -theorem toList_cons (x : α) (l : DList α) : toList (cons x l) = x :: toList l := by - cases l; simp - -theorem toList_push (x : α) (l : DList α) : toList (push l x) = toList l ++ [x] := by - obtain ⟨_, l_invariant⟩ := l; simp; rw [l_invariant] - -end Batteries.DList diff --git a/Mathlib/Data/DList/Instances.lean b/Mathlib/Data/DList/Instances.lean index 58f56d5bb12ac..5a4d14e1b26f5 100644 --- a/Mathlib/Data/DList/Instances.lean +++ b/Mathlib/Data/DList/Instances.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon -/ -import Mathlib.Data.DList.Defs +import Batteries.Data.DList.Lemmas import Mathlib.Control.Traversable.Equiv import Mathlib.Control.Traversable.Instances diff --git a/Mathlib/Data/ENNReal/Basic.lean b/Mathlib/Data/ENNReal/Basic.lean index 11fe99146aa06..011ecb173bcb6 100644 --- a/Mathlib/Data/ENNReal/Basic.lean +++ b/Mathlib/Data/ENNReal/Basic.lean @@ -5,8 +5,7 @@ Authors: Johannes Hölzl, Yury Kudryashov -/ import Mathlib.Algebra.Order.Ring.WithTop import Mathlib.Algebra.Order.Sub.WithTop -import Mathlib.Data.NNReal.Basic -import Mathlib.Order.Interval.Set.WithBotTop +import Mathlib.Data.NNReal.Defs /-! # Extended non-negative reals @@ -133,9 +132,9 @@ noncomputable instance : DivInvMonoid ℝ≥0∞ where variable {a b c d : ℝ≥0∞} {r p q : ℝ≥0} -- Porting note: are these 2 instances still required in Lean 4? -instance covariantClass_mul_le : CovariantClass ℝ≥0∞ ℝ≥0∞ (· * ·) (· ≤ ·) := inferInstance +instance mulLeftMono : MulLeftMono ℝ≥0∞ := inferInstance -instance covariantClass_add_le : CovariantClass ℝ≥0∞ ℝ≥0∞ (· + ·) (· ≤ ·) := inferInstance +instance addLeftMono : AddLeftMono ℝ≥0∞ := inferInstance -- Porting note (#11215): TODO: add a `WithTop` instance and use it here noncomputable instance : LinearOrderedCommMonoidWithZero ℝ≥0∞ := @@ -283,13 +282,15 @@ theorem toNNReal_ne_one : a.toNNReal ≠ 1 ↔ a ≠ 1 := theorem toReal_ne_one : a.toReal ≠ 1 ↔ a ≠ 1 := a.toReal_eq_one_iff.not -@[simp] theorem coe_ne_top : (r : ℝ≥0∞) ≠ ∞ := WithTop.coe_ne_top +@[simp, aesop (rule_sets := [finiteness]) safe apply] +theorem coe_ne_top : (r : ℝ≥0∞) ≠ ∞ := WithTop.coe_ne_top @[simp] theorem top_ne_coe : ∞ ≠ (r : ℝ≥0∞) := WithTop.top_ne_coe @[simp] theorem coe_lt_top : (r : ℝ≥0∞) < ∞ := WithTop.coe_lt_top r -@[simp] theorem ofReal_ne_top {r : ℝ} : ENNReal.ofReal r ≠ ∞ := coe_ne_top +@[simp, aesop (rule_sets := [finiteness]) safe apply] +theorem ofReal_ne_top {r : ℝ} : ENNReal.ofReal r ≠ ∞ := coe_ne_top @[simp] theorem ofReal_lt_top {r : ℝ} : ENNReal.ofReal r < ∞ := coe_lt_top @@ -307,11 +308,11 @@ theorem toReal_ofReal_eq_iff {a : ℝ} : (ENNReal.ofReal a).toReal = a ↔ 0 ≤ rw [← h] exact toReal_nonneg, toReal_ofReal⟩ -@[simp] theorem zero_ne_top : 0 ≠ ∞ := coe_ne_top +@[simp, aesop (rule_sets := [finiteness]) safe apply] theorem zero_ne_top : 0 ≠ ∞ := coe_ne_top @[simp] theorem top_ne_zero : ∞ ≠ 0 := top_ne_coe -@[simp] theorem one_ne_top : 1 ≠ ∞ := coe_ne_top +@[simp, aesop (rule_sets := [finiteness]) safe apply] theorem one_ne_top : 1 ≠ ∞ := coe_ne_top @[simp] theorem top_ne_one : ∞ ≠ 1 := top_ne_coe @@ -382,9 +383,9 @@ theorem toReal_eq_toReal_iff' {x y : ℝ≥0∞} (hx : x ≠ ⊤) (hy : y ≠ theorem one_lt_two : (1 : ℝ≥0∞) < 2 := Nat.one_lt_ofNat -@[simp] theorem two_ne_top : (2 : ℝ≥0∞) ≠ ∞ := coe_ne_top +theorem two_ne_top : (2 : ℝ≥0∞) ≠ ∞ := coe_ne_top -@[simp] theorem two_lt_top : (2 : ℝ≥0∞) < ∞ := coe_lt_top +theorem two_lt_top : (2 : ℝ≥0∞) < ∞ := coe_lt_top /-- `(1 : ℝ≥0∞) ≤ 1`, recorded as a `Fact` for use with `Lp` spaces. -/ instance _root_.fact_one_le_one_ennreal : Fact ((1 : ℝ≥0∞) ≤ 1) := @@ -436,11 +437,6 @@ def ofNNRealHom : ℝ≥0 →+* ℝ≥0∞ where @[simp] theorem coe_ofNNRealHom : ⇑ofNNRealHom = some := rfl -@[simp, norm_cast] -theorem coe_indicator {α} (s : Set α) (f : α → ℝ≥0) (a : α) : - ((s.indicator f a : ℝ≥0) : ℝ≥0∞) = s.indicator (fun x => ↑(f x)) a := - (ofNNRealHom : ℝ≥0 →+ ℝ≥0∞).map_indicator _ _ _ - section Order theorem bot_eq_zero : (⊥ : ℝ≥0∞) = 0 := rfl @@ -471,9 +467,17 @@ theorem coe_natCast (n : ℕ) : ((n : ℝ≥0) : ℝ≥0∞) = n := rfl ENNReal.ofReal (no_index (OfNat.ofNat n)) = OfNat.ofNat n := ofReal_natCast n -@[simp] theorem natCast_ne_top (n : ℕ) : (n : ℝ≥0∞) ≠ ∞ := WithTop.natCast_ne_top n +@[simp, aesop (rule_sets := [finiteness]) safe apply] +theorem natCast_ne_top (n : ℕ) : (n : ℝ≥0∞) ≠ ∞ := WithTop.natCast_ne_top n + @[simp] theorem natCast_lt_top (n : ℕ) : (n : ℝ≥0∞) < ∞ := WithTop.natCast_lt_top n +@[simp, aesop (rule_sets := [finiteness]) safe apply] +lemma ofNat_ne_top {n : ℕ} [Nat.AtLeastTwo n] : no_index (OfNat.ofNat n) ≠ ∞ := natCast_ne_top n + +@[simp] +lemma ofNat_lt_top {n : ℕ} [Nat.AtLeastTwo n] : no_index (OfNat.ofNat n) < ∞ := natCast_lt_top n + @[simp] theorem top_ne_natCast (n : ℕ) : ∞ ≠ n := WithTop.top_ne_natCast n @[simp] theorem one_lt_top : 1 < ∞ := coe_lt_top @@ -502,10 +506,6 @@ theorem toReal_le_coe_of_le_coe {a : ℝ≥0∞} {b : ℝ≥0} (h : a ≤ b) : a lift a to ℝ≥0 using ne_top_of_le_ne_top coe_ne_top h simpa using h -@[simp, norm_cast] -theorem coe_finset_sup {s : Finset α} {f : α → ℝ≥0} : ↑(s.sup f) = s.sup fun x => (f x : ℝ≥0∞) := - Finset.comp_sup_eq_sup_comp_of_is_total _ coe_mono rfl - @[simp] theorem max_eq_zero_iff : max a b = 0 ↔ a = 0 ∧ b = 0 := max_eq_bot theorem max_zero_left : max 0 a = a := @@ -526,7 +526,7 @@ theorem lt_iff_exists_rat_btwn : rcases lt_iff_exists_coe.1 cb with ⟨r, rfl, _⟩ rcases (NNReal.lt_iff_exists_rat_btwn _ _).1 (coe_lt_coe.1 pc) with ⟨q, hq0, pq, qr⟩ exact ⟨q, hq0, coe_lt_coe.2 pq, lt_trans (coe_lt_coe.2 qr) cb⟩, - fun ⟨q, _, qa, qb⟩ => lt_trans qa qb⟩ + fun ⟨_, _, qa, qb⟩ => lt_trans qa qb⟩ theorem lt_iff_exists_real_btwn : a < b ↔ ∃ r : ℝ, 0 ≤ r ∧ a < ENNReal.ofReal r ∧ (ENNReal.ofReal r : ℝ≥0∞) < b := diff --git a/Mathlib/Data/ENNReal/Inv.lean b/Mathlib/Data/ENNReal/Inv.lean index 1fc1f2eb0733b..9e4ded7d0e36e 100644 --- a/Mathlib/Data/ENNReal/Inv.lean +++ b/Mathlib/Data/ENNReal/Inv.lean @@ -123,6 +123,9 @@ instance : InvolutiveInv ℝ≥0∞ where theorem inv_ne_top : a⁻¹ ≠ ∞ ↔ a ≠ 0 := by simp +@[aesop (rule_sets := [finiteness]) safe apply] +protected alias ⟨_, Finiteness.inv_ne_top⟩ := ENNReal.inv_ne_top + @[simp] theorem inv_lt_top {x : ℝ≥0∞} : x⁻¹ < ∞ ↔ 0 < x := by simp only [lt_top_iff_ne_top, inv_ne_top, pos_iff_ne_zero] @@ -444,6 +447,27 @@ theorem sub_half (h : a ≠ ∞) : a - a / 2 = a / 2 := ENNReal.sub_eq_of_eq_add theorem one_sub_inv_two : (1 : ℝ≥0∞) - 2⁻¹ = 2⁻¹ := by simpa only [div_eq_mul_inv, one_mul] using sub_half one_ne_top +private lemma exists_lt_mul_left {a b c : ℝ≥0∞} (hc : c < a * b) : ∃ a' < a, c < a' * b := by + obtain ⟨a', hc, ha'⟩ := exists_between (ENNReal.div_lt_of_lt_mul hc) + exact ⟨_, ha', (ENNReal.div_lt_iff (.inl <| by rintro rfl; simp at *) + (.inr <| by rintro rfl; simp at *)).1 hc⟩ + +private lemma exists_lt_mul_right {a b c : ℝ≥0∞} (hc : c < a * b) : ∃ b' < b, c < a * b' := by + simp_rw [mul_comm a] at hc ⊢; exact exists_lt_mul_left hc + +lemma mul_le_of_forall_lt {a b c : ℝ≥0∞} (h : ∀ a' < a, ∀ b' < b, a' * b' ≤ c) : a * b ≤ c := by + refine le_of_forall_ge_of_dense fun d hd ↦ ?_ + obtain ⟨a', ha', hd⟩ := exists_lt_mul_left hd + obtain ⟨b', hb', hd⟩ := exists_lt_mul_right hd + exact le_trans hd.le <| h _ ha' _ hb' + +lemma le_mul_of_forall_lt {a b c : ℝ≥0∞} (h₁ : a ≠ 0 ∨ b ≠ ∞) (h₂ : a ≠ ∞ ∨ b ≠ 0) + (h : ∀ a' > a, ∀ b' > b, c ≤ a' * b') : c ≤ a * b := by + rw [← ENNReal.inv_le_inv, ENNReal.mul_inv h₁ h₂] + exact mul_le_of_forall_lt fun a' ha' b' hb' ↦ ENNReal.le_inv_iff_le_inv.1 <| + (h _ (ENNReal.lt_inv_iff_lt_inv.1 ha') _ (ENNReal.lt_inv_iff_lt_inv.1 hb')).trans_eq + (ENNReal.mul_inv (Or.inr hb'.ne_top) (Or.inl ha'.ne_top)).symm + /-- The birational order isomorphism between `ℝ≥0∞` and the unit interval `Set.Iic (1 : ℝ≥0∞)`. -/ @[simps! apply_coe] def orderIsoIicOneBirational : ℝ≥0∞ ≃o Iic (1 : ℝ≥0∞) := by @@ -465,7 +489,7 @@ def orderIsoIicCoe (a : ℝ≥0) : Iic (a : ℝ≥0∞) ≃o Iic a := OrderIso.symm { toFun := fun x => ⟨x, coe_le_coe.2 x.2⟩ invFun := fun x => ⟨ENNReal.toNNReal x, coe_le_coe.1 <| coe_toNNReal_le_self.trans x.2⟩ - left_inv := fun x => Subtype.ext <| toNNReal_coe _ + left_inv := fun _ => Subtype.ext <| toNNReal_coe _ right_inv := fun x => Subtype.ext <| coe_toNNReal (ne_top_of_le_ne_top coe_ne_top x.2) map_rel_iff' := fun {_ _} => by simp only [Equiv.coe_fn_mk, Subtype.mk_le_mk, coe_le_coe, Subtype.coe_le_coe] } @@ -731,6 +755,14 @@ lemma inv_iSup (f : ι → ℝ≥0∞) : (⨆ i, f i)⁻¹ = ⨅ i, (f i)⁻¹ : lemma inv_sInf (s : Set ℝ≥0∞) : (sInf s)⁻¹ = ⨆ a ∈ s, a⁻¹ := by simp [sInf_eq_iInf, inv_iInf] lemma inv_sSup (s : Set ℝ≥0∞) : (sSup s)⁻¹ = ⨅ a ∈ s, a⁻¹ := by simp [sSup_eq_iSup, inv_iSup] +lemma le_iInf_mul {ι : Type*} (u v : ι → ℝ≥0∞) : + (⨅ i, u i) * ⨅ i, v i ≤ ⨅ i, u i * v i := + le_iInf fun i ↦ mul_le_mul' (iInf_le u i) (iInf_le v i) + +lemma iSup_mul_le {ι : Type*} {u v : ι → ℝ≥0∞} : + ⨆ i, u i * v i ≤ (⨆ i, u i) * ⨆ i, v i := + iSup_le fun i ↦ mul_le_mul' (le_iSup u i) (le_iSup v i) + lemma add_iSup [Nonempty ι] (f : ι → ℝ≥0∞) : a + ⨆ i, f i = ⨆ i, a + f i := by obtain rfl | ha := eq_or_ne a ∞ · simp @@ -803,6 +835,23 @@ lemma finsetSum_iSup_of_monotone {α ι : Type*} [Preorder ι] [IsDirected ι ( @[deprecated (since := "2024-07-14")] alias finset_sum_iSup_nat := finsetSum_iSup_of_monotone +lemma le_iInf_mul_iInf {g : κ → ℝ≥0∞} (hf : ∃ i, f i ≠ ∞) (hg : ∃ j, g j ≠ ∞) + (ha : ∀ i j, a ≤ f i * g j) : a ≤ (⨅ i, f i) * ⨅ j, g j := by + rw [← iInf_ne_top_subtype] + have := nonempty_subtype.2 hf + have := hg.nonempty + replace hg : ⨅ j, g j ≠ ∞ := by simpa using hg + rw [iInf_mul fun h ↦ (hg h).elim, le_iInf_iff] + rintro ⟨i, hi⟩ + simpa [mul_iInf fun h ↦ (hi h).elim] using ha i + +lemma iInf_mul_iInf {f g : ι → ℝ≥0∞} (hf : ∃ i, f i ≠ ∞) (hg : ∃ j, g j ≠ ∞) + (h : ∀ i j, ∃ k, f k * g k ≤ f i * g j) : (⨅ i, f i) * ⨅ i, g i = ⨅ i, f i * g i := by + refine le_antisymm (le_iInf fun i ↦ mul_le_mul' (iInf_le ..) (iInf_le ..)) + (le_iInf_mul_iInf hf hg fun i j ↦ ?_) + obtain ⟨k, hk⟩ := h i j + exact iInf_le_of_le k hk + lemma smul_iSup {R} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] (f : ι → ℝ≥0∞) (c : R) : c • ⨆ i, f i = ⨆ i, c • f i := by simp only [← smul_one_mul c (f _), ← smul_one_mul c (iSup _), ENNReal.mul_iSup] @@ -814,7 +863,7 @@ lemma smul_sSup {R} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] lemma sub_iSup [Nonempty ι] (ha : a ≠ ∞) : a - ⨆ i, f i = ⨅ i, a - f i := by obtain ⟨i, hi⟩ | h := em (∃ i, a < f i) · rw [tsub_eq_zero_iff_le.2 <| le_iSup_of_le _ hi.le, (iInf_eq_bot _).2, bot_eq_zero] - exact fun x hx ↦ ⟨i, by simpa [hi.le]⟩ + exact fun x hx ↦ ⟨i, by simpa [hi.le, tsub_eq_zero_of_le]⟩ simp_rw [not_exists, not_lt] at h refine le_antisymm (le_iInf fun i ↦ tsub_le_tsub_left (le_iSup ..) _) <| ENNReal.le_sub_of_add_le_left (ne_top_of_le_ne_top ha <| iSup_le h) <| diff --git a/Mathlib/Data/ENNReal/Lemmas.lean b/Mathlib/Data/ENNReal/Lemmas.lean new file mode 100644 index 0000000000000..979bf8305348b --- /dev/null +++ b/Mathlib/Data/ENNReal/Lemmas.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2017 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Indicator +import Mathlib.Data.ENNReal.Basic +import Mathlib.Data.Finset.Lattice + +/-! +# Some lemmas on extended non-negative reals + +These are some lemmas split off from `ENNReal.Basic` because they need a lot more imports. +They are probably good targets for further cleanup or moves. +-/ + + +open Function Set NNReal + +variable {α : Type*} + +namespace ENNReal + +@[simp, norm_cast] +theorem coe_indicator {α} (s : Set α) (f : α → ℝ≥0) (a : α) : + ((s.indicator f a : ℝ≥0) : ℝ≥0∞) = s.indicator (fun x => ↑(f x)) a := + (ofNNRealHom : ℝ≥0 →+ ℝ≥0∞).map_indicator _ _ _ + +section Order + +@[simp, norm_cast] +theorem coe_finset_sup {s : Finset α} {f : α → ℝ≥0} : ↑(s.sup f) = s.sup fun x => (f x : ℝ≥0∞) := + Finset.comp_sup_eq_sup_comp_of_is_total _ coe_mono rfl + +end Order + +end ENNReal diff --git a/Mathlib/Data/ENNReal/Operations.lean b/Mathlib/Data/ENNReal/Operations.lean index 473c3d6c65d78..41fbde8359a61 100644 --- a/Mathlib/Data/ENNReal/Operations.lean +++ b/Mathlib/Data/ENNReal/Operations.lean @@ -5,8 +5,8 @@ Authors: Johannes Hölzl, Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.WithTop import Mathlib.Algebra.GroupWithZero.Divisibility -import Mathlib.Algebra.Module.Basic import Mathlib.Data.ENNReal.Basic +import Mathlib.Data.NNReal.Basic /-! # Properties of addition, multiplication and subtraction on extended non-negative real numbers @@ -39,10 +39,10 @@ theorem mul_lt_mul (ac : a < c) (bd : b < d) : a * b < c * d := by ↑(a * b) < ↑(a' * b') := coe_lt_coe.2 (mul_lt_mul₀ aa' bb') _ ≤ c * d := mul_le_mul' a'c.le b'd.le --- TODO: generalize to `CovariantClass α α (· * ·) (· ≤ ·)` +-- TODO: generalize to `MulLeftMono α` theorem mul_left_mono : Monotone (a * ·) := fun _ _ => mul_le_mul' le_rfl --- TODO: generalize to `CovariantClass α α (swap (· * ·)) (· ≤ ·)` +-- TODO: generalize to `MulRightMono α` theorem mul_right_mono : Monotone (· * a) := fun _ _ h => mul_le_mul' h le_rfl -- Porting note (#11215): TODO: generalize to `WithTop` @@ -143,8 +143,8 @@ protected theorem add_lt_add_of_le_of_lt : a ≠ ∞ → a ≤ b → c < d → a protected theorem add_lt_add_of_lt_of_le : c ≠ ∞ → a < b → c ≤ d → a + c < b + d := WithTop.add_lt_add_of_lt_of_le -instance contravariantClass_add_lt : ContravariantClass ℝ≥0∞ ℝ≥0∞ (· + ·) (· < ·) := - WithTop.contravariantClass_add_lt +instance addLeftReflectLT : AddLeftReflectLT ℝ≥0∞ := + WithTop.addLeftReflectLT theorem lt_add_right (ha : a ≠ ∞) (hb : b ≠ 0) : a < a + b := by rwa [← pos_iff_ne_zero, ← ENNReal.add_lt_add_iff_left ha, add_zero] at hb @@ -169,6 +169,10 @@ theorem not_lt_top {x : ℝ≥0∞} : ¬x < ∞ ↔ x = ∞ := by rw [lt_top_iff theorem add_ne_top : a + b ≠ ∞ ↔ a ≠ ∞ ∧ b ≠ ∞ := by simpa only [lt_top_iff_ne_top] using add_lt_top +@[aesop (rule_sets := [finiteness]) safe apply] +protected lemma Finiteness.add_ne_top {a b : ℝ≥0∞} (ha : a ≠ ∞) (hb : b ≠ ∞) : a + b ≠ ∞ := + ENNReal.add_ne_top.2 ⟨ha, hb⟩ + theorem mul_top' : a * ∞ = if a = 0 then 0 else ∞ := by convert WithTop.mul_top' a -- Porting note: added because `simp` no longer uses `WithTop` lemmas for `ℝ≥0∞` @@ -188,6 +192,9 @@ theorem mul_eq_top : a * b = ∞ ↔ a ≠ 0 ∧ b = ∞ ∨ a = ∞ ∧ b ≠ 0 WithTop.mul_eq_top_iff theorem mul_lt_top : a < ∞ → b < ∞ → a * b < ∞ := WithTop.mul_lt_top + +-- This is unsafe because we could have `a = ∞` and `b = 0` or vice-versa +@[aesop (rule_sets := [finiteness]) unsafe 75% apply] theorem mul_ne_top : a ≠ ∞ → b ≠ ∞ → a * b ≠ ∞ := WithTop.mul_ne_top theorem lt_top_of_mul_ne_top_left (h : a * b ≠ ∞) (hb : b ≠ 0) : a < ∞ := @@ -243,7 +250,7 @@ theorem coe_finset_prod {s : Finset α} {f : α → ℝ≥0} : ↑(∏ a ∈ s, end OperationsAndInfty -- Porting note (#11215): TODO: generalize to `WithTop` -@[gcongr] theorem add_lt_add (ac : a < c) (bd : b < d) : a + b < c + d := by +@[gcongr] protected theorem add_lt_add (ac : a < c) (bd : b < d) : a + b < c + d := by lift a to ℝ≥0 using ac.ne_top lift b to ℝ≥0 using bd.ne_top cases c; · simp @@ -308,6 +315,8 @@ theorem sub_top : a - ∞ = 0 := WithTop.sub_top -- Porting note: added `@[simp]` @[simp] theorem sub_eq_top_iff : a - b = ∞ ↔ a = ∞ ∧ b ≠ ∞ := WithTop.sub_eq_top_iff +-- This is unsafe because we could have `a = b = ∞` +@[aesop (rule_sets := [finiteness]) unsafe 75% apply] theorem sub_ne_top (ha : a ≠ ∞) : a - b ≠ ∞ := mt sub_eq_top_iff.mp <| mt And.left ha @[simp, norm_cast] @@ -405,14 +414,14 @@ theorem sub_right_inj {a b c : ℝ≥0∞} (ha : a ≠ ∞) (hb : b ≤ a) (hc : (cancel_of_ne ha).tsub_right_inj (cancel_of_ne <| ne_top_of_le_ne_top ha hb) (cancel_of_ne <| ne_top_of_le_ne_top ha hc) hb hc -theorem sub_mul (h : 0 < b → b < a → c ≠ ∞) : (a - b) * c = a * c - b * c := by - rcases le_or_lt a b with hab | hab; · simp [hab, mul_right_mono hab] +protected theorem sub_mul (h : 0 < b → b < a → c ≠ ∞) : (a - b) * c = a * c - b * c := by + rcases le_or_lt a b with hab | hab; · simp [hab, mul_right_mono hab, tsub_eq_zero_of_le] rcases eq_or_lt_of_le (zero_le b) with (rfl | hb); · simp exact (cancel_of_ne <| mul_ne_top hab.ne_top (h hb hab)).tsub_mul -theorem mul_sub (h : 0 < c → c < b → a ≠ ∞) : a * (b - c) = a * b - a * c := by +protected theorem mul_sub (h : 0 < c → c < b → a ≠ ∞) : a * (b - c) = a * b - a * c := by simp only [mul_comm a] - exact sub_mul h + exact ENNReal.sub_mul h theorem sub_le_sub_iff_left (h : c ≤ a) (h' : a ≠ ∞) : (a - b ≤ a - c) ↔ c ≤ b := diff --git a/Mathlib/Data/ENNReal/Real.lean b/Mathlib/Data/ENNReal/Real.lean index e9cc940e48612..bccf679b634a5 100644 --- a/Mathlib/Data/ENNReal/Real.lean +++ b/Mathlib/Data/ENNReal/Real.lean @@ -541,7 +541,7 @@ theorem add_iInf {a : ℝ≥0∞} : a + iInf f = ⨅ b, a + f b := by theorem iInf_add_iInf (h : ∀ i j, ∃ k, f k + g k ≤ f i + g j) : iInf f + iInf g = ⨅ a, f a + g a := suffices ⨅ a, f a + g a ≤ iInf f + iInf g from - le_antisymm (le_iInf fun a => add_le_add (iInf_le _ _) (iInf_le _ _)) this + le_antisymm (le_iInf fun _ => add_le_add (iInf_le _ _) (iInf_le _ _)) this calc ⨅ a, f a + g a ≤ ⨅ (a) (a'), f a + g a' := le_iInf₂ fun a a' => let ⟨k, h⟩ := h a a'; iInf_le_of_le k h diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean index 3486a11a1cef2..83c5cd47708c2 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -175,8 +175,11 @@ theorem top_sub_ofNat (a : ℕ) [a.AtLeastTwo] : (⊤ : ℕ∞) - (no_index (OfN top_sub_coe a @[simp] -theorem zero_lt_top : (0 : ℕ∞) < ⊤ := - WithTop.zero_lt_top +theorem top_pos : (0 : ℕ∞) < ⊤ := + WithTop.top_pos + +@[deprecated ENat.top_pos (since := "2024-10-22")] +alias zero_lt_top := top_pos theorem sub_top (a : ℕ∞) : a - ⊤ = 0 := WithTop.sub_top @@ -281,4 +284,13 @@ lemma one_le_iff_ne_zero_withTop {n : WithTop ℕ∞} : ⟨fun h ↦ (zero_lt_one.trans_le h).ne', fun h ↦ add_one_nat_le_withTop_of_lt (pos_iff_ne_zero.mpr h)⟩ +lemma add_one_pos : 0 < n + 1 := + succ_def n ▸ Order.bot_lt_succ n + +lemma add_lt_add_iff_right {k : ℕ∞} (h : k ≠ ⊤) : n + k < m + k ↔ n < m := + WithTop.add_lt_add_iff_right h + +lemma add_lt_add_iff_left {k : ℕ∞} (h : k ≠ ⊤) : k + n < k + m ↔ n < m := + WithTop.add_lt_add_iff_left h + end ENat diff --git a/Mathlib/Data/FP/Basic.lean b/Mathlib/Data/FP/Basic.lean index c854edb12daef..703af9e82aadb 100644 --- a/Mathlib/Data/FP/Basic.lean +++ b/Mathlib/Data/FP/Basic.lean @@ -85,7 +85,7 @@ theorem Float.Zero.valid : ValidFinite emin 0 := ring_nf rw [mul_comm] assumption - le_trans C.precMax (Nat.le_mul_of_pos_left _ two_pos), + le_trans C.precMax (Nat.le_mul_of_pos_left _ Nat.zero_lt_two), by (rw [max_eq_right]; simp [sub_eq_add_neg, Int.ofNat_zero_le])⟩ @[nolint docBlame] diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index e0de8283c150d..95384eac7bdcf 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -171,7 +171,7 @@ then they coincide (in the heq sense). -/ protected theorem heq_fun_iff {α : Sort*} {k l : ℕ} (h : k = l) {f : Fin k → α} {g : Fin l → α} : HEq f g ↔ ∀ i : Fin k, f i = g ⟨(i : ℕ), h ▸ i.2⟩ := by subst h - simp [Function.funext_iff] + simp [funext_iff] /-- Assume `k = l` and `k' = l'`. If two functions `Fin k → Fin k' → α` and `Fin l → Fin l' → α` are equal on each pair, @@ -181,7 +181,7 @@ protected theorem heq_fun₂_iff {α : Sort*} {k l k' l' : ℕ} (h : k = l) (h' HEq f g ↔ ∀ (i : Fin k) (j : Fin k'), f i j = g ⟨(i : ℕ), h ▸ i.2⟩ ⟨(j : ℕ), h' ▸ j.2⟩ := by subst h subst h' - simp [Function.funext_iff] + simp [funext_iff] /-- Two elements of `Fin k` and `Fin l` are heq iff their values in `ℕ` coincide. This requires `k = l`. For the left implication without this assumption, see `val_eq_val_of_heq`. -/ @@ -212,10 +212,8 @@ theorem val_fin_lt {n : ℕ} {a b : Fin n} : (a : ℕ) < (b : ℕ) ↔ a < b := theorem val_fin_le {n : ℕ} {a b : Fin n} : (a : ℕ) ≤ (b : ℕ) ↔ a ≤ b := Iff.rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem min_val {a : Fin n} : min (a : ℕ) n = a := by simp --- @[simp] -- Porting note (#10618): simp can prove this theorem max_val {a : Fin n} : max (a : ℕ) n = n := by simp /-- The inclusion map `Fin n → ℕ` is an embedding. -/ @@ -242,14 +240,12 @@ instance {n : ℕ} : WellFoundedRelation (Fin n) := measure (val : Fin n → ℕ) /-- Given a positive `n`, `Fin.ofNat' i` is `i % n` as an element of `Fin n`. -/ +@[deprecated Fin.ofNat' (since := "2024-10-15")] def ofNat'' [NeZero n] (i : ℕ) : Fin n := ⟨i % n, mod_lt _ n.pos_of_neZero⟩ -- Porting note: `Fin.ofNat'` conflicts with something in core (there the hypothesis is `n > 0`), -- so for now we make this double-prime `''`. This is also the reason for the dubious translation. -instance {n : ℕ} [NeZero n] : Zero (Fin n) := ⟨ofNat'' 0⟩ -instance {n : ℕ} [NeZero n] : One (Fin n) := ⟨ofNat'' 1⟩ - /-- The `Fin.val_zero` in `Lean` only applies in `Fin (n+1)`. This one instead uses a `NeZero n` typeclass hypothesis. @@ -410,7 +406,6 @@ theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by section Monoid --- Porting note (#10618): removing `simp`, `simp` can prove it with AddCommMonoid instance protected theorem add_zero [NeZero n] (k : Fin n) : k + 0 = k := by simp only [add_def, val_zero', Nat.add_zero, mod_eq_of_lt (is_lt k)] @@ -422,15 +417,8 @@ instance inhabitedFinOneAdd (n : ℕ) : Inhabited (Fin (1 + n)) := theorem default_eq_zero (n : ℕ) [NeZero n] : (default : Fin n) = 0 := rfl -section from_ad_hoc - -@[simp] lemma ofNat'_zero [NeZero n] : (Fin.ofNat' n 0) = 0 := rfl -@[simp] lemma ofNat'_one [NeZero n] : (Fin.ofNat' n 1) = 1 := rfl - -end from_ad_hoc - instance instNatCast [NeZero n] : NatCast (Fin n) where - natCast n := Fin.ofNat'' n + natCast i := Fin.ofNat' n i lemma natCast_def [NeZero n] (a : ℕ) : (a : Fin n) = ⟨a % n, mod_lt _ n.pos_of_neZero⟩ := rfl @@ -442,10 +430,14 @@ theorem val_add_eq_ite {n : ℕ} (a b : Fin n) : Nat.mod_eq_of_lt (show ↑b < n from b.2)] --- Porting note: syntactically the same as the above +lemma intCast_val_sub_eq_sub_add_ite {n : ℕ} (a b : Fin n) : + ((a - b).val : ℤ) = a.val - b.val + if b ≤ a then 0 else n := by + split <;> fin_omega + section OfNatCoe @[simp] -theorem ofNat''_eq_cast (n : ℕ) [NeZero n] (a : ℕ) : (Fin.ofNat'' a : Fin n) = a := +theorem ofNat'_eq_cast (n : ℕ) [NeZero n] (a : ℕ) : Fin.ofNat' n a = a := rfl @[simp] lemma val_natCast (a n : ℕ) [NeZero n] : (a : Fin n).val = a % n := rfl @@ -631,6 +623,9 @@ theorem leftInverse_cast (eq : n = m) : LeftInverse (cast eq.symm) (cast eq) := theorem rightInverse_cast (eq : n = m) : RightInverse (cast eq.symm) (cast eq) := fun _ => rfl +theorem cast_lt_cast (eq : n = m) {a b : Fin n} : cast eq a < cast eq b ↔ a < b := + Iff.rfl + theorem cast_le_cast (eq : n = m) {a b : Fin n} : cast eq a ≤ cast eq b ↔ a ≤ b := Iff.rfl @@ -680,13 +675,14 @@ def castSuccEmb : Fin n ↪ Fin (n + 1) := castAddEmb _ @[simp, norm_cast] lemma coe_castSuccEmb : (castSuccEmb : Fin n → Fin (n + 1)) = Fin.castSucc := rfl -@[simp] -theorem castSucc_le_castSucc_iff {a b : Fin n} : castSucc a ≤ castSucc b ↔ a ≤ b := Iff.rfl -@[simp] -theorem succ_le_castSucc_iff {a b : Fin n} : succ a ≤ castSucc b ↔ a < b := by +theorem castSucc_le_succ {n} (i : Fin n) : i.castSucc ≤ i.succ := Nat.le_succ i + +@[simp] theorem castSucc_le_castSucc_iff {a b : Fin n} : castSucc a ≤ castSucc b ↔ a ≤ b := .rfl + +@[simp] theorem succ_le_castSucc_iff {a b : Fin n} : succ a ≤ castSucc b ↔ a < b := by rw [le_castSucc_iff, succ_lt_succ_iff] -@[simp] -theorem castSucc_lt_succ_iff {a b : Fin n} : castSucc a < succ b ↔ a ≤ b := by + +@[simp] theorem castSucc_lt_succ_iff {a b : Fin n} : castSucc a < succ b ↔ a ≤ b := by rw [castSucc_lt_iff_succ_le, succ_le_succ_iff] theorem le_of_castSucc_lt_of_succ_lt {a b : Fin (n + 1)} {i : Fin n} diff --git a/Mathlib/Data/Fin/Tuple/Basic.lean b/Mathlib/Data/Fin/Tuple/Basic.lean index e4cb2370272a7..81cd43b8a59f1 100644 --- a/Mathlib/Data/Fin/Tuple/Basic.lean +++ b/Mathlib/Data/Fin/Tuple/Basic.lean @@ -195,7 +195,7 @@ theorem consCases_cons {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ def consInduction {α : Sort*} {P : ∀ {n : ℕ}, (Fin n → α) → Sort v} (h0 : P Fin.elim0) (h : ∀ {n} (x₀) (x : Fin n → α), P x → P (Fin.cons x₀ x)) : ∀ {n : ℕ} (x : Fin n → α), P x | 0, x => by convert h0 - | n + 1, x => consCases (fun x₀ x ↦ h _ _ <| consInduction h0 h _) x + | _ + 1, x => consCases (fun _ _ ↦ h _ _ <| consInduction h0 h _) x theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x) (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by @@ -394,6 +394,11 @@ lemma append_comp_rev {m n} (xs : Fin m → α) (ys : Fin n → α) : append xs ys ∘ rev = append (ys ∘ rev) (xs ∘ rev) ∘ cast (Nat.add_comm ..) := funext <| append_rev xs ys +theorem append_castAdd_natAdd {f : Fin (m + n) → α} : + append (fun i ↦ f (castAdd n i)) (fun i ↦ f (natAdd m i)) = f := by + unfold append addCases + simp + end Append section Repeat @@ -710,7 +715,7 @@ def snocInduction {α : Sort*} (h0 : P Fin.elim0) (h : ∀ {n} (x : Fin n → α) (x₀), P x → P (Fin.snoc x x₀)) : ∀ {n : ℕ} (x : Fin n → α), P x | 0, x => by convert h0 - | n + 1, x => snocCases (fun x₀ x ↦ h _ _ <| snocInduction h0 h _) x + | _ + 1, x => snocCases (fun _ _ ↦ h _ _ <| snocInduction h0 h _) x end TupleRight @@ -790,7 +795,7 @@ theorem insertNth_apply_succAbove (i : Fin (n + 1)) (x : α i) (p : ∀ j, α (i intro; rfl · generalize_proofs H₀ H₁ H₂; revert H₂ generalize hk : pred (succAbove i j) H₁ = k - erw [pred_succAbove _ _ (Fin.not_lt.1 hlt)] at hk; cases hk + rw [pred_succAbove _ _ (Fin.not_lt.1 hlt)] at hk; cases hk intro; rfl @[simp] @@ -947,7 +952,7 @@ def find : ∀ {n : ℕ} (p : Fin n → Prop) [DecidablePred p], Option (Fin n) /-- If `find p = some i`, then `p i` holds -/ theorem find_spec : ∀ {n : ℕ} (p : Fin n → Prop) [DecidablePred p] {i : Fin n} (_ : i ∈ Fin.find p), p i - | 0, p, I, i, hi => Option.noConfusion hi + | 0, _, _, _, hi => Option.noConfusion hi | n + 1, p, I, i, hi => by rw [find] at hi cases' h : find fun i : Fin n ↦ p (i.castLT (Nat.lt_succ_of_lt i.2)) with j @@ -965,7 +970,7 @@ theorem find_spec : /-- `find p` does not return `none` if and only if `p i` holds at some index `i`. -/ theorem isSome_find_iff : ∀ {n : ℕ} {p : Fin n → Prop} [DecidablePred p], (find p).isSome ↔ ∃ i, p i - | 0, p, _ => iff_of_false (fun h ↦ Bool.noConfusion h) fun ⟨i, _⟩ ↦ Fin.elim0 i + | 0, _, _ => iff_of_false (fun h ↦ Bool.noConfusion h) fun ⟨i, _⟩ ↦ Fin.elim0 i | n + 1, p, _ => ⟨fun h ↦ by rw [Option.isSome_iff_exists] at h @@ -990,7 +995,7 @@ the indices where `p` holds. -/ theorem find_min : ∀ {n : ℕ} {p : Fin n → Prop} [DecidablePred p] {i : Fin n} (_ : i ∈ Fin.find p) {j : Fin n} (_ : j < i), ¬p j - | 0, p, _, i, hi, _, _, _ => Option.noConfusion hi + | 0, _, _, _, hi, _, _, _ => Option.noConfusion hi | n + 1, p, _, i, hi, ⟨j, hjn⟩, hj, hpj => by rw [find] at hi cases' h : find fun i : Fin n ↦ p (i.castLT (Nat.lt_succ_of_lt i.2)) with k diff --git a/Mathlib/Data/Fin/Tuple/BubbleSortInduction.lean b/Mathlib/Data/Fin/Tuple/BubbleSortInduction.lean index 3e674c79d4206..514e9a2bdf59f 100644 --- a/Mathlib/Data/Fin/Tuple/BubbleSortInduction.lean +++ b/Mathlib/Data/Fin/Tuple/BubbleSortInduction.lean @@ -6,6 +6,7 @@ Authors: Michael Stoll import Mathlib.Data.Fin.Tuple.Sort import Mathlib.Order.WellFounded import Mathlib.Order.PiLex +import Mathlib.Data.Finite.Prod /-! # "Bubble sort" induction diff --git a/Mathlib/Data/Fin/Tuple/Finset.lean b/Mathlib/Data/Fin/Tuple/Finset.lean index d376279817e25..7c012e3737704 100644 --- a/Mathlib/Data/Fin/Tuple/Finset.lean +++ b/Mathlib/Data/Fin/Tuple/Finset.lean @@ -57,33 +57,48 @@ namespace Finset variable {n : ℕ} {α : Fin (n + 1) → Type*} {p : Fin (n + 1)} (S : ∀ i, Finset (α i)) lemma map_consEquiv_filter_piFinset (P : (∀ i, α (succ i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| tail r).map (consEquiv α).symm.toEmbedding = - S 0 ×ˢ (piFinset fun x ↦ S <| succ x).filter P := by + {r ∈ piFinset S | P (tail r)}.map (consEquiv α).symm.toEmbedding = + S 0 ×ˢ {r ∈ piFinset (tail S) | P r} := by unfold tail; ext; simp [Fin.forall_iff_succ, and_assoc] lemma map_snocEquiv_filter_piFinset (P : (∀ i, α (castSucc i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| init r).map (snocEquiv α).symm.toEmbedding = - S (last _) ×ˢ (piFinset <| init S).filter P := by + {r ∈ piFinset S | P (init r)}.map (snocEquiv α).symm.toEmbedding = + S (last _) ×ˢ {r ∈ piFinset (init S) | P r} := by unfold init; ext; simp [Fin.forall_iff_castSucc, and_assoc] lemma map_insertNthEquiv_filter_piFinset (P : (∀ i, α (p.succAbove i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| p.removeNth r).map (p.insertNthEquiv α).symm.toEmbedding = - S p ×ˢ (piFinset <| p.removeNth S).filter P := by + {r ∈ piFinset S | P (p.removeNth r)}.map (p.insertNthEquiv α).symm.toEmbedding = + S p ×ˢ {r ∈ piFinset (p.removeNth S) | P r} := by unfold removeNth; ext; simp [Fin.forall_iff_succAbove p, and_assoc] +lemma filter_piFinset_eq_map_consEquiv (P : (∀ i, α (succ i)) → Prop) [DecidablePred P] : + {r ∈ piFinset S | P (tail r)} = + (S 0 ×ˢ {r ∈ piFinset (tail S) | P r}).map (consEquiv α).toEmbedding := by + simp [← map_consEquiv_filter_piFinset, map_map] + +lemma filter_piFinset_eq_map_snocEquiv (P : (∀ i, α (castSucc i)) → Prop) [DecidablePred P] : + {r ∈ piFinset S | P (init r)} = + (S (last _) ×ˢ {r ∈ piFinset (init S) | P r}).map (snocEquiv α).toEmbedding := by + simp [← map_snocEquiv_filter_piFinset, map_map] + +lemma filter_piFinset_eq_map_insertNthEquiv (P : (∀ i, α (p.succAbove i)) → Prop) + [DecidablePred P] : + {r ∈ piFinset S | P (p.removeNth r)} = + (S p ×ˢ {r ∈ piFinset (p.removeNth S) | P r}).map (p.insertNthEquiv α).toEmbedding := by + simp [← map_insertNthEquiv_filter_piFinset, map_map] + lemma card_consEquiv_filter_piFinset (P : (∀ i, α (succ i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| tail r).card = - (S 0).card * ((piFinset fun x ↦ S <| succ x).filter P).card := by + {r ∈ piFinset S | P (tail r)}.card = (S 0).card * {r ∈ piFinset (tail S) | P r}.card := by rw [← card_product, ← map_consEquiv_filter_piFinset, card_map] lemma card_snocEquiv_filter_piFinset (P : (∀ i, α (castSucc i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| init r).card = - (S (last _)).card * ((piFinset <| init S).filter P).card := by + {r ∈ piFinset S | P (init r)}.card = + (S (last _)).card * {r ∈ piFinset (init S) | P r}.card := by rw [← card_product, ← map_snocEquiv_filter_piFinset, card_map] lemma card_insertNthEquiv_filter_piFinset (P : (∀ i, α (p.succAbove i)) → Prop) [DecidablePred P] : - ((piFinset S).filter fun r ↦ P <| p.removeNth r).card = - (S p).card * ((piFinset <| p.removeNth S).filter P).card := by + {r ∈ piFinset S | P (p.removeNth r)}.card = + (S p).card * {r ∈ piFinset (p.removeNth S) | P r}.card := by rw [← card_product, ← map_insertNthEquiv_filter_piFinset, card_map] end Finset diff --git a/Mathlib/Data/Fin/Tuple/Reflection.lean b/Mathlib/Data/Fin/Tuple/Reflection.lean index 2caca583ee4d8..d0d93cedb5255 100644 --- a/Mathlib/Data/Fin/Tuple/Reflection.lean +++ b/Mathlib/Data/Fin/Tuple/Reflection.lean @@ -30,7 +30,7 @@ corresponding `*_eq` lemmas to be used in a place where they are definitionally namespace FinVec -variable {m n : ℕ} {α β γ : Type*} +variable {m : ℕ} {α β : Type*} /-- Evaluate `FinVec.seq f v = ![(f 0) (v 0), (f 1) (v 1), ...]` -/ def seq : ∀ {m}, (Fin m → α → β) → (Fin m → α) → Fin m → β @@ -39,7 +39,7 @@ def seq : ∀ {m}, (Fin m → α → β) → (Fin m → α) → Fin m → β @[simp] theorem seq_eq : ∀ {m} (f : Fin m → α → β) (v : Fin m → α), seq f v = fun i => f i (v i) - | 0, f, v => Subsingleton.elim _ _ + | 0, _, _ => Subsingleton.elim _ _ | n + 1, f, v => funext fun i => by simp_rw [seq, seq_eq] @@ -140,7 +140,7 @@ example [AddCommMonoid α] (a : Fin 3 → α) : ∑ i, a i = a 0 + a 1 + a 2 := -/ @[simp] theorem sum_eq [AddCommMonoid α] : ∀ {m} (a : Fin m → α), sum a = ∑ i, a i - | 0, a => rfl + | 0, _ => rfl | 1, a => (Fintype.sum_unique a).symm | n + 2, a => by rw [Fin.sum_univ_castSucc, sum, sum_eq] diff --git a/Mathlib/Data/Fin/Tuple/Sort.lean b/Mathlib/Data/Fin/Tuple/Sort.lean index 6dfe8a11de7e8..0823fab46883a 100644 --- a/Mathlib/Data/Fin/Tuple/Sort.lean +++ b/Mathlib/Data/Fin/Tuple/Sort.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Mathlib.Data.Finset.Sort +import Mathlib.Data.Fintype.Sum import Mathlib.Data.List.FinRange import Mathlib.Data.Prod.Lex import Mathlib.GroupTheory.Perm.Basic diff --git a/Mathlib/Data/Fin/Tuple/Take.lean b/Mathlib/Data/Fin/Tuple/Take.lean new file mode 100644 index 0000000000000..1ff923b04788e --- /dev/null +++ b/Mathlib/Data/Fin/Tuple/Take.lean @@ -0,0 +1,168 @@ +/- +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 + +/-! +# Take operations on tuples + +We define the `take` operation on `n`-tuples, which restricts a tuple to its first `m` elements. + +* `Fin.take`: Given `h : m ≤ n`, `Fin.take m h v` for a `n`-tuple `v = (v 0, ..., v (n - 1))` is the + `m`-tuple `(v 0, ..., v (m - 1))`. +-/ + +namespace Fin + +open Function + +variable {n : ℕ} {α : Fin n → Sort*} + +section Take + +/-- Take the first `m` elements of an `n`-tuple where `m ≤ n`, returning an `m`-tuple. -/ +def take (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) : (i : Fin m) → α (castLE h i) := + fun i ↦ v (castLE h i) + +@[simp] +theorem take_apply (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) (i : Fin m) : + (take m h v) i = v (castLE h i) := rfl + +@[simp] +theorem take_zero (v : (i : Fin n) → α i) : take 0 n.zero_le v = fun i ↦ elim0 i := by + ext i; exact elim0 i + +@[simp] +theorem take_one {α : Fin (n + 1) → Sort*} (v : (i : Fin (n + 1)) → α i) : + take 1 (Nat.le_add_left 1 n) v = (fun i => v (castLE (Nat.le_add_left 1 n) i)) := by + ext i + simp only [take] + +@[simp] +theorem take_eq_init {α : Fin (n + 1) → Sort*} (v : (i : Fin (n + 1)) → α i) : + take n n.le_succ v = init v := by + ext i + simp only [Nat.succ_eq_add_one, take, init] + congr + +@[simp] +theorem take_eq_self (v : (i : Fin n) → α i) : take n (le_refl n) v = v := by + ext i + simp [take] + +@[simp] +theorem take_take {m n' : ℕ} (h : m ≤ n') (h' : n' ≤ n) (v : (i : Fin n) → α i) : + take m h (take n' h' v) = take m (Nat.le_trans h h') v := by + ext i + simp only [take] + congr + +@[simp] +theorem take_init {α : Fin (n + 1) → Sort*} (m : ℕ) (h : m ≤ n) (v : (i : Fin (n + 1)) → α i) : + take m h (init v) = take m (Nat.le_succ_of_le h) v := by + ext i + simp only [take, init] + congr + +theorem take_repeat {α : Type*} {n' : ℕ} (m : ℕ) (h : m ≤ n) (a : Fin n' → α) : + take (m * n') (Nat.mul_le_mul_right n' h) (Fin.repeat n a) = Fin.repeat m a := by + ext i + simp only [take, repeat_apply, modNat, coe_castLE] + +/-- Taking `m + 1` elements is equal to taking `m` elements and adding the `(m + 1)`th one. -/ +theorem take_succ_eq_snoc (m : ℕ) (h : m < n) (v : (i : Fin n) → α i) : + take m.succ h v = snoc (take m h.le v) (v ⟨m, h⟩) := by + ext i + induction m with + | zero => + have h' : i = 0 := by ext; simp + subst h' + simp [take, snoc, castLE] + | succ m _ => + induction i using reverseInduction with + | last => simp [take, snoc, castLT]; congr + | cast i _ => simp [snoc_cast_add] + +/-- `take` commutes with `update` for indices in the range of `take`. -/ +@[simp] +theorem take_update_of_lt (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) (i : Fin m) + (x : α (castLE h i)) : take m h (update v (castLE h i) x) = update (take m h v) i x := by + ext j + by_cases h' : j = i + · rw [h'] + simp only [take, update_same] + · have : castLE h j ≠ castLE h i := by simp [h'] + simp only [take, update_noteq h', update_noteq this] + +/-- `take` is the same after `update` for indices outside the range of `take`. -/ +@[simp] +theorem take_update_of_ge (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) (i : Fin n) (hi : i ≥ m) + (x : α i) : take m h (update v i x) = take m h v := by + ext j + have : castLE h j ≠ i := by + refine ne_of_val_ne ?_ + simp only [coe_castLE] + exact Nat.ne_of_lt (lt_of_lt_of_le j.isLt hi) + simp only [take, update_noteq this] + +/-- Taking the first `m ≤ n` elements of an `addCases u v`, where `u` is a `n`-tuple, is the same as +taking the first `m` elements of `u`. -/ +theorem take_addCases_left {n' : ℕ} {motive : Fin (n + n') → Sort*} (m : ℕ) (h : m ≤ n) + (u : (i : Fin n) → motive (castAdd n' i)) (v : (i : Fin n') → motive (natAdd n i)) : + take m (Nat.le_add_right_of_le h) (addCases u v) = take m h u := by + ext i + have : i < n := Nat.lt_of_lt_of_le i.isLt h + simp only [take, addCases, this, coe_castLE, ↓reduceDIte] + congr + +/-- Version of `take_addCases_left` that specializes `addCases` to `append`. -/ +theorem take_append_left {n' : ℕ} {α : Sort*} (m : ℕ) (h : m ≤ n) (u : (i : Fin n) → α) + (v : (i : Fin n') → α) : take m (Nat.le_add_right_of_le h) (append u v) = take m h u := + take_addCases_left m h _ _ + +/-- Taking the first `n + m` elements of an `addCases u v`, where `v` is a `n'`-tuple and `m ≤ n'`, +is the same as appending `u` with the first `m` elements of `v`. -/ +theorem take_addCases_right {n' : ℕ} {motive : Fin (n + n') → Sort*} (m : ℕ) (h : m ≤ n') + (u : (i : Fin n) → motive (castAdd n' i)) (v : (i : Fin n') → motive (natAdd n i)) : + take (n + m) (Nat.add_le_add_left h n) (addCases u v) = addCases u (take m h v) := by + ext i + simp only [take, addCases, coe_castLE] + by_cases h' : i < n + · simp only [h', ↓reduceDIte] + congr + · simp only [h', ↓reduceDIte, subNat, castLE, cast, eqRec_eq_cast] + +/-- Version of `take_addCases_right` that specializes `addCases` to `append`. -/ +theorem take_append_right {n' : ℕ} {α : Sort*} (m : ℕ) (h : m ≤ n') (u : (i : Fin n) → α) + (v : (i : Fin n') → α) : take (n + m) (Nat.add_le_add_left h n) (append u v) + = append u (take m h v) := + take_addCases_right m h _ _ + +/-- `Fin.take` intertwines with `List.take` via `List.ofFn`. -/ +theorem ofFn_take_eq_take_ofFn {α : Type*} {m : ℕ} (h : m ≤ n) (v : Fin n → α) : + List.ofFn (take m h v) = (List.ofFn v).take m := + List.ext_get (by simp [h]) (fun n h1 h2 => by simp) + +/-- Alternative version of `take_eq_take_list_ofFn` with `l : List α` instead of `v : Fin n → α`. -/ +theorem ofFn_take_get {α : Type*} {m : ℕ} (l : List α) (h : m ≤ l.length) : + List.ofFn (take m h l.get) = l.take m := + List.ext_get (by simp [h]) (fun n h1 h2 => by simp) + +/-- `Fin.take` intertwines with `List.take` via `List.get`. -/ +theorem get_take_eq_take_get_comp_cast {α : Type*} {m : ℕ} (l : List α) (h : m ≤ l.length) : + (l.take m).get = take m h l.get ∘ Fin.cast (List.length_take_of_le h) := by + ext i + simp only [List.get_eq_getElem, List.getElem_take, comp_apply, take_apply, coe_castLE, coe_cast] + +/-- Alternative version of `take_eq_take_list_get` with `v : Fin n → α` instead of `l : List α`. -/ +theorem get_take_ofFn_eq_take_comp_cast {α : Type*} {m : ℕ} (v : Fin n → α) (h : m ≤ n) : + ((List.ofFn v).take m).get = take m h v ∘ Fin.cast (by simp [h]) := by + ext i + simp [castLE] + +end Take + +end Fin diff --git a/Mathlib/Data/Fin/VecNotation.lean b/Mathlib/Data/Fin/VecNotation.lean index d3b561640f0ae..9d31131cdaf6e 100644 --- a/Mathlib/Data/Fin/VecNotation.lean +++ b/Mathlib/Data/Fin/VecNotation.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.Data.Fin.Tuple.Basic -import Mathlib.Data.List.Range +import Mathlib.Data.List.Defs /-! # Matrix and vector notation @@ -108,7 +108,7 @@ instance _root_.PiFin.hasRepr [Repr α] : Repr (Fin n → α) where end MatrixNotation -variable {m n o : ℕ} {m' n' o' : Type*} +variable {m n o : ℕ} theorem empty_eq (v : Fin 0 → α) : v = ![] := Subsingleton.elim _ _ @@ -160,11 +160,10 @@ theorem range_cons (x : α) (u : Fin n → α) : Set.range (vecCons x u) = {x} theorem range_empty (u : Fin 0 → α) : Set.range u = ∅ := Set.range_eq_empty _ --- @[simp] -- Porting note (#10618): simp can prove this theorem range_cons_empty (x : α) (u : Fin 0 → α) : Set.range (Matrix.vecCons x u) = {x} := by rw [range_cons, range_empty, Set.union_empty] --- @[simp] -- Porting note (#10618): simp can prove this (up to commutativity) +-- simp can prove this (up to commutativity) 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] diff --git a/Mathlib/Data/FinEnum.lean b/Mathlib/Data/FinEnum.lean index c2d94fcfa23ad..f4a3ae5c5e0e2 100644 --- a/Mathlib/Data/FinEnum.lean +++ b/Mathlib/Data/FinEnum.lean @@ -138,7 +138,7 @@ instance PSigma.finEnum [FinEnum α] [∀ a, FinEnum (β a)] : FinEnum (Σ'a, β instance PSigma.finEnumPropLeft {α : Prop} {β : α → Type v} [∀ a, FinEnum (β a)] [Decidable α] : FinEnum (Σ'a, β a) := if h : α then ofList ((toList (β h)).map <| PSigma.mk h) fun ⟨a, Ba⟩ => by simp - else ofList [] fun ⟨a, Ba⟩ => (h a).elim + else ofList [] fun ⟨a, _⟩ => (h a).elim instance PSigma.finEnumPropRight {β : α → Prop} [FinEnum α] [∀ a, Decidable (β a)] : FinEnum (Σ'a, β a) := diff --git a/Mathlib/Data/Finite/Basic.lean b/Mathlib/Data/Finite/Basic.lean deleted file mode 100644 index fdc0bab1f42de..0000000000000 --- a/Mathlib/Data/Finite/Basic.lean +++ /dev/null @@ -1,138 +0,0 @@ -/- -Copyright (c) 2022 Kyle Miller. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kyle Miller --/ -import Mathlib.Data.Fintype.Powerset -import Mathlib.Data.Fintype.Prod -import Mathlib.Data.Fintype.Sigma -import Mathlib.Data.Fintype.Sum -import Mathlib.Data.Fintype.Vector - -/-! -# Finite types - -In this file we prove some theorems about `Finite` and provide some instances. This typeclass is a -`Prop`-valued counterpart of the typeclass `Fintype`. See more details in the file where `Finite` is -defined. - -## Main definitions - -* `Fintype.finite`, `Finite.of_fintype` creates a `Finite` instance from a `Fintype` instance. The - former lemma takes `Fintype α` as an explicit argument while the latter takes it as an instance - argument. -* `Fintype.of_finite` noncomputably creates a `Fintype` instance from a `Finite` instance. - -## Implementation notes - -There is an apparent duplication of many `Fintype` instances in this module, -however they follow a pattern: if a `Fintype` instance depends on `Decidable` -instances or other `Fintype` instances, then we need to "lower" the instance -to be a `Finite` instance by removing the `Decidable` instances and switching -the `Fintype` instances to `Finite` instances. These are precisely the ones -that cannot be inferred using `Finite.of_fintype`. (However, when using -`open scoped Classical` or the `classical` tactic the instances relying only -on `Decidable` instances will give `Finite` instances.) In the future we might -consider writing automation to create these "lowered" instances. - -## Tags - -finiteness, finite types --/ - -open Mathlib - -noncomputable section - -open scoped Classical - -variable {α β γ : Type*} - -namespace Finite - --- see Note [lower instance priority] -instance (priority := 100) of_subsingleton {α : Sort*} [Subsingleton α] : Finite α := - of_injective (Function.const α ()) <| Function.injective_of_subsingleton _ - --- Higher priority for `Prop`s --- Porting note(#12096): removed @[nolint instance_priority], linter not ported yet -instance prop (p : Prop) : Finite p := - Finite.of_subsingleton - -instance [Finite α] [Finite β] : Finite (α × β) := by - haveI := Fintype.ofFinite α - haveI := Fintype.ofFinite β - infer_instance - -instance {α β : Sort*} [Finite α] [Finite β] : Finite (PProd α β) := - of_equiv _ Equiv.pprodEquivProdPLift.symm - -theorem prod_left (β) [Finite (α × β)] [Nonempty β] : Finite α := - of_surjective (Prod.fst : α × β → α) Prod.fst_surjective - -theorem prod_right (α) [Finite (α × β)] [Nonempty α] : Finite β := - of_surjective (Prod.snd : α × β → β) Prod.snd_surjective - -instance [Finite α] [Finite β] : Finite (α ⊕ β) := by - haveI := Fintype.ofFinite α - haveI := Fintype.ofFinite β - infer_instance - -theorem sum_left (β) [Finite (α ⊕ β)] : Finite α := - of_injective (Sum.inl : α → α ⊕ β) Sum.inl_injective - -theorem sum_right (α) [Finite (α ⊕ β)] : Finite β := - of_injective (Sum.inr : β → α ⊕ β) Sum.inr_injective - -instance {β : α → Type*} [Finite α] [∀ a, Finite (β a)] : Finite (Σa, β a) := by - letI := Fintype.ofFinite α - letI := fun a => Fintype.ofFinite (β a) - infer_instance - -instance {ι : Sort*} {π : ι → Sort*} [Finite ι] [∀ i, Finite (π i)] : Finite (Σ'i, π i) := - of_equiv _ (Equiv.psigmaEquivSigmaPLift π).symm - -instance [Finite α] : Finite (Set α) := by - cases nonempty_fintype α - infer_instance - -end Finite - -instance Pi.finite {α : Sort*} {β : α → Sort*} [Finite α] [∀ a, Finite (β a)] : - Finite (∀ a, β a) := by - haveI := Fintype.ofFinite (PLift α) - haveI := fun a => Fintype.ofFinite (PLift (β a)) - exact - Finite.of_equiv (∀ a : PLift α, PLift (β (Equiv.plift a))) - (Equiv.piCongr Equiv.plift fun _ => Equiv.plift) - -instance Vector.finite {α : Type*} [Finite α] {n : ℕ} : Finite (Vector α n) := by - haveI := Fintype.ofFinite α - infer_instance - -instance Quot.finite {α : Sort*} [Finite α] (r : α → α → Prop) : Finite (Quot r) := - Finite.of_surjective _ (surjective_quot_mk r) - -instance Quotient.finite {α : Sort*} [Finite α] (s : Setoid α) : Finite (Quotient s) := - Quot.finite _ - -instance Function.Embedding.finite {α β : Sort*} [Finite β] : Finite (α ↪ β) := by - cases' isEmpty_or_nonempty (α ↪ β) with _ h - · -- Porting note: infer_instance fails because it applies `Finite.of_fintype` and produces a - -- "stuck at solving universe constraint" error. - apply Finite.of_subsingleton - - · refine h.elim fun f => ?_ - haveI : Finite α := Finite.of_injective _ f.injective - exact Finite.of_injective _ DFunLike.coe_injective - -instance Equiv.finite_right {α β : Sort*} [Finite β] : Finite (α ≃ β) := - Finite.of_injective Equiv.toEmbedding fun e₁ e₂ h => Equiv.ext <| by - convert DFunLike.congr_fun h using 0 - -instance Equiv.finite_left {α β : Sort*} [Finite α] : Finite (α ≃ β) := - Finite.of_equiv _ ⟨Equiv.symm, Equiv.symm, Equiv.symm_symm, Equiv.symm_symm⟩ - -instance [Finite α] {n : ℕ} : Finite (Sym α n) := by - haveI := Fintype.ofFinite α - infer_instance diff --git a/Mathlib/Data/Finite/Card.lean b/Mathlib/Data/Finite/Card.lean index c16b94bbcd01b..fb6afe0f1c2f9 100644 --- a/Mathlib/Data/Finite/Card.lean +++ b/Mathlib/Data/Finite/Card.lean @@ -43,7 +43,7 @@ def Finite.equivFinOfCardEq [Finite α] {n : ℕ} (h : Nat.card α = n) : α ≃ apply Finite.equivFin theorem Nat.card_eq (α : Type*) : - Nat.card α = if h : Finite α then @Fintype.card α (Fintype.ofFinite α) else 0 := by + 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] @@ -181,7 +181,7 @@ theorem card_union_le (s t : Set α) : Nat.card (↥(s ∪ t)) ≤ Nat.card s + cases' _root_.finite_or_infinite (↥(s ∪ t)) with h h · rw [finite_coe_iff, finite_union, ← finite_coe_iff, ← finite_coe_iff] at h cases h - rw [← Cardinal.natCast_le, Nat.cast_add, Finite.cast_card_eq_mk, Finite.cast_card_eq_mk, + rw [← @Nat.cast_le Cardinal, Nat.cast_add, Finite.cast_card_eq_mk, Finite.cast_card_eq_mk, Finite.cast_card_eq_mk] exact Cardinal.mk_union_le s t · exact Nat.card_eq_zero_of_infinite.trans_le (zero_le _) diff --git a/Mathlib/Data/Finite/Powerset.lean b/Mathlib/Data/Finite/Powerset.lean new file mode 100644 index 0000000000000..d505de253c6e8 --- /dev/null +++ b/Mathlib/Data/Finite/Powerset.lean @@ -0,0 +1,20 @@ +/- +Copyright (c) 2022 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +import Mathlib.Data.Fintype.Powerset + +/-! +# Finiteness of powersets +-/ + +variable {α : Type*} + +namespace Finite + +instance [Finite α] : Finite (Set α) := by + cases nonempty_fintype α + infer_instance + +end Finite diff --git a/Mathlib/Data/Finite/Prod.lean b/Mathlib/Data/Finite/Prod.lean new file mode 100644 index 0000000000000..4fd2053d88f57 --- /dev/null +++ b/Mathlib/Data/Finite/Prod.lean @@ -0,0 +1,62 @@ +/- +Copyright (c) 2022 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +import Mathlib.Data.Fintype.Prod +import Mathlib.Data.Fintype.Vector + +/-! +# Finiteness of products +-/ + +open scoped Classical + +variable {α β : Type*} + +namespace Finite + +instance [Finite α] [Finite β] : Finite (α × β) := by + haveI := Fintype.ofFinite α + haveI := Fintype.ofFinite β + infer_instance + +instance {α β : Sort*} [Finite α] [Finite β] : Finite (PProd α β) := + of_equiv _ Equiv.pprodEquivProdPLift.symm + +theorem prod_left (β) [Finite (α × β)] [Nonempty β] : Finite α := + of_surjective (Prod.fst : α × β → α) Prod.fst_surjective + +theorem prod_right (α) [Finite (α × β)] [Nonempty α] : Finite β := + of_surjective (Prod.snd : α × β → β) Prod.snd_surjective + +end Finite + +instance Pi.finite {α : Sort*} {β : α → Sort*} [Finite α] [∀ a, Finite (β a)] : + Finite (∀ a, β a) := by + haveI := Fintype.ofFinite (PLift α) + haveI := fun a => Fintype.ofFinite (PLift (β a)) + exact + Finite.of_equiv (∀ a : PLift α, PLift (β (Equiv.plift a))) + (Equiv.piCongr Equiv.plift fun _ => Equiv.plift) + +instance [Finite α] {n : ℕ} : Finite (Sym α n) := by + haveI := Fintype.ofFinite α + infer_instance + +instance Function.Embedding.finite {α β : Sort*} [Finite β] : Finite (α ↪ β) := by + cases' isEmpty_or_nonempty (α ↪ β) with _ h + · -- Porting note: infer_instance fails because it applies `Finite.of_fintype` and produces a + -- "stuck at solving universe constraint" error. + apply Finite.of_subsingleton + + · refine h.elim fun f => ?_ + haveI : Finite α := Finite.of_injective _ f.injective + exact Finite.of_injective _ DFunLike.coe_injective + +instance Equiv.finite_right {α β : Sort*} [Finite β] : Finite (α ≃ β) := + Finite.of_injective Equiv.toEmbedding fun e₁ e₂ h => Equiv.ext <| by + convert DFunLike.congr_fun h using 0 + +instance Equiv.finite_left {α β : Sort*} [Finite α] : Finite (α ≃ β) := + Finite.of_equiv _ ⟨Equiv.symm, Equiv.symm, Equiv.symm_symm, Equiv.symm_symm⟩ diff --git a/Mathlib/Data/Finite/Sigma.lean b/Mathlib/Data/Finite/Sigma.lean new file mode 100644 index 0000000000000..487abd57fc007 --- /dev/null +++ b/Mathlib/Data/Finite/Sigma.lean @@ -0,0 +1,25 @@ +/- +Copyright (c) 2022 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +import Mathlib.Data.Fintype.Sigma +import Mathlib.Data.Fintype.Card + +/-! +# Finiteness of sigma types +-/ + +variable {α : Type*} + +namespace Finite + +instance {β : α → Type*} [Finite α] [∀ a, Finite (β a)] : Finite (Σa, β a) := by + letI := Fintype.ofFinite α + letI := fun a => Fintype.ofFinite (β a) + infer_instance + +instance {ι : Sort*} {π : ι → Sort*} [Finite ι] [∀ i, Finite (π i)] : Finite (Σ'i, π i) := + of_equiv _ (Equiv.psigmaEquivSigmaPLift π).symm + +end Finite diff --git a/Mathlib/Data/Finite/Sum.lean b/Mathlib/Data/Finite/Sum.lean new file mode 100644 index 0000000000000..177f8e038134a --- /dev/null +++ b/Mathlib/Data/Finite/Sum.lean @@ -0,0 +1,27 @@ +/- +Copyright (c) 2022 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +import Mathlib.Data.Fintype.Sum + +/-! +# Finiteness of sum types +-/ + +variable {α β : Type*} + +namespace Finite + +instance [Finite α] [Finite β] : Finite (α ⊕ β) := by + haveI := Fintype.ofFinite α + haveI := Fintype.ofFinite β + infer_instance + +theorem sum_left (β) [Finite (α ⊕ β)] : Finite α := + of_injective (Sum.inl : α → α ⊕ β) Sum.inl_injective + +theorem sum_right (α) [Finite (α ⊕ β)] : Finite β := + of_injective (Sum.inr : β → α ⊕ β) Sum.inr_injective + +end Finite diff --git a/Mathlib/Data/Finite/Vector.lean b/Mathlib/Data/Finite/Vector.lean new file mode 100644 index 0000000000000..9beba5adef683 --- /dev/null +++ b/Mathlib/Data/Finite/Vector.lean @@ -0,0 +1,15 @@ +/- +Copyright (c) 2022 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +import Mathlib.Data.Fintype.Vector +import Mathlib.Data.Fintype.Card + +/-! +# Finiteness of vector types +-/ + +instance Mathlib.Vector.finite {α : Type*} [Finite α] {n : ℕ} : Finite (Vector α n) := by + haveI := Fintype.ofFinite α + infer_instance diff --git a/Mathlib/Data/Finmap.lean b/Mathlib/Data/Finmap.lean index 770bb27ffee01..0b0ae8a95ac49 100644 --- a/Mathlib/Data/Finmap.lean +++ b/Mathlib/Data/Finmap.lean @@ -88,7 +88,6 @@ lemma nodup_entries (f : Finmap β) : f.entries.Nodup := f.nodupKeys.nodup /-! ### Lifting from AList -/ /-- Lift a permutation-respecting function on `AList` to `Finmap`. -/ --- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type def liftOn {γ} (s : Finmap β) (f : AList β → γ) (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by refine @@ -108,11 +107,10 @@ theorem liftOn_toFinmap {γ} (s : AList β) (f : AList β → γ) (H) : liftOn rfl /-- Lift a permutation-respecting function on 2 `AList`s to 2 `Finmap`s. -/ --- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type def liftOn₂ {γ} (s₁ s₂ : Finmap β) (f : AList β → AList β → γ) (H : ∀ a₁ b₁ a₂ b₂ : AList β, a₁.entries ~ a₂.entries → b₁.entries ~ b₂.entries → f a₁ b₁ = f a₂ b₂) : γ := - liftOn s₁ (fun l₁ => liftOn s₂ (f l₁) fun b₁ b₂ p => H _ _ _ _ (Perm.refl _) p) fun a₁ a₂ p => by + liftOn s₁ (fun l₁ => liftOn s₂ (f l₁) fun _ _ p => H _ _ _ _ (Perm.refl _) p) fun a₁ a₂ p => by have H' : f a₁ = f a₂ := funext fun _ => H _ _ _ _ p (Perm.refl _) simp only [H'] @@ -515,7 +513,12 @@ theorem lookup_union_left_of_not_in {a} {s₁ s₂ : Finmap β} (h : a ∉ s₂) · rw [lookup_union_left h'] · rw [lookup_union_right h', lookup_eq_none.mpr h, lookup_eq_none.mpr h'] --- @[simp] -- Porting note (#10618): simp can prove this +/-- `simp`-normal form of `mem_lookup_union` -/ +@[simp] +theorem mem_lookup_union' {a} {b : β a} {s₁ s₂ : Finmap β} : + lookup a (s₁ ∪ s₂) = some b ↔ b ∈ lookup a s₁ ∨ a ∉ s₁ ∧ b ∈ lookup a s₂ := + induction_on₂ s₁ s₂ fun _ _ => AList.mem_lookup_union + theorem mem_lookup_union {a} {b : β a} {s₁ s₂ : Finmap β} : b ∈ lookup a (s₁ ∪ s₂) ↔ b ∈ lookup a s₁ ∨ a ∉ s₁ ∧ b ∈ lookup a s₂ := induction_on₂ s₁ s₂ fun _ _ => AList.mem_lookup_union diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index e86ab424aa5fb..20b17a33c6b37 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Multiset.FinsetOps import Mathlib.Logic.Equiv.Set import Mathlib.Order.Directed import Mathlib.Order.Interval.Set.Basic +import Mathlib.Data.Set.SymmDiff /-! # Finite sets @@ -206,7 +207,6 @@ theorem setOf_mem {α} {s : Finset α} : { a | a ∈ s } = s := theorem coe_mem {s : Finset α} (x : (s : Set α)) : ↑x ∈ s := x.2 --- Porting note (#10618): @[simp] can prove this theorem mk_coe {s : Finset α} (x : (s : Set α)) {h} : (⟨x, h⟩ : (s : Set α)) = x := Subtype.coe_eta _ _ @@ -232,12 +232,10 @@ theorem coe_injective {α} : Injective ((↑) : Finset α → Set α) := fun _s instance {α : Type u} : CoeSort (Finset α) (Type u) := ⟨fun s => { x // x ∈ s }⟩ --- Porting note (#10618): @[simp] can prove this protected theorem forall_coe {α : Type*} (s : Finset α) (p : s → Prop) : (∀ x : s, p x) ↔ ∀ (x : α) (h : x ∈ s), p ⟨x, h⟩ := Subtype.forall --- Porting note (#10618): @[simp] can prove this protected theorem exists_coe {α : Type*} (s : Finset α) (p : s → Prop) : (∃ x : s, p x) ↔ ∃ (x : α) (h : x ∈ s), p ⟨x, h⟩ := Subtype.exists @@ -273,9 +271,9 @@ instance : HasSSubset (Finset α) := instance partialOrder : PartialOrder (Finset α) where le := (· ⊆ ·) lt := (· ⊂ ·) - le_refl s a := id - le_trans s t u hst htu a ha := htu <| hst ha - le_antisymm s t hst hts := ext fun a => ⟨@hst _, @hts _⟩ + le_refl _ _ := id + le_trans _ _ _ hst htu _ ha := htu <| hst ha + le_antisymm _ _ hst hts := ext fun _ => ⟨@hst _, @hts _⟩ instance : IsRefl (Finset α) (· ⊆ ·) := show IsRefl (Finset α) (· ≤ ·) by infer_instance @@ -747,7 +745,6 @@ theorem mem_cons {h} : b ∈ s.cons a h ↔ b = a ∨ b ∈ s := theorem mem_cons_of_mem {a b : α} {s : Finset α} {hb : b ∉ s} (ha : a ∈ s) : a ∈ cons b s hb := Multiset.mem_cons_of_mem ha --- Porting note (#10618): @[simp] can prove this theorem mem_cons_self (a : α) (s : Finset α) {h} : a ∈ cons a s h := Multiset.mem_cons_self _ _ @@ -755,6 +752,13 @@ theorem mem_cons_self (a : α) (s : Finset α) {h} : a ∈ cons a s h := theorem cons_val (h : a ∉ s) : (cons a s h).1 = a ::ₘ s.1 := rfl +theorem eq_of_mem_cons_of_not_mem (has : a ∉ s) (h : b ∈ cons a s has) (hb : b ∉ s) : b = a := + (mem_cons.1 h).resolve_right hb + +theorem mem_of_mem_cons_of_ne {s : Finset α} {a : α} {has} {i : α} + (hi : i ∈ cons a s has) (hia : i ≠ a) : i ∈ s := + (mem_cons.1 hi).resolve_left hia + theorem forall_mem_cons (h : a ∉ s) (p : α → Prop) : (∀ x, x ∈ cons a s h → p x) ↔ p a ∧ ∀ x, x ∈ s → p x := by simp only [mem_cons, or_imp, forall_and, forall_eq] @@ -812,6 +816,36 @@ theorem cons_swap (hb : b ∉ s) (ha : a ∉ s.cons b hb) : ha (mem_cons.mpr (.inl ((mem_cons.mp h).elim symm (fun h ↦ False.elim (hb h))))) := eq_of_veq <| Multiset.cons_swap a b s.val +/-- Split the added element of cons off a Pi type. -/ +@[simps!] +def consPiProd (f : α → Type*) (has : a ∉ s) (x : Π i ∈ cons a s has, f i) : f a × Π i ∈ s, f i := + (x a (mem_cons_self a s), fun i hi => x i (mem_cons_of_mem hi)) + +/-- Combine a product with a pi type to pi of cons. -/ +def prodPiCons [DecidableEq α] (f : α → Type*) {a : α} (has : a ∉ s) (x : f a × Π i ∈ s, f i) : + (Π i ∈ cons a s has, f i) := + fun i hi => + if h : i = a then cast (congrArg f h.symm) x.1 else x.2 i (mem_of_mem_cons_of_ne hi h) + +/-- The equivalence between pi types on cons and the product. -/ +def consPiProdEquiv [DecidableEq α] {s : Finset α} (f : α → Type*) {a : α} (has : a ∉ s) : + (Π i ∈ cons a s has, f i) ≃ f a × Π i ∈ s, f i where + toFun := consPiProd f has + invFun := prodPiCons f has + left_inv _ := by + ext i _ + dsimp only [prodPiCons, consPiProd] + by_cases h : i = a + · rw [dif_pos h] + subst h + simp_all only [cast_eq] + · rw [dif_neg h] + right_inv _ := by + ext _ hi + · simp [prodPiCons] + · simp only [consPiProd_snd] + exact dif_neg (ne_of_mem_of_not_mem hi has) + end Cons /-! ### disjoint -/ @@ -925,10 +959,9 @@ theorem disjUnion_singleton (s : Finset α) (a : α) (h : Disjoint s {a}) : /-! ### insert -/ - section Insert -variable [DecidableEq α] {s t u v : Finset α} {a b : α} +variable [DecidableEq α] {s t u v : Finset α} {a b : α} {f : α → β} /-- `insert a s` is the set `{a} ∪ s` containing `a` and the elements of `s`. -/ instance : Insert α (Finset α) := @@ -960,7 +993,7 @@ theorem mem_insert_of_mem (h : a ∈ s) : a ∈ insert b s := theorem mem_of_mem_insert_of_ne (h : b ∈ insert a s) : b ≠ a → b ∈ s := (mem_insert.1 h).resolve_left -theorem eq_of_not_mem_of_mem_insert (ha : b ∈ insert a s) (hb : b ∉ s) : b = a := +theorem eq_of_mem_insert_of_not_mem (ha : b ∈ insert a s) (hb : b ∉ s) : b = a := (mem_insert.1 ha).resolve_right hb /-- A version of `LawfulSingleton.insert_emptyc_eq` that works with `dsimp`. -/ @@ -991,14 +1024,12 @@ theorem insert_eq_self : insert a s = s ↔ a ∈ s := theorem insert_ne_self : insert a s ≠ s ↔ a ∉ s := insert_eq_self.not --- Porting note (#10618): @[simp] can prove this 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) := ext fun x => by simp only [mem_insert, or_left_comm] --- Porting note (#10618): @[simp] can prove this @[norm_cast] theorem coe_pair {a b : α} : (({a, b} : Finset α) : Set α) = {a, b} := by ext @@ -1011,7 +1042,6 @@ theorem coe_eq_pair {s : Finset α} {a b : α} : (s : Set α) = {a, b} ↔ s = { theorem pair_comm (a b : α) : ({a, b} : Finset α) = {b, a} := Insert.comm a b ∅ --- Porting note (#10618): @[simp] can prove this 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] @@ -1047,7 +1077,7 @@ theorem insert_subset_insert (a : α) {s t : Finset α} (h : s ⊆ t) : insert a simp_rw [← coe_subset]; simp [-coe_subset, ha] theorem insert_inj (ha : a ∉ s) : insert a s = insert b s ↔ a = b := - ⟨fun h => eq_of_not_mem_of_mem_insert (h ▸ mem_insert_self _ _) ha, congr_arg (insert · s)⟩ + ⟨fun h => eq_of_mem_insert_of_not_mem (h ▸ mem_insert_self _ _) ha, congr_arg (insert · s)⟩ theorem insert_inj_on (s : Finset α) : Set.InjOn (fun a => insert a s) sᶜ := fun _ h _ _ => (insert_inj h).1 @@ -1145,6 +1175,35 @@ theorem disjoint_insert_left : Disjoint (insert a s) t ↔ a ∉ t ∧ Disjoint theorem disjoint_insert_right : Disjoint s (insert a t) ↔ a ∉ s ∧ Disjoint s t := disjoint_comm.trans <| by rw [disjoint_insert_left, _root_.disjoint_comm] +/-- Split the added element of insert off a Pi type. -/ +@[simps!] +def insertPiProd (f : α → Type*) (x : Π i ∈ insert a s, f i) : f a × Π i ∈ s, f i := + (x a (mem_insert_self a s), fun i hi => x i (mem_insert_of_mem hi)) + +/-- Combine a product with a pi type to pi of insert. -/ +def prodPiInsert (f : α → Type*) {a : α} (x : f a × Π i ∈ s, f i) : (Π i ∈ insert a s, f i) := + fun i hi => + if h : i = a then cast (congrArg f h.symm) x.1 else x.2 i (mem_of_mem_insert_of_ne hi h) + +/-- The equivalence between pi types on insert and the product. -/ +def insertPiProdEquiv [DecidableEq α] {s : Finset α} (f : α → Type*) {a : α} (has : a ∉ s) : + (Π i ∈ insert a s, f i) ≃ f a × Π i ∈ s, f i where + toFun := insertPiProd f + invFun := prodPiInsert f + left_inv _ := by + ext i _ + dsimp only [prodPiInsert, insertPiProd] + by_cases h : i = a + · rw [dif_pos h] + subst h + simp_all only [cast_eq] + · rw [dif_neg h] + right_inv _ := by + ext _ hi + · simp [prodPiInsert] + · simp only [insertPiProd_snd] + exact dif_neg (ne_of_mem_of_not_mem hi has) + end Insert /-! ### Lattice structure -/ @@ -1493,13 +1552,11 @@ instance : DistribLattice (Finset α) := @[simp] theorem union_left_idem (s t : Finset α) : s ∪ (s ∪ t) = s ∪ t := sup_left_idem _ _ --- Porting note (#10618): @[simp] can prove this theorem union_right_idem (s t : Finset α) : s ∪ t ∪ t = s ∪ t := sup_right_idem _ _ @[simp] theorem inter_left_idem (s t : Finset α) : s ∩ (s ∩ t) = s ∩ t := inf_left_idem _ _ --- Porting note (#10618): @[simp] can prove this theorem inter_right_idem (s t : Finset α) : s ∩ t ∩ t = s ∩ t := inf_right_idem _ _ theorem inter_union_distrib_left (s t u : Finset α) : s ∩ (t ∪ u) = s ∩ t ∪ s ∩ u := @@ -1805,7 +1862,6 @@ theorem inter_sdiff (s t u : Finset α) : s ∩ (t \ u) = (s ∩ t) \ u := (inte theorem sdiff_inter_self (s₁ s₂ : Finset α) : s₂ \ s₁ ∩ s₁ = ∅ := inf_sdiff_self_left --- Porting note (#10618): @[simp] can prove this protected theorem sdiff_self (s₁ : Finset α) : s₁ \ s₁ = ∅ := _root_.sdiff_self @@ -1828,6 +1884,10 @@ theorem sdiff_empty : s \ ∅ = s := theorem sdiff_subset_sdiff (hst : s ⊆ t) (hvu : v ⊆ u) : s \ u ⊆ t \ v := 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 + @[simp, norm_cast] theorem coe_sdiff (s₁ s₂ : Finset α) : ↑(s₁ \ s₂) = (s₁ \ s₂ : Set α) := Set.ext fun _ => mem_sdiff @@ -1857,7 +1917,6 @@ theorem union_sdiff_symm : s ∪ t \ s = t ∪ s \ t := by simp [union_comm] theorem sdiff_union_inter (s t : Finset α) : s \ t ∪ s ∩ t = s := sup_sdiff_inf _ _ --- Porting note (#10618): @[simp] can prove this theorem sdiff_idem (s t : Finset α) : (s \ t) \ t = s \ t := _root_.sdiff_idem @@ -2549,11 +2608,9 @@ theorem range_succ : range (succ n) = insert n (range n) := theorem range_add_one : range (n + 1) = insert n (range n) := range_succ --- Porting note (#10618): @[simp] can prove this theorem not_mem_range_self : n ∉ range n := Multiset.not_mem_range_self --- Porting note (#10618): @[simp] can prove this theorem self_mem_range_succ (n : ℕ) : n ∈ range (n + 1) := Multiset.self_mem_range_succ n @@ -2603,7 +2660,7 @@ lemma range_nontrivial {n : ℕ} (hn : 1 < n) : (Finset.range n).Nontrivial := b theorem exists_nat_subset_range (s : Finset ℕ) : ∃ n : ℕ, s ⊆ range n := s.induction_on (by simp) - fun a s _ ⟨n, hn⟩ => ⟨max (a + 1) n, insert_subset (by simp) (hn.trans (by simp))⟩ + fun a _ _ ⟨n, hn⟩ => ⟨max (a + 1) n, insert_subset (by simp) (hn.trans (by simp))⟩ end Range @@ -2637,7 +2694,7 @@ def notMemRangeEquiv (k : ℕ) : { n // n ∉ range k } ≃ ℕ where rw [Subtype.ext_iff_val] apply Nat.sub_add_cancel simpa using j.2 - right_inv j := Nat.add_sub_cancel_right _ _ + right_inv _ := Nat.add_sub_cancel_right _ _ @[simp] theorem coe_notMemRangeEquiv (k : ℕ) : @@ -2775,7 +2832,8 @@ end Finset namespace List -variable [DecidableEq α] {l l' : List α} {a : α} +variable [DecidableEq α] {l l' : List α} {a : α} {f : α → β} + {s : Finset α} {t : Set β} {t' : Finset β} /-- `toFinset l` removes duplicates from the list `l` to produce a finset. -/ def toFinset (l : List α) : Finset α := @@ -2816,6 +2874,18 @@ theorem toFinset_surjective : Surjective (toFinset : List α → Finset α) := f let ⟨l, _, hls⟩ := toFinset_surj_on (Set.mem_univ s) ⟨l, hls⟩ +instance [DecidableEq β] : Decidable (Set.SurjOn f s t') := + inferInstanceAs (Decidable (∀ x ∈ t', ∃ y ∈ s, f y = x)) + +instance [DecidableEq β] : Decidable (Set.InjOn f s) := + inferInstanceAs (Decidable (∀ x ∈ s, ∀ y ∈ s, f x = f y → x = y)) + +instance [DecidablePred (· ∈ t)] : Decidable (Set.MapsTo f s t) := + inferInstanceAs (Decidable (∀ x ∈ s, f x ∈ t)) + +instance [DecidableEq β] : Decidable (Set.BijOn f s t') := + inferInstanceAs (Decidable (_ ∧ _ ∧ _)) + theorem toFinset_eq_iff_perm_dedup : l.toFinset = l'.toFinset ↔ l.dedup ~ l'.dedup := by simp [Finset.ext_iff, perm_ext_iff_of_nodup (nodup_dedup _) (nodup_dedup _)] @@ -3015,7 +3085,7 @@ open Finset /-- The disjoint union of finsets is a sum -/ def Finset.union (s t : Finset α) (h : Disjoint s t) : s ⊕ t ≃ (s ∪ t : Finset α) := - Equiv.Set.ofEq (coe_union _ _) |>.trans (Equiv.Set.union (disjoint_coe.mpr h).le_bot) |>.symm + Equiv.Set.ofEq (coe_union _ _) |>.trans (Equiv.Set.union (disjoint_coe.mpr h)) |>.symm @[simp] theorem Finset.union_symm_inl (h : Disjoint s t) (x : s) : diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index 6cd9aef810c64..b08d5c973026f 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -12,7 +12,7 @@ This defines the cardinality of a `Finset` and provides induction principles for ## Main declarations -* `Finset.card`: `s.card : ℕ` returns the cardinality of `s : Finset α`. +* `Finset.card`: `#s : ℕ` returns the cardinality of `s : Finset α`. ### Induction principles @@ -25,8 +25,7 @@ This defines the cardinality of a `Finset` and provides induction principles for -/ assert_not_exists MonoidWithZero --- TODO: After a lot more work, --- assert_not_exists OrderedCommMonoid +assert_not_exists OrderedCommMonoid open Function Multiset Nat @@ -36,52 +35,56 @@ namespace Finset variable {s t : Finset α} {a b : α} -/-- `s.card` is the number of elements of `s`, aka its cardinality. -/ +/-- `s.card` is the number of elements of `s`, aka its cardinality. + +The notation `#s` can be accessed in the `Finset` locale. -/ def card (s : Finset α) : ℕ := Multiset.card s.1 -theorem card_def (s : Finset α) : s.card = Multiset.card s.1 := +@[inherit_doc] scoped prefix:arg "#" => Finset.card + +theorem card_def (s : Finset α) : #s = Multiset.card s.1 := rfl -@[simp] lemma card_val (s : Finset α) : Multiset.card s.1 = s.card := rfl +@[simp] lemma card_val (s : Finset α) : Multiset.card s.1 = #s := rfl @[simp] -theorem card_mk {m nodup} : (⟨m, nodup⟩ : Finset α).card = Multiset.card m := +theorem card_mk {m nodup} : #(⟨m, nodup⟩ : Finset α) = Multiset.card m := rfl @[simp] -theorem card_empty : card (∅ : Finset α) = 0 := +theorem card_empty : #(∅ : Finset α) = 0 := rfl @[gcongr] -theorem card_le_card : s ⊆ t → s.card ≤ t.card := +theorem card_le_card : s ⊆ t → #s ≤ #t := Multiset.card_le_card ∘ val_le_iff.mpr @[mono] theorem card_mono : Monotone (@card α) := by apply card_le_card -@[simp] lemma card_eq_zero : s.card = 0 ↔ s = ∅ := Multiset.card_eq_zero.trans val_eq_zero -lemma card_ne_zero : s.card ≠ 0 ↔ s.Nonempty := card_eq_zero.ne.trans nonempty_iff_ne_empty.symm -@[simp] lemma card_pos : 0 < s.card ↔ s.Nonempty := Nat.pos_iff_ne_zero.trans card_ne_zero -@[simp] lemma one_le_card : 1 ≤ s.card ↔ s.Nonempty := card_pos +@[simp] lemma card_eq_zero : #s = 0 ↔ s = ∅ := Multiset.card_eq_zero.trans val_eq_zero +lemma card_ne_zero : #s ≠ 0 ↔ s.Nonempty := card_eq_zero.ne.trans nonempty_iff_ne_empty.symm +@[simp] lemma card_pos : 0 < #s ↔ s.Nonempty := Nat.pos_iff_ne_zero.trans card_ne_zero +@[simp] lemma one_le_card : 1 ≤ #s ↔ s.Nonempty := card_pos alias ⟨_, Nonempty.card_pos⟩ := card_pos alias ⟨_, Nonempty.card_ne_zero⟩ := card_ne_zero -theorem card_ne_zero_of_mem (h : a ∈ s) : s.card ≠ 0 := +theorem card_ne_zero_of_mem (h : a ∈ s) : #s ≠ 0 := (not_congr card_eq_zero).2 <| ne_empty_of_mem h @[simp] -theorem card_singleton (a : α) : card ({a} : Finset α) = 1 := +theorem card_singleton (a : α) : #{a} = 1 := Multiset.card_singleton _ -theorem card_singleton_inter [DecidableEq α] : ({a} ∩ s).card ≤ 1 := by +theorem card_singleton_inter [DecidableEq α] : #({a} ∩ s) ≤ 1 := by cases' Finset.decidableMem a s with h h · simp [Finset.singleton_inter_of_not_mem h] · simp [Finset.singleton_inter_of_mem h] @[simp] -theorem card_cons (h : a ∉ s) : (s.cons a h).card = s.card + 1 := +theorem card_cons (h : a ∉ s) : #(s.cons a h) = #s + 1 := Multiset.card_cons _ _ section InsertErase @@ -89,12 +92,12 @@ section InsertErase variable [DecidableEq α] @[simp] -theorem card_insert_of_not_mem (h : a ∉ s) : (insert a s).card = s.card + 1 := by +theorem card_insert_of_not_mem (h : a ∉ s) : #(insert a s) = #s + 1 := by rw [← cons_eq_insert _ _ h, card_cons] -theorem card_insert_of_mem (h : a ∈ s) : card (insert a s) = s.card := by rw [insert_eq_of_mem h] +theorem card_insert_of_mem (h : a ∈ s) : #(insert a s) = #s := by rw [insert_eq_of_mem h] -theorem card_insert_le (a : α) (s : Finset α) : card (insert a s) ≤ s.card + 1 := by +theorem card_insert_le (a : α) (s : Finset α) : #(insert a s) ≤ #s + 1 := by by_cases h : a ∈ s · rw [insert_eq_of_mem h] exact Nat.le_succ _ @@ -104,43 +107,43 @@ section variable {a b c d e f : α} -theorem card_le_two : card {a, b} ≤ 2 := card_insert_le _ _ +theorem card_le_two : #{a, b} ≤ 2 := card_insert_le _ _ -theorem card_le_three : card {a, b, c} ≤ 3 := +theorem card_le_three : #{a, b, c} ≤ 3 := (card_insert_le _ _).trans (Nat.succ_le_succ card_le_two) -theorem card_le_four : card {a, b, c, d} ≤ 4 := +theorem card_le_four : #{a, b, c, d} ≤ 4 := (card_insert_le _ _).trans (Nat.succ_le_succ card_le_three) -theorem card_le_five : card {a, b, c, d, e} ≤ 5 := +theorem card_le_five : #{a, b, c, d, e} ≤ 5 := (card_insert_le _ _).trans (Nat.succ_le_succ card_le_four) -theorem card_le_six : card {a, b, c, d, e, f} ≤ 6 := +theorem card_le_six : #{a, b, c, d, e, f} ≤ 6 := (card_insert_le _ _).trans (Nat.succ_le_succ card_le_five) end /-- If `a ∈ s` is known, see also `Finset.card_insert_of_mem` and `Finset.card_insert_of_not_mem`. -/ -theorem card_insert_eq_ite : card (insert a s) = if a ∈ s then s.card else s.card + 1 := by +theorem card_insert_eq_ite : #(insert a s) = if a ∈ s then #s else #s + 1 := by by_cases h : a ∈ s · rw [card_insert_of_mem h, if_pos h] · rw [card_insert_of_not_mem h, if_neg h] @[simp] -theorem card_pair_eq_one_or_two : ({a,b} : Finset α).card = 1 ∨ ({a,b} : Finset α).card = 2 := by +theorem card_pair_eq_one_or_two : #{a, b} = 1 ∨ #{a, b} = 2 := by simp [card_insert_eq_ite] tauto @[simp] -theorem card_pair (h : a ≠ b) : ({a, b} : Finset α).card = 2 := by +theorem card_pair (h : a ≠ b) : #{a, b} = 2 := by rw [card_insert_of_not_mem (not_mem_singleton.2 h), card_singleton] @[deprecated (since := "2024-01-04")] alias card_doubleton := Finset.card_pair /-- $\#(s \setminus \{a\}) = \#s - 1$ if $a \in s$. -/ @[simp] -theorem card_erase_of_mem : a ∈ s → (s.erase a).card = s.card - 1 := +theorem card_erase_of_mem : a ∈ s → #(s.erase a) = #s - 1 := Multiset.card_erase_of_mem /-- $\#(s \setminus \{a\}) = \#s - 1$ if $a \in s$. @@ -148,55 +151,57 @@ theorem card_erase_of_mem : a ∈ s → (s.erase a).card = s.card - 1 := so that we don't have to work with `ℕ`-subtraction. -/ @[simp] theorem cast_card_erase_of_mem {R} [AddGroupWithOne R] {s : Finset α} (hs : a ∈ s) : - ((s.erase a).card : R) = s.card - 1 := by + (#(s.erase a) : R) = #s - 1 := by rw [card_erase_of_mem hs, Nat.cast_sub, Nat.cast_one] rw [Nat.add_one_le_iff, Finset.card_pos] exact ⟨a, hs⟩ @[simp] -theorem card_erase_add_one : a ∈ s → (s.erase a).card + 1 = s.card := +theorem card_erase_add_one : a ∈ s → #(s.erase a) + 1 = #s := Multiset.card_erase_add_one -theorem card_erase_lt_of_mem : a ∈ s → (s.erase a).card < s.card := +theorem card_erase_lt_of_mem : a ∈ s → #(s.erase a) < #s := Multiset.card_erase_lt_of_mem -theorem card_erase_le : (s.erase a).card ≤ s.card := +theorem card_erase_le : #(s.erase a) ≤ #s := Multiset.card_erase_le -theorem pred_card_le_card_erase : s.card - 1 ≤ (s.erase a).card := by +theorem pred_card_le_card_erase : #s - 1 ≤ #(s.erase a) := by by_cases h : a ∈ s · exact (card_erase_of_mem h).ge · rw [erase_eq_of_not_mem h] exact Nat.sub_le _ _ /-- If `a ∈ s` is known, see also `Finset.card_erase_of_mem` and `Finset.erase_eq_of_not_mem`. -/ -theorem card_erase_eq_ite : (s.erase a).card = if a ∈ s then s.card - 1 else s.card := +theorem card_erase_eq_ite : #(s.erase a) = if a ∈ s then #s - 1 else #s := Multiset.card_erase_eq_ite end InsertErase @[simp] -theorem card_range (n : ℕ) : (range n).card = n := +theorem card_range (n : ℕ) : #(range n) = n := Multiset.card_range n @[simp] -theorem card_attach : s.attach.card = s.card := +theorem card_attach : #s.attach = #s := Multiset.card_attach end Finset +open scoped Finset + section ToMLListultiset variable [DecidableEq α] (m : Multiset α) (l : List α) -theorem Multiset.card_toFinset : m.toFinset.card = Multiset.card m.dedup := +theorem Multiset.card_toFinset : #m.toFinset = Multiset.card m.dedup := rfl -theorem Multiset.toFinset_card_le : m.toFinset.card ≤ Multiset.card m := +theorem Multiset.toFinset_card_le : #m.toFinset ≤ Multiset.card m := card_le_card <| dedup_le _ theorem Multiset.toFinset_card_of_nodup {m : Multiset α} (h : m.Nodup) : - m.toFinset.card = Multiset.card m := + #m.toFinset = Multiset.card m := congr_arg card <| Multiset.dedup_eq_self.mpr h theorem Multiset.dedup_card_eq_card_iff_nodup {m : Multiset α} : @@ -204,15 +209,15 @@ theorem Multiset.dedup_card_eq_card_iff_nodup {m : Multiset α} : .trans ⟨fun h ↦ eq_of_le_of_card_le (dedup_le m) h.ge, congr_arg _⟩ dedup_eq_self theorem Multiset.toFinset_card_eq_card_iff_nodup {m : Multiset α} : - m.toFinset.card = card m ↔ m.Nodup := dedup_card_eq_card_iff_nodup + #m.toFinset = card m ↔ m.Nodup := dedup_card_eq_card_iff_nodup -theorem List.card_toFinset : l.toFinset.card = l.dedup.length := +theorem List.card_toFinset : #l.toFinset = l.dedup.length := rfl -theorem List.toFinset_card_le : l.toFinset.card ≤ l.length := +theorem List.toFinset_card_le : #l.toFinset ≤ l.length := Multiset.toFinset_card_le ⟦l⟧ -theorem List.toFinset_card_of_nodup {l : List α} (h : l.Nodup) : l.toFinset.card = l.length := +theorem List.toFinset_card_of_nodup {l : List α} (h : l.Nodup) : #l.toFinset = l.length := Multiset.toFinset_card_of_nodup h end ToMLListultiset @@ -222,16 +227,16 @@ namespace Finset variable {s t u : Finset α} {f : α → β} {n : ℕ} @[simp] -theorem length_toList (s : Finset α) : s.toList.length = s.card := by +theorem length_toList (s : Finset α) : s.toList.length = #s := by rw [toList, ← Multiset.coe_card, Multiset.coe_toList, card_def] -theorem card_image_le [DecidableEq β] : (s.image f).card ≤ s.card := by +theorem card_image_le [DecidableEq β] : #(s.image f) ≤ #s := by simpa only [card_map] using (s.1.map f).toFinset_card_le -theorem card_image_of_injOn [DecidableEq β] (H : Set.InjOn f s) : (s.image f).card = s.card := by +theorem card_image_of_injOn [DecidableEq β] (H : Set.InjOn f s) : #(s.image f) = #s := by simp only [card, image_val_of_injOn H, card_map] -theorem injOn_of_card_image_eq [DecidableEq β] (H : (s.image f).card = s.card) : Set.InjOn f s := by +theorem injOn_of_card_image_eq [DecidableEq β] (H : #(s.image f) = #s) : Set.InjOn f s := by rw [card_def, card_def, image, toFinset] at H dsimp only at H have : (s.1.map f).dedup = s.1.map f := by @@ -240,58 +245,70 @@ theorem injOn_of_card_image_eq [DecidableEq β] (H : (s.image f).card = s.card) rw [Multiset.dedup_eq_self] at this exact inj_on_of_nodup_map this -theorem card_image_iff [DecidableEq β] : (s.image f).card = s.card ↔ Set.InjOn f s := +theorem card_image_iff [DecidableEq β] : #(s.image f) = #s ↔ Set.InjOn f s := ⟨injOn_of_card_image_eq, card_image_of_injOn⟩ theorem card_image_of_injective [DecidableEq β] (s : Finset α) (H : Injective f) : - (s.image f).card = s.card := + #(s.image f) = #s := card_image_of_injOn fun _ _ _ _ h => H h theorem fiber_card_ne_zero_iff_mem_image (s : Finset α) (f : α → β) [DecidableEq β] (y : β) : - (s.filter fun x => f x = y).card ≠ 0 ↔ y ∈ s.image f := by + #(s.filter fun x ↦ f x = y) ≠ 0 ↔ y ∈ s.image f := by rw [← Nat.pos_iff_ne_zero, card_pos, fiber_nonempty_iff_mem_image] lemma card_filter_le_iff (s : Finset α) (P : α → Prop) [DecidablePred P] (n : ℕ) : - (s.filter P).card ≤ n ↔ ∀ s' ⊆ s, n < s'.card → ∃ a ∈ s', ¬ P a := + #(s.filter P) ≤ n ↔ ∀ s' ⊆ s, n < #s' → ∃ a ∈ s', ¬ P a := (s.1.card_filter_le_iff P n).trans ⟨fun H s' hs' h ↦ H s'.1 (by aesop) h, - fun H s' hs' h ↦ H ⟨s', nodup_of_le hs' s.2⟩ (fun x hx ↦ subset_of_le hs' hx) h⟩ + fun H s' hs' h ↦ H ⟨s', nodup_of_le hs' s.2⟩ (fun _ hx ↦ subset_of_le hs' hx) h⟩ @[simp] -theorem card_map (f : α ↪ β) : (s.map f).card = s.card := +theorem card_map (f : α ↪ β) : #(s.map f) = #s := Multiset.card_map _ _ @[simp] theorem card_subtype (p : α → Prop) [DecidablePred p] (s : Finset α) : - (s.subtype p).card = (s.filter p).card := by simp [Finset.subtype] + #(s.subtype p) = #(s.filter p) := by simp [Finset.subtype] theorem card_filter_le (s : Finset α) (p : α → Prop) [DecidablePred p] : - (s.filter p).card ≤ s.card := + #(s.filter p) ≤ #s := card_le_card <| filter_subset _ _ -theorem eq_of_subset_of_card_le {s t : Finset α} (h : s ⊆ t) (h₂ : t.card ≤ s.card) : s = t := +theorem eq_of_subset_of_card_le {s t : Finset α} (h : s ⊆ t) (h₂ : #t ≤ #s) : s = t := eq_of_veq <| Multiset.eq_of_le_of_card_le (val_le_iff.mpr h) h₂ -theorem eq_of_superset_of_card_ge (hst : s ⊆ t) (hts : t.card ≤ s.card) : t = s := +theorem eq_iff_card_le_of_subset (hst : s ⊆ t) : #t ≤ #s ↔ s = t := + ⟨eq_of_subset_of_card_le hst, (ge_of_eq <| congr_arg _ ·)⟩ + +theorem eq_of_superset_of_card_ge (hst : s ⊆ t) (hts : #t ≤ #s) : t = s := (eq_of_subset_of_card_le hst hts).symm -theorem subset_iff_eq_of_card_le (h : t.card ≤ s.card) : s ⊆ t ↔ s = t := +theorem eq_iff_card_ge_of_superset (hst : s ⊆ t) : #t ≤ #s ↔ t = s := + (eq_iff_card_le_of_subset hst).trans eq_comm + +theorem subset_iff_eq_of_card_le (h : #t ≤ #s) : s ⊆ t ↔ s = t := ⟨fun hst => eq_of_subset_of_card_le hst h, Eq.subset'⟩ theorem map_eq_of_subset {f : α ↪ α} (hs : s.map f ⊆ s) : s.map f = s := eq_of_subset_of_card_le hs (card_map _).ge -theorem filter_card_eq {p : α → Prop} [DecidablePred p] (h : (s.filter p).card = s.card) (x : α) - (hx : x ∈ s) : p x := by - rw [← eq_of_subset_of_card_le (s.filter_subset p) h.ge, mem_filter] at hx - exact hx.2 +theorem card_filter_eq_iff {p : α → Prop} [DecidablePred p] : + #(s.filter p) = #s ↔ ∀ x ∈ s, p x := by + rw [(card_filter_le s p).eq_iff_not_lt, not_lt, eq_iff_card_le_of_subset (filter_subset p s), + filter_eq_self] + +alias ⟨filter_card_eq, _⟩ := card_filter_eq_iff + +theorem card_filter_eq_zero_iff {p : α → Prop} [DecidablePred p] : + #(s.filter p) = 0 ↔ ∀ x ∈ s, ¬ p x := by + rw [card_eq_zero, filter_eq_empty_iff] -nonrec lemma card_lt_card (h : s ⊂ t) : s.card < t.card := card_lt_card <| val_lt_iff.2 h +nonrec lemma card_lt_card (h : s ⊂ t) : #s < #t := card_lt_card <| val_lt_iff.2 h lemma card_strictMono : StrictMono (card : Finset α → ℕ) := fun _ _ ↦ card_lt_card theorem card_eq_of_bijective (f : ∀ i, i < n → α) (hf : ∀ a ∈ s, ∃ i, ∃ h : i < n, f i h = a) (hf' : ∀ i (h : i < n), f i h ∈ s) - (f_inj : ∀ i j (hi : i < n) (hj : j < n), f i hi = f j hj → i = j) : s.card = n := by + (f_inj : ∀ i j (hi : i < n) (hj : j < n), f i hi = f j hj → i = j) : #s = n := by classical have : s = (range n).attach.image fun i => f i.1 (mem_range.1 i.2) := by ext a @@ -301,10 +318,10 @@ theorem card_eq_of_bijective (f : ∀ i, i < n → α) (hf : ∀ a ∈ s, ∃ i, · intro ha; obtain ⟨i, hi, rfl⟩ := hf a ha; use i, mem_range.2 hi · rintro ⟨i, hi, rfl⟩; apply hf' calc - s.card = ((range n).attach.image fun i => f i.1 (mem_range.1 i.2)).card := by rw [this] - _ = (range n).attach.card := ?_ - _ = (range n).card := card_attach - _ = n := card_range n + #s = #((range n).attach.image fun i => f i.1 (mem_range.1 i.2)) := by rw [this] + _ = #(range n).attach := ?_ + _ = #(range n) := card_attach + _ = n := card_range n apply card_image_of_injective intro ⟨i, hi⟩ ⟨j, hj⟩ eq exact Subtype.eq <| f_inj i j (mem_range.1 hi) (mem_range.1 hj) eq @@ -321,12 +338,12 @@ The difference with `Finset.card_nbij` is that the bijection is allowed to use m domain, rather than being a non-dependent function. -/ lemma card_bij (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t) (i_inj : ∀ a₁ ha₁ a₂ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂) - (i_surj : ∀ b ∈ t, ∃ a ha, i a ha = b) : s.card = t.card := by + (i_surj : ∀ b ∈ t, ∃ a ha, i a ha = b) : #s = #t := by classical calc - s.card = s.attach.card := card_attach.symm - _ = (s.attach.image fun a : { a // a ∈ s } => i a.1 a.2).card := Eq.symm ?_ - _ = t.card := ?_ + #s = #s.attach := card_attach.symm + _ = #(s.attach.image fun a ↦ i a.1 a.2) := Eq.symm ?_ + _ = #t := ?_ · apply card_image_of_injective intro ⟨_, _⟩ ⟨_, _⟩ h simpa using i_inj _ _ _ _ h @@ -347,7 +364,7 @@ The difference with `Finset.card_nbij'` is that the bijection and its inverse ar membership of the domains, rather than being non-dependent functions. -/ lemma card_bij' (i : ∀ a ∈ s, β) (j : ∀ a ∈ t, α) (hi : ∀ a ha, i a ha ∈ t) (hj : ∀ a ha, j a ha ∈ s) (left_inv : ∀ a ha, j (i a ha) (hi a ha) = a) - (right_inv : ∀ a ha, i (j a ha) (hj a ha) = a) : s.card = t.card := by + (right_inv : ∀ a ha, i (j a ha) (hj a ha) = a) : #s = #t := by refine card_bij i hi (fun a1 h1 a2 h2 eq ↦ ?_) (fun b hb ↦ ⟨_, hj b hb, right_inv b hb⟩) rw [← left_inv a1 h1, ← left_inv a2 h2] simp only [eq] @@ -360,7 +377,7 @@ injection, rather than by an inverse function. The difference with `Finset.card_bij` is that the bijection is a non-dependent function, rather than being allowed to use membership of the domain. -/ lemma card_nbij (i : α → β) (hi : ∀ a ∈ s, i a ∈ t) (i_inj : (s : Set α).InjOn i) - (i_surj : (s : Set α).SurjOn i t) : s.card = t.card := + (i_surj : (s : Set α).SurjOn i t) : #s = #t := card_bij (fun a _ ↦ i a) hi i_inj (by simpa using i_surj) /-- Reorder a finset. @@ -374,35 +391,35 @@ functions, rather than being allowed to use membership of the domains. The difference with `Finset.card_equiv` is that bijectivity is only required to hold on the domains, rather than on the entire types. -/ lemma card_nbij' (i : α → β) (j : β → α) (hi : ∀ a ∈ s, i a ∈ t) (hj : ∀ a ∈ t, j a ∈ s) - (left_inv : ∀ a ∈ s, j (i a) = a) (right_inv : ∀ a ∈ t, i (j a) = a) : s.card = t.card := + (left_inv : ∀ a ∈ s, j (i a) = a) (right_inv : ∀ a ∈ t, i (j a) = a) : #s = #t := card_bij' (fun a _ ↦ i a) (fun b _ ↦ j b) hi hj left_inv right_inv /-- Specialization of `Finset.card_nbij'` that automatically fills in most arguments. See `Fintype.card_equiv` for the version where `s` and `t` are `univ`. -/ -lemma card_equiv (e : α ≃ β) (hst : ∀ i, i ∈ s ↔ e i ∈ t) : s.card = t.card := by +lemma card_equiv (e : α ≃ β) (hst : ∀ i, i ∈ s ↔ e i ∈ t) : #s = #t := by refine card_nbij' e e.symm ?_ ?_ ?_ ?_ <;> simp [hst] /-- Specialization of `Finset.card_nbij` that automatically fills in most arguments. See `Fintype.card_bijective` for the version where `s` and `t` are `univ`. -/ lemma card_bijective (e : α → β) (he : e.Bijective) (hst : ∀ i, i ∈ s ↔ e i ∈ t) : - s.card = t.card := card_equiv (.ofBijective e he) hst + #s = #t := card_equiv (.ofBijective e he) hst lemma card_le_card_of_injOn (f : α → β) (hf : ∀ a ∈ s, f a ∈ t) (f_inj : (s : Set α).InjOn f) : - s.card ≤ t.card := by + #s ≤ #t := by classical calc - s.card = (s.image f).card := (card_image_of_injOn f_inj).symm - _ ≤ t.card := card_le_card <| image_subset_iff.2 hf + #s = #(s.image f) := (card_image_of_injOn f_inj).symm + _ ≤ #t := card_le_card <| image_subset_iff.2 hf @[deprecated (since := "2024-06-01")] alias card_le_card_of_inj_on := card_le_card_of_injOn -lemma card_le_card_of_surjOn (f : α → β) (hf : Set.SurjOn f s t) : t.card ≤ s.card := by +lemma card_le_card_of_surjOn (f : α → β) (hf : Set.SurjOn f s t) : #t ≤ #s := by classical unfold Set.SurjOn at hf; exact (card_le_card (mod_cast hf)).trans card_image_le /-- If there are more pigeons than pigeonholes, then there are two pigeons in the same pigeonhole. -/ -theorem exists_ne_map_eq_of_card_lt_of_maps_to {t : Finset β} (hc : t.card < s.card) {f : α → β} +theorem exists_ne_map_eq_of_card_lt_of_maps_to {t : Finset β} (hc : #t < #s) {f : α → β} (hf : ∀ a ∈ s, f a ∈ t) : ∃ x ∈ s, ∃ y ∈ s, x ≠ y ∧ f x = f y := by classical by_contra! hz @@ -412,16 +429,16 @@ theorem exists_ne_map_eq_of_card_lt_of_maps_to {t : Finset β} (hc : t.card < s. exact hz x hx y hy lemma le_card_of_inj_on_range (f : ℕ → α) (hf : ∀ i < n, f i ∈ s) - (f_inj : ∀ i < n, ∀ j < n, f i = f j → i = j) : n ≤ s.card := + (f_inj : ∀ i < n, ∀ j < n, f i = f j → i = j) : n ≤ #s := calc - n = card (range n) := (card_range n).symm - _ ≤ s.card := card_le_card_of_injOn f (by simpa only [mem_range]) (by simpa) + n = #(range n) := (card_range n).symm + _ ≤ #s := card_le_card_of_injOn f (by simpa only [mem_range]) (by simpa) lemma surj_on_of_inj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha ∈ t) - (hinj : ∀ a₁ a₂ ha₁ ha₂, f a₁ ha₁ = f a₂ ha₂ → a₁ = a₂) (hst : t.card ≤ s.card) : + (hinj : ∀ a₁ a₂ ha₁ ha₂, f a₁ ha₁ = f a₂ ha₂ → a₁ = a₂) (hst : #t ≤ #s) : ∀ b ∈ t, ∃ a ha, b = f a ha := by classical - have h : (s.attach.image fun a : { a // a ∈ s } => f a a.prop).card = s.card := by + have h : #(s.attach.image fun a : s ↦ f a a.2) = #s := by rw [← @card_attach _ s, card_image_of_injective] intro ⟨_, _⟩ ⟨_, _⟩ h exact Subtype.eq <| hinj _ _ _ _ h @@ -431,7 +448,7 @@ lemma surj_on_of_inj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha exact fun b a ha hb ↦ ⟨a, ha, hb.symm⟩ theorem inj_on_of_surj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha ∈ t) - (hsurj : ∀ b ∈ t, ∃ a ha, f a ha = b) (hst : s.card ≤ t.card) ⦃a₁⦄ (ha₁ : a₁ ∈ s) ⦃a₂⦄ + (hsurj : ∀ b ∈ t, ∃ a ha, f a ha = b) (hst : #s ≤ #t) ⦃a₁⦄ (ha₁ : a₁ ∈ s) ⦃a₂⦄ (ha₂ : a₂ ∈ s) (ha₁a₂ : f a₁ ha₁ = f a₂ ha₂) : a₁ = a₂ := haveI : Inhabited { x // x ∈ s } := ⟨⟨a₁, ha₁⟩⟩ let f' : { x // x ∈ s } → { x // x ∈ t } := fun x => ⟨f x.1 x.2, hf x.1 x.2⟩ @@ -443,7 +460,7 @@ theorem inj_on_of_surj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a h have hsg : Surjective g := fun x => let ⟨y, hy⟩ := surj_on_of_inj_on_of_card_le (fun (x : { x // x ∈ t }) (_ : x ∈ t.attach) => g x) - (fun x _ => show g x ∈ s.attach from mem_attach _ _) (fun x y _ _ hxy => hg hxy) (by simpa) + (fun x _ => show g x ∈ s.attach from mem_attach _ _) (fun _ _ _ _ hxy => hg hxy) (by simpa) x (mem_attach _ _) ⟨y, hy.snd.symm⟩ have hif : Injective f' := @@ -453,7 +470,7 @@ theorem inj_on_of_surj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a h end bij @[simp] -theorem card_disjUnion (s t : Finset α) (h) : (s.disjUnion t h).card = s.card + t.card := +theorem card_disjUnion (s t : Finset α) (h) : #(s.disjUnion t h) = #s + #t := Multiset.card_add _ _ /-! ### Lattice structure -/ @@ -464,23 +481,23 @@ section Lattice variable [DecidableEq α] theorem card_union_add_card_inter (s t : Finset α) : - (s ∪ t).card + (s ∩ t).card = s.card + t.card := + #(s ∪ t) + #(s ∩ t) = #s + #t := Finset.induction_on t (by simp) fun a r har h => by by_cases a ∈ s <;> simp [*, ← add_assoc, add_right_comm _ 1] theorem card_inter_add_card_union (s t : Finset α) : - (s ∩ t).card + (s ∪ t).card = s.card + t.card := by rw [add_comm, card_union_add_card_inter] + #(s ∩ t) + #(s ∪ t) = #s + #t := by rw [add_comm, card_union_add_card_inter] -lemma card_union (s t : Finset α) : (s ∪ t).card = s.card + t.card - (s ∩ t).card := by +lemma card_union (s t : Finset α) : #(s ∪ t) = #s + #t - #(s ∩ t) := by rw [← card_union_add_card_inter, Nat.add_sub_cancel] -lemma card_inter (s t : Finset α) : (s ∩ t).card = s.card + t.card - (s ∪ t).card := by +lemma card_inter (s t : Finset α) : #(s ∩ t) = #s + #t - #(s ∪ t) := by rw [← card_inter_add_card_union, Nat.add_sub_cancel] -theorem card_union_le (s t : Finset α) : (s ∪ t).card ≤ s.card + t.card := +theorem card_union_le (s t : Finset α) : #(s ∪ t) ≤ #s + #t := card_union_add_card_inter s t ▸ Nat.le_add_right _ _ -lemma card_union_eq_card_add_card : (s ∪ t).card = s.card + t.card ↔ Disjoint s t := by +lemma card_union_eq_card_add_card : #(s ∪ t) = #s + #t ↔ Disjoint s t := by rw [← card_union_add_card_inter]; simp [disjoint_iff_inter_eq_empty] @[simp] alias ⟨_, card_union_of_disjoint⟩ := card_union_eq_card_add_card @@ -489,70 +506,70 @@ lemma card_union_eq_card_add_card : (s ∪ t).card = s.card + t.card ↔ Disjoin @[deprecated (since := "2024-02-09")] alias card_disjoint_union := card_union_of_disjoint lemma cast_card_inter [AddGroupWithOne R] : - ((s ∩ t).card : R) = s.card + t.card - (s ∪ t).card := by + (#(s ∩ t) : R) = #s + #t - #(s ∪ t) := by rw [eq_sub_iff_add_eq, ← cast_add, card_inter_add_card_union, cast_add] lemma cast_card_union [AddGroupWithOne R] : - ((s ∪ t).card : R) = s.card + t.card - (s ∩ t).card := by + (#(s ∪ t) : R) = #s + #t - #(s ∩ t) := by rw [eq_sub_iff_add_eq, ← cast_add, card_union_add_card_inter, cast_add] -theorem card_sdiff (h : s ⊆ t) : card (t \ s) = t.card - s.card := by - suffices card (t \ s) = card (t \ s ∪ s) - s.card by rwa [sdiff_union_of_subset h] at this +theorem card_sdiff (h : s ⊆ t) : #(t \ s) = #t - #s := by + suffices #(t \ s) = #(t \ s ∪ s) - #s by rwa [sdiff_union_of_subset h] at this rw [card_union_of_disjoint sdiff_disjoint, Nat.add_sub_cancel_right] -lemma cast_card_sdiff [AddGroupWithOne R] (h : s ⊆ t) : ((t \ s).card : R) = t.card - s.card := by +lemma cast_card_sdiff [AddGroupWithOne R] (h : s ⊆ t) : (#(t \ s) : R) = #t - #s := by rw [card_sdiff h, Nat.cast_sub (card_mono h)] -theorem card_sdiff_add_card_eq_card {s t : Finset α} (h : s ⊆ t) : card (t \ s) + card s = card t := +theorem card_sdiff_add_card_eq_card {s t : Finset α} (h : s ⊆ t) : #(t \ s) + #s = #t := ((Nat.sub_eq_iff_eq_add (card_le_card h)).mp (card_sdiff h).symm).symm -theorem le_card_sdiff (s t : Finset α) : t.card - s.card ≤ card (t \ s) := +theorem le_card_sdiff (s t : Finset α) : #t - #s ≤ #(t \ s) := calc - card t - card s ≤ card t - card (s ∩ t) := + #t - #s ≤ #t - #(s ∩ t) := Nat.sub_le_sub_left (card_le_card inter_subset_left) _ - _ = card (t \ (s ∩ t)) := (card_sdiff inter_subset_right).symm - _ ≤ card (t \ s) := by rw [sdiff_inter_self_right t s] + _ = #(t \ (s ∩ t)) := (card_sdiff inter_subset_right).symm + _ ≤ #(t \ s) := by rw [sdiff_inter_self_right t s] -theorem card_le_card_sdiff_add_card : s.card ≤ (s \ t).card + t.card := +theorem card_le_card_sdiff_add_card : #s ≤ #(s \ t) + #t := Nat.sub_le_iff_le_add.1 <| le_card_sdiff _ _ -theorem card_sdiff_add_card (s t : Finset α) : (s \ t).card + t.card = (s ∪ t).card := by +theorem card_sdiff_add_card (s t : Finset α) : #(s \ t) + #t = #(s ∪ t) := by rw [← card_union_of_disjoint sdiff_disjoint, sdiff_union_self_eq_union] -lemma card_sdiff_comm (h : s.card = t.card) : (s \ t).card = (t \ s).card := - add_left_injective t.card <| by +lemma card_sdiff_comm (h : #s = #t) : #(s \ t) = #(t \ s) := + add_left_injective #t <| by simp_rw [card_sdiff_add_card, ← h, card_sdiff_add_card, union_comm] @[simp] lemma card_sdiff_add_card_inter (s t : Finset α) : - (s \ t).card + (s ∩ t).card = s.card := by + #(s \ t) + #(s ∩ t) = #s := by rw [← card_union_of_disjoint (disjoint_sdiff_inter _ _), sdiff_union_inter] @[simp] lemma card_inter_add_card_sdiff (s t : Finset α) : - (s ∩ t).card + (s \ t).card = s.card := by + #(s ∩ t) + #(s \ t) = #s := by rw [add_comm, card_sdiff_add_card_inter] /-- **Pigeonhole principle** for two finsets inside an ambient finset. -/ theorem inter_nonempty_of_card_lt_card_add_card (hts : t ⊆ s) (hus : u ⊆ s) - (hstu : s.card < t.card + u.card) : (t ∩ u).Nonempty := by + (hstu : #s < #t + #u) : (t ∩ u).Nonempty := by contrapose! hstu calc - _ = (t ∪ u).card := by simp [← card_union_add_card_inter, not_nonempty_iff_eq_empty.1 hstu] - _ ≤ s.card := by gcongr; exact union_subset hts hus + _ = #(t ∪ u) := by simp [← card_union_add_card_inter, not_nonempty_iff_eq_empty.1 hstu] + _ ≤ #s := by gcongr; exact union_subset hts hus end Lattice theorem filter_card_add_filter_neg_card_eq_card (p : α → Prop) [DecidablePred p] [∀ x, Decidable (¬p x)] : - (s.filter p).card + (s.filter (fun a => ¬ p a)).card = s.card := by + #(s.filter p) + #(s.filter fun a ↦ ¬ p a) = #s := by classical rw [← card_union_of_disjoint (disjoint_filter_filter_neg _ _ _), filter_union_filter_neg_eq] /-- Given a subset `s` of a set `t`, of sizes at most and at least `n` respectively, there exists a set `u` of size `n` which is both a superset of `s` and a subset of `t`. -/ -lemma exists_subsuperset_card_eq (hst : s ⊆ t) (hsn : s.card ≤ n) (hnt : n ≤ t.card) : - ∃ u, s ⊆ u ∧ u ⊆ t ∧ card u = n := by +lemma exists_subsuperset_card_eq (hst : s ⊆ t) (hsn : #s ≤ n) (hnt : n ≤ #t) : + ∃ u, s ⊆ u ∧ u ⊆ t ∧ #u = n := by classical refine Nat.decreasingInduction' ?_ hnt ⟨t, by simp [hst]⟩ intro k _ hnk ⟨u, hu₁, hu₂, hu₃⟩ @@ -561,48 +578,48 @@ lemma exists_subsuperset_card_eq (hst : s ⊆ t) (hsn : s.card ≤ n) (hnt : n exact ⟨u.erase a, by simp [subset_erase, erase_subset_iff_of_mem (hu₂ _), *]⟩ /-- We can shrink a set to any smaller size. -/ -lemma exists_subset_card_eq (hns : n ≤ s.card) : ∃ t ⊆ s, t.card = n := by +lemma exists_subset_card_eq (hns : n ≤ #s) : ∃ t ⊆ s, #t = n := by simpa using exists_subsuperset_card_eq s.empty_subset (by simp) hns /-- Given a set `A` and a set `B` inside it, we can shrink `A` to any appropriate size, and keep `B` inside it. -/ @[deprecated exists_subsuperset_card_eq (since := "2024-06-23")] -theorem exists_intermediate_set {A B : Finset α} (i : ℕ) (h₁ : i + card B ≤ card A) (h₂ : B ⊆ A) : - ∃ C : Finset α, B ⊆ C ∧ C ⊆ A ∧ card C = i + card B := +theorem exists_intermediate_set {A B : Finset α} (i : ℕ) (h₁ : i + #B ≤ #A) (h₂ : B ⊆ A) : + ∃ C : Finset α, B ⊆ C ∧ C ⊆ A ∧ #C = i + #B := exists_subsuperset_card_eq h₂ (Nat.le_add_left ..) h₁ /-- We can shrink `A` to any smaller size. -/ @[deprecated exists_subset_card_eq (since := "2024-06-23")] -theorem exists_smaller_set (A : Finset α) (i : ℕ) (h₁ : i ≤ card A) : - ∃ B : Finset α, B ⊆ A ∧ card B = i := exists_subset_card_eq h₁ +theorem exists_smaller_set (A : Finset α) (i : ℕ) (h₁ : i ≤ #A) : + ∃ B : Finset α, B ⊆ A ∧ #B = i := exists_subset_card_eq h₁ -theorem le_card_iff_exists_subset_card : n ≤ s.card ↔ ∃ t ⊆ s, t.card = n := by +theorem le_card_iff_exists_subset_card : n ≤ #s ↔ ∃ t ⊆ s, #t = n := by refine ⟨fun h => ?_, fun ⟨t, hst, ht⟩ => ht ▸ card_le_card hst⟩ exact exists_subset_card_eq h theorem exists_subset_or_subset_of_two_mul_lt_card [DecidableEq α] {X Y : Finset α} {n : ℕ} - (hXY : 2 * n < (X ∪ Y).card) : ∃ C : Finset α, n < C.card ∧ (C ⊆ X ∨ C ⊆ Y) := by - have h₁ : (X ∩ (Y \ X)).card = 0 := Finset.card_eq_zero.mpr (Finset.inter_sdiff_self X Y) - have h₂ : (X ∪ Y).card = X.card + (Y \ X).card := by + (hXY : 2 * n < #(X ∪ Y)) : ∃ C : Finset α, n < #C ∧ (C ⊆ X ∨ C ⊆ Y) := by + have h₁ : #(X ∩ (Y \ X)) = 0 := Finset.card_eq_zero.mpr (Finset.inter_sdiff_self X Y) + have h₂ : #(X ∪ Y) = #X + #(Y \ X) := by rw [← card_union_add_card_inter X (Y \ X), Finset.union_sdiff_self_eq_union, h₁, add_zero] rw [h₂, Nat.two_mul] at hXY - obtain h | h : n < X.card ∨ n < (Y \ X).card := by contrapose! hXY; omega + obtain h | h : n < #X ∨ n < #(Y \ X) := by contrapose! hXY; omega · exact ⟨X, h, Or.inl (Finset.Subset.refl X)⟩ · exact ⟨Y \ X, h, Or.inr sdiff_subset⟩ /-! ### Explicit description of a finset from its card -/ -theorem card_eq_one : s.card = 1 ↔ ∃ a, s = {a} := by +theorem card_eq_one : #s = 1 ↔ ∃ a, s = {a} := by cases s simp only [Multiset.card_eq_one, Finset.card, ← val_inj, singleton_val] theorem _root_.Multiset.toFinset_card_eq_one_iff [DecidableEq α] (s : Multiset α) : - s.toFinset.card = 1 ↔ Multiset.card s ≠ 0 ∧ ∃ a : α, s = Multiset.card s • {a} := by + #s.toFinset = 1 ↔ Multiset.card s ≠ 0 ∧ ∃ a : α, s = Multiset.card s • {a} := by simp_rw [card_eq_one, Multiset.toFinset_eq_singleton_iff, exists_and_left] theorem exists_eq_insert_iff [DecidableEq α] {s t : Finset α} : - (∃ a ∉ s, insert a s = t) ↔ s ⊆ t ∧ s.card + 1 = t.card := by + (∃ a ∉ s, insert a s = t) ↔ s ⊆ t ∧ #s + 1 = #t := by constructor · rintro ⟨a, ha, rfl⟩ exact ⟨subset_insert _ _, (card_insert_of_not_mem ha).symm⟩ @@ -615,7 +632,7 @@ theorem exists_eq_insert_iff [DecidableEq α] {s t : Finset α} : rw [← ha] exact not_mem_sdiff_of_mem_right hs -theorem card_le_one : s.card ≤ 1 ↔ ∀ a ∈ s, ∀ b ∈ s, a = b := by +theorem card_le_one : #s ≤ 1 ↔ ∀ a ∈ s, ∀ b ∈ s, a = b := by obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty · simp refine (Nat.succ_le_of_lt (card_pos.2 ⟨x, hx⟩)).le_iff_eq.trans (card_eq_one.trans ⟨?_, ?_⟩) @@ -623,14 +640,14 @@ theorem card_le_one : s.card ≤ 1 ↔ ∀ a ∈ s, ∀ b ∈ s, a = b := by simp · exact fun h => ⟨x, eq_singleton_iff_unique_mem.2 ⟨hx, fun y hy => h _ hy _ hx⟩⟩ -theorem card_le_one_iff : s.card ≤ 1 ↔ ∀ {a b}, a ∈ s → b ∈ s → a = b := by +theorem card_le_one_iff : #s ≤ 1 ↔ ∀ {a b}, a ∈ s → b ∈ s → a = b := by rw [card_le_one] tauto -theorem card_le_one_iff_subsingleton_coe : s.card ≤ 1 ↔ Subsingleton (s : Type _) := +theorem card_le_one_iff_subsingleton_coe : #s ≤ 1 ↔ Subsingleton (s : Type _) := card_le_one.trans (s : Set α).subsingleton_coe.symm -theorem card_le_one_iff_subset_singleton [Nonempty α] : s.card ≤ 1 ↔ ∃ x : α, s ⊆ {x} := by +theorem card_le_one_iff_subset_singleton [Nonempty α] : #s ≤ 1 ↔ ∃ x : α, s ⊆ {x} := by refine ⟨fun H => ?_, ?_⟩ · obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty · exact ⟨Classical.arbitrary α, empty_subset _⟩ @@ -639,32 +656,32 @@ theorem card_le_one_iff_subset_singleton [Nonempty α] : s.card ≤ 1 ↔ ∃ x rw [← card_singleton x] exact card_le_card hx -lemma exists_mem_ne (hs : 1 < s.card) (a : α) : ∃ b ∈ s, b ≠ a := by +lemma exists_mem_ne (hs : 1 < #s) (a : α) : ∃ b ∈ s, b ≠ a := by have : Nonempty α := ⟨a⟩ by_contra! exact hs.not_le (card_le_one_iff_subset_singleton.2 ⟨a, subset_singleton_iff'.2 this⟩) /-- A `Finset` of a subsingleton type has cardinality at most one. -/ -theorem card_le_one_of_subsingleton [Subsingleton α] (s : Finset α) : s.card ≤ 1 := +theorem card_le_one_of_subsingleton [Subsingleton α] (s : Finset α) : #s ≤ 1 := Finset.card_le_one_iff.2 fun {_ _ _ _} => Subsingleton.elim _ _ -theorem one_lt_card : 1 < s.card ↔ ∃ a ∈ s, ∃ b ∈ s, a ≠ b := by +theorem one_lt_card : 1 < #s ↔ ∃ a ∈ s, ∃ b ∈ s, a ≠ b := by rw [← not_iff_not] push_neg exact card_le_one -theorem one_lt_card_iff : 1 < s.card ↔ ∃ a b, a ∈ s ∧ b ∈ s ∧ a ≠ b := by +theorem one_lt_card_iff : 1 < #s ↔ ∃ a b, a ∈ s ∧ b ∈ s ∧ a ≠ b := by rw [one_lt_card] simp only [exists_prop, exists_and_left] -theorem one_lt_card_iff_nontrivial : 1 < s.card ↔ s.Nontrivial := by +theorem one_lt_card_iff_nontrivial : 1 < #s ↔ s.Nontrivial := by rw [← not_iff_not, not_lt, Finset.Nontrivial, ← Set.nontrivial_coe_sort, not_nontrivial_iff_subsingleton, card_le_one_iff_subsingleton_coe, coe_sort_coe] @[deprecated (since := "2024-02-05")] alias one_lt_card_iff_nontrivial_coe := one_lt_card_iff_nontrivial -theorem exists_ne_of_one_lt_card (hs : 1 < s.card) (a : α) : ∃ b, b ∈ s ∧ b ≠ a := by +theorem exists_ne_of_one_lt_card (hs : 1 < #s) (a : α) : ∃ b, b ∈ s ∧ b ≠ a := by obtain ⟨x, hx, y, hy, hxy⟩ := Finset.one_lt_card.mp hs by_cases ha : y = a · exact ⟨x, hx, ne_of_ne_of_eq hxy ha⟩ @@ -674,8 +691,8 @@ theorem exists_ne_of_one_lt_card (hs : 1 < s.card) (a : α) : ∃ b, b ∈ s ∧ its projection to some factor is nontrivial, and the fibers of the projection are proper subsets. -/ lemma exists_of_one_lt_card_pi {ι : Type*} {α : ι → Type*} [∀ i, DecidableEq (α i)] - {s : Finset (∀ i, α i)} (h : 1 < s.card) : - ∃ i, 1 < (s.image (· i)).card ∧ ∀ ai, s.filter (· i = ai) ⊂ s := by + {s : Finset (∀ i, α i)} (h : 1 < #s) : + ∃ i, 1 < #(s.image (· i)) ∧ ∀ ai, s.filter (· i = ai) ⊂ s := by simp_rw [one_lt_card_iff, Function.ne_iff] at h ⊢ obtain ⟨a1, a2, h1, h2, i, hne⟩ := h refine ⟨i, ⟨_, _, mem_image_of_mem _ h1, mem_image_of_mem _ h2, hne⟩, fun ai => ?_⟩ @@ -684,21 +701,21 @@ lemma exists_of_one_lt_card_pi {ι : Type*} {α : ι → Type*} [∀ i, Decidabl exacts [⟨a1, h1, hne⟩, ⟨a2, h2, hne⟩] theorem card_eq_succ_iff_cons : - s.card = n + 1 ↔ ∃ a t, ∃ (h : a ∉ t), cons a t h = s ∧ t.card = n := + #s = n + 1 ↔ ∃ a t, ∃ (h : a ∉ t), cons a t h = s ∧ #t = n := ⟨cons_induction_on s (by simp) fun a s _ _ _ => ⟨a, s, by simp_all⟩, fun ⟨a, t, _, hs, _⟩ => by simpa [← hs]⟩ section DecidableEq variable [DecidableEq α] -theorem card_eq_succ : s.card = n + 1 ↔ ∃ a t, a ∉ t ∧ insert a t = s ∧ t.card = n := +theorem card_eq_succ : #s = n + 1 ↔ ∃ a t, a ∉ t ∧ insert a t = s ∧ #t = n := ⟨fun h => - let ⟨a, has⟩ := card_pos.mp (h.symm ▸ Nat.zero_lt_succ _ : 0 < s.card) + let ⟨a, has⟩ := card_pos.mp (h.symm ▸ Nat.zero_lt_succ _ : 0 < #s) ⟨a, s.erase a, s.not_mem_erase a, insert_erase has, by simp only [h, card_erase_of_mem has, Nat.add_sub_cancel_right]⟩, - fun ⟨a, t, hat, s_eq, n_eq⟩ => s_eq ▸ n_eq ▸ card_insert_of_not_mem hat⟩ + fun ⟨_, _, hat, s_eq, n_eq⟩ => s_eq ▸ n_eq ▸ card_insert_of_not_mem hat⟩ -theorem card_eq_two : s.card = 2 ↔ ∃ x y, x ≠ y ∧ s = {x, y} := by +theorem card_eq_two : #s = 2 ↔ ∃ x y, x ≠ y ∧ s = {x, y} := by constructor · rw [card_eq_succ] simp_rw [card_eq_one] @@ -707,7 +724,7 @@ theorem card_eq_two : s.card = 2 ↔ ∃ x y, x ≠ y ∧ s = {x, y} := by · rintro ⟨x, y, h, rfl⟩ exact card_pair h -theorem card_eq_three : s.card = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y ≠ z ∧ s = {x, y, z} := by +theorem card_eq_three : #s = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y ≠ z ∧ s = {x, y, z} := by constructor · rw [card_eq_succ] simp_rw [card_eq_two] @@ -720,7 +737,7 @@ theorem card_eq_three : s.card = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y ≠ end DecidableEq -theorem two_lt_card_iff : 2 < s.card ↔ ∃ a b c, a ∈ s ∧ b ∈ s ∧ c ∈ s ∧ a ≠ b ∧ a ≠ c ∧ b ≠ c := by +theorem two_lt_card_iff : 2 < #s ↔ ∃ a b c, a ∈ s ∧ b ∈ s ∧ c ∈ s ∧ a ≠ b ∧ a ≠ c ∧ b ≠ c := by classical simp_rw [lt_iff_add_one_le, le_card_iff_exists_subset_card, reduceAdd, card_eq_three, ← exists_and_left, exists_comm (α := Finset α)] @@ -730,7 +747,7 @@ theorem two_lt_card_iff : 2 < s.card ↔ ∃ a b c, a ∈ s ∧ b ∈ s ∧ c · rintro ⟨a, b, c, ha, hb, hc, hab, hac, hbc⟩ exact ⟨a, b, c, {a, b, c}, by simp_all [insert_subset_iff]⟩ -theorem two_lt_card : 2 < s.card ↔ ∃ a ∈ s, ∃ b ∈ s, ∃ c ∈ s, a ≠ b ∧ a ≠ c ∧ b ≠ c := by +theorem two_lt_card : 2 < #s ↔ ∃ a ∈ s, ∃ b ∈ s, ∃ c ∈ s, a ≠ b ∧ a ≠ c ∧ b ≠ c := by simp_rw [two_lt_card_iff, exists_and_left] /-! ### Inductions -/ @@ -743,9 +760,9 @@ def strongInduction {p : Finset α → Sort*} (H : ∀ s, (∀ t ⊂ s, p t) → ∀ s : Finset α, p s | s => H s fun t h => - have : t.card < s.card := card_lt_card h + have : #t < #s := card_lt_card h strongInduction H t - termination_by s => Finset.card s + termination_by s => #s @[nolint unusedHavesSuffices] -- Porting note: false positive theorem strongInduction_eq {p : Finset α → Sort*} (H : ∀ s, (∀ t ⊂ s, p t) → p s) @@ -789,25 +806,25 @@ protected lemma Nonempty.strong_induction {p : ∀ s, s.Nonempty → Prop} · refine h₁ hs fun t ht hts ↦ ?_ have := card_lt_card hts exact ht.strong_induction h₀ h₁ -termination_by s => Finset.card s +termination_by s => #s /-- Suppose that, given that `p t` can be defined on all supersets of `s` of cardinality less than `n`, one knows how to define `p s`. Then one can inductively define `p s` for all finsets `s` of cardinality less than `n`, starting from finsets of card `n` and iterating. This can be used either to define data, or to prove properties. -/ def strongDownwardInduction {p : Finset α → Sort*} {n : ℕ} - (H : ∀ t₁, (∀ {t₂ : Finset α}, t₂.card ≤ n → t₁ ⊂ t₂ → p t₂) → t₁.card ≤ n → p t₁) : - ∀ s : Finset α, s.card ≤ n → p s + (H : ∀ t₁, (∀ {t₂ : Finset α}, #t₂ ≤ n → t₁ ⊂ t₂ → p t₂) → #t₁ ≤ n → p t₁) : + ∀ s : Finset α, #s ≤ n → p s | s => H s fun {t} ht h => have := Finset.card_lt_card h - have : n - t.card < n - s.card := by omega + have : n - #t < n - #s := by omega strongDownwardInduction H t ht - termination_by s => n - s.card + termination_by s => n - #s @[nolint unusedHavesSuffices] -- Porting note: false positive theorem strongDownwardInduction_eq {p : Finset α → Sort*} - (H : ∀ t₁, (∀ {t₂ : Finset α}, t₂.card ≤ n → t₁ ⊂ t₂ → p t₂) → t₁.card ≤ n → p t₁) + (H : ∀ t₁, (∀ {t₂ : Finset α}, #t₂ ≤ n → t₁ ⊂ t₂ → p t₂) → #t₁ ≤ n → p t₁) (s : Finset α) : strongDownwardInduction H s = H s fun {t} ht _ => strongDownwardInduction H t ht := by rw [strongDownwardInduction] @@ -815,13 +832,13 @@ theorem strongDownwardInduction_eq {p : Finset α → Sort*} /-- Analogue of `strongDownwardInduction` with order of arguments swapped. -/ @[elab_as_elim] def strongDownwardInductionOn {p : Finset α → Sort*} (s : Finset α) - (H : ∀ t₁, (∀ {t₂ : Finset α}, t₂.card ≤ n → t₁ ⊂ t₂ → p t₂) → t₁.card ≤ n → p t₁) : - s.card ≤ n → p s := + (H : ∀ t₁, (∀ {t₂ : Finset α}, #t₂ ≤ n → t₁ ⊂ t₂ → p t₂) → #t₁ ≤ n → p t₁) : + #s ≤ n → p s := strongDownwardInduction H s @[nolint unusedHavesSuffices] -- Porting note: false positive theorem strongDownwardInductionOn_eq {p : Finset α → Sort*} (s : Finset α) - (H : ∀ t₁, (∀ {t₂ : Finset α}, t₂.card ≤ n → t₁ ⊂ t₂ → p t₂) → t₁.card ≤ n → p t₁) : + (H : ∀ t₁, (∀ {t₂ : Finset α}, #t₂ ≤ n → t₁ ⊂ t₂ → p t₂) → #t₁ ≤ n → p t₁) : s.strongDownwardInductionOn H = H s fun {t} ht _ => t.strongDownwardInductionOn H ht := by dsimp only [strongDownwardInductionOn] rw [strongDownwardInduction] diff --git a/Mathlib/Data/Finset/Density.lean b/Mathlib/Data/Finset/Density.lean index 002513c40e808..08b5292155a45 100644 --- a/Mathlib/Data/Finset/Density.lean +++ b/Mathlib/Data/Finset/Density.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Order.Field.Basic +import Mathlib.Algebra.Order.Field.Rat import Mathlib.Data.Fintype.Card import Mathlib.Data.NNRat.Order import Mathlib.Data.Rat.Cast.CharZero diff --git a/Mathlib/Data/Finset/Finsupp.lean b/Mathlib/Data/Finset/Finsupp.lean index 3d7111a8e4605..43e04648e3ccf 100644 --- a/Mathlib/Data/Finset/Finsupp.lean +++ b/Mathlib/Data/Finset/Finsupp.lean @@ -70,8 +70,7 @@ theorem mem_finsupp_iff_of_support_subset {t : ι →₀ Finset α} (ht : t.supp · rwa [H, mem_zero] at h @[simp] -theorem card_finsupp (s : Finset ι) (t : ι → Finset α) : - (s.finsupp t).card = ∏ i ∈ s, (t i).card := +theorem card_finsupp (s : Finset ι) (t : ι → Finset α) : #(s.finsupp t) = ∏ i ∈ s, #(t i) := (card_map _).trans <| card_pi _ _ end Finset @@ -90,7 +89,7 @@ theorem mem_pi {f : ι →₀ Finset α} {g : ι →₀ α} : g ∈ f.pi ↔ ∀ mem_finsupp_iff_of_support_subset <| Subset.refl _ @[simp] -theorem card_pi (f : ι →₀ Finset α) : f.pi.card = f.prod fun i => (f i).card := by +theorem card_pi (f : ι →₀ Finset α) : #f.pi = f.prod fun i ↦ #(f i) := by rw [pi, card_finsupp] exact Finset.prod_congr rfl fun i _ => by simp only [Pi.natCast_apply, Nat.cast_id] diff --git a/Mathlib/Data/Finset/Fold.lean b/Mathlib/Data/Finset/Fold.lean index 39befbf6c8239..931d4b86e5a6b 100644 --- a/Mathlib/Data/Finset/Fold.lean +++ b/Mathlib/Data/Finset/Fold.lean @@ -231,7 +231,7 @@ theorem fold_max_lt : s.fold max b f < c ↔ b < c ∧ ∀ x ∈ s, f x < c := b theorem lt_fold_max : c < s.fold max b f ↔ c < b ∨ ∃ x ∈ s, c < f x := fold_op_rel_iff_or lt_max_iff -theorem fold_max_add [Add β] [CovariantClass β β (Function.swap (· + ·)) (· ≤ ·)] (n : WithBot β) +theorem fold_max_add [Add β] [AddRightMono β] (n : WithBot β) (s : Finset α) : (s.fold max ⊥ fun x : α => ↑(f x) + n) = s.fold max ⊥ ((↑) ∘ f) + n := by classical induction' s using Finset.induction_on with a s _ ih <;> simp [*, max_add_add_right] diff --git a/Mathlib/Data/Finset/Functor.lean b/Mathlib/Data/Finset/Functor.lean index 1359446c44d7e..219d4336368e2 100644 --- a/Mathlib/Data/Finset/Functor.lean +++ b/Mathlib/Data/Finset/Functor.lean @@ -37,8 +37,8 @@ construct `Functor Finset` when working classically. -/ protected instance functor : Functor Finset where map f s := s.image f instance lawfulFunctor : LawfulFunctor Finset where - id_map s := image_id - comp_map f g s := image_image.symm + id_map _ := image_id + comp_map _ _ _ := image_image.symm map_const {α} {β} := by simp only [Functor.mapConst, Functor.map] @[simp] @@ -115,8 +115,8 @@ instance lawfulApplicative : LawfulApplicative Finset := obtain ⟨_, _, rfl⟩ := hf exact hb pure_seq := fun f s => by simp only [pure_def, seq_def, sup_singleton, fmap_def] - map_pure := fun f a => image_singleton _ _ - seq_pure := fun s a => sup_singleton'' _ _ + map_pure := fun _ _ => image_singleton _ _ + seq_pure := fun _ _ => sup_singleton'' _ _ seq_assoc := fun s t u => by ext a simp_rw [seq_def, fmap_def] @@ -153,9 +153,9 @@ theorem bind_def {α β} : (· >>= ·) = sup (α := Finset α) (β := β) := instance : LawfulMonad Finset := { Finset.lawfulApplicative with - bind_pure_comp := fun f s => sup_singleton'' _ _ - bind_map := fun t s => rfl - pure_bind := fun t s => sup_singleton + bind_pure_comp := fun _ _ => sup_singleton'' _ _ + bind_map := fun _ _ => rfl + pure_bind := fun _ _ => sup_singleton bind_assoc := fun s f g => by simp only [bind, ← sup_biUnion, sup_eq_biUnion, biUnion_biUnion] } end Monad diff --git a/Mathlib/Data/Finset/Grade.lean b/Mathlib/Data/Finset/Grade.lean index 4c5c5fc907f85..73c5f16bbbb90 100644 --- a/Mathlib/Data/Finset/Grade.lean +++ b/Mathlib/Data/Finset/Grade.lean @@ -47,7 +47,7 @@ lemma isAtom_iff : IsAtom s ↔ ∃ a, s = {a} := by simp [← bot_covBy_iff, co instance instGradeMinOrder : GradeMinOrder ℕ (Multiset α) where grade := card grade_strictMono := card_strictMono - covBy_grade s t := CovBy.card_multiset + covBy_grade _ _ := CovBy.card_multiset isMin_grade s hs := by rw [isMin_iff_eq_bot.1 hs]; exact isMin_bot @[simp] lemma grade_eq (m : Multiset α) : grade ℕ m = card m := rfl diff --git a/Mathlib/Data/Finset/Image.lean b/Mathlib/Data/Finset/Image.lean index 88939058da20c..7901095ab605f 100644 --- a/Mathlib/Data/Finset/Image.lean +++ b/Mathlib/Data/Finset/Image.lean @@ -141,7 +141,7 @@ theorem _root_.Function.Commute.finset_map {f g : α ↪ α} (h : Function.Commu @[simp] theorem map_subset_map {s₁ s₂ : Finset α} : s₁.map f ⊆ s₂.map f ↔ s₁ ⊆ s₂ := - ⟨fun h x xs => (mem_map' _).1 <| h <| (mem_map' f).2 xs, + ⟨fun h _ xs => (mem_map' _).1 <| h <| (mem_map' f).2 xs, fun h => by simp [subset_def, Multiset.map_subset_map h]⟩ @[gcongr] alias ⟨_, _root_.GCongr.finsetMap_subset⟩ := map_subset_map @@ -625,7 +625,7 @@ elements belong to `s`. -/ protected def subtype {α} (p : α → Prop) [DecidablePred p] (s : Finset α) : Finset (Subtype p) := (s.filter p).attach.map ⟨fun x => ⟨x.1, by simpa using (Finset.mem_filter.1 x.2).2⟩, - fun x y H => Subtype.eq <| Subtype.mk.inj H⟩ + fun _ _ H => Subtype.eq <| Subtype.mk.inj H⟩ @[simp] theorem mem_subtype {p : α → Prop} [DecidablePred p] {s : Finset α} : diff --git a/Mathlib/Data/Finset/Lattice.lean b/Mathlib/Data/Finset/Lattice.lean index b41a111701bda..9db20f9663e09 100644 --- a/Mathlib/Data/Finset/Lattice.lean +++ b/Mathlib/Data/Finset/Lattice.lean @@ -130,6 +130,7 @@ theorem sup_ite (p : β → Prop) [DecidablePred p] : (s.sup fun i => ite (p i) (f i) (g i)) = (s.filter p).sup f ⊔ (s.filter fun i => ¬p i).sup g := fold_ite _ +@[gcongr] theorem sup_mono_fun {g : β → α} (h : ∀ b ∈ s, f b ≤ g b) : s.sup f ≤ s.sup g := Finset.sup_le fun b hb => le_trans (h b hb) (le_sup hb) @@ -354,6 +355,7 @@ theorem inf_ite (p : β → Prop) [DecidablePred p] : (s.inf fun i ↦ ite (p i) (f i) (g i)) = (s.filter p).inf f ⊓ (s.filter fun i ↦ ¬ p i).inf g := fold_ite _ +@[gcongr] theorem inf_mono_fun {g : β → α} (h : ∀ b ∈ s, f b ≤ g b) : s.inf f ≤ s.inf g := Finset.le_inf fun b hb => le_trans (inf_le hb) (h b hb) @@ -629,7 +631,7 @@ protected theorem lt_sup_iff : a < s.sup f ↔ ∃ b ∈ s, a < f b := by @[simp] protected theorem sup_lt_iff (ha : ⊥ < a) : s.sup f < a ↔ ∀ b ∈ s, f b < a := - ⟨fun hs b hb => lt_of_le_of_lt (le_sup hb) hs, + ⟨fun hs _ hb => lt_of_le_of_lt (le_sup hb) hs, 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⟩ @@ -732,6 +734,10 @@ theorem le_sup' {b : β} (h : b ∈ s) : f b ≤ s.sup' ⟨b, h⟩ f := theorem le_sup'_of_le {a : α} {b : β} (hb : b ∈ s) (h : a ≤ f b) : a ≤ s.sup' ⟨b, hb⟩ f := h.trans <| le_sup' _ hb +lemma sup'_eq_of_forall {a : α} (h : ∀ b ∈ s, f b = a) : s.sup' H f = a := + le_antisymm (sup'_le _ _ (fun _ hb ↦ (h _ hb).le)) + (le_sup'_of_le _ H.choose_spec (h _ H.choose_spec).ge) + @[simp] theorem sup'_const (a : α) : s.sup' H (fun _ => a) = a := by apply le_antisymm @@ -814,7 +820,7 @@ theorem _root_.map_finset_sup' [SemilatticeSup β] [FunLike F α β] [SupHomClas refine hs.cons_induction ?_ ?_ <;> intros <;> simp [*] lemma nsmul_sup' {α β : Type*} [AddMonoid β] [LinearOrder β] - [CovariantClass β β (· + ·) (· ≤ ·)] [CovariantClass β β (swap (· + ·)) (· ≤ ·)] + [AddLeftMono β] [AddRightMono β] {s : Finset α} (hs : s.Nonempty) (f : α → β) (n : ℕ) : s.sup' hs (fun a => n • f a) = n • s.sup' hs f := let ns : SupHom β β := { toFun := (n • ·), map_sup' := fun _ _ => (nsmul_right_mono n).map_max } @@ -900,6 +906,9 @@ theorem inf'_le {b : β} (h : b ∈ s) : s.inf' ⟨b, h⟩ f ≤ f b := theorem inf'_le_of_le {a : α} {b : β} (hb : b ∈ s) (h : f b ≤ a) : s.inf' ⟨b, hb⟩ f ≤ a := (inf'_le _ hb).trans h +lemma inf'_eq_of_forall {a : α} (h : ∀ b ∈ s, f b = a) : s.inf' H f = a := + sup'_eq_of_forall (α := αᵒᵈ) H f h + @[simp] theorem inf'_const (a : α) : (s.inf' H fun _ => a) = a := sup'_const (α := αᵒᵈ) H a @@ -966,7 +975,7 @@ theorem _root_.map_finset_inf' [SemilatticeInf β] [FunLike F α β] [InfHomClas refine hs.cons_induction ?_ ?_ <;> intros <;> simp [*] lemma nsmul_inf' {α β : Type*} [AddMonoid β] [LinearOrder β] - [CovariantClass β β (· + ·) (· ≤ ·)] [CovariantClass β β (swap (· + ·)) (· ≤ ·)] + [AddLeftMono β] [AddRightMono β] {s : Finset α} (hs : s.Nonempty) (f : α → β) (n : ℕ) : s.inf' hs (fun a => n • f a) = n • s.inf' hs f := let ns : InfHom β β := { toFun := (n • ·), map_inf' := fun _ _ => (nsmul_right_mono n).map_min } @@ -1181,12 +1190,18 @@ theorem mem_sup {α β} [DecidableEq β] {s : Finset α} {f : α → Multiset β end Multiset namespace Finset +variable [DecidableEq α] {s : Finset ι} {f : ι → Finset α} {a : α} -theorem mem_sup {α β} [DecidableEq β] {s : Finset α} {f : α → Finset β} {x : β} : - x ∈ s.sup f ↔ ∃ v ∈ s, x ∈ f v := by - change _ ↔ ∃ v ∈ s, x ∈ (f v).val - rw [← Multiset.mem_sup, ← Multiset.mem_toFinset, sup_toFinset] - simp_rw [val_toFinset] +set_option linter.docPrime false in +@[simp] lemma mem_sup' (hs) : a ∈ s.sup' hs f ↔ ∃ i ∈ s, a ∈ f i := by + induction' hs using Nonempty.cons_induction <;> simp [*] + +set_option linter.docPrime false in +@[simp] lemma mem_inf' (hs) : a ∈ s.inf' hs f ↔ ∀ i ∈ s, a ∈ f i := by + induction' hs using Nonempty.cons_induction <;> simp [*] + +@[simp] lemma mem_sup : a ∈ s.sup f ↔ ∃ i ∈ s, a ∈ f i := by + induction' s using cons_induction <;> simp [*] theorem sup_eq_biUnion {α β} [DecidableEq β] (s : Finset α) (t : α → Finset β) : s.sup t = s.biUnion t := by @@ -1194,14 +1209,14 @@ theorem sup_eq_biUnion {α β} [DecidableEq β] (s : Finset α) (t : α → Fins rw [mem_sup, mem_biUnion] @[simp] -theorem sup_singleton'' [DecidableEq α] (s : Finset β) (f : β → α) : +theorem sup_singleton'' (s : Finset β) (f : β → α) : (s.sup fun b => {f b}) = s.image f := by ext a rw [mem_sup, mem_image] simp only [mem_singleton, eq_comm] @[simp] -theorem sup_singleton' [DecidableEq α] (s : Finset α) : s.sup singleton = s := +theorem sup_singleton' (s : Finset α) : s.sup singleton = s := (s.sup_singleton'' _).trans image_id end Finset diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index 4db70840b348d..a7d6db38c1b90 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -46,16 +46,16 @@ theorem coe_image₂ (f : α → β → γ) (s : Finset α) (t : Finset β) : Set.ext fun _ => mem_image₂ theorem card_image₂_le (f : α → β → γ) (s : Finset α) (t : Finset β) : - (image₂ f s t).card ≤ s.card * t.card := + #(image₂ f s t) ≤ #s * #t := card_image_le.trans_eq <| card_product _ _ theorem card_image₂_iff : - (image₂ f s t).card = s.card * t.card ↔ (s ×ˢ t : Set (α × β)).InjOn fun x => f x.1 x.2 := by + #(image₂ f s t) = #s * #t ↔ (s ×ˢ t : Set (α × β)).InjOn fun x => f x.1 x.2 := by rw [← card_product, ← coe_product] exact card_image_iff theorem card_image₂ (hf : Injective2 f) (s : Finset α) (t : Finset β) : - (image₂ f s t).card = s.card * t.card := + #(image₂ f s t) = #s * #t := (card_image_of_injective _ hf.uncurry).trans <| card_product _ _ theorem mem_image₂_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image₂ f s t := @@ -64,13 +64,16 @@ theorem mem_image₂_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image₂ f theorem mem_image₂_iff (hf : Injective2 f) : f a b ∈ image₂ f s t ↔ a ∈ s ∧ b ∈ t := by rw [← mem_coe, coe_image₂, mem_image2_iff hf, mem_coe, mem_coe] +@[gcongr] theorem image₂_subset (hs : s ⊆ s') (ht : t ⊆ t') : image₂ f s t ⊆ image₂ f s' t' := by rw [← coe_subset, coe_image₂, coe_image₂] exact image2_subset hs ht +@[gcongr] theorem image₂_subset_left (ht : t ⊆ t') : image₂ f s t ⊆ image₂ f s t' := image₂_subset Subset.rfl ht +@[gcongr] theorem image₂_subset_right (hs : s ⊆ s') : image₂ f s t ⊆ image₂ f s' t := image₂_subset hs Subset.rfl @@ -193,11 +196,11 @@ theorem image₂_congr' (h : ∀ a b, f a b = f' a b) : image₂ f s t = image variable (s t) -theorem card_image₂_singleton_left (hf : Injective (f a)) : (image₂ f {a} t).card = t.card := by +theorem card_image₂_singleton_left (hf : Injective (f a)) : #(image₂ f {a} t) = #t := by rw [image₂_singleton_left, card_image_of_injective _ hf] theorem card_image₂_singleton_right (hf : Injective fun a => f a b) : - (image₂ f s {b}).card = s.card := by rw [image₂_singleton_right, card_image_of_injective _ hf] + #(image₂ f s {b}) = #s := by rw [image₂_singleton_right, card_image_of_injective _ hf] theorem image₂_singleton_inter [DecidableEq β] (t₁ t₂ : Finset β) (hf : Injective (f a)) : image₂ f {a} (t₁ ∩ t₂) = image₂ f {a} t₁ ∩ image₂ f {a} t₂ := by @@ -208,13 +211,13 @@ theorem image₂_inter_singleton [DecidableEq α] (s₁ s₂ : Finset α) (hf : simp_rw [image₂_singleton_right, image_inter _ _ hf] theorem card_le_card_image₂_left {s : Finset α} (hs : s.Nonempty) (hf : ∀ a, Injective (f a)) : - t.card ≤ (image₂ f s t).card := by + #t ≤ #(image₂ f s t) := by obtain ⟨a, ha⟩ := hs rw [← card_image₂_singleton_left _ (hf a)] exact card_le_card (image₂_subset_right <| singleton_subset_iff.2 ha) theorem card_le_card_image₂_right {t : Finset β} (ht : t.Nonempty) - (hf : ∀ b, Injective fun a => f a b) : s.card ≤ (image₂ f s t).card := by + (hf : ∀ b, Injective fun a => f a b) : #s ≤ #(image₂ f s t) := by obtain ⟨b, hb⟩ := ht rw [← card_image₂_singleton_right _ (hf b)] exact card_le_card (image₂_subset_left <| singleton_subset_iff.2 hb) @@ -428,7 +431,7 @@ theorem image₂_right_identity {f : γ → β → γ} {b : β} (h : ∀ a, f a applications are disjoint (but not necessarily distinct!), then the size of `t` divides the size of `Finset.image₂ f s t`. -/ theorem card_dvd_card_image₂_right (hf : ∀ a ∈ s, Injective (f a)) - (hs : ((fun a => t.image <| f a) '' s).PairwiseDisjoint id) : t.card ∣ (image₂ f s t).card := by + (hs : ((fun a => t.image <| f a) '' s).PairwiseDisjoint id) : #t ∣ #(image₂ f s t) := by classical induction' s using Finset.induction with a s _ ih · simp @@ -450,7 +453,7 @@ applications are disjoint (but not necessarily distinct!), then the size of `s` `Finset.image₂ f s t`. -/ theorem card_dvd_card_image₂_left (hf : ∀ b ∈ t, Injective fun a => f a b) (ht : ((fun b => s.image fun a => f a b) '' t).PairwiseDisjoint id) : - s.card ∣ (image₂ f s t).card := by rw [← image₂_swap]; exact card_dvd_card_image₂_right hf ht + #s ∣ #(image₂ f s t) := by rw [← image₂_swap]; exact card_dvd_card_image₂_right hf ht /-- If a `Finset` is a subset of the image of two `Set`s under a binary operation, then it is a subset of the `Finset.image₂` of two `Finset` subsets of these `Set`s. -/ @@ -579,7 +582,7 @@ variable {ι : Type*} {α β γ : ι → Type*} [DecidableEq ι] [Fintype ι] [ lemma piFinset_image₂ (f : ∀ i, α i → β i → γ i) (s : ∀ i, Finset (α i)) (t : ∀ i, Finset (β i)) : piFinset (fun i ↦ image₂ (f i) (s i) (t i)) = image₂ (fun a b i ↦ f _ (a i) (b i)) (piFinset s) (piFinset t) := by - ext; simp only [mem_piFinset, mem_image₂, Classical.skolem, forall_and, Function.funext_iff] + ext; simp only [mem_piFinset, mem_image₂, Classical.skolem, forall_and, funext_iff] end Fintype diff --git a/Mathlib/Data/Finset/NatAntidiagonal.lean b/Mathlib/Data/Finset/NatAntidiagonal.lean index c5cb7f832ea29..d1860f6db928e 100644 --- a/Mathlib/Data/Finset/NatAntidiagonal.lean +++ b/Mathlib/Data/Finset/NatAntidiagonal.lean @@ -149,12 +149,12 @@ theorem antidiagonal.snd_lt {n : ℕ} {kl : ℕ × ℕ} (hlk : kl ∈ antidiagon /-- The set `antidiagonal n` is equivalent to `Fin (n+1)`, via the first projection. --/ @[simps] def antidiagonalEquivFin (n : ℕ) : antidiagonal n ≃ Fin (n + 1) where - toFun := fun ⟨⟨i, j⟩, h⟩ ↦ ⟨i, antidiagonal.fst_lt h⟩ + toFun := fun ⟨⟨i, _⟩, h⟩ ↦ ⟨i, antidiagonal.fst_lt h⟩ invFun := fun ⟨i, h⟩ ↦ ⟨⟨i, n - i⟩, by rw [mem_antidiagonal, add_comm, Nat.sub_add_cancel] exact Nat.le_of_lt_succ h⟩ left_inv := by rintro ⟨⟨i, j⟩, h⟩; ext; rfl - right_inv x := rfl + right_inv _ := rfl end Nat diff --git a/Mathlib/Data/Finset/NoncommProd.lean b/Mathlib/Data/Finset/NoncommProd.lean index 6074576260a47..7140198dd8237 100644 --- a/Mathlib/Data/Finset/NoncommProd.lean +++ b/Mathlib/Data/Finset/NoncommProd.lean @@ -202,7 +202,7 @@ theorem noncommProd_commute (s : Multiset α) (comm) (y : α) (h : ∀ x ∈ s, exact Commute.list_prod_right _ _ h theorem mul_noncommProd_erase [DecidableEq α] (s : Multiset α) {a : α} (h : a ∈ s) (comm) - (comm' := fun x hx y hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : + (comm' := fun _ hx _ hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : a * (s.erase a).noncommProd comm' = s.noncommProd comm := by induction' s using Quotient.inductionOn with l simp only [quot_mk_to_coe, mem_coe, coe_erase, noncommProd_coe] at comm h ⊢ @@ -213,7 +213,7 @@ theorem mul_noncommProd_erase [DecidableEq α] (s : Multiset α) {a : α} (h : a exact comm hx hy hxy theorem noncommProd_erase_mul [DecidableEq α] (s : Multiset α) {a : α} (h : a ∈ s) (comm) - (comm' := fun x hx y hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : + (comm' := fun _ hx _ hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : (s.erase a).noncommProd comm' * a = s.noncommProd comm := by suffices ∀ b ∈ erase s a, Commute a b by rw [← (noncommProd_commute (s.erase a) comm' a this).eq, mul_noncommProd_erase s h comm comm'] @@ -317,7 +317,7 @@ variable [FunLike F β γ] @[to_additive] theorem map_noncommProd [MonoidHomClass F β γ] (s : Finset α) (f : α → β) (comm) (g : F) : g (s.noncommProd f comm) = - s.noncommProd (fun i => g (f i)) fun x hx y hy _ => (comm.of_refl hx hy).map g := by + s.noncommProd (fun i => g (f i)) fun _ hx _ hy _ => (comm.of_refl hx hy).map g := by simp [noncommProd, Multiset.map_noncommProd] @[deprecated (since := "2024-07-23")] alias noncommProd_map := map_noncommProd @@ -340,14 +340,14 @@ theorem noncommProd_commute (s : Finset α) (f : α → β) (comm) (y : β) exact h x hx theorem mul_noncommProd_erase [DecidableEq α] (s : Finset α) {a : α} (h : a ∈ s) (f : α → β) (comm) - (comm' := fun x hx y hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : + (comm' := fun _ hx _ hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : f a * (s.erase a).noncommProd f comm' = s.noncommProd f comm := by classical simpa only [← Multiset.map_erase_of_mem _ _ h] using Multiset.mul_noncommProd_erase (s.1.map f) (Multiset.mem_map_of_mem f h) _ theorem noncommProd_erase_mul [DecidableEq α] (s : Finset α) {a : α} (h : a ∈ s) (f : α → β) (comm) - (comm' := fun x hx y hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : + (comm' := fun _ hx _ hy hxy ↦ comm (s.mem_of_mem_erase hx) (s.mem_of_mem_erase hy) hxy) : (s.erase a).noncommProd f comm' * f a = s.noncommProd f comm := by classical simpa only [← Multiset.map_erase_of_mem _ _ h] using diff --git a/Mathlib/Data/Finset/Order.lean b/Mathlib/Data/Finset/Order.lean index 09570b4726fd6..f5a514599efdb 100644 --- a/Mathlib/Data/Finset/Order.lean +++ b/Mathlib/Data/Finset/Order.lean @@ -18,9 +18,9 @@ theorem Directed.finset_le {r : α → α → Prop} [IsTrans α r] {ι} [hι : N (D : Directed r f) (s : Finset ι) : ∃ z, ∀ i ∈ s, r (f i) (f z) := show ∃ z, ∀ i ∈ s.1, r (f i) (f z) from Multiset.induction_on s.1 (let ⟨z⟩ := hι; ⟨z, fun _ ↦ by simp⟩) - fun i s ⟨j, H⟩ ↦ + fun i _ ⟨j, H⟩ ↦ let ⟨k, h₁, h₂⟩ := D i j - ⟨k, fun a h ↦ (Multiset.mem_cons.1 h).casesOn (fun h ↦ h.symm ▸ h₁) + ⟨k, fun _ h ↦ (Multiset.mem_cons.1 h).casesOn (fun h ↦ h.symm ▸ h₁) fun h ↦ _root_.trans (H _ h) h₂⟩ theorem Finset.exists_le [Nonempty α] [Preorder α] [IsDirected α (· ≤ ·)] (s : Finset α) : diff --git a/Mathlib/Data/Finset/Piecewise.lean b/Mathlib/Data/Finset/Piecewise.lean index 959a4e4280a6e..99cea5cc557d0 100644 --- a/Mathlib/Data/Finset/Piecewise.lean +++ b/Mathlib/Data/Finset/Piecewise.lean @@ -26,7 +26,6 @@ variable {ι : Type*} {π : ι → Sort*} (s : Finset ι) (f g : ∀ i, π i) complement. -/ def piecewise [∀ j, Decidable (j ∈ s)] : ∀ i, π i := fun i ↦ if i ∈ s then f i else g i --- Porting note (#10618): @[simp] can prove this lemma piecewise_insert_self [DecidableEq ι] {j : ι} [∀ i, Decidable (i ∈ insert j s)] : (insert j s).piecewise f g j = f j := by simp [piecewise] diff --git a/Mathlib/Data/Finset/Preimage.lean b/Mathlib/Data/Finset/Preimage.lean index 657acee065919..1331695180e29 100644 --- a/Mathlib/Data/Finset/Preimage.lean +++ b/Mathlib/Data/Finset/Preimage.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.Finite +import Mathlib.Data.Finset.Sum /-! # Preimage of a `Finset` under an injective map. @@ -46,7 +47,7 @@ theorem preimage_univ {f : α → β} [Fintype α] [Fintype β] (hf) : preimage @[simp] theorem preimage_inter [DecidableEq α] [DecidableEq β] {f : α → β} {s t : Finset β} (hs : Set.InjOn f (f ⁻¹' ↑s)) (ht : Set.InjOn f (f ⁻¹' ↑t)) : - (preimage (s ∩ t) f fun x₁ hx₁ x₂ hx₂ => + (preimage (s ∩ t) f fun _ hx₁ _ hx₂ => hs (mem_of_mem_inter_left hx₁) (mem_of_mem_inter_left hx₂)) = preimage s f hs ∩ preimage t f ht := Finset.coe_injective (by simp) @@ -54,8 +55,8 @@ theorem preimage_inter [DecidableEq α] [DecidableEq β] {f : α → β} {s t : @[simp] theorem preimage_union [DecidableEq α] [DecidableEq β] {f : α → β} {s t : Finset β} (hst) : preimage (s ∪ t) f hst = - (preimage s f fun x₁ hx₁ x₂ hx₂ => hst (mem_union_left _ hx₁) (mem_union_left _ hx₂)) ∪ - preimage t f fun x₁ hx₁ x₂ hx₂ => hst (mem_union_right _ hx₁) (mem_union_right _ hx₂) := + (preimage s f fun _ hx₁ _ hx₂ => hst (mem_union_left _ hx₁) (mem_union_left _ hx₂)) ∪ + preimage t f fun _ hx₁ _ hx₂ => hst (mem_union_right _ hx₁) (mem_union_right _ hx₂) := Finset.coe_injective (by simp) @[simp, nolint simpNF] -- Porting note: linter complains that LHS doesn't simplify @@ -94,6 +95,10 @@ theorem image_preimage_of_bij [DecidableEq β] (f : α → β) (s : Finset β) (hf : Set.BijOn f (f ⁻¹' ↑s) ↑s) : image f (preimage s f hf.injOn) = s := Finset.coe_inj.1 <| by simpa using hf.image_eq +lemma preimage_subset_of_subset_image [DecidableEq β] {f : α → β} {s : Finset β} {t : Finset α} + (hs : s ⊆ t.image f) {hf} : s.preimage f hf ⊆ t := by + rw [← coe_subset, coe_preimage]; exact Set.preimage_subset (mod_cast hs) hf + theorem preimage_subset {f : α ↪ β} {s : Finset β} {t : Finset α} (hs : s ⊆ t.map f) : s.preimage f f.injective.injOn ⊆ t := fun _ h => (mem_map' f).1 (hs (mem_preimage.1 h)) diff --git a/Mathlib/Data/Finset/Slice.lean b/Mathlib/Data/Finset/Slice.lean index 9ad5073eabffc..577c05063d19a 100644 --- a/Mathlib/Data/Finset/Slice.lean +++ b/Mathlib/Data/Finset/Slice.lean @@ -39,13 +39,12 @@ variable {A B : Set (Finset α)} {s : Finset α} {r : ℕ} /-- `Sized r A` means that every Finset in `A` has size `r`. -/ -def Sized (r : ℕ) (A : Set (Finset α)) : Prop := - ∀ ⦃x⦄, x ∈ A → card x = r +def Sized (r : ℕ) (A : Set (Finset α)) : Prop := ∀ ⦃x⦄, x ∈ A → #x = r theorem Sized.mono (h : A ⊆ B) (hB : B.Sized r) : A.Sized r := fun _x hx => hB <| h hx @[simp] lemma sized_empty : (∅ : Set (Finset α)).Sized r := by simp [Sized] -@[simp] lemma sized_singleton : ({s} : Set (Finset α)).Sized r ↔ s.card = r := by simp [Sized] +@[simp] lemma sized_singleton : ({s} : Set (Finset α)).Sized r ↔ #s = r := by simp [Sized] theorem sized_union : (A ∪ B).Sized r ↔ A.Sized r ∧ B.Sized r := ⟨fun hA => ⟨hA.mono subset_union_left, hA.mono subset_union_right⟩, fun hA _x hx => @@ -96,7 +95,7 @@ theorem subset_powersetCard_univ_iff : 𝒜 ⊆ powersetCard r univ ↔ (𝒜 : alias ⟨_, _root_.Set.Sized.subset_powersetCard_univ⟩ := subset_powersetCard_univ_iff theorem _root_.Set.Sized.card_le (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : - card 𝒜 ≤ (Fintype.card α).choose r := by + #𝒜 ≤ (Fintype.card α).choose r := by rw [Fintype.card, ← card_powersetCard] exact card_le_card (subset_powersetCard_univ_iff.mpr h𝒜) @@ -110,15 +109,14 @@ section Slice variable {𝒜 : Finset (Finset α)} {A A₁ A₂ : Finset α} {r r₁ r₂ : ℕ} /-- The `r`-th slice of a set family is the subset of its elements which have cardinality `r`. -/ -def slice (𝒜 : Finset (Finset α)) (r : ℕ) : Finset (Finset α) := - 𝒜.filter fun i => i.card = r +def slice (𝒜 : Finset (Finset α)) (r : ℕ) : Finset (Finset α) := {A ∈ 𝒜 | #A = r} -- Porting note: old code: scoped[FinsetFamily] @[inherit_doc] scoped[Finset] infixl:90 " # " => Finset.slice /-- `A` is in the `r`-th slice of `𝒜` iff it's in `𝒜` and has cardinality `r`. -/ -theorem mem_slice : A ∈ 𝒜 # r ↔ A ∈ 𝒜 ∧ A.card = r := +theorem mem_slice : A ∈ 𝒜 # r ↔ A ∈ 𝒜 ∧ #A = r := mem_filter /-- The `r`-th slice of `𝒜` is a subset of `𝒜`. -/ @@ -143,10 +141,10 @@ variable [Fintype α] (𝒜) @[simp] theorem biUnion_slice [DecidableEq α] : (Iic <| Fintype.card α).biUnion 𝒜.slice = 𝒜 := Subset.antisymm (biUnion_subset.2 fun _r _ => slice_subset) fun s hs => - mem_biUnion.2 ⟨s.card, mem_Iic.2 <| s.card_le_univ, mem_slice.2 <| ⟨hs, rfl⟩⟩ + mem_biUnion.2 ⟨#s, mem_Iic.2 <| s.card_le_univ, mem_slice.2 <| ⟨hs, rfl⟩⟩ @[simp] -theorem sum_card_slice : (∑ r ∈ Iic (Fintype.card α), (𝒜 # r).card) = 𝒜.card := by +theorem sum_card_slice : ∑ r ∈ Iic (Fintype.card α), #(𝒜 # r) = #𝒜 := by letI := Classical.decEq α rw [← card_biUnion, biUnion_slice] exact Finset.pairwiseDisjoint_slice.subset (Set.subset_univ _) diff --git a/Mathlib/Data/Finset/Sort.lean b/Mathlib/Data/Finset/Sort.lean index 361e4f3721a7f..923e35810f214 100644 --- a/Mathlib/Data/Finset/Sort.lean +++ b/Mathlib/Data/Finset/Sort.lean @@ -219,7 +219,7 @@ theorem orderEmbOfFin_unique {s : Finset α} {k : ℕ} (h : s.card = k) {f : Fin the increasing bijection `orderEmbOfFin s h`. -/ theorem orderEmbOfFin_unique' {s : Finset α} {k : ℕ} (h : s.card = k) {f : Fin k ↪o α} (hfs : ∀ x, f x ∈ s) : f = s.orderEmbOfFin h := - RelEmbedding.ext <| Function.funext_iff.1 <| orderEmbOfFin_unique h hfs f.strictMono + RelEmbedding.ext <| funext_iff.1 <| orderEmbOfFin_unique h hfs f.strictMono /-- Two parametrizations `orderEmbOfFin` of the same set take the same value on `i` and `j` if and only if `i = j`. Since they can be defined on a priori not defeq types `Fin k` and `Fin l` diff --git a/Mathlib/Data/Finset/Sups.lean b/Mathlib/Data/Finset/Sups.lean index 5188385616bb7..0b2bf2e8a4359 100644 --- a/Mathlib/Data/Finset/Sups.lean +++ b/Mathlib/Data/Finset/Sups.lean @@ -67,11 +67,9 @@ variable (s t) theorem coe_sups : (↑(s ⊻ t) : Set α) = ↑s ⊻ ↑t := coe_image₂ _ _ _ -theorem card_sups_le : (s ⊻ t).card ≤ s.card * t.card := - card_image₂_le _ _ _ +theorem card_sups_le : #(s ⊻ t) ≤ #s * #t := card_image₂_le _ _ _ -theorem card_sups_iff : - (s ⊻ t).card = s.card * t.card ↔ (s ×ˢ t : Set (α × α)).InjOn fun x => x.1 ⊔ x.2 := +theorem card_sups_iff : #(s ⊻ t) = #s * #t ↔ (s ×ˢ t : Set (α × α)).InjOn fun x => x.1 ⊔ x.2 := card_image₂_iff variable {s s₁ s₂ t t₁ t₂ u} @@ -162,7 +160,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 : α) : - (s ⊻ t).filter (· ≤ a) = s.filter (· ≤ a) ⊻ t.filter (· ≤ a) := by + {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] variable (s t u) @@ -214,11 +212,9 @@ variable (s t) theorem coe_infs : (↑(s ⊼ t) : Set α) = ↑s ⊼ ↑t := coe_image₂ _ _ _ -theorem card_infs_le : (s ⊼ t).card ≤ s.card * t.card := - card_image₂_le _ _ _ +theorem card_infs_le : #(s ⊼ t) ≤ #s * #t := card_image₂_le _ _ _ -theorem card_infs_iff : - (s ⊼ t).card = s.card * t.card ↔ (s ×ˢ t : Set (α × α)).InjOn fun x => x.1 ⊓ x.2 := +theorem card_infs_iff : #(s ⊼ t) = #s * #t ↔ (s ×ˢ t : Set (α × α)).InjOn fun x => x.1 ⊓ x.2 := card_image₂_iff variable {s s₁ s₂ t t₁ t₂ u} @@ -309,7 +305,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 : α) : - (s ⊼ t).filter (a ≤ ·) = s.filter (a ≤ ·) ⊼ t.filter (a ≤ ·) := by + {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] variable (s t u) @@ -360,7 +356,7 @@ end DistribLattice section Finset variable [DecidableEq α] -variable {𝒜 ℬ : Finset (Finset α)} {s t : Finset α} {a : α} +variable {𝒜 ℬ : Finset (Finset α)} {s t : Finset α} @[simp] lemma powerset_union (s t : Finset α) : (s ∪ t).powerset = s.powerset ⊻ t.powerset := by ext u @@ -396,8 +392,7 @@ variable [SemilatticeSup α] [OrderBot α] [@DecidableRel α Disjoint] (s s₁ s /-- The finset of elements of the form `a ⊔ b` where `a ∈ s`, `b ∈ t` and `a` and `b` are disjoint. -/ -def disjSups : Finset α := - ((s ×ˢ t).filter fun ab : α × α => Disjoint ab.1 ab.2).image fun ab => ab.1 ⊔ ab.2 +def disjSups : Finset α := {ab ∈ s ×ˢ t | Disjoint ab.1 ab.2}.image fun ab => ab.1 ⊔ ab.2 @[inherit_doc] scoped[FinsetFamily] infixl:74 " ○ " => Finset.disjSups @@ -416,7 +411,7 @@ theorem disjSups_subset_sups : s ○ t ⊆ s ⊻ t := by variable (s t) -theorem card_disjSups_le : (s ○ t).card ≤ s.card * t.card := +theorem card_disjSups_le : #(s ○ t) ≤ #s * #t := (card_le_card disjSups_subset_sups).trans <| card_sups_le _ _ variable {s s₁ s₂ t t₁ t₂} @@ -513,7 +508,7 @@ theorem disjSups_disjSups_disjSups_comm : s ○ t ○ (u ○ v) = s ○ u ○ (t end DistribLattice section Diffs variable [DecidableEq α] -variable [GeneralizedBooleanAlgebra α] (s s₁ s₂ t t₁ t₂ u v : Finset α) +variable [GeneralizedBooleanAlgebra α] (s s₁ s₂ t t₁ t₂ u : Finset α) /-- `s \\ t` is the finset of elements of the form `a \ b` where `a ∈ s`, `b ∈ t`. -/ def diffs : Finset α → Finset α → Finset α := image₂ (· \ ·) @@ -534,10 +529,9 @@ variable (s t) @[simp, norm_cast] lemma coe_diffs : (↑(s \\ t) : Set α) = Set.image2 (· \ ·) s t := coe_image₂ _ _ _ -lemma card_diffs_le : (s \\ t).card ≤ s.card * t.card := card_image₂_le _ _ _ +lemma card_diffs_le : #(s \\ t) ≤ #s * #t := card_image₂_le _ _ _ -lemma card_diffs_iff : - (s \\ t).card = s.card * t.card ↔ (s ×ˢ t : Set (α × α)).InjOn fun x ↦ x.1 \ x.2 := +lemma card_diffs_iff : #(s \\ t) = #s * #t ↔ (s ×ˢ t : Set (α × α)).InjOn fun x ↦ x.1 \ x.2 := card_image₂_iff variable {s s₁ s₂ t t₁ t₂ u} @@ -598,7 +592,7 @@ lemma diffs_right_comm : s \\ t \\ u = s \\ u \\ t := image₂_right_comm sdiff_ end Diffs section Compls -variable [BooleanAlgebra α] (s s₁ s₂ t t₁ t₂ u v : Finset α) +variable [BooleanAlgebra α] (s s₁ s₂ t : Finset α) /-- `sᶜˢ` is the finset of elements of the form `aᶜ` where `a ∈ s`. -/ def compls : Finset α → Finset α := map ⟨compl, compl_injective⟩ @@ -608,7 +602,7 @@ scoped[FinsetFamily] postfix:max "ᶜˢ" => Finset.compls open FinsetFamily -variable {s t} {a b c : α} +variable {s t} {a : α} @[simp] lemma mem_compls : a ∈ sᶜˢ ↔ aᶜ ∈ s := by rw [Iff.comm, ← mem_map' ⟨compl, compl_injective⟩, Embedding.coeFn_mk, compl_compl, compls] @@ -619,9 +613,9 @@ variable (s t) @[simp, norm_cast] lemma coe_compls : (↑sᶜˢ : Set α) = compl '' ↑s := coe_map _ _ -@[simp] lemma card_compls : sᶜˢ.card = s.card := card_map _ +@[simp] lemma card_compls : #sᶜˢ = #s := card_map _ -variable {s s₁ s₂ t t₁ t₂ u} +variable {s s₁ s₂ t} lemma compl_mem_compls : a ∈ s → aᶜ ∈ sᶜˢ := mem_map_of_mem _ @[simp] lemma compls_subset_compls : s₁ᶜˢ ⊆ s₂ᶜˢ ↔ s₁ ⊆ s₂ := map_subset_map diff --git a/Mathlib/Data/Finset/Sym.lean b/Mathlib/Data/Finset/Sym.lean index c591056cea7ff..f7fe2a928b7c4 100644 --- a/Mathlib/Data/Finset/Sym.lean +++ b/Mathlib/Data/Finset/Sym.lean @@ -2,8 +2,6 @@ Copyright (c) 2021 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies - -[`data.finset.sym`@`98e83c3d541c77cdb7da20d79611a780ff8e7d90`..`02ba8949f486ebecf93fe7460f1ed0564b5e442c`](https://leanprover-community.github.io/mathlib-port-status/file/data/finset/sym?range=98e83c3d541c77cdb7da20d79611a780ff8e7d90..02ba8949f486ebecf93fe7460f1ed0564b5e442c) -/ import Mathlib.Data.Finset.Lattice import Mathlib.Data.Fintype.Vector diff --git a/Mathlib/Data/Finset/Union.lean b/Mathlib/Data/Finset/Union.lean index 3df81fb5d2be1..fd0fac60d95ee 100644 --- a/Mathlib/Data/Finset/Union.lean +++ b/Mathlib/Data/Finset/Union.lean @@ -69,7 +69,7 @@ lemma coe_disjiUnion {h} : (s.disjiUnion t h : Set β) = ⋃ x ∈ (s : Set α), lemma disjiUnion_disjiUnion (s : Finset α) (f : α → Finset β) (g : β → Finset γ) (h1 h2) : (s.disjiUnion f h1).disjiUnion g h2 = s.attach.disjiUnion - (fun a ↦ ((f a).disjiUnion g) fun b hb c hc ↦ + (fun a ↦ ((f a).disjiUnion g) fun _ hb _ hc ↦ h2 (mem_disjiUnion.mpr ⟨_, a.prop, hb⟩) (mem_disjiUnion.mpr ⟨_, a.prop, hc⟩)) fun a _ b _ hab ↦ disjoint_left.mpr fun x hxa hxb ↦ by diff --git a/Mathlib/Data/Finsupp/AList.lean b/Mathlib/Data/Finsupp/AList.lean index d7f3418427f67..4946a43826403 100644 --- a/Mathlib/Data/Finsupp/AList.lean +++ b/Mathlib/Data/Finsupp/AList.lean @@ -103,8 +103,7 @@ theorem insert_lookupFinsupp [DecidableEq α] (l : AList fun _x : α => M) (a : theorem singleton_lookupFinsupp (a : α) (m : M) : (singleton a m).lookupFinsupp = Finsupp.single a m := by classical - -- porting note (#10745): was `simp [← AList.insert_empty]` but timeout issues - simp only [← AList.insert_empty, insert_lookupFinsupp, empty_lookupFinsupp, Finsupp.zero_update] + simp [← AList.insert_empty] @[simp] theorem _root_.Finsupp.toAList_lookupFinsupp (f : α →₀ M) : f.toAList.lookupFinsupp = f := by diff --git a/Mathlib/Data/Finsupp/Basic.lean b/Mathlib/Data/Finsupp/Basic.lean index a9e39269baa78..97af1005ed711 100644 --- a/Mathlib/Data/Finsupp/Basic.lean +++ b/Mathlib/Data/Finsupp/Basic.lean @@ -471,7 +471,7 @@ theorem mapDomain_sum [Zero N] {f : α → β} {s : α →₀ N} {v : α → N theorem mapDomain_support [DecidableEq β] {f : α → β} {s : α →₀ M} : (s.mapDomain f).support ⊆ s.support.image f := Finset.Subset.trans support_sum <| - Finset.Subset.trans (Finset.biUnion_mono fun a _ => support_single_subset) <| by + Finset.Subset.trans (Finset.biUnion_mono fun _ _ => support_single_subset) <| by rw [Finset.biUnion_singleton] theorem mapDomain_apply' (S : Set α) {f : α → β} (x : α →₀ M) (hS : (x.support : Set α) ⊆ S) @@ -799,7 +799,7 @@ theorem filter_apply_pos {a : α} (h : p a) : f.filter p a = f a := if_pos h theorem filter_apply_neg {a : α} (h : ¬p a) : f.filter p a = 0 := if_neg h @[simp] -theorem support_filter : (f.filter p).support = f.support.filter p := rfl +theorem support_filter : (f.filter p).support = {x ∈ f.support | p x} := rfl theorem filter_zero : (0 : α →₀ M).filter p = 0 := by classical rw [← support_eq_empty, support_filter, support_zero, Finset.filter_empty] @@ -1434,9 +1434,7 @@ instance noZeroSMulDivisors [Semiring R] [AddCommMonoid M] [Module R M] {ι : Ty Finsupp.ext fun i => (smul_eq_zero.mp (DFunLike.ext_iff.mp h i)).resolve_left hc⟩ section DistribMulActionSemiHom - -variable [Semiring R] -variable [AddCommMonoid M] [AddCommMonoid N] [DistribMulAction R M] [DistribMulAction R N] +variable [Monoid R] [AddMonoid M] [AddMonoid N] [DistribMulAction R M] [DistribMulAction R N] /-- `Finsupp.single` as a `DistribMulActionSemiHom`. @@ -1669,7 +1667,7 @@ This is the `Finsupp` version of `Equiv.Pi_curry`. -/ noncomputable def sigmaFinsuppEquivPiFinsupp : ((Σj, ιs j) →₀ α) ≃ ∀ j, ιs j →₀ α where toFun := split invFun f := - onFinset (Finset.univ.sigma fun j => (f j).support) (fun ji => f ji.1 ji.2) fun g hg => + onFinset (Finset.univ.sigma fun j => (f j).support) (fun ji => f ji.1 ji.2) fun _ hg => Finset.mem_sigma.mpr ⟨Finset.mem_univ _, mem_support_iff.mpr hg⟩ left_inv f := by ext diff --git a/Mathlib/Data/Finsupp/BigOperators.lean b/Mathlib/Data/Finsupp/BigOperators.lean index 49c8433784071..170585fa66d4b 100644 --- a/Mathlib/Data/Finsupp/BigOperators.lean +++ b/Mathlib/Data/Finsupp/BigOperators.lean @@ -94,10 +94,9 @@ theorem Multiset.support_sum_eq [AddCommMonoid M] (s : Multiset (ι →₀ M)) obtain ⟨l, hl, hd⟩ := hs suffices a.Pairwise (_root_.Disjoint on Finsupp.support) by convert List.support_sum_eq a this - · simp only [Multiset.quot_mk_to_coe'', Multiset.sum_coe] - · dsimp only [Function.comp_def] - simp only [quot_mk_to_coe'', map_coe, sup_coe, Finset.le_eq_subset, - Finset.sup_eq_union, Finset.bot_eq_empty, List.foldr_map] + dsimp only [Function.comp_def] + simp only [quot_mk_to_coe'', map_coe, sup_coe, Finset.le_eq_subset, + Finset.sup_eq_union, Finset.bot_eq_empty, List.foldr_map] simp only [Multiset.quot_mk_to_coe'', Multiset.map_coe, Multiset.coe_eq_coe] at hl exact hl.symm.pairwise hd fun h ↦ _root_.Disjoint.symm h diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index 11717314f657f..31b93c4c9ac8f 100644 --- a/Mathlib/Data/Finsupp/Defs.lean +++ b/Mathlib/Data/Finsupp/Defs.lean @@ -116,11 +116,6 @@ instance instFunLike : FunLike (α →₀ M) α M := ext a exact (hf _).trans (hg _).symm⟩ -/-- Helper instance for when there are too many metavariables to apply the `DFunLike` instance -directly. -/ -instance instCoeFun : CoeFun (α →₀ M) fun _ => α → M := - inferInstance - @[ext] theorem ext {f g : α →₀ M} (h : ∀ a, f a = g a) : f = g := DFunLike.ext _ _ h @@ -176,7 +171,7 @@ theorem support_eq_empty {f : α →₀ M} : f.support = ∅ ↔ f = 0 := theorem support_nonempty_iff {f : α →₀ M} : f.support.Nonempty ↔ f ≠ 0 := by simp only [Finsupp.support_eq_empty, Finset.nonempty_iff_ne_empty, Ne] -theorem card_support_eq_zero {f : α →₀ M} : card f.support = 0 ↔ f = 0 := by simp +theorem card_support_eq_zero {f : α →₀ M} : #f.support = 0 ↔ f = 0 := by simp instance instDecidableEq [DecidableEq α] [DecidableEq M] : DecidableEq (α →₀ M) := fun f g => decidable_of_iff (f.support = g.support ∧ ∀ a ∈ f.support, f a = g a) ext_iff'.symm @@ -393,11 +388,11 @@ theorem support_eq_singleton' {f : α →₀ M} {a : α} : fun ⟨_b, hb, hf⟩ => hf.symm ▸ support_single_ne_zero _ hb⟩ theorem card_support_eq_one {f : α →₀ M} : - card f.support = 1 ↔ ∃ a, f a ≠ 0 ∧ f = single a (f a) := by + #f.support = 1 ↔ ∃ a, f a ≠ 0 ∧ f = single a (f a) := by simp only [card_eq_one, support_eq_singleton] theorem card_support_eq_one' {f : α →₀ M} : - card f.support = 1 ↔ ∃ a, ∃ b ≠ 0, f = single a b := by + #f.support = 1 ↔ ∃ a, ∃ b ≠ 0, f = single a b := by simp only [card_eq_one, support_eq_singleton'] theorem support_subset_singleton {f : α →₀ M} {a : α} : f.support ⊆ {a} ↔ f = single a (f a) := @@ -408,11 +403,11 @@ theorem support_subset_singleton' {f : α →₀ M} {a : α} : f.support ⊆ {a} rw [hb, support_subset_singleton, single_eq_same]⟩ theorem card_support_le_one [Nonempty α] {f : α →₀ M} : - card f.support ≤ 1 ↔ ∃ a, f = single a (f a) := by + #f.support ≤ 1 ↔ ∃ a, f = single a (f a) := by simp only [card_le_one_iff_subset_singleton, support_subset_singleton] theorem card_support_le_one' [Nonempty α] {f : α →₀ M} : - card f.support ≤ 1 ↔ ∃ a b, f = single a b := by + #f.support ≤ 1 ↔ ∃ a b, f = single a b := by simp only [card_le_one_iff_subset_singleton, support_subset_singleton'] @[simp] @@ -627,7 +622,7 @@ otherwise a better set representation is often available. -/ def onFinset (s : Finset α) (f : α → M) (hf : ∀ a, f a ≠ 0 → a ∈ s) : α →₀ M where support := haveI := Classical.decEq M - s.filter (f · ≠ 0) + {a ∈ s | f a ≠ 0} toFun := f mem_support_toFun := by classical simpa @@ -642,14 +637,13 @@ theorem support_onFinset_subset {s : Finset α} {f : α → M} {hf} : (onFinset s f hf).support ⊆ s := by classical convert filter_subset (f · ≠ 0) s --- @[simp] -- Porting note (#10618): simp can prove this theorem mem_support_onFinset {s : Finset α} {f : α → M} (hf : ∀ a : α, f a ≠ 0 → a ∈ s) {a : α} : a ∈ (Finsupp.onFinset s f hf).support ↔ f a ≠ 0 := by rw [Finsupp.mem_support_iff, Finsupp.onFinset_apply] theorem support_onFinset [DecidableEq M] {s : Finset α} {f : α → M} (hf : ∀ a : α, f a ≠ 0 → a ∈ s) : - (Finsupp.onFinset s f hf).support = s.filter fun a => f a ≠ 0 := by + (Finsupp.onFinset s f hf).support = {a ∈ s | f a ≠ 0} := by dsimp [onFinset]; congr end OnFinset @@ -714,6 +708,10 @@ theorem mapRange_comp (f : N → P) (hf : f 0 = 0) (f₂ : M → N) (hf₂ : f (g : α →₀ M) : mapRange (f ∘ f₂) h g = mapRange f hf (mapRange f₂ hf₂ g) := ext fun _ => rfl +@[simp] +lemma mapRange_mapRange (e₁ : N → P) (e₂ : M → N) (he₁ he₂) (f : α →₀ M) : + mapRange e₁ he₁ (mapRange e₂ he₂ f) = mapRange (e₁ ∘ e₂) (by simp [*]) f := ext fun _ ↦ rfl + theorem support_mapRange {f : M → N} {hf : f 0 = 0} {g : α →₀ M} : (mapRange f hf g).support ⊆ g.support := support_onFinset_subset @@ -730,6 +728,14 @@ theorem support_mapRange_of_injective {e : M → N} (he0 : e 0 = 0) (f : ι → simp only [Finsupp.mem_support_iff, Ne, Finsupp.mapRange_apply] exact he.ne_iff' he0 +/-- `Finsupp.mapRange` of a surjective function is surjective. -/ +lemma mapRange_surjective (e : M → N) (he₀ : e 0 = 0) (he : Surjective e) : + Surjective (Finsupp.mapRange (α := α) e he₀) := by + classical + let d (n : N) : M := if n = 0 then 0 else surjInv he n + have : RightInverse d e := fun n ↦ by by_cases h : n = 0 <;> simp [d, h, he₀, surjInv_eq he n] + exact fun f ↦ ⟨mapRange d (by simp [d]) f, by simp [this.comp_eq_id]⟩ + end MapRange /-! ### Declarations about `embDomain` -/ diff --git a/Mathlib/Data/Finsupp/Fintype.lean b/Mathlib/Data/Finsupp/Fintype.lean index 0f5b2e08e4986..b347815decf83 100644 --- a/Mathlib/Data/Finsupp/Fintype.lean +++ b/Mathlib/Data/Finsupp/Fintype.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen, Alex J. Best -/ import Mathlib.Data.Finsupp.Defs -import Mathlib.Data.Fintype.Basic +import Mathlib.Data.Fintype.BigOperators /-! @@ -14,17 +14,19 @@ Some lemmas on the combination of `Finsupp`, `Fintype` and `Infinite`. -/ +variable {ι α : Type*} [DecidableEq ι] [Fintype ι] [Zero α] [Fintype α] -noncomputable instance Finsupp.fintype {ι π : Sort _} [DecidableEq ι] [Zero π] [Fintype ι] - [Fintype π] : Fintype (ι →₀ π) := +noncomputable instance Finsupp.fintype : Fintype (ι →₀ α) := Fintype.ofEquiv _ Finsupp.equivFunOnFinite.symm -instance Finsupp.infinite_of_left {ι π : Sort _} [Nontrivial π] [Zero π] [Infinite ι] : - Infinite (ι →₀ π) := - let ⟨_, hm⟩ := exists_ne (0 : π) +instance Finsupp.infinite_of_left [Nontrivial α] [Infinite ι] : Infinite (ι →₀ α) := + let ⟨_, hm⟩ := exists_ne (0 : α) Infinite.of_injective _ <| Finsupp.single_left_injective hm -instance Finsupp.infinite_of_right {ι π : Sort _} [Infinite π] [Zero π] [Nonempty ι] : - Infinite (ι →₀ π) := +instance Finsupp.infinite_of_right [Infinite α] [Nonempty ι] : Infinite (ι →₀ α) := Infinite.of_injective (fun i => Finsupp.single (Classical.arbitrary ι) i) (Finsupp.single_injective (Classical.arbitrary ι)) + +variable (ι α) in +@[simp] lemma Fintype.card_finsupp : card (ι →₀ α) = card α ^ card ι := by + simp [card_congr Finsupp.equivFunOnFinite] diff --git a/Mathlib/Data/Finsupp/Indicator.lean b/Mathlib/Data/Finsupp/Indicator.lean index 676bbe7d09324..5c4315a90b1c6 100644 --- a/Mathlib/Data/Finsupp/Indicator.lean +++ b/Mathlib/Data/Finsupp/Indicator.lean @@ -33,7 +33,7 @@ def indicator (s : Finset ι) (f : ∀ i ∈ s, α) : ι →₀ α where if H : i ∈ s then f i H else 0 support := haveI := Classical.decEq α - (s.attach.filter fun i : s => f i.1 i.2 ≠ 0).map (Embedding.subtype _) + ({i | f i.1 i.2 ≠ 0} : Finset s).map (Embedding.subtype _) mem_support_toFun i := by classical simp diff --git a/Mathlib/Data/Finsupp/Interval.lean b/Mathlib/Data/Finsupp/Interval.lean index c0104c16bd32a..9fed894fefb53 100644 --- a/Mathlib/Data/Finsupp/Interval.lean +++ b/Mathlib/Data/Finsupp/Interval.lean @@ -97,19 +97,19 @@ instance instLocallyFiniteOrder : LocallyFiniteOrder (ι →₀ α) := theorem Icc_eq : Icc f g = (f.support ∪ g.support).finsupp (f.rangeIcc g) := rfl -- Porting note: removed [DecidableEq ι] -theorem card_Icc : (Icc f g).card = ∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card := by +theorem card_Icc : #(Icc f g) = ∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i)):= by simp_rw [Icc_eq, card_finsupp, coe_rangeIcc] -- Porting note: removed [DecidableEq ι] -theorem card_Ico : (Ico f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 1 := by +theorem card_Ico : #(Ico f g) = ∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i)) - 1 := by rw [card_Ico_eq_card_Icc_sub_one, card_Icc] -- Porting note: removed [DecidableEq ι] -theorem card_Ioc : (Ioc f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 1 := by +theorem card_Ioc : #(Ioc f g) = ∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i)) - 1 := by rw [card_Ioc_eq_card_Icc_sub_one, card_Icc] -- Porting note: removed [DecidableEq ι] -theorem card_Ioo : (Ioo f g).card = (∏ i ∈ f.support ∪ g.support, (Icc (f i) (g i)).card) - 2 := by +theorem card_Ioo : #(Ioo f g) = ∏ i ∈ f.support ∪ g.support, #(Icc (f i) (g i)) - 2 := by rw [card_Ioo_eq_card_Icc_sub_two, card_Icc] end PartialOrder @@ -119,7 +119,7 @@ variable [Lattice α] [Zero α] [LocallyFiniteOrder α] (f g : ι →₀ α) -- Porting note: removed [DecidableEq ι] theorem card_uIcc : - (uIcc f g).card = ∏ i ∈ f.support ∪ g.support, (uIcc (f i) (g i)).card := by + #(uIcc f g) = ∏ i ∈ f.support ∪ g.support, #(uIcc (f i) (g i)) := by rw [← support_inf_union_support_sup]; exact card_Icc (_ : ι →₀ α) _ end Lattice @@ -129,11 +129,11 @@ section CanonicallyOrdered variable [CanonicallyOrderedAddCommMonoid α] [LocallyFiniteOrder α] variable (f : ι →₀ α) -theorem card_Iic : (Iic f).card = ∏ i ∈ f.support, (Iic (f i)).card := by +theorem card_Iic : #(Iic f) = ∏ i ∈ f.support, #(Iic (f i)) := by classical simp_rw [Iic_eq_Icc, card_Icc, Finsupp.bot_eq_zero, support_zero, empty_union, zero_apply, bot_eq_zero] -theorem card_Iio : (Iio f).card = (∏ i ∈ f.support, (Iic (f i)).card) - 1 := by +theorem card_Iio : #(Iio f) = ∏ i ∈ f.support, #(Iic (f i)) - 1 := by rw [card_Iio_eq_card_Iic_sub_one, card_Iic] end CanonicallyOrdered diff --git a/Mathlib/Data/Finsupp/Lex.lean b/Mathlib/Data/Finsupp/Lex.lean index 9174fd421d429..6b2a45dd8483b 100644 --- a/Mathlib/Data/Finsupp/Lex.lean +++ b/Mathlib/Data/Finsupp/Lex.lean @@ -91,39 +91,35 @@ section Covariants variable [LinearOrder α] [AddMonoid N] [LinearOrder N] /-! We are about to sneak in a hypothesis that might appear to be too strong. -We assume `CovariantClass` with *strict* inequality `<` also when proving the one with the -*weak* inequality `≤`. This is actually necessary: addition on `Lex (α →₀ N)` may fail to be -monotone, when it is "just" monotone on `N`. +We assume `AddLeftStrictMono` (covariant with *strict* inequality `<`) also when proving the one +with the *weak* inequality `≤`. This is actually necessary: addition on `Lex (α →₀ N)` may fail to +be monotone, when it is "just" monotone on `N`. See `Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean` for a counterexample. -/ section Left -variable [CovariantClass N N (· + ·) (· < ·)] +variable [AddLeftStrictMono N] -instance Lex.covariantClass_lt_left : - CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (· + ·) (· < ·) := +instance Lex.addLeftStrictMono : AddLeftStrictMono (Lex (α →₀ N)) := ⟨fun _ _ _ ⟨a, lta, ha⟩ ↦ ⟨a, fun j ja ↦ congr_arg _ (lta j ja), add_lt_add_left ha _⟩⟩ -instance Lex.covariantClass_le_left : - CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (· + ·) (· ≤ ·) := - covariantClass_le_of_lt _ _ _ +instance Lex.addLeftMono : AddLeftMono (Lex (α →₀ N)) := + addLeftMono_of_addLeftStrictMono _ end Left section Right -variable [CovariantClass N N (Function.swap (· + ·)) (· < ·)] +variable [AddRightStrictMono N] -instance Lex.covariantClass_lt_right : - CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (Function.swap (· + ·)) (· < ·) := +instance Lex.addRightStrictMono : AddRightStrictMono (Lex (α →₀ N)) := ⟨fun f _ _ ⟨a, lta, ha⟩ ↦ ⟨a, fun j ja ↦ congr_arg (· + ofLex f j) (lta j ja), add_lt_add_right ha _⟩⟩ -instance Lex.covariantClass_le_right : - CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (Function.swap (· + ·)) (· ≤ ·) := - covariantClass_le_of_lt _ _ _ +instance Lex.addRightMono : AddRightMono (Lex (α →₀ N)) := + addRightMono_of_addRightStrictMono _ end Right diff --git a/Mathlib/Data/Finsupp/Multiset.lean b/Mathlib/Data/Finsupp/Multiset.lean index 4d4b1f940f9a8..9e68300b843cc 100644 --- a/Mathlib/Data/Finsupp/Multiset.lean +++ b/Mathlib/Data/Finsupp/Multiset.lean @@ -128,7 +128,7 @@ the multiplicities of the elements of `s`. -/ def toFinsupp : Multiset α ≃+ (α →₀ ℕ) where toFun s := ⟨s.toFinset, fun a => s.count a, fun a => by simp⟩ invFun f := Finsupp.toMultiset f - map_add' s t := Finsupp.ext fun _ => count_add _ _ _ + map_add' _ _ := Finsupp.ext fun _ => count_add _ _ _ right_inv f := Finsupp.ext fun a => by simp only [Finsupp.toMultiset_apply, Finsupp.sum, Multiset.count_sum', diff --git a/Mathlib/Data/Finsupp/Notation.lean b/Mathlib/Data/Finsupp/Notation.lean index 2091f9b3cb8d1..12c11f9e628e5 100644 --- a/Mathlib/Data/Finsupp/Notation.lean +++ b/Mathlib/Data/Finsupp/Notation.lean @@ -83,9 +83,9 @@ unsafe instance instRepr {α β} [Repr α] [Repr β] [Zero β] : Repr (α →₀ if f.support.card = 0 then "0" else - let ret := "fun₀" ++ - Std.Format.join (f.support.val.unquot.map <| - fun a => " | " ++ repr a ++ " => " ++ repr (f a)) + let ret : Std.Format := f!"fun₀" ++ .nest 2 ( + .group (.join <| f.support.val.unquot.map fun a => + .line ++ .group (f!"| {repr a} =>" ++ .line ++ repr (f a)))) if p ≥ leadPrec then Format.paren ret else ret -- This cannot be put in `Mathlib.Data.DFinsupp.Notation` where it belongs, since doc-strings diff --git a/Mathlib/Data/Finsupp/Order.lean b/Mathlib/Data/Finsupp/Order.lean index c77303cc05d77..e1bb9c61c445f 100644 --- a/Mathlib/Data/Finsupp/Order.lean +++ b/Mathlib/Data/Finsupp/Order.lean @@ -3,7 +3,9 @@ Copyright (c) 2021 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Aaron Anderson -/ +import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Algebra.Order.Module.Defs +import Mathlib.Algebra.Order.Pi import Mathlib.Data.Finsupp.Basic /-! @@ -21,7 +23,7 @@ noncomputable section open Finset -variable {ι α β : Type*} +variable {ι κ α β : Type*} namespace Finsupp @@ -32,6 +34,15 @@ section Zero variable [Zero α] +section OrderedAddCommMonoid +variable [OrderedAddCommMonoid β] {f : ι →₀ α} {h₁ h₂ : ι → α → β} + +@[gcongr] +lemma sum_le_sum (h : ∀ i ∈ f.support, h₁ i (f i) ≤ h₂ i (f i)) : f.sum h₁ ≤ f.sum h₂ := + Finset.sum_le_sum h + +end OrderedAddCommMonoid + section LE variable [LE α] {f g : ι →₀ α} @@ -58,12 +69,12 @@ theorem orderEmbeddingToFun_apply {f : ι →₀ α} {i : ι} : orderEmbeddingTo end LE section Preorder -variable [Preorder α] {f g : ι →₀ α} +variable [Preorder α] {f g : ι →₀ α} {i : ι} {a b : α} instance preorder : Preorder (ι →₀ α) := { Finsupp.instLEFinsupp with - le_refl := fun f i => le_rfl - le_trans := fun f g h hfg hgh i => (hfg i).trans (hgh i) } + le_refl := fun _ _ => le_rfl + le_trans := fun _ _ _ hfg hgh i => (hfg i).trans (hgh i) } lemma lt_def : f < g ↔ f ≤ g ∧ ∃ i, f i < g i := Pi.lt_def @[simp, norm_cast] lemma coe_lt_coe : ⇑f < g ↔ f < g := Iff.rfl @@ -72,6 +83,26 @@ lemma coe_mono : Monotone (Finsupp.toFun : (ι →₀ α) → ι → α) := fun lemma coe_strictMono : Monotone (Finsupp.toFun : (ι →₀ α) → ι → α) := fun _ _ ↦ id +@[simp] lemma single_le_single : single i a ≤ single i b ↔ a ≤ b := by + classical exact Pi.single_le_single + +lemma single_mono : Monotone (single i : α → ι →₀ α) := fun _ _ ↦ single_le_single.2 + +@[gcongr] protected alias ⟨_, GCongr.single_mono⟩ := single_le_single + +@[simp] lemma single_nonneg : 0 ≤ single i a ↔ 0 ≤ a := by classical exact Pi.single_nonneg +@[simp] lemma single_nonpos : single i a ≤ 0 ↔ a ≤ 0 := by classical exact Pi.single_nonpos + +variable [OrderedAddCommMonoid β] + +lemma sum_le_sum_index [DecidableEq ι] {f₁ f₂ : ι →₀ α} {h : ι → α → β} (hf : f₁ ≤ f₂) + (hh : ∀ i ∈ f₁.support ∪ f₂.support, Monotone (h i)) + (hh₀ : ∀ i ∈ f₁.support ∪ f₂.support, h i 0 = 0) : f₁.sum h ≤ f₂.sum h := by + classical + rw [sum_of_support_subset _ Finset.subset_union_left _ hh₀, + sum_of_support_subset _ Finset.subset_union_right _ hh₀] + exact Finset.sum_le_sum fun i hi ↦ hh _ hi <| hf _ + end Preorder instance partialorder [PartialOrder α] : PartialOrder (ι →₀ α) := @@ -117,18 +148,31 @@ end Zero /-! ### Algebraic order structures -/ +section OrderedAddCommMonoid +variable [OrderedAddCommMonoid α] {i : ι} {f : ι → κ} {g g₁ g₂ : ι →₀ α} -instance orderedAddCommMonoid [OrderedAddCommMonoid α] : OrderedAddCommMonoid (ι →₀ α) := +instance orderedAddCommMonoid : OrderedAddCommMonoid (ι →₀ α) := { Finsupp.instAddCommMonoid, Finsupp.partialorder with add_le_add_left := fun _a _b h c s => add_le_add_left (h s) (c s) } +lemma mapDomain_mono : Monotone (mapDomain f : (ι →₀ α) → (κ →₀ α)) := by + classical exact fun g₁ g₂ h ↦ sum_le_sum_index h (fun _ _ ↦ single_mono) (by simp) + +@[gcongr] protected lemma GCongr.mapDomain_mono (hg : g₁ ≤ g₂) : g₁.mapDomain f ≤ g₂.mapDomain f := + mapDomain_mono hg + +lemma mapDomain_nonneg (hg : 0 ≤ g) : 0 ≤ g.mapDomain f := by simpa using mapDomain_mono hg +lemma mapDomain_nonpos (hg : g ≤ 0) : g.mapDomain f ≤ 0 := by simpa using mapDomain_mono hg + +end OrderedAddCommMonoid + instance orderedCancelAddCommMonoid [OrderedCancelAddCommMonoid α] : OrderedCancelAddCommMonoid (ι →₀ α) := { Finsupp.orderedAddCommMonoid with le_of_add_le_add_left := fun _f _g _i h s => le_of_add_le_add_left (h s) } -instance contravariantClass [OrderedAddCommMonoid α] [ContravariantClass α α (· + ·) (· ≤ ·)] : - ContravariantClass (ι →₀ α) (ι →₀ α) (· + ·) (· ≤ ·) := +instance addLeftReflectLE [OrderedAddCommMonoid α] [AddLeftReflectLE α] : + AddLeftReflectLE (ι →₀ α) := ⟨fun _f _g _h H x => le_of_add_le_add_left <| H x⟩ section SMulZeroClass diff --git a/Mathlib/Data/Finsupp/Weight.lean b/Mathlib/Data/Finsupp/Weight.lean index ed767ee615ac8..075821985671b 100644 --- a/Mathlib/Data/Finsupp/Weight.lean +++ b/Mathlib/Data/Finsupp/Weight.lean @@ -3,11 +3,7 @@ Copyright (c) 2024 Antoine Chambert-Loir, María Inés de Frutos-Fernández. All 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.Algebra.Order.BigOperators.Group.Finset import Mathlib.Algebra.Order.Module.Defs -import Mathlib.Algebra.Order.Ring.Defs -import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.LinearAlgebra.Finsupp /-! # weights of Finsupp functions diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index 0ff3b973f0141..997a6dd16aeb4 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -376,7 +376,7 @@ namespace Fintype instance decidablePiFintype {α} {β : α → Type*} [∀ a, DecidableEq (β a)] [Fintype α] : DecidableEq (∀ a, β a) := fun f g => decidable_of_iff (∀ a ∈ @Fintype.elems α _, f a = g a) - (by simp [Function.funext_iff, Fintype.complete]) + (by simp [funext_iff, Fintype.complete]) instance decidableForallFintype {p : α → Prop} [DecidablePred p] [Fintype α] : Decidable (∀ a, p a) := diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean index b772a62fd0956..6c8241d4dd465 100644 --- a/Mathlib/Data/Fintype/BigOperators.lean +++ b/Mathlib/Data/Fintype/BigOperators.lean @@ -104,20 +104,20 @@ section Pi variable {ι κ : Type*} {α : ι → Type*} [DecidableEq ι] [DecidableEq κ] @[simp] lemma Finset.card_pi (s : Finset ι) (t : ∀ i, Finset (α i)) : - (s.pi t).card = ∏ i ∈ s, card (t i) := Multiset.card_pi _ _ + #(s.pi t) = ∏ i ∈ s, #(t i) := Multiset.card_pi _ _ namespace Fintype variable [Fintype ι] @[simp] lemma card_piFinset (s : ∀ i, Finset (α i)) : - (piFinset s).card = ∏ i, (s i).card := by simp [piFinset, card_map] + #(piFinset s) = ∏ i, #(s i) := by simp [piFinset, card_map] /-- This lemma is specifically designed to be used backwards, whence the specialisation to `Fin n` as the indexing type doesn't matter in practice. The more general forward direction lemma here is `Fintype.card_piFinset`. -/ lemma card_piFinset_const {α : Type*} (s : Finset α) (n : ℕ) : - (piFinset fun _ : Fin n ↦ s).card = s.card ^ n := by simp + #(piFinset fun _ : Fin n ↦ s) = #s ^ n := by simp @[simp] lemma card_pi [∀ i, Fintype (α i)] : card (∀ i, α i) = ∏ i, card (α i) := card_piFinset _ @@ -132,37 +132,35 @@ lemma card_pi_const (α : Type*) [Fintype α] (n : ℕ) : card (Fin n → α) = card (Sigma α) = ∑ i, card (α i) := card_sigma _ _ /-- The number of dependent maps `f : Π j, s j` for which the `i` component is `a` is the product -over all `j ≠ i` of `(s j).card`. +over all `j ≠ i` of `#(s j)`. Note that this is just a composition of easier lemmas, but there's some glue missing to make that smooth enough not to need this lemma. -/ lemma card_filter_piFinset_eq_of_mem [∀ i, DecidableEq (α i)] (s : ∀ i, Finset (α i)) (i : ι) {a : α i} (ha : a ∈ s i) : - ((piFinset s).filter fun f ↦ f i = a).card = ∏ j ∈ univ.erase i, (s j).card := by + #{f ∈ piFinset s | f i = a} = ∏ j ∈ univ.erase i, #(s j) := by calc - _ = ∏ j, (Function.update s i {a} j).card := by + _ = ∏ j, #(Function.update s i {a} j) := by rw [← piFinset_update_singleton_eq_filter_piFinset_eq _ _ ha, Fintype.card_piFinset] - _ = ∏ j, Function.update (fun j ↦ (s j).card) i 1 j := + _ = ∏ j, Function.update (fun j ↦ #(s j)) i 1 j := Fintype.prod_congr _ _ fun j ↦ by obtain rfl | hji := eq_or_ne j i <;> simp [*] _ = _ := by simp [prod_update_of_mem, erase_eq] lemma card_filter_piFinset_const_eq_of_mem (s : Finset κ) (i : ι) {x : κ} (hx : x ∈ s) : - ((piFinset fun _ ↦ s).filter fun f ↦ f i = x).card = s.card ^ (card ι - 1) := + #{f ∈ piFinset fun _ ↦ s | f i = x} = #s ^ (card ι - 1) := (card_filter_piFinset_eq_of_mem _ _ hx).trans <| by - rw [prod_const s.card, card_erase_of_mem (mem_univ _), card_univ] + rw [prod_const #s, card_erase_of_mem (mem_univ _), card_univ] lemma card_filter_piFinset_eq [∀ i, DecidableEq (α i)] (s : ∀ i, Finset (α i)) (i : ι) (a : α i) : - ((piFinset s).filter fun f ↦ f i = a).card = - if a ∈ s i then ∏ b ∈ univ.erase i, (s b).card else 0 := by + #{f ∈ piFinset s | f i = a} = if a ∈ s i then ∏ b ∈ univ.erase i, #(s b) else 0 := by split_ifs with h · rw [card_filter_piFinset_eq_of_mem _ _ h] · rw [filter_piFinset_of_not_mem _ _ _ h, Finset.card_empty] lemma card_filter_piFinset_const (s : Finset κ) (i : ι) (j : κ) : - ((piFinset fun _ ↦ s).filter fun f ↦ f i = j).card = - if j ∈ s then s.card ^ (card ι - 1) else 0 := + #{f ∈ piFinset fun _ ↦ s | f i = j} = if j ∈ s then #s ^ (card ι - 1) else 0 := (card_filter_piFinset_eq _ _ _).trans <| by - rw [prod_const s.card, card_erase_of_mem (mem_univ _), card_univ] + rw [prod_const #s, card_erase_of_mem (mem_univ _), card_univ] end Fintype end Pi diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 45c0a90562ef5..e5e21cc3387b4 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -112,21 +112,21 @@ def truncFinBijection (α) [Fintype α] : Trunc { f : Fin (card α) → α // Bi mem_univ_val univ.2 theorem subtype_card {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x) : - @card { x // p x } (Fintype.subtype s H) = s.card := + @card { x // p x } (Fintype.subtype s H) = #s := Multiset.card_pmap _ _ _ theorem card_of_subtype {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x) - [Fintype { x // p x }] : card { x // p x } = s.card := by + [Fintype { x // p x }] : card { x // p x } = #s := by rw [← subtype_card s H] congr! @[simp] theorem card_ofFinset {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) : - @Fintype.card p (ofFinset s H) = s.card := + @Fintype.card p (ofFinset s H) = #s := Fintype.subtype_card s H theorem card_of_finset' {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) [Fintype p] : - Fintype.card p = s.card := by rw [← card_ofFinset s H]; congr! + Fintype.card p = #s := by rw [← card_ofFinset s H]; congr! end Fintype @@ -223,50 +223,47 @@ theorem toFinset_card {α : Type*} (s : Set α) [Fintype s] : s.toFinset.card = end Set @[simp] -theorem Finset.card_univ [Fintype α] : (Finset.univ : Finset α).card = Fintype.card α := - rfl +theorem Finset.card_univ [Fintype α] : #(univ : Finset α) = Fintype.card α := rfl -theorem Finset.eq_univ_of_card [Fintype α] (s : Finset α) (hs : s.card = Fintype.card α) : +theorem Finset.eq_univ_of_card [Fintype α] (s : Finset α) (hs : #s = Fintype.card α) : s = univ := eq_of_subset_of_card_le (subset_univ _) <| by rw [hs, Finset.card_univ] -theorem Finset.card_eq_iff_eq_univ [Fintype α] (s : Finset α) : - s.card = Fintype.card α ↔ s = Finset.univ := +theorem Finset.card_eq_iff_eq_univ [Fintype α] (s : Finset α) : #s = Fintype.card α ↔ s = univ := ⟨s.eq_univ_of_card, by rintro rfl exact Finset.card_univ⟩ -theorem Finset.card_le_univ [Fintype α] (s : Finset α) : s.card ≤ Fintype.card α := +theorem Finset.card_le_univ [Fintype α] (s : Finset α) : #s ≤ Fintype.card α := card_le_card (subset_univ s) theorem Finset.card_lt_univ_of_not_mem [Fintype α] {s : Finset α} {x : α} (hx : x ∉ s) : - s.card < Fintype.card α := + #s < Fintype.card α := card_lt_card ⟨subset_univ s, not_forall.2 ⟨x, fun hx' => hx (hx' <| mem_univ x)⟩⟩ theorem Finset.card_lt_iff_ne_univ [Fintype α] (s : Finset α) : - s.card < Fintype.card α ↔ s ≠ Finset.univ := + #s < Fintype.card α ↔ s ≠ Finset.univ := s.card_le_univ.lt_iff_ne.trans (not_congr s.card_eq_iff_eq_univ) theorem Finset.card_compl_lt_iff_nonempty [Fintype α] [DecidableEq α] (s : Finset α) : - sᶜ.card < Fintype.card α ↔ s.Nonempty := + #sᶜ < Fintype.card α ↔ s.Nonempty := sᶜ.card_lt_iff_ne_univ.trans s.compl_ne_univ_iff_nonempty theorem Finset.card_univ_diff [DecidableEq α] [Fintype α] (s : Finset α) : - (Finset.univ \ s).card = Fintype.card α - s.card := + #(univ \ s) = Fintype.card α - #s := Finset.card_sdiff (subset_univ s) -theorem Finset.card_compl [DecidableEq α] [Fintype α] (s : Finset α) : - sᶜ.card = Fintype.card α - s.card := +theorem Finset.card_compl [DecidableEq α] [Fintype α] (s : Finset α) : #sᶜ = Fintype.card α - #s := Finset.card_univ_diff s @[simp] theorem Finset.card_add_card_compl [DecidableEq α] [Fintype α] (s : Finset α) : - s.card + sᶜ.card = Fintype.card α := by + #s + #sᶜ = Fintype.card α := by rw [Finset.card_compl, ← Nat.add_sub_assoc (card_le_univ s), Nat.add_sub_cancel_left] @[simp] theorem Finset.card_compl_add_card [DecidableEq α] [Fintype α] (s : Finset α) : - sᶜ.card + s.card = Fintype.card α := by + #sᶜ + #s = Fintype.card α := by rw [add_comm, card_add_card_compl] theorem Fintype.card_compl_set [Fintype α] (s : Set α) [Fintype s] [Fintype (↥sᶜ : Sort _)] : @@ -286,7 +283,7 @@ theorem Fintype.card_fin_lt_of_le {m n : ℕ} (h : m ≤ n) : left_inv := fun i ↦ rfl right_inv := fun i ↦ rfl } -theorem Finset.card_fin (n : ℕ) : Finset.card (Finset.univ : Finset (Fin n)) = n := by simp +theorem Finset.card_fin (n : ℕ) : #(univ : Finset (Fin n)) = n := by simp /-- `Fin` as a map from `ℕ` to `Type` is injective. Note that since this is a statement about equality of types, using it should be avoided if possible. -/ @@ -303,15 +300,13 @@ theorem Fin.cast_eq_cast' {n m : ℕ} (h : Fin n = Fin m) : cases fin_injective h rfl -theorem card_finset_fin_le {n : ℕ} (s : Finset (Fin n)) : s.card ≤ n := by +theorem card_finset_fin_le {n : ℕ} (s : Finset (Fin n)) : #s ≤ n := by simpa only [Fintype.card_fin] using s.card_le_univ ---@[simp] Porting note (#10618): simp can prove it theorem Fintype.card_subtype_eq (y : α) [Fintype { x // x = y }] : Fintype.card { x // x = y } = 1 := Fintype.card_unique ---@[simp] Porting note (#10618): simp can prove it theorem Fintype.card_subtype_eq' (y : α) [Fintype { x // y = x }] : Fintype.card { x // y = x } = 1 := Fintype.card_unique @@ -401,6 +396,15 @@ theorem Finite.of_injective {α β : Sort*} [Finite β] (f : α → β) (H : Inj rcases Finite.exists_equiv_fin β with ⟨n, ⟨e⟩⟩ classical exact .of_equiv (Set.range (e ∘ f)) (Equiv.ofInjective _ (e.injective.comp H)).symm +-- see Note [lower instance priority] +instance (priority := 100) Finite.of_subsingleton {α : Sort*} [Subsingleton α] : Finite α := + Finite.of_injective (Function.const α ()) <| Function.injective_of_subsingleton _ + +-- Higher priority for `Prop`s +-- Porting note(#12096): removed @[nolint instance_priority], linter not ported yet +instance prop (p : Prop) : Finite p := + Finite.of_subsingleton + /-- This instance also provides `[Finite s]` for `s : Set α`. -/ instance Subtype.finite {α : Sort*} [Finite α] {p : α → Prop} : Finite { x // p x } := Finite.of_injective (↑) Subtype.coe_injective @@ -408,6 +412,12 @@ instance Subtype.finite {α : Sort*} [Finite α] {p : α → Prop} : Finite { x theorem Finite.of_surjective {α β : Sort*} [Finite α] (f : α → β) (H : Surjective f) : Finite β := Finite.of_injective _ <| injective_surjInv H +instance Quot.finite {α : Sort*} [Finite α] (r : α → α → Prop) : Finite (Quot r) := + Finite.of_surjective _ (surjective_quot_mk r) + +instance Quotient.finite {α : Sort*} [Finite α] (s : Setoid α) : Finite (Quotient s) := + Quot.finite _ + theorem Finite.exists_univ_list (α) [Finite α] : ∃ l : List α, l.Nodup ∧ ∀ x : α, x ∈ l := by cases nonempty_fintype α obtain ⟨l, e⟩ := Quotient.exists_rep (@univ α _).1 @@ -531,7 +541,7 @@ theorem card_eq_one_of_forall_eq {i : α} (h : ∀ j, j = i) : card α = 1 := Fintype.card_eq_one_iff.2 ⟨i, h⟩ theorem exists_unique_iff_card_one {α} [Fintype α] (p : α → Prop) [DecidablePred p] : - (∃! a : α, p a) ↔ (Finset.univ.filter p).card = 1 := by + (∃! a : α, p a) ↔ #{x | p x} = 1 := by rw [Finset.card_eq_one] refine exists_congr fun x => ?_ simp only [forall_true_left, Subset.antisymm_iff, subset_singleton_iff', singleton_subset_iff, @@ -650,36 +660,36 @@ def ofRightInverseOfCardLE (hαβ : card α ≤ card β) (f : α → β) (g : β end Equiv @[simp] -theorem Fintype.card_coe (s : Finset α) [Fintype s] : Fintype.card s = s.card := +theorem Fintype.card_coe (s : Finset α) [Fintype s] : Fintype.card s = #s := @Fintype.card_of_finset' _ _ _ (fun _ => Iff.rfl) (id _) -/-- Noncomputable equivalence between a finset `s` coerced to a type and `Fin s.card`. -/ -noncomputable def Finset.equivFin (s : Finset α) : s ≃ Fin s.card := +/-- Noncomputable equivalence between a finset `s` coerced to a type and `Fin #s`. -/ +noncomputable def Finset.equivFin (s : Finset α) : s ≃ Fin #s := Fintype.equivFinOfCardEq (Fintype.card_coe _) /-- Noncomputable equivalence between a finset `s` as a fintype and `Fin n`, when there is a -proof that `s.card = n`. -/ -noncomputable def Finset.equivFinOfCardEq {s : Finset α} {n : ℕ} (h : s.card = n) : s ≃ Fin n := +proof that `#s = n`. -/ +noncomputable def Finset.equivFinOfCardEq {s : Finset α} {n : ℕ} (h : #s = n) : s ≃ Fin n := Fintype.equivFinOfCardEq ((Fintype.card_coe _).trans h) -theorem Finset.card_eq_of_equiv_fin {s : Finset α} {n : ℕ} (i : s ≃ Fin n) : s.card = n := +theorem Finset.card_eq_of_equiv_fin {s : Finset α} {n : ℕ} (i : s ≃ Fin n) : #s = n := Fin.equiv_iff_eq.1 ⟨s.equivFin.symm.trans i⟩ theorem Finset.card_eq_of_equiv_fintype {s : Finset α} [Fintype β] (i : s ≃ β) : - s.card = Fintype.card β := card_eq_of_equiv_fin <| i.trans <| Fintype.equivFin β + #s = Fintype.card β := card_eq_of_equiv_fin <| i.trans <| Fintype.equivFin β /-- Noncomputable equivalence between two finsets `s` and `t` as fintypes when there is a proof -that `s.card = t.card`. -/ -noncomputable def Finset.equivOfCardEq {s : Finset α} {t : Finset β} (h : s.card = t.card) : +that `#s = #t`. -/ +noncomputable def Finset.equivOfCardEq {s : Finset α} {t : Finset β} (h : #s = #t) : s ≃ t := Fintype.equivOfCardEq ((Fintype.card_coe _).trans (h.trans (Fintype.card_coe _).symm)) -theorem Finset.card_eq_of_equiv {s : Finset α} {t : Finset β} (i : s ≃ t) : s.card = t.card := +theorem Finset.card_eq_of_equiv {s : Finset α} {t : Finset β} (i : s ≃ t) : #s = #t := (card_eq_of_equiv_fintype i).trans (Fintype.card_coe _) /-- We can inflate a set `s` to any bigger size. -/ -lemma Finset.exists_superset_card_eq [Fintype α] {n : ℕ} {s : Finset α} (hsn : s.card ≤ n) +lemma Finset.exists_superset_card_eq [Fintype α] {n : ℕ} {s : Finset α} (hsn : #s ≤ n) (hnα : n ≤ Fintype.card α) : - ∃ t, s ⊆ t ∧ t.card = n := by simpa using exists_subsuperset_card_eq s.subset_univ hsn hnα + ∃ t, s ⊆ t ∧ #t = n := by simpa using exists_subsuperset_card_eq s.subset_univ hsn hnα @[simp] theorem Fintype.card_prop : Fintype.card Prop = 2 := @@ -730,7 +740,7 @@ theorem nonempty_iff_card_le [Fintype α] [Fintype β] : Nonempty (α ↪ β) ↔ Fintype.card α ≤ Fintype.card β := ⟨fun ⟨e⟩ => Fintype.card_le_of_embedding e, nonempty_of_card_le⟩ -theorem exists_of_card_le_finset [Fintype α] {s : Finset β} (h : Fintype.card α ≤ s.card) : +theorem exists_of_card_le_finset [Fintype α] {s : Finset β} (h : Fintype.card α ≤ #s) : ∃ f : α ↪ β, Set.range f ⊆ s := by rw [← Fintype.card_coe] at h rcases nonempty_of_card_le h with ⟨f⟩ @@ -762,7 +772,7 @@ theorem Fintype.card_subtype_lt [Fintype α] {p : α → Prop} [DecidablePred p] rwa [Subtype.range_coe_subtype] theorem Fintype.card_subtype [Fintype α] (p : α → Prop) [DecidablePred p] : - Fintype.card { x // p x } = ((Finset.univ : Finset α).filter p).card := by + Fintype.card { x // p x } = #{x | p x} := by refine Fintype.card_of_subtype _ ?_ simp @@ -812,9 +822,7 @@ theorem wellFounded_of_trans_of_irrefl (r : α → α → Prop) [IsTrans α r] [ WellFounded r := by classical cases nonempty_fintype α - have : - ∀ x y, r x y → (univ.filter fun z => r z x).card < (univ.filter fun z => r z y).card := - fun x y hxy => + have (x y) (hxy : r x y) : #{z | r z x} < #{z | r z y} := Finset.card_lt_card <| by simp only [Finset.lt_iff_ssubset.symm, lt_iff_le_not_le, Finset.le_iff_subset, Finset.subset_iff, mem_filter, true_and, mem_univ, hxy] @@ -886,7 +894,7 @@ theorem of_injective_to_set {s : Set α} (hs : s ≠ Set.univ) {f : α → s} (h refine lt_irrefl (Fintype.card α) ?_ calc Fintype.card α ≤ Fintype.card s := Fintype.card_le_of_injective f hf - _ = s.toFinset.card := s.toFinset_card.symm + _ = #s.toFinset := s.toFinset_card.symm _ < Fintype.card α := Finset.card_lt_card <| by rwa [Set.toFinset_ssubset_univ, Set.ssubset_univ_iff] @@ -899,7 +907,7 @@ theorem exists_not_mem_finset [Infinite α] (s : Finset α) : ∃ x, x ∉ s := not_forall.1 fun h => Fintype.false ⟨s, h⟩ -- see Note [lower instance priority] -instance (priority := 100) (α : Type*) [H : Infinite α] : Nontrivial α := +instance (priority := 100) (α : Type*) [Infinite α] : Nontrivial α := ⟨let ⟨x, _hx⟩ := exists_not_mem_finset (∅ : Finset α) let ⟨y, hy⟩ := exists_not_mem_finset ({x} : Finset α) ⟨y, x, by simpa only [mem_singleton] using hy⟩⟩ @@ -977,7 +985,7 @@ private noncomputable def natEmbeddingAux (α : Type*) [Infinite α] : ℕ → letI := Classical.decEq α Classical.choose (exists_not_mem_finset - ((Multiset.range n).pmap (fun m (hm : m < n) => natEmbeddingAux _ m) fun _ => + ((Multiset.range n).pmap (fun m (_ : m < n) => natEmbeddingAux _ m) fun _ => Multiset.mem_range.1).toFinset) private theorem natEmbeddingAux_injective (α : Type*) [Infinite α] : @@ -999,14 +1007,14 @@ noncomputable def natEmbedding (α : Type*) [Infinite α] : ℕ ↪ α := ⟨_, natEmbeddingAux_injective α⟩ /-- See `Infinite.exists_superset_card_eq` for a version that, for an `s : Finset α`, -provides a superset `t : Finset α`, `s ⊆ t` such that `t.card` is fixed. -/ -theorem exists_subset_card_eq (α : Type*) [Infinite α] (n : ℕ) : ∃ s : Finset α, s.card = n := +provides a superset `t : Finset α`, `s ⊆ t` such that `#t` is fixed. -/ +theorem exists_subset_card_eq (α : Type*) [Infinite α] (n : ℕ) : ∃ s : Finset α, #s = n := ⟨(range n).map (natEmbedding α), by rw [card_map, card_range]⟩ /-- See `Infinite.exists_subset_card_eq` for a version that provides an arbitrary `s : Finset α` for any cardinality. -/ -theorem exists_superset_card_eq [Infinite α] (s : Finset α) (n : ℕ) (hn : s.card ≤ n) : - ∃ t : Finset α, s ⊆ t ∧ t.card = n := by +theorem exists_superset_card_eq [Infinite α] (s : Finset α) (n : ℕ) (hn : #s ≤ n) : + ∃ t : Finset α, s ⊆ t ∧ #t = n := by induction' n with n IH generalizing s · exact ⟨s, subset_refl _, Nat.eq_zero_of_le_zero hn⟩ · rcases hn.eq_or_lt with hn' | hn' @@ -1019,7 +1027,7 @@ theorem exists_superset_card_eq [Infinite α] (s : Finset α) (n : ℕ) (hn : s. end Infinite /-- If every finset in a type has bounded cardinality, that type is finite. -/ -noncomputable def fintypeOfFinsetCardLe {ι : Type*} (n : ℕ) (w : ∀ s : Finset ι, s.card ≤ n) : +noncomputable def fintypeOfFinsetCardLe {ι : Type*} (n : ℕ) (w : ∀ s : Finset ι, #s ≤ n) : Fintype ι := by apply fintypeOfNotInfinite intro i diff --git a/Mathlib/Data/Fintype/Fin.lean b/Mathlib/Data/Fintype/Fin.lean index 9c66b04ae7c46..63559a8ab0c85 100644 --- a/Mathlib/Data/Fintype/Fin.lean +++ b/Mathlib/Data/Fintype/Fin.lean @@ -53,19 +53,18 @@ theorem Iio_castSucc (i : Fin n) : Iio (castSucc i) = (Iio i).map Fin.castSuccEm exact (Fin.map_valEmbedding_Iio i).symm theorem card_filter_univ_succ (p : Fin (n + 1) → Prop) [DecidablePred p] : - (univ.filter p).card = - if p 0 then (univ.filter (p ∘ Fin.succ)).card + 1 else (univ.filter (p ∘ Fin.succ)).card := by + #{x | p x} = if p 0 then #{x | p (.succ x)} + 1 else #{x | p (.succ x)} := by rw [Fin.univ_succ, filter_cons, apply_ite Finset.card, card_cons, filter_map, card_map]; rfl theorem card_filter_univ_succ' (p : Fin (n + 1) → Prop) [DecidablePred p] : - (univ.filter p).card = ite (p 0) 1 0 + (univ.filter (p ∘ Fin.succ)).card := by + #{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) : - (univ.filter fun i => v.get i = a).card = v.toList.count a := by + #{i | v.get i = a} = v.toList.count a := by induction' v with n x xs hxs · simp - · simp_rw [card_filter_univ_succ', Vector.get_cons_zero, Vector.toList_cons, Function.comp_def, - Vector.get_cons_succ, hxs, List.count_cons, add_comm (ite (x = a) 1 0), beq_iff_eq] + · simp_rw [card_filter_univ_succ', Vector.get_cons_zero, Vector.toList_cons, Vector.get_cons_succ, + hxs, List.count_cons, add_comm (ite (x = a) 1 0), beq_iff_eq] end Fin diff --git a/Mathlib/Data/Fintype/List.lean b/Mathlib/Data/Fintype/List.lean index 11d79be8c6f44..a93c79912ed44 100644 --- a/Mathlib/Data/Fintype/List.lean +++ b/Mathlib/Data/Fintype/List.lean @@ -5,6 +5,7 @@ Authors: Yakov Pechersky -/ import Mathlib.Data.Fintype.Basic import Mathlib.Data.Finset.Powerset +import Mathlib.Data.List.Permutation /-! diff --git a/Mathlib/Data/Fintype/Option.lean b/Mathlib/Data/Fintype/Option.lean index 1a4f57cb48b3e..5bb9fafa8f916 100644 --- a/Mathlib/Data/Fintype/Option.lean +++ b/Mathlib/Data/Fintype/Option.lean @@ -19,7 +19,7 @@ open Nat universe u v -variable {α β γ : Type*} +variable {α β : Type*} open Finset Function diff --git a/Mathlib/Data/Fintype/Order.lean b/Mathlib/Data/Fintype/Order.lean index 6fa3b6c7e32fd..9e9c7d1d134d1 100644 --- a/Mathlib/Data/Fintype/Order.lean +++ b/Mathlib/Data/Fintype/Order.lean @@ -6,6 +6,7 @@ Authors: Peter Nelson, Yaël Dillies import Mathlib.Data.Finset.Order import Mathlib.Order.Atoms import Mathlib.Data.Set.Finite +import Mathlib.Order.Minimal /-! # Order structures on finite types @@ -87,9 +88,9 @@ noncomputable abbrev toCompleteLattice [Lattice α] [BoundedOrder α] : Complete sSup := fun s => s.toFinset.sup id sInf := fun s => s.toFinset.inf id le_sSup := fun _ _ ha => Finset.le_sup (f := id) (Set.mem_toFinset.mpr ha) - sSup_le := fun s _ ha => Finset.sup_le fun b hb => ha _ <| Set.mem_toFinset.mp hb + sSup_le := fun _ _ ha => Finset.sup_le fun _ hb => ha _ <| Set.mem_toFinset.mp hb sInf_le := fun _ _ ha => Finset.inf_le (Set.mem_toFinset.mpr ha) - le_sInf := fun s _ ha => Finset.le_inf fun b hb => ha _ <| Set.mem_toFinset.mp hb + le_sInf := fun _ _ ha => Finset.le_inf fun _ hb => ha _ <| Set.mem_toFinset.mp hb -- See note [reducible non-instances] /-- A finite bounded distributive lattice is completely distributive. -/ diff --git a/Mathlib/Data/Fintype/Perm.lean b/Mathlib/Data/Fintype/Perm.lean index 47dbd625b6d70..823a08e377bc8 100644 --- a/Mathlib/Data/Fintype/Perm.lean +++ b/Mathlib/Data/Fintype/Perm.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro import Mathlib.Data.Fintype.Card import Mathlib.GroupTheory.Perm.Basic import Mathlib.Tactic.Ring +import Mathlib.Data.Nat.Factorial.Basic /-! # `Fintype` instances for `Equiv` and `Perm` @@ -132,7 +133,7 @@ theorem mem_perms_of_finset_iff : ∀ {s : Finset α} {f : Perm α}, f ∈ permsOfFinset s ↔ ∀ {x}, f x ≠ x → x ∈ s := by rintro ⟨⟨l⟩, hs⟩ f; exact mem_permsOfList_iff -theorem card_perms_of_finset : ∀ s : Finset α, (permsOfFinset s).card = s.card ! := by +theorem card_perms_of_finset : ∀ s : Finset α, #(permsOfFinset s) = (#s)! := by rintro ⟨⟨l⟩, hs⟩; exact length_permsOfList l /-- The collection of permutations of a fintype is a fintype. -/ diff --git a/Mathlib/Data/Fintype/Pi.lean b/Mathlib/Data/Fintype/Pi.lean index 99a88bda7004a..8fdb303b7f64b 100644 --- a/Mathlib/Data/Fintype/Pi.lean +++ b/Mathlib/Data/Fintype/Pi.lean @@ -25,7 +25,7 @@ analogue of `Finset.pi` where the base finset is `univ` (but formally they are n there is an additional condition `i ∈ Finset.univ` in the `Finset.pi` definition). -/ def piFinset (t : ∀ a, Finset (δ a)) : Finset (∀ a, δ a) := (Finset.univ.pi t).map ⟨fun f a => f a (mem_univ a), fun _ _ => - by simp (config := {contextual := true}) [Function.funext_iff]⟩ + by simp (config := {contextual := true}) [funext_iff]⟩ @[simp] theorem mem_piFinset {t : ∀ a, Finset (δ a)} {f : ∀ a, δ a} : f ∈ piFinset t ↔ ∀ a, f a ∈ t a := by @@ -69,7 +69,7 @@ lemma piFinset_of_isEmpty [IsEmpty α] (s : ∀ a, Finset (γ a)) : piFinset s = @[simp] theorem piFinset_singleton (f : ∀ i, δ i) : piFinset (fun i => {f i} : ∀ i, Finset (δ i)) = {f} := - ext fun _ => by simp only [Function.funext_iff, Fintype.mem_piFinset, mem_singleton] + ext fun _ => by simp only [funext_iff, Fintype.mem_piFinset, mem_singleton] theorem piFinset_subsingleton {f : ∀ i, Finset (δ i)} (hf : ∀ i, (f i : Set (δ i)).Subsingleton) : (Fintype.piFinset f : Set (∀ i, δ i)).Subsingleton := fun _ ha _ hb => @@ -83,7 +83,7 @@ theorem piFinset_disjoint_of_disjoint (t₁ t₂ : ∀ a, Finset (δ a)) {a : α lemma piFinset_image [∀ a, DecidableEq (δ a)] (f : ∀ a, γ a → δ a) (s : ∀ a, Finset (γ a)) : piFinset (fun a ↦ (s a).image (f a)) = (piFinset s).image fun b a ↦ f _ (b a) := by - ext; simp only [mem_piFinset, mem_image, Classical.skolem, forall_and, Function.funext_iff] + ext; simp only [mem_piFinset, mem_image, Classical.skolem, forall_and, funext_iff] lemma eval_image_piFinset_subset (t : ∀ a, Finset (δ a)) (a : α) [DecidableEq (δ a)] : ((piFinset t).image fun f ↦ f a) ⊆ t a := image_subset_iff.2 fun _x hx ↦ mem_piFinset.1 hx _ @@ -104,12 +104,12 @@ lemma eval_image_piFinset_const {β} [DecidableEq β] (t : Finset β) (a : α) : variable [∀ a, DecidableEq (δ a)] lemma filter_piFinset_of_not_mem (t : ∀ a, Finset (δ a)) (a : α) (x : δ a) (hx : x ∉ t a) : - (piFinset t).filter (· a = x) = ∅ := by + {f ∈ piFinset t | f a = x} = ∅ := by simp only [filter_eq_empty_iff, mem_piFinset]; rintro f hf rfl; exact hx (hf _) -- TODO: This proof looks like a good example of something that `aesop` can't do but should lemma piFinset_update_eq_filter_piFinset_mem (s : ∀ i, Finset (δ i)) (i : α) {t : Finset (δ i)} - (hts : t ⊆ s i) : piFinset (Function.update s i t) = (piFinset s).filter (fun f ↦ f i ∈ t) := by + (hts : t ⊆ s i) : piFinset (Function.update s i t) = {f ∈ piFinset s | f i ∈ t} := by ext f simp only [mem_piFinset, mem_filter] refine ⟨fun h ↦ ?_, fun h j ↦ ?_⟩ @@ -124,7 +124,7 @@ lemma piFinset_update_eq_filter_piFinset_mem (s : ∀ i, Finset (δ i)) (i : α) lemma piFinset_update_singleton_eq_filter_piFinset_eq (s : ∀ i, Finset (δ i)) (i : α) {a : δ i} (ha : a ∈ s i) : - piFinset (Function.update s i {a}) = (piFinset s).filter (fun f ↦ f i = a) := by + piFinset (Function.update s i {a}) = {f ∈ piFinset s | f i = a} := by simp [piFinset_update_eq_filter_piFinset_mem, ha] end Fintype @@ -172,7 +172,7 @@ namespace Finset variable {ι : Type*} [DecidableEq (ι → α)] {s : Finset α} {f : ι → α} lemma piFinset_filter_const [DecidableEq ι] [Fintype ι] : - (Fintype.piFinset fun _ ↦ s).filter (∃ a ∈ s, const ι a = ·) = s.piDiag ι := by aesop + {f ∈ Fintype.piFinset fun _ : ι ↦ s | ∃ a ∈ s, const ι a = f} = s.piDiag ι := by aesop lemma piDiag_subset_piFinset [DecidableEq ι] [Fintype ι] : s.piDiag ι ⊆ Fintype.piFinset fun _ ↦ s := by simp [← piFinset_filter_const] diff --git a/Mathlib/Data/Fintype/Powerset.lean b/Mathlib/Data/Fintype/Powerset.lean index 206d1da75abc3..7e8604fc99236 100644 --- a/Mathlib/Data/Fintype/Powerset.lean +++ b/Mathlib/Data/Fintype/Powerset.lean @@ -29,30 +29,30 @@ variable [Fintype α] {s : Finset α} {k : ℕ} coe_injective <| by simp [-coe_eq_univ] lemma filter_subset_univ [DecidableEq α] (s : Finset α) : - filter (fun t ↦ t ⊆ s) univ = powerset s := by ext; simp + ({t | t ⊆ s} : Finset _) = powerset s := by ext; simp @[simp] lemma powerset_eq_univ : s.powerset = univ ↔ s = univ := by rw [← Finset.powerset_univ, powerset_inj] -lemma mem_powersetCard_univ : s ∈ powersetCard k (univ : Finset α) ↔ card s = k := +lemma mem_powersetCard_univ : s ∈ powersetCard k (univ : Finset α) ↔ #s = k := mem_powersetCard.trans <| and_iff_right <| subset_univ _ variable (α) @[simp] lemma univ_filter_card_eq (k : ℕ) : - (univ : Finset (Finset α)).filter (fun s ↦ s.card = k) = univ.powersetCard k := by ext; simp + ({s | #s = k} : Finset (Finset α)) = univ.powersetCard k := by ext; simp end Finset @[simp] theorem Fintype.card_finset_len [Fintype α] (k : ℕ) : - Fintype.card { s : Finset α // s.card = k } = Nat.choose (Fintype.card α) k := by + Fintype.card { s : Finset α // #s = k } = Nat.choose (Fintype.card α) k := by simp [Fintype.subtype_card, Finset.card_univ] instance Set.fintype [Fintype α] : Fintype (Set α) := ⟨(@Finset.univ (Finset α) _).map coeEmb.1, fun s => by classical - refine mem_map.2 ⟨Finset.univ.filter (· ∈ s), Finset.mem_univ _, (coe_filter _ _).trans ?_⟩ + refine mem_map.2 ⟨({a | a ∈ s} : Finset _), Finset.mem_univ _, (coe_filter _ _).trans ?_⟩ simp⟩ -- Not to be confused with `Set.Finite`, the predicate diff --git a/Mathlib/Data/Fintype/Quotient.lean b/Mathlib/Data/Fintype/Quotient.lean index 1675f05ea0a49..611a8d77d5b38 100644 --- a/Mathlib/Data/Fintype/Quotient.lean +++ b/Mathlib/Data/Fintype/Quotient.lean @@ -25,7 +25,7 @@ corresponding quotient type, then there is a corresponding term in the quotient of the product of the setoids indexed by `l`. -/ def Quotient.finChoiceAux {ι : Type*} [DecidableEq ι] {α : ι → Type*} [S : ∀ i, Setoid (α i)] : ∀ l : List ι, (∀ i ∈ l, Quotient (S i)) → @Quotient (∀ i ∈ l, α i) (by infer_instance) - | [], _ => ⟦fun i h => nomatch List.not_mem_nil _ h⟧ + | [], _ => ⟦fun _ h => nomatch List.not_mem_nil _ h⟧ | i :: l, f => by refine Quotient.liftOn₂ (f i (List.mem_cons_self _ _)) (Quotient.finChoiceAux l fun j h => f j (List.mem_cons_of_mem _ h)) ?_ ?_ @@ -40,7 +40,7 @@ def Quotient.finChoiceAux {ι : Type*} [DecidableEq ι] {α : ι → Type*} [S : theorem Quotient.finChoiceAux_eq {ι : Type*} [DecidableEq ι] {α : ι → Type*} [S : ∀ i, Setoid (α i)] : ∀ (l : List ι) (f : ∀ i ∈ l, α i), (Quotient.finChoiceAux l fun i h => ⟦f i h⟧) = ⟦f⟧ - | [], f => Quotient.sound fun i h => nomatch List.not_mem_nil _ h + | [], _ => Quotient.sound fun _ h => nomatch List.not_mem_nil _ h | i :: l, f => by simp only [finChoiceAux, Quotient.finChoiceAux_eq l, eq_mpr_eq_cast, lift_mk] refine Quotient.sound fun j h => ?_ @@ -66,7 +66,7 @@ def Quotient.finChoice {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → T · exact eqRec_heq (φ := fun l : Multiset ι => @Quotient (∀ i ∈ l, α i) (by infer_instance)) (Quotient.sound h) (g a) · change HEq (g a) (g b); congr 1; exact Quotient.sound h)) - (fun f => ⟦fun i => f i (Finset.mem_univ _)⟧) (fun a b h => Quotient.sound fun i => by apply h) + (fun f => ⟦fun i => f i (Finset.mem_univ _)⟧) (fun _ _ h => Quotient.sound fun i => by apply h) theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*} [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by diff --git a/Mathlib/Data/Fintype/Sigma.lean b/Mathlib/Data/Fintype/Sigma.lean index 64f8de8f89ab0..6827beb23b927 100644 --- a/Mathlib/Data/Fintype/Sigma.lean +++ b/Mathlib/Data/Fintype/Sigma.lean @@ -17,7 +17,7 @@ open Nat universe u v -variable {ι α β γ : Type*} {κ : ι → Type*} [Π i, Fintype (κ i)] +variable {ι α : Type*} {κ : ι → Type*} [Π i, Fintype (κ i)] open Finset Function diff --git a/Mathlib/Data/Fintype/Sort.lean b/Mathlib/Data/Fintype/Sort.lean index 40f2ba4db88c3..de5153b97b265 100644 --- a/Mathlib/Data/Fintype/Sort.lean +++ b/Mathlib/Data/Fintype/Sort.lean @@ -32,7 +32,7 @@ variable {α : Type*} [DecidableEq α] [Fintype α] [LinearOrder α] {m n : ℕ} cardinality `n`, then `Fin m ⊕ Fin n ≃ α`. The equivalence sends elements of `Fin m` to elements of `s` and elements of `Fin n` to elements of `sᶜ` while preserving order on each "half" of `Fin m ⊕ Fin n` (using `Set.orderIsoOfFin`). -/ -def finSumEquivOfFinset (hm : s.card = m) (hn : sᶜ.card = n) : Fin m ⊕ Fin n ≃ α := +def finSumEquivOfFinset (hm : #s = m) (hn : #sᶜ = n) : Fin m ⊕ Fin n ≃ α := calc Fin m ⊕ Fin n ≃ (s : Set α) ⊕ (sᶜ : Set α) := Equiv.sumCongr (s.orderIsoOfFin hm).toEquiv <| @@ -40,11 +40,11 @@ def finSumEquivOfFinset (hm : s.card = m) (hn : sᶜ.card = n) : Fin m ⊕ Fin n _ ≃ α := Equiv.Set.sumCompl _ @[simp] -theorem finSumEquivOfFinset_inl (hm : s.card = m) (hn : sᶜ.card = n) (i : Fin m) : +theorem finSumEquivOfFinset_inl (hm : #s = m) (hn : #sᶜ = n) (i : Fin m) : finSumEquivOfFinset hm hn (Sum.inl i) = s.orderEmbOfFin hm i := rfl @[simp] -theorem finSumEquivOfFinset_inr (hm : s.card = m) (hn : sᶜ.card = n) (i : Fin n) : +theorem finSumEquivOfFinset_inr (hm : #s = m) (hn : #sᶜ = n) (i : Fin n) : finSumEquivOfFinset hm hn (Sum.inr i) = sᶜ.orderEmbOfFin hn i := rfl diff --git a/Mathlib/Data/Fintype/Sum.lean b/Mathlib/Data/Fintype/Sum.lean index 2e15afba5679f..930f4d0abf5d9 100644 --- a/Mathlib/Data/Fintype/Sum.lean +++ b/Mathlib/Data/Fintype/Sum.lean @@ -35,7 +35,7 @@ theorem Fintype.card_sum [Fintype α] [Fintype β] : card_disjSum _ _ /-- If the subtype of all-but-one elements is a `Fintype` then the type itself is a `Fintype`. -/ -def fintypeOfFintypeNe (a : α) (h : Fintype { b // b ≠ a }) : Fintype α := +def fintypeOfFintypeNe (a : α) (_ : Fintype { b // b ≠ a }) : Fintype α := Fintype.ofBijective (Sum.elim ((↑) : { b // b = a } → α) ((↑) : { b // b ≠ a } → α)) <| by classical exact (Equiv.sumCompl (· = a)).bijective @@ -70,7 +70,7 @@ theorem image_subtype_univ_ssubset_image_univ [Fintype α] [DecidableEq β] (k : /-- Any injection from a finset `s` in a fintype `α` to a finset `t` of the same cardinality as `α` can be extended to a bijection between `α` and `t`. -/ theorem Finset.exists_equiv_extend_of_card_eq [Fintype α] [DecidableEq β] {t : Finset β} - (hαt : Fintype.card α = t.card) {s : Finset α} {f : α → β} (hfst : Finset.image f s ⊆ t) + (hαt : Fintype.card α = #t) {s : Finset α} {f : α → β} (hfst : Finset.image f s ⊆ t) (hfs : Set.InjOn f s) : ∃ g : α ≃ t, ∀ i ∈ s, (g i : β) = f i := by classical induction' s using Finset.induction with a s has H generalizing f @@ -95,7 +95,7 @@ theorem Finset.exists_equiv_extend_of_card_eq [Fintype α] [DecidableEq β] {t : /-- Any injection from a set `s` in a fintype `α` to a finset `t` of the same cardinality as `α` can be extended to a bijection between `α` and `t`. -/ theorem Set.MapsTo.exists_equiv_extend_of_card_eq [Fintype α] {t : Finset β} - (hαt : Fintype.card α = t.card) {s : Set α} {f : α → β} (hfst : s.MapsTo f t) + (hαt : Fintype.card α = #t) {s : Set α} {f : α → β} (hfst : s.MapsTo f t) (hfs : Set.InjOn f s) : ∃ g : α ≃ t, ∀ i ∈ s, (g i : β) = f i := by classical let s' : Finset α := s.toFinset diff --git a/Mathlib/Data/FunLike/Basic.lean b/Mathlib/Data/FunLike/Basic.lean index f23481b549544..afcc1b7e13a25 100644 --- a/Mathlib/Data/FunLike/Basic.lean +++ b/Mathlib/Data/FunLike/Basic.lean @@ -17,7 +17,7 @@ There is the "D"ependent version `DFunLike` and the non-dependent version `FunLi A typical type of morphisms should be declared as: ``` -structure MyHom (A B : Type*) [MyClass A] [MyClass B] := +structure MyHom (A B : Type*) [MyClass A] [MyClass B] where (toFun : A → B) (map_op' : ∀ (x y : A), toFun (MyClass.op x y) = MyClass.op (toFun x) (toFun y)) @@ -79,7 +79,7 @@ The second step is to add instances of your new `MyHomClass` for all types exten Typically, you can just declare a new class analogous to `MyHomClass`: ``` -structure CoolerHom (A B : Type*) [CoolClass A] [CoolClass B] extends MyHom A B := +structure CoolerHom (A B : Type*) [CoolClass A] [CoolClass B] extends MyHom A B where (map_cool' : toFun CoolClass.cool = CoolClass.cool) class CoolerHomClass (F : Type*) (A B : outParam Type*) [CoolClass A] [CoolClass B] @@ -194,7 +194,7 @@ theorem ext (f g : F) (h : ∀ x : α, f x = g x) : f = g := DFunLike.coe_injective' (funext h) theorem ext_iff {f g : F} : f = g ↔ ∀ x, f x = g x := - coe_fn_eq.symm.trans Function.funext_iff + coe_fn_eq.symm.trans funext_iff protected theorem congr_fun {f g : F} (h₁ : f = g) (x : α) : f x = g x := congr_fun (congr_arg _ h₁) x diff --git a/Mathlib/Data/FunLike/Embedding.lean b/Mathlib/Data/FunLike/Embedding.lean index b65a26da5cc05..a8551af72e079 100644 --- a/Mathlib/Data/FunLike/Embedding.lean +++ b/Mathlib/Data/FunLike/Embedding.lean @@ -14,7 +14,7 @@ This typeclass is primarily for use by embeddings such as `RelEmbedding`. A typical type of embeddings should be declared as: ``` -structure MyEmbedding (A B : Type*) [MyClass A] [MyClass B] := +structure MyEmbedding (A B : Type*) [MyClass A] [MyClass B] where (toFun : A → B) (injective' : Function.Injective toFun) (map_op' : ∀ (x y : A), toFun (MyClass.op x y) = MyClass.op (toFun x) (toFun y)) @@ -58,8 +58,8 @@ Continuing the example above: You should extend this class when you extend `MyEmbedding`. -/ class MyEmbeddingClass (F : Type*) (A B : outParam Type*) [MyClass A] [MyClass B] [FunLike F A B] - extends EmbeddingLike F A B := - (map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y)) + extends EmbeddingLike F A B where + map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y) @[simp] lemma map_op {F A B : Type*} [MyClass A] [MyClass B] [FunLike F A B] [MyEmbeddingClass F A B] @@ -84,12 +84,12 @@ The second step is to add instances of your new `MyEmbeddingClass` for all types Typically, you can just declare a new class analogous to `MyEmbeddingClass`: ``` -structure CoolerEmbedding (A B : Type*) [CoolClass A] [CoolClass B] extends MyEmbedding A B := +structure CoolerEmbedding (A B : Type*) [CoolClass A] [CoolClass B] extends MyEmbedding A B where (map_cool' : toFun CoolClass.cool = CoolClass.cool) class CoolerEmbeddingClass (F : Type*) (A B : outParam Type*) [CoolClass A] [CoolClass B] [FunLike F A B] - extends MyEmbeddingClass F A B := + extends MyEmbeddingClass F A B where (map_cool : ∀ (f : F), f CoolClass.cool = CoolClass.cool) @[simp] diff --git a/Mathlib/Data/FunLike/Equiv.lean b/Mathlib/Data/FunLike/Equiv.lean index d2a640eddc593..92881dc5ec3a9 100644 --- a/Mathlib/Data/FunLike/Equiv.lean +++ b/Mathlib/Data/FunLike/Equiv.lean @@ -14,7 +14,7 @@ This typeclass is primarily for use by isomorphisms like `MonoidEquiv` and `Line A typical type of isomorphisms should be declared as: ``` -structure MyIso (A B : Type*) [MyClass A] [MyClass B] extends Equiv A B := +structure MyIso (A B : Type*) [MyClass A] [MyClass B] extends Equiv A B where (map_op' : ∀ (x y : A), toFun (MyClass.op x y) = MyClass.op (toFun x) (toFun y)) namespace MyIso @@ -77,12 +77,12 @@ The second step is to add instances of your new `MyIsoClass` for all types exten Typically, you can just declare a new class analogous to `MyIsoClass`: ``` -structure CoolerIso (A B : Type*) [CoolClass A] [CoolClass B] extends MyIso A B := +structure CoolerIso (A B : Type*) [CoolClass A] [CoolClass B] extends MyIso A B where (map_cool' : toFun CoolClass.cool = CoolClass.cool) class CoolerIsoClass (F : Type*) (A B : outParam Type*) [CoolClass A] [CoolClass B] [EquivLike F A B] - extends MyIsoClass F A B := + extends MyIsoClass F A B where (map_cool : ∀ (f : F), f CoolClass.cool = CoolClass.cool) @[simp] lemma map_cool {F A B : Type*} [CoolClass A] [CoolClass B] diff --git a/Mathlib/Data/FunLike/Fintype.lean b/Mathlib/Data/FunLike/Fintype.lean index e8d4b935941a6..cafeb127772dd 100644 --- a/Mathlib/Data/FunLike/Fintype.lean +++ b/Mathlib/Data/FunLike/Fintype.lean @@ -3,9 +3,9 @@ Copyright (c) 2022 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ -import Mathlib.Data.Finite.Basic import Mathlib.Data.Fintype.Basic import Mathlib.Data.FunLike.Basic +import Mathlib.Data.Finite.Prod /-! # Finiteness of `DFunLike` types diff --git a/Mathlib/Data/Holor.lean b/Mathlib/Data/Holor.lean index d51140bf97ce3..b7fc524917add 100644 --- a/Mathlib/Data/Holor.lean +++ b/Mathlib/Data/Holor.lean @@ -181,9 +181,9 @@ theorem slice_eq (x : Holor α (d :: ds)) (y : Holor α (d :: ds)) (h : slice x have hid : i < d := (forall₂_cons.1 hiisdds).1 have hisds : Forall₂ (· < ·) is ds := (forall₂_cons.1 hiisdds).2 calc - x ⟨i :: is, _⟩ = slice x i hid ⟨is, hisds⟩ := congr_arg (fun t => x t) (Subtype.eq rfl) + x ⟨i :: is, _⟩ = slice x i hid ⟨is, hisds⟩ := congr_arg x (Subtype.eq rfl) _ = slice y i hid ⟨is, hisds⟩ := by rw [h] - _ = y ⟨i :: is, _⟩ := congr_arg (fun t => y t) (Subtype.eq rfl) + _ = y ⟨i :: is, _⟩ := congr_arg y (Subtype.eq rfl) theorem slice_unitVec_mul [Ring α] {i : ℕ} {j : ℕ} (hid : i < d) (x : Holor α ds) : slice (unitVec d j ⊗ x) i hid = if i = j then x else 0 := diff --git a/Mathlib/Data/Int/Align.lean b/Mathlib/Data/Int/Align.lean deleted file mode 100644 index 70c7b26e8b80d..0000000000000 --- a/Mathlib/Data/Int/Align.lean +++ /dev/null @@ -1,10 +0,0 @@ -/- -Copyright (c) 2016 Jeremy Avigad. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jeremy Avigad --/ - -import Mathlib.Init -/-! -# Align statements for results about the integers --/ diff --git a/Mathlib/Data/Int/Bitwise.lean b/Mathlib/Data/Int/Bitwise.lean index 664c817a6e578..e0bc3e616150f 100644 --- a/Mathlib/Data/Int/Bitwise.lean +++ b/Mathlib/Data/Int/Bitwise.lean @@ -404,7 +404,7 @@ attribute [local simp] Int.zero_div theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k | (m : ℕ), n, (k : ℕ) => congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc]) - | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _) + | -[_+1], _, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _) | (m : ℕ), n, -[k+1] => subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k) (fun (i n : ℕ) => diff --git a/Mathlib/Data/Int/CardIntervalMod.lean b/Mathlib/Data/Int/CardIntervalMod.lean index b5725e3f43eb6..b243bdf2208d0 100644 --- a/Mathlib/Data/Int/CardIntervalMod.lean +++ b/Mathlib/Data/Int/CardIntervalMod.lean @@ -25,14 +25,16 @@ namespace Int variable (a b : ℤ) {r : ℤ} -lemma Ico_filter_modEq_eq (v : ℤ) : (Ico a b).filter (· ≡ v [ZMOD r]) = - ((Ico (a - v) (b - v)).filter (r ∣ ·)).map ⟨(· + v), add_left_injective v⟩ := by +lemma Ico_filter_modEq_eq (v : ℤ) : + {x ∈ Ico a b | x ≡ v [ZMOD r]} = + {x ∈ Ico (a - v) (b - v) | r ∣ x}.map ⟨(· + v), add_left_injective v⟩ := by ext x simp_rw [mem_map, mem_filter, mem_Ico, Function.Embedding.coeFn_mk, ← eq_sub_iff_add_eq, exists_eq_right, modEq_comm, modEq_iff_dvd, sub_lt_sub_iff_right, sub_le_sub_iff_right] -lemma Ioc_filter_modEq_eq (v : ℤ) : (Ioc a b).filter (· ≡ v [ZMOD r]) = - ((Ioc (a - v) (b - v)).filter (r ∣ ·)).map ⟨(· + v), add_left_injective v⟩ := by +lemma Ioc_filter_modEq_eq (v : ℤ) : + {x ∈ Ioc a b | x ≡ v [ZMOD r]} = + {x ∈ Ioc (a - v) (b - v) | r ∣ x}.map ⟨(· + v), add_left_injective v⟩ := by ext x simp_rw [mem_map, mem_filter, mem_Ioc, Function.Embedding.coeFn_mk, ← eq_sub_iff_add_eq, exists_eq_right, modEq_comm, modEq_iff_dvd, sub_lt_sub_iff_right, sub_le_sub_iff_right] @@ -40,40 +42,40 @@ lemma Ioc_filter_modEq_eq (v : ℤ) : (Ioc a b).filter (· ≡ v [ZMOD r]) = variable (hr : 0 < r) include hr -lemma Ico_filter_dvd_eq : (Ico a b).filter (r ∣ ·) = - (Ico ⌈a / (r : ℚ)⌉ ⌈b / (r : ℚ)⌉).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by +lemma Ico_filter_dvd_eq : + {x ∈ Ico a b | r ∣ x} = + (Ico ⌈a / (r : ℚ)⌉ ⌈b / (r : ℚ)⌉).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by ext x simp only [mem_map, mem_filter, mem_Ico, ceil_le, lt_ceil, div_le_iff₀, lt_div_iff₀, dvd_iff_exists_eq_mul_left, cast_pos.2 hr, ← cast_mul, cast_lt, cast_le] aesop -lemma Ioc_filter_dvd_eq : (Ioc a b).filter (r ∣ ·) = - (Ioc ⌊a / (r : ℚ)⌋ ⌊b / (r : ℚ)⌋).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by +lemma Ioc_filter_dvd_eq : + {x ∈ Ioc a b | r ∣ x} = + (Ioc ⌊a / (r : ℚ)⌋ ⌊b / (r : ℚ)⌋).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by ext x simp only [mem_map, mem_filter, mem_Ioc, floor_lt, le_floor, div_lt_iff₀, le_div_iff₀, dvd_iff_exists_eq_mul_left, cast_pos.2 hr, ← cast_mul, cast_lt, cast_le] aesop /-- There are `⌈b / r⌉ - ⌈a / r⌉` multiples of `r` in `[a, b)`, if `a ≤ b`. -/ -theorem Ico_filter_dvd_card : ((Ico a b).filter (r ∣ ·)).card = - max (⌈b / (r : ℚ)⌉ - ⌈a / (r : ℚ)⌉) 0 := by +theorem Ico_filter_dvd_card : #{x ∈ Ico a b | r ∣ x} = max (⌈b / (r : ℚ)⌉ - ⌈a / (r : ℚ)⌉) 0 := by rw [Ico_filter_dvd_eq _ _ hr, card_map, card_Ico, toNat_eq_max] /-- There are `⌊b / r⌋ - ⌊a / r⌋` multiples of `r` in `(a, b]`, if `a ≤ b`. -/ -theorem Ioc_filter_dvd_card : ((Ioc a b).filter (r ∣ ·)).card = - max (⌊b / (r : ℚ)⌋ - ⌊a / (r : ℚ)⌋) 0 := by +theorem Ioc_filter_dvd_card : #{x ∈ Ioc a b | r ∣ x} = max (⌊b / (r : ℚ)⌋ - ⌊a / (r : ℚ)⌋) 0 := by rw [Ioc_filter_dvd_eq _ _ hr, card_map, card_Ioc, toNat_eq_max] /-- There are `⌈(b - v) / r⌉ - ⌈(a - v) / r⌉` numbers congruent to `v` mod `r` in `[a, b)`, if `a ≤ b`. -/ -theorem Ico_filter_modEq_card (v : ℤ) : ((Ico a b).filter (· ≡ v [ZMOD r])).card = - max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by +theorem Ico_filter_modEq_card (v : ℤ) : + #{x ∈ Ico a b | x ≡ v [ZMOD r]} = max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by simp [Ico_filter_modEq_eq, Ico_filter_dvd_eq, toNat_eq_max, hr] /-- There are `⌊(b - v) / r⌋ - ⌊(a - v) / r⌋` numbers congruent to `v` mod `r` in `(a, b]`, if `a ≤ b`. -/ -theorem Ioc_filter_modEq_card (v : ℤ) : ((Ioc a b).filter (· ≡ v [ZMOD r])).card = - max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by +theorem Ioc_filter_modEq_card (v : ℤ) : + #{x ∈ Ioc a b | x ≡ v [ZMOD r]} = max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by simp [Ioc_filter_modEq_eq, Ioc_filter_dvd_eq, toNat_eq_max, hr] end Int @@ -82,16 +84,18 @@ namespace Nat variable (a b : ℕ) {r : ℕ} -lemma Ico_filter_modEq_cast {v : ℕ} : ((Ico a b).filter (· ≡ v [MOD r])).map castEmbedding = - (Ico (a : ℤ) (b : ℤ)).filter (· ≡ v [ZMOD r]) := by +lemma Ico_filter_modEq_cast {v : ℕ} : + {x ∈ Ico a b | x ≡ v [MOD r]}.map castEmbedding = + {x ∈ Ico (a : ℤ) (b : ℤ) | x ≡ v [ZMOD r]} := by ext x simp only [mem_map, mem_filter, mem_Ico, castEmbedding_apply] constructor · simp_rw [forall_exists_index, ← natCast_modEq_iff]; intro y ⟨h, c⟩; subst c; exact_mod_cast h · intro h; lift x to ℕ using (by linarith); exact ⟨x, by simp_all [natCast_modEq_iff]⟩ -lemma Ioc_filter_modEq_cast {v : ℕ} : ((Ioc a b).filter (· ≡ v [MOD r])).map castEmbedding = - (Ioc (a : ℤ) (b : ℤ)).filter (· ≡ v [ZMOD r]) := by +lemma Ioc_filter_modEq_cast {v : ℕ} : + {x ∈ Ioc a b | x ≡ v [MOD r]}.map castEmbedding = + {x ∈ Ioc (a : ℤ) (b : ℤ) | x ≡ v [ZMOD r]} := by ext x simp only [mem_map, mem_filter, mem_Ioc, castEmbedding_apply] constructor @@ -103,15 +107,15 @@ include hr /-- There are `⌈(b - v) / r⌉ - ⌈(a - v) / r⌉` numbers congruent to `v` mod `r` in `[a, b)`, if `a ≤ b`. `Nat` version of `Int.Ico_filter_modEq_card`. -/ -theorem Ico_filter_modEq_card (v : ℕ) : ((Ico a b).filter (· ≡ v [MOD r])).card = - max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by +theorem Ico_filter_modEq_card (v : ℕ) : + #{x ∈ Ico a b | x ≡ v [MOD r]} = max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by simp_rw [← Ico_filter_modEq_cast _ _ ▸ card_map _, Int.Ico_filter_modEq_card _ _ (cast_lt.mpr hr), Int.cast_natCast] /-- There are `⌊(b - v) / r⌋ - ⌊(a - v) / r⌋` numbers congruent to `v` mod `r` in `(a, b]`, if `a ≤ b`. `Nat` version of `Int.Ioc_filter_modEq_card`. -/ -theorem Ioc_filter_modEq_card (v : ℕ) : ((Ioc a b).filter (· ≡ v [MOD r])).card = - max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by +theorem Ioc_filter_modEq_card (v : ℕ) : + #{x ∈ Ioc a b | x ≡ v [MOD r]} = max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by simp_rw [← Ioc_filter_modEq_cast _ _ ▸ card_map _, Int.Ioc_filter_modEq_card _ _ (cast_lt.mpr hr), Int.cast_natCast] diff --git a/Mathlib/Data/Int/Cast/Lemmas.lean b/Mathlib/Data/Int/Cast/Lemmas.lean index da5f6ffae2ed7..ef53e50244441 100644 --- a/Mathlib/Data/Int/Cast/Lemmas.lean +++ b/Mathlib/Data/Int/Cast/Lemmas.lean @@ -77,7 +77,7 @@ lemma cast_ne_one : (n : α) ≠ 1 ↔ n ≠ 1 := cast_eq_one.not end AddGroupWithOne section NonAssocRing -variable [NonAssocRing α] {a b : α} {n : ℤ} +variable [NonAssocRing α] variable (α) in /-- `coe : ℤ → α` as a `RingHom`. -/ @@ -147,7 +147,7 @@ end SemiconjBy namespace Commute section NonAssocRing -variable [NonAssocRing α] {a b : α} {n : ℤ} +variable [NonAssocRing α] {a : α} {n : ℤ} @[simp] lemma intCast_left : Commute (n : α) a := Int.cast_commute _ _ @@ -159,7 +159,7 @@ variable [NonAssocRing α] {a b : α} {n : ℤ} end NonAssocRing section Ring -variable [Ring α] {a b : α} {n : ℤ} +variable [Ring α] {a b : α} @[simp] lemma intCast_mul_right (h : Commute a b) (m : ℤ) : Commute a (m * b) := SemiconjBy.intCast_mul_right h m @@ -172,18 +172,8 @@ lemma intCast_mul_intCast_mul (h : Commute a b) (m n : ℤ) : Commute (m * a) (n variable (a) (m n : ℤ) -/- Porting note (#10618): `simp` attribute removed as linter reports: -simp can prove this: - by simp only [Commute.cast_int_right, Commute.refl, Commute.mul_right] --/ --- @[simp] lemma self_intCast_mul : Commute a (n * a : α) := (Commute.refl a).intCast_mul_right n -/- Porting note (#10618): `simp` attribute removed as linter reports: -simp can prove this: - by simp only [Commute.cast_int_left, Commute.refl, Commute.mul_left] --/ --- @[simp] lemma intCast_mul_self : Commute ((n : α) * a) a := (Commute.refl a).intCast_mul_left n lemma self_intCast_mul_intCast_mul : Commute (m * a : α) (n * a : α) := diff --git a/Mathlib/Data/Int/DivMod.lean b/Mathlib/Data/Int/DivMod.lean index e2d8db47293a8..53fa12a4f2eb5 100644 --- a/Mathlib/Data/Int/DivMod.lean +++ b/Mathlib/Data/Int/DivMod.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ +import Mathlib.Init + /-! # Basic lemmas about division and modulo for integers @@ -18,3 +20,5 @@ theorem emod_eq_sub_self_emod {a b : Int} : a % b = (a - b) % b := theorem emod_eq_add_self_emod {a b : Int} : a % b = (a + b) % b := add_emod_self.symm + +end Int diff --git a/Mathlib/Data/Int/GCD.lean b/Mathlib/Data/Int/GCD.lean index 6c4e2b4ad9ed9..eccc02d840c40 100644 --- a/Mathlib/Data/Int/GCD.lean +++ b/Mathlib/Data/Int/GCD.lean @@ -7,7 +7,9 @@ import Mathlib.Algebra.Group.Int import Mathlib.Algebra.GroupWithZero.Semiconj import Mathlib.Algebra.Group.Commute.Units import Mathlib.Data.Nat.GCD.Basic -import Mathlib.Order.Bounds.Basic +import Mathlib.Order.Lattice +import Mathlib.Data.Set.Operations +import Mathlib.Order.Bounds.Defs /-! # Extended GCD and divisibility over ℤ diff --git a/Mathlib/Data/Int/Interval.lean b/Mathlib/Data/Int/Interval.lean index ce53928746469..afb891ee30e61 100644 --- a/Mathlib/Data/Int/Interval.lean +++ b/Mathlib/Data/Int/Interval.lean @@ -98,35 +98,35 @@ theorem uIcc_eq_finset_map : (Nat.castEmbedding.trans <| addLeftEmbedding <| min a b) := rfl @[simp] -theorem card_Icc : (Icc a b).card = (b + 1 - a).toNat := (card_map _).trans <| card_range _ +theorem card_Icc : #(Icc a b) = (b + 1 - a).toNat := (card_map _).trans <| card_range _ @[simp] -theorem card_Ico : (Ico a b).card = (b - a).toNat := (card_map _).trans <| card_range _ +theorem card_Ico : #(Ico a b) = (b - a).toNat := (card_map _).trans <| card_range _ @[simp] -theorem card_Ioc : (Ioc a b).card = (b - a).toNat := (card_map _).trans <| card_range _ +theorem card_Ioc : #(Ioc a b) = (b - a).toNat := (card_map _).trans <| card_range _ @[simp] -theorem card_Ioo : (Ioo a b).card = (b - a - 1).toNat := (card_map _).trans <| card_range _ +theorem card_Ioo : #(Ioo a b) = (b - a - 1).toNat := (card_map _).trans <| card_range _ @[simp] -theorem card_uIcc : (uIcc a b).card = (b - a).natAbs + 1 := +theorem card_uIcc : #(uIcc a b) = (b - a).natAbs + 1 := (card_map _).trans <| (Nat.cast_inj (R := ℤ)).mp <| by rw [card_range, sup_eq_max, inf_eq_min, Int.toNat_of_nonneg (sub_nonneg_of_le <| le_add_one min_le_max), Int.ofNat_add, Int.natCast_natAbs, add_comm, add_sub_assoc, max_sub_min_eq_abs, add_comm, Int.ofNat_one] -theorem card_Icc_of_le (h : a ≤ b + 1) : ((Icc a b).card : ℤ) = b + 1 - a := by +theorem card_Icc_of_le (h : a ≤ b + 1) : (#(Icc a b) : ℤ) = b + 1 - a := by rw [card_Icc, toNat_sub_of_le h] -theorem card_Ico_of_le (h : a ≤ b) : ((Ico a b).card : ℤ) = b - a := by +theorem card_Ico_of_le (h : a ≤ b) : (#(Ico a b) : ℤ) = b - a := by rw [card_Ico, toNat_sub_of_le h] -theorem card_Ioc_of_le (h : a ≤ b) : ((Ioc a b).card : ℤ) = b - a := by +theorem card_Ioc_of_le (h : a ≤ b) : (#(Ioc a b) : ℤ) = b - a := by rw [card_Ioc, toNat_sub_of_le h] -theorem card_Ioo_of_lt (h : a < b) : ((Ioo a b).card : ℤ) = b - a - 1 := by +theorem card_Ioo_of_lt (h : a < b) : (#(Ioo a b) : ℤ) = b - a - 1 := by rw [card_Ioo, sub_sub, toNat_sub_of_le h] -- Porting note (#11119): removed `simp` attribute because `simpNF` says it can prove it diff --git a/Mathlib/Data/Int/LeastGreatest.lean b/Mathlib/Data/Int/LeastGreatest.lean index afe3c87b5a130..9e3c23e0cbff1 100644 --- a/Mathlib/Data/Int/LeastGreatest.lean +++ b/Mathlib/Data/Int/LeastGreatest.lean @@ -77,7 +77,7 @@ integers, with an explicit upper bound and a proof that it is somewhere true, re the greatest value for which the predicate is true. -/ def greatestOfBdd {P : ℤ → Prop} [DecidablePred P] (b : ℤ) (Hb : ∀ z : ℤ, P z → z ≤ b) (Hinh : ∃ z : ℤ, P z) : { ub : ℤ // P ub ∧ ∀ z : ℤ, P z → z ≤ ub } := - have Hbdd' : ∀ z : ℤ, P (-z) → -b ≤ z := fun z h => neg_le.1 (Hb _ h) + have Hbdd' : ∀ z : ℤ, P (-z) → -b ≤ z := fun _ h => neg_le.1 (Hb _ h) have Hinh' : ∃ z : ℤ, P (-z) := let ⟨elt, Helt⟩ := Hinh ⟨-elt, by rw [neg_neg]; exact Helt⟩ diff --git a/Mathlib/Data/Int/Lemmas.lean b/Mathlib/Data/Int/Lemmas.lean index 61ccb22c02adb..7808804746ccb 100644 --- a/Mathlib/Data/Int/Lemmas.lean +++ b/Mathlib/Data/Int/Lemmas.lean @@ -30,15 +30,12 @@ theorem le_natCast_sub (m n : ℕ) : (m - n : ℤ) ≤ ↑(m - n : ℕ) := by /-! ### `succ` and `pred` -/ --- Porting note (#10618): simp can prove this @[simp] theorem succ_natCast_pos (n : ℕ) : 0 < (n : ℤ) + 1 := lt_add_one_iff.mpr (by simp) /-! ### `natAbs` -/ -variable {a b : ℤ} {n : ℕ} - theorem natAbs_eq_iff_sq_eq {a b : ℤ} : a.natAbs = b.natAbs ↔ a ^ 2 = b ^ 2 := by rw [sq, sq] exact natAbs_eq_iff_mul_self_eq @@ -108,7 +105,7 @@ end Intervals theorem toNat_of_nonpos : ∀ {z : ℤ}, z ≤ 0 → z.toNat = 0 | 0, _ => rfl | (n + 1 : ℕ), h => (h.not_lt (by simp)).elim - | -[n+1], _ => rfl + | -[_+1], _ => rfl /-! ### bitwise ops diff --git a/Mathlib/Data/Int/Log.lean b/Mathlib/Data/Int/Log.lean index 8d9efb0ac2af0..e6f5f9f457159 100644 --- a/Mathlib/Data/Int/Log.lean +++ b/Mathlib/Data/Int/Log.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Order.Floor -import Mathlib.Algebra.Order.Field.Power import Mathlib.Data.Nat.Log /-! @@ -94,7 +93,7 @@ theorem zpow_log_le_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) : (b : R) ^ rw [zpow_natCast, ← Nat.cast_pow, ← Nat.le_floor_iff hr.le] exact Nat.pow_log_le_self b (Nat.floor_pos.mpr hr1).ne' · rw [log_of_right_le_one _ hr1, zpow_neg, zpow_natCast, ← Nat.cast_pow] - exact inv_le_of_inv_le hr (Nat.ceil_le.1 <| Nat.le_pow_clog hb _) + exact inv_le_of_inv_le₀ hr (Nat.ceil_le.1 <| Nat.le_pow_clog hb _) theorem lt_zpow_succ_log_self {b : ℕ} (hb : 1 < b) (r : R) : r < (b : R) ^ (log b r + 1) := by rcases le_or_lt r 0 with hr | hr @@ -106,11 +105,11 @@ theorem lt_zpow_succ_log_self {b : ℕ} (hb : 1 < b) (r : R) : r < (b : R) ^ (lo apply Nat.lt_of_floor_lt exact Nat.lt_pow_succ_log_self hb _ · rw [log_of_right_le_one _ hr1.le] - have hcri : 1 < r⁻¹ := one_lt_inv hr hr1 + have hcri : 1 < r⁻¹ := (one_lt_inv₀ hr).2 hr1 have : 1 ≤ Nat.clog b ⌈r⁻¹⌉₊ := Nat.succ_le_of_lt (Nat.clog_pos hb <| Nat.one_lt_cast.1 <| hcri.trans_le (Nat.le_ceil _)) rw [neg_add_eq_sub, ← neg_sub, ← Int.ofNat_one, ← Int.ofNat_sub this, zpow_neg, zpow_natCast, - lt_inv hr (pow_pos (Nat.cast_pos.mpr <| zero_lt_one.trans hb) _), ← Nat.cast_pow] + lt_inv_comm₀ hr (pow_pos (Nat.cast_pos.mpr <| zero_lt_one.trans hb) _), ← Nat.cast_pow] refine Nat.lt_ceil.1 ?_ exact Nat.pow_pred_clog_lt_self hb <| Nat.one_lt_cast.1 <| hcri.trans_le <| Nat.le_ceil _ @@ -135,18 +134,17 @@ theorem log_one_left (r : R) : log 1 r = 0 := by -- Porting note: needed to replace b ^ z with (b : R) ^ z in the below theorem log_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : log b ((b : R) ^ z : R) = z := by obtain ⟨n, rfl | rfl⟩ := Int.eq_nat_or_neg z - · rw [log_of_one_le_right _ (one_le_zpow_of_nonneg _ <| Int.natCast_nonneg _), zpow_natCast, ← - Nat.cast_pow, Nat.floor_natCast, Nat.log_pow hb] - exact mod_cast hb.le - · rw [log_of_right_le_one _ (zpow_le_one_of_nonpos _ <| neg_nonpos.mpr (Int.natCast_nonneg _)), + · rw [log_of_one_le_right _ (one_le_zpow₀ (mod_cast hb.le) <| Int.natCast_nonneg _), zpow_natCast, + ← Nat.cast_pow, Nat.floor_natCast, Nat.log_pow hb] + · rw [log_of_right_le_one _ (zpow_le_one_of_nonpos₀ (mod_cast hb.le) <| + neg_nonpos.2 (Int.natCast_nonneg _)), zpow_neg, inv_inv, zpow_natCast, ← Nat.cast_pow, Nat.ceil_natCast, Nat.clog_pow _ _ hb] - exact mod_cast hb.le @[mono] theorem log_mono_right {b : ℕ} {r₁ r₂ : R} (h₀ : 0 < r₁) (h : r₁ ≤ r₂) : log b r₁ ≤ log b r₂ := by rcases le_total r₁ 1 with h₁ | h₁ <;> rcases le_total r₂ 1 with h₂ | h₂ · rw [log_of_right_le_one _ h₁, log_of_right_le_one _ h₂, neg_le_neg_iff, Int.ofNat_le] - exact Nat.clog_mono_right _ (Nat.ceil_mono <| inv_le_inv_of_le h₀ h) + exact Nat.clog_mono_right _ (Nat.ceil_mono <| inv_anti₀ h₀ h) · rw [log_of_right_le_one _ h₁, log_of_one_le_right _ h₂] exact (neg_nonpos.mpr (Int.natCast_nonneg _)).trans (Int.natCast_nonneg _) · obtain rfl := le_antisymm h (h₂.trans h₁) @@ -160,10 +158,10 @@ variable (R) def zpowLogGi {b : ℕ} (hb : 1 < b) : GaloisCoinsertion (fun z : ℤ => - Subtype.mk ((b : R) ^ z) <| zpow_pos_of_pos (mod_cast zero_lt_one.trans hb) z) + Subtype.mk ((b : R) ^ z) <| zpow_pos (mod_cast zero_lt_one.trans hb) z) fun r : Set.Ioi (0 : R) => Int.log b (r : R) := GaloisCoinsertion.monotoneIntro (fun r₁ _ => log_mono_right r₁.2) - (fun _ _ hz => Subtype.coe_le_coe.mp <| (zpow_strictMono <| mod_cast hb).monotone hz) + (fun _ _ hz => Subtype.coe_le_coe.mp <| (zpow_right_strictMono₀ <| mod_cast hb).monotone hz) (fun r => Subtype.coe_le_coe.mp <| zpow_log_le_self hb r.2) fun _ => log_zpow (R := R) hb _ variable {R} @@ -203,8 +201,8 @@ theorem clog_of_right_le_zero (b : ℕ) {r : R} (hr : r ≤ 0) : clog b r = 0 := theorem clog_inv (b : ℕ) (r : R) : clog b r⁻¹ = -log b r := by cases' lt_or_le 0 r with hrp hrp · obtain hr | hr := le_total 1 r - · rw [clog_of_right_le_one _ (inv_le_one hr), log_of_one_le_right _ hr, inv_inv] - · rw [clog_of_one_le_right _ (one_le_inv hrp hr), log_of_right_le_one _ hr, neg_neg] + · rw [clog_of_right_le_one _ (inv_le_one_of_one_le₀ hr), log_of_one_le_right _ hr, inv_inv] + · rw [clog_of_one_le_right _ ((one_le_inv₀ hrp).2 hr), log_of_right_le_one _ hr, neg_neg] · rw [clog_of_right_le_zero _ (inv_nonpos.mpr hrp), log_of_right_le_zero _ hrp, neg_zero] @[simp] @@ -235,15 +233,15 @@ theorem self_le_zpow_clog {b : ℕ} (hb : 1 < b) (r : R) : r ≤ (b : R) ^ clog rcases le_or_lt r 0 with hr | hr · rw [clog_of_right_le_zero _ hr, zpow_zero] exact hr.trans zero_le_one - rw [← neg_log_inv_eq_clog, zpow_neg, le_inv hr (zpow_pos_of_pos _ _)] + rw [← neg_log_inv_eq_clog, zpow_neg, le_inv_comm₀ hr (zpow_pos ..)] · exact zpow_log_le_self hb (inv_pos.mpr hr) · exact Nat.cast_pos.mpr (zero_le_one.trans_lt hb) theorem zpow_pred_clog_lt_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) : (b : R) ^ (clog b r - 1) < r := by - rw [← neg_log_inv_eq_clog, ← neg_add', zpow_neg, inv_lt _ hr] + rw [← neg_log_inv_eq_clog, ← neg_add', zpow_neg, inv_lt_comm₀ _ hr] · exact lt_zpow_succ_log_self hb _ - · exact zpow_pos_of_pos (Nat.cast_pos.mpr <| zero_le_one.trans_lt hb) _ + · exact zpow_pos (Nat.cast_pos.mpr <| zero_le_one.trans_lt hb) _ @[simp] theorem clog_zero_right (b : ℕ) : clog b (0 : R) = 0 := @@ -271,16 +269,16 @@ theorem clog_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : clog b ((b : R) ^ z : R) = theorem clog_mono_right {b : ℕ} {r₁ r₂ : R} (h₀ : 0 < r₁) (h : r₁ ≤ r₂) : clog b r₁ ≤ clog b r₂ := by rw [← neg_log_inv_eq_clog, ← neg_log_inv_eq_clog, neg_le_neg_iff] - exact log_mono_right (inv_pos.mpr <| h₀.trans_le h) (inv_le_inv_of_le h₀ h) + exact log_mono_right (inv_pos.mpr <| h₀.trans_le h) (inv_anti₀ h₀ h) variable (R) /-- Over suitable subtypes, `Int.clog` and `zpow` form a galois insertion -/ def clogZPowGi {b : ℕ} (hb : 1 < b) : GaloisInsertion (fun r : Set.Ioi (0 : R) => Int.clog b (r : R)) fun z : ℤ => - ⟨(b : R) ^ z, zpow_pos_of_pos (mod_cast zero_lt_one.trans hb) z⟩ := + ⟨(b : R) ^ z, zpow_pos (mod_cast zero_lt_one.trans hb) z⟩ := GaloisInsertion.monotoneIntro - (fun _ _ hz => Subtype.coe_le_coe.mp <| (zpow_strictMono <| mod_cast hb).monotone hz) + (fun _ _ hz => Subtype.coe_le_coe.mp <| (zpow_right_strictMono₀ <| mod_cast hb).monotone hz) (fun r₁ _ => clog_mono_right r₁.2) (fun _ => Subtype.coe_le_coe.mp <| self_le_zpow_clog hb _) fun _ => clog_zpow (R := R) hb _ diff --git a/Mathlib/Data/Int/NatPrime.lean b/Mathlib/Data/Int/NatPrime.lean index f1cbf001f3416..ee1e51f543988 100644 --- a/Mathlib/Data/Int/NatPrime.lean +++ b/Mathlib/Data/Int/NatPrime.lean @@ -3,6 +3,7 @@ Copyright (c) 2020 Bryan Gin-ge Chen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kevin Lacker, Bryan Gin-ge Chen -/ +import Mathlib.Algebra.Group.Int import Mathlib.Data.Nat.Prime.Basic /-! diff --git a/Mathlib/Data/Int/Order/Lemmas.lean b/Mathlib/Data/Int/Order/Lemmas.lean index d664a5b284aca..3e9566c7910ff 100644 --- a/Mathlib/Data/Int/Order/Lemmas.lean +++ b/Mathlib/Data/Int/Order/Lemmas.lean @@ -19,9 +19,6 @@ namespace Int /-! ### nat abs -/ - -variable {a b : ℤ} {n : ℕ} - theorem natAbs_eq_iff_mul_self_eq {a b : ℤ} : a.natAbs = b.natAbs ↔ a * a = b * b := by rw [← abs_eq_iff_mul_self_eq, abs_eq_natAbs, abs_eq_natAbs] exact Int.natCast_inj.symm diff --git a/Mathlib/Data/Int/WithZero.lean b/Mathlib/Data/Int/WithZero.lean index 3cf41e5f88e38..782b0c9336573 100644 --- a/Mathlib/Data/Int/WithZero.lean +++ b/Mathlib/Data/Int/WithZero.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 María Inés de Frutos-Fernández, Filippo A. E. Nuccio. All Released under Apache 2.0 license as described in the file LICENSE. Authors: María Inés de Frutos-Fernández, Filippo A. E. Nuccio -/ -import Mathlib.Data.NNReal.Basic +import Mathlib.Data.NNReal.Defs /-! # WithZero @@ -82,9 +82,9 @@ theorem toNNReal_strictMono {e : NNReal} (he : 1 < e) : simp only [toNNReal, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk] split_ifs with hx hy hy · simp only [hy, not_lt_zero'] at hxy - · exact NNReal.zpow_pos (ne_zero_of_lt he) _ + · exact zpow_pos he.bot_lt _ · simp only [hy, not_lt_zero'] at hxy - · rw [zpow_lt_iff_lt he, Multiplicative.toAdd_lt, ← WithZero.coe_lt_coe, WithZero.coe_unzero hx, + · rw [zpow_lt_zpow_iff_right₀ he, Multiplicative.toAdd_lt, ← coe_lt_coe, coe_unzero hx, WithZero.coe_unzero hy] exact hxy diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index d3d29ac80d33d..efee2daa93ea1 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -261,8 +261,7 @@ theorem reverse_cons' (a : α) (l : List α) : reverse (a :: l) = concat (revers theorem reverse_concat' (l : List α) (a : α) : (l ++ [a]).reverse = a :: l.reverse := by rw [reverse_append]; rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem reverse_singleton (a : α) : reverse [a] = [a] := rfl @@ -287,10 +286,6 @@ theorem map_reverseAux (f : α → β) (l₁ l₂ : List α) : map f (reverseAux l₁ l₂) = reverseAux (map f l₁) (map f l₂) := by simp only [reverseAux_eq, map_append, map_reverse] -/-! ### empty -/ - -@[deprecated (since := "2024-08-15")] alias isEmpty_iff_eq_nil := isEmpty_iff - /-! ### getLast -/ attribute [simp] getLast_cons @@ -312,15 +307,14 @@ theorem getLast_concat' {a : α} (l : List α) : getLast (concat l a) (concat_ne @[simp] theorem getLast_singleton' (a : α) : getLast [a] (cons_ne_nil a []) = a := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem getLast_cons_cons (a₁ a₂ : α) (l : List α) : getLast (a₁ :: a₂ :: l) (cons_ne_nil _ _) = getLast (a₂ :: l) (cons_ne_nil a₂ l) := rfl theorem dropLast_append_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l | [], h => absurd rfl h - | [a], h => rfl + | [_], _ => rfl | a :: b :: l, h => by rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)] congr @@ -385,16 +379,16 @@ theorem dropLast_append_getLast? : ∀ {l : List α}, ∀ a ∈ l.getLast?, drop theorem getLastI_eq_getLast? [Inhabited α] : ∀ l : List α, l.getLastI = l.getLast?.iget | [] => by simp [getLastI, Inhabited.default] - | [a] => rfl - | [a, b] => rfl - | [a, b, c] => rfl + | [_] => rfl + | [_, _] => rfl + | [_, _, _] => rfl | _ :: _ :: c :: l => by simp [getLastI, getLastI_eq_getLast? (c :: l)] #adaptation_note /-- 2024-07-10: removed `@[simp]` since the LHS simplifies using the simp set. -/ theorem getLast?_append_cons : ∀ (l₁ : List α) (a : α) (l₂ : List α), getLast? (l₁ ++ a :: l₂) = getLast? (a :: l₂) - | [], a, l₂ => rfl - | [b], a, l₂ => rfl + | [], _, _ => rfl + | [_], _, _ => rfl | b :: c :: l₁, a, l₂ => by rw [cons_append, cons_append, getLast?_cons_cons, ← cons_append, getLast?_append_cons (c :: l₁)] @@ -472,7 +466,7 @@ theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? l → a :: tai theorem head!_mem_head? [Inhabited α] : ∀ {l : List α}, l ≠ [] → head! l ∈ head? l | [], h => by contradiction - | a :: l, _ => rfl + | _ :: _, _ => rfl theorem cons_head!_tail [Inhabited α] {l : List α} (h : l ≠ []) : head! l :: tail l = l := cons_head?_tail (head!_mem_head? h) @@ -509,9 +503,6 @@ theorem get_cons {l : List α} {a : α} {n} (hl) : l.get ⟨n - 1, by contrapose! hl; rw [length_cons]; omega⟩ := getElem_cons hl -theorem modifyHead_modifyHead (l : List α) (f g : α → α) : - (l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> simp - /-! ### Induction from the right -/ /-- Induction principle from the right for lists: if a property holds for the empty list, and @@ -844,33 +835,43 @@ theorem eq_cons_of_length_one {l : List α} (h : l.length = 1) : l = [l.get ⟨0 end deprecated -theorem modifyNthTail_modifyNthTail {f g : List α → List α} (m : ℕ) : +theorem modifyTailIdx_modifyTailIdx {f g : List α → List α} (m : ℕ) : ∀ (n) (l : List α), - (l.modifyNthTail f n).modifyNthTail g (m + n) = - l.modifyNthTail (fun l => (f l).modifyNthTail g m) n + (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) (modifyNthTail_modifyNthTail m n l) + | 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 modifyNthTail_modifyNthTail_le {f g : List α → List α} (m n : ℕ) (l : List α) +theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : ℕ) (l : List α) (h : n ≤ m) : - (l.modifyNthTail f n).modifyNthTail g m = - l.modifyNthTail (fun l => (f l).modifyNthTail g (m - n)) n := by + (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, modifyNthTail_modifyNthTail, Nat.add_sub_cancel] + rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel] -theorem modifyNthTail_modifyNthTail_same {f g : List α → List α} (n : ℕ) (l : List α) : - (l.modifyNthTail f n).modifyNthTail g n = l.modifyNthTail (g ∘ f) n := by - rw [modifyNthTail_modifyNthTail_le n n l (le_refl n), Nat.sub_self]; rfl +@[deprecated (since := "2024-10-21")] +alias modifyNthTail_modifyNthTail_le := modifyTailIdx_modifyTailIdx_le -@[deprecated (since := "2024-05-04")] alias removeNth_eq_nthTail := eraseIdx_eq_modifyNthTail +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 -theorem modifyNth_eq_set (f : α → α) : - ∀ (n) (l : List α), modifyNth f n l = ((fun a => set l n (f a)) <$> l[n]?).getD l +@[deprecated (since := "2024-10-21")] +alias modifyNthTail_modifyNthTail_same := modifyTailIdx_modifyTailIdx_same +@[deprecated (since := "2024-05-04")] alias removeNth_eq_nthTail := eraseIdx_eq_modifyTailIdx + +theorem modify_eq_set (f : α → α) : + ∀ (n) (l : List α), modify f n l = ((fun a => set l n (f a)) <$> l[n]?).getD l | 0, l => by cases l <;> simp - | n + 1, [] => rfl + | _ + 1, [] => rfl | n + 1, b :: l => - (congr_arg (cons b) (modifyNth_eq_set f n l)).trans <| by cases h : l[n]? <;> simp [h] + (congr_arg (cons b) (modify_eq_set f n l)).trans <| by cases h : l[n]? <;> simp [h] + +@[deprecated (since := "2024-10-21")] alias modifyNth_eq_set := modify_eq_set @[simp] theorem getElem_set_of_ne {l : List α} {i j : ℕ} (h : i ≠ j) (a : α) @@ -887,6 +888,11 @@ theorem get_set_of_ne {l : List α} {i j : ℕ} (h : i ≠ j) (a : α) /-! ### map -/ +-- `List.map_const` (the version with `Function.const` instead of a lambda) is already tagged +-- `simp` in Core +-- TODO: Upstream the tagging to Core? +attribute [simp] map_const' + @[deprecated (since := "2024-06-21")] alias map_congr := map_congr_left theorem bind_pure_eq_map (f : α → β) (l : List α) : l.bind (pure ∘ f) = map f l := @@ -996,8 +1002,8 @@ theorem zipWith_nil (f : α → β → γ) (l : List α) : zipWith f l [] = [] : @[simp] theorem zipWith_flip (f : α → β → γ) : ∀ as bs, zipWith (flip f) bs as = zipWith f as bs | [], [] => rfl - | [], b :: bs => rfl - | a :: as, [] => rfl + | [], _ :: _ => rfl + | _ :: _, [] => rfl | a :: as, b :: bs => by simp! [zipWith_flip] rfl @@ -1105,8 +1111,6 @@ theorem foldl_fixed {a : α} : ∀ l : List β, foldl (fun a _ => a) a l = a := theorem foldr_fixed {b : β} : ∀ l : List α, foldr (fun _ b => b) b l = b := foldr_fixed' fun _ => rfl --- Porting note (#10618): simp can prove this --- @[simp] theorem foldr_eta : ∀ l : List α, foldr cons [] l = l := by simp only [foldr_cons_eq_append, append_nil, forall_const] @@ -1155,7 +1159,7 @@ section Scanl variable {f : β → α → β} {b : β} {a : α} {l : List α} theorem length_scanl : ∀ a l, length (scanl f a l) = l.length + 1 - | a, [] => rfl + | _, [] => rfl | a, x :: l => by rw [scanl, length_cons, length_cons, ← succ_eq_add_one, congr_arg succ] exact length_scanl _ _ @@ -1246,7 +1250,7 @@ variable {f : α → α → α} theorem foldl1_eq_foldr1 [hassoc : Std.Associative f] : ∀ a b l, foldl f a (l ++ [b]) = foldr f b (a :: l) - | a, b, nil => rfl + | _, _, nil => rfl | a, b, c :: l => by simp only [cons_append, foldl_cons, foldr_cons, foldl1_eq_foldr1 _ _ l] rw [hassoc.assoc] @@ -1261,7 +1265,7 @@ theorem foldl_eq_of_comm_of_assoc [hcomm : Std.Commutative f] [hassoc : Std.Asso theorem foldl_eq_foldr [Std.Commutative f] [Std.Associative f] : ∀ a l, foldl f a l = foldr f a l - | a, nil => rfl + | _, nil => rfl | a, b :: l => by simp only [foldr_cons, foldl_eq_of_comm_of_assoc] rw [foldl_eq_foldr a l] @@ -1276,11 +1280,11 @@ variable (hf : ∀ a b c, f (f a b) c = f (f a c) b) include hf theorem foldl_eq_of_comm' : ∀ a b l, foldl f a (b :: l) = f (foldl f a l) b - | a, b, [] => rfl + | _, _, [] => rfl | a, b, c :: l => by rw [foldl, foldl, foldl, ← foldl_eq_of_comm' .., foldl, hf] theorem foldl_eq_foldr' : ∀ a l, foldl f a l = foldr (flip f) a l - | a, [] => rfl + | _, [] => rfl | a, b :: l => by rw [foldl_eq_of_comm' hf, foldr, foldl_eq_foldr' ..]; rfl end FoldlEqFoldlr' @@ -1291,7 +1295,7 @@ variable {f : α → β → β} theorem foldr_eq_of_comm' (hf : ∀ a b c, f a (f b c) = f b (f a c)) : ∀ a b l, foldr f a (b :: l) = foldr f (f b a) l - | a, b, [] => rfl + | _, _, [] => rfl | a, b, c :: l => by rw [foldr, foldr, foldr, hf, ← foldr_eq_of_comm' hf ..]; rfl end FoldlEqFoldlr' @@ -1308,7 +1312,7 @@ local notation l " <*> " a => foldl op a l theorem foldl_op_eq_op_foldr_assoc : ∀ {l : List α} {a₁ a₂}, ((l <*> a₁) ⋆ a₂) = a₁ ⋆ l.foldr (· ⋆ ·) a₂ - | [], a₁, a₂ => rfl + | [], _, _ => rfl | a :: l, a₁, a₂ => by simp only [foldl_cons, foldr_cons, foldl_assoc, ha.assoc]; rw [foldl_op_eq_op_foldr_assoc] @@ -1718,7 +1722,7 @@ lemma map_filter' {f : α → β} (hf : Injective f) (l : List α) lemma filter_attach' (l : List α) (p : {a // a ∈ l} → Bool) [DecidableEq α] : l.attach.filter p = - (l.filter fun x => ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun x => mem_of_mem_filter) := by + (l.filter fun x => ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun _ => mem_of_mem_filter) := by classical refine map_injective_iff.2 Subtype.coe_injective ?_ simp [comp_def, map_filter' _ Subtype.coe_injective] @@ -1726,7 +1730,7 @@ lemma filter_attach' (l : List α) (p : {a // a ∈ l} → Bool) [DecidableEq α -- Porting note: `Lean.Internal.coeM` forces us to type-ascript `{x // x ∈ l}` lemma filter_attach (l : List α) (p : α → Bool) : (l.attach.filter fun x => p x : List {x // x ∈ l}) = - (l.filter p).attach.map (Subtype.map id fun x => mem_of_mem_filter) := + (l.filter p).attach.map (Subtype.map id fun _ => mem_of_mem_filter) := map_injective_iff.2 Subtype.coe_injective <| by simp_rw [map_map, comp_def, Subtype.map, id, ← Function.comp_apply (g := Subtype.val), ← filter_map, attach_map_subtype_val] @@ -1889,7 +1893,7 @@ theorem map_diff [DecidableEq β] {f : α → β} (finj : Injective f) {l₁ l theorem erase_diff_erase_sublist_of_sublist {a : α} : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → (l₂.erase a).diff (l₁.erase a) <+ l₂.diff l₁ - | [], l₂, _ => erase_sublist _ _ + | [], _, _ => erase_sublist _ _ | b :: l₁, l₂, h => if heq : b = a then by simp only [heq, erase_cons_head, diff_cons]; rfl else by @@ -1941,8 +1945,7 @@ theorem map₂Right'_nil_left : map₂Right' f [] bs = (bs.map (f none), []) := theorem map₂Right'_nil_right : map₂Right' f as [] = ([], as) := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem map₂Right'_nil_cons : map₂Right' f [] (b :: bs) = (f none b :: bs.map (f none), []) := rfl @@ -1969,8 +1972,7 @@ theorem zipLeft'_nil_right : zipLeft' as ([] : List β) = (as.map fun a => (a, n theorem zipLeft'_nil_left : zipLeft' ([] : List α) bs = ([], bs) := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem zipLeft'_cons_nil : zipLeft' (a :: as) ([] : List β) = ((a, none) :: as.map fun a => (a, none), []) := rfl @@ -1998,8 +2000,7 @@ theorem zipRight'_nil_left : zipRight' ([] : List α) bs = (bs.map fun b => (non theorem zipRight'_nil_right : zipRight' as ([] : List β) = ([], as) := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem zipRight'_nil_cons : zipRight' ([] : List α) (b :: bs) = ((none, b) :: bs.map fun b => (none, b), []) := rfl @@ -2054,8 +2055,7 @@ theorem map₂Right_nil_left : map₂Right f [] bs = bs.map (f none) := by cases theorem map₂Right_nil_right : map₂Right f as [] = [] := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem map₂Right_nil_cons : map₂Right f [] (b :: bs) = f none b :: bs.map (f none) := rfl @@ -2088,8 +2088,7 @@ theorem zipLeft_nil_right : zipLeft as ([] : List β) = as.map fun a => (a, none theorem zipLeft_nil_left : zipLeft ([] : List α) bs = [] := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem zipLeft_cons_nil : zipLeft (a :: as) ([] : List β) = (a, none) :: as.map fun a => (a, none) := rfl @@ -2126,8 +2125,7 @@ theorem zipRight_nil_left : zipRight ([] : List α) bs = bs.map fun b => (none, theorem zipRight_nil_right : zipRight as ([] : List β) = [] := rfl --- Porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem zipRight_nil_cons : zipRight ([] : List α) (b :: bs) = (none, b) :: bs.map fun b => (none, b) := rfl @@ -2285,4 +2283,4 @@ end lookup end List -set_option linter.style.longFile 2700 +set_option linter.style.longFile 2400 diff --git a/Mathlib/Data/List/Chain.lean b/Mathlib/Data/List/Chain.lean index 965aee596b838..8b844a1f6243c 100644 --- a/Mathlib/Data/List/Chain.lean +++ b/Mathlib/Data/List/Chain.lean @@ -42,7 +42,7 @@ theorem Chain.iff_mem {a : α} {l : List α} : constructor · exact ⟨mem_cons_self _ _, mem_cons_self _ _, r⟩ · exact IH.imp fun a b ⟨am, bm, h⟩ => ⟨mem_cons_of_mem _ am, mem_cons_of_mem _ bm, h⟩, - Chain.imp fun a b h => h.2.2⟩ + Chain.imp fun _ _ h => h.2.2⟩ theorem chain_singleton {a b : α} : Chain R a [b] ↔ R a b := by simp only [chain_cons, Chain.nil, and_true] @@ -95,7 +95,7 @@ theorem chain_of_chain_pmap {S : β → β → Prop} {p : α → Prop} (f : ∀ protected theorem Chain.pairwise [IsTrans α R] : ∀ {a : α} {l : List α}, Chain R a l → Pairwise R (a :: l) - | a, [], Chain.nil => pairwise_singleton _ _ + | _, [], Chain.nil => pairwise_singleton _ _ | a, _, @Chain.cons _ _ _ b l h hb => hb.pairwise.cons (by @@ -178,10 +178,10 @@ theorem chain'_cons {x y l} : Chain' R (x :: y :: l) ↔ R x y ∧ Chain' R (y : theorem chain'_isInfix : ∀ l : List α, Chain' (fun x y => [x, y] <:+: l) l | [] => chain'_nil - | [a] => chain'_singleton _ + | [_] => chain'_singleton _ | a :: b :: l => chain'_cons.2 - ⟨⟨[], l, by simp⟩, (chain'_isInfix (b :: l)).imp fun x y h => h.trans ⟨[a], [], by simp⟩⟩ + ⟨⟨[], l, by simp⟩, (chain'_isInfix (b :: l)).imp fun _ _ h => h.trans ⟨[a], [], by simp⟩⟩ theorem chain'_split {a : α} : ∀ {l₁ l₂ : List α}, Chain' R (l₁ ++ a :: l₂) ↔ Chain' R (l₁ ++ [a]) ∧ Chain' R (a :: l₂) @@ -319,6 +319,26 @@ lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L → simp only [forall_mem_cons, and_assoc, join, head?_append_of_ne_nil _ hL.2.1.symm] exact Iff.rfl.and (Iff.rfl.and <| Iff.rfl.and and_comm) +theorem chain'_attachWith {l : List α} {p : α → Prop} (h : ∀ x ∈ l, p x) + {r : {a // p a} → {a // p a} → Prop} : + (l.attachWith p h).Chain' r ↔ l.Chain' fun a b ↦ ∃ ha hb, r ⟨a, ha⟩ ⟨b, hb⟩ := by + induction l with + | nil => rfl + | cons a l IH => + rw [attachWith_cons, chain'_cons', chain'_cons', IH, and_congr_left] + simp_rw [head?_attachWith] + intros + constructor <;> + intro hc b (hb : _ = _) + · simp_rw [hb, Option.pbind_some] at hc + have hb' := h b (mem_cons_of_mem a (mem_of_mem_head? hb)) + exact ⟨h a (mem_cons_self a l), hb', hc ⟨b, hb'⟩ rfl⟩ + · cases l <;> aesop + +theorem chain'_attach {l : List α} {r : {a // a ∈ l} → {a // a ∈ l} → Prop} : + l.attach.Chain' r ↔ l.Chain' fun a b ↦ ∃ ha hb, r ⟨a, ha⟩ ⟨b, hb⟩ := + chain'_attachWith fun _ ↦ id + /-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an `r`-chain starting from `a` and ending on `b`. The converse of `relationReflTransGen_of_exists_chain`. diff --git a/Mathlib/Data/List/Count.lean b/Mathlib/Data/List/Count.lean index 89475cec9fe1e..13c127b563b2a 100644 --- a/Mathlib/Data/List/Count.lean +++ b/Mathlib/Data/List/Count.lean @@ -10,8 +10,7 @@ import Mathlib.Tactic.Common # Counting in lists This file proves basic properties of `List.countP` and `List.count`, which count the number of -elements of a list satisfying a predicate and equal to a given element respectively. Their -definitions can be found in `Batteries.Data.List.Basic`. +elements of a list satisfying a predicate and equal to a given element respectively. -/ assert_not_exists Set.range diff --git a/Mathlib/Data/List/Cycle.lean b/Mathlib/Data/List/Cycle.lean index 9c8cbaa143209..2f3c103975e43 100644 --- a/Mathlib/Data/List/Cycle.lean +++ b/Mathlib/Data/List/Cycle.lean @@ -196,7 +196,6 @@ theorem prev_getLast_cons (h : x ∈ x :: l) : theorem prev_cons_cons_eq' (y z : α) (h : x ∈ y :: z :: l) (hx : x = y) : prev (y :: z :: l) x h = getLast (z :: l) (cons_ne_nil _ _) := by rw [prev, dif_pos hx] ---@[simp] Porting note (#10618): `simp` can prove it theorem prev_cons_cons_eq (z : α) (h : x ∈ x :: z :: l) : prev (x :: z :: l) x h = getLast (z :: l) (cons_ne_nil _ _) := prev_cons_cons_eq' l x x z h rfl @@ -812,7 +811,6 @@ theorem chain_coe_cons (r : α → α → Prop) (a : α) (l : List α) : Chain r (a :: l) ↔ List.Chain r a (l ++ [a]) := Iff.rfl ---@[simp] Porting note (#10618): `simp` can prove it theorem chain_singleton (r : α → α → Prop) (a : α) : Chain r [a] ↔ r a a := by rw [chain_coe_cons, nil_append, List.chain_singleton] @@ -824,11 +822,11 @@ theorem chain_ne_nil (r : α → α → Prop) {l : List α} : theorem chain_map {β : Type*} {r : α → α → Prop} (f : β → α) {s : Cycle β} : Chain r (s.map f) ↔ Chain (fun a b => r (f a) (f b)) s := - Quotient.inductionOn' s fun l => by + Quotient.inductionOn s fun l => by cases' l with a l · rfl - dsimp only [Chain, ← mk''_eq_coe, Quotient.liftOn'_mk'', Cycle.map, Quotient.map', Quot.map, - Quotient.mk'', Quotient.liftOn', Quotient.liftOn, Quot.liftOn_mk, List.map] + dsimp only [Chain, Quotient.liftOn_mk, Cycle.map, Quotient.map', Quot.map, + Quotient.liftOn', Quotient.liftOn, Quot.liftOn_mk, List.map] rw [← concat_eq_append, ← List.map_concat, List.chain_map f] simp diff --git a/Mathlib/Data/List/Dedup.lean b/Mathlib/Data/List/Dedup.lean index 55576850f682a..2c282a581e0bd 100644 --- a/Mathlib/Data/List/Dedup.lean +++ b/Mathlib/Data/List/Dedup.lean @@ -160,4 +160,11 @@ theorem replicate_dedup {x : α} : ∀ {k}, k ≠ 0 → (replicate k x).dedup = theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1 else 0 := by simp_rw [count_eq_of_nodup <| nodup_dedup l, mem_dedup] +theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup l₂ := + perm_iff_count.2 fun a => + if h : a ∈ l₁ then by + simp [h, nodup_dedup, p.subset h] + else by + simp [h, count_eq_zero_of_not_mem, mt p.mem_iff.2] + end List diff --git a/Mathlib/Data/List/Defs.lean b/Mathlib/Data/List/Defs.lean index f0aad1fcd0f00..fed56f7a1c26f 100644 --- a/Mathlib/Data/List/Defs.lean +++ b/Mathlib/Data/List/Defs.lean @@ -488,6 +488,10 @@ theorem length_mapAccumr₂ : end MapAccumr +/-- All elements of `Fin n`, from `0` to `n-1`. The corresponding finset is `Finset.univ`. -/ +def finRange (n : ℕ) : List (Fin n) := + (range n).pmap Fin.mk fun _ => List.mem_range.1 + section Deprecated @[deprecated List.mem_cons (since := "2024-08-10")] diff --git a/Mathlib/Data/List/Destutter.lean b/Mathlib/Data/List/Destutter.lean index 5f80cabc72631..df3a1ad3b5778 100644 --- a/Mathlib/Data/List/Destutter.lean +++ b/Mathlib/Data/List/Destutter.lean @@ -71,7 +71,7 @@ theorem mem_destutter' (a) : a ∈ l.destutter' R a := by · assumption theorem destutter'_is_chain : ∀ l : List α, ∀ {a b}, R a b → (l.destutter' R b).Chain R a - | [], a, b, h => chain_singleton.mpr h + | [], _, _, h => chain_singleton.mpr h | c :: l, a, b, h => by rw [destutter'] split_ifs with hbc diff --git a/Mathlib/Data/List/Enum.lean b/Mathlib/Data/List/Enum.lean index d4b73fc6bec78..a574ea756a233 100644 --- a/Mathlib/Data/List/Enum.lean +++ b/Mathlib/Data/List/Enum.lean @@ -19,7 +19,7 @@ Any downstream users who can not easily adapt may remove the deprecations as nee namespace List -variable {α β : Type*} +variable {α : Type*} @[deprecated getElem?_enumFrom (since := "2024-08-15")] theorem get?_enumFrom (n) (l : List α) (m) : diff --git a/Mathlib/Data/List/Forall2.lean b/Mathlib/Data/List/Forall2.lean index 20808976c60ab..79f5bf6c1cb0a 100644 --- a/Mathlib/Data/List/Forall2.lean +++ b/Mathlib/Data/List/Forall2.lean @@ -84,18 +84,14 @@ theorem forall₂_cons_right_iff {b l u} : match u, h with | _, ⟨_, _, h₁, h₂, rfl⟩ => Forall₂.cons h₁ h₂ -#adaptation_note -/-- -After nightly-2024-09-06 we can remove the `_root_` prefixes below. --/ theorem forall₂_and_left {p : α → Prop} : ∀ l u, Forall₂ (fun a b => p a ∧ R a b) l u ↔ (∀ a ∈ l, p a) ∧ Forall₂ R l u | [], u => by simp only [forall₂_nil_left_iff, forall_prop_of_false (not_mem_nil _), imp_true_iff, true_and] | a :: l, u => by - simp only [forall₂_and_left l, forall₂_cons_left_iff, forall_mem_cons, _root_.and_assoc, + simp only [forall₂_and_left l, forall₂_cons_left_iff, forall_mem_cons, and_assoc, @and_comm _ (p a), @and_left_comm _ (p a), exists_and_left] - simp only [_root_.and_comm, _root_.and_assoc, and_left_comm, ← exists_and_right] + simp only [and_comm, and_assoc, and_left_comm, ← exists_and_right] @[simp] theorem forall₂_map_left_iff {f : γ → α} : diff --git a/Mathlib/Data/List/GetD.lean b/Mathlib/Data/List/GetD.lean index e16ce04be7e33..33af5b90cdb00 100644 --- a/Mathlib/Data/List/GetD.lean +++ b/Mathlib/Data/List/GetD.lean @@ -129,6 +129,9 @@ theorem getI_append_right (l l' : List α) (n : ℕ) (h : l.length ≤ n) : theorem getI_eq_iget_get? (n : ℕ) : l.getI n = (l.get? n).iget := by rw [← getD_default_eq_getI, getD_eq_getD_get?, Option.getD_default_eq_iget] +theorem getI_eq_iget_getElem? (n : ℕ) : l.getI n = l[n]?.iget := by + rw [← getD_default_eq_getI, getD_eq_getElem?_getD, Option.getD_default_eq_iget] + theorem getI_zero_eq_headI : l.getI 0 = l.headI := by cases l <;> rfl end getI diff --git a/Mathlib/Data/List/GroupBy.lean b/Mathlib/Data/List/GroupBy.lean new file mode 100644 index 0000000000000..6449cb7da1b97 --- /dev/null +++ b/Mathlib/Data/List/GroupBy.lean @@ -0,0 +1,142 @@ +/- +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.List.Chain + +/-! +# Group consecutive elements in a list by a relation + +This file provides the basic API for `List.groupBy` which is defined in Core. +The main results are the following: + +- `List.join_groupBy`: the lists in `List.groupBy` join to the original list. +- `List.nil_not_mem_groupBy`: the empty list is not contained in `List.groupBy`. +- `List.chain'_of_mem_groupBy`: any two adjacent elements in a list in `List.groupBy` are related by + the specified relation. +- `List.chain'_getLast_head_groupBy`: the last element of each list in `List.groupBy` is not + related to the first element of the next list. +-/ + +namespace List + +variable {α : Type*} {m : List α} + +@[simp] +theorem groupBy_nil (r : α → α → Bool) : groupBy r [] = [] := + rfl + +private theorem groupByLoop_eq_append {r : α → α → Bool} {l : List α} {a : α} {g : List α} + (gs : List (List α)) : groupBy.loop r l a g gs = gs.reverse ++ groupBy.loop r l a g [] := by + induction l generalizing a g gs with + | nil => simp [groupBy.loop] + | cons b l IH => + simp_rw [groupBy.loop] + split <;> rw [IH] + conv_rhs => rw [IH] + simp + +private theorem join_groupByLoop {r : α → α → Bool} {l : List α} {a : α} {g : List α} : + (groupBy.loop r l a g []).join = g.reverse ++ a :: l := by + induction l generalizing a g with + | nil => simp [groupBy.loop] + | cons b l IH => + rw [groupBy.loop, groupByLoop_eq_append [_]] + split <;> simp [IH] + +@[simp] +theorem join_groupBy (r : α → α → Bool) (l : List α) : (l.groupBy r).join = l := + match l with + | nil => rfl + | cons _ _ => join_groupByLoop + +private theorem nil_not_mem_groupByLoop {r : α → α → Bool} {l : List α} {a : α} {g : List α} : + [] ∉ groupBy.loop r l a g [] := by + induction l generalizing a g with + | nil => + simp [groupBy.loop] + | cons b l IH => + rw [groupBy.loop] + split + · exact IH + · rw [groupByLoop_eq_append, mem_append] + simpa using IH + +theorem nil_not_mem_groupBy (r : α → α → Bool) (l : List α) : [] ∉ l.groupBy r := + match l with + | nil => not_mem_nil _ + | cons _ _ => nil_not_mem_groupByLoop + +theorem ne_nil_of_mem_groupBy (r : α → α → Bool) {l : List α} (h : m ∈ l.groupBy r) : m ≠ [] := by + rintro rfl + exact nil_not_mem_groupBy r l h + +private theorem chain'_of_mem_groupByLoop {r : α → α → Bool} {l : List α} {a : α} {g : List α} + (hga : ∀ b ∈ g.head?, r b a) (hg : g.Chain' fun y x ↦ r x y) + (h : m ∈ groupBy.loop r l a g []) : m.Chain' fun x y ↦ r x y := by + induction l generalizing a g with + | nil => + rw [groupBy.loop, reverse_cons, mem_append, mem_reverse, mem_singleton] at h + obtain hm | rfl := h + · exact (not_mem_nil m hm).elim + · apply List.chain'_reverse.1 + rw [reverse_reverse] + exact chain'_cons'.2 ⟨hga, hg⟩ + | cons b l IH => + simp [groupBy.loop] at h + split at h + · apply IH _ (chain'_cons'.2 ⟨hga, hg⟩) h + intro b hb + rw [head?_cons, Option.mem_some_iff] at hb + rwa [← hb] + · rw [groupByLoop_eq_append, mem_append, reverse_singleton, mem_singleton] at h + obtain rfl | hm := h + · apply List.chain'_reverse.1 + rw [reverse_append, reverse_cons, reverse_nil, nil_append, reverse_reverse] + exact chain'_cons'.2 ⟨hga, hg⟩ + · apply IH _ chain'_nil hm + rintro _ ⟨⟩ + +theorem chain'_of_mem_groupBy {r : α → α → Bool} {l : List α} (h : m ∈ l.groupBy r) : + m.Chain' fun x y ↦ r x y := by + cases l with + | nil => cases h + | cons a l => + apply chain'_of_mem_groupByLoop _ _ h + · rintro _ ⟨⟩ + · exact chain'_nil + +private theorem chain'_getLast_head_groupByLoop {r : α → α → Bool} (l : List α) {a : α} + {g : List α} {gs : List (List α)} (hgs' : [] ∉ gs) + (hgs : gs.Chain' fun b a ↦ ∃ ha hb, r (a.getLast ha) (b.head hb) = false) + (hga : ∀ m ∈ gs.head?, ∃ ha hb, r (m.getLast ha) ((g.reverse ++ [a]).head hb) = false) : + (groupBy.loop r l a g gs).Chain' fun a b ↦ ∃ ha hb, r (a.getLast ha) (b.head hb) = false := by + induction l generalizing a g gs with + | nil => + rw [groupBy.loop, reverse_cons] + apply List.chain'_reverse.1 + simpa using chain'_cons'.2 ⟨hga, hgs⟩ + | cons b l IH => + rw [groupBy.loop] + split + · apply IH hgs' hgs + intro m hm + obtain ⟨ha, _, H⟩ := hga m hm + refine ⟨ha, append_ne_nil_of_right_ne_nil _ (cons_ne_nil _ _), ?_⟩ + rwa [reverse_cons, head_append_of_ne_nil] + · apply IH + · simpa using hgs' + · rw [reverse_cons] + apply chain'_cons'.2 ⟨hga, hgs⟩ + · simpa + +theorem chain'_getLast_head_groupBy (r : α → α → Bool) (l : List α) : + (l.groupBy r).Chain' fun a b ↦ ∃ ha hb, r (a.getLast ha) (b.head hb) = false := by + cases l with + | nil => exact chain'_nil + | cons _ _ => + apply chain'_getLast_head_groupByLoop _ (not_mem_nil _) chain'_nil + rintro _ ⟨⟩ + +end List diff --git a/Mathlib/Data/List/Infix.lean b/Mathlib/Data/List/Infix.lean index a399857f66da2..030675eb9f683 100644 --- a/Mathlib/Data/List/Infix.lean +++ b/Mathlib/Data/List/Infix.lean @@ -25,11 +25,11 @@ All those (except `insert`) are defined in `Mathlib.Data.List.Defs`. * `l₁ <:+: l₂`: `l₁` is an infix of `l₂`. -/ -variable {α β : Type*} +variable {α : Type*} namespace List -variable {l l₁ l₂ l₃ : List α} {a b : α} {m n : ℕ} +variable {l l₁ l₂ : List α} {a b : α} /-! ### prefix, suffix, infix -/ @@ -70,6 +70,7 @@ theorem mem_of_mem_dropLast (h : a ∈ l.dropLast) : a ∈ l := dropLast_subset l h attribute [gcongr] Sublist.drop +attribute [refl] prefix_refl suffix_refl infix_refl theorem concat_get_prefix {x y : List α} (h : x <+: y) (hl : x.length < y.length) : x ++ [y.get ⟨x.length, hl⟩] <+: y := by diff --git a/Mathlib/Data/List/InsertIdx.lean b/Mathlib/Data/List/InsertIdx.lean new file mode 100644 index 0000000000000..7c1c61e68cdc2 --- /dev/null +++ b/Mathlib/Data/List/InsertIdx.lean @@ -0,0 +1,203 @@ +/- +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.Basic + +/-! +# insertIdx + +Proves various lemmas about `List.insertIdx`. +-/ + +assert_not_exists Set.range + +open Function + +open Nat hiding one_pos + +namespace List + +universe u + +variable {α : Type u} + +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])) : + (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])) : + (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 _ _ _ + +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])) : + (insertIdx n x l).get ⟨n + k + 1, hk⟩ = get l ⟨n + k, hk'⟩ := by + simp [getElem_insertIdx_add_succ, hk, hk'] + +set_option linter.unnecessarySimpa false in +theorem insertIdx_injective (n : ℕ) (x : α) : Function.Injective (insertIdx n x) := by + induction' n with n IH + · have : insertIdx 0 x = cons x := funext fun _ => rfl + simp [this] + · rintro (_ | ⟨a, as⟩) (_ | ⟨b, bs⟩) h <;> simpa [IH.eq_iff] using h + +@[deprecated (since := "2024-10-21")] alias insertNth_zero := insertIdx_zero +@[deprecated (since := "2024-10-21")] alias insertNth_succ_nil := insertIdx_succ_nil +@[deprecated (since := "2024-10-21")] alias insertNth_succ_cons := insertIdx_succ_cons +@[deprecated (since := "2024-10-21")] alias length_insertNth := length_insertIdx +@[deprecated (since := "2024-10-21")] alias removeNth_insertIdx := eraseIdx_insertIdx +@[deprecated (since := "2024-05-04")] alias removeNth_insertNth := eraseIdx_insertIdx +@[deprecated (since := "2024-10-21")] alias insertNth_eraseIdx_of_ge := insertIdx_eraseIdx_of_ge +@[deprecated (since := "2024-05-04")] alias insertNth_removeNth_of_ge := insertIdx_eraseIdx_of_ge +@[deprecated (since := "2024-10-21")] alias insertNth_eraseIdx_of_le := insertIdx_eraseIdx_of_le +@[deprecated (since := "2024-05-04")] alias insertIdx_removeNth_of_le := insertIdx_eraseIdx_of_le +@[deprecated (since := "2024-10-21")] alias insertNth_comm := insertIdx_comm +@[deprecated (since := "2024-10-21")] alias mem_insertNth := mem_insertIdx +@[deprecated (since := "2024-10-21")] alias insertNth_of_length_lt := insertIdx_of_length_lt +@[deprecated (since := "2024-10-21")] alias insertNth_length_self := insertIdx_length_self +@[deprecated (since := "2024-10-21")] alias length_le_length_insertNth := length_le_length_insertIdx +@[deprecated (since := "2024-10-21")] alias length_insertNth_le_succ := length_insertIdx_le_succ +@[deprecated (since := "2024-10-21")] alias getElem_insertNth_of_lt := getElem_insertIdx_of_lt +@[deprecated (since := "2024-10-21")] alias get_insertNth_of_lt := get_insertIdx_of_lt +@[deprecated (since := "2024-10-21")] alias getElem_insertNth_self := getElem_insertIdx_self +@[deprecated (since := "2024-10-21")] alias get_insertNth_self := get_insertIdx_self +@[deprecated (since := "2024-10-21")] alias getElem_insertNth_add_succ := getElem_insertIdx_add_succ +@[deprecated (since := "2024-10-21")] alias get_insertNth_add_succ := get_insertIdx_add_succ +@[deprecated (since := "2024-10-21")] alias insertNth_injective := insertIdx_injective + +end InsertIdx + +end List diff --git a/Mathlib/Data/List/InsertNth.lean b/Mathlib/Data/List/InsertNth.lean index b6b147595d8d8..48923ca75aef6 100644 --- a/Mathlib/Data/List/InsertNth.lean +++ b/Mathlib/Data/List/InsertNth.lean @@ -1,189 +1,13 @@ /- -Copyright (c) 2014 Parikshit Khanna. All rights reserved. +Copyright (c) 2024 Lean FRO. 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 +Authors: Kim Morrison -/ -import Mathlib.Data.List.Basic +import Mathlib.Data.List.InsertIdx /-! -# insertNth +This is a stub file for importing `Mathlib.Data.List.InsertNth`, +which has been renamed to `Mathlib.Data.List.InsertIdx`. -Proves various lemmas about `List.insertNth`. +This file can be removed once the deprecation for `List.insertNth` is removed. -/ - -assert_not_exists Set.range - -open Function - -open Nat hiding one_pos - -namespace List - -universe u v w - -variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : List α} - -section InsertNth - -variable {a : α} - -@[simp] -theorem insertNth_zero (s : List α) (x : α) : insertNth 0 x s = x :: s := - rfl - -@[simp] -theorem insertNth_succ_nil (n : ℕ) (a : α) : insertNth (n + 1) a [] = [] := - rfl - -@[simp] -theorem insertNth_succ_cons (s : List α) (hd x : α) (n : ℕ) : - insertNth (n + 1) x (hd :: s) = hd :: insertNth n x s := - rfl - -theorem length_insertNth : ∀ n as, n ≤ length as → length (insertNth 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_insertNth n as (Nat.le_of_succ_le_succ h) - -theorem eraseIdx_insertNth (n : ℕ) (l : List α) : (l.insertNth n a).eraseIdx n = l := by - rw [eraseIdx_eq_modifyNthTail, insertNth, modifyNthTail_modifyNthTail_same] - exact modifyNthTail_id _ _ - -@[deprecated (since := "2024-05-04")] alias removeNth_insertNth := eraseIdx_insertNth - -theorem insertNth_eraseIdx_of_ge : - ∀ n m as, - n < length as → n ≤ m → insertNth m a (as.eraseIdx n) = (as.insertNth (m + 1) a).eraseIdx n - | 0, 0, [], has, _ => (lt_irrefl _ has).elim - | 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertNth] - | 0, m + 1, a :: as, _, _ => rfl - | n + 1, m + 1, a :: as, has, hmn => - congr_arg (cons a) <| - insertNth_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn) - -@[deprecated (since := "2024-05-04")] alias insertNth_removeNth_of_ge := insertNth_eraseIdx_of_ge - -theorem insertNth_eraseIdx_of_le : - ∀ n m as, - n < length as → m ≤ n → insertNth m a (as.eraseIdx n) = (as.insertNth m a).eraseIdx (n + 1) - | _, 0, _ :: _, _, _ => rfl - | n + 1, m + 1, a :: as, has, hmn => - congr_arg (cons a) <| - insertNth_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn) - -@[deprecated (since := "2024-05-04")] alias insertNth_removeNth_of_le := insertNth_eraseIdx_of_le - -theorem insertNth_comm (a b : α) : - ∀ (i j : ℕ) (l : List α) (_ : i ≤ j) (_ : j ≤ length l), - (l.insertNth i a).insertNth (j + 1) b = (l.insertNth j b).insertNth i a - | 0, j, l => by simp [insertNth] - | i + 1, 0, l => 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 [insertNth_succ_cons, cons.injEq, true_and] - exact insertNth_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁) - -#adaptation_note -/-- -After nightly-2024-09-06 we can remove the `_root_` prefixes below. --/ -theorem mem_insertNth {a b : α} : - ∀ {n : ℕ} {l : List α} (_ : n ≤ l.length), a ∈ l.insertNth n b ↔ a = b ∨ a ∈ l - | 0, as, _ => by simp - | n + 1, [], h => (Nat.not_succ_le_zero _ h).elim - | n + 1, a' :: as, h => by - rw [List.insertNth_succ_cons, mem_cons, mem_insertNth (Nat.le_of_succ_le_succ h), - ← _root_.or_assoc, @or_comm (a = a'), _root_.or_assoc, mem_cons] - -theorem insertNth_of_length_lt (l : List α) (x : α) (n : ℕ) (h : l.length < n) : - insertNth 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 insertNth_length_self (l : List α) (x : α) : insertNth l.length x l = l ++ [x] := by - induction' l with hd tl IH - · simp - · simpa using IH - -theorem length_le_length_insertNth (l : List α) (x : α) (n : ℕ) : - l.length ≤ (insertNth n x l).length := by - rcases le_or_lt n l.length with hn | hn - · rw [length_insertNth _ _ hn] - exact (Nat.lt_succ_self _).le - · rw [insertNth_of_length_lt _ _ _ hn] - -theorem length_insertNth_le_succ (l : List α) (x : α) (n : ℕ) : - (insertNth n x l).length ≤ l.length + 1 := by - rcases le_or_lt n l.length with hn | hn - · rw [length_insertNth _ _ hn] - · rw [insertNth_of_length_lt _ _ _ hn] - exact (Nat.lt_succ_self _).le - -theorem getElem_insertNth_of_lt (l : List α) (x : α) (n k : ℕ) (hn : k < n) (hk : k < l.length) - (hk' : k < (insertNth n x l).length := hk.trans_le (length_le_length_insertNth _ _ _)) : - (insertNth 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_insertNth_of_lt (l : List α) (x : α) (n k : ℕ) (hn : k < n) (hk : k < l.length) - (hk' : k < (insertNth n x l).length := hk.trans_le (length_le_length_insertNth _ _ _)) : - (insertNth n x l).get ⟨k, hk'⟩ = l.get ⟨k, hk⟩ := by - simp_all [getElem_insertNth_of_lt] - -@[simp] -theorem getElem_insertNth_self (l : List α) (x : α) (n : ℕ) (hn : n ≤ l.length) - (hn' : n < (insertNth n x l).length := (by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff])) : - (insertNth n x l)[n] = x := by - induction' l with hd tl IH generalizing n - · simp only [length] at hn - cases hn - simp only [insertNth_zero, getElem_singleton] - · cases n - · simp - · simp only [Nat.succ_le_succ_iff, length] at hn - simpa using IH _ hn - -theorem get_insertNth_self (l : List α) (x : α) (n : ℕ) (hn : n ≤ l.length) - (hn' : n < (insertNth n x l).length := (by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff])) : - (insertNth n x l).get ⟨n, hn'⟩ = x := by - simp [hn, hn'] - -theorem getElem_insertNth_add_succ (l : List α) (x : α) (n k : ℕ) (hk' : n + k < l.length) - (hk : n + k + 1 < (insertNth n x l).length := (by - rwa [length_insertNth _ _ (by omega), Nat.succ_lt_succ_iff])) : - (insertNth 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 _ _ _ - -theorem get_insertNth_add_succ (l : List α) (x : α) (n k : ℕ) (hk' : n + k < l.length) - (hk : n + k + 1 < (insertNth n x l).length := (by - rwa [length_insertNth _ _ (by omega), Nat.succ_lt_succ_iff])) : - (insertNth n x l).get ⟨n + k + 1, hk⟩ = get l ⟨n + k, hk'⟩ := by - simp [getElem_insertNth_add_succ, hk, hk'] - -set_option linter.unnecessarySimpa false in -theorem insertNth_injective (n : ℕ) (x : α) : Function.Injective (insertNth n x) := by - induction' n with n IH - · have : insertNth 0 x = cons x := funext fun _ => rfl - simp [this] - · rintro (_ | ⟨a, as⟩) (_ | ⟨b, bs⟩) h <;> simpa [IH.eq_iff] using h - -end InsertNth - -end List diff --git a/Mathlib/Data/List/Intervals.lean b/Mathlib/Data/List/Intervals.lean index 870f434107df2..9c89237d400af 100644 --- a/Mathlib/Data/List/Intervals.lean +++ b/Mathlib/Data/List/Intervals.lean @@ -125,8 +125,6 @@ theorem chain'_succ (n m : ℕ) : Chain' (fun a b => b = succ a) (Ico n m) := by · rw [eq_nil_of_le (le_of_not_gt h)] trivial --- Porting note (#10618): simp can prove this --- @[simp] theorem not_mem_top {n m : ℕ} : m ∉ Ico n m := by simp theorem filter_lt_of_top_le {n m l : ℕ} (hml : m ≤ l) : diff --git a/Mathlib/Data/List/Lattice.lean b/Mathlib/Data/List/Lattice.lean index 5a0ae92ccc6c0..67914f83dc501 100644 --- a/Mathlib/Data/List/Lattice.lean +++ b/Mathlib/Data/List/Lattice.lean @@ -55,7 +55,7 @@ theorem mem_union_right (l₁ : List α) (h : a ∈ l₂) : a ∈ l₁ ∪ l₂ mem_union_iff.2 (Or.inr h) theorem sublist_suffix_of_union : ∀ l₁ l₂ : List α, ∃ t, t <+ l₁ ∧ t ++ l₂ = l₁ ∪ l₂ - | [], l₂ => ⟨[], by rfl, rfl⟩ + | [], _ => ⟨[], by rfl, rfl⟩ | a :: l₁, l₂ => let ⟨t, s, e⟩ := sublist_suffix_of_union l₁ l₂ if h : a ∈ l₁ ∪ l₂ then diff --git a/Mathlib/Data/List/Lemmas.lean b/Mathlib/Data/List/Lemmas.lean index b055f1b187222..50f55ed3f3832 100644 --- a/Mathlib/Data/List/Lemmas.lean +++ b/Mathlib/Data/List/Lemmas.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yakov Pechersky, Yury Kudryashov -/ import Mathlib.Data.Set.Image -import Mathlib.Data.List.InsertNth +import Mathlib.Data.List.InsertIdx /-! # Some lemmas about lists involving sets @@ -32,8 +32,8 @@ theorem tail_reverse_eq_reverse_dropLast (l : List α) : @[deprecated (since := "2024-08-19")] alias nthLe_tail := getElem_tail -theorem injOn_insertNth_index_of_not_mem (l : List α) (x : α) (hx : x ∉ l) : - Set.InjOn (fun k => insertNth k x l) { n | n ≤ l.length } := by +theorem injOn_insertIdx_index_of_not_mem (l : List α) (x : α) (hx : x ∉ l) : + Set.InjOn (fun k => insertIdx k x l) { n | n ≤ l.length } := by induction' l with hd tl IH · intro n hn m hm _ simp_all [Set.mem_singleton_iff, Set.setOf_eq_eq_singleton, length] @@ -44,12 +44,15 @@ theorem injOn_insertNth_index_of_not_mem (l : List α) (x : α) (hx : x ∉ l) : · rfl · simp [hx.left] at h · simp [Ne.symm hx.left] at h - · simp only [true_and, eq_self_iff_true, insertNth_succ_cons] at h + · simp only [true_and, eq_self_iff_true, insertIdx_succ_cons] at h rw [Nat.succ_inj'] refine IH hx.right ?_ ?_ (by injection h) · simpa [Nat.succ_le_succ_iff] using hn · simpa [Nat.succ_le_succ_iff] using hm +@[deprecated (since := "2024-10-21")] +alias injOn_insertNth_index_of_not_mem := injOn_insertIdx_index_of_not_mem + theorem foldr_range_subset_of_range_subset {f : β → α → α} {g : γ → α → α} (hfg : Set.range f ⊆ Set.range g) (a : α) : Set.range (foldr f a) ⊆ Set.range (foldr g a) := by rintro _ ⟨l, rfl⟩ @@ -97,7 +100,7 @@ theorem mapAccumr_eq_foldr {σ : Type*} (f : α → σ → σ × β) : ∀ (as : let r := f a s.1 (r.1, r.2 :: s.2) ) (s, []) as - | [], s => rfl + | [], _ => rfl | a :: as, s => by simp only [mapAccumr, foldr, mapAccumr_eq_foldr f as] @@ -107,9 +110,9 @@ theorem mapAccumr₂_eq_foldr {σ φ : Type*} (f : α → β → σ → σ × φ let r := f ab.1 ab.2 s.1 (r.1, r.2 :: s.2) ) (s, []) (as.zip bs) - | [], [], s => rfl - | a :: as, [], s => rfl - | [], b :: bs, s => rfl + | [], [], _ => rfl + | _ :: _, [], _ => rfl + | [], _ :: _, _ => rfl | a :: as, b :: bs, s => by simp only [mapAccumr₂, foldr, mapAccumr₂_eq_foldr f as] rfl diff --git a/Mathlib/Data/List/Lex.lean b/Mathlib/Data/List/Lex.lean index 9431966564a45..fef097d96a69f 100644 --- a/Mathlib/Data/List/Lex.lean +++ b/Mathlib/Data/List/Lex.lean @@ -67,11 +67,11 @@ instance isOrderConnected (r : α → α → Prop) [IsOrderConnected α r] [IsTr IsOrderConnected (List α) (Lex r) where conn := aux where aux - | _, [], c :: l₃, nil => Or.inr nil - | _, [], c :: l₃, rel _ => Or.inr nil - | _, [], c :: l₃, cons _ => Or.inr nil - | _, b :: l₂, c :: l₃, nil => Or.inl nil - | a :: l₁, b :: l₂, c :: l₃, rel h => (IsOrderConnected.conn _ b _ h).imp rel rel + | _, [], _ :: _, nil => Or.inr nil + | _, [], _ :: _, rel _ => Or.inr nil + | _, [], _ :: _, cons _ => Or.inr nil + | _, _ :: _, _ :: _, nil => Or.inl nil + | _ :: _, b :: _, _ :: _, rel h => (IsOrderConnected.conn _ b _ h).imp rel rel | a :: l₁, b :: l₂, _ :: l₃, cons h => by rcases trichotomous_of r a b with (ab | rfl | ab) · exact Or.inl (rel ab) @@ -83,8 +83,8 @@ instance isTrichotomous (r : α → α → Prop) [IsTrichotomous α r] : trichotomous := aux where aux | [], [] => Or.inr (Or.inl rfl) - | [], b :: l₂ => Or.inl nil - | a :: l₁, [] => Or.inr (Or.inr nil) + | [], _ :: _ => Or.inl nil + | _ :: _, [] => Or.inr (Or.inr nil) | a :: l₁, b :: l₂ => by rcases trichotomous_of r a b with (ab | rfl | ab) · exact Or.inl (rel ab) @@ -106,7 +106,7 @@ instance isStrictTotalOrder (r : α → α → Prop) [IsStrictTotalOrder α r] : instance decidableRel [DecidableEq α] (r : α → α → Prop) [DecidableRel r] : DecidableRel (Lex r) | l₁, [] => isFalse fun h => by cases h - | [], b :: l₂ => isTrue Lex.nil + | [], _ :: _ => isTrue Lex.nil | a :: l₁, b :: l₂ => by haveI := decidableRel r l₁ l₂ refine decidable_of_iff (r a b ∨ a = b ∧ Lex r l₁ l₂) ⟨fun h => ?_, fun h => ?_⟩ diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 52a8f59fb7167..6ba04976bda0c 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -28,7 +28,7 @@ variable {α β : Type*} section ArgAux -variable (r : α → α → Prop) [DecidableRel r] {l : List α} {o : Option α} {a m : α} +variable (r : α → α → Prop) [DecidableRel r] {l : List α} {o : Option α} {a : α} /-- Auxiliary definition for `argmax` and `argmin`. -/ def argAux (a : Option α) (b : α) : Option α := @@ -88,7 +88,7 @@ end ArgAux section Preorder -variable [Preorder β] [@DecidableRel β (· < ·)] {f : α → β} {l : List α} {o : Option α} {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 @@ -154,7 +154,7 @@ end Preorder section LinearOrder -variable [LinearOrder β] {f : α → β} {l : List α} {o : Option α} {a m : α} +variable [LinearOrder β] {f : α → β} {l : List α} {a m : α} theorem le_of_mem_argmax : a ∈ l → m ∈ argmax f l → f a ≤ f m := fun ha hm => le_of_not_lt <| not_lt_of_mem_argmax ha hm @@ -211,7 +211,7 @@ theorem index_of_argmin : theorem mem_argmax_iff : m ∈ argmax f l ↔ m ∈ l ∧ (∀ a ∈ l, f a ≤ f m) ∧ ∀ a ∈ l, f m ≤ f a → l.indexOf m ≤ l.indexOf a := - ⟨fun hm => ⟨argmax_mem hm, fun a ha => le_of_mem_argmax ha hm, fun _ => index_of_argmax hm⟩, + ⟨fun hm => ⟨argmax_mem hm, fun _ ha => le_of_mem_argmax ha hm, fun _ => index_of_argmax hm⟩, by rintro ⟨hml, ham, hma⟩ cases' harg : argmax f l with n diff --git a/Mathlib/Data/List/NatAntidiagonal.lean b/Mathlib/Data/List/NatAntidiagonal.lean index 3d11150f01d9e..b7ccdccf19f70 100644 --- a/Mathlib/Data/List/NatAntidiagonal.lean +++ b/Mathlib/Data/List/NatAntidiagonal.lean @@ -60,7 +60,7 @@ theorem nodup_antidiagonal (n : ℕ) : Nodup (antidiagonal n) := theorem antidiagonal_succ {n : ℕ} : antidiagonal (n + 1) = (0, n + 1) :: (antidiagonal n).map (Prod.map Nat.succ id) := by simp only [antidiagonal, range_succ_eq_map, map_cons, Nat.add_succ_sub_one, - Nat.add_zero, id, eq_self_iff_true, Nat.sub_zero, map_map, Prod.map_mk] + Nat.add_zero, id, eq_self_iff_true, Nat.sub_zero, map_map, Prod.map_apply] apply congr rfl (congr rfl _) ext; simp diff --git a/Mathlib/Data/List/Nodup.lean b/Mathlib/Data/List/Nodup.lean index f1a4e94793afc..7fc680190d8c0 100644 --- a/Mathlib/Data/List/Nodup.lean +++ b/Mathlib/Data/List/Nodup.lean @@ -213,10 +213,7 @@ theorem nodup_attach {l : List α} : Nodup (attach l) ↔ Nodup l := ⟨fun h => attach_map_subtype_val l ▸ h.map fun _ _ => Subtype.eq, fun h => Nodup.of_map Subtype.val ((attach_map_subtype_val l).symm ▸ h)⟩ -alias ⟨Nodup.of_attach, Nodup.attach⟩ := nodup_attach - --- Porting note: commented out ---attribute [protected] nodup.attach +protected alias ⟨Nodup.of_attach, Nodup.attach⟩ := nodup_attach theorem Nodup.pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} {H} (hf : ∀ a ha b hb, f a ha = f b hb → a = b) (h : Nodup l) : Nodup (pmap f l H) := by @@ -224,7 +221,7 @@ theorem Nodup.pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} {H} exact h.attach.map fun ⟨a, ha⟩ ⟨b, hb⟩ h => by congr; exact hf a (H _ ha) b (H _ hb) h theorem Nodup.filter (p : α → Bool) {l} : Nodup l → Nodup (filter p l) := by - simpa using Pairwise.filter (fun a ↦ p a) + simpa using Pairwise.filter p @[simp] theorem nodup_reverse {l : List α} : Nodup (reverse l) ↔ Nodup l := diff --git a/Mathlib/Data/List/OfFn.lean b/Mathlib/Data/List/OfFn.lean index 9aa74790b948b..27001ba3ea4b0 100644 --- a/Mathlib/Data/List/OfFn.lean +++ b/Mathlib/Data/List/OfFn.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Batteries.Data.List.OfFn -import Batteries.Data.List.Pairwise import Mathlib.Data.Fin.Tuple.Basic /-! @@ -178,8 +177,9 @@ theorem ofFn_fin_repeat {m} (a : Fin m → α) (n : ℕ) : @[simp] theorem pairwise_ofFn {R : α → α → Prop} {n} {f : Fin n → α} : (ofFn f).Pairwise R ↔ ∀ ⦃i j⦄, i < j → R (f i) (f j) := by - simp only [pairwise_iff_get, (Fin.rightInverse_cast (length_ofFn f)).surjective.forall, get_ofFn, - ← Fin.not_le, Fin.cast_le_cast] + simp only [pairwise_iff_getElem, length_ofFn, List.getElem_ofFn, + (Fin.rightInverse_cast (length_ofFn f)).surjective.forall, Fin.forall_iff, Fin.cast_mk, + Fin.mk_lt_mk, forall_comm (α := (_ : Prop)) (β := ℕ)] /-- Lists are equivalent to the sigma type of tuples of a given length. -/ @[simps] @@ -200,14 +200,8 @@ def ofFnRec {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofF @[simp] theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ} - (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by - -- Porting note: Old proof was - -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩ - have := (@equivSigmaTuple α).rightInverse_symm - dsimp [equivSigmaTuple] at this - have := this.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩ - dsimp only at this - rw [ofFnRec, ← this] + (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := + equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩ theorem exists_iff_exists_tuple {P : List α → Prop} : (∃ l : List α, P l) ↔ ∃ (n : _) (f : Fin n → α), P (List.ofFn f) := diff --git a/Mathlib/Data/List/Pairwise.lean b/Mathlib/Data/List/Pairwise.lean index 1a562e854c8c7..cb395fad73168 100644 --- a/Mathlib/Data/List/Pairwise.lean +++ b/Mathlib/Data/List/Pairwise.lean @@ -29,7 +29,7 @@ open Nat Function namespace List -variable {α β : Type*} {R S T : α → α → Prop} {a : α} {l : List α} +variable {α β : Type*} {R : α → α → Prop} {l : List α} mk_iff_of_inductive_prop List.Pairwise List.pairwise_iff @@ -69,12 +69,6 @@ theorem pairwise_of_reflexive_of_forall_ne {l : List α} {r : α → α → Prop /-! ### Pairwise filtering -/ - -variable [DecidableRel R] - -alias ⟨_, Pairwise.pwFilter⟩ := pwFilter_eq_self - --- Porting note: commented out --- attribute [protected] List.Pairwise.pwFilter +protected alias ⟨_, Pairwise.pwFilter⟩ := pwFilter_eq_self end List diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean deleted file mode 100644 index 14611136f55f6..0000000000000 --- a/Mathlib/Data/List/Perm.lean +++ /dev/null @@ -1,654 +0,0 @@ -/- -Copyright (c) 2015 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro --/ -import Mathlib.Data.List.Count -import Mathlib.Data.List.Dedup -import Mathlib.Data.List.Duplicate -import Mathlib.Data.List.InsertNth -import Mathlib.Data.List.Lattice -import Mathlib.Data.List.Permutation -import Mathlib.Data.Nat.Factorial.Basic -import Batteries.Data.List.Perm - -/-! -# List Permutations - -This file introduces the `List.Perm` relation, which is true if two lists are permutations of one -another. - -## Notation - -The notation `~` is used for permutation equivalence. --/ - --- Make sure we don't import algebra -assert_not_exists Monoid - -open Nat - -namespace List -variable {α β : Type*} {l l₁ l₂ : List α} {a : α} - -instance : Trans (@List.Perm α) (@List.Perm α) List.Perm where - trans := @List.Perm.trans α - -open Perm (swap) - -attribute [refl] Perm.refl - -lemma perm_rfl : l ~ l := Perm.refl _ - --- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it -attribute [symm] Perm.symm - -attribute [trans] Perm.trans - -theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ := - ⟨h.symm.subset.trans, h.subset.trans⟩ - -theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₃ ⊆ l₁ ↔ l₃ ⊆ l₂ := - ⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩ - -section Rel - -open Relator - -variable {γ : Type*} {δ : Type*} {r : α → β → Prop} {p : γ → δ → Prop} - -local infixr:80 " ∘r " => Relation.Comp - -theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm := by - funext a c; apply propext - constructor - · exact fun ⟨b, hab, hba⟩ => Perm.trans hab hba - · exact fun h => ⟨a, Perm.refl a, h⟩ - -theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) : - (Forall₂ r ∘r Perm) l v := by - induction hlu generalizing v with - | nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩ - | cons u _hlu ih => - cases' huv with _ b _ v hab huv' - rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩ - exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩ - | swap a₁ a₂ h₂₃ => - cases' huv with _ b₁ _ l₂ h₁ hr₂₃ - cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂ - exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩ - | trans _ _ ih₁ ih₂ => - rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩ - rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩ - exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩ - -theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by - funext l₁ l₃; apply propext - constructor - · intro h - rcases h with ⟨l₂, h₁₂, h₂₃⟩ - have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip - rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩ - exact ⟨l', h₂.symm, h₁.flip⟩ - · exact fun ⟨l₂, h₁₂, h₂₃⟩ => perm_comp_forall₂ h₁₂ h₂₃ - -theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm := - fun a b h₁ c d h₂ h => - have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩ - have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by - rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this - let ⟨b', ⟨c', hbc, hcb⟩, hbd⟩ := this - have : b' = b := right_unique_forall₂' hr hcb hbc - this ▸ hbd - -theorem rel_perm (hr : BiUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· ↔ ·)) Perm Perm := - fun _a _b hab _c _d hcd => - Iff.intro (rel_perm_imp hr.2 hab hcd) (rel_perm_imp hr.left.flip hab.flip hcd.flip) - -end Rel - -section Subperm - - - -attribute [refl] Subperm.refl - -attribute [trans] Subperm.trans - -end Subperm - -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₂⟩ - obtain ⟨l', h₂⟩ := h₂.exists_perm_append - exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩ - -@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by - constructor - · rw [subperm_iff] - rintro ⟨s, hla, h⟩ - rwa [perm_singleton.mp hla, sublist_singleton] at h - · rintro (rfl | rfl) - exacts [nil_subperm, Subperm.refl _] - -attribute [simp] nil_subperm - -@[simp] -theorem subperm_nil : List.Subperm l [] ↔ l = [] := - ⟨fun h ↦ length_eq_zero.1 <| Nat.le_zero.1 h.length_le, by rintro rfl; rfl⟩ - -lemma subperm_cons_self : l <+~ a :: l := ⟨l, Perm.refl _, sublist_cons_self _ _⟩ - -lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P] - (l : List α) (a : α) : - count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by - convert countP_eq_countP_filter_add l _ P - simp only [decide_not] - -theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} [rcomm : RightCommutative f] (p : l₁ ~ l₂) : - ∀ b, foldl f b l₁ = foldl f b l₂ := - p.foldl_eq' fun x _hx y _hy z => rcomm.right_comm z x y - -theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} [lcomm : LeftCommutative f] (p : l₁ ~ l₂) : - ∀ b, foldr f b l₁ = foldr f b l₂ := by - intro b - induction p using Perm.recOnSwap' generalizing b with - | nil => rfl - | cons _ _ r => simp [r b] - | swap' _ _ _ r => simp only [foldr_cons]; rw [lcomm.left_comm, r b] - | trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) - -section - -variable {op : α → α → α} [IA : Std.Associative op] [IC : Std.Commutative op] - -local notation a " * " b => op a b - -local notation l " <*> " a => foldl op a l - -theorem Perm.foldl_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a := - h.foldl_eq _ - -theorem Perm.foldr_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : l₁.foldr op a = l₂.foldr op a := - h.foldr_eq _ - -@[deprecated (since := "2024-09-28")] alias Perm.fold_op_eq := Perm.foldl_op_eq - -end - -theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ := by - refine ⟨fun p => ?_, fun e => e ▸ Perm.refl _⟩ - cases' o₁ with a <;> cases' o₂ with b; · rfl - · cases p.length_eq - · cases p.length_eq - · exact Option.mem_toList.1 (p.symm.subset <| by simp) - -alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons - --- Porting note: commented out ---attribute [protected] subperm.cons - -theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂) - (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ := by - rcases s with ⟨l, p, s⟩ - induction s generalizing l₁ with - | slnil => cases h₂ - | @cons r₁ r₂ b s' ih => - simp? at h₂ says simp only [mem_cons] at h₂ - cases' h₂ with e m - · subst b - exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩ - · rcases ih d₁ h₁ m p with ⟨t, p', s'⟩ - exact ⟨t, p', s'.cons _⟩ - | @cons₂ r₁ r₂ b _ ih => - have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _ - have am : a ∈ r₂ := by - simp only [find?, mem_cons] at h₂ - exact h₂.resolve_left fun e => h₁ <| e.symm ▸ bm - rcases append_of_mem bm with ⟨t₁, t₂, rfl⟩ - have st : t₁ ++ t₂ <+ t₁ ++ b :: t₂ := by simp - rcases ih (d₁.sublist st) (mt (fun x => st.subset x) h₁) am - (Perm.cons_inv <| p.trans perm_middle) with - ⟨t, p', s'⟩ - exact - ⟨b :: t, (p'.cons b).trans <| (swap _ _ _).trans (perm_middle.symm.cons a), s'.cons₂ _⟩ - -protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := - subperm_of_subset d H - -section - -variable [DecidableEq α] - -theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : - l₁.bagInter t ~ l₂.bagInter t := by - induction h generalizing t with - | nil => simp - | cons x => by_cases x ∈ t <;> simp [*, Perm.cons] - | swap x y => - by_cases h : x = y - · simp [h] - by_cases xt : x ∈ t <;> by_cases yt : y ∈ t - · simp [xt, yt, mem_erase_of_ne h, mem_erase_of_ne (Ne.symm h), erase_comm, swap] - · simp [xt, yt, mt mem_of_mem_erase, Perm.cons] - · simp [xt, yt, mt mem_of_mem_erase, Perm.cons] - · simp [xt, yt] - | trans _ _ ih_1 ih_2 => exact (ih_1 _).trans (ih_2 _) - -theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : - l.bagInter t₁ = l.bagInter t₂ := by - induction' l with a l IH generalizing t₁ t₂ p; · simp - by_cases h : a ∈ t₁ - · simp [h, p.subset h, IH (p.erase _)] - · simp [h, mt p.mem_iff.2 h, IH p] - -theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) : - l₁.bagInter t₁ ~ l₂.bagInter t₂ := - ht.bagInter_left l₂ ▸ hl.bagInter_right _ - -theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) : - l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] := by - rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b] - suffices l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by - simp (config := { contextual := true }) [count_replicate, h, this, count_eq_zero, Ne.symm] - trans ∀ c, c ∈ l → c = b ∨ c = a - · simp [subset_def, or_comm] - · exact forall_congr' fun _ => by rw [← and_imp, ← not_or, not_imp_not] - -theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup l₂ := - perm_iff_count.2 fun a => - if h : a ∈ l₁ then by - simp [h, nodup_dedup, p.subset h] - else by - simp [h, count_eq_zero_of_not_mem, mt p.mem_iff.2] - -theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) : - l ∩ (t₁ ++ t₂) ~ l ∩ t₁ ++ l ∩ t₂ := by - induction l with - | nil => simp - | cons x xs l_ih => - by_cases h₁ : x ∈ t₁ - · have h₂ : x ∉ t₂ := h h₁ - simp [*] - by_cases h₂ : x ∈ t₂ - · simp only [*, inter_cons_of_not_mem, false_or, mem_append, inter_cons_of_mem, - not_false_iff] - refine Perm.trans (Perm.cons _ l_ih) ?_ - change [x] ++ xs ∩ t₁ ++ xs ∩ t₂ ~ xs ∩ t₁ ++ ([x] ++ xs ∩ t₂) - rw [← List.append_assoc] - solve_by_elim [Perm.append_right, perm_append_comm] - · simp [*] - -end - - - -theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) : - l.bind f ~ l.bind g := - Perm.join_congr <| by - rwa [List.forall₂_map_right_iff, List.forall₂_map_left_iff, List.forall₂_same] - -theorem bind_append_perm (l : List α) (f g : α → List β) : - l.bind f ++ l.bind g ~ l.bind fun x => f x ++ g x := by - induction' l with a l IH - · simp - simp only [bind_cons, append_assoc] - refine (Perm.trans ?_ (IH.append_left _)).append_left _ - rw [← append_assoc, ← append_assoc] - exact perm_append_comm.append_right _ - -theorem map_append_bind_perm (l : List α) (f : α → β) (g : α → List β) : - l.map f ++ l.bind g ~ l.bind fun x => f x :: g x := by - simpa [← map_eq_bind] using bind_append_perm l (fun x => [f x]) g - -theorem Perm.product_right {l₁ l₂ : List α} (t₁ : List β) (p : l₁ ~ l₂) : - product l₁ t₁ ~ product l₂ t₁ := - p.bind_right _ - -theorem Perm.product_left (l : List α) {t₁ t₂ : List β} (p : t₁ ~ t₂) : - product l t₁ ~ product l t₂ := - (Perm.bind_left _) fun _ _ => p.map _ - -theorem Perm.product {l₁ l₂ : List α} {t₁ t₂ : List β} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : - product l₁ t₁ ~ product l₂ t₂ := - (p₁.product_right t₁).trans (p₂.product_left l₂) - -theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α} - (H : Pairwise (fun a b => ∀ c ∈ f a, ∀ d ∈ f b, a = b ∧ c = d) l₁) (p : l₁ ~ l₂) : - lookmap f l₁ ~ lookmap f l₂ := by - induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp - · cases h : f a - · simpa [h] using IH (pairwise_cons.1 H).2 - · simp [lookmap_cons_some _ _ h, p] - · cases' h₁ : f a with c <;> cases' h₂ : f b with d - · simpa [h₁, h₂] using swap _ _ _ - · simpa [h₁, lookmap_cons_some _ _ h₂] using swap _ _ _ - · simpa [lookmap_cons_some _ _ h₁, h₂] using swap _ _ _ - · rcases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩ - exact Perm.refl _ - · refine (IH₁ H).trans (IH₂ ((p₁.pairwise_iff ?_).1 H)) - intro x y h c hc d hd - rw [@eq_comm _ y, @eq_comm _ c] - apply h d hd c hc - -theorem Perm.take_inter [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) - (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by - simp only [List.inter] - exact Perm.trans (show xs.take n ~ xs.filter (xs.take n).elem by - conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')]) - (Perm.filter _ h) - -theorem Perm.drop_inter [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) : - xs.drop n ~ ys.inter (xs.drop n) := by - by_cases h'' : n ≤ xs.length - · let n' := xs.length - n - have h₀ : n = xs.length - n' := by rwa [Nat.sub_sub_self] - have h₁ : xs.drop n = (xs.reverse.take n').reverse := by - rw [take_reverse, h₀, reverse_reverse] - rw [h₁] - apply (reverse_perm _).trans - rw [inter_reverse] - apply Perm.take_inter _ _ h' - apply (reverse_perm _).trans; assumption - · have : drop n xs = [] := by - apply eq_nil_of_length_eq_zero - rw [length_drop, Nat.sub_eq_zero_iff_le] - apply le_of_not_ge h'' - simp [this, List.inter] - -theorem Perm.dropSlice_inter [DecidableEq α] {xs ys : List α} (n m : ℕ) (h : xs ~ ys) - (h' : ys.Nodup) : List.dropSlice n m xs ~ ys ∩ List.dropSlice n m xs := by - simp only [dropSlice_eq] - have : n ≤ n + m := Nat.le_add_right _ _ - have h₂ := h.nodup_iff.2 h' - apply Perm.trans _ (Perm.inter_append _).symm - · exact Perm.append (Perm.take_inter _ h h') (Perm.drop_inter _ h h') - · exact disjoint_take_drop h₂ this - --- enumerating permutations -section Permutations - -theorem perm_of_mem_permutationsAux : - ∀ {ts is l : List α}, l ∈ permutationsAux ts is → l ~ ts ++ is := by - show ∀ (ts is l : List α), l ∈ permutationsAux ts is → l ~ ts ++ is - refine permutationsAux.rec (by simp) ?_ - introv IH1 IH2 m - rw [permutationsAux_cons, permutations, mem_foldr_permutationsAux2] at m - rcases m with (m | ⟨l₁, l₂, m, _, rfl⟩) - · exact (IH1 _ m).trans perm_middle - · have p : l₁ ++ l₂ ~ is := by - simp only [mem_cons] at m - cases' m with e m - · simp [e] - exact is.append_nil ▸ IH2 _ m - exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _) - -theorem perm_of_mem_permutations {l₁ l₂ : List α} (h : l₁ ∈ permutations l₂) : l₁ ~ l₂ := - (eq_or_mem_of_mem_cons h).elim (fun e => e ▸ Perm.refl _) fun m => - append_nil l₂ ▸ perm_of_mem_permutationsAux m - -theorem length_permutationsAux : - ∀ ts is : List α, length (permutationsAux ts is) + is.length ! = (length ts + length is)! := by - refine permutationsAux.rec (by simp) ?_ - intro t ts is IH1 IH2 - have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2 - simp only [factorial, Nat.mul_comm, add_eq] at IH1 - rw [permutationsAux_cons, - length_foldr_permutationsAux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq, - permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, Nat.mul_comm (_ + 1), - ← Nat.succ_eq_add_one, ← IH1, Nat.add_comm (_ * _), Nat.add_assoc, Nat.mul_succ, Nat.mul_comm] - -theorem length_permutations (l : List α) : length (permutations l) = (length l)! := - length_permutationsAux l [] - -theorem mem_permutations_of_perm_lemma {is l : List α} - (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) : - l ~ is → l ∈ permutations is := by simpa [permutations, perm_nil] using H - -theorem mem_permutationsAux_of_perm : - ∀ {ts is l : List α}, - l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is := by - show ∀ (ts is l : List α), - l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is - refine permutationsAux.rec (by simp) ?_ - intro t ts is IH1 IH2 l p - rw [permutationsAux_cons, mem_foldr_permutationsAux2] - rcases IH1 _ (p.trans perm_middle) with (⟨is', p', e⟩ | m) - · clear p - subst e - rcases append_of_mem (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩ - subst is' - have p := (perm_middle.symm.trans p').cons_inv - cases' l₂ with a l₂' - · exact Or.inl ⟨l₁, by simpa using p⟩ - · exact Or.inr (Or.inr ⟨l₁, a :: l₂', mem_permutations_of_perm_lemma (IH2 _) p, by simp⟩) - · exact Or.inr (Or.inl m) - -@[simp] -theorem mem_permutations {s t : List α} : s ∈ permutations t ↔ s ~ t := - ⟨perm_of_mem_permutations, mem_permutations_of_perm_lemma mem_permutationsAux_of_perm⟩ - --- Porting note: temporary theorem to solve diamond issue -private theorem DecEq_eq [DecidableEq α] : - List.instBEq = @instBEqOfDecidableEq (List α) instDecidableEqList := - congr_arg BEq.mk <| by - funext l₁ l₂ - show (l₁ == l₂) = _ - rw [Bool.eq_iff_iff, @beq_iff_eq _ (_), decide_eq_true_iff] - -theorem perm_permutations'Aux_comm (a b : α) (l : List α) : - (permutations'Aux a l).bind (permutations'Aux b) ~ - (permutations'Aux b l).bind (permutations'Aux a) := by - induction' l with c l ih - · simp [swap] - simp only [permutations'Aux, bind_cons, map_cons, map_map, cons_append] - apply Perm.swap' - have : - ∀ a b, - (map (cons c) (permutations'Aux a l)).bind (permutations'Aux b) ~ - map (cons b ∘ cons c) (permutations'Aux a l) ++ - map (cons c) ((permutations'Aux a l).bind (permutations'Aux b)) := by - intros a' b' - simp only [bind_map, permutations'Aux] - show List.bind (permutations'Aux _ l) (fun a => ([b' :: c :: a] ++ - map (cons c) (permutations'Aux _ a))) ~ _ - refine (bind_append_perm _ (fun x => [b' :: c :: x]) _).symm.trans ?_ - rw [← map_eq_bind, ← map_bind] - exact Perm.refl _ - refine (((this _ _).append_left _).trans ?_).trans ((this _ _).append_left _).symm - rw [← append_assoc, ← append_assoc] - exact perm_append_comm.append (ih.map _) - -theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by - induction p with - | nil => simp - | cons _ _ IH => exact IH.bind_right _ - | swap => - dsimp - rw [bind_assoc, bind_assoc] - apply Perm.bind_left - intro l' _ - apply perm_permutations'Aux_comm - | trans _ _ IH₁ IH₂ => exact IH₁.trans IH₂ - -theorem permutations_perm_permutations' (ts : List α) : ts.permutations ~ ts.permutations' := by - obtain ⟨n, h⟩ : ∃ n, length ts < n := ⟨_, Nat.lt_succ_self _⟩ - induction' n with n IH generalizing ts; · cases h - refine List.reverseRecOn ts (fun _ => ?_) (fun ts t _ h => ?_) h; · simp [permutations] - rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h - have IH₂ := (IH ts.reverse (by rwa [length_reverse])).trans (reverse_perm _).permutations' - simp only [permutations_append, foldr_permutationsAux2, permutationsAux_nil, - permutationsAux_cons, append_nil] - refine - (perm_append_comm.trans ((IH₂.bind_right _).append ((IH _ h).map _))).trans - (Perm.trans ?_ perm_append_comm.permutations') - rw [map_eq_bind, singleton_append, permutations'] - refine (bind_append_perm _ _ _).trans ?_ - refine Perm.of_eq ?_ - congr - funext _ - rw [permutations'Aux_eq_permutationsAux2, permutationsAux2_append] - -@[simp] -theorem mem_permutations' {s t : List α} : s ∈ permutations' t ↔ s ~ t := - (permutations_perm_permutations' _).symm.mem_iff.trans mem_permutations - -theorem Perm.permutations {s t : List α} (h : s ~ t) : permutations s ~ permutations t := - (permutations_perm_permutations' _).trans <| - h.permutations'.trans (permutations_perm_permutations' _).symm - -@[simp] -theorem perm_permutations_iff {s t : List α} : permutations s ~ permutations t ↔ s ~ t := - ⟨fun h => mem_permutations.1 <| h.mem_iff.1 <| mem_permutations.2 (Perm.refl _), - Perm.permutations⟩ - -@[simp] -theorem perm_permutations'_iff {s t : List α} : permutations' s ~ permutations' t ↔ s ~ t := - ⟨fun h => mem_permutations'.1 <| h.mem_iff.1 <| mem_permutations'.2 (Perm.refl _), - Perm.permutations'⟩ - -theorem getElem_permutations'Aux (s : List α) (x : α) (n : ℕ) - (hn : n < length (permutations'Aux x s)) : - (permutations'Aux x s)[n] = s.insertNth n x := by - induction' s with y s IH generalizing n - · simp only [length, Nat.zero_add, Nat.lt_one_iff] at hn - simp [hn] - · cases n - · simp [get] - · simpa [get] using IH _ _ - -theorem get_permutations'Aux (s : List α) (x : α) (n : ℕ) - (hn : n < length (permutations'Aux x s)) : - (permutations'Aux x s).get ⟨n, hn⟩ = s.insertNth n x := by - simp [getElem_permutations'Aux] - -theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) : - count (x :: l) (permutations'Aux x l) = length (takeWhile (x = ·) l) + 1 := by - induction' l with y l IH generalizing x - · simp [takeWhile, count] - · rw [permutations'Aux, count_cons_self] - by_cases hx : x = y - · subst hx - 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] - -@[simp] -theorem length_permutations'Aux (s : List α) (x : α) : - length (permutations'Aux x s) = length s + 1 := by - induction' s with y s IH - · simp - · simpa using IH - -@[deprecated (since := "2024-06-12")] -theorem permutations'Aux_get_zero (s : List α) (x : α) - (hn : 0 < length (permutations'Aux x s) := (by simp)) : - (permutations'Aux x s).get ⟨0, hn⟩ = x :: s := - get_permutations'Aux _ _ _ _ - -theorem injective_permutations'Aux (x : α) : Function.Injective (permutations'Aux x) := by - intro s t h - apply insertNth_injective s.length x - have hl : s.length = t.length := by simpa using congr_arg length h - rw [← get_permutations'Aux s x s.length (by simp), - ← get_permutations'Aux t x s.length (by simp [hl])] - simp only [get_eq_getElem, h, hl] - -theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s) : - Nodup (permutations'Aux x s) := by - induction' s with y s IH - · simp - · simp only [not_or, mem_cons] at hx - simp only [permutations'Aux, nodup_cons, mem_map, cons.injEq, exists_eq_right_right, not_and] - refine ⟨fun _ => Ne.symm hx.left, ?_⟩ - rw [nodup_map_iff] - · exact IH hx.right - · simp - -theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s := by - refine ⟨fun h H ↦ ?_, nodup_permutations'Aux_of_not_mem _ _⟩ - obtain ⟨⟨k, hk⟩, hk'⟩ := get_of_mem H - rw [nodup_iff_injective_get] at h - apply k.succ_ne_self.symm - have kl : k < (permutations'Aux x s).length := by simpa [Nat.lt_succ_iff] using hk.le - have k1l : k + 1 < (permutations'Aux x s).length := by simpa using hk - rw [← @Fin.mk.inj_iff _ _ _ kl k1l]; apply h - rw [get_permutations'Aux, get_permutations'Aux] - have hl : length (insertNth k x s) = length (insertNth (k + 1) x s) := by - rw [length_insertNth _ _ hk.le, length_insertNth _ _ (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_insertNth_of_lt _ _ _ _ H (H.trans hk), - get_insertNth_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))] - · rw [get_insertNth_self _ _ _ hk.le, get_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk, hk'] - · rcases (Nat.succ_le_of_lt H).eq_or_lt with (rfl | H') - · rw [get_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)] - convert hk' using 1 - exact get_insertNth_add_succ _ _ _ 0 _ - · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H' - erw [length_insertNth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn - rw [get_insertNth_add_succ] - · convert get_insertNth_add_succ s x k m.succ (by simpa using hn) using 2 - · simp [Nat.add_assoc, Nat.add_left_comm] - · simp [Nat.add_left_comm, Nat.add_comm] - · simpa [Nat.succ_add] using hn - -theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations := by - rw [(permutations_perm_permutations' s).nodup_iff] - induction' hs with x l h h' IH - · simp - · rw [permutations'] - rw [nodup_bind] - constructor - · intro ys hy - rw [mem_permutations'] at hy - rw [nodup_permutations'Aux_iff, hy.mem_iff] - exact fun H => h x H rfl - · refine IH.pairwise_of_forall_ne fun as ha bs hb H => ?_ - rw [disjoint_iff_ne] - rintro a ha' b hb' rfl - obtain ⟨⟨n, hn⟩, hn'⟩ := get_of_mem ha' - obtain ⟨⟨m, hm⟩, hm'⟩ := get_of_mem hb' - rw [mem_permutations'] at ha hb - 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 : - (insertNth n x as)[m]'(by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff, hl]) = x := by - simp [hn', ← hm', hm] - have hx' : - (insertNth m x bs)[n]'(by rwa [length_insertNth _ _ 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_insertNth_of_lt _ _ _ _ ht (ht.trans_le hm)] - exact get_mem _ _ _ - · simp only [ht] at hm' hn' - rw [← hm'] at hn' - exact H (insertNth_injective _ _ hn') - · suffices x ∈ as by exact h x (ha.subset this) rfl - rw [← hx, getElem_insertNth_of_lt _ _ _ _ ht (ht.trans_le hn)] - exact get_mem _ _ _ - -lemma permutations_take_two (x y : α) (s : List α) : - (x :: y :: s).permutations.take 2 = [x :: y :: s, y :: x :: s] := by - induction s <;> simp only [take, permutationsAux, permutationsAux.rec, permutationsAux2, id_eq] - -@[simp] -theorem nodup_permutations_iff {s : List α} : Nodup s.permutations ↔ Nodup s := by - refine ⟨?_, nodup_permutations s⟩ - contrapose - rw [← exists_duplicate_iff_not_nodup] - intro ⟨x, hs⟩ - rw [duplicate_iff_sublist] at hs - obtain ⟨l, ht⟩ := List.Sublist.exists_perm_append hs - rw [List.Perm.nodup_iff (List.Perm.permutations ht), ← exists_duplicate_iff_not_nodup] - use x :: x :: l - rw [List.duplicate_iff_sublist, ← permutations_take_two] - exact take_sublist 2 _ - --- TODO: `count s s.permutations = (zipWith count s s.tails).prod` -end Permutations - -end List diff --git a/Mathlib/Data/List/Perm/Basic.lean b/Mathlib/Data/List/Perm/Basic.lean new file mode 100644 index 0000000000000..c665732b59f94 --- /dev/null +++ b/Mathlib/Data/List/Perm/Basic.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Batteries.Data.List.Perm +import Mathlib.Logic.Relation +import Mathlib.Order.RelClasses +import Mathlib.Data.List.Forall2 + +/-! +# List Permutations + +This file develops theory about the `List.Perm` relation. + +## Notation + +The notation `~` is used for permutation equivalence. +-/ + +-- Make sure we don't import algebra +assert_not_exists Monoid + +open Nat + +namespace List +variable {α β : Type*} {l l₁ l₂ : List α} {a : α} + +instance : Trans (@List.Perm α) (@List.Perm α) List.Perm where + trans := @List.Perm.trans α + +open Perm (swap) + +lemma perm_rfl : l ~ l := Perm.refl _ + +attribute [symm] Perm.symm +attribute [trans] Perm.trans + +theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ := + ⟨h.symm.subset.trans, h.subset.trans⟩ + +theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₃ ⊆ l₁ ↔ l₃ ⊆ l₂ := + ⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩ + +section Rel + +open Relator + +variable {r : α → β → Prop} + +local infixr:80 " ∘r " => Relation.Comp + +theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm := by + funext a c; apply propext + constructor + · exact fun ⟨b, hab, hba⟩ => Perm.trans hab hba + · exact fun h => ⟨a, Perm.refl a, h⟩ + +theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) : + (Forall₂ r ∘r Perm) l v := by + induction hlu generalizing v with + | nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩ + | cons u _hlu ih => + cases' huv with _ b _ v hab huv' + rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩ + exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩ + | swap a₁ a₂ h₂₃ => + cases' huv with _ b₁ _ l₂ h₁ hr₂₃ + cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂ + exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩ + | trans _ _ ih₁ ih₂ => + rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩ + rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩ + exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩ + +theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by + funext l₁ l₃; apply propext + constructor + · intro h + rcases h with ⟨l₂, h₁₂, h₂₃⟩ + have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip + rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩ + exact ⟨l', h₂.symm, h₁.flip⟩ + · exact fun ⟨l₂, h₁₂, h₂₃⟩ => perm_comp_forall₂ h₁₂ h₂₃ + +theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm := + fun a b h₁ c d h₂ h => + have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩ + have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by + rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this + let ⟨b', ⟨_, hbc, hcb⟩, hbd⟩ := this + have : b' = b := right_unique_forall₂' hr hcb hbc + this ▸ hbd + +theorem rel_perm (hr : BiUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· ↔ ·)) Perm Perm := + fun _a _b hab _c _d hcd => + Iff.intro (rel_perm_imp hr.2 hab hcd) (rel_perm_imp hr.left.flip hab.flip hcd.flip) + +end Rel + +lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P] + (l : List α) (a : α) : + count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by + convert countP_eq_countP_filter_add l _ P + simp only [decide_not] + +theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} [rcomm : RightCommutative f] (p : l₁ ~ l₂) : + ∀ b, foldl f b l₁ = foldl f b l₂ := + p.foldl_eq' fun x _hx y _hy z => rcomm.right_comm z x y + +theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} [lcomm : LeftCommutative f] (p : l₁ ~ l₂) : + ∀ b, foldr f b l₁ = foldr f b l₂ := by + intro b + induction p using Perm.recOnSwap' generalizing b with + | nil => rfl + | cons _ _ r => simp [r b] + | swap' _ _ _ r => simp only [foldr_cons]; rw [lcomm.left_comm, r b] + | trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) + +section + +variable {op : α → α → α} [IA : Std.Associative op] [IC : Std.Commutative op] + +local notation a " * " b => op a b + +local notation l " <*> " a => foldl op a l + +theorem Perm.foldl_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a := + h.foldl_eq _ + +theorem Perm.foldr_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : l₁.foldr op a = l₂.foldr op a := + h.foldr_eq _ + +@[deprecated (since := "2024-09-28")] alias Perm.fold_op_eq := Perm.foldl_op_eq + +end + +theorem perm_option_toList {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ := by + refine ⟨fun p => ?_, fun e => e ▸ Perm.refl _⟩ + cases' o₁ with a <;> cases' o₂ with b; · rfl + · cases p.length_eq + · cases p.length_eq + · exact Option.mem_toList.1 (p.symm.subset <| by simp) + +@[deprecated (since := "2024-10-16")] alias perm_option_to_list := perm_option_toList + +theorem perm_replicate_append_replicate + [DecidableEq α] {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) : + l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] := by + rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b] + suffices l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by + simp (config := { contextual := true }) [count_replicate, h, this, count_eq_zero, Ne.symm] + trans ∀ c, c ∈ l → c = b ∨ c = a + · simp [subset_def, or_comm] + · exact forall_congr' fun _ => by rw [← and_imp, ← not_or, not_imp_not] + +theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) : + l.bind f ~ l.bind g := + Perm.join_congr <| by + rwa [List.forall₂_map_right_iff, List.forall₂_map_left_iff, List.forall₂_same] + +theorem bind_append_perm (l : List α) (f g : α → List β) : + l.bind f ++ l.bind g ~ l.bind fun x => f x ++ g x := by + induction' l with a l IH + · simp + simp only [bind_cons, append_assoc] + refine (Perm.trans ?_ (IH.append_left _)).append_left _ + rw [← append_assoc, ← append_assoc] + exact perm_append_comm.append_right _ + +theorem map_append_bind_perm (l : List α) (f : α → β) (g : α → List β) : + l.map f ++ l.bind g ~ l.bind fun x => f x :: g x := by + simpa [← map_eq_bind] using bind_append_perm l (fun x => [f x]) g + +theorem Perm.product_right {l₁ l₂ : List α} (t₁ : List β) (p : l₁ ~ l₂) : + product l₁ t₁ ~ product l₂ t₁ := + p.bind_right _ + +theorem Perm.product_left (l : List α) {t₁ t₂ : List β} (p : t₁ ~ t₂) : + product l t₁ ~ product l t₂ := + (Perm.bind_left _) fun _ _ => p.map _ + +theorem Perm.product {l₁ l₂ : List α} {t₁ t₂ : List β} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : + product l₁ t₁ ~ product l₂ t₂ := + (p₁.product_right t₁).trans (p₂.product_left l₂) + +theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α} + (H : Pairwise (fun a b => ∀ c ∈ f a, ∀ d ∈ f b, a = b ∧ c = d) l₁) (p : l₁ ~ l₂) : + lookmap f l₁ ~ lookmap f l₂ := by + induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp + · cases h : f a + · simpa [h] using IH (pairwise_cons.1 H).2 + · simp [lookmap_cons_some _ _ h, p] + · cases' h₁ : f a with c <;> cases' h₂ : f b with d + · simpa [h₁, h₂] using swap _ _ _ + · simpa [h₁, lookmap_cons_some _ _ h₂] using swap _ _ _ + · simpa [lookmap_cons_some _ _ h₁, h₂] using swap _ _ _ + · rcases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩ + exact Perm.refl _ + · refine (IH₁ H).trans (IH₂ ((p₁.pairwise_iff ?_).1 H)) + intro x y h c hc d hd + rw [@eq_comm _ y, @eq_comm _ c] + apply h d hd c hc + +end List diff --git a/Mathlib/Data/List/Perm/Lattice.lean b/Mathlib/Data/List/Perm/Lattice.lean new file mode 100644 index 0000000000000..44b3c318a9ff0 --- /dev/null +++ b/Mathlib/Data/List/Perm/Lattice.lean @@ -0,0 +1,107 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Mathlib.Data.List.Forall2 +import Mathlib.Data.Set.Pairwise.Basic +import Mathlib.Data.List.Basic +import Mathlib.Data.List.Lattice +import Mathlib.Data.List.Nodup + +/-! +# List Permutations and list lattice operations. + +This file develops theory about the `List.Perm` relation and the lattice structure on lists. +-/ + +-- Make sure we don't import algebra +assert_not_exists Monoid + +open Nat + +namespace List +variable {α β : Type*} {l l₁ l₂ : List α} {a : α} + +open Perm (swap) + +variable [DecidableEq α] + +theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : + l₁.bagInter t ~ l₂.bagInter t := by + induction h generalizing t with + | nil => simp + | cons x => by_cases x ∈ t <;> simp [*, Perm.cons] + | swap x y => + by_cases h : x = y + · simp [h] + by_cases xt : x ∈ t <;> by_cases yt : y ∈ t + · simp [xt, yt, mem_erase_of_ne h, mem_erase_of_ne (Ne.symm h), erase_comm, swap] + · simp [xt, yt, mt mem_of_mem_erase, Perm.cons] + · simp [xt, yt, mt mem_of_mem_erase, Perm.cons] + · simp [xt, yt] + | trans _ _ ih_1 ih_2 => exact (ih_1 _).trans (ih_2 _) + +theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : + l.bagInter t₁ = l.bagInter t₂ := by + induction' l with a l IH generalizing t₁ t₂ p; · simp + by_cases h : a ∈ t₁ + · simp [h, p.subset h, IH (p.erase _)] + · simp [h, mt p.mem_iff.2 h, IH p] + +theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) : + l₁.bagInter t₁ ~ l₂.bagInter t₂ := + ht.bagInter_left l₂ ▸ hl.bagInter_right _ + +theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) : + l ∩ (t₁ ++ t₂) ~ l ∩ t₁ ++ l ∩ t₂ := by + induction l with + | nil => simp + | cons x xs l_ih => + by_cases h₁ : x ∈ t₁ + · have h₂ : x ∉ t₂ := h h₁ + simp [*] + by_cases h₂ : x ∈ t₂ + · simp only [*, inter_cons_of_not_mem, false_or, mem_append, inter_cons_of_mem, + not_false_iff] + refine Perm.trans (Perm.cons _ l_ih) ?_ + change [x] ++ xs ∩ t₁ ++ xs ∩ t₂ ~ xs ∩ t₁ ++ ([x] ++ xs ∩ t₂) + rw [← List.append_assoc] + solve_by_elim [Perm.append_right, perm_append_comm] + · simp [*] + +theorem Perm.take_inter {xs ys : List α} (n : ℕ) (h : xs ~ ys) + (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by + simp only [List.inter] + exact Perm.trans (show xs.take n ~ xs.filter (xs.take n).elem by + conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')]) + (Perm.filter _ h) + +theorem Perm.drop_inter {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) : + xs.drop n ~ ys.inter (xs.drop n) := by + by_cases h'' : n ≤ xs.length + · let n' := xs.length - n + have h₀ : n = xs.length - n' := by rwa [Nat.sub_sub_self] + have h₁ : xs.drop n = (xs.reverse.take n').reverse := by + rw [take_reverse, h₀, reverse_reverse] + rw [h₁] + apply (reverse_perm _).trans + rw [inter_reverse] + apply Perm.take_inter _ _ h' + apply (reverse_perm _).trans; assumption + · have : drop n xs = [] := by + apply eq_nil_of_length_eq_zero + rw [length_drop, Nat.sub_eq_zero_iff_le] + apply le_of_not_ge h'' + simp [this, List.inter] + +theorem Perm.dropSlice_inter {xs ys : List α} (n m : ℕ) (h : xs ~ ys) + (h' : ys.Nodup) : List.dropSlice n m xs ~ ys ∩ List.dropSlice n m xs := by + simp only [dropSlice_eq] + have : n ≤ n + m := Nat.le_add_right _ _ + have h₂ := h.nodup_iff.2 h' + apply Perm.trans _ (Perm.inter_append _).symm + · exact Perm.append (Perm.take_inter _ h h') (Perm.drop_inter _ h h') + · exact disjoint_take_drop h₂ this + +end List diff --git a/Mathlib/Data/List/Perm/Subperm.lean b/Mathlib/Data/List/Perm/Subperm.lean new file mode 100644 index 0000000000000..9232259156a4d --- /dev/null +++ b/Mathlib/Data/List/Perm/Subperm.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Batteries.Data.List.Pairwise +import Batteries.Data.List.Perm +import Mathlib.Data.List.Basic + +/-! +# List Sub-permutations + +This file develops theory about the `List.Subperm` relation. + +## Notation + +The notation `<+~` is used for sub-permutations. +-/ + +open Nat + +namespace List +variable {α β : Type*} {l l₁ l₂ : List α} {a : α} + +open Perm + +section Subperm + +attribute [trans] Subperm.trans + +end Subperm + +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₂⟩ + obtain ⟨l', h₂⟩ := h₂.exists_perm_append + exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩ + +@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by + constructor + · rw [subperm_iff] + rintro ⟨s, hla, h⟩ + rwa [perm_singleton.mp hla, sublist_singleton] at h + · rintro (rfl | rfl) + exacts [nil_subperm, Subperm.refl _] + +lemma subperm_cons_self : l <+~ a :: l := ⟨l, Perm.refl _, sublist_cons_self _ _⟩ + +protected alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons + +theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂) + (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ := by + rcases s with ⟨l, p, s⟩ + induction s generalizing l₁ with + | slnil => cases h₂ + | @cons r₁ r₂ b s' ih => + simp? at h₂ says simp only [mem_cons] at h₂ + cases' h₂ with e m + · subst b + exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩ + · rcases ih d₁ h₁ m p with ⟨t, p', s'⟩ + exact ⟨t, p', s'.cons _⟩ + | @cons₂ r₁ r₂ b _ ih => + have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _ + have am : a ∈ r₂ := by + simp only [find?, mem_cons] at h₂ + exact h₂.resolve_left fun e => h₁ <| e.symm ▸ bm + rcases append_of_mem bm with ⟨t₁, t₂, rfl⟩ + have st : t₁ ++ t₂ <+ t₁ ++ b :: t₂ := by simp + rcases ih (d₁.sublist st) (mt (fun x => st.subset x) h₁) am + (Perm.cons_inv <| p.trans perm_middle) with + ⟨t, p', s'⟩ + exact + ⟨b :: t, (p'.cons b).trans <| (swap _ _ _).trans (perm_middle.symm.cons a), s'.cons₂ _⟩ + +protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := + subperm_of_subset d H + +end List diff --git a/Mathlib/Data/List/Permutation.lean b/Mathlib/Data/List/Permutation.lean index dfa4674956933..7b30383ce32a7 100644 --- a/Mathlib/Data/List/Permutation.lean +++ b/Mathlib/Data/List/Permutation.lean @@ -4,6 +4,12 @@ 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.Join +import Mathlib.Data.Nat.Factorial.Basic +import Mathlib.Data.List.Count +import Mathlib.Data.List.Duplicate +import Mathlib.Data.List.InsertIdx +import Batteries.Data.List.Perm +import Mathlib.Data.List.Perm.Basic /-! # Permutations of a list @@ -36,16 +42,12 @@ all positions. Hence, to build `[0, 1, 2, 3].permutations'`, it does `[0, 1, 3, 2], [1, 0, 3, 2], [1, 3, 0, 2], [1, 3, 2, 0],` `[0, 3, 1, 2], [3, 0, 1, 2], [3, 1, 0, 2], [3, 1, 2, 0],` `[0, 3, 2, 1], [3, 0, 2, 1], [3, 2, 0, 1], [3, 2, 1, 0]]` - -## TODO - -Show that `l.Nodup → l.permutations.Nodup`. See `Data.Fintype.List`. -/ -- Make sure we don't import algebra assert_not_exists Monoid -open Nat +open Nat Function variable {α β : Type*} @@ -53,7 +55,7 @@ namespace List theorem permutationsAux2_fst (t : α) (ts : List α) (r : List β) : ∀ (ys : List α) (f : List α → β), (permutationsAux2 t ts r ys f).1 = ys ++ ts - | [], f => rfl + | [], _ => rfl | y :: ys, f => by simp [permutationsAux2, permutationsAux2_fst t _ _ ys] @[simp] @@ -241,4 +243,286 @@ theorem permutations_append (is ts : List α) : permutations (is ++ ts) = (permutations is).map (· ++ ts) ++ permutationsAux ts is.reverse := by simp [permutations, permutationsAux_append] +theorem perm_of_mem_permutationsAux : + ∀ {ts is l : List α}, l ∈ permutationsAux ts is → l ~ ts ++ is := by + show ∀ (ts is l : List α), l ∈ permutationsAux ts is → l ~ ts ++ is + refine permutationsAux.rec (by simp) ?_ + introv IH1 IH2 m + rw [permutationsAux_cons, permutations, mem_foldr_permutationsAux2] at m + rcases m with (m | ⟨l₁, l₂, m, _, rfl⟩) + · exact (IH1 _ m).trans perm_middle + · have p : l₁ ++ l₂ ~ is := by + simp only [mem_cons] at m + cases' m with e m + · simp [e] + exact is.append_nil ▸ IH2 _ m + exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _) + +theorem perm_of_mem_permutations {l₁ l₂ : List α} (h : l₁ ∈ permutations l₂) : l₁ ~ l₂ := + (eq_or_mem_of_mem_cons h).elim (fun e => e ▸ Perm.refl _) fun m => + append_nil l₂ ▸ perm_of_mem_permutationsAux m + +theorem length_permutationsAux : + ∀ ts is : List α, length (permutationsAux ts is) + is.length ! = (length ts + length is)! := by + refine permutationsAux.rec (by simp) ?_ + intro t ts is IH1 IH2 + have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2 + simp only [factorial, Nat.mul_comm, add_eq] at IH1 + rw [permutationsAux_cons, + length_foldr_permutationsAux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq, + permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, Nat.mul_comm (_ + 1), + ← Nat.succ_eq_add_one, ← IH1, Nat.add_comm (_ * _), Nat.add_assoc, Nat.mul_succ, Nat.mul_comm] + +theorem length_permutations (l : List α) : length (permutations l) = (length l)! := + length_permutationsAux l [] + +theorem mem_permutations_of_perm_lemma {is l : List α} + (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) : + l ~ is → l ∈ permutations is := by simpa [permutations, perm_nil] using H + +theorem mem_permutationsAux_of_perm : + ∀ {ts is l : List α}, + l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is := by + show ∀ (ts is l : List α), + l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is + refine permutationsAux.rec (by simp) ?_ + intro t ts is IH1 IH2 l p + rw [permutationsAux_cons, mem_foldr_permutationsAux2] + rcases IH1 _ (p.trans perm_middle) with (⟨is', p', e⟩ | m) + · clear p + subst e + rcases append_of_mem (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩ + subst is' + have p := (perm_middle.symm.trans p').cons_inv + cases' l₂ with a l₂' + · exact Or.inl ⟨l₁, by simpa using p⟩ + · exact Or.inr (Or.inr ⟨l₁, a :: l₂', mem_permutations_of_perm_lemma (IH2 _) p, by simp⟩) + · exact Or.inr (Or.inl m) + +@[simp] +theorem mem_permutations {s t : List α} : s ∈ permutations t ↔ s ~ t := + ⟨perm_of_mem_permutations, mem_permutations_of_perm_lemma mem_permutationsAux_of_perm⟩ + +-- Porting note: temporary theorem to solve diamond issue +private theorem DecEq_eq [DecidableEq α] : + List.instBEq = @instBEqOfDecidableEq (List α) instDecidableEqList := + congr_arg BEq.mk <| by + funext l₁ l₂ + show (l₁ == l₂) = _ + rw [Bool.eq_iff_iff, @beq_iff_eq _ (_), decide_eq_true_iff] + +theorem perm_permutations'Aux_comm (a b : α) (l : List α) : + (permutations'Aux a l).bind (permutations'Aux b) ~ + (permutations'Aux b l).bind (permutations'Aux a) := by + induction' l with c l ih + · exact Perm.swap [a, b] [b, a] [] + simp only [permutations'Aux, bind_cons, map_cons, map_map, cons_append] + apply Perm.swap' + have : + ∀ a b, + (map (cons c) (permutations'Aux a l)).bind (permutations'Aux b) ~ + map (cons b ∘ cons c) (permutations'Aux a l) ++ + map (cons c) ((permutations'Aux a l).bind (permutations'Aux b)) := by + intros a' b' + simp only [bind_map, permutations'Aux] + show List.bind (permutations'Aux _ l) (fun a => ([b' :: c :: a] ++ + map (cons c) (permutations'Aux _ a))) ~ _ + refine (bind_append_perm _ (fun x => [b' :: c :: x]) _).symm.trans ?_ + rw [← map_eq_bind, ← map_bind] + exact Perm.refl _ + refine (((this _ _).append_left _).trans ?_).trans ((this _ _).append_left _).symm + rw [← append_assoc, ← append_assoc] + exact perm_append_comm.append (ih.map _) + +theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by + induction p with + | nil => simp + | cons _ _ IH => exact IH.bind_right _ + | swap => + dsimp + rw [bind_assoc, bind_assoc] + apply Perm.bind_left + intro l' _ + apply perm_permutations'Aux_comm + | trans _ _ IH₁ IH₂ => exact IH₁.trans IH₂ + +theorem permutations_perm_permutations' (ts : List α) : ts.permutations ~ ts.permutations' := by + obtain ⟨n, h⟩ : ∃ n, length ts < n := ⟨_, Nat.lt_succ_self _⟩ + induction' n with n IH generalizing ts; · cases h + refine List.reverseRecOn ts (fun _ => ?_) (fun ts t _ h => ?_) h; · simp [permutations] + rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h + have IH₂ := (IH ts.reverse (by rwa [length_reverse])).trans (reverse_perm _).permutations' + simp only [permutations_append, foldr_permutationsAux2, permutationsAux_nil, + permutationsAux_cons, append_nil] + refine + (perm_append_comm.trans ((IH₂.bind_right _).append ((IH _ h).map _))).trans + (Perm.trans ?_ perm_append_comm.permutations') + rw [map_eq_bind, singleton_append, permutations'] + refine (bind_append_perm _ _ _).trans ?_ + refine Perm.of_eq ?_ + congr + funext _ + rw [permutations'Aux_eq_permutationsAux2, permutationsAux2_append] + +@[simp] +theorem mem_permutations' {s t : List α} : s ∈ permutations' t ↔ s ~ t := + (permutations_perm_permutations' _).symm.mem_iff.trans mem_permutations + +theorem Perm.permutations {s t : List α} (h : s ~ t) : permutations s ~ permutations t := + (permutations_perm_permutations' _).trans <| + h.permutations'.trans (permutations_perm_permutations' _).symm + +@[simp] +theorem perm_permutations_iff {s t : List α} : permutations s ~ permutations t ↔ s ~ t := + ⟨fun h => mem_permutations.1 <| h.mem_iff.1 <| mem_permutations.2 (Perm.refl _), + Perm.permutations⟩ + +@[simp] +theorem perm_permutations'_iff {s t : List α} : permutations' s ~ permutations' t ↔ s ~ t := + ⟨fun h => mem_permutations'.1 <| h.mem_iff.1 <| mem_permutations'.2 (Perm.refl _), + Perm.permutations'⟩ + +theorem getElem_permutations'Aux (s : List α) (x : α) (n : ℕ) + (hn : n < length (permutations'Aux x s)) : + (permutations'Aux x s)[n] = s.insertIdx n x := by + induction' s with y s IH generalizing n + · simp only [length, Nat.zero_add, Nat.lt_one_iff] at hn + simp [hn] + · cases n + · simp [get] + · simpa [get] using IH _ _ + +theorem get_permutations'Aux (s : List α) (x : α) (n : ℕ) + (hn : n < length (permutations'Aux x s)) : + (permutations'Aux x s).get ⟨n, hn⟩ = s.insertIdx n x := by + simp [getElem_permutations'Aux] + +theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) : + count (x :: l) (permutations'Aux x l) = length (takeWhile (x = ·) l) + 1 := by + induction' l with y l IH generalizing x + · simp [takeWhile, count] + · rw [permutations'Aux, count_cons_self] + by_cases hx : x = y + · subst hx + 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] + +@[simp] +theorem length_permutations'Aux (s : List α) (x : α) : + length (permutations'Aux x s) = length s + 1 := by + induction' s with y s IH + · simp + · simpa using IH + +@[deprecated (since := "2024-06-12")] +theorem permutations'Aux_get_zero (s : List α) (x : α) + (hn : 0 < length (permutations'Aux x s) := (by simp)) : + (permutations'Aux x s).get ⟨0, hn⟩ = x :: s := + get_permutations'Aux _ _ _ _ + +theorem injective_permutations'Aux (x : α) : Function.Injective (permutations'Aux x) := by + intro s t h + apply insertIdx_injective s.length x + have hl : s.length = t.length := by simpa using congr_arg length h + rw [← get_permutations'Aux s x s.length (by simp), + ← get_permutations'Aux t x s.length (by simp [hl])] + simp only [get_eq_getElem, h, hl] + +theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s) : + Nodup (permutations'Aux x s) := by + induction' s with y s IH + · simp + · simp only [not_or, mem_cons] at hx + simp only [permutations'Aux, nodup_cons, mem_map, cons.injEq, exists_eq_right_right, not_and] + refine ⟨fun _ => Ne.symm hx.left, ?_⟩ + rw [nodup_map_iff] + · exact IH hx.right + · simp + +theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s := by + refine ⟨fun h H ↦ ?_, nodup_permutations'Aux_of_not_mem _ _⟩ + obtain ⟨⟨k, hk⟩, hk'⟩ := get_of_mem H + rw [nodup_iff_injective_get] at h + apply k.succ_ne_self.symm + have kl : k < (permutations'Aux x s).length := by simpa [Nat.lt_succ_iff] using hk.le + have k1l : k + 1 < (permutations'Aux x s).length := by simpa using hk + 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)] + 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), + get_insertIdx_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))] + · rw [get_insertIdx_self _ _ _ hk.le, get_insertIdx_of_lt _ _ _ _ (Nat.lt_succ_self _) hk, hk'] + · rcases (Nat.succ_le_of_lt H).eq_or_lt with (rfl | H') + · rw [get_insertIdx_self _ _ _ (Nat.succ_le_of_lt hk)] + 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 [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] + · simp [Nat.add_left_comm, Nat.add_comm] + · simpa [Nat.succ_add] using hn + +theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations := by + rw [(permutations_perm_permutations' s).nodup_iff] + induction' hs with x l h h' IH + · simp + · rw [permutations'] + rw [nodup_bind] + constructor + · intro ys hy + rw [mem_permutations'] at hy + rw [nodup_permutations'Aux_iff, hy.mem_iff] + exact fun H => h x H rfl + · refine IH.pairwise_of_forall_ne fun as ha bs hb H => ?_ + rw [disjoint_iff_ne] + rintro a ha' b hb' rfl + obtain ⟨⟨n, hn⟩, hn'⟩ := get_of_mem ha' + obtain ⟨⟨m, hm⟩, hm'⟩ := get_of_mem hb' + rw [mem_permutations'] at ha hb + 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 + simp [hn', ← hm', hm] + have hx' : + (insertIdx m x bs)[n]'(by rwa [length_insertIdx _ _ 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)] + exact get_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)] + exact get_mem _ _ _ + +lemma permutations_take_two (x y : α) (s : List α) : + (x :: y :: s).permutations.take 2 = [x :: y :: s, y :: x :: s] := by + induction s <;> simp only [take, permutationsAux, permutationsAux.rec, permutationsAux2, id_eq] + +@[simp] +theorem nodup_permutations_iff {s : List α} : Nodup s.permutations ↔ Nodup s := by + refine ⟨?_, nodup_permutations s⟩ + contrapose + rw [← exists_duplicate_iff_not_nodup] + intro ⟨x, hs⟩ + rw [duplicate_iff_sublist] at hs + obtain ⟨l, ht⟩ := List.Sublist.exists_perm_append hs + rw [List.Perm.nodup_iff (List.Perm.permutations ht), ← exists_duplicate_iff_not_nodup] + use x :: x :: l + rw [List.duplicate_iff_sublist, ← permutations_take_two] + exact take_sublist 2 _ + +-- TODO: `count s s.permutations = (zipWith count s s.tails).prod` + end List diff --git a/Mathlib/Data/List/Prime.lean b/Mathlib/Data/List/Prime.lean index 45c8f957e4d93..2dce64c46d9df 100644 --- a/Mathlib/Data/List/Prime.lean +++ b/Mathlib/Data/List/Prime.lean @@ -5,7 +5,6 @@ Authors: Johannes Hölzl, Jens Wagemaker, Anne Baanen -/ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.List -import Mathlib.Data.List.Perm /-! # Products of lists of prime elements. diff --git a/Mathlib/Data/List/Range.lean b/Mathlib/Data/List/Range.lean index 63ca906ece471..9f779d7aa545b 100644 --- a/Mathlib/Data/List/Range.lean +++ b/Mathlib/Data/List/Range.lean @@ -42,10 +42,6 @@ theorem chain_range_succ (r : ℕ → ℕ → Prop) (n a : ℕ) : rw [range_succ_eq_map, chain_cons, and_congr_right_iff, ← chain'_range_succ, range_succ_eq_map] exact fun _ => Iff.rfl -/-- All elements of `Fin n`, from `0` to `n-1`. The corresponding finset is `Finset.univ`. -/ -def finRange (n : ℕ) : List (Fin n) := - (range n).pmap Fin.mk fun _ => List.mem_range.1 - @[simp] theorem finRange_zero : finRange 0 = [] := rfl diff --git a/Mathlib/Data/List/Rotate.lean b/Mathlib/Data/List/Rotate.lean index 04072b6a698df..1a80659086cc6 100644 --- a/Mathlib/Data/List/Rotate.lean +++ b/Mathlib/Data/List/Rotate.lean @@ -51,7 +51,7 @@ theorem rotate'_cons_succ (l : List α) (a : α) (n : ℕ) : @[simp] theorem length_rotate' : ∀ (l : List α) (n : ℕ), (l.rotate' n).length = l.length | [], _ => by simp - | a :: l, 0 => rfl + | _ :: _, 0 => rfl | a :: l, n + 1 => by rw [List.rotate', length_rotate' (l ++ [a]) n]; simp theorem rotate'_eq_drop_append_take : @@ -610,7 +610,7 @@ variable [DecidableEq α] instance isRotatedDecidable (l l' : List α) : Decidable (l ~r l') := decidable_of_iff' _ isRotated_iff_mem_map_range -instance {l l' : List α} : Decidable (@Setoid.r _ (IsRotated.setoid α) l l') := +instance {l l' : List α} : Decidable (IsRotated.setoid α l l') := List.isRotatedDecidable _ _ end Decidable diff --git a/Mathlib/Data/List/Sigma.lean b/Mathlib/Data/List/Sigma.lean index ba2c572fe9480..2ca3f245e6cdf 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -3,8 +3,9 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Sean Leather -/ -import Mathlib.Data.List.Perm import Mathlib.Data.List.Pairwise +import Mathlib.Data.List.Perm.Basic +import Mathlib.Data.List.Nodup /-! # Utilities for lists of sigmas @@ -63,7 +64,7 @@ theorem not_mem_keys {a} {l : List (Sigma β)} : a ∉ l.keys ↔ ∀ b : β a, theorem not_eq_key {a} {l : List (Sigma β)} : a ∉ l.keys ↔ ∀ s : Sigma β, s ∈ l → a ≠ s.1 := Iff.intro (fun h₁ s h₂ e => absurd (mem_keys_of_mem h₂) (by rwa [e] at h₁)) fun f h₁ => - let ⟨b, h₂⟩ := exists_of_mem_keys h₁ + let ⟨_, h₂⟩ := exists_of_mem_keys h₁ f _ h₂ rfl /-! ### `NodupKeys` -/ @@ -365,7 +366,7 @@ theorem Perm.kreplace {a : α} {b : β a} {l₁ l₂ : List (Sigma β)} (nd : l def kerase (a : α) : List (Sigma β) → List (Sigma β) := eraseP fun s => a = s.1 --- Porting note (#10618): removing @[simp], `simp` can prove it +@[simp] theorem kerase_nil {a} : @kerase _ β _ a [] = [] := rfl diff --git a/Mathlib/Data/List/Sort.lean b/Mathlib/Data/List/Sort.lean index be93169d29b88..6733b9df5e8a3 100644 --- a/Mathlib/Data/List/Sort.lean +++ b/Mathlib/Data/List/Sort.lean @@ -3,39 +3,20 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad -/ +import Batteries.Data.List.Pairwise import Mathlib.Data.List.OfFn import Mathlib.Data.List.Nodup import Mathlib.Order.Fin.Basic -import Batteries.Data.List.Perm /-! # Sorting algorithms on lists In this file we define `List.Sorted r l` to be an alias for `List.Pairwise r l`. This alias is preferred in the case that `r` is a `<` or `≤`-like relation. -Then we define two sorting algorithms: -`List.insertionSort` and `List.mergeSort'`, and prove their correctness. +Then we define the sorting algorithm +`List.insertionSort` and prove its correctness. -/ -#adaptation_note -/-- -`List.mergeSort` has now been implemented in Lean4. -It improves on the one here by being a "stable" sort -(in the sense that a sorted sublist of the original list remains a sublist of the result), -and is also marginally faster. - -However we haven't yet replaced `List.mergeSort'` here. -The obstacle is that `mergeSort'` is written using `r : α → α → Prop` with `[DecidableRel r]`, -while `mergeSort` uses `r : α → α → Bool`. This is hardly insurmountable, -but it's a bit of work that hasn't been done yet. - -`List.mergeSort'` is only used in Mathlib to sort multisets for printing, so this is not critical. - -A pull request cleaning up here, and ideally deprecating or deleting `List.mergeSort'`, -would be welcome. --/ - - open List.Perm universe u v @@ -49,7 +30,7 @@ namespace List section Sorted -variable {α : Type u} {β : Type v} {r : α → α → Prop} {s : β → β → Prop} {a : α} {l : List α} +variable {α : Type u} {r : α → α → Prop} {a : α} {l : List α} /-- `Sorted r l` is the same as `List.Pairwise r l`, preferred in the case that `r` is a `<` or `≤`-like relation (transitive and antisymmetric or asymmetric) -/ @@ -88,6 +69,18 @@ theorem Sorted.tail {r : α → α → Prop} {l : List α} (h : Sorted r l) : So theorem rel_of_sorted_cons {a : α} {l : List α} : Sorted r (a :: l) → ∀ b ∈ l, r a b := rel_of_pairwise_cons +nonrec theorem Sorted.cons {r : α → α → Prop} [IsTrans α r] {l : List α} {a b : α} + (hab : r a b) (h : Sorted r (b :: l)) : Sorted r (a :: b :: l) := + h.cons <| forall_mem_cons.2 ⟨hab, fun _ hx => _root_.trans hab <| rel_of_sorted_cons h _ hx⟩ + +theorem sorted_cons_cons {r : α → α → Prop} [IsTrans α r] {l : List α} {a b : α} : + Sorted r (b :: a :: l) ↔ r b a ∧ Sorted r (a :: l) := by + constructor + · intro h + exact ⟨rel_of_sorted_cons h _ (mem_cons_self a _), h.of_cons⟩ + · rintro ⟨h, ha⟩ + exact ha.cons h + theorem Sorted.head!_le [Inhabited α] [Preorder α] {a : α} {l : List α} (h : Sorted (· < ·) l) (ha : a ∈ l) : l.head! ≤ a := by rw [← List.cons_head!_tail (List.ne_nil_of_mem ha)] at h ha @@ -153,6 +146,14 @@ theorem Sorted.rel_of_mem_take_of_mem_drop {l : List α} (h : List.Sorted r l) { rw [length_take] at hix exact h.rel_get_of_lt (Nat.lt_add_right _ (Nat.lt_min.mp hix).left) +/-- +If a list is sorted with respect to a decidable relation, +then it is sorted with respect to the corresponding Bool-valued relation. +-/ +theorem Sorted.decide [DecidableRel r] (l : List α) (h : Sorted r l) : + Sorted (fun a b => decide (r a b) = true) l := by + refine h.imp fun {a b} h => by simpa using h + end Sorted section Monotone @@ -208,12 +209,17 @@ def insertionSort : List α → List α | [] => [] | b :: l => orderedInsert r b (insertionSort l) +-- A quick check that insertionSort is stable: +example : + insertionSort (fun m n => m / 10 ≤ n / 10) [5, 27, 221, 95, 17, 43, 7, 2, 98, 567, 23, 12] = + [5, 7, 2, 17, 12, 27, 23, 43, 95, 98, 221, 567] := rfl + @[simp] theorem orderedInsert_nil (a : α) : [].orderedInsert r a = [a] := rfl theorem orderedInsert_length : ∀ (L : List α) (a : α), (L.orderedInsert r a).length = L.length + 1 - | [], a => rfl + | [], _ => rfl | hd :: tl, a => by dsimp [orderedInsert] split_ifs <;> simp [orderedInsert_length tl] @@ -313,7 +319,7 @@ variable {r} it. -/ theorem Sorted.insertionSort_eq : ∀ {l : List α}, Sorted r l → insertionSort r l = l | [], _ => rfl - | [a], _ => rfl + | [_], _ => rfl | a :: b :: l, h => by rw [insertionSort, Sorted.insertionSort_eq, orderedInsert, if_pos] exacts [rel_of_sorted_cons h _ (mem_cons_self _ _), h.tail] @@ -480,192 +486,61 @@ end Correctness end InsertionSort -/-! ### Merge sort -/ - - -section MergeSort +/-! ### Merge sort --- TODO(Jeremy): observation: if instead we write (a :: (split l).1, b :: (split l).2), the --- equation compiler can't prove the third equation -/-- Split `l` into two lists of approximately equal length. - - split [1, 2, 3, 4, 5] = ([1, 3, 5], [2, 4]) -/ -@[simp] -def split : List α → List α × List α - | [] => ([], []) - | a :: l => - let (l₁, l₂) := split l - (a :: l₂, l₁) - -theorem split_cons_of_eq (a : α) {l l₁ l₂ : List α} (h : split l = (l₁, l₂)) : - split (a :: l) = (a :: l₂, l₁) := by rw [split, h] +We provide some wrapper functions around the theorems for `mergeSort` provided in Lean, +which rather than using explicit hypotheses for transitivity and totality, +use Mathlib order typeclasses instead. +-/ -@[simp] -theorem map_split (f : α → β) : - ∀ l : List α, (map f l).split = (l.split.1.map f, l.split.2.map f) - | [] => rfl - | a :: l => by simp [map_split] +unseal merge mergeSort in +example : + mergeSort [5, 27, 221, 95, 17, 43, 7, 2, 98, 567, 23, 12] (fun m n => m / 10 ≤ n / 10) = + [5, 7, 2, 17, 12, 27, 23, 43, 95, 98, 221, 567] := rfl -@[simp] -theorem mem_split_iff {x : α} : ∀ {l : List α}, x ∈ l.split.1 ∨ x ∈ l.split.2 ↔ x ∈ l - | [] => by simp - | a :: l => by simp_rw [split, mem_cons, or_assoc, or_comm, mem_split_iff] - -theorem length_split_le : - ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l - | [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0⟩ - | a :: l, l₁', l₂', h => by - cases' e : split l with l₁ l₂ - injection (split_cons_of_eq _ e).symm.trans h; substs l₁' l₂' - cases' length_split_le e with h₁ h₂ - exact ⟨Nat.succ_le_succ h₂, Nat.le_succ_of_le h₁⟩ - -theorem length_split_fst_le (l : List α) : length (split l).1 ≤ length l := - (length_split_le rfl).1 - -theorem length_split_snd_le (l : List α) : length (split l).2 ≤ length l := - (length_split_le rfl).2 - -theorem length_split_lt {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) : - length l₁ < length (a :: b :: l) ∧ length l₂ < length (a :: b :: l) := by - cases' e : split l with l₁' l₂' - injection (split_cons_of_eq _ (split_cons_of_eq _ e)).symm.trans h; substs l₁ l₂ - cases' length_split_le e with h₁ h₂ - exact ⟨Nat.succ_le_succ (Nat.succ_le_succ h₁), Nat.succ_le_succ (Nat.succ_le_succ h₂)⟩ - -theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → l ~ l₁ ++ l₂ - | [], _, _, rfl => Perm.refl _ - | a :: l, l₁', l₂', h => by - cases' e : split l with l₁ l₂ - injection (split_cons_of_eq _ e).symm.trans h; substs l₁' l₂' - exact ((perm_split e).trans perm_append_comm).cons a - -/-- Implementation of a merge sort algorithm to sort a list. -/ -def mergeSort' : List α → List α - | [] => [] - | [a] => [a] - | a :: b :: l => by - -- Porting note: rewrote to make `mergeSort_cons_cons` proof easier - let ls := (split (a :: b :: l)) - have := length_split_fst_le l - have := length_split_snd_le l - exact merge (mergeSort' ls.1) (mergeSort' ls.2) (r · ·) - termination_by l => length l - -@[nolint unusedHavesSuffices] -- Porting note: false positive -theorem mergeSort'_cons_cons {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) : - mergeSort' r (a :: b :: l) = merge (mergeSort' r l₁) (mergeSort' r l₂) (r · ·) := by - simp only [mergeSort', h] +section MergeSort section Correctness -theorem perm_mergeSort' : ∀ l : List α, mergeSort' r l ~ l - | [] => by simp [mergeSort'] - | [a] => by simp [mergeSort'] - | a :: b :: l => by - cases' e : split (a :: b :: l) with l₁ l₂ - cases' length_split_lt e with h₁ h₂ - rw [mergeSort'_cons_cons r e] - apply (perm_merge (r · ·) _ _).trans - exact - ((perm_mergeSort' l₁).append (perm_mergeSort' l₂)).trans (perm_split e).symm - termination_by l => length l - -@[simp] -theorem mem_mergeSort' {l : List α} {x : α} : x ∈ l.mergeSort' r ↔ x ∈ l := - (perm_mergeSort' r l).mem_iff - -@[simp] -theorem length_mergeSort' (l : List α) : (mergeSort' r l).length = l.length := - (perm_mergeSort' r _).length_eq - section TotalAndTransitive variable {r} [IsTotal α r] [IsTrans α r] -theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sorted r (merge l l' (r · ·) ) - | [], [], _, _ => by simp - | [], b :: l', _, h₂ => by simpa using h₂ - | a :: l, [], h₁, _ => by simpa using h₁ - | a :: l, b :: l', h₁, h₂ => by - by_cases h : a ≼ b - · suffices ∀ b' ∈ List.merge l (b :: l') (r · ·) , r a b' by - simpa [h, h₁.of_cons.merge h₂] - intro b' bm - rcases show b' = b ∨ b' ∈ l ∨ b' ∈ l' by - simpa [or_left_comm] using (perm_merge _ _ _).subset bm with - (be | bl | bl') - · subst b' - assumption - · exact rel_of_sorted_cons h₁ _ bl - · exact _root_.trans h (rel_of_sorted_cons h₂ _ bl') - · suffices ∀ b' ∈ List.merge (a :: l) l' (r · ·) , r b b' by - simpa [h, h₁.merge h₂.of_cons] - intro b' bm - have ba : b ≼ a := (total_of r _ _).resolve_left h - have : b' = a ∨ b' ∈ l ∨ b' ∈ l' := by simpa using (perm_merge _ _ _).subset bm - rcases this with (be | bl | bl') - · subst b' - assumption - · exact _root_.trans ba (rel_of_sorted_cons h₁ _ bl) - · exact rel_of_sorted_cons h₂ _ bl' +theorem Sorted.merge {l l' : List α} (h : Sorted r l) (h' : Sorted r l') : + Sorted r (merge l l' (r · ·)) := by + simpa using sorted_merge (le := (r · ·)) + (fun a b c h₁ h₂ => by simpa using _root_.trans (by simpa using h₁) (by simpa using h₂)) + (fun a b => by simpa using IsTotal.total a b) + l l' (by simpa using h) (by simpa using h') variable (r) -theorem sorted_mergeSort' : ∀ l : List α, Sorted r (mergeSort' r l) - | [] => by simp [mergeSort'] - | [a] => by simp [mergeSort'] - | a :: b :: l => by - cases' e : split (a :: b :: l) with l₁ l₂ - cases' length_split_lt e with h₁ h₂ - rw [mergeSort'_cons_cons r e] - exact (sorted_mergeSort' l₁).merge (sorted_mergeSort' l₂) - termination_by l => length l - -theorem mergeSort'_eq_self [IsAntisymm α r] {l : List α} : Sorted r l → mergeSort' r l = l := - eq_of_perm_of_sorted (perm_mergeSort' _ _) (sorted_mergeSort' _ _) - -theorem mergeSort'_eq_insertionSort [IsAntisymm α r] (l : List α) : - mergeSort' r l = insertionSort r l := - eq_of_perm_of_sorted ((perm_mergeSort' r l).trans (perm_insertionSort r l).symm) - (sorted_mergeSort' r l) (sorted_insertionSort r l) +/-- Variant of `sorted_mergeSort` using order typeclasses. -/ +theorem sorted_mergeSort' [Preorder α] [DecidableRel ((· : α) ≤ ·)] [IsTotal α (· ≤ ·)] + (l : List α) : Sorted (· ≤ ·) (mergeSort l) := by + simpa using sorted_mergeSort (le := fun a b => a ≤ b) + (fun a b c h₁ h₂ => by simpa using le_trans (by simpa using h₁) (by simpa using h₂)) + (fun a b => by simpa using IsTotal.total a b) + l + +theorem mergeSort_eq_self [LinearOrder α] {l : List α} : Sorted (· ≤ ·) l → mergeSort l = l := + eq_of_perm_of_sorted (mergeSort_perm _ _) (sorted_mergeSort' l) + +theorem mergeSort_eq_insertionSort [IsAntisymm α r] (l : List α) : + mergeSort l (r · ·) = insertionSort r l := + eq_of_perm_of_sorted ((mergeSort_perm l _).trans (perm_insertionSort r l).symm) + (sorted_mergeSort (le := (r · ·)) + (fun a b c h₁ h₂ => by simpa using _root_.trans (by simpa using h₁) (by simpa using h₂)) + (fun a b => by simpa using IsTotal.total a b) + l) + (sorted_insertionSort r l).decide end TotalAndTransitive end Correctness -@[simp] -theorem mergeSort'_nil : [].mergeSort' r = [] := by rw [List.mergeSort'] - -@[simp] -theorem mergeSort'_singleton (a : α) : [a].mergeSort' r = [a] := by rw [List.mergeSort'] - -theorem map_mergeSort' (f : α → β) (l : List α) (hl : ∀ a ∈ l, ∀ b ∈ l, a ≼ b ↔ f a ≼ f b) : - (l.mergeSort' r).map f = (l.map f).mergeSort' s := - match l with - | [] => by simp - | [x] => by simp - | a :: b :: l => by - simp_rw [← mem_split_iff (l := a :: b :: l), or_imp, forall_and] at hl - set l₁ := (split (a :: b :: l)).1 - set l₂ := (split (a :: b :: l)).2 - have e : split (a :: b :: l) = (l₁, l₂) := rfl - have fe : split (f a :: f b :: l.map f) = (l₁.map f, l₂.map f) := by - rw [← map, ← map, map_split, e] - have := length_split_fst_le l - have := length_split_snd_le l - simp_rw [List.map] - rw [List.mergeSort'_cons_cons _ e, List.mergeSort'_cons_cons _ fe, - map_merge, map_mergeSort' _ l₁ hl.1.1, map_mergeSort' _ l₂ hl.2.2] - simp_rw [mem_mergeSort', decide_eq_decide] - exact hl.1.2 - termination_by length l - end MergeSort end sort --- try them out! ---#eval insertionSort (fun m n : ℕ => m ≤ n) [5, 27, 221, 95, 17, 43, 7, 2, 98, 567, 23, 12] ---#eval mergeSort' (fun m n : ℕ => m ≤ n) [5, 27, 221, 95, 17, 43, 7, 2, 98, 567, 23, 12] end List diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index 3d8300bd2d98a..ca72c47e62664 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Data.Nat.Choose.Basic -import Mathlib.Data.List.Perm import Mathlib.Data.List.Range +import Mathlib.Data.List.Perm.Basic /-! # sublists @@ -205,7 +205,7 @@ theorem sublistsLenAux_append : ∀ (n : ℕ) (l : List α) (f : List α → β) (g : β → γ) (r : List β) (s : List γ), sublistsLenAux n l (g ∘ f) (r.map g ++ s) = (sublistsLenAux n l f r).map g ++ s | 0, l, f, g, r, s => by unfold sublistsLenAux; simp - | n + 1, [], f, g, r, s => rfl + | _ + 1, [], _, _, _, _ => rfl | n + 1, a :: l, f, g, r, s => by unfold sublistsLenAux simp only [show (g ∘ f) ∘ List.cons a = g ∘ f ∘ List.cons a by rfl, sublistsLenAux_append, @@ -327,12 +327,9 @@ theorem nodup_sublists {l : List α} : Nodup (sublists l) ↔ Nodup l := theorem nodup_sublists' {l : List α} : Nodup (sublists' l) ↔ Nodup l := by rw [sublists'_eq_sublists, nodup_map_iff reverse_injective, nodup_sublists, nodup_reverse] -alias ⟨nodup.of_sublists, nodup.sublists⟩ := nodup_sublists +protected alias ⟨Nodup.of_sublists, Nodup.sublists⟩ := nodup_sublists -alias ⟨nodup.of_sublists', nodup.sublists'⟩ := nodup_sublists' - --- Porting note: commented out ---attribute [protected] nodup.sublists nodup.sublists' +protected alias ⟨Nodup.of_sublists', _⟩ := nodup_sublists' theorem nodup_sublistsLen (n : ℕ) {l : List α} (h : Nodup l) : (sublistsLen n l).Nodup := by have : Pairwise (· ≠ ·) l.sublists' := Pairwise.imp @@ -378,7 +375,7 @@ theorem revzip_sublists (l : List α) : ∀ l₁ l₂, (l₁, l₂) ∈ revzip l · intro l₁ l₂ h rw [sublists_concat, reverse_append, zip_append (by simp), ← map_reverse, zip_map_right, zip_map_left] at * - simp only [Prod.mk.inj_iff, mem_map, mem_append, Prod.map_mk, Prod.exists] at h + simp only [Prod.mk.inj_iff, mem_map, mem_append, Prod.map_apply, Prod.exists] at h rcases h with (⟨l₁, l₂', h, rfl, rfl⟩ | ⟨l₁', l₂, h, rfl, rfl⟩) · rw [← append_assoc] exact (ih _ _ h).append_right _ diff --git a/Mathlib/Data/List/TFAE.lean b/Mathlib/Data/List/TFAE.lean index f9bce9204f88b..3dd02febe8c13 100644 --- a/Mathlib/Data/List/TFAE.lean +++ b/Mathlib/Data/List/TFAE.lean @@ -33,7 +33,7 @@ theorem tfae_singleton (p) : TFAE [p] := by simp [TFAE, -eq_iff_iff] theorem tfae_cons_of_mem {a b} {l : List Prop} (h : b ∈ l) : TFAE (a :: l) ↔ (a ↔ b) ∧ TFAE l := ⟨fun H => ⟨H a (by simp) b (Mem.tail a h), - fun p hp q hq => H _ (Mem.tail a hp) _ (Mem.tail a hq)⟩, + fun _ hp _ hq => H _ (Mem.tail a hp) _ (Mem.tail a hq)⟩, by rintro ⟨ab, H⟩ p (_ | ⟨_, hp⟩) q (_ | ⟨_, hq⟩) · rfl diff --git a/Mathlib/Data/List/Zip.lean b/Mathlib/Data/List/Zip.lean index cb8b7daa47501..a05e606d213ad 100644 --- a/Mathlib/Data/List/Zip.lean +++ b/Mathlib/Data/List/Zip.lean @@ -31,7 +31,7 @@ variable {α : Type u} {β γ δ ε : Type*} @[simp] theorem zip_swap : ∀ (l₁ : List α) (l₂ : List β), (zip l₁ l₂).map Prod.swap = zip l₂ l₁ - | [], l₂ => zip_nil_right.symm + | [], _ => zip_nil_right.symm | l₁, [] => by rw [zip_nil_right]; rfl | a :: l₁, b :: l₂ => by simp only [zip_cons_cons, map_cons, zip_swap l₁ l₂, Prod.swap_prod_mk] diff --git a/Mathlib/Data/MLList/Dedup.lean b/Mathlib/Data/MLList/Dedup.lean index f608048a51890..736453f47d9f1 100644 --- a/Mathlib/Data/MLList/Dedup.lean +++ b/Mathlib/Data/MLList/Dedup.lean @@ -36,7 +36,6 @@ def dedupBy (L : MLList m α) (f : α → m β) : MLList m α := /-- Lazily deduplicate a lazy list, using a stored `HashMap`. -/ @[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] -def dedup (L : MLList m β) : MLList m β := - L.dedupBy (fun b => pure b) +def dedup (L : MLList m β) : MLList m β := L.dedupBy pure end MLList diff --git a/Mathlib/Data/Matrix/Basic.lean b/Mathlib/Data/Matrix/Basic.lean index 63bc543ba910b..543197f1454dc 100644 --- a/Mathlib/Data/Matrix/Basic.lean +++ b/Mathlib/Data/Matrix/Basic.lean @@ -14,6 +14,7 @@ import Mathlib.Algebra.Star.BigOperators import Mathlib.Algebra.Star.Module import Mathlib.Algebra.Star.Pi import Mathlib.Data.Fintype.BigOperators +import Mathlib.LinearAlgebra.Pi /-! # Matrices @@ -334,6 +335,31 @@ instance subsingleton_of_empty_right [IsEmpty n] : Subsingleton (Matrix m n α) ext i j exact isEmptyElim j⟩ +/-- This is `Matrix.of` bundled as an additive equivalence. -/ +def ofAddEquiv [Add α] : (m → n → α) ≃+ Matrix m n α where + __ := of + map_add' _ _ := rfl + +@[simp] lemma coe_ofAddEquiv [Add α] : + ⇑(ofAddEquiv : (m → n → α) ≃+ Matrix m n α) = of := rfl +@[simp] lemma coe_ofAddEquiv_symm [Add α] : + ⇑(ofAddEquiv.symm : Matrix m n α ≃+ (m → n → α)) = of.symm := rfl + +section +variable (R) + +/-- This is `Matrix.of` bundled as a linear equivalence. -/ +def ofLinearEquiv [Semiring R] [AddCommMonoid α] [Module R α] : (m → n → α) ≃ₗ[R] Matrix m n α where + __ := ofAddEquiv + map_smul' _ _ := rfl + +@[simp] lemma coe_ofLinearEquiv [Semiring R] [AddCommMonoid α] [Module R α] : + ⇑(ofLinearEquiv _ : (m → n → α) ≃ₗ[R] Matrix m n α) = of := rfl +@[simp] lemma coe_ofLinearEquiv_symm [Semiring R] [AddCommMonoid α] [Module R α] : + ⇑((ofLinearEquiv _).symm : Matrix m n α ≃ₗ[R] (m → n → α)) = of.symm := rfl + +end + end Matrix open Matrix @@ -1169,7 +1195,7 @@ variable [CommSemiring R] [Semiring α] [Semiring β] [Algebra R α] [Algebra R instance instAlgebra : Algebra R (Matrix n n α) where toRingHom := (Matrix.scalar n).comp (algebraMap R α) - commutes' r x := scalar_commute _ (fun r' => Algebra.commutes _ _) _ + commutes' _ _ := scalar_commute _ (fun _ => Algebra.commutes _ _) _ smul_def' r x := by ext; simp [Matrix.scalar, Algebra.smul_def r] theorem algebraMap_matrix_apply {r : R} {i j : n} : @@ -1209,6 +1235,93 @@ def diagonalAlgHom : (n → α) →ₐ[R] Matrix n n α := end Algebra +section AddHom + +variable [Add α] + +variable (R α) in +/-- Extracting entries from a matrix as an additive homomorphism. -/ +@[simps] +def entryAddHom (i : m) (j : n) : AddHom (Matrix m n α) α where + toFun M := M i j + map_add' _ _ := rfl + +-- It is necessary to spell out the name of the coercion explicitly on the RHS +-- for unification to succeed +lemma entryAddHom_eq_comp {i : m} {j : n} : + entryAddHom α i j = + ((Pi.evalAddHom _ j).comp (Pi.evalAddHom _ i)).comp (AddHomClass.toAddHom ofAddEquiv.symm) := + rfl + +end AddHom + +section AddMonoidHom + +variable [AddZeroClass α] + +variable (R α) in +/-- +Extracting entries from a matrix as an additive monoid homomorphism. Note this cannot be upgraded to +a ring homomorphism, as it does not respect multiplication. +-/ +@[simps] +def entryAddMonoidHom (i : m) (j : n) : Matrix m n α →+ α where + toFun M := M i j + map_add' _ _ := rfl + map_zero' := rfl + +-- It is necessary to spell out the name of the coercion explicitly on the RHS +-- for unification to succeed +lemma entryAddMonoidHom_eq_comp {i : m} {j : n} : + entryAddMonoidHom α i j = + ((Pi.evalAddMonoidHom _ j).comp (Pi.evalAddMonoidHom _ i)).comp + (AddMonoidHomClass.toAddMonoidHom ofAddEquiv.symm) := by + rfl + +@[simp] lemma evalAddMonoidHom_comp_diagAddMonoidHom (i : m) : + (Pi.evalAddMonoidHom _ i).comp (diagAddMonoidHom m α) = entryAddMonoidHom α i i := by + simp [AddMonoidHom.ext_iff] + +@[simp] lemma entryAddMonoidHom_toAddHom {i : m} {j : n} : + (entryAddMonoidHom α i j : AddHom _ _) = entryAddHom α i j := rfl + +end AddMonoidHom + +section LinearMap + +variable [Semiring R] [AddCommMonoid α] [Module R α] + +variable (R α) in +/-- +Extracting entries from a matrix as a linear map. Note this cannot be upgraded to an algebra +homomorphism, as it does not respect multiplication. +-/ +@[simps] +def entryLinearMap (i : m) (j : n) : + Matrix m n α →ₗ[R] α where + toFun M := M i j + map_add' _ _ := rfl + map_smul' _ _ := rfl + +-- It is necessary to spell out the name of the coercion explicitly on the RHS +-- for unification to succeed +lemma entryLinearMap_eq_comp {i : m} {j : n} : + entryLinearMap R α i j = + LinearMap.proj j ∘ₗ LinearMap.proj i ∘ₗ (ofLinearEquiv R).symm.toLinearMap := by + rfl + +@[simp] lemma proj_comp_diagLinearMap (i : m) : + LinearMap.proj i ∘ₗ diagLinearMap m R α = entryLinearMap R α i i := by + simp [LinearMap.ext_iff] + +@[simp] lemma entryLinearMap_toAddMonoidHom {i : m} {j : n} : + (entryLinearMap R α i j : _ →+ _) = entryAddMonoidHom α i j := rfl + +@[simp] lemma entryLinearMap_toAddHom {i : m} {j : n} : + (entryLinearMap R α i j : AddHom _ _) = entryAddHom α i j := rfl + +end LinearMap + end Matrix /-! @@ -1263,6 +1376,9 @@ theorem mapMatrix_comp (f : β →+ γ) (g : α →+ β) : f.mapMatrix.comp g.mapMatrix = ((f.comp g).mapMatrix : Matrix m n α →+ _) := rfl +@[simp] lemma entryAddMonoidHom_comp_mapMatrix (f : α →+ β) (i : m) (j : n) : + (entryAddMonoidHom β i j).comp f.mapMatrix = f.comp (entryAddMonoidHom α i j) := rfl + end AddMonoidHom namespace AddEquiv @@ -1291,6 +1407,10 @@ theorem mapMatrix_trans (f : α ≃+ β) (g : β ≃+ γ) : f.mapMatrix.trans g.mapMatrix = ((f.trans g).mapMatrix : Matrix m n α ≃+ _) := rfl +@[simp] lemma entryAddHom_comp_mapMatrix (f : α ≃+ β) (i : m) (j : n) : + (entryAddHom β i j).comp (AddHomClass.toAddHom f.mapMatrix) = + (f : AddHom α β).comp (entryAddHom _ i j) := rfl + end AddEquiv namespace LinearMap @@ -1315,6 +1435,9 @@ theorem mapMatrix_comp (f : β →ₗ[R] γ) (g : α →ₗ[R] β) : f.mapMatrix.comp g.mapMatrix = ((f.comp g).mapMatrix : Matrix m n α →ₗ[R] _) := rfl +@[simp] lemma entryLinearMap_comp_mapMatrix (f : α →ₗ[R] β) (i : m) (j : n) : + entryLinearMap R _ i j ∘ₗ f.mapMatrix = f ∘ₗ entryLinearMap R _ i j := rfl + end LinearMap namespace LinearEquiv @@ -1345,6 +1468,15 @@ theorem mapMatrix_trans (f : α ≃ₗ[R] β) (g : β ≃ₗ[R] γ) : f.mapMatrix.trans g.mapMatrix = ((f.trans g).mapMatrix : Matrix m n α ≃ₗ[R] _) := rfl +@[simp] lemma mapMatrix_toLinearMap (f : α ≃ₗ[R] β) : + (f.mapMatrix : _ ≃ₗ[R] Matrix m n β).toLinearMap = f.toLinearMap.mapMatrix := by + rfl + +@[simp] lemma entryLinearMap_comp_mapMatrix (f : α ≃ₗ[R] β) (i : m) (j : n) : + entryLinearMap R _ i j ∘ₗ f.mapMatrix.toLinearMap = + f.toLinearMap ∘ₗ entryLinearMap R _ i j := by + simp only [mapMatrix_toLinearMap, LinearMap.entryLinearMap_comp_mapMatrix] + end LinearEquiv namespace RingHom @@ -1359,7 +1491,7 @@ def mapMatrix (f : α →+* β) : Matrix m m α →+* Matrix m m β := { f.toAddMonoidHom.mapMatrix with toFun := fun M => M.map f map_one' := by simp - map_mul' := fun L M => Matrix.map_mul } + map_mul' := fun _ _ => Matrix.map_mul } @[simp] theorem mapMatrix_id : (RingHom.id α).mapMatrix = RingHom.id (Matrix m m α) := @@ -2111,7 +2243,6 @@ theorem conjTranspose_smul_non_comm [Star R] [Star α] [SMul R α] [SMul Rᵐᵒ (c • M)ᴴ = MulOpposite.op (star c) • Mᴴ := Matrix.ext <| by simp [h] --- @[simp] -- Porting note (#10618): simp can prove this theorem conjTranspose_smul_self [Mul α] [StarMul α] (c : α) (M : Matrix m n α) : (c • M)ᴴ = MulOpposite.op (star c) • Mᴴ := conjTranspose_smul_non_comm c M star_mul @@ -2449,7 +2580,6 @@ theorem reindex_apply (eₘ : m ≃ l) (eₙ : n ≃ o) (M : Matrix m n α) : reindex eₘ eₙ M = M.submatrix eₘ.symm eₙ.symm := rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem reindex_refl_refl (A : Matrix m n α) : reindex (Equiv.refl _) (Equiv.refl _) A = A := A.submatrix_id_id @@ -2472,7 +2602,6 @@ theorem conjTranspose_reindex [Star α] (eₘ : m ≃ l) (eₙ : n ≃ o) (M : M (reindex eₘ eₙ M)ᴴ = reindex eₙ eₘ Mᴴ := rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem submatrix_mul_transpose_submatrix [Fintype m] [Fintype n] [AddCommMonoid α] [Mul α] (e : m ≃ n) (M : Matrix m n α) : M.submatrix id e * Mᵀ.submatrix e id = M * Mᵀ := by rw [submatrix_mul_equiv, submatrix_id_id] diff --git a/Mathlib/Data/Matrix/Basis.lean b/Mathlib/Data/Matrix/Basis.lean index 01c7a8cf445b6..23333213c522e 100644 --- a/Mathlib/Data/Matrix/Basis.lean +++ b/Mathlib/Data/Matrix/Basis.lean @@ -22,13 +22,21 @@ namespace Matrix open Matrix variable [DecidableEq l] [DecidableEq m] [DecidableEq n] -variable [Semiring α] + +section Zero +variable [Zero α] /-- `stdBasisMatrix i j a` is the matrix with `a` in the `i`-th row, `j`-th column, and zeroes elsewhere. -/ -def stdBasisMatrix (i : m) (j : n) (a : α) : Matrix m n α := fun i' j' => - if i = i' ∧ j = j' then a else 0 +def stdBasisMatrix (i : m) (j : n) (a : α) : Matrix m n α := + of <| fun i' j' => if i = i' ∧ j = j' then a else 0 + +theorem stdBasisMatrix_eq_of_single_single (i : m) (j : n) (a : α) : + stdBasisMatrix i j a = Matrix.of (Pi.single i (Pi.single j a)) := by + ext a b + unfold stdBasisMatrix + by_cases hi : i = a <;> by_cases hj : j = b <;> simp [*] @[simp] theorem smul_stdBasisMatrix [SMulZeroClass R α] (r : R) (i : m) (j : n) (a : α) : @@ -43,12 +51,16 @@ theorem stdBasisMatrix_zero (i : m) (j : n) : stdBasisMatrix i j (0 : α) = 0 := ext simp -theorem stdBasisMatrix_add (i : m) (j : n) (a b : α) : +end Zero + +theorem stdBasisMatrix_add [AddZeroClass α] (i : m) (j : n) (a b : α) : stdBasisMatrix i j (a + b) = stdBasisMatrix i j a + stdBasisMatrix i j b := by - unfold stdBasisMatrix; ext + ext + simp only [stdBasisMatrix, of_apply] split_ifs with h <;> simp [h] -theorem mulVec_stdBasisMatrix [Fintype m] (i : n) (j : m) (c : α) (x : m → α) : +theorem mulVec_stdBasisMatrix [NonUnitalNonAssocSemiring α] [Fintype m] + (i : n) (j : m) (c : α) (x : m → α) : mulVec (stdBasisMatrix i j c) x = Function.update (0 : n → α) i (c * x j) := by ext i' simp [stdBasisMatrix, mulVec, dotProduct] @@ -56,7 +68,7 @@ theorem mulVec_stdBasisMatrix [Fintype m] (i : n) (j : m) (c : α) (x : m → α · simp simp [h, h.symm] -theorem matrix_eq_sum_stdBasisMatrix [Fintype m] [Fintype n] (x : Matrix m n α) : +theorem matrix_eq_sum_stdBasisMatrix [AddCommMonoid α] [Fintype m] [Fintype n] (x : Matrix m n α) : x = ∑ i : m, ∑ j : n, stdBasisMatrix i j (x i j) := by ext i j; symm iterate 2 rw [Finset.sum_apply] @@ -69,7 +81,7 @@ theorem matrix_eq_sum_stdBasisMatrix [Fintype m] [Fintype n] (x : Matrix m n α) @[deprecated (since := "2024-08-11")] alias matrix_eq_sum_std_basis := matrix_eq_sum_stdBasisMatrix -theorem stdBasisMatrix_eq_single_vecMulVec_single (i : m) (j : n) : +theorem stdBasisMatrix_eq_single_vecMulVec_single [MulZeroOneClass α] (i : m) (j : n) : stdBasisMatrix i j (1 : α) = vecMulVec (Pi.single i 1) (Pi.single j 1) := by ext i' j' -- Porting note: lean3 didn't apply `mul_ite`. @@ -78,7 +90,7 @@ theorem stdBasisMatrix_eq_single_vecMulVec_single (i : m) (j : n) : -- TODO: tie this up with the `Basis` machinery of linear algebra -- this is not completely trivial because we are indexing by two types, instead of one @[deprecated stdBasisMatrix_eq_single_vecMulVec_single (since := "2024-08-11")] -theorem std_basis_eq_basis_mul_basis (i : m) (j : n) : +theorem std_basis_eq_basis_mul_basis [MulZeroOneClass α] (i : m) (j : n) : stdBasisMatrix i j (1 : α) = vecMulVec (fun i' => ite (i = i') 1 0) fun j' => ite (j = j') 1 0 := by rw [stdBasisMatrix_eq_single_vecMulVec_single] @@ -86,7 +98,8 @@ theorem std_basis_eq_basis_mul_basis (i : m) (j : n) : -- todo: the old proof used fintypes, I don't know `Finsupp` but this feels generalizable @[elab_as_elim] -protected theorem induction_on' [Finite m] [Finite n] {P : Matrix m n α → Prop} (M : Matrix m n α) +protected theorem induction_on' + [AddCommMonoid α] [Finite m] [Finite n] {P : Matrix m n α → Prop} (M : Matrix m n α) (h_zero : P 0) (h_add : ∀ p q, P p → P q → P (p + q)) (h_std_basis : ∀ (i : m) (j : n) (x : α), P (stdBasisMatrix i j x)) : P M := by cases nonempty_fintype m; cases nonempty_fintype n @@ -96,7 +109,8 @@ protected theorem induction_on' [Finite m] [Finite n] {P : Matrix m n α → Pro apply h_std_basis @[elab_as_elim] -protected theorem induction_on [Finite m] [Finite n] [Nonempty m] [Nonempty n] +protected theorem induction_on + [AddCommMonoid α] [Finite m] [Finite n] [Nonempty m] [Nonempty n] {P : Matrix m n α → Prop} (M : Matrix m n α) (h_add : ∀ p q, P p → P q → P (p + q)) (h_std_basis : ∀ i j x, P (stdBasisMatrix i j x)) : P M := Matrix.induction_on' M @@ -110,7 +124,7 @@ namespace StdBasisMatrix section -variable (i : m) (j : n) (c : α) (i' : m) (j' : n) +variable [Zero α] (i : m) (j : n) (c : α) (i' : m) (j' : n) @[simp] theorem apply_same : stdBasisMatrix i j c i j = c := @@ -118,7 +132,7 @@ theorem apply_same : stdBasisMatrix i j c i j = c := @[simp] theorem apply_of_ne (h : ¬(i = i' ∧ j = j')) : stdBasisMatrix i j c i' j' = 0 := by - simp only [stdBasisMatrix, and_imp, ite_eq_right_iff] + simp only [stdBasisMatrix, and_imp, ite_eq_right_iff, of_apply] tauto @[simp] @@ -132,8 +146,7 @@ theorem apply_of_col_ne (i i' : m) {j j' : n} (hj : j ≠ j') (a : α) : end section - -variable (i j : n) (c : α) (i' j' : n) +variable [Zero α] (i j : n) (c : α) @[simp] theorem diag_zero (h : j ≠ i) : diag (stdBasisMatrix i j c) = 0 := @@ -144,7 +157,10 @@ theorem diag_same : diag (stdBasisMatrix i i c) = Pi.single i c := by ext j by_cases hij : i = j <;> (try rw [hij]) <;> simp [hij] -variable [Fintype n] +end + +section trace +variable [Fintype n] [AddCommMonoid α] (i j : n) (c : α) @[simp] theorem trace_zero (h : j ≠ i) : trace (stdBasisMatrix i j c) = 0 := by @@ -156,6 +172,11 @@ theorem trace_eq : trace (stdBasisMatrix i i c) = c := by -- Porting note: added `-diag_apply` simp [trace, -diag_apply] +end trace + +section mul +variable [Fintype n] [NonUnitalNonAssocSemiring α] (i j : n) (c : α) + @[simp] theorem mul_left_apply_same (b : n) (M : Matrix n n α) : (stdBasisMatrix i j c * M) i b = c * M j b := by simp [mul_apply, stdBasisMatrix] @@ -183,7 +204,7 @@ theorem mul_same (k : n) (d : α) : theorem mul_of_ne {k l : n} (h : j ≠ k) (d : α) : stdBasisMatrix i j c * stdBasisMatrix k l d = 0 := by ext a b - simp only [mul_apply, boole_mul, stdBasisMatrix] + simp only [mul_apply, boole_mul, stdBasisMatrix, of_apply] by_cases h₁ : i = a -- porting note (#10745): was `simp [h₁, h, h.symm]` · simp only [h₁, true_and, mul_ite, ite_mul, zero_mul, mul_zero, ← ite_and, zero_apply] @@ -194,13 +215,13 @@ theorem mul_of_ne {k l : n} (h : j ≠ k) (d : α) : · simp only [h₁, false_and, ite_false, mul_ite, zero_mul, mul_zero, ite_self, Finset.sum_const_zero, zero_apply] -end +end mul end StdBasisMatrix section Commute -variable [Fintype n] +variable [Fintype n] [Semiring α] theorem row_eq_zero_of_commute_stdBasisMatrix {i j k : n} {M : Matrix n n α} (hM : Commute (stdBasisMatrix i j 1) M) (hkj : k ≠ j) : M j k = 0 := by diff --git a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean index 1fef44043ba64..67906c2b869f0 100644 --- a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean +++ b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean @@ -108,12 +108,12 @@ lemma fromRows_toRows (A : Matrix (m₁ ⊕ m₂) n R) : fromRows A.toRows₁ A. lemma fromRows_inj : Function.Injective2 (@fromRows R m₁ m₂ n) := by intros x1 x2 y1 y2 - simp only [Function.funext_iff, ← Matrix.ext_iff] + simp only [funext_iff, ← Matrix.ext_iff] aesop lemma fromColumns_inj : Function.Injective2 (@fromColumns R m n₁ n₂) := by intros x1 x2 y1 y2 - simp only [Function.funext_iff, ← Matrix.ext_iff] + 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) diff --git a/Mathlib/Data/Matrix/DMatrix.lean b/Mathlib/Data/Matrix/DMatrix.lean index d677b3ace646e..cf00fbd771964 100644 --- a/Mathlib/Data/Matrix/DMatrix.lean +++ b/Mathlib/Data/Matrix/DMatrix.lean @@ -20,7 +20,7 @@ In most applications `m` and `n` are finite types. -/ def DMatrix (m : Type u) (n : Type u') (α : m → n → Type v) : Type max u u' v := ∀ i j, α i j -variable {l m n o : Type*} +variable {m n : Type*} variable {α : m → n → Type v} namespace DMatrix @@ -49,7 +49,7 @@ theorem map_apply {M : DMatrix m n α} {β : m → n → Type w} {f : ∀ ⦃i j @[simp] theorem map_map {M : DMatrix m n α} {β : m → n → Type w} {γ : m → n → Type z} {f : ∀ ⦃i j⦄, α i j → β i j} {g : ∀ ⦃i j⦄, β i j → γ i j} : - (M.map f).map g = M.map fun i j x => g (f x) := by ext; simp + (M.map f).map g = M.map fun _ _ x => g (f x) := by ext; simp /-- The transpose of a dmatrix. -/ def transpose (M : DMatrix m n α) : DMatrix n m fun j i => α i j diff --git a/Mathlib/Data/Matrix/DoublyStochastic.lean b/Mathlib/Data/Matrix/DoublyStochastic.lean new file mode 100644 index 0000000000000..8bc91f3996116 --- /dev/null +++ b/Mathlib/Data/Matrix/DoublyStochastic.lean @@ -0,0 +1,139 @@ +/- +Copyright (c) 2024 Bhavik Mehta. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bhavik Mehta +-/ + +import Mathlib.Analysis.Convex.Basic +import Mathlib.LinearAlgebra.Matrix.Permutation + +/-! +# Doubly stochastic matrices + +## Main definitions + +* `doublyStochastic`: a square matrix is doubly stochastic if all entries are nonnegative, and left + or right multiplication by the vector of all 1s gives the vector of all 1s. Equivalently, all + row and column sums are equal to 1. + +## Main statements + +* `convex_doublyStochastic`: The set of doubly stochastic matrices is convex. +* `permMatrix_mem_doublyStochastic`: Any permutation matrix is doubly stochastic. + +## TODO + +Define the submonoids of row-stochastic and column-stochastic matrices. +Show that the submonoid of doubly stochastic matrices is the meet of them, or redefine it as such. + +## Tags + +Doubly stochastic, Birkhoff's theorem, Birkhoff-von Neumann theorem +-/ + +open Finset Function Matrix + +variable {R n : Type*} [Fintype n] [DecidableEq n] + +section OrderedSemiring +variable [OrderedSemiring R] {M : Matrix n n R} + +/-- +A square matrix is doubly stochastic iff all entries are nonnegative, and left or right +multiplication by the vector of all 1s gives the vector of all 1s. +-/ +def doublyStochastic (R n : Type*) [Fintype n] [DecidableEq n] [OrderedSemiring R] : + Submonoid (Matrix n n R) where + carrier := {M | (∀ i j, 0 ≤ M i j) ∧ M *ᵥ 1 = 1 ∧ 1 ᵥ* M = 1 } + mul_mem' {M N} hM hN := by + refine ⟨fun i j => sum_nonneg fun i _ => mul_nonneg (hM.1 _ _) (hN.1 _ _), ?_, ?_⟩ + next => rw [← mulVec_mulVec, hN.2.1, hM.2.1] + next => rw [← vecMul_vecMul, hM.2.2, hN.2.2] + one_mem' := by simp [zero_le_one_elem] + +lemma mem_doublyStochastic : + M ∈ doublyStochastic R n ↔ (∀ i j, 0 ≤ M i j) ∧ M *ᵥ 1 = 1 ∧ 1 ᵥ* M = 1 := + Iff.rfl + +lemma mem_doublyStochastic_iff_sum : + M ∈ doublyStochastic R n ↔ + (∀ i j, 0 ≤ M i j) ∧ (∀ i, ∑ j, M i j = 1) ∧ ∀ j, ∑ i, M i j = 1 := by + simp [funext_iff, doublyStochastic, mulVec, vecMul, dotProduct] + +/-- Every entry of a doubly stochastic matrix is nonnegative. -/ +lemma nonneg_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) {i j : n} : 0 ≤ M i j := + hM.1 _ _ + +/-- Each row sum of a doubly stochastic matrix is 1. -/ +lemma sum_row_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) (i : n) : ∑ j, M i j = 1 := + (mem_doublyStochastic_iff_sum.1 hM).2.1 _ + +/-- Each column sum of a doubly stochastic matrix is 1. -/ +lemma sum_col_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) (j : n) : ∑ i, M i j = 1 := + (mem_doublyStochastic_iff_sum.1 hM).2.2 _ + +/-- A doubly stochastic matrix multiplied with the all-ones column vector is 1. -/ +lemma mulVec_one_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) : M *ᵥ 1 = 1 := + (mem_doublyStochastic.1 hM).2.1 + +/-- The all-ones row vector multiplied with a doubly stochastic matrix is 1. -/ +lemma one_vecMul_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) : 1 ᵥ* M = 1 := + (mem_doublyStochastic.1 hM).2.2 + +/-- Every entry of a doubly stochastic matrix is less than or equal to 1. -/ +lemma le_one_of_mem_doublyStochastic (hM : M ∈ doublyStochastic R n) {i j : n} : + M i j ≤ 1 := by + rw [← sum_row_of_mem_doublyStochastic hM i] + exact single_le_sum (fun k _ => hM.1 _ k) (mem_univ j) + +/-- The set of doubly stochastic matrices is convex. -/ +lemma convex_doublyStochastic : Convex R (doublyStochastic R n : Set (Matrix n n R)) := by + intro x hx y hy a b ha hb h + simp only [SetLike.mem_coe, mem_doublyStochastic_iff_sum] at hx hy ⊢ + simp [add_nonneg, ha, hb, mul_nonneg, hx, hy, sum_add_distrib, ← mul_sum, h] + +/-- Any permutation matrix is doubly stochastic. -/ +lemma permMatrix_mem_doublyStochastic {σ : Equiv.Perm n} : + σ.permMatrix R ∈ doublyStochastic R n := by + rw [mem_doublyStochastic_iff_sum] + refine ⟨fun i j => ?g1, ?g2, ?g3⟩ + case g1 => aesop + case g2 => simp [Equiv.toPEquiv_apply] + case g3 => simp [Equiv.toPEquiv_apply, ← Equiv.eq_symm_apply] + +end OrderedSemiring + +section LinearOrderedSemifield + +variable [LinearOrderedSemifield R] {M : Matrix n n R} + +/-- +A matrix is `s` times a doubly stochastic matrix iff all entries are nonnegative, and all row and +column sums are equal to `s`. + +This lemma is useful for the proof of Birkhoff's theorem - in particular because it allows scaling +by nonnegative factors rather than positive ones only. +-/ +lemma exists_mem_doublyStochastic_eq_smul_iff {M : Matrix n n R} {s : R} (hs : 0 ≤ s) : + (∃ M' ∈ doublyStochastic R n, M = s • M') ↔ + (∀ i j, 0 ≤ M i j) ∧ (∀ i, ∑ j, M i j = s) ∧ (∀ j, ∑ i, M i j = s) := by + classical + constructor + case mp => + rintro ⟨M', hM', rfl⟩ + rw [mem_doublyStochastic_iff_sum] at hM' + simp only [smul_apply, smul_eq_mul, ← mul_sum] + exact ⟨fun i j => mul_nonneg hs (hM'.1 _ _), by simp [hM']⟩ + rcases eq_or_lt_of_le hs with rfl | hs + case inl => + simp only [zero_smul, exists_and_right, and_imp] + intro h₁ h₂ _ + refine ⟨⟨1, Submonoid.one_mem _⟩, ?_⟩ + ext i j + specialize h₂ i + rw [sum_eq_zero_iff_of_nonneg (by simp [h₁ i])] at h₂ + exact h₂ _ (by simp) + rintro ⟨hM₁, hM₂, hM₃⟩ + exact ⟨s⁻¹ • M, by simp [mem_doublyStochastic_iff_sum, ← mul_sum, hs.ne', inv_mul_cancel₀, *]⟩ + +end LinearOrderedSemifield diff --git a/Mathlib/Data/Matrix/DualNumber.lean b/Mathlib/Data/Matrix/DualNumber.lean index 27fb548c65639..22d54e1cafe27 100644 --- a/Mathlib/Data/Matrix/DualNumber.lean +++ b/Mathlib/Data/Matrix/DualNumber.lean @@ -23,8 +23,8 @@ open Matrix TrivSqZeroExt def Matrix.dualNumberEquiv : Matrix n n (DualNumber R) ≃ₐ[R] DualNumber (Matrix n n R) where toFun A := ⟨of fun i j => (A i j).fst, of fun i j => (A i j).snd⟩ invFun d := of fun i j => (d.fst i j, d.snd i j) - left_inv A := Matrix.ext fun i j => TrivSqZeroExt.ext rfl rfl - right_inv d := TrivSqZeroExt.ext (Matrix.ext fun i j => rfl) (Matrix.ext fun i j => rfl) + left_inv _ := Matrix.ext fun _ _ => TrivSqZeroExt.ext rfl rfl + right_inv _ := TrivSqZeroExt.ext (Matrix.ext fun _ _ => rfl) (Matrix.ext fun _ _ => rfl) map_mul' A B := by ext · dsimp [mul_apply] @@ -33,7 +33,7 @@ def Matrix.dualNumberEquiv : Matrix n n (DualNumber R) ≃ₐ[R] DualNumber (Mat · simp_rw [snd_mul, smul_eq_mul, op_smul_eq_mul] simp only [mul_apply, snd_sum, DualNumber.snd_mul, snd_mk, of_apply, fst_mk, add_apply] rw [← Finset.sum_add_distrib] - map_add' A B := TrivSqZeroExt.ext rfl rfl + map_add' _ _ := TrivSqZeroExt.ext rfl rfl commutes' r := by simp_rw [algebraMap_eq_inl', algebraMap_eq_diagonal, Pi.algebraMap_def, Algebra.id.map_eq_self, algebraMap_eq_inl, ← diagonal_map (inl_zero R), map_apply, fst_inl, diff --git a/Mathlib/Data/Matrix/Hadamard.lean b/Mathlib/Data/Matrix/Hadamard.lean index 65b6312faeade..da40578d31dd9 100644 --- a/Mathlib/Data/Matrix/Hadamard.lean +++ b/Mathlib/Data/Matrix/Hadamard.lean @@ -30,8 +30,7 @@ hadamard product, hadamard -/ -variable {α β γ m n : Type*} -variable {R : Type*} +variable {α m n R : Type*} namespace Matrix @@ -124,7 +123,7 @@ end Diagonal section trace variable [Fintype m] [Fintype n] -variable (R) [Semiring α] [Semiring R] [Module R α] +variable (R) [Semiring α] theorem sum_hadamard_eq : (∑ i : m, ∑ j : n, (A ⊙ B) i j) = trace (A * Bᵀ) := rfl diff --git a/Mathlib/Data/Matrix/Kronecker.lean b/Mathlib/Data/Matrix/Kronecker.lean index 61bfd0d4ab97b..9c1172d6755c4 100644 --- a/Mathlib/Data/Matrix/Kronecker.lean +++ b/Mathlib/Data/Matrix/Kronecker.lean @@ -259,11 +259,9 @@ def kroneckerBilinear [CommSemiring R] [Semiring α] [Algebra R α] : hypotheses which can be filled by properties of `*`. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem zero_kronecker [MulZeroClass α] (B : Matrix n p α) : (0 : Matrix l m α) ⊗ₖ B = 0 := kroneckerMap_zero_left _ zero_mul B --- @[simp] -- Porting note (#10618): simp can prove this theorem kronecker_zero [MulZeroClass α] (A : Matrix l m α) : A ⊗ₖ (0 : Matrix n p α) = 0 := kroneckerMap_zero_right _ mul_zero A @@ -327,7 +325,6 @@ theorem ofNat_kronecker [Semiring α] [DecidableEq l] (a : ℕ) [a.AtLeastTwo] ( (blockDiagonal fun _ => (OfNat.ofNat a : α) • B) := diagonal_kronecker _ _ --- @[simp] -- Porting note (#10618): simp can prove this theorem one_kronecker_one [MulZeroOneClass α] [DecidableEq m] [DecidableEq n] : (1 : Matrix m m α) ⊗ₖ (1 : Matrix n n α) = 1 := kroneckerMap_one_one _ zero_mul mul_zero (one_mul _) @@ -443,11 +440,9 @@ def kroneckerTMulBilinear : hypotheses which can be filled by properties of `⊗ₜ`. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem zero_kroneckerTMul (B : Matrix n p β) : (0 : Matrix l m α) ⊗ₖₜ[R] B = 0 := kroneckerMap_zero_left _ (zero_tmul α) B --- @[simp] -- Porting note (#10618): simp can prove this theorem kroneckerTMul_zero (A : Matrix l m α) : A ⊗ₖₜ[R] (0 : Matrix n p β) = 0 := kroneckerMap_zero_right _ (tmul_zero β) A diff --git a/Mathlib/Data/Matrix/Notation.lean b/Mathlib/Data/Matrix/Notation.lean index 34515d69bf4ca..82b807cb9664f 100644 --- a/Mathlib/Data/Matrix/Notation.lean +++ b/Mathlib/Data/Matrix/Notation.lean @@ -180,7 +180,6 @@ theorem dotProduct_cons (v : Fin n.succ → α) (x : α) (w : Fin n → α) : dotProduct v (vecCons x w) = vecHead v * x + dotProduct (vecTail v) w := by simp [dotProduct, Fin.sum_univ_succ, vecHead, vecTail] --- @[simp] -- Porting note (#10618): simp can prove this theorem cons_dotProduct_cons (x : α) (v : Fin n → α) (y : α) (w : Fin n → α) : dotProduct (vecCons x v) (vecCons y w) = x * y + dotProduct v w := by simp @@ -292,7 +291,6 @@ theorem vecMul_cons (v : Fin n.succ → α) (w : o' → α) (B : Fin n → o' ext i simp [vecMul] --- @[simp] -- Porting note (#10618): simp can prove this theorem cons_vecMul_cons (x : α) (v : Fin n → α) (w : o' → α) (B : Fin n → o' → α) : vecCons x v ᵥ* of (vecCons w B) = x • w + v ᵥ* of B := by simp @@ -352,11 +350,9 @@ section SMul variable [NonUnitalNonAssocSemiring α] --- @[simp] -- Porting note (#10618): simp can prove this theorem smul_mat_empty {m' : Type*} (x : α) (A : Fin 0 → m' → α) : x • A = ![] := empty_eq _ --- @[simp] -- Porting note (#10618): simp can prove this theorem smul_mat_cons (x : α) (v : n' → α) (A : Fin m → n' → α) : x • vecCons v A = vecCons (x • v) (x • A) := by ext i diff --git a/Mathlib/Data/Matrix/Reflection.lean b/Mathlib/Data/Matrix/Reflection.lean index 7ac86af668d1c..54ccf4ce38ed2 100644 --- a/Mathlib/Data/Matrix/Reflection.lean +++ b/Mathlib/Data/Matrix/Reflection.lean @@ -36,7 +36,7 @@ open Matrix namespace Matrix -variable {l m n : ℕ} {α β : Type*} +variable {l m n : ℕ} {α : Type*} /-- `∀` with better defeq for `∀ x : Matrix (Fin m) (Fin n) α, P x`. -/ def Forall : ∀ {m n} (_ : Matrix (Fin m) (Fin n) α → Prop), Prop @@ -51,7 +51,7 @@ example (P : Matrix (Fin 2) (Fin 3) α → Prop) : ``` -/ theorem forall_iff : ∀ {m n} (P : Matrix (Fin m) (Fin n) α → Prop), Forall P ↔ ∀ x, P x - | 0, n, P => Iff.symm Fin.forall_fin_zero_pi + | 0, _, _ => Iff.symm Fin.forall_fin_zero_pi | m + 1, n, P => by simp only [Forall, FinVec.forall_iff, forall_iff] exact Iff.symm Fin.forall_fin_succ_pi @@ -73,7 +73,7 @@ example (P : Matrix (Fin 2) (Fin 3) α → Prop) : ``` -/ theorem exists_iff : ∀ {m n} (P : Matrix (Fin m) (Fin n) α → Prop), Exists P ↔ ∃ x, P x - | 0, n, P => Iff.symm Fin.exists_fin_zero_pi + | 0, _, _ => Iff.symm Fin.exists_fin_zero_pi | m + 1, n, P => by simp only [Exists, FinVec.exists_iff, exists_iff] exact Iff.symm Fin.exists_fin_succ_pi @@ -95,7 +95,7 @@ example (a b c d : α) : transpose !![a, b; c, d] = !![a, c; b, d] := (transpose -/ @[simp] theorem transposeᵣ_eq : ∀ {m n} (A : Matrix (Fin m) (Fin n) α), transposeᵣ A = transpose A - | _, 0, A => Subsingleton.elim _ _ + | _, 0, _ => Subsingleton.elim _ _ | m, n + 1, A => Matrix.ext fun i j => by simp_rw [transposeᵣ, transposeᵣ_eq] diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index 5f098b5a7e053..9031fedef544f 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -133,7 +133,7 @@ There are a few design decisions worth discussing. so our notation mirrors common practice. ### Notation - We use a couple of nonstandard conventions in theorem names that are related to the above. + We use a few nonstandard conventions in theorem names that are related to the above. First, we mirror common informal practice by referring explicitly to the `ground` set rather than the notation `E`. (Writing `ground` everywhere in a proof term would be unwieldy, and writing `E` in theorem names would be unnatural to read.) @@ -146,6 +146,10 @@ There are a few design decisions worth discussing. with respect to the ground set, rather than a complement within a type. The lemma `compl_base_dual` is one of the many examples of this. + Finally, in theorem names, matroid predicates that apply to sets + (such as `Base`, `Indep`, `Basis`) are typically used as suffixes rather than prefixes. + For instance, we have `ground_indep_iff_base` rather than `indep_ground_iff_base`. + ## References [1] The standard text on matroid theory @@ -410,11 +414,11 @@ theorem Base.infinite_of_infinite (hB : M.Base B) (h : B.Infinite) (hB₁ : M.Ba by_contra (fun hB_inf ↦ (hB₁.finite_of_finite (not_infinite.mp hB_inf) hB).not_infinite h) theorem Base.finite [FiniteRk M] (hB : M.Base B) : B.Finite := - let ⟨B₀,hB₀⟩ := ‹FiniteRk M›.exists_finite_base + let ⟨_,hB₀⟩ := ‹FiniteRk M›.exists_finite_base hB₀.1.finite_of_finite hB₀.2 hB theorem Base.infinite [InfiniteRk M] (hB : M.Base B) : B.Infinite := - let ⟨B₀,hB₀⟩ := ‹InfiniteRk M›.exists_infinite_base + let ⟨_,hB₀⟩ := ‹InfiniteRk M›.exists_infinite_base hB₀.1.infinite_of_infinite hB₀.2 hB theorem empty_not_base [h : RkPos M] : ¬M.Base ∅ := diff --git a/Mathlib/Data/Matroid/Closure.lean b/Mathlib/Data/Matroid/Closure.lean index 10fddef9acbd1..9849ae57bc974 100644 --- a/Mathlib/Data/Matroid/Closure.lean +++ b/Mathlib/Data/Matroid/Closure.lean @@ -69,7 +69,7 @@ the subtype `↑(Iic M.E)` via `Matroid.SubtypeClosure`, albeit less elegantly. open Set namespace Matroid -variable {ι α : Type*} {M : Matroid α} {F X Y : Set α} {e : α} +variable {ι α : Type*} {M : Matroid α} {F X Y : Set α} {e f : α} section Flat @@ -274,7 +274,7 @@ lemma mem_closure_self (M : Matroid α) (e : α) (he : e ∈ M.E := by aesop_mat section Indep -variable {ι : Sort*} {I J B : Set α} {f x y : α} +variable {ι : Sort*} {I J B : Set α} {x y : α} lemma Indep.closure_eq_setOf_basis_insert (hI : M.Indep I) : M.closure I = {x | M.Basis I (insert x I)} := by @@ -462,7 +462,7 @@ lemma closure_biInter_eq_biInter_closure_of_biUnion_indep {ι : Type*} {A : Set convert closure_iInter_eq_iInter_closure_of_iUnion_indep (Is := fun i : A ↦ I i) (by simpa) <;> simp -lemma Indep.closure_iInter_eq_biInter_closure_of_forall_subset [hι : Nonempty ι] {Js : ι → Set α} +lemma Indep.closure_iInter_eq_biInter_closure_of_forall_subset [Nonempty ι] {Js : ι → Set α} (hI : M.Indep I) (hJs : ∀ i, Js i ⊆ I) : M.closure (⋂ i, Js i) = ⋂ i, M.closure (Js i) := closure_iInter_eq_iInter_closure_of_iUnion_indep _ (hI.subset <| by simpa) @@ -514,6 +514,119 @@ lemma Basis.eq_of_closure_subset (hI : M.Basis I X) (hJI : J ⊆ I) (hJ : X ⊆ @[simp] lemma empty_basis_iff : M.Basis ∅ X ↔ X ⊆ M.closure ∅ := by rw [basis_iff_indep_closure, and_iff_right M.empty_indep, and_iff_left (empty_subset _)] +lemma indep_iff_forall_not_mem_closure_diff (hI : I ⊆ M.E := by aesop_mat) : + M.Indep I ↔ ∀ ⦃e⦄, e ∈ I → e ∉ M.closure (I \ {e}) := by + use fun h e heI he ↦ ((h.closure_inter_eq_self_of_subset diff_subset).subset ⟨he, heI⟩).2 rfl + intro h + obtain ⟨J, hJ⟩ := M.exists_basis I + convert hJ.indep + refine hJ.subset.antisymm' (fun e he ↦ by_contra fun heJ ↦ h he ?_) + exact mem_of_mem_of_subset + (hJ.subset_closure he) (M.closure_subset_closure (subset_diff_singleton hJ.subset heJ)) + +/-- An alternative version of `Matroid.indep_iff_forall_not_mem_closure_diff` where the +hypothesis that `I ⊆ M.E` is contained in the RHS rather than the hypothesis. -/ +lemma indep_iff_forall_not_mem_closure_diff' : + M.Indep I ↔ I ⊆ M.E ∧ ∀ e ∈ I, e ∉ M.closure (I \ {e}) := + ⟨fun h ↦ ⟨h.subset_ground, (indep_iff_forall_not_mem_closure_diff h.subset_ground).mp h⟩, fun h ↦ + (indep_iff_forall_not_mem_closure_diff h.1).mpr h.2⟩ + +lemma Indep.not_mem_closure_diff_of_mem (hI : M.Indep I) (he : e ∈ I) : e ∉ M.closure (I \ {e}) := + (indep_iff_forall_not_mem_closure_diff'.1 hI).2 e he + +lemma indep_iff_forall_closure_diff_ne : + M.Indep I ↔ ∀ ⦃e⦄, e ∈ I → M.closure (I \ {e}) ≠ M.closure I := by + rw [indep_iff_forall_not_mem_closure_diff'] + refine ⟨fun ⟨hIE, h⟩ e heI h_eq ↦ h e heI (h_eq.symm.subset (M.mem_closure_of_mem heI)), + fun h ↦ ⟨fun e heI ↦ by_contra fun heE ↦ h heI ?_,fun e heI hin ↦ h heI ?_⟩⟩ + · rw [← closure_inter_ground, inter_comm, inter_diff_distrib_left, + inter_singleton_eq_empty.mpr heE, diff_empty, inter_comm, closure_inter_ground] + nth_rw 2 [show I = insert e (I \ {e}) by simp [heI]] + rw [← closure_insert_closure_eq_closure_insert, insert_eq_of_mem hin, closure_closure] + +lemma Indep.closure_ssubset_closure (hI : M.Indep I) (hJI : J ⊂ I) : M.closure J ⊂ M.closure I := by + obtain ⟨e, heI, heJ⟩ := exists_of_ssubset hJI + exact (M.closure_subset_closure hJI.subset).ssubset_of_not_subset fun hss ↦ heJ <| + (hI.closure_inter_eq_self_of_subset hJI.subset).subset ⟨hss (M.mem_closure_of_mem heI), heI⟩ + +lemma indep_iff_forall_closure_ssubset_of_ssubset (hI : I ⊆ M.E := by aesop_mat) : + M.Indep I ↔ ∀ ⦃J⦄, J ⊂ I → M.closure J ⊂ M.closure I := by + refine ⟨fun h _ ↦ h.closure_ssubset_closure, + fun h ↦ (indep_iff_forall_not_mem_closure_diff hI).2 fun e heI hecl ↦ ?_⟩ + refine (h (diff_singleton_sSubset.2 heI)).ne ?_ + rw [show I = insert e (I \ {e}) by simp [heI], ← closure_insert_closure_eq_closure_insert, + insert_eq_of_mem hecl] + simp + +lemma Indep.closure_diff_ssubset (hI : M.Indep I) (hX : (I ∩ X).Nonempty) : + M.closure (I \ X) ⊂ M.closure I := by + refine hI.closure_ssubset_closure <| diff_subset.ssubset_of_ne fun h ↦ ?_ + rw [sdiff_eq_left, disjoint_iff_inter_eq_empty] at h + simp [h] at hX + +lemma Indep.closure_diff_singleton_ssubset (hI : M.Indep I) (he : e ∈ I) : + M.closure (I \ {e}) ⊂ M.closure I := + hI.closure_ssubset_closure <| by simpa + end Indep +section insert + +lemma mem_closure_insert (he : e ∉ M.closure X) (hef : e ∈ M.closure (insert f X)) : + f ∈ M.closure (insert e X) := by + rw [← closure_inter_ground] at * + have hfE : f ∈ M.E := by + by_contra! hfE; rw [insert_inter_of_not_mem hfE] at hef; exact he hef + have heE : e ∈ M.E := (M.closure_subset_ground _) hef + rw [insert_inter_of_mem hfE] at hef; rw [insert_inter_of_mem heE] + + obtain ⟨I, hI⟩ := M.exists_basis (X ∩ M.E) + rw [← hI.closure_eq_closure, hI.indep.not_mem_closure_iff] at he + rw [← closure_insert_closure_eq_closure_insert, ← hI.closure_eq_closure, + closure_insert_closure_eq_closure_insert, he.1.mem_closure_iff] at * + rw [or_iff_not_imp_left, dep_iff, insert_comm, + and_iff_left (insert_subset heE (insert_subset hfE hI.indep.subset_ground)), not_not] + intro h + rw [(h.subset (subset_insert _ _)).mem_closure_iff, or_iff_right (h.not_dep), mem_insert_iff, + or_iff_left he.2] at hef + subst hef; apply mem_insert + +lemma closure_exchange (he : e ∈ M.closure (insert f X) \ M.closure X) : + f ∈ M.closure (insert e X) \ M.closure X := + ⟨mem_closure_insert he.2 he.1, fun hf ↦ by + rwa [closure_insert_eq_of_mem_closure hf, diff_self, iff_false_intro (not_mem_empty _)] at he⟩ + +lemma closure_exchange_iff : + e ∈ M.closure (insert f X) \ M.closure X ↔ f ∈ M.closure (insert e X) \ M.closure X := + ⟨closure_exchange, closure_exchange⟩ + +lemma closure_insert_congr (he : e ∈ M.closure (insert f X) \ M.closure X) : + M.closure (insert e X) = M.closure (insert f X) := by + have hf := closure_exchange he + rw [eq_comm, ← closure_closure, ← insert_eq_of_mem he.1, closure_insert_closure_eq_closure_insert, + insert_comm, ← closure_closure, ← closure_insert_closure_eq_closure_insert, + insert_eq_of_mem hf.1, closure_closure, closure_closure] + +lemma closure_diff_eq_self (h : Y ⊆ M.closure (X \ Y)) : M.closure (X \ Y) = M.closure X := by + rw [← diff_union_inter X Y, ← closure_union_closure_left_eq, + union_eq_self_of_subset_right (inter_subset_right.trans h), closure_closure, diff_union_inter] + +lemma closure_diff_singleton_eq_closure (h : e ∈ M.closure (X \ {e})) : + M.closure (X \ {e}) = M.closure X := + closure_diff_eq_self (by simpa) + +lemma subset_closure_diff_iff_closure_eq (h : Y ⊆ X) (hY : Y ⊆ M.E := by aesop_mat) : + Y ⊆ M.closure (X \ Y) ↔ M.closure (X \ Y) = M.closure X := + ⟨closure_diff_eq_self, fun h' ↦ (M.subset_closure_of_subset' h).trans h'.symm.subset⟩ + +lemma mem_closure_diff_singleton_iff_closure (he : e ∈ X) (heE : e ∈ M.E := by aesop_mat) : + e ∈ M.closure (X \ {e}) ↔ M.closure (X \ {e}) = M.closure X := by + simpa using subset_closure_diff_iff_closure_eq (Y := {e}) (X := X) (by simpa) + +end insert + +lemma ext_closure {M₁ M₂ : Matroid α} (h : ∀ X, M₁.closure X = M₂.closure X) : M₁ = M₂ := + eq_of_indep_iff_indep_forall (by simpa using h univ) + (fun _ _ ↦ by simp_rw [indep_iff_forall_closure_diff_ne, h]) + end Matroid diff --git a/Mathlib/Data/Matroid/Dual.lean b/Mathlib/Data/Matroid/Dual.lean index 3d79fbd6d5b3c..73ac1b2d68eba 100644 --- a/Mathlib/Data/Matroid/Dual.lean +++ b/Mathlib/Data/Matroid/Dual.lean @@ -41,7 +41,7 @@ section dual @[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where E := M.E Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B - indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩ + indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun _ hB ↦ ⟨hB, empty_disjoint _⟩)⟩ indep_subset := by rintro I J ⟨hJE, B, hB, hJB⟩ hIJ exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩ diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index 3d56e013d70fa..a1769ebc4fc2f 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -82,7 +82,7 @@ for the inverse of `e`). open Set Matroid -variable {α : Type*} {I B X : Set α} +variable {α : Type*} section IndepMatroid @@ -380,7 +380,7 @@ protected def ofFinset [DecidableEq α] (E : Set α) (Indep : Finset α → Prop (E := E) (Indep := (fun I ↦ (∀ (J : Finset α), (J : Set α) ⊆ I → Indep J))) (indep_empty := by simpa [subset_empty_iff]) - (indep_subset := ( fun I J hJ hIJ K hKI ↦ hJ _ (hKI.trans hIJ) )) + (indep_subset := ( fun _ _ hJ hIJ _ hKI ↦ hJ _ (hKI.trans hIJ) )) (indep_aug := by intro I J hI hIfin hJ hJfin hIJ rw [ncard_eq_toFinset_card _ hIfin, ncard_eq_toFinset_card _ hJfin] at hIJ @@ -388,7 +388,7 @@ protected def ofFinset [DecidableEq α] (E : Set α) (Indep : Finset α → Prop simp only [Finite.mem_toFinset] at aug obtain ⟨e, heJ, heI, hi⟩ := aug exact ⟨e, heJ, heI, fun K hK ↦ indep_subset hi <| Finset.coe_subset.1 (by simpa)⟩ ) - (indep_compact := fun I h J hJ ↦ h _ hJ J.finite_toSet _ Subset.rfl ) + (indep_compact := fun _ h J hJ ↦ h _ hJ J.finite_toSet _ Subset.rfl ) (subset_ground := fun I hI x hxI ↦ by simpa using subset_ground <| hI {x} (by simpa) ) @[simp] theorem ofFinset_E [DecidableEq α] (E : Set α) Indep indep_empty indep_subset indep_aug diff --git a/Mathlib/Data/Matroid/Map.lean b/Mathlib/Data/Matroid/Map.lean index bf22fe80c5b92..2f96ce2ff696f 100644 --- a/Mathlib/Data/Matroid/Map.lean +++ b/Mathlib/Data/Matroid/Map.lean @@ -103,7 +103,7 @@ For this reason, `Matroid.map` requires injectivity to be well-defined in genera open Set Function Set.Notation namespace Matroid -variable {α β : Type*} {f : α → β} {E I s : Set α} {M : Matroid α} {N : Matroid β} +variable {α β : Type*} {f : α → β} {E I : Set α} {M : Matroid α} {N : Matroid β} section comap @@ -116,7 +116,7 @@ def comap (N : Matroid β) (f : α → β) : Matroid α := { E := f ⁻¹' N.E Indep := fun I ↦ N.Indep (f '' I) ∧ InjOn f I indep_empty := by simp - indep_subset := fun I J h hIJ ↦ ⟨h.1.subset (image_subset _ hIJ), InjOn.mono hIJ h.2⟩ + indep_subset := fun _ _ h hIJ ↦ ⟨h.1.subset (image_subset _ hIJ), InjOn.mono hIJ h.2⟩ indep_aug := by rintro I B ⟨hI, hIinj⟩ hImax hBmax obtain ⟨I', hII', hI', hI'inj⟩ := (not_maximal_subset_iff ⟨hI, hIinj⟩).1 hImax @@ -156,7 +156,7 @@ def comap (N : Matroid β) (f : α → β) : Matroid α := refine ⟨J₀, hIJ₀, hJ, hbj.injOn, hJ₀X, fun K hK hKinj hKX hJ₀K ↦ ?_⟩ rw [← hKinj.image_eq_image_iff hJ₀K Subset.rfl, hJmax hK (image_subset_range _ _) (image_subset f hKX) (image_subset f hJ₀K)] - subset_ground := fun I hI e heI ↦ hI.1.subset_ground ⟨e, heI, rfl⟩ } + subset_ground := fun _ hI e heI ↦ hI.1.subset_ground ⟨e, heI, rfl⟩ } @[simp] lemma comap_indep_iff : (N.comap f).Indep I ↔ N.Indep (f '' I) ∧ InjOn f I := Iff.rfl diff --git a/Mathlib/Data/Matroid/Restrict.lean b/Mathlib/Data/Matroid/Restrict.lean index 013d3c6c68740..8b0954f2e1d4a 100644 --- a/Mathlib/Data/Matroid/Restrict.lean +++ b/Mathlib/Data/Matroid/Restrict.lean @@ -66,7 +66,7 @@ open Set namespace Matroid -variable {α : Type*} {M : Matroid α} {R I J X Y : Set α} +variable {α : Type*} {M : Matroid α} {R I X Y : Set α} section restrict @@ -75,7 +75,7 @@ section restrict E := R Indep I := M.Indep I ∧ I ⊆ R indep_empty := ⟨M.empty_indep, empty_subset _⟩ - indep_subset := fun I J h hIJ ↦ ⟨h.1.subset hIJ, hIJ.trans h.2⟩ + indep_subset := fun _ _ h hIJ ↦ ⟨h.1.subset hIJ, hIJ.trans h.2⟩ indep_aug := by rintro I I' ⟨hI, hIY⟩ (hIn : ¬ M.Basis' I R) (hI' : M.Basis' I' R) rw [basis'_iff_basis_inter_ground] at hIn hI' @@ -111,7 +111,7 @@ section restrict simp only [hIJ, and_assoc, maximal_subset_iff, hJ.indep, hJ.subset, and_imp, true_and, hJ.subset.trans hAR] exact fun K hK _ hKA hJK ↦ hJ.eq_of_subset_indep hK hJK hKA - subset_ground I := And.right + subset_ground _ := And.right /-- Change the ground set of a matroid to some `R : Set α`. The independent sets of the restriction are the independent subsets of the new ground set. Most commonly used when `R ⊆ M.E`, diff --git a/Mathlib/Data/Multiset/Antidiagonal.lean b/Mathlib/Data/Multiset/Antidiagonal.lean index df02ceb0f2f41..dea72ad65efc7 100644 --- a/Mathlib/Data/Multiset/Antidiagonal.lean +++ b/Mathlib/Data/Multiset/Antidiagonal.lean @@ -82,7 +82,7 @@ theorem antidiagonal_eq_map_powerset [DecidableEq α] (s : Multiset α) : s.antidiagonal = s.powerset.map fun t ↦ (s - t, t) := by induction' s using Multiset.induction_on with a s hs · simp only [antidiagonal_zero, powerset_zero, Multiset.zero_sub, map_singleton] - · simp_rw [antidiagonal_cons, powerset_cons, map_add, hs, map_map, Function.comp, Prod.map_mk, + · simp_rw [antidiagonal_cons, powerset_cons, map_add, hs, map_map, Function.comp, Prod.map_apply, id, sub_cons, erase_cons_head] rw [add_comm] congr 1 diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index 0c4fb024e449e..0aa5947c0e464 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -5,9 +5,11 @@ Authors: Mario Carneiro -/ import Mathlib.Algebra.Group.Nat import Mathlib.Algebra.Order.Sub.Unbundled.Basic -import Mathlib.Data.List.Perm +import Mathlib.Data.List.Perm.Subperm import Mathlib.Data.Set.List import Mathlib.Order.Hom.Basic +import Mathlib.Data.List.Perm.Lattice +import Mathlib.Data.List.Perm.Basic /-! # Multisets @@ -67,9 +69,12 @@ theorem coe_eq_coe {l₁ l₂ : List α} : (l₁ : Multiset α) = l₂ ↔ l₁ instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ ≈ l₂) := inferInstanceAs (Decidable (l₁ ~ l₂)) +instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (isSetoid α l₁ l₂) := + inferInstanceAs (Decidable (l₁ ~ l₂)) + -- Porting note: `Quotient.recOnSubsingleton₂ s₁ s₂` was in parens which broke elaboration instance decidableEq [DecidableEq α] : DecidableEq (Multiset α) - | s₁, s₂ => Quotient.recOnSubsingleton₂ s₁ s₂ fun _ _ => decidable_of_iff' _ Quotient.eq + | s₁, s₂ => Quotient.recOnSubsingleton₂ s₁ s₂ fun _ _ => decidable_of_iff' _ Quotient.eq_iff_equiv /-- defines a size for a multiset by referring to the size of the underlying list -/ protected @@ -171,7 +176,7 @@ def rec (C_0 : C 0) (C_cons : ∀ a m, C m → C (a ::ₘ m)) (C_cons_heq : ∀ a a' m b, HEq (C_cons a (a' ::ₘ m) (C_cons a' m b)) (C_cons a' (a ::ₘ m) (C_cons a m b))) (m : Multiset α) : C m := - Quotient.hrecOn m (@List.rec α (fun l => C ⟦l⟧) C_0 fun a l b => C_cons a ⟦l⟧ b) fun l l' h => + Quotient.hrecOn m (@List.rec α (fun l => C ⟦l⟧) C_0 fun a l b => C_cons a ⟦l⟧ b) fun _ _ h => h.rec_heq (fun hl _ ↦ by congr 1; exact Quot.sound hl) (C_cons_heq _ _ ⟦_⟧ _) @@ -223,7 +228,6 @@ theorem mem_cons {a b : α} {s : Multiset α} : a ∈ b ::ₘ s ↔ a = b ∨ a theorem mem_cons_of_mem {a b : α} {s : Multiset α} (h : a ∈ s) : a ∈ b ::ₘ s := mem_cons.2 <| Or.inr h --- @[simp] -- Porting note (#10618): simp can prove this theorem mem_cons_self (a : α) (s : Multiset α) : a ∈ a ::ₘ s := mem_cons.2 (Or.inl rfl) @@ -537,6 +541,9 @@ theorem cons_le_of_not_mem (hs : a ∉ s) : a ::ₘ s ≤ t ↔ a ∈ t ∧ s theorem singleton_ne_zero (a : α) : ({a} : Multiset α) ≠ 0 := ne_of_gt (lt_cons_self _ _) +@[simp] +theorem zero_ne_singleton (a : α) : 0 ≠ ({a} : Multiset α) := singleton_ne_zero _ |>.symm + @[simp] theorem singleton_le {a : α} {s : Multiset α} : {a} ≤ s ↔ a ∈ s := ⟨fun h => mem_of_le h (mem_singleton_self _), fun h => @@ -586,17 +593,17 @@ theorem singleton_add (a : α) (s : Multiset α) : {a} + s = a ::ₘ s := private theorem add_le_add_iff_left' {s t u : Multiset α} : s + t ≤ s + u ↔ t ≤ u := Quotient.inductionOn₃ s t u fun _ _ _ => subperm_append_left _ -instance : CovariantClass (Multiset α) (Multiset α) (· + ·) (· ≤ ·) := +instance : AddLeftMono (Multiset α) := ⟨fun _s _t _u => add_le_add_iff_left'.2⟩ -instance : ContravariantClass (Multiset α) (Multiset α) (· + ·) (· ≤ ·) := +instance : AddLeftReflectLE (Multiset α) := ⟨fun _s _t _u => add_le_add_iff_left'.1⟩ instance instAddCommMonoid : AddCancelCommMonoid (Multiset α) where - add_comm := fun s t => Quotient.inductionOn₂ s t fun l₁ l₂ => Quot.sound perm_append_comm + add_comm := fun s t => Quotient.inductionOn₂ s t fun _ _ => Quot.sound perm_append_comm add_assoc := fun s₁ s₂ s₃ => Quotient.inductionOn₃ s₁ s₂ s₃ fun l₁ l₂ l₃ => congr_arg _ <| append_assoc l₁ l₂ l₃ - zero_add := fun s => Quot.inductionOn s fun l => rfl + zero_add := fun s => Quot.inductionOn s fun _ => rfl add_zero := fun s => Quotient.inductionOn s fun l => congr_arg _ <| append_nil l add_left_cancel := fun _ _ _ h => le_antisymm (Multiset.add_le_add_iff_left'.mp h.le) (Multiset.add_le_add_iff_left'.mp h.ge) @@ -864,6 +871,10 @@ theorem nsmul_singleton (a : α) (n) : n • ({a} : Multiset α) = replicate n a theorem replicate_le_replicate (a : α) {k n : ℕ} : replicate k a ≤ replicate n a ↔ k ≤ n := _root_.trans (by rw [← replicate_le_coe, coe_replicate]) (List.replicate_sublist_replicate a) +@[gcongr] +theorem replicate_mono (a : α) {k n : ℕ} (h : k ≤ n) : replicate k a ≤ replicate n a := + (replicate_le_replicate a).2 h + theorem le_replicate_iff {m : Multiset α} {a : α} {n : ℕ} : m ≤ replicate n a ↔ ∃ k ≤ n, m = replicate k a := ⟨fun h => ⟨card m, (card_mono h).trans_eq (card_replicate _ _), @@ -972,6 +983,7 @@ theorem erase_comm (s : Multiset α) (a b : α) : (s.erase a).erase b = (s.erase instance : RightCommutative erase (α := α) := ⟨erase_comm⟩ +@[gcongr] theorem erase_le_erase {s t : Multiset α} (a : α) (h : s ≤ t) : s.erase a ≤ t.erase a := leInductionOn h fun h => (h.erase _).subperm @@ -1151,11 +1163,11 @@ theorem eq_of_mem_map_const {b₁ b₂ : β} {l : List α} (h : b₁ ∈ map (Fu b₁ = b₂ := eq_of_mem_replicate (n := card (l : Multiset α)) <| by rwa [map_const] at h -@[simp] +@[simp, gcongr] theorem map_le_map {f : α → β} {s t : Multiset α} (h : s ≤ t) : map f s ≤ map f t := leInductionOn h fun h => (h.map f).subperm -@[simp] +@[simp, gcongr] theorem map_lt_map {f : α → β} {s t : Multiset α} (h : s < t) : s.map f < t.map f := by refine (map_le_map h.le).lt_of_not_le fun H => h.ne <| eq_of_le_of_card_le h.le ?_ rw [← s.card_map f, ← t.card_map f] @@ -1165,7 +1177,7 @@ theorem map_mono (f : α → β) : Monotone (map f) := fun _ _ => map_le_map theorem map_strictMono (f : α → β) : StrictMono (map f) := fun _ _ => map_lt_map -@[simp] +@[simp, gcongr] theorem map_subset_map {f : α → β} {s t : Multiset α} (H : s ⊆ t) : map f s ⊆ map f t := fun _b m => let ⟨a, h, e⟩ := mem_map.1 m mem_map.2 ⟨a, H h, e⟩ @@ -1403,7 +1415,7 @@ variable {m : Multiset α} /-- If `p` is a decidable predicate, so is the predicate that all elements of a multiset satisfy `p`. -/ -protected def decidableForallMultiset {p : α → Prop} [hp : ∀ a, Decidable (p a)] : +protected def decidableForallMultiset {p : α → Prop} [∀ a, Decidable (p a)] : Decidable (∀ a ∈ m, p a) := Quotient.recOnSubsingleton m fun l => decidable_of_iff (∀ a ∈ l, p a) <| by simp @@ -1414,9 +1426,9 @@ instance decidableDforallMultiset {p : ∀ a ∈ m, Prop} [_hp : ∀ (a) (h : a (@Multiset.decidableForallMultiset _ m.attach (fun a => p a.1 a.2) _) /-- decidable equality for functions whose domain is bounded by multisets -/ -instance decidableEqPiMultiset {β : α → Type*} [h : ∀ a, DecidableEq (β a)] : +instance decidableEqPiMultiset {β : α → Type*} [∀ a, DecidableEq (β a)] : DecidableEq (∀ a ∈ m, β a) := fun f g => - decidable_of_iff (∀ (a) (h : a ∈ m), f a h = g a h) (by simp [Function.funext_iff]) + decidable_of_iff (∀ (a) (h : a ∈ m), f a h = g a h) (by simp [funext_iff]) /-- If `p` is a decidable predicate, so is the existence of an element in a multiset satisfying `p`. -/ @@ -1521,6 +1533,7 @@ theorem le_union_right (s t : Multiset α) : t ≤ s ∪ t := theorem eq_union_left : t ≤ s → s ∪ t = s := tsub_add_cancel_of_le +@[gcongr] theorem union_le_union_right (h : s ≤ t) (u) : s ∪ u ≤ t ∪ u := add_le_add_right (tsub_le_tsub_right h _) u @@ -1626,6 +1639,7 @@ theorem inter_comm (s t : Multiset α) : s ∩ t = t ∩ s := inf_comm _ _ theorem eq_union_right (h : s ≤ t) : s ∪ t = t := by rw [union_comm, eq_union_left h] +@[gcongr] theorem union_le_union_left (h : s ≤ t) (u) : u ∪ s ≤ u ∪ t := sup_le_sup_left h _ @@ -1710,6 +1724,7 @@ theorem filter_zero : filter p 0 = 0 := Please re-enable the linter once we moved to `nightly-2024-06-22` or later. -/ set_option linter.deprecated false in +@[congr] theorem filter_congr {p q : α → Prop} [DecidablePred p] [DecidablePred q] {s : Multiset α} : (∀ x ∈ s, p x ↔ q x) → filter p s = filter q s := Quot.inductionOn s fun _l h => congr_arg ofList <| filter_congr' <| by simpa using h @@ -1726,6 +1741,7 @@ theorem filter_le (s : Multiset α) : filter p s ≤ s := theorem filter_subset (s : Multiset α) : filter p s ⊆ s := subset_of_le <| filter_le _ _ +@[gcongr] theorem filter_le_filter {s t} (h : s ≤ t) : filter p s ≤ filter p t := leInductionOn h fun h => (h.filter (p ·)).subperm @@ -1740,11 +1756,11 @@ variable {p} @[simp] theorem filter_cons_of_pos {a : α} (s) : p a → filter p (a ::ₘ s) = a ::ₘ filter p s := - Quot.inductionOn s fun l h => congr_arg ofList <| List.filter_cons_of_pos <| by simpa using h + Quot.inductionOn s fun _ h => congr_arg ofList <| List.filter_cons_of_pos <| by simpa using h @[simp] theorem filter_cons_of_neg {a : α} (s) : ¬p a → filter p (a ::ₘ s) = filter p s := - Quot.inductionOn s fun l h => congr_arg ofList <| List.filter_cons_of_neg <| by simpa using h + Quot.inductionOn s fun _ h => congr_arg ofList <| List.filter_cons_of_neg <| by simpa using h @[simp] theorem mem_filter {a : α} {s} : a ∈ filter p s ↔ a ∈ s ∧ p a := @@ -1938,6 +1954,7 @@ theorem map_filterMap_of_inv (f : α → Option β) (g : β → α) (H : ∀ x : (s : Multiset α) : map g (filterMap f s) = s := Quot.inductionOn s fun l => congr_arg ofList <| List.map_filterMap_of_inv f g H l +@[gcongr] theorem filterMap_le_filterMap (f : α → Option β) {s t : Multiset α} (h : s ≤ t) : filterMap f s ≤ filterMap f t := leInductionOn h fun h => (h.filterMap _).subperm @@ -2006,6 +2023,7 @@ theorem countP_sub [DecidableEq α] {s t : Multiset α} (h : t ≤ s) : countP p (s - t) = countP p s - countP p t := by simp [countP_eq_card_filter, h, filter_le_filter] +@[gcongr] theorem countP_le_of_le {s t} (h : s ≤ t) : countP p s ≤ countP p t := by simpa [countP_eq_card_filter] using card_le_card (filter_le_filter p h) @@ -2065,6 +2083,7 @@ theorem countP_eq_card {s} : countP p s = card s ↔ ∀ a ∈ s, p a := theorem countP_pos_of_mem {s a} (h : a ∈ s) (pa : p a) : 0 < countP p s := countP_pos.2 ⟨_, h, pa⟩ +@[congr] theorem countP_congr {s s' : Multiset α} (hs : s = s') {p p' : α → Prop} [DecidablePred p] [DecidablePred p'] (hp : ∀ x ∈ s, p x = p' x) : s.countP p = s'.countP p' := by @@ -2108,6 +2127,7 @@ theorem count_cons_of_ne {a b : α} (h : a ≠ b) (s : Multiset α) : count a (b theorem count_le_card (a : α) (s) : count a s ≤ card s := countP_le_card _ _ +@[gcongr] theorem count_le_of_le (a : α) {s t} : s ≤ t → count a s ≤ count a t := countP_le_of_le _ @@ -2518,7 +2538,7 @@ theorem rel_replicate_left {m : Multiset α} {a : α} {r : α → α → Prop} { obtain ⟨b, hb1, hb2⟩ := exists_mem_of_rel_of_mem (rel_flip.2 h) hx rwa [eq_of_mem_replicate hb1] at hb2⟩, fun h => - rel_of_forall (fun x y hx hy => (eq_of_mem_replicate hx).symm ▸ h.2 _ hy) + rel_of_forall (fun _ _ hx hy => (eq_of_mem_replicate hx).symm ▸ h.2 _ hy) (Eq.trans (card_replicate _ _) h.1.symm)⟩ theorem rel_replicate_right {m : Multiset α} {a : α} {r : α → α → Prop} {n : ℕ} : @@ -2558,7 +2578,7 @@ theorem map_injective {f : α → β} (hf : Function.Injective f) : lemma filter_attach' (s : Multiset α) (p : {a // a ∈ s} → Prop) [DecidableEq α] [DecidablePred p] : s.attach.filter p = - (s.filter fun x ↦ ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun x ↦ mem_of_mem_filter) := by + (s.filter fun x ↦ ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun _ ↦ mem_of_mem_filter) := by classical refine Multiset.map_injective Subtype.val_injective ?_ rw [map_filter' _ Subtype.val_injective] diff --git a/Mathlib/Data/Multiset/Bind.lean b/Mathlib/Data/Multiset/Bind.lean index 3fe645c8e220e..89ddc4a81c8f6 100644 --- a/Mathlib/Data/Multiset/Bind.lean +++ b/Mathlib/Data/Multiset/Bind.lean @@ -267,7 +267,7 @@ theorem add_product (s t : Multiset α) (u : Multiset β) : (s + t) ×ˢ u = s @[simp] theorem product_add (s : Multiset α) : ∀ t u : Multiset β, s ×ˢ (t + u) = s ×ˢ t + s ×ˢ u := - Multiset.induction_on s (fun t u => rfl) fun a s IH t u => by + Multiset.induction_on s (fun _ _ => rfl) fun a s IH t u => by rw [cons_product, IH] simp [add_comm, add_left_comm, add_assoc] @@ -322,7 +322,7 @@ theorem add_sigma (s t : Multiset α) (u : ∀ a, Multiset (σ a)) : @[simp] theorem sigma_add : ∀ t u : ∀ a, Multiset (σ a), (s.sigma fun a => t a + u a) = s.sigma t + s.sigma u := - Multiset.induction_on s (fun t u => rfl) fun a s IH t u => by + Multiset.induction_on s (fun _ _ => rfl) fun a s IH t u => by rw [cons_sigma, IH] simp [add_comm, add_left_comm, add_assoc] diff --git a/Mathlib/Data/Multiset/Dedup.lean b/Mathlib/Data/Multiset/Dedup.lean index 4dee768fea017..1c4737c0e1395 100644 --- a/Mathlib/Data/Multiset/Dedup.lean +++ b/Mathlib/Data/Multiset/Dedup.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Data.List.Dedup import Mathlib.Data.Multiset.Nodup /-! diff --git a/Mathlib/Data/Multiset/FinsetOps.lean b/Mathlib/Data/Multiset/FinsetOps.lean index 8cec332c637a5..1df7e981bed4b 100644 --- a/Mathlib/Data/Multiset/FinsetOps.lean +++ b/Mathlib/Data/Multiset/FinsetOps.lean @@ -92,7 +92,7 @@ theorem attach_ndinsert (a : α) (s : Multiset α) : have eq : ∀ h : ∀ p : { x // x ∈ s }, p.1 ∈ s, (fun p : { x // x ∈ s } => ⟨p.val, h p⟩ : { x // x ∈ s } → { x // x ∈ s }) = id := - fun h => funext fun p => Subtype.eq rfl + fun _ => funext fun _ => Subtype.eq rfl have : ∀ (t) (eq : s.ndinsert a = t), t.attach = ndinsert ⟨a, eq ▸ mem_ndinsert_self a s⟩ (s.attach.map fun p => ⟨p.1, eq ▸ mem_ndinsert_of_mem p.2⟩) := by intro t ht diff --git a/Mathlib/Data/Multiset/Fintype.lean b/Mathlib/Data/Multiset/Fintype.lean index ee4962cb23b82..369c39be15028 100644 --- a/Mathlib/Data/Multiset/Fintype.lean +++ b/Mathlib/Data/Multiset/Fintype.lean @@ -217,8 +217,7 @@ theorem Multiset.card_coe (m : Multiset α) : Fintype.card m = Multiset.card m : @[to_additive] theorem Multiset.prod_eq_prod_coe [CommMonoid α] (m : Multiset α) : m.prod = ∏ x : m, (x : α) := by congr - -- Porting note: `simp` fails with "maximum recursion depth has been reached" - erw [map_univ_coe] + simp @[to_additive] theorem Multiset.prod_eq_prod_toEnumFinset [CommMonoid α] (m : Multiset α) : diff --git a/Mathlib/Data/Multiset/Interval.lean b/Mathlib/Data/Multiset/Interval.lean index d4db3e807d935..6602425bbde82 100644 --- a/Mathlib/Data/Multiset/Interval.lean +++ b/Mathlib/Data/Multiset/Interval.lean @@ -51,20 +51,20 @@ theorem uIcc_eq : (Icc_eq _ _).trans <| by simp [uIcc] theorem card_Icc : - (Finset.Icc s t).card = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) := by + #(Finset.Icc s t) = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) := by simp_rw [Icc_eq, Finset.card_map, DFinsupp.card_Icc, Nat.card_Icc, Multiset.toDFinsupp_apply, toDFinsupp_support] theorem card_Ico : - (Finset.Ico s t).card = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 1 := by + #(Finset.Ico s t) = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 1 := by rw [Finset.card_Ico_eq_card_Icc_sub_one, card_Icc] theorem card_Ioc : - (Finset.Ioc s t).card = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 1 := by + #(Finset.Ioc s t) = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 1 := by rw [Finset.card_Ioc_eq_card_Icc_sub_one, card_Icc] theorem card_Ioo : - (Finset.Ioo s t).card = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 2 := by + #(Finset.Ioo s t) = ∏ i ∈ s.toFinset ∪ t.toFinset, (t.count i + 1 - s.count i) - 2 := by rw [Finset.card_Ioo_eq_card_Icc_sub_two, card_Icc] theorem card_uIcc : diff --git a/Mathlib/Data/Multiset/Lattice.lean b/Mathlib/Data/Multiset/Lattice.lean index 194cae4b5a776..43459f4baf5ad 100644 --- a/Mathlib/Data/Multiset/Lattice.lean +++ b/Mathlib/Data/Multiset/Lattice.lean @@ -54,6 +54,7 @@ theorem sup_le {s : Multiset α} {a : α} : s.sup ≤ a ↔ ∀ b ∈ s, b ≤ a theorem le_sup {s : Multiset α} {a : α} (h : a ∈ s) : a ≤ s.sup := sup_le.1 le_rfl _ h +@[gcongr] theorem sup_mono {s₁ s₂ : Multiset α} (h : s₁ ⊆ s₂) : s₁.sup ≤ s₂.sup := sup_le.2 fun _ hb => le_sup (h hb) @@ -124,6 +125,7 @@ theorem le_inf {s : Multiset α} {a : α} : a ≤ s.inf ↔ ∀ b ∈ s, a ≤ b theorem inf_le {s : Multiset α} {a : α} (h : a ∈ s) : s.inf ≤ a := le_inf.1 le_rfl _ h +@[gcongr] theorem inf_mono {s₁ s₂ : Multiset α} (h : s₁ ⊆ s₂) : s₂.inf ≤ s₁.inf := le_inf.2 fun _ hb => inf_le (h hb) diff --git a/Mathlib/Data/Multiset/Nodup.lean b/Mathlib/Data/Multiset/Nodup.lean index 2ea7505ae7caa..6dc1fd10b0a00 100644 --- a/Mathlib/Data/Multiset/Nodup.lean +++ b/Mathlib/Data/Multiset/Nodup.lean @@ -60,7 +60,7 @@ theorem nodup_iff_le {s : Multiset α} : Nodup s ↔ ∀ a : α, ¬a ::ₘ a :: theorem nodup_iff_ne_cons_cons {s : Multiset α} : s.Nodup ↔ ∀ a t, s ≠ a ::ₘ a ::ₘ t := nodup_iff_le.trans - ⟨fun h a t s_eq => h a (s_eq.symm ▸ cons_le_cons a (cons_le_cons a (zero_le _))), fun h a le => + ⟨fun h a _ s_eq => h a (s_eq.symm ▸ cons_le_cons a (cons_le_cons a (zero_le _))), fun h a le => let ⟨t, s_eq⟩ := le_iff_exists_add.mp le h a t (by rwa [cons_add, cons_add, zero_add] at s_eq)⟩ diff --git a/Mathlib/Data/Multiset/Range.lean b/Mathlib/Data/Multiset/Range.lean index f43a5a4f36091..ef904f2a33533 100644 --- a/Mathlib/Data/Multiset/Range.lean +++ b/Mathlib/Data/Multiset/Range.lean @@ -40,7 +40,6 @@ theorem range_subset {m n : ℕ} : range m ⊆ range n ↔ m ≤ n := theorem mem_range {m n : ℕ} : m ∈ range n ↔ m < n := List.mem_range --- Porting note (#10618): removing @[simp], `simp` can prove it theorem not_mem_range_self {n : ℕ} : n ∉ range n := List.not_mem_range_self diff --git a/Mathlib/Data/Multiset/Sort.lean b/Mathlib/Data/Multiset/Sort.lean index 997af93b548c0..7c329e6f85d53 100644 --- a/Mathlib/Data/Multiset/Sort.lean +++ b/Mathlib/Data/Multiset/Sort.lean @@ -10,13 +10,12 @@ import Mathlib.Data.Multiset.Basic # Construct a sorted list from a multiset. -/ +variable {α β : Type*} namespace Multiset open List -variable {α β : Type*} - section sort variable (r : α → α → Prop) [DecidableRel r] [IsTrans α r] [IsAntisymm α r] [IsTotal α r] @@ -25,47 +24,52 @@ variable (r' : β → β → Prop) [DecidableRel r'] [IsTrans β r'] [IsAntisymm /-- `sort s` constructs a sorted list from the multiset `s`. (Uses merge sort algorithm.) -/ def sort (s : Multiset α) : List α := - Quot.liftOn s (mergeSort' r) fun _ _ h => - eq_of_perm_of_sorted ((perm_mergeSort' _ _).trans <| h.trans (perm_mergeSort' _ _).symm) - (sorted_mergeSort' r _) (sorted_mergeSort' r _) + Quot.liftOn s (mergeSort · (r · ·)) fun _ _ h => + eq_of_perm_of_sorted ((mergeSort_perm _ _).trans <| h.trans (mergeSort_perm _ _).symm) + (sorted_mergeSort IsTrans.trans + (fun a b => by simpa using IsTotal.total a b) _) + (sorted_mergeSort IsTrans.trans + (fun a b => by simpa using IsTotal.total a b) _) @[simp] -theorem coe_sort (l : List α) : sort r l = mergeSort' r l := +theorem coe_sort (l : List α) : sort r l = mergeSort l (r · ·) := rfl @[simp] theorem sort_sorted (s : Multiset α) : Sorted r (sort r s) := - Quot.inductionOn s fun _l => sorted_mergeSort' r _ + Quot.inductionOn s fun l => by + simpa using sorted_mergeSort (le := (r · ·)) IsTrans.trans + (fun a b => by simpa using IsTotal.total a b) l @[simp] theorem sort_eq (s : Multiset α) : ↑(sort r s) = s := - Quot.inductionOn s fun _ => Quot.sound <| perm_mergeSort' _ _ + Quot.inductionOn s fun _ => Quot.sound <| mergeSort_perm _ _ @[simp] theorem mem_sort {s : Multiset α} {a : α} : a ∈ sort r s ↔ a ∈ s := by rw [← mem_coe, sort_eq] @[simp] theorem length_sort {s : Multiset α} : (sort r s).length = card s := - Quot.inductionOn s <| length_mergeSort' _ + Quot.inductionOn s <| length_mergeSort @[simp] theorem sort_zero : sort r 0 = [] := - List.mergeSort'_nil r + List.mergeSort_nil @[simp] theorem sort_singleton (a : α) : sort r {a} = [a] := - List.mergeSort'_singleton r a + List.mergeSort_singleton a theorem map_sort (f : α → β) (s : Multiset α) (hs : ∀ a ∈ s, ∀ b ∈ s, r a b ↔ r' (f a) (f b)) : (s.sort r).map f = (s.map f).sort r' := by revert s - exact Quot.ind fun _ => List.map_mergeSort' _ _ _ _ + exact Quot.ind fun l h => map_mergeSort (l := l) (by simpa using h) theorem sort_cons (a : α) (s : Multiset α) : (∀ b ∈ s, r a b) → sort r (a ::ₘ s) = a :: sort r s := by refine Quot.inductionOn s fun l => ?_ - simpa [mergeSort'_eq_insertionSort] using insertionSort_cons r + simpa [mergeSort_eq_insertionSort] using insertionSort_cons r (a := a) (l := l) end sort diff --git a/Mathlib/Data/NNRat/BigOperators.lean b/Mathlib/Data/NNRat/BigOperators.lean index e49a23c8a08e6..547de4bd5a2e7 100644 --- a/Mathlib/Data/NNRat/BigOperators.lean +++ b/Mathlib/Data/NNRat/BigOperators.lean @@ -4,12 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Algebra.Order.BigOperators.Ring.Finset +import Mathlib.Algebra.Order.Ring.Rat import Mathlib.Data.NNRat.Defs /-! # Casting lemmas for non-negative rational numbers involving sums and products -/ -variable {ι α : Type*} +variable {α : Type*} namespace NNRat diff --git a/Mathlib/Data/NNRat/Defs.lean b/Mathlib/Data/NNRat/Defs.lean index e41ecbe750139..e0b69c3d877c3 100644 --- a/Mathlib/Data/NNRat/Defs.lean +++ b/Mathlib/Data/NNRat/Defs.lean @@ -14,7 +14,8 @@ import Mathlib.Algebra.Ring.Rat This file defines the nonnegative rationals as a subtype of `Rat` and provides its basic algebraic order structure. -Note that `NNRat` is not declared as a `Field` here. See `Data.NNRat.Lemmas` for that instance. +Note that `NNRat` is not declared as a `Semifield` here. See `Mathlib.Algebra.Field.Rat` for that +instance. We also define an instance `CanLift ℚ ℚ≥0`. This instance can be used by the `lift` tactic to replace `x : ℚ` and `hx : 0 ≤ x` in the proof context with `x : ℚ≥0` while replacing all occurrences @@ -61,10 +62,18 @@ deriving instance Inhabited for NNRat namespace NNRat -variable {α : Type*} {p q : ℚ≥0} +variable {p q : ℚ≥0} + +instance instNontrivial : Nontrivial ℚ≥0 where exists_pair_ne := ⟨1, 0, by decide⟩ +instance instOrderBot : OrderBot ℚ≥0 where + bot := 0 + bot_le q := q.2 @[simp] lemma val_eq_cast (q : ℚ≥0) : q.1 = q := rfl +instance instCharZero : CharZero ℚ≥0 where + cast_injective a b hab := by simpa using congr_arg num hab + instance canLift : CanLift ℚ ℚ≥0 (↑) fun q ↦ 0 ≤ q where prf q hq := ⟨⟨q, hq⟩, rfl⟩ @@ -106,8 +115,12 @@ theorem coe_nonneg (q : ℚ≥0) : (0 : ℚ) ≤ q := q.2 @[simp, norm_cast] lemma coe_zero : ((0 : ℚ≥0) : ℚ) = 0 := rfl +@[simp] lemma num_zero : num 0 = 0 := rfl +@[simp] lemma den_zero : den 0 = 1 := rfl @[simp, norm_cast] lemma coe_one : ((1 : ℚ≥0) : ℚ) = 1 := rfl +@[simp] lemma num_one : num 1 = 1 := rfl +@[simp] lemma den_one : den 1 = 1 := rfl @[simp, norm_cast] theorem coe_add (p q : ℚ≥0) : ((p + q : ℚ≥0) : ℚ) = p + q := @@ -123,8 +136,6 @@ theorem coe_mul (p q : ℚ≥0) : ((p * q : ℚ≥0) : ℚ) = p * q := @[simp] lemma num_pow (q : ℚ≥0) (n : ℕ) : (q ^ n).num = q.num ^ n := by simp [num, Int.natAbs_pow] @[simp] lemma den_pow (q : ℚ≥0) (n : ℕ) : (q ^ n).den = q.den ^ n := rfl --- Porting note: `bit0` `bit1` are deprecated, so remove these theorems. - @[simp, norm_cast] theorem coe_sub (h : q ≤ p) : ((p - q : ℚ≥0) : ℚ) = p - q := max_eq_left <| le_sub_comm.2 <| by rwa [sub_zero] @@ -136,11 +147,11 @@ theorem coe_eq_zero : (q : ℚ) = 0 ↔ q = 0 := by norm_cast theorem coe_ne_zero : (q : ℚ) ≠ 0 ↔ q ≠ 0 := coe_eq_zero.not -@[norm_cast] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem coe_le_coe : (p : ℚ) ≤ q ↔ p ≤ q := Iff.rfl -@[norm_cast] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem coe_lt_coe : (p : ℚ) < q ↔ p < q := Iff.rfl @@ -283,8 +294,6 @@ theorem toNNRat_lt_iff_lt_coe {p : ℚ≥0} (hq : 0 ≤ q) : toNNRat q < p ↔ q theorem lt_toNNRat_iff_coe_lt {q : ℚ≥0} : q < toNNRat p ↔ ↑q < p := NNRat.gi.gc.lt_iff_lt --- Porting note: `bit0` `bit1` are deprecated, so remove these theorems. - theorem toNNRat_mul (hp : 0 ≤ p) : toNNRat (p * q) = toNNRat p * toNNRat q := by rcases le_total 0 q with hq | hq · ext; simp [toNNRat, hp, hq, max_eq_left, mul_nonneg] @@ -345,7 +354,7 @@ See also `Rat.divInt` and `mkRat`. -/ def divNat (n d : ℕ) : ℚ≥0 := ⟨.divInt n d, Rat.divInt_nonneg (Int.ofNat_zero_le n) (Int.ofNat_zero_le d)⟩ -variable {n₁ n₂ d₁ d₂ d : ℕ} +variable {n₁ n₂ d₁ d₂ : ℕ} @[simp, norm_cast] lemma coe_divNat (n d : ℕ) : (divNat n d : ℚ) = .divInt n d := rfl diff --git a/Mathlib/Data/NNRat/Floor.lean b/Mathlib/Data/NNRat/Floor.lean new file mode 100644 index 0000000000000..9fffafbea6995 --- /dev/null +++ b/Mathlib/Data/NNRat/Floor.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2024 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Data.Rat.Floor + +/-! +# Floor Function for Non-negative Rational Numbers + +## Summary + +We define the `FloorSemiring` instance on `ℚ≥0`, and relate its operators to `NNRat.cast`. + +Note that we cannot talk about `Int.fract`, which currently only works for rings. + +## Tags + +nnrat, rationals, ℚ≥0, floor +-/ + +namespace NNRat + +instance : FloorSemiring ℚ≥0 where + floor q := ⌊q.val⌋₊ + ceil q := ⌈q.val⌉₊ + floor_of_neg h := by simpa using h.trans zero_lt_one + gc_floor {a n} h := by rw [← NNRat.coe_le_coe, Nat.le_floor_iff] <;> norm_cast + gc_ceil {a b} := by rw [← NNRat.coe_le_coe, Nat.ceil_le]; norm_cast + +@[simp, norm_cast] +theorem floor_coe (q : ℚ≥0) : ⌊(q : ℚ)⌋₊ = ⌊q⌋₊ := rfl + +@[simp, norm_cast] +theorem ceil_coe (q : ℚ≥0) : ⌈(q : ℚ)⌉₊ = ⌈q⌉₊ := rfl + +@[simp, norm_cast] +theorem coe_floor (q : ℚ≥0) : ↑⌊q⌋₊ = ⌊(q : ℚ)⌋ := Int.natCast_floor_eq_floor q.coe_nonneg + +@[simp, norm_cast] +theorem coe_ceil (q : ℚ≥0) : ↑⌈q⌉₊ = ⌈(q : ℚ)⌉ := Int.natCast_ceil_eq_ceil q.coe_nonneg + +protected theorem floor_def (q : ℚ≥0) : ⌊q⌋₊ = q.num / q.den := by + rw [← Int.natCast_inj, NNRat.coe_floor, Rat.floor_def, Int.ofNat_ediv, den_coe, num_coe] + +section Semifield + +variable {K} [LinearOrderedSemifield K] [FloorSemiring K] + +@[simp, norm_cast] +theorem floor_cast (x : ℚ≥0) : ⌊(x : K)⌋₊ = ⌊x⌋₊ := + (Nat.floor_eq_iff x.cast_nonneg).2 (mod_cast (Nat.floor_eq_iff x.cast_nonneg).1 (Eq.refl ⌊x⌋₊)) + +@[simp, norm_cast] +theorem ceil_cast (x : ℚ≥0) : ⌈(x : K)⌉₊ = ⌈x⌉₊ := by + obtain rfl | hx := eq_or_ne x 0 + · simp + · refine (Nat.ceil_eq_iff ?_).2 (mod_cast (Nat.ceil_eq_iff ?_).1 (Eq.refl ⌈x⌉₊)) <;> simpa + +end Semifield + +section Field + +variable {K} [LinearOrderedField K] [FloorRing K] + +@[simp, norm_cast] +theorem intFloor_cast (x : ℚ≥0) : ⌊(x : K)⌋ = ⌊(x : ℚ)⌋ := by + rw [Int.floor_eq_iff (α := K), ← coe_floor] + norm_cast + norm_cast + rw [Nat.cast_add_one, ← Nat.floor_eq_iff (zero_le _)] + +@[simp, norm_cast] +theorem intCeil_cast (x : ℚ≥0) : ⌈(x : K)⌉ = ⌈(x : ℚ)⌉ := by + rw [Int.ceil_eq_iff, ← coe_ceil, sub_lt_iff_lt_add] + constructor + · have := NNRat.cast_strictMono (K := K) <| Nat.ceil_lt_add_one <| zero_le x + rw [NNRat.cast_add, NNRat.cast_one] at this + refine Eq.trans_lt ?_ this + norm_cast + · rw [Int.cast_natCast, NNRat.cast_le_natCast] + exact Nat.le_ceil _ + +end Field + +@[norm_cast] +theorem floor_natCast_div_natCast (n d : ℕ) : ⌊(↑n / ↑d : ℚ≥0)⌋₊ = n / d := + Rat.natFloor_natCast_div_natCast n d + +end NNRat diff --git a/Mathlib/Data/NNRat/Lemmas.lean b/Mathlib/Data/NNRat/Lemmas.lean index 4e1ee467939eb..88467e704c1a4 100644 --- a/Mathlib/Data/NNRat/Lemmas.lean +++ b/Mathlib/Data/NNRat/Lemmas.lean @@ -5,6 +5,7 @@ Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Algebra.Field.Rat import Mathlib.Algebra.Group.Indicator +import Mathlib.Algebra.GroupWithZero.Action.End import Mathlib.Algebra.Order.Field.Rat /-! @@ -61,13 +62,6 @@ namespace NNRat variable {p q : ℚ≥0} -@[simp] -lemma num_div_den (q : ℚ≥0) : (q.num : ℚ≥0) / q.den = q := by - ext : 1 - rw [coe_div, coe_natCast, coe_natCast, num, ← Int.cast_natCast, - Int.natAbs_of_nonneg (Rat.num_nonneg.2 q.cast_nonneg)] - exact Rat.num_div_den q - /-- A recursor for nonnegative rationals in terms of numerators and denominators. -/ protected def rec {α : ℚ≥0 → Sort*} (h : ∀ m n : ℕ, α (m / n)) (q : ℚ≥0) : α q := by rw [← num_div_den q]; apply h diff --git a/Mathlib/Data/NNReal/Basic.lean b/Mathlib/Data/NNReal/Basic.lean index 796985dd715ad..be8f76fd33712 100644 --- a/Mathlib/Data/NNReal/Basic.lean +++ b/Mathlib/Data/NNReal/Basic.lean @@ -7,46 +7,19 @@ import Mathlib.Algebra.BigOperators.Expect import Mathlib.Algebra.Order.BigOperators.Ring.Finset import Mathlib.Algebra.Order.Field.Canonical.Basic import Mathlib.Algebra.Order.Nonneg.Floor -import Mathlib.Algebra.Ring.Regular import Mathlib.Data.Real.Pointwise +import Mathlib.Data.NNReal.Defs import Mathlib.Order.ConditionallyCompleteLattice.Group /-! -# Nonnegative real numbers +# Basic results on nonnegative real numbers -In this file we define `NNReal` (notation: `ℝ≥0`) to be the type of non-negative real numbers, -a.k.a. the interval `[0, ∞)`. We also define the following operations and structures on `ℝ≥0`: - -* the order on `ℝ≥0` is the restriction of the order on `ℝ`; these relations define a conditionally - complete linear order with a bottom element, `ConditionallyCompleteLinearOrderBot`; - -* `a + b` and `a * b` are the restrictions of addition and multiplication of real numbers to `ℝ≥0`; - these operations together with `0 = ⟨0, _⟩` and `1 = ⟨1, _⟩` turn `ℝ≥0` into a conditionally - complete linear ordered archimedean commutative semifield; we have no typeclass for this in - `mathlib` yet, so we define the following instances instead: - - - `LinearOrderedSemiring ℝ≥0`; - - `OrderedCommSemiring ℝ≥0`; - - `CanonicallyOrderedCommSemiring ℝ≥0`; - - `LinearOrderedCommGroupWithZero ℝ≥0`; - - `CanonicallyLinearOrderedAddCommMonoid ℝ≥0`; - - `Archimedean ℝ≥0`; - - `ConditionallyCompleteLinearOrderBot ℝ≥0`. - - These instances are derived from corresponding instances about the type `{x : α // 0 ≤ x}` in an - appropriate ordered field/ring/group/monoid `α`, see `Mathlib.Algebra.Order.Nonneg.OrderedRing`. - -* `Real.toNNReal x` is defined as `⟨max x 0, _⟩`, i.e. `↑(Real.toNNReal x) = x` when `0 ≤ x` and - `↑(Real.toNNReal x) = 0` otherwise. - -We also define an instance `CanLift ℝ ℝ≥0`. This instance can be used by the `lift` tactic to -replace `x : ℝ` and `hx : 0 ≤ x` in the proof context with `x : ℝ≥0` while replacing all occurrences -of `x` with `↑x`. This tactic also works for a function `f : α → ℝ` with a hypothesis -`hf : ∀ x, 0 ≤ f x`. +This file contains all results on `NNReal` that do not directly follow from its basic structure. +As a consequence, it is a bit of a random collection of results, and is a good target for cleanup. ## Notations -This file defines `ℝ≥0` as a localized notation for `NNReal`. +This file uses `ℝ≥0` as a localized notation for `NNReal`. -/ assert_not_exists Star @@ -54,212 +27,15 @@ assert_not_exists Star open Function open scoped BigOperators --- to ensure these instances are computable -/-- Nonnegative real numbers. -/ -def NNReal := { r : ℝ // 0 ≤ r } deriving - Zero, One, Semiring, StrictOrderedSemiring, CommMonoidWithZero, CommSemiring, - SemilatticeInf, SemilatticeSup, DistribLattice, OrderedCommSemiring, - CanonicallyOrderedCommSemiring, Inhabited - namespace NNReal -scoped notation "ℝ≥0" => NNReal - noncomputable instance : FloorSemiring ℝ≥0 := Nonneg.floorSemiring -instance instDenselyOrdered : DenselyOrdered ℝ≥0 := Nonneg.instDenselyOrdered -instance : OrderBot ℝ≥0 := inferInstance -instance : Archimedean ℝ≥0 := Nonneg.instArchimedean -instance : MulArchimedean ℝ≥0 := Nonneg.instMulArchimedean -noncomputable instance : Sub ℝ≥0 := Nonneg.sub -noncomputable instance : OrderedSub ℝ≥0 := Nonneg.orderedSub - -noncomputable instance : CanonicallyLinearOrderedSemifield ℝ≥0 := - Nonneg.canonicallyLinearOrderedSemifield - -/-- Coercion `ℝ≥0 → ℝ`. -/ -@[coe] def toReal : ℝ≥0 → ℝ := Subtype.val - -instance : Coe ℝ≥0 ℝ := ⟨toReal⟩ - --- Simp lemma to put back `n.val` into the normal form given by the coercion. -@[simp] -theorem val_eq_coe (n : ℝ≥0) : n.val = n := - rfl - -instance canLift : CanLift ℝ ℝ≥0 toReal fun r => 0 ≤ r := - Subtype.canLift _ - -@[ext] protected theorem eq {n m : ℝ≥0} : (n : ℝ) = (m : ℝ) → n = m := - Subtype.eq - -theorem ne_iff {x y : ℝ≥0} : (x : ℝ) ≠ (y : ℝ) ↔ x ≠ y := - not_congr <| NNReal.eq_iff.symm - -protected theorem «forall» {p : ℝ≥0 → Prop} : - (∀ x : ℝ≥0, p x) ↔ ∀ (x : ℝ) (hx : 0 ≤ x), p ⟨x, hx⟩ := - Subtype.forall - -protected theorem «exists» {p : ℝ≥0 → Prop} : - (∃ x : ℝ≥0, p x) ↔ ∃ (x : ℝ) (hx : 0 ≤ x), p ⟨x, hx⟩ := - Subtype.exists - -/-- Reinterpret a real number `r` as a non-negative real number. Returns `0` if `r < 0`. -/ -noncomputable def _root_.Real.toNNReal (r : ℝ) : ℝ≥0 := - ⟨max r 0, le_max_right _ _⟩ - -theorem _root_.Real.coe_toNNReal (r : ℝ) (hr : 0 ≤ r) : (Real.toNNReal r : ℝ) = r := - max_eq_left hr - -theorem _root_.Real.toNNReal_of_nonneg {r : ℝ} (hr : 0 ≤ r) : r.toNNReal = ⟨r, hr⟩ := by - simp_rw [Real.toNNReal, max_eq_left hr] - -theorem _root_.Real.le_coe_toNNReal (r : ℝ) : r ≤ Real.toNNReal r := - le_max_left r 0 - -@[bound] theorem coe_nonneg (r : ℝ≥0) : (0 : ℝ) ≤ r := r.2 - -@[simp, norm_cast] theorem coe_mk (a : ℝ) (ha) : toReal ⟨a, ha⟩ = a := rfl - -example : Zero ℝ≥0 := by infer_instance - -example : One ℝ≥0 := by infer_instance - -example : Add ℝ≥0 := by infer_instance - -noncomputable example : Sub ℝ≥0 := by infer_instance - -example : Mul ℝ≥0 := by infer_instance - -noncomputable example : Inv ℝ≥0 := by infer_instance - -noncomputable example : Div ℝ≥0 := by infer_instance - -example : LE ℝ≥0 := by infer_instance - -example : Bot ℝ≥0 := by infer_instance - -example : Inhabited ℝ≥0 := by infer_instance - -example : Nontrivial ℝ≥0 := by infer_instance - -protected theorem coe_injective : Injective ((↑) : ℝ≥0 → ℝ) := Subtype.coe_injective - -@[simp, norm_cast] lemma coe_inj {r₁ r₂ : ℝ≥0} : (r₁ : ℝ) = r₂ ↔ r₁ = r₂ := - NNReal.coe_injective.eq_iff - -@[deprecated (since := "2024-02-03")] protected alias coe_eq := coe_inj - -@[simp, norm_cast] lemma coe_zero : ((0 : ℝ≥0) : ℝ) = 0 := rfl - -@[simp, norm_cast] lemma coe_one : ((1 : ℝ≥0) : ℝ) = 1 := rfl - -@[simp] lemma mk_zero : (⟨0, le_rfl⟩ : ℝ≥0) = 0 := rfl -@[simp] lemma mk_one : (⟨1, zero_le_one⟩ : ℝ≥0) = 1 := rfl - -@[simp, norm_cast] -protected theorem coe_add (r₁ r₂ : ℝ≥0) : ((r₁ + r₂ : ℝ≥0) : ℝ) = r₁ + r₂ := - rfl - -@[simp, norm_cast] -protected theorem coe_mul (r₁ r₂ : ℝ≥0) : ((r₁ * r₂ : ℝ≥0) : ℝ) = r₁ * r₂ := - rfl - -@[simp, norm_cast] -protected theorem coe_inv (r : ℝ≥0) : ((r⁻¹ : ℝ≥0) : ℝ) = (r : ℝ)⁻¹ := - rfl - -@[simp, norm_cast] -protected theorem coe_div (r₁ r₂ : ℝ≥0) : ((r₁ / r₂ : ℝ≥0) : ℝ) = (r₁ : ℝ) / r₂ := - rfl - -protected theorem coe_two : ((2 : ℝ≥0) : ℝ) = 2 := rfl - -@[simp, norm_cast] -protected theorem coe_sub {r₁ r₂ : ℝ≥0} (h : r₂ ≤ r₁) : ((r₁ - r₂ : ℝ≥0) : ℝ) = ↑r₁ - ↑r₂ := - max_eq_left <| le_sub_comm.2 <| by simp [show (r₂ : ℝ) ≤ r₁ from h] - -variable {r r₁ r₂ : ℝ≥0} {x y : ℝ} - -@[simp, norm_cast] lemma coe_eq_zero : (r : ℝ) = 0 ↔ r = 0 := by rw [← coe_zero, coe_inj] - -@[simp, norm_cast] lemma coe_eq_one : (r : ℝ) = 1 ↔ r = 1 := by rw [← coe_one, coe_inj] - -@[norm_cast] lemma coe_ne_zero : (r : ℝ) ≠ 0 ↔ r ≠ 0 := coe_eq_zero.not - -@[norm_cast] lemma coe_ne_one : (r : ℝ) ≠ 1 ↔ r ≠ 1 := coe_eq_one.not - -example : CommSemiring ℝ≥0 := by infer_instance - -/-- Coercion `ℝ≥0 → ℝ` as a `RingHom`. - -Porting note (#11215): TODO: what if we define `Coe ℝ≥0 ℝ` using this function? -/ -def toRealHom : ℝ≥0 →+* ℝ where - toFun := (↑) - map_one' := NNReal.coe_one - map_mul' := NNReal.coe_mul - map_zero' := NNReal.coe_zero - map_add' := NNReal.coe_add - -@[simp] theorem coe_toRealHom : ⇑toRealHom = toReal := rfl - -section Actions - -/-- A `MulAction` over `ℝ` restricts to a `MulAction` over `ℝ≥0`. -/ -instance {M : Type*} [MulAction ℝ M] : MulAction ℝ≥0 M := - MulAction.compHom M toRealHom.toMonoidHom - -theorem smul_def {M : Type*} [MulAction ℝ M] (c : ℝ≥0) (x : M) : c • x = (c : ℝ) • x := - rfl - -instance {M N : Type*} [MulAction ℝ M] [MulAction ℝ N] [SMul M N] [IsScalarTower ℝ M N] : - IsScalarTower ℝ≥0 M N where smul_assoc r := (smul_assoc (r : ℝ) : _) - -instance smulCommClass_left {M N : Type*} [MulAction ℝ N] [SMul M N] [SMulCommClass ℝ M N] : - SMulCommClass ℝ≥0 M N where smul_comm r := (smul_comm (r : ℝ) : _) - -instance smulCommClass_right {M N : Type*} [MulAction ℝ N] [SMul M N] [SMulCommClass M ℝ N] : - SMulCommClass M ℝ≥0 N where smul_comm m r := (smul_comm m (r : ℝ) : _) - -/-- A `DistribMulAction` over `ℝ` restricts to a `DistribMulAction` over `ℝ≥0`. -/ -instance {M : Type*} [AddMonoid M] [DistribMulAction ℝ M] : DistribMulAction ℝ≥0 M := - DistribMulAction.compHom M toRealHom.toMonoidHom - -/-- A `Module` over `ℝ` restricts to a `Module` over `ℝ≥0`. -/ -instance {M : Type*} [AddCommMonoid M] [Module ℝ M] : Module ℝ≥0 M := - Module.compHom M toRealHom - --- Porting note (#11215): TODO: after this line, `↑` uses `Algebra.cast` instead of `toReal` -/-- An `Algebra` over `ℝ` restricts to an `Algebra` over `ℝ≥0`. -/ -instance {A : Type*} [Semiring A] [Algebra ℝ A] : Algebra ℝ≥0 A where - smul := (· • ·) - commutes' r x := by simp [Algebra.commutes] - smul_def' r x := by simp [← Algebra.smul_def (r : ℝ) x, smul_def] - toRingHom := (algebraMap ℝ A).comp (toRealHom : ℝ≥0 →+* ℝ) - --- verify that the above produces instances we might care about -example : Algebra ℝ≥0 ℝ := by infer_instance - -example : DistribMulAction ℝ≥0ˣ ℝ := by infer_instance - -end Actions - -example : MonoidWithZero ℝ≥0 := by infer_instance - -example : CommMonoidWithZero ℝ≥0 := by infer_instance - -noncomputable example : CommGroupWithZero ℝ≥0 := by infer_instance @[simp, norm_cast] theorem coe_indicator {α} (s : Set α) (f : α → ℝ≥0) (a : α) : ((s.indicator f a : ℝ≥0) : ℝ) = s.indicator (fun x => ↑(f x)) a := (toRealHom : ℝ≥0 →+ ℝ).map_indicator _ _ _ -@[simp, norm_cast] -theorem coe_pow (r : ℝ≥0) (n : ℕ) : ((r ^ n : ℝ≥0) : ℝ) = (r : ℝ) ^ n := rfl - -@[simp, norm_cast] -theorem coe_zpow (r : ℝ≥0) (n : ℤ) : ((r ^ n : ℝ≥0) : ℝ) = (r : ℝ) ^ n := rfl - @[norm_cast] theorem coe_list_sum (l : List ℝ≥0) : ((l.sum : ℝ≥0) : ℝ) = (l.map (↑)).sum := map_list_sum toRealHom l @@ -300,230 +76,11 @@ theorem _root_.Real.toNNReal_prod_of_nonneg (hf : ∀ a, a ∈ s → 0 ≤ f a) rw [← coe_inj, NNReal.coe_prod, Real.coe_toNNReal _ (Finset.prod_nonneg hf)] exact Finset.prod_congr rfl fun x hxs => by rw [Real.coe_toNNReal _ (hf x hxs)] -@[simp, norm_cast] lemma coe_nsmul (r : ℝ≥0) (n : ℕ) : ↑(n • r) = n • (r : ℝ) := rfl -@[simp, norm_cast] lemma coe_nnqsmul (q : ℚ≥0) (x : ℝ≥0) : ↑(q • x) = (q • x : ℝ) := rfl - -@[simp, norm_cast] -protected theorem coe_natCast (n : ℕ) : (↑(↑n : ℝ≥0) : ℝ) = n := - map_natCast toRealHom n - -@[deprecated (since := "2024-04-17")] -alias coe_nat_cast := NNReal.coe_natCast - --- See note [no_index around OfNat.ofNat] -@[simp, norm_cast] -protected theorem coe_ofNat (n : ℕ) [n.AtLeastTwo] : - (no_index (OfNat.ofNat n : ℝ≥0) : ℝ) = OfNat.ofNat n := - rfl - -@[simp, norm_cast] -protected theorem coe_ofScientific (m : ℕ) (s : Bool) (e : ℕ) : - ↑(OfScientific.ofScientific m s e : ℝ≥0) = (OfScientific.ofScientific m s e : ℝ) := - rfl - -@[simp, norm_cast] -lemma algebraMap_eq_coe : (algebraMap ℝ≥0 ℝ : ℝ≥0 → ℝ) = (↑) := rfl - -noncomputable example : LinearOrder ℝ≥0 := by infer_instance - -@[simp, norm_cast] lemma coe_le_coe : (r₁ : ℝ) ≤ r₂ ↔ r₁ ≤ r₂ := Iff.rfl - -@[simp, norm_cast] lemma coe_lt_coe : (r₁ : ℝ) < r₂ ↔ r₁ < r₂ := Iff.rfl - -@[bound] private alias ⟨_, Bound.coe_lt_coe_of_lt⟩ := coe_lt_coe - -@[simp, norm_cast] lemma coe_pos : (0 : ℝ) < r ↔ 0 < r := Iff.rfl - -@[bound] private alias ⟨_, Bound.coe_pos_of_pos⟩ := coe_pos - -@[simp, norm_cast] lemma one_le_coe : 1 ≤ (r : ℝ) ↔ 1 ≤ r := by rw [← coe_le_coe, coe_one] -@[simp, norm_cast] lemma one_lt_coe : 1 < (r : ℝ) ↔ 1 < r := by rw [← coe_lt_coe, coe_one] -@[simp, norm_cast] lemma coe_le_one : (r : ℝ) ≤ 1 ↔ r ≤ 1 := by rw [← coe_le_coe, coe_one] -@[simp, norm_cast] lemma coe_lt_one : (r : ℝ) < 1 ↔ r < 1 := by rw [← coe_lt_coe, coe_one] - -@[mono] lemma coe_mono : Monotone ((↑) : ℝ≥0 → ℝ) := fun _ _ => NNReal.coe_le_coe.2 - -/-- Alias for the use of `gcongr` -/ -@[gcongr] alias ⟨_, GCongr.toReal_le_toReal⟩ := coe_le_coe - -protected theorem _root_.Real.toNNReal_mono : Monotone Real.toNNReal := fun _ _ h => - max_le_max h (le_refl 0) - -@[simp] -theorem _root_.Real.toNNReal_coe {r : ℝ≥0} : Real.toNNReal r = r := - NNReal.eq <| max_eq_left r.2 - -@[simp] -theorem mk_natCast (n : ℕ) : @Eq ℝ≥0 (⟨(n : ℝ), n.cast_nonneg⟩ : ℝ≥0) n := - NNReal.eq (NNReal.coe_natCast n).symm - -@[deprecated (since := "2024-04-05")] alias mk_coe_nat := mk_natCast - --- Porting note: place this in the `Real` namespace -@[simp] -theorem toNNReal_coe_nat (n : ℕ) : Real.toNNReal n = n := - NNReal.eq <| by simp [Real.coe_toNNReal] - --- See note [no_index around OfNat.ofNat] -@[simp] -theorem _root_.Real.toNNReal_ofNat (n : ℕ) [n.AtLeastTwo] : - Real.toNNReal (no_index (OfNat.ofNat n)) = OfNat.ofNat n := - toNNReal_coe_nat n - -/-- `Real.toNNReal` and `NNReal.toReal : ℝ≥0 → ℝ` form a Galois insertion. -/ -noncomputable def gi : GaloisInsertion Real.toNNReal (↑) := - GaloisInsertion.monotoneIntro NNReal.coe_mono Real.toNNReal_mono Real.le_coe_toNNReal fun _ => - Real.toNNReal_coe - --- note that anything involving the (decidability of the) linear order, --- will be noncomputable, everything else should not be. -example : OrderBot ℝ≥0 := by infer_instance - -example : PartialOrder ℝ≥0 := by infer_instance - -noncomputable example : CanonicallyLinearOrderedAddCommMonoid ℝ≥0 := by infer_instance - -noncomputable example : LinearOrderedAddCommMonoid ℝ≥0 := by infer_instance - -example : DistribLattice ℝ≥0 := by infer_instance - -example : SemilatticeInf ℝ≥0 := by infer_instance - -example : SemilatticeSup ℝ≥0 := by infer_instance - -noncomputable example : LinearOrderedSemiring ℝ≥0 := by infer_instance - -example : OrderedCommSemiring ℝ≥0 := by infer_instance - -noncomputable example : LinearOrderedCommMonoid ℝ≥0 := by infer_instance - -noncomputable example : LinearOrderedCommMonoidWithZero ℝ≥0 := by infer_instance - -noncomputable example : LinearOrderedCommGroupWithZero ℝ≥0 := by infer_instance - -example : CanonicallyOrderedCommSemiring ℝ≥0 := by infer_instance - -example : DenselyOrdered ℝ≥0 := by infer_instance - -example : NoMaxOrder ℝ≥0 := by infer_instance - -instance instPosSMulStrictMono {α} [Preorder α] [MulAction ℝ α] [PosSMulStrictMono ℝ α] : - PosSMulStrictMono ℝ≥0 α where - elim _r hr _a₁ _a₂ ha := (smul_lt_smul_of_pos_left ha (coe_pos.2 hr):) - -instance instSMulPosStrictMono {α} [Zero α] [Preorder α] [MulAction ℝ α] [SMulPosStrictMono ℝ α] : - SMulPosStrictMono ℝ≥0 α where - elim _a ha _r₁ _r₂ hr := (smul_lt_smul_of_pos_right (coe_lt_coe.2 hr) ha :) - -/-- If `a` is a nonnegative real number, then the closed interval `[0, a]` in `ℝ` is order -isomorphic to the interval `Set.Iic a`. -/ --- Porting note (#11215): TODO: restore once `simps` supports `ℝ≥0` @[simps!? apply_coe_coe] -def orderIsoIccZeroCoe (a : ℝ≥0) : Set.Icc (0 : ℝ) a ≃o Set.Iic a where - toEquiv := Equiv.Set.sep (Set.Ici 0) fun x : ℝ => x ≤ a - map_rel_iff' := Iff.rfl - -@[simp] -theorem orderIsoIccZeroCoe_apply_coe_coe (a : ℝ≥0) (b : Set.Icc (0 : ℝ) a) : - (orderIsoIccZeroCoe a b : ℝ) = b := - rfl - -@[simp] -theorem orderIsoIccZeroCoe_symm_apply_coe (a : ℝ≥0) (b : Set.Iic a) : - ((orderIsoIccZeroCoe a).symm b : ℝ) = b := - rfl - --- note we need the `@` to make the `Membership.mem` have a sensible type -theorem coe_image {s : Set ℝ≥0} : - (↑) '' s = { x : ℝ | ∃ h : 0 ≤ x, @Membership.mem ℝ≥0 _ _ s ⟨x, h⟩ } := - Subtype.coe_image - -theorem bddAbove_coe {s : Set ℝ≥0} : BddAbove (((↑) : ℝ≥0 → ℝ) '' s) ↔ BddAbove s := - Iff.intro - (fun ⟨b, hb⟩ => - ⟨Real.toNNReal b, fun ⟨y, _⟩ hys => - show y ≤ max b 0 from le_max_of_le_left <| hb <| Set.mem_image_of_mem _ hys⟩) - fun ⟨b, hb⟩ => ⟨b, fun _ ⟨_, hx, eq⟩ => eq ▸ hb hx⟩ - -theorem bddBelow_coe (s : Set ℝ≥0) : BddBelow (((↑) : ℝ≥0 → ℝ) '' s) := - ⟨0, fun _ ⟨q, _, eq⟩ => eq ▸ q.2⟩ - -noncomputable instance : ConditionallyCompleteLinearOrderBot ℝ≥0 := - Nonneg.conditionallyCompleteLinearOrderBot 0 - -@[norm_cast] -theorem coe_sSup (s : Set ℝ≥0) : (↑(sSup s) : ℝ) = sSup (((↑) : ℝ≥0 → ℝ) '' s) := by - rcases Set.eq_empty_or_nonempty s with rfl|hs - · simp - by_cases H : BddAbove s - · have A : sSup (Subtype.val '' s) ∈ Set.Ici 0 := by - apply Real.sSup_nonneg - rintro - ⟨y, -, rfl⟩ - exact y.2 - exact (@subset_sSup_of_within ℝ (Set.Ici (0 : ℝ)) _ _ (_) s hs H A).symm - · simp only [csSup_of_not_bddAbove H, csSup_empty, bot_eq_zero', NNReal.coe_zero] - apply (Real.sSup_of_not_bddAbove ?_).symm - contrapose! H - exact bddAbove_coe.1 H - -@[simp, norm_cast] -- Porting note: add `simp` -theorem coe_iSup {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨆ i, s i) : ℝ) = ⨆ i, ↑(s i) := by - rw [iSup, iSup, coe_sSup, ← Set.range_comp]; rfl - -@[norm_cast] -theorem coe_sInf (s : Set ℝ≥0) : (↑(sInf s) : ℝ) = sInf (((↑) : ℝ≥0 → ℝ) '' s) := by - rcases Set.eq_empty_or_nonempty s with rfl|hs - · simp only [Set.image_empty, Real.sInf_empty, coe_eq_zero] - exact @subset_sInf_emptyset ℝ (Set.Ici (0 : ℝ)) _ _ (_) - have A : sInf (Subtype.val '' s) ∈ Set.Ici 0 := by - apply Real.sInf_nonneg - rintro - ⟨y, -, rfl⟩ - exact y.2 - exact (@subset_sInf_of_within ℝ (Set.Ici (0 : ℝ)) _ _ (_) s hs (OrderBot.bddBelow s) A).symm - -@[simp] -theorem sInf_empty : sInf (∅ : Set ℝ≥0) = 0 := by - rw [← coe_eq_zero, coe_sInf, Set.image_empty, Real.sInf_empty] - -@[norm_cast] -theorem coe_iInf {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨅ i, s i) : ℝ) = ⨅ i, ↑(s i) := by - rw [iInf, iInf, coe_sInf, ← Set.range_comp]; rfl - theorem le_iInf_add_iInf {ι ι' : Sort*} [Nonempty ι] [Nonempty ι'] {f : ι → ℝ≥0} {g : ι' → ℝ≥0} {a : ℝ≥0} (h : ∀ i j, a ≤ f i + g j) : a ≤ (⨅ i, f i) + ⨅ j, g j := by rw [← NNReal.coe_le_coe, NNReal.coe_add, coe_iInf, coe_iInf] exact le_ciInf_add_ciInf h -example : Archimedean ℝ≥0 := by infer_instance - --- Porting note (#11215): TODO: remove? -instance covariant_add : CovariantClass ℝ≥0 ℝ≥0 (· + ·) (· ≤ ·) := inferInstance - -instance contravariant_add : ContravariantClass ℝ≥0 ℝ≥0 (· + ·) (· < ·) := inferInstance - -instance covariant_mul : CovariantClass ℝ≥0 ℝ≥0 (· * ·) (· ≤ ·) := inferInstance - --- Porting note (#11215): TODO: delete? -nonrec theorem le_of_forall_pos_le_add {a b : ℝ≥0} (h : ∀ ε, 0 < ε → a ≤ b + ε) : a ≤ b := - le_of_forall_pos_le_add h - -theorem lt_iff_exists_rat_btwn (a b : ℝ≥0) : - a < b ↔ ∃ q : ℚ, 0 ≤ q ∧ a < Real.toNNReal q ∧ Real.toNNReal q < b := - Iff.intro - (fun h : (↑a : ℝ) < (↑b : ℝ) => - let ⟨q, haq, hqb⟩ := exists_rat_btwn h - have : 0 ≤ (q : ℝ) := le_trans a.2 <| le_of_lt haq - ⟨q, Rat.cast_nonneg.1 this, by - simp [Real.coe_toNNReal _ this, NNReal.coe_lt_coe.symm, haq, hqb]⟩) - fun ⟨q, _, haq, hqb⟩ => lt_trans haq hqb - -theorem bot_eq_zero : (⊥ : ℝ≥0) = 0 := rfl - -theorem mul_sup (a b c : ℝ≥0) : a * (b ⊔ c) = a * b ⊔ a * c := - mul_max_of_nonneg _ _ <| zero_le a - -theorem sup_mul (a b c : ℝ≥0) : (a ⊔ b) * c = a * c ⊔ b * c := - max_mul_of_nonneg _ _ <| zero_le c - theorem mul_finset_sup {α} (r : ℝ≥0) (s : Finset α) (f : α → ℝ≥0) : r * s.sup f = s.sup fun a => r * f a := Finset.comp_sup_eq_sup_comp _ (NNReal.mul_sup r) (mul_zero r) @@ -535,248 +92,8 @@ theorem finset_sup_mul {α} (s : Finset α) (f : α → ℝ≥0) (r : ℝ≥0) : theorem finset_sup_div {α} {f : α → ℝ≥0} {s : Finset α} (r : ℝ≥0) : s.sup f / r = s.sup fun a => f a / r := by simp only [div_eq_inv_mul, mul_finset_sup] -@[simp, norm_cast] -theorem coe_max (x y : ℝ≥0) : ((max x y : ℝ≥0) : ℝ) = max (x : ℝ) (y : ℝ) := - NNReal.coe_mono.map_max - -@[simp, norm_cast] -theorem coe_min (x y : ℝ≥0) : ((min x y : ℝ≥0) : ℝ) = min (x : ℝ) (y : ℝ) := - NNReal.coe_mono.map_min - -@[simp] -theorem zero_le_coe {q : ℝ≥0} : 0 ≤ (q : ℝ) := - q.2 - -instance instOrderedSMul {M : Type*} [OrderedAddCommMonoid M] [Module ℝ M] [OrderedSMul ℝ M] : - OrderedSMul ℝ≥0 M where - smul_lt_smul_of_pos hab hc := (smul_lt_smul_of_pos_left hab (NNReal.coe_pos.2 hc) : _) - lt_of_smul_lt_smul_of_pos {a b c} hab _ := - lt_of_smul_lt_smul_of_nonneg_left (by exact hab) (NNReal.coe_nonneg c) - -end NNReal - -open NNReal - -namespace Real - -section ToNNReal - -@[simp] -theorem coe_toNNReal' (r : ℝ) : (Real.toNNReal r : ℝ) = max r 0 := - rfl - -@[simp] -theorem toNNReal_zero : Real.toNNReal 0 = 0 := NNReal.eq <| coe_toNNReal _ le_rfl - -@[simp] -theorem toNNReal_one : Real.toNNReal 1 = 1 := NNReal.eq <| coe_toNNReal _ zero_le_one - -@[simp] -theorem toNNReal_pos {r : ℝ} : 0 < Real.toNNReal r ↔ 0 < r := by - simp [← NNReal.coe_lt_coe, lt_irrefl] - -@[simp] -theorem toNNReal_eq_zero {r : ℝ} : Real.toNNReal r = 0 ↔ r ≤ 0 := by - simpa [-toNNReal_pos] using not_iff_not.2 (@toNNReal_pos r) - -theorem toNNReal_of_nonpos {r : ℝ} : r ≤ 0 → Real.toNNReal r = 0 := - toNNReal_eq_zero.2 - -lemma toNNReal_eq_iff_eq_coe {r : ℝ} {p : ℝ≥0} (hp : p ≠ 0) : r.toNNReal = p ↔ r = p := - ⟨fun h ↦ h ▸ (coe_toNNReal _ <| not_lt.1 fun hlt ↦ hp <| h ▸ toNNReal_of_nonpos hlt.le).symm, - fun h ↦ h.symm ▸ toNNReal_coe⟩ - -@[simp] -lemma toNNReal_eq_one {r : ℝ} : r.toNNReal = 1 ↔ r = 1 := toNNReal_eq_iff_eq_coe one_ne_zero - -@[simp] -lemma toNNReal_eq_natCast {r : ℝ} {n : ℕ} (hn : n ≠ 0) : r.toNNReal = n ↔ r = n := - mod_cast toNNReal_eq_iff_eq_coe <| Nat.cast_ne_zero.2 hn - -@[deprecated (since := "2024-04-17")] -alias toNNReal_eq_nat_cast := toNNReal_eq_natCast - -@[simp] -lemma toNNReal_eq_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : - r.toNNReal = no_index (OfNat.ofNat n) ↔ r = OfNat.ofNat n := - toNNReal_eq_natCast (NeZero.ne n) - -@[simp] -theorem toNNReal_le_toNNReal_iff {r p : ℝ} (hp : 0 ≤ p) : - toNNReal r ≤ toNNReal p ↔ r ≤ p := by simp [← NNReal.coe_le_coe, hp] - -@[simp] -lemma toNNReal_le_one {r : ℝ} : r.toNNReal ≤ 1 ↔ r ≤ 1 := by - simpa using toNNReal_le_toNNReal_iff zero_le_one - -@[simp] -lemma one_lt_toNNReal {r : ℝ} : 1 < r.toNNReal ↔ 1 < r := by - simpa only [not_le] using toNNReal_le_one.not - -@[simp] -lemma toNNReal_le_natCast {r : ℝ} {n : ℕ} : r.toNNReal ≤ n ↔ r ≤ n := by - simpa using toNNReal_le_toNNReal_iff n.cast_nonneg - -@[deprecated (since := "2024-04-17")] -alias toNNReal_le_nat_cast := toNNReal_le_natCast - -@[simp] -lemma natCast_lt_toNNReal {r : ℝ} {n : ℕ} : n < r.toNNReal ↔ n < r := by - simpa only [not_le] using toNNReal_le_natCast.not - -@[deprecated (since := "2024-04-17")] -alias nat_cast_lt_toNNReal := natCast_lt_toNNReal - -@[simp] -lemma toNNReal_le_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : - r.toNNReal ≤ no_index (OfNat.ofNat n) ↔ r ≤ n := - toNNReal_le_natCast - -@[simp] -lemma ofNat_lt_toNNReal {r : ℝ} {n : ℕ} [n.AtLeastTwo] : - no_index (OfNat.ofNat n) < r.toNNReal ↔ n < r := - natCast_lt_toNNReal - -@[simp] -theorem toNNReal_eq_toNNReal_iff {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : - toNNReal r = toNNReal p ↔ r = p := by simp [← coe_inj, coe_toNNReal, hr, hp] - -@[simp] -theorem toNNReal_lt_toNNReal_iff' {r p : ℝ} : Real.toNNReal r < Real.toNNReal p ↔ r < p ∧ 0 < p := - NNReal.coe_lt_coe.symm.trans max_lt_max_left_iff - -theorem toNNReal_lt_toNNReal_iff {r p : ℝ} (h : 0 < p) : - Real.toNNReal r < Real.toNNReal p ↔ r < p := - toNNReal_lt_toNNReal_iff'.trans (and_iff_left h) - -theorem lt_of_toNNReal_lt {r p : ℝ} (h : r.toNNReal < p.toNNReal) : r < p := - (Real.toNNReal_lt_toNNReal_iff <| Real.toNNReal_pos.1 (ne_bot_of_gt h).bot_lt).1 h - -theorem toNNReal_lt_toNNReal_iff_of_nonneg {r p : ℝ} (hr : 0 ≤ r) : - Real.toNNReal r < Real.toNNReal p ↔ r < p := - toNNReal_lt_toNNReal_iff'.trans ⟨And.left, fun h => ⟨h, lt_of_le_of_lt hr h⟩⟩ - -lemma toNNReal_le_toNNReal_iff' {r p : ℝ} : r.toNNReal ≤ p.toNNReal ↔ r ≤ p ∨ r ≤ 0 := by - simp_rw [← not_lt, toNNReal_lt_toNNReal_iff', not_and_or] - -lemma toNNReal_le_toNNReal_iff_of_pos {r p : ℝ} (hr : 0 < r) : r.toNNReal ≤ p.toNNReal ↔ r ≤ p := by - simp [toNNReal_le_toNNReal_iff', hr.not_le] - -@[simp] -lemma one_le_toNNReal {r : ℝ} : 1 ≤ r.toNNReal ↔ 1 ≤ r := by - simpa using toNNReal_le_toNNReal_iff_of_pos one_pos - -@[simp] -lemma toNNReal_lt_one {r : ℝ} : r.toNNReal < 1 ↔ r < 1 := by simp only [← not_le, one_le_toNNReal] - -@[simp] -lemma natCastle_toNNReal' {n : ℕ} {r : ℝ} : ↑n ≤ r.toNNReal ↔ n ≤ r ∨ n = 0 := by - simpa [n.cast_nonneg.le_iff_eq] using toNNReal_le_toNNReal_iff' (r := n) - -@[deprecated (since := "2024-04-17")] -alias nat_cast_le_toNNReal' := natCastle_toNNReal' - -@[simp] -lemma toNNReal_lt_natCast' {n : ℕ} {r : ℝ} : r.toNNReal < n ↔ r < n ∧ n ≠ 0 := by - simpa [pos_iff_ne_zero] using toNNReal_lt_toNNReal_iff' (r := r) (p := n) - -@[deprecated (since := "2024-04-17")] -alias toNNReal_lt_nat_cast' := toNNReal_lt_natCast' - -lemma natCast_le_toNNReal {n : ℕ} {r : ℝ} (hn : n ≠ 0) : ↑n ≤ r.toNNReal ↔ n ≤ r := by simp [hn] - -@[deprecated (since := "2024-04-17")] -alias nat_cast_le_toNNReal := natCast_le_toNNReal - -lemma toNNReal_lt_natCast {r : ℝ} {n : ℕ} (hn : n ≠ 0) : r.toNNReal < n ↔ r < n := by simp [hn] - -@[deprecated (since := "2024-04-17")] -alias toNNReal_lt_nat_cast := toNNReal_lt_natCast - -@[simp] -lemma toNNReal_lt_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : - r.toNNReal < no_index (OfNat.ofNat n) ↔ r < OfNat.ofNat n := - toNNReal_lt_natCast (NeZero.ne n) - -@[simp] -lemma ofNat_le_toNNReal {n : ℕ} {r : ℝ} [n.AtLeastTwo] : - no_index (OfNat.ofNat n) ≤ r.toNNReal ↔ OfNat.ofNat n ≤ r := - natCast_le_toNNReal (NeZero.ne n) - -@[simp] -theorem toNNReal_add {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : - Real.toNNReal (r + p) = Real.toNNReal r + Real.toNNReal p := - NNReal.eq <| by simp [hr, hp, add_nonneg] - -theorem toNNReal_add_toNNReal {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : - Real.toNNReal r + Real.toNNReal p = Real.toNNReal (r + p) := - (Real.toNNReal_add hr hp).symm - -theorem toNNReal_le_toNNReal {r p : ℝ} (h : r ≤ p) : Real.toNNReal r ≤ Real.toNNReal p := - Real.toNNReal_mono h - -theorem toNNReal_add_le {r p : ℝ} : Real.toNNReal (r + p) ≤ Real.toNNReal r + Real.toNNReal p := - NNReal.coe_le_coe.1 <| max_le (add_le_add (le_max_left _ _) (le_max_left _ _)) NNReal.zero_le_coe - -theorem toNNReal_le_iff_le_coe {r : ℝ} {p : ℝ≥0} : toNNReal r ≤ p ↔ r ≤ ↑p := - NNReal.gi.gc r p - -theorem le_toNNReal_iff_coe_le {r : ℝ≥0} {p : ℝ} (hp : 0 ≤ p) : r ≤ Real.toNNReal p ↔ ↑r ≤ p := by - rw [← NNReal.coe_le_coe, Real.coe_toNNReal p hp] - -theorem le_toNNReal_iff_coe_le' {r : ℝ≥0} {p : ℝ} (hr : 0 < r) : r ≤ Real.toNNReal p ↔ ↑r ≤ p := - (le_or_lt 0 p).elim le_toNNReal_iff_coe_le fun hp => by - simp only [(hp.trans_le r.coe_nonneg).not_le, toNNReal_eq_zero.2 hp.le, hr.not_le] - -theorem toNNReal_lt_iff_lt_coe {r : ℝ} {p : ℝ≥0} (ha : 0 ≤ r) : Real.toNNReal r < p ↔ r < ↑p := by - rw [← NNReal.coe_lt_coe, Real.coe_toNNReal r ha] - -theorem lt_toNNReal_iff_coe_lt {r : ℝ≥0} {p : ℝ} : r < Real.toNNReal p ↔ ↑r < p := - lt_iff_lt_of_le_iff_le toNNReal_le_iff_le_coe - -theorem toNNReal_pow {x : ℝ} (hx : 0 ≤ x) (n : ℕ) : (x ^ n).toNNReal = x.toNNReal ^ n := by - rw [← coe_inj, NNReal.coe_pow, Real.coe_toNNReal _ (pow_nonneg hx _), - Real.coe_toNNReal x hx] - -theorem toNNReal_mul {p q : ℝ} (hp : 0 ≤ p) : - Real.toNNReal (p * q) = Real.toNNReal p * Real.toNNReal q := - NNReal.eq <| by simp [mul_max_of_nonneg, hp] - -end ToNNReal - -end Real - open Real -namespace NNReal - -section Mul - -theorem mul_eq_mul_left {a b c : ℝ≥0} (h : a ≠ 0) : a * b = a * c ↔ b = c := by - rw [mul_eq_mul_left_iff, or_iff_left h] - -end Mul - -section Pow - -theorem pow_antitone_exp {a : ℝ≥0} (m n : ℕ) (mn : m ≤ n) (a1 : a ≤ 1) : a ^ n ≤ a ^ m := - pow_le_pow_of_le_one (zero_le a) a1 mn - -nonrec theorem exists_pow_lt_of_lt_one {a b : ℝ≥0} (ha : 0 < a) (hb : b < 1) : - ∃ n : ℕ, b ^ n < a := by - simpa only [← coe_pow, NNReal.coe_lt_coe] using - exists_pow_lt_of_lt_one (NNReal.coe_pos.2 ha) (NNReal.coe_lt_coe.2 hb) - -nonrec theorem exists_mem_Ico_zpow {x : ℝ≥0} {y : ℝ≥0} (hx : x ≠ 0) (hy : 1 < y) : - ∃ n : ℤ, x ∈ Set.Ico (y ^ n) (y ^ (n + 1)) := - exists_mem_Ico_zpow (α := ℝ) hx.bot_lt hy - -nonrec theorem exists_mem_Ioc_zpow {x : ℝ≥0} {y : ℝ≥0} (hx : x ≠ 0) (hy : 1 < y) : - ∃ n : ℤ, x ∈ Set.Ioc (y ^ n) (y ^ (n + 1)) := - exists_mem_Ioc_zpow (α := ℝ) hx.bot_lt hy - -end Pow - section Sub /-! @@ -787,166 +104,17 @@ typeclass. For lemmas about subtraction and addition see lemmas about `OrderedSu `Mathlib.Algebra.Order.Sub.Basic`. See also `mul_tsub` and `tsub_mul`. -/ -theorem sub_def {r p : ℝ≥0} : r - p = Real.toNNReal (r - p) := - rfl - -theorem coe_sub_def {r p : ℝ≥0} : ↑(r - p) = max (r - p : ℝ) 0 := - rfl - -example : OrderedSub ℝ≥0 := by infer_instance - theorem sub_div (a b c : ℝ≥0) : (a - b) / c = a / c - b / c := tsub_div _ _ _ end Sub -section Inv - -@[simp] -theorem inv_le {r p : ℝ≥0} (h : r ≠ 0) : r⁻¹ ≤ p ↔ 1 ≤ r * p := by - rw [← mul_le_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h] - -theorem inv_le_of_le_mul {r p : ℝ≥0} (h : 1 ≤ r * p) : r⁻¹ ≤ p := by - by_cases r = 0 <;> simp [*, inv_le] - -@[simp] -theorem le_inv_iff_mul_le {r p : ℝ≥0} (h : p ≠ 0) : r ≤ p⁻¹ ↔ r * p ≤ 1 := by - rw [← mul_le_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h, mul_comm] - -@[simp] -theorem lt_inv_iff_mul_lt {r p : ℝ≥0} (h : p ≠ 0) : r < p⁻¹ ↔ r * p < 1 := by - rw [← mul_lt_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h, mul_comm] - -@[deprecated le_inv_mul_iff₀ (since := "2024-08-21")] -theorem mul_le_iff_le_inv {a b r : ℝ≥0} (hr : r ≠ 0) : r * a ≤ b ↔ a ≤ r⁻¹ * b := - (le_inv_mul_iff₀ (pos_iff_ne_zero.2 hr)).symm - -@[deprecated le_div_iff₀ (since := "2024-08-21")] -theorem le_div_iff_mul_le {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ a * r ≤ b := - le_div_iff₀ (pos_iff_ne_zero.2 hr) - -@[deprecated div_le_iff₀ (since := "2024-08-21")] -protected lemma div_le_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ b * r := - div_le_iff₀ (pos_iff_ne_zero.2 hr) - -@[deprecated div_le_iff₀' (since := "2024-08-21")] -protected lemma div_le_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ r * b := - div_le_iff₀' (pos_iff_ne_zero.2 hr) - -theorem div_le_of_le_mul {a b c : ℝ≥0} (h : a ≤ b * c) : a / c ≤ b := - if h0 : c = 0 then by simp [h0] else (div_le_iff₀ (pos_iff_ne_zero.2 h0)).2 h - -theorem div_le_of_le_mul' {a b c : ℝ≥0} (h : a ≤ b * c) : a / b ≤ c := - div_le_of_le_mul <| mul_comm b c ▸ h - -@[deprecated le_div_iff₀ (since := "2024-08-21")] -protected lemma le_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ a * r ≤ b := - le_div_iff₀ hr.bot_lt - -@[deprecated le_div_iff₀' (since := "2024-10-02")] -theorem le_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ r * a ≤ b := le_div_iff₀' hr.bot_lt - -@[deprecated div_lt_iff₀ (since := "2024-10-02")] -theorem div_lt_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < b * r := div_lt_iff₀ hr.bot_lt - -@[deprecated div_lt_iff₀' (since := "2024-10-02")] -theorem div_lt_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < r * b := div_lt_iff₀' hr.bot_lt - -@[deprecated lt_div_iff₀ (since := "2024-10-02")] -theorem lt_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ a * r < b := lt_div_iff₀ hr.bot_lt - -@[deprecated lt_div_iff₀' (since := "2024-10-02")] -theorem lt_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ r * a < b := lt_div_iff₀' hr.bot_lt - -theorem mul_lt_of_lt_div {a b r : ℝ≥0} (h : a < b / r) : a * r < b := - (lt_div_iff₀ <| pos_iff_ne_zero.2 fun hr => False.elim <| by simp [hr] at h).1 h - -theorem div_le_div_left_of_le {a b c : ℝ≥0} (c0 : c ≠ 0) (cb : c ≤ b) : - a / b ≤ a / c := - div_le_div_of_nonneg_left (zero_le _) c0.bot_lt cb - -nonrec theorem div_le_div_left {a b c : ℝ≥0} (a0 : 0 < a) (b0 : 0 < b) (c0 : 0 < c) : - a / b ≤ a / c ↔ c ≤ b := - div_le_div_left a0 b0 c0 - -theorem le_of_forall_lt_one_mul_le {x y : ℝ≥0} (h : ∀ a < 1, a * x ≤ y) : x ≤ y := - le_of_forall_ge_of_dense fun a ha => by - have hx : x ≠ 0 := pos_iff_ne_zero.1 (lt_of_le_of_lt (zero_le _) ha) - have hx' : x⁻¹ ≠ 0 := by rwa [Ne, inv_eq_zero] - have : a * x⁻¹ < 1 := by rwa [← lt_inv_iff_mul_lt hx', inv_inv] - have : a * x⁻¹ * x ≤ y := h _ this - rwa [mul_assoc, inv_mul_cancel₀ hx, mul_one] at this - -nonrec theorem half_le_self (a : ℝ≥0) : a / 2 ≤ a := - half_le_self bot_le - -nonrec theorem half_lt_self {a : ℝ≥0} (h : a ≠ 0) : a / 2 < a := - half_lt_self h.bot_lt - -theorem div_lt_one_of_lt {a b : ℝ≥0} (h : a < b) : a / b < 1 := by - rwa [div_lt_iff₀ h.bot_lt, one_mul] - -theorem _root_.Real.toNNReal_inv {x : ℝ} : Real.toNNReal x⁻¹ = (Real.toNNReal x)⁻¹ := by - rcases le_total 0 x with hx | hx - · nth_rw 1 [← Real.coe_toNNReal x hx] - rw [← NNReal.coe_inv, Real.toNNReal_coe] - · rw [toNNReal_eq_zero.mpr hx, inv_zero, toNNReal_eq_zero.mpr (inv_nonpos.mpr hx)] - -theorem _root_.Real.toNNReal_div {x y : ℝ} (hx : 0 ≤ x) : - Real.toNNReal (x / y) = Real.toNNReal x / Real.toNNReal y := by - rw [div_eq_mul_inv, div_eq_mul_inv, ← Real.toNNReal_inv, ← Real.toNNReal_mul hx] - -theorem _root_.Real.toNNReal_div' {x y : ℝ} (hy : 0 ≤ y) : - Real.toNNReal (x / y) = Real.toNNReal x / Real.toNNReal y := by - rw [div_eq_inv_mul, div_eq_inv_mul, Real.toNNReal_mul (inv_nonneg.2 hy), Real.toNNReal_inv] - -theorem inv_lt_one_iff {x : ℝ≥0} (hx : x ≠ 0) : x⁻¹ < 1 ↔ 1 < x := by - rw [← one_div, div_lt_iff₀ hx.bot_lt, one_mul] - -theorem zpow_pos {x : ℝ≥0} (hx : x ≠ 0) (n : ℤ) : 0 < x ^ n := - zpow_pos_of_pos hx.bot_lt _ - -theorem inv_lt_inv {x y : ℝ≥0} (hx : x ≠ 0) (h : x < y) : y⁻¹ < x⁻¹ := - inv_lt_inv_of_lt hx.bot_lt h - -end Inv - -@[simp] -theorem abs_eq (x : ℝ≥0) : |(x : ℝ)| = x := - abs_of_nonneg x.property - section Csupr open Set variable {ι : Sort*} {f : ι → ℝ≥0} -theorem le_toNNReal_of_coe_le {x : ℝ≥0} {y : ℝ} (h : ↑x ≤ y) : x ≤ y.toNNReal := - (le_toNNReal_iff_coe_le <| x.2.trans h).2 h - -nonrec theorem sSup_of_not_bddAbove {s : Set ℝ≥0} (hs : ¬BddAbove s) : SupSet.sSup s = 0 := by - rw [← bddAbove_coe] at hs - rw [← coe_inj, coe_sSup, NNReal.coe_zero] - exact sSup_of_not_bddAbove hs - -theorem iSup_of_not_bddAbove (hf : ¬BddAbove (range f)) : ⨆ i, f i = 0 := - sSup_of_not_bddAbove hf - -theorem iSup_empty [IsEmpty ι] (f : ι → ℝ≥0) : ⨆ i, f i = 0 := ciSup_of_empty f - -theorem iInf_empty [IsEmpty ι] (f : ι → ℝ≥0) : ⨅ i, f i = 0 := by - rw [_root_.iInf_of_isEmpty, sInf_empty] - -@[simp] lemma iSup_eq_zero (hf : BddAbove (range f)) : ⨆ i, f i = 0 ↔ ∀ i, f i = 0 := by - cases isEmpty_or_nonempty ι - · simp - · simp [← bot_eq_zero', ← le_bot_iff, ciSup_le_iff hf] - -@[simp] -theorem iInf_const_zero {α : Sort*} : ⨅ _ : α, (0 : ℝ≥0) = 0 := by - rw [← coe_inj, coe_iInf] - exact Real.iInf_const_zero - theorem iInf_mul (f : ι → ℝ≥0) (a : ℝ≥0) : iInf f * a = ⨅ i, f i * a := by rw [← coe_inj, NNReal.coe_mul, coe_iInf, coe_iInf] exact Real.iInf_mul_of_nonneg (NNReal.coe_nonneg _) _ @@ -997,122 +165,3 @@ theorem le_iInf_mul_iInf {a : ℝ≥0} {g h : ι → ℝ≥0} (H : ∀ i j, a end Csupr end NNReal - -namespace Set - -namespace OrdConnected - -variable {s : Set ℝ} {t : Set ℝ≥0} - -theorem preimage_coe_nnreal_real (h : s.OrdConnected) : ((↑) ⁻¹' s : Set ℝ≥0).OrdConnected := - h.preimage_mono NNReal.coe_mono - -theorem image_coe_nnreal_real (h : t.OrdConnected) : ((↑) '' t : Set ℝ).OrdConnected := - ⟨forall_mem_image.2 fun x hx => - forall_mem_image.2 fun _y hy z hz => ⟨⟨z, x.2.trans hz.1⟩, h.out hx hy hz, rfl⟩⟩ - --- Porting note (#11215): TODO: does it generalize to a `GaloisInsertion`? -theorem image_real_toNNReal (h : s.OrdConnected) : (Real.toNNReal '' s).OrdConnected := by - refine ⟨forall_mem_image.2 fun x hx => forall_mem_image.2 fun y hy z hz => ?_⟩ - rcases le_total y 0 with hy₀ | hy₀ - · rw [mem_Icc, Real.toNNReal_of_nonpos hy₀, nonpos_iff_eq_zero] at hz - exact ⟨y, hy, (toNNReal_of_nonpos hy₀).trans hz.2.symm⟩ - · lift y to ℝ≥0 using hy₀ - rw [toNNReal_coe] at hz - exact ⟨z, h.out hx hy ⟨toNNReal_le_iff_le_coe.1 hz.1, hz.2⟩, toNNReal_coe⟩ - -theorem preimage_real_toNNReal (h : t.OrdConnected) : (Real.toNNReal ⁻¹' t).OrdConnected := - h.preimage_mono Real.toNNReal_mono - -end OrdConnected - -end Set - -namespace Real - -/-- The absolute value on `ℝ` as a map to `ℝ≥0`. -/ --- Porting note (kmill): `pp_nodot` has no affect here --- unless RFC lean4#1910 leads to dot notation for CoeFun -@[pp_nodot] -def nnabs : ℝ →*₀ ℝ≥0 where - toFun x := ⟨|x|, abs_nonneg x⟩ - map_zero' := by ext; simp - map_one' := by ext; simp - map_mul' x y := by ext; simp [abs_mul] - -@[norm_cast, simp] -theorem coe_nnabs (x : ℝ) : (nnabs x : ℝ) = |x| := - rfl - -@[simp] -theorem nnabs_of_nonneg {x : ℝ} (h : 0 ≤ x) : nnabs x = toNNReal x := by - ext - rw [coe_toNNReal x h, coe_nnabs, abs_of_nonneg h] - -theorem nnabs_coe (x : ℝ≥0) : nnabs x = x := by simp - -theorem coe_toNNReal_le (x : ℝ) : (toNNReal x : ℝ) ≤ |x| := - max_le (le_abs_self _) (abs_nonneg _) - -@[simp] lemma toNNReal_abs (x : ℝ) : |x|.toNNReal = nnabs x := NNReal.coe_injective <| by simp - -theorem cast_natAbs_eq_nnabs_cast (n : ℤ) : (n.natAbs : ℝ≥0) = nnabs n := by - ext - rw [NNReal.coe_natCast, Int.cast_natAbs, Real.coe_nnabs, Int.cast_abs] - -end Real - -section StrictMono - -open NNReal - -variable {Γ₀ : Type*} [LinearOrderedCommGroupWithZero Γ₀] - -/-- If `Γ₀ˣ` is nontrivial and `f : Γ₀ →*₀ ℝ≥0` is strictly monotone, then for any positive - `r : ℝ≥0`, there exists `d : Γ₀ˣ` with `f d < r`. -/ -theorem NNReal.exists_lt_of_strictMono [h : Nontrivial Γ₀ˣ] {f : Γ₀ →*₀ ℝ≥0} (hf : StrictMono f) - {r : ℝ≥0} (hr : 0 < r) : ∃ d : Γ₀ˣ, f d < r := by - obtain ⟨g, hg1⟩ := (nontrivial_iff_exists_ne (1 : Γ₀ˣ)).mp h - set u : Γ₀ˣ := if g < 1 then g else g⁻¹ with hu - have hfu : f u < 1 := by - rw [hu] - split_ifs with hu1 - · rw [← map_one f]; exact hf hu1 - · have hfg0 : f g ≠ 0 := - fun h0 ↦ (Units.ne_zero g) ((map_eq_zero f).mp h0) - have hg1' : 1 < g := lt_of_le_of_ne (not_lt.mp hu1) hg1.symm - rw [Units.val_inv_eq_inv_val, map_inv₀, inv_lt_one_iff hfg0, ← map_one f] - exact hf hg1' - obtain ⟨n, hn⟩ := exists_pow_lt_of_lt_one hr hfu - use u ^ n - rwa [Units.val_pow_eq_pow_val, map_pow] - -/-- If `Γ₀ˣ` is nontrivial and `f : Γ₀ →*₀ ℝ≥0` is strictly monotone, then for any positive - real `r`, there exists `d : Γ₀ˣ` with `f d < r`. -/ -theorem Real.exists_lt_of_strictMono [h : Nontrivial Γ₀ˣ] {f : Γ₀ →*₀ ℝ≥0} (hf : StrictMono f) - {r : ℝ} (hr : 0 < r) : ∃ d : Γ₀ˣ, (f d : ℝ) < r := by - set s : NNReal := ⟨r, le_of_lt hr⟩ - have hs : 0 < s := hr - exact NNReal.exists_lt_of_strictMono hf hs - -end StrictMono - -namespace Mathlib.Meta.Positivity - -open Lean Meta Qq Function - -private alias ⟨_, nnreal_coe_pos⟩ := coe_pos - -/-- Extension for the `positivity` tactic: cast from `ℝ≥0` to `ℝ`. -/ -@[positivity NNReal.toReal _] -def evalNNRealtoReal : PositivityExt where eval {u α} _zα _pα e := do - match u, α, e with - | 0, ~q(ℝ), ~q(NNReal.toReal $a) => - let ra ← core q(inferInstance) q(inferInstance) a - assertInstancesCommute - match ra with - | .positive pa => pure (.positive q(nnreal_coe_pos $pa)) - | _ => pure (.nonnegative q(NNReal.coe_nonneg $a)) - | _, _, _ => throwError "not NNReal.toReal" - -end Mathlib.Meta.Positivity diff --git a/Mathlib/Data/NNReal/Defs.lean b/Mathlib/Data/NNReal/Defs.lean new file mode 100644 index 0000000000000..9a80187ab708f --- /dev/null +++ b/Mathlib/Data/NNReal/Defs.lean @@ -0,0 +1,999 @@ +/- +Copyright (c) 2018 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.Algebra.Algebra.Defs +import Mathlib.Algebra.Order.Module.OrderedSMul +import Mathlib.Data.Real.Archimedean + +/-! +# Nonnegative real numbers + +In this file we define `NNReal` (notation: `ℝ≥0`) to be the type of non-negative real numbers, +a.k.a. the interval `[0, ∞)`. We also define the following operations and structures on `ℝ≥0`: + +* the order on `ℝ≥0` is the restriction of the order on `ℝ`; these relations define a conditionally + complete linear order with a bottom element, `ConditionallyCompleteLinearOrderBot`; + +* `a + b` and `a * b` are the restrictions of addition and multiplication of real numbers to `ℝ≥0`; + these operations together with `0 = ⟨0, _⟩` and `1 = ⟨1, _⟩` turn `ℝ≥0` into a conditionally + complete linear ordered archimedean commutative semifield; we have no typeclass for this in + `mathlib` yet, so we define the following instances instead: + + - `LinearOrderedSemiring ℝ≥0`; + - `OrderedCommSemiring ℝ≥0`; + - `CanonicallyOrderedCommSemiring ℝ≥0`; + - `LinearOrderedCommGroupWithZero ℝ≥0`; + - `CanonicallyLinearOrderedAddCommMonoid ℝ≥0`; + - `Archimedean ℝ≥0`; + - `ConditionallyCompleteLinearOrderBot ℝ≥0`. + + These instances are derived from corresponding instances about the type `{x : α // 0 ≤ x}` in an + appropriate ordered field/ring/group/monoid `α`, see `Mathlib.Algebra.Order.Nonneg.OrderedRing`. + +* `Real.toNNReal x` is defined as `⟨max x 0, _⟩`, i.e. `↑(Real.toNNReal x) = x` when `0 ≤ x` and + `↑(Real.toNNReal x) = 0` otherwise. + +We also define an instance `CanLift ℝ ℝ≥0`. This instance can be used by the `lift` tactic to +replace `x : ℝ` and `hx : 0 ≤ x` in the proof context with `x : ℝ≥0` while replacing all occurrences +of `x` with `↑x`. This tactic also works for a function `f : α → ℝ` with a hypothesis +`hf : ∀ x, 0 ≤ f x`. + +## Notations + +This file defines `ℝ≥0` as a localized notation for `NNReal`. +-/ + +assert_not_exists Star + +open Function + +-- to ensure these instances are computable +/-- Nonnegative real numbers. -/ +def NNReal := { r : ℝ // 0 ≤ r } deriving + Zero, One, Semiring, StrictOrderedSemiring, CommMonoidWithZero, CommSemiring, + SemilatticeInf, SemilatticeSup, DistribLattice, OrderedCommSemiring, + CanonicallyOrderedCommSemiring, Inhabited + +namespace NNReal + +scoped notation "ℝ≥0" => NNReal + +instance instDenselyOrdered : DenselyOrdered ℝ≥0 := Nonneg.instDenselyOrdered +instance : OrderBot ℝ≥0 := inferInstance +instance instArchimedean : Archimedean ℝ≥0 := Nonneg.instArchimedean +instance instMulArchimedean : MulArchimedean ℝ≥0 := Nonneg.instMulArchimedean +noncomputable instance : Sub ℝ≥0 := Nonneg.sub +noncomputable instance : OrderedSub ℝ≥0 := Nonneg.orderedSub + +noncomputable instance : CanonicallyLinearOrderedSemifield ℝ≥0 := + Nonneg.canonicallyLinearOrderedSemifield + +/-- Coercion `ℝ≥0 → ℝ`. -/ +@[coe] def toReal : ℝ≥0 → ℝ := Subtype.val + +instance : Coe ℝ≥0 ℝ := ⟨toReal⟩ + +-- Simp lemma to put back `n.val` into the normal form given by the coercion. +@[simp] +theorem val_eq_coe (n : ℝ≥0) : n.val = n := + rfl + +instance canLift : CanLift ℝ ℝ≥0 toReal fun r => 0 ≤ r := + Subtype.canLift _ + +@[ext] protected theorem eq {n m : ℝ≥0} : (n : ℝ) = (m : ℝ) → n = m := + Subtype.eq + +theorem ne_iff {x y : ℝ≥0} : (x : ℝ) ≠ (y : ℝ) ↔ x ≠ y := + not_congr <| NNReal.eq_iff.symm + +protected theorem «forall» {p : ℝ≥0 → Prop} : + (∀ x : ℝ≥0, p x) ↔ ∀ (x : ℝ) (hx : 0 ≤ x), p ⟨x, hx⟩ := + Subtype.forall + +protected theorem «exists» {p : ℝ≥0 → Prop} : + (∃ x : ℝ≥0, p x) ↔ ∃ (x : ℝ) (hx : 0 ≤ x), p ⟨x, hx⟩ := + Subtype.exists + +/-- Reinterpret a real number `r` as a non-negative real number. Returns `0` if `r < 0`. -/ +noncomputable def _root_.Real.toNNReal (r : ℝ) : ℝ≥0 := + ⟨max r 0, le_max_right _ _⟩ + +theorem _root_.Real.coe_toNNReal (r : ℝ) (hr : 0 ≤ r) : (Real.toNNReal r : ℝ) = r := + max_eq_left hr + +theorem _root_.Real.toNNReal_of_nonneg {r : ℝ} (hr : 0 ≤ r) : r.toNNReal = ⟨r, hr⟩ := by + simp_rw [Real.toNNReal, max_eq_left hr] + +theorem _root_.Real.le_coe_toNNReal (r : ℝ) : r ≤ Real.toNNReal r := + le_max_left r 0 + +@[bound] theorem coe_nonneg (r : ℝ≥0) : (0 : ℝ) ≤ r := r.2 + +@[simp, norm_cast] theorem coe_mk (a : ℝ) (ha) : toReal ⟨a, ha⟩ = a := rfl + +example : Zero ℝ≥0 := by infer_instance + +example : One ℝ≥0 := by infer_instance + +example : Add ℝ≥0 := by infer_instance + +noncomputable example : Sub ℝ≥0 := by infer_instance + +example : Mul ℝ≥0 := by infer_instance + +noncomputable example : Inv ℝ≥0 := by infer_instance + +noncomputable example : Div ℝ≥0 := by infer_instance + +example : LE ℝ≥0 := by infer_instance + +example : Bot ℝ≥0 := by infer_instance + +example : Inhabited ℝ≥0 := by infer_instance + +example : Nontrivial ℝ≥0 := by infer_instance + +protected theorem coe_injective : Injective ((↑) : ℝ≥0 → ℝ) := Subtype.coe_injective + +@[simp, norm_cast] lemma coe_inj {r₁ r₂ : ℝ≥0} : (r₁ : ℝ) = r₂ ↔ r₁ = r₂ := + NNReal.coe_injective.eq_iff + +@[deprecated (since := "2024-02-03")] protected alias coe_eq := coe_inj + +@[simp, norm_cast] lemma coe_zero : ((0 : ℝ≥0) : ℝ) = 0 := rfl + +@[simp, norm_cast] lemma coe_one : ((1 : ℝ≥0) : ℝ) = 1 := rfl + +@[simp] lemma mk_zero : (⟨0, le_rfl⟩ : ℝ≥0) = 0 := rfl +@[simp] lemma mk_one : (⟨1, zero_le_one⟩ : ℝ≥0) = 1 := rfl + +@[simp, norm_cast] +protected theorem coe_add (r₁ r₂ : ℝ≥0) : ((r₁ + r₂ : ℝ≥0) : ℝ) = r₁ + r₂ := + rfl + +@[simp, norm_cast] +protected theorem coe_mul (r₁ r₂ : ℝ≥0) : ((r₁ * r₂ : ℝ≥0) : ℝ) = r₁ * r₂ := + rfl + +@[simp, norm_cast] +protected theorem coe_inv (r : ℝ≥0) : ((r⁻¹ : ℝ≥0) : ℝ) = (r : ℝ)⁻¹ := + rfl + +@[simp, norm_cast] +protected theorem coe_div (r₁ r₂ : ℝ≥0) : ((r₁ / r₂ : ℝ≥0) : ℝ) = (r₁ : ℝ) / r₂ := + rfl + +protected theorem coe_two : ((2 : ℝ≥0) : ℝ) = 2 := rfl + +@[simp, norm_cast] +protected theorem coe_sub {r₁ r₂ : ℝ≥0} (h : r₂ ≤ r₁) : ((r₁ - r₂ : ℝ≥0) : ℝ) = ↑r₁ - ↑r₂ := + max_eq_left <| le_sub_comm.2 <| by simp [show (r₂ : ℝ) ≤ r₁ from h] + +variable {r r₁ r₂ : ℝ≥0} {x y : ℝ} + +@[simp, norm_cast] lemma coe_eq_zero : (r : ℝ) = 0 ↔ r = 0 := by rw [← coe_zero, coe_inj] + +@[simp, norm_cast] lemma coe_eq_one : (r : ℝ) = 1 ↔ r = 1 := by rw [← coe_one, coe_inj] + +@[norm_cast] lemma coe_ne_zero : (r : ℝ) ≠ 0 ↔ r ≠ 0 := coe_eq_zero.not + +@[norm_cast] lemma coe_ne_one : (r : ℝ) ≠ 1 ↔ r ≠ 1 := coe_eq_one.not + +example : CommSemiring ℝ≥0 := by infer_instance + +/-- Coercion `ℝ≥0 → ℝ` as a `RingHom`. + +Porting note (#11215): TODO: what if we define `Coe ℝ≥0 ℝ` using this function? -/ +def toRealHom : ℝ≥0 →+* ℝ where + toFun := (↑) + map_one' := NNReal.coe_one + map_mul' := NNReal.coe_mul + map_zero' := NNReal.coe_zero + map_add' := NNReal.coe_add + +@[simp] theorem coe_toRealHom : ⇑toRealHom = toReal := rfl + +section Actions + +/-- A `MulAction` over `ℝ` restricts to a `MulAction` over `ℝ≥0`. -/ +instance {M : Type*} [MulAction ℝ M] : MulAction ℝ≥0 M := + MulAction.compHom M toRealHom.toMonoidHom + +theorem smul_def {M : Type*} [MulAction ℝ M] (c : ℝ≥0) (x : M) : c • x = (c : ℝ) • x := + rfl + +instance {M N : Type*} [MulAction ℝ M] [MulAction ℝ N] [SMul M N] [IsScalarTower ℝ M N] : + IsScalarTower ℝ≥0 M N where smul_assoc r := (smul_assoc (r : ℝ) : _) + +instance smulCommClass_left {M N : Type*} [MulAction ℝ N] [SMul M N] [SMulCommClass ℝ M N] : + SMulCommClass ℝ≥0 M N where smul_comm r := (smul_comm (r : ℝ) : _) + +instance smulCommClass_right {M N : Type*} [MulAction ℝ N] [SMul M N] [SMulCommClass M ℝ N] : + SMulCommClass M ℝ≥0 N where smul_comm m r := (smul_comm m (r : ℝ) : _) + +/-- A `DistribMulAction` over `ℝ` restricts to a `DistribMulAction` over `ℝ≥0`. -/ +instance {M : Type*} [AddMonoid M] [DistribMulAction ℝ M] : DistribMulAction ℝ≥0 M := + DistribMulAction.compHom M toRealHom.toMonoidHom + +/-- A `Module` over `ℝ` restricts to a `Module` over `ℝ≥0`. -/ +instance {M : Type*} [AddCommMonoid M] [Module ℝ M] : Module ℝ≥0 M := + Module.compHom M toRealHom + +-- Porting note (#11215): TODO: after this line, `↑` uses `Algebra.cast` instead of `toReal` +/-- An `Algebra` over `ℝ` restricts to an `Algebra` over `ℝ≥0`. -/ +instance {A : Type*} [Semiring A] [Algebra ℝ A] : Algebra ℝ≥0 A where + smul := (· • ·) + commutes' r x := by simp [Algebra.commutes] + smul_def' r x := by simp [← Algebra.smul_def (r : ℝ) x, smul_def] + toRingHom := (algebraMap ℝ A).comp (toRealHom : ℝ≥0 →+* ℝ) + +-- verify that the above produces instances we might care about +example : Algebra ℝ≥0 ℝ := by infer_instance + +example : DistribMulAction ℝ≥0ˣ ℝ := by infer_instance + +end Actions + +example : MonoidWithZero ℝ≥0 := by infer_instance + +example : CommMonoidWithZero ℝ≥0 := by infer_instance + +noncomputable example : CommGroupWithZero ℝ≥0 := by infer_instance + +@[simp, norm_cast] +theorem coe_pow (r : ℝ≥0) (n : ℕ) : ((r ^ n : ℝ≥0) : ℝ) = (r : ℝ) ^ n := rfl + +@[simp, norm_cast] +theorem coe_zpow (r : ℝ≥0) (n : ℤ) : ((r ^ n : ℝ≥0) : ℝ) = (r : ℝ) ^ n := rfl + +variable {ι : Type*} {f : ι → ℝ} + +@[simp, norm_cast] lemma coe_nsmul (r : ℝ≥0) (n : ℕ) : ↑(n • r) = n • (r : ℝ) := rfl +@[simp, norm_cast] lemma coe_nnqsmul (q : ℚ≥0) (x : ℝ≥0) : ↑(q • x) = (q • x : ℝ) := rfl + +@[simp, norm_cast] +protected theorem coe_natCast (n : ℕ) : (↑(↑n : ℝ≥0) : ℝ) = n := + map_natCast toRealHom n + +@[deprecated (since := "2024-04-17")] +alias coe_nat_cast := NNReal.coe_natCast + +-- See note [no_index around OfNat.ofNat] +@[simp, norm_cast] +protected theorem coe_ofNat (n : ℕ) [n.AtLeastTwo] : + (no_index (OfNat.ofNat n : ℝ≥0) : ℝ) = OfNat.ofNat n := + rfl + +@[simp, norm_cast] +protected theorem coe_ofScientific (m : ℕ) (s : Bool) (e : ℕ) : + ↑(OfScientific.ofScientific m s e : ℝ≥0) = (OfScientific.ofScientific m s e : ℝ) := + rfl + +@[simp, norm_cast] +lemma algebraMap_eq_coe : (algebraMap ℝ≥0 ℝ : ℝ≥0 → ℝ) = (↑) := rfl + +noncomputable example : LinearOrder ℝ≥0 := by infer_instance + +@[simp, norm_cast] lemma coe_le_coe : (r₁ : ℝ) ≤ r₂ ↔ r₁ ≤ r₂ := Iff.rfl + +@[simp, norm_cast] lemma coe_lt_coe : (r₁ : ℝ) < r₂ ↔ r₁ < r₂ := Iff.rfl + +@[bound] private alias ⟨_, Bound.coe_lt_coe_of_lt⟩ := coe_lt_coe + +@[simp, norm_cast] lemma coe_pos : (0 : ℝ) < r ↔ 0 < r := Iff.rfl + +@[bound] private alias ⟨_, Bound.coe_pos_of_pos⟩ := coe_pos + +@[simp, norm_cast] lemma one_le_coe : 1 ≤ (r : ℝ) ↔ 1 ≤ r := by rw [← coe_le_coe, coe_one] +@[simp, norm_cast] lemma one_lt_coe : 1 < (r : ℝ) ↔ 1 < r := by rw [← coe_lt_coe, coe_one] +@[simp, norm_cast] lemma coe_le_one : (r : ℝ) ≤ 1 ↔ r ≤ 1 := by rw [← coe_le_coe, coe_one] +@[simp, norm_cast] lemma coe_lt_one : (r : ℝ) < 1 ↔ r < 1 := by rw [← coe_lt_coe, coe_one] + +@[mono] lemma coe_mono : Monotone ((↑) : ℝ≥0 → ℝ) := fun _ _ => NNReal.coe_le_coe.2 + +/-- Alias for the use of `gcongr` -/ +@[gcongr] alias ⟨_, GCongr.toReal_le_toReal⟩ := coe_le_coe + +protected theorem _root_.Real.toNNReal_mono : Monotone Real.toNNReal := fun _ _ h => + max_le_max h (le_refl 0) + +@[simp] +theorem _root_.Real.toNNReal_coe {r : ℝ≥0} : Real.toNNReal r = r := + NNReal.eq <| max_eq_left r.2 + +@[simp] +theorem mk_natCast (n : ℕ) : @Eq ℝ≥0 (⟨(n : ℝ), n.cast_nonneg⟩ : ℝ≥0) n := + NNReal.eq (NNReal.coe_natCast n).symm + +@[deprecated (since := "2024-04-05")] alias mk_coe_nat := mk_natCast + +-- Porting note: place this in the `Real` namespace +@[simp] +theorem toNNReal_coe_nat (n : ℕ) : Real.toNNReal n = n := + NNReal.eq <| by simp [Real.coe_toNNReal] + +-- See note [no_index around OfNat.ofNat] +@[simp] +theorem _root_.Real.toNNReal_ofNat (n : ℕ) [n.AtLeastTwo] : + Real.toNNReal (no_index (OfNat.ofNat n)) = OfNat.ofNat n := + toNNReal_coe_nat n + +/-- `Real.toNNReal` and `NNReal.toReal : ℝ≥0 → ℝ` form a Galois insertion. -/ +noncomputable def gi : GaloisInsertion Real.toNNReal (↑) := + GaloisInsertion.monotoneIntro NNReal.coe_mono Real.toNNReal_mono Real.le_coe_toNNReal fun _ => + Real.toNNReal_coe + +-- note that anything involving the (decidability of the) linear order, +-- will be noncomputable, everything else should not be. +example : OrderBot ℝ≥0 := by infer_instance + +example : PartialOrder ℝ≥0 := by infer_instance + +noncomputable example : CanonicallyLinearOrderedAddCommMonoid ℝ≥0 := by infer_instance + +noncomputable example : LinearOrderedAddCommMonoid ℝ≥0 := by infer_instance + +example : DistribLattice ℝ≥0 := by infer_instance + +example : SemilatticeInf ℝ≥0 := by infer_instance + +example : SemilatticeSup ℝ≥0 := by infer_instance + +noncomputable example : LinearOrderedSemiring ℝ≥0 := by infer_instance + +example : OrderedCommSemiring ℝ≥0 := by infer_instance + +noncomputable example : LinearOrderedCommMonoid ℝ≥0 := by infer_instance + +noncomputable example : LinearOrderedCommMonoidWithZero ℝ≥0 := by infer_instance + +noncomputable example : LinearOrderedCommGroupWithZero ℝ≥0 := by infer_instance + +example : CanonicallyOrderedCommSemiring ℝ≥0 := by infer_instance + +example : DenselyOrdered ℝ≥0 := by infer_instance + +example : NoMaxOrder ℝ≥0 := by infer_instance + +instance instPosSMulStrictMono {α} [Preorder α] [MulAction ℝ α] [PosSMulStrictMono ℝ α] : + PosSMulStrictMono ℝ≥0 α where + elim _r hr _a₁ _a₂ ha := (smul_lt_smul_of_pos_left ha (coe_pos.2 hr):) + +instance instSMulPosStrictMono {α} [Zero α] [Preorder α] [MulAction ℝ α] [SMulPosStrictMono ℝ α] : + SMulPosStrictMono ℝ≥0 α where + elim _a ha _r₁ _r₂ hr := (smul_lt_smul_of_pos_right (coe_lt_coe.2 hr) ha :) + +/-- If `a` is a nonnegative real number, then the closed interval `[0, a]` in `ℝ` is order +isomorphic to the interval `Set.Iic a`. -/ +-- Porting note (#11215): TODO: restore once `simps` supports `ℝ≥0` @[simps!? apply_coe_coe] +def orderIsoIccZeroCoe (a : ℝ≥0) : Set.Icc (0 : ℝ) a ≃o Set.Iic a where + toEquiv := Equiv.Set.sep (Set.Ici 0) fun x : ℝ => x ≤ a + map_rel_iff' := Iff.rfl + +@[simp] +theorem orderIsoIccZeroCoe_apply_coe_coe (a : ℝ≥0) (b : Set.Icc (0 : ℝ) a) : + (orderIsoIccZeroCoe a b : ℝ) = b := + rfl + +@[simp] +theorem orderIsoIccZeroCoe_symm_apply_coe (a : ℝ≥0) (b : Set.Iic a) : + ((orderIsoIccZeroCoe a).symm b : ℝ) = b := + rfl + +-- note we need the `@` to make the `Membership.mem` have a sensible type +theorem coe_image {s : Set ℝ≥0} : + (↑) '' s = { x : ℝ | ∃ h : 0 ≤ x, @Membership.mem ℝ≥0 _ _ s ⟨x, h⟩ } := + Subtype.coe_image + +theorem bddAbove_coe {s : Set ℝ≥0} : BddAbove (((↑) : ℝ≥0 → ℝ) '' s) ↔ BddAbove s := + Iff.intro + (fun ⟨b, hb⟩ => + ⟨Real.toNNReal b, fun ⟨y, _⟩ hys => + show y ≤ max b 0 from le_max_of_le_left <| hb <| Set.mem_image_of_mem _ hys⟩) + fun ⟨b, hb⟩ => ⟨b, fun _ ⟨_, hx, eq⟩ => eq ▸ hb hx⟩ + +theorem bddBelow_coe (s : Set ℝ≥0) : BddBelow (((↑) : ℝ≥0 → ℝ) '' s) := + ⟨0, fun _ ⟨q, _, eq⟩ => eq ▸ q.2⟩ + +noncomputable instance : ConditionallyCompleteLinearOrderBot ℝ≥0 := + Nonneg.conditionallyCompleteLinearOrderBot 0 + +@[norm_cast] +theorem coe_sSup (s : Set ℝ≥0) : (↑(sSup s) : ℝ) = sSup (((↑) : ℝ≥0 → ℝ) '' s) := by + rcases Set.eq_empty_or_nonempty s with rfl|hs + · simp + by_cases H : BddAbove s + · have A : sSup (Subtype.val '' s) ∈ Set.Ici 0 := by + apply Real.sSup_nonneg + rintro - ⟨y, -, rfl⟩ + exact y.2 + exact (@subset_sSup_of_within ℝ (Set.Ici (0 : ℝ)) _ _ (_) s hs H A).symm + · simp only [csSup_of_not_bddAbove H, csSup_empty, bot_eq_zero', NNReal.coe_zero] + apply (Real.sSup_of_not_bddAbove ?_).symm + contrapose! H + exact bddAbove_coe.1 H + +@[simp, norm_cast] -- Porting note: add `simp` +theorem coe_iSup {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨆ i, s i) : ℝ) = ⨆ i, ↑(s i) := by + rw [iSup, iSup, coe_sSup, ← Set.range_comp]; rfl + +@[norm_cast] +theorem coe_sInf (s : Set ℝ≥0) : (↑(sInf s) : ℝ) = sInf (((↑) : ℝ≥0 → ℝ) '' s) := by + rcases Set.eq_empty_or_nonempty s with rfl|hs + · simp only [Set.image_empty, Real.sInf_empty, coe_eq_zero] + exact @subset_sInf_emptyset ℝ (Set.Ici (0 : ℝ)) _ _ (_) + have A : sInf (Subtype.val '' s) ∈ Set.Ici 0 := by + apply Real.sInf_nonneg + rintro - ⟨y, -, rfl⟩ + exact y.2 + exact (@subset_sInf_of_within ℝ (Set.Ici (0 : ℝ)) _ _ (_) s hs (OrderBot.bddBelow s) A).symm + +@[simp] +theorem sInf_empty : sInf (∅ : Set ℝ≥0) = 0 := by + rw [← coe_eq_zero, coe_sInf, Set.image_empty, Real.sInf_empty] + +@[norm_cast] +theorem coe_iInf {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨅ i, s i) : ℝ) = ⨅ i, ↑(s i) := by + rw [iInf, iInf, coe_sInf, ← Set.range_comp]; rfl + +-- Short-circuit instance search +instance addLeftMono : AddLeftMono ℝ≥0 := inferInstance +instance addLeftReflectLT : AddLeftReflectLT ℝ≥0 := inferInstance +instance mulLeftMono : MulLeftMono ℝ≥0 := inferInstance + +@[deprecated le_of_forall_pos_le_add (since := "2024-10-17")] +protected theorem le_of_forall_pos_le_add {a b : ℝ≥0} (h : ∀ ε, 0 < ε → a ≤ b + ε) : a ≤ b := + le_of_forall_pos_le_add h + +theorem lt_iff_exists_rat_btwn (a b : ℝ≥0) : + a < b ↔ ∃ q : ℚ, 0 ≤ q ∧ a < Real.toNNReal q ∧ Real.toNNReal q < b := + Iff.intro + (fun h : (↑a : ℝ) < (↑b : ℝ) => + let ⟨q, haq, hqb⟩ := exists_rat_btwn h + have : 0 ≤ (q : ℝ) := le_trans a.2 <| le_of_lt haq + ⟨q, Rat.cast_nonneg.1 this, by + simp [Real.coe_toNNReal _ this, NNReal.coe_lt_coe.symm, haq, hqb]⟩) + fun ⟨_, _, haq, hqb⟩ => lt_trans haq hqb + +theorem bot_eq_zero : (⊥ : ℝ≥0) = 0 := rfl + +theorem mul_sup (a b c : ℝ≥0) : a * (b ⊔ c) = a * b ⊔ a * c := + mul_max_of_nonneg _ _ <| zero_le a + +theorem sup_mul (a b c : ℝ≥0) : (a ⊔ b) * c = a * c ⊔ b * c := + max_mul_of_nonneg _ _ <| zero_le c + +@[simp, norm_cast] +theorem coe_max (x y : ℝ≥0) : ((max x y : ℝ≥0) : ℝ) = max (x : ℝ) (y : ℝ) := + NNReal.coe_mono.map_max + +@[simp, norm_cast] +theorem coe_min (x y : ℝ≥0) : ((min x y : ℝ≥0) : ℝ) = min (x : ℝ) (y : ℝ) := + NNReal.coe_mono.map_min + +@[simp] +theorem zero_le_coe {q : ℝ≥0} : 0 ≤ (q : ℝ) := + q.2 + +instance instOrderedSMul {M : Type*} [OrderedAddCommMonoid M] [Module ℝ M] [OrderedSMul ℝ M] : + OrderedSMul ℝ≥0 M where + smul_lt_smul_of_pos hab hc := (smul_lt_smul_of_pos_left hab (NNReal.coe_pos.2 hc) : _) + lt_of_smul_lt_smul_of_pos {_ _ c} hab _ := + lt_of_smul_lt_smul_of_nonneg_left (by exact hab) (NNReal.coe_nonneg c) + +end NNReal + +open NNReal + +namespace Real + +section ToNNReal + +@[simp] +theorem coe_toNNReal' (r : ℝ) : (Real.toNNReal r : ℝ) = max r 0 := + rfl + +@[simp] +theorem toNNReal_zero : Real.toNNReal 0 = 0 := NNReal.eq <| coe_toNNReal _ le_rfl + +@[simp] +theorem toNNReal_one : Real.toNNReal 1 = 1 := NNReal.eq <| coe_toNNReal _ zero_le_one + +@[simp] +theorem toNNReal_pos {r : ℝ} : 0 < Real.toNNReal r ↔ 0 < r := by + simp [← NNReal.coe_lt_coe, lt_irrefl] + +@[simp] +theorem toNNReal_eq_zero {r : ℝ} : Real.toNNReal r = 0 ↔ r ≤ 0 := by + simpa [-toNNReal_pos] using not_iff_not.2 (@toNNReal_pos r) + +theorem toNNReal_of_nonpos {r : ℝ} : r ≤ 0 → Real.toNNReal r = 0 := + toNNReal_eq_zero.2 + +lemma toNNReal_eq_iff_eq_coe {r : ℝ} {p : ℝ≥0} (hp : p ≠ 0) : r.toNNReal = p ↔ r = p := + ⟨fun h ↦ h ▸ (coe_toNNReal _ <| not_lt.1 fun hlt ↦ hp <| h ▸ toNNReal_of_nonpos hlt.le).symm, + fun h ↦ h.symm ▸ toNNReal_coe⟩ + +@[simp] +lemma toNNReal_eq_one {r : ℝ} : r.toNNReal = 1 ↔ r = 1 := toNNReal_eq_iff_eq_coe one_ne_zero + +@[simp] +lemma toNNReal_eq_natCast {r : ℝ} {n : ℕ} (hn : n ≠ 0) : r.toNNReal = n ↔ r = n := + mod_cast toNNReal_eq_iff_eq_coe <| Nat.cast_ne_zero.2 hn + +@[deprecated (since := "2024-04-17")] +alias toNNReal_eq_nat_cast := toNNReal_eq_natCast + +@[simp] +lemma toNNReal_eq_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : + r.toNNReal = no_index (OfNat.ofNat n) ↔ r = OfNat.ofNat n := + toNNReal_eq_natCast (NeZero.ne n) + +@[simp] +theorem toNNReal_le_toNNReal_iff {r p : ℝ} (hp : 0 ≤ p) : + toNNReal r ≤ toNNReal p ↔ r ≤ p := by simp [← NNReal.coe_le_coe, hp] + +@[simp] +lemma toNNReal_le_one {r : ℝ} : r.toNNReal ≤ 1 ↔ r ≤ 1 := by + simpa using toNNReal_le_toNNReal_iff zero_le_one + +@[simp] +lemma one_lt_toNNReal {r : ℝ} : 1 < r.toNNReal ↔ 1 < r := by + simpa only [not_le] using toNNReal_le_one.not + +@[simp] +lemma toNNReal_le_natCast {r : ℝ} {n : ℕ} : r.toNNReal ≤ n ↔ r ≤ n := by + simpa using toNNReal_le_toNNReal_iff n.cast_nonneg + +@[deprecated (since := "2024-04-17")] +alias toNNReal_le_nat_cast := toNNReal_le_natCast + +@[simp] +lemma natCast_lt_toNNReal {r : ℝ} {n : ℕ} : n < r.toNNReal ↔ n < r := by + simpa only [not_le] using toNNReal_le_natCast.not + +@[deprecated (since := "2024-04-17")] +alias nat_cast_lt_toNNReal := natCast_lt_toNNReal + +@[simp] +lemma toNNReal_le_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : + r.toNNReal ≤ no_index (OfNat.ofNat n) ↔ r ≤ n := + toNNReal_le_natCast + +@[simp] +lemma ofNat_lt_toNNReal {r : ℝ} {n : ℕ} [n.AtLeastTwo] : + no_index (OfNat.ofNat n) < r.toNNReal ↔ n < r := + natCast_lt_toNNReal + +@[simp] +theorem toNNReal_eq_toNNReal_iff {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : + toNNReal r = toNNReal p ↔ r = p := by simp [← coe_inj, coe_toNNReal, hr, hp] + +@[simp] +theorem toNNReal_lt_toNNReal_iff' {r p : ℝ} : Real.toNNReal r < Real.toNNReal p ↔ r < p ∧ 0 < p := + NNReal.coe_lt_coe.symm.trans max_lt_max_left_iff + +theorem toNNReal_lt_toNNReal_iff {r p : ℝ} (h : 0 < p) : + Real.toNNReal r < Real.toNNReal p ↔ r < p := + toNNReal_lt_toNNReal_iff'.trans (and_iff_left h) + +theorem lt_of_toNNReal_lt {r p : ℝ} (h : r.toNNReal < p.toNNReal) : r < p := + (Real.toNNReal_lt_toNNReal_iff <| Real.toNNReal_pos.1 (ne_bot_of_gt h).bot_lt).1 h + +theorem toNNReal_lt_toNNReal_iff_of_nonneg {r p : ℝ} (hr : 0 ≤ r) : + Real.toNNReal r < Real.toNNReal p ↔ r < p := + toNNReal_lt_toNNReal_iff'.trans ⟨And.left, fun h => ⟨h, lt_of_le_of_lt hr h⟩⟩ + +lemma toNNReal_le_toNNReal_iff' {r p : ℝ} : r.toNNReal ≤ p.toNNReal ↔ r ≤ p ∨ r ≤ 0 := by + simp_rw [← not_lt, toNNReal_lt_toNNReal_iff', not_and_or] + +lemma toNNReal_le_toNNReal_iff_of_pos {r p : ℝ} (hr : 0 < r) : r.toNNReal ≤ p.toNNReal ↔ r ≤ p := by + simp [toNNReal_le_toNNReal_iff', hr.not_le] + +@[simp] +lemma one_le_toNNReal {r : ℝ} : 1 ≤ r.toNNReal ↔ 1 ≤ r := by + simpa using toNNReal_le_toNNReal_iff_of_pos one_pos + +@[simp] +lemma toNNReal_lt_one {r : ℝ} : r.toNNReal < 1 ↔ r < 1 := by simp only [← not_le, one_le_toNNReal] + +@[simp] +lemma natCastle_toNNReal' {n : ℕ} {r : ℝ} : ↑n ≤ r.toNNReal ↔ n ≤ r ∨ n = 0 := by + simpa [n.cast_nonneg.le_iff_eq] using toNNReal_le_toNNReal_iff' (r := n) + +@[deprecated (since := "2024-04-17")] +alias nat_cast_le_toNNReal' := natCastle_toNNReal' + +@[simp] +lemma toNNReal_lt_natCast' {n : ℕ} {r : ℝ} : r.toNNReal < n ↔ r < n ∧ n ≠ 0 := by + simpa [pos_iff_ne_zero] using toNNReal_lt_toNNReal_iff' (r := r) (p := n) + +@[deprecated (since := "2024-04-17")] +alias toNNReal_lt_nat_cast' := toNNReal_lt_natCast' + +lemma natCast_le_toNNReal {n : ℕ} {r : ℝ} (hn : n ≠ 0) : ↑n ≤ r.toNNReal ↔ n ≤ r := by simp [hn] + +@[deprecated (since := "2024-04-17")] +alias nat_cast_le_toNNReal := natCast_le_toNNReal + +lemma toNNReal_lt_natCast {r : ℝ} {n : ℕ} (hn : n ≠ 0) : r.toNNReal < n ↔ r < n := by simp [hn] + +@[deprecated (since := "2024-04-17")] +alias toNNReal_lt_nat_cast := toNNReal_lt_natCast + +@[simp] +lemma toNNReal_lt_ofNat {r : ℝ} {n : ℕ} [n.AtLeastTwo] : + r.toNNReal < no_index (OfNat.ofNat n) ↔ r < OfNat.ofNat n := + toNNReal_lt_natCast (NeZero.ne n) + +@[simp] +lemma ofNat_le_toNNReal {n : ℕ} {r : ℝ} [n.AtLeastTwo] : + no_index (OfNat.ofNat n) ≤ r.toNNReal ↔ OfNat.ofNat n ≤ r := + natCast_le_toNNReal (NeZero.ne n) + +@[simp] +theorem toNNReal_add {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : + Real.toNNReal (r + p) = Real.toNNReal r + Real.toNNReal p := + NNReal.eq <| by simp [hr, hp, add_nonneg] + +theorem toNNReal_add_toNNReal {r p : ℝ} (hr : 0 ≤ r) (hp : 0 ≤ p) : + Real.toNNReal r + Real.toNNReal p = Real.toNNReal (r + p) := + (Real.toNNReal_add hr hp).symm + +theorem toNNReal_le_toNNReal {r p : ℝ} (h : r ≤ p) : Real.toNNReal r ≤ Real.toNNReal p := + Real.toNNReal_mono h + +theorem toNNReal_add_le {r p : ℝ} : Real.toNNReal (r + p) ≤ Real.toNNReal r + Real.toNNReal p := + NNReal.coe_le_coe.1 <| max_le (add_le_add (le_max_left _ _) (le_max_left _ _)) NNReal.zero_le_coe + +theorem toNNReal_le_iff_le_coe {r : ℝ} {p : ℝ≥0} : toNNReal r ≤ p ↔ r ≤ ↑p := + NNReal.gi.gc r p + +theorem le_toNNReal_iff_coe_le {r : ℝ≥0} {p : ℝ} (hp : 0 ≤ p) : r ≤ Real.toNNReal p ↔ ↑r ≤ p := by + rw [← NNReal.coe_le_coe, Real.coe_toNNReal p hp] + +theorem le_toNNReal_iff_coe_le' {r : ℝ≥0} {p : ℝ} (hr : 0 < r) : r ≤ Real.toNNReal p ↔ ↑r ≤ p := + (le_or_lt 0 p).elim le_toNNReal_iff_coe_le fun hp => by + simp only [(hp.trans_le r.coe_nonneg).not_le, toNNReal_eq_zero.2 hp.le, hr.not_le] + +theorem toNNReal_lt_iff_lt_coe {r : ℝ} {p : ℝ≥0} (ha : 0 ≤ r) : Real.toNNReal r < p ↔ r < ↑p := by + rw [← NNReal.coe_lt_coe, Real.coe_toNNReal r ha] + +theorem lt_toNNReal_iff_coe_lt {r : ℝ≥0} {p : ℝ} : r < Real.toNNReal p ↔ ↑r < p := + lt_iff_lt_of_le_iff_le toNNReal_le_iff_le_coe + +theorem toNNReal_pow {x : ℝ} (hx : 0 ≤ x) (n : ℕ) : (x ^ n).toNNReal = x.toNNReal ^ n := by + rw [← coe_inj, NNReal.coe_pow, Real.coe_toNNReal _ (pow_nonneg hx _), + Real.coe_toNNReal x hx] + +theorem toNNReal_mul {p q : ℝ} (hp : 0 ≤ p) : + Real.toNNReal (p * q) = Real.toNNReal p * Real.toNNReal q := + NNReal.eq <| by simp [mul_max_of_nonneg, hp] + +end ToNNReal + +end Real + +open Real + +namespace NNReal + +section Mul + +theorem mul_eq_mul_left {a b c : ℝ≥0} (h : a ≠ 0) : a * b = a * c ↔ b = c := by + rw [mul_eq_mul_left_iff, or_iff_left h] + +end Mul + +section Pow + +theorem pow_antitone_exp {a : ℝ≥0} (m n : ℕ) (mn : m ≤ n) (a1 : a ≤ 1) : a ^ n ≤ a ^ m := + pow_le_pow_of_le_one (zero_le a) a1 mn + +nonrec theorem exists_pow_lt_of_lt_one {a b : ℝ≥0} (ha : 0 < a) (hb : b < 1) : + ∃ n : ℕ, b ^ n < a := by + simpa only [← coe_pow, NNReal.coe_lt_coe] using + exists_pow_lt_of_lt_one (NNReal.coe_pos.2 ha) (NNReal.coe_lt_coe.2 hb) + +nonrec theorem exists_mem_Ico_zpow {x : ℝ≥0} {y : ℝ≥0} (hx : x ≠ 0) (hy : 1 < y) : + ∃ n : ℤ, x ∈ Set.Ico (y ^ n) (y ^ (n + 1)) := + exists_mem_Ico_zpow (α := ℝ) hx.bot_lt hy + +nonrec theorem exists_mem_Ioc_zpow {x : ℝ≥0} {y : ℝ≥0} (hx : x ≠ 0) (hy : 1 < y) : + ∃ n : ℤ, x ∈ Set.Ioc (y ^ n) (y ^ (n + 1)) := + exists_mem_Ioc_zpow (α := ℝ) hx.bot_lt hy + +end Pow + +section Sub + +/-! +### Lemmas about subtraction + +In this section we provide a few lemmas about subtraction that do not fit well into any other +typeclass. For lemmas about subtraction and addition see lemmas about `OrderedSub` in the file +`Mathlib.Algebra.Order.Sub.Basic`. See also `mul_tsub` and `tsub_mul`. +-/ + +theorem sub_def {r p : ℝ≥0} : r - p = Real.toNNReal (r - p) := + rfl + +theorem coe_sub_def {r p : ℝ≥0} : ↑(r - p) = max (r - p : ℝ) 0 := + rfl + +example : OrderedSub ℝ≥0 := by infer_instance + +end Sub + +section Inv + +@[simp] +theorem inv_le {r p : ℝ≥0} (h : r ≠ 0) : r⁻¹ ≤ p ↔ 1 ≤ r * p := by + rw [← mul_le_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h] + +theorem inv_le_of_le_mul {r p : ℝ≥0} (h : 1 ≤ r * p) : r⁻¹ ≤ p := by + by_cases r = 0 <;> simp [*, inv_le] + +@[simp] +theorem le_inv_iff_mul_le {r p : ℝ≥0} (h : p ≠ 0) : r ≤ p⁻¹ ↔ r * p ≤ 1 := by + rw [← mul_le_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h, mul_comm] + +@[simp] +theorem lt_inv_iff_mul_lt {r p : ℝ≥0} (h : p ≠ 0) : r < p⁻¹ ↔ r * p < 1 := by + rw [← mul_lt_mul_left (pos_iff_ne_zero.2 h), mul_inv_cancel₀ h, mul_comm] + +@[deprecated le_inv_mul_iff₀ (since := "2024-08-21")] +theorem mul_le_iff_le_inv {a b r : ℝ≥0} (hr : r ≠ 0) : r * a ≤ b ↔ a ≤ r⁻¹ * b := + (le_inv_mul_iff₀ (pos_iff_ne_zero.2 hr)).symm + +@[deprecated le_div_iff₀ (since := "2024-08-21")] +theorem le_div_iff_mul_le {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ a * r ≤ b := + le_div_iff₀ (pos_iff_ne_zero.2 hr) + +@[deprecated div_le_iff₀ (since := "2024-08-21")] +protected lemma div_le_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ b * r := + div_le_iff₀ (pos_iff_ne_zero.2 hr) + +@[deprecated div_le_iff₀' (since := "2024-08-21")] +protected lemma div_le_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ r * b := + div_le_iff₀' (pos_iff_ne_zero.2 hr) + +theorem div_le_of_le_mul {a b c : ℝ≥0} (h : a ≤ b * c) : a / c ≤ b := + if h0 : c = 0 then by simp [h0] else (div_le_iff₀ (pos_iff_ne_zero.2 h0)).2 h + +theorem div_le_of_le_mul' {a b c : ℝ≥0} (h : a ≤ b * c) : a / b ≤ c := + div_le_of_le_mul <| mul_comm b c ▸ h + +@[deprecated le_div_iff₀ (since := "2024-08-21")] +protected lemma le_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ a * r ≤ b := + le_div_iff₀ hr.bot_lt + +@[deprecated le_div_iff₀' (since := "2024-10-02")] +theorem le_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ r * a ≤ b := le_div_iff₀' hr.bot_lt + +@[deprecated div_lt_iff₀ (since := "2024-10-02")] +theorem div_lt_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < b * r := div_lt_iff₀ hr.bot_lt + +@[deprecated div_lt_iff₀' (since := "2024-10-02")] +theorem div_lt_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r < b ↔ a < r * b := div_lt_iff₀' hr.bot_lt + +@[deprecated lt_div_iff₀ (since := "2024-10-02")] +theorem lt_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ a * r < b := lt_div_iff₀ hr.bot_lt + +@[deprecated lt_div_iff₀' (since := "2024-10-02")] +theorem lt_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ r * a < b := lt_div_iff₀' hr.bot_lt + +theorem mul_lt_of_lt_div {a b r : ℝ≥0} (h : a < b / r) : a * r < b := + (lt_div_iff₀ <| pos_iff_ne_zero.2 fun hr => False.elim <| by simp [hr] at h).1 h + +theorem div_le_div_left_of_le {a b c : ℝ≥0} (c0 : c ≠ 0) (cb : c ≤ b) : + a / b ≤ a / c := + div_le_div_of_nonneg_left (zero_le _) c0.bot_lt cb + +nonrec theorem div_le_div_left {a b c : ℝ≥0} (a0 : 0 < a) (b0 : 0 < b) (c0 : 0 < c) : + a / b ≤ a / c ↔ c ≤ b := + div_le_div_left a0 b0 c0 + +theorem le_of_forall_lt_one_mul_le {x y : ℝ≥0} (h : ∀ a < 1, a * x ≤ y) : x ≤ y := + le_of_forall_ge_of_dense fun a ha => by + have hx : x ≠ 0 := pos_iff_ne_zero.1 (lt_of_le_of_lt (zero_le _) ha) + have hx' : x⁻¹ ≠ 0 := by rwa [Ne, inv_eq_zero] + have : a * x⁻¹ < 1 := by rwa [← lt_inv_iff_mul_lt hx', inv_inv] + have : a * x⁻¹ * x ≤ y := h _ this + rwa [mul_assoc, inv_mul_cancel₀ hx, mul_one] at this + +nonrec theorem half_le_self (a : ℝ≥0) : a / 2 ≤ a := + half_le_self bot_le + +nonrec theorem half_lt_self {a : ℝ≥0} (h : a ≠ 0) : a / 2 < a := + half_lt_self h.bot_lt + +theorem div_lt_one_of_lt {a b : ℝ≥0} (h : a < b) : a / b < 1 := by + rwa [div_lt_iff₀ h.bot_lt, one_mul] + +theorem _root_.Real.toNNReal_inv {x : ℝ} : Real.toNNReal x⁻¹ = (Real.toNNReal x)⁻¹ := by + rcases le_total 0 x with hx | hx + · nth_rw 1 [← Real.coe_toNNReal x hx] + rw [← NNReal.coe_inv, Real.toNNReal_coe] + · rw [toNNReal_eq_zero.mpr hx, inv_zero, toNNReal_eq_zero.mpr (inv_nonpos.mpr hx)] + +theorem _root_.Real.toNNReal_div {x y : ℝ} (hx : 0 ≤ x) : + Real.toNNReal (x / y) = Real.toNNReal x / Real.toNNReal y := by + rw [div_eq_mul_inv, div_eq_mul_inv, ← Real.toNNReal_inv, ← Real.toNNReal_mul hx] + +theorem _root_.Real.toNNReal_div' {x y : ℝ} (hy : 0 ≤ y) : + Real.toNNReal (x / y) = Real.toNNReal x / Real.toNNReal y := by + rw [div_eq_inv_mul, div_eq_inv_mul, Real.toNNReal_mul (inv_nonneg.2 hy), Real.toNNReal_inv] + +theorem inv_lt_one_iff {x : ℝ≥0} (hx : x ≠ 0) : x⁻¹ < 1 ↔ 1 < x := by + rw [← one_div, div_lt_iff₀ hx.bot_lt, one_mul] + +@[deprecated zpow_pos (since := "2024-10-08")] +protected theorem zpow_pos {x : ℝ≥0} (hx : x ≠ 0) (n : ℤ) : 0 < x ^ n := zpow_pos hx.bot_lt _ + +theorem inv_lt_inv {x y : ℝ≥0} (hx : x ≠ 0) (h : x < y) : y⁻¹ < x⁻¹ := + inv_strictAnti₀ hx.bot_lt h + +end Inv + +@[simp] +theorem abs_eq (x : ℝ≥0) : |(x : ℝ)| = x := + abs_of_nonneg x.property + +section Csupr + +open Set + +variable {ι : Sort*} {f : ι → ℝ≥0} + +theorem le_toNNReal_of_coe_le {x : ℝ≥0} {y : ℝ} (h : ↑x ≤ y) : x ≤ y.toNNReal := + (le_toNNReal_iff_coe_le <| x.2.trans h).2 h + +nonrec theorem sSup_of_not_bddAbove {s : Set ℝ≥0} (hs : ¬BddAbove s) : SupSet.sSup s = 0 := by + rw [← bddAbove_coe] at hs + rw [← coe_inj, coe_sSup, NNReal.coe_zero] + exact sSup_of_not_bddAbove hs + +theorem iSup_of_not_bddAbove (hf : ¬BddAbove (range f)) : ⨆ i, f i = 0 := + sSup_of_not_bddAbove hf + +theorem iSup_empty [IsEmpty ι] (f : ι → ℝ≥0) : ⨆ i, f i = 0 := ciSup_of_empty f + +theorem iInf_empty [IsEmpty ι] (f : ι → ℝ≥0) : ⨅ i, f i = 0 := by + rw [_root_.iInf_of_isEmpty, sInf_empty] + +@[simp] lemma iSup_eq_zero (hf : BddAbove (range f)) : ⨆ i, f i = 0 ↔ ∀ i, f i = 0 := by + cases isEmpty_or_nonempty ι + · simp + · simp [← bot_eq_zero', ← le_bot_iff, ciSup_le_iff hf] + +@[simp] +theorem iInf_const_zero {α : Sort*} : ⨅ _ : α, (0 : ℝ≥0) = 0 := by + rw [← coe_inj, coe_iInf] + exact Real.iInf_const_zero + +end Csupr + +end NNReal + +namespace Set + +namespace OrdConnected + +variable {s : Set ℝ} {t : Set ℝ≥0} + +theorem preimage_coe_nnreal_real (h : s.OrdConnected) : ((↑) ⁻¹' s : Set ℝ≥0).OrdConnected := + h.preimage_mono NNReal.coe_mono + +theorem image_coe_nnreal_real (h : t.OrdConnected) : ((↑) '' t : Set ℝ).OrdConnected := + ⟨forall_mem_image.2 fun x hx => + forall_mem_image.2 fun _y hy z hz => ⟨⟨z, x.2.trans hz.1⟩, h.out hx hy hz, rfl⟩⟩ + +-- Porting note (#11215): TODO: does it generalize to a `GaloisInsertion`? +theorem image_real_toNNReal (h : s.OrdConnected) : (Real.toNNReal '' s).OrdConnected := by + refine ⟨forall_mem_image.2 fun x hx => forall_mem_image.2 fun y hy z hz => ?_⟩ + rcases le_total y 0 with hy₀ | hy₀ + · rw [mem_Icc, Real.toNNReal_of_nonpos hy₀, nonpos_iff_eq_zero] at hz + exact ⟨y, hy, (toNNReal_of_nonpos hy₀).trans hz.2.symm⟩ + · lift y to ℝ≥0 using hy₀ + rw [toNNReal_coe] at hz + exact ⟨z, h.out hx hy ⟨toNNReal_le_iff_le_coe.1 hz.1, hz.2⟩, toNNReal_coe⟩ + +theorem preimage_real_toNNReal (h : t.OrdConnected) : (Real.toNNReal ⁻¹' t).OrdConnected := + h.preimage_mono Real.toNNReal_mono + +end OrdConnected + +end Set + +namespace Real + +/-- The absolute value on `ℝ` as a map to `ℝ≥0`. -/ +-- Porting note (kmill): `pp_nodot` has no affect here +-- unless RFC lean4#1910 leads to dot notation for CoeFun +@[pp_nodot] +def nnabs : ℝ →*₀ ℝ≥0 where + toFun x := ⟨|x|, abs_nonneg x⟩ + map_zero' := by ext; simp + map_one' := by ext; simp + map_mul' x y := by ext; simp [abs_mul] + +@[norm_cast, simp] +theorem coe_nnabs (x : ℝ) : (nnabs x : ℝ) = |x| := + rfl + +@[simp] +theorem nnabs_of_nonneg {x : ℝ} (h : 0 ≤ x) : nnabs x = toNNReal x := by + ext + rw [coe_toNNReal x h, coe_nnabs, abs_of_nonneg h] + +theorem nnabs_coe (x : ℝ≥0) : nnabs x = x := by simp + +theorem coe_toNNReal_le (x : ℝ) : (toNNReal x : ℝ) ≤ |x| := + max_le (le_abs_self _) (abs_nonneg _) + +@[simp] lemma toNNReal_abs (x : ℝ) : |x|.toNNReal = nnabs x := NNReal.coe_injective <| by simp + +theorem cast_natAbs_eq_nnabs_cast (n : ℤ) : (n.natAbs : ℝ≥0) = nnabs n := by + ext + rw [NNReal.coe_natCast, Int.cast_natAbs, Real.coe_nnabs, Int.cast_abs] + +end Real + +section StrictMono + +open NNReal + +variable {Γ₀ : Type*} [LinearOrderedCommGroupWithZero Γ₀] + +/-- If `Γ₀ˣ` is nontrivial and `f : Γ₀ →*₀ ℝ≥0` is strictly monotone, then for any positive + `r : ℝ≥0`, there exists `d : Γ₀ˣ` with `f d < r`. -/ +theorem NNReal.exists_lt_of_strictMono [h : Nontrivial Γ₀ˣ] {f : Γ₀ →*₀ ℝ≥0} (hf : StrictMono f) + {r : ℝ≥0} (hr : 0 < r) : ∃ d : Γ₀ˣ, f d < r := by + obtain ⟨g, hg1⟩ := (nontrivial_iff_exists_ne (1 : Γ₀ˣ)).mp h + set u : Γ₀ˣ := if g < 1 then g else g⁻¹ with hu + have hfu : f u < 1 := by + rw [hu] + split_ifs with hu1 + · rw [← map_one f]; exact hf hu1 + · have hfg0 : f g ≠ 0 := + fun h0 ↦ (Units.ne_zero g) ((map_eq_zero f).mp h0) + have hg1' : 1 < g := lt_of_le_of_ne (not_lt.mp hu1) hg1.symm + rw [Units.val_inv_eq_inv_val, map_inv₀, inv_lt_one_iff hfg0, ← map_one f] + exact hf hg1' + obtain ⟨n, hn⟩ := exists_pow_lt_of_lt_one hr hfu + use u ^ n + rwa [Units.val_pow_eq_pow_val, map_pow] + +/-- If `Γ₀ˣ` is nontrivial and `f : Γ₀ →*₀ ℝ≥0` is strictly monotone, then for any positive + real `r`, there exists `d : Γ₀ˣ` with `f d < r`. -/ +theorem Real.exists_lt_of_strictMono [h : Nontrivial Γ₀ˣ] {f : Γ₀ →*₀ ℝ≥0} (hf : StrictMono f) + {r : ℝ} (hr : 0 < r) : ∃ d : Γ₀ˣ, (f d : ℝ) < r := by + set s : NNReal := ⟨r, le_of_lt hr⟩ + have hs : 0 < s := hr + exact NNReal.exists_lt_of_strictMono hf hs + +end StrictMono + +namespace Mathlib.Meta.Positivity + +open Lean Meta Qq Function + +private alias ⟨_, nnreal_coe_pos⟩ := coe_pos + +/-- Extension for the `positivity` tactic: cast from `ℝ≥0` to `ℝ`. -/ +@[positivity NNReal.toReal _] +def evalNNRealtoReal : PositivityExt where eval {u α} _zα _pα e := do + match u, α, e with + | 0, ~q(ℝ), ~q(NNReal.toReal $a) => + let ra ← core q(inferInstance) q(inferInstance) a + assertInstancesCommute + match ra with + | .positive pa => pure (.positive q(nnreal_coe_pos $pa)) + | _ => pure (.nonnegative q(NNReal.coe_nonneg $a)) + | _, _, _ => throwError "not NNReal.toReal" + +end Mathlib.Meta.Positivity diff --git a/Mathlib/Data/NNReal/Star.lean b/Mathlib/Data/NNReal/Star.lean index 37a7a68423a4b..c1f11b1539a4e 100644 --- a/Mathlib/Data/NNReal/Star.lean +++ b/Mathlib/Data/NNReal/Star.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Jireh Loreaux. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ +import Mathlib.Data.NNReal.Defs import Mathlib.Data.Real.Star -import Mathlib.Data.NNReal.Basic /-! # The non-negative real numbers are a `*`-ring, with the trivial `*`-structure diff --git a/Mathlib/Data/Nat/BinaryRec.lean b/Mathlib/Data/Nat/BinaryRec.lean new file mode 100644 index 0000000000000..c13d452454b24 --- /dev/null +++ b/Mathlib/Data/Nat/BinaryRec.lean @@ -0,0 +1,152 @@ +/- +Copyright (c) 2017 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Praneeth Kolichala, Yuyang Zhao +-/ +import Batteries.Tactic.Alias +import Mathlib.Init + +/-! +# Binary recursion on `Nat` + +This file defines binary recursion on `Nat`. + +## Main results +* `Nat.binaryRec`: A recursion principle for `bit` representations of natural numbers. +* `Nat.binaryRec'`: The same as `binaryRec`, but the induction step can assume that if `n=0`, + the bit being appended is `true`. +* `Nat.binaryRecFromOne`: The same as `binaryRec`, but special casing both 0 and 1 as base cases. +-/ + +universe u + +namespace Nat + +/-- `bit b` appends the digit `b` to the binary representation of its natural number input. -/ +def bit (b : Bool) : Nat → Nat := cond b (2 * · + 1) (2 * ·) + +theorem shiftRight_one (n) : n >>> 1 = n / 2 := rfl + +@[simp] +theorem bit_decide_mod_two_eq_one_shiftRight_one (n : Nat) : bit (n % 2 = 1) (n >>> 1) = n := by + simp only [bit, shiftRight_one] + cases mod_two_eq_zero_or_one n with | _ h => simpa [h] using Nat.div_add_mod n 2 + +theorem bit_testBit_zero_shiftRight_one (n : Nat) : bit (n.testBit 0) (n >>> 1) = n := by + simp + +@[simp] +theorem bit_eq_zero_iff {n : Nat} {b : Bool} : bit b n = 0 ↔ n = 0 ∧ b = false := by + cases n <;> cases b <;> simp [bit, Nat.shiftLeft_succ, Nat.two_mul, ← Nat.add_assoc] + +/-- For a predicate `motive : Nat → Sort u`, if instances can be + constructed for natural numbers of the form `bit b n`, + they can be constructed for any given natural number. -/ +@[inline] +def bitCasesOn {motive : Nat → Sort u} (n) (h : ∀ b n, motive (bit b n)) : motive n := + -- `1 &&& n != 0` is faster than `n.testBit 0`. This may change when we have faster `testBit`. + let x := h (1 &&& n != 0) (n >>> 1) + -- `congrArg motive _ ▸ x` is defeq to `x` in non-dependent case + congrArg motive n.bit_testBit_zero_shiftRight_one ▸ x + +/-- A recursion principle for `bit` representations of natural numbers. + For a predicate `motive : Nat → Sort u`, if instances can be + constructed for natural numbers of the form `bit b n`, + they can be constructed for all natural numbers. -/ +@[elab_as_elim, specialize] +def binaryRec {motive : Nat → Sort u} (z : motive 0) (f : ∀ b n, motive n → motive (bit b n)) + (n : Nat) : motive n := + if n0 : n = 0 then congrArg motive n0 ▸ z + else + let x := f (1 &&& n != 0) (n >>> 1) (binaryRec z f (n >>> 1)) + congrArg motive n.bit_testBit_zero_shiftRight_one ▸ x +decreasing_by exact bitwise_rec_lemma n0 + +/-- The same as `binaryRec`, but the induction step can assume that if `n=0`, + the bit being appended is `true`-/ +@[elab_as_elim, specialize] +def binaryRec' {motive : Nat → Sort u} (z : motive 0) + (f : ∀ b n, (n = 0 → b = true) → motive n → motive (bit b n)) : + ∀ n, motive n := + binaryRec z fun b n ih => + if h : n = 0 → b = true then f b n h ih + else + have : bit b n = 0 := by + rw [bit_eq_zero_iff] + cases n <;> cases b <;> simp at h ⊢ + congrArg motive this ▸ z + +/-- The same as `binaryRec`, but special casing both 0 and 1 as base cases -/ +@[elab_as_elim, specialize] +def binaryRecFromOne {motive : Nat → Sort u} (z₀ : motive 0) (z₁ : motive 1) + (f : ∀ b n, n ≠ 0 → motive n → motive (bit b n)) : + ∀ n, motive n := + binaryRec' z₀ fun b n h ih => + if h' : n = 0 then + have : bit b n = bit true 0 := by + rw [h', h h'] + congrArg motive this ▸ z₁ + else f b n h' ih + +theorem bit_val (b n) : bit b n = 2 * n + b.toNat := by + cases b <;> rfl + +@[simp] +theorem bit_div_two (b n) : bit b n / 2 = n := by + rw [bit_val, Nat.add_comm, add_mul_div_left, div_eq_of_lt, Nat.zero_add] + · cases b <;> decide + · decide + +@[simp] +theorem bit_mod_two (b n) : bit b n % 2 = b.toNat := by + cases b <;> simp [bit_val, mul_add_mod] + +@[simp] +theorem bit_shiftRight_one (b n) : bit b n >>> 1 = n := + bit_div_two b n + +theorem testBit_bit_zero (b n) : (bit b n).testBit 0 = b := by + simp + +variable {motive : Nat → Sort u} + +@[simp] +theorem bitCasesOn_bit (h : ∀ b n, motive (bit b n)) (b : Bool) (n : Nat) : + bitCasesOn (bit b n) h = h b n := by + change congrArg motive (bit b n).bit_testBit_zero_shiftRight_one ▸ h _ _ = h b n + generalize congrArg motive (bit b n).bit_testBit_zero_shiftRight_one = e; revert e + rw [testBit_bit_zero, bit_shiftRight_one] + intros; rfl + +unseal binaryRec in +@[simp] +theorem binaryRec_zero (z : motive 0) (f : ∀ b n, motive n → motive (bit b n)) : + binaryRec z f 0 = z := + rfl + +@[simp] +theorem binaryRec_one (z : motive 0) (f : ∀ b n, motive n → motive (bit b n)) : + binaryRec (motive := motive) z f 1 = f true 0 z := by + rw [binaryRec] + simp only [add_one_ne_zero, ↓reduceDIte, Nat.reduceShiftRight, binaryRec_zero] + rfl + +theorem binaryRec_eq {z : motive 0} {f : ∀ b n, motive n → motive (bit b n)} + (b n) (h : f false 0 z = z ∨ (n = 0 → b = true)) : + binaryRec z f (bit b n) = f b n (binaryRec z f n) := by + by_cases h' : bit b n = 0 + case pos => + obtain ⟨rfl, rfl⟩ := bit_eq_zero_iff.mp h' + simp only [Bool.false_eq_true, imp_false, not_true_eq_false, or_false] at h + unfold binaryRec + exact h.symm + case neg => + rw [binaryRec, dif_neg h'] + change congrArg motive (bit b n).bit_testBit_zero_shiftRight_one ▸ f _ _ _ = _ + generalize congrArg motive (bit b n).bit_testBit_zero_shiftRight_one = e; revert e + rw [testBit_bit_zero, bit_shiftRight_one] + intros; rfl + +@[deprecated (since := "2024-10-21")] alias binaryRec_eq' := binaryRec_eq + +end Nat diff --git a/Mathlib/Data/Nat/BitIndices.lean b/Mathlib/Data/Nat/BitIndices.lean index 79bd2eb583ef4..9d9c7c094edad 100644 --- a/Mathlib/Data/Nat/BitIndices.lean +++ b/Mathlib/Data/Nat/BitIndices.lean @@ -3,12 +3,12 @@ Copyright (c) 2024 Peter Nelson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Peter Nelson -/ -import Mathlib.Data.List.Sort -import Mathlib.Data.Nat.Bitwise import Mathlib.Algebra.BigOperators.Ring.List import Mathlib.Algebra.Order.BigOperators.Group.List import Mathlib.Algebra.Order.Star.Basic -import Mathlib.Algebra.Order.Sub.Defs +import Mathlib.Algebra.Order.Sub.Basic +import Mathlib.Data.List.Sort +import Mathlib.Data.Nat.Bitwise /-! # Bit Indices @@ -41,11 +41,11 @@ def bitIndices (n : ℕ) : List ℕ := theorem bitIndices_bit_true (n : ℕ) : bitIndices (bit true n) = 0 :: ((bitIndices n).map (· + 1)) := - binaryRec_eq rfl _ _ + binaryRec_eq _ _ (.inl rfl) theorem bitIndices_bit_false (n : ℕ) : bitIndices (bit false n) = (bitIndices n).map (· + 1) := - binaryRec_eq rfl _ _ + binaryRec_eq _ _ (.inl rfl) @[simp] theorem bitIndices_two_mul_add_one (n : ℕ) : bitIndices (2 * n + 1) = 0 :: (bitIndices n).map (· + 1) := by diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index 753381e7318d1..7079602da88d9 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -6,6 +6,7 @@ Authors: Praneeth Kolichala import Mathlib.Algebra.Group.Basic import Mathlib.Algebra.Group.Nat import Mathlib.Data.Nat.Defs +import Mathlib.Data.Nat.BinaryRec import Mathlib.Data.List.Defs import Mathlib.Tactic.Convert import Mathlib.Tactic.GeneralizeProofs @@ -72,7 +73,7 @@ lemma bodd_mul (m n : ℕ) : bodd (m * n) = (bodd m && bodd n) := by simp only [mul_succ, bodd_add, IH, bodd_succ] cases bodd m <;> cases bodd n <;> rfl -lemma mod_two_of_bodd (n : ℕ) : n % 2 = cond (bodd n) 1 0 := by +lemma mod_two_of_bodd (n : ℕ) : n % 2 = (bodd n).toNat := by have := congr_arg bodd (mod_add_div n 2) simp? [not] at this says simp only [bodd_add, bodd_mul, bodd_succ, not, bodd_zero, Bool.false_and, Bool.bne_false] @@ -99,7 +100,7 @@ lemma div2_succ (n : ℕ) : div2 (n + 1) = cond (bodd n) (succ (div2 n)) (div2 n attribute [local simp] Nat.add_comm Nat.add_assoc Nat.add_left_comm Nat.mul_comm Nat.mul_assoc -lemma bodd_add_div2 : ∀ n, cond (bodd n) 1 0 + 2 * div2 n = n +lemma bodd_add_div2 : ∀ n, (bodd n).toNat + 2 * div2 n = n | 0 => rfl | succ n => by simp only [bodd_succ, Bool.cond_not, div2_succ, Nat.mul_comm] @@ -113,20 +114,9 @@ lemma div2_val (n) : div2 n = n / 2 := by (Nat.add_left_cancel (Eq.trans ?_ (Nat.mod_add_div n 2).symm)) rw [mod_two_of_bodd, bodd_add_div2] -/-- `bit b` appends the digit `b` to the binary representation of its natural number input. -/ -def bit (b : Bool) : ℕ → ℕ := cond b (2 * · + 1) (2 * ·) - -lemma bit_val (b n) : bit b n = 2 * n + cond b 1 0 := by - cases b <;> rfl - lemma bit_decomp (n : Nat) : bit (bodd n) (div2 n) = n := (bit_val _ _).trans <| (Nat.add_comm _ _).trans <| bodd_add_div2 _ -/-- For a predicate `C : Nat → Sort*`, if instances can be - constructed for natural numbers of the form `bit b n`, - they can be constructed for any given natural number. -/ -def bitCasesOn {C : Nat → Sort u} (n) (h : ∀ b n, C (bit b n)) : C n := bit_decomp n ▸ h _ _ - lemma bit_zero : bit false 0 = 0 := rfl @@ -156,23 +146,6 @@ lemma binaryRec_decreasing (h : n ≠ 0) : div2 n < n := by (lt_of_le_of_ne n.zero_le h.symm) rwa [Nat.mul_one] at this -/-- A recursion principle for `bit` representations of natural numbers. - For a predicate `C : Nat → Sort*`, if instances can be - constructed for natural numbers of the form `bit b n`, - they can be constructed for all natural numbers. -/ -def binaryRec {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) : ∀ n, C n := - fun n => - if n0 : n = 0 then by - simp only [n0] - exact z - else by - let n' := div2 n - have _x : bit (bodd n) n' = n := by - apply bit_decomp n - rw [← _x] - exact f (bodd n) n' (binaryRec z f n') - decreasing_by exact binaryRec_decreasing n0 - /-- `size n` : Returns the size of a natural number in bits i.e. the length of its binary representation -/ def size : ℕ → ℕ := @@ -189,18 +162,6 @@ def bits : ℕ → List Bool := def ldiff : ℕ → ℕ → ℕ := bitwise fun a b => a && not b -@[simp] -lemma binaryRec_zero {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) : - binaryRec z f 0 = z := by - rw [binaryRec] - rfl - -@[simp] -lemma binaryRec_one {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) : - binaryRec z f 1 = f true 0 z := by - rw [binaryRec] - simp - /-! bitwise ops -/ lemma bodd_bit (b n) : bodd (bit b n) = b := by @@ -219,7 +180,7 @@ lemma shiftLeft'_add (b m n) : ∀ k, shiftLeft' b m (n + k) = shiftLeft' b (shi | k + 1 => congr_arg (bit b) (shiftLeft'_add b m n k) lemma shiftLeft'_sub (b m) : ∀ {n k}, k ≤ n → shiftLeft' b m (n - k) = (shiftLeft' b m n) >>> k - | n, 0, _ => rfl + | _, 0, _ => rfl | n + 1, k + 1, h => by rw [succ_sub_succ_eq_sub, shiftLeft', Nat.add_comm, shiftRight_add] simp only [shiftLeft'_sub, Nat.le_of_succ_le_succ h, shiftRight_succ, shiftRight_zero] @@ -228,13 +189,6 @@ lemma shiftLeft'_sub (b m) : ∀ {n k}, k ≤ n → shiftLeft' b m (n - k) = (sh lemma shiftLeft_sub : ∀ (m : Nat) {n k}, k ≤ n → m <<< (n - k) = (m <<< n) >>> k := fun _ _ _ hk => by simp only [← shiftLeft'_false, shiftLeft'_sub false _ hk] --- Not a `simp` lemma, as later `simp` will be able to prove this. -lemma testBit_bit_zero (b n) : testBit (bit b n) 0 = b := by - rw [testBit, bit] - cases b - · simp [← Nat.mul_two] - · simp [← Nat.mul_two] - lemma bodd_eq_one_and_ne_zero : ∀ n, bodd n = (1 &&& n != 0) | 0 => rfl | 1 => rfl @@ -248,25 +202,6 @@ lemma testBit_bit_succ (m b n) : testBit (bit b n) (succ m) = testBit n m := by simp only [bodd_eq_one_and_ne_zero] at this exact this -lemma binaryRec_eq {C : Nat → Sort u} {z : C 0} {f : ∀ b n, C n → C (bit b n)} - (h : f false 0 z = z) (b n) : binaryRec z f (bit b n) = f b n (binaryRec z f n) := by - rw [binaryRec] - split_ifs with h' - · generalize binaryRec z f (bit b n) = e - revert e - have bf := bodd_bit b n - have n0 := div2_bit b n - rw [h'] at bf n0 - simp only [bodd_zero, div2_zero] at bf n0 - subst bf n0 - rw [binaryRec_zero] - intros - rw [h, eq_mpr_eq_cast, cast_eq] - · simp only; generalize_proofs h - revert h - rw [bodd_bit, div2_bit] - intros; simp only [eq_mpr_eq_cast, cast_eq] - /-! ### `boddDiv2_eq` and `bodd` -/ @@ -295,37 +230,26 @@ theorem bit_ne_zero (b) {n} (h : n ≠ 0) : bit b n ≠ 0 := by cases b <;> dsimp [bit] <;> omega @[simp] -theorem bitCasesOn_bit {C : ℕ → Sort u} (H : ∀ b n, C (bit b n)) (b : Bool) (n : ℕ) : - bitCasesOn (bit b n) H = H b n := - eq_of_heq <| (eqRec_heq _ _).trans <| by rw [bodd_bit, div2_bit] - -@[simp] -theorem bitCasesOn_bit0 {C : ℕ → Sort u} (H : ∀ b n, C (bit b n)) (n : ℕ) : +theorem bitCasesOn_bit0 {motive : ℕ → Sort u} (H : ∀ b n, motive (bit b n)) (n : ℕ) : bitCasesOn (2 * n) H = H false n := bitCasesOn_bit H false n @[simp] -theorem bitCasesOn_bit1 {C : ℕ → Sort u} (H : ∀ b n, C (bit b n)) (n : ℕ) : +theorem bitCasesOn_bit1 {motive : ℕ → Sort u} (H : ∀ b n, motive (bit b n)) (n : ℕ) : bitCasesOn (2 * n + 1) H = H true n := bitCasesOn_bit H true n -theorem bit_cases_on_injective {C : ℕ → Sort u} : - Function.Injective fun H : ∀ b n, C (bit b n) => fun n => bitCasesOn n H := by +theorem bit_cases_on_injective {motive : ℕ → Sort u} : + Function.Injective fun H : ∀ b n, motive (bit b n) => fun n => bitCasesOn n H := by intro H₁ H₂ h ext b n simpa only [bitCasesOn_bit] using congr_fun h (bit b n) @[simp] -theorem bit_cases_on_inj {C : ℕ → Sort u} (H₁ H₂ : ∀ b n, C (bit b n)) : +theorem bit_cases_on_inj {motive : ℕ → Sort u} (H₁ H₂ : ∀ b n, motive (bit b n)) : ((fun n => bitCasesOn n H₁) = fun n => bitCasesOn n H₂) ↔ H₁ = H₂ := bit_cases_on_injective.eq_iff -theorem bit_eq_zero_iff {n : ℕ} {b : Bool} : bit b n = 0 ↔ n = 0 ∧ b = false := by - constructor - · cases b <;> simp [Nat.bit]; omega - · rintro ⟨rfl, rfl⟩ - rfl - lemma bit_le : ∀ (b : Bool) {m n : ℕ}, m ≤ n → bit b m ≤ bit b n | true, _, _, h => by dsimp [bit]; omega | false, _, _, h => by dsimp [bit]; omega @@ -334,56 +258,13 @@ lemma bit_lt_bit (a b) (h : m < n) : bit a m < bit b n := calc bit a m < 2 * n := by cases a <;> dsimp [bit] <;> omega _ ≤ bit b n := by cases b <;> dsimp [bit] <;> omega -/-- -The same as `binaryRec_eq`, -but that one unfortunately requires `f` to be the identity when appending `false` to `0`. -Here, we allow you to explicitly say that that case is not happening, -i.e. supplying `n = 0 → b = true`. -/ -theorem binaryRec_eq' {C : ℕ → Sort*} {z : C 0} {f : ∀ b n, C n → C (bit b n)} (b n) - (h : f false 0 z = z ∨ (n = 0 → b = true)) : - binaryRec z f (bit b n) = f b n (binaryRec z f n) := by - rw [binaryRec] - split_ifs with h' - · rcases bit_eq_zero_iff.mp h' with ⟨rfl, rfl⟩ - rw [binaryRec_zero] - simp only [imp_false, or_false, eq_self_iff_true, not_true, reduceCtorEq] at h - exact h.symm - · dsimp only [] - generalize_proofs e - revert e - rw [bodd_bit, div2_bit] - intros - rfl - -/-- The same as `binaryRec`, but the induction step can assume that if `n=0`, - the bit being appended is `true`-/ -@[elab_as_elim] -def binaryRec' {C : ℕ → Sort*} (z : C 0) (f : ∀ b n, (n = 0 → b = true) → C n → C (bit b n)) : - ∀ n, C n := - binaryRec z fun b n ih => - if h : n = 0 → b = true then f b n h ih - else by - convert z - rw [bit_eq_zero_iff] - simpa using h - -/-- The same as `binaryRec`, but special casing both 0 and 1 as base cases -/ -@[elab_as_elim] -def binaryRecFromOne {C : ℕ → Sort*} (z₀ : C 0) (z₁ : C 1) (f : ∀ b n, n ≠ 0 → C n → C (bit b n)) : - ∀ n, C n := - binaryRec' z₀ fun b n h ih => - if h' : n = 0 then by - rw [h', h h'] - exact z₁ - else f b n h' ih - @[simp] theorem zero_bits : bits 0 = [] := by simp [Nat.bits] @[simp] theorem bits_append_bit (n : ℕ) (b : Bool) (hn : n = 0 → b = true) : (bit b n).bits = b :: n.bits := by - rw [Nat.bits, binaryRec_eq'] + rw [Nat.bits, Nat.bits, binaryRec_eq] simpa @[simp] diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean index 98bc466c54c8d..70965de4413df 100644 --- a/Mathlib/Data/Nat/Bitwise.lean +++ b/Mathlib/Data/Nat/Bitwise.lean @@ -3,13 +3,14 @@ Copyright (c) 2020 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel, Alex Keizer -/ +import Mathlib.Algebra.Group.Units.Basic +import Mathlib.Algebra.NeZero +import Mathlib.Algebra.Ring.Nat import Mathlib.Data.List.GetD import Mathlib.Data.Nat.Bits -import Mathlib.Algebra.Ring.Nat import Mathlib.Order.Basic import Mathlib.Tactic.AdaptationNote import Mathlib.Tactic.Common -import Mathlib.Algebra.NeZero /-! # Bitwise operations on natural numbers @@ -36,7 +37,6 @@ should be connected. bitwise, and, or, xor -/ - open Function namespace Nat @@ -69,10 +69,12 @@ lemma bitwise_of_ne_zero {n m : Nat} (hn : n ≠ 0) (hm : m ≠ 0) : theorem binaryRec_of_ne_zero {C : Nat → Sort*} (z : C 0) (f : ∀ b n, C n → C (bit b n)) {n} (h : n ≠ 0) : binaryRec z f n = bit_decomp n ▸ f (bodd n) (div2 n) (binaryRec z f (div2 n)) := by - rw [Eq.rec_eq_cast] - rw [binaryRec] - dsimp only - rw [dif_neg h, eq_mpr_eq_cast] + cases n using bitCasesOn with + | h b n => + rw [binaryRec_eq _ _ (by right; simpa [bit_eq_zero_iff] using h)] + generalize_proofs h; revert h + rw [bodd_bit, div2_bit] + simp @[simp] lemma bitwise_bit {f : Bool → Bool → Bool} (h : f false false = false := by rfl) (a m b n) : @@ -86,23 +88,13 @@ lemma bitwise_bit {f : Bool → Bool → Bool} (h : f false false = false := by cases a <;> cases b <;> simp [h2, h4] <;> split_ifs <;> simp_all (config := {decide := true}) [two_mul] -lemma bit_mod_two (a : Bool) (x : ℕ) : - bit a x % 2 = if a then 1 else 0 := by - #adaptation_note /-- nightly-2024-03-16: simp was - -- simp (config := { unfoldPartialApp := true }) only [bit, bit1, bit0, ← mul_two, - -- Bool.cond_eq_ite] -/ - simp only [bit, ite_apply, ← mul_two, Bool.cond_eq_ite] - split_ifs <;> simp [Nat.add_mod] - -@[simp] lemma bit_mod_two_eq_zero_iff (a x) : bit a x % 2 = 0 ↔ !a := by - rw [bit_mod_two]; split_ifs <;> simp_all + simp -@[simp] lemma bit_mod_two_eq_one_iff (a x) : bit a x % 2 = 1 ↔ a := by - rw [bit_mod_two]; split_ifs <;> simp_all + simp @[simp] theorem lor_bit : ∀ a m b n, bit a m ||| bit b n = bit (a || b) (m ||| n) := @@ -144,12 +136,10 @@ theorem bit_false : bit false = (2 * ·) := theorem bit_true : bit true = (2 * · + 1) := rfl -@[simp] -theorem bit_eq_zero {n : ℕ} {b : Bool} : n.bit b = 0 ↔ n = 0 ∧ b = false := by - cases b <;> simp [bit, Nat.mul_eq_zero] +@[deprecated (since := "2024-10-19")] alias bit_eq_zero := bit_eq_zero_iff theorem bit_ne_zero_iff {n : ℕ} {b : Bool} : n.bit b ≠ 0 ↔ n = 0 → b = true := by - simpa only [not_and, Bool.not_eq_false] using (@bit_eq_zero n b).not + simp /-- An alternative for `bitwise_bit` which replaces the `f false false = false` assumption with assumptions that neither `bit a m` nor `bit b n` are `0` @@ -363,6 +353,21 @@ theorem lt_xor_cases {a b c : ℕ} (h : a < b ^^^ c) : a ^^^ c < b ∨ a ^^^ b < obtain ha | hb | hc := xor_trichotomy <| Nat.xor_assoc _ _ _ ▸ xor_ne_zero.2 h.ne exacts [(h.asymm ha).elim, Or.inl <| Nat.xor_comm _ _ ▸ hb, Or.inr hc] +@[simp] +theorem xor_mod_two_eq {m n : ℕ} : (m ^^^ n) % 2 = (m + n) % 2 := by + by_cases h : (m + n) % 2 = 0 + · simp only [h, mod_two_eq_zero_iff_testBit_zero, testBit_zero, xor_mod_two_eq_one, decide_not, + Bool.decide_iff_dist, Bool.not_eq_false', beq_iff_eq, decide_eq_decide] + omega + · simp only [mod_two_ne_zero] at h + simp only [h, xor_mod_two_eq_one] + omega + +@[simp] +theorem even_xor {m n : ℕ} : Even (m ^^^ n) ↔ (Even m ↔ Even n) := by + simp only [even_iff, xor_mod_two_eq] + omega + @[simp] theorem bit_lt_two_pow_succ_iff {b x n} : bit b x < 2 ^ (n + 1) ↔ x < 2 ^ n := by cases b <;> simp <;> omega diff --git a/Mathlib/Data/Nat/Cast/Commute.lean b/Mathlib/Data/Nat/Cast/Commute.lean index 4d8306384d75f..a2d80c1d27b64 100644 --- a/Mathlib/Data/Nat/Cast/Commute.lean +++ b/Mathlib/Data/Nat/Cast/Commute.lean @@ -11,7 +11,7 @@ import Mathlib.Algebra.Ring.Commute -/ -variable {α β : Type*} +variable {α : Type*} namespace Nat @@ -71,17 +71,10 @@ variable [Semiring α] {a b : α} variable (a) (m n : ℕ) --- Porting note (#10618): `simp` can prove this using `Commute.refl`, `Commute.natCast_mul_right` --- @[simp] lemma self_natCast_mul : Commute a (n * a) := (Commute.refl a).natCast_mul_right n --- Porting note (#10618): `simp` can prove this using `Commute.refl`, `Commute.natCast_mul_left` --- @[simp] lemma natCast_mul_self : Commute (n * a) a := (Commute.refl a).natCast_mul_left n --- Porting note (#10618): `simp` can prove this using `Commute.refl`, `Commute.natCast_mul_left`, --- `Commute.natCast_mul_right` --- @[simp] lemma self_natCast_mul_natCast_mul : Commute (m * a) (n * a) := (Commute.refl a).natCast_mul_natCast_mul m n diff --git a/Mathlib/Data/Nat/Cast/Defs.lean b/Mathlib/Data/Nat/Cast/Defs.lean index 937ea2f0f088c..eb1e5e1690360 100644 --- a/Mathlib/Data/Nat/Cast/Defs.lean +++ b/Mathlib/Data/Nat/Cast/Defs.lean @@ -199,3 +199,7 @@ theorem three_add_one_eq_four [AddMonoidWithOne R] : 3 + 1 = (4 : R) := by ← Nat.cast_add, ← Nat.cast_add, ← Nat.cast_add] apply congrArg decide + +theorem two_add_two_eq_four [AddMonoidWithOne R] : 2 + 2 = (4 : R) := by + simp [← one_add_one_eq_two, ← Nat.cast_one, ← three_add_one_eq_four, + ← two_add_one_eq_three, add_assoc] diff --git a/Mathlib/Data/Nat/Cast/Order/Basic.lean b/Mathlib/Data/Nat/Cast/Order/Basic.lean index 0bd91bdef4a52..27a78dfb1c92d 100644 --- a/Mathlib/Data/Nat/Cast/Order/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Order/Basic.lean @@ -16,7 +16,7 @@ import Mathlib.Order.Hom.Basic assert_not_exists OrderedCommMonoid -variable {α β : Type*} +variable {α : Type*} namespace Nat @@ -26,7 +26,7 @@ we use a generic collection of instances so that it applies in other settings (e `StarOrderedRing`, or the `selfAdjoint` or `StarOrderedRing.positive` parts thereof). -/ variable [AddMonoidWithOne α] [PartialOrder α] -variable [CovariantClass α α (· + ·) (· ≤ ·)] [ZeroLEOneClass α] +variable [AddLeftMono α] [ZeroLEOneClass α] @[mono] theorem mono_cast : Monotone (Nat.cast : ℕ → α) := @@ -176,7 +176,7 @@ section RingHomClass variable {R S F : Type*} [NonAssocSemiring R] [NonAssocSemiring S] [FunLike F R S] -theorem NeZero.nat_of_injective {n : ℕ} [h : NeZero (n : R)] [RingHomClass F R S] {f : F} +theorem NeZero.nat_of_injective {n : ℕ} [NeZero (n : R)] [RingHomClass F R S] {f : F} (hf : Function.Injective f) : NeZero (n : S) := ⟨fun h ↦ NeZero.natCast_ne n R <| hf <| by simpa only [map_natCast, map_zero f]⟩ diff --git a/Mathlib/Data/Nat/Cast/Order/Field.lean b/Mathlib/Data/Nat/Cast/Order/Field.lean index 8b16df559d51a..2766f3187a1d5 100644 --- a/Mathlib/Data/Nat/Cast/Order/Field.lean +++ b/Mathlib/Data/Nat/Cast/Order/Field.lean @@ -22,7 +22,7 @@ variable {α : Type*} [LinearOrderedSemifield α] lemma cast_inv_le_one : ∀ n : ℕ, (n⁻¹ : α) ≤ 1 | 0 => by simp - | n + 1 => inv_le_one <| by simp [Nat.cast_nonneg] + | n + 1 => inv_le_one_of_one_le₀ <| by simp [Nat.cast_nonneg] /-- Natural division is always less than division in the field. -/ theorem cast_div_le {m n : ℕ} : ((m / n : ℕ) : α) ≤ m / n := by @@ -49,4 +49,12 @@ theorem one_div_lt_one_div {n m : ℕ} (h : n < m) : 1 / ((m : α) + 1) < 1 / (( · exact Nat.cast_add_one_pos _ · simpa +theorem one_div_cast_pos {n : ℕ} (hn : n ≠ 0) : 0 < 1 / (n : α) := + one_div_pos.mpr (cast_pos.mpr (Nat.pos_of_ne_zero hn)) + +theorem one_div_cast_nonneg (n : ℕ) : 0 ≤ 1 / (n : α) := one_div_nonneg.mpr (cast_nonneg' n) + +theorem one_div_cast_ne_zero {n : ℕ} (hn : n ≠ 0) : 1 / (n : α) ≠ 0 := + _root_.ne_of_gt (one_div_cast_pos hn) + end Nat diff --git a/Mathlib/Data/Nat/Cast/Order/Ring.lean b/Mathlib/Data/Nat/Cast/Order/Ring.lean index b03a53d8607f4..97687710d7557 100644 --- a/Mathlib/Data/Nat/Cast/Order/Ring.lean +++ b/Mathlib/Data/Nat/Cast/Order/Ring.lean @@ -12,7 +12,7 @@ import Mathlib.Data.Nat.Cast.Order.Basic -/ -variable {α β : Type*} +variable {α : Type*} namespace Nat @@ -22,7 +22,7 @@ we use a generic collection of instances so that it applies in other settings (e `StarOrderedRing`, or the `selfAdjoint` or `StarOrderedRing.positive` parts thereof). -/ variable [AddMonoidWithOne α] [PartialOrder α] -variable [CovariantClass α α (· + ·) (· ≤ ·)] [ZeroLEOneClass α] +variable [AddLeftMono α] [ZeroLEOneClass α] /-- Specialisation of `Nat.cast_nonneg'`, which seems to be easier for Lean to use. -/ @[simp] @@ -73,7 +73,7 @@ end OrderedSemiring for `ℕ∞` and `ℝ≥0∞`, so we use type-specific lemmas for these types. -/ @[simp, norm_cast] theorem cast_tsub [CanonicallyOrderedCommSemiring α] [Sub α] [OrderedSub α] - [ContravariantClass α α (· + ·) (· ≤ ·)] (m n : ℕ) : ↑(m - n) = (m - n : α) := by + [AddLeftReflectLE α] (m n : ℕ) : ↑(m - n) = (m - n : α) := by rcases le_total m n with h | h · rw [Nat.sub_eq_zero_of_le h, cast_zero, tsub_eq_zero_of_le] exact mono_cast h diff --git a/Mathlib/Data/Nat/Cast/Synonym.lean b/Mathlib/Data/Nat/Cast/Synonym.lean index fad1703cc9e63..075d62d0d87cf 100644 --- a/Mathlib/Data/Nat/Cast/Synonym.lean +++ b/Mathlib/Data/Nat/Cast/Synonym.lean @@ -22,7 +22,7 @@ the natural numbers into an additive monoid with a one (`Nat.cast`). -- where `simp [map_zero]` should suffice. (Similarly for `map_one`.) -- See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/simp.20regression.20with.20MonoidHomClass -variable {α β : Type*} +variable {α : Type*} /-! ### Order dual -/ diff --git a/Mathlib/Data/Nat/Choose/Basic.lean b/Mathlib/Data/Nat/Choose/Basic.lean index e3c7af108183b..d50601dc0a59d 100644 --- a/Mathlib/Data/Nat/Choose/Basic.lean +++ b/Mathlib/Data/Nat/Choose/Basic.lean @@ -77,7 +77,7 @@ theorem choose_eq_choose_pred_add {n k : ℕ} (hn : 0 < n) (hk : 0 < k) : theorem choose_eq_zero_of_lt : ∀ {n k}, n < k → choose n k = 0 | _, 0, hk => absurd hk (Nat.not_lt_zero _) - | 0, k + 1, _ => choose_zero_succ _ + | 0, _ + 1, _ => choose_zero_succ _ | n + 1, k + 1, hk => by have hnk : n < k := lt_of_succ_lt_succ hk have hnk1 : n < k + 1 := lt_of_succ_lt hk @@ -109,7 +109,7 @@ theorem choose_two_right (n : ℕ) : choose n 2 = n * (n - 1) / 2 := by theorem choose_pos : ∀ {n k}, k ≤ n → 0 < choose n k | 0, _, hk => by rw [Nat.eq_zero_of_le_zero hk]; decide | n + 1, 0, _ => by simp - | n + 1, k + 1, hk => Nat.add_pos_left (choose_pos (le_of_succ_le_succ hk)) _ + | _ + 1, _ + 1, hk => Nat.add_pos_left (choose_pos (le_of_succ_le_succ hk)) _ theorem choose_eq_zero_iff {n k : ℕ} : n.choose k = 0 ↔ n < k := ⟨fun h => lt_of_not_ge (mt Nat.choose_pos h.symm.not_lt), Nat.choose_eq_zero_of_lt⟩ @@ -377,7 +377,7 @@ theorem multichoose_eq : ∀ n k : ℕ, multichoose n k = (n + k - 1).choose k | n + 1, k + 1 => by have : n + (k + 1) < (n + 1) + (k + 1) := Nat.add_lt_add_right (Nat.lt_succ_self _) _ have : (n + 1) + k < (n + 1) + (k + 1) := Nat.add_lt_add_left (Nat.lt_succ_self _) _ - erw [multichoose_succ_succ, Nat.add_comm, Nat.succ_add_sub_one, ← Nat.add_assoc, + rw [multichoose_succ_succ, Nat.add_comm, Nat.succ_add_sub_one, ← Nat.add_assoc, Nat.choose_succ_succ] simp [multichoose_eq n (k+1), multichoose_eq (n+1) k] diff --git a/Mathlib/Data/Nat/Choose/Dvd.lean b/Mathlib/Data/Nat/Choose/Dvd.lean index e5cca9d05b77b..0272d236dd30a 100644 --- a/Mathlib/Data/Nat/Choose/Dvd.lean +++ b/Mathlib/Data/Nat/Choose/Dvd.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Patrick Stevens -/ import Mathlib.Data.Nat.Choose.Basic -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Factorial /-! # Divisibility properties of binomial coefficients diff --git a/Mathlib/Data/Nat/Choose/Factorization.lean b/Mathlib/Data/Nat/Choose/Factorization.lean index 258c4eb897817..6bd3a1dac00f3 100644 --- a/Mathlib/Data/Nat/Choose/Factorization.lean +++ b/Mathlib/Data/Nat/Choose/Factorization.lean @@ -39,8 +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)] - simp only [hp.multiplicity_choose hkn (lt_add_one _), PartENat.get_natCast] - exact (Finset.card_filter_le _ _).trans (le_of_eq (Nat.card_Ico _ _)) + rw [← Nat.cast_le (α := ℕ∞), ← multiplicity.Finite.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⟩ /-- A `pow` form of `Nat.factorization_choose_le` -/ theorem pow_factorization_choose_le (hn : 0 < n) : p ^ (choose n k).factorization p ≤ n := @@ -59,8 +61,9 @@ theorem factorization_choose_of_lt_three_mul (hp' : p ≠ 2) (hk : p ≤ k) (hk' · exact factorization_eq_zero_of_non_prime (choose n k) hp cases' lt_or_le n k with hnk hkn · simp [choose_eq_zero_of_lt hnk] - rw [factorization_def _ hp, @padicValNat_def _ ⟨hp⟩ _ (choose_pos hkn)] - simp only [hp.multiplicity_choose hkn (lt_add_one _), PartENat.get_natCast, Finset.card_eq_zero, + rw [factorization_def _ hp, @padicValNat_def _ ⟨hp⟩ _ (choose_pos hkn), + ← emultiplicity_eq_zero_iff_multiplicity_eq_zero] + simp only [hp.emultiplicity_choose hkn (lt_add_one _), cast_eq_zero, Finset.card_eq_zero, Finset.filter_eq_empty_iff, not_le] intro i hi rcases eq_or_lt_of_le (Finset.mem_Ico.mp hi).1 with (rfl | hi) diff --git a/Mathlib/Data/Nat/Choose/Lucas.lean b/Mathlib/Data/Nat/Choose/Lucas.lean index ed55883414890..e3a167ba89664 100644 --- a/Mathlib/Data/Nat/Choose/Lucas.lean +++ b/Mathlib/Data/Nat/Choose/Lucas.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Gareth Ma. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gareth Ma -/ +import Mathlib.Algebra.CharP.Lemmas import Mathlib.Data.ZMod.Basic import Mathlib.RingTheory.Polynomial.Basic @@ -22,7 +23,7 @@ k_i` modulo `p`, where `n_i` and `k_i` are the base-`p` digits of `n` and `k`, r open Finset hiding choose -open Nat BigOperators Polynomial +open Nat Polynomial namespace Choose @@ -33,7 +34,7 @@ modulo `p`. Also see `choose_modEq_choose_mod_mul_choose_div_nat` for the versio theorem choose_modEq_choose_mod_mul_choose_div : choose n k ≡ choose (n % p) (k % p) * choose (n / p) (k / p) [ZMOD p] := by have decompose : ((X : (ZMod p)[X]) + 1) ^ n = (X + 1) ^ (n % p) * (X ^ p + 1) ^ (n / p) := by - simpa using add_pow_eq_add_pow_mod_mul_pow_add_pow_div _ (X : (ZMod p)[X]) 1 + simpa using add_pow_eq_mul_pow_add_pow_div_char (X : (ZMod p)[X]) 1 p _ simp only [← ZMod.intCast_eq_intCast_iff, Int.cast_mul, Int.cast_ofNat, ← coeff_X_add_one_pow _ n k, ← eq_intCast (Int.castRingHom (ZMod p)), ← coeff_map, Polynomial.map_pow, Polynomial.map_add, Polynomial.map_one, map_X, decompose] diff --git a/Mathlib/Data/Nat/Choose/Multinomial.lean b/Mathlib/Data/Nat/Choose/Multinomial.lean index 62485e17c0efa..19e15e9bc63ee 100644 --- a/Mathlib/Data/Nat/Choose/Multinomial.lean +++ b/Mathlib/Data/Nat/Choose/Multinomial.lean @@ -212,7 +212,7 @@ variable [Semiring R] lemma sum_pow_eq_sum_piAntidiag_of_commute (s : Finset α) (f : α → R) (hc : (s : Set α).Pairwise fun i j ↦ Commute (f i) (f j)) (n : ℕ) : (∑ i in s, f i) ^ n = ∑ k in piAntidiag s n, multinomial s k * - s.noncommProd (fun i ↦ f i ^ k i) (hc.mono' fun i j h ↦ h.pow_pow ..) := by + s.noncommProd (fun i ↦ f i ^ k i) (hc.mono' fun _ _ h ↦ h.pow_pow ..) := by classical induction' s using Finset.cons_induction with a s has ih generalizing n · cases n <;> simp diff --git a/Mathlib/Data/Nat/Choose/Sum.lean b/Mathlib/Data/Nat/Choose/Sum.lean index f339da88c6daf..fd5c6f3f73caa 100644 --- a/Mathlib/Data/Nat/Choose/Sum.lean +++ b/Mathlib/Data/Nat/Choose/Sum.lean @@ -7,7 +7,6 @@ import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.NatAntidiagonal import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Data.Nat.Choose.Basic import Mathlib.Tactic.Linarith import Mathlib.Tactic.Ring @@ -124,7 +123,7 @@ theorem four_pow_le_two_mul_add_one_mul_central_binom (n : ℕ) : calc 4 ^ n = (1 + 1) ^ (2 * n) := by norm_num [pow_mul] _ = ∑ m ∈ range (2 * n + 1), (2 * n).choose m := by set_option simprocs false in simp [add_pow] - _ ≤ ∑ m ∈ range (2 * n + 1), (2 * n).choose (2 * n / 2) := by gcongr; apply choose_le_middle + _ ≤ ∑ _ ∈ range (2 * n + 1), (2 * n).choose (2 * n / 2) := by gcongr; apply choose_le_middle _ = (2 * n + 1) * choose (2 * n) n := by simp /-- **Zhu Shijie's identity** aka hockey-stick identity, version with `Icc`. -/ @@ -169,8 +168,8 @@ theorem Int.alternating_sum_range_choose_of_ne {n : ℕ} (h0 : n ≠ 0) : namespace Finset theorem sum_powerset_apply_card {α β : Type*} [AddCommMonoid α] (f : ℕ → α) {x : Finset β} : - ∑ m ∈ x.powerset, f m.card = ∑ m ∈ range (x.card + 1), x.card.choose m • f m := by - trans ∑ m ∈ range (x.card + 1), ∑ j ∈ x.powerset.filter fun z ↦ z.card = m, f j.card + ∑ m ∈ x.powerset, f #m = ∑ m ∈ range (#x + 1), (#x).choose m • f m := by + trans ∑ m ∈ range (#x + 1), ∑ j ∈ x.powerset with #j = m, f #j · refine (sum_fiberwise_of_maps_to ?_ _).symm intro y hy rw [mem_range, Nat.lt_succ_iff] @@ -182,17 +181,17 @@ theorem sum_powerset_apply_card {α β : Type*} [AddCommMonoid α] (f : ℕ → rw [(mem_powersetCard.1 hz).2] theorem sum_powerset_neg_one_pow_card {α : Type*} [DecidableEq α] {x : Finset α} : - (∑ m ∈ x.powerset, (-1 : ℤ) ^ m.card) = if x = ∅ then 1 else 0 := by + (∑ m ∈ x.powerset, (-1 : ℤ) ^ #m) = if x = ∅ then 1 else 0 := by rw [sum_powerset_apply_card] simp only [nsmul_eq_mul', ← card_eq_zero, Int.alternating_sum_range_choose] theorem sum_powerset_neg_one_pow_card_of_nonempty {α : Type*} {x : Finset α} (h0 : x.Nonempty) : - (∑ m ∈ x.powerset, (-1 : ℤ) ^ m.card) = 0 := by + (∑ m ∈ x.powerset, (-1 : ℤ) ^ #m) = 0 := by classical rw [sum_powerset_neg_one_pow_card] exact if_neg (nonempty_iff_ne_empty.mp h0) -variable {M R : Type*} [CommMonoid M] [NonAssocSemiring R] +variable [NonAssocSemiring R] @[to_additive sum_choose_succ_nsmul] theorem prod_pow_choose_succ {M : Type*} [CommMonoid M] (f : ℕ → ℕ → M) (n : ℕ) : diff --git a/Mathlib/Data/Nat/Count.lean b/Mathlib/Data/Nat/Count.lean index cb2e2160ea3aa..4d8294ce6bceb 100644 --- a/Mathlib/Data/Nat/Count.lean +++ b/Mathlib/Data/Nat/Count.lean @@ -36,7 +36,7 @@ theorem count_zero : count p 0 = 0 := by /-- A fintype instance for the set relevant to `Nat.count`. Locally an instance in locale `count` -/ def CountSet.fintype (n : ℕ) : Fintype { i // i < n ∧ p i } := by - apply Fintype.ofFinset ((Finset.range n).filter p) + apply Fintype.ofFinset {x ∈ range n | p x} intro x rw [mem_filter, mem_range] rfl @@ -45,7 +45,7 @@ scoped[Count] attribute [instance] Nat.CountSet.fintype open Count -theorem count_eq_card_filter_range (n : ℕ) : count p n = ((range n).filter p).card := by +theorem count_eq_card_filter_range (n : ℕ) : count p n = #{x ∈ range n | p x} := by rw [count, List.countP_eq_length_filter] rfl @@ -54,6 +54,10 @@ theorem count_eq_card_fintype (n : ℕ) : count p n = Fintype.card { k : ℕ // rw [count_eq_card_filter_range, ← Fintype.card_ofFinset, ← CountSet.fintype] rfl +theorem count_le {n : ℕ} : count p n ≤ n := by + rw [count_eq_card_filter_range] + exact (card_filter_le _ _).trans_eq (card_range _) + theorem count_succ (n : ℕ) : count p (n + 1) = count p n + if p n then 1 else 0 := by split_ifs with h <;> simp [count, List.range_succ, h] @@ -62,7 +66,7 @@ theorem count_monotone : Monotone (count p) := monotone_nat_of_le_succ fun n ↦ by by_cases h : p n <;> simp [count_succ, h] theorem count_add (a b : ℕ) : count p (a + b) = count p a + count (fun k ↦ p (a + k)) b := by - have : Disjoint ((range a).filter p) (((range b).map <| addLeftEmbedding a).filter p) := by + have : Disjoint {x ∈ range a | p x} {x ∈ (range b).map <| addLeftEmbedding a | p x} := by apply disjoint_filter_filter rw [Finset.disjoint_left] simp_rw [mem_map, mem_range, addLeftEmbedding_apply] @@ -114,22 +118,26 @@ theorem count_injective {m n : ℕ} (hm : p m) (hn : p n) (heq : count p m = cou · exact this hn hm heq.symm h.symm (h.lt_or_lt.resolve_left hmn) · simpa [heq] using count_strict_mono hm hmn -theorem count_le_card (hp : (setOf p).Finite) (n : ℕ) : count p n ≤ hp.toFinset.card := by +theorem count_le_card (hp : (setOf p).Finite) (n : ℕ) : count p n ≤ #hp.toFinset := by rw [count_eq_card_filter_range] exact Finset.card_mono fun x hx ↦ hp.mem_toFinset.2 (mem_filter.1 hx).2 -theorem count_lt_card {n : ℕ} (hp : (setOf p).Finite) (hpn : p n) : count p n < hp.toFinset.card := +theorem count_lt_card {n : ℕ} (hp : (setOf p).Finite) (hpn : p n) : count p n < #hp.toFinset := (count_lt_count_succ_iff.2 hpn).trans_le (count_le_card hp _) -theorem count_of_forall {n : ℕ} (hp : ∀ n' < n, p n') : count p n = n := by - rw [count_eq_card_filter_range, filter_true_of_mem, card_range] - · simpa only [Finset.mem_range] +theorem count_iff_forall {n : ℕ} : count p n = n ↔ ∀ n' < n, p n' := by + simpa [count_eq_card_filter_range, card_range, mem_range] using + card_filter_eq_iff (p := p) (s := range n) + +alias ⟨_, count_of_forall⟩ := count_iff_forall @[simp] theorem count_true (n : ℕ) : count (fun _ ↦ True) n = n := count_of_forall fun _ _ ↦ trivial -theorem count_of_forall_not {n : ℕ} (hp : ∀ n' < n, ¬p n') : count p n = 0 := by - rw [count_eq_card_filter_range, filter_false_of_mem, card_empty] - · simpa only [Finset.mem_range] +theorem count_iff_forall_not {n : ℕ} : count p n = 0 ↔ ∀ m < n, ¬p m := by + simpa [count_eq_card_filter_range, mem_range] using + card_filter_eq_zero_iff (p := p) (s := range n) + +alias ⟨_, count_of_forall_not⟩ := count_iff_forall_not @[simp] theorem count_false (n : ℕ) : count (fun _ ↦ False) n = 0 := count_of_forall_not fun _ _ ↦ id diff --git a/Mathlib/Data/Nat/Defs.lean b/Mathlib/Data/Nat/Defs.lean index 2d6cda97e85fd..2d0223819be8a 100644 --- a/Mathlib/Data/Nat/Defs.lean +++ b/Mathlib/Data/Nat/Defs.lean @@ -57,7 +57,7 @@ assert_not_exists Monoid open Function namespace Nat -variable {a b c d m n k : ℕ} {p q : ℕ → Prop} +variable {a b c d m n k : ℕ} {p : ℕ → Prop} -- TODO: Move the `LinearOrder ℕ` instance to `Order.Nat` (#13092). instance instLinearOrder : LinearOrder ℕ where @@ -165,13 +165,8 @@ lemma pred_eq_of_eq_succ (H : m = n.succ) : m.pred = n := by simp [H] @[simp] lemma pred_eq_succ_iff : n - 1 = m + 1 ↔ n = m + 2 := by cases n <;> constructor <;> rintro ⟨⟩ <;> rfl -#adaptation_note -/-- -After nightly-2024-09-06 we can remove both the `_root_` prefixes below. --/ lemma forall_lt_succ : (∀ m < n + 1, p m) ↔ (∀ m < n, p m) ∧ p n := by - simp only [Nat.lt_succ_iff, Nat.le_iff_lt_or_eq, _root_.or_comm, forall_eq_or_imp, - _root_.and_comm] + simp only [Nat.lt_succ_iff, Nat.le_iff_lt_or_eq, or_comm, forall_eq_or_imp, and_comm] lemma exists_lt_succ : (∃ m < n + 1, p m) ↔ (∃ m < n, p m) ∨ p n := by rw [← not_iff_not] @@ -745,7 +740,7 @@ lemma leRec_trans {n m k} {motive : (m : ℕ) → n ≤ m → Sort*} (refl le_su lemma leRec_succ_left {motive : (m : ℕ) → n ≤ m → Sort*} (refl le_succ_of_le) {m} (h1 : n ≤ m) (h2 : n + 1 ≤ m) : -- the `@` is needed for this to elaborate, even though we only provide explicit arguments! - @leRec _ _ (le_succ_of_le le_rfl refl) (fun k h ih => le_succ_of_le (le_of_succ_le h) ih) _ h2 = + @leRec _ _ (le_succ_of_le le_rfl refl) (fun _ h ih => le_succ_of_le (le_of_succ_le h) ih) _ h2 = leRec (motive := motive) refl le_succ_of_le h1 := by rw [leRec_trans _ _ (le_succ n) h2, leRec_succ'] @@ -875,7 +870,7 @@ lemma decreasingInduction_succ {n} {motive : (m : ℕ) → m ≤ n + 1 → Sort* (mn : m ≤ n) (msn : m ≤ n + 1) : (decreasingInduction (motive := motive) of_succ self msn : motive m msn) = decreasingInduction (motive := fun m h => motive m (le_succ_of_le h)) - (fun i hi => of_succ _ _) (of_succ _ _ self) mn := by + (fun _ _ => of_succ _ _) (of_succ _ _ self) mn := by dsimp only [decreasingInduction]; rw [leRec_succ] @[simp] @@ -886,7 +881,7 @@ lemma decreasingInduction_succ' {n} {motive : (m : ℕ) → m ≤ n + 1 → Sort lemma decreasingInduction_trans {motive : (m : ℕ) → m ≤ k → Sort*} (hmn : m ≤ n) (hnk : n ≤ k) (of_succ self) : (decreasingInduction (motive := motive) of_succ self (Nat.le_trans hmn hnk) : motive m _) = - decreasingInduction (fun n ih => of_succ _ _) (decreasingInduction of_succ self hnk) hmn := by + decreasingInduction (fun _ _ => of_succ _ _) (decreasingInduction of_succ self hnk) hmn := by induction hnk with | refl => rw [decreasingInduction_self] | step hnk ih => @@ -919,7 +914,7 @@ def pincerRecursion {P : ℕ → ℕ → Sort*} (Ha0 : ∀ m : ℕ, P m 0) (H0b (H : ∀ x y : ℕ, P x y.succ → P x.succ y → P x.succ y.succ) : ∀ n m : ℕ, P n m | m, 0 => Ha0 m | 0, n => H0b n - | Nat.succ m, Nat.succ n => H _ _ (pincerRecursion Ha0 H0b H _ _) (pincerRecursion Ha0 H0b H _ _) + | Nat.succ _, Nat.succ _ => H _ _ (pincerRecursion Ha0 H0b H _ _) (pincerRecursion Ha0 H0b H _ _) /-- Decreasing induction: if `P (k+1)` implies `P k` for all `m ≤ k < n`, then `P n` implies `P m`. Also works for functions to `Sort*`. @@ -939,7 +934,7 @@ def decreasingInduction' {P : ℕ → Sort*} (h : ∀ k < n, m ≤ k → P (k + @[elab_as_elim] theorem diag_induction (P : ℕ → ℕ → Prop) (ha : ∀ a, P (a + 1) (a + 1)) (hb : ∀ b, P 0 (b + 1)) (hd : ∀ a b, a < b → P (a + 1) b → P a (b + 1) → P (a + 1) (b + 1)) : ∀ a b, a < b → P a b - | 0, b + 1, _ => hb _ + | 0, _ + 1, _ => hb _ | a + 1, b + 1, h => by apply hd _ _ (Nat.add_lt_add_iff_right.1 h) · have this : a + 1 = b ∨ a + 1 < b := by omega @@ -1305,7 +1300,7 @@ lemma div_lt_div_of_lt_of_dvd {a b d : ℕ} (hdb : d ∣ b) (h : a < b) : a / d /-! ### Decidability of predicates -/ -instance decidableLoHi (lo hi : ℕ) (P : ℕ → Prop) [H : DecidablePred P] : +instance decidableLoHi (lo hi : ℕ) (P : ℕ → Prop) [DecidablePred P] : Decidable (∀ x, lo ≤ x → x < hi → P x) := decidable_of_iff (∀ x < hi - lo, P (lo + x)) <| by refine ⟨fun al x hl hh ↦ ?_, diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index 23cd40d657cba..2af99d2651db3 100644 --- a/Mathlib/Data/Nat/Digits.lean +++ b/Mathlib/Data/Nat/Digits.lean @@ -82,7 +82,6 @@ def digits : ℕ → ℕ → List ℕ theorem digits_zero (b : ℕ) : digits b 0 = [] := by rcases b with (_ | ⟨_ | ⟨_⟩⟩) <;> simp [digits, digitsAux0, digitsAux1] --- @[simp] -- Porting note (#10618): simp can prove this theorem digits_zero_zero : digits 0 0 = [] := rfl diff --git a/Mathlib/Data/Nat/EvenOddRec.lean b/Mathlib/Data/Nat/EvenOddRec.lean index a5c452c173847..679a7ff57f097 100644 --- a/Mathlib/Data/Nat/EvenOddRec.lean +++ b/Mathlib/Data/Nat/EvenOddRec.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Stuart Presnell -/ import Mathlib.Algebra.Ring.Parity -import Mathlib.Data.Nat.Bits +import Mathlib.Data.Nat.BinaryRec + /-! # A recursion principle based on even and odd numbers. -/ namespace Nat @@ -29,14 +30,14 @@ theorem evenOddRec_zero {P : ℕ → Sort*} (h0 : P 0) (h_even : ∀ i, P i → theorem evenOddRec_even {P : ℕ → Sort*} (h0 : P 0) (h_even : ∀ i, P i → P (2 * i)) (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) (n : ℕ) : (2 * n).evenOddRec h0 h_even h_odd = h_even n (evenOddRec h0 h_even h_odd n) := by - apply binaryRec_eq' false n + apply binaryRec_eq false n simp [H] @[simp] theorem evenOddRec_odd {P : ℕ → Sort*} (h0 : P 0) (h_even : ∀ i, P i → P (2 * i)) (h_odd : ∀ i, P i → P (2 * i + 1)) (H : h_even 0 h0 = h0) (n : ℕ) : (2 * n + 1).evenOddRec h0 h_even h_odd = h_odd n (evenOddRec h0 h_even h_odd n) := by - apply binaryRec_eq' true n + apply binaryRec_eq true n simp [H] /-- Strong recursion principle on even and odd numbers: if for all `i : ℕ` we can prove `P (2 * i)` diff --git a/Mathlib/Data/Nat/Factorial/SuperFactorial.lean b/Mathlib/Data/Nat/Factorial/SuperFactorial.lean index ce246432d96d0..d4ce6e34adfbb 100644 --- a/Mathlib/Data/Nat/Factorial/SuperFactorial.lean +++ b/Mathlib/Data/Nat/Factorial/SuperFactorial.lean @@ -33,8 +33,6 @@ scoped notation "sf" n:60 => Nat.superFactorial n section SuperFactorial -variable {n : ℕ} - @[simp] theorem superFactorial_zero : sf 0 = 1 := rfl diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 27ddcf0d3a424..f39676359793d 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -187,7 +187,7 @@ theorem exists_factorization_lt_of_lt {a b : ℕ} (ha : a ≠ 0) (hab : a < b) : theorem factorization_div {d n : ℕ} (h : d ∣ n) : (n / d).factorization = n.factorization - d.factorization := by rcases eq_or_ne d 0 with (rfl | hd); · simp [zero_dvd_iff.mp h] - rcases eq_or_ne n 0 with (rfl | hn); · simp + rcases eq_or_ne n 0 with (rfl | hn); · simp [tsub_eq_zero_of_le] apply add_left_injective d.factorization simp only rw [tsub_add_cancel_of_le <| (Nat.factorization_le_iff_dvd hd hn).mpr h, ← @@ -235,8 +235,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₂⟩ := - multiplicity.exists_eq_pow_mul_and_not_dvd - (multiplicity.finite_nat_iff.mpr ⟨hp, Nat.pos_of_ne_zero hn⟩) + (Nat.multiplicity_finite_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 @@ -458,7 +457,7 @@ theorem setOf_pow_dvd_eq_Icc_factorization {n p : ℕ} (pp : p.Prime) (hn : n /-- The set of positive powers of prime `p` that divide `n` is exactly the set of positive natural numbers up to `n.factorization p`. -/ theorem Icc_factorization_eq_pow_dvd (n : ℕ) {p : ℕ} (pp : Prime p) : - Icc 1 (n.factorization p) = (Ico 1 n).filter fun i : ℕ => p ^ i ∣ n := by + Icc 1 (n.factorization p) = {i ∈ Ico 1 n | p ^ i ∣ n} := by rcases eq_or_ne n 0 with (rfl | hn) · simp ext x @@ -467,11 +466,11 @@ theorem Icc_factorization_eq_pow_dvd (n : ℕ) {p : ℕ} (pp : Prime p) : exact fun _ H => lt_of_le_of_lt H (factorization_lt p hn) theorem factorization_eq_card_pow_dvd (n : ℕ) {p : ℕ} (pp : p.Prime) : - n.factorization p = ((Ico 1 n).filter fun i => p ^ i ∣ n).card := by + n.factorization p = #{i ∈ Ico 1 n | p ^ i ∣ n} := by simp [← Icc_factorization_eq_pow_dvd n pp] theorem Ico_filter_pow_dvd_eq {n p b : ℕ} (pp : p.Prime) (hn : n ≠ 0) (hb : n ≤ p ^ b) : - ((Ico 1 n).filter fun i => p ^ i ∣ n) = (Icc 1 b).filter fun i => p ^ i ∣ n := by + {i ∈ Ico 1 n | p ^ i ∣ n} = {i ∈ Icc 1 b | p ^ i ∣ n} := by ext x simp only [Finset.mem_filter, mem_Ico, mem_Icc, and_congr_left_iff, and_congr_right_iff] rintro h1 - @@ -509,7 +508,7 @@ theorem eq_iff_prime_padicValNat_eq (a b : ℕ) (ha : a ≠ 0) (hb : b ≠ 0) : · simp [factorization_eq_zero_of_non_prime, pp] theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n < m) : - (∏ p ∈ Finset.filter Nat.Prime (Finset.range m), p ^ padicValNat p n) = n := by + ∏ p ∈ range m with p.Prime, p ^ padicValNat p n = n := by -- Porting note: was `nth_rw_rhs` conv => rhs @@ -531,14 +530,14 @@ theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n < -- TODO: Port lemmas from `Data/Nat/Multiplicity` to here, re-written in terms of `factorization` /-- Exactly `n / p` naturals in `[1, n]` are multiples of `p`. See `Nat.card_multiples'` for an alternative spelling of the statement. -/ -theorem card_multiples (n p : ℕ) : card ((Finset.range n).filter fun e => p ∣ e + 1) = n / p := by +theorem card_multiples (n p : ℕ) : #{e ∈ range n | p ∣ e + 1} = n / p := by induction' n with n hn · simp simp [Nat.succ_div, add_ite, add_zero, Finset.range_succ, filter_insert, apply_ite card, card_insert_of_not_mem, hn] /-- Exactly `n / p` naturals in `(0, n]` are multiples of `p`. -/ -theorem Ioc_filter_dvd_card_eq_div (n p : ℕ) : ((Ioc 0 n).filter fun x => p ∣ x).card = n / p := by +theorem Ioc_filter_dvd_card_eq_div (n p : ℕ) : #{x ∈ Ioc 0 n | p ∣ x} = n / p := by induction' n with n IH · simp -- TODO: Golf away `h1` after Yaël PRs a lemma asserting this @@ -551,8 +550,7 @@ theorem Ioc_filter_dvd_card_eq_div (n p : ℕ) : ((Ioc 0 n).filter fun x => p /-- There are exactly `⌊N/n⌋` positive multiples of `n` that are `≤ N`. See `Nat.card_multiples` for a "shifted-by-one" version. -/ -lemma card_multiples' (N n : ℕ) : - ((Finset.range N.succ).filter (fun k ↦ k ≠ 0 ∧ n ∣ k)).card = N / n := by +lemma card_multiples' (N n : ℕ) : #{k ∈ range N.succ | k ≠ 0 ∧ n ∣ k} = N / n := by induction N with | zero => simp [Finset.filter_false_of_mem] | succ N ih => diff --git a/Mathlib/Data/Nat/Factorization/Defs.lean b/Mathlib/Data/Nat/Factorization/Defs.lean index fb64f3dd9d2d6..a274e6adeb506 100644 --- a/Mathlib/Data/Nat/Factorization/Defs.lean +++ b/Mathlib/Data/Nat/Factorization/Defs.lean @@ -163,7 +163,7 @@ theorem factorization_le_iff_dvd {d n : ℕ} (hd : d ≠ 0) (hn : n ≠ 0) : /-- For any `p : ℕ` and any function `g : α → ℕ` that's non-zero on `S : Finset α`, the power of `p` in `S.prod g` equals the sum over `x ∈ S` of the powers of `p` in `g x`. -Generalises `factorization_mul`, which is the special case where `S.card = 2` and `g = id`. -/ +Generalises `factorization_mul`, which is the special case where `#S = 2` and `g = id`. -/ theorem factorization_prod {α : Type*} {S : Finset α} {g : α → ℕ} (hS : ∀ x ∈ S, g x ≠ 0) : (S.prod g).factorization = S.sum fun x => (g x).factorization := by classical diff --git a/Mathlib/Data/Nat/Factorization/PrimePow.lean b/Mathlib/Data/Nat/Factorization/PrimePow.lean index 37333d9e42ecf..f36f7a25b7efd 100644 --- a/Mathlib/Data/Nat/Factorization/PrimePow.lean +++ b/Mathlib/Data/Nat/Factorization/PrimePow.lean @@ -5,6 +5,7 @@ Authors: Bhavik Mehta -/ import Mathlib.Algebra.IsPrimePow import Mathlib.Data.Nat.Factorization.Basic +import Mathlib.Data.Nat.Prime.Pow /-! # Prime powers and factorizations diff --git a/Mathlib/Data/Nat/Factors.lean b/Mathlib/Data/Nat/Factors.lean index df65aa467ceea..ff8e8166a2c28 100644 --- a/Mathlib/Data/Nat/Factors.lean +++ b/Mathlib/Data/Nat/Factors.lean @@ -5,9 +5,10 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Algebra.BigOperators.Ring.List import Mathlib.Data.Nat.GCD.Basic -import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.Prime.Basic import Mathlib.Data.List.Prime import Mathlib.Data.List.Sort +import Mathlib.Data.List.Perm.Subperm /-! # Prime numbers diff --git a/Mathlib/Data/Nat/Fib/Basic.lean b/Mathlib/Data/Nat/Fib/Basic.lean index 4d5698a009a29..399cabbe6107f 100644 --- a/Mathlib/Data/Nat/Fib/Basic.lean +++ b/Mathlib/Data/Nat/Fib/Basic.lean @@ -5,8 +5,9 @@ Authors: Kevin Kappelmann, Kyle Miller, Mario Carneiro -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Data.Finset.NatAntidiagonal -import Mathlib.Data.Nat.Bits import Mathlib.Data.Nat.GCD.Basic +import Mathlib.Data.Nat.BinaryRec +import Mathlib.Logic.Function.Iterate import Mathlib.Tactic.Ring import Mathlib.Tactic.Zify @@ -200,12 +201,12 @@ theorem fast_fib_aux_bit_tt (n : ℕ) : · simp theorem fast_fib_aux_eq (n : ℕ) : fastFibAux n = (fib n, fib (n + 1)) := by - apply Nat.binaryRec _ (fun b n' ih => _) n + refine Nat.binaryRec ?_ ?_ n · simp [fastFibAux] · rintro (_|_) n' ih <;> - simp only [fast_fib_aux_bit_ff, fast_fib_aux_bit_tt, congr_arg Prod.fst ih, - congr_arg Prod.snd ih, Prod.mk.inj_iff] <;> - simp [bit, fib_two_mul, fib_two_mul_add_one, fib_two_mul_add_two] + simp only [fast_fib_aux_bit_ff, fast_fib_aux_bit_tt, congr_arg Prod.fst ih, + congr_arg Prod.snd ih, Prod.mk.inj_iff] <;> + simp [bit, fib_two_mul, fib_two_mul_add_one, fib_two_mul_add_two] theorem fast_fib_eq (n : ℕ) : fastFib n = fib n := by rw [fastFib, fast_fib_aux_eq] diff --git a/Mathlib/Data/Nat/Fib/Zeckendorf.lean b/Mathlib/Data/Nat/Fib/Zeckendorf.lean index 81a5fa9e14130..ea2b791ad22c0 100644 --- a/Mathlib/Data/Nat/Fib/Zeckendorf.lean +++ b/Mathlib/Data/Nat/Fib/Zeckendorf.lean @@ -52,7 +52,7 @@ lemma IsZeckendorfRep_nil : IsZeckendorfRep [] := by simp [IsZeckendorfRep] lemma IsZeckendorfRep.sum_fib_lt : ∀ {n l}, IsZeckendorfRep l → (∀ a ∈ (l ++ [0]).head?, a < n) → (l.map fib).sum < fib n - | n, [], _, hn => fib_pos.2 <| hn _ rfl + | _, [], _, hn => fib_pos.2 <| hn _ rfl | n, a :: l, hl, hn => by simp only [IsZeckendorfRep, cons_append, chain'_iff_pairwise, pairwise_cons] at hl have : ∀ b, b ∈ head? (l ++ [0]) → b < a - 1 := @@ -67,7 +67,7 @@ lemma IsZeckendorfRep.sum_fib_lt : ∀ {n l}, IsZeckendorfRep l → (∀ a ∈ ( end List namespace Nat -variable {l : List ℕ} {a m n : ℕ} +variable {m n : ℕ} /-- The greatest index of a Fibonacci number less than or equal to `n`. -/ def greatestFib (n : ℕ) : ℕ := (n + 1).findGreatest (fun k ↦ fib k ≤ n) diff --git a/Mathlib/Data/Nat/Find.lean b/Mathlib/Data/Nat/Find.lean index e37f555306458..a86b825b1b788 100644 --- a/Mathlib/Data/Nat/Find.lean +++ b/Mathlib/Data/Nat/Find.lean @@ -11,7 +11,7 @@ import Batteries.WF # `Nat.find` and `Nat.findGreatest` -/ -variable {a b c d m n k : ℕ} {p q : ℕ → Prop} +variable {m n k : ℕ} {p q : ℕ → Prop} namespace Nat @@ -26,10 +26,10 @@ variable [DecidablePred p] (H : ∃ n, p n) private def wf_lbp : WellFounded (@lbp p) := ⟨let ⟨n, pn⟩ := H - suffices ∀ m k, n ≤ k + m → Acc lbp k from fun a => this _ _ (Nat.le_add_left _ _) + suffices ∀ m k, n ≤ k + m → Acc lbp k from fun _ => this _ _ (Nat.le_add_left _ _) fun m => Nat.recOn m - (fun k kn => + (fun _ kn => ⟨_, fun y r => match y, r with | _, ⟨rfl, a⟩ => absurd pn (a _ kn)⟩) @@ -46,7 +46,7 @@ protected def findX : { n // p n ∧ ∀ m < n, ¬p m } := have : ∀ n ≤ m, ¬p n := fun n h => Or.elim (Nat.lt_or_eq_of_le h) (al n) fun e => by rw [e]; exact pm IH _ ⟨rfl, this⟩ fun n h => this n <| Nat.le_of_succ_le_succ h) - 0 fun n h => absurd h (Nat.not_lt_zero _) + 0 fun _ h => absurd h (Nat.not_lt_zero _) /-- If `p` is a (decidable) predicate on `ℕ` and `hp : ∃ (n : ℕ), p n` is a proof that there exists some natural number satisfying `p`, then `Nat.find hp` is the @@ -106,7 +106,6 @@ lemma find_comp_succ (h₁ : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h0 : ¬ p 0) cases n exacts [h0, @Nat.find_min (fun n ↦ p (n + 1)) _ h₂ _ (succ_lt_succ_iff.1 hn)] --- Porting note (#10618): removing `simp` attribute as `simp` can prove it lemma find_pos (h : ∃ n : ℕ, p n) : 0 < Nat.find h ↔ ¬p 0 := Nat.pos_iff_ne_zero.trans (Nat.find_eq_zero _).not diff --git a/Mathlib/Data/Nat/GCD/Basic.lean b/Mathlib/Data/Nat/GCD/Basic.lean index 8d4d667ffa251..ff926c64b4005 100644 --- a/Mathlib/Data/Nat/GCD/Basic.lean +++ b/Mathlib/Data/Nat/GCD/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2014 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura -/ +import Batteries.Data.Nat.Gcd import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Ring.Nat diff --git a/Mathlib/Data/Nat/GCD/BigOperators.lean b/Mathlib/Data/Nat/GCD/BigOperators.lean index 279f92b1b9c53..ced2ef1aa916b 100644 --- a/Mathlib/Data/Nat/GCD/BigOperators.lean +++ b/Mathlib/Data/Nat/GCD/BigOperators.lean @@ -3,6 +3,7 @@ Copyright (c) 2014 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura -/ +import Batteries.Data.Nat.Gcd import Mathlib.Algebra.BigOperators.Group.Finset /-! # Lemmas about coprimality with big products. diff --git a/Mathlib/Data/Nat/Lattice.lean b/Mathlib/Data/Nat/Lattice.lean index 46be67ef9f99d..cd3c50fdd53c6 100644 --- a/Mathlib/Data/Nat/Lattice.lean +++ b/Mathlib/Data/Nat/Lattice.lean @@ -61,7 +61,7 @@ theorem iInf_of_empty {ι : Sort*} [IsEmpty ι] (f : ι → ℕ) : iInf f = 0 := /-- This combines `Nat.iInf_of_empty` with `ciInf_const`. -/ @[simp] -lemma iInf_const_zero {ι : Sort*} : ⨅ i : ι, 0 = 0 := +lemma iInf_const_zero {ι : Sort*} : ⨅ _ : ι, 0 = 0 := (isEmpty_or_nonempty ι).elim (fun h ↦ by simp) fun h ↦ sInf_eq_zero.2 <| by simp theorem sInf_mem {s : Set ℕ} (h : s.Nonempty) : sInf s ∈ s := by diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index f2cf3df6eca07..84480adb295c4 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -21,6 +21,14 @@ left adjoints of `Nat.pow b`. See `pow_le_iff_le_log` and `le_pow_iff_clog_le`. namespace Nat +#adaptation_note +/-- +After leanprover/lean4#5338 we just unused argument warnings, +but these are used in the decreasing by blocks. +If instead we inline the `have` blocks, the unusedHavesSuffices linter triggers. +-/ +set_option linter.unusedVariables false + /-! ### Floor logarithm -/ diff --git a/Mathlib/Data/Nat/Multiplicity.lean b/Mathlib/Data/Nat/Multiplicity.lean index 2c3b620821b98..88e818d2af8cd 100644 --- a/Mathlib/Data/Nat/Multiplicity.lean +++ b/Mathlib/Data/Nat/Multiplicity.lean @@ -6,7 +6,6 @@ Authors: Chris Hughes import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Order.Ring.Abs -import Mathlib.Data.Nat.Bitwise import Mathlib.Data.Nat.Log import Mathlib.Data.Nat.Prime.Defs import Mathlib.Data.Nat.Digits @@ -56,58 +55,61 @@ namespace Nat /-- The multiplicity of `m` in `n` is the number of positive natural numbers `i` such that `m ^ i` divides `n`. This set is expressed by filtering `Ico 1 b` where `b` is any bound greater than `log m n`. -/ -theorem multiplicity_eq_card_pow_dvd {m n b : ℕ} (hm : m ≠ 1) (hn : 0 < n) (hb : log m n < b) : - multiplicity m n = ↑((Finset.Ico 1 b).filter fun i => m ^ i ∣ n).card := +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⟩ calc - multiplicity m n = ↑(Ico 1 <| (multiplicity m n).get (finite_nat_iff.2 ⟨hm, hn⟩) + 1).card := by - simp - _ = ↑((Finset.Ico 1 b).filter fun i => m ^ i ∣ n).card := + emultiplicity m n = #(Ico 1 <| multiplicity m n + 1) := by + simp [fin.emultiplicity_eq_multiplicity] + _ = #{i ∈ Ico 1 b | m ^ i ∣ n} := congr_arg _ <| congr_arg card <| Finset.ext fun i => by - rw [mem_filter, mem_Ico, mem_Ico, Nat.lt_succ_iff, ← @PartENat.coe_le_coe i, - PartENat.natCast_get, ← pow_dvd_iff_le_multiplicity, and_right_comm] - refine (and_iff_left_of_imp fun h => lt_of_le_of_lt ?_ hb).symm + simp only [mem_Ico, Nat.lt_succ_iff, + fin.pow_dvd_iff_le_multiplicity, mem_filter, + and_assoc, and_congr_right_iff, iff_and_self] + intro hi h + rw [← fin.pow_dvd_iff_le_multiplicity] at h cases' m with m · rw [zero_pow, zero_dvd_iff] at h - exacts [(hn.ne' h.2).elim, one_le_iff_ne_zero.1 h.1] + exacts [(hn.ne' h).elim, one_le_iff_ne_zero.1 hi] + refine LE.le.trans_lt ?_ hb exact le_log_of_pow_le (one_lt_iff_ne_zero_and_ne_one.2 ⟨m.succ_ne_zero, hm⟩) - (le_of_dvd hn h.2) + (le_of_dvd hn h) namespace Prime -theorem multiplicity_one {p : ℕ} (hp : p.Prime) : multiplicity p 1 = 0 := - multiplicity.one_right hp.prime.not_unit +theorem emultiplicity_one {p : ℕ} (hp : p.Prime) : emultiplicity p 1 = 0 := + emultiplicity_of_one_right hp.prime.not_unit -theorem multiplicity_mul {p m n : ℕ} (hp : p.Prime) : - multiplicity p (m * n) = multiplicity p m + multiplicity p n := - multiplicity.mul hp.prime +theorem emultiplicity_mul {p m n : ℕ} (hp : p.Prime) : + emultiplicity p (m * n) = emultiplicity p m + emultiplicity p n := + _root_.emultiplicity_mul hp.prime -theorem multiplicity_pow {p m n : ℕ} (hp : p.Prime) : - multiplicity p (m ^ n) = n • multiplicity p m := - multiplicity.pow hp.prime +theorem emultiplicity_pow {p m n : ℕ} (hp : p.Prime) : + emultiplicity p (m ^ n) = n * emultiplicity p m := + _root_.emultiplicity_pow hp.prime -theorem multiplicity_self {p : ℕ} (hp : p.Prime) : multiplicity p p = 1 := - multiplicity.multiplicity_self hp.prime.not_unit hp.ne_zero +theorem emultiplicity_self {p : ℕ} (hp : p.Prime) : emultiplicity p p = 1 := + (Nat.multiplicity_finite_iff.2 ⟨hp.ne_one, hp.pos⟩).emultiplicity_self -theorem multiplicity_pow_self {p n : ℕ} (hp : p.Prime) : multiplicity p (p ^ n) = n := - multiplicity.multiplicity_pow_self hp.ne_zero hp.prime.not_unit n +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 /-- **Legendre's Theorem** The multiplicity of a prime in `n!` is the sum of the quotients `n / p ^ i`. This sum is expressed over the finset `Ico 1 b` where `b` is any bound greater than `log p n`. -/ -theorem multiplicity_factorial {p : ℕ} (hp : p.Prime) : - ∀ {n b : ℕ}, log p n < b → multiplicity p n ! = (∑ i ∈ Ico 1 b, n / p ^ i : ℕ) - | 0, b, _ => by simp [Ico, hp.multiplicity_one] +theorem emultiplicity_factorial {p : ℕ} (hp : p.Prime) : + ∀ {n b : ℕ}, log p n < b → emultiplicity p n ! = (∑ i ∈ Ico 1 b, n / p ^ i : ℕ) + | 0, b, _ => by simp [Ico, hp.emultiplicity_one] | n + 1, b, hb => calc - multiplicity p (n + 1)! = multiplicity p n ! + multiplicity p (n + 1) := by - rw [factorial_succ, hp.multiplicity_mul, add_comm] - _ = (∑ i ∈ Ico 1 b, n / p ^ i : ℕ) + - ((Finset.Ico 1 b).filter fun i => p ^ i ∣ n + 1).card := by - rw [multiplicity_factorial hp ((log_mono_right <| le_succ _).trans_lt hb), ← - multiplicity_eq_card_pow_dvd hp.ne_one (succ_pos _) hb] + emultiplicity p (n + 1)! = emultiplicity p n ! + emultiplicity p (n + 1) := by + rw [factorial_succ, hp.emultiplicity_mul, add_comm] + _ = (∑ i ∈ Ico 1 b, n / p ^ i : ℕ) + #{i ∈ Ico 1 b | p ^ i ∣ n + 1} := by + rw [emultiplicity_factorial hp ((log_mono_right <| le_succ _).trans_lt hb), ← + emultiplicity_eq_card_pow_dvd hp.ne_one (succ_pos _) hb] _ = (∑ i ∈ Ico 1 b, (n / p ^ i + if p ^ i ∣ n + 1 then 1 else 0) : ℕ) := by rw [sum_add_distrib, sum_boole] simp @@ -117,44 +119,44 @@ theorem multiplicity_factorial {p : ℕ} (hp : p.Prime) : /-- For a prime number `p`, taking `(p - 1)` times the multiplicity of `p` in `n!` equals `n` minus the sum of base `p` digits of `n`. -/ theorem sub_one_mul_multiplicity_factorial {n p : ℕ} (hp : p.Prime) : - (p - 1) * (multiplicity p n !).get (finite_nat_iff.mpr ⟨hp.ne_one, factorial_pos n⟩) = + (p - 1) * multiplicity p n ! = n - (p.digits n).sum := by - simp only [multiplicity_factorial hp <| lt_succ_of_lt <| lt.base (log p n), - ← Finset.sum_Ico_add' _ 0 _ 1, Ico_zero_eq_range, - ← sub_one_mul_sum_log_div_pow_eq_sub_sum_digits] - rfl + simp only [multiplicity_eq_of_emultiplicity_eq_some <| + emultiplicity_factorial hp <| lt_succ_of_lt <| lt.base (log p n), + ← Finset.sum_Ico_add' _ 0 _ 1, Ico_zero_eq_range, ← + sub_one_mul_sum_log_div_pow_eq_sub_sum_digits] /-- The multiplicity of `p` in `(p * (n + 1))!` is one more than the sum of the multiplicities of `p` in `(p * n)!` and `n + 1`. -/ -theorem multiplicity_factorial_mul_succ {n p : ℕ} (hp : p.Prime) : - multiplicity p (p * (n + 1))! = multiplicity p (p * n)! + multiplicity p (n + 1) + 1 := by +theorem emultiplicity_factorial_mul_succ {n p : ℕ} (hp : p.Prime) : + emultiplicity p (p * (n + 1))! = emultiplicity p (p * n)! + emultiplicity p (n + 1) + 1 := by have hp' := hp.prime have h0 : 2 ≤ p := hp.two_le have h1 : 1 ≤ p * n + 1 := Nat.le_add_left _ _ have h2 : p * n + 1 ≤ p * (n + 1) := by linarith have h3 : p * n + 1 ≤ p * (n + 1) + 1 := by omega - have hm : multiplicity p (p * n)! ≠ ⊤ := by - rw [Ne, eq_top_iff_not_finite, Classical.not_not, finite_nat_iff] + have hm : emultiplicity p (p * n)! ≠ ⊤ := by + rw [Ne, emultiplicity_eq_top, Classical.not_not, Nat.multiplicity_finite_iff] exact ⟨hp.ne_one, factorial_pos _⟩ revert hm - have h4 : ∀ m ∈ Ico (p * n + 1) (p * (n + 1)), multiplicity p m = 0 := by + have h4 : ∀ m ∈ Ico (p * n + 1) (p * (n + 1)), emultiplicity p m = 0 := by intro m hm - rw [multiplicity_eq_zero, ← not_dvd_iff_between_consec_multiples _ hp.pos] + rw [emultiplicity_eq_zero, ← not_dvd_iff_between_consec_multiples _ hp.pos] rw [mem_Ico] at hm exact ⟨n, lt_of_succ_le hm.1, hm.2⟩ - simp_rw [← prod_Ico_id_eq_factorial, multiplicity.Finset.prod hp', ← sum_Ico_consecutive _ h1 h3, + simp_rw [← prod_Ico_id_eq_factorial, Finset.emultiplicity_prod hp', ← sum_Ico_consecutive _ h1 h3, add_assoc] intro h - rw [PartENat.add_left_cancel_iff h, sum_Ico_succ_top h2, multiplicity.mul hp', - hp.multiplicity_self, sum_congr rfl h4, sum_const_zero, zero_add, add_comm (1 : PartENat)] + rw [WithTop.add_left_cancel_iff h, sum_Ico_succ_top h2, hp.emultiplicity_mul, + hp.emultiplicity_self, sum_congr rfl h4, sum_const_zero, zero_add, add_comm 1] /-- The multiplicity of `p` in `(p * n)!` is `n` more than that of `n!`. -/ -theorem multiplicity_factorial_mul {n p : ℕ} (hp : p.Prime) : - multiplicity p (p * n)! = multiplicity p n ! + n := by +theorem emultiplicity_factorial_mul {n p : ℕ} (hp : p.Prime) : + emultiplicity p (p * n)! = emultiplicity p n ! + n := by induction' n with n ih · simp - · simp only [succ_eq_add_one, multiplicity.mul, hp, hp.prime, ih, multiplicity_factorial_mul_succ, - ← add_assoc, Nat.cast_one, Nat.cast_add, factorial_succ] + · simp only [hp, emultiplicity_factorial_mul_succ, ih, factorial_succ, emultiplicity_mul, + cast_add, cast_one, ← add_assoc] congr 1 rw [add_comm, add_assoc] @@ -162,17 +164,19 @@ theorem multiplicity_factorial_mul {n p : ℕ} (hp : p.Prime) : This sum is expressed over the set `Ico 1 b` where `b` is any bound greater than `log p n` -/ theorem pow_dvd_factorial_iff {p : ℕ} {n r b : ℕ} (hp : p.Prime) (hbn : log p n < b) : p ^ r ∣ n ! ↔ r ≤ ∑ i ∈ Ico 1 b, n / p ^ i := by - rw [← PartENat.coe_le_coe, ← hp.multiplicity_factorial hbn, ← pow_dvd_iff_le_multiplicity] + rw [← WithTop.coe_le_coe, ENat.some_eq_coe, ← hp.emultiplicity_factorial hbn, + pow_dvd_iff_le_emultiplicity] -theorem multiplicity_factorial_le_div_pred {p : ℕ} (hp : p.Prime) (n : ℕ) : - multiplicity p n ! ≤ (n / (p - 1) : ℕ) := by - rw [hp.multiplicity_factorial (lt_succ_self _), PartENat.coe_le_coe] +theorem emultiplicity_factorial_le_div_pred {p : ℕ} (hp : p.Prime) (n : ℕ) : + emultiplicity p n ! ≤ (n / (p - 1) : ℕ) := by + rw [hp.emultiplicity_factorial (lt_succ_self _)] + apply WithTop.coe_mono exact Nat.geom_sum_Ico_le hp.two_le _ _ theorem multiplicity_choose_aux {p n b k : ℕ} (hp : p.Prime) (hkn : k ≤ n) : ∑ i ∈ Finset.Ico 1 b, n / p ^ i = ((∑ i ∈ Finset.Ico 1 b, k / p ^ i) + ∑ i ∈ Finset.Ico 1 b, (n - k) / p ^ i) + - ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i).card := + #{i ∈ Ico 1 b | p ^ i ≤ k % p ^ i + (n - k) % p ^ i} := calc ∑ i ∈ Finset.Ico 1 b, n / p ^ i = ∑ i ∈ Finset.Ico 1 b, (k + (n - k)) / p ^ i := by simp only [add_tsub_cancel_of_le hkn] @@ -184,79 +188,80 @@ theorem multiplicity_choose_aux {p n b k : ℕ} (hp : p.Prime) (hkn : k ≤ n) : /-- The multiplicity of `p` in `choose (n + k) k` is the number of carries when `k` and `n` are added in base `p`. The set is expressed by filtering `Ico 1 b` where `b` is any bound greater than `log p (n + k)`. -/ -theorem multiplicity_choose' {p n k b : ℕ} (hp : p.Prime) (hnb : log p (n + k) < b) : - multiplicity p (choose (n + k) k) = - ((Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + n % p ^ i).card := by +theorem emultiplicity_choose' {p n k b : ℕ} (hp : p.Prime) (hnb : log p (n + k) < b) : + emultiplicity p (choose (n + k) k) = #{i ∈ Ico 1 b | p ^ i ≤ k % p ^ i + n % p ^ i} := by have h₁ : - multiplicity p (choose (n + k) k) + multiplicity p (k ! * n !) = - ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + n % p ^ i).card + - multiplicity p (k ! * n !) := by - rw [← hp.multiplicity_mul, ← mul_assoc] + emultiplicity p (choose (n + k) k) + emultiplicity p (k ! * n !) = + #{i ∈ Ico 1 b | p ^ i ≤ k % p ^ i + n % p ^ i} + emultiplicity p (k ! * n !) := by + rw [← hp.emultiplicity_mul, ← mul_assoc] have := (add_tsub_cancel_right n k) ▸ choose_mul_factorial_mul_factorial (le_add_left k n) - rw [this, hp.multiplicity_factorial hnb, hp.multiplicity_mul, - hp.multiplicity_factorial ((log_mono_right (le_add_left k n)).trans_lt hnb), - hp.multiplicity_factorial ((log_mono_right (le_add_left n k)).trans_lt + rw [this, hp.emultiplicity_factorial hnb, hp.emultiplicity_mul, + hp.emultiplicity_factorial ((log_mono_right (le_add_left k n)).trans_lt hnb), + hp.emultiplicity_factorial ((log_mono_right (le_add_left n k)).trans_lt (add_comm n k ▸ hnb)), multiplicity_choose_aux hp (le_add_left k n)] simp [add_comm] - refine (PartENat.add_right_cancel_iff ?_).1 h₁ - apply PartENat.ne_top_iff_dom.2 - exact finite_nat_iff.2 ⟨hp.ne_one, mul_pos (factorial_pos k) (factorial_pos n)⟩ + 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)⟩ /-- 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` is any bound greater than `log p n`. -/ -theorem multiplicity_choose {p n k b : ℕ} (hp : p.Prime) (hkn : k ≤ n) (hnb : log p n < b) : - multiplicity p (choose n k) = - ((Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i).card := by +theorem emultiplicity_choose {p n k b : ℕ} (hp : p.Prime) (hkn : k ≤ n) (hnb : log p n < b) : + emultiplicity p (choose n k) = #{i ∈ Ico 1 b | p ^ i ≤ k % p ^ i + (n - k) % p ^ i} := by have := Nat.sub_add_cancel hkn - convert @multiplicity_choose' p (n - k) k b hp _ + convert @emultiplicity_choose' p (n - k) k b hp _ · rw [this] exact this.symm ▸ hnb /-- A lower bound on the multiplicity of `p` in `choose n k`. -/ -theorem multiplicity_le_multiplicity_choose_add {p : ℕ} (hp : p.Prime) : - ∀ n k : ℕ, multiplicity p n ≤ multiplicity p (choose n k) + multiplicity p k +theorem emultiplicity_le_emultiplicity_choose_add {p : ℕ} (hp : p.Prime) : + ∀ n k : ℕ, emultiplicity p n ≤ emultiplicity p (choose n k) + emultiplicity p k | _, 0 => by simp | 0, _ + 1 => by simp | n + 1, k + 1 => by - rw [← hp.multiplicity_mul] - refine multiplicity_le_multiplicity_of_dvd_right ?_ + rw [← hp.emultiplicity_mul] + refine emultiplicity_le_emultiplicity_of_dvd_right ?_ rw [← succ_mul_choose_eq] exact dvd_mul_right _ _ variable {p n k : ℕ} -theorem multiplicity_choose_prime_pow_add_multiplicity (hp : p.Prime) (hkn : k ≤ p ^ n) - (hk0 : k ≠ 0) : multiplicity p (choose (p ^ n) k) + multiplicity p k = n := +theorem emultiplicity_choose_prime_pow_add_emultiplicity (hp : p.Prime) (hkn : k ≤ p ^ n) + (hk0 : k ≠ 0) : emultiplicity p (choose (p ^ n) k) + emultiplicity p k = n := le_antisymm (by have hdisj : - Disjoint ((Ico 1 n.succ).filter fun i => p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i) - ((Ico 1 n.succ).filter fun i => p ^ i ∣ k) := by + Disjoint {i ∈ Ico 1 n.succ | p ^ i ≤ k % p ^ i + (p ^ n - k) % p ^ i} + {i ∈ Ico 1 n.succ | p ^ i ∣ k} := by simp (config := { contextual := true }) [disjoint_right, *, dvd_iff_mod_eq_zero, Nat.mod_lt _ (pow_pos hp.pos _)] - rw [multiplicity_choose hp hkn (lt_succ_self _), - multiplicity_eq_card_pow_dvd (ne_of_gt hp.one_lt) hk0.bot_lt + rw [emultiplicity_choose hp hkn (lt_succ_self _), + emultiplicity_eq_card_pow_dvd (ne_of_gt hp.one_lt) hk0.bot_lt (lt_succ_of_le (log_mono_right hkn)), - ← Nat.cast_add, PartENat.coe_le_coe, log_pow hp.one_lt, ← card_union_of_disjoint hdisj, - filter_union_right] + ← Nat.cast_add] + apply WithTop.coe_mono + rw [log_pow hp.one_lt, ← card_union_of_disjoint hdisj, filter_union_right] have filter_le_Ico := (Ico 1 n.succ).card_filter_le fun x => p ^ x ≤ k % p ^ x + (p ^ n - k) % p ^ x ∨ p ^ x ∣ k rwa [card_Ico 1 n.succ] at filter_le_Ico) - (by rw [← hp.multiplicity_pow_self]; exact multiplicity_le_multiplicity_choose_add hp _ _) + (by rw [← hp.emultiplicity_pow_self]; exact emultiplicity_le_emultiplicity_choose_add hp _ _) -theorem multiplicity_choose_prime_pow {p n k : ℕ} (hp : p.Prime) (hkn : k ≤ p ^ n) (hk0 : k ≠ 0) : - multiplicity p (choose (p ^ n) k) = - ↑(n - (multiplicity p k).get (finite_nat_iff.2 ⟨hp.ne_one, hk0.bot_lt⟩)) := - PartENat.eq_natCast_sub_of_add_eq_natCast <| - multiplicity_choose_prime_pow_add_multiplicity hp hkn hk0 +theorem emultiplicity_choose_prime_pow {p n k : ℕ} (hp : p.Prime) (hkn : k ≤ p ^ n) (hk0 : k ≠ 0) : + 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] + norm_cast + rw [Nat.add_sub_cancel_right] theorem dvd_choose_pow (hp : Prime p) (hk : k ≠ 0) (hkp : k ≠ p ^ n) : p ∣ (p ^ n).choose k := by obtain hkp | hkp := hkp.symm.lt_or_lt · simp [choose_eq_zero_of_lt hkp] - refine multiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt ?_ - have H := hp.multiplicity_choose_prime_pow_add_multiplicity hkp.le hk - rw [h, zero_add, eq_coe_iff] at H + refine emultiplicity_ne_zero.1 fun h => hkp.not_le <| Nat.le_of_dvd hk.bot_lt ?_ + have H := hp.emultiplicity_choose_prime_pow_add_emultiplicity hkp.le hk + rw [h, zero_add, emultiplicity_eq_coe] at H exact H.1 theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 ∧ k ≠ p ^ n := by @@ -265,28 +270,29 @@ theorem dvd_choose_pow_iff (hp : Prime p) : p ∣ (p ^ n).choose k ↔ k ≠ 0 end Prime -theorem multiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), multiplicity 2 n ! < n := by +theorem emultiplicity_two_factorial_lt : ∀ {n : ℕ} (_ : n ≠ 0), emultiplicity 2 n ! < n := by have h2 := prime_two.prime refine binaryRec ?_ ?_ · exact fun h => False.elim <| h rfl · intro b n ih h by_cases hn : n = 0 · subst hn - simp only [ne_eq, bit_eq_zero, true_and, Bool.not_eq_false] at h - simp only [h, bit_true, factorial, mul_one, Nat.isUnit_iff, cast_one] - rw [Prime.multiplicity_one] - · simp [zero_lt_one] + simp only [ne_eq, bit_eq_zero_iff, true_and, Bool.not_eq_false] at h + simp only [h, factorial, mul_one, Nat.isUnit_iff, cast_one] + rw [Prime.emultiplicity_one] + · exact zero_lt_one · decide - have : multiplicity 2 (2 * n)! < (2 * n : ℕ) := by - rw [prime_two.multiplicity_factorial_mul] - refine (PartENat.add_lt_add_right (ih hn) (PartENat.natCast_ne_top _)).trans_le ?_ + have : emultiplicity 2 (2 * n)! < (2 * n : ℕ) := by + rw [prime_two.emultiplicity_factorial_mul] rw [two_mul] - norm_cast + push_cast + apply WithTop.add_lt_add_right _ (ih hn) + exact Ne.symm nofun cases b · simpa - · suffices multiplicity 2 (2 * n + 1) + multiplicity 2 (2 * n)! < ↑(2 * n) + 1 by - simpa [multiplicity.mul, h2, prime_two, bit, factorial] - rw [multiplicity_eq_zero.2 (two_not_dvd_two_mul_add_one n), zero_add] + · suffices emultiplicity 2 (2 * n + 1) + emultiplicity 2 (2 * n)! < ↑(2 * n) + 1 by + simpa [emultiplicity_mul, h2, prime_two, bit, factorial] + rw [emultiplicity_eq_zero.2 (two_not_dvd_two_mul_add_one n), zero_add] refine this.trans ?_ exact mod_cast lt_succ_self _ diff --git a/Mathlib/Data/Nat/Notation.lean b/Mathlib/Data/Nat/Notation.lean index 729e9b67b0f52..c23a8c794808b 100644 --- a/Mathlib/Data/Nat/Notation.lean +++ b/Mathlib/Data/Nat/Notation.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura -/ +import Mathlib.Init + /-! # Notation `ℕ` for the natural numbers. -/ diff --git a/Mathlib/Data/Nat/Nth.lean b/Mathlib/Data/Nat/Nth.lean index 13b3543cb9adc..fb3e78daa3035 100644 --- a/Mathlib/Data/Nat/Nth.lean +++ b/Mathlib/Data/Nat/Nth.lean @@ -58,40 +58,40 @@ variable {p} -/ -theorem nth_of_card_le (hf : (setOf p).Finite) {n : ℕ} (hn : hf.toFinset.card ≤ n) : +theorem nth_of_card_le (hf : (setOf p).Finite) {n : ℕ} (hn : #hf.toFinset ≤ n) : nth p n = 0 := by rw [nth, dif_pos hf, List.getD_eq_default]; rwa [Finset.length_sort] theorem nth_eq_getD_sort (h : (setOf p).Finite) (n : ℕ) : nth p n = (h.toFinset.sort (· ≤ ·)).getD n 0 := dif_pos h -theorem nth_eq_orderEmbOfFin (hf : (setOf p).Finite) {n : ℕ} (hn : n < hf.toFinset.card) : +theorem nth_eq_orderEmbOfFin (hf : (setOf p).Finite) {n : ℕ} (hn : n < #hf.toFinset) : nth p n = hf.toFinset.orderEmbOfFin rfl ⟨n, hn⟩ := by rw [nth_eq_getD_sort hf, Finset.orderEmbOfFin_apply, List.getD_eq_getElem, Fin.getElem_fin] theorem nth_strictMonoOn (hf : (setOf p).Finite) : - StrictMonoOn (nth p) (Set.Iio hf.toFinset.card) := by + StrictMonoOn (nth p) (Set.Iio #hf.toFinset) := by rintro m (hm : m < _) n (hn : n < _) h simp only [nth_eq_orderEmbOfFin, *] exact OrderEmbedding.strictMono _ h theorem nth_lt_nth_of_lt_card (hf : (setOf p).Finite) {m n : ℕ} (h : m < n) - (hn : n < hf.toFinset.card) : nth p m < nth p n := + (hn : n < #hf.toFinset) : nth p m < nth p n := nth_strictMonoOn hf (h.trans hn) hn h theorem nth_le_nth_of_lt_card (hf : (setOf p).Finite) {m n : ℕ} (h : m ≤ n) - (hn : n < hf.toFinset.card) : nth p m ≤ nth p n := + (hn : n < #hf.toFinset) : nth p m ≤ nth p n := (nth_strictMonoOn hf).monotoneOn (h.trans_lt hn) hn h theorem lt_of_nth_lt_nth_of_lt_card (hf : (setOf p).Finite) {m n : ℕ} (h : nth p m < nth p n) - (hm : m < hf.toFinset.card) : m < n := + (hm : m < #hf.toFinset) : m < n := not_le.1 fun hle => h.not_le <| nth_le_nth_of_lt_card hf hle hm theorem le_of_nth_le_nth_of_lt_card (hf : (setOf p).Finite) {m n : ℕ} (h : nth p m ≤ nth p n) - (hm : m < hf.toFinset.card) : m ≤ n := + (hm : m < #hf.toFinset) : m ≤ n := not_lt.1 fun hlt => h.not_lt <| nth_lt_nth_of_lt_card hf hlt hm -theorem nth_injOn (hf : (setOf p).Finite) : (Set.Iio hf.toFinset.card).InjOn (nth p) := +theorem nth_injOn (hf : (setOf p).Finite) : (Set.Iio #hf.toFinset).InjOn (nth p) := (nth_strictMonoOn hf).injOn theorem range_nth_of_finite (hf : (setOf p).Finite) : Set.range (nth p) = insert 0 (setOf p) := by @@ -99,20 +99,20 @@ theorem range_nth_of_finite (hf : (setOf p).Finite) : Set.range (nth p) = insert Set.Finite.mem_toFinset] using Set.range_list_getD (hf.toFinset.sort (· ≤ ·)) 0 @[simp] -theorem image_nth_Iio_card (hf : (setOf p).Finite) : nth p '' Set.Iio hf.toFinset.card = setOf p := +theorem image_nth_Iio_card (hf : (setOf p).Finite) : nth p '' Set.Iio #hf.toFinset = setOf p := calc - nth p '' Set.Iio hf.toFinset.card = Set.range (hf.toFinset.orderEmbOfFin rfl) := by + nth p '' Set.Iio #hf.toFinset = Set.range (hf.toFinset.orderEmbOfFin rfl) := by ext x simp only [Set.mem_image, Set.mem_range, Fin.exists_iff, ← nth_eq_orderEmbOfFin hf, Set.mem_Iio, exists_prop] _ = setOf p := by rw [range_orderEmbOfFin, Set.Finite.coe_toFinset] -theorem nth_mem_of_lt_card {n : ℕ} (hf : (setOf p).Finite) (hlt : n < hf.toFinset.card) : +theorem nth_mem_of_lt_card {n : ℕ} (hf : (setOf p).Finite) (hlt : n < #hf.toFinset) : p (nth p n) := (image_nth_Iio_card hf).subset <| Set.mem_image_of_mem _ hlt theorem exists_lt_card_finite_nth_eq (hf : (setOf p).Finite) {x} (h : p x) : - ∃ n, n < hf.toFinset.card ∧ nth p n = x := by + ∃ n, n < #hf.toFinset ∧ nth p n = x := by rwa [← @Set.mem_setOf_eq _ _ p, ← image_nth_Iio_card hf] at h /-! @@ -158,7 +158,7 @@ theorem nth_mem_of_infinite (hf : (setOf p).Infinite) (n : ℕ) : p (nth p n) := -/ theorem exists_lt_card_nth_eq {x} (h : p x) : - ∃ n, (∀ hf : (setOf p).Finite, n < hf.toFinset.card) ∧ nth p n = x := by + ∃ n, (∀ hf : (setOf p).Finite, n < #hf.toFinset) ∧ nth p n = x := by refine (setOf p).finite_or_infinite.elim (fun hf => ?_) fun hf => ?_ · rcases exists_lt_card_finite_nth_eq hf h with ⟨n, hn, hx⟩ exact ⟨n, fun _ => hn, hx⟩ @@ -174,32 +174,32 @@ theorem range_nth_subset : Set.range (nth p) ⊆ insert 0 (setOf p) := (setOf p).finite_or_infinite.elim (fun h => (range_nth_of_finite h).subset) fun h => (range_nth_of_infinite h).trans_subset (Set.subset_insert _ _) -theorem nth_mem (n : ℕ) (h : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : p (nth p n) := +theorem nth_mem (n : ℕ) (h : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : p (nth p n) := (setOf p).finite_or_infinite.elim (fun hf => nth_mem_of_lt_card hf (h hf)) fun h => nth_mem_of_infinite h n -theorem nth_lt_nth' {m n : ℕ} (hlt : m < n) (h : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : +theorem nth_lt_nth' {m n : ℕ} (hlt : m < n) (h : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : nth p m < nth p n := (setOf p).finite_or_infinite.elim (fun hf => nth_lt_nth_of_lt_card hf hlt (h _)) fun hf => (nth_lt_nth hf).2 hlt -theorem nth_le_nth' {m n : ℕ} (hle : m ≤ n) (h : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : +theorem nth_le_nth' {m n : ℕ} (hle : m ≤ n) (h : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : nth p m ≤ nth p n := (setOf p).finite_or_infinite.elim (fun hf => nth_le_nth_of_lt_card hf hle (h _)) fun hf => (nth_le_nth hf).2 hle -theorem le_nth {n : ℕ} (h : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : n ≤ nth p n := +theorem le_nth {n : ℕ} (h : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : n ≤ nth p n := (setOf p).finite_or_infinite.elim (fun hf => ((nth_strictMonoOn hf).mono <| Set.Iic_subset_Iio.2 (h _)).Iic_id_le _ le_rfl) fun hf => (nth_strictMono hf).id_le _ -theorem isLeast_nth {n} (h : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : +theorem isLeast_nth {n} (h : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : IsLeast {i | p i ∧ ∀ k < n, nth p k < i} (nth p n) := ⟨⟨nth_mem n h, fun _k hk => nth_lt_nth' hk h⟩, fun _x hx => let ⟨k, hk, hkx⟩ := exists_lt_card_nth_eq hx.1 (lt_or_le k n).elim (fun hlt => absurd hkx (hx.2 _ hlt).ne) fun hle => hkx ▸ nth_le_nth' hle hk⟩ -theorem isLeast_nth_of_lt_card {n : ℕ} (hf : (setOf p).Finite) (hn : n < hf.toFinset.card) : +theorem isLeast_nth_of_lt_card {n : ℕ} (hf : (setOf p).Finite) (hn : n < #hf.toFinset) : IsLeast {i | p i ∧ ∀ k < n, nth p k < i} (nth p n) := isLeast_nth fun _ => hn @@ -210,9 +210,9 @@ theorem isLeast_nth_of_infinite (hf : (setOf p).Infinite) (n : ℕ) : /-- An alternative recursive definition of `Nat.nth`: `Nat.nth s n` is the infimum of `x ∈ s` such that `Nat.nth s k < x` for all `k < n`, if this set is nonempty. We do not assume that the set is nonempty because we use the same "garbage value" `0` both for `sInf` on `ℕ` and for `Nat.nth s n` -for `n ≥ card s`. -/ +for `n ≥ #s`. -/ theorem nth_eq_sInf (p : ℕ → Prop) (n : ℕ) : nth p n = sInf {x | p x ∧ ∀ k < n, nth p k < x} := by - by_cases hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.card + by_cases hn : ∀ hf : (setOf p).Finite, n < #hf.toFinset · exact (isLeast_nth hn).csInf_eq.symm · push_neg at hn rcases hn with ⟨hf, hn⟩ @@ -230,7 +230,7 @@ theorem nth_zero_of_exists [DecidablePred p] (h : ∃ n, p n) : nth p 0 = Nat.fi rw [nth_zero]; convert Nat.sInf_def h theorem nth_eq_zero {n} : - nth p n = 0 ↔ p 0 ∧ n = 0 ∨ ∃ hf : (setOf p).Finite, hf.toFinset.card ≤ n := by + nth p n = 0 ↔ p 0 ∧ n = 0 ∨ ∃ hf : (setOf p).Finite, #hf.toFinset ≤ n := by refine ⟨fun h => ?_, ?_⟩ · simp only [or_iff_not_imp_right, not_exists, not_le] exact fun hn => ⟨h ▸ nth_mem _ hn, nonpos_iff_eq_zero.1 <| h ▸ le_nth hn⟩ @@ -244,7 +244,7 @@ theorem nth_eq_zero_mono (h₀ : ¬p 0) {a b : ℕ} (hab : a ≤ b) (ha : nth p theorem le_nth_of_lt_nth_succ {k a : ℕ} (h : a < nth p (k + 1)) (ha : p a) : a ≤ nth p k := by cases' (setOf p).finite_or_infinite with hf hf · rcases exists_lt_card_finite_nth_eq hf ha with ⟨n, hn, rfl⟩ - cases' lt_or_le (k + 1) hf.toFinset.card with hk hk + cases' lt_or_le (k + 1) #hf.toFinset with hk hk · rwa [(nth_strictMonoOn hf).lt_iff_lt hn hk, Nat.lt_succ_iff, ← (nth_strictMonoOn hf).le_iff_le hn (k.lt_succ_self.trans hk)] at h · rw [nth_of_card_le _ hk] at h @@ -262,7 +262,7 @@ theorem count_nth_zero : count p (nth p 0) = 0 := by exact fun n h₁ h₂ => (mem_range.1 h₁).not_le (Nat.sInf_le h₂) theorem filter_range_nth_subset_insert (k : ℕ) : - (range (nth p (k + 1))).filter p ⊆ insert (nth p k) ((range (nth p k)).filter p) := by + {n ∈ range (nth p (k + 1)) | p n} ⊆ insert (nth p k) {n ∈ range (nth p k) | p n} := by intro a ha simp only [mem_insert, mem_filter, mem_range] at ha ⊢ exact (le_nth_of_lt_nth_succ ha.1 ha.2).eq_or_lt.imp_right fun h => ⟨h, ha.2⟩ @@ -270,8 +270,8 @@ theorem filter_range_nth_subset_insert (k : ℕ) : variable {p} theorem filter_range_nth_eq_insert {k : ℕ} - (hlt : ∀ hf : (setOf p).Finite, k + 1 < hf.toFinset.card) : - (range (nth p (k + 1))).filter p = insert (nth p k) ((range (nth p k)).filter p) := by + (hlt : ∀ hf : (setOf p).Finite, k + 1 < #hf.toFinset) : + {n ∈ range (nth p (k + 1)) | p n} = insert (nth p k) {n ∈ range (nth p k) | p n} := by refine (filter_range_nth_subset_insert p k).antisymm fun a ha => ?_ simp only [mem_insert, mem_filter, mem_range] at ha ⊢ have : nth p k < nth p (k + 1) := nth_lt_nth' k.lt_succ_self hlt @@ -280,15 +280,15 @@ theorem filter_range_nth_eq_insert {k : ℕ} · exact ⟨hlt.trans this, hpa⟩ theorem filter_range_nth_eq_insert_of_finite (hf : (setOf p).Finite) {k : ℕ} - (hlt : k + 1 < hf.toFinset.card) : - (range (nth p (k + 1))).filter p = insert (nth p k) ((range (nth p k)).filter p) := + (hlt : k + 1 < #hf.toFinset) : + {n ∈ range (nth p (k + 1)) | p n} = insert (nth p k) {n ∈ range (nth p k) | p n} := filter_range_nth_eq_insert fun _ => hlt theorem filter_range_nth_eq_insert_of_infinite (hp : (setOf p).Infinite) (k : ℕ) : - (range (nth p (k + 1))).filter p = insert (nth p k) ((range (nth p k)).filter p) := + {n ∈ range (nth p (k + 1)) | p n} = insert (nth p k) {n ∈ range (nth p k) | p n} := filter_range_nth_eq_insert fun hf => absurd hf hp -theorem count_nth {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : +theorem count_nth {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : count p (nth p n) = n := by induction' n with k ihk · exact count_nth_zero _ @@ -296,7 +296,7 @@ theorem count_nth {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.car count_eq_card_filter_range, ihk fun hf => lt_of_succ_lt (hn hf)] simp -theorem count_nth_of_lt_card_finite {n : ℕ} (hp : (setOf p).Finite) (hlt : n < hp.toFinset.card) : +theorem count_nth_of_lt_card_finite {n : ℕ} (hp : (setOf p).Finite) (hlt : n < #hp.toFinset) : count p (nth p n) = n := count_nth fun _ => hlt @@ -307,12 +307,12 @@ theorem surjective_count_of_infinite_setOf (h : {n | p n}.Infinite) : Function.Surjective (Nat.count p) := fun n => ⟨nth p n, count_nth_of_infinite h n⟩ -theorem count_nth_succ {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : +theorem count_nth_succ {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < #hf.toFinset) : count p (nth p n + 1) = n + 1 := by rw [count_succ, count_nth hn, if_pos (nth_mem _ hn)] @[simp] theorem nth_count {n : ℕ} (hpn : p n) : nth p (count p n) = n := - have : ∀ hf : (setOf p).Finite, count p n < hf.toFinset.card := fun hf => count_lt_card hf hpn + have : ∀ hf : (setOf p).Finite, count p n < #hf.toFinset := fun hf => count_lt_card hf hpn count_injective (nth_mem _ this) hpn (count_nth this) theorem nth_lt_of_lt_count {n k : ℕ} (h : k < count p n) : nth p k < n := by @@ -323,6 +323,9 @@ theorem nth_lt_of_lt_count {n k : ℕ} (h : k < count p n) : nth p k < n := by theorem le_nth_of_count_le {n k : ℕ} (h : n ≤ nth p k) : count p n ≤ k := not_lt.1 fun hlt => h.not_lt <| nth_lt_of_lt_count hlt +protected theorem count_eq_zero (h : ∃ n, p n) {n : ℕ} : count p n = 0 ↔ n ≤ nth p 0 := by + rw [nth_zero_of_exists h, le_find_iff h, Nat.count_iff_forall_not] + variable (p) theorem nth_count_eq_sInf (n : ℕ) : nth p (count p n) = sInf {i : ℕ | p i ∧ n ≤ i} := by diff --git a/Mathlib/Data/Nat/Order/Lemmas.lean b/Mathlib/Data/Nat/Order/Lemmas.lean index 72474ceef7eb5..415d72c229f27 100644 --- a/Mathlib/Data/Nat/Order/Lemmas.lean +++ b/Mathlib/Data/Nat/Order/Lemmas.lean @@ -15,10 +15,6 @@ They were separated for now to minimize the porting requirements for tactics during the transition to mathlib4. Please feel free to reorganize these two files. -/ -universe u v - -variable {a b m n k : ℕ} - namespace Nat /-! ### Sets -/ diff --git a/Mathlib/Data/Nat/Pairing.lean b/Mathlib/Data/Nat/Pairing.lean index 6265833d77e17..bda4acd194b8d 100644 --- a/Mathlib/Data/Nat/Pairing.lean +++ b/Mathlib/Data/Nat/Pairing.lean @@ -93,7 +93,7 @@ theorem unpair_zero : unpair 0 = 0 := by theorem unpair_left_le : ∀ n : ℕ, (unpair n).1 ≤ n | 0 => by simp - | n + 1 => le_of_lt (unpair_lt (Nat.succ_pos _)) + | _ + 1 => le_of_lt (unpair_lt (Nat.succ_pos _)) theorem left_le_pair (a b : ℕ) : a ≤ pair a b := by simpa using unpair_left_le (pair a b) diff --git a/Mathlib/Data/Nat/PartENat.lean b/Mathlib/Data/Nat/PartENat.lean index cc13db102cac5..83ed1864a30f6 100644 --- a/Mathlib/Data/Nat/PartENat.lean +++ b/Mathlib/Data/Nat/PartENat.lean @@ -87,10 +87,10 @@ theorem dom_some (x : ℕ) : (some x).Dom := instance addCommMonoid : AddCommMonoid PartENat where add := (· + ·) zero := 0 - add_comm x y := Part.ext' and_comm fun _ _ => add_comm _ _ - zero_add x := Part.ext' (iff_of_eq (true_and _)) fun _ _ => zero_add _ - add_zero x := Part.ext' (iff_of_eq (and_true _)) fun _ _ => add_zero _ - add_assoc x y z := Part.ext' and_assoc fun _ _ => add_assoc _ _ _ + add_comm _ _ := Part.ext' and_comm fun _ _ => add_comm _ _ + zero_add _ := Part.ext' (iff_of_eq (true_and _)) fun _ _ => zero_add _ + add_zero _ := Part.ext' (iff_of_eq (and_true _)) fun _ _ => add_zero _ + add_assoc _ _ _ := Part.ext' and_assoc fun _ _ => add_assoc _ _ _ nsmul := nsmulRec instance : AddCommMonoidWithOne PartENat := @@ -415,8 +415,8 @@ noncomputable instance : CanonicallyOrderedAddCommMonoid PartENat := { PartENat.semilatticeSup, PartENat.orderBot, PartENat.orderedAddCommMonoid with le_self_add := fun a b => - PartENat.casesOn b (le_top.trans_eq (add_top _).symm) fun b => - PartENat.casesOn a (top_add _).ge fun a => + PartENat.casesOn b (le_top.trans_eq (add_top _).symm) fun _ => + PartENat.casesOn a (top_add _).ge fun _ => (coe_le_coe.2 le_self_add).trans_eq (Nat.cast_add _ _) exists_add_of_le := fun {a b} => PartENat.casesOn b (fun _ => ⟨⊤, (add_top _).symm⟩) fun b => diff --git a/Mathlib/Data/Nat/Prime/Basic.lean b/Mathlib/Data/Nat/Prime/Basic.lean index 06a9ca4221721..24bdc1be8b0c1 100644 --- a/Mathlib/Data/Nat/Prime/Basic.lean +++ b/Mathlib/Data/Nat/Prime/Basic.lean @@ -3,22 +3,18 @@ Copyright (c) 2015 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ -import Mathlib.Algebra.Ring.Int -import Mathlib.Order.Bounds.Basic -import Mathlib.Data.Nat.Factorial.Basic +import Mathlib.Algebra.Associated.Basic +import Mathlib.Algebra.Ring.Parity import Mathlib.Data.Nat.Prime.Defs -import Mathlib.Algebra.Order.Monoid.Unbundled.Pow /-! -## Notable Theorems +# Prime numbers -- `Nat.exists_infinite_primes`: Euclid's theorem that there exist infinitely many prime numbers. - This also appears as `Nat.not_bddAbove_setOf_prime` and `Nat.infinite_setOf_prime` (the latter - in `Data.Nat.PrimeFin`). +This file develops the theory of prime numbers: natural numbers `p ≥ 2` whose only divisors are +`p` and `1`. -/ - open Bool Subtype open Nat @@ -26,6 +22,29 @@ open Nat namespace Nat variable {n : ℕ} +theorem prime_mul_iff {a b : ℕ} : Nat.Prime (a * b) ↔ a.Prime ∧ b = 1 ∨ b.Prime ∧ a = 1 := by + simp only [irreducible_mul_iff, ← irreducible_iff_nat_prime, Nat.isUnit_iff] + +theorem not_prime_mul {a b : ℕ} (a1 : a ≠ 1) (b1 : b ≠ 1) : ¬Prime (a * b) := by + simp [prime_mul_iff, _root_.not_or, *] + +theorem not_prime_mul' {a b n : ℕ} (h : a * b = n) (h₁ : a ≠ 1) (h₂ : b ≠ 1) : ¬Prime n := + h ▸ not_prime_mul h₁ h₂ + +theorem Prime.dvd_iff_eq {p a : ℕ} (hp : p.Prime) (a1 : a ≠ 1) : a ∣ p ↔ p = a := by + refine ⟨?_, by rintro rfl; rfl⟩ + rintro ⟨j, rfl⟩ + rcases prime_mul_iff.mp hp with (⟨_, rfl⟩ | ⟨_, rfl⟩) + · exact mul_one _ + · exact (a1 rfl).elim + +theorem Prime.eq_two_or_odd {p : ℕ} (hp : Prime p) : p = 2 ∨ p % 2 = 1 := + p.mod_two_eq_zero_or_one.imp_left fun h => + ((hp.eq_one_or_self_of_dvd 2 (dvd_of_mod_eq_zero h)).resolve_left (by decide)).symm + +theorem Prime.eq_two_or_odd' {p : ℕ} (hp : Prime p) : p = 2 ∨ Odd p := + Or.imp_right (fun h => ⟨p / 2, (div_add_mod p 2).symm.trans (congr_arg _ h)⟩) hp.eq_two_or_odd + section theorem Prime.five_le_of_ne_two_of_ne_three {p : ℕ} (hp : p.Prime) (h_two : p ≠ 2) @@ -77,26 +96,6 @@ theorem dvd_of_forall_prime_mul_dvd {a b : ℕ} obtain ⟨p, hp⟩ := exists_prime_and_dvd ha exact _root_.trans (dvd_mul_left a p) (hdvd p hp.1 hp.2) -/-- Euclid's theorem on the **infinitude of primes**. -Here given in the form: for every `n`, there exists a prime number `p ≥ n`. -/ -theorem exists_infinite_primes (n : ℕ) : ∃ p, n ≤ p ∧ Prime p := - let p := minFac (n ! + 1) - have f1 : n ! + 1 ≠ 1 := ne_of_gt <| succ_lt_succ <| factorial_pos _ - have pp : Prime p := minFac_prime f1 - have np : n ≤ p := - le_of_not_ge fun h => - have h₁ : p ∣ n ! := dvd_factorial (minFac_pos _) h - have h₂ : p ∣ 1 := (Nat.dvd_add_iff_right h₁).2 (minFac_dvd _) - pp.not_dvd_one h₂ - ⟨p, np, pp⟩ - -/-- A version of `Nat.exists_infinite_primes` using the `BddAbove` predicate. -/ -theorem not_bddAbove_setOf_prime : ¬BddAbove { p | Prime p } := by - rw [not_bddAbove_iff] - intro n - obtain ⟨p, hi, hp⟩ := exists_infinite_primes n.succ - exact ⟨p, hp, hi⟩ - theorem Prime.even_iff {p : ℕ} (hp : Prime p) : Even p ↔ p = 2 := by rw [even_iff_two_dvd, prime_dvd_prime_iff_eq prime_two hp, eq_comm] @@ -136,10 +135,8 @@ theorem Prime.not_dvd_mul {p m n : ℕ} (pp : Prime p) (Hm : ¬p ∣ m) (Hn : ¬ @[simp] lemma coprime_two_right : n.Coprime 2 ↔ Odd n := coprime_comm.trans coprime_two_left -alias ⟨Coprime.odd_of_left, _root_.Odd.coprime_two_left⟩ := coprime_two_left -alias ⟨Coprime.odd_of_right, _root_.Odd.coprime_two_right⟩ := coprime_two_right - --- Porting note: attributes `protected`, `nolint dup_namespace` removed +protected alias ⟨Coprime.odd_of_left, _root_.Odd.coprime_two_left⟩ := coprime_two_left +protected alias ⟨Coprime.odd_of_right, _root_.Odd.coprime_two_right⟩ := coprime_two_right theorem Prime.dvd_of_dvd_pow {p m n : ℕ} (pp : Prime p) (h : p ∣ m ^ n) : p ∣ m := pp.prime.dvd_of_dvd_pow h @@ -158,18 +155,6 @@ theorem Prime.pow_eq_iff {p a k : ℕ} (hp : p.Prime) : a ^ k = p ↔ a = p ∧ rw [← h] at hp rw [← h, hp.eq_one_of_pow, eq_self_iff_true, _root_.and_true, pow_one] -theorem pow_minFac {n k : ℕ} (hk : k ≠ 0) : (n ^ k).minFac = n.minFac := by - rcases eq_or_ne n 1 with (rfl | hn) - · simp - have hnk : n ^ k ≠ 1 := fun hk' => hn ((pow_eq_one_iff hk).1 hk') - apply (minFac_le_of_dvd (minFac_prime hn).two_le ((minFac_dvd n).pow hk)).antisymm - apply - minFac_le_of_dvd (minFac_prime hnk).two_le - ((minFac_prime hnk).dvd_of_dvd_pow (minFac_dvd _)) - -theorem Prime.pow_minFac {p k : ℕ} (hp : p.Prime) (hk : k ≠ 0) : (p ^ k).minFac = p := by - rw [Nat.pow_minFac hk, hp.minFac_eq] - theorem Prime.mul_eq_prime_sq_iff {x y p : ℕ} (hp : p.Prime) (hx : x ≠ 1) (hy : y ≠ 1) : x * y = p ^ 2 ↔ x = p ∧ y = p := by refine ⟨fun h => ?_, fun ⟨h₁, h₂⟩ => h₁.symm ▸ h₂.symm ▸ (sq _).symm⟩ @@ -196,14 +181,6 @@ theorem Prime.mul_eq_prime_sq_iff {x y p : ℕ} (hp : p.Prime) (hx : x ≠ 1) (h rw [sq, Nat.mul_right_eq_self_iff (Nat.mul_pos hp.pos hp.pos : 0 < a * a)] at h exact h -theorem Prime.dvd_factorial : ∀ {n p : ℕ} (_ : Prime p), p ∣ n ! ↔ p ≤ n - | 0, p, hp => iff_of_false hp.not_dvd_one (not_le_of_lt hp.pos) - | n + 1, p, hp => by - rw [factorial_succ, hp.dvd_mul, Prime.dvd_factorial hp] - exact - ⟨fun h => h.elim (le_of_dvd (succ_pos _)) le_succ_of_le, fun h => - (_root_.lt_or_eq_of_le h).elim (Or.inr ∘ le_of_lt_succ) fun h => Or.inl <| by rw [h]⟩ - theorem Prime.coprime_pow_of_not_dvd {p m a : ℕ} (pp : Prime p) (h : ¬p ∣ a) : Coprime a (p ^ m) := (pp.coprime_iff_not_dvd.2 h).symm.pow_right _ @@ -268,33 +245,4 @@ theorem succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul {p : ℕ} (p_prime : Prime p) { exact hpd5.elim (fun h : p ∣ m / p ^ k => Or.inl <| mul_dvd_of_dvd_div hpm h) fun h : p ∣ n / p ^ l => Or.inr <| mul_dvd_of_dvd_div hpn h -theorem prime_iff_prime_int {p : ℕ} : p.Prime ↔ _root_.Prime (p : ℤ) := - ⟨fun hp => - ⟨Int.natCast_ne_zero_iff_pos.2 hp.pos, mt Int.isUnit_iff_natAbs_eq.1 hp.ne_one, fun a b h => by - rw [← Int.dvd_natAbs, Int.natCast_dvd_natCast, Int.natAbs_mul, hp.dvd_mul] at h - rwa [← Int.dvd_natAbs, Int.natCast_dvd_natCast, ← Int.dvd_natAbs, Int.natCast_dvd_natCast]⟩, - fun hp => - Nat.prime_iff.2 - ⟨Int.natCast_ne_zero.1 hp.1, - (mt Nat.isUnit_iff.1) fun h => by simp [h, not_prime_one] at hp, fun a b => by - simpa only [Int.natCast_dvd_natCast, (Int.ofNat_mul _ _).symm] using hp.2.2 a b⟩⟩ - -/-- Two prime powers with positive exponents are equal only when the primes and the -exponents are equal. -/ -lemma Prime.pow_inj {p q m n : ℕ} (hp : p.Prime) (hq : q.Prime) - (h : p ^ (m + 1) = q ^ (n + 1)) : p = q ∧ m = n := by - have H := dvd_antisymm (Prime.dvd_of_dvd_pow hp <| h ▸ dvd_pow_self p (succ_ne_zero m)) - (Prime.dvd_of_dvd_pow hq <| h.symm ▸ dvd_pow_self q (succ_ne_zero n)) - exact ⟨H, succ_inj'.mp <| Nat.pow_right_injective hq.two_le (H ▸ h)⟩ - end Nat - -namespace Int - -theorem prime_two : Prime (2 : ℤ) := - Nat.prime_iff_prime_int.mp Nat.prime_two - -theorem prime_three : Prime (3 : ℤ) := - Nat.prime_iff_prime_int.mp Nat.prime_three - -end Int diff --git a/Mathlib/Data/Nat/Prime/Defs.lean b/Mathlib/Data/Nat/Prime/Defs.lean index a7b24cb865b8f..e6a3e5bd1a467 100644 --- a/Mathlib/Data/Nat/Prime/Defs.lean +++ b/Mathlib/Data/Nat/Prime/Defs.lean @@ -3,8 +3,10 @@ Copyright (c) 2015 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ -import Mathlib.Algebra.Associated.Basic -import Mathlib.Algebra.Ring.Parity +import Batteries.Data.Nat.Gcd +import Mathlib.Algebra.Prime.Defs +import Mathlib.Algebra.Ring.Nat +import Mathlib.Order.Lattice /-! # Prime numbers @@ -160,29 +162,6 @@ theorem prime_dvd_prime_iff_eq {p q : ℕ} (pp : p.Prime) (qp : q.Prime) : p ∣ theorem Prime.not_dvd_one {p : ℕ} (pp : Prime p) : ¬p ∣ 1 := Irreducible.not_dvd_one pp -theorem prime_mul_iff {a b : ℕ} : Nat.Prime (a * b) ↔ a.Prime ∧ b = 1 ∨ b.Prime ∧ a = 1 := by - simp only [irreducible_mul_iff, ← irreducible_iff_nat_prime, Nat.isUnit_iff] - -theorem not_prime_mul {a b : ℕ} (a1 : a ≠ 1) (b1 : b ≠ 1) : ¬Prime (a * b) := by - simp [prime_mul_iff, _root_.not_or, *] - -theorem not_prime_mul' {a b n : ℕ} (h : a * b = n) (h₁ : a ≠ 1) (h₂ : b ≠ 1) : ¬Prime n := - h ▸ not_prime_mul h₁ h₂ - -theorem Prime.dvd_iff_eq {p a : ℕ} (hp : p.Prime) (a1 : a ≠ 1) : a ∣ p ↔ p = a := by - refine ⟨?_, by rintro rfl; rfl⟩ - rintro ⟨j, rfl⟩ - rcases prime_mul_iff.mp hp with (⟨_, rfl⟩ | ⟨_, rfl⟩) - · exact mul_one _ - · exact (a1 rfl).elim - -theorem Prime.eq_two_or_odd {p : ℕ} (hp : Prime p) : p = 2 ∨ p % 2 = 1 := - p.mod_two_eq_zero_or_one.imp_left fun h => - ((hp.eq_one_or_self_of_dvd 2 (dvd_of_mod_eq_zero h)).resolve_left (by decide)).symm - -theorem Prime.eq_two_or_odd' {p : ℕ} (hp : Prime p) : p = 2 ∨ Odd p := - Or.imp_right (fun h => ⟨p / 2, (div_add_mod p 2).symm.trans (congr_arg _ h)⟩) hp.eq_two_or_odd - section MinFac theorem minFac_lemma (n k : ℕ) (h : ¬n < k * k) : sqrt n - k < sqrt n + 2 - k := @@ -404,7 +383,7 @@ theorem coprime_of_dvd {m n : ℕ} (H : ∀ k, Prime k → k ∣ m → ¬k ∣ n theorem Prime.coprime_iff_not_dvd {p n : ℕ} (pp : Prime p) : Coprime p n ↔ ¬p ∣ n := ⟨fun co d => pp.not_dvd_one <| co.dvd_of_dvd_mul_left (by simp [d]), fun nd => - coprime_of_dvd fun m m2 mp => ((prime_dvd_prime_iff_eq m2 pp).1 mp).symm ▸ nd⟩ + coprime_of_dvd fun _ m2 mp => ((prime_dvd_prime_iff_eq m2 pp).1 mp).symm ▸ nd⟩ theorem Prime.dvd_mul {p m n : ℕ} (pp : Prime p) : p ∣ m * n ↔ p ∣ m ∨ p ∣ n := ⟨fun H => or_iff_not_imp_left.2 fun h => (pp.coprime_iff_not_dvd.2 h).dvd_of_dvd_mul_left H, diff --git a/Mathlib/Data/Nat/Prime/Factorial.lean b/Mathlib/Data/Nat/Prime/Factorial.lean new file mode 100644 index 0000000000000..4c2f70a84a4c9 --- /dev/null +++ b/Mathlib/Data/Nat/Prime/Factorial.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Mathlib.Data.Nat.Factorial.Basic +import Mathlib.Data.Nat.Prime.Defs + +/-! +# Prime natural numbers and the factorial operator + +-/ + +open Bool Subtype + +open Nat + +namespace Nat + +theorem Prime.dvd_factorial : ∀ {n p : ℕ} (_ : Prime p), p ∣ n ! ↔ p ≤ n + | 0, _, hp => iff_of_false hp.not_dvd_one (not_le_of_lt hp.pos) + | n + 1, p, hp => by + rw [factorial_succ, hp.dvd_mul, Prime.dvd_factorial hp] + exact + ⟨fun h => h.elim (le_of_dvd (succ_pos _)) le_succ_of_le, fun h => + (_root_.lt_or_eq_of_le h).elim (Or.inr ∘ le_of_lt_succ) fun h => Or.inl <| by rw [h]⟩ + +end Nat diff --git a/Mathlib/Data/Nat/Prime/Infinite.lean b/Mathlib/Data/Nat/Prime/Infinite.lean new file mode 100644 index 0000000000000..f67b58631e769 --- /dev/null +++ b/Mathlib/Data/Nat/Prime/Infinite.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Mathlib.Data.Nat.Factorial.Basic +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Order.Bounds.Basic + +/-! +## Notable Theorems + +- `Nat.exists_infinite_primes`: Euclid's theorem that there exist infinitely many prime numbers. + This also appears as `Nat.not_bddAbove_setOf_prime` and `Nat.infinite_setOf_prime` (the latter + in `Data.Nat.PrimeFin`). + +-/ + +open Bool Subtype + +open Nat + +namespace Nat + +section Infinite + +/-- Euclid's theorem on the **infinitude of primes**. +Here given in the form: for every `n`, there exists a prime number `p ≥ n`. -/ +theorem exists_infinite_primes (n : ℕ) : ∃ p, n ≤ p ∧ Prime p := + let p := minFac (n ! + 1) + have f1 : n ! + 1 ≠ 1 := ne_of_gt <| succ_lt_succ <| factorial_pos _ + have pp : Prime p := minFac_prime f1 + have np : n ≤ p := + le_of_not_ge fun h => + have h₁ : p ∣ n ! := dvd_factorial (minFac_pos _) h + have h₂ : p ∣ 1 := (Nat.dvd_add_iff_right h₁).2 (minFac_dvd _) + pp.not_dvd_one h₂ + ⟨p, np, pp⟩ + +/-- A version of `Nat.exists_infinite_primes` using the `BddAbove` predicate. -/ +theorem not_bddAbove_setOf_prime : ¬BddAbove { p | Prime p } := by + rw [not_bddAbove_iff] + intro n + obtain ⟨p, hi, hp⟩ := exists_infinite_primes n.succ + exact ⟨p, hp, hi⟩ + +end Infinite + +end Nat diff --git a/Mathlib/Data/Nat/Prime/Int.lean b/Mathlib/Data/Nat/Prime/Int.lean new file mode 100644 index 0000000000000..9a6f71bc49518 --- /dev/null +++ b/Mathlib/Data/Nat/Prime/Int.lean @@ -0,0 +1,53 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Mathlib.Algebra.Ring.Int +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`. +-/ + + +namespace Nat + +theorem prime_iff_prime_int {p : ℕ} : p.Prime ↔ _root_.Prime (p : ℤ) := + ⟨fun hp => + ⟨Int.natCast_ne_zero_iff_pos.2 hp.pos, mt Int.isUnit_iff_natAbs_eq.1 hp.ne_one, fun a b h => by + rw [← Int.dvd_natAbs, Int.natCast_dvd_natCast, Int.natAbs_mul, hp.dvd_mul] at h + rwa [← Int.dvd_natAbs, Int.natCast_dvd_natCast, ← Int.dvd_natAbs, Int.natCast_dvd_natCast]⟩, + fun hp => + Nat.prime_iff.2 + ⟨Int.natCast_ne_zero.1 hp.1, + (mt Nat.isUnit_iff.1) fun h => by simp [h, not_prime_one] at hp, fun a b => by + simpa only [Int.natCast_dvd_natCast, (Int.ofNat_mul _ _).symm] using hp.2.2 a b⟩⟩ + +/-- Two prime powers with positive exponents are equal only when the primes and the +exponents are equal. -/ +lemma Prime.pow_inj {p q m n : ℕ} (hp : p.Prime) (hq : q.Prime) + (h : p ^ (m + 1) = q ^ (n + 1)) : p = q ∧ m = n := by + have H := dvd_antisymm (Prime.dvd_of_dvd_pow hp <| h ▸ dvd_pow_self p (succ_ne_zero m)) + (Prime.dvd_of_dvd_pow hq <| h.symm ▸ dvd_pow_self q (succ_ne_zero n)) + exact ⟨H, succ_inj'.mp <| Nat.pow_right_injective hq.two_le (H ▸ h)⟩ + +end Nat + +namespace Int + +-- See note [no_index around OfNat.ofNat] +@[simp] +theorem prime_ofNat_iff {n : ℕ} : + Prime (no_index (OfNat.ofNat n : ℤ)) ↔ Nat.Prime (OfNat.ofNat n) := + Nat.prime_iff_prime_int.symm + +theorem prime_two : Prime (2 : ℤ) := + prime_ofNat_iff.mpr Nat.prime_two + +theorem prime_three : Prime (3 : ℤ) := + prime_ofNat_iff.mpr Nat.prime_three + +end Int diff --git a/Mathlib/Data/Nat/Prime/Nth.lean b/Mathlib/Data/Nat/Prime/Nth.lean new file mode 100644 index 0000000000000..bc59dbf9f528f --- /dev/null +++ b/Mathlib/Data/Nat/Prime/Nth.lean @@ -0,0 +1,23 @@ +/- +Copyright (c) 2024 Ralf Stephan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ralf Stephan +-/ +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.Nth + +/-! +# The Nth primes +-/ + +namespace Nat + +@[simp] +theorem nth_prime_zero_eq_two : nth Prime 0 = 2 := nth_count prime_two +@[deprecated (since := "2024-09-21")] +alias zeroth_prime_eq_two := nth_prime_zero_eq_two + +@[simp] +theorem nth_prime_one_eq_three : nth Nat.Prime 1 = 3 := nth_count prime_three + +end Nat diff --git a/Mathlib/Data/Nat/Prime/Pow.lean b/Mathlib/Data/Nat/Prime/Pow.lean new file mode 100644 index 0000000000000..a103a434d4ff6 --- /dev/null +++ b/Mathlib/Data/Nat/Prime/Pow.lean @@ -0,0 +1,31 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro +-/ +import Mathlib.Algebra.Order.Monoid.Unbundled.Pow +import Mathlib.Data.Nat.Prime.Basic + +/-! +# Prime numbers + +This file develops the theory of prime numbers: natural numbers `p ≥ 2` whose only divisors are +`p` and `1`. + +-/ + +namespace Nat + +theorem pow_minFac {n k : ℕ} (hk : k ≠ 0) : (n ^ k).minFac = n.minFac := by + rcases eq_or_ne n 1 with (rfl | hn) + · simp + have hnk : n ^ k ≠ 1 := fun hk' => hn ((pow_eq_one_iff hk).1 hk') + apply (minFac_le_of_dvd (minFac_prime hn).two_le ((minFac_dvd n).pow hk)).antisymm + apply + minFac_le_of_dvd (minFac_prime hnk).two_le + ((minFac_prime hnk).dvd_of_dvd_pow (minFac_dvd _)) + +theorem Prime.pow_minFac {p k : ℕ} (hp : p.Prime) (hk : k ≠ 0) : (p ^ k).minFac = p := by + rw [Nat.pow_minFac hk, hp.minFac_eq] + +end Nat diff --git a/Mathlib/Data/Nat/PrimeFin.lean b/Mathlib/Data/Nat/PrimeFin.lean index 8f1fe7411bc75..ecb04ce9d0c0a 100644 --- a/Mathlib/Data/Nat/PrimeFin.lean +++ b/Mathlib/Data/Nat/PrimeFin.lean @@ -6,7 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro import Mathlib.Data.Countable.Defs import Mathlib.Data.Nat.Factors import Mathlib.Data.Set.Finite -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Infinite /-! # Prime numbers diff --git a/Mathlib/Data/Nat/Size.lean b/Mathlib/Data/Nat/Size.lean index f3f51b3aa4f02..fec3892450d06 100644 --- a/Mathlib/Data/Nat/Size.lean +++ b/Mathlib/Data/Nat/Size.lean @@ -19,8 +19,8 @@ theorem shiftLeft_eq_mul_pow (m) : ∀ n, m <<< n = m * 2 ^ n := shiftLeft_eq _ theorem shiftLeft'_tt_eq_mul_pow (m) : ∀ n, shiftLeft' true m n + 1 = (m + 1) * 2 ^ n | 0 => by simp [shiftLeft', pow_zero, Nat.one_mul] | k + 1 => by - rw [shiftLeft', bit_val, cond_true, add_assoc, ← Nat.mul_add_one, shiftLeft'_tt_eq_mul_pow m k, - mul_left_comm, mul_comm 2, pow_succ] + rw [shiftLeft', bit_val, Bool.toNat_true, add_assoc, ← Nat.mul_add_one, + shiftLeft'_tt_eq_mul_pow m k, mul_left_comm, mul_comm 2, pow_succ] end @@ -39,12 +39,11 @@ theorem size_zero : size 0 = 0 := by simp [size] @[simp] theorem size_bit {b n} (h : bit b n ≠ 0) : size (bit b n) = succ (size n) := by - rw [size] + unfold size conv => lhs rw [binaryRec] simp [h] - rw [div2_bit] section @@ -82,7 +81,7 @@ theorem size_shiftLeft {m} (h : m ≠ 0) (n) : size (m <<< n) = size m + n := by theorem lt_size_self (n : ℕ) : n < 2 ^ size n := by rw [← one_shiftLeft] have : ∀ {n}, n = 0 → n < 1 <<< (size n) := by simp - apply binaryRec _ _ n + refine binaryRec ?_ ?_ n · apply this rfl intro b n IH by_cases h : bit b n = 0 @@ -92,11 +91,11 @@ theorem lt_size_self (n : ℕ) : n < 2 ^ size n := by theorem size_le {m n : ℕ} : size m ≤ n ↔ m < 2 ^ n := ⟨fun h => lt_of_lt_of_le (lt_size_self _) (pow_le_pow_of_le_right (by decide) h), by - rw [← one_shiftLeft]; revert n - apply binaryRec _ _ m - · intro n - simp - · intro b m IH n h + rw [← one_shiftLeft] + induction m using binaryRec generalizing n with + | z => simp + | f b m IH => + intro h by_cases e : bit b m = 0 · simp [e] rw [size_bit e] diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index d11d003343934..40e3df63b05fc 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -49,12 +49,12 @@ 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_multiplicity_le_one] at hn + rw [multiplicity.squarefree_iff_emultiplicity_le_one] at hn by_cases hp : p.Prime · have := hn p - simp only [multiplicity_eq_factorization hp hn', Nat.isUnit_iff, hp.ne_one, or_false] - at this - exact mod_cast this + rw [← multiplicity_eq_factorization hp hn'] + simp only [Nat.isUnit_iff, hp.ne_one, or_false] at this + exact multiplicity_le_of_emultiplicity_le this · rw [factorization_eq_zero_of_non_prime _ hp] exact zero_le_one @@ -245,14 +245,14 @@ theorem squarefree_two : Squarefree 2 := by rw [squarefree_iff_nodup_primeFactorsList] <;> simp theorem divisors_filter_squarefree_of_squarefree {n : ℕ} (hn : Squarefree n) : - n.divisors.filter Squarefree = n.divisors := + {d ∈ n.divisors | Squarefree d} = n.divisors := Finset.ext fun d => ⟨@Finset.filter_subset _ _ _ _ d, fun hd => Finset.mem_filter.mpr ⟨hd, hn.squarefree_of_dvd (Nat.dvd_of_mem_divisors hd) ⟩⟩ open UniqueFactorizationMonoid theorem divisors_filter_squarefree {n : ℕ} (h0 : n ≠ 0) : - (n.divisors.filter Squarefree).val = + {d ∈ n.divisors | Squarefree d}.val = (UniqueFactorizationMonoid.normalizedFactors n).toFinset.powerset.val.map fun x => x.val.prod := by rw [(Finset.nodup _).ext ((Finset.nodup _).map_on _)] @@ -303,7 +303,7 @@ theorem divisors_filter_squarefree {n : ℕ} (h0 : n ≠ 0) : theorem sum_divisors_filter_squarefree {n : ℕ} (h0 : n ≠ 0) {α : Type*} [AddCommMonoid α] {f : ℕ → α} : - ∑ i ∈ n.divisors.filter Squarefree, f i = + ∑ d ∈ n.divisors with Squarefree d, f d = ∑ i ∈ (UniqueFactorizationMonoid.normalizedFactors n).toFinset.powerset, f i.val.prod := by rw [Finset.sum_eq_multiset_sum, divisors_filter_squarefree h0, Multiset.map_map, Finset.sum_eq_multiset_sum] @@ -312,7 +312,7 @@ theorem sum_divisors_filter_squarefree {n : ℕ} (h0 : n ≠ 0) {α : Type*} [Ad theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) : ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by classical -- Porting note: This line is not needed in Lean 3 - set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) + set S := {s ∈ range (n + 1) | s ∣ n ∧ ∃ x, s = x ^ 2} have hSne : S.Nonempty := by use 1 have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩ diff --git a/Mathlib/Data/Nat/Totient.lean b/Mathlib/Data/Nat/Totient.lean index ec08e85c219d9..47f0879f6ad0d 100644 --- a/Mathlib/Data/Nat/Totient.lean +++ b/Mathlib/Data/Nat/Totient.lean @@ -20,14 +20,16 @@ We prove the divisor sum formula, namely that `n` equals `φ` summed over the di `totient_prime_pow`. -/ +assert_not_exists Algebra +assert_not_exists LinearMap + open Finset namespace Nat /-- Euler's totient function. This counts the number of naturals strictly less than `n` which are coprime with `n`. -/ -def totient (n : ℕ) : ℕ := - ((range n).filter n.Coprime).card +def totient (n : ℕ) : ℕ := #{a ∈ range n | n.Coprime a} @[inherit_doc] scoped notation "φ" => Nat.totient @@ -39,12 +41,11 @@ theorem totient_zero : φ 0 = 0 := @[simp] theorem totient_one : φ 1 = 1 := rfl -theorem totient_eq_card_coprime (n : ℕ) : φ n = ((range n).filter n.Coprime).card := - rfl +theorem totient_eq_card_coprime (n : ℕ) : φ n = #{a ∈ range n | n.Coprime a} := rfl /-- A characterisation of `Nat.totient` that avoids `Finset`. -/ theorem totient_eq_card_lt_and_coprime (n : ℕ) : φ n = Nat.card { m | m < n ∧ n.Coprime m } := by - let e : { m | m < n ∧ n.Coprime m } ≃ Finset.filter n.Coprime (Finset.range n) := + let e : { m | m < n ∧ n.Coprime m } ≃ {x ∈ range n | n.Coprime x} := { toFun := fun m => ⟨m, by simpa only [Finset.mem_filter, Finset.mem_range] using m.property⟩ invFun := fun m => ⟨m, by simpa only [Finset.mem_filter, Finset.mem_range] using m.property⟩ left_inv := fun m => by simp only [Subtype.coe_mk, Subtype.coe_eta] @@ -67,12 +68,12 @@ theorem totient_eq_zero : ∀ {n : ℕ}, φ n = 0 ↔ n = 0 @[simp] theorem totient_pos {n : ℕ} : 0 < φ n ↔ 0 < n := by simp [pos_iff_ne_zero] theorem filter_coprime_Ico_eq_totient (a n : ℕ) : - ((Ico n (n + a)).filter (Coprime a)).card = totient a := by + #{x ∈ Ico n (n + a) | a.Coprime x} = totient a := by rw [totient, filter_Ico_card_eq_of_periodic, count_eq_card_filter_range] exact periodic_coprime a theorem Ico_filter_coprime_le {a : ℕ} (k n : ℕ) (a_pos : 0 < a) : - ((Ico k (k + n)).filter (Coprime a)).card ≤ totient a * (n / a + 1) := by + #{x ∈ Ico k (k + n) | a.Coprime x} ≤ totient a * (n / a + 1) := by conv_lhs => rw [← Nat.mod_add_div n a] induction' n / a with i ih · rw [← filter_coprime_Ico_eq_totient a k] @@ -83,14 +84,15 @@ theorem Ico_filter_coprime_le {a : ℕ} (k n : ℕ) (a_pos : 0 < a) : simp only [mul_succ] simp_rw [← add_assoc] at ih ⊢ calc - (filter a.Coprime (Ico k (k + n % a + a * i + a))).card = (filter a.Coprime - (Ico k (k + n % a + a * i) ∪ Ico (k + n % a + a * i) (k + n % a + a * i + a))).card := by + #{x ∈ Ico k (k + n % a + a * i + a) | a.Coprime x} + = #{x ∈ Ico k (k + n % a + a * i) ∪ + Ico (k + n % a + a * i) (k + n % a + a * i + a) | a.Coprime x} := by congr rw [Ico_union_Ico_eq_Ico] · rw [add_assoc] exact le_self_add exact le_self_add - _ ≤ (filter a.Coprime (Ico k (k + n % a + a * i))).card + a.totient := by + _ ≤ #{x ∈ Ico k (k + n % a + a * i) | a.Coprime x} + a.totient := by rw [filter_union, ← filter_coprime_Ico_eq_totient a (k + n % a + a * i)] apply card_union_le _ ≤ a.totient * i + a.totient + a.totient := add_le_add_right ih (totient a) @@ -133,7 +135,7 @@ theorem totient_mul {m n : ℕ} (h : m.Coprime n) : φ (m * n) = φ m * φ n := /-- For `d ∣ n`, the totient of `n/d` equals the number of values `k < n` such that `gcd n k = d` -/ theorem totient_div_of_dvd {n d : ℕ} (hnd : d ∣ n) : - φ (n / d) = (filter (fun k : ℕ => n.gcd k = d) (range n)).card := by + φ (n / d) = #{k ∈ range n | n.gcd k = d} := by rcases d.eq_zero_or_pos with (rfl | hd0); · simp [eq_zero_of_zero_dvd hnd] rcases hnd with ⟨x, rfl⟩ rw [Nat.mul_div_cancel_left x hd0] @@ -155,14 +157,14 @@ theorem sum_totient (n : ℕ) : n.divisors.sum φ = n := by rcases n.eq_zero_or_pos with (rfl | hn) · simp rw [← sum_div_divisors n φ] - have : n = ∑ d ∈ n.divisors, (filter (fun k : ℕ => n.gcd k = d) (range n)).card := by + have : n = ∑ d ∈ n.divisors, #{k ∈ range n | n.gcd k = d} := by nth_rw 1 [← card_range n] refine card_eq_sum_card_fiberwise fun x _ => mem_divisors.2 ⟨?_, hn.ne'⟩ apply gcd_dvd_left nth_rw 3 [this] exact sum_congr rfl fun x hx => totient_div_of_dvd (dvd_of_mem_divisors hx) -theorem sum_totient' (n : ℕ) : (∑ m ∈ (range n.succ).filter (· ∣ n), φ m) = n := by +theorem sum_totient' (n : ℕ) : ∑ m ∈ range n.succ with m ∣ n, φ m = n := by convert sum_totient _ using 1 simp only [Nat.divisors, sum_filter, range_eq_Ico] rw [sum_eq_sum_Ico_succ_bot] <;> simp @@ -170,10 +172,10 @@ theorem sum_totient' (n : ℕ) : (∑ m ∈ (range n.succ).filter (· ∣ n), φ /-- When `p` is prime, then the totient of `p ^ (n + 1)` is `p ^ n * (p - 1)` -/ theorem totient_prime_pow_succ {p : ℕ} (hp : p.Prime) (n : ℕ) : φ (p ^ (n + 1)) = p ^ n * (p - 1) := calc - φ (p ^ (n + 1)) = ((range (p ^ (n + 1))).filter (Coprime (p ^ (n + 1)))).card := + φ (p ^ (n + 1)) = #{a ∈ range (p ^ (n + 1)) | (p ^ (n + 1)).Coprime a} := totient_eq_card_coprime _ - _ = (range (p ^ (n + 1)) \ (range (p ^ n)).image (· * p)).card := - (congr_arg card + _ = #(range (p ^ (n + 1)) \ (range (p ^ n)).image (· * p)) := + congr_arg card (by rw [sdiff_eq_filter] apply filter_congr @@ -185,7 +187,7 @@ theorem totient_prime_pow_succ {p : ℕ} (hp : p.Prime) (n : ℕ) : φ (p ^ (n + exact hap (dvd_mul_left _ _) · rintro h ⟨b, rfl⟩ rw [pow_succ'] at ha - exact h b ⟨lt_of_mul_lt_mul_left ha (zero_le _), mul_comm _ _⟩)) + exact h b ⟨lt_of_mul_lt_mul_left ha (zero_le _), mul_comm _ _⟩) _ = _ := by have h1 : Function.Injective (· * p) := mul_left_injective₀ hp.ne_zero have h2 : (range (p ^ n)).image (· * p) ⊆ range (p ^ (n + 1)) := fun a => by diff --git a/Mathlib/Data/Num/Basic.lean b/Mathlib/Data/Num/Basic.lean index 5e35ca5550ad8..07f592d41ee94 100644 --- a/Mathlib/Data/Num/Basic.lean +++ b/Mathlib/Data/Num/Basic.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Mario Carneiro -/ import Lean.Linter.Deprecated -import Mathlib.Data.Int.Notation import Mathlib.Algebra.Group.ZeroOne -import Mathlib.Data.Nat.Bits +import Mathlib.Data.Int.Notation +import Mathlib.Data.Nat.BinaryRec +import Mathlib.Tactic.TypeStar + /-! # Binary representation of integers using inductive types diff --git a/Mathlib/Data/Num/Lemmas.lean b/Mathlib/Data/Num/Lemmas.lean index 66c8cae9f974a..8e33a4752ee9e 100644 --- a/Mathlib/Data/Num/Lemmas.lean +++ b/Mathlib/Data/Num/Lemmas.lean @@ -45,7 +45,7 @@ theorem cast_to_nat [AddMonoidWithOne α] : ∀ n : PosNum, ((n : ℕ) : α) = n | bit0 p => by dsimp; rw [Nat.cast_add, p.cast_to_nat] | bit1 p => by dsimp; rw [Nat.cast_add, Nat.cast_add, Nat.cast_one, p.cast_to_nat] -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem to_nat_to_int (n : PosNum) : ((n : ℕ) : ℤ) = n := cast_to_nat _ @@ -55,7 +55,7 @@ theorem cast_to_int [AddGroupWithOne α] (n : PosNum) : ((n : ℤ) : α) = n := theorem succ_to_nat : ∀ n, (succ n : ℕ) = n + 1 | 1 => rfl - | bit0 p => rfl + | bit0 _ => rfl | bit1 p => (congr_arg (fun n ↦ n + n) (succ_to_nat p)).trans <| show ↑p + 1 + ↑p + 1 = ↑p + ↑p + 1 + 1 by simp [add_left_comm] @@ -83,9 +83,9 @@ theorem add_succ : ∀ m n : PosNum, m + succ n = succ (m + n) | 1, b => by simp [one_add] | bit0 a, 1 => congr_arg bit0 (add_one a) | bit1 a, 1 => congr_arg bit1 (add_one a) - | bit0 a, bit0 b => rfl + | bit0 _, bit0 _ => rfl | bit0 a, bit1 b => congr_arg bit0 (add_succ a b) - | bit1 a, bit0 b => rfl + | bit1 _, bit0 _ => rfl | bit1 a, bit1 b => congr_arg bit1 (add_succ a b) theorem bit0_of_bit0 : ∀ n, n + n = bit0 n @@ -187,7 +187,7 @@ theorem add_one : ∀ n : Num, n + 1 = succ n theorem add_succ : ∀ m n : Num, m + succ n = succ (m + n) | 0, n => by simp [zero_add] | pos p, 0 => show pos (p + 1) = succ (pos p + 0) by rw [PosNum.add_one, add_zero, succ, succ'] - | pos p, pos q => congr_arg pos (PosNum.add_succ _ _) + | pos _, pos _ => congr_arg pos (PosNum.add_succ _ _) theorem bit0_of_bit0 : ∀ n : Num, n + n = n.bit0 | 0 => rfl @@ -201,7 +201,7 @@ theorem bit1_of_bit1 : ∀ n : Num, (n + n) + 1 = n.bit1 theorem ofNat'_zero : Num.ofNat' 0 = 0 := by simp [Num.ofNat'] theorem ofNat'_bit (b n) : ofNat' (Nat.bit b n) = cond b Num.bit1 Num.bit0 (ofNat' n) := - Nat.binaryRec_eq rfl _ _ + Nat.binaryRec_eq _ _ (.inl rfl) @[simp] theorem ofNat'_one : Num.ofNat' 1 = 1 := by erw [ofNat'_bit true 0, cond, ofNat'_zero]; rfl @@ -215,7 +215,7 @@ theorem ofNat'_succ : ∀ {n}, ofNat' (n + 1) = ofNat' n + 1 := cases b · erw [ofNat'_bit true n, ofNat'_bit] simp only [← bit1_of_bit1, ← bit0_of_bit0, cond] - · erw [show n.bit true + 1 = (n + 1).bit false by simp [Nat.bit, mul_add], + · rw [show n.bit true + 1 = (n + 1).bit false by simp [Nat.bit, mul_add], ofNat'_bit, ofNat'_bit, ih] simp only [cond, add_one, bit1_succ]) @@ -269,8 +269,8 @@ theorem mul_to_nat : ∀ m n, ((m * n : Num) : ℕ) = m * n theorem cmp_to_nat : ∀ m n, (Ordering.casesOn (cmp m n) ((m : ℕ) < n) (m = n) ((n : ℕ) < m) : Prop) | 0, 0 => rfl - | 0, pos b => to_nat_pos _ - | pos a, 0 => to_nat_pos _ + | 0, pos _ => to_nat_pos _ + | pos _, 0 => to_nat_pos _ | pos a, pos b => by have := PosNum.cmp_to_nat a b; revert this; dsimp [cmp]; cases PosNum.cmp a b exacts [id, congr_arg pos, id] @@ -399,11 +399,11 @@ instance linearOrderedSemiring : LinearOrderedSemiring Num := decidableEq := instDecidableEqNum exists_pair_ne := ⟨0, 1, by decide⟩ } -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem add_of_nat (m n) : ((m + n : ℕ) : Num) = m + n := add_ofNat' _ _ -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem to_nat_to_int (n : Num) : ((n : ℕ) : ℤ) = n := cast_to_nat _ @@ -422,7 +422,7 @@ theorem of_natCast {α} [AddMonoidWithOne α] (n : ℕ) : ((n : Num) : α) = n : @[deprecated (since := "2024-04-17")] alias of_nat_cast := of_natCast -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem of_nat_inj {m n : ℕ} : (m : Num) = n ↔ m = n := ⟨fun h => Function.LeftInverse.injective to_of_nat h, congr_arg _⟩ @@ -462,7 +462,7 @@ theorem pred'_to_nat : ∀ n, (pred' n : ℕ) = Nat.pred n pred' n, this with | 0, (h : ((1 : Num) : ℕ) = n) => by rw [← to_nat_inj.1 h]; rfl | Num.pos p, (h : Nat.succ ↑p = n) => by rw [← h]; exact (Nat.succ_add p p).symm - | bit1 n => rfl + | bit1 _ => rfl @[simp] theorem pred'_succ' (n) : pred' (succ' n) = n := @@ -661,12 +661,11 @@ theorem natSize_to_nat (n) : natSize n = Nat.size n := by rw [← size_eq_natSiz theorem ofNat'_eq : ∀ n, Num.ofNat' n = n := Nat.binaryRec (by simp) fun b n IH => by rw [ofNat'] at IH ⊢ - rw [Nat.binaryRec_eq, IH] + rw [Nat.binaryRec_eq _ _ (.inl rfl), IH] -- Porting note: `Nat.cast_bit0` & `Nat.cast_bit1` are not `simp` theorems anymore. - · cases b <;> simp only [cond_false, cond_true, Nat.bit, two_mul, Nat.cast_add, Nat.cast_one] - · rw [bit0_of_bit0] - · rw [bit1_of_bit1] - · rfl + cases b <;> simp only [cond_false, cond_true, Nat.bit, two_mul, Nat.cast_add, Nat.cast_one] + · rw [bit0_of_bit0] + · rw [bit1_of_bit1] theorem zneg_toZNum (n : Num) : -n.toZNum = n.toZNumNeg := by cases n <;> rfl @@ -1095,7 +1094,7 @@ theorem ofInt'_toZNum : ∀ n : ℕ, toZNum n = ZNum.ofInt' n theorem mem_ofZNum' : ∀ {m : Num} {n : ZNum}, m ∈ ofZNum' n ↔ n = toZNum m | 0, 0 => ⟨fun _ => rfl, fun _ => rfl⟩ - | pos m, 0 => ⟨nofun, nofun⟩ + | pos _, 0 => ⟨nofun, nofun⟩ | m, ZNum.pos p => Option.some_inj.trans <| by cases m <;> constructor <;> intro h <;> try cases h <;> rfl | m, ZNum.neg p => ⟨nofun, fun h => by cases m <;> cases h⟩ @@ -1134,7 +1133,7 @@ variable {α : Type*} theorem cast_add [AddGroupWithOne α] : ∀ m n, ((m + n : ZNum) : α) = m + n | 0, a => by cases a <;> exact (_root_.zero_add _).symm | b, 0 => by cases b <;> exact (_root_.add_zero _).symm - | pos a, pos b => PosNum.cast_add _ _ + | pos _, pos _ => PosNum.cast_add _ _ | pos a, neg b => by simpa only [sub_eq_add_neg] using PosNum.cast_sub' (α := α) _ _ | neg a, pos b => have : (↑b + -↑a : α) = -↑a + ↑b := by @@ -1185,12 +1184,12 @@ theorem cmp_to_int : ∀ m n, (Ordering.casesOn (cmp m n) ((m : ℤ) < n) (m = n | neg a, neg b => by have := PosNum.cmp_to_nat b a; revert this; dsimp [cmp] cases PosNum.cmp b a <;> dsimp <;> [simp; simp (config := { contextual := true }); simp [GT.gt]] - | pos a, 0 => PosNum.cast_pos _ - | pos a, neg b => lt_trans (neg_lt_zero.2 <| PosNum.cast_pos _) (PosNum.cast_pos _) - | 0, neg b => neg_lt_zero.2 <| PosNum.cast_pos _ - | neg a, 0 => neg_lt_zero.2 <| PosNum.cast_pos _ - | neg a, pos b => lt_trans (neg_lt_zero.2 <| PosNum.cast_pos _) (PosNum.cast_pos _) - | 0, pos b => PosNum.cast_pos _ + | pos _, 0 => PosNum.cast_pos _ + | pos _, neg _ => lt_trans (neg_lt_zero.2 <| PosNum.cast_pos _) (PosNum.cast_pos _) + | 0, neg _ => neg_lt_zero.2 <| PosNum.cast_pos _ + | neg _, 0 => neg_lt_zero.2 <| PosNum.cast_pos _ + | neg _, pos _ => lt_trans (neg_lt_zero.2 <| PosNum.cast_pos _) (PosNum.cast_pos _) + | 0, pos _ => PosNum.cast_pos _ @[norm_cast] theorem lt_to_int {m n : ZNum} : (m : ℤ) < n ↔ m < n := @@ -1324,11 +1323,11 @@ instance linearOrderedCommRing : LinearOrderedCommRing ZNum := @[simp, norm_cast] theorem cast_sub [Ring α] (m n) : ((m - n : ZNum) : α) = m - n := by simp [sub_eq_neg_add] -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem neg_of_int : ∀ n, ((-n : ℤ) : ZNum) = -n - | (n + 1 : ℕ) => rfl + | (_ + 1 : ℕ) => rfl | 0 => by rw [Int.cast_neg] - | -[n+1] => (zneg_zneg _).symm + | -[_+1] => (zneg_zneg _).symm @[simp] theorem ofInt'_eq : ∀ n : ℤ, ZNum.ofInt' n = n @@ -1440,9 +1439,9 @@ protected theorem div_zero (n : Num) : n / 0 = 0 := @[simp, norm_cast] theorem div_to_nat : ∀ n d, ((n / d : Num) : ℕ) = n / d | 0, 0 => by simp - | 0, pos d => (Nat.zero_div _).symm - | pos n, 0 => (Nat.div_zero _).symm - | pos n, pos d => PosNum.div'_to_nat _ _ + | 0, pos _ => (Nat.zero_div _).symm + | pos _, 0 => (Nat.div_zero _).symm + | pos _, pos _ => PosNum.div'_to_nat _ _ @[simp] protected theorem mod_zero (n : Num) : n % 0 = n := @@ -1454,16 +1453,16 @@ protected theorem mod_zero (n : Num) : n % 0 = n := @[simp, norm_cast] theorem mod_to_nat : ∀ n d, ((n % d : Num) : ℕ) = n % d | 0, 0 => by simp - | 0, pos d => (Nat.zero_mod _).symm - | pos n, 0 => (Nat.mod_zero _).symm - | pos n, pos d => PosNum.mod'_to_nat _ _ + | 0, pos _ => (Nat.zero_mod _).symm + | pos _, 0 => (Nat.mod_zero _).symm + | pos _, pos _ => PosNum.mod'_to_nat _ _ theorem gcd_to_nat_aux : ∀ {n} {a b : Num}, a ≤ b → (a * b).natSize ≤ n → (gcdAux n a b : ℕ) = Nat.gcd a b - | 0, 0, b, _ab, _h => (Nat.gcd_zero_left _).symm - | 0, pos a, 0, ab, _h => (not_lt_of_ge ab).elim rfl - | 0, pos a, pos b, _ab, h => (not_lt_of_le h).elim <| PosNum.natSize_pos _ - | Nat.succ n, 0, b, _ab, _h => (Nat.gcd_zero_left _).symm + | 0, 0, _, _ab, _h => (Nat.gcd_zero_left _).symm + | 0, pos _, 0, ab, _h => (not_lt_of_ge ab).elim rfl + | 0, pos _, pos _, _ab, h => (not_lt_of_le h).elim <| PosNum.natSize_pos _ + | Nat.succ _, 0, _, _ab, _h => (Nat.gcd_zero_left _).symm | Nat.succ n, pos a, b, ab, h => by simp only [gcdAux, cast_pos] rw [Nat.gcd_rec, gcd_to_nat_aux, mod_to_nat] @@ -1516,10 +1515,10 @@ protected theorem div_zero (n : ZNum) : n / 0 = 0 := @[simp, norm_cast] theorem div_to_int : ∀ n d, ((n / d : ZNum) : ℤ) = n / d | 0, 0 => by simp [Int.ediv_zero] - | 0, pos d => (Int.zero_ediv _).symm - | 0, neg d => (Int.zero_ediv _).symm - | pos n, 0 => (Int.ediv_zero _).symm - | neg n, 0 => (Int.ediv_zero _).symm + | 0, pos _ => (Int.zero_ediv _).symm + | 0, neg _ => (Int.zero_ediv _).symm + | pos _, 0 => (Int.ediv_zero _).symm + | neg _, 0 => (Int.ediv_zero _).symm | pos n, pos d => (Num.cast_toZNum _).trans <| by rw [← Num.to_nat_to_int]; simp | pos n, neg d => (Num.cast_toZNumNeg _).trans <| by rw [← Num.to_nat_to_int]; simp | neg n, pos d => @@ -1537,7 +1536,7 @@ theorem div_to_int : ∀ n d, ((n / d : ZNum) : ℤ) = n / d @[simp, norm_cast] theorem mod_to_int : ∀ n d, ((n % d : ZNum) : ℤ) = n % d - | 0, d => (Int.zero_emod _).symm + | 0, _ => (Int.zero_emod _).symm | pos n, d => (Num.cast_toZNum _).trans <| by rw [← Num.to_nat_to_int, cast_pos, Num.mod_to_nat, ← PosNum.to_nat_to_int, abs_to_nat] diff --git a/Mathlib/Data/Opposite.lean b/Mathlib/Data/Opposite.lean index 2482808fe2c64..c9f9e120603ca 100644 --- a/Mathlib/Data/Opposite.lean +++ b/Mathlib/Data/Opposite.lean @@ -30,7 +30,7 @@ variable (α : Sort u) both `unop (op X) = X` and `op (unop X) = X` are definitional equalities. -/ -structure Opposite := +structure Opposite where /-- The canonical map `α → αᵒᵖ`. -/ op :: /-- The canonical map `αᵒᵖ → α`. -/ diff --git a/Mathlib/Data/Option/Basic.lean b/Mathlib/Data/Option/Basic.lean index b0bab527487d9..ba871ac9136ba 100644 --- a/Mathlib/Data/Option/Basic.lean +++ b/Mathlib/Data/Option/Basic.lean @@ -149,7 +149,7 @@ theorem mem_pmem {a : α} (h : ∀ a ∈ x, p a) (ha : a ∈ x) : f a (h a ha) rfl theorem pmap_map (g : γ → α) (x : Option γ) (H) : - pmap f (x.map g) H = pmap (fun a h ↦ f (g a) h) x fun a h ↦ H _ (mem_map_of_mem _ h) := by + pmap f (x.map g) H = pmap (fun a h ↦ f (g a) h) x fun _ h ↦ H _ (mem_map_of_mem _ h) := by cases x <;> simp only [map_none', map_some', pmap] theorem map_pmap (g : β → γ) (f : ∀ a, p a → β) (x H) : @@ -164,7 +164,7 @@ theorem pmap_eq_map (p : α → Prop) (f : α → β) (x H) : theorem pmap_bind {α β γ} {x : Option α} {g : α → Option β} {p : β → Prop} {f : ∀ b, p b → γ} (H) (H' : ∀ (a : α), ∀ b ∈ g a, b ∈ x >>= g) : - pmap f (x >>= g) H = x >>= fun a ↦ pmap f (g a) fun b h ↦ H _ (H' a _ h) := by + pmap f (x >>= g) H = x >>= fun a ↦ pmap f (g a) fun _ h ↦ H _ (H' a _ h) := by cases x <;> simp only [pmap, bind_eq_bind, none_bind, some_bind] theorem bind_pmap {α β γ} {p : α → Prop} (f : ∀ a, p a → β) (x : Option α) (g : β → Option γ) (H) : @@ -233,8 +233,8 @@ theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u theorem liftOrGet_choice {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b = b) : ∀ o₁ o₂, liftOrGet f o₁ o₂ = o₁ ∨ liftOrGet f o₁ o₂ = o₂ | none, none => Or.inl rfl - | some a, none => Or.inl rfl - | none, some b => Or.inr rfl + | some _, none => Or.inl rfl + | none, some _ => Or.inr rfl | some a, some b => by simpa [liftOrGet] using h a b /-- Given an element of `a : Option α`, a default element `b : β` and a function `α → β`, apply this diff --git a/Mathlib/Data/Option/Defs.lean b/Mathlib/Data/Option/Defs.lean index c15bedf853135..d4e660aac7a68 100644 --- a/Mathlib/Data/Option/Defs.lean +++ b/Mathlib/Data/Option/Defs.lean @@ -59,7 +59,7 @@ instance decidableForallMem {p : α → Prop} [DecidablePred p] : ∀ o : Option α, Decidable (∀ a ∈ o, p a) | none => isTrue (by simp [false_imp_iff]) | some a => - if h : p a then isTrue fun o e ↦ some_inj.1 e ▸ h + if h : p a then isTrue fun _ e ↦ some_inj.1 e ▸ h else isFalse <| mt (fun H ↦ H _ rfl) h instance decidableExistsMem {p : α → Prop} [DecidablePred p] : diff --git a/Mathlib/Data/Option/NAry.lean b/Mathlib/Data/Option/NAry.lean index 855ae63c32d0a..b6ee71344701b 100644 --- a/Mathlib/Data/Option/NAry.lean +++ b/Mathlib/Data/Option/NAry.lean @@ -45,7 +45,7 @@ theorem map₂_def {α β γ : Type u} (f : α → β → γ) (a : Option α) (b map₂ f a b = f <$> a <*> b := by cases a <;> rfl --- Porting note (#10618): In Lean3, was `@[simp]` but now `simp` can prove it +@[simp] theorem map₂_some_some (f : α → β → γ) (a : α) (b : β) : map₂ f (some a) (some b) = f a b := rfl theorem map₂_coe_coe (f : α → β → γ) (a : α) (b : β) : map₂ f a b = f a b := rfl diff --git a/Mathlib/Data/Ordmap/Ordset.lean b/Mathlib/Data/Ordmap/Ordset.lean index 06b25c58fc953..290b42a70f8e6 100644 --- a/Mathlib/Data/Ordmap/Ordset.lean +++ b/Mathlib/Data/Ordmap/Ordset.lean @@ -459,7 +459,7 @@ theorem all_balance' {P l x r} : @All α P (balance' l x r) ↔ All P l ∧ P x theorem foldr_cons_eq_toList : ∀ (t : Ordnode α) (r : List α), t.foldr List.cons r = toList t ++ r - | nil, r => rfl + | nil, _ => rfl | node _ l x r, r' => by rw [foldr, foldr_cons_eq_toList l, foldr_cons_eq_toList r, ← List.cons_append, ← List.append_assoc, ← foldr_cons_eq_toList l]; rfl @@ -513,7 +513,7 @@ theorem findMax_dual (t : Ordnode α) : findMax (dual t) = findMin t := by theorem dual_eraseMin : ∀ t : Ordnode α, dual (eraseMin t) = eraseMax (dual t) | nil => rfl - | node _ nil x r => rfl + | node _ nil _ _ => rfl | node _ (node sz l' y r') x r => by rw [eraseMin, dual_balanceR, dual_eraseMin (node sz l' y r'), dual, dual, dual, eraseMax] @@ -522,20 +522,20 @@ theorem dual_eraseMax (t : Ordnode α) : dual (eraseMax t) = eraseMin (dual t) : theorem splitMin_eq : ∀ (s l) (x : α) (r), splitMin' l x r = (findMin' l x, eraseMin (node s l x r)) - | _, nil, x, r => rfl + | _, nil, _, _ => rfl | _, node ls ll lx lr, x, r => by rw [splitMin', splitMin_eq ls ll lx lr, findMin', eraseMin] theorem splitMax_eq : ∀ (s l) (x : α) (r), splitMax' l x r = (eraseMax (node s l x r), findMax' x r) - | _, l, x, nil => rfl + | _, _, _, nil => rfl | _, l, x, node ls ll lx lr => by rw [splitMax', splitMax_eq ls ll lx lr, findMax', eraseMax] --- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type +@[elab_as_elim] theorem findMin'_all {P : α → Prop} : ∀ (t) (x : α), All P t → P x → P (findMin' t x) | nil, _x, _, hx => hx | node _ ll lx _, _, ⟨h₁, h₂, _⟩, _ => findMin'_all ll lx h₁ h₂ --- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type +@[elab_as_elim] theorem findMax'_all {P : α → Prop} : ∀ (x : α) (t), P x → All P t → P (findMax' x t) | _x, nil, hx, _ => hx | _, node _ _ lx lr, _, ⟨_, h₂, h₃⟩ => findMax'_all lx lr h₂ h₃ @@ -793,7 +793,7 @@ def Bounded : Ordnode α → WithBot α → WithTop α → Prop theorem Bounded.dual : ∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → @Bounded αᵒᵈ _ (dual t) o₂ o₁ | nil, o₁, o₂, h => by cases o₁ <;> cases o₂ <;> trivial - | node _ l x r, _, _, ⟨ol, Or⟩ => ⟨Or.dual, ol.dual⟩ + | node _ _ _ _, _, _, ⟨ol, Or⟩ => ⟨Or.dual, ol.dual⟩ theorem Bounded.dual_iff {t : Ordnode α} {o₁ o₂} : Bounded t o₁ o₂ ↔ @Bounded αᵒᵈ _ (.dual t) o₂ o₁ := @@ -802,11 +802,11 @@ theorem Bounded.dual_iff {t : Ordnode α} {o₁ o₂} : theorem Bounded.weak_left : ∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → Bounded t ⊥ o₂ | nil, o₁, o₂, h => by cases o₂ <;> trivial - | node _ l x r, _, _, ⟨ol, Or⟩ => ⟨ol.weak_left, Or⟩ + | node _ _ _ _, _, _, ⟨ol, Or⟩ => ⟨ol.weak_left, Or⟩ theorem Bounded.weak_right : ∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → Bounded t o₁ ⊤ | nil, o₁, o₂, h => by cases o₁ <;> trivial - | node _ l x r, _, _, ⟨ol, Or⟩ => ⟨ol, Or.weak_right⟩ + | node _ _ _ _, _, _, ⟨ol, Or⟩ => ⟨ol, Or.weak_right⟩ theorem Bounded.weak {t : Ordnode α} {o₁ o₂} (h : Bounded t o₁ o₂) : Bounded t ⊥ ⊤ := h.weak_left.weak_right @@ -929,8 +929,8 @@ theorem Valid'.node {s l} {x : α} {r o₁ o₂} (hl : Valid' o₁ l x) (hr : Va ⟨⟨hl.1, hr.1⟩, ⟨hs, hl.2, hr.2⟩, ⟨H, hl.3, hr.3⟩⟩ theorem Valid'.dual : ∀ {t : Ordnode α} {o₁ o₂}, Valid' o₁ t o₂ → @Valid' αᵒᵈ _ o₂ (dual t) o₁ - | .nil, o₁, o₂, h => valid'_nil h.1.dual - | .node _ l x r, o₁, o₂, ⟨⟨ol, Or⟩, ⟨rfl, sl, sr⟩, ⟨b, bl, br⟩⟩ => + | .nil, _, _, h => valid'_nil h.1.dual + | .node _ l _ r, _, _, ⟨⟨ol, Or⟩, ⟨rfl, sl, sr⟩, ⟨b, bl, br⟩⟩ => let ⟨ol', sl', bl'⟩ := Valid'.dual ⟨ol, sl, bl⟩ let ⟨or', sr', br'⟩ := Valid'.dual ⟨Or, sr, br⟩ ⟨⟨or', ol'⟩, ⟨by simp [size_dual, add_comm], sr', sl'⟩, @@ -1111,7 +1111,7 @@ theorem Valid'.rotateL {l} {x : α} {r o₁ o₂} (hl : Valid' o₁ l x) (hr : V · rcases Nat.eq_zero_or_pos (size rl) with rl0 | rl0 · rw [rl0, not_lt, Nat.le_zero, Nat.mul_eq_zero] at h replace h := h.resolve_left (by decide) - erw [rl0, h, Nat.le_zero, Nat.mul_eq_zero] at H2 + rw [rl0, h, Nat.le_zero, Nat.mul_eq_zero] at H2 rw [hr.2.size_eq, rl0, h, H2.resolve_left (by decide)] at H1 cases H1 (by decide) refine hl.node4L hr.left hr.right rl0 ?_ @@ -1324,7 +1324,7 @@ theorem insertWith.valid_aux [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ Bounded nil o₁ x → Bounded nil x o₂ → Valid' o₁ (insertWith f x t) o₂ ∧ Raised (size t) (size (insertWith f x t)) - | nil, o₁, o₂, _, bl, br => ⟨valid'_singleton bl br, Or.inr rfl⟩ + | nil, _, _, _, bl, br => ⟨valid'_singleton bl br, Or.inr rfl⟩ | node sz l y r, o₁, o₂, h, bl, br => by rw [insertWith, cmpLE] split_ifs with h_1 h_2 <;> dsimp only diff --git a/Mathlib/Data/PEquiv.lean b/Mathlib/Data/PEquiv.lean index 920084d283b41..28b8f8af64e9b 100644 --- a/Mathlib/Data/PEquiv.lean +++ b/Mathlib/Data/PEquiv.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Data.Option.Basic -import Mathlib.Data.Set.Basic import Batteries.Tactic.Congr +import Mathlib.Data.Set.Basic +import Mathlib.Tactic.Contrapose /-! @@ -362,7 +363,7 @@ section Order instance instPartialOrderPEquiv : PartialOrder (α ≃. β) where le f g := ∀ (a : α) (b : β), b ∈ f a → b ∈ g a le_refl _ _ _ := id - le_trans f g h fg gh a b := gh a b ∘ fg a b + le_trans _ _ _ fg gh a b := gh a b ∘ fg a b le_antisymm f g fg gf := ext (by diff --git a/Mathlib/Data/PFun.lean b/Mathlib/Data/PFun.lean index 376018c747f3e..3c24f0c13cc70 100644 --- a/Mathlib/Data/PFun.lean +++ b/Mathlib/Data/PFun.lean @@ -109,8 +109,8 @@ def asSubtype (f : α →. β) (s : f.Dom) : β := /-- The type of partial functions `α →. β` is equivalent to the type of pairs `(p : α → Prop, f : Subtype p → β)`. -/ def equivSubtype : (α →. β) ≃ Σp : α → Prop, Subtype p → β := - ⟨fun f => ⟨fun a => (f a).Dom, asSubtype f⟩, fun f x => ⟨f.1 x, fun h => f.2 ⟨x, h⟩⟩, fun f => - funext fun a => Part.eta _, fun ⟨p, f⟩ => by dsimp; congr⟩ + ⟨fun f => ⟨fun a => (f a).Dom, asSubtype f⟩, fun f x => ⟨f.1 x, fun h => f.2 ⟨x, h⟩⟩, fun _ => + funext fun _ => Part.eta _, fun ⟨p, f⟩ => by dsimp; congr⟩ theorem asSubtype_eq_of_mem {f : α →. β} {x : α} {y : β} (fxy : y ∈ f x) (domx : x ∈ f.Dom) : f.asSubtype ⟨x, domx⟩ = y := @@ -191,9 +191,9 @@ instance monad : Monad (PFun α) where map := PFun.map instance lawfulMonad : LawfulMonad (PFun α) := LawfulMonad.mk' - (bind_pure_comp := fun f x => funext fun a => Part.bind_some_eq_map _ _) + (bind_pure_comp := fun _ _ => funext fun _ => Part.bind_some_eq_map _ _) (id_map := fun f => by funext a; dsimp [Functor.map, PFun.map]; cases f a; rfl) - (pure_bind := fun x f => funext fun a => Part.bind_some _ (f x)) + (pure_bind := fun x f => funext fun _ => Part.bind_some _ (f x)) (bind_assoc := fun f g k => funext fun a => (f a).bind_assoc (fun b => g b a) fun b => k b a) theorem pure_defined (p : Set α) (x : β) : p ⊆ (@PFun.pure α _ x).Dom := @@ -292,7 +292,7 @@ def fixInduction {C : α → Sort*} {f : α →. β ⊕ α} {b : β} {a : α} (h theorem fixInduction_spec {C : α → Sort*} {f : α →. β ⊕ α} {b : β} {a : α} (h : b ∈ f.fix a) (H : ∀ a', b ∈ f.fix a' → (∀ a'', Sum.inr a'' ∈ f a' → C a'') → C a') : - @fixInduction _ _ C _ _ _ h H = H a h fun a' h' => fixInduction (fix_fwd h h') H := by + @fixInduction _ _ C _ _ _ h H = H a h fun _ h' => fixInduction (fix_fwd h h') H := by unfold fixInduction generalize_proofs induction ‹Acc _ _› diff --git a/Mathlib/Data/PFunctor/Univariate/M.lean b/Mathlib/Data/PFunctor/Univariate/M.lean index 73fe251a4dda5..58879cd06c136 100644 --- a/Mathlib/Data/PFunctor/Univariate/M.lean +++ b/Mathlib/Data/PFunctor/Univariate/M.lean @@ -92,7 +92,7 @@ theorem truncate_eq_of_agree {n : ℕ} (x : CofixA F n) (y : CofixA F (succ n)) · -- cases' h with _ _ _ _ _ h₀ h₁ cases h simp only [truncate, Function.comp_def, eq_self_iff_true, heq_iff_eq] - -- Porting note: used to be `ext y` + -- Porting note (#11041): used to be `ext y` rename_i n_ih a f y h₁ suffices (fun x => truncate (y x)) = f by simp [this] diff --git a/Mathlib/Data/PNat/Basic.lean b/Mathlib/Data/PNat/Basic.lean index d1fcce241c69f..f81e93cd63db2 100644 --- a/Mathlib/Data/PNat/Basic.lean +++ b/Mathlib/Data/PNat/Basic.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Ralf Stephan, Neil Strickland, Ruben Van de Velde -/ import Mathlib.Data.PNat.Equiv import Mathlib.Algebra.Order.Ring.Nat -import Mathlib.Data.Set.Basic import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Order.Positive.Ring import Mathlib.Order.Hom.Basic @@ -117,17 +116,17 @@ def coeAddHom : AddHom ℕ+ ℕ where toFun := Coe.coe map_add' := add_coe -instance covariantClass_add_le : CovariantClass ℕ+ ℕ+ (· + ·) (· ≤ ·) := - Positive.covariantClass_add_le +instance addLeftMono : AddLeftMono ℕ+ := + Positive.addLeftMono -instance covariantClass_add_lt : CovariantClass ℕ+ ℕ+ (· + ·) (· < ·) := - Positive.covariantClass_add_lt +instance addLeftStrictMono : AddLeftStrictMono ℕ+ := + Positive.addLeftStrictMono -instance contravariantClass_add_le : ContravariantClass ℕ+ ℕ+ (· + ·) (· ≤ ·) := - Positive.contravariantClass_add_le +instance addLeftReflectLE : AddLeftReflectLE ℕ+ := + Positive.addLeftReflectLE -instance contravariantClass_add_lt : ContravariantClass ℕ+ ℕ+ (· + ·) (· < ·) := - Positive.contravariantClass_add_lt +instance addLeftReflectLT : AddLeftReflectLT ℕ+ := + Positive.addLeftReflectLT /-- The order isomorphism between ℕ and ℕ+ given by `succ`. -/ @[simps! (config := .asFn) apply] @@ -273,11 +272,11 @@ theorem exists_eq_succ_of_ne_one : ∀ {n : ℕ+} (_ : n ≠ 1), ∃ k : ℕ+, n theorem modDivAux_spec : ∀ (k : ℕ+) (r q : ℕ) (_ : ¬(r = 0 ∧ q = 0)), ((modDivAux k r q).1 : ℕ) + k * (modDivAux k r q).2 = r + k * q - | k, 0, 0, h => (h ⟨rfl, rfl⟩).elim + | _, 0, 0, h => (h ⟨rfl, rfl⟩).elim | k, 0, q + 1, _ => by change (k : ℕ) + (k : ℕ) * (q + 1).pred = 0 + (k : ℕ) * (q + 1) rw [Nat.pred_succ, Nat.mul_succ, zero_add, add_comm] - | k, r + 1, q, _ => rfl + | _, _ + 1, _, _ => rfl theorem mod_add_div (m k : ℕ+) : (mod m k + k * div m k : ℕ) = m := by let h₀ := Nat.mod_add_div (m : ℕ) (k : ℕ) diff --git a/Mathlib/Data/PNat/Factors.lean b/Mathlib/Data/PNat/Factors.lean index 103a0f6a9d279..2a2367c5bbc13 100644 --- a/Mathlib/Data/PNat/Factors.lean +++ b/Mathlib/Data/PNat/Factors.lean @@ -224,7 +224,6 @@ theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := b rcases v with ⟨l⟩ --unfold_coes dsimp [PrimeMultiset.toNatMultiset] - rw [Multiset.prod_coe] let l' := l.map (Coe.coe : Nat.Primes → ℕ) have : ∀ p : ℕ, p ∈ l' → p.Prime := fun p hp => by rcases List.mem_map.mp hp with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩ diff --git a/Mathlib/Data/PNat/Interval.lean b/Mathlib/Data/PNat/Interval.lean index 4a310ffe979ce..c4b3b23d18a7e 100644 --- a/Mathlib/Data/PNat/Interval.lean +++ b/Mathlib/Data/PNat/Interval.lean @@ -52,39 +52,23 @@ theorem map_subtype_embedding_uIcc : (uIcc a b).map (Embedding.subtype _) = uIcc map_subtype_embedding_Icc _ _ @[simp] -theorem card_Icc : (Icc a b).card = b + 1 - a := by - rw [← Nat.card_Icc] - -- Porting note: I had to change this to `erw` *and* provide the proof, yuck. - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [← Finset.map_subtype_embedding_Icc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)] - rw [card_map] +theorem card_Icc : #(Icc a b) = b + 1 - a := by + rw [← Nat.card_Icc, ← map_subtype_embedding_Icc, card_map] @[simp] -theorem card_Ico : (Ico a b).card = b - a := by - rw [← Nat.card_Ico] - -- Porting note: I had to change this to `erw` *and* provide the proof, yuck. - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [← Finset.map_subtype_embedding_Ico _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)] - rw [card_map] +theorem card_Ico : #(Ico a b) = b - a := by + rw [← Nat.card_Ico, ← map_subtype_embedding_Ico, card_map] @[simp] -theorem card_Ioc : (Ioc a b).card = b - a := by - rw [← Nat.card_Ioc] - -- Porting note: I had to change this to `erw` *and* provide the proof, yuck. - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [← Finset.map_subtype_embedding_Ioc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)] - rw [card_map] +theorem card_Ioc : #(Ioc a b) = b - a := by + rw [← Nat.card_Ioc, ← map_subtype_embedding_Ioc, card_map] @[simp] -theorem card_Ioo : (Ioo a b).card = b - a - 1 := by - rw [← Nat.card_Ioo] - -- Porting note: I had to change this to `erw` *and* provide the proof, yuck. - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [← Finset.map_subtype_embedding_Ioo _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)] - rw [card_map] +theorem card_Ioo : #(Ioo a b) = b - a - 1 := by + rw [← Nat.card_Ioo, ← map_subtype_embedding_Ioo, card_map] @[simp] -theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := by +theorem card_uIcc : #(uIcc a b) = (b - a : ℤ).natAbs + 1 := by rw [← Nat.card_uIcc, ← map_subtype_embedding_uIcc, card_map] -- Porting note: `simpNF` says `simp` can prove this diff --git a/Mathlib/Data/PSigma/Order.lean b/Mathlib/Data/PSigma/Order.lean index fe0d6b8051e5b..c4337051e8a85 100644 --- a/Mathlib/Data/PSigma/Order.lean +++ b/Mathlib/Data/PSigma/Order.lean @@ -51,7 +51,7 @@ instance lt [LT ι] [∀ i, LT (α i)] : LT (Σₗ' i, α i) := instance preorder [Preorder ι] [∀ i, Preorder (α i)] : Preorder (Σₗ' i, α i) := { Lex.le, Lex.lt with - le_refl := fun ⟨i, a⟩ => Lex.right _ le_rfl, + le_refl := fun ⟨_, _⟩ => Lex.right _ le_rfl, le_trans := by rintro ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ ⟨a₃, b₃⟩ ⟨h₁r⟩ ⟨h₂r⟩ · left diff --git a/Mathlib/Data/Part.lean b/Mathlib/Data/Part.lean index c4903f9bf5b4a..58395794466e5 100644 --- a/Mathlib/Data/Part.lean +++ b/Mathlib/Data/Part.lean @@ -330,9 +330,9 @@ noncomputable def equivOption : Part α ≃ Option α := instance : PartialOrder (Part α) where le x y := ∀ i, i ∈ x → i ∈ y - le_refl x y := id - le_trans x y z f g i := g _ ∘ f _ - le_antisymm x y f g := Part.ext fun z => ⟨f _, g _⟩ + le_refl _ _ := id + le_trans _ _ _ f g _ := g _ ∘ f _ + le_antisymm _ _ f g := Part.ext fun _ => ⟨f _, g _⟩ instance : OrderBot (Part α) where bot := none diff --git a/Mathlib/Data/Pi/Interval.lean b/Mathlib/Data/Pi/Interval.lean index c3f501c51ef40..4db37234636e6 100644 --- a/Mathlib/Data/Pi/Interval.lean +++ b/Mathlib/Data/Pi/Interval.lean @@ -34,16 +34,16 @@ variable (a b : ∀ i, α i) theorem Icc_eq : Icc a b = piFinset fun i => Icc (a i) (b i) := rfl -theorem card_Icc : (Icc a b).card = ∏ i, (Icc (a i) (b i)).card := +theorem card_Icc : #(Icc a b) = ∏ i, #(Icc (a i) (b i)) := card_piFinset _ -theorem card_Ico : (Ico a b).card = (∏ i, (Icc (a i) (b i)).card) - 1 := by +theorem card_Ico : #(Ico a b) = ∏ i, #(Icc (a i) (b i)) - 1 := by rw [card_Ico_eq_card_Icc_sub_one, card_Icc] -theorem card_Ioc : (Ioc a b).card = (∏ i, (Icc (a i) (b i)).card) - 1 := by +theorem card_Ioc : #(Ioc a b) = ∏ i, #(Icc (a i) (b i)) - 1 := by rw [card_Ioc_eq_card_Icc_sub_one, card_Icc] -theorem card_Ioo : (Ioo a b).card = (∏ i, (Icc (a i) (b i)).card) - 2 := by +theorem card_Ioo : #(Ioo a b) = ∏ i, #(Icc (a i) (b i)) - 2 := by rw [card_Ioo_eq_card_Icc_sub_two, card_Icc] end LocallyFiniteOrder @@ -55,11 +55,8 @@ instance instLocallyFiniteOrderBot : LocallyFiniteOrderBot (∀ i, α i) := .ofIic _ (fun b => piFinset fun i => Iic (b i)) fun b x => by simp_rw [mem_piFinset, mem_Iic, le_def] -theorem card_Iic : (Iic b).card = ∏ i, (Iic (b i)).card := - card_piFinset _ - -theorem card_Iio : (Iio b).card = (∏ i, (Iic (b i)).card) - 1 := by - rw [card_Iio_eq_card_Iic_sub_one, card_Iic] +lemma card_Iic : #(Iic b) = ∏ i, #(Iic (b i)) := card_piFinset _ +lemma card_Iio : #(Iio b) = ∏ i, #(Iic (b i)) - 1 := by rw [card_Iio_eq_card_Iic_sub_one, card_Iic] end LocallyFiniteOrderBot @@ -70,11 +67,8 @@ instance instLocallyFiniteOrderTop : LocallyFiniteOrderTop (∀ i, α i) := LocallyFiniteOrderTop.ofIci _ (fun a => piFinset fun i => Ici (a i)) fun a x => by simp_rw [mem_piFinset, mem_Ici, le_def] -theorem card_Ici : (Ici a).card = ∏ i, (Ici (a i)).card := - card_piFinset _ - -theorem card_Ioi : (Ioi a).card = (∏ i, (Ici (a i)).card) - 1 := by - rw [card_Ioi_eq_card_Ici_sub_one, card_Ici] +lemma card_Ici : #(Ici a) = ∏ i, #(Ici (a i)) := card_piFinset _ +lemma card_Ioi : #(Ioi a) = ∏ i, #(Ici (a i)) - 1 := by rw [card_Ioi_eq_card_Ici_sub_one, card_Ici] end LocallyFiniteOrderTop end PartialOrder @@ -84,7 +78,7 @@ variable [∀ i, Lattice (α i)] [∀ i, LocallyFiniteOrder (α i)] (a b : ∀ i theorem uIcc_eq : uIcc a b = piFinset fun i => uIcc (a i) (b i) := rfl -theorem card_uIcc : (uIcc a b).card = ∏ i, (uIcc (a i) (b i)).card := card_Icc _ _ +theorem card_uIcc : #(uIcc a b) = ∏ i, #(uIcc (a i) (b i)) := card_Icc _ _ end Lattice end Pi diff --git a/Mathlib/Data/Prod/Basic.lean b/Mathlib/Data/Prod/Basic.lean index 125f987461805..2fbd64bdcf181 100644 --- a/Mathlib/Data/Prod/Basic.lean +++ b/Mathlib/Data/Prod/Basic.lean @@ -42,25 +42,20 @@ theorem snd_comp_mk (x : α) : Prod.snd ∘ (Prod.mk x : β → α × β) = id : theorem fst_comp_mk (x : α) : Prod.fst ∘ (Prod.mk x : β → α × β) = Function.const β x := rfl -@[simp, mfld_simps] -theorem map_mk (f : α → γ) (g : β → δ) (a : α) (b : β) : map f g (a, b) = (f a, g b) := - rfl +@[deprecated (since := "2024-10-17")] alias map_mk := map_apply + +attribute [mfld_simps] map_apply -- This was previously a `simp` lemma, but no longer is on the basis that it destructures the pair. -- See `map_apply`, `map_fst`, and `map_snd` for slightly weaker lemmas in the `simp` set. theorem map_apply' (f : α → γ) (g : β → δ) (p : α × β) : map f g p = (f p.1, g p.2) := rfl -#adaptation_note -/-- -After `nightly-2024-06-23`, the explicitness of `map_fst` and `map_snd` will be fixed and we can -change this back to `funext <| map_fst f g`. Also in `map_snd'` below. --/ theorem map_fst' (f : α → γ) (g : β → δ) : Prod.fst ∘ map f g = f ∘ Prod.fst := - funext <| @map_fst (f := f) (g := g) + funext <| map_fst f g theorem map_snd' (f : α → γ) (g : β → δ) : Prod.snd ∘ map f g = g ∘ Prod.snd := - funext <| @map_snd (f := f) (g := g) + funext <| map_snd f g /-- Composing a `Prod.map` with another `Prod.map` is equal to a single `Prod.map` of composed functions. diff --git a/Mathlib/Data/Prod/Lex.lean b/Mathlib/Data/Prod/Lex.lean index f8116316921ee..b0271fecee021 100644 --- a/Mathlib/Data/Prod/Lex.lean +++ b/Mathlib/Data/Prod/Lex.lean @@ -29,17 +29,13 @@ Related files are: -/ -variable {α β γ : Type*} +variable {α β : Type*} namespace Prod.Lex -@[inherit_doc] notation:35 α " ×ₗ " β:34 => Lex (Prod α β) - -instance decidableEq (α β : Type*) [DecidableEq α] [DecidableEq β] : DecidableEq (α ×ₗ β) := - instDecidableEqProd +open Batteries -instance inhabited (α β : Type*) [Inhabited α] [Inhabited β] : Inhabited (α ×ₗ β) := - instInhabitedProd +@[inherit_doc] notation:35 α " ×ₗ " β:34 => Lex (Prod α β) /-- Dictionary / lexicographic ordering on pairs. -/ instance instLE (α β : Type*) [LT α] [LE β] : LE (α ×ₗ β) where le := Prod.Lex (· < ·) (· ≤ ·) @@ -124,16 +120,36 @@ instance partialOrder (α β : Type*) [PartialOrder α] [PartialOrder β] : Part haveI : IsAntisymm β (· ≤ ·) := ⟨fun _ _ => le_antisymm⟩ exact antisymm (r := Prod.Lex _ _) +instance instOrdLexProd [Ord α] [Ord β] : Ord (α ×ₗ β) := lexOrd + +theorem compare_def [Ord α] [Ord β] : @compare (α ×ₗ β) _ = + compareLex (compareOn fun x => (ofLex x).1) (compareOn fun x => (ofLex x).2) := rfl + +theorem _root_.lexOrd_eq [Ord α] [Ord β] : @lexOrd α β _ _ = instOrdLexProd := rfl + +theorem _root_.Ord.lex_eq [oα : Ord α] [oβ : Ord β] : Ord.lex oα oβ = instOrdLexProd := rfl + +instance [Ord α] [Ord β] [OrientedOrd α] [OrientedOrd β] : OrientedOrd (α ×ₗ β) := + inferInstanceAs (OrientedCmp (compareLex _ _)) + +instance [Ord α] [Ord β] [TransOrd α] [TransOrd β] : TransOrd (α ×ₗ β) := + inferInstanceAs (TransCmp (compareLex _ _)) + /-- Dictionary / lexicographic linear order for pairs. -/ instance linearOrder (α β : Type*) [LinearOrder α] [LinearOrder β] : LinearOrder (α ×ₗ β) := { Prod.Lex.partialOrder α β with - le_total := total_of (Prod.Lex _ _), - decidableLE := Prod.Lex.decidable _ _, - decidableLT := Prod.Lex.decidable _ _, - decidableEq := Lex.decidableEq _ _, } - -instance [Ord α] [Ord β] : Ord (α ×ₗ β) where - compare := compareLex (compareOn (·.1)) (compareOn (·.2)) + le_total := total_of (Prod.Lex _ _) + decidableLE := Prod.Lex.decidable _ _ + decidableLT := Prod.Lex.decidable _ _ + decidableEq := instDecidableEqLex _ + compare_eq_compareOfLessAndEq := fun a b => by + have : DecidableRel (· < · : α ×ₗ β → α ×ₗ β → Prop) := Prod.Lex.decidable _ _ + have : BEqOrd (α ×ₗ β) := ⟨by + simp [compare_def, compareLex, compareOn, Ordering.then_eq_eq, compare_eq_iff_eq]⟩ + have : LTOrd (α ×ₗ β) := ⟨by + simp [compare_def, compareLex, compareOn, Ordering.then_eq_lt, lt_iff, + compare_lt_iff_lt, compare_eq_iff_eq]⟩ + convert LTCmp.eq_compareOfLessAndEq (cmp := compare) a b } instance orderBot [PartialOrder α] [Preorder β] [OrderBot α] [OrderBot β] : OrderBot (α ×ₗ β) where bot := toLex ⊥ diff --git a/Mathlib/Data/QPF/Multivariate/Constructions/Comp.lean b/Mathlib/Data/QPF/Multivariate/Constructions/Comp.lean index 59234b2be7b7e..c8681c4243c48 100644 --- a/Mathlib/Data/QPF/Multivariate/Constructions/Comp.lean +++ b/Mathlib/Data/QPF/Multivariate/Constructions/Comp.lean @@ -69,7 +69,7 @@ end instance [MvQPF F] [∀ i, MvQPF <| G i] : MvQPF (Comp F G) where P := MvPFunctor.comp (P F) fun i ↦ P <| G i - abs := Comp.mk ∘ (map fun i ↦ abs) ∘ abs ∘ MvPFunctor.comp.get + abs := Comp.mk ∘ (map fun _ ↦ abs) ∘ abs ∘ MvPFunctor.comp.get repr {α} := MvPFunctor.comp.mk ∘ repr ∘ (map fun i ↦ (repr : G i α → (fun i : Fin2 n ↦ Obj (P (G i)) α) i)) ∘ Comp.get abs_repr := by diff --git a/Mathlib/Data/QPF/Univariate/Basic.lean b/Mathlib/Data/QPF/Univariate/Basic.lean index b767d995bd81b..0111a3ccaf83e 100644 --- a/Mathlib/Data/QPF/Univariate/Basic.lean +++ b/Mathlib/Data/QPF/Univariate/Basic.lean @@ -512,8 +512,8 @@ elements `x y : F α` are in the same equivalence class if def quotientQPF (FG_abs_repr : ∀ {α} (x : G α), FG_abs (FG_repr x) = x) (FG_abs_map : ∀ {α β} (f : α → β) (x : F α), FG_abs (f <$> x) = f <$> FG_abs x) : QPF G where P := q.P - abs {α} p := FG_abs (abs p) - repr {α} x := repr (FG_repr x) + abs {_} p := FG_abs (abs p) + repr {_} x := repr (FG_repr x) abs_repr {α} x := by simp only; rw [abs_repr, FG_abs_repr] abs_map {α β} f x := by simp only; rw [abs_map, FG_abs_map] diff --git a/Mathlib/Data/Quot.lean b/Mathlib/Data/Quot.lean index 6af294f0b9665..b9ff59544232d 100644 --- a/Mathlib/Data/Quot.lean +++ b/Mathlib/Data/Quot.lean @@ -9,8 +9,11 @@ import Mathlib.Util.Notation3 /-! # Quotient types + This module extends the core library's treatment of quotient types (`Init.Core`). + ## Tags + quotient -/ @@ -18,8 +21,17 @@ variable {α : Sort*} {β : Sort*} namespace Setoid -theorem ext {α : Sort*} : ∀ {s t : Setoid α}, - (∀ a b, @Setoid.r α s a b ↔ @Setoid.r α t a b) → s = t +-- Pretty print `@Setoid.r _ s a b` as `s a b`. +run_cmd Lean.Elab.Command.liftTermElabM do + Lean.Meta.registerCoercion ``Setoid.r + (some { numArgs := 2, coercee := 1, type := .coeFun }) + +/-- When writing a lemma about `someSetoid x y` (which uses this instance), +call it `someSetoid_apply` not `someSetoid_r`. -/ +instance : CoeFun (Setoid α) (fun _ ↦ α → α → Prop) where + coe := @Setoid.r _ + +theorem ext {α : Sort*} : ∀ {s t : Setoid α}, (∀ a b, s a b ↔ t a b) → s = t | ⟨r, _⟩, ⟨p, _⟩, Eq => by have : r = p := funext fun a ↦ funext fun b ↦ propext <| Eq a b subst this @@ -56,7 +68,7 @@ protected def hrecOn₂ (qa : Quot ra) (qb : Quot rb) (f : ∀ a b, φ ⟦a⟧ (cb : ∀ {a b₁ b₂}, rb b₁ b₂ → HEq (f a b₁) (f a b₂)) : φ qa qb := Quot.hrecOn (motive := fun qa ↦ φ qa qb) qa - (fun a ↦ Quot.hrecOn qb (f a) (fun b₁ b₂ pb ↦ cb pb)) + (fun a ↦ Quot.hrecOn qb (f a) (fun _ _ pb ↦ cb pb)) fun a₁ a₂ pa ↦ Quot.induction_on qb fun b ↦ have h₁ : HEq (@Quot.hrecOn _ _ (φ _) ⟦b⟧ (f a₁) (@cb _)) (f a₁ b) := by @@ -99,8 +111,6 @@ theorem liftOn_mk (a : α) (f : α → γ) (h : ∀ a₁ a₂, r a₁ a₂ → f ⟨fun hf => hf.comp Quot.exists_rep, fun hf y => let ⟨x, hx⟩ := hf y; ⟨Quot.mk _ x, hx⟩⟩ /-- Descends a function `f : α → β → γ` to quotients of `α` and `β`. -/ --- Porting note: removed `@[elab_as_elim]`, gave "unexpected resulting type γ" --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` protected def lift₂ (f : α → β → γ) (hr : ∀ a b₁ b₂, s b₁ b₂ → f a b₁ = f a b₂) (hs : ∀ a₁ a₂ b, r a₁ a₂ → f a₁ b = f a₂ b) (q₁ : Quot r) (q₂ : Quot s) : γ := Quot.lift (fun a ↦ Quot.lift (f a) (hr a)) @@ -113,8 +123,6 @@ theorem lift₂_mk (f : α → β → γ) (hr : ∀ a b₁ b₂, s b₁ b₂ → rfl /-- Descends a function `f : α → β → γ` to quotients of `α` and `β` and applies it. -/ --- porting note (#11083): removed `@[elab_as_elim]`, gave "unexpected resulting type γ" --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` protected def liftOn₂ (p : Quot r) (q : Quot s) (f : α → β → γ) (hr : ∀ a b₁ b₂, s b₁ b₂ → f a b₁ = f a b₂) (hs : ∀ a₁ a₂ b, r a₁ a₂ → f a₁ b = f a₂ b) : γ := Quot.lift₂ f hr hs p q @@ -141,7 +149,6 @@ theorem map₂_mk (f : α → β → γ) (hr : ∀ a b₁ b₂, s b₁ b₂ → rfl /-- A binary version of `Quot.recOnSubsingleton`. -/ --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` @[elab_as_elim] protected def recOnSubsingleton₂ {φ : Quot r → Quot s → Sort*} [h : ∀ a b, Subsingleton (φ ⟦a⟧ ⟦b⟧)] (q₁ : Quot r) @@ -189,7 +196,7 @@ end Quot namespace Quotient -variable [sa : Setoid α] [sb : Setoid β] +variable {sa : Setoid α} {sb : Setoid β} variable {φ : Quotient sa → Quotient sb → Sort*} -- Porting note: in mathlib3 this notation took the Setoid as an instance-implicit argument, @@ -228,7 +235,7 @@ theorem map_mk (f : α → β) (h : ((· ≈ ·) ⇒ (· ≈ ·)) f f) (x : α) Quotient.map f h (⟦x⟧ : Quotient sa) = (⟦f x⟧ : Quotient sb) := rfl -variable {γ : Sort*} [sc : Setoid γ] +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`. @@ -269,9 +276,12 @@ theorem Quot.eq {α : Type*} {r : α → α → Prop} {x y : α} : ⟨Quot.eqvGen_exact, Quot.eqvGen_sound⟩ @[simp] -theorem Quotient.eq [r : Setoid α] {x y : α} : Quotient.mk r x = ⟦y⟧ ↔ x ≈ y := +theorem Quotient.eq {r : Setoid α} {x y : α} : Quotient.mk r x = ⟦y⟧ ↔ r x y := ⟨Quotient.exact, Quotient.sound⟩ +theorem Quotient.eq_iff_equiv {r : Setoid α} {x y : α} : Quotient.mk r x = ⟦y⟧ ↔ x ≈ y := + Quotient.eq + theorem Quotient.forall {α : Sort*} {s : Setoid α} {p : Quotient s → Prop} : (∀ a, p a) ↔ ∀ a : α, p ⟦a⟧ := ⟨fun h _ ↦ h _, fun h a ↦ a.ind h⟩ @@ -281,29 +291,29 @@ theorem Quotient.exists {α : Sort*} {s : Setoid α} {p : Quotient s → Prop} : ⟨fun ⟨q, hq⟩ ↦ q.ind (motive := (p · → _)) .intro hq, fun ⟨a, ha⟩ ↦ ⟨⟦a⟧, ha⟩⟩ @[simp] -theorem Quotient.lift_mk [s : Setoid α] (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) (x : α) : +theorem Quotient.lift_mk {s : Setoid α} (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) (x : α) : Quotient.lift f h (Quotient.mk s x) = f x := rfl @[simp] -theorem Quotient.lift_comp_mk [Setoid α] (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) : +theorem Quotient.lift_comp_mk {_ : Setoid α} (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) : Quotient.lift f h ∘ Quotient.mk _ = f := rfl @[simp] -theorem Quotient.lift₂_mk {α : Sort*} {β : Sort*} {γ : Sort*} [Setoid α] [Setoid β] +theorem Quotient.lift₂_mk {α : Sort*} {β : Sort*} {γ : Sort*} {_ : Setoid α} {_ : Setoid β} (f : α → β → γ) (h : ∀ (a₁ : α) (a₂ : β) (b₁ : α) (b₂ : β), a₁ ≈ b₁ → a₂ ≈ b₂ → f a₁ a₂ = f b₁ b₂) (a : α) (b : β) : Quotient.lift₂ f h (Quotient.mk _ a) (Quotient.mk _ b) = f a b := rfl -theorem Quotient.liftOn_mk [s : Setoid α] (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) (x : α) : +theorem Quotient.liftOn_mk {s : Setoid α} (f : α → β) (h : ∀ a b : α, a ≈ b → f a = f b) (x : α) : Quotient.liftOn (Quotient.mk s x) f h = f x := rfl @[simp] -theorem Quotient.liftOn₂_mk {α : Sort*} {β : Sort*} [Setoid α] (f : α → α → β) +theorem Quotient.liftOn₂_mk {α : Sort*} {β : Sort*} {_ : Setoid α} (f : α → α → β) (h : ∀ a₁ a₂ b₁ b₂ : α, a₁ ≈ b₁ → a₂ ≈ b₂ → f a₁ a₂ = f b₁ b₂) (x y : α) : Quotient.liftOn₂ (Quotient.mk _ x) (Quotient.mk _ y) f h = f x y := rfl @@ -338,22 +348,22 @@ theorem Quot.out_eq {r : α → α → Prop} (q : Quot r) : Quot.mk r q.out = q /-- Choose an element of the equivalence class using the axiom of choice. Sound but noncomputable. -/ -noncomputable def Quotient.out [s : Setoid α] : Quotient s → α := +noncomputable def Quotient.out {s : Setoid α} : Quotient s → α := Quot.out @[simp] -theorem Quotient.out_eq [s : Setoid α] (q : Quotient s) : ⟦q.out⟧ = q := +theorem Quotient.out_eq {s : Setoid α} (q : Quotient s) : ⟦q.out⟧ = q := Quot.out_eq q -theorem Quotient.mk_out [Setoid α] (a : α) : ⟦a⟧.out ≈ a := +theorem Quotient.mk_out {s : Setoid α} (a : α) : s (⟦a⟧ : Quotient s).out a := Quotient.exact (Quotient.out_eq _) -theorem Quotient.mk_eq_iff_out [s : Setoid α] {x : α} {y : Quotient s} : +theorem Quotient.mk_eq_iff_out {s : Setoid α} {x : α} {y : Quotient s} : ⟦x⟧ = y ↔ x ≈ Quotient.out y := by refine Iff.trans ?_ Quotient.eq rw [Quotient.out_eq y] -theorem Quotient.eq_mk_iff_out [s : Setoid α] {x : Quotient s} {y : α} : +theorem Quotient.eq_mk_iff_out {s : Setoid α} {x : Quotient s} {y : α} : x = ⟦y⟧ ↔ Quotient.out x ≈ y := by refine Iff.trans ?_ Quotient.eq rw [Quotient.out_eq x] @@ -379,18 +389,18 @@ instance piSetoid {ι : Sort*} {α : ι → Sort*} [∀ i, Setoid (α i)] : Seto /-- Given a function `f : Π i, Quotient (S i)`, returns the class of functions `Π i, α i` sending each `i` to an element of the class `f i`. -/ -noncomputable def Quotient.choice {ι : Type*} {α : ι → Type*} [S : ∀ i, Setoid (α i)] +noncomputable def Quotient.choice {ι : Type*} {α : ι → Type*} {S : ∀ i, Setoid (α i)} (f : ∀ i, Quotient (S i)) : @Quotient (∀ i, α i) (by infer_instance) := ⟦fun i ↦ (f i).out⟧ @[simp] -theorem Quotient.choice_eq {ι : Type*} {α : ι → Type*} [∀ i, Setoid (α i)] (f : ∀ i, α i) : - (Quotient.choice fun i ↦ ⟦f i⟧) = ⟦f⟧ := +theorem Quotient.choice_eq {ι : Type*} {α : ι → Type*} {S : ∀ i, Setoid (α i)} (f : ∀ i, α i) : + (Quotient.choice (S := S) fun i ↦ ⟦f i⟧) = ⟦f⟧ := Quotient.sound fun _ ↦ Quotient.mk_out _ @[elab_as_elim] -theorem Quotient.induction_on_pi {ι : Type*} {α : ι → Sort*} [s : ∀ i, Setoid (α i)] +theorem Quotient.induction_on_pi {ι : Type*} {α : ι → Sort*} {s : ∀ i, Setoid (α i)} {p : (∀ i, Quotient (s i)) → Prop} (f : ∀ i, Quotient (s i)) (h : ∀ a : ∀ i, α i, p fun i ↦ ⟦a i⟧) : p f := by rw [← (funext fun i ↦ Quotient.out_eq (f i) : (fun i ↦ ⟦(f i).out⟧) = f)] @@ -441,8 +451,6 @@ protected theorem lift_mk (f : α → β) (c) (a : α) : lift f c (mk a) = f a : rfl /-- Lift a constant function on `q : Trunc α`. -/ --- Porting note: removed `@[elab_as_elim]` because it gave "unexpected eliminator resulting type" --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` protected def liftOn (q : Trunc α) (f : α → β) (c : ∀ a b : α, f a = f b) : β := lift f c q @@ -491,7 +499,6 @@ instance : LawfulMonad Trunc where variable {C : Trunc α → Sort*} /-- Recursion/induction principle for `Trunc`. -/ --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` @[elab_as_elim] protected def rec (f : ∀ a, C (mk a)) (h : ∀ a b : α, (Eq.ndrec (f a) (Trunc.eq (mk a) (mk b)) : C (mk b)) = f b) @@ -499,14 +506,12 @@ protected def rec (f : ∀ a, C (mk a)) Quot.rec f (fun a b _ ↦ h a b) q /-- A version of `Trunc.rec` taking `q : Trunc α` as the first argument. -/ --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` @[elab_as_elim] protected def recOn (q : Trunc α) (f : ∀ a, C (mk a)) (h : ∀ a b : α, (Eq.ndrec (f a) (Trunc.eq (mk a) (mk b)) : C (mk b)) = f b) : C q := Trunc.rec f h q /-- A version of `Trunc.recOn` assuming the codomain is a `Subsingleton`. -/ --- porting note (#11083)s: removed `@[reducible]` because it caused extremely slow `simp` @[elab_as_elim] protected def recOnSubsingleton [∀ a, Subsingleton (C (mk a))] (q : Trunc α) (f : ∀ a, C (mk a)) : C q := @@ -541,8 +546,8 @@ several different quotient relations on a type, for example quotient groups, rin -- Porting note: Quotient.mk' is the equivalent of Lean 3's `Quotient.mk` /-- A version of `Quotient.mk` taking `{s : Setoid α}` as an implicit argument instead of an instance argument. -/ -protected def mk'' (a : α) : Quotient s₁ := - Quot.mk s₁.1 a +protected abbrev mk'' (a : α) : Quotient s₁ := + ⟦a⟧ /-- `Quotient.mk''` is a surjective function. -/ theorem surjective_Quotient_mk'' : Function.Surjective (Quotient.mk'' : α → Quotient s₁) := @@ -550,9 +555,7 @@ theorem surjective_Quotient_mk'' : Function.Surjective (Quotient.mk'' : α → Q /-- A version of `Quotient.liftOn` taking `{s : Setoid α}` as an implicit argument instead of an instance argument. -/ --- Porting note: removed `@[elab_as_elim]` because it gave "unexpected eliminator resulting type" --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` -protected def liftOn' (q : Quotient s₁) (f : α → φ) (h : ∀ a b, @Setoid.r α s₁ a b → f a = f b) : +protected def liftOn' (q : Quotient s₁) (f : α → φ) (h : ∀ a b, s₁ a b → f a = f b) : φ := Quotient.liftOn q f h @@ -567,10 +570,8 @@ protected theorem liftOn'_mk'' (f : α → φ) (h) (x : α) : /-- A version of `Quotient.liftOn₂` taking `{s₁ : Setoid α} {s₂ : Setoid β}` as implicit arguments instead of instance arguments. -/ --- Porting note: removed `@[elab_as_elim]` because it gave "unexpected eliminator resulting type" --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` protected def liftOn₂' (q₁ : Quotient s₁) (q₂ : Quotient s₂) (f : α → β → γ) - (h : ∀ a₁ a₂ b₁ b₂, @Setoid.r α s₁ a₁ b₁ → @Setoid.r β s₂ a₂ b₂ → f a₁ a₂ = f b₁ b₂) : γ := + (h : ∀ a₁ a₂ b₁ b₂, s₁ a₁ b₁ → s₂ a₂ b₂ → f a₁ a₂ = f b₁ b₂) : γ := Quotient.liftOn₂ q₁ q₂ f h @[simp] @@ -627,7 +628,6 @@ protected def recOnSubsingleton' {φ : Quotient s₁ → Sort*} [∀ a, Subsingl /-- A version of `Quotient.recOnSubsingleton₂` taking `{s₁ : Setoid α} {s₂ : Setoid α}` as implicit arguments instead of instance arguments. -/ --- porting note (#11083): removed `@[reducible]` because it caused extremely slow `simp` @[elab_as_elim] protected def recOnSubsingleton₂' {φ : Quotient s₁ → Quotient s₂ → Sort*} [∀ a b, Subsingleton (φ ⟦a⟧ ⟦b⟧)] @@ -682,19 +682,18 @@ theorem map₂'_mk'' (f : α → β → γ) (h) (x : α) : rfl theorem exact' {a b : α} : - (Quotient.mk'' a : Quotient s₁) = Quotient.mk'' b → @Setoid.r _ s₁ a b := + (Quotient.mk'' a : Quotient s₁) = Quotient.mk'' b → s₁ a b := Quotient.exact -theorem sound' {a b : α} : @Setoid.r _ s₁ a b → @Quotient.mk'' α s₁ a = Quotient.mk'' b := +theorem sound' {a b : α} : s₁ a b → @Quotient.mk'' α s₁ a = Quotient.mk'' b := Quotient.sound @[simp] -protected theorem eq' [s₁ : Setoid α] {a b : α} : - @Quotient.mk' α s₁ a = @Quotient.mk' α s₁ b ↔ @Setoid.r _ s₁ a b := +protected theorem eq' {s₁ : Setoid α} {a b : α} : + @Quotient.mk' α s₁ a = @Quotient.mk' α s₁ b ↔ s₁ a b := Quotient.eq -@[simp] -protected theorem eq'' {a b : α} : @Quotient.mk'' α s₁ a = Quotient.mk'' b ↔ @Setoid.r _ s₁ a b := +protected theorem eq'' {a b : α} : @Quotient.mk'' α s₁ a = Quotient.mk'' b ↔ s₁ a b := Quotient.eq /-- A version of `Quotient.out` taking `{s₁ : Setoid α}` as an implicit argument instead of an @@ -706,12 +705,12 @@ noncomputable def out' (a : Quotient s₁) : α := theorem out_eq' (q : Quotient s₁) : Quotient.mk'' q.out' = q := q.out_eq -theorem mk_out' (a : α) : @Setoid.r α s₁ (Quotient.mk'' a : Quotient s₁).out' a := +theorem mk_out' (a : α) : s₁ (Quotient.mk'' a : Quotient s₁).out' a := Quotient.exact (Quotient.out_eq _) section -variable [s : Setoid α] +variable {s : Setoid α} protected theorem mk''_eq_mk : Quotient.mk'' = Quotient.mk s := rfl @@ -721,24 +720,23 @@ protected theorem liftOn'_mk (x : α) (f : α → β) (h) : (Quotient.mk s x).li rfl @[simp] -protected theorem liftOn₂'_mk [t : Setoid β] (f : α → β → γ) (h) (a : α) (b : β) : +protected theorem liftOn₂'_mk {t : Setoid β} (f : α → β → γ) (h) (a : α) (b : β) : Quotient.liftOn₂' (Quotient.mk s a) (Quotient.mk t b) f h = f a b := Quotient.liftOn₂'_mk'' _ _ _ _ -@[simp] -theorem map'_mk [t : Setoid β] (f : α → β) (h) (x : α) : +theorem map'_mk {t : Setoid β} (f : α → β) (h) (x : α) : (Quotient.mk s x).map' f h = (Quotient.mk t (f x)) := rfl end -instance (q : Quotient s₁) (f : α → Prop) (h : ∀ a b, @Setoid.r α s₁ a b → f a = f b) +instance (q : Quotient s₁) (f : α → Prop) (h : ∀ a b, s₁ a b → f a = f b) [DecidablePred f] : Decidable (Quotient.liftOn' q f h) := Quotient.lift.decidablePred _ _ q instance (q₁ : Quotient s₁) (q₂ : Quotient s₂) (f : α → β → Prop) - (h : ∀ a₁ b₁ a₂ b₂, @Setoid.r α s₁ a₁ a₂ → @Setoid.r β s₂ b₁ b₂ → f a₁ b₁ = f a₂ b₂) + (h : ∀ a₁ b₁ a₂ b₂, s₁ a₁ a₂ → s₂ b₁ b₂ → f a₁ b₁ = f a₂ b₂) [∀ a, DecidablePred (f a)] : Decidable (Quotient.liftOn₂' q₁ q₂ f h) := Quotient.lift₂.decidablePred _ h _ _ diff --git a/Mathlib/Data/Rat/Cast/Defs.lean b/Mathlib/Data/Rat/Cast/Defs.lean index 739dbc17cb0ce..5458a333b2468 100644 --- a/Mathlib/Data/Rat/Cast/Defs.lean +++ b/Mathlib/Data/Rat/Cast/Defs.lean @@ -3,13 +3,12 @@ Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ +import Mathlib.Algebra.Field.Basic import Mathlib.Algebra.Field.Rat import Mathlib.Algebra.Group.Commute.Basic -import Mathlib.Algebra.GroupWithZero.Units.Lemmas -import Mathlib.Algebra.Order.Field.Rat import Mathlib.Data.Int.Cast.Lemmas -import Mathlib.Data.NNRat.Lemmas import Mathlib.Data.Rat.Lemmas +import Mathlib.Order.Nat /-! # Casts for Rational Numbers @@ -24,6 +23,8 @@ casting lemmas showing the well-behavedness of this injection. rat, rationals, field, ℚ, numerator, denominator, num, denom, cast, coercion, casting -/ +assert_not_exists OrderedAddCommMonoid + variable {F ι α β : Type*} namespace NNRat diff --git a/Mathlib/Data/Rat/Cast/Lemmas.lean b/Mathlib/Data/Rat/Cast/Lemmas.lean index 4089d6b56d2e4..f61ef4b456824 100644 --- a/Mathlib/Data/Rat/Cast/Lemmas.lean +++ b/Mathlib/Data/Rat/Cast/Lemmas.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ -import Mathlib.Algebra.Field.Basic +import Mathlib.Algebra.Order.Nonneg.Field import Mathlib.Data.Rat.Cast.Defs import Mathlib.Tactic.Positivity.Basic diff --git a/Mathlib/Data/Rat/Cast/Order.lean b/Mathlib/Data/Rat/Cast/Order.lean index 2a4ebd3ceadb2..c85aa1ca681f0 100644 --- a/Mathlib/Data/Rat/Cast/Order.lean +++ b/Mathlib/Data/Rat/Cast/Order.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ -import Mathlib.Algebra.Order.Ring.Rat +import Mathlib.Algebra.Order.Field.Rat import Mathlib.Data.Rat.Cast.CharZero import Mathlib.Tactic.Positivity.Core import Mathlib.Algebra.Order.Field.Basic @@ -54,6 +54,38 @@ def castOrderEmbedding : ℚ ↪o K := @[simp] lemma cast_lt_zero : (q : K) < 0 ↔ q < 0 := by norm_cast +@[simp, norm_cast] +theorem cast_le_natCast {m : ℚ} {n : ℕ} : (m : K) ≤ n ↔ m ≤ (n : ℚ) := by + rw [← cast_le (K := K), cast_natCast] + +@[simp, norm_cast] +theorem natCast_le_cast {m : ℕ} {n : ℚ} : (m : K) ≤ n ↔ (m : ℚ) ≤ n := by + rw [← cast_le (K := K), cast_natCast] + +@[simp, norm_cast] +theorem cast_le_intCast {m : ℚ} {n : ℤ} : (m : K) ≤ n ↔ m ≤ (n : ℚ) := by + rw [← cast_le (K := K), cast_intCast] + +@[simp, norm_cast] +theorem intCast_le_cast {m : ℤ} {n : ℚ} : (m : K) ≤ n ↔ (m : ℚ) ≤ n := by + rw [← cast_le (K := K), cast_intCast] + +@[simp, norm_cast] +theorem cast_lt_natCast {m : ℚ} {n : ℕ} : (m : K) < n ↔ m < (n : ℚ) := by + rw [← cast_lt (K := K), cast_natCast] + +@[simp, norm_cast] +theorem natCast_lt_cast {m : ℕ} {n : ℚ} : (m : K) < n ↔ (m : ℚ) < n := by + rw [← cast_lt (K := K), cast_natCast] + +@[simp, norm_cast] +theorem cast_lt_intCast {m : ℚ} {n : ℤ} : (m : K) < n ↔ m < (n : ℚ) := by + rw [← cast_lt (K := K), cast_intCast] + +@[simp, norm_cast] +theorem intCast_lt_cast {m : ℤ} {n : ℚ} : (m : K) < n ↔ (m : ℚ) < n := by + rw [← cast_lt (K := K), cast_intCast] + @[simp, norm_cast] lemma cast_min (p q : ℚ) : (↑(min p q) : K) = min (p : K) (q : K) := (@cast_mono K _).map_min @@ -154,6 +186,22 @@ variable {n : ℕ} [n.AtLeastTwo] end ofNat +@[simp, norm_cast] +theorem cast_le_natCast {m : ℚ≥0} {n : ℕ} : (m : K) ≤ n ↔ m ≤ (n : ℚ≥0) := by + rw [← cast_le (K := K), cast_natCast] + +@[simp, norm_cast] +theorem natCast_le_cast {m : ℕ} {n : ℚ≥0} : (m : K) ≤ n ↔ (m : ℚ≥0) ≤ n := by + rw [← cast_le (K := K), cast_natCast] + +@[simp, norm_cast] +theorem cast_lt_natCast {m : ℚ≥0} {n : ℕ} : (m : K) < n ↔ m < (n : ℚ≥0) := by + rw [← cast_lt (K := K), cast_natCast] + +@[simp, norm_cast] +theorem natCast_lt_cast {m : ℕ} {n : ℚ≥0} : (m : K) < n ↔ (m : ℚ≥0) < n := by + rw [← cast_lt (K := K), cast_natCast] + @[simp, norm_cast] lemma cast_min (p q : ℚ≥0) : (↑(min p q) : K) = min (p : K) (q : K) := (@cast_mono K _).map_min diff --git a/Mathlib/Data/Rat/Floor.lean b/Mathlib/Data/Rat/Floor.lean index 9c7accdfc0acb..66006dd0fc062 100644 --- a/Mathlib/Data/Rat/Floor.lean +++ b/Mathlib/Data/Rat/Floor.lean @@ -49,7 +49,8 @@ instance : FloorRing ℚ := protected theorem floor_def {q : ℚ} : ⌊q⌋ = q.num / q.den := Rat.floor_def' q -theorem floor_int_div_nat_eq_div (n : ℤ) (d : ℕ) : ⌊(↑n : ℚ) / (↑d : ℚ)⌋ = n / (↑d : ℤ) := by +@[norm_cast] +theorem floor_intCast_div_natCast (n : ℤ) (d : ℕ) : ⌊(↑n / ↑d : ℚ)⌋ = n / (↑d : ℤ) := by rw [Rat.floor_def] obtain rfl | hd := @eq_zero_or_pos _ _ d · simp @@ -61,6 +62,18 @@ theorem floor_int_div_nat_eq_div (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 floor_natCast_div_natCast (n d : ℕ) : ⌊(↑n / ↑d : ℚ)⌋ = n / d := + floor_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)] + push_cast + exact floor_intCast_div_natCast n d + +@[deprecated (since := "2024-07-23")] alias floor_int_div_nat_eq_div := floor_intCast_div_natCast + @[simp, norm_cast] theorem floor_cast (x : ℚ) : ⌊(x : α)⌋ = ⌊x⌋ := floor_eq_iff.2 (mod_cast floor_eq_iff.1 (Eq.refl ⌊x⌋)) @@ -93,7 +106,7 @@ theorem isInt_intFloor_ofIsRat (r : α) (n : ℤ) (d : ℕ) : rintro ⟨inv, rfl⟩ constructor simp only [invOf_eq_inv, ← div_eq_mul_inv, Int.cast_id] - rw [← floor_int_div_nat_eq_div n d, ← floor_cast (α := α), Rat.cast_div, + rw [← floor_intCast_div_natCast n d, ← floor_cast (α := α), Rat.cast_div, cast_intCast, cast_natCast] /-- `norm_num` extension for `Int.floor` -/ @@ -103,14 +116,14 @@ def evalIntFloor : NormNumExt where eval {u αZ} e := do | 0, ~q(ℤ), ~q(@Int.floor $α $instR $instF $x) => match ← derive x with | .isBool .. => failure - | .isNat sα nb pb => do + | .isNat _ _ pb => do assertInstancesCommute return .isNat q(inferInstance) _ q(isNat_intFloor $x _ $pb) - | .isNegNat sα nb pb => do + | .isNegNat _ _ pb => do assertInstancesCommute -- floor always keeps naturals negative, so we can shortcut `.isInt` return .isNegNat q(inferInstance) _ q(isInt_intFloor _ _ $pb) - | .isRat dα q n d h => do + | .isRat _ q n d h => do let _i ← synthInstanceQ q(LinearOrderedField $α) assertInstancesCommute have z : Q(ℤ) := mkRawIntLit ⌊q⌋ @@ -123,7 +136,7 @@ end NormNum end Rat theorem Int.mod_nat_eq_sub_mul_floor_rat_div {n : ℤ} {d : ℕ} : n % d = n - d * ⌊(n : ℚ) / d⌋ := by - rw [eq_sub_of_add_eq <| Int.emod_add_ediv n d, Rat.floor_int_div_nat_eq_div] + rw [eq_sub_of_add_eq <| Int.emod_add_ediv n d, Rat.floor_intCast_div_natCast] theorem Nat.coprime_sub_mul_floor_rat_div_of_coprime {n d : ℕ} (n_coprime_d : n.Coprime d) : ((n : ℤ) - d * ⌊(n : ℚ) / d⌋).natAbs.Coprime d := by diff --git a/Mathlib/Data/Rat/Lemmas.lean b/Mathlib/Data/Rat/Lemmas.lean index 0aa562b90bce1..2423ed18b9d60 100644 --- a/Mathlib/Data/Rat/Lemmas.lean +++ b/Mathlib/Data/Rat/Lemmas.lean @@ -302,7 +302,7 @@ protected theorem «forall» {p : ℚ → Prop} : (∀ r, p r) ↔ ∀ a b : ℤ rwa [Int.cast_natCast, num_div_den q] at this⟩ protected theorem «exists» {p : ℚ → Prop} : (∃ r, p r) ↔ ∃ a b : ℤ, p (a / b) := - ⟨fun ⟨r, hr⟩ => ⟨r.num, r.den, by convert hr; convert num_div_den r⟩, fun ⟨a, b, h⟩ => ⟨_, h⟩⟩ + ⟨fun ⟨r, hr⟩ => ⟨r.num, r.den, by convert hr; convert num_div_den r⟩, fun ⟨_, _, h⟩ => ⟨_, h⟩⟩ /-! ### Denominator as `ℕ+` diff --git a/Mathlib/Data/Rat/Star.lean b/Mathlib/Data/Rat/Star.lean index 8f4b38afcab0e..1e69ef6c77136 100644 --- a/Mathlib/Data/Rat/Star.lean +++ b/Mathlib/Data/Rat/Star.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux, Yaël Dillies -/ import Mathlib.Algebra.GroupWithZero.Commute +import Mathlib.Algebra.Order.Field.Rat +import Mathlib.Algebra.Order.Monoid.Submonoid import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Algebra.Order.Star.Basic -import Mathlib.Data.NNRat.Lemmas -import Mathlib.Algebra.Order.Monoid.Submonoid import Mathlib.Tactic.FieldSimp /-! diff --git a/Mathlib/Data/Real/Archimedean.lean b/Mathlib/Data/Real/Archimedean.lean index f27de94d155e4..2e6e3bb63eb7a 100644 --- a/Mathlib/Data/Real/Archimedean.lean +++ b/Mathlib/Data/Real/Archimedean.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro, Floris van Doorn import Mathlib.Algebra.Order.Archimedean.Basic import Mathlib.Algebra.Order.Group.Pointwise.Bounds import Mathlib.Data.Real.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Order.Interval.Set.Disjoint /-! @@ -82,7 +83,7 @@ theorem exists_isLUB (hne : s.Nonempty) (hbdd : BddAbove s) : ∃ x, IsLUB s x : have j0 := Nat.cast_pos.1 ((inv_pos.2 ε0).trans_le ij) have k0 := Nat.cast_pos.1 ((inv_pos.2 ε0).trans_le ik) rcases hf₁ _ j0 with ⟨y, yS, hy⟩ - refine lt_of_lt_of_le ((Rat.cast_lt (K := ℝ)).1 ?_) ((inv_le ε0 (Nat.cast_pos.2 k0)).1 ik) + refine lt_of_lt_of_le ((Rat.cast_lt (K := ℝ)).1 ?_) ((inv_le_comm₀ ε0 (Nat.cast_pos.2 k0)).1 ik) simpa using sub_lt_iff_lt_add'.2 (lt_of_le_of_lt hy <| sub_lt_iff_lt_add.1 <| hf₂ _ k0 _ yS) let g : CauSeq ℚ abs := ⟨fun n => f n / n, hg⟩ refine ⟨mk g, ⟨fun x xS => ?_, fun y h => ?_⟩⟩ @@ -93,7 +94,7 @@ theorem exists_isLUB (hne : s.Nonempty) (hbdd : BddAbove s) : ∃ x, IsLUB s x : replace hK := hK.le.trans (Nat.cast_le.2 nK) have n0 : 0 < n := Nat.cast_pos.1 ((inv_pos.2 xz).trans_le hK) refine le_trans ?_ (hf₂ _ n0 _ xS).le - rwa [le_sub_comm, inv_le (Nat.cast_pos.2 n0 : (_ : ℝ) < _) xz] + rwa [le_sub_comm, inv_le_comm₀ (Nat.cast_pos.2 n0 : (_ : ℝ) < _) xz] · exact mk_le_of_forall_le ⟨1, fun n n1 => diff --git a/Mathlib/Data/Real/Basic.lean b/Mathlib/Data/Real/Basic.lean index 7cec019cb7dbe..3465de02f2a9a 100644 --- a/Mathlib/Data/Real/Basic.lean +++ b/Mathlib/Data/Real/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Floris van Doorn -/ import Mathlib.Algebra.Order.CauSeq.Completion +import Mathlib.Algebra.Order.Field.Rat /-! # Real numbers from Cauchy sequences @@ -520,9 +521,9 @@ noncomputable instance instLinearOrderedField : LinearOrderedField ℝ where exact CauSeq.Completion.inv_mul_cancel h inv_zero := by simp [← ofCauchy_zero, ← ofCauchy_inv] nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl nnratCast_def q := by rw [← ofCauchy_nnratCast, NNRat.cast_def, ofCauchy_div, ofCauchy_natCast, ofCauchy_natCast] ratCast_def q := by diff --git a/Mathlib/Data/Real/ConjExponents.lean b/Mathlib/Data/Real/ConjExponents.lean index 8ade2aebf3b1e..581ac0eb8bed3 100644 --- a/Mathlib/Data/Real/ConjExponents.lean +++ b/Mathlib/Data/Real/ConjExponents.lean @@ -108,7 +108,7 @@ theorem inv_add_inv_conj_ennreal : (ENNReal.ofReal p)⁻¹ + (ENNReal.ofReal q) end protected lemma inv_inv (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1) : a⁻¹.IsConjExponent b⁻¹ := - ⟨one_lt_inv ha <| by linarith, by simpa only [inv_inv]⟩ + ⟨(one_lt_inv₀ ha).2 <| by linarith, by simpa only [inv_inv]⟩ lemma inv_one_sub_inv (ha₀ : 0 < a) (ha₁ : a < 1) : a⁻¹.IsConjExponent (1 - a)⁻¹ := .inv_inv ha₀ (sub_pos_of_lt ha₁) <| add_tsub_cancel_of_le ha₁.le @@ -199,7 +199,7 @@ end protected lemma inv_inv (ha : a ≠ 0) (hb : b ≠ 0) (hab : a + b = 1) : a⁻¹.IsConjExponent b⁻¹ := - ⟨one_lt_inv ha.bot_lt <| by rw [← hab]; exact lt_add_of_pos_right _ hb.bot_lt, by + ⟨(one_lt_inv₀ ha.bot_lt).2 <| by rw [← hab]; exact lt_add_of_pos_right _ hb.bot_lt, by simpa only [inv_inv] using hab⟩ lemma inv_one_sub_inv (ha₀ : a ≠ 0) (ha₁ : a < 1) : a⁻¹.IsConjExponent (1 - a)⁻¹ := @@ -272,7 +272,7 @@ protected lemma conjExponent (hp : 1 ≤ p) : p.IsConjExponent (conjExponent p) refine (AddLECancellable.eq_tsub_iff_add_eq_of_le (α := ℝ≥0∞) (by simpa) (by simpa)).1 ?_ rw [inv_eq_iff_eq_inv] obtain rfl | hp₁ := hp.eq_or_lt - · simp + · simp [tsub_eq_zero_of_le] obtain rfl | hp := eq_or_ne p ∞ · simp calc @@ -317,7 +317,7 @@ lemma mul_eq_add : p * q = p + q := by lemma div_conj_eq_sub_one : p / q = p - 1 := by obtain rfl | hq := eq_or_ne q ∞ - · simp [h.symm.conj_eq] + · simp [h.symm.conj_eq, tsub_eq_zero_of_le] refine ENNReal.eq_sub_of_add_eq one_ne_top ?_ rw [← ENNReal.div_self h.symm.ne_zero hq, ← ENNReal.add_div, ← h.mul_eq_add, mul_div_assoc, ENNReal.div_self h.symm.ne_zero hq, mul_one] diff --git a/Mathlib/Data/Real/EReal.lean b/Mathlib/Data/Real/EReal.lean index 4ff49b8b9459b..e714fee04e424 100644 --- a/Mathlib/Data/Real/EReal.lean +++ b/Mathlib/Data/Real/EReal.lean @@ -132,6 +132,14 @@ protected def rec {C : EReal → Sort*} (h_bot : C ⊥) (h_real : ∀ a : ℝ, C | (a : ℝ) => h_real a | ⊤ => h_top +protected lemma «forall» {p : EReal → Prop} : (∀ r, p r) ↔ p ⊥ ∧ p ⊤ ∧ ∀ r : ℝ, p r where + mp h := ⟨h _, h _, fun _ ↦ h _⟩ + mpr h := EReal.rec h.1 h.2.2 h.2.1 + +protected lemma «exists» {p : EReal → Prop} : (∃ r, p r) ↔ p ⊥ ∨ p ⊤ ∨ ∃ r : ℝ, p r where + mp := by rintro ⟨r, hr⟩; cases r <;> aesop + mpr := by rintro (h | h | ⟨r, hr⟩) <;> exact ⟨_, ‹_›⟩ + /-- The multiplication on `EReal`. Our definition satisfies `0 * x = x * 0 = 0` for any `x`, and picks the only sensible value elsewhere. -/ protected def mul : EReal → EReal → EReal @@ -673,7 +681,7 @@ theorem natCast_mul (m n : ℕ) : theorem exists_rat_btwn_of_lt : ∀ {a b : EReal}, a < b → ∃ x : ℚ, a < (x : ℝ) ∧ ((x : ℝ) : EReal) < b - | ⊤, b, h => (not_top_lt h).elim + | ⊤, _, h => (not_top_lt h).elim | (a : ℝ), ⊥, h => (lt_irrefl _ ((bot_lt_coe a).trans h)).elim | (a : ℝ), (b : ℝ), h => by simp [exists_rat_btwn (EReal.coe_lt_coe_iff.1 h)] | (a : ℝ), ⊤, _ => @@ -1485,7 +1493,7 @@ lemma inv_neg_of_neg_ne_bot {a : EReal} (h : a < 0) (h' : a ≠ ⊥) : a⁻¹ < /-! ### Division -/ -lemma div_eq_inv_mul (a b : EReal) : a / b = b⁻¹ * a := EReal.mul_comm a b⁻¹ +protected lemma div_eq_inv_mul (a b : EReal) : a / b = b⁻¹ * a := EReal.mul_comm a b⁻¹ lemma coe_div (a b : ℝ) : (a / b : ℝ) = (a : EReal) / (b : EReal) := rfl diff --git a/Mathlib/Data/Real/GoldenRatio.lean b/Mathlib/Data/Real/GoldenRatio.lean index 7165e37237c30..2518fadf3188a 100644 --- a/Mathlib/Data/Real/GoldenRatio.lean +++ b/Mathlib/Data/Real/GoldenRatio.lean @@ -109,7 +109,7 @@ theorem goldConj_ne_zero : ψ ≠ 0 := theorem neg_one_lt_goldConj : -1 < ψ := by rw [neg_lt, ← inv_gold] - exact inv_lt_one one_lt_gold + exact inv_lt_one_of_one_lt₀ one_lt_gold /-! ## Irrationality @@ -201,7 +201,7 @@ theorem Real.coe_fib_eq' : /-- Binet's formula as a dependent equality. -/ theorem Real.coe_fib_eq : ∀ n, (Nat.fib n : ℝ) = (φ ^ n - ψ ^ n) / √5 := by - rw [← Function.funext_iff, Real.coe_fib_eq'] + rw [← funext_iff, Real.coe_fib_eq'] /-- Relationship between the Fibonacci Sequence, Golden Ratio and its conjugate's exponents --/ theorem fib_golden_conj_exp (n : ℕ) : Nat.fib (n + 1) - φ * Nat.fib n = ψ ^ n := by diff --git a/Mathlib/Data/Real/Hyperreal.lean b/Mathlib/Data/Real/Hyperreal.lean index 68aee623dbde7..4b5d781f4224b 100644 --- a/Mathlib/Data/Real/Hyperreal.lean +++ b/Mathlib/Data/Real/Hyperreal.lean @@ -403,7 +403,7 @@ theorem InfiniteNeg.not_infinitesimal {x : ℝ*} (h : InfiniteNeg x) : ¬Infinit theorem infinitePos_iff_infinite_and_pos {x : ℝ*} : InfinitePos x ↔ Infinite x ∧ 0 < x := ⟨fun hip => ⟨Or.inl hip, hip 0⟩, fun ⟨hi, hp⟩ => - hi.casesOn (fun hip => hip) fun hin => False.elim (not_lt_of_lt hp (hin 0))⟩ + hi.casesOn id fun hin => False.elim (not_lt_of_lt hp (hin 0))⟩ theorem infiniteNeg_iff_infinite_and_neg {x : ℝ*} : InfiniteNeg x ↔ Infinite x ∧ x < 0 := ⟨fun hip => ⟨Or.inr hip, hip 0⟩, fun ⟨hi, hp⟩ => @@ -599,12 +599,12 @@ theorem infinitePos_iff_infinitesimal_inv_pos {x : ℝ*} : ⟨fun hip => ⟨infinitesimal_def.mpr fun r hr => ⟨lt_trans (coe_lt_coe.2 (neg_neg_of_pos hr)) (inv_pos.2 (hip 0)), - (inv_lt (coe_lt_coe.2 hr) (hip 0)).mp (by convert hip r⁻¹)⟩, + inv_lt_of_inv_lt₀ (coe_lt_coe.2 hr) (by convert hip r⁻¹)⟩, inv_pos.2 <| hip 0⟩, fun ⟨hi, hp⟩ r => @_root_.by_cases (r = 0) (↑r < x) (fun h => Eq.substr h (inv_pos.mp hp)) fun h => lt_of_le_of_lt (coe_le_coe.2 (le_abs_self r)) - ((inv_lt_inv (inv_pos.mp hp) (coe_lt_coe.2 (abs_pos.2 h))).mp + ((inv_lt_inv₀ (inv_pos.mp hp) (coe_lt_coe.2 (abs_pos.2 h))).mp ((infinitesimal_def.mp hi) |r|⁻¹ (inv_pos.2 (abs_pos.2 h))).2)⟩ theorem infiniteNeg_iff_infinitesimal_inv_neg {x : ℝ*} : diff --git a/Mathlib/Data/Real/Irrational.lean b/Mathlib/Data/Real/Irrational.lean index 3a8c9b0473110..62ea491e08723 100644 --- a/Mathlib/Data/Real/Irrational.lean +++ b/Mathlib/Data/Real/Irrational.lean @@ -68,24 +68,23 @@ theorem irrational_nrt_of_notint_nrt {x : ℝ} (n : ℕ) (m : ℤ) (hxr : x ^ n is irrational. -/ theorem irrational_nrt_of_n_not_dvd_multiplicity {x : ℝ} (n : ℕ) {m : ℤ} (hm : m ≠ 0) (p : ℕ) [hp : Fact p.Prime] (hxr : x ^ n = m) - (hv : (multiplicity (p : ℤ) m).get (finite_int_iff.2 ⟨hp.1.ne_one, hm⟩) % n ≠ 0) : + (hv : multiplicity (p : ℤ) m % n ≠ 0) : Irrational x := by rcases Nat.eq_zero_or_pos n with (rfl | hnpos) · rw [eq_comm, pow_zero, ← Int.cast_one, Int.cast_inj] at hxr - simp [hxr, multiplicity.one_right (mt isUnit_iff_dvd_one.1 + simp [hxr, multiplicity_of_one_right (mt isUnit_iff_dvd_one.1 (mt Int.natCast_dvd_natCast.1 hp.1.not_dvd_one)), Nat.zero_mod] at hv refine irrational_nrt_of_notint_nrt _ _ hxr ?_ hnpos rintro ⟨y, rfl⟩ 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 - erw [multiplicity.pow' (Nat.prime_iff_prime_int.1 hp.1) (finite_int_iff.2 ⟨hp.1.ne_one, this⟩), - Nat.mul_mod_right] at hv + rw [(Int.multiplicity_finite_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 theorem irrational_sqrt_of_multiplicity_odd (m : ℤ) (hm : 0 < m) (p : ℕ) [hp : Fact p.Prime] - (Hpv : - (multiplicity (p : ℤ) m).get (finite_int_iff.2 ⟨hp.1.ne_one, (ne_of_lt hm).symm⟩) % 2 = 1) : + (Hpv : multiplicity (p : ℤ) m % 2 = 1) : Irrational (√m) := @irrational_nrt_of_n_not_dvd_multiplicity _ 2 _ (Ne.symm (ne_of_lt hm)) p hp (sq_sqrt (Int.cast_nonneg.2 <| le_of_lt hm)) (by rw [Hpv]; exact one_ne_zero) diff --git a/Mathlib/Data/Real/IsNonarchimedean.lean b/Mathlib/Data/Real/IsNonarchimedean.lean new file mode 100644 index 0000000000000..6b8017ac1d629 --- /dev/null +++ b/Mathlib/Data/Real/IsNonarchimedean.lean @@ -0,0 +1,115 @@ +/- +Copyright (c) 2024 María Inés de Frutos-Fernández. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: María Inés de Frutos-Fernández +-/ +import Mathlib.Algebra.Order.Hom.Ultra +import Mathlib.Analysis.Normed.Group.Ultra +import Mathlib.Data.Nat.Choose.Sum + +/-! +# Nonarchimedean functions + +A function `f : R → ℝ≥0` is nonarchimedean if it satisfies the strong triangle inequality +`f (r + s) ≤ max (f r) (f s)` for all `r s : R`. This file proves basic properties of +nonarchimedean functions. +-/ + +namespace IsNonarchimedean + +open IsUltrametricDist + +/-- A nonarchimedean function satisfies the triangle inequality. -/ +theorem add_le {α : Type*} [Add α] {f : α → ℝ} (hf : ∀ x : α, 0 ≤ f x) + (hna : IsNonarchimedean f) {a b : α} : f (a + b) ≤ f a + f b := by + apply le_trans (hna _ _) + rw [max_le_iff, le_add_iff_nonneg_right, le_add_iff_nonneg_left] + exact ⟨hf _, hf _⟩ + +/-- If `f` is a nonarchimedean additive group seminorm on `α`, then for every `n : ℕ` and `a : α`, + we have `f (n • a) ≤ (f a)`. -/ +theorem nsmul_le {F α : Type*} [AddGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] {f : F} (hna : IsNonarchimedean f) {n : ℕ} {a : α} : + f (n • a) ≤ f a := by + let _ := AddGroupSeminormClass.toSeminormedAddGroup f + have := AddGroupSeminormClass.isUltrametricDist hna + simp only [← AddGroupSeminormClass.toSeminormedAddGroup_norm_eq] + exact norm_nsmul_le _ _ + +/-- If `f` is a nonarchimedean additive group seminorm on `α`, then for every `n : ℕ` and `a : α`, + we have `f (n * a) ≤ (f a)`. -/ +theorem nmul_le {F α : Type*} [Ring α] [FunLike F α ℝ] [AddGroupSeminormClass F α ℝ] + {f : F} (hna : IsNonarchimedean f) {n : ℕ} {a : α} : f (n * a) ≤ f a := by + rw [← nsmul_eq_mul] + exact nsmul_le hna + +/-- If `f` is a nonarchimedean additive group seminorm on `α` and `x y : α` are such that + `f x ≠ f y`, then `f (x + y) = max (f x) (f y)`. -/ +theorem add_eq_max_of_ne {F α : Type*} [AddGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] {f : F} (hna : IsNonarchimedean f) {x y : α} (hne : f x ≠ f y) : + f (x + y) = max (f x) (f y) := by + let _ := AddGroupSeminormClass.toSeminormedAddGroup f + have := AddGroupSeminormClass.isUltrametricDist hna + simp only [← AddGroupSeminormClass.toSeminormedAddGroup_norm_eq] at hne ⊢ + exact norm_add_eq_max_of_norm_ne_norm hne + +/-- Given a nonarchimedean additive group seminorm `f` on `α`, a function `g : β → α` and a finset + `t : Finset β`, we can always find `b : β`, belonging to `t` if `t` is nonempty, such that + `f (t.sum g) ≤ f (g b)` . -/ +theorem finset_image_add {F α β : Type*} [AddCommGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] [Nonempty β] {f : F} (hna : IsNonarchimedean f) + (g : β → α) (t : Finset β) : + ∃ b : β, (t.Nonempty → b ∈ t) ∧ f (t.sum g) ≤ f (g b) := by + let _ := AddGroupSeminormClass.toSeminormedAddCommGroup f + have := AddGroupSeminormClass.isUltrametricDist hna + simp only [← AddGroupSeminormClass.toSeminormedAddCommGroup_norm_eq] + apply exists_norm_finset_sum_le + +/-- Given a nonarchimedean additive group seminorm `f` on `α`, a function `g : β → α` and a + nonempty finset `t : Finset β`, we can always find `b : β` belonging to `t` such that + `f (t.sum g) ≤ f (g b)` . -/ +theorem finset_image_add_of_nonempty {F α β : Type*} [AddCommGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] [Nonempty β] {f : F} (hna : IsNonarchimedean f) + (g : β → α) {t : Finset β} (ht : t.Nonempty) : + ∃ b : β, (b ∈ t) ∧ f (t.sum g) ≤ f (g b) := by + obtain ⟨b, hbt, hbf⟩ := finset_image_add hna g t + exact ⟨b, hbt ht, hbf⟩ + +/-- Given a nonarchimedean additive group seminorm `f` on `α`, a function `g : β → α` and a + multiset `s : Multiset β`, we can always find `b : β`, belonging to `s` if `s` is nonempty, + such that `f (t.sum g) ≤ f (g b)` . -/ +theorem multiset_image_add {F α β : Type*} [AddCommGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] [Nonempty β] {f : F} (hna : IsNonarchimedean f) + (g : β → α) (s : Multiset β) : + ∃ b : β, (s ≠ 0 → b ∈ s) ∧ f (Multiset.map g s).sum ≤ f (g b) := by + let _ := AddGroupSeminormClass.toSeminormedAddCommGroup f + have := AddGroupSeminormClass.isUltrametricDist hna + simp only [← AddGroupSeminormClass.toSeminormedAddCommGroup_norm_eq] + apply exists_norm_multiset_sum_le + +/-- Given a nonarchimedean additive group seminorm `f` on `α`, a function `g : β → α` and a + nonempty multiset `s : Multiset β`, we can always find `b : β` belonging to `s` such that + `f (t.sum g) ≤ f (g b)` . -/ +theorem multiset_image_add_of_nonempty {F α β : Type*} [AddCommGroup α] [FunLike F α ℝ] + [AddGroupSeminormClass F α ℝ] [Nonempty β] {f : F} (hna : IsNonarchimedean f) + (g : β → α) {s : Multiset β} (hs : s ≠ 0) : + ∃ b : β, (b ∈ s) ∧ f (Multiset.map g s).sum ≤ f (g b) := by + obtain ⟨b, hbs, hbf⟩ := multiset_image_add hna g s + exact ⟨b, hbs hs, hbf⟩ + +/-- If `f` is a nonarchimedean additive group seminorm on a commutative ring `α`, `n : ℕ`, and + `a b : α`, then we can find `m : ℕ` such that `m ≤ n` and + `f ((a + b) ^ n) ≤ (f (a ^ m)) * (f (b ^ (n - m)))`. -/ +theorem add_pow_le {F α : Type*} [CommRing α] [FunLike F α ℝ] + [RingSeminormClass F α ℝ] {f : F} (hna : IsNonarchimedean f) (n : ℕ) (a b : α) : + ∃ m < n + 1, f ((a + b) ^ n) ≤ f (a ^ m) * f (b ^ (n - m)) := by + obtain ⟨m, hm_lt, hM⟩ := finset_image_add hna + (fun m => a ^ m * b ^ (n - m) * ↑(n.choose m)) (Finset.range (n + 1)) + simp only [Finset.nonempty_range_iff, ne_eq, Nat.succ_ne_zero, not_false_iff, Finset.mem_range, + if_true, forall_true_left] at hm_lt + refine ⟨m, hm_lt, ?_⟩ + simp only [← add_pow] at hM + rw [mul_comm] at hM + exact le_trans hM (le_trans (nmul_le hna) (map_mul_le_mul _ _ _)) + +end IsNonarchimedean diff --git a/Mathlib/Data/Rel.lean b/Mathlib/Data/Rel.lean index 27adb8a69b26d..9717d93d288df 100644 --- a/Mathlib/Data/Rel.lean +++ b/Mathlib/Data/Rel.lean @@ -194,7 +194,7 @@ theorem image_bot (s : Set α) : (⊥ : Rel α β).image s = ∅ := by @[simp] theorem image_top {s : Set α} (h : Set.Nonempty s) : (⊤ : Rel α β).image s = Set.univ := - Set.eq_univ_of_forall fun x ↦ ⟨h.some, by simp [h.some_mem, Top.top]⟩ + Set.eq_univ_of_forall fun _ ↦ ⟨h.some, by simp [h.some_mem, Top.top]⟩ /-- Preimage of a set under a relation `r`. Same as the image of `s` under `r.inv` -/ def preimage (s : Set β) : Set α := diff --git a/Mathlib/Data/Semiquot.lean b/Mathlib/Data/Semiquot.lean index fb1f34b2cb8c3..326ba455059c6 100644 --- a/Mathlib/Data/Semiquot.lean +++ b/Mathlib/Data/Semiquot.lean @@ -153,9 +153,9 @@ instance : LE (Semiquot α) := instance partialOrder : PartialOrder (Semiquot α) where le s t := ∀ ⦃x⦄, x ∈ s → x ∈ t - le_refl s := Set.Subset.refl _ - le_trans s t u := Set.Subset.trans - le_antisymm s t h₁ h₂ := ext_s.2 (Set.Subset.antisymm h₁ h₂) + le_refl _ := Set.Subset.refl _ + le_trans _ _ _ := Set.Subset.trans + le_antisymm _ _ h₁ h₂ := ext_s.2 (Set.Subset.antisymm h₁ h₂) instance : SemilatticeSup (Semiquot α) := { Semiquot.partialOrder with diff --git a/Mathlib/Data/Seq/Computation.lean b/Mathlib/Data/Seq/Computation.lean index 9ff96e3dd47ef..0cb816198ffd8 100644 --- a/Mathlib/Data/Seq/Computation.lean +++ b/Mathlib/Data/Seq/Computation.lean @@ -960,10 +960,10 @@ theorem liftRel_def {R : α → β → Prop} {ca cb} : let ⟨b', mb', ab⟩ := h.left ma rwa [mem_unique mb mb']⟩, fun ⟨l, r⟩ => - ⟨fun {a} ma => + ⟨fun {_} ma => let ⟨⟨b, mb⟩⟩ := l.1 ⟨⟨_, ma⟩⟩ ⟨b, mb, r ma mb⟩, - fun {b} mb => + fun {_} mb => let ⟨⟨a, ma⟩⟩ := l.2 ⟨⟨_, mb⟩⟩ ⟨a, ma, r ma mb⟩⟩⟩ diff --git a/Mathlib/Data/Seq/Seq.lean b/Mathlib/Data/Seq/Seq.lean index e1c08ea1f9bdc..b005e06bce8fb 100644 --- a/Mathlib/Data/Seq/Seq.lean +++ b/Mathlib/Data/Seq/Seq.lean @@ -159,7 +159,7 @@ theorem mem_cons_of_mem (y : α) {a : α} : ∀ {s : Seq α}, a ∈ s → a ∈ | ⟨_, _⟩ => Stream'.mem_cons_of_mem (some y) theorem eq_or_mem_of_mem_cons {a b : α} : ∀ {s : Seq α}, a ∈ cons b s → a = b ∨ a ∈ s - | ⟨f, al⟩, h => (Stream'.eq_or_mem_of_mem_cons h).imp_left fun h => by injection h + | ⟨_, _⟩, h => (Stream'.eq_or_mem_of_mem_cons h).imp_left fun h => by injection h @[simp] theorem mem_cons_iff {a b : α} {s : Seq α} : a ∈ cons b s ↔ a = b ∨ a ∈ s := @@ -512,8 +512,6 @@ def zipWith (f : α → β → γ) (s₁ : Seq α) (s₂ : Seq β) : Seq γ := ⟨fun n => Option.map₂ f (s₁.get? n) (s₂.get? n), fun {_} hn => Option.map₂_eq_none_iff.2 <| (Option.map₂_eq_none_iff.1 hn).imp s₁.2 s₂.2⟩ -variable {s : Seq α} {s' : Seq β} {n : ℕ} - @[simp] theorem get?_zipWith (f : α → β → γ) (s s' n) : (zipWith f s s').get? n = Option.map₂ f (s.get? n) (s'.get? n) := diff --git a/Mathlib/Data/Seq/WSeq.lean b/Mathlib/Data/Seq/WSeq.lean index 4817d9024ec51..5b57888ef3f6e 100644 --- a/Mathlib/Data/Seq/WSeq.lean +++ b/Mathlib/Data/Seq/WSeq.lean @@ -6,7 +6,7 @@ Authors: Mario Carneiro import Mathlib.Logic.Relation import Mathlib.Data.Option.Basic import Mathlib.Data.Seq.Seq -import Batteries.Data.DList +import Batteries.Data.DList.Basic /-! # Partially defined possibly infinite lists @@ -627,7 +627,6 @@ theorem dropn_cons (a : α) (s) (n) : drop (cons a s) (n + 1) = drop s n := by induction n with | zero => simp [drop] | succ n n_ih => - -- porting note (#10745): was `simp [*, drop]`. simp [drop, ← n_ih] @[simp] @@ -708,7 +707,7 @@ theorem drop.aux_none : ∀ n, @drop.aux α n none = Computation.pure none rw [ret_bind, drop.aux_none n] theorem destruct_dropn : ∀ (s : WSeq α) (n), destruct (drop s n) = destruct s >>= drop.aux n - | s, 0 => (bind_pure' _).symm + | _, 0 => (bind_pure' _).symm | s, n + 1 => by rw [← dropn_tail, destruct_dropn _ n, destruct_tail, LawfulMonad.bind_assoc] rfl @@ -875,7 +874,6 @@ theorem exists_get?_of_mem {s : WSeq α} {a} (h : a ∈ s) : ∃ n, some a ∈ g apply ret_mem · cases' h with n h exists n + 1 - -- porting note (#10745): was `simp [get?]`. simpa [get?] · intro s' h cases' h with n h diff --git a/Mathlib/Data/Set/Accumulate.lean b/Mathlib/Data/Set/Accumulate.lean index fcbe0ea222997..ffa9845a9ad40 100644 --- a/Mathlib/Data/Set/Accumulate.lean +++ b/Mathlib/Data/Set/Accumulate.lean @@ -12,7 +12,7 @@ The function `Accumulate` takes a set `s` and returns `⋃ y ≤ x, s y`. -/ -variable {α β γ : Type*} {s : α → Set β} {t : α → Set γ} +variable {α β : Type*} {s : α → Set β} namespace Set diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 691836860b538..0308934067d78 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -6,10 +6,11 @@ Authors: Jeremy Avigad, Leonardo de Moura import Mathlib.Algebra.Group.ZeroOne import Mathlib.Data.Set.Operations import Mathlib.Order.Basic -import Mathlib.Order.SymmDiff +import Mathlib.Order.BooleanAlgebra import Mathlib.Tactic.Tauto import Mathlib.Tactic.ByContra import Mathlib.Util.Delaborators +import Mathlib.Tactic.Lift /-! # Basic properties of sets @@ -65,7 +66,7 @@ set, sets, subset, subsets, union, intersection, insert, singleton, complement, open Function -universe u v w x +universe u v namespace Set @@ -142,11 +143,9 @@ theorem Set.coe_eq_subtype (s : Set α) : ↥s = { x // x ∈ s } := theorem Set.coe_setOf (p : α → Prop) : ↥{ x | p x } = { x // p x } := rfl --- Porting note (#10618): removed `simp` because `simp` can prove it theorem SetCoe.forall {s : Set α} {p : s → Prop} : (∀ x : s, p x) ↔ ∀ (x) (h : x ∈ s), p ⟨x, h⟩ := Subtype.forall --- Porting note (#10618): removed `simp` because `simp` can prove it theorem SetCoe.exists {s : Set α} {p : s → Prop} : (∃ x : s, p x) ↔ ∃ (x : _) (h : x ∈ s), p ⟨x, h⟩ := Subtype.exists @@ -182,7 +181,7 @@ theorem Eq.subset {α} {s t : Set α} : s = t → s ⊆ t := namespace Set -variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} {a b : α} {s s₁ s₂ t t₁ t₂ u : Set α} +variable {α : Type u} {β : Type v} {a b : α} {s s₁ s₂ t t₁ t₂ u : Set α} instance : Inhabited (Set α) := ⟨∅⟩ @@ -347,7 +346,6 @@ protected theorem ssubset_of_subset_of_ssubset {s₁ s₂ s₃ : Set α} (hs₁s theorem not_mem_empty (x : α) : ¬x ∈ (∅ : Set α) := id --- Porting note (#10618): removed `simp` because `simp` can prove it theorem not_not_mem : ¬a ∉ s ↔ a ∈ s := not_not @@ -355,8 +353,6 @@ theorem not_not_mem : ¬a ∉ s ↔ a ∈ s := -- Porting note: we seem to need parentheses at `(↥s)`, -- even if we increase the right precedence of `↥` in `Mathlib.Tactic.Coe`. --- Porting note: removed `simp` as it is competing with `nonempty_subtype`. --- @[simp] theorem nonempty_coe_sort {s : Set α} : Nonempty (↥s) ↔ s.Nonempty := nonempty_subtype @@ -942,7 +938,6 @@ theorem ssubset_insert {s : Set α} {a : α} (h : a ∉ s) : s ⊂ insert a s := theorem insert_comm (a b : α) (s : Set α) : insert a (insert b s) = insert b (insert a s) := ext fun _ => or_left_comm --- Porting note (#10618): removing `simp` attribute because `simp` can prove it theorem insert_idem (a : α) (s : Set α) : insert a (insert a s) = insert a s := insert_eq_of_mem <| mem_insert _ _ @@ -991,6 +986,24 @@ theorem forall_mem_insert {P : α → Prop} {a : α} {s : Set α} : forall₂_or_left.trans <| and_congr_left' forall_eq @[deprecated (since := "2024-03-23")] alias ball_insert_iff := forall_mem_insert +/-- Inserting an element to a set is equivalent to the option type. -/ +def subtypeInsertEquivOption + [DecidableEq α] {t : Set α} {x : α} (h : x ∉ t) : + { i // i ∈ insert x t } ≃ Option { i // i ∈ t } where + toFun y := if h : ↑y = x then none else some ⟨y, (mem_insert_iff.mp y.2).resolve_left h⟩ + invFun y := (y.elim ⟨x, mem_insert _ _⟩) fun z => ⟨z, mem_insert_of_mem _ z.2⟩ + left_inv y := by + by_cases h : ↑y = x + · simp only [Subtype.ext_iff, h, Option.elim, dif_pos, Subtype.coe_mk] + · simp only [h, Option.elim, dif_neg, not_false_iff, Subtype.coe_eta, Subtype.coe_mk] + right_inv := by + rintro (_ | y) + · simp only [Option.elim, dif_pos] + · have : ↑y ≠ x := by + rintro ⟨⟩ + exact h y.2 + simp only [this, Option.elim, Subtype.eta, dif_neg, not_false_iff, Subtype.coe_mk] + /-! ### Lemmas about singletons -/ /- porting note: instance was in core in Lean3 -/ @@ -1046,7 +1059,6 @@ theorem singleton_nonempty (a : α) : ({a} : Set α).Nonempty := theorem singleton_ne_empty (a : α) : ({a} : Set α) ≠ ∅ := (singleton_nonempty _).ne_empty ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem empty_ssubset_singleton : (∅ : Set α) ⊂ {a} := (singleton_nonempty _).empty_ssubset @@ -1136,19 +1148,15 @@ theorem sep_eq_self_iff_mem_true : { x ∈ s | p x } = s ↔ ∀ x ∈ s, p x := theorem sep_eq_empty_iff_mem_false : { x ∈ s | p x } = ∅ ↔ ∀ x ∈ s, ¬p x := by simp_rw [Set.ext_iff, mem_sep_iff, mem_empty_iff_false, iff_false, not_and] ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem sep_true : { x ∈ s | True } = s := inter_univ s ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem sep_false : { x ∈ s | False } = ∅ := inter_empty s ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem sep_empty (p : α → Prop) : { x ∈ (∅ : Set α) | p x } = ∅ := empty_inter {x | p x} ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem sep_univ : { x ∈ (univ : Set α) | p x } = { x | p x } := univ_inter {x | p x} @@ -1497,6 +1505,10 @@ theorem diff_subset_diff_left {s₁ s₂ t : Set α} (h : s₁ ⊆ s₂) : s₁ theorem diff_subset_diff_right {s t u : Set α} (h : t ⊆ u) : s \ u ⊆ s \ t := sdiff_le_sdiff_left ‹t ≤ u› +theorem diff_subset_diff_iff_subset {r : Set α} (hs : s ⊆ r) (ht : t ⊆ r) : + r \ s ⊆ r \ t ↔ t ⊆ s := + sdiff_le_sdiff_iff_le hs ht + theorem compl_eq_univ_diff (s : Set α) : sᶜ = univ \ s := top_sdiff.symm @@ -1557,6 +1569,11 @@ theorem diff_compl : s \ tᶜ = s ∩ t := theorem diff_diff_right {s t u : Set α} : s \ (t \ u) = s \ t ∪ s ∩ u := sdiff_sdiff_right' +theorem diff_insert_of_not_mem {x : α} (h : x ∉ s) : s \ insert x t = s \ t := by + refine Subset.antisymm (diff_subset_diff (refl _) (subset_insert ..)) fun y hy ↦ ?_ + simp only [mem_diff, mem_insert_iff, not_or] at hy ⊢ + exact ⟨hy.1, fun hxy ↦ h <| hxy ▸ hy.1, hy.2⟩ + @[simp] theorem insert_diff_of_mem (s) (h : a ∈ t) : insert a s \ t = s \ t := by ext @@ -1634,7 +1651,6 @@ theorem insert_diff_singleton_comm (hab : a ≠ b) (s : Set α) : simp_rw [← union_singleton, union_diff_distrib, diff_singleton_eq_self (mem_singleton_iff.not.2 hab.symm)] ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem diff_self {s : Set α} : s \ s = ∅ := sdiff_self @@ -1662,7 +1678,6 @@ theorem union_eq_diff_union_diff_union_inter (s t : Set α) : s ∪ t = s \ t /-! ### Lemmas about pairs -/ ---Porting note (#10618): removed `simp` attribute because `simp` can prove it theorem pair_eq_singleton (a : α) : ({a, a} : Set α) = {a} := union_self _ @@ -1699,43 +1714,6 @@ theorem Nonempty.subset_pair_iff_eq (hs : s.Nonempty) : s ⊆ {a, b} ↔ s = {a} ∨ s = {b} ∨ s = {a, b} := by rw [Set.subset_pair_iff_eq, or_iff_right]; exact hs.ne_empty -/-! ### Symmetric difference -/ - -section - -open scoped symmDiff - -theorem mem_symmDiff : a ∈ s ∆ t ↔ a ∈ s ∧ a ∉ t ∨ a ∈ t ∧ a ∉ s := - Iff.rfl - -protected theorem symmDiff_def (s t : Set α) : s ∆ t = s \ t ∪ t \ s := - rfl - -theorem symmDiff_subset_union : s ∆ t ⊆ s ∪ t := - @symmDiff_le_sup (Set α) _ _ _ - -@[simp] -theorem symmDiff_eq_empty : s ∆ t = ∅ ↔ s = t := - symmDiff_eq_bot - -@[simp] -theorem symmDiff_nonempty : (s ∆ t).Nonempty ↔ s ≠ t := - nonempty_iff_ne_empty.trans symmDiff_eq_empty.not - -theorem inter_symmDiff_distrib_left (s t u : Set α) : s ∩ t ∆ u = (s ∩ t) ∆ (s ∩ u) := - inf_symmDiff_distrib_left _ _ _ - -theorem inter_symmDiff_distrib_right (s t u : Set α) : s ∆ t ∩ u = (s ∩ u) ∆ (t ∩ u) := - inf_symmDiff_distrib_right _ _ _ - -theorem subset_symmDiff_union_symmDiff_left (h : Disjoint s t) : u ⊆ s ∆ u ∪ t ∆ u := - h.le_symmDiff_sup_symmDiff_left - -theorem subset_symmDiff_union_symmDiff_right (h : Disjoint t u) : s ⊆ s ∆ t ∪ s ∆ u := - h.le_symmDiff_sup_symmDiff_right - -end - /-! ### Powerset -/ theorem mem_powerset {x s : Set α} (h : x ⊆ s) : x ∈ 𝒫 s := @h diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 57aba3430a761..fa03f476c8309 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -109,8 +109,7 @@ theorem encard_ne_zero : s.encard ≠ 0 ↔ s.Nonempty := by theorem encard_union_eq (h : Disjoint s t) : (s ∪ t).encard = s.encard + t.encard := by classical - have e := (Equiv.Set.union (by rwa [subset_empty_iff, ← disjoint_iff_inter_eq_empty])).symm - simp [encard, ← PartENat.card_congr e, PartENat.card_sum, PartENat.withTopEquiv] + simp [encard, PartENat.card_congr (Equiv.Set.union h), PartENat.card_sum, PartENat.withTopEquiv] 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] diff --git a/Mathlib/Data/Set/Enumerate.lean b/Mathlib/Data/Set/Enumerate.lean index fd4f8dbb791b1..908974989a9e3 100644 --- a/Mathlib/Data/Set/Enumerate.lean +++ b/Mathlib/Data/Set/Enumerate.lean @@ -5,8 +5,8 @@ Authors: Johannes Hölzl -/ import Mathlib.Algebra.Group.Basic import Mathlib.Algebra.Group.Nat -import Mathlib.Data.Set.Basic import Mathlib.Tactic.Common +import Mathlib.Data.Set.Basic /-! # Set enumeration @@ -42,7 +42,7 @@ theorem enumerate_eq_none_of_sel {s : Set α} (h : sel s = none) : ∀ {n}, enum theorem enumerate_eq_none : ∀ {s n₁ n₂}, enumerate sel s n₁ = none → n₁ ≤ n₂ → enumerate sel s n₂ = none - | s, 0, m => fun h _ ↦ enumerate_eq_none_of_sel sel h + | _, 0, _ => fun h _ ↦ enumerate_eq_none_of_sel sel h | s, n + 1, m => fun h hm ↦ by cases hs : sel s · exact enumerate_eq_none_of_sel sel hs diff --git a/Mathlib/Data/Set/Equitable.lean b/Mathlib/Data/Set/Equitable.lean index 8eb08216d19ac..b2e7669c813a3 100644 --- a/Mathlib/Data/Set/Equitable.lean +++ b/Mathlib/Data/Set/Equitable.lean @@ -3,10 +3,8 @@ Copyright (c) 2021 Yaël Dillies, Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ -import Mathlib.Data.Set.Subsingleton import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Algebra.Group.Nat -import Mathlib.Data.Set.Basic +import Mathlib.Algebra.Order.Ring.Defs /-! # Equitable functions diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index cf7a2bfbb02d2..a9931dc317e91 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -3,10 +3,14 @@ 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, Kyle Miller -/ -import Mathlib.Data.Finite.Basic import Mathlib.Data.Finset.Max import Mathlib.Data.Set.Functor import Mathlib.Data.Set.Lattice +import Mathlib.Data.Finite.Powerset +import Mathlib.Data.Finite.Prod +import Mathlib.Data.Finite.Sigma +import Mathlib.Data.Finite.Vector +import Mathlib.Logic.Embedding.Set /-! # Finite sets @@ -193,12 +197,9 @@ protected theorem toFinset_subset_toFinset : hs.toFinset ⊆ ht.toFinset ↔ s protected theorem toFinset_ssubset_toFinset : hs.toFinset ⊂ ht.toFinset ↔ s ⊂ t := by simp only [← Finset.coe_ssubset, Finite.coe_toFinset] -alias ⟨_, toFinset_mono⟩ := Finite.toFinset_subset_toFinset +protected alias ⟨_, toFinset_mono⟩ := Finite.toFinset_subset_toFinset -alias ⟨_, toFinset_strictMono⟩ := Finite.toFinset_ssubset_toFinset - --- Porting note: attribute [protected] doesn't work --- attribute [protected] toFinset_mono toFinset_strictMono +protected alias ⟨_, toFinset_strictMono⟩ := Finite.toFinset_ssubset_toFinset -- Porting note: `simp` can simplify LHS but then it simplifies something -- in the generated `Fintype {x | p x}` instance and fails to apply `Set.toFinset_setOf` @@ -261,8 +262,6 @@ protected theorem toFinset_image [DecidableEq β] (f : α → β) (hs : s.Finite ext simp --- Porting note (#10618): now `simp` can prove it but it needs the `fintypeRange` instance --- from the next section protected theorem toFinset_range [DecidableEq α] [Fintype β] (f : β → α) (h : (range f).Finite) : h.toFinset = Finset.univ.image f := by ext @@ -477,7 +476,6 @@ This is a wrapper around `Set.toFinite`. -/ theorem finite_toSet (s : Finset α) : (s : Set α).Finite := Set.toFinite _ --- Porting note (#10618): was @[simp], now `simp` can prove it theorem finite_toSet_toFinset (s : Finset α) : s.finite_toSet.toFinset = s := by rw [toFinite_toFinset, toFinset_coe] @@ -1009,7 +1007,7 @@ theorem eq_finite_iUnion_of_finite_subset_iUnion {ι} {s : ι → Set α} {t : S I.Finite ∧ ∃ σ : { i | i ∈ I } → Set α, (∀ i, (σ i).Finite) ∧ (∀ i, σ i ⊆ s i) ∧ t = ⋃ i, σ i := let ⟨I, Ifin, hI⟩ := finite_subset_iUnion tfin h - ⟨I, Ifin, fun x => s x ∩ t, fun i => tfin.subset inter_subset_right, fun i => + ⟨I, Ifin, fun x => s x ∩ t, fun _ => tfin.subset inter_subset_right, fun _ => inter_subset_left, by ext x rw [mem_iUnion] @@ -1111,7 +1109,7 @@ theorem card_image_of_inj_on {s : Set α} [Fintype s] {f : α → β} [Fintype ( _ = s.toFinset.card := Finset.card_image_of_injOn fun x hx y hy hxy => H x (mem_toFinset.1 hx) y (mem_toFinset.1 hy) hxy - _ = Fintype.card s := (Fintype.card_of_finset' _ fun a => mem_toFinset).symm + _ = Fintype.card s := (Fintype.card_of_finset' _ fun _ => mem_toFinset).symm theorem card_image_of_injective (s : Set α) [Fintype s] {f : α → β} [Fintype (f '' s)] (H : Function.Injective f) : Fintype.card (f '' s) = Fintype.card s := @@ -1212,10 +1210,7 @@ theorem infinite_range_iff {f : α → β} (hi : Injective f) : (range f).Infinite ↔ Infinite α := by rw [← image_univ, infinite_image_iff hi.injOn, infinite_univ_iff] -alias ⟨_, Infinite.image⟩ := infinite_image_iff - --- Porting note: attribute [protected] doesn't work --- attribute [protected] infinite.image +protected alias ⟨_, Infinite.image⟩ := infinite_image_iff section Image2 @@ -1574,7 +1569,7 @@ end LinearOrder namespace List variable (α) [Finite α] (n : ℕ) -lemma finite_length_eq : {l : List α | l.length = n}.Finite := Vector.finite +lemma finite_length_eq : {l : List α | l.length = n}.Finite := Mathlib.Vector.finite lemma finite_length_lt : {l : List α | l.length < n}.Finite := by convert (Finset.range n).finite_toSet.biUnion fun i _ ↦ finite_length_eq α i; ext; simp diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index e6ab24cdeaac3..230e18833cc9c 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -272,7 +272,7 @@ theorem MapsTo.range_restrict (f : α → β) (s : Set α) (t : Set β) (h : Map theorem mapsTo_iff_exists_map_subtype : MapsTo f s t ↔ ∃ g : s → t, ∀ x : s, f x = g x := ⟨fun h => ⟨h.restrict f s t, fun _ => rfl⟩, fun ⟨g, hg⟩ x hx => by - erw [hg ⟨x, hx⟩] + rw [hg ⟨x, hx⟩] apply Subtype.coe_prop⟩ theorem mapsTo' : MapsTo f s t ↔ f '' s ⊆ t := @@ -281,9 +281,9 @@ theorem mapsTo' : MapsTo f s t ↔ f '' s ⊆ t := theorem mapsTo_prod_map_diagonal : MapsTo (Prod.map f f) (diagonal α) (diagonal β) := diagonal_subset_iff.2 fun _ => rfl -theorem MapsTo.subset_preimage {f : α → β} {s : Set α} {t : Set β} (hf : MapsTo f s t) : - s ⊆ f ⁻¹' t := - hf +theorem MapsTo.subset_preimage (hf : MapsTo f s t) : s ⊆ f ⁻¹' t := hf + +theorem mapsTo_iff_subset_preimage : MapsTo f s t ↔ s ⊆ f ⁻¹' t := Iff.rfl @[simp] theorem mapsTo_singleton {x : α} : MapsTo f {x} t ↔ f x ∈ t := @@ -544,7 +544,7 @@ theorem MapsTo.restrict_inj (h : MapsTo f s t) : Injective (h.restrict f s t) theorem exists_injOn_iff_injective [Nonempty β] : (∃ f : α → β, InjOn f s) ↔ ∃ f : s → β, Injective f := - ⟨fun ⟨f, hf⟩ => ⟨_, hf.injective⟩, + ⟨fun ⟨_, hf⟩ => ⟨_, hf.injective⟩, fun ⟨f, hf⟩ => by lift f to α → β using trivial exact ⟨f, injOn_iff_injective.2 hf⟩⟩ @@ -625,8 +625,15 @@ theorem InjOn.imageFactorization_injective (h : InjOn f s) : end injOn section graphOn +variable {x : α × β} + +@[simp] lemma mem_graphOn : x ∈ s.graphOn f ↔ x.1 ∈ s ∧ f x.1 = x.2 := by aesop (add simp graphOn) @[simp] lemma graphOn_empty (f : α → β) : graphOn f ∅ = ∅ := image_empty _ +@[simp] lemma graphOn_eq_empty : graphOn f s = ∅ ↔ s = ∅ := image_eq_empty +@[simp] lemma graphOn_nonempty : (s.graphOn f).Nonempty ↔ s.Nonempty := image_nonempty + +protected alias ⟨_, Nonempty.graphOn⟩ := graphOn_nonempty @[simp] lemma graphOn_union (f : α → β) (s t : Set α) : graphOn f (s ∪ t) = graphOn f s ∪ graphOn f t := @@ -645,6 +652,24 @@ lemma graphOn_insert (f : α → β) (x : α) (s : Set α) : lemma image_fst_graphOn (f : α → β) (s : Set α) : Prod.fst '' graphOn f s = s := by simp [graphOn, image_image] +@[simp] lemma image_snd_graphOn (f : α → β) : Prod.snd '' s.graphOn f = f '' s := by ext x; simp + +lemma fst_injOn_graph : (s.graphOn f).InjOn Prod.fst := by aesop (add simp InjOn) + +lemma graphOn_comp (s : Set α) (f : α → β) (g : β → γ) : + s.graphOn (g ∘ f) = (fun x ↦ (x.1, g x.2)) '' s.graphOn f := by + simpa using image_comp (fun x ↦ (x.1, g x.2)) (fun x ↦ (x, f x)) _ + +lemma graphOn_univ_eq_range : univ.graphOn f = range fun x ↦ (x, f x) := image_univ + +@[simp] lemma graphOn_inj {g : α → β} : s.graphOn f = s.graphOn g ↔ s.EqOn f g := by + simp [Set.ext_iff, funext_iff, forall_swap, EqOn] + +lemma graphOn_univ_inj {g : α → β} : univ.graphOn f = univ.graphOn g ↔ f = g := by simp + +lemma graphOn_univ_injective : Injective (univ.graphOn : (α → β) → Set (α × β)) := + fun _f _g ↦ graphOn_univ_inj.1 + lemma exists_eq_graphOn_image_fst [Nonempty β] {s : Set (α × β)} : (∃ f : α → β, s = graphOn f (Prod.fst '' s)) ↔ InjOn Prod.fst s := by refine ⟨?_, fun h ↦ ?_⟩ @@ -866,7 +891,7 @@ theorem BijOn.image_eq (h : BijOn f s t) : f '' s = t := h.surjOn.image_eq_of_mapsTo h.mapsTo lemma BijOn.forall {p : β → Prop} (hf : BijOn f s t) : (∀ b ∈ t, p b) ↔ ∀ a ∈ s, p (f a) where - mp h a ha := h _ <| hf.mapsTo ha + mp h _ ha := h _ <| hf.mapsTo ha mpr h b hb := by obtain ⟨a, ha, rfl⟩ := hf.surjOn hb; exact h _ ha lemma BijOn.exists {p : β → Prop} (hf : BijOn f s t) : (∃ b ∈ t, p b) ↔ ∃ a ∈ s, p (f a) where @@ -922,6 +947,34 @@ theorem BijOn.subset_left {r : Set α} (hf : BijOn f s t) (hrs : r ⊆ s) : BijOn f r (f '' r) := (hf.injOn.mono hrs).bijOn_image +theorem BijOn.insert_iff (ha : a ∉ s) (hfa : f a ∉ t) : + BijOn f (insert a s) (insert (f a) t) ↔ BijOn f s t where + mp h := by + have := congrArg (· \ {f a}) (image_insert_eq ▸ h.image_eq) + simp only [mem_singleton_iff, insert_diff_of_mem] at this + rw [diff_singleton_eq_self hfa, diff_singleton_eq_self] at this + · exact ⟨by simp [← this, mapsTo'], h.injOn.mono (subset_insert ..), + by simp [← this, surjOn_image]⟩ + simp only [mem_image, not_exists, not_and] + intro x hx + rw [h.injOn.eq_iff (by simp [hx]) (by simp)] + exact ha ∘ (· ▸ hx) + mpr h := by + repeat rw [insert_eq] + refine (bijOn_singleton.mpr rfl).union h ?_ + simp only [singleton_union, injOn_insert fun x ↦ (hfa (h.mapsTo x)), h.injOn, mem_image, + not_exists, not_and, true_and] + exact fun _ hx h₂ ↦ hfa (h₂ ▸ h.mapsTo hx) + +theorem BijOn.insert (h₁ : BijOn f s t) (h₂ : f a ∉ t) : + BijOn f (insert a s) (insert (f a) t) := + (insert_iff (h₂ <| h₁.mapsTo ·) h₂).mpr h₁ + +theorem BijOn.sdiff_singleton (h₁ : BijOn f s t) (h₂ : a ∈ s) : + BijOn f (s \ {a}) (t \ {f a}) := by + convert h₁.subset_left diff_subset + simp [h₁.injOn.image_diff, h₁.image_eq, h₂, inter_eq_self_of_subset_right] + end bijOn /-! ### left inverse -/ @@ -1584,7 +1637,7 @@ lemma bijOn' (h₁ : MapsTo e s t) (h₂ : MapsTo e.symm t s) : BijOn e s t := ⟨h₁, e.injective.injOn, fun b hb ↦ ⟨e.symm b, h₂ hb, apply_symm_apply _ _⟩⟩ protected lemma bijOn (h : ∀ a, e a ∈ t ↔ a ∈ s) : BijOn e s t := - e.bijOn' (fun a ↦ (h _).2) fun b hb ↦ (h _).1 <| by rwa [apply_symm_apply] + e.bijOn' (fun _ ↦ (h _).2) fun b hb ↦ (h _).1 <| by rwa [apply_symm_apply] lemma invOn : InvOn e e.symm t s := ⟨e.rightInverse_symm.leftInvOn _, e.leftInverse_symm.leftInvOn _⟩ diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index 9b390e67bad19..af9427b7d8259 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -8,6 +8,7 @@ import Mathlib.Tactic.Use import Batteries.Tactic.Congr import Mathlib.Order.TypeTags import Mathlib.Data.Option.Basic +import Mathlib.Data.Set.SymmDiff /-! # Images and preimages of sets @@ -37,7 +38,7 @@ open Function Set namespace Set -variable {α β γ : Type*} {ι ι' : Sort*} +variable {α β γ : Type*} {ι : Sort*} /-! ### Inverse image -/ @@ -168,6 +169,12 @@ theorem preimage_subtype_coe_eq_compl {s u v : Set α} (hsuv : s ⊆ u ∪ v) · intro hx exact Or.elim (hsuv x_in_s) id fun hx' => hx.elim hx' +lemma preimage_subset {s t} (hs : s ⊆ f '' t) (hf : Set.InjOn f (f ⁻¹' s)) : f ⁻¹' s ⊆ t := by + rintro a ha + obtain ⟨b, hb, hba⟩ := hs ha + rwa [hf ha _ hba.symm] + simpa [hba] + end Preimage /-! ### Image of a set under a function -/ @@ -570,7 +577,7 @@ theorem forall_mem_range {p : α → Prop} : (∀ a ∈ range f, p a) ↔ ∀ i, theorem forall_subtype_range_iff {p : range f → Prop} : (∀ a : range f, p a) ↔ ∀ i, p ⟨f i, mem_range_self _⟩ := - ⟨fun H i => H _, fun H ⟨y, i, hi⟩ => by + ⟨fun H _ => H _, fun H ⟨y, i, hi⟩ => by subst hi apply H⟩ @@ -584,7 +591,7 @@ theorem exists_subtype_range_iff {p : range f → Prop} : ⟨fun ⟨⟨a, i, hi⟩, ha⟩ => by subst a exact ⟨i, ha⟩, - fun ⟨i, hi⟩ => ⟨_, hi⟩⟩ + fun ⟨_, hi⟩ => ⟨_, hi⟩⟩ theorem range_iff_surjective : range f = univ ↔ Surjective f := eq_univ_iff_forall @@ -628,7 +635,7 @@ theorem range_subset_iff : range f ⊆ s ↔ ∀ y, f y ∈ s := theorem range_subset_range_iff_exists_comp {f : α → γ} {g : β → γ} : range f ⊆ range g ↔ ∃ h : α → β, f = g ∘ h := by - simp only [range_subset_iff, mem_range, Classical.skolem, Function.funext_iff, (· ∘ ·), eq_comm] + simp only [range_subset_iff, mem_range, Classical.skolem, funext_iff, (· ∘ ·), eq_comm] theorem range_eq_iff (f : α → β) (s : Set β) : range f = s ↔ (∀ a, f a ∈ s) ∧ ∀ b ∈ s, ∃ a, f a = b := by @@ -663,7 +670,7 @@ theorem insert_image_compl_eq_range (f : α → β) (x : α) : insert (f x) (f ' theorem image_preimage_eq_range_inter {f : α → β} {t : Set β} : f '' (f ⁻¹' t) = range f ∩ t := ext fun x => - ⟨fun ⟨x, hx, HEq⟩ => HEq ▸ ⟨mem_range_self _, hx⟩, fun ⟨⟨y, h_eq⟩, hx⟩ => + ⟨fun ⟨_, hx, HEq⟩ => HEq ▸ ⟨mem_range_self _, hx⟩, fun ⟨⟨y, h_eq⟩, hx⟩ => h_eq ▸ mem_image_of_mem f <| show y ∈ f ⁻¹' t by rw [preimage, mem_setOf, h_eq]; exact hx⟩ theorem image_preimage_eq_inter_range {f : α → β} {t : Set β} : f '' (f ⁻¹' t) = t ∩ range f := by @@ -817,9 +824,8 @@ theorem range_quot_lift {r : ι → ι → Prop} (hf : ∀ x y, r x y → f x = range (Quot.lift f hf) = range f := ext fun _ => (surjective_quot_mk _).exists --- Porting note: the `Setoid α` instance is not being filled in @[simp] -theorem range_quotient_mk [sa : Setoid α] : (range (α := Quotient sa) fun x : α => ⟦x⟧) = univ := +theorem range_quotient_mk {s : Setoid α} : range (Quotient.mk s) = univ := range_quot_mk _ @[simp] @@ -831,7 +837,7 @@ theorem range_quotient_lift [s : Setoid ι] (hf) : theorem range_quotient_mk' {s : Setoid α} : range (Quotient.mk' : α → Quotient s) = univ := range_quot_mk _ -@[simp] lemma Quotient.range_mk'' {sa : Setoid α} : range (Quotient.mk'' (s₁ := sa)) = univ := +lemma Quotient.range_mk'' {sa : Setoid α} : range (Quotient.mk'' (s₁ := sa)) = univ := range_quotient_mk @[simp] @@ -945,7 +951,7 @@ theorem range_inclusion (h : s ⊆ t) : range (inclusion h) = { x : t | (x : α) -- When `f` is injective, see also `Equiv.ofInjective`. theorem leftInverse_rangeSplitting (f : α → β) : LeftInverse (rangeFactorization f) (rangeSplitting f) := fun x => by - apply Subtype.ext -- Porting note: why doesn't `ext` find this lemma? + ext simp only [rangeFactorization_coe] apply apply_rangeSplitting diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index b6f29fa406fdf..f85d0821bddfd 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -87,10 +87,10 @@ theorem mem_iInter₂_of_mem {s : ∀ i, κ i → Set α} {a : α} (h : ∀ i j, instance completeAtomicBooleanAlgebra : CompleteAtomicBooleanAlgebra (Set α) := { instBooleanAlgebraSet with - le_sSup := fun s t t_in a a_in => ⟨t, t_in, a_in⟩ - sSup_le := fun s t h a ⟨t', ⟨t'_in, a_in⟩⟩ => h t' t'_in a_in - le_sInf := fun s t h a a_in t' t'_in => h t' t'_in a_in - sInf_le := fun s t t_in a h => h _ t_in + le_sSup := fun _ t t_in _ a_in => ⟨t, t_in, a_in⟩ + sSup_le := fun _ _ h _ ⟨t', ⟨t'_in, a_in⟩⟩ => h t' t'_in a_in + le_sInf := fun _ _ h _ a_in t' t'_in => h t' t'_in a_in + sInf_le := fun _ _ t_in _ h => h _ t_in iInf_iSup_eq := by intros; ext; simp [Classical.skolem] } section GaloisConnection @@ -239,7 +239,6 @@ theorem subset_iInter_iff {s : Set α} {t : ι → Set α} : (s ⊆ ⋂ i, t i) le_iInf_iff /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/ --- Porting note (#10618): removing `simp`. `simp` can prove it theorem subset_iInter₂_iff {s : Set α} {t : ∀ i, κ i → Set α} : (s ⊆ ⋂ (i) (j), t i j) ↔ ∀ i j, s ⊆ t i j := by simp_rw [subset_iInter_iff] @@ -568,7 +567,6 @@ theorem iInter_eq_univ : ⋂ i, s i = univ ↔ ∀ i, s i = univ := theorem nonempty_iUnion : (⋃ i, s i).Nonempty ↔ ∃ i, (s i).Nonempty := by simp [nonempty_iff_ne_empty] --- Porting note (#10618): removing `simp`. `simp` can prove it theorem nonempty_biUnion {t : Set α} {s : α → Set β} : (⋃ i ∈ t, s i).Nonempty ↔ ∃ i ∈ t, (s i).Nonempty := by simp @@ -1019,7 +1017,6 @@ theorem nonempty_iInter {f : ι → Set α} : (⋂ i, f i).Nonempty ↔ ∃ x, /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/ -- classical --- Porting note (#10618): removing `simp`. `simp` can prove it theorem nonempty_iInter₂ {s : ∀ i, κ i → Set α} : (⋂ (i) (j), s i j).Nonempty ↔ ∃ a, ∀ i j, a ∈ s i j := by simp @@ -1173,6 +1170,30 @@ theorem union_distrib_iInter_right (s : ι → Set α) (t : Set α) : (⋂ i, s theorem union_distrib_iInter₂_right (s : ∀ i, κ i → Set α) (t : Set α) : (⋂ (i) (j), s i j) ∪ t = ⋂ (i) (j), s i j ∪ t := by simp_rw [union_distrib_iInter_right] +lemma biUnion_lt_eq_iUnion [LT α] [NoMaxOrder α] {s : α → Set β} : + ⋃ (n) (m < n), s m = ⋃ n, s n := biSup_lt_eq_iSup + +lemma biUnion_le_eq_iUnion [Preorder α] {s : α → Set β} : + ⋃ (n) (m ≤ n), s m = ⋃ n, s n := biSup_le_eq_iSup + +lemma biInter_lt_eq_iInter [LT α] [NoMaxOrder α] {s : α → Set β} : + ⋂ (n) (m < n), s m = ⋂ (n), s n := biInf_lt_eq_iInf + +lemma biInter_le_eq_iInter [Preorder α] {s : α → Set β} : + ⋂ (n) (m ≤ n), s m = ⋂ (n), s n := biInf_le_eq_iInf + +lemma biUnion_gt_eq_iUnion [LT α] [NoMinOrder α] {s : α → Set β} : + ⋃ (n) (m > n), s m = ⋃ n, s n := biSup_gt_eq_iSup + +lemma biUnion_ge_eq_iUnion [Preorder α] {s : α → Set β} : + ⋃ (n) (m ≥ n), s m = ⋃ n, s n := biSup_ge_eq_iSup + +lemma biInter_gt_eq_iInf [LT α] [NoMinOrder α] {s : α → Set β} : + ⋂ (n) (m > n), s m = ⋂ n, s n := biInf_gt_eq_iInf + +lemma biInter_ge_eq_iInf [Preorder α] {s : α → Set β} : + ⋂ (n) (m ≥ n), s m = ⋂ n, s n := biInf_ge_eq_iInf + section Function /-! ### Lemmas about `Set.MapsTo` @@ -1767,13 +1788,11 @@ theorem disjoint_iUnion_right {ι : Sort*} {s : ι → Set α} : disjoint_iSup_iff /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/ --- Porting note (#10618): removing `simp`. `simp` can prove it theorem disjoint_iUnion₂_left {s : ∀ i, κ i → Set α} {t : Set α} : Disjoint (⋃ (i) (j), s i j) t ↔ ∀ i j, Disjoint (s i j) t := iSup₂_disjoint_iff /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/ --- Porting note (#10618): removing `simp`. `simp` can prove it theorem disjoint_iUnion₂_right {s : Set α} {t : ∀ i, κ i → Set α} : Disjoint s (⋃ (i) (j), t i j) ↔ ∀ i j, Disjoint s (t i j) := disjoint_iSup₂_iff diff --git a/Mathlib/Data/Set/MulAntidiagonal.lean b/Mathlib/Data/Set/MulAntidiagonal.lean index 487d0d5850eb3..8bddb878d7cc2 100644 --- a/Mathlib/Data/Set/MulAntidiagonal.lean +++ b/Mathlib/Data/Set/MulAntidiagonal.lean @@ -83,8 +83,7 @@ end CancelCommMonoid section OrderedCancelCommMonoid -variable [CancelCommMonoid α] [PartialOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· < ·)] +variable [CancelCommMonoid α] [PartialOrder α] [MulLeftMono α] [MulRightStrictMono α] (s t : Set α) (a : α) {x y : mulAntidiagonal s t a} @[to_additive Set.AddAntidiagonal.eq_of_fst_le_fst_of_snd_le_snd] @@ -112,8 +111,7 @@ theorem finite_of_isPWO (hs : s.IsPWO) (ht : t.IsPWO) (a) : (mulAntidiagonal s t end OrderedCancelCommMonoid -variable [CancelCommMonoid α] [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· < ·)] +variable [CancelCommMonoid α] [LinearOrder α] [MulLeftMono α] [MulRightStrictMono α] @[to_additive Set.AddAntidiagonal.finite_of_isWF] theorem finite_of_isWF {s t : Set α} (hs : s.IsWF) (ht : t.IsWF) diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index 9f1f7eb954123..72515c986a918 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -20,9 +20,8 @@ This file is very similar to `Data.Finset.NAry`, to `Order.Filter.NAry`, and to open Function namespace Set -variable {α α' β β' γ γ' δ δ' ε ε' ζ ζ' ν : Type*} {f f' : α → β → γ} {g g' : α → β → γ → δ} -variable {s s' : Set α} {t t' : Set β} {u u' : Set γ} {v : Set δ} {a a' : α} {b b' : β} {c c' : γ} - {d d' : δ} +variable {α α' β β' γ γ' δ δ' ε ε' ζ ζ' ν : Type*} {f f' : α → β → γ} +variable {s s' : Set α} {t t' : Set β} {u : Set γ} {v : Set δ} {a : α} {b : β} theorem mem_image2_iff (hf : Injective2 f) : f a b ∈ image2 f s t ↔ a ∈ s ∧ b ∈ t := ⟨by @@ -31,13 +30,16 @@ theorem mem_image2_iff (hf : Injective2 f) : f a b ∈ image2 f s t ↔ a ∈ s exact ⟨ha', hb'⟩, fun ⟨ha, hb⟩ => mem_image2_of_mem ha hb⟩ /-- image2 is monotone with respect to `⊆`. -/ +@[gcongr] theorem image2_subset (hs : s ⊆ s') (ht : t ⊆ t') : image2 f s t ⊆ image2 f s' t' := by rintro _ ⟨a, ha, b, hb, rfl⟩ exact mem_image2_of_mem (hs ha) (ht hb) +@[gcongr] theorem image2_subset_left (ht : t ⊆ t') : image2 f s t ⊆ image2 f s t' := image2_subset Subset.rfl ht +@[gcongr] theorem image2_subset_right (hs : s ⊆ s') : image2 f s t ⊆ image2 f s' t := image2_subset hs Subset.rfl diff --git a/Mathlib/Data/Set/Pairwise/Basic.lean b/Mathlib/Data/Set/Pairwise/Basic.lean index a40768a7e768d..ec5b714ca6538 100644 --- a/Mathlib/Data/Set/Pairwise/Basic.lean +++ b/Mathlib/Data/Set/Pairwise/Basic.lean @@ -30,11 +30,11 @@ on `Set.PairwiseDisjoint`, even though the latter unfolds to something nicer. open Function Order Set -variable {α β γ ι ι' : Type*} {r p q : α → α → Prop} +variable {α β γ ι ι' : Type*} {r p : α → α → Prop} section Pairwise -variable {f g : ι → α} {s t u : Set α} {a b : α} +variable {f g : ι → α} {s t : Set α} {a b : α} theorem pairwise_on_bool (hr : Symmetric r) {a b : α} : Pairwise (r on fun c => cond c a b) ↔ r a b := by simpa [Pairwise, Function.onFun] using @hr a b @@ -296,12 +296,8 @@ lemma PairwiseDisjoint.eq_or_disjoint exact h.elim hi hj lemma pairwiseDisjoint_range_iff {α β : Type*} {f : α → (Set β)} : - (Set.range f).PairwiseDisjoint id ↔ ∀ x y, f x = f y ∨ Disjoint (f x) (f y) := by - constructor - · intro h x y - apply h.eq_or_disjoint (Set.mem_range_self x) (Set.mem_range_self y) - · rintro h _ ⟨x, rfl⟩ _ ⟨y, rfl⟩ hxy - exact (h x y).resolve_left hxy + (range f).PairwiseDisjoint id ↔ ∀ x y, f x ≠ f y → Disjoint (f x) (f y) := by + aesop (add simp [PairwiseDisjoint, Set.Pairwise]) /-- If the range of `f` is pairwise disjoint, then the image of any set `s` under `f` is as well. -/ lemma _root_.Pairwise.pairwiseDisjoint (h : Pairwise (Disjoint on f)) (s : Set ι) : @@ -311,7 +307,7 @@ end PartialOrderBot section SemilatticeInfBot -variable [SemilatticeInf α] [OrderBot α] {s t : Set ι} {f g : ι → α} +variable [SemilatticeInf α] [OrderBot α] {s : Set ι} {f : ι → α} -- classical theorem PairwiseDisjoint.elim' (hs : s.PairwiseDisjoint f) {i j : ι} (hi : i ∈ s) (hj : j ∈ s) diff --git a/Mathlib/Data/Set/Pairwise/Lattice.lean b/Mathlib/Data/Set/Pairwise/Lattice.lean index 6e82a9acdc83d..c71e6effc0488 100644 --- a/Mathlib/Data/Set/Pairwise/Lattice.lean +++ b/Mathlib/Data/Set/Pairwise/Lattice.lean @@ -15,10 +15,10 @@ In this file we prove many facts about `Pairwise` and the set lattice. open Function Set Order -variable {α β γ ι ι' : Type*} {κ : Sort*} {r p q : α → α → Prop} +variable {α ι ι' : Type*} {κ : Sort*} {r : α → α → Prop} section Pairwise -variable {f g : ι → α} {s t u : Set α} {a b : α} +variable {f : ι → α} {s : Set α} namespace Set @@ -45,7 +45,7 @@ namespace Set section PartialOrderBot -variable [PartialOrder α] [OrderBot α] {s t : Set ι} {f g : ι → α} +variable [PartialOrder α] [OrderBot α] {s : Set ι} {f : ι → α} theorem pairwiseDisjoint_iUnion {g : ι' → Set ι} (h : Directed (· ⊆ ·) g) : (⋃ n, g n).PairwiseDisjoint f ↔ ∀ ⦃n⦄, (g n).PairwiseDisjoint f := diff --git a/Mathlib/Data/Set/Pointwise/Interval.lean b/Mathlib/Data/Set/Pointwise/Interval.lean index 7ee860b81b0d1..535b6e9100c34 100644 --- a/Mathlib/Data/Set/Pointwise/Interval.lean +++ b/Mathlib/Data/Set/Pointwise/Interval.lean @@ -37,8 +37,7 @@ the unprimed names have been reserved for section ContravariantLE -variable [Mul α] [Preorder α] -variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Function.swap HMul.hMul) LE.le] +variable [Mul α] [Preorder α] [MulLeftMono α] [MulRightMono α] @[to_additive Icc_add_Icc_subset] theorem Icc_mul_Icc_subset' (a b c d : α) : Icc a b * Icc c d ⊆ Icc (a * c) (b * d) := by @@ -59,54 +58,57 @@ end ContravariantLE section ContravariantLT -variable [Mul α] [PartialOrder α] -variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (Function.swap HMul.hMul) LT.lt] +variable [Mul α] [PartialOrder α] [MulLeftStrictMono α] [MulRightStrictMono α] @[to_additive Icc_add_Ico_subset] theorem Icc_mul_Ico_subset' (a b c d : α) : Icc a b * Ico c d ⊆ Ico (a * c) (b * d) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ @[to_additive Ico_add_Icc_subset] theorem Ico_mul_Icc_subset' (a b c d : α) : Ico a b * Icc c d ⊆ Ico (a * c) (b * d) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ @[to_additive Ioc_add_Ico_subset] theorem Ioc_mul_Ico_subset' (a b c d : α) : Ioc a b * Ico c d ⊆ Ioo (a * c) (b * d) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_lt_mul_of_lt_of_le hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ @[to_additive Ico_add_Ioc_subset] theorem Ico_mul_Ioc_subset' (a b c d : α) : Ico a b * Ioc c d ⊆ Ioo (a * c) (b * d) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_lt_mul_of_le_of_lt hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ @[to_additive Iic_add_Iio_subset] theorem Iic_mul_Iio_subset' (a b : α) : Iic a * Iio b ⊆ Iio (a * b) := by - haveI := covariantClass_le_of_lt + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_le_of_lt hya hzb @[to_additive Iio_add_Iic_subset] theorem Iio_mul_Iic_subset' (a b : α) : Iio a * Iic b ⊆ Iio (a * b) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_lt_of_le hya hzb @[to_additive Ioi_add_Ici_subset] theorem Ioi_mul_Ici_subset' (a b : α) : Ioi a * Ici b ⊆ Ioi (a * b) := by - haveI := covariantClass_le_of_lt + have := mulLeftMono_of_mulLeftStrictMono α rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_lt_of_le hya hzb @[to_additive Ici_add_Ioi_subset] theorem Ici_mul_Ioi_subset' (a b : α) : Ici a * Ioi b ⊆ Ioi (a * b) := by - haveI := covariantClass_le_of_lt + have := mulRightMono_of_mulRightStrictMono α rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_le_of_lt hya hzb @@ -304,10 +306,10 @@ theorem preimage_const_sub_Ioo : (fun x => a - x) ⁻¹' Ioo b c = Ioo (a - c) ( -/ --- @[simp] -- Porting note (#10618): simp can prove this modulo `add_comm` +-- simp can prove this modulo `add_comm` theorem image_const_add_Iic : (fun x => a + x) '' Iic b = Iic (a + b) := by simp [add_comm] --- @[simp] -- Porting note (#10618): simp can prove this modulo `add_comm` +-- simp can prove this modulo `add_comm` theorem image_const_add_Iio : (fun x => a + x) '' Iio b = Iio (a + b) := by simp [add_comm] /-! @@ -315,10 +317,8 @@ theorem image_const_add_Iio : (fun x => a + x) '' Iio b = Iio (a + b) := by simp -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem image_add_const_Iic : (fun x => x + a) '' Iic b = Iic (b + a) := by simp --- @[simp] -- Porting note (#10618): simp can prove this theorem image_add_const_Iio : (fun x => x + a) '' Iio b = Iio (b + a) := by simp /-! @@ -459,10 +459,9 @@ theorem preimage_const_sub_uIcc : (fun x => a - x) ⁻¹' [[b, c]] = [[a - b, a simp_rw [← Icc_min_max, preimage_const_sub_Icc] simp only [sub_eq_add_neg, min_add_add_left, max_add_add_left, min_neg_neg, max_neg_neg] --- @[simp] -- Porting note (#10618): simp can prove this module `add_comm` +-- simp can prove this modulo `add_comm` theorem image_const_add_uIcc : (fun x => a + x) '' [[b, c]] = [[a + b, a + c]] := by simp [add_comm] --- @[simp] -- Porting note (#10618): simp can prove this theorem image_add_const_uIcc : (fun x => x + a) '' [[b, c]] = [[b + a, c + a]] := by simp @[simp] @@ -670,6 +669,18 @@ theorem preimage_div_const_uIcc (ha : a ≠ 0) (b c : α) : (fun x => x / a) ⁻¹' [[b, c]] = [[b * a, c * a]] := by simp only [div_eq_mul_inv, preimage_mul_const_uIcc (inv_ne_zero ha), inv_inv] +lemma preimage_const_mul_Ioi_or_Iio (hb : a ≠ 0) {U V : Set α} + (hU : U ∈ {s | ∃ a, s = Ioi a ∨ s = Iio a}) (hV : V = HMul.hMul a ⁻¹' U) : + V ∈ {s | ∃ a, s = Ioi a ∨ s = Iio a} := by + obtain ⟨aU, (haU | haU)⟩ := hU <;> + simp only [hV, haU, mem_setOf_eq] <;> + use a⁻¹ * aU <;> + rcases lt_or_gt_of_ne hb with (hb | hb) + · right; rw [Set.preimage_const_mul_Ioi_of_neg _ hb, div_eq_inv_mul] + · left; rw [Set.preimage_const_mul_Ioi _ hb, div_eq_inv_mul] + · left; rw [Set.preimage_const_mul_Iio_of_neg _ hb, div_eq_inv_mul] + · right; rw [Set.preimage_const_mul_Iio _ hb, div_eq_inv_mul] + @[simp] theorem image_mul_const_uIcc (a b c : α) : (· * a) '' [[b, c]] = [[b * a, c * a]] := if ha : a = 0 then by simp [ha] @@ -718,9 +729,9 @@ theorem image_mul_left_Ioo {a : α} (h : 0 < a) (b c : α) : theorem inv_Ioo_0_left {a : α} (ha : 0 < a) : (Ioo 0 a)⁻¹ = Ioi a⁻¹ := by ext x exact - ⟨fun h => inv_inv x ▸ (inv_lt_inv ha h.1).2 h.2, fun h => + ⟨fun h => inv_inv x ▸ (inv_lt_inv₀ ha h.1).2 h.2, fun h => ⟨inv_pos.2 <| (inv_pos.2 ha).trans h, - inv_inv a ▸ (inv_lt_inv ((inv_pos.2 ha).trans h) + inv_inv a ▸ (inv_lt_inv₀ ((inv_pos.2 ha).trans h) (inv_pos.2 ha)).2 h⟩⟩ theorem inv_Ioi {a : α} (ha : 0 < a) : (Ioi a)⁻¹ = Ioo 0 a⁻¹ := by diff --git a/Mathlib/Data/Set/Pointwise/ListOfFn.lean b/Mathlib/Data/Set/Pointwise/ListOfFn.lean index 21e7712a88181..120059da9dfca 100644 --- a/Mathlib/Data/Set/Pointwise/ListOfFn.lean +++ b/Mathlib/Data/Set/Pointwise/ListOfFn.lean @@ -15,8 +15,7 @@ This file proves some lemmas about pointwise algebraic operations with lists of namespace Set -variable {F α β γ : Type*} -variable [Monoid α] {s t : Set α} {a : α} {m n : ℕ} +variable {α : Type*} [Monoid α] {s : Set α} {n : ℕ} open Pointwise diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index e3ed79c944b46..68200c4096290 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -7,6 +7,8 @@ import Mathlib.Algebra.Group.Pi.Basic import Mathlib.Algebra.Group.Pointwise.Set.Basic import Mathlib.Algebra.GroupWithZero.Action.Basic import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Ring.Opposite +import Mathlib.Algebra.NoZeroSMulDivisors.Defs import Mathlib.Data.Set.Pairwise.Basic /-! @@ -330,7 +332,7 @@ theorem smul_set_inter : a • (s ∩ t) = a • s ∩ a • t := image_inter <| MulAction.injective a @[to_additive] -theorem smul_set_iInter {ι : Type*} +theorem smul_set_iInter {ι : Sort*} (a : α) (t : ι → Set β) : (a • ⋂ i, t i) = ⋂ i, a • t i := image_iInter (MulAction.bijective a) t @@ -401,11 +403,48 @@ lemma inv_op_smul_set_distrib (a : α) (s : Set α) : (op a • s)⁻¹ = a⁻¹ ext; simp [mem_smul_set_iff_inv_smul_mem] @[to_additive (attr := simp)] -lemma smul_set_disjoint_iff : Disjoint (a • s) (a • t) ↔ Disjoint s t := by - simp [disjoint_iff, ← smul_set_inter] +lemma disjoint_smul_set : Disjoint (a • s) (a • t) ↔ Disjoint s t := + disjoint_image_iff <| MulAction.injective _ + +@[to_additive] +lemma disjoint_smul_set_left : Disjoint (a • s) t ↔ Disjoint s (a⁻¹ • t) := by + simpa using disjoint_smul_set (a := a) (t := a⁻¹ • t) + +@[to_additive] +lemma disjoint_smul_set_right : Disjoint s (a • t) ↔ Disjoint (a⁻¹ • s) t := by + simpa using disjoint_smul_set (a := a) (s := a⁻¹ • s) + +@[to_additive (attr := deprecated (since := "2024-10-18"))] +alias smul_set_disjoint_iff := disjoint_smul_set + +end Group + +section Group +variable [Group α] [CommGroup β] [FunLike F α β] [MonoidHomClass F α β] + +@[to_additive] +lemma smul_graphOn (x : α × β) (s : Set α) (f : F) : + x • s.graphOn f = (x.1 • s).graphOn fun a ↦ x.2 / f x.1 * f a := by + ext ⟨a, b⟩ + simp [mem_smul_set_iff_inv_smul_mem, Prod.ext_iff, and_comm (a := _ = a), inv_mul_eq_iff_eq_mul, + mul_left_comm _ _⁻¹, eq_inv_mul_iff_mul_eq, ← mul_div_right_comm, div_eq_iff_eq_mul, mul_comm b] + +@[to_additive] +lemma smul_graphOn_univ (x : α × β) (f : F) : + x • univ.graphOn f = univ.graphOn fun a ↦ x.2 / f x.1 * f a := by simp [smul_graphOn] end Group +section CommGroup +variable [CommGroup α] + +@[to_additive] lemma smul_div_smul_comm (a : α) (s : Set α) (b : α) (t : Set α) : + a • s / b • t = (a / b) • (s / t) := by + simp_rw [← image_smul, smul_eq_mul, ← singleton_mul, mul_div_mul_comm _ s, + singleton_div_singleton] + +end CommGroup + section GroupWithZero variable [GroupWithZero α] [MulAction α β] {s t : Set β} {a : α} diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index b1c42bc17e180..5464761ef4475 100644 --- a/Mathlib/Data/Set/Prod.lean +++ b/Mathlib/Data/Set/Prod.lean @@ -532,7 +532,7 @@ namespace Set section OffDiag -variable {α : Type*} {s t : Set α} {x : α × α} {a : α} +variable {α : Type*} {s t : Set α} {a : α} theorem offDiag_mono : Monotone (offDiag : Set α → Set (α × α)) := fun _ _ h _ => And.imp (@h _) <| And.imp_left <| @h _ @@ -686,15 +686,6 @@ theorem disjoint_pi : Disjoint (s.pi t₁) (s.pi t₂) ↔ ∃ i ∈ s, Disjoint end Nonempty --- Porting note: Removing `simp` - LHS does not simplify -theorem range_dcomp (f : ∀ i, α i → β i) : - (range fun g : ∀ i, α i => fun i => f i (g i)) = pi univ fun i => range (f i) := by - refine Subset.antisymm ?_ fun x hx => ?_ - · rintro _ ⟨x, rfl⟩ i - - exact ⟨x i, rfl⟩ - · choose y hy using hx - exact ⟨fun i => y i trivial, funext fun i => hy i trivial⟩ - @[simp] theorem insert_pi (i : ι) (s : Set ι) (t : ∀ i, Set (α i)) : pi (insert i s) t = eval i ⁻¹' t i ∩ pi s t := by @@ -809,8 +800,8 @@ theorem eval_image_univ_pi (ht : (pi univ t).Nonempty) : (fun f : ∀ i, α i => f i) '' pi univ t = t i := eval_image_pi (mem_univ i) ht -theorem dcomp_image_pi {f : ∀ i, α i → β i} (hf : ∀ i ∉ s, Surjective (f i)) (t : ∀ i, Set (α i)) : - (f _ ∘' ·) '' s.pi t = s.pi fun i ↦ f i '' t i := by +theorem piMap_image_pi {f : ∀ i, α i → β i} (hf : ∀ i ∉ s, Surjective (f i)) (t : ∀ i, Set (α i)) : + Pi.map f '' s.pi t = s.pi fun i ↦ f i '' t i := by refine Subset.antisymm (image_subset_iff.2 fun a ha i hi ↦ mem_image_of_mem _ (ha _ hi)) ?_ intro b hb have : ∀ i, ∃ a, f i a = b i ∧ (i ∈ s → a ∈ t i) := by @@ -822,9 +813,19 @@ theorem dcomp_image_pi {f : ∀ i, α i → β i} (hf : ∀ i ∉ s, Surjective choose a hab hat using this exact ⟨a, hat, funext hab⟩ -theorem dcomp_image_univ_pi (f : ∀ i, α i → β i) (t : ∀ i, Set (α i)) : - (f _ ∘' ·) '' univ.pi t = univ.pi fun i ↦ f i '' t i := - dcomp_image_pi (by simp) t +@[deprecated (since := "2024-10-06")] alias dcomp_image_pi := piMap_image_pi + +theorem piMap_image_univ_pi (f : ∀ i, α i → β i) (t : ∀ i, Set (α i)) : + Pi.map f '' univ.pi t = univ.pi fun i ↦ f i '' t i := + piMap_image_pi (by simp) t + +@[deprecated (since := "2024-10-06")] alias dcomp_image_univ_pi := piMap_image_univ_pi + +@[simp] +theorem range_piMap (f : ∀ i, α i → β i) : range (Pi.map f) = pi univ fun i ↦ range (f i) := by + simp only [← image_univ, ← piMap_image_univ_pi, pi_univ] + +@[deprecated (since := "2024-10-06")] alias range_dcomp := range_piMap theorem pi_subset_pi_iff : pi s t₁ ⊆ pi s t₂ ↔ (∀ i ∈ s, t₁ i ⊆ t₂ i) ∨ pi s t₁ = ∅ := by refine @@ -838,12 +839,12 @@ theorem univ_pi_subset_univ_pi_iff : pi univ t₁ ⊆ pi univ t₂ ↔ (∀ i, t₁ i ⊆ t₂ i) ∨ ∃ i, t₁ i = ∅ := by simp [pi_subset_pi_iff] theorem eval_preimage [DecidableEq ι] {s : Set (α i)} : - eval i ⁻¹' s = pi univ (update (fun i => univ) i s) := by + eval i ⁻¹' s = pi univ (update (fun _ => univ) i s) := by ext x simp [@forall_update_iff _ (fun i => Set (α i)) _ _ _ _ fun i' y => x i' ∈ y] theorem eval_preimage' [DecidableEq ι] {s : Set (α i)} : - eval i ⁻¹' s = pi {i} (update (fun i => univ) i s) := by + eval i ⁻¹' s = pi {i} (update (fun _ => univ) i s) := by ext simp diff --git a/Mathlib/Data/Set/Semiring.lean b/Mathlib/Data/Set/Semiring.lean index e6ff5cf305201..e275628926e7c 100644 --- a/Mathlib/Data/Set/Semiring.lean +++ b/Mathlib/Data/Set/Semiring.lean @@ -115,8 +115,8 @@ theorem _root_.Set.up_union (s t : Set α) : up (s ∪ t) = up s + up t := rfl /- Since addition on `SetSemiring` is commutative (it is set union), there is no need -to also have the instance `CovariantClass (SetSemiring α) (SetSemiring α) (swap (+)) (≤)`. -/ -instance covariantClass_add : CovariantClass (SetSemiring α) (SetSemiring α) (· + ·) (· ≤ ·) := +to also have the instance `AddRightMono (SetSemiring α)`. -/ +instance addLeftMono : AddLeftMono (SetSemiring α) := ⟨fun _ _ _ => union_subset_union_right _⟩ section Mul @@ -150,12 +150,10 @@ instance : NoZeroDivisors (SetSemiring α) := b.eq_empty_or_nonempty.resolve_right fun hb => Nonempty.ne_empty ⟨_, mul_mem_mul ha.some_mem hb.some_mem⟩ ab⟩ -instance covariantClass_mul_left : - CovariantClass (SetSemiring α) (SetSemiring α) (· * ·) (· ≤ ·) := +instance mulLeftMono : MulLeftMono (SetSemiring α) := ⟨fun _ _ _ => mul_subset_mul_left⟩ -instance covariantClass_mul_right : - CovariantClass (SetSemiring α) (SetSemiring α) (swap (· * ·)) (· ≤ ·) := +instance mulRightMono : MulRightMono (SetSemiring α) := ⟨fun _ _ _ => mul_subset_mul_right⟩ end Mul diff --git a/Mathlib/Data/Set/Subset.lean b/Mathlib/Data/Set/Subset.lean index 675ae793d1bc8..6672f997e1bd5 100644 --- a/Mathlib/Data/Set/Subset.lean +++ b/Mathlib/Data/Set/Subset.lean @@ -112,8 +112,10 @@ lemma image_val_union_self_left_eq : ↑D ∪ A = A := union_eq_right.2 image_val_subset @[simp] -lemma cou_inter_self_right_eq_coe : A ∩ ↑D = ↑D := +lemma image_val_inter_self_right_eq_coe : A ∩ ↑D = ↑D := inter_eq_right.2 image_val_subset +@[deprecated (since := "2024-10-25")] +alias cou_inter_self_right_eq_coe := image_val_inter_self_right_eq_coe @[simp] lemma image_val_inter_self_left_eq_coe : ↑D ∩ A = ↑D := diff --git a/Mathlib/Data/Set/SymmDiff.lean b/Mathlib/Data/Set/SymmDiff.lean new file mode 100644 index 0000000000000..7914ca1b3143d --- /dev/null +++ b/Mathlib/Data/Set/SymmDiff.lean @@ -0,0 +1,55 @@ +/- +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 +-/ +import Mathlib.Algebra.Group.ZeroOne +import Mathlib.Data.Set.Operations +import Mathlib.Order.Basic +import Mathlib.Order.BooleanAlgebra +import Mathlib.Logic.Equiv.Basic +import Mathlib.Tactic.Tauto +import Mathlib.Tactic.ByContra +import Mathlib.Util.Delaborators +import Mathlib.Order.SymmDiff +import Mathlib.Data.Set.Basic + +/-! # Symmetric differences of sets -/ + +namespace Set + +universe u v +variable {α : Type u} {β : Type v} {a b : α} {s s₁ s₂ t t₁ t₂ u : Set α} + +open scoped symmDiff + +theorem mem_symmDiff : a ∈ s ∆ t ↔ a ∈ s ∧ a ∉ t ∨ a ∈ t ∧ a ∉ s := + Iff.rfl + +protected theorem symmDiff_def (s t : Set α) : s ∆ t = s \ t ∪ t \ s := + rfl + +theorem symmDiff_subset_union : s ∆ t ⊆ s ∪ t := + @symmDiff_le_sup (Set α) _ _ _ + +@[simp] +theorem symmDiff_eq_empty : s ∆ t = ∅ ↔ s = t := + symmDiff_eq_bot + +@[simp] +theorem symmDiff_nonempty : (s ∆ t).Nonempty ↔ s ≠ t := + nonempty_iff_ne_empty.trans symmDiff_eq_empty.not + +theorem inter_symmDiff_distrib_left (s t u : Set α) : s ∩ t ∆ u = (s ∩ t) ∆ (s ∩ u) := + inf_symmDiff_distrib_left _ _ _ + +theorem inter_symmDiff_distrib_right (s t u : Set α) : s ∆ t ∩ u = (s ∩ u) ∆ (t ∩ u) := + inf_symmDiff_distrib_right _ _ _ + +theorem subset_symmDiff_union_symmDiff_left (h : Disjoint s t) : u ⊆ s ∆ u ∪ t ∆ u := + h.le_symmDiff_sup_symmDiff_left + +theorem subset_symmDiff_union_symmDiff_right (h : Disjoint t u) : s ⊆ s ∆ t ∪ s ∆ u := + h.le_symmDiff_sup_symmDiff_right + +end Set diff --git a/Mathlib/Data/SetLike/Basic.lean b/Mathlib/Data/SetLike/Basic.lean index 9613ca363c6b8..021b2c1a7978b 100644 --- a/Mathlib/Data/SetLike/Basic.lean +++ b/Mathlib/Data/SetLike/Basic.lean @@ -3,9 +3,9 @@ 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.Data.Set.Basic import Mathlib.Tactic.Monotonicity.Attr import Mathlib.Tactic.SetLike +import Mathlib.Data.Set.Basic /-! # Typeclass for types with a set-like extensionality property @@ -28,7 +28,7 @@ boilerplate for every `SetLike`: a `coe_sort`, a `coe` to set, a A typical subobject should be declared as: ``` -structure MySubobject (X : Type*) [ObjectTypeclass X] := +structure MySubobject (X : Type*) [ObjectTypeclass X] where (carrier : Set X) (op_mem' : ∀ {x : X}, x ∈ carrier → sorry ∈ carrier) @@ -60,7 +60,7 @@ end MySubobject An alternative to `SetLike` could have been an extensional `Membership` typeclass: ``` -class ExtMembership (α : out_param <| Type u) (β : Type v) extends Membership α β := +class ExtMembership (α : out_param <| Type u) (β : Type v) extends Membership α β where (ext_iff : ∀ {s t : β}, s = t ↔ ∀ (x : α), x ∈ s ↔ x ∈ t) ``` While this is equivalent, `SetLike` conveniently uses a carrier set projection directly. diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index 4f812be71f3cd..e4b60325f1b21 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -15,9 +15,6 @@ theorems for quotients of arbitrary types. ## Implementation notes -The function `Rel` and lemmas ending in ' make it easier to talk about different -equivalence relations on the same type. - The complete lattice instance for equivalence relations could have been defined by lifting 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 @@ -39,47 +36,57 @@ attribute [trans] Setoid.trans variable {α : Type*} {β : Type*} /-- A version of `Setoid.r` that takes the equivalence relation as an explicit argument. -/ +@[deprecated (since := "2024-08-29")] def Setoid.Rel (r : Setoid α) : α → α → Prop := @Setoid.r _ r +set_option linter.deprecated false in +@[deprecated (since := "2024-10-09")] instance Setoid.decidableRel (r : Setoid α) [h : DecidableRel r.r] : DecidableRel r.Rel := h +set_option linter.deprecated false in /-- A version of `Quotient.eq'` compatible with `Setoid.Rel`, to make rewriting possible. -/ +@[deprecated Quotient.eq' (since := "2024-10-09")] theorem Quotient.eq_rel {r : Setoid α} {x y} : (Quotient.mk' x : Quotient r) = Quotient.mk' y ↔ r.Rel x y := Quotient.eq namespace Setoid -@[ext] +attribute [ext] ext + +set_option linter.deprecated false in +@[deprecated Setoid.ext (since := "2024-10-09")] theorem ext' {r s : Setoid α} (H : ∀ a b, r.Rel a b ↔ s.Rel a b) : r = s := ext H -theorem ext_iff {r s : Setoid α} : r = s ↔ ∀ a b, r.Rel a b ↔ s.Rel a b := +set_option linter.deprecated false in +@[deprecated Setoid.ext_iff (since := "2024-10-09")] +theorem ext'_iff {r s : Setoid α} : r = s ↔ ∀ a b, r.Rel a b ↔ s.Rel a b := ⟨fun h _ _ => h ▸ Iff.rfl, ext'⟩ /-- Two equivalence relations are equal iff their underlying binary operations are equal. -/ -theorem eq_iff_rel_eq {r₁ r₂ : Setoid α} : r₁ = r₂ ↔ r₁.Rel = r₂.Rel := - ⟨fun h => h ▸ rfl, fun h => Setoid.ext' fun _ _ => h ▸ Iff.rfl⟩ +theorem eq_iff_rel_eq {r₁ r₂ : Setoid α} : r₁ = r₂ ↔ ⇑r₁ = ⇑r₂ := + ⟨fun h => h ▸ rfl, fun h => Setoid.ext fun _ _ => h ▸ Iff.rfl⟩ /-- Defining `≤` for equivalence relations. -/ instance : LE (Setoid α) := - ⟨fun r s => ∀ ⦃x y⦄, r.Rel x y → s.Rel x y⟩ + ⟨fun r s => ∀ ⦃x y⦄, r x y → s x y⟩ -theorem le_def {r s : Setoid α} : r ≤ s ↔ ∀ {x y}, r.Rel x y → s.Rel x y := +theorem le_def {r s : Setoid α} : r ≤ s ↔ ∀ {x y}, r x y → s x y := Iff.rfl @[refl] -theorem refl' (r : Setoid α) (x) : r.Rel x x := r.iseqv.refl x +theorem refl' (r : Setoid α) (x) : r x x := r.iseqv.refl x @[symm] -theorem symm' (r : Setoid α) : ∀ {x y}, r.Rel x y → r.Rel y x := r.iseqv.symm +theorem symm' (r : Setoid α) : ∀ {x y}, r x y → r y x := r.iseqv.symm @[trans] -theorem trans' (r : Setoid α) : ∀ {x y z}, r.Rel x y → r.Rel y z → r.Rel x z := r.iseqv.trans +theorem trans' (r : Setoid α) : ∀ {x y z}, r x y → r y z → r x z := r.iseqv.trans -theorem comm' (s : Setoid α) {x y} : s.Rel x y ↔ s.Rel y x := +theorem comm' (s : Setoid α) {x y} : s x y ↔ s y x := ⟨s.symm', s.symm'⟩ /-- The kernel of a function is an equivalence relation. -/ @@ -89,16 +96,16 @@ def ker (f : α → β) : Setoid α := /-- The kernel of the quotient map induced by an equivalence relation r equals r. -/ @[simp] theorem ker_mk_eq (r : Setoid α) : ker (@Quotient.mk'' _ r) = r := - ext' fun _ _ => Quotient.eq + ext fun _ _ => Quotient.eq -theorem ker_apply_mk_out {f : α → β} (a : α) : f (haveI := Setoid.ker f; ⟦a⟧.out) = f a := +theorem ker_apply_mk_out {f : α → β} (a : α) : f (⟦a⟧ : Quotient (Setoid.ker f)).out = f a := @Quotient.mk_out _ (Setoid.ker f) a theorem ker_apply_mk_out' {f : α → β} (a : α) : f (Quotient.mk _ a : Quotient <| Setoid.ker f).out' = f a := @Quotient.mk_out' _ (Setoid.ker f) a -theorem ker_def {f : α → β} {x y : α} : (ker f).Rel x y ↔ f x = f y := +theorem ker_def {f : α → β} {x y : α} : ker f x y ↔ f x = f y := Iff.rfl /-- Given types `α`, `β`, the product of two equivalence relations `r` on `α` and `s` on `β`: @@ -106,36 +113,79 @@ theorem ker_def {f : α → β} {x y : α} : (ker f).Rel x y ↔ f x = f y := by `r` and `x₂` is related to `y₂` by `s`. -/ protected def prod (r : Setoid α) (s : Setoid β) : Setoid (α × β) where - r x y := r.Rel x.1 y.1 ∧ s.Rel x.2 y.2 + r x y := r x.1 y.1 ∧ s x.2 y.2 iseqv := ⟨fun x => ⟨r.refl' x.1, s.refl' x.2⟩, fun h => ⟨r.symm' h.1, s.symm' h.2⟩, fun h₁ h₂ => ⟨r.trans' h₁.1 h₂.1, s.trans' h₁.2 h₂.2⟩⟩ +lemma prod_apply {r : Setoid α} {s : Setoid β} {x₁ x₂ : α} {y₁ y₂ : β} : + @Setoid.r _ (r.prod s) (x₁, y₁) (x₂, y₂) ↔ (@Setoid.r _ r x₁ x₂ ∧ @Setoid.r _ s y₁ y₂) := + Iff.rfl + +lemma piSetoid_apply {ι : Sort*} {α : ι → Sort*} {r : ∀ i, Setoid (α i)} {x y : ∀ i, α i} : + @Setoid.r _ (@piSetoid _ _ r) x y ↔ ∀ i, @Setoid.r _ (r i) (x i) (y i) := + Iff.rfl + +/-- A bijection between the product of two quotients and the quotient by the product of the +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 + 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 + rcases q with ⟨qa, qb⟩ + exact Quotient.inductionOn₂' qa qb fun _ _ ↦ rfl + right_inv := fun q ↦ by + simp only + refine Quotient.inductionOn' q fun _ ↦ rfl + +/-- A bijection between an indexed product of quotients and the quotient by the product of the +equivalence relations. -/ +@[simps] +noncomputable def piQuotientEquiv {ι : Sort*} {α : ι → Sort*} (r : ∀ i, Setoid (α i)) : + (∀ i, Quotient (r i)) ≃ Quotient (@piSetoid _ _ r) where + toFun := fun x ↦ Quotient.mk'' fun i ↦ (x i).out' + invFun := fun q ↦ Quotient.liftOn' q (fun x i ↦ Quotient.mk'' (x i)) fun x y hxy ↦ by + ext i + simpa using hxy i + left_inv := fun q ↦ by + ext i + simp + right_inv := fun q ↦ by + refine Quotient.inductionOn' q fun _ ↦ ?_ + simp only [Quotient.liftOn'_mk'', Quotient.eq''] + intro i + change Setoid.r _ _ + rw [← Quotient.eq''] + simp + /-- The infimum of two equivalence relations. -/ instance : Inf (Setoid α) := ⟨fun r s => - ⟨fun x y => r.Rel x y ∧ s.Rel x y, + ⟨fun x y => r x y ∧ s x y, ⟨fun x => ⟨r.refl' x, s.refl' x⟩, fun h => ⟨r.symm' h.1, s.symm' h.2⟩, fun h1 h2 => ⟨r.trans' h1.1 h2.1, s.trans' h1.2 h2.2⟩⟩⟩⟩ /-- The infimum of 2 equivalence relations r and s is the same relation as the infimum of the underlying binary operations. -/ -theorem inf_def {r s : Setoid α} : (r ⊓ s).Rel = r.Rel ⊓ s.Rel := +theorem inf_def {r s : Setoid α} : ⇑(r ⊓ s) = ⇑r ⊓ ⇑s := rfl -theorem inf_iff_and {r s : Setoid α} {x y} : (r ⊓ s).Rel x y ↔ r.Rel x y ∧ s.Rel x y := +theorem inf_iff_and {r s : Setoid α} {x y} : (r ⊓ s) x y ↔ r x y ∧ s x y := Iff.rfl /-- The infimum of a set of equivalence relations. -/ instance : InfSet (Setoid α) := ⟨fun S => - { r := fun x y => ∀ r ∈ S, r.Rel x y + { r := fun x y => ∀ r ∈ S, r x y iseqv := ⟨fun x r _ => r.refl' x, fun h r hr => r.symm' <| h r hr, fun h1 h2 r hr => r.trans' (h1 r hr) <| h2 r hr⟩ }⟩ /-- The underlying binary operation of the infimum of a set of equivalence relations is the infimum of the set's image under the map to the underlying binary operation. -/ -theorem sInf_def {s : Set (Setoid α)} : (sInf s).Rel = sInf (Rel '' s) := by +theorem sInf_def {s : Set (Setoid α)} : ⇑(sInf s) = sInf ((⇑) '' s) := by ext simp only [sInf_image, iInf_apply, iInf_Prop_eq] rfl @@ -146,7 +196,7 @@ instance : PartialOrder (Setoid α) where le_refl _ _ _ := id le_trans _ _ _ hr hs _ _ h := hs <| hr h lt_iff_le_not_le _ _ := Iff.rfl - le_antisymm _ _ h1 h2 := Setoid.ext' fun _ _ => ⟨fun h => h1 h, fun h => h2 h⟩ + le_antisymm _ _ h1 h2 := Setoid.ext fun _ _ => ⟨fun h => h1 h, fun h => h2 h⟩ /-- The complete lattice of equivalence relations on a type, with bottom element `=` and top element the trivial equivalence relation. -/ @@ -163,24 +213,27 @@ instance completeLattice : CompleteLattice (Setoid α) := bot_le := fun r x _ h => h ▸ r.2.1 x } @[simp] -theorem top_def : (⊤ : Setoid α).Rel = ⊤ := +theorem top_def : ⇑(⊤ : Setoid α) = ⊤ := rfl @[simp] -theorem bot_def : (⊥ : Setoid α).Rel = (· = ·) := +theorem bot_def : ⇑(⊥ : Setoid α) = (· = ·) := rfl -theorem eq_top_iff {s : Setoid α} : s = (⊤ : Setoid α) ↔ ∀ x y : α, s.Rel x y := by +theorem eq_top_iff {s : Setoid α} : s = (⊤ : Setoid α) ↔ ∀ x y : α, s x y := by rw [_root_.eq_top_iff, Setoid.le_def, Setoid.top_def] simp only [Pi.top_apply, Prop.top_eq_true, forall_true_left] lemma sInf_equiv {S : Set (Setoid α)} {x y : α} : letI := sInf S - x ≈ y ↔ ∀ s ∈ S, s.Rel x y := Iff.rfl + x ≈ y ↔ ∀ s ∈ S, s x y := Iff.rfl + +lemma sInf_iff {S : Set (Setoid α)} {x y : α} : + sInf S x y ↔ ∀ s ∈ S, s x y := Iff.rfl lemma quotient_mk_sInf_eq {S : Set (Setoid α)} {x y : α} : - Quotient.mk (sInf S) x = Quotient.mk (sInf S) y ↔ ∀ s ∈ S, s.Rel x y := by - simp [sInf_equiv] + Quotient.mk (sInf S) x = Quotient.mk (sInf S) y ↔ ∀ s ∈ S, s x y := by + simp [sInf_iff] /-- The map induced between quotients by a setoid inequality. -/ def map_of_le {s t : Setoid α} (h : s ≤ t) : Quotient s → Quotient t := @@ -199,7 +252,7 @@ open Relation /-- The inductively defined equivalence closure of a binary relation r is the infimum of the set of all equivalence relations containing r. -/ theorem eqvGen_eq (r : α → α → Prop) : - EqvGen.setoid r = sInf { s : Setoid α | ∀ ⦃x y⦄, r x y → s.Rel x y } := + EqvGen.setoid r = sInf { s : Setoid α | ∀ ⦃x y⦄, r x y → s x y } := le_antisymm (fun _ _ H => EqvGen.rec (fun _ _ h _ hs => hs h) (refl' _) (fun _ _ _ => symm' _) @@ -209,20 +262,20 @@ theorem eqvGen_eq (r : α → α → Prop) : /-- The supremum of two equivalence relations r and s is the equivalence closure of the binary relation `x is related to y by r or s`. -/ theorem sup_eq_eqvGen (r s : Setoid α) : - r ⊔ s = EqvGen.setoid fun x y => r.Rel x y ∨ s.Rel x y := by + r ⊔ s = EqvGen.setoid fun x y => r x y ∨ s x y := by rw [eqvGen_eq] apply congr_arg sInf simp only [le_def, or_imp, ← forall_and] /-- The supremum of 2 equivalence relations r and s is the equivalence closure of the supremum of the underlying binary operations. -/ -theorem sup_def {r s : Setoid α} : r ⊔ s = EqvGen.setoid (r.Rel ⊔ s.Rel) := by +theorem sup_def {r s : Setoid α} : r ⊔ s = EqvGen.setoid (⇑r ⊔ ⇑s) := by rw [sup_eq_eqvGen]; rfl /-- The supremum of a set S of equivalence relations is the equivalence closure of the binary relation `there exists r ∈ S relating x and y`. -/ theorem sSup_eq_eqvGen (S : Set (Setoid α)) : - sSup S = EqvGen.setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by + sSup S = EqvGen.setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r x y := by rw [eqvGen_eq] apply congr_arg sInf simp only [upperBounds, le_def, and_imp, exists_imp] @@ -231,7 +284,7 @@ theorem sSup_eq_eqvGen (S : Set (Setoid α)) : /-- The supremum of a set of equivalence relations is the equivalence closure of the supremum of the set's image under the map to the underlying binary operation. -/ -theorem sSup_def {s : Set (Setoid α)} : sSup s = EqvGen.setoid (sSup (Rel '' s)) := by +theorem sSup_def {s : Set (Setoid α)} : sSup s = EqvGen.setoid (sSup ((⇑) '' s)) := by rw [sSup_eq_eqvGen, sSup_image] congr with (x y) simp only [iSup_apply, iSup_Prop_eq, exists_prop] @@ -242,13 +295,12 @@ theorem eqvGen_of_setoid (r : Setoid α) : EqvGen.setoid r.r = r := le_antisymm (by rw [eqvGen_eq]; exact sInf_le fun _ _ => id) EqvGen.rel /-- Equivalence closure is idempotent. -/ -@[simp] -theorem eqvGen_idem (r : α → α → Prop) : EqvGen.setoid (EqvGen.setoid r).Rel = EqvGen.setoid r := +theorem eqvGen_idem (r : α → α → Prop) : EqvGen.setoid (EqvGen.setoid r) = EqvGen.setoid r := eqvGen_of_setoid _ /-- The equivalence closure of a binary relation r is contained in any equivalence relation containing r. -/ -theorem eqvGen_le {r : α → α → Prop} {s : Setoid α} (h : ∀ x y, r x y → s.Rel x y) : +theorem eqvGen_le {r : α → α → Prop} {s : Setoid α} (h : ∀ x y, r x y → s x y) : EqvGen.setoid r ≤ s := by rw [eqvGen_eq]; exact sInf_le h /-- Equivalence closure of binary relations is monotone. -/ @@ -258,7 +310,7 @@ theorem eqvGen_mono {r s : α → α → Prop} (h : ∀ x y, r x y → s x y) : /-- There is a Galois insertion of equivalence relations on α into binary relations on α, with equivalence closure the lower adjoint. -/ -def gi : @GaloisInsertion (α → α → Prop) (Setoid α) _ _ EqvGen.setoid Rel where +def gi : @GaloisInsertion (α → α → Prop) (Setoid α) _ _ EqvGen.setoid (⇑) where choice r _ := EqvGen.setoid r gc _ s := ⟨fun H _ _ h => H <| EqvGen.rel _ _ h, fun H => eqvGen_of_setoid s ▸ eqvGen_mono H⟩ le_l_u x := (eqvGen_of_setoid x).symm ▸ le_refl x @@ -274,7 +326,7 @@ theorem injective_iff_ker_bot (f : α → β) : Injective f ↔ ker f = ⊥ := (@eq_bot_iff (Setoid α) _ _ (ker f)).symm /-- The elements related to x ∈ α by the kernel of f are those in the preimage of f(x) under f. -/ -theorem ker_iff_mem_preimage {f : α → β} {x y} : (ker f).Rel x y ↔ x ∈ f ⁻¹' {f y} := +theorem ker_iff_mem_preimage {f : α → β} {x y} : ker f x y ↔ x ∈ f ⁻¹' {f y} := Iff.rfl /-- Equivalence between functions `α → β` such that `r x y → f x = f y` and functions @@ -282,8 +334,8 @@ theorem ker_iff_mem_preimage {f : α → β} {x y} : (ker f).Rel x y ↔ x ∈ f def liftEquiv (r : Setoid α) : { f : α → β // r ≤ ker f } ≃ (Quotient r → β) where toFun f := Quotient.lift (f : α → β) f.2 invFun f := ⟨f ∘ Quotient.mk'', fun x y h => by simp [ker_def, Quotient.sound' h]⟩ - left_inv := fun ⟨f, hf⟩ => Subtype.eq <| funext fun x => rfl - right_inv f := funext fun x => Quotient.inductionOn' x fun x => rfl + left_inv := fun ⟨_, _⟩ => Subtype.eq <| funext fun _ => rfl + right_inv _ := funext fun x => Quotient.inductionOn' x fun _ => rfl /-- The uniqueness part of the universal property for quotients of an arbitrary type. -/ theorem lift_unique {r : Setoid α} {f : α → β} (H : r ≤ ker f) (g : Quotient r → β) @@ -299,7 +351,7 @@ theorem ker_lift_injective (f : α → β) : Injective (@Quotient.lift _ _ (ker /-- Given a map f from α to β, the kernel of f is the unique equivalence relation on α whose induced map from the quotient of α to β is injective. -/ -theorem ker_eq_lift_of_injective {r : Setoid α} (f : α → β) (H : ∀ x y, r.Rel x y → f x = f y) +theorem ker_eq_lift_of_injective {r : Setoid α} (f : α → β) (H : ∀ x y, r x y → f x = f y) (h : Injective (Quotient.lift f H)) : ker f = r := le_antisymm (fun x y hk => @@ -315,7 +367,7 @@ noncomputable def quotientKerEquivRange : Quotient (ker f) ≃ Set.range f := ((@Quotient.lift _ (Set.range f) (ker f) fun x => ⟨f x, Set.mem_range_self x⟩) fun _ _ h => Subtype.ext_val h) ⟨fun x y h => ker_lift_injective f <| by rcases x with ⟨⟩; rcases y with ⟨⟩; injections, - fun ⟨w, z, hz⟩ => + fun ⟨_, z, hz⟩ => ⟨@Quotient.mk'' _ (ker f) z, Subtype.ext_iff_val.2 hz⟩⟩ /-- If `f` has a computable right-inverse, then the quotient by its kernel is equivalent to its @@ -341,13 +393,13 @@ variable {r f} closure of the relation on `f`'s image defined by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` by `r`.' -/ def map (r : Setoid α) (f : α → β) : Setoid β := - Relation.EqvGen.setoid fun x y => ∃ a b, f a = x ∧ f b = y ∧ r.Rel a b + Relation.EqvGen.setoid fun x y => ∃ a b, f a = x ∧ f b = y ∧ r a b /-- Given a surjective function f whose kernel is contained in an equivalence relation r, the equivalence relation on f's codomain defined by x ≈ y ↔ the elements of f⁻¹(x) are related to the elements of f⁻¹(y) by r. -/ def mapOfSurjective (r) (f : α → β) (h : ker f ≤ r) (hf : Surjective f) : Setoid β := - ⟨fun x y => ∃ a b, f a = x ∧ f b = y ∧ r.Rel a b, + ⟨fun x y => ∃ a b, f a = x ∧ f b = y ∧ r a b, ⟨fun x => let ⟨y, hy⟩ := hf x ⟨y, y, hy, hy, r.refl' y⟩, @@ -365,9 +417,9 @@ relation on `α` defined by '`x ≈ y` iff `f(x)` is related to `f(y)` by `r`'. See note [reducible non-instances]. -/ abbrev comap (f : α → β) (r : Setoid β) : Setoid α := - ⟨r.Rel on f, r.iseqv.comap _⟩ + ⟨r on f, r.iseqv.comap _⟩ -theorem comap_rel (f : α → β) (r : Setoid β) (x y : α) : (comap f r).Rel x y ↔ r.Rel (f x) (f y) := +theorem comap_rel (f : α → β) (r : Setoid β) (x y : α) : comap f r x y ↔ r (f x) (f y) := Iff.rfl /-- Given a map `f : N → M` and an equivalence relation `r` on `β`, the equivalence relation @@ -378,7 +430,8 @@ theorem comap_eq {f : α → β} {r : Setoid β} : comap f r = ker (@Quotient.mk /-- The second isomorphism theorem for sets. -/ noncomputable def comapQuotientEquiv (f : α → β) (r : Setoid β) : Quotient (comap f r) ≃ Set.range (@Quotient.mk'' _ r ∘ f) := - (Quotient.congrRight <| ext_iff.1 comap_eq).trans <| quotientKerEquivRange <| Quotient.mk'' ∘ f + (Quotient.congrRight <| Setoid.ext_iff.1 comap_eq).trans <| quotientKerEquivRange <| + Quotient.mk'' ∘ f variable (r f) @@ -387,11 +440,11 @@ def quotientQuotientEquivQuotient (s : Setoid α) (h : r ≤ s) : Quotient (ker (Quot.mapRight h)) ≃ Quotient s where toFun x := (Quotient.liftOn' x fun w => - (Quotient.liftOn' w (@Quotient.mk'' _ s)) fun x y H => Quotient.sound <| h H) - fun x y => Quotient.inductionOn₂' x y fun w z H => show @Quot.mk _ _ _ = @Quot.mk _ _ _ from H + (Quotient.liftOn' w (@Quotient.mk'' _ s)) fun _ _ H => Quotient.sound <| h H) + fun x y => Quotient.inductionOn₂' x y fun _ _ H => show @Quot.mk _ _ _ = @Quot.mk _ _ _ from H invFun x := (Quotient.liftOn' x fun w => @Quotient.mk'' _ (ker <| Quot.mapRight h) <| @Quotient.mk'' _ r w) - fun x y H => Quotient.sound' <| show @Quot.mk _ _ _ = @Quot.mk _ _ _ from Quotient.sound H + fun _ _ H => Quotient.sound' <| show @Quot.mk _ _ _ = @Quot.mk _ _ _ from Quotient.sound H left_inv x := Quotient.inductionOn' x fun y => Quotient.inductionOn' y fun w => by show ⟦_⟧ = _; rfl right_inv x := Quotient.inductionOn' x fun y => by show ⟦_⟧ = _; rfl @@ -408,9 +461,9 @@ def correspondence (r : Setoid α) : { s // r ≤ s } ≃o Setoid (Quotient r) w (fun h ↦ s.1.trans' (s.1.trans' (s.2 h₁) h) (s.1.symm' (s.2 h₂))), ⟨Quotient.ind s.1.2.1, @fun x y ↦ Quotient.inductionOn₂ x y fun _ _ ↦ s.1.2.2, @fun x y z ↦ Quotient.inductionOn₃ x y z fun _ _ _ ↦ s.1.2.3⟩⟩ - invFun s := ⟨comap Quotient.mk' s, fun x y h => by rw [comap_rel, eq_rel.2 h]⟩ - left_inv s := rfl - right_inv s := ext fun x y ↦ Quotient.inductionOn₂ x y fun _ _ ↦ Iff.rfl + invFun s := ⟨comap Quotient.mk' s, fun x y h => by rw [comap_rel, Quotient.eq'.2 h]⟩ + left_inv _ := rfl + right_inv _ := ext fun x y ↦ Quotient.inductionOn₂ x y fun _ _ ↦ Iff.rfl map_rel_iff' := ⟨fun h x y hs ↦ @h ⟦x⟧ ⟦y⟧ hs, fun h x y ↦ Quotient.inductionOn₂ x y fun _ _ hs ↦ h hs⟩ @@ -432,7 +485,6 @@ theorem Quotient.subsingleton_iff {s : Setoid α} : Subsingleton (Quotient s) refine (surjective_quotient_mk' _).forall.trans (forall_congr' fun a => ?_) refine (surjective_quotient_mk' _).forall.trans (forall_congr' fun b => ?_) simp_rw [Prop.top_eq_true, true_implies, Quotient.eq'] - rfl theorem Quot.subsingleton_iff (r : α → α → Prop) : Subsingleton (Quot r) ↔ Relation.EqvGen r = ⊤ := by diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index 1cc028237c179..27e668bcb2ece 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -49,13 +49,13 @@ def mkClasses (c : Set (Set α)) (H : ∀ a, ∃! b ∈ c, a ∈ b) : Setoid α iseqv.symm := fun {x _y} h s hs hy => by obtain ⟨t, ⟨ht, hx⟩, _⟩ := H x rwa [eq_of_mem_eqv_class H hs hy ht (h t ht hx)] - iseqv.trans := fun {_x y z} h1 h2 s hs hx => h2 s hs (h1 s hs hx) + iseqv.trans := fun {_x _ _} h1 h2 s hs hx => h2 s hs (h1 s hs hx) /-- Makes the equivalence classes of an equivalence relation. -/ def classes (r : Setoid α) : Set (Set α) := - { s | ∃ y, s = { x | r.Rel x y } } + { s | ∃ y, s = { x | r x y } } -theorem mem_classes (r : Setoid α) (y) : { x | r.Rel x y } ∈ r.classes := +theorem mem_classes (r : Setoid α) (y) : { x | r x y } ∈ r.classes := ⟨y, rfl⟩ theorem classes_ker_subset_fiber_set {β : Type*} (f : α → β) : @@ -74,17 +74,17 @@ theorem card_classes_ker_le {α β : Type*} [Fintype β] (f : α → β) /-- Two equivalence relations are equal iff all their equivalence classes are equal. -/ theorem eq_iff_classes_eq {r₁ r₂ : Setoid α} : - r₁ = r₂ ↔ ∀ x, { y | r₁.Rel x y } = { y | r₂.Rel x y } := - ⟨fun h _x => h ▸ rfl, fun h => ext' fun x => Set.ext_iff.1 <| h x⟩ + r₁ = r₂ ↔ ∀ x, { y | r₁ x y } = { y | r₂ x y } := + ⟨fun h _x => h ▸ rfl, fun h => ext fun x => Set.ext_iff.1 <| h x⟩ -theorem rel_iff_exists_classes (r : Setoid α) {x y} : r.Rel x y ↔ ∃ c ∈ r.classes, x ∈ c ∧ y ∈ c := +theorem rel_iff_exists_classes (r : Setoid α) {x y} : r x y ↔ ∃ c ∈ r.classes, x ∈ c ∧ y ∈ c := ⟨fun h => ⟨_, r.mem_classes y, h, r.refl' y⟩, fun ⟨c, ⟨z, hz⟩, hx, hy⟩ => by subst c exact r.trans' hx (r.symm' hy)⟩ /-- Two equivalence relations are equal iff their equivalence classes are equal. -/ theorem classes_inj {r₁ r₂ : Setoid α} : r₁ = r₂ ↔ r₁.classes = r₂.classes := - ⟨fun h => h ▸ rfl, fun h => ext' fun a b => by simp only [rel_iff_exists_classes, exists_prop, h]⟩ + ⟨fun h => h ▸ rfl, fun h => ext fun a b => by simp only [rel_iff_exists_classes, exists_prop, h]⟩ /-- The empty set is not an equivalence class. -/ theorem empty_not_mem_classes {r : Setoid α} : ∅ ∉ r.classes := fun ⟨y, hy⟩ => @@ -92,7 +92,7 @@ theorem empty_not_mem_classes {r : Setoid α} : ∅ ∉ r.classes := fun ⟨y, h /-- Equivalence classes partition the type. -/ theorem classes_eqv_classes {r : Setoid α} (a) : ∃! b ∈ r.classes, a ∈ b := - ExistsUnique.intro { x | r.Rel x a } ⟨r.mem_classes a, r.refl' _⟩ <| by + ExistsUnique.intro { x | r x a } ⟨r.mem_classes a, r.refl' _⟩ <| by rintro y ⟨⟨_, rfl⟩, ha⟩ ext x exact ⟨fun hx => r.trans' hx (r.symm' ha), fun hx => r.trans' hx ha⟩ @@ -105,7 +105,7 @@ theorem eq_of_mem_classes {r : Setoid α} {x b} (hc : b ∈ r.classes) (hb : x /-- The elements of a set of sets partitioning α are the equivalence classes of the equivalence relation defined by the set of sets. -/ theorem eq_eqv_class_of_mem {c : Set (Set α)} (H : ∀ a, ∃! b ∈ c, a ∈ b) {s y} - (hs : s ∈ c) (hy : y ∈ s) : s = { x | (mkClasses c H).Rel x y } := by + (hs : s ∈ c) (hy : y ∈ s) : s = { x | mkClasses c H x y } := by ext x constructor · intro hx _s' hs' hx' @@ -117,11 +117,11 @@ theorem eq_eqv_class_of_mem {c : Set (Set α)} (H : ∀ a, ∃! b ∈ c, a ∈ b /-- The equivalence classes of the equivalence relation defined by a set of sets partitioning α are elements of the set of sets. -/ theorem eqv_class_mem {c : Set (Set α)} (H : ∀ a, ∃! b ∈ c, a ∈ b) {y} : - { x | (mkClasses c H).Rel x y } ∈ c := + { x | mkClasses c H x y } ∈ c := (H y).elim fun _ hc _ => eq_eqv_class_of_mem H hc.1 hc.2 ▸ hc.1 theorem eqv_class_mem' {c : Set (Set α)} (H : ∀ a, ∃! b ∈ c, a ∈ b) {x} : - { y : α | (mkClasses c H).Rel x y } ∈ c := by + { y : α | mkClasses c H x y } ∈ c := by convert @Setoid.eqv_class_mem _ _ H x using 3 rw [Setoid.comm'] @@ -135,7 +135,7 @@ theorem eqv_classes_disjoint {c : Set (Set α)} (H : ∀ a, ∃! b ∈ c, a ∈ theorem eqv_classes_of_disjoint_union {c : Set (Set α)} (hu : Set.sUnion c = @Set.univ α) (H : c.PairwiseDisjoint id) (a) : ∃! b ∈ c, a ∈ b := let ⟨b, hc, ha⟩ := Set.mem_sUnion.1 <| show a ∈ _ by rw [hu]; exact Set.mem_univ a - ExistsUnique.intro b ⟨hc, ha⟩ fun b' hc' => H.elim_set hc'.1 hc _ hc'.2 ha + ExistsUnique.intro b ⟨hc, ha⟩ fun _ hc' => H.elim_set hc'.1 hc _ hc'.2 ha /-- Makes an equivalence relation from a set of disjoints sets covering α. -/ def setoidOfDisjointUnion {c : Set (Set α)} (hu : Set.sUnion c = @Set.univ α) @@ -145,19 +145,19 @@ def setoidOfDisjointUnion {c : Set (Set α)} (hu : Set.sUnion c = @Set.univ α) /-- The equivalence relation made from the equivalence classes of an equivalence relation r equals r. -/ theorem mkClasses_classes (r : Setoid α) : mkClasses r.classes classes_eqv_classes = r := - ext' fun x _y => - ⟨fun h => r.symm' (h { z | r.Rel z x } (r.mem_classes x) <| r.refl' x), fun h _b hb hx => + ext fun x _y => + ⟨fun h => r.symm' (h { z | r z x } (r.mem_classes x) <| r.refl' x), fun h _b hb hx => eq_of_mem_classes (r.mem_classes x) (r.refl' x) hb hx ▸ r.symm' h⟩ @[simp] theorem sUnion_classes (r : Setoid α) : ⋃₀ r.classes = Set.univ := - Set.eq_univ_of_forall fun x => Set.mem_sUnion.2 ⟨{ y | r.Rel y x }, ⟨x, rfl⟩, Setoid.refl _⟩ + Set.eq_univ_of_forall fun x => Set.mem_sUnion.2 ⟨{ y | r y x }, ⟨x, rfl⟩, Setoid.refl _⟩ /-- The equivalence between the quotient by an equivalence relation and its type of equivalence classes. -/ noncomputable def quotientEquivClasses (r : Setoid α) : Quotient r ≃ Setoid.classes r := by - let f (a : α) : Setoid.classes r := ⟨{ x | Setoid.r x a }, Setoid.mem_classes r a⟩ - have f_respects_relation (a b : α) (a_rel_b : Setoid.r a b) : f a = f b := by + let f (a : α) : Setoid.classes r := ⟨{ x | r x a }, Setoid.mem_classes r a⟩ + have f_respects_relation (a b : α) (a_rel_b : r a b) : f a = f b := by rw [Subtype.mk.injEq] exact Setoid.eq_of_mem_classes (Setoid.mem_classes r a) (Setoid.symm a_rel_b) (Setoid.mem_classes r b) (Setoid.refl b) @@ -168,7 +168,7 @@ noncomputable def quotientEquivClasses (r : Setoid α) : Quotient r ≃ Setoid.c induction' q_b using Quotient.ind with b simp only [Subtype.ext_iff, Quotient.lift_mk, Subtype.ext_iff] at h_eq apply Quotient.sound - show a ∈ { x | Setoid.r x b } + show a ∈ { x | r x b } rw [← h_eq] exact Setoid.refl a · rw [Quot.surjective_lift] @@ -177,8 +177,8 @@ noncomputable def quotientEquivClasses (r : Setoid α) : Quotient r ≃ Setoid.c @[simp] lemma quotientEquivClasses_mk_eq (r : Setoid α) (a : α) : - (quotientEquivClasses r (Quotient.mk r a) : Set α) = { x | r.Rel x a } := - (@Subtype.ext_iff_val _ _ _ ⟨{ x | r.Rel x a }, Setoid.mem_classes r a⟩).mp rfl + (quotientEquivClasses r (Quotient.mk r a) : Set α) = { x | r x a } := + (@Subtype.ext_iff_val _ _ _ ⟨{ x | r x a }, Setoid.mem_classes r a⟩).mp rfl section Partition @@ -217,7 +217,7 @@ theorem IsPartition.sUnion_eq_univ {c : Set (Set α)} (hc : IsPartition c) : ⋃ /-- All elements of a partition of α are the equivalence class of some y ∈ α. -/ theorem exists_of_mem_partition {c : Set (Set α)} (hc : IsPartition c) {s} (hs : s ∈ c) : - ∃ y, s = { x | (mkClasses c hc.2).Rel x y } := + ∃ y, s = { x | mkClasses c hc.2 x y } := let ⟨y, hy⟩ := nonempty_of_mem_partition hc hs ⟨y, eq_eqv_class_of_mem hc.2 hs hy⟩ @@ -367,7 +367,7 @@ protected abbrev setoid (hs : IndexedPartition s) : Setoid α := theorem index_some (i : ι) : hs.index (hs.some i) = i := (mem_iff_index_eq _).1 <| hs.some_mem i -theorem some_index (x : α) : hs.setoid.Rel (hs.some (hs.index x)) x := +theorem some_index (x : α) : hs.setoid (hs.some (hs.index x)) x := hs.index_some (hs.index x) /-- The quotient associated to an indexed partition. -/ @@ -382,7 +382,7 @@ instance [Inhabited α] : Inhabited hs.Quotient := ⟨hs.proj default⟩ theorem proj_eq_iff {x y : α} : hs.proj x = hs.proj y ↔ hs.index x = hs.index y := - Quotient.eq_rel + Quotient.eq'' @[simp] theorem proj_some_index (x : α) : hs.proj (hs.some (hs.index x)) = hs.proj x := @@ -423,7 +423,7 @@ theorem index_out' (x : hs.Quotient) : hs.index x.out' = hs.index (hs.out x) := theorem proj_out (x : hs.Quotient) : hs.proj (hs.out x) = x := Quotient.inductionOn' x fun x => Quotient.sound' <| hs.some_index x -theorem class_of {x : α} : setOf (hs.setoid.Rel x) = s (hs.index x) := +theorem class_of {x : α} : setOf (hs.setoid x) = s (hs.index x) := Set.ext fun _y => eq_comm.trans hs.mem_iff_index_eq.symm theorem proj_fiber (x : hs.Quotient) : hs.proj ⁻¹' {x} = s (hs.equivQuotient.symm x) := diff --git a/Mathlib/Data/Sigma/Interval.lean b/Mathlib/Data/Sigma/Interval.lean index ed1676aff61dd..cde30276d4e61 100644 --- a/Mathlib/Data/Sigma/Interval.lean +++ b/Mathlib/Data/Sigma/Interval.lean @@ -55,16 +55,16 @@ section variable (a b : Σ i, α i) -theorem card_Icc : (Icc a b).card = if h : a.1 = b.1 then (Icc (h.rec a.2) b.2).card else 0 := +theorem card_Icc : #(Icc a b) = if h : a.1 = b.1 then #(Icc (h.rec a.2) b.2) else 0 := card_sigmaLift (fun _ => Icc) _ _ -theorem card_Ico : (Ico a b).card = if h : a.1 = b.1 then (Ico (h.rec a.2) b.2).card else 0 := +theorem card_Ico : #(Ico a b) = if h : a.1 = b.1 then #(Ico (h.rec a.2) b.2) else 0 := card_sigmaLift (fun _ => Ico) _ _ -theorem card_Ioc : (Ioc a b).card = if h : a.1 = b.1 then (Ioc (h.rec a.2) b.2).card else 0 := +theorem card_Ioc : #(Ioc a b) = if h : a.1 = b.1 then #(Ioc (h.rec a.2) b.2) else 0 := card_sigmaLift (fun _ => Ioc) _ _ -theorem card_Ioo : (Ioo a b).card = if h : a.1 = b.1 then (Ioo (h.rec a.2) b.2).card else 0 := +theorem card_Ioo : #(Ioo a b) = if h : a.1 = b.1 then #(Ioo (h.rec a.2) b.2) else 0 := card_sigmaLift (fun _ => Ioo) _ _ end diff --git a/Mathlib/Data/Sigma/Lex.lean b/Mathlib/Data/Sigma/Lex.lean index 6b5e6be4f0f6d..db66010da8c5d 100644 --- a/Mathlib/Data/Sigma/Lex.lean +++ b/Mathlib/Data/Sigma/Lex.lean @@ -137,7 +137,7 @@ end Sigma namespace PSigma -variable {ι : Sort*} {α : ι → Sort*} {r r₁ r₂ : ι → ι → Prop} {s s₁ s₂ : ∀ i, α i → α i → Prop} +variable {ι : Sort*} {α : ι → Sort*} {r : ι → ι → Prop} {s : ∀ i, α i → α i → Prop} theorem lex_iff {a b : Σ' i, α i} : Lex r s a b ↔ r a.1 b.1 ∨ ∃ h : a.1 = b.1, s b.1 (h.rec a.2) b.2 := by diff --git a/Mathlib/Data/Sigma/Order.lean b/Mathlib/Data/Sigma/Order.lean index f7d007a46e857..3afb990febe69 100644 --- a/Mathlib/Data/Sigma/Order.lean +++ b/Mathlib/Data/Sigma/Order.lean @@ -140,7 +140,7 @@ theorem lt_def [LT ι] [∀ i, LT (α i)] {a b : Σₗ i, α i} : /-- The lexicographical preorder on a sigma type. -/ instance preorder [Preorder ι] [∀ i, Preorder (α i)] : Preorder (Σₗ i, α i) := { Sigma.Lex.LE, Sigma.Lex.LT with - le_refl := fun ⟨i, a⟩ => Lex.right a a le_rfl, + le_refl := fun ⟨_, a⟩ => Lex.right a a le_rfl, le_trans := fun _ _ _ => trans_of ((Lex (· < ·)) fun _ => (· ≤ ·)), lt_iff_le_not_le := by refine fun a b => ⟨fun hab => ⟨hab.mono_right fun i a b => le_of_lt, ?_⟩, ?_⟩ diff --git a/Mathlib/Data/Sign.lean b/Mathlib/Data/Sign.lean index 7e0033c7d8a2a..85c7fb46a38a3 100644 --- a/Mathlib/Data/Sign.lean +++ b/Mathlib/Data/Sign.lean @@ -5,7 +5,9 @@ Authors: Eric Rodriguez -/ import Mathlib.Algebra.GroupWithZero.Units.Lemmas import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Ring.Cast import Mathlib.Data.Fintype.BigOperators + /-! # Sign function @@ -373,7 +375,6 @@ section OrderedSemiring variable [OrderedSemiring α] [DecidableRel ((· < ·) : α → α → Prop)] [Nontrivial α] --- @[simp] -- Porting note (#10618): simp can prove this theorem sign_one : sign (1 : α) = 1 := sign_pos zero_lt_one @@ -430,7 +431,7 @@ section AddGroup variable [AddGroup α] [Preorder α] [DecidableRel ((· < ·) : α → α → Prop)] -theorem Left.sign_neg [CovariantClass α α (· + ·) (· < ·)] (a : α) : sign (-a) = -sign a := by +theorem Left.sign_neg [AddLeftStrictMono α] (a : α) : sign (-a) = -sign a := by simp_rw [sign_apply, Left.neg_pos_iff, Left.neg_neg_iff] split_ifs with h h' · exact False.elim (lt_asymm h h') @@ -438,7 +439,7 @@ theorem Left.sign_neg [CovariantClass α α (· + ·) (· < ·)] (a : α) : sign · simp · simp -theorem Right.sign_neg [CovariantClass α α (Function.swap (· + ·)) (· < ·)] (a : α) : +theorem Right.sign_neg [AddRightStrictMono α] (a : α) : sign (-a) = -sign a := by simp_rw [sign_apply, Right.neg_pos_iff, Right.neg_neg_iff] split_ifs with h h' @@ -484,7 +485,7 @@ because lean4 infers α to live in a different universe u_2 otherwise -/ private theorem exists_signed_sum_aux {α : Type u_1} [DecidableEq α] (s : Finset α) (f : α → ℤ) : ∃ (β : Type u_1) (t : Finset β) (sgn : β → SignType) (g : β → α), (∀ b, g b ∈ s) ∧ - (t.card = ∑ a ∈ s, (f a).natAbs) ∧ + (#t = ∑ a ∈ s, (f a).natAbs) ∧ ∀ a ∈ s, (∑ b ∈ t, if g b = a then (sgn b : ℤ) else 0) = f a := by refine ⟨(Σ _ : { x // x ∈ s }, ℕ), Finset.univ.sigma fun a => range (f a).natAbs, diff --git a/Mathlib/Data/Stream/Defs.lean b/Mathlib/Data/Stream/Defs.lean index ce2dc694fd4fc..6a1171545ddf4 100644 --- a/Mathlib/Data/Stream/Defs.lean +++ b/Mathlib/Data/Stream/Defs.lean @@ -82,7 +82,7 @@ def corec' (f : α → β × α) : α → Stream' β := def corecState {σ α} (cmd : StateM σ α) (s : σ) : Stream' α := corec Prod.fst (cmd.run ∘ Prod.snd) (cmd.run s) --- corec is also known as unfold +-- corec is also known as unfolds abbrev unfolds (g : α → β) (f : α → α) (a : α) : Stream' β := corec g f a @@ -94,7 +94,7 @@ infixl:65 " ⋈ " => interleave /-- Elements of a stream with even indices. -/ def even (s : Stream' α) : Stream' α := - corec (fun s => head s) (fun s => tail (tail s)) s + corec head (fun s => tail (tail s)) s /-- Elements of a stream with odd indices. -/ def odd (s : Stream' α) : Stream' α := diff --git a/Mathlib/Data/Stream/Init.lean b/Mathlib/Data/Stream/Init.lean index c90ad62ac925d..b893cc61acf48 100644 --- a/Mathlib/Data/Stream/Init.lean +++ b/Mathlib/Data/Stream/Init.lean @@ -356,7 +356,7 @@ theorem interleave_tail_tail (s₁ s₂ : Stream' α) : tail s₁ ⋈ tail s₂ theorem get_interleave_left : ∀ (n : ℕ) (s₁ s₂ : Stream' α), get (s₁ ⋈ s₂) (2 * n) = get s₁ n - | 0, s₁, s₂ => rfl + | 0, _, _ => rfl | n + 1, s₁, s₂ => by change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n) rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons] @@ -365,7 +365,7 @@ theorem get_interleave_left : ∀ (n : ℕ) (s₁ s₂ : Stream' α), theorem get_interleave_right : ∀ (n : ℕ) (s₁ s₂ : Stream' α), get (s₁ ⋈ s₂) (2 * n + 1) = get s₂ n - | 0, s₁, s₂ => rfl + | 0, _, _ => rfl | n + 1, s₁, s₂ => by change get (s₁ ⋈ s₂) (succ (succ (2 * n + 1))) = get s₂ (succ n) rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons, @@ -415,7 +415,7 @@ theorem interleave_even_odd (s₁ : Stream' α) : even s₁ ⋈ odd s₁ = s₁ rfl theorem get_even : ∀ (n : ℕ) (s : Stream' α), get (even s) n = get s (2 * n) - | 0, s => rfl + | 0, _ => rfl | succ n, s => by change get (even s) (succ n) = get s (succ (succ (2 * n))) rw [get_succ, get_succ, tail_even, get_even n]; rfl @@ -438,13 +438,13 @@ theorem cons_append_stream (a : α) (l : List α) (s : Stream' α) : theorem append_append_stream : ∀ (l₁ l₂ : List α) (s : Stream' α), l₁ ++ l₂ ++ₛ s = l₁ ++ₛ (l₂ ++ₛ s) - | [], l₂, s => rfl + | [], _, _ => rfl | List.cons a l₁, l₂, s => by rw [List.cons_append, cons_append_stream, cons_append_stream, append_append_stream l₁] theorem map_append_stream (f : α → β) : ∀ (l : List α) (s : Stream' α), map f (l ++ₛ s) = List.map f l ++ₛ map f s - | [], s => rfl + | [], _ => rfl | List.cons a l, s => by rw [cons_append_stream, List.map_cons, map_cons, cons_append_stream, map_append_stream f l] @@ -499,7 +499,7 @@ theorem take_take {s : Stream' α} : ∀ {m n}, (s.take n).take m = s.take (min (take_succ' n).symm theorem get?_take {s : Stream' α} : ∀ {k n}, k < n → (s.take n).get? k = s.get k - | 0, n+1, _ => rfl + | 0, _+1, _ => rfl | k+1, n+1, h => by rw [take_succ, List.get?, get?_take (Nat.lt_of_succ_lt_succ h), get_succ] theorem get?_take_succ (n : ℕ) (s : Stream' α) : diff --git a/Mathlib/Data/String/Basic.lean b/Mathlib/Data/String/Basic.lean index d30479b15e611..d77a4e02a1f33 100644 --- a/Mathlib/Data/String/Basic.lean +++ b/Mathlib/Data/String/Basic.lean @@ -6,7 +6,6 @@ Authors: Mario Carneiro import Batteries.Data.String.Lemmas import Mathlib.Data.List.Lex import Mathlib.Data.Char -import Mathlib.Tactic.AdaptationNote import Mathlib.Algebra.Order.Group.Nat /-! @@ -17,6 +16,8 @@ Supplementary theorems about the `String` type. namespace String +@[simp] theorem endPos_empty : "".endPos = 0 := rfl + /-- `<` on string iterators. This coincides with `<` on strings as lists. -/ def ltb (s₁ s₂ : Iterator) : Bool := if s₂.hasNext then @@ -76,13 +77,11 @@ theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList · unfold ltb; decide · rename_i c₂ cs₂; apply iff_of_true · unfold ltb - #adaptation_note /-- v4.7.0-rc1 exclude reduceMk from simp -/ - simp [-reduceMk, Iterator.hasNext, Char.utf8Size_pos] + simp [Iterator.hasNext, Char.utf8Size_pos] · apply List.nil_lt_cons · rename_i c₁ cs₁ ih; apply iff_of_false · unfold ltb - #adaptation_note /-- v4.7.0-rc1 exclude reduceMk from simp -/ - simp [-reduceMk, Iterator.hasNext] + simp [Iterator.hasNext] · apply not_lt_of_lt; apply List.nil_lt_cons · rename_i c₁ cs₁ ih c₂ cs₂; unfold ltb simp only [Iterator.hasNext, Pos.byteIdx_zero, endPos, utf8ByteSize, utf8ByteSize.go, @@ -139,7 +138,7 @@ theorem head_empty : "".data.head! = default := rfl instance : LinearOrder String where - le_refl a := le_iff_toList_le.mpr le_rfl + le_refl _ := le_iff_toList_le.mpr le_rfl le_trans a b c := by simp only [le_iff_toList_le] apply le_trans diff --git a/Mathlib/Data/Sum/Interval.lean b/Mathlib/Data/Sum/Interval.lean index 75478d551bcc8..851ec0a28c334 100644 --- a/Mathlib/Data/Sum/Interval.lean +++ b/Mathlib/Data/Sum/Interval.lean @@ -222,7 +222,7 @@ instance instLocallyFiniteOrder : LocallyFiniteOrder (α ⊕ β) where finset_mem_Ioc := by rintro (a | a) (b | b) (x | x) <;> simp finset_mem_Ioo := by rintro (a | a) (b | b) (x | x) <;> simp -variable (a₁ a₂ : α) (b₁ b₂ : β) (a b : α ⊕ β) +variable (a₁ a₂ : α) (b₁ b₂ : β) theorem Icc_inl_inl : Icc (inl a₁ : α ⊕ β) (inl a₂) = (Icc a₁ a₂).map Embedding.inl := rfl diff --git a/Mathlib/Data/Sum/Order.lean b/Mathlib/Data/Sum/Order.lean index 7eef753b32d1a..27fdc8c6c267a 100644 --- a/Mathlib/Data/Sum/Order.lean +++ b/Mathlib/Data/Sum/Order.lean @@ -25,7 +25,7 @@ type synonym. -/ -variable {α β γ δ : Type*} +variable {α β γ : Type*} namespace Sum @@ -157,7 +157,7 @@ variable [Preorder α] [Preorder β] instance instPreorderSum : Preorder (α ⊕ β) := { instLESum, instLTSum with - le_refl := fun x => LiftRel.refl _ _ _, + le_refl := fun _ => LiftRel.refl _ _ _, le_trans := fun _ _ _ => LiftRel.trans _ _, lt_iff_le_not_le := fun a b => by refine ⟨fun hab => ⟨hab.mono (fun _ _ => le_of_lt) fun _ _ => le_of_lt, ?_⟩, ?_⟩ diff --git a/Mathlib/Data/Sym/Basic.lean b/Mathlib/Data/Sym/Basic.lean index 4378b439653ed..8d71b72273208 100644 --- a/Mathlib/Data/Sym/Basic.lean +++ b/Mathlib/Data/Sym/Basic.lean @@ -176,7 +176,6 @@ theorem mem_coe : a ∈ (s : Multiset α) ↔ a ∈ s := theorem mem_cons_of_mem (h : a ∈ s) : a ∈ b ::ₛ s := Multiset.mem_cons_of_mem h ---@[simp] Porting note (#10618): simp can prove it theorem mem_cons_self (a : α) (s : Sym α n) : a ∈ a ::ₛ s := Multiset.mem_cons_self a s.1 @@ -468,7 +467,7 @@ theorem mem_append_iff {s' : Sym α m} : a ∈ s.append s' ↔ a ∈ s ∨ a ∈ def oneEquiv : α ≃ Sym α 1 where toFun a := ⟨{a}, by simp⟩ invFun s := (Equiv.subtypeQuotientEquivQuotientSubtype - (·.length = 1) _ (fun l ↦ Iff.rfl) (fun l l' ↦ by rfl) s).liftOn + (·.length = 1) _ (fun _ ↦ Iff.rfl) (fun l l' ↦ by rfl) s).liftOn (fun l ↦ l.1.head <| List.length_pos.mp <| by simp) fun ⟨_, _⟩ ⟨_, h⟩ ↦ fun perm ↦ by obtain ⟨a, rfl⟩ := List.length_eq_one.mp h diff --git a/Mathlib/Data/Sym/Card.lean b/Mathlib/Data/Sym/Card.lean index 4b1dff004b78f..9e65f781aa92d 100644 --- a/Mathlib/Data/Sym/Card.lean +++ b/Mathlib/Data/Sym/Card.lean @@ -121,8 +121,8 @@ namespace Sym2 variable [DecidableEq α] -/-- The `diag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `s.card`. -/ -theorem card_image_diag (s : Finset α) : (s.diag.image Sym2.mk).card = s.card := by +/-- The `diag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `#s`. -/ +theorem card_image_diag (s : Finset α) : #(s.diag.image Sym2.mk) = #s := by rw [card_image_of_injOn, diag_card] rintro ⟨x₀, x₁⟩ hx _ _ h cases Sym2.eq.1 h @@ -130,8 +130,7 @@ theorem card_image_diag (s : Finset α) : (s.diag.image Sym2.mk).card = s.card : · simp only [mem_coe, mem_diag] at hx rw [hx.2] -theorem two_mul_card_image_offDiag (s : Finset α) : - 2 * (s.offDiag.image Sym2.mk).card = s.offDiag.card := by +lemma two_mul_card_image_offDiag (s : Finset α) : 2 * #(s.offDiag.image Sym2.mk) = #s.offDiag := by rw [card_eq_sum_card_image (Sym2.mk : α × α → _), sum_const_nat (Sym2.ind _), mul_comm] rintro x y hxy simp_rw [mem_image, mem_offDiag] at hxy @@ -140,7 +139,7 @@ theorem two_mul_card_image_offDiag (s : Finset α) : obtain ⟨hx, hy, hxy⟩ : x ∈ s ∧ y ∈ s ∧ x ≠ y := by cases h <;> refine ⟨‹_›, ‹_›, ?_⟩ <;> [exact ha; exact ha.symm] have hxy' : y ≠ x := hxy.symm - have : (s.offDiag.filter fun z => Sym2.mk z = s(x, y)) = ({(x, y), (y, x)} : Finset _) := by + have : {z ∈ s.offDiag | Sym2.mk z = s(x, y)} = {(x, y), (y, x)} := by ext ⟨x₁, y₁⟩ rw [mem_filter, mem_insert, mem_singleton, Sym2.eq_iff, Prod.mk.inj_iff, Prod.mk.inj_iff, and_iff_right_iff_imp] @@ -150,11 +149,10 @@ theorem two_mul_card_image_offDiag (s : Finset α) : simp only [not_and, Prod.mk.inj_iff, mem_singleton] exact fun _ => hxy' -/-- The `offDiag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `s.offDiag.card / 2`. +/-- The `offDiag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `#s.offDiag / 2`. This is because every element `s(x, y)` of `Sym2 α` not on the diagonal comes from exactly two pairs: `(x, y)` and `(y, x)`. -/ -theorem card_image_offDiag (s : Finset α) : - (s.offDiag.image Sym2.mk).card = s.card.choose 2 := by +theorem card_image_offDiag (s : Finset α) : #(s.offDiag.image Sym2.mk) = (#s).choose 2 := by rw [Nat.choose_two_right, Nat.mul_sub_left_distrib, mul_one, ← offDiag_card, Nat.div_eq_of_eq_mul_right Nat.zero_lt_two (two_mul_card_image_offDiag s).symm] diff --git a/Mathlib/Data/Sym/Sym2.lean b/Mathlib/Data/Sym/Sym2.lean index 945179cd192f3..8ae04f76e29e4 100644 --- a/Mathlib/Data/Sym/Sym2.lean +++ b/Mathlib/Data/Sym/Sym2.lean @@ -182,9 +182,9 @@ def lift : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ } Quot.lift (uncurry ↑f) <| by rintro _ _ ⟨⟩ exacts [rfl, f.prop _ _] - invFun F := ⟨curry (F ∘ Sym2.mk), fun a₁ a₂ => congr_arg F eq_swap⟩ - left_inv f := Subtype.ext rfl - right_inv F := funext <| Sym2.ind fun x y => rfl + invFun F := ⟨curry (F ∘ Sym2.mk), fun _ _ => congr_arg F eq_swap⟩ + left_inv _ := Subtype.ext rfl + right_inv _ := funext <| Sym2.ind fun _ _ => rfl @[simp] theorem lift_mk (f : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ }) (a₁ a₂ : α) : @@ -211,8 +211,8 @@ def lift₂ : ⟨fun a₁ a₂ b₁ b₂ => F s(a₁, a₂) s(b₁, b₂), fun a₁ a₂ b₁ b₂ => by constructor exacts [congr_arg₂ F eq_swap rfl, congr_arg₂ F rfl eq_swap]⟩ - left_inv f := Subtype.ext rfl - right_inv F := funext₂ fun a b => Sym2.inductionOn₂ a b fun _ _ _ _ => rfl + left_inv _ := Subtype.ext rfl + right_inv _ := funext₂ fun a b => Sym2.inductionOn₂ a b fun _ _ _ _ => rfl @[simp] theorem lift₂_mk @@ -456,23 +456,23 @@ theorem fromRel_proj_prop {sym : Symmetric r} {z : α × α} : Sym2.mk z ∈ fro theorem fromRel_prop {sym : Symmetric r} {a b : α} : s(a, b) ∈ fromRel sym ↔ r a b := Iff.rfl -theorem fromRel_bot : fromRel (fun (x y : α) z => z : Symmetric ⊥) = ∅ := by +theorem fromRel_bot : fromRel (fun (_ _ : α) z => z : Symmetric ⊥) = ∅ := by apply Set.eq_empty_of_forall_not_mem fun e => _ apply Sym2.ind simp [-Set.bot_eq_empty, Prop.bot_eq_false] -theorem fromRel_top : fromRel (fun (x y : α) z => z : Symmetric ⊤) = Set.univ := by +theorem fromRel_top : fromRel (fun (_ _ : α) z => z : Symmetric ⊤) = Set.univ := by apply Set.eq_univ_of_forall fun e => _ apply Sym2.ind simp [-Set.top_eq_univ, Prop.top_eq_true] -theorem fromRel_ne : fromRel (fun (x y : α) z => z.symm : Symmetric Ne) = {z | ¬IsDiag z} := by +theorem fromRel_ne : fromRel (fun (_ _ : α) z => z.symm : Symmetric Ne) = {z | ¬IsDiag z} := by ext z; exact z.ind (by simp) theorem fromRel_irreflexive {sym : Symmetric r} : Irreflexive r ↔ ∀ {z}, z ∈ fromRel sym → ¬IsDiag z := { mp := by intro h; apply Sym2.ind; aesop - mpr := fun h x hr => h (fromRel_prop.mpr hr) rfl } + mpr := fun h _ hr => h (fromRel_prop.mpr hr) rfl } theorem mem_fromRel_irrefl_other_ne {sym : Symmetric r} (irrefl : Irreflexive r) {a : α} {z : Sym2 α} (hz : z ∈ fromRel sym) (h : a ∈ z) : Mem.other h ≠ a := @@ -647,7 +647,7 @@ theorem other_invol {a : α} {z : Sym2 α} (ha : a ∈ z) (hb : Mem.other ha ∈ apply other_eq_other' theorem filter_image_mk_isDiag [DecidableEq α] (s : Finset α) : - ((s ×ˢ s).image Sym2.mk).filter IsDiag = s.diag.image Sym2.mk := by + {a ∈ (s ×ˢ s).image Sym2.mk | a.IsDiag} = s.diag.image Sym2.mk := by ext z induction' z simp only [mem_image, mem_diag, exists_prop, mem_filter, Prod.exists, mem_product] @@ -660,8 +660,7 @@ theorem filter_image_mk_isDiag [DecidableEq α] (s : Finset α) : exact ⟨⟨a, a, ⟨ha, ha⟩, rfl⟩, rfl⟩ theorem filter_image_mk_not_isDiag [DecidableEq α] (s : Finset α) : - (((s ×ˢ s).image Sym2.mk).filter fun a : Sym2 α => ¬a.IsDiag) = - s.offDiag.image Sym2.mk := by + {a ∈ (s ×ˢ s).image Sym2.mk | ¬a.IsDiag} = s.offDiag.image Sym2.mk := by ext z induction z simp only [mem_image, mem_offDiag, mem_filter, Prod.exists, mem_product] diff --git a/Mathlib/Data/Tree/Basic.lean b/Mathlib/Data/Tree/Basic.lean index 2b1d95d767b68..df733700e6e4a 100644 --- a/Mathlib/Data/Tree/Basic.lean +++ b/Mathlib/Data/Tree/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2019 mathlib community. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Wojciech Nawrocki -/ -import Batteries.Data.RBMap.Basic import Mathlib.Data.Nat.Notation import Mathlib.Tactic.TypeStar import Mathlib.Util.CompileInductive @@ -46,13 +45,6 @@ variable {α : Type u} instance : Inhabited (Tree α) := ⟨nil⟩ -open Batteries (RBNode) - -/-- Makes a `Tree α` out of a red-black tree. -/ -def ofRBNode : RBNode α → Tree α - | RBNode.nil => nil - | RBNode.node _color l key r => node key (ofRBNode l) (ofRBNode r) - /-- Apply a function to each value in the tree. This is the `map` function for the `Tree` functor. -/ def map {β} (f : α → β) : Tree α → Tree β @@ -111,12 +103,10 @@ compile_inductive% Tree @[elab_as_elim] def unitRecOn {motive : Tree Unit → Sort*} (t : Tree Unit) (base : motive nil) (ind : ∀ x y, motive x → motive y → motive (x △ y)) : motive t := - -- Porting note: Old proof was `t.recOn base fun u => u.recOn ind` but - -- structure eta makes it unnecessary (https://github.com/leanprover/lean4/issues/777). - t.recOn base fun _u => ind + t.recOn base fun _u ↦ ind theorem left_node_right_eq_self : ∀ {x : Tree Unit} (_hx : x ≠ nil), x.left △ x.right = x | nil, h => by trivial - | node a l r, _ => rfl -- Porting note: `a △ b` no longer works in pattern matching + | node _ _ _, _ => rfl -- Porting note: `a △ b` no longer works in pattern matching end Tree diff --git a/Mathlib/Data/Tree/Get.lean b/Mathlib/Data/Tree/Get.lean index e3adeba9eea04..b374b675b07ba 100644 --- a/Mathlib/Data/Tree/Get.lean +++ b/Mathlib/Data/Tree/Get.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Wojciech Nawrocki -/ import Mathlib.Data.Num.Basic +import Mathlib.Data.Ordering.Basic import Mathlib.Data.Tree.Basic /-! diff --git a/Mathlib/Data/Tree/RBMap.lean b/Mathlib/Data/Tree/RBMap.lean new file mode 100644 index 0000000000000..6ea502b79c94c --- /dev/null +++ b/Mathlib/Data/Tree/RBMap.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2019 mathlib community. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Wojciech Nawrocki +-/ +import Batteries.Data.RBMap.Basic +import Mathlib.Data.Tree.Basic + +/-! +# Binary tree and RBMaps + +In this file we define `Tree.ofRBNode`. +This definition was moved from the main file to avoid a dependency on `RBMap`. + +## TODO + +Implement a `Traversable` instance for `Tree`. + +## References + + +-/ + +namespace Tree + +universe u + +variable {α : Type u} + +open Batteries (RBNode) + +/-- Makes a `Tree α` out of a red-black tree. -/ +def ofRBNode : RBNode α → Tree α + | RBNode.nil => nil + | RBNode.node _color l key r => node key (ofRBNode l) (ofRBNode r) + +end Tree diff --git a/Mathlib/Data/TypeVec.lean b/Mathlib/Data/TypeVec.lean index ed974cab4a625..df15092ea20be 100644 --- a/Mathlib/Data/TypeVec.lean +++ b/Mathlib/Data/TypeVec.lean @@ -419,8 +419,8 @@ theorem const_iff_true {α : TypeVec n} {i x p} : ofRepeat (TypeVec.const p α i section -variable {α β γ : TypeVec.{u} n} -variable (p : α ⟹ «repeat» n Prop) (r : α ⊗ α ⟹ «repeat» n Prop) +variable {α β : TypeVec.{u} n} +variable (p : α ⟹ «repeat» n Prop) /-- left projection of a `prod` vector -/ def prod.fst : ∀ {n} {α β : TypeVec.{u} n}, α ⊗ β ⟹ α diff --git a/Mathlib/Data/Vector/Basic.lean b/Mathlib/Data/Vector/Basic.lean index 5db96436f76b0..50418d58cb02f 100644 --- a/Mathlib/Data/Vector/Basic.lean +++ b/Mathlib/Data/Vector/Basic.lean @@ -7,7 +7,7 @@ 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.InsertNth +import Mathlib.Data.List.InsertIdx import Mathlib.Control.Applicative import Mathlib.Control.Traversable.Basic @@ -73,12 +73,6 @@ theorem mk_toList : ∀ (v : Vector α n) (h), (⟨toList v, h⟩ : Vector α n) @[simp] theorem length_val (v : Vector α n) : v.val.length = n := v.2 --- Porting note: not used in mathlib and coercions done differently in Lean 4 --- @[simp] --- theorem length_coe (v : Vector α n) : --- ((coe : { l : List α // l.length = n } → List α) v).length = n := --- v.2 - @[simp] theorem toList_map {β : Type*} (v : Vector α n) (f : α → β) : (v.map f).toList = v.toList.map f := by cases v; rfl @@ -220,7 +214,6 @@ theorem get_zero : ∀ v : Vector α n.succ, get v 0 = head v theorem head_ofFn {n : ℕ} (f : Fin n.succ → α) : head (ofFn f) = f 0 := by rw [← get_zero, get_ofFn] ---@[simp] Porting note (#10618): simp can prove it theorem get_cons_zero (a : α) (v : Vector α n) : get (a ::ᵥ v) 0 = a := by simp [get_zero] /-- Accessing the nth element of a vector made up @@ -348,7 +341,7 @@ def mOfFn {m} [Monad m] {α : Type u} : ∀ {n}, (Fin n → m α) → m (Vector theorem mOfFn_pure {m} [Monad m] [LawfulMonad m] {α} : ∀ {n} (f : Fin n → α), (@mOfFn m _ _ _ fun i => pure (f i)) = pure (ofFn f) - | 0, f => rfl + | 0, _ => rfl | n + 1, f => by rw [mOfFn, @mOfFn_pure m _ _ _ n _, ofFn] simp @@ -478,71 +471,81 @@ def casesOn₃ {motive : ∀{n}, Vector α n → Vector β n → Vector γ n def toArray : Vector α n → Array α | ⟨xs, _⟩ => cast (by rfl) xs.toArray -section InsertNth +section InsertIdx variable {a : α} -/-- `v.insertNth a i` inserts `a` into the vector `v` at position `i` +/-- `v.insertIdx a i` inserts `a` into the vector `v` at position `i` (and shifting later components to the right). -/ -def insertNth (a : α) (i : Fin (n + 1)) (v : Vector α n) : Vector α (n + 1) := - ⟨v.1.insertNth i a, by - rw [List.length_insertNth, v.2] +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⟩ -theorem insertNth_val {i : Fin (n + 1)} {v : Vector α n} : - (v.insertNth a i).val = v.val.insertNth i.1 a := +@[deprecated (since := "2024-10-21")] alias insertNth := insertIdx + +theorem insertIdx_val {i : Fin (n + 1)} {v : Vector α n} : + (v.insertIdx a i).val = v.val.insertIdx i.1 a := rfl +@[deprecated (since := "2024-10-21")] alias insertNth_val := insertIdx_val + @[simp] theorem eraseIdx_val {i : Fin n} : ∀ {v : Vector α n}, (eraseIdx i v).val = v.val.eraseIdx i | _ => rfl +@[deprecated (since := "2024-10-21")] alias eraseNth_val := eraseIdx_val @[deprecated (since := "2024-05-04")] alias removeNth_val := eraseIdx_val -theorem eraseIdx_insertNth {v : Vector α n} {i : Fin (n + 1)} : - eraseIdx i (insertNth a i v) = v := - Subtype.eq <| List.eraseIdx_insertNth i.1 v.1 +theorem eraseIdx_insertIdx {v : Vector α n} {i : Fin (n + 1)} : + eraseIdx i (insertIdx a i v) = v := + Subtype.eq <| List.eraseIdx_insertIdx i.1 v.1 -@[deprecated (since := "2024-05-04")] alias removeNth_insertNth := eraseIdx_insertNth +@[deprecated (since := "2024-05-04")] alias eraseIdx_insertNth := eraseIdx_insertIdx +@[deprecated (since := "2024-05-04")] alias removeNth_insertNth := eraseIdx_insertIdx -theorem eraseIdx_insertNth' {v : Vector α (n + 1)} : +/-- Erasing an element after inserting an element, at different indices. -/ +theorem eraseIdx_insertIdx' {v : Vector α (n + 1)} : ∀ {i : Fin (n + 1)} {j : Fin (n + 2)}, - eraseIdx (j.succAbove i) (insertNth a j v) = insertNth a (i.predAbove j) (eraseIdx i v) + eraseIdx (j.succAbove i) (insertIdx a j v) = insertIdx a (i.predAbove j) (eraseIdx i v) | ⟨i, hi⟩, ⟨j, hj⟩ => by - dsimp [insertNth, eraseIdx, Fin.succAbove, Fin.predAbove] + dsimp [insertIdx, eraseIdx, Fin.succAbove, Fin.predAbove] rw [Subtype.mk_eq_mk] simp only [Fin.lt_iff_val_lt_val] split_ifs with hij · rcases Nat.exists_eq_succ_of_ne_zero (Nat.pos_iff_ne_zero.1 (lt_of_le_of_lt (Nat.zero_le _) hij)) with ⟨j, rfl⟩ - rw [← List.insertNth_eraseIdx_of_ge] + rw [← List.insertIdx_eraseIdx_of_ge] · simp; rfl · simpa · simpa [Nat.lt_succ_iff] using hij · dsimp - rw [← List.insertNth_eraseIdx_of_le i j _ _ _] + rw [← List.insertIdx_eraseIdx_of_le i j _ _ _] · rfl · simpa · simpa [not_lt] using hij -@[deprecated (since := "2024-05-04")] alias removeNth_insertNth' := eraseIdx_insertNth' +@[deprecated (since := "2024-05-04")] alias eraseIdx_insertNth' := eraseIdx_insertIdx' +@[deprecated (since := "2024-05-04")] alias removeNth_insertNth' := eraseIdx_insertIdx' -theorem insertNth_comm (a b : α) (i j : Fin (n + 1)) (h : i ≤ j) : +theorem insertIdx_comm (a b : α) (i j : Fin (n + 1)) (h : i ≤ j) : ∀ v : Vector α n, - (v.insertNth a i).insertNth b j.succ = (v.insertNth b j).insertNth a (Fin.castSucc i) + (v.insertIdx a i).insertIdx b j.succ = (v.insertIdx b j).insertIdx a (Fin.castSucc i) | ⟨l, hl⟩ => by refine Subtype.eq ?_ - simp only [insertNth_val, Fin.val_succ, Fin.castSucc, Fin.coe_castAdd] - apply List.insertNth_comm + simp only [insertIdx_val, Fin.val_succ, Fin.castSucc, Fin.coe_castAdd] + apply List.insertIdx_comm · assumption · rw [hl] exact Nat.le_of_succ_le_succ j.2 -end InsertNth +@[deprecated (since := "2024-10-21")] alias insertNth_comm := insertIdx_comm + +end InsertIdx -- Porting note: renamed to `set` from `updateNth` to align with `List` -section ModifyNth +section Set /-- `set v n a` replaces the `n`th element of `v` with `a`. -/ def set (v : Vector α n) (i : Fin n) (a : α) : Vector α n := @@ -580,7 +583,7 @@ theorem prod_set' [CommGroup α] (v : Vector α n) (i : Fin n) (a : α) : refine (List.prod_set' v.toList i a).trans ?_ simp [get_eq_get, mul_assoc] -end ModifyNth +end Set end Vector diff --git a/Mathlib/Data/Vector/Defs.lean b/Mathlib/Data/Vector/Defs.lean index 8c08c0254b502..24273d810fe4f 100644 --- a/Mathlib/Data/Vector/Defs.lean +++ b/Mathlib/Data/Vector/Defs.lean @@ -65,7 +65,7 @@ theorem tail_cons (a : α) : ∀ v : Vector α n, tail (cons a v) = v @[simp] theorem cons_head_tail : ∀ v : Vector α (succ n), cons (head v) (tail v) = v | ⟨[], h⟩ => by contradiction - | ⟨a :: v, h⟩ => rfl + | ⟨_ :: _, _⟩ => rfl /-- The list obtained from a vector. -/ def toList (v : Vector α n) : List α := diff --git a/Mathlib/Data/Vector3.lean b/Mathlib/Data/Vector3.lean index 9ec3dea934529..d1c8061307db8 100644 --- a/Mathlib/Data/Vector3.lean +++ b/Mathlib/Data/Vector3.lean @@ -146,13 +146,13 @@ theorem append_cons (a : α) (v : Vector3 α m) (w : Vector3 α n) : (a :: v) +- @[simp] theorem append_left : ∀ {m} (i : Fin2 m) (v : Vector3 α m) {n} (w : Vector3 α n), (v +-+ w) (left n i) = v i - | _, @fz m, v, n, w => v.consElim fun a _t => by simp [*, left] + | _, @fz m, v, _, _ => v.consElim fun a _t => by simp [*, left] | _, @fs m i, v, n, w => v.consElim fun _a t => by simp [append_left, left] @[simp] theorem append_add : ∀ {m} (v : Vector3 α m) {n} (w : Vector3 α n) (i : Fin2 n), (v +-+ w) (add i m) = w i - | 0, v, n, w, i => rfl + | 0, _, _, _, _ => rfl | m + 1, v, n, w, i => v.consElim fun _a t => by simp [append_add, add] /-- Insert `a` into `v` at index `i`. -/ @@ -205,7 +205,7 @@ theorem exists_vector_zero (f : Vector3 α 0 → Prop) : Exists f ↔ f [] := ⟨fun ⟨v, fv⟩ => by rw [← eq_nil v]; exact fv, fun f0 => ⟨[], f0⟩⟩ theorem exists_vector_succ (f : Vector3 α (succ n) → Prop) : Exists f ↔ ∃ x v, f (x :: v) := - ⟨fun ⟨v, fv⟩ => ⟨_, _, by rw [cons_head_tail v]; exact fv⟩, fun ⟨x, v, fxv⟩ => ⟨_, fxv⟩⟩ + ⟨fun ⟨v, fv⟩ => ⟨_, _, by rw [cons_head_tail v]; exact fv⟩, fun ⟨_, _, fxv⟩ => ⟨_, fxv⟩⟩ theorem vectorEx_iff_exists : ∀ {n} (f : Vector3 α n → Prop), VectorEx n f ↔ Exists f | 0, f => (exists_vector_zero f).symm diff --git a/Mathlib/Data/W/Basic.lean b/Mathlib/Data/W/Basic.lean index aec104886a43b..7c1f339cc49d0 100644 --- a/Mathlib/Data/W/Basic.lean +++ b/Mathlib/Data/W/Basic.lean @@ -103,7 +103,7 @@ theorem infinite_of_nonempty_of_isEmpty (a b : α) [ha : Nonempty (β a)] [he : · cases' m with m · simp_all · refine congr_arg Nat.succ (ih ?_) - simp_all [Function.funext_iff]⟩ + simp_all [funext_iff]⟩ variable [∀ a : α, Fintype (β a)] @@ -133,11 +133,11 @@ private abbrev WType' {α : Type*} (β : α → Type*) [∀ a : α, Fintype (β variable [∀ a : α, Encodable (β a)] private def encodable_zero : Encodable (WType' β 0) := - let f : WType' β 0 → Empty := fun ⟨x, h⟩ => False.elim <| not_lt_of_ge h (WType.depth_pos _) + let f : WType' β 0 → Empty := fun ⟨_, h⟩ => False.elim <| not_lt_of_ge h (WType.depth_pos _) let finv : Empty → WType' β 0 := by intro x cases x - have : ∀ x, finv (f x) = x := fun ⟨x, h⟩ => False.elim <| not_lt_of_ge h (WType.depth_pos _) + have : ∀ x, finv (f x) = x := fun ⟨_, h⟩ => False.elim <| not_lt_of_ge h (WType.depth_pos _) Encodable.ofLeftInverse f finv this private def f (n : ℕ) : WType' β (n + 1) → Σa : α, β a → WType' β n @@ -155,7 +155,7 @@ private def finv (n : ℕ) : (Σa : α, β a → WType' β n) → WType' β (n + variable [Encodable α] -private def encodable_succ (n : Nat) (h : Encodable (WType' β n)) : Encodable (WType' β (n + 1)) := +private def encodable_succ (n : Nat) (_ : Encodable (WType' β n)) : Encodable (WType' β (n + 1)) := Encodable.ofLeftInverse (f n) (finv n) (by rintro ⟨⟨_, _⟩, _⟩ diff --git a/Mathlib/Data/W/Cardinal.lean b/Mathlib/Data/W/Cardinal.lean index 911d370ca2ef1..62545bd0184ae 100644 --- a/Mathlib/Data/W/Cardinal.lean +++ b/Mathlib/Data/W/Cardinal.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Data.W.Basic -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic /-! # Cardinality of W-types @@ -67,7 +67,7 @@ theorem cardinal_mk_le_max_aleph0_of_finite' [∀ a, Finite (β a)] : _ ≤ m * ⨆ a, m ^ lift.{u} #(β a) := mul_le_mul' (le_max_left _ _) le_rfl _ = m := mul_eq_left (le_max_right _ _) - (ciSup_le' fun i => pow_le (le_max_right _ _) (lt_aleph0_of_finite _)) <| + (ciSup_le' fun _ => pow_le (le_max_right _ _) (lt_aleph0_of_finite _)) <| pos_iff_ne_zero.1 <| Order.succ_le_iff.1 (by diff --git a/Mathlib/Data/ZMod/Basic.lean b/Mathlib/Data/ZMod/Basic.lean index 8c9d56fcedfec..3edc84886e2cc 100644 --- a/Mathlib/Data/ZMod/Basic.lean +++ b/Mathlib/Data/ZMod/Basic.lean @@ -3,6 +3,8 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ +import Mathlib.Algebra.CharP.Basic +import Mathlib.Algebra.Module.End import Mathlib.Algebra.Ring.Prod import Mathlib.GroupTheory.GroupAction.SubMulAction import Mathlib.GroupTheory.OrderOfElement @@ -10,7 +12,6 @@ import Mathlib.Tactic.FinCases import Mathlib.Tactic.Linarith import Mathlib.Data.Fintype.Units - /-! # Integers mod `n` @@ -34,7 +35,7 @@ This is a ring hom if the ring has characteristic dividing `n` assert_not_exists Submodule -open Function +open Function ZMod namespace ZMod @@ -129,7 +130,6 @@ theorem ringChar_zmod_n (n : ℕ) : ringChar (ZMod n) = n := by rw [ringChar.eq_iff] exact ZMod.charP n --- @[simp] -- Porting note (#10618): simp can prove this theorem natCast_self (n : ℕ) : (n : ZMod n) = 0 := CharP.cast_eq_zero (ZMod n) n @@ -519,7 +519,7 @@ variable {m n : ℕ} @[simp] theorem val_eq_zero : ∀ {n : ℕ} (a : ZMod n), a.val = 0 ↔ a = 0 - | 0, a => Int.natAbs_eq_zero + | 0, _ => Int.natAbs_eq_zero | n + 1, a => by rw [Fin.ext_iff] exact Iff.rfl @@ -780,7 +780,6 @@ def inv : ∀ n : ℕ, ZMod n → ZMod n instance (n : ℕ) : Inv (ZMod n) := ⟨inv n⟩ -@[nolint unusedHavesSuffices] theorem inv_zero : ∀ n : ℕ, (0 : ZMod n)⁻¹ = 0 | 0 => Int.sign_zero | n + 1 => @@ -1016,7 +1015,7 @@ theorem val_eq_one : ∀ {n : ℕ} (_ : 1 < n) (a : ZMod n), a.val = 1 ↔ a = 1 theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by rw [neg_eq_iff_add_eq_zero, ← two_mul] cases n - · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero] + · rw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero] exact ⟨fun h => h.elim (by simp) Or.inl, fun h => Or.inr (h.elim id fun h => h.elim (by simp) id)⟩ @@ -1025,7 +1024,7 @@ theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val constructor · rintro ⟨m, he⟩ cases' m with m - · erw [mul_zero, mul_eq_zero] at he + · rw [mul_zero, mul_eq_zero] at he rcases he with (⟨⟨⟩⟩ | he) exact Or.inl (a.val_eq_zero.1 he) cases m @@ -1139,7 +1138,7 @@ theorem valMinAbs_def_pos {n : ℕ} [NeZero n] (x : ZMod n) : @[simp, norm_cast] theorem coe_valMinAbs : ∀ {n : ℕ} (x : ZMod n), (x.valMinAbs : ZMod n) = x - | 0, x => Int.cast_id + | 0, _ => Int.cast_id | k@(n + 1), x => by rw [valMinAbs_def_pos] split_ifs @@ -1218,7 +1217,7 @@ theorem valMinAbs_eq_zero {n : ℕ} (x : ZMod n) : x.valMinAbs = 0 ↔ x = 0 := theorem natCast_natAbs_valMinAbs {n : ℕ} [NeZero n] (a : ZMod n) : (a.valMinAbs.natAbs : ZMod n) = if a.val ≤ (n : ℕ) / 2 then a else -a := by have : (a.val : ℤ) - n ≤ 0 := by - erw [sub_nonpos, Int.ofNat_le] + rw [sub_nonpos, Int.ofNat_le] exact a.val_le rw [valMinAbs_def_pos] split_ifs @@ -1331,9 +1330,9 @@ instance instField : Field (ZMod p) where mul_inv_cancel := mul_inv_cancel_aux p inv_zero := inv_zero p nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun a x => rfl + qsmul_def := fun _ _ => rfl /-- `ZMod p` is an integral domain when `p` is prime. -/ instance (p : ℕ) [hp : Fact p.Prime] : IsDomain (ZMod p) := by @@ -1432,9 +1431,26 @@ end lift end ZMod +/-! +### Groups of bounded torsion + +For `G` a group and `n` a natural number, `G` having torsion dividing `n` +(`∀ x : G, n • x = 0`) can be derived from `Module R G` where `R` has characteristic dividing `n`. + +It is however painful to have the API for such groups `G` stated in this generality, as `R` does not +appear anywhere in the lemmas' return type. Instead of writing the API in terms of a general `R`, we +therefore specialise to the canonical ring of order `n`, namely `ZMod n`. + +This spelling `Module (ZMod n) G` has the extra advantage of providing the canonical action by +`ZMod n`. It is however Type-valued, so we might want to acquire a Prop-valued version in the +future. +-/ + section Module -variable {S G : Type*} [AddCommGroup G] {n : ℕ} [Module (ZMod n) G] [SetLike S G] - [AddSubgroupClass S G] {K : S} {x : G} +variable {n : ℕ} {S G : Type*} [AddCommGroup G] [SetLike S G] [AddSubgroupClass S G] {K : S} {x : G} + +section general +variable [Module (ZMod n) G] {x : G} lemma zmod_smul_mem (hx : x ∈ K) : ∀ a : ZMod n, a • x ∈ K := by simpa [ZMod.forall, Int.cast_smul_eq_zsmul] using zsmul_mem hx @@ -1453,6 +1469,44 @@ instance instZModModule : Module (ZMod n) K := Subtype.coe_injective.module _ (AddSubmonoidClass.subtype K) coe_zmod_smul end AddSubgroupClass + +variable (n) + +lemma ZModModule.char_nsmul_eq_zero (x : G) : n • x = 0 := by + simp [← Nat.cast_smul_eq_nsmul (ZMod n)] + +variable (G) in +lemma ZModModule.char_ne_one [Nontrivial G] : n ≠ 1 := by + rintro rfl + obtain ⟨x, hx⟩ := exists_ne (0 : G) + exact hx <| by simpa using char_nsmul_eq_zero 1 x + +variable (G) in +lemma ZModModule.two_le_char [NeZero n] [Nontrivial G] : 2 ≤ n := by + have := NeZero.ne n + have := char_ne_one n G + omega + +lemma ZModModule.periodicPts_add_left [NeZero n] (x : G) : periodicPts (x + ·) = .univ := + Set.eq_univ_of_forall fun y ↦ ⟨n, NeZero.pos n, by + simpa [char_nsmul_eq_zero, IsPeriodicPt] using isFixedPt_id _⟩ + +end general + +section two +variable [Module (ZMod 2) G] + +lemma ZModModule.add_self (x : G) : x + x = 0 := by + simpa [two_nsmul] using char_nsmul_eq_zero 2 x + +lemma ZModModule.neg_eq_self (x : G) : -x = x := by simp [add_self, eq_comm, ← sub_eq_zero] + +lemma ZModModule.sub_eq_add (x y : G) : x - y = x + y := by simp [neg_eq_self, sub_eq_add_neg] + +lemma ZModModule.add_add_add_cancel (x y z : G) : (x + y) + (y + z) = x + z := by + simpa [sub_eq_add] using sub_add_sub_cancel x y z + +end two end Module section AddGroup diff --git a/Mathlib/Data/ZMod/Defs.lean b/Mathlib/Data/ZMod/Defs.lean index 76e27012548a5..97124f237c44e 100644 --- a/Mathlib/Data/ZMod/Defs.lean +++ b/Mathlib/Data/ZMod/Defs.lean @@ -16,14 +16,14 @@ This file provides the basic details of `ZMod n`, including its commutative ring ## Implementation details -This used to be inlined into `Data.ZMod.Basic`. This file imports `CharP.Basic`, which is an +This used to be inlined into `Data.ZMod.Basic`. This file imports `CharP.Lemmas`, which is an issue; all `CharP` instances create an `Algebra (ZMod p) R` instance; however, this instance may not be definitionally equal to other `Algebra` instances (for example, `GaloisField` also has an `Algebra` instance as it is defined as a `SplittingField`). The way to fix this is to use the forgetful inheritance pattern, and make `CharP` carry the data of what the `smul` should be (so for example, the `smul` on the `GaloisField` `CharP` instance should be equal to the `smul` from its `SplittingField` structure); there is only one possible `ZMod p` algebra for any `p`, so this -is not an issue mathematically. For this to be possible, however, we need `CharP.Basic` to be +is not an issue mathematically. For this to be possible, however, we need `CharP.Lemmas` to be able to import some part of `ZMod`. -/ @@ -45,7 +45,7 @@ open Nat.ModEq Int /-- Multiplicative commutative semigroup structure on `Fin n`. -/ instance instCommSemigroup (n : ℕ) : CommSemigroup (Fin n) := { inferInstanceAs (Mul (Fin n)) with - mul_assoc := fun ⟨a, ha⟩ ⟨b, hb⟩ ⟨c, hc⟩ => + mul_assoc := fun ⟨a, _⟩ ⟨b, _⟩ ⟨c, _⟩ => Fin.eq_of_val_eq <| calc a * b % n * c ≡ a * b * c [MOD n] := (Nat.mod_modEq _ _).mul_right _ @@ -54,7 +54,7 @@ instance instCommSemigroup (n : ℕ) : CommSemigroup (Fin n) := mul_comm := Fin.mul_comm } private theorem left_distrib_aux (n : ℕ) : ∀ a b c : Fin n, a * (b + c) = a * b + a * c := - fun ⟨a, ha⟩ ⟨b, hb⟩ ⟨c, hc⟩ => + fun ⟨a, _⟩ ⟨b, _⟩ ⟨c, _⟩ => Fin.eq_of_val_eq <| calc a * ((b + c) % n) ≡ a * (b + c) [MOD n] := (Nat.mod_modEq _ _).mul_left _ diff --git a/Mathlib/Data/ZMod/IntUnitsPower.lean b/Mathlib/Data/ZMod/IntUnitsPower.lean index 4d6bd6c1d8b3d..c627c6cd17d15 100644 --- a/Mathlib/Data/ZMod/IntUnitsPower.lean +++ b/Mathlib/Data/ZMod/IntUnitsPower.lean @@ -35,12 +35,12 @@ lemma ZMod.natCast_smul_units (n : ℕ) (au : Additive ℤˣ) : (n : ZMod 2) • /-- This is an indirect way of saying that `ℤˣ` has a power operation by `ZMod 2`. -/ instance : Module (ZMod 2) (Additive ℤˣ) where smul z au := .ofMul <| Additive.toMul au ^ z.val - one_smul au := Additive.toMul.injective <| pow_one _ + one_smul _ := Additive.toMul.injective <| pow_one _ mul_smul z₁ z₂ au := Additive.toMul.injective <| by dsimp only [ZMod.smul_units_def, toMul_nsmul] rw [← pow_mul, ZMod.val_mul, ← Int.units_pow_eq_pow_mod_two, mul_comm] - smul_zero z := Additive.toMul.injective <| one_pow _ - smul_add z au₁ au₂ := Additive.toMul.injective <| mul_pow _ _ _ + smul_zero _ := Additive.toMul.injective <| one_pow _ + smul_add _ _ _ := Additive.toMul.injective <| mul_pow _ _ _ add_smul z₁ z₂ au := Additive.toMul.injective <| by dsimp only [ZMod.smul_units_def, toMul_nsmul, toMul_add] rw [← pow_add, ZMod.val_add, ← Int.units_pow_eq_pow_mod_two] diff --git a/Mathlib/Data/ZMod/Quotient.lean b/Mathlib/Data/ZMod/Quotient.lean index 3ea9499281fd8..031fa4b2b17ad 100644 --- a/Mathlib/Data/ZMod/Quotient.lean +++ b/Mathlib/Data/ZMod/Quotient.lean @@ -6,7 +6,7 @@ Authors: Anne Baanen import Mathlib.Algebra.Group.Equiv.TypeTags import Mathlib.Data.ZMod.Basic import Mathlib.GroupTheory.GroupAction.Quotient -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Int.Basic import Mathlib.RingTheory.ZMod diff --git a/Mathlib/Init/Algebra/Classes.lean b/Mathlib/Deprecated/AlgebraClasses.lean similarity index 95% rename from Mathlib/Init/Algebra/Classes.lean rename to Mathlib/Deprecated/AlgebraClasses.lean index c7be944592e5c..cc26f497422b2 100644 --- a/Mathlib/Init/Algebra/Classes.lean +++ b/Mathlib/Deprecated/AlgebraClasses.lean @@ -6,12 +6,10 @@ Authors: Leonardo de Moura import Mathlib.Order.Defs /-! -# Note about `Mathlib/Init/` -The files in `Mathlib/Init` are leftovers from the port from Mathlib3. -(They contain content moved from lean3 itself that Mathlib needed but was not moved to lean4.) +# Note about deprecated files -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. # Unbundled algebra classes @@ -25,7 +23,7 @@ set_option linter.deprecated false universe u v -variable {α : Sort u} {β : Sort v} +variable {α : Sort u} @[deprecated (since := "2024-09-11")] class IsLeftCancel (α : Sort u) (op : α → α → α) : Prop where diff --git a/Mathlib/Data/ByteArray.lean b/Mathlib/Deprecated/ByteArray.lean similarity index 100% rename from Mathlib/Data/ByteArray.lean rename to Mathlib/Deprecated/ByteArray.lean diff --git a/Mathlib/Deprecated/Combinator.lean b/Mathlib/Deprecated/Combinator.lean index a19596bdeb6eb..5c79bf0837a59 100644 --- a/Mathlib/Deprecated/Combinator.lean +++ b/Mathlib/Deprecated/Combinator.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Mario Carneiro -/ +import Mathlib.Init + /-! # Deprecated combinators, ported from Lean 3 core. -/ diff --git a/Mathlib/Deprecated/Equiv.lean b/Mathlib/Deprecated/Equiv.lean new file mode 100644 index 0000000000000..74bc9b68ecdd3 --- /dev/null +++ b/Mathlib/Deprecated/Equiv.lean @@ -0,0 +1,30 @@ +/- +Copyright (c) 2015 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Mario Carneiro +-/ +import Mathlib.Deprecated.AlgebraClasses +import Mathlib.Logic.Equiv.Defs +/-! +# Note about deprecated files + +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. + +# Unbundled algebra classes and `Equiv` + +This file contains a few deprecated results on the `Is*` classes introduced in +`Mathlib/Deprecated/AlgebraClasses.lean` that involve the `Equiv` type. +-/ + +variable {α₁ β₁ : Type*} (e : α₁ ≃ β₁) (f : α₁ → α₁ → α₁) + +set_option linter.deprecated false + +@[deprecated (since := "2024-09-11")] +instance [IsLeftCancel α₁ f] : IsLeftCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := + ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsLeftCancel.left_cancel _ f _ x y z⟩ + +@[deprecated (since := "2024-09-11")] +instance [IsRightCancel α₁ f] : IsRightCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := + ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsRightCancel.right_cancel _ f _ x y z⟩ diff --git a/Mathlib/Deprecated/Group.lean b/Mathlib/Deprecated/Group.lean index d2d59cec9f5b0..539782f49e725 100644 --- a/Mathlib/Deprecated/Group.lean +++ b/Mathlib/Deprecated/Group.lean @@ -359,7 +359,7 @@ end Units namespace IsUnit -variable {M : Type*} {N : Type*} [Monoid M] [Monoid N] {x : M} +variable {M : Type*} {N : Type*} [Monoid M] [Monoid N] theorem map' {f : M → N} (hf : IsMonoidHom f) {x : M} (h : IsUnit x) : IsUnit (f x) := h.map (MonoidHom.of hf) diff --git a/Mathlib/Init/Logic.lean b/Mathlib/Deprecated/Logic.lean similarity index 97% rename from Mathlib/Init/Logic.lean rename to Mathlib/Deprecated/Logic.lean index 5fae3e2475809..0117b26449c81 100644 --- a/Mathlib/Init/Logic.lean +++ b/Mathlib/Deprecated/Logic.lean @@ -4,14 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn -/ import Batteries.Tactic.Alias +import Mathlib.Init /-! -# Note about `Mathlib/Init/` -The files in `Mathlib/Init` are leftovers from the port from Mathlib3. -(They contain content moved from lean3 itself that Mathlib needed but was not moved to lean4.) +# Note about deprecated files -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. -/ set_option linter.deprecated false diff --git a/Mathlib/Deprecated/MinMax.lean b/Mathlib/Deprecated/MinMax.lean new file mode 100644 index 0000000000000..1263096222aef --- /dev/null +++ b/Mathlib/Deprecated/MinMax.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2017 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro +-/ +import Mathlib.Deprecated.Logic +import Mathlib.Order.MinMax +/-! +# Note about deprecated files + +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. +-/ + +universe u + +variable {α : Type u} [LinearOrder α] + +set_option linter.deprecated false + +@[deprecated instCommutativeMax (since := "2024-09-12")] +theorem max_commutative : Commutative (α := α) max := max_comm +@[deprecated instAssociativeMax (since := "2024-09-12")] +theorem max_associative : Associative (α := α) max := max_assoc +@[deprecated instCommutativeMin (since := "2024-09-12")] +theorem min_commutative : Commutative (α := α) min := min_comm +@[deprecated instAssociativeMin (since := "2024-09-12")] +theorem min_associative : Associative (α := α) min := min_assoc diff --git a/Mathlib/Init/Data/Nat/Lemmas.lean b/Mathlib/Deprecated/NatLemmas.lean similarity index 83% rename from Mathlib/Init/Data/Nat/Lemmas.lean rename to Mathlib/Deprecated/NatLemmas.lean index fe8bd94cacac2..37fd557b3fec3 100644 --- a/Mathlib/Init/Data/Nat/Lemmas.lean +++ b/Mathlib/Deprecated/NatLemmas.lean @@ -8,12 +8,10 @@ import Mathlib.Util.AssertExists import Mathlib.Data.Nat.Notation /-! -# Note about `Mathlib/Init/` -The files in `Mathlib/Init` are leftovers from the port from Mathlib3. -(They contain content moved from lean3 itself that Mathlib needed but was not moved to lean4.) +# Note about deprecated files -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. -/ assert_not_exists Preorder diff --git a/Mathlib/Deprecated/RelClasses.lean b/Mathlib/Deprecated/RelClasses.lean new file mode 100644 index 0000000000000..357b10283c2d5 --- /dev/null +++ b/Mathlib/Deprecated/RelClasses.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2020 Jeremy Avigad. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jeremy Avigad, Mario Carneiro, Yury Kudryashov +-/ +import Mathlib.Deprecated.AlgebraClasses +import Mathlib.Order.RelClasses + +/-! +# Note about deprecated files + +This file is deprecated, and is no longer imported by anything in mathlib other than other +deprecated files, and test files. You should not need to import it. + +# Unbundled relation classes + +In this file we prove some properties of `Is*` classes defined in +`Mathlib/Deprecated/AlgebraClasses.lean`. + +-/ + +set_option linter.deprecated false + +universe u v + +variable {α : Type u} + +open Function + +@[deprecated (since := "2024-07-30")] +theorem IsTotalPreorder.swap (r) [IsTotalPreorder α r] : IsTotalPreorder α (swap r) := + { @IsPreorder.swap α r _, @IsTotal.swap α r _ with } + +@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where +@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where + +@[deprecated (since := "2024-07-30")] +instance [LinearOrder α] : IsIncompTrans α (· < ·) := by infer_instance diff --git a/Mathlib/Deprecated/Ring.lean b/Mathlib/Deprecated/Ring.lean index 5cc4f4a17e1ca..fc34ab12c07ee 100644 --- a/Mathlib/Deprecated/Ring.lean +++ b/Mathlib/Deprecated/Ring.lean @@ -27,7 +27,7 @@ IsSemiringHom, IsRingHom -/ -universe u v w +universe u v variable {α : Type u} @@ -45,7 +45,7 @@ structure IsSemiringHom {α : Type u} {β : Type v} [Semiring α] [Semiring β] namespace IsSemiringHom variable {β : Type v} [Semiring α] [Semiring β] -variable {f : α → β} (hf : IsSemiringHom f) {x y : α} +variable {f : α → β} /-- The identity map is a semiring homomorphism. -/ theorem id : IsSemiringHom (@id α) := by constructor <;> intros <;> rfl @@ -85,7 +85,7 @@ variable {β : Type v} [Ring α] [Ring β] theorem of_semiring {f : α → β} (H : IsSemiringHom f) : IsRingHom f := { H with } -variable {f : α → β} (hf : IsRingHom f) {x y : α} +variable {f : α → β} {x y : α} /-- Ring homomorphisms map zero to zero. -/ theorem map_zero (hf : IsRingHom f) : f 0 = 0 := @@ -122,7 +122,7 @@ theorem to_isAddGroupHom (hf : IsRingHom f) : IsAddGroupHom f := end IsRingHom -variable {β : Type v} {γ : Type w} {rα : Semiring α} {rβ : Semiring β} +variable {β : Type v} {rα : Semiring α} {rβ : Semiring β} namespace RingHom diff --git a/Mathlib/Deprecated/Subgroup.lean b/Mathlib/Deprecated/Subgroup.lean index f30ed0f0e3ca3..5c168b0eb1a99 100644 --- a/Mathlib/Deprecated/Subgroup.lean +++ b/Mathlib/Deprecated/Subgroup.lean @@ -32,7 +32,7 @@ subgroup, subgroups, IsSubgroup open Set Function -variable {G : Type*} {H : Type*} {A : Type*} {a a₁ a₂ b c : G} +variable {G : Type*} {H : Type*} {A : Type*} {a b : G} section Group @@ -456,8 +456,8 @@ theorem exists_list_of_mem_closure {s : Set G} {a : G} (h : a ∈ closure s) : InClosure.recOn h (fun {x} hxs => ⟨[x], List.forall_mem_singleton.2 <| Or.inl hxs, List.prod_singleton⟩) ⟨[], List.forall_mem_nil _, rfl⟩ - (fun {x} _ ⟨L, HL1, HL2⟩ => - ⟨L.reverse.map Inv.inv, fun x hx => + (fun {_} _ ⟨L, HL1, HL2⟩ => + ⟨L.reverse.map Inv.inv, fun _ hx => let ⟨y, hy1, hy2⟩ := List.exists_of_mem_map hx hy2 ▸ Or.imp id (by rw [inv_inv]; exact id) (HL1 _ <| List.mem_reverse.1 hy1).symm, HL2 ▸ diff --git a/Mathlib/Deprecated/Submonoid.lean b/Mathlib/Deprecated/Submonoid.lean index ef7d983287a9d..f85c670a230b8 100644 --- a/Mathlib/Deprecated/Submonoid.lean +++ b/Mathlib/Deprecated/Submonoid.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzzard -/ import Mathlib.Algebra.BigOperators.Group.Finset -import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Deprecated.Group /-! @@ -347,7 +347,7 @@ theorem mem_closure_union_iff {M : Type*} [CommMonoid M] {s t : Set M} {x : M} : ⟨y, hy, z * hd, (closure.isSubmonoid _).mul_mem hz (subset_closure ht), by rw [← mul_assoc, List.prod_cons, ← hyzx, mul_comm hd]⟩) HL1, - fun ⟨y, hy, z, hz, hyzx⟩ => + fun ⟨_, hy, _, hz, hyzx⟩ => hyzx ▸ (closure.isSubmonoid _).mul_mem (closure_mono Set.subset_union_left hy) (closure_mono Set.subset_union_right hz)⟩ diff --git a/Mathlib/Deprecated/Subring.lean b/Mathlib/Deprecated/Subring.lean index 20fc691ea4b93..b4b7c02b787e0 100644 --- a/Mathlib/Deprecated/Subring.lean +++ b/Mathlib/Deprecated/Subring.lean @@ -64,8 +64,6 @@ theorem isSubring_set_range {R : Type u} {S : Type v} [Ring R] [Ring S] (f : R end RingHom -variable {cR : Type u} [CommRing cR] - theorem IsSubring.inter {S₁ S₂ : Set R} (hS₁ : IsSubring S₁) (hS₂ : IsSubring S₂) : IsSubring (S₁ ∩ S₂) := { IsAddSubgroup.inter hS₁.toIsAddSubgroup hS₂.toIsAddSubgroup, diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean index bf93db2355a6d..65ee8350a4451 100644 --- a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean +++ b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean @@ -164,9 +164,9 @@ instance : Monoid CircleDeg1Lift where { toOrderHom := f.1.comp g.1 map_add_one' := fun x => by simp [map_add_one] } one := ⟨.id, fun _ => rfl⟩ - mul_one f := rfl - one_mul f := rfl - mul_assoc f₁ f₂ f₃ := DFunLike.coe_injective rfl + mul_one _ := rfl + one_mul _ := rfl + mul_assoc _ _ _ := DFunLike.coe_injective rfl instance : Inhabited CircleDeg1Lift := ⟨1⟩ @@ -201,7 +201,7 @@ def toOrderIso : CircleDeg1Liftˣ →* ℝ ≃o ℝ where right_inv := units_apply_inv_apply f map_rel_iff' := ⟨fun h => by simpa using mono (↑f⁻¹) h, mono f⟩ } map_one' := rfl - map_mul' f g := rfl + map_mul' _ _ := rfl @[simp] theorem coe_toOrderIso (f : CircleDeg1Liftˣ) : ⇑(toOrderIso f) = f := @@ -350,23 +350,23 @@ theorem map_fract_sub_fract_eq (x : ℝ) : f (fract x) - fract x = f x - x := by noncomputable instance : Lattice CircleDeg1Lift where sup f g := { toFun := fun x => max (f x) (g x) - monotone' := fun x y h => max_le_max (f.mono h) (g.mono h) + monotone' := fun _ _ h => max_le_max (f.mono h) (g.mono h) -- TODO: generalize to `Monotone.max` map_add_one' := fun x => by simp [max_add_add_right] } le f g := ∀ x, f x ≤ g x le_refl f x := le_refl (f x) - le_trans f₁ f₂ f₃ h₁₂ h₂₃ x := le_trans (h₁₂ x) (h₂₃ x) - le_antisymm f₁ f₂ h₁₂ h₂₁ := ext fun x => le_antisymm (h₁₂ x) (h₂₁ x) + le_trans _ _ _ h₁₂ h₂₃ x := le_trans (h₁₂ x) (h₂₃ x) + le_antisymm _ _ h₁₂ h₂₁ := ext fun x => le_antisymm (h₁₂ x) (h₂₁ x) le_sup_left f g x := le_max_left (f x) (g x) le_sup_right f g x := le_max_right (f x) (g x) - sup_le f₁ f₂ f₃ h₁ h₂ x := max_le (h₁ x) (h₂ x) + sup_le _ _ _ h₁ h₂ x := max_le (h₁ x) (h₂ x) inf f g := { toFun := fun x => min (f x) (g x) - monotone' := fun x y h => min_le_min (f.mono h) (g.mono h) + monotone' := fun _ _ h => min_le_min (f.mono h) (g.mono h) map_add_one' := fun x => by simp [min_add_add_right] } inf_le_left f g x := min_le_left (f x) (g x) inf_le_right f g x := min_le_right (f x) (g x) - le_inf f₁ f₂ f₃ h₂ h₃ x := le_min (h₂ x) (h₃ x) + le_inf _ _ _ h₂ h₃ x := le_min (h₂ x) (h₃ x) @[simp] theorem sup_apply (x : ℝ) : (f ⊔ g) x = max (f x) (g x) := @@ -607,7 +607,7 @@ theorem tendsto_translationNumber_of_dist_bounded_aux (x : ℕ → ℝ) (C : ℝ theorem translationNumber_eq_of_dist_bounded {f g : CircleDeg1Lift} (C : ℝ) (H : ∀ n : ℕ, dist ((f ^ n) 0) ((g ^ n) 0) ≤ C) : τ f = τ g := Eq.symm <| g.translationNumber_eq_of_tendsto_aux <| - f.tendsto_translationNumber_of_dist_bounded_aux _ C H + f.tendsto_translationNumber_of_dist_bounded_aux (fun n ↦ (g ^ n) 0) C H @[simp] theorem translationNumber_one : τ 1 = 0 := diff --git a/Mathlib/Dynamics/Ergodic/Conservative.lean b/Mathlib/Dynamics/Ergodic/Conservative.lean index f89c15dd99f1b..2b9a33bb435ba 100644 --- a/Mathlib/Dynamics/Ergodic/Conservative.lean +++ b/Mathlib/Dynamics/Ergodic/Conservative.lean @@ -40,7 +40,7 @@ noncomputable section open Set Filter MeasureTheory Finset Function TopologicalSpace Topology -variable {ι : Type*} {α : Type*} [MeasurableSpace α] {f : α → α} {s : Set α} {μ : Measure α} +variable {α : Type*} [MeasurableSpace α] {f : α → α} {s : Set α} {μ : Measure α} namespace MeasureTheory diff --git a/Mathlib/Dynamics/Ergodic/Ergodic.lean b/Mathlib/Dynamics/Ergodic/Ergodic.lean index eb2fbac4d06d4..6b1648fa292e1 100644 --- a/Mathlib/Dynamics/Ergodic/Ergodic.lean +++ b/Mathlib/Dynamics/Ergodic/Ergodic.lean @@ -80,7 +80,7 @@ end PreErgodic namespace MeasureTheory.MeasurePreserving -variable {β : Type*} {m' : MeasurableSpace β} {μ' : Measure β} {s' : Set β} {g : α → β} +variable {β : Type*} {m' : MeasurableSpace β} {μ' : Measure β} {g : α → β} theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ) {f' : β → β} (h_comm : Semiconj g f f') : PreErgodic f' μ' where diff --git a/Mathlib/Dynamics/FixedPoints/Basic.lean b/Mathlib/Dynamics/FixedPoints/Basic.lean index 9f13fb19bc6cf..78081cb348764 100644 --- a/Mathlib/Dynamics/FixedPoints/Basic.lean +++ b/Mathlib/Dynamics/FixedPoints/Basic.lean @@ -27,7 +27,7 @@ open Equiv universe u v -variable {α : Type u} {β : Type v} {f fa g : α → α} {x y : α} {fb : β → β} {m n k : ℕ} {e : Perm α} +variable {α : Type u} {β : Type v} {f fa g : α → α} {x : α} {fb : β → β} {e : Perm α} namespace Function diff --git a/Mathlib/Dynamics/FixedPoints/Topology.lean b/Mathlib/Dynamics/FixedPoints/Topology.lean index 092a3114204f4..c657d45d24997 100644 --- a/Mathlib/Dynamics/FixedPoints/Topology.lean +++ b/Mathlib/Dynamics/FixedPoints/Topology.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Johannes Hölzl -/ import Mathlib.Dynamics.FixedPoints.Basic -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Topological properties of fixed points diff --git a/Mathlib/Dynamics/Minimal.lean b/Mathlib/Dynamics/Minimal.lean index 394bd9cb13203..ce019b475eaf4 100644 --- a/Mathlib/Dynamics/Minimal.lean +++ b/Mathlib/Dynamics/Minimal.lean @@ -3,7 +3,6 @@ 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.GroupTheory.GroupAction.Basic import Mathlib.Topology.Algebra.ConstMulAction /-! diff --git a/Mathlib/Dynamics/PeriodicPts.lean b/Mathlib/Dynamics/PeriodicPts.lean index 160a6606f5e0f..6924fe05ed12c 100644 --- a/Mathlib/Dynamics/PeriodicPts.lean +++ b/Mathlib/Dynamics/PeriodicPts.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.GroupPower.IterateHom import Mathlib.Algebra.Ring.Divisibility.Basic +import Mathlib.Algebra.Ring.Int import Mathlib.Data.List.Cycle import Mathlib.Data.Nat.GCD.Basic import Mathlib.Data.Nat.Prime.Basic @@ -181,7 +182,7 @@ theorem Semiconj.mapsTo_ptsOfPeriod {g : α → β} (h : Semiconj g fa fb) (n : theorem bijOn_ptsOfPeriod (f : α → α) {n : ℕ} (hn : 0 < n) : BijOn f (ptsOfPeriod f n) (ptsOfPeriod f n) := - ⟨(Commute.refl f).mapsTo_ptsOfPeriod n, fun x hx y hy hxy => hx.eq_of_apply_eq_same hy hn hxy, + ⟨(Commute.refl f).mapsTo_ptsOfPeriod n, fun _ hx _ hy hxy => hx.eq_of_apply_eq_same hy hn hxy, fun x hx => ⟨f^[n.pred] x, hx.apply_iterate _, by rw [← comp_apply (f := f), comp_iterate_pred_of_pos f hn, hx.eq]⟩⟩ diff --git a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean index 2b8f40fded2bf..b5c4368d3eecd 100644 --- a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean +++ b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean @@ -274,7 +274,7 @@ lemma coverMincard_eq_zero_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : coverMincard T F U n = 0 ↔ F = ∅ := by refine Iff.intro (fun h ↦ subset_empty_iff.1 ?_) (fun F_empt ↦ by rw [F_empt, coverMincard_empty]) have := coverMincard_finite_iff T F U n - rw [h, eq_true ENat.zero_lt_top, true_iff] at this + rw [h, eq_true ENat.top_pos, true_iff] at this simp only [IsDynCoverOf, Finset.mem_coe, Nat.cast_eq_zero, Finset.card_eq_zero, exists_eq_right, Finset.not_mem_empty, iUnion_of_empty, iUnion_empty] at this exact this diff --git a/Mathlib/Dynamics/TopologicalEntropy/Semiconj.lean b/Mathlib/Dynamics/TopologicalEntropy/Semiconj.lean new file mode 100644 index 0000000000000..66d3c3288216b --- /dev/null +++ b/Mathlib/Dynamics/TopologicalEntropy/Semiconj.lean @@ -0,0 +1,231 @@ +/- +Copyright (c) 2024 Damien Thomine. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damien Thomine, Pietro Monticone +-/ +import Mathlib.Dynamics.TopologicalEntropy.CoverEntropy + +/-! +# Topological entropy of the image of a set under a semiconjugacy +Consider two dynamical systems `(X, S)` and `(Y, T)` together with a semiconjugacy `φ`: + + +``` +X ---S--> X +| | +φ φ +| | +v v +Y ---T--> Y +``` + +We relate the topological entropy of a subset `F ⊆ X` with the topological entropy +of its image `φ '' F ⊆ Y`. + +The best-known theorem is that, if all maps are uniformly continuous, then +`coverEntropy T (φ '' F) ≤ coverEntropy S F`. This is theorem +`coverEntropy_image_le_of_uniformContinuous` herein. We actually prove the much more general +statement that `coverEntropy T (φ '' F) = coverEntropy S F` if `X` is endowed with the pullback +by `φ` of the uniform structure of `Y`. + +This more general statement has another direct consequence: if `F` is `S`-invariant, then the +topological entropy of the restriction of `S` to `F` is exactly `coverEntropy S F`. This +corollary is essential: in most references, the entropy of an invariant subset (or subsystem) `F` is +defined as the entropy of the restriction to `F` of the system. We chose instead to give a direct +definition of the topological entropy of a subset, so as to avoid working with subtypes. Theorem +`coverEntropy_restrict` shows that this choice is coherent with the literature. + +## Implementation notes +We use only the definition of the topological entropy using covers; the simplest version of +`IsDynCoverOf.image` for nets fails. + +## Main results +- `coverEntropy_image_of_comap`/`coverEntropyInf_image_of_comap`: the entropy of `φ '' F` equals +the entropy of `F` if `X` is endowed with the pullback by `φ` of the uniform structure of `Y`. +- `coverEntropy_image_le_of_uniformContinuous`/`coverEntropyInf_image_le_of_uniformContinuous`: +the entropy of `φ '' F` is lower than the entropy of `F` if `φ` is uniformly continuous. +- `coverEntropy_restrict`: the entropy of the restriction of `S` to an invariant set `F` is +`coverEntropy S F`. + +## Tags +entropy, semiconjugacy +-/ + +namespace Dynamics + +open Function Prod Set Uniformity UniformSpace + +variable {X Y : Type*} {S : X → X} {T : Y → Y} {φ : X → Y} + +lemma IsDynCoverOf.image (h : Semiconj φ S T) {F : Set X} {V : Set (Y × Y)} {n : ℕ} {s : Set X} + (h' : IsDynCoverOf S F ((map φ φ) ⁻¹' V) n s) : + IsDynCoverOf T (φ '' F) V n (φ '' s) := by + simp only [IsDynCoverOf, image_subset_iff, preimage_iUnion₂, biUnion_image] + refine h'.trans (iUnion₂_mono fun i _ ↦ subset_of_eq ?_) + rw [← h.preimage_dynEntourage V n, ball_preimage] + +lemma IsDynCoverOf.preimage (h : Semiconj φ S T) {F : Set X} {V : Set (Y × Y)} + (V_symm : SymmetricRel V) {n : ℕ} {t : Finset Y} (h' : IsDynCoverOf T (φ '' F) V n t) : + ∃ s : Finset X, IsDynCoverOf S F ((map φ φ) ⁻¹' (V ○ V)) n s ∧ s.card ≤ t.card := by + classical + rcases isEmpty_or_nonempty X with _ | _ + · exact ⟨∅, eq_empty_of_isEmpty F ▸ ⟨isDynCoverOf_empty, Finset.card_empty ▸ zero_le t.card⟩⟩ + -- If `t` is a dynamical cover of `φ '' F`, then we want to choose one preimage by `φ` for each + -- element of `t`. This is complicated by the fact that `t` may not be a subset of `φ '' F`, + -- and may not even be in the range of `φ`. Hence, we first modify `t` to make it a subset + -- of `φ '' F`. This requires taking larger entourages. + rcases h'.nonempty_inter with ⟨s, s_cover, s_card, s_inter⟩ + choose! g gs_cover using fun (x : Y) (h : x ∈ s) ↦ nonempty_def.1 (s_inter x h) + choose! f f_section using fun (y : Y) (a : y ∈ φ '' F) ↦ a + refine ⟨s.image (f ∘ g), And.intro ?_ (Finset.card_image_le.trans s_card)⟩ + simp only [IsDynCoverOf, Finset.mem_coe, image_subset_iff, preimage_iUnion₂] at s_cover ⊢ + apply s_cover.trans + rw [← h.preimage_dynEntourage (V ○ V) n, Finset.set_biUnion_finset_image] + refine iUnion₂_mono fun i i_s ↦ ?_ + rw [comp_apply, ball_preimage, (f_section (g i) (gs_cover i i_s).2).2] + refine preimage_mono fun x x_i ↦ mem_ball_dynEntourage_comp T n V_symm x (g i) ⟨i, ?_⟩ + replace gs_cover := (gs_cover i i_s).1 + rw [mem_ball_symmetry (V_symm.dynEntourage T n)] at x_i gs_cover + exact ⟨x_i, gs_cover⟩ + +lemma le_coverMincard_image (h : Semiconj φ S T) (F : Set X) {V : Set (Y × Y)} + (V_symm : SymmetricRel V) (n : ℕ) : + coverMincard S F ((map φ φ) ⁻¹' (V ○ V)) n ≤ coverMincard T (φ '' F) V n := by + rcases eq_top_or_lt_top (coverMincard T (φ '' F) V n) with h' | h' + · exact h' ▸ le_top + rcases (coverMincard_finite_iff T (φ '' F) V n).1 h' with ⟨t, t_cover, t_card⟩ + rcases t_cover.preimage h V_symm with ⟨s, s_cover, s_card⟩ + rw [← t_card] + exact s_cover.coverMincard_le_card.trans (WithTop.coe_le_coe.2 s_card) + +lemma coverMincard_image_le (h : Semiconj φ S T) (F : Set X) (V : Set (Y × Y)) (n : ℕ) : + coverMincard T (φ '' F) V n ≤ coverMincard S F ((map φ φ) ⁻¹' V) n := by + classical + rcases eq_top_or_lt_top (coverMincard S F ((map φ φ) ⁻¹' V) n) with h' | h' + · exact h' ▸ le_top + rcases (coverMincard_finite_iff S F ((map φ φ) ⁻¹' V) n).1 h' with ⟨s, s_cover, s_card⟩ + rw [← s_card] + have := s_cover.image h + rw [← s.coe_image] at this + exact this.coverMincard_le_card.trans (WithTop.coe_le_coe.2 s.card_image_le) + +open ENNReal EReal Filter + +lemma le_coverEntropyEntourage_image (h : Semiconj φ S T) (F : Set X) {V : Set (Y × Y)} + (V_symm : SymmetricRel V) : + coverEntropyEntourage S F ((map φ φ) ⁻¹' (V ○ V)) ≤ coverEntropyEntourage T (φ '' F) V := + limsup_le_limsup (Eventually.of_forall fun n ↦ (monotone_div_right_of_nonneg (Nat.cast_nonneg' n) + (log_monotone (ENat.toENNReal_mono (le_coverMincard_image h F V_symm n))))) + +lemma le_coverEntropyInfEntourage_image (h : Semiconj φ S T) (F : Set X) {V : Set (Y × Y)} + (V_symm : SymmetricRel V) : + coverEntropyInfEntourage S F ((map φ φ) ⁻¹' (V ○ V)) ≤ coverEntropyInfEntourage T (φ '' F) V := + liminf_le_liminf (Eventually.of_forall fun n ↦ (monotone_div_right_of_nonneg (Nat.cast_nonneg' n) + (log_monotone (ENat.toENNReal_mono (le_coverMincard_image h F V_symm n))))) + +lemma coverEntropyEntourage_image_le (h : Semiconj φ S T) (F : Set X) (V : Set (Y × Y)) : + coverEntropyEntourage T (φ '' F) V ≤ coverEntropyEntourage S F ((map φ φ) ⁻¹' V) := + limsup_le_limsup (Eventually.of_forall fun n ↦ (monotone_div_right_of_nonneg (Nat.cast_nonneg' n) + (log_monotone (ENat.toENNReal_mono (coverMincard_image_le h F V n))))) + +lemma coverEntropyInfEntourage_image_le (h : Semiconj φ S T) (F : Set X) (V : Set (Y × Y)) : + coverEntropyInfEntourage T (φ '' F) V ≤ coverEntropyInfEntourage S F ((map φ φ) ⁻¹' V) := + liminf_le_liminf (Eventually.of_forall fun n ↦ (monotone_div_right_of_nonneg (Nat.cast_nonneg' n) + (log_monotone (ENat.toENNReal_mono (coverMincard_image_le h F V n))))) + +/-- The entropy of `φ '' F` equals the entropy of `F` if `X` is endowed with the pullback by `φ` + of the uniform structure of `Y`.-/ +theorem coverEntropy_image_of_comap (u : UniformSpace Y) {S : X → X} {T : Y → Y} {φ : X → Y} + (h : Semiconj φ S T) (F : Set X) : + coverEntropy T (φ '' F) = @coverEntropy X (comap φ u) S F := by + apply le_antisymm + · refine iSup₂_le fun V V_uni ↦ (coverEntropyEntourage_image_le h F V).trans ?_ + apply @coverEntropyEntourage_le_coverEntropy X (comap φ u) S F + rw [uniformity_comap φ, mem_comap] + exact ⟨V, V_uni, Subset.rfl⟩ + · refine iSup₂_le fun U U_uni ↦ ?_ + simp only [uniformity_comap φ, mem_comap] at U_uni + rcases U_uni with ⟨V, V_uni, V_sub⟩ + rcases comp_symm_mem_uniformity_sets V_uni with ⟨W, W_uni, W_symm, W_V⟩ + apply (coverEntropyEntourage_antitone S F ((preimage_mono W_V).trans V_sub)).trans + apply (le_coverEntropyEntourage_image h F W_symm).trans + exact coverEntropyEntourage_le_coverEntropy T (φ '' F) W_uni + +/-- The entropy of `φ '' F` equals the entropy of `F` if `X` is endowed with the pullback by `φ` + of the uniform structure of `Y`. This version uses a `liminf`.-/ +theorem coverEntropyInf_image_of_comap (u : UniformSpace Y) {S : X → X} {T : Y → Y} {φ : X → Y} + (h : Semiconj φ S T) (F : Set X) : + coverEntropyInf T (φ '' F) = @coverEntropyInf X (comap φ u) S F := by + apply le_antisymm + · refine iSup₂_le fun V V_uni ↦ (coverEntropyInfEntourage_image_le h F V).trans ?_ + apply @coverEntropyInfEntourage_le_coverEntropyInf X (comap φ u) S F + rw [uniformity_comap φ, mem_comap] + exact ⟨V, V_uni, Subset.rfl⟩ + · refine iSup₂_le fun U U_uni ↦ ?_ + simp only [uniformity_comap φ, mem_comap] at U_uni + rcases U_uni with ⟨V, V_uni, V_sub⟩ + rcases comp_symm_mem_uniformity_sets V_uni with ⟨W, W_uni, W_symm, W_V⟩ + apply (coverEntropyInfEntourage_antitone S F ((preimage_mono W_V).trans V_sub)).trans + apply (le_coverEntropyInfEntourage_image h F W_symm).trans + exact coverEntropyInfEntourage_le_coverEntropyInf T (φ '' F) W_uni + +open Subtype + +lemma coverEntropy_restrict_subset [UniformSpace X] {T : X → X} {F G : Set X} (hF : F ⊆ G) + (hG : MapsTo T G G) : + coverEntropy (hG.restrict T G G) (val ⁻¹' F) = coverEntropy T F := by + rw [← coverEntropy_image_of_comap _ hG.val_restrict_apply (val ⁻¹' F), image_preimage_coe G F, + inter_eq_right.2 hF] + +lemma coverEntropyInf_restrict_subset [UniformSpace X] {T : X → X} {F G : Set X} (hF : F ⊆ G) + (hG : MapsTo T G G) : + coverEntropyInf (hG.restrict T G G) (val ⁻¹' F) = coverEntropyInf T F := by + rw [← coverEntropyInf_image_of_comap _ hG.val_restrict_apply (val ⁻¹' F), image_preimage_coe G F, + inter_eq_right.2 hF] + +/-- The entropy of the restriction of `T` to an invariant set `F` is `coverEntropy S F`. This +theorem justifies our definition of `coverEntropy T F`.-/ +theorem coverEntropy_restrict [UniformSpace X] {T : X → X} {F : Set X} (h : MapsTo T F F) : + coverEntropy (h.restrict T F F) univ = coverEntropy T F := by + rw [← coverEntropy_restrict_subset Subset.rfl h, coe_preimage_self F] + +/-- The entropy of `φ '' F` is lower than entropy of `F` if `φ` is uniformly continuous.-/ +theorem coverEntropy_image_le_of_uniformContinuous [UniformSpace X] [UniformSpace Y] {S : X → X} + {T : Y → Y} {φ : X → Y} (h : Semiconj φ S T) (h' : UniformContinuous φ) (F : Set X) : + coverEntropy T (φ '' F) ≤ coverEntropy S F := by + rw [coverEntropy_image_of_comap _ h F] + exact coverEntropy_antitone S F (uniformContinuous_iff.1 h') + +/-- The entropy of `φ '' F` is lower than entropy of `F` if `φ` is uniformly continuous. This + version uses a `liminf`.-/ +theorem coverEntropyInf_image_le_of_uniformContinuous [UniformSpace X] [UniformSpace Y] {S : X → X} + {T : Y → Y} {φ : X → Y} (h : Semiconj φ S T) (h' : UniformContinuous φ) (F : Set X) : + coverEntropyInf T (φ '' F) ≤ coverEntropyInf S F := by + rw [coverEntropyInf_image_of_comap _ h F] + exact coverEntropyInf_antitone S F (uniformContinuous_iff.1 h') + +lemma coverEntropy_image_le_of_uniformContinuousOn_invariant [UniformSpace X] [UniformSpace Y] + {S : X → X} {T : Y → Y} {φ : X → Y} (h : Semiconj φ S T) {F G : Set X} + (h' : UniformContinuousOn φ G) (hF : F ⊆ G) (hG : MapsTo S G G) : + coverEntropy T (φ '' F) ≤ coverEntropy S F := by + rw [← coverEntropy_restrict_subset hF hG] + have hφ : Semiconj (G.restrict φ) (hG.restrict S G G) T := by + intro x + rw [G.restrict_apply, G.restrict_apply, hG.val_restrict_apply, h.eq x] + apply (coverEntropy_image_le_of_uniformContinuous hφ + (uniformContinuousOn_iff_restrict.1 h') (val ⁻¹' F)).trans_eq' + rw [← image_image_val_eq_restrict_image, image_preimage_coe G F, inter_eq_right.2 hF] + +lemma coverEntropyInf_image_le_of_uniformContinuousOn_invariant [UniformSpace X] [UniformSpace Y] + {S : X → X} {T : Y → Y} {φ : X → Y} (h : Semiconj φ S T) {F G : Set X} + (h' : UniformContinuousOn φ G) (hF : F ⊆ G) (hG : MapsTo S G G) : + coverEntropyInf T (φ '' F) ≤ coverEntropyInf S F := by + rw [← coverEntropyInf_restrict_subset hF hG] + have hφ : Semiconj (G.restrict φ) (hG.restrict S G G) T := by + intro a + rw [G.restrict_apply, G.restrict_apply, hG.val_restrict_apply, h.eq a] + apply (coverEntropyInf_image_le_of_uniformContinuous hφ + (uniformContinuousOn_iff_restrict.1 h') (val ⁻¹' F)).trans_eq' + rw [← image_image_val_eq_restrict_image, image_preimage_coe G F, inter_eq_right.2 hF] + +end Dynamics diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index c83073349810a..f5504ce434121 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -42,6 +42,10 @@ def adjoin : IntermediateField F E := { Subfield.closure (Set.range (algebraMap F E) ∪ S) with algebraMap_mem' := fun x => Subfield.subset_closure (Or.inl (Set.mem_range_self x)) } +@[simp] +theorem adjoin_toSubfield : + (adjoin F S).toSubfield = Subfield.closure (Set.range (algebraMap F E) ∪ S) := rfl + variable {S} theorem mem_adjoin_iff (x : E) : @@ -66,7 +70,7 @@ section Lattice variable {F : Type*} [Field F] {E : Type*} [Field E] [Algebra F E] @[simp] -theorem adjoin_le_iff {S : Set E} {T : IntermediateField F E} : adjoin F S ≤ T ↔ S ≤ T := +theorem adjoin_le_iff {S : Set E} {T : IntermediateField F E} : adjoin F S ≤ T ↔ S ⊆ T := ⟨fun H => le_trans (le_trans Set.subset_union_right Subfield.subset_closure) H, fun H => (@Subfield.closure_le E _ (Set.range (algebraMap F E) ∪ S) T.toSubfield).mpr (Set.union_subset (IntermediateField.set_range_subset T) H)⟩ @@ -90,6 +94,11 @@ instance : CompleteLattice (IntermediateField F E) where inv_mem' := by rintro x ⟨r, rfl⟩; exact ⟨r⁻¹, map_inv₀ _ _⟩ } bot_le x := (bot_le : ⊥ ≤ x.toSubalgebra) +theorem sup_def (S T : IntermediateField F E) : S ⊔ T = adjoin F (S ∪ T : Set E) := rfl + +theorem sSup_def (S : Set (IntermediateField F E)) : + sSup S = adjoin F (⋃₀ (SetLike.coe '' S)) := rfl + instance : Inhabited (IntermediateField F E) := ⟨⊤⟩ @@ -105,6 +114,9 @@ theorem mem_bot {x : E} : x ∈ (⊥ : IntermediateField F E) ↔ x ∈ Set.rang @[simp] theorem bot_toSubalgebra : (⊥ : IntermediateField F E).toSubalgebra = ⊥ := rfl +theorem bot_toSubfield : (⊥ : IntermediateField F E).toSubfield = (algebraMap F E).fieldRange := + rfl + @[simp] theorem coe_top : ↑(⊤ : IntermediateField F E) = (Set.univ : Set E) := rfl @@ -139,6 +151,16 @@ theorem inf_toSubfield (S T : IntermediateField F E) : (S ⊓ T).toSubfield = S.toSubfield ⊓ T.toSubfield := rfl +@[simp] +theorem sup_toSubfield (S T : IntermediateField F E) : + (S ⊔ T).toSubfield = S.toSubfield ⊔ T.toSubfield := by + rw [← S.toSubfield.closure_eq, ← T.toSubfield.closure_eq, ← Subfield.closure_union] + simp_rw [sup_def, adjoin_toSubfield, coe_toSubfield] + congr 1 + rw [Set.union_eq_right] + rintro _ ⟨x, rfl⟩ + exact Set.mem_union_left _ (algebraMap_mem S x) + @[simp, norm_cast] theorem coe_sInf (S : Set (IntermediateField F E)) : (↑(sInf S) : Set E) = sInf ((fun (x : IntermediateField F E) => (x : Set E)) '' S) := @@ -154,6 +176,21 @@ theorem sInf_toSubfield (S : Set (IntermediateField F E)) : (sInf S).toSubfield = sInf (toSubfield '' S) := SetLike.coe_injective <| by simp [Set.sUnion_image] +@[simp] +theorem sSup_toSubfield (S : Set (IntermediateField F E)) (hS : S.Nonempty) : + (sSup S).toSubfield = sSup (toSubfield '' S) := by + have h : toSubfield '' S = Subfield.closure '' (SetLike.coe '' S) := by + rw [Set.image_image] + congr! with x + exact x.toSubfield.closure_eq.symm + rw [h, sSup_image, ← Subfield.closure_sUnion, sSup_def, adjoin_toSubfield] + congr 1 + rw [Set.union_eq_right] + rintro _ ⟨x, rfl⟩ + obtain ⟨y, hy⟩ := hS + simp only [Set.mem_sUnion, Set.mem_image, exists_exists_and_eq_and, SetLike.mem_coe] + exact ⟨y, hy, algebraMap_mem y x⟩ + @[simp, norm_cast] theorem coe_iInf {ι : Sort*} (S : ι → IntermediateField F E) : (↑(iInf S) : Set E) = ⋂ i, S i := by simp [iInf] @@ -168,6 +205,11 @@ theorem iInf_toSubfield {ι : Sort*} (S : ι → IntermediateField F E) : (iInf S).toSubfield = ⨅ i, (S i).toSubfield := SetLike.coe_injective <| by simp [iInf] +@[simp] +theorem iSup_toSubfield {ι : Sort*} [Nonempty ι] (S : ι → IntermediateField F E) : + (iSup S).toSubfield = ⨆ i, (S i).toSubfield := by + simp only [iSup, Set.range_nonempty, sSup_toSubfield, ← Set.range_comp, Function.comp_def] + /-- Construct an algebra isomorphism from an equality of intermediate fields -/ @[simps! apply] def equivOfEq {S T : IntermediateField F E} (h : S = T) : S ≃ₐ[F] T := @@ -224,20 +266,35 @@ instance isScalarTower_over_bot : IsScalarTower (⊥ : IntermediateField F E) F This is the intermediate field version of `Subalgebra.topEquiv`. -/ @[simps!] def topEquiv : (⊤ : IntermediateField F E) ≃ₐ[F] E := - (Subalgebra.equivOfEq _ _ top_toSubalgebra).trans Subalgebra.topEquiv + Subalgebra.topEquiv -- Porting note: this theorem is now generated by the `@[simps!]` above. +section RestrictScalars + @[simp] theorem restrictScalars_bot_eq_self (K : IntermediateField F E) : (⊥ : IntermediateField K E).restrictScalars _ = K := SetLike.coe_injective Subtype.range_coe +variable {K : Type*} [Field K] [Algebra K E] [Algebra K F] [IsScalarTower K F E] + @[simp] -theorem restrictScalars_top {K : Type*} [Field K] [Algebra K E] [Algebra K F] - [IsScalarTower K F E] : (⊤ : IntermediateField F E).restrictScalars K = ⊤ := +theorem restrictScalars_top : (⊤ : IntermediateField F E).restrictScalars K = ⊤ := rfl +variable (K) +variable (L L' : IntermediateField F E) + +theorem restrictScalars_sup : + L.restrictScalars K ⊔ L'.restrictScalars K = (L ⊔ L').restrictScalars K := + toSubfield_injective (by simp) + +theorem restrictScalars_inf : + L.restrictScalars K ⊓ L'.restrictScalars K = (L ⊓ L').restrictScalars K := rfl + +end RestrictScalars + variable {K : Type*} [Field K] [Algebra F K] @[simp] @@ -361,24 +418,14 @@ theorem adjoin_subset_adjoin_iff {F' : Type*} [Field F'] [Algebra F' E] {S S' : theorem adjoin_adjoin_left (T : Set E) : (adjoin (adjoin F S) T).restrictScalars _ = adjoin F (S ∪ T) := by rw [SetLike.ext'_iff] - change (↑(adjoin (adjoin F S) T) : Set E) = _ - apply Set.eq_of_subset_of_subset <;> rw [adjoin_subset_adjoin_iff] <;> constructor + change (adjoin (adjoin F S) T : Set E) = _ + apply subset_antisymm <;> rw [adjoin_subset_adjoin_iff] <;> constructor · rintro _ ⟨⟨x, hx⟩, rfl⟩; exact adjoin.mono _ _ _ Set.subset_union_left hx · exact subset_adjoin_of_subset_right _ _ Set.subset_union_right --- Porting note: original proof times out - · rintro x ⟨f, rfl⟩ - refine Subfield.subset_closure ?_ - left - exact ⟨f, rfl⟩ --- Porting note: original proof times out - · refine Set.union_subset (fun x hx => Subfield.subset_closure ?_) - (fun x hx => Subfield.subset_closure ?_) - · left - refine ⟨⟨x, Subfield.subset_closure ?_⟩, rfl⟩ - right - exact hx - · right - exact hx + · exact Set.range_subset_iff.mpr fun f ↦ Subfield.subset_closure (.inl ⟨f, rfl⟩) + · exact Set.union_subset + (fun x hx ↦ Subfield.subset_closure <| .inl ⟨⟨x, Subfield.subset_closure (.inr hx)⟩, rfl⟩) + (fun x hx ↦ Subfield.subset_closure <| .inr hx) @[simp] theorem adjoin_insert_adjoin (x : E) : @@ -396,14 +443,10 @@ theorem adjoin_adjoin_comm (T : Set E) : rw [adjoin_adjoin_left, adjoin_adjoin_left, Set.union_comm] theorem adjoin_map {E' : Type*} [Field E'] [Algebra F E'] (f : E →ₐ[F] E') : - (adjoin F S).map f = adjoin F (f '' S) := by - ext x - show - x ∈ (Subfield.closure (Set.range (algebraMap F E) ∪ S)).map (f : E →+* E') ↔ - x ∈ Subfield.closure (Set.range (algebraMap F E') ∪ f '' S) - rw [RingHom.map_field_closure, Set.image_union, ← Set.range_comp, ← RingHom.coe_comp, - f.comp_algebraMap] - rfl + (adjoin F S).map f = adjoin F (f '' S) := + le_antisymm + (map_le_iff_le_comap.mpr <| adjoin_le_iff.mpr fun x hx ↦ subset_adjoin _ _ ⟨x, hx, rfl⟩) + (adjoin_le_iff.mpr <| Set.monotone_image <| subset_adjoin _ _) @[simp] theorem lift_adjoin (K : IntermediateField F E) (S : Set K) : @@ -471,9 +514,9 @@ theorem eq_adjoin_of_eq_algebra_adjoin (K : IntermediateField F E) (h : K.toSubalgebra = Algebra.adjoin F S) : K = adjoin F S := by apply toSubalgebra_injective rw [h] - refine (adjoin_eq_algebra_adjoin F _ ?_).symm - intro x - convert K.inv_mem (x := x) <;> rw [← h] <;> rfl + refine (adjoin_eq_algebra_adjoin F _ fun x ↦ ?_).symm + rw [← h] + exact K.inv_mem theorem adjoin_eq_top_of_algebra (hS : Algebra.adjoin F S = ⊤) : adjoin F S = ⊤ := top_le_iff.mp (hS.symm.trans_le <| algebra_adjoin_le_adjoin F S) @@ -561,12 +604,9 @@ theorem adjoin_simple_comm (β : E) : F⟮α⟯⟮β⟯.restrictScalars F = F⟮ variable {F} {α} theorem adjoin_algebraic_toSubalgebra {S : Set E} (hS : ∀ x ∈ S, IsAlgebraic F x) : - (IntermediateField.adjoin F S).toSubalgebra = Algebra.adjoin F S := by - simp only [isAlgebraic_iff_isIntegral] at hS - have : Algebra.IsIntegral F (Algebra.adjoin F S) := by - rwa [← le_integralClosure_iff_isIntegral, Algebra.adjoin_le_iff] - have : IsField (Algebra.adjoin F S) := isField_of_isIntegral_of_isField' (Field.toIsField F) - rw [← ((Algebra.adjoin F S).toIntermediateField' this).eq_adjoin_of_eq_algebra_adjoin F S] <;> rfl + (IntermediateField.adjoin F S).toSubalgebra = Algebra.adjoin F S := + adjoin_eq_algebra_adjoin _ _ fun _ ↦ + (Algebra.IsIntegral.adjoin fun x hx ↦ (hS x hx).isIntegral).inv_mem theorem adjoin_simple_toSubalgebra_of_integral (hα : IsIntegral F α) : F⟮α⟯.toSubalgebra = Algebra.adjoin F {α} := by @@ -845,7 +885,7 @@ variable {F : Type*} [Field F] {E : Type*} [Field E] [Algebra F E] {α : E} {S : @[simp] theorem adjoin_eq_bot_iff : adjoin F S = ⊥ ↔ S ⊆ (⊥ : IntermediateField F E) := by - rw [eq_bot_iff, adjoin_le_iff]; rfl + rw [eq_bot_iff, adjoin_le_iff] /- Porting note: this was tagged `simp`. -/ theorem adjoin_simple_eq_bot_iff : F⟮α⟯ = ⊥ ↔ α ∈ (⊥ : IntermediateField F E) := by @@ -1182,7 +1222,7 @@ open Module AdjoinRoot in in `K⟮α⟯` with `α` a root of `f`, then `f(g(x))` is irreducible. -/ theorem _root_.Polynomial.irreducible_comp {f g : K[X]} (hfm : f.Monic) (hgm : g.Monic) (hf : Irreducible f) - (hg : ∀ (E : Type u) [Field E] [Algebra K E] (x : E) (hx : minpoly K x = f), + (hg : ∀ (E : Type u) [Field E] [Algebra K E] (x : E) (_ : minpoly K x = f), Irreducible (g.map (algebraMap _ _) - C (AdjoinSimple.gen K x))) : Irreducible (f.comp g) := by have hf' : natDegree f ≠ 0 := @@ -1444,3 +1484,63 @@ theorem comap_map (f : L →ₐ[K] L') (S : IntermediateField K L) : (S.map f).c SetLike.coe_injective (Set.preimage_image_eq _ f.injective) end IntermediateField + +section ExtendScalars + +variable {K : Type*} [Field K] {L : Type*} [Field L] [Algebra K L] + +namespace Subfield + +variable (F : Subfield L) + +@[simp] +theorem extendScalars_self : extendScalars (le_refl F) = ⊥ := by + ext x + rw [mem_extendScalars, IntermediateField.mem_bot] + refine ⟨fun h ↦ ⟨⟨x, h⟩, rfl⟩, ?_⟩ + rintro ⟨y, rfl⟩ + exact y.2 + +@[simp] +theorem extendScalars_top : extendScalars (le_top : F ≤ ⊤) = ⊤ := + IntermediateField.toSubfield_injective (by simp) + +variable {F} +variable {E E' : Subfield L} (h : F ≤ E) (h' : F ≤ E') + +theorem extendScalars_sup : + extendScalars h ⊔ extendScalars h' = extendScalars (le_sup_of_le_left h : F ≤ E ⊔ E') := + ((extendScalars.orderIso F).map_sup ⟨_, h⟩ ⟨_, h'⟩).symm + +theorem extendScalars_inf : extendScalars h ⊓ extendScalars h' = extendScalars (le_inf h h') := + ((extendScalars.orderIso F).map_inf ⟨_, h⟩ ⟨_, h'⟩).symm + +end Subfield + +namespace IntermediateField + +variable (F : IntermediateField K L) + +@[simp] +theorem extendScalars_self : extendScalars (le_refl F) = ⊥ := + restrictScalars_injective K (by simp) + +@[simp] +theorem extendScalars_top : extendScalars (le_top : F ≤ ⊤) = ⊤ := + restrictScalars_injective K (by simp) + +variable {F} +variable {E E' : IntermediateField K L} (h : F ≤ E) (h' : F ≤ E') + +theorem extendScalars_sup : + extendScalars h ⊔ extendScalars h' = extendScalars (le_sup_of_le_left h : F ≤ E ⊔ E') := + ((extendScalars.orderIso F).map_sup ⟨_, h⟩ ⟨_, h'⟩).symm + +theorem extendScalars_inf : extendScalars h ⊓ extendScalars h' = extendScalars (le_inf h h') := + ((extendScalars.orderIso F).map_inf ⟨_, h⟩ ⟨_, h'⟩).symm + +end IntermediateField + +end ExtendScalars + +set_option linter.style.longFile 1700 diff --git a/Mathlib/FieldTheory/AlgebraicClosure.lean b/Mathlib/FieldTheory/AlgebraicClosure.lean new file mode 100644 index 0000000000000..d82e2ddcf8fd7 --- /dev/null +++ b/Mathlib/FieldTheory/AlgebraicClosure.lean @@ -0,0 +1,202 @@ +/- +Copyright (c) 2024 Jiedong Jiang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Junyan Xu, Jiedong Jiang +-/ +import Mathlib.FieldTheory.NormalClosure +import Mathlib.FieldTheory.IsAlgClosed.Basic +import Mathlib.FieldTheory.IntermediateField.Algebraic + +/-! +# Relative Algebraic Closure + +In this file we construct the relative algebraic closure of a field extension. + +## Main Definitions + +- `algebraicClosure F E` is the relative algebraic closure (i.e. the maximal algebraic subextension) + of the field extension `E / F`, which is defined to be the integral closure of `F` in `E`. + +-/ +noncomputable section + +open Polynomial FiniteDimensional IntermediateField Field + +variable (F E : Type*) [Field F] [Field E] [Algebra F E] +variable {K : Type*} [Field K] [Algebra F K] + +/-- +The *relative algebraic closure* of a field `F` in a field extension `E`, +also called the *maximal algebraic subextension* of `E / F`, +is defined to be the subalgebra `integralClosure F E` +upgraded to an intermediate field (since `F` and `E` are both fields). +This is exactly the intermediate field of `E / F` consisting of all integral/algebraic elements. +-/ +def algebraicClosure : IntermediateField F E := + Algebra.IsAlgebraic.toIntermediateField (integralClosure F E) + +variable {F E} + +/-- 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} : + x ∈ algebraicClosure F E ↔ IsIntegral F x := Iff.rfl + +/-- An element is contained in the algebraic closure of `F` in `E` if and only if +it is an algebraic element. -/ +theorem mem_algebraicClosure_iff {x : E} : + x ∈ algebraicClosure F E ↔ IsAlgebraic F x := isAlgebraic_iff_isIntegral.symm + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `i x` is contained in +`algebraicClosure F K` if and only if `x` is contained in `algebraicClosure F E`. -/ +theorem map_mem_algebraicClosure_iff (i : E →ₐ[F] K) {x : E} : + i x ∈ algebraicClosure F K ↔ x ∈ algebraicClosure F E := by + simp_rw [mem_algebraicClosure_iff', ← minpoly.ne_zero_iff, minpoly.algHom_eq i i.injective] + +namespace algebraicClosure + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the preimage of +`algebraicClosure F K` under the map `i` is equal to `algebraicClosure F E`. -/ +theorem comap_eq_of_algHom (i : E →ₐ[F] K) : + (algebraicClosure F K).comap i = algebraicClosure F E := by + ext x + exact map_mem_algebraicClosure_iff i + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the image of `algebraicClosure F E` +under the map `i` is contained in `algebraicClosure F K`. -/ +theorem map_le_of_algHom (i : E →ₐ[F] K) : + (algebraicClosure F E).map i ≤ algebraicClosure F K := + map_le_iff_le_comap.2 (comap_eq_of_algHom i).ge + +variable (F) in +/-- If `K / E / F` is a field extension tower, such that `K / E` has no non-trivial algebraic +subextensions (this means that it is purely transcendental), +then the image of `algebraicClosure F E` in `K` is equal to `algebraicClosure F K`. -/ +theorem map_eq_of_algebraicClosure_eq_bot [Algebra E K] [IsScalarTower F E K] + (h : algebraicClosure E K = ⊥) : + (algebraicClosure F E).map (IsScalarTower.toAlgHom F E K) = algebraicClosure F K := by + refine le_antisymm (map_le_of_algHom _) (fun x hx ↦ ?_) + obtain ⟨y, rfl⟩ := mem_bot.1 <| h ▸ mem_algebraicClosure_iff'.2 + (IsIntegral.tower_top <| mem_algebraicClosure_iff'.1 hx) + exact ⟨y, (map_mem_algebraicClosure_iff <| IsScalarTower.toAlgHom F E K).mp hx, rfl⟩ + +/-- If `i` is an `F`-algebra isomorphism of `E` and `K`, then the image of `algebraicClosure F E` +under the map `i` is equal to `algebraicClosure F K`. -/ +theorem map_eq_of_algEquiv (i : E ≃ₐ[F] K) : + (algebraicClosure F E).map i = algebraicClosure F K := + (map_le_of_algHom i.toAlgHom).antisymm + (fun x h ↦ ⟨_, (map_mem_algebraicClosure_iff i.symm).2 h, by simp⟩) + +/-- If `E` and `K` are isomorphic as `F`-algebras, then `algebraicClosure F E` and +`algebraicClosure F K` are also isomorphic as `F`-algebras. -/ +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 + +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⟩ + +/-- The algebraic closure of `F` in `E` is the integral closure of `F` in `E`. -/ +instance isIntegralClosure : IsIntegralClosure (algebraicClosure F E) F E := + inferInstanceAs (IsIntegralClosure (integralClosure F E) F E) + +end algebraicClosure + +variable (F E K) + +/-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` +if all of its elements are algebraic over `F`. -/ +theorem le_algebraicClosure' {L : IntermediateField F E} (hs : ∀ x : L, IsAlgebraic F x) : + L ≤ algebraicClosure F E := fun x h ↦ by + simpa only [mem_algebraicClosure_iff, IsAlgebraic, ne_eq, ← aeval_algebraMap_eq_zero_iff E, + Algebra.id.map_eq_id, RingHom.id_apply, IntermediateField.algebraMap_apply] using hs ⟨x, h⟩ + +/-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` +if it is algebraic over `F`. -/ +theorem le_algebraicClosure (L : IntermediateField F E) [Algebra.IsAlgebraic F L] : + L ≤ algebraicClosure F E := le_algebraicClosure' F E (Algebra.IsAlgebraic.isAlgebraic) + +/-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` +if and only if it is algebraic over `F`. -/ +theorem le_algebraicClosure_iff (L : IntermediateField F E) : + L ≤ algebraicClosure F E ↔ Algebra.IsAlgebraic F L := + ⟨fun h ↦ ⟨fun x ↦ by simpa only [IsAlgebraic, ne_eq, ← aeval_algebraMap_eq_zero_iff E, + IntermediateField.algebraMap_apply, + Algebra.id.map_eq_id, RingHomCompTriple.comp_apply, mem_algebraicClosure_iff] using h x.2⟩, + fun _ ↦ le_algebraicClosure _ _ _⟩ + +namespace algebraicClosure + +/-- The algebraic closure in `E` of the algebraic closure of `F` in `E` is equal to itself. -/ +theorem algebraicClosure_eq_bot : + algebraicClosure (algebraicClosure F E) E = ⊥ := + bot_unique fun x hx ↦ mem_bot.2 + ⟨⟨x, isIntegral_trans x (mem_algebraicClosure_iff'.1 hx)⟩, rfl⟩ + +/-- The normal closure in `E/F` of the algebraic closure of `F` in `E` is equal to itself. -/ +theorem normalClosure_eq_self : + normalClosure F (algebraicClosure F E) E = algebraicClosure F E := + le_antisymm (normalClosure_le_iff.2 fun i ↦ + haveI : Algebra.IsAlgebraic F i.fieldRange := (AlgEquiv.ofInjectiveField i).isAlgebraic + le_algebraicClosure F E _) (le_normalClosure _) + +end algebraicClosure + +/-- If `E / F` is a field extension and `E` is algebraically closed, then the algebraic closure +of `F` in `E` is equal to `F` if and only if `F` is algebraically closed. -/ +theorem IsAlgClosed.algebraicClosure_eq_bot_iff [IsAlgClosed E] : + algebraicClosure F E = ⊥ ↔ IsAlgClosed F := by + refine ⟨fun h ↦ IsAlgClosed.of_exists_root _ fun p hmon hirr ↦ ?_, + fun _ ↦ IntermediateField.eq_bot_of_isAlgClosed_of_isAlgebraic _⟩ + obtain ⟨x, hx⟩ := IsAlgClosed.exists_aeval_eq_zero E p (degree_pos_of_irreducible hirr).ne' + obtain ⟨x, rfl⟩ := h ▸ mem_algebraicClosure_iff'.2 (minpoly.ne_zero_iff.1 <| + ne_zero_of_dvd_ne_zero hmon.ne_zero (minpoly.dvd _ x hx)) + exact ⟨x, by simpa [Algebra.ofId_apply] using hx⟩ + +/-- `F(S) / F` is a algebraic extension if and only if all elements of `S` are +algebraic elements. -/ +theorem IntermediateField.isAlgebraic_adjoin_iff_isAlgebraic {S : Set E} : + Algebra.IsAlgebraic F (adjoin F S) ↔ ∀ x ∈ S, IsAlgebraic F x := + ((le_algebraicClosure_iff F E _).symm.trans (adjoin_le_iff.trans <| forall_congr' <| + fun _ => Iff.imp Iff.rfl mem_algebraicClosure_iff)) + +namespace algebraicClosure + +/-- If `E` is algebraically closed, then the algebraic closure of `F` in `E` is an absolute +algebraic closure of `F`. -/ +instance isAlgClosure [IsAlgClosed E] : IsAlgClosure F (algebraicClosure F E) := + ⟨(IsAlgClosed.algebraicClosure_eq_bot_iff _ E).mp (algebraicClosure_eq_bot F E), + isAlgebraic F E⟩ + +/-- The algebraic closure of `F` in `E` is equal to `E` if and only if `E / F` is +algebraic. -/ +theorem eq_top_iff : algebraicClosure F E = ⊤ ↔ Algebra.IsAlgebraic F E := + ⟨fun h ↦ ⟨fun _ ↦ mem_algebraicClosure_iff.1 (h ▸ mem_top)⟩, + fun _ ↦ top_unique fun x _ ↦ mem_algebraicClosure_iff.2 (Algebra.IsAlgebraic.isAlgebraic x)⟩ + +/-- If `K / E / F` is a field extension tower, then `algebraicClosure F K` is contained in +`algebraicClosure E K`. -/ +theorem le_restrictScalars [Algebra E K] [IsScalarTower F E K] : + algebraicClosure F K ≤ (algebraicClosure E K).restrictScalars F := + fun _ h ↦ mem_algebraicClosure_iff.2 <| IsAlgebraic.tower_top E (mem_algebraicClosure_iff.1 h) + +/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then +`algebraicClosure F K` is equal to `algebraicClosure E K`. -/ +theorem eq_restrictScalars_of_isAlgebraic [Algebra E K] [IsScalarTower F E K] + [Algebra.IsAlgebraic F E] : algebraicClosure F K = (algebraicClosure E K).restrictScalars F := + (algebraicClosure.le_restrictScalars F E K).antisymm fun _ h ↦ + isIntegral_trans _ h + +/-- If `K / E / F` is a field extension tower, then `E` adjoin `algebraicClosure F K` is contained +in `algebraicClosure E K`. -/ +theorem adjoin_le [Algebra E K] [IsScalarTower F E K] : + adjoin E (algebraicClosure F K) ≤ algebraicClosure E K := + adjoin_le_iff.2 <| le_restrictScalars F E K + +end algebraicClosure diff --git a/Mathlib/FieldTheory/AxGrothendieck.lean b/Mathlib/FieldTheory/AxGrothendieck.lean index e386e095dad39..9ddfa55c77de3 100644 --- a/Mathlib/FieldTheory/AxGrothendieck.lean +++ b/Mathlib/FieldTheory/AxGrothendieck.lean @@ -48,8 +48,7 @@ theorem ax_grothendieck_of_locally_finite {ι K R : Type*} [Field K] [Finite K] (mem_union_left _ (mem_biUnion.2 ⟨i, mem_univ _, mem_image_of_mem _ hk⟩)) letI := isNoetherian_adjoin_finset s fun x _ => Algebra.IsIntegral.isIntegral (R := K) x letI := Module.IsNoetherian.finite K (Algebra.adjoin K (s : Set R)) - letI : Finite (Algebra.adjoin K (s : Set R)) := - FiniteDimensional.finite_of_finite K (Algebra.adjoin K (s : Set R)) + letI : Finite (Algebra.adjoin K (s : Set R)) := Module.finite_of_finite K -- The restriction of the polynomial map, `ps`, to the subalgebra generated by `s` let res : (ι → Algebra.adjoin K (s : Set R)) → ι → Algebra.adjoin K (s : Set R) := fun x i => ⟨eval (fun j : ι => (x j : R)) (ps i), eval_mem (hs₁ _) fun i => (x i).2⟩ diff --git a/Mathlib/FieldTheory/Cardinality.lean b/Mathlib/FieldTheory/Cardinality.lean index 045db9322dcbf..f054c960147ca 100644 --- a/Mathlib/FieldTheory/Cardinality.lean +++ b/Mathlib/FieldTheory/Cardinality.lean @@ -59,16 +59,9 @@ theorem Fintype.not_isField_of_card_not_prime_pow {α} [Fintype α] [Ring α] : /-- Any infinite type can be endowed a field structure. -/ theorem Infinite.nonempty_field {α : Type u} [Infinite α] : Nonempty (Field α) := by - letI K := FractionRing (MvPolynomial α <| ULift.{u} ℚ) - suffices #α = #K by - obtain ⟨e⟩ := Cardinal.eq.1 this - exact ⟨e.field⟩ - rw [← IsLocalization.card K (MvPolynomial α <| ULift.{u} ℚ)⁰ le_rfl] - apply le_antisymm - · refine - ⟨⟨fun a => MvPolynomial.monomial (Finsupp.single a 1) (1 : ULift.{u} ℚ), fun x y h => ?_⟩⟩ - simpa [MvPolynomial.monomial_eq_monomial_iff, Finsupp.single_eq_single_iff] using h - · simp + suffices #α = #(FractionRing (MvPolynomial α <| ULift.{u} ℚ)) from + (Cardinal.eq.1 this).map (·.field) + simp /-- There is a field structure on type if and only if its cardinality is a prime power. -/ theorem Field.nonempty_iff {α : Type u} : Nonempty (Field α) ↔ IsPrimePow #α := by diff --git a/Mathlib/FieldTheory/Finite/Basic.lean b/Mathlib/FieldTheory/Finite/Basic.lean index 715387ba0669b..d34cb87cc5907 100644 --- a/Mathlib/FieldTheory/Finite/Basic.lean +++ b/Mathlib/FieldTheory/Finite/Basic.lean @@ -61,10 +61,10 @@ open Polynomial /-- The cardinality of a field is at most `n` times the cardinality of the image of a degree `n` polynomial -/ theorem card_image_polynomial_eval [DecidableEq R] [Fintype R] {p : R[X]} (hp : 0 < p.degree) : - Fintype.card R ≤ natDegree p * (univ.image fun x => eval x p).card := + Fintype.card R ≤ natDegree p * #(univ.image fun x => eval x p) := Finset.card_le_mul_card_image _ _ (fun a _ => calc - _ = (p - C a).roots.toFinset.card := + _ = #(p - C a).roots.toFinset := congr_arg card (by simp [Finset.ext_iff, ← mem_roots_sub_C hp]) _ ≤ Multiset.card (p - C a).roots := Multiset.toFinset_card_le _ _ ≤ _ := card_roots_sub_C' hp) @@ -80,17 +80,17 @@ theorem exists_root_sum_quadratic [Fintype R] {f g : R[X]} (hf2 : degree f = 2) rcases this with ⟨x, ⟨a, _, ha⟩, ⟨b, _, hb⟩⟩ exact ⟨a, b, by rw [ha, ← hb, eval_neg, neg_add_cancel]⟩ fun hd : Disjoint _ _ => - lt_irrefl (2 * ((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g)).card) <| - calc 2 * ((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g)).card + lt_irrefl (2 * #((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g))) <| + calc 2 * #((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g)) ≤ 2 * Fintype.card R := Nat.mul_le_mul_left _ (Finset.card_le_univ _) _ = Fintype.card R + Fintype.card R := two_mul _ - _ < natDegree f * (univ.image fun x : R => eval x f).card + - natDegree (-g) * (univ.image fun x : R => eval x (-g)).card := + _ < natDegree f * #(univ.image fun x : R => eval x f) + + natDegree (-g) * #(univ.image fun x : R => eval x (-g)) := (add_lt_add_of_lt_of_le (lt_of_le_of_ne (card_image_polynomial_eval (by rw [hf2]; decide)) (mt (congr_arg (· % 2)) (by simp [natDegree_eq_of_degree_eq_some hf2, hR]))) (card_image_polynomial_eval (by rw [degree_neg, hg2]; decide))) - _ = 2 * ((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g)).card := by + _ = 2 * #((univ.image fun x : R => eval x f) ∪ univ.image fun x : R => eval x (-g)) := by rw [card_union_of_disjoint hd] simp [natDegree_eq_of_degree_eq_some hf2, natDegree_eq_of_degree_eq_some hg2, mul_add] @@ -328,8 +328,6 @@ theorem X_pow_card_pow_sub_X_ne_zero (hn : n ≠ 0) (hp : 1 < p) : (X ^ p ^ n - end -variable (p : ℕ) [Fact p.Prime] [Algebra (ZMod p) K] - theorem roots_X_pow_card_sub_X : roots (X ^ q - X : K[X]) = Finset.univ.val := by classical have aux : (X ^ q - X : K[X]) ≠ 0 := X_pow_card_sub_X_ne_zero K Fintype.one_lt_card diff --git a/Mathlib/FieldTheory/Finite/GaloisField.lean b/Mathlib/FieldTheory/Finite/GaloisField.lean index 89b627d0328c8..e3868fc90d591 100644 --- a/Mathlib/FieldTheory/Finite/GaloisField.lean +++ b/Mathlib/FieldTheory/Finite/GaloisField.lean @@ -114,7 +114,7 @@ theorem finrank {n} (h : n ≠ 0) : Module.finrank (ZMod p) (GaloisField p n) = intro x hx -- We discharge the `p = 0` separately, to avoid typeclass issues on `ZMod p`. cases p; cases hp - refine Subring.closure_induction hx ?_ ?_ ?_ ?_ ?_ ?_ <;> simp_rw [mem_rootSet_of_ne aux] + refine Subring.closure_induction ?_ ?_ ?_ ?_ ?_ ?_ hx <;> simp_rw [mem_rootSet_of_ne aux] · rintro x (⟨r, rfl⟩ | hx) · simp only [g_poly, map_sub, map_pow, aeval_X] rw [← map_pow, ZMod.pow_card_pow, sub_self] @@ -127,14 +127,14 @@ theorem finrank {n} (h : n ≠ 0) : Module.finrank (ZMod p) (GaloisField p n) = exact Nat.not_lt_zero 1 (pow_eq_zero hn.symm ▸ hp) · simp [g_poly] · simp only [g_poly, aeval_X_pow, aeval_X, map_sub, add_pow_char_pow, sub_eq_zero] - intro x y hx hy + intro x y _ _ hx hy rw [hx, hy] - · intro x hx + · intro x _ hx simp only [g_poly, sub_eq_zero, aeval_X_pow, aeval_X, map_sub, sub_neg_eq_add] at * - rw [neg_pow, hx, CharP.neg_one_pow_char_pow] + rw [neg_pow, hx, neg_one_pow_char_pow] simp · simp only [g_poly, aeval_X_pow, aeval_X, map_sub, mul_pow, sub_eq_zero] - intro x y hx hy + intro x y _ _ hx hy rw [hx, hy] theorem card (h : n ≠ 0) : Fintype.card (GaloisField p n) = p ^ n := by diff --git a/Mathlib/FieldTheory/Finite/Polynomial.lean b/Mathlib/FieldTheory/Finite/Polynomial.lean index 00e92545eba5b..fa34749883456 100644 --- a/Mathlib/FieldTheory/Finite/Polynomial.lean +++ b/Mathlib/FieldTheory/Finite/Polynomial.lean @@ -99,7 +99,7 @@ end CommRing variable [Field K] theorem eval_indicator_apply_eq_zero (a b : σ → K) (h : a ≠ b) : eval a (indicator b) = 0 := by - obtain ⟨i, hi⟩ : ∃ i, a i ≠ b i := by rwa [Ne, Function.funext_iff, not_forall] at h + obtain ⟨i, hi⟩ : ∃ i, a i ≠ b i := by rwa [Ne, funext_iff, not_forall] at h simp only [indicator, map_prod, map_sub, map_one, map_pow, eval_X, eval_C, sub_self, Finset.prod_eq_zero_iff] refine ⟨i, Finset.mem_univ _, ?_⟩ @@ -173,18 +173,12 @@ noncomputable instance [CommRing K] : Inhabited (R σ K) := def evalᵢ [CommRing K] : R σ K →ₗ[K] (σ → K) → K := (evalₗ K σ).comp (restrictDegree σ K (Fintype.card K - 1)).subtype -section CommRing - -variable [CommRing K] - -- TODO: would be nice to replace this by suitable decidability assumptions open Classical in noncomputable instance decidableRestrictDegree (m : ℕ) : DecidablePred (· ∈ { n : σ →₀ ℕ | ∀ i, n i ≤ m }) := by simp only [Set.mem_setOf_eq]; infer_instance -end CommRing - variable [Field K] open Classical in @@ -200,7 +194,7 @@ theorem rank_R [Fintype σ] : Module.rank K (R σ K) = Fintype.card (σ → K) : refine forall_congr' fun n => le_tsub_iff_right ?_ exact Fintype.card_pos_iff.2 ⟨0⟩ _ = #(σ → { n // n < Fintype.card K }) := - (@Equiv.subtypePiEquivPi σ (fun _ => ℕ) fun s n => n < Fintype.card K).cardinal_eq + (@Equiv.subtypePiEquivPi σ (fun _ => ℕ) fun _ n => n < Fintype.card K).cardinal_eq _ = #(σ → Fin (Fintype.card K)) := (Equiv.arrowCongr (Equiv.refl σ) Fin.equivSubtype.symm).cardinal_eq _ = #(σ → K) := (Equiv.arrowCongr (Equiv.refl σ) (Fintype.equivFin K).symm).cardinal_eq diff --git a/Mathlib/FieldTheory/Fixed.lean b/Mathlib/FieldTheory/Fixed.lean index 965f23a35eefe..dab929cb5fbef 100644 --- a/Mathlib/FieldTheory/Fixed.lean +++ b/Mathlib/FieldTheory/Fixed.lean @@ -17,7 +17,7 @@ This is the basis of the Fundamental Theorem of Galois Theory. Given a (finite) group `G` that acts on a field `F`, we define `FixedPoints.subfield G F`, the subfield consisting of elements of `F` fixed_points by every element of `G`. -This subfield is then normal and separable, and in addition (TODO) if `G` acts faithfully on `F` +This subfield is then normal and separable, and in addition if `G` acts faithfully on `F` then `finrank (FixedPoints.subfield G F) F = Fintype.card G`. ## Main Definitions @@ -193,7 +193,7 @@ theorem of_eval₂ (f : Polynomial (FixedPoints.subfield G F)) have h : Polynomial.map (MulSemiringActionHom.toRingHom (IsInvariantSubring.subtypeHom G (subfield G F).toSubring)) f = Polynomial.map ((IsInvariantSubring.subtypeHom G (subfield G F).toSubring)) f := rfl - erw [← Polynomial.map_dvd_map' (Subfield.subtype <| FixedPoints.subfield G F), minpoly, this, + rw [← Polynomial.map_dvd_map' (Subfield.subtype <| FixedPoints.subfield G F), minpoly, this, Polynomial.map_toSubring _ _, prodXSubSMul] refine Fintype.prod_dvd_of_coprime @@ -246,7 +246,7 @@ theorem minpoly_eq_minpoly : minpoly G F x = _root_.minpoly (FixedPoints.subfiel theorem rank_le_card : Module.rank (FixedPoints.subfield G F) F ≤ Fintype.card G := rank_le fun s hs => by simpa only [rank_fun', Cardinal.mk_coe_finset, Finset.coe_sort_coe, Cardinal.lift_natCast, - Cardinal.natCast_le] using + Nat.cast_le] using (linearIndependent_smul_of_linearIndependent G F hs).cardinal_lift_le_rank end Fintype @@ -282,7 +282,7 @@ instance : FiniteDimensional (subfield G F) F := by end Finite theorem finrank_le_card [Fintype G] : finrank (subfield G F) F ≤ Fintype.card G := by - rw [← Cardinal.natCast_le, finrank_eq_rank] + rw [← @Nat.cast_le Cardinal, finrank_eq_rank] apply rank_le_card end FixedPoints @@ -311,8 +311,9 @@ theorem finrank_algHom (K : Type u) (V : Type v) [Field K] [Field V] [Algebra K namespace FixedPoints -theorem finrank_eq_card (G : Type u) (F : Type v) [Group G] [Field F] [Fintype G] - [MulSemiringAction G F] [FaithfulSMul G F] : +variable (G F : Type*) [Group G] [Field F] [MulSemiringAction G F] + +theorem finrank_eq_card [Fintype G] [FaithfulSMul G F] : finrank (FixedPoints.subfield G F) F = Fintype.card G := le_antisymm (FixedPoints.finrank_le_card G F) <| calc @@ -322,8 +323,7 @@ theorem finrank_eq_card (G : Type u) (F : Type v) [Group G] [Field F] [Fintype G _ = finrank (FixedPoints.subfield G F) F := finrank_linearMap_self _ _ _ /-- `MulSemiringAction.toAlgHom` is bijective. -/ -theorem toAlgHom_bijective (G : Type u) (F : Type v) [Group G] [Field F] [Finite G] - [MulSemiringAction G F] [FaithfulSMul G F] : +theorem toAlgHom_bijective [Finite G] [FaithfulSMul G F] : Function.Bijective (MulSemiringAction.toAlgHom _ _ : G → F →ₐ[subfield G F] F) := by cases nonempty_fintype G rw [Fintype.bijective_iff_injective_and_card] @@ -334,9 +334,37 @@ theorem toAlgHom_bijective (G : Type u) (F : Type v) [Group G] [Field F] [Finite · rw [← finrank_eq_card G F] exact LE.le.trans_eq (finrank_algHom _ F) (finrank_linearMap_self _ _ _) -/-- Bijection between G and algebra homomorphisms that fix the fixed points -/ -def toAlgHomEquiv (G : Type u) (F : Type v) [Group G] [Field F] [Finite G] [MulSemiringAction G F] - [FaithfulSMul G F] : G ≃ (F →ₐ[FixedPoints.subfield G F] F) := +/-- Bijection between `G` and algebra endomorphisms of `F` that fix the fixed points. -/ +def toAlgHomEquiv [Finite G] [FaithfulSMul G F] : G ≃ (F →ₐ[FixedPoints.subfield G F] F) := Equiv.ofBijective _ (toAlgHom_bijective G F) +/-- `MulSemiringAction.toAlgAut` is bijective. -/ +theorem toAlgAut_bijective [Finite G] [FaithfulSMul G F] : + Function.Bijective (MulSemiringAction.toAlgAut G (FixedPoints.subfield G F) F) := by + refine ⟨fun _ _ h ↦ (FixedPoints.toAlgHom_bijective G F).injective ?_, + fun f ↦ ((FixedPoints.toAlgHom_bijective G F).surjective f).imp (fun _ h ↦ ?_)⟩ <;> + rwa [DFunLike.ext_iff] at h ⊢ + +/-- Bijection between `G` and algebra automorphisms of `F` that fix the fixed points. -/ +def toAlgAutMulEquiv [Finite G] [FaithfulSMul G F] : G ≃* (F ≃ₐ[FixedPoints.subfield G F] F) := + MulEquiv.ofBijective _ (toAlgAut_bijective G F) + +/-- `MulSemiringAction.toAlgAut` is surjective. -/ +theorem toAlgAut_surjective [Finite G] : + Function.Surjective (MulSemiringAction.toAlgAut G (FixedPoints.subfield G F) F) := by + let f : G →* F ≃ₐ[FixedPoints.subfield G F] F := + MulSemiringAction.toAlgAut G (FixedPoints.subfield G F) F + let Q := G ⧸ f.ker + let _ : MulSemiringAction Q F := MulSemiringAction.compHom _ (QuotientGroup.kerLift f) + have : FaithfulSMul Q F := ⟨by + intro q₁ q₂ + refine Quotient.inductionOn₂' q₁ q₂ (fun g₁ g₂ h ↦ QuotientGroup.eq.mpr ?_) + rwa [MonoidHom.mem_ker, map_mul, map_inv, inv_mul_eq_one, AlgEquiv.ext_iff]⟩ + intro f + obtain ⟨q, hq⟩ := (toAlgAut_bijective Q F).surjective + (AlgEquiv.ofRingEquiv (f := f) (fun ⟨x, hx⟩ ↦ f.commutes' ⟨x, fun g ↦ hx g⟩)) + revert hq + refine QuotientGroup.induction_on q (fun g hg ↦ ⟨g, ?_⟩) + rwa [AlgEquiv.ext_iff] at hg ⊢ + end FixedPoints diff --git a/Mathlib/FieldTheory/Galois/GaloisClosure.lean b/Mathlib/FieldTheory/Galois/GaloisClosure.lean new file mode 100644 index 0000000000000..c1f93236da4c0 --- /dev/null +++ b/Mathlib/FieldTheory/Galois/GaloisClosure.lean @@ -0,0 +1,144 @@ +/- +Copyright (c) 2024 Nailin Guan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nailin Guan, Yuyang Zhao +-/ + +import Mathlib.FieldTheory.NormalClosure +import Mathlib.FieldTheory.SeparableClosure + +/-! + +# Main definitions and results + +In a field extension `K/k` + +* `FiniteGaloisIntermediateField` : The type of intermediate fields of `K/k` + that are finite and Galois over `k` + +* `adjoin` : The finite Galois intermediate field obtained from the normal closure of adjoining a + finite `s : Set K` to `k`. + +# TODO + +* `FiniteGaloisIntermediateField` should be a `ConditionallyCompleteLattice` but isn't proved yet. + +-/ + +variable (k K : Type*) [Field k] [Field K] [Algebra k K] + +/-- The type of intermediate fields of `K/k` that are finite and Galois over `k` -/ +structure FiniteGaloisIntermediateField extends IntermediateField k K where + [finiteDimensional : FiniteDimensional k toIntermediateField] + [isGalois : IsGalois k toIntermediateField] + +namespace FiniteGaloisIntermediateField + +instance : Coe (FiniteGaloisIntermediateField k K) (IntermediateField k K) where + coe := toIntermediateField + +instance : CoeSort (FiniteGaloisIntermediateField k K) (Type _) where + coe L := L.toIntermediateField + +instance (L : FiniteGaloisIntermediateField k K) : FiniteDimensional k L := + L.finiteDimensional + +instance (L : FiniteGaloisIntermediateField k K) : IsGalois k L := L.isGalois + +variable {k K} + +lemma val_injective : Function.Injective (toIntermediateField (k := k) (K := K)) := by + rintro ⟨⟩ ⟨⟩ eq + simpa only [mk.injEq] using eq + +/-- Turns the collection of finite Galois IntermediateFields of `K/k` into a lattice. -/ + +instance (L₁ L₂ : IntermediateField k K) [IsGalois k L₁] [IsGalois k L₂] : + IsGalois k ↑(L₁ ⊔ L₂) where + +instance (L₁ L₂ : IntermediateField k K) [FiniteDimensional k L₁] : + FiniteDimensional k ↑(L₁ ⊓ L₂) := + .of_injective (IntermediateField.inclusion inf_le_left).toLinearMap + (IntermediateField.inclusion inf_le_left).injective + +instance (L₁ L₂ : IntermediateField k K) [FiniteDimensional k L₂] : + FiniteDimensional k ↑(L₁ ⊓ L₂) := + .of_injective (IntermediateField.inclusion inf_le_right).toLinearMap + (IntermediateField.inclusion inf_le_right).injective + +instance (L₁ L₂ : IntermediateField k K) [Algebra.IsSeparable k L₁] : + Algebra.IsSeparable k ↑(L₁ ⊓ L₂) := + .of_algHom _ _ (IntermediateField.inclusion inf_le_left) + +instance (L₁ L₂ : IntermediateField k K) [Algebra.IsSeparable k L₂] : + Algebra.IsSeparable k ↑(L₁ ⊓ L₂) := + .of_algHom _ _ (IntermediateField.inclusion inf_le_right) + +instance (L₁ L₂ : IntermediateField k K) [IsGalois k L₁] [IsGalois k L₂] : + IsGalois k ↑(L₁ ⊓ L₂) where + +instance : Sup (FiniteGaloisIntermediateField k K) where + sup L₁ L₂ := .mk <| L₁ ⊔ L₂ + +instance : Inf (FiniteGaloisIntermediateField k K) where + inf L₁ L₂ := .mk <| L₁ ⊓ L₂ + +instance : Lattice (FiniteGaloisIntermediateField k K) := + val_injective.lattice _ (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) + +instance : OrderBot (FiniteGaloisIntermediateField k K) where + bot := .mk ⊥ + bot_le _ := bot_le (α := IntermediateField _ _) + +@[simp] +lemma le_iff (L₁ L₂ : FiniteGaloisIntermediateField k K) : + L₁ ≤ L₂ ↔ L₁.toIntermediateField ≤ L₂.toIntermediateField := + Iff.rfl + +variable (k) in +/-- The minimal (finite) Galois intermediate field containing a finite set `s : Set K` in a +Galois extension `K/k` defined as the the normal closure of the field obtained by adjoining +the set `s : Set K` to `k`. -/ +noncomputable def adjoin [IsGalois k K] (s : Set K) [Finite s] : + FiniteGaloisIntermediateField k K := { + normalClosure k (IntermediateField.adjoin k (s : Set K)) K with + finiteDimensional := + letI : FiniteDimensional k (IntermediateField.adjoin k (s : Set K)) := + IntermediateField.finiteDimensional_adjoin <| fun z _ => + IsAlgebraic.isIntegral (Algebra.IsAlgebraic.isAlgebraic z) + normalClosure.is_finiteDimensional k (IntermediateField.adjoin k (s : Set K)) K + isGalois := IsGalois.normalClosure k (IntermediateField.adjoin k (s : Set K)) K } + +@[simp] +lemma adjoin_val [IsGalois k K] (s : Set K) [Finite s] : + (FiniteGaloisIntermediateField.adjoin k s) = + normalClosure k (IntermediateField.adjoin k s) K := + rfl + +variable (k) in +lemma subset_adjoin [IsGalois k K] (s : Set K) [Finite s] : + s ⊆ (adjoin k s).toIntermediateField := + (IntermediateField.subset_adjoin k s).trans (IntermediateField.le_normalClosure _) + +theorem adjoin_simple_le_iff [IsGalois k K] {x : K} {L : FiniteGaloisIntermediateField k K} : + adjoin k {x} ≤ L ↔ x ∈ L.toIntermediateField := by + simp only [le_iff, adjoin_val, IntermediateField.normalClosure_le_iff_of_normal, + IntermediateField.adjoin_le_iff, Set.le_eq_subset, Set.singleton_subset_iff, SetLike.mem_coe] + +@[simp] +theorem adjoin_map [IsGalois k K] (f : K →ₐ[k] K) (s : Set K) [Finite s] : + adjoin k (f '' s) = adjoin k s := by + apply val_injective; dsimp [adjoin_val] + rw [← IntermediateField.adjoin_map, IntermediateField.normalClosure_map_eq] + +@[simp] +theorem adjoin_simple_map_algHom [IsGalois k K] (f : K →ₐ[k] K) (x : K) : + adjoin k {f x} = adjoin k {x} := by + simpa only [Set.image_singleton] using adjoin_map f { x } + +@[simp] +theorem adjoin_simple_map_algEquiv [IsGalois k K] (f : K ≃ₐ[k] K) (x : K) : + adjoin k {f x} = adjoin k {x} := + adjoin_simple_map_algHom (f : K →ₐ[k] K) x + +end FiniteGaloisIntermediateField diff --git a/Mathlib/FieldTheory/Galois/Profinite.lean b/Mathlib/FieldTheory/Galois/Profinite.lean new file mode 100644 index 0000000000000..300f56169316b --- /dev/null +++ b/Mathlib/FieldTheory/Galois/Profinite.lean @@ -0,0 +1,84 @@ +/- +Copyright (c) 2024 Nailin Guan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nailin Guan, Yuyang Zhao, Jujian Zhang +-/ + +import Mathlib.Algebra.Category.Grp.FiniteGrp +import Mathlib.CategoryTheory.Category.Preorder +import Mathlib.FieldTheory.Galois.GaloisClosure + +/-! + +# Main definitions and results + +In a field extension `K/k` + +* `finGaloisGroup L` : The (finite) Galois group `Gal(L/k)` associated to a + `L : FiniteGaloisIntermediateField k K` `L`. + +* `finGaloisGroupMap` : For `FiniteGaloisIntermediateField` s `L₁` and `L₂` with `L₂ ≤ L₁` + giving the restriction of `Gal(L₁/k)` to `Gal(L₂/k)` + +* `finGaloisGroupFunctor` : Mapping `FiniteGaloisIntermediateField` ordered by inverse inclusion to + its corresponding Galois Group as `FiniteGrp`. + +-/ + +open CategoryTheory Opposite + +variable {k K : Type*} [Field k] [Field K] [Algebra k K] + +section Profinite + +/-- The (finite) Galois group `Gal(L / k)` associated to a +`L : FiniteGaloisIntermediateField k K` `L`. -/ +def FiniteGaloisIntermediateField.finGaloisGroup (L : FiniteGaloisIntermediateField k K) : + FiniteGrp := + letI := AlgEquiv.fintype k L + FiniteGrp.of <| L ≃ₐ[k] L + +/-- For `FiniteGaloisIntermediateField` s `L₁` and `L₂` with `L₂ ≤ L₁` + the restriction homomorphism from `Gal(L₁/k)` to `Gal(L₂/k)` -/ +noncomputable def finGaloisGroupMap {L₁ L₂ : (FiniteGaloisIntermediateField k K)ᵒᵖ} + (le : L₁ ⟶ L₂) : L₁.unop.finGaloisGroup ⟶ L₂.unop.finGaloisGroup := + haveI : Normal k L₂.unop := IsGalois.to_normal + letI : Algebra L₂.unop L₁.unop := RingHom.toAlgebra (Subsemiring.inclusion <| leOfHom le.1) + haveI : IsScalarTower k L₂.unop L₁.unop := IsScalarTower.of_algebraMap_eq (congrFun rfl) + FiniteGrp.ofHom (AlgEquiv.restrictNormalHom L₂.unop) + +namespace finGaloisGroupMap + +@[simp] +lemma map_id (L : (FiniteGaloisIntermediateField k K)ᵒᵖ) : + (finGaloisGroupMap (𝟙 L)) = 𝟙 L.unop.finGaloisGroup := + AlgEquiv.restrictNormalHom_id _ _ + +@[simp] +lemma map_comp {L₁ L₂ L₃ : (FiniteGaloisIntermediateField k K)ᵒᵖ} (f : L₁ ⟶ L₂) (g : L₂ ⟶ L₃) : + finGaloisGroupMap (f ≫ g) = finGaloisGroupMap f ≫ finGaloisGroupMap g := by + iterate 2 + induction L₁ with | _ L₁ => ?_ + induction L₂ with | _ L₂ => ?_ + induction L₃ with | _ L₃ => ?_ + letI : Algebra L₃ L₂ := RingHom.toAlgebra (Subsemiring.inclusion g.unop.le) + letI : Algebra L₂ L₁ := RingHom.toAlgebra (Subsemiring.inclusion f.unop.le) + letI : Algebra L₃ L₁ := RingHom.toAlgebra (Subsemiring.inclusion (g.unop.le.trans f.unop.le)) + haveI : IsScalarTower k L₂ L₁ := IsScalarTower.of_algebraMap_eq' rfl + haveI : IsScalarTower k L₃ L₁ := IsScalarTower.of_algebraMap_eq' rfl + haveI : IsScalarTower k L₃ L₂ := IsScalarTower.of_algebraMap_eq' rfl + haveI : IsScalarTower L₃ L₂ L₁ := IsScalarTower.of_algebraMap_eq' rfl + apply IsScalarTower.AlgEquiv.restrictNormalHom_comp k L₃ L₂ L₁ + +end finGaloisGroupMap + +variable (k K) in +/-- The functor from `FiniteGaloisIntermediateField` (ordered by reverse inclusion) to `FiniteGrp`, +mapping each intermediate field `K/L/k` to `Gal (L/k)`.-/ +noncomputable def finGaloisGroupFunctor : (FiniteGaloisIntermediateField k K)ᵒᵖ ⥤ FiniteGrp where + obj L := L.unop.finGaloisGroup + map := finGaloisGroupMap + map_id := finGaloisGroupMap.map_id + map_comp := finGaloisGroupMap.map_comp + +end Profinite diff --git a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean index 55ecc96148306..fadc8889330f0 100644 --- a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean @@ -15,11 +15,32 @@ import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition open Module -variable {K : Type*} {L : Type*} [Field K] [Field L] [Algebra K L] +variable {K L : Type*} [Field K] [Field L] [Algebra K L] {S : IntermediateField K L} +theorem IntermediateField.coe_isIntegral_iff {R : Type*} [CommRing R] [Algebra R K] [Algebra R L] + [IsScalarTower R K L] {x : S} : IsIntegral R (x : L) ↔ IsIntegral R x := + isIntegral_algHom_iff (S.val.restrictScalars R) Subtype.val_injective + +/-- Turn an algebraic subalgebra into an intermediate field, `Subalgebra.IsAlgebraic` version. -/ +def Subalgebra.IsAlgebraic.toIntermediateField {S : Subalgebra K L} (hS : S.IsAlgebraic) : + IntermediateField K L where + toSubalgebra := S + inv_mem' x hx := Algebra.adjoin_le_iff.mpr + (Set.singleton_subset_iff.mpr hx) (hS x hx).isIntegral.inv_mem_adjoin + +/-- Turn an algebraic subalgebra into an intermediate field, `Algebra.IsAlgebraic` version. -/ +abbrev Algebra.IsAlgebraic.toIntermediateField (S : Subalgebra K L) [Algebra.IsAlgebraic K S] : + IntermediateField K L := (S.isAlgebraic_iff.mpr ‹_›).toIntermediateField + namespace IntermediateField +instance isAlgebraic_tower_bot [Algebra.IsAlgebraic K L] : Algebra.IsAlgebraic K S := + Algebra.IsAlgebraic.of_injective S.val S.val.injective + +instance isAlgebraic_tower_top [Algebra.IsAlgebraic K L] : Algebra.IsAlgebraic S L := + Algebra.IsAlgebraic.tower_top (K := K) S + section FiniteDimensional variable (F E : IntermediateField K L) @@ -86,8 +107,8 @@ end FiniteDimensional theorem isAlgebraic_iff {x : S} : IsAlgebraic K x ↔ IsAlgebraic K (x : L) := (isAlgebraic_algebraMap_iff (algebraMap S L).injective).symm -theorem isIntegral_iff {x : S} : IsIntegral K x ↔ IsIntegral K (x : L) := by - rw [← isAlgebraic_iff_isIntegral, isAlgebraic_iff, isAlgebraic_iff_isIntegral] +theorem isIntegral_iff {x : S} : IsIntegral K x ↔ IsIntegral K (x : L) := + (isIntegral_algHom_iff S.val S.val.injective).symm theorem minpoly_eq (x : S) : minpoly K x = minpoly K (x : L) := (minpoly.algebraMap_eq (algebraMap S L).injective x).symm diff --git a/Mathlib/FieldTheory/IntermediateField/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Basic.lean index 27a9fb8cd57cd..d1337b2dca3dc 100644 --- a/Mathlib/FieldTheory/IntermediateField/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Basic.lean @@ -6,7 +6,6 @@ Authors: Anne Baanen import Mathlib.Algebra.Field.Subfield import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.RingTheory.LocalRing.Basic -import Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs /-! # Intermediate fields @@ -112,10 +111,8 @@ theorem mem_toSubfield (s : IntermediateField K L) (x : L) : x ∈ s.toSubfield definitional equalities. -/ protected def copy (S : IntermediateField K L) (s : Set L) (hs : s = ↑S) : IntermediateField K L where - toSubalgebra := S.toSubalgebra.copy s (hs : s = S.toSubalgebra.carrier) - inv_mem' := - have hs' : (S.toSubalgebra.copy s hs).carrier = S.toSubalgebra.carrier := hs - hs'.symm ▸ S.inv_mem' + toSubalgebra := S.toSubalgebra.copy s hs + inv_mem' := hs.symm ▸ S.inv_mem' @[simp] theorem coe_copy (S : IntermediateField K L) (s : Set L) (hs : s = ↑S) : @@ -252,7 +249,7 @@ theorem toSubalgebra_toIntermediateField (S : Subalgebra K L) (inv_mem : ∀ x @[simp] theorem toIntermediateField_toSubalgebra (S : IntermediateField K L) : - (S.toSubalgebra.toIntermediateField fun x => S.inv_mem) = S := by + (S.toSubalgebra.toIntermediateField fun _ => S.inv_mem) = S := by ext rfl @@ -291,20 +288,81 @@ namespace IntermediateField instance toField : Field S := S.toSubfield.toField -@[simp, norm_cast] +@[norm_cast] theorem coe_sum {ι : Type*} [Fintype ι] (f : ι → S) : (↑(∑ i, f i) : L) = ∑ i, (f i : L) := by classical induction' (Finset.univ : Finset ι) using Finset.induction_on with i s hi H · simp · rw [Finset.sum_insert hi, AddMemClass.coe_add, H, Finset.sum_insert hi] -@[norm_cast] --Porting note (#10618): `simp` can prove it +@[norm_cast] theorem coe_prod {ι : Type*} [Fintype ι] (f : ι → S) : (↑(∏ i, f i) : L) = ∏ i, (f i : L) := by classical induction' (Finset.univ : Finset ι) using Finset.induction_on with i s hi H · simp · rw [Finset.prod_insert hi, MulMemClass.coe_mul, H, Finset.prod_insert hi] +/-! +`IntermediateField`s inherit structure from their `Subfield` coercions. +-/ + +variable {X Y} + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [SMul L X] (F : IntermediateField K L) : SMul F X := + inferInstanceAs (SMul F.toSubfield X) + +theorem smul_def [SMul L X] {F : IntermediateField K L} (g : F) (m : X) : g • m = (g : L) • m := + rfl + +instance smulCommClass_left [SMul L Y] [SMul X Y] [SMulCommClass L X Y] + (F : IntermediateField K L) : SMulCommClass F X Y := + inferInstanceAs (SMulCommClass F.toSubfield X Y) + +instance smulCommClass_right [SMul X Y] [SMul L Y] [SMulCommClass X L Y] + (F : IntermediateField K L) : SMulCommClass X F Y := + inferInstanceAs (SMulCommClass X F.toSubfield Y) + +--note: setting this istance the default priority may trigger trouble to synthize instance +--for field extension with more than one intermedaite field, example : in a field extension `F/E`, +--`K₁ ≤ K₂` are of type `intermediatefield F E`, the instance `IsScalarTower K₁ K₂ E` +/-- Note that this provides `IsScalarTower F K K` which is needed by `smul_mul_assoc`. -/ +instance (priority := 900) [SMul X Y] [SMul L X] [SMul L Y] [IsScalarTower L X Y] + (F : IntermediateField K L) : IsScalarTower F X Y := + inferInstanceAs (IsScalarTower F.toSubfield X Y) + +instance [SMul L X] [FaithfulSMul L X] (F : IntermediateField K L) : FaithfulSMul F X := + inferInstanceAs (FaithfulSMul F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [MulAction L X] (F : IntermediateField K L) : MulAction F X := + inferInstanceAs (MulAction F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [AddMonoid X] [DistribMulAction L X] (F : IntermediateField K L) : DistribMulAction F X := + inferInstanceAs (DistribMulAction F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [Monoid X] [MulDistribMulAction L X] (F : IntermediateField K L) : + MulDistribMulAction F X := + inferInstanceAs (MulDistribMulAction F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [Zero X] [SMulWithZero L X] (F : IntermediateField K L) : SMulWithZero F X := + inferInstanceAs (SMulWithZero F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [Zero X] [MulActionWithZero L X] (F : IntermediateField K L) : MulActionWithZero F X := + inferInstanceAs (MulActionWithZero F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [AddCommMonoid X] [Module L X] (F : IntermediateField K L) : Module F X := + inferInstanceAs (Module F.toSubfield X) + +/-- The action by an intermediate field is the action by the underlying field. -/ +instance [Semiring X] [MulSemiringAction L X] (F : IntermediateField K L) : MulSemiringAction F X := + inferInstanceAs (MulSemiringAction F.toSubfield X) + /-! `IntermediateField`s inherit structure from their `Subalgebra` coercions. -/ instance toAlgebra : Algebra S L := @@ -341,7 +399,7 @@ instance isScalarTower_mid {R : Type*} [Semiring R] [Algebra L R] [Algebra K R] /-- Specialize `is_scalar_tower_mid` to the common case where the top field is `L` -/ instance isScalarTower_mid' : IsScalarTower K S L := - S.isScalarTower_mid + inferInstance instance {E} [Semiring E] [Algebra L E] : Algebra S E := inferInstanceAs (Algebra S.toSubalgebra E) @@ -468,25 +526,8 @@ instance AlgHom.inhabited : Inhabited (S →ₐ[K] L) := ⟨S.val⟩ theorem aeval_coe {R : Type*} [CommRing R] [Algebra R K] [Algebra R L] [IsScalarTower R K L] - (x : S) (P : R[X]) : aeval (x : L) P = aeval x P := by - refine Polynomial.induction_on' P (fun f g hf hg => ?_) fun n r => ?_ - · rw [aeval_add, aeval_add, AddMemClass.coe_add, hf, hg] - · simp only [MulMemClass.coe_mul, aeval_monomial, SubmonoidClass.coe_pow, mul_eq_mul_right_iff] - left - rfl - -theorem coe_isIntegral_iff {R : Type*} [CommRing R] [Algebra R K] [Algebra R L] - [IsScalarTower R K L] {x : S} : IsIntegral R (x : L) ↔ IsIntegral R x := by - refine ⟨fun h => ?_, fun h => ?_⟩ - · obtain ⟨P, hPmo, hProot⟩ := h - refine ⟨P, hPmo, (injective_iff_map_eq_zero _).1 (algebraMap (↥S) L).injective _ ?_⟩ - letI : IsScalarTower R S L := IsScalarTower.of_algebraMap_eq (congr_fun rfl) - rw [eval₂_eq_eval_map, ← eval₂_at_apply, eval₂_eq_eval_map, Polynomial.map_map, ← - IsScalarTower.algebraMap_eq, ← eval₂_eq_eval_map] - exact hProot - · obtain ⟨P, hPmo, hProot⟩ := h - refine ⟨P, hPmo, ?_⟩ - rw [← aeval_def, aeval_coe, aeval_def, hProot, ZeroMemClass.coe_zero] + (x : S) (P : R[X]) : aeval (x : L) P = aeval x P := + aeval_algHom_apply (S.val.restrictScalars R) x P /-- The map `E → F` when `E` is an intermediate field contained in the intermediate field `F`. @@ -514,14 +555,17 @@ theorem coe_inclusion {E F : IntermediateField K L} (hEF : E ≤ F) (e : E) : variable {S} -theorem toSubalgebra_injective : - Function.Injective (IntermediateField.toSubalgebra : IntermediateField K L → _) := by - intro S S' h +theorem toSubalgebra_injective : Function.Injective (toSubalgebra : IntermediateField K L → _) := by + intro _ _ h + ext + simp_rw [← mem_toSubalgebra, h] + +theorem toSubfield_injective : Function.Injective (toSubfield : IntermediateField K L → _) := by + intro _ _ h ext - rw [← mem_toSubalgebra, ← mem_toSubalgebra, h] + simp_rw [← mem_toSubfield, h] -theorem map_injective (f : L →ₐ[K] L') : - Function.Injective (map f) := by +theorem map_injective (f : L →ₐ[K] L') : Function.Injective (map f) := by intro _ _ h rwa [← toSubalgebra_injective.eq_iff, toSubalgebra_map, toSubalgebra_map, (Subalgebra.map_injective f.injective).eq_iff, toSubalgebra_injective.eq_iff] at h @@ -650,8 +694,8 @@ def extendScalars.orderIso : { E : Subfield L // F ≤ E } ≃o IntermediateField F L where toFun E := extendScalars E.2 invFun E := ⟨E.toSubfield, fun x hx ↦ E.algebraMap_mem ⟨x, hx⟩⟩ - left_inv E := rfl - right_inv E := rfl + left_inv _ := rfl + right_inv _ := rfl map_rel_iff' {E E'} := by simp only [Equiv.coe_fn_mk] exact extendScalars_le_extendScalars_iff _ _ @@ -702,8 +746,8 @@ into an order isomorphism from def extendScalars.orderIso : { E : IntermediateField K L // F ≤ E } ≃o IntermediateField F L where toFun E := extendScalars E.2 invFun E := ⟨E.restrictScalars K, fun x hx ↦ E.algebraMap_mem ⟨x, hx⟩⟩ - left_inv E := rfl - right_inv E := rfl + left_inv _ := rfl + right_inv _ := rfl map_rel_iff' {E E'} := by simp only [Equiv.coe_fn_mk] exact extendScalars_le_extendScalars_iff _ _ diff --git a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean index 787429c5e3827..d58f8dcbc128b 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean @@ -164,12 +164,8 @@ 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 := by --- Porting note: original proof was `@AdjoinMonic.exists_root _ (Step.field k n) _ hfm hfi`, --- but it timeouts. - obtain ⟨x, hx⟩ := @AdjoinMonic.exists_root _ (Step.field k n) _ hfm hfi --- Porting note: using `hx` instead of `by apply hx` timeouts. - exact ⟨x, by apply hx⟩ + (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 @@ -186,29 +182,24 @@ private theorem toStepOfLE'.succ (m n : ℕ) (h : m ≤ n) : def toStepOfLE (m n : ℕ) (h : m ≤ n) : Step k m →+* Step k n where toFun := toStepOfLE' k m n h map_one' := by --- Porting note: original proof was `induction' h with n h ih; · exact Nat.leRecOn_self 1` --- `rw [Nat.leRecOn_succ h, ih, RingHom.map_one]` induction' h with a h ih · exact Nat.leRecOn_self 1 - · rw [toStepOfLE'.succ k m a h]; simp [ih] + · simp [toStepOfLE'.succ k m a h, ih] map_mul' x y := by --- Porting note: original proof was `induction' h with n h ih; · simp_rw [Nat.leRecOn_self]` --- `simp_rw [Nat.leRecOn_succ h, ih, RingHom.map_mul]` + simp only induction' h with a h ih - · dsimp [toStepOfLE']; simp_rw [Nat.leRecOn_self] - · simp_rw [toStepOfLE'.succ k m a h]; simp only at ih; simp [ih] --- Porting note: original proof was `induction' h with n h ih; · exact Nat.leRecOn_self 0` --- `rw [Nat.leRecOn_succ h, ih, RingHom.map_zero]` + · 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_rw [toStepOfLE'.succ k m a h]; simp only at ih; simp [ih] + · simp [toStepOfLE'.succ k m a h, ih] map_add' x y := by --- Porting note: original proof was `induction' h with n h ih; · simp_rw [Nat.leRecOn_self]` --- `simp_rw [Nat.leRecOn_succ h, ih, RingHom.map_add]` + simp only induction' h with a h ih - · dsimp [toStepOfLE']; simp_rw [Nat.leRecOn_self] - · simp_rw [toStepOfLE'.succ k m a h]; simp only at ih; simp [ih] + · simp_rw [toStepOfLE', Nat.leRecOn_self] + · simp [toStepOfLE'.succ k m a h, ih] @[simp] theorem coe_toStepOfLE (m n : ℕ) (h : m ≤ n) : @@ -404,7 +395,7 @@ instance : IsAlgClosure k (AlgebraicClosure k) := by exact ⟨inferInstance, (algEquivAlgebraicClosureAux k).symm.isAlgebraic⟩ instance isAlgebraic : Algebra.IsAlgebraic k (AlgebraicClosure k) := - IsAlgClosure.algebraic + IsAlgClosure.isAlgebraic instance [CharZero k] : CharZero (AlgebraicClosure k) := charZero_of_injective_algebraMap (RingHom.injective (algebraMap k (AlgebraicClosure k))) @@ -412,4 +403,9 @@ instance [CharZero k] : CharZero (AlgebraicClosure k) := instance {p : ℕ} [CharP k p] : CharP (AlgebraicClosure k) p := charP_of_injective_algebraMap (RingHom.injective (algebraMap k (AlgebraicClosure k))) p +instance {L : Type*} [Field k] [Field L] [Algebra k L] [Algebra.IsAlgebraic k L] : + IsAlgClosure k (AlgebraicClosure L) where + isAlgebraic := .trans (L := L) + isAlgClosed := inferInstance + end AlgebraicClosure diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index f50d91d7f2c11..f4f1bcc97f725 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -202,10 +202,13 @@ lemma Polynomial.isCoprime_iff_aeval_ne_zero_of_isAlgClosed (K : Type v) [Field /-- Typeclass for an extension being an algebraic closure. -/ class IsAlgClosure (R : Type u) (K : Type v) [CommRing R] [Field K] [Algebra R K] [NoZeroSMulDivisors R K] : Prop where - alg_closed : IsAlgClosed K - algebraic : Algebra.IsAlgebraic R K + isAlgClosed : IsAlgClosed K + isAlgebraic : Algebra.IsAlgebraic R K -attribute [instance] IsAlgClosure.algebraic +@[deprecated (since := "2024-08-31")] alias IsAlgClosure.alg_closed := IsAlgClosure.isAlgClosed +@[deprecated (since := "2024-08-31")] alias IsAlgClosure.algebraic := IsAlgClosure.isAlgebraic + +attribute [instance] IsAlgClosure.isAlgebraic theorem isAlgClosure_iff (K : Type v) [Field K] [Algebra k K] : IsAlgClosure k K ↔ IsAlgClosed K ∧ Algebra.IsAlgebraic k K := @@ -213,13 +216,17 @@ theorem isAlgClosure_iff (K : Type v) [Field K] [Algebra k K] : instance (priority := 100) IsAlgClosure.normal (R K : Type*) [Field R] [Field K] [Algebra R K] [IsAlgClosure R K] : Normal R K where - toIsAlgebraic := IsAlgClosure.algebraic - splits' _ := @IsAlgClosed.splits_codomain _ _ _ (IsAlgClosure.alg_closed R) _ _ _ + toIsAlgebraic := IsAlgClosure.isAlgebraic + splits' _ := @IsAlgClosed.splits_codomain _ _ _ (IsAlgClosure.isAlgClosed R) _ _ _ instance (priority := 100) IsAlgClosure.separable (R K : Type*) [Field R] [Field K] [Algebra R K] [IsAlgClosure R K] [CharZero R] : Algebra.IsSeparable R K := ⟨fun _ => (minpoly.irreducible (Algebra.IsIntegral.isIntegral _)).separable⟩ +instance IsAlgClosed.instIsAlgClosure (F : Type*) [Field F] [IsAlgClosed F] : IsAlgClosure F F where + isAlgClosed := ‹_› + isAlgebraic := .of_finite F F + namespace IsAlgClosed variable {K : Type u} [Field K] {L : Type v} {M : Type w} [Field L] [Algebra K L] [Field M] @@ -298,9 +305,9 @@ end IsAlgClosed namespace IsAlgClosure -- Porting note: errors with --- > cannot find synthesization order for instance alg_closed with type +-- > cannot find synthesization order for instance isAlgClosed with type -- > all remaining arguments have metavariables --- attribute [local instance] IsAlgClosure.alg_closed +-- attribute [local instance] IsAlgClosure.isAlgClosed section @@ -311,9 +318,9 @@ variable [Algebra R L] [NoZeroSMulDivisors R L] [IsAlgClosure R L] /-- A (random) isomorphism between two algebraic closures of `R`. -/ noncomputable def equiv : L ≃ₐ[R] M := -- Porting note (#10754): added to replace local instance above - haveI : IsAlgClosed L := IsAlgClosure.alg_closed R - haveI : IsAlgClosed M := IsAlgClosure.alg_closed R - AlgEquiv.ofBijective _ (IsAlgClosure.algebraic.algHom_bijective₂ + haveI : IsAlgClosed L := IsAlgClosure.isAlgClosed R + haveI : IsAlgClosed M := IsAlgClosure.isAlgClosed R + AlgEquiv.ofBijective _ (IsAlgClosure.isAlgebraic.algHom_bijective₂ (IsAlgClosed.lift : L →ₐ[R] M) (IsAlgClosed.lift : M →ₐ[R] L)).1 @@ -332,7 +339,7 @@ variable [Algebra K J] [Algebra J L] [IsAlgClosure J L] [Algebra K L] [IsScalarT /-- If `J` is an algebraic extension of `K` and `L` is an algebraic closure of `J`, then it is also an algebraic closure of `K`. -/ theorem ofAlgebraic [hKJ : Algebra.IsAlgebraic K J] : IsAlgClosure K L := - ⟨IsAlgClosure.alg_closed J, hKJ.trans⟩ + ⟨IsAlgClosure.isAlgClosed J, hKJ.trans⟩ /-- A (random) isomorphism between an algebraic closure of `R` and an algebraic closure of an algebraic extension of `R` -/ @@ -343,8 +350,8 @@ noncomputable def equivOfAlgebraic' [Nontrivial S] [NoZeroSMulDivisors R S] exact (Function.Injective.comp (NoZeroSMulDivisors.algebraMap_injective S L) (NoZeroSMulDivisors.algebraMap_injective R S) : _) letI : IsAlgClosure R L := - { alg_closed := IsAlgClosure.alg_closed S - algebraic := ‹_› } + { isAlgClosed := IsAlgClosure.isAlgClosed S + isAlgebraic := ‹_› } exact IsAlgClosure.equiv _ _ _ /-- A (random) isomorphism between an algebraic closure of `K` and an algebraic closure @@ -371,7 +378,7 @@ noncomputable def equivOfEquivAux (hSR : S ≃+* R) : haveI : IsScalarTower S R L := IsScalarTower.of_algebraMap_eq (by simp [RingHom.algebraMap_toAlgebra]) haveI : NoZeroSMulDivisors R S := NoZeroSMulDivisors.of_algebraMap_injective hSR.symm.injective - have : Algebra.IsAlgebraic R L := (IsAlgClosure.algebraic.tower_top_of_injective + have : Algebra.IsAlgebraic R L := (IsAlgClosure.isAlgebraic.tower_top_of_injective (show Function.Injective (algebraMap S R) from hSR.injective)) refine ⟨equivOfAlgebraic' R S L M, ?_⟩ diff --git a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean index 2f13ff3833e58..99b41accb1cf2 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean @@ -48,7 +48,7 @@ theorem cardinal_mk_le_sigma_polynomial : Polynomial.degree_map_eq_of_injective (NoZeroSMulDivisors.algebraMap_injective R L), Polynomial.degree_eq_bot] exact p.2.1 - erw [Polynomial.mem_roots h, Polynomial.IsRoot, Polynomial.eval_map, ← Polynomial.aeval_def, + rw [Polynomial.mem_roots h, Polynomial.IsRoot, Polynomial.eval_map, ← Polynomial.aeval_def, p.2.2]⟩) fun x y => by intro h @@ -65,7 +65,7 @@ theorem cardinal_mk_le_max : #L ≤ max #R ℵ₀ := _ = Cardinal.sum fun p : R[X] => #{x : L | x ∈ p.aroots L} := by rw [← mk_sigma]; rfl _ ≤ Cardinal.sum.{u, u} fun _ : R[X] => ℵ₀ := - (sum_le_sum _ _ fun p => (Multiset.finite_toSet _).lt_aleph0.le) + (sum_le_sum _ _ fun _ => (Multiset.finite_toSet _).lt_aleph0.le) _ = #(R[X]) * ℵ₀ := sum_const' _ _ _ ≤ max (max #(R[X]) ℵ₀) ℵ₀ := mul_le_max _ _ _ ≤ max (max (max #R ℵ₀) ℵ₀) ℵ₀ := @@ -92,8 +92,8 @@ variable (hv : AlgebraicIndependent R v) theorem isAlgClosure_of_transcendence_basis [IsAlgClosed K] (hv : IsTranscendenceBasis R v) : IsAlgClosure (Algebra.adjoin R (Set.range v)) K := letI := RingHom.domain_nontrivial (algebraMap R K) - { alg_closed := by infer_instance - algebraic := hv.isAlgebraic } + { isAlgClosed := by infer_instance + isAlgebraic := hv.isAlgebraic } variable (hw : AlgebraicIndependent R w) @@ -119,10 +119,8 @@ end Classification section Cardinal -variable {R L K : Type u} [CommRing R] -variable [Field K] [Algebra R K] [IsAlgClosed K] +variable {R K : Type u} [CommRing R] [Field K] [Algebra R K] [IsAlgClosed K] variable {ι : Type u} (v : ι → K) -variable (hv : IsTranscendenceBasis R v) theorem cardinal_le_max_transcendence_basis (hv : IsTranscendenceBasis R v) : #K ≤ max (max #R #ι) ℵ₀ := diff --git a/Mathlib/FieldTheory/IsPerfectClosure.lean b/Mathlib/FieldTheory/IsPerfectClosure.lean index 743199124c340..5c6d7928dc1a4 100644 --- a/Mathlib/FieldTheory/IsPerfectClosure.lean +++ b/Mathlib/FieldTheory/IsPerfectClosure.lean @@ -196,7 +196,7 @@ theorem RingHom.pNilradical_le_ker_of_perfectRing [ExpChar L p] [PerfectRing L p rwa [map_pow, ← iterateFrobenius_def, ← iterateFrobeniusEquiv_apply, RingEquiv.symm_apply_apply, map_zero, map_zero] at h -variable [ExpChar L p] [ExpChar M p] in +variable [ExpChar L p] in theorem IsPerfectClosure.ker_eq [PerfectRing L p] [IsPerfectClosure i p] : RingHom.ker i = pNilradical K p := IsPRadical.ker_le'.antisymm (i.pNilradical_le_ker_of_perfectRing p) diff --git a/Mathlib/FieldTheory/IsSepClosed.lean b/Mathlib/FieldTheory/IsSepClosed.lean index 1a11e8d38dff7..d7d9c870dda5a 100644 --- a/Mathlib/FieldTheory/IsSepClosed.lean +++ b/Mathlib/FieldTheory/IsSepClosed.lean @@ -92,6 +92,35 @@ theorem exists_root [IsSepClosed k] (p : k[X]) (hp : p.degree ≠ 0) (hsep : p.S ∃ x, IsRoot p x := exists_root_of_splits _ (IsSepClosed.splits_of_separable p hsep) hp +/-- If `n ≥ 2` equals zero in a separably closed field `k`, `b ≠ 0`, +then there exists `x` in `k` such that `a * x ^ n + b * x + c = 0`. -/ +theorem exists_root_C_mul_X_pow_add_C_mul_X_add_C + [IsSepClosed k] {n : ℕ} (a b c : k) (hn : (n : k) = 0) (hn' : 2 ≤ n) (hb : b ≠ 0) : + ∃ x, a * x ^ n + b * x + c = 0 := by + let f : k[X] := C a * X ^ n + C b * X + C c + have hdeg : f.degree ≠ 0 := degree_ne_of_natDegree_ne <| by + by_cases ha : a = 0 + · suffices f.natDegree = 1 from this ▸ one_ne_zero + simp_rw [f, ha, map_zero, zero_mul, zero_add] + compute_degree! + · suffices f.natDegree = n from this ▸ (lt_of_lt_of_le zero_lt_two hn').ne' + simp_rw [f] + have h0 : n ≠ 0 := by linarith only [hn'] + have h1 : n ≠ 1 := by linarith only [hn'] + have : 1 ≤ n := le_trans one_le_two hn' + compute_degree! + simp [h0, h1, ha] + have hsep : f.Separable := separable_C_mul_X_pow_add_C_mul_X_add_C a b c hn hb.isUnit + obtain ⟨x, hx⟩ := exists_root f hdeg hsep + exact ⟨x, by simpa [f] using hx⟩ + +/-- If a separably closed field `k` is of characteristic `p`, `n ≥ 2` is such that `p ∣ n`, `b ≠ 0`, +then there exists `x` in `k` such that `a * x ^ n + b * x + c = 0`. -/ +theorem exists_root_C_mul_X_pow_add_C_mul_X_add_C' + [IsSepClosed k] (p n : ℕ) (a b c : k) [CharP k p] (hn : p ∣ n) (hn' : 2 ≤ n) (hb : b ≠ 0) : + ∃ x, a * x ^ n + b * x + c = 0 := + exists_root_C_mul_X_pow_add_C_mul_X_add_C a b c ((CharP.cast_eq_zero_iff k p n).2 hn) hn' hb + variable (k) in /-- A separably closed perfect field is also algebraically closed. -/ instance (priority := 100) isAlgClosed_of_perfectField [IsSepClosed k] [PerfectField k] : @@ -214,8 +243,8 @@ instance (priority := 100) IsSepClosure.isAlgClosure_of_perfectField then it is also a separable closure of `k`. -/ instance (priority := 100) IsSepClosure.of_isAlgClosure_of_perfectField [Algebra k K] [IsAlgClosure k K] [PerfectField k] : IsSepClosure k K := - ⟨haveI := IsAlgClosure.alg_closed (R := k) (K := K); inferInstance, - (IsAlgClosure.algebraic (R := k) (K := K)).isSeparable_of_perfectField⟩ + ⟨haveI := IsAlgClosure.isAlgClosed (R := k) (K := K); inferInstance, + (IsAlgClosure.isAlgebraic (R := k) (K := K)).isSeparable_of_perfectField⟩ variable {k} {K} diff --git a/Mathlib/FieldTheory/KrullTopology.lean b/Mathlib/FieldTheory/KrullTopology.lean index 7f7f53c3109a7..c5751d36c7ff4 100644 --- a/Mathlib/FieldTheory/KrullTopology.lean +++ b/Mathlib/FieldTheory/KrullTopology.lean @@ -178,6 +178,17 @@ instance krullTopology (K L : Type*) [Field K] [Field L] [Algebra K L] : instance (K L : Type*) [Field K] [Field L] [Algebra K L] : TopologicalGroup (L ≃ₐ[K] L) := GroupFilterBasis.isTopologicalGroup (galGroupBasis K L) +open scoped Topology in +lemma krullTopology_mem_nhds_one (K L : Type*) [Field K] [Field L] [Algebra K L] + (s : Set (L ≃ₐ[K] L)) : s ∈ 𝓝 1 ↔ ∃ E : IntermediateField K L, + FiniteDimensional K E ∧ (E.fixingSubgroup : Set (L ≃ₐ[K] L)) ⊆ s := by + rw [GroupFilterBasis.nhds_one_eq] + constructor + · rintro ⟨-, ⟨-, ⟨E, fin, rfl⟩, rfl⟩, hE⟩ + exact ⟨E, fin, hE⟩ + · rintro ⟨E, fin, hE⟩ + exact ⟨E.fixingSubgroup, ⟨E.fixingSubgroup, ⟨E, fin, rfl⟩, rfl⟩, hE⟩ + section KrullT2 open scoped Topology Filter diff --git a/Mathlib/FieldTheory/KummerExtension.lean b/Mathlib/FieldTheory/KummerExtension.lean index 671a4b1bb374a..095253e93171d 100644 --- a/Mathlib/FieldTheory/KummerExtension.lean +++ b/Mathlib/FieldTheory/KummerExtension.lean @@ -182,7 +182,7 @@ theorem X_pow_sub_C_irreducible_iff_of_prime {p : ℕ} (hp : p.Prime) {a : K} : theorem X_pow_mul_sub_C_irreducible {n m : ℕ} {a : K} (hm : Irreducible (X ^ m - C a)) - (hn : ∀ (E : Type u) [Field E] [Algebra K E] (x : E) (hx : minpoly K x = X ^ m - C a), + (hn : ∀ (E : Type u) [Field E] [Algebra K E] (x : E) (_ : minpoly K x = X ^ m - C a), Irreducible (X ^ n - C (AdjoinSimple.gen K x))) : Irreducible (X ^ (n * m) - C a) := by have hm' : m ≠ 0 := by @@ -369,7 +369,6 @@ lemma autAdjoinRootXPowSubCEquiv_root (η) : autAdjoinRootXPowSubCEquiv hζ hn H η (root _) = ((η : Kˣ) : K) • root _ := autAdjoinRootXPowSubC_root hn a η -set_option tactic.skipAssignedInstances false in lemma autAdjoinRootXPowSubCEquiv_symm_smul (σ) : ((autAdjoinRootXPowSubCEquiv hζ hn H).symm σ : Kˣ) • (root _ : K[n√a]) = σ (root _) := by have := Fact.mk H @@ -380,7 +379,7 @@ lemma autAdjoinRootXPowSubCEquiv_symm_smul (σ) : Units.val_ofPowEqOne, ite_mul, one_mul, ne_eq] simp_rw [← root_X_pow_sub_C_eq_zero_iff H] split_ifs with h - · rw [h, mul_zero, map_zero] + · rw [h, map_zero] · rw [div_mul_cancel₀ _ h] end AdjoinRoot diff --git a/Mathlib/FieldTheory/Minpoly/Basic.lean b/Mathlib/FieldTheory/Minpoly/Basic.lean index ee4583757d618..356b47cef750e 100644 --- a/Mathlib/FieldTheory/Minpoly/Basic.lean +++ b/Mathlib/FieldTheory/Minpoly/Basic.lean @@ -58,6 +58,9 @@ theorem ne_zero [Nontrivial A] (hx : IsIntegral A x) : minpoly A x ≠ 0 := theorem eq_zero (hx : ¬IsIntegral A x) : minpoly A x = 0 := dif_neg hx +theorem ne_zero_iff [Nontrivial A] : minpoly A x ≠ 0 ↔ IsIntegral A x := + ⟨fun h => of_not_not <| eq_zero.mt h, ne_zero⟩ + theorem algHom_eq (f : B →ₐ[A] B') (hf : Function.Injective f) (x : B) : minpoly A (f x) = minpoly A x := by simp_rw [minpoly, isIntegral_algHom_iff _ hf, ← Polynomial.aeval_def, aeval_algHom, diff --git a/Mathlib/FieldTheory/Minpoly/Field.lean b/Mathlib/FieldTheory/Minpoly/Field.lean index b129b8a0ecbc5..da8cfbe1cc77e 100644 --- a/Mathlib/FieldTheory/Minpoly/Field.lean +++ b/Mathlib/FieldTheory/Minpoly/Field.lean @@ -77,7 +77,7 @@ lemma dvd_iff {p : A[X]} : minpoly A x ∣ p ↔ Polynomial.aeval x p = 0 := theorem isRadical [IsReduced B] : IsRadical (minpoly A x) := fun n p dvd ↦ by rw [dvd_iff] at dvd ⊢; rw [map_pow] at dvd; exact IsReduced.eq_zero _ ⟨n, dvd⟩ -theorem dvd_map_of_isScalarTower (A K : Type*) {R : Type*} [CommRing A] [Field K] [CommRing R] +theorem dvd_map_of_isScalarTower (A K : Type*) {R : Type*} [CommRing A] [Field K] [Ring R] [Algebra A K] [Algebra A R] [Algebra K R] [IsScalarTower A K R] (x : R) : minpoly K x ∣ (minpoly A x).map (algebraMap A K) := by refine minpoly.dvd K x ?_ @@ -144,7 +144,7 @@ theorem add_algebraMap {B : Type*} [CommRing B] [Algebra A B] (x : B) refine fun h ↦ hx ?_ simpa only [add_sub_cancel_right] using IsIntegral.sub h (isIntegral_algebraMap (x := a)) -theorem sub_algebraMap {B : Type*} [CommRing B] [Algebra A B] {x : B} +theorem sub_algebraMap {B : Type*} [CommRing B] [Algebra A B] (x : B) (a : A) : minpoly A (x - algebraMap A B a) = (minpoly A x).comp (X + C a) := by simpa [sub_eq_add_neg] using add_algebraMap x (-a) @@ -179,8 +179,6 @@ noncomputable def Fintype.subtypeProd {E : Type*} {X : Set E} (hX : X.Finite) {L variable (F E K : Type*) [Field F] [Ring E] [CommRing K] [IsDomain K] [Algebra F E] [Algebra F K] [FiniteDimensional F E] --- Porting note (#11083): removed `noncomputable!` since it seems not to be slow in lean 4, --- though it isn't very computable in practice (since neither `finrank` nor `finBasis` are). /-- Function from Hom_K(E,L) to pi type Π (x : basis), roots of min poly of x -/ def rootsOfMinPolyPiType (φ : E →ₐ[F] K) (x : range (Module.finBasis F E : _ → E)) : diff --git a/Mathlib/FieldTheory/Minpoly/IsConjRoot.lean b/Mathlib/FieldTheory/Minpoly/IsConjRoot.lean new file mode 100644 index 0000000000000..d9c57dbc10fda --- /dev/null +++ b/Mathlib/FieldTheory/Minpoly/IsConjRoot.lean @@ -0,0 +1,374 @@ +/- +Copyright (c) 2024 Jiedong Jiang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jiedong Jiang +-/ +import Mathlib.FieldTheory.Minpoly.Basic +import Mathlib.FieldTheory.Adjoin +import Mathlib.FieldTheory.Normal + +/-! +# Conjugate roots + +Given two elements `x` and `y` of some `K`-algebra, these two elements are *conjugate roots* +over `K` if they have the same minimal polynomial over `K`. + +## Main definitions + +* `IsConjRoot`: `IsConjRoot K x y` means `y` is a conjugate root of `x` over `K`. + +## Main results + +* `isConjRoot_iff_exists_algEquiv`: Let `L / K` be a normal field extension. For any two elements +`x` and `y` in `L`, `IsConjRoot K x y` is equivalent to the existence of an algebra equivalence +`σ : L ≃ₐ[K] L` such that `y = σ x`. +* `not_mem_iff_exists_ne_and_isConjRoot`: Let `L / K` be a field extension. If `x` is a separable +element over `K` and the minimal polynomial of `x` splits in `L`, then `x` is not in the `K` iff +there exists a different conjugate root of `x` in `L` over `K`. + +## TODO +* Move `IsConjRoot` to earlier files and refactor the theorems in field theory using `IsConjRoot`. + +* Prove `IsConjRoot.smul`, if `x` and `y` are conjugate roots, then so are `r • x` and `r • y`. + +## Tags +conjugate root, minimal polynomial +-/ + + +open Polynomial minpoly IntermediateField + +variable {R K L S A B : Type*} [CommRing R] [CommRing S] [Ring A] [Ring B] [Field K] [Field L] +variable [Algebra R S] [Algebra R A] [Algebra R B] +variable [Algebra K S] [Algebra K L] [Algebra K A] [Algebra L S] + +variable (R) in +/-- +We say that `y` is a conjugate root of `x` over `K` if the minimal polynomial of `x` is the +same as the minimal polynomial of `y`. +-/ +def IsConjRoot (x y : A) : Prop := minpoly R x = minpoly R y + +/-- +The definition of conjugate roots. +-/ +theorem isConjRoot_def {x y : A} : IsConjRoot R x y ↔ minpoly R x = minpoly R y := Iff.rfl + +namespace IsConjRoot + +/-- +Every element is a conjugate root of itself. +-/ +@[refl] theorem refl {x : A} : IsConjRoot R x x := rfl + +/-- +If `y` is a conjugate root of `x`, then `x` is also a conjugate root of `y`. +-/ +@[symm] theorem symm {x y : A} (h : IsConjRoot R x y) : IsConjRoot R y x := Eq.symm h + +/-- +If `y` is a conjugate root of `x` and `z` is a conjugate root of `y`, then `z` is a conjugate +root of `x`. +-/ +@[trans] theorem trans {x y z: A} (h₁ : IsConjRoot R x y) (h₂ : IsConjRoot R y z) : + IsConjRoot R x z := Eq.trans h₁ h₂ + +variable (R A) in +/-- +The setoid structure on `A` defined by the equivalence relation of `IsConjRoot R · ·`. +-/ +def setoid : Setoid A where + r := IsConjRoot R + iseqv := ⟨fun _ => refl, symm, trans⟩ + +/-- +Let `p` be the minimal polynomial of `x`. If `y` is a conjugate root of `x`, then `p y = 0`. +-/ +theorem aeval_eq_zero {x y : A} (h : IsConjRoot R x y) : aeval y (minpoly R x) = 0 := + h ▸ minpoly.aeval R y + +/-- +Let `r` be an element of the base ring. If `y` is a conjugate root of `x`, then `y + r` is a +conjugate root of `x + r`. +-/ +theorem add_algebraMap {x y : S} (r : K) (h : IsConjRoot K x y) : + IsConjRoot K (x + algebraMap K S r) (y + algebraMap K S r) := by + rw [isConjRoot_def, minpoly.add_algebraMap x r, minpoly.add_algebraMap y r, h] + +/-- +Let `r` be an element of the base ring. If `y` is a conjugate root of `x`, then `y - r` is a +conjugate root of `x - r`. +-/ +theorem sub_algebraMap {x y : S} (r : K) (h : IsConjRoot K x y) : + IsConjRoot K (x - algebraMap K S r) (y - algebraMap K S r) := by + simpa only [sub_eq_add_neg, map_neg] using add_algebraMap (-r) h + +/-- +If `y` is a conjugate root of `x`, then `-y` is a conjugate root of `-x`. +-/ +theorem neg {x y : S} (h : IsConjRoot K x y) : + IsConjRoot K (-x) (-y) := by + rw [isConjRoot_def, minpoly.neg x, minpoly.neg y, h] + +end IsConjRoot + +open IsConjRoot + +/-- +A variant of `isConjRoot_algHom_iff`, only assuming `Function.Injective f`, +instead of `DivisionRing A`. +If `y` is a conjugate root of `x` and `f` is an injective `R`-algebra homomorphism, then `f y` is +a conjugate root of `f x`. +-/ +theorem isConjRoot_algHom_iff_of_injective {x y : A} {f : A →ₐ[R] B} + (hf : Function.Injective f) : IsConjRoot R (f x) (f y) ↔ IsConjRoot R x y := by + rw [isConjRoot_def, isConjRoot_def, algHom_eq f hf, algHom_eq f hf] + +/-- +If `y` is a conjugate root of `x` in some division ring and `f` is a `R`-algebra homomorphism, then +`f y` is a conjugate root of `f x`. +-/ +theorem isConjRoot_algHom_iff {A} [DivisionRing A] [Algebra R A] + [Nontrivial B] {x y : A} (f : A →ₐ[R] B) : IsConjRoot R (f x) (f y) ↔ IsConjRoot R x y := + isConjRoot_algHom_iff_of_injective f.injective + +/-- +Let `p` be the minimal polynomial of an integral element `x`. If `p y` = 0, then `y` is a +conjugate root of `x`. +-/ +theorem isConjRoot_of_aeval_eq_zero [IsDomain A] {x y : A} (hx : IsIntegral K x) + (h : aeval y (minpoly K x) = 0) : IsConjRoot K x y := + minpoly.eq_of_irreducible_of_monic (minpoly.irreducible hx) h (minpoly.monic hx) + +/-- +Let `p` be the minimal polynomial of an integral element `x`. Then `y` is a conjugate root of `x` +if and only if `p y = 0`. +-/ +theorem isConjRoot_iff_aeval_eq_zero [IsDomain A] {x y : A} + (h : IsIntegral K x) : IsConjRoot K x y ↔ aeval y (minpoly K x) = 0 := + ⟨IsConjRoot.aeval_eq_zero, isConjRoot_of_aeval_eq_zero h⟩ + +/-- +Let `s` be an `R`-algebra isomorphism. Then `s x` is a conjugate root of `x`. +-/ +@[simp] +theorem isConjRoot_of_algEquiv (x : A) (s : A ≃ₐ[R] A) : IsConjRoot R x (s x) := + Eq.symm (minpoly.algEquiv_eq s x) + +/-- +A variant of `isConjRoot_of_algEquiv`. +Let `s` be an `R`-algebra isomorphism. Then `x` is a conjugate root of `s x`. +-/ +@[simp] +theorem isConjRoot_of_algEquiv' (x : A) (s : A ≃ₐ[R] A) : IsConjRoot R (s x) x := + (minpoly.algEquiv_eq s x) + +/-- +Let `s₁` and `s₂` be two `R`-algebra isomorphisms. Then `s₂ x` is a conjugate root of `s₁ x`. +-/ +@[simp] +theorem isConjRoot_of_algEquiv₂ (x : A) (s₁ s₂ : A ≃ₐ[R] A) : IsConjRoot R (s₁ x) (s₂ x) := + isConjRoot_def.mpr <| (minpoly.algEquiv_eq s₂ x) ▸ (minpoly.algEquiv_eq s₁ x) + +/-- +Let `L / K` be a normal field extension. For any two elements `x` and `y` in `L`, if `y` is a +conjugate root of `x`, then there exists a `K`-automorphism `σ : L ≃ₐ[K] L` such +that `σ y = x`. +-/ +theorem IsConjRoot.exists_algEquiv [Normal K L] {x y: L} (h : IsConjRoot K x y) : + ∃ σ : L ≃ₐ[K] L, σ y = x := by + obtain ⟨σ, hσ⟩ := + exists_algHom_of_splits_of_aeval (normal_iff.mp inferInstance) (h ▸ minpoly.aeval K x) + exact ⟨AlgEquiv.ofBijective σ (σ.normal_bijective _ _ _), hσ⟩ + +/-- +Let `L / K` be a normal field extension. For any two elements `x` and `y` in `L`, `y` is a +conjugate root of `x` if and only if there exists a `K`-automorphism `σ : L ≃ₐ[K] L` such +that `σ y = x`. +-/ +theorem isConjRoot_iff_exists_algEquiv [Normal K L] {x y : L} : + IsConjRoot K x y ↔ ∃ σ : L ≃ₐ[K] L, σ y = x := + ⟨exists_algEquiv, fun ⟨_, h⟩ => h ▸ (isConjRoot_of_algEquiv _ _).symm⟩ + +/-- +Let `L / K` be a normal field extension. For any two elements `x` and `y` in `L`, `y` is a +conjugate root of `x` if and only if `x` and `y` falls in the same orbit of the action of Galois +group. +-/ +theorem isConjRoot_iff_orbitRel [Normal K L] {x y : L} : + IsConjRoot K x y ↔ MulAction.orbitRel (L ≃ₐ[K] L) L x y:= + (isConjRoot_iff_exists_algEquiv) + +variable [IsDomain S] + +/-- +Let `S / L / K` be a tower of extensions. For any two elements `y` and `x` in `S`, if `y` is a +conjugate root of `x` over `L`, then `y` is also a conjugate root of `x` over +`K`. +-/ +theorem IsConjRoot.of_isScalarTower [IsScalarTower K L S] {x y : S} (hx : IsIntegral K x) + (h : IsConjRoot L x y) : IsConjRoot K x y := + isConjRoot_of_aeval_eq_zero hx <| minpoly.aeval_of_isScalarTower K x y (aeval_eq_zero h) + +/-- +`y` is a conjugate root of `x` over `K` if and only if `y` is a root of the minimal polynomial of +`x`. This is variant of `isConjRoot_iff_aeval_eq_zero`. +-/ +theorem isConjRoot_iff_mem_minpoly_aroots {x y : S} (h : IsIntegral K x) : + IsConjRoot K x y ↔ y ∈ (minpoly K x).aroots S := by + rw [Polynomial.mem_aroots, isConjRoot_iff_aeval_eq_zero h] + simp only [iff_and_self] + exact fun _ => minpoly.ne_zero h + +/-- +`y` is a conjugate root of `x` over `K` if and only if `y` is a root of the minimal polynomial of +`x`. This is variant of `isConjRoot_iff_aeval_eq_zero`. +-/ +theorem isConjRoot_iff_mem_minpoly_rootSet {x y : S} + (h : IsIntegral K x) : IsConjRoot K x y ↔ y ∈ (minpoly K x).rootSet S := + (isConjRoot_iff_mem_minpoly_aroots h).trans (by simp [rootSet]) + +namespace IsConjRoot + +/-- +If `y` is a conjugate root of an integral element `x` over `R`, then `y` is also integral +over `R`. +-/ +theorem isIntegral {x y : A} (hx : IsIntegral R x) (h : IsConjRoot R x y) : + IsIntegral R y := + ⟨minpoly R x, minpoly.monic hx, h ▸ minpoly.aeval R y⟩ + +/-- +A variant of `IsConjRoot.eq_of_isConjRoot_algebraMap`, only assuming `Nontrivial R`, +`NoZeroSMulDivisors R A` and `Function.Injective (algebraMap R A)` instead of `Field R`. If `x` is a +conjugate root of some element `algebraMap R S r` in the image of the base ring, then +`x = algebraMap R S r`. +-/ +theorem eq_algebraMap_of_injective [Nontrivial R] [NoZeroSMulDivisors R S] {r : R} {x : S} + (h : IsConjRoot R (algebraMap R S r) x) (hf : Function.Injective (algebraMap R S)) : + x = algebraMap R S r := by + rw [IsConjRoot, minpoly.eq_X_sub_C_of_algebraMap_inj _ hf] at h + have : x ∈ (X - C r).aroots S := by + rw [mem_aroots] + simp [X_sub_C_ne_zero, h ▸ minpoly.aeval R x] + simpa [aroots_X_sub_C] using this + +/-- +If `x` is a conjugate root of some element `algebraMap R S r` in the image of the base ring, then +`x = algebraMap R S r`. +-/ +theorem eq_algebraMap {r : K} {x : S} (h : IsConjRoot K (algebraMap K S r) x) : + x = algebraMap K S r := + eq_algebraMap_of_injective h (algebraMap K S).injective + +/-- +A variant of `IsConjRoot.eq_zero`, only assuming `Nontrivial R`, +`NoZeroSMulDivisors R A` and `Function.Injective (algebraMap R A)` instead of `Field R`. If `x` is a +conjugate root of `0`, then `x = 0`. +-/ +theorem eq_zero_of_injective [Nontrivial R] [NoZeroSMulDivisors R S] {x : S} (h : IsConjRoot R 0 x) + (hf : Function.Injective (algebraMap R S)) : x = 0 := + (algebraMap R S).map_zero ▸ (eq_algebraMap_of_injective ((algebraMap R S).map_zero ▸ h) hf) + +/-- +If `x` is a conjugate root of `0`, then `x = 0`. +-/ +theorem eq_zero {x : S} (h : IsConjRoot K 0 x) : x = 0 := + eq_zero_of_injective h (algebraMap K S).injective + +end IsConjRoot + +/-- +A variant of `IsConjRoot.eq_of_isConjRoot_algebraMap`, only assuming `Nontrivial R`, +`NoZeroSMulDivisors R A` and `Function.Injective (algebraMap R A)` instead of `Field R`. If `x` is a +conjugate root of some element `algebraMap R S r` in the image of the base ring, then +`x = algebraMap R S r`. +-/ +theorem isConjRoot_iff_eq_algebraMap_of_injective [Nontrivial R] [NoZeroSMulDivisors R S] {r : R} + {x : S} (hf : Function.Injective (algebraMap R S)) : + IsConjRoot R (algebraMap R S r) x ↔ x = algebraMap R S r := + ⟨fun h => eq_algebraMap_of_injective h hf, fun h => h.symm ▸ rfl⟩ + +/-- +An element `x` is a conjugate root of some element `algebraMap R S r` in the image of the base ring +if and only if `x = algebraMap R S r`. +-/ +@[simp] +theorem isConjRoot_iff_eq_algebraMap {r : K} {x : S} : + IsConjRoot K (algebraMap K S r) x ↔ x = algebraMap K S r := + isConjRoot_iff_eq_algebraMap_of_injective (algebraMap K S).injective + +/-- +A variant of `isConjRoot_iff_eq_algebraMap`. +an element `algebraMap R S r` in the image of the base ring is a conjugate root of an element `x` +if and only if `x = algebraMap R S r`. +-/ +@[simp] +theorem isConjRoot_iff_eq_algebraMap' {r : K} {x : S} : + IsConjRoot K x (algebraMap K S r) ↔ x = algebraMap K S r := + eq_comm.trans <| isConjRoot_iff_eq_algebraMap_of_injective (algebraMap K S).injective + +/-- +A variant of `IsConjRoot.iff_eq_zero`, only assuming `Nontrivial R`, +`NoZeroSMulDivisors R A` and `Function.Injective (algebraMap R A)` instead of `Field R`. `x` is a +conjugate root of `0` if and only if `x = 0`. +-/ +theorem isConjRoot_zero_iff_eq_zero_of_injective [Nontrivial R] {x : S} [NoZeroSMulDivisors R S] + (hf : Function.Injective (algebraMap R S)) : IsConjRoot R 0 x ↔ x = 0 := + ⟨fun h => eq_zero_of_injective h hf, fun h => h.symm ▸ rfl⟩ + +/-- +`x` is a conjugate root of `0` if and only if `x = 0`. +-/ +@[simp] +theorem isConjRoot_zero_iff_eq_zero {x : S} : IsConjRoot K 0 x ↔ x = 0 := + isConjRoot_zero_iff_eq_zero_of_injective (algebraMap K S).injective + +/-- +A variant of `IsConjRoot.iff_eq_zero`. `0` is a conjugate root of `x` if and only if `x = 0`. +-/ +@[simp] +theorem isConjRoot_zero_iff_eq_zero' {x : S} : IsConjRoot K x 0 ↔ x = 0 := + eq_comm.trans <| isConjRoot_zero_iff_eq_zero_of_injective (algebraMap K S).injective + +namespace IsConjRoot + +/-- +A variant of `IsConjRoot.ne_zero`, only assuming `Nontrivial R`, +`NoZeroSMulDivisors R A` and `Function.Injective (algebraMap R A)` instead of `Field R`. If `y` is +a conjugate root of a nonzero element `x`, then `y` is not zero. +-/ +theorem ne_zero_of_injective [Nontrivial R] [NoZeroSMulDivisors R S] {x y : S} (hx : x ≠ 0) + (h : IsConjRoot R x y) (hf : Function.Injective (algebraMap R S)) : y ≠ 0 := + fun g => hx (eq_zero_of_injective (g ▸ h.symm) hf) + +/-- +If `y` is a conjugate root of a nonzero element `x`, then `y` is not zero. +-/ +theorem ne_zero {x y : S} (hx : x ≠ 0) (h : IsConjRoot K x y) : y ≠ 0 := + ne_zero_of_injective hx h (algebraMap K S).injective + +end IsConjRoot + +/-- +Let `L / K` be a field extension. If `x` is a separable element over `K` and the minimal polynomial +of `x` splits in `L`, then `x` is not in `K` if and only if there exists a conjugate +root of `x` over `K` in `L` which is not equal to `x` itself. +-/ +theorem not_mem_iff_exists_ne_and_isConjRoot {x : L} (h : IsSeparable K x) + (sp : (minpoly K x).Splits (algebraMap K L)) : + x ∉ (⊥ : Subalgebra K L) ↔ ∃ y : L, x ≠ y ∧ IsConjRoot K x y := by + calc + _ ↔ 2 ≤ (minpoly K x).natDegree := (minpoly.two_le_natDegree_iff h.isIntegral).symm + _ ↔ 2 ≤ Fintype.card ((minpoly K x).rootSet L) := + (Polynomial.card_rootSet_eq_natDegree h sp) ▸ Iff.rfl + _ ↔ Nontrivial ((minpoly K x).rootSet L) := Fintype.one_lt_card_iff_nontrivial + _ ↔ ∃ y : ((minpoly K x).rootSet L), ↑y ≠ x := + (nontrivial_iff_exists_ne ⟨x, mem_rootSet.mpr ⟨minpoly.ne_zero h.isIntegral, + minpoly.aeval K x⟩⟩).trans ⟨fun ⟨y, hy⟩ => ⟨y, Subtype.coe_ne_coe.mpr hy⟩, + fun ⟨y, hy⟩ => ⟨y, Subtype.coe_ne_coe.mp hy⟩⟩ + _ ↔ _ := + ⟨fun ⟨⟨y, hy⟩, hne⟩ => ⟨y, ⟨hne.symm, + (isConjRoot_iff_mem_minpoly_rootSet h.isIntegral).mpr hy⟩⟩, + fun ⟨y, hne, hy⟩ => ⟨⟨y, + (isConjRoot_iff_mem_minpoly_rootSet h.isIntegral).mp hy⟩, hne.symm⟩⟩ diff --git a/Mathlib/FieldTheory/Normal.lean b/Mathlib/FieldTheory/Normal.lean index 98ae051a5fd57..242f0ef840a7d 100644 --- a/Mathlib/FieldTheory/Normal.lean +++ b/Mathlib/FieldTheory/Normal.lean @@ -355,10 +355,55 @@ theorem AlgEquiv.restrict_liftNormal (χ : K₁ ≃ₐ[F] K₁) [Normal F K₁] (algebraMap K₁ E).injective (Eq.trans (AlgEquiv.restrictNormal_commutes _ K₁ x) (χ.liftNormal_commutes E x)) +/-- The group homomorphism given by restricting an algebra isomorphism to a normal subfield +is surjective. -/ theorem AlgEquiv.restrictNormalHom_surjective [Normal F K₁] [Normal F E] : Function.Surjective (AlgEquiv.restrictNormalHom K₁ : (E ≃ₐ[F] E) → K₁ ≃ₐ[F] K₁) := fun χ => ⟨χ.liftNormal E, χ.restrict_liftNormal E⟩ +/-- The group homomorphism given by restricting an algebra isomorphism to itself +is the identity map. -/ +@[simp] +theorem AlgEquiv.restrictNormalHom_id (F K : Type*) + [Field F] [Field K] [Algebra F K] [Normal F K] : + AlgEquiv.restrictNormalHom K = MonoidHom.id (K ≃ₐ[F] K) := by + ext f x + dsimp only [restrictNormalHom, MonoidHom.mk'_apply, MonoidHom.id_apply] + apply (algebraMap K K).injective + rw [AlgEquiv.restrictNormal_commutes] + simp only [Algebra.id.map_eq_id, RingHom.id_apply] + +namespace IsScalarTower + +/-- In a scalar tower `K₃/K₂/K₁/F` with `K₁` and `K₂` are normal over `F`, the group homomorphism +given by the restriction of algebra isomorphisms of `K₃` to `K₁` is equal to the composition of +the group homomorphism given by the restricting an algebra isomorphism of `K₃` to `K₂` and +the group homomorphism given by the restricting an algebra isomorphism of `K₂` to `K₁` -/ +theorem AlgEquiv.restrictNormalHom_comp (F K₁ K₂ K₃ : Type*) + [Field F] [Field K₁] [Field K₂] [Field K₃] + [Algebra F K₁] [Algebra F K₂] [Algebra F K₃] [Algebra K₁ K₂] [Algebra K₁ K₃] [Algebra K₂ K₃] + [IsScalarTower F K₁ K₃] [IsScalarTower F K₁ K₂] [IsScalarTower F K₂ K₃] [IsScalarTower K₁ K₂ K₃] + [Normal F K₁] [Normal F K₂] : + AlgEquiv.restrictNormalHom K₁ = + (AlgEquiv.restrictNormalHom K₁).comp + (AlgEquiv.restrictNormalHom (F := F) (K₁ := K₃) K₂) := by + ext f x + apply (algebraMap K₁ K₃).injective + rw [IsScalarTower.algebraMap_eq K₁ K₂ K₃] + simp only [AlgEquiv.restrictNormalHom, MonoidHom.mk'_apply, RingHom.coe_comp, Function.comp_apply, + ← algebraMap_apply, AlgEquiv.restrictNormal_commutes, MonoidHom.coe_comp] + +theorem AlgEquiv.restrictNormalHom_comp_apply (K₁ K₂ : Type*) {F K₃ : Type*} + [Field F] [Field K₁] [Field K₂] [Field K₃] + [Algebra F K₁] [Algebra F K₂] [Algebra F K₃] [Algebra K₁ K₂] [Algebra K₁ K₃] [Algebra K₂ K₃] + [IsScalarTower F K₁ K₃] [IsScalarTower F K₁ K₂] [IsScalarTower F K₂ K₃] [IsScalarTower K₁ K₂ K₃] + [Normal F K₁] [Normal F K₂] (f : K₃ ≃ₐ[F] K₃) : + AlgEquiv.restrictNormalHom K₁ f = + (AlgEquiv.restrictNormalHom K₁) (AlgEquiv.restrictNormalHom K₂ f) := by + rw [IsScalarTower.AlgEquiv.restrictNormalHom_comp F K₁ K₂ K₃, MonoidHom.comp_apply] + +end IsScalarTower + open IntermediateField in theorem Normal.minpoly_eq_iff_mem_orbit [h : Normal F E] {x y : E} : minpoly F x = minpoly F y ↔ x ∈ MulAction.orbit (E ≃ₐ[F] E) y := by diff --git a/Mathlib/FieldTheory/NormalClosure.lean b/Mathlib/FieldTheory/NormalClosure.lean index 680dc94bf8709..fac28822a66a5 100644 --- a/Mathlib/FieldTheory/NormalClosure.lean +++ b/Mathlib/FieldTheory/NormalClosure.lean @@ -282,4 +282,21 @@ lemma normal_iff_forall_map_eq : Normal F K ↔ ∀ σ : L →ₐ[F] L, K.map σ lemma normal_iff_forall_map_eq' : Normal F K ↔ ∀ σ : L ≃ₐ[F] L, K.map ↑σ = K := ⟨fun h σ ↦ normal_iff_forall_map_eq.1 h σ, fun h ↦ normal_iff_forall_map_le'.2 (fun σ ↦ (h σ).le)⟩ +@[simp] +lemma normalClosure_map_eq (K : IntermediateField F L) (σ : L →ₐ[F] L) : + normalClosure F (K.map σ) L = normalClosure F K L := by + have (σ : L ≃ₐ[F] L) : normalClosure F (K.map (σ : L →ₐ[F] L)) L = normalClosure F K L := by + simp_rw [normalClosure_def'', map_map] + exact (Equiv.mulRight σ).iSup_congr fun _ ↦ rfl + exact this ((Algebra.IsAlgebraic.algEquivEquivAlgHom _ _).symm σ) + +@[simp] +theorem normalClosure_le_iff_of_normal {K₁ K₂ : IntermediateField F L} [Normal F K₂] : + normalClosure F K₁ L ≤ K₂ ↔ K₁ ≤ K₂ := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · rw [normalClosure_le_iff] at h + simpa only [fieldRange_val] using h K₁.val + · rw [← normalClosure_of_normal K₂] + exact normalClosure_mono K₁ K₂ h + end IntermediateField diff --git a/Mathlib/FieldTheory/PerfectClosure.lean b/Mathlib/FieldTheory/PerfectClosure.lean index df62d0fc00813..700ee9dc3791a 100644 --- a/Mathlib/FieldTheory/PerfectClosure.lean +++ b/Mathlib/FieldTheory/PerfectClosure.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: Kenny Lau, Yury Kudryashov -/ +import Mathlib.Algebra.CharP.ExpChar import Mathlib.FieldTheory.Perfect /-! @@ -92,7 +93,6 @@ theorem quot_mk_eq_mk (x : ℕ × K) : (Quot.mk (R K p) x : PerfectClosure K p) variable {K p} /-- Lift a function `ℕ × K → L` to a function on `PerfectClosure K p`. -/ --- Porting note: removed `@[elab_as_elim]` for "unexpected eliminator resulting type L" def liftOn {L : Type*} (x : PerfectClosure K p) (f : ℕ × K → L) (hf : ∀ x y, R K p x y → f x = f y) : L := Quot.liftOn x f hf @@ -272,7 +272,7 @@ instance instAddCommGroup : AddCommGroup (PerfectClosure K p) := Quot.inductionOn e fun ⟨n, x⟩ => congr_arg (Quot.mk _) <| by simp only [iterate_map_zero, iterate_zero_apply, add_zero] - sub_eq_add_neg := fun a b => rfl + sub_eq_add_neg := fun _ _ => rfl neg_add_cancel := fun e => Quot.inductionOn e fun ⟨n, x⟩ => by simp only [quot_mk_eq_mk, neg_mk, mk_add_mk, iterate_map_neg, neg_add_cancel, mk_zero_right] @@ -496,9 +496,9 @@ instance instDivisionRing : DivisionRing (PerfectClosure K p) where rw [mul_inv_cancel₀ this, iterate_map_one] inv_zero := congr_arg (Quot.mk (R K p)) (by rw [inv_zero]) nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl instance instField : Field (PerfectClosure K p) := { (inferInstance : DivisionRing (PerfectClosure K p)), diff --git a/Mathlib/FieldTheory/PrimitiveElement.lean b/Mathlib/FieldTheory/PrimitiveElement.lean index da215b5d8dbf4..09b73357bf4f2 100644 --- a/Mathlib/FieldTheory/PrimitiveElement.lean +++ b/Mathlib/FieldTheory/PrimitiveElement.lean @@ -63,7 +63,7 @@ theorem exists_primitive_element_of_finite_top [Finite E] : ∃ α : E, F⟮α /-- Primitive element theorem for finite dimensional extension of a finite field. -/ theorem exists_primitive_element_of_finite_bot [Finite F] [FiniteDimensional F E] : ∃ α : E, F⟮α⟯ = ⊤ := - haveI : Finite E := FiniteDimensional.finite_of_finite F E + haveI : Finite E := Module.finite_of_finite F exists_primitive_element_of_finite_top F E end PrimitiveElementFinite diff --git a/Mathlib/FieldTheory/PurelyInseparable.lean b/Mathlib/FieldTheory/PurelyInseparable.lean index 93c3226de53d7..de7fb198e5afc 100644 --- a/Mathlib/FieldTheory/PurelyInseparable.lean +++ b/Mathlib/FieldTheory/PurelyInseparable.lean @@ -3,8 +3,9 @@ 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.FieldTheory.SeparableClosure +import Mathlib.Algebra.CharP.ExpChar import Mathlib.Algebra.CharP.IntermediateField +import Mathlib.FieldTheory.SeparableClosure /-! @@ -455,6 +456,18 @@ theorem IsPurelyInseparable.trans [Algebra E K] [IsScalarTower F E K] refine ⟨n + m, z, ?_⟩ rw [IsScalarTower.algebraMap_apply F E K, h1, map_pow, h2, ← pow_mul, ← pow_add] +namespace IntermediateField + +variable (M : IntermediateField F K) + +instance isPurelyInseparable_tower_bot [IsPurelyInseparable F K] : IsPurelyInseparable F M := + IsPurelyInseparable.tower_bot F M K + +instance isPurelyInseparable_tower_top [IsPurelyInseparable F K] : IsPurelyInseparable M K := + IsPurelyInseparable.tower_top F M K + +end IntermediateField + variable {E} /-- A field extension `E / F` is purely inseparable if and only if for every element `x` of `E`, @@ -667,7 +680,7 @@ if and only if for any `x ∈ S`, `x ^ (q ^ n)` is contained in `F` for some `n theorem isPurelyInseparable_adjoin_iff_pow_mem (q : ℕ) [hF : ExpChar F q] {S : Set E} : IsPurelyInseparable F (adjoin F S) ↔ ∀ x ∈ S, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by simp_rw [← le_perfectClosure_iff, adjoin_le_iff, ← mem_perfectClosure_iff_pow_mem q, - Set.le_iff_subset, Set.subset_def, SetLike.mem_coe] + Set.subset_def, SetLike.mem_coe] /-- A compositum of two purely inseparable extensions is purely inseparable. -/ instance isPurelyInseparable_sup (L1 L2 : IntermediateField F E) @@ -811,8 +824,8 @@ end purely inseparable. -/ theorem isSepClosed_iff_isPurelyInseparable_algebraicClosure [IsAlgClosure F E] : IsSepClosed F ↔ IsPurelyInseparable F E := - ⟨fun _ ↦ IsAlgClosure.algebraic.isPurelyInseparable_of_isSepClosed, fun H ↦ by - haveI := IsAlgClosure.alg_closed F (K := E) + ⟨fun _ ↦ IsAlgClosure.isAlgebraic.isPurelyInseparable_of_isSepClosed, fun H ↦ by + haveI := IsAlgClosure.isAlgClosed F (K := E) rwa [← separableClosure.eq_bot_iff, IsSepClosed.separableClosure_eq_bot_iff] at H⟩ variable {F E} in @@ -845,7 +858,7 @@ theorem perfectField_of_isSeparable_of_perfectField_top [Algebra.IsSeparable F E separable. -/ theorem perfectField_iff_isSeparable_algebraicClosure [IsAlgClosure F E] : PerfectField F ↔ Algebra.IsSeparable F E := - ⟨fun _ ↦ IsSepClosure.separable, fun _ ↦ haveI : IsAlgClosed E := IsAlgClosure.alg_closed F + ⟨fun _ ↦ IsSepClosure.separable, fun _ ↦ haveI : IsAlgClosed E := IsAlgClosure.isAlgClosed F perfectField_of_isSeparable_of_perfectField_top F E⟩ namespace Field diff --git a/Mathlib/FieldTheory/RatFunc/Basic.lean b/Mathlib/FieldTheory/RatFunc/Basic.lean index 477f652402ff1..0aedae6b5183d 100644 --- a/Mathlib/FieldTheory/RatFunc/Basic.lean +++ b/Mathlib/FieldTheory/RatFunc/Basic.lean @@ -269,7 +269,7 @@ macro "smul_tac" : tactic => `(tactic| simp_rw [← ofFractionRing_smul] <;> simp only [add_comm, mul_comm, zero_smul, succ_nsmul, zsmul_eq_mul, mul_add, mul_one, mul_zero, neg_add, mul_neg, - Int.ofNat_eq_coe, Int.cast_zero, Int.cast_add, Int.cast_one, + Int.cast_zero, Int.cast_add, Int.cast_one, Int.cast_negSucc, Int.cast_natCast, Nat.cast_succ, Localization.mk_zero, Localization.add_mk_self, Localization.neg_mk, ofFractionRing_zero, ← ofFractionRing_add, ← ofFractionRing_neg]) @@ -364,7 +364,7 @@ def map [MonoidHomClass F R[X] S[X]] (φ : F) (hφ : R[X]⁰ ≤ S[X]⁰.comap map_one' := by beta_reduce -- Porting note(#12129): force the function to be applied rw [← ofFractionRing_one, ← Localization.mk_one, liftOn_ofFractionRing_mk, dif_pos] - · simpa using ofFractionRing_one + · simpa [Localization.mk_eq_monoidOf_mk'] using ofFractionRing_one · simpa using Submonoid.one_mem _ map_mul' x y := by beta_reduce -- Porting note(#12129): force the function to be applied @@ -522,9 +522,9 @@ instance instField [IsDomain K] : Field (RatFunc K) where mul_inv_cancel _ := mul_inv_cancel zpow := zpowRec nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl section IsFractionRing @@ -547,7 +547,7 @@ instance (R : Type*) [CommSemiring R] [Algebra R K[X]] : Algebra R (RatFunc K) w rw [RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk] rw [mk_one', ← mk_smul, mk_def_of_ne (c • p) hq, mk_def_of_ne p hq, ← ofFractionRing_mul, IsLocalization.mul_mk'_eq_mk'_of_mul, Algebra.smul_def] - commutes' c x := mul_comm _ _ + commutes' _ _ := mul_comm _ _ variable {K} @@ -717,7 +717,7 @@ theorem algebraMap_ne_zero {x : K[X]} (hx : x ≠ 0) : algebraMap K[X] (RatFunc theorem liftOn_div {P : Sort v} (p q : K[X]) (f : K[X] → K[X] → P) (f0 : ∀ p, f p 0 = f 0 1) (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q') (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' := - fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) : + fun {_ _ _ _} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) : (RatFunc.liftOn (algebraMap _ (RatFunc K) p / algebraMap _ _ q)) f @H = f p q := by rw [← mk_eq_div, liftOn_mk _ _ f f0 @H'] @@ -735,7 +735,7 @@ then `P` holds on all elements of `RatFunc K`. See also `induction_on'`, which is a recursion principle defined in terms of `RatFunc.mk`. -/ protected theorem induction_on {P : RatFunc K → Prop} (x : RatFunc K) - (f : ∀ (p q : K[X]) (hq : q ≠ 0), P (algebraMap _ (RatFunc K) p / algebraMap _ _ q)) : P x := + (f : ∀ (p q : K[X]) (_ : q ≠ 0), P (algebraMap _ (RatFunc K) p / algebraMap _ _ q)) : P x := x.induction_on' fun p q hq => by simpa using f p q hq theorem ofFractionRing_mk' (x : K[X]) (y : K[X]⁰) : diff --git a/Mathlib/FieldTheory/RatFunc/Defs.lean b/Mathlib/FieldTheory/RatFunc/Defs.lean index b45d1838b3eb7..c8a7d4b92a7b4 100644 --- a/Mathlib/FieldTheory/RatFunc/Defs.lean +++ b/Mathlib/FieldTheory/RatFunc/Defs.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ +import Mathlib.Algebra.Polynomial.Degree.Definitions import Mathlib.RingTheory.Localization.FractionRing -import Mathlib.Algebra.Polynomial.RingDivision /-! # The field of rational functions @@ -119,7 +119,7 @@ theorem liftOn_ofFractionRing_mk {P : Sort v} (n : K[X]) (d : K[X]⁰) (f : K[X] exact Localization.liftOn_mk _ _ _ _ theorem liftOn_condition_of_liftOn'_condition {P : Sort v} {f : K[X] → K[X] → P} - (H : ∀ {p q a} (hq : q ≠ 0) (_ha : a ≠ 0), f (a * p) (a * q) = f p q) ⦃p q p' q' : K[X]⦄ + (H : ∀ {p q a} (_ : q ≠ 0) (_ha : a ≠ 0), f (a * p) (a * q) = f p q) ⦃p q p' q' : K[X]⦄ (hq : q ≠ 0) (hq' : q' ≠ 0) (h : q' * p = q * p') : f p q = f p' q' := calc f p q = f (q' * p) (q' * q) := (H hq hq').symm @@ -183,7 +183,7 @@ theorem mk_eq_mk {p q p' q' : K[X]} (hq : q ≠ 0) (hq' : q' ≠ 0) : theorem liftOn_mk {P : Sort v} (p q : K[X]) (f : K[X] → K[X] → P) (f0 : ∀ p, f p 0 = f 0 1) (H' : ∀ {p q p' q'} (_hq : q ≠ 0) (_hq' : q' ≠ 0), q' * p = q * p' → f p q = f p' q') (H : ∀ {p q p' q'} (_hq : q ∈ K[X]⁰) (_hq' : q' ∈ K[X]⁰), q' * p = q * p' → f p q = f p' q' := - fun {p q p' q'} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) : + fun {_ _ _ _} hq hq' h => H' (nonZeroDivisors.ne_zero hq) (nonZeroDivisors.ne_zero hq') h) : (RatFunc.mk p q).liftOn f @H = f p q := by by_cases hq : q = 0 · subst hq diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index fd852c7cdf7d7..a4eefb8290f2c 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.Polynomial.Splits import Mathlib.Algebra.Squarefree.Basic import Mathlib.FieldTheory.Minpoly.Field import Mathlib.RingTheory.PowerBasis +import Mathlib.FieldTheory.IntermediateField.Basic /-! @@ -167,16 +168,13 @@ theorem isUnit_of_self_mul_dvd_separable {p q : R[X]} (hp : p.Separable) (hq : q ring exact IsCoprime.of_mul_right_left (IsCoprime.of_mul_left_left this) -theorem multiplicity_le_one_of_separable [DecidableRel fun (x : R[X]) x_1 ↦ x ∣ x_1] - {p q : R[X]} (hq : ¬IsUnit q) (hsep : Separable p) : - multiplicity q p ≤ 1 := by +theorem emultiplicity_le_one_of_separable {p q : R[X]} (hq : ¬IsUnit q) (hsep : Separable p) : + emultiplicity q p ≤ 1 := by contrapose! hq apply isUnit_of_self_mul_dvd_separable hsep rw [← sq] - apply multiplicity.pow_dvd_of_le_multiplicity - have h : ⟨Part.Dom 1 ∧ Part.Dom 1, fun _ ↦ 2⟩ ≤ multiplicity q p := PartENat.add_one_le_of_lt hq - rw [and_self] at h - exact h + apply pow_dvd_of_le_emultiplicity + exact Order.add_one_le_of_lt hq /-- A separable polynomial is square-free. @@ -184,8 +182,8 @@ 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_multiplicity_le_one p] - exact fun f => or_iff_not_imp_right.mpr fun hunit => multiplicity_le_one_of_separable hunit hsep + rw [multiplicity.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 @@ -256,14 +254,34 @@ theorem separable_X_pow_sub_C_unit {n : ℕ} (u : Rˣ) (hn : IsUnit (n : R)) : simp only [Units.inv_mul, hn', C.map_one, mul_one, ← pow_succ', Nat.sub_add_cancel (show 1 ≤ n from hpos), sub_add_cancel] +/-- If `n = 0` in `R` and `b` is a unit, then `a * X ^ n + b * X + c` is separable. -/ +theorem separable_C_mul_X_pow_add_C_mul_X_add_C + {n : ℕ} (a b c : R) (hn : (n : R) = 0) (hb : IsUnit b) : + (C a * X ^ n + C b * X + C c).Separable := by + set f := C a * X ^ n + C b * X + C c + have hderiv : derivative f = C b := by + simp_rw [f, map_add derivative, derivative_C] + simp [hn] + obtain ⟨e, hb⟩ := hb.exists_left_inv + refine ⟨-derivative f, f + C e, ?_⟩ + rw [hderiv, right_distrib, ← add_assoc, neg_mul, mul_comm, neg_add_cancel, zero_add, + ← map_mul, hb, map_one] + +/-- If `R` is of characteristic `p`, `p ∣ n` and `b` is a unit, +then `a * X ^ n + b * X + c` is separable. -/ +theorem separable_C_mul_X_pow_add_C_mul_X_add_C' + (p n : ℕ) (a b c : R) [CharP R p] (hn : p ∣ n) (hb : IsUnit b) : + (C a * X ^ n + C b * X + C c).Separable := + separable_C_mul_X_pow_add_C_mul_X_add_C a b c ((CharP.cast_eq_zero_iff R p n).2 hn) hb + theorem rootMultiplicity_le_one_of_separable [Nontrivial R] {p : R[X]} (hsep : Separable p) (x : R) : rootMultiplicity x p ≤ 1 := by classical by_cases hp : p = 0 · simp [hp] - rw [rootMultiplicity_eq_multiplicity, dif_neg hp, ← PartENat.coe_le_coe, PartENat.natCast_get, - Nat.cast_one] - exact multiplicity_le_one_of_separable (not_isUnit_X_sub_C _) hsep + rw [rootMultiplicity_eq_multiplicity, if_neg hp, ← Nat.cast_le (α := ℕ∞), + Nat.cast_one, ← (multiplicity_X_sub_C_finite x hp).emultiplicity_eq_multiplicity] + apply emultiplicity_le_one_of_separable (not_isUnit_X_sub_C _) hsep end CommRing @@ -307,7 +325,7 @@ theorem separable_map {S} [CommRing S] [Nontrivial S] (f : F →+* S) {p : F[X]} theorem separable_prod_X_sub_C_iff' {ι : Sort _} {f : ι → F} {s : Finset ι} : (∏ i ∈ s, (X - C (f i))).Separable ↔ ∀ x ∈ s, ∀ y ∈ s, f x = f y → x = y := - ⟨fun hfs x hx y hy hfxy => hfs.inj_of_prod_X_sub_C hx hy hfxy, fun H => by + ⟨fun hfs _ hx _ hy hfxy => hfs.inj_of_prod_X_sub_C hx hy hfxy, fun H => by rw [← prod_attach] exact separable_prod' @@ -333,12 +351,11 @@ theorem separable_or {f : F[X]} (hf : Irreducible f) : have := natDegree_eq_zero_of_derivative_eq_zero H have := (natDegree_pos_iff_degree_pos.mpr <| degree_pos_of_irreducible hf).ne' contradiction - haveI := isLocalRingHom_expand F hp + haveI := isLocalHom_expand F hp exact Or.inr ⟨by rw [separable_iff_derivative_ne_zero hf, Classical.not_not, H], contract p f, - of_irreducible_map (expand F p : F[X] →+* F[X]) - (by rwa [← expand_contract p H hp.ne'] at hf), + Irreducible.of_map (by rwa [← expand_contract p H hp.ne'] at hf), expand_contract p H hp.ne'⟩ else Or.inl <| (separable_iff_derivative_ne_zero hf).2 H @@ -407,6 +424,11 @@ theorem separable_X_pow_sub_C {n : ℕ} (a : F) (hn : (n : F) ≠ 0) (ha : a ≠ Separable (X ^ n - C a) := separable_X_pow_sub_C_unit (Units.mk0 a ha) (IsUnit.mk0 (n : F) hn) +/-- If `F` is of characteristic `p` and `p ∤ n`, then `X ^ n - a` is separable for any `a ≠ 0`. -/ +theorem separable_X_pow_sub_C' (p n : ℕ) (a : F) [CharP F p] (hn : ¬p ∣ n) (ha : a ≠ 0) : + Separable (X ^ n - C a) := + separable_X_pow_sub_C a (by rwa [← CharP.cast_eq_zero_iff F p n] at hn) ha + -- this can possibly be strengthened to making `separable_X_pow_sub_C_unit` a -- bi-implication, but it is nontrivial! /-- In a field `F`, `X ^ n - 1` is separable iff `↑n ≠ 0`. -/ @@ -584,7 +606,7 @@ end AlgEquiv section IsScalarTower -variable [Field L] [CommRing E] [Algebra F L] +variable [Field L] [Ring E] [Algebra F L] [Algebra F E] [Algebra L E] [IsScalarTower F L E] /-- If `E / L / F` is a scalar tower and `x : E` is separable over `F`, then it's also separable @@ -675,29 +697,45 @@ theorem Algebra.IsSeparable.of_algHom [Algebra.IsSeparable F E'] : Algebra.IsSep end +namespace IntermediateField + +variable [Field K] [Algebra F K] (M : IntermediateField F K) + +instance isSeparable_tower_bot [Algebra.IsSeparable F K] : Algebra.IsSeparable F M := + Algebra.isSeparable_tower_bot_of_isSeparable F M K + +instance isSeparable_tower_top [Algebra.IsSeparable F K] : Algebra.IsSeparable M K := + Algebra.isSeparable_tower_top_of_isSeparable F M K + +end IntermediateField + end Field section AlgEquiv -variable {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁] - [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) +open RingHom RingEquiv + +variable {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Ring B₁] [Field A₂] [Ring B₂] + [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) -include e₁ e₂ he +include he lemma IsSeparable.of_equiv_equiv {x : B₁} (h : IsSeparable A₁ x) : IsSeparable A₂ (e₂ x) := letI := e₁.toRingHom.toAlgebra - letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra - haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq - (fun x ↦ by simp [RingHom.algebraMap_toAlgebra]) + letI : Algebra A₂ B₁ := + { (algebraMap A₁ B₁).comp e₁.symm.toRingHom with + smul := fun a b ↦ ((algebraMap A₁ B₁).comp e₁.symm.toRingHom a) * b + commutes' := fun r x ↦ (Algebra.commutes) (e₁.symm.toRingHom r) x + smul_def' := fun _ _ ↦ rfl } + haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq <| fun x ↦ + (algebraMap A₁ B₁).congr_arg <| id ((e₁.symm_apply_apply x).symm) let e : B₁ ≃ₐ[A₂] B₂ := { e₂ with - commutes' := fun r ↦ by - simpa [RingHom.algebraMap_toAlgebra] using DFunLike.congr_fun he.symm (e₁.symm r) } - have := IsSeparable.tower_top A₂ h - IsSeparable.of_algHom e.symm ((e₂.symm_apply_apply x).symm ▸ this) + commutes' := fun x ↦ by + simpa [RingHom.algebraMap_toAlgebra] using DFunLike.congr_fun he.symm (e₁.symm x) } + (AlgEquiv.isSeparable_iff e).mpr <| IsSeparable.tower_top A₂ h -lemma Algebra.IsSeparable.of_equiv_equiv - [Algebra.IsSeparable A₁ B₁] : Algebra.IsSeparable A₂ B₂ := +lemma Algebra.IsSeparable.of_equiv_equiv [Algebra.IsSeparable A₁ B₁] : Algebra.IsSeparable A₂ B₂ := ⟨fun x ↦ (e₂.apply_symm_apply x) ▸ _root_.IsSeparable.of_equiv_equiv e₁ e₂ he (Algebra.IsSeparable.isSeparable _ _)⟩ diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index fb1ec8ab2843c..ec3dbd6aa4fb7 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -564,9 +564,9 @@ theorem eq_X_pow_char_pow_sub_C_pow_of_natSepDegree_eq_one (q : ℕ) [ExpChar F 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 classical - have hne := (multiplicity.pos_of_dvd hF hf).ne' + have hne := (multiplicity_pos_of_dvd hf).ne' refine ⟨_, n, y, hne, H, ?_⟩ - obtain ⟨c, hf, H⟩ := multiplicity.exists_eq_pow_mul_and_not_dvd hF + obtain ⟨c, hf, H⟩ := hF.exists_eq_pow_mul_and_not_dvd rw [hf, natSepDegree_mul_of_isCoprime _ c <| IsCoprime.pow_left <| (hI.coprime_or_dvd c).resolve_right H, natSepDegree_pow_of_ne_zero _ hne, hD, add_right_eq_self, natSepDegree_eq_zero_iff] at h @@ -639,10 +639,10 @@ theorem natSepDegree_eq_one_iff_eq_X_sub_C_pow : (minpoly F x).natSepDegree = 1 rw [minpoly.aeval, map_sub, map_pow, aeval_X, aeval_C, sub_eq_zero, eq_comm] at hx use n rw [h, Polynomial.map_sub, Polynomial.map_pow, map_X, map_C, hx, map_pow, - ← sub_pow_expChar_pow_of_commute E[X] X (C x) (commute_X _)] + ← sub_pow_expChar_pow_of_commute _ _ (commute_X _)] apply_fun constantCoeff at h simp_rw [map_pow, map_sub, constantCoeff_apply, coeff_map, coeff_X_zero, coeff_C_zero] at h - rw [zero_sub, neg_pow, ExpChar.neg_one_pow_expChar_pow] at h + rw [zero_sub, neg_pow, neg_one_pow_expChar_pow] at h exact ⟨n, -(minpoly F x).coeff 0, by rw [map_neg, h, neg_mul, one_mul, neg_neg]⟩ end minpoly diff --git a/Mathlib/FieldTheory/SplittingField/Construction.lean b/Mathlib/FieldTheory/SplittingField/Construction.lean index fb0572b56c8b9..8f9e3daadffc7 100644 --- a/Mathlib/FieldTheory/SplittingField/Construction.lean +++ b/Mathlib/FieldTheory/SplittingField/Construction.lean @@ -165,7 +165,7 @@ protected theorem splits (n : ℕ) : ∀ (f : K[X]) (_hfn : f.natDegree = n), Splits (algebraMap K <| SplittingFieldAux n f) f := Nat.recOn (motive := fun n => ∀ {K : Type u} [Field K], ∀ (f : K[X]) (_hfn : f.natDegree = n), Splits (algebraMap K <| SplittingFieldAux n f) f) n - (fun {K} _ _ hf => + (fun {_} _ _ hf => splits_of_degree_le_one _ (le_trans degree_le_natDegree <| hf.symm ▸ WithBot.coe_le_coe.2 zero_le_one)) fun n ih {K} _ f hf => by @@ -181,7 +181,7 @@ theorem adjoin_rootSet (n : ℕ) : ∀ {K : Type u} [Field K], ∀ (f : K[X]) (_hfn : f.natDegree = n), Algebra.adjoin K (f.rootSet (SplittingFieldAux n f)) = ⊤) - n (fun {K} _ f _hf => Algebra.eq_top_iff.2 fun x => Subalgebra.range_le _ ⟨x, rfl⟩) + n (fun {_} _ _ _hf => Algebra.eq_top_iff.2 fun x => Subalgebra.range_le _ ⟨x, rfl⟩) fun n ih {K} _ f hfn => by have hndf : f.natDegree ≠ 0 := by intro h; rw [h] at hfn; cases hfn have hfn0 : f ≠ 0 := by intro h; rw [h] at hndf; exact hndf rfl diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean index 6e6e991b9b0b4..eb38b5464c6a8 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean @@ -620,7 +620,7 @@ theorem _root_.Collinear.oangle_sign_of_sameRay_vsub {p₁ p₂ p₃ p₄ : P} ( (continuous_fst.subtype_val.prod_mk (continuous_const.prod_mk (continuous_snd.vadd continuous_fst.subtype_val))).continuousOn have hf : ContinuousOn (fun p : P × P × P => ∡ p.1 p.2.1 p.2.2) s := by - refine ContinuousAt.continuousOn fun p hp => continuousAt_oangle ?_ ?_ + refine continuousOn_of_forall_continuousAt fun p hp => continuousAt_oangle ?_ ?_ all_goals simp_rw [s, Set.mem_image, Set.mem_prod, Set.mem_univ, true_and, Prod.ext_iff] at hp obtain ⟨q₁, q₅, q₂⟩ := p @@ -716,7 +716,7 @@ theorem _root_.AffineSubspace.SSameSide.oangle_sign_eq {s : AffineSubspace ℝ P have hc : IsConnected sp := (isConnected_setOf_sSameSide hp₃p₄.2.1 hp₃p₄.nonempty).image _ (continuous_const.prod_mk (Continuous.Prod.mk_left _)).continuousOn have hf : ContinuousOn (fun p : P × P × P => ∡ p.1 p.2.1 p.2.2) sp := by - refine ContinuousAt.continuousOn fun p hp => continuousAt_oangle ?_ ?_ + refine continuousOn_of_forall_continuousAt fun p hp => continuousAt_oangle ?_ ?_ all_goals simp_rw [sp, Set.mem_image, Set.mem_setOf] at hp obtain ⟨p', hp', rfl⟩ := hp diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean index 3f2938cdce408..3e26c839b61d6 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean @@ -223,12 +223,10 @@ theorem oangle_neg_self_right {x : V} (hx : x ≠ 0) : o.oangle x (-x) = π := b simp [oangle_neg_right, hx] /-- Twice the angle between the negation of a vector and that vector is 0. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem two_zsmul_oangle_neg_self_left (x : V) : (2 : ℤ) • o.oangle (-x) x = 0 := by by_cases hx : x = 0 <;> simp [hx] /-- Twice the angle between a vector and its negation is 0. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem two_zsmul_oangle_neg_self_right (x : V) : (2 : ℤ) • o.oangle x (-x) = 0 := by by_cases hx : x = 0 <;> simp [hx] @@ -757,19 +755,8 @@ outside of that proof. -/ theorem oangle_smul_add_right_eq_zero_or_eq_pi_iff {x y : V} (r : ℝ) : o.oangle x (r • x + y) = 0 ∨ o.oangle x (r • x + y) = π ↔ o.oangle x y = 0 ∨ o.oangle x y = π := by - simp_rw [oangle_eq_zero_or_eq_pi_iff_not_linearIndependent, Fintype.not_linearIndependent_iff] - -- Porting note: at this point all occurrences of the bound variable `i` are of type - -- `Fin (Nat.succ (Nat.succ 0))`, but `Fin.sum_univ_two` and `Fin.exists_fin_two` expect it to be - -- `Fin 2` instead. Hence all the `conv`s. - -- Was `simp_rw [Fin.sum_univ_two, Fin.exists_fin_two]` - conv_lhs => enter [1, g, 1, 1, 2, i]; tactic => change Fin 2 at i - conv_lhs => enter [1, g]; rw [Fin.sum_univ_two] - conv_rhs => enter [1, g, 1, 1, 2, i]; tactic => change Fin 2 at i - conv_rhs => enter [1, g]; rw [Fin.sum_univ_two] - conv_lhs => enter [1, g, 2, 1, i]; tactic => change Fin 2 at i - conv_lhs => enter [1, g]; rw [Fin.exists_fin_two] - conv_rhs => enter [1, g, 2, 1, i]; tactic => change Fin 2 at i - conv_rhs => enter [1, g]; rw [Fin.exists_fin_two] + simp_rw [oangle_eq_zero_or_eq_pi_iff_not_linearIndependent, Fintype.not_linearIndependent_iff, + Fin.sum_univ_two, Fin.exists_fin_two] refine ⟨fun h => ?_, fun h => ?_⟩ · rcases h with ⟨m, h, hm⟩ change m 0 • x + m 1 • (r • x + y) = 0 at h @@ -807,7 +794,7 @@ theorem oangle_sign_smul_add_right (x y : V) (r : ℝ) : have hc : IsConnected s := isConnected_univ.image _ (continuous_const.prod_mk ((continuous_id.smul continuous_const).add continuous_const)).continuousOn have hf : ContinuousOn (fun z : V × V => o.oangle z.1 z.2) s := by - refine ContinuousAt.continuousOn fun z hz => o.continuousAt_oangle ?_ ?_ + refine continuousOn_of_forall_continuousAt fun z hz => o.continuousAt_oangle ?_ ?_ all_goals simp_rw [s, Set.mem_image] at hz obtain ⟨r', -, rfl⟩ := hz @@ -912,7 +899,6 @@ theorem oangle_sign_sub_left_swap (x y : V) : (o.oangle (x - y) x).sign = (o.oan /-- The sign of the angle between a vector, and a linear combination of that vector with a second vector, is the sign of the factor by which the second vector is multiplied in that combination multiplied by the sign of the angle between the two vectors. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem oangle_sign_smul_add_smul_right (x y : V) (r₁ r₂ : ℝ) : (o.oangle x (r₁ • x + r₂ • y)).sign = SignType.sign r₂ * (o.oangle x y).sign := by rw [← o.oangle_sign_smul_add_right x (r₁ • x + r₂ • y) (-r₁)] @@ -921,7 +907,6 @@ theorem oangle_sign_smul_add_smul_right (x y : V) (r₁ r₂ : ℝ) : /-- The sign of the angle between a linear combination of two vectors and the second vector is the sign of the factor by which the first vector is multiplied in that combination multiplied by the sign of the angle between the two vectors. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem oangle_sign_smul_add_smul_left (x y : V) (r₁ r₂ : ℝ) : (o.oangle (r₁ • x + r₂ • y) y).sign = SignType.sign r₁ * (o.oangle x y).sign := by simp_rw [o.oangle_rev y, Real.Angle.sign_neg, add_comm (r₁ • x), oangle_sign_smul_add_smul_right, diff --git a/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean index 9dcdde2ba5730..36b42892368e8 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean @@ -33,7 +33,7 @@ namespace EuclideanGeometry open InnerProductGeometry variable {V P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P] - [NormedAddTorsor V P] {p p₀ p₁ p₂ : P} + [NormedAddTorsor V P] {p p₀ : P} /-- The undirected angle at `p2` between the line segments to `p1` and `p3`. If either of those points equals `p2`, this is π/2. Use @@ -350,7 +350,7 @@ theorem angle_eq_zero_iff_ne_and_wbtw {p₁ p₂ p₃ : P} : · rw [angle, angle_eq_zero_iff] rintro ⟨hp₁p₂, r, hr0, hp₃p₂⟩ rcases le_or_lt 1 r with (hr1 | hr1) - · refine Or.inl ⟨vsub_ne_zero.1 hp₁p₂, r⁻¹, ⟨(inv_pos.2 hr0).le, inv_le_one hr1⟩, ?_⟩ + · refine Or.inl ⟨vsub_ne_zero.1 hp₁p₂, r⁻¹, ⟨(inv_pos.2 hr0).le, inv_le_one_of_one_le₀ hr1⟩, ?_⟩ rw [AffineMap.lineMap_apply, hp₃p₂, smul_smul, inv_mul_cancel₀ hr0.ne.symm, one_smul, vsub_vadd] · refine Or.inr ⟨?_, r, ⟨hr0.le, hr1.le⟩, ?_⟩ diff --git a/Mathlib/Geometry/Euclidean/Basic.lean b/Mathlib/Geometry/Euclidean/Basic.lean index b9807b923e2cb..d39b79aad2703 100644 --- a/Mathlib/Geometry/Euclidean/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Basic.lean @@ -353,7 +353,6 @@ theorem orthogonalProjection_mem_subspace_eq_self {s : AffineSubspace ℝ P} [No exact p.2 /-- Orthogonal projection is idempotent. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem orthogonalProjection_orthogonalProjection (s : AffineSubspace ℝ P) [Nonempty s] [HasOrthogonalProjection s.direction] (p : P) : orthogonalProjection s (orthogonalProjection s p) = orthogonalProjection s p := by diff --git a/Mathlib/Geometry/Euclidean/Circumcenter.lean b/Mathlib/Geometry/Euclidean/Circumcenter.lean index ab715d6d83899..bd9d26e0df104 100644 --- a/Mathlib/Geometry/Euclidean/Circumcenter.lean +++ b/Mathlib/Geometry/Euclidean/Circumcenter.lean @@ -453,7 +453,7 @@ theorem orthogonalProjection_eq_circumcenter_of_dist_eq {n : ℕ} (s : Simplex /-- The orthogonal projection of the circumcenter onto a face is the circumcenter of that face. -/ theorem orthogonalProjection_circumcenter {n : ℕ} (s : Simplex ℝ P n) {fs : Finset (Fin (n + 1))} - {m : ℕ} (h : fs.card = m + 1) : + {m : ℕ} (h : #fs = m + 1) : ↑((s.face h).orthogonalProjectionSpan s.circumcenter) = (s.face h).circumcenter := haveI hr : ∃ r, ∀ i, dist ((s.face h).points i) s.circumcenter = r := by use s.circumradius @@ -564,7 +564,7 @@ theorem point_eq_affineCombination_of_pointsWithCircumcenter {n : ℕ} (s : Simp terms of `pointsWithCircumcenter`. -/ def centroidWeightsWithCircumcenter {n : ℕ} (fs : Finset (Fin (n + 1))) : PointsWithCircumcenterIndex n → ℝ - | pointIndex i => if i ∈ fs then (card fs : ℝ)⁻¹ else 0 + | pointIndex i => if i ∈ fs then (#fs : ℝ)⁻¹ else 0 | circumcenterIndex => 0 /-- `centroidWeightsWithCircumcenter` sums to 1, if the `Finset` is nonempty. -/ @@ -584,7 +584,7 @@ theorem centroid_eq_affineCombination_of_pointsWithCircumcenter {n : ℕ} (s : S simp_rw [centroid_def, affineCombination_apply, weightedVSubOfPoint_apply, sum_pointsWithCircumcenter, centroidWeightsWithCircumcenter, pointsWithCircumcenter_point, zero_smul, add_zero, centroidWeights, - ← sum_indicator_subset_of_eq_zero (Function.const (Fin (n + 1)) (card fs : ℝ)⁻¹) + ← sum_indicator_subset_of_eq_zero (Function.const (Fin (n + 1)) (#fs : ℝ)⁻¹) (fun i wi => wi • (s.points i -ᵥ Classical.choice AddTorsor.nonempty)) fs.subset_univ fun _ => zero_smul ℝ _, Set.indicator_apply] @@ -638,7 +638,7 @@ theorem reflection_circumcenter_eq_affineCombination_of_pointsWithCircumcenter { reflection (affineSpan ℝ (s.points '' {i₁, i₂})) s.circumcenter = (univ : Finset (PointsWithCircumcenterIndex n)).affineCombination ℝ s.pointsWithCircumcenter (reflectionCircumcenterWeightsWithCircumcenter i₁ i₂) := by - have hc : card ({i₁, i₂} : Finset (Fin (n + 1))) = 2 := by simp [h] + have hc : #{i₁, i₂} = 2 := by simp [h] -- Making the next line a separate definition helps the elaborator: set W : AffineSubspace ℝ P := affineSpan ℝ (s.points '' {i₁, i₂}) have h_faces : diff --git a/Mathlib/Geometry/Euclidean/Inversion/Basic.lean b/Mathlib/Geometry/Euclidean/Inversion/Basic.lean index d819c1008538f..f1ccbd341903b 100644 --- a/Mathlib/Geometry/Euclidean/Inversion/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Inversion/Basic.lean @@ -32,7 +32,7 @@ variable {V P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricS namespace EuclideanGeometry -variable {a b c d x y z : P} {r R : ℝ} +variable {c x y : P} {R : ℝ} /-- Inversion in a sphere in an affine space. This map sends each point `x` to the point `y` such that `y -ᵥ c = (R / dist x c) ^ 2 • (x -ᵥ c)`, where `c` and `R` are the center and the radius the diff --git a/Mathlib/Geometry/Euclidean/Inversion/Calculus.lean b/Mathlib/Geometry/Euclidean/Inversion/Calculus.lean index c79d35e96efba..78cc525a15568 100644 --- a/Mathlib/Geometry/Euclidean/Inversion/Calculus.lean +++ b/Mathlib/Geometry/Euclidean/Inversion/Calculus.lean @@ -81,7 +81,7 @@ end DotNotation namespace EuclideanGeometry -variable {a b c d x y z : F} {r R : ℝ} +variable {c x : F} {R : ℝ} /-- Formula for the Fréchet derivative of `EuclideanGeometry.inversion c R`. -/ theorem hasFDerivAt_inversion (hx : x ≠ c) : diff --git a/Mathlib/Geometry/Euclidean/MongePoint.lean b/Mathlib/Geometry/Euclidean/MongePoint.lean index fbf488bef44b3..f08ceefb2ff48 100644 --- a/Mathlib/Geometry/Euclidean/MongePoint.lean +++ b/Mathlib/Geometry/Euclidean/MongePoint.lean @@ -168,7 +168,7 @@ theorem mongePointVSubFaceCentroidWeightsWithCircumcenter_eq_sub {n : ℕ} {i₁ cases' i with i · rw [Pi.sub_apply, mongePointWeightsWithCircumcenter, centroidWeightsWithCircumcenter, mongePointVSubFaceCentroidWeightsWithCircumcenter] - have hu : card ({i₁, i₂}ᶜ : Finset (Fin (n + 3))) = n + 1 := by + have hu : #{i₁, i₂}ᶜ = n + 1 := by simp [card_compl, Fintype.card_fin, h] rw [hu] by_cases hi : i = i₁ ∨ i = i₂ <;> simp [compl_eq_univ_sdiff, hi] @@ -306,7 +306,7 @@ theorem eq_mongePoint_of_forall_mem_mongePlane {n : ℕ} {s : Simplex ℝ P (n + rw [hu, ← vectorSpan_image_eq_span_vsub_set_left_ne ℝ _ (Set.mem_univ _), Set.image_univ] at hi have hv : p -ᵥ s.mongePoint ∈ vectorSpan ℝ (Set.range s.points) := by let s₁ : Finset (Fin (n + 3)) := univ.erase i₁ - obtain ⟨i₂, h₂⟩ := card_pos.1 (show 0 < card s₁ by simp [s₁, card_erase_of_mem]) + obtain ⟨i₂, h₂⟩ := card_pos.1 (show 0 < #s₁ by simp [s₁, card_erase_of_mem]) have h₁₂ : i₁ ≠ i₂ := (ne_of_mem_erase h₂).symm exact (Submodule.mem_inf.1 (h' i₂ h₁₂)).2 exact Submodule.disjoint_def.1 (vectorSpan ℝ (Set.range s.points)).orthogonal_disjoint _ hv hi @@ -359,7 +359,7 @@ theorem finrank_direction_altitude {n : ℕ} (s : Simplex ℝ P (n + 1)) (i : Fi rw [direction_altitude] have h := Submodule.finrank_add_inf_finrank_orthogonal (vectorSpan_mono ℝ (Set.image_subset_range s.points ↑(univ.erase i))) - have hc : card (univ.erase i) = n + 1 := by rw [card_erase_of_mem (mem_univ _)]; simp + have hc : #(univ.erase i) = n + 1 := by rw [card_erase_of_mem (mem_univ _)]; simp refine add_left_cancel (_root_.trans h ?_) classical rw [s.independent.finrank_vectorSpan (Fintype.card_fin _), ← Finset.coe_image, @@ -502,16 +502,8 @@ theorem dist_orthocenter_reflection_circumcenter (t : Triangle ℝ P) {i₁ i₂ ∃ i₃, univ \ ({i₁, i₂} : Finset (Fin 3)) = {i₃} ∧ i₃ ≠ i₁ ∧ i₃ ≠ i₂ := by -- Porting note (#11043): was `decide!` fin_cases i₁ <;> fin_cases i₂ <;> simp at h <;> decide - -- Porting note: Original proof was `simp_rw [← sum_sdiff hu, hi₃]; simp [hi₃₁, hi₃₂]; norm_num` - rw [← sum_sdiff hu, ← sum_sdiff hu, hi₃, sum_singleton, ← sum_sdiff hu, hi₃] - split_ifs with h - · exact (h.elim hi₃₁ hi₃₂).elim - simp only [zero_add, Nat.cast_one, inv_one, sub_zero, one_mul, pointsWithCircumcenter_point, - sum_singleton, h, ite_false, dist_self, mul_zero, mem_singleton, true_or, ite_true, sub_self, - zero_mul, implies_true, sum_insert_of_eq_zero_if_not_mem, or_true, add_zero, div_one, - sub_neg_eq_add, pointsWithCircumcenter_eq_circumcenter, dist_circumcenter_eq_circumradius, - sum_const_zero, dist_circumcenter_eq_circumradius', mul_one, neg_add_rev, add_self_div_two] - norm_num + simp_rw [← sum_sdiff hu, hi₃] + norm_num [hi₃₁, hi₃₂] /-- The distance from the orthocenter to the reflection of the circumcenter in a side equals the circumradius, variant using a diff --git a/Mathlib/Geometry/Euclidean/PerpBisector.lean b/Mathlib/Geometry/Euclidean/PerpBisector.lean index 00730a11e550c..b2d97cbe87082 100644 --- a/Mathlib/Geometry/Euclidean/PerpBisector.lean +++ b/Mathlib/Geometry/Euclidean/PerpBisector.lean @@ -29,7 +29,7 @@ noncomputable section namespace AffineSubspace -variable {c c₁ c₂ p₁ p₂ : P} +variable {c p₁ p₂ : P} /-- Perpendicular bisector of a segment in a Euclidean affine space. -/ def perpBisector (p₁ p₂ : P) : AffineSubspace ℝ P := diff --git a/Mathlib/Geometry/Euclidean/Sphere/Basic.lean b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean index 6c5067aad4c23..c4e42b8477423 100644 --- a/Mathlib/Geometry/Euclidean/Sphere/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean @@ -157,7 +157,7 @@ theorem Cospherical.subset {ps₁ ps₂ : Set P} (hs : ps₁ ⊆ ps₂) (hc : Co /-- The empty set is cospherical. -/ theorem cospherical_empty [Nonempty P] : Cospherical (∅ : Set P) := let ⟨p⟩ := ‹Nonempty P› - ⟨p, 0, fun p => False.elim⟩ + ⟨p, 0, fun _ => False.elim⟩ /-- A single point is cospherical. -/ theorem cospherical_singleton (p : P) : Cospherical ({p} : Set P) := by diff --git a/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean b/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean index 5e70b3f083574..5a4202667a015 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean @@ -65,8 +65,7 @@ instance : LinearMapClass (LeftInvariantDerivation I G) 𝕜 C^∞⟮I, G; 𝕜 map_add f := map_add f.1 map_smulₛₗ f := map_smul f.1.1 -variable {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {x : M} {r : 𝕜} - {X Y : LeftInvariantDerivation I G} {f f' : C^∞⟮I, G; 𝕜⟯} +variable {r : 𝕜} {X Y : LeftInvariantDerivation I G} {f f' : C^∞⟮I, G; 𝕜⟯} theorem toFun_eq_coe : X.toFun = ⇑X := rfl diff --git a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean index 8bec2b7fa5b4f..c054be8efa60b 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean @@ -79,13 +79,10 @@ class LieGroup {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [Topolo section PointwiseDivision variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalSpace H] {E : Type*} - [NormedAddCommGroup E] [NormedSpace 𝕜 E] {I : ModelWithCorners 𝕜 E H} {F : Type*} - [NormedAddCommGroup F] [NormedSpace 𝕜 F] {J : ModelWithCorners 𝕜 F F} {G : Type*} + [NormedAddCommGroup E] [NormedSpace 𝕜 E] {I : ModelWithCorners 𝕜 E H} {G : Type*} [TopologicalSpace G] [ChartedSpace H G] [Group G] [LieGroup I G] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M : Type*} [TopologicalSpace M] [ChartedSpace H' M] - {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] - {I'' : ModelWithCorners 𝕜 E'' H''} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H'' M'] {n : ℕ∞} section @@ -236,7 +233,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalS [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] - {n : ℕ∞} {f g : M → G} + {n : ℕ∞} {f : M → G} theorem smoothAt_inv₀ {x : G} (hx : x ≠ 0) : SmoothAt I I (fun y ↦ y⁻¹) x := SmoothInv₀.smoothAt_inv₀ hx diff --git a/Mathlib/Geometry/Manifold/AnalyticManifold.lean b/Mathlib/Geometry/Manifold/AnalyticManifold.lean index 8ef606a4540a1..9a1ab30e1daa9 100644 --- a/Mathlib/Geometry/Manifold/AnalyticManifold.lean +++ b/Mathlib/Geometry/Manifold/AnalyticManifold.lean @@ -29,7 +29,7 @@ open scoped Manifold Filter Topology variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} - [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] + [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] /-! ## `analyticGroupoid` @@ -41,6 +41,7 @@ analytic on the interior, and map the interior to itself. This allows us to def section analyticGroupoid +variable (I) in /-- Given a model with corners `(E, H)`, we define the pregroupoid of analytic transformations of `H` as the maps that are `AnalyticOn` when read in `E` through `I`. Using `AnalyticOn` rather than `AnalyticOnNhd` gives us meaningful definitions at boundary points. -/ @@ -74,6 +75,7 @@ def analyticPregroupoid : Pregroupoid H where simp only [mfld_simps, ← hx] at hy1 ⊢ rw [fg _ hy1] +variable (I) in /-- Given a model with corners `(E, H)`, we define the groupoid of analytic transformations of `H` as the maps that are `AnalyticOn` when read in `E` through `I`. Using `AnalyticOn` rather than `AnalyticOnNhd` gives us meaningful definitions at boundary points. -/ @@ -95,7 +97,7 @@ theorem symm_trans_mem_analyticGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ analyticGroupoid I := haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := PartialHomeomorph.symm_trans_self _ - StructureGroupoid.mem_of_eqOnSource _ (ofSet_mem_analyticGroupoid I e.open_target) this + StructureGroupoid.mem_of_eqOnSource _ (ofSet_mem_analyticGroupoid e.open_target) this /-- The analytic groupoid is closed under restriction. -/ instance : ClosedUnderRestriction (analyticGroupoid I) := @@ -103,7 +105,7 @@ instance : ClosedUnderRestriction (analyticGroupoid I) := (by rw [StructureGroupoid.le_iff] rintro e ⟨s, hs, hes⟩ - exact (analyticGroupoid I).mem_of_eqOnSource' _ _ (ofSet_mem_analyticGroupoid I hs) hes) + exact (analyticGroupoid I).mem_of_eqOnSource' _ _ (ofSet_mem_analyticGroupoid hs) hes) /-- `f ∈ analyticGroupoid` iff it and its inverse are analytic within `range I`. -/ lemma mem_analyticGroupoid {I : ModelWithCorners 𝕜 E H} {f : PartialHomeomorph H H} : diff --git a/Mathlib/Geometry/Manifold/BumpFunction.lean b/Mathlib/Geometry/Manifold/BumpFunction.lean index 16f7d52a36180..fa6698b53773a 100644 --- a/Mathlib/Geometry/Manifold/BumpFunction.lean +++ b/Mathlib/Geometry/Manifold/BumpFunction.lean @@ -95,7 +95,7 @@ theorem ball_inter_range_eq_ball_inter_target : ball (extChartAt I c c) f.rOut ∩ range I = ball (extChartAt I c c) f.rOut ∩ (extChartAt I c).target := (subset_inter inter_subset_left f.ball_subset).antisymm <| inter_subset_inter_right _ <| - extChartAt_target_subset_range _ _ + extChartAt_target_subset_range _ section FiniteDimensional @@ -120,7 +120,7 @@ theorem support_eq_inter_preimage : theorem isOpen_support : IsOpen (support f) := by rw [support_eq_inter_preimage] - exact isOpen_extChartAt_preimage I c isOpen_ball + exact isOpen_extChartAt_preimage c isOpen_ball theorem support_eq_symm_image : support f = (extChartAt I c).symm '' (ball (extChartAt I c c) f.rOut ∩ range I) := by @@ -157,7 +157,7 @@ theorem le_one : f x ≤ 1 := theorem eventuallyEq_one_of_dist_lt (hs : x ∈ (chartAt H c).source) (hd : dist (extChartAt I c x) (extChartAt I c c) < f.rIn) : f =ᶠ[𝓝 x] 1 := by - filter_upwards [IsOpen.mem_nhds (isOpen_extChartAt_preimage I c isOpen_ball) ⟨hs, hd⟩] + filter_upwards [IsOpen.mem_nhds (isOpen_extChartAt_preimage c isOpen_ball) ⟨hs, hd⟩] rintro z ⟨hzs, hzd⟩ exact f.one_of_dist_le hzs <| le_of_lt hzd @@ -183,7 +183,7 @@ theorem nonempty_support : (support f).Nonempty := theorem isCompact_symm_image_closedBall : IsCompact ((extChartAt I c).symm '' (closedBall (extChartAt I c c) f.rOut ∩ range I)) := ((isCompact_closedBall _ _).inter_right I.isClosed_range).image_of_continuousOn <| - (continuousOn_extChartAt_symm _ _).mono f.closedBall_subset + (continuousOn_extChartAt_symm _).mono f.closedBall_subset end FiniteDimensional @@ -194,7 +194,7 @@ theorem nhdsWithin_range_basis : (𝓝[range I] extChartAt I c c).HasBasis (fun _ : SmoothBumpFunction I c => True) fun f => closedBall (extChartAt I c c) f.rOut ∩ range I := by refine ((nhdsWithin_hasBasis nhds_basis_closedBall _).restrict_subset - (extChartAt_target_mem_nhdsWithin _ _)).to_hasBasis' ?_ ?_ + (extChartAt_target_mem_nhdsWithin _)).to_hasBasis' ?_ ?_ · rintro R ⟨hR0, hsub⟩ exact ⟨⟨⟨R / 2, R, half_pos hR0, half_lt_self hR0⟩, hsub⟩, trivial, Subset.rfl⟩ · exact fun f _ => inter_mem (mem_nhdsWithin_of_mem_nhds <| closedBall_mem_nhds _ f.rOut_pos) @@ -206,7 +206,7 @@ theorem isClosed_image_of_isClosed {s : Set M} (hsc : IsClosed s) (hs : s ⊆ su IsClosed (extChartAt I c '' s) := by rw [f.image_eq_inter_preimage_of_subset_support hs] refine ContinuousOn.preimage_isClosed_of_isClosed - ((continuousOn_extChartAt_symm _ _).mono f.closedBall_subset) ?_ hsc + ((continuousOn_extChartAt_symm _).mono f.closedBall_subset) ?_ hsc exact IsClosed.inter isClosed_ball I.isClosed_range /-- If `f` is a smooth bump function and `s` closed subset of the support of `f` (i.e., of the open @@ -260,8 +260,6 @@ protected theorem hasCompactSupport : HasCompactSupport f := f.isCompact_symm_image_closedBall.of_isClosed_subset isClosed_closure f.tsupport_subset_symm_image_closedBall -variable (I) - variable (c) in /-- The closures of supports of smooth bump functions centered at `c` form a basis of `𝓝 c`. In other words, each of these closures is a neighborhood of `c` and each neighborhood of `c` @@ -271,7 +269,7 @@ theorem nhds_basis_tsupport : have : (𝓝 c).HasBasis (fun _ : SmoothBumpFunction I c => True) fun f => (extChartAt I c).symm '' (closedBall (extChartAt I c c) f.rOut ∩ range I) := by - rw [← map_extChartAt_symm_nhdsWithin_range I c] + rw [← map_extChartAt_symm_nhdsWithin_range (I := I) c] exact nhdsWithin_range_basis.map _ exact this.to_hasBasis' (fun f _ => ⟨f, trivial, f.tsupport_subset_symm_image_closedBall⟩) fun f _ => f.tsupport_mem_nhds @@ -282,10 +280,10 @@ neighborhood of `c` and each neighborhood of `c` includes `support f` for some `f : SmoothBumpFunction I c` such that `tsupport f ⊆ s`. -/ theorem nhds_basis_support {s : Set M} (hs : s ∈ 𝓝 c) : (𝓝 c).HasBasis (fun f : SmoothBumpFunction I c => tsupport f ⊆ s) fun f => support f := - ((nhds_basis_tsupport I c).restrict_subset hs).to_hasBasis' + ((nhds_basis_tsupport c).restrict_subset hs).to_hasBasis' (fun f hf => ⟨f, hf.2, subset_closure⟩) fun f _ => f.support_mem_nhds -variable [SmoothManifoldWithCorners I M] {I} +variable [SmoothManifoldWithCorners I M] /-- A smooth bump function is infinitely smooth. -/ protected theorem smooth : Smooth I 𝓘(ℝ) f := by diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index d62d89afae12c..006514be87487 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -366,7 +366,7 @@ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where apply e.continuousOn_toFun.isOpen_inter_preimage e.open_source e'.open_source · apply PG.comp he'.2 he.2 e'.open_target e.open_target apply e'.continuousOn_invFun.isOpen_inter_preimage e'.open_target e.open_target - symm' e he := ⟨he.2, he.1⟩ + symm' _ he := ⟨he.2, he.1⟩ id_mem' := ⟨PG.id_mem, PG.id_mem⟩ locality' e he := by constructor @@ -445,7 +445,7 @@ instance : CompleteLattice (StructureGroupoid H) := top := instStructureGroupoidOrderTop.top le_top := instStructureGroupoidOrderTop.le_top inf := (· ⊓ ·) - le_inf := fun N₁ N₂ N₃ h₁₂ h₁₃ m hm ↦ ⟨h₁₂ hm, h₁₃ hm⟩ + le_inf := fun _ _ _ h₁₂ h₁₃ _ hm ↦ ⟨h₁₂ hm, h₁₃ hm⟩ inf_le_left := fun _ _ _ ↦ And.left inf_le_right := fun _ _ _ ↦ And.right } @@ -758,9 +758,8 @@ section variable {ι : Type*} {Hi : ι → Type*} --- Porting note: Old proof was `Pi.inhabited _`. instance modelPiInhabited [∀ i, Inhabited (Hi i)] : Inhabited (ModelPi Hi) := - ⟨fun _ ↦ default⟩ + Pi.instInhabited instance [∀ i, TopologicalSpace (Hi i)] : TopologicalSpace (ModelPi Hi) := Pi.topologicalSpace @@ -1050,7 +1049,7 @@ variable (e : PartialHomeomorph α H) /-- If a single partial homeomorphism `e` from a space `α` into `H` has source covering the whole space `α`, then that partial homeomorphism induces an `H`-charted space structure on `α`. (This condition is equivalent to `e` being an open embedding of `α` into `H`; see -`OpenEmbedding.singletonChartedSpace`.) -/ +`IsOpenEmbedding.singletonChartedSpace`.) -/ def singletonChartedSpace (h : e.source = Set.univ) : ChartedSpace H α where atlas := {e} chartAt _ := e @@ -1086,24 +1085,24 @@ theorem singleton_hasGroupoid (h : e.source = Set.univ) (G : StructureGroupoid H end PartialHomeomorph -namespace OpenEmbedding +namespace IsOpenEmbedding variable [Nonempty α] /-- An open embedding of `α` into `H` induces an `H`-charted space structure on `α`. See `PartialHomeomorph.singletonChartedSpace`. -/ -def singletonChartedSpace {f : α → H} (h : OpenEmbedding f) : ChartedSpace H α := +def singletonChartedSpace {f : α → H} (h : IsOpenEmbedding f) : ChartedSpace H α := (h.toPartialHomeomorph f).singletonChartedSpace (toPartialHomeomorph_source _ _) -theorem singletonChartedSpace_chartAt_eq {f : α → H} (h : OpenEmbedding f) {x : α} : +theorem singletonChartedSpace_chartAt_eq {f : α → H} (h : IsOpenEmbedding f) {x : α} : ⇑(@chartAt H _ α _ h.singletonChartedSpace x) = f := rfl -theorem singleton_hasGroupoid {f : α → H} (h : OpenEmbedding f) (G : StructureGroupoid H) +theorem singleton_hasGroupoid {f : α → H} (h : IsOpenEmbedding f) (G : StructureGroupoid H) [ClosedUnderRestriction G] : @HasGroupoid _ _ _ _ h.singletonChartedSpace G := (h.toPartialHomeomorph f).singleton_hasGroupoid (toPartialHomeomorph_source _ _) G -end OpenEmbedding +end IsOpenEmbedding end Singleton diff --git a/Mathlib/Geometry/Manifold/Complex.lean b/Mathlib/Geometry/Manifold/Complex.lean index a0110600277bb..4d7fa4e80bc64 100644 --- a/Mathlib/Geometry/Manifold/Complex.lean +++ b/Mathlib/Geometry/Manifold/Complex.lean @@ -55,10 +55,10 @@ theorem Complex.norm_eventually_eq_of_mdifferentiableAt_of_isLocalMax {f : M → have hI : range I = univ := ModelWithCorners.Boundaryless.range_eq_univ have H₁ : 𝓝[range I] (e c) = 𝓝 (e c) := by rw [hI, nhdsWithin_univ] have H₂ : map e.symm (𝓝 (e c)) = 𝓝 c := by - rw [← map_extChartAt_symm_nhdsWithin_range I c, H₁] + rw [← map_extChartAt_symm_nhdsWithin_range (I := I) c, H₁] rw [← H₂, eventually_map] replace hd : ∀ᶠ y in 𝓝 (e c), DifferentiableAt ℂ (f ∘ e.symm) y := by - have : e.target ∈ 𝓝 (e c) := H₁ ▸ extChartAt_target_mem_nhdsWithin I c + have : e.target ∈ 𝓝 (e c) := H₁ ▸ extChartAt_target_mem_nhdsWithin c filter_upwards [this, Tendsto.eventually H₂.le hd] with y hyt hy₂ have hys : e.symm y ∈ (chartAt H c).source := by rw [← extChartAt_source I c] @@ -68,7 +68,7 @@ theorem Complex.norm_eventually_eq_of_mdifferentiableAt_of_isLocalMax {f : M → e.right_inv hyt] at hy₂ exact hy₂.2 convert norm_eventually_eq_of_isLocalMax hd _ - · exact congr_arg f (extChartAt_to_inv _ _).symm + · exact congr_arg f (extChartAt_to_inv _).symm · simpa only [e, IsLocalMax, IsMaxFilter, ← H₂, (· ∘ ·), extChartAt_to_inv] using hc /-! @@ -90,7 +90,7 @@ theorem norm_eqOn_of_isPreconnected_of_isMaxOn {f : M → F} {U : Set M} {c : M} replace hm : IsLocalMax (‖f ·‖) x := mem_of_superset (ho.mem_nhds hx.1) fun z hz ↦ (hm hz).out.trans_eq hx.2.symm replace hd : ∀ᶠ y in 𝓝 x, MDifferentiableAt I 𝓘(ℂ, F) f y := - (eventually_mem_nhds.2 (ho.mem_nhds hx.1)).mono fun z ↦ hd.mdifferentiableAt + (eventually_mem_nhds_iff.2 (ho.mem_nhds hx.1)).mono fun z ↦ hd.mdifferentiableAt exact (Complex.norm_eventually_eq_of_mdifferentiableAt_of_isLocalMax hd hm).mono fun _ ↦ (Eq.trans · hx.2) have hVne : (U ∩ V).Nonempty := ⟨c, hcU, hcU, rfl⟩ diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean index 61057854d30c6..7ef289e5099f9 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean @@ -21,13 +21,10 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M] - -- declare a smooth manifold `M'` over the pair `(E', H')`. - {E' : Type*} - [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] - [SmoothManifoldWithCorners I' M'] + -- declare a topological space `M'`. + {M' : Type*} [TopologicalSpace M'] -- declare functions, sets, points and smoothness indices - {e : PartialHomeomorph M H} {x : M} {m n : ℕ∞} + {e : PartialHomeomorph M H} {x : M} {n : ℕ∞} /-! ### Atlas members are smooth -/ @@ -35,7 +32,7 @@ section Atlas theorem contMDiff_model : ContMDiff I 𝓘(𝕜, E) n I := by intro x - refine (contMDiffAt_iff _ _).mpr ⟨I.continuousAt, ?_⟩ + refine contMDiffAt_iff.mpr ⟨I.continuousAt, ?_⟩ simp only [mfld_simps] refine contDiffWithinAt_id.congr_of_eventuallyEq ?_ ?_ · exact Filter.eventuallyEq_of_mem self_mem_nhdsWithin fun x₂ => I.right_inv @@ -50,16 +47,16 @@ theorem contMDiffOn_model_symm : ContMDiffOn 𝓘(𝕜, E) I n I.symm (range I) /-- An atlas member is `C^n` for any `n`. -/ theorem contMDiffOn_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) : ContMDiffOn I I n e e.source := ContMDiffOn.of_le - ((contDiffWithinAt_localInvariantProp I I ∞).liftPropOn_of_mem_maximalAtlas - (contDiffWithinAtProp_id I) h) + ((contDiffWithinAt_localInvariantProp ∞).liftPropOn_of_mem_maximalAtlas + contDiffWithinAtProp_id h) le_top /-- The inverse of an atlas member is `C^n` for any `n`. -/ theorem contMDiffOn_symm_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) : ContMDiffOn I I n e.symm e.target := ContMDiffOn.of_le - ((contDiffWithinAt_localInvariantProp I I ∞).liftPropOn_symm_of_mem_maximalAtlas - (contDiffWithinAtProp_id I) h) + ((contDiffWithinAt_localInvariantProp ∞).liftPropOn_symm_of_mem_maximalAtlas + contDiffWithinAtProp_id h) le_top theorem contMDiffAt_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) (hx : x ∈ e.source) : @@ -71,10 +68,10 @@ theorem contMDiffAt_symm_of_mem_maximalAtlas {x : H} (h : e ∈ maximalAtlas I M (contMDiffOn_symm_of_mem_maximalAtlas h).contMDiffAt <| e.open_target.mem_nhds hx theorem contMDiffOn_chart : ContMDiffOn I I n (chartAt H x) (chartAt H x).source := - contMDiffOn_of_mem_maximalAtlas <| chart_mem_maximalAtlas I x + contMDiffOn_of_mem_maximalAtlas <| chart_mem_maximalAtlas x theorem contMDiffOn_chart_symm : ContMDiffOn I I n (chartAt H x).symm (chartAt H x).target := - contMDiffOn_symm_of_mem_maximalAtlas <| chart_mem_maximalAtlas I x + contMDiffOn_symm_of_mem_maximalAtlas <| chart_mem_maximalAtlas x theorem contMDiffAt_extend {x : M} (he : e ∈ maximalAtlas I M) (hx : x ∈ e.source) : ContMDiffAt I 𝓘(𝕜, E) n (e.extend I) x := @@ -82,7 +79,7 @@ theorem contMDiffAt_extend {x : M} (he : e ∈ maximalAtlas I M) (hx : x ∈ e.s theorem contMDiffAt_extChartAt' {x' : M} (h : x' ∈ (chartAt H x).source) : ContMDiffAt I 𝓘(𝕜, E) n (extChartAt I x) x' := - contMDiffAt_extend (chart_mem_maximalAtlas I x) h + contMDiffAt_extend (chart_mem_maximalAtlas x) h theorem contMDiffAt_extChartAt : ContMDiffAt I 𝓘(𝕜, E) n (extChartAt I x) x := contMDiffAt_extChartAt' <| mem_chart_source H x @@ -99,14 +96,13 @@ theorem contMDiffOn_extend_symm (he : e ∈ maximalAtlas I M) : theorem contMDiffOn_extChartAt_symm (x : M) : ContMDiffOn 𝓘(𝕜, E) I n (extChartAt I x).symm (extChartAt I x).target := by - convert contMDiffOn_extend_symm (chart_mem_maximalAtlas I x) + convert contMDiffOn_extend_symm (chart_mem_maximalAtlas (I := I) x) rw [extChartAt_target, I.image_eq] /-- An element of `contDiffGroupoid ⊤ I` is `C^n` for any `n`. -/ theorem contMDiffOn_of_mem_contDiffGroupoid {e' : PartialHomeomorph H H} (h : e' ∈ contDiffGroupoid ⊤ I) : ContMDiffOn I I n e' e'.source := - (contDiffWithinAt_localInvariantProp I I n).liftPropOn_of_mem_groupoid - (contDiffWithinAtProp_id I) h + (contDiffWithinAt_localInvariantProp n).liftPropOn_of_mem_groupoid contDiffWithinAtProp_id h end Atlas diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean index c8a972fc9462a..28e0da5a750fe 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean @@ -13,7 +13,7 @@ In this file, we show that standard operations on smooth maps between smooth man * `contMDiff_id` gives the smoothness of the identity * `contMDiff_const` gives the smoothness of constant functions * `contMDiff_inclusion` shows that the inclusion between open sets of a topological space is smooth -* `contMDiff_openEmbedding` shows that if `M` has a `ChartedSpace` structure induced by an open +* `contMDiff_isOpenEmbedding` shows that if `M` has a `ChartedSpace` structure induced by an open embedding `e : M → H`, then `e` is smooth. ## Tags @@ -28,11 +28,11 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] -- declare the prerequisites for a charted space `M` over the pair `(E, H)`. {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] -- declare the prerequisites for a charted space `M'` over the pair `(E', H')`. {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} [TopologicalSpace M'] + {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] -- declare the prerequisites for a charted space `M''` over the pair `(E'', H'')`. {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] @@ -41,9 +41,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] section ChartedSpace variable [ChartedSpace H M] [ChartedSpace H' M'] [ChartedSpace H'' M''] -- declare functions, sets, points and smoothness indices - {e : PartialHomeomorph M H} - {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} -variable {I I'} + {f : M → M'} {s : Set M} {x : M} {n : ℕ∞} /-! ### Smoothness of the composition of smooth functions between manifolds -/ @@ -61,12 +59,13 @@ theorem ContMDiffWithinAt.comp {t : Set M'} {g : M' → M''} (x : M) rw [this] at hg have A : ∀ᶠ y in 𝓝[e.symm ⁻¹' s ∩ range I] e x, f (e.symm y) ∈ t ∧ f (e.symm y) ∈ e'.source := by simp only [e, ← map_extChartAt_nhdsWithin, eventually_map] - filter_upwards [hf.1.tendsto (extChartAt_source_mem_nhds I' (f x)), - inter_mem_nhdsWithin s (extChartAt_source_mem_nhds I x)] + filter_upwards [hf.1.tendsto (extChartAt_source_mem_nhds (I := I') (f x)), + inter_mem_nhdsWithin s (extChartAt_source_mem_nhds (I := I) x)] rintro x' (hfx' : f x' ∈ e'.source) ⟨hx's, hx'⟩ simp only [e.map_source hx', true_and, e.left_inv hx', st hx's, *] - refine ((hg.2.comp _ (hf.2.mono inter_subset_right) inter_subset_left).mono_of_mem - (inter_mem ?_ self_mem_nhdsWithin)).congr_of_eventuallyEq ?_ ?_ + refine ((hg.2.comp _ (hf.2.mono inter_subset_right) + ((mapsTo_preimage _ _).mono_left inter_subset_left)).mono_of_mem_nhdsWithin + (inter_mem ?_ self_mem_nhdsWithin)).congr_of_eventuallyEq ?_ ?_ · filter_upwards [A] rintro x' ⟨ht, hfx'⟩ simp only [*, mem_preimage, writtenInExtChartAt, (· ∘ ·), mem_inter_iff, e'.left_inv, @@ -184,7 +183,7 @@ section id theorem contMDiff_id : ContMDiff I I n (id : M → M) := ContMDiff.of_le - ((contDiffWithinAt_localInvariantProp I I ∞).liftProp_id (contDiffWithinAtProp_id I)) le_top + ((contDiffWithinAt_localInvariantProp ∞).liftProp_id contDiffWithinAtProp_id) le_top theorem smooth_id : Smooth I I (id : M → M) := contMDiff_id @@ -310,7 +309,7 @@ open TopologicalSpace theorem contMdiffAt_subtype_iff {n : ℕ∞} {U : Opens M} {f : M → M'} {x : U} : ContMDiffAt I I' n (fun x : U ↦ f x) x ↔ ContMDiffAt I I' n f x := - ((contDiffWithinAt_localInvariantProp I I' n).liftPropAt_iff_comp_subtype_val _ _).symm + ((contDiffWithinAt_localInvariantProp n).liftPropAt_iff_comp_subtype_val _ _).symm theorem contMDiff_subtype_val {n : ℕ∞} {U : Opens M} : ContMDiff I I n (Subtype.val : U → M) := fun _ ↦ contMdiffAt_subtype_iff.mpr contMDiffAt_id @@ -324,13 +323,13 @@ theorem ContMDiff.extend_one [T2Space M] [One M'] {n : ℕ∞} {U : Opens M} {f (supp.mulTSupport_extend_one_subset continuous_subtype_val h) rw [← contMdiffAt_subtype_iff] simp_rw [← comp_def] - erw [extend_comp Subtype.val_injective] + rw [extend_comp Subtype.val_injective] exact diff.contMDiffAt theorem contMDiff_inclusion {n : ℕ∞} {U V : Opens M} (h : U ≤ V) : ContMDiff I I n (Opens.inclusion h : U → V) := by rintro ⟨x, hx : x ∈ U⟩ - apply (contDiffWithinAt_localInvariantProp I I n).liftProp_inclusion + apply (contDiffWithinAt_localInvariantProp n).liftProp_inclusion intro y dsimp only [ContDiffWithinAtProp, id_comp, preimage_univ] rw [Set.univ_inter] @@ -358,13 +357,13 @@ end ChartedSpace section -variable {e : M → H} (h : OpenEmbedding e) {n : WithTop ℕ} +variable {e : M → H} (h : IsOpenEmbedding e) {n : WithTop ℕ} /-- If the `ChartedSpace` structure on a manifold `M` is given by an open embedding `e : M → H`, then `e` is smooth. -/ -lemma contMDiff_openEmbedding [Nonempty M] : +lemma contMDiff_isOpenEmbedding [Nonempty M] : haveI := h.singletonChartedSpace; ContMDiff I I n e := by - haveI := h.singleton_smoothManifoldWithCorners I + haveI := h.singleton_smoothManifoldWithCorners (I := I) rw [@contMDiff_iff _ _ _ _ _ _ _ _ _ _ h.singletonChartedSpace] use h.continuous intros x y @@ -376,7 +375,7 @@ lemma contMDiff_openEmbedding [Nonempty M] : rw [h.toPartialHomeomorph_right_inv] · rw [I.right_inv] apply mem_of_subset_of_mem _ hz.1 - exact haveI := h.singletonChartedSpace; extChartAt_target_subset_range I x + exact haveI := h.singletonChartedSpace; extChartAt_target_subset_range (I := I) x · -- `hz` implies that `z ∈ range (I ∘ e)` have := hz.1 rw [@extChartAt_target _ _ _ _ _ _ _ _ _ _ h.singletonChartedSpace] at this @@ -385,13 +384,15 @@ lemma contMDiff_openEmbedding [Nonempty M] : h.toPartialHomeomorph_target] at this exact this -variable {I I'} +@[deprecated (since := "2024-10-18")] +alias contMDiff_openEmbedding := contMDiff_isOpenEmbedding + /-- If the `ChartedSpace` structure on a manifold `M` is given by an open embedding `e : M → H`, then the inverse of `e` is smooth. -/ -lemma contMDiffOn_openEmbedding_symm [Nonempty M] : +lemma contMDiffOn_isOpenEmbedding_symm [Nonempty M] : haveI := h.singletonChartedSpace; ContMDiffOn I I - n (OpenEmbedding.toPartialHomeomorph e h).symm (range e) := by - haveI := h.singleton_smoothManifoldWithCorners I + n (IsOpenEmbedding.toPartialHomeomorph e h).symm (range e) := by + haveI := h.singleton_smoothManifoldWithCorners (I := I) rw [@contMDiffOn_iff] constructor · rw [← h.toPartialHomeomorph_target] @@ -407,23 +408,29 @@ lemma contMDiffOn_openEmbedding_symm [Nonempty M] : exact hz.2.1 rw [h.toPartialHomeomorph_right_inv e this] apply I.right_inv - exact mem_of_subset_of_mem (extChartAt_target_subset_range _ _) hz.1 + exact mem_of_subset_of_mem (extChartAt_target_subset_range _) hz.1 + +@[deprecated (since := "2024-10-18")] +alias contMDiffOn_openEmbedding_symm := contMDiffOn_isOpenEmbedding_symm variable [ChartedSpace H M] -variable [Nonempty M'] {e' : M' → H'} (h' : OpenEmbedding e') +variable [Nonempty M'] {e' : M' → H'} (h' : IsOpenEmbedding e') /-- Let `M'` be a manifold whose chart structure is given by an open embedding `e'` into its model space `H'`. Then the smoothness of `e' ∘ f : M → H'` implies the smoothness of `f`. This is useful, for example, when `e' ∘ f = g ∘ e` for smooth maps `e : M → X` and `g : X → H'`. -/ -lemma ContMDiff.of_comp_openEmbedding {f : M → M'} (hf : ContMDiff I I' n (e' ∘ f)) : +lemma ContMDiff.of_comp_isOpenEmbedding {f : M → M'} (hf : ContMDiff I I' n (e' ∘ f)) : haveI := h'.singletonChartedSpace; ContMDiff I I' n f := by have : f = (h'.toPartialHomeomorph e').symm ∘ e' ∘ f := by ext - rw [Function.comp_apply, Function.comp_apply, OpenEmbedding.toPartialHomeomorph_left_inv] + rw [Function.comp_apply, Function.comp_apply, IsOpenEmbedding.toPartialHomeomorph_left_inv] rw [this] apply @ContMDiffOn.comp_contMDiff _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - h'.singletonChartedSpace _ _ (range e') _ (contMDiffOn_openEmbedding_symm h') hf + h'.singletonChartedSpace _ _ (range e') _ (contMDiffOn_isOpenEmbedding_symm h') hf simp +@[deprecated (since := "2024-10-18")] +alias ContMDiff.of_comp_openEmbedding := ContMDiff.of_comp_isOpenEmbedding + end diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index 3028f6318c3cd..2a6b38187494f 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -55,34 +55,20 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] -- Prerequisite typeclasses to say that `M` is a smooth manifold over the pair `(E, H)` {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] -- Prerequisite typeclasses to say that `M'` is a smooth manifold over the pair `(E', H')` {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] -- Prerequisite typeclasses to say that `M''` is a smooth manifold over the pair `(E'', H'')` {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] - -- declare a smooth manifold `N` over the pair `(F, G)`. - {F : Type*} - [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] - {J : ModelWithCorners 𝕜 F G} {N : Type*} [TopologicalSpace N] [ChartedSpace G N] - [SmoothManifoldWithCorners J N] - -- declare a smooth manifold `N'` over the pair `(F', G')`. - {F' : Type*} - [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {G' : Type*} [TopologicalSpace G'] - {J' : ModelWithCorners 𝕜 F' G'} {N' : Type*} [TopologicalSpace N'] [ChartedSpace G' N'] - [SmoothManifoldWithCorners J' N'] - -- F₁, F₂, F₃, F₄ are normed spaces - {F₁ : Type*} - [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] {F₂ : Type*} [NormedAddCommGroup F₂] - [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} - [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices {e : PartialHomeomorph M H} {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} +variable (I I') in /-- Property in the model space of a model with corners of being `C^n` within at set at a point, when read in the model vector space. This property will be lifted to manifolds to define smooth functions between manifolds. -/ @@ -96,7 +82,7 @@ theorem contDiffWithinAtProp_self_source {f : E → H'} {s : Set E} {x : E} : theorem contDiffWithinAtProp_self {f : E → E'} {s : Set E} {x : E} : ContDiffWithinAtProp 𝓘(𝕜, E) 𝓘(𝕜, E') n f s x ↔ ContDiffWithinAt 𝕜 n f s x := - contDiffWithinAtProp_self_source 𝓘(𝕜, E') + contDiffWithinAtProp_self_source theorem contDiffWithinAtProp_self_target {f : H → E'} {s : Set H} {x : H} : ContDiffWithinAtProp I 𝓘(𝕜, E') n f s x ↔ @@ -124,7 +110,7 @@ theorem contDiffWithinAt_localInvariantProp (n : ℕ∞) : rw [this] at h have : I (e x) ∈ I.symm ⁻¹' e.target ∩ range I := by simp only [hx, mfld_simps] have := (mem_groupoid_of_pregroupoid.2 he).2.contDiffWithinAt this - convert (h.comp' _ (this.of_le le_top)).mono_of_mem _ using 1 + convert (h.comp_inter _ (this.of_le le_top)).mono_of_mem_nhdsWithin _ using 1 · ext y; simp only [mfld_simps] refine mem_nhdsWithin.mpr ⟨I.symm ⁻¹' e.target, e.open_target.preimage I.continuous_symm, by @@ -147,7 +133,7 @@ theorem contDiffWithinAt_localInvariantProp (n : ℕ∞) : theorem contDiffWithinAtProp_mono_of_mem (n : ℕ∞) ⦃s x t⦄ ⦃f : H → H'⦄ (hts : s ∈ 𝓝[t] x) (h : ContDiffWithinAtProp I I' n f s x) : ContDiffWithinAtProp I I' n f t x := by - refine h.mono_of_mem ?_ + refine h.mono_of_mem_nhdsWithin ?_ refine inter_mem ?_ (mem_of_superset self_mem_nhdsWithin inter_subset_right) rwa [← Filter.mem_map, ← I.image_eq, I.symm_map_nhdsWithin_image] @@ -158,17 +144,20 @@ theorem contDiffWithinAtProp_id (x : H) : ContDiffWithinAtProp I I n id univ x : · simp only [ModelWithCorners.right_inv I hy, mfld_simps] · simp only [mfld_simps] +variable (I I') in /-- A function is `n` times continuously differentiable within a set at a point in a manifold if it is continuous and it is `n` times continuously differentiable in this set around this point, when read in the preferred chart at this point. -/ def ContMDiffWithinAt (n : ℕ∞) (f : M → M') (s : Set M) (x : M) := LiftPropWithinAt (ContDiffWithinAtProp I I' n) f s x +variable (I I') in /-- Abbreviation for `ContMDiffWithinAt I I' ⊤ f s x`. See also documentation for `Smooth`. -/ abbrev SmoothWithinAt (f : M → M') (s : Set M) (x : M) := ContMDiffWithinAt I I' ⊤ f s x +variable (I I') in /-- A function is `n` times continuously differentiable at a point in a manifold if it is continuous and it is `n` times continuously differentiable around this point, when read in the preferred chart at this point. -/ @@ -182,26 +171,31 @@ theorem contMDiffAt_iff {n : ℕ∞} {f : M → M'} {x : M} : (extChartAt I x x) := liftPropAt_iff.trans <| by rw [ContDiffWithinAtProp, preimage_univ, univ_inter]; rfl +variable (I I') in /-- Abbreviation for `ContMDiffAt I I' ⊤ f x`. See also documentation for `Smooth`. -/ abbrev SmoothAt (f : M → M') (x : M) := ContMDiffAt I I' ⊤ f x +variable (I I') in /-- A function is `n` times continuously differentiable in a set of a manifold if it is continuous and, for any pair of points, it is `n` times continuously differentiable on this set in the charts around these points. -/ def ContMDiffOn (n : ℕ∞) (f : M → M') (s : Set M) := ∀ x ∈ s, ContMDiffWithinAt I I' n f s x +variable (I I') in /-- Abbreviation for `ContMDiffOn I I' ⊤ f s`. See also documentation for `Smooth`. -/ abbrev SmoothOn (f : M → M') (s : Set M) := ContMDiffOn I I' ⊤ f s +variable (I I') in /-- A function is `n` times continuously differentiable in a manifold if it is continuous and, for any pair of points, it is `n` times continuously differentiable in the charts around these points. -/ def ContMDiff (n : ℕ∞) (f : M → M') := ∀ x, ContMDiffAt I I' n f x +variable (I I') in /-- Abbreviation for `ContMDiff I I' ⊤ f`. Short note to work with these abbreviations: a lemma of the form `ContMDiffFoo.bar` will apply fine to an assumption `SmoothFoo` using dot notation or normal notation. @@ -212,8 +206,6 @@ This also applies to `SmoothAt`, `SmoothOn` and `SmoothWithinAt`. -/ abbrev Smooth (f : M → M') := ContMDiff I I' ⊤ f -variable {I I'} - /-! ### Deducing smoothness from higher smoothness -/ theorem ContMDiffWithinAt.of_le (hf : ContMDiffWithinAt I I' n f s x) (le : m ≤ n) : @@ -301,8 +293,8 @@ theorem contMDiffWithinAt_iff' : (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source)) (extChartAt I x x) := by simp only [ContMDiffWithinAt, liftPropWithinAt_iff'] - exact and_congr_right fun hc => contDiffWithinAt_congr_nhds <| - hc.nhdsWithin_extChartAt_symm_preimage_inter_range I I' + exact and_congr_right fun hc => contDiffWithinAt_congr_set <| + hc.extChartAt_symm_preimage_inter_range_eventuallyEq /-- One can reformulate smoothness within a set at a point as continuity within this set at this point, and smoothness in the corresponding extended chart in the target. -/ @@ -313,7 +305,7 @@ theorem contMDiffWithinAt_iff_target : have cont : ContinuousWithinAt f s x ∧ ContinuousWithinAt (extChartAt I' (f x) ∘ f) s x ↔ ContinuousWithinAt f s x := - and_iff_left_of_imp <| (continuousAt_extChartAt _ _).comp_continuousWithinAt + and_iff_left_of_imp <| (continuousAt_extChartAt _).comp_continuousWithinAt simp_rw [cont, ContDiffWithinAtProp, extChartAt, PartialHomeomorph.extend, PartialEquiv.coe_trans, ModelWithCorners.toPartialEquiv_coe, PartialHomeomorph.coe_coe, modelWithCornersSelf_coe, chartAt_self_eq, PartialHomeomorph.refl_apply, id_comp] @@ -347,9 +339,9 @@ theorem contMDiffWithinAt_iff_source_of_mem_maximalAtlas ContMDiffWithinAt I I' n f s x ↔ ContMDiffWithinAt 𝓘(𝕜, E) I' n (f ∘ (e.extend I).symm) ((e.extend I).symm ⁻¹' s ∩ range I) (e.extend I x) := by - have h2x := hx; rw [← e.extend_source I] at h2x + have h2x := hx; rw [← e.extend_source (I := I)] at h2x simp_rw [ContMDiffWithinAt, - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_indep_chart_source he hx, + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_indep_chart_source he hx, StructureGroupoid.liftPropWithinAt_self_source, e.extend_symm_continuousWithinAt_comp_right_iff, contDiffWithinAtProp_self_source, ContDiffWithinAtProp, Function.comp, e.left_inv hx, (e.extend I).left_inv h2x] @@ -360,7 +352,7 @@ theorem contMDiffWithinAt_iff_source_of_mem_source ContMDiffWithinAt I I' n f s x' ↔ ContMDiffWithinAt 𝓘(𝕜, E) I' n (f ∘ (extChartAt I x).symm) ((extChartAt I x).symm ⁻¹' s ∩ range I) (extChartAt I x x') := - contMDiffWithinAt_iff_source_of_mem_maximalAtlas (chart_mem_maximalAtlas I x) hx' + contMDiffWithinAt_iff_source_of_mem_maximalAtlas (chart_mem_maximalAtlas x) hx' theorem contMDiffAt_iff_source_of_mem_source [SmoothManifoldWithCorners I M] {x' : M} (hx' : x' ∈ (chartAt H x).source) : @@ -373,14 +365,14 @@ theorem contMDiffWithinAt_iff_target_of_mem_source ContMDiffWithinAt I I' n f s x ↔ ContinuousWithinAt f s x ∧ ContMDiffWithinAt I 𝓘(𝕜, E') n (extChartAt I' y ∘ f) s x := by simp_rw [ContMDiffWithinAt] - rw [(contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_indep_chart_target - (chart_mem_maximalAtlas I' y) hy, + rw [(contDiffWithinAt_localInvariantProp n).liftPropWithinAt_indep_chart_target + (chart_mem_maximalAtlas y) hy, and_congr_right] intro hf simp_rw [StructureGroupoid.liftPropWithinAt_self_target] simp_rw [((chartAt H' y).continuousAt hy).comp_continuousWithinAt hf] - rw [← extChartAt_source I'] at hy - simp_rw [(continuousAt_extChartAt' I' hy).comp_continuousWithinAt hf] + rw [← extChartAt_source (I := I')] at hy + simp_rw [(continuousAt_extChartAt' hy).comp_continuousWithinAt hf] rfl theorem contMDiffAt_iff_target_of_mem_source @@ -398,7 +390,7 @@ theorem contMDiffWithinAt_iff_of_mem_maximalAtlas {x : M} (he : e ∈ maximalAtl ContinuousWithinAt f s x ∧ ContDiffWithinAt 𝕜 n (e'.extend I' ∘ f ∘ (e.extend I).symm) ((e.extend I).symm ⁻¹' s ∩ range I) (e.extend I x) := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_indep_chart he hx he' hy + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_indep_chart he hx he' hy /-- An alternative formulation of `contMDiffWithinAt_iff_of_mem_maximalAtlas` if the set if `s` lies in `e.source`. -/ @@ -409,8 +401,8 @@ theorem contMDiffWithinAt_iff_image {x : M} (he : e ∈ maximalAtlas I M) ContDiffWithinAt 𝕜 n (e'.extend I' ∘ f ∘ (e.extend I).symm) (e.extend I '' s) (e.extend I x) := by rw [contMDiffWithinAt_iff_of_mem_maximalAtlas he he' hx hy, and_congr_right_iff] - refine fun _ => contDiffWithinAt_congr_nhds ?_ - simp_rw [nhdsWithin_eq_iff_eventuallyEq, e.extend_symm_preimage_inter_range_eventuallyEq I hs hx] + refine fun _ => contDiffWithinAt_congr_set ?_ + simp_rw [e.extend_symm_preimage_inter_range_eventuallyEq hs hx] /-- One can reformulate smoothness within a set at a point as continuity within this set at this point, and smoothness in any chart containing that point. -/ @@ -420,8 +412,8 @@ theorem contMDiffWithinAt_iff_of_mem_source {x' : M} {y : M'} (hx : x' ∈ (char ContinuousWithinAt f s x' ∧ ContDiffWithinAt 𝕜 n (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) ((extChartAt I x).symm ⁻¹' s ∩ range I) (extChartAt I x x') := - contMDiffWithinAt_iff_of_mem_maximalAtlas (chart_mem_maximalAtlas _ x) - (chart_mem_maximalAtlas _ y) hx hy + contMDiffWithinAt_iff_of_mem_maximalAtlas (chart_mem_maximalAtlas x) + (chart_mem_maximalAtlas y) hx hy theorem contMDiffWithinAt_iff_of_mem_source' {x' : M} {y : M'} (hx : x' ∈ (chartAt H x).source) (hy : f x' ∈ (chartAt H' y).source) : @@ -435,10 +427,11 @@ theorem contMDiffWithinAt_iff_of_mem_source' {x' : M} {y : M'} (hx : x' ∈ (cha rw [← extChartAt_source I'] at hy rw [and_congr_right_iff] set e := extChartAt I x; set e' := extChartAt I' (f x) - refine fun hc => contDiffWithinAt_congr_nhds ?_ - rw [← e.image_source_inter_eq', ← map_extChartAt_nhdsWithin_eq_image' I hx, ← - map_extChartAt_nhdsWithin' I hx, inter_comm, nhdsWithin_inter_of_mem] - exact hc (extChartAt_source_mem_nhds' _ hy) + refine fun hc => contDiffWithinAt_congr_set ?_ + rw [← nhdsWithin_eq_iff_eventuallyEq, ← e.image_source_inter_eq', + ← map_extChartAt_nhdsWithin_eq_image' hx, + ← map_extChartAt_nhdsWithin' hx, inter_comm, nhdsWithin_inter_of_mem] + exact hc (extChartAt_source_mem_nhds' hy) theorem contMDiffAt_iff_of_mem_source {x' : M} {y : M'} (hx : x' ∈ (chartAt H x).source) (hy : f x' ∈ (chartAt H' y).source) : @@ -462,7 +455,7 @@ theorem contMDiffOn_iff_of_mem_maximalAtlas' (he : e ∈ maximalAtlas I M) ContMDiffOn I I' n f s ↔ ContDiffOn 𝕜 n (e'.extend I' ∘ f ∘ (e.extend I).symm) (e.extend I '' s) := (contMDiffOn_iff_of_mem_maximalAtlas he he' hs h2s).trans <| and_iff_right_of_imp fun h ↦ - (e.continuousOn_writtenInExtend_iff _ _ hs h2s).1 h.continuousOn + (e.continuousOn_writtenInExtend_iff hs h2s).1 h.continuousOn /-- If the set where you want `f` to be smooth lies entirely in a single chart, and `f` maps it into a single chart, the smoothness of `f` on that set can be expressed by purely looking in @@ -474,7 +467,7 @@ theorem contMDiffOn_iff_of_subset_source {x : M} {y : M'} (hs : s ⊆ (chartAt H ContMDiffOn I I' n f s ↔ ContinuousOn f s ∧ ContDiffOn 𝕜 n (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) (extChartAt I x '' s) := - contMDiffOn_iff_of_mem_maximalAtlas (chart_mem_maximalAtlas I x) (chart_mem_maximalAtlas I' y) hs + contMDiffOn_iff_of_mem_maximalAtlas (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas y) hs h2s /-- If the set where you want `f` to be smooth lies entirely in a single chart, and `f` maps it @@ -487,8 +480,8 @@ theorem contMDiffOn_iff_of_subset_source' {x : M} {y : M'} (hs : s ⊆ (extChart ContMDiffOn I I' n f s ↔ ContDiffOn 𝕜 n (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) (extChartAt I x '' s) := by rw [extChartAt_source] at hs h2s - exact contMDiffOn_iff_of_mem_maximalAtlas' (chart_mem_maximalAtlas I x) - (chart_mem_maximalAtlas I' y) hs h2s + exact contMDiffOn_iff_of_mem_maximalAtlas' (chart_mem_maximalAtlas x) + (chart_mem_maximalAtlas y) hs h2s /-- One can reformulate smoothness on a set as continuity on this set, and smoothness in any extended chart. -/ @@ -512,7 +505,7 @@ theorem contMDiffOn_iff : · simp only [w, hz, mfld_simps] · mfld_set_tac · rintro ⟨hcont, hdiff⟩ x hx - refine (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_iff.mpr ?_ + refine (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_iff.mpr ?_ refine ⟨hcont x hx, ?_⟩ dsimp [ContDiffWithinAtProp] convert hdiff x (f x) (extChartAt I x x) (by simp only [hx, mfld_simps]) using 1 @@ -532,7 +525,7 @@ theorem contMDiffOn_iff_target : constructor · refine fun h' y => ⟨?_, fun x _ => h' x y⟩ have h'' : ContinuousOn _ univ := (ModelWithCorners.continuous I').continuousOn - convert (h''.comp' (chartAt H' y).continuousOn_toFun).comp' h + convert (h''.comp_inter (chartAt H' y).continuousOn_toFun).comp_inter h simp · exact fun h' x y => (h' y).2 x 0 @@ -647,7 +640,7 @@ theorem contMDiffWithinAt_iff_nat : theorem ContMDiffWithinAt.mono_of_mem (hf : ContMDiffWithinAt I I' n f s x) (hts : s ∈ 𝓝[t] x) : ContMDiffWithinAt I I' n f t x := StructureGroupoid.LocalInvariantProp.liftPropWithinAt_mono_of_mem - (contDiffWithinAtProp_mono_of_mem I I' n) hf hts + (contDiffWithinAtProp_mono_of_mem n) hf hts theorem ContMDiffWithinAt.mono (hf : ContMDiffWithinAt I I' n f s x) (hts : t ⊆ s) : ContMDiffWithinAt I I' n f t x := @@ -661,8 +654,9 @@ theorem contMDiffWithinAt_congr_nhds (hst : 𝓝[s] x = 𝓝[t] x) : theorem contMDiffWithinAt_insert_self : ContMDiffWithinAt I I' n f (insert x s) x ↔ ContMDiffWithinAt I I' n f s x := by simp only [contMDiffWithinAt_iff, continuousWithinAt_insert_self] - refine Iff.rfl.and <| (contDiffWithinAt_congr_nhds ?_).trans contDiffWithinAt_insert_self - simp only [← map_extChartAt_nhdsWithin I, nhdsWithin_insert, Filter.map_sup, Filter.map_pure] + refine Iff.rfl.and <| (contDiffWithinAt_congr_set ?_).trans contDiffWithinAt_insert_self + simp only [← map_extChartAt_nhdsWithin, nhdsWithin_insert, Filter.map_sup, Filter.map_pure, + ← nhdsWithin_eq_iff_eventuallyEq] alias ⟨ContMDiffWithinAt.of_insert, _⟩ := contMDiffWithinAt_insert_self @@ -689,15 +683,15 @@ theorem Smooth.smoothOn (hf : Smooth I I' f) : SmoothOn I I' f s := theorem contMDiffWithinAt_inter' (ht : t ∈ 𝓝[s] x) : ContMDiffWithinAt I I' n f (s ∩ t) x ↔ ContMDiffWithinAt I I' n f s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_inter' ht + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_inter' ht theorem contMDiffWithinAt_inter (ht : t ∈ 𝓝 x) : ContMDiffWithinAt I I' n f (s ∩ t) x ↔ ContMDiffWithinAt I I' n f s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_inter ht + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_inter ht theorem ContMDiffWithinAt.contMDiffAt (h : ContMDiffWithinAt I I' n f s x) (ht : s ∈ 𝓝 x) : ContMDiffAt I I' n f x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropAt_of_liftPropWithinAt h ht + (contDiffWithinAt_localInvariantProp n).liftPropAt_of_liftPropWithinAt h ht theorem SmoothWithinAt.smoothAt (h : SmoothWithinAt I I' f s x) (ht : s ∈ 𝓝 x) : SmoothAt I I' f x := @@ -719,7 +713,7 @@ theorem contMDiffOn_iff_source_of_mem_maximalAtlas [SmoothManifoldWithCorners I rw [contMDiffWithinAt_iff_source_of_mem_maximalAtlas he (hs hx)] apply contMDiffWithinAt_congr_nhds simp_rw [nhdsWithin_eq_iff_eventuallyEq, - e.extend_symm_preimage_inter_range_eventuallyEq I hs (hs hx)] + e.extend_symm_preimage_inter_range_eventuallyEq hs (hs hx)] -- Porting note: didn't compile; fixed by golfing the proof and moving parts to lemmas /-- A function is `C^n` within a set at a point, for `n : ℕ`, if and only if it is `C^n` on @@ -738,13 +732,13 @@ theorem contMDiffWithinAt_iff_contMDiffOn_nhds rcases (contMDiffWithinAt_iff'.1 h).2.contDiffOn le_rfl 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 + ⟨(extChartAt I x).map_source (mem_extChartAt_source _), by rwa [extChartAt_to_inv], by rw [extChartAt_to_inv]; apply mem_extChartAt_source⟩ rw [insert_eq_of_mem hxs'] at hmem hsub -- Then `(extChartAt I x).symm '' v` is the neighborhood we are looking for. refine ⟨(extChartAt I x).symm '' v, ?_, ?_⟩ - · rw [← map_extChartAt_symm_nhdsWithin I, - h.1.nhdsWithin_extChartAt_symm_preimage_inter_range I I'] + · rw [← map_extChartAt_symm_nhdsWithin (I := I), + h.1.nhdsWithin_extChartAt_symm_preimage_inter_range (I := I) (I' := I')] exact image_mem_map hmem · have hv₁ : (extChartAt I x).symm '' v ⊆ (extChartAt I x).source := image_subset_iff.2 fun y hy ↦ (extChartAt I x).map_target (hsub hy).1 @@ -769,42 +763,42 @@ theorem contMDiffAt_iff_contMDiffAt_nhds refine ⟨?_, fun h => h.self_of_nhds⟩ rw [contMDiffAt_iff_contMDiffOn_nhds] rintro ⟨u, hu, h⟩ - refine (eventually_mem_nhds.mpr hu).mono fun x' hx' => ?_ + refine (eventually_mem_nhds_iff.mpr hu).mono fun x' hx' => ?_ exact (h x' <| mem_of_mem_nhds hx').contMDiffAt hx' /-! ### Congruence lemmas -/ theorem ContMDiffWithinAt.congr (h : ContMDiffWithinAt I I' n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : ContMDiffWithinAt I I' n f₁ s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_congr h h₁ hx + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_congr h h₁ hx theorem contMDiffWithinAt_congr (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : ContMDiffWithinAt I I' n f₁ s x ↔ ContMDiffWithinAt I I' n f s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_congr_iff h₁ hx + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_congr_iff h₁ hx theorem ContMDiffWithinAt.congr_of_eventuallyEq (h : ContMDiffWithinAt I I' n f s x) (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : ContMDiffWithinAt I I' n f₁ s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_congr_of_eventuallyEq h h₁ hx + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_congr_of_eventuallyEq h h₁ hx theorem Filter.EventuallyEq.contMDiffWithinAt_iff (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : ContMDiffWithinAt I I' n f₁ s x ↔ ContMDiffWithinAt I I' n f s x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropWithinAt_congr_iff_of_eventuallyEq h₁ hx + (contDiffWithinAt_localInvariantProp n).liftPropWithinAt_congr_iff_of_eventuallyEq h₁ hx theorem ContMDiffAt.congr_of_eventuallyEq (h : ContMDiffAt I I' n f x) (h₁ : f₁ =ᶠ[𝓝 x] f) : ContMDiffAt I I' n f₁ x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropAt_congr_of_eventuallyEq h h₁ + (contDiffWithinAt_localInvariantProp n).liftPropAt_congr_of_eventuallyEq h h₁ theorem Filter.EventuallyEq.contMDiffAt_iff (h₁ : f₁ =ᶠ[𝓝 x] f) : ContMDiffAt I I' n f₁ x ↔ ContMDiffAt I I' n f x := - (contDiffWithinAt_localInvariantProp I I' n).liftPropAt_congr_iff_of_eventuallyEq h₁ + (contDiffWithinAt_localInvariantProp n).liftPropAt_congr_iff_of_eventuallyEq h₁ theorem ContMDiffOn.congr (h : ContMDiffOn I I' n f s) (h₁ : ∀ y ∈ s, f₁ y = f y) : ContMDiffOn I I' n f₁ s := - (contDiffWithinAt_localInvariantProp I I' n).liftPropOn_congr h h₁ + (contDiffWithinAt_localInvariantProp n).liftPropOn_congr h h₁ theorem contMDiffOn_congr (h₁ : ∀ y ∈ s, f₁ y = f y) : ContMDiffOn I I' n f₁ s ↔ ContMDiffOn I I' n f s := - (contDiffWithinAt_localInvariantProp I I' n).liftPropOn_congr_iff h₁ + (contDiffWithinAt_localInvariantProp n).liftPropOn_congr_iff h₁ theorem ContMDiffOn.congr_mono (hf : ContMDiffOn I I' n f s) (h₁ : ∀ y ∈ s₁, f₁ y = f y) (hs : s₁ ⊆ s) : ContMDiffOn I I' n f₁ s₁ := @@ -816,8 +810,8 @@ theorem ContMDiffOn.congr_mono (hf : ContMDiffOn I I' n f s) (h₁ : ∀ y ∈ s /-- Being `C^n` is a local property. -/ theorem contMDiffOn_of_locally_contMDiffOn (h : ∀ x ∈ s, ∃ u, IsOpen u ∧ x ∈ u ∧ ContMDiffOn I I' n f (s ∩ u)) : ContMDiffOn I I' n f s := - (contDiffWithinAt_localInvariantProp I I' n).liftPropOn_of_locally_liftPropOn h + (contDiffWithinAt_localInvariantProp n).liftPropOn_of_locally_liftPropOn h theorem contMDiff_of_locally_contMDiffOn (h : ∀ x, ∃ u, IsOpen u ∧ x ∈ u ∧ ContMDiffOn I I' n f u) : ContMDiff I I' n f := - (contDiffWithinAt_localInvariantProp I I' n).liftProp_of_locally_liftPropOn h + (contDiffWithinAt_localInvariantProp n).liftProp_of_locally_liftPropOn h diff --git a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean index 0b857f12e00f4..cf3347791e051 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean @@ -15,7 +15,7 @@ import Mathlib.Analysis.NormedSpace.OperatorNorm.Prod -/ -open Set ChartedSpace SmoothManifoldWithCorners +open Set ChartedSpace open scoped Topology Manifold variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] @@ -23,27 +23,15 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] - -- declare a smooth manifold `M'` over the pair `(E', H')`. - {E' : Type*} - [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] - [SmoothManifoldWithCorners I' M'] - -- declare a smooth manifold `N` over the pair `(F, G)`. - {F : Type*} - [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] - {J : ModelWithCorners 𝕜 F G} {N : Type*} [TopologicalSpace N] [ChartedSpace G N] - [SmoothManifoldWithCorners J N] - -- declare a smooth manifold `N'` over the pair `(F', G')`. - {F' : Type*} - [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {G' : Type*} [TopologicalSpace G'] - {J' : ModelWithCorners 𝕜 F' G'} {N' : Type*} [TopologicalSpace N'] [ChartedSpace G' N'] - [SmoothManifoldWithCorners J' N'] - -- F₁, F₂, F₃, F₄ are normed spaces + -- declare normed spaces `E'`, `F`, `F'`, `F₁`, `F₂`, `F₃`, `F₄`. + {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] + {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {F₁ : Type*} [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] {F₂ : Type*} [NormedAddCommGroup F₂] [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices - {f f₁ : M → M'} {s t : Set M} {x : M} {m n : ℕ∞} + {s : Set M} {x : M} {n : ℕ∞} section Module diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean index 5208fce1bdcc3..fcd0a708a6a66 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean @@ -23,11 +23,11 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] -- declare a charted space `M` over the pair `(E, H)`. {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] -- declare a charted space `M'` over the pair `(E', H')`. {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] -- declare a charted space `N` over the pair `(F, G)`. {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] @@ -36,15 +36,8 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {G' : Type*} [TopologicalSpace G'] {J' : ModelWithCorners 𝕜 F' G'} {N' : Type*} [TopologicalSpace N'] [ChartedSpace G' N'] - -- F₁, F₂, F₃, F₄ are normed spaces - {F₁ : Type*} - [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] {F₂ : Type*} [NormedAddCommGroup F₂] - [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} - [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices - {e : PartialHomeomorph M H} - {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} -variable {I I'} + {f : M → M'} {s : Set M} {x : M} {n : ℕ∞} section ProdMk @@ -135,7 +128,7 @@ theorem contMDiffWithinAt_fst {s : Set (M × N)} {p : M × N} : rw [contMDiffWithinAt_iff'] refine ⟨continuousWithinAt_fst, contDiffWithinAt_fst.congr (fun y hy => ?_) ?_⟩ · exact (extChartAt I p.1).right_inv ⟨hy.1.1.1, hy.1.2.1⟩ - · exact (extChartAt I p.1).right_inv <| (extChartAt I p.1).map_source (mem_extChartAt_source _ _) + · exact (extChartAt I p.1).right_inv <| (extChartAt I p.1).map_source (mem_extChartAt_source _) theorem ContMDiffWithinAt.fst {f : N → M × M'} {s : Set N} {x : N} (hf : ContMDiffWithinAt J (I.prod I') n f s x) : @@ -191,7 +184,7 @@ theorem contMDiffWithinAt_snd {s : Set (M × N)} {p : M × N} : rw [contMDiffWithinAt_iff'] refine ⟨continuousWithinAt_snd, contDiffWithinAt_snd.congr (fun y hy => ?_) ?_⟩ · exact (extChartAt J p.2).right_inv ⟨hy.1.1.2, hy.1.2.2⟩ - · exact (extChartAt J p.2).right_inv <| (extChartAt J p.2).map_source (mem_extChartAt_source _ _) + · exact (extChartAt J p.2).right_inv <| (extChartAt J p.2).map_source (mem_extChartAt_source _) theorem ContMDiffWithinAt.snd {f : N → M × M'} {s : Set N} {x : N} (hf : ContMDiffWithinAt J (I.prod I') n f s x) : diff --git a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean index 0b4140f98c392..18b485a8d8b2c 100644 --- a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean +++ b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ -import Mathlib.Geometry.Manifold.MFDeriv.UniqueDifferential +import Mathlib.Geometry.Manifold.MFDeriv.Tangent import Mathlib.Geometry.Manifold.ContMDiffMap /-! @@ -45,13 +45,9 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {G' : Type*} [TopologicalSpace G'] {J' : ModelWithCorners 𝕜 F' G'} {N' : Type*} [TopologicalSpace N'] [ChartedSpace G' N'] - -- declare some additional normed spaces, used for fibers of vector bundles - {F₁ : Type*} - [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] {F₂ : Type*} [NormedAddCommGroup F₂] - [NormedSpace 𝕜 F₂] -- declare functions, sets, points and smoothness indices - {f f₁ : M → M'} - {s s₁ t : Set M} {x : M} {m n : ℕ∞} + {f : M → M'} + {s : Set M} {m n : ℕ∞} -- Porting note: section about deducing differentiability from smoothness moved to -- `Geometry.Manifold.MFDeriv.Basic` @@ -80,12 +76,12 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → x₀ := by have h4f : ContinuousAt (fun x => f x (g x)) x₀ := ContinuousAt.comp_of_eq hf.continuousAt (continuousAt_id.prod hg.continuousAt) rfl - have h4f := h4f.preimage_mem_nhds (extChartAt_source_mem_nhds I' (f x₀ (g x₀))) + have h4f := h4f.preimage_mem_nhds (extChartAt_source_mem_nhds (I := I') (f x₀ (g x₀))) have h3f := contMDiffAt_iff_contMDiffAt_nhds.mp (hf.of_le <| (self_le_add_left 1 m).trans hmn) have h2f : ∀ᶠ x₂ in 𝓝 x₀, ContMDiffAt I I' 1 (f x₂) (g x₂) := by refine ((continuousAt_id.prod hg.continuousAt).tendsto.eventually h3f).mono fun x hx => ?_ exact hx.comp (g x) (contMDiffAt_const.prod_mk contMDiffAt_id) - have h2g := hg.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds I (g x₀)) + have h2g := hg.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds (I := I) (g x₀)) have : ContDiffWithinAt 𝕜 m (fun x => @@ -134,9 +130,9 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → rw [(extChartAt I (g x₂)).left_inv hx, (extChartAt I' (f x₂ (g x₂))).left_inv h2x] refine Filter.EventuallyEq.fderivWithin_eq_nhds ?_ refine eventually_of_mem (inter_mem ?_ ?_) this - · exact extChartAt_preimage_mem_nhds' _ hx₂ (extChartAt_source_mem_nhds I (g x₂)) - · refine extChartAt_preimage_mem_nhds' _ hx₂ ?_ - exact h2x₂.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds _ _) + · exact extChartAt_preimage_mem_nhds' hx₂ (extChartAt_source_mem_nhds (g x₂)) + · refine extChartAt_preimage_mem_nhds' hx₂ ?_ + exact h2x₂.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds _) /- The conclusion is equal to the following, when unfolding coord_change of `tangentBundleCore` -/ -- Porting note: added @@ -157,19 +153,19 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → intro x₂ hx₂ h2x₂ h3x₂ symm rw [(h2x₂.mdifferentiableAt le_rfl).mfderiv] - have hI := (contDiffWithinAt_ext_coord_change I (g x₂) (g x₀) <| + have hI := (contDiffWithinAt_ext_coord_change (I := I) (g x₂) (g x₀) <| PartialEquiv.mem_symm_trans_source _ hx₂ <| - mem_extChartAt_source I (g x₂)).differentiableWithinAt le_top + mem_extChartAt_source (g x₂)).differentiableWithinAt le_top have hI' := - (contDiffWithinAt_ext_coord_change I' (f x₀ (g x₀)) (f x₂ (g x₂)) <| - PartialEquiv.mem_symm_trans_source _ (mem_extChartAt_source I' (f x₂ (g x₂))) + (contDiffWithinAt_ext_coord_change (f x₀ (g x₀)) (f x₂ (g x₂)) <| + PartialEquiv.mem_symm_trans_source _ (mem_extChartAt_source (f x₂ (g x₂))) h3x₂).differentiableWithinAt le_top have h3f := (h2x₂.mdifferentiableAt le_rfl).differentiableWithinAt_writtenInExtChartAt refine fderivWithin.comp₃ _ hI' h3f hI ?_ ?_ ?_ ?_ (I.uniqueDiffOn _ <| mem_range_self _) · exact fun x _ => mem_range_self _ · exact fun x _ => mem_range_self _ · simp_rw [writtenInExtChartAt, Function.comp_apply, - (extChartAt I (g x₂)).left_inv (mem_extChartAt_source I (g x₂))] + (extChartAt I (g x₂)).left_inv (mem_extChartAt_source (g x₂))] · simp_rw [Function.comp_apply, (extChartAt I (g x₀)).left_inv hx₂] refine this.congr_of_eventuallyEq ?_ filter_upwards [h2g, h4f] with x hx h2x @@ -227,12 +223,12 @@ theorem ContMDiffOn.continuousOn_tangentMapWithin_aux {f : H → H'} {s : Set H} (f p.fst, (fderivWithin 𝕜 (writtenInExtChartAt I I' p.fst f) (I.symm ⁻¹' s ∩ range I) ((extChartAt I p.fst) p.fst) : E →L[𝕜] E') p.snd)) (Prod.fst ⁻¹' s) by - have A := (tangentBundleModelSpaceHomeomorph H I).continuous + have A := (tangentBundleModelSpaceHomeomorph I).continuous rw [continuous_iff_continuousOn_univ] at A have B := - ((tangentBundleModelSpaceHomeomorph H' I').symm.continuous.comp_continuousOn h).comp' A + ((tangentBundleModelSpaceHomeomorph I').symm.continuous.comp_continuousOn h).comp_inter A have : - univ ∩ tangentBundleModelSpaceHomeomorph H I ⁻¹' (Prod.fst ⁻¹' s) = + univ ∩ tangentBundleModelSpaceHomeomorph I ⁻¹' (Prod.fst ⁻¹' s) = π E (TangentSpace I) ⁻¹' s := by ext ⟨x, v⟩; simp only [mfld_simps] rw [this] at B @@ -394,7 +390,7 @@ theorem ContMDiffOn.contMDiffOn_tangentMapWithin apply UniqueMDiffOn.inter _ l.open_source rw [ho, inter_comm] exact hs.inter o_open - have U'l : UniqueMDiffOn I s'l := U'.uniqueMDiffOn_preimage (mdifferentiable_chart _ _) + have U'l : UniqueMDiffOn I s'l := U'.uniqueMDiffOn_preimage (mdifferentiable_chart _) have diff_f : ContMDiffOn I I' n f s' := hf.mono (by unfold_let s'; mfld_set_tac) have diff_r : ContMDiffOn I' I' n r r.source := contMDiffOn_chart have diff_rf : ContMDiffOn I I' n (r ∘ f) s' := by @@ -465,7 +461,7 @@ theorem ContMDiffOn.contMDiffOn_tangentMapWithin tangentMap I I l.symm (il.symm (Dl q)) := by refine tangentMapWithin_eq_tangentMap U'lq ?_ -- Porting note: the arguments below were underscores. - refine mdifferentiableAt_atlas_symm I (chart_mem_atlas H (TotalSpace.proj p)) ?_ + refine mdifferentiableAt_atlas_symm (chart_mem_atlas H (TotalSpace.proj p)) ?_ simp only [Dl, il, hq, mfld_simps] rw [this, tangentMap_chart_symm, hDl] · simp only [il, hq, mfld_simps] @@ -491,7 +487,7 @@ theorem ContMDiffOn.contMDiffOn_tangentMapWithin apply tangentMapWithin_eq_tangentMap · apply r.open_source.uniqueMDiffWithinAt _ simp [hq] - · exact mdifferentiableAt_atlas I' (chart_mem_atlas H' (f p.proj)) hq.1.1 + · exact mdifferentiableAt_atlas (chart_mem_atlas H' (f p.proj)) hq.1.1 have : f p.proj = (tangentMapWithin I I' f s p).1 := rfl rw [A] dsimp [Dr, ir, s', r, l] @@ -542,8 +538,6 @@ end tangentMap namespace TangentBundle -variable (I M) - open Bundle /-- The derivative of the zero section of the tangent bundle maps `⟨x, v⟩` to `⟨⟨x, 0⟩, ⟨v, 0⟩⟩`. diff --git a/Mathlib/Geometry/Manifold/ContMDiffMap.lean b/Mathlib/Geometry/Manifold/ContMDiffMap.lean index 9eac199f01e6d..8566926007fa4 100644 --- a/Mathlib/Geometry/Manifold/ContMDiffMap.lean +++ b/Mathlib/Geometry/Manifold/ContMDiffMap.lean @@ -14,8 +14,8 @@ bundled maps. variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H : Type*} - [TopologicalSpace H] {H' : Type*} [TopologicalSpace H'] (I : ModelWithCorners 𝕜 E H) - (I' : ModelWithCorners 𝕜 E' H') (M : Type*) [TopologicalSpace M] [ChartedSpace H M] (M' : Type*) + [TopologicalSpace H] {H' : Type*} [TopologicalSpace H'] {I : ModelWithCorners 𝕜 E H} + {I' : ModelWithCorners 𝕜 E' H'} (M : Type*) [TopologicalSpace M] [ChartedSpace H M] (M' : Type*) [TopologicalSpace M'] [ChartedSpace H' M'] {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] @@ -24,10 +24,12 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] {J : ModelWithCorners 𝕜 F G} {N : Type*} [TopologicalSpace N] [ChartedSpace G N] (n : ℕ∞) +variable (I I') in /-- Bundled `n` times continuously differentiable maps. -/ def ContMDiffMap := { f : M → M' // ContMDiff I I' n f } +variable (I I') in /-- Bundled smooth maps. -/ abbrev SmoothMap := ContMDiffMap I I' M M' ⊤ @@ -43,7 +45,7 @@ open scoped Manifold namespace ContMDiffMap -variable {I} {I'} {M} {M'} {n} +variable {M} {M'} {n} instance instFunLike : FunLike C^n⟮I, M; I', M'⟯ M M' where coe := Subtype.val diff --git a/Mathlib/Geometry/Manifold/DerivationBundle.lean b/Mathlib/Geometry/Manifold/DerivationBundle.lean index fad0b9a9bd14e..4398a408bf6df 100644 --- a/Mathlib/Geometry/Manifold/DerivationBundle.lean +++ b/Mathlib/Geometry/Manifold/DerivationBundle.lean @@ -94,7 +94,7 @@ section open scoped Derivation -variable (X Y : Derivation 𝕜 C^∞⟮I, M; 𝕜⟯ C^∞⟮I, M; 𝕜⟯) (f g : C^∞⟮I, M; 𝕜⟯) (r : 𝕜) +variable (X : Derivation 𝕜 C^∞⟮I, M; 𝕜⟯ C^∞⟮I, M; 𝕜⟯) (f : C^∞⟮I, M; 𝕜⟯) /-- Evaluation at a point gives rise to a `C^∞⟮I, M; 𝕜⟯`-linear map between `C^∞⟮I, M; 𝕜⟯` and `𝕜`. -/ @@ -135,8 +135,8 @@ def hfdifferential {f : C^∞⟮I, M; I', M'⟯} {x : M} {y : M'} (h : f x = y) PointedSmoothMap.smul_def, ContMDiffMap.comp_apply, PointedSmoothMap.smul_def, ContMDiffMap.comp_apply, h] norm_cast - map_smul' k v := rfl - map_add' v w := rfl + map_smul' _ _ := rfl + map_add' _ _ := rfl /-- The homogeneous differential as a linear map. -/ def fdifferential (f : C^∞⟮I, M; I', M'⟯) (x : M) : diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 07f8ab47bb49f..b1dd98224633d 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -383,8 +383,6 @@ end end Constructions -variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners J N] - theorem uniqueMDiffOn_image_aux (h : M ≃ₘ^n⟮I, J⟯ N) (hn : 1 ≤ n) {s : Set M} (hs : UniqueMDiffOn I s) : UniqueMDiffOn J (h '' s) := by convert hs.uniqueMDiffOn_preimage (h.toPartialHomeomorph_mdifferentiable hn) @@ -485,6 +483,7 @@ instance smoothManifoldWithCorners_transDiffeomorph [SmoothManifoldWithCorners I refine smoothManifoldWithCorners_of_contDiffOn (I.transDiffeomorph e) M fun e₁ e₂ h₁ h₂ => ?_ refine e.contDiff.comp_contDiffOn (((contDiffGroupoid ⊤ I).compatible h₁ h₂).1.comp e.symm.contDiff.contDiffOn ?_) + simp only [mapsTo_iff_subset_preimage] mfld_set_tac variable (I M) @@ -495,18 +494,18 @@ def toTransDiffeomorph (e : E ≃ₘ[𝕜] F) : M ≃ₘ⟮I, I.transDiffeomorph toEquiv := Equiv.refl M contMDiff_toFun x := by refine contMDiffWithinAt_iff'.2 ⟨continuousWithinAt_id, ?_⟩ - refine e.contDiff.contDiffWithinAt.congr' (fun y hy ↦ ?_) ?_ + refine e.contDiff.contDiffWithinAt.congr_of_mem (fun y hy ↦ ?_) ?_ · simp only [Equiv.coe_refl, id, (· ∘ ·), I.coe_extChartAt_transDiffeomorph, (extChartAt I x).right_inv hy.1] · exact - ⟨(extChartAt I x).map_source (mem_extChartAt_source I x), trivial, by simp only [mfld_simps]⟩ + ⟨(extChartAt I x).map_source (mem_extChartAt_source x), trivial, by simp only [mfld_simps]⟩ contMDiff_invFun x := by refine contMDiffWithinAt_iff'.2 ⟨continuousWithinAt_id, ?_⟩ - refine e.symm.contDiff.contDiffWithinAt.congr' (fun y hy => ?_) ?_ + refine e.symm.contDiff.contDiffWithinAt.congr_of_mem (fun y hy => ?_) ?_ · simp only [mem_inter_iff, I.extChartAt_transDiffeomorph_target] at hy simp only [Equiv.coe_refl, Equiv.refl_symm, id, (· ∘ ·), I.coe_extChartAt_transDiffeomorph_symm, (extChartAt I x).right_inv hy.1] - exact ⟨(extChartAt _ x).map_source (mem_extChartAt_source _ x), trivial, by + exact ⟨(extChartAt _ x).map_source (mem_extChartAt_source x), trivial, by simp only [e.symm_apply_apply, Equiv.refl_symm, Equiv.coe_refl, mfld_simps]⟩ variable {I M} @@ -531,7 +530,6 @@ theorem contMDiff_transDiffeomorph_right {f : M' → M} : ContMDiff I' (I.transDiffeomorph e) n f ↔ ContMDiff I' I n f := (toTransDiffeomorph I M e).contMDiff_diffeomorph_comp_iff le_top --- Porting note (#10618): was `@[simp]` but now `simp` can prove it theorem smooth_transDiffeomorph_right {f : M' → M} : Smooth I' (I.transDiffeomorph e) f ↔ Smooth I' I f := contMDiff_transDiffeomorph_right e @@ -556,7 +554,6 @@ theorem contMDiff_transDiffeomorph_left {f : M → M'} : ContMDiff (I.transDiffeomorph e) I' n f ↔ ContMDiff I I' n f := ((toTransDiffeomorph I M e).contMDiff_comp_diffeomorph_iff le_top).symm --- Porting note (#10618): was `@[simp]` but now `simp` can prove it theorem smooth_transDiffeomorph_left {f : M → M'} : Smooth (I.transDiffeomorph e) I' f ↔ Smooth I I' f := e.contMDiff_transDiffeomorph_left diff --git a/Mathlib/Geometry/Manifold/Instances/Real.lean b/Mathlib/Geometry/Manifold/Instances/Real.lean index 43cbf79926a58..9b54f975c0526 100644 --- a/Mathlib/Geometry/Manifold/Instances/Real.lean +++ b/Mathlib/Geometry/Manifold/Instances/Real.lean @@ -134,7 +134,7 @@ def modelWithCornersEuclideanHalfSpace (n : ℕ) [NeZero n] : left_inv' := fun ⟨xval, xprop⟩ _ => by rw [Subtype.mk_eq_mk, update_eq_iff] exact ⟨max_eq_left xprop, fun i _ => rfl⟩ - right_inv' x hx := update_eq_iff.2 ⟨max_eq_left hx, fun i _ => rfl⟩ + right_inv' _ hx := update_eq_iff.2 ⟨max_eq_left hx, fun _ _ => rfl⟩ source_eq := rfl uniqueDiffOn' := by have : UniqueDiffOn ℝ _ := @@ -155,7 +155,7 @@ def modelWithCornersEuclideanQuadrant (n : ℕ) : source := univ target := { x | ∀ i, 0 ≤ x i } map_source' x _ := x.property - map_target' x _ := mem_univ _ + map_target' _ _ := mem_univ _ left_inv' x _ := by ext i; simp only [Subtype.coe_mk, x.2 i, max_eq_left] right_inv' x hx := by ext1 i; simp only [hx i, max_eq_left] source_eq := rfl @@ -323,7 +323,7 @@ instance Icc_smooth_manifold (x y : ℝ) [Fact (x < y)] : either the left chart or the right chart, leaving 4 possibilities that we handle successively. -/ rcases he with (rfl | rfl) <;> rcases he' with (rfl | rfl) · -- `e = left chart`, `e' = left chart` - exact (mem_groupoid_of_pregroupoid.mpr (symm_trans_mem_contDiffGroupoid _ _ _)).1 + exact (mem_groupoid_of_pregroupoid.mpr (symm_trans_mem_contDiffGroupoid _)).1 · -- `e = left chart`, `e' = right chart` apply M.contDiffOn.congr rintro _ ⟨⟨hz₁, hz₂⟩, ⟨⟨z, hz₀⟩, rfl⟩⟩ @@ -347,7 +347,7 @@ instance Icc_smooth_manifold (x y : ℝ) [Fact (x < y)] : PiLp.neg_apply, update_same, max_eq_left, hz₀, hz₁.le, mfld_simps] abel ·-- `e = right chart`, `e' = right chart` - exact (mem_groupoid_of_pregroupoid.mpr (symm_trans_mem_contDiffGroupoid _ _ _)).1 + exact (mem_groupoid_of_pregroupoid.mpr (symm_trans_mem_contDiffGroupoid _)).1 /-! Register the manifold structure on `Icc 0 1`, and also its zero and one. -/ diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index f5d59a6f08222..d6924e2d45735 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -389,7 +389,7 @@ instance EuclideanSpace.instSmoothManifoldWithCornersSphere {n : ℕ} [Fact (fin -- Porting note: need to help with implicit variables again have H₂ := (contDiff_stereoInvFunAux (v := v.val)|>.comp (ℝ ∙ (v : E))ᗮ.subtypeL.contDiff).comp U.symm.contDiff - convert H₁.comp' (H₂.contDiffOn : ContDiffOn ℝ ⊤ _ Set.univ) using 1 + convert H₁.comp_inter (H₂.contDiffOn : ContDiffOn ℝ ⊤ _ Set.univ) using 1 -- -- squeezed from `ext, simp [sphere_ext_iff, stereographic'_symm_apply, real_inner_comm]` simp only [PartialHomeomorph.trans_toPartialEquiv, PartialHomeomorph.symm_toPartialEquiv, PartialEquiv.trans_source, PartialEquiv.symm_source, stereographic'_target, @@ -439,7 +439,7 @@ theorem ContMDiff.codRestrict_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] {m OrthonormalBasis.fromOrthogonalSpanSingleton n (ne_zero_of_mem_unit_sphere (-v))).repr have h : ContDiffOn ℝ ⊤ _ Set.univ := U.contDiff.contDiffOn - have H₁ := (h.comp' contDiffOn_stereoToFun).contMDiffOn + have H₁ := (h.comp_inter contDiffOn_stereoToFun).contMDiffOn have H₂ : ContMDiffOn _ _ _ _ Set.univ := hf.contMDiffOn convert (H₁.of_le le_top).comp' H₂ using 1 ext x @@ -477,8 +477,6 @@ theorem range_mfderiv_coe_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] (v : s TangentSpace (𝓡 n) v →L[ℝ] E) = (ℝ ∙ (v : E))ᗮ := by rw [((contMDiff_coe_sphere v).mdifferentiableAt le_top).mfderiv] dsimp [chartAt] - -- rw [LinearIsometryEquiv.toHomeomorph_symm] - -- rw [← LinearIsometryEquiv.coe_toHomeomorph] simp only [chartAt, stereographic_neg_apply, fderivWithin_univ, LinearIsometryEquiv.toHomeomorph_symm, LinearIsometryEquiv.coe_toHomeomorph, LinearIsometryEquiv.map_zero, mfld_simps] diff --git a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean index e7690b95e11f0..8ee99e793fb7c 100644 --- a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean +++ b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean @@ -33,7 +33,7 @@ namespace Units variable {R : Type*} [NormedRing R] [CompleteSpace R] instance : ChartedSpace R Rˣ := - openEmbedding_val.singletonChartedSpace + isOpenEmbedding_val.singletonChartedSpace theorem chartAt_apply {a : Rˣ} {b : Rˣ} : chartAt R a b = b := rfl @@ -44,17 +44,17 @@ theorem chartAt_source {a : Rˣ} : (chartAt R a).source = Set.univ := variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedAlgebra 𝕜 R] instance : SmoothManifoldWithCorners 𝓘(𝕜, R) Rˣ := - openEmbedding_val.singleton_smoothManifoldWithCorners 𝓘(𝕜, R) + isOpenEmbedding_val.singleton_smoothManifoldWithCorners /-- For a complete normed ring `R`, the embedding of the units `Rˣ` into `R` is a smooth map between manifolds. -/ lemma contMDiff_val {m : ℕ∞} : ContMDiff 𝓘(𝕜, R) 𝓘(𝕜, R) m (val : Rˣ → R) := - contMDiff_openEmbedding 𝓘(𝕜, R) Units.openEmbedding_val + contMDiff_isOpenEmbedding Units.isOpenEmbedding_val /-- The units of a complete normed ring form a Lie group. -/ instance : LieGroup 𝓘(𝕜, R) Rˣ where smooth_mul := by - apply ContMDiff.of_comp_openEmbedding Units.openEmbedding_val + apply ContMDiff.of_comp_isOpenEmbedding Units.isOpenEmbedding_val have : (val : Rˣ → R) ∘ (fun x : Rˣ × Rˣ => x.1 * x.2) = (fun x : R × R => x.1 * x.2) ∘ (fun x : Rˣ × Rˣ => (x.1, x.2)) := by ext; simp rw [this] @@ -65,7 +65,7 @@ instance : LieGroup 𝓘(𝕜, R) Rˣ where rw [contMDiff_iff_contDiff] exact contDiff_mul smooth_inv := by - apply ContMDiff.of_comp_openEmbedding Units.openEmbedding_val + apply ContMDiff.of_comp_isOpenEmbedding Units.isOpenEmbedding_val have : (val : Rˣ → R) ∘ (fun x : Rˣ => x⁻¹) = Ring.inverse ∘ val := by ext; simp rw [this, ContMDiff] refine fun x => ContMDiffAt.comp x ?_ (contMDiff_val x) diff --git a/Mathlib/Geometry/Manifold/IntegralCurve.lean b/Mathlib/Geometry/Manifold/IntegralCurve.lean index 064e40fa40d71..624dbdbf85a0b 100644 --- a/Mathlib/Geometry/Manifold/IntegralCurve.lean +++ b/Mathlib/Geometry/Manifold/IntegralCurve.lean @@ -6,7 +6,7 @@ Authors: Winston Yin import Mathlib.Analysis.ODE.Gronwall import Mathlib.Analysis.ODE.PicardLindelof import Mathlib.Geometry.Manifold.InteriorBoundary -import Mathlib.Geometry.Manifold.MFDeriv.Atlas +import Mathlib.Geometry.Manifold.MFDeriv.Tangent /-! # Integral curves of vector fields on a manifold @@ -65,7 +65,7 @@ open Function Set variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners ℝ E H} - {M : Type*} [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M] + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] /-- If `γ : ℝ → M` is $C^1$ on `s : Set ℝ` and `v` is a vector field on `M`, `IsIntegralCurveOn γ v s` means `γ t` is tangent to `v (γ t)` for all `t ∈ s`. The value of `γ` @@ -150,6 +150,7 @@ lemma IsIntegralCurveAt.continuousAt (hγ : IsIntegralCurveAt γ v t₀) : lemma IsIntegralCurve.continuous (hγ : IsIntegralCurve γ v) : Continuous γ := continuous_iff_continuousAt.mpr fun _ ↦ (hγ.isIntegralCurveOn univ).continuousAt (mem_univ _) +variable [SmoothManifoldWithCorners I M] in /-- If `γ` is an integral curve of a vector field `v`, then `γ t` is tangent to `v (γ t)` when expressed in the local chart around the initial point `γ t₀`. -/ lemma IsIntegralCurveOn.hasDerivAt (hγ : IsIntegralCurveOn γ v s) {t : ℝ} (ht : t ∈ s) @@ -160,29 +161,30 @@ lemma IsIntegralCurveOn.hasDerivAt (hγ : IsIntegralCurveOn γ v s) {t : ℝ} (h have hsrc := extChartAt_source I (γ t₀) ▸ hsrc rw [hasDerivAt_iff_hasFDerivAt, ← hasMFDerivAt_iff_hasFDerivAt] apply (HasMFDerivAt.comp t - (hasMFDerivAt_extChartAt I hsrc) (hγ _ ht)).congr_mfderiv + (hasMFDerivAt_extChartAt (I := I) hsrc) (hγ _ ht)).congr_mfderiv rw [ContinuousLinearMap.ext_iff] intro a rw [ContinuousLinearMap.comp_apply, ContinuousLinearMap.smulRight_apply, map_smul, ← ContinuousLinearMap.one_apply (R₁ := ℝ) a, ← ContinuousLinearMap.smulRight_apply, - mfderiv_chartAt_eq_tangentCoordChange I hsrc] + mfderiv_chartAt_eq_tangentCoordChange hsrc] rfl +variable [SmoothManifoldWithCorners I M] in lemma IsIntegralCurveAt.eventually_hasDerivAt (hγ : IsIntegralCurveAt γ v t₀) : ∀ᶠ t in 𝓝 t₀, HasDerivAt ((extChartAt I (γ t₀)) ∘ γ) (tangentCoordChange I (γ t) (γ t₀) (γ t) (v (γ t))) t := by - apply eventually_mem_nhds.mpr - (hγ.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds I _)) |>.and hγ |>.mono + apply eventually_mem_nhds_iff.mpr + (hγ.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds (I := I) _)) |>.and hγ |>.mono rintro t ⟨ht1, ht2⟩ have hsrc := mem_of_mem_nhds ht1 rw [mem_preimage, extChartAt_source I (γ t₀)] at hsrc rw [hasDerivAt_iff_hasFDerivAt, ← hasMFDerivAt_iff_hasFDerivAt] - apply (HasMFDerivAt.comp t (hasMFDerivAt_extChartAt I hsrc) ht2).congr_mfderiv + apply (HasMFDerivAt.comp t (hasMFDerivAt_extChartAt (I := I) hsrc) ht2).congr_mfderiv rw [ContinuousLinearMap.ext_iff] intro a rw [ContinuousLinearMap.comp_apply, ContinuousLinearMap.smulRight_apply, map_smul, ← ContinuousLinearMap.one_apply (R₁ := ℝ) a, ← ContinuousLinearMap.smulRight_apply, - mfderiv_chartAt_eq_tangentCoordChange I hsrc] + mfderiv_chartAt_eq_tangentCoordChange hsrc] rfl /-! ### Translation lemmas -/ @@ -304,7 +306,7 @@ end Scaling section ExistUnique -variable (t₀) {x₀ : M} +variable [SmoothManifoldWithCorners I M] (t₀) {x₀ : M} /-- Existence of local integral curves for a $C^1$ vector field at interior points of a smooth manifold. -/ @@ -325,7 +327,7 @@ theorem exists_isIntegralCurveAt_of_contMDiffAt [CompleteSpace E] rw [continuousAt_def, hf1] at hcont have hnhds : f ⁻¹' (interior (extChartAt I x₀).target) ∈ 𝓝 t₀ := hcont _ (isOpen_interior.mem_nhds ((I.isInteriorPoint_iff).mp hx)) - rw [← eventually_mem_nhds] at hnhds + rw [← eventually_mem_nhds_iff] at hnhds -- obtain a neighbourhood `s` so that the above conditions both hold in `s` obtain ⟨s, hs, haux⟩ := (hf2.and hnhds).exists_mem -- prove that `γ := (extChartAt I x₀).symm ∘ f` is a desired integral curve @@ -342,9 +344,9 @@ theorem exists_isIntegralCurveAt_of_contMDiffAt [CompleteSpace E] have hf3' := mem_of_mem_of_subset hf3 interior_subset have hft1 := mem_preimage.mp <| mem_of_mem_of_subset hf3' (extChartAt I x₀).target_subset_preimage_source - have hft2 := mem_extChartAt_source I xₜ + have hft2 := mem_extChartAt_source (I := I) xₜ -- express the derivative of the integral curve in the local chart - refine ⟨(continuousAt_extChartAt_symm'' _ hf3').comp h.continuousAt, + refine ⟨(continuousAt_extChartAt_symm'' hf3').comp h.continuousAt, HasDerivWithinAt.hasFDerivWithinAt ?_⟩ simp only [mfld_simps, hasDerivWithinAt_univ] show HasDerivAt ((extChartAt I xₜ ∘ (extChartAt I x₀).symm) ∘ f) (v xₜ) t @@ -366,7 +368,7 @@ lemma exists_isIntegralCurveAt_of_contMDiffAt_boundaryless [CompleteSpace E] [BoundarylessManifold I M] (hv : ContMDiffAt I I.tangent 1 (fun x ↦ (⟨x, v x⟩ : TangentBundle I M)) x₀) : ∃ γ : ℝ → M, γ t₀ = x₀ ∧ IsIntegralCurveAt γ v t₀ := - exists_isIntegralCurveAt_of_contMDiffAt t₀ hv (BoundarylessManifold.isInteriorPoint I) + exists_isIntegralCurveAt_of_contMDiffAt t₀ hv BoundarylessManifold.isInteriorPoint variable {t₀} @@ -391,8 +393,8 @@ theorem isIntegralCurveAt_eventuallyEq_of_contMDiffAt (hγt₀ : I.IsInteriorPoi have hlip (t : ℝ) : LipschitzOnWith K ((fun _ ↦ v') t) ((fun _ ↦ s) t) := hlip -- internal lemmas to reduce code duplication have hsrc {g} (hg : IsIntegralCurveAt g v t₀) : - ∀ᶠ t in 𝓝 t₀, g ⁻¹' (extChartAt I (g t₀)).source ∈ 𝓝 t := eventually_mem_nhds.mpr <| - continuousAt_def.mp hg.continuousAt _ <| extChartAt_source_mem_nhds I (g t₀) + ∀ᶠ t in 𝓝 t₀, g ⁻¹' (extChartAt I (g t₀)).source ∈ 𝓝 t := eventually_mem_nhds_iff.mpr <| + continuousAt_def.mp hg.continuousAt _ <| extChartAt_source_mem_nhds (g t₀) have hmem {g : ℝ → M} {t} (ht : g ⁻¹' (extChartAt I (g t₀)).source ∈ 𝓝 t) : g t ∈ (extChartAt I (g t₀)).source := mem_preimage.mp <| mem_of_mem_nhds ht have hdrv {g} (hg : IsIntegralCurveAt g v t₀) (h' : γ t₀ = g t₀) : ∀ᶠ t in 𝓝 t₀, @@ -405,7 +407,7 @@ theorem isIntegralCurveAt_eventuallyEq_of_contMDiffAt (hγt₀ : I.IsInteriorPoi apply ht2.congr_deriv congr <;> rw [Function.comp_apply, PartialEquiv.left_inv _ (hmem ht1)] - · apply ((continuousAt_extChartAt I (g t₀)).comp hg.continuousAt).preimage_mem_nhds + · apply ((continuousAt_extChartAt (g t₀)).comp hg.continuousAt).preimage_mem_nhds rw [Function.comp_apply, ← h'] exact hs have heq {g} (hg : IsIntegralCurveAt g v t₀) : @@ -423,7 +425,7 @@ theorem isIntegralCurveAt_eventuallyEq_of_contMDiffAt_boundaryless [Boundaryless (hv : ContMDiffAt I I.tangent 1 (fun x ↦ (⟨x, v x⟩ : TangentBundle I M)) (γ t₀)) (hγ : IsIntegralCurveAt γ v t₀) (hγ' : IsIntegralCurveAt γ' v t₀) (h : γ t₀ = γ' t₀) : γ =ᶠ[𝓝 t₀] γ' := - isIntegralCurveAt_eventuallyEq_of_contMDiffAt (BoundarylessManifold.isInteriorPoint I) hv hγ hγ' h + isIntegralCurveAt_eventuallyEq_of_contMDiffAt BoundarylessManifold.isInteriorPoint hv hγ hγ' h variable [T2Space M] {a b : ℝ} @@ -475,7 +477,7 @@ theorem isIntegralCurveOn_Ioo_eqOn_of_contMDiff_boundaryless [BoundarylessManifo (hγ : IsIntegralCurveOn γ v (Ioo a b)) (hγ' : IsIntegralCurveOn γ' v (Ioo a b)) (h : γ t₀ = γ' t₀) : EqOn γ γ' (Ioo a b) := isIntegralCurveOn_Ioo_eqOn_of_contMDiff - ht₀ (fun _ _ ↦ BoundarylessManifold.isInteriorPoint I) hv hγ hγ' h + ht₀ (fun _ _ ↦ BoundarylessManifold.isInteriorPoint) hv hγ hγ' h /-- Global integral curves are unique. @@ -498,7 +500,7 @@ theorem isIntegralCurve_eq_of_contMDiff (hγt : ∀ t, I.IsInteriorPoint (γ t)) theorem isIntegralCurve_Ioo_eq_of_contMDiff_boundaryless [BoundarylessManifold I M] (hv : ContMDiff I I.tangent 1 (fun x ↦ (⟨x, v x⟩ : TangentBundle I M))) (hγ : IsIntegralCurve γ v) (hγ' : IsIntegralCurve γ' v) (h : γ t₀ = γ' t₀) : γ = γ' := - isIntegralCurve_eq_of_contMDiff (fun _ ↦ BoundarylessManifold.isInteriorPoint I) hv hγ hγ' h + isIntegralCurve_eq_of_contMDiff (fun _ ↦ BoundarylessManifold.isInteriorPoint) hv hγ hγ' h /-- For a global integral curve `γ`, if it crosses itself at `a b : ℝ`, then it is periodic with period `a - b`. -/ diff --git a/Mathlib/Geometry/Manifold/InteriorBoundary.lean b/Mathlib/Geometry/Manifold/InteriorBoundary.lean index ae3c3a754f493..2fc03bd7d0a9a 100644 --- a/Mathlib/Geometry/Manifold/InteriorBoundary.lean +++ b/Mathlib/Geometry/Manifold/InteriorBoundary.lean @@ -50,14 +50,17 @@ open scoped Topology -- Let `M` be a manifold with corners over the pair `(E, H)`. variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] - {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] namespace ModelWithCorners + +variable (I) in /-- `p ∈ M` is an interior point of a manifold `M` iff its image in the extended chart lies in the interior of the model space. -/ def IsInteriorPoint (x : M) := extChartAt I x x ∈ interior (range I) +variable (I) in /-- `p ∈ M` is a boundary point of a manifold `M` iff its image in the extended chart lies on the boundary of the model space. -/ def IsBoundaryPoint (x : M) := extChartAt I x x ∈ frontier (range I) @@ -68,8 +71,8 @@ protected def interior : Set M := { x : M | I.IsInteriorPoint x } lemma isInteriorPoint_iff {x : M} : I.IsInteriorPoint x ↔ extChartAt I x x ∈ interior (extChartAt I x).target := - ⟨fun h ↦ (chartAt H x).mem_interior_extend_target _ (mem_chart_target H x) h, - fun h ↦ PartialHomeomorph.interior_extend_target_subset_interior_range _ _ h⟩ + ⟨fun h ↦ (chartAt H x).mem_interior_extend_target (mem_chart_target H x) h, + fun h ↦ PartialHomeomorph.interior_extend_target_subset_interior_range _ h⟩ variable (M) in /-- The **boundary** of a manifold `M` is the set of its boundary points. -/ @@ -106,7 +109,6 @@ lemma compl_interior : (I.interior M)ᶜ = I.boundary M:= by lemma compl_boundary : (I.boundary M)ᶜ = I.interior M:= by rw [← compl_interior, compl_compl] -variable {I} in lemma _root_.range_mem_nhds_isInteriorPoint {x : M} (h : I.IsInteriorPoint x) : range I ∈ 𝓝 (extChartAt I x x) := by rw [mem_nhds_iff] @@ -126,11 +128,11 @@ variable [I.Boundaryless] /-- Boundaryless `ModelWithCorners` implies boundaryless manifold. -/ instance : BoundarylessManifold I M where isInteriorPoint' x := by - let r := ((chartAt H x).isOpen_extend_target I).interior_eq + let r := ((chartAt H x).isOpen_extend_target (I := I)).interior_eq have : extChartAt I x = (chartAt H x).extend I := rfl rw [← this] at r rw [isInteriorPoint_iff, r] - exact PartialEquiv.map_source _ (mem_extChartAt_source _ _) + exact PartialEquiv.map_source _ (mem_extChartAt_source _) end Boundaryless @@ -145,18 +147,18 @@ lemma _root_.BoundarylessManifold.isInteriorPoint {x : M} [BoundarylessManifold /-- If `I` is boundaryless, `M` has full interior. -/ lemma interior_eq_univ [BoundarylessManifold I M] : I.interior M = univ := - eq_univ_of_forall fun _ => BoundarylessManifold.isInteriorPoint I + eq_univ_of_forall fun _ => BoundarylessManifold.isInteriorPoint /-- Boundaryless manifolds have empty boundary. -/ lemma Boundaryless.boundary_eq_empty [BoundarylessManifold I M] : I.boundary M = ∅ := by rw [← I.compl_interior, I.interior_eq_univ, compl_empty_iff] instance [BoundarylessManifold I M] : IsEmpty (I.boundary M) := - isEmpty_coe_sort.mpr (Boundaryless.boundary_eq_empty I) + isEmpty_coe_sort.mpr Boundaryless.boundary_eq_empty /-- `M` is boundaryless iff its boundary is empty. -/ lemma Boundaryless.iff_boundary_eq_empty : I.boundary M = ∅ ↔ BoundarylessManifold I M := by - refine ⟨fun h ↦ { isInteriorPoint' := ?_ }, fun a ↦ boundary_eq_empty I⟩ + refine ⟨fun h ↦ { isInteriorPoint' := ?_ }, fun a ↦ boundary_eq_empty⟩ intro x show x ∈ I.interior M rw [← compl_interior, compl_empty_iff] at h @@ -172,11 +174,11 @@ end BoundarylessManifold /-! Interior and boundary of the product of two manifolds. -/ section prod -variable {I} +variable {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {N : Type*} [TopologicalSpace N] [ChartedSpace H' N] - (J : ModelWithCorners 𝕜 E' H') {x : M} {y : N} + {J : ModelWithCorners 𝕜 E' H'} {x : M} {y : N} /-- The interior of `M × N` is the product of the interiors of `M` and `N`. -/ lemma interior_prod : @@ -198,7 +200,7 @@ lemma interior_prod : lemma boundary_prod : (I.prod J).boundary (M × N) = Set.prod univ (J.boundary N) ∪ Set.prod (I.boundary M) univ := by let h := calc (I.prod J).boundary (M × N) - _ = ((I.prod J).interior (M × N))ᶜ := (I.prod J).compl_interior.symm + _ = ((I.prod J).interior (M × N))ᶜ := compl_interior.symm _ = ((I.interior M) ×ˢ (J.interior N))ᶜ := by rw [interior_prod] _ = (I.interior M)ᶜ ×ˢ univ ∪ univ ×ˢ (J.interior N)ᶜ := by rw [compl_prod_eq_union] rw [h, I.compl_interior, J.compl_interior, union_comm] @@ -207,14 +209,14 @@ lemma boundary_prod : /-- If `M` is boundaryless, `∂(M×N) = M × ∂N`. -/ lemma boundary_of_boundaryless_left [BoundarylessManifold I M] : (I.prod J).boundary (M × N) = Set.prod (univ : Set M) (J.boundary N) := by - rw [boundary_prod, Boundaryless.boundary_eq_empty I] + rw [boundary_prod, Boundaryless.boundary_eq_empty (I := I)] have : Set.prod (∅ : Set M) (univ : Set N) = ∅ := Set.empty_prod rw [this, union_empty] /-- If `N` is boundaryless, `∂(M×N) = ∂M × N`. -/ lemma boundary_of_boundaryless_right [BoundarylessManifold J N] : (I.prod J).boundary (M × N) = Set.prod (I.boundary M) (univ : Set N) := by - rw [boundary_prod, Boundaryless.boundary_eq_empty J] + rw [boundary_prod, Boundaryless.boundary_eq_empty (I := J)] have : Set.prod (univ : Set M) (∅ : Set N) = ∅ := Set.prod_empty rw [this, empty_union] diff --git a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean index 5ea4b4a42e6b8..1a9bf211ea412 100644 --- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean +++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean @@ -403,7 +403,7 @@ theorem liftPropWithinAt_mono_of_mem (mono_of_mem : ∀ ⦃s x t⦄ ⦃f : H → H'⦄, s ∈ 𝓝[t] x → P f s x → P f t x) (h : LiftPropWithinAt P g s x) (hst : s ∈ 𝓝[t] x) : LiftPropWithinAt P g t x := by simp only [liftPropWithinAt_iff'] at h ⊢ - refine ⟨h.1.mono_of_mem hst, mono_of_mem ?_ h.2⟩ + refine ⟨h.1.mono_of_mem_nhdsWithin hst, mono_of_mem ?_ h.2⟩ simp_rw [← mem_map, (chartAt H x).symm.map_nhdsWithin_preimage_eq (mem_chart_target H x), (chartAt H x).left_inv (mem_chart_source H x), hst] @@ -490,7 +490,7 @@ theorem liftPropAt_iff_comp_subtype_val (hG : LocalInvariantProp G G' P) {U : Op LiftPropAt P f x ↔ LiftPropAt P (f ∘ Subtype.val) x := by simp only [LiftPropAt, liftPropWithinAt_iff'] congrm ?_ ∧ ?_ - · simp_rw [continuousWithinAt_univ, U.openEmbedding'.continuousAt_iff] + · simp_rw [continuousWithinAt_univ, U.isOpenEmbedding'.continuousAt_iff] · apply hG.congr_iff exact (U.chartAt_subtype_val_symm_eventuallyEq).fun_comp (chartAt H' (f x) ∘ f) @@ -500,7 +500,7 @@ theorem liftPropAt_iff_comp_inclusion (hG : LocalInvariantProp G G' P) {U V : Op simp only [LiftPropAt, liftPropWithinAt_iff'] congrm ?_ ∧ ?_ · simp_rw [continuousWithinAt_univ, - (TopologicalSpace.Opens.openEmbedding_of_le hUV).continuousAt_iff] + (TopologicalSpace.Opens.isOpenEmbedding_of_le hUV).continuousAt_iff] · apply hG.congr_iff exact (TopologicalSpace.Opens.chartAt_inclusion_symm_eventuallyEq hUV).fun_comp (chartAt H' (f (Set.inclusion hUV x)) ∘ f) diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean index 908659feaf54a..f7b0ade18a085 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean @@ -32,15 +32,19 @@ open Bundle Set Topology variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] - (I'' : ModelWithCorners 𝕜 E'' H'') {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] + {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] section ModelWithCorners namespace ModelWithCorners +/- In general, the model with corner `I` is implicit in most theorems in differential geometry, but +this section is about `I` as a map, not as a parameter. Therefore, we make it explicit. -/ +variable (I) + /-! #### Model with corners -/ protected theorem hasMFDerivAt {x} : HasMFDerivAt I 𝓘(𝕜, E) I x (ContinuousLinearMap.id _ _) := @@ -98,7 +102,7 @@ theorem mdifferentiableAt_atlas (h : e ∈ atlas H M) {x : M} (hx : x ∈ e.sour · apply IsOpen.mem_nhds ((PartialHomeomorph.open_source _).preimage I.continuous_symm) mem.1 theorem mdifferentiableOn_atlas (h : e ∈ atlas H M) : MDifferentiableOn I I e e.source := - fun _x hx => (mdifferentiableAt_atlas I h hx).mdifferentiableWithinAt + fun _x hx => (mdifferentiableAt_atlas h hx).mdifferentiableWithinAt theorem mdifferentiableAt_atlas_symm (h : e ∈ atlas H M) {x : H} (hx : x ∈ e.target) : MDifferentiableAt I I e.symm x := by @@ -119,44 +123,13 @@ theorem mdifferentiableAt_atlas_symm (h : e ∈ atlas H M) {x : H} (hx : x ∈ e · apply IsOpen.mem_nhds ((PartialHomeomorph.open_source _).preimage I.continuous_symm) mem.1 theorem mdifferentiableOn_atlas_symm (h : e ∈ atlas H M) : MDifferentiableOn I I e.symm e.target := - fun _x hx => (mdifferentiableAt_atlas_symm I h hx).mdifferentiableWithinAt + fun _x hx => (mdifferentiableAt_atlas_symm h hx).mdifferentiableWithinAt theorem mdifferentiable_of_mem_atlas (h : e ∈ atlas H M) : e.MDifferentiable I I := - ⟨mdifferentiableOn_atlas I h, mdifferentiableOn_atlas_symm I h⟩ + ⟨mdifferentiableOn_atlas h, mdifferentiableOn_atlas_symm h⟩ theorem mdifferentiable_chart (x : M) : (chartAt H x).MDifferentiable I I := - mdifferentiable_of_mem_atlas _ (chart_mem_atlas _ _) - -/-- The derivative of the chart at a base point is the chart of the tangent bundle, composed with -the identification between the tangent bundle of the model space and the product space. -/ -theorem tangentMap_chart {p q : TangentBundle I M} (h : q.1 ∈ (chartAt H p.1).source) : - tangentMap I I (chartAt H p.1) q = - (TotalSpace.toProd _ _).symm - ((chartAt (ModelProd H E) p : TangentBundle I M → ModelProd H E) q) := by - dsimp [tangentMap] - rw [MDifferentiableAt.mfderiv] - · rfl - · exact mdifferentiableAt_atlas _ (chart_mem_atlas _ _) h - -/-- The derivative of the inverse of the chart at a base point is the inverse of the chart of the -tangent bundle, composed with the identification between the tangent bundle of the model space and -the product space. -/ -theorem tangentMap_chart_symm {p : TangentBundle I M} {q : TangentBundle I H} - (h : q.1 ∈ (chartAt H p.1).target) : - tangentMap I I (chartAt H p.1).symm q = - (chartAt (ModelProd H E) p).symm (TotalSpace.toProd H E q) := by - dsimp only [tangentMap] - rw [MDifferentiableAt.mfderiv (mdifferentiableAt_atlas_symm _ (chart_mem_atlas _ _) h)] - simp only [ContinuousLinearMap.coe_coe, TangentBundle.chartAt, h, tangentBundleCore, - mfld_simps, (· ∘ ·)] - -- `simp` fails to apply `PartialEquiv.prod_symm` with `ModelProd` - congr - exact ((chartAt H (TotalSpace.proj p)).right_inv h).symm - -lemma mfderiv_chartAt_eq_tangentCoordChange {x y : M} (hsrc : x ∈ (chartAt H y).source) : - mfderiv I I (chartAt H y) x = tangentCoordChange I x y x := by - have := mdifferentiableAt_atlas I (ChartedSpace.chart_mem_atlas _) hsrc - simp [mfderiv, if_pos this, Function.comp_assoc] + mdifferentiable_of_mem_atlas (chart_mem_atlas _ _) end Charts @@ -164,7 +137,6 @@ end Charts /-! ### Differentiable partial homeomorphisms -/ namespace PartialHomeomorph.MDifferentiable -variable {I I' I''} variable {e : PartialHomeomorph M M'} (he : e.MDifferentiable I I') {e' : PartialHomeomorph M' M''} include he @@ -176,16 +148,13 @@ protected theorem mdifferentiableAt {x : M} (hx : x ∈ e.source) : MDifferentia theorem mdifferentiableAt_symm {x : M'} (hx : x ∈ e.target) : MDifferentiableAt I' I e.symm x := (he.2 x hx).mdifferentiableAt (e.open_target.mem_nhds hx) -variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] - [SmoothManifoldWithCorners I'' M''] - theorem symm_comp_deriv {x : M} (hx : x ∈ e.source) : (mfderiv I' I e.symm (e x)).comp (mfderiv I I' e x) = ContinuousLinearMap.id 𝕜 (TangentSpace I x) := by have : mfderiv I I (e.symm ∘ e) x = (mfderiv I' I e.symm (e x)).comp (mfderiv I I' e x) := mfderiv_comp x (he.mdifferentiableAt_symm (e.map_source hx)) (he.mdifferentiableAt hx) rw [← this] - have : mfderiv I I (_root_.id : M → M) x = ContinuousLinearMap.id _ _ := mfderiv_id I + have : mfderiv I I (_root_.id : M → M) x = ContinuousLinearMap.id _ _ := mfderiv_id rw [← this] apply Filter.EventuallyEq.mfderiv_eq have : e.source ∈ 𝓝 x := e.open_source.mem_nhds hx @@ -252,24 +221,22 @@ end PartialHomeomorph.MDifferentiable section extChartAt -variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} - [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M] {s : Set M} {x y : M} +variable [SmoothManifoldWithCorners I M] {s : Set M} {x y : M} theorem hasMFDerivAt_extChartAt (h : y ∈ (chartAt H x).source) : HasMFDerivAt I 𝓘(𝕜, E) (extChartAt I x) y (mfderiv I I (chartAt H x) y : _) := - I.hasMFDerivAt.comp y ((mdifferentiable_chart I x).mdifferentiableAt h).hasMFDerivAt + I.hasMFDerivAt.comp y ((mdifferentiable_chart x).mdifferentiableAt h).hasMFDerivAt theorem hasMFDerivWithinAt_extChartAt (h : y ∈ (chartAt H x).source) : HasMFDerivWithinAt I 𝓘(𝕜, E) (extChartAt I x) s y (mfderiv I I (chartAt H x) y : _) := - (hasMFDerivAt_extChartAt I h).hasMFDerivWithinAt + (hasMFDerivAt_extChartAt h).hasMFDerivWithinAt theorem mdifferentiableAt_extChartAt (h : y ∈ (chartAt H x).source) : MDifferentiableAt I 𝓘(𝕜, E) (extChartAt I x) y := - (hasMFDerivAt_extChartAt I h).mdifferentiableAt + (hasMFDerivAt_extChartAt h).mdifferentiableAt theorem mdifferentiableOn_extChartAt : MDifferentiableOn I 𝓘(𝕜, E) (extChartAt I x) (chartAt H x).source := fun _y hy => - (hasMFDerivWithinAt_extChartAt I hy).mdifferentiableWithinAt + (hasMFDerivWithinAt_extChartAt hy).mdifferentiableWithinAt end extChartAt diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean b/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean index a5e16af8e340f..883bc8a09c31f 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ import Mathlib.Geometry.Manifold.MFDeriv.Defs +import Mathlib.Geometry.Manifold.ContMDiff.Defs /-! # Basic properties of the manifold Fréchet derivative @@ -21,6 +22,8 @@ mimicking the API for Fréchet derivatives. noncomputable section +assert_not_exists tangentBundleCore + open scoped Topology Manifold open Set Bundle @@ -39,7 +42,7 @@ variable {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] - {f f₀ f₁ : M → M'} {x : M} {s t : Set M} {g : M' → M''} {u : Set M'} + {f f₁ : M → M'} {x : M} {s t : Set M} {g : M' → M''} {u : Set M'} theorem uniqueMDiffWithinAt_univ : UniqueMDiffWithinAt I univ x := by unfold UniqueMDiffWithinAt @@ -120,12 +123,12 @@ theorem mdifferentiableWithinAt_univ : theorem mdifferentiableWithinAt_inter (ht : t ∈ 𝓝 x) : MDifferentiableWithinAt I I' f (s ∩ t) x ↔ MDifferentiableWithinAt I I' f s x := by rw [MDifferentiableWithinAt, MDifferentiableWithinAt, - (differentiable_within_at_localInvariantProp I I').liftPropWithinAt_inter ht] + differentiableWithinAt_localInvariantProp.liftPropWithinAt_inter ht] theorem mdifferentiableWithinAt_inter' (ht : t ∈ 𝓝[s] x) : MDifferentiableWithinAt I I' f (s ∩ t) x ↔ MDifferentiableWithinAt I I' f s x := by rw [MDifferentiableWithinAt, MDifferentiableWithinAt, - (differentiable_within_at_localInvariantProp I I').liftPropWithinAt_inter' ht] + differentiableWithinAt_localInvariantProp.liftPropWithinAt_inter' ht] theorem MDifferentiableAt.mdifferentiableWithinAt (h : MDifferentiableAt I I' f x) : MDifferentiableWithinAt I I' f s x := @@ -166,7 +169,7 @@ theorem ContMDiffWithinAt.mdifferentiableWithinAt (hf : ContMDiffWithinAt I I' n suffices h : MDifferentiableWithinAt I I' f (s ∩ f ⁻¹' (extChartAt I' (f x)).source) x by rwa [mdifferentiableWithinAt_inter'] at h apply hf.1.preimage_mem_nhdsWithin - exact extChartAt_source_mem_nhds I' (f x) + exact extChartAt_source_mem_nhds (f x) rw [mdifferentiableWithinAt_iff] exact ⟨hf.1.mono inter_subset_left, (hf.2.differentiableWithinAt hn).mono (by mfld_set_tac)⟩ @@ -252,26 +255,21 @@ theorem writtenInExtChartAt_comp (h : ContinuousWithinAt f s x) : 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := by apply @Filter.mem_of_superset _ _ (f ∘ (extChartAt I x).symm ⁻¹' (extChartAt I' (f x)).source) _ - (extChartAt_preimage_mem_nhdsWithin I - (h.preimage_mem_nhdsWithin (extChartAt_source_mem_nhds _ _))) + (extChartAt_preimage_mem_nhdsWithin + (h.preimage_mem_nhdsWithin (extChartAt_source_mem_nhds _))) mfld_set_tac -/- We name the typeclass variables related to `SmoothManifoldWithCorners` structure as they are -necessary in lemmas mentioning the derivative, but not in lemmas about differentiability, so we -want to include them or omit them when necessary. -/ -variable [Is : SmoothManifoldWithCorners I M] [I's : SmoothManifoldWithCorners I' M'] - [I''s : SmoothManifoldWithCorners I'' M''] - {f' f₀' f₁' : TangentSpace I x →L[𝕜] TangentSpace I' (f x)} +variable {f' f₀' f₁' : TangentSpace I x →L[𝕜] TangentSpace I' (f x)} {g' : TangentSpace I' (f x) →L[𝕜] TangentSpace I'' (g (f x))} /-- `UniqueMDiffWithinAt` achieves its goal: it implies the uniqueness of the derivative. -/ -nonrec theorem UniqueMDiffWithinAt.eq (U : UniqueMDiffWithinAt I s x) +protected nonrec theorem UniqueMDiffWithinAt.eq (U : UniqueMDiffWithinAt I s x) (h : HasMFDerivWithinAt I I' f s x f') (h₁ : HasMFDerivWithinAt I I' f s x f₁') : f' = f₁' := by -- Porting note: didn't need `convert` because of finding instances by unification convert U.eq h.2 h₁.2 -theorem UniqueMDiffOn.eq (U : UniqueMDiffOn I s) (hx : x ∈ s) (h : HasMFDerivWithinAt I I' f s x f') - (h₁ : HasMFDerivWithinAt I I' f s x f₁') : f' = f₁' := +protected theorem UniqueMDiffOn.eq (U : UniqueMDiffOn I s) (hx : x ∈ s) + (h : HasMFDerivWithinAt I I' f s x f') (h₁ : HasMFDerivWithinAt I I' f s x f₁') : f' = f₁' := UniqueMDiffWithinAt.eq (U _ hx) h h₁ /-! @@ -280,6 +278,7 @@ theorem UniqueMDiffOn.eq (U : UniqueMDiffOn I s) (hx : x ∈ s) (h : HasMFDerivW We mimic the API for functions between vector spaces -/ +variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] in /-- One can reformulate differentiability within a set at a point as continuity within this set at this point, and differentiability in any chart containing that point. -/ theorem mdifferentiableWithinAt_iff_of_mem_source {x' : M} {y : M'} @@ -288,7 +287,7 @@ theorem mdifferentiableWithinAt_iff_of_mem_source {x' : M} {y : M'} ContinuousWithinAt f s x' ∧ DifferentiableWithinAt 𝕜 (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) ((extChartAt I x).symm ⁻¹' s ∩ Set.range I) ((extChartAt I x) x') := - (differentiable_within_at_localInvariantProp I I').liftPropWithinAt_indep_chart + differentiableWithinAt_localInvariantProp.liftPropWithinAt_indep_chart (StructureGroupoid.chart_mem_maximalAtlas _ x) hx (StructureGroupoid.chart_mem_maximalAtlas _ y) hy @@ -331,13 +330,13 @@ theorem hasMFDerivWithinAt_inter' (h : t ∈ 𝓝[s] x) : HasMFDerivWithinAt I I' f (s ∩ t) x f' ↔ HasMFDerivWithinAt I I' f s x f' := by rw [HasMFDerivWithinAt, HasMFDerivWithinAt, extChartAt_preimage_inter_eq, hasFDerivWithinAt_inter', continuousWithinAt_inter' h] - exact extChartAt_preimage_mem_nhdsWithin I h + exact extChartAt_preimage_mem_nhdsWithin h theorem hasMFDerivWithinAt_inter (h : t ∈ 𝓝 x) : HasMFDerivWithinAt I I' f (s ∩ t) x f' ↔ HasMFDerivWithinAt I I' f s x f' := by rw [HasMFDerivWithinAt, HasMFDerivWithinAt, extChartAt_preimage_inter_eq, hasFDerivWithinAt_inter, continuousWithinAt_inter h] - exact extChartAt_preimage_mem_nhds I h + exact extChartAt_preimage_mem_nhds h theorem HasMFDerivWithinAt.union (hs : HasMFDerivWithinAt I I' f s x f') (ht : HasMFDerivWithinAt I I' f t x f') : HasMFDerivWithinAt I I' f (s ∪ t) x f' := by @@ -404,7 +403,7 @@ theorem mfderivWithin_univ : mfderivWithin I I' f univ = mfderiv I I' f := by theorem mfderivWithin_inter (ht : t ∈ 𝓝 x) : mfderivWithin I I' f (s ∩ t) x = mfderivWithin I I' f s x := by rw [mfderivWithin, mfderivWithin, extChartAt_preimage_inter_eq, mdifferentiableWithinAt_inter ht, - fderivWithin_inter (extChartAt_preimage_mem_nhds I ht)] + fderivWithin_inter (extChartAt_preimage_mem_nhds ht)] theorem mfderivWithin_of_mem_nhds (h : s ∈ 𝓝 x) : mfderivWithin I I' f s x = mfderiv I I' f x := by rw [← mfderivWithin_univ, ← univ_inter s, mfderivWithin_inter h] @@ -418,6 +417,7 @@ theorem mfderivWithin_eq_mfderiv (hs : UniqueMDiffWithinAt I s x) (h : MDifferen rw [← mfderivWithin_univ] exact mfderivWithin_subset (subset_univ _) hs h.mdifferentiableWithinAt +variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] in theorem mdifferentiableAt_iff_of_mem_source {x' : M} {y : M'} (hx : x' ∈ (chartAt H x).source) (hy : f x' ∈ (chartAt H' y).source) : MDifferentiableAt I I' f x' ↔ @@ -479,7 +479,7 @@ theorem HasMFDerivWithinAt.congr_of_eventuallyEq (h : HasMFDerivWithinAt I I' f · have : (extChartAt I x).symm ⁻¹' {y | f₁ y = f y} ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := - extChartAt_preimage_mem_nhdsWithin I h₁ + extChartAt_preimage_mem_nhdsWithin h₁ apply Filter.mem_of_superset this fun y => _ simp (config := { contextual := true }) only [hx, mfld_simps] · simp only [hx, mfld_simps] @@ -586,8 +586,8 @@ theorem HasMFDerivWithinAt.comp (hg : HasMFDerivWithinAt I' I'' g u (f x) g') have : (extChartAt I x).symm ⁻¹' (f ⁻¹' (extChartAt I' (f x)).source) ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := - extChartAt_preimage_mem_nhdsWithin I - (hf.1.preimage_mem_nhdsWithin (extChartAt_source_mem_nhds _ _)) + extChartAt_preimage_mem_nhdsWithin + (hf.1.preimage_mem_nhdsWithin (extChartAt_source_mem_nhds _)) unfold HasMFDerivWithinAt at * rw [← hasFDerivWithinAt_inter' this, ← extChartAt_preimage_inter_eq] at hf ⊢ have : writtenInExtChartAt I I' x f ((extChartAt I x) x) = (extChartAt I' (f x)) (f x) := by diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean index 6a68a762193e5..6d30a6a3b1c43 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean @@ -3,7 +3,8 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ -import Mathlib.Geometry.Manifold.VectorBundle.Tangent +import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners +import Mathlib.Geometry.Manifold.LocalInvariantProperties /-! # The derivative of functions between smooth manifolds @@ -115,11 +116,12 @@ We use the names `MDifferentiable` and `mfderiv`, where the prefix letter `m` me -/ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] - {H' : Type*} [TopologicalSpace H'] (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} + {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] +variable (I I') in /-- Property in the model space of a model with corners of being differentiable within at set at a point, when read in the model vector space. This property will be lifted to manifolds to define differentiable functions between manifolds. -/ @@ -128,7 +130,7 @@ def DifferentiableWithinAtProp (f : H → H') (s : Set H) (x : H) : Prop := /-- Being differentiable in the model space is a local property, invariant under smooth maps. Therefore, it will lift nicely to manifolds. -/ -theorem differentiable_within_at_localInvariantProp : +theorem differentiableWithinAt_localInvariantProp : (contDiffGroupoid ⊤ I).LocalInvariantProp (contDiffGroupoid ⊤ I') (DifferentiableWithinAtProp I I') := { is_local := by @@ -173,15 +175,21 @@ theorem differentiable_within_at_localInvariantProp : · ext y; simp only [mfld_simps] · intro y hy; simp only [mfld_simps] at hy; simpa only [hy, mfld_simps] using hs hy.1 } +@[deprecated (since := "2024-10-10")] +alias differentiable_within_at_localInvariantProp := differentiableWithinAt_localInvariantProp + +variable (I) in /-- Predicate ensuring that, at a point and within a set, a function can have at most one derivative. This is expressed using the preferred chart at the considered point. -/ def UniqueMDiffWithinAt (s : Set M) (x : M) := UniqueDiffWithinAt 𝕜 ((extChartAt I x).symm ⁻¹' s ∩ range I) ((extChartAt I x) x) +variable (I) in /-- Predicate ensuring that, at all points of a set, a function can have at most one derivative. -/ def UniqueMDiffOn (s : Set M) := ∀ x ∈ s, UniqueMDiffWithinAt I s x +variable (I I') in /-- `MDifferentiableWithinAt I I' f s x` indicates that the function `f` between manifolds has a derivative at the point `x` within the set `s`. This is a generalization of `DifferentiableWithinAt` to manifolds. @@ -202,19 +210,18 @@ theorem mdifferentiableWithinAt_iff' (f : M → M') (s : Set M) (x : M) : @[deprecated (since := "2024-04-30")] alias mdifferentiableWithinAt_iff_liftPropWithinAt := mdifferentiableWithinAt_iff' -variable {I I'} in theorem MDifferentiableWithinAt.continuousWithinAt {f : M → M'} {s : Set M} {x : M} (hf : MDifferentiableWithinAt I I' f s x) : ContinuousWithinAt f s x := mdifferentiableWithinAt_iff' .. |>.1 hf |>.1 -variable {I I'} in theorem MDifferentiableWithinAt.differentiableWithinAt_writtenInExtChartAt {f : M → M'} {s : Set M} {x : M} (hf : MDifferentiableWithinAt I I' f s x) : DifferentiableWithinAt 𝕜 (writtenInExtChartAt I I' x f) ((extChartAt I x).symm ⁻¹' s ∩ range I) ((extChartAt I x) x) := mdifferentiableWithinAt_iff' .. |>.1 hf |>.2 +variable (I I') in /-- `MDifferentiableAt I I' f x` indicates that the function `f` between manifolds has a derivative at the point `x`. This is a generalization of `DifferentiableAt` to manifolds. @@ -238,35 +245,35 @@ theorem mdifferentiableAt_iff (f : M → M') (x : M) : @[deprecated (since := "2024-04-30")] alias mdifferentiableAt_iff_liftPropAt := mdifferentiableAt_iff -variable {I I'} in theorem MDifferentiableAt.continuousAt {f : M → M'} {x : M} (hf : MDifferentiableAt I I' f x) : ContinuousAt f x := mdifferentiableAt_iff .. |>.1 hf |>.1 -variable {I I'} in theorem MDifferentiableAt.differentiableWithinAt_writtenInExtChartAt {f : M → M'} {x : M} (hf : MDifferentiableAt I I' f x) : DifferentiableWithinAt 𝕜 (writtenInExtChartAt I I' x f) (range I) ((extChartAt I x) x) := mdifferentiableAt_iff .. |>.1 hf |>.2 +variable (I I') in /-- `MDifferentiableOn I I' f s` indicates that the function `f` between manifolds has a derivative within `s` at all points of `s`. This is a generalization of `DifferentiableOn` to manifolds. -/ def MDifferentiableOn (f : M → M') (s : Set M) := ∀ x ∈ s, MDifferentiableWithinAt I I' f s x +variable (I I') in /-- `MDifferentiable I I' f` indicates that the function `f` between manifolds has a derivative everywhere. This is a generalization of `Differentiable` to manifolds. -/ def MDifferentiable (f : M → M') := ∀ x, MDifferentiableAt I I' f x +variable (I I') in /-- Prop registering if a partial homeomorphism is a local diffeomorphism on its source -/ def PartialHomeomorph.MDifferentiable (f : PartialHomeomorph M M') := MDifferentiableOn I I' f f.source ∧ MDifferentiableOn I' I f.symm f.target -variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] - +variable (I I') in /-- `HasMFDerivWithinAt I I' f s x f'` indicates that the function `f` between manifolds has, at the point `x` and within the set `s`, the derivative `f'`. Here, `f'` is a continuous linear map from the tangent space at `x` to the tangent space at `f x`. @@ -284,6 +291,7 @@ def HasMFDerivWithinAt (f : M → M') (s : Set M) (x : M) HasFDerivWithinAt (writtenInExtChartAt I I' x f : E → E') f' ((extChartAt I x).symm ⁻¹' s ∩ range I) ((extChartAt I x) x) +variable (I I') in /-- `HasMFDerivAt I I' f x f'` indicates that the function `f` between manifolds has, at the point `x`, the derivative `f'`. Here, `f'` is a continuous linear map from the tangent space at `x` to the tangent space at `f x`. @@ -297,6 +305,7 @@ def HasMFDerivAt (f : M → M') (x : M) (f' : TangentSpace I x →L[𝕜] Tangen HasFDerivWithinAt (writtenInExtChartAt I I' x f : E → E') f' (range I) ((extChartAt I x) x) open Classical in +variable (I I') in /-- Let `f` be a function between two smooth manifolds. Then `mfderivWithin I I' f s x` is the derivative of `f` at `x` within `s`, as a continuous linear map from the tangent space at `x` to the tangent space at `f x`. -/ @@ -308,6 +317,7 @@ def mfderivWithin (f : M → M') (s : Set M) (x : M) : TangentSpace I x →L[ else 0 open Classical in +variable (I I') in /-- Let `f` be a function between two smooth manifolds. Then `mfderiv I I' f x` is the derivative of `f` at `x`, as a continuous linear map from the tangent space at `x` to the tangent space at `f x`. -/ @@ -316,10 +326,12 @@ def mfderiv (f : M → M') (x : M) : TangentSpace I x →L[𝕜] TangentSpace I' (fderivWithin 𝕜 (writtenInExtChartAt I I' x f : E → E') (range I) ((extChartAt I x) x) : _) else 0 +variable (I I') in /-- The derivative within a set, as a map between the tangent bundles -/ def tangentMapWithin (f : M → M') (s : Set M) : TangentBundle I M → TangentBundle I' M' := fun p => ⟨f p.1, (mfderivWithin I I' f s p.1 : TangentSpace I p.1 → TangentSpace I' (f p.1)) p.2⟩ +variable (I I') in /-- The derivative, as a map between the tangent bundles -/ def tangentMap (f : M → M') : TangentBundle I M → TangentBundle I' M' := fun p => ⟨f p.1, (mfderiv I I' f p.1 : TangentSpace I p.1 → TangentSpace I' (f p.1)) p.2⟩ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/FDeriv.lean b/Mathlib/Geometry/Manifold/MFDeriv/FDeriv.lean index b0bcd7be1a4a3..40a58337f4b9e 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/FDeriv.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/FDeriv.lean @@ -35,7 +35,7 @@ theorem uniqueMDiffOn_iff_uniqueDiffOn : UniqueMDiffOn 𝓘(𝕜, E) s ↔ Uniqu alias ⟨UniqueMDiffOn.uniqueDiffOn, UniqueDiffOn.uniqueMDiffOn⟩ := uniqueMDiffOn_iff_uniqueDiffOn --- Porting note (#10618): was `@[simp, mfld_simps]` but `simp` can prove it +@[simp, mfld_simps] theorem writtenInExtChartAt_model_space : writtenInExtChartAt 𝓘(𝕜, E) 𝓘(𝕜, E') x f = f := rfl diff --git a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean index 5e0909b901206..2bbe312b6c383 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean @@ -27,13 +27,13 @@ section SpecificFunctions /-! ### Differentiability of specific functions -/ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} - [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M] {E' : Type*} + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} + [TopologicalSpace M] [ChartedSpace H M] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] - (I' : ModelWithCorners 𝕜 E' H') {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] - [SmoothManifoldWithCorners I' M'] {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] - {H'' : Type*} [TopologicalSpace H''] (I'' : ModelWithCorners 𝕜 E'' H'') {M'' : Type*} - [TopologicalSpace M''] [ChartedSpace H'' M''] [SmoothManifoldWithCorners I'' M''] + {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] + {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} + [TopologicalSpace M''] [ChartedSpace H'' M''] namespace ContinuousLinearMap @@ -107,34 +107,34 @@ theorem hasMFDerivAt_id (x : M) : HasMFDerivAt I I (@id M) x (ContinuousLinearMap.id 𝕜 (TangentSpace I x)) := by refine ⟨continuousAt_id, ?_⟩ have : ∀ᶠ y in 𝓝[range I] (extChartAt I x) x, (extChartAt I x ∘ (extChartAt I x).symm) y = y := by - apply Filter.mem_of_superset (extChartAt_target_mem_nhdsWithin I x) + apply Filter.mem_of_superset (extChartAt_target_mem_nhdsWithin x) mfld_set_tac apply HasFDerivWithinAt.congr_of_eventuallyEq (hasFDerivWithinAt_id _ _) this simp only [mfld_simps] theorem hasMFDerivWithinAt_id (s : Set M) (x : M) : HasMFDerivWithinAt I I (@id M) s x (ContinuousLinearMap.id 𝕜 (TangentSpace I x)) := - (hasMFDerivAt_id I x).hasMFDerivWithinAt + (hasMFDerivAt_id x).hasMFDerivWithinAt theorem mdifferentiableAt_id : MDifferentiableAt I I (@id M) x := - (hasMFDerivAt_id I x).mdifferentiableAt + (hasMFDerivAt_id x).mdifferentiableAt theorem mdifferentiableWithinAt_id : MDifferentiableWithinAt I I (@id M) s x := - (mdifferentiableAt_id I).mdifferentiableWithinAt + mdifferentiableAt_id.mdifferentiableWithinAt -theorem mdifferentiable_id : MDifferentiable I I (@id M) := fun _ => mdifferentiableAt_id I +theorem mdifferentiable_id : MDifferentiable I I (@id M) := fun _ => mdifferentiableAt_id theorem mdifferentiableOn_id : MDifferentiableOn I I (@id M) s := - (mdifferentiable_id I).mdifferentiableOn + mdifferentiable_id.mdifferentiableOn @[simp, mfld_simps] theorem mfderiv_id : mfderiv I I (@id M) x = ContinuousLinearMap.id 𝕜 (TangentSpace I x) := - HasMFDerivAt.mfderiv (hasMFDerivAt_id I x) + HasMFDerivAt.mfderiv (hasMFDerivAt_id x) theorem mfderivWithin_id (hxs : UniqueMDiffWithinAt I s x) : mfderivWithin I I (@id M) s x = ContinuousLinearMap.id 𝕜 (TangentSpace I x) := by - rw [MDifferentiable.mfderivWithin (mdifferentiableAt_id I) hxs] - exact mfderiv_id I + rw [MDifferentiable.mfderivWithin mdifferentiableAt_id hxs] + exact mfderiv_id @[simp, mfld_simps] theorem tangentMap_id : tangentMap I I (id : M → M) = id := by ext1 ⟨x, v⟩; simp [tangentMap] @@ -162,28 +162,28 @@ theorem hasMFDerivAt_const (c : M') (x : M) : theorem hasMFDerivWithinAt_const (c : M') (s : Set M) (x : M) : HasMFDerivWithinAt I I' (fun _ : M => c) s x (0 : TangentSpace I x →L[𝕜] TangentSpace I' c) := - (hasMFDerivAt_const I I' c x).hasMFDerivWithinAt + (hasMFDerivAt_const c x).hasMFDerivWithinAt theorem mdifferentiableAt_const : MDifferentiableAt I I' (fun _ : M => c) x := - (hasMFDerivAt_const I I' c x).mdifferentiableAt + (hasMFDerivAt_const c x).mdifferentiableAt theorem mdifferentiableWithinAt_const : MDifferentiableWithinAt I I' (fun _ : M => c) s x := - (mdifferentiableAt_const I I').mdifferentiableWithinAt + mdifferentiableAt_const.mdifferentiableWithinAt theorem mdifferentiable_const : MDifferentiable I I' fun _ : M => c := fun _ => - mdifferentiableAt_const I I' + mdifferentiableAt_const theorem mdifferentiableOn_const : MDifferentiableOn I I' (fun _ : M => c) s := - (mdifferentiable_const I I').mdifferentiableOn + mdifferentiable_const.mdifferentiableOn @[simp, mfld_simps] theorem mfderiv_const : mfderiv I I' (fun _ : M => c) x = (0 : TangentSpace I x →L[𝕜] TangentSpace I' c) := - HasMFDerivAt.mfderiv (hasMFDerivAt_const I I' c x) + HasMFDerivAt.mfderiv (hasMFDerivAt_const c x) theorem mfderivWithin_const (hxs : UniqueMDiffWithinAt I s x) : mfderivWithin I I' (fun _ : M => c) s x = (0 : TangentSpace I x →L[𝕜] TangentSpace I' c) := - (hasMFDerivWithinAt_const _ _ _ _ _).mfderivWithin hxs + (hasMFDerivWithinAt_const _ _ _).mfderivWithin hxs end Const @@ -202,42 +202,42 @@ theorem hasMFDerivAt_fst (x : M × M') : apply Filter.mem_of_superset (extChartAt_target_mem_nhdsWithin (I.prod I') x) mfld_set_tac -/ - filter_upwards [extChartAt_target_mem_nhdsWithin (I.prod I') x] with y hy + filter_upwards [extChartAt_target_mem_nhdsWithin x] with y hy rw [extChartAt_prod] at hy exact (extChartAt I x.1).right_inv hy.1 apply HasFDerivWithinAt.congr_of_eventuallyEq hasFDerivWithinAt_fst this -- Porting note: next line was `simp only [mfld_simps]` - exact (extChartAt I x.1).right_inv <| (extChartAt I x.1).map_source (mem_extChartAt_source _ _) + exact (extChartAt I x.1).right_inv <| (extChartAt I x.1).map_source (mem_extChartAt_source _) theorem hasMFDerivWithinAt_fst (s : Set (M × M')) (x : M × M') : HasMFDerivWithinAt (I.prod I') I Prod.fst s x (ContinuousLinearMap.fst 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2)) := - (hasMFDerivAt_fst I I' x).hasMFDerivWithinAt + (hasMFDerivAt_fst x).hasMFDerivWithinAt theorem mdifferentiableAt_fst {x : M × M'} : MDifferentiableAt (I.prod I') I Prod.fst x := - (hasMFDerivAt_fst I I' x).mdifferentiableAt + (hasMFDerivAt_fst x).mdifferentiableAt theorem mdifferentiableWithinAt_fst {s : Set (M × M')} {x : M × M'} : MDifferentiableWithinAt (I.prod I') I Prod.fst s x := - (mdifferentiableAt_fst I I').mdifferentiableWithinAt + mdifferentiableAt_fst.mdifferentiableWithinAt theorem mdifferentiable_fst : MDifferentiable (I.prod I') I (Prod.fst : M × M' → M) := fun _ => - mdifferentiableAt_fst I I' + mdifferentiableAt_fst theorem mdifferentiableOn_fst {s : Set (M × M')} : MDifferentiableOn (I.prod I') I Prod.fst s := - (mdifferentiable_fst I I').mdifferentiableOn + mdifferentiable_fst.mdifferentiableOn @[simp, mfld_simps] theorem mfderiv_fst {x : M × M'} : mfderiv (I.prod I') I Prod.fst x = ContinuousLinearMap.fst 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2) := - (hasMFDerivAt_fst I I' x).mfderiv + (hasMFDerivAt_fst x).mfderiv theorem mfderivWithin_fst {s : Set (M × M')} {x : M × M'} (hxs : UniqueMDiffWithinAt (I.prod I') s x) : mfderivWithin (I.prod I') I Prod.fst s x = ContinuousLinearMap.fst 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2) := by - rw [MDifferentiable.mfderivWithin (mdifferentiableAt_fst I I') hxs]; exact mfderiv_fst I I' + rw [MDifferentiable.mfderivWithin mdifferentiableAt_fst hxs]; exact mfderiv_fst @[simp, mfld_simps] theorem tangentMap_prod_fst {p : TangentBundle (I.prod I') (M × M')} : @@ -264,42 +264,42 @@ theorem hasMFDerivAt_snd (x : M × M') : apply Filter.mem_of_superset (extChartAt_target_mem_nhdsWithin (I.prod I') x) mfld_set_tac -/ - filter_upwards [extChartAt_target_mem_nhdsWithin (I.prod I') x] with y hy + filter_upwards [extChartAt_target_mem_nhdsWithin x] with y hy rw [extChartAt_prod] at hy exact (extChartAt I' x.2).right_inv hy.2 apply HasFDerivWithinAt.congr_of_eventuallyEq hasFDerivWithinAt_snd this -- Porting note: the next line was `simp only [mfld_simps]` - exact (extChartAt I' x.2).right_inv <| (extChartAt I' x.2).map_source (mem_extChartAt_source _ _) + exact (extChartAt I' x.2).right_inv <| (extChartAt I' x.2).map_source (mem_extChartAt_source _) theorem hasMFDerivWithinAt_snd (s : Set (M × M')) (x : M × M') : HasMFDerivWithinAt (I.prod I') I' Prod.snd s x (ContinuousLinearMap.snd 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2)) := - (hasMFDerivAt_snd I I' x).hasMFDerivWithinAt + (hasMFDerivAt_snd x).hasMFDerivWithinAt theorem mdifferentiableAt_snd {x : M × M'} : MDifferentiableAt (I.prod I') I' Prod.snd x := - (hasMFDerivAt_snd I I' x).mdifferentiableAt + (hasMFDerivAt_snd x).mdifferentiableAt theorem mdifferentiableWithinAt_snd {s : Set (M × M')} {x : M × M'} : MDifferentiableWithinAt (I.prod I') I' Prod.snd s x := - (mdifferentiableAt_snd I I').mdifferentiableWithinAt + mdifferentiableAt_snd.mdifferentiableWithinAt theorem mdifferentiable_snd : MDifferentiable (I.prod I') I' (Prod.snd : M × M' → M') := fun _ => - mdifferentiableAt_snd I I' + mdifferentiableAt_snd theorem mdifferentiableOn_snd {s : Set (M × M')} : MDifferentiableOn (I.prod I') I' Prod.snd s := - (mdifferentiable_snd I I').mdifferentiableOn + mdifferentiable_snd.mdifferentiableOn @[simp, mfld_simps] theorem mfderiv_snd {x : M × M'} : mfderiv (I.prod I') I' Prod.snd x = ContinuousLinearMap.snd 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2) := - (hasMFDerivAt_snd I I' x).mfderiv + (hasMFDerivAt_snd x).mfderiv theorem mfderivWithin_snd {s : Set (M × M')} {x : M × M'} (hxs : UniqueMDiffWithinAt (I.prod I') s x) : mfderivWithin (I.prod I') I' Prod.snd s x = ContinuousLinearMap.snd 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2) := by - rw [MDifferentiable.mfderivWithin (mdifferentiableAt_snd I I') hxs]; exact mfderiv_snd I I' + rw [MDifferentiable.mfderivWithin mdifferentiableAt_snd hxs]; exact mfderiv_snd @[simp, mfld_simps] theorem tangentMap_prod_snd {p : TangentBundle (I.prod I') (M × M')} : @@ -315,8 +315,6 @@ theorem tangentMapWithin_prod_snd {s : Set (M × M')} {p : TangentBundle (I.prod · rcases p with ⟨⟩; rfl · exact hs -variable {I I' I''} - theorem MDifferentiableAt.mfderiv_prod {f : M → M'} {g : M → M''} {x : M} (hf : MDifferentiableAt I I' f x) (hg : MDifferentiableAt I I'' g x) : mfderiv I (I'.prod I'') (fun x => (f x, g x)) x = @@ -326,18 +324,16 @@ theorem MDifferentiableAt.mfderiv_prod {f : M → M'} {g : M → M''} {x : M} exact hf.differentiableWithinAt_writtenInExtChartAt.fderivWithin_prod hg.differentiableWithinAt_writtenInExtChartAt (I.uniqueDiffOn _ (mem_range_self _)) -variable (I I' I'') - theorem mfderiv_prod_left {x₀ : M} {y₀ : M'} : mfderiv I (I.prod I') (fun x => (x, y₀)) x₀ = ContinuousLinearMap.inl 𝕜 (TangentSpace I x₀) (TangentSpace I' y₀) := by - refine ((mdifferentiableAt_id I).mfderiv_prod (mdifferentiableAt_const I I')).trans ?_ + refine (mdifferentiableAt_id.mfderiv_prod mdifferentiableAt_const).trans ?_ rw [mfderiv_id, mfderiv_const, ContinuousLinearMap.inl] theorem mfderiv_prod_right {x₀ : M} {y₀ : M'} : mfderiv I' (I.prod I') (fun y => (x₀, y)) y₀ = ContinuousLinearMap.inr 𝕜 (TangentSpace I x₀) (TangentSpace I' y₀) := by - refine ((mdifferentiableAt_const I' I).mfderiv_prod (mdifferentiableAt_id I')).trans ?_ + refine (mdifferentiableAt_const.mfderiv_prod mdifferentiableAt_id).trans ?_ rw [mfderiv_id, mfderiv_const, ContinuousLinearMap.inr] /-- The total derivative of a function in two variables is the sum of the partial derivatives. @@ -350,12 +346,11 @@ theorem mfderiv_prod_eq_add {f : M × M' → M''} {p : M × M'} mfderiv (I.prod I') I'' (fun z : M × M' => f (z.1, p.2)) p + mfderiv (I.prod I') I'' (fun z : M × M' => f (p.1, z.2)) p := by dsimp only - erw [mfderiv_comp_of_eq hf ((mdifferentiableAt_fst I I').prod_mk (mdifferentiableAt_const _ _)) - rfl, - mfderiv_comp_of_eq hf ((mdifferentiableAt_const _ _).prod_mk (mdifferentiableAt_snd I I')) rfl, + erw [mfderiv_comp_of_eq hf (mdifferentiableAt_fst.prod_mk mdifferentiableAt_const) rfl, + mfderiv_comp_of_eq hf (mdifferentiableAt_const.prod_mk mdifferentiableAt_snd) rfl, ← ContinuousLinearMap.comp_add, - (mdifferentiableAt_fst I I').mfderiv_prod (mdifferentiableAt_const (I.prod I') I'), - (mdifferentiableAt_const (I.prod I') I).mfderiv_prod (mdifferentiableAt_snd I I'), mfderiv_fst, + mdifferentiableAt_fst.mfderiv_prod mdifferentiableAt_const, + mdifferentiableAt_const.mfderiv_prod mdifferentiableAt_snd, mfderiv_fst, mfderiv_snd, mfderiv_const, mfderiv_const] symm convert ContinuousLinearMap.comp_id <| mfderiv (.prod I I') I'' f (p.1, p.2) @@ -374,7 +369,6 @@ canonical, but in this case (the tangent space of a vector space) it is canonica section Group -variable {I} variable {z : M} {f g : M → E'} {f' g' : TangentSpace I z →L[𝕜] E'} theorem HasMFDerivAt.add (hf : HasMFDerivAt I 𝓘(𝕜, E') f z f') @@ -460,7 +454,6 @@ end Group section AlgebraOverRing -variable {I} variable {z : M} {F' : Type*} [NormedRing F'] [NormedAlgebra 𝕜 F'] {p q : M → F'} {p' q' : TangentSpace I z →L[𝕜] F'} @@ -495,7 +488,6 @@ end AlgebraOverRing section AlgebraOverCommRing -variable {I} variable {z : M} {F' : Type*} [NormedCommRing F'] [NormedAlgebra 𝕜 F'] {p q : M → F'} {p' q' : TangentSpace I z →L[𝕜] F'} diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean new file mode 100644 index 0000000000000..4814f3ebcafdf --- /dev/null +++ b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean @@ -0,0 +1,60 @@ +/- +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, Floris van Doorn +-/ +import Mathlib.Geometry.Manifold.MFDeriv.Atlas +import Mathlib.Geometry.Manifold.MFDeriv.UniqueDifferential +import Mathlib.Geometry.Manifold.VectorBundle.Tangent + +/-! +# Derivatives of maps in the tangent bundle + +This file contains properties of derivatives which need the manifold structure of the tangent +bundle. Notably, it includes formulas for the tangent maps to charts, and unique differentiability +statements for subsets of the tangent bundle. +-/ + +open Bundle + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + [SmoothManifoldWithCorners I M] + +/-- The derivative of the chart at a base point is the chart of the tangent bundle, composed with +the identification between the tangent bundle of the model space and the product space. -/ +theorem tangentMap_chart {p q : TangentBundle I M} (h : q.1 ∈ (chartAt H p.1).source) : + tangentMap I I (chartAt H p.1) q = + (TotalSpace.toProd _ _).symm + ((chartAt (ModelProd H E) p : TangentBundle I M → ModelProd H E) q) := by + dsimp [tangentMap] + rw [MDifferentiableAt.mfderiv] + · rfl + · exact mdifferentiableAt_atlas (chart_mem_atlas _ _) h + +/-- The derivative of the inverse of the chart at a base point is the inverse of the chart of the +tangent bundle, composed with the identification between the tangent bundle of the model space and +the product space. -/ +theorem tangentMap_chart_symm {p : TangentBundle I M} {q : TangentBundle I H} + (h : q.1 ∈ (chartAt H p.1).target) : + tangentMap I I (chartAt H p.1).symm q = + (chartAt (ModelProd H E) p).symm (TotalSpace.toProd H E q) := by + dsimp only [tangentMap] + rw [MDifferentiableAt.mfderiv (mdifferentiableAt_atlas_symm (chart_mem_atlas _ _) h)] + simp only [ContinuousLinearMap.coe_coe, TangentBundle.chartAt, h, tangentBundleCore, + mfld_simps, (· ∘ ·)] + -- `simp` fails to apply `PartialEquiv.prod_symm` with `ModelProd` + congr + exact ((chartAt H (TotalSpace.proj p)).right_inv h).symm + +lemma mfderiv_chartAt_eq_tangentCoordChange {x y : M} (hsrc : x ∈ (chartAt H y).source) : + mfderiv I I (chartAt H y) x = tangentCoordChange I x y x := by + have := mdifferentiableAt_atlas (I := I) (ChartedSpace.chart_mem_atlas _) hsrc + simp [mfderiv, if_pos this, Function.comp_assoc] + +/-- The preimage under the projection from the tangent bundle of a set with unique differential in +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 _ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean index d73131e3999fb..4facc7f820910 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ import Mathlib.Geometry.Manifold.MFDeriv.Atlas +import Mathlib.Geometry.Manifold.VectorBundle.Basic /-! # Unique derivative sets in manifolds @@ -32,11 +33,10 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom [TopologicalSpace M] [ChartedSpace H M] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] - [SmoothManifoldWithCorners I' M'] {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H' M''] + {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H' M''] {s : Set M} {x : M} section -variable [SmoothManifoldWithCorners I M] /-- If `s` has the unique differential property at `x`, `f` is differentiable within `s` at x` and its derivative has dense range, then `f '' s` has the unique differential property at `f x`. -/ @@ -44,7 +44,7 @@ theorem UniqueMDiffWithinAt.image_denseRange (hs : UniqueMDiffWithinAt I s x) {f : M → M'} {f' : E →L[𝕜] E'} (hf : HasMFDerivWithinAt I I' f s x f') (hd : DenseRange f') : UniqueMDiffWithinAt I' (f '' s) (f x) := by /- Rewrite in coordinates, apply `HasFDerivWithinAt.uniqueDiffWithinAt`. -/ - have := hs.inter' <| hf.1 (extChartAt_source_mem_nhds I' (f x)) + have := hs.inter' <| hf.1 (extChartAt_source_mem_nhds (I := I') (f x)) refine (((hf.2.mono ?sub1).uniqueDiffWithinAt this hd).mono ?sub2).congr_pt ?pt case pt => simp only [mfld_simps] case sub1 => mfld_set_tac @@ -82,6 +82,7 @@ theorem UniqueMDiffOn.uniqueMDiffOn_preimage (hs : UniqueMDiffOn I s) {e : Parti (he : e.MDifferentiable I I') : UniqueMDiffOn I' (e.target ∩ e.symm ⁻¹' s) := fun _x hx ↦ e.right_inv hx.1 ▸ (hs _ hx.2).preimage_partialHomeomorph he (e.map_target hx.1) +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) : @@ -91,9 +92,10 @@ theorem UniqueMDiffOn.uniqueDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) 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 I hy.2) - fun y hy ↦ ((mdifferentiable_chart _ _).mfderiv_surjective hy.2).denseRange + (fun y hy ↦ hasMFDerivWithinAt_extChartAt hy.2) + fun y hy ↦ ((mdifferentiable_chart _).mfderiv_surjective hy.2).denseRange +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 be read in the charts. -/ @@ -105,7 +107,7 @@ theorem UniqueMDiffOn.uniqueDiffOn_inter_preimage (hs : UniqueMDiffOn I s) (x : intro z hz apply (hs z hz.1).inter' apply (hf z hz.1).preimage_mem_nhdsWithin - exact (isOpen_extChartAt_source I' y).mem_nhds hz.2 + exact (isOpen_extChartAt_source y).mem_nhds hz.2 this.uniqueDiffOn_target_inter _ end @@ -118,9 +120,7 @@ variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {Z : M → Type theorem Trivialization.mdifferentiable (e : Trivialization F (π F Z)) [MemTrivializationAtlas e] : e.toPartialHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := - ⟨(e.smoothOn I).mdifferentiableOn, (e.smoothOn_symm I).mdifferentiableOn⟩ - -variable [SmoothManifoldWithCorners I M] + ⟨e.smoothOn.mdifferentiableOn, e.smoothOn_symm.mdifferentiableOn⟩ theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} (hs : UniqueMDiffWithinAt I s p.proj) : @@ -147,10 +147,4 @@ theorem UniqueMDiffOn.smooth_bundle_preimage (hs : UniqueMDiffOn I s) : UniqueMDiffOn (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) := fun _p hp ↦ (hs _ hp).smooth_bundle_preimage -/-- The preimage under the projection from the tangent bundle of a set with unique differential in -the basis also has unique differential. -/ -theorem UniqueMDiffOn.tangentBundle_proj_preimage (hs : UniqueMDiffOn I s) : - UniqueMDiffOn I.tangent (π E (TangentSpace I) ⁻¹' s) := - hs.smooth_bundle_preimage _ - end UniqueMDiff diff --git a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean index d0c29cb8d57a6..db39ef95a11c9 100644 --- a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean +++ b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean @@ -371,7 +371,6 @@ theorem IsSubordinate.support_subset {fs : SmoothBumpCovering ι I M s} {U : M Subset.trans subset_closure (h i) variable (I) in - /-- Let `M` be a smooth manifold with corners modelled on a finite dimensional real vector space. Suppose also that `M` is a Hausdorff `σ`-compact topological space. Let `s` be a closed set in `M` and `U : M → Set M` be a collection of sets such that `U x ∈ 𝓝 x` for every `x ∈ s`. @@ -383,7 +382,7 @@ theorem exists_isSubordinate [T2Space M] [SigmaCompactSpace M] (hs : IsClosed s) haveI : LocallyCompactSpace H := I.locallyCompactSpace haveI : LocallyCompactSpace M := ChartedSpace.locallyCompactSpace H M -- Next we choose a covering by supports of smooth bump functions - have hB := fun x hx => SmoothBumpFunction.nhds_basis_support I (hU x hx) + have hB := fun x hx => SmoothBumpFunction.nhds_basis_support (I := I) (hU x hx) rcases refinement_of_locallyCompact_sigmaCompact_of_nhds_basis_set hs hB with ⟨ι, c, f, hf, hsub', hfin⟩ choose hcs hfU using hf @@ -718,7 +717,7 @@ theorem IsOpen.exists_msmooth_support_eq {s : Set M} (hs : IsOpen s) : · apply SmoothPartitionOfUnity.smooth_finsum_smul intro c x hx apply (g_diff c (chartAt H c x)).comp - exact contMDiffAt_of_mem_maximalAtlas (SmoothManifoldWithCorners.chart_mem_maximalAtlas I _) + exact contMDiffAt_of_mem_maximalAtlas (SmoothManifoldWithCorners.chart_mem_maximalAtlas _) (hf c hx) · intro x apply finsum_nonneg (fun c ↦ h''g c x) diff --git a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean index fcd7714d974ef..468a549418177 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean @@ -54,7 +54,7 @@ theorem smoothSheafCommRing.isUnit_stalk_iff {x : M} obtain ⟨U : Opens M, hxU, f : C^∞⟮IM, U; 𝓘(𝕜), 𝕜⟯, rfl⟩ := S.germ_exist x f have hf' : f ⟨x, hxU⟩ ≠ 0 := by convert hf - exact (smoothSheafCommRing.eval_germ U ⟨x, hxU⟩ f).symm + exact (smoothSheafCommRing.eval_germ U x hxU f).symm -- In fact, by continuity, `f` is nonzero on a neighbourhood `V` of `x` have H : ∀ᶠ (z : U) in 𝓝 ⟨x, hxU⟩, f z ≠ 0 := f.2.continuous.continuousAt.eventually_ne hf' rw [eventually_nhds_iff] at H @@ -77,8 +77,8 @@ theorem smoothSheafCommRing.isUnit_stalk_iff {x : M} -- Let `g` be the pointwise inverse of `f` on `V`, which is smooth since `f` is nonzero there let g : C^∞⟮IM, V; 𝓘(𝕜), 𝕜⟯ := ⟨(f ∘ Set.inclusion hUV)⁻¹, ?_⟩ -- The germ of `g` is inverse to the germ of `f`, so `f` is a unit - · refine ⟨⟨S.germ ⟨x, hxV⟩ (SmoothMap.restrictRingHom IM 𝓘(𝕜) 𝕜 hUV f), S.germ ⟨x, hxV⟩ g, - ?_, ?_⟩, S.germ_res_apply hUV.hom ⟨x, hxV⟩ f⟩ + · refine ⟨⟨S.germ _ x (hxV) (SmoothMap.restrictRingHom IM 𝓘(𝕜) 𝕜 hUV f), S.germ _ x hxV g, + ?_, ?_⟩, S.germ_res_apply hUV.hom x hxV f⟩ · rw [← map_mul] -- Qualified the name to avoid Lean not finding a `OneHomClass` #8386 convert RingHom.map_one _ diff --git a/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean b/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean index 3fb40aacdf854..1bb560ec583ab 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean @@ -82,13 +82,13 @@ section TypeCat /-- The sheaf of smooth functions from `M` to `N`, as a sheaf of types. -/ def smoothSheaf : TopCat.Sheaf (Type u) (TopCat.of M) := - (contDiffWithinAt_localInvariantProp IM I ⊤).sheaf M N + (contDiffWithinAt_localInvariantProp (I := IM) (I' := I) ⊤).sheaf M N variable {M} instance smoothSheaf.coeFun (U : (Opens (TopCat.of M))ᵒᵖ) : CoeFun ((smoothSheaf IM I M N).presheaf.obj U) (fun _ ↦ ↑(unop U) → N) := - (contDiffWithinAt_localInvariantProp IM I ⊤).sheafHasCoeToFun _ _ _ + (contDiffWithinAt_localInvariantProp ⊤).sheafHasCoeToFun _ _ _ open Manifold in /-- The object of `smoothSheaf IM I M N` for the open set `U` in `M` is @@ -132,15 +132,15 @@ instance [Nontrivial N] (x : M) : Nontrivial ((smoothSheaf IM I M N).presheaf.st variable {IM I N} -@[simp] lemma smoothSheaf.eval_germ (U : Opens M) (x : U) +@[simp] lemma smoothSheaf.eval_germ (U : Opens M) (x : M) (hx : x ∈ U) (f : (smoothSheaf IM I M N).presheaf.obj (op U)) : - smoothSheaf.eval IM I N (x : M) ((smoothSheaf IM I M N).presheaf.germ x f) = f x := - TopCat.stalkToFiber_germ ((contDiffWithinAt_localInvariantProp IM I ⊤).localPredicate M N) _ _ _ + smoothSheaf.eval IM I N (x : M) ((smoothSheaf IM I M N).presheaf.germ U x hx f) = f ⟨x, hx⟩ := + TopCat.stalkToFiber_germ ((contDiffWithinAt_localInvariantProp ⊤).localPredicate M N) _ _ _ _ lemma smoothSheaf.smooth_section {U : (Opens (TopCat.of M))ᵒᵖ} (f : (smoothSheaf IM I M N).presheaf.obj U) : Smooth IM I f := - (contDiffWithinAt_localInvariantProp IM I ⊤).section_spec _ _ _ _ + (contDiffWithinAt_localInvariantProp ⊤).section_spec _ _ _ _ end TypeCat @@ -278,7 +278,7 @@ example : (CategoryTheory.sheafCompose _ (CategoryTheory.forget CommRingCat.{u}) instance smoothSheafCommRing.coeFun (U : (Opens (TopCat.of M))ᵒᵖ) : CoeFun ((smoothSheafCommRing IM I M R).presheaf.obj U) (fun _ ↦ ↑(unop U) → R) := - (contDiffWithinAt_localInvariantProp IM I ⊤).sheafHasCoeToFun _ _ _ + (contDiffWithinAt_localInvariantProp ⊤).sheafHasCoeToFun _ _ _ open CategoryTheory Limits @@ -298,7 +298,7 @@ def smoothSheafCommRing.forgetStalk (x : TopCat.of M) : (colimit.ι ((OpenNhds.inclusion x).op ⋙ (smoothSheafCommRing IM I M R).presheaf) U)) (forgetStalk IM I M R x).hom = colimit.ι ((OpenNhds.inclusion x).op ⋙ (smoothSheaf IM I M R).presheaf) U := - ι_preservesColimitsIso_hom _ _ _ + ι_preservesColimitIso_hom _ _ _ @[simp, reassoc, elementwise] lemma smoothSheafCommRing.ι_forgetStalk_inv (x : TopCat.of M) (U) : colimit.ι ((OpenNhds.inclusion x).op ⋙ (smoothSheaf IM I M R).presheaf) U ≫ @@ -333,12 +333,12 @@ def smoothSheafCommRing.eval (x : M) : (smoothSheafCommRing IM I M R).presheaf.s smoothSheafCommRing.evalAt _ _ _ _ _ _ := colimit.ι_desc _ _ -@[simp] lemma smoothSheafCommRing.evalHom_germ (U : Opens (TopCat.of M)) (x : U) +@[simp] lemma smoothSheafCommRing.evalHom_germ (U : Opens (TopCat.of M)) (x : M) (hx : x ∈ U) (f : (smoothSheafCommRing IM I M R).presheaf.obj (op U)) : smoothSheafCommRing.evalHom IM I M R (x : TopCat.of M) - ((smoothSheafCommRing IM I M R).presheaf.germ x f) - = f x := - congr_arg (fun a ↦ a f) <| smoothSheafCommRing.ι_evalHom IM I M R x ⟨U, x.2⟩ + ((smoothSheafCommRing IM I M R).presheaf.germ U x hx f) + = f ⟨x, hx⟩ := + congr_arg (fun a ↦ a f) <| smoothSheafCommRing.ι_evalHom IM I M R x ⟨U, hx⟩ @[simp, reassoc, elementwise] lemma smoothSheafCommRing.forgetStalk_inv_comp_eval (x : TopCat.of M) : @@ -372,10 +372,10 @@ instance [Nontrivial R] (x : M) : Nontrivial ((smoothSheafCommRing IM I M R).pre variable {IM I M R} -@[simp] lemma smoothSheafCommRing.eval_germ (U : Opens M) (x : U) +@[simp] lemma smoothSheafCommRing.eval_germ (U : Opens M) (x : M) (hx : x ∈ U) (f : (smoothSheafCommRing IM I M R).presheaf.obj (op U)) : - smoothSheafCommRing.eval IM I M R x ((smoothSheafCommRing IM I M R).presheaf.germ x f) - = f x := - smoothSheafCommRing.evalHom_germ IM I M R U x f + smoothSheafCommRing.eval IM I M R x ((smoothSheafCommRing IM I M R).presheaf.germ U x hx f) + = f ⟨x, hx⟩ := + smoothSheafCommRing.evalHom_germ IM I M R U x hx f end SmoothCommRing diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 1b1e09a291612..8b27a6abfaa2b 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -3,9 +3,11 @@ 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.Geometry.Manifold.ChartedSpace +import Mathlib.Analysis.Convex.Normed import Mathlib.Analysis.Normed.Module.FiniteDimension import Mathlib.Analysis.Calculus.ContDiff.Basic +import Mathlib.Data.Bundle +import Mathlib.Geometry.Manifold.ChartedSpace /-! # Smooth manifolds (possibly with boundary or corners) @@ -80,6 +82,14 @@ but again in product manifolds the natural model with corners will not be this o one (and they are not defeq as `(fun p : E × F ↦ (p.1, p.2))` is not defeq to the identity). So, it is important to use the above incantation to maximize the applicability of theorems. +We also define `TangentSpace I (x : M)` as a type synonym of `E`, and `TangentBundle I M` as a +type synonym for `Π (x : M), TangentSpace I x` (in the form of an +abbrev of `Bundle.TotalSpace E (TangentSpace I : M → Type _)`). Apart from basic typeclasses on +`TangentSpace I x`, nothing is proved about them in this file, but it is useful to have them +available as definitions early on to get a clean import structure below. The smooth bundle structure +is defined in `VectorBundle.Tangent`, while the definition is used to talk about manifold +derivatives in `MFDeriv.Basic`, and neither file needs import the other. + ## Implementation notes We want to talk about manifolds modelled on a vector space, but also on manifolds with @@ -270,19 +280,22 @@ protected theorem image_eq (s : Set H) : I '' s = I.symm ⁻¹' s ∩ range I := · rw [I.source_eq]; exact subset_univ _ · rw [inter_comm, I.target_eq, I.toPartialEquiv_coe_symm] -protected theorem closedEmbedding : ClosedEmbedding I := - I.leftInverse.closedEmbedding I.continuous_symm I.continuous +theorem isClosedEmbedding : IsClosedEmbedding I := + I.leftInverse.isClosedEmbedding I.continuous_symm I.continuous + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding := isClosedEmbedding theorem isClosed_range : IsClosed (range I) := - I.closedEmbedding.isClosed_range + I.isClosedEmbedding.isClosed_range @[deprecated (since := "2024-03-17")] alias closed_range := isClosed_range theorem map_nhds_eq (x : H) : map I (𝓝 x) = 𝓝[range I] I x := - I.closedEmbedding.toEmbedding.map_nhds_eq x + I.isClosedEmbedding.isEmbedding.map_nhds_eq x theorem map_nhdsWithin_eq (s : Set H) (x : H) : map I (𝓝[s] x) = 𝓝[I '' s] I x := - I.closedEmbedding.toEmbedding.map_nhdsWithin_eq s x + I.isClosedEmbedding.isEmbedding.map_nhdsWithin_eq s x theorem image_mem_nhdsWithin {x : H} {s : Set H} (hs : s ∈ 𝓝 x) : I '' s ∈ 𝓝[range I] I x := I.map_nhds_eq x ▸ image_mem_map hs @@ -338,7 +351,7 @@ open TopologicalSpace protected theorem secondCountableTopology [SecondCountableTopology E] (I : ModelWithCorners 𝕜 E H) : SecondCountableTopology H := - I.closedEmbedding.toEmbedding.secondCountableTopology + I.isClosedEmbedding.isEmbedding.secondCountableTopology end ModelWithCorners @@ -407,9 +420,9 @@ abbrev ModelWithCorners.tangent {𝕜 : Type u} [NontriviallyNormedField 𝕜] { variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {F : Type*} - [NormedAddCommGroup F] [NormedSpace 𝕜 F] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] + [NormedAddCommGroup F] [NormedSpace 𝕜 F] {H : Type*} [TopologicalSpace H] {H' : Type*} [TopologicalSpace H'] {G : Type*} - [TopologicalSpace G] {G' : Type*} [TopologicalSpace G'] {I : ModelWithCorners 𝕜 E H} + [TopologicalSpace G] {I : ModelWithCorners 𝕜 E H} {J : ModelWithCorners 𝕜 F G} @[simp, mfld_simps] @@ -483,11 +496,10 @@ section contDiffGroupoid variable {m n : ℕ∞} {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] -variable (n) - +variable (n I) in /-- Given a model with corners `(E, H)`, we define the pregroupoid of `C^n` transformations of `H` as the maps that are `C^n` when read in `E` through `I`. -/ def contDiffPregroupoid : Pregroupoid H where @@ -526,13 +538,12 @@ def contDiffPregroupoid : Pregroupoid H where simp only [mfld_simps] at hy1 ⊢ rw [fg _ hy1] +variable (n I) in /-- Given a model with corners `(E, H)`, we define the groupoid of invertible `C^n` transformations of `H` as the invertible maps that are `C^n` when read in `E` through `I`. -/ def contDiffGroupoid : StructureGroupoid H := Pregroupoid.groupoid (contDiffPregroupoid n I) -variable {n} - /-- Inclusion of the groupoid of `C^n` local diffeos in the groupoid of `C^m` local diffeos when `m ≤ n` -/ theorem contDiffGroupoid_le (h : m ≤ n) : contDiffGroupoid n I ≤ contDiffGroupoid m I := by @@ -557,8 +568,6 @@ theorem contDiffGroupoid_zero_eq : contDiffGroupoid 0 I = continuousGroupoid H : · refine I.continuous.comp_continuousOn (u.symm.continuousOn.comp I.continuousOn_symm ?_) exact (mapsTo_preimage _ _).mono_left inter_subset_left -variable (n) - /-- An identity partial homeomorphism belongs to the `C^n` groupoid. -/ theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) : PartialHomeomorph.ofSet s hs ∈ contDiffGroupoid n I := by @@ -574,7 +583,7 @@ theorem symm_trans_mem_contDiffGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ contDiffGroupoid n I := haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := PartialHomeomorph.symm_trans_self _ - StructureGroupoid.mem_of_eqOnSource _ (ofSet_mem_contDiffGroupoid n I e.open_target) this + StructureGroupoid.mem_of_eqOnSource _ (ofSet_mem_contDiffGroupoid e.open_target) this variable {E' H' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] @@ -603,7 +612,7 @@ instance : ClosedUnderRestriction (contDiffGroupoid n I) := rw [StructureGroupoid.le_iff] rintro e ⟨s, hs, hes⟩ apply (contDiffGroupoid n I).mem_of_eqOnSource' _ _ _ hes - exact ofSet_mem_contDiffGroupoid n I hs) + exact ofSet_mem_contDiffGroupoid hs) end contDiffGroupoid @@ -657,7 +666,7 @@ model with corners `I`. -/ def maximalAtlas := (contDiffGroupoid ∞ I).maximalAtlas M -variable {M} +variable {I M} theorem subset_maximalAtlas [SmoothManifoldWithCorners I M] : atlas H M ⊆ maximalAtlas I M := StructureGroupoid.subset_maximalAtlas _ @@ -666,8 +675,6 @@ theorem chart_mem_maximalAtlas [SmoothManifoldWithCorners I M] (x : M) : chartAt H x ∈ maximalAtlas I M := StructureGroupoid.chart_mem_maximalAtlas _ x -variable {I} - theorem compatible_of_mem_maximalAtlas {e e' : PartialHomeomorph M H} (he : e ∈ maximalAtlas I M) (he' : e' ∈ maximalAtlas I M) : e.symm.trans e' ∈ contDiffGroupoid ∞ I := StructureGroupoid.compatible_of_mem_maximalAtlas he he' @@ -708,25 +715,29 @@ end SmoothManifoldWithCorners theorem PartialHomeomorph.singleton_smoothManifoldWithCorners {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] - {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] (e : PartialHomeomorph M H) (h : e.source = Set.univ) : @SmoothManifoldWithCorners 𝕜 _ E _ _ H _ I M _ (e.singletonChartedSpace h) := @SmoothManifoldWithCorners.mk' _ _ _ _ _ _ _ _ _ _ (id _) <| e.singleton_hasGroupoid h (contDiffGroupoid ∞ I) -theorem OpenEmbedding.singleton_smoothManifoldWithCorners {𝕜 : Type*} [NontriviallyNormedField 𝕜] +theorem IsOpenEmbedding.singleton_smoothManifoldWithCorners {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] [Nonempty M] {f : M → H} - (h : OpenEmbedding f) : + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [Nonempty M] {f : M → H} + (h : IsOpenEmbedding f) : @SmoothManifoldWithCorners 𝕜 _ E _ _ H _ I M _ h.singletonChartedSpace := - (h.toPartialHomeomorph f).singleton_smoothManifoldWithCorners I (by simp) + (h.toPartialHomeomorph f).singleton_smoothManifoldWithCorners (by simp) + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.singleton_smoothManifoldWithCorners := + IsOpenEmbedding.singleton_smoothManifoldWithCorners namespace TopologicalSpace.Opens open TopologicalSpace variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] [SmoothManifoldWithCorners I M] (s : Opens M) instance : SmoothManifoldWithCorners I s := @@ -740,8 +751,8 @@ open scoped Topology variable {𝕜 E M H E' M' H' : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] [TopologicalSpace H] [TopologicalSpace M] (f f' : PartialHomeomorph M H) - (I : ModelWithCorners 𝕜 E H) [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] - [TopologicalSpace M'] (I' : ModelWithCorners 𝕜 E' H') {s t : Set M} + {I : ModelWithCorners 𝕜 E H} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] + [TopologicalSpace M'] {I' : ModelWithCorners 𝕜 E' H'} {s t : Set M} /-! ### Extended charts @@ -755,6 +766,7 @@ as `PartialEquiv`. namespace PartialHomeomorph +variable (I) in /-- Given a chart `f` on a manifold with corners, `f.extend I` is the extended chart to the model vector space. -/ @[simp, mfld_simps] @@ -795,13 +807,13 @@ theorem extend_left_inv {x : M} (hxf : x ∈ f.source) : (f.extend I).symm (f.ex /-- Variant of `f.extend_left_inv I`, stated in terms of images. -/ lemma extend_left_inv' (ht : t ⊆ f.source) : ((f.extend I).symm ∘ (f.extend I)) '' t = t := - EqOn.image_eq_self (fun _ hx ↦ f.extend_left_inv I (ht hx)) + EqOn.image_eq_self (fun _ hx ↦ f.extend_left_inv (ht hx)) theorem extend_source_mem_nhds {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝 x := - (isOpen_extend_source f I).mem_nhds <| by rwa [f.extend_source I] + (isOpen_extend_source f).mem_nhds <| by rwa [f.extend_source] theorem extend_source_mem_nhdsWithin {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝[s] x := - mem_nhdsWithin_of_mem_nhds <| extend_source_mem_nhds f I h + mem_nhdsWithin_of_mem_nhds <| extend_source_mem_nhds f h theorem continuousOn_extend : ContinuousOn (f.extend I) (f.extend I).source := by refine I.continuous.comp_continuousOn ?_ @@ -809,7 +821,7 @@ theorem continuousOn_extend : ContinuousOn (f.extend I) (f.extend I).source := b exact f.continuousOn theorem continuousAt_extend {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I) x := - (continuousOn_extend f I).continuousAt <| extend_source_mem_nhds f I h + (continuousOn_extend f).continuousAt <| extend_source_mem_nhds f h theorem map_extend_nhds {x : M} (hy : x ∈ f.source) : map (f.extend I) (𝓝 x) = 𝓝[range I] f.extend I x := by @@ -817,16 +829,16 @@ theorem map_extend_nhds {x : M} (hy : x ∈ f.source) : theorem map_extend_nhds_of_boundaryless [I.Boundaryless] {x : M} (hx : x ∈ f.source) : map (f.extend I) (𝓝 x) = 𝓝 (f.extend I x) := by - rw [f.map_extend_nhds _ hx, I.range_eq_univ, nhdsWithin_univ] + rw [f.map_extend_nhds hx, I.range_eq_univ, nhdsWithin_univ] theorem extend_target_mem_nhdsWithin {y : M} (hy : y ∈ f.source) : (f.extend I).target ∈ 𝓝[range I] f.extend I y := by - rw [← PartialEquiv.image_source_eq_target, ← map_extend_nhds f I hy] - exact image_mem_map (extend_source_mem_nhds _ _ hy) + rw [← PartialEquiv.image_source_eq_target, ← map_extend_nhds f hy] + exact image_mem_map (extend_source_mem_nhds _ hy) theorem extend_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] {x} (hx : x ∈ f.source) {s : Set M} (h : s ∈ 𝓝 x) : (f.extend I) '' s ∈ 𝓝 ((f.extend I) x) := by - rw [← f.map_extend_nhds_of_boundaryless _ hx, Filter.mem_map] + rw [← f.map_extend_nhds_of_boundaryless hx, Filter.mem_map] filter_upwards [h] using subset_preimage_image (f.extend I) s theorem extend_target_subset_range : (f.extend I).target ⊆ range I := by simp only [mfld_simps] @@ -846,8 +858,8 @@ lemma mem_interior_extend_target {y : H} (hy : y ∈ f.target) theorem nhdsWithin_extend_target_eq {y : M} (hy : y ∈ f.source) : 𝓝[(f.extend I).target] f.extend I y = 𝓝[range I] f.extend I y := - (nhdsWithin_mono _ (extend_target_subset_range _ _)).antisymm <| - nhdsWithin_le_of_mem (extend_target_mem_nhdsWithin _ _ hy) + (nhdsWithin_mono _ (extend_target_subset_range _)).antisymm <| + nhdsWithin_le_of_mem (extend_target_mem_nhdsWithin _ hy) theorem continuousAt_extend_symm' {x : E} (h : x ∈ (f.extend I).target) : ContinuousAt (f.extend I).symm x := @@ -855,10 +867,10 @@ theorem continuousAt_extend_symm' {x : E} (h : x ∈ (f.extend I).target) : theorem continuousAt_extend_symm {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I).symm (f.extend I x) := - continuousAt_extend_symm' f I <| (f.extend I).map_source <| by rwa [f.extend_source] + continuousAt_extend_symm' f <| (f.extend I).map_source <| by rwa [f.extend_source] theorem continuousOn_extend_symm : ContinuousOn (f.extend I).symm (f.extend I).target := fun _ h => - (continuousAt_extend_symm' _ _ h).continuousWithinAt + (continuousAt_extend_symm' _ h).continuousWithinAt theorem extend_symm_continuousWithinAt_comp_right_iff {X} [TopologicalSpace X] {g : M → X} {s : Set M} {x : M} : @@ -868,52 +880,52 @@ theorem extend_symm_continuousWithinAt_comp_right_iff {X} [TopologicalSpace X] { theorem isOpen_extend_preimage' {s : Set E} (hs : IsOpen s) : IsOpen ((f.extend I).source ∩ f.extend I ⁻¹' s) := - (continuousOn_extend f I).isOpen_inter_preimage (isOpen_extend_source _ _) hs + (continuousOn_extend f).isOpen_inter_preimage (isOpen_extend_source _) hs theorem isOpen_extend_preimage {s : Set E} (hs : IsOpen s) : IsOpen (f.source ∩ f.extend I ⁻¹' s) := by - rw [← extend_source f I]; exact isOpen_extend_preimage' f I hs + rw [← extend_source f (I := I)]; exact isOpen_extend_preimage' f hs theorem map_extend_nhdsWithin_eq_image {y : M} (hy : y ∈ f.source) : map (f.extend I) (𝓝[s] y) = 𝓝[f.extend I '' ((f.extend I).source ∩ s)] f.extend I y := by set e := f.extend I calc map e (𝓝[s] y) = map e (𝓝[e.source ∩ s] y) := - congr_arg (map e) (nhdsWithin_inter_of_mem (extend_source_mem_nhdsWithin f I hy)).symm + congr_arg (map e) (nhdsWithin_inter_of_mem (extend_source_mem_nhdsWithin f hy)).symm _ = 𝓝[e '' (e.source ∩ s)] e y := ((f.extend I).leftInvOn.mono inter_subset_left).map_nhdsWithin_eq ((f.extend I).left_inv <| by rwa [f.extend_source]) - (continuousAt_extend_symm f I hy).continuousWithinAt - (continuousAt_extend f I hy).continuousWithinAt + (continuousAt_extend_symm f hy).continuousWithinAt + (continuousAt_extend f hy).continuousWithinAt theorem map_extend_nhdsWithin_eq_image_of_subset {y : M} (hy : y ∈ f.source) (hs : s ⊆ f.source) : map (f.extend I) (𝓝[s] y) = 𝓝[f.extend I '' s] f.extend I y := by - rw [map_extend_nhdsWithin_eq_image _ _ hy, inter_eq_self_of_subset_right] + rw [map_extend_nhdsWithin_eq_image _ hy, inter_eq_self_of_subset_right] rwa [extend_source] theorem map_extend_nhdsWithin {y : M} (hy : y ∈ f.source) : map (f.extend I) (𝓝[s] y) = 𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I y := by - rw [map_extend_nhdsWithin_eq_image f I hy, nhdsWithin_inter, ← - nhdsWithin_extend_target_eq _ _ hy, ← nhdsWithin_inter, (f.extend I).image_source_inter_eq', + rw [map_extend_nhdsWithin_eq_image f hy, nhdsWithin_inter, ← + nhdsWithin_extend_target_eq _ hy, ← nhdsWithin_inter, (f.extend I).image_source_inter_eq', inter_comm] theorem map_extend_symm_nhdsWithin {y : M} (hy : y ∈ f.source) : map (f.extend I).symm (𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I y) = 𝓝[s] y := by - rw [← map_extend_nhdsWithin f I hy, map_map, Filter.map_congr, map_id] - exact (f.extend I).leftInvOn.eqOn.eventuallyEq_of_mem (extend_source_mem_nhdsWithin _ _ hy) + rw [← map_extend_nhdsWithin f hy, map_map, Filter.map_congr, map_id] + exact (f.extend I).leftInvOn.eqOn.eventuallyEq_of_mem (extend_source_mem_nhdsWithin _ hy) theorem map_extend_symm_nhdsWithin_range {y : M} (hy : y ∈ f.source) : map (f.extend I).symm (𝓝[range I] f.extend I y) = 𝓝 y := by - rw [← nhdsWithin_univ, ← map_extend_symm_nhdsWithin f I hy, preimage_univ, univ_inter] + rw [← nhdsWithin_univ, ← map_extend_symm_nhdsWithin f (I := I) hy, preimage_univ, univ_inter] theorem tendsto_extend_comp_iff {α : Type*} {l : Filter α} {g : α → M} (hg : ∀ᶠ z in l, g z ∈ f.source) {y : M} (hy : y ∈ f.source) : Tendsto (f.extend I ∘ g) l (𝓝 (f.extend I y)) ↔ Tendsto g l (𝓝 y) := by - refine ⟨fun h u hu ↦ mem_map.2 ?_, (continuousAt_extend _ _ hy).tendsto.comp⟩ - have := (f.continuousAt_extend_symm I hy).tendsto.comp h - rw [extend_left_inv _ _ hy] at this + refine ⟨fun h u hu ↦ mem_map.2 ?_, (continuousAt_extend _ hy).tendsto.comp⟩ + have := (f.continuousAt_extend_symm hy).tendsto.comp h + rw [extend_left_inv _ hy] at this filter_upwards [hg, mem_map.1 (this hu)] with z hz hzu - simpa only [(· ∘ ·), extend_left_inv _ _ hz, mem_preimage] using hzu + simpa only [(· ∘ ·), extend_left_inv _ hz, mem_preimage] using hzu -- there is no definition `writtenInExtend` but we already use some made-up names in this file theorem continuousWithinAt_writtenInExtend_iff {f' : PartialHomeomorph M' H'} {g : M → M'} {y : M} @@ -922,11 +934,11 @@ theorem continuousWithinAt_writtenInExtend_iff {f' : PartialHomeomorph M' H'} {g ((f.extend I).symm ⁻¹' s ∩ range I) (f.extend I y) ↔ ContinuousWithinAt g s y := by unfold ContinuousWithinAt simp only [comp_apply] - rw [extend_left_inv _ _ hy, f'.tendsto_extend_comp_iff _ _ hgy, - ← f.map_extend_symm_nhdsWithin I hy, tendsto_map'_iff] - rw [← f.map_extend_nhdsWithin I hy, eventually_map] + rw [extend_left_inv _ hy, f'.tendsto_extend_comp_iff _ hgy, + ← f.map_extend_symm_nhdsWithin (I := I) hy, tendsto_map'_iff] + rw [← f.map_extend_nhdsWithin (I := I) hy, eventually_map] filter_upwards [inter_mem_nhdsWithin _ (f.open_source.mem_nhds hy)] with z hz - rw [comp_apply, extend_left_inv _ _ hz.2] + rw [comp_apply, extend_left_inv _ hz.2] exact hmaps hz.1 -- there is no definition `writtenInExtend` but we already use some made-up names in this file @@ -937,20 +949,21 @@ theorem continuousOn_writtenInExtend_iff {f' : PartialHomeomorph M' H'} {g : M (hs : s ⊆ f.source) (hmaps : MapsTo g s f'.source) : ContinuousOn (f'.extend I' ∘ g ∘ (f.extend I).symm) (f.extend I '' s) ↔ ContinuousOn g s := by refine forall_mem_image.trans <| forall₂_congr fun x hx ↦ ?_ - refine (continuousWithinAt_congr_nhds ?_).trans - (continuousWithinAt_writtenInExtend_iff _ _ _ (hs hx) (hmaps hx) hmaps) - rw [← map_extend_nhdsWithin_eq_image_of_subset, ← map_extend_nhdsWithin] + refine (continuousWithinAt_congr_set ?_).trans + (continuousWithinAt_writtenInExtend_iff _ (hs hx) (hmaps hx) hmaps) + rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin_eq_image_of_subset, + ← map_extend_nhdsWithin] exacts [hs hx, hs hx, hs] /-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point in the source is a neighborhood of the preimage, within a set. -/ theorem extend_preimage_mem_nhdsWithin {x : M} (h : x ∈ f.source) (ht : t ∈ 𝓝[s] x) : (f.extend I).symm ⁻¹' t ∈ 𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I x := by - rwa [← map_extend_symm_nhdsWithin f I h, mem_map] at ht + rwa [← map_extend_symm_nhdsWithin f (I := I) h, mem_map] at ht theorem extend_preimage_mem_nhds {x : M} (h : x ∈ f.source) (ht : t ∈ 𝓝 x) : (f.extend I).symm ⁻¹' t ∈ 𝓝 (f.extend I x) := by - apply (continuousAt_extend_symm f I h).preimage_mem_nhds + apply (continuousAt_extend_symm f h).preimage_mem_nhds rwa [(f.extend I).left_inv] rwa [f.extend_source] @@ -977,8 +990,8 @@ theorem extend_symm_preimage_inter_range_eventuallyEq_aux {s : Set M} {x : M} (h theorem extend_symm_preimage_inter_range_eventuallyEq {s : Set M} {x : M} (hs : s ⊆ f.source) (hx : x ∈ f.source) : ((f.extend I).symm ⁻¹' s ∩ range I : Set _) =ᶠ[𝓝 (f.extend I x)] f.extend I '' s := by - rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin _ _ hx, - map_extend_nhdsWithin_eq_image_of_subset _ _ hx hs] + rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin _ hx, + map_extend_nhdsWithin_eq_image_of_subset _ hx hs] /-! We use the name `extend_coord_change` for `(f'.extend I).symm ≫ f.extend I`. -/ @@ -1021,7 +1034,7 @@ theorem contDiffOn_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtl theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : E} (hx : x ∈ ((f'.extend I).symm ≫ f.extend I).source) : ContDiffWithinAt 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) (range I) x := by - apply (contDiffOn_extend_coord_change I hf hf' x hx).mono_of_mem + apply (contDiffOn_extend_coord_change hf hf' x hx).mono_of_mem_nhdsWithin rw [extend_coord_change_source] at hx ⊢ obtain ⟨z, hz, rfl⟩ := hx exact I.image_mem_nhdsWithin ((PartialHomeomorph.open_source _).mem_nhds hz) @@ -1029,7 +1042,7 @@ theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maxi theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : ContDiffWithinAt 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) (range I) (f'.extend I x) := by - refine contDiffWithinAt_extend_coord_change I hf hf' ?_ + refine contDiffWithinAt_extend_coord_change hf hf' ?_ rw [← extend_image_source_inter] exact mem_image_of_mem _ ⟨hxf', hxf⟩ @@ -1039,6 +1052,7 @@ open PartialHomeomorph variable [ChartedSpace H M] [ChartedSpace H' M'] +variable (I) in /-- The preferred extended chart on a manifold with corners around a point `x`, from a neighborhood of `x` to the model vector space. -/ @[simp, mfld_simps] @@ -1051,21 +1065,23 @@ theorem extChartAt_coe (x : M) : ⇑(extChartAt I x) = I ∘ chartAt H x := theorem extChartAt_coe_symm (x : M) : ⇑(extChartAt I x).symm = (chartAt H x).symm ∘ I.symm := rfl +variable (I) in theorem extChartAt_source (x : M) : (extChartAt I x).source = (chartAt H x).source := - extend_source _ _ + extend_source _ theorem isOpen_extChartAt_source (x : M) : IsOpen (extChartAt I x).source := - isOpen_extend_source _ _ + isOpen_extend_source _ theorem mem_extChartAt_source (x : M) : x ∈ (extChartAt I x).source := by simp only [extChartAt_source, mem_chart_source] theorem mem_extChartAt_target (x : M) : extChartAt I x x ∈ (extChartAt I x).target := - (extChartAt I x).map_source <| mem_extChartAt_source _ _ + (extChartAt I x).map_source <| mem_extChartAt_source _ +variable (I) in theorem extChartAt_target (x : M) : (extChartAt I x).target = I.symm ⁻¹' (chartAt H x).target ∩ range I := - extend_target _ _ + extend_target _ theorem uniqueDiffOn_extChartAt_target (x : M) : UniqueDiffOn 𝕜 (extChartAt I x).target := by rw [extChartAt_target] @@ -1073,64 +1089,64 @@ theorem uniqueDiffOn_extChartAt_target (x : M) : UniqueDiffOn 𝕜 (extChartAt I theorem uniqueDiffWithinAt_extChartAt_target (x : M) : UniqueDiffWithinAt 𝕜 (extChartAt I x).target (extChartAt I x x) := - uniqueDiffOn_extChartAt_target I x _ <| mem_extChartAt_target I x + uniqueDiffOn_extChartAt_target x _ <| mem_extChartAt_target x theorem extChartAt_to_inv (x : M) : (extChartAt I x).symm ((extChartAt I x) x) = x := - (extChartAt I x).left_inv (mem_extChartAt_source I x) + (extChartAt I x).left_inv (mem_extChartAt_source x) theorem mapsTo_extChartAt {x : M} (hs : s ⊆ (chartAt H x).source) : MapsTo (extChartAt I x) s ((extChartAt I x).symm ⁻¹' s ∩ range I) := - mapsTo_extend _ _ hs + mapsTo_extend _ hs theorem extChartAt_source_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) : (extChartAt I x).source ∈ 𝓝 x' := - extend_source_mem_nhds _ _ <| by rwa [← extChartAt_source I] + extend_source_mem_nhds _ <| by rwa [← extChartAt_source I] theorem extChartAt_source_mem_nhds (x : M) : (extChartAt I x).source ∈ 𝓝 x := - extChartAt_source_mem_nhds' I (mem_extChartAt_source I x) + extChartAt_source_mem_nhds' (mem_extChartAt_source x) theorem extChartAt_source_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) : (extChartAt I x).source ∈ 𝓝[s] x' := - mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds' I h) + mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds' h) theorem extChartAt_source_mem_nhdsWithin (x : M) : (extChartAt I x).source ∈ 𝓝[s] x := - mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds I x) + mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds x) theorem continuousOn_extChartAt (x : M) : ContinuousOn (extChartAt I x) (extChartAt I x).source := - continuousOn_extend _ _ + continuousOn_extend _ theorem continuousAt_extChartAt' {x x' : M} (h : x' ∈ (extChartAt I x).source) : ContinuousAt (extChartAt I x) x' := - continuousAt_extend _ _ <| by rwa [← extChartAt_source I] + continuousAt_extend _ <| by rwa [← extChartAt_source I] theorem continuousAt_extChartAt (x : M) : ContinuousAt (extChartAt I x) x := - continuousAt_extChartAt' _ (mem_extChartAt_source I x) + continuousAt_extChartAt' (mem_extChartAt_source x) theorem map_extChartAt_nhds' {x y : M} (hy : y ∈ (extChartAt I x).source) : map (extChartAt I x) (𝓝 y) = 𝓝[range I] extChartAt I x y := - map_extend_nhds _ _ <| by rwa [← extChartAt_source I] + map_extend_nhds _ <| by rwa [← extChartAt_source I] theorem map_extChartAt_nhds (x : M) : map (extChartAt I x) (𝓝 x) = 𝓝[range I] extChartAt I x x := - map_extChartAt_nhds' I <| mem_extChartAt_source I x + map_extChartAt_nhds' <| mem_extChartAt_source x theorem map_extChartAt_nhds_of_boundaryless [I.Boundaryless] (x : M) : map (extChartAt I x) (𝓝 x) = 𝓝 (extChartAt I x x) := by rw [extChartAt] - exact map_extend_nhds_of_boundaryless (chartAt H x) I (mem_chart_source H x) + exact map_extend_nhds_of_boundaryless (chartAt H x) (mem_chart_source H x) variable {x} in theorem extChartAt_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] {x : M} (hx : s ∈ 𝓝 x) : extChartAt I x '' s ∈ 𝓝 (extChartAt I x x) := by rw [extChartAt] - exact extend_image_nhd_mem_nhds_of_boundaryless _ I (mem_chart_source H x) hx + exact extend_image_nhd_mem_nhds_of_boundaryless _ (mem_chart_source H x) hx theorem extChartAt_target_mem_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x y := - extend_target_mem_nhdsWithin _ _ <| by rwa [← extChartAt_source I] + extend_target_mem_nhdsWithin _ <| by rwa [← extChartAt_source I] theorem extChartAt_target_mem_nhdsWithin (x : M) : (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x x := - extChartAt_target_mem_nhdsWithin' I (mem_extChartAt_source I x) + extChartAt_target_mem_nhdsWithin' (mem_extChartAt_source x) /-- If we're boundaryless, `extChartAt` has open target -/ theorem isOpen_extChartAt_target [I.Boundaryless] (x : M) : IsOpen (extChartAt I x).target := by @@ -1140,109 +1156,109 @@ theorem isOpen_extChartAt_target [I.Boundaryless] (x : M) : IsOpen (extChartAt I /-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of the key point -/ theorem extChartAt_target_mem_nhds [I.Boundaryless] (x : M) : (extChartAt I x).target ∈ 𝓝 (extChartAt I x x) := by - convert extChartAt_target_mem_nhdsWithin I x + convert extChartAt_target_mem_nhdsWithin x simp only [I.range_eq_univ, nhdsWithin_univ] /-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of any of its points -/ theorem extChartAt_target_mem_nhds' [I.Boundaryless] {x : M} {y : E} (m : y ∈ (extChartAt I x).target) : (extChartAt I x).target ∈ 𝓝 y := - (isOpen_extChartAt_target I x).mem_nhds m + (isOpen_extChartAt_target x).mem_nhds m theorem extChartAt_target_subset_range (x : M) : (extChartAt I x).target ⊆ range I := by simp only [mfld_simps] theorem nhdsWithin_extChartAt_target_eq' {x y : M} (hy : y ∈ (extChartAt I x).source) : 𝓝[(extChartAt I x).target] extChartAt I x y = 𝓝[range I] extChartAt I x y := - nhdsWithin_extend_target_eq _ _ <| by rwa [← extChartAt_source I] + nhdsWithin_extend_target_eq _ <| by rwa [← extChartAt_source I] theorem nhdsWithin_extChartAt_target_eq (x : M) : 𝓝[(extChartAt I x).target] (extChartAt I x) x = 𝓝[range I] (extChartAt I x) x := - nhdsWithin_extChartAt_target_eq' I (mem_extChartAt_source I x) + nhdsWithin_extChartAt_target_eq' (mem_extChartAt_source x) theorem continuousAt_extChartAt_symm'' {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : ContinuousAt (extChartAt I x).symm y := - continuousAt_extend_symm' _ _ h + continuousAt_extend_symm' _ h theorem continuousAt_extChartAt_symm' {x x' : M} (h : x' ∈ (extChartAt I x).source) : ContinuousAt (extChartAt I x).symm (extChartAt I x x') := - continuousAt_extChartAt_symm'' I <| (extChartAt I x).map_source h + continuousAt_extChartAt_symm'' <| (extChartAt I x).map_source h theorem continuousAt_extChartAt_symm (x : M) : ContinuousAt (extChartAt I x).symm ((extChartAt I x) x) := - continuousAt_extChartAt_symm' I (mem_extChartAt_source I x) + continuousAt_extChartAt_symm' (mem_extChartAt_source x) theorem continuousOn_extChartAt_symm (x : M) : ContinuousOn (extChartAt I x).symm (extChartAt I x).target := - fun _y hy => (continuousAt_extChartAt_symm'' _ hy).continuousWithinAt + fun _y hy => (continuousAt_extChartAt_symm'' hy).continuousWithinAt theorem isOpen_extChartAt_preimage' (x : M) {s : Set E} (hs : IsOpen s) : IsOpen ((extChartAt I x).source ∩ extChartAt I x ⁻¹' s) := - isOpen_extend_preimage' _ _ hs + isOpen_extend_preimage' _ hs theorem isOpen_extChartAt_preimage (x : M) {s : Set E} (hs : IsOpen s) : IsOpen ((chartAt H x).source ∩ extChartAt I x ⁻¹' s) := by rw [← extChartAt_source I] - exact isOpen_extChartAt_preimage' I x hs + exact isOpen_extChartAt_preimage' x hs theorem map_extChartAt_nhdsWithin_eq_image' {x y : M} (hy : y ∈ (extChartAt I x).source) : map (extChartAt I x) (𝓝[s] y) = 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x y := - map_extend_nhdsWithin_eq_image _ _ <| by rwa [← extChartAt_source I] + map_extend_nhdsWithin_eq_image _ <| by rwa [← extChartAt_source I] theorem map_extChartAt_nhdsWithin_eq_image (x : M) : map (extChartAt I x) (𝓝[s] x) = 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x x := - map_extChartAt_nhdsWithin_eq_image' I (mem_extChartAt_source I x) + map_extChartAt_nhdsWithin_eq_image' (mem_extChartAt_source x) theorem map_extChartAt_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : map (extChartAt I x) (𝓝[s] y) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y := - map_extend_nhdsWithin _ _ <| by rwa [← extChartAt_source I] + map_extend_nhdsWithin _ <| by rwa [← extChartAt_source I] theorem map_extChartAt_nhdsWithin (x : M) : map (extChartAt I x) (𝓝[s] x) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x := - map_extChartAt_nhdsWithin' I (mem_extChartAt_source I x) + map_extChartAt_nhdsWithin' (mem_extChartAt_source x) theorem map_extChartAt_symm_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y) = 𝓝[s] y := - map_extend_symm_nhdsWithin _ _ <| by rwa [← extChartAt_source I] + map_extend_symm_nhdsWithin _ <| by rwa [← extChartAt_source I] theorem map_extChartAt_symm_nhdsWithin_range' {x y : M} (hy : y ∈ (extChartAt I x).source) : map (extChartAt I x).symm (𝓝[range I] extChartAt I x y) = 𝓝 y := - map_extend_symm_nhdsWithin_range _ _ <| by rwa [← extChartAt_source I] + map_extend_symm_nhdsWithin_range _ <| by rwa [← extChartAt_source I] theorem map_extChartAt_symm_nhdsWithin (x : M) : map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x) = 𝓝[s] x := - map_extChartAt_symm_nhdsWithin' I (mem_extChartAt_source I x) + map_extChartAt_symm_nhdsWithin' (mem_extChartAt_source x) theorem map_extChartAt_symm_nhdsWithin_range (x : M) : map (extChartAt I x).symm (𝓝[range I] extChartAt I x x) = 𝓝 x := - map_extChartAt_symm_nhdsWithin_range' I (mem_extChartAt_source I x) + map_extChartAt_symm_nhdsWithin_range' (mem_extChartAt_source x) /-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point in the source is a neighborhood of the preimage, within a set. -/ theorem extChartAt_preimage_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) (ht : t ∈ 𝓝[s] x') : (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x' := by - rwa [← map_extChartAt_symm_nhdsWithin' I h, mem_map] at ht + rwa [← map_extChartAt_symm_nhdsWithin' h, mem_map] at ht /-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of the base point is a neighborhood of the preimage, within a set. -/ theorem extChartAt_preimage_mem_nhdsWithin {x : M} (ht : t ∈ 𝓝[s] x) : (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := - extChartAt_preimage_mem_nhdsWithin' I (mem_extChartAt_source I x) ht + extChartAt_preimage_mem_nhdsWithin' (mem_extChartAt_source x) ht theorem extChartAt_preimage_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) (ht : t ∈ 𝓝 x') : (extChartAt I x).symm ⁻¹' t ∈ 𝓝 (extChartAt I x x') := - extend_preimage_mem_nhds _ _ (by rwa [← extChartAt_source I]) ht + extend_preimage_mem_nhds _ (by rwa [← extChartAt_source I]) ht /-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point is a neighborhood of the preimage. -/ theorem extChartAt_preimage_mem_nhds {x : M} (ht : t ∈ 𝓝 x) : (extChartAt I x).symm ⁻¹' t ∈ 𝓝 ((extChartAt I x) x) := by - apply (continuousAt_extChartAt_symm I x).preimage_mem_nhds - rwa [(extChartAt I x).left_inv (mem_extChartAt_source _ _)] + apply (continuousAt_extChartAt_symm x).preimage_mem_nhds + rwa [(extChartAt I x).left_inv (mem_extChartAt_source _)] /-- Technical lemma to rewrite suitably the preimage of an intersection under an extended chart, to bring it into a convenient form to apply derivative lemmas. -/ @@ -1258,28 +1274,37 @@ theorem ContinuousWithinAt.nhdsWithin_extChartAt_symm_preimage_inter_range (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source)] (extChartAt I x x) := by rw [← (extChartAt I x).image_source_inter_eq', ← map_extChartAt_nhdsWithin_eq_image, ← map_extChartAt_nhdsWithin, nhdsWithin_inter_of_mem'] - exact hc (extChartAt_source_mem_nhds _ _) + exact hc (extChartAt_source_mem_nhds _) + +theorem ContinuousWithinAt.extChartAt_symm_preimage_inter_range_eventuallyEq + {f : M → M'} {x : M} (hc : ContinuousWithinAt f s x) : + ((extChartAt I x).symm ⁻¹' s ∩ range I : Set E) =ᶠ[𝓝 (extChartAt I x x)] + ((extChartAt I x).target ∩ + (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source) : Set E) := by + rw [← nhdsWithin_eq_iff_eventuallyEq] + exact hc.nhdsWithin_extChartAt_symm_preimage_inter_range /-! We use the name `ext_coord_change` for `(extChartAt I x').symm ≫ extChartAt I x`. -/ theorem ext_coord_change_source (x x' : M) : ((extChartAt I x').symm ≫ extChartAt I x).source = I '' ((chartAt H x').symm ≫ₕ chartAt H x).source := - extend_coord_change_source _ _ _ + extend_coord_change_source _ _ open SmoothManifoldWithCorners theorem contDiffOn_ext_coord_change [SmoothManifoldWithCorners I M] (x x' : M) : ContDiffOn 𝕜 ⊤ (extChartAt I x ∘ (extChartAt I x').symm) ((extChartAt I x').symm ≫ extChartAt I x).source := - contDiffOn_extend_coord_change I (chart_mem_maximalAtlas I x) (chart_mem_maximalAtlas I x') + contDiffOn_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') theorem contDiffWithinAt_ext_coord_change [SmoothManifoldWithCorners I M] (x x' : M) {y : E} (hy : y ∈ ((extChartAt I x').symm ≫ extChartAt I x).source) : ContDiffWithinAt 𝕜 ⊤ (extChartAt I x ∘ (extChartAt I x').symm) (range I) y := - contDiffWithinAt_extend_coord_change I (chart_mem_maximalAtlas I x) (chart_mem_maximalAtlas I x') + contDiffWithinAt_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') hy +variable (I I') in /-- Conjugating a function to write it in the preferred charts around `x`. The manifold derivative of `f` will just be the derivative of this conjugated function. -/ @[simp, mfld_simps] @@ -1363,3 +1388,56 @@ lemma Manifold.locallyCompact_of_finiteDimensional exact ChartedSpace.locallyCompactSpace H M end Topology + +section TangentSpace + +/- We define the tangent space to `M` modelled on `I : ModelWithCorners 𝕜 E H` as a type synonym +for `E`. This is enough to define linear maps between tangent spaces, for instance derivatives, +but the interesting part is to define a manifold structure on the whole tangent bundle, which +requires that `M` is a smooth manifold with corners. The definition is put here to avoid importing +all the smooth bundle structure when defining manifold derivatives. -/ + +set_option linter.unusedVariables false in +/-- The tangent space at a point of the manifold `M`. It is just `E`. We could use instead +`(tangentBundleCore I M).to_topological_vector_bundle_core.fiber x`, but we use `E` to help the +kernel. +-/ +@[nolint unusedArguments] +def TangentSpace {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type u} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] (_x : M) : Type u := E +-- Porting note: was deriving TopologicalSpace, AddCommGroup, TopologicalAddGroup + +/- In general, the definition of `TangentSpace` is not reducible, so that type class inference +does not pick wrong instances. We record the right instances for them. -/ + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {x : M} + +instance : TopologicalSpace (TangentSpace I x) := inferInstanceAs (TopologicalSpace E) +instance : AddCommGroup (TangentSpace I x) := inferInstanceAs (AddCommGroup E) +instance : TopologicalAddGroup (TangentSpace I x) := inferInstanceAs (TopologicalAddGroup E) +instance : Module 𝕜 (TangentSpace I x) := inferInstanceAs (Module 𝕜 E) +instance : Inhabited (TangentSpace I x) := ⟨0⟩ + +variable (M) in +-- is empty if the base manifold is empty +/-- The tangent bundle to a smooth manifold, as a Sigma type. Defined in terms of +`Bundle.TotalSpace` to be able to put a suitable topology on it. -/ +-- Porting note(#5171): was nolint has_nonempty_instance +abbrev TangentBundle := + Bundle.TotalSpace E (TangentSpace I : M → Type _) + +end TangentSpace + +section Real + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {H : Type*} [TopologicalSpace H] + {I : ModelWithCorners ℝ E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {x : M} + +instance : PathConnectedSpace (TangentSpace I x) := inferInstanceAs (PathConnectedSpace E) + +end Real diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean index 02abb186cc8f9..001e1a6509395 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean @@ -122,7 +122,7 @@ section 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*} + {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 : ℕ∞} @@ -149,13 +149,13 @@ theorem FiberBundle.writtenInExtChartAt_trivializationAt {x : TotalSpace F E} {y (hy : y ∈ (extChartAt (IB.prod 𝓘(𝕜, F)) x).target) : writtenInExtChartAt (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) x (trivializationAt F E x.proj) y = y := - writtenInExtChartAt_chartAt_comp _ _ hy + writtenInExtChartAt_chartAt_comp _ hy theorem FiberBundle.writtenInExtChartAt_trivializationAt_symm {x : TotalSpace F E} {y} (hy : y ∈ (extChartAt (IB.prod 𝓘(𝕜, F)) x).target) : writtenInExtChartAt (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) (trivializationAt F E x.proj x) (trivializationAt F E x.proj).toPartialHomeomorph.symm y = y := - writtenInExtChartAt_chartAt_symm_comp _ _ hy + writtenInExtChartAt_chartAt_symm_comp _ hy /-! ### Smoothness of maps in/out fiber bundles @@ -165,8 +165,6 @@ bundle at all, just that it is a fiber bundle over a charted base space. namespace Bundle -variable {IB} - /-- Characterization of C^n functions into a smooth vector bundle. -/ theorem contMDiffWithinAt_totalSpace (f : M → TotalSpace F E) {s : Set M} {x₀ : M} : ContMDiffWithinAt IM (IB.prod 𝓘(𝕜, F)) n f s x₀ ↔ @@ -251,7 +249,7 @@ end variable [NontriviallyNormedField 𝕜] {EB : Type*} [NormedAddCommGroup EB] [NormedSpace 𝕜 EB] - {HB : Type*} [TopologicalSpace HB] (IB : ModelWithCorners 𝕜 EB HB) [TopologicalSpace B] + {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 : ℕ∞} @@ -262,6 +260,7 @@ section WithTopology variable [TopologicalSpace (TotalSpace F E)] [∀ x, TopologicalSpace (E x)] (F E) variable [FiberBundle F E] [VectorBundle 𝕜 F E] +variable (IB) in /-- When `B` is a smooth manifold with corners with respect to a model `IB` and `E` is a topological vector bundle over `B` with fibers isomorphic to `F`, then `SmoothVectorBundle F E IB` registers that the bundle is smooth, in the sense of having smooth transition functions. @@ -294,31 +293,30 @@ theorem smoothOn_symm_coordChangeL : theorem contMDiffOn_coordChangeL : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) (e.baseSet ∩ e'.baseSet) := - (smoothOn_coordChangeL IB e e').of_le le_top + (smoothOn_coordChangeL e e').of_le le_top theorem contMDiffOn_symm_coordChangeL : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => ((e.coordChangeL 𝕜 e' b).symm : F →L[𝕜] F)) (e.baseSet ∩ e'.baseSet) := - (smoothOn_symm_coordChangeL IB e e').of_le le_top + (smoothOn_symm_coordChangeL e e').of_le le_top variable {e e'} theorem contMDiffAt_coordChangeL {x : B} (h : x ∈ e.baseSet) (h' : x ∈ e'.baseSet) : ContMDiffAt IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) x := - (contMDiffOn_coordChangeL IB e e').contMDiffAt <| + (contMDiffOn_coordChangeL e e').contMDiffAt <| (e.open_baseSet.inter e'.open_baseSet).mem_nhds ⟨h, h'⟩ theorem smoothAt_coordChangeL {x : B} (h : x ∈ e.baseSet) (h' : x ∈ e'.baseSet) : SmoothAt IB 𝓘(𝕜, F →L[𝕜] F) (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) x := - contMDiffAt_coordChangeL IB h h' + contMDiffAt_coordChangeL h h' -variable {IB} variable {s : Set M} {f : M → B} {g : M → F} {x : M} protected theorem ContMDiffWithinAt.coordChangeL (hf : ContMDiffWithinAt IM IB n f s x) (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : ContMDiffWithinAt IM 𝓘(𝕜, F →L[𝕜] F) n (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) s x := - (contMDiffAt_coordChangeL IB he he').comp_contMDiffWithinAt _ hf + (contMDiffAt_coordChangeL he he').comp_contMDiffWithinAt _ hf protected nonrec theorem ContMDiffAt.coordChangeL (hf : ContMDiffAt IM IB n f x) (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : @@ -454,8 +452,8 @@ instance SmoothFiberwiseLinear.hasGroupoid : haveI : MemTrivializationAtlas e := ⟨he⟩ haveI : MemTrivializationAtlas e' := ⟨he'⟩ rw [mem_smoothFiberwiseLinear_iff] - refine ⟨_, _, e.open_baseSet.inter e'.open_baseSet, smoothOn_coordChangeL IB e e', - smoothOn_symm_coordChangeL IB e e', ?_⟩ + refine ⟨_, _, e.open_baseSet.inter e'.open_baseSet, smoothOn_coordChangeL e e', + smoothOn_symm_coordChangeL e e', ?_⟩ refine PartialHomeomorph.eqOnSourceSetoid.symm ⟨?_, ?_⟩ · simp only [e.symm_trans_source_eq e', FiberwiseLinear.partialHomeomorph, trans_toPartialEquiv, symm_toPartialEquiv] @@ -497,7 +495,7 @@ theorem Trivialization.contMDiffAt_iff {f : M → TotalSpace F E} {x₀ : M} (he ContMDiffAt IM (IB.prod 𝓘(𝕜, F)) n f x₀ ↔ ContMDiffAt IM IB n (fun x => (f x).proj) x₀ ∧ ContMDiffAt IM 𝓘(𝕜, F) n (fun x ↦ (e (f x)).2) x₀ := - e.contMDiffWithinAt_iff _ he + e.contMDiffWithinAt_iff he theorem Trivialization.contMDiffOn_iff {f : M → TotalSpace F E} {s : Set M} (he : MapsTo f s e.source) : @@ -505,46 +503,46 @@ theorem Trivialization.contMDiffOn_iff {f : M → TotalSpace F E} {s : Set M} ContMDiffOn IM IB n (fun x => (f x).proj) s ∧ ContMDiffOn IM 𝓘(𝕜, F) n (fun x ↦ (e (f x)).2) s := by simp only [ContMDiffOn, ← forall_and] - exact forall₂_congr fun x hx ↦ e.contMDiffWithinAt_iff IB (he hx) + exact forall₂_congr fun x hx ↦ e.contMDiffWithinAt_iff (he hx) theorem Trivialization.contMDiff_iff {f : M → TotalSpace F E} (he : ∀ x, f x ∈ e.source) : ContMDiff IM (IB.prod 𝓘(𝕜, F)) n f ↔ ContMDiff IM IB n (fun x => (f x).proj) ∧ ContMDiff IM 𝓘(𝕜, F) n (fun x ↦ (e (f x)).2) := - (forall_congr' fun x ↦ e.contMDiffAt_iff IB (he x)).trans forall_and + (forall_congr' fun x ↦ e.contMDiffAt_iff (he x)).trans forall_and theorem Trivialization.smoothWithinAt_iff {f : M → TotalSpace F E} {s : Set M} {x₀ : M} (he : f x₀ ∈ e.source) : SmoothWithinAt IM (IB.prod 𝓘(𝕜, F)) f s x₀ ↔ SmoothWithinAt IM IB (fun x => (f x).proj) s x₀ ∧ SmoothWithinAt IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) s x₀ := - e.contMDiffWithinAt_iff IB he + e.contMDiffWithinAt_iff he theorem Trivialization.smoothAt_iff {f : M → TotalSpace F E} {x₀ : M} (he : f x₀ ∈ e.source) : SmoothAt IM (IB.prod 𝓘(𝕜, F)) f x₀ ↔ SmoothAt IM IB (fun x => (f x).proj) x₀ ∧ SmoothAt IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) x₀ := - e.contMDiffAt_iff IB he + e.contMDiffAt_iff he theorem Trivialization.smoothOn_iff {f : M → TotalSpace F E} {s : Set M} (he : MapsTo f s e.source) : SmoothOn IM (IB.prod 𝓘(𝕜, F)) f s ↔ SmoothOn IM IB (fun x => (f x).proj) s ∧ SmoothOn IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) s := - e.contMDiffOn_iff IB he + e.contMDiffOn_iff he theorem Trivialization.smooth_iff {f : M → TotalSpace F E} (he : ∀ x, f x ∈ e.source) : Smooth IM (IB.prod 𝓘(𝕜, F)) f ↔ Smooth IM IB (fun x => (f x).proj) ∧ Smooth IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) := - e.contMDiff_iff IB he + e.contMDiff_iff he theorem Trivialization.smoothOn (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e e.source := by have : SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) id e.source := smoothOn_id - rw [e.smoothOn_iff IB (mapsTo_id _)] at this + rw [e.smoothOn_iff (mapsTo_id _)] at this exact (this.1.prod_mk this.2).congr fun x hx ↦ (e.mk_proj_snd hx).symm theorem Trivialization.smoothOn_symm (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e.toPartialHomeomorph.symm e.target := by - rw [e.smoothOn_iff IB e.toPartialHomeomorph.symm_mapsTo] + rw [e.smoothOn_iff e.toPartialHomeomorph.symm_mapsTo] refine ⟨smoothOn_fst.congr fun x hx ↦ e.proj_symm_apply hx, smoothOn_snd.congr fun x hx ↦ ?_⟩ rw [e.apply_symm_apply hx] @@ -614,10 +612,10 @@ instance Bundle.Prod.smoothVectorBundle : SmoothVectorBundle (F₁ × F₂) (E rw [SmoothOn] refine ContMDiffOn.congr ?_ (e₁.coordChangeL_prod 𝕜 e₁' e₂ e₂') refine ContMDiffOn.clm_prodMap ?_ ?_ - · refine (smoothOn_coordChangeL IB e₁ e₁').mono ?_ + · refine (smoothOn_coordChangeL e₁ e₁').mono ?_ simp only [Trivialization.baseSet_prod, mfld_simps] mfld_set_tac - · refine (smoothOn_coordChangeL IB e₂ e₂').mono ?_ + · refine (smoothOn_coordChangeL e₂ e₂').mono ?_ simp only [Trivialization.baseSet_prod, mfld_simps] mfld_set_tac @@ -631,6 +629,7 @@ namespace VectorPrebundle variable [∀ x, TopologicalSpace (E x)] +variable (IB) in /-- Mixin for a `VectorPrebundle` stating smoothness of coordinate changes. -/ class IsSmooth (a : VectorPrebundle 𝕜 F E) : Prop where exists_smoothCoordChange : @@ -642,6 +641,7 @@ class IsSmooth (a : VectorPrebundle 𝕜 F E) : Prop where variable (a : VectorPrebundle 𝕜 F E) [ha : a.IsSmooth IB] {e e' : Pretrivialization F (π F E)} +variable (IB) in /-- A randomly chosen coordinate change on a `SmoothVectorPrebundle`, given by the field `exists_coordChange`. Note that `a.smoothCoordChange` need not be the same as `a.coordChange`. -/ @@ -649,8 +649,6 @@ noncomputable def smoothCoordChange (he : e ∈ a.pretrivializationAtlas) (he' : e' ∈ a.pretrivializationAtlas) (b : B) : F →L[𝕜] F := Classical.choose (ha.exists_smoothCoordChange e he e' he') b -variable {IB} - theorem smoothOn_smoothCoordChange (he : e ∈ a.pretrivializationAtlas) (he' : e' ∈ a.pretrivializationAtlas) : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (a.smoothCoordChange IB he he') (e.baseSet ∩ e'.baseSet) := @@ -669,7 +667,7 @@ theorem mk_smoothCoordChange (he : e ∈ a.pretrivializationAtlas) rw [e.proj_symm_apply' hb.1]; exact hb.2 · exact a.smoothCoordChange_apply he he' hb v -variable (IB) +variable (IB) in /-- Make a `SmoothVectorBundle` from a `SmoothVectorPrebundle`. -/ theorem smoothVectorBundle : @SmoothVectorBundle _ _ F E _ _ _ _ _ _ IB _ _ _ _ _ _ a.totalSpaceTopology _ a.toFiberBundle a.toVectorBundle := diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean index 33808cd26cd8e..eeee06ea57f19 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean @@ -29,10 +29,10 @@ variable {𝕜 B F₁ F₂ M : Type*} {E₁ : B → Type*} {E₂ : B → Type*} [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] {EM : Type*} + {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₁] [FiberBundle F₂ E₂] [VectorBundle 𝕜 F₂ E₂] {e₁ e₁' : Trivialization F₁ (π F₁ E₁)} {e₂ e₂' : Trivialization F₂ (π F₂ E₂)} @@ -45,8 +45,8 @@ theorem smoothOn_continuousLinearMapCoordChange SmoothOn IB 𝓘(𝕜, (F₁ →L[𝕜] F₂) →L[𝕜] F₁ →L[𝕜] F₂) (continuousLinearMapCoordChange (RingHom.id 𝕜) e₁ e₁' e₂ e₂') (e₁.baseSet ∩ e₂.baseSet ∩ (e₁'.baseSet ∩ e₂'.baseSet)) := by - have h₁ := smoothOn_coordChangeL IB e₁' e₁ - have h₂ := smoothOn_coordChangeL IB e₂ e₂' + have h₁ := smoothOn_coordChangeL (IB := IB) e₁' e₁ + have h₂ := smoothOn_coordChangeL (IB := IB) e₂ e₂' refine (h₁.mono ?_).cle_arrowCongr (h₂.mono ?_) <;> mfld_set_tac variable [∀ x, TopologicalAddGroup (E₂ x)] [∀ x, ContinuousSMul 𝕜 (E₂ x)] @@ -58,8 +58,6 @@ theorem hom_chart (y₀ y : LE₁E₂) : Trivialization.coe_coe, PartialHomeomorph.refl_apply, Function.id_def, hom_trivializationAt_apply] -variable {IB} - theorem contMDiffAt_hom_bundle (f : M → LE₁E₂) {x₀ : M} {n : ℕ∞} : ContMDiffAt IM (IB.prod 𝓘(𝕜, F₁ →L[𝕜] F₂)) n f x₀ ↔ ContMDiffAt IM IB n (fun x => (f x).1) x₀ ∧ @@ -81,7 +79,7 @@ instance Bundle.ContinuousLinearMap.vectorPrebundle.isSmooth : exists_smoothCoordChange := by rintro _ ⟨e₁, e₂, he₁, he₂, rfl⟩ _ ⟨e₁', e₂', he₁', he₂', rfl⟩ exact ⟨continuousLinearMapCoordChange (RingHom.id 𝕜) e₁ e₁' e₂ e₂', - smoothOn_continuousLinearMapCoordChange IB, + smoothOn_continuousLinearMapCoordChange, continuousLinearMapCoordChange_apply (RingHom.id 𝕜) e₁ e₁' e₂ e₂'⟩ instance SmoothVectorBundle.continuousLinearMap : diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean b/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean index 30454293a1bd9..fe187b0ed7d21 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean @@ -20,11 +20,11 @@ This file defines pullbacks of smooth vector bundles over a smooth manifold. open Bundle Set open scoped Manifold -variable {𝕜 B B' M : Type*} (F : Type*) (E : B → Type*) +variable {𝕜 B B' : Type*} (F : Type*) (E : B → Type*) variable [NontriviallyNormedField 𝕜] [∀ x, AddCommMonoid (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] + {HB : Type*} [TopologicalSpace HB] {IB : ModelWithCorners 𝕜 EB HB} [TopologicalSpace B] [ChartedSpace HB B] [SmoothManifoldWithCorners IB B] {EB' : Type*} [NormedAddCommGroup EB'] [NormedSpace 𝕜 EB'] {HB' : Type*} [TopologicalSpace HB'] (IB' : ModelWithCorners 𝕜 EB' HB') [TopologicalSpace B'] [ChartedSpace HB' B'] [SmoothManifoldWithCorners IB' B'] [FiberBundle F E] @@ -35,7 +35,7 @@ vector bundle `f *ᵖ E` is a smooth vector bundle. -/ instance SmoothVectorBundle.pullback : SmoothVectorBundle F (f *ᵖ E) IB' where smoothOn_coordChangeL := by rintro _ _ ⟨e, he, rfl⟩ ⟨e', he', rfl⟩ - refine ((smoothOn_coordChangeL _ e e').comp f.smooth.smoothOn fun b hb => hb).congr ?_ + refine ((smoothOn_coordChangeL e e').comp f.smooth.smoothOn fun b hb => hb).congr ?_ rintro b (hb : f b ∈ e.baseSet ∩ e'.baseSet); ext v show ((e.pullback f).coordChangeL 𝕜 (e'.pullback f) b) v = (e.coordChangeL 𝕜 e' (f b)) v rw [e.coordChangeL_apply e' hb, (e.pullback f).coordChangeL_apply' _] diff --git a/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean b/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean index b8beaedc2623e..198e5170ad73e 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean @@ -3,9 +3,10 @@ Copyright (c) 2023 Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth, Floris van Doorn -/ +import Mathlib.Geometry.Manifold.Algebra.LieGroup import Mathlib.Geometry.Manifold.MFDeriv.Basic import Mathlib.Topology.ContinuousMap.Basic -import Mathlib.Geometry.Manifold.Algebra.LieGroup +import Mathlib.Geometry.Manifold.VectorBundle.Basic /-! # Smooth sections @@ -20,12 +21,8 @@ open Bundle Filter Function open scoped Bundle Manifold variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H : Type*} - [TopologicalSpace H] {H' : Type*} [TopologicalSpace H'] (I : ModelWithCorners 𝕜 E H) - (I' : ModelWithCorners 𝕜 E' H') {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {M' : Type*} - [TopologicalSpace M'] [ChartedSpace H' M'] {E'' : Type*} [NormedAddCommGroup E''] - [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} - {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] variable (F : Type*) [NormedAddCommGroup F] [NormedSpace 𝕜 F] -- `F` model fiber @@ -50,7 +47,7 @@ abbrev SmoothSection := namespace ContMDiffSection -variable {I} {I'} {n} {F} {V} +variable {I} {n} {F} {V} instance : DFunLike Cₛ^n⟮I; F, V⟯ M V where coe := ContMDiffSection.toFun diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index df7663e67c7ac..7625f03d10a19 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean @@ -4,16 +4,19 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Heather Macbeth -/ import Mathlib.Geometry.Manifold.VectorBundle.Basic -import Mathlib.Analysis.Convex.Normed /-! # Tangent bundles This file defines the tangent bundle as a smooth vector bundle. -Let `M` be a smooth manifold with corners with model `I` on `(E, H)`. We define the tangent bundle -of `M` using the `VectorBundleCore` construction indexed by the charts of `M` with fibers `E`. -Given two charts `i, j : PartialHomeomorph M H`, the coordinate change between `i` and `j` -at a point `x : M` is the derivative of the composite +Let `M` be a manifold with model `I` on `(E, H)`. The tangent space `TangentSpace I (x : M)` has +already been defined as a type synonym for `E`, and the tangent bundle `TangentBundle I M` as an +abbrev of `Bundle.TotalSpace E (TangentSpace I : M → Type _)`. + +In this file, when `M` is smooth, we construct a smooth vector bundle structure +on `TangentBundle I M` using the `VectorBundleCore` construction indexed by the charts of `M` +with fibers `E`. Given two charts `i, j : PartialHomeomorph M H`, the coordinate change +between `i` and `j` at a point `x : M` is the derivative of the composite ``` I.symm i.symm j I E -----> H -----> M --> H --> E @@ -21,12 +24,13 @@ E -----> H -----> M --> H --> E within the set `range I ⊆ E` at `I (i x) : E`. This defines a smooth vector bundle `TangentBundle` with fibers `TangentSpace`. -## Main definitions +## Main definitions and results -* `TangentSpace I M x` is the fiber of the tangent bundle at `x : M`, which is defined to be `E`. +* `tangentBundleCore I M` is the vector bundle core for the tangent bundle over `M`. -* `TangentBundle I M` is the total space of `TangentSpace I M`, proven to be a smooth vector - bundle. +* When `M` is a smooth manifold with corners, `TangentBundle I M` has a smooth vector bundle +structure over `M`. In particular, it is a topological space, a vector bundle, a fiber bundle, +and a smooth manifold. -/ @@ -45,7 +49,6 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom [SmoothManifoldWithCorners I M] {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] [SmoothManifoldWithCorners I' M'] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -variable (I) /-- Auxiliary lemma for tangent spaces: the derivative of a coordinate change between two charts is smooth on its source. -/ @@ -56,16 +59,16 @@ theorem contDiffOn_fderiv_coord_change (i j : atlas H M) : rw [i.1.extend_coord_change_source]; apply image_subset_range intro x hx refine (ContDiffWithinAt.fderivWithin_right ?_ I.uniqueDiffOn le_top <| h hx).mono h - refine (PartialHomeomorph.contDiffOn_extend_coord_change I (subset_maximalAtlas I j.2) - (subset_maximalAtlas I i.2) x hx).mono_of_mem ?_ - exact i.1.extend_coord_change_source_mem_nhdsWithin j.1 I hx + refine (PartialHomeomorph.contDiffOn_extend_coord_change (subset_maximalAtlas j.2) + (subset_maximalAtlas i.2) x hx).mono_of_mem_nhdsWithin ?_ + exact i.1.extend_coord_change_source_mem_nhdsWithin j.1 hx -variable (M) open SmoothManifoldWithCorners +variable (I M) in /-- Let `M` be a smooth manifold with corners with model `I` on `(E, H)`. -Then `VectorBundleCore I M` is the vector bundle core for the tangent bundle over `M`. +Then `tangentBundleCore I M` is the vector bundle core for the tangent bundle over `M`. It is indexed by the atlas of `M`, with fiber `E` and its change of coordinates from the chart `i` to the chart `j` at point `x : M` is the derivative of the composite ``` @@ -85,35 +88,33 @@ def tangentBundleCore : VectorBundleCore 𝕜 M E (atlas H M) where simp only rw [Filter.EventuallyEq.fderivWithin_eq, fderivWithin_id', ContinuousLinearMap.id_apply] · exact I.uniqueDiffWithinAt_image - · filter_upwards [i.1.extend_target_mem_nhdsWithin I hx] with y hy + · filter_upwards [i.1.extend_target_mem_nhdsWithin hx] with y hy exact (i.1.extend I).right_inv hy - · simp_rw [Function.comp_apply, i.1.extend_left_inv I hx] + · simp_rw [Function.comp_apply, i.1.extend_left_inv hx] continuousOn_coordChange i j := by - refine (contDiffOn_fderiv_coord_change I i j).continuousOn.comp - ((i.1.continuousOn_extend I).mono ?_) ?_ + refine (contDiffOn_fderiv_coord_change i j).continuousOn.comp + (i.1.continuousOn_extend.mono ?_) ?_ · rw [i.1.extend_source]; exact inter_subset_left simp_rw [← i.1.extend_image_source_inter, mapsTo_image] coordChange_comp := by rintro i j k x ⟨⟨hxi, hxj⟩, hxk⟩ v rw [fderivWithin_fderivWithin, Filter.EventuallyEq.fderivWithin_eq] - · have := i.1.extend_preimage_mem_nhds I hxi (j.1.extend_source_mem_nhds I hxj) + · have := i.1.extend_preimage_mem_nhds (I := I) hxi (j.1.extend_source_mem_nhds (I := I) hxj) filter_upwards [nhdsWithin_le_nhds this] with y hy simp_rw [Function.comp_apply, (j.1.extend I).left_inv hy] - · simp_rw [Function.comp_apply, i.1.extend_left_inv I hxi, j.1.extend_left_inv I hxj] - · exact (contDiffWithinAt_extend_coord_change' I (subset_maximalAtlas I k.2) - (subset_maximalAtlas I j.2) hxk hxj).differentiableWithinAt le_top - · exact (contDiffWithinAt_extend_coord_change' I (subset_maximalAtlas I j.2) - (subset_maximalAtlas I i.2) hxj hxi).differentiableWithinAt le_top + · simp_rw [Function.comp_apply, i.1.extend_left_inv hxi, j.1.extend_left_inv hxj] + · exact (contDiffWithinAt_extend_coord_change' (subset_maximalAtlas k.2) + (subset_maximalAtlas j.2) hxk hxj).differentiableWithinAt le_top + · exact (contDiffWithinAt_extend_coord_change' (subset_maximalAtlas j.2) + (subset_maximalAtlas i.2) hxj hxi).differentiableWithinAt le_top · intro x _; exact mem_range_self _ · exact I.uniqueDiffWithinAt_image - · rw [Function.comp_apply, i.1.extend_left_inv I hxi] + · rw [Function.comp_apply, i.1.extend_left_inv hxi] -- Porting note: moved to a separate `simp high` lemma b/c `simp` can simplify the LHS @[simp high] theorem tangentBundleCore_baseSet (i) : (tangentBundleCore I M).baseSet i = i.1.source := rfl -variable {M} - theorem tangentBundleCore_coordChange_achart (x x' z : M) : (tangentBundleCore I M).coordChange (achart H x) (achart H x') z = fderivWithin 𝕜 (extChartAt I x' ∘ (extChartAt I x).symm) (range I) (extChartAt I x z) := @@ -121,6 +122,7 @@ theorem tangentBundleCore_coordChange_achart (x x' z : M) : section tangentCoordChange +variable (I) in /-- In a manifold `M`, given two preferred charts indexed by `x y : M`, `tangentCoordChange I x y` is the family of derivatives of the corresponding change-of-coordinates map. It takes junk values outside the intersection of the sources of the two charts. @@ -130,8 +132,6 @@ sets as the preferred charts of the base manifold. -/ abbrev tangentCoordChange (x y : M) : M → E →L[𝕜] E := (tangentBundleCore I M).coordChange (achart H x) (achart H y) -variable {I} - lemma tangentCoordChange_def {x y z : M} : tangentCoordChange I x y z = fderivWithin 𝕜 (extChartAt I y ∘ (extChartAt I x).symm) (range I) (extChartAt I x z) := rfl @@ -155,7 +155,7 @@ lemma hasFDerivWithinAt_tangentCoordChange {x y z : M} have h' : extChartAt I x z ∈ ((extChartAt I x).symm ≫ (extChartAt I y)).source := by rw [PartialEquiv.trans_source'', PartialEquiv.symm_symm, PartialEquiv.symm_target] exact mem_image_of_mem _ h - ((contDiffWithinAt_ext_coord_change I y x h').differentiableWithinAt (by simp)).hasFDerivWithinAt + ((contDiffWithinAt_ext_coord_change y x h').differentiableWithinAt (by simp)).hasFDerivWithinAt lemma continuousOn_tangentCoordChange (x y : M) : ContinuousOn (tangentCoordChange I x y) ((extChartAt I x).source ∩ (extChartAt I y).source) := by @@ -164,49 +164,10 @@ lemma continuousOn_tangentCoordChange (x y : M) : ContinuousOn (tangentCoordChan end tangentCoordChange -/-- The tangent space at a point of the manifold `M`. It is just `E`. We could use instead -`(tangentBundleCore I M).to_topological_vector_bundle_core.fiber x`, but we use `E` to help the -kernel. --/ -@[nolint unusedArguments] -def TangentSpace {𝕜} [NontriviallyNormedField 𝕜] {E} [NormedAddCommGroup E] [NormedSpace 𝕜 E] - {H} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M} [TopologicalSpace M] - [ChartedSpace H M] [SmoothManifoldWithCorners I M] (_x : M) : Type* := E --- Porting note: was deriving TopologicalSpace, AddCommGroup, TopologicalAddGroup - -instance {x : M} : TopologicalSpace (TangentSpace I x) := inferInstanceAs (TopologicalSpace E) -instance {x : M} : AddCommGroup (TangentSpace I x) := inferInstanceAs (AddCommGroup E) -instance {x : M} : TopologicalAddGroup (TangentSpace I x) := inferInstanceAs (TopologicalAddGroup E) - -variable (M) - --- is empty if the base manifold is empty -/-- The tangent bundle to a smooth manifold, as a Sigma type. Defined in terms of -`Bundle.TotalSpace` to be able to put a suitable topology on it. -/ --- Porting note(#5171): was nolint has_nonempty_instance -abbrev TangentBundle := - Bundle.TotalSpace E (TangentSpace I : M → Type _) - local notation "TM" => TangentBundle I M section TangentBundleInstances -/- In general, the definition of `TangentSpace` is not reducible, so that type class inference -does not pick wrong instances. In this section, we record the right instances for -them, noting in particular that the tangent bundle is a smooth manifold. -/ -section - -variable {M} -variable (x : M) - -instance : Module 𝕜 (TangentSpace I x) := inferInstanceAs (Module 𝕜 E) - -instance : Inhabited (TangentSpace I x) := ⟨0⟩ - --- Porting note: removed unneeded ContinuousAdd (TangentSpace I x) - -end - instance : TopologicalSpace TM := (tangentBundleCore I M).toTopologicalSpace @@ -325,16 +286,16 @@ end TangentBundle instance tangentBundleCore.isSmooth : (tangentBundleCore I M).IsSmooth I := by refine ⟨fun i j => ?_⟩ - rw [SmoothOn, contMDiffOn_iff_source_of_mem_maximalAtlas (subset_maximalAtlas I i.2), + rw [SmoothOn, contMDiffOn_iff_source_of_mem_maximalAtlas (subset_maximalAtlas i.2), contMDiffOn_iff_contDiffOn] - · refine ((contDiffOn_fderiv_coord_change I i j).congr fun x hx => ?_).mono ?_ + · refine ((contDiffOn_fderiv_coord_change (I := I) i j).congr fun x hx => ?_).mono ?_ · rw [PartialEquiv.trans_source'] at hx simp_rw [Function.comp_apply, tangentBundleCore_coordChange, (i.1.extend I).right_inv hx.1] - · exact (i.1.extend_image_source_inter j.1 I).subset + · exact (i.1.extend_image_source_inter j.1).subset · apply inter_subset_left instance TangentBundle.smoothVectorBundle : SmoothVectorBundle E (TangentSpace I : M → Type _) I := - (tangentBundleCore I M).smoothVectorBundle _ + (tangentBundleCore I M).smoothVectorBundle end TangentBundleInstances @@ -374,8 +335,7 @@ theorem tangentBundleCore_coordChange_model_space (x x' z : H) : ContinuousLinearMap.id 𝕜 E := by ext v; exact (tangentBundleCore I H).coordChange_self (achart _ z) z (mem_univ _) v -variable (H) - +variable (I) in /-- The canonical identification between the tangent bundle to the model space and the product, as a homeomorphism -/ def tangentBundleModelSpaceHomeomorph : TangentBundle I H ≃ₜ ModelProd H E := @@ -397,19 +357,18 @@ def tangentBundleModelSpaceHomeomorph : TangentBundle I H ≃ₜ ModelProd H E : @[simp, mfld_simps] theorem tangentBundleModelSpaceHomeomorph_coe : - (tangentBundleModelSpaceHomeomorph H I : TangentBundle I H → ModelProd H E) = + (tangentBundleModelSpaceHomeomorph I : TangentBundle I H → ModelProd H E) = TotalSpace.toProd H E := rfl @[simp, mfld_simps] theorem tangentBundleModelSpaceHomeomorph_coe_symm : - ((tangentBundleModelSpaceHomeomorph H I).symm : ModelProd H E → TangentBundle I H) = + ((tangentBundleModelSpaceHomeomorph I).symm : ModelProd H E → TangentBundle I H) = (TotalSpace.toProd H E).symm := rfl section inTangentCoordinates -variable (I') {M H} variable {N : Type*} /-- The map `in_coordinates` for the tangent bundle is trivial on the model spaces -/ @@ -419,6 +378,7 @@ theorem inCoordinates_tangent_bundle_core_model_space (x₀ x : H) (y₀ y : H') simp_rw [tangentBundleCore_indexAt, tangentBundleCore_coordChange_model_space, ContinuousLinearMap.id_comp, ContinuousLinearMap.comp_id] +variable (I I') in /-- When `ϕ x` is a continuous linear map that changes vectors in charts around `f x` to vectors in charts around `g x`, `inTangentCoordinates I I' f g ϕ x₀ x` is a coordinate change of this continuous linear map that makes sense from charts around `f x₀` to charts around `g x₀` @@ -448,13 +408,3 @@ theorem inTangentCoordinates_eq (f : N → M) (g : N → M') (ϕ : N → E →L[ end inTangentCoordinates end General - -section Real - -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {H : Type*} [TopologicalSpace H] - {I : ModelWithCorners ℝ E H} {M : Type*} [TopologicalSpace M] [ChartedSpace H M] - [SmoothManifoldWithCorners I M] - -instance {x : M} : PathConnectedSpace (TangentSpace I x) := by unfold TangentSpace; infer_instance - -end Real diff --git a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean index 3e3f2e4bb92fd..8106c8dd8e80c 100644 --- a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean +++ b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean @@ -83,7 +83,7 @@ theorem comp_embeddingPiTangent_mfderiv (x : M) (hx : x ∈ s) : (@ContinuousLinearMap.proj ℝ _ ι (fun _ => E × ℝ) _ _ (fun _ => inferInstance) (f.ind x hx)) have := L.hasMFDerivAt.comp x f.embeddingPiTangent.smooth.mdifferentiableAt.hasMFDerivAt convert hasMFDerivAt_unique this _ - refine (hasMFDerivAt_extChartAt I (f.mem_chartAt_ind_source x hx)).congr_of_eventuallyEq ?_ + refine (hasMFDerivAt_extChartAt (f.mem_chartAt_ind_source x hx)).congr_of_eventuallyEq ?_ refine (f.eventuallyEq_one x hx).mono fun y hy => ?_ simp only [L, embeddingPiTangent_coe, ContinuousLinearMap.coe_comp', (· ∘ ·), ContinuousLinearMap.coe_fst', ContinuousLinearMap.proj_apply] @@ -92,7 +92,7 @@ theorem comp_embeddingPiTangent_mfderiv (x : M) (hx : x ∈ s) : theorem embeddingPiTangent_ker_mfderiv (x : M) (hx : x ∈ s) : LinearMap.ker (mfderiv I 𝓘(ℝ, ι → E × ℝ) f.embeddingPiTangent x) = ⊥ := by apply bot_unique - rw [← (mdifferentiable_chart I (f.c (f.ind x hx))).ker_mfderiv_eq_bot + rw [← (mdifferentiable_chart (f.c (f.ind x hx))).ker_mfderiv_eq_bot (f.mem_chartAt_ind_source x hx), ← comp_embeddingPiTangent_mfderiv] exact LinearMap.ker_le_ker_comp _ _ @@ -128,9 +128,9 @@ supports of bump functions, then for some `n` it can be embedded into the `n`-di Euclidean space. -/ theorem exists_embedding_euclidean_of_compact [T2Space M] [CompactSpace M] : ∃ (n : ℕ) (e : M → EuclideanSpace ℝ (Fin n)), - Smooth I (𝓡 n) e ∧ ClosedEmbedding e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by + Smooth I (𝓡 n) e ∧ IsClosedEmbedding e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by rcases SmoothBumpCovering.exists_isSubordinate I isClosed_univ fun (x : M) _ => univ_mem with ⟨ι, f, -⟩ haveI := f.fintype rcases f.exists_immersion_euclidean with ⟨n, e, hsmooth, hinj, hinj_mfderiv⟩ - exact ⟨n, e, hsmooth, hsmooth.continuous.closedEmbedding hinj, hinj_mfderiv⟩ + exact ⟨n, e, hsmooth, hsmooth.continuous.isClosedEmbedding hinj, hinj_mfderiv⟩ diff --git a/Mathlib/Geometry/RingedSpace/Basic.lean b/Mathlib/Geometry/RingedSpace/Basic.lean index 5b110af7a48ad..a11af973bc890 100644 --- a/Mathlib/Geometry/RingedSpace/Basic.lean +++ b/Mathlib/Geometry/RingedSpace/Basic.lean @@ -41,34 +41,48 @@ namespace RingedSpace open SheafedSpace +@[simp] +lemma res_zero {X : RingedSpace.{u}} {U V : TopologicalSpace.Opens X} + (hUV : U ≤ V) : (0 : X.presheaf.obj (op V)) |_ U = 0 := + map_zero _ + variable (X : RingedSpace) --- Porting note (#10670): this was not necessary in mathlib3 instance : CoeSort RingedSpace Type* where coe X := X.carrier +/-- If the germ of a section `f` is zero in the stalk at `x`, then `f` is zero on some neighbourhood +around `x`. -/ +lemma exists_res_eq_zero_of_germ_eq_zero (U : Opens X) (f : X.presheaf.obj (op U)) (x : U) + (h : X.presheaf.germ U x.val x.property f = 0) : + ∃ (V : Opens X) (i : V ⟶ U) (_ : x.1 ∈ V), X.presheaf.map i.op f = 0 := by + have h1 : X.presheaf.germ U x.val x.property f = X.presheaf.germ U x.val x.property 0 := by simpa + obtain ⟨V, hv, i, _, hv4⟩ := TopCat.Presheaf.germ_eq X.presheaf x.1 x.2 x.2 f 0 h1 + use V, i, hv + simpa using hv4 + /-- If the germ of a section `f` is a unit in the stalk at `x`, then `f` must be a unit on some small neighborhood around `x`. -/ -theorem isUnit_res_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) (x : U) - (h : IsUnit (X.presheaf.germ x f)) : - ∃ (V : Opens X) (i : V ⟶ U) (_ : x.1 ∈ V), IsUnit (X.presheaf.map i.op f) := by +theorem isUnit_res_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) (x : X) (hx : x ∈ U) + (h : IsUnit (X.presheaf.germ U x hx f)) : + ∃ (V : Opens X) (i : V ⟶ U) (_ : x ∈ V), IsUnit (X.presheaf.map i.op f) := by obtain ⟨g', heq⟩ := h.exists_right_inv - obtain ⟨V, hxV, g, rfl⟩ := X.presheaf.germ_exist x.1 g' + obtain ⟨V, hxV, g, rfl⟩ := X.presheaf.germ_exist x g' let W := U ⊓ V - have hxW : x.1 ∈ W := ⟨x.2, hxV⟩ + have hxW : x ∈ W := ⟨hx, hxV⟩ -- Porting note: `erw` can't write into `HEq`, so this is replaced with another `HEq` in the -- desired form - replace heq : (X.presheaf.germ ⟨x.val, hxW⟩) ((X.presheaf.map (U.infLELeft V).op) f * - (X.presheaf.map (U.infLERight V).op) g) = (X.presheaf.germ ⟨x.val, hxW⟩) 1 := by + replace heq : (X.presheaf.germ _ x hxW) ((X.presheaf.map (U.infLELeft V).op) f * + (X.presheaf.map (U.infLERight V).op) g) = (X.presheaf.germ _ x hxW) 1 := by dsimp [germ] - erw [map_mul, map_one, show X.presheaf.germ ⟨x, hxW⟩ ((X.presheaf.map (U.infLELeft V).op) f) = - X.presheaf.germ x f from X.presheaf.germ_res_apply (Opens.infLELeft U V) ⟨x.1, hxW⟩ f, - show X.presheaf.germ ⟨x, hxW⟩ (X.presheaf.map (U.infLERight V).op g) = - X.presheaf.germ ⟨x, hxV⟩ g from X.presheaf.germ_res_apply (Opens.infLERight U V) ⟨x.1, hxW⟩ g] + erw [map_mul, map_one, show X.presheaf.germ _ x hxW ((X.presheaf.map (U.infLELeft V).op) f) = + X.presheaf.germ U x hx f from X.presheaf.germ_res_apply (Opens.infLELeft U V) x hxW f, + show X.presheaf.germ _ x hxW (X.presheaf.map (U.infLERight V).op g) = + X.presheaf.germ _ x hxV g from X.presheaf.germ_res_apply (Opens.infLERight U V) x hxW g] exact heq - obtain ⟨W', hxW', i₁, i₂, heq'⟩ := X.presheaf.germ_eq x.1 hxW hxW _ _ heq + obtain ⟨W', hxW', i₁, i₂, heq'⟩ := X.presheaf.germ_eq x hxW hxW _ _ heq use W', i₁ ≫ Opens.infLELeft U V, hxW' rw [(X.presheaf.map i₂.op).map_one, (X.presheaf.map i₁.op).map_mul] at heq' rw [← comp_apply, ← X.presheaf.map_comp, ← comp_apply, ← X.presheaf.map_comp, ← op_comp] at heq' @@ -76,9 +90,9 @@ theorem isUnit_res_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) (x : /-- If a section `f` is a unit in each stalk, `f` must be a unit. -/ theorem isUnit_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) - (h : ∀ x : U, IsUnit (X.presheaf.germ x f)) : IsUnit f := by + (h : ∀ (x) (hx : x ∈ U), IsUnit (X.presheaf.germ U x hx f)) : IsUnit f := by -- We pick a cover of `U` by open sets `V x`, such that `f` is a unit on each `V x`. - choose V iVU m h_unit using fun x : U => X.isUnit_res_of_isUnit_germ U f x (h x) + choose V iVU m h_unit using fun x : U => X.isUnit_res_of_isUnit_germ U f x x.2 (h x.1 x.2) have hcover : U ≤ iSup V := by intro x hxU -- Porting note: in Lean3 `rw` is sufficient @@ -89,27 +103,20 @@ theorem isUnit_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) have ic : IsCompatible (sheaf X).val V g := by intro x y apply section_ext X.sheaf (V x ⊓ V y) - rintro ⟨z, hzVx, hzVy⟩ - erw [germ_res_apply, germ_res_apply] - apply (IsUnit.mul_right_inj (h ⟨z, (iVU x).le hzVx⟩)).mp + rintro z ⟨hzVx, hzVy⟩ + rw [germ_res_apply, germ_res_apply] + apply (h z ((iVU x).le hzVx)).mul_right_inj.mp -- Porting note: now need explicitly typing the rewrites - rw [← show X.presheaf.germ ⟨z, hzVx⟩ (X.presheaf.map (iVU x).op f) = - X.presheaf.germ ⟨z, ((iVU x) ⟨z, hzVx⟩).2⟩ f from - X.presheaf.germ_res_apply (iVU x) ⟨z, hzVx⟩ f] + rw [← X.presheaf.germ_res_apply (iVU x) z hzVx f] -- Porting note: change was not necessary in Lean3 - change X.presheaf.germ ⟨z, hzVx⟩ _ * (X.presheaf.germ ⟨z, hzVx⟩ _) = - X.presheaf.germ ⟨z, hzVx⟩ _ * X.presheaf.germ ⟨z, hzVy⟩ (g y) + change X.presheaf.germ _ z hzVx _ * (X.presheaf.germ _ z hzVx _) = + X.presheaf.germ _ z hzVx _ * X.presheaf.germ _ z hzVy (g y) rw [← RingHom.map_mul, - congr_arg (X.presheaf.germ (⟨z, hzVx⟩ : V x)) (hg x), - -- Porting note: now need explicitly typing the rewrites - show X.presheaf.germ ⟨z, hzVx⟩ (X.presheaf.map (iVU x).op f) = - X.presheaf.germ ⟨z, ((iVU x) ⟨z, hzVx⟩).2⟩ f from X.presheaf.germ_res_apply _ _ f, - -- Porting note: now need explicitly typing the rewrites - ← show X.presheaf.germ ⟨z, hzVy⟩ (X.presheaf.map (iVU y).op f) = - X.presheaf.germ ⟨z, ((iVU x) ⟨z, hzVx⟩).2⟩ f from - X.presheaf.germ_res_apply (iVU y) ⟨z, hzVy⟩ f, + congr_arg (X.presheaf.germ (V x) z hzVx) (hg x), + X.presheaf.germ_res_apply _ _ _ f, + ← X.presheaf.germ_res_apply (iVU y) z hzVy f, ← RingHom.map_mul, - congr_arg (X.presheaf.germ (⟨z, hzVy⟩ : V y)) (hg y), RingHom.map_one, RingHom.map_one] + congr_arg (X.presheaf.germ (V y) z hzVy) (hg y), RingHom.map_one, RingHom.map_one] -- We claim that these local inverses glue together to a global inverse of `f`. obtain ⟨gl, gl_spec, -⟩ := X.sheaf.existsUnique_gluing' V U iVU hcover g ic apply isUnit_of_mul_eq_one f gl @@ -122,58 +129,54 @@ theorem isUnit_of_isUnit_germ (U : Opens X) (f : X.presheaf.obj (op U)) `x` is a unit. -/ def basicOpen {U : Opens X} (f : X.presheaf.obj (op U)) : Opens X where - -- Porting note: `coe` does not work - carrier := Subtype.val '' { x : U | IsUnit (X.presheaf.germ x f) } + carrier := { x : X | ∃ (hx : x ∈ U), IsUnit (X.presheaf.germ U x hx f) } is_open' := by rw [isOpen_iff_forall_mem_open] - rintro _ ⟨x, hx, rfl⟩ - obtain ⟨V, i, hxV, hf⟩ := X.isUnit_res_of_isUnit_germ U f x hx + rintro x ⟨hxU, hx⟩ + obtain ⟨V, i, hxV, hf⟩ := X.isUnit_res_of_isUnit_germ U f x hxU hx use V.1 refine ⟨?_, V.2, hxV⟩ intro y hy - use (⟨y, i.le hy⟩ : U) - rw [Set.mem_setOf_eq] - constructor - · convert RingHom.isUnit_map (X.presheaf.germ ⟨y, hy⟩) hf - exact (X.presheaf.germ_res_apply i ⟨y, hy⟩ f).symm - · rfl + use i.le hy + convert RingHom.isUnit_map (X.presheaf.germ _ y hy) hf + exact (X.presheaf.germ_res_apply i y hy f).symm + +theorem mem_basicOpen {U : Opens X} (f : X.presheaf.obj (op U)) (x : X) (hx : x ∈ U) : + x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ U x hx f) := + ⟨Exists.choose_spec, (⟨hx, ·⟩)⟩ +/-- A variant of `mem_basicOpen` with bundled `x : U`. -/ @[simp] -theorem mem_basicOpen {U : Opens X} (f : X.presheaf.obj (op U)) (x : U) : - ↑x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ x f) := by - constructor - · rintro ⟨x, hx, a⟩; cases Subtype.eq a; exact hx - · intro h; exact ⟨x, h, rfl⟩ +theorem mem_basicOpen' {U : Opens X} (f : X.presheaf.obj (op U)) (x : U) : + ↑x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ U x.1 x.2 f) := + mem_basicOpen X f x.1 x.2 @[simp] theorem mem_top_basicOpen (f : X.presheaf.obj (op ⊤)) (x : X) : - x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.germ ⟨x, show x ∈ (⊤ : Opens X) by trivial⟩ f) := - mem_basicOpen X f ⟨x, _⟩ + x ∈ X.basicOpen f ↔ IsUnit (X.presheaf.Γgerm x f) := + mem_basicOpen X f x .intro theorem basicOpen_le {U : Opens X} (f : X.presheaf.obj (op U)) : X.basicOpen f ≤ U := by - rintro _ ⟨x, _, rfl⟩; exact x.2 + rintro x ⟨h, _⟩; exact h /-- The restriction of a section `f` to the basic open of `f` is a unit. -/ theorem isUnit_res_basicOpen {U : Opens X} (f : X.presheaf.obj (op U)) : IsUnit (X.presheaf.map (@homOfLE (Opens X) _ _ _ (X.basicOpen_le f)).op f) := by apply isUnit_of_isUnit_germ - rintro ⟨_, ⟨x, (hx : IsUnit _), rfl⟩⟩ + rintro x ⟨hxU, hx⟩ convert hx - convert X.presheaf.germ_res_apply _ _ _ + convert X.presheaf.germ_res_apply _ _ _ _ @[simp] theorem basicOpen_res {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) (f : X.presheaf.obj U) : @basicOpen X (unop V) (X.presheaf.map i f) = unop V ⊓ @basicOpen X (unop U) f := by - induction U using Opposite.rec' - induction V using Opposite.rec' - let g := i.unop; have : i = g.op := rfl; clear_value g; subst this - ext; constructor - · rintro ⟨x, hx : IsUnit _, rfl⟩ - erw [X.presheaf.germ_res_apply _ _ _] at hx - exact ⟨x.2, g x, hx, rfl⟩ - · rintro ⟨hxV, x, hx, rfl⟩ - refine ⟨⟨x, hxV⟩, (?_ : IsUnit _), rfl⟩ - erw [X.presheaf.germ_res_apply _ _ _] + ext x; constructor + · rintro ⟨hxV, hx⟩ + rw [X.presheaf.germ_res_apply'] at hx + exact ⟨hxV, i.unop.le hxV, hx⟩ + · rintro ⟨hxV, _, hx⟩ + refine ⟨hxV, ?_⟩ + rw [X.presheaf.germ_res_apply'] exact hx -- This should fire before `basicOpen_res`. @@ -193,11 +196,10 @@ theorem basicOpen_res_eq {U V : (Opens X)ᵒᵖ} (i : U ⟶ V) [IsIso i] (f : X. @[simp] theorem basicOpen_mul {U : Opens X} (f g : X.presheaf.obj (op U)) : X.basicOpen (f * g) = X.basicOpen f ⊓ X.basicOpen g := by - ext1 - dsimp [RingedSpace.basicOpen] - rw [← Set.image_inter Subtype.coe_injective] ext x - simp [map_mul, Set.mem_image] + by_cases hx : x ∈ U + · simp [mem_basicOpen (hx := hx)] + · simp [mt (basicOpen_le X _ ·) hx] @[simp] lemma basicOpen_pow {U : Opens X} (f : X.presheaf.obj (op U)) (n : ℕ) (h : 0 < n) : @@ -212,7 +214,7 @@ theorem basicOpen_of_isUnit {U : Opens X} {f : X.presheaf.obj (op U)} (hf : IsUn apply le_antisymm · exact X.basicOpen_le f intro x hx - erw [X.mem_basicOpen f (⟨x, hx⟩ : U)] + rw [SetLike.mem_coe, X.mem_basicOpen f x hx] exact RingHom.isUnit_map _ hf /-- diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean index 75e798757aa2f..2fc0a8b8893ef 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean @@ -11,7 +11,7 @@ import Mathlib.Geometry.RingedSpace.Stalks We define (bundled) locally ringed spaces (as `SheafedSpace CommRing` along with the fact that the stalks are local rings), and morphisms between these (morphisms in `SheafedSpace` with -`IsLocalRingHom` on the stalk maps). +`IsLocalHom` on the stalk maps). -/ -- Explicit universe annotations were used in this file to improve performance #12737 @@ -70,63 +70,85 @@ def 𝒪 : Sheaf CommRingCat X.toTopCat := /-- A morphism of locally ringed spaces is a morphism of ringed spaces such that the morphisms induced on stalks are local ring homomorphisms. -/ @[ext] -structure Hom (X Y : LocallyRingedSpace.{u}) : Type _ where - /-- the underlying morphism between ringed spaces -/ - val : X.toSheafedSpace ⟶ Y.toSheafedSpace +structure Hom (X Y : LocallyRingedSpace.{u}) + extends X.toPresheafedSpace.Hom Y.toPresheafedSpace : Type _ where /-- the underlying morphism induces a local ring homomorphism on stalks -/ - prop : ∀ x, IsLocalRingHom (val.stalkMap x) + prop : ∀ x, IsLocalHom (toHom.stalkMap x) + +/-- A morphism of locally ringed spaces as a morphism of sheafed spaces. -/ +abbrev Hom.toShHom {X Y : LocallyRingedSpace.{u}} (f : X.Hom Y) : + X.toSheafedSpace ⟶ Y.toSheafedSpace := f.1 + +@[simp, nolint simpVarHead] +lemma Hom.toShHom_mk {X Y : LocallyRingedSpace.{u}} + (f : X.toPresheafedSpace.Hom Y.toPresheafedSpace) (hf) : + Hom.toShHom ⟨f, hf⟩ = f := rfl instance : Quiver LocallyRingedSpace := ⟨Hom⟩ -@[ext] lemma Hom.ext' (X Y : LocallyRingedSpace.{u}) {f g : X ⟶ Y} (h : f.val = g.val) : f = g := - Hom.ext h +@[ext] lemma Hom.ext' {X Y : LocallyRingedSpace.{u}} {f g : X ⟶ Y} (h : f.toShHom = g.toShHom) : + f = g := by cases f; cases g; congr + +/-- See Note [custom simps projection] -/ +def Hom.Simps.toShHom {X Y : LocallyRingedSpace.{u}} (f : X.Hom Y) : + X.toSheafedSpace ⟶ Y.toSheafedSpace := + f.toShHom + +initialize_simps_projections Hom (toHom → toShHom) /-- A morphism of locally ringed spaces `f : X ⟶ Y` induces a local ring homomorphism from `Y.stalk (f x)` to `X.stalk x` for any `x : X`. -/ noncomputable def Hom.stalkMap {X Y : LocallyRingedSpace.{u}} (f : Hom X Y) (x : X) : Y.presheaf.stalk (f.1.1 x) ⟶ X.presheaf.stalk x := - f.val.stalkMap x + f.toShHom.stalkMap x -instance {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : IsLocalRingHom (f.stalkMap x) := +@[instance] +theorem isLocalHomStalkMap {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : + IsLocalHom (f.stalkMap x) := f.2 x -instance {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : - IsLocalRingHom (f.val.stalkMap x) := +@[instance] +theorem isLocalHomValStalkMap {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : + IsLocalHom (f.toShHom.stalkMap x) := f.2 x +@[deprecated (since := "2024-10-10")] +alias isLocalRingHomValStalkMap := isLocalHomValStalkMap + /-- The identity morphism on a locally ringed space. -/ -@[simps] +@[simps! toShHom] def id (X : LocallyRingedSpace.{u}) : Hom X X := - ⟨𝟙 _, fun x => by erw [PresheafedSpace.stalkMap.id]; apply isLocalRingHom_id⟩ + ⟨𝟙 X.toSheafedSpace, fun x => by erw [PresheafedSpace.stalkMap.id]; infer_instance⟩ instance (X : LocallyRingedSpace.{u}) : Inhabited (Hom X X) := ⟨id X⟩ /-- Composition of morphisms of locally ringed spaces. -/ def comp {X Y Z : LocallyRingedSpace.{u}} (f : Hom X Y) (g : Hom Y Z) : Hom X Z := - ⟨f.val ≫ g.val, fun x => by + ⟨f.toShHom ≫ g.toShHom, fun x => by erw [PresheafedSpace.stalkMap.comp] - exact @isLocalRingHom_comp _ _ _ _ _ _ _ _ (f.2 _) (g.2 _)⟩ + infer_instance⟩ /-- The category of locally ringed spaces. -/ instance : Category LocallyRingedSpace.{u} where Hom := Hom id := id - comp {X Y Z} f g := comp f g - comp_id {X Y} f := Hom.ext <| by simp [comp] - id_comp {X Y} f := Hom.ext <| by simp [comp] - assoc {_ _ _ _} f g h := Hom.ext <| by simp [comp] + comp {_ _ _} f g := comp f g + comp_id {X Y} f := Hom.ext' <| by simp [comp] + id_comp {X Y} f := Hom.ext' <| by simp [comp] + assoc {_ _ _ _} f g h := Hom.ext' <| by simp [comp] /-- The forgetful functor from `LocallyRingedSpace` to `SheafedSpace CommRing`. -/ @[simps] def forgetToSheafedSpace : LocallyRingedSpace.{u} ⥤ SheafedSpace CommRingCat.{u} where obj X := X.toSheafedSpace - map {X Y} f := f.1 + map {_ _} f := f.1 +/-- The canonical map `X ⟶ Spec Γ(X, ⊤)`. This is the unit of the `Γ-Spec` adjunction. -/ instance : forgetToSheafedSpace.Faithful where - map_injective {_ _} _ _ h := Hom.ext h + map_injective {_ _} _ _ h := Hom.ext' h /-- The forgetful functor from `LocallyRingedSpace` to `Top`. -/ @[simps!] @@ -134,22 +156,25 @@ def forgetToTop : LocallyRingedSpace.{u} ⥤ TopCat.{u} := forgetToSheafedSpace ⋙ SheafedSpace.forget _ @[simp] -theorem comp_val {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : - (f ≫ g).val = f.val ≫ g.val := +theorem comp_toShHom {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).toShHom = f.toShHom ≫ g.toShHom := rfl -@[simp] theorem id_val' (X : LocallyRingedSpace.{u}) : Hom.val (𝟙 X) = 𝟙 X.toSheafedSpace := +/-- A variant of `id_toShHom'` that works with `𝟙 X` instead of `id X`. -/ +@[simp] theorem id_toShHom' (X : LocallyRingedSpace.{u}) : + Hom.toShHom (𝟙 X) = 𝟙 X.toSheafedSpace := rfl --- Porting note: complains that `(f ≫ g).val.c` can be further simplified --- so changed to its simp normal form `(f.val ≫ g.val).c` -@[simp] -theorem comp_val_c {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : - (f.1 ≫ g.1).c = g.val.c ≫ (Presheaf.pushforward _ g.val.base).map f.val.c := +theorem comp_base {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).base = f.base ≫ g.base := + rfl + +theorem comp_c {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).c = g.c ≫ (Presheaf.pushforward _ g.base).map f.c := rfl -theorem comp_val_c_app {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (U : (Opens Z)ᵒᵖ) : - (f ≫ g).val.c.app U = g.val.c.app U ≫ f.val.c.app (op <| (Opens.map g.val.base).obj U.unop) := +theorem comp_c_app {X Y Z : LocallyRingedSpace.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (U : (Opens Z)ᵒᵖ) : + (f ≫ g).c.app U = g.c.app U ≫ f.c.app (op <| (Opens.map g.base).obj U.unop) := rfl /-- Given two locally ringed spaces `X` and `Y`, an isomorphism between `X` and `Y` as _sheafed_ @@ -157,15 +182,14 @@ spaces can be lifted to a morphism `X ⟶ Y` as locally ringed spaces. See also `isoOfSheafedSpaceIso`. -/ -@[simps] +@[simps! toShHom] def homOfSheafedSpaceHomOfIsIso {X Y : LocallyRingedSpace.{u}} (f : X.toSheafedSpace ⟶ Y.toSheafedSpace) [IsIso f] : X ⟶ Y := - Hom.mk f fun x => + Hom.mk f fun _ => -- Here we need to see that the stalk maps are really local ring homomorphisms. -- This can be solved by type class inference, because stalk maps of isomorphisms -- are isomorphisms and isomorphisms are local ring homomorphisms. - show IsLocalRingHom ((SheafedSpace.forgetToPresheafedSpace.map f).stalkMap x) by - infer_instance + inferInstance /-- Given two locally ringed spaces `X` and `Y`, an isomorphism between `X` and `Y` as _sheafed_ spaces can be lifted to an isomorphism `X ⟶ Y` as locally ringed spaces. @@ -178,22 +202,23 @@ def isoOfSheafedSpaceIso {X Y : LocallyRingedSpace.{u}} (f : X.toSheafedSpace X ≅ Y where hom := homOfSheafedSpaceHomOfIsIso f.hom inv := homOfSheafedSpaceHomOfIsIso f.inv - hom_inv_id := Hom.ext f.hom_inv_id - inv_hom_id := Hom.ext f.inv_hom_id + hom_inv_id := Hom.ext' f.hom_inv_id + inv_hom_id := Hom.ext' f.inv_hom_id instance : forgetToSheafedSpace.ReflectsIsomorphisms where reflects {_ _} f i := { out := ⟨homOfSheafedSpaceHomOfIsIso (CategoryTheory.inv (forgetToSheafedSpace.map f)), - Hom.ext (IsIso.hom_inv_id (I := i)), Hom.ext (IsIso.inv_hom_id (I := i))⟩ } + Hom.ext' (IsIso.hom_inv_id (I := i)), Hom.ext' (IsIso.inv_hom_id (I := i))⟩ } -instance is_sheafedSpace_iso {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) [IsIso f] : IsIso f.1 := +instance is_sheafedSpace_iso {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) [IsIso f] : + IsIso f.toShHom := LocallyRingedSpace.forgetToSheafedSpace.map_isIso f /-- The restriction of a locally ringed space along an open embedding. -/ @[simps!] -def restrict {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} (h : OpenEmbedding f) : - LocallyRingedSpace where +def restrict {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} + (h : IsOpenEmbedding f) : LocallyRingedSpace where localRing := by intro x -- We show that the stalk of the restriction is isomorphic to the original stalk, @@ -203,13 +228,13 @@ def restrict {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} (h /-- The canonical map from the restriction to the subspace. -/ def ofRestrict {U : TopCat} (X : LocallyRingedSpace.{u}) - {f : U ⟶ X.toTopCat} (h : OpenEmbedding f) : X.restrict h ⟶ X := + {f : U ⟶ X.toTopCat} (h : IsOpenEmbedding f) : X.restrict h ⟶ X := ⟨X.toPresheafedSpace.ofRestrict h, fun _ => inferInstance⟩ /-- The restriction of a locally ringed space `X` to the top subspace is isomorphic to `X` itself. -/ def restrictTopIso (X : LocallyRingedSpace.{u}) : - X.restrict (Opens.openEmbedding ⊤) ≅ X := + X.restrict (Opens.isOpenEmbedding ⊤) ≅ X := isoOfSheafedSpaceIso X.toSheafedSpace.restrictTopIso /-- The global sections, notated Gamma. @@ -228,10 +253,10 @@ theorem Γ_obj_op (X : LocallyRingedSpace.{u}) : Γ.obj (op X) = X.presheaf.obj rfl @[simp] -theorem Γ_map {X Y : LocallyRingedSpace.{u}ᵒᵖ} (f : X ⟶ Y) : Γ.map f = f.unop.1.c.app (op ⊤) := +theorem Γ_map {X Y : LocallyRingedSpace.{u}ᵒᵖ} (f : X ⟶ Y) : Γ.map f = f.unop.c.app (op ⊤) := rfl -theorem Γ_map_op {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) : Γ.map f.op = f.1.c.app (op ⊤) := +theorem Γ_map_op {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) : Γ.map f.op = f.c.app (op ⊤) := rfl /-- The empty locally ringed space. -/ @@ -258,21 +283,6 @@ instance {X : LocallyRingedSpace} : Unique (∅ ⟶ X) where noncomputable def emptyIsInitial : Limits.IsInitial (∅ : LocallyRingedSpace.{u}) := Limits.IsInitial.ofUnique _ -theorem preimage_basicOpen {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) {U : Opens Y} - (s : Y.presheaf.obj (op U)) : - (Opens.map f.1.base).obj (Y.toRingedSpace.basicOpen s) = - @RingedSpace.basicOpen X.toRingedSpace ((Opens.map f.1.base).obj U) (f.1.c.app _ s) := by - ext x - constructor - · rintro ⟨⟨y, hyU⟩, hy : IsUnit _, rfl : y = _⟩ - erw [RingedSpace.mem_basicOpen _ _ ⟨x, show x ∈ (Opens.map f.1.base).obj U from hyU⟩, - ← PresheafedSpace.stalkMap_germ_apply] - exact (f.val.stalkMap _).isUnit_map hy - · rintro ⟨y, hy : IsUnit _, rfl⟩ - erw [RingedSpace.mem_basicOpen _ _ ⟨f.1.base y.1, y.2⟩] - erw [← PresheafedSpace.stalkMap_germ_apply] at hy - exact (isUnit_map_iff (f.val.stalkMap _) _).mp hy - -- This actually holds for all ringed spaces with nontrivial stalks. theorem basicOpen_zero (X : LocallyRingedSpace.{u}) (U : Opens X.carrier) : X.toRingedSpace.basicOpen (0 : X.presheaf.obj <| op U) = ⊥ := by @@ -300,30 +310,30 @@ lemma basicOpen_eq_bot_of_isNilpotent (X : LocallyRingedSpace.{u}) (U : Opens X. instance component_nontrivial (X : LocallyRingedSpace.{u}) (U : Opens X.carrier) [hU : Nonempty U] : Nontrivial (X.presheaf.obj <| op U) := - (X.presheaf.germ hU.some).domain_nontrivial + (X.presheaf.germ _ _ hU.some.2).domain_nontrivial @[simp] -lemma iso_hom_val_base_inv_val_base {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) : - e.hom.val.base ≫ e.inv.val.base = 𝟙 _ := by - rw [← SheafedSpace.comp_base, ← LocallyRingedSpace.comp_val] +lemma iso_hom_base_inv_base {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) : + e.hom.base ≫ e.inv.base = 𝟙 _ := by + rw [← SheafedSpace.comp_base, ← LocallyRingedSpace.comp_toShHom] simp @[simp] -lemma iso_hom_val_base_inv_val_base_apply {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) (x : X) : - (e.inv.val.base (e.hom.val.base x)) = x := by - show (e.hom.val.base ≫ e.inv.val.base) x = 𝟙 X.toPresheafedSpace x +lemma iso_hom_base_inv_base_apply {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) (x : X) : + (e.inv.base (e.hom.base x)) = x := by + show (e.hom.base ≫ e.inv.base) x = 𝟙 X.toPresheafedSpace x simp @[simp] -lemma iso_inv_val_base_hom_val_base {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) : - e.inv.val.base ≫ e.hom.val.base = 𝟙 _ := by - rw [← SheafedSpace.comp_base, ← LocallyRingedSpace.comp_val] +lemma iso_inv_base_hom_base {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) : + e.inv.base ≫ e.hom.base = 𝟙 _ := by + rw [← SheafedSpace.comp_base, ← LocallyRingedSpace.comp_toShHom] simp @[simp] -lemma iso_inv_val_base_hom_val_base_apply {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) (y : Y) : - (e.hom.val.base (e.inv.val.base y)) = y := by - show (e.inv.val.base ≫ e.hom.val.base) y = 𝟙 Y.toPresheafedSpace y +lemma iso_inv_base_hom_base_apply {X Y : LocallyRingedSpace.{u}} (e : X ≅ Y) (y : Y) : + (e.hom.base (e.inv.base y)) = y := by + show (e.inv.base ≫ e.hom.base) y = 𝟙 Y.toPresheafedSpace y simp section Stalks @@ -336,17 +346,17 @@ lemma stalkMap_id (X : LocallyRingedSpace.{u}) (x : X) : PresheafedSpace.stalkMap.id _ x lemma stalkMap_comp (x : X) : - (f ≫ g : X ⟶ Z).stalkMap x = g.stalkMap (f.val.base x) ≫ f.stalkMap x := - PresheafedSpace.stalkMap.comp f.val g.val x + (f ≫ g : X ⟶ Z).stalkMap x = g.stalkMap (f.base x) ≫ f.stalkMap x := + PresheafedSpace.stalkMap.comp f.toShHom g.toShHom x @[reassoc] lemma stalkSpecializes_stalkMap (x x' : X) (h : x ⤳ x') : - Y.presheaf.stalkSpecializes (f.val.base.map_specializes h) ≫ f.stalkMap x = + Y.presheaf.stalkSpecializes (f.base.map_specializes h) ≫ f.stalkMap x = f.stalkMap x' ≫ X.presheaf.stalkSpecializes h := - PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.val h + PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.toShHom h lemma stalkSpecializes_stalkMap_apply (x x' : X) (h : x ⤳ x') (y) : - f.stalkMap x (Y.presheaf.stalkSpecializes (f.val.base.map_specializes h) y) = + f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.map_specializes h) y) = (X.presheaf.stalkSpecializes h (f.stalkMap x' y)) := DFunLike.congr_fun (stalkSpecializes_stalkMap f x x' h) y @@ -374,56 +384,59 @@ lemma stalkMap_congr_point {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x x' : @[reassoc (attr := simp)] lemma stalkMap_hom_inv (e : X ≅ Y) (y : Y) : - e.hom.stalkMap (e.inv.val.base y) ≫ e.inv.stalkMap y = + e.hom.stalkMap (e.inv.base y) ≫ e.inv.stalkMap y = Y.presheaf.stalkSpecializes (specializes_of_eq <| by simp) := by rw [← stalkMap_comp, LocallyRingedSpace.stalkMap_congr_hom (e.inv ≫ e.hom) (𝟙 _) (by simp)] simp @[simp] lemma stalkMap_hom_inv_apply (e : X ≅ Y) (y : Y) (z) : - e.inv.stalkMap y (e.hom.stalkMap (e.inv.val.base y) z) = + e.inv.stalkMap y (e.hom.stalkMap (e.inv.base y) z) = Y.presheaf.stalkSpecializes (specializes_of_eq <| by simp) z := DFunLike.congr_fun (stalkMap_hom_inv e y) z @[reassoc (attr := simp)] lemma stalkMap_inv_hom (e : X ≅ Y) (x : X) : - e.inv.stalkMap (e.hom.val.base x) ≫ e.hom.stalkMap x = + e.inv.stalkMap (e.hom.base x) ≫ e.hom.stalkMap x = X.presheaf.stalkSpecializes (specializes_of_eq <| by simp) := by rw [← stalkMap_comp, LocallyRingedSpace.stalkMap_congr_hom (e.hom ≫ e.inv) (𝟙 _) (by simp)] simp @[simp] lemma stalkMap_inv_hom_apply (e : X ≅ Y) (x : X) (y) : - e.hom.stalkMap x (e.inv.stalkMap (e.hom.val.base x) y) = + e.hom.stalkMap x (e.inv.stalkMap (e.hom.base x) y) = X.presheaf.stalkSpecializes (specializes_of_eq <| by simp) y := DFunLike.congr_fun (stalkMap_inv_hom e x) y -@[reassoc] -lemma stalkMap_germ (U : Opens Y) - (x : (Opens.map f.val.base).obj U) : - Y.presheaf.germ ⟨f.val.base x.val, x.property⟩ ≫ f.stalkMap x.val = - f.val.c.app (op U) ≫ X.presheaf.germ x := - PresheafedSpace.stalkMap_germ f.val U x - -lemma stalkMap_germ_apply (U : Opens Y) (x : (Opens.map f.val.base).obj U) (y) : - f.stalkMap x.val (Y.presheaf.germ ⟨f.val.base x.val, x.property⟩ y) = - X.presheaf.germ x (f.val.c.app (op U) y) := - PresheafedSpace.stalkMap_germ_apply f.val U x y - @[reassoc (attr := simp)] -lemma stalkMap_germ' (U : Opens Y) (x : X) (hx : f.val.base x ∈ U) : - Y.presheaf.germ ⟨f.val.base x, hx⟩ ≫ f.stalkMap x = - f.val.c.app (op U) ≫ X.presheaf.germ (U := (Opens.map f.val.base).obj U) ⟨x, hx⟩ := - PresheafedSpace.stalkMap_germ' f.val U x hx +lemma stalkMap_germ (U : Opens Y) (x : X) (hx : f.base x ∈ U) : + Y.presheaf.germ U (f.base x) hx ≫ f.stalkMap x = + f.c.app (op U) ≫ X.presheaf.germ ((Opens.map f.base).obj U) x hx := + PresheafedSpace.stalkMap_germ f.toShHom U x hx -@[simp] -lemma stalkMap_germ'_apply - (U : Opens Y) (x : X) (hx : f.val.base x ∈ U) (y : Y.presheaf.obj (op U)) : - f.stalkMap x (Y.presheaf.germ (U := U) ⟨f.val.base x, hx⟩ y) = - X.presheaf.germ (U := (Opens.map f.val.base).obj U) ⟨x, hx⟩ (f.val.c.app (op U) y) := - PresheafedSpace.stalkMap_germ_apply f.val U ⟨x, hx⟩ y +lemma stalkMap_germ_apply (U : Opens Y) (x : X) (hx : f.base x ∈ U) (y) : + f.stalkMap x (Y.presheaf.germ U (f.base x) hx y) = + X.presheaf.germ ((Opens.map f.base).obj U) x hx (f.c.app (op U) y) := + PresheafedSpace.stalkMap_germ_apply f.toShHom U x hx y -variable {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} (h : OpenEmbedding f) +theorem preimage_basicOpen {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) {U : Opens Y} + (s : Y.presheaf.obj (op U)) : + (Opens.map f.base).obj (Y.toRingedSpace.basicOpen s) = + @RingedSpace.basicOpen X.toRingedSpace ((Opens.map f.base).obj U) (f.c.app _ s) := by + ext x + constructor + · rintro ⟨hxU, hx⟩ + rw [SetLike.mem_coe, X.toRingedSpace.mem_basicOpen _ _ hxU] + delta toRingedSpace + rw [← stalkMap_germ_apply] + exact (f.stalkMap _).isUnit_map hx + · rintro ⟨hxU, hx⟩ + simp only [Opens.map_coe, Set.mem_preimage, SetLike.mem_coe, toRingedSpace] at hx ⊢ + rw [RingedSpace.mem_basicOpen _ s (f.base x) hxU] + rw [← stalkMap_germ_apply] at hx + exact (isUnit_map_iff (f.toShHom.stalkMap _) _).mp hx + +variable {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} (h : IsOpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) /-- For an open embedding `f : U ⟶ X` and a point `x : U`, we get an isomorphism between the stalk @@ -434,25 +447,25 @@ def restrictStalkIso : (X.restrict h).presheaf.stalk x ≅ X.presheaf.stalk (f x @[reassoc (attr := simp)] lemma restrictStalkIso_hom_eq_germ : - (X.restrict h).presheaf.germ ⟨x, hx⟩ ≫ (X.restrictStalkIso h x).hom = - X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ := + (X.restrict h).presheaf.germ _ x hx ≫ (X.restrictStalkIso h x).hom = + X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ := PresheafedSpace.restrictStalkIso_hom_eq_germ X.toPresheafedSpace h V x hx lemma restrictStalkIso_hom_eq_germ_apply (y) : - (X.restrictStalkIso h x).hom ((X.restrict h).presheaf.germ ⟨x, hx⟩ y) = - X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ y := + (X.restrictStalkIso h x).hom ((X.restrict h).presheaf.germ _ x hx y) = + X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ y := PresheafedSpace.restrictStalkIso_hom_eq_germ_apply X.toPresheafedSpace h V x hx y @[reassoc (attr := simp)] lemma restrictStalkIso_inv_eq_germ : - X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ ≫ - (X.restrictStalkIso h x).inv = (X.restrict h).presheaf.germ ⟨x, hx⟩ := + X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ ≫ + (X.restrictStalkIso h x).inv = (X.restrict h).presheaf.germ _ x hx := PresheafedSpace.restrictStalkIso_inv_eq_germ X.toPresheafedSpace h V x hx lemma restrictStalkIso_inv_eq_germ_apply (y) : (X.restrictStalkIso h x).inv - (X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ y) = - (X.restrict h).presheaf.germ ⟨x, hx⟩ y := + (X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ y) = + (X.restrict h).presheaf.germ _ x hx y := PresheafedSpace.restrictStalkIso_inv_eq_germ_apply X.toPresheafedSpace h V x hx y lemma restrictStalkIso_inv_eq_ofRestrict : diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean index b94c92ea5a9a2..01ff44c393aaa 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean @@ -40,10 +40,9 @@ theorem colimit_exists_rep (x : colimit (C := SheafedSpace C) F) : (isColimitOfPreserves (SheafedSpace.forget _) (colimit.isColimit F)) x instance {X Y : SheafedSpace C} (f g : X ⟶ Y) : Epi (coequalizer.π f g).base := by - erw [← - show _ = (coequalizer.π f g).base from - ι_comp_coequalizerComparison f g (SheafedSpace.forget C)] - rw [← PreservesCoequalizer.iso_hom] + rw [← show _ = (coequalizer.π f g).base from + ι_comp_coequalizerComparison f g (SheafedSpace.forget C), + ← PreservesCoequalizer.iso_hom] apply epi_comp end SheafedSpace @@ -103,16 +102,16 @@ noncomputable def coproductCofanIsColimit : IsColimit (coproductCofan F) where (colimit.ι_desc (C := SheafedSpace.{u+1, u, u} CommRingCatMax.{u, u}) (forgetToSheafedSpace.mapCocone s) i : _)] haveI : - IsLocalRingHom + IsLocalHom (((forgetToSheafedSpace.mapCocone s).ι.app i).stalkMap y) := (s.ι.app i).2 y infer_instance⟩ - fac s j := LocallyRingedSpace.Hom.ext + fac _ _ := LocallyRingedSpace.Hom.ext' (colimit.ι_desc (C := SheafedSpace.{u+1, u, u} CommRingCatMax.{u, u}) _ _) uniq s f h := - LocallyRingedSpace.Hom.ext - (IsColimit.uniq _ (forgetToSheafedSpace.mapCocone s) f.1 fun j => - congr_arg LocallyRingedSpace.Hom.val (h j)) + LocallyRingedSpace.Hom.ext' + (IsColimit.uniq _ (forgetToSheafedSpace.mapCocone s) f.toShHom fun j => + congr_arg LocallyRingedSpace.Hom.toShHom (h j)) instance : HasCoproducts.{u} LocallyRingedSpace.{u} := fun _ => ⟨fun F => ⟨⟨⟨_, coproductCofanIsColimit F⟩⟩⟩⟩ @@ -132,18 +131,23 @@ variable {X Y : LocallyRingedSpace.{v}} (f g : X ⟶ Y) namespace HasCoequalizer -instance coequalizer_π_app_isLocalRingHom - (U : TopologicalSpace.Opens (coequalizer f.val g.val).carrier) : - IsLocalRingHom ((coequalizer.π f.val g.val : _).c.app (op U)) := by - have := ι_comp_coequalizerComparison f.1 g.1 SheafedSpace.forgetToPresheafedSpace +@[instance] +theorem coequalizer_π_app_isLocalHom + (U : TopologicalSpace.Opens (coequalizer f.toShHom g.toShHom).carrier) : + IsLocalHom ((coequalizer.π f.toShHom g.toShHom : _).c.app (op U)) := by + have := ι_comp_coequalizerComparison f.toShHom g.toShHom SheafedSpace.forgetToPresheafedSpace rw [← PreservesCoequalizer.iso_hom] at this erw [SheafedSpace.congr_app this.symm (op U)] rw [PresheafedSpace.comp_c_app, ← PresheafedSpace.colimitPresheafObjIsoComponentwiseLimit_hom_π] -- Porting note (#10754): this instance has to be manually added - haveI : IsIso (PreservesCoequalizer.iso SheafedSpace.forgetToPresheafedSpace f.val g.val).hom.c := + haveI : IsIso (PreservesCoequalizer.iso + SheafedSpace.forgetToPresheafedSpace f.toShHom g.toShHom).hom.c := PresheafedSpace.c_isIso_of_iso _ infer_instance +@[deprecated (since := "2024-10-10")] +alias coequalizer_π_app_isLocalRingHom := coequalizer_π_app_isLocalHom + /-! We roughly follow the construction given in [MR0302656]. Given a pair `f, g : X ⟶ Y` of morphisms of locally ringed spaces, we want to show that the stalk map of @@ -163,46 +167,46 @@ are local ring homs. -/ -variable (U : Opens (coequalizer f.1 g.1).carrier) -variable (s : (coequalizer f.1 g.1).presheaf.obj (op U)) +variable (U : Opens (coequalizer f.toShHom g.toShHom).carrier) +variable (s : (coequalizer f.toShHom g.toShHom).presheaf.obj (op U)) /-- (Implementation). The basic open set of the section `π꙳ s`. -/ noncomputable def imageBasicOpen : Opens Y := Y.toRingedSpace.basicOpen - (show Y.presheaf.obj (op (unop _)) from ((coequalizer.π f.1 g.1).c.app (op U)) s) + (show Y.presheaf.obj (op (unop _)) from ((coequalizer.π f.toShHom g.toShHom).c.app (op U)) s) theorem imageBasicOpen_image_preimage : - (coequalizer.π f.1 g.1).base ⁻¹' ((coequalizer.π f.1 g.1).base '' (imageBasicOpen f g U s).1) = - (imageBasicOpen f g U s).1 := by - fapply Types.coequalizer_preimage_image_eq_of_preimage_eq - -- Porting note: Type of `f.1.base` and `g.1.base` needs to be explicit - (f.1.base : X.carrier.1 ⟶ Y.carrier.1) (g.1.base : X.carrier.1 ⟶ Y.carrier.1) + (coequalizer.π f.toShHom g.toShHom).base ⁻¹' ((coequalizer.π f.toShHom g.toShHom).base '' + (imageBasicOpen f g U s).1) = (imageBasicOpen f g U s).1 := by + fapply Types.coequalizer_preimage_image_eq_of_preimage_eq f.base + -- Porting note: Type of `f.base` and `g.base` needs to be explicit + (g.base : X.carrier.1 ⟶ Y.carrier.1) · ext simp_rw [types_comp_apply, ← TopCat.comp_app, ← PresheafedSpace.comp_base] congr 2 - exact coequalizer.condition f.1 g.1 + exact coequalizer.condition f.toShHom g.toShHom · apply isColimitCoforkMapOfIsColimit (forget TopCat) apply isColimitCoforkMapOfIsColimit (SheafedSpace.forget _) - exact coequalizerIsCoequalizer f.1 g.1 + exact coequalizerIsCoequalizer f.toShHom g.toShHom · suffices - (TopologicalSpace.Opens.map f.1.base).obj (imageBasicOpen f g U s) = - (TopologicalSpace.Opens.map g.1.base).obj (imageBasicOpen f g U s) + (TopologicalSpace.Opens.map f.base).obj (imageBasicOpen f g U s) = + (TopologicalSpace.Opens.map g.base).obj (imageBasicOpen f g U s) by injection this delta imageBasicOpen rw [preimage_basicOpen f, preimage_basicOpen g] dsimp only [Functor.op, unop_op] -- Porting note (#11224): change `rw` to `erw` erw [← comp_apply, ← SheafedSpace.comp_c_app', ← comp_apply, ← SheafedSpace.comp_c_app', - SheafedSpace.congr_app (coequalizer.condition f.1 g.1), comp_apply, + SheafedSpace.congr_app (coequalizer.condition f.toShHom g.toShHom), comp_apply, X.toRingedSpace.basicOpen_res] apply inf_eq_right.mpr refine (RingedSpace.basicOpen_le _ _).trans ?_ - rw [coequalizer.condition f.1 g.1] + rw [coequalizer.condition f.toShHom g.toShHom] theorem imageBasicOpen_image_open : - IsOpen ((coequalizer.π f.1 g.1).base '' (imageBasicOpen f g U s).1) := by - rw [← (TopCat.homeoOfIso (PreservesCoequalizer.iso (SheafedSpace.forget _) f.1 - g.1)).isOpen_preimage, TopCat.coequalizer_isOpen_iff, ← Set.preimage_comp] + IsOpen ((coequalizer.π f.toShHom g.toShHom).base '' (imageBasicOpen f g U s).1) := by + rw [← (TopCat.homeoOfIso (PreservesCoequalizer.iso (SheafedSpace.forget _) f.toShHom + g.toShHom)).isOpen_preimage, TopCat.coequalizer_isOpen_iff, ← Set.preimage_comp] erw [← TopCat.coe_comp] rw [PreservesCoequalizer.iso_hom, ι_comp_coequalizerComparison] dsimp only [SheafedSpace.forget] @@ -210,85 +214,94 @@ theorem imageBasicOpen_image_open : erw [imageBasicOpen_image_preimage] exact (imageBasicOpen f g U s).2 -instance coequalizer_π_stalk_isLocalRingHom (x : Y) : - IsLocalRingHom ((coequalizer.π f.val g.val : _).stalkMap x) := by +@[instance] +theorem coequalizer_π_stalk_isLocalHom (x : Y) : + IsLocalHom ((coequalizer.π f.toShHom g.toShHom : _).stalkMap x) := by constructor rintro a ha rcases TopCat.Presheaf.germ_exist _ _ a with ⟨U, hU, s, rfl⟩ - erw [PresheafedSpace.stalkMap_germ_apply (coequalizer.π f.1 g.1 : _) U ⟨_, hU⟩] at ha + rw [PresheafedSpace.stalkMap_germ_apply + (coequalizer.π (C := SheafedSpace _) f.toShHom g.toShHom) U _ hU] at ha let V := imageBasicOpen f g U s - have hV : (coequalizer.π f.1 g.1).base ⁻¹' ((coequalizer.π f.1 g.1).base '' V.1) = V.1 := + have hV : (coequalizer.π f.toShHom g.toShHom).base ⁻¹' + ((coequalizer.π f.toShHom g.toShHom).base '' V.1) = V.1 := imageBasicOpen_image_preimage f g U s - have hV' : - V = ⟨(coequalizer.π f.1 g.1).base ⁻¹' ((coequalizer.π f.1 g.1).base '' V.1), hV.symm ▸ V.2⟩ := + have hV' : V = ⟨(coequalizer.π f.toShHom g.toShHom).base ⁻¹' + ((coequalizer.π f.toShHom g.toShHom).base '' V.1), hV.symm ▸ V.2⟩ := SetLike.ext' hV.symm - have V_open : IsOpen ((coequalizer.π f.val g.val).base '' V.1) := + have V_open : IsOpen ((coequalizer.π f.toShHom g.toShHom).base '' V.1) := imageBasicOpen_image_open f g U s - have VleU : (⟨(coequalizer.π f.val g.val).base '' V.1, V_open⟩ : TopologicalSpace.Opens _) ≤ U := + have VleU : (⟨(coequalizer.π f.toShHom g.toShHom).base '' V.1, V_open⟩ : _) ≤ U := Set.image_subset_iff.mpr (Y.toRingedSpace.basicOpen_le _) - have hxV : x ∈ V := ⟨⟨_, hU⟩, ha, rfl⟩ - erw [← - (coequalizer f.val g.val).presheaf.germ_res_apply (homOfLE VleU) - ⟨_, @Set.mem_image_of_mem _ _ (coequalizer.π f.val g.val).base x V.1 hxV⟩ s] + have hxV : x ∈ V := ⟨hU, ha⟩ + rw [← + (coequalizer f.toShHom g.toShHom).presheaf.germ_res_apply (homOfLE VleU) _ + (@Set.mem_image_of_mem _ _ (coequalizer.π f.toShHom g.toShHom).base x V.1 hxV) s] apply RingHom.isUnit_map - rw [← isUnit_map_iff ((coequalizer.π f.val g.val : _).c.app _), ← comp_apply, + rw [← isUnit_map_iff ((coequalizer.π f.toShHom g.toShHom : _).c.app _), ← comp_apply, NatTrans.naturality, comp_apply, ← isUnit_map_iff (Y.presheaf.map (eqToHom hV').op)] -- Porting note (#11224): change `rw` to `erw` erw [← comp_apply, ← comp_apply, ← Y.presheaf.map_comp] convert @RingedSpace.isUnit_res_basicOpen Y.toRingedSpace (unop _) - (((coequalizer.π f.val g.val).c.app (op U)) s) + (((coequalizer.π f.toShHom g.toShHom).c.app (op U)) s) + +@[deprecated (since := "2024-10-10")] +alias coequalizer_π_stalk_isLocalRingHom := coequalizer_π_stalk_isLocalHom end HasCoequalizer /-- The coequalizer of two locally ringed space in the category of sheafed spaces is a locally ringed space. -/ noncomputable def coequalizer : LocallyRingedSpace where - toSheafedSpace := Limits.coequalizer f.1 g.1 + toSheafedSpace := Limits.coequalizer f.toShHom g.toShHom localRing x := by obtain ⟨y, rfl⟩ := - (TopCat.epi_iff_surjective (coequalizer.π f.val g.val).base).mp inferInstance x - exact ((coequalizer.π f.val g.val : _).stalkMap y).domain_localRing + (TopCat.epi_iff_surjective (coequalizer.π f.toShHom g.toShHom).base).mp inferInstance x + exact ((coequalizer.π f.toShHom g.toShHom : _).stalkMap y).domain_localRing /-- The explicit coequalizer cofork of locally ringed spaces. -/ noncomputable def coequalizerCofork : Cofork f g := - @Cofork.ofπ _ _ _ _ f g (coequalizer f g) ⟨coequalizer.π f.1 g.1, + @Cofork.ofπ _ _ _ _ f g (coequalizer f g) ⟨coequalizer.π f.toShHom g.toShHom, -- Porting note: this used to be automatic - HasCoequalizer.coequalizer_π_stalk_isLocalRingHom _ _⟩ - (LocallyRingedSpace.Hom.ext (coequalizer.condition f.1 g.1)) + HasCoequalizer.coequalizer_π_stalk_isLocalHom _ _⟩ + (LocallyRingedSpace.Hom.ext' (coequalizer.condition f.toShHom g.toShHom)) -theorem isLocalRingHom_stalkMap_congr {X Y : RingedSpace} (f g : X ⟶ Y) (H : f = g) (x) - (h : IsLocalRingHom (f.stalkMap x)) : - IsLocalRingHom (g.stalkMap x) := by +theorem isLocalHom_stalkMap_congr {X Y : RingedSpace} (f g : X ⟶ Y) (H : f = g) (x) + (h : IsLocalHom (f.stalkMap x)) : + IsLocalHom (g.stalkMap x) := by rw [PresheafedSpace.stalkMap.congr_hom _ _ H.symm x]; infer_instance /-- The cofork constructed in `coequalizer_cofork` is indeed a colimit cocone. -/ noncomputable def coequalizerCoforkIsColimit : IsColimit (coequalizerCofork f g) := by apply Cofork.IsColimit.mk' intro s - have e : f.val ≫ s.π.val = g.val ≫ s.π.val := by injection s.condition - refine ⟨⟨coequalizer.desc s.π.1 e, ?_⟩, ?_⟩ + have e : f.toShHom ≫ s.π.toShHom = g.toShHom ≫ s.π.toShHom := by injection s.condition + refine ⟨⟨coequalizer.desc s.π.toShHom e, ?_⟩, ?_⟩ · intro x - rcases (TopCat.epi_iff_surjective (coequalizer.π f.val g.val).base).mp inferInstance x with - ⟨y, rfl⟩ - -- Porting note: was `apply isLocalRingHom_of_comp _ (PresheafedSpace.stalkMap ...)`, this + rcases (TopCat.epi_iff_surjective + (coequalizer.π f.toShHom g.toShHom).base).mp inferInstance x with ⟨y, rfl⟩ + -- Porting note: was `apply isLocalHom_of_comp _ (PresheafedSpace.stalkMap ...)`, this -- used to allow you to provide the proof that `... ≫ ...` is a local ring homomorphism later, -- but this is no longer possible set h := _ - change IsLocalRingHom h - suffices IsLocalRingHom (((coequalizerCofork f g).π.val.stalkMap _).comp h) from - isLocalRingHom_of_comp _ ((coequalizerCofork f g).π.val.stalkMap _) - change IsLocalRingHom (_ ≫ (coequalizerCofork f g).π.val.stalkMap y) + change IsLocalHom h + suffices _ : IsLocalHom (((coequalizerCofork f g).π.1.stalkMap _).comp h) by + apply isLocalHom_of_comp _ ((coequalizerCofork f g).π.1.stalkMap _) + -- note to reviewers: this `change` is now more brittle because it now has to fully resolve + -- the type to be able to search for `MonoidHomClass`, even though of course all homs in + -- `CommRingCat` are clearly such + change IsLocalHom (h ≫ (coequalizerCofork f g).π.toShHom.stalkMap y) erw [← PresheafedSpace.stalkMap.comp] - apply isLocalRingHom_stalkMap_congr _ _ (coequalizer.π_desc s.π.1 e).symm y + apply isLocalHom_stalkMap_congr _ _ (coequalizer.π_desc s.π.toShHom e).symm y infer_instance constructor - · exact LocallyRingedSpace.Hom.ext (coequalizer.π_desc _ _) + · exact LocallyRingedSpace.Hom.ext' (coequalizer.π_desc _ _) intro m h - replace h : (coequalizerCofork f g).π.1 ≫ m.1 = s.π.1 := by rw [← h]; rfl - apply LocallyRingedSpace.Hom.ext - apply (colimit.isColimit (parallelPair f.1 g.1)).uniq (Cofork.ofπ s.π.1 e) m.1 + replace h : (coequalizerCofork f g).π.toShHom ≫ m.1 = s.π.toShHom := by rw [← h]; rfl + apply LocallyRingedSpace.Hom.ext' + apply (colimit.isColimit (parallelPair f.toShHom g.toShHom)).uniq (Cofork.ofπ s.π.toShHom e) m.1 rintro ⟨⟩ - · rw [← (colimit.cocone (parallelPair f.val g.val)).w WalkingParallelPairHom.left, + · rw [← (colimit.cocone (parallelPair f.toShHom g.toShHom)).w WalkingParallelPairHom.left, Category.assoc] change _ ≫ _ ≫ _ = _ ≫ _ congr diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean index e4395a78b6708..3a60a5f355de1 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean @@ -52,7 +52,7 @@ If we interpret sections over `U` as functions of `X` defined on `U`, then this corresponds to evaluation at `x`. -/ def evaluation (x : U) : X.presheaf.obj (op U) ⟶ X.residueField x := - X.presheaf.germ x ≫ LocalRing.residue _ + X.presheaf.germ U x.1 x.2 ≫ LocalRing.residue _ /-- The global evaluation map from `Γ(X, ⊤)` to the residue field at `x`. -/ def Γevaluation (x : X) : X.presheaf.obj (op ⊤) ⟶ X.residueField x := @@ -61,13 +61,19 @@ def Γevaluation (x : X) : X.presheaf.obj (op ⊤) ⟶ X.residueField x := @[simp] lemma evaluation_eq_zero_iff_not_mem_basicOpen (x : U) (f : X.presheaf.obj (op U)) : X.evaluation x f = 0 ↔ x.val ∉ X.toRingedSpace.basicOpen f := by - rw [X.toRingedSpace.mem_basicOpen f x, ← not_iff_not, not_not] + rw [X.toRingedSpace.mem_basicOpen f x.1 x.2, ← not_iff_not, not_not] exact (LocalRing.residue_ne_zero_iff_isUnit _) lemma evaluation_ne_zero_iff_mem_basicOpen (x : U) (f : X.presheaf.obj (op U)) : X.evaluation x f ≠ 0 ↔ x.val ∈ X.toRingedSpace.basicOpen f := by simp +lemma basicOpen_eq_bot_iff_forall_evaluation_eq_zero (f : X.presheaf.obj (op U)) : + X.toRingedSpace.basicOpen f = ⊥ ↔ ∀ (x : U), X.evaluation x f = 0 := by + simp only [evaluation_eq_zero_iff_not_mem_basicOpen, Subtype.forall] + exact ⟨fun h ↦ h ▸ fun a _ hc ↦ hc, + fun h ↦ eq_bot_iff.mpr <| fun a ha ↦ h a (X.toRingedSpace.basicOpen_le f ha) ha⟩ + @[simp] lemma Γevaluation_eq_zero_iff_not_mem_basicOpen (x : X) (f : X.presheaf.obj (op ⊤)) : X.Γevaluation x f = 0 ↔ x ∉ X.toRingedSpace.basicOpen f := @@ -77,11 +83,11 @@ lemma Γevaluation_ne_zero_iff_mem_basicOpen (x : X) (f : X.presheaf.obj (op ⊤ X.Γevaluation x f ≠ 0 ↔ x ∈ X.toRingedSpace.basicOpen f := evaluation_ne_zero_iff_mem_basicOpen X ⟨x, show x ∈ ⊤ by trivial⟩ f -variable {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) +variable {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) /-- If `X ⟶ Y` is a morphism of locally ringed spaces and `x` a point of `X`, we obtain a morphism of residue fields in the other direction. -/ -def residueFieldMap (x : X) : Y.residueField (f.val.base x) ⟶ X.residueField x := +def residueFieldMap (x : X) : Y.residueField (f.base x) ⟶ X.residueField x := LocalRing.ResidueField.map (f.stalkMap x) lemma residue_comp_residueFieldMap_eq_stalkMap_comp_residue (x : X) : @@ -92,44 +98,43 @@ lemma residue_comp_residueFieldMap_eq_stalkMap_comp_residue (x : X) : @[simp] lemma residueFieldMap_id (x : X) : residueFieldMap (𝟙 X) x = 𝟙 (X.residueField x) := by - simp only [id_val', SheafedSpace.id_base, TopCat.coe_id, id_eq, residueFieldMap, stalkMap_id] + simp only [id_toShHom', SheafedSpace.id_base, TopCat.coe_id, id_eq, residueFieldMap, stalkMap_id] apply LocalRing.ResidueField.map_id @[simp] lemma residueFieldMap_comp {Z : LocallyRingedSpace.{u}} (g : Y ⟶ Z) (x : X) : - residueFieldMap (f ≫ g) x = residueFieldMap g (f.val.base x) ≫ residueFieldMap f x := by - simp only [comp_val, SheafedSpace.comp_base, Function.comp_apply, residueFieldMap] + residueFieldMap (f ≫ g) x = residueFieldMap g (f.base x) ≫ residueFieldMap f x := by + simp only [comp_toShHom, SheafedSpace.comp_base, Function.comp_apply, residueFieldMap] simp_rw [stalkMap_comp] - haveI : IsLocalRingHom (g.stalkMap (f.val.base x)) := inferInstance apply LocalRing.ResidueField.map_comp @[reassoc] -lemma evaluation_naturality {V : Opens Y} (x : (Opens.map f.1.base).obj V) : - Y.evaluation ⟨f.val.base x, x.property⟩ ≫ residueFieldMap f x.val = - f.val.c.app (op V) ≫ X.evaluation x := by +lemma evaluation_naturality {V : Opens Y} (x : (Opens.map f.base).obj V) : + Y.evaluation ⟨f.base x, x.property⟩ ≫ residueFieldMap f x.val = + f.c.app (op V) ≫ X.evaluation x := by dsimp only [LocallyRingedSpace.evaluation, LocallyRingedSpace.residueFieldMap] rw [Category.assoc] ext a simp only [comp_apply] - erw [LocalRing.ResidueField.map_residue, PresheafedSpace.stalkMap_germ'_apply] + erw [LocalRing.ResidueField.map_residue, PresheafedSpace.stalkMap_germ_apply] rfl -lemma evaluation_naturality_apply {V : Opens Y} (x : (Opens.map f.1.base).obj V) +lemma evaluation_naturality_apply {V : Opens Y} (x : (Opens.map f.base).obj V) (a : Y.presheaf.obj (op V)) : - residueFieldMap f x.val (Y.evaluation ⟨f.val.base x, x.property⟩ a) = - X.evaluation x (f.val.c.app (op V) a) := by + residueFieldMap f x.val (Y.evaluation ⟨f.base x, x.property⟩ a) = + X.evaluation x (f.c.app (op V) a) := by simpa using congrFun (congrArg DFunLike.coe <| evaluation_naturality f x) a @[reassoc] lemma Γevaluation_naturality (x : X) : - Y.Γevaluation (f.val.base x) ≫ residueFieldMap f x = - f.val.c.app (op ⊤) ≫ X.Γevaluation x := + Y.Γevaluation (f.base x) ≫ residueFieldMap f x = + f.c.app (op ⊤) ≫ X.Γevaluation x := evaluation_naturality f ⟨x, by simp only [Opens.map_top]; trivial⟩ lemma Γevaluation_naturality_apply (x : X) (a : Y.presheaf.obj (op ⊤)) : - residueFieldMap f x (Y.Γevaluation (f.val.base x) a) = - X.Γevaluation x (f.val.c.app (op ⊤) a) := + residueFieldMap f x (Y.Γevaluation (f.base x) a) = + X.Γevaluation x (f.c.app (op ⊤) a) := evaluation_naturality_apply f ⟨x, by simp only [Opens.map_top]; trivial⟩ a end LocallyRingedSpace diff --git a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean index a966c23b3b918..6966f5cdf1f71 100644 --- a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean +++ b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean @@ -68,7 +68,7 @@ spaces, such that the sheaf map `Y(V) ⟶ f _* X(V)` is an iso for each `V ⊆ U class PresheafedSpace.IsOpenImmersion {X Y : PresheafedSpace C} (f : X ⟶ Y) : Prop where /-- the underlying continuous map of underlying spaces from the source to an open subset of the target. -/ - base_open : OpenEmbedding f.base + base_open : IsOpenEmbedding f.base /-- the underlying sheaf morphism is an isomorphism on each open subset -/ c_iso : ∀ U : Opens X, IsIso (f.c.app (op (base_open.isOpenMap.functor.obj U))) @@ -118,12 +118,12 @@ noncomputable def isoRestrict : X ≅ Y.restrict H.base_open := dsimp simp only [NatTrans.naturality_assoc, TopCat.Presheaf.pushforward_obj_obj, TopCat.Presheaf.pushforward_obj_map, Quiver.Hom.unop_op, Category.assoc] - erw [← X.presheaf.map_comp, ← X.presheaf.map_comp] + rw [← X.presheaf.map_comp, ← X.presheaf.map_comp] congr 1 @[reassoc (attr := simp)] theorem isoRestrict_hom_ofRestrict : (isoRestrict f).hom ≫ Y.ofRestrict _ = f := by - -- Porting note: `ext` did not pick up `NatTrans.ext` + -- Porting note (#11041): `ext` did not pick up `NatTrans.ext` refine PresheafedSpace.Hom.ext _ _ rfl <| NatTrans.ext <| funext fun x => ?_ simp only [isoRestrict_hom_c_app, NatTrans.comp_app, eqToHom_refl, ofRestrict_c_app, Category.assoc, whiskerRight_id'] @@ -214,7 +214,7 @@ theorem app_inv_app' (U : Opens Y) (hU : (U : Set Y) ⊆ Set.range f.base) : /-- An isomorphism is an open immersion. -/ instance ofIso {X Y : PresheafedSpace C} (H : X ≅ Y) : IsOpenImmersion H.hom where - base_open := (TopCat.homeoOfIso ((forget C).mapIso H)).openEmbedding + base_open := (TopCat.homeoOfIso ((forget C).mapIso H)).isOpenEmbedding -- Porting note: `inferInstance` will fail if Lean is not told that `H.hom.c` is iso c_iso _ := letI : IsIso H.hom.c := c_isIso_of_iso H.hom; inferInstance @@ -223,7 +223,7 @@ instance (priority := 100) ofIsIso {X Y : PresheafedSpace C} (f : X ⟶ Y) [IsIs AlgebraicGeometry.PresheafedSpace.IsOpenImmersion.ofIso (asIso f) instance ofRestrict {X : TopCat} (Y : PresheafedSpace C) {f : X ⟶ Y.carrier} - (hf : OpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) where + (hf : IsOpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) where base_open := hf c_iso U := by dsimp @@ -243,7 +243,7 @@ instance ofRestrict {X : TopCat} (Y : PresheafedSpace C) {f : X ⟶ Y.carrier} @[elementwise, simp] theorem ofRestrict_invApp {C : Type*} [Category C] (X : PresheafedSpace C) {Y : TopCat} - {f : Y ⟶ TopCat.of X.carrier} (h : OpenEmbedding f) (U : Opens (X.restrict h).carrier) : + {f : Y ⟶ TopCat.of X.carrier} (h : IsOpenEmbedding f) (U : Opens (X.restrict h).carrier) : (PresheafedSpace.IsOpenImmersion.ofRestrict X h).invApp _ U = 𝟙 _ := by delta invApp rw [IsIso.comp_inv_eq, Category.id_comp] @@ -265,7 +265,7 @@ theorem to_iso [h' : Epi f.base] : IsIso f := by have : IsIso f.c := NatIso.isIso_of_isIso_app _ apply (config := { allowSynthFailures := true }) isIso_of_components - let t : X ≃ₜ Y := (Homeomorph.ofEmbedding _ H.base_open.toEmbedding).trans + let t : X ≃ₜ Y := (Homeomorph.ofIsEmbedding _ H.base_open.isEmbedding).trans { toFun := Subtype.val invFun := fun x => ⟨x, by rw [Set.range_iff_surjective.mpr ((TopCat.epi_iff_surjective _).mp h')]; trivial⟩ @@ -286,7 +286,7 @@ variable {X Y Z : PresheafedSpace C} (f : X ⟶ Z) [hf : IsOpenImmersion f] (g : /-- (Implementation.) The projection map when constructing the pullback along an open immersion. -/ def pullbackConeOfLeftFst : - Y.restrict (TopCat.snd_openEmbedding_of_left_openEmbedding hf.base_open g.base) ⟶ X where + Y.restrict (TopCat.snd_isOpenEmbedding_of_left hf.base_open g.base) ⟶ X where base := pullback.fst _ _ c := { app := fun U => @@ -330,7 +330,7 @@ def pullbackConeOfLeftFst : rfl } theorem pullback_cone_of_left_condition : pullbackConeOfLeftFst f g ≫ f = Y.ofRestrict _ ≫ g := by - -- Porting note: `ext` did not pick up `NatTrans.ext` + -- Porting note (#11041): `ext` did not pick up `NatTrans.ext` refine PresheafedSpace.Hom.ext _ _ ?_ <| NatTrans.ext <| funext fun U => ?_ · simpa using pullback.condition · induction U using Opposite.rec' @@ -377,7 +377,7 @@ def pullbackConeOfLeftLift : s.pt ⟶ (pullbackConeOfLeft f g).pt where dsimp [s'] rw [Function.comp_def, ← Set.preimage_preimage] rw [Set.preimage_image_eq _ - (TopCat.snd_openEmbedding_of_left_openEmbedding hf.base_open g.base).inj] + (TopCat.snd_isOpenEmbedding_of_left hf.base_open g.base).inj] rfl)) naturality := fun U V i => by erw [s.snd.c.naturality_assoc] @@ -388,7 +388,7 @@ def pullbackConeOfLeftLift : s.pt ⟶ (pullbackConeOfLeft f g).pt where -- this lemma is not a `simp` lemma, because it is an implementation detail theorem pullbackConeOfLeftLift_fst : pullbackConeOfLeftLift f g s ≫ (pullbackConeOfLeft f g).fst = s.fst := by - -- Porting note: `ext` did not pick up `NatTrans.ext` + -- Porting note (#11041): `ext` did not pick up `NatTrans.ext` refine PresheafedSpace.Hom.ext _ _ ?_ <| NatTrans.ext <| funext fun x => ?_ · change pullback.lift _ _ _ ≫ pullback.fst _ _ = _ simp @@ -407,7 +407,7 @@ theorem pullbackConeOfLeftLift_fst : -- this lemma is not a `simp` lemma, because it is an implementation detail theorem pullbackConeOfLeftLift_snd : pullbackConeOfLeftLift f g s ≫ (pullbackConeOfLeft f g).snd = s.snd := by - -- Porting note: `ext` did not pick up `NatTrans.ext` + -- Porting note (#11041): `ext` did not pick up `NatTrans.ext` refine PresheafedSpace.Hom.ext _ _ ?_ <| NatTrans.ext <| funext fun x => ?_ · change pullback.lift _ _ _ ≫ pullback.snd _ _ = _ simp @@ -476,7 +476,7 @@ instance forgetPreservesLimitsOfRight : PreservesLimit (cospan g f) (forget C) : theorem pullback_snd_isIso_of_range_subset (H : Set.range g.base ⊆ Set.range f.base) : IsIso (pullback.snd f g) := by - haveI := TopCat.snd_iso_of_left_embedding_range_subset hf.base_open.toEmbedding g.base H + haveI := TopCat.snd_iso_of_left_embedding_range_subset hf.base_open.isEmbedding g.base H have : IsIso (pullback.snd f g).base := by delta pullback.snd rw [← limit.isoLimitCone_hom_π ⟨_, pullbackConeOfLeftIsLimit f g⟩ WalkingCospan.right] @@ -577,7 +577,7 @@ def toLocallyRingedSpaceHom : toLocallyRingedSpace Y f ⟶ Y := ⟨f, fun _ => inferInstance⟩ @[simp] -theorem toLocallyRingedSpaceHom_val : (toLocallyRingedSpaceHom Y f).val = f := +theorem toLocallyRingedSpaceHom_val : (toLocallyRingedSpaceHom Y f).toShHom = f := rfl instance toLocallyRingedSpace_isOpenImmersion : @@ -688,7 +688,7 @@ instance sheafedSpace_hasPullback_of_right : HasPullback g f := instance sheafedSpace_pullback_snd_of_left : SheafedSpace.IsOpenImmersion (pullback.snd f g) := by delta pullback.snd - have : _ = limit.π (cospan f g) right := preservesLimitsIso_hom_π forget (cospan f g) right + have : _ = limit.π (cospan f g) right := preservesLimitIso_hom_π forget (cospan f g) right rw [← this] have := HasLimit.isoOfNatIso_hom_π (diagramIsoCospan (cospan f g ⋙ forget)) right erw [Category.comp_id] at this @@ -699,7 +699,7 @@ instance sheafedSpace_pullback_snd_of_left : instance sheafedSpace_pullback_fst_of_right : SheafedSpace.IsOpenImmersion (pullback.fst g f) := by delta pullback.fst - have : _ = limit.π (cospan g f) left := preservesLimitsIso_hom_π forget (cospan g f) left + have : _ = limit.π (cospan g f) left := preservesLimitIso_hom_π forget (cospan g f) left rw [← this] have := HasLimit.isoOfNatIso_hom_π (diagramIsoCospan (cospan g f ⋙ forget)) left erw [Category.comp_id] at this @@ -727,7 +727,7 @@ whose forgetful functor reflects isomorphisms, preserves limits and filtered col Then a morphism `X ⟶ Y` that is a topological open embedding is an open immersion iff every stalk map is an iso. -/ -theorem of_stalk_iso {X Y : SheafedSpace C} (f : X ⟶ Y) (hf : OpenEmbedding f.base) +theorem of_stalk_iso {X Y : SheafedSpace C} (f : X ⟶ Y) (hf : IsOpenEmbedding f.base) [H : ∀ x : X.1, IsIso (f.stalkMap x)] : SheafedSpace.IsOpenImmersion f := { base_open := hf c_iso := fun U => by @@ -738,7 +738,7 @@ theorem of_stalk_iso {X Y : SheafedSpace C} (f : X ⟶ Y) (hf : OpenEmbedding f. specialize H y delta PresheafedSpace.Hom.stalkMap at H haveI H' := - TopCat.Presheaf.stalkPushforward.stalkPushforward_iso_of_openEmbedding C hf X.presheaf y + TopCat.Presheaf.stalkPushforward.stalkPushforward_iso_of_isOpenEmbedding C hf X.presheaf y have := IsIso.comp_isIso' H (@IsIso.inv_isIso _ _ _ _ _ H') rwa [Category.assoc, IsIso.hom_inv_id, Category.comp_id] at this } @@ -812,12 +812,12 @@ theorem app_inv_app' (U : Opens Y) (hU : (U : Set Y) ⊆ Set.range f.base) : PresheafedSpace.IsOpenImmersion.app_invApp f U instance ofRestrict {X : TopCat} (Y : SheafedSpace C) {f : X ⟶ Y.carrier} - (hf : OpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) := + (hf : IsOpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) := PresheafedSpace.IsOpenImmersion.ofRestrict _ hf @[elementwise, simp] theorem ofRestrict_invApp {C : Type*} [Category C] (X : SheafedSpace C) {Y : TopCat} - {f : Y ⟶ TopCat.of X.carrier} (h : OpenEmbedding f) (U : Opens (X.restrict h).carrier) : + {f : Y ⟶ TopCat.of X.carrier} (h : IsOpenEmbedding f) (U : Opens (X.restrict h).carrier) : (SheafedSpace.IsOpenImmersion.ofRestrict X h).invApp _ U = 𝟙 _ := PresheafedSpace.IsOpenImmersion.ofRestrict_invApp _ h U @@ -839,8 +839,8 @@ section Prod variable [HasLimits C] {ι : Type v} (F : Discrete ι ⥤ SheafedSpace.{_, v, v} C) [HasColimit F] (i : Discrete ι) -theorem sigma_ι_openEmbedding : OpenEmbedding (colimit.ι F i).base := by - rw [← show _ = (colimit.ι F i).base from ι_preservesColimitsIso_inv (SheafedSpace.forget C) F i] +theorem sigma_ι_isOpenEmbedding : IsOpenEmbedding (colimit.ι F i).base := by + rw [← show _ = (colimit.ι F i).base from ι_preservesColimitIso_inv (SheafedSpace.forget C) F i] have : _ = _ ≫ colimit.ι (Discrete.functor ((F ⋙ SheafedSpace.forget C).obj ∘ Discrete.mk)) i := HasColimit.isoOfNatIso_ι_hom Discrete.natIsoFunctor i rw [← Iso.eq_comp_inv] at this @@ -850,17 +850,20 @@ theorem sigma_ι_openEmbedding : OpenEmbedding (colimit.ι F i).base := by rw [← Iso.eq_comp_inv] at this cases i rw [this, ← Category.assoc] - -- Porting note: `simp_rw` can't use `TopCat.openEmbedding_iff_comp_isIso` and - -- `TopCat.openEmbedding_iff_isIso_comp`. + -- Porting note: `simp_rw` can't use `TopCat.isOpenEmbedding_iff_comp_isIso` and + -- `TopCat.isOpenEmbedding_iff_isIso_comp`. -- See https://github.com/leanprover-community/mathlib4/issues/5026 - erw [TopCat.openEmbedding_iff_comp_isIso, TopCat.openEmbedding_iff_comp_isIso, - TopCat.openEmbedding_iff_comp_isIso, TopCat.openEmbedding_iff_isIso_comp] - exact openEmbedding_sigmaMk + erw [TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_comp_isIso, + TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_isIso_comp] + exact isOpenEmbedding_sigmaMk + +@[deprecated (since := "2024-10-18")] +alias sigma_ι_openEmbedding := sigma_ι_isOpenEmbedding theorem image_preimage_is_empty (j : Discrete ι) (h : i ≠ j) (U : Opens (F.obj i)) : (Opens.map (colimit.ι (F ⋙ SheafedSpace.forgetToPresheafedSpace) j).base).obj ((Opens.map (preservesColimitIso SheafedSpace.forgetToPresheafedSpace F).inv.base).obj - ((sigma_ι_openEmbedding F i).isOpenMap.functor.obj U)) = + ((sigma_ι_isOpenEmbedding F i).isOpenMap.functor.obj U)) = ⊥ := by ext x apply iff_false_intro @@ -868,27 +871,27 @@ theorem image_preimage_is_empty (j : Discrete ι) (h : i ≠ j) (U : Opens (F.ob replace eq := ConcreteCategory.congr_arg (preservesColimitIso (SheafedSpace.forget C) F ≪≫ HasColimit.isoOfNatIso Discrete.natIsoFunctor ≪≫ TopCat.sigmaIsoSigma.{v, v} _).hom eq simp_rw [CategoryTheory.Iso.trans_hom, ← TopCat.comp_app, ← PresheafedSpace.comp_base] at eq - rw [ι_preservesColimitsIso_inv] at eq + rw [ι_preservesColimitIso_inv] at eq change ((SheafedSpace.forget C).map (colimit.ι F i) ≫ _) y = ((SheafedSpace.forget C).map (colimit.ι F j) ≫ _) x at eq cases i; cases j - rw [ι_preservesColimitsIso_hom_assoc, ι_preservesColimitsIso_hom_assoc, + rw [ι_preservesColimitIso_hom_assoc, ι_preservesColimitIso_hom_assoc, HasColimit.isoOfNatIso_ι_hom_assoc, HasColimit.isoOfNatIso_ι_hom_assoc, TopCat.sigmaIsoSigma_hom_ι, TopCat.sigmaIsoSigma_hom_ι] at eq exact h (congr_arg Discrete.mk (congr_arg Sigma.fst eq)) instance sigma_ι_isOpenImmersion [HasStrictTerminalObjects C] : SheafedSpace.IsOpenImmersion (colimit.ι F i) where - base_open := sigma_ι_openEmbedding F i + base_open := sigma_ι_isOpenEmbedding F i c_iso U := by have e : colimit.ι F i = _ := - (ι_preservesColimitsIso_inv SheafedSpace.forgetToPresheafedSpace F i).symm + (ι_preservesColimitIso_inv SheafedSpace.forgetToPresheafedSpace F i).symm have H : - OpenEmbedding + IsOpenEmbedding (colimit.ι (F ⋙ SheafedSpace.forgetToPresheafedSpace) i ≫ (preservesColimitIso SheafedSpace.forgetToPresheafedSpace F).inv).base := - e ▸ sigma_ι_openEmbedding F i + e ▸ sigma_ι_isOpenEmbedding F i suffices IsIso <| (colimit.ι (F ⋙ SheafedSpace.forgetToPresheafedSpace) i ≫ (preservesColimitIso SheafedSpace.forgetToPresheafedSpace F).inv).c.app <| op (H.isOpenMap.functor.obj U) by @@ -921,7 +924,7 @@ end SheafedSpace.IsOpenImmersion namespace LocallyRingedSpace.IsOpenImmersion -instance (X : LocallyRingedSpace) {U : TopCat} (f : U ⟶ X.toTopCat) (hf : OpenEmbedding f) : +instance (X : LocallyRingedSpace) {U : TopCat} (f : U ⟶ X.toTopCat) (hf : IsOpenEmbedding f) : LocallyRingedSpace.IsOpenImmersion (X.ofRestrict hf) := PresheafedSpace.IsOpenImmersion.ofRestrict X.toPresheafedSpace hf @@ -933,23 +936,25 @@ variable [H : LocallyRingedSpace.IsOpenImmersion f] instance (priority := 100) of_isIso [IsIso g] : LocallyRingedSpace.IsOpenImmersion g := @PresheafedSpace.IsOpenImmersion.ofIsIso _ _ _ _ g.1 ⟨⟨(inv g).1, by - erw [← LocallyRingedSpace.comp_val]; rw [IsIso.hom_inv_id] - erw [← LocallyRingedSpace.comp_val]; rw [IsIso.inv_hom_id]; constructor <;> rfl⟩⟩ + erw [← LocallyRingedSpace.comp_toShHom]; rw [IsIso.hom_inv_id] + erw [← LocallyRingedSpace.comp_toShHom]; rw [IsIso.inv_hom_id]; constructor <;> rfl⟩⟩ instance comp (g : Z ⟶ Y) [LocallyRingedSpace.IsOpenImmersion g] : LocallyRingedSpace.IsOpenImmersion (f ≫ g) := PresheafedSpace.IsOpenImmersion.comp f.1 g.1 instance mono : Mono f := - LocallyRingedSpace.forgetToSheafedSpace.mono_of_mono_map (show Mono f.1 by infer_instance) + LocallyRingedSpace.forgetToSheafedSpace.mono_of_mono_map (show Mono f.toShHom by infer_instance) instance : SheafedSpace.IsOpenImmersion (LocallyRingedSpace.forgetToSheafedSpace.map f) := H +-- note to reviewers: is there a `count_heartbeats` for this? +set_option synthInstance.maxHeartbeats 40000 in /-- An explicit pullback cone over `cospan f g` if `f` is an open immersion. -/ def pullbackConeOfLeft : PullbackCone f g := by refine PullbackCone.mk ?_ - (Y.ofRestrict (TopCat.snd_openEmbedding_of_left_openEmbedding H.base_open g.1.base)) ?_ + (Y.ofRestrict (TopCat.snd_isOpenEmbedding_of_left H.base_open g.base)) ?_ · use PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftFst f.1 g.1 intro x have := PresheafedSpace.stalkMap.congr_hom _ _ @@ -958,26 +963,28 @@ def pullbackConeOfLeft : PullbackCone f g := by rw [← IsIso.eq_inv_comp] at this rw [this] infer_instance - · exact LocallyRingedSpace.Hom.ext + · exact LocallyRingedSpace.Hom.ext' (PresheafedSpace.IsOpenImmersion.pullback_cone_of_left_condition _ _) instance : LocallyRingedSpace.IsOpenImmersion (pullbackConeOfLeft f g).snd := show PresheafedSpace.IsOpenImmersion (Y.toPresheafedSpace.ofRestrict _) by infer_instance +set_option synthInstance.maxHeartbeats 40000 in /-- The constructed `pullbackConeOfLeft` is indeed limiting. -/ def pullbackConeOfLeftIsLimit : IsLimit (pullbackConeOfLeft f g) := PullbackCone.isLimitAux' _ fun s => by refine ⟨LocallyRingedSpace.Hom.mk (PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftLift - f.1 g.1 (PullbackCone.mk _ _ (congr_arg LocallyRingedSpace.Hom.val s.condition))) ?_, - LocallyRingedSpace.Hom.ext + f.1 g.1 (PullbackCone.mk _ _ (congr_arg LocallyRingedSpace.Hom.toShHom s.condition))) ?_, + LocallyRingedSpace.Hom.ext' (PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftLift_fst f.1 g.1 _), - LocallyRingedSpace.Hom.ext + LocallyRingedSpace.Hom.ext' (PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftLift_snd f.1 g.1 _), ?_⟩ · intro x have := PresheafedSpace.stalkMap.congr_hom _ _ (PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftLift_snd f.1 g.1 - (PullbackCone.mk s.fst.1 s.snd.1 (congr_arg LocallyRingedSpace.Hom.val s.condition))) + (PullbackCone.mk s.fst.1 s.snd.1 + (congr_arg LocallyRingedSpace.Hom.toShHom s.condition))) x change _ = _ ≫ s.snd.1.stalkMap x at this rw [PresheafedSpace.stalkMap.comp, ← IsIso.eq_inv_comp] at this @@ -985,9 +992,10 @@ def pullbackConeOfLeftIsLimit : IsLimit (pullbackConeOfLeft f g) := infer_instance · intro m _ h₂ rw [← cancel_mono (pullbackConeOfLeft f g).snd] - exact h₂.trans <| LocallyRingedSpace.Hom.ext + exact h₂.trans <| LocallyRingedSpace.Hom.ext' (PresheafedSpace.IsOpenImmersion.pullbackConeOfLeftLift_snd f.1 g.1 <| - PullbackCone.mk s.fst.1 s.snd.1 <| congr_arg LocallyRingedSpace.Hom.val s.condition).symm + PullbackCone.mk s.fst.1 s.snd.1 <| congr_arg + LocallyRingedSpace.Hom.toShHom s.condition).symm instance hasPullback_of_left : HasPullback f g := ⟨⟨⟨_, pullbackConeOfLeftIsLimit f g⟩⟩⟩ @@ -1078,7 +1086,7 @@ instance forgetToPresheafedSpaceReflectsPullbackOfRight : (LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forgetToPresheafedSpace) := reflectsLimitOfReflectsIsomorphisms _ _ -theorem pullback_snd_isIso_of_range_subset (H' : Set.range g.1.base ⊆ Set.range f.1.base) : +theorem pullback_snd_isIso_of_range_subset (H' : Set.range g.base ⊆ Set.range f.base) : IsIso (pullback.snd f g) := by apply (config := {allowSynthFailures := true}) Functor.ReflectsIsomorphisms.reflects (F := LocallyRingedSpace.forgetToSheafedSpace) @@ -1095,37 +1103,35 @@ For an open immersion `f : X ⟶ Z`, given any morphism of schemes `g : Y ⟶ Z` image is contained in the image of `f`, we can lift this morphism to a unique `Y ⟶ X` that commutes with these maps. -/ -def lift (H' : Set.range g.1.base ⊆ Set.range f.1.base) : Y ⟶ X := +def lift (H' : Set.range g.base ⊆ Set.range f.base) : Y ⟶ X := -- Porting note (#10754): added instance manually have := pullback_snd_isIso_of_range_subset f g H' inv (pullback.snd f g) ≫ pullback.fst _ _ @[simp, reassoc] -theorem lift_fac (H' : Set.range g.1.base ⊆ Set.range f.1.base) : lift f g H' ≫ f = g := by +theorem lift_fac (H' : Set.range g.base ⊆ Set.range f.base) : lift f g H' ≫ f = g := by erw [Category.assoc]; rw [IsIso.inv_comp_eq]; exact pullback.condition -theorem lift_uniq (H' : Set.range g.1.base ⊆ Set.range f.1.base) (l : Y ⟶ X) (hl : l ≫ f = g) : +theorem lift_uniq (H' : Set.range g.base ⊆ Set.range f.base) (l : Y ⟶ X) (hl : l ≫ f = g) : l = lift f g H' := by rw [← cancel_mono f, hl, lift_fac] -theorem lift_range (H' : Set.range g.1.base ⊆ Set.range f.1.base) : - Set.range (lift f g H').1.base = f.1.base ⁻¹' Set.range g.1.base := by +theorem lift_range (H' : Set.range g.base ⊆ Set.range f.base) : + Set.range (lift f g H').base = f.base ⁻¹' Set.range g.base := by -- Porting note (#10754): added instance manually have := pullback_snd_isIso_of_range_subset f g H' dsimp only [lift] - have : _ = (pullback.fst f g).val.base := + have : _ = (pullback.fst f g).base := PreservesPullback.iso_hom_fst (LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forget _) f g - erw [LocallyRingedSpace.comp_val, SheafedSpace.comp_base, ← this, ← Category.assoc, coe_comp] - -- now `erw` after #13170 - rw [Set.range_comp, Set.range_iff_surjective.mpr, Set.image_univ] + rw [LocallyRingedSpace.comp_base, ← this, ← Category.assoc, coe_comp, Set.range_comp, + Set.range_iff_surjective.mpr, Set.image_univ] -- Porting note (#11224): change `rw` to `erw` on this lemma · erw [TopCat.pullback_fst_range] ext constructor · rintro ⟨y, eq⟩; exact ⟨y, eq.symm⟩ · rintro ⟨y, eq⟩; exact ⟨y, eq.symm⟩ - · erw [← TopCat.epi_iff_surjective] -- now `erw` after #13170 - rw [show (inv (pullback.snd f g)).val.base = _ from + · rw [← TopCat.epi_iff_surjective, show (inv (pullback.snd f g)).base = _ from (LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forget _).map_inv _] infer_instance @@ -1151,7 +1157,7 @@ whose forgetful functor reflects isomorphisms, preserves limits and filtered col Then a morphism `X ⟶ Y` that is a topological open embedding is an open immersion iff every stalk map is an iso. -/ -theorem of_stalk_iso {X Y : LocallyRingedSpace} (f : X ⟶ Y) (hf : OpenEmbedding f.1.base) +theorem of_stalk_iso {X Y : LocallyRingedSpace} (f : X ⟶ Y) (hf : IsOpenEmbedding f.base) [stalk_iso : ∀ x : X.1, IsIso (f.stalkMap x)] : LocallyRingedSpace.IsOpenImmersion f := SheafedSpace.IsOpenImmersion.of_stalk_iso _ hf (H := stalk_iso) @@ -1188,13 +1194,13 @@ instance (U : Opens X) : IsIso (H.invApp _ U) := by delta invApp; infer_instance theorem inv_invApp (U : Opens X) : inv (H.invApp _ U) = - f.1.c.app (op (opensFunctor f |>.obj U)) ≫ + f.c.app (op (opensFunctor f |>.obj U)) ≫ X.presheaf.map (eqToHom (by simp [Opens.map, Set.preimage_image_eq _ H.base_open.inj])) := PresheafedSpace.IsOpenImmersion.inv_invApp f.1 U @[reassoc (attr := simp)] theorem invApp_app (U : Opens X) : - H.invApp _ U ≫ f.1.c.app (op (opensFunctor f |>.obj U)) = + H.invApp _ U ≫ f.c.app (op (opensFunctor f |>.obj U)) = X.presheaf.map (eqToHom (by simp [Opens.map, Set.preimage_image_eq _ H.base_open.inj])) := PresheafedSpace.IsOpenImmersion.invApp_app f.1 U @@ -1202,37 +1208,37 @@ attribute [elementwise] invApp_app @[reassoc (attr := simp)] theorem app_invApp (U : Opens Y) : - f.1.c.app (op U) ≫ H.invApp _ ((Opens.map f.1.base).obj U) = + f.c.app (op U) ≫ H.invApp _ ((Opens.map f.base).obj U) = Y.presheaf.map - ((homOfLE (Set.image_preimage_subset f.1.base U.1)).op : - op U ⟶ op (opensFunctor f |>.obj ((Opens.map f.1.base).obj U))) := + ((homOfLE (Set.image_preimage_subset f.base U.1)).op : + op U ⟶ op (opensFunctor f |>.obj ((Opens.map f.base).obj U))) := PresheafedSpace.IsOpenImmersion.app_invApp f.1 U /-- A variant of `app_inv_app` that gives an `eqToHom` instead of `homOfLe`. -/ @[reassoc] -theorem app_inv_app' (U : Opens Y) (hU : (U : Set Y) ⊆ Set.range f.1.base) : - f.1.c.app (op U) ≫ H.invApp _ ((Opens.map f.1.base).obj U) = +theorem app_inv_app' (U : Opens Y) (hU : (U : Set Y) ⊆ Set.range f.base) : + f.c.app (op U) ≫ H.invApp _ ((Opens.map f.base).obj U) = Y.presheaf.map (eqToHom <| - le_antisymm (Set.image_preimage_subset f.1.base U.1) <| - (Set.image_preimage_eq_inter_range (f := f.1.base) (t := U.1)).symm ▸ + le_antisymm (Set.image_preimage_subset f.base U.1) <| + (Set.image_preimage_eq_inter_range (f := f.base) (t := U.1)).symm ▸ Set.subset_inter_iff.mpr ⟨fun _ h => h, hU⟩).op := PresheafedSpace.IsOpenImmersion.app_invApp f.1 U instance ofRestrict {X : TopCat} (Y : LocallyRingedSpace) {f : X ⟶ Y.carrier} - (hf : OpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) := + (hf : IsOpenEmbedding f) : IsOpenImmersion (Y.ofRestrict hf) := PresheafedSpace.IsOpenImmersion.ofRestrict _ hf @[elementwise, simp] theorem ofRestrict_invApp (X : LocallyRingedSpace) {Y : TopCat} - {f : Y ⟶ TopCat.of X.carrier} (h : OpenEmbedding f) (U : Opens (X.restrict h).carrier) : + {f : Y ⟶ TopCat.of X.carrier} (h : IsOpenEmbedding f) (U : Opens (X.restrict h).carrier) : (LocallyRingedSpace.IsOpenImmersion.ofRestrict X h).invApp _ U = 𝟙 _ := PresheafedSpace.IsOpenImmersion.ofRestrict_invApp _ h U instance stalk_iso (x : X) : IsIso (f.stalkMap x) := PresheafedSpace.IsOpenImmersion.stalk_iso f.1 x -theorem to_iso [h' : Epi f.1.base] : IsIso f := by +theorem to_iso [h' : Epi f.base] : IsIso f := by suffices IsIso (LocallyRingedSpace.forgetToSheafedSpace.map f) from isIso_of_reflects_iso _ LocallyRingedSpace.forgetToSheafedSpace exact SheafedSpace.IsOpenImmersion.to_iso f.1 diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean index 43d40b52b040c..366aeeda7b4b0 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean @@ -157,7 +157,9 @@ instance categoryOfPresheafedSpaces : Category (PresheafedSpace C) where variable {C} --- Porting note (#5229): adding an `ext` lemma. +/-- Cast `Hom X Y` as an arrow `X ⟶ Y` of presheaves. -/ +abbrev Hom.toPshHom {X Y : PresheafedSpace C} (f : Hom X Y) : X ⟶ Y := f + @[ext (iff := false)] theorem ext {X Y : PresheafedSpace C} (α β : X ⟶ Y) (w : α.base = β.base) (h : α.c ≫ whiskerRight (eqToHom (by rw [w])) _ = β.c) : α = β := @@ -291,7 +293,7 @@ section Restrict -/ @[simps] def restrict {U : TopCat} (X : PresheafedSpace C) {f : U ⟶ (X : TopCat)} - (h : OpenEmbedding f) : PresheafedSpace C where + (h : IsOpenEmbedding f) : PresheafedSpace C where carrier := U presheaf := h.isOpenMap.functor.op ⋙ X.presheaf @@ -299,7 +301,7 @@ def restrict {U : TopCat} (X : PresheafedSpace C) {f : U ⟶ (X : TopCat)} -/ @[simps] def ofRestrict {U : TopCat} (X : PresheafedSpace C) {f : U ⟶ (X : TopCat)} - (h : OpenEmbedding f) : X.restrict h ⟶ X where + (h : IsOpenEmbedding f) : X.restrict h ⟶ X where base := f c := { app := fun V => X.presheaf.map (h.isOpenMap.adjunction.counit.app V.unop).op @@ -308,8 +310,8 @@ def ofRestrict {U : TopCat} (X : PresheafedSpace C) {f : U ⟶ (X : TopCat)} rw [← map_comp, ← map_comp] rfl } -instance ofRestrict_mono {U : TopCat} (X : PresheafedSpace C) (f : U ⟶ X.1) (hf : OpenEmbedding f) : - Mono (X.ofRestrict hf) := by +instance ofRestrict_mono {U : TopCat} (X : PresheafedSpace C) (f : U ⟶ X.1) + (hf : IsOpenEmbedding f) : Mono (X.ofRestrict hf) := by haveI : Mono f := (TopCat.mono_iff_injective _).mpr hf.inj constructor intro Z g₁ g₂ eq @@ -337,14 +339,14 @@ instance ofRestrict_mono {U : TopCat} (X : PresheafedSpace C) (f : U ⟶ X.1) (h simpa using h theorem restrict_top_presheaf (X : PresheafedSpace C) : - (X.restrict (Opens.openEmbedding ⊤)).presheaf = + (X.restrict (Opens.isOpenEmbedding ⊤)).presheaf = (Opens.inclusionTopIso X.carrier).inv _* X.presheaf := by dsimp rw [Opens.inclusion'_top_functor X.carrier] rfl theorem ofRestrict_top_c (X : PresheafedSpace C) : - (X.ofRestrict (Opens.openEmbedding ⊤)).c = + (X.ofRestrict (Opens.isOpenEmbedding ⊤)).c = eqToHom (by rw [restrict_top_presheaf, ← Presheaf.Pushforward.comp_eq] @@ -363,14 +365,14 @@ theorem ofRestrict_top_c (X : PresheafedSpace C) : subspace. -/ @[simps] -def toRestrictTop (X : PresheafedSpace C) : X ⟶ X.restrict (Opens.openEmbedding ⊤) where +def toRestrictTop (X : PresheafedSpace C) : X ⟶ X.restrict (Opens.isOpenEmbedding ⊤) where base := (Opens.inclusionTopIso X.carrier).inv c := eqToHom (restrict_top_presheaf X) /-- The isomorphism from the restriction to the top subspace. -/ @[simps] -def restrictTopIso (X : PresheafedSpace C) : X.restrict (Opens.openEmbedding ⊤) ≅ X where +def restrictTopIso (X : PresheafedSpace C) : X.restrict (Opens.isOpenEmbedding ⊤) ≅ X where hom := X.ofRestrict _ inv := X.toRestrictTop hom_inv_id := by diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean index b84225323dd1d..16c8a58289001 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean @@ -121,14 +121,17 @@ abbrev toTopGlueData : TopCat.GlueData := { f_open := fun i j => (D.f_open i j).base_open toGlueData := 𝖣.mapGlueData (forget C) } -theorem ι_openEmbedding [HasLimits C] (i : D.J) : OpenEmbedding (𝖣.ι i).base := by +theorem ι_isOpenEmbedding [HasLimits C] (i : D.J) : IsOpenEmbedding (𝖣.ι i).base := by rw [← show _ = (𝖣.ι i).base from 𝖣.ι_gluedIso_inv (PresheafedSpace.forget _) _] -- Porting note: added this erewrite erw [coe_comp] refine - OpenEmbedding.comp - (TopCat.homeoOfIso (𝖣.gluedIso (PresheafedSpace.forget _)).symm).openEmbedding - (D.toTopGlueData.ι_openEmbedding i) + IsOpenEmbedding.comp + (TopCat.homeoOfIso (𝖣.gluedIso (PresheafedSpace.forget _)).symm).isOpenEmbedding + (D.toTopGlueData.ι_isOpenEmbedding i) + +@[deprecated (since := "2024-10-18")] +alias ι_openEmbedding := ι_isOpenEmbedding theorem pullback_base (i j k : D.J) (S : Set (D.V (i, j)).carrier) : (π₂ i, j, k) '' ((π₁ i, j, k) ⁻¹' S) = D.f i k ⁻¹' (D.f i j '' S) := by @@ -140,10 +143,9 @@ theorem pullback_base (i j k : D.J) (S : Set (D.V (i, j)).carrier) : rw [Set.image_comp] -- Porting note: `rw` to `erw` on `coe_comp` erw [coe_comp] - erw [Set.preimage_comp, Set.image_preimage_eq, TopCat.pullback_snd_image_fst_preimage] - -- now `erw` after #13170 + rw [Set.preimage_comp, Set.image_preimage_eq, TopCat.pullback_snd_image_fst_preimage] · rfl - erw [← TopCat.epi_iff_surjective] -- now `erw` after #13170 + rw [← TopCat.epi_iff_surjective] infer_instance /-- The red and the blue arrows in ![this diagram](https://i.imgur.com/0GiBUh6.png) commute. -/ @@ -191,20 +193,18 @@ theorem snd_invApp_t_app' (i j k : D.J) (U : Opens (pullback (D.f i j) (D.f i k) replace this := (congr_arg ((PresheafedSpace.Hom.base ·)) this).symm replace this := congr_arg (ContinuousMap.toFun ·) this dsimp at this - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [coe_comp, coe_comp] at this - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [this, Set.image_comp, Set.image_comp, Set.preimage_image_eq] + rw [coe_comp, coe_comp] at this + rw [this, Set.image_comp, Set.image_comp, Set.preimage_image_eq] swap · refine Function.HasLeftInverse.injective ⟨(D.t i k).base, fun x => ?_⟩ - erw [← comp_apply, ← comp_base, D.t_inv, id_base, id_apply] -- now `erw` after #13170 + rw [← comp_apply, ← comp_base, D.t_inv, id_base, id_apply] refine congr_arg (_ '' ·) ?_ refine congr_fun ?_ _ refine Set.image_eq_preimage_of_inverse ?_ ?_ · intro x - erw [← comp_apply, ← comp_base, IsIso.inv_hom_id, id_base, id_apply] -- now `erw` after #13170 + rw [← comp_apply, ← comp_base, IsIso.inv_hom_id, id_base, id_apply] · intro x - erw [← comp_apply, ← comp_base, IsIso.hom_inv_id, id_base, id_apply] -- now `erw` after #13170 + rw [← comp_apply, ← comp_base, IsIso.hom_inv_id, id_base, id_apply] · rw [← IsIso.eq_inv_comp, IsOpenImmersion.inv_invApp, Category.assoc, (D.t' k i j).c.naturality_assoc] simp_rw [← Category.assoc] @@ -240,7 +240,7 @@ theorem snd_invApp_t_app (i j k : D.J) (U : Opens (pullback (D.f i j) (D.f i k)) variable [HasLimits C] theorem ι_image_preimage_eq (i j : D.J) (U : Opens (D.U i).carrier) : - (Opens.map (𝖣.ι j).base).obj ((D.ι_openEmbedding i).isOpenMap.functor.obj U) = + (Opens.map (𝖣.ι j).base).obj ((D.ι_isOpenEmbedding i).isOpenMap.functor.obj U) = (opensFunctor (D.f j i)).obj ((Opens.map (𝖣.t j i).base).obj ((Opens.map (𝖣.f i j).base).obj U)) := by ext1 @@ -261,14 +261,14 @@ theorem ι_image_preimage_eq (i j : D.J) (U : Opens (D.U i).carrier) : change (D.t i j ≫ D.t j i).base '' _ = _ rw [𝖣.t_inv] simp - · erw [← coe_comp, ← TopCat.mono_iff_injective] -- now `erw` after #13170 + · rw [← coe_comp, ← TopCat.mono_iff_injective] infer_instance /-- (Implementation). The map `Γ(𝒪_{U_i}, U) ⟶ Γ(𝒪_{U_j}, 𝖣.ι j ⁻¹' (𝖣.ι i '' U))` -/ def opensImagePreimageMap (i j : D.J) (U : Opens (D.U i).carrier) : (D.U i).presheaf.obj (op U) ⟶ (D.U j).presheaf.obj (op <| - (Opens.map (𝖣.ι j).base).obj ((D.ι_openEmbedding i).isOpenMap.functor.obj U)) := + (Opens.map (𝖣.ι j).base).obj ((D.ι_isOpenEmbedding i).isOpenMap.functor.obj U)) := (D.f i j).c.app (op U) ≫ (D.t j i).c.app _ ≫ (D.f_open j i).invApp _ (unop _) ≫ @@ -314,7 +314,7 @@ the image `ι '' U` in the glued space is the limit of this diagram. -/ abbrev diagramOverOpen {i : D.J} (U : Opens (D.U i).carrier) : -- Porting note : ↓ these need to be explicit (WalkingMultispan D.diagram.fstFrom D.diagram.sndFrom)ᵒᵖ ⥤ C := - componentwiseDiagram 𝖣.diagram.multispan ((D.ι_openEmbedding i).isOpenMap.functor.obj U) + componentwiseDiagram 𝖣.diagram.multispan ((D.ι_isOpenEmbedding i).isOpenMap.functor.obj U) /-- (Implementation) The projection from the limit of `diagram_over_open` to a component of `D.U j`. -/ @@ -334,9 +334,9 @@ def ιInvAppπApp {i : D.J} (U : Opens (D.U i).carrier) (j) : rw [Set.preimage_preimage] change (D.f j k ≫ 𝖣.ι j).base ⁻¹' _ = _ -- Porting note: used to be `congr 3` - refine congr_arg (· ⁻¹' _) ?_ - convert congr_arg (ContinuousMap.toFun (α := D.V ⟨j, k⟩) (β := D.glued) ·) ?_ - refine congr_arg (PresheafedSpace.Hom.base (C := C) ·) ?_ + suffices D.f j k ≫ D.ι j = colimit.ι D.diagram.multispan (WalkingMultispan.left (j, k)) by + rw [this] + rfl exact colimit.w 𝖣.diagram.multispan (WalkingMultispan.Hom.fst (j, k)) · exact D.opensImagePreimageMap i j U @@ -368,11 +368,11 @@ def ιInvApp {i : D.J} (U : Opens (D.U i).carrier) : (D.f j k).c.app _ ≫ (D.V (j, k)).presheaf.map (eqToHom _) = D.opensImagePreimageMap _ _ _ ≫ ((D.f k j).c.app _ ≫ (D.t j k).c.app _) ≫ (D.V (j, k)).presheaf.map (eqToHom _) - erw [opensImagePreimageMap_app_assoc] + rw [opensImagePreimageMap_app_assoc] simp_rw [Category.assoc] - erw [opensImagePreimageMap_app_assoc, (D.t j k).c.naturality_assoc] - rw [snd_invApp_t_app_assoc] - erw [← PresheafedSpace.comp_c_app_assoc] + rw [opensImagePreimageMap_app_assoc, (D.t j k).c.naturality_assoc, + snd_invApp_t_app_assoc, + ← PresheafedSpace.comp_c_app_assoc] -- light-blue = green is relatively easy since the part that differs does not involve -- partial inverses. have : @@ -380,19 +380,21 @@ def ιInvApp {i : D.J} (U : Opens (D.U i).carrier) : (pullbackSymmetry _ _).hom ≫ (π₁ j, i, k) ≫ D.t j i ≫ D.f i j := by rw [← 𝖣.t_fac_assoc, 𝖣.t'_comp_eq_pullbackSymmetry_assoc, pullbackSymmetry_hom_comp_snd_assoc, pullback.condition, 𝖣.t_fac_assoc] - rw [congr_app this] - erw [PresheafedSpace.comp_c_app_assoc (pullbackSymmetry _ _).hom] + rw [congr_app this, + PresheafedSpace.comp_c_app_assoc (pullbackSymmetry _ _).hom] simp_rw [Category.assoc] congr 1 - rw [← IsIso.eq_inv_comp] - erw [IsOpenImmersion.inv_invApp] + rw [← IsIso.eq_inv_comp, + IsOpenImmersion.inv_invApp] simp_rw [Category.assoc] erw [NatTrans.naturality_assoc, ← PresheafedSpace.comp_c_app_assoc, congr_app (pullbackSymmetry_hom_comp_snd _ _)] simp_rw [Category.assoc] erw [IsOpenImmersion.inv_naturality_assoc, IsOpenImmersion.inv_naturality_assoc, IsOpenImmersion.inv_naturality_assoc, IsOpenImmersion.app_invApp_assoc] - repeat' erw [← (D.V (j, k)).presheaf.map_comp] + rw [← (D.V (j, k)).presheaf.map_comp] + erw [← (D.V (j, k)).presheaf.map_comp] + repeat rw [← (D.V (j, k)).presheaf.map_comp] -- Porting note: was just `congr` exact congr_arg ((D.V (j, k)).presheaf.map ·) rfl } } @@ -411,9 +413,9 @@ theorem ιInvApp_π {i : D.J} (U : Opens (D.U i).carrier) : · exact h2.symm · have := D.ι_gluedIso_inv (PresheafedSpace.forget _) i dsimp at this - erw [← this, coe_comp] -- now `erw` after #13170 + rw [← this, coe_comp] refine Function.Injective.comp ?_ (TopCat.GlueData.ι_injective D.toTopGlueData i) - erw [← TopCat.mono_iff_injective] -- now `erw` after #13170 + rw [← TopCat.mono_iff_injective] infer_instance delta ιInvApp rw [limit.lift_π] @@ -491,7 +493,7 @@ instance componentwise_diagram_π_isIso (i : D.J) (U : Opens (D.U i).carrier) : exact Iso.inv_hom_id ((D.U i).presheaf.mapIso (eqToIso _)) instance ιIsOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) where - base_open := D.ι_openEmbedding i + base_open := D.ι_isOpenEmbedding i c_iso U := by erw [← colimitPresheafObjIsoComponentwiseLimit_hom_π]; infer_instance /-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`. @@ -661,7 +663,7 @@ instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by instance (i j k : D.J) : PreservesLimit (cospan (𝖣.f i j) (𝖣.f i k)) forgetToSheafedSpace := inferInstance -theorem ι_jointly_surjective (x : 𝖣.glued) : ∃ (i : D.J) (y : D.U i), (𝖣.ι i).1.base y = x := +theorem ι_jointly_surjective (x : 𝖣.glued) : ∃ (i : D.J) (y : D.U i), (𝖣.ι i).base y = x := 𝖣.ι_jointly_surjective ((LocallyRingedSpace.forgetToSheafedSpace.{u} ⋙ SheafedSpace.forget CommRingCatMax.{u, u}) ⋙ forget TopCat.{u}) x diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean index 3ce2bceb89768..6f94368b8f4a6 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean @@ -224,7 +224,7 @@ theorem desc_fac (F : J ⥤ PresheafedSpace.{_, _, v} C) (s : Cocone F) (j : J) (colimitCocone F).ι.app j ≫ desc F s = s.ι.app j := by ext U · simp [desc] - · -- Porting note: the original proof is just `ext; dsimp [desc, descCApp]; simpa`, + · -- Porting note (#11041): the original proof is just `ext; dsimp [desc, descCApp]; simpa`, -- but this has to be expanded a bit rw [NatTrans.comp_app, PresheafedSpace.comp_c_app, whiskerRight_app] dsimp [desc, descCApp] @@ -307,7 +307,7 @@ def colimitPresheafObjIsoComponentwiseLimit (F : J ⥤ PresheafedSpace.{_, _, v} refine congr_arg (Set.preimage · U.1) (funext fun x => ?_) erw [← TopCat.comp_app] congr - exact ι_preservesColimitsIso_inv (forget C) F (unop X) + exact ι_preservesColimitIso_inv (forget C) F (unop X) · intro X Y f change ((F.map f.unop).c.app _ ≫ _ ≫ _) ≫ (F.obj (unop Y)).presheaf.map _ = _ ≫ _ rw [TopCat.Presheaf.Pushforward.comp_inv_app] @@ -326,9 +326,9 @@ theorem colimitPresheafObjIsoComponentwiseLimit_inv_ι_app (F : J ⥤ Presheafed rw [Iso.trans_inv, Iso.trans_inv, Iso.app_inv, sheafIsoOfIso_inv, pushforwardToOfIso_app, congr_app (Iso.symm_inv _)] dsimp - rw [map_id, comp_id, assoc, assoc, assoc, NatTrans.naturality] - erw [← comp_c_app_assoc] - rw [congr_app (colimit.isoColimitCocone_ι_hom _ _), assoc] + rw [map_id, comp_id, assoc, assoc, assoc, NatTrans.naturality, + ← comp_c_app_assoc, + congr_app (colimit.isoColimitCocone_ι_hom _ _), assoc] erw [limitObjIsoLimitCompEvaluation_inv_π_app_assoc, limMap_π_assoc] -- Porting note: `convert` doesn't work due to meta variable, so change to a `suffices` block set f := _ diff --git a/Mathlib/Geometry/RingedSpace/SheafedSpace.lean b/Mathlib/Geometry/RingedSpace/SheafedSpace.lean index 11a937b20ac78..4a94f1819e128 100644 --- a/Mathlib/Geometry/RingedSpace/SheafedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/SheafedSpace.lean @@ -80,7 +80,6 @@ instance : Category (SheafedSpace C) := show Category (InducedCategory (PresheafedSpace C) SheafedSpace.toPresheafedSpace) by infer_instance --- Porting note (#5229): adding an `ext` lemma. @[ext (iff := false)] theorem ext {X Y : SheafedSpace C} (α β : X ⟶ Y) (w : α.base = β.base) (h : α.c ≫ whiskerRight (eqToHom (by rw [w])) _ = β.c) : α = β := @@ -149,7 +148,7 @@ variable (C) /-- The forgetful functor from `SheafedSpace` to `Top`. -/ def forget : SheafedSpace C ⥤ TopCat where obj X := (X : TopCat) - map {X Y} f := f.base + map {_ _} f := f.base end @@ -157,20 +156,20 @@ open TopCat.Presheaf /-- The restriction of a sheafed space along an open embedding into the space. -/ -def restrict {U : TopCat} (X : SheafedSpace C) {f : U ⟶ (X : TopCat)} (h : OpenEmbedding f) : +def restrict {U : TopCat} (X : SheafedSpace C) {f : U ⟶ (X : TopCat)} (h : IsOpenEmbedding f) : SheafedSpace C := - { X.toPresheafedSpace.restrict h with IsSheaf := isSheaf_of_openEmbedding h X.IsSheaf } + { X.toPresheafedSpace.restrict h with IsSheaf := isSheaf_of_isOpenEmbedding h X.IsSheaf } /-- The map from the restriction of a presheafed space. -/ @[simps!] def ofRestrict {U : TopCat} (X : SheafedSpace C) {f : U ⟶ (X : TopCat)} - (h : OpenEmbedding f) : X.restrict h ⟶ X := X.toPresheafedSpace.ofRestrict h + (h : IsOpenEmbedding f) : X.restrict h ⟶ X := X.toPresheafedSpace.ofRestrict h /-- The restriction of a sheafed space `X` to the top subspace is isomorphic to `X` itself. -/ @[simps! hom inv] -def restrictTopIso (X : SheafedSpace C) : X.restrict (Opens.openEmbedding ⊤) ≅ X := +def restrictTopIso (X : SheafedSpace C) : X.restrict (Opens.isOpenEmbedding ⊤) ≅ X := isoMk (X.toPresheafedSpace.restrictTopIso) /-- The global sections, notated Gamma. @@ -226,7 +225,8 @@ lemma hom_stalk_ext {X Y : SheafedSpace C} (f g : X ⟶ Y) (h : f.base = g.base) obtain rfl : f = g := h congr ext U s - refine section_ext X.sheaf _ _ _ fun x ↦ show X.presheaf.germ x _ = X.presheaf.germ x _ from ?_ + refine section_ext X.sheaf _ _ _ fun x hx ↦ + show X.presheaf.germ _ x _ _ = X.presheaf.germ _ x _ _ from ?_ erw [← PresheafedSpace.stalkMap_germ_apply ⟨f, fc⟩, ← PresheafedSpace.stalkMap_germ_apply ⟨f, gc⟩] simp [h'] diff --git a/Mathlib/Geometry/RingedSpace/Stalks.lean b/Mathlib/Geometry/RingedSpace/Stalks.lean index 858441ca519fa..8f6f8f792d874 100644 --- a/Mathlib/Geometry/RingedSpace/Stalks.lean +++ b/Mathlib/Geometry/RingedSpace/Stalks.lean @@ -43,16 +43,13 @@ def Hom.stalkMap {X Y : PresheafedSpace.{_, _, v} C} (α : Hom X Y) (x : X) : @[elementwise, reassoc] theorem stalkMap_germ {X Y : PresheafedSpace.{_, _, v} C} (α : X ⟶ Y) (U : Opens Y) - (x : (Opens.map α.base).obj U) : - Y.presheaf.germ ⟨α.base x.1, x.2⟩ ≫ α.stalkMap ↑x = α.c.app (op U) ≫ X.presheaf.germ x := by + (x : X) (hx : α x ∈ U) : + Y.presheaf.germ U (α x) hx ≫ α.stalkMap x = α.c.app (op U) ≫ + X.presheaf.germ ((Opens.map α.base).obj U) x hx := by rw [Hom.stalkMap, stalkFunctor_map_germ_assoc, stalkPushforward_germ] -@[simp, elementwise, reassoc] -theorem stalkMap_germ' {X Y : PresheafedSpace.{_, _, v} C} - (α : X ⟶ Y) (U : Opens Y) (x : X) (hx : α.base x ∈ U) : - Y.presheaf.germ ⟨α.base x, hx⟩ ≫ α.stalkMap x = α.c.app (op U) ≫ - X.presheaf.germ (U := (Opens.map α.base).obj U) ⟨x, hx⟩ := - stalkMap_germ α U ⟨x, hx⟩ +@[deprecated (since := "2024-07-30")] alias stalkMap_germ' := stalkMap_germ +@[deprecated (since := "2024-07-30")] alias stalkMap_germ'_assoc := stalkMap_germ section Restrict @@ -60,7 +57,7 @@ section Restrict of `X` at `f x` and the stalk of the restriction of `X` along `f` at t `x`. -/ def restrictStalkIso {U : TopCat} (X : PresheafedSpace.{_, _, v} C) {f : U ⟶ (X : TopCat.{v})} - (h : OpenEmbedding f) (x : U) : (X.restrict h).presheaf.stalk x ≅ X.presheaf.stalk (f x) := + (h : IsOpenEmbedding f) (x : U) : (X.restrict h).presheaf.stalk x ≅ X.presheaf.stalk (f x) := haveI := initial_of_adjunction (h.isOpenMap.adjunctionNhds x) Final.colimitIso (h.isOpenMap.functorNhds x).op ((OpenNhds.inclusion (f x)).op ⋙ X.presheaf) -- As a left adjoint, the functor `h.is_open_map.functor_nhds x` is initial. @@ -70,9 +67,9 @@ def restrictStalkIso {U : TopCat} (X : PresheafedSpace.{_, _, v} C) {f : U ⟶ ( -- Porting note (#11119): removed `simp` attribute, for left hand side is not in simple normal form. @[elementwise, reassoc] theorem restrictStalkIso_hom_eq_germ {U : TopCat} (X : PresheafedSpace.{_, _, v} C) - {f : U ⟶ (X : TopCat.{v})} (h : OpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) : - (X.restrict h).presheaf.germ ⟨x, hx⟩ ≫ (restrictStalkIso X h x).hom = - X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ := + {f : U ⟶ (X : TopCat.{v})} (h : IsOpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) : + (X.restrict h).presheaf.germ _ x hx ≫ (restrictStalkIso X h x).hom = + X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ := colimit.ι_pre ((OpenNhds.inclusion (f x)).op ⋙ X.presheaf) (h.isOpenMap.functorNhds x).op (op ⟨V, hx⟩) @@ -80,14 +77,14 @@ theorem restrictStalkIso_hom_eq_germ {U : TopCat} (X : PresheafedSpace.{_, _, v} -- as the simpNF linter claims they never apply. @[simp, elementwise, reassoc] theorem restrictStalkIso_inv_eq_germ {U : TopCat} (X : PresheafedSpace.{_, _, v} C) - {f : U ⟶ (X : TopCat.{v})} (h : OpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) : - X.presheaf.germ ⟨f x, show f x ∈ h.isOpenMap.functor.obj V from ⟨x, hx, rfl⟩⟩ ≫ + {f : U ⟶ (X : TopCat.{v})} (h : IsOpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) : + X.presheaf.germ (h.isOpenMap.functor.obj V) (f x) ⟨x, hx, rfl⟩ ≫ (restrictStalkIso X h x).inv = - (X.restrict h).presheaf.germ ⟨x, hx⟩ := by + (X.restrict h).presheaf.germ _ x hx := by rw [← restrictStalkIso_hom_eq_germ, Category.assoc, Iso.hom_inv_id, Category.comp_id] theorem restrictStalkIso_inv_eq_ofRestrict {U : TopCat} (X : PresheafedSpace.{_, _, v} C) - {f : U ⟶ (X : TopCat.{v})} (h : OpenEmbedding f) (x : U) : + {f : U ⟶ (X : TopCat.{v})} (h : IsOpenEmbedding f) (x : U) : (X.restrictStalkIso h x).inv = (X.ofRestrict h).stalkMap x := by -- We can't use `ext` here due to https://github.com/leanprover/std4/pull/159 refine colimit.hom_ext fun V => ?_ @@ -102,7 +99,7 @@ theorem restrictStalkIso_inv_eq_ofRestrict {U : TopCat} (X : PresheafedSpace.{_, exact (colimit.w ((OpenNhds.inclusion (f x)).op ⋙ X.presheaf) i.op).symm instance ofRestrict_stalkMap_isIso {U : TopCat} (X : PresheafedSpace.{_, _, v} C) - {f : U ⟶ (X : TopCat.{v})} (h : OpenEmbedding f) (x : U) : + {f : U ⟶ (X : TopCat.{v})} (h : IsOpenEmbedding f) (x : U) : IsIso ((X.ofRestrict h).stalkMap x) := by rw [← restrictStalkIso_inv_eq_ofRestrict]; infer_instance @@ -115,7 +112,7 @@ theorem id (X : PresheafedSpace.{_, _, v} C) (x : X) : (𝟙 X : X ⟶ X).stalkMap x = 𝟙 (X.presheaf.stalk x) := by dsimp [Hom.stalkMap] simp only [stalkPushforward.id] - erw [← map_comp] + rw [← map_comp] convert (stalkFunctor C x).map_id X.presheaf ext simp only [id_c, id_comp, Pushforward.id_hom_app, op_obj, eqToHom_refl, map_id] diff --git a/Mathlib/GroupTheory/Abelianization.lean b/Mathlib/GroupTheory/Abelianization.lean index 5ee8a835a60c4..0d35f5937e6b3 100644 --- a/Mathlib/GroupTheory/Abelianization.lean +++ b/Mathlib/GroupTheory/Abelianization.lean @@ -4,8 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Michael Howes -/ import Mathlib.Data.Finite.Card -import Mathlib.GroupTheory.Finiteness +import Mathlib.Data.Finite.Prod import Mathlib.GroupTheory.Commutator.Basic +import Mathlib.GroupTheory.Coset.Basic +import Mathlib.GroupTheory.Finiteness /-! # The abelianization of a group @@ -231,7 +233,7 @@ def Abelianization.equivOfComm {H : Type*} [CommGroup H] : H ≃* Abelianization { Abelianization.of with toFun := Abelianization.of invFun := Abelianization.lift (MonoidHom.id H) - left_inv := fun a => rfl + left_inv := fun _ => rfl right_inv := by rintro ⟨a⟩ rfl } diff --git a/Mathlib/GroupTheory/Archimedean.lean b/Mathlib/GroupTheory/Archimedean.lean index 4105f66700e0c..a84d8e3053217 100644 --- a/Mathlib/GroupTheory/Archimedean.lean +++ b/Mathlib/GroupTheory/Archimedean.lean @@ -103,6 +103,6 @@ theorem Subgroup.cyclic_of_isolated_one {H : Subgroup G} {a : G} (h₀ : 1 < a) /-- Every subgroup of `ℤ` is cyclic. -/ theorem Int.subgroup_cyclic (H : AddSubgroup ℤ) : ∃ a, H = AddSubgroup.closure {a} := - have : Ioo (0 : ℤ) 1 = ∅ := eq_empty_of_forall_not_mem fun m hm => + have : Ioo (0 : ℤ) 1 = ∅ := eq_empty_of_forall_not_mem fun _ hm => hm.1.not_le (lt_add_one_iff.1 hm.2) AddSubgroup.cyclic_of_isolated_zero one_pos <| by simp [this] diff --git a/Mathlib/GroupTheory/ArchimedeanDensely.lean b/Mathlib/GroupTheory/ArchimedeanDensely.lean index 8b00a52cd33de..cf344500028b4 100644 --- a/Mathlib/GroupTheory/ArchimedeanDensely.lean +++ b/Mathlib/GroupTheory/ArchimedeanDensely.lean @@ -191,6 +191,21 @@ lemma LinearOrderedAddCommGroup.discrete_or_denselyOrdered (G : Type*) · simp [hz.left] · simpa [lt_sub_iff_add_lt'] using hz.right +/-- Any linearly ordered archimedean additive group is either isomorphic (and order-isomorphic) +to the integers, or is densely ordered, exclusively. -/ +lemma LinearOrderedAddCommGroup.discrete_iff_not_denselyOrdered (G : Type*) + [LinearOrderedAddCommGroup G] [Archimedean G] : + Nonempty (G ≃+o ℤ) ↔ ¬ DenselyOrdered G := by + suffices ∀ (_ : G ≃+o ℤ), ¬ DenselyOrdered G by + rcases LinearOrderedAddCommGroup.discrete_or_denselyOrdered G with ⟨⟨h⟩⟩|h + · simpa [this h] using ⟨h⟩ + · simp only [h, not_true_eq_false, iff_false, not_nonempty_iff] + exact ⟨fun H ↦ (this H) h⟩ + intro e H + rw [denselyOrdered_iff_of_orderIsoClass e] at H + obtain ⟨_, _⟩ := exists_between (one_pos (α := ℤ)) + linarith + variable (G) in /-- Any linearly ordered mul-archimedean group is either isomorphic (and order-isomorphic) to the multiplicative integers, or is densely ordered. -/ @@ -201,31 +216,28 @@ lemma LinearOrderedCommGroup.discrete_or_denselyOrdered : rintro ⟨f, hf⟩ exact ⟨AddEquiv.toMultiplicative' f, hf⟩ -/-- Any nontrivial (has other than 0 and 1) linearly ordered mul-archimedean group with zero is -either isomorphic (and order-isomorphic) to `ℤₘ₀`, or is densely ordered. -/ -lemma LinearOrderedCommGroupWithZero.discrete_or_denselyOrdered (G : Type*) - [LinearOrderedCommGroupWithZero G] [Nontrivial Gˣ] [MulArchimedean G] : - Nonempty (G ≃*o ℤₘ₀) ∨ DenselyOrdered G := by - classical - refine (LinearOrderedCommGroup.discrete_or_denselyOrdered Gˣ).imp ?_ ?_ - · intro ⟨f⟩ - refine ⟨OrderMonoidIso.trans - ⟨WithZero.withZeroUnitsEquiv.symm, ?_⟩ ⟨f.withZero, ?_⟩⟩ - · intro - simp only [WithZero.withZeroUnitsEquiv, MulEquiv.symm_mk, - MulEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, MulEquiv.coe_mk, - Equiv.coe_fn_symm_mk ] - split_ifs <;> - simp_all [← Units.val_le_val] - · intro a b - induction a <;> induction b <;> - simp [MulEquiv.withZero] +variable (G) in +/-- Any linearly ordered mul-archimedean group is either isomorphic (and order-isomorphic) +to the multiplicative integers, or is densely ordered, exclusively. -/ +@[to_additive existing] +lemma LinearOrderedCommGroup.discrete_iff_not_denselyOrdered : + Nonempty (G ≃*o Multiplicative ℤ) ↔ ¬ DenselyOrdered G := by + let e : G ≃o Additive G := OrderIso.refl G + rw [denselyOrdered_iff_of_orderIsoClass e, + ← LinearOrderedAddCommGroup.discrete_iff_not_denselyOrdered (Additive G)] + refine Nonempty.congr ?_ ?_ <;> intro f + · exact ⟨MulEquiv.toAdditive' f, by simp⟩ + · exact ⟨MulEquiv.toAdditive'.symm f, by simp⟩ + +lemma denselyOrdered_units_iff {G₀ : Type*} [LinearOrderedCommGroupWithZero G₀] [Nontrivial G₀ˣ] : + DenselyOrdered G₀ˣ ↔ DenselyOrdered G₀ := by + constructor · intro H refine ⟨fun x y h ↦ ?_⟩ rcases (zero_le' (a := x)).eq_or_lt with rfl|hx - · lift y to Gˣ using h.ne'.isUnit - obtain ⟨z, hz⟩ := exists_ne (1 : Gˣ) - refine ⟨(y * |z|ₘ⁻¹ : Gˣ), ?_, ?_⟩ + · lift y to G₀ˣ using h.ne'.isUnit + obtain ⟨z, hz⟩ := exists_ne (1 : G₀ˣ) + refine ⟨(y * |z|ₘ⁻¹ : G₀ˣ), ?_, ?_⟩ · simp [zero_lt_iff] · rw [Units.val_lt_val] simp [hz] @@ -233,3 +245,55 @@ lemma LinearOrderedCommGroupWithZero.discrete_or_denselyOrdered (G : Type*) (by simp [← Units.val_lt_val, h]) refine ⟨z, ?_, ?_⟩ <;> simpa [← Units.val_lt_val] + · intro H + refine ⟨fun x y h ↦ ?_⟩ + obtain ⟨z, hz⟩ := exists_between (Units.val_lt_val.mpr h) + rcases (zero_le' (a := z)).eq_or_lt with rfl|hz' + · simp at hz + refine ⟨Units.mk0 z hz'.ne', ?_⟩ + simp [← Units.val_lt_val, hz] + +/-- Any nontrivial (has other than 0 and 1) linearly ordered mul-archimedean group with zero is +either isomorphic (and order-isomorphic) to `ℤₘ₀`, or is densely ordered. -/ +lemma LinearOrderedCommGroupWithZero.discrete_or_denselyOrdered (G : Type*) + [LinearOrderedCommGroupWithZero G] [Nontrivial Gˣ] [MulArchimedean G] : + Nonempty (G ≃*o WithZero (Multiplicative ℤ)) ∨ DenselyOrdered G := by + classical + rw [← denselyOrdered_units_iff] + refine (LinearOrderedCommGroup.discrete_or_denselyOrdered Gˣ).imp_left ?_ + intro ⟨f⟩ + refine ⟨OrderMonoidIso.trans + ⟨WithZero.withZeroUnitsEquiv.symm, ?_⟩ ⟨f.withZero, ?_⟩⟩ + · intro + simp only [WithZero.withZeroUnitsEquiv, MulEquiv.symm_mk, + MulEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, MulEquiv.coe_mk, + Equiv.coe_fn_symm_mk ] + split_ifs <;> + simp_all [← Units.val_le_val] + · intro a b + induction a <;> induction b <;> + simp [MulEquiv.withZero] + +open WithZero in +/-- Any nontrivial (has other than 0 and 1) linearly ordered mul-archimedean group with zero is +either isomorphic (and order-isomorphic) to `ℤₘ₀`, or is densely ordered, exclusively -/ +lemma LinearOrderedCommGroupWithZero.discrete_iff_not_denselyOrdered (G : Type*) + [LinearOrderedCommGroupWithZero G] [Nontrivial Gˣ] [MulArchimedean G] : + Nonempty (G ≃*o WithZero (Multiplicative ℤ)) ↔ ¬ DenselyOrdered G := by + rw [← denselyOrdered_units_iff, + ← LinearOrderedCommGroup.discrete_iff_not_denselyOrdered] + refine Nonempty.congr ?_ ?_ <;> intro f + · refine ⟨MulEquiv.unzero (withZeroUnitsEquiv.trans f), ?_⟩ + intros + simp only [MulEquiv.unzero, withZeroUnitsEquiv, MulEquiv.trans_apply, + MulEquiv.coe_mk, Equiv.coe_fn_mk, recZeroCoe_coe, OrderMonoidIso.coe_mulEquiv, + MulEquiv.symm_trans_apply, MulEquiv.symm_mk, Equiv.coe_fn_symm_mk, map_eq_zero, coe_ne_zero, + ↓reduceDIte, unzero_coe, MulEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe] + rw [← Units.val_le_val, ← map_le_map_iff f, ← coe_le_coe, coe_unzero, coe_unzero] + · refine ⟨withZeroUnitsEquiv.symm.trans (MulEquiv.withZero f), ?_⟩ + intros + simp only [withZeroUnitsEquiv, MulEquiv.symm_mk, MulEquiv.withZero, + MulEquiv.toMonoidHom_eq_coe, MulEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, + MulEquiv.trans_apply, MulEquiv.coe_mk, Equiv.coe_fn_symm_mk, Equiv.coe_fn_mk] + split_ifs <;> + simp_all [← Units.val_le_val] diff --git a/Mathlib/GroupTheory/CommutingProbability.lean b/Mathlib/GroupTheory/CommutingProbability.lean index dc3739fd84c36..df8f7702b7fdd 100644 --- a/Mathlib/GroupTheory/CommutingProbability.lean +++ b/Mathlib/GroupTheory/CommutingProbability.lean @@ -47,7 +47,7 @@ theorem commProb_prod (M' : Type*) [Mul M'] : commProb (M × M') = commProb M * theorem commProb_pi {α : Type*} (i : α → Type*) [Fintype α] [∀ a, Mul (i a)] : commProb (∀ a, i a) = ∏ a, commProb (i a) := by simp_rw [commProb_def, Finset.prod_div_distrib, Finset.prod_pow, ← Nat.cast_prod, - ← Nat.card_pi, Commute, SemiconjBy, Function.funext_iff] + ← Nat.card_pi, Commute, SemiconjBy, funext_iff] congr 2 exact Nat.card_congr ⟨fun x a => ⟨⟨x.1.1 a, x.1.2 a⟩, x.2 a⟩, fun x => ⟨⟨fun a => (x a).1.1, fun a => (x a).1.2⟩, fun a => (x a).2⟩, fun x => rfl, fun x => rfl⟩ @@ -142,8 +142,8 @@ private lemma div_four_lt : {n : ℕ} → (h0 : n ≠ 0) → (h1 : n ≠ 1) → /-- A list of Dihedral groups whose product will have commuting probability `1 / n`. -/ def reciprocalFactors (n : ℕ) : List ℕ := - if h0 : n = 0 then [0] - else if h1 : n = 1 then [] + if _ : n = 0 then [0] + else if _ : n = 1 then [] else if Even n then 3 :: reciprocalFactors (n / 2) else diff --git a/Mathlib/GroupTheory/Congruence/Basic.lean b/Mathlib/GroupTheory/Congruence/Basic.lean index fe6cfe5261d0a..c17ba1b5ca00b 100644 --- a/Mathlib/GroupTheory/Congruence/Basic.lean +++ b/Mathlib/GroupTheory/Congruence/Basic.lean @@ -7,19 +7,12 @@ import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.GroupWithZero.Action.Defs import Mathlib.Data.Setoid.Basic +import Mathlib.GroupTheory.Congruence.Hom /-! # Congruence relations -This file defines congruence relations: equivalence relations that preserve a binary operation, -which in this case is multiplication or addition. The principal definition is a `structure` -extending a `Setoid` (an equivalence relation), and the inductive definition of the smallest -congruence relation containing a binary relation is also given (see `ConGen`). - -The file also proves basic properties of the quotient of a type by a congruence relation, and the -complete lattice of congruence relations on a type. We then establish an order-preserving bijection -between the set of congruence relations containing a congruence relation `c` and the set of -congruence relations on the quotient by `c`. +This file proves basic properties of the quotient of a type by a congruence relation. The second half of the file concerns congruence relations on monoids, in which case the quotient by the congruence relation is also a monoid. There are results about the universal @@ -27,17 +20,6 @@ property of quotients of monoids, and the isomorphism theorems for monoids. ## Implementation notes -The inductive definition of a congruence relation could be a nested inductive type, defined using -the equivalence closure of a binary relation `EqvGen`, but the recursor generated does not work. -A nested inductive definition could conceivably shorten proofs, because they would allow invocation -of the corresponding lemmas about `EqvGen`. - -The lemmas `refl`, `symm` and `trans` are not tagged with `@[refl]`, `@[symm]`, and `@[trans]` -respectively as these tags do not work on a structure coerced to a binary relation. - -There is a coercion from elements of a type to the element's equivalence class under a -congruence relation. - A congruence relation on a monoid `M` can be thought of as a submonoid of `M × M` for which membership is an equivalence relation, but whilst this fact is established in the file, it is not used, since this perspective adds more layers of definitional unfolding. @@ -53,136 +35,16 @@ variable (M : Type*) {N : Type*} {P : Type*} open Function Setoid -/-- A congruence relation on a type with an addition is an equivalence relation which - preserves addition. -/ -structure AddCon [Add M] extends Setoid M where - /-- Additive congruence relations are closed under addition -/ - add' : ∀ {w x y z}, r w x → r y z → r (w + y) (x + z) - -/-- A congruence relation on a type with a multiplication is an equivalence relation which - preserves multiplication. -/ -@[to_additive AddCon] -structure Con [Mul M] extends Setoid M where - /-- Congruence relations are closed under multiplication -/ - mul' : ∀ {w x y z}, r w x → r y z → r (w * y) (x * z) - -/-- The equivalence relation underlying an additive congruence relation. -/ -add_decl_doc AddCon.toSetoid - -/-- The equivalence relation underlying a multiplicative congruence relation. -/ -add_decl_doc Con.toSetoid - variable {M} -/-- The inductively defined smallest additive congruence relation containing a given binary - relation. -/ -inductive AddConGen.Rel [Add M] (r : M → M → Prop) : M → M → Prop - | of : ∀ x y, r x y → AddConGen.Rel r x y - | refl : ∀ x, AddConGen.Rel r x x - | symm : ∀ {x y}, AddConGen.Rel r x y → AddConGen.Rel r y x - | trans : ∀ {x y z}, AddConGen.Rel r x y → AddConGen.Rel r y z → AddConGen.Rel r x z - | add : ∀ {w x y z}, AddConGen.Rel r w x → AddConGen.Rel r y z → AddConGen.Rel r (w + y) (x + z) - -/-- The inductively defined smallest multiplicative congruence relation containing a given binary - relation. -/ -@[to_additive AddConGen.Rel] -inductive ConGen.Rel [Mul M] (r : M → M → Prop) : M → M → Prop - | of : ∀ x y, r x y → ConGen.Rel r x y - | refl : ∀ x, ConGen.Rel r x x - | symm : ∀ {x y}, ConGen.Rel r x y → ConGen.Rel r y x - | trans : ∀ {x y z}, ConGen.Rel r x y → ConGen.Rel r y z → ConGen.Rel r x z - | mul : ∀ {w x y z}, ConGen.Rel r w x → ConGen.Rel r y z → ConGen.Rel r (w * y) (x * z) - -/-- The inductively defined smallest multiplicative congruence relation containing a given binary - relation. -/ -@[to_additive addConGen "The inductively defined smallest additive congruence relation containing -a given binary relation."] -def conGen [Mul M] (r : M → M → Prop) : Con M := - ⟨⟨ConGen.Rel r, ⟨ConGen.Rel.refl, ConGen.Rel.symm, ConGen.Rel.trans⟩⟩, ConGen.Rel.mul⟩ - namespace Con section variable [Mul M] [Mul N] [Mul P] (c : Con M) -@[to_additive] -instance : Inhabited (Con M) := - ⟨conGen EmptyRelation⟩ - -/-- A coercion from a congruence relation to its underlying binary relation. -/ -@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."] -instance : FunLike (Con M) M (M → Prop) where - coe c := c.r - coe_injective' x y h := by - rcases x with ⟨⟨x, _⟩, _⟩ - rcases y with ⟨⟨y, _⟩, _⟩ - have : x = y := h - subst x; rfl - -@[to_additive (attr := simp)] -theorem rel_eq_coe (c : Con M) : c.r = c := - rfl - -/-- Congruence relations are reflexive. -/ -@[to_additive "Additive congruence relations are reflexive."] -protected theorem refl (x) : c x x := - c.toSetoid.refl' x - -/-- Congruence relations are symmetric. -/ -@[to_additive "Additive congruence relations are symmetric."] -protected theorem symm {x y} : c x y → c y x := c.toSetoid.symm' - -/-- Congruence relations are transitive. -/ -@[to_additive "Additive congruence relations are transitive."] -protected theorem trans {x y z} : c x y → c y z → c x z := c.toSetoid.trans' - -/-- Multiplicative congruence relations preserve multiplication. -/ -@[to_additive "Additive congruence relations preserve addition."] -protected theorem mul {w x y z} : c w x → c y z → c (w * y) (x * z) := c.mul' - -@[to_additive (attr := simp)] -theorem rel_mk {s : Setoid M} {h a b} : Con.mk s h a b ↔ r a b := - Iff.rfl - -/-- Given a type `M` with a multiplication, a congruence relation `c` on `M`, and elements of `M` - `x, y`, `(x, y) ∈ M × M` iff `x` is related to `y` by `c`. -/ -@[to_additive "Given a type `M` with an addition, `x, y ∈ M`, and an additive congruence relation -`c` on `M`, `(x, y) ∈ M × M` iff `x` is related to `y` by `c`."] -instance : Membership (M × M) (Con M) := - ⟨fun c x => c x.1 x.2⟩ - variable {c} -/-- The map sending a congruence relation to its underlying binary relation is injective. -/ -@[to_additive "The map sending an additive congruence relation to its underlying binary relation -is injective."] -theorem ext' {c d : Con M} (H : ⇑c = ⇑d) : c = d := DFunLike.coe_injective H - -/-- Extensionality rule for congruence relations. -/ -@[to_additive (attr := ext) "Extensionality rule for additive congruence relations."] -theorem ext {c d : Con M} (H : ∀ x y, c x y ↔ d x y) : c = d := - ext' <| by ext; apply H - -/-- The map sending a congruence relation to its underlying equivalence relation is injective. -/ -@[to_additive "The map sending an additive congruence relation to its underlying equivalence -relation is injective."] -theorem toSetoid_inj {c d : Con M} (H : c.toSetoid = d.toSetoid) : c = d := - ext <| ext_iff.1 H - -/-- Two congruence relations are equal iff their underlying binary relations are equal. -/ -@[to_additive "Two additive congruence relations are equal iff their underlying binary relations -are equal."] -theorem coe_inj {c d : Con M} : ⇑c = ⇑d ↔ c = d := DFunLike.coe_injective.eq_iff - -/-- The kernel of a multiplication-preserving function as a congruence relation. -/ -@[to_additive "The kernel of an addition-preserving function as an additive congruence relation."] -def mulKer (f : M → P) (h : ∀ x y, f (x * y) = f x * f y) : Con M where - toSetoid := Setoid.ker f - mul' h1 h2 := by - dsimp [Setoid.ker, onFun] at * - rw [h, h1, h2, h] - /-- Given types with multiplications `M, N`, the product of two congruence relations `c` on `M` and `d` on `N`: `(x₁, x₂), (y₁, y₂) ∈ M × N` are related by `c.prod d` iff `x₁` is related to `y₁` by `c` and `x₂` is related to `y₂` by `d`. -/ @@ -199,131 +61,6 @@ def pi {ι : Type*} {f : ι → Type*} [∀ i, Mul (f i)] (C : ∀ i, Con (f i)) { @piSetoid _ _ fun i => (C i).toSetoid with mul' := fun h1 h2 i => (C i).mul (h1 i) (h2 i) } -variable (c) - --- Quotients -/-- Defining the quotient by a congruence relation of a type with a multiplication. -/ -@[to_additive "Defining the quotient by an additive congruence relation of a type with -an addition."] -protected def Quotient := - Quotient c.toSetoid - --- Porting note: made implicit -variable {c} - -/-- The morphism into the quotient by a congruence relation -/ -@[to_additive (attr := coe) "The morphism into the quotient by an additive congruence relation"] -def toQuotient : M → c.Quotient := - Quotient.mk'' - -variable (c) - --- Porting note: was `priority 0`. why? -/-- Coercion from a type with a multiplication to its quotient by a congruence relation. - -See Note [use has_coe_t]. -/ -@[to_additive "Coercion from a type with an addition to its quotient by an additive congruence -relation"] -instance (priority := 10) : CoeTC M c.Quotient := - ⟨toQuotient⟩ - --- Lower the priority since it unifies with any quotient type. -/-- The quotient by a decidable congruence relation has decidable equality. -/ -@[to_additive "The quotient by a decidable additive congruence relation has decidable equality."] -instance (priority := 500) [∀ a b, Decidable (c a b)] : DecidableEq c.Quotient := - inferInstanceAs (DecidableEq (Quotient c.toSetoid)) - -@[to_additive (attr := simp)] -theorem quot_mk_eq_coe {M : Type*} [Mul M] (c : Con M) (x : M) : Quot.mk c x = (x : c.Quotient) := - rfl - --- Porting note (#11215): TODO: restore `elab_as_elim` -/-- The function on the quotient by a congruence relation `c` induced by a function that is - constant on `c`'s equivalence classes. -/ -@[to_additive "The function on the quotient by a congruence relation `c` -induced by a function that is constant on `c`'s equivalence classes."] -protected def liftOn {β} {c : Con M} (q : c.Quotient) (f : M → β) (h : ∀ a b, c a b → f a = f b) : - β := - Quotient.liftOn' q f h - --- Porting note (#11215): TODO: restore `elab_as_elim` -/-- The binary function on the quotient by a congruence relation `c` induced by a binary function - that is constant on `c`'s equivalence classes. -/ -@[to_additive "The binary function on the quotient by a congruence relation `c` -induced by a binary function that is constant on `c`'s equivalence classes."] -protected def liftOn₂ {β} {c : Con M} (q r : c.Quotient) (f : M → M → β) - (h : ∀ a₁ a₂ b₁ b₂, c a₁ b₁ → c a₂ b₂ → f a₁ a₂ = f b₁ b₂) : β := - Quotient.liftOn₂' q r f h - -/-- A version of `Quotient.hrecOn₂'` for quotients by `Con`. -/ -@[to_additive "A version of `Quotient.hrecOn₂'` for quotients by `AddCon`."] -protected def hrecOn₂ {cM : Con M} {cN : Con N} {φ : cM.Quotient → cN.Quotient → Sort*} - (a : cM.Quotient) (b : cN.Quotient) (f : ∀ (x : M) (y : N), φ x y) - (h : ∀ x y x' y', cM x x' → cN y y' → HEq (f x y) (f x' y')) : φ a b := - Quotient.hrecOn₂' a b f h - -@[to_additive (attr := simp)] -theorem hrec_on₂_coe {cM : Con M} {cN : Con N} {φ : cM.Quotient → cN.Quotient → Sort*} (a : M) - (b : N) (f : ∀ (x : M) (y : N), φ x y) - (h : ∀ x y x' y', cM x x' → cN y y' → HEq (f x y) (f x' y')) : - Con.hrecOn₂ (↑a) (↑b) f h = f a b := - rfl - -variable {c} - -/-- The inductive principle used to prove propositions about the elements of a quotient by a - congruence relation. -/ -@[to_additive (attr := elab_as_elim) "The inductive principle used to prove propositions about -the elements of a quotient by an additive congruence relation."] -protected theorem induction_on {C : c.Quotient → Prop} (q : c.Quotient) (H : ∀ x : M, C x) : C q := - Quotient.inductionOn' q H - -/-- A version of `Con.induction_on` for predicates which take two arguments. -/ -@[to_additive (attr := elab_as_elim) "A version of `AddCon.induction_on` for predicates which take -two arguments."] -protected theorem induction_on₂ {d : Con N} {C : c.Quotient → d.Quotient → Prop} (p : c.Quotient) - (q : d.Quotient) (H : ∀ (x : M) (y : N), C x y) : C p q := - Quotient.inductionOn₂' p q H - -variable (c) - -/-- Two elements are related by a congruence relation `c` iff they are represented by the same - element of the quotient by `c`. -/ -@[to_additive (attr := simp) "Two elements are related by an additive congruence relation `c` iff -they are represented by the same element of the quotient by `c`."] -protected theorem eq {a b : M} : (a : c.Quotient) = (b : c.Quotient) ↔ c a b := - Quotient.eq'' - -/-- The multiplication induced on the quotient by a congruence relation on a type with a - multiplication. -/ -@[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⟩ - -/-- 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 -relation `c` equals `c`."] -theorem mul_ker_mk_eq : (mulKer ((↑) : M → c.Quotient) fun _ _ => rfl) = c := - ext fun _ _ => Quotient.eq'' - -variable {c} - -/-- The coercion to the quotient of a congruence relation commutes with multiplication (by - definition). -/ -@[to_additive (attr := simp) "The coercion to the quotient of an additive congruence relation -commutes with addition (by definition)."] -theorem coe_mul (x y : M) : (↑(x * y) : c.Quotient) = ↑x * ↑y := - rfl - -/-- Definition of the function on the quotient by a congruence relation `c` induced by a function - that is constant on `c`'s equivalence classes. -/ -@[to_additive (attr := simp) "Definition of the function on the quotient by an additive congruence -relation `c` induced by a function that is constant on `c`'s equivalence classes."] -protected theorem liftOn_coe {β} (c : Con M) (f : M → β) (h : ∀ a b, c a b → f a = f b) (x : M) : - Con.liftOn (x : c.Quotient) f h = f x := - rfl - /-- Makes an isomorphism of quotients by two congruence relations, given that the relations are equal. -/ @[to_additive "Makes an additive isomorphism of quotients by two additive congruence relations, @@ -332,305 +69,12 @@ protected def congr {c d : Con M} (h : c = d) : c.Quotient ≃* d.Quotient := { Quotient.congr (Equiv.refl M) <| by apply Con.ext_iff.mp h with map_mul' := fun x y => by rcases x with ⟨⟩; rcases y with ⟨⟩; rfl } --- The complete lattice of congruence relations on a type -/-- For congruence relations `c, d` on a type `M` with a multiplication, `c ≤ d` iff `∀ x y ∈ M`, - `x` is related to `y` by `d` if `x` is related to `y` by `c`. -/ -@[to_additive "For additive congruence relations `c, d` on a type `M` with an addition, `c ≤ d` iff -`∀ x y ∈ M`, `x` is related to `y` by `d` if `x` is related to `y` by `c`."] -instance : LE (Con M) where - le c d := ∀ ⦃x y⦄, c x y → d x y - -/-- Definition of `≤` for congruence relations. -/ -@[to_additive "Definition of `≤` for additive congruence relations."] -theorem le_def {c d : Con M} : c ≤ d ↔ ∀ {x y}, c x y → d x y := - Iff.rfl - -/-- The infimum of a set of congruence relations on a given type with a multiplication. -/ -@[to_additive "The infimum of a set of additive congruence relations on a given type with -an addition."] -instance : InfSet (Con M) where - sInf S := - { r := fun x y => ∀ c : Con M, c ∈ S → c x y - iseqv := ⟨fun x c _ => c.refl x, fun h c hc => c.symm <| h c hc, - fun h1 h2 c hc => c.trans (h1 c hc) <| h2 c hc⟩ - mul' := fun h1 h2 c hc => c.mul (h1 c hc) <| h2 c hc } - -/-- The infimum of a set of congruence relations is the same as the infimum of the set's image - under the map to the underlying equivalence relation. -/ -@[to_additive "The infimum of a set of additive congruence relations is the same as the infimum of -the set's image under the map to the underlying equivalence relation."] -theorem sInf_toSetoid (S : Set (Con M)) : (sInf S).toSetoid = sInf (toSetoid '' S) := - Setoid.ext' fun x y => - ⟨fun h r ⟨c, hS, hr⟩ => by rw [← hr]; exact h c hS, fun h c hS => h c.toSetoid ⟨c, hS, rfl⟩⟩ - -/-- The infimum of a set of congruence relations is the same as the infimum of the set's image - under the map to the underlying binary relation. -/ -@[to_additive (attr := simp, norm_cast) - "The infimum of a set of additive congruence relations is the same as the infimum - of the set's image under the map to the underlying binary relation."] -theorem coe_sInf (S : Set (Con M)) : - ⇑(sInf S) = sInf ((⇑) '' S) := by - ext - simp only [sInf_image, iInf_apply, iInf_Prop_eq] - rfl - -@[to_additive (attr := simp, norm_cast)] -theorem coe_iInf {ι : Sort*} (f : ι → Con M) : ⇑(iInf f) = ⨅ i, ⇑(f i) := by - rw [iInf, coe_sInf, ← Set.range_comp, sInf_range, Function.comp_def] - -@[to_additive] -instance : PartialOrder (Con M) where - le_refl _ _ _ := id - le_trans _ _ _ h1 h2 _ _ h := h2 <| h1 h - le_antisymm _ _ hc hd := ext fun _ _ => ⟨fun h => hc h, fun h => hd h⟩ - -/-- The complete lattice of congruence relations on a given type with a multiplication. -/ -@[to_additive "The complete lattice of additive congruence relations on a given type with -an addition."] -instance : CompleteLattice (Con M) where - __ := completeLatticeOfInf (Con M) fun s => - ⟨fun r hr x y h => (h : ∀ r ∈ s, (r : Con M) x y) r hr, fun r hr x y h r' hr' => - hr hr' - h⟩ - inf c d := ⟨c.toSetoid ⊓ d.toSetoid, fun h1 h2 => ⟨c.mul h1.1 h2.1, d.mul h1.2 h2.2⟩⟩ - inf_le_left _ _ := fun _ _ h => h.1 - inf_le_right _ _ := fun _ _ h => h.2 - le_inf _ _ _ hb hc := fun _ _ h => ⟨hb h, hc h⟩ - top := { Setoid.completeLattice.top with mul' := by tauto } - le_top _ := fun _ _ _ => trivial - bot := { Setoid.completeLattice.bot with mul' := fun h1 h2 => h1 ▸ h2 ▸ rfl } - bot_le c := fun x y h => h ▸ c.refl x - -/-- The infimum of two congruence relations equals the infimum of the underlying binary - operations. -/ -@[to_additive (attr := simp, norm_cast) - "The infimum of two additive congruence relations equals the infimum of the underlying binary - operations."] -theorem coe_inf {c d : Con M} : ⇑(c ⊓ d) = ⇑c ⊓ ⇑d := - rfl - -/-- Definition of the infimum of two congruence relations. -/ -@[to_additive "Definition of the infimum of two additive congruence relations."] -theorem inf_iff_and {c d : Con M} {x y} : (c ⊓ d) x y ↔ c x y ∧ d x y := - Iff.rfl - -/-- The inductively defined smallest congruence relation containing a binary relation `r` equals - the infimum of the set of congruence relations containing `r`. -/ -@[to_additive addConGen_eq "The inductively defined smallest additive congruence relation -containing a binary relation `r` equals the infimum of the set of additive congruence relations -containing `r`."] -theorem conGen_eq (r : M → M → Prop) : conGen r = sInf { s : Con M | ∀ x y, r x y → s x y } := - le_antisymm - (le_sInf (fun s hs x y (hxy : (conGen r) x y) => - show s x y by - apply ConGen.Rel.recOn (motive := fun x y _ => s x y) hxy - · exact fun x y h => hs x y h - · exact s.refl' - · exact fun _ => s.symm' - · exact fun _ _ => s.trans' - · exact fun _ _ => s.mul)) - (sInf_le ConGen.Rel.of) - -/-- The smallest congruence relation containing a binary relation `r` is contained in any - congruence relation containing `r`. -/ -@[to_additive addConGen_le "The smallest additive congruence relation containing a binary -relation `r` is contained in any additive congruence relation containing `r`."] -theorem conGen_le {r : M → M → Prop} {c : Con M} (h : ∀ x y, r x y → c x y) : - conGen r ≤ c := by rw [conGen_eq]; exact sInf_le h - -/-- Given binary relations `r, s` with `r` contained in `s`, the smallest congruence relation - containing `s` contains the smallest congruence relation containing `r`. -/ -@[to_additive addConGen_mono "Given binary relations `r, s` with `r` contained in `s`, the -smallest additive congruence relation containing `s` contains the smallest additive congruence -relation containing `r`."] -theorem conGen_mono {r s : M → M → Prop} (h : ∀ x y, r x y → s x y) : conGen r ≤ conGen s := - conGen_le fun x y hr => ConGen.Rel.of _ _ <| h x y hr - -/-- Congruence relations equal the smallest congruence relation in which they are contained. -/ -@[to_additive (attr := simp) addConGen_of_addCon "Additive congruence relations equal the smallest -additive congruence relation in which they are contained."] -theorem conGen_of_con (c : Con M) : conGen c = c := - le_antisymm (by rw [conGen_eq]; exact sInf_le fun _ _ => id) ConGen.Rel.of - --- Porting note: removing simp, simp can prove it -/-- The map sending a binary relation to the smallest congruence relation in which it is - contained is idempotent. -/ -@[to_additive addConGen_idem "The map sending a binary relation to the smallest additive -congruence relation in which it is contained is idempotent."] -theorem conGen_idem (r : M → M → Prop) : conGen (conGen r) = conGen r := - conGen_of_con _ - -/-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing - the binary relation '`x` is related to `y` by `c` or `d`'. -/ -@[to_additive sup_eq_addConGen "The supremum of additive congruence relations `c, d` equals the -smallest additive congruence relation containing the binary relation '`x` is related to `y` -by `c` or `d`'."] -theorem sup_eq_conGen (c d : Con M) : c ⊔ d = conGen fun x y => c x y ∨ d x y := by - rw [conGen_eq] - apply congr_arg sInf - simp only [le_def, or_imp, ← forall_and] - -/-- The supremum of two congruence relations equals the smallest congruence relation containing - the supremum of the underlying binary operations. -/ -@[to_additive "The supremum of two additive congruence relations equals the smallest additive -congruence relation containing the supremum of the underlying binary operations."] -theorem sup_def {c d : Con M} : c ⊔ d = conGen (⇑c ⊔ ⇑d) := by rw [sup_eq_conGen]; rfl - -/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation - containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by - `c`'. -/ -@[to_additive sSup_eq_addConGen "The supremum of a set of additive congruence relations `S` equals -the smallest additive congruence relation containing the binary relation 'there exists `c ∈ S` -such that `x` is related to `y` by `c`'."] -theorem sSup_eq_conGen (S : Set (Con M)) : - sSup S = conGen fun x y => ∃ c : Con M, c ∈ S ∧ c x y := by - rw [conGen_eq] - apply congr_arg sInf - ext - exact ⟨fun h _ _ ⟨r, hr⟩ => h hr.1 hr.2, fun h r hS _ _ hr => h _ _ ⟨r, hS, hr⟩⟩ - -/-- The supremum of a set of congruence relations is the same as the smallest congruence relation - containing the supremum of the set's image under the map to the underlying binary relation. -/ -@[to_additive "The supremum of a set of additive congruence relations is the same as the smallest -additive congruence relation containing the supremum of the set's image under the map to the -underlying binary relation."] -theorem sSup_def {S : Set (Con M)} : - sSup S = conGen (sSup ((⇑) '' S)) := by - rw [sSup_eq_conGen, sSup_image] - congr with (x y) - simp only [sSup_image, iSup_apply, iSup_Prop_eq, exists_prop, rel_eq_coe] - -variable (M) - -/-- There is a Galois insertion of congruence relations on a type with a multiplication `M` into - binary relations on `M`. -/ -@[to_additive "There is a Galois insertion of additive congruence relations on a type with -an addition `M` into binary relations on `M`."] -protected def gi : @GaloisInsertion (M → M → Prop) (Con M) _ _ conGen DFunLike.coe where - choice r _ := conGen r - gc _ c := ⟨fun H _ _ h => H <| ConGen.Rel.of _ _ h, @fun H => conGen_of_con c ▸ conGen_mono H⟩ - le_l_u x := (conGen_of_con x).symm ▸ le_refl x - choice_eq _ _ := rfl - -variable {M} (c) - -/-- Given a function `f`, the smallest congruence relation containing the binary relation on `f`'s - image defined by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` - by a congruence relation `c`.' -/ -@[to_additive "Given a function `f`, the smallest additive congruence relation containing the -binary relation on `f`'s image defined by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the -elements of `f⁻¹(y)` by an additive congruence relation `c`.'"] -def mapGen (f : M → N) : Con N := - conGen fun x y => ∃ a b, f a = x ∧ f b = y ∧ c a b - -/-- Given a surjective multiplicative-preserving function `f` whose kernel is contained in a - congruence relation `c`, the congruence relation on `f`'s codomain defined by '`x ≈ y` iff the - elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` by `c`.' -/ -@[to_additive "Given a surjective addition-preserving function `f` whose kernel is contained in -an additive congruence relation `c`, the additive congruence relation on `f`'s codomain defined -by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` by `c`.'"] -def mapOfSurjective (f : M → N) (H : ∀ x y, f (x * y) = f x * f y) (h : mulKer f H ≤ c) - (hf : Surjective f) : Con N := - { c.toSetoid.mapOfSurjective f h hf with - mul' := fun h₁ h₂ => by - rcases h₁ with ⟨a, b, rfl, rfl, h1⟩ - rcases h₂ with ⟨p, q, rfl, rfl, h2⟩ - exact ⟨a * p, b * q, by rw [H], by rw [H], c.mul h1 h2⟩ } - -/-- A specialization of 'the smallest congruence relation containing a congruence relation `c` - equals `c`'. -/ -@[to_additive "A specialization of 'the smallest additive congruence relation containing -an additive congruence relation `c` equals `c`'."] -theorem mapOfSurjective_eq_mapGen {c : Con M} {f : M → N} (H : ∀ x y, f (x * y) = f x * f y) - (h : mulKer f H ≤ c) (hf : Surjective f) : c.mapGen f = c.mapOfSurjective f H h hf := by - rw [← conGen_of_con (c.mapOfSurjective f H h hf)]; rfl - -/-- Given types with multiplications `M, N` and a congruence relation `c` on `N`, a - multiplication-preserving map `f : M → N` induces a congruence relation on `f`'s domain - defined by '`x ≈ y` iff `f(x)` is related to `f(y)` by `c`.' -/ -@[to_additive "Given types with additions `M, N` and an additive congruence relation `c` on `N`, -an addition-preserving map `f : M → N` induces an additive congruence relation on `f`'s domain -defined by '`x ≈ y` iff `f(x)` is related to `f(y)` by `c`.' "] -def comap (f : M → N) (H : ∀ x y, f (x * y) = f x * f y) (c : Con N) : Con M := - { c.toSetoid.comap f with - mul' := @fun w x y z h1 h2 => show c (f (w * y)) (f (x * z)) by rw [H, H]; exact c.mul h1 h2 } - -@[to_additive (attr := simp)] -theorem comap_rel {f : M → N} (H : ∀ x y, f (x * y) = f x * f y) {c : Con N} {x y : M} : - comap f H c x y ↔ c (f x) (f y) := - Iff.rfl - -section - -open Quotient - -/-- Given a congruence relation `c` on a type `M` with a multiplication, the order-preserving - bijection between the set of congruence relations containing `c` and the congruence relations - on the quotient of `M` by `c`. -/ -@[to_additive "Given an additive congruence relation `c` on a type `M` with an addition, -the order-preserving bijection between the set of additive congruence relations containing `c` and -the additive congruence relations on the quotient of `M` by `c`."] -def correspondence : { d // c ≤ d } ≃o Con c.Quotient where - toFun d := - d.1.mapOfSurjective (↑) (fun x y => rfl) (by rw [mul_ker_mk_eq]; exact d.2) <| - @Quotient.exists_rep _ c.toSetoid - invFun d := - ⟨comap ((↑) : M → c.Quotient) (fun x y => rfl) d, fun x y h => - show d x y by rw [c.eq.2 h]; exact d.refl _⟩ - left_inv d := - -- Porting note: by exact needed for unknown reason - by exact - Subtype.ext_iff_val.2 <| - ext fun x y => - ⟨fun h => - let ⟨a, b, hx, hy, H⟩ := h - d.1.trans (d.1.symm <| d.2 <| c.eq.1 hx) <| d.1.trans H <| d.2 <| c.eq.1 hy, - fun h => ⟨_, _, rfl, rfl, h⟩⟩ - right_inv d := - -- Porting note: by exact needed for unknown reason - by exact - ext fun x y => - ⟨fun h => - let ⟨_, _, hx, hy, H⟩ := h - hx ▸ hy ▸ H, - Con.induction_on₂ x y fun w z h => ⟨w, z, rfl, rfl, h⟩⟩ - map_rel_iff' := @fun s t => by - constructor - · intros h x y hs - rcases h ⟨x, y, rfl, rfl, hs⟩ with ⟨a, b, hx, hy, ht⟩ - exact t.1.trans (t.1.symm <| t.2 <| Quotient.eq_rel.1 hx) - (t.1.trans ht (t.2 <| Quotient.eq_rel.1 hy)) - · intros h _ _ hs - rcases hs with ⟨a, b, hx, hy, Hs⟩ - exact ⟨a, b, hx, hy, h Hs⟩ - -end - end section MulOneClass variable [MulOneClass M] [MulOneClass N] [MulOneClass P] (c : Con M) -/-- The quotient of a monoid by a congruence relation is a monoid. -/ -@[to_additive "The quotient of an `AddMonoid` by an additive congruence relation is -an `AddMonoid`."] -instance mulOneClass : MulOneClass c.Quotient where - one := ((1 : M) : c.Quotient) - mul_one x := Quotient.inductionOn' x fun _ => congr_arg ((↑) : M → c.Quotient) <| mul_one _ - one_mul x := Quotient.inductionOn' x fun _ => congr_arg ((↑) : M → c.Quotient) <| one_mul _ - -variable {c} - -/-- The 1 of the quotient of a monoid by a congruence relation is the equivalence class of the - monoid's 1. -/ -@[to_additive (attr := simp) "The 0 of the quotient of an `AddMonoid` by an additive congruence -relation is the equivalence class of the `AddMonoid`'s 0."] -theorem coe_one : ((1 : M) : c.Quotient) = 1 := - rfl - -variable (c) - -- Porting note: made M implicit /-- The submonoid of `M × M` defined by a congruence relation on a monoid `M`. -/ @[to_additive (attr := coe) "The `AddSubmonoid` of `M × M` defined by an additive congruence @@ -671,131 +115,14 @@ theorem to_submonoid_inj (c d : Con M) (H : (c : Submonoid (M × M)) = d) : c = theorem le_iff {c d : Con M} : c ≤ d ↔ (c : Submonoid (M × M)) ≤ d := ⟨fun h _ H => h H, fun h x y hc => h <| show (x, y) ∈ c from hc⟩ -/-- The kernel of a monoid homomorphism as a congruence relation. -/ -@[to_additive "The kernel of an `AddMonoid` homomorphism as an additive congruence relation."] -def ker (f : M →* P) : Con M := - mulKer f (map_mul f) - -/-- The definition of the congruence relation defined by a monoid homomorphism's kernel. -/ -@[to_additive (attr := simp) "The definition of the additive congruence relation defined by an -`AddMonoid` homomorphism's kernel."] -theorem ker_rel (f : M →* P) {x y} : ker f x y ↔ f x = f y := - Iff.rfl - -/-- There exists an element of the quotient of a monoid by a congruence relation (namely 1). -/ -@[to_additive "There exists an element of the quotient of an `AddMonoid` by a congruence relation -(namely 0)."] -instance Quotient.inhabited : Inhabited c.Quotient := - ⟨((1 : M) : c.Quotient)⟩ - -variable (c) - -/-- The natural homomorphism from a monoid to its quotient by a congruence relation. -/ -@[to_additive "The natural homomorphism from an `AddMonoid` to its quotient by an additive -congruence relation."] -def mk' : M →* c.Quotient := - { toFun := (↑) - map_one' := rfl - map_mul' := fun _ _ => rfl } - variable (x y : M) -/-- The kernel of the natural homomorphism from a monoid to its quotient by a congruence - relation `c` equals `c`. -/ -@[to_additive (attr := simp) "The kernel of the natural homomorphism from an `AddMonoid` to its -quotient by an additive congruence relation `c` equals `c`."] -theorem mk'_ker : ker c.mk' = c := - ext fun _ _ => c.eq - -variable {c} - -/-- The natural homomorphism from a monoid to its quotient by a congruence relation is - surjective. -/ -@[to_additive "The natural homomorphism from an `AddMonoid` to its quotient by a congruence -relation is surjective."] -theorem mk'_surjective : Surjective c.mk' := - Quotient.surjective_Quotient_mk'' - -@[to_additive (attr := simp)] -theorem coe_mk' : (c.mk' : M → c.Quotient) = ((↑) : M → c.Quotient) := - rfl - @[to_additive (attr := simp)] -- Porting note: removed dot notation theorem mrange_mk' : MonoidHom.mrange c.mk' = ⊤ := MonoidHom.mrange_top_iff_surjective.2 mk'_surjective --- Porting note: used to abuse defeq between sets and predicates -@[to_additive] -theorem ker_apply {f : M →* P} {x y} : ker f x y ↔ f x = f y := Iff.rfl - -/-- Given a monoid homomorphism `f : N → M` and a congruence relation `c` on `M`, the congruence - relation induced on `N` by `f` equals the kernel of `c`'s quotient homomorphism composed with - `f`. -/ -@[to_additive "Given an `AddMonoid` homomorphism `f : N → M` and an additive congruence relation -`c` on `M`, the additive congruence relation induced on `N` by `f` equals the kernel of `c`'s -quotient homomorphism composed with `f`."] -theorem comap_eq {f : N →* M} : comap f f.map_mul c = ker (c.mk'.comp f) := - ext fun x y => show c _ _ ↔ c.mk' _ = c.mk' _ by rw [← c.eq]; rfl - -variable (c) (f : M →* P) - -/-- The homomorphism on the quotient of a monoid by a congruence relation `c` induced by a - homomorphism constant on `c`'s equivalence classes. -/ -@[to_additive "The homomorphism on the quotient of an `AddMonoid` by an additive congruence -relation `c` induced by a homomorphism constant on `c`'s equivalence classes."] -def lift (H : c ≤ ker f) : c.Quotient →* P where - toFun x := (Con.liftOn x f) fun _ _ h => H h - map_one' := by rw [← f.map_one]; rfl - map_mul' x y := Con.induction_on₂ x y fun m n => by - dsimp only [← coe_mul, Con.liftOn_coe] - rw [map_mul] - -variable {c f} - -/-- The diagram describing the universal property for quotients of monoids commutes. -/ -@[to_additive "The diagram describing the universal property for quotients of `AddMonoid`s -commutes."] -theorem lift_mk' (H : c ≤ ker f) (x) : c.lift f H (c.mk' x) = f x := - rfl - -/-- The diagram describing the universal property for quotients of monoids commutes. -/ -@[to_additive (attr := simp) "The diagram describing the universal property for quotients of -`AddMonoid`s commutes."] -theorem lift_coe (H : c ≤ ker f) (x : M) : c.lift f H x = f x := - rfl - -/-- The diagram describing the universal property for quotients of monoids commutes. -/ -@[to_additive (attr := simp) "The diagram describing the universal property for quotients of -`AddMonoid`s commutes."] -theorem lift_comp_mk' (H : c ≤ ker f) : (c.lift f H).comp c.mk' = f := by ext; rfl - -/-- Given a homomorphism `f` from the quotient of a monoid by a congruence relation, `f` equals the - homomorphism on the quotient induced by `f` composed with the natural map from the monoid to - the quotient. -/ -@[to_additive (attr := simp) "Given a homomorphism `f` from the quotient of an `AddMonoid` by an -additive congruence relation, `f` equals the homomorphism on the quotient induced by `f` composed -with the natural map from the `AddMonoid` to the quotient."] -theorem lift_apply_mk' (f : c.Quotient →* P) : - (c.lift (f.comp c.mk') fun x y h => show f ↑x = f ↑y by rw [c.eq.2 h]) = f := by - ext x; rcases x with ⟨⟩; rfl - -/-- Homomorphisms on the quotient of a monoid by a congruence relation are equal if they - are equal on elements that are coercions from the monoid. -/ -@[to_additive "Homomorphisms on the quotient of an `AddMonoid` by an additive congruence relation -are equal if they are equal on elements that are coercions from the `AddMonoid`."] -theorem lift_funext (f g : c.Quotient →* P) (h : ∀ a : M, f a = g a) : f = g := by - rw [← lift_apply_mk' f, ← lift_apply_mk' g] - congr 1 - exact DFunLike.ext_iff.2 h - -/-- The uniqueness part of the universal property for quotients of monoids. -/ -@[to_additive "The uniqueness part of the universal property for quotients of `AddMonoid`s."] -theorem lift_unique (H : c ≤ ker f) (g : c.Quotient →* P) (Hg : g.comp c.mk' = f) : - g = c.lift f H := - (lift_funext g (c.lift f H)) fun x => by - subst f - rfl +variable {f : M →* P} /-- Given a congruence relation `c` on a monoid and a homomorphism `f` constant on `c`'s equivalence classes, `f` has the same image as the homomorphism that `f` induces on the @@ -806,42 +133,6 @@ on the quotient."] theorem lift_range (H : c ≤ ker f) : MonoidHom.mrange (c.lift f H) = MonoidHom.mrange f := Submonoid.ext fun x => ⟨by rintro ⟨⟨y⟩, hy⟩; exact ⟨y, hy⟩, fun ⟨y, hy⟩ => ⟨↑y, hy⟩⟩ -/-- Surjective monoid homomorphisms constant on a congruence relation `c`'s equivalence classes - induce a surjective homomorphism on `c`'s quotient. -/ -@[to_additive "Surjective `AddMonoid` homomorphisms constant on an additive congruence -relation `c`'s equivalence classes induce a surjective homomorphism on `c`'s quotient."] -theorem lift_surjective_of_surjective (h : c ≤ ker f) (hf : Surjective f) : - Surjective (c.lift f h) := fun y => - (Exists.elim (hf y)) fun w hw => ⟨w, (lift_mk' h w).symm ▸ hw⟩ - -variable (c f) - -/-- Given a monoid homomorphism `f` from `M` to `P`, the kernel of `f` is the unique congruence - relation on `M` whose induced map from the quotient of `M` to `P` is injective. -/ -@[to_additive "Given an `AddMonoid` homomorphism `f` from `M` to `P`, the kernel of `f` -is the unique additive congruence relation on `M` whose induced map from the quotient of `M` -to `P` is injective."] -theorem ker_eq_lift_of_injective (H : c ≤ ker f) (h : Injective (c.lift f H)) : ker f = c := - toSetoid_inj <| Setoid.ker_eq_lift_of_injective f H h - -variable {c} - -/-- The homomorphism induced on the quotient of a monoid by the kernel of a monoid homomorphism. -/ -@[to_additive "The homomorphism induced on the quotient of an `AddMonoid` by the kernel -of an `AddMonoid` homomorphism."] -def kerLift : (ker f).Quotient →* P := - ((ker f).lift f) fun _ _ => id - -variable {f} - -/-- The diagram described by the universal property for quotients of monoids, when the congruence - relation is the kernel of the homomorphism, commutes. -/ -@[to_additive (attr := simp) "The diagram described by the universal property for quotients -of `AddMonoid`s, when the additive congruence relation is the kernel of the homomorphism, -commutes."] -theorem kerLift_mk (x : M) : kerLift f x = f x := - rfl - /-- Given a monoid homomorphism `f`, the induced homomorphism on the quotient by `f`'s kernel has the same image as `f`. -/ @[to_additive (attr := simp) "Given an `AddMonoid` homomorphism `f`, the induced homomorphism @@ -849,30 +140,6 @@ on the quotient by `f`'s kernel has the same image as `f`."] theorem kerLift_range_eq : MonoidHom.mrange (kerLift f) = MonoidHom.mrange f := lift_range fun _ _ => id -/-- A monoid homomorphism `f` induces an injective homomorphism on the quotient by `f`'s kernel. -/ -@[to_additive "An `AddMonoid` homomorphism `f` induces an injective homomorphism on the quotient -by `f`'s kernel."] -theorem kerLift_injective (f : M →* P) : Injective (kerLift f) := fun x y => - Quotient.inductionOn₂' x y fun _ _ => (ker f).eq.2 - -/-- Given congruence relations `c, d` on a monoid such that `d` contains `c`, `d`'s quotient - map induces a homomorphism from the quotient by `c` to the quotient by `d`. -/ -@[to_additive "Given additive congruence relations `c, d` on an `AddMonoid` such that `d` -contains `c`, `d`'s quotient map induces a homomorphism from the quotient by `c` to the quotient -by `d`."] -def map (c d : Con M) (h : c ≤ d) : c.Quotient →* d.Quotient := - (c.lift d.mk') fun x y hc => show (ker d.mk') x y from (mk'_ker d).symm ▸ h hc - -/-- Given congruence relations `c, d` on a monoid such that `d` contains `c`, the definition of - the homomorphism from the quotient by `c` to the quotient by `d` induced by `d`'s quotient - map. -/ -@[to_additive "Given additive congruence relations `c, d` on an `AddMonoid` such that `d` -contains `c`, the definition of the homomorphism from the quotient by `c` to the quotient by `d` -induced by `d`'s quotient map."] -theorem map_apply {c d : Con M} (h : c ≤ d) (x) : - c.map d h x = c.lift d.mk' (fun _ _ hc => d.eq.2 <| h hc) x := - rfl - variable (c) /-- The **first isomorphism theorem for monoids**. -/ @@ -934,211 +201,13 @@ end MulOneClass section Monoids -/-- Multiplicative congruence relations preserve natural powers. -/ -@[to_additive "Additive congruence relations preserve natural scaling."] -protected theorem pow {M : Type*} [Monoid M] (c : Con M) : - ∀ (n : ℕ) {w x}, c w x → c (w ^ n) (x ^ n) - | 0, w, x, _ => by simpa using c.refl _ - | Nat.succ n, w, x, h => by simpa [pow_succ] using c.mul (Con.pow c n h) h - -@[to_additive] -instance one [MulOneClass M] (c : Con M) : One c.Quotient where - -- Using Quotient.mk'' here instead of c.toQuotient - -- since c.toQuotient is not reducible. - -- This would lead to non-defeq diamonds since this instance ends up in - -- quotients modulo ideals. - one := Quotient.mk'' (1 : M) - -- one := ((1 : M) : c.Quotient) - @[to_additive] theorem smul {α M : Type*} [MulOneClass M] [SMul α M] [IsScalarTower α M M] (c : Con M) (a : α) {w x : M} (h : c w x) : c (a • w) (a • x) := by simpa only [smul_one_mul] using c.mul (c.refl' (a • (1 : M) : M)) h -instance _root_.AddCon.Quotient.nsmul {M : Type*} [AddMonoid M] (c : AddCon M) : - SMul ℕ c.Quotient where - smul n := (Quotient.map' (n • ·)) fun _ _ => c.nsmul n - -@[to_additive existing AddCon.Quotient.nsmul] -instance {M : Type*} [Monoid M] (c : Con M) : Pow c.Quotient ℕ where - pow x n := Quotient.map' (fun x => x ^ n) (fun _ _ => c.pow n) x - -/-- The quotient of a semigroup by a congruence relation is a semigroup. -/ -@[to_additive "The quotient of an `AddSemigroup` by an additive congruence relation is -an `AddSemigroup`."] -instance semigroup {M : Type*} [Semigroup M] (c : Con M) : Semigroup c.Quotient := - { (Function.Surjective.semigroup _ Quotient.surjective_Quotient_mk'' fun _ _ => rfl : - Semigroup c.Quotient) with - /- The `toMul` field is given explicitly for performance reasons. - This avoids any need to unfold `Function.Surjective.semigroup` when the type checker is checking - that instance diagrams commute -/ - toMul := Con.hasMul _ } - -/-- The quotient of a commutative semigroup by a congruence relation is a semigroup. -/ -@[to_additive "The quotient of an `AddCommSemigroup` by an additive congruence relation is -an `AddCommSemigroup`."] -instance commSemigroup {M : Type*} [CommSemigroup M] (c : Con M) : CommSemigroup c.Quotient := - { (Function.Surjective.commSemigroup _ Quotient.surjective_Quotient_mk'' fun _ _ => rfl : - CommSemigroup c.Quotient) with - /- The `toSemigroup` field is given explicitly for performance reasons. - This avoids any need to unfold `Function.Surjective.commSemigroup` when the type checker is - checking that instance diagrams commute -/ - toSemigroup := Con.semigroup _ } - -/-- The quotient of a monoid by a congruence relation is a monoid. -/ -@[to_additive "The quotient of an `AddMonoid` by an additive congruence relation is -an `AddMonoid`."] -instance monoid {M : Type*} [Monoid M] (c : Con M) : Monoid c.Quotient := - { (Function.Surjective.monoid _ Quotient.surjective_Quotient_mk'' rfl - (fun _ _ => rfl) fun _ _ => rfl : Monoid c.Quotient) with - /- The `toSemigroup` and `toOne` fields are given explicitly for performance reasons. - This avoids any need to unfold `Function.Surjective.monoid` when the type checker is - checking that instance diagrams commute -/ - toSemigroup := Con.semigroup _ - toOne := Con.one _ } - -/-- The quotient of a `CommMonoid` by a congruence relation is a `CommMonoid`. -/ -@[to_additive "The quotient of an `AddCommMonoid` by an additive congruence -relation is an `AddCommMonoid`."] -instance commMonoid {M : Type*} [CommMonoid M] (c : Con M) : CommMonoid c.Quotient := - { (Function.Surjective.commMonoid _ Quotient.surjective_Quotient_mk'' rfl - (fun _ _ => rfl) fun _ _ => rfl : CommMonoid c.Quotient) with - /- The `toMonoid` field is given explicitly for performance reasons. - This avoids any need to unfold `Function.Surjective.commMonoid` when the type checker is - checking that instance diagrams commute -/ - toMonoid := Con.monoid _ } - -/-- Sometimes, a group is defined as a quotient of a monoid by a congruence relation. -Usually, the inverse operation is defined as `Setoid.map f _` for some `f`. -This lemma allows to avoid code duplication in the definition of the inverse operation: -instead of proving both `∀ x y, c x y → c (f x) (f y)` (to define the operation) -and `∀ x, c (f x * x) 1` (to prove the group laws), one can only prove the latter. -/ -@[to_additive "Sometimes, an additive group is defined as a quotient of a monoid - by an additive congruence relation. - Usually, the inverse operation is defined as `Setoid.map f _` for some `f`. - This lemma allows to avoid code duplication in the definition of the inverse operation: - instead of proving both `∀ x y, c x y → c (f x) (f y)` (to define the operation) - and `∀ x, c (f x + x) 0` (to prove the group laws), one can only prove the latter."] -theorem map_of_mul_left_rel_one [Monoid M] (c : Con M) - (f : M → M) (hf : ∀ x, c (f x * x) 1) {x y} (h : c x y) : c (f x) (f y) := by - simp only [← Con.eq, coe_one, coe_mul] at * - have hf' : ∀ x : M, (x : c.Quotient) * f x = 1 := fun x ↦ - calc - (x : c.Quotient) * f x = f (f x) * f x * (x * f x) := by simp [hf] - _ = f (f x) * (f x * x) * f x := by ac_rfl - _ = 1 := by simp [hf] - have : (⟨_, _, hf' x, hf x⟩ : c.Quotientˣ) = ⟨_, _, hf' y, hf y⟩ := Units.ext h - exact congr_arg Units.inv this - end Monoids -section Groups - -variable [Group M] [Group N] [Group P] (c : Con M) - -/-- Multiplicative congruence relations preserve inversion. -/ -@[to_additive "Additive congruence relations preserve negation."] -protected theorem inv {x y} (h : c x y) : c x⁻¹ y⁻¹ := - c.map_of_mul_left_rel_one Inv.inv (fun x => by simp only [inv_mul_cancel, c.refl 1]) h - -/-- Multiplicative congruence relations preserve division. -/ -@[to_additive "Additive congruence relations preserve subtraction."] -protected theorem div : ∀ {w x y z}, c w x → c y z → c (w / y) (x / z) := @fun w x y z h1 h2 => by - simpa only [div_eq_mul_inv] using c.mul h1 (c.inv h2) - -/-- Multiplicative congruence relations preserve integer powers. -/ -@[to_additive "Additive congruence relations preserve integer scaling."] -protected theorem zpow : ∀ (n : ℤ) {w x}, c w x → c (w ^ n) (x ^ n) - | Int.ofNat n, w, x, h => by simpa only [zpow_natCast, Int.ofNat_eq_coe] using c.pow n h - | Int.negSucc n, w, x, h => by simpa only [zpow_negSucc] using c.inv (c.pow _ h) - -/-- The inversion induced on the quotient by a congruence relation on a type with an - inversion. -/ -@[to_additive "The negation induced on the quotient by an additive congruence relation on a type -with a negation."] -instance hasInv : Inv c.Quotient := - ⟨(Quotient.map' Inv.inv) fun _ _ => c.inv⟩ - -/-- The division induced on the quotient by a congruence relation on a type with a - division. -/ -@[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₂⟩ - -/-- The integer scaling induced on the quotient by a congruence relation on a type with a - subtraction. -/ -instance _root_.AddCon.Quotient.zsmul {M : Type*} [AddGroup M] (c : AddCon M) : - SMul ℤ c.Quotient := - ⟨fun z => (Quotient.map' (z • ·)) fun _ _ => c.zsmul z⟩ - -/-- The integer power induced on the quotient by a congruence relation on a type with a - division. -/ -@[to_additive existing AddCon.Quotient.zsmul] -instance zpowinst : Pow c.Quotient ℤ := - ⟨fun x z => Quotient.map' (fun x => x ^ z) (fun _ _ h => c.zpow z h) x⟩ - -/-- The quotient of a group by a congruence relation is a group. -/ -@[to_additive "The quotient of an `AddGroup` by an additive congruence relation is -an `AddGroup`."] -instance group : Group c.Quotient := - { (Function.Surjective.group Quotient.mk'' - Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) (fun _ => rfl) - (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl : Group c.Quotient) with - toMonoid := Con.monoid _ - toInv := Con.hasInv _ - toDiv := Con.hasDiv _ } - -end Groups - -section Units - -variable {α : Type*} [Monoid M] {c : Con M} - -/-- In order to define a function `(Con.Quotient c)ˣ → α` on the units of `Con.Quotient c`, -where `c : Con M` is a multiplicative congruence on a monoid, it suffices to define a function `f` -that takes elements `x y : M` with proofs of `c (x * y) 1` and `c (y * x) 1`, and returns an element -of `α` provided that `f x y _ _ = f x' y' _ _` whenever `c x x'` and `c y y'`. -/ -@[to_additive] -def liftOnUnits (u : Units c.Quotient) (f : ∀ x y : M, c (x * y) 1 → c (y * x) 1 → α) - (Hf : ∀ x y hxy hyx x' y' hxy' hyx', - c x x' → c y y' → f x y hxy hyx = f x' y' hxy' hyx') : α := by - refine - Con.hrecOn₂ (cN := c) (φ := fun x y => x * y = 1 → y * x = 1 → α) (u : c.Quotient) - (↑u⁻¹ : c.Quotient) - (fun (x y : M) (hxy : (x * y : c.Quotient) = 1) (hyx : (y * x : c.Quotient) = 1) => - f x y (c.eq.1 hxy) (c.eq.1 hyx)) - (fun x y x' y' hx hy => ?_) u.3 u.4 - refine Function.hfunext ?_ ?_ - · rw [c.eq.2 hx, c.eq.2 hy] - · rintro Hxy Hxy' - - refine Function.hfunext ?_ ?_ - · rw [c.eq.2 hx, c.eq.2 hy] - · rintro Hyx Hyx' - - exact heq_of_eq (Hf _ _ _ _ _ _ _ _ hx hy) - -/-- In order to define a function `(Con.Quotient c)ˣ → α` on the units of `Con.Quotient c`, -where `c : Con M` is a multiplicative congruence on a monoid, it suffices to define a function `f` -that takes elements `x y : M` with proofs of `c (x * y) 1` and `c (y * x) 1`, and returns an element -of `α` provided that `f x y _ _ = f x' y' _ _` whenever `c x x'` and `c y y'`. -/ -add_decl_doc AddCon.liftOnAddUnits - -@[to_additive (attr := simp)] -theorem liftOnUnits_mk (f : ∀ x y : M, c (x * y) 1 → c (y * x) 1 → α) - (Hf : ∀ x y hxy hyx x' y' hxy' hyx', c x x' → c y y' → f x y hxy hyx = f x' y' hxy' hyx') - (x y : M) (hxy hyx) : - liftOnUnits ⟨(x : c.Quotient), y, hxy, hyx⟩ f Hf = f x y (c.eq.1 hxy) (c.eq.1 hyx) := - rfl - -@[to_additive (attr := elab_as_elim)] -theorem induction_on_units {p : Units c.Quotient → Prop} (u : Units c.Quotient) - (H : ∀ (x y : M) (hxy : c (x * y) 1) (hyx : c (y * x) 1), p ⟨x, y, c.eq.2 hxy, c.eq.2 hyx⟩) : - p u := by - rcases u with ⟨⟨x⟩, ⟨y⟩, h₁, h₂⟩ - exact H x y (c.eq.1 h₁) (c.eq.1 h₂) - -end Units - section Actions @[to_additive] diff --git a/Mathlib/GroupTheory/Congruence/BigOperators.lean b/Mathlib/GroupTheory/Congruence/BigOperators.lean index 5e4ad659e7ac7..d7acdc5c89d6d 100644 --- a/Mathlib/GroupTheory/Congruence/BigOperators.lean +++ b/Mathlib/GroupTheory/Congruence/BigOperators.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston -/ -import Mathlib.GroupTheory.Congruence.Basic import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.BigOperators.Group.Multiset import Mathlib.Algebra.BigOperators.Group.List +import Mathlib.GroupTheory.Congruence.Defs /-! # Interactions between `∑, ∏` and `(Add)Con` diff --git a/Mathlib/GroupTheory/Congruence/Defs.lean b/Mathlib/GroupTheory/Congruence/Defs.lean new file mode 100644 index 0000000000000..118baa87520bd --- /dev/null +++ b/Mathlib/GroupTheory/Congruence/Defs.lean @@ -0,0 +1,817 @@ +/- +Copyright (c) 2019 Amelia Livingston. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Amelia Livingston +-/ +import Mathlib.Algebra.Group.InjSurj +import Mathlib.Algebra.Group.Units.Defs +import Mathlib.Data.Setoid.Basic + +/-! +# Congruence relations + +This file defines congruence relations: equivalence relations that preserve a binary operation, +which in this case is multiplication or addition. The principal definition is a `structure` +extending a `Setoid` (an equivalence relation), and the inductive definition of the smallest +congruence relation containing a binary relation is also given (see `ConGen`). + +The file also proves basic properties of the quotient of a type by a congruence relation, and the +complete lattice of congruence relations on a type. We then establish an order-preserving bijection +between the set of congruence relations containing a congruence relation `c` and the set of +congruence relations on the quotient by `c`. + +The second half of the file concerns congruence relations on monoids, in which case the +quotient by the congruence relation is also a monoid. + +## Implementation notes + +The inductive definition of a congruence relation could be a nested inductive type, defined using +the equivalence closure of a binary relation `EqvGen`, but the recursor generated does not work. +A nested inductive definition could conceivably shorten proofs, because they would allow invocation +of the corresponding lemmas about `EqvGen`. + +The lemmas `refl`, `symm` and `trans` are not tagged with `@[refl]`, `@[symm]`, and `@[trans]` +respectively as these tags do not work on a structure coerced to a binary relation. + +There is a coercion from elements of a type to the element's equivalence class under a +congruence relation. + +A congruence relation on a monoid `M` can be thought of as a submonoid of `M × M` for which +membership is an equivalence relation, but whilst this fact is established in the file, it is not +used, since this perspective adds more layers of definitional unfolding. + +## Tags + +congruence, congruence relation, quotient, quotient by congruence relation, monoid, +quotient monoid, isomorphism theorems +-/ + + +variable (M : Type*) {N : Type*} {P : Type*} + +open Function Setoid + +/-- A congruence relation on a type with an addition is an equivalence relation which + preserves addition. -/ +structure AddCon [Add M] extends Setoid M where + /-- Additive congruence relations are closed under addition -/ + add' : ∀ {w x y z}, r w x → r y z → r (w + y) (x + z) + +/-- A congruence relation on a type with a multiplication is an equivalence relation which + preserves multiplication. -/ +@[to_additive AddCon] +structure Con [Mul M] extends Setoid M where + /-- Congruence relations are closed under multiplication -/ + mul' : ∀ {w x y z}, r w x → r y z → r (w * y) (x * z) + +/-- The equivalence relation underlying an additive congruence relation. -/ +add_decl_doc AddCon.toSetoid + +/-- The equivalence relation underlying a multiplicative congruence relation. -/ +add_decl_doc Con.toSetoid + +variable {M} + +/-- The inductively defined smallest additive congruence relation containing a given binary + relation. -/ +inductive AddConGen.Rel [Add M] (r : M → M → Prop) : M → M → Prop + | of : ∀ x y, r x y → AddConGen.Rel r x y + | refl : ∀ x, AddConGen.Rel r x x + | symm : ∀ {x y}, AddConGen.Rel r x y → AddConGen.Rel r y x + | trans : ∀ {x y z}, AddConGen.Rel r x y → AddConGen.Rel r y z → AddConGen.Rel r x z + | add : ∀ {w x y z}, AddConGen.Rel r w x → AddConGen.Rel r y z → AddConGen.Rel r (w + y) (x + z) + +/-- The inductively defined smallest multiplicative congruence relation containing a given binary + relation. -/ +@[to_additive AddConGen.Rel] +inductive ConGen.Rel [Mul M] (r : M → M → Prop) : M → M → Prop + | of : ∀ x y, r x y → ConGen.Rel r x y + | refl : ∀ x, ConGen.Rel r x x + | symm : ∀ {x y}, ConGen.Rel r x y → ConGen.Rel r y x + | trans : ∀ {x y z}, ConGen.Rel r x y → ConGen.Rel r y z → ConGen.Rel r x z + | mul : ∀ {w x y z}, ConGen.Rel r w x → ConGen.Rel r y z → ConGen.Rel r (w * y) (x * z) + +/-- The inductively defined smallest multiplicative congruence relation containing a given binary + relation. -/ +@[to_additive addConGen "The inductively defined smallest additive congruence relation containing +a given binary relation."] +def conGen [Mul M] (r : M → M → Prop) : Con M := + ⟨⟨ConGen.Rel r, ⟨ConGen.Rel.refl, ConGen.Rel.symm, ConGen.Rel.trans⟩⟩, ConGen.Rel.mul⟩ + +namespace Con + +section + +variable [Mul M] [Mul N] [Mul P] (c : Con M) + +@[to_additive] +instance : Inhabited (Con M) := + ⟨conGen EmptyRelation⟩ + +/-- A coercion from a congruence relation to its underlying binary relation. -/ +@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."] +instance : FunLike (Con M) M (M → Prop) where + coe c := c.r + coe_injective' x y h := by + rcases x with ⟨⟨x, _⟩, _⟩ + rcases y with ⟨⟨y, _⟩, _⟩ + have : x = y := h + subst x; rfl + +@[to_additive (attr := simp)] +theorem rel_eq_coe (c : Con M) : c.r = c := + rfl + +/-- Congruence relations are reflexive. -/ +@[to_additive "Additive congruence relations are reflexive."] +protected theorem refl (x) : c x x := + c.toSetoid.refl' x + +/-- Congruence relations are symmetric. -/ +@[to_additive "Additive congruence relations are symmetric."] +protected theorem symm {x y} : c x y → c y x := c.toSetoid.symm' + +/-- Congruence relations are transitive. -/ +@[to_additive "Additive congruence relations are transitive."] +protected theorem trans {x y z} : c x y → c y z → c x z := c.toSetoid.trans' + +/-- Multiplicative congruence relations preserve multiplication. -/ +@[to_additive "Additive congruence relations preserve addition."] +protected theorem mul {w x y z} : c w x → c y z → c (w * y) (x * z) := c.mul' + +@[to_additive (attr := simp)] +theorem rel_mk {s : Setoid M} {h a b} : Con.mk s h a b ↔ r a b := + Iff.rfl + +/-- Given a type `M` with a multiplication, a congruence relation `c` on `M`, and elements of `M` + `x, y`, `(x, y) ∈ M × M` iff `x` is related to `y` by `c`. -/ +@[to_additive "Given a type `M` with an addition, `x, y ∈ M`, and an additive congruence relation +`c` on `M`, `(x, y) ∈ M × M` iff `x` is related to `y` by `c`."] +instance : Membership (M × M) (Con M) := + ⟨fun c x => c x.1 x.2⟩ + +variable {c} + +/-- The map sending a congruence relation to its underlying binary relation is injective. -/ +@[to_additive "The map sending an additive congruence relation to its underlying binary relation +is injective."] +theorem ext' {c d : Con M} (H : ⇑c = ⇑d) : c = d := DFunLike.coe_injective H + +/-- Extensionality rule for congruence relations. -/ +@[to_additive (attr := ext) "Extensionality rule for additive congruence relations."] +theorem ext {c d : Con M} (H : ∀ x y, c x y ↔ d x y) : c = d := + ext' <| by ext; apply H + +/-- The map sending a congruence relation to its underlying equivalence relation is injective. -/ +@[to_additive "The map sending an additive congruence relation to its underlying equivalence +relation is injective."] +theorem toSetoid_inj {c d : Con M} (H : c.toSetoid = d.toSetoid) : c = d := + ext <| Setoid.ext_iff.1 H + +/-- Two congruence relations are equal iff their underlying binary relations are equal. -/ +@[to_additive "Two additive congruence relations are equal iff their underlying binary relations +are equal."] +theorem coe_inj {c d : Con M} : ⇑c = ⇑d ↔ c = d := DFunLike.coe_injective.eq_iff + +/-- The kernel of a multiplication-preserving function as a congruence relation. -/ +@[to_additive "The kernel of an addition-preserving function as an additive congruence relation."] +def mulKer (f : M → P) (h : ∀ x y, f (x * y) = f x * f y) : Con M where + toSetoid := Setoid.ker f + mul' h1 h2 := by + dsimp [Setoid.ker, onFun] at * + rw [h, h1, h2, h] + +variable (c) + +-- Quotients +/-- Defining the quotient by a congruence relation of a type with a multiplication. -/ +@[to_additive "Defining the quotient by an additive congruence relation of a type with +an addition."] +protected def Quotient := + Quotient c.toSetoid + +-- Porting note: made implicit +variable {c} + +/-- The morphism into the quotient by a congruence relation -/ +@[to_additive (attr := coe) "The morphism into the quotient by an additive congruence relation"] +def toQuotient : M → c.Quotient := + Quotient.mk'' + +variable (c) + +-- Porting note: was `priority 0`. why? +/-- Coercion from a type with a multiplication to its quotient by a congruence relation. + +See Note [use has_coe_t]. -/ +@[to_additive "Coercion from a type with an addition to its quotient by an additive congruence +relation"] +instance (priority := 10) : CoeTC M c.Quotient := + ⟨toQuotient⟩ + +-- Lower the priority since it unifies with any quotient type. +/-- The quotient by a decidable congruence relation has decidable equality. -/ +@[to_additive "The quotient by a decidable additive congruence relation has decidable equality."] +instance (priority := 500) [∀ a b, Decidable (c a b)] : DecidableEq c.Quotient := + inferInstanceAs (DecidableEq (Quotient c.toSetoid)) + +@[to_additive (attr := simp)] +theorem quot_mk_eq_coe {M : Type*} [Mul M] (c : Con M) (x : M) : Quot.mk c x = (x : c.Quotient) := + rfl + +-- Porting note (#11215): TODO: restore `elab_as_elim` +/-- The function on the quotient by a congruence relation `c` induced by a function that is + constant on `c`'s equivalence classes. -/ +@[to_additive "The function on the quotient by a congruence relation `c` +induced by a function that is constant on `c`'s equivalence classes."] +protected def liftOn {β} {c : Con M} (q : c.Quotient) (f : M → β) (h : ∀ a b, c a b → f a = f b) : + β := + Quotient.liftOn' q f h + +-- Porting note (#11215): TODO: restore `elab_as_elim` +/-- The binary function on the quotient by a congruence relation `c` induced by a binary function + that is constant on `c`'s equivalence classes. -/ +@[to_additive "The binary function on the quotient by a congruence relation `c` +induced by a binary function that is constant on `c`'s equivalence classes."] +protected def liftOn₂ {β} {c : Con M} (q r : c.Quotient) (f : M → M → β) + (h : ∀ a₁ a₂ b₁ b₂, c a₁ b₁ → c a₂ b₂ → f a₁ a₂ = f b₁ b₂) : β := + Quotient.liftOn₂' q r f h + +/-- A version of `Quotient.hrecOn₂'` for quotients by `Con`. -/ +@[to_additive "A version of `Quotient.hrecOn₂'` for quotients by `AddCon`."] +protected def hrecOn₂ {cM : Con M} {cN : Con N} {φ : cM.Quotient → cN.Quotient → Sort*} + (a : cM.Quotient) (b : cN.Quotient) (f : ∀ (x : M) (y : N), φ x y) + (h : ∀ x y x' y', cM x x' → cN y y' → HEq (f x y) (f x' y')) : φ a b := + Quotient.hrecOn₂' a b f h + +@[to_additive (attr := simp)] +theorem hrec_on₂_coe {cM : Con M} {cN : Con N} {φ : cM.Quotient → cN.Quotient → Sort*} (a : M) + (b : N) (f : ∀ (x : M) (y : N), φ x y) + (h : ∀ x y x' y', cM x x' → cN y y' → HEq (f x y) (f x' y')) : + Con.hrecOn₂ (↑a) (↑b) f h = f a b := + rfl + +variable {c} + +/-- The inductive principle used to prove propositions about the elements of a quotient by a + congruence relation. -/ +@[to_additive (attr := elab_as_elim) "The inductive principle used to prove propositions about +the elements of a quotient by an additive congruence relation."] +protected theorem induction_on {C : c.Quotient → Prop} (q : c.Quotient) (H : ∀ x : M, C x) : C q := + Quotient.inductionOn' q H + +/-- A version of `Con.induction_on` for predicates which take two arguments. -/ +@[to_additive (attr := elab_as_elim) "A version of `AddCon.induction_on` for predicates which take +two arguments."] +protected theorem induction_on₂ {d : Con N} {C : c.Quotient → d.Quotient → Prop} (p : c.Quotient) + (q : d.Quotient) (H : ∀ (x : M) (y : N), C x y) : C p q := + Quotient.inductionOn₂' p q H + +variable (c) + +/-- Two elements are related by a congruence relation `c` iff they are represented by the same + element of the quotient by `c`. -/ +@[to_additive (attr := simp) "Two elements are related by an additive congruence relation `c` iff +they are represented by the same element of the quotient by `c`."] +protected theorem eq {a b : M} : (a : c.Quotient) = (b : c.Quotient) ↔ c a b := + Quotient.eq'' + +/-- The multiplication induced on the quotient by a congruence relation on a type with a + multiplication. -/ +@[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⟩ + +/-- 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 +relation `c` equals `c`."] +theorem mul_ker_mk_eq : (mulKer ((↑) : M → c.Quotient) fun _ _ => rfl) = c := + ext fun _ _ => Quotient.eq'' + +variable {c} + +/-- The coercion to the quotient of a congruence relation commutes with multiplication (by + definition). -/ +@[to_additive (attr := simp) "The coercion to the quotient of an additive congruence relation +commutes with addition (by definition)."] +theorem coe_mul (x y : M) : (↑(x * y) : c.Quotient) = ↑x * ↑y := + rfl + +/-- Definition of the function on the quotient by a congruence relation `c` induced by a function + that is constant on `c`'s equivalence classes. -/ +@[to_additive (attr := simp) "Definition of the function on the quotient by an additive congruence +relation `c` induced by a function that is constant on `c`'s equivalence classes."] +protected theorem liftOn_coe {β} (c : Con M) (f : M → β) (h : ∀ a b, c a b → f a = f b) (x : M) : + Con.liftOn (x : c.Quotient) f h = f x := + rfl + +-- The complete lattice of congruence relations on a type +/-- For congruence relations `c, d` on a type `M` with a multiplication, `c ≤ d` iff `∀ x y ∈ M`, + `x` is related to `y` by `d` if `x` is related to `y` by `c`. -/ +@[to_additive "For additive congruence relations `c, d` on a type `M` with an addition, `c ≤ d` iff +`∀ x y ∈ M`, `x` is related to `y` by `d` if `x` is related to `y` by `c`."] +instance : LE (Con M) where + le c d := ∀ ⦃x y⦄, c x y → d x y + +/-- Definition of `≤` for congruence relations. -/ +@[to_additive "Definition of `≤` for additive congruence relations."] +theorem le_def {c d : Con M} : c ≤ d ↔ ∀ {x y}, c x y → d x y := + Iff.rfl + +/-- The infimum of a set of congruence relations on a given type with a multiplication. -/ +@[to_additive "The infimum of a set of additive congruence relations on a given type with +an addition."] +instance : InfSet (Con M) where + sInf S := + { r := fun x y => ∀ c : Con M, c ∈ S → c x y + iseqv := ⟨fun x c _ => c.refl x, fun h c hc => c.symm <| h c hc, + fun h1 h2 c hc => c.trans (h1 c hc) <| h2 c hc⟩ + mul' := fun h1 h2 c hc => c.mul (h1 c hc) <| h2 c hc } + +/-- The infimum of a set of congruence relations is the same as the infimum of the set's image + under the map to the underlying equivalence relation. -/ +@[to_additive "The infimum of a set of additive congruence relations is the same as the infimum of +the set's image under the map to the underlying equivalence relation."] +theorem sInf_toSetoid (S : Set (Con M)) : (sInf S).toSetoid = sInf (toSetoid '' S) := + Setoid.ext fun x y => + ⟨fun h r ⟨c, hS, hr⟩ => by rw [← hr]; exact h c hS, fun h c hS => h c.toSetoid ⟨c, hS, rfl⟩⟩ + +/-- The infimum of a set of congruence relations is the same as the infimum of the set's image + under the map to the underlying binary relation. -/ +@[to_additive (attr := simp, norm_cast) + "The infimum of a set of additive congruence relations is the same as the infimum + of the set's image under the map to the underlying binary relation."] +theorem coe_sInf (S : Set (Con M)) : + ⇑(sInf S) = sInf ((⇑) '' S) := by + ext + simp only [sInf_image, iInf_apply, iInf_Prop_eq] + rfl + +@[to_additive (attr := simp, norm_cast)] +theorem coe_iInf {ι : Sort*} (f : ι → Con M) : ⇑(iInf f) = ⨅ i, ⇑(f i) := by + rw [iInf, coe_sInf, ← Set.range_comp, sInf_range, Function.comp_def] + +@[to_additive] +instance : PartialOrder (Con M) where + le_refl _ _ _ := id + le_trans _ _ _ h1 h2 _ _ h := h2 <| h1 h + le_antisymm _ _ hc hd := ext fun _ _ => ⟨fun h => hc h, fun h => hd h⟩ + +/-- The complete lattice of congruence relations on a given type with a multiplication. -/ +@[to_additive "The complete lattice of additive congruence relations on a given type with +an addition."] +instance : CompleteLattice (Con M) where + __ := completeLatticeOfInf (Con M) fun s => + ⟨fun r hr x y h => (h : ∀ r ∈ s, (r : Con M) x y) r hr, fun r hr x y h r' hr' => + hr hr' + h⟩ + inf c d := ⟨c.toSetoid ⊓ d.toSetoid, fun h1 h2 => ⟨c.mul h1.1 h2.1, d.mul h1.2 h2.2⟩⟩ + inf_le_left _ _ := fun _ _ h => h.1 + inf_le_right _ _ := fun _ _ h => h.2 + le_inf _ _ _ hb hc := fun _ _ h => ⟨hb h, hc h⟩ + top := { Setoid.completeLattice.top with mul' := by tauto } + le_top _ := fun _ _ _ => trivial + bot := { Setoid.completeLattice.bot with mul' := fun h1 h2 => h1 ▸ h2 ▸ rfl } + bot_le c := fun x _ h => h ▸ c.refl x + +/-- The infimum of two congruence relations equals the infimum of the underlying binary + operations. -/ +@[to_additive (attr := simp, norm_cast) + "The infimum of two additive congruence relations equals the infimum of the underlying binary + operations."] +theorem coe_inf {c d : Con M} : ⇑(c ⊓ d) = ⇑c ⊓ ⇑d := + rfl + +/-- Definition of the infimum of two congruence relations. -/ +@[to_additive "Definition of the infimum of two additive congruence relations."] +theorem inf_iff_and {c d : Con M} {x y} : (c ⊓ d) x y ↔ c x y ∧ d x y := + Iff.rfl + +/-- The inductively defined smallest congruence relation containing a binary relation `r` equals + the infimum of the set of congruence relations containing `r`. -/ +@[to_additive addConGen_eq "The inductively defined smallest additive congruence relation +containing a binary relation `r` equals the infimum of the set of additive congruence relations +containing `r`."] +theorem conGen_eq (r : M → M → Prop) : conGen r = sInf { s : Con M | ∀ x y, r x y → s x y } := + le_antisymm + (le_sInf (fun s hs x y (hxy : (conGen r) x y) => + show s x y by + apply ConGen.Rel.recOn (motive := fun x y _ => s x y) hxy + · exact fun x y h => hs x y h + · exact s.refl' + · exact fun _ => s.symm' + · exact fun _ _ => s.trans' + · exact fun _ _ => s.mul)) + (sInf_le ConGen.Rel.of) + +/-- The smallest congruence relation containing a binary relation `r` is contained in any + congruence relation containing `r`. -/ +@[to_additive addConGen_le "The smallest additive congruence relation containing a binary +relation `r` is contained in any additive congruence relation containing `r`."] +theorem conGen_le {r : M → M → Prop} {c : Con M} (h : ∀ x y, r x y → c x y) : + conGen r ≤ c := by rw [conGen_eq]; exact sInf_le h + +/-- Given binary relations `r, s` with `r` contained in `s`, the smallest congruence relation + containing `s` contains the smallest congruence relation containing `r`. -/ +@[to_additive addConGen_mono "Given binary relations `r, s` with `r` contained in `s`, the +smallest additive congruence relation containing `s` contains the smallest additive congruence +relation containing `r`."] +theorem conGen_mono {r s : M → M → Prop} (h : ∀ x y, r x y → s x y) : conGen r ≤ conGen s := + conGen_le fun x y hr => ConGen.Rel.of _ _ <| h x y hr + +/-- Congruence relations equal the smallest congruence relation in which they are contained. -/ +@[to_additive (attr := simp) addConGen_of_addCon "Additive congruence relations equal the smallest +additive congruence relation in which they are contained."] +theorem conGen_of_con (c : Con M) : conGen c = c := + le_antisymm (by rw [conGen_eq]; exact sInf_le fun _ _ => id) ConGen.Rel.of + +-- Porting note: removing simp, simp can prove it +/-- The map sending a binary relation to the smallest congruence relation in which it is + contained is idempotent. -/ +@[to_additive addConGen_idem "The map sending a binary relation to the smallest additive +congruence relation in which it is contained is idempotent."] +theorem conGen_idem (r : M → M → Prop) : conGen (conGen r) = conGen r := + conGen_of_con _ + +/-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing + the binary relation '`x` is related to `y` by `c` or `d`'. -/ +@[to_additive sup_eq_addConGen "The supremum of additive congruence relations `c, d` equals the +smallest additive congruence relation containing the binary relation '`x` is related to `y` +by `c` or `d`'."] +theorem sup_eq_conGen (c d : Con M) : c ⊔ d = conGen fun x y => c x y ∨ d x y := by + rw [conGen_eq] + apply congr_arg sInf + simp only [le_def, or_imp, ← forall_and] + +/-- The supremum of two congruence relations equals the smallest congruence relation containing + the supremum of the underlying binary operations. -/ +@[to_additive "The supremum of two additive congruence relations equals the smallest additive +congruence relation containing the supremum of the underlying binary operations."] +theorem sup_def {c d : Con M} : c ⊔ d = conGen (⇑c ⊔ ⇑d) := by rw [sup_eq_conGen]; rfl + +/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation + containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by + `c`'. -/ +@[to_additive sSup_eq_addConGen "The supremum of a set of additive congruence relations `S` equals +the smallest additive congruence relation containing the binary relation 'there exists `c ∈ S` +such that `x` is related to `y` by `c`'."] +theorem sSup_eq_conGen (S : Set (Con M)) : + sSup S = conGen fun x y => ∃ c : Con M, c ∈ S ∧ c x y := by + rw [conGen_eq] + apply congr_arg sInf + ext + exact ⟨fun h _ _ ⟨r, hr⟩ => h hr.1 hr.2, fun h r hS _ _ hr => h _ _ ⟨r, hS, hr⟩⟩ + +/-- The supremum of a set of congruence relations is the same as the smallest congruence relation + containing the supremum of the set's image under the map to the underlying binary relation. -/ +@[to_additive "The supremum of a set of additive congruence relations is the same as the smallest +additive congruence relation containing the supremum of the set's image under the map to the +underlying binary relation."] +theorem sSup_def {S : Set (Con M)} : + sSup S = conGen (sSup ((⇑) '' S)) := by + rw [sSup_eq_conGen, sSup_image] + congr with (x y) + simp only [sSup_image, iSup_apply, iSup_Prop_eq, exists_prop, rel_eq_coe] + +variable (M) + +/-- There is a Galois insertion of congruence relations on a type with a multiplication `M` into + binary relations on `M`. -/ +@[to_additive "There is a Galois insertion of additive congruence relations on a type with +an addition `M` into binary relations on `M`."] +protected def gi : @GaloisInsertion (M → M → Prop) (Con M) _ _ conGen DFunLike.coe where + choice r _ := conGen r + gc _ c := ⟨fun H _ _ h => H <| ConGen.Rel.of _ _ h, @fun H => conGen_of_con c ▸ conGen_mono H⟩ + le_l_u x := (conGen_of_con x).symm ▸ le_refl x + choice_eq _ _ := rfl + +variable {M} (c) + +/-- Given a function `f`, the smallest congruence relation containing the binary relation on `f`'s + image defined by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` + by a congruence relation `c`.' -/ +@[to_additive "Given a function `f`, the smallest additive congruence relation containing the +binary relation on `f`'s image defined by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the +elements of `f⁻¹(y)` by an additive congruence relation `c`.'"] +def mapGen (f : M → N) : Con N := + conGen fun x y => ∃ a b, f a = x ∧ f b = y ∧ c a b + +/-- Given a surjective multiplicative-preserving function `f` whose kernel is contained in a + congruence relation `c`, the congruence relation on `f`'s codomain defined by '`x ≈ y` iff the + elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` by `c`.' -/ +@[to_additive "Given a surjective addition-preserving function `f` whose kernel is contained in +an additive congruence relation `c`, the additive congruence relation on `f`'s codomain defined +by '`x ≈ y` iff the elements of `f⁻¹(x)` are related to the elements of `f⁻¹(y)` by `c`.'"] +def mapOfSurjective (f : M → N) (H : ∀ x y, f (x * y) = f x * f y) (h : mulKer f H ≤ c) + (hf : Surjective f) : Con N := + { c.toSetoid.mapOfSurjective f h hf with + mul' := fun h₁ h₂ => by + rcases h₁ with ⟨a, b, rfl, rfl, h1⟩ + rcases h₂ with ⟨p, q, rfl, rfl, h2⟩ + exact ⟨a * p, b * q, by rw [H], by rw [H], c.mul h1 h2⟩ } + +/-- A specialization of 'the smallest congruence relation containing a congruence relation `c` + equals `c`'. -/ +@[to_additive "A specialization of 'the smallest additive congruence relation containing +an additive congruence relation `c` equals `c`'."] +theorem mapOfSurjective_eq_mapGen {c : Con M} {f : M → N} (H : ∀ x y, f (x * y) = f x * f y) + (h : mulKer f H ≤ c) (hf : Surjective f) : c.mapGen f = c.mapOfSurjective f H h hf := by + rw [← conGen_of_con (c.mapOfSurjective f H h hf)]; rfl + +/-- Given types with multiplications `M, N` and a congruence relation `c` on `N`, a + multiplication-preserving map `f : M → N` induces a congruence relation on `f`'s domain + defined by '`x ≈ y` iff `f(x)` is related to `f(y)` by `c`.' -/ +@[to_additive "Given types with additions `M, N` and an additive congruence relation `c` on `N`, +an addition-preserving map `f : M → N` induces an additive congruence relation on `f`'s domain +defined by '`x ≈ y` iff `f(x)` is related to `f(y)` by `c`.' "] +def comap (f : M → N) (H : ∀ x y, f (x * y) = f x * f y) (c : Con N) : Con M := + { c.toSetoid.comap f with + mul' := @fun w x y z h1 h2 => show c (f (w * y)) (f (x * z)) by rw [H, H]; exact c.mul h1 h2 } + +@[to_additive (attr := simp)] +theorem comap_rel {f : M → N} (H : ∀ x y, f (x * y) = f x * f y) {c : Con N} {x y : M} : + comap f H c x y ↔ c (f x) (f y) := + Iff.rfl + +section + +open Quotient + +/-- Given a congruence relation `c` on a type `M` with a multiplication, the order-preserving + bijection between the set of congruence relations containing `c` and the congruence relations + on the quotient of `M` by `c`. -/ +@[to_additive "Given an additive congruence relation `c` on a type `M` with an addition, +the order-preserving bijection between the set of additive congruence relations containing `c` and +the additive congruence relations on the quotient of `M` by `c`."] +def correspondence : { d // c ≤ d } ≃o Con c.Quotient where + toFun d := + d.1.mapOfSurjective (↑) (fun _ _ => rfl) (by rw [mul_ker_mk_eq]; exact d.2) <| + @Quotient.exists_rep _ c.toSetoid + invFun d := + ⟨comap ((↑) : M → c.Quotient) (fun _ _ => rfl) d, fun x y h => + show d x y by rw [c.eq.2 h]; exact d.refl _⟩ + left_inv d := + -- Porting note: by exact needed for unknown reason + by exact + Subtype.ext_iff_val.2 <| + ext fun x y => + ⟨fun h => + let ⟨a, b, hx, hy, H⟩ := h + d.1.trans (d.1.symm <| d.2 <| c.eq.1 hx) <| d.1.trans H <| d.2 <| c.eq.1 hy, + fun h => ⟨_, _, rfl, rfl, h⟩⟩ + right_inv d := + -- Porting note: by exact needed for unknown reason + by exact + ext fun x y => + ⟨fun h => + let ⟨_, _, hx, hy, H⟩ := h + hx ▸ hy ▸ H, + Con.induction_on₂ x y fun w z h => ⟨w, z, rfl, rfl, h⟩⟩ + map_rel_iff' := @fun s t => by + constructor + · intros h x y hs + rcases h ⟨x, y, rfl, rfl, hs⟩ with ⟨a, b, hx, hy, ht⟩ + exact t.1.trans (t.1.symm <| t.2 <| Quotient.eq'.1 hx) + (t.1.trans ht (t.2 <| Quotient.eq'.1 hy)) + · intros h _ _ hs + rcases hs with ⟨a, b, hx, hy, Hs⟩ + exact ⟨a, b, hx, hy, h Hs⟩ + +end + +end + +section MulOneClass + +variable [MulOneClass M] (c : Con M) + +/-- The quotient of a monoid by a congruence relation is a monoid. -/ +@[to_additive "The quotient of an `AddMonoid` by an additive congruence relation is +an `AddMonoid`."] +instance mulOneClass : MulOneClass c.Quotient where + one := ((1 : M) : c.Quotient) + mul_one x := Quotient.inductionOn' x fun _ => congr_arg ((↑) : M → c.Quotient) <| mul_one _ + one_mul x := Quotient.inductionOn' x fun _ => congr_arg ((↑) : M → c.Quotient) <| one_mul _ + +variable {c} + +/-- The 1 of the quotient of a monoid by a congruence relation is the equivalence class of the + monoid's 1. -/ +@[to_additive (attr := simp) "The 0 of the quotient of an `AddMonoid` by an additive congruence +relation is the equivalence class of the `AddMonoid`'s 0."] +theorem coe_one : ((1 : M) : c.Quotient) = 1 := + rfl + +/-- There exists an element of the quotient of a monoid by a congruence relation (namely 1). -/ +@[to_additive "There exists an element of the quotient of an `AddMonoid` by a congruence relation +(namely 0)."] +instance Quotient.inhabited : Inhabited c.Quotient := + ⟨((1 : M) : c.Quotient)⟩ + +end MulOneClass + +section Monoids + +/-- Multiplicative congruence relations preserve natural powers. -/ +@[to_additive "Additive congruence relations preserve natural scaling."] +protected theorem pow {M : Type*} [Monoid M] (c : Con M) : + ∀ (n : ℕ) {w x}, c w x → c (w ^ n) (x ^ n) + | 0, w, x, _ => by simpa using c.refl _ + | Nat.succ n, w, x, h => by simpa [pow_succ] using c.mul (Con.pow c n h) h + +@[to_additive] +instance one [MulOneClass M] (c : Con M) : One c.Quotient where + -- Using Quotient.mk'' here instead of c.toQuotient + -- since c.toQuotient is not reducible. + -- This would lead to non-defeq diamonds since this instance ends up in + -- quotients modulo ideals. + one := Quotient.mk'' (1 : M) + -- one := ((1 : M) : c.Quotient) + +instance _root_.AddCon.Quotient.nsmul {M : Type*} [AddMonoid M] (c : AddCon M) : + SMul ℕ c.Quotient where + smul n := (Quotient.map' (n • ·)) fun _ _ => c.nsmul n + +@[to_additive existing AddCon.Quotient.nsmul] +instance {M : Type*} [Monoid M] (c : Con M) : Pow c.Quotient ℕ where + pow x n := Quotient.map' (fun x => x ^ n) (fun _ _ => c.pow n) x + +/-- The quotient of a semigroup by a congruence relation is a semigroup. -/ +@[to_additive "The quotient of an `AddSemigroup` by an additive congruence relation is +an `AddSemigroup`."] +instance semigroup {M : Type*} [Semigroup M] (c : Con M) : Semigroup c.Quotient := + { (Function.Surjective.semigroup _ + Quotient.surjective_Quotient_mk'' fun _ _ => rfl : + Semigroup c.Quotient) with + /- The `toMul` field is given explicitly for performance reasons. + This avoids any need to unfold `Function.Surjective.semigroup` when the type checker is checking + that instance diagrams commute -/ + toMul := Con.hasMul _ } + +/-- The quotient of a commutative semigroup by a congruence relation is a semigroup. -/ +@[to_additive "The quotient of an `AddCommSemigroup` by an additive congruence relation is +an `AddCommSemigroup`."] +instance commSemigroup {M : Type*} [CommSemigroup M] (c : Con M) : CommSemigroup c.Quotient := + { (Function.Surjective.commSemigroup _ Quotient.surjective_Quotient_mk'' fun _ _ => rfl : + CommSemigroup c.Quotient) with + /- The `toSemigroup` field is given explicitly for performance reasons. + This avoids any need to unfold `Function.Surjective.commSemigroup` when the type checker is + checking that instance diagrams commute -/ + toSemigroup := Con.semigroup _ } + +/-- The quotient of a monoid by a congruence relation is a monoid. -/ +@[to_additive "The quotient of an `AddMonoid` by an additive congruence relation is +an `AddMonoid`."] +instance monoid {M : Type*} [Monoid M] (c : Con M) : Monoid c.Quotient := + { (Function.Surjective.monoid _ Quotient.surjective_Quotient_mk'' rfl + (fun _ _ => rfl) fun _ _ => rfl : Monoid c.Quotient) with + /- The `toSemigroup` and `toOne` fields are given explicitly for performance reasons. + This avoids any need to unfold `Function.Surjective.monoid` when the type checker is + checking that instance diagrams commute -/ + toSemigroup := Con.semigroup _ + toOne := Con.one _ } + +/-- The quotient of a `CommMonoid` by a congruence relation is a `CommMonoid`. -/ +@[to_additive "The quotient of an `AddCommMonoid` by an additive congruence +relation is an `AddCommMonoid`."] +instance commMonoid {M : Type*} [CommMonoid M] (c : Con M) : CommMonoid c.Quotient := + { (Function.Surjective.commMonoid _ Quotient.surjective_Quotient_mk'' rfl + (fun _ _ => rfl) fun _ _ => rfl : CommMonoid c.Quotient) with + /- The `toMonoid` field is given explicitly for performance reasons. + This avoids any need to unfold `Function.Surjective.commMonoid` when the type checker is + checking that instance diagrams commute -/ + toMonoid := Con.monoid _ } + +/-- Sometimes, a group is defined as a quotient of a monoid by a congruence relation. +Usually, the inverse operation is defined as `Setoid.map f _` for some `f`. +This lemma allows to avoid code duplication in the definition of the inverse operation: +instead of proving both `∀ x y, c x y → c (f x) (f y)` (to define the operation) +and `∀ x, c (f x * x) 1` (to prove the group laws), one can only prove the latter. -/ +@[to_additive "Sometimes, an additive group is defined as a quotient of a monoid + by an additive congruence relation. + Usually, the inverse operation is defined as `Setoid.map f _` for some `f`. + This lemma allows to avoid code duplication in the definition of the inverse operation: + instead of proving both `∀ x y, c x y → c (f x) (f y)` (to define the operation) + and `∀ x, c (f x + x) 0` (to prove the group laws), one can only prove the latter."] +theorem map_of_mul_left_rel_one [Monoid M] (c : Con M) + (f : M → M) (hf : ∀ x, c (f x * x) 1) {x y} (h : c x y) : c (f x) (f y) := by + simp only [← Con.eq, coe_one, coe_mul] at * + have hf' : ∀ x : M, (x : c.Quotient) * f x = 1 := fun x ↦ + calc + (x : c.Quotient) * f x = f (f x) * f x * (x * f x) := by simp [hf] + _ = f (f x) * (f x * x) * f x := by ac_rfl + _ = 1 := by simp [hf] + have : (⟨_, _, hf' x, hf x⟩ : c.Quotientˣ) = ⟨_, _, hf' y, hf y⟩ := Units.ext h + exact congr_arg Units.inv this + +end Monoids + +section Groups + +variable [Group M] (c : Con M) + +/-- Multiplicative congruence relations preserve inversion. -/ +@[to_additive "Additive congruence relations preserve negation."] +protected theorem inv {x y} (h : c x y) : c x⁻¹ y⁻¹ := + c.map_of_mul_left_rel_one Inv.inv (fun x => by simp only [inv_mul_cancel, c.refl 1]) h + +/-- Multiplicative congruence relations preserve division. -/ +@[to_additive "Additive congruence relations preserve subtraction."] +protected theorem div : ∀ {w x y z}, c w x → c y z → c (w / y) (x / z) := @fun w x y z h1 h2 => by + simpa only [div_eq_mul_inv] using c.mul h1 (c.inv h2) + +/-- Multiplicative congruence relations preserve integer powers. -/ +@[to_additive "Additive congruence relations preserve integer scaling."] +protected theorem zpow : ∀ (n : ℤ) {w x}, c w x → c (w ^ n) (x ^ n) + | Int.ofNat n, w, x, h => by simpa only [zpow_natCast, Int.ofNat_eq_coe] using c.pow n h + | Int.negSucc n, w, x, h => by simpa only [zpow_negSucc] using c.inv (c.pow _ h) + +/-- The inversion induced on the quotient by a congruence relation on a type with an + inversion. -/ +@[to_additive "The negation induced on the quotient by an additive congruence relation on a type +with a negation."] +instance hasInv : Inv c.Quotient := + ⟨(Quotient.map' Inv.inv) fun _ _ => c.inv⟩ + +/-- The division induced on the quotient by a congruence relation on a type with a + division. -/ +@[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₂⟩ + +/-- The integer scaling induced on the quotient by a congruence relation on a type with a + subtraction. -/ +instance _root_.AddCon.Quotient.zsmul {M : Type*} [AddGroup M] (c : AddCon M) : + SMul ℤ c.Quotient := + ⟨fun z => (Quotient.map' (z • ·)) fun _ _ => c.zsmul z⟩ + +/-- The integer power induced on the quotient by a congruence relation on a type with a + division. -/ +@[to_additive existing AddCon.Quotient.zsmul] +instance zpowinst : Pow c.Quotient ℤ := + ⟨fun x z => Quotient.map' (fun x => x ^ z) (fun _ _ h => c.zpow z h) x⟩ + +/-- The quotient of a group by a congruence relation is a group. -/ +@[to_additive "The quotient of an `AddGroup` by an additive congruence relation is +an `AddGroup`."] +instance group : Group c.Quotient := + { (Function.Surjective.group Quotient.mk'' + Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) (fun _ => rfl) + (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl : Group c.Quotient) with + toMonoid := Con.monoid _ + toInv := Con.hasInv _ + toDiv := Con.hasDiv _ } + +end Groups + +section Units + +variable {α : Type*} [Monoid M] {c : Con M} + +/-- In order to define a function `(Con.Quotient c)ˣ → α` on the units of `Con.Quotient c`, +where `c : Con M` is a multiplicative congruence on a monoid, it suffices to define a function `f` +that takes elements `x y : M` with proofs of `c (x * y) 1` and `c (y * x) 1`, and returns an element +of `α` provided that `f x y _ _ = f x' y' _ _` whenever `c x x'` and `c y y'`. -/ +@[to_additive] +def liftOnUnits (u : Units c.Quotient) (f : ∀ x y : M, c (x * y) 1 → c (y * x) 1 → α) + (Hf : ∀ x y hxy hyx x' y' hxy' hyx', + c x x' → c y y' → f x y hxy hyx = f x' y' hxy' hyx') : α := by + refine + Con.hrecOn₂ (cN := c) (φ := fun x y => x * y = 1 → y * x = 1 → α) (u : c.Quotient) + (↑u⁻¹ : c.Quotient) + (fun (x y : M) (hxy : (x * y : c.Quotient) = 1) (hyx : (y * x : c.Quotient) = 1) => + f x y (c.eq.1 hxy) (c.eq.1 hyx)) + (fun x y x' y' hx hy => ?_) u.3 u.4 + refine Function.hfunext ?_ ?_ + · rw [c.eq.2 hx, c.eq.2 hy] + · rintro Hxy Hxy' - + refine Function.hfunext ?_ ?_ + · rw [c.eq.2 hx, c.eq.2 hy] + · rintro Hyx Hyx' - + exact heq_of_eq (Hf _ _ _ _ _ _ _ _ hx hy) + +/-- In order to define a function `(Con.Quotient c)ˣ → α` on the units of `Con.Quotient c`, +where `c : Con M` is a multiplicative congruence on a monoid, it suffices to define a function `f` +that takes elements `x y : M` with proofs of `c (x * y) 1` and `c (y * x) 1`, and returns an element +of `α` provided that `f x y _ _ = f x' y' _ _` whenever `c x x'` and `c y y'`. -/ +add_decl_doc AddCon.liftOnAddUnits + +@[to_additive (attr := simp)] +theorem liftOnUnits_mk (f : ∀ x y : M, c (x * y) 1 → c (y * x) 1 → α) + (Hf : ∀ x y hxy hyx x' y' hxy' hyx', c x x' → c y y' → f x y hxy hyx = f x' y' hxy' hyx') + (x y : M) (hxy hyx) : + liftOnUnits ⟨(x : c.Quotient), y, hxy, hyx⟩ f Hf = f x y (c.eq.1 hxy) (c.eq.1 hyx) := + rfl + +@[to_additive (attr := elab_as_elim)] +theorem induction_on_units {p : Units c.Quotient → Prop} (u : Units c.Quotient) + (H : ∀ (x y : M) (hxy : c (x * y) 1) (hyx : c (y * x) 1), p ⟨x, y, c.eq.2 hxy, c.eq.2 hyx⟩) : + p u := by + rcases u with ⟨⟨x⟩, ⟨y⟩, h₁, h₂⟩ + exact H x y (c.eq.1 h₁) (c.eq.1 h₂) + +end Units + +end Con diff --git a/Mathlib/GroupTheory/Congruence/Hom.lean b/Mathlib/GroupTheory/Congruence/Hom.lean new file mode 100644 index 0000000000000..9adfa62245816 --- /dev/null +++ b/Mathlib/GroupTheory/Congruence/Hom.lean @@ -0,0 +1,217 @@ +/- +Copyright (c) 2019 Amelia Livingston. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Amelia Livingston +-/ +import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.GroupTheory.Congruence.Defs + +/-! +# Congruence relations and homomorphisms + +This file contains elementary definitions involving congruence relations and morphisms. + +## Main definitions + + * `Con.ker`: the kernel of a monoid homomorphism as a congruence relation + * `Con.mk'`: the map from a monoid to its quotient by a congruence relation + * `Con.lift`: the homomorphism on the quotient given that the congruence is in the kernel + * `Con.map`: homomorphism from a smaller to a larger quotient + +## Tags + +congruence, congruence relation, quotient, quotient by congruence relation, monoid, +quotient monoid +-/ + + +variable (M : Type*) {N : Type*} {P : Type*} + +open Function Setoid + +variable {M} + +namespace Con + +section MulOneClass + +variable [MulOneClass M] [MulOneClass N] [MulOneClass P] {c : Con M} + +/-- The kernel of a monoid homomorphism as a congruence relation. -/ +@[to_additive "The kernel of an `AddMonoid` homomorphism as an additive congruence relation."] +def ker (f : M →* P) : Con M := + mulKer f (map_mul f) + +/-- The definition of the congruence relation defined by a monoid homomorphism's kernel. -/ +@[to_additive (attr := simp) "The definition of the additive congruence relation defined by an +`AddMonoid` homomorphism's kernel."] +theorem ker_rel (f : M →* P) {x y} : ker f x y ↔ f x = f y := + Iff.rfl + +variable (c) + +/-- The natural homomorphism from a monoid to its quotient by a congruence relation. -/ +@[to_additive "The natural homomorphism from an `AddMonoid` to its quotient by an additive +congruence relation."] +def mk' : M →* c.Quotient := + { toFun := (↑) + map_one' := rfl + map_mul' := fun _ _ => rfl } + +variable (x y : M) + +/-- The kernel of the natural homomorphism from a monoid to its quotient by a congruence + relation `c` equals `c`. -/ +@[to_additive (attr := simp) "The kernel of the natural homomorphism from an `AddMonoid` to its +quotient by an additive congruence relation `c` equals `c`."] +theorem mk'_ker : ker c.mk' = c := + ext fun _ _ => c.eq + +variable {c} + +/-- The natural homomorphism from a monoid to its quotient by a congruence relation is + surjective. -/ +@[to_additive "The natural homomorphism from an `AddMonoid` to its quotient by a congruence +relation is surjective."] +theorem mk'_surjective : Surjective c.mk' := + Quotient.surjective_Quotient_mk'' + +@[to_additive (attr := simp)] +theorem coe_mk' : (c.mk' : M → c.Quotient) = ((↑) : M → c.Quotient) := + rfl + +-- Porting note: used to abuse defeq between sets and predicates +@[to_additive] +theorem ker_apply {f : M →* P} {x y} : ker f x y ↔ f x = f y := Iff.rfl + +/-- Given a monoid homomorphism `f : N → M` and a congruence relation `c` on `M`, the congruence + relation induced on `N` by `f` equals the kernel of `c`'s quotient homomorphism composed with + `f`. -/ +@[to_additive "Given an `AddMonoid` homomorphism `f : N → M` and an additive congruence relation +`c` on `M`, the additive congruence relation induced on `N` by `f` equals the kernel of `c`'s +quotient homomorphism composed with `f`."] +theorem comap_eq {f : N →* M} : comap f f.map_mul c = ker (c.mk'.comp f) := + ext fun x y => show c _ _ ↔ c.mk' _ = c.mk' _ by rw [← c.eq]; rfl + +variable (c) (f : M →* P) + +/-- The homomorphism on the quotient of a monoid by a congruence relation `c` induced by a + homomorphism constant on `c`'s equivalence classes. -/ +@[to_additive "The homomorphism on the quotient of an `AddMonoid` by an additive congruence +relation `c` induced by a homomorphism constant on `c`'s equivalence classes."] +def lift (H : c ≤ ker f) : c.Quotient →* P where + toFun x := (Con.liftOn x f) fun _ _ h => H h + map_one' := by rw [← f.map_one]; rfl + map_mul' x y := Con.induction_on₂ x y fun m n => by + dsimp only [← coe_mul, Con.liftOn_coe] + rw [map_mul] + +variable {c f} + +/-- The diagram describing the universal property for quotients of monoids commutes. -/ +@[to_additive "The diagram describing the universal property for quotients of `AddMonoid`s +commutes."] +theorem lift_mk' (H : c ≤ ker f) (x) : c.lift f H (c.mk' x) = f x := + rfl + +/-- The diagram describing the universal property for quotients of monoids commutes. -/ +@[to_additive (attr := simp) "The diagram describing the universal property for quotients of +`AddMonoid`s commutes."] +theorem lift_coe (H : c ≤ ker f) (x : M) : c.lift f H x = f x := + rfl + +/-- The diagram describing the universal property for quotients of monoids commutes. -/ +@[to_additive (attr := simp) "The diagram describing the universal property for quotients of +`AddMonoid`s commutes."] +theorem lift_comp_mk' (H : c ≤ ker f) : (c.lift f H).comp c.mk' = f := by ext; rfl + +/-- Given a homomorphism `f` from the quotient of a monoid by a congruence relation, `f` equals the + homomorphism on the quotient induced by `f` composed with the natural map from the monoid to + the quotient. -/ +@[to_additive (attr := simp) "Given a homomorphism `f` from the quotient of an `AddMonoid` by an +additive congruence relation, `f` equals the homomorphism on the quotient induced by `f` composed +with the natural map from the `AddMonoid` to the quotient."] +theorem lift_apply_mk' (f : c.Quotient →* P) : + (c.lift (f.comp c.mk') fun x y h => show f ↑x = f ↑y by rw [c.eq.2 h]) = f := by + ext x; rcases x with ⟨⟩; rfl + +/-- Homomorphisms on the quotient of a monoid by a congruence relation are equal if they + are equal on elements that are coercions from the monoid. -/ +@[to_additive "Homomorphisms on the quotient of an `AddMonoid` by an additive congruence relation +are equal if they are equal on elements that are coercions from the `AddMonoid`."] +theorem lift_funext (f g : c.Quotient →* P) (h : ∀ a : M, f a = g a) : f = g := by + rw [← lift_apply_mk' f, ← lift_apply_mk' g] + congr 1 + exact DFunLike.ext_iff.2 h + +/-- The uniqueness part of the universal property for quotients of monoids. -/ +@[to_additive "The uniqueness part of the universal property for quotients of `AddMonoid`s."] +theorem lift_unique (H : c ≤ ker f) (g : c.Quotient →* P) (Hg : g.comp c.mk' = f) : + g = c.lift f H := + (lift_funext g (c.lift f H)) fun x => by + subst f + rfl + +/-- Surjective monoid homomorphisms constant on a congruence relation `c`'s equivalence classes + induce a surjective homomorphism on `c`'s quotient. -/ +@[to_additive "Surjective `AddMonoid` homomorphisms constant on an additive congruence +relation `c`'s equivalence classes induce a surjective homomorphism on `c`'s quotient."] +theorem lift_surjective_of_surjective (h : c ≤ ker f) (hf : Surjective f) : + Surjective (c.lift f h) := fun y => + (Exists.elim (hf y)) fun w hw => ⟨w, (lift_mk' h w).symm ▸ hw⟩ + +variable (c f) + +/-- Given a monoid homomorphism `f` from `M` to `P`, the kernel of `f` is the unique congruence + relation on `M` whose induced map from the quotient of `M` to `P` is injective. -/ +@[to_additive "Given an `AddMonoid` homomorphism `f` from `M` to `P`, the kernel of `f` +is the unique additive congruence relation on `M` whose induced map from the quotient of `M` +to `P` is injective."] +theorem ker_eq_lift_of_injective (H : c ≤ ker f) (h : Injective (c.lift f H)) : ker f = c := + toSetoid_inj <| Setoid.ker_eq_lift_of_injective f H h + +variable {c} + +/-- The homomorphism induced on the quotient of a monoid by the kernel of a monoid homomorphism. -/ +@[to_additive "The homomorphism induced on the quotient of an `AddMonoid` by the kernel +of an `AddMonoid` homomorphism."] +def kerLift : (ker f).Quotient →* P := + ((ker f).lift f) fun _ _ => id + +variable {f} + +/-- The diagram described by the universal property for quotients of monoids, when the congruence + relation is the kernel of the homomorphism, commutes. -/ +@[to_additive (attr := simp) "The diagram described by the universal property for quotients +of `AddMonoid`s, when the additive congruence relation is the kernel of the homomorphism, +commutes."] +theorem kerLift_mk (x : M) : kerLift f x = f x := + rfl + +/-- A monoid homomorphism `f` induces an injective homomorphism on the quotient by `f`'s kernel. -/ +@[to_additive "An `AddMonoid` homomorphism `f` induces an injective homomorphism on the quotient +by `f`'s kernel."] +theorem kerLift_injective (f : M →* P) : Injective (kerLift f) := fun x y => + Quotient.inductionOn₂' x y fun _ _ => (ker f).eq.2 + +/-- Given congruence relations `c, d` on a monoid such that `d` contains `c`, `d`'s quotient + map induces a homomorphism from the quotient by `c` to the quotient by `d`. -/ +@[to_additive "Given additive congruence relations `c, d` on an `AddMonoid` such that `d` +contains `c`, `d`'s quotient map induces a homomorphism from the quotient by `c` to the quotient +by `d`."] +def map (c d : Con M) (h : c ≤ d) : c.Quotient →* d.Quotient := + (c.lift d.mk') fun x y hc => show (ker d.mk') x y from (mk'_ker d).symm ▸ h hc + +/-- Given congruence relations `c, d` on a monoid such that `d` contains `c`, the definition of + the homomorphism from the quotient by `c` to the quotient by `d` induced by `d`'s quotient + map. -/ +@[to_additive "Given additive congruence relations `c, d` on an `AddMonoid` such that `d` +contains `c`, the definition of the homomorphism from the quotient by `c` to the quotient by `d` +induced by `d`'s quotient map."] +theorem map_apply {c d : Con M} (h : c ≤ d) (x) : + c.map d h x = c.lift d.mk' (fun _ _ hc => d.eq.2 <| h hc) x := + rfl + +end MulOneClass + +end Con diff --git a/Mathlib/GroupTheory/Congruence/Opposite.lean b/Mathlib/GroupTheory/Congruence/Opposite.lean index c0701bb273a2f..6d07398f60e72 100644 --- a/Mathlib/GroupTheory/Congruence/Opposite.lean +++ b/Mathlib/GroupTheory/Congruence/Opposite.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston -/ -import Mathlib.GroupTheory.Congruence.Basic import Mathlib.Algebra.Opposites +import Mathlib.GroupTheory.Congruence.Defs /-! # Congruences on the opposite of a group diff --git a/Mathlib/GroupTheory/Coprod/Basic.lean b/Mathlib/GroupTheory/Coprod/Basic.lean index 2349d4a1dad9b..169ff1d0e0bc6 100644 --- a/Mathlib/GroupTheory/Coprod/Basic.lean +++ b/Mathlib/GroupTheory/Coprod/Basic.lean @@ -191,9 +191,9 @@ theorem induction_on' {C : M ∗ N → Prop} (m : M ∗ N) (inl_mul : ∀ m x, C x → C (inl m * x)) (inr_mul : ∀ n x, C x → C (inr n * x)) : C m := by rcases mk_surjective m with ⟨x, rfl⟩ - induction x with - | h0 => exact one - | ih x xs ih => + induction x using FreeMonoid.inductionOn' with + | one => exact one + | mul_of x xs ih => cases x with | inl m => simpa using inl_mul m _ ih | inr n => simpa using inr_mul n _ ih @@ -573,9 +573,9 @@ theorem mk_of_inv_mul : ∀ x : G ⊕ H, mk (of (x.map Inv.inv Inv.inv)) * mk (o theorem con_inv_mul_cancel (x : FreeMonoid (G ⊕ H)) : coprodCon G H (ofList (x.toList.map (Sum.map Inv.inv Inv.inv)).reverse * x) 1 := by rw [← mk_eq_mk, map_mul, map_one] - induction x with - | h0 => simp [map_one mk] -- TODO: fails without `[map_one mk]` - | ih x xs ihx => + induction x using FreeMonoid.inductionOn' with + | one => simp + | mul_of x xs ihx => simp only [toList_of_mul, map_cons, reverse_cons, ofList_append, map_mul, ihx, ofList_singleton] rwa [mul_assoc, ← mul_assoc (mk (of _)), mk_of_inv_mul, one_mul] diff --git a/Mathlib/GroupTheory/CoprodI.lean b/Mathlib/GroupTheory/CoprodI.lean index 67d5fdc6738bd..eb0bad0e811e8 100644 --- a/Mathlib/GroupTheory/CoprodI.lean +++ b/Mathlib/GroupTheory/CoprodI.lean @@ -151,7 +151,7 @@ def lift : (∀ i, M i →* N) ≃ (CoprodI M →* N) where FreeMonoid.lift _ (FreeMonoid.of _ * FreeMonoid.of _) = FreeMonoid.lift _ (FreeMonoid.of _) simp only [MonoidHom.map_mul, FreeMonoid.lift_eval_of] - invFun f i := f.comp of + invFun f _ := f.comp of left_inv := by intro fi ext i x diff --git a/Mathlib/GroupTheory/Coset/Basic.lean b/Mathlib/GroupTheory/Coset/Basic.lean index 75ec037119a2a..1466feedeb685 100644 --- a/Mathlib/GroupTheory/Coset/Basic.lean +++ b/Mathlib/GroupTheory/Coset/Basic.lean @@ -3,9 +3,12 @@ Copyright (c) 2018 Mitchell Rowett. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mitchell Rowett, Kim Morrison -/ -import Mathlib.Algebra.Quotient import Mathlib.Algebra.Group.Subgroup.MulOpposite -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Algebra.Quotient +import Mathlib.Data.Fintype.Card +import Mathlib.Data.Set.Pointwise.SMul +import Mathlib.Data.Setoid.Basic +import Mathlib.GroupTheory.Coset.Defs /-! # Cosets @@ -22,10 +25,6 @@ If instead `G` is an additive group, we can write (with `open scoped Pointwise` ## Main definitions -* `QuotientGroup.quotient s`: the quotient type representing the left cosets with respect to a - subgroup `s`, for an `AddGroup` this is `QuotientAddGroup.quotient s`. -* `QuotientGroup.mk`: the canonical map from `α` to `α/s` for a subgroup `s` of `α`, for an - `AddGroup` this is `QuotientAddGroup.mk`. * `Subgroup.leftCosetEquivSubgroup`: the natural bijection between a left coset and the subgroup, for an `AddGroup` this is `AddSubgroup.leftCosetEquivAddSubgroup`. @@ -218,117 +217,49 @@ theorem rightCoset_eq_iff {x y : α} : op x • (s : Set α) = op y • s ↔ y end CosetSubgroup --- Porting note: see https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/.E2.9C.94.20to_additive.2Emap_namespace -run_cmd Lean.Elab.Command.liftCoreM <| ToAdditive.insertTranslation `QuotientGroup `QuotientAddGroup - namespace QuotientGroup variable [Group α] (s : Subgroup α) -/-- The equivalence relation corresponding to the partition of a group by left cosets -of a subgroup. -/ -@[to_additive "The equivalence relation corresponding to the partition of a group by left cosets - of a subgroup."] -def leftRel : Setoid α := - MulAction.orbitRel s.op α - -variable {s} - -@[to_additive] -theorem leftRel_apply {x y : α} : @Setoid.r _ (leftRel s) x y ↔ x⁻¹ * y ∈ s := - calc - (∃ a : s.op, y * MulOpposite.unop a = x) ↔ ∃ a : s, y * a = x := - s.equivOp.symm.exists_congr_left - _ ↔ ∃ a : s, x⁻¹ * y = a⁻¹ := by - simp only [inv_mul_eq_iff_eq_mul, Subgroup.coe_inv, eq_mul_inv_iff_mul_eq] - _ ↔ x⁻¹ * y ∈ s := by simp [exists_inv_mem_iff_exists_mem] - -variable (s) - -@[to_additive] -theorem leftRel_eq : @Setoid.r _ (leftRel s) = fun x y => x⁻¹ * y ∈ s := - funext₂ <| by - simp only [eq_iff_iff] - apply leftRel_apply - theorem leftRel_r_eq_leftCosetEquivalence : - @Setoid.r _ (QuotientGroup.leftRel s) = LeftCosetEquivalence s := by + ⇑(QuotientGroup.leftRel s) = LeftCosetEquivalence s := by ext rw [leftRel_eq] exact (leftCoset_eq_iff s).symm @[to_additive] -instance leftRelDecidable [DecidablePred (· ∈ s)] : DecidableRel (leftRel s).r := fun x y => by - rw [leftRel_eq] - exact ‹DecidablePred (· ∈ s)› _ - -/-- `α ⧸ s` is the quotient type representing the left cosets of `s`. - If `s` is a normal subgroup, `α ⧸ s` is a group -/ -@[to_additive "`α ⧸ s` is the quotient type representing the left cosets of `s`. If `s` is a normal - subgroup, `α ⧸ s` is a group"] -instance instHasQuotientSubgroup : HasQuotient α (Subgroup α) := - ⟨fun s => Quotient (leftRel s)⟩ - -/-- The equivalence relation corresponding to the partition of a group by right cosets of a -subgroup. -/ -@[to_additive "The equivalence relation corresponding to the partition of a group by right cosets - of a subgroup."] -def rightRel : Setoid α := - MulAction.orbitRel s α - -variable {s} - -@[to_additive] -theorem rightRel_apply {x y : α} : @Setoid.r _ (rightRel s) x y ↔ y * x⁻¹ ∈ s := - calc - (∃ a : s, (a : α) * y = x) ↔ ∃ a : s, y * x⁻¹ = a⁻¹ := by - simp only [mul_inv_eq_iff_eq_mul, Subgroup.coe_inv, eq_inv_mul_iff_mul_eq] - _ ↔ y * x⁻¹ ∈ s := by simp [exists_inv_mem_iff_exists_mem] - -variable (s) +lemma leftRel_prod {β : Type*} [Group β] (s' : Subgroup β) : + leftRel (s.prod s') = (leftRel s).prod (leftRel s') := by + refine Setoid.ext fun x y ↦ ?_ + rw [Setoid.prod_apply] + simp_rw [leftRel_apply] + rfl @[to_additive] -theorem rightRel_eq : @Setoid.r _ (rightRel s) = fun x y => y * x⁻¹ ∈ s := - funext₂ <| by - simp only [eq_iff_iff] - apply rightRel_apply +lemma leftRel_pi {ι : Type*} {β : ι → Type*} [∀ i, Group (β i)] (s' : ∀ i, Subgroup (β i)) : + leftRel (Subgroup.pi Set.univ s') = @piSetoid _ _ fun i ↦ leftRel (s' i) := by + refine Setoid.ext fun x y ↦ ?_ + simp [Setoid.piSetoid_apply, leftRel_apply, Subgroup.mem_pi] theorem rightRel_r_eq_rightCosetEquivalence : - @Setoid.r _ (QuotientGroup.rightRel s) = RightCosetEquivalence s := by + ⇑(QuotientGroup.rightRel s) = RightCosetEquivalence s := by ext rw [rightRel_eq] exact (rightCoset_eq_iff s).symm @[to_additive] -instance rightRelDecidable [DecidablePred (· ∈ s)] : DecidableRel (rightRel s).r := fun x y => by - rw [rightRel_eq] - exact ‹DecidablePred (· ∈ s)› _ +lemma rightRel_prod {β : Type*} [Group β] (s' : Subgroup β) : + rightRel (s.prod s') = (rightRel s).prod (rightRel s') := by + refine Setoid.ext fun x y ↦ ?_ + rw [Setoid.prod_apply] + simp_rw [rightRel_apply] + rfl -/-- Right cosets are in bijection with left cosets. -/ -@[to_additive "Right cosets are in bijection with left cosets."] -def quotientRightRelEquivQuotientLeftRel : Quotient (QuotientGroup.rightRel s) ≃ α ⧸ s where - toFun := - Quotient.map' (fun g => g⁻¹) fun a b => by - rw [leftRel_apply, rightRel_apply] - exact fun h => (congr_arg (· ∈ s) (by simp [mul_assoc])).mp (s.inv_mem h) - -- Porting note: replace with `by group` - invFun := - Quotient.map' (fun g => g⁻¹) fun a b => by - rw [leftRel_apply, rightRel_apply] - exact fun h => (congr_arg (· ∈ s) (by simp [mul_assoc])).mp (s.inv_mem h) - -- Porting note: replace with `by group` - left_inv g := - Quotient.inductionOn' g fun g => - Quotient.sound' - (by - simp only [inv_inv] - exact Quotient.exact' rfl) - right_inv g := - Quotient.inductionOn' g fun g => - Quotient.sound' - (by - simp only [inv_inv] - exact Quotient.exact' rfl) +@[to_additive] +lemma rightRel_pi {ι : Type*} {β : ι → Type*} [∀ i, Group (β i)] (s' : ∀ i, Subgroup (β i)) : + rightRel (Subgroup.pi Set.univ s') = @piSetoid _ _ fun i ↦ rightRel (s' i) := by + refine Setoid.ext fun x y ↦ ?_ + simp [Setoid.piSetoid_apply, rightRel_apply, Subgroup.mem_pi] @[to_additive] instance fintypeQuotientRightRel [Fintype (α ⧸ s)] : @@ -350,56 +281,6 @@ variable [Group α] {s : Subgroup α} instance fintype [Fintype α] (s : Subgroup α) [DecidableRel (leftRel s).r] : Fintype (α ⧸ s) := Quotient.fintype (leftRel s) -/-- The canonical map from a group `α` to the quotient `α ⧸ s`. -/ -@[to_additive (attr := coe) "The canonical map from an `AddGroup` `α` to the quotient `α ⧸ s`."] -abbrev mk (a : α) : α ⧸ s := - Quotient.mk'' a - -@[to_additive] -theorem mk_surjective : Function.Surjective <| @mk _ _ s := - Quotient.surjective_Quotient_mk'' - -@[to_additive (attr := simp)] -lemma range_mk : range (QuotientGroup.mk (s := s)) = univ := range_iff_surjective.mpr mk_surjective - -@[to_additive (attr := elab_as_elim)] -theorem induction_on {C : α ⧸ s → Prop} (x : α ⧸ s) (H : ∀ z, C (QuotientGroup.mk z)) : C x := - Quotient.inductionOn' x H - -@[to_additive] -instance : Coe α (α ⧸ s) := - ⟨mk⟩ - -@[to_additive (attr := deprecated (since := "2024-08-04"))] alias induction_on' := induction_on - -@[to_additive (attr := simp)] -theorem quotient_liftOn_mk {β} (f : α → β) (h) (x : α) : Quotient.liftOn' (x : α ⧸ s) f h = f x := - rfl - -@[to_additive] -theorem forall_mk {C : α ⧸ s → Prop} : (∀ x : α ⧸ s, C x) ↔ ∀ x : α, C x := - mk_surjective.forall - -@[to_additive] -theorem exists_mk {C : α ⧸ s → Prop} : (∃ x : α ⧸ s, C x) ↔ ∃ x : α, C x := - mk_surjective.exists - -@[to_additive] -instance (s : Subgroup α) : Inhabited (α ⧸ s) := - ⟨((1 : α) : α ⧸ s)⟩ - -@[to_additive] -protected theorem eq {a b : α} : (a : α ⧸ s) = b ↔ a⁻¹ * b ∈ s := - calc - _ ↔ @Setoid.r _ (leftRel s) a b := Quotient.eq'' - _ ↔ _ := by rw [leftRel_apply] - -@[to_additive (attr := deprecated (since := "2024-08-04"))] alias eq' := QuotientGroup.eq - -@[to_additive] -- Porting note (#10618): `simp` can prove this. -theorem out_eq' (a : α ⧸ s) : mk a.out' = a := - Quotient.out_eq' a - variable (s) /-- Given a subgroup `s`, the function that sends a subgroup `t` to the pair consisting of @@ -417,46 +298,25 @@ theorem strictMono_comap_prod_image : convert ← t₁.mul_mem h' (@le1 ⟨_, QuotientGroup.eq.1 eq⟩ <| t₂.mul_mem (t₂.inv_mem <| h.1 h') ha) apply mul_inv_cancel_left -/- It can be useful to write `obtain ⟨h, H⟩ := mk_out'_eq_mul ...`, and then `rw [H]` or - `simp_rw [H]` or `simp only [H]`. In order for `simp_rw` and `simp only` to work, this lemma is - stated in terms of an arbitrary `h : s`, rather than the specific `h = g⁻¹ * (mk g).out'`. -/ -@[to_additive QuotientAddGroup.mk_out'_eq_mul] -theorem mk_out'_eq_mul (g : α) : ∃ h : s, (mk g : α ⧸ s).out' = g * h := - ⟨⟨g⁻¹ * (mk g).out', QuotientGroup.eq.mp (mk g).out_eq'.symm⟩, by rw [mul_inv_cancel_left]⟩ - variable {s} {a b : α} -@[to_additive (attr := simp)] -theorem mk_mul_of_mem (a : α) (hb : b ∈ s) : (mk (a * b) : α ⧸ s) = mk a := by - rwa [QuotientGroup.eq, mul_inv_rev, inv_mul_cancel_right, s.inv_mem_iff] - @[to_additive] theorem eq_class_eq_leftCoset (s : Subgroup α) (g : α) : { x : α | (x : α ⧸ s) = g } = g • s := Set.ext fun z => by rw [mem_leftCoset_iff, Set.mem_setOf_eq, eq_comm, QuotientGroup.eq, SetLike.mem_coe] +open MulAction in @[to_additive] -theorem preimage_image_mk (N : Subgroup α) (s : Set α) : - mk ⁻¹' ((mk : α → α ⧸ N) '' s) = ⋃ x : N, (· * (x : α)) ⁻¹' s := by - ext x - simp only [QuotientGroup.eq, SetLike.exists, exists_prop, Set.mem_preimage, Set.mem_iUnion, - Set.mem_image, ← eq_inv_mul_iff_mul_eq] - exact - ⟨fun ⟨y, hs, hN⟩ => ⟨_, N.inv_mem hN, by simpa using hs⟩, fun ⟨z, hz, hxz⟩ => - ⟨x * z, hxz, by simpa using hz⟩⟩ - -@[to_additive] -theorem preimage_image_mk_eq_iUnion_image (N : Subgroup α) (s : Set α) : - mk ⁻¹' ((mk : α → α ⧸ N) '' s) = ⋃ x : N, (· * (x : α)) '' s := by - rw [preimage_image_mk, iUnion_congr_of_surjective (·⁻¹) inv_surjective] - exact fun x ↦ image_mul_right' +lemma orbit_mk_eq_smul (x : α) : MulAction.orbitRel.Quotient.orbit (x : α ⧸ s) = x • s := by + ext + rw [orbitRel.Quotient.mem_orbit] + simpa [mem_smul_set_iff_inv_smul_mem, ← leftRel_apply, Quotient.eq''] using Setoid.comm' _ @[to_additive] -theorem preimage_image_mk_eq_mul (N : Subgroup α) (s : Set α) : - mk ⁻¹' ((mk : α → α ⧸ N) '' s) = s * N := by - rw [preimage_image_mk_eq_iUnion_image, iUnion_subtype, ← image2_mul, ← iUnion_image_right] - simp only [SetLike.mem_coe] +lemma orbit_eq_out'_smul (x : α ⧸ s) : MulAction.orbitRel.Quotient.orbit x = x.out' • s := by + induction x using QuotientGroup.induction_on + simp only [orbit_mk_eq_smul, ← eq_class_eq_leftCoset, Quotient.out_eq'] end QuotientGroup @@ -470,13 +330,13 @@ variable [Group α] {s : Subgroup α} @[to_additive "The natural bijection between the cosets `g + s` and `s`."] def leftCosetEquivSubgroup (g : α) : (g • s : Set α) ≃ s := ⟨fun x => ⟨g⁻¹ * x.1, (mem_leftCoset_iff _).1 x.2⟩, fun x => ⟨g * x.1, x.1, x.2, rfl⟩, - fun ⟨x, hx⟩ => Subtype.eq <| by simp, fun ⟨g, hg⟩ => Subtype.eq <| by simp⟩ + fun ⟨x, _⟩ => Subtype.eq <| by simp, fun ⟨g, _⟩ => Subtype.eq <| by simp⟩ /-- The natural bijection between a right coset `s * g` and `s`. -/ @[to_additive "The natural bijection between the cosets `s + g` and `s`."] def rightCosetEquivSubgroup (g : α) : (op g • s : Set α) ≃ s := ⟨fun x => ⟨x.1 * g⁻¹, (mem_rightCoset_iff _).1 x.2⟩, fun x => ⟨x.1 * g, x.1, x.2, rfl⟩, - fun ⟨x, hx⟩ => Subtype.eq <| by simp, fun ⟨g, hg⟩ => Subtype.eq <| by simp⟩ + fun ⟨x, _⟩ => Subtype.eq <| by simp, fun ⟨g, _⟩ => Subtype.eq <| by simp⟩ /-- A (non-canonical) bijection between a group `α` and the product `(α/s) × s` -/ @[to_additive addGroupEquivQuotientProdAddSubgroup @@ -490,25 +350,13 @@ noncomputable def groupEquivQuotientProdSubgroup : α ≃ (α ⧸ s) × s := show (_root_.Subtype fun x : α => Quotient.mk'' x = L) ≃ _root_.Subtype fun x : α => Quotient.mk'' x = Quotient.mk'' _ - simp [-Quotient.eq''] + simp rfl - _ ≃ Σ _L : α ⧸ s, s := Equiv.sigmaCongrRight fun L => leftCosetEquivSubgroup _ + _ ≃ Σ _L : α ⧸ s, s := Equiv.sigmaCongrRight fun _ => leftCosetEquivSubgroup _ _ ≃ (α ⧸ s) × s := Equiv.sigmaEquivProd _ _ variable {t : Subgroup α} -/-- If two subgroups `M` and `N` of `G` are equal, their quotients are in bijection. -/ -@[to_additive "If two subgroups `M` and `N` of `G` are equal, their quotients are in bijection."] -def quotientEquivOfEq (h : s = t) : α ⧸ s ≃ α ⧸ t where - toFun := Quotient.map' id fun _a _b h' => h ▸ h' - invFun := Quotient.map' id fun _a _b h' => h.symm ▸ h' - left_inv q := induction_on q fun _g => rfl - right_inv q := induction_on q fun _g => rfl - -theorem quotientEquivOfEq_mk (h : s = t) (a : α) : - quotientEquivOfEq h (QuotientGroup.mk a) = QuotientGroup.mk a := - rfl - /-- If `H ≤ K`, then `G/H ≃ G/K × K/H` constructively, using the provided right inverse of the quotient map `G → G/K`. The classical version is `Subgroup.quotientEquivProdOfLE`. -/ @[to_additive (attr := simps) @@ -517,7 +365,7 @@ of the quotient map `G → G/K`. The classical version is `Subgroup.quotientEqui def quotientEquivProdOfLE' (h_le : s ≤ t) (f : α ⧸ t → α) (hf : Function.RightInverse f QuotientGroup.mk) : α ⧸ s ≃ (α ⧸ t) × t ⧸ s.subgroupOf t where toFun a := - ⟨a.map' id fun b c h => leftRel_apply.mpr (h_le (leftRel_apply.mp h)), + ⟨a.map' id fun _ _ h => leftRel_apply.mpr (h_le (leftRel_apply.mp h)), a.map' (fun g : α => ⟨(f (Quotient.mk'' g))⁻¹ * g, leftRel_apply.mp (Quotient.exact' (hf g))⟩) fun b c h => by rw [leftRel_apply] @@ -703,7 +551,16 @@ noncomputable def preimageMkEquivSubgroupProdSet (s : Subgroup α) (t : Set (α show QuotientGroup.mk _ ∈ t by rw [mk_mul_of_mem _ a.1.2, out_eq'] exact a.2.2⟩ - left_inv := fun ⟨a, ha⟩ => Subtype.eq <| show _ * _ = a by simp + left_inv := fun ⟨a, _⟩ => Subtype.eq <| show _ * _ = a by simp right_inv := fun ⟨⟨a, ha⟩, ⟨x, hx⟩⟩ => by ext <;> simp [ha] +open MulAction in +/-- A group is made up of a disjoint union of cosets of a subgroup. -/ +@[to_additive "An additive group is made up of a disjoint union of cosets of an additive +subgroup."] +lemma univ_eq_iUnion_smul (H : Subgroup α) : + (Set.univ (α := α)) = ⋃ x : α ⧸ H, x.out' • (H : Set _) := by + simp_rw [univ_eq_iUnion_orbit H.op, orbit_eq_out'_smul] + rfl + end QuotientGroup diff --git a/Mathlib/GroupTheory/Coset/Card.lean b/Mathlib/GroupTheory/Coset/Card.lean index 67a686a06e9b1..df9e2e1b9a667 100644 --- a/Mathlib/GroupTheory/Coset/Card.lean +++ b/Mathlib/GroupTheory/Coset/Card.lean @@ -10,6 +10,8 @@ import Mathlib.SetTheory.Cardinal.Finite # Lagrange's theorem: the order of a subgroup divides the order of the group. -/ +open scoped Pointwise + namespace Subgroup variable {α : Type*} [Group α] @@ -19,6 +21,15 @@ theorem card_eq_card_quotient_mul_card_subgroup (s : Subgroup α) : Nat.card α = Nat.card (α ⧸ s) * Nat.card s := by rw [← Nat.card_prod]; exact Nat.card_congr Subgroup.groupEquivQuotientProdSubgroup +@[to_additive] +lemma card_mul_eq_card_subgroup_mul_card_quotient (s : Subgroup α) (t : Set α) : + Nat.card (t * s : Set α) = Nat.card s * Nat.card (t.image (↑) : Set (α ⧸ s)) := by + rw [← Nat.card_prod, Nat.card_congr] + apply Equiv.trans _ (QuotientGroup.preimageMkEquivSubgroupProdSet _ _) + rw [QuotientGroup.preimage_image_mk] + convert Equiv.refl ↑(t * s) + aesop (add simp [Set.mem_mul]) + /-- **Lagrange's Theorem**: The order of a subgroup divides the order of its ambient group. -/ @[to_additive "**Lagrange's Theorem**: The order of an additive subgroup divides the order of its ambient additive group."] diff --git a/Mathlib/GroupTheory/Coset/Defs.lean b/Mathlib/GroupTheory/Coset/Defs.lean new file mode 100644 index 0000000000000..3673d80c2fb03 --- /dev/null +++ b/Mathlib/GroupTheory/Coset/Defs.lean @@ -0,0 +1,261 @@ +/- +Copyright (c) 2018 Mitchell Rowett. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mitchell Rowett, Kim Morrison +-/ +import Mathlib.Algebra.Quotient +import Mathlib.Algebra.Group.Subgroup.MulOpposite +import Mathlib.GroupTheory.GroupAction.Defs + +/-! +# Cosets + +This file develops the basic theory of left and right cosets. + +When `G` is a group and `a : G`, `s : Set G`, with `open scoped Pointwise` we can write: +* the left coset of `s` by `a` as `a • s` +* the right coset of `s` by `a` as `MulOpposite.op a • s` (or `op a • s` with `open MulOpposite`) + +If instead `G` is an additive group, we can write (with `open scoped Pointwise` still) +* the left coset of `s` by `a` as `a +ᵥ s` +* the right coset of `s` by `a` as `AddOpposite.op a +ᵥ s` (or `op a • s` with `open AddOpposite`) + +## Main definitions + +* `QuotientGroup.quotient s`: the quotient type representing the left cosets with respect to a + subgroup `s`, for an `AddGroup` this is `QuotientAddGroup.quotient s`. +* `QuotientGroup.mk`: the canonical map from `α` to `α/s` for a subgroup `s` of `α`, for an + `AddGroup` this is `QuotientAddGroup.mk`. + +## Notation + +* `G ⧸ H` is the quotient of the (additive) group `G` by the (additive) subgroup `H` + +## TODO + +Properly merge with pointwise actions on sets, by renaming and deduplicating lemmas as appropriate. +-/ + +assert_not_exists Cardinal + +open Function Set +open scoped Pointwise + +variable {α : Type*} + +-- Porting note: see https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/.E2.9C.94.20to_additive.2Emap_namespace +run_cmd Lean.Elab.Command.liftCoreM <| ToAdditive.insertTranslation `QuotientGroup `QuotientAddGroup + +namespace QuotientGroup + +variable [Group α] (s : Subgroup α) + +/-- The equivalence relation corresponding to the partition of a group by left cosets +of a subgroup. -/ +@[to_additive "The equivalence relation corresponding to the partition of a group by left cosets + of a subgroup."] +def leftRel : Setoid α := + MulAction.orbitRel s.op α + +variable {s} + +@[to_additive] +theorem leftRel_apply {x y : α} : leftRel s x y ↔ x⁻¹ * y ∈ s := + calc + (∃ a : s.op, y * MulOpposite.unop a = x) ↔ ∃ a : s, y * a = x := + s.equivOp.symm.exists_congr_left + _ ↔ ∃ a : s, x⁻¹ * y = a⁻¹ := by + simp only [inv_mul_eq_iff_eq_mul, Subgroup.coe_inv, eq_mul_inv_iff_mul_eq] + _ ↔ x⁻¹ * y ∈ s := by simp [exists_inv_mem_iff_exists_mem] + +variable (s) + +@[to_additive] +theorem leftRel_eq : ⇑(leftRel s) = fun x y => x⁻¹ * y ∈ s := + funext₂ <| by + simp only [eq_iff_iff] + apply leftRel_apply + +@[to_additive] +instance leftRelDecidable [DecidablePred (· ∈ s)] : DecidableRel (leftRel s).r := fun x y => by + rw [leftRel_eq] + exact ‹DecidablePred (· ∈ s)› _ + +/-- `α ⧸ s` is the quotient type representing the left cosets of `s`. + If `s` is a normal subgroup, `α ⧸ s` is a group -/ +@[to_additive "`α ⧸ s` is the quotient type representing the left cosets of `s`. If `s` is a normal + subgroup, `α ⧸ s` is a group"] +instance instHasQuotientSubgroup : HasQuotient α (Subgroup α) := + ⟨fun s => Quotient (leftRel s)⟩ + +/-- The equivalence relation corresponding to the partition of a group by right cosets of a +subgroup. -/ +@[to_additive "The equivalence relation corresponding to the partition of a group by right cosets + of a subgroup."] +def rightRel : Setoid α := + MulAction.orbitRel s α + +variable {s} + +@[to_additive] +theorem rightRel_apply {x y : α} : rightRel s x y ↔ y * x⁻¹ ∈ s := + calc + (∃ a : s, (a : α) * y = x) ↔ ∃ a : s, y * x⁻¹ = a⁻¹ := by + simp only [mul_inv_eq_iff_eq_mul, Subgroup.coe_inv, eq_inv_mul_iff_mul_eq] + _ ↔ y * x⁻¹ ∈ s := by simp [exists_inv_mem_iff_exists_mem] + +variable (s) + +@[to_additive] +theorem rightRel_eq : ⇑(rightRel s) = fun x y => y * x⁻¹ ∈ s := + funext₂ <| by + simp only [eq_iff_iff] + apply rightRel_apply + +@[to_additive] +instance rightRelDecidable [DecidablePred (· ∈ s)] : DecidableRel (rightRel s).r := fun x y => by + rw [rightRel_eq] + exact ‹DecidablePred (· ∈ s)› _ + +/-- Right cosets are in bijection with left cosets. -/ +@[to_additive "Right cosets are in bijection with left cosets."] +def quotientRightRelEquivQuotientLeftRel : Quotient (QuotientGroup.rightRel s) ≃ α ⧸ s where + toFun := + Quotient.map' (fun g => g⁻¹) fun a b => by + rw [leftRel_apply, rightRel_apply] + exact fun h => (congr_arg (· ∈ s) (by simp [mul_assoc])).mp (s.inv_mem h) + -- Porting note: replace with `by group` + invFun := + Quotient.map' (fun g => g⁻¹) fun a b => by + rw [leftRel_apply, rightRel_apply] + exact fun h => (congr_arg (· ∈ s) (by simp [mul_assoc])).mp (s.inv_mem h) + -- Porting note: replace with `by group` + left_inv g := + Quotient.inductionOn' g fun g => + Quotient.sound' + (by + simp only [inv_inv] + exact Quotient.exact' rfl) + right_inv g := + Quotient.inductionOn' g fun g => + Quotient.sound' + (by + simp only [inv_inv] + exact Quotient.exact' rfl) + +end QuotientGroup + +namespace QuotientGroup + +variable [Group α] {s : Subgroup α} + +/-- The canonical map from a group `α` to the quotient `α ⧸ s`. -/ +@[to_additive (attr := coe) "The canonical map from an `AddGroup` `α` to the quotient `α ⧸ s`."] +abbrev mk (a : α) : α ⧸ s := + Quotient.mk'' a + +@[to_additive] +theorem mk_surjective : Function.Surjective <| @mk _ _ s := + Quotient.surjective_Quotient_mk'' + +@[to_additive (attr := simp)] +lemma range_mk : range (QuotientGroup.mk (s := s)) = univ := range_iff_surjective.mpr mk_surjective + +@[to_additive (attr := elab_as_elim)] +theorem induction_on {C : α ⧸ s → Prop} (x : α ⧸ s) (H : ∀ z, C (QuotientGroup.mk z)) : C x := + Quotient.inductionOn' x H + +@[to_additive] +instance : Coe α (α ⧸ s) := + ⟨mk⟩ + +@[to_additive (attr := deprecated (since := "2024-08-04"))] alias induction_on' := induction_on + +@[to_additive (attr := simp)] +theorem quotient_liftOn_mk {β} (f : α → β) (h) (x : α) : Quotient.liftOn' (x : α ⧸ s) f h = f x := + rfl + +@[to_additive] +theorem forall_mk {C : α ⧸ s → Prop} : (∀ x : α ⧸ s, C x) ↔ ∀ x : α, C x := + mk_surjective.forall + +@[to_additive] +theorem exists_mk {C : α ⧸ s → Prop} : (∃ x : α ⧸ s, C x) ↔ ∃ x : α, C x := + mk_surjective.exists + +@[to_additive] +instance (s : Subgroup α) : Inhabited (α ⧸ s) := + ⟨((1 : α) : α ⧸ s)⟩ + +@[to_additive] +protected theorem eq {a b : α} : (a : α ⧸ s) = b ↔ a⁻¹ * b ∈ s := + calc + _ ↔ leftRel s a b := Quotient.eq'' + _ ↔ _ := by rw [leftRel_apply] + +@[to_additive (attr := deprecated (since := "2024-08-04"))] alias eq' := QuotientGroup.eq + +@[to_additive] +theorem out_eq' (a : α ⧸ s) : mk a.out' = a := + Quotient.out_eq' a + +variable (s) + +/- It can be useful to write `obtain ⟨h, H⟩ := mk_out'_eq_mul ...`, and then `rw [H]` or + `simp_rw [H]` or `simp only [H]`. In order for `simp_rw` and `simp only` to work, this lemma is + stated in terms of an arbitrary `h : s`, rather than the specific `h = g⁻¹ * (mk g).out'`. -/ +@[to_additive QuotientAddGroup.mk_out'_eq_mul] +theorem mk_out'_eq_mul (g : α) : ∃ h : s, (mk g : α ⧸ s).out' = g * h := + ⟨⟨g⁻¹ * (mk g).out', QuotientGroup.eq.mp (mk g).out_eq'.symm⟩, by rw [mul_inv_cancel_left]⟩ + +variable {s} {a b : α} + +@[to_additive (attr := simp)] +theorem mk_mul_of_mem (a : α) (hb : b ∈ s) : (mk (a * b) : α ⧸ s) = mk a := by + rwa [QuotientGroup.eq, mul_inv_rev, inv_mul_cancel_right, s.inv_mem_iff] + +@[to_additive] +theorem preimage_image_mk (N : Subgroup α) (s : Set α) : + mk ⁻¹' ((mk : α → α ⧸ N) '' s) = ⋃ x : N, (· * (x : α)) ⁻¹' s := by + ext x + simp only [QuotientGroup.eq, SetLike.exists, exists_prop, Set.mem_preimage, Set.mem_iUnion, + Set.mem_image, ← eq_inv_mul_iff_mul_eq] + exact + ⟨fun ⟨y, hs, hN⟩ => ⟨_, N.inv_mem hN, by simpa using hs⟩, fun ⟨z, hz, hxz⟩ => + ⟨x * z, hxz, by simpa using hz⟩⟩ + +@[to_additive] +theorem preimage_image_mk_eq_iUnion_image (N : Subgroup α) (s : Set α) : + mk ⁻¹' ((mk : α → α ⧸ N) '' s) = ⋃ x : N, (· * (x : α)) '' s := by + rw [preimage_image_mk, iUnion_congr_of_surjective (·⁻¹) inv_surjective] + exact fun x ↦ image_mul_right' + +@[to_additive] +theorem preimage_image_mk_eq_mul (N : Subgroup α) (s : Set α) : + mk ⁻¹' ((mk : α → α ⧸ N) '' s) = s * N := by + rw [preimage_image_mk_eq_iUnion_image, iUnion_subtype, ← image2_mul, ← iUnion_image_right] + simp only [SetLike.mem_coe] + +end QuotientGroup + +namespace Subgroup + +open QuotientGroup + +variable [Group α] {s : Subgroup α} + +variable {t : Subgroup α} + +/-- If two subgroups `M` and `N` of `G` are equal, their quotients are in bijection. -/ +@[to_additive "If two subgroups `M` and `N` of `G` are equal, their quotients are in bijection."] +def quotientEquivOfEq (h : s = t) : α ⧸ s ≃ α ⧸ t where + toFun := Quotient.map' id fun _a _b h' => h ▸ h' + invFun := Quotient.map' id fun _a _b h' => h.symm ▸ h' + left_inv q := induction_on q fun _g => rfl + right_inv q := induction_on q fun _g => rfl + +theorem quotientEquivOfEq_mk (h : s = t) (a : α) : + quotientEquivOfEq h (QuotientGroup.mk a) = QuotientGroup.mk a := + rfl + +end Subgroup diff --git a/Mathlib/GroupTheory/CosetCover.lean b/Mathlib/GroupTheory/CosetCover.lean index c9cefdcb06558..155e9fd467601 100644 --- a/Mathlib/GroupTheory/CosetCover.lean +++ b/Mathlib/GroupTheory/CosetCover.lean @@ -42,7 +42,7 @@ set of all minimal polynomials (not proved here). -/ -open scoped Pointwise BigOperators +open scoped Pointwise namespace Subgroup @@ -343,7 +343,7 @@ theorem exists_index_le_card_of_leftCoset_cover : | inl hindex => rwa [hindex, Nat.cast_zero, inv_zero, inv_pos, Nat.cast_pos] | inr hindex => - exact inv_lt_inv_of_lt (by exact_mod_cast hs') (by exact_mod_cast h i hi ⟨hindex⟩) + exact inv_strictAnti₀ (by exact_mod_cast hs') (by exact_mod_cast h i hi ⟨hindex⟩) apply (Finset.sum_lt_sum_of_nonempty hs hlt).trans_eq rw [Finset.sum_const, nsmul_eq_mul, mul_inv_cancel₀ (Nat.cast_ne_zero.mpr hs'.ne')] @@ -366,7 +366,7 @@ end Submodule section Subspace -variable {k E ι : Type*} [DivisionRing k] [Infinite k] [AddCommGroup E] [Module k E] +variable {k E : Type*} [DivisionRing k] [Infinite k] [AddCommGroup E] [Module k E] {s : Finset (Subspace k E)} /- A vector space over an infinite field cannot be a finite union of proper subspaces. -/ diff --git a/Mathlib/GroupTheory/Coxeter/Basic.lean b/Mathlib/GroupTheory/Coxeter/Basic.lean index fd14569331ee8..0d9a5d61d777b 100644 --- a/Mathlib/GroupTheory/Coxeter/Basic.lean +++ b/Mathlib/GroupTheory/Coxeter/Basic.lean @@ -3,12 +3,13 @@ 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 -/ +import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Ring.Int -import Mathlib.GroupTheory.PresentedGroup import Mathlib.GroupTheory.Coxeter.Matrix +import Mathlib.GroupTheory.PresentedGroup +import Mathlib.Tactic.NormNum.DivMod import Mathlib.Tactic.Ring import Mathlib.Tactic.Use -import Mathlib.Tactic.NormNum.DivMod /-! # Coxeter groups and Coxeter systems @@ -249,7 +250,8 @@ preserved under multiplication, then it holds for all elements of `W`. -/ theorem simple_induction {p : W → Prop} (w : W) (simple : ∀ i : B, p (s i)) (one : p 1) (mul : ∀ w w' : W, p w → p w' → p (w * w')) : p w := by have := cs.submonoid_closure_range_simple.symm ▸ Submonoid.mem_top w - exact Submonoid.closure_induction this (fun x ⟨i, hi⟩ ↦ hi ▸ simple i) one mul + exact Submonoid.closure_induction (fun x ⟨i, hi⟩ ↦ hi ▸ simple i) one (fun _ _ _ _ ↦ mul _ _) + this /-- If `p : W → Prop` holds for the identity and it is preserved under multiplying on the left by a simple reflection, then it holds for all elements of `W`. -/ diff --git a/Mathlib/GroupTheory/Divisible.lean b/Mathlib/GroupTheory/Divisible.lean index 4276c6c3fd8b1..99ead5b297aa7 100644 --- a/Mathlib/GroupTheory/Divisible.lean +++ b/Mathlib/GroupTheory/Divisible.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ import Mathlib.Algebra.Group.ULift -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Algebra.Group.Subgroup.Pointwise +import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.Tactic.NormNum.Eq /-! @@ -173,7 +174,7 @@ noncomputable def divisibleByIntOfSMulTopEqTop (H : ∀ {n : ℤ} (_hn : n ≠ 0), n • (⊤ : AddSubgroup A) = ⊤) : DivisibleBy A ℤ where div a n := if hn : n = 0 then 0 else (show a ∈ n • (⊤ : AddSubgroup A) by rw [H hn]; trivial).choose - div_zero a := dif_pos rfl + div_zero _ := dif_pos rfl div_cancel a hn := by simp_rw [dif_neg hn] generalize_proofs h1 diff --git a/Mathlib/GroupTheory/DoubleCoset.lean b/Mathlib/GroupTheory/DoubleCoset.lean index 771be71a00bb9..d80688cff9e27 100644 --- a/Mathlib/GroupTheory/DoubleCoset.lean +++ b/Mathlib/GroupTheory/DoubleCoset.lean @@ -22,7 +22,7 @@ this is the usual left or right quotient of a group by a subgroup. -- Porting note: removed import -- import Mathlib.Tactic.Group -variable {G : Type*} [Group G] {α : Type*} [Mul α] (J : Subgroup G) (g : G) +variable {G : Type*} [Group G] {α : Type*} [Mul α] open MulOpposite open scoped Pointwise @@ -72,15 +72,15 @@ def Quotient (H K : Set G) : Type _ := _root_.Quotient (setoid H K) theorem rel_iff {H K : Subgroup G} {x y : G} : - (setoid ↑H ↑K).Rel x y ↔ ∃ a ∈ H, ∃ b ∈ K, y = a * x * b := + setoid ↑H ↑K x y ↔ ∃ a ∈ H, ∃ b ∈ K, y = a * x * b := Iff.trans ⟨fun (hxy : doset x H K = doset y H K) => hxy ▸ mem_doset_self H K y, fun hxy => (doset_eq_of_mem hxy).symm⟩ mem_doset theorem bot_rel_eq_leftRel (H : Subgroup G) : - (setoid ↑(⊥ : Subgroup G) ↑H).Rel = (QuotientGroup.leftRel H).Rel := by + ⇑(setoid ↑(⊥ : Subgroup G) ↑H) = ⇑(QuotientGroup.leftRel H) := by ext a b - rw [rel_iff, Setoid.Rel, QuotientGroup.leftRel_apply] + rw [rel_iff, QuotientGroup.leftRel_apply] constructor · rintro ⟨a, rfl : a = 1, b, hb, rfl⟩ change a⁻¹ * (1 * a * b) ∈ H @@ -89,9 +89,9 @@ theorem bot_rel_eq_leftRel (H : Subgroup G) : exact ⟨1, rfl, a⁻¹ * b, h, by rw [one_mul, mul_inv_cancel_left]⟩ theorem rel_bot_eq_right_group_rel (H : Subgroup G) : - (setoid ↑H ↑(⊥ : Subgroup G)).Rel = (QuotientGroup.rightRel H).Rel := by + ⇑(setoid ↑H ↑(⊥ : Subgroup G)) = ⇑(QuotientGroup.rightRel H) := by ext a b - rw [rel_iff, Setoid.Rel, QuotientGroup.rightRel_apply] + rw [rel_iff, QuotientGroup.rightRel_apply] constructor · rintro ⟨b, hb, a, rfl : a = 1, rfl⟩ change b * a * 1 * a⁻¹ ∈ H diff --git a/Mathlib/GroupTheory/Finiteness.lean b/Mathlib/GroupTheory/Finiteness.lean index 6d7da785053a0..88f64c318c38f 100644 --- a/Mathlib/GroupTheory/Finiteness.lean +++ b/Mathlib/GroupTheory/Finiteness.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ +import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Data.Set.Pointwise.Finite -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.SetTheory.Cardinal.Finite /-! diff --git a/Mathlib/GroupTheory/FreeAbelianGroup.lean b/Mathlib/GroupTheory/FreeAbelianGroup.lean index 2fc7ca86f0f66..163b552783eb7 100644 --- a/Mathlib/GroupTheory/FreeAbelianGroup.lean +++ b/Mathlib/GroupTheory/FreeAbelianGroup.lean @@ -87,7 +87,7 @@ namespace FreeAbelianGroup /-- The canonical map from `α` to `FreeAbelianGroup α`. -/ def of (x : α) : FreeAbelianGroup α := - Abelianization.of <| FreeGroup.of x + Additive.ofMul <| Abelianization.of <| FreeGroup.of x /-- The map `FreeAbelianGroup α →+ A` induced by a map of types `α → A`. -/ def lift {β : Type v} [AddCommGroup β] : (α → β) ≃ (FreeAbelianGroup α →+ β) := @@ -138,6 +138,20 @@ theorem of_injective : Function.Injective (of : α → FreeAbelianGroup α) := have hfy0 : f (of y) = 0 := (lift.of _ _).trans <| if_neg hxy one_ne_zero <| hfy1.symm.trans hfy0 +@[simp] +theorem of_ne_zero (x : α) : of x ≠ 0 := by + intro h + let f : FreeAbelianGroup α →+ ℤ := lift 1 + have hfx : f (of x) = 1 := lift.of _ _ + have hf0 : f (of x) = 0 := by rw [h, map_zero] + exact one_ne_zero <| hfx.symm.trans hf0 + +@[simp] +theorem zero_ne_of (x : α) : 0 ≠ of x := of_ne_zero _ |>.symm + +instance [Nonempty α] : Nontrivial (FreeAbelianGroup α) where + exists_pair_ne := let ⟨x⟩ := ‹Nonempty α›; ⟨0, of x, zero_ne_of _⟩ + end attribute [local instance] QuotientGroup.leftRel @@ -211,7 +225,6 @@ protected theorem map_sub (f : α → β) (x y : FreeAbelianGroup α) : theorem map_of (f : α → β) (y : α) : f <$> of y = of (f y) := rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem pure_bind (f : α → FreeAbelianGroup β) (x) : pure x >>= f = f x := lift.of _ _ @@ -375,7 +388,7 @@ theorem of_mul (x y : α) : of (x * y) = of x * of y := instance distrib : Distrib (FreeAbelianGroup α) := { FreeAbelianGroup.mul α, FreeAbelianGroup.addCommGroup α with - left_distrib := fun x y z ↦ (lift _).map_add _ _ + left_distrib := fun _ _ _ ↦ (lift _).map_add _ _ right_distrib := fun x y z ↦ by simp only [(· * ·), Mul.mul, map_add, ← Pi.add_def, lift.add'] } instance nonUnitalNonAssocRing : NonUnitalNonAssocRing (FreeAbelianGroup α) := @@ -419,7 +432,7 @@ instance ring : Ring (FreeAbelianGroup α) := dsimp only [(· * ·), Mul.mul, OfNat.ofNat, One.one] rw [lift.of] refine FreeAbelianGroup.induction_on x rfl (fun L ↦ ?_) (fun L ih ↦ ?_) fun x1 x2 ih1 ih2 ↦ ?_ - · erw [lift.of] + · rw [lift.of] congr 1 exact mul_one L · rw [map_neg, ih] diff --git a/Mathlib/GroupTheory/FreeGroup/Basic.lean b/Mathlib/GroupTheory/FreeGroup/Basic.lean index 4dfea2fbf13f6..4049097ce77cb 100644 --- a/Mathlib/GroupTheory/FreeGroup/Basic.lean +++ b/Mathlib/GroupTheory/FreeGroup/Basic.lean @@ -6,7 +6,6 @@ Authors: Kenny Lau import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.Data.Fintype.Basic import Mathlib.Data.List.Sublists -import Mathlib.Data.List.InsertNth /-! # Free groups @@ -195,10 +194,10 @@ respectively. This is also known as Newman's diamond lemma. -/ to `w2` and `w3` respectively, then there is a word `w4` such that `w2` and `w3` reduce to `w4` respectively. This is also known as Newman's diamond lemma."] theorem church_rosser : Red L₁ L₂ → Red L₁ L₃ → Join Red L₂ L₃ := - Relation.church_rosser fun a b c hab hac => + Relation.church_rosser fun _ b c hab hac => match b, c, Red.Step.diamond hab hac rfl with | b, _, Or.inl rfl => ⟨b, by rfl, by rfl⟩ - | b, c, Or.inr ⟨d, hbd, hcd⟩ => ⟨d, ReflGen.single hbd, hcd.to_red⟩ + | _, _, Or.inr ⟨d, hbd, hcd⟩ => ⟨d, ReflGen.single hbd, hcd.to_red⟩ @[to_additive] theorem cons_cons {p} : Red L₁ L₂ → Red (p :: L₁) (p :: L₂) := @@ -252,7 +251,7 @@ theorem to_append_iff : Red L (L₁ ++ L₂) ↔ ∃ L₃ L₄, L = L₃ ++ L₄ by simp rcases ih this with ⟨w₁, w₂, rfl, h₁, h₂⟩ exact ⟨w₁, w₂, rfl, h₁.tail Step.not, h₂⟩) - fun ⟨L₃, L₄, Eq, h₃, h₄⟩ => Eq.symm ▸ append_append h₃ h₄ + fun ⟨_, _, Eq, h₃, h₄⟩ => Eq.symm ▸ append_append h₃ h₄ /-- The empty word `[]` only reduces to itself. -/ @[to_additive "The empty word `[]` only reduces to itself."] @@ -369,10 +368,10 @@ end Red @[to_additive FreeAddGroup.equivalence_join_red] theorem equivalence_join_red : Equivalence (Join (@Red α)) := - equivalence_join_reflTransGen fun a b c hab hac => + equivalence_join_reflTransGen fun _ b c hab hac => match b, c, Red.Step.diamond hab hac rfl with | b, _, Or.inl rfl => ⟨b, by rfl, by rfl⟩ - | b, c, Or.inr ⟨d, hbd, hcd⟩ => ⟨d, ReflGen.single hbd, ReflTransGen.single hcd⟩ + | _, _, Or.inr ⟨d, hbd, hcd⟩ => ⟨d, ReflGen.single hbd, ReflTransGen.single hcd⟩ @[to_additive FreeAddGroup.join_red_of_step] theorem join_red_of_step (h : Red.Step L₁ L₂) : Join Red L₁ L₂ := @@ -529,6 +528,12 @@ instance : Group (FreeGroup α) where List.recOn L rfl fun ⟨x, b⟩ tl ih => Eq.trans (Quot.sound <| by simp [invRev, one_eq_mk]) ih +@[to_additive (attr := simp)] +theorem pow_mk (n : ℕ) : mk L ^ n = mk (List.join <| List.replicate n L) := + match n with + | 0 => rfl + | n + 1 => by rw [pow_succ', pow_mk, mul_mk, List.replicate_succ, List.join_cons] + /-- `of` is the canonical injection from the type to the free group over that type by sending each element to the equivalence class of the letter that is the element. -/ @[to_additive "`of` is the canonical injection from the type to the free group over that type @@ -569,7 +574,7 @@ from the free group over `α` to `β` -/ additive group homomorphism from the free additive group over `α` to `β`"] def lift : (α → β) ≃ (FreeGroup α →* β) where toFun f := - MonoidHom.mk' (Quot.lift (Lift.aux f) fun L₁ L₂ => Red.Step.lift) <| by + MonoidHom.mk' (Quot.lift (Lift.aux f) fun _ _ => Red.Step.lift) <| by rintro ⟨L₁⟩ ⟨L₂⟩; simp [Lift.aux] invFun g := g ∘ of left_inv f := List.prod_singleton @@ -839,7 +844,6 @@ protected theorem induction_on {C : FreeGroup α → Prop} (z : FreeGroup α) (C Quot.inductionOn z fun L => List.recOn L C1 fun ⟨x, b⟩ _tl ih => Bool.recOn b (Cm _ _ (Ci _ <| Cp x) ih) (Cm _ _ (Cp x) ih) --- porting note (#10618): simp can prove this: by simp only [@map_pure] @[to_additive] theorem map_pure (f : α → β) (x : α) : f <$> (pure x : FreeGroup α) = pure (f x) := map.of @@ -856,7 +860,6 @@ theorem map_mul (f : α → β) (x y : FreeGroup α) : f <$> (x * y) = f <$> x * theorem map_inv (f : α → β) (x : FreeGroup α) : f <$> x⁻¹ = (f <$> x)⁻¹ := (map f).map_inv x --- porting note (#10618): simp can prove this: by simp only [@pure_bind] @[to_additive] theorem pure_bind (f : α → FreeGroup β) (x) : pure x >>= f = f x := lift.of @@ -911,6 +914,17 @@ theorem reduce.cons (x) : if x.1 = hd.1 ∧ x.2 = not hd.2 then tl else x :: hd :: tl := rfl +@[to_additive (attr := simp)] +theorem reduce_replicate (n : ℕ) (x : α × Bool) : + reduce (.replicate n x) = .replicate n x := by + induction n with + | zero => simp [reduce] + | succ n ih => + rw [List.replicate_succ, reduce.cons, ih] + cases n with + | zero => simp + | succ n => simp [List.replicate_succ] + /-- The first theorem that characterises the function `reduce`: a word reduces to its maximal reduction. -/ @[to_additive "The first theorem that characterises the function `reduce`: a word reduces to its @@ -1056,6 +1070,10 @@ theorem toWord_inj {x y : FreeGroup α} : toWord x = toWord y ↔ x = y := theorem toWord_mk : (mk L₁).toWord = reduce L₁ := rfl +@[to_additive (attr := simp)] +theorem toWord_of (a : α) : (of a).toWord = [(a, true)] := + rfl + @[to_additive (attr := simp)] theorem reduce_toWord : ∀ x : FreeGroup α, reduce (toWord x) = toWord x := by rintro ⟨L⟩ @@ -1065,6 +1083,11 @@ theorem reduce_toWord : ∀ x : FreeGroup α, reduce (toWord x) = toWord x := by theorem toWord_one : (1 : FreeGroup α).toWord = [] := rfl +@[to_additive (attr := simp)] +theorem toWord_of_pow (a : α) (n : ℕ) : (of a ^ n).toWord = List.replicate n (a, true) := by + rw [of, pow_mk, List.join_replicate_singleton, toWord] + exact reduce_replicate _ _ + @[to_additive (attr := simp)] theorem toWord_eq_nil_iff {x : FreeGroup α} : x.toWord = [] ↔ x = 1 := toWord_injective.eq_iff' toWord_one @@ -1126,6 +1149,17 @@ instance : Fintype { L₂ // Red L₁ L₂ } := end Reduce +@[to_additive (attr := simp)] +theorem one_ne_of (a : α) : 1 ≠ of a := + letI := Classical.decEq α; ne_of_apply_ne toWord <| by simp + +@[to_additive (attr := simp)] +theorem of_ne_one (a : α) : of a ≠ 1 := one_ne_of _ |>.symm + +@[to_additive] +instance [Nonempty α] : Nontrivial (FreeGroup α) where + exists_pair_ne := let ⟨x⟩ := ‹Nonempty α›; ⟨1, of x, one_ne_of x⟩ + section Metric variable [DecidableEq α] @@ -1147,6 +1181,10 @@ theorem norm_eq_zero {x : FreeGroup α} : norm x = 0 ↔ x = 1 := by theorem norm_one : norm (1 : FreeGroup α) = 0 := rfl +@[to_additive (attr := simp)] +theorem norm_of (a : α) : norm (of a) = 1 := + rfl + @[to_additive] theorem norm_mk_le : norm (mk L₁) ≤ L₁.length := reduce.red.length_le @@ -1158,6 +1196,15 @@ theorem norm_mul_le (x y : FreeGroup α) : norm (x * y) ≤ norm x + norm y := _ ≤ (x.toWord ++ y.toWord).length := norm_mk_le _ = norm x + norm y := List.length_append _ _ +@[to_additive (attr := simp)] +theorem norm_of_pow (a : α) (n : ℕ) : norm (of a ^ n) = n := by + rw [norm, toWord_of_pow, List.length_replicate] + +@[to_additive] +theorem norm_surjective [Nonempty α] : Function.Surjective (norm (α := α)) := by + let ⟨a⟩ := ‹Nonempty α› + exact Function.RightInverse.surjective <| norm_of_pow a + end Metric end FreeGroup diff --git a/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean b/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean index 5999f4a20b721..e3a6f25954b2b 100644 --- a/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean +++ b/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean @@ -214,7 +214,7 @@ group extends in a unique way to a homomorphism from `G`. Note that since `IsFreeGroup.lift` is expressed as a bijection, it already expresses the universal property. -/ theorem unique_lift (f : Generators G → H) : ∃! F : G →* H, ∀ a, F (of a) = f a := by - simpa only [Function.funext_iff] using lift.symm.bijective.existsUnique f + simpa only [funext_iff] using lift.symm.bijective.existsUnique f /-- If a group satisfies the universal property of a free group with respect to a given type, then it is free. Here, the universal property is expressed as in `IsFreeGroup.lift` and its diff --git a/Mathlib/GroupTheory/FreeGroup/NielsenSchreier.lean b/Mathlib/GroupTheory/FreeGroup/NielsenSchreier.lean index 9ce47f7942f61..61c97a1f0113b 100644 --- a/Mathlib/GroupTheory/FreeGroup/NielsenSchreier.lean +++ b/Mathlib/GroupTheory/FreeGroup/NielsenSchreier.lean @@ -96,6 +96,13 @@ theorem ext_functor {G} [Groupoid.{v} G] [IsFreeGroupoid G] {X : Type v} [Group let ⟨_, _, u⟩ := @unique_lift G _ _ X _ fun (a b : Generators G) (e : a ⟶ b) => g.map (of e) _root_.trans (u _ h) (u _ fun _ _ _ => rfl).symm +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `{ e // _ }`. +-/ +set_option linter.unusedVariables false in /-- An action groupoid over a free group is free. More generally, one could show that the groupoid of elements over a free groupoid is free, but this version is easier to prove and suffices for our purposes. @@ -106,7 +113,7 @@ instance actionGroupoidIsFree {G A : Type u} [Group G] [IsFreeGroup G] [MulActio IsFreeGroupoid (ActionCategory G A) where quiverGenerators := ⟨fun a b => { e : IsFreeGroup.Generators G // IsFreeGroup.of e • a.back = b.back }⟩ - of := fun (e : { e // _}) => ⟨IsFreeGroup.of e, e.property⟩ + of := fun (e : { e // _ }) => ⟨IsFreeGroup.of e, e.property⟩ unique_lift := by intro X _ f let f' : IsFreeGroup.Generators G → (A → X) ⋊[mulAutArrow] G := fun e => @@ -114,7 +121,6 @@ instance actionGroupoidIsFree {G A : Type u} [Group G] [IsFreeGroup G] [MulActio rcases IsFreeGroup.unique_lift f' with ⟨F', hF', uF'⟩ refine ⟨uncurry F' ?_, ?_, ?_⟩ · suffices SemidirectProduct.rightHom.comp F' = MonoidHom.id _ by - -- Porting note: `MonoidHom.ext_iff` has been deprecated. exact DFunLike.ext_iff.mp this apply IsFreeGroup.ext_hom (fun x ↦ ?_) rw [MonoidHom.comp_apply, hF'] diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index cc847556ec7f8..eeb44d323690a 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -4,11 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Algebra.Group.Subgroup.Basic -import Mathlib.Algebra.GroupWithZero.Action.Defs -import Mathlib.Data.Fintype.Card import Mathlib.Data.Set.Finite import Mathlib.Data.Set.Pointwise.SMul -import Mathlib.Data.Setoid.Basic +import Mathlib.GroupTheory.GroupAction.Defs /-! # Basic properties of group actions @@ -39,62 +37,7 @@ variable (M : Type u) [Monoid M] (α : Type v) [MulAction M α] {β : Type*} [Mu section Orbit -variable {α} - -/-- The orbit of an element under an action. -/ -@[to_additive "The orbit of an element under an action."] -def orbit (a : α) := - Set.range fun m : M => m • a - -variable {M} - -@[to_additive] -theorem mem_orbit_iff {a₁ a₂ : α} : a₂ ∈ orbit M a₁ ↔ ∃ x : M, x • a₁ = a₂ := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_orbit (a : α) (m : M) : m • a ∈ orbit M a := - ⟨m, rfl⟩ - -@[to_additive (attr := simp)] -theorem mem_orbit_self (a : α) : a ∈ orbit M a := - ⟨1, by simp [MulAction.one_smul]⟩ - -@[to_additive] -theorem orbit_nonempty (a : α) : Set.Nonempty (orbit M a) := - Set.range_nonempty _ - -@[to_additive] -theorem mapsTo_smul_orbit (m : M) (a : α) : Set.MapsTo (m • ·) (orbit M a) (orbit M a) := - Set.range_subset_iff.2 fun m' => ⟨m * m', mul_smul _ _ _⟩ - -@[to_additive] -theorem smul_orbit_subset (m : M) (a : α) : m • orbit M a ⊆ orbit M a := - (mapsTo_smul_orbit m a).image_subset - -@[to_additive] -theorem orbit_smul_subset (m : M) (a : α) : orbit M (m • a) ⊆ orbit M a := - Set.range_subset_iff.2 fun m' => mul_smul m' m a ▸ mem_orbit _ _ - -@[to_additive] -instance {a : α} : MulAction M (orbit M a) where - smul m := (mapsTo_smul_orbit m a).restrict _ _ _ - one_smul m := Subtype.ext (one_smul M (m : α)) - mul_smul m m' a' := Subtype.ext (mul_smul m m' (a' : α)) - -@[to_additive (attr := simp)] -theorem orbit.coe_smul {a : α} {m : M} {a' : orbit M a} : ↑(m • a') = m • (a' : α) := - rfl - -@[to_additive] -lemma orbit_submonoid_subset (S : Submonoid M) (a : α) : orbit S a ⊆ orbit M a := by - rintro b ⟨g, rfl⟩ - exact mem_orbit _ _ - -@[to_additive] -lemma mem_orbit_of_mem_orbit_submonoid {S : Submonoid M} {a b : α} (h : a ∈ orbit S b) : - a ∈ orbit M b := - orbit_submonoid_subset S _ h +variable {α M} @[to_additive] lemma fst_mem_orbit_of_mem_orbit {x y : α × β} (h : x ∈ MulAction.orbit M y) : @@ -108,6 +51,10 @@ lemma snd_mem_orbit_of_mem_orbit {x y : α × β} (h : x ∈ MulAction.orbit M y rcases h with ⟨g, rfl⟩ exact mem_orbit _ _ +@[to_additive] +lemma _root_.Finite.finite_mulAction_orbit [Finite M] (a : α) : Set.Finite (orbit M a) := + Set.finite_range _ + variable (M) @[to_additive] @@ -118,42 +65,8 @@ end Orbit section FixedPoints -/-- The set of elements fixed under the whole action. -/ -@[to_additive "The set of elements fixed under the whole action."] -def fixedPoints : Set α := - { a : α | ∀ m : M, m • a = a } - -variable {M} - -/-- `fixedBy m` is the set of elements fixed by `m`. -/ -@[to_additive "`fixedBy m` is the set of elements fixed by `m`."] -def fixedBy (m : M) : Set α := - { x | m • x = x } - -variable (M) - -@[to_additive] -theorem fixed_eq_iInter_fixedBy : fixedPoints M α = ⋂ m : M, fixedBy α m := - Set.ext fun _ => - ⟨fun hx => Set.mem_iInter.2 fun m => hx m, fun hx m => (Set.mem_iInter.1 hx m : _)⟩ - variable {M α} -@[to_additive (attr := simp)] -theorem mem_fixedPoints {a : α} : a ∈ fixedPoints M α ↔ ∀ m : M, m • a = a := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_fixedBy {m : M} {a : α} : a ∈ fixedBy α m ↔ m • a = a := - Iff.rfl - -@[to_additive] -theorem mem_fixedPoints' {a : α} : a ∈ fixedPoints M α ↔ ∀ a', a' ∈ orbit M a → a' = a := - ⟨fun h _ h₁ => - let ⟨m, hm⟩ := mem_orbit_iff.1 h₁ - hm ▸ h m, - fun h _ => h _ (mem_orbit _ _)⟩ - @[to_additive mem_fixedPoints_iff_card_orbit_eq_one] theorem mem_fixedPoints_iff_card_orbit_eq_one {a : α} [Fintype (orbit M a)] : a ∈ fixedPoints M α ↔ Fintype.card (orbit M a) = 1 := by @@ -168,115 +81,8 @@ theorem mem_fixedPoints_iff_card_orbit_eq_one {a : α} [Fintype (orbit M a)] : end FixedPoints -section Stabilizers - -variable {α} - -/-- The stabilizer of a point `a` as a submonoid of `M`. -/ -@[to_additive "The stabilizer of a point `a` as an additive submonoid of `M`."] -def stabilizerSubmonoid (a : α) : Submonoid M where - carrier := { m | m • a = a } - one_mem' := one_smul _ a - mul_mem' {m m'} (ha : m • a = a) (hb : m' • a = a) := - show (m * m') • a = a by rw [← smul_smul, hb, ha] - -variable {M} - -@[to_additive] -instance [DecidableEq α] (a : α) : DecidablePred (· ∈ stabilizerSubmonoid M a) := - fun _ => inferInstanceAs <| Decidable (_ = _) - -@[to_additive (attr := simp)] -theorem mem_stabilizerSubmonoid_iff {a : α} {m : M} : m ∈ stabilizerSubmonoid M a ↔ m • a = a := - Iff.rfl - -end Stabilizers - end MulAction -section FixedPoints - -variable (M : Type u) (α : Type v) [Monoid M] - -section Monoid - -variable [Monoid α] [MulDistribMulAction M α] - -/-- The submonoid of elements fixed under the whole action. -/ -def FixedPoints.submonoid : Submonoid α where - carrier := MulAction.fixedPoints M α - one_mem' := smul_one - mul_mem' ha hb _ := by rw [smul_mul', ha, hb] - -@[simp] -lemma FixedPoints.mem_submonoid (a : α) : a ∈ submonoid M α ↔ ∀ m : M, m • a = a := - Iff.rfl - -end Monoid - -section Group -namespace FixedPoints -variable [Group α] [MulDistribMulAction M α] - -/-- The subgroup of elements fixed under the whole action. -/ -def subgroup : Subgroup α where - __ := submonoid M α - inv_mem' ha _ := by rw [smul_inv', ha] - -/-- The notation for `FixedPoints.subgroup`, chosen to resemble `αᴹ`. -/ -scoped notation α "^*" M:51 => FixedPoints.subgroup M α - -@[simp] -lemma mem_subgroup (a : α) : a ∈ α^*M ↔ ∀ m : M, m • a = a := - Iff.rfl - -@[simp] -lemma subgroup_toSubmonoid : (α^*M).toSubmonoid = submonoid M α := - rfl - -end FixedPoints -end Group - -section AddMonoid - -variable [AddMonoid α] [DistribMulAction M α] - -/-- The additive submonoid of elements fixed under the whole action. -/ -def FixedPoints.addSubmonoid : AddSubmonoid α where - carrier := MulAction.fixedPoints M α - zero_mem' := smul_zero - add_mem' ha hb _ := by rw [smul_add, ha, hb] - -@[simp] -lemma FixedPoints.mem_addSubmonoid (a : α) : a ∈ addSubmonoid M α ↔ ∀ m : M, m • a = a := - Iff.rfl - -end AddMonoid - -section AddGroup - -variable [AddGroup α] [DistribMulAction M α] - -/-- The additive subgroup of elements fixed under the whole action. -/ -def FixedPoints.addSubgroup : AddSubgroup α where - __ := addSubmonoid M α - neg_mem' ha _ := by rw [smul_neg, ha] - -/-- The notation for `FixedPoints.addSubgroup`, chosen to resemble `αᴹ`. -/ -notation α "^+" M:51 => FixedPoints.addSubgroup M α - -@[simp] -lemma FixedPoints.mem_addSubgroup (a : α) : a ∈ α^+M ↔ ∀ m : M, m • a = a := - Iff.rfl - -@[simp] -lemma FixedPoints.addSubgroup_toAddSubmonoid : (α^+M).toAddSubmonoid = addSubmonoid M α := - rfl - -end AddGroup - -end FixedPoints - /-- `smul` by a `k : M` over a ring is injective, if `k` is not a zero divisor. The general theory of such `k` is elaborated by `IsSMulRegular`. The typeclass that restricts all terms of `M` to have this property is `NoZeroSMulDivisors`. -/ @@ -292,6 +98,8 @@ variable {G α β : Type*} [Group G] [MulAction G α] [MulAction G β] section Orbit +-- TODO: This proof is redoing a special case of `MulAction.IsInvariantBlock.isBlock`. Can we move +-- this lemma earlier to golf? @[to_additive (attr := simp)] theorem smul_orbit (g : G) (a : α) : g • orbit G a = orbit G a := (smul_orbit_subset g a).antisymm <| @@ -299,13 +107,6 @@ theorem smul_orbit (g : G) (a : α) : g • orbit G a = orbit G a := orbit G a = g • g⁻¹ • orbit G a := (smul_inv_smul _ _).symm _ ⊆ g • orbit G a := Set.image_subset _ (smul_orbit_subset _ _) -@[to_additive (attr := simp)] -theorem orbit_smul (g : G) (a : α) : orbit G (g • a) = orbit G a := - (orbit_smul_subset g a).antisymm <| - calc - orbit G a = orbit G (g⁻¹ • g • a) := by rw [inv_smul_smul] - _ ⊆ orbit G (g • a) := orbit_smul_subset _ _ - /-- The action of a group on an orbit is transitive. -/ @[to_additive "The action of an additive group on an orbit is transitive."] instance (a : α) : IsPretransitive G (orbit G a) := @@ -315,67 +116,6 @@ instance (a : α) : IsPretransitive G (orbit G a) := ext1 simp [mul_smul]⟩ -@[to_additive] -theorem orbit_eq_iff {a b : α} : orbit G a = orbit G b ↔ a ∈ orbit G b := - ⟨fun h => h ▸ mem_orbit_self _, fun ⟨_, hc⟩ => hc ▸ orbit_smul _ _⟩ - -@[to_additive] -theorem mem_orbit_smul (g : G) (a : α) : a ∈ orbit G (g • a) := by - simp only [orbit_smul, mem_orbit_self] - -@[to_additive] -theorem smul_mem_orbit_smul (g h : G) (a : α) : g • a ∈ orbit G (h • a) := by - simp only [orbit_smul, mem_orbit] - -@[to_additive] -instance instMulAction (H : Subgroup G) : MulAction H α := - inferInstanceAs (MulAction H.toSubmonoid α) - -@[to_additive] -lemma orbit_subgroup_subset (H : Subgroup G) (a : α) : orbit H a ⊆ orbit G a := - orbit_submonoid_subset H.toSubmonoid a - -@[to_additive] -lemma mem_orbit_of_mem_orbit_subgroup {H : Subgroup G} {a b : α} (h : a ∈ orbit H b) : - a ∈ orbit G b := - orbit_subgroup_subset H _ h - -@[to_additive] -lemma mem_orbit_symm {a₁ a₂ : α} : a₁ ∈ orbit G a₂ ↔ a₂ ∈ orbit G a₁ := by - simp_rw [← orbit_eq_iff, eq_comm] - -@[to_additive] -lemma mem_subgroup_orbit_iff {H : Subgroup G} {x : α} {a b : orbit G x} : - a ∈ MulAction.orbit H b ↔ (a : α) ∈ MulAction.orbit H (b : α) := by - refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · rcases h with ⟨g, rfl⟩ - exact MulAction.mem_orbit _ g - · rcases h with ⟨g, h⟩ - dsimp at h - erw [← orbit.coe_smul, ← Subtype.ext_iff] at h - subst h - exact MulAction.mem_orbit _ g - -variable (G α) - -/-- The relation 'in the same orbit'. -/ -@[to_additive "The relation 'in the same orbit'."] -def orbitRel : Setoid α where - r a b := a ∈ orbit G b - iseqv := - ⟨mem_orbit_self, fun {a b} => by simp [orbit_eq_iff.symm, eq_comm], fun {a b} => by - simp (config := { contextual := true }) [orbit_eq_iff.symm, eq_comm]⟩ - -variable {G α} - -@[to_additive] -theorem orbitRel_apply {a b : α} : (orbitRel G α).Rel a b ↔ a ∈ orbit G b := - Iff.rfl - -@[to_additive] -lemma orbitRel_r_apply {a b : α} : (orbitRel G _).r a b ↔ a ∈ orbit G b := - Iff.rfl - @[to_additive] lemma orbitRel_subgroup_le (H : Subgroup G) : orbitRel H α ≤ orbitRel G α := Setoid.le_def.2 mem_orbit_of_mem_orbit_subgroup @@ -399,61 +139,8 @@ lemma orbitRel_subgroupOf (H K : Subgroup G) : · simp only [Subgroup.mem_subgroupOf] exact gp.1 -/-- When you take a set `U` in `α`, push it down to the quotient, and pull back, you get the union -of the orbit of `U` under `G`. -/ -@[to_additive - "When you take a set `U` in `α`, push it down to the quotient, and pull back, you get the - union of the orbit of `U` under `G`."] -theorem quotient_preimage_image_eq_union_mul (U : Set α) : - letI := orbitRel G α - Quotient.mk' ⁻¹' (Quotient.mk' '' U) = ⋃ g : G, (g • ·) '' U := by - letI := orbitRel G α - set f : α → Quotient (MulAction.orbitRel G α) := Quotient.mk' - ext a - constructor - · rintro ⟨b, hb, hab⟩ - obtain ⟨g, rfl⟩ := Quotient.exact hab - rw [Set.mem_iUnion] - exact ⟨g⁻¹, g • a, hb, inv_smul_smul g a⟩ - · intro hx - rw [Set.mem_iUnion] at hx - obtain ⟨g, u, hu₁, hu₂⟩ := hx - rw [Set.mem_preimage, Set.mem_image] - refine ⟨g⁻¹ • a, ?_, by simp only [f, Quotient.eq']; use g⁻¹⟩ - rw [← hu₂] - convert hu₁ - simp only [inv_smul_smul] - -@[to_additive] -theorem disjoint_image_image_iff {U V : Set α} : - letI := orbitRel G α - Disjoint (Quotient.mk' '' U) (Quotient.mk' '' V) ↔ ∀ x ∈ U, ∀ g : G, g • x ∉ V := by - letI := orbitRel G α - set f : α → Quotient (MulAction.orbitRel G α) := Quotient.mk' - refine - ⟨fun h a a_in_U g g_in_V => - h.le_bot ⟨⟨a, a_in_U, Quotient.sound ⟨g⁻¹, ?_⟩⟩, ⟨g • a, g_in_V, rfl⟩⟩, ?_⟩ - · simp - · intro h - rw [Set.disjoint_left] - rintro _ ⟨b, hb₁, hb₂⟩ ⟨c, hc₁, hc₂⟩ - obtain ⟨g, rfl⟩ := Quotient.exact (hc₂.trans hb₂.symm) - exact h b hb₁ g hc₁ - -@[to_additive] -theorem image_inter_image_iff (U V : Set α) : - letI := orbitRel G α - Quotient.mk' '' U ∩ Quotient.mk' '' V = ∅ ↔ ∀ x ∈ U, ∀ g : G, g • x ∉ V := - Set.disjoint_iff_inter_eq_empty.symm.trans disjoint_image_image_iff - variable (G α) -/-- The quotient by `MulAction.orbitRel`, given a name to enable dot notation. -/ -@[to_additive - "The quotient by `AddAction.orbitRel`, given a name to enable dot notation."] -abbrev orbitRel.Quotient : Type _ := - _root_.Quotient <| orbitRel G α - /-- An action is pretransitive if and only if the quotient by `MulAction.orbitRel` is a subsingleton. -/ @[to_additive "An additive action is pretransitive if and only if the quotient by @@ -464,7 +151,7 @@ theorem pretransitive_iff_subsingleton_quotient : · refine Quot.inductionOn a (fun x ↦ ?_) exact Quot.inductionOn b (fun y ↦ Quot.sound <| exists_smul_eq G y x) · have h : Quotient.mk (orbitRel G α) b = ⟦a⟧ := Subsingleton.elim _ _ - exact Quotient.eq_rel.mp h + exact Quotient.eq''.mp h /-- If `α` is non-empty, an action is pretransitive if and only if the quotient has exactly one element. -/ @@ -477,78 +164,6 @@ theorem pretransitive_iff_unique_quotient_of_nonempty [Nonempty α] : variable {G α} -/-- The orbit corresponding to an element of the quotient by `MulAction.orbitRel` -/ -@[to_additive "The orbit corresponding to an element of the quotient by `AddAction.orbitRel`"] -nonrec def orbitRel.Quotient.orbit (x : orbitRel.Quotient G α) : Set α := - Quotient.liftOn' x (orbit G) fun _ _ => MulAction.orbit_eq_iff.2 - -@[to_additive (attr := simp)] -theorem orbitRel.Quotient.orbit_mk (a : α) : - orbitRel.Quotient.orbit (Quotient.mk'' a : orbitRel.Quotient G α) = MulAction.orbit G a := - rfl - -@[to_additive] -theorem orbitRel.Quotient.mem_orbit {a : α} {x : orbitRel.Quotient G α} : - a ∈ x.orbit ↔ Quotient.mk'' a = x := by - induction x using Quotient.inductionOn' - rw [Quotient.eq''] - rfl - -/-- Note that `hφ = Quotient.out_eq'` is a useful choice here. -/ -@[to_additive "Note that `hφ = Quotient.out_eq'` is a useful choice here."] -theorem orbitRel.Quotient.orbit_eq_orbit_out (x : orbitRel.Quotient G α) - {φ : orbitRel.Quotient G α → α} (hφ : letI := orbitRel G α; RightInverse φ Quotient.mk') : - orbitRel.Quotient.orbit x = MulAction.orbit G (φ x) := by - conv_lhs => rw [← hφ x] - rfl - -@[to_additive] -lemma orbitRel.Quotient.orbit_injective : - Injective (orbitRel.Quotient.orbit : orbitRel.Quotient G α → Set α) := by - intro x y h - simp_rw [orbitRel.Quotient.orbit_eq_orbit_out _ Quotient.out_eq', orbit_eq_iff, - ← orbitRel_r_apply] at h - simpa [← Quotient.eq''] using h - -@[to_additive (attr := simp)] -lemma orbitRel.Quotient.orbit_inj {x y : orbitRel.Quotient G α} : x.orbit = y.orbit ↔ x = y := - orbitRel.Quotient.orbit_injective.eq_iff - -@[to_additive] -lemma orbitRel.quotient_eq_of_quotient_subgroup_eq {H : Subgroup G} {a b : α} - (h : (⟦a⟧ : orbitRel.Quotient H α) = ⟦b⟧) : (⟦a⟧ : orbitRel.Quotient G α) = ⟦b⟧ := by - rw [@Quotient.eq] at h ⊢ - exact mem_orbit_of_mem_orbit_subgroup h - -@[to_additive] -lemma orbitRel.quotient_eq_of_quotient_subgroup_eq' {H : Subgroup G} {a b : α} - (h : (Quotient.mk'' a : orbitRel.Quotient H α) = Quotient.mk'' b) : - (Quotient.mk'' a : orbitRel.Quotient G α) = Quotient.mk'' b := - orbitRel.quotient_eq_of_quotient_subgroup_eq h - -@[to_additive] -nonrec lemma orbitRel.Quotient.orbit_nonempty (x : orbitRel.Quotient G α) : - Set.Nonempty x.orbit := by - rw [orbitRel.Quotient.orbit_eq_orbit_out x Quotient.out_eq'] - exact orbit_nonempty _ - -@[to_additive] -nonrec lemma orbitRel.Quotient.mapsTo_smul_orbit (g : G) (x : orbitRel.Quotient G α) : - Set.MapsTo (g • ·) x.orbit x.orbit := by - rw [orbitRel.Quotient.orbit_eq_orbit_out x Quotient.out_eq'] - exact mapsTo_smul_orbit g x.out' - -@[to_additive] -instance (x : orbitRel.Quotient G α) : MulAction G x.orbit where - smul g := (orbitRel.Quotient.mapsTo_smul_orbit g x).restrict _ _ _ - one_smul a := Subtype.ext (one_smul G (a : α)) - mul_smul g g' a' := Subtype.ext (mul_smul g g' (a' : α)) - -@[to_additive (attr := simp)] -lemma orbitRel.Quotient.orbit.coe_smul {g : G} {x : orbitRel.Quotient G α} {a : x.orbit} : - ↑(g • a) = g • (a : α) := - rfl - @[to_additive] instance (x : orbitRel.Quotient G α) : IsPretransitive G x.orbit where exists_smul_eq := by @@ -561,69 +176,18 @@ instance (x : orbitRel.Quotient G α) : IsPretransitive G x.orbit where ext simp [mul_smul] -@[to_additive (attr := norm_cast, simp)] -lemma orbitRel.Quotient.mem_subgroup_orbit_iff {H : Subgroup G} {x : orbitRel.Quotient G α} - {a b : x.orbit} : (a : α) ∈ MulAction.orbit H (b : α) ↔ a ∈ MulAction.orbit H b := by - refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · rcases h with ⟨g, h⟩ - dsimp at h - erw [← orbit.coe_smul, ← Subtype.ext_iff] at h - subst h - exact MulAction.mem_orbit _ g - · rcases h with ⟨g, rfl⟩ - exact MulAction.mem_orbit _ g - -@[to_additive] -lemma orbitRel.Quotient.subgroup_quotient_eq_iff {H : Subgroup G} {x : orbitRel.Quotient G α} - {a b : x.orbit} : (⟦a⟧ : orbitRel.Quotient H x.orbit) = ⟦b⟧ ↔ - (⟦↑a⟧ : orbitRel.Quotient H α) = ⟦↑b⟧ := by - simp_rw [← @Quotient.mk''_eq_mk, Quotient.eq''] - exact orbitRel.Quotient.mem_subgroup_orbit_iff.symm - -@[to_additive] -lemma orbitRel.Quotient.mem_subgroup_orbit_iff' {H : Subgroup G} {x : orbitRel.Quotient G α} - {a b : x.orbit} {c : α} (h : (⟦a⟧ : orbitRel.Quotient H x.orbit) = ⟦b⟧) : - (a : α) ∈ MulAction.orbit H c ↔ (b : α) ∈ MulAction.orbit H c := by - simp_rw [mem_orbit_symm (a₂ := c)] - convert Iff.rfl using 2 - rw [orbit_eq_iff] - suffices hb : ↑b ∈ orbitRel.Quotient.orbit (⟦a⟧ : orbitRel.Quotient H x.orbit) by - rw [orbitRel.Quotient.orbit_eq_orbit_out (⟦a⟧ : orbitRel.Quotient H x.orbit) Quotient.out_eq'] - at hb - rw [orbitRel.Quotient.mem_subgroup_orbit_iff] - convert hb using 1 - rw [orbit_eq_iff, ← orbitRel_r_apply, ← Quotient.eq'', Quotient.out_eq', @Quotient.mk''_eq_mk] - rw [orbitRel.Quotient.mem_orbit, h, @Quotient.mk''_eq_mk] - variable (G) (α) local notation "Ω" => orbitRel.Quotient G α -/-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. - -This version is expressed in terms of `MulAction.orbitRel.Quotient.orbit` instead of -`MulAction.orbit`, to avoid mentioning `Quotient.out'`. -/ -@[to_additive - "Decomposition of a type `X` as a disjoint union of its orbits under an additive group action. - - This version is expressed in terms of `AddAction.orbitRel.Quotient.orbit` instead of - `AddAction.orbit`, to avoid mentioning `Quotient.out'`. "] -def selfEquivSigmaOrbits' : α ≃ Σω : Ω, ω.orbit := - letI := orbitRel G α - calc - α ≃ Σω : Ω, { a // Quotient.mk' a = ω } := (Equiv.sigmaFiberEquiv Quotient.mk').symm - _ ≃ Σω : Ω, ω.orbit := - Equiv.sigmaCongrRight fun _ => - Equiv.subtypeEquivRight fun _ => orbitRel.Quotient.mem_orbit.symm - -/-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. -/ -@[to_additive - "Decomposition of a type `X` as a disjoint union of its orbits under an additive group - action."] -def selfEquivSigmaOrbits : α ≃ Σω : Ω, orbit G ω.out' := - (selfEquivSigmaOrbits' G α).trans <| - Equiv.sigmaCongrRight fun _ => - Equiv.Set.ofEq <| orbitRel.Quotient.orbit_eq_orbit_out _ Quotient.out_eq' +@[to_additive] +lemma _root_.Finite.of_finite_mulAction_orbitRel_quotient [Finite G] [Finite Ω] : Finite α := by + rw [(selfEquivSigmaOrbits' G _).finite_iff] + have : ∀ g : Ω, Finite g.orbit := by + intro g + induction g using Quotient.inductionOn' + simpa [Set.finite_coe_iff] using Finite.finite_mulAction_orbit _ + exact Finite.instSigma variable (β) @@ -642,58 +206,8 @@ end Orbit section Stabilizer variable (G) -/-- The stabilizer of an element under an action, i.e. what sends the element to itself. -A subgroup. -/ -@[to_additive - "The stabilizer of an element under an action, i.e. what sends the element to itself. - An additive subgroup."] -def stabilizer (a : α) : Subgroup G := - { stabilizerSubmonoid G a with - inv_mem' := fun {m} (ha : m • a = a) => show m⁻¹ • a = a by rw [inv_smul_eq_iff, ha] } - variable {G} -@[to_additive] -instance [DecidableEq α] (a : α) : DecidablePred (· ∈ stabilizer G a) := - fun _ => inferInstanceAs <| Decidable (_ = _) - -@[to_additive (attr := simp)] -theorem mem_stabilizer_iff {a : α} {g : G} : g ∈ stabilizer G a ↔ g • a = a := - Iff.rfl - -@[to_additive] -lemma le_stabilizer_smul_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) : - stabilizer G a ≤ stabilizer G (a • b) := by - simp_rw [SetLike.le_def, mem_stabilizer_iff, ← smul_assoc]; rintro a h; rw [h] - --- This lemma does not need `MulAction G α`, only `SMul G α`. --- We use `G'` instead of `G` to locally reduce the typeclass assumptions. -@[to_additive] -lemma le_stabilizer_smul_right {G'} [Group G'] [SMul α β] [MulAction G' β] - [SMulCommClass G' α β] (a : α) (b : β) : - stabilizer G' b ≤ stabilizer G' (a • b) := by - simp_rw [SetLike.le_def, mem_stabilizer_iff, smul_comm]; rintro a h; rw [h] - -@[to_additive (attr := simp)] -lemma stabilizer_smul_eq_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) - (h : Injective (· • b : α → β)) : stabilizer G (a • b) = stabilizer G a := by - refine (le_stabilizer_smul_left _ _).antisymm' fun a ha ↦ ?_ - simpa only [mem_stabilizer_iff, ← smul_assoc, h.eq_iff] using ha - -@[to_additive (attr := simp)] -lemma stabilizer_smul_eq_right {α} [Group α] [MulAction α β] [SMulCommClass G α β] (a : α) (b : β) : - stabilizer G (a • b) = stabilizer G b := - (le_stabilizer_smul_right _ _).antisymm' <| (le_stabilizer_smul_right a⁻¹ _).trans_eq <| by - rw [inv_smul_smul] - -@[to_additive (attr := simp)] -lemma stabilizer_mul_eq_left [Group α] [IsScalarTower G α α] (a b : α) : - stabilizer G (a * b) = stabilizer G a := stabilizer_smul_eq_left a _ <| mul_left_injective _ - -@[to_additive (attr := simp)] -lemma stabilizer_mul_eq_right [Group α] [SMulCommClass G α α] (a b : α) : - stabilizer G (a * b) = stabilizer G b := stabilizer_smul_eq_right a _ - /-- If the stabilizer of `a` is `S`, then the stabilizer of `g • a` is `gSg⁻¹`. -/ theorem stabilizer_smul_eq_stabilizer_map_conj (g : G) (a : α) : stabilizer G (g • a) = (stabilizer G a).map (MulAut.conj g).toMonoidHom := by @@ -702,7 +216,7 @@ theorem stabilizer_smul_eq_stabilizer_map_conj (g : G) (a : α) : inv_mul_cancel, one_smul, ← mem_stabilizer_iff, Subgroup.mem_map_equiv, MulAut.conj_symm_apply] /-- A bijection between the stabilizers of two elements in the same orbit. -/ -noncomputable def stabilizerEquivStabilizerOfOrbitRel {a b : α} (h : (orbitRel G α).Rel a b) : +noncomputable def stabilizerEquivStabilizerOfOrbitRel {a b : α} (h : orbitRel G α a b) : stabilizer G a ≃* stabilizer G b := let g : G := Classical.choose h have hg : g • b = a := Classical.choose_spec h @@ -726,7 +240,7 @@ theorem stabilizer_vadd_eq_stabilizer_map_conj (g : G) (a : α) : AddAut.conj_symm_apply] /-- A bijection between the stabilizers of two elements in the same orbit. -/ -noncomputable def stabilizerEquivStabilizerOfOrbitRel {a b : α} (h : (orbitRel G α).Rel a b) : +noncomputable def stabilizerEquivStabilizerOfOrbitRel {a b : α} (h : orbitRel G α a b) : stabilizer G a ≃+ stabilizer G b := let g : G := Classical.choose h have hg : g +ᵥ b = a := Classical.choose_spec h diff --git a/Mathlib/GroupTheory/GroupAction/Blocks.lean b/Mathlib/GroupTheory/GroupAction/Blocks.lean index 9fbae888310e9..8359ba6ca7c44 100644 --- a/Mathlib/GroupTheory/GroupAction/Blocks.lean +++ b/Mathlib/GroupTheory/GroupAction/Blocks.lean @@ -3,12 +3,11 @@ 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.Setoid.Partition -import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.Pointwise import Mathlib.GroupTheory.GroupAction.SubMulAction -import Mathlib.Algebra.Group.Subgroup.Actions +import Mathlib.GroupTheory.Index +import Mathlib.Tactic.IntervalCases /-! # Blocks @@ -22,13 +21,25 @@ Given `SMul G X`, an action of a type `G` on a type `X`, we define The non-existence of nontrivial blocks is the definition of primitive actions. -## References +## Results for actions on finite sets + +- `IsBlock.ncard_block_mul_ncard_orbit_eq` : The cardinality of a block +multiplied by the number of its translates is the cardinal of the ambient type + +- `IsBlock.is_univ_of_large_block` : a too large block is equal to `Set.univ` + +- `IsBlock.is_subsingleton` : a too small block is a subsingleton -We follow [wieland1964]. +- `IsBlock.of_subset` : the intersections of the translates of a finite subset +that contain a given point is a block +## References + +We follow [Wielandt-1964]. -/ -open scoped BigOperators Pointwise +open Set +open scoped Pointwise namespace MulAction @@ -36,12 +47,14 @@ section orbits variable {G : Type*} [Group G] {X : Type*} [MulAction G X] +@[to_additive] theorem orbit.eq_or_disjoint (a b : X) : orbit G a = orbit G b ∨ Disjoint (orbit G a) (orbit G b) := by apply (em (Disjoint (orbit G a) (orbit G b))).symm.imp _ id simp (config := { contextual := true }) only [Set.not_disjoint_iff, ← orbit_eq_iff, forall_exists_index, and_imp, eq_comm, implies_true] +@[to_additive] theorem orbit.pairwiseDisjoint : (Set.range fun x : X => orbit G x).PairwiseDisjoint id := by rintro s ⟨x, rfl⟩ t ⟨y, rfl⟩ h @@ -49,6 +62,7 @@ theorem orbit.pairwiseDisjoint : exact (orbit.eq_or_disjoint x y).resolve_right h /-- Orbits of an element form a partition -/ +@[to_additive] theorem IsPartition.of_orbits : Setoid.IsPartition (Set.range fun a : X => orbit G a) := by apply orbit.pairwiseDisjoint.isPartition_of_exists_of_ne_empty @@ -61,245 +75,201 @@ end orbits section SMul -variable (G : Type*) {X : Type*} [SMul G X] +variable (G : Type*) {X : Type*} [SMul G X] {B : Set X} {a : X} -- Change terminology : is_fully_invariant ? -/-- For `SMul G X`, a fixed block is a `Set X` which is fully invariant: - `g • B = B` for all `g : G` -/ +/-- A set `B` is a `G`-fixed block if `g • B = B` for all `g : G`. -/ +@[to_additive "A set `B` is a `G`-fixed block if `g +ᵥ B = B` for all `g : G`."] def IsFixedBlock (B : Set X) := ∀ g : G, g • B = B -/-- For `SMul G X`, an invariant block is a `Set X` which is stable: - `g • B ⊆ B` for all `g : G` -/ -def IsInvariantBlock (B : Set X) := ∀ g : G, g • B ⊆ B - -/-- A trivial block is a `Set X` which is either a subsingleton or ⊤ - (it is not necessarily a block…) -/ -def IsTrivialBlock (B : Set X) := B.Subsingleton ∨ B = ⊤ - -/-- `For SMul G X`, a block is a `Set X` whose translates are pairwise disjoint -/ -def IsBlock (B : Set X) := (Set.range fun g : G => g • B).PairwiseDisjoint id +/-- A set `B` is a `G`-invariant block if `g • B ⊆ B` for all `g : G`. -variable {G} - -/-- A set B is a block iff for all g, g', -the sets g • B and g' • B are either equal or disjoint -/ -theorem IsBlock.def {B : Set X} : - IsBlock G B ↔ ∀ g g' : G, g • B = g' • B ∨ Disjoint (g • B) (g' • B) := by - apply Set.pairwiseDisjoint_range_iff - -/-- Alternate definition of a block -/ -theorem IsBlock.mk_notempty {B : Set X} : - IsBlock G B ↔ ∀ g g' : G, g • B ∩ g' • B ≠ ∅ → g • B = g' • B := by - simp_rw [IsBlock.def, or_iff_not_imp_right, Set.disjoint_iff_inter_eq_empty] +Note: It is not necessarily a block when the action is not by a group. -/ +@[to_additive +"A set `B` is a `G`-invariant block if `g +ᵥ B ⊆ B` for all `g : G`. -/-- A fixed block is a block -/ -theorem IsFixedBlock.isBlock {B : Set X} (hfB : IsFixedBlock G B) : - IsBlock G B := by - simp [IsBlock.def, hfB _] +Note: It is not necessarily a block when the action is not by a group. "] +def IsInvariantBlock (B : Set X) := ∀ g : G, g • B ⊆ B -variable (X) +/-- A trivial block is a `Set X` which is either a subsingleton or `univ`. -/-- The empty set is a block -/ -theorem isBlock_empty : IsBlock G (⊥ : Set X) := by - simp [IsBlock.def, Set.bot_eq_empty, Set.smul_set_empty] +Note: It is not necessarily a block when the action is not by a group. -/ +@[to_additive +"A trivial block is a `Set X` which is either a subsingleton or `univ`. -variable {X} +Note: It is not necessarily a block when the action is not by a group."] +def IsTrivialBlock (B : Set X) := B.Subsingleton ∨ B = univ -theorem isBlock_singleton (a : X) : IsBlock G ({a} : Set X) := by - simp [IsBlock.def, Classical.or_iff_not_imp_left] +/-- A set `B` is a `G`-block iff the sets of the form `g • B` are pairwise equal or disjoint. -/ +@[to_additive +"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) -/-- Subsingletons are (trivial) blocks -/ -theorem isBlock_subsingleton {B : Set X} (hB : B.Subsingleton) : - IsBlock G B := - hB.induction_on (isBlock_empty _) isBlock_singleton +variable {G} -end SMul +@[to_additive] +lemma isBlock_iff_smul_eq_smul_of_nonempty : + IsBlock G B ↔ ∀ ⦃g₁ g₂ : G⦄, (g₁ • B ∩ g₂ • B).Nonempty → g₁ • B = g₂ • B := by + simp_rw [IsBlock, ← not_disjoint_iff_nonempty_inter, not_imp_comm] -section Group +@[to_additive] +lemma isBlock_iff_pairwiseDisjoint_range_smul : + IsBlock G B ↔ (range fun g : G ↦ g • B).PairwiseDisjoint id := pairwiseDisjoint_range_iff.symm -variable {G : Type*} [Group G] {X : Type*} [MulAction G X] +@[to_additive] +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 -theorem IsBlock.smul_eq_or_disjoint {B : Set X} (hB : IsBlock G B) (g : G) : - g • B = B ∨ Disjoint (g • B) B := by - rw [IsBlock.def] at hB - simpa only [one_smul] using hB g 1 - -theorem IsBlock.def_one {B : Set X} : - IsBlock G B ↔ ∀ g : G, g • B = B ∨ Disjoint (g • B) B := by - refine ⟨IsBlock.smul_eq_or_disjoint, ?_⟩ - rw [IsBlock.def] - intro hB g g' - apply (hB (g'⁻¹ * g)).imp - · rw [← smul_smul, ← eq_inv_smul_iff, inv_inv] - exact id - · intro h - rw [Set.disjoint_iff] at h ⊢ - rintro x hx - suffices g'⁻¹ • x ∈ (g'⁻¹ * g) • B ∩ B by apply h this - rw [Set.mem_inter_iff] - simp only [← smul_smul, ← Set.mem_smul_set_iff_inv_smul_mem, smul_inv_smul] - exact hx - -theorem IsBlock.mk_notempty_one {B : Set X} : - IsBlock G B ↔ ∀ g : G, g • B ∩ B ≠ ∅ → g • B = B := by - simp_rw [IsBlock.def_one, Set.disjoint_iff_inter_eq_empty, or_iff_not_imp_right] - -theorem IsBlock.mk_mem {B : Set X} : - IsBlock G B ↔ ∀ (g : G) (a : X) (_ : a ∈ B) (_ : g • a ∈ B), g • B = B := by - rw [IsBlock.mk_notempty_one] - simp only [← Set.nonempty_iff_ne_empty, Set.nonempty_def, Set.mem_inter_iff, - exists_imp, and_imp, Set.mem_smul_set_iff_inv_smul_mem] - constructor - · intro H g a ha hga - apply H g (g • a) _ hga - simpa only [inv_smul_smul] using ha - · intro H g a ha hga - rw [← eq_inv_smul_iff, eq_comm] - exact H g⁻¹ a hga ha - -theorem IsBlock.def_mem {B : Set X} (hB : IsBlock G B) {a : X} {g : G} : - a ∈ B → g • a ∈ B → g • B = B := - IsBlock.mk_mem.mp hB g a - -theorem IsBlock.mk_subset {B : Set X} : - IsBlock G B ↔ ∀ {g : G} {b : X} (_ : b ∈ B) (_ : b ∈ g • B), g • B ⊆ B := by - simp_rw [IsBlock.mk_notempty_one, ← Set.nonempty_iff_ne_empty] - constructor - · intro hB g b hb hgb - exact (hB g ⟨b, hgb, hb⟩).le - · intro hB g ⟨b, hb', hb⟩ - apply le_antisymm (hB hb hb') - suffices g⁻¹ • B ≤ B by - rw [Set.le_iff_subset] at this ⊢ - rwa [← inv_inv g, ← Set.set_smul_subset_iff] - exact hB (Set.mem_smul_set_iff_inv_smul_mem.mp hb') (Set.smul_mem_smul_set_iff.mpr hb) - -/-- An invariant block is a fixed block -/ -theorem IsInvariantBlock.isFixedBlock {B : Set X} (hfB : IsInvariantBlock G B) : - IsFixedBlock G B := by - intro g - apply le_antisymm (hfB g) - intro x hx - rw [Set.mem_smul_set_iff_inv_smul_mem] - apply hfB g⁻¹ - rwa [Set.smul_mem_smul_set_iff] +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 -/-- An invariant block is a block -/ -theorem IsInvariantBlock.isBlock {B : Set X} (hfB : IsInvariantBlock G B) : - IsBlock G B := - hfB.isFixedBlock.isBlock +/-- A fixed block is a block. -/ +@[to_additive "A fixed block is a block."] +lemma IsFixedBlock.isBlock (hfB : IsFixedBlock G B) : IsBlock G B := by simp [IsBlock, hfB _] -/-- An orbit is a block -/ -theorem isFixedBlock_orbit (a : X) : IsFixedBlock G (orbit G a) := - (smul_orbit · a) +/-- The empty set is a block. -/ +@[to_additive (attr := simp) "The empty set is a block."] +lemma IsBlock.empty : IsBlock G (∅ : Set X) := by simp [IsBlock] -/-- An orbit is a block -/ -theorem isBlock_orbit (a : X) : IsBlock G (orbit G a) := - (isFixedBlock_orbit a).isBlock +/-- A singleton is a block. -/ +@[to_additive "A singleton is a block."] +lemma IsBlock.singleton : IsBlock G ({a} : Set X) := by simp [IsBlock] -variable (X) +/-- Subsingletons are (trivial) blocks. -/ +@[to_additive "Subsingletons are (trivial) blocks."] +lemma IsBlock.of_subsingleton (hB : B.Subsingleton) : IsBlock G B := + hB.induction_on .empty fun _ ↦ .singleton -/-- The full set is a (trivial) block -/ -theorem isFixedBlock_top : IsFixedBlock G (⊤ : Set X) := - fun _ ↦ by simp only [Set.top_eq_univ, Set.smul_set_univ] +/-- A fixed block is an invariant block. -/ +@[to_additive "A fixed block is an invariant block."] +lemma IsFixedBlock.isInvariantBlock (hB : IsFixedBlock G B) : IsInvariantBlock G B := + fun _ ↦ (hB _).le -/-- The full set is a (trivial) block -/ -theorem isBlock_top : IsBlock G (⊤ : Set X) := - (isFixedBlock_top _).isBlock +end SMul -variable {X} +section Group -/-- Is `B` is a block for an action of `G`, it is a block for the action of any subgroup of `G` -/ -theorem IsBlock.subgroup {H : Subgroup G} {B : Set X} (hfB : IsBlock G B) : - IsBlock H B := by - rw [IsBlock.def_one]; rintro ⟨g, _⟩ - simpa only using hfB.smul_eq_or_disjoint g +variable {G : Type*} [Group G] {X : Type*} [MulAction G X] {B : Set X} + +@[to_additive] +lemma isBlock_iff_disjoint_smul_of_ne : + IsBlock G B ↔ ∀ ⦃g : G⦄, g • B ≠ B → Disjoint (g • B) B := by + refine ⟨fun hB g ↦ by simpa using hB (g₂ := 1), fun hB g₁ g₂ h ↦ ?_⟩ + simp only [disjoint_smul_set_right, ne_eq, ← inv_smul_eq_iff, smul_smul] at h ⊢ + exact hB h + +@[to_additive] +lemma isBlock_iff_smul_eq_of_nonempty : + IsBlock G B ↔ ∀ ⦃g : G⦄, (g • B ∩ B).Nonempty → g • B = B := by + simp_rw [isBlock_iff_disjoint_smul_of_ne, ← not_disjoint_iff_nonempty_inter, not_imp_comm] + +@[to_additive] +lemma isBlock_iff_smul_eq_or_disjoint : + IsBlock G B ↔ ∀ g : G, g • B = B ∨ Disjoint (g • B) B := + isBlock_iff_disjoint_smul_of_ne.trans <| forall_congr' fun _ ↦ or_iff_not_imp_left.symm + +@[to_additive] +lemma isBlock_iff_smul_eq_of_mem : + IsBlock G B ↔ ∀ ⦃g : G⦄ ⦃a : X⦄, a ∈ B → g • a ∈ B → g • B = B := by + simp [isBlock_iff_smul_eq_of_nonempty, Set.Nonempty, mem_smul_set] + +@[to_additive] alias ⟨IsBlock.disjoint_smul_of_ne, _⟩ := isBlock_iff_disjoint_smul_of_ne +@[to_additive] alias ⟨IsBlock.smul_eq_of_nonempty, _⟩ := isBlock_iff_smul_eq_of_nonempty +@[to_additive] alias ⟨IsBlock.smul_eq_or_disjoint, _⟩ := isBlock_iff_smul_eq_or_disjoint +@[to_additive] alias ⟨IsBlock.smul_eq_of_mem, _⟩ := isBlock_iff_smul_eq_of_mem + +-- TODO: Generalise to `SubgroupClass` +/-- If `B` is a `G`-block, then it is also a `H`-block for any subgroup `H` of `G`. -/ +@[to_additive +"If `B` is a `G`-block, then it is also a `H`-block for any subgroup `H` of `G`."] +lemma IsBlock.subgroup {H : Subgroup G} (hB : IsBlock G B) : IsBlock H B := fun _ _ h ↦ hB h + +/-- A block of a group action is invariant iff it is fixed. -/ +@[to_additive "A block of a group action is invariant iff it is fixed."] +lemma isInvariantBlock_iff_isFixedBlock : IsInvariantBlock G B ↔ IsFixedBlock G B := + ⟨fun hB g ↦ (hB g).antisymm <| subset_set_smul_iff.2 <| hB _, IsFixedBlock.isInvariantBlock⟩ + +/-- An invariant block of a group action is a fixed block. -/ +@[to_additive "An invariant block of a group action is a fixed block."] +alias ⟨IsInvariantBlock.isFixedBlock, _⟩ := isInvariantBlock_iff_isFixedBlock + +/-- An invariant block of a group action is a block. -/ +@[to_additive "An invariant block of a group action is a block."] +lemma IsInvariantBlock.isBlock (hB : IsInvariantBlock G B) : IsBlock G B := hB.isFixedBlock.isBlock + +/-- The full set is a fixed block. -/ +@[to_additive "The full set is a fixed block."] +lemma IsFixedBlock.univ : IsFixedBlock G (univ : Set X) := fun _ ↦ by simp + +/-- The full set is a block. -/ +@[to_additive (attr := simp) "The full set is a block."] +lemma IsBlock.univ : IsBlock G (univ : Set X) := IsFixedBlock.univ.isBlock + +/-- The intersection of two blocks is a block. -/ +@[to_additive "The intersection of two blocks is a block."] +lemma IsBlock.inter {B₁ B₂ : Set X} (h₁ : IsBlock G B₁) (h₂ : IsBlock G B₂) : + IsBlock G (B₁ ∩ B₂) := by + simp only [isBlock_iff_smul_eq_smul_of_nonempty, smul_set_inter] at h₁ h₂ ⊢ + rintro g₁ g₂ ⟨a, ha₁, ha₂⟩ + rw [h₁ ⟨a, ha₁.1, ha₂.1⟩, h₂ ⟨a, ha₁.2, ha₂.2⟩] -theorem IsBlock.preimage {H Y : Type*} [Group H] [MulAction H Y] - {φ : H → G} (j : Y →ₑ[φ] X) {B : Set X} (hB : IsBlock G B) : +/-- An intersection of blocks is a block. -/ +@[to_additive "An intersection of blocks is a block."] +lemma IsBlock.iInter {ι : Sort*} {B : ι → Set X} (hB : ∀ i, IsBlock G (B i)) : + IsBlock G (⋂ i, B i) := by + simp only [isBlock_iff_smul_eq_smul_of_nonempty, smul_set_iInter] at hB ⊢ + rintro g₁ g₂ ⟨a, ha₁, ha₂⟩ + simp_rw [fun i ↦ hB i ⟨a, iInter_subset _ i ha₁, iInter_subset _ i ha₂⟩] + +/-- A trivial block is a block. -/ +@[to_additive "A trivial block is a block."] +lemma IsTrivialBlock.isBlock (hB : IsTrivialBlock B) : IsBlock G B := by + obtain hB | rfl := hB + · exact .of_subsingleton hB + · exact .univ + +/-- An orbit is a fixed block. -/ +@[to_additive "An orbit is a fixed block."] +protected lemma IsFixedBlock.orbit (a : X) : IsFixedBlock G (orbit G a) := (smul_orbit · a) + +/-- An orbit is a block. -/ +@[to_additive "An orbit is a block."] +protected lemma IsBlock.orbit (a : X) : IsBlock G (orbit G a) := (IsFixedBlock.orbit a).isBlock + +@[to_additive] +lemma isBlock_top : IsBlock (⊤ : Subgroup G) B ↔ IsBlock G B := + Subgroup.topEquiv.toEquiv.forall_congr fun _ ↦ Subgroup.topEquiv.toEquiv.forall_congr_left + +lemma IsBlock.preimage {H Y : Type*} [Group H] [MulAction H Y] + {φ : H → G} (j : Y →ₑ[φ] X) (hB : IsBlock G B) : IsBlock H (j ⁻¹' B) := by - rw [IsBlock.def_one] - intro g - rw [← Group.preimage_smul_setₛₗ Y X φ j] - apply (hB.smul_eq_or_disjoint (φ g)).imp - · intro heq - rw [heq] - · exact Disjoint.preimage _ + rintro g₁ g₂ hg + rw [← Group.preimage_smul_setₛₗ, ← Group.preimage_smul_setₛₗ] at hg ⊢ + exact (hB <| ne_of_apply_ne _ hg).preimage _ theorem IsBlock.image {H Y : Type*} [Group H] [MulAction H Y] {φ : G →* H} (j : X →ₑ[φ] Y) (hφ : Function.Surjective φ) (hj : Function.Injective j) - {B : Set X} (hB : IsBlock G B) : + (hB : IsBlock G B) : IsBlock H (j '' B) := by - rw [IsBlock.def] - intro h h' - obtain ⟨g, rfl⟩ := hφ h - obtain ⟨g', rfl⟩ := hφ h' - simp only [← image_smul_setₛₗ X Y φ j] - cases' IsBlock.def.mp hB g g' with h h - · left; rw [h] - · right; exact Set.disjoint_image_of_injective hj h - -theorem IsBlock.subtype_val_preimage {C : SubMulAction G X} {B : Set X} (hB : IsBlock G B) : + simp only [IsBlock, hφ.forall, ← image_smul_setₛₗ] + exact fun g₁ g₂ hg ↦ disjoint_image_of_injective hj <| hB <| ne_of_apply_ne _ hg + +theorem IsBlock.subtype_val_preimage {C : SubMulAction G X} (hB : IsBlock G B) : IsBlock G (Subtype.val ⁻¹' B : Set C) := hB.preimage C.inclusion -theorem IsBlock.iff_subtype_val {C : SubMulAction G X} {B : Set C} : - IsBlock G B ↔ IsBlock G (Subtype.val '' B : Set X) := by - simp only [IsBlock.def_one] - apply forall_congr' - intro g - rw [← SubMulAction.inclusion.coe_eq, ← image_smul_set _ _ _ C.inclusion g B, - ← Set.image_eq_image Subtype.coe_injective] - apply or_congr Iff.rfl - simp only [Set.disjoint_iff, Set.subset_empty_iff, Set.image_eq_empty, - ← C.inclusion_injective.injOn.image_inter (Set.subset_univ _) (Set.subset_univ _)] - -theorem IsBlock.iff_top (B : Set X) : - IsBlock G B ↔ IsBlock (⊤ : Subgroup G) B := by - simp only [IsBlock.def_one] - constructor - · intro h g; exact h g - · intro h g; exact h ⟨g, Subgroup.mem_top g⟩ +theorem isBlock_subtypeVal {C : SubMulAction G X} {B : Set C} : + IsBlock G (Subtype.val '' B : Set X) ↔ IsBlock G B := by + refine forall₂_congr fun g₁ g₂ ↦ ?_ + rw [← SubMulAction.inclusion.coe_eq, ← image_smul_set, ← image_smul_set, ne_eq, + Set.image_eq_image C.inclusion_injective, disjoint_image_iff C.inclusion_injective] -/-- The intersection of two blocks is a block -/ -theorem IsBlock.inter {B₁ B₂ : Set X} (h₁ : IsBlock G B₁) (h₂ : IsBlock G B₂) : - IsBlock G (B₁ ∩ B₂) := by - rw [IsBlock.def_one] - intro g - rw [Set.smul_set_inter] - cases' h₁.smul_eq_or_disjoint g with h₁ h₁ - · cases' h₂.smul_eq_or_disjoint g with h₂ h₂ - · left; rw [h₁, h₂] - right - apply Disjoint.inter_left'; apply Disjoint.inter_right' - exact h₂ - · right - apply Disjoint.inter_left; apply Disjoint.inter_right - exact h₁ - -/-- An intersection of blocks is a block -/ -theorem IsBlock.iInter {ι : Type*} {B : ι → Set X} (hB : ∀ i : ι, IsBlock G (B i)) : - IsBlock G (⋂ i, B i) := by - by_cases hι : (IsEmpty ι) - · -- ι = ∅, block = ⊤ - suffices (⋂ i : ι, B i) = Set.univ by simpa only [this] using isBlock_top X - simpa only [Set.top_eq_univ, Set.iInter_eq_univ] using (hι.elim' ·) - rw [IsBlock.def_one] - intro g - rw [Set.smul_set_iInter] - by_cases h : ∃ i : ι, Disjoint (g • B i) (B i) - · right - obtain ⟨j, hj⟩ := h - refine Disjoint.mono ?_ ?_ hj <;> apply Set.iInter_subset - · left - simp only [not_exists] at h - have : ∀ i : ι, g • B i = B i := fun i => ((hB i).smul_eq_or_disjoint g).resolve_right (h i) - rw [Set.iInter_congr this] - -theorem IsBlock.of_subgroup_of_conjugate {B : Set X} {H : Subgroup G} (hB : IsBlock H B) (g : G) : +theorem IsBlock.of_subgroup_of_conjugate {H : Subgroup G} (hB : IsBlock H B) (g : G) : IsBlock (Subgroup.map (MulEquiv.toMonoidHom (MulAut.conj g)) H) (g • B) := by - rw [IsBlock.def_one] + rw [isBlock_iff_smul_eq_or_disjoint] intro h' obtain ⟨h, hH, hh⟩ := Subgroup.mem_map.mp (SetLike.coe_mem h') simp only [MulEquiv.coe_toMonoidHom, MulAut.conj_apply] at hh @@ -313,9 +283,9 @@ theorem IsBlock.of_subgroup_of_conjugate {B : Set X} {H : Subgroup G} (hB : IsBl rw [← hh, smul_smul (g * h * g⁻¹) g B, smul_smul g h B, inv_mul_cancel_right] /-- A translate of a block is a block -/ -theorem IsBlock.translate {B : Set X} (g : G) (hB : IsBlock G B) : +theorem IsBlock.translate (g : G) (hB : IsBlock G B) : IsBlock G (g • B) := by - rw [IsBlock.iff_top] at hB ⊢ + rw [← isBlock_top] at hB ⊢ rw [← Subgroup.map_comap_eq_self_of_surjective (f := MulAut.conj g) (MulAut.conj g).surjective ⊤] apply IsBlock.of_subgroup_of_conjugate rwa [Subgroup.comap_top] @@ -323,12 +293,11 @@ theorem IsBlock.translate {B : Set X} (g : G) (hB : IsBlock G B) : variable (G) in /-- For `SMul G X`, a block system of `X` is a partition of `X` into blocks for the action of `G` -/ -def IsBlockSystem (B : Set (Set X)) := - Setoid.IsPartition B ∧ ∀ b : Set X, b ∈ B → IsBlock G b +def IsBlockSystem (ℬ : Set (Set X)) := Setoid.IsPartition ℬ ∧ ∀ ⦃B⦄, B ∈ ℬ → IsBlock G B -/-- Translates of a block form a `block_system` -/ +/-- Translates of a block form a block system. -/ theorem IsBlock.isBlockSystem [hGX : MulAction.IsPretransitive G X] - {B : Set X} (hB : IsBlock G B) (hBe : B.Nonempty) : + (hB : IsBlock G B) (hBe : B.Nonempty) : IsBlockSystem G (Set.range fun g : G => g • B) := by refine ⟨⟨?nonempty, ?cover⟩, ?mem_blocks⟩ case mem_blocks => rintro B' ⟨g, rfl⟩; exact hB.translate g @@ -343,10 +312,7 @@ theorem IsBlock.isBlockSystem [hGX : MulAction.IsPretransitive G X] simp only [Set.smul_mem_smul_set_iff, hb, exists_unique_iff_exists, Set.mem_range, exists_apply_eq_apply, exists_const, exists_prop, and_imp, forall_exists_index, forall_apply_eq_imp_iff, true_and] - intro g' ha - apply (IsBlock.def.mp hB g' g).resolve_right - rw [Set.not_disjoint_iff] - refine ⟨g • b, ha, ⟨b, hb, rfl⟩⟩ + exact fun g' ha ↦ hB.smul_eq_smul_of_nonempty ⟨g • b, ha, ⟨b, hb, rfl⟩⟩ section Normal @@ -366,9 +332,9 @@ lemma smul_orbit_eq_orbit_smul (N : Subgroup G) [nN : N.Normal] (a : X) (g : G) simp only [← mul_assoc, ← smul_smul, smul_inv_smul, inv_inv] /-- An orbit of a normal subgroup is a block -/ -theorem orbit.isBlock_of_normal {N : Subgroup G} [N.Normal] (a : X) : +theorem IsBlock.orbit_of_normal {N : Subgroup G} [N.Normal] (a : X) : IsBlock G (orbit N a) := by - rw [IsBlock.def_one] + rw [isBlock_iff_smul_eq_or_disjoint] intro g rw [smul_orbit_eq_orbit_smul] apply orbit.eq_or_disjoint @@ -379,7 +345,48 @@ theorem IsBlockSystem.of_normal {N : Subgroup G} [N.Normal] : constructor · apply IsPartition.of_orbits · intro b; rintro ⟨a, rfl⟩ - exact orbit.isBlock_of_normal a + exact .orbit_of_normal a + +section Group +variable {S H : Type*} [Group H] [SetLike S H] [SubgroupClass S H] {s : S} {a : G} + +/-! +Annoyingly, it seems like the following two lemmas cannot be unified. +-/ + +section Left +variable [MulAction G H] [IsScalarTower G H H] + +/-- See `MulAction.isBlock_subgroup'` for a version that works for the right action of a group on +itself. -/ +@[to_additive "See `AddAction.isBlock_subgroup'` for a version that works for the right action +of a group on itself."] +lemma isBlock_subgroup : IsBlock G (s : Set H) := by + simp only [IsBlock, disjoint_left] + rintro a b hab _ ⟨c, hc, rfl⟩ ⟨d, hd, (hcd : b • d = a • c)⟩ + refine hab ?_ + rw [← smul_coe_set hc, ← smul_assoc, ← hcd, smul_assoc, smul_coe_set hc, smul_coe_set hd] + +end Left + +section Right +variable [MulAction G H] [IsScalarTower G Hᵐᵒᵖ H] + +open MulOpposite + +/-- See `MulAction.isBlock_subgroup` for a version that works for the left action of a group on +itself. -/ +@[to_additive "See `AddAction.isBlock_subgroup` for a version that works for the left action +of a group on itself."] +lemma isBlock_subgroup' : IsBlock G (s : Set H) := by + simp only [IsBlock, disjoint_left] + rintro a b hab _ ⟨c, hc, rfl⟩ ⟨d, hd, (hcd : b • d = a • c)⟩ + refine hab ?_ + rw [← op_smul_coe_set hc, ← smul_assoc, ← op_smul, ← hcd, op_smul, smul_assoc, op_smul_coe_set hc, + op_smul_coe_set hd] + +end Right +end Group end Normal @@ -395,28 +402,21 @@ section Stabilizer /-- The orbit of `a` under a subgroup containing the stabilizer of `a` is a block -/ theorem IsBlock.of_orbit {H : Subgroup G} {a : X} (hH : stabilizer G a ≤ H) : IsBlock G (MulAction.orbit H a) := by - simp_rw [IsBlock.def_one, or_iff_not_imp_right, Set.not_disjoint_iff] - rintro g ⟨-, ⟨-, ⟨h₁, rfl⟩, h⟩, ⟨h₂, rfl⟩⟩ + rw [isBlock_iff_smul_eq_of_nonempty] + rintro g ⟨-, ⟨-, ⟨h₁, rfl⟩, h⟩, h₂, rfl⟩ suffices g ∈ H by rw [← Subgroup.coe_mk H g this, ← H.toSubmonoid.smul_def, smul_orbit (⟨g, this⟩ : H) a] rw [← mul_mem_cancel_left h₂⁻¹.2, ← mul_mem_cancel_right h₁.2] apply hH - simp only [mem_stabilizer_iff, InvMemClass.coe_inv, mul_smul, inv_smul_eq_iff] - exact h + simpa only [mem_stabilizer_iff, InvMemClass.coe_inv, mul_smul, inv_smul_eq_iff] /-- If `B` is a block containing `a`, then the stabilizer of `B` contains the stabilizer of `a` -/ -theorem IsBlock.stabilizer_le {B : Set X} (hB : IsBlock G B) {a : X} (ha : a ∈ B) : - stabilizer G a ≤ stabilizer G B := by - intro g hg - apply Or.resolve_right (hB.smul_eq_or_disjoint g) - rw [Set.not_disjoint_iff] - refine ⟨a, ?_, ha⟩ - rw [← hg, Set.smul_mem_smul_set_iff] - exact ha +theorem IsBlock.stabilizer_le (hB : IsBlock G B) {a : X} (ha : a ∈ B) : + stabilizer G a ≤ stabilizer G B := + fun g hg ↦ hB.smul_eq_of_nonempty ⟨a, by rwa [← hg, smul_mem_smul_set_iff], ha⟩ /-- A block containing `a` is the orbit of `a` under its stabilizer -/ -theorem IsBlock.orbit_stabilizer_eq - [htGX : IsPretransitive G X] {B : Set X} (hB : IsBlock G B) {a : X} (ha : a ∈ B) : +theorem IsBlock.orbit_stabilizer_eq [IsPretransitive G X] (hB : IsBlock G B) {a : X} (ha : a ∈ B) : MulAction.orbit (stabilizer G B) a = B := by ext x constructor @@ -426,7 +426,7 @@ theorem IsBlock.orbit_stabilizer_eq exact ha · intro hx obtain ⟨k, rfl⟩ := exists_smul_eq G a x - exact ⟨⟨k, hB.def_mem ha hx⟩, rfl⟩ + exact ⟨⟨k, hB.smul_eq_of_mem ha hx⟩, rfl⟩ /-- A subgroup containing the stabilizer of `a` is the stabilizer of the orbit of `a` under that subgroup -/ @@ -451,9 +451,9 @@ def block_stabilizerOrderIso [htGX : IsPretransitive G X] (a : X) : toFun := fun ⟨B, ha, hB⟩ => ⟨stabilizer G B, hB.stabilizer_le ha⟩ invFun := fun ⟨H, hH⟩ => ⟨MulAction.orbit H a, MulAction.mem_orbit_self a, IsBlock.of_orbit hH⟩ - left_inv := fun ⟨B, ha, hB⟩ => + left_inv := fun ⟨_, ha, hB⟩ => (id (propext Subtype.mk_eq_mk)).mpr (hB.orbit_stabilizer_eq ha) - right_inv := fun ⟨H, hH⟩ => + right_inv := fun ⟨_, hH⟩ => (id (propext Subtype.mk_eq_mk)).mpr (stabilizer_orbit_eq hH) map_rel_iff' := by rintro ⟨B, ha, hB⟩; rintro ⟨B', ha', hB'⟩ @@ -463,13 +463,115 @@ def block_stabilizerOrderIso [htGX : IsPretransitive G X] (a : X) : obtain ⟨k, rfl⟩ := htGX.exists_smul_eq a b suffices k ∈ stabilizer G B' by exact this.symm ▸ (Set.smul_mem_smul_set ha') - exact hBB' (hB.def_mem ha hb) + exact hBB' (hB.smul_eq_of_mem ha hb) · intro hBB' g hgB - apply IsBlock.def_mem hB' ha' + apply hB'.smul_eq_of_mem ha' exact hBB' <| hgB.symm ▸ (Set.smul_mem_smul_set ha) end Stabilizer +section Finite + +namespace IsBlock + +variable [IsPretransitive G X] {B : Set X} + +theorem ncard_block_eq_relindex (hB : IsBlock G B) {x : X} (hx : x ∈ B) : + B.ncard = (stabilizer G x).relindex (stabilizer G B) := by + have key : (stabilizer G x).subgroupOf (stabilizer G B) = stabilizer (stabilizer G B) x := by + ext; rfl + rw [Subgroup.relindex, key, index_stabilizer, hB.orbit_stabilizer_eq hx] + +/-- The cardinality of the ambient space is the product of the cardinality of a block + by the cardinality of the set of translates of that block -/ +theorem ncard_block_mul_ncard_orbit_eq (hB : IsBlock G B) (hB_ne : B.Nonempty) : + Set.ncard B * Set.ncard (orbit G B) = Nat.card X := by + obtain ⟨x, hx⟩ := hB_ne + rw [ncard_block_eq_relindex hB hx, ← index_stabilizer, + Subgroup.relindex_mul_index (hB.stabilizer_le hx), index_stabilizer_of_transitive] + +/-- The cardinality of a block divides the cardinality of the ambient type -/ +theorem ncard_dvd_card (hB : IsBlock G B) (hB_ne : B.Nonempty) : + Set.ncard B ∣ Nat.card X := + Dvd.intro _ (hB.ncard_block_mul_ncard_orbit_eq hB_ne) + +/-- A too large block is equal to `univ` -/ +theorem eq_univ_card_lt [hX : Finite X] (hB : IsBlock G B) (hB' : Nat.card X < Set.ncard B * 2) : + B = Set.univ := by + rcases Set.eq_empty_or_nonempty B with rfl | hB_ne + · simp only [Set.ncard_empty, zero_mul, not_lt_zero'] at hB' + have key := hB.ncard_block_mul_ncard_orbit_eq hB_ne + rw [← key, mul_lt_mul_iff_of_pos_left (by rwa [Set.ncard_pos])] at hB' + interval_cases (orbit G B).ncard + · rw [mul_zero, eq_comm, Nat.card_eq_zero, or_iff_left hX.not_infinite] at key + exact (IsEmpty.exists_iff.mp hB_ne).elim + · rw [mul_one, ← Set.ncard_univ] at key + rw [Set.eq_of_subset_of_ncard_le (Set.subset_univ B) key.ge] + +/-- If a block has too many translates, then it is a (sub)singleton -/ +theorem subsingleton_of_card_lt [Finite X] (hB : IsBlock G B) + (hB' : Nat.card X < 2 * Set.ncard (orbit G B)) : + B.Subsingleton := by + suffices Set.ncard B < 2 by + rw [Nat.lt_succ_iff, Set.ncard_le_one_iff_eq] at this + cases this with + | inl h => rw [h]; exact Set.subsingleton_empty + | inr h => + obtain ⟨a, ha⟩ := h; rw [ha]; exact Set.subsingleton_singleton + cases Set.eq_empty_or_nonempty B with + | inl h => rw [h, Set.ncard_empty]; norm_num + | inr h => + rw [← hB.ncard_block_mul_ncard_orbit_eq h, lt_iff_not_ge] at hB' + rw [← not_le] + exact fun hb ↦ hB' (Nat.mul_le_mul_right _ hb) + +/- The assumption `B.Finite` is necessary : + For G = ℤ acting on itself, a = 0 and B = ℕ, the translates `k • B` of the statement + are just `k + ℕ`, for `k ≤ 0`, and the corresponding intersection is `ℕ`, which is not a block. + (Remark by Thomas Browning) -/ +-- Note : add {B} because otherwise Lean includes `hB : IsBlock G B` +/-- The intersection of the translates of a *finite* subset which contain a given point +is a block (Wielandt, th. 7.3 )-/ +theorem of_subset {B : Set X} (a : X) (hfB : B.Finite) : + IsBlock G (⋂ (k : G) (_ : a ∈ k • B), k • B) := by + let B' := ⋂ (k : G) (_ : a ∈ k • B), k • B + cases' Set.eq_empty_or_nonempty B with hfB_e hfB_ne + · simp [hfB_e] + have hB'₀ : ∀ (k : G) (_ : a ∈ k • B), B' ≤ k • B := by + intro k hk + exact Set.biInter_subset_of_mem hk + have hfB' : B'.Finite := by + obtain ⟨b, hb : b ∈ B⟩ := hfB_ne + obtain ⟨k, hk : k • b = a⟩ := exists_smul_eq G b a + apply Set.Finite.subset (Set.Finite.map _ hfB) (hB'₀ k ⟨b, hb, hk⟩) + have hag : ∀ g : G, a ∈ g • B' → B' ≤ g • B' := by + intro g hg x hx + -- a = g • b; b ∈ B'; a ∈ k • B → b ∈ k • B + simp only [B', Set.mem_iInter, Set.mem_smul_set_iff_inv_smul_mem, + 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'] + exact hag g hg + rw [isBlock_iff_smul_eq_of_nonempty] + rintro g ⟨b : X, hb' : b ∈ g • B', hb : b ∈ B'⟩ + obtain ⟨k : G, hk : k • a = b⟩ := exists_smul_eq G a b + have hak : a ∈ k⁻¹ • B' := by + refine ⟨b, hb, ?_⟩ + simp only [← hk, inv_smul_smul] + have hagk : a ∈ (k⁻¹ * g) • B' := by + rw [mul_smul, Set.mem_smul_set_iff_inv_smul_mem, inv_inv, hk] + exact hb' + have hkB' : B' = k⁻¹ • B' := hag' k⁻¹ hak + have hgkB' : B' = (k⁻¹ * g) • B' := hag' (k⁻¹ * g) hagk + rw [mul_smul] at hgkB' + rw [← smul_eq_iff_eq_inv_smul] at hkB' hgkB' + rw [← hgkB', hkB'] + +end IsBlock + +end Finite + end Group end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/ConjAct.lean b/Mathlib/GroupTheory/GroupAction/ConjAct.lean index b16c6ce0f2902..6aa1a4aeb2ee5 100644 --- a/Mathlib/GroupTheory/GroupAction/ConjAct.lean +++ b/Mathlib/GroupTheory/GroupAction/ConjAct.lean @@ -5,8 +5,10 @@ Authors: Chris Hughes -/ import Mathlib.Algebra.Field.Defs import Mathlib.Algebra.Group.Subgroup.ZPowers +import Mathlib.Algebra.GroupWithZero.Action.Basic import Mathlib.Algebra.Ring.Action.Basic -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Data.Fintype.Card +import Mathlib.GroupTheory.GroupAction.Defs /-! # Conjugation action of a group on itself @@ -146,18 +148,11 @@ instance unitsScalar : SMul (ConjAct Mˣ) M where smul g h := ofConjAct g * h * theorem units_smul_def (g : ConjAct Mˣ) (h : M) : g • h = ofConjAct g * h * ↑(ofConjAct g)⁻¹ := rfl --- porting note (#11083): very slow without `simp only` and need to separate `units_smul_def` --- so that things trigger appropriately instance unitsMulDistribMulAction : MulDistribMulAction (ConjAct Mˣ) M where - one_smul := by simp only [units_smul_def, ofConjAct_one, Units.val_one, one_mul, inv_one, - mul_one, forall_const] - mul_smul := by - simp only [units_smul_def] - simp only [map_mul, Units.val_mul, mul_assoc, mul_inv_rev, forall_const, «forall»] - smul_mul := by - simp only [units_smul_def] - simp only [mul_assoc, Units.inv_mul_cancel_left, forall_const, «forall»] - smul_one := by simp [units_smul_def, mul_one, Units.mul_inv, «forall», forall_const] + one_smul := by simp [units_smul_def] + mul_smul := by simp [units_smul_def, mul_assoc] + smul_mul := by simp [units_smul_def, mul_assoc] + smul_one := by simp [units_smul_def] instance unitsSMulCommClass [SMul α M] [SMulCommClass α M M] [IsScalarTower α M M] : @@ -175,15 +170,10 @@ section Semiring variable [Semiring R] --- porting note (#11083): very slow without `simp only` and need to separate `units_smul_def` --- so that things trigger appropriately instance unitsMulSemiringAction : MulSemiringAction (ConjAct Rˣ) R := { ConjAct.unitsMulDistribMulAction with - smul_zero := by - simp only [units_smul_def, mul_zero, zero_mul, «forall», forall_const] - smul_add := by - simp only [units_smul_def] - simp only [mul_add, add_mul, forall_const, «forall»] } + smul_zero := by simp [units_smul_def] + smul_add := by simp [units_smul_def, mul_add, add_mul] } end Semiring @@ -201,15 +191,9 @@ theorem ofConjAct_zero : ofConjAct (0 : ConjAct G₀) = 0 := theorem toConjAct_zero : toConjAct (0 : G₀) = 0 := rfl --- porting note (#11083): very slow without `simp only` and need to separate `smul_def` --- so that things trigger appropriately instance mulAction₀ : MulAction (ConjAct G₀) G₀ where - one_smul := by - simp only [smul_def] - simp only [map_one, one_mul, inv_one, mul_one, forall_const] - mul_smul := by - simp only [smul_def] - simp only [map_mul, mul_assoc, mul_inv_rev, forall_const, «forall»] + one_smul := by simp [smul_def] + mul_smul := by simp [smul_def, mul_assoc] instance smulCommClass₀ [SMul α G₀] [SMulCommClass α G₀ G₀] [IsScalarTower α G₀ G₀] : SMulCommClass α (ConjAct G₀) G₀ where @@ -226,16 +210,10 @@ section DivisionRing variable [DivisionRing K] --- porting note (#11083): very slow without `simp only` and need to separate `smul_def` --- so that things trigger appropriately instance distribMulAction₀ : DistribMulAction (ConjAct K) K := { ConjAct.mulAction₀ with - smul_zero := by - simp only [smul_def] - simp only [mul_zero, zero_mul, «forall», forall_const] - smul_add := by - simp only [smul_def] - simp only [mul_add, add_mul, forall_const, «forall»] } + smul_zero := by simp [smul_def] + smul_add := by simp [smul_def, mul_add, add_mul] } end DivisionRing @@ -243,17 +221,11 @@ variable [Group G] -- todo: this file is not in good order; I will refactor this after the PR --- porting note (#11083): very slow without `simp only` and need to separate `smul_def` --- so that things trigger appropriately instance : MulDistribMulAction (ConjAct G) G where - smul_mul := by - simp only [smul_def] - simp only [mul_assoc, inv_mul_cancel_left, forall_const, «forall»] - smul_one := by simp only [smul_def, mul_one, mul_inv_cancel, «forall», forall_const] - one_smul := by simp only [smul_def, ofConjAct_one, one_mul, inv_one, mul_one, forall_const] - mul_smul := by - simp only [smul_def] - simp only [map_mul, mul_assoc, mul_inv_rev, forall_const, «forall»] + smul_mul := by simp [smul_def] + smul_one := by simp [smul_def] + one_smul := by simp [smul_def] + mul_smul := by simp [smul_def, mul_assoc] instance smulCommClass [SMul α G] [SMulCommClass α G G] [IsScalarTower α G G] : SMulCommClass α (ConjAct G) G where @@ -276,7 +248,7 @@ theorem fixedPoints_eq_center : fixedPoints (ConjAct G) G = center G := by theorem mem_orbit_conjAct {g h : G} : g ∈ orbit (ConjAct G) h ↔ IsConj g h := by rw [isConj_comm, isConj_iff, mem_orbit_iff]; rfl -theorem orbitRel_conjAct : (orbitRel (ConjAct G) G).Rel = IsConj := +theorem orbitRel_conjAct : ⇑(orbitRel (ConjAct G) G) = IsConj := funext₂ fun g h => by rw [orbitRel_apply, mem_orbit_conjAct] theorem orbit_eq_carrier_conjClasses (g : G) : @@ -352,7 +324,7 @@ def unitsCentralizerEquiv (x : Mˣ) : have : (u : ConjAct Mˣ) • x = x := u.2 rwa [ConjAct.smul_def, mul_inv_eq_iff_eq_mul, Units.ext_iff, eq_comm] at this⟩, map_one' := rfl, - map_mul' := fun a b ↦ rfl } + map_mul' := fun _ _ ↦ rfl } invFun := fun u ↦ ⟨ConjAct.toConjAct (Units.map (Submonoid.centralizer ({↑x} : Set M)).subtype u), by change _ • _ = _ diff --git a/Mathlib/GroupTheory/GroupAction/Defs.lean b/Mathlib/GroupTheory/GroupAction/Defs.lean new file mode 100644 index 0000000000000..0beafab0cdd6f --- /dev/null +++ b/Mathlib/GroupTheory/GroupAction/Defs.lean @@ -0,0 +1,580 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.Algebra.Group.Pointwise.Set.Basic +import Mathlib.Algebra.Group.Subgroup.Defs +import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.GroupWithZero.Action.Defs + +/-! +# Definition of `orbit`, `fixedPoints` and `stabilizer` + +This file defines orbits, stabilizers, and other objects defined in terms of actions. + +## Main definitions + +* `MulAction.orbit` +* `MulAction.fixedPoints` +* `MulAction.fixedBy` +* `MulAction.stabilizer` + +-/ + + +universe u v + +open Pointwise + +open Function + +namespace MulAction + +variable (M : Type u) [Monoid M] (α : Type v) [MulAction M α] {β : Type*} [MulAction M β] + +section Orbit + +variable {α} + +/-- The orbit of an element under an action. -/ +@[to_additive "The orbit of an element under an action."] +def orbit (a : α) := + Set.range fun m : M => m • a + +variable {M} + +@[to_additive] +theorem mem_orbit_iff {a₁ a₂ : α} : a₂ ∈ orbit M a₁ ↔ ∃ x : M, x • a₁ = a₂ := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_orbit (a : α) (m : M) : m • a ∈ orbit M a := + ⟨m, rfl⟩ + +@[to_additive (attr := simp)] +theorem mem_orbit_self (a : α) : a ∈ orbit M a := + ⟨1, by simp [MulAction.one_smul]⟩ + +@[to_additive] +theorem orbit_nonempty (a : α) : Set.Nonempty (orbit M a) := + Set.range_nonempty _ + +@[to_additive] +theorem mapsTo_smul_orbit (m : M) (a : α) : Set.MapsTo (m • ·) (orbit M a) (orbit M a) := + Set.range_subset_iff.2 fun m' => ⟨m * m', mul_smul _ _ _⟩ + +@[to_additive] +theorem smul_orbit_subset (m : M) (a : α) : m • orbit M a ⊆ orbit M a := + (mapsTo_smul_orbit m a).image_subset + +@[to_additive] +theorem orbit_smul_subset (m : M) (a : α) : orbit M (m • a) ⊆ orbit M a := + Set.range_subset_iff.2 fun m' => mul_smul m' m a ▸ mem_orbit _ _ + +@[to_additive] +instance {a : α} : MulAction M (orbit M a) where + smul m := (mapsTo_smul_orbit m a).restrict _ _ _ + one_smul m := Subtype.ext (one_smul M (m : α)) + mul_smul m m' a' := Subtype.ext (mul_smul m m' (a' : α)) + +@[to_additive (attr := simp)] +theorem orbit.coe_smul {a : α} {m : M} {a' : orbit M a} : ↑(m • a') = m • (a' : α) := + rfl + +@[to_additive] +lemma orbit_submonoid_subset (S : Submonoid M) (a : α) : orbit S a ⊆ orbit M a := by + rintro b ⟨g, rfl⟩ + exact mem_orbit _ _ + +@[to_additive] +lemma mem_orbit_of_mem_orbit_submonoid {S : Submonoid M} {a b : α} (h : a ∈ orbit S b) : + a ∈ orbit M b := + orbit_submonoid_subset S _ h + +end Orbit + +section FixedPoints + +/-- The set of elements fixed under the whole action. -/ +@[to_additive "The set of elements fixed under the whole action."] +def fixedPoints : Set α := + { a : α | ∀ m : M, m • a = a } + +variable {M} + +/-- `fixedBy m` is the set of elements fixed by `m`. -/ +@[to_additive "`fixedBy m` is the set of elements fixed by `m`."] +def fixedBy (m : M) : Set α := + { x | m • x = x } + +variable (M) + +@[to_additive] +theorem fixed_eq_iInter_fixedBy : fixedPoints M α = ⋂ m : M, fixedBy α m := + Set.ext fun _ => + ⟨fun hx => Set.mem_iInter.2 fun m => hx m, fun hx m => (Set.mem_iInter.1 hx m : _)⟩ + +variable {M α} + +@[to_additive (attr := simp)] +theorem mem_fixedPoints {a : α} : a ∈ fixedPoints M α ↔ ∀ m : M, m • a = a := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_fixedBy {m : M} {a : α} : a ∈ fixedBy α m ↔ m • a = a := + Iff.rfl + +@[to_additive] +theorem mem_fixedPoints' {a : α} : a ∈ fixedPoints M α ↔ ∀ a', a' ∈ orbit M a → a' = a := + ⟨fun h _ h₁ => + let ⟨m, hm⟩ := mem_orbit_iff.1 h₁ + hm ▸ h m, + fun h _ => h _ (mem_orbit _ _)⟩ + +end FixedPoints + +section Stabilizers + +variable {α} + +/-- The stabilizer of a point `a` as a submonoid of `M`. -/ +@[to_additive "The stabilizer of a point `a` as an additive submonoid of `M`."] +def stabilizerSubmonoid (a : α) : Submonoid M where + carrier := { m | m • a = a } + one_mem' := one_smul _ a + mul_mem' {m m'} (ha : m • a = a) (hb : m' • a = a) := + show (m * m') • a = a by rw [← smul_smul, hb, ha] + +variable {M} + +@[to_additive] +instance [DecidableEq α] (a : α) : DecidablePred (· ∈ stabilizerSubmonoid M a) := + fun _ => inferInstanceAs <| Decidable (_ = _) + +@[to_additive (attr := simp)] +theorem mem_stabilizerSubmonoid_iff {a : α} {m : M} : m ∈ stabilizerSubmonoid M a ↔ m • a = a := + Iff.rfl + +end Stabilizers + +end MulAction + +section FixedPoints + +variable (M : Type u) (α : Type v) [Monoid M] + +section Monoid + +variable [Monoid α] [MulDistribMulAction M α] + +/-- The submonoid of elements fixed under the whole action. -/ +def FixedPoints.submonoid : Submonoid α where + carrier := MulAction.fixedPoints M α + one_mem' := smul_one + mul_mem' ha hb _ := by rw [smul_mul', ha, hb] + +@[simp] +lemma FixedPoints.mem_submonoid (a : α) : a ∈ submonoid M α ↔ ∀ m : M, m • a = a := + Iff.rfl + +end Monoid + +section Group +namespace FixedPoints +variable [Group α] [MulDistribMulAction M α] + +/-- The subgroup of elements fixed under the whole action. -/ +def subgroup : Subgroup α where + __ := submonoid M α + inv_mem' ha _ := by rw [smul_inv', ha] + +/-- The notation for `FixedPoints.subgroup`, chosen to resemble `αᴹ`. -/ +scoped notation α "^*" M:51 => FixedPoints.subgroup M α + +@[simp] +lemma mem_subgroup (a : α) : a ∈ α^*M ↔ ∀ m : M, m • a = a := + Iff.rfl + +@[simp] +lemma subgroup_toSubmonoid : (α^*M).toSubmonoid = submonoid M α := + rfl + +end FixedPoints +end Group + +section AddMonoid + +variable [AddMonoid α] [DistribMulAction M α] + +/-- The additive submonoid of elements fixed under the whole action. -/ +def FixedPoints.addSubmonoid : AddSubmonoid α where + carrier := MulAction.fixedPoints M α + zero_mem' := smul_zero + add_mem' ha hb _ := by rw [smul_add, ha, hb] + +@[simp] +lemma FixedPoints.mem_addSubmonoid (a : α) : a ∈ addSubmonoid M α ↔ ∀ m : M, m • a = a := + Iff.rfl + +end AddMonoid + +section AddGroup + +variable [AddGroup α] [DistribMulAction M α] + +/-- The additive subgroup of elements fixed under the whole action. -/ +def FixedPoints.addSubgroup : AddSubgroup α where + __ := addSubmonoid M α + neg_mem' ha _ := by rw [smul_neg, ha] + +/-- The notation for `FixedPoints.addSubgroup`, chosen to resemble `αᴹ`. -/ +notation α "^+" M:51 => FixedPoints.addSubgroup M α + +@[simp] +lemma FixedPoints.mem_addSubgroup (a : α) : a ∈ α^+M ↔ ∀ m : M, m • a = a := + Iff.rfl + +@[simp] +lemma FixedPoints.addSubgroup_toAddSubmonoid : (α^+M).toAddSubmonoid = addSubmonoid M α := + rfl + +end AddGroup + +end FixedPoints + +namespace MulAction +variable {G α β : Type*} [Group G] [MulAction G α] [MulAction G β] + +section Orbit + +@[to_additive (attr := simp)] +theorem orbit_smul (g : G) (a : α) : orbit G (g • a) = orbit G a := + (orbit_smul_subset g a).antisymm <| + calc + orbit G a = orbit G (g⁻¹ • g • a) := by rw [inv_smul_smul] + _ ⊆ orbit G (g • a) := orbit_smul_subset _ _ + +@[to_additive] +theorem orbit_eq_iff {a b : α} : orbit G a = orbit G b ↔ a ∈ orbit G b := + ⟨fun h => h ▸ mem_orbit_self _, fun ⟨_, hc⟩ => hc ▸ orbit_smul _ _⟩ + +@[to_additive] +theorem mem_orbit_smul (g : G) (a : α) : a ∈ orbit G (g • a) := by + simp only [orbit_smul, mem_orbit_self] + +@[to_additive] +theorem smul_mem_orbit_smul (g h : G) (a : α) : g • a ∈ orbit G (h • a) := by + simp only [orbit_smul, mem_orbit] + +@[to_additive] +instance instMulAction (H : Subgroup G) : MulAction H α := + inferInstanceAs (MulAction H.toSubmonoid α) + +@[to_additive] +lemma orbit_subgroup_subset (H : Subgroup G) (a : α) : orbit H a ⊆ orbit G a := + orbit_submonoid_subset H.toSubmonoid a + +@[to_additive] +lemma mem_orbit_of_mem_orbit_subgroup {H : Subgroup G} {a b : α} (h : a ∈ orbit H b) : + a ∈ orbit G b := + orbit_subgroup_subset H _ h + +@[to_additive] +lemma mem_orbit_symm {a₁ a₂ : α} : a₁ ∈ orbit G a₂ ↔ a₂ ∈ orbit G a₁ := by + simp_rw [← orbit_eq_iff, eq_comm] + +@[to_additive] +lemma mem_subgroup_orbit_iff {H : Subgroup G} {x : α} {a b : orbit G x} : + a ∈ MulAction.orbit H b ↔ (a : α) ∈ MulAction.orbit H (b : α) := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · rcases h with ⟨g, rfl⟩ + exact MulAction.mem_orbit _ g + · rcases h with ⟨g, h⟩ + dsimp at h + erw [← orbit.coe_smul, ← Subtype.ext_iff] at h + subst h + exact MulAction.mem_orbit _ g + +variable (G α) + +/-- The relation 'in the same orbit'. -/ +@[to_additive "The relation 'in the same orbit'."] +def orbitRel : Setoid α where + r a b := a ∈ orbit G b + iseqv := + ⟨mem_orbit_self, fun {a b} => by simp [orbit_eq_iff.symm, eq_comm], fun {a b} => by + simp (config := { contextual := true }) [orbit_eq_iff.symm, eq_comm]⟩ + +variable {G α} + +@[to_additive] +theorem orbitRel_apply {a b : α} : orbitRel G α a b ↔ a ∈ orbit G b := + Iff.rfl + +@[to_additive (attr := deprecated (since := "2024-10-18"))] +alias orbitRel_r_apply := orbitRel_apply + +/-- When you take a set `U` in `α`, push it down to the quotient, and pull back, you get the union +of the orbit of `U` under `G`. -/ +@[to_additive + "When you take a set `U` in `α`, push it down to the quotient, and pull back, you get the + union of the orbit of `U` under `G`."] +theorem quotient_preimage_image_eq_union_mul (U : Set α) : + letI := orbitRel G α + Quotient.mk' ⁻¹' (Quotient.mk' '' U) = ⋃ g : G, (g • ·) '' U := by + letI := orbitRel G α + set f : α → Quotient (MulAction.orbitRel G α) := Quotient.mk' + ext a + constructor + · rintro ⟨b, hb, hab⟩ + obtain ⟨g, rfl⟩ := Quotient.exact hab + rw [Set.mem_iUnion] + exact ⟨g⁻¹, g • a, hb, inv_smul_smul g a⟩ + · intro hx + rw [Set.mem_iUnion] at hx + obtain ⟨g, u, hu₁, hu₂⟩ := hx + rw [Set.mem_preimage, Set.mem_image] + refine ⟨g⁻¹ • a, ?_, by simp only [f, Quotient.eq']; use g⁻¹⟩ + rw [← hu₂] + convert hu₁ + simp only [inv_smul_smul] + +@[to_additive] +theorem disjoint_image_image_iff {U V : Set α} : + letI := orbitRel G α + Disjoint (Quotient.mk' '' U) (Quotient.mk' '' V) ↔ ∀ x ∈ U, ∀ g : G, g • x ∉ V := by + letI := orbitRel G α + set f : α → Quotient (MulAction.orbitRel G α) := Quotient.mk' + refine + ⟨fun h a a_in_U g g_in_V => + h.le_bot ⟨⟨a, a_in_U, Quotient.sound ⟨g⁻¹, ?_⟩⟩, ⟨g • a, g_in_V, rfl⟩⟩, ?_⟩ + · simp + · intro h + rw [Set.disjoint_left] + rintro _ ⟨b, hb₁, hb₂⟩ ⟨c, hc₁, hc₂⟩ + obtain ⟨g, rfl⟩ := Quotient.exact (hc₂.trans hb₂.symm) + exact h b hb₁ g hc₁ + +@[to_additive] +theorem image_inter_image_iff (U V : Set α) : + letI := orbitRel G α + Quotient.mk' '' U ∩ Quotient.mk' '' V = ∅ ↔ ∀ x ∈ U, ∀ g : G, g • x ∉ V := + Set.disjoint_iff_inter_eq_empty.symm.trans disjoint_image_image_iff + +variable (G α) + +/-- The quotient by `MulAction.orbitRel`, given a name to enable dot notation. -/ +@[to_additive + "The quotient by `AddAction.orbitRel`, given a name to enable dot notation."] +abbrev orbitRel.Quotient : Type _ := + _root_.Quotient <| orbitRel G α + +variable {G α} + +/-- The orbit corresponding to an element of the quotient by `MulAction.orbitRel` -/ +@[to_additive "The orbit corresponding to an element of the quotient by `AddAction.orbitRel`"] +nonrec def orbitRel.Quotient.orbit (x : orbitRel.Quotient G α) : Set α := + Quotient.liftOn' x (orbit G) fun _ _ => MulAction.orbit_eq_iff.2 + +@[to_additive (attr := simp)] +theorem orbitRel.Quotient.orbit_mk (a : α) : + orbitRel.Quotient.orbit (Quotient.mk'' a : orbitRel.Quotient G α) = MulAction.orbit G a := + rfl + +@[to_additive] +theorem orbitRel.Quotient.mem_orbit {a : α} {x : orbitRel.Quotient G α} : + a ∈ x.orbit ↔ Quotient.mk'' a = x := by + induction x using Quotient.inductionOn' + rw [Quotient.eq''] + rfl + +/-- Note that `hφ = Quotient.out_eq'` is a useful choice here. -/ +@[to_additive "Note that `hφ = Quotient.out_eq'` is a useful choice here."] +theorem orbitRel.Quotient.orbit_eq_orbit_out (x : orbitRel.Quotient G α) + {φ : orbitRel.Quotient G α → α} (hφ : letI := orbitRel G α; RightInverse φ Quotient.mk') : + orbitRel.Quotient.orbit x = MulAction.orbit G (φ x) := by + conv_lhs => rw [← hφ x] + rfl + +@[to_additive] +lemma orbitRel.Quotient.orbit_injective : + Injective (orbitRel.Quotient.orbit : orbitRel.Quotient G α → Set α) := by + intro x y h + simp_rw [orbitRel.Quotient.orbit_eq_orbit_out _ Quotient.out_eq', orbit_eq_iff, + ← orbitRel_apply] at h + simpa [← Quotient.eq''] using h + +@[to_additive (attr := simp)] +lemma orbitRel.Quotient.orbit_inj {x y : orbitRel.Quotient G α} : x.orbit = y.orbit ↔ x = y := + orbitRel.Quotient.orbit_injective.eq_iff + +@[to_additive] +lemma orbitRel.quotient_eq_of_quotient_subgroup_eq {H : Subgroup G} {a b : α} + (h : (⟦a⟧ : orbitRel.Quotient H α) = ⟦b⟧) : (⟦a⟧ : orbitRel.Quotient G α) = ⟦b⟧ := by + rw [@Quotient.eq] at h ⊢ + exact mem_orbit_of_mem_orbit_subgroup h + +@[to_additive] +lemma orbitRel.quotient_eq_of_quotient_subgroup_eq' {H : Subgroup G} {a b : α} + (h : (Quotient.mk'' a : orbitRel.Quotient H α) = Quotient.mk'' b) : + (Quotient.mk'' a : orbitRel.Quotient G α) = Quotient.mk'' b := + orbitRel.quotient_eq_of_quotient_subgroup_eq h + +@[to_additive] +nonrec lemma orbitRel.Quotient.orbit_nonempty (x : orbitRel.Quotient G α) : + Set.Nonempty x.orbit := by + rw [orbitRel.Quotient.orbit_eq_orbit_out x Quotient.out_eq'] + exact orbit_nonempty _ + +@[to_additive] +nonrec lemma orbitRel.Quotient.mapsTo_smul_orbit (g : G) (x : orbitRel.Quotient G α) : + Set.MapsTo (g • ·) x.orbit x.orbit := by + rw [orbitRel.Quotient.orbit_eq_orbit_out x Quotient.out_eq'] + exact mapsTo_smul_orbit g x.out' + +@[to_additive] +instance (x : orbitRel.Quotient G α) : MulAction G x.orbit where + smul g := (orbitRel.Quotient.mapsTo_smul_orbit g x).restrict _ _ _ + one_smul a := Subtype.ext (one_smul G (a : α)) + mul_smul g g' a' := Subtype.ext (mul_smul g g' (a' : α)) + +@[to_additive (attr := simp)] +lemma orbitRel.Quotient.orbit.coe_smul {g : G} {x : orbitRel.Quotient G α} {a : x.orbit} : + ↑(g • a) = g • (a : α) := + rfl + +@[to_additive (attr := norm_cast, simp)] +lemma orbitRel.Quotient.mem_subgroup_orbit_iff {H : Subgroup G} {x : orbitRel.Quotient G α} + {a b : x.orbit} : (a : α) ∈ MulAction.orbit H (b : α) ↔ a ∈ MulAction.orbit H b := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · rcases h with ⟨g, h⟩ + dsimp at h + erw [← orbit.coe_smul, ← Subtype.ext_iff] at h + subst h + exact MulAction.mem_orbit _ g + · rcases h with ⟨g, rfl⟩ + exact MulAction.mem_orbit _ g + +@[to_additive] +lemma orbitRel.Quotient.subgroup_quotient_eq_iff {H : Subgroup G} {x : orbitRel.Quotient G α} + {a b : x.orbit} : (⟦a⟧ : orbitRel.Quotient H x.orbit) = ⟦b⟧ ↔ + (⟦↑a⟧ : orbitRel.Quotient H α) = ⟦↑b⟧ := by + simp_rw [← @Quotient.mk''_eq_mk, Quotient.eq''] + exact orbitRel.Quotient.mem_subgroup_orbit_iff.symm + +@[to_additive] +lemma orbitRel.Quotient.mem_subgroup_orbit_iff' {H : Subgroup G} {x : orbitRel.Quotient G α} + {a b : x.orbit} {c : α} (h : (⟦a⟧ : orbitRel.Quotient H x.orbit) = ⟦b⟧) : + (a : α) ∈ MulAction.orbit H c ↔ (b : α) ∈ MulAction.orbit H c := by + simp_rw [mem_orbit_symm (a₂ := c)] + convert Iff.rfl using 2 + rw [orbit_eq_iff] + suffices hb : ↑b ∈ orbitRel.Quotient.orbit (⟦a⟧ : orbitRel.Quotient H x.orbit) by + rw [orbitRel.Quotient.orbit_eq_orbit_out (⟦a⟧ : orbitRel.Quotient H x.orbit) Quotient.out_eq'] + at hb + rw [orbitRel.Quotient.mem_subgroup_orbit_iff] + convert hb using 1 + rw [orbit_eq_iff, ← orbitRel_apply, ← Quotient.eq'', Quotient.out_eq', @Quotient.mk''_eq_mk] + rw [orbitRel.Quotient.mem_orbit, h, @Quotient.mk''_eq_mk] + +variable (G) (α) + +local notation "Ω" => orbitRel.Quotient G α + +/-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. + +This version is expressed in terms of `MulAction.orbitRel.Quotient.orbit` instead of +`MulAction.orbit`, to avoid mentioning `Quotient.out'`. -/ +@[to_additive + "Decomposition of a type `X` as a disjoint union of its orbits under an additive group action. + + This version is expressed in terms of `AddAction.orbitRel.Quotient.orbit` instead of + `AddAction.orbit`, to avoid mentioning `Quotient.out'`. "] +def selfEquivSigmaOrbits' : α ≃ Σω : Ω, ω.orbit := + letI := orbitRel G α + calc + α ≃ Σω : Ω, { a // Quotient.mk' a = ω } := (Equiv.sigmaFiberEquiv Quotient.mk').symm + _ ≃ Σω : Ω, ω.orbit := + Equiv.sigmaCongrRight fun _ => + Equiv.subtypeEquivRight fun _ => orbitRel.Quotient.mem_orbit.symm + +/-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. -/ +@[to_additive + "Decomposition of a type `X` as a disjoint union of its orbits under an additive group + action."] +def selfEquivSigmaOrbits : α ≃ Σω : Ω, orbit G ω.out' := + (selfEquivSigmaOrbits' G α).trans <| + Equiv.sigmaCongrRight fun _ => + Equiv.Set.ofEq <| orbitRel.Quotient.orbit_eq_orbit_out _ Quotient.out_eq' + +/-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. +Phrased as a set union. See `MulAction.selfEquivSigmaOrbits` for the type isomorphism. -/ +@[to_additive "Decomposition of a type `X` as a disjoint union of its orbits under an additive group +action. Phrased as a set union. See `AddAction.selfEquivSigmaOrbits` for the type isomorphism."] +lemma univ_eq_iUnion_orbit : + Set.univ (α := α) = ⋃ x : Ω, x.orbit := by + ext x + simp only [Set.mem_univ, Set.mem_iUnion, true_iff] + exact ⟨Quotient.mk'' x, by simp⟩ + +end Orbit + +section Stabilizer +variable (G) + +/-- The stabilizer of an element under an action, i.e. what sends the element to itself. +A subgroup. -/ +@[to_additive + "The stabilizer of an element under an action, i.e. what sends the element to itself. + An additive subgroup."] +def stabilizer (a : α) : Subgroup G := + { stabilizerSubmonoid G a with + inv_mem' := fun {m} (ha : m • a = a) => show m⁻¹ • a = a by rw [inv_smul_eq_iff, ha] } + +variable {G} + +@[to_additive] +instance [DecidableEq α] (a : α) : DecidablePred (· ∈ stabilizer G a) := + fun _ => inferInstanceAs <| Decidable (_ = _) + +@[to_additive (attr := simp)] +theorem mem_stabilizer_iff {a : α} {g : G} : g ∈ stabilizer G a ↔ g • a = a := + Iff.rfl + +@[to_additive] +lemma le_stabilizer_smul_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) : + stabilizer G a ≤ stabilizer G (a • b) := by + simp_rw [SetLike.le_def, mem_stabilizer_iff, ← smul_assoc]; rintro a h; rw [h] + +-- This lemma does not need `MulAction G α`, only `SMul G α`. +-- We use `G'` instead of `G` to locally reduce the typeclass assumptions. +@[to_additive] +lemma le_stabilizer_smul_right {G'} [Group G'] [SMul α β] [MulAction G' β] + [SMulCommClass G' α β] (a : α) (b : β) : + stabilizer G' b ≤ stabilizer G' (a • b) := by + simp_rw [SetLike.le_def, mem_stabilizer_iff, smul_comm]; rintro a h; rw [h] + +@[to_additive (attr := simp)] +lemma stabilizer_smul_eq_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) + (h : Injective (· • b : α → β)) : stabilizer G (a • b) = stabilizer G a := by + refine (le_stabilizer_smul_left _ _).antisymm' fun a ha ↦ ?_ + simpa only [mem_stabilizer_iff, ← smul_assoc, h.eq_iff] using ha + +@[to_additive (attr := simp)] +lemma stabilizer_smul_eq_right {α} [Group α] [MulAction α β] [SMulCommClass G α β] (a : α) (b : β) : + stabilizer G (a • b) = stabilizer G b := + (le_stabilizer_smul_right _ _).antisymm' <| (le_stabilizer_smul_right a⁻¹ _).trans_eq <| by + rw [inv_smul_smul] + +@[to_additive (attr := simp)] +lemma stabilizer_mul_eq_left [Group α] [IsScalarTower G α α] (a b : α) : + stabilizer G (a * b) = stabilizer G a := stabilizer_smul_eq_left a _ <| mul_left_injective _ + +@[to_additive (attr := simp)] +lemma stabilizer_mul_eq_right [Group α] [SMulCommClass G α α] (a b : α) : + stabilizer G (a * b) = stabilizer G b := stabilizer_smul_eq_right a _ + +end Stabilizer + +end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean b/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean index d780cdee10131..9e0ab1536c2d5 100644 --- a/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Opposite import Mathlib.Algebra.Group.Pi.Lemmas +import Mathlib.Algebra.Group.Action.Faithful import Mathlib.Algebra.GroupWithZero.Action.Defs import Mathlib.Algebra.Ring.Defs diff --git a/Mathlib/GroupTheory/GroupAction/FixedPoints.lean b/Mathlib/GroupTheory/GroupAction/FixedPoints.lean index 070b3e8dd30e2..214c7c2f51a38 100644 --- a/Mathlib/GroupTheory/GroupAction/FixedPoints.lean +++ b/Mathlib/GroupTheory/GroupAction/FixedPoints.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Emilie Burgun -/ import Mathlib.Algebra.Group.Commute.Basic -import Mathlib.GroupTheory.GroupAction.Basic -import Mathlib.Dynamics.PeriodicPts import Mathlib.Data.Set.Pointwise.SMul +import Mathlib.Dynamics.PeriodicPts +import Mathlib.GroupTheory.GroupAction.Defs /-! # Properties of `fixedPoints` and `fixedBy` @@ -237,7 +237,7 @@ then `fixedBy α m = Set.univ` implies that `m = 1`. -/ then `fixedBy α m = Set.univ` implies that `m = 1`."] theorem fixedBy_eq_univ_iff_eq_one {m : M} : fixedBy α m = Set.univ ↔ m = 1 := by rw [← (smul_left_injective' (M := M) (α := α)).eq_iff, Set.eq_univ_iff_forall] - simp_rw [Function.funext_iff, one_smul, mem_fixedBy] + simp_rw [funext_iff, one_smul, mem_fixedBy] /-- If the image of the `(fixedBy α g)ᶜ` set by the pointwise action of `h: G` diff --git a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean index afcac247ac820..f968df45e92a9 100644 --- a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean +++ b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Antoine Chambert-Loir. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Antoine Chambert-Loir -/ -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.GroupTheory.GroupAction.FixedPoints /-! diff --git a/Mathlib/GroupTheory/GroupAction/Hom.lean b/Mathlib/GroupTheory/GroupAction/Hom.lean index 2a9db62dd963a..962885a423eb3 100644 --- a/Mathlib/GroupTheory/GroupAction/Hom.lean +++ b/Mathlib/GroupTheory/GroupAction/Hom.lean @@ -2,7 +2,6 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Antoine Chambert-Loir - -/ import Mathlib.Algebra.Module.Defs @@ -357,9 +356,6 @@ abbrev DistribMulActionHomClass (F : Type*) (M : outParam Type*) [DistribMulAction M A] [DistribMulAction M B] [FunLike F A B] := DistribMulActionSemiHomClass F (MonoidHom.id M) A B -/- porting note: Removed a @[nolint dangerousInstance] for -DistribMulActionHomClass.toAddMonoidHomClass not dangerous due to `outParam`s -/ - namespace DistribMulActionHom /- Porting note (#11215): TODO decide whether the next two instances should be removed @@ -525,13 +521,10 @@ def inverse (f : A →+[M] B₁) (g : B₁ → A) (h₁ : Function.LeftInverse g section Semiring variable (R : Type*) [Semiring R] [MulSemiringAction M R] -variable (R' : Type*) [Ring R'] [MulSemiringAction M R'] variable (S : Type*) [Semiring S] [MulSemiringAction N S] -variable (S' : Type*) [Ring S'] [MulSemiringAction N S'] variable (T : Type*) [Semiring T] [MulSemiringAction P T] -variable {R S M' N'} -variable [AddMonoid M'] [DistribMulAction R M'] +variable {R S N'} variable [AddMonoid N'] [DistribMulAction S N'] variable {σ : R →* S} @@ -605,9 +598,6 @@ abbrev MulSemiringActionHomClass [DistribMulAction M R] [DistribMulAction M S] [FunLike F R S] := MulSemiringActionSemiHomClass F (MonoidHom.id M) R S -/- porting note: Removed a @[nolint dangerousInstance] for MulSemiringActionHomClass.toRingHomClass - not dangerous due to outParam -/ - namespace MulSemiringActionHom /- Porting note (#11215): TODO decide whether the next two instances should be removed diff --git a/Mathlib/GroupTheory/GroupAction/Quotient.lean b/Mathlib/GroupTheory/GroupAction/Quotient.lean index 2cdd8bb08b134..efb12ad49b6fa 100644 --- a/Mathlib/GroupTheory/GroupAction/Quotient.lean +++ b/Mathlib/GroupTheory/GroupAction/Quotient.lean @@ -5,11 +5,13 @@ Authors: Chris Hughes, Thomas Browning -/ import Mathlib.Data.Fintype.BigOperators import Mathlib.Dynamics.PeriodicPts +import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.ConjAct import Mathlib.GroupTheory.GroupAction.Hom import Mathlib.GroupTheory.Coset.Basic import Mathlib.GroupTheory.Commutator.Basic import Mathlib.Algebra.Group.Subgroup.Actions +import Mathlib.Data.Finite.Prod /-! # Properties of group actions involving quotient groups @@ -157,7 +159,7 @@ noncomputable def orbitEquivQuotientStabilizer (b : β) : orbit α b ≃ α ⧸ Equiv.symm <| Equiv.ofBijective (fun g => ⟨ofQuotientStabilizer α b g, ofQuotientStabilizer_mem_orbit α b g⟩) ⟨fun x y hxy => injective_ofQuotientStabilizer α b (by convert congr_arg Subtype.val hxy), - fun ⟨b, ⟨g, hgb⟩⟩ => ⟨g, Subtype.eq hgb⟩⟩ + fun ⟨_, ⟨g, hgb⟩⟩ => ⟨g, Subtype.eq hgb⟩⟩ /-- Orbit-stabilizer theorem. -/ @[to_additive AddAction.orbitProdStabilizerEquivAddGroup "Orbit-stabilizer theorem."] @@ -319,17 +321,16 @@ noncomputable def equivSubgroupOrbitsSetoidComap (H : Subgroup α) (ω : Ω) : toFun := fun q ↦ q.liftOn' (fun x ↦ ⟦⟨↑x, by simp only [Set.mem_preimage, Set.mem_singleton_iff] have hx := x.property - rwa [orbitRel.Quotient.mem_orbit, @Quotient.mk''_eq_mk] at hx⟩⟧) fun a b h ↦ by - simp only [← Quotient.eq'', Quotient.mk''_eq_mk, + rwa [orbitRel.Quotient.mem_orbit] at hx⟩⟧) fun a b h ↦ by + simp only [← Quotient.eq, orbitRel.Quotient.subgroup_quotient_eq_iff] at h - simp only [← Quotient.mk''_eq_mk, Quotient.eq''] at h ⊢ + simp only [Quotient.eq] at h ⊢ exact h invFun := fun q ↦ q.liftOn' (fun x ↦ ⟦⟨↑x, by have hx := x.property simp only [Set.mem_preimage, Set.mem_singleton_iff] at hx rwa [orbitRel.Quotient.mem_orbit, @Quotient.mk''_eq_mk]⟩⟧) fun a b h ↦ by - change Setoid.Rel _ _ _ at h - rw [Setoid.comap_rel, Setoid.Rel, ← Quotient.eq'', @Quotient.mk''_eq_mk] at h + rw [Setoid.comap_rel, ← Quotient.eq'', @Quotient.mk''_eq_mk] at h simp only [orbitRel.Quotient.subgroup_quotient_eq_iff] exact h left_inv := by @@ -372,7 +373,7 @@ noncomputable def equivSubgroupOrbitsQuotientGroup [IsPretransitive α β] orbitRel.Quotient H β ≃ α ⧸ H where toFun := fun q ↦ q.liftOn' (fun y ↦ (exists_smul_eq α y x).choose) (by intro y₁ y₂ h - rw [orbitRel_r_apply] at h + rw [orbitRel_apply] at h rw [Quotient.eq'', leftRel_eq] dsimp only rcases h with ⟨g, rfl⟩ @@ -388,12 +389,12 @@ noncomputable def equivSubgroupOrbitsQuotientGroup [IsPretransitive α β] intro g₁ g₂ h rw [leftRel_eq] at h simp only - rw [← @Quotient.mk''_eq_mk, Quotient.eq'', orbitRel_r_apply] + rw [← @Quotient.mk''_eq_mk, Quotient.eq'', orbitRel_apply] exact ⟨⟨_, h⟩, by simp [mul_smul]⟩) left_inv := fun y ↦ by induction' y using Quotient.inductionOn' with y simp only [Quotient.liftOn'_mk''] - rw [← @Quotient.mk''_eq_mk, Quotient.eq'', orbitRel_r_apply] + rw [← @Quotient.mk''_eq_mk, Quotient.eq'', orbitRel_apply] convert mem_orbit_self _ rw [inv_smul_eq_iff, (exists_smul_eq α y x).choose_spec] right_inv := fun g ↦ by @@ -404,12 +405,6 @@ noncomputable def equivSubgroupOrbitsQuotientGroup [IsPretransitive α β] convert one_mem H · rw [inv_mul_eq_one, eq_comm, ← inv_mul_eq_one, ← Subgroup.mem_bot, ← free (g⁻¹ • x), mem_stabilizer_iff, mul_smul, (exists_smul_eq α (g⁻¹ • x) x).choose_spec] - #adaptation_note - /-- - After https://github.com/leanprover/lean4/pull/5376 we need to search for this instance explicitly. - TODO: change `convert` to more agressively solve such goals with `infer_instance` itself. - -/ - infer_instance end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/SubMulAction.lean b/Mathlib/GroupTheory/GroupAction/SubMulAction.lean index 6f4c858afeb02..3f4e9a445929f 100644 --- a/Mathlib/GroupTheory/GroupAction/SubMulAction.lean +++ b/Mathlib/GroupTheory/GroupAction/SubMulAction.lean @@ -5,7 +5,8 @@ Authors: Eric Wieser -/ import Mathlib.Algebra.Module.Defs import Mathlib.Data.SetLike.Basic -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Data.Setoid.Basic +import Mathlib.GroupTheory.GroupAction.Defs import Mathlib.GroupTheory.GroupAction.Hom /-! diff --git a/Mathlib/GroupTheory/GroupAction/Support.lean b/Mathlib/GroupTheory/GroupAction/Support.lean index 392881eb03ad9..bda425911ec09 100644 --- a/Mathlib/GroupTheory/GroupAction/Support.lean +++ b/Mathlib/GroupTheory/GroupAction/Support.lean @@ -44,7 +44,7 @@ theorem Supports.mono (h : s ⊆ t) (hs : Supports G s b) : Supports G t b := fu end SMul variable [Group H] [SMul G α] [SMul G β] [MulAction H α] [SMul H β] [SMulCommClass G H β] - [SMulCommClass G H α] {s t : Set α} {b : β} + [SMulCommClass G H α] {s : Set α} {b : β} -- TODO: This should work without `SMulCommClass` @[to_additive] diff --git a/Mathlib/GroupTheory/HNNExtension.lean b/Mathlib/GroupTheory/HNNExtension.lean index d4c6a1677d248..a4d0b7d277511 100644 --- a/Mathlib/GroupTheory/HNNExtension.lean +++ b/Mathlib/GroupTheory/HNNExtension.lean @@ -174,7 +174,7 @@ namespace NormalWord variable (G A B) /-- To put word in the HNN Extension into a normal form, we must choose an element of each right coset of both `A` and `B`, such that the chosen element of the subgroup itself is `1`. -/ -structure TransversalPair : Type _ := +structure TransversalPair : Type _ where /-- The transversal of each subgroup -/ set : ℤˣ → Set G /-- We have exactly one element of each coset of the subgroup -/ @@ -187,7 +187,7 @@ instance TransversalPair.nonempty : Nonempty (TransversalPair G A B) := by /-- A reduced word is a `head`, which is an element of `G`, followed by the product list of pairs. There should also be no sequences of the form `t^u * g * t^-u`, where `g` is in `toSubgroup A B u` This is a less strict condition than required for `NormalWord`. -/ -structure ReducedWord : Type _ := +structure ReducedWord : Type _ where /-- Every `ReducedWord` is the product of an element of the group and a word made up of letters each of which is in the transversal. `head` is that element of the base group. -/ head : G @@ -215,7 +215,7 @@ The normal form is a `head`, which is an element of `G`, followed by the product `toSubgroup A B u`. There should also be no sequences of the form `t^u * g * t^-u` where `g ∈ toSubgroup A B u` -/ structure _root_.HNNExtension.NormalWord (d : TransversalPair G A B) - extends ReducedWord G A B : Type _ := + extends ReducedWord G A B : Type _ where /-- Every element `g : G` in the list is the chosen element of its coset -/ mem_set : ∀ (u : ℤˣ) (g : G), (u, g) ∈ toList → g ∈ d.set u @@ -356,7 +356,7 @@ def Cancels (u : ℤˣ) (w : NormalWord d) : Prop := def unitsSMulWithCancel (u : ℤˣ) (w : NormalWord d) : Cancels u w → NormalWord d := consRecOn w (by simp [Cancels, ofGroup]; tauto) - (fun g u' w h1 h2 _ can => + (fun g _ w _ _ _ can => (toSubgroupEquiv φ u ⟨g, can.1⟩ : G) • w) /-- Multiplying `t^u` by a `NormalWord`, `w` and putting the result in normal form. -/ @@ -595,7 +595,7 @@ theorem of_injective : Function.Injective (of : G → HNNExtension G A B φ) := (f := ((· • ·) : HNNExtension G A B φ → NormalWord d → NormalWord d)) ?_ intros _ _ h exact eq_of_smul_eq_smul (fun w : NormalWord d => - by simp_all [Function.funext_iff, of_smul_eq_smul]) + by simp_all [funext_iff, of_smul_eq_smul]) namespace ReducedWord diff --git a/Mathlib/GroupTheory/Index.lean b/Mathlib/GroupTheory/Index.lean index 9085d649c8d8c..38d3dbe061cf8 100644 --- a/Mathlib/GroupTheory/Index.lean +++ b/Mathlib/GroupTheory/Index.lean @@ -3,11 +3,13 @@ Copyright (c) 2021 Thomas Browning. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ -import Mathlib.Data.Finite.Card import Mathlib.Algebra.BigOperators.GroupWithZero.Finset +import Mathlib.Data.Finite.Card +import Mathlib.Data.Set.Card import Mathlib.GroupTheory.Coset.Card import Mathlib.GroupTheory.Finiteness import Mathlib.GroupTheory.GroupAction.Quotient +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # Index of a Subgroup @@ -30,7 +32,7 @@ Several theorems proved in this file are known as Lagrange's theorem. - `relindex_mul_index` : If `H ≤ K`, then `H.relindex K * K.index = H.index` - `index_dvd_of_le` : If `H ≤ K`, then `K.index ∣ H.index` - `relindex_mul_relindex` : `relindex` is multiplicative in towers - +- `MulAction.index_stabilizer`: the index of the stabilizer is the cardinality of the orbit -/ @@ -56,9 +58,8 @@ noncomputable def relindex : ℕ := @[to_additive] theorem index_comap_of_surjective {f : G' →* G} (hf : Function.Surjective f) : (H.comap f).index = H.index := by - letI := QuotientGroup.leftRel H - letI := QuotientGroup.leftRel (H.comap f) - have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by + have key : ∀ x y : G', + QuotientGroup.leftRel (H.comap f) x y ↔ QuotientGroup.leftRel H (f x) (f y) := by simp only [QuotientGroup.leftRel_apply] exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv])) refine Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨?_, ?_⟩) @@ -449,6 +450,21 @@ lemma pow_mem_of_relindex_ne_zero_of_dvd (h : H.relindex K ≠ 0) {a : G} (ha : convert pow_mem_of_index_ne_zero_of_dvd h ⟨a, ha⟩ hn simp [pow_mem ha, mem_subgroupOf] +@[to_additive (attr := simp)] +lemma index_prod (H : Subgroup G) (K : Subgroup G') : (H.prod K).index = H.index * K.index := by + simp_rw [index, ← Nat.card_prod] + refine Nat.card_congr + ((Quotient.congrRight (fun x y ↦ ?_)).trans (Setoid.prodQuotientEquiv _ _).symm) + rw [QuotientGroup.leftRel_prod] + +@[to_additive (attr := simp)] +lemma index_pi {ι : Type*} [Fintype ι] (H : ι → Subgroup G) : + (Subgroup.pi Set.univ H).index = ∏ i, (H i).index := by + simp_rw [index, ← Nat.card_pi] + refine Nat.card_congr + ((Quotient.congrRight (fun x y ↦ ?_)).trans (Setoid.piQuotientEquiv _).symm) + rw [QuotientGroup.leftRel_pi] + @[simp] lemma index_toAddSubgroup : (Subgroup.toAddSubgroup H).index = H.index := rfl @@ -559,6 +575,21 @@ end FiniteIndex end Subgroup +namespace MulAction + +variable (G : Type*) {X : Type*} [Group G] [MulAction G X] (x : X) + +theorem index_stabilizer : + (stabilizer G x).index = (orbit G x).ncard := + (Nat.card_congr (MulAction.orbitEquivQuotientStabilizer G x)).symm.trans + (Set.Nat.card_coe_set_eq (orbit G x)) + +theorem index_stabilizer_of_transitive [IsPretransitive G X] : + (stabilizer G x).index = Nat.card X := by + rw [index_stabilizer, orbit_eq_univ, Set.ncard_univ] + +end MulAction + namespace MonoidHom open Finset @@ -568,7 +599,7 @@ variable {G M F : Type*} [Group G] [Fintype G] [Monoid M] [DecidableEq M] @[to_additive] lemma card_fiber_eq_of_mem_range (f : F) {x y : M} (hx : x ∈ Set.range f) (hy : y ∈ Set.range f) : - (univ.filter <| fun g => f g = x).card = (univ.filter <| fun g => f g = y).card := by + #{g | f g = x} = #{g | f g = y} := by rcases hx with ⟨x, rfl⟩ rcases hy with ⟨y, rfl⟩ rcases mul_left_surjective x y with ⟨y, rfl⟩ diff --git a/Mathlib/GroupTheory/MonoidLocalization/Away.lean b/Mathlib/GroupTheory/MonoidLocalization/Away.lean new file mode 100644 index 0000000000000..e64618255bc9d --- /dev/null +++ b/Mathlib/GroupTheory/MonoidLocalization/Away.lean @@ -0,0 +1,172 @@ +/- +Copyright (c) 2019 Amelia Livingston. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Amelia Livingston +-/ +import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.GroupTheory.MonoidLocalization.Basic + +/-! +# Localizing commutative monoids away from an alement + +We treat the special case of localizing away from an element in the sections +`AwayMap` and `Away`. + +## Tags +localization, monoid localization, quotient monoid, congruence relation, characteristic predicate, +commutative monoid, grothendieck group +-/ + +open Function + +section CommMonoid + +variable {M : Type*} [CommMonoid M] {S : Submonoid M} {N : Type*} [CommMonoid N] {P : Type*} + [CommMonoid P] + +namespace Submonoid + +namespace LocalizationMap + +section AwayMap + +variable {g : M →* P} (hg : ∀ y : S, IsUnit (g y)) +variable (x : M) + +/-- Given `x : M`, the type of `CommMonoid` homomorphisms `f : M →* N` such that `N` +is isomorphic to the Localization of `M` at the Submonoid generated by `x`. -/ +@[to_additive + "Given `x : M`, the type of `AddCommMonoid` homomorphisms `f : M →+ N` such that `N` +is isomorphic to the localization of `M` at the AddSubmonoid generated by `x`."] +abbrev AwayMap (N' : Type*) [CommMonoid N'] := LocalizationMap (powers x) N' + +variable (F : AwayMap x N) + +/-- Given `x : M` and a Localization map `F : M →* N` away from `x`, `invSelf` is `(F x)⁻¹`. -/ +noncomputable def AwayMap.invSelf : N := F.mk' 1 ⟨x, mem_powers _⟩ + +/-- Given `x : M`, a Localization map `F : M →* N` away from `x`, and a map of `CommMonoid`s +`g : M →* P` such that `g x` is invertible, the homomorphism induced from `N` to `P` sending +`z : N` to `g y * (g x)⁻ⁿ`, where `y : M, n : ℕ` are such that `z = F y * (F x)⁻ⁿ`. -/ +noncomputable def AwayMap.lift (hg : IsUnit (g x)) : N →* P := + Submonoid.LocalizationMap.lift F fun y ↦ + show IsUnit (g y.1) by + obtain ⟨n, hn⟩ := y.2 + rw [← hn, g.map_pow] + exact IsUnit.pow n hg + +@[simp] +theorem AwayMap.lift_eq (hg : IsUnit (g x)) (a : M) : F.lift x hg (F.toMap a) = g a := + Submonoid.LocalizationMap.lift_eq _ _ _ + +@[simp] +theorem AwayMap.lift_comp (hg : IsUnit (g x)) : (F.lift x hg).comp F.toMap = g := + Submonoid.LocalizationMap.lift_comp _ _ + +/-- Given `x y : M` and Localization maps `F : M →* N, G : M →* P` away from `x` and `x * y` +respectively, the homomorphism induced from `N` to `P`. -/ +noncomputable def awayToAwayRight (y : M) (G : AwayMap (x * y) P) : N →* P := + F.lift x <| + show IsUnit (G.toMap x) from + isUnit_of_mul_eq_one (G.toMap x) (G.mk' y ⟨x * y, mem_powers _⟩) <| by + rw [mul_mk'_eq_mk'_of_mul, mk'_self] + +end AwayMap + +end LocalizationMap + +end Submonoid + +namespace AddSubmonoid + +namespace LocalizationMap + +section AwayMap + +variable {A : Type*} [AddCommMonoid A] (x : A) {B : Type*} [AddCommMonoid B] (F : AwayMap x B) + {C : Type*} [AddCommMonoid C] {g : A →+ C} + +/-- Given `x : A` and a Localization map `F : A →+ B` away from `x`, `neg_self` is `- (F x)`. -/ +noncomputable def AwayMap.negSelf : B := + F.mk' 0 ⟨x, mem_multiples _⟩ + +/-- Given `x : A`, a localization map `F : A →+ B` away from `x`, and a map of `AddCommMonoid`s +`g : A →+ C` such that `g x` is invertible, the homomorphism induced from `B` to `C` sending +`z : B` to `g y - n • g x`, where `y : A, n : ℕ` are such that `z = F y - n • F x`. -/ +noncomputable def AwayMap.lift (hg : IsAddUnit (g x)) : B →+ C := + AddSubmonoid.LocalizationMap.lift F fun y ↦ + show IsAddUnit (g y.1) by + obtain ⟨n, hn⟩ := y.2 + rw [← hn] + dsimp + rw [g.map_nsmul] + exact IsAddUnit.map (nsmulAddMonoidHom n : C →+ C) hg + +@[simp] +theorem AwayMap.lift_eq (hg : IsAddUnit (g x)) (a : A) : F.lift x hg (F.toMap a) = g a := + AddSubmonoid.LocalizationMap.lift_eq _ _ _ + +@[simp] +theorem AwayMap.lift_comp (hg : IsAddUnit (g x)) : (F.lift x hg).comp F.toMap = g := + AddSubmonoid.LocalizationMap.lift_comp _ _ + +/-- Given `x y : A` and Localization maps `F : A →+ B, G : A →+ C` away from `x` and `x + y` +respectively, the homomorphism induced from `B` to `C`. -/ +noncomputable def awayToAwayRight (y : A) (G : AwayMap (x + y) C) : B →+ C := + F.lift x <| + show IsAddUnit (G.toMap x) from + isAddUnit_of_add_eq_zero (G.toMap x) (G.mk' y ⟨x + y, mem_multiples _⟩) <| by + rw [add_mk'_eq_mk'_of_add, mk'_self] + +end AwayMap + +end LocalizationMap + +end AddSubmonoid + +namespace Localization + +section Away + +variable (x : M) + +/-- Given `x : M`, the Localization of `M` at the Submonoid generated by `x`, as a quotient. -/ +@[to_additive + "Given `x : M`, the Localization of `M` at the Submonoid generated by `x`, as a quotient."] +abbrev Away := + Localization (Submonoid.powers x) + +/-- Given `x : M`, `invSelf` is `x⁻¹` in the Localization (as a quotient type) of `M` at the +Submonoid generated by `x`. -/ +@[to_additive + "Given `x : M`, `negSelf` is `-x` in the Localization (as a quotient type) of `M` at the +Submonoid generated by `x`."] +def Away.invSelf : Away x := + mk 1 ⟨x, Submonoid.mem_powers _⟩ + +/-- Given `x : M`, the natural hom sending `y : M`, `M` a `CommMonoid`, to the equivalence class +of `(y, 1)` in the Localization of `M` at the Submonoid generated by `x`. -/ +@[to_additive + "Given `x : M`, the natural hom sending `y : M`, `M` an `AddCommMonoid`, to the equivalence +class of `(y, 0)` in the Localization of `M` at the Submonoid generated by `x`."] +abbrev Away.monoidOf : Submonoid.LocalizationMap.AwayMap x (Away x) := + Localization.monoidOf (Submonoid.powers x) + +@[to_additive] +theorem Away.mk_eq_monoidOf_mk' : mk = (Away.monoidOf x).mk' := by + simp [Localization.mk_eq_monoidOf_mk'] + +/-- Given `x : M` and a Localization map `f : M →* N` away from `x`, we get an isomorphism between +the Localization of `M` at the Submonoid generated by `x` as a quotient type and `N`. -/ +@[to_additive + "Given `x : M` and a Localization map `f : M →+ N` away from `x`, we get an isomorphism between +the Localization of `M` at the Submonoid generated by `x` as a quotient type and `N`."] +noncomputable def Away.mulEquivOfQuotient (f : Submonoid.LocalizationMap.AwayMap x N) : + Away x ≃* N := + Localization.mulEquivOfQuotient f + +end Away + +end Localization + +end CommMonoid diff --git a/Mathlib/GroupTheory/MonoidLocalization/Basic.lean b/Mathlib/GroupTheory/MonoidLocalization/Basic.lean index b5db348da57a7..6ad962c53ad34 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/Basic.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2019 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston -/ -import Mathlib.Algebra.Group.Submonoid.Membership -import Mathlib.GroupTheory.Congruence.Basic -import Mathlib.RingTheory.OreLocalization.Basic +import Mathlib.Algebra.Group.Submonoid.Defs +import Mathlib.GroupTheory.Congruence.Hom +import Mathlib.GroupTheory.OreLocalization.Basic /-! # Localizations of commutative monoids @@ -27,8 +27,7 @@ Given such a localization map `f : M →* N`, we can define the surjection maps elements of `S` to invertible elements of the codomain. Similarly, given commutative monoids `P, Q`, a submonoid `T` of `P` and a localization map for `T` from `P` to `Q`, then a homomorphism `g : M →* P` such that `g(S) ⊆ T` induces a homomorphism of localizations, `LocalizationMap.map`, -from `N` to `Q`. We treat the special case of localizing away from an element in the sections -`AwayMap` and `Away`. +from `N` to `Q`. We also define the quotient of `M × S` by the unique congruence relation (equivalence relation preserving a binary operation) `r` such that for any other congruence relation `s` on `M × S` @@ -74,6 +73,9 @@ localization, monoid localization, quotient monoid, congruence relation, charact commutative monoid, grothendieck group -/ +assert_not_exists MonoidWithZero +assert_not_exists Ring + open Function namespace AddSubmonoid @@ -268,8 +270,6 @@ theorem ndrec_mk {p : Localization S → Sort u} (f : ∀ (a : M) (b : S), p (mk /-- Non-dependent recursion principle for localizations: given elements `f a b : p` for all `a b`, such that `r S (a, b) (c, d)` implies `f a b = f c d`, then `f` is defined on the whole `Localization S`. -/ --- Porting note: the attribute `elab_as_elim` fails with `unexpected eliminator resulting type p` --- @[to_additive (attr := elab_as_elim) @[to_additive "Non-dependent recursion principle for `AddLocalization`s: given elements `f a b : p` for all `a b`, such that `r S (a, b) (c, d)` implies `f a b = f c d`, @@ -293,8 +293,6 @@ theorem induction_on {p : Localization S → Prop} (x) (H : ∀ y : M × S, p (m /-- Non-dependent recursion principle for localizations: given elements `f x y : p` for all `x` and `y`, such that `r S x x'` and `r S y y'` implies `f x y = f x' y'`, then `f` is defined on the whole `Localization S`. -/ --- Porting note: the attribute `elab_as_elim` fails with `unexpected eliminator resulting type p` --- @[to_additive (attr := elab_as_elim) @[to_additive "Non-dependent recursion principle for localizations: given elements `f x y : p` for all `x` and `y`, such that `r S x x'` and `r S y y'` implies `f x y = f x' y'`, @@ -995,101 +993,10 @@ theorem map_surjective_of_surjective (hg : Surjective g) (k : LocalizationMap (S use f.mk' x ⟨s, hs⟩ rw [map_mk'] -section AwayMap - -variable (x : M) - -/-- Given `x : M`, the type of `CommMonoid` homomorphisms `f : M →* N` such that `N` -is isomorphic to the Localization of `M` at the Submonoid generated by `x`. -/ -@[to_additive - "Given `x : M`, the type of `AddCommMonoid` homomorphisms `f : M →+ N` such that `N` -is isomorphic to the localization of `M` at the AddSubmonoid generated by `x`."] -abbrev AwayMap (N' : Type*) [CommMonoid N'] := LocalizationMap (powers x) N' - -variable (F : AwayMap x N) - -/-- Given `x : M` and a Localization map `F : M →* N` away from `x`, `invSelf` is `(F x)⁻¹`. -/ -noncomputable def AwayMap.invSelf : N := F.mk' 1 ⟨x, mem_powers _⟩ - -/-- Given `x : M`, a Localization map `F : M →* N` away from `x`, and a map of `CommMonoid`s -`g : M →* P` such that `g x` is invertible, the homomorphism induced from `N` to `P` sending -`z : N` to `g y * (g x)⁻ⁿ`, where `y : M, n : ℕ` are such that `z = F y * (F x)⁻ⁿ`. -/ -noncomputable def AwayMap.lift (hg : IsUnit (g x)) : N →* P := - Submonoid.LocalizationMap.lift F fun y ↦ - show IsUnit (g y.1) by - obtain ⟨n, hn⟩ := y.2 - rw [← hn, g.map_pow] - exact IsUnit.pow n hg - -@[simp] -theorem AwayMap.lift_eq (hg : IsUnit (g x)) (a : M) : F.lift x hg (F.toMap a) = g a := - Submonoid.LocalizationMap.lift_eq _ _ _ - -@[simp] -theorem AwayMap.lift_comp (hg : IsUnit (g x)) : (F.lift x hg).comp F.toMap = g := - Submonoid.LocalizationMap.lift_comp _ _ - -/-- Given `x y : M` and Localization maps `F : M →* N, G : M →* P` away from `x` and `x * y` -respectively, the homomorphism induced from `N` to `P`. -/ -noncomputable def awayToAwayRight (y : M) (G : AwayMap (x * y) P) : N →* P := - F.lift x <| - show IsUnit (G.toMap x) from - isUnit_of_mul_eq_one (G.toMap x) (G.mk' y ⟨x * y, mem_powers _⟩) <| by - rw [mul_mk'_eq_mk'_of_mul, mk'_self] - -end AwayMap - end LocalizationMap end Submonoid -namespace AddSubmonoid - -namespace LocalizationMap - -section AwayMap - -variable {A : Type*} [AddCommMonoid A] (x : A) {B : Type*} [AddCommMonoid B] (F : AwayMap x B) - {C : Type*} [AddCommMonoid C] {g : A →+ C} - -/-- Given `x : A` and a Localization map `F : A →+ B` away from `x`, `neg_self` is `- (F x)`. -/ -noncomputable def AwayMap.negSelf : B := - F.mk' 0 ⟨x, mem_multiples _⟩ - -/-- Given `x : A`, a localization map `F : A →+ B` away from `x`, and a map of `AddCommMonoid`s -`g : A →+ C` such that `g x` is invertible, the homomorphism induced from `B` to `C` sending -`z : B` to `g y - n • g x`, where `y : A, n : ℕ` are such that `z = F y - n • F x`. -/ -noncomputable def AwayMap.lift (hg : IsAddUnit (g x)) : B →+ C := - AddSubmonoid.LocalizationMap.lift F fun y ↦ - show IsAddUnit (g y.1) by - obtain ⟨n, hn⟩ := y.2 - rw [← hn] - dsimp - rw [g.map_nsmul] - exact IsAddUnit.map (nsmulAddMonoidHom n : C →+ C) hg - -@[simp] -theorem AwayMap.lift_eq (hg : IsAddUnit (g x)) (a : A) : F.lift x hg (F.toMap a) = g a := - AddSubmonoid.LocalizationMap.lift_eq _ _ _ - -@[simp] -theorem AwayMap.lift_comp (hg : IsAddUnit (g x)) : (F.lift x hg).comp F.toMap = g := - AddSubmonoid.LocalizationMap.lift_comp _ _ - -/-- Given `x y : A` and Localization maps `F : A →+ B, G : A →+ C` away from `x` and `x + y` -respectively, the homomorphism induced from `B` to `C`. -/ -noncomputable def awayToAwayRight (y : A) (G : AwayMap (x + y) C) : B →+ C := - F.lift x <| - show IsAddUnit (G.toMap x) from - isAddUnit_of_add_eq_zero (G.toMap x) (G.mk' y ⟨x + y, mem_multiples _⟩) <| by - rw [add_mk'_eq_mk'_of_add, mk'_self] - -end AwayMap - -end LocalizationMap - -end AddSubmonoid - namespace Submonoid namespace LocalizationMap @@ -1160,7 +1067,6 @@ theorem mulEquivOfLocalizations_right_inv (k : LocalizationMap S P) : f.ofMulEquivOfLocalizations (f.mulEquivOfLocalizations k) = k := toMap_injective <| f.lift_comp k.map_units --- @[simp] -- Porting note (#10618): simp can prove this @[to_additive addEquivOfLocalizations_right_inv_apply] theorem mulEquivOfLocalizations_right_inv_apply {k : LocalizationMap S P} {x} : (f.ofMulEquivOfLocalizations (f.mulEquivOfLocalizations k)).toMap x = k.toMap x := by simp @@ -1170,7 +1076,6 @@ theorem mulEquivOfLocalizations_left_inv (k : N ≃* P) : f.mulEquivOfLocalizations (f.ofMulEquivOfLocalizations k) = k := DFunLike.ext _ _ fun x ↦ DFunLike.ext_iff.1 (f.lift_of_comp k.toMonoidHom) x --- @[simp] -- Porting note (#10618): simp can prove this @[to_additive] theorem mulEquivOfLocalizations_left_inv_apply {k : N ≃* P} (x) : f.mulEquivOfLocalizations (f.ofMulEquivOfLocalizations k) x = k x := by simp @@ -1323,7 +1228,7 @@ theorem mk_eq_monoidOf_mk'_apply (x y) : mk x y = (monoidOf S).mk' x y := conv => rhs; rw [← mul_one 1]; rw [← mul_one x] exact mk_eq_mk_iff.2 (Con.symm _ <| (Localization.r S).mul (Con.refl _ (x, 1)) <| one_rel _) -@[to_additive (attr := simp)] +@[to_additive] theorem mk_eq_monoidOf_mk' : mk = (monoidOf S).mk' := funext fun _ ↦ funext fun _ ↦ mk_eq_monoidOf_mk'_apply _ _ @@ -1362,7 +1267,6 @@ theorem mulEquivOfQuotient_mk' (x y) : mulEquivOfQuotient f ((monoidOf S).mk' x theorem mulEquivOfQuotient_mk (x y) : mulEquivOfQuotient f (mk x y) = f.mk' x y := by rw [mk_eq_monoidOf_mk'_apply]; exact mulEquivOfQuotient_mk' _ _ --- @[simp] -- Porting note (#10618): simp can prove this @[to_additive] theorem mulEquivOfQuotient_monoidOf (x) : mulEquivOfQuotient f ((monoidOf S).toMap x) = f.toMap x := by simp @@ -1381,47 +1285,6 @@ theorem mulEquivOfQuotient_symm_monoidOf (x) : (mulEquivOfQuotient f).symm (f.toMap x) = (monoidOf S).toMap x := f.lift_eq (monoidOf S).map_units _ -section Away - -variable (x : M) - -/-- Given `x : M`, the Localization of `M` at the Submonoid generated by `x`, as a quotient. -/ -@[to_additive - "Given `x : M`, the Localization of `M` at the Submonoid generated by `x`, as a quotient."] -abbrev Away := - Localization (Submonoid.powers x) - -/-- Given `x : M`, `invSelf` is `x⁻¹` in the Localization (as a quotient type) of `M` at the -Submonoid generated by `x`. -/ -@[to_additive - "Given `x : M`, `negSelf` is `-x` in the Localization (as a quotient type) of `M` at the -Submonoid generated by `x`."] -def Away.invSelf : Away x := - mk 1 ⟨x, Submonoid.mem_powers _⟩ - -/-- Given `x : M`, the natural hom sending `y : M`, `M` a `CommMonoid`, to the equivalence class -of `(y, 1)` in the Localization of `M` at the Submonoid generated by `x`. -/ -@[to_additive - "Given `x : M`, the natural hom sending `y : M`, `M` an `AddCommMonoid`, to the equivalence -class of `(y, 0)` in the Localization of `M` at the Submonoid generated by `x`."] -abbrev Away.monoidOf : Submonoid.LocalizationMap.AwayMap x (Away x) := - Localization.monoidOf (Submonoid.powers x) - --- @[simp] -- Porting note (#10618): simp can prove thisrove this -@[to_additive] -theorem Away.mk_eq_monoidOf_mk' : mk = (Away.monoidOf x).mk' := by simp - -/-- Given `x : M` and a Localization map `f : M →* N` away from `x`, we get an isomorphism between -the Localization of `M` at the Submonoid generated by `x` as a quotient type and `N`. -/ -@[to_additive - "Given `x : M` and a Localization map `f : M →+ N` away from `x`, we get an isomorphism between -the Localization of `M` at the Submonoid generated by `x` as a quotient type and `N`."] -noncomputable def Away.mulEquivOfQuotient (f : Submonoid.LocalizationMap.AwayMap x N) : - Away x ≃* N := - Localization.mulEquivOfQuotient f - -end Away - end Localization end CommMonoid @@ -1432,7 +1295,7 @@ variable {α : Type*} [CancelCommMonoid α] {s : Submonoid α} {a₁ b₁ : α} @[to_additive] theorem mk_left_injective (b : s) : Injective fun a => mk a b := fun c d h => by - simpa [-mk_eq_monoidOf_mk', mk_eq_mk_iff, r_iff_exists] using h + simpa [mk_eq_mk_iff, r_iff_exists] using h @[to_additive] theorem mk_eq_mk_iff' : mk a₁ a₂ = mk b₁ b₂ ↔ ↑b₂ * a₁ = a₂ * b₁ := by diff --git a/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean b/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean index 3c6c5f38a066e..edb758c5a3268 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean @@ -3,8 +3,10 @@ Copyright (c) 2019 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston -/ +import Mathlib.Algebra.GroupWithZero.Hom import Mathlib.Algebra.Regular.Basic import Mathlib.GroupTheory.MonoidLocalization.Basic +import Mathlib.RingTheory.OreLocalization.Basic /-! # Localizations of commutative monoids with zeroes diff --git a/Mathlib/GroupTheory/MonoidLocalization/Order.lean b/Mathlib/GroupTheory/MonoidLocalization/Order.lean index ccdd1707f6e4d..50502f62e0f37 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/Order.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/Order.lean @@ -60,7 +60,7 @@ theorem mk_lt_mk : mk a₁ a₂ < mk b₁ b₂ ↔ ↑b₂ * a₁ < a₂ * b₁ instance partialOrder : PartialOrder (Localization s) where le := (· ≤ ·) lt := (· < ·) - le_refl a := Localization.induction_on a fun a => le_rfl + le_refl a := Localization.induction_on a fun _ => le_rfl le_trans a b c := Localization.induction_on₃ a b c fun a b c hab hbc => by simp only [mk_le_mk] at hab hbc ⊢ @@ -76,7 +76,7 @@ instance partialOrder : PartialOrder (Localization s) where · simp_rw [mk_le_mk, mk_eq_mk_iff, r_iff_exists] exact fun hab hba => ⟨1, by rw [hab.antisymm hba]⟩ all_goals rfl - lt_iff_le_not_le a b := Localization.induction_on₂ a b fun a b => lt_iff_le_not_le + lt_iff_le_not_le a b := Localization.induction_on₂ a b fun _ _ => lt_iff_le_not_le @[to_additive] instance orderedCancelCommMonoid : OrderedCancelCommMonoid (Localization s) where @@ -106,7 +106,7 @@ sending `a` to `a - b`."] def mkOrderEmbedding (b : s) : α ↪o Localization s where toFun a := mk a b inj' := mk_left_injective _ - map_rel_iff' {a b} := by simp [-mk_eq_monoidOf_mk', mk_le_mk] + map_rel_iff' {a b} := by simp [mk_le_mk] end OrderedCancelCommMonoid diff --git a/Mathlib/GroupTheory/Nilpotent.lean b/Mathlib/GroupTheory/Nilpotent.lean index 90196dde62882..9d9b75bfeff2d 100644 --- a/Mathlib/GroupTheory/Nilpotent.lean +++ b/Mathlib/GroupTheory/Nilpotent.lean @@ -144,25 +144,55 @@ theorem upperCentralSeries_one : upperCentralSeries G 1 = center G := by Subgroup.mem_center_iff, mem_mk, mem_bot, Set.mem_setOf_eq] exact forall_congr' fun y => by rw [mul_inv_eq_one, mul_inv_eq_iff_eq_mul, eq_comm] +variable {G} + /-- The `n+1`st term of the upper central series `H i` has underlying set equal to the `x` such that `⁅x,G⁆ ⊆ H n`-/ -theorem mem_upperCentralSeries_succ_iff (n : ℕ) (x : G) : +theorem mem_upperCentralSeries_succ_iff {n : ℕ} {x : G} : x ∈ upperCentralSeries G (n + 1) ↔ ∀ y : G, x * y * x⁻¹ * y⁻¹ ∈ upperCentralSeries G n := Iff.rfl +@[simp] lemma comap_upperCentralSeries {H : Type*} [Group H] (e : H ≃* G) : + ∀ n, (upperCentralSeries G n).comap e = upperCentralSeries H n + | 0 => by simpa [MonoidHom.ker_eq_bot_iff] using e.injective + | n + 1 => by + ext + simp [mem_upperCentralSeries_succ_iff, ← comap_upperCentralSeries e n, + ← e.toEquiv.forall_congr_right] + +namespace Group --- is_nilpotent is already defined in the root namespace (for elements of rings). +variable (G) in +-- `IsNilpotent` is already defined in the root namespace (for elements of rings). +-- TODO: Rename it to `IsNilpotentElement`? /-- A group `G` is nilpotent if its upper central series is eventually `G`. -/ -class Group.IsNilpotent (G : Type*) [Group G] : Prop where +@[mk_iff] +class IsNilpotent (G : Type*) [Group G] : Prop where nilpotent' : ∃ n : ℕ, upperCentralSeries G n = ⊤ -- Porting note: add lemma since infer kinds are unsupported in the definition of `IsNilpotent` -lemma Group.IsNilpotent.nilpotent (G : Type*) [Group G] [IsNilpotent G] : +lemma IsNilpotent.nilpotent (G : Type*) [Group G] [IsNilpotent G] : ∃ n : ℕ, upperCentralSeries G n = ⊤ := Group.IsNilpotent.nilpotent' -open Group +lemma isNilpotent_congr {H : Type*} [Group H] (e : G ≃* H) : IsNilpotent G ↔ IsNilpotent H := by + simp_rw [isNilpotent_iff] + refine exists_congr fun n ↦ ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · simp [← Subgroup.comap_top e.symm.toMonoidHom, ← h] + · simp [← Subgroup.comap_top e.toMonoidHom, ← h] -variable {G} +@[simp] lemma isNilpotent_top : IsNilpotent (⊤ : Subgroup G) ↔ IsNilpotent G := + isNilpotent_congr Subgroup.topEquiv + +variable (G) in +/-- A group `G` is virtually nilpotent if it has a nilpotent cofinite subgroup `N`. -/ +def IsVirtuallyNilpotent : Prop := ∃ N : Subgroup G, IsNilpotent N ∧ FiniteIndex N + +lemma IsNilpotent.isVirtuallyNilpotent (hG : IsNilpotent G) : IsVirtuallyNilpotent G := + ⟨⊤, by simpa, inferInstance⟩ + +end Group + +open Group /-- A sequence of subgroups of `G` is an ascending central series if `H 0` is trivial and `⁅H (n + 1), G⁆ ⊆ H n` for all `n`. Note that we do not require that `H n = G` for some `n`. -/ @@ -287,11 +317,12 @@ theorem lowerCentralSeries_antitone : Antitone (lowerCentralSeries G) := by simp only [mem_lowerCentralSeries_succ_iff, exists_prop, mem_top, exists_true_left, true_and] at hx refine - closure_induction hx ?_ (Subgroup.one_mem _) (@Subgroup.mul_mem _ _ _) (@Subgroup.inv_mem _ _ _) + closure_induction ?_ (Subgroup.one_mem _) (fun _ _ _ _ ↦ mul_mem) (fun _ _ ↦ inv_mem) hx rintro y ⟨z, hz, a, ha⟩ rw [← ha, mul_assoc, mul_assoc, ← mul_assoc a z⁻¹ a⁻¹] exact mul_mem hz (Normal.conj_mem (lowerCentralSeries_normal n) z⁻¹ (inv_mem hz) a) + /-- The lower central series of a group is a descending central series. -/ theorem lowerCentralSeries_isDescendingCentralSeries : IsDescendingCentralSeries (lowerCentralSeries G) := by @@ -449,8 +480,8 @@ theorem lowerCentralSeries.map {H : Type*} [Group H] (f : G →* H) (n : ℕ) : induction' n with d hd · simp · rintro a ⟨x, hx : x ∈ lowerCentralSeries G d.succ, rfl⟩ - refine closure_induction hx ?_ (by simp [f.map_one, Subgroup.one_mem _]) - (fun y z hy hz => by simp [MonoidHom.map_mul, Subgroup.mul_mem _ hy hz]) (fun y hy => by + refine closure_induction (hx := hx) ?_ (by simp [f.map_one, Subgroup.one_mem _]) + (fun y z _ _ hy hz => by simp [MonoidHom.map_mul, Subgroup.mul_mem _ hy hz]) (fun y _ hy => by rw [f.map_inv]; exact Subgroup.inv_mem _ hy) rintro a ⟨y, hy, z, ⟨-, rfl⟩⟩ apply mem_closure.mpr diff --git a/Mathlib/GroupTheory/NoncommPiCoprod.lean b/Mathlib/GroupTheory/NoncommPiCoprod.lean index 52503c3b5a08c..d675c2b73a7f5 100644 --- a/Mathlib/GroupTheory/NoncommPiCoprod.lean +++ b/Mathlib/GroupTheory/NoncommPiCoprod.lean @@ -90,16 +90,13 @@ variable (ϕ : ∀ i : ι, N i →* M) -- We assume that the elements of different morphism commute variable (hcomm : Pairwise fun i j => ∀ x y, Commute (ϕ i x) (ϕ j y)) --- We use `f` and `g` to denote elements of `Π (i : ι), N i` -variable (f g : ∀ i : ι, N i) - namespace MonoidHom /-- The canonical homomorphism from a family of monoids. -/ @[to_additive "The canonical homomorphism from a family of additive monoids. See also `LinearMap.lsum` for a linear version without the commutativity assumption."] def noncommPiCoprod : (∀ i : ι, N i) →* M where - toFun f := Finset.univ.noncommProd (fun i => ϕ i (f i)) fun i _ j _ h => hcomm h _ _ + toFun f := Finset.univ.noncommProd (fun i => ϕ i (f i)) fun _ _ _ _ h => hcomm h _ _ map_one' := by apply (Finset.noncommProd_eq_pow_card _ _ _ _ _).trans (one_pow _) simp @@ -135,7 +132,7 @@ def noncommPiCoprodEquiv [DecidableEq ι] : ((∀ i, N i) →* M) where toFun ϕ := noncommPiCoprod ϕ.1 ϕ.2 invFun f := - ⟨fun i => f.comp (MonoidHom.mulSingle N i), fun i j hij x y => + ⟨fun i => f.comp (MonoidHom.mulSingle N i), fun _ _ hij x y => Commute.map (Pi.mulSingle_commute hij x y) f⟩ left_inv ϕ := by ext @@ -168,9 +165,6 @@ variable {ι : Type*} variable {H : ι → Type*} [∀ i, Group (H i)] variable (ϕ : ∀ i : ι, H i →* G) --- We use `f` and `g` to denote elements of `Π (i : ι), H i` -variable (f g : ∀ i : ι, H i) - namespace MonoidHom -- The subgroup version of `MonoidHom.noncommPiCoprod_mrange` @[to_additive] @@ -251,9 +245,6 @@ namespace Subgroup variable {G : Type*} [Group G] variable {ι : Type*} {H : ι → Subgroup G} --- Elements of `Π (i : ι), H i` are called `f` and `g` here -variable (f g : ∀ i : ι, H i) - section CommutingSubgroups -- We assume that the elements of different subgroups commute diff --git a/Mathlib/GroupTheory/Order/Min.lean b/Mathlib/GroupTheory/Order/Min.lean index 6cbf10250be02..3d1047b06f179 100644 --- a/Mathlib/GroupTheory/Order/Min.lean +++ b/Mathlib/GroupTheory/Order/Min.lean @@ -49,7 +49,7 @@ lemma minOrder_le_orderOf (ha : a ≠ 1) (ha' : IsOfFinOrder a) : minOrder α end Monoid -variable [Group α] {s : Subgroup α} {n : ℕ} +variable [Group α] {s : Subgroup α} @[to_additive] lemma le_minOrder_iff_forall_subgroup {n : ℕ∞} : diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 9e33d48b21996..12dbd230d8ffa 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -80,11 +80,32 @@ theorem not_isOfFinOrder_of_injective_pow {x : G} (h : Injective fun n : ℕ => rw [h hnx] at hn_pos exact irrefl 0 hn_pos +/-- 1 is of finite order in any monoid. -/ +@[to_additive (attr := simp) "0 is of finite order in any additive monoid."] +theorem IsOfFinOrder.one : IsOfFinOrder (1 : G) := + isOfFinOrder_iff_pow_eq_one.mpr ⟨1, Nat.one_pos, one_pow 1⟩ + +@[to_additive (attr := deprecated (since := "2024-10-11"))] +alias isOfFinOrder_one := IsOfFinOrder.one + +@[to_additive] lemma IsOfFinOrder.pow {n : ℕ} : IsOfFinOrder a → IsOfFinOrder (a ^ n) := by simp_rw [isOfFinOrder_iff_pow_eq_one] rintro ⟨m, hm, ha⟩ exact ⟨m, hm, by simp [pow_right_comm _ n, ha]⟩ +@[to_additive] +lemma IsOfFinOrder.of_pow {n : ℕ} (h : IsOfFinOrder (a ^ n)) (hn : n ≠ 0) : IsOfFinOrder a := by + rw [isOfFinOrder_iff_pow_eq_one] at * + rcases h with ⟨m, hm, ha⟩ + exact ⟨n * m, by positivity, by rwa [pow_mul]⟩ + +@[to_additive (attr := simp)] +lemma isOfFinOrder_pow {n : ℕ} : IsOfFinOrder (a ^ n) ↔ IsOfFinOrder a ∨ n = 0 := by + rcases Decidable.eq_or_ne n 0 with rfl | hn + · simp + · exact ⟨fun h ↦ .inl <| h.of_pow hn, fun h ↦ (h.resolve_right hn).pow⟩ + /-- Elements of finite order are of finite order in submonoids. -/ @[to_additive "Elements of finite order are of finite order in submonoids."] theorem Submonoid.isOfFinOrder_coe {H : Submonoid G} {x : H} : @@ -107,11 +128,6 @@ theorem IsOfFinOrder.apply {η : Type*} {Gs : η → Type*} [∀ i, Monoid (Gs i obtain ⟨n, npos, hn⟩ := h.exists_pow_eq_one exact fun _ => isOfFinOrder_iff_pow_eq_one.mpr ⟨n, npos, (congr_fun hn.symm _).symm⟩ -/-- 1 is of finite order in any monoid. -/ -@[to_additive "0 is of finite order in any additive monoid."] -theorem isOfFinOrder_one : IsOfFinOrder (1 : G) := - isOfFinOrder_iff_pow_eq_one.mpr ⟨1, Nat.one_pos, one_pow 1⟩ - /-- The submonoid generated by an element is a group if that element has finite order. -/ @[to_additive "The additive submonoid generated by an element is an additive group if that element has finite order."] @@ -558,7 +574,7 @@ theorem orderOf_inv (x : G) : orderOf x⁻¹ = orderOf x := by simp [orderOf_eq_ namespace Subgroup variable {H : Subgroup G} -@[to_additive (attr := norm_cast)] -- Porting note (#10618): simp can prove this (so removed simp) +@[to_additive (attr := norm_cast)] lemma orderOf_coe (a : H) : orderOf (a : G) = orderOf a := orderOf_injective H.subtype Subtype.coe_injective _ @@ -926,11 +942,11 @@ noncomputable def powCoprime {G : Type*} [Group G] (h : (Nat.card G).Coprime n) rwa [zpow_add, zpow_mul, zpow_mul', zpow_natCast, zpow_natCast, zpow_natCast, h.gcd_eq_one, pow_one, pow_card_eq_one', one_zpow, one_mul, eq_comm] at key -@[to_additive] -- Porting note (#10618): simp can prove this (so removed simp) +@[to_additive] theorem powCoprime_one {G : Type*} [Group G] (h : (Nat.card G).Coprime n) : powCoprime h 1 = 1 := one_pow n -@[to_additive] -- Porting note (#10618): simp can prove this (so removed simp) +@[to_additive] theorem powCoprime_inv {G : Type*} [Group G] (h : (Nat.card G).Coprime n) {g : G} : powCoprime h g⁻¹ = (powCoprime h g)⁻¹ := inv_pow g n diff --git a/Mathlib/GroupTheory/OreLocalization/Basic.lean b/Mathlib/GroupTheory/OreLocalization/Basic.lean new file mode 100644 index 0000000000000..82c2f2d7c5cd1 --- /dev/null +++ b/Mathlib/GroupTheory/OreLocalization/Basic.lean @@ -0,0 +1,641 @@ +/- +Copyright (c) 2022 Jakob von Raumer. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jakob von Raumer, Kevin Klinge, Andrew Yang +-/ +import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.GroupTheory.OreLocalization.OreSet + +/-! + +# Localization over left Ore sets. + +This file defines the localization of a monoid over a left Ore set and proves its universal +mapping property. + +## Notations + +Introduces the notation `R[S⁻¹]` for the Ore localization of a monoid `R` at a right Ore +subset `S`. Also defines a new heterogeneous division notation `r /ₒ s` for a numerator `r : R` and +a denominator `s : S`. + +## References + +* +* [Zoran Škoda, *Noncommutative localization in noncommutative geometry*][skoda2006] + + +## Tags +localization, Ore, non-commutative + +-/ + +assert_not_exists MonoidWithZero +assert_not_exists Ring + +universe u + +open OreLocalization + +namespace OreLocalization + +variable {R : Type*} [Monoid R] (S : Submonoid R) [OreSet S] (X) [MulAction R X] + +/-- The setoid on `R × S` used for the Ore localization. -/ +@[to_additive AddOreLocalization.oreEqv "The setoid on `R × S` used for the Ore localization."] +def oreEqv : Setoid (X × S) where + r rs rs' := ∃ (u : S) (v : R), u • rs'.1 = v • rs.1 ∧ u * rs'.2 = v * rs.2 + iseqv := by + refine ⟨fun _ => ⟨1, 1, by simp⟩, ?_, ?_⟩ + · rintro ⟨r, s⟩ ⟨r', s'⟩ ⟨u, v, hru, hsu⟩; dsimp only at * + rcases oreCondition (s : R) s' with ⟨r₂, s₂, h₁⟩ + rcases oreCondition r₂ u with ⟨r₃, s₃, h₂⟩ + have : r₃ * v * s = s₃ * s₂ * s := by + -- Porting note: the proof used `assoc_rw` + rw [mul_assoc _ (s₂ : R), h₁, ← mul_assoc, h₂, mul_assoc, ← hsu, ← mul_assoc] + rcases ore_right_cancel (r₃ * v) (s₃ * s₂) s this with ⟨w, hw⟩ + refine ⟨w * (s₃ * s₂), w * (r₃ * u), ?_, ?_⟩ <;> + simp only [Submonoid.coe_mul, Submonoid.smul_def, ← hw] + · simp only [mul_smul, hru, ← Submonoid.smul_def] + · simp only [mul_assoc, hsu] + · rintro ⟨r₁, s₁⟩ ⟨r₂, s₂⟩ ⟨r₃, s₃⟩ ⟨u, v, hur₁, hs₁u⟩ ⟨u', v', hur₂, hs₂u⟩ + rcases oreCondition v' u with ⟨r', s', h⟩; dsimp only at * + refine ⟨s' * u', r' * v, ?_, ?_⟩ <;> + simp only [Submonoid.smul_def, Submonoid.coe_mul, mul_smul, mul_assoc] at * + · rw [hur₂, smul_smul, h, mul_smul, hur₁] + · rw [hs₂u, ← mul_assoc, h, mul_assoc, hs₁u] + +end OreLocalization + +/-- The Ore localization of a monoid and a submonoid fulfilling the Ore condition. -/ +@[to_additive AddOreLocalization "The Ore localization of an additive monoid and a submonoid +fulfilling the Ore condition."] +def OreLocalization {R : Type*} [Monoid R] (S : Submonoid R) [OreSet S] + (X : Type*) [MulAction R X] := + Quotient (OreLocalization.oreEqv S X) + +namespace OreLocalization + +section Monoid + +variable (R : Type*) [Monoid R] (S : Submonoid R) [OreSet S] + +@[inherit_doc OreLocalization] +scoped syntax:1075 term noWs atomic("[" term "⁻¹" noWs "]") : term +macro_rules | `($R[$S⁻¹]) => ``(OreLocalization $S $R) + +attribute [local instance] oreEqv + +variable {R S} +variable {X} [MulAction R X] + +/-- The division in the Ore localization `X[S⁻¹]`, as a fraction of an element of `X` and `S`. -/ +@[to_additive "The subtraction in the Ore localization, +as a difference of an element of `X` and `S`."] +def oreDiv (r : X) (s : S) : X[S⁻¹] := + Quotient.mk' (r, s) + +@[inherit_doc] +infixl:70 " /ₒ " => oreDiv + +@[inherit_doc] +infixl:65 " -ₒ " => _root_.AddOreLocalization.oreSub + +@[to_additive (attr := elab_as_elim, cases_eliminator, induction_eliminator)] +protected theorem ind {β : X[S⁻¹] → Prop} + (c : ∀ (r : X) (s : S), β (r /ₒ s)) : ∀ q, β q := by + apply Quotient.ind + rintro ⟨r, s⟩ + exact c r s + +@[to_additive] +theorem oreDiv_eq_iff {r₁ r₂ : X} {s₁ s₂ : S} : + r₁ /ₒ s₁ = r₂ /ₒ s₂ ↔ ∃ (u : S) (v : R), u • r₂ = v • r₁ ∧ u * s₂ = v * s₁ := + Quotient.eq'' + +/-- A fraction `r /ₒ s` is equal to its expansion by an arbitrary factor `t` if `t * s ∈ S`. -/ +@[to_additive "A difference `r -ₒ s` is equal to its expansion by an +arbitrary translation `t` if `t + s ∈ S`."] +protected theorem expand (r : X) (s : S) (t : R) (hst : t * (s : R) ∈ S) : + r /ₒ s = t • r /ₒ ⟨t * s, hst⟩ := by + apply Quotient.sound + exact ⟨s, s * t, by rw [mul_smul, Submonoid.smul_def], by rw [← mul_assoc]⟩ + +/-- A fraction is equal to its expansion by a factor from `S`. -/ +@[to_additive "A difference is equal to its expansion by a summand from `S`."] +protected theorem expand' (r : X) (s s' : S) : r /ₒ s = s' • r /ₒ (s' * s) := + OreLocalization.expand r s s' (by norm_cast; apply SetLike.coe_mem) + +/-- Fractions which differ by a factor of the numerator can be proven equal if +those factors expand to equal elements of `R`. -/ +@[to_additive "Differences whose minuends differ by a common summand can be proven equal if +those summands expand to equal elements of `R`."] +protected theorem eq_of_num_factor_eq {r r' r₁ r₂ : R} {s t : S} (h : t * r = t * r') : + r₁ * r * r₂ /ₒ s = r₁ * r' * r₂ /ₒ s := by + rcases oreCondition r₁ t with ⟨r₁', t', hr₁⟩ + rw [OreLocalization.expand' _ s t', OreLocalization.expand' _ s t'] + congr 1 + -- Porting note (#11215): TODO: use `assoc_rw`? + calc (t' : R) * (r₁ * r * r₂) + = t' * r₁ * r * r₂ := by simp [← mul_assoc] + _ = r₁' * t * r * r₂ := by rw [hr₁] + _ = r₁' * (t * r) * r₂ := by simp [← mul_assoc] + _ = r₁' * (t * r') * r₂ := by rw [h] + _ = r₁' * t * r' * r₂ := by simp [← mul_assoc] + _ = t' * r₁ * r' * r₂ := by rw [hr₁] + _ = t' * (r₁ * r' * r₂) := by simp [← mul_assoc] + +/-- A function or predicate over `X` and `S` can be lifted to `X[S⁻¹]` if it is invariant +under expansion on the left. -/ +@[to_additive "A function or predicate over `X` and `S` can be lifted to the localizaton if it is +invariant under expansion on the left."] +def liftExpand {C : Sort*} (P : X → S → C) + (hP : ∀ (r : X) (t : R) (s : S) (ht : t * s ∈ S), P r s = P (t • r) ⟨t * s, ht⟩) : + X[S⁻¹] → C := + Quotient.lift (fun p : X × S => P p.1 p.2) fun (r₁, s₁) (r₂, s₂) ⟨u, v, hr₂, hs₂⟩ => by + dsimp at * + have s₁vS : v * s₁ ∈ S := by + rw [← hs₂, ← S.coe_mul] + exact SetLike.coe_mem (u * s₂) + replace hs₂ : u * s₂ = ⟨_, s₁vS⟩ := by ext; simp [hs₂] + rw [hP r₁ v s₁ s₁vS, hP r₂ u s₂ (by norm_cast; rwa [hs₂]), ← hr₂] + simp only [← hs₂]; rfl + +@[to_additive (attr := simp)] +theorem liftExpand_of {C : Sort*} {P : X → S → C} + {hP : ∀ (r : X) (t : R) (s : S) (ht : t * s ∈ S), P r s = P (t • r) ⟨t * s, ht⟩} (r : X) + (s : S) : liftExpand P hP (r /ₒ s) = P r s := + rfl + +/-- A version of `liftExpand` used to simultaneously lift functions with two arguments +in `X[S⁻¹]`. -/ +@[to_additive "A version of `liftExpand` used to simultaneously lift functions with two arguments"] +def lift₂Expand {C : Sort*} (P : X → S → X → S → C) + (hP : + ∀ (r₁ : X) (t₁ : R) (s₁ : S) (ht₁ : t₁ * s₁ ∈ S) (r₂ : X) (t₂ : R) (s₂ : S) + (ht₂ : t₂ * s₂ ∈ S), + P r₁ s₁ r₂ s₂ = P (t₁ • r₁) ⟨t₁ * s₁, ht₁⟩ (t₂ • r₂) ⟨t₂ * s₂, ht₂⟩) : + X[S⁻¹] → X[S⁻¹] → C := + liftExpand + (fun r₁ s₁ => liftExpand (P r₁ s₁) fun r₂ t₂ s₂ ht₂ => by + have := hP r₁ 1 s₁ (by simp) r₂ t₂ s₂ ht₂ + simp [this]) + fun r₁ t₁ s₁ ht₁ => by + ext x; induction' x with r₂ s₂ + dsimp only + rw [liftExpand_of, liftExpand_of, hP r₁ t₁ s₁ ht₁ r₂ 1 s₂ (by simp)]; simp + +@[to_additive (attr := simp)] +theorem lift₂Expand_of {C : Sort*} {P : X → S → X → S → C} + {hP : + ∀ (r₁ : X) (t₁ : R) (s₁ : S) (ht₁ : t₁ * s₁ ∈ S) (r₂ : X) (t₂ : R) (s₂ : S) + (ht₂ : t₂ * s₂ ∈ S), + P r₁ s₁ r₂ s₂ = P (t₁ • r₁) ⟨t₁ * s₁, ht₁⟩ (t₂ • r₂) ⟨t₂ * s₂, ht₂⟩} + (r₁ : X) (s₁ : S) (r₂ : X) (s₂ : S) : lift₂Expand P hP (r₁ /ₒ s₁) (r₂ /ₒ s₂) = P r₁ s₁ r₂ s₂ := + rfl + +@[to_additive] +private def smul' (r₁ : R) (s₁ : S) (r₂ : X) (s₂ : S) : X[S⁻¹] := + oreNum r₁ s₂ • r₂ /ₒ (oreDenom r₁ s₂ * s₁) + +@[to_additive] +private theorem smul'_char (r₁ : R) (r₂ : X) (s₁ s₂ : S) (u : S) (v : R) (huv : u * r₁ = v * s₂) : + OreLocalization.smul' r₁ s₁ r₂ s₂ = v • r₂ /ₒ (u * s₁) := by + -- Porting note: `assoc_rw` was not ported yet + simp only [smul'] + have h₀ := ore_eq r₁ s₂; set v₀ := oreNum r₁ s₂; set u₀ := oreDenom r₁ s₂ + rcases oreCondition (u₀ : R) u with ⟨r₃, s₃, h₃⟩ + have := + calc + r₃ * v * s₂ = r₃ * (u * r₁) := by rw [mul_assoc, ← huv] + _ = s₃ * (u₀ * r₁) := by rw [← mul_assoc, ← mul_assoc, h₃] + _ = s₃ * v₀ * s₂ := by rw [mul_assoc, h₀] + rcases ore_right_cancel _ _ _ this with ⟨s₄, hs₄⟩ + symm; rw [oreDiv_eq_iff] + use s₄ * s₃ + use s₄ * r₃ + simp only [Submonoid.coe_mul, Submonoid.smul_def, smul_eq_mul] + constructor + · rw [smul_smul, mul_assoc (c := v₀), ← hs₄] + simp only [smul_smul, mul_assoc] + · rw [← mul_assoc (b := (u₀ : R)), mul_assoc (c := (u₀ : R)), h₃] + simp only [mul_assoc] + +/-- The multiplication on the Ore localization of monoids. -/ +@[to_additive] +private def smul'' (r : R) (s : S) : X[S⁻¹] → X[S⁻¹] := + liftExpand (smul' r s) fun r₁ r₂ s' hs => by + rcases oreCondition r s' with ⟨r₁', s₁', h₁⟩ + rw [smul'_char _ _ _ _ _ _ h₁] + rcases oreCondition r ⟨_, hs⟩ with ⟨r₂', s₂', h₂⟩ + rw [smul'_char _ _ _ _ _ _ h₂] + rcases oreCondition (s₁' : R) (s₂') with ⟨r₃', s₃', h₃⟩ + have : s₃' * r₁' * s' = (r₃' * r₂' * r₂) * s' := by + rw [mul_assoc, ← h₁, ← mul_assoc, h₃, mul_assoc, h₂] + simp [mul_assoc] + rcases ore_right_cancel _ _ _ this with ⟨s₄', h₄⟩ + have : (s₄' * r₃') * (s₂' * s) ∈ S := by + rw [mul_assoc, ← mul_assoc r₃', ← h₃] + exact (s₄' * (s₃' * s₁' * s)).2 + rw [OreLocalization.expand' _ _ (s₄' * s₃'), OreLocalization.expand _ (s₂' * s) _ this] + simp only [Submonoid.smul_def, Submonoid.coe_mul, smul_smul, mul_assoc, h₄] + congr 1 + ext; simp only [Submonoid.coe_mul, ← mul_assoc] + rw [mul_assoc (s₄' : R), h₃, ← mul_assoc] + +/-- The scalar multiplication on the Ore localization of monoids. -/ +@[to_additive (attr := irreducible) + "the vector addition on the Ore localization of additive monoids."] +protected def smul : R[S⁻¹] → X[S⁻¹] → X[S⁻¹] := + liftExpand smul'' fun r₁ r₂ s hs => by + ext x + induction' x with x s₂ + show OreLocalization.smul' r₁ s x s₂ = OreLocalization.smul' (r₂ * r₁) ⟨_, hs⟩ x s₂ + rcases oreCondition r₁ s₂ with ⟨r₁', s₁', h₁⟩ + rw [smul'_char _ _ _ _ _ _ h₁] + rcases oreCondition (r₂ * r₁) s₂ with ⟨r₂', s₂', h₂⟩ + rw [smul'_char _ _ _ _ _ _ h₂] + rcases oreCondition (s₂' * r₂) (s₁') with ⟨r₃', s₃', h₃⟩ + have : s₃' * r₂' * s₂ = r₃' * r₁' * s₂ := by + rw [mul_assoc, ← h₂, ← mul_assoc _ r₂, ← mul_assoc, h₃, mul_assoc, h₁, mul_assoc] + rcases ore_right_cancel _ _ _ this with ⟨s₄', h₄⟩ + have : (s₄' * r₃') * (s₁' * s) ∈ S := by + rw [← mul_assoc, mul_assoc _ r₃', ← h₃, ← mul_assoc, ← mul_assoc, mul_assoc] + exact mul_mem (s₄' * s₃' * s₂').2 hs + rw [OreLocalization.expand' (r₂' • x) _ (s₄' * s₃'), OreLocalization.expand _ _ _ this] + simp only [Submonoid.smul_def, Submonoid.coe_mul, smul_smul, mul_assoc, h₄] + congr 1 + ext; simp only [Submonoid.coe_mul, ← mul_assoc] + rw [mul_assoc _ r₃', ← h₃, ← mul_assoc, ← mul_assoc] + +@[to_additive] +instance : SMul R[S⁻¹] X[S⁻¹] := + ⟨OreLocalization.smul⟩ + +@[to_additive] +instance : Mul R[S⁻¹] := + ⟨OreLocalization.smul⟩ + +@[to_additive] +theorem oreDiv_smul_oreDiv {r₁ : R} {r₂ : X} {s₁ s₂ : S} : + (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = oreNum r₁ s₂ • r₂ /ₒ (oreDenom r₁ s₂ * s₁) := by + with_unfolding_all rfl + +@[to_additive] +theorem oreDiv_mul_oreDiv {r₁ : R} {r₂ : R} {s₁ s₂ : S} : + (r₁ /ₒ s₁) * (r₂ /ₒ s₂) = oreNum r₁ s₂ * r₂ /ₒ (oreDenom r₁ s₂ * s₁) := by + with_unfolding_all rfl + +/-- A characterization lemma for the scalar multiplication on the Ore localization, +allowing for a choice of Ore numerator and Ore denominator. -/ +@[to_additive "A characterization lemma for the vector addition on the Ore localization, +allowing for a choice of Ore minuend and Ore subtrahend."] +theorem oreDiv_smul_char (r₁ : R) (r₂ : X) (s₁ s₂ : S) (r' : R) (s' : S) (huv : s' * r₁ = r' * s₂) : + (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = r' • r₂ /ₒ (s' * s₁) := by + with_unfolding_all exact smul'_char r₁ r₂ s₁ s₂ s' r' huv + +/-- A characterization lemma for the multiplication on the Ore localization, allowing for a choice +of Ore numerator and Ore denominator. -/ +@[to_additive "A characterization lemma for the addition on the Ore localization, +allowing for a choice of Ore minuend and Ore subtrahend."] +theorem oreDiv_mul_char (r₁ r₂ : R) (s₁ s₂ : S) (r' : R) (s' : S) (huv : s' * r₁ = r' * s₂) : + r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r' * r₂ /ₒ (s' * s₁) := by + with_unfolding_all exact smul'_char r₁ r₂ s₁ s₂ s' r' huv + +/-- Another characterization lemma for the scalar multiplication on the Ore localizaion delivering +Ore witnesses and conditions bundled in a sigma type. -/ +@[to_additive "Another characterization lemma for the vector addition on the + Ore localizaion delivering Ore witnesses and conditions bundled in a sigma type."] +def oreDivSMulChar' (r₁ : R) (r₂ : X) (s₁ s₂ : S) : + Σ'r' : R, Σ's' : S, s' * r₁ = r' * s₂ ∧ (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = r' • r₂ /ₒ (s' * s₁) := + ⟨oreNum r₁ s₂, oreDenom r₁ s₂, ore_eq r₁ s₂, oreDiv_smul_oreDiv⟩ + +/-- Another characterization lemma for the multiplication on the Ore localizaion delivering +Ore witnesses and conditions bundled in a sigma type. -/ +@[to_additive "Another characterization lemma for the addition on the Ore localizaion delivering + Ore witnesses and conditions bundled in a sigma type."] +def oreDivMulChar' (r₁ r₂ : R) (s₁ s₂ : S) : + Σ'r' : R, Σ's' : S, s' * r₁ = r' * s₂ ∧ r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r' * r₂ /ₒ (s' * s₁) := + ⟨oreNum r₁ s₂, oreDenom r₁ s₂, ore_eq r₁ s₂, oreDiv_mul_oreDiv⟩ + +/-- `1` in the localization, defined as `1 /ₒ 1`. -/ +@[to_additive (attr := irreducible) "`0` in the additive localization, defined as `0 -ₒ 0`."] +protected def one : R[S⁻¹] := 1 /ₒ 1 + +@[to_additive] +instance : One R[S⁻¹] := + ⟨OreLocalization.one⟩ + +@[to_additive] +protected theorem one_def : (1 : R[S⁻¹]) = 1 /ₒ 1 := by + with_unfolding_all rfl + +@[to_additive] +instance : Inhabited R[S⁻¹] := + ⟨1⟩ + +@[to_additive (attr := simp)] +protected theorem div_eq_one' {r : R} (hr : r ∈ S) : r /ₒ ⟨r, hr⟩ = 1 := by + rw [OreLocalization.one_def, oreDiv_eq_iff] + exact ⟨⟨r, hr⟩, 1, by simp, by simp⟩ + +@[to_additive (attr := simp)] +protected theorem div_eq_one {s : S} : (s : R) /ₒ s = 1 := + OreLocalization.div_eq_one' _ + +@[to_additive] +protected theorem one_smul (x : X[S⁻¹]) : (1 : R[S⁻¹]) • x = x := by + induction' x with r s + simp [OreLocalization.one_def, oreDiv_smul_char 1 r 1 s 1 s (by simp)] + +@[to_additive] +protected theorem one_mul (x : R[S⁻¹]) : 1 * x = x := + OreLocalization.one_smul x + +@[to_additive] +protected theorem mul_one (x : R[S⁻¹]) : x * 1 = x := by + induction' x with r s + simp [OreLocalization.one_def, oreDiv_mul_char r (1 : R) s (1 : S) r 1 (by simp)] + +@[to_additive] +protected theorem mul_smul (x y : R[S⁻¹]) (z : X[S⁻¹]) : (x * y) • z = x • y • z := by + -- Porting note: `assoc_rw` was not ported yet + induction' x with r₁ s₁ + induction' y with r₂ s₂ + induction' z with r₃ s₃ + rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha' + rcases oreDivSMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb' + rcases oreCondition ra sb with ⟨rc, sc, hc⟩ + rw [oreDiv_smul_char (ra * r₂) r₃ (sa * s₁) s₃ (rc * rb) sc]; swap + · rw [← mul_assoc _ ra, hc, mul_assoc, hb, ← mul_assoc] + rw [← mul_assoc, mul_smul] + symm; apply oreDiv_smul_char + rw [Submonoid.coe_mul, Submonoid.coe_mul, ← mul_assoc, ← hc, mul_assoc _ ra, ← ha, mul_assoc] + +@[to_additive] +protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := + OreLocalization.mul_smul x y z + +/-- `npow` of `OreLocalization` -/ +@[to_additive (attr := irreducible) "`nsmul` of `AddOreLocalization`"] +protected def npow : ℕ → R[S⁻¹] → R[S⁻¹] := npowRec + +unseal OreLocalization.npow in +@[to_additive] +instance : Monoid R[S⁻¹] where + one_mul := OreLocalization.one_mul + mul_one := OreLocalization.mul_one + mul_assoc := OreLocalization.mul_assoc + npow := OreLocalization.npow + +@[to_additive] +instance instMulActionOreLocalization : MulAction R[S⁻¹] X[S⁻¹] where + one_smul := OreLocalization.one_smul + mul_smul := OreLocalization.mul_smul + +@[to_additive] +protected theorem mul_inv (s s' : S) : ((s : R) /ₒ s') * ((s' : R) /ₒ s) = 1 := by + simp [oreDiv_mul_char (s : R) s' s' s 1 1 (by simp)] + +@[to_additive (attr := simp)] +protected theorem one_div_smul {r : X} {s t : S} : ((1 : R) /ₒ t) • (r /ₒ s) = r /ₒ (s * t) := by + simp [oreDiv_smul_char 1 r t s 1 s (by simp)] + +@[to_additive (attr := simp)] +protected theorem one_div_mul {r : R} {s t : S} : (1 /ₒ t) * (r /ₒ s) = r /ₒ (s * t) := by + simp [oreDiv_mul_char 1 r t s 1 s (by simp)] + +@[to_additive (attr := simp)] +protected theorem smul_cancel {r : X} {s t : S} : ((s : R) /ₒ t) • (r /ₒ s) = r /ₒ t := by + simp [oreDiv_smul_char s.1 r t s 1 1 (by simp)] + +@[to_additive (attr := simp)] +protected theorem mul_cancel {r : R} {s t : S} : ((s : R) /ₒ t) * (r /ₒ s) = r /ₒ t := by + simp [oreDiv_mul_char s.1 r t s 1 1 (by simp)] + +@[to_additive (attr := simp)] +protected theorem smul_cancel' {r₁ : R} {r₂ : X} {s t : S} : + ((r₁ * s) /ₒ t) • (r₂ /ₒ s) = (r₁ • r₂) /ₒ t := by + simp [oreDiv_smul_char (r₁ * s) r₂ t s r₁ 1 (by simp)] + +@[to_additive (attr := simp)] +protected theorem mul_cancel' {r₁ r₂ : R} {s t : S} : + ((r₁ * s) /ₒ t) * (r₂ /ₒ s) = (r₁ * r₂) /ₒ t := by + simp [oreDiv_mul_char (r₁ * s) r₂ t s r₁ 1 (by simp)] + +@[to_additive (attr := simp)] +theorem smul_div_one {p : R} {r : X} {s : S} : (p /ₒ s) • (r /ₒ 1) = (p • r) /ₒ s := by + simp [oreDiv_smul_char p r s 1 p 1 (by simp)] + +@[to_additive (attr := simp)] +theorem mul_div_one {p r : R} {s : S} : (p /ₒ s) * (r /ₒ 1) = (p * r) /ₒ s := by + --TODO use coercion r ↦ r /ₒ 1 + simp [oreDiv_mul_char p r s 1 p 1 (by simp)] + +/-- The fraction `s /ₒ 1` as a unit in `R[S⁻¹]`, where `s : S`. -/ +@[to_additive "The difference `s -ₒ 0` as a an additive unit."] +def numeratorUnit (s : S) : Units R[S⁻¹] where + val := (s : R) /ₒ 1 + inv := (1 : R) /ₒ s + val_inv := OreLocalization.mul_inv s 1 + inv_val := OreLocalization.mul_inv 1 s + +/-- The multiplicative homomorphism from `R` to `R[S⁻¹]`, mapping `r : R` to the +fraction `r /ₒ 1`. -/ +@[to_additive "The additive homomorphism from `R` to `AddOreLocalization R S`, + mapping `r : R` to the difference `r -ₒ 0`."] +def numeratorHom : R →* R[S⁻¹] where + toFun r := r /ₒ 1 + map_one' := by with_unfolding_all rfl + map_mul' _ _ := mul_div_one.symm + +@[to_additive] +theorem numeratorHom_apply {r : R} : numeratorHom r = r /ₒ (1 : S) := + rfl + +@[to_additive] +theorem numerator_isUnit (s : S) : IsUnit (numeratorHom (s : R) : R[S⁻¹]) := + ⟨numeratorUnit s, rfl⟩ + +section UMP + +variable {T : Type*} [Monoid T] +variable (f : R →* T) (fS : S →* Units T) + +/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`, +to a morphism `R[S⁻¹] →* T`. -/ +@[to_additive "The universal lift from a morphism `R →+ T`, which maps elements of `S` to + additive-units of `T`, to a morphism `AddOreLocalization R S →+ T`."] +def universalMulHom (hf : ∀ s : S, f s = fS s) : R[S⁻¹] →* T where + -- Porting note(#12129): additional beta reduction needed + toFun x := + x.liftExpand (fun r s => ((fS s)⁻¹ : Units T) * f r) fun r t s ht => by + simp only [smul_eq_mul] + have : (fS ⟨t * s, ht⟩ : T) = f t * fS s := by + simp only [← hf, MonoidHom.map_mul] + conv_rhs => + rw [MonoidHom.map_mul, ← one_mul (f r), ← Units.val_one, ← mul_inv_cancel (fS s)] + rw [Units.val_mul, mul_assoc, ← mul_assoc _ (fS s : T), ← this, ← mul_assoc] + simp only [one_mul, Units.inv_mul] + map_one' := by beta_reduce; rw [OreLocalization.one_def, liftExpand_of]; simp + map_mul' x y := by + -- Porting note: `simp only []` required, not just for beta reductions + beta_reduce + simp only [] -- TODO more! + induction' x with r₁ s₁ + induction' y with r₂ s₂ + rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha' + rw [liftExpand_of, liftExpand_of, liftExpand_of, Units.inv_mul_eq_iff_eq_mul, map_mul, map_mul, + Units.val_mul, mul_assoc, ← mul_assoc (fS s₁ : T), ← mul_assoc (fS s₁ : T), Units.mul_inv, + one_mul, ← hf, ← mul_assoc, ← map_mul _ _ r₁, ha, map_mul, hf s₂, mul_assoc, + ← mul_assoc (fS s₂ : T), (fS s₂).mul_inv, one_mul] + +variable (hf : ∀ s : S, f s = fS s) + +@[to_additive] +theorem universalMulHom_apply {r : R} {s : S} : + universalMulHom f fS hf (r /ₒ s) = ((fS s)⁻¹ : Units T) * f r := + rfl + +@[to_additive] +theorem universalMulHom_commutes {r : R} : universalMulHom f fS hf (numeratorHom r) = f r := by + simp [numeratorHom_apply, universalMulHom_apply] + +/-- The universal morphism `universalMulHom` is unique. -/ +@[to_additive "The universal morphism `universalAddHom` is unique."] +theorem universalMulHom_unique (φ : R[S⁻¹] →* T) (huniv : ∀ r : R, φ (numeratorHom r) = f r) : + φ = universalMulHom f fS hf := by + ext x; induction' x with r s + rw [universalMulHom_apply, ← huniv r, numeratorHom_apply, ← one_mul (φ (r /ₒ s)), ← + Units.val_one, ← inv_mul_cancel (fS s), Units.val_mul, mul_assoc, ← hf, ← huniv, ← φ.map_mul, + numeratorHom_apply, OreLocalization.mul_cancel] + +end UMP + +end Monoid + +section SMul + +variable {R R' M X : Type*} [Monoid M] {S : Submonoid M} [OreSet S] [MulAction M X] +variable [SMul R X] [SMul R M] [IsScalarTower R M M] [IsScalarTower R M X] +variable [SMul R' X] [SMul R' M] [IsScalarTower R' M M] [IsScalarTower R' M X] +variable [SMul R R'] [IsScalarTower R R' M] + +/-- Scalar multiplication in a monoid localization. -/ +@[to_additive (attr := irreducible) "Vector addition in an additive monoid localization."] +protected def hsmul (c : R) : + X[S⁻¹] → X[S⁻¹] := + liftExpand (fun m s ↦ oreNum (c • 1) s • m /ₒ oreDenom (c • 1) s) (fun r t s ht ↦ by + dsimp only + rw [← mul_one (oreDenom (c • 1) s), ← oreDiv_smul_oreDiv, ← mul_one (oreDenom (c • 1) _), + ← oreDiv_smul_oreDiv, ← OreLocalization.expand]) + +/- Warning: This gives an diamond on `SMul R[S⁻¹] M[S⁻¹][S⁻¹]`, but we will almost never localize +at the same monoid twice. -/ +/- Although the definition does not require `IsScalarTower R M X`, +it does not make sense without it. -/ +@[to_additive (attr := nolint unusedArguments)] +instance [SMul R X] [SMul R M] [IsScalarTower R M X] [IsScalarTower R M M] : SMul R (X[S⁻¹]) where + smul := OreLocalization.hsmul + +@[to_additive] +theorem smul_oreDiv (r : R) (x : X) (s : S) : + r • (x /ₒ s) = oreNum (r • 1) s • x /ₒ oreDenom (r • 1) s := by with_unfolding_all rfl + +@[to_additive (attr := simp)] +theorem oreDiv_one_smul (r : M) (x : X[S⁻¹]) : (r /ₒ (1 : S)) • x = r • x := by + induction' x using OreLocalization.ind with r' s + rw [smul_oreDiv, oreDiv_smul_oreDiv, mul_one, smul_eq_mul, mul_one] + +@[to_additive] +theorem smul_one_smul (r : R) (x : X[S⁻¹]) : (r • 1 : M) • x = r • x := by + induction' x using OreLocalization.ind with r' s + simp only [smul_oreDiv, smul_eq_mul, mul_one] + +@[to_additive] +theorem smul_one_oreDiv_one_smul (r : R) (x : X[S⁻¹]) : + ((r • 1 : M) /ₒ (1 : S)) • x = r • x := by + rw [oreDiv_one_smul, smul_one_smul] + +@[to_additive] +instance : IsScalarTower R R' X[S⁻¹] where + smul_assoc r m x := by + rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, + ← mul_smul, mul_div_one] + simp only [smul_eq_mul, mul_one, smul_mul_assoc, smul_assoc, one_mul] + +@[to_additive] +instance [SMulCommClass R R' M] : SMulCommClass R R' X[S⁻¹] where + smul_comm r m x := by + rw [← smul_one_smul m, ← smul_assoc, smul_comm, smul_assoc, smul_one_smul] + +@[to_additive] +instance : IsScalarTower R M[S⁻¹] X[S⁻¹] where + smul_assoc r m x := by + rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, ← mul_smul, smul_eq_mul] + +@[to_additive] +instance [SMulCommClass R M M] : SMulCommClass R M[S⁻¹] X[S⁻¹] where + smul_comm r x y := by + induction' x using OreLocalization.ind with r₁ s₁ + induction' y using OreLocalization.ind with r₂ s₂ + rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, smul_smul, smul_smul, + mul_div_one, oreDiv_mul_char _ _ _ _ (r • 1) s₁ (by simp), mul_one] + simp + +@[to_additive] +instance [SMul Rᵐᵒᵖ M] [SMul Rᵐᵒᵖ X] [IsScalarTower Rᵐᵒᵖ M M] [IsScalarTower Rᵐᵒᵖ M X] + [IsCentralScalar R M] : IsCentralScalar R X[S⁻¹] where + op_smul_eq_smul r x := by + rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, op_smul_eq_smul] + +@[to_additive] +instance {R} [Monoid R] [MulAction R M] [IsScalarTower R M M] + [MulAction R X] [IsScalarTower R M X] : MulAction R X[S⁻¹] where + one_smul := OreLocalization.ind fun x s ↦ by + rw [← smul_one_oreDiv_one_smul, one_smul, ← OreLocalization.one_def, one_smul] + mul_smul s₁ s₂ x := by rw [← smul_eq_mul, smul_assoc] + +@[to_additive] +theorem smul_oreDiv_one (r : R) (x : X) : r • (x /ₒ (1 : S)) = (r • x) /ₒ (1 : S) := by + rw [← smul_one_oreDiv_one_smul, smul_div_one, smul_assoc, one_smul] + +end SMul + +section CommMonoid + +variable {R : Type*} [CommMonoid R] {S : Submonoid R} [OreSet S] + +@[to_additive] +theorem oreDiv_mul_oreDiv_comm {r₁ r₂ : R} {s₁ s₂ : S} : + r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r₁ * r₂ /ₒ (s₁ * s₂) := by + rw [oreDiv_mul_char r₁ r₂ s₁ s₂ r₁ s₂ (by simp [mul_comm]), mul_comm s₂] + +@[to_additive] +instance : CommMonoid R[S⁻¹] where + mul_comm := fun x y => by + induction' x with r₁ s₁ + induction' y with r₂ s₂ + rw [oreDiv_mul_oreDiv_comm, oreDiv_mul_oreDiv_comm, mul_comm r₁, mul_comm s₁] + +end CommMonoid + +section Zero + +variable {R : Type*} [Monoid R] {S : Submonoid R} [OreSet S] {X : Type*} [Zero X] +variable [MulAction R X] + + +/-- `0` in the localization, defined as `0 /ₒ 1`. -/ +@[irreducible] +protected def zero : X[S⁻¹] := 0 /ₒ 1 + +instance : Zero X[S⁻¹] := + ⟨OreLocalization.zero⟩ + +protected theorem zero_def : (0 : X[S⁻¹]) = 0 /ₒ 1 := by + with_unfolding_all rfl + +end Zero + +end OreLocalization diff --git a/Mathlib/GroupTheory/OreLocalization/OreSet.lean b/Mathlib/GroupTheory/OreLocalization/OreSet.lean new file mode 100644 index 0000000000000..3f414ea7b61d1 --- /dev/null +++ b/Mathlib/GroupTheory/OreLocalization/OreSet.lean @@ -0,0 +1,120 @@ +/- +Copyright (c) 2022 Jakob von Raumer. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jakob von Raumer, Kevin Klinge +-/ +import Mathlib.Algebra.Group.Submonoid.Defs + +/-! + +# (Left) Ore sets + +This defines left Ore sets on arbitrary monoids. + +## References + +* https://ncatlab.org/nlab/show/Ore+set + +-/ + +namespace AddOreLocalization + +/-- A submonoid `S` of an additive monoid `R` is (left) Ore if common summands on the right can be +turned into common summands on the left, and if each pair of `r : R` and `s : S` admits an Ore +minuend `v : R` and an Ore subtrahend `u : S` such that `u + r = v + s`. -/ +class AddOreSet {R : Type*} [AddMonoid R] (S : AddSubmonoid R) where + /-- Common summands on the right can be turned into common summands on the left, a weak form of +cancellability. -/ + ore_right_cancel : ∀ (r₁ r₂ : R) (s : S), r₁ + s = r₂ + s → ∃ s' : S, s' + r₁ = s' + r₂ + /-- The Ore minuend of a difference. -/ + oreMin : R → S → R + /-- The Ore subtrahend of a difference. -/ + oreSubtra : R → S → S + /-- The Ore condition of a difference, expressed in terms of `oreMin` and `oreSubtra`. -/ + ore_eq : ∀ (r : R) (s : S), oreSubtra r s + r = oreMin r s + s + +end AddOreLocalization + +namespace OreLocalization + +section Monoid + +/-- A submonoid `S` of a monoid `R` is (left) Ore if common factors on the right can be turned +into common factors on the left, and if each pair of `r : R` and `s : S` admits an Ore numerator +`v : R` and an Ore denominator `u : S` such that `u * r = v * s`. -/ +@[to_additive AddOreLocalization.AddOreSet] +class OreSet {R : Type*} [Monoid R] (S : Submonoid R) where + /-- Common factors on the right can be turned into common factors on the left, a weak form of +cancellability. -/ + ore_right_cancel : ∀ (r₁ r₂ : R) (s : S), r₁ * s = r₂ * s → ∃ s' : S, s' * r₁ = s' * r₂ + /-- The Ore numerator of a fraction. -/ + oreNum : R → S → R + /-- The Ore denominator of a fraction. -/ + oreDenom : R → S → S + /-- The Ore condition of a fraction, expressed in terms of `oreNum` and `oreDenom`. -/ + ore_eq : ∀ (r : R) (s : S), oreDenom r s * r = oreNum r s * s + +-- TODO: use this once it's available. +-- run_cmd to_additive.map_namespace `OreLocalization `AddOreLocalization + +variable {R : Type*} [Monoid R] {S : Submonoid R} [OreSet S] + +/-- Common factors on the right can be turned into common factors on the left, a weak form of +cancellability. -/ +@[to_additive AddOreLocalization.ore_right_cancel] +theorem ore_right_cancel (r₁ r₂ : R) (s : S) (h : r₁ * s = r₂ * s) : ∃ s' : S, s' * r₁ = s' * r₂ := + OreSet.ore_right_cancel r₁ r₂ s h + +/-- The Ore numerator of a fraction. -/ +@[to_additive AddOreLocalization.oreMin "The Ore minuend of a difference."] +def oreNum (r : R) (s : S) : R := + OreSet.oreNum r s + +/-- The Ore denominator of a fraction. -/ +@[to_additive AddOreLocalization.oreSubtra "The Ore subtrahend of a difference."] +def oreDenom (r : R) (s : S) : S := + OreSet.oreDenom r s + +/-- The Ore condition of a fraction, expressed in terms of `oreNum` and `oreDenom`. -/ +@[to_additive AddOreLocalization.add_ore_eq + "The Ore condition of a difference, expressed in terms of `oreMin` and `oreSubtra`."] +theorem ore_eq (r : R) (s : S) : oreDenom r s * r = oreNum r s * s := + OreSet.ore_eq r s + +/-- The Ore condition bundled in a sigma type. This is useful in situations where we want to obtain +both witnesses and the condition for a given fraction. -/ +@[to_additive AddOreLocalization.addOreCondition + "The Ore condition bundled in a sigma type. This is useful in situations where we want to obtain +both witnesses and the condition for a given difference."] +def oreCondition (r : R) (s : S) : Σ'r' : R, Σ's' : S, s' * r = r' * s := + ⟨oreNum r s, oreDenom r s, ore_eq r s⟩ + +/-- The trivial submonoid is an Ore set. -/ +@[to_additive AddOreLocalization.addOreSetBot] +instance oreSetBot : OreSet (⊥ : Submonoid R) where + ore_right_cancel _ _ s h := + ⟨s, by + rcases s with ⟨s, hs⟩ + rw [Submonoid.mem_bot] at hs + subst hs + rw [mul_one, mul_one] at h + subst h + rfl⟩ + oreNum r _ := r + oreDenom _ s := s + ore_eq _ s := by + rcases s with ⟨s, hs⟩ + rw [Submonoid.mem_bot] at hs + simp [hs] + +/-- Every submonoid of a commutative monoid is an Ore set. -/ +@[to_additive AddOreLocalization.addOreSetComm] +instance (priority := 100) oreSetComm {R} [CommMonoid R] (S : Submonoid R) : OreSet S where + ore_right_cancel m n s h := ⟨s, by rw [mul_comm (s : R) n, mul_comm (s : R) m, h]⟩ + oreNum r _ := r + oreDenom _ s := s + ore_eq r s := by rw [mul_comm] + +end Monoid + +end OreLocalization diff --git a/Mathlib/GroupTheory/PGroup.lean b/Mathlib/GroupTheory/PGroup.lean index 52fcaf2fb7a60..eb9cdfbf182a9 100644 --- a/Mathlib/GroupTheory/PGroup.lean +++ b/Mathlib/GroupTheory/PGroup.lean @@ -28,7 +28,7 @@ namespace IsPGroup theorem iff_orderOf [hp : Fact p.Prime] : IsPGroup p G ↔ ∀ g : G, ∃ k : ℕ, orderOf g = p ^ k := forall_congr' fun g => - ⟨fun ⟨k, hk⟩ => + ⟨fun ⟨_, hk⟩ => Exists.imp (fun _ h => h.right) ((Nat.dvd_prime_pow hp.out).mp (orderOf_dvd_of_pow_eq_one hk)), Exists.imp fun k hk => by rw [← hk, pow_orderOf_eq_one]⟩ @@ -134,7 +134,7 @@ theorem nontrivial_iff_card [Finite G] : Nontrivial G ↔ ∃ n > 0, Nat.card G Nat.pos_of_ne_zero fun hk0 => by rw [hk0, pow_zero] at hk; exact Finite.one_lt_card.ne' hk, hk⟩, - fun ⟨k, hk0, hk⟩ => + fun ⟨_, hk0, hk⟩ => Finite.one_lt_card_iff_nontrivial.1 <| hk.symm ▸ one_lt_pow₀ (Fact.out (p := p.Prime)).one_lt (ne_of_gt hk0)⟩ @@ -179,7 +179,7 @@ theorem card_modEq_card_fixedPoints : Nat.card α ≡ Nat.card (fixedPoints G α rw [Nat.card_eq_fintype_card] at hk have : k = 0 := by contrapose! hb - simp [-Quotient.eq'', key, hk, hb] + simp [-Quotient.eq, key, hk, hb] exact ⟨⟨b, mem_fixedPoints_iff_card_orbit_eq_one.2 <| by rw [hk, this, pow_zero]⟩, Finset.mem_univ _, ne_of_eq_of_ne Nat.cast_one one_ne_zero, rfl⟩ diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean index 5dc3ff87f4586..70e6c423d6dfd 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -31,14 +31,14 @@ instance instPowNat : Pow (Perm α) ℕ where pow f n := ⟨f^[n], f.symm^[n], f.left_inv.iterate _, f.right_inv.iterate _⟩ instance permGroup : Group (Perm α) where - mul_assoc f g h := (trans_assoc _ _ _).symm + mul_assoc _ _ _ := (trans_assoc _ _ _).symm one_mul := trans_refl mul_one := refl_trans inv_mul_cancel := self_trans_symm npow n f := f ^ n - npow_succ n f := coe_fn_injective <| Function.iterate_succ _ _ + npow_succ _ _ := coe_fn_injective <| Function.iterate_succ _ _ zpow := zpowRec fun n f ↦ f ^ n - zpow_succ' n f := coe_fn_injective <| Function.iterate_succ _ _ + zpow_succ' _ _ := coe_fn_injective <| Function.iterate_succ _ _ @[simp] theorem default_eq : (default : Perm α) = 1 := @@ -351,7 +351,7 @@ theorem subtypePerm_pow (f : Perm α) (n : ℕ) (hf) : | succ n ih => simp_rw [pow_succ', ih, subtypePerm_mul] private theorem zpow_aux (hf : ∀ x, p x ↔ p (f x)) : ∀ {n : ℤ} (x), p x ↔ p ((f ^ n) x) - | Int.ofNat n => pow_aux hf + | Int.ofNat _ => pow_aux hf | Int.negSucc n => by rw [zpow_negSucc] exact inv_aux.1 (pow_aux hf) diff --git a/Mathlib/GroupTheory/Perm/ClosureSwap.lean b/Mathlib/GroupTheory/Perm/ClosureSwap.lean index 304cfc7bc7b78..bc0309ee929ce 100644 --- a/Mathlib/GroupTheory/Perm/ClosureSwap.lean +++ b/Mathlib/GroupTheory/Perm/ClosureSwap.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning, Junyan Xu -/ import Mathlib.Data.Set.Finite +import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.FixedPoints import Mathlib.GroupTheory.Perm.Support @@ -31,7 +32,8 @@ then the support of every element in the group is finite. -/ theorem finite_compl_fixedBy_closure_iff {S : Set G} : (∀ g ∈ closure S, (fixedBy α g)ᶜ.Finite) ↔ ∀ g ∈ S, (fixedBy α g)ᶜ.Finite := ⟨fun h g hg ↦ h g (subset_closure hg), fun h g hg ↦ by - refine closure_induction hg h (by simp) (fun g g' hg hg' ↦ (hg.union hg').subset ?_) (by simp) + refine closure_induction h (by simp) (fun g g' _ _ hg hg' ↦ (hg.union hg').subset ?_) + (by simp) hg simp_rw [← compl_inter, compl_subset_compl, fixedBy_mul]⟩ /-- Given a symmetric generating set of a permutation group, if T is a nonempty proper subset of diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean index a13b28ec141ca..6cf77b57dbfc2 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -278,7 +278,7 @@ theorem isCycle_iff_sameCycle (hx : f x ≠ x) : IsCycle f ↔ ∀ {y}, SameCycl rw [← zpow_apply_eq_self_of_apply_eq_self hy i, (f ^ i).injective.eq_iff] at hi rw [hi, hy], hf.exists_zpow_eq hx⟩, - fun h => ⟨x, hx, fun y hy => h.2 hy⟩⟩ + fun h => ⟨x, hx, fun _ hy => h.2 hy⟩⟩ section Finite @@ -310,7 +310,7 @@ protected theorem IsSwap.isCycle : IsSwap f → IsCycle f := by variable [Fintype α] -theorem IsCycle.two_le_card_support (h : IsCycle f) : 2 ≤ f.support.card := +theorem IsCycle.two_le_card_support (h : IsCycle f) : 2 ≤ #f.support := two_le_card_support_of_ne_one h.ne_one /-- The subgroup generated by a cycle is in bijection with its support -/ @@ -351,7 +351,7 @@ theorem IsCycle.zpowersEquivSupport_symm_apply {σ : Perm α} (hσ : IsCycle σ) ⟨σ ^ n, n, rfl⟩ := (Equiv.symm_apply_eq _).2 hσ.zpowersEquivSupport_apply -protected theorem IsCycle.orderOf (hf : IsCycle f) : orderOf f = f.support.card := by +protected theorem IsCycle.orderOf (hf : IsCycle f) : orderOf f = #f.support := by rw [← Fintype.card_zpowers, ← Fintype.card_coe] convert Fintype.card_congr (IsCycle.zpowersEquivSupport hf) @@ -438,12 +438,12 @@ theorem IsCycle.swap_mul {α : Type*} [DecidableEq α] {f : Perm α} (hf : IsCyc isCycle_swap_mul_aux₂ (i - 1) hy hi⟩ -theorem IsCycle.sign {f : Perm α} (hf : IsCycle f) : sign f = -(-1) ^ f.support.card := +theorem IsCycle.sign {f : Perm α} (hf : IsCycle f) : sign f = -(-1) ^ #f.support := let ⟨x, hx⟩ := hf calc Perm.sign f = Perm.sign (swap x (f x) * (swap x (f x) * f)) := by {rw [← mul_assoc, mul_def, mul_def, swap_swap, trans_refl]} - _ = -(-1) ^ f.support.card := + _ = -(-1) ^ #f.support := if h1 : f (f x) = x then by have h : swap x (f x) * f = 1 := by simp only [mul_def, one_def] @@ -452,14 +452,13 @@ theorem IsCycle.sign {f : Perm α} (hf : IsCycle f) : sign f = -(-1) ^ f.support hf.eq_swap_of_apply_apply_eq_self hx.1 h1, card_support_swap hx.1.symm] rfl else by - have h : card (support (swap x (f x) * f)) + 1 = card (support f) := by + have h : #(swap x (f x) * f).support + 1 = #f.support := by rw [← insert_erase (mem_support.2 hx.1), support_swap_mul_eq _ _ h1, card_insert_of_not_mem (not_mem_erase _ _), sdiff_singleton_eq_erase] - have : card (support (swap x (f x) * f)) < card (support f) := - card_support_swap_mul hx.1 + have : #(swap x (f x) * f).support < #f.support := card_support_swap_mul hx.1 rw [sign_mul, sign_swap hx.1.symm, (hf.swap_mul hx.1 h1).sign, ← h] simp only [mul_neg, neg_mul, one_mul, neg_neg, pow_add, pow_one, mul_one] -termination_by f.support.card +termination_by #f.support theorem IsCycle.of_pow {n : ℕ} (h1 : IsCycle (f ^ n)) (h2 : f.support ⊆ (f ^ n).support) : IsCycle f := by @@ -472,7 +471,7 @@ theorem IsCycle.of_pow {n : ℕ} (h1 : IsCycle (f ^ n)) (h2 : f.support ⊆ (f ^ exact ⟨n * i, by rwa [zpow_mul]⟩ -- The lemma `support_zpow_le` is relevant. It means that `h2` is equivalent to --- `σ.support = (σ ^ n).support`, as well as to `σ.support.card ≤ (σ ^ n).support.card`. +-- `σ.support = (σ ^ n).support`, as well as to `#σ.support ≤ #(σ ^ n).support`. theorem IsCycle.of_zpow {n : ℤ} (h1 : IsCycle (f ^ n)) (h2 : f.support ⊆ (f ^ n).support) : IsCycle f := by cases n @@ -645,7 +644,7 @@ section Conjugation variable [Fintype α] [DecidableEq α] {σ τ : Perm α} -theorem IsCycle.isConj (hσ : IsCycle σ) (hτ : IsCycle τ) (h : σ.support.card = τ.support.card) : +theorem IsCycle.isConj (hσ : IsCycle σ) (hτ : IsCycle τ) (h : #σ.support = #τ.support) : IsConj σ τ := by refine isConj_of_support_equiv @@ -665,7 +664,7 @@ theorem IsCycle.isConj (hσ : IsCycle σ) (hτ : IsCycle τ) (h : σ.support.car rfl theorem IsCycle.isConj_iff (hσ : IsCycle σ) (hτ : IsCycle τ) : - IsConj σ τ ↔ σ.support.card = τ.support.card where + IsConj σ τ ↔ #σ.support = #τ.support where mp h := by obtain ⟨π, rfl⟩ := (_root_.isConj_iff).1 h refine Finset.card_bij (fun a _ => π a) (fun _ ha => ?_) (fun _ _ _ _ ab => π.injective ab) @@ -770,16 +769,15 @@ protected theorem IsCycleOn.subtypePerm (hf : f.IsCycleOn s) : -- TODO: Theory of order of an element under an action theorem IsCycleOn.pow_apply_eq {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) {n : ℕ} : - (f ^ n) a = a ↔ s.card ∣ n := by + (f ^ n) a = a ↔ #s ∣ n := by obtain rfl | hs := Finset.eq_singleton_or_nontrivial ha · rw [coe_singleton, isCycleOn_singleton] at hf simpa using IsFixedPt.iterate hf n classical - have h : ∀ x ∈ s.attach, ¬f ↑x = ↑x := fun x _ => hf.apply_ne hs x.2 + have h (x : s) : ¬f x = x := hf.apply_ne hs x.2 have := (hf.isCycle_subtypePerm hs).orderOf - simp only [coe_sort_coe, support_subtype_perm, ne_eq, decide_not, Bool.not_eq_true', - decide_eq_false_iff_not, mem_attach, forall_true_left, Subtype.forall, filter_true_of_mem h, - card_attach] at this + simp only [coe_sort_coe, support_subtype_perm, ne_eq, h, not_false_eq_true, univ_eq_attach, + mem_attach, imp_self, implies_true, filter_true_of_mem, card_attach] at this rw [← this, orderOf_dvd_iff_pow_eq_one, (hf.isCycle_subtypePerm hs).pow_eq_one_iff' (ne_of_apply_ne ((↑) : s → α) <| hf.apply_ne hs (⟨a, ha⟩ : s).2)] @@ -789,32 +787,32 @@ theorem IsCycleOn.pow_apply_eq {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ simp theorem IsCycleOn.zpow_apply_eq {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) : - ∀ {n : ℤ}, (f ^ n) a = a ↔ (s.card : ℤ) ∣ n - | Int.ofNat n => (hf.pow_apply_eq ha).trans Int.natCast_dvd_natCast.symm + ∀ {n : ℤ}, (f ^ n) a = a ↔ (#s : ℤ) ∣ n + | Int.ofNat _ => (hf.pow_apply_eq ha).trans Int.natCast_dvd_natCast.symm | Int.negSucc n => by rw [zpow_negSucc, ← inv_pow] exact (hf.inv.pow_apply_eq ha).trans (dvd_neg.trans Int.natCast_dvd_natCast).symm theorem IsCycleOn.pow_apply_eq_pow_apply {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) - {m n : ℕ} : (f ^ m) a = (f ^ n) a ↔ m ≡ n [MOD s.card] := by + {m n : ℕ} : (f ^ m) a = (f ^ n) a ↔ m ≡ n [MOD #s] := by rw [Nat.modEq_iff_dvd, ← hf.zpow_apply_eq ha] simp [sub_eq_neg_add, zpow_add, eq_inv_iff_eq, eq_comm] theorem IsCycleOn.zpow_apply_eq_zpow_apply {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) - {m n : ℤ} : (f ^ m) a = (f ^ n) a ↔ m ≡ n [ZMOD s.card] := by + {m n : ℤ} : (f ^ m) a = (f ^ n) a ↔ m ≡ n [ZMOD #s] := by rw [Int.modEq_iff_dvd, ← hf.zpow_apply_eq ha] simp [sub_eq_neg_add, zpow_add, eq_inv_iff_eq, eq_comm] theorem IsCycleOn.pow_card_apply {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) : - (f ^ s.card) a = a := + (f ^ #s) a = a := (hf.pow_apply_eq ha).2 dvd_rfl theorem IsCycleOn.exists_pow_eq {s : Finset α} (hf : f.IsCycleOn s) (ha : a ∈ s) (hb : b ∈ s) : - ∃ n < s.card, (f ^ n) a = b := by + ∃ n < #s, (f ^ n) a = b := by classical obtain ⟨n, rfl⟩ := hf.2 ha hb - obtain ⟨k, hk⟩ := (Int.mod_modEq n s.card).symm.dvd - refine ⟨n.natMod s.card, Int.natMod_lt (Nonempty.card_pos ⟨a, ha⟩).ne', ?_⟩ + obtain ⟨k, hk⟩ := (Int.mod_modEq n #s).symm.dvd + refine ⟨n.natMod #s, Int.natMod_lt (Nonempty.card_pos ⟨a, ha⟩).ne', ?_⟩ rw [← zpow_natCast, Int.natMod, Int.toNat_of_nonneg (Int.emod_nonneg _ <| Nat.cast_ne_zero.2 (Nonempty.card_pos ⟨a, ha⟩).ne'), sub_eq_iff_eq_add'.1 hk, zpow_add, zpow_mul] @@ -931,8 +929,8 @@ namespace Finset variable {f : Perm α} {s : Finset α} theorem product_self_eq_disjiUnion_perm_aux (hf : f.IsCycleOn s) : - (range s.card : Set ℕ).PairwiseDisjoint fun k => - s.map ⟨fun i => (i, (f ^ k) i), fun i j => congr_arg Prod.fst⟩ := by + (range #s : Set ℕ).PairwiseDisjoint fun k => + s.map ⟨fun i => (i, (f ^ k) i), fun _ _ => congr_arg Prod.fst⟩ := by obtain hs | _ := (s : Set α).subsingleton_or_nontrivial · refine Set.Subsingleton.pairwise ?_ _ simp_rw [Set.Subsingleton, mem_coe, ← card_le_one] at hs ⊢ @@ -959,8 +957,8 @@ The diagonals are given by the cycle `f`. -/ theorem product_self_eq_disjiUnion_perm (hf : f.IsCycleOn s) : s ×ˢ s = - (range s.card).disjiUnion - (fun k => s.map ⟨fun i => (i, (f ^ k) i), fun i j => congr_arg Prod.fst⟩) + (range #s).disjiUnion + (fun k => s.map ⟨fun i => (i, (f ^ k) i), fun _ _ => congr_arg Prod.fst⟩) (product_self_eq_disjiUnion_perm_aux hf) := by ext ⟨a, b⟩ simp only [mem_product, Equiv.Perm.coe_pow, mem_disjiUnion, mem_range, mem_map, @@ -978,12 +976,12 @@ namespace Finset variable [Semiring α] [AddCommMonoid β] [Module α β] {s : Finset ι} {σ : Perm ι} theorem sum_smul_sum_eq_sum_perm (hσ : σ.IsCycleOn s) (f : ι → α) (g : ι → β) : - (∑ i ∈ s, f i) • ∑ i ∈ s, g i = ∑ k ∈ range s.card, ∑ i ∈ s, f i • g ((σ ^ k) i) := by + (∑ i ∈ s, f i) • ∑ i ∈ s, g i = ∑ k ∈ range #s, ∑ i ∈ s, f i • g ((σ ^ k) i) := by rw [sum_smul_sum, ← sum_product'] simp_rw [product_self_eq_disjiUnion_perm hσ, sum_disjiUnion, sum_map, Embedding.coeFn_mk] theorem sum_mul_sum_eq_sum_perm (hσ : σ.IsCycleOn s) (f g : ι → α) : - ((∑ i ∈ s, f i) * ∑ i ∈ s, g i) = ∑ k ∈ range s.card, ∑ i ∈ s, f i * g ((σ ^ k) i) := + ((∑ i ∈ s, f i) * ∑ i ∈ s, g i) = ∑ k ∈ range #s, ∑ i ∈ s, f i * g ((σ ^ k) i) := sum_smul_sum_eq_sum_perm hσ f g end Finset @@ -1094,10 +1092,10 @@ theorem zpow_eq_ofSubtype_subtypePerm_iff theorem cycle_zpow_mem_support_iff {g : Perm α} (hg : g.IsCycle) {n : ℤ} {x : α} (hx : g x ≠ x) : - (g ^ n) x = x ↔ n % g.support.card = 0 := by - set q := n / g.support.card - set r := n % g.support.card - have div_euc : r + g.support.card * q = n ∧ 0 ≤ r ∧ r < g.support.card := by + (g ^ n) x = x ↔ n % #g.support = 0 := by + set q := n / #g.support + set r := n % #g.support + have div_euc : r + #g.support * q = n ∧ 0 ≤ r ∧ r < #g.support := by rw [← Int.ediv_emod_unique _] · exact ⟨rfl, rfl⟩ simp only [Int.natCast_pos] diff --git a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean index c16d73ee548bd..806d527b92bc4 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean @@ -118,7 +118,7 @@ end List namespace Cycle -variable [DecidableEq α] (s s' : Cycle α) +variable [DecidableEq α] (s : Cycle α) /-- A cycle `s : Cycle α`, given `Nodup s` can be interpreted as an `Equiv.Perm α` where each element in the list is permuted to the next one, defined as `formPerm`. @@ -325,7 +325,7 @@ theorem toList_formPerm_isRotated_self (l : List α) (hl : 2 ≤ l.length) (hn : rw [formPerm_eq_of_isRotated hn hr] rw [get_eq_get_rotate l k k] simp only [Nat.mod_eq_of_lt k.2, tsub_add_cancel_of_le (le_of_lt k.2), Nat.mod_self] - erw [toList_formPerm_nontrivial] + rw [toList_formPerm_nontrivial] · simp · simpa using hl · simpa using hn diff --git a/Mathlib/GroupTheory/Perm/Cycle/Factors.lean b/Mathlib/GroupTheory/Perm/Cycle/Factors.lean index e2fc3224e97be..aa5260cd2a4c3 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Factors.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Factors.lean @@ -166,7 +166,7 @@ theorem isCycle_cycleOf (f : Perm α) [DecidableRel f.SameCycle] (hx : f x ≠ x @[simp] theorem two_le_card_support_cycleOf_iff [DecidableEq α] [Fintype α] : - 2 ≤ card (cycleOf f x).support ↔ f x ≠ x := by + 2 ≤ #(cycleOf f x).support ↔ f x ≠ x := by refine ⟨fun h => ?_, fun h => by simpa using (isCycle_cycleOf _ h).two_le_card_support⟩ contrapose! h rw [← cycleOf_eq_one_iff] at h @@ -179,7 +179,7 @@ theorem two_le_card_support_cycleOf_iff [DecidableEq α] [Fintype α] : @[deprecated support_cycleOf_nonempty (since := "2024-06-16")] theorem card_support_cycleOf_pos_iff [DecidableEq α] [Fintype α] : - 0 < card (cycleOf f x).support ↔ f x ≠ x := by + 0 < #(cycleOf f x).support ↔ f x ≠ x := by rw [card_pos, support_cycleOf_nonempty] theorem pow_mod_orderOf_cycleOf_apply (f : Perm α) [DecidableRel f.SameCycle] (n : ℕ) (x : α) : @@ -241,7 +241,7 @@ theorem SameCycle.mem_support_iff {f} [DecidableEq α] [Fintype α] (h : SameCyc support_cycleOf_le f y (mem_support_cycleOf_iff.mpr ⟨h.symm, hy⟩)⟩ theorem pow_mod_card_support_cycleOf_self_apply [DecidableEq α] [Fintype α] - (f : Perm α) (n : ℕ) (x : α) : (f ^ (n % (f.cycleOf x).support.card)) x = (f ^ n) x := by + (f : Perm α) (n : ℕ) (x : α) : (f ^ (n % #(f.cycleOf x).support)) x = (f ^ n) x := by by_cases hx : f x = x · rw [pow_apply_eq_self_of_apply_eq_self hx, pow_apply_eq_self_of_apply_eq_self hx] · rw [← cycleOf_pow_apply_self, ← cycleOf_pow_apply_self f, ← (isCycle_cycleOf f hx).orderOf, @@ -268,17 +268,17 @@ theorem isCycleOn_support_cycleOf [DecidableEq α] [Fintype α] (f : Perm α) (x exact ha.1.symm.trans hb.1⟩ theorem SameCycle.exists_pow_eq_of_mem_support {f} [DecidableEq α] [Fintype α] (h : SameCycle f x y) - (hx : x ∈ f.support) : ∃ i < (f.cycleOf x).support.card, (f ^ i) x = y := by + (hx : x ∈ f.support) : ∃ i < #(f.cycleOf x).support, (f ^ i) x = y := by rw [mem_support] at hx exact Equiv.Perm.IsCycleOn.exists_pow_eq (b := y) (f.isCycleOn_support_cycleOf x) (by rw [mem_support_cycleOf_iff' hx]) (by rwa [mem_support_cycleOf_iff' hx]) theorem SameCycle.exists_pow_eq [DecidableEq α] [Fintype α] (f : Perm α) (h : SameCycle f x y) : - ∃ i : ℕ, 0 < i ∧ i ≤ (f.cycleOf x).support.card + 1 ∧ (f ^ i) x = y := by + ∃ i : ℕ, 0 < i ∧ i ≤ #(f.cycleOf x).support + 1 ∧ (f ^ i) x = y := by by_cases hx : x ∈ f.support · obtain ⟨k, hk, hk'⟩ := h.exists_pow_eq_of_mem_support hx cases' k with k - · refine ⟨(f.cycleOf x).support.card, ?_, self_le_add_right _ _, ?_⟩ + · refine ⟨#(f.cycleOf x).support, ?_, self_le_add_right _ _, ?_⟩ · refine zero_lt_one.trans (one_lt_card_support_of_ne_one ?_) simpa using hx · simp only [pow_zero, coe_one, id_eq] at hk' @@ -293,8 +293,7 @@ theorem SameCycle.exists_pow_eq [DecidableEq α] [Fintype α] (f : Perm α) (h : theorem zpow_eq_zpow_on_iff [DecidableEq α] [Fintype α] (g : Perm α) {m n : ℤ} {x : α} (hx : g x ≠ x) : - (g ^ m) x = (g ^ n) x ↔ - m % (g.cycleOf x).support.card = n % (g.cycleOf x).support.card := by + (g ^ m) x = (g ^ n) x ↔ m % #(g.cycleOf x).support = n % #(g.cycleOf x).support := by rw [Int.emod_eq_emod_iff_emod_sub_eq_zero] conv_lhs => rw [← Int.sub_add_cancel m n, Int.add_comm, zpow_add] simp only [coe_mul, Function.comp_apply, EmbeddingLike.apply_eq_iff_eq] diff --git a/Mathlib/GroupTheory/Perm/Cycle/Type.lean b/Mathlib/GroupTheory/Perm/Cycle/Type.lean index 5a823f43577e4..c690004e7f541 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean @@ -461,7 +461,7 @@ theorem _root_.exists_prime_orderOf_dvd_card {G : Type*} [Group G] [Fintype G] ( /-- For every prime `p` dividing the order of a finite additive group `G` there exists an element of order `p` in `G`. This is the additive version of Cauchy's theorem. -/ theorem _root_.exists_prime_addOrderOf_dvd_card {G : Type*} [AddGroup G] [Fintype G] (p : ℕ) - [hp : Fact p.Prime] (hdvd : p ∣ Fintype.card G) : ∃ x : G, addOrderOf x = p := + [Fact p.Prime] (hdvd : p ∣ Fintype.card G) : ∃ x : G, addOrderOf x = p := @exists_prime_orderOf_dvd_card (Multiplicative G) _ _ _ _ (by convert hdvd) attribute [to_additive existing] exists_prime_orderOf_dvd_card diff --git a/Mathlib/GroupTheory/Perm/DomMulAct.lean b/Mathlib/GroupTheory/Perm/DomMulAct.lean index 4bfd4c758ab0d..37e7b1a23eb39 100644 --- a/Mathlib/GroupTheory/Perm/DomMulAct.lean +++ b/Mathlib/GroupTheory/Perm/DomMulAct.lean @@ -3,12 +3,12 @@ Copyright (c) 2023 Junyan Xu, Antoine Chambert-Loir. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Junyan Xu, Antoine Chambert-Loir -/ -import Mathlib.Algebra.Group.Subgroup.Basic -import Mathlib.GroupTheory.GroupAction.DomAct.Basic -import Mathlib.GroupTheory.GroupAction.Basic +import Mathlib.Algebra.Group.Action.Basic import Mathlib.Data.Fintype.Basic import Mathlib.Data.Fintype.Perm import Mathlib.Data.Set.Card +import Mathlib.GroupTheory.GroupAction.Defs +import Mathlib.GroupTheory.GroupAction.DomAct.Basic import Mathlib.SetTheory.Cardinal.Finite /-! Subgroup of `Equiv.Perm α` preserving a function @@ -77,9 +77,9 @@ def stabilizerMulEquiv : (stabilizer (Perm α)ᵈᵐᵃ f)ᵐᵒᵖ ≃* (∀ i, ext a rw [smul_apply, symm_apply_apply, Perm.smul_def] apply comp_stabilizerEquiv_invFun⟩ - left_inv g := rfl + left_inv _ := rfl right_inv g := by ext i a; apply stabilizerEquiv_invFun_eq - map_mul' g h := rfl + map_mul' _ _ := rfl variable {f} @@ -139,7 +139,7 @@ theorem stabilizer_card': rw [refl_apply, ← Subtype.coe_inj] simp only [φ, Set.val_codRestrict_apply] · intro g - simp only [Function.funext_iff] + simp only [funext_iff] apply forall_congr' intro a simp only [Function.comp_apply, φ, ← Subtype.coe_inj, Set.val_codRestrict_apply] diff --git a/Mathlib/GroupTheory/Perm/Fin.lean b/Mathlib/GroupTheory/Perm/Fin.lean index 7df1d1ceaefbe..6d0fa972e68ea 100644 --- a/Mathlib/GroupTheory/Perm/Fin.lean +++ b/Mathlib/GroupTheory/Perm/Fin.lean @@ -151,7 +151,7 @@ theorem cycleRange_of_gt {n : ℕ} {i j : Fin n.succ} (h : i < j) : cycleRange i theorem cycleRange_of_le {n : ℕ} {i j : Fin n.succ} (h : j ≤ i) : cycleRange i j = if j = i then 0 else j + 1 := by cases n - · exact Subsingleton.elim (α := Fin 1) _ _ --Porting note; was `simp` + · subsingleton have : j = (Fin.castLE (Nat.succ_le_of_lt i.is_lt)) ⟨j, lt_of_le_of_lt h (Nat.lt_succ_self i)⟩ := by simp ext diff --git a/Mathlib/GroupTheory/Perm/Finite.lean b/Mathlib/GroupTheory/Perm/Finite.lean index 4c4f0cfef47b7..8c9cb242cb255 100644 --- a/Mathlib/GroupTheory/Perm/Finite.lean +++ b/Mathlib/GroupTheory/Perm/Finite.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Int.Order.Units import Mathlib.GroupTheory.OrderOfElement import Mathlib.GroupTheory.Perm.Support import Mathlib.Logic.Equiv.Fintype +import Mathlib.Data.Finite.Sum /-! # Permutations on `Fintype`s @@ -183,9 +184,9 @@ theorem Disjoint.isConj_mul [Finite α] {σ τ π ρ : Perm α} (hc1 : IsConj σ have hd2'' := disjoint_coe.2 (disjoint_iff_disjoint_support.1 hd2) refine isConj_of_support_equiv ?_ ?_ · refine - ((Equiv.Set.ofEq hd1').trans (Equiv.Set.union hd1''.le_bot)).trans + ((Equiv.Set.ofEq hd1').trans (Equiv.Set.union hd1'')).trans ((Equiv.sumCongr (subtypeEquiv f fun a => ?_) (subtypeEquiv g fun a => ?_)).trans - ((Equiv.Set.ofEq hd2').trans (Equiv.Set.union hd2''.le_bot)).symm) <;> + ((Equiv.Set.ofEq hd2').trans (Equiv.Set.union hd2'')).symm) <;> · simp only [Set.mem_image, toEmbedding_apply, exists_eq_right, support_conj, coe_map, apply_eq_iff_eq] · intro x hx @@ -194,7 +195,7 @@ theorem Disjoint.isConj_mul [Finite α] {σ τ π ρ : Perm α} (hc1 : IsConj σ rw [hd1', Set.mem_union] at hx cases' hx with hxσ hxτ · rw [mem_coe, mem_support] at hxσ - rw [Set.union_apply_left hd1''.le_bot _, Set.union_apply_left hd1''.le_bot _] + rw [Set.union_apply_left, Set.union_apply_left] · simp only [subtypeEquiv_apply, Perm.coe_mul, Sum.map_inl, comp_apply, Set.union_symm_apply_left, Subtype.coe_mk, apply_eq_iff_eq] have h := (hd2 (f x)).resolve_left ?_ @@ -205,7 +206,7 @@ theorem Disjoint.isConj_mul [Finite α] {σ τ π ρ : Perm α} (hc1 : IsConj σ · rwa [Subtype.coe_mk, Perm.mul_apply, (hd1 x).resolve_left hxσ, mem_coe, apply_mem_support, mem_support] · rw [mem_coe, ← apply_mem_support, mem_support] at hxτ - rw [Set.union_apply_right hd1''.le_bot _, Set.union_apply_right hd1''.le_bot _] + rw [Set.union_apply_right, Set.union_apply_right] · simp only [subtypeEquiv_apply, Perm.coe_mul, Sum.map_inr, comp_apply, Set.union_symm_apply_right, Subtype.coe_mk, apply_eq_iff_eq] have h := (hd2 (g (τ x))).resolve_right ?_ diff --git a/Mathlib/GroupTheory/Perm/List.lean b/Mathlib/GroupTheory/Perm/List.lean index 1cdc01f35e5cd..8e9416970a1b3 100644 --- a/Mathlib/GroupTheory/Perm/List.lean +++ b/Mathlib/GroupTheory/Perm/List.lean @@ -257,7 +257,7 @@ theorem formPerm_eq_of_isRotated {l l' : List α} (hd : Nodup l) (h : l ~r l') : theorem formPerm_append_pair : ∀ (l : List α) (a b : α), formPerm (l ++ [a, b]) = formPerm (l ++ [a]) * swap a b | [], _, _ => rfl - | [x], _, _ => rfl + | [_], _, _ => rfl | x::y::l, a, b => by simpa [mul_assoc] using formPerm_append_pair (y::l) a b diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index 269920ef0aab3..41c9a40ec36c5 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Data.Finset.Fin import Mathlib.Data.Finset.Sort +import Mathlib.Data.Fintype.Sum import Mathlib.Data.Int.Order.Units import Mathlib.GroupTheory.Perm.Support import Mathlib.Logic.Equiv.Fin @@ -72,7 +73,7 @@ def swapFactorsAux : ⟨swap x (f x)::m.1, by rw [List.prod_cons, m.2.1, ← mul_assoc, mul_def (swap x (f x)), swap_swap, ← one_def, one_mul], - fun {g} hg => ((List.mem_cons).1 hg).elim (fun h => ⟨x, f x, hfx, h⟩) (m.2.2 _)⟩ + fun {_} hg => ((List.mem_cons).1 hg).elim (fun h => ⟨x, f x, hfx, h⟩) (m.2.2 _)⟩ /-- `swapFactors` represents a permutation as a product of a list of transpositions. The representation is non unique and depends on the linear order structure. @@ -245,7 +246,7 @@ theorem signAux_mul {n : ℕ} (f g : Perm (Fin n)) : signAux (f * g) = signAux f rfl private theorem signAux_swap_zero_one' (n : ℕ) : signAux (swap (0 : Fin (n + 2)) 1) = -1 := - show _ = ∏ x ∈ {(⟨1, 0⟩ : Σ a : Fin (n + 2), Fin (n + 2))}, + show _ = ∏ x ∈ {(⟨1, 0⟩ : Σ _ : Fin (n + 2), Fin (n + 2))}, if (Equiv.swap 0 1) x.1 ≤ swap 0 1 x.2 then (-1 : ℤˣ) else 1 by refine Eq.symm (prod_subset (fun ⟨x₁, x₂⟩ => by simp (config := { contextual := true }) [mem_finPairsLT, Fin.one_pos]) fun a ha₁ ha₂ => ?_) @@ -369,7 +370,7 @@ section SignType.sign variable [Fintype α] ---@[simp] Porting note (#10618): simp can prove +@[simp] theorem sign_mul (f g : Perm α) : sign (f * g) = sign f * sign g := MonoidHom.map_mul sign f g @@ -377,7 +378,7 @@ theorem sign_mul (f g : Perm α) : sign (f * g) = sign f * sign g := theorem sign_trans (f g : Perm α) : sign (f.trans g) = sign g * sign f := by rw [← mul_def, sign_mul] ---@[simp] Porting note (#10618): simp can prove +@[simp] theorem sign_one : sign (1 : Perm α) = 1 := MonoidHom.map_one sign @@ -385,7 +386,7 @@ theorem sign_one : sign (1 : Perm α) = 1 := theorem sign_refl : sign (Equiv.refl α) = 1 := MonoidHom.map_one sign ---@[simp] Porting note (#10618): simp can prove +@[simp] theorem sign_inv (f : Perm α) : sign f⁻¹ = sign f := by rw [MonoidHom.map_inv sign f, Int.units_inv_eq_self] @@ -495,7 +496,7 @@ theorem sign_bij [DecidableEq β] [Fintype β] {f : Perm α} {g : Perm β} (i : rw [← h _ x.2 this] exact mt (hi _ _ this x.2) x.2⟩ : { y // g y ≠ y })) - ⟨fun ⟨x, hx⟩ ⟨y, hy⟩ h => Subtype.eq (hi _ _ _ _ (Subtype.mk.inj h)), fun ⟨y, hy⟩ => + ⟨fun ⟨_, _⟩ ⟨_, _⟩ h => Subtype.eq (hi _ _ _ _ (Subtype.mk.inj h)), fun ⟨y, hy⟩ => let ⟨x, hfx, hx⟩ := hg y hy ⟨⟨x, hfx⟩, Subtype.eq hx⟩⟩) fun ⟨x, _⟩ => Subtype.eq (h x _ _) diff --git a/Mathlib/GroupTheory/Perm/Support.lean b/Mathlib/GroupTheory/Perm/Support.lean index f95ba42476e2a..10124edc16294 100644 --- a/Mathlib/GroupTheory/Perm/Support.lean +++ b/Mathlib/GroupTheory/Perm/Support.lean @@ -264,8 +264,7 @@ theorem apply_zpow_apply_eq_iff (f : Perm α) (n : ℤ) {x : α} : variable [DecidableEq α] [Fintype α] {f g : Perm α} /-- The `Finset` of nonfixed points of a permutation. -/ -def support (f : Perm α) : Finset α := - univ.filter fun x => f x ≠ x +def support (f : Perm α) : Finset α := {x | f x ≠ x} @[simp] theorem mem_support {x : α} : x ∈ f.support ↔ f x ≠ x := by @@ -328,7 +327,6 @@ theorem support_pow_le (σ : Perm α) (n : ℕ) : (σ ^ n).support ≤ σ.suppor theorem support_inv (σ : Perm α) : support σ⁻¹ = σ.support := by simp_rw [Finset.ext_iff, mem_support, not_iff_not, inv_eq_iff_eq.trans eq_comm, imp_true_iff] --- @[simp] -- Porting note (#10618): simp can prove this theorem apply_mem_support {x : α} : f x ∈ f.support ↔ x ∈ f.support := by rw [mem_support, mem_support, Ne, Ne, apply_eq_iff_eq] @@ -363,11 +361,9 @@ lemma ofSubtype_eq_iff {g c : Equiv.Perm α} {s : Finset α} · rw [ofSubtype_apply_of_not_mem (p := (· ∈ s)) _ ha, eq_comm, ← not_mem_support] exact Finset.not_mem_mono hc ha --- @[simp] -- Porting note (#10618): simp can prove this theorem pow_apply_mem_support {n : ℕ} {x : α} : (f ^ n) x ∈ f.support ↔ x ∈ f.support := by simp only [mem_support, ne_eq, apply_pow_apply_eq_iff] --- @[simp] -- Porting note (#10618): simp can prove this theorem zpow_apply_mem_support {n : ℤ} {x : α} : (f ^ n) x ∈ f.support ↔ x ∈ f.support := by simp only [mem_support, ne_eq, apply_zpow_apply_eq_iff] @@ -529,48 +525,47 @@ theorem support_extend_domain (f : α ≃ Subtype p) {g : Perm α} : exact pb (Subtype.prop _) theorem card_support_extend_domain (f : α ≃ Subtype p) {g : Perm α} : - (g.extendDomain f).support.card = g.support.card := by simp + #(g.extendDomain f).support = #g.support := by simp end ExtendDomain section Card --- @[simp] -- Porting note (#10618): simp can prove thisrove this -theorem card_support_eq_zero {f : Perm α} : f.support.card = 0 ↔ f = 1 := by +theorem card_support_eq_zero {f : Perm α} : #f.support = 0 ↔ f = 1 := by rw [Finset.card_eq_zero, support_eq_empty_iff] -theorem one_lt_card_support_of_ne_one {f : Perm α} (h : f ≠ 1) : 1 < f.support.card := by +theorem one_lt_card_support_of_ne_one {f : Perm α} (h : f ≠ 1) : 1 < #f.support := by simp_rw [one_lt_card_iff, mem_support, ← not_or] contrapose! h ext a specialize h (f a) a rwa [apply_eq_iff_eq, or_self_iff, or_self_iff] at h -theorem card_support_ne_one (f : Perm α) : f.support.card ≠ 1 := by +theorem card_support_ne_one (f : Perm α) : #f.support ≠ 1 := by by_cases h : f = 1 · exact ne_of_eq_of_ne (card_support_eq_zero.mpr h) zero_ne_one · exact ne_of_gt (one_lt_card_support_of_ne_one h) @[simp] -theorem card_support_le_one {f : Perm α} : f.support.card ≤ 1 ↔ f = 1 := by +theorem card_support_le_one {f : Perm α} : #f.support ≤ 1 ↔ f = 1 := by rw [le_iff_lt_or_eq, Nat.lt_succ_iff, Nat.le_zero, card_support_eq_zero, or_iff_not_imp_right, imp_iff_right f.card_support_ne_one] -theorem two_le_card_support_of_ne_one {f : Perm α} (h : f ≠ 1) : 2 ≤ f.support.card := +theorem two_le_card_support_of_ne_one {f : Perm α} (h : f ≠ 1) : 2 ≤ #f.support := one_lt_card_support_of_ne_one h theorem card_support_swap_mul {f : Perm α} {x : α} (hx : f x ≠ x) : - (swap x (f x) * f).support.card < f.support.card := + #(swap x (f x) * f).support < #f.support := Finset.card_lt_card - ⟨fun z hz => (mem_support_swap_mul_imp_mem_support_ne hz).left, fun h => + ⟨fun _ hz => (mem_support_swap_mul_imp_mem_support_ne hz).left, fun h => absurd (h (mem_support.2 hx)) (mt mem_support.1 (by simp))⟩ -theorem card_support_swap {x y : α} (hxy : x ≠ y) : (swap x y).support.card = 2 := - show (swap x y).support.card = Finset.card ⟨x ::ₘ y ::ₘ 0, by simp [hxy]⟩ from +theorem card_support_swap {x y : α} (hxy : x ≠ y) : #(swap x y).support = 2 := + show #(swap x y).support = #⟨x ::ₘ y ::ₘ 0, by simp [hxy]⟩ from congr_arg card <| by simp [support_swap hxy, *, Finset.ext_iff] @[simp] -theorem card_support_eq_two {f : Perm α} : f.support.card = 2 ↔ IsSwap f := by +theorem card_support_eq_two {f : Perm α} : #f.support = 2 ↔ IsSwap f := by constructor <;> intro h · obtain ⟨x, t, hmem, hins, ht⟩ := card_eq_succ.1 h obtain ⟨y, rfl⟩ := card_eq_one.1 ht @@ -589,7 +584,7 @@ theorem card_support_eq_two {f : Perm α} : f.support.card = 2 ↔ IsSwap f := b exact card_support_swap hxy theorem Disjoint.card_support_mul (h : Disjoint f g) : - (f * g).support.card = f.support.card + g.support.card := by + #(f * g).support = #f.support + #g.support := by rw [← Finset.card_union_of_disjoint] · congr ext @@ -597,7 +592,7 @@ theorem Disjoint.card_support_mul (h : Disjoint f g) : · simpa using h.disjoint_support theorem card_support_prod_list_of_pairwise_disjoint {l : List (Perm α)} (h : l.Pairwise Disjoint) : - l.prod.support.card = (l.map (Finset.card ∘ support)).sum := by + #l.prod.support = (l.map (card ∘ support)).sum := by induction' l with a t ih · exact card_support_eq_zero.mpr rfl · obtain ⟨ha, ht⟩ := List.pairwise_cons.1 h @@ -610,10 +605,8 @@ end support @[simp] theorem support_subtype_perm [DecidableEq α] {s : Finset α} (f : Perm α) (h) : - ((f.subtypePerm h : Perm { x // x ∈ s }).support) = - (s.attach.filter ((fun x => decide (f x ≠ x))) : Finset { x // x ∈ s }) := by - ext - simp [Subtype.ext_iff] + (f.subtypePerm h : Perm s).support = ({x | f x ≠ x} : Finset s) := by + ext; simp [Subtype.ext_iff] end Equiv.Perm @@ -627,7 +620,7 @@ namespace Equiv.Perm variable {α : Type*} theorem fixed_point_card_lt_of_ne_one [DecidableEq α] [Fintype α] {σ : Perm α} (h : σ ≠ 1) : - (filter (fun x => σ x = x) univ).card < Fintype.card α - 1 := by + #{x | σ x = x} < Fintype.card α - 1 := by rw [Nat.lt_sub_iff_add_lt, ← Nat.lt_sub_iff_add_lt', ← Finset.card_compl, Finset.compl_filter] exact one_lt_card_support_of_ne_one h @@ -647,7 +640,7 @@ theorem support_conj : (σ * τ * σ⁻¹).support = τ.support.map σ.toEmbeddi simp only [mem_map_equiv, Perm.coe_mul, Function.comp_apply, Ne, Perm.mem_support, Equiv.eq_symm_apply, inv_def] -theorem card_support_conj : (σ * τ * σ⁻¹).support.card = τ.support.card := by simp +theorem card_support_conj : #(σ * τ * σ⁻¹).support = #τ.support := by simp end Equiv.Perm diff --git a/Mathlib/GroupTheory/PresentedGroup.lean b/Mathlib/GroupTheory/PresentedGroup.lean index 35916a0da95d5..f1bf24a4e9739 100644 --- a/Mathlib/GroupTheory/PresentedGroup.lean +++ b/Mathlib/GroupTheory/PresentedGroup.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Howes, Newell Jensen -/ import Mathlib.GroupTheory.FreeGroup.Basic -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Defining a group given by generators and relations diff --git a/Mathlib/GroupTheory/PushoutI.lean b/Mathlib/GroupTheory/PushoutI.lean index ab561721ed4f6..0f672f3da1e25 100644 --- a/Mathlib/GroupTheory/PushoutI.lean +++ b/Mathlib/GroupTheory/PushoutI.lean @@ -152,7 +152,7 @@ def homEquiv : invFun := fun f => lift f.1.1 f.1.2 f.2, left_inv := fun _ => hom_ext (by simp [DFunLike.ext_iff]) (by simp [DFunLike.ext_iff]) - right_inv := fun ⟨⟨_, _⟩, _⟩ => by simp [DFunLike.ext_iff, Function.funext_iff] } + right_inv := fun ⟨⟨_, _⟩, _⟩ => by simp [DFunLike.ext_iff, funext_iff] } /-- The map from the coproduct into the pushout -/ def ofCoprodI : CoprodI G →* PushoutI φ := @@ -454,7 +454,7 @@ theorem summand_smul_def' {i : ι} (g : G i) (w : NormalWord d) : noncomputable instance mulAction : MulAction (PushoutI φ) (NormalWord d) := MulAction.ofEndHom <| lift - (fun i => MulAction.toEndHom) + (fun _ => MulAction.toEndHom) MulAction.toEndHom <| by intro i simp only [MulAction.toEndHom, DFunLike.ext_iff, MonoidHom.coe_comp, MonoidHom.coe_mk, @@ -596,7 +596,7 @@ theorem of_injective (hφ : ∀ i, Function.Injective (φ i)) (i : ι) : (f := ((· • ·) : PushoutI φ → NormalWord d → NormalWord d)) ?_ intros _ _ h exact eq_of_smul_eq_smul (fun w : NormalWord d => - by simp_all [Function.funext_iff, of_smul_eq_smul]) + by simp_all [funext_iff, of_smul_eq_smul]) theorem base_injective (hφ : ∀ i, Function.Injective (φ i)) : Function.Injective (base φ) := by @@ -607,7 +607,7 @@ theorem base_injective (hφ : ∀ i, Function.Injective (φ i)) : (f := ((· • ·) : PushoutI φ → NormalWord d → NormalWord d)) ?_ intros _ _ h exact eq_of_smul_eq_smul (fun w : NormalWord d => - by simp_all [Function.funext_iff, base_smul_eq_smul]) + by simp_all [funext_iff, base_smul_eq_smul]) section Reduced diff --git a/Mathlib/GroupTheory/QuotientGroup/Basic.lean b/Mathlib/GroupTheory/QuotientGroup/Basic.lean index ec446e552f0d8..4495ebe68b078 100644 --- a/Mathlib/GroupTheory/QuotientGroup/Basic.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Basic.lean @@ -6,8 +6,9 @@ Authors: Kevin Buzzard, Patrick Massot -- This file is to a certain extent based on `quotient_module.lean` by Johannes Hölzl. import Mathlib.Algebra.Group.Subgroup.Pointwise -import Mathlib.GroupTheory.Congruence.Basic +import Mathlib.GroupTheory.Congruence.Hom import Mathlib.GroupTheory.Coset.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs /-! # Quotients of groups by normal subgroups @@ -15,14 +16,6 @@ import Mathlib.GroupTheory.Coset.Basic This files develops the basic theory of quotients of groups by normal subgroups. In particular it proves Noether's first and second isomorphism theorems. -## Main definitions - -* `mk'`: the canonical group homomorphism `G →* G/N` given a normal subgroup `N` of `G`. -* `lift φ`: the group homomorphism `G/N →* H` given a group homomorphism `φ : G →* H` such that - `N ⊆ ker φ`. -* `map f`: the group homomorphism `G/N →* H/M` given a group homomorphism `f : G →* H` such that - `N ⊆ f⁻¹(M)`. - ## Main statements * `QuotientGroup.quotientKerEquivRange`: Noether's first isomorphism theorem, an explicit @@ -47,44 +40,6 @@ namespace QuotientGroup variable {G : Type u} [Group G] (N : Subgroup G) [nN : N.Normal] {H : Type v} [Group H] {M : Type x} [Monoid M] -/-- The congruence relation generated by a normal subgroup. -/ -@[to_additive "The additive congruence relation generated by a normal additive subgroup."] -protected def con : Con G where - toSetoid := leftRel N - mul' := fun {a b c d} hab hcd => by - rw [leftRel_eq] at hab hcd ⊢ - dsimp only - calc - c⁻¹ * (a⁻¹ * b) * c⁻¹⁻¹ * (c⁻¹ * d) ∈ N := N.mul_mem (nN.conj_mem _ hab _) hcd - _ = (a * c)⁻¹ * (b * d) := by - simp only [mul_inv_rev, mul_assoc, inv_mul_cancel_left] - -@[to_additive] -instance Quotient.group : Group (G ⧸ N) := - (QuotientGroup.con N).group - -/-- The group homomorphism from `G` to `G/N`. -/ -@[to_additive "The additive group homomorphism from `G` to `G/N`."] -def mk' : G →* G ⧸ N := - MonoidHom.mk' QuotientGroup.mk fun _ _ => rfl - -@[to_additive (attr := simp)] -theorem coe_mk' : (mk' N : G → G ⧸ N) = mk := - rfl - -@[to_additive (attr := simp)] -theorem mk'_apply (x : G) : mk' N x = x := - rfl - -@[to_additive] -theorem mk'_surjective : Surjective <| mk' N := - @mk_surjective _ _ N - -@[to_additive] -theorem mk'_eq_mk' {x y : G} : mk' N x = mk' N y ↔ ∃ z ∈ N, x * z = y := - QuotientGroup.eq.trans <| by - simp only [← _root_.eq_inv_mul_iff_mul_eq, exists_prop, exists_eq_right] - open scoped Pointwise in @[to_additive] theorem sound (U : Set (G ⧸ N)) (g : N.op) : @@ -94,230 +49,20 @@ theorem sound (U : Set (G ⧸ N)) (g : N.op) : congr! 1 exact Quotient.sound ⟨g⁻¹, rfl⟩ -/-- Two `MonoidHom`s from a quotient group are equal if their compositions with -`QuotientGroup.mk'` are equal. - -See note [partially-applied ext lemmas]. -/ -@[to_additive (attr := ext 1100) "Two `AddMonoidHom`s from an additive quotient group are equal if - their compositions with `AddQuotientGroup.mk'` are equal. - - See note [partially-applied ext lemmas]. "] -theorem monoidHom_ext ⦃f g : G ⧸ N →* M⦄ (h : f.comp (mk' N) = g.comp (mk' N)) : f = g := - MonoidHom.ext fun x => QuotientGroup.induction_on x <| (DFunLike.congr_fun h : _) - -@[to_additive (attr := simp)] -theorem eq_one_iff {N : Subgroup G} [nN : N.Normal] (x : G) : (x : G ⧸ N) = 1 ↔ x ∈ N := by - refine QuotientGroup.eq.trans ?_ - rw [mul_one, Subgroup.inv_mem_iff] - -@[to_additive] -theorem ker_le_range_iff {I : Type w} [Group I] (f : G →* H) [f.range.Normal] (g : H →* I) : - g.ker ≤ f.range ↔ (mk' f.range).comp g.ker.subtype = 1 := - ⟨fun h => MonoidHom.ext fun ⟨_, hx⟩ => (eq_one_iff _).mpr <| h hx, - fun h x hx => (eq_one_iff _).mp <| by exact DFunLike.congr_fun h ⟨x, hx⟩⟩ - -@[to_additive (attr := simp)] -theorem ker_mk' : MonoidHom.ker (QuotientGroup.mk' N : G →* G ⧸ N) = N := - Subgroup.ext eq_one_iff --- Porting note: I think this is misnamed without the prime - -@[to_additive] -theorem eq_iff_div_mem {N : Subgroup G} [nN : N.Normal] {x y : G} : - (x : G ⧸ N) = y ↔ x / y ∈ N := by - refine eq_comm.trans (QuotientGroup.eq.trans ?_) - rw [nN.mem_comm_iff, div_eq_mul_inv] - -- for commutative groups we don't need normality assumption -@[to_additive] -instance Quotient.commGroup {G : Type*} [CommGroup G] (N : Subgroup G) : CommGroup (G ⧸ N) := - { toGroup := have := N.normal_of_comm; QuotientGroup.Quotient.group N - mul_comm := fun a b => Quotient.inductionOn₂' a b fun a b => congr_arg mk (mul_comm a b) } - local notation " Q " => G ⧸ N -@[to_additive (attr := simp)] -theorem mk_one : ((1 : G) : Q) = 1 := - rfl - -@[to_additive (attr := simp)] -theorem mk_mul (a b : G) : ((a * b : G) : Q) = a * b := - rfl - -@[to_additive (attr := simp)] -theorem mk_inv (a : G) : ((a⁻¹ : G) : Q) = (a : Q)⁻¹ := - rfl - -@[to_additive (attr := simp)] -theorem mk_div (a b : G) : ((a / b : G) : Q) = a / b := - rfl - -@[to_additive (attr := simp)] -theorem mk_pow (a : G) (n : ℕ) : ((a ^ n : G) : Q) = (a : Q) ^ n := - rfl - -@[to_additive (attr := simp)] -theorem mk_zpow (a : G) (n : ℤ) : ((a ^ n : G) : Q) = (a : Q) ^ n := - rfl - @[to_additive (attr := simp)] theorem mk_prod {G ι : Type*} [CommGroup G] (N : Subgroup G) (s : Finset ι) {f : ι → G} : ((Finset.prod s f : G) : G ⧸ N) = Finset.prod s (fun i => (f i : G ⧸ N)) := map_prod (QuotientGroup.mk' N) _ _ -@[to_additive (attr := simp)] lemma map_mk'_self : N.map (mk' N) = ⊥ := by aesop - @[to_additive QuotientAddGroup.strictMono_comap_prod_map] theorem strictMono_comap_prod_map : StrictMono fun H : Subgroup G ↦ (H.comap N.subtype, H.map (mk' N)) := strictMono_comap_prod_image N -/-- A group homomorphism `φ : G →* M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) to a -group homomorphism `G/N →* M`. -/ -@[to_additive "An `AddGroup` homomorphism `φ : G →+ M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) - to a group homomorphism `G/N →* M`."] -def lift (φ : G →* M) (HN : N ≤ φ.ker) : Q →* M := - (QuotientGroup.con N).lift φ fun x y h => by - simp only [QuotientGroup.con, leftRel_apply, Con.rel_mk] at h - rw [Con.ker_rel] - calc - φ x = φ (y * (x⁻¹ * y)⁻¹) := by rw [mul_inv_rev, inv_inv, mul_inv_cancel_left] - _ = φ y := by rw [φ.map_mul, HN (N.inv_mem h), mul_one] - -@[to_additive (attr := simp)] -theorem lift_mk {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : lift N φ HN (g : Q) = φ g := - rfl - -@[to_additive (attr := simp)] -theorem lift_mk' {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : lift N φ HN (mk g : Q) = φ g := - rfl --- TODO: replace `mk` with `mk'`) - -@[to_additive (attr := simp)] -theorem lift_quot_mk {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : - lift N φ HN (Quot.mk _ g : Q) = φ g := - rfl - -/-- A group homomorphism `f : G →* H` induces a map `G/N →* H/M` if `N ⊆ f⁻¹(M)`. -/ -@[to_additive - "An `AddGroup` homomorphism `f : G →+ H` induces a map `G/N →+ H/M` if `N ⊆ f⁻¹(M)`."] -def map (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) : G ⧸ N →* H ⧸ M := by - refine QuotientGroup.lift N ((mk' M).comp f) ?_ - intro x hx - refine QuotientGroup.eq.2 ?_ - rw [mul_one, Subgroup.inv_mem_iff] - exact h hx - -@[to_additive (attr := simp)] -theorem map_mk (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) (x : G) : - map N M f h ↑x = ↑(f x) := - rfl - -@[to_additive] -theorem map_mk' (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) (x : G) : - map N M f h (mk' _ x) = ↑(f x) := - rfl - -@[to_additive] -theorem map_id_apply (h : N ≤ Subgroup.comap (MonoidHom.id _) N := (Subgroup.comap_id N).le) (x) : - map N N (MonoidHom.id _) h x = x := - induction_on x fun _x => rfl - -@[to_additive (attr := simp)] -theorem map_id (h : N ≤ Subgroup.comap (MonoidHom.id _) N := (Subgroup.comap_id N).le) : - map N N (MonoidHom.id _) h = MonoidHom.id _ := - MonoidHom.ext (map_id_apply N h) - -@[to_additive (attr := simp)] -theorem map_map {I : Type*} [Group I] (M : Subgroup H) (O : Subgroup I) [M.Normal] [O.Normal] - (f : G →* H) (g : H →* I) (hf : N ≤ Subgroup.comap f M) (hg : M ≤ Subgroup.comap g O) - (hgf : N ≤ Subgroup.comap (g.comp f) O := - hf.trans ((Subgroup.comap_mono hg).trans_eq (Subgroup.comap_comap _ _ _))) - (x : G ⧸ N) : map M O g hg (map N M f hf x) = map N O (g.comp f) hgf x := by - refine induction_on x fun x => ?_ - simp only [map_mk, MonoidHom.comp_apply] - -@[to_additive (attr := simp)] -theorem map_comp_map {I : Type*} [Group I] (M : Subgroup H) (O : Subgroup I) [M.Normal] [O.Normal] - (f : G →* H) (g : H →* I) (hf : N ≤ Subgroup.comap f M) (hg : M ≤ Subgroup.comap g O) - (hgf : N ≤ Subgroup.comap (g.comp f) O := - hf.trans ((Subgroup.comap_mono hg).trans_eq (Subgroup.comap_comap _ _ _))) : - (map M O g hg).comp (map N M f hf) = map N O (g.comp f) hgf := - MonoidHom.ext (map_map N M O f g hf hg hgf) - -section Pointwise -open Set - -@[to_additive (attr := simp)] lemma image_coe : ((↑) : G → Q) '' N = 1 := - congr_arg ((↑) : Subgroup Q → Set Q) <| map_mk'_self N - -@[to_additive] -lemma preimage_image_coe (s : Set G) : ((↑) : G → Q) ⁻¹' ((↑) '' s) = N * s := by - ext a - constructor - · rintro ⟨b, hb, h⟩ - refine ⟨a / b, (QuotientGroup.eq_one_iff _).1 ?_, b, hb, div_mul_cancel _ _⟩ - simp only [h, QuotientGroup.mk_div, div_self'] - · rintro ⟨a, ha, b, hb, rfl⟩ - refine ⟨b, hb, ?_⟩ - simpa only [QuotientGroup.mk_mul, self_eq_mul_left, QuotientGroup.eq_one_iff] - -@[to_additive] -lemma image_coe_inj {s t : Set G} : ((↑) : G → Q) '' s = ((↑) : G → Q) '' t ↔ ↑N * s = N * t := by - simp_rw [← preimage_image_coe] - exact QuotientGroup.mk_surjective.preimage_injective.eq_iff.symm - -end Pointwise - -section congr - -variable (G' : Subgroup G) (H' : Subgroup H) [Subgroup.Normal G'] [Subgroup.Normal H'] - -/-- `QuotientGroup.congr` lifts the isomorphism `e : G ≃ H` to `G ⧸ G' ≃ H ⧸ H'`, -given that `e` maps `G` to `H`. -/ -@[to_additive "`QuotientAddGroup.congr` lifts the isomorphism `e : G ≃ H` to `G ⧸ G' ≃ H ⧸ H'`, - given that `e` maps `G` to `H`."] -def congr (e : G ≃* H) (he : G'.map e = H') : G ⧸ G' ≃* H ⧸ H' := - { map G' H' e (he ▸ G'.le_comap_map (e : G →* H)) with - toFun := map G' H' e (he ▸ G'.le_comap_map (e : G →* H)) - invFun := map H' G' e.symm (he ▸ (G'.map_equiv_eq_comap_symm e).le) - left_inv := fun x => by - rw [map_map G' H' G' e e.symm (he ▸ G'.le_comap_map (e : G →* H)) - (he ▸ (G'.map_equiv_eq_comap_symm e).le)] - simp only [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.self_trans_symm, - MulEquiv.coe_monoidHom_refl, map_id_apply] - right_inv := fun x => by - rw [map_map H' G' H' e.symm e (he ▸ (G'.map_equiv_eq_comap_symm e).le) - (he ▸ G'.le_comap_map (e : G →* H)) ] - simp only [← MulEquiv.coe_monoidHom_trans, MulEquiv.symm_trans_self, - MulEquiv.coe_monoidHom_refl, map_id_apply] } - -@[simp] -theorem congr_mk (e : G ≃* H) (he : G'.map ↑e = H') (x) : congr G' H' e he (mk x) = e x := - rfl - -theorem congr_mk' (e : G ≃* H) (he : G'.map ↑e = H') (x) : - congr G' H' e he (mk' G' x) = mk' H' (e x) := - rfl - -@[simp] -theorem congr_apply (e : G ≃* H) (he : G'.map ↑e = H') (x : G) : - congr G' H' e he x = mk' H' (e x) := - rfl - -@[simp] -theorem congr_refl (he : G'.map (MulEquiv.refl G : G →* G) = G' := Subgroup.map_id G') : - congr G' G' (MulEquiv.refl G) he = MulEquiv.refl (G ⧸ G') := by - ext ⟨x⟩ - rfl - -@[simp] -theorem congr_symm (e : G ≃* H) (he : G'.map ↑e = H') : - (congr G' H' e he).symm = congr H' G' e.symm ((Subgroup.map_symm_eq_iff_map_eq _).mpr he) := - rfl - -end congr - variable (φ : G →* H) open MonoidHom @@ -432,7 +177,7 @@ the equalities, since the type of `(A'.addSubgroupOf A : AddSubgroup A)` depends def equivQuotientSubgroupOfOfEq {A' A B' B : Subgroup G} [hAN : (A'.subgroupOf A).Normal] [hBN : (B'.subgroupOf B).Normal] (h' : A' = B') (h : A = B) : A ⧸ A'.subgroupOf A ≃* B ⧸ B'.subgroupOf B := - MonoidHom.toMulEquiv (quotientMapSubgroupOfOfLe h'.le h.le) (quotientMapSubgroupOfOfLe h'.ge h.ge) + (quotientMapSubgroupOfOfLe h'.le h.le).toMulEquiv (quotientMapSubgroupOfOfLe h'.ge h.ge) (by ext ⟨x, hx⟩; rfl) (by ext ⟨x, hx⟩; rfl) @@ -524,7 +269,7 @@ noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Norma (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N))) -- Porting note: Lean couldn't find this automatically refine Quotient.eq.mpr ?_ - change Setoid.r _ _ + change leftRel _ _ _ rw [leftRel_apply] change h⁻¹ * (h * n) ∈ N rwa [← mul_assoc, inv_mul_cancel, one_mul] diff --git a/Mathlib/GroupTheory/QuotientGroup/Defs.lean b/Mathlib/GroupTheory/QuotientGroup/Defs.lean new file mode 100644 index 0000000000000..0eeaeb9aa5c12 --- /dev/null +++ b/Mathlib/GroupTheory/QuotientGroup/Defs.lean @@ -0,0 +1,291 @@ +/- +Copyright (c) 2018 Kevin Buzzard, Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kevin Buzzard, Patrick Massot +-/ +-- This file is to a certain extent based on `quotient_module.lean` by Johannes Hölzl. + +import Mathlib.GroupTheory.Congruence.Hom +import Mathlib.GroupTheory.Coset.Defs + +/-! +# Quotients of groups by normal subgroups + +This file defines the group structure on the quotient by a normal subgroup. + +## Main definitions + +* `QuotientGroup.Quotient.Group`: the group structure on `G/N` given a normal subgroup `N` of `G`. +* `mk'`: the canonical group homomorphism `G →* G/N` given a normal subgroup `N` of `G`. +* `lift φ`: the group homomorphism `G/N →* H` given a group homomorphism `φ : G →* H` such that + `N ⊆ ker φ`. +* `map f`: the group homomorphism `G/N →* H/M` given a group homomorphism `f : G →* H` such that + `N ⊆ f⁻¹(M)`. + +## Tags + +quotient groups +-/ + +open Function +open scoped Pointwise + +universe u v w x +namespace QuotientGroup + +variable {G : Type u} [Group G] (N : Subgroup G) [nN : N.Normal] {H : Type v} [Group H] + {M : Type x} [Monoid M] + +/-- The congruence relation generated by a normal subgroup. -/ +@[to_additive "The additive congruence relation generated by a normal additive subgroup."] +protected def con : Con G where + toSetoid := leftRel N + mul' := fun {a b c d} hab hcd => by + rw [leftRel_eq] at hab hcd ⊢ + dsimp only + calc + c⁻¹ * (a⁻¹ * b) * c⁻¹⁻¹ * (c⁻¹ * d) ∈ N := N.mul_mem (nN.conj_mem _ hab _) hcd + _ = (a * c)⁻¹ * (b * d) := by + simp only [mul_inv_rev, mul_assoc, inv_mul_cancel_left] + +@[to_additive] +instance Quotient.group : Group (G ⧸ N) := + (QuotientGroup.con N).group + +/-- The group homomorphism from `G` to `G/N`. -/ +@[to_additive "The additive group homomorphism from `G` to `G/N`."] +def mk' : G →* G ⧸ N := + MonoidHom.mk' QuotientGroup.mk fun _ _ => rfl + +@[to_additive (attr := simp)] +theorem coe_mk' : (mk' N : G → G ⧸ N) = mk := + rfl + +@[to_additive (attr := simp)] +theorem mk'_apply (x : G) : mk' N x = x := + rfl + +@[to_additive] +theorem mk'_surjective : Surjective <| mk' N := + @mk_surjective _ _ N + +@[to_additive] +theorem mk'_eq_mk' {x y : G} : mk' N x = mk' N y ↔ ∃ z ∈ N, x * z = y := + QuotientGroup.eq.trans <| by + simp only [← _root_.eq_inv_mul_iff_mul_eq, exists_prop, exists_eq_right] + +/-- Two `MonoidHom`s from a quotient group are equal if their compositions with +`QuotientGroup.mk'` are equal. + +See note [partially-applied ext lemmas]. -/ +@[to_additive (attr := ext 1100) "Two `AddMonoidHom`s from an additive quotient group are equal if + their compositions with `AddQuotientGroup.mk'` are equal. + + See note [partially-applied ext lemmas]. "] +theorem monoidHom_ext ⦃f g : G ⧸ N →* M⦄ (h : f.comp (mk' N) = g.comp (mk' N)) : f = g := + MonoidHom.ext fun x => QuotientGroup.induction_on x <| (DFunLike.congr_fun h : _) + +@[to_additive (attr := simp)] +theorem eq_one_iff {N : Subgroup G} [N.Normal] (x : G) : (x : G ⧸ N) = 1 ↔ x ∈ N := by + refine QuotientGroup.eq.trans ?_ + rw [mul_one, Subgroup.inv_mem_iff] + +@[to_additive] +theorem ker_le_range_iff {I : Type w} [Group I] (f : G →* H) [f.range.Normal] (g : H →* I) : + g.ker ≤ f.range ↔ (mk' f.range).comp g.ker.subtype = 1 := + ⟨fun h => MonoidHom.ext fun ⟨_, hx⟩ => (eq_one_iff _).mpr <| h hx, + fun h x hx => (eq_one_iff _).mp <| by exact DFunLike.congr_fun h ⟨x, hx⟩⟩ + +@[to_additive (attr := simp)] +theorem ker_mk' : MonoidHom.ker (QuotientGroup.mk' N : G →* G ⧸ N) = N := + Subgroup.ext eq_one_iff +-- Porting note: I think this is misnamed without the prime + +@[to_additive] +theorem eq_iff_div_mem {N : Subgroup G} [nN : N.Normal] {x y : G} : + (x : G ⧸ N) = y ↔ x / y ∈ N := by + refine eq_comm.trans (QuotientGroup.eq.trans ?_) + rw [nN.mem_comm_iff, div_eq_mul_inv] + +-- for commutative groups we don't need normality assumption + +@[to_additive] +instance Quotient.commGroup {G : Type*} [CommGroup G] (N : Subgroup G) : CommGroup (G ⧸ N) := + { toGroup := have := N.normal_of_comm; QuotientGroup.Quotient.group N + mul_comm := fun a b => Quotient.inductionOn₂' a b fun a b => congr_arg mk (mul_comm a b) } + +local notation " Q " => G ⧸ N + +@[to_additive (attr := simp)] +theorem mk_one : ((1 : G) : Q) = 1 := + rfl + +@[to_additive (attr := simp)] +theorem mk_mul (a b : G) : ((a * b : G) : Q) = a * b := + rfl + +@[to_additive (attr := simp)] +theorem mk_inv (a : G) : ((a⁻¹ : G) : Q) = (a : Q)⁻¹ := + rfl + +@[to_additive (attr := simp)] +theorem mk_div (a b : G) : ((a / b : G) : Q) = a / b := + rfl + +@[to_additive (attr := simp)] +theorem mk_pow (a : G) (n : ℕ) : ((a ^ n : G) : Q) = (a : Q) ^ n := + rfl + +@[to_additive (attr := simp)] +theorem mk_zpow (a : G) (n : ℤ) : ((a ^ n : G) : Q) = (a : Q) ^ n := + rfl + +@[to_additive (attr := simp)] lemma map_mk'_self : N.map (mk' N) = ⊥ := by aesop + +/-- A group homomorphism `φ : G →* M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) to a +group homomorphism `G/N →* M`. -/ +@[to_additive "An `AddGroup` homomorphism `φ : G →+ M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) + to a group homomorphism `G/N →* M`."] +def lift (φ : G →* M) (HN : N ≤ φ.ker) : Q →* M := + (QuotientGroup.con N).lift φ fun x y h => by + simp only [QuotientGroup.con, leftRel_apply, Con.rel_mk] at h + rw [Con.ker_rel] + calc + φ x = φ (y * (x⁻¹ * y)⁻¹) := by rw [mul_inv_rev, inv_inv, mul_inv_cancel_left] + _ = φ y := by rw [φ.map_mul, HN (N.inv_mem h), mul_one] + +@[to_additive (attr := simp)] +theorem lift_mk {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : lift N φ HN (g : Q) = φ g := + rfl + +@[to_additive (attr := simp)] +theorem lift_mk' {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : lift N φ HN (mk g : Q) = φ g := + rfl +-- TODO: replace `mk` with `mk'`) + +@[to_additive (attr := simp)] +theorem lift_quot_mk {φ : G →* M} (HN : N ≤ φ.ker) (g : G) : + lift N φ HN (Quot.mk _ g : Q) = φ g := + rfl + +/-- A group homomorphism `f : G →* H` induces a map `G/N →* H/M` if `N ⊆ f⁻¹(M)`. -/ +@[to_additive + "An `AddGroup` homomorphism `f : G →+ H` induces a map `G/N →+ H/M` if `N ⊆ f⁻¹(M)`."] +def map (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) : G ⧸ N →* H ⧸ M := by + refine QuotientGroup.lift N ((mk' M).comp f) ?_ + intro x hx + refine QuotientGroup.eq.2 ?_ + rw [mul_one, Subgroup.inv_mem_iff] + exact h hx + +@[to_additive (attr := simp)] +theorem map_mk (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) (x : G) : + map N M f h ↑x = ↑(f x) := + rfl + +@[to_additive] +theorem map_mk' (M : Subgroup H) [M.Normal] (f : G →* H) (h : N ≤ M.comap f) (x : G) : + map N M f h (mk' _ x) = ↑(f x) := + rfl + +@[to_additive] +theorem map_id_apply (h : N ≤ Subgroup.comap (MonoidHom.id _) N := (Subgroup.comap_id N).le) (x) : + map N N (MonoidHom.id _) h x = x := + induction_on x fun _x => rfl + +@[to_additive (attr := simp)] +theorem map_id (h : N ≤ Subgroup.comap (MonoidHom.id _) N := (Subgroup.comap_id N).le) : + map N N (MonoidHom.id _) h = MonoidHom.id _ := + MonoidHom.ext (map_id_apply N h) + +@[to_additive (attr := simp)] +theorem map_map {I : Type*} [Group I] (M : Subgroup H) (O : Subgroup I) [M.Normal] [O.Normal] + (f : G →* H) (g : H →* I) (hf : N ≤ Subgroup.comap f M) (hg : M ≤ Subgroup.comap g O) + (hgf : N ≤ Subgroup.comap (g.comp f) O := + hf.trans ((Subgroup.comap_mono hg).trans_eq (Subgroup.comap_comap _ _ _))) + (x : G ⧸ N) : map M O g hg (map N M f hf x) = map N O (g.comp f) hgf x := by + refine induction_on x fun x => ?_ + simp only [map_mk, MonoidHom.comp_apply] + +@[to_additive (attr := simp)] +theorem map_comp_map {I : Type*} [Group I] (M : Subgroup H) (O : Subgroup I) [M.Normal] [O.Normal] + (f : G →* H) (g : H →* I) (hf : N ≤ Subgroup.comap f M) (hg : M ≤ Subgroup.comap g O) + (hgf : N ≤ Subgroup.comap (g.comp f) O := + hf.trans ((Subgroup.comap_mono hg).trans_eq (Subgroup.comap_comap _ _ _))) : + (map M O g hg).comp (map N M f hf) = map N O (g.comp f) hgf := + MonoidHom.ext (map_map N M O f g hf hg hgf) + +section Pointwise +open Set + +@[to_additive (attr := simp)] lemma image_coe : ((↑) : G → Q) '' N = 1 := + congr_arg ((↑) : Subgroup Q → Set Q) <| map_mk'_self N + +@[to_additive] +lemma preimage_image_coe (s : Set G) : ((↑) : G → Q) ⁻¹' ((↑) '' s) = N * s := by + ext a + constructor + · rintro ⟨b, hb, h⟩ + refine ⟨a / b, (QuotientGroup.eq_one_iff _).1 ?_, b, hb, div_mul_cancel _ _⟩ + simp only [h, QuotientGroup.mk_div, div_self'] + · rintro ⟨a, ha, b, hb, rfl⟩ + refine ⟨b, hb, ?_⟩ + simpa only [QuotientGroup.mk_mul, self_eq_mul_left, QuotientGroup.eq_one_iff] + +@[to_additive] +lemma image_coe_inj {s t : Set G} : ((↑) : G → Q) '' s = ((↑) : G → Q) '' t ↔ ↑N * s = N * t := by + simp_rw [← preimage_image_coe] + exact QuotientGroup.mk_surjective.preimage_injective.eq_iff.symm + +end Pointwise + +section congr + +variable (G' : Subgroup G) (H' : Subgroup H) [Subgroup.Normal G'] [Subgroup.Normal H'] + +/-- `QuotientGroup.congr` lifts the isomorphism `e : G ≃ H` to `G ⧸ G' ≃ H ⧸ H'`, +given that `e` maps `G` to `H`. -/ +@[to_additive "`QuotientAddGroup.congr` lifts the isomorphism `e : G ≃ H` to `G ⧸ G' ≃ H ⧸ H'`, + given that `e` maps `G` to `H`."] +def congr (e : G ≃* H) (he : G'.map e = H') : G ⧸ G' ≃* H ⧸ H' := + { map G' H' e (he ▸ G'.le_comap_map (e : G →* H)) with + toFun := map G' H' e (he ▸ G'.le_comap_map (e : G →* H)) + invFun := map H' G' e.symm (he ▸ (G'.map_equiv_eq_comap_symm e).le) + left_inv := fun x => by + rw [map_map G' H' G' e e.symm (he ▸ G'.le_comap_map (e : G →* H)) + (he ▸ (G'.map_equiv_eq_comap_symm e).le)] + simp only [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.self_trans_symm, + MulEquiv.coe_monoidHom_refl, map_id_apply] + right_inv := fun x => by + rw [map_map H' G' H' e.symm e (he ▸ (G'.map_equiv_eq_comap_symm e).le) + (he ▸ G'.le_comap_map (e : G →* H)) ] + simp only [← MulEquiv.coe_monoidHom_trans, MulEquiv.symm_trans_self, + MulEquiv.coe_monoidHom_refl, map_id_apply] } + +@[simp] +theorem congr_mk (e : G ≃* H) (he : G'.map ↑e = H') (x) : congr G' H' e he (mk x) = e x := + rfl + +theorem congr_mk' (e : G ≃* H) (he : G'.map ↑e = H') (x) : + congr G' H' e he (mk' G' x) = mk' H' (e x) := + rfl + +@[simp] +theorem congr_apply (e : G ≃* H) (he : G'.map ↑e = H') (x : G) : + congr G' H' e he x = mk' H' (e x) := + rfl + +@[simp] +theorem congr_refl (he : G'.map (MulEquiv.refl G : G →* G) = G' := Subgroup.map_id G') : + congr G' G' (MulEquiv.refl G) he = MulEquiv.refl (G ⧸ G') := by + ext ⟨x⟩ + rfl + +@[simp] +theorem congr_symm (e : G ≃* H) (he : G'.map ↑e = H') : + (congr G' H' e he).symm = congr H' G' e.symm ((Subgroup.map_symm_eq_iff_map_eq _).mpr he) := + rfl + +end congr + +end QuotientGroup diff --git a/Mathlib/GroupTheory/QuotientGroup/Finite.lean b/Mathlib/GroupTheory/QuotientGroup/Finite.lean index 76877f51f87b7..6d234fdd50c16 100644 --- a/Mathlib/GroupTheory/QuotientGroup/Finite.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Finite.lean @@ -50,4 +50,9 @@ noncomputable def fintypeOfKerOfCodom [Fintype g.ker] : Fintype G := noncomputable def fintypeOfDomOfCoker [Normal f.range] [Fintype <| G ⧸ f.range] : Fintype G := fintypeOfKerLeRange _ (mk' f.range) fun x => (eq_one_iff x).mp +@[to_additive] +lemma _root_.Finite.of_finite_quot_finite_subgroup {H : Subgroup G} [Finite H] [Finite (G ⧸ H)] : + Finite G := + Finite.of_equiv _ (groupEquivQuotientProdSubgroup (s := H)).symm + end Group diff --git a/Mathlib/GroupTheory/SchurZassenhaus.lean b/Mathlib/GroupTheory/SchurZassenhaus.lean index a143963c7cc26..ed1bc6f16be04 100644 --- a/Mathlib/GroupTheory/SchurZassenhaus.lean +++ b/Mathlib/GroupTheory/SchurZassenhaus.lean @@ -98,7 +98,7 @@ theorem exists_smul_eq (hH : Nat.Coprime (Nat.card H) H.index) (α β : H.Quotie ∃ h : H, h • α = β := Quotient.inductionOn' α (Quotient.inductionOn' β fun β α => - Exists.imp (fun n => Quotient.sound') + Exists.imp (fun _ => Quotient.sound') ⟨(powCoprime hH).symm (diff (MonoidHom.id H) β α), (diff_inv _ _ _).symm.trans (inv_eq_one.mpr diff --git a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean index 200e6d06c39ac..60f59d2000a12 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean @@ -137,7 +137,7 @@ open alternatingGroup @[simp] theorem closure_three_cycles_eq_alternating : closure { σ : Perm α | IsThreeCycle σ } = alternatingGroup α := - closure_eq_of_le _ (fun σ hσ => mem_alternatingGroup.2 hσ.sign) fun σ hσ => by + closure_eq_of_le _ (fun _ hσ => mem_alternatingGroup.2 hσ.sign) fun σ hσ => by suffices hind : ∀ (n : ℕ) (l : List (Perm α)) (_ : ∀ g, g ∈ l → IsSwap g) (_ : l.length = 2 * n), l.prod ∈ closure { σ : Perm α | IsThreeCycle σ } by diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index 38b5ab4ee0b07..4a709390a2037 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -278,11 +278,11 @@ open scoped Classical @[to_additive IsAddCyclic.card_nsmul_eq_zero_le] theorem IsCyclic.card_pow_eq_one_le [DecidableEq α] [Fintype α] [IsCyclic α] {n : ℕ} (hn0 : 0 < n) : - (univ.filter fun a : α => a ^ n = 1).card ≤ n := + #{a : α | a ^ n = 1} ≤ n := let ⟨g, hg⟩ := IsCyclic.exists_generator (α := α) calc - (univ.filter fun a : α => a ^ n = 1).card ≤ - (zpowers (g ^ (Fintype.card α / Nat.gcd n (Fintype.card α))) : Set α).toFinset.card := + #{a : α | a ^ n = 1} ≤ + #(zpowers (g ^ (Fintype.card α / Nat.gcd n (Fintype.card α))) : Set α).toFinset := card_le_card fun x hx => let ⟨m, hm⟩ := show x ∈ Submonoid.powers g from mem_powers_iff_mem_zpowers.2 <| hg x Set.mem_toFinset.2 @@ -382,21 +382,19 @@ end section Totient -variable [DecidableEq α] [Fintype α] - (hn : ∀ n : ℕ, 0 < n → (univ.filter fun a : α => a ^ n = 1).card ≤ n) +variable [DecidableEq α] [Fintype α] (hn : ∀ n : ℕ, 0 < n → #{a : α | a ^ n = 1} ≤ n) include hn @[to_additive] -private theorem card_pow_eq_one_eq_orderOf_aux (a : α) : - (Finset.univ.filter fun b : α => b ^ orderOf a = 1).card = orderOf a := +private theorem card_pow_eq_one_eq_orderOf_aux (a : α) : #{b : α | b ^ orderOf a = 1} = orderOf a := le_antisymm (hn _ (orderOf_pos a)) (calc orderOf a = @Fintype.card (zpowers a) (id _) := Fintype.card_zpowers.symm _ ≤ - @Fintype.card (↑(univ.filter fun b : α => b ^ orderOf a = 1) : Set α) + @Fintype.card (({b : α | b ^ orderOf a = 1} : Finset _) : Set α) (Fintype.ofFinset _ fun _ => Iff.rfl) := (@Fintype.card_le_of_injective (zpowers a) - (↑(univ.filter fun b : α => b ^ orderOf a = 1) : Set α) (id _) (id _) + (({b : α | b ^ orderOf a = 1} : Finset _) : Set α) (id _) (id _) (fun b => ⟨b.1, mem_filter.2 @@ -405,25 +403,21 @@ private theorem card_pow_eq_one_eq_orderOf_aux (a : α) : rw [← hi, ← zpow_natCast, ← zpow_mul, mul_comm, zpow_mul, zpow_natCast, pow_orderOf_eq_one, one_zpow]⟩⟩) fun _ _ h => Subtype.eq (Subtype.mk.inj h)) - _ = (univ.filter fun b : α => b ^ orderOf a = 1).card := Fintype.card_ofFinset _ _ + _ = #{b : α | b ^ orderOf a = 1} := Fintype.card_ofFinset _ _ ) -- Use φ for `Nat.totient` open Nat @[to_additive] -private theorem card_orderOf_eq_totient_aux₁ : - ∀ {d : ℕ}, - d ∣ Fintype.card α → - 0 < (univ.filter fun a : α => orderOf a = d).card → - (univ.filter fun a : α => orderOf a = d).card = φ d := by - intro d hd hpos +private theorem card_orderOf_eq_totient_aux₁ {d : ℕ} (hd : d ∣ Fintype.card α) + (hpos : 0 < #{a : α | orderOf a = d}) : #{a : α | orderOf a = d} = φ d := by induction' d using Nat.strongRec' with d IH rcases Decidable.eq_or_ne d 0 with (rfl | hd0) · cases Fintype.card_ne_zero (eq_zero_of_zero_dvd hd) - rcases card_pos.1 hpos with ⟨a, ha'⟩ + rcases Finset.card_pos.1 hpos with ⟨a, ha'⟩ have ha : orderOf a = d := (mem_filter.1 ha').2 have h1 : - (∑ m ∈ d.properDivisors, (univ.filter fun a : α => orderOf a = m).card) = + (∑ m ∈ d.properDivisors, #{a : α | orderOf a = m}) = ∑ m ∈ d.properDivisors, φ m := by refine Finset.sum_congr rfl fun m hm => ?_ simp only [mem_filter, mem_range, mem_properDivisors] at hm @@ -431,7 +425,7 @@ private theorem card_orderOf_eq_totient_aux₁ : simp only [mem_filter, mem_univ, orderOf_pow a, ha, true_and, Nat.gcd_eq_right (div_dvd_of_dvd hm.1), Nat.div_div_self hm.1 hd0] have h2 : - (∑ m ∈ d.divisors, (univ.filter fun a : α => orderOf a = m).card) = + (∑ m ∈ d.divisors, #{a : α | orderOf a = m}) = ∑ m ∈ d.divisors, φ m := by rw [← filter_dvd_eq_divisors hd0, sum_card_orderOf_eq_card_pow_eq_one hd0, filter_dvd_eq_divisors hd0, sum_totient, ← ha, card_pow_eq_one_eq_orderOf_aux hn a] @@ -439,7 +433,7 @@ private theorem card_orderOf_eq_totient_aux₁ : @[to_additive] theorem card_orderOf_eq_totient_aux₂ {d : ℕ} (hd : d ∣ Fintype.card α) : - (univ.filter fun a : α => orderOf a = d).card = φ d := by + #{a : α | orderOf a = d} = φ d := by let c := Fintype.card α have hc0 : 0 < c := Fintype.card_pos_iff.2 ⟨1⟩ apply card_orderOf_eq_totient_aux₁ hn hd @@ -448,11 +442,11 @@ theorem card_orderOf_eq_totient_aux₂ {d : ℕ} (hd : d ∣ Fintype.card α) : simp_rw [not_lt, Nat.le_zero, Finset.card_eq_zero] at h0 apply lt_irrefl c calc - c = ∑ m ∈ c.divisors, (univ.filter fun a : α => orderOf a = m).card := by + c = ∑ m ∈ c.divisors, #{a : α | orderOf a = m} := by simp only [← filter_dvd_eq_divisors hc0.ne', sum_card_orderOf_eq_card_pow_eq_one hc0.ne'] apply congr_arg card simp [c] - _ = ∑ m ∈ c.divisors.erase d, (univ.filter fun a : α => orderOf a = m).card := by + _ = ∑ m ∈ c.divisors.erase d, #{a : α | orderOf a = m} := by rw [eq_comm] refine sum_subset (erase_subset _ _) fun m hm₁ hm₂ => ?_ have : m = d := by @@ -464,7 +458,7 @@ theorem card_orderOf_eq_totient_aux₂ {d : ℕ} (hd : d ∣ Fintype.card α) : have hmc : m ∣ c := by simp only [mem_erase, mem_divisors] at hm tauto - rcases (filter (fun a : α => orderOf a = m) univ).card.eq_zero_or_pos with (h1 | h1) + obtain h1 | h1 := (#{a : α | orderOf a = m}).eq_zero_or_pos · simp [h1] · simp [card_orderOf_eq_totient_aux₁ hn hmc h1] _ < ∑ m ∈ c.divisors, φ m := @@ -473,7 +467,7 @@ theorem card_orderOf_eq_totient_aux₂ {d : ℕ} (hd : d ∣ Fintype.card α) : @[to_additive isAddCyclic_of_card_nsmul_eq_zero_le] theorem isCyclic_of_card_pow_eq_one_le : IsCyclic α := - have : (univ.filter fun a : α => orderOf a = Fintype.card α).Nonempty := + have : Finset.Nonempty {a : α | orderOf a = Fintype.card α} := card_pos.1 <| by rw [card_orderOf_eq_totient_aux₂ hn dvd_rfl, totient_pos] apply Fintype.card_pos @@ -486,8 +480,8 @@ alias isAddCyclic_of_card_pow_eq_one_le := isAddCyclic_of_card_nsmul_eq_zero_le end Totient @[to_additive] -theorem IsCyclic.card_orderOf_eq_totient [IsCyclic α] [Fintype α] {d : ℕ} - (hd : d ∣ Fintype.card α) : (univ.filter fun a : α => orderOf a = d).card = totient d := by +lemma IsCyclic.card_orderOf_eq_totient [IsCyclic α] [Fintype α] {d : ℕ} (hd : d ∣ Fintype.card α) : + #{a : α | orderOf a = d} = totient d := by classical apply card_orderOf_eq_totient_aux₂ (fun n => IsCyclic.card_pow_eq_one_le) hd @[deprecated (since := "2024-02-21")] diff --git a/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean b/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean index 53949cd3a109b..3618172616b02 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean @@ -6,6 +6,7 @@ Authors: Shing Tak Lam import Mathlib.Data.ZMod.Basic import Mathlib.GroupTheory.Exponent import Mathlib.GroupTheory.GroupAction.CardCommute +import Mathlib.Data.Finite.Sum /-! # Dihedral Groups @@ -200,7 +201,7 @@ $n + n + n + n*n$) of commuting elements. -/ def OddCommuteEquiv (hn : Odd n) : { p : DihedralGroup n × DihedralGroup n // Commute p.1 p.2 } ≃ ZMod n ⊕ ZMod n ⊕ ZMod n ⊕ ZMod n × ZMod n := let u := ZMod.unitOfCoprime 2 (Nat.prime_two.coprime_iff_not_dvd.mpr hn.not_two_dvd_nat) - have hu : ∀ a : ZMod n, a + a = 0 ↔ a = 0 := fun a => ZMod.add_self_eq_zero_iff_eq_zero hn + have hu : ∀ a : ZMod n, a + a = 0 ↔ a = 0 := fun _ => ZMod.add_self_eq_zero_iff_eq_zero hn { toFun := fun | ⟨⟨sr i, r _⟩, _⟩ => Sum.inl i | ⟨⟨r _, sr j⟩, _⟩ => Sum.inr (Sum.inl j) @@ -212,7 +213,7 @@ def OddCommuteEquiv (hn : Odd n) : { p : DihedralGroup n × DihedralGroup n // C | .inr (.inr (.inl k)) => ⟨⟨sr (u⁻¹ * k), sr (u⁻¹ * k)⟩, rfl⟩ | .inr (.inr (.inr ⟨i, j⟩)) => ⟨⟨r i, r j⟩, congrArg r (add_comm i j)⟩ left_inv := fun - | ⟨⟨r i, r j⟩, h⟩ => rfl + | ⟨⟨r _, r _⟩, _⟩ => rfl | ⟨⟨r i, sr j⟩, h⟩ => by simpa [sub_eq_add_neg, neg_eq_iff_add_eq_zero, hu, eq_comm (a := i) (b := 0)] using h.eq | ⟨⟨sr i, r j⟩, h⟩ => by @@ -223,11 +224,11 @@ def OddCommuteEquiv (hn : Odd n) : { p : DihedralGroup n × DihedralGroup n // C rw [Subtype.ext_iff, Prod.ext_iff, sr.injEq, sr.injEq, h, and_self, ← two_mul] exact u.inv_mul_cancel_left j right_inv := fun - | .inl i => rfl - | .inr (.inl j) => rfl + | .inl _ => rfl + | .inr (.inl _) => rfl | .inr (.inr (.inl k)) => congrArg (Sum.inr ∘ Sum.inr ∘ Sum.inl) <| two_mul (u⁻¹ * k) ▸ u.mul_inv_cancel_left k - | .inr (.inr (.inr ⟨i, j⟩)) => rfl } + | .inr (.inr (.inr ⟨_, _⟩)) => rfl } /-- If n is odd, then the Dihedral group of order $2n$ has $n(n+3)$ pairs of commuting elements. -/ lemma card_commute_odd (hn : Odd n) : diff --git a/Mathlib/GroupTheory/SpecificGroups/KleinFour.lean b/Mathlib/GroupTheory/SpecificGroups/KleinFour.lean index b902f89c46909..e5a725fd32218 100644 --- a/Mathlib/GroupTheory/SpecificGroups/KleinFour.lean +++ b/Mathlib/GroupTheory/SpecificGroups/KleinFour.lean @@ -120,7 +120,7 @@ lemma eq_mul_of_ne_all {x y z : G} (hx : x ≠ 1) (hy : y ≠ 1) (hxy : x ≠ y) (hz : z ≠ 1) (hzx : z ≠ x) (hzy : z ≠ y) : z = x * y := by classical let _ := Fintype.ofFinite G - apply eq_of_not_mem_of_mem_insert <| (eq_finset_univ hx hy hxy).symm ▸ mem_univ _ + apply eq_of_mem_insert_of_not_mem <| (eq_finset_univ hx hy hxy).symm ▸ mem_univ _ simpa only [mem_singleton, mem_insert, not_or] using ⟨hzx, hzy, hz⟩ variable {G₁ G₂ : Type*} [Group G₁] [Group G₂] [IsKleinFour G₁] @@ -146,7 +146,7 @@ def mulEquiv' (e : G₁ ≃ G₂) (he : e 1 = 1) (h : Monoid.exponent G₂ = 2) rw [← Ne, ← e.injective.ne_iff] at hx hy hxy rw [he] at hx hy symm - apply eq_of_not_mem_of_mem_insert <| univ₂.symm ▸ mem_univ _ + apply eq_of_mem_insert_of_not_mem <| univ₂.symm ▸ mem_univ _ simpa using mul_not_mem_of_exponent_two h hx hy hxy /-- Any two `IsKleinFour` groups are isomorphic via any equivalence which sends the identity of one diff --git a/Mathlib/GroupTheory/Subgroup/Saturated.lean b/Mathlib/GroupTheory/Subgroup/Saturated.lean index 1d7d366b914ad..6cbc7b2c45d71 100644 --- a/Mathlib/GroupTheory/Subgroup/Saturated.lean +++ b/Mathlib/GroupTheory/Subgroup/Saturated.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ import Mathlib.Algebra.Group.Subgroup.Basic -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Defs /-! # Saturated subgroups diff --git a/Mathlib/GroupTheory/Submonoid/Inverses.lean b/Mathlib/GroupTheory/Submonoid/Inverses.lean index 469f9ece7f56c..a58eb0aad5f62 100644 --- a/Mathlib/GroupTheory/Submonoid/Inverses.lean +++ b/Mathlib/GroupTheory/Submonoid/Inverses.lean @@ -136,20 +136,15 @@ variable (hS : S ≤ IsUnit.submonoid M) `AddEquiv` to `S`."] noncomputable def leftInvEquiv : S.leftInv ≃* S := { S.fromCommLeftInv with - invFun := fun x ↦ by - choose x' hx using hS x.prop - exact ⟨x'.inv, x, hx ▸ x'.inv_val⟩ - left_inv := fun x ↦ - Subtype.eq <| by - dsimp only; generalize_proofs h; rw [← h.choose.mul_left_inj] - conv => rhs; rw [h.choose_spec] - exact h.choose.inv_val.trans (S.mul_fromLeftInv x).symm - right_inv := fun x ↦ by - dsimp only [fromCommLeftInv] + invFun := fun x ↦ ⟨↑(hS x.2).unit⁻¹, x, by simp⟩ + left_inv := by + intro x ext - rw [fromLeftInv_eq_iff] - convert (hS x.prop).choose.inv_val - exact (hS x.prop).choose_spec.symm } + simp [← Units.mul_eq_one_iff_inv_eq] + right_inv := by + rintro ⟨x, hx⟩ + ext + simp [fromLeftInv_eq_iff] } @[to_additive (attr := simp)] theorem fromLeftInv_leftInvEquiv_symm (x : S) : S.fromLeftInv ((S.leftInvEquiv hS).symm x) = x := diff --git a/Mathlib/GroupTheory/Subsemigroup/Center.lean b/Mathlib/GroupTheory/Subsemigroup/Center.lean index d0970e7e4ca85..fefb61e0ba65c 100644 --- a/Mathlib/GroupTheory/Subsemigroup/Center.lean +++ b/Mathlib/GroupTheory/Subsemigroup/Center.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser, Jireh Loreaux -/ import Mathlib.Algebra.Group.Center -import Mathlib.Algebra.Group.Subsemigroup.Operations +import Mathlib.Algebra.Group.Subsemigroup.Defs /-! # Centers of semigroups, as subsemigroups. diff --git a/Mathlib/GroupTheory/Subsemigroup/Centralizer.lean b/Mathlib/GroupTheory/Subsemigroup/Centralizer.lean index 40211ea65474b..3f5aa2075a30e 100644 --- a/Mathlib/GroupTheory/Subsemigroup/Centralizer.lean +++ b/Mathlib/GroupTheory/Subsemigroup/Centralizer.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Thomas Browning. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning, Jireh Loreaux -/ -import Mathlib.GroupTheory.Subsemigroup.Center import Mathlib.Algebra.Group.Center +import Mathlib.Algebra.Group.Subsemigroup.Basic +import Mathlib.GroupTheory.Subsemigroup.Center /-! # Centralizers in semigroups, as subsemigroups. diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index a534e244575fe..6609de9811ac4 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -130,13 +130,13 @@ theorem IsPGroup.exists_le_sylow {P : Subgroup G} (hP : IsPGroup p P) : ∃ Q : (fun c hc1 hc2 Q hQ => ⟨{ carrier := ⋃ R : c, R one_mem' := ⟨Q, ⟨⟨Q, hQ⟩, rfl⟩, Q.one_mem⟩ - inv_mem' := fun {g} ⟨_, ⟨R, rfl⟩, hg⟩ => ⟨R, ⟨R, rfl⟩, R.1.inv_mem hg⟩ - mul_mem' := fun {g} h ⟨_, ⟨R, rfl⟩, hg⟩ ⟨_, ⟨S, rfl⟩, hh⟩ => + inv_mem' := fun {_} ⟨_, ⟨R, rfl⟩, hg⟩ => ⟨R, ⟨R, rfl⟩, R.1.inv_mem hg⟩ + mul_mem' := fun {_} _ ⟨_, ⟨R, rfl⟩, hg⟩ ⟨_, ⟨S, rfl⟩, hh⟩ => (hc2.total R.2 S.2).elim (fun T => ⟨S, ⟨S, rfl⟩, S.1.mul_mem (T hg) hh⟩) fun T => ⟨R, ⟨R, rfl⟩, R.1.mul_mem hg (T hh)⟩ }, fun ⟨g, _, ⟨S, rfl⟩, hg⟩ => by refine Exists.imp (fun k hk => ?_) (hc1 S.2 ⟨g, hg⟩) - rwa [Subtype.ext_iff, coe_pow] at hk ⊢, fun M hM g hg => ⟨M, ⟨⟨M, hM⟩, rfl⟩, hg⟩⟩) + rwa [Subtype.ext_iff, coe_pow] at hk ⊢, fun M hM _ hg => ⟨M, ⟨⟨M, hM⟩, rfl⟩, hg⟩⟩) P hP) fun {Q} h => ⟨⟨Q, h.2.prop, h.2.eq_of_ge⟩, h.1⟩ @@ -414,9 +414,9 @@ end InfiniteSylow open Equiv Equiv.Perm Finset Function List QuotientGroup -universe u v w +universe u -variable {G : Type u} {α : Type v} {β : Type w} [Group G] +variable {G : Type u} [Group G] theorem QuotientGroup.card_preimage_mk (s : Subgroup G) (t : Set (G ⧸ s)) : Nat.card (QuotientGroup.mk ⁻¹' t) = Nat.card s * Nat.card t := by @@ -451,7 +451,7 @@ def fixedPointsMulLeftCosetsEquivQuotient (H : Subgroup G) [Finite (H : Set G)] normalizer H ⧸ Subgroup.comap ((normalizer H).subtype : normalizer H →* G) H := @subtypeQuotientEquivQuotientSubtype G (normalizer H : Set G) (_) (_) (MulAction.fixedPoints H (G ⧸ H)) - (fun a => (@mem_fixedPoints_mul_left_cosets_iff_mem_normalizer _ _ _ ‹_› _).symm) + (fun _ => (@mem_fixedPoints_mul_left_cosets_iff_mem_normalizer _ _ _ ‹_› _).symm) (by intros unfold_projs @@ -479,7 +479,7 @@ theorem card_normalizer_modEq_card [Finite G] {p : ℕ} {n : ℕ} [hp : Fact p.P /-- If `H` is a `p`-subgroup but not a Sylow `p`-subgroup, then `p` divides the index of `H` inside its normalizer. -/ -theorem prime_dvd_card_quotient_normalizer [Finite G] {p : ℕ} {n : ℕ} [hp : Fact p.Prime] +theorem prime_dvd_card_quotient_normalizer [Finite G] {p : ℕ} {n : ℕ} [Fact p.Prime] (hdvd : p ^ (n + 1) ∣ Nat.card G) {H : Subgroup G} (hH : Nat.card H = p ^ n) : p ∣ Nat.card (normalizer H ⧸ Subgroup.comap ((normalizer H).subtype : normalizer H →* G) H) := let ⟨s, hs⟩ := exists_eq_mul_left_of_dvd hdvd diff --git a/Mathlib/GroupTheory/Torsion.lean b/Mathlib/GroupTheory/Torsion.lean index 1fe565875fe91..2c301f72a0d33 100644 --- a/Mathlib/GroupTheory/Torsion.lean +++ b/Mathlib/GroupTheory/Torsion.lean @@ -161,7 +161,7 @@ namespace CommMonoid @[to_additive addTorsion "The torsion submonoid of an additive commutative monoid."] def torsion : Submonoid G where carrier := { x | IsOfFinOrder x } - one_mem' := isOfFinOrder_one + one_mem' := IsOfFinOrder.one mul_mem' hx hy := hx.mul hy variable {G} @@ -297,7 +297,7 @@ end CommGroup end CommGroup namespace Monoid - +section Monoid variable (G) [Monoid G] /-- A predicate on a monoid saying that only 1 is of finite order. -/ @@ -326,22 +326,17 @@ lemma isTorsionFree_iff_torsion_eq_bot {G} [CommGroup G] : end Monoid section Group - -open Monoid - variable [Group G] /-- A nontrivial torsion group is not torsion-free. -/ -@[to_additive AddMonoid.IsTorsion.not_torsion_free - "A nontrivial additive torsion group is not torsion-free."] +@[to_additive "A nontrivial additive torsion group is not torsion-free."] theorem IsTorsion.not_torsion_free [hN : Nontrivial G] : IsTorsion G → ¬IsTorsionFree G := fun tG => not_isTorsionFree_iff.mpr <| by obtain ⟨x, hx⟩ := (nontrivial_iff_exists_ne (1 : G)).mp hN exact ⟨x, hx, tG x⟩ /-- A nontrivial torsion-free group is not torsion. -/ -@[to_additive AddMonoid.IsTorsionFree.not_torsion - "A nontrivial torsion-free additive group is not torsion."] +@[to_additive "A nontrivial torsion-free additive group is not torsion."] theorem IsTorsionFree.not_torsion [hN : Nontrivial G] : IsTorsionFree G → ¬IsTorsion G := fun tfG => (not_isTorsion_iff _).mpr <| by obtain ⟨x, hx⟩ := (nontrivial_iff_exists_ne (1 : G)).mp hN @@ -371,8 +366,8 @@ open CommGroup (torsion) variable (G) [CommGroup G] /-- Quotienting a group by its torsion subgroup yields a torsion free group. -/ -@[to_additive AddIsTorsionFree.quotient_torsion - "Quotienting a group by its additive torsion subgroup yields an additive torsion free group."] +@[to_additive +"Quotienting a group by its additive torsion subgroup yields an additive torsion free group."] theorem IsTorsionFree.quotient_torsion : IsTorsionFree <| G ⧸ torsion G := fun g hne hfin => hne <| by induction' g using QuotientGroup.induction_on with g @@ -383,21 +378,26 @@ theorem IsTorsionFree.quotient_torsion : IsTorsionFree <| G ⧸ torsion G := fun (isOfFinOrder_iff_pow_eq_one.mpr ⟨m * n, mul_pos mpos npos, (pow_mul g m n).symm ▸ hn⟩) end CommGroup +end Monoid + +namespace AddMonoid lemma isTorsionFree_iff_noZeroSMulDivisors_nat {M : Type*} [AddMonoid M] : - AddMonoid.IsTorsionFree M ↔ NoZeroSMulDivisors ℕ M := by + IsTorsionFree M ↔ NoZeroSMulDivisors ℕ M := by simp_rw [AddMonoid.IsTorsionFree, isOfFinAddOrder_iff_nsmul_eq_zero, not_exists, not_and, pos_iff_ne_zero, noZeroSMulDivisors_iff, forall_swap (β := ℕ)] exact forall₂_congr fun _ _ ↦ by tauto lemma isTorsionFree_iff_noZeroSMulDivisors_int [AddGroup G] : - AddMonoid.IsTorsionFree G ↔ NoZeroSMulDivisors ℤ G := by + IsTorsionFree G ↔ NoZeroSMulDivisors ℤ G := by simp_rw [AddMonoid.IsTorsionFree, isOfFinAddOrder_iff_zsmul_eq_zero, not_exists, not_and, noZeroSMulDivisors_iff, forall_swap (β := ℤ)] exact forall₂_congr fun _ _ ↦ by tauto -@[deprecated (since := "2024-02-29")] -alias AddMonoid.IsTorsionFree_iff_noZeroSMulDivisors := isTorsionFree_iff_noZeroSMulDivisors_int - lemma IsTorsionFree.of_noZeroSMulDivisors {M : Type*} [AddMonoid M] [NoZeroSMulDivisors ℕ M] : - AddMonoid.IsTorsionFree M := isTorsionFree_iff_noZeroSMulDivisors_nat.2 ‹_› + IsTorsionFree M := isTorsionFree_iff_noZeroSMulDivisors_nat.2 ‹_› + +alias ⟨IsTorsionFree.noZeroSMulDivisors_nat, _⟩ := isTorsionFree_iff_noZeroSMulDivisors_nat +alias ⟨IsTorsionFree.noZeroSMulDivisors_int, _⟩ := isTorsionFree_iff_noZeroSMulDivisors_int + +end AddMonoid diff --git a/Mathlib/InformationTheory/Hamming.lean b/Mathlib/InformationTheory/Hamming.lean index 63b352144a998..38a74feba3a9d 100644 --- a/Mathlib/InformationTheory/Hamming.lean +++ b/Mathlib/InformationTheory/Hamming.lean @@ -34,8 +34,7 @@ variable {α ι : Type*} {β : ι → Type*} [Fintype ι] [∀ i, DecidableEq ( variable {γ : ι → Type*} [∀ i, DecidableEq (γ i)] /-- The Hamming distance function to the naturals. -/ -def hammingDist (x y : ∀ i, β i) : ℕ := - (univ.filter fun i => x i ≠ y i).card +def hammingDist (x y : ∀ i, β i) : ℕ := #{i | x i ≠ y i} /-- Corresponds to `dist_self`. -/ @[simp] @@ -103,7 +102,6 @@ theorem hammingDist_ne_zero {x y : ∀ i, β i} : hammingDist x y ≠ 0 ↔ x theorem hammingDist_pos {x y : ∀ i, β i} : 0 < hammingDist x y ↔ x ≠ y := by rw [← hammingDist_ne_zero, iff_not_comm, not_lt, Nat.le_zero] --- @[simp] -- Porting note (#10618): simp can prove this theorem hammingDist_lt_one {x y : ∀ i, β i} : hammingDist x y < 1 ↔ x = y := by rw [Nat.lt_one_iff, hammingDist_eq_zero] @@ -133,8 +131,7 @@ section Zero variable [∀ i, Zero (β i)] [∀ i, Zero (γ i)] /-- The Hamming weight function to the naturals. -/ -def hammingNorm (x : ∀ i, β i) : ℕ := - (univ.filter (x · ≠ 0)).card +def hammingNorm (x : ∀ i, β i) : ℕ := #{i | x i ≠ 0} /-- Corresponds to `dist_zero_right`. -/ @[simp] @@ -147,7 +144,6 @@ theorem hammingDist_zero_left : hammingDist (0 : ∀ i, β i) = hammingNorm := funext fun x => by rw [hammingDist_comm, hammingDist_zero_right] /-- Corresponds to `norm_nonneg`. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem hammingNorm_nonneg {x : ∀ i, β i} : 0 ≤ hammingNorm x := zero_le _ @@ -170,7 +166,6 @@ theorem hammingNorm_ne_zero_iff {x : ∀ i, β i} : hammingNorm x ≠ 0 ↔ x theorem hammingNorm_pos_iff {x : ∀ i, β i} : 0 < hammingNorm x ↔ x ≠ 0 := hammingDist_pos --- @[simp] -- Porting note (#10618): simp can prove this theorem hammingNorm_lt_one {x : ∀ i, β i} : hammingNorm x < 1 ↔ x = 0 := hammingDist_lt_one @@ -288,13 +283,9 @@ theorem toHamming_ofHamming (x : Hamming β) : toHamming (ofHamming x) = x := theorem ofHamming_toHamming (x : ∀ i, β i) : ofHamming (toHamming x) = x := rfl ---@[simp] -- Porting note (#10618): removing `simp`, `simp` can prove it --- and `dsimp` cannot use `Iff.rfl` theorem toHamming_inj {x y : ∀ i, β i} : toHamming x = toHamming y ↔ x = y := Iff.rfl ---@[simp] -- Porting note (#10618): removing `simp`, `simp` can prove it --- and `dsimp` cannot use `Iff.rfl` theorem ofHamming_inj {x y : Hamming β} : ofHamming x = ofHamming y ↔ x = y := Iff.rfl diff --git a/Mathlib/Init.lean b/Mathlib/Init.lean index dff297db373ea..32cb637b4877d 100644 --- a/Mathlib/Init.lean +++ b/Mathlib/Init.lean @@ -1,8 +1,10 @@ import Mathlib.Tactic.Linter.DocPrime import Mathlib.Tactic.Linter.HashCommandLinter import Mathlib.Tactic.Linter.GlobalAttributeIn +import Mathlib.Tactic.Linter.Header -- This file imports Batteries.Tactic.Lint, where the `env_linter` attribute is defined. import Mathlib.Tactic.Linter.Lint +import Mathlib.Tactic.Linter.Multigoal import Mathlib.Tactic.Linter.OldObtain import Mathlib.Tactic.Linter.RefineLinter import Mathlib.Tactic.Linter.UnusedTactic diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index add7ca2edafdb..02701a1fb4c6d 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -7,7 +7,6 @@ Floris van Doorn, Edward Ayers, Arthur Paulino import Mathlib.Init import Lean.Meta.Tactic.Rewrite import Batteries.Lean.Expr -import Batteries.Data.Rat.Basic import Batteries.Tactic.Alias import Lean.Elab.Binders @@ -205,39 +204,6 @@ def eraseProofs (e : Expr) : MetaM Expr := else return .continue) -/-- -Check if an expression is a "rational in normal form", -i.e. either an integer number in normal form, -or `n / d` where `n` is an integer in normal form, `d` is a natural number in normal form, -`d ≠ 1`, and `n` and `d` are coprime (in particular, we check that `(mkRat n d).den = d`). -If so returns the rational number. --/ -def rat? (e : Expr) : Option Rat := do - if e.isAppOfArity ``Div.div 4 then - let d ← e.appArg!.nat? - guard (d ≠ 1) - let n ← e.appFn!.appArg!.int? - let q := mkRat n d - guard (q.den = d) - pure q - else - e.int? - -/-- -Test if an expression represents an explicit number written in normal form: -* A "natural number in normal form" is an expression `OfNat.ofNat n`, even if it is not of type `ℕ`, - as long as `n` is a literal. -* An "integer in normal form" is an expression which is either a natural number in number form, - or `-n`, where `n` is a natural number in normal form. -* A "rational in normal form" is an expressions which is either an integer in normal form, - or `n / d` where `n` is an integer in normal form, `d` is a natural number in normal form, - `d ≠ 1`, and `n` and `d` are coprime (in particular, we check that `(mkRat n d).den = d`). --/ -def isExplicitNumber : Expr → Bool - | .lit _ => true - | .mdata _ e => isExplicitNumber e - | e => e.rat?.isSome - /-- If an `Expr` has form `.fvar n`, then returns `some n`, otherwise `none`. -/ def fvarId? : Expr → Option FVarId | .fvar n => n @@ -324,6 +290,13 @@ otherwise, it returns `none`. -/ let (type, _, lhs, rhs) ← p.app4? ``LE.le return (type, lhs, rhs) +/-- `Lean.Expr.lt? e` takes `e : Expr` as input. +If `e` represents `a < b`, then it returns `some (t, a, b)`, where `t` is the Type of `a`, +otherwise, it returns `none`. -/ +@[inline] def lt? (p : Expr) : Option (Expr × Expr × Expr) := do + let (type, _, lhs, rhs) ← p.app4? ``LT.lt + return (type, lhs, rhs) + /-- Given a proposition `ty` that is an `Eq`, `Iff`, or `HEq`, returns `(tyLhs, lhs, tyRhs, rhs)`, where `lhs : tyLhs` and `rhs : tyRhs`, and where `lhs` is related to `rhs` by the respective relation. diff --git a/Mathlib/Lean/Expr/Rat.lean b/Mathlib/Lean/Expr/Rat.lean new file mode 100644 index 0000000000000..7eb5996b72aa5 --- /dev/null +++ b/Mathlib/Lean/Expr/Rat.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2019 Robert Y. Lewis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Kim Morrison +-/ +import Mathlib.Init +import Batteries.Data.Rat.Basic +import Batteries.Tactic.Alias + +/-! +# Additional operations on Expr and rational numbers + +This file defines some operations involving `Expr` and rational numbers. + +## Main definitions + + * `Lean.Expr.isExplicitNumber`: is an expression a number in normal form? + This includes natural numbers, integers and rationals. +-/ + +namespace Lean.Expr + +/-- +Check if an expression is a "rational in normal form", +i.e. either an integer number in normal form, +or `n / d` where `n` is an integer in normal form, `d` is a natural number in normal form, +`d ≠ 1`, and `n` and `d` are coprime (in particular, we check that `(mkRat n d).den = d`). +If so returns the rational number. +-/ +def rat? (e : Expr) : Option Rat := do + if e.isAppOfArity ``Div.div 4 then + let d ← e.appArg!.nat? + guard (d ≠ 1) + let n ← e.appFn!.appArg!.int? + let q := mkRat n d + guard (q.den = d) + pure q + else + e.int? + +/-- +Test if an expression represents an explicit number written in normal form: +* A "natural number in normal form" is an expression `OfNat.ofNat n`, even if it is not of type `ℕ`, + as long as `n` is a literal. +* An "integer in normal form" is an expression which is either a natural number in number form, + or `-n`, where `n` is a natural number in normal form. +* A "rational in normal form" is an expressions which is either an integer in normal form, + or `n / d` where `n` is an integer in normal form, `d` is a natural number in normal form, + `d ≠ 1`, and `n` and `d` are coprime (in particular, we check that `(mkRat n d).den = d`). +-/ +def isExplicitNumber : Expr → Bool + | .lit _ => true + | .mdata _ e => isExplicitNumber e + | e => e.rat?.isSome + +end Lean.Expr diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean index 86b064cb61eac..3dcf47e22249d 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean @@ -89,9 +89,6 @@ instance equivLike : EquivLike (P₁ ≃ᵃ[k] P₂) P₁ P₂ where right_inv f := f.right_inv coe_injective' _ _ h _ := toAffineMap_injective (DFunLike.coe_injective h) -instance : CoeFun (P₁ ≃ᵃ[k] P₂) fun _ => P₁ → P₂ := - DFunLike.hasCoeToFun - instance : CoeOut (P₁ ≃ᵃ[k] P₂) (P₁ ≃ P₂) := ⟨AffineEquiv.toEquiv⟩ @@ -323,7 +320,7 @@ instance group : Group (P₁ ≃ᵃ[k] P₁) where one := refl k P₁ mul e e' := e'.trans e inv := symm - mul_assoc e₁ e₂ e₃ := trans_assoc _ _ _ + mul_assoc _ _ _ := trans_assoc _ _ _ one_mul := trans_refl mul_one := refl_trans inv_mul_cancel := self_trans_symm diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean index eb8a41bbe9312..71f99e5c85dde 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean @@ -65,12 +65,7 @@ instance AffineMap.instFunLike (k : Type*) {V1 : Type*} (P1 : Type*) {V2 : Type* cases' (AddTorsor.nonempty : Nonempty P1) with p congr with v apply vadd_right_cancel (f p) - erw [← f_add, h, ← g_add] - -instance AffineMap.hasCoeToFun (k : Type*) {V1 : Type*} (P1 : Type*) {V2 : Type*} (P2 : Type*) - [Ring k] [AddCommGroup V1] [Module k V1] [AffineSpace V1 P1] [AddCommGroup V2] [Module k V2] - [AffineSpace V2 P2] : CoeFun (P1 →ᵃ[k] P2) fun _ => P1 → P2 := - DFunLike.hasCoeToFun + rw [← f_add, h, ← g_add] namespace LinearMap @@ -213,8 +208,8 @@ variable {R : Type*} [Monoid R] [DistribMulAction R V2] [SMulCommClass k R V2] instance mulAction : MulAction R (P1 →ᵃ[k] V2) where -- Porting note: `map_vadd` is `simp`, but we still have to pass it explicitly smul c f := ⟨c • ⇑f, c • f.linear, fun p v => by simp [smul_add, map_vadd f]⟩ - one_smul f := ext fun p => one_smul _ _ - mul_smul c₁ c₂ f := ext fun p => mul_smul _ _ _ + one_smul _ := ext fun _ => one_smul _ _ + mul_smul _ _ _ := ext fun _ => mul_smul _ _ _ @[simp, norm_cast] theorem coe_smul (c : R) (f : P1 →ᵃ[k] V2) : ⇑(c • f) = c • ⇑f := @@ -703,7 +698,7 @@ theorem pi_comp (g : P3 →ᵃ[k] P1) : (pi fp).comp g = pi (fun i => (fp i).com rfl theorem pi_eq_zero : pi fv = 0 ↔ ∀ i, fv i = 0 := by - simp only [AffineMap.ext_iff, Function.funext_iff, pi_apply] + simp only [AffineMap.ext_iff, funext_iff, pi_apply] exact forall_comm theorem pi_zero : pi (fun _ ↦ 0 : (i : ι) → P1 →ᵃ[k] φv i) = 0 := by diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index ab4b6063b2c23..4ad30ae06cd1d 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -49,6 +49,7 @@ noncomputable section open Affine open Set +open scoped Pointwise section @@ -510,6 +511,12 @@ theorem direction_affineSpan (s : Set P) : (affineSpan k s).direction = vectorSp theorem mem_affineSpan {p : P} {s : Set P} (hp : p ∈ s) : p ∈ affineSpan k s := mem_spanPoints k p s hp +@[simp] +lemma vectorSpan_add_self (s : Set V) : (vectorSpan k s : Set V) + s = affineSpan k s := by + ext + simp [mem_add, spanPoints] + aesop + end affineSpan namespace AffineSubspace @@ -522,13 +529,13 @@ instance : CompleteLattice (AffineSubspace k P) := PartialOrder.lift ((↑) : AffineSubspace k P → Set P) coe_injective with sup := fun s1 s2 => affineSpan k (s1 ∪ s2) - le_sup_left := fun s1 s2 => + le_sup_left := fun _ _ => Set.Subset.trans Set.subset_union_left (subset_spanPoints k _) - le_sup_right := fun s1 s2 => + le_sup_right := fun _ _ => Set.Subset.trans Set.subset_union_right (subset_spanPoints k _) - sup_le := fun s1 s2 s3 hs1 hs2 => spanPoints_subset_coe_of_subset_coe (Set.union_subset hs1 hs2) + sup_le := fun _ _ _ hs1 hs2 => spanPoints_subset_coe_of_subset_coe (Set.union_subset hs1 hs2) inf := fun s1 s2 => - mk (s1 ∩ s2) fun c p1 p2 p3 hp1 hp2 hp3 => + mk (s1 ∩ s2) fun c _ _ _ hp1 hp2 hp3 => ⟨s1.smul_vsub_vadd_mem c hp1.1 hp2.1 hp3.1, s2.smul_vsub_vadd_mem c hp1.2 hp2.2 hp3.2⟩ inf_le_left := fun _ _ => Set.inter_subset_left inf_le_right := fun _ _ => Set.inter_subset_right @@ -1284,6 +1291,17 @@ lemma affineSpan_subset_span {s : Set V} : (affineSpan k s : Set V) ⊆ Submodule.span k s := affineSpan_le_toAffineSubspace_span +-- TODO: We want this to be simp, but `affineSpan` gets simped away to `spanPoints`! +-- Let's delete `spanPoints` +lemma affineSpan_insert_zero (s : Set V) : + (affineSpan k (insert 0 s) : Set V) = Submodule.span k s := by + rw [← Submodule.span_insert_zero] + refine affineSpan_subset_span.antisymm ?_ + rw [← vectorSpan_add_self, vectorSpan_def] + refine Subset.trans ?_ <| subset_add_left _ <| mem_insert .. + gcongr + exact subset_sub_left <| mem_insert .. + end AffineSpace' namespace AffineSubspace diff --git a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean index 74aad257f2367..33d82512d88eb 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean @@ -122,7 +122,7 @@ theorem weightedVSubOfPoint_eq_of_sum_eq_zero (w : ι → k) (p : ι → P) (h : base point when the sum of the weights is 1. -/ theorem weightedVSubOfPoint_vadd_eq_of_sum_eq_one (w : ι → k) (p : ι → P) (h : ∑ i ∈ s, w i = 1) (b₁ b₂ : P) : s.weightedVSubOfPoint p b₁ w +ᵥ b₁ = s.weightedVSubOfPoint p b₂ w +ᵥ b₂ := by - erw [weightedVSubOfPoint_apply, weightedVSubOfPoint_apply, ← @vsub_eq_zero_iff_eq V, + rw [weightedVSubOfPoint_apply, weightedVSubOfPoint_apply, ← @vsub_eq_zero_iff_eq V, vadd_vsub_assoc, vsub_vadd_eq_vsub_sub, ← add_sub_assoc, add_comm, add_sub_assoc, ← sum_sub_distrib] conv_lhs => @@ -202,18 +202,18 @@ theorem weightedVSubOfPoint_sdiff_sub [DecidableEq ι] {s₂ : Finset ι} (h : s s.weightedVSubOfPoint p b w := by rw [map_neg, sub_neg_eq_add, s.weightedVSubOfPoint_sdiff h] -/-- A weighted sum over `s.subtype pred` equals one over `s.filter pred`. -/ +/-- A weighted sum over `s.subtype pred` equals one over `{x ∈ s | pred x}`. -/ theorem weightedVSubOfPoint_subtype_eq_filter (w : ι → k) (p : ι → P) (b : P) (pred : ι → Prop) [DecidablePred pred] : ((s.subtype pred).weightedVSubOfPoint (fun i => p i) b fun i => w i) = - (s.filter pred).weightedVSubOfPoint p b w := by + {x ∈ s | pred x}.weightedVSubOfPoint p b w := by rw [weightedVSubOfPoint_apply, weightedVSubOfPoint_apply, ← sum_subtype_eq_sum_filter] -/-- A weighted sum over `s.filter pred` equals one over `s` if all the weights at indices in `s` +/-- A weighted sum over `{x ∈ s | pred x}` equals one over `s` if all the weights at indices in `s` not satisfying `pred` are zero. -/ theorem weightedVSubOfPoint_filter_of_ne (w : ι → k) (p : ι → P) (b : P) {pred : ι → Prop} [DecidablePred pred] (h : ∀ i ∈ s, w i ≠ 0 → pred i) : - (s.filter pred).weightedVSubOfPoint p b w = s.weightedVSubOfPoint p b w := by + {x ∈ s | pred x}.weightedVSubOfPoint p b w = s.weightedVSubOfPoint p b w := by rw [weightedVSubOfPoint_apply, weightedVSubOfPoint_apply, sum_filter_of_ne] intro i hi hne refine h i hi ?_ @@ -319,17 +319,17 @@ theorem weightedVSub_sdiff_sub [DecidableEq ι] {s₂ : Finset ι} (h : s₂ ⊆ (p : ι → P) : (s \ s₂).weightedVSub p w - s₂.weightedVSub p (-w) = s.weightedVSub p w := s.weightedVSubOfPoint_sdiff_sub h _ _ _ -/-- A weighted sum over `s.subtype pred` equals one over `s.filter pred`. -/ +/-- A weighted sum over `s.subtype pred` equals one over `{x ∈ s | pred x}`. -/ theorem weightedVSub_subtype_eq_filter (w : ι → k) (p : ι → P) (pred : ι → Prop) [DecidablePred pred] : ((s.subtype pred).weightedVSub (fun i => p i) fun i => w i) = - (s.filter pred).weightedVSub p w := + {x ∈ s | pred x}.weightedVSub p w := s.weightedVSubOfPoint_subtype_eq_filter _ _ _ _ -/-- A weighted sum over `s.filter pred` equals one over `s` if all the weights at indices in `s` +/-- A weighted sum over `{x ∈ s | pred x}` equals one over `s` if all the weights at indices in `s` not satisfying `pred` are zero. -/ theorem weightedVSub_filter_of_ne (w : ι → k) (p : ι → P) {pred : ι → Prop} [DecidablePred pred] - (h : ∀ i ∈ s, w i ≠ 0 → pred i) : (s.filter pred).weightedVSub p w = s.weightedVSub p w := + (h : ∀ i ∈ s, w i ≠ 0 → pred i) : {x ∈ s | pred x}.weightedVSub p w = s.weightedVSub p w := s.weightedVSubOfPoint_filter_of_ne _ _ _ h /-- A constant multiplier of the weights in `weightedVSub_of` may be moved outside the sum. -/ @@ -497,7 +497,7 @@ theorem affineCombination_sdiff_sub [DecidableEq ι] {s₂ : Finset ι} (h : s the affine combination of the other points with the given weights. -/ theorem affineCombination_eq_of_weightedVSub_eq_zero_of_eq_neg_one {w : ι → k} {p : ι → P} (hw : s.weightedVSub p w = (0 : V)) {i : ι} [DecidablePred (· ≠ i)] (his : i ∈ s) - (hwi : w i = -1) : (s.filter (· ≠ i)).affineCombination k p w = p i := by + (hwi : w i = -1) : {x ∈ s | x ≠ i}.affineCombination k p w = p i := by classical rw [← @vsub_eq_zero_iff_eq V, ← hw, ← s.affineCombination_sdiff_sub (singleton_subset_iff.2 his), sdiff_singleton_eq_erase, @@ -507,18 +507,18 @@ theorem affineCombination_eq_of_weightedVSub_eq_zero_of_eq_neg_one {w : ι → k · simp [hwi] · simp -/-- An affine combination over `s.subtype pred` equals one over `s.filter pred`. -/ +/-- An affine combination over `s.subtype pred` equals one over `{x ∈ s | pred x}`. -/ theorem affineCombination_subtype_eq_filter (w : ι → k) (p : ι → P) (pred : ι → Prop) [DecidablePred pred] : ((s.subtype pred).affineCombination k (fun i => p i) fun i => w i) = - (s.filter pred).affineCombination k p w := by + {x ∈ s | pred x}.affineCombination k p w := by rw [affineCombination_apply, affineCombination_apply, weightedVSubOfPoint_subtype_eq_filter] -/-- An affine combination over `s.filter pred` equals one over `s` if all the weights at indices +/-- An affine combination over `{x ∈ s | pred x}` equals one over `s` if all the weights at indices in `s` not satisfying `pred` are zero. -/ theorem affineCombination_filter_of_ne (w : ι → k) (p : ι → P) {pred : ι → Prop} [DecidablePred pred] (h : ∀ i ∈ s, w i ≠ 0 → pred i) : - (s.filter pred).affineCombination k p w = s.affineCombination k p w := by + {x ∈ s | pred x}.affineCombination k p w = s.affineCombination k p w := by rw [affineCombination_apply, affineCombination_apply, s.weightedVSubOfPoint_filter_of_ne _ _ _ h] @@ -712,29 +712,29 @@ variable [AffineSpace V P] {ι : Type*} (s : Finset ι) {ι₂ : Type*} (s₂ : /-- The weights for the centroid of some points. -/ def centroidWeights : ι → k := - Function.const ι (card s : k)⁻¹ + Function.const ι (#s : k)⁻¹ /-- `centroidWeights` at any point. -/ @[simp] -theorem centroidWeights_apply (i : ι) : s.centroidWeights k i = (card s : k)⁻¹ := +theorem centroidWeights_apply (i : ι) : s.centroidWeights k i = (#s : k)⁻¹ := rfl /-- `centroidWeights` equals a constant function. -/ -theorem centroidWeights_eq_const : s.centroidWeights k = Function.const ι (card s : k)⁻¹ := +theorem centroidWeights_eq_const : s.centroidWeights k = Function.const ι (#s : k)⁻¹ := rfl variable {k} /-- The weights in the centroid sum to 1, if the number of points, converted to `k`, is not zero. -/ -theorem sum_centroidWeights_eq_one_of_cast_card_ne_zero (h : (card s : k) ≠ 0) : +theorem sum_centroidWeights_eq_one_of_cast_card_ne_zero (h : (#s : k) ≠ 0) : ∑ i ∈ s, s.centroidWeights k i = 1 := by simp [h] variable (k) /-- In the characteristic zero case, the weights in the centroid sum to 1 if the number of points is not zero. -/ -theorem sum_centroidWeights_eq_one_of_card_ne_zero [CharZero k] (h : card s ≠ 0) : +theorem sum_centroidWeights_eq_one_of_card_ne_zero [CharZero k] (h : #s ≠ 0) : ∑ i ∈ s, s.centroidWeights k i = 1 := by -- Porting note: `simp` cannot find `mul_inv_cancel` and does not use `norm_cast` simp only [centroidWeights_apply, sum_const, nsmul_eq_mul, ne_eq, Nat.cast_eq_zero, card_eq_zero] @@ -749,7 +749,7 @@ theorem sum_centroidWeights_eq_one_of_nonempty [CharZero k] (h : s.Nonempty) : /-- In the characteristic zero case, the weights in the centroid sum to 1 if the number of points is `n + 1`. -/ -theorem sum_centroidWeights_eq_one_of_card_eq_add_one [CharZero k] {n : ℕ} (h : card s = n + 1) : +theorem sum_centroidWeights_eq_one_of_card_eq_add_one [CharZero k] {n : ℕ} (h : #s = n + 1) : ∑ i ∈ s, s.centroidWeights k i = 1 := s.sum_centroidWeights_eq_one_of_card_ne_zero k (h.symm ▸ Nat.succ_ne_zero n) @@ -780,7 +780,7 @@ theorem centroid_pair [DecidableEq ι] [Invertible (2 : k)] (p : ι → P) (i₁ ({i₁, i₂} : Finset ι).centroid k p = (2⁻¹ : k) • (p i₂ -ᵥ p i₁) +ᵥ p i₁ := by by_cases h : i₁ = i₂ · simp [h] - · have hc : (card ({i₁, i₂} : Finset ι) : k) ≠ 0 := by + · have hc : (#{i₁, i₂} : k) ≠ 0 := by rw [card_insert_of_not_mem (not_mem_singleton.2 h), card_singleton] norm_num exact Invertible.ne_zero _ @@ -825,7 +825,7 @@ theorem sum_centroidWeightsIndicator [Fintype ι] : indexed by a `Fintype` sum to 1 if the number of points is not zero. -/ theorem sum_centroidWeightsIndicator_eq_one_of_card_ne_zero [CharZero k] [Fintype ι] - (h : card s ≠ 0) : ∑ i, s.centroidWeightsIndicator k i = 1 := by + (h : #s ≠ 0) : ∑ i, s.centroidWeightsIndicator k i = 1 := by rw [sum_centroidWeightsIndicator] exact s.sum_centroidWeights_eq_one_of_card_ne_zero k h @@ -839,7 +839,7 @@ theorem sum_centroidWeightsIndicator_eq_one_of_nonempty [CharZero k] [Fintype ι /-- In the characteristic zero case, the weights in the centroid indexed by a `Fintype` sum to 1 if the number of points is `n + 1`. -/ theorem sum_centroidWeightsIndicator_eq_one_of_card_eq_add_one [CharZero k] [Fintype ι] {n : ℕ} - (h : card s = n + 1) : ∑ i, s.centroidWeightsIndicator k i = 1 := by + (h : #s = n + 1) : ∑ i, s.centroidWeightsIndicator k i = 1 := by rw [sum_centroidWeightsIndicator] exact s.sum_centroidWeights_eq_one_of_card_eq_add_one k h @@ -935,10 +935,7 @@ theorem affineCombination_mem_affineSpan [Nontrivial k] {s : Finset ι} {w : ι have hv : s.affineCombination k p w -ᵥ p i1 ∈ (affineSpan k (Set.range p)).direction := by rw [direction_affineSpan, ← hw1s, Finset.affineCombination_vsub] apply weightedVSub_mem_vectorSpan - -- Porting note: Rest was `simp [Pi.sub_apply, h, hw1]`, - -- but `Pi.sub_apply` transforms the goal into nonsense - change (Finset.sum s fun i => w i - w1 i) = 0 - simp only [Finset.sum_sub_distrib, h, hw1, sub_self] + simp [Pi.sub_apply, h, hw1] rw [← vsub_vadd (s.affineCombination k p w) (p i1)] exact AffineSubspace.vadd_mem_of_mem_direction hv (mem_affineSpan k (Set.mem_range_self _)) @@ -1019,8 +1016,7 @@ theorem eq_affineCombination_of_mem_affineSpan {p1 : P} {p : ι → P} s'.affineCombination_of_eq_one_of_eq_zero w0 p (Finset.mem_insert_self _ _) (Function.update_same _ _ _) fun _ _ hne => Function.update_noteq hne _ _ refine ⟨s', w0 + w', ?_, ?_⟩ - · -- Porting note: proof was `simp [Pi.add_apply, Finset.sum_add_distrib, hw0, h']` - simp only [Pi.add_apply, Finset.sum_add_distrib, hw0, h', add_zero] + · simp [Pi.add_apply, Finset.sum_add_distrib, hw0, h'] · rw [add_comm, ← Finset.weightedVSub_vadd_affineCombination, hw0s, hs', vsub_vadd] theorem eq_affineCombination_of_mem_affineSpan_of_fintype [Fintype ι] {p1 : P} {p : ι → P} @@ -1103,7 +1099,7 @@ open Set Finset /-- The centroid lies in the affine span if the number of points, converted to `k`, is not zero. -/ theorem centroid_mem_affineSpan_of_cast_card_ne_zero {s : Finset ι} (p : ι → P) - (h : (card s : k) ≠ 0) : s.centroid k p ∈ affineSpan k (range p) := + (h : (#s : k) ≠ 0) : s.centroid k p ∈ affineSpan k (range p) := affineCombination_mem_affineSpan (s.sum_centroidWeights_eq_one_of_cast_card_ne_zero h) p variable (k) @@ -1111,7 +1107,7 @@ variable (k) /-- In the characteristic zero case, the centroid lies in the affine span if the number of points is not zero. -/ theorem centroid_mem_affineSpan_of_card_ne_zero [CharZero k] {s : Finset ι} (p : ι → P) - (h : card s ≠ 0) : s.centroid k p ∈ affineSpan k (range p) := + (h : #s ≠ 0) : s.centroid k p ∈ affineSpan k (range p) := affineCombination_mem_affineSpan (s.sum_centroidWeights_eq_one_of_card_ne_zero k h) p /-- In the characteristic zero case, the centroid lies in the affine @@ -1123,7 +1119,7 @@ theorem centroid_mem_affineSpan_of_nonempty [CharZero k] {s : Finset ι} (p : ι /-- In the characteristic zero case, the centroid lies in the affine span if the number of points is `n + 1`. -/ theorem centroid_mem_affineSpan_of_card_eq_add_one [CharZero k] {s : Finset ι} (p : ι → P) {n : ℕ} - (h : card s = n + 1) : s.centroid k p ∈ affineSpan k (range p) := + (h : #s = n + 1) : s.centroid k p ∈ affineSpan k (range p) := affineCombination_mem_affineSpan (s.sum_centroidWeights_eq_one_of_card_eq_add_one k h) p end DivisionRing diff --git a/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean b/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean index 12ffbd6ace838..df744660c3393 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean @@ -73,9 +73,6 @@ instance instEquivLike : EquivLike (P₁ ≃ᵃL[k] P₂) P₁ P₂ where right_inv f := f.right_inv coe_injective' _ _ h _ := toAffineEquiv_injective (DFunLike.coe_injective h) -instance : CoeFun (P₁ ≃ᵃL[k] P₂) fun _ ↦ P₁ → P₂ := - DFunLike.hasCoeToFun - attribute [coe] ContinuousAffineEquiv.toAffineEquiv /-- Coerce continuous affine equivalences to affine equivalences. -/ diff --git a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean index 935dc82abfb3b..0ef068c764695 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean @@ -23,6 +23,7 @@ subspaces of affine spaces. noncomputable section open Affine +open scoped Finset section AffineSpace' @@ -87,18 +88,18 @@ variable {k} /-- The `vectorSpan` of a finite subset of an affinely independent family has dimension one less than its cardinality. -/ theorem AffineIndependent.finrank_vectorSpan_image_finset [DecidableEq P] - {p : ι → P} (hi : AffineIndependent k p) {s : Finset ι} {n : ℕ} (hc : Finset.card s = n + 1) : + {p : ι → P} (hi : AffineIndependent k p) {s : Finset ι} {n : ℕ} (hc : #s = n + 1) : finrank k (vectorSpan k (s.image p : Set P)) = n := by classical have hi' := hi.range.mono (Set.image_subset_range p ↑s) - have hc' : (s.image p).card = n + 1 := by rwa [s.card_image_of_injective hi.injective] + have hc' : #(s.image p) = n + 1 := by rwa [s.card_image_of_injective hi.injective] have hn : (s.image p).Nonempty := by simp [hc', ← Finset.card_pos] rcases hn with ⟨p₁, hp₁⟩ have hp₁' : p₁ ∈ p '' s := by simpa using hp₁ rw [affineIndependent_set_iff_linearIndependent_vsub k hp₁', ← Finset.coe_singleton, ← Finset.coe_image, ← Finset.coe_sdiff, Finset.sdiff_singleton_eq_erase, ← Finset.coe_image] at hi' - have hc : (Finset.image (fun p : P => p -ᵥ p₁) ((Finset.image p s).erase p₁)).card = n := by + have hc : #(((s.image p).erase p₁).image (· -ᵥ p₁)) = n := by rw [Finset.card_image_of_injective _ (vsub_left_injective _), Finset.card_erase_of_mem hp₁] exact Nat.pred_eq_of_eq_succ hc' rwa [vectorSpan_eq_span_vsub_finset_right_ne k hp₁, finrank_span_finset_eq_card, hc] @@ -132,7 +133,7 @@ variable (k) /-- The `vectorSpan` of `n + 1` points in an indexed family has dimension at most `n`. -/ theorem finrank_vectorSpan_image_finset_le [DecidableEq P] (p : ι → P) (s : Finset ι) {n : ℕ} - (hc : Finset.card s = n + 1) : finrank k (vectorSpan k (s.image p : Set P)) ≤ n := by + (hc : #s = n + 1) : finrank k (vectorSpan k (s.image p : Set P)) ≤ n := by classical have hn : (s.image p).Nonempty := by rw [Finset.image_nonempty, ← Finset.card_pos, hc] @@ -214,7 +215,7 @@ open Finset in cardinality is at most the cardinality of that finset. -/ lemma AffineIndependent.card_le_card_of_subset_affineSpan {s t : Finset V} (hs : AffineIndependent k ((↑) : s → V)) (hst : (s : Set V) ⊆ affineSpan k (t : Set V)) : - s.card ≤ t.card := by + #s ≤ #t := by obtain rfl | hs' := s.eq_empty_or_nonempty · simp obtain rfl | ht' := t.eq_empty_or_nonempty @@ -234,7 +235,7 @@ open Finset in another finset, then its cardinality is strictly less than the cardinality of that finset. -/ lemma AffineIndependent.card_lt_card_of_affineSpan_lt_affineSpan {s t : Finset V} (hs : AffineIndependent k ((↑) : s → V)) - (hst : affineSpan k (s : Set V) < affineSpan k (t : Set V)) : s.card < t.card := by + (hst : affineSpan k (s : Set V) < affineSpan k (t : Set V)) : #s < #t := by obtain rfl | hs' := s.eq_empty_or_nonempty · simpa [card_pos] using hst obtain rfl | ht' := t.eq_empty_or_nonempty @@ -255,7 +256,7 @@ cardinality, it equals that submodule. -/ theorem AffineIndependent.vectorSpan_image_finset_eq_of_le_of_card_eq_finrank_add_one [DecidableEq P] {p : ι → P} (hi : AffineIndependent k p) {s : Finset ι} {sm : Submodule k V} [FiniteDimensional k sm] - (hle : vectorSpan k (s.image p : Set P) ≤ sm) (hc : Finset.card s = finrank k sm + 1) : + (hle : vectorSpan k (s.image p : Set P) ≤ sm) (hc : #s = finrank k sm + 1) : vectorSpan k (s.image p : Set P) = sm := Submodule.eq_of_le_of_finrank_eq hle <| hi.finrank_vectorSpan_image_finset hc @@ -275,7 +276,7 @@ theorem AffineIndependent.affineSpan_image_finset_eq_of_le_of_card_eq_finrank_ad [DecidableEq P] {p : ι → P} (hi : AffineIndependent k p) {s : Finset ι} {sp : AffineSubspace k P} [FiniteDimensional k sp.direction] (hle : affineSpan k (s.image p : Set P) ≤ sp) - (hc : Finset.card s = finrank k sp.direction + 1) : affineSpan k (s.image p : Set P) = sp := by + (hc : #s = finrank k sp.direction + 1) : affineSpan k (s.image p : Set P) = sp := by have hn : s.Nonempty := by rw [← Finset.card_pos, hc] apply Nat.succ_pos diff --git a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean index 0adb6c8ef435b..f8801772f8d02 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean @@ -104,7 +104,7 @@ theorem affineIndependent_iff_linearIndependent_vsub (p : ι → P) (i1 : ι) : intro x rw [hfdef] dsimp only - erw [dif_neg x.property, Subtype.coe_eta] + rw [dif_neg x.property, Subtype.coe_eta] rw [hfg] have hf : ∑ ι ∈ s2, f ι = 0 := by rw [Finset.sum_insert @@ -810,19 +810,19 @@ add_decl_doc Affine.Simplex.ext_iff /-- A face of a simplex is a simplex with the given subset of points. -/ -def face {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} (h : fs.card = m + 1) : +def face {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} (h : #fs = m + 1) : Simplex k P m := ⟨s.points ∘ fs.orderEmbOfFin h, s.independent.comp_embedding (fs.orderEmbOfFin h).toEmbedding⟩ /-- The points of a face of a simplex are given by `mono_of_fin`. -/ theorem face_points {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} - (h : fs.card = m + 1) (i : Fin (m + 1)) : + (h : #fs = m + 1) (i : Fin (m + 1)) : (s.face h).points i = s.points (fs.orderEmbOfFin h i) := rfl /-- The points of a face of a simplex are given by `mono_of_fin`. -/ theorem face_points' {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} - (h : fs.card = m + 1) : (s.face h).points = s.points ∘ fs.orderEmbOfFin h := + (h : #fs = m + 1) : (s.face h).points = s.points ∘ fs.orderEmbOfFin h := rfl /-- A single-point face equals the 0-simplex constructed with @@ -838,7 +838,7 @@ theorem face_eq_mkOfPoint {n : ℕ} (s : Simplex k P n) (i : Fin (n + 1)) : /-- The set of points of a face. -/ @[simp] theorem range_face_points {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} - (h : fs.card = m + 1) : Set.range (s.face h).points = s.points '' ↑fs := by + (h : #fs = m + 1) : Set.range (s.face h).points = s.points '' ↑fs := by rw [face_points', Set.range_comp, Finset.range_orderEmbOfFin] /-- Remap a simplex along an `Equiv` of index types. -/ @@ -889,7 +889,7 @@ variable {k : Type*} {V : Type*} {P : Type*} [DivisionRing k] [AddCommGroup V] [ the points. -/ @[simp] theorem face_centroid_eq_centroid {n : ℕ} (s : Simplex k P n) {fs : Finset (Fin (n + 1))} {m : ℕ} - (h : fs.card = m + 1) : Finset.univ.centroid k (s.face h).points = fs.centroid k s.points := by + (h : #fs = m + 1) : Finset.univ.centroid k (s.face h).points = fs.centroid k s.points := by convert (Finset.univ.centroid_map k (fs.orderEmbOfFin h).toEmbedding s.points).symm rw [← Finset.coe_inj, Finset.coe_map, Finset.coe_univ, Set.image_univ] simp @@ -899,7 +899,7 @@ two subsets of the points of a simplex are equal if and only if those faces are given by the same subset of points. -/ @[simp] theorem centroid_eq_iff [CharZero k] {n : ℕ} (s : Simplex k P n) {fs₁ fs₂ : Finset (Fin (n + 1))} - {m₁ m₂ : ℕ} (h₁ : fs₁.card = m₁ + 1) (h₂ : fs₂.card = m₂ + 1) : + {m₁ m₂ : ℕ} (h₁ : #fs₁ = m₁ + 1) (h₂ : #fs₂ = m₂ + 1) : fs₁.centroid k s.points = fs₂.centroid k s.points ↔ fs₁ = fs₂ := by refine ⟨fun h => ?_, @congrArg _ _ fs₁ fs₂ (fun z => Finset.centroid k z s.points)⟩ rw [Finset.centroid_eq_affineCombination_fintype, @@ -908,7 +908,7 @@ theorem centroid_eq_iff [CharZero k] {n : ℕ} (s : Simplex k P n) {fs₁ fs₂ (affineIndependent_iff_indicator_eq_of_affineCombination_eq k s.points).1 s.independent _ _ _ _ (fs₁.sum_centroidWeightsIndicator_eq_one_of_card_eq_add_one k h₁) (fs₂.sum_centroidWeightsIndicator_eq_one_of_card_eq_add_one k h₂) h - simp_rw [Finset.coe_univ, Set.indicator_univ, Function.funext_iff, + simp_rw [Finset.coe_univ, Set.indicator_univ, funext_iff, Finset.centroidWeightsIndicator_def, Finset.centroidWeights, h₁, h₂] at ha ext i specialize ha i @@ -924,7 +924,7 @@ theorem centroid_eq_iff [CharZero k] {n : ℕ} (s : Simplex k P n) {fs₁ fs₂ faces of a simplex are equal if and only if those faces are given by the same subset of points. -/ theorem face_centroid_eq_iff [CharZero k] {n : ℕ} (s : Simplex k P n) - {fs₁ fs₂ : Finset (Fin (n + 1))} {m₁ m₂ : ℕ} (h₁ : fs₁.card = m₁ + 1) (h₂ : fs₂.card = m₂ + 1) : + {fs₁ fs₂ : Finset (Fin (n + 1))} {m₁ m₂ : ℕ} (h₁ : #fs₁ = m₁ + 1) (h₂ : #fs₂ = m₂ + 1) : Finset.univ.centroid k (s.face h₁).points = Finset.univ.centroid k (s.face h₂).points ↔ fs₁ = fs₂ := by rw [face_centroid_eq_centroid, face_centroid_eq_centroid] diff --git a/Mathlib/LinearAlgebra/AffineSpace/Midpoint.lean b/Mathlib/LinearAlgebra/AffineSpace/Midpoint.lean index d57b4f3a3c569..90be3fd7ffbba 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Midpoint.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Midpoint.lean @@ -3,6 +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.Module.Basic import Mathlib.LinearAlgebra.AffineSpace.AffineEquiv /-! diff --git a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean index bc28ee54454cb..9f3c4c81c015f 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean @@ -134,15 +134,13 @@ theorem lineMap_le_right_iff_le (h : r < 1) : lineMap a b r ≤ b ↔ a ≤ b := Iff.trans (by rw [lineMap_apply_one]) (lineMap_le_lineMap_iff_of_lt h) @[simp] -theorem midpoint_le_right : midpoint k a b ≤ b ↔ a ≤ b := - lineMap_le_right_iff_le <| inv_lt_one one_lt_two +theorem midpoint_le_right : midpoint k a b ≤ b ↔ a ≤ b := lineMap_le_right_iff_le two_inv_lt_one theorem right_le_lineMap_iff_le (h : r < 1) : b ≤ lineMap a b r ↔ b ≤ a := lineMap_le_right_iff_le (E := Eᵒᵈ) h @[simp] -theorem right_le_midpoint : b ≤ midpoint k a b ↔ b ≤ a := - right_le_lineMap_iff_le <| inv_lt_one one_lt_two +theorem right_le_midpoint : b ≤ midpoint k a b ↔ b ≤ a := right_le_lineMap_iff_le two_inv_lt_one end diff --git a/Mathlib/LinearAlgebra/AffineSpace/Pointwise.lean b/Mathlib/LinearAlgebra/AffineSpace/Pointwise.lean index d7a79d2cfd7b2..3ad614ee09a53 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Pointwise.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Pointwise.lean @@ -69,7 +69,7 @@ theorem pointwise_vadd_span (v : V) (s : Set P) : v +ᵥ affineSpan k s = affine theorem map_pointwise_vadd (f : P₁ →ᵃ[k] P₂) (v : V₁) (s : AffineSubspace k P₁) : (v +ᵥ s).map f = f.linear v +ᵥ s.map f := by - erw [pointwise_vadd_eq_map, pointwise_vadd_eq_map, map_map, map_map] + rw [pointwise_vadd_eq_map, pointwise_vadd_eq_map, map_map, map_map] congr 1 ext exact f.map_vadd _ _ diff --git a/Mathlib/LinearAlgebra/Alternating/Basic.lean b/Mathlib/LinearAlgebra/Alternating/Basic.lean index 007a27d357368..6fc8b20955e39 100644 --- a/Mathlib/LinearAlgebra/Alternating/Basic.lean +++ b/Mathlib/LinearAlgebra/Alternating/Basic.lean @@ -93,10 +93,6 @@ instance instFunLike : FunLike (M [⋀^ι]→ₗ[R] N) (ι → M) N where rcases g with ⟨⟨_, _, _⟩, _⟩ congr --- shortcut instance -instance coeFun : CoeFun (M [⋀^ι]→ₗ[R] N) fun _ => (ι → M) → N := - ⟨DFunLike.coe⟩ - initialize_simps_projections AlternatingMap (toFun → apply) @[simp] @@ -118,7 +114,7 @@ protected theorem congr_arg (f : M [⋀^ι]→ₗ[R] N) {x y : ι → M} (h : x theorem coe_injective : Injective ((↑) : M [⋀^ι]→ₗ[R] N → (ι → M) → N) := DFunLike.coe_injective -@[norm_cast] -- @[simp] -- Porting note (#10618): simp can prove this +@[norm_cast] theorem coe_inj {f g : M [⋀^ι]→ₗ[R] N} : (f : (ι → M) → N) = g ↔ f = g := coe_injective.eq_iff @@ -286,7 +282,7 @@ theorem coe_add : (↑(f + f') : MultilinearMap R (fun _ : ι => M) N) = f + f' instance zero : Zero (M [⋀^ι]→ₗ[R] N) := ⟨{ (0 : MultilinearMap R (fun _ : ι => M) N) with - map_eq_zero_of_eq' := fun v i j _ _ => by simp }⟩ + map_eq_zero_of_eq' := fun _ _ _ _ _ => by simp }⟩ @[simp] theorem zero_apply : (0 : M [⋀^ι]→ₗ[R] N) v = 0 := @@ -407,19 +403,12 @@ end AlternatingMap namespace LinearMap -variable {N₂ : Type*} [AddCommMonoid N₂] [Module R N₂] +variable {S : Type*} {N₂ : Type*} [AddCommMonoid N₂] [Module R N₂] /-- Composing an alternating map with a linear map on the left gives again an alternating map. -/ -def compAlternatingMap (g : N →ₗ[R] N₂) : (M [⋀^ι]→ₗ[R] N) →+ (M [⋀^ι]→ₗ[R] N₂) where - toFun f := - { g.compMultilinearMap (f : MultilinearMap R (fun _ : ι => M) N) with - map_eq_zero_of_eq' := fun v i j h hij => by simp [f.map_eq_zero_of_eq v h hij] } - map_zero' := by - ext - simp - map_add' a b := by - ext - simp +def compAlternatingMap (g : N →ₗ[R] N₂) (f : M [⋀^ι]→ₗ[R] N) : M [⋀^ι]→ₗ[R] N₂ where + __ := g.compMultilinearMap (f : MultilinearMap R (fun _ : ι => M) N) + map_eq_zero_of_eq' v i j h hij := by simp [f.map_eq_zero_of_eq v h hij] @[simp] theorem coe_compAlternatingMap (g : N →ₗ[R] N₂) (f : M [⋀^ι]→ₗ[R] N) : @@ -431,6 +420,47 @@ theorem compAlternatingMap_apply (g : N →ₗ[R] N₂) (f : M [⋀^ι]→ₗ[R] g.compAlternatingMap f m = g (f m) := rfl +@[simp] +theorem compAlternatingMap_zero (g : N →ₗ[R] N₂) : + g.compAlternatingMap (0 : M [⋀^ι]→ₗ[R] N) = 0 := + AlternatingMap.ext fun _ => map_zero g + +@[simp] +theorem zero_compAlternatingMap (f: M [⋀^ι]→ₗ[R] N) : + (0 : N →ₗ[R] N₂).compAlternatingMap f = 0 := rfl + +@[simp] +theorem compAlternatingMap_add (g : N →ₗ[R] N₂) (f₁ f₂ : M [⋀^ι]→ₗ[R] N) : + g.compAlternatingMap (f₁ + f₂) = g.compAlternatingMap f₁ + g.compAlternatingMap f₂ := + AlternatingMap.ext fun _ => map_add g _ _ + +@[simp] +theorem add_compAlternatingMap (g₁ g₂ : N →ₗ[R] N₂) (f: M [⋀^ι]→ₗ[R] N) : + (g₁ + g₂).compAlternatingMap f = g₁.compAlternatingMap f + g₂.compAlternatingMap f := rfl + +@[simp] +theorem compAlternatingMap_smul [Monoid S] [DistribMulAction S N] [DistribMulAction S N₂] + [SMulCommClass R S N] [SMulCommClass R S N₂] [CompatibleSMul N N₂ S R] + (g : N →ₗ[R] N₂) (s : S) (f : M [⋀^ι]→ₗ[R] N) : + g.compAlternatingMap (s • f) = s • g.compAlternatingMap f := + AlternatingMap.ext fun _ => g.map_smul_of_tower _ _ + +@[simp] +theorem smul_compAlternatingMap [Monoid S] [DistribMulAction S N₂] [SMulCommClass R S N₂] + (g : N →ₗ[R] N₂) (s : S) (f : M [⋀^ι]→ₗ[R] N) : + (s • g).compAlternatingMap f = s • g.compAlternatingMap f := rfl + +variable (S) in +/-- `LinearMap.compAlternatingMap` as an `S`-linear map. -/ +@[simps] +def compAlternatingMapₗ [Semiring S] [Module S N] [Module S N₂] + [SMulCommClass R S N] [SMulCommClass R S N₂] [LinearMap.CompatibleSMul N N₂ S R] + (g : N →ₗ[R] N₂) : + (M [⋀^ι]→ₗ[R] N) →ₗ[S] (M [⋀^ι]→ₗ[R] N₂) where + toFun := g.compAlternatingMap + map_add' := g.compAlternatingMap_add + map_smul' := g.compAlternatingMap_smul + theorem smulRight_eq_comp {R M₁ M₂ ι : Type*} [CommSemiring R] [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R M₁] [Module R M₂] (f : M₁ [⋀^ι]→ₗ[R] R) (z : M₂) : f.smulRight z = (LinearMap.id.smulRight z).compAlternatingMap f := @@ -491,9 +521,7 @@ theorem add_compLinearMap (f₁ f₂ : M [⋀^ι]→ₗ[R] N) (g : M₂ →ₗ[R theorem compLinearMap_zero [Nonempty ι] (f : M [⋀^ι]→ₗ[R] N) : f.compLinearMap (0 : M₂ →ₗ[R] M) = 0 := by ext - -- Porting note: Was `simp_rw [.., ← Pi.zero_def, map_zero, zero_apply]`. - simp_rw [compLinearMap_apply, LinearMap.zero_apply, ← Pi.zero_def, zero_apply] - exact map_zero f + simp_rw [compLinearMap_apply, LinearMap.zero_apply, ← Pi.zero_def, map_zero, zero_apply] /-- Composing an alternating map with the identity linear map in each argument. -/ @[simp] @@ -873,8 +901,8 @@ def curryLeft {n : ℕ} (f : M'' [⋀^Fin n.succ]→ₗ[R'] N'') : map_eq_zero_of_eq' := fun v i j hv hij => f.map_eq_zero_of_eq _ (by rwa [Matrix.cons_val_succ, Matrix.cons_val_succ]) ((Fin.succ_injective _).ne hij) } - map_add' m₁ m₂ := ext fun v => f.map_vecCons_add _ _ _ - map_smul' r m := ext fun v => f.map_vecCons_smul _ _ _ + map_add' _ _ := ext fun _ => f.map_vecCons_add _ _ _ + map_smul' _ _ := ext fun _ => f.map_vecCons_smul _ _ _ @[simp] theorem curryLeft_zero {n : ℕ} : curryLeft (0 : M'' [⋀^Fin n.succ]→ₗ[R'] N'') = 0 := @@ -903,7 +931,7 @@ def curryLeftLinearMap {n : ℕ} : @[simp] theorem curryLeft_same {n : ℕ} (f : M'' [⋀^Fin n.succ.succ]→ₗ[R'] N'') (m : M'') : (f.curryLeft m).curryLeft m = 0 := - ext fun x => f.map_eq_zero_of_eq _ (by simp) Fin.zero_ne_one + ext fun _ => f.map_eq_zero_of_eq _ (by simp) Fin.zero_ne_one @[simp] theorem curryLeft_compAlternatingMap {n : ℕ} (g : N'' →ₗ[R'] N₂'') diff --git a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean index 9f90f39e9ee1f..001f2f17ef8d5 100644 --- a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean +++ b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean @@ -57,7 +57,7 @@ def domCoprod.summand (a : Mᵢ [⋀^ιa]→ₗ[R'] N₁) (b : Mᵢ [⋀^ιb]→ TensorProduct.smul_tmul'] simp only [Sum.map_inr, Perm.sumCongrHom_apply, Perm.sumCongr_apply, Sum.map_inl, Function.comp_apply, Perm.coe_mul] - -- Porting note (#10691): was `rw`. + -- Porting note (#11224): was `rw`. erw [← a.map_congr_perm fun i => v (σ₁ _), ← b.map_congr_perm fun i => v (σ₁ _)] theorem domCoprod.summand_mk'' (a : Mᵢ [⋀^ιa]→ₗ[R'] N₁) (b : Mᵢ [⋀^ιb]→ₗ[R'] N₂) @@ -225,7 +225,7 @@ theorem MultilinearMap.domCoprod_alternization [DecidableEq ιa] [DecidableEq ι refine Quotient.inductionOn' σ fun σ => ?_ -- unfold the quotient mess left by `Finset.sum_partition` -- Porting note: Was `conv in .. => ..`. - erw + rw [@Finset.filter_congr _ _ _ (fun a => @Quotient.decidableEq _ _ (QuotientGroup.leftRelDecidable (MonoidHom.range (Perm.sumCongrHom ιa ιb))) (Quotient.mk (QuotientGroup.leftRel (MonoidHom.range (Perm.sumCongrHom ιa ιb))) a) diff --git a/Mathlib/LinearAlgebra/Basis/Basic.lean b/Mathlib/LinearAlgebra/Basis/Basic.lean index 46ed8282bcd9a..0279f219ad9bf 100644 --- a/Mathlib/LinearAlgebra/Basis/Basic.lean +++ b/Mathlib/LinearAlgebra/Basis/Basic.lean @@ -24,18 +24,15 @@ universe u open Function Set Submodule Finsupp -variable {ι : Type*} {ι' : Type*} {R : Type*} {R₂ : Type*} {K : Type*} -variable {M : Type*} {M' M'' : Type*} {V : Type u} {V' : Type*} +variable {ι : Type*} {ι' : Type*} {R : Type*} {R₂ : Type*} {M : Type*} {M' : Type*} section Module -variable [Semiring R] -variable [AddCommMonoid M] [Module R M] [AddCommMonoid M'] [Module R M'] - +variable [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid M'] [Module R M'] namespace Basis -variable (b b₁ : Basis ι R M) (i : ι) (c : R) (x : M) +variable (b : Basis ι R M) section Coord @@ -49,10 +46,8 @@ theorem coe_sumCoords_eq_finsum : (b.sumCoords : M → R) = fun m => ∑ᶠ i, b end Coord protected theorem linearIndependent : LinearIndependent R b := - linearIndependent_iff.mpr fun l hl => - calc - l = b.repr (Finsupp.linearCombination _ b l) := (b.repr_linearCombination l).symm - _ = 0 := by rw [hl, LinearEquiv.map_zero] + fun x y hxy => by + rw [← b.repr_linearCombination x, hxy, b.repr_linearCombination y] protected theorem ne_zero [Nontrivial R] (i) : b i ≠ 0 := b.linearIndependent.ne_zero i @@ -125,8 +120,9 @@ protected theorem noZeroSMulDivisors [NoZeroDivisors R] (b : Basis ι R M) : NoZeroSMulDivisors R M := ⟨fun {c x} hcx => by exact or_iff_not_imp_right.mpr fun hx => by - rw [← b.linearCombination_repr x, ← LinearMap.map_smul] at hcx - have := linearIndependent_iff.mp b.linearIndependent (c • b.repr x) hcx + rw [← b.linearCombination_repr x, ← LinearMap.map_smul, + ← map_zero (linearCombination R b)] at hcx + have := b.linearIndependent hcx rw [smul_eq_zero] at this exact this.resolve_right fun hr => hx (b.repr.map_eq_zero_iff.mp hr)⟩ @@ -134,20 +130,6 @@ protected theorem smul_eq_zero [NoZeroDivisors R] (b : Basis ι R M) {c : R} {x c • x = 0 ↔ c = 0 ∨ x = 0 := @smul_eq_zero _ _ _ _ _ b.noZeroSMulDivisors _ _ -theorem eq_bot_of_rank_eq_zero [NoZeroDivisors R] (b : Basis ι R M) (N : Submodule R M) - (rank_eq : ∀ {m : ℕ} (v : Fin m → N), LinearIndependent R ((↑) ∘ v : Fin m → M) → m = 0) : - N = ⊥ := by - rw [Submodule.eq_bot_iff] - intro x hx - contrapose! rank_eq with x_ne - refine ⟨1, fun _ => ⟨x, hx⟩, ?_, one_ne_zero⟩ - rw [Fintype.linearIndependent_iff] - rintro g sum_eq i - cases' i with _ hi - simp only [Function.const_apply, Fin.default_eq_zero, Submodule.coe_mk, Finset.univ_unique, - Function.comp_const, Finset.sum_singleton] at sum_eq - convert (b.smul_eq_zero.mp sum_eq).resolve_right x_ne - end NoZeroSMulDivisors section Singleton @@ -187,11 +169,25 @@ section Module open LinearMap variable {v : ι → M} -variable [Ring R] [CommRing R₂] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M''] -variable [Module R M] [Module R₂ M] [Module R M'] [Module R M''] -variable {c d : R} {x y : M} +variable [Ring R] [CommRing R₂] [AddCommGroup M] +variable [Module R M] [Module R₂ M] +variable {x y : M} variable (b : Basis ι R M) +theorem Basis.eq_bot_of_rank_eq_zero [NoZeroDivisors R] (b : Basis ι R M) (N : Submodule R M) + (rank_eq : ∀ {m : ℕ} (v : Fin m → N), LinearIndependent R ((↑) ∘ v : Fin m → M) → m = 0) : + N = ⊥ := by + rw [Submodule.eq_bot_iff] + intro x hx + contrapose! rank_eq with x_ne + refine ⟨1, fun _ => ⟨x, hx⟩, ?_, one_ne_zero⟩ + rw [Fintype.linearIndependent_iff] + rintro g sum_eq i + cases' i with _ hi + simp only [Function.const_apply, Fin.default_eq_zero, Submodule.coe_mk, Finset.univ_unique, + Function.comp_const, Finset.sum_singleton] at sum_eq + convert (b.smul_eq_zero.mp sum_eq).resolve_right x_ne + namespace Basis /-- Any basis is a maximal linear independent set. diff --git a/Mathlib/LinearAlgebra/Basis/Cardinality.lean b/Mathlib/LinearAlgebra/Basis/Cardinality.lean index 284ad5ed30aa4..64108a9f48908 100644 --- a/Mathlib/LinearAlgebra/Basis/Cardinality.lean +++ b/Mathlib/LinearAlgebra/Basis/Cardinality.lean @@ -21,7 +21,7 @@ variable {R : Type u} {M : Type v} section Semiring -variable [Semiring R] [AddCommGroup M] [Nontrivial R] [Module R M] +variable [Semiring R] [AddCommMonoid M] [Nontrivial R] [Module R M] -- One might hope that a finite spanning set implies that any linearly independent set is finite. -- While this is true over a division ring diff --git a/Mathlib/LinearAlgebra/Basis/VectorSpace.lean b/Mathlib/LinearAlgebra/Basis/VectorSpace.lean index 5ffcc1cc36b43..c16a5b57e71ea 100644 --- a/Mathlib/LinearAlgebra/Basis/VectorSpace.lean +++ b/Mathlib/LinearAlgebra/Basis/VectorSpace.lean @@ -86,6 +86,61 @@ theorem subset_extend {s : Set V} (hs : LinearIndependent K ((↑) : s → V)) : s ⊆ hs.extend (Set.subset_univ _) := hs.subset_extend _ +/-- If `s` is a family of linearly independent vectors contained in a set `t` spanning `V`, +then one can get a basis of `V` containing `s` and contained in `t`. -/ +noncomputable def extendLe (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) : + Basis (hs.extend hst) K V := + Basis.mk + (@LinearIndependent.restrict_of_comp_subtype _ _ _ id _ _ _ _ (hs.linearIndependent_extend _)) + (le_trans ht <| Submodule.span_le.2 <| by simpa using hs.subset_span_extend hst) + +theorem extendLe_apply_self (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) (x : hs.extend hst) : + Basis.extendLe hs hst ht x = x := + Basis.mk_apply _ _ _ + +@[simp] +theorem coe_extendLe (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) : ⇑(Basis.extendLe hs hst ht) = ((↑) : _ → _) := + funext (extendLe_apply_self hs hst ht) + +theorem range_extendLe (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) : + range (Basis.extendLe hs hst ht) = hs.extend hst := by + rw [coe_extendLe, Subtype.range_coe_subtype, setOf_mem_eq] + +theorem subset_extendLe (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) : + s ⊆ range (Basis.extendLe hs hst ht) := + (range_extendLe hs hst ht).symm ▸ hs.subset_extend hst + +theorem extendLe_subset (hs : LinearIndependent K ((↑) : s → V)) + (hst : s ⊆ t) (ht : ⊤ ≤ span K t) : + range (Basis.extendLe hs hst ht) ⊆ t := + (range_extendLe hs hst ht).symm ▸ hs.extend_subset hst + +/-- If a set `s` spans the space, this is a basis contained in `s`. -/ +noncomputable def ofSpan (hs : ⊤ ≤ span K s) : + Basis ((linearIndependent_empty K V).extend (empty_subset s)) K V := + extendLe (linearIndependent_empty K V) (empty_subset s) hs + +theorem ofSpan_apply_self (hs : ⊤ ≤ span K s) + (x : (linearIndependent_empty K V).extend (empty_subset s)) : + Basis.ofSpan hs x = x := + extendLe_apply_self (linearIndependent_empty K V) (empty_subset s) hs x + +@[simp] +theorem coe_ofSpan (hs : ⊤ ≤ span K s) : ⇑(ofSpan hs) = ((↑) : _ → _) := + funext (ofSpan_apply_self hs) + +theorem range_ofSpan (hs : ⊤ ≤ span K s) : + range (ofSpan hs) = (linearIndependent_empty K V).extend (empty_subset s) := by + rw [coe_ofSpan, Subtype.range_coe_subtype, setOf_mem_eq] + +theorem ofSpan_subset (hs : ⊤ ≤ span K s) : range (ofSpan hs) ⊆ s := + extendLe_subset (linearIndependent_empty K V) (empty_subset s) hs + section variable (K V) @@ -211,15 +266,6 @@ theorem Submodule.exists_isCompl (p : Submodule K V) : ∃ q : Submodule K V, Is instance Submodule.complementedLattice : ComplementedLattice (Submodule K V) := ⟨Submodule.exists_isCompl⟩ -theorem LinearMap.exists_rightInverse_of_surjective (f : V →ₗ[K] V') (hf_surj : range f = ⊤) : - ∃ g : V' →ₗ[K] V, f.comp g = LinearMap.id := by - let C := Basis.ofVectorSpaceIndex K V' - let hC := Basis.ofVectorSpace K V' - haveI : Inhabited V := ⟨0⟩ - refine ⟨(hC.constr ℕ : _ → _) (C.restrict (invFun f)), hC.ext fun c => ?_⟩ - rw [LinearMap.comp_apply, hC.constr_basis] - simp [hC, rightInverse_invFun (LinearMap.range_eq_top.1 hf_surj) c] - /-- Any linear map `f : p →ₗ[K] V'` defined on a subspace `p` can be extended to the whole space. -/ theorem LinearMap.exists_extend {p : Submodule K V} (f : p →ₗ[K] V') : diff --git a/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean index 24c02406a750c..8fba55a7ccff6 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean @@ -51,12 +51,12 @@ lemma le_flip_dualSubmodule {N₁ N₂ : Submodule R M} : This is bundled as a bilinear map in `BilinForm.dualSubmoduleToDual`. -/ noncomputable def dualSubmoduleParing {N : Submodule R M} (x : B.dualSubmodule N) (y : N) : R := - (x.prop y y.prop).choose + (Submodule.mem_one.mp <| x.prop y y.prop).choose @[simp] lemma dualSubmoduleParing_spec {N : Submodule R M} (x : B.dualSubmodule N) (y : N) : algebraMap R S (B.dualSubmoduleParing x y) = B x y := - (x.prop y y.prop).choose_spec + (Submodule.mem_one.mp <| x.prop y y.prop).choose_spec /-- The natural paring of `B.dualSubmodule N` and `N`. -/ -- TODO: Show that this is perfect when `N` is a lattice and `B` is nondegenerate. @@ -94,7 +94,7 @@ lemma dualSubmodule_span_of_basis {ι} [Finite ι] [DecidableEq ι] rw [← (B.dualBasis hB b).sum_repr x] apply sum_mem rintro i - - obtain ⟨r, hr⟩ := hx (b i) (Submodule.subset_span ⟨_, rfl⟩) + obtain ⟨r, hr⟩ := Submodule.mem_one.mp <| hx (b i) (Submodule.subset_span ⟨_, rfl⟩) simp only [dualBasis_repr_apply, ← hr, Algebra.linearMap_apply, algebraMap_smul] apply Submodule.smul_mem exact Submodule.subset_span ⟨_, rfl⟩ @@ -107,7 +107,7 @@ lemma dualSubmodule_span_of_basis {ι} [Finite ι] [DecidableEq ι] rw [← IsScalarTower.algebraMap_smul S (f j), map_smul] simp_rw [apply_dualBasis_left] rw [smul_eq_mul, mul_ite, mul_one, mul_zero, ← (algebraMap R S).map_zero, ← apply_ite] - exact ⟨_, rfl⟩ + exact Submodule.mem_one.mpr ⟨_, rfl⟩ lemma dualSubmodule_dualSubmodule_flip_of_basis {ι : Type*} [Finite ι] (hB : B.Nondegenerate) (b : Basis ι S M) : diff --git a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean index f32f28e8aea31..9c011c36ed52b 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean @@ -39,6 +39,7 @@ Bilinear form, -/ open LinearMap (BilinForm) +open LinearMap (BilinMap) universe u v w @@ -261,15 +262,8 @@ variable [AddCommMonoid M'] [AddCommMonoid M''] [Module R M'] [Module R M''] section congr /-- Apply a linear equivalence on the arguments of a bilinear form. -/ -def congr (e : M ≃ₗ[R] M') : BilinForm R M ≃ₗ[R] BilinForm R M' where - toFun B := B.comp e.symm e.symm - invFun B := B.comp e e - left_inv B := ext₂ fun x => by - simp only [comp_apply, LinearEquiv.coe_coe, LinearEquiv.symm_apply_apply, forall_const] - right_inv B := ext₂ fun x => by - simp only [comp_apply, LinearEquiv.coe_coe, LinearEquiv.apply_symm_apply, forall_const] - map_add' B B' := ext₂ fun x y => rfl - map_smul' B B' := ext₂ fun x y => rfl +def congr (e : M ≃ₗ[R] M') : BilinForm R M ≃ₗ[R] BilinForm R M' := + LinearEquiv.congrRight (LinearEquiv.congrLeft _ _ e) ≪≫ₗ LinearEquiv.congrLeft _ _ e @[simp] theorem congr_apply (e : M ≃ₗ[R] M') (B : BilinForm R M) (x y : M') : @@ -307,6 +301,37 @@ theorem comp_congr (e : M' ≃ₗ[R] M'') (B : BilinForm R M) (l r : M' →ₗ[R end congr +section congrRight₂ + +variable {N₁ N₂ N₃ : Type*} +variable [AddCommMonoid N₁] [AddCommMonoid N₂] [AddCommMonoid N₃] +variable [Module R N₁] [Module R N₂] [Module R N₃] + +/-- When `N₁` and `N₂` are equivalent, bilinear maps on `M` into `N₁` are equivalent to bilinear +maps into `N₂`. -/ +def _root_.LinearEquiv.congrRight₂ (e : N₁ ≃ₗ[R] N₂) : BilinMap R M N₁ ≃ₗ[R] BilinMap R M N₂ := + LinearEquiv.congrRight (LinearEquiv.congrRight e) + +@[simp] +theorem _root_.LinearEquiv.congrRight₂_apply (e : N₁ ≃ₗ[R] N₂) (B : BilinMap R M N₁) : + LinearEquiv.congrRight₂ e B = compr₂ B e := rfl + +@[simp] +theorem _root_.LinearEquiv.congrRight₂_refl : + LinearEquiv.congrRight₂ (.refl R N₁) = .refl R (BilinMap R M N₁) := rfl + +@[simp] +theorem _root_.LinearEquiv.congrRight_symm (e : N₁ ≃ₗ[R] N₂) : + (LinearEquiv.congrRight₂ e (M := M)).symm = LinearEquiv.congrRight₂ e.symm := + rfl + +theorem _root_.LinearEquiv.congrRight₂_trans (e₁₂ : N₁ ≃ₗ[R] N₂) (e₂₃ : N₂ ≃ₗ[R] N₃) : + LinearEquiv.congrRight₂ (M := M) (e₁₂ ≪≫ₗ e₂₃) = + LinearEquiv.congrRight₂ e₁₂ ≪≫ₗ LinearEquiv.congrRight₂ e₂₃ := + rfl + +end congrRight₂ + section LinMulLin /-- `linMulLin f g` is the bilinear form mapping `x` and `y` to `f x * g y` -/ diff --git a/Mathlib/LinearAlgebra/BilinearForm/Properties.lean b/Mathlib/LinearAlgebra/BilinearForm/Properties.lean index 47f62c2cd1587..65f1bea36c373 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Properties.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Properties.lean @@ -464,7 +464,7 @@ noncomputable def symmCompOfNondegenerate (B₁ B₂ : BilinForm K V) (b₂ : B theorem comp_symmCompOfNondegenerate_apply (B₁ : BilinForm K V) {B₂ : BilinForm K V} (b₂ : B₂.Nondegenerate) (v : V) : B₂ (B₁.symmCompOfNondegenerate B₂ b₂ v) = B₁ v := by - erw [symmCompOfNondegenerate] + rw [symmCompOfNondegenerate] simp only [coe_comp, LinearEquiv.coe_coe, Function.comp_apply, DFunLike.coe_fn_eq] erw [LinearEquiv.apply_symm_apply (B₂.toDual b₂)] diff --git a/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean b/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean index d7ab301e16a91..27fae6ed0d462 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean @@ -5,6 +5,7 @@ Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.Dual import Mathlib.LinearAlgebra.TensorProduct.Tower +import Mathlib.LinearAlgebra.BilinearForm.Hom /-! # The bilinear form on a tensor product @@ -20,24 +21,68 @@ import Mathlib.LinearAlgebra.TensorProduct.Tower suppress_compilation -universe u v w uι uR uA uM₁ uM₂ +universe u v w uR uA uM₁ uM₂ uN₁ uN₂ -variable {ι : Type uι} {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂} +variable {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂} {N₁ : Type uN₁} {N₂ : Type uN₂} open TensorProduct namespace LinearMap -namespace BilinMap - open LinearMap (BilinMap BilinForm) section CommSemiring + variable [CommSemiring R] [CommSemiring A] -variable [AddCommMonoid M₁] [AddCommMonoid M₂] -variable [Algebra R A] [Module R M₁] [Module A M₁] +variable [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid N₁] [AddCommMonoid N₂] +variable [Algebra R A] [Module R M₁] [Module A M₁] [Module R N₁] [Module A N₁] variable [SMulCommClass R A M₁] [IsScalarTower R A M₁] -variable [Module R M₂] +variable [SMulCommClass R A N₁] [IsScalarTower R A N₁] +variable [Module R M₂] [Module R N₂] + +namespace BilinMap + +variable (R A) in +/-- The tensor product of two bilinear maps injects into bilinear maps on tensor products. + +Note this is heterobasic; the bilinear map on the left can take values in a module over a +(commutative) algebra over the ring of the module in which the right bilinear map is valued. -/ +def tensorDistrib : + (BilinMap A M₁ N₁ ⊗[R] BilinMap R M₂ N₂) →ₗ[A] BilinMap A (M₁ ⊗[R] M₂) (N₁ ⊗[R] N₂) := + (TensorProduct.lift.equiv A (M₁ ⊗[R] M₂) (M₁ ⊗[R] M₂) (N₁ ⊗[R] N₂)).symm.toLinearMap ∘ₗ + ((LinearMap.llcomp A _ _ _).flip + (TensorProduct.AlgebraTensorModule.tensorTensorTensorComm R A M₁ M₂ M₁ M₂).toLinearMap) + ∘ₗ TensorProduct.AlgebraTensorModule.homTensorHomMap R _ _ _ _ _ _ + ∘ₗ (TensorProduct.AlgebraTensorModule.congr + (TensorProduct.lift.equiv A M₁ M₁ N₁) + (TensorProduct.lift.equiv R _ _ _)).toLinearMap + +@[simp] +theorem tensorDistrib_tmul (B₁ : BilinMap A M₁ N₁) (B₂ : BilinMap R M₂ N₂) (m₁ : M₁) (m₂ : M₂) + (m₁' : M₁) (m₂' : M₂) : + tensorDistrib R A (B₁ ⊗ₜ B₂) (m₁ ⊗ₜ m₂) (m₁' ⊗ₜ m₂') + = B₁ m₁ m₁' ⊗ₜ B₂ m₂ m₂' := + rfl + +/-- The tensor product of two bilinear forms, a shorthand for dot notation. -/ +protected abbrev tmul (B₁ : BilinMap A M₁ N₁) (B₂ : BilinMap R M₂ N₂) : + BilinMap A (M₁ ⊗[R] M₂) (N₁ ⊗[R] N₂) := + tensorDistrib R A (B₁ ⊗ₜ[R] B₂) + +variable (A) in +/-- The base change of a bilinear map (also known as "extension of scalars"). -/ +protected def baseChange (B : BilinMap R M₂ N₂) : BilinMap A (A ⊗[R] M₂) (A ⊗[R] N₂) := + BilinMap.tmul (R := R) (A := A) (M₁ := A) (M₂ := M₂) (LinearMap.mul A A) B + +@[simp] +theorem baseChange_tmul (B₂ : BilinMap R M₂ N₂) (a : A) (m₂ : M₂) + (a' : A) (m₂' : M₂) : + B₂.baseChange A (a ⊗ₜ m₂) (a' ⊗ₜ m₂') = (a * a') ⊗ₜ (B₂ m₂ m₂') := + rfl + +end BilinMap + +namespace BilinForm variable (R A) in /-- The tensor product of two bilinear forms injects into bilinear forms on tensor products. @@ -45,12 +90,9 @@ variable (R A) in Note this is heterobasic; the bilinear form on the left can take values in an (commutative) algebra over the ring in which the right bilinear form is valued. -/ def tensorDistrib : BilinForm A M₁ ⊗[R] BilinForm R M₂ →ₗ[A] BilinForm A (M₁ ⊗[R] M₂) := - ((TensorProduct.AlgebraTensorModule.tensorTensorTensorComm R A M₁ M₂ M₁ M₂).dualMap - ≪≫ₗ (TensorProduct.lift.equiv A (M₁ ⊗[R] M₂) (M₁ ⊗[R] M₂) A).symm).toLinearMap - ∘ₗ TensorProduct.AlgebraTensorModule.dualDistrib R _ _ _ - ∘ₗ (TensorProduct.AlgebraTensorModule.congr - (TensorProduct.lift.equiv A M₁ M₁ A) - (TensorProduct.lift.equiv R _ _ _)).toLinearMap + (AlgebraTensorModule.rid R A A).congrRight₂.toLinearMap ∘ₗ (BilinMap.tensorDistrib R A) + +variable (R A) in -- TODO: make the RHS `MulOpposite.op (B₂ m₂ m₂') • B₁ m₁ m₁'` so that this has a nicer defeq for -- `R = A` of `B₁ m₁ m₁' * B₂ m₂ m₂'`, as it did before the generalization in #6306. @@ -62,12 +104,12 @@ theorem tensorDistrib_tmul (B₁ : BilinForm A M₁) (B₂ : BilinForm R M₂) ( rfl /-- The tensor product of two bilinear forms, a shorthand for dot notation. -/ -protected abbrev tmul (B₁ : BilinMap A M₁ A) (B₂ : BilinMap R M₂ R) : BilinMap A (M₁ ⊗[R] M₂) A := +protected abbrev tmul (B₁ : BilinForm A M₁) (B₂ : BilinMap R M₂ R) : BilinMap A (M₁ ⊗[R] M₂) A := tensorDistrib R A (B₁ ⊗ₜ[R] B₂) attribute [local ext] TensorProduct.ext in /-- A tensor product of symmetric bilinear forms is symmetric. -/ -lemma _root_.LinearMap.IsSymm.tmul {B₁ : BilinMap A M₁ A} {B₂ : BilinMap R M₂ R} +lemma _root_.LinearMap.IsSymm.tmul {B₁ : BilinForm A M₁} {B₂ : BilinForm R M₂} (hB₁ : B₁.IsSymm) (hB₂ : B₂.IsSymm) : (B₁.tmul B₂).IsSymm := by rw [LinearMap.isSymm_iff_eq_flip] ext x₁ x₂ y₁ y₂ @@ -75,11 +117,11 @@ lemma _root_.LinearMap.IsSymm.tmul {B₁ : BilinMap A M₁ A} {B₂ : BilinMap R variable (A) in /-- The base change of a bilinear form. -/ -protected def baseChange (B : BilinMap R M₂ R) : BilinForm A (A ⊗[R] M₂) := - BilinMap.tmul (R := R) (A := A) (M₁ := A) (M₂ := M₂) (LinearMap.mul A A) B +protected def baseChange (B : BilinForm R M₂) : BilinForm A (A ⊗[R] M₂) := + BilinForm.tmul (R := R) (A := A) (M₁ := A) (M₂ := M₂) (LinearMap.mul A A) B @[simp] -theorem baseChange_tmul (B₂ : BilinMap R M₂ R) (a : A) (m₂ : M₂) +theorem baseChange_tmul (B₂ : BilinForm R M₂) (a : A) (m₂ : M₂) (a' : A) (m₂' : M₂) : B₂.baseChange A (a ⊗ₜ m₂) (a' ⊗ₜ m₂') = (B₂ m₂ m₂') • (a * a') := rfl @@ -89,6 +131,8 @@ variable (A) in lemma IsSymm.baseChange {B₂ : BilinForm R M₂} (hB₂ : B₂.IsSymm) : (B₂.baseChange A).IsSymm := IsSymm.tmul mul_comm hB₂ +end BilinForm + end CommSemiring section CommRing @@ -99,6 +143,8 @@ variable [Module R M₁] [Module R M₂] variable [Module.Free R M₁] [Module.Finite R M₁] variable [Module.Free R M₂] [Module.Finite R M₂] +namespace BilinForm + variable (R) in /-- `tensorDistrib` as an equivalence. -/ noncomputable def tensorDistribEquiv : @@ -131,8 +177,8 @@ theorem tensorDistribEquiv_apply (B : BilinForm R M₁ ⊗ BilinForm R M₂) : tensorDistribEquiv R (M₁ := M₁) (M₂ := M₂) B = tensorDistrib R R B := DFunLike.congr_fun (tensorDistribEquiv_toLinearMap R M₁ M₂) B -end CommRing +end BilinForm -end BilinMap +end CommRing end LinearMap diff --git a/Mathlib/LinearAlgebra/BilinearMap.lean b/Mathlib/LinearAlgebra/BilinearMap.lean index 10c008423626e..c720aff5ff9b6 100644 --- a/Mathlib/LinearAlgebra/BilinearMap.lean +++ b/Mathlib/LinearAlgebra/BilinearMap.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro -/ import Mathlib.Algebra.Module.Submodule.Ker +import Mathlib.Algebra.NoZeroSMulDivisors.Basic /-! # Basics on bilinear maps @@ -102,8 +103,8 @@ attribute [local instance] SMulCommClass.symm /-- Given a linear map from `M` to linear maps from `N` to `P`, i.e., a bilinear map from `M × N` to `P`, change the order of variables and get a linear map from `N` to linear maps from `M` to `P`. -/ def flip (f : M →ₛₗ[ρ₁₂] N →ₛₗ[σ₁₂] P) : N →ₛₗ[σ₁₂] M →ₛₗ[ρ₁₂] P := - mk₂'ₛₗ σ₁₂ ρ₁₂ (fun n m => f m n) (fun n₁ n₂ m => (f m).map_add _ _) - (fun c n m => (f m).map_smulₛₗ _ _) + mk₂'ₛₗ σ₁₂ ρ₁₂ (fun n m => f m n) (fun _ _ m => (f m).map_add _ _) + (fun _ _ m => (f m).map_smulₛₗ _ _) (fun n m₁ m₂ => by simp only [map_add, add_apply]) -- Note: #8386 changed `map_smulₛₗ` into `map_smulₛₗ _`. -- It looks like we now run out of assignable metavariables. diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/BaseChange.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/BaseChange.lean index e83ba0a051353..e25b22b5361e7 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/BaseChange.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/BaseChange.lean @@ -95,7 +95,7 @@ noncomputable def toBaseChange (Q : QuadraticForm R V) : exact hpure_tensor v w intros v w rw [← TensorProduct.tmul_add, CliffordAlgebra.ι_mul_ι_add_swap, - QuadraticForm.polarBilin_baseChange, LinearMap.BilinMap.baseChange_tmul, one_mul, + QuadraticForm.polarBilin_baseChange, LinearMap.BilinForm.baseChange_tmul, one_mul, TensorProduct.smul_tmul, Algebra.algebraMap_eq_smul_one, QuadraticMap.polarBilin_apply_apply] @[simp] theorem toBaseChange_ι (Q : QuadraticForm R V) (z : A) (v : V) : diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean index 8f6b4168968e9..410d9c7363d47 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean @@ -46,7 +46,6 @@ This file is almost identical to `Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.le variable {R : Type*} [CommRing R] variable {M : Type*} [AddCommGroup M] [Module R M] variable (Q : QuadraticForm R M) -variable {n : ℕ} namespace CliffordAlgebra diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean index 019e24cf0951f..52780073fdfe0 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.CliffordAlgebra.Grading -import Mathlib.Algebra.Module.Opposites +import Mathlib.Algebra.Module.Opposite /-! # Conjugations diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean index 30687d5b35594..82b7f5635657c 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean @@ -105,7 +105,7 @@ theorem involute_eq_id : protected def equiv : CliffordAlgebra (0 : QuadraticForm R Unit) ≃ₐ[R] R := AlgEquiv.ofAlgHom (CliffordAlgebra.lift (0 : QuadraticForm R Unit) <| - ⟨0, fun m : Unit => (zero_mul (0 : R)).trans (algebraMap R _).map_zero.symm⟩) + ⟨0, fun _ : Unit => (zero_mul (0 : R)).trans (algebraMap R _).map_zero.symm⟩) (Algebra.ofId R _) (by ext) (by ext : 1; rw [ι_eq_zero, LinearMap.comp_zero, LinearMap.comp_zero]) @@ -354,7 +354,7 @@ open scoped DualNumber open DualNumber TrivSqZeroExt -variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] +variable {R : Type*} [CommRing R] theorem ι_mul_ι (r₁ r₂) : ι (0 : QuadraticForm R R) r₁ * ι (0 : QuadraticForm R R) r₂ = 0 := by rw [← mul_one r₁, ← mul_one r₂, ← smul_eq_mul R, ← smul_eq_mul R, LinearMap.map_smul, @@ -392,7 +392,6 @@ theorem equiv_ι (r : R) : CliffordAlgebraDualNumber.equiv (ι (R := R) _ r) = r @[simp] theorem equiv_symm_eps : CliffordAlgebraDualNumber.equiv.symm (eps : R[ε]) = ι (0 : QuadraticForm R R) 1 := - -- Porting note: Original proof was `DualNumber.lift_apply_eps _` - DualNumber.lift_apply_eps (R := R) (B := CliffordAlgebra (0 : QuadraticForm R R)) _ + DualNumber.lift_apply_eps _ end CliffordAlgebraDualNumber diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean index 76bff36c9a4d1..c7ec32d1e1e44 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean @@ -157,8 +157,8 @@ private def fFold : M →ₗ[R] A × S f →ₗ[R] A × S f := LinearMap.ext fun m₃ => show f.bilin m₃ (c • m) * a.1 = c • (f.bilin m₃ m * a.1) by rw [LinearMap.map_smul, smul_mul_assoc])) - (fun m a₁ a₂ => Prod.ext rfl (Subtype.ext <| LinearMap.ext fun m₃ => mul_add _ _ _)) - fun c m a => Prod.ext rfl (Subtype.ext <| LinearMap.ext fun m₃ => mul_smul_comm _ _ _) + (fun _ _ _ => Prod.ext rfl (Subtype.ext <| LinearMap.ext fun _ => mul_add _ _ _)) + fun _ _ _ => Prod.ext rfl (Subtype.ext <| LinearMap.ext fun _ => mul_smul_comm _ _ _) @[simp] private theorem fst_fFold_fFold (m₁ m₂ : M) (x : A × S f) : @@ -177,13 +177,13 @@ private theorem fFold_fFold (m : M) (x : A × S f) : fFold f m (fFold f m x) = Q rw [Algebra.smul_def, f.contract] · ext m₁ change f.bilin _ _ * g m = Q m • g m₁ - refine Submodule.span_induction' ?_ ?_ ?_ ?_ hg + refine Submodule.span_induction ?_ ?_ ?_ ?_ hg · rintro _ ⟨b, m₃, rfl⟩ change f.bilin _ _ * (f.bilin _ _ * b) = Q m • (f.bilin _ _ * b) rw [← smul_mul_assoc, ← mul_assoc, f.contract_mid] · change f.bilin m₁ m * 0 = Q m • (0 : A) -- Porting note: `•` now needs the type of `0` rw [mul_zero, smul_zero] - · rintro x _hx y _hy ihx ihy + · rintro x y _hx _hy ihx ihy rw [LinearMap.add_apply, LinearMap.add_apply, mul_add, smul_add, ihx, ihy] · rintro x hx _c ihx rw [LinearMap.smul_apply, LinearMap.smul_apply, mul_smul_comm, ihx, smul_comm] diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean index d699e29ff8b2d..e9ab3a38b7895 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean @@ -117,7 +117,7 @@ def toEven : CliffordAlgebra Q →ₐ[R] CliffordAlgebra.even (Q' Q) := by theorem toEven_ι (m : M) : (toEven Q (ι Q m) : CliffordAlgebra (Q' Q)) = e0 Q * v Q m := by rw [toEven, CliffordAlgebra.lift_ι_apply] - -- Porting note (#10691): was `rw` + -- Porting note (#11224): was `rw` erw [LinearMap.codRestrict_apply] rw [LinearMap.coe_comp, Function.comp_apply, LinearMap.mulLeft_apply] @@ -152,13 +152,8 @@ def ofEven : CliffordAlgebra.even (Q' Q) →ₐ[R] CliffordAlgebra Q := by theorem ofEven_ι (x y : M × R) : ofEven Q ((even.ι (Q' Q)).bilin x y) = - (ι Q x.1 + algebraMap R _ x.2) * (ι Q y.1 - algebraMap R _ y.2) := by - -- Porting note: entire proof was the term-mode `even.lift_ι (Q' Q) _ x y` - unfold ofEven - lift_lets - intro f - -- TODO: replacing `?_` with `_` takes way longer? - exact @even.lift_ι R (M × R) _ _ _ (Q' Q) _ _ _ ⟨f, ?_, ?_⟩ x y + (ι Q x.1 + algebraMap R _ x.2) * (ι Q y.1 - algebraMap R _ y.2) := + even.lift_ι (Q' Q) _ x y theorem toEven_comp_ofEven : (toEven Q).comp (ofEven Q) = AlgHom.id R _ := even.algHom_ext (Q' Q) <| diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean index e5f6c2be85383..c4d8aeb1a344f 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean @@ -63,7 +63,6 @@ instance evenOdd.gradedMonoid : SetLike.GradedMonoid (evenOdd Q) where /-- A version of `CliffordAlgebra.ι` that maps directly into the graded structure. This is primarily an auxiliary construction used to provide `CliffordAlgebra.gradedAlgebra`. -/ --- Porting note: added `protected` protected def GradedAlgebra.ι : M →ₗ[R] ⨁ i : ZMod 2, evenOdd Q i := DirectSum.lof R (ZMod 2) (fun i => ↥(evenOdd Q i)) 1 ∘ₗ (ι Q).codRestrict _ (ι_mem_evenOdd_one Q) @@ -197,8 +196,8 @@ theorem even_induction {motive : ∀ x, x ∈ evenOdd Q 0 → Prop} motive (ι Q m₁ * ι Q m₂ * x) (zero_add (0 : ZMod 2) ▸ SetLike.mul_mem_graded (ι_mul_ι_mem_evenOdd_zero Q m₁ m₂) hx)) (x : CliffordAlgebra Q) (hx : x ∈ evenOdd Q 0) : motive x hx := by - refine evenOdd_induction _ _ (motive := motive) (fun rx => ?_) add ι_mul_ι_mul x hx - rintro ⟨r, rfl⟩ + refine evenOdd_induction _ _ (motive := motive) (fun rx h => ?_) add ι_mul_ι_mul x hx + obtain ⟨r, rfl⟩ := Submodule.mem_one.mp h exact algebraMap r /-- To show a property is true on the odd parts, it suffices to show it is true on the @@ -214,8 +213,7 @@ theorem odd_induction {P : ∀ x, x ∈ evenOdd Q 1 → Prop} (zero_add (1 : ZMod 2) ▸ SetLike.mul_mem_graded (ι_mul_ι_mem_evenOdd_zero Q m₁ m₂) hx)) (x : CliffordAlgebra Q) (hx : x ∈ evenOdd Q 1) : P x hx := by refine evenOdd_induction _ _ (motive := P) (fun ιv => ?_) add ι_mul_ι_mul x hx - -- Porting note: was `simp_rw [ZMod.val_one, pow_one]`, lean4#1926 - intro h; rw [ZMod.val_one, pow_one] at h; revert h + simp_rw [ZMod.val_one, pow_one] rintro ⟨v, rfl⟩ exact ι v diff --git a/Mathlib/LinearAlgebra/DFinsupp.lean b/Mathlib/LinearAlgebra/DFinsupp.lean index 7f631f041c8c3..5da7fbab05ab4 100644 --- a/Mathlib/LinearAlgebra/DFinsupp.lean +++ b/Mathlib/LinearAlgebra/DFinsupp.lean @@ -11,17 +11,17 @@ import Mathlib.LinearAlgebra.LinearIndependent # Properties of the module `Π₀ i, M i` Given an indexed collection of `R`-modules `M i`, the `R`-module structure on `Π₀ i, M i` -is defined in `Data.DFinsupp`. +is defined in `Mathlib.Data.DFinsupp.Basic`. In this file we define `LinearMap` versions of various maps: * `DFinsupp.lsingle a : M →ₗ[R] Π₀ i, M i`: `DFinsupp.single a` as a linear map; -* `DFinsupp.lmk s : (Π i : (↑s : Set ι), M i) →ₗ[R] Π₀ i, M i`: `DFinsupp.single a` as a linear map; +* `DFinsupp.lmk s : (Π i : (↑s : Set ι), M i) →ₗ[R] Π₀ i, M i`: `DFinsupp.mk` as a linear map; * `DFinsupp.lapply i : (Π₀ i, M i) →ₗ[R] M`: the map `fun f ↦ f i` as a linear map; -* `DFinsupp.lsum`: `DFinsupp.sum` or `DFinsupp.liftAddHom` as a `LinearMap`; +* `DFinsupp.lsum`: `DFinsupp.sum` or `DFinsupp.liftAddHom` as a `LinearMap`. ## Implementation notes @@ -62,7 +62,8 @@ theorem lhom_ext ⦃φ ψ : (Π₀ i, M i) →ₗ[R] N⦄ (h : ∀ i x, φ (sing /-- Two `R`-linear maps from `Π₀ i, M i` which agree on each `single i x` agree everywhere. See note [partially-applied ext lemmas]. -After apply this lemma, if `M = R` then it suffices to verify `φ (single a 1) = ψ (single a 1)`. -/ +After applying this lemma, if `M = R` then it suffices to verify +`φ (single a 1) = ψ (single a 1)`. -/ @[ext 1100] theorem lhom_ext' ⦃φ ψ : (Π₀ i, M i) →ₗ[R] N⦄ (h : ∀ i, φ.comp (lsingle i) = ψ.comp (lsingle i)) : φ = ψ := @@ -89,6 +90,14 @@ def lapply (i : ι) : (Π₀ i, M i) →ₗ[R] M i where theorem lapply_apply (i : ι) (f : Π₀ i, M i) : (lapply i : (Π₀ i, M i) →ₗ[R] _) f = f i := rfl +@[simp] +theorem lapply_comp_lsingle_same [DecidableEq ι] (i : ι) : + lapply i ∘ₗ lsingle i = (.id : M i →ₗ[R] M i) := by ext; simp + +@[simp] +theorem lapply_comp_lsingle_of_ne [DecidableEq ι] (i i' : ι) (h : i ≠ i') : + lapply i ∘ₗ lsingle i' = (0 : M i' →ₗ[R] M i) := by ext; simp [h.symm] + section Lsum -- Porting note: Unclear how true these docstrings are in lean 4 @@ -319,7 +328,7 @@ theorem mem_iSup_iff_exists_dfinsupp (p : ι → Submodule R N) (x : N) : See also `Submodule.mem_iSup_iff_exists_finsupp`. -/ theorem mem_iSup_iff_exists_dfinsupp' (p : ι → Submodule R N) [∀ (i) (x : p i), Decidable (x ≠ 0)] - (x : N) : x ∈ iSup p ↔ ∃ f : Π₀ i, p i, (f.sum fun i xi => ↑xi) = x := by + (x : N) : x ∈ iSup p ↔ ∃ f : Π₀ i, p i, (f.sum fun _ xi => ↑xi) = x := by rw [mem_iSup_iff_exists_dfinsupp] simp_rw [DFinsupp.lsum_apply_apply, DFinsupp.sumAddHom_apply, LinearMap.toAddMonoidHom_coe, coe_subtype] @@ -531,18 +540,13 @@ namespace LinearMap section AddCommMonoid -variable {R : Type*} {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} {R₄ : Type*} -variable {S : Type*} -variable {K : Type*} {K₂ : Type*} -variable {M : Type*} {M' : Type*} {M₁ : Type*} {M₂ : Type*} {M₃ : Type*} {M₄ : Type*} -variable {N : Type*} {N₂ : Type*} +variable {R : Type*} {R₂ : Type*} +variable {M : Type*} {M₂ : Type*} variable {ι : Type*} -variable {V : Type*} {V₂ : Type*} -variable [Semiring R] [Semiring R₂] [Semiring R₃] -variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} -variable [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] -variable [Module R M] [Module R₂ M₂] [Module R₃ M₃] +variable [Semiring R] [Semiring R₂] +variable [AddCommMonoid M] [AddCommMonoid M₂] +variable {σ₁₂ : R →+* R₂} +variable [Module R M] [Module R₂ M₂] open Submodule diff --git a/Mathlib/LinearAlgebra/Determinant.lean b/Mathlib/LinearAlgebra/Determinant.lean index 8f8edaca16e32..c33431bdc1398 100644 --- a/Mathlib/LinearAlgebra/Determinant.lean +++ b/Mathlib/LinearAlgebra/Determinant.lean @@ -207,7 +207,7 @@ theorem det_toLin' (f : Matrix ι ι R) : LinearMap.det (Matrix.toLin' f) = Matr /-- To show `P (LinearMap.det f)` it suffices to consider `P (Matrix.det (toMatrix _ _ f))` and `P 1`. -/ --- @[elab_as_elim] -- Porting note: This attr can't be applied. +@[elab_as_elim] theorem det_cases [DecidableEq M] {P : A → Prop} (f : M →ₗ[A] M) (hb : ∀ (s : Finset M) (b : Basis s A M), P (Matrix.det (toMatrix b b f))) (h1 : P 1) : P (LinearMap.det f) := by @@ -599,9 +599,7 @@ theorem Basis.det_unitsSMul (e : Basis ι R M) (w : ι → Rˣ) : (↑(∏ i, w i)⁻¹ : R) • Matrix.det fun i j => e.repr (f j) i simp only [e.repr_unitsSMul] convert Matrix.det_mul_column (fun i => (↑(w i)⁻¹ : R)) fun i j => e.repr (f j) i - -- porting note (#10745): was `simp [← Finset.prod_inv_distrib]` - simp only [← Finset.prod_inv_distrib] - norm_cast + simp [← Finset.prod_inv_distrib] /-- The determinant of a basis constructed by `unitsSMul` is the product of the given units. -/ @[simp] diff --git a/Mathlib/LinearAlgebra/Dimension/Constructions.lean b/Mathlib/LinearAlgebra/Dimension/Constructions.lean index 9a7b997644973..fb4695c2deb46 100644 --- a/Mathlib/LinearAlgebra/Dimension/Constructions.lean +++ b/Mathlib/LinearAlgebra/Dimension/Constructions.lean @@ -183,27 +183,42 @@ theorem rank_directSum {ι : Type v} (M : ι → Type w) [∀ i : ι, AddCommGro let b : Basis _ R (⨁ i, M i) := DFinsupp.basis fun i => B i simp [← b.mk_eq_rank'', fun i => (B i).mk_eq_rank''] -/-- If `m` and `n` are `Fintype`, the rank of `m × n` matrices is `(#m).lift * (#n).lift`. -/ +/-- If `m` and `n` are finite, the rank of `m × n` matrices over a module `M` is +`(#m).lift * (#n).lift * rank R M`. -/ @[simp] +theorem rank_matrix_module (m : Type w) (n : Type w') [Finite m] [Finite n] : + Module.rank R (Matrix m n M) = + lift.{max v w'} #m * lift.{max v w} #n * lift.{max w w'} (Module.rank R M) := by + cases nonempty_fintype m + cases nonempty_fintype n + obtain ⟨I, b⟩ := Module.Free.exists_basis (R := R) (M := M) + rw [← (b.matrix m n).mk_eq_rank''] + simp only [mk_prod, lift_mul, lift_lift, ← mul_assoc, b.mk_eq_rank''] + + +/-- If `m` and `n` are finite and lie in the same universe, the rank of `m × n` matrices over a +module `M` is `(#m * #n).lift * rank R M`. -/ +@[simp high] +theorem rank_matrix_module' (m n : Type w) [Finite m] [Finite n] : + Module.rank R (Matrix m n M) = + lift.{max v} (#m * #n) * lift.{w} (Module.rank R M) := by + rw [rank_matrix_module, lift_mul, lift_umax.{w, v}] + +/-- If `m` and `n` are finite, the rank of `m × n` matrices is `(#m).lift * (#n).lift`. -/ theorem rank_matrix (m : Type v) (n : Type w) [Finite m] [Finite n] : Module.rank R (Matrix m n R) = Cardinal.lift.{max v w u, v} #m * Cardinal.lift.{max v w u, w} #n := by - cases nonempty_fintype m - cases nonempty_fintype n - have h := (Matrix.stdBasis R m n).mk_eq_rank - rw [← lift_lift.{max v w u, max v w}, lift_inj] at h - simpa using h.symm + rw [rank_matrix_module, rank_self, lift_one, mul_one, ← lift_lift.{v, max u w}, lift_id, + ← lift_lift.{w, max u v}, lift_id] -/-- If `m` and `n` are `Fintype` that lie in the same universe, the rank of `m × n` matrices is +/-- If `m` and `n` are finite and lie in the same universe, the rank of `m × n` matrices is `(#n * #m).lift`. -/ -@[simp high] theorem rank_matrix' (m n : Type v) [Finite m] [Finite n] : Module.rank R (Matrix m n R) = Cardinal.lift.{u} (#m * #n) := by rw [rank_matrix, lift_mul, lift_umax.{v, u}] -/-- If `m` and `n` are `Fintype` that lie in the same universe as `R`, the rank of `m × n` matrices +/-- If `m` and `n` are finite and lie in the same universe as `R`, the rank of `m × n` matrices is `# m * # n`. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem rank_matrix'' (m n : Type u) [Finite m] [Finite n] : Module.rank R (Matrix m n R) = #m * #n := by simp @@ -229,10 +244,10 @@ theorem finrank_directSum {ι : Type v} [Fintype ι] (M : ι → Type w) [∀ i simp only [finrank, fun i => rank_eq_card_chooseBasisIndex R (M i), rank_directSum, ← mk_sigma, mk_toNat_eq_card, card_sigma] -/-- If `m` and `n` are `Fintype`, the finrank of `m × n` matrices is - `(Fintype.card m) * (Fintype.card n)`. -/ +/-- If `m` and `n` are `Fintype`, the finrank of `m × n` matrices over a module `M` is + `(Fintype.card m) * (Fintype.card n) * finrank R M`. -/ theorem finrank_matrix (m n : Type*) [Fintype m] [Fintype n] : - finrank R (Matrix m n R) = card m * card n := by simp [finrank] + finrank R (Matrix m n M) = card m * card n * finrank R M := by simp [finrank] end Module @@ -298,7 +313,6 @@ theorem Module.finrank_fintype_fun_eq_card : finrank R (η → R) = Fintype.card finrank_eq_of_rank_eq rank_fun' /-- The vector space of functions on `Fin n` has finrank equal to `n`. -/ --- @[simp] -- Porting note (#10618): simp already proves this theorem Module.finrank_fin_fun {n : ℕ} : finrank R (Fin n → R) = n := by simp variable {R} @@ -469,6 +483,12 @@ theorem span_lt_top_of_card_lt_finrank {s : Set M} [Fintype s] (card_lt : s.toFinset.card < finrank R M) : span R s < ⊤ := lt_top_of_finrank_lt_finrank (lt_of_le_of_lt (finrank_span_le_card _) card_lt) +lemma finrank_le_of_span_eq_top {ι : Type*} [Fintype ι] {v : ι → M} + (hv : Submodule.span R (Set.range v) = ⊤) : finrank R M ≤ Fintype.card ι := by + classical + rw [← finrank_top, ← hv] + exact (finrank_span_le_card _).trans (by convert Fintype.card_range_le v; rw [Set.toFinset_card]) + end Span section SubalgebraRank diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean index 90c82db1cfcc3..8cce5dddc805b 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finite.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Module.Torsion import Mathlib.SetTheory.Cardinal.Cofinality import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.LinearAlgebra.Dimension.StrongRankCondition +import Mathlib.LinearAlgebra.Dimension.Constructions /-! # Conditions for rank to be finite @@ -232,7 +233,7 @@ lemma exists_finset_linearIndependent_of_le_finrank {n : ℕ} (hn : n ≤ finran · rw [le_zero_iff.mp (hn.trans_eq h)] exact ⟨∅, rfl, by convert linearIndependent_empty R M using 2 <;> aesop⟩ exact exists_finset_linearIndependent_of_le_rank - ((natCast_le.mpr hn).trans_eq (cast_toNat_of_lt_aleph0 (toNat_ne_zero.mp h).2)) + ((Nat.cast_le.mpr hn).trans_eq (cast_toNat_of_lt_aleph0 (toNat_ne_zero.mp h).2)) lemma exists_linearIndependent_of_le_finrank {n : ℕ} (hn : n ≤ finrank R M) : ∃ f : Fin n → M, LinearIndependent R f := @@ -426,6 +427,14 @@ theorem Module.finrank_zero_iff [NoZeroSMulDivisors R M] : rw [← rank_zero_iff (R := R), ← finrank_eq_rank] norm_cast +/-- Similar to `rank_quotient_add_rank_le` but for `finrank` and a finite `M`. -/ +lemma Module.finrank_quotient_add_finrank_le (N : Submodule R M) : + finrank R (M ⧸ N) + finrank R N ≤ finrank R M := by + haveI := nontrivial_of_invariantBasisNumber R + have := rank_quotient_add_rank_le N + rw [← finrank_eq_rank R M, ← finrank_eq_rank R, ← N.finrank_eq_rank] at this + exact mod_cast this + end StrongRankCondition theorem Module.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R M = 0) : @@ -454,7 +463,7 @@ theorem Submodule.rank_eq_zero [Nontrivial R] [NoZeroSMulDivisors R M] {S : Subm theorem Submodule.finrank_eq_zero [StrongRankCondition R] [NoZeroSMulDivisors R M] {S : Submodule R M} [Module.Finite R S] : finrank R S = 0 ↔ S = ⊥ := by - rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] + rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Nat.cast_inj] @[simp] lemma Submodule.one_le_finrank_iff [StrongRankCondition R] [NoZeroSMulDivisors R M] diff --git a/Mathlib/LinearAlgebra/Dimension/Finrank.lean b/Mathlib/LinearAlgebra/Dimension/Finrank.lean index 69668ef8b667a..b702b49f38f5c 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finrank.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finrank.lean @@ -48,6 +48,9 @@ Defined by convention to be `0` if the space has infinite rank. For a vector space `M` over a field `R`, this is the same as the finite dimension of `M` over `R`. + +Note that it is possible to have `M` with `¬(Module.Finite R M)` but `finrank R M ≠ 0`, for example +`ℤ × ℚ/ℤ` has `finrank` equal to `1`. -/ noncomputable def finrank (R M : Type*) [Semiring R] [AddCommGroup M] [Module R M] : ℕ := Cardinal.toNat (Module.rank R M) diff --git a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean index 17254b66084e3..212770aa65383 100644 --- a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean +++ b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean @@ -202,16 +202,16 @@ there is some `v : V` so every vector is a multiple of `v`. -/ theorem finrank_le_one_iff [Module.Free K V] [Module.Finite K V] : finrank K V ≤ 1 ↔ ∃ v : V, ∀ w : V, ∃ c : K, c • v = w := by - rw [← rank_le_one_iff, ← finrank_eq_rank, ← natCast_le, Nat.cast_one] + rw [← rank_le_one_iff, ← finrank_eq_rank, Nat.cast_le_one] theorem Submodule.finrank_le_one_iff_isPrincipal (W : Submodule K V) [Module.Free K W] [Module.Finite K W] : finrank K W ≤ 1 ↔ W.IsPrincipal := by - rw [← W.rank_le_one_iff_isPrincipal, ← finrank_eq_rank, ← natCast_le, Nat.cast_one] + rw [← W.rank_le_one_iff_isPrincipal, ← finrank_eq_rank, Nat.cast_le_one] theorem Module.finrank_le_one_iff_top_isPrincipal [Module.Free K V] [Module.Finite K V] : finrank K V ≤ 1 ↔ (⊤ : Submodule K V).IsPrincipal := by - rw [← Module.rank_le_one_iff_top_isPrincipal, ← finrank_eq_rank, ← natCast_le, Nat.cast_one] + rw [← Module.rank_le_one_iff_top_isPrincipal, ← finrank_eq_rank, Nat.cast_le_one] variable (K V) in theorem lift_cardinal_mk_eq_lift_cardinal_mk_field_pow_lift_rank [Module.Free K V] @@ -271,7 +271,8 @@ theorem rank_eq_one_iff [Nontrivial E] [Module.Free F S] : Module.rank F S = 1 obtain ⟨κ, b⟩ := Module.Free.exists_basis (R := F) (M := (⊥ : Subalgebra F E)) refine le_antisymm ?_ ?_ · have := lift_rank_range_le (Algebra.linearMap F E) - rwa [← one_eq_range, rank_self, lift_one, lift_le_one_iff] at this + rwa [← one_eq_range, rank_self, lift_one, lift_le_one_iff, + ← Algebra.toSubmodule_bot, rank_toSubmodule] at this · by_contra H rw [not_le, lt_one_iff_zero] at H haveI := mk_eq_zero_iff.1 (H ▸ b.mk_eq_rank'') diff --git a/Mathlib/LinearAlgebra/Dimension/LinearMap.lean b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean index ca2cb869a8ec5..d9f144980e339 100644 --- a/Mathlib/LinearAlgebra/Dimension/LinearMap.lean +++ b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean @@ -3,6 +3,7 @@ Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ +import Mathlib.Algebra.Module.Projective import Mathlib.LinearAlgebra.Dimension.DivisionRing import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition diff --git a/Mathlib/LinearAlgebra/Dimension/Localization.lean b/Mathlib/LinearAlgebra/Dimension/Localization.lean index b6445fadfe529..594d62bba3e1d 100644 --- a/Mathlib/LinearAlgebra/Dimension/Localization.lean +++ b/Mathlib/LinearAlgebra/Dimension/Localization.lean @@ -120,7 +120,7 @@ end CommRing section Ring -variable {R} [Ring R] [IsDomain R] (S : Submonoid R) +variable {R} [Ring R] [IsDomain R] /-- A domain that is not (left) Ore is of infinite rank. See [cohn_1995] Proposition 1.3.6 -/ diff --git a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean index 2e6cb6ba25096..79f9779cf6271 100644 --- a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean +++ b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean @@ -24,7 +24,7 @@ See `nonempty_oreSet_of_strongRankCondition` for a start. -/ universe u v -open Function Set Cardinal +open Function Set Cardinal Submodule LinearMap variable {R} {M M₁ M₂ M₃ : Type u} {M' : Type v} [Ring R] variable [AddCommGroup M] [AddCommGroup M₁] [AddCommGroup M₂] [AddCommGroup M₃] [AddCommGroup M'] @@ -49,7 +49,7 @@ class HasRankNullity (R : Type v) [inst : Ring R] : Prop where variable [HasRankNullity.{u} R] -lemma rank_quotient_add_rank (N : Submodule R M) : +lemma Submodule.rank_quotient_add_rank (N : Submodule R M) : Module.rank R (M ⧸ N) + Module.rank R N = Module.rank R M := HasRankNullity.rank_quotient_add_rank N @@ -66,24 +66,24 @@ theorem nontrivial_of_hasRankNullity : Nontrivial R := by attribute [local instance] nontrivial_of_hasRankNullity -theorem lift_rank_range_add_rank_ker (f : M →ₗ[R] M') : +theorem LinearMap.lift_rank_range_add_rank_ker (f : M →ₗ[R] M') : lift.{u} (Module.rank R (LinearMap.range f)) + lift.{v} (Module.rank R (LinearMap.ker f)) = lift.{v} (Module.rank R M) := by haveI := fun p : Submodule R M => Classical.decEq (M ⧸ p) rw [← f.quotKerEquivRange.lift_rank_eq, ← lift_add, rank_quotient_add_rank] /-- The **rank-nullity theorem** -/ -theorem rank_range_add_rank_ker (f : M →ₗ[R] M₁) : +theorem LinearMap.rank_range_add_rank_ker (f : M →ₗ[R] M₁) : Module.rank R (LinearMap.range f) + Module.rank R (LinearMap.ker f) = Module.rank R M := by haveI := fun p : Submodule R M => Classical.decEq (M ⧸ p) rw [← f.quotKerEquivRange.rank_eq, rank_quotient_add_rank] -theorem lift_rank_eq_of_surjective {f : M →ₗ[R] M'} (h : Surjective f) : +theorem LinearMap.lift_rank_eq_of_surjective {f : M →ₗ[R] M'} (h : Surjective f) : lift.{v} (Module.rank R M) = lift.{u} (Module.rank R M') + lift.{v} (Module.rank R (LinearMap.ker f)) := by rw [← lift_rank_range_add_rank_ker f, ← rank_range_of_surjective f h] -theorem rank_eq_of_surjective {f : M →ₗ[R] M₁} (h : Surjective f) : +theorem LinearMap.rank_eq_of_surjective {f : M →ₗ[R] M₁} (h : Surjective f) : Module.rank R M = Module.rank R M₁ + Module.rank R (LinearMap.ker f) := by rw [← rank_range_add_rank_ker f, ← rank_range_of_surjective f h] @@ -92,7 +92,7 @@ theorem exists_linearIndependent_of_lt_rank [StrongRankCondition R] ∃ t, s ⊆ t ∧ #t = Module.rank R M ∧ LinearIndependent (ι := t) R Subtype.val := by obtain ⟨t, ht, ht'⟩ := exists_set_linearIndependent R (M ⧸ Submodule.span R s) choose sec hsec using Submodule.Quotient.mk_surjective (Submodule.span R s) - have hsec' : Submodule.Quotient.mk ∘ sec = id := funext hsec + have hsec' : Submodule.Quotient.mk ∘ sec = _root_.id := funext hsec have hst : Disjoint s (sec '' t) := by rw [Set.disjoint_iff] rintro _ ⟨hxs, ⟨x, hxt, rfl⟩⟩ @@ -140,8 +140,8 @@ theorem exists_linearIndependent_pair_of_one_lt_rank [StrongRankCondition R] rw [this] at hy exact ⟨y, hy⟩ -theorem exists_smul_not_mem_of_rank_lt {N : Submodule R M} (h : Module.rank R N < Module.rank R M) : - ∃ m : M, ∀ r : R, r ≠ 0 → r • m ∉ N := by +theorem Submodule.exists_smul_not_mem_of_rank_lt {N : Submodule R M} + (h : Module.rank R N < Module.rank R M) : ∃ m : M, ∀ r : R, r ≠ 0 → r • m ∉ N := by have : Module.rank R (M ⧸ N) ≠ 0 := by intro e rw [← rank_quotient_add_rank N, e, zero_add] at h @@ -196,4 +196,38 @@ theorem exists_linearIndependent_pair_of_one_lt_finrank [NoZeroSMulDivisors R M] ∃ y, LinearIndependent R ![x, y] := exists_linearIndependent_pair_of_one_lt_rank (one_lt_rank_of_one_lt_finrank h) hx +/-- Rank-nullity theorem using `finrank`. -/ +lemma Submodule.finrank_quotient_add_finrank [Module.Finite R M] (N : Submodule R M) : + finrank R (M ⧸ N) + finrank R N = finrank R M := by + rw [← Nat.cast_inj (R := Cardinal), Module.finrank_eq_rank, Nat.cast_add, Module.finrank_eq_rank, + Submodule.finrank_eq_rank] + exact HasRankNullity.rank_quotient_add_rank _ + + +/-- Rank-nullity theorem using `finrank` and subtraction. -/ +lemma Submodule.finrank_quotient [Module.Finite R M] {S : Type*} [Ring S] [SMul R S] [Module S M] + [IsScalarTower R S M] (N : Submodule S M) : finrank R (M ⧸ N) = finrank R M - finrank R N := by + rw [← (N.restrictScalars R).finrank_quotient_add_finrank] + exact Nat.eq_sub_of_add_eq rfl + end Finrank + +section + +open Submodule Module + +variable [StrongRankCondition R] [Module.Finite R M] + +lemma Submodule.exists_of_finrank_lt (N : Submodule R M) (h : finrank R N < finrank R M) : + ∃ m : M, ∀ r : R, r ≠ 0 → r • m ∉ N := by + obtain ⟨s, hs, hs'⟩ := + exists_finset_linearIndependent_of_le_finrank (R := R) (M := M ⧸ N) le_rfl + obtain ⟨v, hv⟩ : s.Nonempty := by rwa [Finset.nonempty_iff_ne_empty, ne_eq, ← Finset.card_eq_zero, + hs, finrank_quotient, tsub_eq_zero_iff_le, not_le] + obtain ⟨v, rfl⟩ := N.mkQ_surjective v + refine ⟨v, fun r hr ↦ mt ?_ hr⟩ + have := linearIndependent_iff.mp hs' (Finsupp.single ⟨_, hv⟩ r) + rwa [Finsupp.linearCombination_single, Finsupp.single_eq_zero, ← LinearMap.map_smul, + Submodule.mkQ_apply, Submodule.Quotient.mk_eq_zero] at this + +end diff --git a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean index 12001f79238c5..a84c1fb77e7b2 100644 --- a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean +++ b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean @@ -64,7 +64,7 @@ theorem mk_eq_mk_of_basis (v : Basis ι R M) (v' : Basis ι' R M) : cases nonempty_fintype ι' -- We clean up a little: rw [Cardinal.mk_fintype, Cardinal.mk_fintype] - simp only [Cardinal.lift_natCast, Cardinal.natCast_inj] + simp only [Cardinal.lift_natCast, Nat.cast_inj] -- Now we can use invariant basis number to show they have the same cardinality. apply card_eq_of_linearEquiv R exact @@ -122,7 +122,7 @@ theorem basis_le_span' {ι : Type*} (b : Basis ι R M) {w : Set M} [Fintype w] ( haveI := basis_finite_of_finite_spans w (toFinite _) s b cases nonempty_fintype ι rw [Cardinal.mk_fintype ι] - simp only [Cardinal.natCast_le] + simp only [Nat.cast_le] exact Basis.le_span'' b s -- Note that if `R` satisfies the strong rank condition, @@ -207,7 +207,7 @@ theorem linearIndependent_le_span' {ι : Type*} (v : ι → M) (i : LinearIndepe haveI : Finite ι := i.finite_of_le_span_finite v w s letI := Fintype.ofFinite ι rw [Cardinal.mk_fintype] - simp only [Cardinal.natCast_le] + simp only [Nat.cast_le] exact linearIndependent_le_span_aux' v i w s /-- If `R` satisfies the strong rank condition, @@ -430,11 +430,26 @@ theorem rank_lt_aleph0 [Module.Finite R M] : Module.rank R M < ℵ₀ := by refine (ciSup_le' fun i => ?_).trans_lt (nat_lt_aleph0 S.card) exact linearIndependent_le_span_finset _ i.prop S hS +noncomputable instance {R M : Type*} [DivisionRing R] [AddCommGroup M] [Module R M] + {s t : Set M} [Module.Finite R (span R t)] + (hs : LinearIndependent R ((↑) : s → M)) (hst : s ⊆ t) : + Fintype (hs.extend hst) := by + refine Classical.choice (Cardinal.lt_aleph0_iff_fintype.1 ?_) + rw [← rank_span_set (hs.linearIndependent_extend hst), hs.span_extend_eq_span] + exact Module.rank_lt_aleph0 .. + /-- If `M` is finite, `finrank M = rank M`. -/ @[simp] theorem finrank_eq_rank [Module.Finite R M] : ↑(finrank R M) = Module.rank R M := by rw [Module.finrank, cast_toNat_of_lt_aleph0 (rank_lt_aleph0 R M)] +/-- If `M` is finite, then `finrank N = rank N` for all `N : Submodule M`. Note that +such an `N` need not be finitely generated. -/ +protected theorem _root_.Submodule.finrank_eq_rank [Module.Finite R M] (N : Submodule R M) : + finrank R N = Module.rank R N := by + rw [finrank, Cardinal.cast_toNat_of_lt_aleph0] + exact lt_of_le_of_lt (Submodule.rank_le N) (rank_lt_aleph0 R M) + end Module open Module diff --git a/Mathlib/LinearAlgebra/DirectSum/TensorProduct.lean b/Mathlib/LinearAlgebra/DirectSum/TensorProduct.lean index 58b0cd735d196..1a6c8831e3b9d 100644 --- a/Mathlib/LinearAlgebra/DirectSum/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/DirectSum/TensorProduct.lean @@ -117,9 +117,9 @@ protected def directSum : def directSumLeft : (⨁ i₁, M₁ i₁) ⊗[R] M₂' ≃ₗ[R] ⨁ i, M₁ i ⊗[R] M₂' := LinearEquiv.ofLinear (lift <| - DirectSum.toModule R _ _ fun i => + DirectSum.toModule R _ _ fun _ => (mk R _ _).compr₂ <| DirectSum.lof R ι₁ (fun i => M₁ i ⊗[R] M₂') _) - (DirectSum.toModule R _ _ fun i => rTensor _ (DirectSum.lof R ι₁ _ _)) + (DirectSum.toModule R _ _ fun _ => rTensor _ (DirectSum.lof R ι₁ _ _)) (DirectSum.linearMap_ext R fun i => TensorProduct.ext <| LinearMap.ext₂ fun m₁ m₂ => by diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 734efc1dd1911..285e6bf70576b 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -604,6 +604,28 @@ def evalEquiv : M ≃ₗ[R] Dual R (Dual R M) := (evalEquiv R M).symm.dualMap = Dual.eval R (Dual R M) := by ext; simp +@[simp] lemma Dual.eval_comp_comp_evalEquiv_eq + {M' : Type*} [AddCommGroup M'] [Module R M'] {f : M →ₗ[R] M'} : + Dual.eval R M' ∘ₗ f ∘ₗ (evalEquiv R M).symm = f.dualMap.dualMap := by + ext x g + simp only [dualMap_apply, coe_comp, LinearEquiv.coe_coe, Function.comp_apply, Dual.eval_apply] + rw [← apply_evalEquiv_symm_apply, dualMap_apply] + +lemma dualMap_dualMap_eq_iff_of_injective + {M' : Type*} [AddCommGroup M'] [Module R M'] {f g : M →ₗ[R] M'} + (h : Injective (Dual.eval R M')) : + f.dualMap.dualMap = g.dualMap.dualMap ↔ f = g := by + simp only [← Dual.eval_comp_comp_evalEquiv_eq] + refine ⟨ fun hfg => ?_, fun a ↦ congrArg (Dual.eval R M').comp + (congrFun (congrArg LinearMap.comp a) (evalEquiv R M).symm.toLinearMap) ⟩ + rw [propext (cancel_left h), LinearEquiv.eq_comp_toLinearMap_iff] at hfg + exact hfg + +@[simp] lemma dualMap_dualMap_eq_iff + {M' : Type*} [AddCommGroup M'] [Module R M'] [IsReflexive R M'] {f g : M →ₗ[R] M'} : + f.dualMap.dualMap = g.dualMap.dualMap ↔ f = g := + dualMap_dualMap_eq_iff_of_injective _ _ (bijective_dual_eval R M').injective + /-- The dual of a reflexive module is reflexive. -/ instance Dual.instIsReflecive : IsReflexive R (Dual R M) := ⟨by simpa only [← symm_dualMap_evalEquiv] using (evalEquiv R M).dualMap.symm.bijective⟩ @@ -690,6 +712,61 @@ theorem exists_dual_map_eq_bot_of_lt_top (hp : p < ⊤) (hp' : Free R (M ⧸ p)) obtain ⟨f, hf, hf'⟩ := p.exists_dual_map_eq_bot_of_nmem hx hp' exact ⟨f, by aesop, hf'⟩ +/-- Consider a reflexive module and a set `s` of linear forms. If for any `z ≠ 0` there exists +`f ∈ s` such that `f z ≠ 0`, then `s` spans the whole dual space. -/ +theorem span_eq_top_of_ne_zero [IsReflexive R M] + {s : Set (M →ₗ[R] R)} [Free R ((M →ₗ[R] R) ⧸ (span R s))] + (h : ∀ z ≠ 0, ∃ f ∈ s, f z ≠ 0) : span R s = ⊤ := by + by_contra! hn + obtain ⟨φ, φne, hφ⟩ := exists_dual_map_eq_bot_of_lt_top hn.lt_top inferInstance + let φs := (evalEquiv R M).symm φ + have this f (hf : f ∈ s) : f φs = 0 := by + rw [← mem_bot R, ← hφ, mem_map] + exact ⟨f, subset_span hf, (apply_evalEquiv_symm_apply R M f φ).symm⟩ + obtain ⟨x, xs, hx⟩ := h φs (by simp [φne, φs]) + exact hx <| this x xs + +variable {ι 𝕜 E : Type*} [Field 𝕜] [AddCommGroup E] [Module 𝕜 E] + +open LinearMap Set FiniteDimensional + +theorem _root_.FiniteDimensional.mem_span_of_iInf_ker_le_ker [FiniteDimensional 𝕜 E] + {L : ι → E →ₗ[𝕜] 𝕜} {K : E →ₗ[𝕜] 𝕜} + (h : ⨅ i, LinearMap.ker (L i) ≤ ker K) : K ∈ span 𝕜 (range L) := by + by_contra hK + rcases exists_dual_map_eq_bot_of_nmem hK inferInstance with ⟨φ, φne, hφ⟩ + let φs := (Module.evalEquiv 𝕜 E).symm φ + have : K φs = 0 := by + refine h <| (Submodule.mem_iInf _).2 fun i ↦ (mem_bot 𝕜).1 ?_ + rw [← hφ, Submodule.mem_map] + exact ⟨L i, Submodule.subset_span ⟨i, rfl⟩, (apply_evalEquiv_symm_apply 𝕜 E _ φ).symm⟩ + simp only [apply_evalEquiv_symm_apply, φs, φne] at this + +/-- Given some linear forms $L_1, ..., L_n, K$ over a vector space $E$, if +$\bigcap_{i=1}^n \mathrm{ker}(L_i) \subseteq \mathrm{ker}(K)$, then $K$ is in the space generated +by $L_1, ..., L_n$. -/ +theorem _root_.mem_span_of_iInf_ker_le_ker [Finite ι] {L : ι → E →ₗ[𝕜] 𝕜} {K : E →ₗ[𝕜] 𝕜} + (h : ⨅ i, ker (L i) ≤ ker K) : K ∈ span 𝕜 (range L) := by + have _ := Fintype.ofFinite ι + let φ : E →ₗ[𝕜] ι → 𝕜 := LinearMap.pi L + let p := ⨅ i, ker (L i) + have p_eq : p = ker φ := (ker_pi L).symm + let ψ : (E ⧸ p) →ₗ[𝕜] ι → 𝕜 := p.liftQ φ p_eq.le + have _ : FiniteDimensional 𝕜 (E ⧸ p) := of_injective ψ (ker_eq_bot.1 (ker_liftQ_eq_bot' p φ p_eq)) + let L' i : (E ⧸ p) →ₗ[𝕜] 𝕜 := p.liftQ (L i) (iInf_le _ i) + let K' : (E ⧸ p) →ₗ[𝕜] 𝕜 := p.liftQ K h + have : ⨅ i, ker (L' i) ≤ ker K' := by + simp_rw [← ker_pi, L', pi_liftQ_eq_liftQ_pi, ker_liftQ_eq_bot' p φ p_eq] + exact bot_le + obtain ⟨c, hK'⟩ := + (mem_span_range_iff_exists_fun 𝕜).1 (FiniteDimensional.mem_span_of_iInf_ker_le_ker this) + refine (mem_span_range_iff_exists_fun 𝕜).2 ⟨c, ?_⟩ + conv_lhs => enter [2]; intro i; rw [← p.liftQ_mkQ (L i) (iInf_le _ i)] + 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] + end Submodule section DualBases @@ -1187,7 +1264,7 @@ instance (W : Submodule R M) : FunLike (W.dualAnnihilator) M R where coe φ := φ.val coe_injective' φ ψ h := by ext - simp only [Function.funext_iff] at h + simp only [funext_iff] at h exact h _ @[simp] diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index e2e7aa9fcb4c9..05c1324d366e9 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -58,29 +58,31 @@ open Module Set variable {K R : Type v} {V M : Type w} [CommRing R] [AddCommGroup M] [Module R M] [Field K] [AddCommGroup V] [Module K V] -/-- The submodule `unifEigenspace f μ k` for a linear map `f`, a scalar `μ`, -and a number `k : ℕ∞` is the kernel of `(f - μ • id) ^ k` if `k` is a natural number, -or the union of all these kernels if `k = ∞`. -/ -def unifEigenspace (f : End R M) (μ : R) : ℕ∞ →o Submodule R M where +/-- The submodule `genEigenspace f μ k` for a linear map `f`, a scalar `μ`, +and a number `k : ℕ∞` is the kernel of `(f - μ • id) ^ k` if `k` is a natural number +(see Def 8.10 of [axler2015]), or the union of all these kernels if `k = ∞`. +A generalized eigenspace for some exponent `k` is contained in +the generalized eigenspace for exponents larger than `k`. -/ +def genEigenspace (f : End R M) (μ : R) : ℕ∞ →o Submodule R M where toFun k := ⨆ l : ℕ, ⨆ _ : l ≤ k, LinearMap.ker ((f - μ • 1) ^ l) monotone' _ _ hkl := biSup_mono fun _ hi ↦ hi.trans hkl -lemma mem_unifEigenspace {f : End R M} {μ : R} {k : ℕ∞} {x : M} : - x ∈ f.unifEigenspace μ k ↔ ∃ l : ℕ, l ≤ k ∧ x ∈ LinearMap.ker ((f - μ • 1) ^ l) := by +lemma mem_genEigenspace {f : End R M} {μ : R} {k : ℕ∞} {x : M} : + x ∈ f.genEigenspace μ k ↔ ∃ l : ℕ, l ≤ k ∧ x ∈ LinearMap.ker ((f - μ • 1) ^ l) := by have : Nonempty {l : ℕ // l ≤ k} := ⟨⟨0, zero_le _⟩⟩ have : Directed (ι := { i : ℕ // i ≤ k }) (· ≤ ·) fun i ↦ LinearMap.ker ((f - μ • 1) ^ (i : ℕ)) := Monotone.directed_le fun m n h ↦ by simpa using (f - μ • 1).iterateKer.monotone h - simp_rw [unifEigenspace, OrderHom.coe_mk, LinearMap.mem_ker, iSup_subtype', + simp_rw [genEigenspace, OrderHom.coe_mk, LinearMap.mem_ker, iSup_subtype', Submodule.mem_iSup_of_directed _ this, LinearMap.mem_ker, Subtype.exists, exists_prop] -lemma unifEigenspace_directed {f : End R M} {μ : R} {k : ℕ∞} : - Directed (· ≤ ·) (fun l : {l : ℕ // l ≤ k} ↦ f.unifEigenspace μ l) := by +lemma genEigenspace_directed {f : End R M} {μ : R} {k : ℕ∞} : + Directed (· ≤ ·) (fun l : {l : ℕ // l ≤ k} ↦ f.genEigenspace μ l) := by have aux : Monotone ((↑) : {l : ℕ // l ≤ k} → ℕ∞) := fun x y h ↦ by simpa using h - exact ((unifEigenspace f μ).monotone.comp aux).directed_le + exact ((genEigenspace f μ).monotone.comp aux).directed_le -lemma mem_unifEigenspace_nat {f : End R M} {μ : R} {k : ℕ} {x : M} : - x ∈ f.unifEigenspace μ k ↔ x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by - rw [mem_unifEigenspace] +lemma mem_genEigenspace_nat {f : End R M} {μ : R} {k : ℕ} {x : M} : + x ∈ f.genEigenspace μ k ↔ x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by + rw [mem_genEigenspace] constructor · rintro ⟨l, hl, hx⟩ simp only [Nat.cast_le] at hl @@ -88,64 +90,64 @@ lemma mem_unifEigenspace_nat {f : End R M} {μ : R} {k : ℕ} {x : M} : · intro hx exact ⟨k, le_rfl, hx⟩ -lemma mem_unifEigenspace_top {f : End R M} {μ : R} {x : M} : - x ∈ f.unifEigenspace μ ⊤ ↔ ∃ k : ℕ, x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by - simp [mem_unifEigenspace] +lemma mem_genEigenspace_top {f : End R M} {μ : R} {x : M} : + x ∈ f.genEigenspace μ ⊤ ↔ ∃ k : ℕ, x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by + simp [mem_genEigenspace] -lemma unifEigenspace_nat {f : End R M} {μ : R} {k : ℕ} : - f.unifEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by - ext; simp [mem_unifEigenspace_nat] +lemma genEigenspace_nat {f : End R M} {μ : R} {k : ℕ} : + f.genEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by + ext; simp [mem_genEigenspace_nat] -lemma unifEigenspace_eq_iSup_unifEigenspace_nat (f : End R M) (μ : R) (k : ℕ∞) : - f.unifEigenspace μ k = ⨆ l : {l : ℕ // l ≤ k}, f.unifEigenspace μ l := by - simp_rw [unifEigenspace_nat, unifEigenspace, OrderHom.coe_mk, iSup_subtype] +lemma genEigenspace_eq_iSup_genEigenspace_nat (f : End R M) (μ : R) (k : ℕ∞) : + f.genEigenspace μ k = ⨆ l : {l : ℕ // l ≤ k}, f.genEigenspace μ l := by + simp_rw [genEigenspace_nat, genEigenspace, OrderHom.coe_mk, iSup_subtype] -lemma unifEigenspace_top (f : End R M) (μ : R) : - f.unifEigenspace μ ⊤ = ⨆ k : ℕ, f.unifEigenspace μ k := by - rw [unifEigenspace_eq_iSup_unifEigenspace_nat, iSup_subtype] +lemma genEigenspace_top (f : End R M) (μ : R) : + f.genEigenspace μ ⊤ = ⨆ k : ℕ, f.genEigenspace μ k := by + rw [genEigenspace_eq_iSup_genEigenspace_nat, iSup_subtype] simp only [le_top, iSup_pos, OrderHom.coe_mk] -lemma unifEigenspace_one {f : End R M} {μ : R} : - f.unifEigenspace μ 1 = LinearMap.ker (f - μ • 1) := by - rw [← Nat.cast_one, unifEigenspace_nat, pow_one] +lemma genEigenspace_one {f : End R M} {μ : R} : + f.genEigenspace μ 1 = LinearMap.ker (f - μ • 1) := by + rw [← Nat.cast_one, genEigenspace_nat, pow_one] @[simp] -lemma mem_unifEigenspace_one {f : End R M} {μ : R} {x : M} : - x ∈ f.unifEigenspace μ 1 ↔ f x = μ • x := by - rw [unifEigenspace_one, LinearMap.mem_ker, LinearMap.sub_apply, +lemma mem_genEigenspace_one {f : End R M} {μ : R} {x : M} : + x ∈ f.genEigenspace μ 1 ↔ f x = μ • x := by + rw [genEigenspace_one, LinearMap.mem_ker, LinearMap.sub_apply, sub_eq_zero, LinearMap.smul_apply, LinearMap.one_apply] --- `simp` can prove this using `unifEigenspace_zero` -lemma mem_unifEigenspace_zero {f : End R M} {μ : R} {x : M} : - x ∈ f.unifEigenspace μ 0 ↔ x = 0 := by - rw [← Nat.cast_zero, mem_unifEigenspace_nat, pow_zero, LinearMap.mem_ker, LinearMap.one_apply] +-- `simp` can prove this using `genEigenspace_zero` +lemma mem_genEigenspace_zero {f : End R M} {μ : R} {x : M} : + x ∈ f.genEigenspace μ 0 ↔ x = 0 := by + rw [← Nat.cast_zero, mem_genEigenspace_nat, pow_zero, LinearMap.mem_ker, LinearMap.one_apply] @[simp] -lemma unifEigenspace_zero {f : End R M} {μ : R} : - f.unifEigenspace μ 0 = ⊥ := by - ext; apply mem_unifEigenspace_zero +lemma genEigenspace_zero {f : End R M} {μ : R} : + f.genEigenspace μ 0 = ⊥ := by + ext; apply mem_genEigenspace_zero @[simp] -lemma unifEigenspace_zero_nat (f : End R M) (k : ℕ) : - f.unifEigenspace 0 k = LinearMap.ker (f ^ k) := by - ext; simp [mem_unifEigenspace_nat] +lemma genEigenspace_zero_nat (f : End R M) (k : ℕ) : + f.genEigenspace 0 k = LinearMap.ker (f ^ k) := by + ext; simp [mem_genEigenspace_nat] /-- Let `M` be an `R`-module, and `f` an `R`-linear endomorphism of `M`, and let `μ : R` and `k : ℕ∞` be given. Then `x : M` satisfies `HasUnifEigenvector f μ k x` if -`x ∈ f.unifEigenspace μ k` and `x ≠ 0`. +`x ∈ f.genEigenspace μ k` and `x ≠ 0`. For `k = 1`, this means that `x` is an eigenvector of `f` with eigenvalue `μ`. -/ def HasUnifEigenvector (f : End R M) (μ : R) (k : ℕ∞) (x : M) : Prop := - x ∈ f.unifEigenspace μ k ∧ x ≠ 0 + x ∈ f.genEigenspace μ k ∧ x ≠ 0 /-- Let `M` be an `R`-module, and `f` an `R`-linear endomorphism of `M`. Then `μ : R` and `k : ℕ∞` satisfy `HasUnifEigenvalue f μ k` if -`f.unifEigenspace μ k ≠ ⊥`. +`f.genEigenspace μ k ≠ ⊥`. For `k = 1`, this means that `μ` is an eigenvalue of `f`. -/ def HasUnifEigenvalue (f : End R M) (μ : R) (k : ℕ∞) : Prop := - f.unifEigenspace μ k ≠ ⊥ + f.genEigenspace μ k ≠ ⊥ /-- Let `M` be an `R`-module, and `f` an `R`-linear endomorphism of `M`. For `k : ℕ∞`, we define `UnifEigenvalues f k` to be the type of all @@ -174,7 +176,7 @@ lemma HasUnifEigenvector.hasUnifEigenvalue {f : End R M} {μ : R} {k : ℕ∞} { lemma HasUnifEigenvector.apply_eq_smul {f : End R M} {μ : R} {x : M} (hx : f.HasUnifEigenvector μ 1 x) : f x = μ • x := - mem_unifEigenspace_one.mp hx.1 + mem_genEigenspace_one.mp hx.1 lemma HasUnifEigenvector.pow_apply {f : End R M} {μ : R} {v : M} (hv : f.HasUnifEigenvector μ 1 v) (n : ℕ) : (f ^ n) v = μ ^ n • v := by @@ -189,7 +191,7 @@ lemma HasUnifEigenvalue.pow {f : End R M} {μ : R} (h : f.HasUnifEigenvalue μ 1 (f ^ n).HasUnifEigenvalue (μ ^ n) 1 := by rw [HasUnifEigenvalue, Submodule.ne_bot_iff] obtain ⟨m : M, hm⟩ := h.exists_hasUnifEigenvector - exact ⟨m, by simpa [mem_unifEigenspace_one] using hm.pow_apply n, hm.2⟩ + exact ⟨m, by simpa [mem_genEigenspace_one] using hm.pow_apply n, hm.2⟩ /-- A nilpotent endomorphism has nilpotent eigenvalues. @@ -212,16 +214,16 @@ lemma HasUnifEigenvalue.mem_spectrum {f : End R M} {μ : R} (hμ : HasUnifEigenv lemma hasUnifEigenvalue_iff_mem_spectrum [FiniteDimensional K V] {f : End K V} {μ : K} : f.HasUnifEigenvalue μ 1 ↔ μ ∈ spectrum K f := by rw [spectrum.mem_iff, IsUnit.sub_iff, LinearMap.isUnit_iff_ker_eq_bot, - HasUnifEigenvalue, unifEigenspace_one, ne_eq, not_iff_not] + HasUnifEigenvalue, genEigenspace_one, ne_eq, not_iff_not] simp [Submodule.ext_iff, LinearMap.mem_ker] alias ⟨_, HasUnifEigenvalue.of_mem_spectrum⟩ := hasUnifEigenvalue_iff_mem_spectrum -lemma unifEigenspace_div (f : End K V) (a b : K) (hb : b ≠ 0) : - unifEigenspace f (a / b) 1 = LinearMap.ker (b • f - a • 1) := +lemma genEigenspace_div (f : End K V) (a b : K) (hb : b ≠ 0) : + genEigenspace f (a / b) 1 = LinearMap.ker (b • f - a • 1) := calc - unifEigenspace f (a / b) 1 = unifEigenspace f (b⁻¹ * a) 1 := by rw [div_eq_mul_inv, mul_comm] - _ = LinearMap.ker (f - (b⁻¹ * a) • 1) := by rw [unifEigenspace_one] + genEigenspace f (a / b) 1 = genEigenspace f (b⁻¹ * a) 1 := by rw [div_eq_mul_inv, mul_comm] + _ = LinearMap.ker (f - (b⁻¹ * a) • 1) := by rw [genEigenspace_one] _ = LinearMap.ker (f - b⁻¹ • a • 1) := by rw [smul_smul] _ = LinearMap.ker (b • (f - b⁻¹ • a • 1)) := by rw [LinearMap.ker_smul _ b hb] _ = LinearMap.ker (b • f - a • 1) := by rw [smul_sub, smul_inv_smul₀ hb] @@ -229,13 +231,13 @@ lemma unifEigenspace_div (f : End K V) (a b : K) (hb : b ≠ 0) : /-- The generalized eigenrange for a linear map `f`, a scalar `μ`, and an exponent `k ∈ ℕ∞` is the range of `(f - μ • id) ^ k` if `k` is a natural number, or the infimum of these ranges if `k = ∞`. -/ -def unifEigenrange (f : End R M) (μ : R) (k : ℕ∞) : Submodule R M := +def genEigenrange (f : End R M) (μ : R) (k : ℕ∞) : Submodule R M := ⨅ l : ℕ, ⨅ (_ : l ≤ k), LinearMap.range ((f - μ • 1) ^ l) -lemma unifEigenrange_nat {f : End R M} {μ : R} {k : ℕ} : - f.unifEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by +lemma genEigenrange_nat {f : End R M} {μ : R} {k : ℕ} : + f.genEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by ext x - simp only [unifEigenrange, Nat.cast_le, Submodule.mem_iInf, LinearMap.mem_range] + simp only [genEigenrange, Nat.cast_le, Submodule.mem_iInf, LinearMap.mem_range] constructor · intro h exact h _ le_rfl @@ -248,41 +250,41 @@ lemma unifEigenrange_nat {f : End R M} {μ : R} {k : ℕ} : lemma HasUnifEigenvalue.exp_ne_zero {f : End R M} {μ : R} {k : ℕ} (h : f.HasUnifEigenvalue μ k) : k ≠ 0 := by rintro rfl - simp [HasUnifEigenvalue, Nat.cast_zero, unifEigenspace_zero] at h + simp [HasUnifEigenvalue, Nat.cast_zero, genEigenspace_zero] at h /-- If there exists a natural number `k` such that the kernel of `(f - μ • id) ^ k` is the maximal generalized eigenspace, then this value is the least such `k`. If not, this value is not meaningful. -/ noncomputable def maxUnifEigenspaceIndex (f : End R M) (μ : R) := - monotonicSequenceLimitIndex <| (f.unifEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom + monotonicSequenceLimitIndex <| (f.genEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom /-- For an endomorphism of a Noetherian module, the maximal eigenspace is always of the form kernel `(f - μ • id) ^ k` for some `k`. -/ -lemma unifEigenspace_top_eq_maxUnifEigenspaceIndex [h : IsNoetherian R M] (f : End R M) (μ : R) : - unifEigenspace f μ ⊤ = f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := by +lemma genEigenspace_top_eq_maxUnifEigenspaceIndex [h : IsNoetherian R M] (f : End R M) (μ : R) : + genEigenspace f μ ⊤ = f.genEigenspace μ (maxUnifEigenspaceIndex f μ) := by rw [isNoetherian_iff] at h have := WellFounded.iSup_eq_monotonicSequenceLimit h <| - (f.unifEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom + (f.genEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom convert this using 1 - simp only [unifEigenspace, OrderHom.coe_mk, le_top, iSup_pos, OrderHom.comp_coe, + simp only [genEigenspace, OrderHom.coe_mk, le_top, iSup_pos, OrderHom.comp_coe, Function.comp_def] rw [iSup_prod', iSup_subtype', ← sSup_range, ← sSup_range] congr aesop -lemma unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex [IsNoetherian R M] (f : End R M) +lemma genEigenspace_le_genEigenspace_maxUnifEigenspaceIndex [IsNoetherian R M] (f : End R M) (μ : R) (k : ℕ∞) : - f.unifEigenspace μ k ≤ f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := by - rw [← unifEigenspace_top_eq_maxUnifEigenspaceIndex] - exact (f.unifEigenspace μ).monotone le_top + f.genEigenspace μ k ≤ f.genEigenspace μ (maxUnifEigenspaceIndex f μ) := by + rw [← genEigenspace_top_eq_maxUnifEigenspaceIndex] + exact (f.genEigenspace μ).monotone le_top /-- Generalized eigenspaces for exponents at least `finrank K V` are equal to each other. -/ -theorem unifEigenspace_eq_unifEigenspace_maxUnifEigenspaceIndex_of_le [IsNoetherian R M] +theorem genEigenspace_eq_genEigenspace_maxUnifEigenspaceIndex_of_le [IsNoetherian R M] (f : End R M) (μ : R) {k : ℕ} (hk : maxUnifEigenspaceIndex f μ ≤ k) : - f.unifEigenspace μ k = f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := + f.genEigenspace μ k = f.genEigenspace μ (maxUnifEigenspaceIndex f μ) := le_antisymm - (unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex _ _ _) - ((f.unifEigenspace μ).monotone <| by simpa using hk) + (genEigenspace_le_genEigenspace_maxUnifEigenspaceIndex _ _ _) + ((f.genEigenspace μ).monotone <| by simpa using hk) /-- A generalized eigenvalue for some exponent `k` is also a generalized eigenvalue for exponents larger than `k`. -/ @@ -292,7 +294,7 @@ lemma HasUnifEigenvalue.le {f : End R M} {μ : R} {k m : ℕ∞} unfold HasUnifEigenvalue at * contrapose! hk rw [← le_bot_iff, ← hk] - exact (f.unifEigenspace _).monotone hm + exact (f.genEigenspace _).monotone hm /-- A generalized eigenvalue for some exponent `k` is also a generalized eigenvalue for positive exponents. -/ @@ -301,10 +303,10 @@ lemma HasUnifEigenvalue.lt {f : End R M} {μ : R} {k m : ℕ∞} f.HasUnifEigenvalue μ m := by apply HasUnifEigenvalue.le (k := 1) (Order.one_le_iff_pos.mpr hm) intro contra; apply hk - rw [unifEigenspace_one, LinearMap.ker_eq_bot] at contra + rw [genEigenspace_one, LinearMap.ker_eq_bot] at contra rw [eq_bot_iff] intro x hx - rw [mem_unifEigenspace] at hx + rw [mem_genEigenspace] at hx rcases hx with ⟨l, -, hx⟩ rwa [LinearMap.ker_eq_bot.mpr] at hx rw [LinearMap.coe_pow (f - μ • 1) l] @@ -321,33 +323,33 @@ lemma maxUnifEigenspaceIndex_le_finrank [FiniteDimensional K V] (f : End K V) ( apply Nat.sInf_le intro n hn apply le_antisymm - · exact (f.unifEigenspace μ).monotone <| WithTop.coeOrderHom.monotone hn - · show (f.unifEigenspace μ) n ≤ (f.unifEigenspace μ) (finrank K V) - rw [unifEigenspace_nat, unifEigenspace_nat] + · exact (f.genEigenspace μ).monotone <| WithTop.coeOrderHom.monotone hn + · show (f.genEigenspace μ) n ≤ (f.genEigenspace μ) (finrank K V) + rw [genEigenspace_nat, genEigenspace_nat] apply ker_pow_le_ker_pow_finrank /-- Every generalized eigenvector is a generalized eigenvector for exponent `finrank K V`. (Lemma 8.11 of [axler2015]) -/ -lemma unifEigenspace_le_unifEigenspace_finrank [FiniteDimensional K V] (f : End K V) - (μ : K) (k : ℕ∞) : f.unifEigenspace μ k ≤ f.unifEigenspace μ (finrank K V) := by - calc f.unifEigenspace μ k - ≤ f.unifEigenspace μ ⊤ := (f.unifEigenspace _).monotone le_top - _ ≤ f.unifEigenspace μ (finrank K V) := by - rw [unifEigenspace_top_eq_maxUnifEigenspaceIndex] - exact (f.unifEigenspace _).monotone <| by simpa using maxUnifEigenspaceIndex_le_finrank f μ +lemma genEigenspace_le_genEigenspace_finrank [FiniteDimensional K V] (f : End K V) + (μ : K) (k : ℕ∞) : f.genEigenspace μ k ≤ f.genEigenspace μ (finrank K V) := by + calc f.genEigenspace μ k + ≤ f.genEigenspace μ ⊤ := (f.genEigenspace _).monotone le_top + _ ≤ f.genEigenspace μ (finrank K V) := by + rw [genEigenspace_top_eq_maxUnifEigenspaceIndex] + exact (f.genEigenspace _).monotone <| by simpa using maxUnifEigenspaceIndex_le_finrank f μ /-- Generalized eigenspaces for exponents at least `finrank K V` are equal to each other. -/ -theorem unifEigenspace_eq_unifEigenspace_finrank_of_le [FiniteDimensional K V] +theorem genEigenspace_eq_genEigenspace_finrank_of_le [FiniteDimensional K V] (f : End K V) (μ : K) {k : ℕ} (hk : finrank K V ≤ k) : - f.unifEigenspace μ k = f.unifEigenspace μ (finrank K V) := + f.genEigenspace μ k = f.genEigenspace μ (finrank K V) := le_antisymm - (unifEigenspace_le_unifEigenspace_finrank _ _ _) - ((f.unifEigenspace μ).monotone <| by simpa using hk) + (genEigenspace_le_genEigenspace_finrank _ _ _) + ((f.genEigenspace μ).monotone <| by simpa using hk) -lemma mapsTo_unifEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k : ℕ∞) : - MapsTo g (f.unifEigenspace μ k) (f.unifEigenspace μ k) := by +lemma mapsTo_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k : ℕ∞) : + MapsTo g (f.genEigenspace μ k) (f.genEigenspace μ k) := by intro x hx - simp only [SetLike.mem_coe, mem_unifEigenspace, LinearMap.mem_ker] at hx ⊢ + simp only [SetLike.mem_coe, mem_genEigenspace, LinearMap.mem_ker] at hx ⊢ rcases hx with ⟨l, hl, hx⟩ replace h : Commute ((f - μ • (1 : End R M)) ^ l) g := (h.sub_left <| Algebra.commute_algebraMap_left μ g).pow_left l @@ -356,41 +358,41 @@ lemma mapsTo_unifEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) ( LinearMap.comp_apply, hx, map_zero] /-- The restriction of `f - μ • 1` to the `k`-fold generalized `μ`-eigenspace is nilpotent. -/ -lemma isNilpotent_restrict_unifEigenspace_nat (f : End R M) (μ : R) (k : ℕ) +lemma isNilpotent_restrict_genEigenspace_nat (f : End R M) (μ : R) (k : ℕ) (h : MapsTo (f - μ • (1 : End R M)) - (f.unifEigenspace μ k) (f.unifEigenspace μ k) := - mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ k) : + (f.genEigenspace μ k) (f.genEigenspace μ k) := + mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ k) : IsNilpotent ((f - μ • 1).restrict h) := by use k ext ⟨x, hx⟩ - rw [mem_unifEigenspace_nat] at hx + rw [mem_genEigenspace_nat] at hx rw [LinearMap.zero_apply, ZeroMemClass.coe_zero, ZeroMemClass.coe_eq_zero, LinearMap.pow_restrict, LinearMap.restrict_apply] ext simpa /-- The restriction of `f - μ • 1` to the generalized `μ`-eigenspace is nilpotent. -/ -lemma isNilpotent_restrict_unifEigenspace_top [IsNoetherian R M] (f : End R M) (μ : R) +lemma isNilpotent_restrict_genEigenspace_top [IsNoetherian R M] (f : End R M) (μ : R) (h : MapsTo (f - μ • (1 : End R M)) - (f.unifEigenspace μ ⊤) (f.unifEigenspace μ ⊤) := - mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ _) : + (f.genEigenspace μ ⊤) (f.genEigenspace μ ⊤) := + mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ _) : IsNilpotent ((f - μ • 1).restrict h) := by apply isNilpotent_restrict_of_le - swap; apply isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ) - rw [unifEigenspace_top_eq_maxUnifEigenspaceIndex] + on_goal 2 => apply isNilpotent_restrict_genEigenspace_nat f μ (maxUnifEigenspaceIndex f μ) + rw [genEigenspace_top_eq_maxUnifEigenspaceIndex] /-- The submodule `eigenspace f μ` for a linear map `f` and a scalar `μ` consists of all vectors `x` such that `f x = μ • x`. (Def 5.36 of [axler2015])-/ abbrev eigenspace (f : End R M) (μ : R) : Submodule R M := - f.unifEigenspace μ 1 + f.genEigenspace μ 1 lemma eigenspace_def {f : End R M} {μ : R} : f.eigenspace μ = LinearMap.ker (f - μ • 1) := by - rw [eigenspace, unifEigenspace_one] + rw [eigenspace, genEigenspace_one] @[simp] theorem eigenspace_zero (f : End R M) : f.eigenspace 0 = LinearMap.ker f := by - simp only [eigenspace, ← Nat.cast_one (R := ℕ∞), unifEigenspace_zero_nat, pow_one] + simp only [eigenspace, ← Nat.cast_one (R := ℕ∞), genEigenspace_zero_nat, pow_one] /-- A nonzero element of an eigenspace is an eigenvector. (Def 5.7 of [axler2015]) -/ abbrev HasEigenvector (f : End R M) (μ : R) (x : M) : Prop := @@ -419,7 +421,7 @@ theorem hasEigenvalue_of_hasEigenvector {f : End R M} {μ : R} {x : M} (h : HasE h.hasUnifEigenvalue theorem mem_eigenspace_iff {f : End R M} {μ : R} {x : M} : x ∈ eigenspace f μ ↔ f x = μ • x := - mem_unifEigenspace_one + mem_genEigenspace_one nonrec theorem HasEigenvector.apply_eq_smul {f : End R M} {μ : R} {x : M} (hx : f.HasEigenvector μ x) : @@ -462,28 +464,12 @@ alias ⟨_, HasEigenvalue.of_mem_spectrum⟩ := hasEigenvalue_iff_mem_spectrum theorem eigenspace_div (f : End K V) (a b : K) (hb : b ≠ 0) : eigenspace f (a / b) = LinearMap.ker (b • f - algebraMap K (End K V) a) := - unifEigenspace_div f a b hb - -/-- The generalized eigenspace for a linear map `f`, a scalar `μ`, and an exponent `k ∈ ℕ` is the -kernel of `(f - μ • id) ^ k`. (Def 8.10 of [axler2015]). Furthermore, a generalized eigenspace for -some exponent `k` is contained in the generalized eigenspace for exponents larger than `k`. -/ -def genEigenspace (f : End R M) (μ : R) : ℕ →o Submodule R M where - toFun k := f.unifEigenspace μ k - monotone' k l hkl := (f.unifEigenspace μ).monotone <| by simpa + genEigenspace_div f a b hb +@[deprecated genEigenspace_nat (since := "2024-10-28")] lemma genEigenspace_def (f : End R M) (μ : R) (k : ℕ) : - f.genEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by - rw [genEigenspace, OrderHom.coe_mk, unifEigenspace_nat] - -@[simp] -theorem mem_genEigenspace (f : End R M) (μ : R) (k : ℕ) (m : M) : - m ∈ f.genEigenspace μ k ↔ ((f - μ • (1 : End R M)) ^ k) m = 0 := - mem_unifEigenspace_nat - -@[simp] -theorem genEigenspace_zero (f : End R M) (k : ℕ) : - f.genEigenspace 0 k = LinearMap.ker (f ^ k) := - unifEigenspace_zero_nat _ _ + f.genEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := + genEigenspace_nat /-- A nonzero element of a generalized eigenspace is a generalized eigenvector. (Def 8.9 of [axler2015])-/ @@ -501,14 +487,10 @@ abbrev HasGenEigenvalue (f : End R M) (μ : R) (k : ℕ) : Prop := lemma hasGenEigenvalue_iff {f : End R M} {μ : R} {k : ℕ} : f.HasGenEigenvalue μ k ↔ f.genEigenspace μ k ≠ ⊥ := Iff.rfl -/-- The generalized eigenrange for a linear map `f`, a scalar `μ`, and an exponent `k ∈ ℕ` is the - range of `(f - μ • id) ^ k`. -/ -abbrev genEigenrange (f : End R M) (μ : R) (k : ℕ) : Submodule R M := - unifEigenrange f μ k - +@[deprecated genEigenrange_nat (since := "2024-10-28")] lemma genEigenrange_def {f : End R M} {μ : R} {k : ℕ} : - f.genEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by - rw [genEigenrange, unifEigenrange_nat] + f.genEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := + genEigenrange_nat /-- The exponent of a generalized eigenvalue is never 0. -/ theorem exp_ne_zero_of_hasGenEigenvalue {f : End R M} {μ : R} {k : ℕ} @@ -517,20 +499,25 @@ theorem exp_ne_zero_of_hasGenEigenvalue {f : End R M} {μ : R} {k : ℕ} /-- The union of the kernels of `(f - μ • id) ^ k` over all `k`. -/ abbrev maxGenEigenspace (f : End R M) (μ : R) : Submodule R M := - unifEigenspace f μ ⊤ + genEigenspace f μ ⊤ + +lemma iSup_genEigenspace_eq (f : End R M) (μ : R) : + ⨆ k : ℕ, (f.genEigenspace μ) k = f.maxGenEigenspace μ := by + simp_rw [maxGenEigenspace, genEigenspace_top] +@[deprecated iSup_genEigenspace_eq (since := "2024-10-23")] lemma maxGenEigenspace_def (f : End R M) (μ : R) : - f.maxGenEigenspace μ = ⨆ k, f.genEigenspace μ k := by - simp_rw [maxGenEigenspace, unifEigenspace_top, genEigenspace, OrderHom.coe_mk] + f.maxGenEigenspace μ = ⨆ k : ℕ, f.genEigenspace μ k := + (iSup_genEigenspace_eq f μ).symm theorem genEigenspace_le_maximal (f : End R M) (μ : R) (k : ℕ) : f.genEigenspace μ k ≤ f.maxGenEigenspace μ := - (f.unifEigenspace μ).monotone le_top + (f.genEigenspace μ).monotone le_top @[simp] theorem mem_maxGenEigenspace (f : End R M) (μ : R) (m : M) : m ∈ f.maxGenEigenspace μ ↔ ∃ k : ℕ, ((f - μ • (1 : End R M)) ^ k) m = 0 := - mem_unifEigenspace_top + mem_genEigenspace_top /-- If there exists a natural number `k` such that the kernel of `(f - μ • id) ^ k` is the maximal generalized eigenspace, then this value is the least such `k`. If not, this value is not @@ -542,7 +529,7 @@ noncomputable abbrev maxGenEigenspaceIndex (f : End R M) (μ : R) := `(f - μ • id) ^ k` for some `k`. -/ theorem maxGenEigenspace_eq [IsNoetherian R M] (f : End R M) (μ : R) : maxGenEigenspace f μ = f.genEigenspace μ (maxGenEigenspaceIndex f μ) := - unifEigenspace_top_eq_maxUnifEigenspaceIndex _ _ + genEigenspace_top_eq_maxUnifEigenspaceIndex _ _ /-- A generalized eigenvalue for some exponent `k` is also a generalized eigenvalue for exponents larger than `k`. -/ @@ -554,7 +541,7 @@ theorem hasGenEigenvalue_of_hasGenEigenvalue_of_le {f : End R M} {μ : R} {k : /-- The eigenspace is a subspace of the generalized eigenspace. -/ theorem eigenspace_le_genEigenspace {f : End R M} {μ : R} {k : ℕ} (hk : 0 < k) : f.eigenspace μ ≤ f.genEigenspace μ k := - (f.unifEigenspace _).monotone <| by simpa using Nat.succ_le_of_lt hk + (f.genEigenspace _).monotone <| by simpa using Nat.succ_le_of_lt hk /-- All eigenvalues are generalized eigenvalues. -/ theorem hasGenEigenvalue_of_hasEigenvalue {f : End R M} {μ : R} {k : ℕ} (hk : 0 < k) @@ -572,49 +559,21 @@ theorem hasGenEigenvalue_iff_hasEigenvalue {f : End R M} {μ : R} {k : ℕ} (hk f.HasGenEigenvalue μ k ↔ f.HasEigenvalue μ := hasUnifEigenvalue_iff_hasUnifEigenvalue_one <| by simpa using hk -/-- Every generalized eigenvector is a generalized eigenvector for exponent `finrank K V`. - (Lemma 8.11 of [axler2015]) -/ -theorem genEigenspace_le_genEigenspace_finrank [FiniteDimensional K V] (f : End K V) - (μ : K) (k : ℕ) : f.genEigenspace μ k ≤ f.genEigenspace μ (finrank K V) := - unifEigenspace_le_unifEigenspace_finrank _ _ _ - -@[simp] theorem iSup_genEigenspace_eq_genEigenspace_finrank +theorem maxGenEigenspace_eq_genEigenspace_finrank [FiniteDimensional K V] (f : End K V) (μ : K) : - ⨆ k, f.genEigenspace μ k = f.genEigenspace μ (finrank K V) := - le_antisymm (iSup_le (genEigenspace_le_genEigenspace_finrank f μ)) (le_iSup _ _) - -/-- Generalized eigenspaces for exponents at least `finrank K V` are equal to each other. -/ -theorem genEigenspace_eq_genEigenspace_finrank_of_le [FiniteDimensional K V] - (f : End K V) (μ : K) {k : ℕ} (hk : finrank K V ≤ k) : - f.genEigenspace μ k = f.genEigenspace μ (finrank K V) := - unifEigenspace_eq_unifEigenspace_finrank_of_le f μ hk - -lemma mapsTo_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k : ℕ) : - MapsTo g (f.genEigenspace μ k) (f.genEigenspace μ k) := by - replace h : Commute ((f - μ • (1 : End R M)) ^ k) g := - (h.sub_left <| Algebra.commute_algebraMap_left μ g).pow_left k - intro x hx - simp only [SetLike.mem_coe, mem_genEigenspace] at hx ⊢ - rw [← LinearMap.comp_apply, ← LinearMap.mul_eq_comp, h.eq, LinearMap.mul_eq_comp, - LinearMap.comp_apply, hx, map_zero] - -lemma iSup_genEigenspace_eq (f : End R M) (μ : R) : - ⨆ k, (f.genEigenspace μ) k = f.unifEigenspace μ ⊤ := by - rw [unifEigenspace_eq_iSup_unifEigenspace_nat] - ext - simp only [iSup_subtype, le_top, iSup_pos] - rfl + f.maxGenEigenspace μ = f.genEigenspace μ (finrank K V) := by + apply le_antisymm _ <| (f.genEigenspace μ).monotone le_top + rw [genEigenspace_top_eq_maxUnifEigenspaceIndex] + apply genEigenspace_le_genEigenspace_finrank f μ lemma mapsTo_maxGenEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) : - MapsTo g ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) := by - rw [maxGenEigenspace_def] - simp only [MapsTo, Submodule.coe_iSup_of_chain, mem_iUnion, SetLike.mem_coe] - rintro x ⟨k, hk⟩ - exact ⟨k, f.mapsTo_genEigenspace_of_comm h μ k hk⟩ + MapsTo g ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) := + mapsTo_genEigenspace_of_comm h μ ⊤ +@[deprecated mapsTo_iSup_genEigenspace_of_comm (since := "2024-10-23")] lemma mapsTo_iSup_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) : - MapsTo g ↑(⨆ k, f.genEigenspace μ k) ↑(⨆ k, f.genEigenspace μ k) := by - rw [← maxGenEigenspace_def] + MapsTo g ↑(⨆ k : ℕ, f.genEigenspace μ k) ↑(⨆ k : ℕ, f.genEigenspace μ k) := by + rw [iSup_genEigenspace_eq] apply mapsTo_maxGenEigenspace_of_comm h /-- The restriction of `f - μ • 1` to the `k`-fold generalized `μ`-eigenspace is nilpotent. -/ @@ -623,7 +582,7 @@ lemma isNilpotent_restrict_sub_algebraMap (f : End R M) (μ : R) (k : ℕ) (f.genEigenspace μ k) (f.genEigenspace μ k) := mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ k) : IsNilpotent ((f - algebraMap R (End R M) μ).restrict h) := - isNilpotent_restrict_unifEigenspace_nat _ _ _ + isNilpotent_restrict_genEigenspace_nat _ _ _ /-- The restriction of `f - μ • 1` to the generalized `μ`-eigenspace is nilpotent. -/ lemma isNilpotent_restrict_maxGenEigenspace_sub_algebraMap [IsNoetherian R M] (f : End R M) (μ : R) @@ -631,80 +590,85 @@ lemma isNilpotent_restrict_maxGenEigenspace_sub_algebraMap [IsNoetherian R M] (f ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) := mapsTo_maxGenEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ) : IsNilpotent ((f - algebraMap R (End R M) μ).restrict h) := by - apply isNilpotent_restrict_of_le (q := f.unifEigenspace μ (maxUnifEigenspaceIndex f μ)) - _ (isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) + apply isNilpotent_restrict_of_le (q := f.genEigenspace μ (maxUnifEigenspaceIndex f μ)) + _ (isNilpotent_restrict_genEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) rw [maxGenEigenspace_eq] - exact le_rfl +set_option linter.deprecated false in /-- The restriction of `f - μ • 1` to the generalized `μ`-eigenspace is nilpotent. -/ +@[deprecated isNilpotent_restrict_maxGenEigenspace_sub_algebraMap (since := "2024-10-23")] lemma isNilpotent_restrict_iSup_sub_algebraMap [IsNoetherian R M] (f : End R M) (μ : R) (h : MapsTo (f - algebraMap R (End R M) μ) - ↑(⨆ k, f.genEigenspace μ k) ↑(⨆ k, f.genEigenspace μ k) := + ↑(⨆ k : ℕ, f.genEigenspace μ k) ↑(⨆ k : ℕ, f.genEigenspace μ k) := mapsTo_iSup_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ) : IsNilpotent ((f - algebraMap R (End R M) μ).restrict h) := by - apply isNilpotent_restrict_of_le (q := f.unifEigenspace μ (maxUnifEigenspaceIndex f μ)) - _ (isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) + apply isNilpotent_restrict_of_le (q := f.genEigenspace μ (maxUnifEigenspaceIndex f μ)) + _ (isNilpotent_restrict_genEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) apply iSup_le intro k - apply unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex + apply genEigenspace_le_genEigenspace_maxUnifEigenspaceIndex -lemma disjoint_unifEigenspace [NoZeroSMulDivisors R M] +lemma disjoint_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ∞) : - Disjoint (f.unifEigenspace μ₁ k) (f.unifEigenspace μ₂ l) := by - rw [unifEigenspace_eq_iSup_unifEigenspace_nat, unifEigenspace_eq_iSup_unifEigenspace_nat] - simp_rw [unifEigenspace_directed.disjoint_iSup_left, unifEigenspace_directed.disjoint_iSup_right] + Disjoint (f.genEigenspace μ₁ k) (f.genEigenspace μ₂ l) := by + rw [genEigenspace_eq_iSup_genEigenspace_nat, genEigenspace_eq_iSup_genEigenspace_nat] + simp_rw [genEigenspace_directed.disjoint_iSup_left, genEigenspace_directed.disjoint_iSup_right] rintro ⟨k, -⟩ ⟨l, -⟩ nontriviality M have := NoZeroSMulDivisors.isReduced R M rw [disjoint_iff] - set p := f.unifEigenspace μ₁ k ⊓ f.unifEigenspace μ₂ l + set p := f.genEigenspace μ₁ k ⊓ f.genEigenspace μ₂ l by_contra hp replace hp : Nontrivial p := Submodule.nontrivial_iff_ne_bot.mpr hp let f₁ : End R p := (f - algebraMap R (End R M) μ₁).restrict <| MapsTo.inter_inter - (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₁ k) - (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₂ l) + (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₁ k) + (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₂ l) let f₂ : End R p := (f - algebraMap R (End R M) μ₂).restrict <| MapsTo.inter_inter - (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₁ k) - (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₂ l) + (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₁ k) + (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₂ l) have : IsNilpotent (f₂ - f₁) := by apply Commute.isNilpotent_sub (x := f₂) (y := f₁) _ (isNilpotent_restrict_of_le inf_le_right _) (isNilpotent_restrict_of_le inf_le_left _) · ext; simp [f₁, f₂, smul_sub, sub_sub, smul_comm μ₁, add_sub_left_comm] - apply mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) - apply isNilpotent_restrict_unifEigenspace_nat - apply mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) - apply isNilpotent_restrict_unifEigenspace_nat + apply mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) + apply isNilpotent_restrict_genEigenspace_nat + apply mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) + apply isNilpotent_restrict_genEigenspace_nat have hf₁₂ : f₂ - f₁ = algebraMap R (End R p) (μ₁ - μ₂) := by ext; simp [f₁, f₂, sub_smul] rw [hf₁₂, IsNilpotent.map_iff (NoZeroSMulDivisors.algebraMap_injective R (End R p)), isNilpotent_iff_eq_zero, sub_eq_zero] at this contradiction -lemma disjoint_genEigenspace [NoZeroSMulDivisors R M] - (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ) : - Disjoint (f.genEigenspace μ₁ k) (f.genEigenspace μ₂ l) := - disjoint_unifEigenspace f hμ k l +lemma injOn_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) (k : ℕ∞) : + InjOn (f.genEigenspace · k) {μ | f.genEigenspace μ k ≠ ⊥} := by + rintro μ₁ _ μ₂ hμ₂ hμ₁₂ + by_contra contra + apply hμ₂ + simpa only [hμ₁₂, disjoint_self] using f.disjoint_genEigenspace contra k k +@[deprecated disjoint_genEigenspace (since := "2024-10-23")] lemma disjoint_iSup_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) : - Disjoint (⨆ k, f.genEigenspace μ₁ k) (⨆ k, f.genEigenspace μ₂ k) := by - simpa only [iSup_genEigenspace_eq] using disjoint_unifEigenspace f hμ ⊤ ⊤ + Disjoint (⨆ k : ℕ, f.genEigenspace μ₁ k) (⨆ k : ℕ, f.genEigenspace μ₂ k) := by + simpa only [iSup_genEigenspace_eq] using disjoint_genEigenspace f hμ ⊤ ⊤ -lemma injOn_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - InjOn (⨆ k, f.genEigenspace · k) {μ | ⨆ k, f.genEigenspace μ k ≠ ⊥} := by - rintro μ₁ _ μ₂ hμ₂ (hμ₁₂ : ⨆ k, f.genEigenspace μ₁ k = ⨆ k, f.genEigenspace μ₂ k) - by_contra contra - apply hμ₂ - simpa only [hμ₁₂, disjoint_self] using f.disjoint_iSup_genEigenspace contra +lemma injOn_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + InjOn (f.maxGenEigenspace ·) {μ | f.maxGenEigenspace μ ≠ ⊥} := + injOn_genEigenspace f ⊤ -theorem independent_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent f.maxGenEigenspace := by +@[deprecated injOn_genEigenspace (since := "2024-10-23")] +lemma injOn_iSup_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + InjOn (⨆ k : ℕ, f.genEigenspace · k) {μ | ⨆ k : ℕ, f.genEigenspace μ k ≠ ⊥} := by + simp_rw [iSup_genEigenspace_eq] + apply injOn_maxGenEigenspace + +theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) (k : ℕ∞) : + CompleteLattice.Independent (f.genEigenspace · k) := by classical - suffices ∀ μ (s : Finset R), μ ∉ s → Disjoint (⨆ k, f.genEigenspace μ k) - (s.sup fun μ ↦ ⨆ k, f.genEigenspace μ k) by - show CompleteLattice.Independent (f.maxGenEigenspace ·) - simp_rw [maxGenEigenspace_def, - CompleteLattice.independent_iff_supIndep_of_injOn f.injOn_genEigenspace, + suffices ∀ μ₁ (s : Finset R), μ₁ ∉ s → Disjoint (f.genEigenspace μ₁ k) + (s.sup fun μ ↦ f.genEigenspace μ k) by + simp_rw [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_genEigenspace f k), Finset.supIndep_iff_disjoint_erase] exact fun s μ _ ↦ this _ _ (s.not_mem_erase μ) intro μ₁ s @@ -716,38 +680,43 @@ theorem independent_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : rw [Finset.sup_insert, disjoint_iff, Submodule.eq_bot_iff] rintro x ⟨hx, hx'⟩ simp only [SetLike.mem_coe] at hx hx' - suffices x ∈ ⨆ k, genEigenspace f μ₂ k by - rw [← Submodule.mem_bot (R := R), ← (f.disjoint_iSup_genEigenspace hμ₁₂).eq_bot] + suffices x ∈ genEigenspace f μ₂ k by + rw [← Submodule.mem_bot (R := R), ← (f.disjoint_genEigenspace hμ₁₂ k k).eq_bot] exact ⟨hx, this⟩ obtain ⟨y, hy, z, hz, rfl⟩ := Submodule.mem_sup.mp hx'; clear hx' - let g := f - algebraMap R (End R M) μ₂ - obtain ⟨k : ℕ, hk : (g ^ k) y = 0⟩ := by simpa using hy - have hyz : (g ^ k) (y + z) ∈ - (⨆ k, genEigenspace f μ₁ k) ⊓ s.sup fun μ ↦ ⨆ k, f.genEigenspace μ k := by - refine ⟨f.mapsTo_iSup_genEigenspace_of_comm ?_ μ₁ hx, ?_⟩ - · exact Algebra.mul_sub_algebraMap_pow_commutes f μ₂ k - · rw [SetLike.mem_coe, map_add, hk, zero_add] - suffices (s.sup fun μ ↦ ⨆ k, f.genEigenspace μ k).map (g ^ k) ≤ - s.sup fun μ ↦ ⨆ k, f.genEigenspace μ k by exact this (Submodule.mem_map_of_mem hz) + let g := f - μ₂ • 1 + simp_rw [mem_genEigenspace, ← exists_prop] at hy ⊢ + peel hy with l hlk hl + simp only [mem_genEigenspace_nat, LinearMap.mem_ker] at hl + have hyz : (g ^ l) (y + z) ∈ + (f.genEigenspace μ₁ k) ⊓ s.sup fun μ ↦ f.genEigenspace μ k := by + refine ⟨f.mapsTo_genEigenspace_of_comm (g := g ^ l) ?_ μ₁ k hx, ?_⟩ + · exact Algebra.mul_sub_algebraMap_pow_commutes f μ₂ l + · rw [SetLike.mem_coe, map_add, hl, zero_add] + suffices (s.sup fun μ ↦ f.genEigenspace μ k).map (g ^ l) ≤ + s.sup fun μ ↦ f.genEigenspace μ k by exact this (Submodule.mem_map_of_mem hz) simp_rw [Finset.sup_eq_iSup, Submodule.map_iSup (ι := R), Submodule.map_iSup (ι := _ ∈ s)] refine iSup₂_mono fun μ _ ↦ ?_ rintro - ⟨u, hu, rfl⟩ - refine f.mapsTo_iSup_genEigenspace_of_comm ?_ μ hu - exact Algebra.mul_sub_algebraMap_pow_commutes f μ₂ k - rw [ih.eq_bot, Submodule.mem_bot] at hyz - simp_rw [Submodule.mem_iSup_of_chain, mem_genEigenspace] - exact ⟨k, hyz⟩ - -theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent (fun μ ↦ ⨆ k, f.genEigenspace μ k) := by - simp_rw [← maxGenEigenspace_def] + refine f.mapsTo_genEigenspace_of_comm ?_ μ k hu + exact Algebra.mul_sub_algebraMap_pow_commutes f μ₂ l + rwa [ih.eq_bot, Submodule.mem_bot] at hyz + +theorem independent_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + CompleteLattice.Independent f.maxGenEigenspace := by + apply independent_genEigenspace + +@[deprecated independent_genEigenspace (since := "2024-10-23")] +theorem independent_iSup_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + CompleteLattice.Independent (fun μ ↦ ⨆ k : ℕ, f.genEigenspace μ k) := by + simp_rw [iSup_genEigenspace_eq] apply independent_maxGenEigenspace /-- The eigenspaces of a linear operator form an independent family of subspaces of `M`. That is, any eigenspace has trivial intersection with the span of all the other eigenspaces. -/ theorem eigenspaces_independent [NoZeroSMulDivisors R M] (f : End R M) : CompleteLattice.Independent f.eigenspace := - f.independent_genEigenspace.mono fun μ ↦ le_iSup (genEigenspace f μ) 1 + (f.independent_genEigenspace 1).mono fun _ ↦ le_rfl /-- Eigenvectors corresponding to distinct eigenvalues of a linear operator are linearly independent. -/ @@ -770,55 +739,29 @@ theorem eigenvectors_linearIndependent [NoZeroSMulDivisors R M] /-- If `f` maps a subspace `p` into itself, then the generalized eigenspace of the restriction of `f` to `p` is the part of the generalized eigenspace of `f` that lies in `p`. -/ -theorem genEigenspace_restrict (f : End R M) (p : Submodule R M) (k : ℕ) (μ : R) +theorem genEigenspace_restrict (f : End R M) (p : Submodule R M) (k : ℕ∞) (μ : R) (hfp : ∀ x : M, x ∈ p → f x ∈ p) : genEigenspace (LinearMap.restrict f hfp) μ k = Submodule.comap p.subtype (f.genEigenspace μ k) := by - simp only [genEigenspace_def, OrderHom.coe_mk, ← LinearMap.ker_comp] - induction' k with k ih + ext x + suffices ∀ l : ℕ, genEigenspace (LinearMap.restrict f hfp) μ l = + Submodule.comap p.subtype (f.genEigenspace μ l) by + simp_rw [mem_genEigenspace, ← mem_genEigenspace_nat, this, + Submodule.mem_comap, mem_genEigenspace (k := k), mem_genEigenspace_nat] + intro l + simp only [genEigenspace_nat, OrderHom.coe_mk, ← LinearMap.ker_comp] + induction' l with l ih · rw [pow_zero, pow_zero, LinearMap.one_eq_id] apply (Submodule.ker_subtype _).symm · erw [pow_succ, pow_succ, LinearMap.ker_comp, LinearMap.ker_comp, ih, ← LinearMap.ker_comp, LinearMap.comp_assoc] -lemma _root_.Submodule.inf_genEigenspace (f : End R M) (p : Submodule R M) {k : ℕ} {μ : R} +lemma _root_.Submodule.inf_genEigenspace (f : End R M) (p : Submodule R M) {k : ℕ∞} {μ : R} (hfp : ∀ x : M, x ∈ p → f x ∈ p) : p ⊓ f.genEigenspace μ k = (genEigenspace (LinearMap.restrict f hfp) μ k).map p.subtype := by rw [f.genEigenspace_restrict _ _ _ hfp, Submodule.map_comap_eq, Submodule.range_subtype] -/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a -submodule `p` which is invariant wrt every `f i`, the intersection of `p` with the simultaneous -maximal generalised eigenspace (taken over all `i`), is the same as the simultaneous maximal -generalised eigenspace of the `f i` restricted to `p`. -/ -lemma _root_.Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo {ι : Type*} {μ : ι → R} - (f : ι → End R M) (p : Submodule R M) (hfp : ∀ i, MapsTo (f i) p p) : - p ⊓ ⨅ i, (f i).maxGenEigenspace (μ i) = - (⨅ i, maxGenEigenspace ((f i).restrict (hfp i)) (μ i)).map p.subtype := by - cases isEmpty_or_nonempty ι - · simp [iInf_of_isEmpty] - · simp_rw [inf_iInf, maxGenEigenspace_def, ((f _).genEigenspace _).mono.directed_le.inf_iSup_eq, - p.inf_genEigenspace _ (hfp _), ← Submodule.map_iSup, Submodule.map_iInf _ p.injective_subtype] - -/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a -distinguished index `i` whose maximal generalised `μ i`-eigenspace is invariant wrt every `f j`, -taking simultaneous maximal generalised eigenspaces is unaffected by first restricting to the -distinguished generalised `μ i`-eigenspace. -/ -lemma iInf_maxGenEigenspace_restrict_map_subtype_eq - {ι : Type*} {μ : ι → R} (i : ι) (f : ι → End R M) - (h : ∀ j, MapsTo (f j) ((f i).maxGenEigenspace (μ i)) ((f i).maxGenEigenspace (μ i))) : - letI p := (f i).maxGenEigenspace (μ i) - letI q (j : ι) := maxGenEigenspace ((f j).restrict (h j)) (μ j) - (⨅ j, q j).map p.subtype = ⨅ j, (f j).maxGenEigenspace (μ j) := by - have : Nonempty ι := ⟨i⟩ - set p := (f i).maxGenEigenspace (μ i) - have : ⨅ j, (f j).maxGenEigenspace (μ j) = p ⊓ ⨅ j, (f j).maxGenEigenspace (μ j) := by - refine le_antisymm ?_ inf_le_right - simpa only [le_inf_iff, le_refl, and_true] using iInf_le _ _ - rw [Submodule.map_iInf _ p.injective_subtype, this, Submodule.inf_iInf] - simp_rw [maxGenEigenspace_def, Submodule.map_iSup, - ((f _).genEigenspace _).mono.directed_le.inf_iSup_eq, p.inf_genEigenspace (f _) (h _)] - lemma mapsTo_restrict_maxGenEigenspace_restrict_of_mapsTo {p : Submodule R M} (f g : End R M) (hf : MapsTo f p p) (hg : MapsTo g p p) {μ₁ μ₂ : R} (h : MapsTo f (g.maxGenEigenspace μ₁) (g.maxGenEigenspace μ₂)) : @@ -849,14 +792,13 @@ theorem generalized_eigenvec_disjoint_range_ker [FiniteDimensional K V] (f : End (f.genEigenspace μ (finrank K V)) = LinearMap.ker ((f - algebraMap _ _ μ) ^ finrank K V * (f - algebraMap K (End K V) μ) ^ finrank K V) := by - rw [genEigenspace, OrderHom.coe_mk, unifEigenspace_nat, ← LinearMap.ker_comp]; rfl - _ = f.genEigenspace μ (finrank K V + finrank K V) := by - rw [← pow_add, genEigenspace, OrderHom.coe_mk, unifEigenspace_nat]; rfl + rw [genEigenspace_nat, ← LinearMap.ker_comp]; rfl + _ = f.genEigenspace μ (finrank K V + finrank K V : ℕ) := by + simp_rw [← pow_add, genEigenspace_nat]; rfl _ = f.genEigenspace μ (finrank K V) := by rw [genEigenspace_eq_genEigenspace_finrank_of_le]; omega - rw [disjoint_iff_inf_le, genEigenrange, unifEigenrange_nat, LinearMap.range_eq_map, - Submodule.map_inf_eq_map_inf_comap, top_inf_eq, h, - genEigenspace, OrderHom.coe_mk, unifEigenspace_nat] + rw [disjoint_iff_inf_le, genEigenrange_nat, LinearMap.range_eq_map, + Submodule.map_inf_eq_map_inf_comap, top_inf_eq, h, genEigenspace_nat] apply Submodule.map_comap_le /-- If an invariant subspace `p` of an endomorphism `f` is disjoint from the `μ`-eigenspace of `f`, @@ -875,7 +817,7 @@ theorem pos_finrank_genEigenspace_of_hasEigenvalue [FiniteDimensional K V] {f : 0 = finrank K (⊥ : Submodule K V) := by rw [finrank_bot] _ < finrank K (f.eigenspace μ) := Submodule.finrank_lt_finrank_of_lt (bot_lt_iff_ne_bot.2 hx) _ ≤ finrank K (f.genEigenspace μ k) := - Submodule.finrank_mono ((f.genEigenspace μ).monotone (Nat.succ_le_of_lt hk)) + Submodule.finrank_mono ((f.genEigenspace μ).monotone (by simpa using Nat.succ_le_of_lt hk)) /-- A linear map maps a generalized eigenrange into itself. -/ theorem map_genEigenrange_le {f : End K V} {μ : K} {n : ℕ} : @@ -883,70 +825,103 @@ theorem map_genEigenrange_le {f : End K V} {μ : K} {n : ℕ} : calc Submodule.map f (f.genEigenrange μ n) = LinearMap.range (f * (f - algebraMap _ _ μ) ^ n) := by - rw [genEigenrange, unifEigenrange_nat]; exact (LinearMap.range_comp _ _).symm + rw [genEigenrange_nat]; exact (LinearMap.range_comp _ _).symm _ = LinearMap.range ((f - algebraMap _ _ μ) ^ n * f) := by rw [Algebra.mul_sub_algebraMap_pow_commutes] _ = Submodule.map ((f - algebraMap _ _ μ) ^ n) (LinearMap.range f) := LinearMap.range_comp _ _ - _ ≤ f.genEigenrange μ n := by - rw [genEigenrange, unifEigenrange_nat] - apply LinearMap.map_le_range + _ ≤ f.genEigenrange μ n := by rw [genEigenrange_nat]; apply LinearMap.map_le_range -lemma iSup_genEigenspace_le_smul (f : Module.End R M) (μ t : R) : - (⨆ k, f.genEigenspace μ k) ≤ ⨆ k, (t • f).genEigenspace (t * μ) k := by +lemma genEigenspace_le_smul (f : Module.End R M) (μ t : R) (k : ℕ∞) : + (f.genEigenspace μ k) ≤ (t • f).genEigenspace (t * μ) k := by intro m hm - simp only [Submodule.mem_iSup_of_chain, mem_genEigenspace] at hm ⊢ - refine Exists.imp (fun k hk ↦ ?_) hm - rw [mul_smul, ← smul_sub, smul_pow, LinearMap.smul_apply, hk, smul_zero] + simp_rw [mem_genEigenspace, ← exists_prop, LinearMap.mem_ker] at hm ⊢ + peel hm with l hlk hl + rw [mul_smul, ← smul_sub, smul_pow, LinearMap.smul_apply, hl, smul_zero] -lemma iSup_genEigenspace_inf_le_add - (f₁ f₂ : End R M) (μ₁ μ₂ : R) (h : Commute f₁ f₂) : - (⨆ k, f₁.genEigenspace μ₁ k) ⊓ (⨆ k, f₂.genEigenspace μ₂ k) ≤ - ⨆ k, (f₁ + f₂).genEigenspace (μ₁ + μ₂) k := by +@[deprecated genEigenspace_le_smul (since := "2024-10-23")] +lemma iSup_genEigenspace_le_smul (f : Module.End R M) (μ t : R) : + (⨆ k : ℕ, f.genEigenspace μ k) ≤ ⨆ k : ℕ, (t • f).genEigenspace (t * μ) k := by + rw [iSup_genEigenspace_eq, iSup_genEigenspace_eq] + apply genEigenspace_le_smul + +lemma genEigenspace_inf_le_add + (f₁ f₂ : End R M) (μ₁ μ₂ : R) (k₁ k₂ : ℕ∞) (h : Commute f₁ f₂) : + (f₁.genEigenspace μ₁ k₁) ⊓ (f₂.genEigenspace μ₂ k₂) ≤ + (f₁ + f₂).genEigenspace (μ₁ + μ₂) (k₁ + k₂) := by intro m hm - simp only [iSup_le_iff, Submodule.mem_inf, Submodule.mem_iSup_of_chain, - mem_genEigenspace] at hm ⊢ - obtain ⟨⟨k₁, hk₁⟩, ⟨k₂, hk₂⟩⟩ := hm - use k₁ + k₂ - 1 + simp only [Submodule.mem_inf, mem_genEigenspace, LinearMap.mem_ker] at hm ⊢ + obtain ⟨⟨l₁, hlk₁, hl₁⟩, ⟨l₂, hlk₂, hl₂⟩⟩ := hm + use l₁ + l₂ have : f₁ + f₂ - (μ₁ + μ₂) • 1 = (f₁ - μ₁ • 1) + (f₂ - μ₂ • 1) := by rw [add_smul]; exact add_sub_add_comm f₁ f₂ (μ₁ • 1) (μ₂ • 1) replace h : Commute (f₁ - μ₁ • 1) (f₂ - μ₂ • 1) := (h.sub_right <| Algebra.commute_algebraMap_right μ₂ f₁).sub_left (Algebra.commute_algebraMap_left μ₁ _) rw [this, h.add_pow', LinearMap.coeFn_sum, Finset.sum_apply] + constructor + · simpa only [Nat.cast_add] using add_le_add hlk₁ hlk₂ refine Finset.sum_eq_zero fun ⟨i, j⟩ hij ↦ ?_ suffices (((f₁ - μ₁ • 1) ^ i) * ((f₂ - μ₂ • 1) ^ j)) m = 0 by rw [LinearMap.smul_apply, this, smul_zero] - cases' Nat.le_or_le_of_add_eq_add_pred (Finset.mem_antidiagonal.mp hij) with hi hj - · rw [(h.pow_pow i j).eq, LinearMap.mul_apply, LinearMap.pow_map_zero_of_le hi hk₁, + rw [Finset.mem_antidiagonal] at hij + obtain hi|hj : l₁ ≤ i ∨ l₂ ≤ j := by omega + · rw [(h.pow_pow i j).eq, LinearMap.mul_apply, LinearMap.pow_map_zero_of_le hi hl₁, LinearMap.map_zero] - · rw [LinearMap.mul_apply, LinearMap.pow_map_zero_of_le hj hk₂, LinearMap.map_zero] + · rw [LinearMap.mul_apply, LinearMap.pow_map_zero_of_le hj hl₂, LinearMap.map_zero] + +@[deprecated genEigenspace_inf_le_add (since := "2024-10-23")] +lemma iSup_genEigenspace_inf_le_add + (f₁ f₂ : End R M) (μ₁ μ₂ : R) (h : Commute f₁ f₂) : + (⨆ k : ℕ, f₁.genEigenspace μ₁ k) ⊓ (⨆ k : ℕ, f₂.genEigenspace μ₂ k) ≤ + ⨆ k : ℕ, (f₁ + f₂).genEigenspace (μ₁ + μ₂) k := by + simp_rw [iSup_genEigenspace_eq] + apply genEigenspace_inf_le_add + assumption lemma map_smul_of_iInf_genEigenspace_ne_bot [NoZeroSMulDivisors R M] {L F : Type*} [SMul R L] [FunLike F L (End R M)] [MulActionHomClass F R L (End R M)] (f : F) - (μ : L → R) (h_ne : ⨅ x, ⨆ k, (f x).genEigenspace (μ x) k ≠ ⊥) + (μ : L → R) (k : ℕ∞) (h_ne : ⨅ x, (f x).genEigenspace (μ x) k ≠ ⊥) (t : R) (x : L) : μ (t • x) = t • μ x := by by_contra contra - let g : L → Submodule R M := fun x ↦ ⨆ k, (f x).genEigenspace (μ x) k + let g : L → Submodule R M := fun x ↦ (f x).genEigenspace (μ x) k have : ⨅ x, g x ≤ g x ⊓ g (t • x) := le_inf_iff.mpr ⟨iInf_le g x, iInf_le g (t • x)⟩ refine h_ne <| eq_bot_iff.mpr (le_trans this (disjoint_iff_inf_le.mp ?_)) - apply Disjoint.mono_left (iSup_genEigenspace_le_smul (f x) (μ x) t) + apply Disjoint.mono_left (genEigenspace_le_smul (f x) (μ x) t k) simp only [g, map_smul] - exact disjoint_iSup_genEigenspace (t • f x) (Ne.symm contra) + exact disjoint_genEigenspace (t • f x) (Ne.symm contra) k k + +@[deprecated map_smul_of_iInf_genEigenspace_ne_bot (since := "2024-10-23")] +lemma map_smul_of_iInf_iSup_genEigenspace_ne_bot [NoZeroSMulDivisors R M] + {L F : Type*} [SMul R L] [FunLike F L (End R M)] [MulActionHomClass F R L (End R M)] (f : F) + (μ : L → R) (h_ne : ⨅ x, ⨆ k : ℕ, (f x).genEigenspace (μ x) k ≠ ⊥) + (t : R) (x : L) : + μ (t • x) = t • μ x := by + simp_rw [iSup_genEigenspace_eq] at h_ne + apply map_smul_of_iInf_genEigenspace_ne_bot f μ ⊤ h_ne t x lemma map_add_of_iInf_genEigenspace_ne_bot_of_commute [NoZeroSMulDivisors R M] {L F : Type*} [Add L] [FunLike F L (End R M)] [AddHomClass F L (End R M)] (f : F) - (μ : L → R) (h_ne : ⨅ x, ⨆ k, (f x).genEigenspace (μ x) k ≠ ⊥) + (μ : L → R) (k : ℕ∞) (h_ne : ⨅ x, (f x).genEigenspace (μ x) k ≠ ⊥) (h : ∀ x y, Commute (f x) (f y)) (x y : L) : μ (x + y) = μ x + μ y := by by_contra contra - let g : L → Submodule R M := fun x ↦ ⨆ k, (f x).genEigenspace (μ x) k + let g : L → Submodule R M := fun x ↦ (f x).genEigenspace (μ x) k have : ⨅ x, g x ≤ (g x ⊓ g y) ⊓ g (x + y) := le_inf_iff.mpr ⟨le_inf_iff.mpr ⟨iInf_le g x, iInf_le g y⟩, iInf_le g (x + y)⟩ refine h_ne <| eq_bot_iff.mpr (le_trans this (disjoint_iff_inf_le.mp ?_)) - apply Disjoint.mono_left (iSup_genEigenspace_inf_le_add (f x) (f y) (μ x) (μ y) (h x y)) + apply Disjoint.mono_left (genEigenspace_inf_le_add (f x) (f y) (μ x) (μ y) k k (h x y)) simp only [g, map_add] - exact disjoint_iSup_genEigenspace (f x + f y) (Ne.symm contra) + exact disjoint_genEigenspace (f x + f y) (Ne.symm contra) _ k + +@[deprecated map_add_of_iInf_genEigenspace_ne_bot_of_commute (since := "2024-10-23")] +lemma map_add_of_iInf_iSup_genEigenspace_ne_bot_of_commute [NoZeroSMulDivisors R M] + {L F : Type*} [Add L] [FunLike F L (End R M)] [AddHomClass F L (End R M)] (f : F) + (μ : L → R) (h_ne : ⨅ x, ⨆ k : ℕ, (f x).genEigenspace (μ x) k ≠ ⊥) + (h : ∀ x y, Commute (f x) (f y)) (x y : L) : + μ (x + y) = μ x + μ y := by + simp_rw [iSup_genEigenspace_eq] at h_ne + apply map_add_of_iInf_genEigenspace_ne_bot_of_commute f μ ⊤ h_ne h x y end End diff --git a/Mathlib/LinearAlgebra/Eigenspace/Pi.lean b/Mathlib/LinearAlgebra/Eigenspace/Pi.lean new file mode 100644 index 0000000000000..73c18265d61ab --- /dev/null +++ b/Mathlib/LinearAlgebra/Eigenspace/Pi.lean @@ -0,0 +1,192 @@ +/- +Copyright (c) 2024 Oliver Nash. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Oliver Nash +-/ +import Mathlib.LinearAlgebra.Eigenspace.Triangularizable + +/-! +# Simultaneous eigenvectors and eigenvalues for families of endomorphisms + +In finite dimensions, the theory of simultaneous eigenvalues for a family of linear endomorphisms +`i ↦ f i` enjoys similar properties to that of a single endomorphism, provided the family obeys a +compatibilty condition. This condition is that the maximum generalised eigenspaces of each +endomorphism are invariant under the action of all members of the family. It is trivially satisfied +for commuting endomorphisms but there are important more general situations where it also holds +(e.g., representations of nilpotent Lie algebras). + +## Main definitions / results + * `Module.End.independent_iInf_maxGenEigenspace_of_forall_mapsTo`: the simultaneous generalised + eigenspaces of a compatible family of endomorphisms are independent. + * `Module.End.iSup_iInf_maxGenEigenspace_eq_top_of_forall_mapsTo`: in finite dimensions, the + simultaneous generalised eigenspaces of a compatible family of endomorphisms span if the same + is true of each map individually. + +-/ + +open Function Set + +namespace Module.End + +variable {ι R K M : Type*} [CommRing R] [Field K] [AddCommGroup M] [Module R M] [Module K M] + (f : ι → End R M) + +theorem mem_iInf_maxGenEigenspace_iff (χ : ι → R) (m : M) : + m ∈ ⨅ i, (f i).maxGenEigenspace (χ i) ↔ ∀ j, ∃ k : ℕ, ((f j - χ j • ↑1) ^ k) m = 0 := by + simp + +/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a +submodule `p` which is invariant wrt every `f i`, the intersection of `p` with the simultaneous +maximal generalised eigenspace (taken over all `i`), is the same as the simultaneous maximal +generalised eigenspace of the `f i` restricted to `p`. -/ +lemma _root_.Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo {μ : ι → R} + (p : Submodule R M) (hfp : ∀ i, MapsTo (f i) p p) : + p ⊓ ⨅ i, (f i).maxGenEigenspace (μ i) = + (⨅ i, maxGenEigenspace ((f i).restrict (hfp i)) (μ i)).map p.subtype := by + cases isEmpty_or_nonempty ι + · simp [iInf_of_isEmpty] + · simp_rw [inf_iInf, p.inf_genEigenspace _ (hfp _), Submodule.map_iInf _ p.injective_subtype] + +/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a +distinguished index `i` whose maximal generalised `μ i`-eigenspace is invariant wrt every `f j`, +taking simultaneous maximal generalised eigenspaces is unaffected by first restricting to the +distinguished generalised `μ i`-eigenspace. -/ +lemma iInf_maxGenEigenspace_restrict_map_subtype_eq + {μ : ι → R} (i : ι) + (h : ∀ j, MapsTo (f j) ((f i).maxGenEigenspace (μ i)) ((f i).maxGenEigenspace (μ i))) : + letI p := (f i).maxGenEigenspace (μ i) + letI q (j : ι) := maxGenEigenspace ((f j).restrict (h j)) (μ j) + (⨅ j, q j).map p.subtype = ⨅ j, (f j).maxGenEigenspace (μ j) := by + have : Nonempty ι := ⟨i⟩ + set p := (f i).maxGenEigenspace (μ i) + have : ⨅ j, (f j).maxGenEigenspace (μ j) = p ⊓ ⨅ j, (f j).maxGenEigenspace (μ j) := by + refine le_antisymm ?_ inf_le_right + simpa only [le_inf_iff, le_refl, and_true] using iInf_le _ _ + rw [Submodule.map_iInf _ p.injective_subtype, this, Submodule.inf_iInf] + conv_rhs => + enter [1] + ext + rw [p.inf_genEigenspace (f _) (h _)] + +variable [NoZeroSMulDivisors R M] + +lemma disjoint_iInf_maxGenEigenspace {χ₁ χ₂ : ι → R} (h : χ₁ ≠ χ₂) : + Disjoint (⨅ i, (f i).maxGenEigenspace (χ₁ i)) (⨅ i, (f i).maxGenEigenspace (χ₂ i)) := by + obtain ⟨j, hj⟩ : ∃ j, χ₁ j ≠ χ₂ j := Function.ne_iff.mp h + exact (End.disjoint_genEigenspace (f j) hj ⊤ ⊤).mono (iInf_le _ j) (iInf_le _ j) + +lemma injOn_iInf_maxGenEigenspace : + InjOn (fun χ : ι → R ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) + {χ | ⨅ i, (f i).maxGenEigenspace (χ i) ≠ ⊥} := by + rintro χ₁ _ χ₂ + hχ₂ (hχ₁₂ : ⨅ i, (f i).maxGenEigenspace (χ₁ i) = ⨅ i, (f i).maxGenEigenspace (χ₂ i)) + contrapose! hχ₂ + simpa [hχ₁₂] using disjoint_iInf_maxGenEigenspace f hχ₂ + +lemma independent_iInf_maxGenEigenspace_of_forall_mapsTo + (h : ∀ i j φ, MapsTo (f i) ((f j).maxGenEigenspace φ) ((f j).maxGenEigenspace φ)) : + CompleteLattice.Independent fun χ : ι → R ↦ ⨅ i, (f i).maxGenEigenspace (χ i) := by + replace h (l : ι) (χ : ι → R) : + MapsTo (f l) (⨅ i, (f i).maxGenEigenspace (χ i)) (⨅ i, (f i).maxGenEigenspace (χ i)) := by + intro x hx + simp only [iInf_eq_iInter, mem_iInter, SetLike.mem_coe] at hx ⊢ + exact fun i ↦ h l i (χ i) (hx i) + classical + suffices ∀ χ (s : Finset (ι → R)) (_ : χ ∉ s), + Disjoint (⨅ i, (f i).maxGenEigenspace (χ i)) + (s.sup fun (χ : ι → R) ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) by + simpa only [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_iInf_maxGenEigenspace f), + Finset.supIndep_iff_disjoint_erase] using fun s χ _ ↦ this _ _ (s.not_mem_erase χ) + intro χ₁ s + induction s using Finset.induction_on with + | empty => simp + | insert _n ih => + rename_i χ₂ s + intro hχ₁₂ + obtain ⟨hχ₁₂ : χ₁ ≠ χ₂, hχ₁ : χ₁ ∉ s⟩ := by rwa [Finset.mem_insert, not_or] at hχ₁₂ + specialize ih hχ₁ + rw [Finset.sup_insert, disjoint_iff, Submodule.eq_bot_iff] + rintro x ⟨hx, hx'⟩ + simp only [SetLike.mem_coe] at hx hx' + suffices x ∈ ⨅ i, (f i).maxGenEigenspace (χ₂ i) by + rw [← Submodule.mem_bot (R := R), ← (disjoint_iInf_maxGenEigenspace f hχ₁₂).eq_bot] + exact ⟨hx, this⟩ + obtain ⟨y, hy, z, hz, rfl⟩ := Submodule.mem_sup.mp hx'; clear hx' + suffices ∀ l, ∃ (k : ℕ), + ((f l - algebraMap R (Module.End R M) (χ₂ l)) ^ k) (y + z) ∈ + (⨅ i, (f i).maxGenEigenspace (χ₁ i)) ⊓ + Finset.sup s fun χ ↦ ⨅ i, (f i).maxGenEigenspace (χ i) by + simpa [ih.eq_bot, Submodule.mem_bot] using this + intro l + let g : Module.End R M := f l - algebraMap R (Module.End R M) (χ₂ l) + obtain ⟨k, hk : (g ^ k) y = 0⟩ := (mem_iInf_maxGenEigenspace_iff _ _ _).mp hy l + have aux (f : End R M) (φ : R) (k : ℕ) (p : Submodule R M) (hp : MapsTo f p p) : + MapsTo ((f - algebraMap R (Module.End R M) φ) ^ k) p p := by + rw [LinearMap.coe_pow] + exact MapsTo.iterate (fun m hm ↦ p.sub_mem (hp hm) (p.smul_mem _ hm)) k + refine ⟨k, Submodule.mem_inf.mp ⟨?_, ?_⟩⟩ + · refine aux (f l) (χ₂ l) k (⨅ i, (f i).maxGenEigenspace (χ₁ i)) ?_ hx + simp only [Submodule.iInf_coe] + exact h l χ₁ + · rw [map_add, hk, zero_add] + suffices (s.sup fun χ ↦ (⨅ i, (f i).maxGenEigenspace (χ i))).map (g ^ k) ≤ + s.sup fun χ ↦ (⨅ i, (f i).maxGenEigenspace (χ i)) by + refine this (Submodule.mem_map_of_mem ?_) + simp_rw [Finset.sup_eq_iSup, ← Finset.sup_eq_iSup] at hz + exact hz + simp_rw [Finset.sup_eq_iSup, Submodule.map_iSup (ι := ι → R), Submodule.map_iSup (ι := _ ∈ s)] + refine iSup₂_mono fun χ _ ↦ ?_ + rintro - ⟨u, hu, rfl⟩ + refine aux (f l) (χ₂ l) k (⨅ i, (f i).maxGenEigenspace (χ i)) ?_ hu + simp only [Submodule.iInf_coe] + exact h l χ + +/-- Given a family of endomorphisms `i ↦ f i` which are compatible in the sense that every maximal +generalised eigenspace of `f i` is invariant wrt `f j`, if each `f i` is triangularizable, the +family is simultaneously triangularizable. -/ +lemma iSup_iInf_maxGenEigenspace_eq_top_of_forall_mapsTo [FiniteDimensional K M] + (f : ι → End K M) + (h : ∀ i j φ, MapsTo (f i) ((f j).maxGenEigenspace φ) ((f j).maxGenEigenspace φ)) + (h' : ∀ i, ⨆ μ, (f i).maxGenEigenspace μ = ⊤) : + ⨆ χ : ι → K, ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by + generalize h_dim : finrank K M = n + induction n using Nat.strongRecOn generalizing M with | ind n ih => ?_ + obtain this | ⟨i : ι, hy : ¬ ∃ φ, (f i).maxGenEigenspace φ = ⊤⟩ := + forall_or_exists_not (fun j : ι ↦ ∃ φ : K, (f j).maxGenEigenspace φ = ⊤) + · choose χ hχ using this + replace hχ : ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by simpa + simp_rw [eq_top_iff] at hχ ⊢ + exact le_trans hχ <| le_iSup (fun χ : ι → K ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) χ + · replace hy : ∀ φ, finrank K ((f i).maxGenEigenspace φ) < n := fun φ ↦ by + simp_rw [not_exists, ← lt_top_iff_ne_top] at hy; exact h_dim ▸ Submodule.finrank_lt (hy φ) + have hi (j : ι) (φ : K) : + MapsTo (f j) ((f i).maxGenEigenspace φ) ((f i).maxGenEigenspace φ) := by + exact h j i φ + replace ih (φ : K) : + ⨆ χ : ι → K, ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by + apply ih _ (hy φ) + · intro j k μ + exact mapsTo_restrict_maxGenEigenspace_restrict_of_mapsTo (f j) (f k) _ _ (h j k μ) + · exact fun j ↦ Module.End.genEigenspace_restrict_eq_top _ (h' j) + · rfl + replace ih (φ : K) : + ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by + suffices ∀ χ : ι → K, χ i ≠ φ → ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊥ by + specialize ih φ; rw [iSup_split, biSup_congr this] at ih; simpa using ih + intro χ hχ + rw [eq_bot_iff, ← ((f i).maxGenEigenspace φ).ker_subtype, LinearMap.ker, + ← Submodule.map_le_iff_le_comap, ← Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo, + ← disjoint_iff_inf_le] + exact ((f i).disjoint_genEigenspace hχ.symm _ _).mono_right (iInf_le _ i) + replace ih (φ : K) : + ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace (f j) (χ j) = + maxGenEigenspace (f i) φ := by + have (χ : ι → K) (hχ : χ i = φ) : ⨅ j, maxGenEigenspace (f j) (χ j) = + (⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j)).map + ((f i).maxGenEigenspace φ).subtype := by + rw [← hχ, iInf_maxGenEigenspace_restrict_map_subtype_eq] + simp_rw [biSup_congr this, ← Submodule.map_iSup, ih, Submodule.map_top, + Submodule.range_subtype] + simpa only [← ih, iSup_comm (ι := K), iSup_iSup_eq_right] using h' i + +end Module.End diff --git a/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean b/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean index aefced273795c..bf60fd45e813a 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean @@ -25,37 +25,41 @@ namespace Module.End variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] {f g : End R M} -lemma apply_eq_of_mem_genEigenspace_of_comm_of_isSemisimple_of_isNilpotent_sub - {μ : R} {k : ℕ} {m : M} (hm : m ∈ f.genEigenspace μ k) - (hfg : Commute f g) (hss : g.IsSemisimple) (hnil : IsNilpotent (f - g)) : +lemma apply_eq_of_mem_of_comm_of_isFinitelySemisimple_of_isNil + {μ : R} {k : ℕ∞} {m : M} (hm : m ∈ f.genEigenspace μ k) + (hfg : Commute f g) (hss : g.IsFinitelySemisimple) (hnil : IsNilpotent (f - g)) : g m = μ • m := by - set p := f.genEigenspace μ k - have h₁ : MapsTo g p p := mapsTo_genEigenspace_of_comm hfg μ k + rw [f.mem_genEigenspace] at hm + obtain ⟨l, -, hm⟩ := hm + rw [← f.mem_genEigenspace_nat] at hm + set p := f.genEigenspace μ l + have h₁ : MapsTo g p p := mapsTo_genEigenspace_of_comm hfg μ l have h₂ : MapsTo (g - algebraMap R (End R M) μ) p p := - mapsTo_genEigenspace_of_comm (hfg.sub_right <| Algebra.commute_algebraMap_right μ f) μ k + mapsTo_genEigenspace_of_comm (hfg.sub_right <| Algebra.commute_algebraMap_right μ f) μ l have h₃ : MapsTo (f - g) p p := - mapsTo_genEigenspace_of_comm (Commute.sub_right rfl hfg) μ k + mapsTo_genEigenspace_of_comm (Commute.sub_right rfl hfg) μ l have h₄ : MapsTo (f - algebraMap R (End R M) μ) p p := - mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ k + mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ l replace hfg : Commute (f - algebraMap R (End R M) μ) (f - g) := (Commute.sub_right rfl hfg).sub_left <| Algebra.commute_algebraMap_left μ (f - g) suffices IsNilpotent ((g - algebraMap R (End R M) μ).restrict h₂) by replace this : g.restrict h₁ - algebraMap R (End R p) μ = 0 := - eq_zero_of_isNilpotent_isSemisimple this (by simpa using hss.restrict) + eq_zero_of_isNilpotent_of_isFinitelySemisimple this (by simpa using hss.restrict _) simpa [LinearMap.restrict_apply, sub_eq_zero] using LinearMap.congr_fun this ⟨m, hm⟩ simpa [LinearMap.restrict_sub h₄ h₃] using (LinearMap.restrict_commute hfg h₄ h₃).isNilpotent_sub - (f.isNilpotent_restrict_sub_algebraMap μ k) (Module.End.isNilpotent.restrict h₃ hnil) + (f.isNilpotent_restrict_sub_algebraMap μ l) (Module.End.isNilpotent.restrict h₃ hnil) -lemma IsSemisimple.genEigenspace_eq_eigenspace - (hf : f.IsSemisimple) (μ : R) {k : ℕ} (hk : 0 < k) : +lemma IsFinitelySemisimple.genEigenspace_eq_eigenspace + (hf : f.IsFinitelySemisimple) (μ : R) {k : ℕ∞} (hk : 0 < k) : f.genEigenspace μ k = f.eigenspace μ := by - refine le_antisymm (fun m hm ↦ mem_eigenspace_iff.mpr ?_) (eigenspace_le_genEigenspace hk) - exact apply_eq_of_mem_genEigenspace_of_comm_of_isSemisimple_of_isNilpotent_sub hm rfl hf (by simp) - -lemma IsSemisimple.maxGenEigenspace_eq_eigenspace - (hf : f.IsSemisimple) (μ : R) : - f.maxGenEigenspace μ = f.eigenspace μ := by - simp_rw [maxGenEigenspace_def, ← (f.genEigenspace μ).monotone.iSup_nat_add 1, - hf.genEigenspace_eq_eigenspace μ (Nat.zero_lt_succ _), ciSup_const] + refine le_antisymm (fun m hm ↦ mem_eigenspace_iff.mpr ?_) (f.genEigenspace μ |>.mono ?_) + · apply apply_eq_of_mem_of_comm_of_isFinitelySemisimple_of_isNil hm rfl hf + simp + · exact Order.one_le_iff_pos.mpr hk + +lemma IsFinitelySemisimple.maxGenEigenspace_eq_eigenspace + (hf : f.IsFinitelySemisimple) (μ : R) : + f.maxGenEigenspace μ = f.eigenspace μ := + hf.genEigenspace_eq_eigenspace μ ENat.top_pos end Module.End diff --git a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean index 03e4ac0132b66..76112cc06a755 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean @@ -45,16 +45,20 @@ variable {K V : Type*} [Field K] [AddCommGroup V] [Module K V] namespace Module.End +theorem exists_hasEigenvalue_of_genEigenspace_eq_top [Nontrivial M] {f : End R M} (k : ℕ∞) + (hf : ⨆ μ, f.genEigenspace μ k = ⊤) : + ∃ μ, f.HasEigenvalue μ := by + suffices ∃ μ, f.HasUnifEigenvalue μ k by + peel this with μ hμ + exact HasUnifEigenvalue.lt zero_lt_one hμ + simp [HasUnifEigenvalue, ← not_forall, ← iSup_eq_bot, hf] + +@[deprecated exists_hasEigenvalue_of_genEigenspace_eq_top (since := "2024-10-11")] theorem exists_hasEigenvalue_of_iSup_genEigenspace_eq_top [Nontrivial M] {f : End R M} - (hf : ⨆ μ, ⨆ k, f.genEigenspace μ k = ⊤) : + (hf : ⨆ μ, ⨆ k : ℕ, f.genEigenspace μ k = ⊤) : ∃ μ, f.HasEigenvalue μ := by - by_contra! contra - suffices ∀ μ, ⨆ k, f.genEigenspace μ k = ⊥ by simp [this] at hf - intro μ - replace contra : ∀ k, f.genEigenspace μ k = ⊥ := fun k ↦ by - have hk : ¬ f.HasGenEigenvalue μ k := fun hk ↦ contra μ (f.hasEigenvalue_of_hasGenEigenvalue hk) - rwa [hasGenEigenvalue_iff, not_not] at hk - simp [contra] + simp_rw [iSup_genEigenspace_eq] at hf + apply exists_hasEigenvalue_of_genEigenspace_eq_top _ hf -- This is Lemma 5.21 of [axler2015], although we are no longer following that proof. /-- In finite dimensions, over an algebraically closed field, every linear endomorphism has an @@ -71,8 +75,8 @@ noncomputable instance [IsAlgClosed K] [FiniteDimensional K V] [Nontrivial V] (f -- Lemma 8.21 of [axler2015] /-- In finite dimensions, over an algebraically closed field, the generalized eigenspaces of any linear endomorphism span the whole space. -/ -theorem iSup_genEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f : End K V) : - ⨆ (μ : K) (k : ℕ), f.genEigenspace μ k = ⊤ := by +theorem iSup_maxGenEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f : End K V) : + ⨆ (μ : K), f.maxGenEigenspace μ = ⊤ := by -- We prove the claim by strong induction on the dimension of the vector space. induction' h_dim : finrank K V using Nat.strong_induction_on with n ih generalizing V cases' n with n @@ -100,62 +104,73 @@ theorem iSup_genEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f : E -- and the dimensions of `ES` and `ER` add up to `finrank K V`. have h_dim_add : finrank K ER + finrank K ES = finrank K V := by dsimp only [ER, ES] - rw [Module.End.genEigenspace_def, Module.End.genEigenrange_def] + rw [Module.End.genEigenspace_nat, Module.End.genEigenrange_nat] apply LinearMap.finrank_range_add_finrank_ker -- Therefore the dimension `ER` mus be smaller than `finrank K V`. have h_dim_ER : finrank K ER < n.succ := by linarith -- This allows us to apply the induction hypothesis on `ER`: - have ih_ER : ⨆ (μ : K) (k : ℕ), f'.genEigenspace μ k = ⊤ := + have ih_ER : ⨆ (μ : K), f'.maxGenEigenspace μ = ⊤ := ih (finrank K ER) h_dim_ER f' rfl -- The induction hypothesis gives us a statement about subspaces of `ER`. We can transfer this -- to a statement about subspaces of `V` via `Submodule.subtype`: - have ih_ER' : ⨆ (μ : K) (k : ℕ), (f'.genEigenspace μ k).map ER.subtype = ER := by + have ih_ER' : ⨆ (μ : K), (f'.maxGenEigenspace μ).map ER.subtype = ER := by simp only [(Submodule.map_iSup _ _).symm, ih_ER, Submodule.map_subtype_top ER] -- Moreover, every generalized eigenspace of `f'` is contained in the corresponding generalized -- eigenspace of `f`. have hff' : - ∀ μ k, (f'.genEigenspace μ k).map ER.subtype ≤ f.genEigenspace μ k := by + ∀ μ, (f'.maxGenEigenspace μ).map ER.subtype ≤ f.maxGenEigenspace μ := by intros - rw [genEigenspace_restrict] + rw [maxGenEigenspace, genEigenspace_restrict] apply Submodule.map_comap_le -- It follows that `ER` is contained in the span of all generalized eigenvectors. - have hER : ER ≤ ⨆ (μ : K) (k : ℕ), f.genEigenspace μ k := by + have hER : ER ≤ ⨆ (μ : K), f.maxGenEigenspace μ := by rw [← ih_ER'] - exact iSup₂_mono hff' + exact iSup_mono hff' -- `ES` is contained in this span by definition. - have hES : ES ≤ ⨆ (μ : K) (k : ℕ), f.genEigenspace μ k := - le_trans (le_iSup (fun k => f.genEigenspace μ₀ k) (finrank K V)) - (le_iSup (fun μ : K => ⨆ k : ℕ, f.genEigenspace μ k) μ₀) + have hES : ES ≤ ⨆ (μ : K), f.maxGenEigenspace μ := + ((f.genEigenspace μ₀).mono le_top).trans (le_iSup f.maxGenEigenspace μ₀) -- Moreover, we know that `ER` and `ES` are disjoint. have h_disjoint : Disjoint ER ES := generalized_eigenvec_disjoint_range_ker 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) (k : ℕ), f.genEigenspace μ k = ⊤ + show ⨆ (μ : K), f.maxGenEigenspace μ = ⊤ rw [← top_le_iff, ← Submodule.eq_top_of_disjoint ER ES h_dim_add h_disjoint] apply sup_le hER hES +-- Lemma 8.21 of [axler2015] +/-- In finite dimensions, over an algebraically closed field, the generalized eigenspaces of any +linear endomorphism span the whole space. -/ +@[deprecated iSup_maxGenEigenspace_eq_top (since := "2024-10-11")] +theorem iSup_genEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f : End K V) : + ⨆ (μ : K) (k : ℕ), f.genEigenspace μ k = ⊤ := by + simp_rw [iSup_genEigenspace_eq] + apply iSup_maxGenEigenspace_eq_top + end Module.End namespace Submodule variable {p : Submodule K V} {f : Module.End K V} -theorem inf_iSup_genEigenspace [FiniteDimensional K V] (h : ∀ x ∈ p, f x ∈ p) : - p ⊓ ⨆ μ, ⨆ k, f.genEigenspace μ k = ⨆ μ, ⨆ k, p ⊓ f.genEigenspace μ k := by - simp_rw [← (f.genEigenspace _).mono.directed_le.inf_iSup_eq] +theorem inf_iSup_genEigenspace [FiniteDimensional K V] (h : ∀ x ∈ p, f x ∈ p) (k : ℕ∞) : + p ⊓ ⨆ μ, f.genEigenspace μ k = ⨆ μ, p ⊓ f.genEigenspace μ k := by refine le_antisymm (fun m hm ↦ ?_) (le_inf_iff.mpr ⟨iSup_le fun μ ↦ inf_le_left, iSup_mono fun μ ↦ inf_le_right⟩) classical - obtain ⟨hm₀ : m ∈ p, hm₁ : m ∈ ⨆ μ, ⨆ k, f.genEigenspace μ k⟩ := hm + obtain ⟨hm₀ : m ∈ p, hm₁ : m ∈ ⨆ μ, f.genEigenspace μ k⟩ := hm obtain ⟨m, hm₂, rfl⟩ := (mem_iSup_iff_exists_finsupp _ _).mp hm₁ suffices ∀ μ, (m μ : V) ∈ p by exact (mem_iSup_iff_exists_finsupp _ _).mpr ⟨m, fun μ ↦ mem_inf.mp ⟨this μ, hm₂ μ⟩, rfl⟩ intro μ by_cases hμ : μ ∈ m.support; swap · simp only [Finsupp.not_mem_support_iff.mp hμ, p.zero_mem] + have hm₂_aux := hm₂ + simp_rw [Module.End.mem_genEigenspace] at hm₂_aux + choose l hlk hl using hm₂_aux + let l₀ : ℕ := m.support.sup l have h_comm : ∀ (μ₁ μ₂ : K), - Commute ((f - algebraMap K (End K V) μ₁) ^ finrank K V) - ((f - algebraMap K (End K V) μ₂) ^ finrank K V) := fun μ₁ μ₂ ↦ + Commute ((f - algebraMap K (End K V) μ₁) ^ l₀) + ((f - algebraMap K (End K V) μ₂) ^ l₀) := fun μ₁ μ₂ ↦ ((Commute.sub_right rfl <| Algebra.commute_algebraMap_right _ _).sub_left (Algebra.commute_algebraMap_left _ _)).pow_pow _ _ let g : End K V := (m.support.erase μ).noncommProd _ fun μ₁ _ μ₂ _ _ ↦ h_comm μ₁ μ₂ @@ -168,108 +183,83 @@ theorem inf_iSup_genEigenspace [FiniteDimensional K V] (h : ∀ x ∈ p, f x ∈ rintro μ' hμ' split_ifs with hμμ' · rw [hμμ'] - replace hm₂ : ((f - algebraMap K (End K V) μ') ^ finrank K V) (m μ') = 0 := by - obtain ⟨k, hk⟩ := (mem_iSup_of_chain _ _).mp (hm₂ μ') - simpa only [End.mem_genEigenspace] using - Module.End.genEigenspace_le_genEigenspace_finrank _ _ k hk + have hl₀ : ((f - algebraMap K (End K V) μ') ^ l₀) (m μ') = 0 := by + rw [← LinearMap.mem_ker, Algebra.algebraMap_eq_smul_one, ← End.mem_genEigenspace_nat] + simp_rw [← End.mem_genEigenspace_nat] at hl + suffices (l μ' : ℕ∞) ≤ l₀ from (f.genEigenspace μ').mono this (hl μ') + simpa only [Nat.cast_le] using Finset.le_sup hμ' have : _ = g := (m.support.erase μ).noncommProd_erase_mul (Finset.mem_erase.mpr ⟨hμμ', hμ'⟩) - (fun μ ↦ (f - algebraMap K (End K V) μ) ^ finrank K V) (fun μ₁ _ μ₂ _ _ ↦ h_comm μ₁ μ₂) - rw [← this, LinearMap.mul_apply, hm₂, _root_.map_zero] + (fun μ ↦ (f - algebraMap K (End K V) μ) ^ l₀) (fun μ₁ _ μ₂ _ _ ↦ h_comm μ₁ μ₂) + rw [← this, LinearMap.mul_apply, hl₀, _root_.map_zero] have hg₁ : MapsTo g p p := Finset.noncommProd_induction _ _ _ (fun g' : End K V ↦ MapsTo g' p p) (fun f₁ f₂ ↦ MapsTo.comp) (mapsTo_id _) fun μ' _ ↦ by suffices MapsTo (f - algebraMap K (End K V) μ') p p by - simp only [LinearMap.coe_pow]; exact this.iterate (finrank K V) + simp only [LinearMap.coe_pow]; exact this.iterate l₀ intro x hx rw [LinearMap.sub_apply, algebraMap_end_apply] exact p.sub_mem (h _ hx) (smul_mem p μ' hx) - have hg₂ : MapsTo g ↑(⨆ k, f.genEigenspace μ k) ↑(⨆ k, f.genEigenspace μ k) := - f.mapsTo_iSup_genEigenspace_of_comm hfg μ - have hg₃ : InjOn g ↑(⨆ k, f.genEigenspace μ k) := by + have hg₂ : MapsTo g ↑(f.genEigenspace μ k) ↑(f.genEigenspace μ k) := + f.mapsTo_genEigenspace_of_comm hfg μ k + have hg₃ : InjOn g ↑(f.genEigenspace μ k) := by apply LinearMap.injOn_of_disjoint_ker (subset_refl _) - have this := f.independent_genEigenspace - simp_rw [f.iSup_genEigenspace_eq_genEigenspace_finrank] at this ⊢ + have this := f.independent_genEigenspace k + have aux (μ') (_hμ' : μ' ∈ m.support.erase μ) : + (f.genEigenspace μ') ↑l₀ ≤ (f.genEigenspace μ') k := by + apply (f.genEigenspace μ').mono + rintro k rfl + simp only [ENat.some_eq_coe, Nat.cast_inj, exists_eq_left'] + apply Finset.sup_le + intro i _hi + simpa using hlk i rw [LinearMap.ker_noncommProd_eq_of_supIndep_ker, ← Finset.sup_eq_iSup] - · simpa only [End.genEigenspace_def] using - Finset.supIndep_iff_disjoint_erase.mp (this.supIndep' m.support) μ hμ - · simpa only [End.genEigenspace_def] using this.supIndep' (m.support.erase μ) + · have := Finset.supIndep_iff_disjoint_erase.mp (this.supIndep' m.support) μ hμ + apply this.mono_right + apply Finset.sup_mono_fun + intro μ' hμ' + rw [Algebra.algebraMap_eq_smul_one, ← End.genEigenspace_nat] + apply aux μ' hμ' + · have := this.supIndep' (m.support.erase μ) + apply Finset.supIndep_antimono_fun _ this + intro μ' hμ' + rw [Algebra.algebraMap_eq_smul_one, ← End.genEigenspace_nat] + apply aux μ' hμ' have hg₄ : SurjOn g - ↑(p ⊓ ⨆ k, f.genEigenspace μ k) ↑(p ⊓ ⨆ k, f.genEigenspace μ k) := by + ↑(p ⊓ f.genEigenspace μ k) ↑(p ⊓ f.genEigenspace μ k) := by have : MapsTo g - ↑(p ⊓ ⨆ k, f.genEigenspace μ k) ↑(p ⊓ ⨆ k, f.genEigenspace μ k) := + ↑(p ⊓ f.genEigenspace μ k) ↑(p ⊓ f.genEigenspace μ k) := hg₁.inter_inter hg₂ rw [← LinearMap.injOn_iff_surjOn this] exact hg₃.mono inter_subset_right specialize hm₂ μ - obtain ⟨y, ⟨hy₀ : y ∈ p, hy₁ : y ∈ ⨆ k, f.genEigenspace μ k⟩, hy₂ : g y = g (m μ)⟩ := + obtain ⟨y, ⟨hy₀ : y ∈ p, hy₁ : y ∈ f.genEigenspace μ k⟩, hy₂ : g y = g (m μ)⟩ := hg₄ ⟨(hg₀ ▸ hg₁ hm₀), hg₂ hm₂⟩ rwa [← hg₃ hy₁ hm₂ hy₂] -theorem eq_iSup_inf_genEigenspace [FiniteDimensional K V] - (h : ∀ x ∈ p, f x ∈ p) (h' : ⨆ μ, ⨆ k, f.genEigenspace μ k = ⊤) : - p = ⨆ μ, ⨆ k, p ⊓ f.genEigenspace μ k := by +theorem eq_iSup_inf_genEigenspace [FiniteDimensional K V] (k : ℕ∞) + (h : ∀ x ∈ p, f x ∈ p) (h' : ⨆ μ, f.genEigenspace μ k = ⊤) : + p = ⨆ μ, p ⊓ f.genEigenspace μ k := by rw [← inf_iSup_genEigenspace h, h', inf_top_eq] end Submodule /-- In finite dimensions, if the generalized eigenspaces of a linear endomorphism span the whole space then the same is true of its restriction to any invariant submodule. -/ -theorem Module.End.iSup_genEigenspace_restrict_eq_top - {p : Submodule K V} {f : Module.End K V} [FiniteDimensional K V] - (h : ∀ x ∈ p, f x ∈ p) (h' : ⨆ μ, ⨆ k, f.genEigenspace μ k = ⊤) : - ⨆ μ, ⨆ k, Module.End.genEigenspace (LinearMap.restrict f h) μ k = ⊤ := by - have := congr_arg (Submodule.comap p.subtype) (Submodule.eq_iSup_inf_genEigenspace h h') +theorem Module.End.genEigenspace_restrict_eq_top + {p : Submodule K V} {f : Module.End K V} [FiniteDimensional K V] {k : ℕ∞} + (h : ∀ x ∈ p, f x ∈ p) (h' : ⨆ μ, f.genEigenspace μ k = ⊤) : + ⨆ μ, Module.End.genEigenspace (LinearMap.restrict f h) μ k = ⊤ := by + have := congr_arg (Submodule.comap p.subtype) (Submodule.eq_iSup_inf_genEigenspace k h h') have h_inj : Function.Injective p.subtype := Subtype.coe_injective simp_rw [Submodule.inf_genEigenspace f p h, Submodule.comap_subtype_self, ← Submodule.map_iSup, Submodule.comap_map_eq_of_injective h_inj] at this exact this.symm -/-- Given a family of endomorphisms `i ↦ f i` which are compatible in the sense that every maximal -generalised eigenspace of `f i` is invariant wrt `f j`, if each `f i` is triangularizable, the -family is simultaneously triangularizable. -/ -lemma Module.End.iSup_iInf_maxGenEigenspace_eq_top_of_forall_mapsTo - {ι : Type*} [FiniteDimensional K V] - (f : ι → End K V) - (h : ∀ i j φ, MapsTo (f i) ((f j).maxGenEigenspace φ) ((f j).maxGenEigenspace φ)) - (h' : ∀ i, ⨆ μ, (f i).maxGenEigenspace μ = ⊤) : - ⨆ χ : ι → K, ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by - generalize h_dim : finrank K V = n - induction n using Nat.strongRecOn generalizing V with | ind n ih => ?_ - obtain this | ⟨i : ι, hy : ¬ ∃ φ, (f i).maxGenEigenspace φ = ⊤⟩ := - forall_or_exists_not (fun j : ι ↦ ∃ φ : K, (f j).maxGenEigenspace φ = ⊤) - · choose χ hχ using this - replace hχ : ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by simpa - simp_rw [eq_top_iff] at hχ ⊢ - exact le_trans hχ <| le_iSup (fun χ : ι → K ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) χ - · replace hy : ∀ φ, finrank K ((f i).maxGenEigenspace φ) < n := fun φ ↦ by - simp_rw [not_exists, ← lt_top_iff_ne_top] at hy; exact h_dim ▸ Submodule.finrank_lt (hy φ) - have hi (j : ι) (φ : K) : - MapsTo (f j) ((f i).maxGenEigenspace φ) ((f i).maxGenEigenspace φ) := by - exact h j i φ - replace ih (φ : K) : - ⨆ χ : ι → K, ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by - apply ih _ (hy φ) - · intro j k μ - exact mapsTo_restrict_maxGenEigenspace_restrict_of_mapsTo (f j) (f k) _ _ (h j k μ) - · simp_rw [maxGenEigenspace_def] at h' ⊢ - exact fun j ↦ Module.End.iSup_genEigenspace_restrict_eq_top _ (h' j) - · rfl - replace ih (φ : K) : - ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by - suffices ∀ χ : ι → K, χ i ≠ φ → ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊥ by - specialize ih φ; rw [iSup_split, biSup_congr this] at ih; simpa using ih - intro χ hχ - rw [eq_bot_iff, ← ((f i).maxGenEigenspace φ).ker_subtype, LinearMap.ker, - ← Submodule.map_le_iff_le_comap, ← Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo, - ← disjoint_iff_inf_le] - simp_rw [maxGenEigenspace_def] - exact ((f i).disjoint_iSup_genEigenspace hχ.symm).mono_right (iInf_le _ i) - replace ih (φ : K) : - ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace (f j) (χ j) = - maxGenEigenspace (f i) φ := by - have (χ : ι → K) (hχ : χ i = φ) : ⨅ j, maxGenEigenspace (f j) (χ j) = - (⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j)).map - ((f i).maxGenEigenspace φ).subtype := by - rw [← hχ, iInf_maxGenEigenspace_restrict_map_subtype_eq] - simp_rw [biSup_congr this, ← Submodule.map_iSup, ih, Submodule.map_top, - Submodule.range_subtype] - simpa only [← ih, iSup_comm (ι := K), iSup_iSup_eq_right] using h' i +/-- In finite dimensions, if the generalized eigenspaces of a linear endomorphism span the whole +space then the same is true of its restriction to any invariant submodule. -/ +@[deprecated Module.End.genEigenspace_restrict_eq_top (since := "2024-10-11")] +theorem Module.End.iSup_genEigenspace_restrict_eq_top + {p : Submodule K V} {f : Module.End K V} [FiniteDimensional K V] + (h : ∀ x ∈ p, f x ∈ p) (h' : ⨆ μ, ⨆ k : ℕ, f.genEigenspace μ k = ⊤) : + ⨆ μ, ⨆ k : ℕ, Module.End.genEigenspace (LinearMap.restrict f h) μ k = ⊤ := by + simp_rw [iSup_genEigenspace_eq] at h' ⊢ + apply Module.End.genEigenspace_restrict_eq_top h h' diff --git a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean index 30837353e1b0a..21e08bdf55996 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean @@ -132,7 +132,7 @@ lemma finrank_maxGenEigenspace (φ : Module.End K M) : finrank K (φ.maxGenEigenspace 0) = natTrailingDegree (φ.charpoly) := by set V := φ.maxGenEigenspace 0 have hV : V = ⨆ (n : ℕ), ker (φ ^ n) := by - simp [V, Module.End.maxGenEigenspace_def, Module.End.genEigenspace_def] + simp [V, ← Module.End.iSup_genEigenspace_eq, Module.End.genEigenspace_nat] let W := ⨅ (n : ℕ), LinearMap.range (φ ^ n) have hVW : IsCompl V W := by rw [hV] diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean index 8992078b835ca..b81a28f1405ee 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean @@ -82,14 +82,12 @@ end exteriorPower variable {R} /-- As well as being linear, `ι m` squares to zero. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem ι_sq_zero (m : M) : ι R m * ι R m = 0 := (CliffordAlgebra.ι_sq_scalar _ m).trans <| map_zero _ section variable {A : Type*} [Semiring A] [Algebra R A] --- @[simp] -- Porting note (#10618): simp can prove this theorem comp_ι_sq_zero (g : ExteriorAlgebra R M →ₐ[R] A) (m : M) : g (ι R m) * g (ι R m) = 0 := by rw [← map_mul, ι_sq_zero, map_zero] @@ -164,6 +162,13 @@ theorem algebraMap_eq_zero_iff (x : R) : algebraMap R (ExteriorAlgebra R M) x = theorem algebraMap_eq_one_iff (x : R) : algebraMap R (ExteriorAlgebra R M) x = 1 ↔ x = 1 := map_eq_one_iff (algebraMap _ _) (algebraMap_leftInverse _).injective +@[instance] +theorem isLocalHom_algebraMap : IsLocalHom (algebraMap R (ExteriorAlgebra R M)) := + isLocalHom_of_leftInverse _ (algebraMap_leftInverse M) + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_algebraMap := isLocalHom_algebraMap + theorem isUnit_algebraMap (r : R) : IsUnit (algebraMap R (ExteriorAlgebra R M) r) ↔ IsUnit r := isUnit_map_of_leftInverse _ (algebraMap_leftInverse M) @@ -234,7 +239,8 @@ theorem ι_range_disjoint_one : Disjoint (LinearMap.range (ι R : M →ₗ[R] ExteriorAlgebra R M)) (1 : Submodule R (ExteriorAlgebra R M)) := by rw [Submodule.disjoint_def] - rintro _ ⟨x, hx⟩ ⟨r, rfl : algebraMap R (ExteriorAlgebra R M) r = _⟩ + rintro _ ⟨x, hx⟩ h + obtain ⟨r, rfl : algebraMap R (ExteriorAlgebra R M) r = _⟩ := Submodule.mem_one.mp h rw [ι_eq_algebraMap_iff x] at hx rw [hx.2, RingHom.map_zero] diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean index 0d6ddd5843e26..81a29f1543817 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean @@ -24,7 +24,6 @@ open scoped DirectSum /-- A version of `ExteriorAlgebra.ι` that maps directly into the graded structure. This is primarily an auxiliary construction used to provide `ExteriorAlgebra.gradedAlgebra`. -/ --- Porting note: protected protected def GradedAlgebra.ι : M →ₗ[R] ⨁ i : ℕ, ⋀[R]^i M := DirectSum.lof R ℕ (fun i => ⋀[R]^i M) 1 ∘ₗ diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/OfAlternating.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/OfAlternating.lean index 0aaaa15bab98c..ebefb027f8c14 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/OfAlternating.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/OfAlternating.lean @@ -141,7 +141,7 @@ def liftAlternatingEquiv : (∀ i, M [⋀^Fin i]→ₗ[R] N) ≃ₗ[R] ExteriorA map_add' := map_add _ map_smul' := map_smul _ invFun F i := F.compAlternatingMap (ιMulti R i) - left_inv f := funext fun i => liftAlternating_comp_ιMulti _ + left_inv _ := funext fun _ => liftAlternating_comp_ιMulti _ right_inv F := (liftAlternating_comp _ _).trans <| by rw [liftAlternating_ιMulti, LinearMap.comp_id] diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 7b2f68f6cdcdd..3b375180e50b1 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -33,14 +33,6 @@ section DivisionRing variable [DivisionRing K] [AddCommGroup V] [Module K V] -/-- In a finite-dimensional vector space, the dimensions of a submodule and of the corresponding -quotient add up to the dimension of the space. -/ -theorem finrank_quotient_add_finrank [FiniteDimensional K V] (s : Submodule K V) : - finrank K (V ⧸ s) + finrank K s = finrank K V := by - have := rank_quotient_add_rank s - rw [← finrank_eq_rank, ← finrank_eq_rank, ← finrank_eq_rank] at this - exact mod_cast this - /-- The dimension of a strict submodule is strictly bounded by the dimension of the ambient space. -/ theorem finrank_lt [FiniteDimensional K V] {s : Submodule K V} (h : s < ⊤) : diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean index f7ab907b35f9c..bcbbfded66f88 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean @@ -3,6 +3,7 @@ Copyright (c) 2019 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ +import Mathlib.Algebra.Module.Projective import Mathlib.FieldTheory.Finiteness /-! @@ -107,11 +108,6 @@ instance finiteDimensional_pi' {ι : Type*} [Finite ι] (M : ι → Type*) [∀ noncomputable def fintypeOfFintype [Fintype K] [FiniteDimensional K V] : Fintype V := Module.fintypeOfFintype (@finsetBasis K V _ _ _ (iff_fg.2 inferInstance)) -theorem finite_of_finite [Finite K] [FiniteDimensional K V] : Finite V := by - cases nonempty_fintype K - haveI := fintypeOfFintype K V - infer_instance - variable {K V} /-- If a vector space has a finite basis, then it is finite-dimensional. -/ @@ -167,8 +163,7 @@ end FiniteDimensional namespace Module variable (K V) -variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] - [Module K V₂] +variable [DivisionRing K] [AddCommGroup V] [Module K V] /-- In a finite-dimensional space, its dimension (seen as a cardinal) coincides with its `finrank`. This is a copy of `finrank_eq_rank _ _` which creates easier typeclass searches. -/ @@ -431,9 +426,6 @@ protected theorem finiteDimensional (f : V ≃ₗ[K] V₂) [FiniteDimensional K FiniteDimensional K V₂ := Module.Finite.equiv f -variable {R M M₂ : Type*} [Ring R] [AddCommGroup M] [AddCommGroup M₂] -variable [Module R M] [Module R M₂] - end LinearEquiv section @@ -447,8 +439,7 @@ instance finiteDimensional_finsupp {ι : Type*} [Finite ι] [FiniteDimensional K end namespace Submodule -variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] - [Module K V₂] +variable [DivisionRing K] [AddCommGroup V] [Module K V] /-- If a submodule is contained in a finite-dimensional submodule with the same or smaller dimension, they are equal. -/ @@ -497,7 +488,7 @@ variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCom theorem surjective_of_injective [FiniteDimensional K V] {f : V →ₗ[K] V} (hinj : Injective f) : Surjective f := by have h := rank_range_of_injective _ hinj - rw [← finrank_eq_rank, ← finrank_eq_rank, natCast_inj] at h + rw [← finrank_eq_rank, ← finrank_eq_rank, Nat.cast_inj] at h exact range_eq_top.1 (eq_top_of_finrank_eq h) /-- The image under an onto linear map of a finite-dimensional space is also finite-dimensional. -/ @@ -671,18 +662,23 @@ noncomputable def divisionRingOfFiniteDimensional (F K : Type*) [Field F] [Ring if H : x = 0 then 0 else Classical.choose <| FiniteDimensional.exists_mul_eq_one F H mul_inv_cancel x hx := show x * dite _ (h := _) _ _ = _ by rw [dif_neg hx] - exact (Classical.choose_spec (FiniteDimensional.exists_mul_eq_one F hx):) + exact (Classical.choose_spec (FiniteDimensional.exists_mul_eq_one F hx) :) inv_zero := dif_pos rfl nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl + +lemma FiniteDimensional.isUnit (F : Type*) {K : Type*} [Field F] [Ring K] [IsDomain K] + [Algebra F K] [FiniteDimensional F K] {x : K} (H : x ≠ 0) : IsUnit x := + let _ := divisionRingOfFiniteDimensional F K; H.isUnit /-- An integral domain that is module-finite as an algebra over a field is a field. -/ noncomputable def fieldOfFiniteDimensional (F K : Type*) [Field F] [h : CommRing K] [IsDomain K] [Algebra F K] [FiniteDimensional F K] : Field K := { divisionRingOfFiniteDimensional F K with toCommRing := h } + end section DivisionRing diff --git a/Mathlib/LinearAlgebra/FiniteSpan.lean b/Mathlib/LinearAlgebra/FiniteSpan.lean index 5e6065d494f51..fb34823624e17 100644 --- a/Mathlib/LinearAlgebra/FiniteSpan.lean +++ b/Mathlib/LinearAlgebra/FiniteSpan.lean @@ -29,8 +29,8 @@ lemma LinearEquiv.isOfFinOrder_of_finite_of_span_eq_top_of_mapsTo ext m have hm : m ∈ span R Φ := hΦ₂ ▸ Submodule.mem_top simp only [mul_left_iterate, mul_one, LinearEquiv.coe_one, id_eq] - refine Submodule.span_induction hm (fun x hx ↦ ?_) (by simp) - (fun x y hx hy ↦ by simp [map_add, hx, hy]) (fun t x hx ↦ by simp [map_smul, hx]) + refine Submodule.span_induction (fun x hx ↦ ?_) (by simp) + (fun x y _ _ hx hy ↦ by simp [map_add, hx, hy]) (fun t x _ hx ↦ by simp [map_smul, hx]) hm rw [LinearEquiv.pow_apply, ← he.1.coe_iterate_restrict ⟨x, hx⟩ k] replace hk : (e') ^ k = 1 := by simpa [IsPeriodicPt, IsFixedPt] using hk replace hk := Equiv.congr_fun hk ⟨x, hx⟩ diff --git a/Mathlib/LinearAlgebra/Finsupp.lean b/Mathlib/LinearAlgebra/Finsupp.lean index 810b8a01afebd..d8827696368ab 100644 --- a/Mathlib/LinearAlgebra/Finsupp.lean +++ b/Mathlib/LinearAlgebra/Finsupp.lean @@ -276,7 +276,7 @@ def supported (s : Set α) : Submodule R (α →₀ M) where simp only [subset_def, Finset.mem_coe, Set.mem_setOf_eq, mem_support_iff, zero_apply] intro h ha exact (ha rfl).elim - smul_mem' a p hp := Subset.trans (Finset.coe_subset.2 support_smul) hp + smul_mem' _ _ hp := Subset.trans (Finset.coe_subset.2 support_smul) hp variable {M} @@ -889,7 +889,6 @@ theorem domLCongr_symm {α₁ α₂ : Type*} (f : α₁ ≃ α₂) : ((Finsupp.domLCongr f).symm : (_ →₀ M) ≃ₗ[R] _) = Finsupp.domLCongr f.symm := LinearEquiv.ext fun _ => rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem domLCongr_single {α₁ : Type*} {α₂ : Type*} (e : α₁ ≃ α₂) (i : α₁) (m : M) : (Finsupp.domLCongr e : _ ≃ₗ[R] _) (Finsupp.single i m) = Finsupp.single (e i) m := by simp @@ -1266,7 +1265,7 @@ theorem mem_span_finset {s : Finset M} {x : M} : (Finsupp.mem_span_image_iff_linearCombination _).1 (show x ∈ span R (_root_.id '' (↑s : Set M)) by rwa [Set.image_id]) ⟨v, hvx ▸ (linearCombination_apply_of_mem_supported _ hvs).symm⟩, - fun ⟨f, hf⟩ => hf ▸ sum_mem fun i hi => smul_mem _ _ <| subset_span hi⟩ + fun ⟨_, hf⟩ => hf ▸ sum_mem fun _ hi => smul_mem _ _ <| subset_span hi⟩ /-- An element `m ∈ M` is contained in the `R`-submodule spanned by a set `s ⊆ M`, if and only if `m` can be written as a finite `R`-linear combination of elements of `s`. @@ -1331,8 +1330,7 @@ def splittingOfFinsuppSurjective (f : M →ₗ[R] α →₀ R) (s : Surjective f theorem splittingOfFinsuppSurjective_splits (f : M →ₗ[R] α →₀ R) (s : Surjective f) : f.comp (splittingOfFinsuppSurjective f s) = LinearMap.id := by - -- Porting note: `ext` can't find appropriate theorems. - refine lhom_ext' fun x => ext_ring <| Finsupp.ext fun y => ?_ + ext x dsimp [splittingOfFinsuppSurjective] congr rw [sum_single_index, one_smul] @@ -1357,8 +1355,7 @@ def splittingOfFunOnFintypeSurjective [Finite α] (f : M →ₗ[R] α → R) (s theorem splittingOfFunOnFintypeSurjective_splits [Finite α] (f : M →ₗ[R] α → R) (s : Surjective f) : f.comp (splittingOfFunOnFintypeSurjective f s) = LinearMap.id := by classical - -- Porting note: `ext` can't find appropriate theorems. - refine pi_ext' fun x => ext_ring <| funext fun y => ?_ + ext x y dsimp [splittingOfFunOnFintypeSurjective] rw [linearEquivFunOnFinite_symm_single, Finsupp.sum_single_index, one_smul, (s (Finsupp.single x 1)).choose_spec, Finsupp.single_eq_pi_single] diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean index fd4961dd7d2fc..d9da43ef8b1b4 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean @@ -22,7 +22,7 @@ universe u v w /-- If a free module is finite, then the arbitrary basis is finite. -/ noncomputable instance Module.Free.ChooseBasisIndex.fintype (R : Type u) (M : Type v) - [Semiring R] [AddCommGroup M] [Module R M] [Module.Free R M] [Module.Finite R M] : + [Semiring R] [AddCommMonoid M] [Module R M] [Module.Free R M] [Module.Finite R M] : Fintype (Module.Free.ChooseBasisIndex R M) := by refine @Fintype.ofFinite _ ?_ cases subsingleton_or_nontrivial R @@ -39,9 +39,13 @@ theorem Module.Finite.of_basis {R M ι : Type*} [Semiring R] [AddCommMonoid M] [ refine ⟨⟨Finset.univ.image b, ?_⟩⟩ simp only [Set.image_univ, Finset.coe_univ, Finset.coe_image, Basis.span_eq] -instance Module.Finite.matrix {R : Type u} [Semiring R] - {ι₁ ι₂ : Type*} [_root_.Finite ι₁] [_root_.Finite ι₂] : - Module.Finite R (Matrix ι₁ ι₂ R) := by +instance Module.Finite.matrix {R ι₁ ι₂ M : Type*} + [Semiring R] [AddCommMonoid M] [Module R M] [Module.Free R M] [Module.Finite R M] + [_root_.Finite ι₁] [_root_.Finite ι₂] : + Module.Finite R (Matrix ι₁ ι₂ M) := by cases nonempty_fintype ι₁ cases nonempty_fintype ι₂ - exact Module.Finite.of_basis (Pi.basis fun _ => Pi.basisFun R _) + exact Module.Finite.of_basis <| (Free.chooseBasis _ _).matrix _ _ + +example {ι₁ ι₂ R : Type*} [Semiring R] [Finite ι₁] [Finite ι₂] : + Module.Finite R (Matrix ι₁ ι₂ R) := inferInstance diff --git a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean index 054d145f3347d..81dfb10854f99 100644 --- a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean +++ b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean @@ -6,7 +6,7 @@ Authors: Anne Baanen import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.LinearAlgebra.FreeModule.PID import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition -import Mathlib.LinearAlgebra.QuotientPi +import Mathlib.LinearAlgebra.Quotient.Pi import Mathlib.RingTheory.Ideal.Basis import Mathlib.LinearAlgebra.Dimension.Constructions diff --git a/Mathlib/LinearAlgebra/FreeModule/Norm.lean b/Mathlib/LinearAlgebra/FreeModule/Norm.lean index 5332fcc328e26..f7a6c74335a21 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Norm.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Norm.lean @@ -21,7 +21,7 @@ variable {R S ι : Type*} [CommRing R] [IsDomain R] [IsPrincipalIdealRing R] [Co section CommRing -variable (F : Type*) [CommRing F] [Algebra F R] [Algebra F S] [IsScalarTower F R S] +variable (F : Type*) /-- For a nonzero element `f` in an algebra `S` over a principal ideal domain `R` that is finite and free as an `R`-module, the norm of `f` relative to `R` is associated to the product of the Smith diff --git a/Mathlib/LinearAlgebra/GeneralLinearGroup.lean b/Mathlib/LinearAlgebra/GeneralLinearGroup.lean index c85e27df2b8bf..289bcb15903b7 100644 --- a/Mathlib/LinearAlgebra/GeneralLinearGroup.lean +++ b/Mathlib/LinearAlgebra/GeneralLinearGroup.lean @@ -37,8 +37,8 @@ variable {R M} def toLinearEquiv (f : GeneralLinearGroup R M) : M ≃ₗ[R] M := { f.val with invFun := f.inv.toFun - left_inv := fun m ↦ show (f.inv * f.val) m = m by erw [f.inv_val]; simp - right_inv := fun m ↦ show (f.val * f.inv) m = m by erw [f.val_inv]; simp } + left_inv := fun m ↦ show (f.inv * f.val) m = m by rw [f.inv_val]; simp + right_inv := fun m ↦ show (f.val * f.inv) m = m by rw [f.val_inv]; simp } /-- An equivalence from `M` to itself determines an invertible linear map. -/ def ofLinearEquiv (f : M ≃ₗ[R] M) : GeneralLinearGroup R M where diff --git a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean index fb28e11886df5..21a217aa2d30c 100644 --- a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean +++ b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel, Kim Morrison -/ +import Mathlib.RingTheory.Ideal.Quotient.Basic import Mathlib.RingTheory.OrzechProperty -import Mathlib.RingTheory.Ideal.Quotient import Mathlib.RingTheory.PrincipalIdealDomain /-! @@ -282,7 +282,7 @@ private def induced_map (I : Ideal R) (e : (ι → R) →ₗ[R] ι' → R) : Quotient.liftOn' x (fun y => Ideal.Quotient.mk (I.pi ι') (e y)) (by refine fun a b hab => Ideal.Quotient.eq.2 fun h => ?_ - rw [Submodule.quotientRel_r_def] at hab + rw [Submodule.quotientRel_def] at hab rw [← LinearMap.map_sub] exact Ideal.map_pi _ _ hab e h) diff --git a/Mathlib/LinearAlgebra/Isomorphisms.lean b/Mathlib/LinearAlgebra/Isomorphisms.lean index 54a39b6372052..3dae0b8f30bfe 100644 --- a/Mathlib/LinearAlgebra/Isomorphisms.lean +++ b/Mathlib/LinearAlgebra/Isomorphisms.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov -/ -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic /-! # Isomorphism theorems for modules. @@ -117,12 +117,9 @@ theorem quotientInfEquivSupQuotient_symm_apply_left (p p' : Submodule R M) (x : rw [quotientInfEquivSupQuotient_apply_mk, inclusion_apply] --- @[simp] -- Porting note (#10618): simp can prove this theorem quotientInfEquivSupQuotient_symm_apply_eq_zero_iff {p p' : Submodule R M} {x : ↥(p ⊔ p')} : (quotientInfEquivSupQuotient p p').symm (Submodule.Quotient.mk x) = 0 ↔ (x : M) ∈ p' := - (LinearEquiv.symm_apply_eq _).trans <| by - -- porting note (#10745): was `simp`. - rw [_root_.map_zero, Quotient.mk_eq_zero, mem_comap, Submodule.coe_subtype] + (LinearEquiv.symm_apply_eq _).trans <| by simp theorem quotientInfEquivSupQuotient_symm_apply_right (p p' : Submodule R M) {x : ↥(p ⊔ p')} (hx : (x : M) ∈ p') : (quotientInfEquivSupQuotient p p').symm (Submodule.Quotient.mk x) @@ -152,7 +149,7 @@ theorem quotientQuotientEquivQuotientAux_mk (x : M ⧸ S) : quotientQuotientEquivQuotientAux S T h (Quotient.mk x) = mapQ S T LinearMap.id h x := liftQ_apply _ _ _ --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem quotientQuotientEquivQuotientAux_mk_mk (x : M) : quotientQuotientEquivQuotientAux S T h (Quotient.mk (Quotient.mk x)) = Quotient.mk x := by simp diff --git a/Mathlib/LinearAlgebra/Lagrange.lean b/Mathlib/LinearAlgebra/Lagrange.lean index ab7d725e81277..eebd330370ef9 100644 --- a/Mathlib/LinearAlgebra/Lagrange.lean +++ b/Mathlib/LinearAlgebra/Lagrange.lean @@ -36,10 +36,11 @@ variable {R : Type*} [CommRing R] [IsDomain R] {f g : R[X]} section Finset open Function Fintype +open scoped Finset variable (s : Finset R) -theorem eq_zero_of_degree_lt_of_eval_finset_eq_zero (degree_f_lt : f.degree < s.card) +theorem eq_zero_of_degree_lt_of_eval_finset_eq_zero (degree_f_lt : f.degree < #s) (eval_f : ∀ x ∈ s, f.eval x = 0) : f = 0 := by rw [← mem_degreeLT] at degree_f_lt simp_rw [eval_eq_sum_degreeLTEquiv degree_f_lt] at eval_f @@ -49,15 +50,15 @@ theorem eq_zero_of_degree_lt_of_eval_finset_eq_zero (degree_f_lt : f.degree < s. (Injective.comp (Embedding.subtype _).inj' (equivFinOfCardEq (card_coe _)).symm.injective) fun _ => eval_f _ (Finset.coe_mem _) -theorem eq_of_degree_sub_lt_of_eval_finset_eq (degree_fg_lt : (f - g).degree < s.card) +theorem eq_of_degree_sub_lt_of_eval_finset_eq (degree_fg_lt : (f - g).degree < #s) (eval_fg : ∀ x ∈ s, f.eval x = g.eval x) : f = g := by rw [← sub_eq_zero] refine eq_zero_of_degree_lt_of_eval_finset_eq_zero _ degree_fg_lt ?_ simp_rw [eval_sub, sub_eq_zero] exact eval_fg -theorem eq_of_degrees_lt_of_eval_finset_eq (degree_f_lt : f.degree < s.card) - (degree_g_lt : g.degree < s.card) (eval_fg : ∀ x ∈ s, f.eval x = g.eval x) : f = g := by +theorem eq_of_degrees_lt_of_eval_finset_eq (degree_f_lt : f.degree < #s) + (degree_g_lt : g.degree < #s) (eval_fg : ∀ x ∈ s, f.eval x = g.eval x) : f = g := by rw [← mem_degreeLT] at degree_f_lt degree_g_lt refine eq_of_degree_sub_lt_of_eval_finset_eq _ ?_ eval_fg rw [← mem_degreeLT]; exact Submodule.sub_mem _ degree_f_lt degree_g_lt @@ -67,7 +68,7 @@ Two polynomials, with the same degree and leading coefficient, which have the sa on a set of distinct values with cardinality equal to the degree, are equal. -/ theorem eq_of_degree_le_of_eval_finset_eq - (h_deg_le : f.degree ≤ s.card) + (h_deg_le : f.degree ≤ #s) (h_deg_eq : f.degree = g.degree) (hlc : f.leadingCoeff = g.leadingCoeff) (h_eval : ∀ x ∈ s, f.eval x = g.eval x) : @@ -86,7 +87,7 @@ open Finset variable {ι : Type*} {v : ι → R} (s : Finset ι) theorem eq_zero_of_degree_lt_of_eval_index_eq_zero (hvs : Set.InjOn v s) - (degree_f_lt : f.degree < s.card) (eval_f : ∀ i ∈ s, f.eval (v i) = 0) : f = 0 := by + (degree_f_lt : f.degree < #s) (eval_f : ∀ i ∈ s, f.eval (v i) = 0) : f = 0 := by classical rw [← card_image_of_injOn hvs] at degree_f_lt refine eq_zero_of_degree_lt_of_eval_finset_eq_zero _ degree_f_lt ?_ @@ -95,21 +96,21 @@ theorem eq_zero_of_degree_lt_of_eval_index_eq_zero (hvs : Set.InjOn v s) exact eval_f _ hj theorem eq_of_degree_sub_lt_of_eval_index_eq (hvs : Set.InjOn v s) - (degree_fg_lt : (f - g).degree < s.card) (eval_fg : ∀ i ∈ s, f.eval (v i) = g.eval (v i)) : + (degree_fg_lt : (f - g).degree < #s) (eval_fg : ∀ i ∈ s, f.eval (v i) = g.eval (v i)) : f = g := by rw [← sub_eq_zero] refine eq_zero_of_degree_lt_of_eval_index_eq_zero _ hvs degree_fg_lt ?_ simp_rw [eval_sub, sub_eq_zero] exact eval_fg -theorem eq_of_degrees_lt_of_eval_index_eq (hvs : Set.InjOn v s) (degree_f_lt : f.degree < s.card) - (degree_g_lt : g.degree < s.card) (eval_fg : ∀ i ∈ s, f.eval (v i) = g.eval (v i)) : f = g := by +theorem eq_of_degrees_lt_of_eval_index_eq (hvs : Set.InjOn v s) (degree_f_lt : f.degree < #s) + (degree_g_lt : g.degree < #s) (eval_fg : ∀ i ∈ s, f.eval (v i) = g.eval (v i)) : f = g := by refine eq_of_degree_sub_lt_of_eval_index_eq _ hvs ?_ eval_fg rw [← mem_degreeLT] at degree_f_lt degree_g_lt ⊢ exact Submodule.sub_mem _ degree_f_lt degree_g_lt theorem eq_of_degree_le_of_eval_index_eq (hvs : Set.InjOn v s) - (h_deg_le : f.degree ≤ s.card) + (h_deg_le : f.degree ≤ #s) (h_deg_eq : f.degree = g.degree) (hlc : f.leadingCoeff = g.leadingCoeff) (h_eval : ∀ i ∈ s, f.eval (v i) = g.eval (v i)) : f = g := by @@ -233,7 +234,7 @@ theorem eval_basis_of_ne (hij : i ≠ j) (hj : j ∈ s) : (Lagrange.basis s v i) @[simp] theorem natDegree_basis (hvs : Set.InjOn v s) (hi : i ∈ s) : - (Lagrange.basis s v i).natDegree = s.card - 1 := by + (Lagrange.basis s v i).natDegree = #s - 1 := by have H : ∀ j, j ∈ s.erase i → basisDivisor (v i) (v j) ≠ 0 := by simp_rw [Ne, mem_erase, basisDivisor_eq_zero_iff] exact fun j ⟨hij₁, hj⟩ hij₂ => hij₁ (hvs hj hi hij₂.symm) @@ -244,14 +245,14 @@ theorem natDegree_basis (hvs : Set.InjOn v s) (hi : i ∈ s) : exact H _ hj theorem degree_basis (hvs : Set.InjOn v s) (hi : i ∈ s) : - (Lagrange.basis s v i).degree = ↑(s.card - 1) := by + (Lagrange.basis s v i).degree = ↑(#s - 1) := by rw [degree_eq_natDegree (basis_ne_zero hvs hi), natDegree_basis hvs hi] -- Porting note: Added `Nat.cast_withBot` rewrites theorem sum_basis (hvs : Set.InjOn v s) (hs : s.Nonempty) : ∑ j ∈ s, Lagrange.basis s v j = 1 := by refine eq_of_degrees_lt_of_eval_index_eq s hvs (lt_of_le_of_lt (degree_sum_le _ _) ?_) ?_ ?_ - · rw [Nat.cast_withBot, Finset.sup_lt_iff (WithBot.bot_lt_coe s.card)] + · rw [Nat.cast_withBot, Finset.sup_lt_iff (WithBot.bot_lt_coe #s)] intro i hi rw [degree_basis hvs hi, Nat.cast_withBot, WithBot.coe_lt_coe] exact Nat.pred_lt (card_ne_zero_of_mem hi) @@ -282,7 +283,7 @@ open Finset /-- Lagrange interpolation: given a finset `s : Finset ι`, a nodal map `v : ι → F` injective on `s` and a value function `r : ι → F`, `interpolate s v r` is the unique -polynomial of degree `< s.card` that takes value `r i` on `v i` for all `i` in `s`. -/ +polynomial of degree `< #s` that takes value `r i` on `v i` for all `i` in `s`. -/ @[simps] def interpolate (s : Finset ι) (v : ι → F) : (ι → F) →ₗ[F] F[X] where toFun r := ∑ i ∈ s, C (r i) * Lagrange.basis s v i @@ -295,12 +296,8 @@ def interpolate (s : Finset ι) (v : ι → F) : (ι → F) →ₗ[F] F[X] where map_smul' c f := by simp_rw [Finset.smul_sum, C_mul', smul_smul, Pi.smul_apply, RingHom.id_apply, smul_eq_mul] --- Porting note (#10618): There was originally '@[simp]' on this line but it was removed because --- 'simp' could prove 'interpolate_empty' theorem interpolate_empty : interpolate ∅ v r = 0 := by rw [interpolate_apply, sum_empty] --- Porting note (#10618): There was originally '@[simp]' on this line but it was removed because --- 'simp' could prove 'interpolate_singleton' theorem interpolate_singleton : interpolate {i} v r = C (r i) := by rw [interpolate_apply, sum_singleton, basis_singleton, mul_one] @@ -316,7 +313,7 @@ theorem eval_interpolate_at_node (hvs : Set.InjOn v s) (hi : i ∈ s) : rw [eval_basis_of_ne (mem_erase.mp H).1 hi, mul_zero] theorem degree_interpolate_le (hvs : Set.InjOn v s) : - (interpolate s v r).degree ≤ ↑(s.card - 1) := by + (interpolate s v r).degree ≤ ↑(#s - 1) := by refine (degree_sum_le _ _).trans ?_ rw [Finset.sup_le_iff] intro i hi @@ -326,7 +323,7 @@ theorem degree_interpolate_le (hvs : Set.InjOn v s) : · rw [degree_C hr, zero_add] -- Porting note: Added `Nat.cast_withBot` rewrites -theorem degree_interpolate_lt (hvs : Set.InjOn v s) : (interpolate s v r).degree < s.card := by +theorem degree_interpolate_lt (hvs : Set.InjOn v s) : (interpolate s v r).degree < #s := by rw [Nat.cast_withBot] rcases eq_empty_or_nonempty s with (rfl | h) · rw [interpolate_empty, degree_zero, card_empty] @@ -336,7 +333,7 @@ theorem degree_interpolate_lt (hvs : Set.InjOn v s) : (interpolate s v r).degree exact Nat.sub_lt (Nonempty.card_pos h) zero_lt_one theorem degree_interpolate_erase_lt (hvs : Set.InjOn v s) (hi : i ∈ s) : - (interpolate (s.erase i) v r).degree < ↑(s.card - 1) := by + (interpolate (s.erase i) v r).degree < ↑(#s - 1) := by rw [← Finset.card_erase_of_mem hi] exact degree_interpolate_lt _ (Set.InjOn.mono (coe_subset.mpr (erase_subset _ _)) hvs) @@ -352,12 +349,12 @@ theorem interpolate_eq_iff_values_eq_on (hvs : Set.InjOn v s) : interpolate s v r = interpolate s v r' ↔ ∀ i ∈ s, r i = r' i := ⟨values_eq_on_of_interpolate_eq _ _ hvs, interpolate_eq_of_values_eq_on _ _⟩ -theorem eq_interpolate {f : F[X]} (hvs : Set.InjOn v s) (degree_f_lt : f.degree < s.card) : +theorem eq_interpolate {f : F[X]} (hvs : Set.InjOn v s) (degree_f_lt : f.degree < #s) : f = interpolate s v fun i => f.eval (v i) := eq_of_degrees_lt_of_eval_index_eq _ hvs degree_f_lt (degree_interpolate_lt _ hvs) fun _ hi => (eval_interpolate_at_node (fun x ↦ eval (v x) f) hvs hi).symm -theorem eq_interpolate_of_eval_eq {f : F[X]} (hvs : Set.InjOn v s) (degree_f_lt : f.degree < s.card) +theorem eq_interpolate_of_eval_eq {f : F[X]} (hvs : Set.InjOn v s) (degree_f_lt : f.degree < #s) (eval_f : ∀ i ∈ s, f.eval (v i) = r i) : f = interpolate s v r := by rw [eq_interpolate hvs degree_f_lt] exact interpolate_eq_of_values_eq_on _ _ eval_f @@ -366,7 +363,7 @@ theorem eq_interpolate_of_eval_eq {f : F[X]} (hvs : Set.InjOn v s) (degree_f_lt unique polynomial of `degree < Fintype.card ι` which takes the value of the `r i` on the `v i`. -/ theorem eq_interpolate_iff {f : F[X]} (hvs : Set.InjOn v s) : - (f.degree < s.card ∧ ∀ i ∈ s, eval (v i) f = r i) ↔ f = interpolate s v r := by + (f.degree < #s ∧ ∀ i ∈ s, eval (v i) f = r i) ↔ f = interpolate s v r := by constructor <;> intro h · exact eq_interpolate_of_eval_eq _ hvs h.1 h.2 · rw [h] @@ -374,9 +371,9 @@ theorem eq_interpolate_iff {f : F[X]} (hvs : Set.InjOn v s) : /-- Lagrange interpolation induces isomorphism between functions from `s` and polynomials of degree less than `Fintype.card ι`. -/ -def funEquivDegreeLT (hvs : Set.InjOn v s) : degreeLT F s.card ≃ₗ[F] s → F where +def funEquivDegreeLT (hvs : Set.InjOn v s) : degreeLT F #s ≃ₗ[F] s → F where toFun f i := f.1.eval (v i) - map_add' f g := funext fun v => eval_add + map_add' _ _ := funext fun _ => eval_add map_smul' c f := funext <| by simp invFun r := ⟨interpolate s v fun x => if hx : x ∈ s then r ⟨x, hx⟩ else 0, @@ -399,15 +396,15 @@ theorem interpolate_eq_sum_interpolate_insert_sdiff (hvt : Set.InjOn v t) (hs : interpolate t v r = ∑ i ∈ s, interpolate (insert i (t \ s)) v r * Lagrange.basis s v i := by symm refine eq_interpolate_of_eval_eq _ hvt (lt_of_le_of_lt (degree_sum_le _ _) ?_) fun i hi => ?_ - · simp_rw [Nat.cast_withBot, Finset.sup_lt_iff (WithBot.bot_lt_coe t.card), degree_mul] + · simp_rw [Nat.cast_withBot, Finset.sup_lt_iff (WithBot.bot_lt_coe #t), degree_mul] intro i hi - have hs : 1 ≤ s.card := Nonempty.card_pos ⟨_, hi⟩ - have hst' : s.card ≤ t.card := card_le_card hst - have H : t.card = 1 + (t.card - s.card) + (s.card - 1) := by + have hs : 1 ≤ #s := Nonempty.card_pos ⟨_, hi⟩ + have hst' : #s ≤ #t := card_le_card hst + have H : #t = 1 + (#t - #s) + (#s - 1) := by rw [add_assoc, tsub_add_tsub_cancel hst' hs, ← add_tsub_assoc_of_le (hs.trans hst'), Nat.succ_add_sub_one, zero_add] rw [degree_basis (Set.InjOn.mono hst hvt) hi, H, WithBot.coe_add, Nat.cast_withBot, - WithBot.add_lt_add_iff_right (@WithBot.coe_ne_bot _ (s.card - 1))] + WithBot.add_lt_add_iff_right (@WithBot.coe_ne_bot _ (#s - 1))] convert degree_interpolate_lt _ (hvt.mono (coe_subset.mpr (insert_subset_iff.mpr ⟨hst hi, sdiff_subset⟩))) rw [card_insert_of_not_mem (not_mem_sdiff_of_mem_right hi), card_sdiff hst, add_comm] @@ -471,7 +468,7 @@ theorem nodal_empty : nodal ∅ v = 1 := by rfl @[simp] -theorem natDegree_nodal [Nontrivial R] : (nodal s v).natDegree = s.card := by +theorem natDegree_nodal [Nontrivial R] : (nodal s v).natDegree = #s := by simp_rw [nodal, natDegree_prod_of_monic (h := fun i _ => monic_X_sub_C (v i)), natDegree_X_sub_C, sum_const, smul_eq_mul, mul_one] @@ -482,7 +479,7 @@ rcases s.eq_empty_or_nonempty with (rfl | h) simp only [natDegree_nodal, h.card_pos] @[simp] -theorem degree_nodal [Nontrivial R] : (nodal s v).degree = s.card := by +theorem degree_nodal [Nontrivial R] : (nodal s v).degree = #s := by simp_rw [degree_eq_natDegree nodal_ne_zero, natDegree_nodal] theorem nodal_monic : (nodal s v).Monic := diff --git a/Mathlib/LinearAlgebra/LinearDisjoint.lean b/Mathlib/LinearAlgebra/LinearDisjoint.lean index f290e4e777d86..18ed93e9d07ed 100644 --- a/Mathlib/LinearAlgebra/LinearDisjoint.lean +++ b/Mathlib/LinearAlgebra/LinearDisjoint.lean @@ -11,9 +11,9 @@ import Mathlib.RingTheory.Flat.Basic /-! -# Linearly disjoint of submodules +# Linearly disjoint submodules -This file contains basics about the linearly disjoint of submodules. +This file contains basics about linearly disjoint submodules. ## Mathematical background @@ -115,7 +115,7 @@ The following is the second equivalent characterization of linearly disjointness if `M` and itself are linearly disjoint, if `M` is flat, if any two elements in `M` are commutative, then the rank of `M` is at most one. -The results with name containing "of_commute" also have corresponding specified versions +The results with name containing "of_commute" also have corresponding specialized versions assuming `S` is commutative. ## Tags @@ -232,12 +232,12 @@ theorem bot_right : M.LinearDisjoint (⊥ : Submodule R S) := /-- The image of `R` in `S` is linearly disjoint with any other submodules. -/ theorem one_left : (1 : Submodule R S).LinearDisjoint N := by - rw [linearDisjoint_iff, mulMap_one_left_eq] + rw [linearDisjoint_iff, ← Algebra.toSubmodule_bot, mulMap_one_left_eq] exact N.injective_subtype.comp N.lTensorOne.injective /-- The image of `R` in `S` is linearly disjoint with any other submodules. -/ theorem one_right : M.LinearDisjoint (1 : Submodule R S) := by - rw [linearDisjoint_iff, mulMap_one_right_eq] + rw [linearDisjoint_iff, ← Algebra.toSubmodule_bot, mulMap_one_right_eq] exact M.injective_subtype.comp M.rTensorOne.injective /-- If for any finitely generated submodules `M'` of `M`, `M'` and `N` are linearly disjoint, @@ -312,7 +312,7 @@ theorem linearIndependent_left_of_flat (H : M.LinearDisjoint N) [Module.Flat R N refine LinearMap.ker_eq_bot_of_injective ?_ classical simp_rw [mulLeftMap_eq_mulMap_comp, LinearMap.coe_comp, LinearEquiv.coe_coe, ← Function.comp_assoc, EquivLike.injective_comp] - rw [LinearIndependent, LinearMap.ker_eq_bot] at hm + rw [LinearIndependent] at hm exact H.injective.comp (Module.Flat.rTensor_preserves_injective_linearMap (M := N) _ hm) /-- If `{ m_i }` is an `R`-basis of `M`, which is also `N`-linearly independent, @@ -333,7 +333,7 @@ theorem linearIndependent_right_of_flat (H : M.LinearDisjoint N) [Module.Flat R refine LinearMap.ker_eq_bot_of_injective ?_ classical simp_rw [mulRightMap_eq_mulMap_comp, LinearMap.coe_comp, LinearEquiv.coe_coe, ← Function.comp_assoc, EquivLike.injective_comp] - rw [LinearIndependent, LinearMap.ker_eq_bot] at hn + rw [LinearIndependent] at hn exact H.injective.comp (Module.Flat.lTensor_preserves_injective_linearMap (M := M) _ hn) /-- If `{ n_i }` is an `R`-basis of `N`, which is also `M`-linearly independent, @@ -352,7 +352,7 @@ also `R`-linearly independent. -/ theorem linearIndependent_mul_of_flat_left (H : M.LinearDisjoint N) [Module.Flat R M] {κ ι : Type*} {m : κ → M} {n : ι → N} (hm : LinearIndependent R m) (hn : LinearIndependent R n) : LinearIndependent R fun (i : κ × ι) ↦ (m i.1).1 * (n i.2).1 := by - rw [LinearIndependent, LinearMap.ker_eq_bot] at hm hn ⊢ + rw [LinearIndependent] at hm hn ⊢ let i0 := (finsuppTensorFinsupp' R κ ι).symm let i1 := LinearMap.rTensor (ι →₀ R) (Finsupp.linearCombination R m) let i2 := LinearMap.lTensor M (Finsupp.linearCombination R n) @@ -373,7 +373,7 @@ also `R`-linearly independent. -/ theorem linearIndependent_mul_of_flat_right (H : M.LinearDisjoint N) [Module.Flat R N] {κ ι : Type*} {m : κ → M} {n : ι → N} (hm : LinearIndependent R m) (hn : LinearIndependent R n) : LinearIndependent R fun (i : κ × ι) ↦ (m i.1).1 * (n i.2).1 := by - rw [LinearIndependent, LinearMap.ker_eq_bot] at hm hn ⊢ + rw [LinearIndependent] at hm hn ⊢ let i0 := (finsuppTensorFinsupp' R κ ι).symm let i1 := LinearMap.lTensor (κ →₀ R) (Finsupp.linearCombination R n) let i2 := LinearMap.rTensor N (Finsupp.linearCombination R m) @@ -399,12 +399,12 @@ theorem linearIndependent_mul_of_flat (H : M.LinearDisjoint N) · exact H.linearIndependent_mul_of_flat_left hm hn · exact H.linearIndependent_mul_of_flat_right hm hn -/-- If `{ m_i }` is an `R`-basis of `M`, if `{ n_i }` is an `R`-basis of `N`, +/-- If `{ m_i }` is an `R`-basis of `M`, if `{ n_j }` is an `R`-basis of `N`, such that the family `{ m_i * n_j }` in `S` is `R`-linearly independent, then `M` and `N` are linearly disjoint. -/ theorem of_basis_mul {κ ι : Type*} (m : Basis κ R M) (n : Basis ι R N) (H : LinearIndependent R fun (i : κ × ι) ↦ (m i.1).1 * (n i.2).1) : M.LinearDisjoint N := by - rw [LinearIndependent, LinearMap.ker_eq_bot] at H + rw [LinearIndependent] at H exact of_basis_mul' M N m n H variable {M N} in diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index f045983a13cd3..1c1b164bab895 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -22,10 +22,10 @@ This file defines linear independence in a module or vector space. It is inspired by Isabelle/HOL's linear algebra, and hence indirectly by HOL Light. -We define `LinearIndependent R v` as `ker (Finsupp.linearCombination R v) = ⊥`. Here +We define `LinearIndependent R v` as `Function.Injective (Finsupp.linearCombination R v)`. Here `Finsupp.linearCombination` is the linear map sending a function `f : ι →₀ R` with finite support to the linear combination of vectors from `v` with these coefficients. Then we prove that several other -statements are equivalent to this one, including injectivity of `Finsupp.linearCombination R v` and +statements are equivalent to this one, including `ker (Finsupp.linearCombination R v) = ⊥` and some versions with explicitly written linear combinations. ## Main definitions @@ -70,6 +70,11 @@ If you want to use sets, use the family `(fun x ↦ x : s → M)` given a set `s `LinearIndependent.to_subtype_range` and `LinearIndependent.of_subtype_range` connect those two worlds. +## TODO + +Rework proofs to hold in semirings, by avoiding the path through +`ker (Finsupp.linearCombination R v) = ⊥`. + ## Tags linearly dependent, linear dependence, linearly independent, linear independence @@ -86,19 +91,18 @@ open Cardinal universe u' u variable {ι : Type u'} {ι' : Type*} {R : Type*} {K : Type*} -variable {M : Type*} {M' M'' : Type*} {V : Type u} {V' : Type*} +variable {M : Type*} {M' : Type*} {V : Type u} + +section Semiring -section Module variable {v : ι → M} -variable [Semiring R] [AddCommMonoid M] [AddCommMonoid M'] [AddCommMonoid M''] -variable [Module R M] [Module R M'] [Module R M''] -variable {a b : R} {x y : M} +variable [Semiring R] [AddCommMonoid M] [AddCommMonoid M'] +variable [Module R M] [Module R M'] variable (R) (v) - /-- `LinearIndependent R v` states the family of vectors `v` is linearly independent over `R`. -/ def LinearIndependent : Prop := - LinearMap.ker (Finsupp.linearCombination R v) = ⊥ + Function.Injective (Finsupp.linearCombination R v) open Lean PrettyPrinter.Delaborator SubExpr in /-- Delaborator for `LinearIndependent` that suggests pretty printing with type hints @@ -120,11 +124,65 @@ def delabLinearIndependent : Delab := withNaryArg 0 do return (← read).optionsPerPos.setBool (← getPos) `pp.analysis.namedArg true withTheReader Context ({· with optionsPerPos}) delab -variable {R} {v} +variable {R v} + +theorem linearIndependent_iff_injective_linearCombination : + LinearIndependent R v ↔ Function.Injective (Finsupp.linearCombination R v) := Iff.rfl + +alias ⟨LinearIndependent.injective_linearCombination, _⟩ := + linearIndependent_iff_injective_linearCombination + +theorem LinearIndependent.ne_zero [Nontrivial R] (i : ι) (hv : LinearIndependent R v) : + v i ≠ 0 := by + intro h + have := @hv (Finsupp.single i 1 : ι →₀ R) 0 ?_ + · simp at this + simpa using h + + +theorem linearIndependent_empty_type [IsEmpty ι] : LinearIndependent R v := + Function.injective_of_subsingleton _ + +variable (R M) in +theorem linearIndependent_empty : LinearIndependent R (fun x => x : (∅ : Set M) → M) := + linearIndependent_empty_type + +/-- A subfamily of a linearly independent family (i.e., a composition with an injective map) is a +linearly independent family. -/ +theorem LinearIndependent.comp (h : LinearIndependent R v) (f : ι' → ι) (hf : Injective f) : + LinearIndependent R (v ∘ f) := by + simpa [Function.comp_def] using Function.Injective.comp h (Finsupp.mapDomain_injective hf) + +/-- A set of linearly independent vectors in a module `M` over a semiring `K` is also linearly +independent over a subring `R` of `K`. +The implementation uses minimal assumptions about the relationship between `R`, `K` and `M`. +The version where `K` is an `R`-algebra is `LinearIndependent.restrict_scalars_algebras`. + -/ +theorem LinearIndependent.restrict_scalars [Semiring K] [SMulWithZero R K] [Module K M] + [IsScalarTower R K M] (hinj : Function.Injective fun r : R => r • (1 : K)) + (li : LinearIndependent K v) : LinearIndependent R v := by + intro x y hxy + let f := fun r : R => r • (1 : K) + have := @li (x.mapRange f (by simp [f])) (y.mapRange f (by simp [f])) ?_ + · ext i + exact hinj congr($this i) + simpa [Finsupp.linearCombination, f, Finsupp.sum_mapRange_index] + +end Semiring + +section Module + +variable {v : ι → M} +variable [Ring R] [AddCommGroup M] [AddCommGroup M'] +variable [Module R M] [Module R M'] + +theorem linearIndependent_iff_ker : + LinearIndependent R v ↔ LinearMap.ker (Finsupp.linearCombination R v) = ⊥ := + LinearMap.ker_eq_bot.symm theorem linearIndependent_iff : LinearIndependent R v ↔ ∀ l, Finsupp.linearCombination R v l = 0 → l = 0 := by - simp [LinearIndependent, LinearMap.ker_eq_bot'] + simp [linearIndependent_iff_ker, LinearMap.ker_eq_bot'] theorem linearIndependent_iff' : LinearIndependent R v ↔ @@ -144,8 +202,8 @@ theorem linearIndependent_iff' : fun hnis => hnis.elim his _ = (∑ j ∈ s, Finsupp.single j (g j)) i := (map_sum ..).symm _ = 0 := DFunLike.ext_iff.1 h i, - fun hf l hl => - Finsupp.ext fun i => + fun hf _ hl => + Finsupp.ext fun _ => _root_.by_contradiction fun hni => hni <| hf _ _ hl _ <| Finsupp.mem_support_iff.2 hni⟩ theorem linearIndependent_iff'' : @@ -186,25 +244,11 @@ theorem Fintype.not_linearIndependent_iff [Fintype ι] : ¬LinearIndependent R v ↔ ∃ g : ι → R, ∑ i, g i • v i = 0 ∧ ∃ i, g i ≠ 0 := by simpa using not_iff_not.2 Fintype.linearIndependent_iff -theorem linearIndependent_empty_type [IsEmpty ι] : LinearIndependent R v := - linearIndependent_iff.mpr fun v _hv => Subsingleton.elim v 0 - -theorem LinearIndependent.ne_zero [Nontrivial R] (i : ι) (hv : LinearIndependent R v) : v i ≠ 0 := - fun h => - zero_ne_one' R <| - Eq.symm - (by - suffices (Finsupp.single i 1 : ι →₀ R) i = 0 by simpa - rw [linearIndependent_iff.1 hv (Finsupp.single i 1)] - · simp - · simp [h]) - lemma LinearIndependent.eq_zero_of_pair {x y : M} (h : LinearIndependent R ![x, y]) {s t : R} (h' : s • x + t • y = 0) : s = 0 ∧ t = 0 := by - have := linearIndependent_iff'.1 h Finset.univ ![s, t] - simp only [Fin.sum_univ_two, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons, h', - Finset.mem_univ, forall_true_left] at this - exact ⟨this 0, this 1⟩ + replace h := @h (.single 0 s + .single 1 t) 0 ?_ + · exact ⟨by simpa using congr($h 0), by simpa using congr($h 1)⟩ + simpa /-- Also see `LinearIndependent.pair_iff'` for a simpler version over fields. -/ lemma LinearIndependent.pair_iff {x y : M} : @@ -217,18 +261,6 @@ lemma LinearIndependent.pair_iff {x y : M} : fin_cases i exacts [(h _ _ hg).1, (h _ _ hg).2] -/-- A subfamily of a linearly independent family (i.e., a composition with an injective map) is a -linearly independent family. -/ -theorem LinearIndependent.comp (h : LinearIndependent R v) (f : ι' → ι) (hf : Injective f) : - LinearIndependent R (v ∘ f) := by - rw [linearIndependent_iff, Finsupp.linearCombination_comp] - intro l hl - have h_map_domain : ∀ x, (Finsupp.mapDomain f l) (f x) = 0 := by - rw [linearIndependent_iff.1 h (Finsupp.mapDomain f l) hl]; simp - ext x - convert h_map_domain x - rw [Finsupp.mapDomain_apply hf] - /-- A family is linearly independent if and only if all of its finite subfamily is linearly independent. -/ theorem linearIndependent_iff_finset_linearIndependent : @@ -248,7 +280,7 @@ theorem LinearIndependent.map (hv : LinearIndependent R v) {f : M →ₗ[R] M'} rw [disjoint_iff_inf_le, ← Set.image_univ, Finsupp.span_image_eq_map_linearCombination, map_inf_eq_map_inf_comap, map_le_iff_le_comap, comap_bot, Finsupp.supported_univ, top_inf_eq] at hf_inj - unfold LinearIndependent at hv ⊢ + rw [linearIndependent_iff_ker] at hv ⊢ rw [hv, le_bot_iff] at hf_inj haveI : Inhabited M := ⟨0⟩ rw [Finsupp.linearCombination_comp, Finsupp.lmapDomain_linearCombination _ _ f, @@ -260,7 +292,7 @@ theorem LinearIndependent.map (hv : LinearIndependent R v) {f : M →ₗ[R] M'} theorem Submodule.range_ker_disjoint {f : M →ₗ[R] M'} (hv : LinearIndependent R (f ∘ v)) : Disjoint (span R (range v)) (LinearMap.ker f) := by - rw [LinearIndependent, Finsupp.linearCombination_comp, + rw [linearIndependent_iff_ker, Finsupp.linearCombination_comp, Finsupp.lmapDomain_linearCombination R _ f (fun _ ↦ rfl), LinearMap.ker_comp] at hv rw [disjoint_iff_inf_le, ← Set.image_univ, Finsupp.span_image_eq_map_linearCombination, map_inf_eq_map_inf_comap, hv, inf_bot_eq, map_bot] @@ -277,7 +309,7 @@ multiplications on `M` and `M'`, then `j` sends linearly independent families of linearly independent families of vectors. As a special case, taking `R = R'` it is `LinearIndependent.map'`. -/ theorem LinearIndependent.map_of_injective_injective {R' : Type*} {M' : Type*} - [Semiring R'] [AddCommMonoid M'] [Module R' M'] (hv : LinearIndependent R v) + [Ring R'] [AddCommGroup M'] [Module R' M'] (hv : LinearIndependent R v) (i : R' → R) (j : M →+ M') (hi : ∀ r, i r = 0 → r = 0) (hj : ∀ m, j m = 0 → m = 0) (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : LinearIndependent R' (j ∘ v) := by rw [linearIndependent_iff'] at hv ⊢ @@ -291,7 +323,7 @@ scalar multiplications on `M` and `M'` are compatible, then `j` sends linearly i of vectors to linearly independent families of vectors. As a special case, taking `R = R'` it is `LinearIndependent.map'`. -/ theorem LinearIndependent.map_of_surjective_injective {R' : Type*} {M' : Type*} - [Semiring R'] [AddCommMonoid M'] [Module R' M'] (hv : LinearIndependent R v) + [Ring R'] [AddCommGroup M'] [Module R' M'] (hv : LinearIndependent R v) (i : ZeroHom R R') (j : M →+ M') (hi : Surjective i) (hj : ∀ m, j m = 0 → m = 0) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : LinearIndependent R' (j ∘ v) := by obtain ⟨i', hi'⟩ := hi.hasRightInverse @@ -356,20 +388,6 @@ theorem LinearIndependent.fin_cons' {m : ℕ} (x : M) (v : Fin m → M) (hli : L rw [this, zero_smul, zero_add] at total_eq exact Fin.cases this (hli _ total_eq) j -/-- A set of linearly independent vectors in a module `M` over a semiring `K` is also linearly -independent over a subring `R` of `K`. -The implementation uses minimal assumptions about the relationship between `R`, `K` and `M`. -The version where `K` is an `R`-algebra is `LinearIndependent.restrict_scalars_algebras`. - -/ -theorem LinearIndependent.restrict_scalars [Semiring K] [SMulWithZero R K] [Module K M] - [IsScalarTower R K M] (hinj : Function.Injective fun r : R => r • (1 : K)) - (li : LinearIndependent K v) : LinearIndependent R v := by - refine linearIndependent_iff'.mpr fun s g hg i hi => hinj ?_ - dsimp only; rw [zero_smul] - refine (linearIndependent_iff'.mp li : _) _ (g · • (1 : K)) ?_ i hi - simp_rw [smul_assoc, one_smul] - exact hg - /-- Every finite subset of a linearly independent set is linearly independent. -/ theorem linearIndependent_finset_map_embedding_subtype (s : Set M) (li : LinearIndependent R ((↑) : s → M)) (t : Finset s) : @@ -462,13 +480,6 @@ theorem LinearIndependent.restrict_of_comp_subtype {s : Set ι} (hs : LinearIndependent R (v ∘ (↑) : s → M)) : LinearIndependent R (s.restrict v) := hs -variable (R M) - -theorem linearIndependent_empty : LinearIndependent R (fun x => x : (∅ : Set M) → M) := by - simp [linearIndependent_subtype_disjoint] - -variable {R M} - theorem LinearIndependent.mono {t s : Set M} (h : t ⊆ s) : LinearIndependent R (fun x => x : s → M) → LinearIndependent R (fun x => x : t → M) := by simp only [linearIndependent_subtype_disjoint] @@ -515,35 +526,18 @@ end Module section Module variable {v : ι → M} -variable [Ring R] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M''] -variable [Module R M] [Module R M'] [Module R M''] -variable {a b : R} {x y : M} - -theorem linearIndependent_iff_injective_linearCombination : - LinearIndependent R v ↔ Function.Injective (Finsupp.linearCombination R v) := - linearIndependent_iff.trans - (injective_iff_map_eq_zero (Finsupp.linearCombination R v).toAddMonoidHom).symm +variable [Ring R] [AddCommGroup M] [AddCommGroup M'] +variable [Module R M] [Module R M'] @[deprecated (since := "2024-08-29")] alias linearIndependent_iff_injective_total := linearIndependent_iff_injective_linearCombination -alias ⟨LinearIndependent.injective_linearCombination, _⟩ := - - linearIndependent_iff_injective_linearCombination - @[deprecated (since := "2024-08-29")] alias LinearIndependent.injective_total := LinearIndependent.injective_linearCombination theorem LinearIndependent.injective [Nontrivial R] (hv : LinearIndependent R v) : Injective v := by - intro i j hij - let l : ι →₀ R := Finsupp.single i (1 : R) - Finsupp.single j 1 - have h_total : Finsupp.linearCombination R v l = 0 := by - simp_rw [l, LinearMap.map_sub, Finsupp.linearCombination_apply] - simp [hij] - have h_single_eq : Finsupp.single i (1 : R) = Finsupp.single j 1 := by - rw [linearIndependent_iff] at hv - simp [eq_add_of_sub_eq' (hv l h_total)] - simpa [Finsupp.single_eq_single_iff] using h_single_eq + simpa [Function.comp_def] + using Function.Injective.comp hv (Finsupp.single_left_injective one_ne_zero) theorem LinearIndependent.to_subtype_range {ι} {f : ι → M} (hf : LinearIndependent R f) : LinearIndependent R ((↑) : range f → M) := by @@ -631,7 +625,7 @@ universe v w A linearly independent family is maximal if there is no strictly larger linearly independent family. -/ @[nolint unusedArguments] -def LinearIndependent.Maximal {ι : Type w} {R : Type u} [Semiring R] {M : Type v} [AddCommMonoid M] +def LinearIndependent.Maximal {ι : Type w} {R : Type u} [Ring R] {M : Type v} [AddCommGroup M] [Module R M] {v : ι → M} (_i : LinearIndependent R v) : Prop := ∀ (s : Set M) (_i' : LinearIndependent R ((↑) : s → M)) (_h : range v ≤ s), range v = s @@ -819,7 +813,7 @@ def LinearIndependent.linearCombinationEquiv (hv : LinearIndependent R v) : apply LinearEquiv.ofBijective (LinearMap.codRestrict (span R (range v)) (Finsupp.linearCombination R v) _) constructor - · rw [← LinearMap.ker_eq_bot, LinearMap.ker_codRestrict] + · rw [← LinearMap.ker_eq_bot, LinearMap.ker_codRestrict, ← linearIndependent_iff_ker] · apply hv · intro l rw [← Finsupp.range_linearCombination] @@ -933,9 +927,7 @@ theorem LinearIndependent.independent_span_singleton (hv : LinearIndependent R v obtain ⟨⟨r, rfl⟩, hm⟩ := hm suffices r = 0 by simp [this] apply linearIndependent_iff_not_smul_mem_span.mp hv i - -- Porting note: The original proof was using `convert hm`. - suffices v '' (univ \ {i}) = range fun j : { j // j ≠ i } => v j by - rwa [this] + convert hm ext simp @@ -1014,7 +1006,7 @@ theorem surjective_of_linearIndependent_of_span [Nontrivial R] (hv : LinearIndep have h_total_eq : Finsupp.linearCombination R v l = Finsupp.linearCombination R v (Finsupp.single i 1) := by rw [h_total_l, Finsupp.linearCombination_single, one_smul] - have l_eq : l = _ := LinearMap.ker_eq_bot.1 hv h_total_eq + have l_eq : l = _ := hv h_total_eq dsimp only [l] at l_eq rw [← Finsupp.embDomain_eq_mapDomain] at l_eq rcases Finsupp.single_of_embDomain_single (repr ⟨v i, _⟩) f i (1 : R) zero_ne_one.symm l_eq with @@ -1185,9 +1177,9 @@ end Module section Nontrivial -variable [Ring R] [Nontrivial R] [AddCommGroup M] [AddCommGroup M'] -variable [Module R M] [NoZeroSMulDivisors R M] [Module R M'] -variable {v : ι → M} {s t : Set M} {x y z : M} +variable [Ring R] [Nontrivial R] [AddCommGroup M] +variable [Module R M] [NoZeroSMulDivisors R M] +variable {s t : Set M} theorem linearIndependent_unique_iff (v : ι → M) [Unique ι] : LinearIndependent R v ↔ v default ≠ 0 := by @@ -1213,9 +1205,8 @@ These can be considered generalizations of properties of linear independence in section Module -variable [DivisionRing K] [AddCommGroup V] [AddCommGroup V'] -variable [Module K V] [Module K V'] -variable {v : ι → V} {s t : Set V} {x y z : V} +variable [DivisionRing K] [AddCommGroup V] [Module K V] +variable {v : ι → V} {s t : Set V} {x y : V} open Submodule @@ -1252,7 +1243,7 @@ theorem linearIndependent_option' : LinearIndependent K (fun o => Option.casesOn' o x v : Option ι → V) ↔ LinearIndependent K v ∧ x ∉ Submodule.span K (range v) := by -- Porting note: Explicit universe level is required in `Equiv.optionEquivSumPUnit`. - rw [← linearIndependent_equiv (Equiv.optionEquivSumPUnit.{_, u'} ι).symm, linearIndependent_sum, + rw [← linearIndependent_equiv (Equiv.optionEquivSumPUnit.{u', _} ι).symm, linearIndependent_sum, @range_unique _ PUnit, @linearIndependent_unique_iff PUnit, disjoint_span_singleton] dsimp [(· ∘ ·)] refine ⟨fun h => ⟨h.1, fun hx => h.2.1 <| h.2.2 hx⟩, fun h => ⟨h.1, ?_, fun hx => (h.2 hx).elim⟩⟩ @@ -1401,6 +1392,10 @@ theorem LinearIndependent.subset_span_extend (hs : LinearIndependent K (fun x => let ⟨_hbt, _hsb, htb, _hli⟩ := Classical.choose_spec (exists_linearIndependent_extension hs hst) htb +theorem LinearIndependent.span_extend_eq_span (hs : LinearIndependent K (fun x => x : s → V)) + (hst : s ⊆ t) : span K (hs.extend hst) = span K t := + le_antisymm (span_mono (hs.extend_subset hst)) (span_le.2 (hs.subset_span_extend hst)) + theorem LinearIndependent.linearIndependent_extend (hs : LinearIndependent K (fun x => x : s → V)) (hst : s ⊆ t) : LinearIndependent K ((↑) : hs.extend hst → V) := let ⟨_hbt, _hsb, _htb, hli⟩ := Classical.choose_spec (exists_linearIndependent_extension hs hst) diff --git a/Mathlib/LinearAlgebra/LinearPMap.lean b/Mathlib/LinearAlgebra/LinearPMap.lean index bae8ae629f0f7..6cc05feeabb39 100644 --- a/Mathlib/LinearAlgebra/LinearPMap.lean +++ b/Mathlib/LinearAlgebra/LinearPMap.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Moritz Doll -/ import Mathlib.LinearAlgebra.Prod -import Mathlib.Algebra.Module.Basic /-! # Partially defined linear maps @@ -223,12 +222,12 @@ instance inhabited : Inhabited (E →ₗ.[R] F) := instance semilatticeInf : SemilatticeInf (E →ₗ.[R] F) where le := (· ≤ ·) - le_refl f := ⟨le_refl f.domain, fun x y h => Subtype.eq h ▸ rfl⟩ - le_trans := fun f g h ⟨fg_le, fg_eq⟩ ⟨gh_le, gh_eq⟩ => - ⟨le_trans fg_le gh_le, fun x z hxz => + le_refl f := ⟨le_refl f.domain, fun _ _ h => Subtype.eq h ▸ rfl⟩ + le_trans := fun _ _ _ ⟨fg_le, fg_eq⟩ ⟨gh_le, gh_eq⟩ => + ⟨le_trans fg_le gh_le, fun x _ hxz => have hxy : (x : E) = inclusion fg_le x := rfl (fg_eq hxy).trans (gh_eq <| hxy.symm.trans hxz)⟩ - le_antisymm f g fg gf := eq_of_le_of_domain_eq fg (le_antisymm fg.1 gf.1) + le_antisymm _ _ fg gf := eq_of_le_of_domain_eq fg (le_antisymm fg.1 gf.1) inf := (· ⊓ ·) -- Porting note: `by rintro` is required, or error of a metavariable happens. le_inf := by @@ -240,9 +239,9 @@ instance semilatticeInf : SemilatticeInf (E →ₗ.[R] F) where fun x ⟨y, yg, hy⟩ h => by apply fg_eq exact h⟩ - inf_le_left f g := ⟨fun x hx => hx.fst, fun x y h => congr_arg f <| Subtype.eq <| h⟩ - inf_le_right f g := - ⟨fun x hx => hx.snd.fst, fun ⟨x, xf, xg, hx⟩ y h => hx.trans <| congr_arg g <| Subtype.eq <| h⟩ + inf_le_left f _ := ⟨fun _ hx => hx.fst, fun _ _ h => congr_arg f <| Subtype.eq <| h⟩ + inf_le_right _ g := + ⟨fun _ hx => hx.snd.fst, fun ⟨_, _, _, hx⟩ _ h => hx.trans <| congr_arg g <| Subtype.eq <| h⟩ instance orderBot : OrderBot (E →ₗ.[R] F) where bot := ⊥ @@ -676,7 +675,7 @@ theorem domRestrict_apply {f : E →ₗ.[R] F} {S : Submodule R E} ⦃x : ↥(S exact LinearPMap.mk_apply _ _ _ theorem domRestrict_le {f : E →ₗ.[R] F} {S : Submodule R E} : f.domRestrict S ≤ f := - ⟨by simp, fun x y hxy => domRestrict_apply hxy⟩ + ⟨by simp, fun _ _ hxy => domRestrict_apply hxy⟩ /-! ### Graph -/ diff --git a/Mathlib/LinearAlgebra/Matrix/AbsoluteValue.lean b/Mathlib/LinearAlgebra/Matrix/AbsoluteValue.lean index 1af383318a9ae..201767b2c0744 100644 --- a/Mathlib/LinearAlgebra/Matrix/AbsoluteValue.lean +++ b/Mathlib/LinearAlgebra/Matrix/AbsoluteValue.lean @@ -50,19 +50,19 @@ theorem det_le {A : Matrix n n R} {abv : AbsoluteValue R S} {x : S} (hx : ∀ i theorem det_sum_le {ι : Type*} (s : Finset ι) {A : ι → Matrix n n R} {abv : AbsoluteValue R S} {x : S} (hx : ∀ k i j, abv (A k i j) ≤ x) : abv (det (∑ k ∈ s, A k)) ≤ - Nat.factorial (Fintype.card n) • (Finset.card s • x) ^ Fintype.card n := + Nat.factorial (Fintype.card n) • (#s• x) ^ Fintype.card n := det_le fun i j => calc abv ((∑ k ∈ s, A k) i j) = abv (∑ k ∈ s, A k i j) := by simp only [sum_apply] _ ≤ ∑ k ∈ s, abv (A k i j) := abv.sum_le _ _ _ ≤ ∑ _k ∈ s, x := sum_le_sum fun k _ => hx k i j - _ = s.card • x := sum_const _ + _ = #s • x := sum_const _ theorem det_sum_smul_le {ι : Type*} (s : Finset ι) {c : ι → R} {A : ι → Matrix n n R} {abv : AbsoluteValue R S} {x : S} (hx : ∀ k i j, abv (A k i j) ≤ x) {y : S} (hy : ∀ k, abv (c k) ≤ y) : abv (det (∑ k ∈ s, c k • A k)) ≤ - Nat.factorial (Fintype.card n) • (Finset.card s • y * x) ^ Fintype.card n := by + Nat.factorial (Fintype.card n) • (#s • y * x) ^ Fintype.card n := by simpa only [smul_mul_assoc] using det_sum_le s fun k i j => calc diff --git a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean index 84ce3839bb755..516ba73963c50 100644 --- a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean +++ b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean @@ -114,8 +114,7 @@ theorem cramer_row_self (i : n) (h : ∀ j, b j = A j i) : A.cramer b = Pi.singl @[simp] theorem cramer_one : cramer (1 : Matrix n n α) = 1 := by - -- Porting note: was `ext i j` - refine LinearMap.pi_ext' (fun (i : n) => LinearMap.ext_ring (funext (fun (j : n) => ?_))) + ext i j convert congr_fun (cramer_row_self (1 : Matrix n n α) (Pi.single i 1) i _) j · simp · intro j @@ -256,7 +255,7 @@ theorem cramer_eq_adjugate_mulVec (A : Matrix n n α) (b : n → α) : theorem mul_adjugate_apply (A : Matrix n n α) (i j k) : A i k * adjugate A k j = cramer Aᵀ (Pi.single k (A i k)) j := by - erw [← smul_eq_mul, adjugate, of_apply, ← Pi.smul_apply, ← LinearMap.map_smul, ← Pi.single_smul', + rw [← smul_eq_mul, adjugate, of_apply, ← Pi.smul_apply, ← LinearMap.map_smul, ← Pi.single_smul', smul_eq_mul, mul_one] theorem mul_adjugate (A : Matrix n n α) : A * adjugate A = A.det • (1 : Matrix n n α) := by diff --git a/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean b/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean index f6e6c15a38732..6ba3a7550fedf 100644 --- a/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean +++ b/Mathlib/LinearAlgebra/Matrix/BilinearForm.lean @@ -21,11 +21,8 @@ This file defines the conversion between bilinear forms and matrices. ## Notations In this file we use the following type variables: - - `M`, `M'`, ... are modules over the commutative semiring `R`, - - `M₁`, `M₁'`, ... are modules over the commutative ring `R₁`, - - `M₂`, `M₂'`, ... are modules over the commutative semiring `R₂`, - - `M₃`, `M₃'`, ... are modules over the commutative ring `R₃`, - - `V`, ... is a vector space over the field `K`. + - `M₁` is a module over the commutative semiring `R₁`, + - `M₂` is a module over the commutative ring `R₂`. ## Tags @@ -35,12 +32,8 @@ bilinear form, bilin form, BilinearForm, matrix, basis open LinearMap (BilinForm) -variable {R : Type*} {M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] -variable {R₁ : Type*} {M₁ : Type*} [CommRing R₁] [AddCommGroup M₁] [Module R₁ M₁] -variable {R₂ : Type*} {M₂ : Type*} [CommSemiring R₂] [AddCommMonoid M₂] [Module R₂ M₂] -variable {R₃ : Type*} {M₃ : Type*} [CommRing R₃] [AddCommGroup M₃] [Module R₃ M₃] -variable {V : Type*} {K : Type*} [Field K] [AddCommGroup V] [Module K V] -variable {B : BilinForm R M} {B₁ : BilinForm R₁ M₁} {B₂ : BilinForm R₂ M₂} +variable {R₁ : Type*} {M₁ : Type*} [CommSemiring R₁] [AddCommMonoid M₁] [Module R₁ M₁] +variable {R₂ : Type*} {M₂ : Type*} [CommRing R₂] [AddCommGroup M₂] [Module R₂ M₂] section Matrix @@ -53,30 +46,30 @@ open Matrix /-- The map from `Matrix n n R` to bilinear forms on `n → R`. This is an auxiliary definition for the equivalence `Matrix.toBilin'`. -/ -def Matrix.toBilin'Aux [Fintype n] (M : Matrix n n R₂) : BilinForm R₂ (n → R₂) := +def Matrix.toBilin'Aux [Fintype n] (M : Matrix n n R₁) : BilinForm R₁ (n → R₁) := Matrix.toLinearMap₂'Aux _ _ M -theorem Matrix.toBilin'Aux_single [Fintype n] [DecidableEq n] (M : Matrix n n R₂) (i j : n) : +theorem Matrix.toBilin'Aux_single [Fintype n] [DecidableEq n] (M : Matrix n n R₁) (i j : n) : M.toBilin'Aux (Pi.single i 1) (Pi.single j 1) = M i j := Matrix.toLinearMap₂'Aux_single _ _ _ _ _ /-- The linear map from bilinear forms to `Matrix n n R` given an `n`-indexed basis. This is an auxiliary definition for the equivalence `Matrix.toBilin'`. -/ -def BilinForm.toMatrixAux (b : n → M₂) : BilinForm R₂ M₂ →ₗ[R₂] Matrix n n R₂ := - LinearMap.toMatrix₂Aux R₂ b b +def BilinForm.toMatrixAux (b : n → M₁) : BilinForm R₁ M₁ →ₗ[R₁] Matrix n n R₁ := + LinearMap.toMatrix₂Aux R₁ b b @[simp] -theorem LinearMap.BilinForm.toMatrixAux_apply (B : BilinForm R₂ M₂) (b : n → M₂) (i j : n) : +theorem LinearMap.BilinForm.toMatrixAux_apply (B : BilinForm R₁ M₁) (b : n → M₁) (i j : n) : -- Porting note: had to hint the base ring even though it should be clear from context... - BilinForm.toMatrixAux (R₂ := R₂) b B i j = B (b i) (b j) := - LinearMap.toMatrix₂Aux_apply R₂ B _ _ _ _ + BilinForm.toMatrixAux (R₁ := R₁) b B i j = B (b i) (b j) := + LinearMap.toMatrix₂Aux_apply R₁ B _ _ _ _ variable [Fintype n] [Fintype o] -theorem toBilin'Aux_toMatrixAux [DecidableEq n] (B₂ : BilinForm R₂ (n → R₂)) : +theorem toBilin'Aux_toMatrixAux [DecidableEq n] (B₂ : BilinForm R₁ (n → R₁)) : -- Porting note: had to hint the base ring even though it should be clear from context... - Matrix.toBilin'Aux (BilinForm.toMatrixAux (R₂ := R₂) (fun j => Pi.single j 1) B₂) = B₂ := by + Matrix.toBilin'Aux (BilinForm.toMatrixAux (R₁ := R₁) (fun j => Pi.single j 1) B₂) = B₂ := by rw [BilinForm.toMatrixAux, Matrix.toBilin'Aux, toLinearMap₂'Aux_toMatrix₂Aux] section ToMatrix' @@ -90,95 +83,95 @@ This section deals with the conversion between matrices and bilinear forms on `n variable [DecidableEq n] [DecidableEq o] /-- The linear equivalence between bilinear forms on `n → R` and `n × n` matrices -/ -def LinearMap.BilinForm.toMatrix' : BilinForm R₂ (n → R₂) ≃ₗ[R₂] Matrix n n R₂ := - LinearMap.toMatrix₂' R₂ +def LinearMap.BilinForm.toMatrix' : BilinForm R₁ (n → R₁) ≃ₗ[R₁] Matrix n n R₁ := + LinearMap.toMatrix₂' R₁ /-- The linear equivalence between `n × n` matrices and bilinear forms on `n → R` -/ -def Matrix.toBilin' : Matrix n n R₂ ≃ₗ[R₂] BilinForm R₂ (n → R₂) := +def Matrix.toBilin' : Matrix n n R₁ ≃ₗ[R₁] BilinForm R₁ (n → R₁) := BilinForm.toMatrix'.symm @[simp] -theorem Matrix.toBilin'Aux_eq (M : Matrix n n R₂) : Matrix.toBilin'Aux M = Matrix.toBilin' M := +theorem Matrix.toBilin'Aux_eq (M : Matrix n n R₁) : Matrix.toBilin'Aux M = Matrix.toBilin' M := rfl -theorem Matrix.toBilin'_apply (M : Matrix n n R₂) (x y : n → R₂) : +theorem Matrix.toBilin'_apply (M : Matrix n n R₁) (x y : n → R₁) : Matrix.toBilin' M x y = ∑ i, ∑ j, x i * M i j * y j := (Matrix.toLinearMap₂'_apply _ _ _).trans (by simp only [smul_eq_mul, mul_assoc, mul_comm, mul_left_comm]) -theorem Matrix.toBilin'_apply' (M : Matrix n n R₂) (v w : n → R₂) : +theorem Matrix.toBilin'_apply' (M : Matrix n n R₁) (v w : n → R₁) : Matrix.toBilin' M v w = Matrix.dotProduct v (M *ᵥ w) := Matrix.toLinearMap₂'_apply' _ _ _ @[simp] -theorem Matrix.toBilin'_single (M : Matrix n n R₂) (i j : n) : +theorem Matrix.toBilin'_single (M : Matrix n n R₁) (i j : n) : Matrix.toBilin' M (Pi.single i 1) (Pi.single j 1) = M i j := by simp [Matrix.toBilin'_apply, Pi.single_apply] set_option linter.deprecated false in @[simp, deprecated Matrix.toBilin'_single (since := "2024-08-09")] -theorem Matrix.toBilin'_stdBasis (M : Matrix n n R₂) (i j : n) : +theorem Matrix.toBilin'_stdBasis (M : Matrix n n R₁) (i j : n) : Matrix.toBilin' M - (LinearMap.stdBasis R₂ (fun _ ↦ R₂) i 1) - (LinearMap.stdBasis R₂ (fun _ ↦ R₂) j 1) = M i j := Matrix.toBilin'_single _ _ _ + (LinearMap.stdBasis R₁ (fun _ ↦ R₁) i 1) + (LinearMap.stdBasis R₁ (fun _ ↦ R₁) j 1) = M i j := Matrix.toBilin'_single _ _ _ @[simp] theorem LinearMap.BilinForm.toMatrix'_symm : - (BilinForm.toMatrix'.symm : Matrix n n R₂ ≃ₗ[R₂] _) = Matrix.toBilin' := + (BilinForm.toMatrix'.symm : Matrix n n R₁ ≃ₗ[R₁] _) = Matrix.toBilin' := rfl @[simp] theorem Matrix.toBilin'_symm : - (Matrix.toBilin'.symm : _ ≃ₗ[R₂] Matrix n n R₂) = BilinForm.toMatrix' := + (Matrix.toBilin'.symm : _ ≃ₗ[R₁] Matrix n n R₁) = BilinForm.toMatrix' := BilinForm.toMatrix'.symm_symm @[simp] -theorem Matrix.toBilin'_toMatrix' (B : BilinForm R₂ (n → R₂)) : +theorem Matrix.toBilin'_toMatrix' (B : BilinForm R₁ (n → R₁)) : Matrix.toBilin' (BilinForm.toMatrix' B) = B := Matrix.toBilin'.apply_symm_apply B namespace LinearMap @[simp] -theorem BilinForm.toMatrix'_toBilin' (M : Matrix n n R₂) : +theorem BilinForm.toMatrix'_toBilin' (M : Matrix n n R₁) : BilinForm.toMatrix' (Matrix.toBilin' M) = M := - (LinearMap.toMatrix₂' R₂).apply_symm_apply M + (LinearMap.toMatrix₂' R₁).apply_symm_apply M @[simp] -theorem BilinForm.toMatrix'_apply (B : BilinForm R₂ (n → R₂)) (i j : n) : +theorem BilinForm.toMatrix'_apply (B : BilinForm R₁ (n → R₁)) (i j : n) : BilinForm.toMatrix' B i j = B (Pi.single i 1) (Pi.single j 1) := LinearMap.toMatrix₂'_apply _ _ _ -- Porting note: dot notation for bundled maps doesn't work in the rest of this section @[simp] -theorem BilinForm.toMatrix'_comp (B : BilinForm R₂ (n → R₂)) (l r : (o → R₂) →ₗ[R₂] n → R₂) : +theorem BilinForm.toMatrix'_comp (B : BilinForm R₁ (n → R₁)) (l r : (o → R₁) →ₗ[R₁] n → R₁) : BilinForm.toMatrix' (B.comp l r) = (LinearMap.toMatrix' l)ᵀ * BilinForm.toMatrix' B * LinearMap.toMatrix' r := LinearMap.toMatrix₂'_compl₁₂ B _ _ -theorem BilinForm.toMatrix'_compLeft (B : BilinForm R₂ (n → R₂)) (f : (n → R₂) →ₗ[R₂] n → R₂) : +theorem BilinForm.toMatrix'_compLeft (B : BilinForm R₁ (n → R₁)) (f : (n → R₁) →ₗ[R₁] n → R₁) : BilinForm.toMatrix' (B.compLeft f) = (LinearMap.toMatrix' f)ᵀ * BilinForm.toMatrix' B := LinearMap.toMatrix₂'_comp B _ -theorem BilinForm.toMatrix'_compRight (B : BilinForm R₂ (n → R₂)) (f : (n → R₂) →ₗ[R₂] n → R₂) : +theorem BilinForm.toMatrix'_compRight (B : BilinForm R₁ (n → R₁)) (f : (n → R₁) →ₗ[R₁] n → R₁) : BilinForm.toMatrix' (B.compRight f) = BilinForm.toMatrix' B * LinearMap.toMatrix' f := LinearMap.toMatrix₂'_compl₂ B _ -theorem BilinForm.mul_toMatrix'_mul (B : BilinForm R₂ (n → R₂)) (M : Matrix o n R₂) - (N : Matrix n o R₂) : M * BilinForm.toMatrix' B * N = +theorem BilinForm.mul_toMatrix'_mul (B : BilinForm R₁ (n → R₁)) (M : Matrix o n R₁) + (N : Matrix n o R₁) : M * BilinForm.toMatrix' B * N = BilinForm.toMatrix' (B.comp (Matrix.toLin' Mᵀ) (Matrix.toLin' N)) := LinearMap.mul_toMatrix₂'_mul B _ _ -theorem BilinForm.mul_toMatrix' (B : BilinForm R₂ (n → R₂)) (M : Matrix n n R₂) : +theorem BilinForm.mul_toMatrix' (B : BilinForm R₁ (n → R₁)) (M : Matrix n n R₁) : M * BilinForm.toMatrix' B = BilinForm.toMatrix' (B.compLeft (Matrix.toLin' Mᵀ)) := LinearMap.mul_toMatrix' B _ -theorem BilinForm.toMatrix'_mul (B : BilinForm R₂ (n → R₂)) (M : Matrix n n R₂) : +theorem BilinForm.toMatrix'_mul (B : BilinForm R₁ (n → R₁)) (M : Matrix n n R₁) : BilinForm.toMatrix' B * M = BilinForm.toMatrix' (B.compRight (Matrix.toLin' M)) := LinearMap.toMatrix₂'_mul B _ end LinearMap -theorem Matrix.toBilin'_comp (M : Matrix n n R₂) (P Q : Matrix n o R₂) : +theorem Matrix.toBilin'_comp (M : Matrix n n R₁) (P Q : Matrix n o R₁) : M.toBilin'.comp (Matrix.toLin' P) (Matrix.toLin' Q) = Matrix.toBilin' (Pᵀ * M * Q) := BilinForm.toMatrix'.injective (by simp only [BilinForm.toMatrix'_comp, BilinForm.toMatrix'_toBilin', toMatrix'_toLin']) @@ -194,32 +187,32 @@ a module with a fixed basis. -/ -variable [DecidableEq n] (b : Basis n R₂ M₂) +variable [DecidableEq n] (b : Basis n R₁ M₁) /-- `BilinForm.toMatrix b` is the equivalence between `R`-bilinear forms on `M` and `n`-by-`n` matrices with entries in `R`, if `b` is an `R`-basis for `M`. -/ -noncomputable def BilinForm.toMatrix : BilinForm R₂ M₂ ≃ₗ[R₂] Matrix n n R₂ := +noncomputable def BilinForm.toMatrix : BilinForm R₁ M₁ ≃ₗ[R₁] Matrix n n R₁ := LinearMap.toMatrix₂ b b /-- `BilinForm.toMatrix b` is the equivalence between `R`-bilinear forms on `M` and `n`-by-`n` matrices with entries in `R`, if `b` is an `R`-basis for `M`. -/ -noncomputable def Matrix.toBilin : Matrix n n R₂ ≃ₗ[R₂] BilinForm R₂ M₂ := +noncomputable def Matrix.toBilin : Matrix n n R₁ ≃ₗ[R₁] BilinForm R₁ M₁ := (BilinForm.toMatrix b).symm @[simp] -theorem BilinForm.toMatrix_apply (B : BilinForm R₂ M₂) (i j : n) : +theorem BilinForm.toMatrix_apply (B : BilinForm R₁ M₁) (i j : n) : BilinForm.toMatrix b B i j = B (b i) (b j) := LinearMap.toMatrix₂_apply _ _ B _ _ @[simp] -theorem Matrix.toBilin_apply (M : Matrix n n R₂) (x y : M₂) : +theorem Matrix.toBilin_apply (M : Matrix n n R₁) (x y : M₁) : Matrix.toBilin b M x y = ∑ i, ∑ j, b.repr x i * M i j * b.repr y j := (Matrix.toLinearMap₂_apply _ _ _ _ _).trans (by simp only [smul_eq_mul, mul_assoc, mul_comm, mul_left_comm]) -- Not a `simp` lemma since `BilinForm.toMatrix` needs an extra argument -theorem BilinearForm.toMatrixAux_eq (B : BilinForm R₂ M₂) : - BilinForm.toMatrixAux (R₂ := R₂) b B = BilinForm.toMatrix b B := +theorem BilinearForm.toMatrixAux_eq (B : BilinForm R₁ M₁) : + BilinForm.toMatrixAux (R₁ := R₁) b B = BilinForm.toMatrix b B := LinearMap.toMatrix₂Aux_eq _ _ B @[simp] @@ -230,62 +223,62 @@ theorem BilinForm.toMatrix_symm : (BilinForm.toMatrix b).symm = Matrix.toBilin b theorem Matrix.toBilin_symm : (Matrix.toBilin b).symm = BilinForm.toMatrix b := (BilinForm.toMatrix b).symm_symm -theorem Matrix.toBilin_basisFun : Matrix.toBilin (Pi.basisFun R₂ n) = Matrix.toBilin' := by +theorem Matrix.toBilin_basisFun : Matrix.toBilin (Pi.basisFun R₁ n) = Matrix.toBilin' := by ext M simp only [coe_comp, coe_single, Function.comp_apply, toBilin_apply, Pi.basisFun_repr, toBilin'_apply] theorem BilinForm.toMatrix_basisFun : - BilinForm.toMatrix (Pi.basisFun R₂ n) = BilinForm.toMatrix' := by + BilinForm.toMatrix (Pi.basisFun R₁ n) = BilinForm.toMatrix' := by rw [BilinForm.toMatrix, BilinForm.toMatrix', LinearMap.toMatrix₂_basisFun] @[simp] -theorem Matrix.toBilin_toMatrix (B : BilinForm R₂ M₂) : +theorem Matrix.toBilin_toMatrix (B : BilinForm R₁ M₁) : Matrix.toBilin b (BilinForm.toMatrix b B) = B := (Matrix.toBilin b).apply_symm_apply B @[simp] -theorem BilinForm.toMatrix_toBilin (M : Matrix n n R₂) : +theorem BilinForm.toMatrix_toBilin (M : Matrix n n R₁) : BilinForm.toMatrix b (Matrix.toBilin b M) = M := (BilinForm.toMatrix b).apply_symm_apply M -variable {M₂' : Type*} [AddCommMonoid M₂'] [Module R₂ M₂'] -variable (c : Basis o R₂ M₂') +variable {M₂' : Type*} [AddCommMonoid M₂'] [Module R₁ M₂'] +variable (c : Basis o R₁ M₂') variable [DecidableEq o] -- Cannot be a `simp` lemma because `b` must be inferred. -theorem BilinForm.toMatrix_comp (B : BilinForm R₂ M₂) (l r : M₂' →ₗ[R₂] M₂) : +theorem BilinForm.toMatrix_comp (B : BilinForm R₁ M₁) (l r : M₂' →ₗ[R₁] M₁) : BilinForm.toMatrix c (B.comp l r) = (LinearMap.toMatrix c b l)ᵀ * BilinForm.toMatrix b B * LinearMap.toMatrix c b r := LinearMap.toMatrix₂_compl₁₂ _ _ _ _ B _ _ -theorem BilinForm.toMatrix_compLeft (B : BilinForm R₂ M₂) (f : M₂ →ₗ[R₂] M₂) : +theorem BilinForm.toMatrix_compLeft (B : BilinForm R₁ M₁) (f : M₁ →ₗ[R₁] M₁) : BilinForm.toMatrix b (B.compLeft f) = (LinearMap.toMatrix b b f)ᵀ * BilinForm.toMatrix b B := LinearMap.toMatrix₂_comp _ _ _ B _ -theorem BilinForm.toMatrix_compRight (B : BilinForm R₂ M₂) (f : M₂ →ₗ[R₂] M₂) : +theorem BilinForm.toMatrix_compRight (B : BilinForm R₁ M₁) (f : M₁ →ₗ[R₁] M₁) : BilinForm.toMatrix b (B.compRight f) = BilinForm.toMatrix b B * LinearMap.toMatrix b b f := LinearMap.toMatrix₂_compl₂ _ _ _ B _ @[simp] -theorem BilinForm.toMatrix_mul_basis_toMatrix (c : Basis o R₂ M₂) (B : BilinForm R₂ M₂) : +theorem BilinForm.toMatrix_mul_basis_toMatrix (c : Basis o R₁ M₁) (B : BilinForm R₁ M₁) : (b.toMatrix c)ᵀ * BilinForm.toMatrix b B * b.toMatrix c = BilinForm.toMatrix c B := LinearMap.toMatrix₂_mul_basis_toMatrix _ _ _ _ B -theorem BilinForm.mul_toMatrix_mul (B : BilinForm R₂ M₂) (M : Matrix o n R₂) (N : Matrix n o R₂) : +theorem BilinForm.mul_toMatrix_mul (B : BilinForm R₁ M₁) (M : Matrix o n R₁) (N : Matrix n o R₁) : M * BilinForm.toMatrix b B * N = BilinForm.toMatrix c (B.comp (Matrix.toLin c b Mᵀ) (Matrix.toLin c b N)) := LinearMap.mul_toMatrix₂_mul _ _ _ _ B _ _ -theorem BilinForm.mul_toMatrix (B : BilinForm R₂ M₂) (M : Matrix n n R₂) : +theorem BilinForm.mul_toMatrix (B : BilinForm R₁ M₁) (M : Matrix n n R₁) : M * BilinForm.toMatrix b B = BilinForm.toMatrix b (B.compLeft (Matrix.toLin b b Mᵀ)) := LinearMap.mul_toMatrix₂ _ _ _ B _ -theorem BilinForm.toMatrix_mul (B : BilinForm R₂ M₂) (M : Matrix n n R₂) : +theorem BilinForm.toMatrix_mul (B : BilinForm R₁ M₁) (M : Matrix n n R₁) : BilinForm.toMatrix b B * M = BilinForm.toMatrix b (B.compRight (Matrix.toLin b b M)) := LinearMap.toMatrix₂_mul _ _ _ B _ -theorem Matrix.toBilin_comp (M : Matrix n n R₂) (P Q : Matrix n o R₂) : +theorem Matrix.toBilin_comp (M : Matrix n n R₁) (P Q : Matrix n o R₁) : (Matrix.toBilin b M).comp (toLin c b P) (toLin c b Q) = Matrix.toBilin c (Pᵀ * M * Q) := by ext x y rw [Matrix.toBilin, BilinForm.toMatrix, Matrix.toBilin, BilinForm.toMatrix, toMatrix₂_symm, @@ -301,8 +294,8 @@ section MatrixAdjoints open Matrix variable {n : Type*} [Fintype n] -variable (b : Basis n R₃ M₃) -variable (J J₃ A A' : Matrix n n R₃) +variable (b : Basis n R₂ M₂) +variable (J J₃ A A' : Matrix n n R₂) @[simp] theorem isAdjointPair_toBilin' [DecidableEq n] : @@ -318,7 +311,7 @@ theorem isAdjointPair_toBilin [DecidableEq n] : Matrix.IsAdjointPair J J₃ A A' := isAdjointPair_toLinearMap₂ _ _ _ _ _ _ -theorem Matrix.isAdjointPair_equiv' [DecidableEq n] (P : Matrix n n R₃) (h : IsUnit P) : +theorem Matrix.isAdjointPair_equiv' [DecidableEq n] (P : Matrix n n R₂) (h : IsUnit P) : (Pᵀ * J * P).IsAdjointPair (Pᵀ * J * P) A A' ↔ J.IsAdjointPair J (P * A * P⁻¹) (P * A' * P⁻¹) := Matrix.isAdjointPair_equiv _ _ _ _ h @@ -327,10 +320,10 @@ variable [DecidableEq n] /-- The submodule of pair-self-adjoint matrices with respect to bilinear forms corresponding to given matrices `J`, `J₂`. -/ -def pairSelfAdjointMatricesSubmodule' : Submodule R₃ (Matrix n n R₃) := +def pairSelfAdjointMatricesSubmodule' : Submodule R₂ (Matrix n n R₂) := (BilinForm.isPairSelfAdjointSubmodule (Matrix.toBilin' J) (Matrix.toBilin' J₃)).map - ((LinearMap.toMatrix' : ((n → R₃) →ₗ[R₃] n → R₃) ≃ₗ[R₃] Matrix n n R₃) : - ((n → R₃) →ₗ[R₃] n → R₃) →ₗ[R₃] Matrix n n R₃) + ((LinearMap.toMatrix' : ((n → R₂) →ₗ[R₂] n → R₂) ≃ₗ[R₂] Matrix n n R₂) : + ((n → R₂) →ₗ[R₂] n → R₂) →ₗ[R₂] Matrix n n R₂) theorem mem_pairSelfAdjointMatricesSubmodule' : A ∈ pairSelfAdjointMatricesSubmodule J J₃ ↔ Matrix.IsAdjointPair J J₃ A A := by @@ -338,7 +331,7 @@ theorem mem_pairSelfAdjointMatricesSubmodule' : /-- The submodule of self-adjoint matrices with respect to the bilinear form corresponding to the matrix `J`. -/ -def selfAdjointMatricesSubmodule' : Submodule R₃ (Matrix n n R₃) := +def selfAdjointMatricesSubmodule' : Submodule R₂ (Matrix n n R₂) := pairSelfAdjointMatricesSubmodule J J theorem mem_selfAdjointMatricesSubmodule' : @@ -347,7 +340,7 @@ theorem mem_selfAdjointMatricesSubmodule' : /-- The submodule of skew-adjoint matrices with respect to the bilinear form corresponding to the matrix `J`. -/ -def skewAdjointMatricesSubmodule' : Submodule R₃ (Matrix n n R₃) := +def skewAdjointMatricesSubmodule' : Submodule R₂ (Matrix n n R₂) := pairSelfAdjointMatricesSubmodule (-J) J theorem mem_skewAdjointMatricesSubmodule' : @@ -364,49 +357,49 @@ section Det open Matrix -variable {A : Type*} [CommRing A] [IsDomain A] [Module A M₃] (B₃ : BilinForm A M₃) +variable {A : Type*} [CommRing A] [IsDomain A] [Module A M₂] (B₃ : BilinForm A M₂) variable {ι : Type*} [DecidableEq ι] [Fintype ι] -theorem _root_.Matrix.nondegenerate_toBilin'_iff_nondegenerate_toBilin {M : Matrix ι ι R₂} - (b : Basis ι R₂ M₂) : M.toBilin'.Nondegenerate ↔ (Matrix.toBilin b M).Nondegenerate := +theorem _root_.Matrix.nondegenerate_toBilin'_iff_nondegenerate_toBilin {M : Matrix ι ι R₁} + (b : Basis ι R₁ M₁) : M.toBilin'.Nondegenerate ↔ (Matrix.toBilin b M).Nondegenerate := (nondegenerate_congr_iff b.equivFun.symm).symm -- Lemmas transferring nondegeneracy between a matrix and its associated bilinear form -theorem _root_.Matrix.Nondegenerate.toBilin' {M : Matrix ι ι R₃} (h : M.Nondegenerate) : +theorem _root_.Matrix.Nondegenerate.toBilin' {M : Matrix ι ι R₂} (h : M.Nondegenerate) : M.toBilin'.Nondegenerate := fun x hx => h.eq_zero_of_ortho fun y => by simpa only [toBilin'_apply'] using hx y @[simp] -theorem _root_.Matrix.nondegenerate_toBilin'_iff {M : Matrix ι ι R₃} : +theorem _root_.Matrix.nondegenerate_toBilin'_iff {M : Matrix ι ι R₂} : M.toBilin'.Nondegenerate ↔ M.Nondegenerate := ⟨fun h v hv => h v fun w => (M.toBilin'_apply' _ _).trans <| hv w, Matrix.Nondegenerate.toBilin'⟩ -theorem _root_.Matrix.Nondegenerate.toBilin {M : Matrix ι ι R₃} (h : M.Nondegenerate) - (b : Basis ι R₃ M₃) : (Matrix.toBilin b M).Nondegenerate := +theorem _root_.Matrix.Nondegenerate.toBilin {M : Matrix ι ι R₂} (h : M.Nondegenerate) + (b : Basis ι R₂ M₂) : (Matrix.toBilin b M).Nondegenerate := (Matrix.nondegenerate_toBilin'_iff_nondegenerate_toBilin b).mp h.toBilin' @[simp] -theorem _root_.Matrix.nondegenerate_toBilin_iff {M : Matrix ι ι R₃} (b : Basis ι R₃ M₃) : +theorem _root_.Matrix.nondegenerate_toBilin_iff {M : Matrix ι ι R₂} (b : Basis ι R₂ M₂) : (Matrix.toBilin b M).Nondegenerate ↔ M.Nondegenerate := by rw [← Matrix.nondegenerate_toBilin'_iff_nondegenerate_toBilin, Matrix.nondegenerate_toBilin'_iff] /-! Lemmas transferring nondegeneracy between a bilinear form and its associated matrix -/ @[simp] -theorem nondegenerate_toMatrix'_iff {B : BilinForm R₃ (ι → R₃)} : +theorem nondegenerate_toMatrix'_iff {B : BilinForm R₂ (ι → R₂)} : B.toMatrix'.Nondegenerate (m := ι) ↔ B.Nondegenerate := Matrix.nondegenerate_toBilin'_iff.symm.trans <| (Matrix.toBilin'_toMatrix' B).symm ▸ Iff.rfl -theorem Nondegenerate.toMatrix' {B : BilinForm R₃ (ι → R₃)} (h : B.Nondegenerate) : +theorem Nondegenerate.toMatrix' {B : BilinForm R₂ (ι → R₂)} (h : B.Nondegenerate) : B.toMatrix'.Nondegenerate := nondegenerate_toMatrix'_iff.mpr h @[simp] -theorem nondegenerate_toMatrix_iff {B : BilinForm R₃ M₃} (b : Basis ι R₃ M₃) : +theorem nondegenerate_toMatrix_iff {B : BilinForm R₂ M₂} (b : Basis ι R₂ M₂) : (BilinForm.toMatrix b B).Nondegenerate ↔ B.Nondegenerate := (Matrix.nondegenerate_toBilin_iff b).symm.trans <| (Matrix.toBilin_toMatrix b B).symm ▸ Iff.rfl -theorem Nondegenerate.toMatrix {B : BilinForm R₃ M₃} (h : B.Nondegenerate) (b : Basis ι R₃ M₃) : +theorem Nondegenerate.toMatrix {B : BilinForm R₂ M₂} (h : B.Nondegenerate) (b : Basis ι R₂ M₂) : (BilinForm.toMatrix b B).Nondegenerate := (nondegenerate_toMatrix_iff b).mpr h @@ -420,11 +413,11 @@ theorem nondegenerate_toBilin'_of_det_ne_zero' (M : Matrix ι ι A) (h : M.det M.toBilin'.Nondegenerate := nondegenerate_toBilin'_iff_det_ne_zero.mpr h -theorem nondegenerate_iff_det_ne_zero {B : BilinForm A M₃} (b : Basis ι A M₃) : +theorem nondegenerate_iff_det_ne_zero {B : BilinForm A M₂} (b : Basis ι A M₂) : B.Nondegenerate ↔ (BilinForm.toMatrix b B).det ≠ 0 := by rw [← Matrix.nondegenerate_iff_det_ne_zero, nondegenerate_toMatrix_iff] -theorem nondegenerate_of_det_ne_zero (b : Basis ι A M₃) (h : (BilinForm.toMatrix b B₃).det ≠ 0) : +theorem nondegenerate_of_det_ne_zero (b : Basis ι A M₂) (h : (BilinForm.toMatrix b B₃).det ≠ 0) : B₃.Nondegenerate := (nondegenerate_iff_det_ne_zero b).mpr h diff --git a/Mathlib/LinearAlgebra/Matrix/Block.lean b/Mathlib/LinearAlgebra/Matrix/Block.lean index 8432d56b10b42..401caa2ef1eff 100644 --- a/Mathlib/LinearAlgebra/Matrix/Block.lean +++ b/Mathlib/LinearAlgebra/Matrix/Block.lean @@ -85,6 +85,18 @@ theorem BlockTriangular.add (hM : BlockTriangular M b) (hN : BlockTriangular N b theorem BlockTriangular.sub (hM : BlockTriangular M b) (hN : BlockTriangular N b) : BlockTriangular (M - N) b := fun i j h => by simp_rw [Matrix.sub_apply, hM h, hN h, sub_zero] +lemma BlockTriangular.add_iff_right (hM : BlockTriangular M b) : + BlockTriangular (M + N) b ↔ BlockTriangular N b := ⟨(by simpa using ·.sub hM), hM.add⟩ + +lemma BlockTriangular.add_iff_left (hN : BlockTriangular N b) : + BlockTriangular (M + N) b ↔ BlockTriangular M b := by rw [add_comm, hN.add_iff_right] + +lemma BlockTriangular.sub_iff_right (hM : BlockTriangular M b) : + BlockTriangular (M - N) b ↔ BlockTriangular N b := ⟨(by simpa using hM.sub ·), hM.sub⟩ + +lemma BlockTriangular.sub_iff_left (hN : BlockTriangular N b) : + BlockTriangular (M - N) b ↔ BlockTriangular M b := ⟨(by simpa using ·.add hN), (·.sub hN)⟩ + end LT section Preorder diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean index 83b4e6ed3bec2..f2f8e2eff0c0c 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Mathlib.LinearAlgebra.Matrix.Adjugate +import Mathlib.LinearAlgebra.Matrix.Block import Mathlib.RingTheory.PolynomialAlgebra /-! @@ -85,6 +86,16 @@ lemma charmatrix_fromBlocks : simp only [charmatrix] ext (i|i) (j|j) : 2 <;> simp [diagonal] +-- TODO: importing block triangular here is somewhat expensive, if more lemmas about it are added +-- to this file, it may be worth extracting things out to Charpoly/Block.lean +@[simp] +lemma charmatrix_blockTriangular_iff {α : Type*} [Preorder α] {M : Matrix n n R} {b : n → α} : + M.charmatrix.BlockTriangular b ↔ M.BlockTriangular b := by + rw [charmatrix, scalar_apply, RingHom.mapMatrix_apply, (blockTriangular_diagonal _).sub_iff_right] + simp [BlockTriangular] + +alias ⟨BlockTriangular.of_charmatrix, BlockTriangular.charmatrix⟩ := charmatrix_blockTriangular_iff + /-- The characteristic polynomial of a matrix `M` is given by $\det (t I - M)$. -/ def charpoly (M : Matrix n n R) : R[X] := @@ -112,6 +123,19 @@ lemma charpoly_fromBlocks_zero₂₁ : simp only [charpoly, charmatrix_fromBlocks, Matrix.map_zero _ (Polynomial.C_0), neg_zero, det_fromBlocks_zero₂₁] +lemma charmatrix_toSquareBlock {α : Type*} [DecidableEq α] {b : n → α} {a : α} : + (M.toSquareBlock b a).charmatrix = M.charmatrix.toSquareBlock b a := by + ext i j : 1 + simp [charmatrix_apply, toSquareBlock_def, diagonal_apply, Subtype.ext_iff] + +lemma BlockTriangular.charpoly {α : Type*} {b : n → α} [LinearOrder α] (h : M.BlockTriangular b) : + M.charpoly = ∏ a ∈ image b univ, (M.toSquareBlock b a).charpoly := by + simp only [Matrix.charpoly, h.charmatrix.det, charmatrix_toSquareBlock] + +lemma charpoly_of_upperTriangular [LinearOrder n] (M : Matrix n n R) (h : M.BlockTriangular id) : + M.charpoly = ∏ i : n, (X - C (M i i)) := by + simp [charpoly, det_of_upperTriangular h.charmatrix] + -- This proof follows http://drorbn.net/AcademicPensieve/2015-12/CayleyHamilton.pdf /-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix, applied to the matrix itself, is zero. diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean index 73a35fa98fa85..a6138962526ff 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean @@ -93,8 +93,7 @@ theorem Matrix.represents_iff' {A : Matrix ι ι R} {f : Module.End R M} : have := LinearMap.congr_fun h (Pi.single i 1) rwa [PiToModule.fromEnd_apply_single_one, PiToModule.fromMatrix_apply_single_one] at this · intro h - -- Porting note: was `ext` - refine LinearMap.pi_ext' (fun i => LinearMap.ext_ring ?_) + ext simp_rw [LinearMap.comp_apply, LinearMap.coe_single, PiToModule.fromEnd_apply_single_one, PiToModule.fromMatrix_apply_single_one] apply h @@ -229,4 +228,4 @@ theorem LinearMap.exists_monic_and_coeff_mem_pow_and_aeval_eq_zero_of_range_le_s theorem LinearMap.exists_monic_and_aeval_eq_zero [Module.Finite R M] (f : Module.End R M) : ∃ p : R[X], p.Monic ∧ Polynomial.aeval f p = 0 := (LinearMap.exists_monic_and_coeff_mem_pow_and_aeval_eq_zero_of_range_le_smul R f ⊤ (by simp)).imp - fun p h => h.imp_right And.right + fun _ h => h.imp_right And.right diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean index 4f8c88911dcd1..e4c7fb458c0ae 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean @@ -71,7 +71,6 @@ variable (R) lemma univ_monic : (univ R n).Monic := charpoly_monic (mvPolynomialX n n R) --- Porting note (#10618): no @[simp], since simp can prove this lemma univ_natDegree [Nontrivial R] : (univ R n).natDegree = Fintype.card n := charpoly_natDegree_eq_dim (mvPolynomialX n n R) diff --git a/Mathlib/LinearAlgebra/Matrix/Circulant.lean b/Mathlib/LinearAlgebra/Matrix/Circulant.lean index 769780c3325b5..2e87e67a1fa42 100644 --- a/Mathlib/LinearAlgebra/Matrix/Circulant.lean +++ b/Mathlib/LinearAlgebra/Matrix/Circulant.lean @@ -32,7 +32,7 @@ circulant, matrix -/ -variable {α β m n R : Type*} +variable {α β n R : Type*} namespace Matrix @@ -60,7 +60,7 @@ theorem circulant_injective [AddGroup n] : Injective (circulant : (n → α) → theorem Fin.circulant_injective : ∀ n, Injective fun v : Fin n → α => circulant v | 0 => by simp [Injective] - | n + 1 => Matrix.circulant_injective + | _ + 1 => Matrix.circulant_injective @[simp] theorem circulant_inj [AddGroup n] {v w : n → α} : circulant v = circulant w ↔ v = w := @@ -78,12 +78,12 @@ theorem conjTranspose_circulant [Star α] [AddGroup n] (v : n → α) : theorem Fin.transpose_circulant : ∀ {n} (v : Fin n → α), (circulant v)ᵀ = circulant fun i => v (-i) | 0 => by simp [Injective, eq_iff_true_of_subsingleton] - | n + 1 => Matrix.transpose_circulant + | _ + 1 => Matrix.transpose_circulant theorem Fin.conjTranspose_circulant [Star α] : ∀ {n} (v : Fin n → α), (circulant v)ᴴ = circulant (star fun i => v (-i)) | 0 => by simp [Injective, eq_iff_true_of_subsingleton] - | n + 1 => Matrix.conjTranspose_circulant + | _ + 1 => Matrix.conjTranspose_circulant theorem map_circulant [Sub n] (v : n → α) (f : α → β) : (circulant v).map f = circulant fun i => f (v i) := @@ -117,7 +117,7 @@ theorem circulant_mul [Semiring α] [Fintype n] [AddGroup n] (v w : n → α) : theorem Fin.circulant_mul [Semiring α] : ∀ {n} (v w : Fin n → α), circulant v * circulant w = circulant (circulant v *ᵥ w) | 0 => by simp [Injective, eq_iff_true_of_subsingleton] - | n + 1 => Matrix.circulant_mul + | _ + 1 => Matrix.circulant_mul /-- Multiplication of circulant matrices commutes when the elements do. -/ theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [AddCommGroup n] @@ -134,7 +134,7 @@ theorem circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] [Fintype n] [Ad theorem Fin.circulant_mul_comm [CommSemigroup α] [AddCommMonoid α] : ∀ {n} (v w : Fin n → α), circulant v * circulant w = circulant w * circulant v | 0 => by simp [Injective] - | n + 1 => Matrix.circulant_mul_comm + | _ + 1 => Matrix.circulant_mul_comm /-- `k • circulant v` is another circulant matrix `circulant (k • v)`. -/ theorem circulant_smul [Sub n] [SMul R α] (k : R) (v : n → α) : @@ -169,7 +169,7 @@ theorem circulant_isSymm_iff [AddGroup n] {v : n → α} : theorem Fin.circulant_isSymm_iff : ∀ {n} {v : Fin n → α}, (circulant v).IsSymm ↔ ∀ i, v (-i) = v i | 0 => by simp [IsSymm.ext_iff, IsEmpty.forall_iff] - | n + 1 => Matrix.circulant_isSymm_iff + | _ + 1 => Matrix.circulant_isSymm_iff /-- If `circulant v` is symmetric, `∀ i j : I, v (- i) = v i`. -/ theorem circulant_isSymm_apply [AddGroup n] {v : n → α} (h : (circulant v).IsSymm) (i : n) : diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean index c33327a8858ae..24fa035e5eef1 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean @@ -75,7 +75,6 @@ theorem det_diagonal {d : n → R} : det (diagonal d) = ∏ i, d i := by · simp · simp --- @[simp] -- Porting note (#10618): simp can prove this theorem det_zero (_ : Nonempty n) : det (0 : Matrix n n R) = 0 := (detRowAlternating : (n → R) [⋀^n]→ₗ[R] R).map_zero @@ -131,12 +130,9 @@ theorem det_mul (M N : Matrix n n R) : det (M * N) = det M * det N := det (M * N) = ∑ p : n → n, ∑ σ : Perm n, ε σ * ∏ i, M (σ i) (p i) * N (p i) i := by simp only [det_apply', mul_apply, prod_univ_sum, mul_sum, Fintype.piFinset_univ] rw [Finset.sum_comm] - _ = - ∑ p ∈ (@univ (n → n) _).filter Bijective, - ∑ σ : Perm n, ε σ * ∏ i, M (σ i) (p i) * N (p i) i := - (Eq.symm <| - sum_subset (filter_subset _ _) fun f _ hbij => - det_mul_aux <| by simpa only [true_and, mem_filter, mem_univ] using hbij) + _ = ∑ p : n → n with Bijective p, ∑ σ : Perm n, ε σ * ∏ i, M (σ i) (p i) * N (p i) i := by + refine (sum_subset (filter_subset _ _) fun f _ hbij ↦ det_mul_aux ?_).symm + simpa only [true_and, mem_filter, mem_univ] using hbij _ = ∑ τ : Perm n, ∑ σ : Perm n, ε σ * ∏ i, M (σ i) (τ i) * N (τ i) i := sum_bij (fun p h ↦ Equiv.ofBijective p (mem_filter.1 h).2) (fun _ _ ↦ mem_univ _) (fun _ _ _ _ h ↦ by injection h) @@ -543,8 +539,7 @@ theorem det_blockDiagonal {o : Type*} [Fintype o] [DecidableEq o] (M : o → Mat simp_rw [Finset.prod_attach_univ, Finset.univ_pi_univ] -- We claim that the only permutations contributing to the sum are those that -- preserve their second component. - let preserving_snd : Finset (Equiv.Perm (n × o)) := - Finset.univ.filter fun σ => ∀ x, (σ x).snd = x.snd + let preserving_snd : Finset (Equiv.Perm (n × o)) := {σ | ∀ x, (σ x).snd = x.snd} have mem_preserving_snd : ∀ {σ : Equiv.Perm (n × o)}, σ ∈ preserving_snd ↔ ∀ x, (σ x).snd = x.snd := fun {σ} => Finset.mem_filter.trans ⟨fun h => h.2, fun h => ⟨Finset.mem_univ _, h⟩⟩ diff --git a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean index a8b92d3cd2a99..ff4b403c74f6f 100644 --- a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean +++ b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean @@ -52,7 +52,7 @@ end CommSemiring section Semifield -variable {m n : Type*} [Fintype m] [Fintype n] {K : Type u} [Semifield K] +variable {m : Type*} [Fintype m] {K : Type u} [Semifield K] -- maybe try to relax the universe constraint theorem ker_diagonal_toLin' [DecidableEq m] (w : m → K) : @@ -81,7 +81,7 @@ namespace LinearMap section Field -variable {m n : Type*} [Fintype m] [Fintype n] {K : Type u} [Field K] +variable {m : Type*} [Fintype m] {K : Type u} [Field K] theorem rank_diagonal [DecidableEq m] [DecidableEq K] (w : m → K) : LinearMap.rank (toLin' (diagonal w)) = Fintype.card { i // w i ≠ 0 } := by diff --git a/Mathlib/LinearAlgebra/Matrix/DotProduct.lean b/Mathlib/LinearAlgebra/Matrix/DotProduct.lean index d943a52a81685..bf76ac67e8efa 100644 --- a/Mathlib/LinearAlgebra/Matrix/DotProduct.lean +++ b/Mathlib/LinearAlgebra/Matrix/DotProduct.lean @@ -3,11 +3,8 @@ Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Patrick Massot, Casper Putz, Anne Baanen -/ -import Mathlib.Algebra.Ring.Regular import Mathlib.Algebra.Order.Star.Basic -import Mathlib.Data.Matrix.Basic import Mathlib.LinearAlgebra.StdBasis -import Mathlib.Algebra.Order.BigOperators.Group.Finset /-! # Dot product of two vectors @@ -88,7 +85,7 @@ variable [Fintype m] [Fintype n] [Fintype p] @[simp] theorem dotProduct_self_eq_zero [LinearOrderedRing R] {v : n → R} : dotProduct v v = 0 ↔ v = 0 := (Finset.sum_eq_zero_iff_of_nonneg fun i _ => mul_self_nonneg (v i)).trans <| by - simp [Function.funext_iff] + simp [funext_iff] section StarOrderedRing @@ -109,14 +106,14 @@ variable [NoZeroDivisors R] /-- Note that this applies to `ℂ` via `RCLike.toStarOrderedRing`. -/ @[simp] theorem dotProduct_star_self_eq_zero {v : n → R} : dotProduct (star v) v = 0 ↔ v = 0 := - (Fintype.sum_eq_zero_iff_of_nonneg fun i => star_mul_self_nonneg _).trans <| - by simp [Function.funext_iff, mul_eq_zero] + (Fintype.sum_eq_zero_iff_of_nonneg fun _ => star_mul_self_nonneg _).trans <| + by simp [funext_iff, mul_eq_zero] /-- Note that this applies to `ℂ` via `RCLike.toStarOrderedRing`. -/ @[simp] theorem dotProduct_self_star_eq_zero {v : n → R} : dotProduct v (star v) = 0 ↔ v = 0 := - (Fintype.sum_eq_zero_iff_of_nonneg fun i => mul_star_self_nonneg _).trans <| - by simp [Function.funext_iff, mul_eq_zero] + (Fintype.sum_eq_zero_iff_of_nonneg fun _ => mul_star_self_nonneg _).trans <| + by simp [funext_iff, mul_eq_zero] @[simp] lemma conjTranspose_mul_self_eq_zero {n} {A : Matrix m n R} : Aᴴ * A = 0 ↔ A = 0 := diff --git a/Mathlib/LinearAlgebra/Matrix/FixedDetMatrices.lean b/Mathlib/LinearAlgebra/Matrix/FixedDetMatrices.lean new file mode 100644 index 0000000000000..3120568c26c11 --- /dev/null +++ b/Mathlib/LinearAlgebra/Matrix/FixedDetMatrices.lean @@ -0,0 +1,55 @@ +/- +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.LinearAlgebra.Matrix.SpecialLinearGroup + +/-! +# Matrices with fixed determinant + +This file defines the type of matrices with fixed determinant `m` and proves some basic results +about them. + +Note: Some of this was done originally in Lean 3 in the +kbb (https://github.com/kim-em/kbb/tree/master) repository, so credit to those authors. +-/ + +variable (n : Type*) [DecidableEq n] [Fintype n] (R : Type*) [CommRing R] + +/--The set of matrices with fixed determinant `m`. -/ +def FixedDetMatrix (m : R) := { A : Matrix n n R // A.det = m } + +namespace FixedDetMatrix + +open ModularGroup Matrix SpecialLinearGroup MatrixGroups + +/--Extensionality theorem for `FixedDetMatrix` with respect to the underlying matrix, not +entriwise. -/ +lemma ext' {m : R} {A B : FixedDetMatrix n R m} (h : A.1 = B.1) : A = B := by + cases A; cases B + congr + +@[ext] +lemma ext {m : R} {A B : FixedDetMatrix n R m} (h : ∀ i j , A.1 i j = B.1 i j) : A = B := by + apply ext' + ext i j + apply h + +instance (m : R) : SMul (SpecialLinearGroup n R) (FixedDetMatrix n R m) where + smul g A := ⟨g * A.1, by simp only [det_mul, SpecialLinearGroup.det_coe, A.2, one_mul]⟩ + +lemma smul_def (m : R) (g : SpecialLinearGroup n R) (A : (FixedDetMatrix n R m)) : + g • A = ⟨g * A.1, by simp only [det_mul, SpecialLinearGroup.det_coe, A.2, one_mul]⟩ := + rfl + +instance (m : R) : MulAction (SpecialLinearGroup n R) (FixedDetMatrix n R m) where + one_smul b := by rw [smul_def]; simp only [coe_one, one_mul, Subtype.coe_eta] + mul_smul x y b := by simp_rw [smul_def, ← mul_assoc, coe_mul] + +lemma smul_coe (m : R) (g : SpecialLinearGroup n R) (A : FixedDetMatrix n R m) : + (g • A).1 = g * A.1 := by + rw [smul_def] + +end FixedDetMatrix diff --git a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean index d7867798bc310..92453f4171360 100644 --- a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean +++ b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean @@ -38,7 +38,7 @@ theorem card_linearIndependent {k : ℕ} (hk : k ≤ n) : ∏ i : Fin k, (q ^ n - q ^ i.val) := by rw [Nat.card_eq_fintype_card] induction k with - | zero => simp only [LinearIndependent, Finsupp.linearCombination_fin_zero, ker_zero, + | zero => simp only [linearIndependent_iff_ker, Finsupp.linearCombination_fin_zero, ker_zero, card_ofSubsingleton, Finset.univ_eq_empty, Finset.prod_empty] | succ k ih => have (s : { s : Fin k → V // LinearIndependent K s }) : @@ -77,7 +77,7 @@ noncomputable def equiv_GL_linearindependent (hn : 0 < n) : rw [← Basis.coePiBasisFun.toMatrix_eq_transpose, ← coe_basisOfLinearIndependentOfCardEqFinrank M.2] exact isUnit_det_of_invertible _ - left_inv := fun x ↦ Units.ext (ext fun i j ↦ rfl) + left_inv := fun _ ↦ Units.ext (ext fun _ _ ↦ rfl) right_inv := by exact congrFun rfl /-- The cardinal of the general linear group over a finite field. -/ diff --git a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean index 5ae49bf1b77c9..da7f4ec732165 100644 --- a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean +++ b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean @@ -67,7 +67,7 @@ def det : GL n R →* Rˣ where val_inv := by rw [← det_mul, A.mul_inv, det_one] inv_val := by rw [← det_mul, A.inv_mul, det_one] } map_one' := Units.ext det_one - map_mul' A B := Units.ext <| det_mul _ _ + map_mul' _ _ := Units.ext <| det_mul _ _ /-- The `GL n R` and `Matrix.GeneralLinearGroup R n` groups are multiplicatively equivalent -/ def toLin : GL n R ≃* LinearMap.GeneralLinearGroup R (n → R) := diff --git a/Mathlib/LinearAlgebra/Matrix/Hermitian.lean b/Mathlib/LinearAlgebra/Matrix/Hermitian.lean index 0201300fe7f22..8f8dc321c4457 100644 --- a/Mathlib/LinearAlgebra/Matrix/Hermitian.lean +++ b/Mathlib/LinearAlgebra/Matrix/Hermitian.lean @@ -114,7 +114,7 @@ end InvolutiveStar section AddMonoid -variable [AddMonoid α] [StarAddMonoid α] [AddMonoid β] [StarAddMonoid β] +variable [AddMonoid α] [StarAddMonoid α] /-- A diagonal matrix is hermitian if the entries are self-adjoint (as a vector) -/ theorem isHermitian_diagonal_of_self_adjoint [DecidableEq n] (v : n → α) (h : IsSelfAdjoint v) : @@ -174,7 +174,7 @@ end AddGroup section NonUnitalSemiring -variable [NonUnitalSemiring α] [StarRing α] [NonUnitalSemiring β] [StarRing β] +variable [NonUnitalSemiring α] [StarRing α] /-- Note this is more general than `IsSelfAdjoint.mul_star_self` as `B` can be rectangular. -/ theorem isHermitian_mul_conjTranspose_self [Fintype n] (A : Matrix m n α) : @@ -202,7 +202,7 @@ end NonUnitalSemiring section Semiring -variable [Semiring α] [StarRing α] [Semiring β] [StarRing β] +variable [Semiring α] [StarRing α] /-- Note this is more general for matrices than `isSelfAdjoint_one` as it does not require `Fintype n`, which is necessary for `Monoid (Matrix n n R)`. -/ @@ -255,7 +255,7 @@ section RCLike open RCLike -variable [RCLike α] [RCLike β] +variable [RCLike α] /-- The diagonal elements of a complex hermitian matrix are real. -/ theorem IsHermitian.coe_re_apply_self {A : Matrix n n α} (h : A.IsHermitian) (i : n) : diff --git a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean index ff884d2e289ad..70a529e030dc1 100644 --- a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean +++ b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean @@ -8,6 +8,8 @@ import Mathlib.LinearAlgebra.Matrix.Spectrum import Mathlib.LinearAlgebra.Eigenspace.Matrix import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unique import Mathlib.Topology.ContinuousMap.Units +import Mathlib.Analysis.Matrix +import Mathlib.Topology.UniformSpace.Matrix /-! # Continuous Functional Calculus for Hermitian Matrices @@ -87,10 +89,10 @@ noncomputable def cfcAux : C(spectrum ℝ A, ℝ) →⋆ₐ[ℝ] (Matrix n n ext simp -lemma closedEmbedding_cfcAux : ClosedEmbedding hA.cfcAux := by +lemma isClosedEmbedding_cfcAux : IsClosedEmbedding hA.cfcAux := by have h0 : FiniteDimensional ℝ C(spectrum ℝ A, ℝ) := FiniteDimensional.of_injective (ContinuousMap.coeFnLinearMap ℝ (M := ℝ)) DFunLike.coe_injective - refine LinearMap.closedEmbedding_of_injective (𝕜 := ℝ) (E := C(spectrum ℝ A, ℝ)) + refine LinearMap.isClosedEmbedding_of_injective (𝕜 := ℝ) (E := C(spectrum ℝ A, ℝ)) (F := Matrix n n 𝕜) (f := hA.cfcAux) <| LinearMap.ker_eq_bot'.mpr fun f hf ↦ ?_ have h2 : diagonal (RCLike.ofReal ∘ f ∘ fun i ↦ ⟨hA.eigenvalues i, hA.eigenvalues_mem_spectrum_real i⟩) @@ -107,6 +109,9 @@ lemma closedEmbedding_cfcAux : ClosedEmbedding hA.cfcAux := by have := (diagonal_eq_diagonal_iff).mp h2 refine RCLike.ofReal_eq_zero.mp (this i) +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_cfcAux := isClosedEmbedding_cfcAux + lemma cfcAux_id : hA.cfcAux (.restrict (spectrum ℝ A) (.id ℝ)) = A := by conv_rhs => rw [hA.spectral_theorem] congr! @@ -117,7 +122,7 @@ instance instContinuousFunctionalCalculus : ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : Matrix n n 𝕜 → Prop) where exists_cfc_of_predicate a ha := by replace ha : IsHermitian a := ha - refine ⟨ha.cfcAux, ha.closedEmbedding_cfcAux, ha.cfcAux_id, fun f ↦ ?map_spec, + refine ⟨ha.cfcAux, ha.isClosedEmbedding_cfcAux, ha.cfcAux_id, fun f ↦ ?map_spec, fun f ↦ ?hermitian⟩ case map_spec => apply Set.eq_of_subset_of_subset @@ -135,6 +140,11 @@ instance instContinuousFunctionalCalculus : rw [star_eq_conjTranspose, diagonal_conjTranspose] congr! simp [Pi.star_def, Function.comp_def] + spectrum_nonempty a ha := by + obtain (h | h) := isEmpty_or_nonempty n + · obtain ⟨x, y, hxy⟩ := exists_pair_ne (Matrix n n 𝕜) + exact False.elim <| Matrix.of.symm.injective.ne hxy <| Subsingleton.elim _ _ + · exact eigenvalues_eq_spectrum_real ha ▸ Set.range_nonempty _ predicate_zero := .zero _ instance instUniqueContinuousFunctionalCalculus : @@ -154,7 +164,7 @@ protected noncomputable def cfc (f : ℝ → ℝ) : Matrix n n 𝕜 := lemma cfc_eq (f : ℝ → ℝ) : cfc f A = hA.cfc f := by have hA' : IsSelfAdjoint A := hA - have := cfcHom_eq_of_continuous_of_map_id hA' hA.cfcAux hA.closedEmbedding_cfcAux.continuous + have := cfcHom_eq_of_continuous_of_map_id hA' hA.cfcAux hA.isClosedEmbedding_cfcAux.continuous hA.cfcAux_id rw [cfc_apply f A hA' (by rw [continuousOn_iff_continuous_restrict]; fun_prop), this] simp only [cfcAux_apply, ContinuousMap.coe_mk, Function.comp_def, Set.restrict_apply, diff --git a/Mathlib/LinearAlgebra/Matrix/Ideal.lean b/Mathlib/LinearAlgebra/Matrix/Ideal.lean new file mode 100644 index 0000000000000..f251e331989ae --- /dev/null +++ b/Mathlib/LinearAlgebra/Matrix/Ideal.lean @@ -0,0 +1,204 @@ +/- +Copyright (c) 2024 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang, Wojciech Nawrocki +-/ +import Mathlib.Data.Matrix.Basis +import Mathlib.RingTheory.Ideal.Lattice +import Mathlib.RingTheory.TwoSidedIdeal.Operations + +/-! +# Ideals in a matrix ring + +This file defines left (resp. two-sided) ideals in a matrix semiring (resp. ring) +over left (resp. two-sided) ideals in the base semiring (resp. ring). + +## Main results + +* `TwoSidedIdeal.equivMatricesOver` and `TwoSidedIdeal.orderIsoMatricesOver` + establish an order isomorphism between two-sided ideals in $R$ and those in $Mₙ(R)$. +-/ + +/-! ### Left ideals in a matrix ring -/ + +namespace Ideal +open Matrix + +variable {R : Type*} [Semiring R] + (n : Type*) [Fintype n] [DecidableEq n] + +/-- The left ideal of matrices with entries in `I ≤ R`. -/ +def matricesOver (I : Ideal R) : Ideal (Matrix n n R) where + carrier := { M | ∀ i j, M i j ∈ I } + add_mem' ha hb i j := I.add_mem (ha i j) (hb i j) + zero_mem' _ _ := I.zero_mem + smul_mem' M N hN := by + intro i j + rw [smul_eq_mul, mul_apply] + apply sum_mem + intro k _ + apply I.mul_mem_left _ (hN k j) + +@[simp] +theorem mem_matricesOver (I : Ideal R) (M : Matrix n n R) : + M ∈ I.matricesOver n ↔ ∀ i j, M i j ∈ I := by rfl + +theorem matricesOver_monotone : Monotone (matricesOver (R := R) n) := + fun _ _ IJ _ MI i j => IJ (MI i j) + +theorem matricesOver_strictMono_of_nonempty [Nonempty n] : + StrictMono (matricesOver (R := R) n) := + matricesOver_monotone n |>.strictMono_of_injective <| fun I J eq => by + ext x + have : (∀ _ _, x ∈ I) ↔ (∀ _ _, x ∈ J) := congr((Matrix.of fun _ _ => x) ∈ $eq) + simpa only [forall_const] using this + +@[simp] +theorem matricesOver_bot : (⊥ : Ideal R).matricesOver n = ⊥ := by + ext M + simp only [mem_matricesOver, mem_bot] + constructor + · intro H; ext; apply H + · intro H; simp [H] + +@[simp] +theorem matricesOver_top : (⊤ : Ideal R).matricesOver n = ⊤ := by + ext; simp + +end Ideal + +/-! ### Two-sided ideals in a matrix ring -/ + +namespace TwoSidedIdeal +open Matrix + +variable {R : Type*} [Ring R] + (n : Type*) [Fintype n] + +/-- The two-sided ideal of matrices with entries in `I ≤ R`. -/ +def matricesOver (I : TwoSidedIdeal R) : TwoSidedIdeal (Matrix n n R) := + TwoSidedIdeal.mk' { M | ∀ i j, M i j ∈ I } + (fun _ _ => I.zero_mem) + (fun ha hb i j => I.add_mem (ha i j) (hb i j)) + (fun ha i j => I.neg_mem (ha i j)) + (fun ha i j => by + rw [mul_apply] + apply sum_mem + intro k _ + apply I.mul_mem_left _ _ (ha k j)) + (fun ha i j => by + rw [mul_apply] + apply sum_mem + intro k _ + apply I.mul_mem_right _ _ (ha i k)) + +@[simp] +lemma mem_matricesOver (I : TwoSidedIdeal R) (M : Matrix n n R) : + M ∈ I.matricesOver n ↔ ∀ i j, M i j ∈ I := by + simp [matricesOver] + +theorem matricesOver_monotone : Monotone (matricesOver (R := R) n) := + fun _ _ IJ _ MI i j => IJ (MI i j) + +theorem matricesOver_strictMono_of_nonempty [h : Nonempty n] : + StrictMono (matricesOver (R := R) n) := + matricesOver_monotone n |>.strictMono_of_injective <| fun I J eq => by + ext x + have : _ ↔ _ := congr((Matrix.of fun _ _ => x) ∈ $eq) + simpa only [mem_matricesOver, of_apply, forall_const] using this + +@[simp] +theorem matricesOver_bot : (⊥ : TwoSidedIdeal R).matricesOver n = ⊥ := by + ext M + simp only [mem_matricesOver, mem_bot] + constructor + · intro H; ext; apply H + · intro H; simp [H] + +@[simp] +theorem matricesOver_top : (⊤ : TwoSidedIdeal R).matricesOver n = ⊤ := by + ext; simp + +theorem asIdeal_matricesOver [DecidableEq n] (I : TwoSidedIdeal R) : + asIdeal (I.matricesOver n) = (asIdeal I).matricesOver n := by + ext; simp + +variable {n : Type*} [Fintype n] [DecidableEq n] + +/-- +Two-sided ideals in $R$ correspond bijectively to those in $Mₙ(R)$. +Given an ideal $I ≤ R$, we send it to $Mₙ(I)$. +Given an ideal $J ≤ Mₙ(R)$, we send it to $\{Nᵢⱼ ∣ ∃ N ∈ J\}$. +-/ +@[simps] +def equivMatricesOver (i j : n) : TwoSidedIdeal R ≃ TwoSidedIdeal (Matrix n n R) where + toFun I := I.matricesOver n + invFun J := TwoSidedIdeal.mk' + { N i j | N ∈ J } + ⟨0, J.zero_mem, rfl⟩ + (by rintro _ _ ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩; exact ⟨x + y, J.add_mem hx hy, rfl⟩) + (by rintro _ ⟨x, hx, rfl⟩; exact ⟨-x, J.neg_mem hx, rfl⟩) + (by + rintro x _ ⟨y, hy, rfl⟩ + exact ⟨diagonal (fun _ ↦ x) * y, J.mul_mem_left _ _ hy, by simp⟩) + (by + rintro _ y ⟨x, hx, rfl⟩ + exact ⟨x * diagonal (fun _ ↦ y), J.mul_mem_right _ _ hx, by simp⟩) + right_inv J := SetLike.ext fun x ↦ by + simp only [mem_mk', Set.mem_image, SetLike.mem_coe, mem_matricesOver] + constructor + · intro h + choose y hy1 hy2 using h + rw [matrix_eq_sum_stdBasisMatrix x] + refine sum_mem fun k _ ↦ sum_mem fun l _ ↦ ?_ + suffices + stdBasisMatrix k l (x k l) = + stdBasisMatrix k i 1 * y k l * stdBasisMatrix j l 1 by + rw [this] + exact J.mul_mem_right _ _ (J.mul_mem_left _ _ <| hy1 _ _) + ext a b + by_cases hab : a = k ∧ b = l + · rcases hab with ⟨ha, hb⟩ + subst ha hb + simp only [StdBasisMatrix.apply_same, StdBasisMatrix.mul_right_apply_same, + StdBasisMatrix.mul_left_apply_same, one_mul, mul_one] + rw [hy2 a b] + · conv_lhs => + dsimp [stdBasisMatrix] + rw [if_neg (by tauto)] + rw [not_and_or] at hab + rcases hab with ha | hb + · rw [mul_assoc, StdBasisMatrix.mul_left_apply_of_ne (h := ha)] + · rw [StdBasisMatrix.mul_right_apply_of_ne (hbj := hb)] + · intro hx k l + refine ⟨stdBasisMatrix i k 1 * x * stdBasisMatrix l j 1, + J.mul_mem_right _ _ (J.mul_mem_left _ _ hx), ?_⟩ + rw [StdBasisMatrix.mul_right_apply_same, StdBasisMatrix.mul_left_apply_same, + mul_one, one_mul] + left_inv I := SetLike.ext fun x ↦ by + simp only [mem_mk', Set.mem_image, SetLike.mem_coe, mem_matricesOver] + constructor + · intro h + choose y hy1 hy2 using h + exact hy2 ▸ hy1 _ _ + · intro h + exact ⟨of fun _ _ => x, by simp [h], rfl⟩ + +/-- +Two-sided ideals in $R$ are order-isomorphic with those in $Mₙ(R)$. +See also `equivMatricesOver`. +-/ +@[simps!] +def orderIsoMatricesOver (i j : n) : TwoSidedIdeal R ≃o TwoSidedIdeal (Matrix n n R) where + __ := equivMatricesOver i j + map_rel_iff' {I J} := by + simp only [equivMatricesOver_apply] + constructor + · intro le x xI + specialize @le (of fun _ _ => x) (by simp [xI]) + letI : Inhabited n := ⟨i⟩ + simpa using le + · intro IJ M MI i j + exact IJ <| MI i j + +end TwoSidedIdeal diff --git a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean index 6ef3b1d0b480f..41e80c3f6b369 100644 --- a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean +++ b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean @@ -776,4 +776,21 @@ theorem det_conj' {M : Matrix m m α} (h : IsUnit M) (N : Matrix m m α) : end Det +/-! ### More results about traces -/ + + +section trace + +variable [Fintype m] [DecidableEq m] + +/-- A variant of `Matrix.trace_units_conj`. -/ +theorem trace_conj {M : Matrix m m α} (h : IsUnit M) (N : Matrix m m α) : + trace (M * N * M⁻¹) = trace N := by rw [← h.unit_spec, ← coe_units_inv, trace_units_conj] + +/-- A variant of `Matrix.trace_units_conj'`. -/ +theorem trace_conj' {M : Matrix m m α} (h : IsUnit M) (N : Matrix m m α) : + trace (M⁻¹ * N * M) = trace N := by rw [← h.unit_spec, ← coe_units_inv, trace_units_conj'] + +end trace + end Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/PosDef.lean b/Mathlib/LinearAlgebra/Matrix/PosDef.lean index 9343bc8070623..0f7ca95450e7f 100644 --- a/Mathlib/LinearAlgebra/Matrix/PosDef.lean +++ b/Mathlib/LinearAlgebra/Matrix/PosDef.lean @@ -150,7 +150,7 @@ protected lemma zpow [StarOrderedRing R] [DecidableEq n] · simpa using hM.pow n · simpa using (hM.pow n).inv -protected lemma add [CovariantClass R R (· + ·) (· ≤ · )] {A : Matrix m m R} {B : Matrix m m R} +protected lemma add [AddLeftMono R] {A : Matrix m m R} {B : Matrix m m R} (hA : A.PosSemidef) (hB : B.PosSemidef) : (A + B).PosSemidef := ⟨hA.isHermitian.add hB.isHermitian, fun x => by rw [add_mulVec, dotProduct_add] @@ -406,21 +406,21 @@ theorem _root_.Matrix.posDef_intCast_iff [StarOrderedRing R] [DecidableEq n] [No PosDef (d : Matrix n n R) ↔ 0 < d := posDef_diagonal_iff.trans <| by simp -protected lemma add_posSemidef [CovariantClass R R (· + ·) (· ≤ · )] +protected lemma add_posSemidef [AddLeftMono R] {A : Matrix m m R} {B : Matrix m m R} (hA : A.PosDef) (hB : B.PosSemidef) : (A + B).PosDef := ⟨hA.isHermitian.add hB.isHermitian, fun x hx => by rw [add_mulVec, dotProduct_add] exact add_pos_of_pos_of_nonneg (hA.2 x hx) (hB.2 x)⟩ -protected lemma posSemidef_add [CovariantClass R R (· + ·) (· ≤ · )] +protected lemma posSemidef_add [AddLeftMono R] {A : Matrix m m R} {B : Matrix m m R} (hA : A.PosSemidef) (hB : B.PosDef) : (A + B).PosDef := ⟨hA.isHermitian.add hB.isHermitian, fun x hx => by rw [add_mulVec, dotProduct_add] exact add_pos_of_nonneg_of_pos (hA.2 x) (hB.2 x hx)⟩ -protected lemma add [CovariantClass R R (· + ·) (· ≤ · )] {A : Matrix m m R} {B : Matrix m m R} +protected lemma add [AddLeftMono R] {A : Matrix m m R} {B : Matrix m m R} (hA : A.PosDef) (hB : B.PosDef) : (A + B).PosDef := hA.add_posSemidef hB.posSemidef diff --git a/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean b/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean index abb3fa721cfad..2ab689b9d2f8f 100644 --- a/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean +++ b/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean @@ -124,6 +124,9 @@ instance : Pow (SpecialLinearGroup n R) ℕ where instance : Inhabited (SpecialLinearGroup n R) := ⟨1⟩ +instance [Fintype R] [DecidableEq R] : Fintype (SpecialLinearGroup n R) := Subtype.fintype _ +instance [Finite R] : Finite (SpecialLinearGroup n R) := Subtype.finite + /-- The transpose of a matrix in `SL(n, R)` -/ def transpose (A : SpecialLinearGroup n R) : SpecialLinearGroup n R := ⟨A.1.transpose, A.1.det_transpose ▸ A.2⟩ @@ -299,7 +302,7 @@ noncomputable def center_equiv_rootsOfUnity : (fun hn ↦ by rw [center_eq_bot_of_subsingleton, Fintype.card_eq_zero, Nat.toPNat'_zero, rootsOfUnity_one] exact MulEquiv.mulEquivOfUnique) - (fun hn ↦ center_equiv_rootsOfUnity' (Classical.arbitrary n)) + (fun _ ↦ center_equiv_rootsOfUnity' (Classical.arbitrary n)) end center @@ -490,4 +493,10 @@ theorem T_mul_apply_one (g : SL(2, ℤ)) : ↑ₘ(T * g) 1 = ↑ₘg 1 := by theorem T_inv_mul_apply_one (g : SL(2, ℤ)) : ↑ₘ(T⁻¹ * g) 1 = ↑ₘg 1 := by simpa using T_pow_mul_apply_one (-1) g +lemma S_mul_S_eq : (↑ₘS * ↑ₘS) = -1 := by + simp only [S, Int.reduceNeg, pow_two, coe_mul, cons_mul, Nat.succ_eq_add_one, Nat.reduceAdd, + vecMul_cons, head_cons, zero_smul, tail_cons, neg_smul, one_smul, neg_cons, neg_zero, neg_empty, + empty_vecMul, add_zero, zero_add, empty_mul, Equiv.symm_apply_apply] + exact Eq.symm (eta_fin_two (-1)) + end ModularGroup diff --git a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean index e20e0a672cfc3..9f15fd930b639 100644 --- a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean +++ b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean @@ -7,7 +7,6 @@ import Mathlib.Analysis.InnerProductSpace.Spectrum import Mathlib.Data.Matrix.Rank import Mathlib.LinearAlgebra.Matrix.Diagonal import Mathlib.LinearAlgebra.Matrix.Hermitian -import Mathlib.Analysis.CStarAlgebra.Matrix import Mathlib.Topology.Algebra.Module.FiniteDimension /-! # Spectral theory of hermitian matrices @@ -54,12 +53,7 @@ lemma mulVec_eigenvectorBasis (j : n) : /-- The spectrum of a Hermitian matrix `A` coincides with the spectrum of `toEuclideanLin A`. -/ theorem spectrum_toEuclideanLin : spectrum 𝕜 (toEuclideanLin A) = spectrum 𝕜 A := - AlgEquiv.spectrum_eq - (AlgEquiv.trans - ((toEuclideanCLM : Matrix n n 𝕜 ≃⋆ₐ[𝕜] EuclideanSpace 𝕜 n →L[𝕜] EuclideanSpace 𝕜 n) : - Matrix n n 𝕜 ≃ₐ[𝕜] EuclideanSpace 𝕜 n →L[𝕜] EuclideanSpace 𝕜 n) - (Module.End.toContinuousLinearMap (EuclideanSpace 𝕜 n)).symm) - _ + AlgEquiv.spectrum_eq (Matrix.toLinAlgEquiv (PiLp.basisFun 2 𝕜 n)) _ /-- Eigenvalues of a hermitian matrix A are in the ℝ spectrum of A. -/ theorem eigenvalues_mem_spectrum_real (i : n) : hA.eigenvalues i ∈ spectrum ℝ A := by diff --git a/Mathlib/LinearAlgebra/Matrix/ToLin.lean b/Mathlib/LinearAlgebra/Matrix/ToLin.lean index 803a75b7be149..693066a10400f 100644 --- a/Mathlib/LinearAlgebra/Matrix/ToLin.lean +++ b/Mathlib/LinearAlgebra/Matrix/ToLin.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Matrix.Notation import Mathlib.LinearAlgebra.StdBasis import Mathlib.RingTheory.AlgebraTower import Mathlib.Algebra.Algebra.Subalgebra.Tower +import Mathlib.Data.Finite.Sum /-! # Linear maps and matrices @@ -959,7 +960,7 @@ lemma linearMap_apply_apply (ij : ι₂ × ι₁) (k : ι₁) : (b₁.linearMap b₂ ij) (b₁ k) = if ij.2 = k then b₂ ij.1 else 0 := by have := Classical.decEq ι₂ rw [linearMap_apply, Matrix.stdBasis_eq_stdBasisMatrix, Matrix.toLin_self] - dsimp only [Matrix.stdBasisMatrix] + dsimp only [Matrix.stdBasisMatrix, of_apply] simp_rw [ite_smul, one_smul, zero_smul, ite_and, Finset.sum_ite_eq, Finset.mem_univ, if_true] /-- The standard basis of the endomorphism algebra of a module diff --git a/Mathlib/LinearAlgebra/Matrix/Trace.lean b/Mathlib/LinearAlgebra/Matrix/Trace.lean index fbc571b846cfc..86b9568b2b0d9 100644 --- a/Mathlib/LinearAlgebra/Matrix/Trace.lean +++ b/Mathlib/LinearAlgebra/Matrix/Trace.lean @@ -103,8 +103,9 @@ theorem trace_sum (s : Finset ι) (f : ι → Matrix n n R) : trace (∑ i ∈ s, f i) = ∑ i ∈ s, trace (f i) := map_sum (traceAddMonoidHom n R) f s -theorem _root_.AddMonoidHom.map_trace [AddCommMonoid S] (f : R →+ S) (A : Matrix n n R) : - f (trace A) = trace (f.mapMatrix A) := +theorem _root_.AddMonoidHom.map_trace [AddCommMonoid S] {F : Type*} [FunLike F R S] + [AddMonoidHomClass F R S] (f : F) (A : Matrix n n R) : + f (trace A) = trace ((f : R →+ S).mapMatrix A) := map_sum f (fun i => diag A i) Finset.univ lemma trace_blockDiagonal [DecidableEq p] (M : p → Matrix n n R) : @@ -175,6 +176,23 @@ lemma trace_submatrix_succ {n : ℕ} [NonUnitalNonAssocSemiring R] rw [← (finSuccEquiv n).symm.sum_comp] simp +section CommSemiring + +variable [DecidableEq m] [CommSemiring R] + +-- TODO(mathlib4#6607): fix elaboration so that the ascription isn't needed +theorem trace_units_conj (M : (Matrix m m R)ˣ) (N : Matrix m m R) : + trace ((M : Matrix _ _ _) * N * (↑M⁻¹ : Matrix _ _ _)) = trace N := by + rw [trace_mul_cycle, Units.inv_mul, one_mul] + +set_option linter.docPrime false in +-- TODO(mathlib4#6607): fix elaboration so that the ascription isn't needed +theorem trace_units_conj' (M : (Matrix m m R)ˣ) (N : Matrix m m R) : + trace ((↑M⁻¹ : Matrix _ _ _) * N * (↑M : Matrix _ _ _)) = trace N := + trace_units_conj M⁻¹ N + +end CommSemiring + section Fin variable [AddCommMonoid R] diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean index 25022902c14a5..9b8313b2b87e7 100644 --- a/Mathlib/LinearAlgebra/Multilinear/Basic.lean +++ b/Mathlib/LinearAlgebra/Multilinear/Basic.lean @@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.Algebra.Algebra.Defs -import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.NoZeroSMulDivisors.Pi import Mathlib.Data.Fintype.BigOperators import Mathlib.Data.Fintype.Sort -import Mathlib.Data.List.FinRange import Mathlib.LinearAlgebra.Pi import Mathlib.Logic.Equiv.Fintype import Mathlib.Tactic.Abel @@ -72,8 +71,7 @@ something similar, but of the form `Fin.decidableEq n = _inst`, which is much ea since `_inst` is a free variable and so the equality can just be substituted. -/ - -open Function Fin Set +open Fin Function Finset Set universe uR uS uι v v' v₁ v₂ v₃ @@ -106,7 +104,6 @@ variable [Semiring R] [∀ i, AddCommMonoid (M i)] [∀ i, AddCommMonoid (M₁ i [AddCommMonoid M₃] [AddCommMonoid M'] [∀ i, Module R (M i)] [∀ i, Module R (M₁ i)] [Module R M₂] [Module R M₃] [Module R M'] (f f' : MultilinearMap R M₁ M₂) --- Porting note: Replaced CoeFun with FunLike instance instance : FunLike (MultilinearMap R M₁ M₂) (∀ i, M₁ i) M₂ where coe f := f.toFun coe_injective' f g h := by cases f; cases g; cases h; rfl @@ -130,7 +127,7 @@ nonrec theorem congr_arg (f : MultilinearMap R M₁ M₂) {x y : ∀ i, M₁ i} theorem coe_injective : Injective ((↑) : MultilinearMap R M₁ M₂ → (∀ i, M₁ i) → M₂) := DFunLike.coe_injective -@[norm_cast] -- Porting note (#10618): Removed simp attribute, simp can prove this +@[norm_cast] theorem coe_inj {f g : MultilinearMap R M₁ M₂} : (f : (∀ i, M₁ i) → M₂) = g ↔ f = g := DFunLike.coe_fn_eq @@ -176,7 +173,7 @@ theorem add_apply (m : ∀ i, M₁ i) : (f + f') m = f m + f' m := rfl instance : Zero (MultilinearMap R M₁ M₂) := - ⟨⟨fun _ => 0, fun _ i _ _ => by simp, fun _ i c _ => by simp⟩⟩ + ⟨⟨fun _ => 0, fun _ _ _ _ => by simp, fun _ _ c _ => by simp⟩⟩ instance : Inhabited (MultilinearMap R M₁ M₂) := ⟨0⟩ @@ -260,7 +257,7 @@ def ofSubsingleton [Subsingleton ι] (i : ι) : { toFun := fun x ↦ f fun _ ↦ x map_add' := fun x y ↦ by simpa [update_eq_const_of_subsingleton] using f.map_add 0 i x y map_smul' := fun c x ↦ by simpa [update_eq_const_of_subsingleton] using f.map_smul 0 i c x } - left_inv f := rfl + left_inv _ := rfl right_inv f := by ext x; refine congr_arg f ?_; exact (eq_const_of_subsingleton _ _).symm variable (M₁) {M₂} @@ -282,7 +279,7 @@ the other ones equal to a given value `z`. It is denoted by `f.restr s hk z`, wh proof that the cardinality of `s` is `k`. The implicit identification between `Fin k` and `s` that we use is the canonical (increasing) bijection. -/ def restr {k n : ℕ} (f : MultilinearMap R (fun _ : Fin n => M') M₂) (s : Finset (Fin n)) - (hk : s.card = k) (z : M') : MultilinearMap R (fun _ : Fin k => M') M₂ where + (hk : #s = k) (z : M') : MultilinearMap R (fun _ : Fin k => M') M₂ where toFun v := f fun j => if h : j ∈ s then v ((DFunLike.coe (s.orderIsoOfFin hk).symm) ⟨j, h⟩) else z /- Porting note: The proofs of the following two lemmas used to only use `erw` followed by `simp`, but it seems `erw` no longer unfolds or unifies well enough to work without more help. -/ @@ -447,7 +444,7 @@ open Fintype Finset `r n ∈ Aₙ`. This follows from multilinearity by expanding successively with respect to each coordinate. Here, we give an auxiliary statement tailored for an inductive proof. Use instead `map_sum_finset`. -/ -theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, (A i).card) = n) : +theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, #(A i)) = n) : (f fun i => ∑ j ∈ A i, g i j) = ∑ r ∈ piFinset A, f fun i => g i (r i) := by letI := fun i => Classical.decEq (α i) induction' n using Nat.strong_induction_on with n IH generalizing A @@ -459,11 +456,11 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, push_neg at Ai_empty -- Otherwise, if all sets are at most singletons, then they are exactly singletons and the result -- is again straightforward - by_cases Ai_singleton : ∀ i, (A i).card ≤ 1 - · have Ai_card : ∀ i, (A i).card = 1 := by + by_cases Ai_singleton : ∀ i, #(A i) ≤ 1 + · have Ai_card : ∀ i, #(A i) = 1 := by intro i - have pos : Finset.card (A i) ≠ 0 := by simp [Finset.card_eq_zero, Ai_empty i] - have : Finset.card (A i) ≤ 1 := Ai_singleton i + have pos : #(A i) ≠ 0 := by simp [Finset.card_eq_zero, Ai_empty i] + have : #(A i) ≤ 1 := Ai_singleton i exact le_antisymm this (Nat.succ_le_of_lt (_root_.pos_iff_ne_zero.mpr pos)) have : ∀ r : ∀ i, α i, r ∈ piFinset A → (f fun i => g i (r i)) = f fun i => ∑ j ∈ A i, g i j := by @@ -482,7 +479,7 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, -- for `i ≠ i₀`, apply the inductive assumption to `B` and `C`, and add up the corresponding -- parts to get the sum for `A`. push_neg at Ai_singleton - obtain ⟨i₀, hi₀⟩ : ∃ i, 1 < (A i).card := Ai_singleton + obtain ⟨i₀, hi₀⟩ : ∃ i, 1 < #(A i) := Ai_singleton obtain ⟨j₁, j₂, _, hj₂, _⟩ : ∃ j₁ j₂, j₁ ∈ A i₀ ∧ j₂ ∈ A i₀ ∧ j₁ ≠ j₂ := Finset.one_lt_card_iff.1 hi₀ let B := Function.update A i₀ (A i₀ \ {j₂}) @@ -537,10 +534,8 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, · simp only [C, hi, update_noteq, Ne, not_false_iff] -- Express the inductive assumption for `B` have Brec : (f fun i => ∑ j ∈ B i, g i j) = ∑ r ∈ piFinset B, f fun i => g i (r i) := by - have : (∑ i, Finset.card (B i)) < ∑ i, Finset.card (A i) := by - refine - Finset.sum_lt_sum (fun i _ => Finset.card_le_card (B_subset_A i)) - ⟨i₀, Finset.mem_univ _, ?_⟩ + have : ∑ i, #(B i) < ∑ i, #(A i) := by + refine sum_lt_sum (fun i _ => card_le_card (B_subset_A i)) ⟨i₀, mem_univ _, ?_⟩ have : {j₂} ⊆ A i₀ := by simp [hj₂] simp only [B, Finset.card_sdiff this, Function.update_same, Finset.card_singleton] exact Nat.pred_lt (ne_of_gt (lt_trans Nat.zero_lt_one hi₀)) @@ -548,7 +543,7 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, exact IH _ this B rfl -- Express the inductive assumption for `C` have Crec : (f fun i => ∑ j ∈ C i, g i j) = ∑ r ∈ piFinset C, f fun i => g i (r i) := by - have : (∑ i, Finset.card (C i)) < ∑ i, Finset.card (A i) := + have : (∑ i, #(C i)) < ∑ i, #(A i) := Finset.sum_lt_sum (fun i _ => Finset.card_le_card (C_subset_A i)) ⟨i₀, Finset.mem_univ _, by simp [C, hi₀]⟩ rw [h] at this @@ -788,6 +783,36 @@ theorem compMultilinearMap_apply (g : M₂ →ₗ[R] M₃) (f : MultilinearMap R g.compMultilinearMap f m = g (f m) := rfl +@[simp] +theorem compMultilinearMap_zero (g : M₂ →ₗ[R] M₃) : + g.compMultilinearMap (0 : MultilinearMap R M₁ M₂) = 0 := + MultilinearMap.ext fun _ => map_zero g + +@[simp] +theorem zero_compMultilinearMap (f: MultilinearMap R M₁ M₂) : + (0 : M₂ →ₗ[R] M₃).compMultilinearMap f = 0 := rfl + +@[simp] +theorem compMultilinearMap_add (g : M₂ →ₗ[R] M₃) (f₁ f₂ : MultilinearMap R M₁ M₂) : + g.compMultilinearMap (f₁ + f₂) = g.compMultilinearMap f₁ + g.compMultilinearMap f₂ := + MultilinearMap.ext fun _ => map_add g _ _ + +@[simp] +theorem add_compMultilinearMap (g₁ g₂ : M₂ →ₗ[R] M₃) (f: MultilinearMap R M₁ M₂) : + (g₁ + g₂).compMultilinearMap f = g₁.compMultilinearMap f + g₂.compMultilinearMap f := rfl + +@[simp] +theorem compMultilinearMap_smul [Monoid S] [DistribMulAction S M₂] [DistribMulAction S M₃] + [SMulCommClass R S M₂] [SMulCommClass R S M₃] [CompatibleSMul M₂ M₃ S R] + (g : M₂ →ₗ[R] M₃) (s : S) (f : MultilinearMap R M₁ M₂) : + g.compMultilinearMap (s • f) = s • g.compMultilinearMap f := + MultilinearMap.ext fun _ => g.map_smul_of_tower _ _ + +@[simp] +theorem smul_compMultilinearMap [Monoid S] [DistribMulAction S M₃] [SMulCommClass R S M₃] + (g : M₂ →ₗ[R] M₃) (s : S) (f : MultilinearMap R M₁ M₂) : + (s • g).compMultilinearMap f = s • g.compMultilinearMap f := rfl + /-- The multilinear version of `LinearMap.subtype_comp_codRestrict` -/ @[simp] theorem subtype_compMultilinearMap_codRestrict (f : MultilinearMap R M₁ M₂) (p : Submodule R M₂) @@ -836,12 +861,23 @@ instance : Module S (MultilinearMap R M₁ M₂) := instance [NoZeroSMulDivisors S M₂] : NoZeroSMulDivisors S (MultilinearMap R M₁ M₂) := coe_injective.noZeroSMulDivisors _ rfl coe_smul +variable [AddCommMonoid M₃] [Module S M₃] [Module R M₃] [SMulCommClass R S M₃] + +variable (S) in +/-- `LinearMap.compMultilinearMap` as an `S`-linear map. -/ +@[simps] +def _root_.LinearMap.compMultilinearMapₗ [Semiring S] [Module S M₂] [Module S M₃] + [SMulCommClass R S M₂] [SMulCommClass R S M₃] [LinearMap.CompatibleSMul M₂ M₃ S R] + (g : M₂ →ₗ[R] M₃) : + MultilinearMap R M₁ M₂ →ₗ[S] MultilinearMap R M₁ M₃ where + toFun := g.compMultilinearMap + map_add' := g.compMultilinearMap_add + map_smul' := g.compMultilinearMap_smul + variable (R S M₁ M₂ M₃) section OfSubsingleton -variable [AddCommMonoid M₃] [Module S M₃] [Module R M₃] [SMulCommClass R S M₃] - /-- Linear equivalence between linear maps `M₂ →ₗ[R] M₃` and one-multilinear maps `MultilinearMap R (fun _ : ι ↦ M₂) M₃`. -/ @[simps (config := { simpRhs := true })] @@ -905,8 +941,6 @@ def constLinearEquivOfIsEmpty [IsEmpty ι] : M₂ ≃ₗ[S] MultilinearMap R M left_inv _ := rfl right_inv f := ext fun _ => MultilinearMap.congr_arg f <| Subsingleton.elim _ _ -variable [AddCommMonoid M₃] [Module R M₃] [Module S M₃] [SMulCommClass R S M₃] - /-- `MultilinearMap.domDomCongr` as a `LinearEquiv`. -/ @[simps apply symm_apply] def domDomCongrLinearEquiv {ι₁ ι₂} (σ : ι₁ ≃ ι₂) : @@ -1004,7 +1038,7 @@ sending a multilinear map `g` to `g (f₁ ⬝ , ..., fₙ ⬝ )` is linear in `g @[simps] def compLinearMapMultilinear : @MultilinearMap R ι (fun i ↦ M₁ i →ₗ[R] M₁' i) ((MultilinearMap R M₁' M₂) →ₗ[R] MultilinearMap R M₁ M₂) _ _ _ - (fun i ↦ LinearMap.module) _ where + (fun _ ↦ LinearMap.module) _ where toFun := MultilinearMap.compLinearMapₗ map_add' := by intro _ f i f₁ f₂ @@ -1208,16 +1242,16 @@ theorem sub_apply (m : ∀ i, M₁ i) : (f - g) m = f m - g m := instance : AddCommGroup (MultilinearMap R M₁ M₂) := { MultilinearMap.addCommMonoid with - neg_add_cancel := fun a => MultilinearMap.ext fun v => neg_add_cancel _ - sub_eq_add_neg := fun a b => MultilinearMap.ext fun v => sub_eq_add_neg _ _ + neg_add_cancel := fun _ => MultilinearMap.ext fun _ => neg_add_cancel _ + sub_eq_add_neg := fun _ _ => MultilinearMap.ext fun _ => sub_eq_add_neg _ _ zsmul := fun n f => { toFun := fun m => n • f m map_add' := fun m i x y => by simp [smul_add] map_smul' := fun l i x d => by simp [← smul_comm x n (_ : M₂)] } -- Porting note: changed from `AddCommGroup` to `SubNegMonoid` - zsmul_zero' := fun a => MultilinearMap.ext fun v => SubNegMonoid.zsmul_zero' _ - zsmul_succ' := fun z a => MultilinearMap.ext fun v => SubNegMonoid.zsmul_succ' _ _ - zsmul_neg' := fun z a => MultilinearMap.ext fun v => SubNegMonoid.zsmul_neg' _ _ } + zsmul_zero' := fun _ => MultilinearMap.ext fun _ => SubNegMonoid.zsmul_zero' _ + zsmul_succ' := fun _ _ => MultilinearMap.ext fun _ => SubNegMonoid.zsmul_succ' _ _ + zsmul_neg' := fun _ _ => MultilinearMap.ext fun _ => SubNegMonoid.zsmul_neg' _ _ } end RangeAddCommGroup @@ -1282,10 +1316,9 @@ lemma map_piecewise_sub_map_piecewise [LinearOrder ι] (a b v : (i : ι) → M open Finset in lemma map_add_eq_map_add_linearDeriv_add [DecidableEq ι] [Fintype ι] (x h : (i : ι) → M₁ i) : - f (x + h) = f x + f.linearDeriv x h + - ∑ s ∈ univ.powerset.filter (2 ≤ ·.card), f (s.piecewise h x) := by + f (x + h) = f x + f.linearDeriv x h + ∑ s with 2 ≤ #s, f (s.piecewise h x) := by rw [add_comm, map_add_univ, ← Finset.powerset_univ, - ← sum_filter_add_sum_filter_not _ (2 ≤ ·.card)] + ← sum_filter_add_sum_filter_not _ (2 ≤ #·)] simp_rw [not_le, Nat.lt_succ, le_iff_lt_or_eq (b := 1), Nat.lt_one_iff, filter_or, ← powersetCard_eq_filter, sum_union (univ.pairwise_disjoint_powersetCard zero_ne_one), powersetCard_zero, powersetCard_one, sum_singleton, Finset.piecewise_empty, sum_map, @@ -1297,7 +1330,7 @@ at two points "close to `x`" in terms of the "derivative" of the multilinear map and of "second-order" terms. -/ lemma map_add_sub_map_add_sub_linearDeriv [DecidableEq ι] [Fintype ι] (x h h' : (i : ι) → M₁ i) : f (x + h) - f (x + h') - f.linearDeriv x (h - h') = - ∑ s ∈ univ.powerset.filter (2 ≤ ·.card), (f (s.piecewise h x) - f (s.piecewise h' x)) := by + ∑ s with 2 ≤ #s, (f (s.piecewise h x) - f (s.piecewise h' x)) := by simp_rw [map_add_eq_map_add_linearDeriv_add, add_assoc, add_sub_add_comm, sub_self, zero_add, ← LinearMap.map_sub, add_sub_cancel_left, sum_sub_distrib] @@ -1642,7 +1675,7 @@ variable (R M₂ M') `l`, then the space of multilinear maps on `fun i : Fin n => M'` is isomorphic to the space of multilinear maps on `fun i : Fin k => M'` taking values in the space of multilinear maps on `fun i : Fin l => M'`. -/ -def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) (hl : sᶜ.card = l) : +def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) : MultilinearMap R (fun _ : Fin n => M') M₂ ≃ₗ[R] MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂) := (domDomCongrLinearEquiv R R M' M₂ (finSumEquivOfFinset hk hl).symm).trans @@ -1651,15 +1684,15 @@ def curryFinFinset {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) (hl : s variable {R M₂ M'} @[simp] -theorem curryFinFinset_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) (hl : sᶜ.card = l) +theorem curryFinFinset_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (mk : Fin k → M') (ml : Fin l → M') : curryFinFinset R M₂ M' hk hl f mk ml = f fun i => Sum.elim mk ml ((finSumEquivOfFinset hk hl).symm i) := rfl @[simp] -theorem curryFinFinset_symm_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) - (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) + (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) (m : Fin n → M') : (curryFinFinset R M₂ M' hk hl).symm f m = @@ -1668,8 +1701,8 @@ theorem curryFinFinset_symm_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : s.car rfl -- @[simp] -- Porting note: simpNF linter, lhs simplifies, added aux version below -theorem curryFinFinset_symm_apply_piecewise_const {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) - (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply_piecewise_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) + (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) (x y : M') : (curryFinFinset R M₂ M' hk hl).symm f (s.piecewise (fun _ => x) fun _ => y) = @@ -1684,7 +1717,7 @@ theorem curryFinFinset_symm_apply_piecewise_const {k l n : ℕ} {s : Finset (Fin @[simp] theorem curryFinFinset_symm_apply_piecewise_const_aux {k l n : ℕ} {s : Finset (Fin n)} - (hk : s.card = k) (hl : sᶜ.card = l) + (hk : #s = k) (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) (x y : M') : ((⇑f fun _ => x) (fun i => (Finset.piecewise s (fun _ => x) (fun _ => y) @@ -1695,15 +1728,15 @@ theorem curryFinFinset_symm_apply_piecewise_const_aux {k l n : ℕ} {s : Finset exact this @[simp] -theorem curryFinFinset_symm_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) - (hl : sᶜ.card = l) +theorem curryFinFinset_symm_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) + (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) (x : M') : ((curryFinFinset R M₂ M' hk hl).symm f fun _ => x) = f (fun _ => x) fun _ => x := rfl -- @[simp] -- Porting note: simpNF, lhs simplifies, added aux version below -theorem curryFinFinset_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) - (hl : sᶜ.card = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : +theorem curryFinFinset_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) + (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : (curryFinFinset R M₂ M' hk hl f (fun _ => x) fun _ => y) = f (s.piecewise (fun _ => x) fun _ => y) := by refine (curryFinFinset_symm_apply_piecewise_const hk hl _ _ _).symm.trans ?_ @@ -1711,8 +1744,8 @@ theorem curryFinFinset_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : s.ca rw [LinearEquiv.symm_apply_apply] @[simp] -theorem curryFinFinset_apply_const_aux {k l n : ℕ} {s : Finset (Fin n)} (hk : s.card = k) - (hl : sᶜ.card = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : +theorem curryFinFinset_apply_const_aux {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) + (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : (f fun i => Sum.elim (fun _ => x) (fun _ => y) ((⇑ (Equiv.symm (finSumEquivOfFinset hk hl))) i)) = f (s.piecewise (fun _ => x) fun _ => y) := by rw [← curryFinFinset_apply] diff --git a/Mathlib/LinearAlgebra/Multilinear/DFinsupp.lean b/Mathlib/LinearAlgebra/Multilinear/DFinsupp.lean new file mode 100644 index 0000000000000..29ccf70c57c39 --- /dev/null +++ b/Mathlib/LinearAlgebra/Multilinear/DFinsupp.lean @@ -0,0 +1,181 @@ +/- +Copyright (c) 2024 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser, Sophie Morel +-/ +import Mathlib.LinearAlgebra.DFinsupp +import Mathlib.LinearAlgebra.Multilinear.Basic + +/-! +# Interactions between finitely-supported functions and multilinear maps + +## Main definitions + +* `MultilinearMap.dfinsupp_ext` +* `MultilinearMap.dfinsuppFamily`, which satisfies + `dfinsuppFamily f x p = f p (fun i => x i (p i))`. + + This is the finitely-supported version of `MultilinearMap.piFamily`. + + This is useful because all the intermediate results are bundled: + + - `MultilinearMap.dfinsuppFamily f x` is a `DFinsupp` supported by families of indices `p`. + - `MultilinearMap.dfinsuppFamily f` is a `MultilinearMap` operating on finitely-supported + functions `x`. + - `MultilinearMap.dfinsuppFamilyₗ` is a `LinearMap`, linear in the family of multilinear maps `f`. + +-/ + +universe uι uκ uS uR uM uN +variable {ι : Type uι} {κ : ι → Type uκ} +variable {S : Type uS} {R : Type uR} + +namespace MultilinearMap + +section Semiring +variable {M : ∀ i, κ i → Type uM} {N : Type uN} + +variable [DecidableEq ι] [Fintype ι] [Semiring R] +variable [∀ i k, AddCommMonoid (M i k)] [ AddCommMonoid N] +variable [∀ i k, Module R (M i k)] [Module R N] + +/-- Two multilinear maps from finitely supported functions are equal if they agree on the +generators. + +This is a multilinear version of `DFinsupp.lhom_ext'`. -/ +@[ext] +theorem dfinsupp_ext [∀ i, DecidableEq (κ i)] + ⦃f g : MultilinearMap R (fun i ↦ Π₀ j : κ i, M i j) N⦄ + (h : ∀ p : Π i, κ i, + f.compLinearMap (fun i => DFinsupp.lsingle (p i)) = + g.compLinearMap (fun i => DFinsupp.lsingle (p i))) : f = g := by + ext x + show f (fun i ↦ x i) = g (fun i ↦ x i) + classical + rw [funext (fun i ↦ Eq.symm (DFinsupp.sum_single (f := x i)))] + simp_rw [DFinsupp.sum, MultilinearMap.map_sum_finset] + congr! 1 with p + simp_rw [MultilinearMap.ext_iff] at h + exact h _ _ + +end Semiring + +section dfinsuppFamily +variable {M : ∀ i, κ i → Type uM} {N : (Π i, κ i) → Type uN} + +section Semiring + +variable [DecidableEq ι] [Fintype ι] [Semiring R] +variable [∀ i k, AddCommMonoid (M i k)] [∀ p, AddCommMonoid (N p)] +variable [∀ i k, Module R (M i k)] [∀ p, Module R (N p)] + +/-- +Given a family of indices `κ` and a multilinear map `f p` for each way `p` to select one index from +each family, `dfinsuppFamily f` maps a family of finitely-supported functions (one for each domain +`κ i`) into a finitely-supported function from each selection of indices (with domain `Π i, κ i`). + +Strictly this doesn't need multilinearity, only the fact that `f p m = 0` whenever `m i = 0` for +some `i`. + +This is the `DFinsupp` version of `MultilinearMap.piFamily`. +-/ +@[simps] +def dfinsuppFamily + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + MultilinearMap R (fun i => Π₀ j : κ i, M i j) (Π₀ t : Π i, κ i, N t) where + toFun x := + { toFun := fun p => f p (fun i => x i (p i)) + support' := (Trunc.finChoice fun i => (x i).support').map fun s => ⟨ + Finset.univ.val.pi (fun i ↦ (s i).val) |>.map fun f i => f i (Finset.mem_univ _), + fun p => by + simp only [Multiset.mem_map, Multiset.mem_pi, Finset.mem_val, Finset.mem_univ, + forall_true_left] + simp_rw [or_iff_not_imp_right] + intro h + push_neg at h + refine ⟨fun i _ => p i, fun i => (s i).prop _ |>.resolve_right ?_, rfl⟩ + exact mt ((f p).map_coord_zero (m := fun i => x i _) i) h⟩} + map_add' {dec} m i x y := DFinsupp.ext fun p => by + cases Subsingleton.elim dec (by infer_instance) + dsimp + simp_rw [Function.apply_update (fun i m => m (p i)) m, DFinsupp.add_apply, (f p).map_add] + map_smul' {dec} m i c x := DFinsupp.ext fun p => by + cases Subsingleton.elim dec (by infer_instance) + dsimp + simp_rw [Function.apply_update (fun i m => m (p i)) m, DFinsupp.smul_apply, (f p).map_smul] + +theorem support_dfinsuppFamily_subset + [∀ i, DecidableEq (κ i)] + [∀ i j, (x : M i j) → Decidable (x ≠ 0)] [∀ i, (x : N i) → Decidable (x ≠ 0)] + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) + (x : ∀ i, Π₀ j : κ i, M i j) : + (dfinsuppFamily f x).support ⊆ Fintype.piFinset fun i => (x i).support := by + intro p hp + simp only [DFinsupp.mem_support_toFun, dfinsuppFamily_apply_toFun, ne_eq, + Fintype.mem_piFinset] at hp ⊢ + intro i + exact mt ((f p).map_coord_zero (m := fun i => x i _) i) hp + +/-- When applied to a family of finitely-supported functions each supported on a single element, +`dfinsuppFamily` is itself supported on a single element, with value equal to the map `f` applied +at that point. -/ +@[simp] +theorem dfinsuppFamily_single [∀ i, DecidableEq (κ i)] + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) + (p : ∀ i, κ i) (m : ∀ i, M i (p i)) : + dfinsuppFamily f (fun i => .single (p i) (m i)) = DFinsupp.single p (f p m) := by + ext q + obtain rfl | hpq := eq_or_ne p q + · simp + · rw [DFinsupp.single_eq_of_ne hpq] + rw [Function.ne_iff] at hpq + obtain ⟨i, hpqi⟩ := hpq + apply (f q).map_coord_zero i + simp_rw [DFinsupp.single_eq_of_ne hpqi] + +@[simp] +theorem dfinsuppFamily_compLinearMap_lsingle [∀ i, DecidableEq (κ i)] + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) (p : ∀ i, κ i) : + (dfinsuppFamily f).compLinearMap (fun i => DFinsupp.lsingle (p i)) + = (DFinsupp.lsingle p).compMultilinearMap (f p) := + MultilinearMap.ext <| dfinsuppFamily_single f p + +@[simp] +theorem dfinsuppFamily_zero : + dfinsuppFamily (0 : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) = 0 := by + ext; simp + +@[simp] +theorem dfinsuppFamily_add (f g : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + dfinsuppFamily (f + g) = dfinsuppFamily f + dfinsuppFamily g := by + ext; simp + +@[simp] +theorem dfinsuppFamily_smul + [Monoid S] [∀ p, DistribMulAction S (N p)] [∀ p, SMulCommClass R S (N p)] + (s : S) (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + dfinsuppFamily (s • f) = s • dfinsuppFamily f := by + ext; simp + +end Semiring + +section CommSemiring + +variable [DecidableEq ι] [Fintype ι] [CommSemiring R] +variable [∀ i k, AddCommMonoid (M i k)] [∀ p, AddCommMonoid (N p)] +variable [∀ i k, Module R (M i k)] [∀ p, Module R (N p)] + +/-- `MultilinearMap.dfinsuppFamily` as a linear map. -/ +@[simps] +def dfinsuppFamilyₗ : + (Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) + →ₗ[R] MultilinearMap R (fun i => Π₀ j : κ i, M i j) (Π₀ t : Π i, κ i, N t) where + toFun := dfinsuppFamily + map_add' := dfinsuppFamily_add + map_smul' := dfinsuppFamily_smul + +end CommSemiring + +end dfinsuppFamily + +end MultilinearMap diff --git a/Mathlib/LinearAlgebra/Multilinear/Pi.lean b/Mathlib/LinearAlgebra/Multilinear/Pi.lean new file mode 100644 index 0000000000000..9850e973b88a8 --- /dev/null +++ b/Mathlib/LinearAlgebra/Multilinear/Pi.lean @@ -0,0 +1,147 @@ +/- +Copyright (c) 2024 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.LinearAlgebra.Pi +import Mathlib.LinearAlgebra.Multilinear.Basic + +/-! +# Interactions between (dependent) functions and multilinear maps + +## Main definitions + +* `MultilinearMap.pi_ext`, a multilinear version of `LinearMap.pi_ext` +* `MultilinearMap.piFamily`, which satisfies `piFamily f x p = f p (fun i => x i (p i))`. + + This is useful because all the intermediate results are bundled: + + - `MultilinearMap.piFamily f` is a `MultilinearMap` operating on functions `x`. + - `MultilinearMap.piFamilyₗ` is a `LinearMap`, linear in the family of multilinear maps `f`. +-/ + +universe uι uκ uS uR uM uN +variable {ι : Type uι} {κ : ι → Type uκ} +variable {S : Type uS} {R : Type uR} + +namespace MultilinearMap + +section Semiring + +variable {M : ∀ i, κ i → Type uM} {N : Type uN} +variable [Semiring R] +variable [∀ i k, AddCommMonoid (M i k)] [AddCommMonoid N] +variable [∀ i k, Module R (M i k)] [Module R N] + +/-- Two multilinear maps from finite families are equal if they agree on the generators. + +This is a multilinear version of `LinearMap.pi_ext`. -/ +@[ext] +theorem pi_ext [Finite ι] [∀ i, Finite (κ i)] [∀ i, DecidableEq (κ i)] + ⦃f g : MultilinearMap R (fun i ↦ Π j : κ i, M i j) N⦄ + (h : ∀ p : Π i, κ i, + f.compLinearMap (fun i => LinearMap.single R _ (p i)) = + g.compLinearMap (fun i => LinearMap.single R _ (p i))) : f = g := by + ext x + show f (fun i ↦ x i) = g (fun i ↦ x i) + obtain ⟨i⟩ := nonempty_fintype ι + have (i) := (nonempty_fintype (κ i)).some + have := Classical.decEq ι + rw [funext (fun i ↦ Eq.symm (Finset.univ_sum_single (x i)))] + simp_rw [MultilinearMap.map_sum_finset] + congr! 1 with p + simp_rw [MultilinearMap.ext_iff] at h + exact h _ _ + +end Semiring + +section piFamily +variable {M : ∀ i, κ i → Type uM} {N : (Π i, κ i) → Type uN} + +section Semiring + +variable [Semiring R] +variable [∀ i k, AddCommMonoid (M i k)] [∀ p, AddCommMonoid (N p)] +variable [∀ i k, Module R (M i k)] [∀ p, Module R (N p)] + +/-- +Given a family of indices `κ` and a multilinear map `f p` for each way `p` to select one index from +each family, `piFamily f` maps a family of functions (one for each domain `κ i`) into a function +from each selection of indices (with domain `Π i, κ i`). +-/ +@[simps] +def piFamily (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + MultilinearMap R (fun i => Π j : κ i, M i j) (Π t : Π i, κ i, N t) where + toFun x := fun p => f p (fun i => x i (p i)) + map_add' {dec} m i x y := funext fun p => by + cases Subsingleton.elim dec (by infer_instance) + dsimp + simp_rw [Function.apply_update (fun i m => m (p i)) m, Pi.add_apply, (f p).map_add] + map_smul' {dec} m i c x := funext fun p => by + cases Subsingleton.elim dec (by infer_instance) + dsimp + simp_rw [Function.apply_update (fun i m => m (p i)) m, Pi.smul_apply, (f p).map_smul] + +/-- When applied to a family of finitely-supported functions each supported on a single element, +`piFamily` is itself supported on a single element, with value equal to the map `f` applied +at that point. -/ +@[simp] +theorem piFamily_single [Fintype ι] [∀ i, DecidableEq (κ i)] + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) + (p : ∀ i, κ i) (m : ∀ i, M i (p i)) : + piFamily f (fun i => Pi.single (p i) (m i)) = Pi.single p (f p m) := by + ext q + obtain rfl | hpq := eq_or_ne p q + · simp + · rw [Pi.single_eq_of_ne' hpq] + rw [Function.ne_iff] at hpq + obtain ⟨i, hpqi⟩ := hpq + apply (f q).map_coord_zero i + simp_rw [Pi.single_eq_of_ne' hpqi] + +@[simp] +theorem piFamily_compLinearMap_lsingle [Fintype ι] [∀ i, DecidableEq (κ i)] + (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) (p : ∀ i, κ i) : + (piFamily f).compLinearMap (fun i => LinearMap.single _ _ (p i)) + = (LinearMap.single _ _ p).compMultilinearMap (f p) := + MultilinearMap.ext <| piFamily_single f p + +@[simp] +theorem piFamily_zero : + piFamily (0 : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) = 0 := by + ext; simp + +@[simp] +theorem piFamily_add (f g : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + piFamily (f + g) = piFamily f + piFamily g := by + ext; simp + +@[simp] +theorem piFamily_smul + [Monoid S] [∀ p, DistribMulAction S (N p)] [∀ p, SMulCommClass R S (N p)] + (s : S) (f : Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) : + piFamily (s • f) = s • piFamily f := by + ext; simp + +end Semiring + +section CommSemiring + +variable [CommSemiring R] +variable [∀ i k, AddCommMonoid (M i k)] [∀ p, AddCommMonoid (N p)] +variable [∀ i k, Module R (M i k)] [∀ p, Module R (N p)] + +/-- `MultilinearMap.piFamily` as a linear map. -/ +@[simps] +def piFamilyₗ : + (Π (p : Π i, κ i), MultilinearMap R (fun i ↦ M i (p i)) (N p)) + →ₗ[R] MultilinearMap R (fun i => Π j : κ i, M i j) (Π t : Π i, κ i, N t) where + toFun := piFamily + map_add' := piFamily_add + map_smul' := piFamily_smul + +end CommSemiring + +end piFamily + +end MultilinearMap diff --git a/Mathlib/LinearAlgebra/PerfectPairing.lean b/Mathlib/LinearAlgebra/PerfectPairing.lean index d5e2dd945411b..dfec7b49779cd 100644 --- a/Mathlib/LinearAlgebra/PerfectPairing.lean +++ b/Mathlib/LinearAlgebra/PerfectPairing.lean @@ -34,7 +34,7 @@ open Function Module variable (R M N : Type*) [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] /-- A perfect pairing of two (left) modules over a commutative ring. -/ -structure PerfectPairing := +structure PerfectPairing where toLin : M →ₗ[R] N →ₗ[R] R bijectiveLeft : Bijective toLin bijectiveRight : Bijective toLin.flip diff --git a/Mathlib/LinearAlgebra/Pi.lean b/Mathlib/LinearAlgebra/Pi.lean index 18abf808fda35..079b058aab3d1 100644 --- a/Mathlib/LinearAlgebra/Pi.lean +++ b/Mathlib/LinearAlgebra/Pi.lean @@ -63,7 +63,7 @@ theorem pi_eq_zero (f : (i : ι) → M₂ →ₗ[R] φ i) : pi f = 0 ↔ ∀ i, simp only [LinearMap.ext_iff, pi_apply, funext_iff] exact ⟨fun h a b => h b a, fun h a b => h b a⟩ -theorem pi_zero : pi (fun i => 0 : (i : ι) → M₂ →ₗ[R] φ i) = 0 := by ext; rfl +theorem pi_zero : pi (fun _ => 0 : (i : ι) → M₂ →ₗ[R] φ i) = 0 := by ext; rfl theorem pi_comp (f : (i : ι) → M₂ →ₗ[R] φ i) (g : M₃ →ₗ[R] M₂) : (pi f).comp g = pi fun i => (f i).comp g := @@ -462,8 +462,8 @@ def piOptionEquivProd {ι : Type*} {M : Option ι → Type*} [(i : Option ι) [(i : Option ι) → Module R (M i)] : ((i : Option ι) → M i) ≃ₗ[R] M none × ((i : ι) → M (some i)) := { Equiv.piOptionEquivProd with - map_add' := by simp [Function.funext_iff] - map_smul' := by simp [Function.funext_iff] } + map_add' := by simp [funext_iff] + map_smul' := by simp [funext_iff] } variable (ι M) (S : Type*) [Fintype ι] [DecidableEq ι] [Semiring S] [AddCommMonoid M] [Module R M] [Module S M] [SMulCommClass R S M] diff --git a/Mathlib/LinearAlgebra/PiTensorProduct.lean b/Mathlib/LinearAlgebra/PiTensorProduct.lean index acdc671ceb60a..549483263a2a1 100644 --- a/Mathlib/LinearAlgebra/PiTensorProduct.lean +++ b/Mathlib/LinearAlgebra/PiTensorProduct.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Frédéric Dupuis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Frédéric Dupuis, Eric Wieser -/ -import Mathlib.GroupTheory.Congruence.Basic import Mathlib.LinearAlgebra.Multilinear.TensorProduct import Mathlib.Tactic.AdaptationNote @@ -226,14 +225,14 @@ protected theorem smul_add (r : R₁) (x y : ⨂[R] i, s i) : r • (x + y) = r instance distribMulAction' : DistribMulAction R₁ (⨂[R] i, s i) where smul := (· • ·) - smul_add r x y := AddMonoidHom.map_add _ _ _ + smul_add _ _ _ := AddMonoidHom.map_add _ _ _ mul_smul r r' x := PiTensorProduct.induction_on' x (fun {r'' f} ↦ by simp [smul_tprodCoeff', smul_smul]) fun {x y} ihx ihy ↦ by simp_rw [PiTensorProduct.smul_add, ihx, ihy] one_smul x := PiTensorProduct.induction_on' x (fun {r f} ↦ by rw [smul_tprodCoeff', one_smul]) fun {z y} ihz ihy ↦ by simp_rw [PiTensorProduct.smul_add, ihz, ihy] - smul_zero r := AddMonoidHom.map_zero _ + smul_zero _ := AddMonoidHom.map_zero _ instance smulCommClass' [SMulCommClass R₁ R₂ R] : SMulCommClass R₁ R₂ (⨂[R] i, s i) := ⟨fun {r' r''} x ↦ @@ -411,7 +410,7 @@ theorem liftAux_tprod (φ : MultilinearMap R s E) (f : Π i, s i) : liftAux φ ( -- show _ • _ = _ -- rw [one_smul] erw [AddCon.lift_coe] - erw [FreeAddMonoid.of] + rw [FreeAddMonoid.of] dsimp [FreeAddMonoid.ofList] rw [← one_smul R (φ f)] erw [Equiv.refl_apply] diff --git a/Mathlib/LinearAlgebra/Prod.lean b/Mathlib/LinearAlgebra/Prod.lean index fb36914029e72..deb0c5569016f 100644 --- a/Mathlib/LinearAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/Prod.lean @@ -113,8 +113,8 @@ def prodEquiv [Module S M₂] [Module S M₃] [SMulCommClass R S M₂] [SMulComm invFun f := ((fst _ _ _).comp f, (snd _ _ _).comp f) left_inv f := by ext <;> rfl right_inv f := by ext <;> rfl - map_add' a b := rfl - map_smul' r a := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl section @@ -657,6 +657,32 @@ theorem snd_comp_prodComm : end prodComm +/-- Product of modules is associative up to linear isomorphism. -/ +@[simps apply] +def prodAssoc (R M₁ M₂ M₃ : Type*) [Semiring R] + [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] + [Module R M₁] [Module R M₂] [Module R M₃] : ((M₁ × M₂) × M₃) ≃ₗ[R] (M₁ × (M₂ × M₃)) := + { AddEquiv.prodAssoc with + map_smul' := fun _r ⟨_m, _n⟩ => rfl } + +section prodAssoc + +variable {M₁ : Type*} +variable [Semiring R] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] +variable [Module R M₁] [Module R M₂] [Module R M₃] + +theorem fst_comp_prodAssoc : + (LinearMap.fst R M₁ (M₂ × M₃)).comp (prodAssoc R M₁ M₂ M₃).toLinearMap = + (LinearMap.fst R M₁ M₂).comp (LinearMap.fst R (M₁ × M₂) M₃) := by + ext <;> simp + +theorem snd_comp_prodAssoc : + (LinearMap.snd R M₁ (M₂ × M₃)).comp (prodAssoc R M₁ M₂ M₃).toLinearMap = + (LinearMap.snd R M₁ M₂).prodMap (LinearMap.id : M₃ →ₗ[R] M₃):= by + ext <;> simp + +end prodAssoc + section variable (R M M₂ M₃ M₄) @@ -863,7 +889,7 @@ theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) Disjoint (tailing f i n) (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) := by rw [disjoint_iff] dsimp [tailing, tunnel, tunnel'] - erw [Submodule.map_inf_eq_map_inf_comap, + rw [Submodule.map_inf_eq_map_inf_comap, Submodule.comap_map_eq_of_injective (tunnelAux_injective _ i _), inf_comm, Submodule.fst_inf_snd, Submodule.map_bot] @@ -872,7 +898,7 @@ theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injectiv tailing f i n ⊔ (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) ≤ (OrderDual.ofDual (α := Submodule R M) <| tunnel f i n) := by dsimp [tailing, tunnel, tunnel', tunnelAux] - erw [← Submodule.map_sup, sup_comm, Submodule.fst_sup_snd, Submodule.map_comp, Submodule.map_comp] + rw [← Submodule.map_sup, sup_comm, Submodule.fst_sup_snd, Submodule.map_comp, Submodule.map_comp] apply Submodule.map_subtype_le /-- The supremum of all the copies of `N` found inside the tunnel. -/ diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index d7766cbbf641f..7a372e543c8fe 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.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.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic import Mathlib.LinearAlgebra.Prod /-! @@ -40,7 +40,7 @@ theorem ker_id_sub_eq_of_proj {f : E →ₗ[R] p} (hf : ∀ x : p, f x = x) : ker (id - p.subtype.comp f) = p := by ext x simp only [comp_apply, mem_ker, subtype_apply, sub_apply, id_apply, sub_eq_zero] - exact ⟨fun h => h.symm ▸ Submodule.coe_mem _, fun hx => by erw [hf ⟨x, hx⟩, Subtype.coe_mk]⟩ + exact ⟨fun h => h.symm ▸ Submodule.coe_mem _, fun hx => by rw [hf ⟨x, hx⟩, Subtype.coe_mk]⟩ theorem range_eq_of_proj {f : E →ₗ[R] p} (hf : ∀ x : p, f x = x) : range f = ⊤ := range_eq_top.2 fun x => ⟨x, hf x⟩ @@ -49,7 +49,7 @@ theorem isCompl_of_proj {f : E →ₗ[R] p} (hf : ∀ x : p, f x = x) : IsCompl constructor · rw [disjoint_iff_inf_le] rintro x ⟨hpx, hfx⟩ - erw [SetLike.mem_coe, mem_ker, hf ⟨x, hpx⟩, mk_eq_zero] at hfx + rw [SetLike.mem_coe, mem_ker, hf ⟨x, hpx⟩, mk_eq_zero] at hfx simp only [hfx, SetLike.mem_coe, zero_mem] · rw [codisjoint_iff_le_sup] intro x _ diff --git a/Mathlib/LinearAlgebra/Projectivization/Basic.lean b/Mathlib/LinearAlgebra/Projectivization/Basic.lean index 94d4e7925bb43..9a12ad4ccb657 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Basic.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Basic.lean @@ -68,6 +68,20 @@ instance [Nontrivial V] : Nonempty (ℙ K V) := variable {K} +/-- A function on non-zero vectors which is independent of scale, descends to a function on the +projectivization. -/ +protected def lift {α : Type*} (f : { v : V // v ≠ 0 } → α) + (hf : ∀ (a b : { v : V // v ≠ 0 }) (t : K), a = t • (b : V) → f a = f b) + (x : ℙ K V) : α := + Quotient.lift f (by rintro ⟨-, hv⟩ ⟨w, hw⟩ ⟨⟨t, -⟩, rfl⟩; exact hf ⟨_, hv⟩ ⟨w, hw⟩ t rfl) x + +@[simp] +protected lemma lift_mk {α : Type*} (f : { v : V // v ≠ 0 } → α) + (hf : ∀ (a b : { v : V // v ≠ 0 }) (t : K), a = t • (b : V) → f a = f b) + (v : V) (hv : v ≠ 0) : + Projectivization.lift f hf (mk K v hv) = f ⟨v, hv⟩ := + rfl + /-- Choose a representative of `v : Projectivization K V` in `V`. -/ protected noncomputable def rep (v : ℙ K V) : V := v.out' diff --git a/Mathlib/LinearAlgebra/Projectivization/Subspace.lean b/Mathlib/LinearAlgebra/Projectivization/Subspace.lean index c915615a57a83..6bb52dbaf5aa2 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Subspace.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Subspace.lean @@ -96,7 +96,7 @@ def gi : GaloisInsertion (span : Set (ℙ K V) → Subspace K V) SetLike.coe whe assumption · apply B.mem_add assumption'⟩ - le_l_u S := subset_span _ + le_l_u _ := subset_span _ choice_eq _ _ := rfl /-- The span of a subspace is the subspace. -/ @@ -128,7 +128,7 @@ instance : CompleteLattice (Subspace K V) := exact ha hE hx) inf_le_left := fun A B _ hx => (@inf_le_left _ _ A B) hx inf_le_right := fun A B _ hx => (@inf_le_right _ _ A B) hx - le_inf := fun A B _ h1 h2 _ hx => (le_inf h1 h2) hx } + le_inf := fun _ _ _ h1 h2 _ hx => (le_inf h1 h2) hx } instance subspaceInhabited : Inhabited (Subspace K V) where default := ⊤ diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean index fe2fe2b66dfe2..bec420998fa64 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean @@ -161,11 +161,6 @@ instance instFunLike : FunLike (QuadraticMap R M N) M N where coe := toFun coe_injective' x y h := by cases x; cases y; congr -/-- Helper instance for when there's too many metavariables to apply -`DFunLike.hasCoeToFun` directly. -/ -instance : CoeFun (QuadraticMap R M N) fun _ => M → N := - ⟨DFunLike.coe⟩ - variable (Q) /-- The `simp` normal form for a quadratic map is `DFunLike.coe`, not `toFun`. -/ @@ -334,7 +329,7 @@ theorem choose_exists_companion : Q.exists_companion.choose = polarBilin Q := protected theorem map_sum {ι} [DecidableEq ι] (Q : QuadraticMap R M N) (s : Finset ι) (f : ι → M) : Q (∑ i ∈ s, f i) = ∑ i ∈ s, Q (f i) + - ∑ ij in s.sym2.filter (¬ ·.IsDiag), + ∑ ij ∈ s.sym2 with ¬ ij.IsDiag, Sym2.lift ⟨fun i j => polar Q (f i) (f j), fun _ _ => polar_comm _ _ _⟩ ij := by induction s using Finset.cons_induction with | empty => simp @@ -579,6 +574,28 @@ def _root_.LinearMap.compQuadraticMap' [CommSemiring S] [Algebra S R] [Module S (f : N →ₗ[S] P) (Q : QuadraticMap R M N) : QuadraticMap S M P := _root_.LinearMap.compQuadraticMap f Q.restrictScalars +/-- When `N` and `P` are equivalent, quadratic maps on `M` into `N` are equivalent to quadratic +maps on `M` into `P`. + +See `LinearMap.BilinMap.congr₂` for the bilinear map version. -/ +@[simps] +def _root_.LinearEquiv.congrQuadraticMap (e : N ≃ₗ[R] P) : + QuadraticMap R M N ≃ₗ[R] QuadraticMap R M P where + toFun Q := e.compQuadraticMap Q + invFun Q := e.symm.compQuadraticMap Q + left_inv _ := ext fun _ => e.symm_apply_apply _ + right_inv _ := ext fun _ => e.apply_symm_apply _ + map_add' _ _ := ext fun _ => map_add e _ _ + map_smul' _ _ := ext fun _ => _root_.map_smul e _ _ + +@[simp] +theorem _root_.LinearEquiv.congrQuadraticMap_refl : + LinearEquiv.congrQuadraticMap (.refl R N) = .refl R (QuadraticMap R M N) := rfl + +@[simp] +theorem _root_.LinearEquiv.congrQuadraticMap_symm (e : N ≃ₗ[R] P) : + (LinearEquiv.congrQuadraticMap e (M := M)).symm = e.symm.congrQuadraticMap := rfl + end Comp section NonUnitalNonAssocSemiring @@ -769,7 +786,6 @@ theorem _root_.QuadraticMap.polarBilin_injective (h : IsUnit (2 : R)) : section variable {N' : Type*} [AddCommGroup N'] [Module R N'] -variable [CommRing S] [Algebra S R] [Module S M] [IsScalarTower S R M] theorem _root_.QuadraticMap.polarBilin_comp (Q : QuadraticMap R N' N) (f : M →ₗ[R] N') : polarBilin (Q.comp f) = LinearMap.compl₁₂ (polarBilin Q) f f := @@ -870,12 +886,12 @@ theorem toQuadraticMap_associated : (associatedHom S Q).toQuadraticMap = Q := -- note: usually `rightInverse` lemmas are named the other way around, but this is consistent -- with historical naming in this file. theorem associated_rightInverse : - Function.RightInverse (associatedHom S) (BilinMap.toQuadraticMap : _ → QuadraticMap R M R) := + Function.RightInverse (associatedHom S) (BilinMap.toQuadraticMap : _ → QuadraticMap R M N) := fun Q => toQuadraticMap_associated S Q /-- `associated'` is the `ℤ`-linear map that sends a quadratic form on a module `M` over `R` to its associated symmetric bilinear form. -/ -abbrev associated' : QuadraticMap R M R →ₗ[ℤ] BilinMap R M R := +abbrev associated' : QuadraticMap R M N →ₗ[ℤ] BilinMap R M N := associatedHom ℤ /-- Symmetric bilinear forms can be lifted to quadratic forms -/ @@ -885,15 +901,18 @@ instance canLift : /-- There exists a non-null vector with respect to any quadratic form `Q` whose associated bilinear form is non-zero, i.e. there exists `x` such that `Q x ≠ 0`. -/ -theorem exists_quadraticForm_ne_zero {Q : QuadraticForm R M} +theorem exists_quadraticMap_ne_zero {Q : QuadraticMap R M N} -- Porting note: added implicit argument - (hB₁ : associated' (R := R) Q ≠ 0) : + (hB₁ : associated' (R := R) (N := N) Q ≠ 0) : ∃ x, Q x ≠ 0 := by rw [← not_forall] intro h apply hB₁ rw [(QuadraticMap.ext h : Q = 0), LinearMap.map_zero] +@[deprecated (since := "2024-10-05")] alias exists_quadraticForm_ne_zero := + exists_quadraticMap_ne_zero + end AssociatedHom section Associated @@ -1020,7 +1039,7 @@ variable [CommRing R] [AddCommGroup M] [Module R M] theorem separatingLeft_of_anisotropic [Invertible (2 : R)] (Q : QuadraticMap R M R) (hB : Q.Anisotropic) : -- Porting note: added implicit argument - (QuadraticMap.associated' (R := R) Q).SeparatingLeft := fun x hx ↦ hB _ <| by + (QuadraticMap.associated' (R := R) (N := R) Q).SeparatingLeft := fun x hx ↦ hB _ <| by rw [← hx x] exact (associated_eq_self_apply _ _ x).symm @@ -1062,7 +1081,7 @@ theorem posDef_of_nonneg {Q : QuadraticMap R₂ M N} (h : ∀ x, 0 ≤ Q x) (h0 theorem posDef_iff_nonneg {Q : QuadraticMap R₂ M N} : PosDef Q ↔ (∀ x, 0 ≤ Q x) ∧ Q.Anisotropic := ⟨fun h => ⟨h.nonneg, h.anisotropic⟩, fun ⟨n, a⟩ => posDef_of_nonneg n a⟩ -theorem PosDef.add [CovariantClass N N (· + ·) (· < ·)] +theorem PosDef.add [AddLeftStrictMono N] (Q Q' : QuadraticMap R₂ M N) (hQ : PosDef Q) (hQ' : PosDef Q') : PosDef (Q + Q') := fun x hx => add_pos (hQ x hx) (hQ' x hx) @@ -1177,7 +1196,7 @@ on a module `M` over a ring `R` with invertible `2`, i.e. there exists some theorem exists_bilinForm_self_ne_zero [htwo : Invertible (2 : R)] {B : BilinForm R M} (hB₁ : B ≠ 0) (hB₂ : B.IsSymm) : ∃ x, ¬B.IsOrtho x x := by lift B to QuadraticForm R M using hB₂ with Q - obtain ⟨x, hx⟩ := QuadraticMap.exists_quadraticForm_ne_zero hB₁ + obtain ⟨x, hx⟩ := QuadraticMap.exists_quadraticMap_ne_zero hB₁ exact ⟨x, fun h => hx (Q.associated_eq_self_apply ℕ x ▸ h)⟩ open Module @@ -1253,7 +1272,7 @@ theorem basisRepr_apply [Fintype ι] {v : Basis ι R M} (Q : QuadraticMap R M N) rw [← v.equivFun_symm_apply] rfl -variable [Fintype ι] {v : Basis ι R M} +variable [Fintype ι] section diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean index c2c99925d7bb1..40f483a2ba81e 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean @@ -13,6 +13,8 @@ does not require `Invertible (2 : R)`. Unlike that definition, this only works i a basis. -/ +open LinearMap (BilinMap) + namespace QuadraticMap variable {ι R M N} [LinearOrder ι] @@ -60,4 +62,32 @@ theorem _root_.LinearMap.BilinMap.toQuadraticMap_surjective [Module.Free R M] : letI : LinearOrder ι := IsWellOrder.linearOrder WellOrderingRel exact ⟨_, toQuadraticMap_toBilin _ b⟩ +@[simp] +lemma add_toBilin (bm : Basis ι R M) (Q₁ Q₂ : QuadraticMap R M N) : + (Q₁ + Q₂).toBilin bm = Q₁.toBilin bm + Q₂.toBilin bm := by + refine bm.ext fun i => bm.ext fun j => ?_ + obtain h | rfl | h := lt_trichotomy i j + · simp [h.ne, h, toBilin_apply, polar_add] + · simp [toBilin_apply] + · simp [h.ne', h.not_lt, toBilin_apply, polar_add] + +variable (S) [CommSemiring S] [Algebra S R] +variable [Module S N] [IsScalarTower S R N] + +@[simp] +lemma smul_toBilin (bm : Basis ι R M) (s : S) (Q : QuadraticMap R M N) : + (s • Q).toBilin bm = s • Q.toBilin bm := by + refine bm.ext fun i => bm.ext fun j => ?_ + obtain h | rfl | h := lt_trichotomy i j + · simp [h.ne, h, toBilin_apply, polar_smul] + · simp [toBilin_apply] + · simp [h.ne', h.not_lt, toBilin_apply] + +/-- `QuadraticMap.toBilin` as an S-linear map -/ +@[simps] +noncomputable def toBilinHom (bm : Basis ι R M) : QuadraticMap R M N →ₗ[S] BilinMap R M N where + toFun Q := Q.toBilin bm + map_add' := add_toBilin bm + map_smul' := smul_toBilin S bm + end QuadraticMap diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Complex.lean b/Mathlib/LinearAlgebra/QuadraticForm/Complex.lean index 8f1a7a9b3e50d..a8c98d7d5b6cf 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Complex.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Complex.lean @@ -35,7 +35,7 @@ noncomputable def isometryEquivSumSquares (w' : ι → ℂ) : convert QuadraticMap.isometryEquivBasisRepr (weightedSumSquares ℂ w') ((Pi.basisFun ℂ ι).unitsSMul fun i => (isUnit_iff_ne_zero.2 <| hw' i).unit) ext1 v - erw [basisRepr_apply, weightedSumSquares_apply, weightedSumSquares_apply] + rw [basisRepr_apply, weightedSumSquares_apply, weightedSumSquares_apply] refine sum_congr rfl fun j hj => ?_ have hsum : (∑ i : ι, v i • ((isUnit_iff_ne_zero.2 <| hw' i).unit : ℂ) • (Pi.basisFun ℂ ι) i) j = v j • w j ^ (-(1 / 2 : ℂ)) := by diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Isometry.lean b/Mathlib/LinearAlgebra/QuadraticForm/Isometry.lean index c662062c74bc4..4208354f24bc0 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Isometry.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Isometry.lean @@ -17,7 +17,7 @@ import Mathlib.LinearAlgebra.QuadraticForm.Basic `Q₁ →qᵢ Q₂` is notation for `Q₁.Isometry Q₂`. -/ -variable {ι R M M₁ M₂ M₃ M₄ N : Type*} +variable {R M M₁ M₂ M₃ M₄ N : Type*} namespace QuadraticMap diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean index 891097a9ae0b6..328b2319e0765 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean @@ -144,7 +144,7 @@ theorem anisotropic_of_prod refine (h 0 x ?_).2 rw [hx, add_zero, map_zero] -theorem nonneg_prod_iff [Preorder P] [CovariantClass P P (· + ·) (· ≤ ·)] +theorem nonneg_prod_iff [Preorder P] [AddLeftMono P] {Q₁ : QuadraticMap R M₁ P} {Q₂ : QuadraticMap R M₂ P} : (∀ x, 0 ≤ (Q₁.prod Q₂) x) ↔ (∀ x, 0 ≤ Q₁ x) ∧ ∀ x, 0 ≤ Q₂ x := by simp_rw [Prod.forall, prod_apply] @@ -156,7 +156,7 @@ theorem nonneg_prod_iff [Preorder P] [CovariantClass P P (· + ·) (· ≤ ·)] · rintro ⟨h₁, h₂⟩ x₁ x₂ exact add_nonneg (h₁ x₁) (h₂ x₂) -theorem posDef_prod_iff [PartialOrder P] [CovariantClass P P (· + ·) (· ≤ ·)] +theorem posDef_prod_iff [PartialOrder P] [AddLeftMono P] {Q₁ : QuadraticMap R M₁ P} {Q₂ : QuadraticMap R M₂ P} : (Q₁.prod Q₂).PosDef ↔ Q₁.PosDef ∧ Q₂.PosDef := by simp_rw [posDef_iff_nonneg, nonneg_prod_iff] @@ -170,7 +170,7 @@ theorem posDef_prod_iff [PartialOrder P] [CovariantClass P P (· + ·) (· ≤ rw [add_eq_zero_iff_of_nonneg (hle₁ x₁) (hle₂ x₂), ha₁.eq_zero_iff, ha₂.eq_zero_iff] at hx rwa [Prod.mk_eq_zero] -theorem PosDef.prod [PartialOrder P] [CovariantClass P P (· + ·) (· ≤ ·)] +theorem PosDef.prod [PartialOrder P] [AddLeftMono P] {Q₁ : QuadraticMap R M₁ P} {Q₂ : QuadraticMap R M₂ P} (h₁ : Q₁.PosDef) (h₂ : Q₂.PosDef) : (Q₁.prod Q₂).PosDef := posDef_prod_iff.mpr ⟨h₁, h₂⟩ @@ -303,7 +303,7 @@ theorem Equivalent.pi [Fintype ι] {Q : ∀ i, QuadraticMap R (Mᵢ i) P} /-- If a family is anisotropic then its components must be. The converse is not true. -/ theorem anisotropic_of_pi [Fintype ι] {Q : ∀ i, QuadraticMap R (Mᵢ i) P} (h : (pi Q).Anisotropic) : ∀ i, (Q i).Anisotropic := by - simp_rw [Anisotropic, pi_apply, Function.funext_iff, Pi.zero_apply] at h + simp_rw [Anisotropic, pi_apply, funext_iff, Pi.zero_apply] at h intro i x hx classical have := h (Pi.single i x) ?_ i @@ -346,9 +346,7 @@ end Semiring namespace Ring variable [CommRing R] -variable [∀ i, AddCommGroup (Mᵢ i)] [∀ i, AddCommGroup (Nᵢ i)] [AddCommGroup P] -variable [∀ i, Module R (Mᵢ i)] [∀ i, Module R (Nᵢ i)] [Module R P] -variable [Fintype ι] +variable [∀ i, AddCommGroup (Mᵢ i)] [AddCommGroup P] [∀ i, Module R (Mᵢ i)] [Module R P] [Fintype ι] @[simp] theorem polar_pi (Q : ∀ i, QuadraticMap R (Mᵢ i) P) (x y : ∀ i, Mᵢ i) : polar (pi Q) x y = ∑ i, polar (Q i) (x i) (y i) := by diff --git a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean index c05f820fefc9c..7e6c8fa28492e 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean @@ -43,7 +43,7 @@ def of {X : Type v} [AddCommGroup X] [Module R X] (Q : QuadraticForm R X) : /-- A type alias for `QuadraticForm.LinearIsometry` to avoid confusion between the categorical and algebraic spellings of composition. -/ @[ext] -structure Hom (V W : QuadraticModuleCat.{v} R) := +structure Hom (V W : QuadraticModuleCat.{v} R) where /-- The underlying isometry -/ toIsometry : V.form →qᵢ W.form @@ -84,7 +84,7 @@ instance concreteCategory : ConcreteCategory.{v} (QuadraticModuleCat.{v} R) wher { obj := fun M => M map := fun f => f.toIsometry } forget_faithful := - { map_injective := fun {M N} => DFunLike.coe_injective.comp <| Hom.toIsometry_injective _ _ } + { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toIsometry_injective _ _ } instance hasForgetToModule : HasForget₂ (QuadraticModuleCat R) (ModuleCat R) where forget₂ := diff --git a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean index f7b52334b7167..d7c1d70ea2269 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean @@ -82,7 +82,7 @@ theorem forget₂_map_associator_inv (X Y Z : QuadraticModuleCat.{u} R) : noncomputable instance instMonoidalCategory : MonoidalCategory (QuadraticModuleCat.{u} R) := Monoidal.induced (forget₂ (QuadraticModuleCat R) (ModuleCat R)) - { μIso := fun X Y => Iso.refl _ + { μIso := fun _ _ => Iso.refl _ εIso := Iso.refl _ leftUnitor_eq := fun X => by simp only [forget₂_obj, forget₂_map, Iso.refl_symm, Iso.trans_assoc, Iso.trans_hom, diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Real.lean b/Mathlib/LinearAlgebra/QuadraticForm/Real.lean index b9fe9bdf90ae3..69811abb31c01 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Real.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Real.lean @@ -7,7 +7,6 @@ import Mathlib.LinearAlgebra.QuadraticForm.IsometryEquiv import Mathlib.Data.Sign import Mathlib.Algebra.CharP.Invertible import Mathlib.Analysis.RCLike.Basic -import Mathlib.Data.Complex.Abs /-! # Real quadratic forms diff --git a/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean b/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean index 1d4c4ee3c081a..48cee02f8f77e 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean @@ -16,50 +16,77 @@ import Mathlib.LinearAlgebra.QuadraticForm.Basic -/ -universe uR uA uM₁ uM₂ +universe uR uA uM₁ uM₂ uN₁ uN₂ -variable {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂} +variable {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂} {N₁ : Type uN₁} {N₂ : Type uN₂} open LinearMap (BilinMap BilinForm) open TensorProduct QuadraticMap -namespace QuadraticForm - section CommRing variable [CommRing R] [CommRing A] -variable [AddCommGroup M₁] [AddCommGroup M₂] -variable [Algebra R A] [Module R M₁] [Module A M₁] -variable [SMulCommClass R A M₁] [IsScalarTower R A M₁] -variable [Module R M₂] +variable [AddCommGroup M₁] [AddCommGroup M₂] [AddCommGroup N₁] [AddCommGroup N₂] +variable [Algebra R A] [Module R M₁] [Module A M₁] [Module R N₁] [Module A N₁] +variable [SMulCommClass R A M₁] [IsScalarTower R A M₁] [SMulCommClass R A N₁] [IsScalarTower R A N₁] +variable [Module R M₂] [Module R N₂] section InvertibleTwo variable [Invertible (2 : R)] +namespace QuadraticMap + variable (R A) in -/-- The tensor product of two quadratic forms injects into quadratic forms on tensor products. +/-- The tensor product of two quadratic maps injects into quadratic maps on tensor products. -Note this is heterobasic; the quadratic form on the left can take values in a larger ring than -the one on the right. -/ +Note this is heterobasic; the quadratic map on the left can take values in a module over a larger +ring than the one on the right. -/ -- `noncomputable` is a performance workaround for mathlib4#7103 noncomputable def tensorDistrib : - QuadraticForm A M₁ ⊗[R] QuadraticForm R M₂ →ₗ[A] QuadraticForm A (M₁ ⊗[R] M₂) := + QuadraticMap A M₁ N₁ ⊗[R] QuadraticMap R M₂ N₂ →ₗ[A] QuadraticMap A (M₁ ⊗[R] M₂) (N₁ ⊗[R] N₂) := letI : Invertible (2 : A) := (Invertible.map (algebraMap R A) 2).copy 2 (map_ofNat _ _).symm -- while `letI`s would produce a better term than `let`, they would make this already-slow -- definition even slower. let toQ := BilinMap.toQuadraticMapLinearMap A A (M₁ ⊗[R] M₂) let tmulB := BilinMap.tensorDistrib R A (M₁ := M₁) (M₂ := M₂) let toB := AlgebraTensorModule.map - (QuadraticMap.associated : QuadraticForm A M₁ →ₗ[A] BilinForm A M₁) - (QuadraticMap.associated : QuadraticForm R M₂ →ₗ[R] BilinForm R M₂) + (QuadraticMap.associated : QuadraticMap A M₁ N₁ →ₗ[A] BilinMap A M₁ N₁) + (QuadraticMap.associated : QuadraticMap R M₂ N₂ →ₗ[R] BilinMap R M₂ N₂) toQ ∘ₗ tmulB ∘ₗ toB +@[simp] +theorem tensorDistrib_tmul (Q₁ : QuadraticMap A M₁ N₁) (Q₂ : QuadraticMap R M₂ N₂) (m₁ : M₁) + (m₂ : M₂) : tensorDistrib R A (Q₁ ⊗ₜ Q₂) (m₁ ⊗ₜ m₂) = Q₁ m₁ ⊗ₜ Q₂ m₂ := + letI : Invertible (2 : A) := (Invertible.map (algebraMap R A) 2).copy 2 (map_ofNat _ _).symm + (BilinMap.tensorDistrib_tmul _ _ _ _ _ _).trans <| congr_arg₂ _ + (associated_eq_self_apply _ _ _) (associated_eq_self_apply _ _ _) + +/-- The tensor product of two quadratic maps, a shorthand for dot notation. -/ +-- `noncomputable` is a performance workaround for mathlib4#7103 +protected noncomputable abbrev tmul (Q₁ : QuadraticMap A M₁ N₁) + (Q₂ : QuadraticMap R M₂ N₂) : QuadraticMap A (M₁ ⊗[R] M₂) (N₁ ⊗[R] N₂) := + tensorDistrib R A (Q₁ ⊗ₜ[R] Q₂) + +end QuadraticMap + +namespace QuadraticForm + +variable (R A) in +/-- The tensor product of two quadratic forms injects into quadratic forms on tensor products. + +Note this is heterobasic; the quadratic form on the left can take values in a larger ring than +the one on the right. -/ +-- `noncomputable` is a performance workaround for mathlib4#7103 +noncomputable def tensorDistrib : + QuadraticForm A M₁ ⊗[R] QuadraticForm R M₂ →ₗ[A] QuadraticForm A (M₁ ⊗[R] M₂) := + (AlgebraTensorModule.rid R A A).congrQuadraticMap.toLinearMap ∘ₗ QuadraticMap.tensorDistrib R A + -- TODO: make the RHS `MulOpposite.op (Q₂ m₂) • Q₁ m₁` so that this has a nicer defeq for -- `R = A` of `Q₁ m₁ * Q₂ m₂`. @[simp] theorem tensorDistrib_tmul (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) (m₁ : M₁) (m₂ : M₂) : tensorDistrib R A (Q₁ ⊗ₜ Q₂) (m₁ ⊗ₜ m₂) = Q₂ m₂ • Q₁ m₁ := letI : Invertible (2 : A) := (Invertible.map (algebraMap R A) 2).copy 2 (map_ofNat _ _).symm - (BilinMap.tensorDistrib_tmul _ _ _ _ _ _).trans <| congr_arg₂ _ + (LinearMap.BilinForm.tensorDistrib_tmul _ _ _ _ _ _ _ _).trans <| congr_arg₂ _ (associated_eq_self_apply _ _ _) (associated_eq_self_apply _ _ _) /-- The tensor product of two quadratic forms, a shorthand for dot notation. -/ @@ -70,15 +97,29 @@ protected noncomputable abbrev tmul (Q₁ : QuadraticForm A M₁) (Q₂ : Quadra theorem associated_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) : associated (R := A) (Q₁.tmul Q₂) - = (associated (R := A) Q₁).tmul (associated (R := R) Q₂) := by - rw [QuadraticForm.tmul, tensorDistrib, BilinMap.tmul] + = BilinForm.tmul ((associated (R := A) Q₁)) (associated (R := R) Q₂) := by + letI : Invertible (2 : A) := (Invertible.map (algebraMap R A) 2).copy 2 (map_ofNat _ _).symm + /- Previously `QuadraticForm.tensorDistrib` was defined in a similar way to + `QuadraticMap.tensorDistrib`. We now obtain the definition of `QuadraticForm.tensorDistrib` + from `QuadraticMap.tensorDistrib` using `A ⊗[R] R ≃ₗ[A] A`. Hypothesis `e1` below shows that the + new definition is equal to the old, and allows us to reuse the old proof. + + TODO: Define `IsSymm` for bilinear maps and generalise this result to Quadratic Maps. + -/ + have e1: (BilinMap.toQuadraticMapLinearMap A A (M₁ ⊗[R] M₂) ∘ + BilinForm.tensorDistrib R A (M₁ := M₁) (M₂ := M₂) ∘ + AlgebraTensorModule.map + (QuadraticMap.associated : QuadraticForm A M₁ →ₗ[A] BilinForm A M₁) + (QuadraticMap.associated : QuadraticForm R M₂ →ₗ[R] BilinForm R M₂)) = + tensorDistrib R A := rfl + rw [QuadraticForm.tmul, ← e1, BilinForm.tmul] dsimp have : Subsingleton (Invertible (2 : A)) := inferInstance convert associated_left_inverse A ((associated_isSymm A Q₁).tmul (associated_isSymm R Q₂)) theorem polarBilin_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) : - polarBilin (Q₁.tmul Q₂) = ⅟(2 : A) • (polarBilin Q₁).tmul (polarBilin Q₂) := by - simp_rw [← two_nsmul_associated A, ← two_nsmul_associated R, BilinMap.tmul, tmul_smul, + polarBilin (Q₁.tmul Q₂) = ⅟(2 : A) • BilinForm.tmul (polarBilin Q₁) (polarBilin Q₂) := by + simp_rw [← two_nsmul_associated A, ← two_nsmul_associated R, BilinForm.tmul, tmul_smul, ← smul_tmul', map_nsmul, associated_tmul] rw [smul_comm (_ : A) (_ : ℕ), ← smul_assoc, two_smul _ (_ : A), invOf_two_add_invOf_two, one_smul] @@ -95,17 +136,19 @@ theorem baseChange_tmul (Q : QuadraticForm R M₂) (a : A) (m₂ : M₂) : tensorDistrib_tmul _ _ _ _ theorem associated_baseChange [Invertible (2 : A)] (Q : QuadraticForm R M₂) : - associated (R := A) (Q.baseChange A) = (associated (R := R) Q).baseChange A := by + associated (R := A) (Q.baseChange A) = BilinForm.baseChange A (associated (R := R) Q) := by dsimp only [QuadraticForm.baseChange, LinearMap.baseChange] rw [associated_tmul (QuadraticMap.sq (R := A)) Q, associated_sq] exact rfl theorem polarBilin_baseChange [Invertible (2 : A)] (Q : QuadraticForm R M₂) : - polarBilin (Q.baseChange A) = (polarBilin Q).baseChange A := by - rw [QuadraticForm.baseChange, BilinMap.baseChange, polarBilin_tmul, BilinMap.tmul, + polarBilin (Q.baseChange A) = BilinForm.baseChange A (polarBilin Q) := by + rw [QuadraticForm.baseChange, BilinForm.baseChange, polarBilin_tmul, BilinForm.tmul, ← LinearMap.map_smul, smul_tmul', ← two_nsmul_associated R, coe_associatedHom, associated_sq, smul_comm, ← smul_assoc, two_smul, invOf_two_add_invOf_two, one_smul] +end QuadraticForm + end InvertibleTwo /-- If two quadratic forms from `A ⊗[R] M₂` agree on elements of the form `1 ⊗ m`, they are equal. @@ -133,5 +176,3 @@ theorem baseChange_ext ⦃Q₁ Q₂ : QuadraticForm A (A ⊗[R] M₂)⦄ linear_combination this + hx + hy end CommRing - -end QuadraticForm diff --git a/Mathlib/LinearAlgebra/Quotient.lean b/Mathlib/LinearAlgebra/Quotient/Basic.lean similarity index 63% rename from Mathlib/LinearAlgebra/Quotient.lean rename to Mathlib/LinearAlgebra/Quotient/Basic.lean index ca7aacc2896a2..0f5bd394978ce 100644 --- a/Mathlib/LinearAlgebra/Quotient.lean +++ b/Mathlib/LinearAlgebra/Quotient/Basic.lean @@ -3,9 +3,11 @@ 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, Kevin Buzzard, Yury Kudryashov -/ -import Mathlib.LinearAlgebra.Span import Mathlib.Algebra.Module.Equiv.Basic import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.LinearAlgebra.Pi +import Mathlib.LinearAlgebra.Quotient.Defs +import Mathlib.LinearAlgebra.Span import Mathlib.SetTheory.Cardinal.Finite /-! @@ -14,6 +16,14 @@ import Mathlib.SetTheory.Cardinal.Finite * If `p` is a submodule of `M`, `M ⧸ p` is the quotient of `M` with respect to `p`: that is, elements of `M` are identified if their difference is in `p`. This is itself a module. +## Main definitions + +* `Submodule.Quotient.restrictScalarsEquiv`: The quotient of `P` as an `S`-submodule is the same + as the quotient of `P` as an `R`-submodule, +* `Submodule.liftQ`: lift a map `M → M₂` to a map `M ⧸ p → M₂` if the kernel is contained in `p` +* `Submodule.mapQ`: lift a map `M → M₂` to a map `M ⧸ p → M₂ ⧸ q` if the image of `p` is contained + in `q` + -/ -- For most of this file we work over a noncommutative ring @@ -26,173 +36,11 @@ variable (p p' : Submodule R M) open LinearMap QuotientAddGroup -/-- The equivalence relation associated to a submodule `p`, defined by `x ≈ y` iff `-x + y ∈ p`. - -Note this is equivalent to `y - x ∈ p`, but defined this way to be defeq to the `AddSubgroup` -version, where commutativity can't be assumed. -/ -def quotientRel : Setoid M := - QuotientAddGroup.leftRel p.toAddSubgroup - -theorem quotientRel_r_def {x y : M} : @Setoid.r _ p.quotientRel x y ↔ x - y ∈ p := - Iff.trans - (by - rw [leftRel_apply, sub_eq_add_neg, neg_add, neg_neg] - rfl) - neg_mem_iff - -/-- The quotient of a module `M` by a submodule `p ⊆ M`. -/ -instance hasQuotient : HasQuotient M (Submodule R M) := - ⟨fun p => Quotient (quotientRel p)⟩ - namespace Quotient -/-- Map associating to an element of `M` the corresponding element of `M/p`, -when `p` is a submodule of `M`. -/ -def mk {p : Submodule R M} : M → M ⧸ p := - Quotient.mk'' - -/- porting note: here and throughout elaboration is sped up *tremendously* (in some cases even -avoiding timeouts) by providing type ascriptions to `mk` (or `mk x`) and its variants. Lean 3 -didn't need this help. -/ -theorem mk'_eq_mk' {p : Submodule R M} (x : M) : - @Quotient.mk' _ (quotientRel p) x = (mk : M → M ⧸ p) x := - rfl - -theorem mk''_eq_mk {p : Submodule R M} (x : M) : (Quotient.mk'' x : M ⧸ p) = (mk : M → M ⧸ p) x := - rfl - -theorem quot_mk_eq_mk {p : Submodule R M} (x : M) : (Quot.mk _ x : M ⧸ p) = (mk : M → M ⧸ p) x := - rfl - -protected theorem eq' {x y : M} : (mk x : M ⧸ p) = (mk : M → M ⧸ p) y ↔ -x + y ∈ p := - QuotientAddGroup.eq - -protected theorem eq {x y : M} : (mk x : M ⧸ p) = (mk y : M ⧸ p) ↔ x - y ∈ p := - (Submodule.Quotient.eq' p).trans (leftRel_apply.symm.trans p.quotientRel_r_def) - -instance : Zero (M ⧸ p) where - -- Use Quotient.mk'' instead of mk here because mk is not reducible. - -- This would lead to non-defeq diamonds. - -- See also the same comment at the One instance for Con. - zero := Quotient.mk'' 0 - -instance : Inhabited (M ⧸ p) := - ⟨0⟩ - -@[simp] -theorem mk_zero : mk 0 = (0 : M ⧸ p) := - rfl - -@[simp] -theorem mk_eq_zero : (mk x : M ⧸ p) = 0 ↔ x ∈ p := by simpa using (Quotient.eq' p : mk x = 0 ↔ _) - -instance addCommGroup : AddCommGroup (M ⧸ p) := - QuotientAddGroup.Quotient.addCommGroup p.toAddSubgroup - -@[simp] -theorem mk_add : (mk (x + y) : M ⧸ p) = (mk x : M ⧸ p) + (mk y : M ⧸ p) := - rfl - -@[simp] -theorem mk_neg : (mk (-x) : M ⧸ p) = -(mk x : M ⧸ p) := - rfl - -@[simp] -theorem mk_sub : (mk (x - y) : M ⧸ p) = (mk x : M ⧸ p) - (mk y : M ⧸ p) := - rfl - -section SMul - -variable {S : Type*} [SMul S R] [SMul S M] [IsScalarTower S R M] (P : Submodule R M) - -instance instSMul' : SMul S (M ⧸ P) := - ⟨fun a => - Quotient.map' (a • ·) fun x y h => - leftRel_apply.mpr <| by simpa using Submodule.smul_mem P (a • (1 : R)) (leftRel_apply.mp h)⟩ - --- Porting note: should this be marked as a `@[default_instance]`? -/-- Shortcut to help the elaborator in the common case. -/ -instance instSMul : SMul R (M ⧸ P) := - Quotient.instSMul' P - -@[simp] -theorem mk_smul (r : S) (x : M) : (mk (r • x) : M ⧸ p) = r • mk x := - rfl - -instance smulCommClass (T : Type*) [SMul T R] [SMul T M] [IsScalarTower T R M] - [SMulCommClass S T M] : SMulCommClass S T (M ⧸ P) where - smul_comm _x _y := Quotient.ind' fun _z => congr_arg mk (smul_comm _ _ _) - -instance isScalarTower (T : Type*) [SMul T R] [SMul T M] [IsScalarTower T R M] [SMul S T] - [IsScalarTower S T M] : IsScalarTower S T (M ⧸ P) where - smul_assoc _x _y := Quotient.ind' fun _z => congr_arg mk (smul_assoc _ _ _) - -instance isCentralScalar [SMul Sᵐᵒᵖ R] [SMul Sᵐᵒᵖ M] [IsScalarTower Sᵐᵒᵖ R M] - [IsCentralScalar S M] : IsCentralScalar S (M ⧸ P) where - op_smul_eq_smul _x := Quotient.ind' fun _z => congr_arg mk <| op_smul_eq_smul _ _ - -end SMul - section Module -variable {S : Type*} - --- Performance of `Function.Surjective.mulAction` is worse since it has to unify data to apply --- TODO: leanprover-community/mathlib4#7432 -instance mulAction' [Monoid S] [SMul S R] [MulAction S M] [IsScalarTower S R M] - (P : Submodule R M) : MulAction S (M ⧸ P) := - { Function.Surjective.mulAction mk (surjective_quot_mk _) <| Submodule.Quotient.mk_smul P with - toSMul := instSMul' _ } - --- Porting note: should this be marked as a `@[default_instance]`? -instance mulAction (P : Submodule R M) : MulAction R (M ⧸ P) := - Quotient.mulAction' P - -instance smulZeroClass' [SMul S R] [SMulZeroClass S M] [IsScalarTower S R M] (P : Submodule R M) : - SMulZeroClass S (M ⧸ P) := - ZeroHom.smulZeroClass ⟨mk, mk_zero _⟩ <| Submodule.Quotient.mk_smul P - --- Porting note: should this be marked as a `@[default_instance]`? -instance smulZeroClass (P : Submodule R M) : SMulZeroClass R (M ⧸ P) := - Quotient.smulZeroClass' P - --- Performance of `Function.Surjective.distribSMul` is worse since it has to unify data to apply --- TODO: leanprover-community/mathlib4#7432 -instance distribSMul' [SMul S R] [DistribSMul S M] [IsScalarTower S R M] (P : Submodule R M) : - DistribSMul S (M ⧸ P) := - { Function.Surjective.distribSMul {toFun := mk, map_zero' := rfl, map_add' := fun _ _ => rfl} - (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with - toSMulZeroClass := smulZeroClass' _ } - --- Porting note: should this be marked as a `@[default_instance]`? -instance distribSMul (P : Submodule R M) : DistribSMul R (M ⧸ P) := - Quotient.distribSMul' P - --- Performance of `Function.Surjective.distribMulAction` is worse since it has to unify data --- TODO: leanprover-community/mathlib4#7432 -instance distribMulAction' [Monoid S] [SMul S R] [DistribMulAction S M] [IsScalarTower S R M] - (P : Submodule R M) : DistribMulAction S (M ⧸ P) := - { Function.Surjective.distribMulAction {toFun := mk, map_zero' := rfl, map_add' := fun _ _ => rfl} - (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with - toMulAction := mulAction' _ } - --- Porting note: should this be marked as a `@[default_instance]`? -instance distribMulAction (P : Submodule R M) : DistribMulAction R (M ⧸ P) := - Quotient.distribMulAction' P - --- Performance of `Function.Surjective.module` is worse since it has to unify data to apply --- TODO: leanprover-community/mathlib4#7432 -instance module' [Semiring S] [SMul S R] [Module S M] [IsScalarTower S R M] (P : Submodule R M) : - Module S (M ⧸ P) := - { Function.Surjective.module _ {toFun := mk, map_zero' := by rfl, map_add' := fun _ _ => by rfl} - (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with - toDistribMulAction := distribMulAction' _ } - --- Porting note: should this be marked as a `@[default_instance]`? -instance module (P : Submodule R M) : Module R (M ⧸ P) := - Quotient.module' P - -variable (S) +variable (S : Type*) /-- The quotient of `P` as an `S`-submodule is the same as the quotient of `P` as an `R`-submodule, where `P : Submodule R M`. @@ -206,21 +54,17 @@ def restrictScalarsEquiv [Ring S] [SMul S R] [Module S M] [IsScalarTower S R M] @[simp] theorem restrictScalarsEquiv_mk [Ring S] [SMul S R] [Module S M] [IsScalarTower S R M] (P : Submodule R M) (x : M) : - restrictScalarsEquiv S P (mk x : M ⧸ P) = (mk x : M ⧸ P) := + restrictScalarsEquiv S P (mk x) = mk x := rfl @[simp] theorem restrictScalarsEquiv_symm_mk [Ring S] [SMul S R] [Module S M] [IsScalarTower S R M] (P : Submodule R M) (x : M) : - (restrictScalarsEquiv S P).symm ((mk : M → M ⧸ P) x) = (mk : M → M ⧸ P) x := + (restrictScalarsEquiv S P).symm (mk x) = mk x := rfl end Module -theorem mk_surjective : Function.Surjective (@mk _ _ _ _ _ p) := by - rintro ⟨x⟩ - exact ⟨x, rfl⟩ - theorem nontrivial_of_lt_top (h : p < ⊤) : Nontrivial (M ⧸ p) := by obtain ⟨x, _, not_mem_s⟩ := SetLike.exists_of_lt h refine ⟨⟨mk x, 0, ?_⟩⟩ @@ -268,23 +112,6 @@ section variable {M₂ : Type*} [AddCommGroup M₂] [Module R M₂] -theorem quot_hom_ext (f g : (M ⧸ p) →ₗ[R] M₂) (h : ∀ x : M, f (Quotient.mk x) = g (Quotient.mk x)) : - f = g := - LinearMap.ext fun x => Quotient.inductionOn' x h - -/-- The map from a module `M` to the quotient of `M` by a submodule `p` as a linear map. -/ -def mkQ : M →ₗ[R] M ⧸ p where - toFun := Quotient.mk - map_add' := by simp - map_smul' := by simp - -@[simp] -theorem mkQ_apply (x : M) : p.mkQ x = (Quotient.mk x : M ⧸ p) := - rfl - -theorem mkQ_surjective : Function.Surjective p.mkQ := by - rintro ⟨x⟩; exact ⟨x, rfl⟩ - theorem strictMono_comap_prod_map : StrictMono fun m : Submodule R M ↦ (m.comap p.subtype, m.map p.mkQ) := fun m₁ m₂ ↦ QuotientAddGroup.strictMono_comap_prod_map @@ -294,14 +121,6 @@ end variable {R₂ M₂ : Type*} [Ring R₂] [AddCommGroup M₂] [Module R₂ M₂] {τ₁₂ : R →+* R₂} -/-- Two `LinearMap`s from a quotient module are equal if their compositions with -`submodule.mkQ` are equal. - -See note [partially-applied ext lemmas]. -/ -@[ext 1100] -- Porting note: increase priority so this applies before `LinearMap.ext` -theorem linearMap_qext ⦃f g : M ⧸ p →ₛₗ[τ₁₂] M₂⦄ (h : f.comp p.mkQ = g.comp p.mkQ) : f = g := - LinearMap.ext fun x => Quotient.inductionOn' x <| (LinearMap.congr_fun h : _) - /-- The map from the quotient of `M` by a submodule `p` to `M₂` induced by a linear map `f : M → M₂` vanishing on `p`, as a linear map. -/ def liftQ (f : M →ₛₗ[τ₁₂] M₂) (h : p ≤ ker f) : M ⧸ p →ₛₗ[τ₁₂] M₂ := @@ -315,6 +134,14 @@ theorem liftQ_apply (f : M →ₛₗ[τ₁₂] M₂) {h} (x : M) : p.liftQ f h ( @[simp] theorem liftQ_mkQ (f : M →ₛₗ[τ₁₂] M₂) (h) : (p.liftQ f h).comp p.mkQ = f := by ext; rfl +theorem pi_liftQ_eq_liftQ_pi {ι : Type*} {N : ι → Type*} + [∀ i, AddCommGroup (N i)] [∀ i, Module R (N i)] + (f : (i : ι) → M →ₗ[R] (N i)) {p : Submodule R M} (h : ∀ i, p ≤ ker (f i)) : + LinearMap.pi (fun i ↦ p.liftQ (f i) (h i)) = + p.liftQ (LinearMap.pi f) (LinearMap.ker_pi f ▸ le_iInf h) := by + ext x i + simp + /-- Special case of `submodule.liftQ` when `p` is the span of `x`. In this case, the condition on `f` simply becomes vanishing at `x`. -/ def liftQSpanSingleton (x : M) (f : M →ₛₗ[τ₁₂] M₂) (h : f x = 0) : (M ⧸ R ∙ x) →ₛₗ[τ₁₂] M₂ := @@ -357,7 +184,7 @@ def mapQ (f : M →ₛₗ[τ₁₂] M₂) (h : p ≤ comap f q) : M ⧸ p →ₛ @[simp] theorem mapQ_apply (f : M →ₛₗ[τ₁₂] M₂) {h} (x : M) : - mapQ p q f h (Quotient.mk x : M ⧸ p) = (Quotient.mk (f x) : M₂ ⧸ q) := + mapQ p q f h (Quotient.mk x) = Quotient.mk (f x) := rfl theorem mapQ_mkQ (f : M →ₛₗ[τ₁₂] M₂) {h} : (mapQ p q f h).comp p.mkQ = q.mkQ.comp f := by @@ -459,8 +286,8 @@ and `f : M ≃ₗ N` maps `P` to `Q`, then `M ⧸ P` is equivalent to `N ⧸ Q`. @[simps] def Quotient.equiv {N : Type*} [AddCommGroup N] [Module R N] (P : Submodule R M) (Q : Submodule R N) (f : M ≃ₗ[R] N) (hf : P.map f = Q) : (M ⧸ P) ≃ₗ[R] N ⧸ Q := - { P.mapQ Q (f : M →ₗ[R] N) fun x hx => hf ▸ Submodule.mem_map_of_mem hx with - toFun := P.mapQ Q (f : M →ₗ[R] N) fun x hx => hf ▸ Submodule.mem_map_of_mem hx + { P.mapQ Q (f : M →ₗ[R] N) fun _ hx => hf ▸ Submodule.mem_map_of_mem hx with + toFun := P.mapQ Q (f : M →ₗ[R] N) fun _ hx => hf ▸ Submodule.mem_map_of_mem hx invFun := Q.mapQ P (f.symm : N →ₗ[R] M) fun x hx => by rw [← hf, Submodule.mem_map] at hx @@ -536,12 +363,12 @@ def quotEquivOfEqBot (hp : p = ⊥) : (M ⧸ p) ≃ₗ[R] M := @[simp] theorem quotEquivOfEqBot_apply_mk (hp : p = ⊥) (x : M) : - p.quotEquivOfEqBot hp (Quotient.mk x : M ⧸ p) = x := + p.quotEquivOfEqBot hp (Quotient.mk x) = x := rfl @[simp] theorem quotEquivOfEqBot_symm_apply (hp : p = ⊥) (x : M) : - (p.quotEquivOfEqBot hp).symm x = (Quotient.mk x : M ⧸ p) := + (p.quotEquivOfEqBot hp).symm x = (Quotient.mk x) := rfl @[simp] @@ -549,24 +376,6 @@ theorem coe_quotEquivOfEqBot_symm (hp : p = ⊥) : ((p.quotEquivOfEqBot hp).symm : M →ₗ[R] M ⧸ p) = p.mkQ := rfl -/-- Quotienting by equal submodules gives linearly equivalent quotients. -/ -def quotEquivOfEq (h : p = p') : (M ⧸ p) ≃ₗ[R] M ⧸ p' := - { @Quotient.congr _ _ (quotientRel p) (quotientRel p') (Equiv.refl _) fun a b => by - subst h - rfl with - map_add' := by - rintro ⟨x⟩ ⟨y⟩ - rfl - map_smul' := by - rintro x ⟨y⟩ - rfl } - -@[simp] -theorem quotEquivOfEq_mk (h : p = p') (x : M) : - Submodule.quotEquivOfEq p p' h (Submodule.Quotient.mk x : M ⧸ p) = - (Submodule.Quotient.mk x : M ⧸ p') := - rfl - @[simp] theorem Quotient.equiv_refl (P : Submodule R M) (Q : Submodule R M) (hf : P.map (LinearEquiv.refl R M : M →ₗ[R] M) = Q) : diff --git a/Mathlib/LinearAlgebra/Quotient/Defs.lean b/Mathlib/LinearAlgebra/Quotient/Defs.lean new file mode 100644 index 0000000000000..ab4b3b8558678 --- /dev/null +++ b/Mathlib/LinearAlgebra/Quotient/Defs.lean @@ -0,0 +1,262 @@ +/- +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, Kevin Buzzard, Yury Kudryashov +-/ +import Mathlib.Algebra.Module.Submodule.Basic +import Mathlib.Algebra.Module.Equiv.Defs +import Mathlib.GroupTheory.QuotientGroup.Defs + +/-! +# Quotients by submodules + +* If `p` is a submodule of `M`, `M ⧸ p` is the quotient of `M` with respect to `p`: + that is, elements of `M` are identified if their difference is in `p`. This is itself a module. + +## Main definitions + + * `Submodule.Quotient.mk`: a function sending an element of `M` to `M ⧸ p` + * `Submodule.Quotient.module`: `M ⧸ p` is a module + * `Submodule.Quotient.mkQ`: a linear map sending an element of `M` to `M ⧸ p` + * `Submodule.quotEquivOfEq`: if `p` and `p'` are equal, their quotients are equivalent + +-/ + +-- For most of this file we work over a noncommutative ring +section Ring + +namespace Submodule + +variable {R M : Type*} {r : R} {x y : M} [Ring R] [AddCommGroup M] [Module R M] +variable (p p' : Submodule R M) + +open QuotientAddGroup + +/-- The equivalence relation associated to a submodule `p`, defined by `x ≈ y` iff `-x + y ∈ p`. + +Note this is equivalent to `y - x ∈ p`, but defined this way to be defeq to the `AddSubgroup` +version, where commutativity can't be assumed. -/ +def quotientRel : Setoid M := + QuotientAddGroup.leftRel p.toAddSubgroup + +theorem quotientRel_def {x y : M} : p.quotientRel x y ↔ x - y ∈ p := + Iff.trans + (by + rw [leftRel_apply, sub_eq_add_neg, neg_add, neg_neg] + rfl) + neg_mem_iff + +@[deprecated (since := "2024-08-29")] alias quotientRel_r_def := quotientRel_def + +/-- The quotient of a module `M` by a submodule `p ⊆ M`. -/ +instance hasQuotient : HasQuotient M (Submodule R M) := + ⟨fun p => Quotient (quotientRel p)⟩ + +namespace Quotient +/-- Map associating to an element of `M` the corresponding element of `M/p`, +when `p` is a submodule of `M`. -/ +def mk {p : Submodule R M} : M → M ⧸ p := + Quotient.mk'' + +theorem mk'_eq_mk' {p : Submodule R M} (x : M) : + @Quotient.mk' _ (quotientRel p) x = mk x := + rfl + +theorem mk''_eq_mk {p : Submodule R M} (x : M) : (Quotient.mk'' x : M ⧸ p) = mk x := + rfl + +theorem quot_mk_eq_mk {p : Submodule R M} (x : M) : (Quot.mk _ x : M ⧸ p) = mk x := + rfl + +protected theorem eq' {x y : M} : (mk x : M ⧸ p) = mk y ↔ -x + y ∈ p := + QuotientAddGroup.eq + +protected theorem eq {x y : M} : (mk x : M ⧸ p) = mk y ↔ x - y ∈ p := + (Submodule.Quotient.eq' p).trans (leftRel_apply.symm.trans p.quotientRel_def) + +instance : Zero (M ⧸ p) where + -- Use Quotient.mk'' instead of mk here because mk is not reducible. + -- This would lead to non-defeq diamonds. + -- See also the same comment at the One instance for Con. + zero := Quotient.mk'' 0 + +instance : Inhabited (M ⧸ p) := + ⟨0⟩ + +@[simp] +theorem mk_zero : mk 0 = (0 : M ⧸ p) := + rfl + +@[simp] +theorem mk_eq_zero : (mk x : M ⧸ p) = 0 ↔ x ∈ p := by simpa using (Quotient.eq' p : mk x = 0 ↔ _) + +instance addCommGroup : AddCommGroup (M ⧸ p) := + QuotientAddGroup.Quotient.addCommGroup p.toAddSubgroup + +@[simp] +theorem mk_add : (mk (x + y) : M ⧸ p) = mk x + mk y := + rfl + +@[simp] +theorem mk_neg : (mk (-x) : M ⧸ p) = -(mk x) := + rfl + +@[simp] +theorem mk_sub : (mk (x - y) : M ⧸ p) = mk x - mk y := + rfl + +protected nonrec lemma «forall» {P : M ⧸ p → Prop} : (∀ a, P a) ↔ ∀ a, P (mk a) := Quotient.forall + +section SMul + +variable {S : Type*} [SMul S R] [SMul S M] [IsScalarTower S R M] (P : Submodule R M) + +instance instSMul' : SMul S (M ⧸ P) := + ⟨fun a => + Quotient.map' (a • ·) fun x y h => + leftRel_apply.mpr <| by simpa using Submodule.smul_mem P (a • (1 : R)) (leftRel_apply.mp h)⟩ + +-- Porting note: should this be marked as a `@[default_instance]`? +/-- Shortcut to help the elaborator in the common case. -/ +instance instSMul : SMul R (M ⧸ P) := + Quotient.instSMul' P + +@[simp] +theorem mk_smul (r : S) (x : M) : (mk (r • x) : M ⧸ p) = r • mk x := + rfl + +instance smulCommClass (T : Type*) [SMul T R] [SMul T M] [IsScalarTower T R M] + [SMulCommClass S T M] : SMulCommClass S T (M ⧸ P) where + smul_comm _x _y := Quotient.ind' fun _z => congr_arg mk (smul_comm _ _ _) + +instance isScalarTower (T : Type*) [SMul T R] [SMul T M] [IsScalarTower T R M] [SMul S T] + [IsScalarTower S T M] : IsScalarTower S T (M ⧸ P) where + smul_assoc _x _y := Quotient.ind' fun _z => congr_arg mk (smul_assoc _ _ _) + +instance isCentralScalar [SMul Sᵐᵒᵖ R] [SMul Sᵐᵒᵖ M] [IsScalarTower Sᵐᵒᵖ R M] + [IsCentralScalar S M] : IsCentralScalar S (M ⧸ P) where + op_smul_eq_smul _x := Quotient.ind' fun _z => congr_arg mk <| op_smul_eq_smul _ _ + +end SMul + +section Module + +variable {S : Type*} + +-- Performance of `Function.Surjective.mulAction` is worse since it has to unify data to apply +-- TODO: leanprover-community/mathlib4#7432 +instance mulAction' [Monoid S] [SMul S R] [MulAction S M] [IsScalarTower S R M] + (P : Submodule R M) : MulAction S (M ⧸ P) := + { Function.Surjective.mulAction mk (surjective_quot_mk _) <| Submodule.Quotient.mk_smul P with + toSMul := instSMul' _ } + +-- Porting note: should this be marked as a `@[default_instance]`? +instance mulAction (P : Submodule R M) : MulAction R (M ⧸ P) := + Quotient.mulAction' P + +instance smulZeroClass' [SMul S R] [SMulZeroClass S M] [IsScalarTower S R M] (P : Submodule R M) : + SMulZeroClass S (M ⧸ P) := + ZeroHom.smulZeroClass ⟨mk, mk_zero _⟩ <| Submodule.Quotient.mk_smul P + +-- Porting note: should this be marked as a `@[default_instance]`? +instance smulZeroClass (P : Submodule R M) : SMulZeroClass R (M ⧸ P) := + Quotient.smulZeroClass' P + +-- Performance of `Function.Surjective.distribSMul` is worse since it has to unify data to apply +-- TODO: leanprover-community/mathlib4#7432 +instance distribSMul' [SMul S R] [DistribSMul S M] [IsScalarTower S R M] (P : Submodule R M) : + DistribSMul S (M ⧸ P) := + { Function.Surjective.distribSMul {toFun := mk, map_zero' := rfl, map_add' := fun _ _ => rfl} + (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with + toSMulZeroClass := smulZeroClass' _ } + +-- Porting note: should this be marked as a `@[default_instance]`? +instance distribSMul (P : Submodule R M) : DistribSMul R (M ⧸ P) := + Quotient.distribSMul' P + +-- Performance of `Function.Surjective.distribMulAction` is worse since it has to unify data +-- TODO: leanprover-community/mathlib4#7432 +instance distribMulAction' [Monoid S] [SMul S R] [DistribMulAction S M] [IsScalarTower S R M] + (P : Submodule R M) : DistribMulAction S (M ⧸ P) := + { Function.Surjective.distribMulAction {toFun := mk, map_zero' := rfl, map_add' := fun _ _ => rfl} + (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with + toMulAction := mulAction' _ } + +-- Porting note: should this be marked as a `@[default_instance]`? +instance distribMulAction (P : Submodule R M) : DistribMulAction R (M ⧸ P) := + Quotient.distribMulAction' P + +-- Performance of `Function.Surjective.module` is worse since it has to unify data to apply +-- TODO: leanprover-community/mathlib4#7432 +instance module' [Semiring S] [SMul S R] [Module S M] [IsScalarTower S R M] (P : Submodule R M) : + Module S (M ⧸ P) := + { Function.Surjective.module _ {toFun := mk, map_zero' := by rfl, map_add' := fun _ _ => by rfl} + (surjective_quot_mk _) (Submodule.Quotient.mk_smul P) with + toDistribMulAction := distribMulAction' _ } + +-- Porting note: should this be marked as a `@[default_instance]`? +instance module (P : Submodule R M) : Module R (M ⧸ P) := + Quotient.module' P + +end Module + +theorem mk_surjective : Function.Surjective (@mk _ _ _ _ _ p) := by + rintro ⟨x⟩ + exact ⟨x, rfl⟩ + +end Quotient + +section + +variable {M₂ : Type*} [AddCommGroup M₂] [Module R M₂] + +theorem quot_hom_ext (f g : (M ⧸ p) →ₗ[R] M₂) (h : ∀ x : M, f (Quotient.mk x) = g (Quotient.mk x)) : + f = g := + LinearMap.ext fun x => Quotient.inductionOn' x h + +/-- The map from a module `M` to the quotient of `M` by a submodule `p` as a linear map. -/ +def mkQ : M →ₗ[R] M ⧸ p where + toFun := Quotient.mk + map_add' := by simp + map_smul' := by simp + +@[simp] +theorem mkQ_apply (x : M) : p.mkQ x = Quotient.mk x := + rfl + +theorem mkQ_surjective : Function.Surjective p.mkQ := by + rintro ⟨x⟩; exact ⟨x, rfl⟩ + +end + +variable {R₂ M₂ : Type*} [Ring R₂] [AddCommGroup M₂] [Module R₂ M₂] {τ₁₂ : R →+* R₂} + +/-- Two `LinearMap`s from a quotient module are equal if their compositions with +`submodule.mkQ` are equal. + +See note [partially-applied ext lemmas]. -/ +@[ext 1100] -- Porting note: increase priority so this applies before `LinearMap.ext` +theorem linearMap_qext ⦃f g : M ⧸ p →ₛₗ[τ₁₂] M₂⦄ (h : f.comp p.mkQ = g.comp p.mkQ) : f = g := + LinearMap.ext fun x => Quotient.inductionOn' x <| (LinearMap.congr_fun h : _) + +/-- Quotienting by equal submodules gives linearly equivalent quotients. -/ +def quotEquivOfEq (h : p = p') : (M ⧸ p) ≃ₗ[R] M ⧸ p' := + { @Quotient.congr _ _ (quotientRel p) (quotientRel p') (Equiv.refl _) fun a b => by + subst h + rfl with + map_add' := by + rintro ⟨x⟩ ⟨y⟩ + rfl + map_smul' := by + rintro x ⟨y⟩ + rfl } + +@[simp] +theorem quotEquivOfEq_mk (h : p = p') (x : M) : + Submodule.quotEquivOfEq p p' h (Submodule.Quotient.mk x) = + (Submodule.Quotient.mk x) := + rfl + +end Submodule + +end Ring diff --git a/Mathlib/LinearAlgebra/QuotientPi.lean b/Mathlib/LinearAlgebra/Quotient/Pi.lean similarity index 97% rename from Mathlib/LinearAlgebra/QuotientPi.lean rename to Mathlib/LinearAlgebra/Quotient/Pi.lean index e4771d9be3c91..67ac5c5aa2063 100644 --- a/Mathlib/LinearAlgebra/QuotientPi.lean +++ b/Mathlib/LinearAlgebra/Quotient/Pi.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen, Alex J. Best -/ import Mathlib.LinearAlgebra.Pi -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic /-! # Submodule quotients and direct sums @@ -69,7 +69,6 @@ theorem quotientPiLift_mk (p : ∀ i, Submodule R (Ms i)) (f : ∀ i, Ms i → quotientPiLift p f hf (Quotient.mk x) = fun i => f i (x i) := rfl --- Porting note (#11083): split up the definition to avoid timeouts. Still slow. namespace quotientPi_aux variable (p : ∀ i, Submodule R (Ms i)) diff --git a/Mathlib/LinearAlgebra/Ray.lean b/Mathlib/LinearAlgebra/Ray.lean index 547a7c8540f4b..cf4501ff16800 100644 --- a/Mathlib/LinearAlgebra/Ray.lean +++ b/Mathlib/LinearAlgebra/Ray.lean @@ -188,9 +188,9 @@ set_option linter.unusedVariables false in def RayVector (R M : Type*) [Zero M] := { v : M // v ≠ 0 } --- Porting note: Made Coe into CoeOut so it's not dangerous anymore instance RayVector.coe [Zero M] : CoeOut (RayVector R M) M where coe := Subtype.val + instance {R M : Type*} [Zero M] [Nontrivial M] : Nonempty (RayVector R M) := let ⟨x, hx⟩ := exists_ne (0 : M) ⟨⟨x, hx⟩⟩ @@ -200,7 +200,7 @@ variable (R M) instance RayVector.Setoid : Setoid (RayVector R M) where r x y := SameRay R (x : M) y iseqv := - ⟨fun x => SameRay.refl _, fun h => h.symm, by + ⟨fun _ => SameRay.refl _, fun h => h.symm, by intros x y z hxy hyz exact hxy.trans hyz fun hy => (y.2 hy).elim⟩ @@ -217,7 +217,6 @@ theorem equiv_iff_sameRay {v₁ v₂ : RayVector R M} : v₁ ≈ v₂ ↔ SameRa variable (R) --- Porting note: Removed `protected` here, not in namespace /-- The ray given by a nonzero vector. -/ def rayOfNeZero (v : M) (h : v ≠ 0) : Module.Ray R M := ⟦⟨v, h⟩⟧ diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean index 607057bd4e391..420de4b340130 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean @@ -86,7 +86,7 @@ evaluates to `2`, and the permutation attached to each element of `ι` is compat reflections on the corresponding roots and coroots. It exists to allow for a convenient unification of the theories of root systems and root data. -/ -structure RootPairing extends PerfectPairing R M N := +structure RootPairing extends PerfectPairing R M N where /-- A parametrized family of vectors, called roots. -/ root : ι ↪ M /-- A parametrized family of dual vectors, called coroots. -/ @@ -110,7 +110,7 @@ abbrev RootDatum (X₁ X₂ : Type*) [AddCommGroup X₁] [AddCommGroup X₂] := Note that this is slightly more general than the usual definition in the sense that `N` is not required to be the dual of `M`. -/ -structure RootSystem extends RootPairing ι R M N := +structure RootSystem extends RootPairing ι R M N where span_eq_top : span R (range root) = ⊤ attribute [simp] RootSystem.span_eq_top @@ -501,12 +501,12 @@ lemma reflection_perm_eq_reflection_perm_iff_of_span : P.reflection_perm i = P.reflection_perm j ↔ ∀ x ∈ span R (range P.root), P.reflection i x = P.reflection j x := by refine ⟨fun h x hx ↦ ?_, fun h ↦ ?_⟩ - · induction hx using Submodule.span_induction' with + · induction hx using Submodule.span_induction with | mem x hx => obtain ⟨k, rfl⟩ := hx simp only [← root_reflection_perm, h] | zero => simp - | add x _ y _ hx hy => simp [hx, hy] + | add x y _ _ hx hy => simp [hx, hy] | smul t x _ hx => simp [hx] · ext k apply P.root.injective diff --git a/Mathlib/LinearAlgebra/RootSystem/Hom.lean b/Mathlib/LinearAlgebra/RootSystem/Hom.lean index 5d58b28dabbf4..08f552e72ccc3 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Hom.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Hom.lean @@ -11,13 +11,34 @@ This file defines morphisms of root pairings, following the definition of morphi given in SGA III Exp. 21 Section 6. ## Main definitions: - * `Hom`: A morphism of root data is a linear map of weight spaces, its transverse on coweight + * `Hom`: A morphism of root pairings is a linear map of weight spaces, its transverse on coweight spaces, and a bijection on the set that indexes roots and coroots. * `Hom.id`: The identity morphism. * `Hom.comp`: The composite of two morphisms. + * `End`: The endomorphism monoid of a root pairing. + * `Hom.weightHom`: The homomorphism from the endomorphism monoid to linear endomorphisms on the + weight space. + * `Hom.coweightHom`: The homomorphism from the endomorphism monoid to the opposite monoid of linear + endomorphisms on the coweight space. + * `Equiv`: An equivalence of root pairings is a morphism for which the maps on weight spaces and + coweight spaces are bijective. + * `Equiv.toHom`: The morphism underlying an equivalence. + * `Equiv.weightEquiv`: The linear isomorphism on weight spaces given by an equivalence. + * `Equiv.coweightEquiv`: The linear isomorphism on coweight spaces given by an equivalence. + * `Equiv.id`: The identity equivalence. + * `Equiv.comp`: The composite of two equivalences. + * `Equiv.symm`: The inverse of an equivalence. + * `Aut`: The automorphism group of a root pairing. + * `Equiv.toEndUnit`: The group isomorphism between the automorphism group of a root pairing and the + group of invertible endomorphisms. + * `Equiv.weightHom`: The homomorphism from the automorphism group to linear automorphisms on the + weight space. + * `Equiv.coweightHom`: The homomorphism from the automorphism group to the opposite group of linear + automorphisms on the coweight space. + * `Equiv.reflection`: The automorphism of a root pairing given by reflection in a root and + coreflection in the corresponding coroot. ## TODO - * Special types of morphisms: Isogenies, weight/coweight space embeddings * Weyl group reimplementation? @@ -47,9 +68,29 @@ structure Hom {ι₂ M₂ N₂ : Type*} root_weightMap : weightMap ∘ P.root = Q.root ∘ indexEquiv coroot_coweightMap : coweightMap ∘ Q.coroot = P.coroot ∘ indexEquiv.symm +namespace Hom + +lemma weight_coweight_transpose_apply {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (x : N₂) (f : Hom P Q) : + f.weightMap.dualMap (Q.toDualRight x) = P.toDualRight (f.coweightMap x) := + Eq.mp (propext LinearMap.ext_iff) f.weight_coweight_transpose x + +lemma root_weightMap_apply {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (i : ι) (f : Hom P Q) : + f.weightMap (P.root i) = Q.root (f.indexEquiv i) := + Eq.mp (propext funext_iff) f.root_weightMap i + +lemma coroot_coweightMap_apply {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (i : ι₂) (f : Hom P Q) : + f.coweightMap (Q.coroot i) = P.coroot (f.indexEquiv.symm i) := + Eq.mp (propext funext_iff) f.coroot_coweightMap i + /-- The identity morphism of a root pairing. -/ @[simps!] -def Hom.id (P : RootPairing ι R M N) : Hom P P where +def id (P : RootPairing ι R M N) : Hom P P where weightMap := LinearMap.id coweightMap := LinearMap.id indexEquiv := Equiv.refl ι @@ -59,7 +100,7 @@ def Hom.id (P : RootPairing ι R M N) : Hom P P where /-- Composition of morphisms -/ @[simps!] -def Hom.comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Module R M₁] [AddCommGroup N₁] +def comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Module R M₁] [AddCommGroup N₁] [Module R N₁] [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] {P : RootPairing ι R M N} {P₁ : RootPairing ι₁ R M₁ N₁} {P₂ : RootPairing ι₂ R M₂ N₂} (g : Hom P₁ P₂) (f : Hom P P₁) : Hom P P₂ where @@ -82,31 +123,451 @@ def Hom.comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Modu simp @[simp] -lemma Hom.id_comp {ι₂ M₂ N₂ : Type*} +lemma id_comp {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (f : Hom P Q) : - Hom.comp f (Hom.id P) = f := by + comp f (id P) = f := by ext x <;> simp @[simp] -lemma Hom.comp_id {ι₂ M₂ N₂ : Type*} +lemma comp_id {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (f : Hom P Q) : - Hom.comp (Hom.id Q) f = f := by + comp (id Q) f = f := by ext x <;> simp @[simp] -lemma Hom.comp_assoc {ι₁ M₁ N₁ ι₂ M₂ N₂ ι₃ M₃ N₃ : Type*} [AddCommGroup M₁] [Module R M₁] +lemma comp_assoc {ι₁ M₁ N₁ ι₂ M₂ N₂ ι₃ M₃ N₃ : Type*} [AddCommGroup M₁] [Module R M₁] [AddCommGroup N₁] [Module R N₁] [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] [AddCommGroup M₃] [Module R M₃] [AddCommGroup N₃] [Module R N₃] {P : RootPairing ι R M N} {P₁ : RootPairing ι₁ R M₁ N₁} {P₂ : RootPairing ι₂ R M₂ N₂} {P₃ : RootPairing ι₃ R M₃ N₃} (h : Hom P₂ P₃) (g : Hom P₁ P₂) (f : Hom P P₁) : - Hom.comp (Hom.comp h g) f = Hom.comp h (Hom.comp g f) := by + comp (comp h g) f = comp h (comp g f) := by ext <;> simp -/-- The endomorphism of a root pairing given by a reflection. -/ +/-- The endomorphism monoid of a root pairing. -/ +instance (P : RootPairing ι R M N) : Monoid (Hom P P) where + mul := comp + mul_assoc := comp_assoc + one := id P + one_mul := id_comp P P + mul_one := comp_id P P + +@[simp] +lemma weightMap_one (P : RootPairing ι R M N) : + weightMap (P := P) (Q := P) 1 = LinearMap.id (R := R) (M := M) := + rfl + +@[simp] +lemma coweightMap_one (P : RootPairing ι R M N) : + coweightMap (P := P) (Q := P) 1 = LinearMap.id (R := R) (M := N) := + rfl + +@[simp] +lemma indexEquiv_one (P : RootPairing ι R M N) : + indexEquiv (P := P) (Q := P) 1 = Equiv.refl ι := + rfl + +@[simp] +lemma weightMap_mul (P : RootPairing ι R M N) (x y : Hom P P) : + weightMap (x * y) = weightMap x ∘ₗ weightMap y := + rfl + +@[simp] +lemma coweightMap_mul (P : RootPairing ι R M N) (x y : Hom P P) : + coweightMap (x * y) = coweightMap y ∘ₗ coweightMap x := + rfl + +@[simp] +lemma indexEquiv_mul (P : RootPairing ι R M N) (x y : Hom P P) : + indexEquiv (x * y) = indexEquiv x ∘ indexEquiv y := + rfl + +/-- The endomorphism monoid of a root pairing. -/ +abbrev _root_.RootPairing.End (P : RootPairing ι R M N) := Hom P P + +/-- The weight space representation of endomorphisms -/ +def weightHom (P : RootPairing ι R M N) : End P →* (Module.End R M) where + toFun g := Hom.weightMap (P := P) (Q := P) g + map_mul' g h := by ext; simp + map_one' := by ext; simp + +lemma weightHom_injective (P : RootPairing ι R M N) : Injective (weightHom P) := by + intro f g hfg + ext x + · exact LinearMap.congr_fun hfg x + · refine (LinearEquiv.injective P.toDualRight) ?_ + simp_rw [← weight_coweight_transpose_apply] + exact congrFun (congrArg DFunLike.coe (congrArg LinearMap.dualMap hfg)) (P.toDualRight x) + · refine (Embedding.injective P.root) ?_ + simp_rw [← root_weightMap_apply] + exact congrFun (congrArg DFunLike.coe hfg) (P.root x) + +/-- The coweight space representation of endomorphisms -/ +def coweightHom (P : RootPairing ι R M N) : End P →* (N →ₗ[R] N)ᵐᵒᵖ where + toFun g := MulOpposite.op (Hom.coweightMap (P := P) (Q := P) g) + map_mul' g h := by + simp only [← MulOpposite.op_mul, coweightMap_mul, LinearMap.mul_eq_comp] + map_one' := by + simp only [MulOpposite.op_eq_one_iff, coweightMap_one, LinearMap.one_eq_id] + +lemma coweightHom_injective (P : RootPairing ι R M N) : Injective (coweightHom P) := by + intro f g hfg + ext x + · dsimp [coweightHom] at hfg + rw [MulOpposite.op_inj] at hfg + have h := congrArg (LinearMap.comp (M₃ := Module.Dual R M) + (σ₂₃ := RingHom.id R) (P.toDualRight)) hfg + rw [← f.weight_coweight_transpose, ← g.weight_coweight_transpose] at h + have : f.weightMap = g.weightMap := by + haveI : Module.IsReflexive R M := PerfectPairing.reflexive_left P.toPerfectPairing + refine (Module.dualMap_dualMap_eq_iff R M).mp (congrArg LinearMap.dualMap + ((LinearEquiv.eq_comp_toLinearMap_iff f.weightMap.dualMap g.weightMap.dualMap).mp h)) + exact congrFun (congrArg DFunLike.coe this) x + · dsimp [coweightHom] at hfg + simp_all only [MulOpposite.op_inj] + · dsimp [coweightHom] at hfg + rw [MulOpposite.op_inj] at hfg + set y := f.indexEquiv x with hy + have : f.coweightMap (P.coroot y) = g.coweightMap (P.coroot y) := by + exact congrFun (congrArg DFunLike.coe hfg) (P.coroot y) + rw [coroot_coweightMap_apply, coroot_coweightMap_apply, Embedding.apply_eq_iff_eq, hy] at this + rw [Equiv.symm_apply_apply] at this + rw [this, Equiv.apply_symm_apply] + +end Hom + +variable {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) + +/-- An equivalence of root pairings is a morphism where the maps of weight and coweight spaces are +bijective. + +See also `RootPairing.Equiv.toEndUnit`. -/ +@[ext] +protected structure Equiv extends Hom P Q where + bijective_weightMap : Bijective weightMap + bijective_coweightMap : Bijective coweightMap + +attribute [coe] Equiv.toHom + +/-- The root pairing homomorphism underlying an equivalence. -/ +add_decl_doc Equiv.toHom + +namespace Equiv + +/-- The linear equivalence of weight spaces given by an equivalence of root pairings. -/ +def weightEquiv (e : RootPairing.Equiv P Q) : M ≃ₗ[R] M₂ := + LinearEquiv.ofBijective _ e.bijective_weightMap + +@[simp] +lemma weightEquiv_apply (e : RootPairing.Equiv P Q) (m : M) : + weightEquiv P Q e m = e.toHom.weightMap m := + rfl + +@[simp] +lemma weightEquiv_symm_weightMap (e : RootPairing.Equiv P Q) (m : M) : + (weightEquiv P Q e).symm (e.toHom.weightMap m) = m := + (LinearEquiv.symm_apply_eq (weightEquiv P Q e)).mpr rfl + +@[simp] +lemma weightMap_weightEquiv_symm (e : RootPairing.Equiv P Q) (m : M₂) : + e.toHom.weightMap ((weightEquiv P Q e).symm m) = m := by + rw [← weightEquiv_apply] + exact LinearEquiv.apply_symm_apply (weightEquiv P Q e) m + +/-- The contravariant equivalence of coweight spaces given by an equivalence of root pairings. -/ +def coweightEquiv (e : RootPairing.Equiv P Q) : N₂ ≃ₗ[R] N := + LinearEquiv.ofBijective _ e.bijective_coweightMap + +@[simp] +lemma coweightEquiv_apply (e : RootPairing.Equiv P Q) (n : N₂) : + coweightEquiv P Q e n = e.toHom.coweightMap n := + rfl + +@[simp] +lemma coweightEquiv_symm_coweightMap (e : RootPairing.Equiv P Q) (n : N₂) : + (coweightEquiv P Q e).symm (e.toHom.coweightMap n) = n := + (LinearEquiv.symm_apply_eq (coweightEquiv P Q e)).mpr rfl + +@[simp] +lemma coweightMap_coweightEquiv_symm (e : RootPairing.Equiv P Q) (n : N) : + e.toHom.coweightMap ((coweightEquiv P Q e).symm n) = n := by + rw [← coweightEquiv_apply] + exact LinearEquiv.apply_symm_apply (coweightEquiv P Q e) n + +/-- The identity equivalence of a root pairing. -/ +@[simps!] +def id (P : RootPairing ι R M N) : RootPairing.Equiv P P := + { Hom.id P with + bijective_weightMap := _root_.id bijective_id + bijective_coweightMap := _root_.id bijective_id } + +/-- Composition of equivalences -/ @[simps!] -def Hom.reflection (P : RootPairing ι R M N) (i : ι) : Hom P P where +def comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Module R M₁] [AddCommGroup N₁] + [Module R N₁] [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + {P : RootPairing ι R M N} {P₁ : RootPairing ι₁ R M₁ N₁} {P₂ : RootPairing ι₂ R M₂ N₂} + (g : RootPairing.Equiv P₁ P₂) (f : RootPairing.Equiv P P₁) : RootPairing.Equiv P P₂ := + { Hom.comp g.toHom f.toHom with + bijective_weightMap := by + simp only [Hom.comp, LinearMap.coe_comp] + exact Bijective.comp g.bijective_weightMap f.bijective_weightMap + bijective_coweightMap := by + simp only [Hom.comp, LinearMap.coe_comp] + exact Bijective.comp f.bijective_coweightMap g.bijective_coweightMap } + +@[simp] +lemma toHom_comp {ι₁ M₁ N₁ ι₂ M₂ N₂ : Type*} [AddCommGroup M₁] [Module R M₁] [AddCommGroup N₁] + [Module R N₁] [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + {P : RootPairing ι R M N} {P₁ : RootPairing ι₁ R M₁ N₁} {P₂ : RootPairing ι₂ R M₂ N₂} + (g : RootPairing.Equiv P₁ P₂) (f : RootPairing.Equiv P P₁) : + (Equiv.comp g f).toHom = Hom.comp g.toHom f.toHom := by + rfl + +@[simp] +lemma id_comp {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (f : RootPairing.Equiv P Q) : + comp f (id P) = f := by + ext x <;> simp + +@[simp] +lemma comp_id {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (f : RootPairing.Equiv P Q) : + comp (id Q) f = f := by + ext x <;> simp + +@[simp] +lemma comp_assoc {ι₁ M₁ N₁ ι₂ M₂ N₂ ι₃ M₃ N₃ : Type*} [AddCommGroup M₁] [Module R M₁] + [AddCommGroup N₁] [Module R N₁] [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + [AddCommGroup M₃] [Module R M₃] [AddCommGroup N₃] [Module R N₃] {P : RootPairing ι R M N} + {P₁ : RootPairing ι₁ R M₁ N₁} {P₂ : RootPairing ι₂ R M₂ N₂} {P₃ : RootPairing ι₃ R M₃ N₃} + (h : RootPairing.Equiv P₂ P₃) (g : RootPairing.Equiv P₁ P₂) (f : RootPairing.Equiv P P₁) : + comp (comp h g) f = comp h (comp g f) := by + ext <;> simp + +/-- The endomorphism monoid of a root pairing. -/ +instance (P : RootPairing ι R M N) : Monoid (RootPairing.Equiv P P) where + mul := comp + mul_assoc := comp_assoc + one := id P + one_mul := id_comp P P + mul_one := comp_id P P + +@[simp] +lemma weightEquiv_one (P : RootPairing ι R M N) : + weightEquiv (P := P) (Q := P) 1 = LinearMap.id (R := R) (M := M) := + rfl + +@[simp] +lemma coweightEquiv_one (P : RootPairing ι R M N) : + coweightEquiv (P := P) (Q := P) 1 = LinearMap.id (R := R) (M := N) := + rfl + +@[simp] +lemma toHom_one (P : RootPairing ι R M N) : + (1 : RootPairing.Equiv P P).toHom = (1 : RootPairing.Hom P P) := + rfl + +@[simp] +lemma mul_eq_comp {P : RootPairing ι R M N} (x y : RootPairing.Equiv P P) : + x * y = Equiv.comp x y := + rfl + +@[simp] +lemma weightEquiv_comp_toLin {P : RootPairing ι R M N} (x y : RootPairing.Equiv P P) : + weightEquiv P P (Equiv.comp x y) = weightEquiv P P y ≪≫ₗ weightEquiv P P x := by + ext; simp + +@[simp] +lemma weightEquiv_mul {P : RootPairing ι R M N} (x y : RootPairing.Equiv P P) : + weightEquiv P P x * weightEquiv P P y = weightEquiv P P y ≪≫ₗ weightEquiv P P x := by + rfl + +@[simp] +lemma coweightEquiv_comp_toLin {P : RootPairing ι R M N} (x y : RootPairing.Equiv P P) : + coweightEquiv P P (Equiv.comp x y) = coweightEquiv P P x ≪≫ₗ coweightEquiv P P y := by + ext; simp + +@[simp] +lemma coweightEquiv_mul {P : RootPairing ι R M N} (x y : RootPairing.Equiv P P) : + coweightEquiv P P x * coweightEquiv P P y = coweightEquiv P P y ≪≫ₗ coweightEquiv P P x := by + rfl + +/-- The inverse of a root pairing equivalence. -/ +def symm {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) (f : RootPairing.Equiv P Q) : + RootPairing.Equiv Q P where + weightMap := (weightEquiv P Q f).symm + coweightMap := (coweightEquiv P Q f).symm + indexEquiv := f.indexEquiv.symm + weight_coweight_transpose := by + ext n m + nth_rw 2 [show m = (weightEquiv P Q f) ((weightEquiv P Q f).symm m) by + exact (LinearEquiv.symm_apply_eq (weightEquiv P Q f)).mp rfl] + nth_rw 1 [show n = (coweightEquiv P Q f) ((coweightEquiv P Q f).symm n) by + exact (LinearEquiv.symm_apply_eq (coweightEquiv P Q f)).mp rfl] + have := f.weight_coweight_transpose + rw [LinearMap.ext_iff₂] at this + exact Eq.symm (this ((coweightEquiv P Q f).symm n) ((weightEquiv P Q f).symm m)) + root_weightMap := by + ext i + simp only [LinearEquiv.coe_coe, comp_apply] + have := f.root_weightMap + rw [funext_iff] at this + specialize this (f.indexEquiv.symm i) + simp only [comp_apply, Equiv.apply_symm_apply] at this + simp [← this] + coroot_coweightMap := by + ext i + simp only [LinearEquiv.coe_coe, comp_apply, Equiv.symm_symm] + have := f.coroot_coweightMap + rw [funext_iff] at this + specialize this (f.indexEquiv i) + simp only [comp_apply, Equiv.symm_apply_apply] at this + simp [← this] + bijective_weightMap := by + simp only [LinearEquiv.coe_coe] + exact LinearEquiv.bijective (weightEquiv P Q f).symm + bijective_coweightMap := by + simp only [LinearEquiv.coe_coe] + exact LinearEquiv.bijective (coweightEquiv P Q f).symm + +@[simp] +lemma inv_weightMap {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] + [Module R N₂] (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) + (f : RootPairing.Equiv P Q) : (symm P Q f).weightMap = (weightEquiv P Q f).symm := + rfl + +@[simp] +lemma inv_coweightMap {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] + [Module R N₂] (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) + (f : RootPairing.Equiv P Q) : (symm P Q f).coweightMap = (coweightEquiv P Q f).symm := + rfl + +@[simp] +lemma inv_indexEquiv {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] + [Module R N₂] (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) + (f : RootPairing.Equiv P Q) : (symm P Q f).indexEquiv = (Hom.indexEquiv f.toHom).symm := + rfl + +/-- The endomorphism monoid of a root pairing. -/ +instance (P : RootPairing ι R M N) : Group (RootPairing.Equiv P P) where + mul := comp + mul_assoc := comp_assoc + one := id P + one_mul := id_comp P P + mul_one := comp_id P P + inv := symm P P + inv_mul_cancel e := by + ext m + · rw [← weightEquiv_apply] + simp + · rw [← coweightEquiv_apply] + simp + · simp + +end Equiv + +/-- The automorphism group of a root pairing. -/ +abbrev Aut (P : RootPairing ι R M N) := (RootPairing.Equiv P P) + +namespace Equiv + +/-- The isomorphism between the automorphism group of a root pairing and the group of invertible +endomorphisms. -/ +def toEndUnit (P : RootPairing ι R M N) : Aut P ≃* (End P)ˣ where + toFun f := + { val := f.toHom + inv := (Equiv.symm P P f).toHom + val_inv := by ext <;> simp + inv_val := by ext <;> simp } + invFun f := + { f.val with + bijective_weightMap := by + refine bijective_iff_has_inverse.mpr ?_ + use f.inv.weightMap + constructor + · refine leftInverse_iff_comp.mpr ?_ + simp only [← @LinearMap.coe_comp] + rw [← Hom.weightMap_mul, f.inv_val, Hom.weightMap_one, LinearMap.id_coe] + · refine rightInverse_iff_comp.mpr ?_ + simp only [← @LinearMap.coe_comp] + rw [← Hom.weightMap_mul, f.val_inv, Hom.weightMap_one, LinearMap.id_coe] + bijective_coweightMap := by + refine bijective_iff_has_inverse.mpr ?_ + use f.inv.coweightMap + constructor + · refine leftInverse_iff_comp.mpr ?_ + simp only [← @LinearMap.coe_comp] + rw [← Hom.coweightMap_mul, f.val_inv, Hom.coweightMap_one, LinearMap.id_coe] + · refine rightInverse_iff_comp.mpr ?_ + simp only [← @LinearMap.coe_comp] + rw [← Hom.coweightMap_mul, f.inv_val, Hom.coweightMap_one, LinearMap.id_coe] } + left_inv f := by simp + right_inv f := by simp + map_mul' f g := by + simp only [Equiv.mul_eq_comp, Equiv.toHom_comp] + ext <;> simp + +lemma toEndUnit_val (P : RootPairing ι R M N) (g : Aut P) : (toEndUnit P g).val = g.toHom := + rfl + +lemma toEndUnit_inv (P : RootPairing ι R M N) (g : Aut P) : + (toEndUnit P g).inv = (symm P P g).toHom := + rfl + +/-- The weight space representation of automorphisms -/ +@[simps] +def weightHom (P : RootPairing ι R M N) : Aut P →* (M ≃ₗ[R] M) where + toFun := weightEquiv P P + map_one' := by ext; simp + 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 := + 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 + 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' + +/-- 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) + map_one' := by + simp only [MulOpposite.op_eq_one_iff] + exact LinearEquiv.toLinearMap_inj.mp rfl + map_mul' := by + simp only [mul_eq_comp, coweightEquiv_comp_toLin] + 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) := + 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 + simp_all + rw [coweightHom_toLinearMap, coweightHom_toLinearMap] at h + suffices h' : g.toHom = g'.toHom by + exact Equiv.ext (congrArg Hom.weightMap h') h (congrArg Hom.indexEquiv h') + apply Hom.coweightHom_injective P + exact MulOpposite.unop_inj.mp h + +/-- 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 coweightMap := P.coreflection i indexEquiv := P.reflection_perm i @@ -121,5 +582,27 @@ def Hom.reflection (P : RootPairing ι R M N) (i : ι) : Hom P P where simp only [PerfectPairing.toLin_apply, PerfectPairing.flip_apply_apply, mul_comm] root_weightMap := by ext; simp coroot_coweightMap := by ext; simp + bijective_weightMap := by + simp only [LinearEquiv.coe_coe] + exact LinearEquiv.bijective (P.reflection i) + bijective_coweightMap := by + simp only [LinearEquiv.coe_coe] + exact LinearEquiv.bijective (P.coreflection i) + +@[simp] +lemma reflection_weightEquiv (P : RootPairing ι R M N) (i : ι) : + (reflection P i).weightEquiv = P.reflection i := + LinearEquiv.toLinearMap_inj.mp rfl + +@[simp] +lemma reflection_coweightEquiv (P : RootPairing ι R M N) (i : ι) : + (reflection P i).coweightEquiv = P.coreflection i := + LinearEquiv.toLinearMap_inj.mp rfl + +@[simp] +lemma reflection_indexEquiv (P : RootPairing ι R M N) (i : ι) : + (reflection P i).indexEquiv = P.reflection_perm i := rfl + +end Equiv end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean index 026b7b23f30d7..ae27ada2167b0 100644 --- a/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean +++ b/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean @@ -25,7 +25,7 @@ open Set Function Module noncomputable section -variable {ι R M N : Type*} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] namespace LinearMap @@ -33,7 +33,7 @@ namespace LinearMap injective, and for any vector `y`, the norm of `x` divides twice the inner product of `x` and `y`. These conditions are what we need when describing reflection as a map taking `y` to `y - 2 • (B x y) / (B x x) • x`. -/ -structure IsReflective (B : M →ₗ[R] M →ₗ[R] R) (x : M) : Prop := +structure IsReflective (B : M →ₗ[R] M →ₗ[R] R) (x : M) : Prop where regular : IsRegular (B x x) dvd_two_mul : ∀ y, B x x ∣ 2 * B x y diff --git a/Mathlib/LinearAlgebra/SModEq.lean b/Mathlib/LinearAlgebra/SModEq.lean index 2c50a7ef8519f..d2851ed817bf6 100644 --- a/Mathlib/LinearAlgebra/SModEq.lean +++ b/Mathlib/LinearAlgebra/SModEq.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ import Mathlib.Algebra.Polynomial.Eval -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Defs /-! # modular equivalence for submodule diff --git a/Mathlib/LinearAlgebra/Semisimple.lean b/Mathlib/LinearAlgebra/Semisimple.lean index 3aeb94be63ed6..34d9925e6aa6a 100644 --- a/Mathlib/LinearAlgebra/Semisimple.lean +++ b/Mathlib/LinearAlgebra/Semisimple.lean @@ -4,11 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ import Mathlib.FieldTheory.Perfect -import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.LinearAlgebra.AnnihilatingPolynomial -import Mathlib.Order.CompleteSublattice +import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.RingTheory.Artinian -import Mathlib.RingTheory.QuotientNilpotent +import Mathlib.RingTheory.Ideal.Quotient.Nilpotent import Mathlib.RingTheory.SimpleModule /-! @@ -49,22 +48,61 @@ namespace Module.End section CommRing -variable (f g : End R M) +variable (f : End R M) /-- A linear endomorphism of an `R`-module `M` is called *semisimple* if the induced `R[X]`-module structure on `M` is semisimple. This is equivalent to saying that every `f`-invariant `R`-submodule of `M` has an `f`-invariant complement: see `Module.End.isSemisimple_iff`. -/ -abbrev IsSemisimple := IsSemisimpleModule R[X] (AEval' f) +def IsSemisimple := IsSemisimpleModule R[X] (AEval' f) + +/-- A weaker version of semisimplicity that only prescribes behaviour on finitely-generated +submodules. -/ +def IsFinitelySemisimple : Prop := + ∀ p (hp : p ∈ invtSubmodule f), Module.Finite R p → IsSemisimple (LinearMap.restrict f hp) + +variable {f} -variable {f g} +/-- A linear endomorphism is semisimple if every invariant submodule has in invariant complement. + +See also `Module.End.isSemisimple_iff`. -/ +lemma isSemisimple_iff' : + f.IsSemisimple ↔ ∀ p : invtSubmodule f, ∃ q : invtSubmodule f, IsCompl p q := by + rw [IsSemisimple, IsSemisimpleModule, (AEval.mapSubmodule R M f).symm.complementedLattice_iff, + complementedLattice_iff] + rfl lemma isSemisimple_iff : - f.IsSemisimple ↔ ∀ p : Submodule R M, p ≤ p.comap f → ∃ q, q ≤ q.comap f ∧ IsCompl p q := by - set s := (AEval.comapSubmodule R M f).range - have h : s = {p : Submodule R M | p ≤ p.comap f} := AEval.range_comapSubmodule R M f - let e := CompleteLatticeHom.toOrderIsoRangeOfInjective _ (AEval.injective_comapSubmodule R M f) - simp_rw [Module.End.IsSemisimple, IsSemisimpleModule, e.complementedLattice_iff, - s.isComplemented_iff, ← SetLike.mem_coe, h, mem_setOf_eq] + f.IsSemisimple ↔ ∀ p ∈ invtSubmodule f, ∃ q ∈ invtSubmodule f, IsCompl p q := by + simp_rw [isSemisimple_iff'] + aesop + +lemma isSemisimple_restrict_iff (p) (hp : p ∈ invtSubmodule f) : + IsSemisimple (LinearMap.restrict f hp) ↔ + ∀ q ∈ f.invtSubmodule, q ≤ p → ∃ r ≤ p, r ∈ f.invtSubmodule ∧ Disjoint q r ∧ q ⊔ r = p := by + let e : Submodule R[X] (AEval' (f.restrict hp)) ≃o Iic (AEval.mapSubmodule R M f ⟨p, hp⟩) := + (Submodule.orderIsoMapComap <| AEval.restrict_equiv_mapSubmodule f p hp).trans + (Submodule.mapIic _) + simp_rw [IsSemisimple, IsSemisimpleModule, e.complementedLattice_iff, disjoint_iff, + ← (OrderIso.Iic _ _).complementedLattice_iff, Iic.complementedLattice_iff, Subtype.forall, + Subtype.exists, Subtype.mk_le_mk, Sublattice.mk_inf_mk, Sublattice.mk_sup_mk, Subtype.mk.injEq, + exists_and_left, exists_and_right, invtSubmodule.mk_eq_bot_iff, exists_prop, and_assoc] + rfl + +/-- A linear endomorphism is finitely semisimple if it is semisimple on every finitely-generated +invariant submodule. + +See also `Module.End.isFinitelySemisimple_iff`. -/ +lemma isFinitelySemisimple_iff' : + f.IsFinitelySemisimple ↔ ∀ p (hp : p ∈ invtSubmodule f), + Module.Finite R p → IsSemisimple (LinearMap.restrict f hp) := + Iff.rfl + +/-- A characterisation of `Module.End.IsFinitelySemisimple` using only the lattice of submodules of +`M` (thus avoiding submodules of submodules). -/ +lemma isFinitelySemisimple_iff : + f.IsFinitelySemisimple ↔ ∀ p ∈ invtSubmodule f, Module.Finite R p → ∀ q ∈ invtSubmodule f, + q ≤ p → ∃ r, r ≤ p ∧ r ∈ invtSubmodule f ∧ Disjoint q r ∧ q ⊔ r = p := by + simp_rw [isFinitelySemisimple_iff', isSemisimple_restrict_iff] @[simp] lemma isSemisimple_zero [IsSemisimpleModule R M] : IsSemisimple (0 : Module.End R M) := by @@ -74,7 +112,16 @@ lemma isSemisimple_zero [IsSemisimpleModule R M] : IsSemisimple (0 : Module.End lemma isSemisimple_id [IsSemisimpleModule R M] : IsSemisimple (LinearMap.id : Module.End R M) := by simpa [isSemisimple_iff] using exists_isCompl -@[simp] lemma isSemisimple_neg : (-f).IsSemisimple ↔ f.IsSemisimple := by simp [isSemisimple_iff] +@[simp] lemma isSemisimple_neg : (-f).IsSemisimple ↔ f.IsSemisimple := by + simp [isSemisimple_iff, mem_invtSubmodule] + +variable (f) in +protected lemma _root_.LinearEquiv.isSemisimple_iff {M₂ : Type*} [AddCommGroup M₂] [Module R M₂] + (g : End R M₂) (e : M ≃ₗ[R] M₂) (he : e ∘ₗ f = g ∘ₗ e) : + f.IsSemisimple ↔ g.IsSemisimple := by + let e : AEval' f ≃ₗ[R[X]] AEval' g := LinearEquiv.ofAEval _ (e.trans (AEval'.of g)) fun x ↦ by + simpa [AEval'.X_smul_of] using LinearMap.congr_fun he x + exact (Submodule.orderIsoMapComap e).complementedLattice_iff lemma eq_zero_of_isNilpotent_isSemisimple (hn : IsNilpotent f) (hs : f.IsSemisimple) : f = 0 := by have ⟨n, h0⟩ := hn @@ -82,24 +129,74 @@ lemma eq_zero_of_isNilpotent_isSemisimple (hn : IsNilpotent f) (hs : f.IsSemisim rw [← RingHom.mem_ker, ← AEval.annihilator_eq_ker_aeval (M := M)] at h0 ⊢ exact hs.annihilator_isRadical _ _ ⟨n, h0⟩ +lemma eq_zero_of_isNilpotent_of_isFinitelySemisimple + (hn : IsNilpotent f) (hs : IsFinitelySemisimple f) : f = 0 := by + have (p) (hp₁ : p ∈ f.invtSubmodule) (hp₂ : Module.Finite R p) : f.restrict hp₁ = 0 := by + specialize hs p hp₁ hp₂ + replace hn : IsNilpotent (f.restrict hp₁) := isNilpotent.restrict hp₁ hn + exact eq_zero_of_isNilpotent_isSemisimple hn hs + ext x + obtain ⟨k : ℕ, hk : f ^ k = 0⟩ := hn + let p := Submodule.span R {(f ^ i) x | (i : ℕ) (_ : i ≤ k)} + have hp₁ : p ∈ f.invtSubmodule := by + simp only [mem_invtSubmodule, p, Submodule.span_le] + rintro - ⟨i, hi, rfl⟩ + apply Submodule.subset_span + rcases lt_or_eq_of_le hi with hik | rfl + · exact ⟨i + 1, hik, by simpa [LinearMap.pow_apply] using iterate_succ_apply' f i x⟩ + · exact ⟨i, by simp [hk]⟩ + have hp₂ : Module.Finite R p := by + let g : ℕ → M := fun i ↦ (f ^ i) x + have hg : {(f ^ i) x | (i : ℕ) (_ : i ≤ k)} = g '' Iic k := by ext; simp [g] + exact Module.Finite.span_of_finite _ <| hg ▸ toFinite (g '' Iic k) + simpa [LinearMap.restrict_apply, Subtype.ext_iff] using + LinearMap.congr_fun (this p hp₁ hp₂) ⟨x, Submodule.subset_span ⟨0, k.zero_le, rfl⟩⟩ + @[simp] lemma isSemisimple_sub_algebraMap_iff {μ : R} : (f - algebraMap R (End R M) μ).IsSemisimple ↔ f.IsSemisimple := by suffices ∀ p : Submodule R M, p ≤ p.comap (f - algebraMap R (Module.End R M) μ) ↔ p ≤ p.comap f by - simp [isSemisimple_iff, this] + simp [mem_invtSubmodule, isSemisimple_iff, this] refine fun p ↦ ⟨fun h x hx ↦ ?_, fun h x hx ↦ p.sub_mem (h hx) (p.smul_mem μ hx)⟩ simpa using p.add_mem (h hx) (p.smul_mem μ hx) -lemma IsSemisimple.restrict {p : Submodule R M} {hp : MapsTo f p p} (hf : f.IsSemisimple) : +lemma IsSemisimple.restrict {p : Submodule R M} (hp : p ∈ f.invtSubmodule) (hf : f.IsSemisimple) : IsSemisimple (f.restrict hp) := by - simp only [isSemisimple_iff] at hf ⊢ - intro q hq - replace hq : MapsTo f (q.map p.subtype) (q.map p.subtype) := by - rintro - ⟨⟨x, hx⟩, hx', rfl⟩; exact ⟨⟨f x, hp hx⟩, by simpa using hq hx', rfl⟩ - obtain ⟨r, hr₁, hr₂⟩ := hf _ hq - refine ⟨r.comap p.subtype, fun x hx ↦ hr₁ hx, ?_⟩ - rw [← q.comap_map_eq_of_injective p.injective_subtype] - exact p.isCompl_comap_subtype_of_isCompl_of_le hr₂ <| p.map_subtype_le q + rw [IsSemisimple] at hf ⊢ + let e : Submodule R[X] (AEval' (LinearMap.restrict f hp)) ≃o + Iic (AEval.mapSubmodule R M f ⟨p, hp⟩) := + (Submodule.orderIsoMapComap <| AEval.restrict_equiv_mapSubmodule f p hp).trans <| + Submodule.mapIic _ + exact e.complementedLattice_iff.mpr inferInstance + +lemma IsSemisimple.isFinitelySemisimple (hf : f.IsSemisimple) : + f.IsFinitelySemisimple := + isFinitelySemisimple_iff'.mp fun _ _ _ ↦ hf.restrict _ + +@[simp] +lemma isFinitelySemisimple_iff_isSemisimple [Module.Finite R M] : + f.IsFinitelySemisimple ↔ f.IsSemisimple := by + refine ⟨fun hf ↦ isSemisimple_iff.mpr fun p hp ↦ ?_, IsSemisimple.isFinitelySemisimple⟩ + obtain ⟨q, -, hq₁, hq₂, hq₃⟩ := + isFinitelySemisimple_iff.mp hf ⊤ (invtSubmodule.top_mem f) inferInstance p hp le_top + exact ⟨q, hq₁, hq₂, codisjoint_iff.mpr hq₃⟩ + +@[simp] +lemma isFinitelySemisimple_sub_algebraMap_iff {μ : R} : + (f - algebraMap R (End R M) μ).IsFinitelySemisimple ↔ f.IsFinitelySemisimple := by + suffices ∀ p : Submodule R M, p ≤ p.comap (f - algebraMap R (Module.End R M) μ) ↔ p ≤ p.comap f by + simp_rw [isFinitelySemisimple_iff, mem_invtSubmodule, this] + refine fun p ↦ ⟨fun h x hx ↦ ?_, fun h x hx ↦ p.sub_mem (h hx) (p.smul_mem μ hx)⟩ + simpa using p.add_mem (h hx) (p.smul_mem μ hx) + +lemma IsFinitelySemisimple.restrict {p : Submodule R M} (hp : p ∈ f.invtSubmodule) + (hf : f.IsFinitelySemisimple) : + IsFinitelySemisimple (f.restrict hp) := by + intro q hq₁ hq₂ + have := invtSubmodule.map_subtype_mem_of_mem_invtSubmodule f hp hq₁ + let e : q ≃ₗ[R] q.map p.subtype := p.equivSubtypeMap q + rw [e.isSemisimple_iff ((LinearMap.restrict f hp).restrict hq₁) (LinearMap.restrict f this) rfl] + exact hf _ this (Finite.map q p.subtype) end CommRing @@ -109,7 +206,7 @@ variable {K : Type*} [Field K] [Module K M] {f g : End K M} lemma IsSemisimple_smul_iff {t : K} (ht : t ≠ 0) : (t • f).IsSemisimple ↔ f.IsSemisimple := by - simp [isSemisimple_iff, Submodule.comap_smul f (h := ht)] + simp [isSemisimple_iff, mem_invtSubmodule, Submodule.comap_smul f (h := ht)] lemma IsSemisimple_smul (t : K) (h : f.IsSemisimple) : (t • f).IsSemisimple := by diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean index 460f7003ad94b..9fb5fb671feff 100644 --- a/Mathlib/LinearAlgebra/Span.lean +++ b/Mathlib/LinearAlgebra/Span.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Module.Submodule.EqLocus import Mathlib.Algebra.Module.Submodule.Equiv import Mathlib.Algebra.Module.Submodule.RestrictScalars +import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Ring.Idempotents import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Order.CompactlyGenerated.Basic @@ -157,82 +158,87 @@ theorem span_closure {s : Set M} : span R (AddSubmonoid.closure s : Set M) = spa preserved under addition and scalar multiplication, then `p` holds for all elements of the span of `s`. -/ @[elab_as_elim] -theorem span_induction {p : M → Prop} (h : x ∈ span R s) (mem : ∀ x ∈ s, p x) (zero : p 0) - (add : ∀ x y, p x → p y → p (x + y)) (smul : ∀ (a : R) (x), p x → p (a • x)) : p x := - ((@span_le (p := ⟨⟨⟨p, by intros x y; exact add x y⟩, zero⟩, smul⟩)) s).2 mem h - -/-- An induction principle for span membership. This is a version of `Submodule.span_induction` -for binary predicates. -/ -theorem span_induction₂ {p : M → M → Prop} {a b : M} (ha : a ∈ Submodule.span R s) - (hb : b ∈ Submodule.span R s) (mem_mem : ∀ x ∈ s, ∀ y ∈ s, p x y) - (zero_left : ∀ y, p 0 y) (zero_right : ∀ x, p x 0) - (add_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (add_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (smul_left : ∀ (r : R) x y, p x y → p (r • x) y) - (smul_right : ∀ (r : R) x y, p x y → p x (r • y)) : p a b := - Submodule.span_induction ha - (fun x hx => Submodule.span_induction hb (mem_mem x hx) (zero_right x) (add_right x) fun r => - smul_right r x) - (zero_left b) (fun x₁ x₂ => add_left x₁ x₂ b) fun r x => smul_left r x b - -/-- A dependent version of `Submodule.span_induction`. -/ -@[elab_as_elim] -theorem span_induction' {p : ∀ x, x ∈ span R s → Prop} +theorem span_induction {p : (x : M) → x ∈ span R s → Prop} (mem : ∀ (x) (h : x ∈ s), p x (subset_span h)) (zero : p 0 (Submodule.zero_mem _)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (Submodule.add_mem _ ‹_› ‹_›)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (Submodule.add_mem _ ‹_› ‹_›)) (smul : ∀ (a : R) (x hx), p x hx → p (a • x) (Submodule.smul_mem _ _ ‹_›)) {x} (hx : x ∈ span R s) : p x hx := by - refine Exists.elim ?_ fun (hx : x ∈ span R s) (hc : p x hx) => hc - refine - span_induction hx (fun m hm => ⟨subset_span hm, mem m hm⟩) ⟨zero_mem _, zero⟩ - (fun x y hx hy => - Exists.elim hx fun hx' hx => - Exists.elim hy fun hy' hy => ⟨add_mem hx' hy', add _ _ _ _ hx hy⟩) - fun r x hx => Exists.elim hx fun hx' hx => ⟨smul_mem _ _ hx', smul r _ _ hx⟩ + let p : Submodule R M := + { carrier := { x | ∃ hx, p x hx } + add_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, add _ _ _ _ hpx hpy⟩ + zero_mem' := ⟨_, zero⟩ + smul_mem' := fun r ↦ fun ⟨_, hpx⟩ ↦ ⟨_, smul r _ _ hpx⟩ } + exact span_le (p := p) |>.mpr (fun y hy ↦ ⟨subset_span hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated span_induction (since := "2024-10-10")] +alias span_induction' := span_induction + +/-- An induction principle for span membership. This is a version of `Submodule.span_induction` +for binary predicates. -/ +theorem span_induction₂ {p : (x y : M) → x ∈ span R s → y ∈ span R s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_span hx) (subset_span hy)) + (zero_left : ∀ y hy, p 0 y (zero_mem _) hy) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (smul_left : ∀ (r : R) x y hx hy, p x y hx hy → p (r • x) y (smul_mem _ r hx) hy) + (smul_right : ∀ (r : R) x y hx hy, p x y hx hy → p x (r • y) hx (smul_mem _ r hy)) + {a b : M} (ha : a ∈ Submodule.span R s) + (hb : b ∈ Submodule.span R s) : p a b ha hb := by + induction hb using span_induction with + | mem z hz => induction ha using span_induction with + | mem _ h => exact mem_mem _ _ h hz + | zero => exact zero_left _ _ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | smul _ _ _ h => exact smul_left _ _ _ _ _ h + | zero => exact zero_right a ha + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ + | smul _ _ _ h => exact smul_right _ _ _ _ _ h open AddSubmonoid in theorem span_eq_closure {s : Set M} : (span R s).toAddSubmonoid = closure (@univ R • s) := by - refine le_antisymm - (fun x hx ↦ span_induction hx (fun x hx ↦ subset_closure ⟨1, trivial, x, hx, one_smul R x⟩) - (zero_mem _) (fun _ _ ↦ add_mem) fun r m hm ↦ closure_induction hm ?_ ?_ fun _ _ h h' ↦ ?_) - (closure_le.2 ?_) - · rintro _ ⟨r, -, m, hm, rfl⟩; exact smul_mem _ _ (subset_span hm) - · rintro _ ⟨r', -, m, hm, rfl⟩; exact subset_closure ⟨r * r', trivial, m, hm, mul_smul r r' m⟩ - · rw [smul_zero]; apply zero_mem - · rw [smul_add]; exact add_mem h h' + refine le_antisymm (fun x (hx : x ∈ span R s) ↦ ?of_mem_span) (fun x hx ↦ ?of_mem_closure) + case of_mem_span => + induction hx using span_induction with + | mem x hx => exact subset_closure ⟨1, trivial, x, hx, one_smul R x⟩ + | zero => exact zero_mem _ + | add _ _ _ _ h₁ h₂ => exact add_mem h₁ h₂ + | smul r₁ y _h hy => + clear _h + induction hy using AddSubmonoid.closure_induction with + | mem _ h => + obtain ⟨r₂, -, x, hx, rfl⟩ := h + exact subset_closure ⟨r₁ * r₂, trivial, x, hx, mul_smul ..⟩ + | one => simpa only [smul_zero] using zero_mem _ + | mul _ _ _ _ h₁ h₂ => simpa only [smul_add] using add_mem h₁ h₂ + case of_mem_closure => + refine closure_le.2 ?_ hx + rintro - ⟨r, -, x, hx, rfl⟩ + exact smul_mem _ _ (subset_span hx) +open AddSubmonoid in /-- A variant of `span_induction` that combines `∀ x ∈ s, p x` and `∀ r x, p x → p (r • x)` into a single condition `∀ r, ∀ x ∈ s, p (r • x)`, which can be easier to verify. -/ @[elab_as_elim] -theorem closure_induction {p : M → Prop} (h : x ∈ span R s) (zero : p 0) - (add : ∀ x y, p x → p y → p (x + y)) (smul_mem : ∀ r : R, ∀ x ∈ s, p (r • x)) : p x := by - rw [← mem_toAddSubmonoid, span_eq_closure] at h - refine AddSubmonoid.closure_induction h ?_ zero add - rintro _ ⟨r, -, m, hm, rfl⟩ - exact smul_mem r m hm - -/-- A dependent version of `Submodule.closure_induction`. -/ -@[elab_as_elim] -theorem closure_induction' {p : ∀ x, x ∈ span R s → Prop} +theorem closure_induction {p : (x : M) → x ∈ span R s → Prop} (zero : p 0 (Submodule.zero_mem _)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (Submodule.add_mem _ ‹_› ‹_›)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (Submodule.add_mem _ ‹_› ‹_›)) (smul_mem : ∀ (r x) (h : x ∈ s), p (r • x) (Submodule.smul_mem _ _ <| subset_span h)) {x} (hx : x ∈ span R s) : p x hx := by - refine Exists.elim ?_ fun (hx : x ∈ span R s) (hc : p x hx) ↦ hc - refine closure_induction hx ⟨zero_mem _, zero⟩ - (fun x y hx hy ↦ Exists.elim hx fun hx' hx ↦ - Exists.elim hy fun hy' hy ↦ ⟨add_mem hx' hy', add _ _ _ _ hx hy⟩) - fun r x hx ↦ ⟨Submodule.smul_mem _ _ (subset_span hx), smul_mem r x hx⟩ + have key {v} : v ∈ span R s ↔ v ∈ closure (@univ R • s) := by simp [← span_eq_closure] + refine AddSubmonoid.closure_induction (p := fun x hx ↦ p x (key.mpr hx)) + ?_ zero (by simpa only [key] using add) (key.mp hx) + rintro - ⟨r, -, x, hx, rfl⟩ + exact smul_mem r x hx + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction @[simp] theorem span_span_coe_preimage : span R (((↑) : span R s → M) ⁻¹' s) = ⊤ := - eq_top_iff.2 fun x ↦ Subtype.recOn x fun x hx _ ↦ by - refine span_induction' (p := fun x hx ↦ (⟨x, hx⟩ : span R s) ∈ span R (Subtype.val ⁻¹' s)) - (fun x' hx' ↦ subset_span hx') ?_ (fun x _ y _ ↦ ?_) (fun r x _ ↦ ?_) hx - · exact zero_mem _ - · exact add_mem - · exact smul_mem _ _ + eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ + span_induction (fun _ h ↦ subset_span h) (zero_mem _) (fun _ _ _ _ ↦ add_mem) + (fun _ _ _ ↦ smul_mem _ _) hx' @[simp] lemma span_setOf_mem_eq_top : @@ -254,9 +260,9 @@ theorem span_nat_eq (s : AddSubmonoid M) : (span ℕ (s : Set M)).toAddSubmonoid theorem span_int_eq_addSubgroup_closure {M : Type*} [AddCommGroup M] (s : Set M) : (span ℤ s).toAddSubgroup = AddSubgroup.closure s := Eq.symm <| - AddSubgroup.closure_eq_of_le _ subset_span fun x hx => - span_induction hx (fun x hx => AddSubgroup.subset_closure hx) (AddSubgroup.zero_mem _) - (fun _ _ => AddSubgroup.add_mem _) fun _ _ _ => AddSubgroup.zsmul_mem _ ‹_› _ + AddSubgroup.closure_eq_of_le _ subset_span fun _ hx => + span_induction (fun _ hx => AddSubgroup.subset_closure hx) (AddSubgroup.zero_mem _) + (fun _ _ _ _ => AddSubgroup.add_mem _) (fun _ _ _ _ => AddSubgroup.zsmul_mem _ ‹_› _) hx @[simp] theorem span_int_eq {M : Type*} [AddCommGroup M] (s : AddSubgroup M) : @@ -377,15 +383,15 @@ variable {p p'} theorem mem_sup : x ∈ p ⊔ p' ↔ ∃ y ∈ p, ∃ z ∈ p', y + z = x := ⟨fun h => by rw [← span_eq p, ← span_eq p', ← span_union] at h - refine span_induction h ?_ ?_ ?_ ?_ + refine span_induction ?_ ?_ ?_ ?_ h · rintro y (h | h) · exact ⟨y, h, 0, by simp, by simp⟩ · exact ⟨0, by simp, y, h, by simp⟩ · exact ⟨0, by simp, 0, by simp⟩ - · rintro _ _ ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ + · rintro _ _ - - ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ exact ⟨_, add_mem hy₁ hy₂, _, add_mem hz₁ hz₂, by rw [add_assoc, add_assoc, ← add_assoc y₂, ← add_assoc z₁, add_comm y₂]⟩ - · rintro a _ ⟨y, hy, z, hz, rfl⟩ + · rintro a - _ ⟨y, hy, z, hz, rfl⟩ exact ⟨_, smul_mem _ a hy, _, smul_mem _ a hz, by simp [smul_add]⟩, by rintro ⟨y, hy, z, hz, rfl⟩ exact add_mem ((le_sup_left : p ≤ p ⊔ p') hy) ((le_sup_right : p' ≤ p ⊔ p') hz)⟩ @@ -430,13 +436,13 @@ theorem nontrivial_span_singleton {x : M} (h : x ≠ 0) : Nontrivial (R ∙ x) : theorem mem_span_singleton {y : M} : (x ∈ R ∙ y) ↔ ∃ a : R, a • y = x := ⟨fun h => by - refine span_induction h ?_ ?_ ?_ ?_ + refine span_induction ?_ ?_ ?_ ?_ h · rintro y (rfl | ⟨⟨_⟩⟩) exact ⟨1, by simp⟩ · exact ⟨0, by simp⟩ - · rintro _ _ ⟨a, rfl⟩ ⟨b, rfl⟩ + · rintro _ _ - - ⟨a, rfl⟩ ⟨b, rfl⟩ exact ⟨a + b, by simp [add_smul]⟩ - · rintro a _ ⟨b, rfl⟩ + · rintro a _ - ⟨b, rfl⟩ exact ⟨a * b, by simp [smul_smul]⟩, by rintro ⟨a, y, rfl⟩; exact smul_mem _ _ (subset_span <| by simp)⟩ @@ -603,17 +609,18 @@ theorem iSup_toAddSubmonoid {ι : Sort*} (p : ι → Submodule R M) : refine le_antisymm (fun x => ?_) (iSup_le fun i => toAddSubmonoid_mono <| le_iSup _ i) simp_rw [iSup_eq_span, AddSubmonoid.iSup_eq_closure, mem_toAddSubmonoid, coe_toAddSubmonoid] intro hx - refine Submodule.span_induction hx (fun x hx => ?_) ?_ (fun x y hx hy => ?_) fun r x hx => ?_ + refine Submodule.span_induction (fun x hx => ?_) ?_ (fun x y _ _ hx hy => ?_) + (fun r x _ hx => ?_) hx · exact AddSubmonoid.subset_closure hx · exact AddSubmonoid.zero_mem _ · exact AddSubmonoid.add_mem _ hx hy - · refine AddSubmonoid.closure_induction hx ?_ ?_ ?_ + · refine AddSubmonoid.closure_induction ?_ ?_ ?_ hx · rintro x ⟨_, ⟨i, rfl⟩, hix : x ∈ p i⟩ apply AddSubmonoid.subset_closure (Set.mem_iUnion.mpr ⟨i, _⟩) exact smul_mem _ r hix · rw [smul_zero] exact AddSubmonoid.zero_mem _ - · intro x y hx hy + · intro x y _ _ hx hy rw [smul_add] exact AddSubmonoid.add_mem _ hx hy @@ -703,20 +710,20 @@ such that the element is contained in the span of the subset. -/ theorem mem_span_finite_of_mem_span {S : Set M} {x : M} (hx : x ∈ span R S) : ∃ T : Finset M, ↑T ⊆ S ∧ x ∈ span R (T : Set M) := by classical - refine span_induction hx (fun x hx => ?_) ?_ ?_ ?_ + refine span_induction (fun x hx => ?_) ?_ ?_ ?_ hx · refine ⟨{x}, ?_, ?_⟩ · rwa [Finset.coe_singleton, Set.singleton_subset_iff] · rw [Finset.coe_singleton] exact Submodule.mem_span_singleton_self x · use ∅ simp - · rintro x y ⟨X, hX, hxX⟩ ⟨Y, hY, hyY⟩ + · rintro x y - - ⟨X, hX, hxX⟩ ⟨Y, hY, hyY⟩ refine ⟨X ∪ Y, ?_, ?_⟩ · rw [Finset.coe_union] exact Set.union_subset hX hY rw [Finset.coe_union, span_union, mem_sup] exact ⟨x, hxX, y, hyY, rfl⟩ - · rintro a x ⟨T, hT, h2⟩ + · rintro a x - ⟨T, hT, h2⟩ exact ⟨T, hT, smul_mem _ _ h2⟩ end @@ -940,7 +947,6 @@ theorem span_singleton_eq_range (x : M) : (R ∙ x) = range (toSpanSingleton R M refine Iff.trans ?_ LinearMap.mem_range.symm exact mem_span_singleton --- @[simp] -- Porting note (#10618): simp can prove this theorem toSpanSingleton_one (x : M) : toSpanSingleton R M x 1 = x := one_smul _ _ diff --git a/Mathlib/LinearAlgebra/StdBasis.lean b/Mathlib/LinearAlgebra/StdBasis.lean index bd602506eb518..8896d7312a535 100644 --- a/Mathlib/LinearAlgebra/StdBasis.lean +++ b/Mathlib/LinearAlgebra/StdBasis.lean @@ -287,6 +287,26 @@ lemma piEquiv_apply_apply (ι R M : Type*) [Fintype ι] [CommSemiring R] end Module +namespace Basis +variable {ι R M : Type*} (m n : Type*) +variable [Fintype m] [Fintype n] [Semiring R] [AddCommMonoid M] [Module R M] + +/-- The standard basis of `Matrix m n M` given a basis on `M`. -/ +protected noncomputable def matrix (b : Basis ι R M) : + Basis (m × n × ι) R (Matrix m n M) := + Basis.reindex (Pi.basis fun _ : m => Pi.basis fun _ : n => b) + ((Equiv.sigmaEquivProd _ _).trans <| .prodCongr (.refl _) (Equiv.sigmaEquivProd _ _)) + |>.map (Matrix.ofLinearEquiv R) + +variable {n m} + +@[simp] +theorem matrix_apply (b : Basis ι R M) (i : m) (j : n) (k : ι) [DecidableEq m] [DecidableEq n] : + b.matrix m n (i, j, k) = Matrix.stdBasisMatrix i j (b k) := by + simp [Basis.matrix, Matrix.stdBasisMatrix_eq_of_single_single] + +end Basis + namespace Matrix variable (R : Type*) (m n : Type*) [Fintype m] [Finite n] [Semiring R] @@ -294,29 +314,12 @@ variable (R : Type*) (m n : Type*) [Fintype m] [Finite n] [Semiring R] /-- The standard basis of `Matrix m n R`. -/ noncomputable def stdBasis : Basis (m × n) R (Matrix m n R) := Basis.reindex (Pi.basis fun _ : m => Pi.basisFun R n) (Equiv.sigmaEquivProd _ _) + |>.map (ofLinearEquiv R) variable {n m} theorem stdBasis_eq_stdBasisMatrix (i : m) (j : n) [DecidableEq m] [DecidableEq n] : stdBasis R m n (i, j) = stdBasisMatrix i j (1 : R) := by - -- Porting note: `simp` fails to apply `Pi.basis_apply` - ext a b - by_cases hi : i = a <;> by_cases hj : j = b - · simp only [stdBasis, hi, hj, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply, - StdBasisMatrix.apply_same] - erw [Pi.basis_apply] - simp - · simp only [stdBasis, hi, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply, - hj, and_false, not_false_iff, StdBasisMatrix.apply_of_ne] - erw [Pi.basis_apply] - simp [hj] - · simp only [stdBasis, hj, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply, - hi, and_true, not_false_iff, StdBasisMatrix.apply_of_ne] - erw [Pi.basis_apply] - simp [hi, hj, Ne.symm hi, Pi.single_eq_of_ne] - · simp only [stdBasis, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply, - hi, hj, and_self, not_false_iff, StdBasisMatrix.apply_of_ne] - erw [Pi.basis_apply] - simp [hi, hj, Ne.symm hj, Ne.symm hi, Pi.single_eq_of_ne] + simp [stdBasis, stdBasisMatrix_eq_of_single_single] end Matrix diff --git a/Mathlib/LinearAlgebra/SymplecticGroup.lean b/Mathlib/LinearAlgebra/SymplecticGroup.lean index c638f98ae8bd9..55b9036e4c5a4 100644 --- a/Mathlib/LinearAlgebra/SymplecticGroup.lean +++ b/Mathlib/LinearAlgebra/SymplecticGroup.lean @@ -86,7 +86,6 @@ open Matrix theorem mem_iff {A : Matrix (l ⊕ l) (l ⊕ l) R} : A ∈ symplecticGroup l R ↔ A * J l R * Aᵀ = J l R := by simp [symplecticGroup] --- Porting note: Previous proof was `by infer_instance` instance coeMatrix : Coe (symplecticGroup l R) (Matrix (l ⊕ l) (l ⊕ l) R) := ⟨Subtype.val⟩ diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean index 9355d09c2992a..f24b144938533 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean @@ -288,7 +288,7 @@ theorem ι_ne_one [Nontrivial R] (x : M) : ι R x ≠ 1 := by theorem ι_range_disjoint_one : Disjoint (LinearMap.range (ι R : M →ₗ[R] TensorAlgebra R M)) (1 : Submodule R (TensorAlgebra R M)) := by - rw [Submodule.disjoint_def] + rw [Submodule.disjoint_def, Submodule.one_eq_range] rintro _ ⟨x, hx⟩ ⟨r, rfl⟩ rw [Algebra.linearMap_apply, ι_eq_algebraMap_iff] at hx rw [hx.2, map_zero] diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean index 24e2067ed86e6..dc1cb2176c883 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean @@ -65,7 +65,7 @@ instance instModuleFree [Module.Free R M] : Module.Free R (TensorAlgebra R M) := no zero-divisors. -/ instance instNoZeroDivisors [NoZeroDivisors R] [Module.Free R M] : NoZeroDivisors (TensorAlgebra R M) := - have ⟨⟨κ, b⟩⟩ := ‹Module.Free R M› + have ⟨⟨_, b⟩⟩ := ‹Module.Free R M› (equivFreeAlgebra b).toMulEquiv.noZeroDivisors end CommSemiring diff --git a/Mathlib/LinearAlgebra/TensorPower.lean b/Mathlib/LinearAlgebra/TensorPower.lean index b05bd64ae042d..cf2823fc1606a 100644 --- a/Mathlib/LinearAlgebra/TensorPower.lean +++ b/Mathlib/LinearAlgebra/TensorPower.lean @@ -197,9 +197,9 @@ theorem mul_assoc {na nb nc} (a : (⨂[R]^na) M) (b : (⨂[R]^nb) M) (c : (⨂[R -- for now we just use the default for the `gnpow` field as it's easier. instance gmonoid : GradedMonoid.GMonoid fun i => ⨂[R]^i M := { TensorPower.gMul, TensorPower.gOne with - one_mul := fun a => gradedMonoid_eq_of_cast (zero_add _) (one_mul _) - mul_one := fun a => gradedMonoid_eq_of_cast (add_zero _) (mul_one _) - mul_assoc := fun a b c => gradedMonoid_eq_of_cast (add_assoc _ _ _) (mul_assoc _ _ _) } + one_mul := fun _ => gradedMonoid_eq_of_cast (zero_add _) (one_mul _) + mul_one := fun _ => gradedMonoid_eq_of_cast (add_zero _) (mul_one _) + mul_assoc := fun _ _ _ => gradedMonoid_eq_of_cast (add_assoc _ _ _) (mul_assoc _ _ _) } /-- The canonical map from `R` to `⨂[R]^0 M` corresponding to the `algebraMap` of the tensor algebra. -/ @@ -229,10 +229,10 @@ theorem algebraMap₀_mul_algebraMap₀ (r s : R) : instance gsemiring : DirectSum.GSemiring fun i => ⨂[R]^i M := { TensorPower.gmonoid with - mul_zero := fun a => LinearMap.map_zero _ - zero_mul := fun b => LinearMap.map_zero₂ _ _ - mul_add := fun a b₁ b₂ => LinearMap.map_add _ _ _ - add_mul := fun a₁ a₂ b => LinearMap.map_add₂ _ _ _ _ + mul_zero := fun _ => LinearMap.map_zero _ + zero_mul := fun _ => LinearMap.map_zero₂ _ _ + mul_add := fun _ _ _ => LinearMap.map_add _ _ _ + add_mul := fun _ _ _ => LinearMap.map_add₂ _ _ _ _ natCast := fun n => algebraMap₀ (n : R) natCast_zero := by simp only [Nat.cast_zero, map_zero] natCast_succ := fun n => by simp only [Nat.cast_succ, map_add, algebraMap₀_one] } diff --git a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean index 98e1a776a8717..f08d4d96958bb 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Mario Carneiro -/ import Mathlib.Algebra.Module.Submodule.Bilinear import Mathlib.Algebra.Module.Equiv.Basic -import Mathlib.GroupTheory.Congruence.Basic +import Mathlib.GroupTheory.Congruence.Hom import Mathlib.Tactic.Abel import Mathlib.Tactic.SuppressCompilation @@ -526,13 +526,6 @@ theorem ext' {g h : M ⊗[R] N →ₗ[R] P} (H : ∀ x y, g (x ⊗ₜ y) = h (x TensorProduct.induction_on z (by simp_rw [LinearMap.map_zero]) H fun x y ihx ihy => by rw [g.map_add, h.map_add, ihx, ihy] -theorem ext₃ {g h : (M ⊗[R] N) ⊗[R] P →ₗ[R] Q} - (H : ∀ x y z, g (x ⊗ₜ y ⊗ₜ z) = h (x ⊗ₜ y ⊗ₜ z)) : g = h := - ext' fun x => TensorProduct.induction_on x - (fun x => by simp only [zero_tmul, map_zero]) - (fun x y => H x y) - (fun x y ihx ihy z => by rw [add_tmul, g.map_add, h.map_add, ihx, ihy]) - theorem lift.unique {g : M ⊗[R] N →ₗ[R] P} (H : ∀ x y, g (x ⊗ₜ y) = f x y) : g = lift f := ext' fun m n => by rw [H, lift.tmul] @@ -621,6 +614,8 @@ theorem ext_threefold {g h : (M ⊗[R] N) ⊗[R] P →ₗ[R] Q} ext x y z exact H x y z +@[deprecated (since := "2024-10-18")] alias ext₃ := ext_threefold + -- We'll need this one for checking the pentagon identity! theorem ext_fourfold {g h : ((M ⊗[R] N) ⊗[R] P) ⊗[R] Q →ₗ[R] S} (H : ∀ w x y z, g (w ⊗ₜ x ⊗ₜ y ⊗ₜ z) = h (w ⊗ₜ x ⊗ₜ y ⊗ₜ z)) : g = h := by diff --git a/Mathlib/LinearAlgebra/TensorProduct/DirectLimit.lean b/Mathlib/LinearAlgebra/TensorProduct/DirectLimit.lean index 76b533c78ac5c..90eb34ab76c15 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/DirectLimit.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/DirectLimit.lean @@ -96,7 +96,7 @@ noncomputable def directLimitLeft : noncomputable def directLimitRight : M ⊗[R] DirectLimit G f ≃ₗ[R] DirectLimit (M ⊗[R] G ·) (M ◁ f) := TensorProduct.comm _ _ _ ≪≫ₗ directLimitLeft f M ≪≫ₗ - Module.DirectLimit.congr (fun i ↦ TensorProduct.comm _ _ _) + Module.DirectLimit.congr (fun _ ↦ TensorProduct.comm _ _ _) (fun i j h ↦ TensorProduct.ext <| DFunLike.ext _ _ <| by aesop) @[simp] lemma directLimitRight_tmul_of {i : ι} (m : M) (g : G i) : diff --git a/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean index 64465d3ce42e3..de51f0a712aab 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean @@ -47,7 +47,7 @@ suppress_compilation open scoped TensorProduct DirectSum -variable {R ι A B : Type*} +variable {R ι : Type*} namespace TensorProduct @@ -225,8 +225,8 @@ theorem gradedMul_algebraMap (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) (r : R) ext dsimp erw [tmul_of_gradedMul_of_tmul] - rw [mul_zero, uzpow_zero, one_smul, smul_tmul'] - erw [mul_one, _root_.Algebra.smul_def, Algebra.commutes] + rw [mul_zero, uzpow_zero, one_smul, smul_tmul', + mul_one, _root_.Algebra.smul_def, Algebra.commutes] rfl theorem gradedMul_one (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) : diff --git a/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean b/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean index 18c2623b09806..2560f546b9ab3 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean @@ -184,7 +184,7 @@ theorem tmul_coe_mul_coe_tmul {j₁ i₂ : ι} (a₁ : A) (b₁ : ℬ j₁) (a (-1 : ℤˣ)^(j₁ * i₂) • ((a₁ * a₂ : A) ᵍ⊗ₜ (b₁ * b₂ : B)) := by dsimp only [mul_def, mulHom_apply, of_symm_of] dsimp [auxEquiv, tmul] - erw [decompose_coe, decompose_coe] + rw [decompose_coe, decompose_coe] simp_rw [← lof_eq_of R] rw [tmul_of_gradedMul_of_tmul] simp_rw [lof_eq_of R] diff --git a/Mathlib/LinearAlgebra/TensorProduct/Pi.lean b/Mathlib/LinearAlgebra/TensorProduct/Pi.lean index 96a279919c16c..06c4f31969cbf 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Pi.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Pi.lean @@ -64,7 +64,7 @@ def piScalarRightInv : (ι → N) →ₗ[S] N ⊗[R] (ι → R) := LinearMap.lsum S (fun _ ↦ N) S <| fun i ↦ { toFun := fun n ↦ n ⊗ₜ Pi.single i 1 map_add' := fun x y ↦ by simp [add_tmul] - map_smul' := fun s x ↦ rfl + map_smul' := fun _ _ ↦ rfl } @[simp] diff --git a/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean b/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean new file mode 100644 index 0000000000000..4ae2be8cf1b11 --- /dev/null +++ b/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean @@ -0,0 +1,241 @@ +/- +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, Jujian Zhang +-/ + +import Mathlib.LinearAlgebra.TensorProduct.Basic +import Mathlib.LinearAlgebra.Quotient.Basic +import Mathlib.LinearAlgebra.Prod +import Mathlib.RingTheory.Ideal.Operations +import Mathlib.RingTheory.Ideal.Quotient.Defs + +/-! + +# Interaction between Quotients and Tensor Products + +This file contains constructions that relate quotients and tensor products. +Let `M, N` be `R`-modules, `m ≤ M` and `n ≤ N` be an `R`-submodules and `I ≤ R` an ideal. We prove +the following isomorphisms: + +## Main results +- `TensorProduct.quotientTensorQuotientEquiv`: + `(M ⧸ m) ⊗[R] (N ⧸ n) ≃ₗ[R] (M ⊗[R] N) ⧸ (m ⊗ N ⊔ M ⊗ n)` +- `TensorProduct.quotientTensorEquiv`: + `(M ⧸ m) ⊗[R] N ≃ₗ[R] (M ⊗[R] N) ⧸ (m ⊗ N)` +- `TensorProduct.tensorQuotientEquiv`: + `M ⊗[R] (N ⧸ n) ≃ₗ[R] (M ⊗[R] N) ⧸ (M ⊗ n)` +- `TensorProduct.quotTensorEquivQuotSMul`: + `(R ⧸ I) ⊗[R] M ≃ₗ[R] M ⧸ (I • M)` +- `TensorProduct.tensorQuotEquivQuotSMul`: + `M ⊗[R] (R ⧸ I) ≃ₗ[R] M ⧸ (I • M)` + +## Tags + +Quotient, Tensor Product + +-/ + +namespace TensorProduct + +variable {R M N : Type*} [CommRing R] +variable [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + +attribute [local ext high] ext LinearMap.prod_ext + +/-- +Let `M, N` be `R`-modules, `m ≤ M` and `n ≤ N` be an `R`-submodules. Then we have a linear +isomorphism between tensor products of the quotients and the quotient of the tensor product: +`(M ⧸ m) ⊗[R] (N ⧸ n) ≃ₗ[R] (M ⊗[R] N) ⧸ (m ⊗ N ⊔ M ⊗ n)`. +-/ +noncomputable def quotientTensorQuotientEquiv (m : Submodule R M) (n : Submodule R N) : + (M ⧸ (m : Submodule R M)) ⊗[R] (N ⧸ (n : Submodule R N)) ≃ₗ[R] + (M ⊗[R] N) ⧸ + (LinearMap.range (map m.subtype LinearMap.id) ⊔ + LinearMap.range (map LinearMap.id n.subtype)) := + LinearEquiv.ofLinear + (lift <| Submodule.liftQ _ (LinearMap.flip <| Submodule.liftQ _ + ((mk R (M := M) (N := N)).flip.compr₂ (Submodule.mkQ _)) fun x hx => by + ext y + simp only [LinearMap.compr₂_apply, LinearMap.flip_apply, mk_apply, Submodule.mkQ_apply, + LinearMap.zero_apply, Submodule.Quotient.mk_eq_zero] + exact Submodule.mem_sup_right ⟨y ⊗ₜ ⟨x, hx⟩, rfl⟩) fun x hx => by + ext y + simp only [LinearMap.coe_comp, Function.comp_apply, Submodule.mkQ_apply, LinearMap.flip_apply, + Submodule.liftQ_apply, LinearMap.compr₂_apply, mk_apply, LinearMap.zero_comp, + LinearMap.zero_apply, Submodule.Quotient.mk_eq_zero] + exact Submodule.mem_sup_left ⟨⟨x, hx⟩ ⊗ₜ y, rfl⟩) + (Submodule.liftQ _ (map (Submodule.mkQ _) (Submodule.mkQ _)) fun x hx => by + rw [Submodule.mem_sup] at hx + rcases hx with ⟨_, ⟨a, rfl⟩, _, ⟨b, rfl⟩, rfl⟩ + simp only [LinearMap.mem_ker, map_add] + set f := (map m.mkQ n.mkQ) ∘ₗ (map m.subtype LinearMap.id) + set g := (map m.mkQ n.mkQ) ∘ₗ (map LinearMap.id n.subtype) + have eq : LinearMap.coprod f g = 0 := by + ext x y + · simp [f, Submodule.Quotient.mk_eq_zero _ |>.2 x.2] + · simp [g, Submodule.Quotient.mk_eq_zero _ |>.2 y.2] + exact congr($eq (a, b))) + (by ext; simp) (by ext; simp) + +@[simp] +lemma quotientTensorQuotientEquiv_apply_tmul_mk_tmul_mk + (m : Submodule R M) (n : Submodule R N) (x : M) (y : N) : + quotientTensorQuotientEquiv m n + (Submodule.Quotient.mk x ⊗ₜ[R] Submodule.Quotient.mk y) = + Submodule.Quotient.mk (x ⊗ₜ y) := rfl + +@[simp] +lemma quotientTensorQuotientEquiv_symm_apply_mk_tmul + (m : Submodule R M) (n : Submodule R N) (x : M) (y : N) : + (quotientTensorQuotientEquiv m n).symm (Submodule.Quotient.mk (x ⊗ₜ y)) = + Submodule.Quotient.mk x ⊗ₜ[R] Submodule.Quotient.mk y := rfl + +variable (N) in +/-- +Let `M, N` be `R`-modules, `m ≤ M` be an `R`-submodule. Then we have a linear isomorphism between +tensor products of the quotient and the quotient of the tensor product: +`(M ⧸ m) ⊗[R] N ≃ₗ[R] (M ⊗[R] N) ⧸ (m ⊗ N)`. +-/ +noncomputable def quotientTensorEquiv (m : Submodule R M) : + (M ⧸ (m : Submodule R M)) ⊗[R] N ≃ₗ[R] + (M ⊗[R] N) ⧸ (LinearMap.range (map m.subtype (LinearMap.id : N →ₗ[R] N))) := + congr (LinearEquiv.refl _ _) ((Submodule.quotEquivOfEqBot _ rfl).symm) ≪≫ₗ + quotientTensorQuotientEquiv (N := N) m ⊥ ≪≫ₗ + Submodule.Quotient.equiv _ _ (LinearEquiv.refl _ _) (by + simp only [Submodule.map_sup] + erw [Submodule.map_id, Submodule.map_id] + simp only [sup_eq_left] + rw [map_range_eq_span_tmul, map_range_eq_span_tmul] + aesop) + +@[simp] +lemma quotientTensorEquiv_apply_tmul_mk (m : Submodule R M) (x : M) (y : N) : + quotientTensorEquiv N m (Submodule.Quotient.mk x ⊗ₜ[R] y) = + Submodule.Quotient.mk (x ⊗ₜ y) := + rfl + +@[simp] +lemma quotientTensorEquiv_symm_apply_mk_tmul (m : Submodule R M) (x : M) (y : N) : + (quotientTensorEquiv N m).symm (Submodule.Quotient.mk (x ⊗ₜ y)) = + Submodule.Quotient.mk x ⊗ₜ[R] y := + rfl + +variable (M) in +/-- +Let `M, N` be `R`-modules, `n ≤ N` be an `R`-submodule. Then we have a linear isomorphism between +tensor products of the quotient and the quotient of the tensor product: +`M ⊗[R] (N ⧸ n) ≃ₗ[R] (M ⊗[R] N) ⧸ (M ⊗ n)`. +-/ +noncomputable def tensorQuotientEquiv (n : Submodule R N) : + M ⊗[R] (N ⧸ (n : Submodule R N)) ≃ₗ[R] + (M ⊗[R] N) ⧸ (LinearMap.range (map (LinearMap.id : M →ₗ[R] M) n.subtype)) := + congr ((Submodule.quotEquivOfEqBot _ rfl).symm) (LinearEquiv.refl _ _) ≪≫ₗ + quotientTensorQuotientEquiv (⊥ : Submodule R M) n ≪≫ₗ + Submodule.Quotient.equiv _ _ (LinearEquiv.refl _ _) (by + simp only [Submodule.map_sup] + erw [Submodule.map_id, Submodule.map_id] + simp only [sup_eq_right] + rw [map_range_eq_span_tmul, map_range_eq_span_tmul] + aesop) + +@[simp] +lemma tensorQuotientEquiv_apply_mk_tmul (n : Submodule R N) (x : M) (y : N) : + tensorQuotientEquiv M n (x ⊗ₜ[R] Submodule.Quotient.mk y) = + Submodule.Quotient.mk (x ⊗ₜ y) := + rfl + +@[simp] +lemma tensorQuotientEquiv_symm_apply_tmul_mk (n : Submodule R N) (x : M) (y : N) : + (tensorQuotientEquiv M n).symm (Submodule.Quotient.mk (x ⊗ₜ y)) = + x ⊗ₜ[R] Submodule.Quotient.mk y := + rfl + +variable (M) in +/-- Left tensoring a module with a quotient of the ring is the same as +quotienting that module by the corresponding submodule. -/ +noncomputable def quotTensorEquivQuotSMul (I : Ideal R) : + ((R ⧸ I) ⊗[R] M) ≃ₗ[R] M ⧸ (I • (⊤ : Submodule R M)) := + quotientTensorEquiv M I ≪≫ₗ + Submodule.Quotient.equiv (M := R ⊗[R] M) (N := M) (f := TensorProduct.lid R M) (hf := rfl) ≪≫ₗ + Submodule.Quotient.equiv _ _ (LinearEquiv.refl R M) (by + erw [Submodule.map_id] + rw [TensorProduct.map_range_eq_span_tmul, Submodule.map_span] + refine le_antisymm (Submodule.span_le.2 ?_) (Submodule.map₂_le.2 ?_) + · rintro _ ⟨_, ⟨r, m, rfl⟩, rfl⟩ + simp only [Submodule.coe_subtype, LinearMap.id_coe, id_eq, lid_tmul, SetLike.mem_coe] + apply Submodule.apply_mem_map₂ <;> aesop + · rintro r hr m - + simp only [Submodule.coe_subtype, LinearMap.id_coe, id_eq, Subtype.exists, exists_prop, + LinearMap.lsmul_apply] + refine Submodule.subset_span ?_ + simp only [Set.mem_image, Set.mem_setOf_eq] + exact ⟨r ⊗ₜ m, ⟨r, hr, m, rfl⟩, rfl⟩) + +variable (M) in +/-- Right tensoring a module with a quotient of the ring is the same as +quotienting that module by the corresponding submodule. -/ +noncomputable def tensorQuotEquivQuotSMul (I : Ideal R) : + (M ⊗[R] (R ⧸ I)) ≃ₗ[R] M ⧸ (I • (⊤ : Submodule R M)) := + TensorProduct.comm _ _ _ ≪≫ₗ quotTensorEquivQuotSMul M I + +@[simp] +lemma quotTensorEquivQuotSMul_mk_tmul (I : Ideal R) (r : R) (x : M) : + quotTensorEquivQuotSMul M I (Ideal.Quotient.mk I r ⊗ₜ[R] x) = + Submodule.Quotient.mk (r • x) := + (quotTensorEquivQuotSMul M I).eq_symm_apply.mp <| + Eq.trans (congrArg (· ⊗ₜ[R] x) <| + Eq.trans (congrArg (Ideal.Quotient.mk I) + (Eq.trans (smul_eq_mul R) (mul_one r))).symm <| + Submodule.Quotient.mk_smul I r 1) <| + smul_tmul r _ x + +lemma quotTensorEquivQuotSMul_comp_mkQ_rTensor (I : Ideal R) : + quotTensorEquivQuotSMul M I ∘ₗ I.mkQ.rTensor M = + (I • ⊤ : Submodule R M).mkQ ∘ₗ TensorProduct.lid R M := + TensorProduct.ext' (quotTensorEquivQuotSMul_mk_tmul I) + +@[simp] +lemma quotTensorEquivQuotSMul_symm_mk (I : Ideal R) (x : M) : + (quotTensorEquivQuotSMul M I).symm (Submodule.Quotient.mk x) = 1 ⊗ₜ[R] x := + rfl + +lemma quotTensorEquivQuotSMul_symm_comp_mkQ (I : Ideal R) : + (quotTensorEquivQuotSMul M I).symm ∘ₗ (I • ⊤ : Submodule R M).mkQ = + TensorProduct.mk R (R ⧸ I) M 1 := + LinearMap.ext (quotTensorEquivQuotSMul_symm_mk I) + +lemma quotTensorEquivQuotSMul_comp_mk (I : Ideal R) : + quotTensorEquivQuotSMul M I ∘ₗ TensorProduct.mk R (R ⧸ I) M 1 = + Submodule.mkQ (I • ⊤) := + Eq.symm <| (LinearEquiv.toLinearMap_symm_comp_eq _ _).mp <| + quotTensorEquivQuotSMul_symm_comp_mkQ I + +@[simp] +lemma tensorQuotEquivQuotSMul_tmul_mk (I : Ideal R) (x : M) (r : R) : + tensorQuotEquivQuotSMul M I (x ⊗ₜ[R] Ideal.Quotient.mk I r) = + Submodule.Quotient.mk (r • x) := + quotTensorEquivQuotSMul_mk_tmul I r x + +lemma tensorQuotEquivQuotSMul_comp_mkQ_lTensor (I : Ideal R) : + tensorQuotEquivQuotSMul M I ∘ₗ I.mkQ.lTensor M = + (I • ⊤ : Submodule R M).mkQ ∘ₗ TensorProduct.rid R M := + TensorProduct.ext' (tensorQuotEquivQuotSMul_tmul_mk I) + +@[simp] +lemma tensorQuotEquivQuotSMul_symm_mk (I : Ideal R) (x : M) : + (tensorQuotEquivQuotSMul M I).symm (Submodule.Quotient.mk x) = x ⊗ₜ[R] 1 := + rfl + +lemma tensorQuotEquivQuotSMul_symm_comp_mkQ (I : Ideal R) : + (tensorQuotEquivQuotSMul M I).symm ∘ₗ (I • ⊤ : Submodule R M).mkQ = + (TensorProduct.mk R M (R ⧸ I)).flip 1 := + LinearMap.ext (tensorQuotEquivQuotSMul_symm_mk I) + +lemma tensorQuotEquivQuotSMul_comp_mk (I : Ideal R) : + tensorQuotEquivQuotSMul M I ∘ₗ (TensorProduct.mk R M (R ⧸ I)).flip 1 = + Submodule.mkQ (I • ⊤) := + Eq.symm <| (LinearEquiv.toLinearMap_symm_comp_eq _ _).mp <| + tensorQuotEquivQuotSMul_symm_comp_mkQ I + +end TensorProduct diff --git a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean index 14d7396e79842..89591b4a9ce54 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean @@ -6,7 +6,6 @@ Authors: Antoine Chambert-Loir import Mathlib.Algebra.Exact import Mathlib.RingTheory.TensorProduct.Basic -import Mathlib.RingTheory.Ideal.Quotient /-! # Right-exactness properties of tensor product @@ -158,6 +157,13 @@ theorem LinearMap.rTensor_range : apply rTensor_surjective rw [← range_eq_top, range_rangeRestrict] +lemma LinearMap.rTensor_exact_iff_lTensor_exact : + Function.Exact (f.rTensor Q) (g.rTensor Q) ↔ + Function.Exact (f.lTensor Q) (g.lTensor Q) := + Function.Exact.iff_of_ladder_linearEquiv (e₁ := TensorProduct.comm _ _ _) + (e₂ := TensorProduct.comm _ _ _) (e₃ := TensorProduct.comm _ _ _) + (by ext; simp) (by ext; simp) + end Semiring variable {R M N P : Type*} [CommRing R] @@ -371,12 +377,8 @@ noncomputable def rTensor.equiv : include hfg hg in /-- Tensoring an exact pair on the right gives an exact pair -/ theorem rTensor_exact : Exact (rTensor Q f) (rTensor Q g) := by - rw [exact_iff, ← Submodule.ker_mkQ (p := range (rTensor Q f)), - ← rTensor.inverse_comp_rTensor Q hfg hg] - apply symm - apply ker_comp_of_ker_eq_bot - rw [ker_eq_bot] - exact (rTensor.equiv Q hfg hg).symm.injective + rw [rTensor_exact_iff_lTensor_exact] + exact lTensor_exact Q hfg hg /-- Right-exactness of tensor product (`rTensor`) -/ lemma rTensor_mkQ (N : Submodule R M) : @@ -423,84 +425,6 @@ theorem TensorProduct.mk_surjective (S) [Semiring S] [Algebra R S] rw [Algebra.algebraMap_eq_smul_one, smul_tmul] exact ⟨x • y, rfl⟩ -/-- Left tensoring a module with a quotient of the ring is the same as -quotienting that module by the corresponding submodule. -/ -noncomputable def quotTensorEquivQuotSMul (I : Ideal R) : - (R ⧸ I) ⊗[R] M ≃ₗ[R] M ⧸ (I • ⊤ : Submodule R M) := - (rTensor.equiv M (exact_subtype_mkQ I) I.mkQ_surjective).symm.trans <| - Submodule.Quotient.equiv _ _ (TensorProduct.lid R M) <| - Eq.trans (LinearMap.range_comp _ _).symm <| - Eq.trans ((Submodule.topEquiv.lTensor I).range_comp _).symm <| - Eq.symm <| Eq.trans (map₂_eq_range_lift_comp_mapIncl _ _ _) <| - congrArg _ (TensorProduct.ext' (fun _ _ => rfl)) - -/-- Right tensoring a module with a quotient of the ring is the same as -quotienting that module by the corresponding submodule. -/ -noncomputable def tensorQuotEquivQuotSMul (I : Ideal R) : - M ⊗[R] (R ⧸ I) ≃ₗ[R] M ⧸ (I • ⊤ : Submodule R M) := - TensorProduct.comm R M _ ≪≫ₗ quotTensorEquivQuotSMul M I - -variable {M} - -@[simp] -lemma quotTensorEquivQuotSMul_mk_tmul (I : Ideal R) (r : R) (x : M) : - quotTensorEquivQuotSMul M I (Ideal.Quotient.mk I r ⊗ₜ[R] x) = - Submodule.Quotient.mk (r • x) := - (quotTensorEquivQuotSMul M I).eq_symm_apply.mp <| - Eq.trans (congrArg (· ⊗ₜ[R] x) <| - Eq.trans (congrArg (Ideal.Quotient.mk I) - (Eq.trans (smul_eq_mul R) (mul_one r))).symm <| - Submodule.Quotient.mk_smul I r 1) <| - smul_tmul r _ x - -lemma quotTensorEquivQuotSMul_comp_mkQ_rTensor (I : Ideal R) : - quotTensorEquivQuotSMul M I ∘ₗ I.mkQ.rTensor M = - (I • ⊤ : Submodule R M).mkQ ∘ₗ TensorProduct.lid R M := - TensorProduct.ext' (quotTensorEquivQuotSMul_mk_tmul I) - -@[simp] -lemma quotTensorEquivQuotSMul_symm_mk (I : Ideal R) (x : M) : - (quotTensorEquivQuotSMul M I).symm (Submodule.Quotient.mk x) = 1 ⊗ₜ[R] x := - rfl - -lemma quotTensorEquivQuotSMul_symm_comp_mkQ (I : Ideal R) : - (quotTensorEquivQuotSMul M I).symm ∘ₗ (I • ⊤ : Submodule R M).mkQ = - TensorProduct.mk R (R ⧸ I) M 1 := - LinearMap.ext (quotTensorEquivQuotSMul_symm_mk I) - -lemma quotTensorEquivQuotSMul_comp_mk (I : Ideal R) : - quotTensorEquivQuotSMul M I ∘ₗ TensorProduct.mk R (R ⧸ I) M 1 = - Submodule.mkQ (I • ⊤) := - Eq.symm <| (LinearEquiv.toLinearMap_symm_comp_eq _ _).mp <| - quotTensorEquivQuotSMul_symm_comp_mkQ I - -@[simp] -lemma tensorQuotEquivQuotSMul_tmul_mk (I : Ideal R) (x : M) (r : R) : - tensorQuotEquivQuotSMul M I (x ⊗ₜ[R] Ideal.Quotient.mk I r) = - Submodule.Quotient.mk (r • x) := - quotTensorEquivQuotSMul_mk_tmul I r x - -lemma tensorQuotEquivQuotSMul_comp_mkQ_lTensor (I : Ideal R) : - tensorQuotEquivQuotSMul M I ∘ₗ I.mkQ.lTensor M = - (I • ⊤ : Submodule R M).mkQ ∘ₗ TensorProduct.rid R M := - TensorProduct.ext' (tensorQuotEquivQuotSMul_tmul_mk I) - -@[simp] -lemma tensorQuotEquivQuotSMul_symm_mk (I : Ideal R) (x : M) : - (tensorQuotEquivQuotSMul M I).symm (Submodule.Quotient.mk x) = x ⊗ₜ[R] 1 := - rfl - -lemma tensorQuotEquivQuotSMul_symm_comp_mkQ (I : Ideal R) : - (tensorQuotEquivQuotSMul M I).symm ∘ₗ (I • ⊤ : Submodule R M).mkQ = - (TensorProduct.mk R M (R ⧸ I)).flip 1 := - LinearMap.ext (tensorQuotEquivQuotSMul_symm_mk I) - -lemma tensorQuotEquivQuotSMul_comp_mk (I : Ideal R) : - tensorQuotEquivQuotSMul M I ∘ₗ (TensorProduct.mk R M (R ⧸ I)).flip 1 = - Submodule.mkQ (I • ⊤) := - Eq.symm <| (LinearEquiv.toLinearMap_symm_comp_eq _ _).mp <| - tensorQuotEquivQuotSMul_symm_comp_mkQ I - end Modules section Algebras @@ -524,7 +448,7 @@ lemma Ideal.map_includeLeft_eq (I : Ideal A) : Submodule.mem_toAddSubmonoid, Submodule.restrictScalars_mem, LinearMap.mem_range] intro hx rw [Ideal.map, ← submodule_span_eq] at hx - refine Submodule.span_induction hx ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ hx · intro x simp only [includeLeft_apply, Set.mem_image, SetLike.mem_coe] rintro ⟨y, hy, rfl⟩ @@ -532,10 +456,10 @@ lemma Ideal.map_includeLeft_eq (I : Ideal A) : rfl · use 0 simp only [map_zero] - · rintro x y ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩ + · rintro x y - - ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩ use x + y simp only [map_add] - · rintro a x ⟨x, hx, rfl⟩ + · rintro a x - ⟨x, hx, rfl⟩ induction a with | zero => use 0 @@ -592,7 +516,7 @@ lemma Ideal.map_includeRight_eq (I : Ideal B) : Submodule.mem_toAddSubmonoid, Submodule.restrictScalars_mem, LinearMap.mem_range] intro hx rw [Ideal.map, ← submodule_span_eq] at hx - refine Submodule.span_induction hx ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ hx · intro x simp only [includeRight_apply, Set.mem_image, SetLike.mem_coe] rintro ⟨y, hy, rfl⟩ @@ -600,10 +524,10 @@ lemma Ideal.map_includeRight_eq (I : Ideal B) : rfl · use 0 simp only [map_zero] - · rintro x y ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩ + · rintro x y - - ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩ use x + y simp only [map_add] - · rintro a x ⟨x, hx, rfl⟩ + · rintro a x - ⟨x, hx, rfl⟩ induction a with | zero => use 0 diff --git a/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean b/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean index 838f15025ec00..074c5389f0f01 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean @@ -121,8 +121,9 @@ theorem mulMap'_surjective : Function.Surjective (mulMap' M N) := by `i(R) ⊗[R] N →ₗ[R] N` induced by multiplication in `S`, here `i : R → S` is the structure map. This is promoted to an isomorphism of `R`-modules as `Submodule.lTensorOne`. Use that instead. -/ def lTensorOne' : (⊥ : Subalgebra R S) ⊗[R] N →ₗ[R] N := - show (1 : Submodule R S) ⊗[R] N →ₗ[R] N from - (LinearEquiv.ofEq _ _ (by rw [mulMap_range, one_mul])).toLinearMap ∘ₗ (mulMap _ N).rangeRestrict + show Subalgebra.toSubmodule ⊥ ⊗[R] N →ₗ[R] N from + (LinearEquiv.ofEq _ _ (by rw [Algebra.toSubmodule_bot, mulMap_range, one_mul])).toLinearMap ∘ₗ + (mulMap _ N).rangeRestrict variable {N} in @[simp] @@ -130,7 +131,7 @@ theorem lTensorOne'_tmul (y : R) (n : N) : N.lTensorOne' (algebraMap R _ y ⊗ₜ[R] n) = y • n := Subtype.val_injective <| by simp_rw [lTensorOne', LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, LinearEquiv.coe_ofEq_apply, LinearMap.codRestrict_apply, SetLike.val_smul, Algebra.smul_def] - exact mulMap_tmul 1 N _ _ + exact mulMap_tmul _ N _ _ variable {N} in @[simp] @@ -163,15 +164,17 @@ variable {N} in @[simp] theorem lTensorOne_symm_apply (n : N) : N.lTensorOne.symm n = 1 ⊗ₜ[R] n := rfl -theorem mulMap_one_left_eq : mulMap 1 N = N.subtype ∘ₗ N.lTensorOne.toLinearMap := +theorem mulMap_one_left_eq : + mulMap (Subalgebra.toSubmodule ⊥) N = N.subtype ∘ₗ N.lTensorOne.toLinearMap := TensorProduct.ext' fun _ _ ↦ rfl /-- If `M` is a submodule in an algebra `S` over `R`, there is the natural `R`-linear map `M ⊗[R] i(R) →ₗ[R] M` induced by multiplication in `S`, here `i : R → S` is the structure map. This is promoted to an isomorphism of `R`-modules as `Submodule.rTensorOne`. Use that instead. -/ def rTensorOne' : M ⊗[R] (⊥ : Subalgebra R S) →ₗ[R] M := - show M ⊗[R] (1 : Submodule R S) →ₗ[R] M from - (LinearEquiv.ofEq _ _ (by rw [mulMap_range, mul_one])).toLinearMap ∘ₗ (mulMap M _).rangeRestrict + show M ⊗[R] Subalgebra.toSubmodule ⊥ →ₗ[R] M from + (LinearEquiv.ofEq _ _ (by rw [Algebra.toSubmodule_bot, mulMap_range, mul_one])).toLinearMap ∘ₗ + (mulMap M _).rangeRestrict variable {M} in @[simp] @@ -180,7 +183,7 @@ theorem rTensorOne'_tmul (y : R) (m : M) : simp_rw [rTensorOne', LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, LinearEquiv.coe_ofEq_apply, LinearMap.codRestrict_apply, SetLike.val_smul] rw [Algebra.smul_def, Algebra.commutes] - exact mulMap_tmul M 1 _ _ + exact mulMap_tmul M _ _ _ variable {M} in @[simp] @@ -213,7 +216,8 @@ variable {M} in @[simp] theorem rTensorOne_symm_apply (m : M) : M.rTensorOne.symm m = m ⊗ₜ[R] 1 := rfl -theorem mulMap_one_right_eq : mulMap M 1 = M.subtype ∘ₗ M.rTensorOne.toLinearMap := +theorem mulMap_one_right_eq : + mulMap M (Subalgebra.toSubmodule ⊥) = M.subtype ∘ₗ M.rTensorOne.toLinearMap := TensorProduct.ext' fun _ _ ↦ rfl @[simp] diff --git a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean index 5ed4fbb0c5ba5..9634e23fe06da 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean @@ -489,14 +489,15 @@ lemma baseChange_span (s : Set M) : simp only [baseChange, map_coe] refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span) rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩ - apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm + apply span_induction (p := fun m' _ ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) + (hx := hm) · intro m hm exact subset_span ⟨m, hm, rfl⟩ · simp - · intro m₁ m₂ hm₁ hm₂ + · intro m₁ m₂ _ _ hm₁ hm₂ rw [tmul_add] exact Submodule.add_mem _ hm₁ hm₂ - · intro r m' hm' + · intro r m' _ hm' rw [tmul_smul, ← one_smul A ((1 : A) ⊗ₜ[R] m'), ← smul_assoc] exact smul_mem _ (r • 1) hm' diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean index 2bdc1a10ded1d..cf41e0848cfdf 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -485,6 +485,10 @@ theorem imp_forall_iff {α : Type*} {p : Prop} {q : α → Prop} : (p → ∀ x, theorem exists_swap {p : α → β → Prop} : (∃ x y, p x y) ↔ ∃ y x, p x y := ⟨fun ⟨x, y, h⟩ ↦ ⟨y, x, h⟩, fun ⟨y, x, h⟩ ↦ ⟨x, y, h⟩⟩ +theorem exists_and_exists_comm {P : α → Prop} {Q : β → Prop} : + (∃ a, P a) ∧ (∃ b, Q b) ↔ ∃ a b, P a ∧ Q b := + ⟨fun ⟨⟨a, ha⟩, ⟨b, hb⟩⟩ ↦ ⟨a, b, ⟨ha, hb⟩⟩, fun ⟨a, b, ⟨ha, hb⟩⟩ ↦ ⟨⟨a, ha⟩, ⟨b, hb⟩⟩⟩ + export Classical (not_forall) theorem not_forall_not : (¬∀ x, ¬p x) ↔ ∃ x, p x := Decidable.not_forall_not @@ -670,7 +674,7 @@ namespace Classical /-- Any prop `p` is decidable classically. A shorthand for `Classical.propDecidable`. -/ noncomputable def dec (p : Prop) : Decidable p := by infer_instance -variable {α : Sort*} {p : α → Prop} +variable {α : Sort*} /-- Any predicate `p` is decidable classically. -/ noncomputable def decPred (p : α → Prop) : DecidablePred p := by infer_instance @@ -683,7 +687,6 @@ noncomputable def decEq (α : Sort*) : DecidableEq α := by infer_instance /-- Construct a function from a default value `H0`, and a function to use if there exists a value satisfying the predicate. -/ --- @[elab_as_elim] -- FIXME noncomputable def existsCases {α C : Sort*} {p : α → Prop} (H0 : C) (H : ∀ a, p a → C) : C := if h : ∃ a, p a then H (Classical.choose h) (Classical.choose_spec h) else H0 @@ -743,7 +746,6 @@ end Classical /-- This function has the same type as `Exists.recOn`, and can be used to case on an equality, but `Exists.recOn` can only eliminate into Prop, while this version eliminates into any universe using the axiom of choice. -/ --- @[elab_as_elim] -- FIXME noncomputable def Exists.classicalRecOn {α : Sort*} {p : α → Prop} (h : ∃ a, p a) {C : Sort*} (H : ∀ a, p a → C) : C := H (Classical.choose h) (Classical.choose_spec h) diff --git a/Mathlib/Logic/Denumerable.lean b/Mathlib/Logic/Denumerable.lean index cf0e64c97bd1d..f96dccd8f839c 100644 --- a/Mathlib/Logic/Denumerable.lean +++ b/Mathlib/Logic/Denumerable.lean @@ -30,7 +30,7 @@ class Denumerable (α : Type*) extends Encodable α where /-- `decode` and `encode` are inverses. -/ decode_inv : ∀ n, ∃ a ∈ decode n, encode a = n -open Nat +open Finset Nat namespace Denumerable @@ -274,7 +274,7 @@ private def toFunAux (x : s) : ℕ := (List.range x).countP (· ∈ s) private theorem toFunAux_eq {s : Set ℕ} [DecidablePred (· ∈ s)] (x : s) : - toFunAux x = ((Finset.range x).filter (· ∈ s)).card := by + toFunAux x = #{y ∈ Finset.range x | y ∈ s} := by rw [toFunAux, List.countP_eq_length_filter] rfl @@ -288,9 +288,9 @@ private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1) | n + 1 => by have ih : toFunAux (ofNat s n) = n := right_inverse_aux n - have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp - have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) = - insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by + have h₁ : (ofNat s n : ℕ) ∉ {x ∈ range (ofNat s n) | x ∈ s} := by simp + have h₂ : {x ∈ range (succ (ofNat s n)) | x ∈ s} = + insert ↑(ofNat s n) {x ∈ range (ofNat s n) | x ∈ s} := by simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter] exact fun m => ⟨fun h => by diff --git a/Mathlib/Logic/Embedding/Basic.lean b/Mathlib/Logic/Embedding/Basic.lean index c52ae8f8e8e1d..15583697c3f5a 100644 --- a/Mathlib/Logic/Embedding/Basic.lean +++ b/Mathlib/Logic/Embedding/Basic.lean @@ -180,6 +180,15 @@ theorem setValue_eq_iff {α β} (f : α ↪ β) {a a' : α} {b : β} [∀ a', De [∀ a', Decidable (f a' = b)] : setValue f a b a' = b ↔ a' = a := (setValue f a b).injective.eq_iff' <| setValue_eq .. +lemma setValue_eq_of_ne {α β} {f : α ↪ β} {a : α} {b : β} {c : α} [∀ a', Decidable (a' = a)] + [∀ a', Decidable (f a' = b)] (hc : c ≠ a) (hb : f c ≠ b) : setValue f a b c = f c := by + simp [setValue, hc, hb] + +@[simp] +lemma setValue_right_apply_eq {α β} (f : α ↪ β) (a c : α) [∀ a', Decidable (a' = a)] + [∀ a', Decidable (f a' = f c)] : setValue f a (f c) c = f a := by + simp [setValue] + /-- Embedding into `Option α` using `some`. -/ @[simps (config := .asFn)] protected def some {α} : α ↪ Option α := diff --git a/Mathlib/Logic/Encodable/Lattice.lean b/Mathlib/Logic/Encodable/Lattice.lean index 61e01cc0053a4..039681749b576 100644 --- a/Mathlib/Logic/Encodable/Lattice.lean +++ b/Mathlib/Logic/Encodable/Lattice.lean @@ -33,8 +33,7 @@ theorem iSup_decode₂ [CompleteLattice α] (f : β → α) : theorem iUnion_decode₂ (f : β → Set α) : ⋃ (i : ℕ) (b ∈ decode₂ β i), f b = ⋃ b, f b := iSup_decode₂ f -/- Porting note: `@[elab_as_elim]` gives `unexpected eliminator resulting type`. -/ ---@[elab_as_elim] +@[elab_as_elim] theorem iUnion_decode₂_cases {f : β → Set α} {C : Set α → Prop} (H0 : C ∅) (H1 : ∀ b, C (f b)) {n} : C (⋃ b ∈ decode₂ β n, f b) := match decode₂ β n with diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean index d8c4acbd7d587..34383fc48d388 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -9,7 +9,6 @@ import Mathlib.Data.Prod.Basic import Mathlib.Data.Sigma.Basic import Mathlib.Data.Subtype import Mathlib.Data.Sum.Basic -import Mathlib.Init.Algebra.Classes import Mathlib.Logic.Equiv.Defs import Mathlib.Logic.Function.Conjugate import Mathlib.Tactic.Coe @@ -52,7 +51,7 @@ universe u v w z open Function -- Unless required to be `Type*`, all variables in this file are `Sort*` -variable {α α₁ α₂ β β₁ β₂ γ γ₁ γ₂ δ : Sort*} +variable {α α₁ α₂ β β₁ β₂ γ δ : Sort*} namespace Equiv @@ -484,7 +483,7 @@ def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] : snd.left_inv a := by dsimp only; split_ifs <;> simp [*] snd.right_inv | none => by simp - | some ⟨a, ha⟩ => dif_neg ha + | some ⟨_, ha⟩ => dif_neg ha end @@ -600,7 +599,7 @@ is naturally equivalent to the type of functions `{a // ¬ p a} → β`. -/ @[simps] def subtypePreimage : { x : α → β // x ∘ Subtype.val = x₀ } ≃ ({ a // ¬p a } → β) where toFun (x : { x : α → β // x ∘ Subtype.val = x₀ }) a := (x : α → β) a - invFun x := ⟨fun a => if h : p a then x₀ ⟨a, h⟩ else x ⟨a, h⟩, funext fun ⟨a, h⟩ => dif_pos h⟩ + invFun x := ⟨fun a => if h : p a then x₀ ⟨a, h⟩ else x ⟨a, h⟩, funext fun ⟨_, h⟩ => dif_pos h⟩ left_inv := fun ⟨x, hx⟩ => Subtype.val_injective <| funext fun a => by @@ -629,7 +628,7 @@ section /-- A family of equivalences `∀ a, β₁ a ≃ β₂ a` generates an equivalence between `∀ a, β₁ a` and `∀ a, β₂ a`. -/ def piCongrRight {β₁ β₂ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ a) : (∀ a, β₁ a) ≃ (∀ a, β₂ a) := - ⟨fun H a => F a (H a), fun H a => (F a).symm (H a), fun H => funext <| by simp, + ⟨Pi.map fun a ↦ F a, Pi.map fun a ↦ (F a).symm, fun H => funext <| by simp, fun H => funext <| by simp⟩ /-- Given `φ : α → β → Sort*`, we have an equivalence between `∀ a b, φ a b` and `∀ b a, φ a b`. @@ -817,7 +816,7 @@ section def arrowProdEquivProdArrow (α β γ : Type*) : (γ → α × β) ≃ (γ → α) × (γ → β) where toFun := fun f => (fun c => (f c).1, fun c => (f c).2) invFun := fun p c => (p.1 c, p.2 c) - left_inv := fun f => rfl + left_inv := fun _ => rfl right_inv := fun p => by cases p; rfl open Sum @@ -830,7 +829,7 @@ def sumPiEquivProdPi {ι ι'} (π : ι ⊕ ι' → Type*) : toFun f := ⟨fun i => f (inl i), fun i' => f (inr i')⟩ invFun g := Sum.rec g.1 g.2 left_inv f := by ext (i | i) <;> rfl - right_inv g := Prod.ext rfl rfl + right_inv _ := Prod.ext rfl rfl /-- The equivalence between a product of two dependent functions types and a single dependent function type. Basically a symmetric version of `Equiv.sumPiEquivProdPi`. -/ @@ -1028,7 +1027,7 @@ lemma coe_subtypeEquiv_eq_map {X Y} {p : X → Prop} {q : Y → Prop} (e : X ≃ rfl @[simp] -theorem subtypeEquiv_refl {p : α → Prop} (h : ∀ a, p a ↔ p (Equiv.refl _ a) := fun a => Iff.rfl) : +theorem subtypeEquiv_refl {p : α → Prop} (h : ∀ a, p a ↔ p (Equiv.refl _ a) := fun _ => Iff.rfl) : (Equiv.refl α).subtypeEquiv h = Equiv.refl { a : α // p a } := by ext rfl @@ -1090,7 +1089,7 @@ def subtypeSubtypeEquivSubtypeExists (p : α → Prop) (q : Subtype p → Prop) ⟨a.1, a.1.2, by rcases a with ⟨⟨a, hap⟩, haq⟩ exact haq⟩, - fun a => ⟨⟨a, a.2.fst⟩, a.2.snd⟩, fun ⟨⟨a, ha⟩, h⟩ => rfl, fun ⟨a, h₁, h₂⟩ => rfl⟩ + fun a => ⟨⟨a, a.2.fst⟩, a.2.snd⟩, fun ⟨⟨_, _⟩, _⟩ => rfl, fun ⟨_, _, _⟩ => rfl⟩ /-- A subtype of a subtype is equivalent to the subtype of elements satisfying both predicates. -/ @[simps!] @@ -1166,9 +1165,9 @@ def sigmaOptionEquivOfSome {α} (p : Option α → Type v) (h : p none → False `Sigma` type such that for all `i` we have `(f i).fst = i`. -/ def piEquivSubtypeSigma (ι) (π : ι → Type*) : (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where - toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun i => rfl⟩ + toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun _ => rfl⟩ invFun := fun f i => by rw [← f.2 i]; exact (f.1 i).2 - left_inv := fun f => funext fun i => rfl + left_inv := fun _ => funext fun _ => rfl right_inv := fun ⟨f, hf⟩ => Subtype.eq <| funext fun i => Sigma.eq (hf i).symm <| eq_of_heq <| rec_heq_of_heq _ <| by simp @@ -1211,7 +1210,7 @@ def subtypeProdEquivSigmaSubtype {α β} (p : α → β → Prop) : toFun x := ⟨x.1.1, x.1.2, x.property⟩ invFun x := ⟨⟨x.1, x.2⟩, x.2.property⟩ left_inv x := by ext <;> rfl - right_inv := fun ⟨a, b, pab⟩ => rfl + right_inv := fun ⟨_, _, _⟩ => rfl /-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α` depending on whether they satisfy a predicate `p` or not. -/ @@ -1360,11 +1359,11 @@ def subtypeQuotientEquivQuotientSubtype (p₁ : α → Prop) {s₁ : Setoid α} (h : ∀ x y : Subtype p₁, s₂.r x y ↔ s₁.r x y) : {x // p₂ x} ≃ Quotient s₂ where toFun a := Quotient.hrecOn a.1 (fun a h => ⟦⟨a, (hp₂ _).2 h⟩⟧) - (fun a b hab => hfunext (by rw [Quotient.sound hab]) fun h₁ h₂ _ => + (fun a b hab => hfunext (by rw [Quotient.sound hab]) fun _ _ _ => heq_of_eq (Quotient.sound ((h _ _).2 hab))) a.2 invFun a := - Quotient.liftOn a (fun a => (⟨⟦a.1⟧, (hp₂ _).1 a.2⟩ : { x // p₂ x })) fun a b hab => + Quotient.liftOn a (fun a => (⟨⟦a.1⟧, (hp₂ _).1 a.2⟩ : { x // p₂ x })) fun _ _ hab => Subtype.ext_val (Quotient.sound ((h _ _).1 hab)) left_inv := by exact fun ⟨a, ha⟩ => Quotient.inductionOn a (fun b hb => rfl) ha right_inv a := by exact Quotient.inductionOn a fun ⟨a, ha⟩ => rfl @@ -1372,14 +1371,14 @@ def subtypeQuotientEquivQuotientSubtype (p₁ : α → Prop) {s₁ : Setoid α} @[simp] theorem subtypeQuotientEquivQuotientSubtype_mk (p₁ : α → Prop) [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧) - (h : ∀ x y : Subtype p₁, @Setoid.r _ s₂ x y ↔ (x : α) ≈ y) + (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y) (x hx) : subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h ⟨⟦x⟧, hx⟩ = ⟦⟨x, (hp₂ _).2 hx⟩⟧ := rfl @[simp] theorem subtypeQuotientEquivQuotientSubtype_symm_mk (p₁ : α → Prop) [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧) - (h : ∀ x y : Subtype p₁, @Setoid.r _ s₂ x y ↔ (x : α) ≈ y) (x) : + (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y) (x) : (subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h).symm ⟦x⟧ = ⟨⟦x⟧, (hp₂ _).1 x.property⟩ := rfl @@ -1688,7 +1687,7 @@ theorem piCongr_symm_apply (f : ∀ b, Z b) : @[simp] theorem piCongr_apply_apply (f : ∀ a, W a) (a : α) : h₁.piCongr h₂ f (h₁ a) = h₂ a (f a) := by - simp only [piCongr, piCongrRight, trans_apply, coe_fn_mk, piCongrLeft_apply_apply] + simp only [piCongr, piCongrRight, trans_apply, coe_fn_mk, piCongrLeft_apply_apply, Pi.map_apply] end @@ -1732,16 +1731,6 @@ instance [Std.Associative f] : Std.Associative (e.arrowCongr (e.arrowCongr e) f) instance [Std.IdempotentOp f] : Std.IdempotentOp (e.arrowCongr (e.arrowCongr e) f) := (e.semiconj₂_conj f).isIdempotent_right e.surjective -set_option linter.deprecated false in -@[deprecated (since := "2024-09-11")] -instance [IsLeftCancel α₁ f] : IsLeftCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := - ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsLeftCancel.left_cancel _ f _ x y z⟩ - -set_option linter.deprecated false in -@[deprecated (since := "2024-09-11")] -instance [IsRightCancel α₁ f] : IsRightCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := - ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsRightCancel.right_cancel _ f _ x y z⟩ - end BinaryOp section ULift diff --git a/Mathlib/Logic/Equiv/Defs.lean b/Mathlib/Logic/Equiv/Defs.lean index 78cf1e5f1f2e2..2650567700550 100644 --- a/Mathlib/Logic/Equiv/Defs.lean +++ b/Mathlib/Logic/Equiv/Defs.lean @@ -534,7 +534,7 @@ def piUnique [Unique α] (β : α → Sort*) : (∀ i, β i) ≃ β default wher toFun f := f default invFun := uniqueElim left_inv f := by ext i; cases Unique.eq_default i; rfl - right_inv x := rfl + right_inv _ := rfl /-- If `α` has a unique term, then the type of function `α → β` is equivalent to `β`. -/ @[simps! (config := .asFn) apply symm_apply] @@ -591,17 +591,15 @@ def psigmaCongrRight {β₁ β₂ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ left_inv | ⟨a, b⟩ => congr_arg (PSigma.mk a) <| symm_apply_apply (F a) b right_inv | ⟨a, b⟩ => congr_arg (PSigma.mk a) <| apply_symm_apply (F a) b --- Porting note (#10618): simp can now simplify the LHS, so I have removed `@[simp]` theorem psigmaCongrRight_trans {α} {β₁ β₂ β₃ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ a) (G : ∀ a, β₂ a ≃ β₃ a) : (psigmaCongrRight F).trans (psigmaCongrRight G) = psigmaCongrRight fun a => (F a).trans (G a) := rfl --- Porting note (#10618): simp can now simplify the LHS, so I have removed `@[simp]` theorem psigmaCongrRight_symm {α} {β₁ β₂ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ a) : (psigmaCongrRight F).symm = psigmaCongrRight fun a => (F a).symm := rfl --- Porting note (#10618): simp can now prove this, so I have removed `@[simp]` +@[simp] theorem psigmaCongrRight_refl {α} {β : α → Sort*} : (psigmaCongrRight fun a => Equiv.refl (β a)) = Equiv.refl (Σ' a, β a) := rfl @@ -614,17 +612,15 @@ def sigmaCongrRight {α} {β₁ β₂ : α → Type*} (F : ∀ a, β₁ a ≃ β left_inv | ⟨a, b⟩ => congr_arg (Sigma.mk a) <| symm_apply_apply (F a) b right_inv | ⟨a, b⟩ => congr_arg (Sigma.mk a) <| apply_symm_apply (F a) b --- Porting note (#10618): simp can now simplify the LHS, so I have removed `@[simp]` theorem sigmaCongrRight_trans {α} {β₁ β₂ β₃ : α → Type*} (F : ∀ a, β₁ a ≃ β₂ a) (G : ∀ a, β₂ a ≃ β₃ a) : (sigmaCongrRight F).trans (sigmaCongrRight G) = sigmaCongrRight fun a => (F a).trans (G a) := rfl --- Porting note (#10618): simp can now simplify the LHS, so I have removed `@[simp]` theorem sigmaCongrRight_symm {α} {β₁ β₂ : α → Type*} (F : ∀ a, β₁ a ≃ β₂ a) : (sigmaCongrRight F).symm = sigmaCongrRight fun a => (F a).symm := rfl --- Porting note (#10618): simp can now prove this, so I have removed `@[simp]` +@[simp] theorem sigmaCongrRight_refl {α} {β : α → Type*} : (sigmaCongrRight fun a => Equiv.refl (β a)) = Equiv.refl (Σ a, β a) := rfl @@ -716,7 +712,7 @@ end variable {p : α → Prop} {q : β → Prop} (e : α ≃ β) protected lemma forall_congr_right : (∀ a, q (e a)) ↔ ∀ b, q b := - ⟨fun h a ↦ by simpa using h (e.symm a), fun h b ↦ h _⟩ + ⟨fun h a ↦ by simpa using h (e.symm a), fun h _ ↦ h _⟩ protected lemma forall_congr_left : (∀ a, p a) ↔ ∀ b, p (e.symm b) := e.symm.forall_congr_right.symm @@ -730,7 +726,7 @@ protected lemma forall_congr' (h : ∀ b, p (e.symm b) ↔ q b) : (∀ a, p a) e.forall_congr_left.trans (by simp [h]) protected lemma exists_congr_right : (∃ a, q (e a)) ↔ ∃ b, q b := - ⟨fun ⟨b, h⟩ ↦ ⟨_, h⟩, fun ⟨a, h⟩ ↦ ⟨e.symm a, by simpa using h⟩⟩ + ⟨fun ⟨_, h⟩ ↦ ⟨_, h⟩, fun ⟨a, h⟩ ↦ ⟨e.symm a, by simpa using h⟩⟩ protected lemma exists_congr_left : (∃ a, p a) ↔ ∃ b, p (e.symm b) := e.symm.exists_congr_right.symm @@ -844,17 +840,17 @@ namespace Quotient /-- An equivalence `e : α ≃ β` generates an equivalence between quotient spaces, if `ra a₁ a₂ ↔ rb (e a₁) (e a₂)`. -/ protected def congr {ra : Setoid α} {rb : Setoid β} (e : α ≃ β) - (eq : ∀ a₁ a₂, @Setoid.r α ra a₁ a₂ ↔ @Setoid.r β rb (e a₁) (e a₂)) : + (eq : ∀ a₁ a₂, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) : Quotient ra ≃ Quotient rb := Quot.congr e eq @[simp] theorem congr_mk {ra : Setoid α} {rb : Setoid β} (e : α ≃ β) - (eq : ∀ a₁ a₂ : α, Setoid.r a₁ a₂ ↔ Setoid.r (e a₁) (e a₂)) (a : α) : + (eq : ∀ a₁ a₂ : α, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) (a : α) : Quotient.congr e eq (Quotient.mk ra a) = Quotient.mk rb (e a) := rfl /-- Quotients are congruent on equivalences under equality of their relation. An alternative is just to use rewriting with `eq`, but then computational proofs get stuck. -/ protected def congrRight {r r' : Setoid α} - (eq : ∀ a₁ a₂, @Setoid.r α r a₁ a₂ ↔ @Setoid.r α r' a₁ a₂) : Quotient r ≃ Quotient r' := + (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : Quotient r ≃ Quotient r' := Quot.congrRight eq end Quotient diff --git a/Mathlib/Logic/Equiv/Fin.lean b/Mathlib/Logic/Equiv/Fin.lean index 3453d19eac020..7e551963a14c7 100644 --- a/Mathlib/Logic/Equiv/Fin.lean +++ b/Mathlib/Logic/Equiv/Fin.lean @@ -63,7 +63,7 @@ given by separating out the last element of the tuple. This is `Fin.snoc` as an `Equiv`. -/ @[simps] def snocEquiv (α : Fin (n + 1) → Type*) : α (last n) × (∀ i, α (castSucc i)) ≃ ∀ i, α i where - toFun f i := Fin.snoc f.2 f.1 _ + toFun f _ := Fin.snoc f.2 f.1 _ invFun f := ⟨f _, Fin.init f⟩ left_inv f := by simp right_inv f := by simp @@ -444,7 +444,7 @@ def finProdFinEquiv : Fin m × Fin n ≃ Fin (m * n) where (y.1 + n * x.1) % n = y.1 % n := Nat.add_mul_mod_self_left _ _ _ _ = y.1 := Nat.mod_eq_of_lt y.2 ) - right_inv x := Fin.eq_of_val_eq <| Nat.mod_add_div _ _ + right_inv _ := Fin.eq_of_val_eq <| Nat.mod_add_div _ _ /-- The equivalence induced by `a ↦ (a / n, a % n)` for nonzero `n`. This is like `finProdFinEquiv.symm` but with `m` infinite. @@ -454,7 +454,7 @@ def Nat.divModEquiv (n : ℕ) [NeZero n] : ℕ ≃ ℕ × Fin n where toFun a := (a / n, ↑a) invFun p := p.1 * n + ↑p.2 -- TODO: is there a canonical order of `*` and `+` here? - left_inv a := Nat.div_add_mod' _ _ + left_inv _ := Nat.div_add_mod' _ _ right_inv p := by refine Prod.ext ?_ (Fin.ext <| Nat.mul_add_mod_of_lt p.2.is_lt) dsimp only @@ -498,3 +498,12 @@ instance subsingleton_fin_zero : Subsingleton (Fin 0) := /-- `Fin 1` is a subsingleton. -/ instance subsingleton_fin_one : Subsingleton (Fin 1) := finOneEquiv.subsingleton + +/-- The natural `Equiv` between `(Fin m → α) × (Fin n → α)` and `Fin (m + n) → α`.-/ +@[simps] +def Fin.appendEquiv {α : Type*} (m n : ℕ) : + (Fin m → α) × (Fin n → α) ≃ (Fin (m + n) → α) where + toFun fg := Fin.append fg.1 fg.2 + invFun f := ⟨fun i ↦ f (Fin.castAdd n i), fun i ↦ f (Fin.natAdd m i)⟩ + left_inv fg := by simp + right_inv f := by simp [Fin.append_castAdd_natAdd] diff --git a/Mathlib/Logic/Equiv/List.lean b/Mathlib/Logic/Equiv/List.lean index 7a050c68661b5..c0753898bf0dc 100644 --- a/Mathlib/Logic/Equiv/List.lean +++ b/Mathlib/Logic/Equiv/List.lean @@ -259,11 +259,11 @@ def raise : List ℕ → ℕ → List ℕ | m :: l, n => (m + n) :: raise l (m + n) theorem lower_raise : ∀ l n, lower (raise l n) n = l - | [], n => rfl + | [], _ => rfl | m :: l, n => by rw [raise, lower, Nat.add_sub_cancel_right, lower_raise l] theorem raise_lower : ∀ {l n}, List.Sorted (· ≤ ·) (n :: l) → raise (lower l n) n = l - | [], n, _ => rfl + | [], _, _ => rfl | m :: l, n, h => by have : n ≤ m := List.rel_of_sorted_cons h _ (l.mem_cons_self _) simp [raise, lower, Nat.sub_add_cancel this, raise_lower h.of_cons] @@ -289,7 +289,7 @@ instance multiset : Denumerable (Multiset α) := raise_lower (List.sorted_cons.2 ⟨fun n _ => Nat.zero_le n, (s.map encode).sort_sorted _⟩) simp [-Multiset.map_coe, this], fun n => by - simp [-Multiset.map_coe, List.mergeSort'_eq_self _ (raise_sorted _ _), lower_raise]⟩ + simp [-Multiset.map_coe, List.mergeSort_eq_self (raise_sorted _ _), lower_raise]⟩ end Multiset @@ -309,11 +309,11 @@ def raise' : List ℕ → ℕ → List ℕ | m :: l, n => (m + n) :: raise' l (m + n + 1) theorem lower_raise' : ∀ l n, lower' (raise' l n) n = l - | [], n => rfl + | [], _ => rfl | m :: l, n => by simp [raise', lower', add_tsub_cancel_right, lower_raise'] theorem raise_lower' : ∀ {l n}, (∀ m ∈ l, n ≤ m) → List.Sorted (· < ·) l → raise' (lower' l n) n = l - | [], n, _, _ => rfl + | [], _, _, _ => rfl | m :: l, n, h₁, h₂ => by have : n ≤ m := h₁ _ (l.mem_cons_self _) simp [raise', lower', Nat.sub_add_cancel this, @@ -344,7 +344,7 @@ instance finset : Denumerable (Finset α) := raise_lower' (fun n _ => Nat.zero_le n) (Finset.sort_sorted_lt _)], fun n => by simp [-Multiset.map_coe, Finset.map, raise'Finset, Finset.sort, - List.mergeSort'_eq_self (· ≤ ·) ((raise'_sorted _ _).imp (@le_of_lt _ _)), lower_raise']⟩ + List.mergeSort_eq_self ((raise'_sorted _ _).imp (@le_of_lt _ _)), lower_raise']⟩ end Finset diff --git a/Mathlib/Logic/Equiv/PartialEquiv.lean b/Mathlib/Logic/Equiv/PartialEquiv.lean index 7d93cc552f446..0a231722f6cfa 100644 --- a/Mathlib/Logic/Equiv/PartialEquiv.lean +++ b/Mathlib/Logic/Equiv/PartialEquiv.lean @@ -236,7 +236,7 @@ def _root_.Equiv.toPartialEquivOfImageEq (e : α ≃ β) (s : Set α) (t : Set invFun := e.symm source := s target := t - map_source' x hx := h ▸ mem_image_of_mem _ hx + map_source' _ hx := h ▸ mem_image_of_mem _ hx map_target' x hx := by subst t rcases hx with ⟨x, hx, rfl⟩ @@ -316,7 +316,7 @@ def IsImage (s : Set α) (t : Set β) : Prop := namespace IsImage -variable {e} {s : Set α} {t : Set β} {x : α} {y : β} +variable {e} {s : Set α} {t : Set β} {x : α} theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s := h hx @@ -622,32 +622,32 @@ theorem inv_image_trans_target : e'.symm '' (e.trans e').target = e'.source ∩ image_trans_source e'.symm e.symm theorem trans_assoc (e'' : PartialEquiv γ δ) : (e.trans e').trans e'' = e.trans (e'.trans e'') := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [trans_source, @preimage_comp α β γ, inter_assoc]) @[simp, mfld_simps] theorem trans_refl : e.trans (PartialEquiv.refl β) = e := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [trans_source]) @[simp, mfld_simps] theorem refl_trans : (PartialEquiv.refl α).trans e = e := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source, preimage_id]) + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [trans_source, preimage_id]) theorem trans_ofSet (s : Set β) : e.trans (ofSet s) = e.restr (e ⁻¹' s) := PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) rfl theorem trans_refl_restr (s : Set β) : e.trans ((PartialEquiv.refl β).restr s) = e.restr (e ⁻¹' s) := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [trans_source]) theorem trans_refl_restr' (s : Set β) : e.trans ((PartialEquiv.refl β).restr s) = e.restr (e.source ∩ e ⁻¹' s) := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) <| by + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) <| by simp only [trans_source, restr_source, refl_source, univ_inter] rw [← inter_assoc, inter_self] theorem restr_trans (s : Set α) : (e.restr s).trans e' = (e.trans e').restr s := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) <| by + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) <| by simp [trans_source, inter_comm, inter_assoc] /-- A lemma commonly useful when `e` and `e'` are charts of a manifold. -/ @@ -843,8 +843,8 @@ variable {ι : Type*} {αi βi γi : ι → Type*} /-- The product of a family of partial equivalences, as a partial equivalence on the pi type. -/ @[simps (config := mfld_cfg) apply source target] protected def pi (ei : ∀ i, PartialEquiv (αi i) (βi i)) : PartialEquiv (∀ i, αi i) (∀ i, βi i) where - toFun f i := ei i (f i) - invFun f i := (ei i).symm (f i) + toFun := Pi.map fun i ↦ ei i + invFun := Pi.map fun i ↦ (ei i).symm source := pi univ fun i => (ei i).source target := pi univ fun i => (ei i).target map_source' _ hf i hi := (ei i).map_source (hf i hi) @@ -916,7 +916,7 @@ theorem symm_toPartialEquiv : e.symm.toPartialEquiv = e.toPartialEquiv.symm := @[simp, mfld_simps] theorem trans_toPartialEquiv : (e.trans e').toPartialEquiv = e.toPartialEquiv.trans e'.toPartialEquiv := - PartialEquiv.ext (fun x => rfl) (fun x => rfl) + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [PartialEquiv.trans_source, Equiv.toPartialEquiv]) /-- Precompose a partial equivalence with an equivalence. diff --git a/Mathlib/Logic/Equiv/Set.lean b/Mathlib/Logic/Equiv/Set.lean index 660731bfc4b8a..641faf211dc32 100644 --- a/Mathlib/Logic/Equiv/Set.lean +++ b/Mathlib/Logic/Equiv/Set.lean @@ -104,7 +104,6 @@ theorem preimage_symm_preimage {α β} (e : α ≃ β) (s : Set α) : e ⁻¹' ( theorem preimage_subset {α β} (e : α ≃ β) (s t : Set β) : e ⁻¹' s ⊆ e ⁻¹' t ↔ s ⊆ t := e.surjective.preimage_subset_preimage_iff --- Porting note (#10618): removed `simp` attribute. `simp` can prove it. theorem image_subset {α β} (e : α ≃ β) (s t : Set α) : e '' s ⊆ e '' t ↔ s ⊆ t := image_subset_image_iff e.injective @@ -149,8 +148,8 @@ def setProdEquivSigma {α β : Type*} (s : Set (α × β)) : s ≃ Σx : α, { y : β | (x, y) ∈ s } where toFun x := ⟨x.1.1, x.1.2, by simp⟩ invFun x := ⟨(x.1, x.2.1), x.2.2⟩ - left_inv := fun ⟨⟨x, y⟩, h⟩ => rfl - right_inv := fun ⟨x, y, h⟩ => rfl + left_inv := fun ⟨⟨_, _⟩, _⟩ => rfl + right_inv := fun ⟨_, _, _⟩ => rfl /-- The subtypes corresponding to equal sets are equivalent. -/ @[simps! apply] @@ -174,8 +173,8 @@ def image {α β : Type*} (e : α ≃ β) (s : Set α) : namespace Set --- Porting note: Removed attribute @[simps apply symm_apply] /-- `univ α` is equivalent to `α`. -/ +@[simps apply symm_apply] protected def univ (α) : @univ α ≃ α := ⟨Subtype.val, fun a => ⟨a, trivial⟩, fun ⟨_, _⟩ => rfl, fun _ => rfl⟩ @@ -203,25 +202,25 @@ protected def union' {α} {s t : Set α} (p : α → Prop) [DecidablePred p] (hs rcases o with (⟨x, h⟩ | ⟨x, h⟩) <;> [simp [hs _ h]; simp [ht _ h]] /-- If sets `s` and `t` are disjoint, then `s ∪ t` is equivalent to `s ⊕ t`. -/ -protected def union {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : s ∩ t ⊆ ∅) : +protected def union {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : Disjoint s t) : (s ∪ t : Set α) ≃ s ⊕ t := - Set.union' (fun x => x ∈ s) (fun _ => id) fun _ xt xs => H ⟨xs, xt⟩ + Set.union' (fun x => x ∈ s) (fun _ => id) fun _ xt xs => Set.disjoint_left.mp H xs xt -theorem union_apply_left {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : s ∩ t ⊆ ∅) +theorem union_apply_left {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : Disjoint s t) {a : (s ∪ t : Set α)} (ha : ↑a ∈ s) : Equiv.Set.union H a = Sum.inl ⟨a, ha⟩ := dif_pos ha -theorem union_apply_right {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : s ∩ t ⊆ ∅) +theorem union_apply_right {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : Disjoint s t) {a : (s ∪ t : Set α)} (ha : ↑a ∈ t) : Equiv.Set.union H a = Sum.inr ⟨a, ha⟩ := - dif_neg fun h => H ⟨h, ha⟩ + dif_neg fun h => Set.disjoint_left.mp H h ha @[simp] -theorem union_symm_apply_left {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : s ∩ t ⊆ ∅) +theorem union_symm_apply_left {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : Disjoint s t) (a : s) : (Equiv.Set.union H).symm (Sum.inl a) = ⟨a, by simp⟩ := rfl @[simp] -theorem union_symm_apply_right {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : s ∩ t ⊆ ∅) +theorem union_symm_apply_right {α} {s t : Set α} [DecidablePred fun x => x ∈ s] (H : Disjoint s t) (a : t) : (Equiv.Set.union H).symm (Sum.inr a) = ⟨a, by simp⟩ := rfl @@ -247,7 +246,7 @@ protected def insert {α} {s : Set.{u} α} [DecidablePred (· ∈ s)] {a : α} ( (insert a s : Set α) ≃ s ⊕ PUnit.{u + 1} := calc (insert a s : Set α) ≃ ↥(s ∪ {a}) := Equiv.Set.ofEq (by simp) - _ ≃ s ⊕ ({a} : Set α) := Equiv.Set.union fun x ⟨hx, _⟩ => by simp_all + _ ≃ s ⊕ ({a} : Set α) := Equiv.Set.union <| by simpa _ ≃ s ⊕ PUnit.{u + 1} := sumCongr (Equiv.refl _) (Equiv.Set.singleton _) @[simp] @@ -273,7 +272,7 @@ theorem insert_apply_right {α} {s : Set.{u} α} [DecidablePred (· ∈ s)] {a : /-- If `s : Set α` is a set with decidable membership, then `s ⊕ sᶜ` is equivalent to `α`. -/ protected def sumCompl {α} (s : Set α) [DecidablePred (· ∈ s)] : s ⊕ (sᶜ : Set α) ≃ α := calc - s ⊕ (sᶜ : Set α) ≃ ↥(s ∪ sᶜ) := (Equiv.Set.union (by simp [Set.ext_iff])).symm + s ⊕ (sᶜ : Set α) ≃ ↥(s ∪ sᶜ) := (Equiv.Set.union disjoint_compl_right).symm _ ≃ @univ α := Equiv.Set.ofEq (by simp) _ ≃ α := Equiv.Set.univ _ @@ -289,15 +288,11 @@ theorem sumCompl_apply_inr {α : Type u} (s : Set α) [DecidablePred (· ∈ s)] theorem sumCompl_symm_apply_of_mem {α : Type u} {s : Set α} [DecidablePred (· ∈ s)] {x : α} (hx : x ∈ s) : (Equiv.Set.sumCompl s).symm x = Sum.inl ⟨x, hx⟩ := by - have : ((⟨x, Or.inl hx⟩ : (s ∪ sᶜ : Set α)) : α) ∈ s := hx - rw [Equiv.Set.sumCompl] - simpa using Set.union_apply_left (by simp) this + simp [Equiv.Set.sumCompl, Equiv.Set.univ, union_apply_left, hx] theorem sumCompl_symm_apply_of_not_mem {α : Type u} {s : Set α} [DecidablePred (· ∈ s)] {x : α} (hx : x ∉ s) : (Equiv.Set.sumCompl s).symm x = Sum.inr ⟨x, hx⟩ := by - have : ((⟨x, Or.inr hx⟩ : (s ∪ sᶜ : Set α)) : α) ∈ sᶜ := hx - rw [Equiv.Set.sumCompl] - simpa using Set.union_apply_right (by simp) this + simp [Equiv.Set.sumCompl, Equiv.Set.univ, union_apply_right, hx] @[simp] theorem sumCompl_symm_apply {α : Type*} {s : Set α} [DecidablePred (· ∈ s)] {x : s} : @@ -315,7 +310,7 @@ protected def sumDiffSubset {α} {s t : Set α} (h : s ⊆ t) [DecidablePred (· s ⊕ (t \ s : Set α) ≃ t := calc s ⊕ (t \ s : Set α) ≃ (s ∪ t \ s : Set α) := - (Equiv.Set.union (by simp [inter_diff_self])).symm + (Equiv.Set.union disjoint_sdiff_self_right).symm _ ≃ t := Equiv.Set.ofEq (by simp [union_diff_self, union_eq_self_of_subset_left h]) @[simp] @@ -346,7 +341,7 @@ protected def unionSumInter {α : Type u} (s t : Set α) [DecidablePred (· ∈ (s ∪ t : Set α) ⊕ (s ∩ t : Set α) ≃ (s ∪ t \ s : Set α) ⊕ (s ∩ t : Set α) := by rw [union_diff_self] _ ≃ (s ⊕ (t \ s : Set α)) ⊕ (s ∩ t : Set α) := - sumCongr (Set.union <| subset_empty_iff.2 (inter_diff_self _ _)) (Equiv.refl _) + sumCongr (Set.union disjoint_sdiff_self_right) (Equiv.refl _) _ ≃ s ⊕ ((t \ s : Set α) ⊕ (s ∩ t : Set α)) := sumAssoc _ _ _ _ ≃ s ⊕ (t \ s ∪ s ∩ t : Set α) := sumCongr (Equiv.refl _) @@ -364,7 +359,7 @@ protected def compl {α : Type u} {β : Type v} {s : Set α} {t : Set β} [Decid [DecidablePred (· ∈ t)] (e₀ : s ≃ t) : { e : α ≃ β // ∀ x : s, e x = e₀ x } ≃ ((sᶜ : Set α) ≃ (tᶜ : Set β)) where toFun e := - subtypeEquiv e fun a => + subtypeEquiv e fun _ => not_congr <| Iff.symm <| MapsTo.mem_iff (mapsTo_iff_exists_map_subtype.2 ⟨e₀, e.2⟩) @@ -478,7 +473,7 @@ def rangeInl (α β : Type*) : Set.range (Sum.inl : α → α ⊕ β) ≃ α whe | ⟨.inr _, h⟩ => False.elim <| by rcases h with ⟨x, h'⟩; cases h' invFun x := ⟨.inl x, mem_range_self _⟩ left_inv := fun ⟨_, _, rfl⟩ => rfl - right_inv x := rfl + right_inv _ := rfl @[simp] lemma rangeInl_apply_inl {α : Type*} (β : Type*) (x : α) : (rangeInl α β) ⟨.inl x, mem_range_self _⟩ = x := @@ -492,7 +487,7 @@ def rangeInr (α β : Type*) : Set.range (Sum.inr : β → α ⊕ β) ≃ β whe | ⟨.inr x, _⟩ => x invFun x := ⟨.inr x, mem_range_self _⟩ left_inv := fun ⟨_, _, rfl⟩ => rfl - right_inv x := rfl + right_inv _ := rfl @[simp] lemma rangeInr_apply_inr (α : Type*) {β : Type*} (x : β) : (rangeInr α β) ⟨.inr x, mem_range_self _⟩ = x := @@ -554,7 +549,7 @@ theorem self_comp_ofInjective_symm {α β} {f : α → β} (hf : Injective f) : theorem ofLeftInverse_eq_ofInjective {α β : Type*} (f : α → β) (f_inv : Nonempty α → β → α) (hf : ∀ h : Nonempty α, LeftInverse (f_inv h) f) : ofLeftInverse f f_inv hf = - ofInjective f ((isEmpty_or_nonempty α).elim (fun h _ _ _ => Subsingleton.elim _ _) + ofInjective f ((isEmpty_or_nonempty α).elim (fun _ _ _ _ => Subsingleton.elim _ _) (fun h => (hf h).injective)) := by ext simp diff --git a/Mathlib/Logic/Equiv/TransferInstance.lean b/Mathlib/Logic/Equiv/TransferInstance.lean index f4afabe33c38e..e1e5ce7366f08 100644 --- a/Mathlib/Logic/Equiv/TransferInstance.lean +++ b/Mathlib/Logic/Equiv/TransferInstance.lean @@ -133,7 +133,7 @@ on `β` back along `e`. -/ the additive structure on `α` is the one obtained by transporting an additive structure on `β` back along `e`."] def mulEquiv (e : α ≃ β) [Mul β] : - let mul := Equiv.mul e + let _ := Equiv.mul e α ≃* β := by intros exact @@ -343,7 +343,7 @@ protected abbrev addGroupWithOne [AddGroupWithOne β] : AddGroupWithOne α := e.addGroup with intCast := fun n => e.symm n intCast_ofNat := fun n => by simp only [Int.cast_natCast]; rfl - intCast_negSucc := fun n => + intCast_negSucc := fun _ => congr_arg e.symm <| (Int.cast_negSucc _).trans <| congr_arg _ (e.apply_symm_apply _).symm } noncomputable instance [Small.{v} α] [AddGroupWithOne α] : AddGroupWithOne (Shrink.{v} α) := @@ -565,7 +565,7 @@ variable [Semiring R] /-- Transfer `Module` across an `Equiv` -/ protected abbrev module (e : α ≃ β) [AddCommMonoid β] : - let addCommMonoid := Equiv.addCommMonoid e + let _ := Equiv.addCommMonoid e ∀ [Module R β], Module R α := by intros exact @@ -608,7 +608,7 @@ variable [CommSemiring R] /-- Transfer `Algebra` across an `Equiv` -/ protected abbrev algebra (e : α ≃ β) [Semiring β] : - let semiring := Equiv.semiring e + let _ := Equiv.semiring e ∀ [Algebra R β], Algebra R α := by intros letI : Module R α := e.module R @@ -621,8 +621,8 @@ protected abbrev algebra (e : α ≃ β) [Semiring β] : simp only [apply_symm_apply, Algebra.mul_smul_comm] lemma algebraMap_def (e : α ≃ β) [Semiring β] [Algebra R β] (r : R) : - let semiring := Equiv.semiring e - let algebra := Equiv.algebra R e + let _ := Equiv.semiring e + let _ := Equiv.algebra R e (algebraMap R α) r = e.symm ((algebraMap R β) r) := by intros simp only [Algebra.algebraMap_eq_smul_one] diff --git a/Mathlib/Logic/Function/Basic.lean b/Mathlib/Logic/Function/Basic.lean index 21435518020b1..58b832fa43354 100644 --- a/Mathlib/Logic/Function/Basic.lean +++ b/Mathlib/Logic/Function/Basic.lean @@ -33,7 +33,7 @@ theorem eval_apply {β : α → Sort*} (x : α) (f : ∀ x, β x) : eval x f = f theorem const_def {y : β} : (fun _ : α ↦ y) = const α y := rfl -theorem const_injective [Nonempty α] : Injective (const α : β → α → β) := fun y₁ y₂ h ↦ +theorem const_injective [Nonempty α] : Injective (const α : β → α → β) := fun _ _ h ↦ let ⟨x⟩ := ‹Nonempty α› congr_fun h x @@ -65,6 +65,11 @@ lemma funext_iff_of_subsingleton [Subsingleton α] {g : α → β} (x y : α) : · rwa [Subsingleton.elim x z, Subsingleton.elim y z] at h · rw [h, Subsingleton.elim x y] +theorem swap_lt {α} [Preorder α] : swap (· < · : α → α → _) = (· > ·) := rfl +theorem swap_le {α} [Preorder α] : swap (· ≤ · : α → α → _) = (· ≥ ·) := rfl +theorem swap_gt {α} [Preorder α] : swap (· > · : α → α → _) = (· < ·) := rfl +theorem swap_ge {α} [Preorder α] : swap (· ≥ · : α → α → _) = (· ≤ ·) := rfl + protected theorem Bijective.injective {f : α → β} (hf : Bijective f) : Injective f := hf.1 protected theorem Bijective.surjective {f : α → β} (hf : Bijective f) : Surjective f := hf.2 @@ -118,10 +123,15 @@ theorem Injective.of_comp_iff' (f : α → β) {g : γ → α} (hg : Bijective g Injective (f ∘ g) ↔ Injective f := ⟨fun I ↦ I.of_comp_right hg.2, fun h ↦ h.comp hg.injective⟩ +theorem Injective.piMap {ι : Sort*} {α β : ι → Sort*} {f : ∀ i, α i → β i} + (hf : ∀ i, Injective (f i)) : Injective (Pi.map f) := fun _ _ h ↦ + funext fun i ↦ hf i <| congrFun h _ + +@[deprecated (since := "2024-10-06")] alias injective_pi_map := Injective.piMap + /-- Composition by an injective function on the left is itself injective. -/ -theorem Injective.comp_left {g : β → γ} (hg : Function.Injective g) : - Function.Injective (g ∘ · : (α → β) → α → γ) := - fun _ _ hgf ↦ funext fun i ↦ hg <| (congr_fun hgf i : _) +theorem Injective.comp_left {g : β → γ} (hg : Injective g) : Injective (g ∘ · : (α → β) → α → γ) := + .piMap fun _ ↦ hg theorem injective_of_subsingleton [Subsingleton α] (f : α → β) : Injective f := fun _ _ _ ↦ Subsingleton.elim _ _ @@ -359,7 +369,7 @@ end section InvFun -variable {α β : Sort*} [Nonempty α] {f : α → β} {a : α} {b : β} +variable {α β : Sort*} [Nonempty α] {f : α → β} {b : β} attribute [local instance] Classical.propDecidable @@ -442,10 +452,22 @@ theorem surjective_to_subsingleton [na : Nonempty α] [Subsingleton β] (f : α Surjective f := fun _ ↦ let ⟨a⟩ := na; ⟨a, Subsingleton.elim _ _⟩ +theorem Surjective.piMap {ι : Sort*} {α β : ι → Sort*} {f : ∀ i, α i → β i} + (hf : ∀ i, Surjective (f i)) : Surjective (Pi.map f) := fun g ↦ + ⟨fun i ↦ surjInv (hf i) (g i), funext fun _ ↦ rightInverse_surjInv _ _⟩ + +@[deprecated (since := "2024-10-06")] alias surjective_pi_map := Surjective.piMap + /-- Composition by a surjective function on the left is itself surjective. -/ theorem Surjective.comp_left {g : β → γ} (hg : Surjective g) : - Surjective (g ∘ · : (α → β) → α → γ) := fun f ↦ - ⟨surjInv hg ∘ f, funext fun _ ↦ rightInverse_surjInv _ _⟩ + Surjective (g ∘ · : (α → β) → α → γ) := + .piMap fun _ ↦ hg + +theorem Bijective.piMap {ι : Sort*} {α β : ι → Sort*} {f : ∀ i, α i → β i} + (hf : ∀ i, Bijective (f i)) : Bijective (Pi.map f) := + ⟨.piMap fun i ↦ (hf i).1, .piMap fun i ↦ (hf i).2⟩ + +@[deprecated (since := "2024-10-06")] alias bijective_pi_map := Bijective.piMap /-- Composition by a bijective function on the left is itself bijective. -/ theorem Bijective.comp_left {g : β → γ} (hg : Bijective g) : @@ -457,7 +479,7 @@ end SurjInv section Update variable {α : Sort u} {β : α → Sort v} {α' : Sort w} [DecidableEq α] - {f g : (a : α) → β a} {a : α} {b : β a} + {f : (a : α) → β a} {a : α} {b : β a} /-- Replacing the value of a function at a given point by a given value. -/ @@ -822,13 +844,13 @@ protected theorem uncurry {α β γ : Type*} {f : α → β → γ} (hf : Inject fun ⟨_, _⟩ ⟨_, _⟩ h ↦ (hf h).elim (congr_arg₂ _) /-- As a map from the left argument to a unary function, `f` is injective. -/ -theorem left' (hf : Injective2 f) [Nonempty β] : Function.Injective f := fun a₁ a₂ h ↦ +theorem left' (hf : Injective2 f) [Nonempty β] : Function.Injective f := fun _ _ h ↦ let ⟨b⟩ := ‹Nonempty β› hf.left b <| (congr_fun h b : _) /-- As a map from the right argument to a unary function, `f` is injective. -/ theorem right' (hf : Injective2 f) [Nonempty α] : Function.Injective fun b a ↦ f a b := - fun b₁ b₂ h ↦ + fun _ _ h ↦ let ⟨a⟩ := ‹Nonempty α› hf.right a <| (congr_fun h a : _) @@ -876,7 +898,7 @@ lemma forall_existsUnique_iff {r : α → β → Prop} : if and only if it is `(f · = ·)` for some function `f`. -/ lemma forall_existsUnique_iff' {r : α → β → Prop} : (∀ a, ∃! b, r a b) ↔ ∃ f : α → β, r = (f · = ·) := by - simp [forall_existsUnique_iff, Function.funext_iff] + simp [forall_existsUnique_iff, funext_iff] /-- A symmetric relation `r : α → α → Prop` is "function-like" (for each `a` there exists a unique `b` such that `r a b`) diff --git a/Mathlib/Logic/Function/Defs.lean b/Mathlib/Logic/Function/Defs.lean index 78f83b38c66c0..0d0d15994a4f7 100644 --- a/Mathlib/Logic/Function/Defs.lean +++ b/Mathlib/Logic/Function/Defs.lean @@ -21,8 +21,6 @@ namespace Function -- Porting note: fix the universe of `ζ`, it used to be `u₁` variable {α : Sort u₁} {β : Sort u₂} {φ : Sort u₃} {δ : Sort u₄} {ζ : Sort u₅} -attribute [eqns comp_def] comp - lemma flip_def {f : α → β → φ} : flip f = fun b a => f a b := rfl #adaptation_note /-- nightly-2024-03-16 @@ -203,3 +201,16 @@ protected theorem RightInverse.id {g : β → α} {f : α → β} (h : RightInve def IsFixedPt (f : α → α) (x : α) := f x = x end Function + +namespace Pi + +variable {ι : Sort*} {α β : ι → Sort*} + +/-- Sends a dependent function `a : ∀ i, α i` to a dependent function `Pi.map f a : ∀ i, β i` +by applying `f i` to `i`-th component. -/ +protected def map (f : ∀ i, α i → β i) : (∀ i, α i) → (∀ i, β i) := fun a i ↦ f i (a i) + +@[simp] +lemma map_apply (f : ∀ i, α i → β i) (a : ∀ i, α i) (i : ι) : Pi.map f a i = f i (a i) := rfl + +end Pi diff --git a/Mathlib/Logic/OpClass.lean b/Mathlib/Logic/OpClass.lean index 2f65fe0b3d85e..6427c0f587784 100644 --- a/Mathlib/Logic/OpClass.lean +++ b/Mathlib/Logic/OpClass.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ +import Mathlib.Init + /-! # Typeclasses for commuting heterogeneous operations diff --git a/Mathlib/Logic/Pairwise.lean b/Mathlib/Logic/Pairwise.lean index 26dd58b7b3c9e..13ae772203bbe 100644 --- a/Mathlib/Logic/Pairwise.lean +++ b/Mathlib/Logic/Pairwise.lean @@ -21,11 +21,11 @@ This file defines pairwise relations. open Set Function -variable {α β γ ι ι' : Type*} {r p q : α → α → Prop} +variable {α β ι : Type*} {r p : α → α → Prop} section Pairwise -variable {f g : ι → α} {s t u : Set α} {a b : α} +variable {f : ι → α} {s : Set α} {a b : α} /-- A relation `r` holds pairwise if `r i j` for all `i ≠ j`. -/ def Pairwise (r : α → α → Prop) := diff --git a/Mathlib/Logic/Relation.lean b/Mathlib/Logic/Relation.lean index bbe9ad200f0ca..93afac58af709 100644 --- a/Mathlib/Logic/Relation.lean +++ b/Mathlib/Logic/Relation.lean @@ -213,7 +213,7 @@ instance [Decidable (∃ a b, r a b ∧ f a = c ∧ g b = d)] : Decidable (Relat end Map -variable {r : α → α → Prop} {a b c d : α} +variable {r : α → α → Prop} {a b c : α} /-- `ReflTransGen r`: reflexive transitive closure of `r` -/ @[mk_iff ReflTransGen.cases_tail_iff] @@ -245,7 +245,7 @@ namespace ReflGen theorem to_reflTransGen : ∀ {a b}, ReflGen r a b → ReflTransGen r a b | a, _, refl => by rfl - | a, b, single h => ReflTransGen.tail ReflTransGen.refl h + | _, _, single h => ReflTransGen.tail ReflTransGen.refl h theorem mono {p : α → α → Prop} (hp : ∀ a b, r a b → p a b) : ∀ {a b}, ReflGen r a b → ReflGen p a b | a, _, ReflGen.refl => by rfl diff --git a/Mathlib/Logic/Unique.lean b/Mathlib/Logic/Unique.lean index 678d68e2ff016..5aad9af23a014 100644 --- a/Mathlib/Logic/Unique.lean +++ b/Mathlib/Logic/Unique.lean @@ -141,10 +141,14 @@ abbrev mk' (α : Sort u) [h₁ : Inhabited α] [Subsingleton α] : Unique α := end Unique +theorem nonempty_unique (α : Sort u) [Subsingleton α] [Nonempty α] : Nonempty (Unique α) := by + inhabit α + exact ⟨Unique.mk' α⟩ + theorem unique_iff_subsingleton_and_nonempty (α : Sort u) : Nonempty (Unique α) ↔ Subsingleton α ∧ Nonempty α := ⟨fun ⟨u⟩ ↦ by constructor <;> exact inferInstance, - fun ⟨hs, hn⟩ ↦ ⟨by inhabit α; exact Unique.mk' α⟩⟩ + fun ⟨hs, hn⟩ ↦ nonempty_unique α⟩ variable {α : Sort*} diff --git a/Mathlib/MeasureTheory/Category/MeasCat.lean b/Mathlib/MeasureTheory/Category/MeasCat.lean index 02453ff552ced..0ea23b5368bf1 100644 --- a/Mathlib/MeasureTheory/Category/MeasCat.lean +++ b/Mathlib/MeasureTheory/Category/MeasCat.lean @@ -106,7 +106,7 @@ nicely under the monad operations. -/ def Integral : Giry.Algebra where A := MeasCat.of ℝ≥0∞ a := ⟨fun m : MeasureTheory.Measure ℝ≥0∞ ↦ ∫⁻ x, x ∂m, Measure.measurable_lintegral measurable_id⟩ - unit := Subtype.eq <| funext fun r : ℝ≥0∞ => lintegral_dirac' _ measurable_id + unit := Subtype.eq <| funext fun _ : ℝ≥0∞ => lintegral_dirac' _ measurable_id assoc := Subtype.eq <| funext fun μ : MeasureTheory.Measure (MeasureTheory.Measure ℝ≥0∞) => show ∫⁻ x, x ∂μ.join = ∫⁻ x, x ∂Measure.map (fun m => ∫⁻ x, x ∂m) μ by rw [Measure.lintegral_join, lintegral_map] <;> diff --git a/Mathlib/MeasureTheory/Constructions/AddChar.lean b/Mathlib/MeasureTheory/Constructions/AddChar.lean new file mode 100644 index 0000000000000..acc12ca8fcb9c --- /dev/null +++ b/Mathlib/MeasureTheory/Constructions/AddChar.lean @@ -0,0 +1,27 @@ +/- +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.AddChar +import Mathlib.MeasureTheory.MeasurableSpace.Defs + +/-! +# Measurable space instance for additive characters + +This file endows `AddChar A M` with the discrete measurable space structure whenever `A` and `M` +are themselves discrete measurable spaces. + +## TODO + +Give the definition in the correct generality. +-/ + +namespace AddChar +variable {A M : Type*} [AddMonoid A] [Monoid M] + [MeasurableSpace A] [DiscreteMeasurableSpace A] [MeasurableSpace M] [DiscreteMeasurableSpace M] + +instance instMeasurableSpace : MeasurableSpace (AddChar A M) := ⊤ +instance instDiscreteMeasurableSpace : DiscreteMeasurableSpace (AddChar A M) := ⟨fun _ ↦ trivial⟩ + +end AddChar diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index b7ac515ab27d0..c0ef45bc72809 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Yury Kudryashov -/ import Mathlib.MeasureTheory.Group.Arithmetic -import Mathlib.Topology.GDelta +import Mathlib.Topology.GDelta.UniformSpace import Mathlib.Topology.Instances.EReal import Mathlib.Topology.Instances.Rat @@ -266,7 +266,7 @@ theorem IsCompact.nullMeasurableSet [T2Space α] {μ} (h : IsCompact s) : NullMe then they can't be separated by a Borel measurable set. -/ theorem Inseparable.mem_measurableSet_iff {x y : γ} (h : Inseparable x y) {s : Set γ} (hs : MeasurableSet s) : x ∈ s ↔ y ∈ s := - hs.induction_on_open (C := fun s ↦ (x ∈ s ↔ y ∈ s)) (fun _ ↦ h.mem_open_iff) (fun s _ ↦ Iff.not) + hs.induction_on_open (C := fun s ↦ (x ∈ s ↔ y ∈ s)) (fun _ ↦ h.mem_open_iff) (fun _ _ ↦ Iff.not) fun _ _ _ h ↦ by simp [h] /-- If `K` is a compact set in an R₁ space and `s ⊇ K` is a Borel measurable superset, @@ -472,9 +472,12 @@ is ae-measurable. -/ theorem Continuous.aemeasurable {f : α → γ} (h : Continuous f) {μ : Measure α} : AEMeasurable f μ := h.measurable.aemeasurable -theorem ClosedEmbedding.measurable {f : α → γ} (hf : ClosedEmbedding f) : Measurable f := +theorem IsClosedEmbedding.measurable {f : α → γ} (hf : IsClosedEmbedding f) : Measurable f := hf.continuous.measurable +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.measurable := IsClosedEmbedding.measurable + /-- If a function is defined piecewise in terms of functions which are continuous on their respective pieces, then it is measurable. -/ theorem ContinuousOn.measurable_piecewise {f g : α → γ} {s : Set α} [∀ j : α, Decidable (j ∈ s)] @@ -613,32 +616,41 @@ instance Prod.borelSpace [SecondCountableTopologyEither α β] : source space is also a Borel space. -/ lemma MeasurableEmbedding.borelSpace {α β : Type*} [MeasurableSpace α] [TopologicalSpace α] [MeasurableSpace β] [TopologicalSpace β] [hβ : BorelSpace β] {e : α → β} - (h'e : MeasurableEmbedding e) (h''e : Inducing e) : + (h'e : MeasurableEmbedding e) (h''e : IsInducing e) : BorelSpace α := by constructor have : MeasurableSpace.comap e (borel β) = ‹_› := by simpa [hβ.measurable_eq] using h'e.comap_eq - rw [← this, ← borel_comap, h''e.induced] + rw [← this, ← borel_comap, h''e.eq_induced] instance _root_.ULift.instBorelSpace : BorelSpace (ULift α) := - MeasurableEquiv.ulift.measurableEmbedding.borelSpace Homeomorph.ulift.inducing + MeasurableEquiv.ulift.measurableEmbedding.borelSpace Homeomorph.ulift.isInducing instance DiscreteMeasurableSpace.toBorelSpace {α : Type*} [TopologicalSpace α] [DiscreteTopology α] [MeasurableSpace α] [DiscreteMeasurableSpace α] : BorelSpace α := by constructor; ext; simp [MeasurableSpace.measurableSet_generateFrom, MeasurableSet.of_discrete] -protected theorem Embedding.measurableEmbedding {f : α → β} (h₁ : Embedding f) +protected theorem IsEmbedding.measurableEmbedding {f : α → β} (h₁ : IsEmbedding f) (h₂ : MeasurableSet (range f)) : MeasurableEmbedding f := show MeasurableEmbedding - (((↑) : range f → β) ∘ (Homeomorph.ofEmbedding f h₁).toMeasurableEquiv) from + (((↑) : range f → β) ∘ (Homeomorph.ofIsEmbedding f h₁).toMeasurableEquiv) from (MeasurableEmbedding.subtype_coe h₂).comp (MeasurableEquiv.measurableEmbedding _) -protected theorem ClosedEmbedding.measurableEmbedding {f : α → β} (h : ClosedEmbedding f) : - MeasurableEmbedding f := - h.toEmbedding.measurableEmbedding h.isClosed_range.measurableSet +@[deprecated (since := "2024-10-26")] +alias Embedding.measurableEmbedding := IsEmbedding.measurableEmbedding + +protected theorem IsClosedEmbedding.measurableEmbedding {f : α → β} + (h : IsClosedEmbedding f) : MeasurableEmbedding f := + h.isEmbedding.measurableEmbedding h.isClosed_range.measurableSet -protected theorem OpenEmbedding.measurableEmbedding {f : α → β} (h : OpenEmbedding f) : +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.measurableEmbedding := IsClosedEmbedding.measurableEmbedding + +protected theorem IsOpenEmbedding.measurableEmbedding {f : α → β} (h : IsOpenEmbedding f) : MeasurableEmbedding f := - h.toEmbedding.measurableEmbedding h.isOpen_range.measurableSet + h.isEmbedding.measurableEmbedding h.isOpen_range.measurableSet + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.measurableEmbedding := IsOpenEmbedding.measurableEmbedding instance Empty.borelSpace : BorelSpace Empty := ⟨borel_eq_top_of_discrete.symm⟩ diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/ContinuousLinearMap.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/ContinuousLinearMap.lean index 32e8e945358ec..c32b095c05312 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/ContinuousLinearMap.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/ContinuousLinearMap.lean @@ -90,10 +90,10 @@ variable [BorelSpace 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 theorem measurable_smul_const {f : α → 𝕜} {c : E} (hc : c ≠ 0) : (Measurable fun x => f x • c) ↔ Measurable f := - (closedEmbedding_smul_left hc).measurableEmbedding.measurable_comp_iff + (isClosedEmbedding_smul_left hc).measurableEmbedding.measurable_comp_iff theorem aemeasurable_smul_const {f : α → 𝕜} {μ : Measure α} {c : E} (hc : c ≠ 0) : AEMeasurable (fun x => f x • c) μ ↔ AEMeasurable f μ := - (closedEmbedding_smul_left hc).measurableEmbedding.aemeasurable_comp_iff + (isClosedEmbedding_smul_left hc).measurableEmbedding.aemeasurable_comp_iff end NormedSpace diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean index 2a7e7bc08abc6..595bdb4902a33 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean @@ -193,19 +193,19 @@ theorem tendsto_measure_cthickening_of_isCompact [MetricSpace α] [MeasurableSpa the borel sets of some second countable t4 topology (i.e. a separable metrizable one). -/ theorem exists_borelSpace_of_countablyGenerated_of_separatesPoints (α : Type*) [m : MeasurableSpace α] [CountablyGenerated α] [SeparatesPoints α] : - ∃ τ : TopologicalSpace α, SecondCountableTopology α ∧ T4Space α ∧ BorelSpace α := by + ∃ _ : TopologicalSpace α, SecondCountableTopology α ∧ T4Space α ∧ BorelSpace α := by rcases measurableEquiv_nat_bool_of_countablyGenerated α with ⟨s, ⟨f⟩⟩ letI := induced f inferInstance - let F := f.toEquiv.toHomeomorphOfInducing <| inducing_induced _ + let F := f.toEquiv.toHomeomorphOfIsInducing <| .induced _ exact ⟨inferInstance, F.secondCountableTopology, F.symm.t4Space, - MeasurableEmbedding.borelSpace f.measurableEmbedding F.inducing⟩ + f.measurableEmbedding.borelSpace F.isInducing⟩ /-- If a measurable space on `α` is countably generated and separates points, there is some second countable t4 topology on `α` (i.e. a separable metrizable one) for which every open set is measurable. -/ theorem exists_opensMeasurableSpace_of_countablySeparated (α : Type*) [m : MeasurableSpace α] [CountablySeparated α] : - ∃ τ : TopologicalSpace α, SecondCountableTopology α ∧ T4Space α ∧ OpensMeasurableSpace α := by + ∃ _ : TopologicalSpace α, SecondCountableTopology α ∧ T4Space α ∧ OpensMeasurableSpace α := by rcases exists_countablyGenerated_le_of_countablySeparated α with ⟨m', _, _, m'le⟩ rcases exists_borelSpace_of_countablyGenerated_of_separatesPoints (m := m') with ⟨τ, _, _, τm'⟩ exact ⟨τ, ‹_›, ‹_›, @OpensMeasurableSpace.mk _ _ m (τm'.measurable_eq.symm.le.trans m'le)⟩ diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean index 4bd14a8a98d53..c52471a68104f 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean @@ -27,10 +27,10 @@ import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic intervals of the given kind. * `UpperSemicontinuous.measurable`, `LowerSemicontinuous.measurable`: Semicontinuous functions are measurable. -* `measurable_iSup`, `measurable_iInf`, `measurable_sSup`, `measurable_sInf`: +* `Measurable.iSup`, `Measurable.iInf`, `Measurable.sSup`, `Measurable.sInf`: Countable supremums and infimums of measurable functions to conditionally complete linear orders are measurable. -* `measurable_liminf`, `measurable_limsup`: +* `Measurable.liminf`, `Measurable.limsup`: Countable liminfs and limsups of measurable functions to conditionally complete linear orders are measurable. @@ -94,8 +94,8 @@ end OrderTopology section Orders -variable [TopologicalSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] -variable [MeasurableSpace δ] +variable [TopologicalSpace α] {mα : MeasurableSpace α} [OpensMeasurableSpace α] +variable {mδ : MeasurableSpace δ} section Preorder @@ -299,7 +299,7 @@ theorem Dense.borel_eq_generateFrom_Ico_mem {α : Type*} [TopologicalSpace α] [ [OrderTopology α] [SecondCountableTopology α] [DenselyOrdered α] [NoMinOrder α] {s : Set α} (hd : Dense s) : borel α = .generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, l < u ∧ Ico l u = S } := - hd.borel_eq_generateFrom_Ico_mem_aux (by simp) fun x y hxy H => + hd.borel_eq_generateFrom_Ico_mem_aux (by simp) fun _ _ hxy H => ((nonempty_Ioo.2 hxy).ne_empty H).elim theorem borel_eq_generateFrom_Ico (α : Type*) [TopologicalSpace α] [SecondCountableTopology α] @@ -325,7 +325,7 @@ theorem Dense.borel_eq_generateFrom_Ioc_mem {α : Type*} [TopologicalSpace α] [ [OrderTopology α] [SecondCountableTopology α] [DenselyOrdered α] [NoMaxOrder α] {s : Set α} (hd : Dense s) : borel α = .generateFrom { S : Set α | ∃ l ∈ s, ∃ u ∈ s, l < u ∧ Ioc l u = S } := - hd.borel_eq_generateFrom_Ioc_mem_aux (by simp) fun x y hxy H => + hd.borel_eq_generateFrom_Ioc_mem_aux (by simp) fun _ _ hxy H => ((nonempty_Ioo.2 hxy).ne_empty H).elim theorem borel_eq_generateFrom_Ioc (α : Type*) [TopologicalSpace α] [SecondCountableTopology α] @@ -430,7 +430,7 @@ theorem ext_of_Iic {α : Type*} [TopologicalSpace α] {m : MeasurableSpace α} /-- Two finite measures on a Borel space are equal if they agree on all left-closed right-infinite intervals. -/ -theorem ext_of_Ici {α : Type*} [TopologicalSpace α] {m : MeasurableSpace α} +theorem ext_of_Ici {α : Type*} [TopologicalSpace α] {_ : MeasurableSpace α} [SecondCountableTopology α] [LinearOrder α] [OrderTopology α] [BorelSpace α] (μ ν : Measure α) [IsFiniteMeasure μ] (h : ∀ a, μ (Ici a) = ν (Ici a)) : μ = ν := @ext_of_Iic αᵒᵈ _ _ _ _ _ ‹_› _ _ _ h @@ -473,7 +473,7 @@ end LinearOrder section Lattice -variable [TopologicalSpace γ] [MeasurableSpace γ] [BorelSpace γ] +variable [TopologicalSpace γ] {mγ : MeasurableSpace γ} [BorelSpace γ] instance (priority := 100) ContinuousSup.measurableSup [Sup γ] [ContinuousSup γ] : MeasurableSup γ where @@ -499,9 +499,9 @@ end Orders section BorelSpace -variable [TopologicalSpace α] [MeasurableSpace α] [BorelSpace α] -variable [TopologicalSpace β] [MeasurableSpace β] [BorelSpace β] -variable [MeasurableSpace δ] +variable [TopologicalSpace α] {mα : MeasurableSpace α} [BorelSpace α] +variable [TopologicalSpace β] {mβ : MeasurableSpace β} [BorelSpace β] +variable {mδ : MeasurableSpace δ} section LinearOrder @@ -721,7 +721,7 @@ end LinearOrder section ConditionallyCompleteLattice @[measurability] -theorem Measurable.iSup_Prop {α} [MeasurableSpace α] [ConditionallyCompleteLattice α] +theorem Measurable.iSup_Prop {α} {mα : MeasurableSpace α} [ConditionallyCompleteLattice α] (p : Prop) {f : δ → α} (hf : Measurable f) : Measurable fun b => ⨆ _ : p, f b := by classical simp_rw [ciSup_eq_ite] @@ -730,7 +730,7 @@ theorem Measurable.iSup_Prop {α} [MeasurableSpace α] [ConditionallyCompleteLat · exact measurable_const @[measurability] -theorem Measurable.iInf_Prop {α} [MeasurableSpace α] [ConditionallyCompleteLattice α] +theorem Measurable.iInf_Prop {α} {mα : MeasurableSpace α} [ConditionallyCompleteLattice α] (p : Prop) {f : δ → α} (hf : Measurable f) : Measurable fun b => ⨅ _ : p, f b := by classical simp_rw [ciInf_eq_ite] @@ -744,8 +744,8 @@ section ConditionallyCompleteLinearOrder variable [ConditionallyCompleteLinearOrder α] [OrderTopology α] [SecondCountableTopology α] -@[measurability] -theorem measurable_iSup {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) : +@[measurability, fun_prop] +protected theorem Measurable.iSup {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) : Measurable (fun b ↦ ⨆ i, f i b) := by rcases isEmpty_or_nonempty ι with hι|hι · simp [iSup_of_empty'] @@ -762,74 +762,111 @@ theorem measurable_iSup {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, apply csSup_of_not_bddAbove exact hb +@[deprecated (since := "2024-10-21")] +alias measurable_iSup := Measurable.iSup + +-- TODO: Why does this error? +-- /-- Compositional version of `Measurable.iSup` for use by `fun_prop`. -/ +-- @[fun_prop] +-- protected lemma Measurable.iSup'' {_ : MeasurableSpace γ} {ι : Sort*} [Countable ι] +-- {f : ι → γ → δ → α} {h : γ → δ} (hf : ∀ i, Measurable ↿(f i)) (hh : Measurable h) : +-- Measurable fun a ↦ (⨆ i, f i a) (h a) := by +-- simp_rw [iSup_apply] +-- exact .iSup fun i ↦ by fun_prop + @[measurability] -theorem aemeasurable_iSup {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} +protected theorem AEMeasurable.iSup {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} (hf : ∀ i, AEMeasurable (f i) μ) : AEMeasurable (fun b => ⨆ i, f i b) μ := by - refine ⟨fun b ↦ ⨆ i, (hf i).mk (f i) b, measurable_iSup (fun i ↦ (hf i).measurable_mk), ?_⟩ + refine ⟨fun b ↦ ⨆ i, (hf i).mk (f i) b, .iSup (fun i ↦ (hf i).measurable_mk), ?_⟩ filter_upwards [ae_all_iff.2 (fun i ↦ (hf i).ae_eq_mk)] with b hb using by simp [hb] -@[measurability] -theorem measurable_iInf {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) : +@[deprecated (since := "2024-10-21")] +alias aemeasurable_iSup := AEMeasurable.iSup + +@[measurability, fun_prop] +protected theorem Measurable.iInf {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) : Measurable fun b => ⨅ i, f i b := - measurable_iSup (α := αᵒᵈ) hf + .iSup (α := αᵒᵈ) hf + +@[deprecated (since := "2024-10-21")] +alias measurable_iInf := Measurable.iInf @[measurability] -theorem aemeasurable_iInf {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} +protected theorem AEMeasurable.iInf {ι} {μ : Measure δ} [Countable ι] {f : ι → δ → α} (hf : ∀ i, AEMeasurable (f i) μ) : AEMeasurable (fun b => ⨅ i, f i b) μ := - aemeasurable_iSup (α := αᵒᵈ) hf + .iSup (α := αᵒᵈ) hf + +@[deprecated (since := "2024-10-21")] +alias aemeasurable_iInf := AEMeasurable.iInf -theorem measurable_sSup {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable) +protected theorem Measurable.sSup {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable) (hf : ∀ i ∈ s, Measurable (f i)) : Measurable fun x => sSup ((fun i => f i x) '' s) := by - have : Countable ↑s := countable_coe_iff.2 hs - convert measurable_iSup (f := (fun (i : s) ↦ f i)) (fun i ↦ hf i i.2) using 1 - ext b - congr - exact image_eq_range (fun i ↦ f i b) s + simp_rw [image_eq_range] + have : Countable s := hs.to_subtype + exact .iSup fun i ↦ hf i i.2 -theorem measurable_sInf {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable) +@[deprecated (since := "2024-10-21")] +alias measurable_sSup := Measurable.sSup + +protected theorem Measurable.sInf {ι} {f : ι → δ → α} {s : Set ι} (hs : s.Countable) (hf : ∀ i ∈ s, Measurable (f i)) : Measurable fun x => sInf ((fun i => f i x) '' s) := - measurable_sSup (α := αᵒᵈ) hs hf + .sSup (α := αᵒᵈ) hs hf + +@[deprecated (since := "2024-10-21")] +alias measurable_sInf := Measurable.sInf -theorem measurable_biSup {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) +theorem Measurable.biSup {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) (hf : ∀ i ∈ s, Measurable (f i)) : Measurable fun b => ⨆ i ∈ s, f i b := by haveI : Encodable s := hs.toEncodable by_cases H : ∀ i, i ∈ s · have : ∀ b, ⨆ i ∈ s, f i b = ⨆ (i : s), f i b := fun b ↦ cbiSup_eq_of_forall (f := fun i ↦ f i b) H simp only [this] - exact measurable_iSup (fun (i : s) ↦ hf i i.2) + exact .iSup (fun (i : s) ↦ hf i i.2) · have : ∀ b, ⨆ i ∈ s, f i b = (⨆ (i : s), f i b) ⊔ sSup ∅ := fun b ↦ cbiSup_eq_of_not_forall (f := fun i ↦ f i b) H simp only [this] apply Measurable.sup _ measurable_const - exact measurable_iSup (fun (i : s) ↦ hf i i.2) + exact .iSup (fun (i : s) ↦ hf i i.2) -theorem aemeasurable_biSup {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) +@[deprecated (since := "2024-10-21")] +alias measurable_biSup := Measurable.biSup + +theorem AEMeasurable.biSup {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) (hf : ∀ i ∈ s, AEMeasurable (f i) μ) : AEMeasurable (fun b => ⨆ i ∈ s, f i b) μ := by classical let g : ι → δ → α := fun i ↦ if hi : i ∈ s then (hf i hi).mk (f i) else fun _b ↦ sSup ∅ have : ∀ i ∈ s, Measurable (g i) := by intro i hi simpa [g, hi] using (hf i hi).measurable_mk - refine ⟨fun b ↦ ⨆ (i) (_ : i ∈ s), g i b, measurable_biSup s hs this, ?_⟩ + refine ⟨fun b ↦ ⨆ (i) (_ : i ∈ s), g i b, .biSup s hs this, ?_⟩ have : ∀ i ∈ s, ∀ᵐ b ∂μ, f i b = g i b := fun i hi ↦ by simpa [g, hi] using (hf i hi).ae_eq_mk filter_upwards [(ae_ball_iff hs).2 this] with b hb exact iSup_congr fun i => iSup_congr (hb i) -theorem measurable_biInf {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) +@[deprecated (since := "2024-10-21")] +alias aemeasurable_biSup := AEMeasurable.biSup + +theorem Measurable.biInf {ι} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) (hf : ∀ i ∈ s, Measurable (f i)) : Measurable fun b => ⨅ i ∈ s, f i b := - measurable_biSup (α := αᵒᵈ) s hs hf + .biSup (α := αᵒᵈ) s hs hf -theorem aemeasurable_biInf {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) +@[deprecated (since := "2024-10-21")] +alias measurable_biInf := Measurable.biInf + +theorem AEMeasurable.biInf {ι} {μ : Measure δ} (s : Set ι) {f : ι → δ → α} (hs : s.Countable) (hf : ∀ i ∈ s, AEMeasurable (f i) μ) : AEMeasurable (fun b => ⨅ i ∈ s, f i b) μ := - aemeasurable_biSup (α := αᵒᵈ) s hs hf + .biSup (α := αᵒᵈ) s hs hf + +@[deprecated (since := "2024-10-21")] +alias aemeasurable_biInf := AEMeasurable.biInf -/-- `liminf` over a general filter is measurable. See `measurable_liminf` for the version over `ℕ`. +/-- `liminf` over a general filter is measurable. See `Measurable.liminf` for the version over `ℕ`. -/ -theorem measurable_liminf' {ι ι'} {f : ι → δ → α} {v : Filter ι} (hf : ∀ i, Measurable (f i)) +theorem Measurable.liminf' {ι ι'} {f : ι → δ → α} {v : Filter ι} (hf : ∀ i, Measurable (f i)) {p : ι' → Prop} {s : ι' → Set ι} (hv : v.HasCountableBasis p s) (hs : ∀ j, (s j).Countable) : Measurable fun x => liminf (f · x) v := by classical @@ -852,11 +889,10 @@ theorem measurable_liminf' {ι ι'} {f : ι → δ → α} {v : Filter ι} (hf : have mc_meas : MeasurableSet {x | ∀ (j : Subtype p), x ∉ m j} := by rw [setOf_forall] exact MeasurableSet.iInter (fun j ↦ (m_meas j).compl) - apply Measurable.piecewise mc_meas measurable_const - apply measurable_iSup (fun j ↦ ?_) + refine measurable_const.piecewise mc_meas <| .iSup fun j ↦ ?_ let reparam : δ → Subtype p → Subtype p := fun x ↦ liminf_reparam (fun i ↦ f i x) s p let F0 : Subtype p → δ → α := fun j x ↦ ⨅ (i : s j), f i x - have F0_meas : ∀ j, Measurable (F0 j) := fun j ↦ measurable_iInf (fun (i : s j) ↦ hf i) + have F0_meas : ∀ j, Measurable (F0 j) := fun j ↦ .iInf (fun (i : s j) ↦ hf i) set F1 : δ → α := fun x ↦ F0 (reparam x j) x with hF1 change Measurable F1 let g : ℕ → Subtype p := Classical.choose (exists_surjective_nat (Subtype p)) @@ -881,26 +917,38 @@ theorem measurable_liminf' {ι ι'} {f : ι → δ → α} {v : Filter ι} (hf : apply Measurable.find (fun n ↦ F0_meas (g n)) (fun n ↦ ?_) exact (m_meas (g n)).union mc_meas -/-- `limsup` over a general filter is measurable. See `measurable_limsup` for the version over `ℕ`. +@[deprecated (since := "2024-10-21")] +alias measurable_liminf' := Measurable.liminf' + +/-- `limsup` over a general filter is measurable. See `Measurable.limsup` for the version over `ℕ`. -/ -theorem measurable_limsup' {ι ι'} {f : ι → δ → α} {u : Filter ι} (hf : ∀ i, Measurable (f i)) +theorem Measurable.limsup' {ι ι'} {f : ι → δ → α} {u : Filter ι} (hf : ∀ i, Measurable (f i)) {p : ι' → Prop} {s : ι' → Set ι} (hu : u.HasCountableBasis p s) (hs : ∀ i, (s i).Countable) : Measurable fun x => limsup (fun i => f i x) u := - measurable_liminf' (α := αᵒᵈ) hf hu hs + .liminf' (α := αᵒᵈ) hf hu hs + +@[deprecated (since := "2024-10-21")] +alias measurable_limsup' := Measurable.limsup' -/-- `liminf` over `ℕ` is measurable. See `measurable_liminf'` for a version with a general filter. +/-- `liminf` over `ℕ` is measurable. See `Measurable.liminf'` for a version with a general filter. -/ @[measurability] -theorem measurable_liminf {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) : +theorem Measurable.liminf {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) : Measurable fun x => liminf (fun i => f i x) atTop := - measurable_liminf' hf atTop_countable_basis fun _ => to_countable _ + .liminf' hf atTop_countable_basis fun _ => to_countable _ -/-- `limsup` over `ℕ` is measurable. See `measurable_limsup'` for a version with a general filter. +@[deprecated (since := "2024-10-21")] +alias measurable_liminf := Measurable.liminf + +/-- `limsup` over `ℕ` is measurable. See `Measurable.limsup'` for a version with a general filter. -/ @[measurability] -theorem measurable_limsup {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) : +theorem Measurable.limsup {f : ℕ → δ → α} (hf : ∀ i, Measurable (f i)) : Measurable fun x => limsup (fun i => f i x) atTop := - measurable_limsup' hf atTop_countable_basis fun _ => to_countable _ + .limsup' hf atTop_countable_basis fun _ => to_countable _ + +@[deprecated (since := "2024-10-21")] +alias measurable_limsup := Measurable.limsup end ConditionallyCompleteLinearOrder @@ -923,7 +971,7 @@ section ENNReal /-- One can cut out `ℝ≥0∞` into the sets `{0}`, `Ico (t^n) (t^(n+1))` for `n : ℤ` and `{∞}`. This gives a way to compute the measure of a set in terms of sets on which a given function `f` does not fluctuate by more than `t`. -/ -theorem measure_eq_measure_preimage_add_measure_tsum_Ico_zpow {α : Type*} [MeasurableSpace α] +theorem measure_eq_measure_preimage_add_measure_tsum_Ico_zpow {α : Type*} {mα : MeasurableSpace α} (μ : Measure α) {f : α → ℝ≥0∞} (hf : Measurable f) {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht : 1 < t) : μ s = diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean index f15add556e5f0..c89fefe9a34d6 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean @@ -115,7 +115,7 @@ def finiteSpanningSetsInIooRat (μ : Measure ℝ) [IsLocallyFiniteMeasure μ] : -- TODO: norm_cast fails here? push_cast exact neg_lt_self n.cast_add_one_pos - finite n := measure_Ioo_lt_top + finite _ := measure_Ioo_lt_top spanning := iUnion_eq_univ_iff.2 fun x => ⟨⌊|x|⌋₊, neg_lt.1 ((neg_le_abs x).trans_lt (Nat.lt_floor_add_one _)), @@ -130,7 +130,7 @@ theorem measure_ext_Ioo_rat {μ ν : Measure ℝ} [IsLocallyFiniteMeasure μ] end Real -variable [MeasurableSpace α] +variable {mα : MeasurableSpace α} @[measurability, fun_prop] theorem measurable_real_toNNReal : Measurable Real.toNNReal := @@ -217,7 +217,7 @@ def ennrealEquivSum : ℝ≥0∞ ≃ᵐ ℝ≥0 ⊕ Unit := open Function (uncurry) -theorem measurable_of_measurable_nnreal_prod [MeasurableSpace β] [MeasurableSpace γ] +theorem measurable_of_measurable_nnreal_prod {_ : MeasurableSpace β} {_ : MeasurableSpace γ} {f : ℝ≥0∞ × β → γ} (H₁ : Measurable fun p : ℝ≥0 × β => f (p.1, p.2)) (H₂ : Measurable fun x => f (∞, x)) : Measurable f := let e : ℝ≥0∞ × β ≃ᵐ (ℝ≥0 × β) ⊕ (Unit × β) := @@ -225,7 +225,7 @@ theorem measurable_of_measurable_nnreal_prod [MeasurableSpace β] [MeasurableSpa (MeasurableEquiv.sumProdDistrib _ _ _) e.symm.measurable_comp_iff.1 <| measurable_sum H₁ (H₂.comp measurable_id.snd) -theorem measurable_of_measurable_nnreal_nnreal [MeasurableSpace β] {f : ℝ≥0∞ × ℝ≥0∞ → β} +theorem measurable_of_measurable_nnreal_nnreal {_ : MeasurableSpace β} {f : ℝ≥0∞ × ℝ≥0∞ → β} (h₁ : Measurable fun p : ℝ≥0 × ℝ≥0 => f (p.1, p.2)) (h₂ : Measurable fun r : ℝ≥0 => f (∞, r)) (h₃ : Measurable fun r : ℝ≥0 => f (r, ∞)) : Measurable f := measurable_of_measurable_nnreal_prod @@ -255,7 +255,8 @@ instance instMeasurableMul₂ : MeasurableMul₂ ℝ≥0∞ := by instance instMeasurableSub₂ : MeasurableSub₂ ℝ≥0∞ := ⟨by apply measurable_of_measurable_nnreal_nnreal <;> - simp [← WithTop.coe_sub]; exact continuous_sub.measurable.coe_nnreal_ennreal⟩ + simp [← WithTop.coe_sub, tsub_eq_zero_of_le]; + exact continuous_sub.measurable.coe_nnreal_ennreal⟩ instance instMeasurableInv : MeasurableInv ℝ≥0∞ := ⟨continuous_inv.measurable⟩ @@ -279,7 +280,7 @@ theorem measurable_of_tendsto' {ι : Type*} {f : ι → α → ℝ≥0∞} {g : exact ((lim y).comp hx).liminf_eq rw [← this] show Measurable fun y => liminf (fun n => (f (x n) y : ℝ≥0∞)) atTop - exact measurable_liminf fun n => hf (x n) + exact .liminf fun n => hf (x n) @[deprecated (since := "2024-03-09")] alias _root_.measurable_of_tendsto_ennreal' := ENNReal.measurable_of_tendsto' @@ -359,8 +360,7 @@ theorem AEMeasurable.ennreal_toReal {f : α → ℝ≥0∞} {μ : Measure α} (h theorem Measurable.ennreal_tsum {ι} [Countable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, Measurable (f i)) : Measurable fun x => ∑' i, f i x := by simp_rw [ENNReal.tsum_eq_iSup_sum] - apply measurable_iSup - exact fun s => s.measurable_sum fun i _ => h i + exact .iSup fun s ↦ s.measurable_sum fun i _ => h i @[measurability, fun_prop] theorem Measurable.ennreal_tsum' {ι} [Countable ι] {f : ι → α → ℝ≥0∞} (h : ∀ i, Measurable (f i)) : @@ -378,12 +378,11 @@ theorem Measurable.nnreal_tsum {ι} [Countable ι] {f : ι → α → ℝ≥0} ( theorem AEMeasurable.ennreal_tsum {ι} [Countable ι] {f : ι → α → ℝ≥0∞} {μ : Measure α} (h : ∀ i, AEMeasurable (f i) μ) : AEMeasurable (fun x => ∑' i, f i x) μ := by simp_rw [ENNReal.tsum_eq_iSup_sum] - apply aemeasurable_iSup - exact fun s => Finset.aemeasurable_sum s fun i _ => h i + exact .iSup fun s ↦ Finset.aemeasurable_sum s fun i _ => h i @[measurability, fun_prop] -theorem AEMeasurable.nnreal_tsum {α : Type*} [MeasurableSpace α] {ι : Type*} [Countable ι] - {f : ι → α → NNReal} {μ : MeasureTheory.Measure α} (h : ∀ i : ι, AEMeasurable (f i) μ) : +theorem AEMeasurable.nnreal_tsum {α : Type*} {_ : MeasurableSpace α} {ι : Type*} [Countable ι] + {f : ι → α → NNReal} {μ : Measure α} (h : ∀ i : ι, AEMeasurable (f i) μ) : AEMeasurable (fun x : α => ∑' i : ι, f i x) μ := by simp_rw [NNReal.tsum_eq_toNNReal_tsum] exact (AEMeasurable.ennreal_tsum fun i => (h i).coe_nnreal_ennreal).ennreal_toNNReal @@ -470,9 +469,8 @@ end NNReal spanning measurable sets with finite measure on which `f` is bounded. See also `StronglyMeasurable.exists_spanning_measurableSet_norm_le` for functions into normed groups. -/ --- We redeclare `α` to temporarily avoid the `[MeasurableSpace α]` instance. -theorem exists_spanning_measurableSet_le {α : Type*} {m : MeasurableSpace α} {f : α → ℝ≥0} - (hf : Measurable f) (μ : Measure α) [SigmaFinite μ] : +theorem exists_spanning_measurableSet_le {f : α → ℝ≥0} (hf : Measurable f) (μ : Measure α) + [SigmaFinite μ] : ∃ s : ℕ → Set α, (∀ n, MeasurableSet (s n) ∧ μ (s n) < ∞ ∧ ∀ x ∈ s n, f x ≤ n) ∧ ⋃ i, s i = Set.univ := by @@ -485,7 +483,7 @@ theorem exists_spanning_measurableSet_le {α : Type*} {m : MeasurableSpace α} { let sets n := sigma_finite_sets n ∩ norm_sets n have h_meas : ∀ n, MeasurableSet (sets n) := by refine fun n => MeasurableSet.inter ?_ ?_ - · exact measurable_spanningSets μ n + · exact measurableSet_spanningSets μ n · exact hf measurableSet_Iic have h_finite : ∀ n, μ (sets n) < ∞ := by refine fun n => (measure_mono Set.inter_subset_left).trans_lt ?_ diff --git a/Mathlib/MeasureTheory/Constructions/Cylinders.lean b/Mathlib/MeasureTheory/Constructions/Cylinders.lean index 3ef19d096a73e..1f30b5fc6437d 100644 --- a/Mathlib/MeasureTheory/Constructions/Cylinders.lean +++ b/Mathlib/MeasureTheory/Constructions/Cylinders.lean @@ -1,7 +1,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, Peter Pfaffelhuber +Authors: Rémy Degenne, Peter Pfaffelhuber, Yaël Dillies, Kin Yau James Wong -/ import Mathlib.MeasureTheory.PiSystem import Mathlib.Order.OmegaCompletePartialOrder @@ -29,6 +29,8 @@ a product set. all `i` in the finset defining the box, the projection to `α i` belongs to `C i`. The main application of this is with `C i = {s : Set (α i) | MeasurableSet s}`. * `measurableCylinders`: set of all cylinders with measurable base sets. +* `cylinderEvents Δ`: The σ-algebra of cylinder events on `Δ`. It is the smallest σ-algebra making + the projections on the `i`-th coordinate continuous for all `i ∈ Δ`. ## Main statements @@ -39,7 +41,7 @@ a product set. -/ -open Set +open Function Set namespace MeasureTheory @@ -361,4 +363,79 @@ theorem generateFrom_measurableCylinders : end cylinders +/-! ### Cylinder events as a sigma-algebra -/ + +section cylinderEvents + +variable {α ι : Type*} {π : ι → Type*} {mα : MeasurableSpace α} [m : ∀ i, MeasurableSpace (π i)] + {Δ Δ₁ Δ₂ : Set ι} {i : ι} + +/-- The σ-algebra of cylinder events on `Δ`. It is the smallest σ-algebra making the projections +on the `i`-th coordinate continuous for all `i ∈ Δ`. -/ +def cylinderEvents (Δ : Set ι) : MeasurableSpace (∀ i, π i) := ⨆ i ∈ Δ, (m i).comap fun σ ↦ σ i + +@[simp] lemma cylinderEvents_univ : cylinderEvents (π := π) univ = MeasurableSpace.pi := by + simp [cylinderEvents, MeasurableSpace.pi] + +@[gcongr] +lemma cylinderEvents_mono (h : Δ₁ ⊆ Δ₂) : cylinderEvents (π := π) Δ₁ ≤ cylinderEvents Δ₂ := + biSup_mono h + +lemma cylinderEvents_le_pi : cylinderEvents (π := π) Δ ≤ MeasurableSpace.pi := by + simpa using cylinderEvents_mono (subset_univ _) + +lemma measurable_cylinderEvents_iff {g : α → ∀ i, π i} : + @Measurable _ _ _ (cylinderEvents Δ) g ↔ ∀ ⦃i⦄, i ∈ Δ → Measurable fun a ↦ g a i := by + simp_rw [measurable_iff_comap_le, cylinderEvents, MeasurableSpace.comap_iSup, + MeasurableSpace.comap_comp, Function.comp_def, iSup_le_iff] + +@[fun_prop, aesop safe 100 apply (rule_sets := [Measurable])] +lemma measurable_cylinderEvent_apply (hi : i ∈ Δ) : + Measurable[cylinderEvents Δ] fun f : ∀ i, π i => f i := + measurable_cylinderEvents_iff.1 measurable_id hi + +@[aesop safe 100 apply (rule_sets := [Measurable])] +lemma Measurable.eval_cylinderEvents {g : α → ∀ i, π i} (hi : i ∈ Δ) + (hg : @Measurable _ _ _ (cylinderEvents Δ) g) : Measurable fun a ↦ g a i := + (measurable_cylinderEvent_apply hi).comp hg + +@[fun_prop, aesop safe 100 apply (rule_sets := [Measurable])] +lemma measurable_cylinderEvents_lambda (f : α → ∀ i, π i) (hf : ∀ i, Measurable fun a ↦ f a i) : + Measurable f := + measurable_pi_iff.mpr hf + +/-- The function `(f, x) ↦ update f a x : (Π a, π a) × π a → Π a, π a` is measurable. -/ +lemma measurable_update_cylinderEvents' [DecidableEq ι] : + @Measurable _ _ (.prod (cylinderEvents Δ) (m i)) (cylinderEvents Δ) + (fun p : (∀ i, π i) × π i ↦ update p.1 i p.2) := by + rw [measurable_cylinderEvents_iff] + intro j hj + dsimp [update] + split_ifs with h + · subst h + dsimp + exact measurable_snd + · exact measurable_cylinderEvents_iff.1 measurable_fst hj + +lemma measurable_uniqueElim_cylinderEvents [Unique ι] : + Measurable (uniqueElim : π (default : ι) → ∀ i, π i) := by + simp_rw [measurable_pi_iff, Unique.forall_iff, uniqueElim_default]; exact measurable_id + +/-- The function `update f a : π a → Π a, π a` is always measurable. +This doesn't require `f` to be measurable. +This should not be confused with the statement that `update f a x` is measurable. -/ +@[measurability] +lemma measurable_update_cylinderEvents (f : ∀ a : ι, π a) {a : ι} [DecidableEq ι] : + @Measurable _ _ _ (cylinderEvents Δ) (update f a) := + measurable_update_cylinderEvents'.comp measurable_prod_mk_left + +lemma measurable_update_cylinderEvents_left {a : ι} [DecidableEq ι] {x : π a} : + @Measurable _ _ (cylinderEvents Δ) (cylinderEvents Δ) (update · a x) := + measurable_update_cylinderEvents'.comp measurable_prod_mk_right + +lemma measurable_restrict_cylinderEvents (Δ : Set ι) : + Measurable[cylinderEvents (π := π) Δ] (restrict Δ) := by + rw [@measurable_pi_iff]; exact fun i ↦ measurable_cylinderEvent_apply i.2 + +end cylinderEvents end MeasureTheory diff --git a/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean b/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean index c26b40b3beb7d..a82d9ab57e451 100644 --- a/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean +++ b/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean @@ -40,7 +40,7 @@ on `α`, modulo a given σ-filter `l` on `α`. -/ def EventuallyMeasurableSpace (l : Filter α) [CountableInterFilter l] : MeasurableSpace α where MeasurableSet' s := ∃ t, MeasurableSet t ∧ s =ᶠ[l] t measurableSet_empty := ⟨∅, MeasurableSet.empty, EventuallyEq.refl _ _ ⟩ - measurableSet_compl := fun s ⟨t, ht, hts⟩ => ⟨tᶜ, ht.compl, hts.compl⟩ + measurableSet_compl := fun _ ⟨t, ht, hts⟩ => ⟨tᶜ, ht.compl, hts.compl⟩ measurableSet_iUnion s hs := by choose t ht hts using hs exact ⟨⋃ i, t i, MeasurableSet.iUnion ht, EventuallyEq.countable_iUnion hts⟩ diff --git a/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean b/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean index 2b64a512ceb6e..8b8f004c2cbd6 100644 --- a/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean +++ b/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean @@ -6,7 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Algebra.Order.Field.Pointwise import Mathlib.Analysis.NormedSpace.SphereNormEquiv import Mathlib.Analysis.SpecialFunctions.Integrals -import Mathlib.MeasureTheory.Constructions.Prod.Integral +import Mathlib.MeasureTheory.Integral.Prod import Mathlib.MeasureTheory.Measure.Lebesgue.EqHaar /-! @@ -97,7 +97,7 @@ and cover the whole open ray `(0, +∞)`. -/ def finiteSpanningSetsIn_volumeIoiPow_range_Iio (n : ℕ) : FiniteSpanningSetsIn (volumeIoiPow n) (range Iio) where set k := Iio ⟨k + 1, mem_Ioi.2 k.cast_add_one_pos⟩ - set_mem k := mem_range_self _ + set_mem _ := mem_range_self _ finite k := by simp [volumeIoiPow_apply_Iio] spanning := iUnion_eq_univ_iff.2 fun x ↦ ⟨⌊x.1⌋₊, Nat.lt_floor_add_one x.1⟩ @@ -147,7 +147,7 @@ lemma integral_fun_norm_addHaar (f : ℝ → F) : rw [integral_withDensity_eq_integral_smul, μ.toSphere_apply_univ, ENNReal.toReal_mul, ENNReal.toReal_nat, ← nsmul_eq_mul, smul_assoc, integral_subtype_comap measurableSet_Ioi fun a ↦ Real.toNNReal (a ^ (dim E - 1)) • f a, - setIntegral_congr measurableSet_Ioi fun x hx ↦ ?_] + setIntegral_congr_fun measurableSet_Ioi fun x hx ↦ ?_] · rw [NNReal.smul_def, Real.coe_toNNReal _ (pow_nonneg hx.out.le _)] · exact (measurable_subtype_coe.pow_const _).real_toNNReal diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index 300e10ce1b53a..222b04a9c5ac8 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Group.Measure +import Mathlib.MeasureTheory.Measure.Prod import Mathlib.Topology.Constructions /-! @@ -62,6 +62,9 @@ variable {ι ι' : Type*} {α : ι → Type*} /-! We start with some measurability properties -/ +lemma MeasurableSpace.pi_eq_generateFrom_projections {mα : ∀ i, MeasurableSpace (α i)} : + pi = generateFrom {B | ∃ (i : ι) (A : Set (α i)), MeasurableSet A ∧ eval i ⁻¹' A = B} := by + simp only [pi, ← generateFrom_iUnion_measurableSet, iUnion_setOf, measurableSet_comap] /-- Boxes formed by π-systems form a π-system. -/ theorem IsPiSystem.pi {C : ∀ i, Set (Set (α i))} (hC : ∀ i, IsPiSystem (C i)) : @@ -836,7 +839,7 @@ theorem volume_preserving_piFinTwo (α : Fin 2 → Type u) [∀ i, MeasureSpace MeasurePreserving (MeasurableEquiv.piFinTwo α) volume volume := measurePreserving_piFinTwo _ -theorem measurePreserving_finTwoArrow_vec {α : Type u} {m : MeasurableSpace α} (μ ν : Measure α) +theorem measurePreserving_finTwoArrow_vec {α : Type u} {_ : MeasurableSpace α} (μ ν : Measure α) [SigmaFinite μ] [SigmaFinite ν] : MeasurePreserving MeasurableEquiv.finTwoArrow (Measure.pi ![μ, ν]) (μ.prod ν) := haveI : ∀ i, SigmaFinite (![μ, ν] i) := Fin.forall_fin_two.2 ⟨‹_›, ‹_›⟩ diff --git a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean index 89db09097d3cb..02c0d1b8c30a6 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean @@ -106,15 +106,26 @@ section variable [MeasurableSpace α] -instance standardBorel_of_polish [τ : TopologicalSpace α] +-- See note [lower instance priority] +instance (priority := 100) standardBorel_of_polish [τ : TopologicalSpace α] [BorelSpace α] [PolishSpace α] : StandardBorelSpace α := by exists τ -instance countablyGenerated_of_standardBorel [StandardBorelSpace α] : +-- See note [lower instance priority] +instance (priority := 100) standardBorelSpace_of_discreteMeasurableSpace [DiscreteMeasurableSpace α] + [Countable α] : StandardBorelSpace α := + let _ : TopologicalSpace α := ⊥ + have : DiscreteTopology α := ⟨rfl⟩ + inferInstance + +-- See note [lower instance priority] +instance (priority := 100) countablyGenerated_of_standardBorel [StandardBorelSpace α] : MeasurableSpace.CountablyGenerated α := letI := upgradeStandardBorel α inferInstance -instance measurableSingleton_of_standardBorel [StandardBorelSpace α] : MeasurableSingletonClass α := +-- See note [lower instance priority] +instance (priority := 100) measurableSingleton_of_standardBorel [StandardBorelSpace α] : + MeasurableSingletonClass α := letI := upgradeStandardBorel α inferInstance @@ -620,10 +631,7 @@ instance CosetSpace.borelSpace {G : Type*} [TopologicalSpace G] [PolishSpace G] instance QuotientGroup.borelSpace {G : Type*} [TopologicalSpace G] [PolishSpace G] [Group G] [TopologicalGroup G] [MeasurableSpace G] [BorelSpace G] {N : Subgroup G} [N.Normal] [IsClosed (N : Set G)] : BorelSpace (G ⧸ N) := - -- Porting note: 1st and 3rd `haveI`s were not needed in Lean 3 - haveI := Subgroup.t3_quotient_of_isClosed N - haveI := QuotientGroup.secondCountableTopology (Γ := N) - Quotient.borelSpace + ⟨continuous_mk.map_eq_borel mk_surjective⟩ namespace MeasureTheory diff --git a/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean b/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean index 67a330bbb5bb7..49a72519b60d3 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean @@ -24,7 +24,7 @@ theorem exists_nat_measurableEquiv_range_coe_fin_of_finite [Finite α] : theorem measurableEquiv_range_coe_nat_of_infinite_of_countable [Infinite α] [Countable α] : Nonempty (α ≃ᵐ range ((↑) : ℕ → ℝ)) := by have : PolishSpace (range ((↑) : ℕ → ℝ)) := - Nat.closedEmbedding_coe_real.isClosedMap.isClosed_range.polishSpace + Nat.isClosedEmbedding_coe_real.isClosedMap.isClosed_range.polishSpace refine ⟨PolishSpace.Equiv.measurableEquiv ?_⟩ refine (nonempty_equiv_of_countable.some : α ≃ ℕ).trans ?_ exact Equiv.ofInjective ((↑) : ℕ → ℝ) Nat.cast_injective diff --git a/Mathlib/MeasureTheory/Constructions/SubmoduleQuotient.lean b/Mathlib/MeasureTheory/Constructions/SubmoduleQuotient.lean new file mode 100644 index 0000000000000..711760a5fb963 --- /dev/null +++ b/Mathlib/MeasureTheory/Constructions/SubmoduleQuotient.lean @@ -0,0 +1,20 @@ +/- +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.LinearAlgebra.Quotient.Defs +import Mathlib.MeasureTheory.MeasurableSpace.Basic + +/-! +# Measurability on the quotient of a module by a submodule +-/ + +namespace Submodule.Quotient +variable {R M : Type*} [Ring R] [AddCommGroup M] [Module R M] {p : Submodule R M} + +instance [MeasurableSpace M] : MeasurableSpace (M ⧸ p) := Quotient.instMeasurableSpace +instance [MeasurableSpace M] [DiscreteMeasurableSpace M] : DiscreteMeasurableSpace (M ⧸ p) := + Quotient.instDiscreteMeasurableSpace + +end Submodule.Quotient diff --git a/Mathlib/MeasureTheory/Covering/Besicovitch.lean b/Mathlib/MeasureTheory/Covering/Besicovitch.lean index 466e9d9155efd..1e7a76eadda2d 100644 --- a/Mathlib/MeasureTheory/Covering/Besicovitch.lean +++ b/Mathlib/MeasureTheory/Covering/Besicovitch.lean @@ -309,7 +309,7 @@ theorem mem_iUnionUpTo_lastStep (x : β) : p.c x ∈ p.iUnionUpTo p.lastStep := apply lt_trans (mul_pos (_root_.zero_lt_one.trans p.one_lt_tau) (p.rpos _)) H have B : p.τ⁻¹ * p.R p.lastStep < p.R p.lastStep := by conv_rhs => rw [← one_mul (p.R p.lastStep)] - exact mul_lt_mul (inv_lt_one p.one_lt_tau) le_rfl Rpos zero_le_one + exact mul_lt_mul (inv_lt_one_of_one_lt₀ p.one_lt_tau) le_rfl Rpos zero_le_one obtain ⟨y, hy1, hy2⟩ : ∃ y, p.c y ∉ p.iUnionUpTo p.lastStep ∧ p.τ⁻¹ * p.R p.lastStep < p.r y := by have := exists_lt_of_lt_csSup ?_ B · simpa only [exists_prop, mem_range, exists_exists_and_eq_and, Subtype.exists, @@ -1016,7 +1016,7 @@ forms a Vitali family. This is essentially a restatement of the measurable Besic protected def vitaliFamily (μ : Measure α) [SFinite μ] : VitaliFamily μ where setsAt x := (fun r : ℝ => closedBall x r) '' Ioi (0 : ℝ) measurableSet _ := forall_mem_image.2 fun _ _ ↦ isClosed_ball.measurableSet - nonempty_interior _ := forall_mem_image.2 fun r rpos ↦ + nonempty_interior _ := forall_mem_image.2 fun _ rpos ↦ (nonempty_ball.2 rpos).mono ball_subset_interior_closedBall nontrivial x ε εpos := ⟨closedBall x ε, mem_image_of_mem _ εpos, Subset.rfl⟩ covering := by diff --git a/Mathlib/MeasureTheory/Covering/DensityTheorem.lean b/Mathlib/MeasureTheory/Covering/DensityTheorem.lean index 62c58768b78a6..d48e556855462 100644 --- a/Mathlib/MeasureTheory/Covering/DensityTheorem.lean +++ b/Mathlib/MeasureTheory/Covering/DensityTheorem.lean @@ -35,7 +35,7 @@ open scoped NNReal Topology namespace IsUnifLocDoublingMeasure -variable {α : Type*} [MetricSpace α] [MeasurableSpace α] (μ : Measure α) +variable {α : Type*} [PseudoMetricSpace α] [MeasurableSpace α] (μ : Measure α) [IsUnifLocDoublingMeasure μ] section @@ -139,8 +139,8 @@ not required to be fixed. See also `Besicovitch.ae_tendsto_measure_inter_div`. -/ theorem ae_tendsto_measure_inter_div (S : Set α) (K : ℝ) : ∀ᵐ x ∂μ.restrict S, - ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (δlim : Tendsto δ l (𝓝[>] 0)) - (xmem : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), + ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (_ : Tendsto δ l (𝓝[>] 0)) + (_ : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), Tendsto (fun j => μ (S ∩ closedBall (w j) (δ j)) / μ (closedBall (w j) (δ j))) l (𝓝 1) := by filter_upwards [(vitaliFamily μ K).ae_tendsto_measure_inter_div S] with x hx ι l w δ δlim xmem using hx.comp (tendsto_closedBall_filterAt μ _ _ δlim xmem) @@ -148,8 +148,8 @@ theorem ae_tendsto_measure_inter_div (S : Set α) (K : ℝ) : ∀ᵐ x ∂μ.res /-- A version of **Lebesgue differentiation theorem** for a sequence of closed balls whose centers are not required to be fixed. -/ theorem ae_tendsto_average_norm_sub {f : α → E} (hf : LocallyIntegrable f μ) (K : ℝ) : ∀ᵐ x ∂μ, - ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (δlim : Tendsto δ l (𝓝[>] 0)) - (xmem : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), + ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (_ : Tendsto δ l (𝓝[>] 0)) + (_ : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), Tendsto (fun j => ⨍ y in closedBall (w j) (δ j), ‖f y - f x‖ ∂μ) l (𝓝 0) := by filter_upwards [(vitaliFamily μ K).ae_tendsto_average_norm_sub hf] with x hx ι l w δ δlim xmem using hx.comp (tendsto_closedBall_filterAt μ _ _ δlim xmem) @@ -158,8 +158,8 @@ theorem ae_tendsto_average_norm_sub {f : α → E} (hf : LocallyIntegrable f μ) centers are not required to be fixed. -/ theorem ae_tendsto_average [NormedSpace ℝ E] [CompleteSpace E] {f : α → E} (hf : LocallyIntegrable f μ) (K : ℝ) : ∀ᵐ x ∂μ, - ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (δlim : Tendsto δ l (𝓝[>] 0)) - (xmem : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), + ∀ {ι : Type*} {l : Filter ι} (w : ι → α) (δ : ι → ℝ) (_ : Tendsto δ l (𝓝[>] 0)) + (_ : ∀ᶠ j in l, x ∈ closedBall (w j) (K * δ j)), Tendsto (fun j => ⨍ y in closedBall (w j) (δ j), f y ∂μ) l (𝓝 (f x)) := by filter_upwards [(vitaliFamily μ K).ae_tendsto_average hf] with x hx ι l w δ δlim xmem using hx.comp (tendsto_closedBall_filterAt μ _ _ δlim xmem) diff --git a/Mathlib/MeasureTheory/Covering/Differentiation.lean b/Mathlib/MeasureTheory/Covering/Differentiation.lean index 4af0418c40a8e..f2de314db2a9e 100644 --- a/Mathlib/MeasureTheory/Covering/Differentiation.lean +++ b/Mathlib/MeasureTheory/Covering/Differentiation.lean @@ -78,7 +78,8 @@ open MeasureTheory Metric Set Filter TopologicalSpace MeasureTheory.Measure open scoped Filter ENNReal MeasureTheory NNReal Topology -variable {α : Type*} [MetricSpace α] {m0 : MeasurableSpace α} {μ : Measure α} (v : VitaliFamily μ) +variable {α : Type*} [PseudoMetricSpace α] {m0 : MeasurableSpace α} {μ : Measure α} + (v : VitaliFamily μ) {E : Type*} [NormedAddCommGroup E] namespace VitaliFamily @@ -573,7 +574,7 @@ theorem withDensity_le_mul {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht conv_rhs => rw [← mul_one (t ^ n)] gcongr rw [zpow_neg_one] - exact inv_lt_one ht + exact inv_lt_one_of_one_lt₀ ht calc ν s = ν (s ∩ f ⁻¹' {0}) + ν (s ∩ f ⁻¹' {∞}) + diff --git a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean index 539f24411b7c9..564f7b35210b9 100644 --- a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean +++ b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean @@ -28,7 +28,8 @@ open Set Filter Metric MeasureTheory TopologicalSpace open scoped NNReal ENNReal Topology -variable {α : Type*} [MetricSpace α] [SecondCountableTopology α] [MeasurableSpace α] [BorelSpace α] +variable {α : Type*} +variable [PseudoMetricSpace α] [SecondCountableTopology α] [MeasurableSpace α] [BorelSpace α] variable (μ : Measure α) [IsLocallyFiniteMeasure μ] [IsUnifLocDoublingMeasure μ] /-- This is really an auxiliary result en route to `blimsup_cthickening_ae_le_of_eventually_mul_le` diff --git a/Mathlib/MeasureTheory/Covering/Vitali.lean b/Mathlib/MeasureTheory/Covering/Vitali.lean index 364031a842a49..817189a085c43 100644 --- a/Mathlib/MeasureTheory/Covering/Vitali.lean +++ b/Mathlib/MeasureTheory/Covering/Vitali.lean @@ -155,7 +155,8 @@ theorem exists_disjoint_subfamily_covering_enlargment (B : ι → Set α) (t : S /-- Vitali covering theorem, closed balls version: given a family `t` of closed balls, one can extract a disjoint subfamily `u ⊆ t` so that all balls in `t` are covered by the τ-times dilations of balls in `u`, for some `τ > 3`. -/ -theorem exists_disjoint_subfamily_covering_enlargment_closedBall [MetricSpace α] (t : Set ι) +theorem exists_disjoint_subfamily_covering_enlargment_closedBall + [PseudoMetricSpace α] (t : Set ι) (x : ι → α) (r : ι → ℝ) (R : ℝ) (hr : ∀ a ∈ t, r a ≤ R) (τ : ℝ) (hτ : 3 < τ) : ∃ u ⊆ t, (u.PairwiseDisjoint fun a => closedBall (x a) (r a)) ∧ @@ -200,7 +201,8 @@ Then one can extract from `t` a disjoint subfamily that covers almost all `s`. For more flexibility, we give a statement with a parameterized family of sets. -/ -theorem exists_disjoint_covering_ae [MetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] +theorem exists_disjoint_covering_ae + [PseudoMetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] [SecondCountableTopology α] (μ : Measure α) [IsLocallyFiniteMeasure μ] (s : Set α) (t : Set ι) (C : ℝ≥0) (r : ι → ℝ) (c : ι → α) (B : ι → Set α) (hB : ∀ a ∈ t, B a ⊆ closedBall (c a) (r a)) (μB : ∀ a ∈ t, μ (closedBall (c a) (3 * r a)) ≤ C * μ (B a)) @@ -390,14 +392,14 @@ theorem exists_disjoint_covering_ae [MetricSpace α] [MeasurableSpace α] [Opens doubling. Then the set of closed sets `a` with nonempty interior contained in `closedBall x r` and covering a fixed proportion `1/C` of the ball `closedBall x (3 * r)` forms a Vitali family. This is essentially a restatement of the measurable Vitali theorem. -/ -protected def vitaliFamily [MetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] +protected def vitaliFamily [PseudoMetricSpace α] [MeasurableSpace α] [OpensMeasurableSpace α] [SecondCountableTopology α] (μ : Measure α) [IsLocallyFiniteMeasure μ] (C : ℝ≥0) (h : ∀ x, ∃ᶠ r in 𝓝[>] 0, μ (closedBall x (3 * r)) ≤ C * μ (closedBall x r)) : VitaliFamily μ where setsAt x := { a | IsClosed a ∧ (interior a).Nonempty ∧ ∃ r, a ⊆ closedBall x r ∧ μ (closedBall x (3 * r)) ≤ C * μ a } - measurableSet x a ha := ha.1.measurableSet - nonempty_interior x a ha := ha.2.1 + measurableSet _ _ ha := ha.1.measurableSet + nonempty_interior _ _ ha := ha.2.1 nontrivial x ε εpos := by obtain ⟨r, μr, rpos, rε⟩ : ∃ r, μ (closedBall x (3 * r)) ≤ C * μ (closedBall x r) ∧ r ∈ Ioc (0 : ℝ) ε := diff --git a/Mathlib/MeasureTheory/Covering/VitaliFamily.lean b/Mathlib/MeasureTheory/Covering/VitaliFamily.lean index a584639b9f6e9..ec5f09391c9ae 100644 --- a/Mathlib/MeasureTheory/Covering/VitaliFamily.lean +++ b/Mathlib/MeasureTheory/Covering/VitaliFamily.lean @@ -49,7 +49,7 @@ Vitali relations there) open MeasureTheory Metric Set Filter TopologicalSpace MeasureTheory.Measure open scoped Topology -variable {X : Type*} [MetricSpace X] +variable {X : Type*} [PseudoMetricSpace X] /-- On a metric space `X` with a measure `μ`, consider for each `x : X` a family of measurable sets with nonempty interiors, called `setsAt x`. This family is a Vitali family if it satisfies the diff --git a/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean b/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean index a6f283377c6c5..0cf002bd37fb1 100644 --- a/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean +++ b/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean @@ -284,7 +284,7 @@ lemma measure_compl_sigmaFiniteSetWRT (hμν : μ ≪ ν) [SigmaFinite μ] [SFin by_contra h0 refine ENNReal.top_ne_zero ?_ rw [← h h0, ← Measure.iSup_restrict_spanningSets] - simp_rw [Measure.restrict_apply' (measurable_spanningSets μ _), ENNReal.iSup_eq_zero] + simp_rw [Measure.restrict_apply' (measurableSet_spanningSets μ _), ENNReal.iSup_eq_zero] intro i by_contra h_ne_zero have h_zero_top := measure_eq_top_of_subset_compl_sigmaFiniteSetWRT diff --git a/Mathlib/MeasureTheory/Decomposition/Jordan.lean b/Mathlib/MeasureTheory/Decomposition/Jordan.lean index 6ff1e74d9497e..12402fc826cce 100644 --- a/Mathlib/MeasureTheory/Decomposition/Jordan.lean +++ b/Mathlib/MeasureTheory/Decomposition/Jordan.lean @@ -44,7 +44,7 @@ noncomputable section open scoped Classical MeasureTheory ENNReal NNReal -variable {α β : Type*} [MeasurableSpace α] +variable {α : Type*} [MeasurableSpace α] namespace MeasureTheory @@ -187,7 +187,7 @@ namespace SignedMeasure open scoped Classical open JordanDecomposition Measure Set VectorMeasure -variable {s : SignedMeasure α} {μ ν : Measure α} [IsFiniteMeasure μ] [IsFiniteMeasure ν] +variable {s : SignedMeasure α} /-- Given a signed measure `s`, `s.toJordanDecomposition` is the Jordan decomposition `j`, such that `s = j.toSignedMeasure`. This property is known as the Jordan decomposition diff --git a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean index 243efac2011bc..71f36a0f282cf 100644 --- a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean @@ -369,7 +369,7 @@ theorem rnDeriv_lt_top (μ ν : Measure α) [SigmaFinite μ] : ∀ᵐ x ∂ν, suffices ∀ n, ∀ᵐ x ∂ν, x ∈ spanningSets μ n → μ.rnDeriv ν x < ∞ by filter_upwards [ae_all_iff.2 this] with _ hx using hx _ (mem_spanningSetsIndex _ _) intro n - rw [← ae_restrict_iff' (measurable_spanningSets _ _)] + rw [← ae_restrict_iff' (measurableSet_spanningSets _ _)] apply ae_lt_top (measurable_rnDeriv _ _) refine (lintegral_rnDeriv_lt_top_of_measure_ne_top _ ?_).ne exact (measure_spanningSets_lt_top _ _).ne @@ -777,7 +777,7 @@ theorem iSup_mem_measurableLE (f : ℕ → α → ℝ≥0∞) (hf : ∀ n, f n (fun a : α ↦ ⨆ (k : ℕ) (_ : k ≤ m + 1), f k a) = fun a ↦ f m.succ a ⊔ ⨆ (k : ℕ) (_ : k ≤ m), f k a := funext fun _ ↦ iSup_succ_eq_sup _ _ _ - refine ⟨measurable_iSup fun n ↦ Measurable.iSup_Prop _ (hf n).1, fun A hA ↦ ?_⟩ + refine ⟨.iSup fun n ↦ Measurable.iSup_Prop _ (hf n).1, fun A hA ↦ ?_⟩ rw [this]; exact (sup_mem_measurableLE (hf m.succ) hm).2 A hA theorem iSup_mem_measurableLE' (f : ℕ → α → ℝ≥0∞) (hf : ∀ n, f n ∈ measurableLE μ ν) (n : ℕ) : @@ -846,7 +846,7 @@ theorem haveLebesgueDecomposition_of_finiteMeasure [IsFiniteMeasure μ] [IsFinit · refine Filter.Eventually.of_forall fun a ↦ ?_ simp [tendsto_atTop_iSup (iSup_monotone' f a)] have hξm : Measurable ξ := by - convert measurable_iSup fun n ↦ (iSup_mem_measurableLE _ hf₁ n).1 + convert Measurable.iSup fun n ↦ (iSup_mem_measurableLE _ hf₁ n).1 simp [hξ] -- `ξ` is the `f` in the theorem statement and we set `μ₁` to be `μ - ν.withDensity ξ` -- since we need `μ₁ + ν.withDensity ξ = μ` @@ -900,7 +900,7 @@ theorem haveLebesgueDecomposition_of_finiteMeasure [IsFiniteMeasure μ] [IsFinit (∫⁻ a in A ∩ E, ε + ξ a ∂ν) + ∫⁻ a in A \ E, ξ a ∂ν := by simp only [lintegral_add_left measurable_const, lintegral_add_left hξm, setLIntegral_const, add_assoc, lintegral_inter_add_diff _ _ hE₁, Pi.add_apply, - lintegral_indicator _ hE₁, restrict_apply hE₁] + lintegral_indicator hE₁, restrict_apply hE₁] rw [inter_comm, add_comm] rw [this, ← measure_inter_add_diff A hE₁] exact add_le_add (hε₂ A hA) (hξle (A \ E) (hA.diff hE₁)) @@ -908,7 +908,7 @@ theorem haveLebesgueDecomposition_of_finiteMeasure [IsFiniteMeasure μ] [IsFinit le_sSup ⟨ξ + E.indicator fun _ ↦ (ε : ℝ≥0∞), hξε, rfl⟩ -- but this contradicts the maximality of `∫⁻ x, ξ x ∂ν` refine not_lt.2 this ?_ - rw [hξ₁, lintegral_add_left hξm, lintegral_indicator _ hE₁, setLIntegral_const] + rw [hξ₁, lintegral_add_left hξm, lintegral_indicator hE₁, setLIntegral_const] refine ENNReal.lt_add_right ?_ (ENNReal.mul_pos_iff.2 ⟨ENNReal.coe_pos.2 hε₁, hE₂⟩).ne' have := measure_ne_top (ν.withDensity ξ) univ rwa [withDensity_apply _ MeasurableSet.univ, Measure.restrict_univ] at this @@ -922,7 +922,7 @@ then the same is true for any s-finite measure. -/ theorem HaveLebesgueDecomposition.sfinite_of_isFiniteMeasure [SFinite μ] (_h : ∀ (μ : Measure α) [IsFiniteMeasure μ], HaveLebesgueDecomposition μ ν) : HaveLebesgueDecomposition μ ν := - sum_sFiniteSeq μ ▸ sum_left _ + sum_sfiniteSeq μ ▸ sum_left _ attribute [local instance] haveLebesgueDecomposition_of_finiteMeasure @@ -938,7 +938,7 @@ nonrec instance (priority := 100) haveLebesgueDecomposition_of_sigmaFinite · exact .sfinite_of_isFiniteMeasure fun μ _ ↦ this μ ‹_› -- Take a disjoint cover that consists of sets of finite measure `ν`. set s : ℕ → Set α := disjointed (spanningSets ν) - have hsm : ∀ n, MeasurableSet (s n) := .disjointed <| measurable_spanningSets _ + have hsm : ∀ n, MeasurableSet (s n) := .disjointed <| measurableSet_spanningSets _ have hs : ∀ n, Fact (ν (s n) < ⊤) := fun n ↦ ⟨lt_of_le_of_lt (measure_mono <| disjointed_le ..) (measure_spanningSets_lt_top ν n)⟩ -- Note that the restrictions of `μ` and `ν` to `s n` are finite measures. diff --git a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean index 48bb69b5fadb2..133145051b3f2 100644 --- a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean +++ b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean @@ -88,7 +88,7 @@ lemma rnDeriv_pos' [HaveLebesgueDecomposition ν μ] [SigmaFinite μ] (hμν : section rnDeriv_withDensity_leftRight -variable {μ ν : Measure α} {f : α → ℝ≥0∞} +variable {f : α → ℝ≥0∞} /-- Auxiliary lemma for `rnDeriv_withDensity_left`. -/ lemma rnDeriv_withDensity_withDensity_rnDeriv_left (μ ν : Measure α) [SigmaFinite μ] [SigmaFinite ν] @@ -305,6 +305,9 @@ lemma setLIntegral_rnDeriv_le (s : Set α) : @[deprecated (since := "2024-06-29")] alias set_lintegral_rnDeriv_le := setLIntegral_rnDeriv_le +lemma lintegral_rnDeriv_le : ∫⁻ x, μ.rnDeriv ν x ∂ν ≤ μ Set.univ := + (setLIntegral_univ _).symm ▸ Measure.setLIntegral_rnDeriv_le Set.univ + lemma setLIntegral_rnDeriv' [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ ν) {s : Set α} (hs : MeasurableSet s) : ∫⁻ x in s, μ.rnDeriv ν x ∂ν = μ s := by @@ -388,13 +391,13 @@ alias set_integral_toReal_rnDeriv := setIntegral_toReal_rnDeriv lemma integral_toReal_rnDeriv [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ν) : ∫ x, (μ.rnDeriv ν x).toReal ∂ν = (μ Set.univ).toReal := by - rw [← integral_univ, setIntegral_toReal_rnDeriv hμν Set.univ] + rw [← setIntegral_univ, setIntegral_toReal_rnDeriv hμν Set.univ] lemma integral_toReal_rnDeriv' [IsFiniteMeasure μ] [SigmaFinite ν] : ∫ x, (μ.rnDeriv ν x).toReal ∂ν = (μ Set.univ).toReal - (μ.singularPart ν Set.univ).toReal := by rw [← ENNReal.toReal_sub_of_le (μ.singularPart_le ν Set.univ) (measure_ne_top _ _), ← Measure.sub_apply .univ (Measure.singularPart_le μ ν), Measure.measure_sub_singularPart, - ← Measure.setIntegral_toReal_rnDeriv_eq_withDensity, integral_univ] + ← Measure.setIntegral_toReal_rnDeriv_eq_withDensity, setIntegral_univ] end integral @@ -563,8 +566,8 @@ theorem integral_rnDeriv_smul [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ [SigmaFinite μ] {f : α → E} : ∫ x, (μ.rnDeriv ν x).toReal • f x ∂ν = ∫ x, f x ∂μ := by by_cases hf : Integrable f μ - · rw [← integral_univ, ← withDensityᵥ_apply ((integrable_rnDeriv_smul_iff hμν).mpr hf) .univ, - ← integral_univ, ← withDensityᵥ_apply hf .univ, withDensityᵥ_rnDeriv_smul hμν hf] + · rw [← setIntegral_univ, ← withDensityᵥ_apply ((integrable_rnDeriv_smul_iff hμν).mpr hf) .univ, + ← setIntegral_univ, ← withDensityᵥ_apply hf .univ, withDensityᵥ_rnDeriv_smul hμν hf] · rw [integral_undef hf, integral_undef] contrapose! hf exact (integrable_rnDeriv_smul_iff hμν).mp hf diff --git a/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean b/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean index 947cbabbc4212..77cd7b8a79759 100644 --- a/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean +++ b/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean @@ -312,7 +312,7 @@ theorem exists_subset_restrict_nonpos (hi : s i < 0) : · have : 1 / s E < bdd k := by linarith only [le_of_max_le_left (hk k le_rfl)] rw [one_div] at this ⊢ - rwa [inv_lt (lt_trans (inv_pos.2 hE₃) this) hE₃] + exact inv_lt_of_inv_lt₀ hE₃ this obtain ⟨k, hk₁, hk₂⟩ := this have hA' : A ⊆ i \ ⋃ l ≤ k, restrictNonposSeq s i l := by apply Set.diff_subset_diff_right diff --git a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean index a74a832aa9956..7652993309eaf 100644 --- a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean @@ -46,7 +46,7 @@ open scoped Classical MeasureTheory NNReal ENNReal open Set -variable {α β : Type*} {m : MeasurableSpace α} {μ ν : MeasureTheory.Measure α} +variable {α : Type*} {m : MeasurableSpace α} {μ : MeasureTheory.Measure α} namespace MeasureTheory diff --git a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean index 37c95e1795cb8..ce393e78fea5c 100644 --- a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean +++ b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean @@ -63,7 +63,7 @@ theorem ae_eq_zero_of_forall_inner [NormedAddCommGroup E] [InnerProductSpace rw [Pi.zero_apply, ← @inner_self_eq_zero 𝕜] have h_closed : IsClosed {c : E | inner c (f x) = (0 : 𝕜)} := isClosed_eq (continuous_id.inner continuous_const) continuous_const - exact @isClosed_property ℕ E _ s (fun c => inner c (f x) = (0 : 𝕜)) hs h_closed (fun n => hx n) _ + exact @isClosed_property ℕ E _ s (fun c => inner c (f x) = (0 : 𝕜)) hs h_closed hx _ local notation "⟪" x ", " y "⟫" => y x @@ -113,7 +113,7 @@ variable {𝕜} end AeEqOfForall -variable {α E : Type*} {m m0 : MeasurableSpace α} {μ : Measure α} {s t : Set α} +variable {α E : Type*} {m m0 : MeasurableSpace α} {μ : Measure α} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] {p : ℝ≥0∞} section AeEqOfForallSetIntegralEq @@ -423,10 +423,10 @@ theorem ae_eq_zero_of_forall_setIntegral_eq_of_sigmaFinite [SigmaFinite μ] {f : (hf_zero : ∀ s : Set α, MeasurableSet s → μ s < ∞ → ∫ x in s, f x ∂μ = 0) : f =ᵐ[μ] 0 := by let S := spanningSets μ rw [← @Measure.restrict_univ _ _ μ, ← iUnion_spanningSets μ, EventuallyEq, ae_iff, - Measure.restrict_apply' (MeasurableSet.iUnion (measurable_spanningSets μ))] + Measure.restrict_apply' (MeasurableSet.iUnion (measurableSet_spanningSets μ))] rw [Set.inter_iUnion, measure_iUnion_null_iff] intro n - have h_meas_n : MeasurableSet (S n) := measurable_spanningSets μ n + have h_meas_n : MeasurableSet (S n) := measurableSet_spanningSets μ n have hμn : μ (S n) < ∞ := measure_spanningSets_lt_top μ n rw [← Measure.restrict_apply' h_meas_n] exact ae_eq_zero_restrict_of_forall_setIntegral_eq_zero hf_int_finite hf_zero h_meas_n hμn.ne @@ -590,7 +590,7 @@ lemma ae_eq_zero_of_forall_setIntegral_isClosed_eq_zero {μ : Measure β} {f : have A : ∀ (t : Set β), MeasurableSet t → ∫ (x : β) in t, f x ∂μ = 0 → ∫ (x : β) in tᶜ, f x ∂μ = 0 := by intro t t_meas ht - have I : ∫ x, f x ∂μ = 0 := by rw [← integral_univ]; exact h'f _ isClosed_univ + have I : ∫ x, f x ∂μ = 0 := by rw [← setIntegral_univ]; exact h'f _ isClosed_univ simpa [ht, I] using integral_add_compl t_meas hf intro s hs refine MeasurableSet.induction_on_open (fun U hU ↦ ?_) A (fun g g_disj g_meas hg ↦ ?_) hs diff --git a/Mathlib/MeasureTheory/Function/AEMeasurableOrder.lean b/Mathlib/MeasureTheory/Function/AEMeasurableOrder.lean index 7d3d2817a1aba..0f4dba7c8de33 100644 --- a/Mathlib/MeasureTheory/Function/AEMeasurableOrder.lean +++ b/Mathlib/MeasureTheory/Function/AEMeasurableOrder.lean @@ -54,9 +54,7 @@ theorem MeasureTheory.aemeasurable_of_exist_almost_disjoint_supersets {α : Type intro i exact MeasurableSet.biInter (s_count.mono inter_subset_left) fun b _ => (huv i b).1 let f' : α → β := fun x => ⨅ i : s, piecewise (u' i) (fun _ => (i : β)) (fun _ => (⊤ : β)) x - have f'_meas : Measurable f' := by - apply measurable_iInf - exact fun i => Measurable.piecewise (u'_meas i) measurable_const measurable_const + have f'_meas : Measurable f' := by fun_prop (disch := aesop) let t := ⋃ (p : s) (q : ↥(s ∩ Ioi p)), u' p ∩ v p q have μt : μ t ≤ 0 := calc diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean index 98a2a41d0a279..95319082eb996 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean @@ -175,17 +175,10 @@ theorem AEStronglyMeasurable'.aeStronglyMeasurable'_of_measurableSpace_le_on {α hf_ind.stronglyMeasurable_of_measurableSpace_le_on hs_m hs fun x hxs => Set.indicator_of_not_mem hxs _ -variable {α E' F F' 𝕜 : Type*} {p : ℝ≥0∞} [RCLike 𝕜] +variable {α F 𝕜 : Type*} {p : ℝ≥0∞} [RCLike 𝕜] -- 𝕜 for ℝ or ℂ - -- E' for an inner product space on which we compute integrals - [NormedAddCommGroup E'] - [InnerProductSpace 𝕜 E'] [CompleteSpace E'] [NormedSpace ℝ E'] -- F for a Lp submodule - [NormedAddCommGroup F] - [NormedSpace 𝕜 F] - -- F' for integrals on a Lp submodule - [NormedAddCommGroup F'] - [NormedSpace 𝕜 F'] [NormedSpace ℝ F'] [CompleteSpace F'] + [NormedAddCommGroup F] [NormedSpace 𝕜 F] section LpMeas @@ -257,7 +250,7 @@ measure `μ.trim hm`. As a consequence, the completeness of `Lp` implies complet `lpMeasSubgroup` (and `lpMeas`). -/ -variable {ι : Type*} {m m0 : MeasurableSpace α} {μ : Measure α} +variable {m m0 : MeasurableSpace α} {μ : Measure α} /-- If `f` belongs to `lpMeasSubgroup F m p μ`, then the measurable function it is almost everywhere equal to (given by `AEMeasurable.mk`) belongs to `ℒp` for the measure `μ.trim hm`. -/ diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean index daab2ab684f35..8b2d1dfe66dd5 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean @@ -69,7 +69,7 @@ open scoped ENNReal Topology MeasureTheory namespace MeasureTheory -variable {α F F' 𝕜 : Type*} {p : ℝ≥0∞} [RCLike 𝕜] +variable {α F F' 𝕜 : Type*} [RCLike 𝕜] -- 𝕜 for ℝ or ℂ -- F' for integrals on a Lp submodule [NormedAddCommGroup F'] @@ -208,7 +208,7 @@ theorem integral_condexp (hm : m ≤ m0) [hμm : SigmaFinite (μ.trim hm)] : ∫ x, (μ[f|m]) x ∂μ = ∫ x, f x ∂μ := by by_cases hf : Integrable f μ · suffices ∫ x in Set.univ, (μ[f|m]) x ∂μ = ∫ x in Set.univ, f x ∂μ by - simp_rw [integral_univ] at this; exact this + simp_rw [setIntegral_univ] at this; exact this exact setIntegral_condexp hm hf (@MeasurableSet.univ _ m) simp only [condexp_undef hf, Pi.zero_apply, integral_zero, integral_undef hf] diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean index a0b70b96c1884..cdd2dddd698c5 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean @@ -35,7 +35,7 @@ open scoped NNReal ENNReal Topology MeasureTheory namespace MeasureTheory -variable {α β F F' G G' 𝕜 : Type*} {p : ℝ≥0∞} [RCLike 𝕜] +variable {α F F' G G' 𝕜 : Type*} [RCLike 𝕜] -- 𝕜 for ℝ or ℂ -- F for a Lp submodule [NormedAddCommGroup F] @@ -135,7 +135,7 @@ theorem norm_condexpIndL1Fin_le (hs : MeasurableSet s) (hμs : μ s ≠ ∞) (x exact lintegral_nnnorm_condexpIndSMul_le hm hs hμs x theorem condexpIndL1Fin_disjoint_union (hs : MeasurableSet s) (ht : MeasurableSet t) (hμs : μ s ≠ ∞) - (hμt : μ t ≠ ∞) (hst : s ∩ t = ∅) (x : G) : + (hμt : μ t ≠ ∞) (hst : Disjoint s t) (x : G) : condexpIndL1Fin hm (hs.union ht) ((measure_union_le s t).trans_lt (lt_top_iff_ne_top.mpr (ENNReal.add_ne_top.mpr ⟨hμs, hμt⟩))).ne x = condexpIndL1Fin hm hs hμs x + condexpIndL1Fin hm ht hμt x := by @@ -224,7 +224,7 @@ theorem continuous_condexpIndL1 : Continuous fun x : G => condexpIndL1 hm μ s x continuous_of_linear_of_bound condexpIndL1_add condexpIndL1_smul norm_condexpIndL1_le theorem condexpIndL1_disjoint_union (hs : MeasurableSet s) (ht : MeasurableSet t) (hμs : μ s ≠ ∞) - (hμt : μ t ≠ ∞) (hst : s ∩ t = ∅) (x : G) : + (hμt : μ t ≠ ∞) (hst : Disjoint s t) (x : G) : condexpIndL1 hm μ (s ∪ t) x = condexpIndL1 hm μ s x + condexpIndL1 hm μ t x := by have hμst : μ (s ∪ t) ≠ ∞ := ((measure_union_le s t).trans_lt (lt_top_iff_ne_top.mpr (ENNReal.add_ne_top.mpr ⟨hμs, hμt⟩))).ne @@ -283,12 +283,12 @@ theorem norm_condexpInd_le : ‖(condexpInd G hm μ s : G →L[ℝ] α →₁[μ ContinuousLinearMap.opNorm_le_bound _ ENNReal.toReal_nonneg norm_condexpInd_apply_le theorem condexpInd_disjoint_union_apply (hs : MeasurableSet s) (ht : MeasurableSet t) - (hμs : μ s ≠ ∞) (hμt : μ t ≠ ∞) (hst : s ∩ t = ∅) (x : G) : + (hμs : μ s ≠ ∞) (hμt : μ t ≠ ∞) (hst : Disjoint s t) (x : G) : condexpInd G hm μ (s ∪ t) x = condexpInd G hm μ s x + condexpInd G hm μ t x := condexpIndL1_disjoint_union hs ht hμs hμt hst x theorem condexpInd_disjoint_union (hs : MeasurableSet s) (ht : MeasurableSet t) (hμs : μ s ≠ ∞) - (hμt : μ t ≠ ∞) (hst : s ∩ t = ∅) : (condexpInd G hm μ (s ∪ t) : G →L[ℝ] α →₁[μ] G) = + (hμt : μ t ≠ ∞) (hst : Disjoint s t) : (condexpInd G hm μ (s ∪ t) : G →L[ℝ] α →₁[μ] G) = condexpInd G hm μ s + condexpInd G hm μ t := by ext1 x; push_cast; exact condexpInd_disjoint_union_apply hs ht hμs hμt hst x @@ -395,7 +395,7 @@ to the integral of `f` on that set. See also `setIntegral_condexp`, the similar theorem setIntegral_condexpL1CLM (f : α →₁[μ] F') (hs : MeasurableSet[m] s) : ∫ x in s, condexpL1CLM F' hm μ f x ∂μ = ∫ x in s, f x ∂μ := by let S := spanningSets (μ.trim hm) - have hS_meas : ∀ i, MeasurableSet[m] (S i) := measurable_spanningSets (μ.trim hm) + have hS_meas : ∀ i, MeasurableSet[m] (S i) := measurableSet_spanningSets (μ.trim hm) have hS_meas0 : ∀ i, MeasurableSet (S i) := fun i => hm _ (hS_meas i) have hs_eq : s = ⋃ i, S i ∩ s := by simp_rw [Set.inter_comm] diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean index fd79dc7a0b777..54f8441a10130 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean @@ -38,7 +38,7 @@ open scoped ENNReal Topology MeasureTheory namespace MeasureTheory -variable {α E E' F G G' 𝕜 : Type*} {p : ℝ≥0∞} [RCLike 𝕜] +variable {α E E' F G G' 𝕜 : Type*} [RCLike 𝕜] -- 𝕜 for ℝ or ℂ -- E for an inner product space [NormedAddCommGroup E] @@ -203,7 +203,7 @@ theorem lintegral_nnnorm_condexpL2_indicator_le_real (hs : MeasurableSet s) (hμ classical simp_rw [Set.indicator_apply] split_ifs <;> simp - rw [h_eq, lintegral_indicator _ hs, lintegral_const, Measure.restrict_restrict hs] + rw [h_eq, lintegral_indicator hs, lintegral_const, Measure.restrict_restrict hs] simp only [one_mul, Set.univ_inter, MeasurableSet.univ, Measure.restrict_apply] end Real @@ -457,7 +457,7 @@ theorem setIntegral_condexpIndSMul (hs : MeasurableSet[m] s) (ht : MeasurableSet ∫ a in s, (condexpIndSMul hm ht hμt x) a ∂μ = ∫ a in s, (condexpL2 ℝ ℝ hm (indicatorConstLp 2 ht hμt 1) : α → ℝ) a • x ∂μ := setIntegral_congr_ae (hm s hs) - ((condexpIndSMul_ae_eq_smul hm ht hμt x).mono fun x hx _ => hx) + ((condexpIndSMul_ae_eq_smul hm ht hμt x).mono fun _ hx _ => hx) _ = (∫ a in s, (condexpL2 ℝ ℝ hm (indicatorConstLp 2 ht hμt 1) : α → ℝ) a ∂μ) • x := (integral_smul_const _ x) _ = (μ (t ∩ s)).toReal • x := by rw [setIntegral_condexpL2_indicator hs ht hμs hμt] diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Indicator.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Indicator.lean index ac39db1fcf879..260205e45cac9 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Indicator.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Indicator.lean @@ -30,7 +30,7 @@ open scoped NNReal ENNReal Topology MeasureTheory namespace MeasureTheory -variable {α 𝕜 E : Type*} {m m0 : MeasurableSpace α} [NormedAddCommGroup E] [NormedSpace ℝ E] +variable {α E : Type*} {m m0 : MeasurableSpace α} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] {μ : Measure α} {f : α → E} {s : Set α} theorem condexp_ae_eq_restrict_zero (hs : MeasurableSet[m] s) (hf : f =ᵐ[μ.restrict s] 0) : diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean index ef56edebde96d..aa7f322d0889d 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean @@ -37,7 +37,7 @@ variable {α E' F' 𝕜 : Type*} {p : ℝ≥0∞} {m m0 : MeasurableSpace α} { [InnerProductSpace 𝕜 E'] [CompleteSpace E'] [NormedSpace ℝ E'] -- F' for integrals on a Lp submodule [NormedAddCommGroup F'] - [NormedSpace 𝕜 F'] [NormedSpace ℝ F'] [CompleteSpace F'] + [NormedSpace ℝ F'] [CompleteSpace F'] section UniquenessOfConditionalExpectation diff --git a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean index 2d82b8b7e4d4e..f9a7daf12fa48 100644 --- a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean +++ b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean @@ -208,7 +208,8 @@ theorem TendstoInMeasure.exists_seq_tendsto_ae (hfg : TendstoInMeasure μ f atTo congr rw [← pow_one (2 : ℝ)⁻¹] rw [← pow_add, add_comm] - exact pow_le_pow_of_le_one (one_div (2 : ℝ) ▸ one_half_pos.le) (inv_le_one one_le_two) + exact pow_le_pow_of_le_one (one_div (2 : ℝ) ▸ one_half_pos.le) + (inv_le_one_of_one_le₀ one_le_two) ((le_tsub_add.trans (add_le_add_right (le_max_right _ _) 1)).trans (add_le_add_right hn_ge 1)) exact le_trans hNx.le h_inv_n_le_k diff --git a/Mathlib/MeasureTheory/Function/Egorov.lean b/Mathlib/MeasureTheory/Function/Egorov.lean index 932a6fefb1d33..93797f4c9e62b 100644 --- a/Mathlib/MeasureTheory/Function/Egorov.lean +++ b/Mathlib/MeasureTheory/Function/Egorov.lean @@ -42,7 +42,7 @@ This definition is useful for Egorov's theorem. -/ def notConvergentSeq [Preorder ι] (f : ι → α → β) (g : α → β) (n : ℕ) (j : ι) : Set α := ⋃ (k) (_ : j ≤ k), { x | 1 / (n + 1 : ℝ) < dist (f k x) (g x) } -variable {n : ℕ} {i j : ι} {s : Set α} {ε : ℝ} {f : ι → α → β} {g : α → β} +variable {n : ℕ} {j : ι} {s : Set α} {ε : ℝ} {f : ι → α → β} {g : α → β} theorem mem_notConvergentSeq_iff [Preorder ι] {x : α} : x ∈ notConvergentSeq f g n j ↔ ∃ k ≥ j, 1 / (n + 1 : ℝ) < dist (f k x) (g x) := by @@ -171,7 +171,7 @@ theorem tendstoUniformlyOn_diff_iUnionNotConvergentSeq (hε : 0 < ε) end Egorov -variable [SemilatticeSup ι] [Nonempty ι] [Countable ι] {γ : Type*} [TopologicalSpace γ] +variable [SemilatticeSup ι] [Nonempty ι] [Countable ι] {f : ι → α → β} {g : α → β} {s : Set α} /-- **Egorov's theorem**: If `f : ι → α → β` is a sequence of strongly measurable functions that diff --git a/Mathlib/MeasureTheory/Function/EssSup.lean b/Mathlib/MeasureTheory/Function/EssSup.lean index 503c49f68e8df..08d14b549d3b7 100644 --- a/Mathlib/MeasureTheory/Function/EssSup.lean +++ b/Mathlib/MeasureTheory/Function/EssSup.lean @@ -6,6 +6,7 @@ Authors: Rémy Degenne import Mathlib.MeasureTheory.Constructions.BorelSpace.Order import Mathlib.MeasureTheory.Measure.Count import Mathlib.Order.Filter.ENNReal +import Mathlib.Probability.UniformOn /-! # Essential supremum and infimum @@ -28,9 +29,8 @@ sense). We do not define that quantity here, which is simply the supremum of a m -/ -open MeasureTheory Filter Set TopologicalSpace - -open ENNReal MeasureTheory NNReal +open Filter MeasureTheory ProbabilityTheory Set TopologicalSpace +open scoped ENNReal NNReal variable {α β : Type*} {m : MeasurableSpace α} {μ ν : Measure α} @@ -94,6 +94,14 @@ variable [MeasurableSingletonClass α] @[simp] lemma essInf_count_eq_ciInf (hf : BddBelow (Set.range f)) : essInf f .count = ⨅ a, f a := essInf_eq_ciInf (by simp) hf +@[simp] lemma essSup_uniformOn_eq_ciSup [Finite α] (hf : BddAbove (Set.range f)) : + essSup f (uniformOn univ) = ⨆ a, f a := + essSup_eq_ciSup (by simp [uniformOn, cond_apply, Set.finite_univ]) hf + +@[simp] lemma essInf_cond_count_eq_ciInf [Finite α] (hf : BddBelow (Set.range f)) : + essInf f (uniformOn univ) = ⨅ a, f a := + essInf_eq_ciInf (by simp [uniformOn, cond_apply, Set.finite_univ]) hf + end ConditionallyCompleteLattice section ConditionallyCompleteLinearOrder diff --git a/Mathlib/MeasureTheory/Function/Intersectivity.lean b/Mathlib/MeasureTheory/Function/Intersectivity.lean index 5ea828b2fcf5b..c571061c05018 100644 --- a/Mathlib/MeasureTheory/Function/Intersectivity.lean +++ b/Mathlib/MeasureTheory/Function/Intersectivity.lean @@ -61,8 +61,7 @@ lemma bergelson' {s : ℕ → Set α} (hs : ∀ n, MeasurableSet (s n)) (hr₀ : have hfapp : ∀ n a, f n a = (↑(n + 1))⁻¹ * ∑ k in Finset.range (n + 1), (s k).indicator 1 a := by simp only [f, Pi.natCast_def, Pi.smul_apply, Pi.inv_apply, Finset.sum_apply, eq_self_iff_true, forall_const, imp_true_iff, smul_eq_mul] - have hf n : Measurable (f n) := Measurable.mul' (@measurable_const ℝ≥0∞ _ _ _ (↑(n + 1))⁻¹) - (Finset.measurable_sum' _ fun i _ ↦ measurable_one.indicator <| hs i) + have hf n : Measurable (f n) := by fun_prop (disch := exact hs _) have hf₁ n : f n ≤ 1 := by rintro a rw [hfapp, ← ENNReal.div_eq_inv_mul] diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index ce6116b747cb5..77a1878659c77 100644 --- a/Mathlib/MeasureTheory/Function/Jacobian.lean +++ b/Mathlib/MeasureTheory/Function/Jacobian.lean @@ -883,7 +883,7 @@ theorem addHaar_image_le_lintegral_abs_det_fderiv (hs : MeasurableSet s) have u_meas : ∀ n, MeasurableSet (u n) := by intro n apply MeasurableSet.disjointed fun i => ?_ - exact measurable_spanningSets μ i + exact measurableSet_spanningSets μ i have A : s = ⋃ n, s ∩ u n := by rw [← inter_iUnion, iUnion_disjointed, iUnion_spanningSets, inter_univ] calc @@ -1035,7 +1035,7 @@ theorem lintegral_abs_det_fderiv_le_addHaar_image (hs : MeasurableSet s) have u_meas : ∀ n, MeasurableSet (u n) := by intro n apply MeasurableSet.disjointed fun i => ?_ - exact measurable_spanningSets μ i + exact measurableSet_spanningSets μ i have A : s = ⋃ n, s ∩ u n := by rw [← inter_iUnion, iUnion_disjointed, iUnion_spanningSets, inter_univ] calc diff --git a/Mathlib/MeasureTheory/Function/L1Space.lean b/Mathlib/MeasureTheory/Function/L1Space.lean index 9994ae4d6e8b1..87c029742d760 100644 --- a/Mathlib/MeasureTheory/Function/L1Space.lean +++ b/Mathlib/MeasureTheory/Function/L1Space.lean @@ -1375,12 +1375,10 @@ theorem edist_toL1_toL1 (f g : α → β) (hf : Integrable f μ) (hg : Integrabl ENNReal.rpow_one, ne_eq, not_false_eq_true, div_self, ite_false] simp [edist_eq_coe_nnnorm_sub] -@[simp] theorem edist_toL1_zero (f : α → β) (hf : Integrable f μ) : edist (hf.toL1 f) 0 = ∫⁻ a, edist (f a) 0 ∂μ := by - simp only [toL1, Lp.edist_toLp_zero, eLpNorm, one_ne_zero, eLpNorm', one_toReal, ENNReal.rpow_one, - ne_eq, not_false_eq_true, div_self, ite_false] - simp [edist_eq_coe_nnnorm] + simp only [edist_zero_right, Lp.nnnorm_coe_ennreal, toL1_eq_mk, eLpNorm_aeeqFun] + apply eLpNorm_one_eq_lintegral_nnnorm variable {𝕜 : Type*} [NormedRing 𝕜] [Module 𝕜 β] [BoundedSMul 𝕜 β] diff --git a/Mathlib/MeasureTheory/Function/LpOrder.lean b/Mathlib/MeasureTheory/Function/LpOrder.lean index 86290745da5ec..07bfca33ec50e 100644 --- a/Mathlib/MeasureTheory/Function/LpOrder.lean +++ b/Mathlib/MeasureTheory/Function/LpOrder.lean @@ -45,7 +45,7 @@ theorem coeFn_nonneg (f : Lp E p μ) : 0 ≤ᵐ[μ] f ↔ 0 ≤ f := by · rwa [h2] · rwa [← h2] -instance instCovariantClassLE : CovariantClass (Lp E p μ) (Lp E p μ) (· + ·) (· ≤ ·) := by +instance instAddLeftMono : AddLeftMono (Lp E p μ) := by refine ⟨fun f g₁ g₂ hg₁₂ => ?_⟩ rw [← coeFn_le] at hg₁₂ ⊢ filter_upwards [coeFn_add f g₁, coeFn_add f g₂, hg₁₂] with _ h1 h2 h3 @@ -90,7 +90,7 @@ theorem coeFn_abs (f : Lp E p μ) : ⇑|f| =ᵐ[μ] fun x => |f x| := noncomputable instance instNormedLatticeAddCommGroup [Fact (1 ≤ p)] : NormedLatticeAddCommGroup (Lp E p μ) := { Lp.instLattice, Lp.instNormedAddCommGroup with - add_le_add_left := fun f g => add_le_add_left + add_le_add_left := fun _ _ => add_le_add_left solid := fun f g hfg => by rw [← coeFn_le] at hfg simp_rw [Lp.norm_def, ENNReal.toReal_le_toReal (Lp.eLpNorm_ne_top f) (Lp.eLpNorm_ne_top g)] diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean index fdf5f19ca96be..71c2449fa8236 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean @@ -139,7 +139,7 @@ alias lintegral_rpow_nnnorm_eq_rpow_snorm' := lintegral_rpow_nnnorm_eq_rpow_eLpN lemma eLpNorm_nnreal_pow_eq_lintegral {f : α → F} {p : ℝ≥0} (hp : p ≠ 0) : eLpNorm f p μ ^ (p : ℝ) = ∫⁻ x, ‖f x‖₊ ^ (p : ℝ) ∂μ := by simp [eLpNorm_eq_eLpNorm' (by exact_mod_cast hp) ENNReal.coe_ne_top, - lintegral_rpow_nnnorm_eq_rpow_eLpNorm' (show 0 < (p : ℝ) from pos_iff_ne_zero.mpr hp)] + lintegral_rpow_nnnorm_eq_rpow_eLpNorm' ((NNReal.coe_pos.trans pos_iff_ne_zero).mpr hp)] @[deprecated (since := "2024-07-27")] alias snorm_nnreal_pow_eq_lintegral := eLpNorm_nnreal_pow_eq_lintegral @@ -335,7 +335,7 @@ theorem eLpNorm_indicator_eq_restrict {f : α → E} {s : Set α} (hs : Measurab ← ENNReal.essSup_indicator_eq_essSup_restrict hs, ENNReal.coe_indicator, nnnorm_indicator_eq_indicator_nnnorm] · rcases eq_or_ne p 0 with rfl | hp₀; · simp - simp only [eLpNorm_eq_lintegral_rpow_nnnorm hp₀ hp, ← lintegral_indicator _ hs, + simp only [eLpNorm_eq_lintegral_rpow_nnnorm hp₀ hp, ← lintegral_indicator hs, ENNReal.coe_indicator, nnnorm_indicator_eq_indicator_nnnorm] congr with x by_cases hx : x ∈ s <;> simp [ENNReal.toReal_pos, *] @@ -721,6 +721,13 @@ theorem Memℒp.of_bound [IsFiniteMeasure μ] {f : α → E} (hf : AEStronglyMea (hfC : ∀ᵐ x ∂μ, ‖f x‖ ≤ C) : Memℒp f p μ := (memℒp_const C).of_le hf (hfC.mono fun _x hx => le_trans hx (le_abs_self _)) +theorem memℒp_of_bounded [IsFiniteMeasure μ] + {a b : ℝ} {f : α → ℝ} (h : ∀ᵐ x ∂μ, f x ∈ Set.Icc a b) + (hX : AEStronglyMeasurable f μ) (p : ENNReal) : Memℒp f p μ := + have ha : ∀ᵐ x ∂μ, a ≤ f x := h.mono fun ω h => h.1 + 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] theorem eLpNorm'_mono_measure (f : α → F) (hμν : ν ≤ μ) (hq : 0 ≤ q) : eLpNorm' f q ν ≤ eLpNorm' f q μ := by @@ -1113,7 +1120,7 @@ theorem eLpNormEssSup_le_nnreal_smul_eLpNormEssSup_of_ae_le_mul {f : α → F} { (h : ∀ᵐ x ∂μ, ‖f x‖₊ ≤ c * ‖g x‖₊) : eLpNormEssSup f μ ≤ c • eLpNormEssSup g μ := calc essSup (fun x => (‖f x‖₊ : ℝ≥0∞)) μ ≤ essSup (fun x => (↑(c * ‖g x‖₊) : ℝ≥0∞)) μ := - essSup_mono_ae <| h.mono fun x hx => ENNReal.coe_le_coe.mpr hx + essSup_mono_ae <| h.mono fun _ hx => ENNReal.coe_le_coe.mpr hx _ = essSup (fun x => (c * ‖g x‖₊ : ℝ≥0∞)) μ := by simp_rw [ENNReal.coe_mul] _ = c • essSup (fun x => (‖g x‖₊ : ℝ≥0∞)) μ := ENNReal.essSup_const_mul @@ -1273,7 +1280,7 @@ theorem le_eLpNorm_of_bddBelow (hp : p ≠ 0) (hp' : p ≠ ∞) {f : α → F} ( one_div, ENNReal.le_rpow_inv_iff (ENNReal.toReal_pos hp hp'), ENNReal.mul_rpow_of_nonneg _ _ ENNReal.toReal_nonneg, ← ENNReal.rpow_mul, inv_mul_cancel₀ (ENNReal.toReal_pos hp hp').ne.symm, ENNReal.rpow_one, ← setLIntegral_const, - ← lintegral_indicator _ hs] + ← lintegral_indicator hs] refine lintegral_mono_ae ?_ filter_upwards [hf] with x hx by_cases hxs : x ∈ s @@ -1325,7 +1332,7 @@ theorem ae_bdd_liminf_atTop_rpow_of_eLpNorm_bdd {p : ℝ≥0∞} {f : ℕ → α have hp : p ≠ 0 := fun h => by simp [h] at hp0 have hp' : p ≠ ∞ := fun h => by simp [h] at hp0 refine - ae_lt_top (measurable_liminf fun n => (hfmeas n).nnnorm.coe_nnreal_ennreal.pow_const p.toReal) + ae_lt_top (.liminf fun n => (hfmeas n).nnnorm.coe_nnreal_ennreal.pow_const p.toReal) (lt_of_le_of_lt (lintegral_liminf_le fun n => (hfmeas n).nnnorm.coe_nnreal_ennreal.pow_const p.toReal) (lt_of_le_of_lt ?_ diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean index dcafb2aeecbec..e7723bfa145de 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean @@ -126,7 +126,7 @@ theorem eLpNorm'_lt_top_of_eLpNorm'_lt_top_of_exponent_le {p q : ℝ} [IsFiniteM _ < ∞ := by rw [ENNReal.mul_lt_top_iff] refine Or.inl ⟨hfq_lt_top, ENNReal.rpow_lt_top_of_nonneg ?_ (measure_ne_top μ Set.univ)⟩ - rwa [le_sub_comm, sub_zero, one_div, one_div, inv_le_inv hq_pos hp_pos] + rwa [le_sub_comm, sub_zero, one_div, one_div, inv_le_inv₀ hq_pos hp_pos] @[deprecated (since := "2024-07-27")] alias snorm'_lt_top_of_snorm'_lt_top_of_exponent_le := diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean index 42f9edb4bd2b4..cc56d954aa492 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean @@ -88,9 +88,8 @@ theorem LpAddConst_lt_top (p : ℝ≥0∞) : LpAddConst p < ∞ := by rw [LpAddConst] split_ifs with h · apply ENNReal.rpow_lt_top_of_nonneg _ ENNReal.two_ne_top - simp only [one_div, sub_nonneg] - apply one_le_inv (ENNReal.toReal_pos h.1.ne' (h.2.trans ENNReal.one_lt_top).ne) - simpa using ENNReal.toReal_mono ENNReal.one_ne_top h.2.le + rw [one_div, sub_nonneg, ← ENNReal.toReal_inv, ← ENNReal.one_toReal] + exact ENNReal.toReal_mono (by simpa using h.1.ne') (ENNReal.one_le_inv.2 h.2.le) · exact ENNReal.one_lt_top theorem eLpNorm_add_le' (hf : AEStronglyMeasurable f μ) (hg : AEStronglyMeasurable g μ) diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index 5410247494af6..adb2b6dba2e06 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -254,7 +254,7 @@ theorem nnnorm_coe_ennreal (f : Lp E p μ) : (‖f‖₊ : ℝ≥0∞) = eLpNorm @[simp] lemma norm_toLp (f : α → E) (hf : Memℒp f p μ) : ‖hf.toLp f‖ = ENNReal.toReal (eLpNorm f p μ) := by - erw [norm_def, eLpNorm_congr_ae (Memℒp.coeFn_toLp hf)] + rw [norm_def, eLpNorm_congr_ae (Memℒp.coeFn_toLp hf)] @[simp] theorem nnnorm_toLp (f : α → E) (hf : Memℒp f p μ) : @@ -406,7 +406,7 @@ instance instNormedAddCommGroup [hp : Fact (1 ≤ p)] : NormedAddCommGroup (Lp E simp only [Lp.nnnorm_coe_ennreal] exact (eLpNorm_congr_ae (AEEqFun.coeFn_add _ _)).trans_le (eLpNorm_add_le (Lp.aestronglyMeasurable _) (Lp.aestronglyMeasurable _) hp.out) - eq_zero_of_map_eq_zero' := fun f => + eq_zero_of_map_eq_zero' := fun _ => (norm_eq_zero_iff <| zero_lt_one.trans_le hp.1).1 } with edist := edist edist_dist := Lp.edist_dist } @@ -616,7 +616,7 @@ theorem eLpNorm_indicator_eq_eLpNorm_restrict {f : α → F} (hs : MeasurableSet simp_rw [eLpNorm_eq_lintegral_rpow_nnnorm hp_zero hp_top] suffices (∫⁻ x, (‖s.indicator f x‖₊ : ℝ≥0∞) ^ p.toReal ∂μ) = ∫⁻ x in s, (‖f x‖₊ : ℝ≥0∞) ^ p.toReal ∂μ by rw [this] - rw [← lintegral_indicator _ hs] + rw [← lintegral_indicator hs] congr simp_rw [nnnorm_indicator_eq_indicator_nnnorm, ENNReal.coe_indicator] have h_zero : (fun x => x ^ p.toReal) (0 : ℝ≥0∞) = 0 := by @@ -857,7 +857,7 @@ theorem memℒp_add_of_disjoint {f g : α → E} (h : Disjoint (support f) (supp /-- The indicator of a disjoint union of two sets is the sum of the indicators of the sets. -/ theorem indicatorConstLp_disjoint_union {s t : Set α} (hs : MeasurableSet s) (ht : MeasurableSet t) - (hμs : μ s ≠ ∞) (hμt : μ t ≠ ∞) (hst : s ∩ t = ∅) (c : E) : + (hμs : μ s ≠ ∞) (hμt : μ t ≠ ∞) (hst : Disjoint s t) (c : E) : indicatorConstLp p (hs.union ht) (measure_union_ne_top hμs hμt) c = indicatorConstLp p hs hμs c + indicatorConstLp p ht hμt c := by ext1 @@ -865,7 +865,7 @@ theorem indicatorConstLp_disjoint_union {s t : Set α} (hs : MeasurableSet s) (h refine EventuallyEq.trans ?_ (EventuallyEq.add indicatorConstLp_coeFn.symm indicatorConstLp_coeFn.symm) - rw [Set.indicator_union_of_disjoint (Set.disjoint_iff_inter_eq_empty.mpr hst) _] + rw [Set.indicator_union_of_disjoint hst] end IndicatorConstLp @@ -1064,7 +1064,7 @@ theorem MeasureTheory.Memℒp.of_comp_antilipschitzWith {α E F} {K'} [Measurabl rw [← dist_zero_right, ← dist_zero_right, ← g0] apply hg'.le_mul_dist have B : AEStronglyMeasurable f μ := - (hg'.isUniformEmbedding hg).embedding.aestronglyMeasurable_comp_iff.1 hL.1 + (hg'.isUniformEmbedding hg).isEmbedding.aestronglyMeasurable_comp_iff.1 hL.1 exact hL.of_le_mul B (Filter.Eventually.of_forall A) namespace LipschitzWith @@ -1435,8 +1435,8 @@ theorem cauchySeq_Lp_iff_cauchySeq_ℒp {ι} [Nonempty ι] [SemilatticeSup ι] [ theorem completeSpace_lp_of_cauchy_complete_ℒp [hp : Fact (1 ≤ p)] (H : - ∀ (f : ℕ → α → E) (hf : ∀ n, Memℒp (f n) p μ) (B : ℕ → ℝ≥0∞) (hB : ∑' i, B i < ∞) - (h_cau : ∀ N n m : ℕ, N ≤ n → N ≤ m → eLpNorm (f n - f m) p μ < B N), + ∀ (f : ℕ → α → E) (_ : ∀ n, Memℒp (f n) p μ) (B : ℕ → ℝ≥0∞) (_ : ∑' i, B i < ∞) + (_ : ∀ N n m : ℕ, N ≤ n → N ≤ m → eLpNorm (f n - f m) p μ < B N), ∃ (f_lim : α → E), Memℒp f_lim p μ ∧ atTop.Tendsto (fun n => eLpNorm (f n - f_lim) p μ) (𝓝 0)) : CompleteSpace (Lp E p μ) := by diff --git a/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean b/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean index ecb76ae835229..b8f726696df54 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean @@ -24,7 +24,7 @@ Finally, we provide dot notation convenience lemmas. open Filter Set MeasureTheory open scoped ENNReal Topology symmDiff -variable {α X Y : Type*} +variable {X Y : Type*} [TopologicalSpace X] [MeasurableSpace X] [BorelSpace X] [R1Space X] [TopologicalSpace Y] [MeasurableSpace Y] [BorelSpace Y] [R1Space Y] {μ : Measure X} {ν : Measure Y} [μ.InnerRegularCompactLTTop] [IsLocallyFiniteMeasure ν] diff --git a/Mathlib/MeasureTheory/Function/SimpleFunc.lean b/Mathlib/MeasureTheory/Function/SimpleFunc.lean index 5615eaebce091..703145555d7ac 100644 --- a/Mathlib/MeasureTheory/Function/SimpleFunc.lean +++ b/Mathlib/MeasureTheory/Function/SimpleFunc.lean @@ -161,7 +161,7 @@ theorem measurableSet_preimage (f : α →ₛ β) (s) : MeasurableSet (f ⁻¹' measurableSet_cut (fun _ b => b ∈ s) f fun b => MeasurableSet.const (b ∈ s) /-- A simple function is measurable -/ -@[measurability] +@[measurability, fun_prop] protected theorem measurable [MeasurableSpace β] (f : α →ₛ β) : Measurable f := fun s _ => measurableSet_preimage f s @@ -197,21 +197,15 @@ theorem piecewise_apply {s : Set α} (hs : MeasurableSet s) (f g : α →ₛ β) @[simp] theorem piecewise_compl {s : Set α} (hs : MeasurableSet sᶜ) (f g : α →ₛ β) : piecewise sᶜ hs f g = piecewise s hs.of_compl g f := - coe_injective <| by - set_option tactic.skipAssignedInstances false in - simp [hs]; convert Set.piecewise_compl s f g + coe_injective <| by simp [hs] @[simp] theorem piecewise_univ (f g : α →ₛ β) : piecewise univ MeasurableSet.univ f g = f := - coe_injective <| by - set_option tactic.skipAssignedInstances false in - simp; convert Set.piecewise_univ f g + coe_injective <| by simp @[simp] theorem piecewise_empty (f g : α →ₛ β) : piecewise ∅ MeasurableSet.empty f g = g := - coe_injective <| by - set_option tactic.skipAssignedInstances false in - simp; convert Set.piecewise_empty f g + coe_injective <| by simp @[simp] theorem piecewise_same (f : α →ₛ β) {s : Set α} (hs : MeasurableSet s) : @@ -269,13 +263,13 @@ theorem map_const (g : β → γ) (b : β) : (const α b).map g = const α (g b) rfl theorem map_preimage (f : α →ₛ β) (g : β → γ) (s : Set γ) : - f.map g ⁻¹' s = f ⁻¹' ↑(f.range.filter fun b => g b ∈ s) := by + f.map g ⁻¹' s = f ⁻¹' ↑{b ∈ f.range | g b ∈ s} := by simp only [coe_range, sep_mem_eq, coe_map, Finset.coe_filter, ← mem_preimage, inter_comm, preimage_inter_range, ← Finset.mem_coe] exact preimage_comp theorem map_preimage_singleton (f : α →ₛ β) (g : β → γ) (c : γ) : - f.map g ⁻¹' {c} = f ⁻¹' ↑(f.range.filter fun b => g b = c) := + f.map g ⁻¹' {c} = f ⁻¹' ↑{b ∈ f.range | g b = c} := map_preimage _ _ _ /-- Composition of a `SimpleFun` and a measurable function is a `SimpleFunc`. -/ @@ -553,8 +547,8 @@ theorem smul_eq_map [SMul K β] (k : K) (f : α →ₛ β) : k • f = f.map (k instance instPreorder [Preorder β] : Preorder (α →ₛ β) := { SimpleFunc.instLE with - le_refl := fun f a => le_rfl - le_trans := fun f g h hfg hgh a => le_trans (hfg _) (hgh a) } + le_refl := fun _ _ => le_rfl + le_trans := fun _ _ _ hfg hgh a => le_trans (hfg _) (hgh a) } instance instPartialOrder [PartialOrder β] : PartialOrder (α →ₛ β) := { SimpleFunc.instPreorder with @@ -730,7 +724,7 @@ def eapprox : (α → ℝ≥0∞) → ℕ → α →ₛ ℝ≥0∞ := theorem eapprox_lt_top (f : α → ℝ≥0∞) (n : ℕ) (a : α) : eapprox f n a < ∞ := by simp only [eapprox, approx, finset_sup_apply, Finset.mem_range, ENNReal.bot_eq_zero, restrict] - rw [Finset.sup_lt_iff (α := ℝ≥0∞) WithTop.zero_lt_top] + rw [Finset.sup_lt_iff (α := ℝ≥0∞) WithTop.top_pos] intro b _ split_ifs · simp only [coe_zero, coe_piecewise, piecewise_eq_indicator, coe_const] @@ -739,7 +733,7 @@ theorem eapprox_lt_top (f : α → ℝ≥0∞) (n : ℕ) (a : α) : eapprox f n ennrealRatEmbed b := indicator_le_self _ _ a _ < ⊤ := ENNReal.coe_lt_top - · exact WithTop.zero_lt_top + · exact WithTop.top_pos @[mono] theorem monotone_eapprox (f : α → ℝ≥0∞) : Monotone (eapprox f) := @@ -773,7 +767,7 @@ theorem sum_eapproxDiff (f : α → ℝ≥0∞) (n : ℕ) (a : α) : induction' n with n IH · simp only [Nat.zero_add, Finset.sum_singleton, Finset.range_one] rfl - · erw [Finset.sum_range_succ, IH, eapproxDiff, coe_map, Function.comp_apply, + · rw [Finset.sum_range_succ, IH, eapproxDiff, coe_map, Function.comp_apply, coe_sub, Pi.sub_apply, ENNReal.coe_toNNReal, add_tsub_cancel_of_le (monotone_eapprox f (Nat.le_succ _) _)] apply (lt_of_le_of_lt _ (eapprox_lt_top f (n + 1) a)).ne @@ -855,8 +849,8 @@ def lintegralₗ {m : MeasurableSpace α} : (α →ₛ ℝ≥0∞) →ₗ[ℝ≥ map_add' := by simp [lintegral, mul_add, Finset.sum_add_distrib] map_smul' := fun c μ => by simp [lintegral, mul_left_comm _ c, Finset.mul_sum, Measure.smul_apply c] } - map_add' f g := LinearMap.ext fun μ => add_lintegral f g - map_smul' c f := LinearMap.ext fun μ => const_mul_lintegral f c + map_add' f g := LinearMap.ext fun _ => add_lintegral f g + map_smul' c f := LinearMap.ext fun _ => const_mul_lintegral f c @[simp] theorem zero_lintegral : (0 : α →ₛ ℝ≥0∞).lintegral μ = 0 := @@ -985,7 +979,7 @@ section FinMeasSupp open Finset Function theorem support_eq [MeasurableSpace α] [Zero β] (f : α →ₛ β) : - support f = ⋃ y ∈ f.range.filter fun y => y ≠ 0, f ⁻¹' {y} := + support f = ⋃ y ∈ {y ∈ f.range | y ≠ 0}, f ⁻¹' {y} := Set.ext fun x => by simp only [mem_support, Set.mem_preimage, mem_filter, mem_range_self, true_and, exists_prop, mem_iUnion, Set.mem_range, mem_singleton_iff, exists_eq_right'] diff --git a/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean b/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean index 72dd2f1509641..920ebf5d42e0d 100644 --- a/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean +++ b/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean @@ -684,8 +684,11 @@ lemma isUniformEmbedding : IsUniformEmbedding ((↑) : Lp.simpleFunc E p μ → @[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding -protected theorem uniformInducing : UniformInducing ((↑) : Lp.simpleFunc E p μ → Lp E p μ) := - simpleFunc.isUniformEmbedding.toUniformInducing +theorem isUniformInducing : IsUniformInducing ((↑) : Lp.simpleFunc E p μ → Lp E p μ) := + simpleFunc.isUniformEmbedding.isUniformInducing + +@[deprecated (since := "2024-10-05")] +alias uniformInducing := isUniformInducing lemma isDenseEmbedding (hp_ne_top : p ≠ ∞) : IsDenseEmbedding ((↑) : Lp.simpleFunc E p μ → Lp E p μ) := by @@ -739,8 +742,7 @@ variable {G : Type*} [NormedLatticeAddCommGroup G] theorem coeFn_le (f g : Lp.simpleFunc G p μ) : (f : α → G) ≤ᵐ[μ] g ↔ f ≤ g := by rw [← Subtype.coe_le_coe, ← Lp.coeFn_le] -instance instCovariantClassLE : - CovariantClass (Lp.simpleFunc G p μ) (Lp.simpleFunc G p μ) (· + ·) (· ≤ ·) := by +instance instAddLeftMono : AddLeftMono (Lp.simpleFunc G p μ) := by refine ⟨fun f g₁ g₂ hg₁₂ => ?_⟩ rw [← Lp.simpleFunc.coeFn_le] at hg₁₂ ⊢ have h_add_1 : ((f + g₁ : Lp.simpleFunc G p μ) : α → G) =ᵐ[μ] (f : α → G) + g₁ := Lp.coeFn_add _ _ diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index b9644215bcca2..08b42756f8fae 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -269,7 +269,7 @@ theorem finStronglyMeasurable_of_set_sigmaFinite [TopologicalSpace β] [Zero β] FinStronglyMeasurable f μ := by haveI : SigmaFinite (μ.restrict t) := htμ let S := spanningSets (μ.restrict t) - have hS_meas : ∀ n, MeasurableSet (S n) := measurable_spanningSets (μ.restrict t) + have hS_meas : ∀ n, MeasurableSet (S n) := measurableSet_spanningSets (μ.restrict t) let f_approx := hf_meas.approx let fs n := SimpleFunc.restrict (f_approx n) (S n ∩ t) have h_fs_t_compl : ∀ n, ∀ x, x ∉ t → fs n x = 0 := by @@ -684,14 +684,14 @@ lemma _root_.HasCompactSupport.stronglyMeasurable_of_prod {X Y : Type*} [Zero α /-- If `g` is a topological embedding, then `f` is strongly measurable iff `g ∘ f` is. -/ theorem _root_.Embedding.comp_stronglyMeasurable_iff {m : MeasurableSpace α} [TopologicalSpace β] [PseudoMetrizableSpace β] [TopologicalSpace γ] [PseudoMetrizableSpace γ] {g : β → γ} {f : α → β} - (hg : Embedding g) : (StronglyMeasurable fun x => g (f x)) ↔ StronglyMeasurable f := by + (hg : IsEmbedding g) : (StronglyMeasurable fun x => g (f x)) ↔ StronglyMeasurable f := by letI := pseudoMetrizableSpacePseudoMetric γ borelize β γ refine ⟨fun H => stronglyMeasurable_iff_measurable_separable.2 ⟨?_, ?_⟩, fun H => hg.continuous.comp_stronglyMeasurable H⟩ · let G : β → range g := rangeFactorization g - have hG : ClosedEmbedding G := + have hG : IsClosedEmbedding G := { hg.codRestrict _ _ with isClosed_range := by rw [surjective_onto_range.range_eq] @@ -1504,8 +1504,8 @@ theorem _root_.MeasurableEmbedding.aestronglyMeasurable_map_iff {γ : Type*} rcases hf.exists_stronglyMeasurable_extend hgm₁ fun x => ⟨g x⟩ with ⟨g₂, hgm₂, rfl⟩ exact ⟨g₂, hgm₂, hf.ae_map_iff.2 heq⟩ -theorem _root_.Embedding.aestronglyMeasurable_comp_iff [PseudoMetrizableSpace β] - [PseudoMetrizableSpace γ] {g : β → γ} {f : α → β} (hg : Embedding g) : +theorem _root_.IsEmbedding.aestronglyMeasurable_comp_iff [PseudoMetrizableSpace β] + [PseudoMetrizableSpace γ] {g : β → γ} {f : α → β} (hg : IsEmbedding g) : AEStronglyMeasurable (fun x => g (f x)) μ ↔ AEStronglyMeasurable f μ := by letI := pseudoMetrizableSpacePseudoMetric γ borelize β γ @@ -1513,7 +1513,7 @@ theorem _root_.Embedding.aestronglyMeasurable_comp_iff [PseudoMetrizableSpace β ⟨fun H => aestronglyMeasurable_iff_aemeasurable_separable.2 ⟨?_, ?_⟩, fun H => hg.continuous.comp_aestronglyMeasurable H⟩ · let G : β → range g := rangeFactorization g - have hG : ClosedEmbedding G := + have hG : IsClosedEmbedding G := { hg.codRestrict _ _ with isClosed_range := by rw [surjective_onto_range.range_eq]; exact isClosed_univ } have : AEMeasurable (G ∘ f) μ := AEMeasurable.subtype_mk H.aemeasurable @@ -1521,6 +1521,9 @@ theorem _root_.Embedding.aestronglyMeasurable_comp_iff [PseudoMetrizableSpace β · rcases (aestronglyMeasurable_iff_aemeasurable_separable.1 H).2 with ⟨t, ht, h't⟩ exact ⟨g ⁻¹' t, hg.isSeparable_preimage ht, h't⟩ +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.aestronglyMeasurable_comp_iff := IsEmbedding.aestronglyMeasurable_comp_iff + /-- An almost everywhere sequential limit of almost everywhere strongly measurable functions is almost everywhere strongly measurable. -/ theorem _root_.aestronglyMeasurable_of_tendsto_ae {ι : Type*} [PseudoMetrizableSpace β] @@ -1777,9 +1780,8 @@ end AEFinStronglyMeasurable section SecondCountableTopology -variable {G : Type*} {p : ℝ≥0∞} {m m0 : MeasurableSpace α} {μ : Measure α} - [SeminormedAddCommGroup G] [MeasurableSpace G] [BorelSpace G] [SecondCountableTopology G] - {f : α → G} +variable {G : Type*} [SeminormedAddCommGroup G] [MeasurableSpace G] [BorelSpace G] + [SecondCountableTopology G] {f : α → G} /-- In a space with second countable topology and a sigma-finite measure, `FinStronglyMeasurable` and `Measurable` are equivalent. -/ diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Lemmas.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Lemmas.lean index 4251891161db2..232923661f030 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Lemmas.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Lemmas.lean @@ -46,7 +46,7 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] theorem aestronglyMeasurable_smul_const_iff {f : α → 𝕜} {c : E} (hc : c ≠ 0) : AEStronglyMeasurable (fun x => f x • c) μ ↔ AEStronglyMeasurable f μ := - (closedEmbedding_smul_left hc).toEmbedding.aestronglyMeasurable_comp_iff + (isClosedEmbedding_smul_left hc).isEmbedding.aestronglyMeasurable_comp_iff end NormedSpace diff --git a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean index 52d0280c4dbba..cd1ec970e0581 100644 --- a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean +++ b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean @@ -327,7 +327,7 @@ end theorem eLpNorm_indicator_le_of_bound {f : α → β} (hp_top : p ≠ ∞) {ε : ℝ} (hε : 0 < ε) {M : ℝ} (hf : ∀ x, ‖f x‖ < M) : - ∃ (δ : ℝ) (hδ : 0 < δ), ∀ s, MeasurableSet s → + ∃ (δ : ℝ) (_ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → eLpNorm (s.indicator f) p μ ≤ ENNReal.ofReal ε := by by_cases hM : M ≤ 0 · refine ⟨1, zero_lt_one, fun s _ _ => ?_⟩ @@ -363,7 +363,7 @@ variable {f : α → β} /-- Auxiliary lemma for `MeasureTheory.Memℒp.eLpNorm_indicator_le`. -/ theorem Memℒp.eLpNorm_indicator_le' (hp_one : 1 ≤ p) (hp_top : p ≠ ∞) (hf : Memℒp f p μ) (hmeas : StronglyMeasurable f) {ε : ℝ} (hε : 0 < ε) : - ∃ (δ : ℝ) (hδ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → + ∃ (δ : ℝ) (_ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → eLpNorm (s.indicator f) p μ ≤ 2 * ENNReal.ofReal ε := by obtain ⟨M, hMpos, hM⟩ := hf.eLpNorm_indicator_norm_ge_pos_le hmeas hε obtain ⟨δ, hδpos, hδ⟩ := @@ -397,7 +397,7 @@ alias Memℒp.snorm_indicator_le' := Memℒp.eLpNorm_indicator_le' measurability on `f`. -/ theorem Memℒp.eLpNorm_indicator_le_of_meas (hp_one : 1 ≤ p) (hp_top : p ≠ ∞) (hf : Memℒp f p μ) (hmeas : StronglyMeasurable f) {ε : ℝ} (hε : 0 < ε) : - ∃ (δ : ℝ) (hδ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → + ∃ (δ : ℝ) (_ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → eLpNorm (s.indicator f) p μ ≤ ENNReal.ofReal ε := by obtain ⟨δ, hδpos, hδ⟩ := hf.eLpNorm_indicator_le' hp_one hp_top hmeas (half_pos hε) refine ⟨δ, hδpos, fun s hs hμs => le_trans (hδ s hs hμs) ?_⟩ @@ -410,7 +410,7 @@ alias Memℒp.snorm_indicator_le_of_meas := Memℒp.eLpNorm_indicator_le_of_meas theorem Memℒp.eLpNorm_indicator_le (hp_one : 1 ≤ p) (hp_top : p ≠ ∞) (hf : Memℒp f p μ) {ε : ℝ} (hε : 0 < ε) : - ∃ (δ : ℝ) (hδ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → + ∃ (δ : ℝ) (_ : 0 < δ), ∀ s, MeasurableSet s → μ s ≤ ENNReal.ofReal δ → eLpNorm (s.indicator f) p μ ≤ ENNReal.ofReal ε := by have hℒp := hf obtain ⟨⟨f', hf', heq⟩, _⟩ := hf diff --git a/Mathlib/MeasureTheory/Group/Arithmetic.lean b/Mathlib/MeasureTheory/Group/Arithmetic.lean index 1893764f613b0..a265438e4ebd7 100644 --- a/Mathlib/MeasureTheory/Group/Arithmetic.lean +++ b/Mathlib/MeasureTheory/Group/Arithmetic.lean @@ -87,8 +87,8 @@ export MeasurableMul₂ (measurable_mul) section Mul -variable {M α : Type*} [MeasurableSpace M] [Mul M] {m : MeasurableSpace α} {f g : α → M} - {μ : Measure α} +variable {M α β : Type*} [MeasurableSpace M] [Mul M] {m : MeasurableSpace α} + {mβ : MeasurableSpace β} {f g : α → M} {μ : Measure α} @[to_additive (attr := fun_prop, measurability)] theorem Measurable.const_mul [MeasurableMul M] (hf : Measurable f) (c : M) : @@ -110,17 +110,19 @@ theorem AEMeasurable.mul_const [MeasurableMul M] (hf : AEMeasurable f μ) (c : M AEMeasurable (fun x => f x * c) μ := (measurable_mul_const c).comp_aemeasurable hf -@[to_additive (attr := aesop safe 20 apply (rule_sets := [Measurable]))] -theorem Measurable.mul' [MeasurableMul₂ M] (hf : Measurable f) (hg : Measurable g) : - Measurable (f * g) := - measurable_mul.comp (hf.prod_mk hg) - @[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] theorem Measurable.mul [MeasurableMul₂ M] (hf : Measurable f) (hg : Measurable g) : Measurable fun a => f a * g a := measurable_mul.comp (hf.prod_mk hg) -@[to_additive (attr := aesop safe 20 apply (rule_sets := [Measurable]))] +/-- Compositional version of `Measurable.mul` for use by `fun_prop`. -/ +@[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable])) +"Compositional version of `Measurable.add` for use by `fun_prop`."] +lemma Measurable.mul' [MeasurableMul₂ M] {f g : α → β → M} {h : α → β} (hf : Measurable ↿f) + (hg : Measurable ↿g) (hh : Measurable h) : Measurable fun a ↦ (f a * g a) (h a) := by + simp; fun_prop + +@[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] theorem AEMeasurable.mul' [MeasurableMul₂ M] (hf : AEMeasurable f μ) (hg : AEMeasurable g μ) : AEMeasurable (f * g) μ := measurable_mul.comp_aemeasurable (hf.prod_mk hg) @@ -238,8 +240,8 @@ export MeasurableDiv₂ (measurable_div) section Div -variable {G α : Type*} [MeasurableSpace G] [Div G] {m : MeasurableSpace α} {f g : α → G} - {μ : Measure α} +variable {G α β : Type*} [MeasurableSpace G] [Div G] {m : MeasurableSpace α} + {mβ : MeasurableSpace β} {f g : α → G} {μ : Measure α} @[to_additive (attr := measurability)] theorem Measurable.const_div [MeasurableDiv G] (hf : Measurable f) (c : G) : @@ -261,17 +263,17 @@ theorem AEMeasurable.div_const [MeasurableDiv G] (hf : AEMeasurable f μ) (c : G AEMeasurable (fun x => f x / c) μ := (MeasurableDiv.measurable_div_const c).comp_aemeasurable hf -@[to_additive (attr := aesop safe 20 apply (rule_sets := [Measurable]))] -theorem Measurable.div' [MeasurableDiv₂ G] (hf : Measurable f) (hg : Measurable g) : - Measurable (f / g) := - measurable_div.comp (hf.prod_mk hg) - @[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] theorem Measurable.div [MeasurableDiv₂ G] (hf : Measurable f) (hg : Measurable g) : Measurable fun a => f a / g a := measurable_div.comp (hf.prod_mk hg) -@[to_additive (attr := aesop safe 20 apply (rule_sets := [Measurable]))] +@[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] +lemma Measurable.div' [MeasurableDiv₂ G] {f g : α → β → G} {h : α → β} (hf : Measurable ↿f) + (hg : Measurable ↿g) (hh : Measurable h) : Measurable fun a ↦ (f a / g a) (h a) := by + simp; fun_prop + +@[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] theorem AEMeasurable.div' [MeasurableDiv₂ G] (hf : AEMeasurable f μ) (hg : AEMeasurable g μ) : AEMeasurable (f / g) μ := measurable_div.comp_aemeasurable (hf.prod_mk hg) @@ -528,42 +530,52 @@ instance Subgroup.measurableSMul {G α} [MeasurableSpace G] [MeasurableSpace α] section SMul -variable {M β α : Type*} [MeasurableSpace M] [MeasurableSpace β] [_root_.SMul M β] - {m : MeasurableSpace α} {f : α → M} {g : α → β} +variable {M X α β : Type*} [MeasurableSpace M] [MeasurableSpace X] [SMul M X] + {m : MeasurableSpace α} {mβ : MeasurableSpace β} {f : α → M} {g : α → X} @[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] -theorem Measurable.smul [MeasurableSMul₂ M β] (hf : Measurable f) (hg : Measurable g) : +theorem Measurable.smul [MeasurableSMul₂ M X] (hf : Measurable f) (hg : Measurable g) : Measurable fun x => f x • g x := measurable_smul.comp (hf.prod_mk hg) +/-- Compositional version of `Measurable.smul` for use by `fun_prop`. -/ +@[to_additive (attr := fun_prop) +"Compositional version of `Measurable.vadd` for use by `fun_prop`."] +lemma Measurable.smul' [MeasurableSMul₂ M X] {f : α → β → M} {g : α → β → X} {h : α → β} + (hf : Measurable ↿f) (hg : Measurable ↿g) (hh : Measurable h) : + Measurable fun a ↦ (f a • g a) (h a) := by simp; fun_prop + @[to_additive (attr := fun_prop, aesop safe 20 apply (rule_sets := [Measurable]))] -theorem AEMeasurable.smul [MeasurableSMul₂ M β] {μ : Measure α} (hf : AEMeasurable f μ) +theorem AEMeasurable.smul [MeasurableSMul₂ M X] {μ : Measure α} (hf : AEMeasurable f μ) (hg : AEMeasurable g μ) : AEMeasurable (fun x => f x • g x) μ := MeasurableSMul₂.measurable_smul.comp_aemeasurable (hf.prod_mk hg) @[to_additive] -instance (priority := 100) MeasurableSMul₂.toMeasurableSMul [MeasurableSMul₂ M β] : - MeasurableSMul M β := +instance (priority := 100) MeasurableSMul₂.toMeasurableSMul [MeasurableSMul₂ M X] : + MeasurableSMul M X := ⟨fun _ => measurable_const.smul measurable_id, fun _ => measurable_id.smul measurable_const⟩ -variable [MeasurableSMul M β] {μ : Measure α} +variable [MeasurableSMul M X] {μ : Measure α} @[to_additive (attr := measurability)] -theorem Measurable.smul_const (hf : Measurable f) (y : β) : Measurable fun x => f x • y := +theorem Measurable.smul_const (hf : Measurable f) (y : X) : Measurable fun x => f x • y := (MeasurableSMul.measurable_smul_const y).comp hf @[to_additive (attr := measurability)] -theorem AEMeasurable.smul_const (hf : AEMeasurable f μ) (y : β) : +theorem AEMeasurable.smul_const (hf : AEMeasurable f μ) (y : X) : AEMeasurable (fun x => f x • y) μ := (MeasurableSMul.measurable_smul_const y).comp_aemeasurable hf -@[to_additive (attr := measurability)] -theorem Measurable.const_smul' (hg : Measurable g) (c : M) : Measurable fun x => c • g x := +@[to_additive (attr := fun_prop, measurability)] +theorem Measurable.const_smul (hg : Measurable g) (c : M) : Measurable (c • g) := (MeasurableSMul.measurable_const_smul c).comp hg -@[to_additive (attr := measurability)] -theorem Measurable.const_smul (hg : Measurable g) (c : M) : Measurable (c • g) := - hg.const_smul' c +/-- Compositional version of `Measurable.const_smul` for use by `fun_prop`. -/ +@[to_additive (attr := fun_prop) +"Compositional version of `Measurable.const_vadd` for use by `fun_prop`."] +lemma Measurable.const_smul' {g : α → β → X} {h : α → β} (hg : Measurable ↿g) (hh : Measurable h) + (c : M) : Measurable fun a ↦ (c • g a) (h a) := + (hg.comp <| measurable_id.prod_mk hh).const_smul _ @[to_additive (attr := measurability)] theorem AEMeasurable.const_smul' (hg : AEMeasurable g μ) (c : M) : @@ -638,12 +650,12 @@ variable {G : Type*} [Group G] [MeasurableSpace G] [MulAction G β] [MeasurableS @[to_additive] theorem measurable_const_smul_iff (c : G) : (Measurable fun x => c • f x) ↔ Measurable f := - ⟨fun h => by simpa only [inv_smul_smul] using h.const_smul' c⁻¹, fun h => h.const_smul c⟩ + ⟨fun h => by simpa [inv_smul_smul, Pi.smul_def] using h.const_smul c⁻¹, fun h => h.const_smul c⟩ @[to_additive] theorem aemeasurable_const_smul_iff (c : G) : AEMeasurable (fun x => c • f x) μ ↔ AEMeasurable f μ := - ⟨fun h => by simpa only [inv_smul_smul] using h.const_smul' c⁻¹, fun h => h.const_smul c⟩ + ⟨fun h => by simpa [inv_smul_smul, Pi.smul_def] using h.const_smul c⁻¹, fun h => h.const_smul c⟩ @[to_additive] instance Units.instMeasurableSpace : MeasurableSpace Mˣ := MeasurableSpace.comap ((↑) : Mˣ → M) ‹_› @@ -782,8 +794,8 @@ end Monoid section CommMonoid -variable {M ι α : Type*} [CommMonoid M] [MeasurableSpace M] [MeasurableMul₂ M] - {m : MeasurableSpace α} {μ : Measure α} {f : ι → α → M} +variable {M ι α β : Type*} [CommMonoid M] [MeasurableSpace M] [MeasurableMul₂ M] + {m : MeasurableSpace α} {mβ : MeasurableSpace β} {μ : Measure α} {f : ι → α → M} @[to_additive (attr := measurability)] theorem Multiset.measurable_prod' (l : Multiset (α → M)) (hl : ∀ f ∈ l, Measurable f) : @@ -807,15 +819,18 @@ theorem Multiset.aemeasurable_prod (s : Multiset (α → M)) (hs : ∀ f ∈ s, AEMeasurable (fun x => (s.map fun f : α → M => f x).prod) μ := by simpa only [← Pi.multiset_prod_apply] using s.aemeasurable_prod' hs -@[to_additive (attr := measurability)] -theorem Finset.measurable_prod' (s : Finset ι) (hf : ∀ i ∈ s, Measurable (f i)) : - Measurable (∏ i ∈ s, f i) := - Finset.prod_induction _ _ (fun _ _ => Measurable.mul) (@measurable_one M _ _ _ _) hf - -@[to_additive (attr := measurability)] +@[to_additive (attr := fun_prop, measurability)] theorem Finset.measurable_prod (s : Finset ι) (hf : ∀ i ∈ s, Measurable (f i)) : - Measurable fun a => ∏ i ∈ s, f i a := by - simpa only [← Finset.prod_apply] using s.measurable_prod' hf + Measurable fun a ↦ ∏ i ∈ s, f i a := by + simp_rw [← Finset.prod_apply] + exact Finset.prod_induction _ _ (fun _ _ => Measurable.mul) (@measurable_one M _ _ _ _) hf + +/-- Compositional version of `Finset.measurable_prod` for use by `fun_prop`. -/ +@[to_additive (attr := measurability, fun_prop) +"Compositional version of `Finset.measurable_sum` for use by `fun_prop`."] +lemma Finset.measurable_prod' {f : ι → α → β → M} {g : α → β} {s : Finset ι} + (hf : ∀ i, Measurable ↿(f i)) (hg : Measurable g) : + Measurable fun a ↦ (∏ i ∈ s, f i a) (g a) := by simp; fun_prop @[to_additive (attr := measurability)] theorem Finset.aemeasurable_prod' (s : Finset ι) (hf : ∀ i ∈ s, AEMeasurable (f i) μ) : diff --git a/Mathlib/MeasureTheory/Group/Convolution.lean b/Mathlib/MeasureTheory/Group/Convolution.lean index 0796630b4e41a..07a0fe4cdab79 100644 --- a/Mathlib/MeasureTheory/Group/Convolution.lean +++ b/Mathlib/MeasureTheory/Group/Convolution.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Josha Dekker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Josha Dekker -/ -import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Measure.MeasureSpace +import Mathlib.MeasureTheory.Measure.Prod /-! # The multiplicative and additive convolution of measures diff --git a/Mathlib/MeasureTheory/Group/FundamentalDomain.lean b/Mathlib/MeasureTheory/Group/FundamentalDomain.lean index b7e676a68b71b..993b79332bb45 100644 --- a/Mathlib/MeasureTheory/Group/FundamentalDomain.lean +++ b/Mathlib/MeasureTheory/Group/FundamentalDomain.lean @@ -317,7 +317,7 @@ theorem measure_set_eq (hs : IsFundamentalDomain G s μ) (ht : IsFundamentalDoma refine hs.setLIntegral_eq ht (Set.indicator A fun _ => 1) fun g x ↦ ?_ convert (Set.indicator_comp_right (g • · : α → α) (g := fun _ ↦ (1 : ℝ≥0∞))).symm rw [hA g] - simpa [Measure.restrict_apply hA₀, lintegral_indicator _ hA₀] using this + simpa [Measure.restrict_apply hA₀, lintegral_indicator hA₀] using this /-- If `s` and `t` are two fundamental domains of the same action, then their measures are equal. -/ @[to_additive "If `s` and `t` are two fundamental domains of the same action, then their measures diff --git a/Mathlib/MeasureTheory/Group/Integral.lean b/Mathlib/MeasureTheory/Group/Integral.lean index 665790505f3cd..31e10db1f25bb 100644 --- a/Mathlib/MeasureTheory/Group/Integral.lean +++ b/Mathlib/MeasureTheory/Group/Integral.lean @@ -68,9 +68,7 @@ theorem integral_mul_right_eq_self [IsMulRightInvariant μ] (f : G → E) (g : G @[to_additive] -- Porting note: was `@[simp]` theorem integral_div_right_eq_self [IsMulRightInvariant μ] (f : G → E) (g : G) : (∫ x, f (x / g) ∂μ) = ∫ x, f x ∂μ := by - simp_rw [div_eq_mul_inv] - -- Porting note: was `simp_rw` - rw [integral_mul_right_eq_self f g⁻¹] + simp_rw [div_eq_mul_inv, integral_mul_right_eq_self f g⁻¹] /-- If some left-translate of a function negates it, then the integral of the function with respect to a left-invariant measure is 0. -/ @@ -123,9 +121,8 @@ theorem integrable_comp_div_left (f : G → F) [IsInvInvariant μ] [IsMulLeftInv @[to_additive] -- Porting note: was `@[simp]` theorem integral_div_left_eq_self (f : G → E) (μ : Measure G) [IsInvInvariant μ] [IsMulLeftInvariant μ] (x' : G) : (∫ x, f (x' / x) ∂μ) = ∫ x, f x ∂μ := by - simp_rw [div_eq_mul_inv] - -- Porting note: was `simp_rw` - rw [integral_inv_eq_self (fun x => f (x' * x)) μ, integral_mul_left_eq_self f x'] + simp_rw [div_eq_mul_inv, integral_inv_eq_self (fun x => f (x' * x)) μ, + integral_mul_left_eq_self f x'] end MeasurableMul diff --git a/Mathlib/MeasureTheory/Group/Measure.lean b/Mathlib/MeasureTheory/Group/Measure.lean index 3e36cb114970b..1dbf773aa37b2 100644 --- a/Mathlib/MeasureTheory/Group/Measure.lean +++ b/Mathlib/MeasureTheory/Group/Measure.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Group.Action +import Mathlib.MeasureTheory.Measure.Prod import Mathlib.Topology.ContinuousMap.CocompactMap /-! @@ -28,7 +28,7 @@ open scoped NNReal ENNReal Pointwise Topology open Inv Set Function MeasureTheory.Measure Filter -variable {𝕜 G H : Type*} [MeasurableSpace G] [MeasurableSpace H] +variable {G H : Type*} [MeasurableSpace G] [MeasurableSpace H] namespace MeasureTheory @@ -775,7 +775,7 @@ 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.closedEmbedding.tendsto_cocompact + isHaarMeasure_map μ (e : G →* H) 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 38b8691d5bc0d..8c7b2f7d77ef1 100644 --- a/Mathlib/MeasureTheory/Group/Prod.lean +++ b/Mathlib/MeasureTheory/Group/Prod.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Group.Measure +import Mathlib.MeasureTheory.Measure.Prod /-! # Measure theory in the product of groups @@ -221,7 +221,7 @@ theorem absolutelyContinuous_map_div_left (g : G) : μ ≪ map (fun h => g / h) @[to_additive "This is the computation performed in the proof of [Halmos, §60 Th. A]."] theorem measure_mul_lintegral_eq [IsMulLeftInvariant ν] (sm : MeasurableSet s) (f : G → ℝ≥0∞) (hf : Measurable f) : (μ s * ∫⁻ y, f y ∂ν) = ∫⁻ x, ν ((fun z => z * x) ⁻¹' s) * f x⁻¹ ∂μ := by - rw [← setLIntegral_one, ← lintegral_indicator _ sm, + rw [← setLIntegral_one, ← lintegral_indicator sm, ← lintegral_lintegral_mul (measurable_const.indicator sm).aemeasurable hf.aemeasurable, ← lintegral_lintegral_mul_inv μ ν] swap @@ -233,7 +233,7 @@ theorem measure_mul_lintegral_eq [IsMulLeftInvariant ν] (sm : MeasurableSet s) have : ∀ x y, s.indicator (fun _ : G => (1 : ℝ≥0∞)) (y * x) = ((fun z => z * x) ⁻¹' s).indicator (fun b : G => 1) y := by intro x y; symm; convert indicator_comp_right (M := ℝ≥0∞) fun y => y * x using 2; ext1; rfl - simp_rw [this, lintegral_mul_const _ (ms _), lintegral_indicator _ (measurable_mul_const _ sm), + simp_rw [this, lintegral_mul_const _ (ms _), lintegral_indicator (measurable_mul_const _ sm), setLIntegral_one] /-- Any two nonzero left-invariant measures are absolutely continuous w.r.t. each other. -/ @@ -262,11 +262,11 @@ theorem ae_measure_preimage_mul_right_lt_top (hμs : μ' s ≠ ∞) : simp only [ν'.inv_apply] at h3A apply ae_lt_top (measurable_measure_mul_right ν' sm) have h1 := measure_mul_lintegral_eq μ' ν' sm (A⁻¹.indicator 1) (measurable_one.indicator hA.inv) - rw [lintegral_indicator _ hA.inv] at h1 + rw [lintegral_indicator hA.inv] at h1 simp_rw [Pi.one_apply, setLIntegral_one, ← image_inv, indicator_image inv_injective, image_inv, ← indicator_mul_right _ fun x => ν' ((fun y => y * x) ⁻¹' s), Function.comp, Pi.one_apply, mul_one] at h1 - rw [← lintegral_indicator _ hA, ← h1] + rw [← lintegral_indicator hA, ← h1] exact ENNReal.mul_ne_top hμs h3A.ne @[to_additive] @@ -320,7 +320,7 @@ theorem measure_mul_measure_eq (s t : Set G) (h2s : ν' s ≠ 0) (h3s : ν' s (measurable_const.indicator ht) have h2 := measure_lintegral_div_measure μ' ν' hs h2s h3s (t.indicator fun _ => 1) (measurable_const.indicator ht) - rw [lintegral_indicator _ ht, setLIntegral_one] at h1 h2 + rw [lintegral_indicator ht, setLIntegral_one] at h1 h2 rw [← h1, mul_left_comm, h2] /-- Left invariant Borel measures on a measurable group are unique (up to a scalar). -/ diff --git a/Mathlib/MeasureTheory/Integral/Asymptotics.lean b/Mathlib/MeasureTheory/Integral/Asymptotics.lean index f80409c54ea35..a99edd79274bf 100644 --- a/Mathlib/MeasureTheory/Integral/Asymptotics.lean +++ b/Mathlib/MeasureTheory/Integral/Asymptotics.lean @@ -29,7 +29,7 @@ We establish integrability of `f` from `f = O(g)`. open Asymptotics MeasureTheory Set Filter -variable {α E F : Type*} [NormedAddCommGroup E] {f : α → E} {g : α → F} {a b : α} {l : Filter α} +variable {α E F : Type*} [NormedAddCommGroup E] {f : α → E} {g : α → F} {a : α} {l : Filter α} namespace Asymptotics diff --git a/Mathlib/MeasureTheory/Integral/Average.lean b/Mathlib/MeasureTheory/Integral/Average.lean index 2b93b827a0339..7f6337976b25d 100644 --- a/Mathlib/MeasureTheory/Integral/Average.lean +++ b/Mathlib/MeasureTheory/Integral/Average.lean @@ -321,7 +321,7 @@ theorem average_congr {f g : α → E} (h : f =ᵐ[μ] g) : ⨍ x, f x ∂μ = simp only [average_eq, integral_congr_ae h] theorem setAverage_congr (h : s =ᵐ[μ] t) : ⨍ x in s, f x ∂μ = ⨍ x in t, f x ∂μ := by - simp only [setAverage_eq, setIntegral_congr_set_ae h, measure_congr h] + simp only [setAverage_eq, setIntegral_congr_set h, measure_congr h] theorem setAverage_congr_fun (hs : MeasurableSet s) (h : ∀ᵐ x ∂μ, x ∈ s → f x = g x) : ⨍ x in s, f x ∂μ = ⨍ x in s, g x ∂μ := by simp only [average_eq, setIntegral_congr_ae hs h] @@ -396,7 +396,6 @@ theorem setAverage_const {s : Set α} (hs₀ : μ s ≠ 0) (hs : μ s ≠ ∞) ( ⨍ _ in s, c ∂μ = c := have := NeZero.mk hs₀; have := Fact.mk hs.lt_top; average_const _ _ --- Porting note (#10618): was `@[simp]` but `simp` can prove it theorem integral_average (μ : Measure α) [IsFiniteMeasure μ] (f : α → E) : ∫ _, ⨍ a, f a ∂μ ∂μ = ∫ x, f x ∂μ := by simp diff --git a/Mathlib/MeasureTheory/Integral/Bochner.lean b/Mathlib/MeasureTheory/Integral/Bochner.lean index 1ea3d369e9733..ada8eefa261f7 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner.lean @@ -201,18 +201,17 @@ theorem weightedSMul_null {s : Set α} (h_zero : μ s = 0) : (weightedSMul μ s ext1 x; rw [weightedSMul_apply, h_zero]; simp theorem weightedSMul_union' (s t : Set α) (ht : MeasurableSet t) (hs_finite : μ s ≠ ∞) - (ht_finite : μ t ≠ ∞) (h_inter : s ∩ t = ∅) : + (ht_finite : μ t ≠ ∞) (hdisj : Disjoint s t) : (weightedSMul μ (s ∪ t) : F →L[ℝ] F) = weightedSMul μ s + weightedSMul μ t := by ext1 x - simp_rw [add_apply, weightedSMul_apply, - measure_union (Set.disjoint_iff_inter_eq_empty.mpr h_inter) ht, + simp_rw [add_apply, weightedSMul_apply, measure_union hdisj ht, ENNReal.toReal_add hs_finite ht_finite, add_smul] @[nolint unusedArguments] theorem weightedSMul_union (s t : Set α) (_hs : MeasurableSet s) (ht : MeasurableSet t) - (hs_finite : μ s ≠ ∞) (ht_finite : μ t ≠ ∞) (h_inter : s ∩ t = ∅) : + (hs_finite : μ s ≠ ∞) (ht_finite : μ t ≠ ∞) (hdisj : Disjoint s t) : (weightedSMul μ (s ∪ t) : F →L[ℝ] F) = weightedSMul μ s + weightedSMul μ t := - weightedSMul_union' s t ht hs_finite ht_finite h_inter + weightedSMul_union' s t ht hs_finite ht_finite hdisj theorem weightedSMul_smul [NormedField 𝕜] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] (c : 𝕜) (s : Set α) (x : F) : weightedSMul μ s (c • x) = c • weightedSMul μ s x := by @@ -279,9 +278,8 @@ and prove basic property of this integral. open Finset -variable [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedSpace ℝ F] {p : ℝ≥0∞} {G F' : Type*} - [NormedAddCommGroup G] [NormedAddCommGroup F'] [NormedSpace ℝ F'] {m : MeasurableSpace α} - {μ : Measure α} +variable [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedSpace ℝ F] + {m : MeasurableSpace α} {μ : Measure α} /-- Bochner integral of simple functions whose codomain is a real `NormedSpace`. This is equal to `∑ x ∈ f.range, (μ (f ⁻¹' {x})).toReal • x` (see `integral_eq`). -/ @@ -297,12 +295,12 @@ theorem integral_eq {m : MeasurableSpace α} (μ : Measure α) (f : α →ₛ F) theorem integral_eq_sum_filter [DecidablePred fun x : F => x ≠ 0] {m : MeasurableSpace α} (f : α →ₛ F) (μ : Measure α) : - f.integral μ = ∑ x ∈ f.range.filter fun x => x ≠ 0, (μ (f ⁻¹' {x})).toReal • x := by + f.integral μ = ∑ x ∈ {x ∈ f.range | x ≠ 0}, (μ (f ⁻¹' {x})).toReal • x := by simp_rw [integral_def, setToSimpleFunc_eq_sum_filter, weightedSMul_apply] /-- The Bochner integral is equal to a sum over any set that includes `f.range` (except `0`). -/ theorem integral_eq_sum_of_subset [DecidablePred fun x : F => x ≠ 0] {f : α →ₛ F} {s : Finset F} - (hs : (f.range.filter fun x => x ≠ 0) ⊆ s) : + (hs : {x ∈ f.range | x ≠ 0} ⊆ s) : f.integral μ = ∑ x ∈ s, (μ (f ⁻¹' {x})).toReal • x := by rw [SimpleFunc.integral_eq_sum_filter, Finset.sum_subset hs] rintro x - hx; rw [Finset.mem_filter, not_and_or, Ne, Classical.not_not] at hx @@ -423,7 +421,7 @@ namespace L1 open AEEqFun Lp.simpleFunc Lp -variable [NormedAddCommGroup E] [NormedAddCommGroup F] {m : MeasurableSpace α} {μ : Measure α} +variable [NormedAddCommGroup E] {m : MeasurableSpace α} {μ : Measure α} namespace SimpleFunc @@ -464,8 +462,7 @@ Define the Bochner integral on `α →₁ₛ[μ] E` by extension from the simple and prove basic properties of this integral. -/ -variable [NormedField 𝕜] [NormedSpace 𝕜 E] [NormedSpace ℝ E] [SMulCommClass ℝ 𝕜 E] {F' : Type*} - [NormedAddCommGroup F'] [NormedSpace ℝ F'] +variable [NormedField 𝕜] [NormedSpace 𝕜 E] [NormedSpace ℝ E] [SMulCommClass ℝ 𝕜 E] attribute [local instance] simpleFunc.normedSpace @@ -495,7 +492,6 @@ theorem norm_integral_le_norm (f : α →₁ₛ[μ] E) : ‖integral f‖ ≤ rw [integral, norm_eq_integral] exact (toSimpleFunc f).norm_integral_le_integral_norm (SimpleFunc.integrable f) -variable {E' : Type*} [NormedAddCommGroup E'] [NormedSpace ℝ E'] [NormedSpace 𝕜 E'] variable (α E μ 𝕜) /-- The Bochner integral over simple functions in L1 space as a continuous linear map. -/ @@ -575,7 +571,7 @@ open SimpleFunc local notation "Integral" => @integralCLM α E _ _ _ _ _ μ _ variable [NormedSpace ℝ E] [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 E] [SMulCommClass ℝ 𝕜 E] - [NormedSpace ℝ F] [CompleteSpace E] + [CompleteSpace E] section IntegrationInL1 @@ -588,7 +584,7 @@ variable (𝕜) /-- The Bochner integral in L1 space as a continuous linear map. -/ nonrec def integralCLM' : (α →₁[μ] E) →L[𝕜] E := (integralCLM' α E 𝕜 μ).extend (coeToLp α E 𝕜) (simpleFunc.denseRange one_ne_top) - simpleFunc.uniformInducing + simpleFunc.isUniformInducing variable {𝕜} @@ -700,7 +696,7 @@ functions, and 0 otherwise; prove its basic properties. -/ variable [NormedAddCommGroup E] [hE : CompleteSpace E] [NontriviallyNormedField 𝕜] - [NormedSpace 𝕜 E] [NormedAddCommGroup F] [NormedSpace ℝ F] [CompleteSpace F] + [NormedAddCommGroup F] [NormedSpace ℝ F] [CompleteSpace F] {G : Type*} [NormedAddCommGroup G] [NormedSpace ℝ G] open Classical in @@ -730,8 +726,8 @@ section Properties open ContinuousLinearMap MeasureTheory.SimpleFunc -variable [NormedSpace ℝ E] [SMulCommClass ℝ 𝕜 E] -variable {f g : α → E} {m : MeasurableSpace α} {μ : Measure α} +variable [NormedSpace ℝ E] +variable {f : α → E} {m : MeasurableSpace α} {μ : Measure α} theorem integral_eq (f : α → E) (hf : Integrable f μ) : ∫ a, f a ∂μ = L1.integral (hf.toL1 f) := by simp [integral, hE, hf] @@ -1578,11 +1574,14 @@ theorem _root_.MeasurableEmbedding.integral_map {β} {_ : MeasurableSpace β} {f · rw [integral_non_aestronglyMeasurable hgm, integral_non_aestronglyMeasurable] exact fun hgf => hgm (hf.aestronglyMeasurable_map_iff.2 hgf) -theorem _root_.ClosedEmbedding.integral_map {β} [TopologicalSpace α] [BorelSpace α] - [TopologicalSpace β] [MeasurableSpace β] [BorelSpace β] {φ : α → β} (hφ : ClosedEmbedding φ) +theorem _root_.IsClosedEmbedding.integral_map {β} [TopologicalSpace α] [BorelSpace α] + [TopologicalSpace β] [MeasurableSpace β] [BorelSpace β] {φ : α → β} (hφ : IsClosedEmbedding φ) (f : β → G) : ∫ y, f y ∂Measure.map φ μ = ∫ x, f (φ x) ∂μ := hφ.measurableEmbedding.integral_map _ +@[deprecated (since := "2024-10-20")] +alias _root_.ClosedEmbedding.integral_map := _root_.IsClosedEmbedding.integral_map + theorem integral_map_equiv {β} [MeasurableSpace β] (e : α ≃ᵐ β) (f : β → G) : ∫ y, f y ∂Measure.map e μ = ∫ x, f (e x) ∂μ := e.measurableEmbedding.integral_map f @@ -1788,7 +1787,7 @@ end Properties section IntegralTrim -variable {H β γ : Type*} [NormedAddCommGroup H] {m m0 : MeasurableSpace β} {μ : Measure β} +variable {β γ : Type*} {m m0 : MeasurableSpace β} {μ : Measure β} /-- Simple function seen as simple function of a larger `MeasurableSpace`. -/ def SimpleFunc.toLargerSpace (hm : m ≤ m0) (f : @SimpleFunc β m γ) : SimpleFunc β γ := diff --git a/Mathlib/MeasureTheory/Integral/CircleIntegral.lean b/Mathlib/MeasureTheory/Integral/CircleIntegral.lean index 673ac92017bbf..bd267c4c74fe6 100644 --- a/Mathlib/MeasureTheory/Integral/CircleIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/CircleIntegral.lean @@ -286,7 +286,7 @@ theorem circleIntegrable_sub_zpow_iff {c w : ℂ} {R : ℝ} {n : ℤ} : not_false_iff] using this have : x ∈ Ioo (0 : ℝ) 1 := by simpa [x, and_comm] using hθ' rw [← zpow_neg_one] - refine (zpow_strictAnti this.1 this.2).le_iff_le.2 (Int.lt_add_one_iff.1 ?_); exact hn + refine (zpow_right_strictAnti₀ this.1 this.2).le_iff_le.2 (Int.lt_add_one_iff.1 ?_); exact hn · rintro (rfl | H) exacts [circleIntegrable_zero_radius, ((continuousOn_id.sub continuousOn_const).zpow₀ _ fun z hz => diff --git a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean index 2280f163883e0..827108c784d82 100644 --- a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean +++ b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean @@ -6,9 +6,9 @@ Authors: Yury Kudryashov import Mathlib.Analysis.BoxIntegral.DivergenceTheorem import Mathlib.Analysis.BoxIntegral.Integrability import Mathlib.Analysis.Calculus.Deriv.Basic -import Mathlib.MeasureTheory.Constructions.Prod.Integral -import Mathlib.MeasureTheory.Integral.IntervalIntegral import Mathlib.Analysis.Calculus.FDeriv.Equiv +import Mathlib.MeasureTheory.Integral.Prod +import Mathlib.MeasureTheory.Integral.IntervalIntegral /-! # Divergence theorem for Bochner integral @@ -116,7 +116,7 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable_aux₁ (I : Box ( ∑ i : Fin (n + 1), ((∫ x in Box.Icc (I.face i), f (i.insertNth (I.upper i) x) i) - ∫ x in Box.Icc (I.face i), f (i.insertNth (I.lower i) x) i) := by - simp only [← setIntegral_congr_set_ae (Box.coe_ae_eq_Icc _)] + simp only [← setIntegral_congr_set (Box.coe_ae_eq_Icc _)] have A := (Hi.mono_set Box.coe_subset_Icc).hasBoxIntegral ⊥ rfl have B := hasIntegral_GP_divergence_of_forall_hasDerivWithinAt I f f' (s ∩ Box.Icc I) @@ -273,10 +273,10 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable (hle : a ≤ b) ((∫ x in face i, f (frontFace i x) i) - ∫ x in face i, f (backFace i x) i) := by rcases em (∃ i, a i = b i) with (⟨i, hi⟩ | hne) · -- First we sort out the trivial case `∃ i, a i = b i`. - rw [volume_pi, ← setIntegral_congr_set_ae Measure.univ_pi_Ioc_ae_eq_Icc] + rw [volume_pi, ← setIntegral_congr_set Measure.univ_pi_Ioc_ae_eq_Icc] have hi' : Ioc (a i) (b i) = ∅ := Ioc_eq_empty hi.not_lt have : (pi Set.univ fun j => Ioc (a j) (b j)) = ∅ := univ_pi_eq_empty hi' - rw [this, integral_empty, sum_eq_zero] + rw [this, setIntegral_empty, sum_eq_zero] rintro j - rcases eq_or_ne i j with (rfl | hne) · simp [hi] @@ -284,8 +284,8 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable (hle : a ≤ b) have : Icc (a ∘ j.succAbove) (b ∘ j.succAbove) =ᵐ[volume] (∅ : Set ℝⁿ) := by rw [ae_eq_empty, Real.volume_Icc_pi, prod_eq_zero (Finset.mem_univ i)] simp [hi] - rw [setIntegral_congr_set_ae this, setIntegral_congr_set_ae this, integral_empty, - integral_empty, sub_self] + rw [setIntegral_congr_set this, setIntegral_congr_set this, setIntegral_empty, + setIntegral_empty, sub_self] · -- In the non-trivial case `∀ i, a i < b i`, we apply a lemma we proved above. have hlt : ∀ i, a i < b i := fun i => (hle i).lt_of_ne fun hi => hne ⟨i, hi⟩ exact integral_divergence_of_hasFDerivWithinAt_off_countable_aux₂ ⟨a, b, hlt⟩ f f' s hs Hc @@ -382,7 +382,7 @@ theorem integral_eq_of_hasDerivWithinAt_off_countable_of_le (f f' : ℝ → E) { have hF' : ∀ x y, F' x y = y • f' x := fun x y => rfl calc ∫ x in a..b, f' x = ∫ x in Icc a b, f' x := by - rw [intervalIntegral.integral_of_le hle, setIntegral_congr_set_ae Ioc_ae_eq_Icc] + rw [intervalIntegral.integral_of_le hle, setIntegral_congr_set Ioc_ae_eq_Icc] _ = ∑ i : Fin 1, ((∫ x in Icc (e a ∘ i.succAbove) (e b ∘ i.succAbove), f (e.symm <| i.insertNth (e b i) x)) - @@ -467,7 +467,7 @@ theorem integral_divergence_prod_Icc_of_hasFDerivWithinAt_off_countable_of_le (f _ = (((∫ x in a.1..b.1, g (x, b.2)) - ∫ x in a.1..b.1, g (x, a.2)) + ∫ y in a.2..b.2, f (b.1, y)) - ∫ y in a.2..b.2, f (a.1, y) := by simp only [intervalIntegral.integral_of_le hle.1, intervalIntegral.integral_of_le hle.2, - setIntegral_congr_set_ae (Ioc_ae_eq_Icc (α := ℝ) (μ := volume))] + setIntegral_congr_set (Ioc_ae_eq_Icc (α := ℝ) (μ := volume))] abel /-- **Divergence theorem** for functions on the plane. It is formulated in terms of two functions @@ -506,7 +506,7 @@ theorem integral2_divergence_prod_of_hasFDerivWithinAt_off_countable (f g : ℝ (∫ x in a₁..b₁, ∫ y in a₂..b₂, f' (x, y) (1, 0) + g' (x, y) (0, 1)) = ∫ x in Icc a₁ b₁, ∫ y in Icc a₂ b₂, f' (x, y) (1, 0) + g' (x, y) (0, 1) := by simp only [intervalIntegral.integral_of_le, h₁, h₂, - setIntegral_congr_set_ae (Ioc_ae_eq_Icc (α := ℝ) (μ := volume))] + setIntegral_congr_set (Ioc_ae_eq_Icc (α := ℝ) (μ := volume))] _ = ∫ x in Icc a₁ b₁ ×ˢ Icc a₂ b₂, f' x (1, 0) + g' x (0, 1) := (setIntegral_prod _ Hi).symm _ = (((∫ x in a₁..b₁, g (x, b₂)) - ∫ x in a₁..b₁, g (x, a₂)) + ∫ y in a₂..b₂, f (b₁, y)) - ∫ y in a₂..b₂, f (a₁, y) := by diff --git a/Mathlib/MeasureTheory/Integral/Gamma.lean b/Mathlib/MeasureTheory/Integral/Gamma.lean index e45745db0df27..e8364efdee04a 100644 --- a/Mathlib/MeasureTheory/Integral/Gamma.lean +++ b/Mathlib/MeasureTheory/Integral/Gamma.lean @@ -24,11 +24,11 @@ theorem integral_rpow_mul_exp_neg_rpow {p q : ℝ} (hp : 0 < p) (hq : - 1 < q) : _ = ∫ (x : ℝ) in Ioi 0, (1 / p * x ^ (1 / p - 1)) • ((x ^ (1 / p)) ^ q * exp (-x)) := by rw [← integral_comp_rpow_Ioi _ (one_div_ne_zero (ne_of_gt hp)), abs_eq_self.mpr (le_of_lt (one_div_pos.mpr hp))] - refine setIntegral_congr measurableSet_Ioi (fun _ hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun _ hx => ?_) rw [← rpow_mul (le_of_lt hx) _ p, one_div_mul_cancel (ne_of_gt hp), rpow_one] _ = ∫ (x : ℝ) in Ioi 0, 1 / p * exp (-x) * x ^ (1 / p - 1 + q / p) := by simp_rw [smul_eq_mul, mul_assoc] - refine setIntegral_congr measurableSet_Ioi (fun _ hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun _ hx => ?_) rw [← rpow_mul (le_of_lt hx), div_mul_eq_mul_div, one_mul, rpow_add hx] ring_nf _ = (1 / p) * Gamma ((q + 1) / p) := by @@ -41,7 +41,7 @@ theorem integral_rpow_mul_exp_neg_mul_rpow {p q b : ℝ} (hp : 0 < p) (hq : - 1 b ^ (-(q + 1) / p) * (1 / p) * Gamma ((q + 1) / p) := by calc _ = ∫ x in Ioi (0 : ℝ), b ^ (-p⁻¹ * q) * ((b ^ p⁻¹ * x) ^ q * rexp (-(b ^ p⁻¹ * x) ^ p)) := by - refine setIntegral_congr measurableSet_Ioi (fun _ hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun _ hx => ?_) rw [mul_rpow _ (le_of_lt hx), mul_rpow _ (le_of_lt hx), ← rpow_mul, ← rpow_mul, inv_mul_cancel₀, rpow_one, mul_assoc, ← mul_assoc, ← rpow_add, neg_mul p⁻¹, neg_add_cancel, rpow_zero, one_mul, neg_mul] @@ -88,7 +88,7 @@ theorem Complex.integral_rpow_mul_exp_neg_rpow {p q : ℝ} (hp : 1 ≤ p) (hq : smul_eq_mul, mul_one, mul_comm] _ = 2 * π * ∫ x in Ioi (0 : ℝ), x ^ (q + 1) * rexp (-x ^ p) := by congr 1 - refine setIntegral_congr measurableSet_Ioi (fun x hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun x hx => ?_) rw [mem_Ioi] at hx rw [abs_eq_self.mpr hx.le, rpow_add hx, rpow_one] ring @@ -115,7 +115,7 @@ theorem Complex.integral_rpow_mul_exp_neg_mul_rpow {p q b : ℝ} (hp : 1 ≤ p) smul_eq_mul, mul_one, mul_comm] _ = 2 * π * ∫ x in Ioi (0 : ℝ), x ^ (q + 1) * rexp (-b * x ^ p) := by congr 1 - refine setIntegral_congr measurableSet_Ioi (fun x hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun x hx => ?_) rw [mem_Ioi] at hx rw [abs_eq_self.mpr hx.le, rpow_add hx, rpow_one] ring diff --git a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean index ae1b813c974c1..fec9cc5488e12 100644 --- a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean +++ b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean @@ -227,7 +227,7 @@ theorem MeasurePreserving.integrableOn_image [MeasurableSpace β] {e : α → β theorem integrable_indicator_iff (hs : MeasurableSet s) : Integrable (indicator s f) μ ↔ IntegrableOn f s μ := by simp [IntegrableOn, Integrable, HasFiniteIntegral, nnnorm_indicator_eq_indicator_nnnorm, - ENNReal.coe_indicator, lintegral_indicator _ hs, aestronglyMeasurable_indicator_iff hs] + ENNReal.coe_indicator, lintegral_indicator hs, aestronglyMeasurable_indicator_iff hs] theorem IntegrableOn.integrable_indicator (h : IntegrableOn f s μ) (hs : MeasurableSet s) : Integrable (indicator s f) μ := @@ -591,7 +591,7 @@ theorem ContinuousOn.stronglyMeasurableAtFilter [TopologicalSpace α] [OpensMeas theorem ContinuousAt.stronglyMeasurableAtFilter [TopologicalSpace α] [OpensMeasurableSpace α] [SecondCountableTopologyEither α E] {f : α → E} {s : Set α} {μ : Measure α} (hs : IsOpen s) (hf : ∀ x ∈ s, ContinuousAt f x) : ∀ x ∈ s, StronglyMeasurableAtFilter f (𝓝 x) μ := - ContinuousOn.stronglyMeasurableAtFilter hs <| ContinuousAt.continuousOn hf + ContinuousOn.stronglyMeasurableAtFilter hs <| continuousOn_of_forall_continuousAt hf theorem Continuous.stronglyMeasurableAtFilter [TopologicalSpace α] [OpensMeasurableSpace α] [TopologicalSpace β] [PseudoMetrizableSpace β] [SecondCountableTopologyEither α β] {f : α → β} diff --git a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean index ac2ffb0b0ce8f..b0faec3a21f94 100644 --- a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean +++ b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean @@ -344,7 +344,7 @@ theorem AECover.biInter_Ici_aecover [Preorder ι] {φ : ι → Set α} (hφ : AECover μ atTop φ) : AECover μ atTop fun n : ι => ⋂ (k) (_h : k ∈ Ici n), φ k where ae_eventually_mem := hφ.ae_eventually_mem.mono fun x h ↦ by simpa only [mem_iInter, mem_Ici, eventually_forall_ge_atTop] - measurableSet i := .biInter (to_countable _) fun n _ => hφ.measurableSet n + measurableSet _ := .biInter (to_countable _) fun n _ => hφ.measurableSet n end AECoverUnionInterCountable @@ -361,7 +361,7 @@ private theorem lintegral_tendsto_of_monotone_of_nat {φ : ℕ → Set α} (hφ indicator_le_indicator_of_subset (hmono hij) (fun x => zero_le <| f x) x have key₃ : ∀ᵐ x : α ∂μ, Tendsto (fun n => F n x) atTop (𝓝 (f x)) := hφ.ae_tendsto_indicator f (lintegral_tendsto_of_tendsto_of_monotone key₁ key₂ key₃).congr fun n => - lintegral_indicator f (hφ.measurableSet n) + lintegral_indicator (hφ.measurableSet n) _ theorem AECover.lintegral_tendsto_of_nat {φ : ℕ → Set α} (hφ : AECover μ atTop φ) {f : α → ℝ≥0∞} (hfm : AEMeasurable f μ) : Tendsto (∫⁻ x in φ ·, f x ∂μ) atTop (𝓝 <| ∫⁻ x, f x ∂μ) := by @@ -475,7 +475,7 @@ theorem AECover.integral_tendsto_of_countably_generated [l.IsCountablyGenerated] convert h using 2; rw [integral_indicator (hφ.measurableSet _)] tendsto_integral_filter_of_dominated_convergence (fun x => ‖f x‖) (Eventually.of_forall fun i => hfi.aestronglyMeasurable.indicator <| hφ.measurableSet i) - (Eventually.of_forall fun i => ae_of_all _ fun x => norm_indicator_le_norm_self _ _) hfi.norm + (Eventually.of_forall fun _ => ae_of_all _ fun _ => norm_indicator_le_norm_self _ _) hfi.norm (hφ.ae_tendsto_indicator f) /-- Slight reformulation of @@ -642,7 +642,7 @@ open scoped Interval section IoiFTC -variable {E : Type*} {f f' : ℝ → E} {g g' : ℝ → ℝ} {a b l : ℝ} {m : E} [NormedAddCommGroup E] +variable {E : Type*} {f f' : ℝ → E} {g g' : ℝ → ℝ} {a l : ℝ} {m : E} [NormedAddCommGroup E] [NormedSpace ℝ E] /-- If the derivative of a function defined on the real line is integrable close to `+∞`, then @@ -711,8 +711,8 @@ theorem tendsto_zero_of_hasDerivAt_of_integrableOn_Ioi rcases mem_atTop_sets.1 hs with ⟨b, hb⟩ rw [← top_le_iff, ← volume_Ici (a := b)] exact measure_mono hb - rwa [B, ← Embedding.tendsto_nhds_iff] at A - exact (Completion.isUniformEmbedding_coe E).embedding + rwa [B, ← IsEmbedding.tendsto_nhds_iff] at A + exact (Completion.isUniformEmbedding_coe E).isEmbedding variable [CompleteSpace E] @@ -793,7 +793,7 @@ theorem integrableOn_Ioi_deriv_of_nonneg (hcont : ContinuousWithinAt g (Ici a) a (fun y hy => hderiv y hy.1) fun y hy => g'pos y hy.1 _ = ∫ y in a..id x, ‖g' y‖ := by simp_rw [intervalIntegral.integral_of_le h'x] - refine setIntegral_congr measurableSet_Ioc fun y hy => ?_ + refine setIntegral_congr_fun measurableSet_Ioc fun y hy => ?_ dsimp rw [abs_of_nonneg] exact g'pos _ hy.1 @@ -864,7 +864,7 @@ end IoiFTC section IicFTC -variable {E : Type*} {f f' : ℝ → E} {g g' : ℝ → ℝ} {a b l : ℝ} {m : E} [NormedAddCommGroup E] +variable {E : Type*} {f f' : ℝ → E} {a : ℝ} {m : E} [NormedAddCommGroup E] [NormedSpace ℝ E] /-- If the derivative of a function defined on the real line is integrable close to `-∞`, then @@ -908,8 +908,8 @@ theorem tendsto_zero_of_hasDerivAt_of_integrableOn_Iic apply le_antisymm (le_top) rw [← volume_Iic (a := b)] exact measure_mono hb - rwa [B, ← Embedding.tendsto_nhds_iff] at A - exact (Completion.isUniformEmbedding_coe E).embedding + rwa [B, ← IsEmbedding.tendsto_nhds_iff] at A + exact (Completion.isUniformEmbedding_coe E).isEmbedding variable [CompleteSpace E] @@ -983,7 +983,7 @@ end IicFTC section UnivFTC -variable {E : Type*} {f f' : ℝ → E} {g g' : ℝ → ℝ} {a b l : ℝ} {m n : E} [NormedAddCommGroup E] +variable {E : Type*} {f f' : ℝ → E} {m n : E} [NormedAddCommGroup E] [NormedSpace ℝ E] /-- **Fundamental theorem of calculus-2**, on the whole real line @@ -996,8 +996,8 @@ see `tendsto_limUnder_of_hasDerivAt_of_integrableOn_Iic` and theorem integral_of_hasDerivAt_of_tendsto [CompleteSpace E] (hderiv : ∀ x, HasDerivAt f (f' x) x) (hf' : Integrable f') (hbot : Tendsto f atBot (𝓝 m)) (htop : Tendsto f atTop (𝓝 n)) : ∫ x, f' x = n - m := by - rw [← integral_univ, ← Set.Iic_union_Ioi (a := 0), - integral_union (Iic_disjoint_Ioi le_rfl) measurableSet_Ioi hf'.integrableOn hf'.integrableOn, + rw [← setIntegral_univ, ← Set.Iic_union_Ioi (a := 0), + setIntegral_union (Iic_disjoint_Ioi le_rfl) measurableSet_Ioi hf'.integrableOn hf'.integrableOn, integral_Iic_of_hasDerivAt_of_tendsto' (fun x _ ↦ hderiv x) hf'.integrableOn hbot, integral_Ioi_of_hasDerivAt_of_tendsto' (fun x _ ↦ hderiv x) hf'.integrableOn htop] abel @@ -1025,7 +1025,7 @@ open Real open scoped Interval -variable {E : Type*} {f : ℝ → E} [NormedAddCommGroup E] [NormedSpace ℝ E] +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] /-- Change-of-variables formula for `Ioi` integrals of vector-valued functions, proved by taking limits from the result for finite intervals. -/ @@ -1075,7 +1075,7 @@ theorem integral_comp_rpow_Ioi (g : ℝ → E) {p : ℝ} (hp : p ≠ 0) : rcases lt_or_gt_of_ne hp with (h | h) · apply StrictAntiOn.injOn intro x hx y hy hxy - rw [← inv_lt_inv (rpow_pos_of_pos hx p) (rpow_pos_of_pos hy p), ← rpow_neg (le_of_lt hx), + rw [← inv_lt_inv₀ (rpow_pos_of_pos hx p) (rpow_pos_of_pos hy p), ← rpow_neg (le_of_lt hx), ← rpow_neg (le_of_lt hy)] exact rpow_lt_rpow (le_of_lt hx) hxy (neg_pos.mpr h) exact StrictMonoOn.injOn fun x hx y _ hxy => rpow_lt_rpow (mem_Ioi.mp hx).le hxy h @@ -1086,7 +1086,7 @@ theorem integral_comp_rpow_Ioi (g : ℝ → E) {p : ℝ} (hp : p ≠ 0) : rw [← rpow_mul (le_of_lt hx), one_div_mul_cancel hp, rpow_one] have := integral_image_eq_integral_abs_deriv_smul measurableSet_Ioi a1 a2 g rw [a3] at this; rw [this] - refine setIntegral_congr measurableSet_Ioi ?_ + refine setIntegral_congr_fun measurableSet_Ioi ?_ intro x hx; dsimp only rw [abs_mul, abs_of_nonneg (rpow_nonneg (le_of_lt hx) _)] @@ -1129,7 +1129,7 @@ theorem integrableOn_Ioi_comp_rpow_iff [NormedSpace ℝ E] (f : ℝ → E) {p : rcases lt_or_gt_of_ne hp with (h | h) · apply StrictAntiOn.injOn intro x hx y hy hxy - rw [← inv_lt_inv (rpow_pos_of_pos hx p) (rpow_pos_of_pos hy p), ← rpow_neg (le_of_lt hx), ← + rw [← inv_lt_inv₀ (rpow_pos_of_pos hx p) (rpow_pos_of_pos hy p), ← rpow_neg (le_of_lt hx), ← rpow_neg (le_of_lt hy)] exact rpow_lt_rpow (le_of_lt hx) hxy (neg_pos.mpr h) exact StrictMonoOn.injOn fun x hx y _hy hxy => rpow_lt_rpow (mem_Ioi.mp hx).le hxy h @@ -1224,7 +1224,7 @@ end IntegrationByPartsBilinear section IntegrationByPartsAlgebra variable {A : Type*} [NormedRing A] [NormedAlgebra ℝ A] - {a b : ℝ} {a' b' : A} {u : ℝ → A} {v : ℝ → A} {u' : ℝ → A} {v' : ℝ → A} + {a : ℝ} {a' b' : A} {u : ℝ → A} {v : ℝ → A} {u' : ℝ → A} {v' : ℝ → A} /-- For finite intervals, see: `intervalIntegral.integral_deriv_mul_eq_sub`. -/ theorem integral_deriv_mul_eq_sub [CompleteSpace A] diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index d7473d6e2d8df..ff624c6f12d1a 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -120,7 +120,7 @@ theorem intervalIntegrable_const_iff {c : E} : IntervalIntegrable (fun _ => c) μ a b ↔ c = 0 ∨ μ (Ι a b) < ∞ := by simp only [intervalIntegrable_iff, integrableOn_const] -@[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem intervalIntegrable_const [IsLocallyFiniteMeasure μ] {c : E} : IntervalIntegrable (fun _ => c) μ a b := intervalIntegrable_const_iff.2 <| Or.inr measure_Ioc_lt_top @@ -271,7 +271,7 @@ theorem comp_mul_left (hf : IntervalIntegrable f volume a b) (c : ℝ) : rcases eq_or_ne c 0 with (hc | hc); · rw [hc]; simp rw [intervalIntegrable_iff'] at hf ⊢ have A : MeasurableEmbedding fun x => x * c⁻¹ := - (Homeomorph.mulRight₀ _ (inv_ne_zero hc)).closedEmbedding.measurableEmbedding + (Homeomorph.mulRight₀ _ (inv_ne_zero hc)).isClosedEmbedding.measurableEmbedding rw [← Real.smul_map_volume_mul_right (inv_ne_zero hc), IntegrableOn, Measure.restrict_smul, integrable_smul_measure (by simpa : ENNReal.ofReal |c⁻¹| ≠ 0) ENNReal.ofReal_ne_top, ← IntegrableOn, MeasurableEmbedding.integrableOn_map_iff A] @@ -294,7 +294,7 @@ theorem comp_add_right (hf : IntervalIntegrable f volume a b) (c : ℝ) : · exact IntervalIntegrable.symm (this hf.symm (le_of_not_le h)) rw [intervalIntegrable_iff'] at hf ⊢ have A : MeasurableEmbedding fun x => x + c := - (Homeomorph.addRight c).closedEmbedding.measurableEmbedding + (Homeomorph.addRight c).isClosedEmbedding.measurableEmbedding rw [← map_add_right_eq_self volume c] at hf convert (MeasurableEmbedding.integrableOn_map_iff A).mp hf using 1 rw [preimage_add_const_uIcc] @@ -624,7 +624,7 @@ variable {a b c d : ℝ} (f : ℝ → E) theorem integral_comp_mul_right (hc : c ≠ 0) : (∫ x in a..b, f (x * c)) = c⁻¹ • ∫ x in a * c..b * c, f x := by have A : MeasurableEmbedding fun x => x * c := - (Homeomorph.mulRight₀ c hc).closedEmbedding.measurableEmbedding + (Homeomorph.mulRight₀ c hc).isClosedEmbedding.measurableEmbedding conv_rhs => rw [← Real.smul_map_volume_mul_right hc] simp_rw [integral_smul_measure, intervalIntegral, A.setIntegral_map, ENNReal.toReal_ofReal (abs_nonneg c)] @@ -661,7 +661,7 @@ theorem inv_smul_integral_comp_div (c) : @[simp] theorem integral_comp_add_right (d) : (∫ x in a..b, f (x + d)) = ∫ x in a + d..b + d, f x := have A : MeasurableEmbedding fun x => x + d := - (Homeomorph.addRight d).closedEmbedding.measurableEmbedding + (Homeomorph.addRight d).isClosedEmbedding.measurableEmbedding calc (∫ x in a..b, f (x + d)) = ∫ x in a + d..b + d, f x ∂Measure.map (fun x => x + d) volume := by simp [intervalIntegral, A.setIntegral_map] @@ -786,14 +786,14 @@ theorem integral_congr {a b : ℝ} (h : EqOn f g [[a, b]]) : ∫ x in a..b, f x ∂μ = ∫ x in a..b, g x ∂μ := by rcases le_total a b with hab | hab <;> simpa [hab, integral_of_le, integral_of_ge] using - setIntegral_congr measurableSet_Ioc (h.mono Ioc_subset_Icc_self) + setIntegral_congr_fun measurableSet_Ioc (h.mono Ioc_subset_Icc_self) theorem integral_add_adjacent_intervals_cancel (hab : IntervalIntegrable f μ a b) (hbc : IntervalIntegrable f μ b c) : (((∫ x in a..b, f x ∂μ) + ∫ x in b..c, f x ∂μ) + ∫ x in c..a, f x ∂μ) = 0 := by have hac := hab.trans hbc simp only [intervalIntegral, sub_add_sub_comm, sub_eq_zero] - iterate 4 rw [← integral_union] + iterate 4 rw [← setIntegral_union] · suffices Ioc a b ∪ Ioc b c ∪ Ioc c a = Ioc b a ∪ Ioc c b ∪ Ioc a c by rw [this] rw [Ioc_union_Ioc_union_Ioc_cycle, union_right_comm, Ioc_union_Ioc_union_Ioc_cycle, min_left_comm, max_left_comm] @@ -857,20 +857,20 @@ theorem integral_Iic_sub_Iic (ha : IntegrableOn f (Iic a) μ) (hb : IntegrableOn ((∫ x in Iic b, f x ∂μ) - ∫ x in Iic a, f x ∂μ) = ∫ x in a..b, f x ∂μ := by wlog hab : a ≤ b generalizing a b · rw [integral_symm, ← this hb ha (le_of_not_le hab), neg_sub] - rw [sub_eq_iff_eq_add', integral_of_le hab, ← integral_union (Iic_disjoint_Ioc le_rfl), + rw [sub_eq_iff_eq_add', integral_of_le hab, ← setIntegral_union (Iic_disjoint_Ioc le_rfl), Iic_union_Ioc_eq_Iic hab] exacts [measurableSet_Ioc, ha, hb.mono_set fun _ => And.right] theorem integral_Iic_add_Ioi (h_left : IntegrableOn f (Iic b) μ) (h_right : IntegrableOn f (Ioi b) μ) : (∫ x in Iic b, f x ∂μ) + (∫ x in Ioi b, f x ∂μ) = ∫ (x : ℝ), f x ∂μ := by - convert (integral_union (Iic_disjoint_Ioi <| Eq.le rfl) measurableSet_Ioi h_left h_right).symm + convert (setIntegral_union (Iic_disjoint_Ioi <| Eq.le rfl) measurableSet_Ioi h_left h_right).symm rw [Iic_union_Ioi, Measure.restrict_univ] theorem integral_Iio_add_Ici (h_left : IntegrableOn f (Iio b) μ) (h_right : IntegrableOn f (Ici b) μ) : (∫ x in Iio b, f x ∂μ) + (∫ x in Ici b, f x ∂μ) = ∫ (x : ℝ), f x ∂μ := by - convert (integral_union (Iio_disjoint_Ici <| Eq.le rfl) measurableSet_Ici h_left h_right).symm + convert (setIntegral_union (Iio_disjoint_Ici <| Eq.le rfl) measurableSet_Ici h_left h_right).symm rw [Iio_union_Ici, Measure.restrict_univ] /-- If `μ` is a finite measure then `∫ x in a..b, c ∂μ = (μ (Iic b) - μ (Iic a)) • c`. -/ @@ -1075,7 +1075,7 @@ variable {μ : Measure ℝ} {f : ℝ → E} theorem _root_.MeasureTheory.Integrable.hasSum_intervalIntegral (hfi : Integrable f μ) (y : ℝ) : HasSum (fun n : ℤ => ∫ x in y + n..y + n + 1, f x ∂μ) (∫ x, f x ∂μ) := by simp_rw [integral_of_le (le_add_of_nonneg_right zero_le_one)] - rw [← integral_univ, ← iUnion_Ioc_add_intCast y] + rw [← setIntegral_univ, ← iUnion_Ioc_add_intCast y] exact hasSum_integral_iUnion (fun i => measurableSet_Ioc) (pairwise_disjoint_Ioc_add_intCast y) hfi.integrableOn diff --git a/Mathlib/MeasureTheory/Integral/Layercake.lean b/Mathlib/MeasureTheory/Integral/Layercake.lean index ccdbcf47487ab..7059fa3093f5a 100644 --- a/Mathlib/MeasureTheory/Integral/Layercake.lean +++ b/Mathlib/MeasureTheory/Integral/Layercake.lean @@ -91,7 +91,7 @@ end section Layercake -variable {α : Type*} [MeasurableSpace α] {f : α → ℝ} {g : ℝ → ℝ} {s : Set α} +variable {α : Type*} [MeasurableSpace α] {f : α → ℝ} {g : ℝ → ℝ} /-- An auxiliary version of the layer cake formula (Cavalieri's principle, tail probability formula), with a measurability assumption that would also essentially follow from the @@ -122,9 +122,9 @@ theorem lintegral_comp_eq_lintegral_meas_le_mul_of_measurable_of_sigmaFinite congr exact intervalIntegral.integral_of_le (f_nn ω) rw [lintegral_congr integrand_eq] - simp_rw [← lintegral_indicator (fun t => ENNReal.ofReal (g t)) measurableSet_Ioc] + simp_rw [← lintegral_indicator measurableSet_Ioc] -- Porting note: was part of `simp_rw` on the previous line, but didn't trigger. - rw [← lintegral_indicator _ measurableSet_Ioi, lintegral_lintegral_swap] + rw [← lintegral_indicator measurableSet_Ioi, lintegral_lintegral_swap] · apply congr_arg funext s have aux₁ : @@ -458,9 +458,8 @@ end Layercake section LayercakeLT -variable {α : Type*} [MeasurableSpace α] (μ : Measure α) -variable {β : Type*} [MeasurableSpace β] [MeasurableSingletonClass β] -variable {f : α → ℝ} {g : ℝ → ℝ} {s : Set α} +variable {α : Type*} [MeasurableSpace α] +variable {f : α → ℝ} {g : ℝ → ℝ} /-- The layer cake formula / Cavalieri's principle / tail probability formula: diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean index 9fced5cac44e7..2108802bc1e8e 100644 --- a/Mathlib/MeasureTheory/Integral/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Integral/Lebesgue.lean @@ -129,7 +129,6 @@ theorem lintegral_zero : ∫⁻ _ : α, 0 ∂μ = 0 := by simp theorem lintegral_zero_fun : lintegral μ (0 : α → ℝ≥0∞) = 0 := lintegral_zero --- @[simp] -- Porting note (#10618): simp can prove this theorem lintegral_one : ∫⁻ _, (1 : ℝ≥0∞) ∂μ = μ univ := by rw [lintegral_const, one_mul] theorem setLIntegral_const (s : Set α) (c : ℝ≥0∞) : ∫⁻ _ in s, c ∂μ = c * μ s := by @@ -171,7 +170,7 @@ theorem exists_measurable_le_lintegral_eq (f : α → ℝ≥0∞) : (hLf n).2 choose g hgm hgf hLg using this refine - ⟨fun x => ⨆ n, g n x, measurable_iSup hgm, fun x => iSup_le fun n => hgf n x, le_antisymm ?_ ?_⟩ + ⟨fun x => ⨆ n, g n x, .iSup hgm, fun x => iSup_le fun n => hgf n x, le_antisymm ?_ ?_⟩ · refine le_of_tendsto' hL_tendsto fun n => (hLg n).le.trans <| lintegral_mono fun x => ?_ exact le_iSup (fun n => g n x) n · exact lintegral_mono fun x => iSup_le fun n => hgf n x @@ -530,7 +529,7 @@ theorem lintegral_add_aux {f g : α → ℝ≥0∞} (hf : Measurable f) (hg : Me funext n rw [← SimpleFunc.add_lintegral, ← SimpleFunc.lintegral_eq_lintegral] simp only [Pi.add_apply, SimpleFunc.coe_add] - · measurability + · fun_prop · intro i j h a dsimp gcongr <;> exact monotone_eapprox _ h _ @@ -757,7 +756,7 @@ theorem lintegral_indicator_le (f : α → ℝ≥0∞) (s : Set α) : simpa [H] using hg x @[simp] -theorem lintegral_indicator (f : α → ℝ≥0∞) {s : Set α} (hs : MeasurableSet s) : +theorem lintegral_indicator {s : Set α} (hs : MeasurableSet s) (f : α → ℝ≥0∞) : ∫⁻ a, s.indicator f a ∂μ = ∫⁻ a in s, f a ∂μ := by apply le_antisymm (lintegral_indicator_le f s) simp only [lintegral, ← restrict_lintegral_eq_lintegral_restrict _ hs, iSup_subtype'] @@ -765,19 +764,28 @@ theorem lintegral_indicator (f : α → ℝ≥0∞) {s : Set α} (hs : Measurabl refine ⟨⟨φ.restrict s, fun x => ?_⟩, le_rfl⟩ simp [hφ x, hs, indicator_le_indicator] -theorem lintegral_indicator₀ (f : α → ℝ≥0∞) {s : Set α} (hs : NullMeasurableSet s μ) : +lemma setLIntegral_indicator {s t : Set α} (hs : MeasurableSet s) (f : α → ℝ≥0∞) : + ∫⁻ a in t, s.indicator f a ∂μ = ∫⁻ a in s ∩ t, f a ∂μ := by + rw [lintegral_indicator hs, Measure.restrict_restrict hs] + +theorem lintegral_indicator₀ {s : Set α} (hs : NullMeasurableSet s μ) (f : α → ℝ≥0∞) : ∫⁻ a, s.indicator f a ∂μ = ∫⁻ a in s, f a ∂μ := by rw [← lintegral_congr_ae (indicator_ae_eq_of_ae_eq_set hs.toMeasurable_ae_eq), - lintegral_indicator _ (measurableSet_toMeasurable _ _), + lintegral_indicator (measurableSet_toMeasurable _ _), Measure.restrict_congr_set hs.toMeasurable_ae_eq] +lemma setLIntegral_indicator₀ (f : α → ℝ≥0∞) {s t : Set α} + (hs : NullMeasurableSet s (μ.restrict t)) : + ∫⁻ a in t, s.indicator f a ∂μ = ∫⁻ a in s ∩ t, f a ∂μ := by + rw [lintegral_indicator₀ hs, Measure.restrict_restrict₀ hs] + theorem lintegral_indicator_const_le (s : Set α) (c : ℝ≥0∞) : ∫⁻ a, s.indicator (fun _ => c) a ∂μ ≤ c * μ s := (lintegral_indicator_le _ _).trans (setLIntegral_const s c).le theorem lintegral_indicator_const₀ {s : Set α} (hs : NullMeasurableSet s μ) (c : ℝ≥0∞) : ∫⁻ a, s.indicator (fun _ => c) a ∂μ = c * μ s := by - rw [lintegral_indicator₀ _ hs, setLIntegral_const] + rw [lintegral_indicator₀ hs, setLIntegral_const] theorem lintegral_indicator_const {s : Set α} (hs : MeasurableSet s) (c : ℝ≥0∞) : ∫⁻ a, s.indicator (fun _ => c) a ∂μ = c * μ s := @@ -860,6 +868,13 @@ lemma lintegral_le_meas {s : Set α} {f : α → ℝ≥0∞} (hf : ∀ a, f a · simpa [hx] using hf x · simpa [hx] using h'f x hx +lemma setLIntegral_le_meas {s t : Set α} (hs : MeasurableSet s) + {f : α → ℝ≥0∞} (hf : ∀ a ∈ s, a ∈ t → f a ≤ 1) + (hf' : ∀ a ∈ s, a ∉ t → f a = 0) : ∫⁻ a in s, f a ∂μ ≤ μ t := by + rw [← lintegral_indicator hs] + refine lintegral_le_meas (fun a ↦ ?_) (by aesop) + by_cases has : a ∈ s <;> [by_cases hat : a ∈ t; skip] <;> simp [*] + theorem lintegral_eq_top_of_measure_eq_top_ne_zero {f : α → ℝ≥0∞} (hf : AEMeasurable f μ) (hμf : μ {x | f x = ∞} ≠ 0) : ∫⁻ x, f x ∂μ = ∞ := eq_top_iff.mpr <| @@ -1012,19 +1027,19 @@ theorem lintegral_iInf_ae {f : ℕ → α → ℝ≥0∞} (h_meas : ∀ n, Measu (h_mono : ∀ n : ℕ, f n.succ ≤ᵐ[μ] f n) (h_fin : ∫⁻ a, f 0 a ∂μ ≠ ∞) : ∫⁻ a, ⨅ n, f n a ∂μ = ⨅ n, ∫⁻ a, f n a ∂μ := have fn_le_f0 : ∫⁻ a, ⨅ n, f n a ∂μ ≤ ∫⁻ a, f 0 a ∂μ := - lintegral_mono fun a => iInf_le_of_le 0 le_rfl + lintegral_mono fun _ => iInf_le_of_le 0 le_rfl have fn_le_f0' : ⨅ n, ∫⁻ a, f n a ∂μ ≤ ∫⁻ a, f 0 a ∂μ := iInf_le_of_le 0 le_rfl (ENNReal.sub_right_inj h_fin fn_le_f0 fn_le_f0').1 <| show ∫⁻ a, f 0 a ∂μ - ∫⁻ a, ⨅ n, f n a ∂μ = ∫⁻ a, f 0 a ∂μ - ⨅ n, ∫⁻ a, f n a ∂μ from calc ∫⁻ a, f 0 a ∂μ - ∫⁻ a, ⨅ n, f n a ∂μ = ∫⁻ a, f 0 a - ⨅ n, f n a ∂μ := - (lintegral_sub (measurable_iInf h_meas) - (ne_top_of_le_ne_top h_fin <| lintegral_mono fun a => iInf_le _ _) - (ae_of_all _ fun a => iInf_le _ _)).symm - _ = ∫⁻ a, ⨆ n, f 0 a - f n a ∂μ := congr rfl (funext fun a => ENNReal.sub_iInf) + (lintegral_sub (.iInf h_meas) + (ne_top_of_le_ne_top h_fin <| lintegral_mono fun _ => iInf_le _ _) + (ae_of_all _ fun _ => iInf_le _ _)).symm + _ = ∫⁻ a, ⨆ n, f 0 a - f n a ∂μ := congr rfl (funext fun _ => ENNReal.sub_iInf) _ = ⨆ n, ∫⁻ a, f 0 a - f n a ∂μ := (lintegral_iSup_ae (fun n => (h_meas 0).sub (h_meas n)) fun n => - (h_mono n).mono fun a ha => tsub_le_tsub le_rfl ha) + (h_mono n).mono fun _ ha => tsub_le_tsub le_rfl ha) _ = ⨆ n, ∫⁻ a, f 0 a ∂μ - ∫⁻ a, f n a ∂μ := (have h_mono : ∀ᵐ a ∂μ, ∀ n : ℕ, f n.succ a ≤ f n a := ae_all_iff.2 h_mono have h_mono : ∀ n, ∀ᵐ a ∂μ, f n a ≤ f 0 a := fun n => @@ -1097,9 +1112,9 @@ theorem lintegral_liminf_le' {f : ℕ → α → ℝ≥0∞} (h_meas : ∀ n, AE ∫⁻ a, liminf (fun n => f n a) atTop ∂μ = ∫⁻ a, ⨆ n : ℕ, ⨅ i ≥ n, f i a ∂μ := by simp only [liminf_eq_iSup_iInf_of_nat] _ = ⨆ n : ℕ, ∫⁻ a, ⨅ i ≥ n, f i a ∂μ := - (lintegral_iSup' (fun n => aemeasurable_biInf _ (to_countable _) (fun i _ ↦ h_meas i)) - (ae_of_all μ fun a n m hnm => iInf_le_iInf_of_subset fun i hi => le_trans hnm hi)) - _ ≤ ⨆ n : ℕ, ⨅ i ≥ n, ∫⁻ a, f i a ∂μ := iSup_mono fun n => le_iInf₂_lintegral _ + (lintegral_iSup' (fun _ => .biInf _ (to_countable _) (fun i _ ↦ h_meas i)) + (ae_of_all μ fun _ _ _ hnm => iInf_le_iInf_of_subset fun _ hi => le_trans hnm hi)) + _ ≤ ⨆ n : ℕ, ⨅ i ≥ n, ∫⁻ a, f i a ∂μ := iSup_mono fun _ => le_iInf₂_lintegral _ _ = atTop.liminf fun n => ∫⁻ a, f n a ∂μ := Filter.liminf_eq_iSup_iInf_of_nat.symm /-- Known as Fatou's lemma -/ @@ -1113,11 +1128,11 @@ theorem limsup_lintegral_le {f : ℕ → α → ℝ≥0∞} (g : α → ℝ≥0 calc limsup (fun n => ∫⁻ a, f n a ∂μ) atTop = ⨅ n : ℕ, ⨆ i ≥ n, ∫⁻ a, f i a ∂μ := limsup_eq_iInf_iSup_of_nat - _ ≤ ⨅ n : ℕ, ∫⁻ a, ⨆ i ≥ n, f i a ∂μ := iInf_mono fun n => iSup₂_lintegral_le _ + _ ≤ ⨅ n : ℕ, ∫⁻ a, ⨆ i ≥ n, f i a ∂μ := iInf_mono fun _ => iSup₂_lintegral_le _ _ = ∫⁻ a, ⨅ n : ℕ, ⨆ i ≥ n, f i a ∂μ := by refine (lintegral_iInf ?_ ?_ ?_).symm · intro n - exact measurable_biSup _ (to_countable _) (fun i _ ↦ hf_meas i) + exact .biSup _ (to_countable _) (fun i _ ↦ hf_meas i) · intro n m hnm a exact iSup_le_iSup_of_subset fun i hi => le_trans hnm hi · refine ne_top_of_le_ne_top h_fin (lintegral_mono_ae ?_) @@ -1133,13 +1148,13 @@ theorem tendsto_lintegral_of_dominated_convergence {F : ℕ → α → ℝ≥0 tendsto_of_le_liminf_of_limsup_le (calc ∫⁻ a, f a ∂μ = ∫⁻ a, liminf (fun n : ℕ => F n a) atTop ∂μ := - lintegral_congr_ae <| h_lim.mono fun a h => h.liminf_eq.symm + lintegral_congr_ae <| h_lim.mono fun _ h => h.liminf_eq.symm _ ≤ liminf (fun n => ∫⁻ a, F n a ∂μ) atTop := lintegral_liminf_le hF_meas ) (calc limsup (fun n : ℕ => ∫⁻ a, F n a ∂μ) atTop ≤ ∫⁻ a, limsup (fun n => F n a) atTop ∂μ := limsup_lintegral_le _ hF_meas h_bound h_fin - _ = ∫⁻ a, f a ∂μ := lintegral_congr_ae <| h_lim.mono fun a h => h.limsup_eq + _ = ∫⁻ a, f a ∂μ := lintegral_congr_ae <| h_lim.mono fun _ h => h.limsup_eq ) /-- Dominated convergence theorem for nonnegative functions which are just almost everywhere @@ -1820,9 +1835,9 @@ theorem exists_measurable_le_forall_setLIntegral_eq [SFinite μ] (f : α → ℝ · exact ⟨g, hgm, hgle, fun s ↦ (hleg s).antisymm (lintegral_mono hgle)⟩ -- Without loss of generality, `μ` is a finite measure. wlog h : IsFiniteMeasure μ generalizing μ - · choose g hgm hgle hgint using fun n ↦ @this (sFiniteSeq μ n) _ inferInstance - refine ⟨fun x ↦ ⨆ n, g n x, measurable_iSup hgm, fun x ↦ iSup_le (hgle · x), fun s ↦ ?_⟩ - rw [← sum_sFiniteSeq μ, Measure.restrict_sum_of_countable, + · choose g hgm hgle hgint using fun n ↦ @this (sfiniteSeq μ n) _ inferInstance + refine ⟨fun x ↦ ⨆ n, g n x, .iSup hgm, fun x ↦ iSup_le (hgle · x), fun s ↦ ?_⟩ + rw [← sum_sfiniteSeq μ, Measure.restrict_sum_of_countable, lintegral_sum_measure, lintegral_sum_measure] exact ENNReal.tsum_le_tsum fun n ↦ (hgint n s).trans (lintegral_mono fun x ↦ le_iSup (g · x) _) -- According to `exists_measurable_le_lintegral_eq`, for any natural `n` @@ -1882,18 +1897,18 @@ theorem exists_pos_lintegral_lt_of_sigmaFinite (μ : Measure α) [SigmaFinite μ obtain ⟨δ, δpos, δsum⟩ : ∃ δ : ℕ → ℝ≥0, (∀ i, 0 < δ i) ∧ (∑' i, μ (s i) * δ i) < ε := ENNReal.exists_pos_tsum_mul_lt_of_countable ε0 _ fun n => (this n).ne set N : α → ℕ := spanningSetsIndex μ - have hN_meas : Measurable N := measurable_spanningSetsIndex μ + have hN_meas : Measurable N := measurableSet_spanningSetsIndex μ have hNs : ∀ n, N ⁻¹' {n} = s n := preimage_spanningSetsIndex_singleton μ refine ⟨δ ∘ N, fun x => δpos _, measurable_from_nat.comp hN_meas, ?_⟩ erw [lintegral_comp measurable_from_nat.coe_nnreal_ennreal hN_meas] - simpa [N, hNs, lintegral_countable', measurable_spanningSetsIndex, mul_comm] using δsum + simpa [N, hNs, lintegral_countable', measurableSet_spanningSetsIndex, mul_comm] using δsum theorem lintegral_trim {μ : Measure α} (hm : m ≤ m0) {f : α → ℝ≥0∞} (hf : Measurable[m] f) : ∫⁻ a, f a ∂μ.trim hm = ∫⁻ a, f a ∂μ := by refine @Measurable.ennreal_induction α m (fun f => ∫⁻ a, f a ∂μ.trim hm = ∫⁻ a, f a ∂μ) ?_ ?_ ?_ f hf · intro c s hs - rw [lintegral_indicator _ hs, lintegral_indicator _ (hm s hs), setLIntegral_const, + rw [lintegral_indicator hs, lintegral_indicator (hm s hs), setLIntegral_const, setLIntegral_const] suffices h_trim_s : μ.trim hm s = μ s by rw [h_trim_s] exact trim_measurableSet_eq hm hs @@ -1923,7 +1938,7 @@ theorem univ_le_of_forall_fin_meas_le {μ : Measure α} (hm : m ≤ m0) [SigmaFi f univ ≤ C := by let S := @spanningSets _ m (μ.trim hm) _ have hS_mono : Monotone S := @monotone_spanningSets _ m (μ.trim hm) _ - have hS_meas : ∀ n, MeasurableSet[m] (S n) := @measurable_spanningSets _ m (μ.trim hm) _ + have hS_meas : ∀ n, MeasurableSet[m] (S n) := @measurableSet_spanningSets _ m (μ.trim hm) _ rw [← @iUnion_spanningSets _ m (μ.trim hm)] refine (h_F_lim S hS_meas hS_mono).trans ?_ refine iSup_le fun n => hf (S n) (hS_meas n) ?_ diff --git a/Mathlib/MeasureTheory/Integral/LebesgueNormedSpace.lean b/Mathlib/MeasureTheory/Integral/LebesgueNormedSpace.lean index 874a14fc17cc0..02feec70974ce 100644 --- a/Mathlib/MeasureTheory/Integral/LebesgueNormedSpace.lean +++ b/Mathlib/MeasureTheory/Integral/LebesgueNormedSpace.lean @@ -13,7 +13,7 @@ open MeasureTheory Filter ENNReal Set open NNReal ENNReal -variable {α β γ δ : Type*} {m : MeasurableSpace α} {μ : MeasureTheory.Measure α} +variable {α : Type*} {m : MeasurableSpace α} {μ : MeasureTheory.Measure α} theorem aemeasurable_withDensity_iff {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [SecondCountableTopology E] [MeasurableSpace E] [BorelSpace E] {f : α → ℝ≥0} diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index 7b324585c63a5..424952fb5cb92 100644 --- a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean +++ b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean @@ -180,8 +180,7 @@ theorem lintegral_mul_norm_pow_le {α} [MeasurableSpace α] {μ : Measure α} · rw [add_zero] at hpq simp [hpq] have h2p : 1 < 1 / p := by - rw [one_div] - apply one_lt_inv hp + rw [one_div, one_lt_inv₀ hp] linarith have h2pq : (1 / p)⁻¹ + (1 / q)⁻¹ = 1 := by simp [hp.ne', hq.ne', hpq] have := ENNReal.lintegral_mul_le_Lp_mul_Lq μ ⟨h2p, h2pq⟩ (hf.pow_const p) (hg.pow_const q) diff --git a/Mathlib/MeasureTheory/Integral/PeakFunction.lean b/Mathlib/MeasureTheory/Integral/PeakFunction.lean index 845644d23d8fb..e9adaff6ffe0a 100644 --- a/Mathlib/MeasureTheory/Integral/PeakFunction.lean +++ b/Mathlib/MeasureTheory/Integral/PeakFunction.lean @@ -147,7 +147,7 @@ theorem tendsto_setIntegral_peak_smul_of_integrableOn_of_tendsto_aux · exact Eventually.of_forall fun x => mul_nonneg (norm_nonneg _) δpos.le · exact Eventually.of_forall ut _ = ∫ x in t, φ i x * δ ∂μ := by - apply setIntegral_congr ht fun x hx => ?_ + apply setIntegral_congr_fun ht fun x hx => ?_ rw [Real.norm_of_nonneg (hφpos _ (hts hx))] _ = (∫ x in t, φ i x ∂μ) * δ := by rw [integral_mul_right] _ ≤ 2 * δ := by gcongr; linarith [(le_abs_self _).trans h'i.le] @@ -171,7 +171,7 @@ theorem tendsto_setIntegral_peak_smul_of_integrableOn_of_tendsto_aux ‖∫ x in s, φ i x • g x ∂μ‖ = ‖(∫ x in s \ u, φ i x • g x ∂μ) + ∫ x in s ∩ u, φ i x • g x ∂μ‖ := by conv_lhs => rw [← diff_union_inter s u] - rw [integral_union disjoint_sdiff_inter (hs.inter u_open.measurableSet) + rw [setIntegral_union disjoint_sdiff_inter (hs.inter u_open.measurableSet) (h''i.mono_set diff_subset) (h''i.mono_set inter_subset_left)] _ ≤ ‖∫ x in s \ u, φ i x • g x ∂μ‖ + ‖∫ x in s ∩ u, φ i x • g x ∂μ‖ := norm_add_le _ _ _ ≤ (δ * ∫ x in s, ‖g x‖ ∂μ) + 2 * δ := add_le_add C B diff --git a/Mathlib/MeasureTheory/Integral/Periodic.lean b/Mathlib/MeasureTheory/Integral/Periodic.lean index c86458b3ee841..90abdbcb2baaf 100644 --- a/Mathlib/MeasureTheory/Integral/Periodic.lean +++ b/Mathlib/MeasureTheory/Integral/Periodic.lean @@ -124,7 +124,7 @@ instance : IsUnifLocDoublingMeasure (volume : Measure (AddCircle T)) := by noncomputable def measurableEquivIoc (a : ℝ) : AddCircle T ≃ᵐ Ioc a (a + T) where toEquiv := equivIoc T a measurable_toFun := measurable_of_measurable_on_compl_singleton _ - (continuousOn_iff_continuous_restrict.mp <| ContinuousAt.continuousOn fun _x hx => + (continuousOn_iff_continuous_restrict.mp <| continuousOn_of_forall_continuousAt fun _x hx => continuousAt_equivIoc T a hx).measurable measurable_invFun := AddCircle.measurable_mk'.comp measurable_subtype_coe @@ -133,7 +133,7 @@ noncomputable def measurableEquivIoc (a : ℝ) : AddCircle T ≃ᵐ Ioc a (a + T noncomputable def measurableEquivIco (a : ℝ) : AddCircle T ≃ᵐ Ico a (a + T) where toEquiv := equivIco T a measurable_toFun := measurable_of_measurable_on_compl_singleton _ - (continuousOn_iff_continuous_restrict.mp <| ContinuousAt.continuousOn fun _x hx => + (continuousOn_iff_continuous_restrict.mp <| continuousOn_of_forall_continuousAt fun _x hx => continuousAt_equivIco T a hx).measurable measurable_invFun := AddCircle.measurable_mk'.comp measurable_subtype_coe diff --git a/Mathlib/MeasureTheory/Integral/Pi.lean b/Mathlib/MeasureTheory/Integral/Pi.lean index 3445cc3f930f1..2bf9b9af0c309 100644 --- a/Mathlib/MeasureTheory/Integral/Pi.lean +++ b/Mathlib/MeasureTheory/Integral/Pi.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ import Mathlib.MeasureTheory.Constructions.Pi -import Mathlib.MeasureTheory.Constructions.Prod.Integral +import Mathlib.MeasureTheory.Integral.Prod /-! # Integration with respect to a finite product of measures diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean b/Mathlib/MeasureTheory/Integral/Prod.lean similarity index 99% rename from Mathlib/MeasureTheory/Constructions/Prod/Integral.lean rename to Mathlib/MeasureTheory/Integral/Prod.lean index 25d335405cc0f..f2ec386e8dfd7 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean +++ b/Mathlib/MeasureTheory/Integral/Prod.lean @@ -3,9 +3,9 @@ Copyright (c) 2020 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Integral.DominatedConvergence import Mathlib.MeasureTheory.Integral.SetIntegral +import Mathlib.MeasureTheory.Measure.Prod /-! # Integration with respect to the product measure @@ -153,7 +153,6 @@ theorem integrable_measure_prod_mk_left {s : Set (α × β)} (hs : MeasurableSet refine ⟨(measurable_measure_prod_mk_left hs).ennreal_toReal.aemeasurable.aestronglyMeasurable, ?_⟩ simp_rw [HasFiniteIntegral, ennnorm_eq_ofReal toReal_nonneg] convert h2s.lt_top using 1 - -- Porting note: was `simp_rw` rw [prod_apply hs] apply lintegral_congr_ae filter_upwards [ae_measure_lt_top hs h2s] with x hx @@ -426,7 +425,6 @@ theorem integral_prod (f : α × β → E) (hf : Integrable f (μ.prod ν)) : integral_indicator (measurable_prod_mk_left hs), setIntegral_const, integral_smul_const, integral_toReal (measurable_measure_prod_mk_left hs).aemeasurable (ae_measure_lt_top hs h2s.ne)] - -- Porting note: was `simp_rw` rw [prod_apply hs] · rintro f g - i_f i_g hf hg simp_rw [integral_add' i_f i_g, integral_integral_add' i_f i_g, hf, hg] diff --git a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean index b6a9c18db7857..da3bb92699829 100644 --- a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean +++ b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean @@ -86,7 +86,7 @@ theorem exists_lt_rieszContentAux_add_pos (K : Compacts X) {ε : ℝ≥0} (εpos finitely subadditive: `λ(K₁ ∪ K₂) ≤ λ(K₁) + λ(K₂)` for any compact subsets `K₁, K₂ ⊆ X`. -/ theorem rieszContentAux_sup_le (K1 K2 : Compacts X) : rieszContentAux Λ (K1 ⊔ K2) ≤ rieszContentAux Λ K1 + rieszContentAux Λ K2 := by - apply NNReal.le_of_forall_pos_le_add + apply _root_.le_of_forall_pos_le_add intro ε εpos --get test functions s.t. `λ(Ki) ≤ Λfi ≤ λ(Ki) + ε/2, i=1,2` obtain ⟨f1, f_test_function_K1⟩ := exists_lt_rieszContentAux_add_pos Λ K1 (half_pos εpos) diff --git a/Mathlib/MeasureTheory/Integral/SetIntegral.lean b/Mathlib/MeasureTheory/Integral/SetIntegral.lean index be099131dfc9b..49b3978cb0252 100644 --- a/Mathlib/MeasureTheory/Integral/SetIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/SetIntegral.lean @@ -21,7 +21,7 @@ and is zero otherwise. Since `∫ x in s, f x ∂μ` is a notation, one can rewrite or apply any theorem about `∫ x, f x ∂μ` directly. In this file we prove some theorems about dependence of `∫ x in s, f x ∂μ` on `s`, e.g. -`integral_union`, `integral_empty`, `integral_univ`. +`setIntegral_union`, `setIntegral_empty`, `setIntegral_univ`. We use the property `IntegrableOn f s μ := Integrable f (μ.restrict s)`, defined in `MeasureTheory.IntegrableOn`. We also defined in that same file a predicate @@ -66,7 +66,7 @@ variable [MeasurableSpace X] section NormedAddCommGroup variable [NormedAddCommGroup E] [NormedSpace ℝ E] - {f g : X → E} {s t : Set X} {μ ν : Measure X} {l l' : Filter X} + {f g : X → E} {s t : Set X} {μ : Measure X} theorem setIntegral_congr_ae₀ (hs : NullMeasurableSet s μ) (h : ∀ᵐ x ∂μ, x ∈ s → f x = g x) : ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ := @@ -82,38 +82,50 @@ theorem setIntegral_congr_ae (hs : MeasurableSet s) (h : ∀ᵐ x ∂μ, x ∈ s @[deprecated (since := "2024-04-17")] alias set_integral_congr_ae := setIntegral_congr_ae -theorem setIntegral_congr₀ (hs : NullMeasurableSet s μ) (h : EqOn f g s) : +theorem setIntegral_congr_fun₀ (hs : NullMeasurableSet s μ) (h : EqOn f g s) : ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ := setIntegral_congr_ae₀ hs <| Eventually.of_forall h +@[deprecated (since := "2024-10-12")] +alias setIntegral_congr₀ := setIntegral_congr_fun₀ + @[deprecated (since := "2024-04-17")] -alias set_integral_congr₀ := setIntegral_congr₀ +alias set_integral_congr₀ := setIntegral_congr_fun₀ -theorem setIntegral_congr (hs : MeasurableSet s) (h : EqOn f g s) : +theorem setIntegral_congr_fun (hs : MeasurableSet s) (h : EqOn f g s) : ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ := setIntegral_congr_ae hs <| Eventually.of_forall h +@[deprecated (since := "2024-10-12")] +alias setIntegral_congr := setIntegral_congr_fun + @[deprecated (since := "2024-04-17")] -alias set_integral_congr := setIntegral_congr +alias set_integral_congr := setIntegral_congr_fun -theorem setIntegral_congr_set_ae (hst : s =ᵐ[μ] t) : ∫ x in s, f x ∂μ = ∫ x in t, f x ∂μ := by +theorem setIntegral_congr_set (hst : s =ᵐ[μ] t) : ∫ x in s, f x ∂μ = ∫ x in t, f x ∂μ := by rw [Measure.restrict_congr_set hst] +@[deprecated (since := "2024-10-12")] +alias setIntegral_congr_set_ae := setIntegral_congr_set + @[deprecated (since := "2024-04-17")] -alias set_integral_congr_set_ae := setIntegral_congr_set_ae +alias set_integral_congr_set_ae := setIntegral_congr_set theorem integral_union_ae (hst : AEDisjoint μ s t) (ht : NullMeasurableSet t μ) (hfs : IntegrableOn f s μ) (hft : IntegrableOn f t μ) : ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ + ∫ x in t, f x ∂μ := by simp only [IntegrableOn, Measure.restrict_union₀ hst ht, integral_add_measure hfs hft] -theorem integral_union (hst : Disjoint s t) (ht : MeasurableSet t) (hfs : IntegrableOn f s μ) +theorem setIntegral_union (hst : Disjoint s t) (ht : MeasurableSet t) (hfs : IntegrableOn f s μ) (hft : IntegrableOn f t μ) : ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ + ∫ x in t, f x ∂μ := integral_union_ae hst.aedisjoint ht.nullMeasurableSet hfs hft +@[deprecated (since := "2024-10-12")] +alias integral_union := setIntegral_union + theorem integral_diff (ht : MeasurableSet t) (hfs : IntegrableOn f s μ) (hts : t ⊆ s) : ∫ x in s \ t, f x ∂μ = ∫ x in s, f x ∂μ - ∫ x in t, f x ∂μ := by - rw [eq_sub_iff_add_eq, ← integral_union, diff_union_of_subset hts] + rw [eq_sub_iff_add_eq, ← setIntegral_union, diff_union_of_subset hts] exacts [disjoint_sdiff_self_left, ht, hfs.mono_set diff_subset, hfs.mono_set hts] theorem integral_inter_add_diff₀ (ht : NullMeasurableSet t μ) (hfs : IntegrableOn f s μ) : @@ -134,7 +146,7 @@ theorem integral_finset_biUnion {ι : Type*} (t : Finset ι) {s : ι → Set X} · simp · simp only [Finset.coe_insert, Finset.forall_mem_insert, Set.pairwise_insert, Finset.set_biUnion_insert] at hs hf h's ⊢ - rw [integral_union _ _ hf.1 (integrableOn_finset_iUnion.2 hf.2)] + rw [setIntegral_union _ _ hf.1 (integrableOn_finset_iUnion.2 hf.2)] · rw [Finset.sum_insert hat, IH hs.2 h's.1 hf.2] · simp only [disjoint_iUnion_right] exact fun i hi => (h's.2 i hi (ne_of_mem_of_not_mem hi hat).symm).1 @@ -147,16 +159,22 @@ theorem integral_fintype_iUnion {ι : Type*} [Fintype ι] {s : ι → Set X} · simp · simp [pairwise_univ, h's] -theorem integral_empty : ∫ x in ∅, f x ∂μ = 0 := by +theorem setIntegral_empty : ∫ x in ∅, f x ∂μ = 0 := by rw [Measure.restrict_empty, integral_zero_measure] -theorem integral_univ : ∫ x in univ, f x ∂μ = ∫ x, f x ∂μ := by rw [Measure.restrict_univ] +@[deprecated (since := "2024-10-12")] +alias integral_empty := setIntegral_empty + +theorem setIntegral_univ : ∫ x in univ, f x ∂μ = ∫ x, f x ∂μ := by rw [Measure.restrict_univ] + +@[deprecated (since := "2024-10-12")] +alias integral_univ := setIntegral_univ theorem integral_add_compl₀ (hs : NullMeasurableSet s μ) (hfi : Integrable f μ) : ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ := by rw [ ← integral_union_ae disjoint_compl_right.aedisjoint hs.compl hfi.integrableOn hfi.integrableOn, - union_compl_self, integral_univ] + union_compl_self, setIntegral_univ] theorem integral_add_compl (hs : MeasurableSet s) (hfi : Integrable f μ) : ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ := @@ -328,7 +346,7 @@ theorem integral_union_eq_left_of_ae_aux (ht_eq : ∀ᵐ x ∂μ.restrict t, f x setIntegral_eq_zero_of_forall_eq_zero fun x hx => hx.2 rw [← integral_inter_add_diff hk h's, ← integral_inter_add_diff hk H, A, A, zero_add, zero_add, union_diff_distrib, union_comm] - apply setIntegral_congr_set_ae + apply setIntegral_congr_set rw [union_ae_eq_right] apply measure_mono_null diff_subset rw [measure_zero_iff_ae_nmem] @@ -371,7 +389,7 @@ theorem setIntegral_eq_of_subset_of_ae_diff_eq_zero_aux (hts : s ⊆ t) _ = ∫ x in t \ k, f x ∂μ := by rw [setIntegral_eq_zero_of_forall_eq_zero fun x hx => ?_, zero_add]; exact hx.2 _ = ∫ x in s \ k, f x ∂μ := by - apply setIntegral_congr_set_ae + apply setIntegral_congr_set filter_upwards [h't] with x hx change (x ∈ t \ k) = (x ∈ s \ k) simp only [mem_preimage, mem_singleton_iff, eq_iff_iff, and_congr_left_iff, mem_diff] @@ -430,7 +448,7 @@ coincides with its integral on the whole space. -/ theorem setIntegral_eq_integral_of_ae_compl_eq_zero (h : ∀ᵐ x ∂μ, x ∉ s → f x = 0) : ∫ x in s, f x ∂μ = ∫ x, f x ∂μ := by symm - nth_rw 1 [← integral_univ] + nth_rw 1 [← setIntegral_univ] apply setIntegral_eq_of_subset_of_ae_diff_eq_zero nullMeasurableSet_univ (subset_univ _) filter_upwards [h] with x hx h'x using hx h'x.2 @@ -471,14 +489,14 @@ theorem integral_norm_eq_pos_sub_neg {f : X → ℝ} (hfi : Integrable f μ) : rw [← integral_add_compl₀ h_meas hfi.norm] _ = ∫ x in {x | 0 ≤ f x}, f x ∂μ + ∫ x in {x | 0 ≤ f x}ᶜ, ‖f x‖ ∂μ := by congr 1 - refine setIntegral_congr₀ h_meas fun x hx => ?_ + refine setIntegral_congr_fun₀ h_meas fun x hx => ?_ dsimp only rw [Real.norm_eq_abs, abs_eq_self.mpr _] exact hx _ = ∫ x in {x | 0 ≤ f x}, f x ∂μ - ∫ x in {x | 0 ≤ f x}ᶜ, f x ∂μ := by congr 1 rw [← integral_neg] - refine setIntegral_congr₀ h_meas.compl fun x hx => ?_ + refine setIntegral_congr_fun₀ h_meas.compl fun x hx => ?_ dsimp only rw [Real.norm_eq_abs, abs_eq_neg_self.mpr _] rw [Set.mem_compl_iff, Set.nmem_setOf_iff] at hx @@ -518,7 +536,7 @@ theorem integral_indicatorConstLp [CompleteSpace E] ∫ x, indicatorConstLp p ht hμt e x ∂μ = (μ t).toReal • e := calc ∫ x, indicatorConstLp p ht hμt e x ∂μ = ∫ x in univ, indicatorConstLp p ht hμt e x ∂μ := by - rw [integral_univ] + rw [setIntegral_univ] _ = (μ (t ∩ univ)).toReal • e := setIntegral_indicatorConstLp MeasurableSet.univ ht hμt e _ = (μ t).toReal • e := by rw [inter_univ] @@ -540,13 +558,19 @@ theorem _root_.MeasurableEmbedding.setIntegral_map {Y} {_ : MeasurableSpace Y} { @[deprecated (since := "2024-04-17")] alias _root_.MeasurableEmbedding.set_integral_map := _root_.MeasurableEmbedding.setIntegral_map -theorem _root_.ClosedEmbedding.setIntegral_map [TopologicalSpace X] [BorelSpace X] {Y} +theorem _root_.IsClosedEmbedding.setIntegral_map [TopologicalSpace X] [BorelSpace X] {Y} [MeasurableSpace Y] [TopologicalSpace Y] [BorelSpace Y] {g : X → Y} {f : Y → E} (s : Set Y) - (hg : ClosedEmbedding g) : ∫ y in s, f y ∂Measure.map g μ = ∫ x in g ⁻¹' s, f (g x) ∂μ := + (hg : IsClosedEmbedding g) : ∫ y in s, f y ∂Measure.map g μ = ∫ x in g ⁻¹' s, f (g x) ∂μ := hg.measurableEmbedding.setIntegral_map _ _ +@[deprecated (since := "2024-10-20")] +alias _root_.ClosedEmbedding.setIntegral_map := IsClosedEmbedding.setIntegral_map + @[deprecated (since := "2024-04-17")] -alias _root_.ClosedEmbedding.set_integral_map := _root_.ClosedEmbedding.setIntegral_map +alias _root_.IsClosedEmbedding.set_integral_map := _root_.IsClosedEmbedding.setIntegral_map + +@[deprecated (since := "2024-10-20")] +alias _root_.ClosedEmbedding.set_integral_map := IsClosedEmbedding.set_integral_map theorem MeasurePreserving.setIntegral_preimage_emb {Y} {_ : MeasurableSpace Y} {f : X → Y} {ν} (h₁ : MeasurePreserving f μ ν) (h₂ : MeasurableEmbedding f) (g : Y → E) (s : Set Y) : @@ -676,31 +700,31 @@ variable [PartialOrder X] {x y : X} theorem integral_Icc_eq_integral_Ioc' (hx : μ {x} = 0) : ∫ t in Icc x y, f t ∂μ = ∫ t in Ioc x y, f t ∂μ := - setIntegral_congr_set_ae (Ioc_ae_eq_Icc' hx).symm + setIntegral_congr_set (Ioc_ae_eq_Icc' hx).symm theorem integral_Icc_eq_integral_Ico' (hy : μ {y} = 0) : ∫ t in Icc x y, f t ∂μ = ∫ t in Ico x y, f t ∂μ := - setIntegral_congr_set_ae (Ico_ae_eq_Icc' hy).symm + setIntegral_congr_set (Ico_ae_eq_Icc' hy).symm theorem integral_Ioc_eq_integral_Ioo' (hy : μ {y} = 0) : ∫ t in Ioc x y, f t ∂μ = ∫ t in Ioo x y, f t ∂μ := - setIntegral_congr_set_ae (Ioo_ae_eq_Ioc' hy).symm + setIntegral_congr_set (Ioo_ae_eq_Ioc' hy).symm theorem integral_Ico_eq_integral_Ioo' (hx : μ {x} = 0) : ∫ t in Ico x y, f t ∂μ = ∫ t in Ioo x y, f t ∂μ := - setIntegral_congr_set_ae (Ioo_ae_eq_Ico' hx).symm + setIntegral_congr_set (Ioo_ae_eq_Ico' hx).symm theorem integral_Icc_eq_integral_Ioo' (hx : μ {x} = 0) (hy : μ {y} = 0) : ∫ t in Icc x y, f t ∂μ = ∫ t in Ioo x y, f t ∂μ := - setIntegral_congr_set_ae (Ioo_ae_eq_Icc' hx hy).symm + setIntegral_congr_set (Ioo_ae_eq_Icc' hx hy).symm theorem integral_Iic_eq_integral_Iio' (hx : μ {x} = 0) : ∫ t in Iic x, f t ∂μ = ∫ t in Iio x, f t ∂μ := - setIntegral_congr_set_ae (Iio_ae_eq_Iic' hx).symm + setIntegral_congr_set (Iio_ae_eq_Iic' hx).symm theorem integral_Ici_eq_integral_Ioi' (hx : μ {x} = 0) : ∫ t in Ici x, f t ∂μ = ∫ t in Ioi x, f t ∂μ := - setIntegral_congr_set_ae (Ioi_ae_eq_Ici' hx).symm + setIntegral_congr_set (Ioi_ae_eq_Ici' hx).symm variable [NoAtoms μ] @@ -1457,7 +1481,7 @@ variable [MeasurableSpace X] [PseudoEMetricSpace X] theorem measure_le_lintegral_thickenedIndicatorAux (μ : Measure X) {E : Set X} (E_mble : MeasurableSet E) (δ : ℝ) : μ E ≤ ∫⁻ x, (thickenedIndicatorAux δ E x : ℝ≥0∞) ∂μ := by convert_to lintegral μ (E.indicator fun _ => (1 : ℝ≥0∞)) ≤ lintegral μ (thickenedIndicatorAux δ E) - · rw [lintegral_indicator _ E_mble] + · rw [lintegral_indicator E_mble] simp only [lintegral_one, Measure.restrict_apply, MeasurableSet.univ, univ_inter] · apply lintegral_mono apply indicator_le_thickenedIndicatorAux diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index 02dbf1cdd368b..456069af75266 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -9,7 +9,7 @@ import Mathlib.MeasureTheory.Function.SimpleFuncDenseLp # Extension of a linear function from indicators to L1 Let `T : Set α → E →L[ℝ] F` be additive for measurable sets with finite measure, in the sense that -for `s, t` two such sets, `s ∩ t = ∅ → T (s ∪ t) = T s + T t`. `T` is akin to a bilinear map on +for `s, t` two such sets, `Disjoint s t → T (s ∪ t) = T s + T t`. `T` is akin to a bilinear map on `Set α × E`, or a linear map on indicator functions. This file constructs an extension of `T` to integrable simple functions, which are finite sums of @@ -23,7 +23,7 @@ expectation of an integrable function in `MeasureTheory.Function.ConditionalExpe ## Main Definitions - `FinMeasAdditive μ T`: the property that `T` is additive on measurable sets with finite measure. - For two such sets, `s ∩ t = ∅ → T (s ∪ t) = T s + T t`. + For two such sets, `Disjoint s t → T (s ∪ t) = T s + T t`. - `DominatedFinMeasAdditive μ T C`: `FinMeasAdditive μ T ∧ ∀ s, ‖T s‖ ≤ C * (μ s).toReal`. This is the property needed to perform the extension from indicators to L1. - `setToL1 (hT : DominatedFinMeasAdditive μ T C) : (α →₁[μ] E) →L[ℝ] F`: the extension of `T` @@ -90,13 +90,14 @@ section FinMeasAdditive sets with finite measure is the sum of its values on each set. -/ def FinMeasAdditive {β} [AddMonoid β] {_ : MeasurableSpace α} (μ : Measure α) (T : Set α → β) : Prop := - ∀ s t, MeasurableSet s → MeasurableSet t → μ s ≠ ∞ → μ t ≠ ∞ → s ∩ t = ∅ → T (s ∪ t) = T s + T t + ∀ s t, MeasurableSet s → MeasurableSet t → μ s ≠ ∞ → μ t ≠ ∞ → Disjoint s t → + T (s ∪ t) = T s + T t namespace FinMeasAdditive variable {β : Type*} [AddCommMonoid β] {T T' : Set α → β} -theorem zero : FinMeasAdditive μ (0 : Set α → β) := fun s t _ _ _ _ _ => by simp +theorem zero : FinMeasAdditive μ (0 : Set α → β) := fun _ _ _ _ _ _ _ => by simp theorem add (hT : FinMeasAdditive μ T) (hT' : FinMeasAdditive μ T') : FinMeasAdditive μ (T + T') := by @@ -133,7 +134,7 @@ theorem smul_measure_iff (c : ℝ≥0∞) (hc_ne_zero : c ≠ 0) (hc_ne_top : c theorem map_empty_eq_zero {β} [AddCancelMonoid β] {T : Set α → β} (hT : FinMeasAdditive μ T) : T ∅ = 0 := by have h_empty : μ ∅ ≠ ∞ := (measure_empty.le.trans_lt ENNReal.coe_lt_top).ne - specialize hT ∅ ∅ MeasurableSet.empty MeasurableSet.empty h_empty h_empty (Set.inter_empty ∅) + specialize hT ∅ ∅ MeasurableSet.empty MeasurableSet.empty h_empty h_empty (disjoint_empty _) rw [Set.union_empty] at hT nth_rw 1 [← add_zero (T ∅)] at hT exact (add_left_cancel hT).symm @@ -160,10 +161,9 @@ theorem map_iUnion_fin_meas_set_eq_sum (T : Set α → β) (T_empty : T ∅ = 0) · congr; convert Finset.iSup_insert a s S · exact (measure_biUnion_lt_top s.finite_toSet fun i hi ↦ (hps i <| Finset.mem_insert_of_mem hi).lt_top).ne - · simp_rw [Set.inter_iUnion] - refine iUnion_eq_empty.mpr fun i => iUnion_eq_empty.mpr fun hi => ?_ - rw [← Set.disjoint_iff_inter_eq_empty] - refine h_disj a (Finset.mem_insert_self a s) i (Finset.mem_insert_of_mem hi) fun hai => ?_ + · simp_rw [Set.disjoint_iUnion_right] + intro i hi + refine h_disj a (Finset.mem_insert_self a s) i (Finset.mem_insert_of_mem hi) fun hai ↦ ?_ rw [← hai] at hi exact has hi @@ -192,7 +192,7 @@ theorem eq_zero_of_measure_zero {β : Type*} [NormedAddCommGroup β] {T : Set α refine ((hT.2 s hs (by simp [hs_zero])).trans (le_of_eq ?_)).antisymm (norm_nonneg _) rw [hs_zero, ENNReal.zero_toReal, mul_zero] -theorem eq_zero {β : Type*} [NormedAddCommGroup β] {T : Set α → β} {C : ℝ} {m : MeasurableSpace α} +theorem eq_zero {β : Type*} [NormedAddCommGroup β] {T : Set α → β} {C : ℝ} {_ : MeasurableSpace α} (hT : DominatedFinMeasAdditive (0 : Measure α) T C) {s : Set α} (hs : MeasurableSet s) : T s = 0 := eq_zero_of_measure_zero hT hs (by simp only [Measure.coe_zero, Pi.zero_apply]) @@ -277,9 +277,8 @@ theorem setToSimpleFunc_zero_apply {m : MeasurableSpace α} (T : Set α → F cases isEmpty_or_nonempty α <;> simp [setToSimpleFunc] theorem setToSimpleFunc_eq_sum_filter [DecidablePred fun x ↦ x ≠ (0 : F)] - {m : MeasurableSpace α} (T : Set α → F →L[ℝ] F') - (f : α →ₛ F) : - setToSimpleFunc T f = ∑ x ∈ f.range.filter fun x => x ≠ 0, (T (f ⁻¹' {x})) x := by + {m : MeasurableSpace α} (T : Set α → F →L[ℝ] F') (f : α →ₛ F) : + setToSimpleFunc T f = ∑ x ∈ f.range with x ≠ 0, T (f ⁻¹' {x}) x := by symm refine sum_filter_of_ne fun x _ => mt fun hx0 => ?_ rw [hx0] @@ -301,13 +300,13 @@ theorem map_setToSimpleFunc (T : Set α → F →L[ℝ] F') (h_add : FinMeasAddi rw [mem_filter] at hx rw [hx.2, ContinuousLinearMap.map_zero] have h_left_eq : - T (map g f ⁻¹' {g (f a)}) (g (f a)) = - T (f ⁻¹' (f.range.filter fun b => g b = g (f a))) (g (f a)) := by + T (map g f ⁻¹' {g (f a)}) (g (f a)) + = T (f ⁻¹' ({b ∈ f.range | g b = g (f a)} : Finset _)) (g (f a)) := by congr; rw [map_preimage_singleton] rw [h_left_eq] have h_left_eq' : - T (f ⁻¹' (filter (fun b : G => g b = g (f a)) f.range)) (g (f a)) = - T (⋃ y ∈ filter (fun b : G => g b = g (f a)) f.range, f ⁻¹' {y}) (g (f a)) := by + T (f ⁻¹' ({b ∈ f.range | g b = g (f a)} : Finset _)) (g (f a)) + = T (⋃ y ∈ {b ∈ f.range | g b = g (f a)}, f ⁻¹' {y}) (g (f a)) := by congr; rw [← Finset.set_biUnion_preimage_singleton] rw [h_left_eq'] rw [h_add.map_iUnion_fin_meas_set_eq_sum T T_empty] @@ -381,7 +380,7 @@ theorem setToSimpleFunc_add_left' (T T' T'' : Set α → E →L[ℝ] F) classical simp_rw [setToSimpleFunc_eq_sum_filter] suffices - ∀ x ∈ filter (fun x : E => x ≠ 0) f.range, T'' (f ⁻¹' {x}) = T (f ⁻¹' {x}) + T' (f ⁻¹' {x}) by + ∀ x ∈ {x ∈ f.range | x ≠ 0}, T'' (f ⁻¹' {x}) = T (f ⁻¹' {x}) + T' (f ⁻¹' {x}) by rw [← sum_add_distrib] refine Finset.sum_congr rfl fun x hx => ?_ rw [this x hx] @@ -402,7 +401,7 @@ theorem setToSimpleFunc_smul_left' (T T' : Set α → E →L[ℝ] F') (c : ℝ) setToSimpleFunc T' f = c • setToSimpleFunc T f := by classical simp_rw [setToSimpleFunc_eq_sum_filter] - suffices ∀ x ∈ filter (fun x : E => x ≠ 0) f.range, T' (f ⁻¹' {x}) = c • T (f ⁻¹' {x}) by + suffices ∀ x ∈ {x ∈ f.range | x ≠ 0}, T' (f ⁻¹' {x}) = c • T (f ⁻¹' {x}) by rw [smul_sum] refine Finset.sum_congr rfl fun x hx => ?_ rw [this x hx] @@ -421,7 +420,7 @@ theorem setToSimpleFunc_add (T : Set α → E →L[ℝ] F) (h_add : FinMeasAddit setToSimpleFunc T (f + g) = ∑ x ∈ (pair f g).range, T (pair f g ⁻¹' {x}) (x.fst + x.snd) := by rw [add_eq_map₂, map_setToSimpleFunc T h_add hp_pair]; simp _ = ∑ x ∈ (pair f g).range, (T (pair f g ⁻¹' {x}) x.fst + T (pair f g ⁻¹' {x}) x.snd) := - (Finset.sum_congr rfl fun a _ => ContinuousLinearMap.map_add _ _ _) + (Finset.sum_congr rfl fun _ _ => ContinuousLinearMap.map_add _ _ _) _ = (∑ x ∈ (pair f g).range, T (pair f g ⁻¹' {x}) x.fst) + ∑ x ∈ (pair f g).range, T (pair f g ⁻¹' {x}) x.snd := by rw [Finset.sum_add_distrib] @@ -920,18 +919,18 @@ variable (𝕜) [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 E] [NormedSpace def setToL1' (hT : DominatedFinMeasAdditive μ T C) (h_smul : ∀ c : 𝕜, ∀ s x, T s (c • x) = c • T s x) : (α →₁[μ] E) →L[𝕜] F := (setToL1SCLM' α E 𝕜 μ hT h_smul).extend (coeToLp α E 𝕜) (simpleFunc.denseRange one_ne_top) - simpleFunc.uniformInducing + simpleFunc.isUniformInducing variable {𝕜} /-- Extend `Set α → E →L[ℝ] F` to `(α →₁[μ] E) →L[ℝ] F`. -/ def setToL1 (hT : DominatedFinMeasAdditive μ T C) : (α →₁[μ] E) →L[ℝ] F := (setToL1SCLM α E μ hT).extend (coeToLp α E ℝ) (simpleFunc.denseRange one_ne_top) - simpleFunc.uniformInducing + simpleFunc.isUniformInducing theorem setToL1_eq_setToL1SCLM (hT : DominatedFinMeasAdditive μ T C) (f : α →₁ₛ[μ] E) : setToL1 hT f = setToL1SCLM α E μ hT f := - uniformly_extend_of_ind simpleFunc.uniformInducing (simpleFunc.denseRange one_ne_top) + uniformly_extend_of_ind simpleFunc.isUniformInducing (simpleFunc.denseRange one_ne_top) (setToL1SCLM α E μ hT).uniformContinuous _ theorem setToL1_eq_setToL1' (hT : DominatedFinMeasAdditive μ T C) @@ -1637,7 +1636,7 @@ theorem continuous_setToFun_of_dominated (hT : DominatedFinMeasAdditive μ T C) {bound : α → ℝ} (hfs_meas : ∀ x, AEStronglyMeasurable (fs x) μ) (h_bound : ∀ x, ∀ᵐ a ∂μ, ‖fs x a‖ ≤ bound a) (bound_integrable : Integrable bound μ) (h_cont : ∀ᵐ a ∂μ, Continuous fun x => fs x a) : Continuous fun x => setToFun μ T hT (fs x) := - continuous_iff_continuousAt.mpr fun x₀ => + continuous_iff_continuousAt.mpr fun _ => continuousAt_setToFun_of_dominated hT (Eventually.of_forall hfs_meas) (Eventually.of_forall h_bound) ‹_› <| h_cont.mono fun _ => Continuous.continuousAt diff --git a/Mathlib/MeasureTheory/Integral/TorusIntegral.lean b/Mathlib/MeasureTheory/Integral/TorusIntegral.lean index 2ac46ce80a629..80b6f7583b816 100644 --- a/Mathlib/MeasureTheory/Integral/TorusIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/TorusIntegral.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 Cuma Kökmen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Cuma Kökmen, Yury Kudryashov -/ -import Mathlib.MeasureTheory.Constructions.Prod.Integral import Mathlib.MeasureTheory.Integral.CircleIntegral +import Mathlib.MeasureTheory.Integral.Prod import Mathlib.Order.Fin.Tuple /-! @@ -220,10 +220,10 @@ theorem torusIntegral_succAbove ((Fin.insertNthOrderIso (fun _ => ℝ) i).preimage_Icc _ _).trans (Icc_prod_eq _ _) rw [torusIntegral, ← hem.map_eq, setIntegral_map_equiv, heπ, Measure.volume_eq_prod, setIntegral_prod, circleIntegral_def_Icc] - · refine setIntegral_congr measurableSet_Icc fun θ _ => ?_ + · refine setIntegral_congr_fun measurableSet_Icc fun θ _ => ?_ simp (config := { unfoldPartialApp := true }) only [e, torusIntegral, ← integral_smul, deriv_circleMap, i.prod_univ_succAbove _, smul_smul, torusMap, circleMap_zero] - refine setIntegral_congr measurableSet_Icc fun Θ _ => ?_ + refine setIntegral_congr_fun measurableSet_Icc fun Θ _ => ?_ simp only [MeasurableEquiv.piFinSuccAbove_symm_apply, i.insertNth_apply_same, i.insertNth_apply_succAbove, (· ∘ ·), Fin.insertNthEquiv, Equiv.coe_fn_mk] congr 2 diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index b47c60a0d8a7f..8f20f3b9c1bd2 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -4,13 +4,14 @@ 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.Prod.TProd +import Mathlib.Data.Set.UnionLift +import Mathlib.GroupTheory.Coset.Defs import Mathlib.Logic.Equiv.Fin import Mathlib.MeasureTheory.MeasurableSpace.Instances -import Mathlib.Order.LiminfLimsup -import Mathlib.Data.Set.UnionLift import Mathlib.Order.Filter.SmallSets -import Mathlib.GroupTheory.Coset.Basic +import Mathlib.Order.LiminfLimsup /-! # Measurable spaces and measurable functions @@ -67,7 +68,7 @@ variable {m m₁ m₂ : MeasurableSpace α} {m' : MeasurableSpace β} {f : α protected def map (f : α → β) (m : MeasurableSpace α) : MeasurableSpace β where MeasurableSet' s := MeasurableSet[m] <| f ⁻¹' s measurableSet_empty := m.measurableSet_empty - measurableSet_compl s hs := m.measurableSet_compl _ hs + measurableSet_compl _ hs := m.measurableSet_compl _ hs measurableSet_iUnion f hf := by simpa only [preimage_iUnion] using m.measurableSet_iUnion _ hf lemma map_def {s : Set β} : MeasurableSet[m.map f] s ↔ MeasurableSet[m] (f ⁻¹' s) := Iff.rfl @@ -85,11 +86,14 @@ theorem map_comp {f : α → β} {g : β → γ} : (m.map f).map g = m.map (g protected def comap (f : α → β) (m : MeasurableSpace β) : MeasurableSpace α where MeasurableSet' s := ∃ s', MeasurableSet[m] s' ∧ f ⁻¹' s' = s measurableSet_empty := ⟨∅, m.measurableSet_empty, rfl⟩ - measurableSet_compl := fun s ⟨s', h₁, h₂⟩ => ⟨s'ᶜ, m.measurableSet_compl _ h₁, h₂ ▸ rfl⟩ + measurableSet_compl := fun _ ⟨s', h₁, h₂⟩ => ⟨s'ᶜ, m.measurableSet_compl _ h₁, h₂ ▸ rfl⟩ measurableSet_iUnion s hs := let ⟨s', hs'⟩ := Classical.axiom_of_choice hs ⟨⋃ i, s' i, m.measurableSet_iUnion _ fun i => (hs' i).left, by simp [hs']⟩ +lemma measurableSet_comap {m : MeasurableSpace β} : + MeasurableSet[m.comap f] s ↔ ∃ s', MeasurableSet[m] s' ∧ f ⁻¹' s' = s := .rfl + theorem comap_eq_generateFrom (m : MeasurableSpace β) (f : α → β) : m.comap f = generateFrom { t | ∃ s, MeasurableSet s ∧ f ⁻¹' s = t } := (@generateFrom_measurableSet _ (.comap f m)).symm @@ -231,7 +235,7 @@ theorem Subsingleton.measurable [Subsingleton α] : Measurable f := fun _ _ => theorem measurable_of_subsingleton_codomain [Subsingleton β] (f : α → β) : Measurable f := fun s _ => Subsingleton.set_cases MeasurableSet.empty MeasurableSet.univ s -@[to_additive (attr := measurability)] +@[to_additive (attr := measurability, fun_prop)] theorem measurable_one [One α] : Measurable (1 : β → α) := @measurable_const _ _ _ _ 1 @@ -284,7 +288,7 @@ protected theorem MeasurableSet.preimage {t : Set β} (ht : MeasurableSet t) (hf MeasurableSet (f ⁻¹' t) := hf ht -@[measurability] +@[measurability, fun_prop] protected theorem Measurable.piecewise {_ : DecidablePred (· ∈ s)} (hs : MeasurableSet s) (hf : Measurable f) (hg : Measurable g) : Measurable (piecewise s f g) := by intro t ht @@ -472,6 +476,15 @@ nonrec theorem QuotientGroup.measurable_from_quotient {G} [Group G] [MeasurableS {S : Subgroup G} {f : G ⧸ S → α} : Measurable f ↔ Measurable (f ∘ ((↑) : G → G ⧸ S)) := measurable_from_quotient +instance Quotient.instDiscreteMeasurableSpace {α} {s : Setoid α} [MeasurableSpace α] + [DiscreteMeasurableSpace α] : DiscreteMeasurableSpace (Quotient s) where + forall_measurableSet _ := measurableSet_quotient.2 .of_discrete + +@[to_additive] +instance QuotientGroup.instDiscreteMeasurableSpace {G} [Group G] [MeasurableSpace G] + [DiscreteMeasurableSpace G] (S : Subgroup G) : DiscreteMeasurableSpace (G ⧸ S) := + Quotient.instDiscreteMeasurableSpace + end Quotient section Subtype @@ -1256,6 +1269,13 @@ theorem isCountablySpanning_measurableSet [MeasurableSpace α] : IsCountablySpanning { s : Set α | MeasurableSet s } := ⟨fun _ => univ, fun _ => MeasurableSet.univ, iUnion_const _⟩ +/-- Rectangles of countably spanning sets are countably spanning. -/ +lemma IsCountablySpanning.prod {C : Set (Set α)} {D : Set (Set β)} (hC : IsCountablySpanning C) + (hD : IsCountablySpanning D) : IsCountablySpanning (image2 (· ×ˢ ·) C D) := by + rcases hC, hD with ⟨⟨s, h1s, h2s⟩, t, h1t, h2t⟩ + refine ⟨fun n => s n.unpair.1 ×ˢ t n.unpair.2, fun n => mem_image2_of_mem (h1s _) (h1t _), ?_⟩ + rw [iUnion_unpair_prod, h2s, h2t, univ_prod_univ] + namespace MeasurableSet /-! diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Card.lean b/Mathlib/MeasureTheory/MeasurableSpace/Card.lean index 9da03d77e896e..f6d160c7eefc7 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Card.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Card.lean @@ -121,7 +121,7 @@ theorem generateMeasurable_eq_rec (s : Set (Set α)) : refine mem_iUnion.2 ⟨Ordinal.enum (α := ω₁) (· < ·) ⟨Ordinal.lsub fun n => Ordinal.typein.{u} (α := ω₁) (· < ·) (I n), ?_⟩, iUnion_mem_generateMeasurableRec fun n => ⟨I n, ?_, hI n⟩⟩ - · rw [Ordinal.type_lt] + · rw [Ordinal.type_toType] refine Ordinal.lsub_lt_ord_lift ?_ fun i => Ordinal.typein_lt_self _ rw [mk_denumerable, lift_aleph0, isRegular_aleph_one.cof_eq] exact aleph0_lt_aleph_one diff --git a/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean b/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean index 19be50fbff257..9ff18dc3605be 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean @@ -516,7 +516,8 @@ variable [MeasurableSpace β] /-- A class registering that either `α` is countable or `β` is a countably generated measurable space. -/ -class CountableOrCountablyGenerated (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] : Prop := +class CountableOrCountablyGenerated (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] : + Prop where countableOrCountablyGenerated : Countable α ∨ MeasurableSpace.CountablyGenerated β instance instCountableOrCountablyGeneratedOfCountable [h1 : Countable α] : diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean b/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean index 6345012319658..0a5c5306735ce 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean @@ -418,9 +418,9 @@ theorem measurableSet_bot_iff {s : Set α} : MeasurableSet[⊥] s ↔ s = ∅ { MeasurableSet' := fun s => s = ∅ ∨ s = univ measurableSet_empty := Or.inl rfl measurableSet_compl := by simp (config := { contextual := true }) [or_imp] - measurableSet_iUnion := fun f hf => sUnion_mem_empty_univ (forall_mem_range.2 hf) } + measurableSet_iUnion := fun _ hf => sUnion_mem_empty_univ (forall_mem_range.2 hf) } have : b = ⊥ := - bot_unique fun s hs => + bot_unique fun _ hs => hs.elim (fun s => s.symm ▸ @measurableSet_empty _ ⊥) fun s => s.symm ▸ @MeasurableSet.univ _ ⊥ this ▸ Iff.rfl @@ -534,7 +534,7 @@ variable [MeasurableSpace α] [MeasurableSpace β] [DiscreteMeasurableSpace α] @[measurability] lemma MeasurableSet.of_discrete : MeasurableSet s := DiscreteMeasurableSpace.forall_measurableSet _ -@[measurability] lemma Measurable.of_discrete : Measurable f := fun _ _ ↦ .of_discrete +@[measurability, fun_prop] lemma Measurable.of_discrete : Measurable f := fun _ _ ↦ .of_discrete @[deprecated MeasurableSet.of_discrete (since := "2024-08-25")] lemma measurableSet_discrete (s : Set α) : MeasurableSet s := .of_discrete diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean b/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean index 539df69ae463e..6cd197d8d3f76 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean @@ -60,6 +60,8 @@ structure MeasurableEmbedding [MeasurableSpace α] [MeasurableSpace β] (f : α /-- The image of a measurable set under a measurable embedding is a measurable set. -/ protected measurableSet_image' : ∀ ⦃s⦄, MeasurableSet s → MeasurableSet (f '' s) +attribute [fun_prop] MeasurableEmbedding.measurable + namespace MeasurableEmbedding variable {mα : MeasurableSpace α} [MeasurableSpace β] [MeasurableSpace γ] {f : α → β} {g : β → γ} @@ -118,6 +120,38 @@ theorem measurable_comp_iff (hg : MeasurableEmbedding g) : Measurable (g ∘ f) end MeasurableEmbedding +section gluing +variable {α₁ α₂ α₃ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + {mα₁ : MeasurableSpace α₁} {mα₂ : MeasurableSpace α₂} {mα₃ : MeasurableSpace α₃} + {i₁ : α₁ → α} {i₂ : α₂ → α} {i₃ : α₃ → α} {s : Set α} {f : α → β} + +lemma MeasurableSet.of_union_range_cover (hi₁ : MeasurableEmbedding i₁) + (hi₂ : MeasurableEmbedding i₂) (h : univ ⊆ range i₁ ∪ range i₂) + (hs₁ : MeasurableSet (i₁ ⁻¹' s)) (hs₂ : MeasurableSet (i₂ ⁻¹' s)) : MeasurableSet s := by + convert (hi₁.measurableSet_image' hs₁).union (hi₂.measurableSet_image' hs₂) + simp [image_preimage_eq_range_inter, ← union_inter_distrib_right,univ_subset_iff.1 h] + +lemma MeasurableSet.of_union₃_range_cover (hi₁ : MeasurableEmbedding i₁) + (hi₂ : MeasurableEmbedding i₂) (hi₃ : MeasurableEmbedding i₃) + (h : univ ⊆ range i₁ ∪ range i₂ ∪ range i₃) (hs₁ : MeasurableSet (i₁ ⁻¹' s)) + (hs₂ : MeasurableSet (i₂ ⁻¹' s)) (hs₃ : MeasurableSet (i₃ ⁻¹' s)) : MeasurableSet s := by + convert (hi₁.measurableSet_image' hs₁).union (hi₂.measurableSet_image' hs₂) |>.union + (hi₃.measurableSet_image' hs₃) + simp [image_preimage_eq_range_inter, ← union_inter_distrib_right, univ_subset_iff.1 h] + +lemma Measurable.of_union_range_cover (hi₁ : MeasurableEmbedding i₁) + (hi₂ : MeasurableEmbedding i₂) (h : univ ⊆ range i₁ ∪ range i₂) + (hf₁ : Measurable (f ∘ i₁)) (hf₂ : Measurable (f ∘ i₂)) : Measurable f := + fun _s hs ↦ .of_union_range_cover hi₁ hi₂ h (hf₁ hs) (hf₂ hs) + +lemma Measurable.of_union₃_range_cover (hi₁ : MeasurableEmbedding i₁) + (hi₂ : MeasurableEmbedding i₂) (hi₃ : MeasurableEmbedding i₃) + (h : univ ⊆ range i₁ ∪ range i₂ ∪ range i₃) (hf₁ : Measurable (f ∘ i₁)) + (hf₂ : Measurable (f ∘ i₂)) (hf₃ : Measurable (f ∘ i₃)) : Measurable f := + fun _s hs ↦ .of_union₃_range_cover hi₁ hi₂ hi₃ h (hf₁ hs) (hf₂ hs) (hf₃ hs) + +end gluing + theorem MeasurableSet.exists_measurable_proj {_ : MeasurableSpace α} (hs : MeasurableSet s) (hne : s.Nonempty) : ∃ f : α → s, Measurable f ∧ ∀ x : s, f x = x := let ⟨f, hfm, hf⟩ := @@ -155,7 +189,7 @@ instance instEquivLike : EquivLike (α ≃ᵐ β) α β where theorem coe_toEquiv (e : α ≃ᵐ β) : (e.toEquiv : α → β) = e := rfl -@[measurability] +@[measurability, fun_prop] protected theorem measurable (e : α ≃ᵐ β) : Measurable (e : α → β) := e.measurable_toFun @@ -350,6 +384,18 @@ def prodAssoc : (α × β) × γ ≃ᵐ α × β × γ where measurable_toFun := measurable_fst.fst.prod_mk <| measurable_fst.snd.prod_mk measurable_snd measurable_invFun := (measurable_fst.prod_mk measurable_snd.fst).prod_mk measurable_snd.snd +/-- `PUnit` is a left identity for product of measurable spaces up to a measurable equivalence. -/ +def punitProd : PUnit × α ≃ᵐ α where + toEquiv := Equiv.punitProd α + measurable_toFun := measurable_snd + measurable_invFun := measurable_prod_mk_left + +/-- `PUnit` is a right identity for product of measurable spaces up to a measurable equivalence. -/ +def prodPUnit : α × PUnit ≃ᵐ α where + toEquiv := Equiv.prodPUnit α + measurable_toFun := measurable_fst + measurable_invFun := measurable_prod_mk_right + variable [MeasurableSpace δ] in /-- Sums of measurable spaces are symmetric. -/ def sumCongr (ab : α ≃ᵐ β) (cd : γ ≃ᵐ δ) : α ⊕ γ ≃ᵐ β ⊕ δ where @@ -495,7 +541,7 @@ Measurable version of `Fin.insertNthEquiv`. -/ def piFinSuccAbove {n : ℕ} (α : Fin (n + 1) → Type*) [∀ i, MeasurableSpace (α i)] (i : Fin (n + 1)) : (∀ j, α j) ≃ᵐ α i × ∀ j, α (i.succAbove j) where toEquiv := (Fin.insertNthEquiv α i).symm - measurable_toFun := (measurable_pi_apply i).prod_mk <| measurable_pi_iff.2 fun j => + measurable_toFun := (measurable_pi_apply i).prod_mk <| measurable_pi_iff.2 fun _ => measurable_pi_apply _ measurable_invFun := measurable_pi_iff.2 <| i.forall_iff_succAbove.2 ⟨by simp [measurable_fst], fun j => by simpa using (measurable_pi_apply _).comp measurable_snd⟩ diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean b/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean new file mode 100644 index 0000000000000..e9f2db14bfc25 --- /dev/null +++ b/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean @@ -0,0 +1,136 @@ +/- +Copyright (c) 2020 Floris van Doorn. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Floris van Doorn +-/ +import Mathlib.MeasureTheory.MeasurableSpace.Embedding +import Mathlib.MeasureTheory.PiSystem + +/-! +# The product sigma algebra + +This file talks about the measurability of operations on binary functions. +-/ + +assert_not_exists MeasureTheory.Measure + +noncomputable section + +open Set MeasurableSpace + +variable {α β γ : Type*} [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] + +/-- The product of generated σ-algebras is the one generated by rectangles, if both generating sets + are countably spanning. -/ +theorem generateFrom_prod_eq {α β} {C : Set (Set α)} {D : Set (Set β)} (hC : IsCountablySpanning C) + (hD : IsCountablySpanning D) : + @Prod.instMeasurableSpace _ _ (generateFrom C) (generateFrom D) = + generateFrom (image2 (· ×ˢ ·) C D) := by + apply le_antisymm + · refine sup_le ?_ ?_ <;> rw [comap_generateFrom] <;> apply generateFrom_le <;> + rintro _ ⟨s, hs, rfl⟩ + · rcases hD with ⟨t, h1t, h2t⟩ + rw [← prod_univ, ← h2t, prod_iUnion] + apply MeasurableSet.iUnion + intro n + apply measurableSet_generateFrom + exact ⟨s, hs, t n, h1t n, rfl⟩ + · rcases hC with ⟨t, h1t, h2t⟩ + rw [← univ_prod, ← h2t, iUnion_prod_const] + apply MeasurableSet.iUnion + rintro n + apply measurableSet_generateFrom + exact mem_image2_of_mem (h1t n) hs + · apply generateFrom_le + rintro _ ⟨s, hs, t, ht, rfl⟩ + dsimp only + rw [prod_eq] + apply (measurable_fst _).inter (measurable_snd _) + · exact measurableSet_generateFrom hs + · exact measurableSet_generateFrom ht + +/-- If `C` and `D` generate the σ-algebras on `α` resp. `β`, then rectangles formed by `C` and `D` + generate the σ-algebra on `α × β`. -/ +theorem generateFrom_eq_prod {C : Set (Set α)} {D : Set (Set β)} (hC : generateFrom C = ‹_›) + (hD : generateFrom D = ‹_›) (h2C : IsCountablySpanning C) (h2D : IsCountablySpanning D) : + generateFrom (image2 (· ×ˢ ·) C D) = Prod.instMeasurableSpace := by + rw [← hC, ← hD, generateFrom_prod_eq h2C h2D] + +/-- The product σ-algebra is generated from boxes, i.e. `s ×ˢ t` for sets `s : Set α` and + `t : Set β`. -/ +lemma generateFrom_prod : + generateFrom (image2 (· ×ˢ ·) { s : Set α | MeasurableSet s } { t : Set β | MeasurableSet t }) = + Prod.instMeasurableSpace := + generateFrom_eq_prod generateFrom_measurableSet generateFrom_measurableSet + isCountablySpanning_measurableSet isCountablySpanning_measurableSet + +/-- Rectangles form a π-system. -/ +lemma isPiSystem_prod : + IsPiSystem (image2 (· ×ˢ ·) { s : Set α | MeasurableSet s } { t : Set β | MeasurableSet t }) := + isPiSystem_measurableSet.prod isPiSystem_measurableSet + +lemma MeasurableEmbedding.prod_mk {α β γ δ : Type*} {mα : MeasurableSpace α} + {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {f : α → β} + {g : γ → δ} (hg : MeasurableEmbedding g) (hf : MeasurableEmbedding f) : + MeasurableEmbedding fun x : γ × α => (g x.1, f x.2) := by + have h_inj : Function.Injective fun x : γ × α => (g x.fst, f x.snd) := by + intro x y hxy + rw [← @Prod.mk.eta _ _ x, ← @Prod.mk.eta _ _ y] + simp only [Prod.mk.inj_iff] at hxy ⊢ + exact ⟨hg.injective hxy.1, hf.injective hxy.2⟩ + refine ⟨h_inj, ?_, ?_⟩ + · exact (hg.measurable.comp measurable_fst).prod_mk (hf.measurable.comp measurable_snd) + · -- Induction using the π-system of rectangles + refine fun s hs => + @MeasurableSpace.induction_on_inter _ + (fun s => MeasurableSet ((fun x : γ × α => (g x.fst, f x.snd)) '' s)) _ _ + generateFrom_prod.symm isPiSystem_prod ?_ ?_ ?_ ?_ _ hs + · simp only [Set.image_empty, MeasurableSet.empty] + · rintro t ⟨t₁, ht₁, t₂, ht₂, rfl⟩ + rw [← Set.prod_image_image_eq] + exact (hg.measurableSet_image.mpr ht₁).prod (hf.measurableSet_image.mpr ht₂) + · intro t _ ht_m + rw [← Set.range_diff_image h_inj, ← Set.prod_range_range_eq] + exact + MeasurableSet.diff (MeasurableSet.prod hg.measurableSet_range hf.measurableSet_range) ht_m + · intro g _ _ hg + simp_rw [Set.image_iUnion] + exact MeasurableSet.iUnion hg + +lemma MeasurableEmbedding.prod_mk_left {β γ : Type*} [MeasurableSingletonClass α] + {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + (x : α) {f : γ → β} (hf : MeasurableEmbedding f) : + MeasurableEmbedding (fun y ↦ (x, f y)) where + injective := by + intro y y' + simp only [Prod.mk.injEq, true_and] + exact fun h ↦ hf.injective h + measurable := Measurable.prod_mk measurable_const hf.measurable + measurableSet_image' := by + intro s hs + convert (MeasurableSet.singleton x).prod (hf.measurableSet_image.mpr hs) + ext x + simp + +lemma measurableEmbedding_prod_mk_left [MeasurableSingletonClass α] (x : α) : + MeasurableEmbedding (Prod.mk x : β → α × β) := + MeasurableEmbedding.prod_mk_left x MeasurableEmbedding.id + +lemma MeasurableEmbedding.prod_mk_right {β γ : Type*} [MeasurableSingletonClass α] + {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + {f : γ → β} (hf : MeasurableEmbedding f) (x : α) : + MeasurableEmbedding (fun y ↦ (f y, x)) where + injective := by + intro y y' + simp only [Prod.mk.injEq, and_true] + exact fun h ↦ hf.injective h + measurable := Measurable.prod_mk hf.measurable measurable_const + measurableSet_image' := by + intro s hs + convert (hf.measurableSet_image.mpr hs).prod (MeasurableSet.singleton x) + ext x + simp + +lemma measurableEmbedding_prod_mk_right [MeasurableSingletonClass α] (x : α) : + MeasurableEmbedding (fun y ↦ (y, x) : β → β × α) := + MeasurableEmbedding.prod_mk_right MeasurableEmbedding.id x diff --git a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean index 7ea4ac9be4b94..6f771b3602413 100644 --- a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean @@ -248,7 +248,7 @@ theorem aemeasurable_restrict_iff_comap_subtype {s : Set α} (hs : MeasurableSet {f : α → β} : AEMeasurable f (μ.restrict s) ↔ AEMeasurable (f ∘ (↑) : s → β) (comap (↑) μ) := by rw [← map_comap_subtype_coe hs, (MeasurableEmbedding.subtype_coe hs).aemeasurable_map_iff] -@[to_additive] -- @[to_additive (attr := simp)] -- Porting note (#10618): simp can prove this +@[to_additive] theorem aemeasurable_one [One β] : AEMeasurable (fun _ : α => (1 : β)) μ := measurable_one.aemeasurable @@ -413,7 +413,7 @@ lemma map_sum {ι : Type*} {m : ι → Measure α} {f : α → β} (hf : AEMeasu instance (μ : Measure α) (f : α → β) [SFinite μ] : SFinite (μ.map f) := by by_cases H : AEMeasurable f μ - · rw [← sum_sFiniteSeq μ] at H ⊢ + · rw [← sum_sfiniteSeq μ] at H ⊢ rw [map_sum H] infer_instance · rw [map_of_not_aemeasurable H] diff --git a/Mathlib/MeasureTheory/Measure/AddContent.lean b/Mathlib/MeasureTheory/Measure/AddContent.lean index e07a40a78c24f..835d2ea391739 100644 --- a/Mathlib/MeasureTheory/Measure/AddContent.lean +++ b/Mathlib/MeasureTheory/Measure/AddContent.lean @@ -3,6 +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, Peter Pfaffelhuber -/ +import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Data.ENNReal.Basic import Mathlib.MeasureTheory.SetSemiring diff --git a/Mathlib/MeasureTheory/Measure/Complex.lean b/Mathlib/MeasureTheory/Measure/Complex.lean index 7ce4fcfe8f699..611174a941c5f 100644 --- a/Mathlib/MeasureTheory/Measure/Complex.lean +++ b/Mathlib/MeasureTheory/Measure/Complex.lean @@ -34,7 +34,7 @@ noncomputable section open scoped MeasureTheory ENNReal NNReal -variable {α β : Type*} {m : MeasurableSpace α} +variable {α : Type*} {m : MeasurableSpace α} namespace MeasureTheory @@ -63,7 +63,7 @@ def _root_.MeasureTheory.SignedMeasure.toComplexMeasure (s t : SignedMeasure α) measureOf' i := ⟨s i, t i⟩ empty' := by dsimp only; rw [s.empty, t.empty]; rfl not_measurable' i hi := by dsimp only; rw [s.not_measurable hi, t.not_measurable hi]; rfl - m_iUnion' f hf hfdisj := (Complex.hasSum_iff _ _).2 ⟨s.m_iUnion hf hfdisj, t.m_iUnion hf hfdisj⟩ + m_iUnion' _ hf hfdisj := (Complex.hasSum_iff _ _).2 ⟨s.m_iUnion hf hfdisj, t.m_iUnion hf hfdisj⟩ theorem _root_.MeasureTheory.SignedMeasure.toComplexMeasure_apply {s t : SignedMeasure α} {i : Set α} : s.toComplexMeasure t i = ⟨s i, t i⟩ := rfl diff --git a/Mathlib/MeasureTheory/Measure/Content.lean b/Mathlib/MeasureTheory/Measure/Content.lean index b07a09b9ad57e..77169173b08ad 100644 --- a/Mathlib/MeasureTheory/Measure/Content.lean +++ b/Mathlib/MeasureTheory/Measure/Content.lean @@ -190,7 +190,7 @@ theorem innerContent_iUnion_nat [R1Space G] ⦃U : ℕ → Set G⦄ rwa [Opens.iSup_def] at this theorem innerContent_comap (f : G ≃ₜ G) (h : ∀ ⦃K : Compacts G⦄, μ (K.map f f.continuous) = μ K) - (U : Opens G) : μ.innerContent (Opens.comap f.toContinuousMap U) = μ.innerContent U := by + (U : Opens G) : μ.innerContent (Opens.comap f U) = μ.innerContent U := by refine (Compacts.equiv f).surjective.iSup_congr _ fun K => iSup_congr_Prop image_subset_iff ?_ intro hK simp only [Equiv.coe_fn_mk, Subtype.mk_eq_mk, Compacts.equiv] @@ -200,7 +200,7 @@ theorem innerContent_comap (f : G ≃ₜ G) (h : ∀ ⦃K : Compacts G⦄, μ (K theorem is_mul_left_invariant_innerContent [Group G] [TopologicalGroup G] (h : ∀ (g : G) {K : Compacts G}, μ (K.map _ <| continuous_mul_left g) = μ K) (g : G) (U : Opens G) : - μ.innerContent (Opens.comap (Homeomorph.mulLeft g).toContinuousMap U) = μ.innerContent U := by + μ.innerContent (Opens.comap (Homeomorph.mulLeft g) U) = μ.innerContent U := by convert μ.innerContent_comap (Homeomorph.mulLeft g) (fun K => h g) U @[to_additive] @@ -211,7 +211,7 @@ theorem innerContent_pos_of_is_mul_left_invariant [Group G] [TopologicalGroup G] rcases compact_covered_by_mul_left_translates K.2 this with ⟨s, hs⟩ suffices μ K ≤ s.card * μ.innerContent U by exact (ENNReal.mul_pos_iff.mp <| hK.bot_lt.trans_le this).2 - have : (K : Set G) ⊆ ↑(⨆ g ∈ s, Opens.comap (Homeomorph.mulLeft g).toContinuousMap U) := by + have : (K : Set G) ⊆ ↑(⨆ g ∈ s, Opens.comap (Homeomorph.mulLeft g : C(G, G)) U) := by simpa only [Opens.iSup_def, Opens.coe_comap, Subtype.coe_mk] refine (μ.le_innerContent _ _ this).trans ?_ refine diff --git a/Mathlib/MeasureTheory/Measure/Count.lean b/Mathlib/MeasureTheory/Measure/Count.lean index 0383da666916a..b91e37e621e4a 100644 --- a/Mathlib/MeasureTheory/Measure/Count.lean +++ b/Mathlib/MeasureTheory/Measure/Count.lean @@ -34,18 +34,17 @@ theorem le_count_apply : ∑' _ : s, (1 : ℝ≥0∞) ≤ count s := _ ≤ ∑' i, dirac i s := ENNReal.tsum_le_tsum fun _ => le_dirac_apply _ ≤ count s := le_sum_apply _ _ -theorem count_apply (hs : MeasurableSet s) : count s = ∑' i : s, 1 := by +theorem count_apply (hs : MeasurableSet s) : count s = ∑' _ : s, 1 := by simp only [count, sum_apply, hs, dirac_apply', ← tsum_subtype s (1 : α → ℝ≥0∞), Pi.one_apply] --- @[simp] -- Porting note (#10618): simp can prove this theorem count_empty : count (∅ : Set α) = 0 := by rw [count_apply MeasurableSet.empty, tsum_empty] @[simp] theorem count_apply_finset' {s : Finset α} (s_mble : MeasurableSet (s : Set α)) : count (↑s : Set α) = s.card := calc - count (↑s : Set α) = ∑' i : (↑s : Set α), 1 := count_apply s_mble - _ = ∑ i ∈ s, 1 := s.tsum_subtype 1 + count (↑s : Set α) = ∑' _ : (↑s : Set α), 1 := count_apply s_mble + _ = ∑ _ ∈ s, 1 := s.tsum_subtype 1 _ = s.card := by simp @[simp] @@ -102,13 +101,13 @@ theorem count_apply_lt_top [MeasurableSingletonClass α] : count s < ∞ ↔ s.F theorem empty_of_count_eq_zero' (s_mble : MeasurableSet s) (hsc : count s = 0) : s = ∅ := by have hs : s.Finite := by rw [← count_apply_lt_top' s_mble, hsc] - exact WithTop.zero_lt_top + exact WithTop.top_pos simpa [count_apply_finite' hs s_mble] using hsc theorem empty_of_count_eq_zero [MeasurableSingletonClass α] (hsc : count s = 0) : s = ∅ := by have hs : s.Finite := by rw [← count_apply_lt_top, hsc] - exact WithTop.zero_lt_top + exact WithTop.top_pos simpa [count_apply_finite _ hs] using hsc @[simp] @@ -133,7 +132,6 @@ theorem count_singleton' {a : α} (ha : MeasurableSet ({a} : Set α)) : count ({ simp [@toFinset_card _ _ (Set.finite_singleton a).fintype, @Fintype.card_unique _ _ (Set.finite_singleton a).fintype] --- @[simp] -- Porting note (#10618): simp can prove this theorem count_singleton [MeasurableSingletonClass α] (a : α) : count ({a} : Set α) = 1 := count_singleton' (measurableSet_singleton a) diff --git a/Mathlib/MeasureTheory/Measure/Dirac.lean b/Mathlib/MeasureTheory/Measure/Dirac.lean index 29e9d534230ce..bf8d888f3eea2 100644 --- a/Mathlib/MeasureTheory/Measure/Dirac.lean +++ b/Mathlib/MeasureTheory/Measure/Dirac.lean @@ -80,6 +80,14 @@ theorem restrict_singleton (μ : Measure α) (a : α) : μ.restrict {a} = μ {a} · have : s ∩ {a} = ∅ := inter_singleton_eq_empty.2 ha simp [*] +/-- Two measures on a countable space are equal if they agree on singletons. -/ +theorem ext_of_singleton [Countable α] {μ ν : Measure α} (h : ∀ a, μ {a} = ν {a}) : μ = ν := + ext_of_sUnion_eq_univ (countable_range singleton) (by aesop) (by aesop) + +/-- Two measures on a countable space are equal if and only if they agree on singletons. -/ +theorem ext_iff_singleton [Countable α] {μ ν : Measure α} : μ = ν ↔ ∀ a, μ {a} = ν {a} := + ⟨fun h _ ↦ h ▸ rfl, ext_of_singleton⟩ + /-- If `f` is a map with countable codomain, then `μ.map f` is a sum of Dirac measures. -/ theorem map_eq_sum [Countable β] [MeasurableSingletonClass β] (μ : Measure α) (f : α → β) (hf : Measurable f) : μ.map f = sum fun b : β => μ (f ⁻¹' {b}) • dirac b := by diff --git a/Mathlib/MeasureTheory/Measure/DiracProba.lean b/Mathlib/MeasureTheory/Measure/DiracProba.lean index 18bc9a7f40a5e..9a4f81e244015 100644 --- a/Mathlib/MeasureTheory/Measure/DiracProba.lean +++ b/Mathlib/MeasureTheory/Measure/DiracProba.lean @@ -13,7 +13,7 @@ import Mathlib.MeasureTheory.Measure.ProbabilityMeasure * `diracProba`: The Dirac delta mass at a point as a probability measure. ## Main results -* `embedding_diracProba`: If `X` is a completely regular T0 space with its Borel sigma algebra, +* `isEmbedding_diracProba`: If `X` is a completely regular T0 space with its Borel sigma algebra, then the mapping that takes a point `x : X` to the delta-measure `diracProba x` is an embedding `X ↪ ProbabilityMeasure X`. @@ -36,7 +36,7 @@ lemma CompletelyRegularSpace.exists_BCNN {X : Type*} [TopologicalSpace X] [Compl set g' := BoundedContinuousFunction.mkOfBound ⟨fun x ↦ Real.toNNReal (g x), continuous_real_toNNReal.comp g_cont.subtype_val⟩ 1 g_bdd set f := 1 - g' - refine ⟨f, by simp [f, g', gx_zero], fun y y_in_K ↦ by simp [f, g', g_one_on_K y_in_K]⟩ + refine ⟨f, by simp [f, g', gx_zero], fun y y_in_K ↦ by simp [f, g', g_one_on_K y_in_K, tsub_self]⟩ namespace MeasureTheory @@ -180,9 +180,12 @@ noncomputable def diracProbaHomeomorph [T0Space X] [CompletelyRegularSpace X] : /-- If `X` is a completely regular T0 space with its Borel sigma algebra, then the mapping that takes a point `x : X` to the delta-measure `diracProba x` is an embedding `X → ProbabilityMeasure X`. -/ -theorem embedding_diracProba [T0Space X] [CompletelyRegularSpace X] : - Embedding (fun (x : X) ↦ diracProba x) := - embedding_subtype_val.comp diracProbaHomeomorph.embedding +theorem isEmbedding_diracProba [T0Space X] [CompletelyRegularSpace X] : + IsEmbedding (fun (x : X) ↦ diracProba x) := + IsEmbedding.subtypeVal.comp diracProbaHomeomorph.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_diracProba := isEmbedding_diracProba end embed_to_probabilityMeasure diff --git a/Mathlib/MeasureTheory/Measure/Doubling.lean b/Mathlib/MeasureTheory/Measure/Doubling.lean index 0aabc6cf60a99..d8195c77470d6 100644 --- a/Mathlib/MeasureTheory/Measure/Doubling.lean +++ b/Mathlib/MeasureTheory/Measure/Doubling.lean @@ -36,14 +36,14 @@ example we want hyperbolic space to carry the instance `IsUnifLocDoublingMeasure volumes grow exponentially in hyperbolic space. To be really explicit, consider the hyperbolic plane of curvature -1, the area of a disc of radius `ε` is `A(ε) = 2π(cosh(ε) - 1)` so `A(2ε)/A(ε) ~ exp(ε)`. -/ -class IsUnifLocDoublingMeasure {α : Type*} [MetricSpace α] [MeasurableSpace α] +class IsUnifLocDoublingMeasure {α : Type*} [PseudoMetricSpace α] [MeasurableSpace α] (μ : Measure α) : Prop where exists_measure_closedBall_le_mul'' : ∃ C : ℝ≥0, ∀ᶠ ε in 𝓝[>] 0, ∀ x, μ (closedBall x (2 * ε)) ≤ C * μ (closedBall x ε) namespace IsUnifLocDoublingMeasure -variable {α : Type*} [MetricSpace α] [MeasurableSpace α] (μ : Measure α) +variable {α : Type*} [PseudoMetricSpace α] [MeasurableSpace α] (μ : Measure α) [IsUnifLocDoublingMeasure μ] -- Porting note: added for missing infer kinds diff --git a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean index f10ffdcda79a3..e5f6140996c3c 100644 --- a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean @@ -428,7 +428,7 @@ theorem _root_.Filter.Tendsto.mass {γ : Type*} {F : Filter γ} {μs : γ → Fi theorem tendsto_iff_weakDual_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ Tendsto (fun i ↦ (μs i).toWeakDualBCNN) F (𝓝 μ.toWeakDualBCNN) := - Inducing.tendsto_nhds_iff ⟨rfl⟩ + IsInducing.tendsto_nhds_iff ⟨rfl⟩ theorem tendsto_iff_forall_toWeakDualBCNN_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} : @@ -501,16 +501,18 @@ lemma injective_toWeakDualBCNN : variable (Ω) -lemma embedding_toWeakDualBCNN : - Embedding (toWeakDualBCNN : FiniteMeasure Ω → WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0)) where - induced := rfl +lemma isEmbedding_toWeakDualBCNN : + IsEmbedding (toWeakDualBCNN : FiniteMeasure Ω → WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0)) where + eq_induced := rfl inj := injective_toWeakDualBCNN +@[deprecated (since := "2024-10-26")] +alias embedding_toWeakDualBCNN := isEmbedding_toWeakDualBCNN + /-- On topological spaces where indicators of closed sets have decreasing approximating sequences of continuous functions (`HasOuterApproxClosed`), the topology of weak convergence of finite Borel measures is Hausdorff (`T2Space`). -/ -instance t2Space : T2Space (FiniteMeasure Ω) := - Embedding.t2Space (embedding_toWeakDualBCNN Ω) +instance t2Space : T2Space (FiniteMeasure Ω) := (isEmbedding_toWeakDualBCNN Ω).t2Space end Hausdorff -- section diff --git a/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean b/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean index 97ffeece7c11c..422da03a98cea 100644 --- a/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean +++ b/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ import Mathlib.MeasureTheory.Measure.ProbabilityMeasure -import Mathlib.MeasureTheory.Constructions.Prod.Basic +import Mathlib.MeasureTheory.Measure.Prod /-! # Products of finite measures and probability measures diff --git a/Mathlib/MeasureTheory/Measure/GiryMonad.lean b/Mathlib/MeasureTheory/Measure/GiryMonad.lean index c84c4f1258001..4b954b6e64486 100644 --- a/Mathlib/MeasureTheory/Measure/GiryMonad.lean +++ b/Mathlib/MeasureTheory/Measure/GiryMonad.lean @@ -78,7 +78,7 @@ theorem measurable_dirac : Measurable (Measure.dirac : α → Measure α) := by theorem measurable_lintegral {f : α → ℝ≥0∞} (hf : Measurable f) : Measurable fun μ : Measure α => ∫⁻ x, f x ∂μ := by simp only [lintegral_eq_iSup_eapprox_lintegral, hf, SimpleFunc.lintegral] - refine measurable_iSup fun n => Finset.measurable_sum _ fun i _ => ?_ + refine .iSup fun n => Finset.measurable_sum _ fun i _ => ?_ refine Measurable.const_mul ?_ _ exact measurable_coe ((SimpleFunc.eapprox f n).measurableSet_preimage _) @@ -154,6 +154,11 @@ theorem bind_apply {m : Measure α} {f : α → Measure β} {s : Set β} (hs : M (hf : Measurable f) : bind m f s = ∫⁻ a, f a s ∂m := by rw [bind, join_apply hs, lintegral_map (measurable_coe hs) hf] +@[simp] +lemma bind_const {m : Measure α} {ν : Measure β} : m.bind (fun _ ↦ ν) = m Set.univ • ν := by + ext s hs + rw [bind_apply hs measurable_const, lintegral_const, smul_apply, smul_eq_mul, mul_comm] + theorem measurable_bind' {g : α → Measure β} (hg : Measurable g) : Measurable fun m => bind m g := measurable_join.comp (measurable_map _ hg) @@ -169,16 +174,27 @@ theorem bind_bind {γ} [MeasurableSpace γ] {m : Measure α} {f : α → Measure conv_rhs => enter [2, a]; erw [bind_apply hs hg] rfl -theorem bind_dirac {f : α → Measure β} (hf : Measurable f) (a : α) : bind (dirac a) f = f a := by +theorem dirac_bind {f : α → Measure β} (hf : Measurable f) (a : α) : bind (dirac a) f = f a := by ext1 s hs erw [bind_apply hs hf, lintegral_dirac' a ((measurable_coe hs).comp hf)] rfl -theorem dirac_bind {m : Measure α} : bind m dirac = m := by +@[simp] +theorem bind_dirac {m : Measure α} : bind m dirac = m := by ext1 s hs - simp only [bind_apply hs measurable_dirac, dirac_apply' _ hs, lintegral_indicator 1 hs, + simp only [bind_apply hs measurable_dirac, dirac_apply' _ hs, lintegral_indicator hs, Pi.one_apply, lintegral_one, restrict_apply, MeasurableSet.univ, univ_inter] +@[simp] +lemma bind_dirac_eq_map (m : Measure α) {f : α → β} (hf : Measurable f) : + m.bind (fun x ↦ Measure.dirac (f x)) = m.map f := by + ext s hs + rw [bind_apply hs] + swap; · exact measurable_dirac.comp hf + simp_rw [dirac_apply' _ hs] + rw [← lintegral_map _ hf, lintegral_indicator_one hs] + exact measurable_const.indicator hs + theorem join_eq_bind (μ : Measure (Measure α)) : join μ = bind μ id := by rw [bind, map_id] theorem join_map_map {f : α → β} (hf : Measurable f) (μ : Measure (Measure α)) : @@ -195,11 +211,10 @@ theorem join_map_join (μ : Measure (Measure (Measure α))) : join (map join μ) funext ν exact join_eq_bind ν -theorem join_map_dirac (μ : Measure α) : join (map dirac μ) = μ := - dirac_bind +theorem join_map_dirac (μ : Measure α) : join (map dirac μ) = μ := bind_dirac theorem join_dirac (μ : Measure α) : join (dirac μ) = μ := - (join_eq_bind (dirac μ)).trans (bind_dirac measurable_id _) + (join_eq_bind (dirac μ)).trans (dirac_bind measurable_id _) end Measure diff --git a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean index a4030ed00f9d7..dc9e9ec5eeea0 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean @@ -48,8 +48,6 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [MeasurableSpace [FiniteDimensional ℝ E] (μ : Measure E) [IsAddHaarMeasure μ] {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] -variable {s : Set E} - /-- The integral of `f (R • x)` with respect to an additive Haar measure is a multiple of the integral of `f`. The formula we give works even when `f` is not integrable or `R = 0` thanks to the convention that a non-integrable function has integral zero. -/ diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean index 853e3faeab186..7f76b5cbe8048 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean @@ -213,8 +213,6 @@ theorem Basis.parallelepiped_map (b : Basis ι ℝ E) (e : E ≃ₗ[ℝ] F) : LinearMap.isOpenMap_of_finiteDimensional _ e.surjective) := PositiveCompacts.ext (image_parallelepiped e.toLinearMap _).symm --- removing this option makes elaboration approximately 1 second slower -set_option tactic.skipAssignedInstances false in theorem Basis.prod_parallelepiped (v : Basis ι ℝ E) (w : Basis ι' ℝ F) : (v.prod w).parallelepiped = v.parallelepiped.prod w.parallelepiped := by ext x diff --git a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean index 6cb8d92d7d95f..e552fa14c3286 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean @@ -57,7 +57,7 @@ instance QuotientGroup.measurableSMul {G : Type*} [Group G] {Γ : Subgroup G} [M [TopologicalSpace G] [TopologicalGroup G] [BorelSpace G] [BorelSpace (G ⧸ Γ)] : MeasurableSMul G (G ⧸ Γ) where measurable_const_smul g := (continuous_const_smul g).measurable - measurable_smul_const x := (QuotientGroup.continuous_smul₁ x).measurable + measurable_smul_const _ := (continuous_id.smul continuous_const).measurable end diff --git a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean index 0b75436b65433..a9088acc3aeda 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean @@ -3,14 +3,14 @@ Copyright (c) 2023 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.MeasureTheory.Constructions.Prod.Integral import Mathlib.MeasureTheory.Function.LocallyIntegrable import Mathlib.MeasureTheory.Group.Integral +import Mathlib.MeasureTheory.Integral.Prod +import Mathlib.MeasureTheory.Integral.SetIntegral +import Mathlib.MeasureTheory.Measure.EverywherePos +import Mathlib.MeasureTheory.Measure.Haar.Basic import Mathlib.Topology.Metrizable.Urysohn import Mathlib.Topology.UrysohnsLemma -import Mathlib.MeasureTheory.Measure.Haar.Basic -import Mathlib.MeasureTheory.Measure.EverywherePos -import Mathlib.MeasureTheory.Integral.SetIntegral /-! # Uniqueness of Haar measure in locally compact groups diff --git a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean index d824d0aecc8ad..6fe5d37bd096f 100644 --- a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean +++ b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean @@ -80,7 +80,7 @@ theorem measure_of_cont_bdd_of_tendsto_filter_indicator {ι : Type*} {L : Filter convert tendsto_lintegral_nn_filter_of_le_const μ fs_bdd fs_lim have aux : ∀ ω, indicator E (fun _ ↦ (1 : ℝ≥0∞)) ω = ↑(indicator E (fun _ ↦ (1 : ℝ≥0)) ω) := fun ω ↦ by simp only [ENNReal.coe_indicator, ENNReal.coe_one] - simp_rw [← aux, lintegral_indicator _ E_mble] + simp_rw [← aux, lintegral_indicator E_mble] simp only [lintegral_one, Measure.restrict_apply, MeasurableSet.univ, univ_inter] /-- If a sequence of bounded continuous functions tends to the indicator of a measurable set and @@ -162,7 +162,7 @@ approximating sequence to the indicator of the set. -/ theorem measure_le_lintegral [MeasurableSpace X] [OpensMeasurableSpace X] (μ : Measure X) (n : ℕ) : μ F ≤ ∫⁻ x, (hF.apprSeq n x : ℝ≥0∞) ∂μ := by convert_to ∫⁻ x, (F.indicator (fun _ ↦ (1 : ℝ≥0∞))) x ∂μ ≤ ∫⁻ x, hF.apprSeq n x ∂μ - · rw [lintegral_indicator _ hF.measurableSet] + · rw [lintegral_indicator hF.measurableSet] simp only [lintegral_one, MeasurableSet.univ, Measure.restrict_apply, univ_inter] · apply lintegral_mono intro x diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean index 497ba69408ba9..ce69db687e782 100644 --- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean +++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean @@ -268,7 +268,7 @@ theorem mono_pre (m : Set X → ℝ≥0∞) {r r' : ℝ≥0∞} (h : r ≤ r') : le_pre.2 fun _ hs => pre_le (hs.trans h) theorem mono_pre_nat (m : Set X → ℝ≥0∞) : Monotone fun k : ℕ => pre m k⁻¹ := - fun k l h => le_pre.2 fun s hs => pre_le (hs.trans <| by simpa) + fun k l h => le_pre.2 fun _ hs => pre_le (hs.trans <| by simpa) theorem tendsto_pre (m : Set X → ℝ≥0∞) (s : Set X) : Tendsto (fun r => pre m r s) (𝓝[>] 0) (𝓝 <| mkMetric' m s) := by @@ -470,7 +470,7 @@ theorem mkMetric_apply (m : ℝ≥0∞ → ℝ≥0∞) (s : Set X) : simp only [← OuterMeasure.coe_mkMetric, OuterMeasure.mkMetric, OuterMeasure.mkMetric', OuterMeasure.iSup_apply, OuterMeasure.mkMetric'.pre, OuterMeasure.boundedBy_apply, extend] refine - surjective_id.iSup_congr (fun r => r) fun r => + surjective_id.iSup_congr (id) fun r => iSup_congr_Prop Iff.rfl fun _ => surjective_id.iInf_congr _ fun t => iInf_congr_Prop Iff.rfl fun ht => ?_ dsimp @@ -669,7 +669,7 @@ variable [MeasurableSpace X] [BorelSpace X] [MeasurableSpace Y] [BorelSpace Y] namespace HolderOnWith -variable {C r : ℝ≥0} {f : X → Y} {s t : Set X} +variable {C r : ℝ≥0} {f : X → Y} {s : Set X} /-- If `f : X → Y` is Hölder continuous on `s` with a positive exponent `r`, then `μH[d] (f '' s) ≤ C ^ d * μH[r * d] s`. -/ @@ -715,7 +715,7 @@ end HolderOnWith namespace LipschitzOnWith -variable {K : ℝ≥0} {f : X → Y} {s t : Set X} +variable {K : ℝ≥0} {f : X → Y} {s : Set X} /-- If `f : X → Y` is `K`-Lipschitz on `s`, then `μH[d] (f '' s) ≤ K ^ d * μH[d] s`. -/ theorem hausdorffMeasure_image_le (h : LipschitzOnWith K f s) {d : ℝ} (hd : 0 ≤ d) : @@ -1026,18 +1026,8 @@ theorem hausdorffMeasure_smul_right_image [NormedAddCommGroup E] [NormedSpace -- break lineMap into pieces suffices μH[1] ((‖v‖ • ·) '' (LinearMap.toSpanSingleton ℝ E (‖v‖⁻¹ • v) '' s)) = ‖v‖₊ • μH[1] s by - -- Porting note: proof was shorter, could need some golf - simp only [hausdorffMeasure_real, nnreal_smul_coe_apply] - convert this - · simp only [image_smul, LinearMap.toSpanSingleton_apply, Set.image_image] - ext e - simp only [mem_image] - refine ⟨fun ⟨x, h⟩ => ⟨x, ?_⟩, fun ⟨x, h⟩ => ⟨x, ?_⟩⟩ - · rw [smul_comm (norm _), smul_comm (norm _), inv_smul_smul₀ hn] - exact h - · rw [smul_comm (norm _), smul_comm (norm _), inv_smul_smul₀ hn] at h - exact h - · exact hausdorffMeasure_real.symm + simpa only [Set.image_image, smul_comm (norm _), inv_smul_smul₀ hn, + LinearMap.toSpanSingleton_apply] using this have iso_smul : Isometry (LinearMap.toSpanSingleton ℝ E (‖v‖⁻¹ • v)) := by refine AddMonoidHomClass.isometry_of_norm _ fun x => (norm_smul _ _).trans ?_ rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel₀ hn, mul_one, LinearMap.id_apply] diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/Basic.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/Basic.lean index afb91c570543c..36b280ec89fdf 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/Basic.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/Basic.lean @@ -83,10 +83,8 @@ theorem volume_Ioo {a b : ℝ} : volume (Ioo a b) = ofReal (b - a) := by simp [v @[simp] theorem volume_Ioc {a b : ℝ} : volume (Ioc a b) = ofReal (b - a) := by simp [volume_val] --- @[simp] -- Porting note (#10618): simp can prove this theorem volume_singleton {a : ℝ} : volume ({a} : Set ℝ) = 0 := by simp [volume_val] --- @[simp] -- Porting note (#10618): simp can prove this, after mathlib4#4628 theorem volume_univ : volume (univ : Set ℝ) = ∞ := ENNReal.eq_top_of_forall_nnreal_le fun r => calc diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean index 15ee5ceb0977a..e4968335130b1 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean @@ -80,7 +80,7 @@ itself, it does not apply when `f` is more complicated -/ theorem integral_comp_neg_Iic {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] (c : ℝ) (f : ℝ → E) : (∫ x in Iic c, f (-x)) = ∫ x in Ioi (-c), f x := by have A : MeasurableEmbedding fun x : ℝ => -x := - (Homeomorph.neg ℝ).closedEmbedding.measurableEmbedding + (Homeomorph.neg ℝ).isClosedEmbedding.measurableEmbedding have := MeasurableEmbedding.setIntegral_map (μ := volume) A f (Ici (-c)) rw [Measure.map_neg_eq_self (volume : Measure ℝ)] at this simp_rw [← integral_Ici_eq_integral_Ioi, this, neg_preimage, preimage_neg_Ici, neg_neg] @@ -95,7 +95,7 @@ theorem integral_comp_neg_Ioi {E : Type*} [NormedAddCommGroup E] [NormedSpace theorem integral_comp_abs {f : ℝ → ℝ} : ∫ x, f |x| = 2 * ∫ x in Ioi (0 : ℝ), f x := by have eq : ∫ (x : ℝ) in Ioi 0, f |x| = ∫ (x : ℝ) in Ioi 0, f x := by - refine setIntegral_congr measurableSet_Ioi (fun _ hx => ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun _ hx => ?_) rw [abs_eq_self.mpr (le_of_lt (by exact hx))] by_cases hf : IntegrableOn (fun x => f |x|) (Ioi 0) · have int_Iic : IntegrableOn (fun x ↦ f |x|) (Iic 0) := by @@ -106,13 +106,13 @@ theorem integral_comp_abs {f : ℝ → ℝ} : exact integrableOn_Ici_iff_integrableOn_Ioi.mpr hf calc _ = (∫ x in Iic 0, f |x|) + ∫ x in Ioi 0, f |x| := by - rw [← integral_union (Iic_disjoint_Ioi le_rfl) measurableSet_Ioi int_Iic hf, + rw [← setIntegral_union (Iic_disjoint_Ioi le_rfl) measurableSet_Ioi int_Iic hf, Iic_union_Ioi, restrict_univ] _ = 2 * ∫ x in Ioi 0, f x := by rw [two_mul, eq] congr! 1 rw [← neg_zero, ← integral_comp_neg_Iic, neg_zero] - refine setIntegral_congr measurableSet_Iic (fun _ hx => ?_) + refine setIntegral_congr_fun measurableSet_Iic (fun _ hx => ?_) rw [abs_eq_neg_self.mpr (by exact hx)] · have : ¬ Integrable (fun x => f |x|) := by contrapose! hf diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean index 73abc051da088..8cde3b7093566 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean @@ -48,10 +48,10 @@ theorem MeasureTheory.measure_unitBall_eq_integral_div_gamma {E : Type*} {p : μ (Metric.ball 0 1) = .ofReal ((∫ (x : E), Real.exp (- ‖x‖ ^ p) ∂μ) / Real.Gamma (finrank ℝ E / p + 1)) := by obtain hE | hE := subsingleton_or_nontrivial E - · rw [(Metric.nonempty_ball.mpr zero_lt_one).eq_zero, ← integral_univ, Set.univ_nonempty.eq_zero, - integral_singleton, finrank_zero_of_subsingleton, Nat.cast_zero, zero_div, zero_add, - Real.Gamma_one, div_one, norm_zero, Real.zero_rpow (ne_of_gt hp), neg_zero, Real.exp_zero, - smul_eq_mul, mul_one, ofReal_toReal (measure_ne_top μ {0})] + · rw [(Metric.nonempty_ball.mpr zero_lt_one).eq_zero, ← setIntegral_univ, + Set.univ_nonempty.eq_zero, integral_singleton, finrank_zero_of_subsingleton, Nat.cast_zero, + zero_div, zero_add, Real.Gamma_one, div_one, norm_zero, Real.zero_rpow hp.ne', neg_zero, + Real.exp_zero, smul_eq_mul, mul_one, ofReal_toReal (measure_ne_top μ {0})] · have : (0 : ℝ) < finrank ℝ E := Nat.cast_pos.mpr finrank_pos have : ((∫ y in Set.Ioi (0 : ℝ), y ^ (finrank ℝ E - 1) • Real.exp (-y ^ p)) / Real.Gamma ((finrank ℝ E) / p + 1)) * (finrank ℝ E) = 1 := by @@ -112,7 +112,7 @@ theorem MeasureTheory.measure_lt_one_eq_integral_div_gamma {p : ℝ} (hp : 0 < p -- The map `ψ` is measure preserving by construction have : @MeasurePreserving E F mE _ ψ μ ν := @Measurable.measurePreserving E F mE _ ψ (@MeasurableEquiv.measurable E F mE _ ψ) _ - erw [← this.integral_comp'] + rw [← this.integral_comp'] rfl theorem MeasureTheory.measure_le_eq_lt [Nontrivial E] (r : ℝ) : diff --git a/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean b/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean index fd684e18cafc6..02ed4b6805a38 100644 --- a/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean +++ b/Mathlib/MeasureTheory/Measure/LevyProkhorovMetric.lean @@ -43,7 +43,7 @@ section Levy_Prokhorov /-! ### Lévy-Prokhorov metric -/ -variable {ι : Type*} {Ω : Type*} [MeasurableSpace Ω] [PseudoEMetricSpace Ω] +variable {Ω : Type*} [MeasurableSpace Ω] [PseudoEMetricSpace Ω] /-- The Lévy-Prokhorov edistance between measures: `d(μ,ν) = inf {r ≥ 0 | ∀ B, μ B ≤ ν Bᵣ + r ∧ ν B ≤ μ Bᵣ + r}`. -/ @@ -213,9 +213,9 @@ space. The instance is recorded on the type synonym noncomputable instance levyProkhorovDist_pseudoMetricSpace_finiteMeasure : PseudoMetricSpace (LevyProkhorov (FiniteMeasure Ω)) where dist μ ν := levyProkhorovDist μ.toMeasure ν.toMeasure - dist_self μ := levyProkhorovDist_self _ - dist_comm μ ν := levyProkhorovDist_comm _ _ - dist_triangle μ ν κ := levyProkhorovDist_triangle _ _ _ + dist_self _ := levyProkhorovDist_self _ + dist_comm _ _ := levyProkhorovDist_comm _ _ + dist_triangle _ _ _ := levyProkhorovDist_triangle _ _ _ edist_dist μ ν := by simp [← ENNReal.ofReal_coe_nnreal] lemma measure_le_measure_closure_of_levyProkhorovEDist_eq_zero {μ ν : Measure Ω} @@ -258,9 +258,9 @@ furthermore assume that `Ω` is separable. -/ noncomputable instance levyProkhorovDist_pseudoMetricSpace_probabilityMeasure : PseudoMetricSpace (LevyProkhorov (ProbabilityMeasure Ω)) where dist μ ν := levyProkhorovDist μ.toMeasure ν.toMeasure - dist_self μ := levyProkhorovDist_self _ - dist_comm μ ν := levyProkhorovDist_comm _ _ - dist_triangle μ ν κ := levyProkhorovDist_triangle _ _ _ + dist_self _ := levyProkhorovDist_self _ + dist_comm _ _ := levyProkhorovDist_comm _ _ + dist_triangle _ _ _ := levyProkhorovDist_triangle _ _ _ edist_dist μ ν := by simp [← ENNReal.ofReal_coe_nnreal] lemma LevyProkhorov.dist_def (μ ν : LevyProkhorov (ProbabilityMeasure Ω)) : @@ -333,7 +333,7 @@ section Levy_Prokhorov_is_finer open BoundedContinuousFunction -variable {ι : Type*} {Ω : Type*} [MeasurableSpace Ω] +variable {Ω : Type*} [MeasurableSpace Ω] variable [PseudoMetricSpace Ω] [OpensMeasurableSpace Ω] @@ -497,7 +497,7 @@ section Levy_Prokhorov_metrizes_convergence_in_distribution open BoundedContinuousFunction TopologicalSpace -variable {ι : Type*} {Ω : Type*} [PseudoMetricSpace Ω] +variable {Ω : Type*} [PseudoMetricSpace Ω] variable [MeasurableSpace Ω] [OpensMeasurableSpace Ω] lemma ProbabilityMeasure.toMeasure_add_pos_gt_mem_nhds (P : ProbabilityMeasure Ω) @@ -675,14 +675,14 @@ instance (X : Type*) [TopologicalSpace X] [PseudoMetrizableSpace X] [SeparableSp [MeasurableSpace X] [OpensMeasurableSpace X] : PseudoMetrizableSpace (ProbabilityMeasure X) := letI : PseudoMetricSpace X := TopologicalSpace.pseudoMetrizableSpacePseudoMetric X - (homeomorph_probabilityMeasure_levyProkhorov (Ω := X)).inducing.pseudoMetrizableSpace + (homeomorph_probabilityMeasure_levyProkhorov (Ω := X)).isInducing.pseudoMetrizableSpace /-- The topology of convergence in distribution on a separable Borel space is metrizable. -/ instance instMetrizableSpaceProbabilityMeasure (X : Type*) [TopologicalSpace X] [PseudoMetrizableSpace X] [SeparableSpace X] [MeasurableSpace X] [BorelSpace X] : MetrizableSpace (ProbabilityMeasure X) := by letI : PseudoMetricSpace X := TopologicalSpace.pseudoMetrizableSpacePseudoMetric X - exact homeomorph_probabilityMeasure_levyProkhorov.embedding.metrizableSpace + exact homeomorph_probabilityMeasure_levyProkhorov.isEmbedding.metrizableSpace end Levy_Prokhorov_metrizes_convergence_in_distribution diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index b61c2e17ffc68..cb05efae203e2 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -171,7 +171,7 @@ theorem measure_biUnion_finset {s : Finset ι} {f : ι → Set α} (hd : Pairwis /-- The measure of an a.e. disjoint union (even uncountable) of null-measurable sets is at least the sum of the measures of the sets. -/ -theorem tsum_meas_le_meas_iUnion_of_disjoint₀ {ι : Type*} [MeasurableSpace α] (μ : Measure α) +theorem tsum_meas_le_meas_iUnion_of_disjoint₀ {ι : Type*} {_ : MeasurableSpace α} (μ : Measure α) {As : ι → Set α} (As_mble : ∀ i : ι, NullMeasurableSet (As i) μ) (As_disj : Pairwise (AEDisjoint μ on As)) : (∑' i, μ (As i)) ≤ μ (⋃ i, As i) := by rw [ENNReal.tsum_eq_iSup_sum, iSup_le_iff] @@ -182,7 +182,7 @@ theorem tsum_meas_le_meas_iUnion_of_disjoint₀ {ι : Type*} [MeasurableSpace α /-- The measure of a disjoint union (even uncountable) of measurable sets is at least the sum of the measures of the sets. -/ -theorem tsum_meas_le_meas_iUnion_of_disjoint {ι : Type*} [MeasurableSpace α] (μ : Measure α) +theorem tsum_meas_le_meas_iUnion_of_disjoint {ι : Type*} {_ : MeasurableSpace α} (μ : Measure α) {As : ι → Set α} (As_mble : ∀ i : ι, MeasurableSet (As i)) (As_disj : Pairwise (Disjoint on As)) : (∑' i, μ (As i)) ≤ μ (⋃ i, As i) := tsum_meas_le_meas_iUnion_of_disjoint₀ μ (fun i ↦ (As_mble i).nullMeasurableSet) @@ -518,7 +518,7 @@ theorem measure_iInter_eq_iInf [Countable ι] {s : ι → Set α} (h : ∀ i, Nu /-- Continuity from above: the measure of the intersection of a sequence of measurable sets is the infimum of the measures of the partial intersections. -/ -theorem measure_iInter_eq_iInf' {α ι : Type*} [MeasurableSpace α] {μ : Measure α} +theorem measure_iInter_eq_iInf' {α ι : Type*} {_ : MeasurableSpace α} {μ : Measure α} [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)] {f : ι → Set α} (h : ∀ i, NullMeasurableSet (f i) μ) (hfin : ∃ i, μ (f i) ≠ ∞) : μ (⋂ i, f i) = ⨅ i, μ (⋂ j ≤ i, f j) := by @@ -543,25 +543,27 @@ theorem measure_iInter_eq_iInf' {α ι : Type*} [MeasurableSpace α] {μ : Measu /-- Continuity from below: the measure of the union of an increasing sequence of (not necessarily measurable) sets is the limit of the measures. -/ -theorem tendsto_measure_iUnion_atTop [Preorder ι] [IsDirected ι (· ≤ ·)] - [IsCountablyGenerated (atTop : Filter ι)] {s : ι → Set α} (hm : Monotone s) : - Tendsto (μ ∘ s) atTop (𝓝 (μ (⋃ n, s n))) := by +theorem tendsto_measure_iUnion_atTop [Preorder ι] [IsCountablyGenerated (atTop : Filter ι)] + {s : ι → Set α} (hm : Monotone s) : Tendsto (μ ∘ s) atTop (𝓝 (μ (⋃ n, s n))) := by + refine .of_neBot_imp fun h ↦ ?_ + have := (atTop_neBot_iff.1 h).2 rw [hm.measure_iUnion] exact tendsto_atTop_iSup fun n m hnm => measure_mono <| hm hnm @[deprecated (since := "2024-09-01")] alias tendsto_measure_iUnion := tendsto_measure_iUnion_atTop -theorem tendsto_measure_iUnion_atBot [Preorder ι] [IsDirected ι (· ≥ ·)] - [IsCountablyGenerated (atBot : Filter ι)] {s : ι → Set α} (hm : Antitone s) : - Tendsto (μ ∘ s) atBot (𝓝 (μ (⋃ n, s n))) := +theorem tendsto_measure_iUnion_atBot [Preorder ι] [IsCountablyGenerated (atBot : Filter ι)] + {s : ι → Set α} (hm : Antitone s) : Tendsto (μ ∘ s) atBot (𝓝 (μ (⋃ n, s n))) := tendsto_measure_iUnion_atTop (ι := ιᵒᵈ) hm.dual_left /-- Continuity from below: the measure of the union of a sequence of (not necessarily measurable) sets is the limit of the measures of the partial unions. -/ theorem tendsto_measure_iUnion_accumulate {α ι : Type*} - [Preorder ι] [IsDirected ι (· ≤ ·)] [IsCountablyGenerated (atTop : Filter ι)] - [MeasurableSpace α] {μ : Measure α} {f : ι → Set α} : + [Preorder ι] [IsCountablyGenerated (atTop : Filter ι)] + {_ : MeasurableSpace α} {μ : Measure α} {f : ι → Set α} : Tendsto (fun i ↦ μ (Accumulate f i)) atTop (𝓝 (μ (⋃ i, f i))) := by + refine .of_neBot_imp fun h ↦ ?_ + have := (atTop_neBot_iff.1 h).2 rw [measure_iUnion_eq_iSup_accumulate] exact tendsto_atTop_iSup fun i j hij ↦ by gcongr @@ -570,15 +572,17 @@ alias tendsto_measure_iUnion' := tendsto_measure_iUnion_accumulate /-- Continuity from above: the measure of the intersection of a decreasing sequence of measurable sets is the limit of the measures. -/ -theorem tendsto_measure_iInter [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)] {s : ι → Set α} +theorem tendsto_measure_iInter [Countable ι] [Preorder ι] {s : ι → Set α} (hs : ∀ n, NullMeasurableSet (s n) μ) (hm : Antitone s) (hf : ∃ i, μ (s i) ≠ ∞) : Tendsto (μ ∘ s) atTop (𝓝 (μ (⋂ n, s n))) := by + refine .of_neBot_imp fun h ↦ ?_ + have := (atTop_neBot_iff.1 h).2 rw [measure_iInter_eq_iInf hs hm.directed_ge hf] exact tendsto_atTop_iInf fun n m hnm => measure_mono <| hm hnm /-- Continuity from above: the measure of the intersection of a sequence of measurable sets such that one has finite measure is the limit of the measures of the partial intersections. -/ -theorem tendsto_measure_iInter' {α ι : Type*} [MeasurableSpace α] {μ : Measure α} [Countable ι] +theorem tendsto_measure_iInter' {α ι : Type*} {_ : MeasurableSpace α} {μ : Measure α} [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)] {f : ι → Set α} (hm : ∀ i, NullMeasurableSet (f i) μ) (hf : ∃ i, μ (f i) ≠ ∞) : Tendsto (fun i ↦ μ (⋂ j ∈ {j | j ≤ i}, f j)) atTop (𝓝 (μ (⋂ i, f i))) := by @@ -711,7 +715,7 @@ theorem measure_toMeasurable_inter {s t : Set α} (hs : MeasurableSet s) (ht : /-! ### The `ℝ≥0∞`-module of measures -/ -instance instZero [MeasurableSpace α] : Zero (Measure α) := +instance instZero {_ : MeasurableSpace α} : Zero (Measure α) := ⟨{ toOuterMeasure := 0 m_iUnion := fun _f _hf _hd => tsum_zero.symm trim_le := OuterMeasure.trim_zero.le }⟩ @@ -741,10 +745,10 @@ instance instSubsingleton [IsEmpty α] {m : MeasurableSpace α} : Subsingleton ( theorem eq_zero_of_isEmpty [IsEmpty α] {_m : MeasurableSpace α} (μ : Measure α) : μ = 0 := Subsingleton.elim μ 0 -instance instInhabited [MeasurableSpace α] : Inhabited (Measure α) := +instance instInhabited {_ : MeasurableSpace α} : Inhabited (Measure α) := ⟨0⟩ -instance instAdd [MeasurableSpace α] : Add (Measure α) := +instance instAdd {_ : MeasurableSpace α} : Add (Measure α) := ⟨fun μ₁ μ₂ => { toOuterMeasure := μ₁.toOuterMeasure + μ₂.toOuterMeasure m_iUnion := fun s hs hd => @@ -770,7 +774,7 @@ section SMul variable [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] variable [SMul R' ℝ≥0∞] [IsScalarTower R' ℝ≥0∞ ℝ≥0∞] -instance instSMul [MeasurableSpace α] : SMul R (Measure α) := +instance instSMul {_ : MeasurableSpace α} : SMul R (Measure α) := ⟨fun c μ => { toOuterMeasure := c • μ.toOuterMeasure m_iUnion := fun s hs hd => by @@ -792,15 +796,15 @@ theorem smul_apply {_m : MeasurableSpace α} (c : R) (μ : Measure α) (s : Set (c • μ) s = c • μ s := rfl -instance instSMulCommClass [SMulCommClass R R' ℝ≥0∞] [MeasurableSpace α] : +instance instSMulCommClass [SMulCommClass R R' ℝ≥0∞] {_ : MeasurableSpace α} : SMulCommClass R R' (Measure α) := ⟨fun _ _ _ => ext fun _ _ => smul_comm _ _ _⟩ -instance instIsScalarTower [SMul R R'] [IsScalarTower R R' ℝ≥0∞] [MeasurableSpace α] : +instance instIsScalarTower [SMul R R'] [IsScalarTower R R' ℝ≥0∞] {_ : MeasurableSpace α} : IsScalarTower R R' (Measure α) := ⟨fun _ _ _ => ext fun _ _ => smul_assoc _ _ _⟩ -instance instIsCentralScalar [SMul Rᵐᵒᵖ ℝ≥0∞] [IsCentralScalar R ℝ≥0∞] [MeasurableSpace α] : +instance instIsCentralScalar [SMul Rᵐᵒᵖ ℝ≥0∞] [IsCentralScalar R ℝ≥0∞] {_ : MeasurableSpace α} : IsCentralScalar R (Measure α) := ⟨fun _ _ => ext fun _ _ => op_smul_eq_smul _ _⟩ @@ -811,10 +815,10 @@ instance instNoZeroSMulDivisors [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTo eq_zero_or_eq_zero_of_smul_eq_zero h := by simpa [Ne, ext_iff', forall_or_left] using h instance instMulAction [Monoid R] [MulAction R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] - [MeasurableSpace α] : MulAction R (Measure α) := + {_ : MeasurableSpace α} : MulAction R (Measure α) := Injective.mulAction _ toOuterMeasure_injective smul_toOuterMeasure -instance instAddCommMonoid [MeasurableSpace α] : AddCommMonoid (Measure α) := +instance instAddCommMonoid {_ : MeasurableSpace α} : AddCommMonoid (Measure α) := toOuterMeasure_injective.addCommMonoid toOuterMeasure zero_toOuterMeasure add_toOuterMeasure fun _ _ => smul_toOuterMeasure _ _ @@ -832,12 +836,12 @@ theorem finset_sum_apply {m : MeasurableSpace α} (I : Finset ι) (μ : ι → M (∑ i ∈ I, μ i) s = ∑ i ∈ I, μ i s := by rw [coe_finset_sum, Finset.sum_apply] instance instDistribMulAction [Monoid R] [DistribMulAction R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] - [MeasurableSpace α] : DistribMulAction R (Measure α) := + {_ : MeasurableSpace α} : DistribMulAction R (Measure α) := Injective.distribMulAction ⟨⟨toOuterMeasure, zero_toOuterMeasure⟩, add_toOuterMeasure⟩ toOuterMeasure_injective smul_toOuterMeasure -instance instModule [Semiring R] [Module R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] [MeasurableSpace α] : - Module R (Measure α) := +instance instModule [Semiring R] [Module R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] + {_ : MeasurableSpace α} : Module R (Measure α) := Injective.module R ⟨⟨toOuterMeasure, zero_toOuterMeasure⟩, add_toOuterMeasure⟩ toOuterMeasure_injective smul_toOuterMeasure @@ -898,11 +902,11 @@ theorem measure_toMeasurable_add_inter_right {s t : Set α} (hs : MeasurableSet /-- Measures are partially ordered. -/ -instance instPartialOrder [MeasurableSpace α] : PartialOrder (Measure α) where +instance instPartialOrder {_ : MeasurableSpace α} : PartialOrder (Measure α) where le m₁ m₂ := ∀ s, m₁ s ≤ m₂ s - le_refl m s := le_rfl - le_trans m₁ m₂ m₃ h₁ h₂ s := le_trans (h₁ s) (h₂ s) - le_antisymm m₁ m₂ h₁ h₂ := ext fun s _ => le_antisymm (h₁ s) (h₂ s) + le_refl _ _ := le_rfl + le_trans _ _ _ h₁ h₂ s := le_trans (h₁ s) (h₂ s) + le_antisymm _ _ h₁ h₂ := ext fun s _ => le_antisymm (h₁ s) (h₂ s) theorem toOuterMeasure_le : μ₁.toOuterMeasure ≤ μ₂.toOuterMeasure ↔ μ₁ ≤ μ₂ := .rfl @@ -920,8 +924,7 @@ theorem lt_iff : μ < ν ↔ μ ≤ ν ∧ ∃ s, MeasurableSet s ∧ μ s < ν theorem lt_iff' : μ < ν ↔ μ ≤ ν ∧ ∃ s, μ s < ν s := lt_iff_le_not_le.trans <| and_congr Iff.rfl <| by simp only [le_iff', not_forall, not_le] -instance covariantAddLE [MeasurableSpace α] : - CovariantClass (Measure α) (Measure α) (· + ·) (· ≤ ·) := +instance instAddLeftMono {_ : MeasurableSpace α} : AddLeftMono (Measure α) := ⟨fun _ν _μ₁ _μ₂ hμ s => add_le_add_left (hμ s) _⟩ protected theorem le_add_left (h : μ ≤ ν) : μ ≤ ν' + ν := fun s => le_add_left (h s) @@ -946,7 +949,7 @@ theorem sInf_caratheodory (s : Set α) (hs : MeasurableSet s) : rw [← measure_inter_add_diff u hs] exact add_le_add (hm <| inter_subset_inter_left _ htu) (hm <| diff_subset_diff_left htu) -instance [MeasurableSpace α] : InfSet (Measure α) := +instance {_ : MeasurableSpace α} : InfSet (Measure α) := ⟨fun m => (sInf (toOuterMeasure '' m)).toMeasure <| sInf_caratheodory⟩ theorem sInf_apply (hs : MeasurableSet s) : sInf m s = sInf (toOuterMeasure '' m) s := @@ -958,16 +961,16 @@ private theorem measure_sInf_le (h : μ ∈ m) : sInf m ≤ μ := private theorem measure_le_sInf (h : ∀ μ' ∈ m, μ ≤ μ') : μ ≤ sInf m := have : μ.toOuterMeasure ≤ sInf (toOuterMeasure '' m) := - le_sInf <| forall_mem_image.2 fun μ hμ ↦ toOuterMeasure_le.2 <| h _ hμ + le_sInf <| forall_mem_image.2 fun _ hμ ↦ toOuterMeasure_le.2 <| h _ hμ le_iff.2 fun s hs => by rw [sInf_apply hs]; exact this s -instance instCompleteSemilatticeInf [MeasurableSpace α] : CompleteSemilatticeInf (Measure α) := +instance instCompleteSemilatticeInf {_ : MeasurableSpace α} : CompleteSemilatticeInf (Measure α) := { (by infer_instance : PartialOrder (Measure α)), (by infer_instance : InfSet (Measure α)) with sInf_le := fun _s _a => measure_sInf_le le_sInf := fun _s _a => measure_le_sInf } -instance instCompleteLattice [MeasurableSpace α] : CompleteLattice (Measure α) := +instance instCompleteLattice {_ : MeasurableSpace α} : CompleteLattice (Measure α) := { completeLatticeOfCompleteSemilatticeInf (Measure α) with top := { toOuterMeasure := ⊤, @@ -980,7 +983,7 @@ instance instCompleteLattice [MeasurableSpace α] : CompleteLattice (Measure α) else simp_all [Set.not_nonempty_iff_eq_empty] trim_le := le_top }, - le_top := fun μ => toOuterMeasure_le.mp le_top + le_top := fun _ => toOuterMeasure_le.mp le_top bot := 0 bot_le := fun _a _s => bot_le } @@ -993,7 +996,7 @@ theorem _root_.MeasureTheory.OuterMeasure.toMeasure_top : toOuterMeasure_toMeasure (μ := ⊤) @[simp] -theorem toOuterMeasure_top [MeasurableSpace α] : +theorem toOuterMeasure_top {_ : MeasurableSpace α} : (⊤ : Measure α).toOuterMeasure = (⊤ : OuterMeasure α) := rfl @@ -1025,6 +1028,10 @@ instance [NeZero μ] : NeZero (μ univ) := ⟨measure_univ_ne_zero.2 <| NeZero.n theorem measure_univ_pos : 0 < μ univ ↔ μ ≠ 0 := pos_iff_ne_zero.trans measure_univ_ne_zero +lemma nonempty_of_neZero (μ : Measure α) [NeZero μ] : Nonempty α := + (isEmpty_or_nonempty α).resolve_left fun h ↦ by + simpa [eq_empty_of_isEmpty] using NeZero.ne (μ univ) + /-! ### Pushforward and pullback -/ @@ -1227,7 +1234,7 @@ def comapₗ [MeasurableSpace α] (f : α → β) : Measure β →ₗ[ℝ≥0∞ exact hf.2 s hs else 0 -theorem comapₗ_apply {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : α → β) +theorem comapₗ_apply {β} {_ : MeasurableSpace α} {mβ : MeasurableSpace β} (f : α → β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → MeasurableSet (f '' s)) (μ : Measure β) (hs : MeasurableSet s) : comapₗ f μ s = μ (f '' s) := by rw [comapₗ, dif_pos, liftLinear_apply _ hs, OuterMeasure.comap_apply, coe_toOuterMeasure] @@ -1245,35 +1252,35 @@ def comap [MeasurableSpace α] (f : α → β) (μ : Measure β) : Measure α := exact (measure_inter_add_diff₀ _ (hf.2 s hs)).symm else 0 -theorem comap_apply₀ [MeasurableSpace α] (f : α → β) (μ : Measure β) (hfi : Injective f) +theorem comap_apply₀ {_ : MeasurableSpace α} (f : α → β) (μ : Measure β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) (hs : NullMeasurableSet s (comap f μ)) : comap f μ s = μ (f '' s) := by rw [comap, dif_pos (And.intro hfi hf)] at hs ⊢ rw [toMeasure_apply₀ _ _ hs, OuterMeasure.comap_apply, coe_toOuterMeasure] -theorem le_comap_apply {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : α → β) (μ : Measure β) - (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) (s : Set α) : - μ (f '' s) ≤ comap f μ s := by +theorem le_comap_apply {β} {_ : MeasurableSpace α} {mβ : MeasurableSpace β} (f : α → β) + (μ : Measure β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) + (s : Set α) : μ (f '' s) ≤ comap f μ s := by rw [comap, dif_pos (And.intro hfi hf)] exact le_toMeasure_apply _ _ _ -theorem comap_apply {β} [MeasurableSpace α] {_mβ : MeasurableSpace β} (f : α → β) +theorem comap_apply {β} {_ : MeasurableSpace α} {_mβ : MeasurableSpace β} (f : α → β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → MeasurableSet (f '' s)) (μ : Measure β) (hs : MeasurableSet s) : comap f μ s = μ (f '' s) := comap_apply₀ f μ hfi (fun s hs => (hf s hs).nullMeasurableSet) hs.nullMeasurableSet -theorem comapₗ_eq_comap {β} [MeasurableSpace α] {_mβ : MeasurableSpace β} (f : α → β) +theorem comapₗ_eq_comap {β} {_ : MeasurableSpace α} {_mβ : MeasurableSpace β} (f : α → β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → MeasurableSet (f '' s)) (μ : Measure β) (hs : MeasurableSet s) : comapₗ f μ s = comap f μ s := (comapₗ_apply f hfi hf μ hs).trans (comap_apply f hfi hf μ hs).symm -theorem measure_image_eq_zero_of_comap_eq_zero {β} [MeasurableSpace α] {_mβ : MeasurableSpace β} +theorem measure_image_eq_zero_of_comap_eq_zero {β} {_ : MeasurableSpace α} {_mβ : MeasurableSpace β} (f : α → β) (μ : Measure β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) {s : Set α} (hs : comap f μ s = 0) : μ (f '' s) = 0 := le_antisymm ((le_comap_apply f μ hfi hf s).trans hs.le) (zero_le _) -theorem ae_eq_image_of_ae_eq_comap {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : α → β) +theorem ae_eq_image_of_ae_eq_comap {β} {_ : MeasurableSpace α} {mβ : MeasurableSpace β} (f : α → β) (μ : Measure β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) {s t : Set α} (hst : s =ᵐ[comap f μ] t) : f '' s =ᵐ[μ] f '' t := by rw [EventuallyEq, ae_iff] at hst ⊢ @@ -1290,7 +1297,7 @@ theorem ae_eq_image_of_ae_eq_comap {β} [MeasurableSpace α] {mβ : MeasurableSp rw [h_eq_α] at hst exact measure_image_eq_zero_of_comap_eq_zero f μ hfi hf hst -theorem NullMeasurableSet.image {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : α → β) +theorem NullMeasurableSet.image {β} {_ : MeasurableSpace α} {mβ : MeasurableSpace β} (f : α → β) (μ : Measure β) (hfi : Injective f) (hf : ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ) {s : Set α} (hs : NullMeasurableSet s (μ.comap f)) : NullMeasurableSet (f '' s) μ := by refine ⟨toMeasurable μ (f '' toMeasurable (μ.comap f) s), measurableSet_toMeasurable _ _, ?_⟩ @@ -1301,8 +1308,8 @@ theorem NullMeasurableSet.image {β} [MeasurableSpace α] {mβ : MeasurableSpace NullMeasurableSet.toMeasurable_ae_eq hs exact ae_eq_image_of_ae_eq_comap f μ hfi hf h.symm -theorem comap_preimage {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : α → β) (μ : Measure β) - {s : Set β} (hf : Injective f) (hf' : Measurable f) +theorem comap_preimage {β} {_ : MeasurableSpace α} {mβ : MeasurableSpace β} (f : α → β) + (μ : Measure β) {s : Set β} (hf : Injective f) (hf' : Measurable f) (h : ∀ t, MeasurableSet t → NullMeasurableSet (f '' t) μ) (hs : MeasurableSet s) : μ.comap f (f ⁻¹' s) = μ (s ∩ range f) := by rw [comap_apply₀ _ _ hf h (hf' hs).nullMeasurableSet, image_preimage_eq_inter_range] @@ -1475,11 +1482,11 @@ protected theorem refl {_m0 : MeasurableSpace α} (μ : Measure α) : μ ≪ μ protected theorem rfl : μ ≪ μ := fun _s hs => hs -instance instIsRefl [MeasurableSpace α] : IsRefl (Measure α) (· ≪ ·) := +instance instIsRefl {_ : MeasurableSpace α} : IsRefl (Measure α) (· ≪ ·) := ⟨fun _ => AbsolutelyContinuous.rfl⟩ @[simp] -protected lemma zero (μ : Measure α) : 0 ≪ μ := fun s _ ↦ by simp +protected lemma zero (μ : Measure α) : 0 ≪ μ := fun _ _ ↦ by simp @[trans] protected theorem trans (h1 : μ₁ ≪ μ₂) (h2 : μ₂ ≪ μ₃) : μ₁ ≪ μ₃ := fun _s hs => h1 <| h2 hs @@ -1545,7 +1552,7 @@ lemma absolutelyContinuous_smul {c : ℝ≥0∞} (hc : c ≠ 0) : μ ≪ c • theorem ae_le_iff_absolutelyContinuous : ae μ ≤ ae ν ↔ μ ≪ ν := ⟨fun h s => by rw [measure_zero_iff_ae_nmem, measure_zero_iff_ae_nmem] - exact fun hs => h hs, fun h s hs => h hs⟩ + exact fun hs => h hs, fun h _ hs => h hs⟩ alias ⟨_root_.LE.le.absolutelyContinuous_of_ae, AbsolutelyContinuous.ae_le⟩ := ae_le_iff_absolutelyContinuous @@ -1698,7 +1705,7 @@ theorem exists_preimage_eq_of_preimage_ae {f : α → α} (h : QuasiMeasurePrese open Pointwise @[to_additive] -theorem smul_ae_eq_of_ae_eq {G α : Type*} [Group G] [MulAction G α] [MeasurableSpace α] +theorem smul_ae_eq_of_ae_eq {G α : Type*} [Group G] [MulAction G α] {_ : MeasurableSpace α} {s t : Set α} {μ : Measure α} (g : G) (h_qmp : QuasiMeasurePreserving (g⁻¹ • · : α → α) μ μ) (h_ae_eq : s =ᵐ[μ] t) : (g • s : Set α) =ᵐ[μ] (g • t : Set α) := by @@ -1712,7 +1719,7 @@ open Pointwise @[to_additive] theorem pairwise_aedisjoint_of_aedisjoint_forall_ne_one {G α : Type*} [Group G] [MulAction G α] - [MeasurableSpace α] {μ : Measure α} {s : Set α} + {_ : MeasurableSpace α} {μ : Measure α} {s : Set α} (h_ae_disjoint : ∀ g ≠ (1 : G), AEDisjoint μ (g • s) s) (h_qmp : ∀ g : G, QuasiMeasurePreserving (g • ·) μ μ) : Pairwise (AEDisjoint μ on fun g : G => g • s) := by @@ -1733,7 +1740,7 @@ end Pointwise /-- The filter of sets `s` such that `sᶜ` has finite measure. -/ def cofinite {m0 : MeasurableSpace α} (μ : Measure α) : Filter α := - comk (μ · < ∞) (by simp) (fun t ht s hs ↦ (measure_mono hs).trans_lt ht) fun s hs t ht ↦ + comk (μ · < ∞) (by simp) (fun _ ht _ hs ↦ (measure_mono hs).trans_lt ht) fun s hs t ht ↦ (measure_union_le s t).trans_lt <| ENNReal.add_lt_top.2 ⟨hs, ht⟩ theorem mem_cofinite : s ∈ μ.cofinite ↔ μ sᶜ < ∞ := @@ -1830,27 +1837,25 @@ theorem biSup_measure_Iic [Preorder α] {s : Set α} (hsc : s.Countable) exact iUnion₂_eq_univ_iff.2 hst · exact directedOn_iff_directed.2 (hdir.directed_val.mono_comp _ fun x y => Iic_subset_Iic.2) -theorem tendsto_measure_Ico_atTop [Preorder α] [IsDirected α (· ≤ ·)] [NoMaxOrder α] +theorem tendsto_measure_Ico_atTop [Preorder α] [NoMaxOrder α] [(atTop : Filter α).IsCountablyGenerated] (μ : Measure α) (a : α) : Tendsto (fun x => μ (Ico a x)) atTop (𝓝 (μ (Ici a))) := by rw [← iUnion_Ico_right] exact tendsto_measure_iUnion_atTop (antitone_const.Ico monotone_id) -theorem tendsto_measure_Ioc_atBot [Preorder α] [IsDirected α (· ≥ ·)] [NoMinOrder α] +theorem tendsto_measure_Ioc_atBot [Preorder α] [NoMinOrder α] [(atBot : Filter α).IsCountablyGenerated] (μ : Measure α) (a : α) : Tendsto (fun x => μ (Ioc x a)) atBot (𝓝 (μ (Iic a))) := by rw [← iUnion_Ioc_left] exact tendsto_measure_iUnion_atBot (monotone_id.Ioc antitone_const) -theorem tendsto_measure_Iic_atTop [Preorder α] [IsDirected α (· ≤ ·)] - [(atTop : Filter α).IsCountablyGenerated] (μ : Measure α) : - Tendsto (fun x => μ (Iic x)) atTop (𝓝 (μ univ)) := by +theorem tendsto_measure_Iic_atTop [Preorder α] [(atTop : Filter α).IsCountablyGenerated] + (μ : Measure α) : Tendsto (fun x => μ (Iic x)) atTop (𝓝 (μ univ)) := by rw [← iUnion_Iic] exact tendsto_measure_iUnion_atTop monotone_Iic -theorem tendsto_measure_Ici_atBot [Preorder α] [IsDirected α (· ≥ ·)] - [(atBot : Filter α).IsCountablyGenerated] (μ : Measure α) : - Tendsto (fun x => μ (Ici x)) atBot (𝓝 (μ univ)) := +theorem tendsto_measure_Ici_atBot [Preorder α] [(atBot : Filter α).IsCountablyGenerated] + (μ : Measure α) : Tendsto (fun x => μ (Ici x)) atBot (𝓝 (μ univ)) := tendsto_measure_Iic_atTop (α := αᵒᵈ) μ variable [PartialOrder α] {a b : α} @@ -1928,7 +1933,7 @@ namespace MeasurableEquiv open Equiv MeasureTheory.Measure -variable [MeasurableSpace α] [MeasurableSpace β] {μ : Measure α} {ν : Measure β} +variable {_ : MeasurableSpace α} [MeasurableSpace β] {μ : Measure α} {ν : Measure β} /-- If we map a measure along a measurable equivalence, we can compute the measure on all sets (not just the measurable ones). -/ @@ -1969,6 +1974,13 @@ theorem quasiMeasurePreserving_symm (μ : Measure α) (e : α ≃ᵐ β) : end MeasurableEquiv +namespace MeasureTheory.Measure +variable {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + +lemma comap_swap (μ : Measure (α × β)) : μ.comap Prod.swap = μ.map Prod.swap := + (MeasurableEquiv.prodComm ..).comap_symm + +end MeasureTheory.Measure end set_option linter.style.longFile 2000 diff --git a/Mathlib/MeasureTheory/Measure/NullMeasurable.lean b/Mathlib/MeasureTheory/Measure/NullMeasurable.lean index 09e4f3a49eccb..a3090e8782b25 100644 --- a/Mathlib/MeasureTheory/Measure/NullMeasurable.lean +++ b/Mathlib/MeasureTheory/Measure/NullMeasurable.lean @@ -92,11 +92,9 @@ def NullMeasurableSet [MeasurableSpace α] (s : Set α) theorem _root_.MeasurableSet.nullMeasurableSet (h : MeasurableSet s) : NullMeasurableSet s μ := h.eventuallyMeasurableSet --- @[simp] -- Porting note (#10618): simp can prove this theorem nullMeasurableSet_empty : NullMeasurableSet ∅ μ := MeasurableSet.empty --- @[simp] -- Porting note (#10618): simp can prove this theorem nullMeasurableSet_univ : NullMeasurableSet univ μ := MeasurableSet.univ @@ -173,7 +171,6 @@ protected theorem disjointed {f : ℕ → Set α} (h : ∀ i, NullMeasurableSet NullMeasurableSet (disjointed f n) μ := MeasurableSet.disjointed h n --- @[simp] -- Porting note (#10618): simp can prove thisrove this protected theorem const (p : Prop) : NullMeasurableSet { _a : α | p } μ := MeasurableSet.const p @@ -280,6 +277,9 @@ theorem measure_union₀' (hs : NullMeasurableSet s μ) (hd : AEDisjoint μ s t) theorem measure_add_measure_compl₀ {s : Set α} (hs : NullMeasurableSet s μ) : μ s + μ sᶜ = μ univ := by rw [← measure_union₀' hs aedisjoint_compl_right, union_compl_self] +lemma measure_of_measure_compl_eq_zero (hs : μ sᶜ = 0) : μ s = μ Set.univ := by + simpa [hs] using measure_add_measure_compl₀ <| .of_compl <| .of_null hs + section MeasurableSingletonClass variable [MeasurableSingletonClass (NullMeasurableSpace α μ)] @@ -398,7 +398,7 @@ namespace Measure def completion {_ : MeasurableSpace α} (μ : Measure α) : MeasureTheory.Measure (NullMeasurableSpace α μ) where toOuterMeasure := μ.toOuterMeasure - m_iUnion s hs hd := measure_iUnion₀ (hd.mono fun i j h => h.aedisjoint) hs + m_iUnion _ hs hd := measure_iUnion₀ (hd.mono fun _ _ h => h.aedisjoint) hs trim_le := by nth_rewrite 2 [← μ.trimmed] exact OuterMeasure.trim_anti_measurableSpace _ fun _ ↦ MeasurableSet.nullMeasurableSet diff --git a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean index 465298ca8e9fc..5c3cd70ba7f90 100644 --- a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean @@ -252,16 +252,19 @@ theorem continuous_testAgainstNN_eval (f : Ω →ᵇ ℝ≥0) : (FiniteMeasure.continuous_testAgainstNN_eval f).comp toFiniteMeasure_continuous -- The canonical mapping from probability measures to finite measures is an embedding. -theorem toFiniteMeasure_embedding (Ω : Type*) [MeasurableSpace Ω] [TopologicalSpace Ω] +theorem toFiniteMeasure_isEmbedding (Ω : Type*) [MeasurableSpace Ω] [TopologicalSpace Ω] [OpensMeasurableSpace Ω] : - Embedding (toFiniteMeasure : ProbabilityMeasure Ω → FiniteMeasure Ω) := - { induced := rfl - inj := fun _μ _ν h ↦ Subtype.eq <| congr_arg FiniteMeasure.toMeasure h } + IsEmbedding (toFiniteMeasure : ProbabilityMeasure Ω → FiniteMeasure Ω) where + eq_induced := rfl + inj _μ _ν h := Subtype.eq <| congr_arg FiniteMeasure.toMeasure h + +@[deprecated (since := "2024-10-26")] +alias toFiniteMeasure_embedding := toFiniteMeasure_isEmbedding theorem tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds {δ : Type*} (F : Filter δ) {μs : δ → ProbabilityMeasure Ω} {μ₀ : ProbabilityMeasure Ω} : Tendsto μs F (𝓝 μ₀) ↔ Tendsto (toFiniteMeasure ∘ μs) F (𝓝 μ₀.toFiniteMeasure) := - Embedding.tendsto_nhds_iff (toFiniteMeasure_embedding Ω) + (toFiniteMeasure_isEmbedding Ω).tendsto_nhds_iff /-- A characterization of weak convergence of probability measures by the condition that the integrals of every continuous bounded nonnegative function converge to the integral of the function @@ -296,8 +299,7 @@ variable (Ω) /-- On topological spaces where indicators of closed sets have decreasing approximating sequences of continuous functions (`HasOuterApproxClosed`), the topology of convergence in distribution of Borel probability measures is Hausdorff (`T2Space`). -/ -instance t2Space : T2Space (ProbabilityMeasure Ω) := - Embedding.t2Space (toFiniteMeasure_embedding Ω) +instance t2Space : T2Space (ProbabilityMeasure Ω) := (toFiniteMeasure_isEmbedding Ω).t2Space end Hausdorff -- section diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean b/Mathlib/MeasureTheory/Measure/Prod.lean similarity index 84% rename from Mathlib/MeasureTheory/Constructions/Prod/Basic.lean rename to Mathlib/MeasureTheory/Measure/Prod.lean index a8e405fc234e1..72c1bde2e71bf 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean +++ b/Mathlib/MeasureTheory/Measure/Prod.lean @@ -3,9 +3,10 @@ Copyright (c) 2020 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.MeasureTheory.Measure.GiryMonad import Mathlib.Dynamics.Ergodic.MeasurePreserving import Mathlib.MeasureTheory.Integral.Lebesgue +import Mathlib.MeasureTheory.MeasurableSpace.Prod +import Mathlib.MeasureTheory.Measure.GiryMonad import Mathlib.MeasureTheory.Measure.OpenPos /-! @@ -60,82 +61,10 @@ open TopologicalSpace hiding generateFrom open Filter hiding prod_eq map -variable {α α' β β' γ E : Type*} - -/-- Rectangles formed by π-systems form a π-system. -/ -theorem IsPiSystem.prod {C : Set (Set α)} {D : Set (Set β)} (hC : IsPiSystem C) - (hD : IsPiSystem D) : IsPiSystem (image2 (· ×ˢ ·) C D) := by - rintro _ ⟨s₁, hs₁, t₁, ht₁, rfl⟩ _ ⟨s₂, hs₂, t₂, ht₂, rfl⟩ hst - rw [prod_inter_prod] at hst ⊢; rw [prod_nonempty_iff] at hst - exact mem_image2_of_mem (hC _ hs₁ _ hs₂ hst.1) (hD _ ht₁ _ ht₂ hst.2) +variable {α β γ : Type*} -/-- Rectangles of countably spanning sets are countably spanning. -/ -theorem IsCountablySpanning.prod {C : Set (Set α)} {D : Set (Set β)} (hC : IsCountablySpanning C) - (hD : IsCountablySpanning D) : IsCountablySpanning (image2 (· ×ˢ ·) C D) := by - rcases hC, hD with ⟨⟨s, h1s, h2s⟩, t, h1t, h2t⟩ - refine ⟨fun n => s n.unpair.1 ×ˢ t n.unpair.2, fun n => mem_image2_of_mem (h1s _) (h1t _), ?_⟩ - rw [iUnion_unpair_prod, h2s, h2t, univ_prod_univ] - -variable [MeasurableSpace α] [MeasurableSpace α'] [MeasurableSpace β] [MeasurableSpace β'] -variable [MeasurableSpace γ] +variable [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] variable {μ μ' : Measure α} {ν ν' : Measure β} {τ : Measure γ} -variable [NormedAddCommGroup E] - -/-! ### Measurability - -Before we define the product measure, we can talk about the measurability of operations on binary -functions. We show that if `f` is a binary measurable function, then the function that integrates -along one of the variables (using either the Lebesgue or Bochner integral) is measurable. --/ - -/-- The product of generated σ-algebras is the one generated by rectangles, if both generating sets - are countably spanning. -/ -theorem generateFrom_prod_eq {α β} {C : Set (Set α)} {D : Set (Set β)} (hC : IsCountablySpanning C) - (hD : IsCountablySpanning D) : - @Prod.instMeasurableSpace _ _ (generateFrom C) (generateFrom D) = - generateFrom (image2 (· ×ˢ ·) C D) := by - apply le_antisymm - · refine sup_le ?_ ?_ <;> rw [comap_generateFrom] <;> apply generateFrom_le <;> - rintro _ ⟨s, hs, rfl⟩ - · rcases hD with ⟨t, h1t, h2t⟩ - rw [← prod_univ, ← h2t, prod_iUnion] - apply MeasurableSet.iUnion - intro n - apply measurableSet_generateFrom - exact ⟨s, hs, t n, h1t n, rfl⟩ - · rcases hC with ⟨t, h1t, h2t⟩ - rw [← univ_prod, ← h2t, iUnion_prod_const] - apply MeasurableSet.iUnion - rintro n - apply measurableSet_generateFrom - exact mem_image2_of_mem (h1t n) hs - · apply generateFrom_le - rintro _ ⟨s, hs, t, ht, rfl⟩ - dsimp only - rw [prod_eq] - apply (measurable_fst _).inter (measurable_snd _) - · exact measurableSet_generateFrom hs - · exact measurableSet_generateFrom ht - -/-- If `C` and `D` generate the σ-algebras on `α` resp. `β`, then rectangles formed by `C` and `D` - generate the σ-algebra on `α × β`. -/ -theorem generateFrom_eq_prod {C : Set (Set α)} {D : Set (Set β)} (hC : generateFrom C = ‹_›) - (hD : generateFrom D = ‹_›) (h2C : IsCountablySpanning C) (h2D : IsCountablySpanning D) : - generateFrom (image2 (· ×ˢ ·) C D) = Prod.instMeasurableSpace := by - rw [← hC, ← hD, generateFrom_prod_eq h2C h2D] - -/-- The product σ-algebra is generated from boxes, i.e. `s ×ˢ t` for sets `s : Set α` and - `t : Set β`. -/ -theorem generateFrom_prod : - generateFrom (image2 (· ×ˢ ·) { s : Set α | MeasurableSet s } { t : Set β | MeasurableSet t }) = - Prod.instMeasurableSpace := - generateFrom_eq_prod generateFrom_measurableSet generateFrom_measurableSet - isCountablySpanning_measurableSet isCountablySpanning_measurableSet - -/-- Rectangles form a π-system. -/ -theorem isPiSystem_prod : - IsPiSystem (image2 (· ×ˢ ·) { s : Set α | MeasurableSet s } { t : Set β | MeasurableSet t }) := - isPiSystem_measurableSet.prod isPiSystem_measurableSet /-- If `ν` is a finite measure, and `s ⊆ α × β` is measurable, then `x ↦ ν { y | (x, y) ∈ s }` is a measurable function. `measurable_measure_prod_mk_left` is strictly more general. -/ @@ -163,7 +92,7 @@ theorem measurable_measure_prod_mk_left_finite [IsFiniteMeasure ν] {s : Set (α is a measurable function. -/ theorem measurable_measure_prod_mk_left [SFinite ν] {s : Set (α × β)} (hs : MeasurableSet s) : Measurable fun x => ν (Prod.mk x ⁻¹' s) := by - rw [← sum_sFiniteSeq ν] + rw [← sum_sfiniteSeq ν] simp_rw [Measure.sum_apply_of_countable] exact Measurable.ennreal_tsum (fun i ↦ measurable_measure_prod_mk_left_finite hs) @@ -185,72 +114,6 @@ theorem Measurable.map_prod_mk_right {μ : Measure α} [SFinite μ] : simp_rw [map_apply measurable_prod_mk_right hs] exact measurable_measure_prod_mk_right hs -theorem MeasurableEmbedding.prod_mk {α β γ δ : Type*} {mα : MeasurableSpace α} - {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {f : α → β} - {g : γ → δ} (hg : MeasurableEmbedding g) (hf : MeasurableEmbedding f) : - MeasurableEmbedding fun x : γ × α => (g x.1, f x.2) := by - have h_inj : Function.Injective fun x : γ × α => (g x.fst, f x.snd) := by - intro x y hxy - rw [← @Prod.mk.eta _ _ x, ← @Prod.mk.eta _ _ y] - simp only [Prod.mk.inj_iff] at hxy ⊢ - exact ⟨hg.injective hxy.1, hf.injective hxy.2⟩ - refine ⟨h_inj, ?_, ?_⟩ - · exact (hg.measurable.comp measurable_fst).prod_mk (hf.measurable.comp measurable_snd) - · -- Induction using the π-system of rectangles - refine fun s hs => - @MeasurableSpace.induction_on_inter _ - (fun s => MeasurableSet ((fun x : γ × α => (g x.fst, f x.snd)) '' s)) _ _ - generateFrom_prod.symm isPiSystem_prod ?_ ?_ ?_ ?_ _ hs - · simp only [Set.image_empty, MeasurableSet.empty] - · rintro t ⟨t₁, ht₁, t₂, ht₂, rfl⟩ - rw [← Set.prod_image_image_eq] - exact (hg.measurableSet_image.mpr ht₁).prod (hf.measurableSet_image.mpr ht₂) - · intro t _ ht_m - rw [← Set.range_diff_image h_inj, ← Set.prod_range_range_eq] - exact - MeasurableSet.diff (MeasurableSet.prod hg.measurableSet_range hf.measurableSet_range) ht_m - · intro g _ _ hg - simp_rw [Set.image_iUnion] - exact MeasurableSet.iUnion hg - -lemma MeasurableEmbedding.prod_mk_left {β γ : Type*} [MeasurableSingletonClass α] - {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - (x : α) {f : γ → β} (hf : MeasurableEmbedding f) : - MeasurableEmbedding (fun y ↦ (x, f y)) where - injective := by - intro y y' - simp only [Prod.mk.injEq, true_and] - exact fun h ↦ hf.injective h - measurable := Measurable.prod_mk measurable_const hf.measurable - measurableSet_image' := by - intro s hs - convert (MeasurableSet.singleton x).prod (hf.measurableSet_image.mpr hs) - ext x - simp - -lemma measurableEmbedding_prod_mk_left [MeasurableSingletonClass α] (x : α) : - MeasurableEmbedding (Prod.mk x : β → α × β) := - MeasurableEmbedding.prod_mk_left x MeasurableEmbedding.id - -lemma MeasurableEmbedding.prod_mk_right {β γ : Type*} [MeasurableSingletonClass α] - {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {f : γ → β} (hf : MeasurableEmbedding f) (x : α) : - MeasurableEmbedding (fun y ↦ (f y, x)) where - injective := by - intro y y' - simp only [Prod.mk.injEq, and_true] - exact fun h ↦ hf.injective h - measurable := Measurable.prod_mk hf.measurable measurable_const - measurableSet_image' := by - intro s hs - convert (hf.measurableSet_image.mpr hs).prod (MeasurableSet.singleton x) - ext x - simp - -lemma measurableEmbedding_prod_mk_right [MeasurableSingletonClass α] (x : α) : - MeasurableEmbedding (fun y ↦ (y, x) : β → β × α) := - MeasurableEmbedding.prod_mk_right MeasurableEmbedding.id x - /-- The Lebesgue integral is measurable. This shows that the integrand of (the right-hand-side of) Tonelli's theorem is measurable. -/ theorem Measurable.lintegral_prod_right' [SFinite ν] : @@ -260,17 +123,16 @@ theorem Measurable.lintegral_prod_right' [SFinite ν] : ?_ ?_ ?_ · intro c s hs simp only [← indicator_comp_right] - suffices Measurable fun x => c * ν (Prod.mk x ⁻¹' s) by simpa [lintegral_indicator _ (m hs)] + suffices Measurable fun x => c * ν (Prod.mk x ⁻¹' s) by simpa [lintegral_indicator (m hs)] exact (measurable_measure_prod_mk_left hs).const_mul _ · rintro f g - hf - h2f h2g simp only [Pi.add_apply] conv => enter [1, x]; erw [lintegral_add_left (hf.comp m)] exact h2f.add h2g · intro f hf h2f h3f - have := measurable_iSup h3f have : ∀ x, Monotone fun n y => f n (x, y) := fun x i j hij y => h2f hij (x, y) conv => enter [1, x]; erw [lintegral_iSup (fun n => (hf n).comp m) (this x)] - assumption + exact .iSup h3f /-- The Lebesgue integral is measurable. This shows that the integrand of (the right-hand-side of) Tonelli's theorem is measurable. @@ -333,7 +195,7 @@ theorem prod_prod (s : Set α) (t : Set β) : μ.prod ν (s ×ˢ t) = μ s * ν _ = μ S * ν T := by rw [prod_apply hSTm] simp_rw [mk_preimage_prod_right_eq_if, measure_if, - lintegral_indicator _ (measurableSet_toMeasurable _ _), lintegral_const, + lintegral_indicator (measurableSet_toMeasurable _ _), lintegral_const, restrict_apply_univ, mul_comm] _ = μ s * ν t := by rw [measure_toMeasurable, measure_toMeasurable] · -- Formalization is based on https://mathoverflow.net/a/254134/136589 @@ -573,8 +435,8 @@ instance prod.instSFinite {α β : Type*} {_ : MeasurableSpace α} {μ : Measure [SFinite μ] {_ : MeasurableSpace β} {ν : Measure β} [SFinite ν] : SFinite (μ.prod ν) := by have : μ.prod ν = - Measure.sum (fun (p : ℕ × ℕ) ↦ (sFiniteSeq μ p.1).prod (sFiniteSeq ν p.2)) := by - conv_lhs => rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq ν] + Measure.sum (fun (p : ℕ × ℕ) ↦ (sfiniteSeq μ p.1).prod (sfiniteSeq ν p.2)) := by + conv_lhs => rw [← sum_sfiniteSeq μ, ← sum_sfiniteSeq ν] apply prod_sum rw [this] infer_instance @@ -620,12 +482,12 @@ theorem prod_eq {μ : Measure α} [SigmaFinite μ] {ν : Measure β} [SigmaFinit variable [SFinite μ] theorem prod_swap : map Prod.swap (μ.prod ν) = ν.prod μ := by - have : sum (fun (i : ℕ × ℕ) ↦ map Prod.swap ((sFiniteSeq μ i.1).prod (sFiniteSeq ν i.2))) - = sum (fun (i : ℕ × ℕ) ↦ map Prod.swap ((sFiniteSeq μ i.2).prod (sFiniteSeq ν i.1))) := by + have : sum (fun (i : ℕ × ℕ) ↦ map Prod.swap ((sfiniteSeq μ i.1).prod (sfiniteSeq ν i.2))) + = sum (fun (i : ℕ × ℕ) ↦ map Prod.swap ((sfiniteSeq μ i.2).prod (sfiniteSeq ν i.1))) := by ext s hs rw [sum_apply _ hs, sum_apply _ hs] exact ((Equiv.prodComm ℕ ℕ).tsum_eq _).symm - rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq ν, prod_sum, prod_sum, + rw [← sum_sfiniteSeq μ, ← sum_sfiniteSeq ν, prod_sum, prod_sum, map_sum measurable_swap.aemeasurable, this] congr 1 ext1 i @@ -687,19 +549,19 @@ lemma nullMeasurableSet_prod {s : Set α} {t : Set β} : theorem prodAssoc_prod [SFinite τ] : map MeasurableEquiv.prodAssoc ((μ.prod ν).prod τ) = μ.prod (ν.prod τ) := by have : sum (fun (p : ℕ × ℕ × ℕ) ↦ - (sFiniteSeq μ p.1).prod ((sFiniteSeq ν p.2.1).prod (sFiniteSeq τ p.2.2))) + (sfiniteSeq μ p.1).prod ((sfiniteSeq ν p.2.1).prod (sfiniteSeq τ p.2.2))) = sum (fun (p : (ℕ × ℕ) × ℕ) ↦ - (sFiniteSeq μ p.1.1).prod ((sFiniteSeq ν p.1.2).prod (sFiniteSeq τ p.2))) := by + (sfiniteSeq μ p.1.1).prod ((sfiniteSeq ν p.1.2).prod (sfiniteSeq τ p.2))) := by ext s hs rw [sum_apply _ hs, sum_apply _ hs, ← (Equiv.prodAssoc _ _ _).tsum_eq] simp only [Equiv.prodAssoc_apply] - rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq ν, ← sum_sFiniteSeq τ, prod_sum, prod_sum, + rw [← sum_sfiniteSeq μ, ← sum_sfiniteSeq ν, ← sum_sfiniteSeq τ, prod_sum, prod_sum, map_sum MeasurableEquiv.prodAssoc.measurable.aemeasurable, prod_sum, prod_sum, this] congr ext1 i refine (prod_eq_generateFrom generateFrom_measurableSet generateFrom_prod - isPiSystem_measurableSet isPiSystem_prod ((sFiniteSeq μ i.1.1)).toFiniteSpanningSetsIn - ((sFiniteSeq ν i.1.2).toFiniteSpanningSetsIn.prod (sFiniteSeq τ i.2).toFiniteSpanningSetsIn) + isPiSystem_measurableSet isPiSystem_prod ((sfiniteSeq μ i.1.1)).toFiniteSpanningSetsIn + ((sfiniteSeq ν i.1.2).toFiniteSpanningSetsIn.prod (sfiniteSeq τ i.2).toFiniteSpanningSetsIn) ?_).symm rintro s hs _ ⟨t, ht, u, hu, rfl⟩; rw [mem_setOf_eq] at hs ht hu simp_rw [map_apply (MeasurableEquiv.measurable _) (hs.prod (ht.prod hu)), @@ -710,7 +572,7 @@ theorem prodAssoc_prod [SFinite τ] : theorem prod_restrict (s : Set α) (t : Set β) : (μ.restrict s).prod (ν.restrict t) = (μ.prod ν).restrict (s ×ˢ t) := by - rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq ν, restrict_sum_of_countable, restrict_sum_of_countable, + rw [← sum_sfiniteSeq μ, ← sum_sfiniteSeq ν, restrict_sum_of_countable, restrict_sum_of_countable, prod_sum, prod_sum, restrict_sum_of_countable] congr 1 ext1 i @@ -725,27 +587,27 @@ theorem restrict_prod_eq_prod_univ (s : Set α) : theorem prod_dirac (y : β) : μ.prod (dirac y) = map (fun x => (x, y)) μ := by classical - rw [← sum_sFiniteSeq μ, prod_sum_left, map_sum measurable_prod_mk_right.aemeasurable] + rw [← sum_sfiniteSeq μ, prod_sum_left, map_sum measurable_prod_mk_right.aemeasurable] congr ext1 i refine prod_eq fun s t hs ht => ?_ simp_rw [map_apply measurable_prod_mk_right (hs.prod ht), mk_preimage_prod_left_eq_if, measure_if, - dirac_apply' _ ht, ← indicator_mul_right _ fun _ => sFiniteSeq μ i s, Pi.one_apply, mul_one] + dirac_apply' _ ht, ← indicator_mul_right _ fun _ => sfiniteSeq μ i s, Pi.one_apply, mul_one] theorem dirac_prod (x : α) : (dirac x).prod ν = map (Prod.mk x) ν := by classical - rw [← sum_sFiniteSeq ν, prod_sum_right, map_sum measurable_prod_mk_left.aemeasurable] + rw [← sum_sfiniteSeq ν, prod_sum_right, map_sum measurable_prod_mk_left.aemeasurable] congr ext1 i refine prod_eq fun s t hs ht => ?_ simp_rw [map_apply measurable_prod_mk_left (hs.prod ht), mk_preimage_prod_right_eq_if, measure_if, - dirac_apply' _ hs, ← indicator_mul_left _ _ fun _ => sFiniteSeq ν i t, Pi.one_apply, one_mul] + dirac_apply' _ hs, ← indicator_mul_left _ _ fun _ => sfiniteSeq ν i t, Pi.one_apply, one_mul] theorem dirac_prod_dirac {x : α} {y : β} : (dirac x).prod (dirac y) = dirac (x, y) := by rw [prod_dirac, map_dirac measurable_prod_mk_right] theorem prod_add (ν' : Measure β) [SFinite ν'] : μ.prod (ν + ν') = μ.prod ν + μ.prod ν' := by - simp_rw [← sum_sFiniteSeq ν, ← sum_sFiniteSeq ν', sum_add_sum, ← sum_sFiniteSeq μ, prod_sum, + simp_rw [← sum_sfiniteSeq ν, ← sum_sfiniteSeq ν', sum_add_sum, ← sum_sfiniteSeq μ, prod_sum, sum_add_sum] congr ext1 i @@ -753,7 +615,7 @@ theorem prod_add (ν' : Measure β) [SFinite ν'] : μ.prod (ν + ν') = μ.prod simp_rw [add_apply, prod_prod, left_distrib] theorem add_prod (μ' : Measure α) [SFinite μ'] : (μ + μ').prod ν = μ.prod ν + μ'.prod ν := by - simp_rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq μ', sum_add_sum, ← sum_sFiniteSeq ν, prod_sum, + simp_rw [← sum_sfiniteSeq μ, ← sum_sfiniteSeq μ', sum_add_sum, ← sum_sfiniteSeq ν, prod_sum, sum_add_sum] congr ext1 i @@ -771,7 +633,7 @@ theorem prod_zero (μ : Measure α) : μ.prod (0 : Measure β) = 0 := by simp [M theorem map_prod_map {δ} [MeasurableSpace δ] {f : α → β} {g : γ → δ} (μa : Measure α) (μc : Measure γ) [SFinite μa] [SFinite μc] (hf : Measurable f) (hg : Measurable g) : (map f μa).prod (map g μc) = map (Prod.map f g) (μa.prod μc) := by - simp_rw [← sum_sFiniteSeq μa, ← sum_sFiniteSeq μc, map_sum hf.aemeasurable, + simp_rw [← sum_sfiniteSeq μa, ← sum_sfiniteSeq μc, map_sum hf.aemeasurable, map_sum hg.aemeasurable, prod_sum, map_sum (hf.prod_map hg).aemeasurable] congr ext1 i @@ -899,7 +761,7 @@ theorem lintegral_prod_of_measurable : rw [← indicator_comp_right, const_def, const_comp, ← const_def] conv_rhs => enter [2, x] - rw [lintegral_indicator _ (m (x := x) hs), lintegral_const, + rw [lintegral_indicator (m (x := x) hs), lintegral_const, Measure.restrict_apply MeasurableSet.univ, univ_inter] simp [hs, lintegral_const_mul, measurable_measure_prod_mk_left (ν := ν) hs, prod_apply] · rintro f g - hf _ h2f h2g diff --git a/Mathlib/MeasureTheory/Measure/Regular.lean b/Mathlib/MeasureTheory/Measure/Regular.lean index 362b5a971e2a4..f283ccf0b3e83 100644 --- a/Mathlib/MeasureTheory/Measure/Regular.lean +++ b/Mathlib/MeasureTheory/Measure/Regular.lean @@ -511,7 +511,7 @@ lemma of_sigmaFinite [SigmaFinite μ] : rw [← (monotone_const.inter (monotone_spanningSets μ)).measure_iUnion, hBU] rw [this] at hr rcases lt_iSup_iff.1 hr with ⟨n, hn⟩ - refine ⟨s ∩ B n, inter_subset_left, ⟨hs.inter (measurable_spanningSets μ n), ?_⟩, hn⟩ + refine ⟨s ∩ B n, inter_subset_left, ⟨hs.inter (measurableSet_spanningSets μ n), ?_⟩, hn⟩ exact ((measure_mono inter_subset_right).trans_lt (measure_spanningSets_lt_top μ n)).ne variable [TopologicalSpace α] diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean index 5e3e7702c9a7e..128b3126b22c9 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -634,8 +634,7 @@ theorem div_ae_eq_one {β} [Group β] (f g : α → β) : f / g =ᵐ[μ] 1 ↔ f · rwa [Pi.div_apply, Pi.one_apply, div_eq_one] @[to_additive sub_nonneg_ae] -lemma one_le_div_ae {β : Type*} [Group β] [LE β] - [CovariantClass β β (Function.swap (· * ·)) (· ≤ ·)] (f g : α → β) : +lemma one_le_div_ae {β : Type*} [Group β] [LE β] [MulRightMono β] (f g : α → β) : 1 ≤ᵐ[μ] g / f ↔ f ≤ᵐ[μ] g := by refine ⟨fun h ↦ h.mono fun a ha ↦ ?_, fun h ↦ h.mono fun a ha ↦ ?_⟩ · rwa [Pi.one_apply, Pi.div_apply, one_le_div'] at ha @@ -651,7 +650,6 @@ theorem ae_restrict_eq (hs : MeasurableSet s) : ae (μ.restrict s) = ae μ ⊓ Classical.not_imp, fun a => and_comm (a := a ∈ s) (b := ¬a ∈ t)] rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem ae_restrict_eq_bot {s} : ae (μ.restrict s) = ⊥ ↔ μ s = 0 := ae_eq_bot.trans restrict_eq_zero diff --git a/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean b/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean index ec687e378d87f..cb0e5e2a0c352 100644 --- a/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean @@ -63,7 +63,7 @@ written `≠ ∞` rather than `< ∞`. See `Ne.lt_top` and `ne_of_lt` to switch separable measure, measure-dense, Lp space, second-countable -/ -open MeasurableSpace Set ENNReal TopologicalSpace BigOperators symmDiff Filter Real +open MeasurableSpace Set ENNReal TopologicalSpace symmDiff Real namespace MeasureTheory @@ -83,7 +83,7 @@ sets with finite measures. The term "measure-dense" is justified by the fact that the approximating condition translates to the usual notion of density in the metric space made by constant indicators of measurable sets equipped with the `Lᵖ` norm. -/ -structure Measure.MeasureDense (μ : Measure X) (𝒜 : Set (Set X)) : Prop := +structure Measure.MeasureDense (μ : Measure X) (𝒜 : Set (Set X)) : Prop where /-- Each set has to be measurable. -/ measurable : ∀ s ∈ 𝒜, MeasurableSet s /-- Any measurable set can be approximated by sets in the family. -/ @@ -319,7 +319,7 @@ section IsSeparable The term "separable" is justified by the fact that the definition translates to the usual notion of separability in the metric space made by constant indicators equipped with the `Lᵖ` norm. -/ -class IsSeparable (μ : Measure X) : Prop := +class IsSeparable (μ : Measure X) : Prop where exists_countable_measureDense : ∃ 𝒜, 𝒜.Countable ∧ μ.MeasureDense 𝒜 /-- By definition, a separable measure admits a countable and measure-dense family of sets. -/ @@ -425,7 +425,7 @@ instance Lp.SecondCountableTopology [IsSeparable μ] [TopologicalSpace.Separable refine ⟨D, ?_, ?_⟩ · -- Countability directly follows from countability of `u` and `𝒜₀`. The function `f` below -- is the uncurryfied version of `key`, which is easier to manipulate as countability of the - -- domain is automatically infered. + -- domain is automatically inferred. let f (nds : Σ n : ℕ, (Fin n → u) × (Fin n → 𝒜₀)) : Lp E p μ := key nds.1 nds.2.1 nds.2.2 have := count_𝒜₀.to_subtype have := countable_u.to_subtype diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean index 841b773d2cd9d..1e25364777f6e 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -136,7 +136,7 @@ at `x` is a Stieltjes function, i.e., it is monotone and right-continuous. -/ noncomputable def _root_.Monotone.stieltjesFunction {f : ℝ → ℝ} (hf : Monotone f) : StieltjesFunction where toFun := rightLim f - mono' x y hxy := hf.rightLim hxy + mono' _ _ hxy := hf.rightLim hxy right_continuous' := by intro x s hs obtain ⟨l, u, hlu, lus⟩ : ∃ l u : ℝ, rightLim f x ∈ Ioo l u ∧ Ioo l u ⊆ s := diff --git a/Mathlib/MeasureTheory/Measure/Tilted.lean b/Mathlib/MeasureTheory/Measure/Tilted.lean index 0dcb5897a5937..78793a1d88732 100644 --- a/Mathlib/MeasureTheory/Measure/Tilted.lean +++ b/Mathlib/MeasureTheory/Measure/Tilted.lean @@ -235,7 +235,7 @@ alias set_integral_tilted := setIntegral_tilted lemma integral_tilted (f : α → ℝ) (g : α → E) : ∫ x, g x ∂(μ.tilted f) = ∫ x, (exp (f x) / ∫ x, exp (f x) ∂μ) • (g x) ∂μ := by - rw [← integral_univ, setIntegral_tilted' f g MeasurableSet.univ, integral_univ] + rw [← setIntegral_univ, setIntegral_tilted' f g MeasurableSet.univ, setIntegral_univ] end integral diff --git a/Mathlib/MeasureTheory/Measure/Trim.lean b/Mathlib/MeasureTheory/Measure/Trim.lean index af9a03aa6916a..3afc9ad874998 100644 --- a/Mathlib/MeasureTheory/Measure/Trim.lean +++ b/Mathlib/MeasureTheory/Measure/Trim.lean @@ -104,7 +104,7 @@ theorem sigmaFiniteTrim_mono {m m₂ m0 : MeasurableSpace α} {μ : Measure α} calc (μ.trim hm) (spanningSets (μ.trim (hm₂.trans hm)) i) = ((μ.trim hm).trim hm₂) (spanningSets (μ.trim (hm₂.trans hm)) i) := by - rw [@trim_measurableSet_eq α m₂ m (μ.trim hm) _ hm₂ (measurable_spanningSets _ _)] + rw [@trim_measurableSet_eq α m₂ m (μ.trim hm) _ hm₂ (measurableSet_spanningSets _ _)] _ = (μ.trim (hm₂.trans hm)) (spanningSets (μ.trim (hm₂.trans hm)) i) := by rw [@trim_trim _ _ μ _ _ hm₂ hm] _ < ∞ := measure_spanningSets_lt_top _ _ diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses.lean b/Mathlib/MeasureTheory/Measure/Typeclasses.lean index 21a35d7e02dd3..c0205825e011a 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean @@ -53,7 +53,7 @@ theorem measure_lt_top (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ instance isFiniteMeasureRestrict (μ : Measure α) (s : Set α) [h : IsFiniteMeasure μ] : IsFiniteMeasure (μ.restrict s) := ⟨by simp⟩ -@[simp] +@[simp, aesop (rule_sets := [finiteness]) safe apply] theorem measure_ne_top (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ s ≠ ∞ := ne_of_lt (measure_lt_top μ s) @@ -122,6 +122,14 @@ theorem Measure.isFiniteMeasure_map {m : MeasurableSpace α} (μ : Measure α) [ · rw [map_of_not_aemeasurable hf] exact MeasureTheory.isFiniteMeasureZero +instance IsFiniteMeasure_comap (f : β → α) [IsFiniteMeasure μ] : IsFiniteMeasure (μ.comap f) where + measure_univ_lt_top := by + by_cases hf : Injective f ∧ ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) μ + · rw [Measure.comap_apply₀ _ _ hf.1 hf.2 MeasurableSet.univ.nullMeasurableSet] + exact measure_lt_top μ _ + · rw [Measure.comap, dif_neg hf] + exact zero_lt_top + @[simp] theorem measureUnivNNReal_eq_zero [IsFiniteMeasure μ] : measureUnivNNReal μ = 0 ↔ μ = 0 := by rw [← MeasureTheory.Measure.measure_univ_eq_zero, ← coe_measureUnivNNReal] @@ -277,6 +285,9 @@ theorem isProbabilityMeasure_map {f : α → β} (hf : AEMeasurable f μ) : IsProbabilityMeasure (map f μ) := ⟨by simp [map_apply_of_aemeasurable, hf]⟩ +instance IsProbabilityMeasure_comap_equiv (f : β ≃ᵐ α) : IsProbabilityMeasure (μ.comap f) := by + rw [← MeasurableEquiv.map_symm]; exact isProbabilityMeasure_map f.symm.measurable.aemeasurable + /-- Note that this is not quite as useful as it looks because the measure takes values in `ℝ≥0∞`. Thus the subtraction appearing is the truncated subtraction of `ℝ≥0∞`, rather than the better-behaved subtraction of `ℝ`. -/ @@ -548,25 +559,36 @@ section SFinite class SFinite (μ : Measure α) : Prop where out' : ∃ m : ℕ → Measure α, (∀ n, IsFiniteMeasure (m n)) ∧ μ = Measure.sum m -/-- A sequence of finite measures such that `μ = sum (sFiniteSeq μ)` (see `sum_sFiniteSeq`). -/ -noncomputable -def sFiniteSeq (μ : Measure α) [h : SFinite μ] : ℕ → Measure α := h.1.choose +/-- A sequence of finite measures such that `μ = sum (sfiniteSeq μ)` (see `sum_sfiniteSeq`). -/ +noncomputable def sfiniteSeq (μ : Measure α) [h : SFinite μ] : ℕ → Measure α := h.1.choose -instance isFiniteMeasure_sFiniteSeq [h : SFinite μ] (n : ℕ) : IsFiniteMeasure (sFiniteSeq μ n) := +@[deprecated (since := "2024-10-11")] alias sFiniteSeq := sfiniteSeq + +instance isFiniteMeasure_sfiniteSeq [h : SFinite μ] (n : ℕ) : IsFiniteMeasure (sfiniteSeq μ n) := h.1.choose_spec.1 n -lemma sum_sFiniteSeq (μ : Measure α) [h : SFinite μ] : sum (sFiniteSeq μ) = μ := +set_option linter.deprecated false in +@[deprecated (since := "2024-10-11")] +instance isFiniteMeasure_sFiniteSeq [SFinite μ] (n : ℕ) : IsFiniteMeasure (sFiniteSeq μ n) := + isFiniteMeasure_sfiniteSeq n + +lemma sum_sfiniteSeq (μ : Measure α) [h : SFinite μ] : sum (sfiniteSeq μ) = μ := h.1.choose_spec.2.symm +@[deprecated (since := "2024-10-11")] alias sum_sFiniteSeq := sum_sfiniteSeq + +lemma sfiniteSeq_le (μ : Measure α) [SFinite μ] (n : ℕ) : sfiniteSeq μ n ≤ μ := + (le_sum _ n).trans (sum_sfiniteSeq μ).le + +@[deprecated (since := "2024-10-11")] alias sFiniteSeq_le := sfiniteSeq_le + instance : SFinite (0 : Measure α) := ⟨fun _ ↦ 0, inferInstance, by rw [Measure.sum_zero]⟩ @[simp] -lemma sFiniteSeq_zero (n : ℕ) : sFiniteSeq (0 : Measure α) n = 0 := by - ext s hs - have h : ∑' n, sFiniteSeq (0 : Measure α) n s = 0 := by - simp [← Measure.sum_apply _ hs, sum_sFiniteSeq] - simp only [ENNReal.tsum_eq_zero] at h - exact h n +lemma sfiniteSeq_zero (n : ℕ) : sfiniteSeq (0 : Measure α) n = 0 := + bot_unique <| sfiniteSeq_le _ _ + +@[deprecated (since := "2024-10-11")] alias sFiniteSeq_zero := sfiniteSeq_zero /-- A countable sum of finite measures is s-finite. This lemma is superseded by the instance below. -/ @@ -583,7 +605,7 @@ lemma sfinite_sum_of_countable [Countable ι] instance [Countable ι] (m : ι → Measure α) [∀ n, SFinite (m n)] : SFinite (Measure.sum m) := by change SFinite (Measure.sum (fun i ↦ m i)) - simp_rw [← sum_sFiniteSeq (m _), Measure.sum_sum] + simp_rw [← sum_sfiniteSeq (m _), Measure.sum_sum] apply sfinite_sum_of_countable instance [SFinite μ] [SFinite ν] : SFinite (μ + ν) := by @@ -591,8 +613,8 @@ instance [SFinite μ] [SFinite ν] : SFinite (μ + ν) := by simpa using inferInstanceAs (SFinite (.sum (cond · μ ν))) instance [SFinite μ] (s : Set α) : SFinite (μ.restrict s) := - ⟨fun n ↦ (sFiniteSeq μ n).restrict s, fun n ↦ inferInstance, - by rw [← restrict_sum_of_countable, sum_sFiniteSeq]⟩ + ⟨fun n ↦ (sfiniteSeq μ n).restrict s, fun n ↦ inferInstance, + by rw [← restrict_sum_of_countable, sum_sfiniteSeq]⟩ variable (μ) in /-- For an s-finite measure `μ`, there exists a finite measure `ν` @@ -600,12 +622,12 @@ such that each of `μ` and `ν` is absolutely continuous with respect to the oth -/ theorem exists_isFiniteMeasure_absolutelyContinuous [SFinite μ] : ∃ ν : Measure α, IsFiniteMeasure ν ∧ μ ≪ ν ∧ ν ≪ μ := by - rcases ENNReal.exists_pos_tsum_mul_lt_of_countable top_ne_zero (sFiniteSeq μ · univ) + rcases ENNReal.exists_pos_tsum_mul_lt_of_countable top_ne_zero (sfiniteSeq μ · univ) fun _ ↦ measure_ne_top _ _ with ⟨c, hc₀, hc⟩ - have {s : Set α} : sum (fun n ↦ c n • sFiniteSeq μ n) s = 0 ↔ μ s = 0 := by - conv_rhs => rw [← sum_sFiniteSeq μ, sum_apply_of_countable] + have {s : Set α} : sum (fun n ↦ c n • sfiniteSeq μ n) s = 0 ↔ μ s = 0 := by + conv_rhs => rw [← sum_sfiniteSeq μ, sum_apply_of_countable] simp [(hc₀ _).ne'] - refine ⟨.sum fun n ↦ c n • sFiniteSeq μ n, ⟨?_⟩, fun _ ↦ this.1, fun _ ↦ this.2⟩ + refine ⟨.sum fun n ↦ c n • sfiniteSeq μ n, ⟨?_⟩, fun _ ↦ this.1, fun _ ↦ this.2⟩ simpa [mul_comm] using hc variable (μ) in @@ -631,11 +653,11 @@ theorem SigmaFinite.out (h : SigmaFinite μ) : Nonempty (μ.FiniteSpanningSetsIn def Measure.toFiniteSpanningSetsIn (μ : Measure α) [h : SigmaFinite μ] : μ.FiniteSpanningSetsIn { s | MeasurableSet s } where set n := toMeasurable μ (h.out.some.set n) - set_mem n := measurableSet_toMeasurable _ _ + set_mem _ := measurableSet_toMeasurable _ _ finite n := by rw [measure_toMeasurable] exact h.out.some.finite n - spanning := eq_univ_of_subset (iUnion_mono fun n => subset_toMeasurable _ _) h.out.some.spanning + spanning := eq_univ_of_subset (iUnion_mono fun _ => subset_toMeasurable _ _) h.out.some.spanning /-- A noncomputable way to get a monotone collection of sets that span `univ` and have finite measure using `Classical.choose`. This definition satisfies monotonicity in addition to all other @@ -646,14 +668,21 @@ def spanningSets (μ : Measure α) [SigmaFinite μ] (i : ℕ) : Set α := theorem monotone_spanningSets (μ : Measure α) [SigmaFinite μ] : Monotone (spanningSets μ) := monotone_accumulate -theorem measurable_spanningSets (μ : Measure α) [SigmaFinite μ] (i : ℕ) : +@[gcongr] +lemma spanningSets_mono [SigmaFinite μ] {m n : ℕ} (hmn : m ≤ n) : + spanningSets μ m ⊆ spanningSets μ n := monotone_spanningSets _ hmn + +theorem measurableSet_spanningSets (μ : Measure α) [SigmaFinite μ] (i : ℕ) : MeasurableSet (spanningSets μ i) := MeasurableSet.iUnion fun j => MeasurableSet.iUnion fun _ => μ.toFiniteSpanningSetsIn.set_mem j +@[deprecated (since := "2024-10-16")] alias measurable_spanningSets := measurableSet_spanningSets + theorem measure_spanningSets_lt_top (μ : Measure α) [SigmaFinite μ] (i : ℕ) : μ (spanningSets μ i) < ∞ := measure_biUnion_lt_top (finite_le_nat i) fun j _ => μ.toFiniteSpanningSetsIn.finite j +@[simp] theorem iUnion_spanningSets (μ : Measure α) [SigmaFinite μ] : ⋃ i : ℕ, spanningSets μ i = univ := by simp_rw [spanningSets, iUnion_accumulate, μ.toFiniteSpanningSetsIn.spanning] @@ -667,9 +696,9 @@ noncomputable def spanningSetsIndex (μ : Measure α) [SigmaFinite μ] (x : α) Nat.find <| iUnion_eq_univ_iff.1 (iUnion_spanningSets μ) x open scoped Classical in -theorem measurable_spanningSetsIndex (μ : Measure α) [SigmaFinite μ] : +theorem measurableSet_spanningSetsIndex (μ : Measure α) [SigmaFinite μ] : Measurable (spanningSetsIndex μ) := - measurable_find _ <| measurable_spanningSets μ + measurable_find _ <| measurableSet_spanningSets μ open scoped Classical in theorem preimage_spanningSetsIndex_singleton (μ : Measure α) [SigmaFinite μ] (n : ℕ) : @@ -699,7 +728,7 @@ theorem eventually_mem_spanningSets (μ : Measure α) [SigmaFinite μ] (x : α) theorem sum_restrict_disjointed_spanningSets (μ ν : Measure α) [SigmaFinite ν] : sum (fun n ↦ μ.restrict (disjointed (spanningSets ν) n)) = μ := by rw [← restrict_iUnion (disjoint_disjointed _) - (MeasurableSet.disjointed (measurable_spanningSets _)), + (MeasurableSet.disjointed (measurableSet_spanningSets _)), iUnion_disjointed, iUnion_spanningSets, restrict_univ] instance (priority := 100) [SigmaFinite μ] : SFinite μ := by @@ -792,9 +821,9 @@ theorem countable_meas_pos_of_disjoint_iUnion₀ {ι : Type*} {_ : MeasurableSpa [SFinite μ] {As : ι → Set α} (As_mble : ∀ i : ι, NullMeasurableSet (As i) μ) (As_disj : Pairwise (AEDisjoint μ on As)) : Set.Countable { i : ι | 0 < μ (As i) } := by - rw [← sum_sFiniteSeq μ] at As_disj As_mble ⊢ - have obs : { i : ι | 0 < sum (sFiniteSeq μ) (As i) } - ⊆ ⋃ n, { i : ι | 0 < sFiniteSeq μ n (As i) } := by + rw [← sum_sfiniteSeq μ] at As_disj As_mble ⊢ + have obs : { i : ι | 0 < sum (sfiniteSeq μ) (As i) } + ⊆ ⋃ n, { i : ι | 0 < sfiniteSeq μ n (As i) } := by intro i hi by_contra con simp only [mem_iUnion, mem_setOf_eq, not_exists, not_lt, nonpos_iff_eq_zero] at * @@ -940,7 +969,7 @@ This only holds when `μ` is s-finite -- for example for σ-finite measures. For this assumption (but requiring that `t` has finite measure), see `measure_toMeasurable_inter`. -/ theorem measure_toMeasurable_inter_of_sFinite [SFinite μ] {s : Set α} (hs : MeasurableSet s) (t : Set α) : μ (toMeasurable μ t ∩ s) = μ (t ∩ s) := - measure_toMeasurable_inter_of_sum hs (fun _ ↦ measure_ne_top _ t) (sum_sFiniteSeq μ).symm + measure_toMeasurable_inter_of_sum hs (fun _ ↦ measure_ne_top _ t) (sum_sfiniteSeq μ).symm @[simp] theorem restrict_toMeasurable_of_sFinite [SFinite μ] (s : Set α) : @@ -961,9 +990,9 @@ theorem iSup_restrict_spanningSets [SigmaFinite μ] (s : Set α) : ⨆ i, μ.restrict (spanningSets μ i) s = μ s := by rw [← measure_toMeasurable s, ← iSup_restrict_spanningSets_of_measurableSet (measurableSet_toMeasurable _ _)] - simp_rw [restrict_apply' (measurable_spanningSets μ _), Set.inter_comm s, - ← restrict_apply (measurable_spanningSets μ _), ← restrict_toMeasurable_of_sFinite s, - restrict_apply (measurable_spanningSets μ _), Set.inter_comm _ (toMeasurable μ s)] + simp_rw [restrict_apply' (measurableSet_spanningSets μ _), Set.inter_comm s, + ← restrict_apply (measurableSet_spanningSets μ _), ← restrict_toMeasurable_of_sFinite s, + restrict_apply (measurableSet_spanningSets μ _), Set.inter_comm _ (toMeasurable μ s)] /-- In a σ-finite space, any measurable set of measure `> r` contains a measurable subset of finite measure `> r`. -/ @@ -974,7 +1003,7 @@ theorem exists_subset_measure_lt_top [SigmaFinite μ] {r : ℝ≥0∞} (hs : Mea rcases h's with ⟨n, hn⟩ simp only [restrict_apply hs] at hn refine - ⟨s ∩ spanningSets μ n, hs.inter (measurable_spanningSets _ _), inter_subset_left, hn, ?_⟩ + ⟨s ∩ spanningSets μ n, hs.inter (measurableSet_spanningSets _ _), inter_subset_left, hn, ?_⟩ exact (measure_mono inter_subset_right).trans_lt (measure_spanningSets_lt_top _ _) namespace FiniteSpanningSetsIn @@ -1054,7 +1083,7 @@ theorem sigmaFinite_bot_iff (μ : @Measure α ⊥) : SigmaFinite μ ↔ IsFinite haveI : SigmaFinite μ := h let s := spanningSets μ have hs_univ : ⋃ i, s i = Set.univ := iUnion_spanningSets μ - have hs_meas : ∀ i, MeasurableSet[⊥] (s i) := measurable_spanningSets μ + have hs_meas : ∀ i, MeasurableSet[⊥] (s i) := measurableSet_spanningSets μ simp_rw [MeasurableSpace.measurableSet_bot_iff] at hs_meas by_cases h_univ_empty : (Set.univ : Set α) = ∅ · rw [h_univ_empty, measure_empty] @@ -1070,14 +1099,14 @@ theorem sigmaFinite_bot_iff (μ : @Measure α ⊥) : SigmaFinite μ ↔ IsFinite instance Restrict.sigmaFinite (μ : Measure α) [SigmaFinite μ] (s : Set α) : SigmaFinite (μ.restrict s) := by refine ⟨⟨⟨spanningSets μ, fun _ => trivial, fun i => ?_, iUnion_spanningSets μ⟩⟩⟩ - rw [Measure.restrict_apply (measurable_spanningSets μ i)] + rw [Measure.restrict_apply (measurableSet_spanningSets μ i)] exact (measure_mono inter_subset_left).trans_lt (measure_spanningSets_lt_top μ i) instance sum.sigmaFinite {ι} [Finite ι] (μ : ι → Measure α) [∀ i, SigmaFinite (μ i)] : SigmaFinite (sum μ) := by cases nonempty_fintype ι have : ∀ n, MeasurableSet (⋂ i : ι, spanningSets (μ i) n) := fun n => - MeasurableSet.iInter fun i => measurable_spanningSets (μ i) n + MeasurableSet.iInter fun i => measurableSet_spanningSets (μ i) n refine ⟨⟨⟨fun n => ⋂ i, spanningSets (μ i) n, fun _ => trivial, fun n => ?_, ?_⟩⟩⟩ · rw [sum_apply _ (this n), tsum_fintype, ENNReal.sum_lt_top] rintro i - @@ -1114,7 +1143,7 @@ instance [SigmaFinite (μ.restrict t)] : SigmaFinite (μ.restrict (s ∩ t)) := theorem SigmaFinite.of_map (μ : Measure α) {f : α → β} (hf : AEMeasurable f μ) (h : SigmaFinite (μ.map f)) : SigmaFinite μ := ⟨⟨⟨fun n => f ⁻¹' spanningSets (μ.map f) n, fun _ => trivial, fun n => by - simp only [← map_apply_of_aemeasurable hf, measurable_spanningSets, + simp only [← map_apply_of_aemeasurable hf, measurableSet_spanningSets, measure_spanningSets_lt_top], by rw [← preimage_iUnion, iUnion_spanningSets, preimage_univ]⟩⟩⟩ @@ -1140,10 +1169,10 @@ theorem ae_of_forall_measure_lt_top_ae_restrict' {μ : Measure α} (ν : Measure have : ∀ n, ∀ᵐ x ∂μ, x ∈ spanningSets (μ + ν) n → P x := by intro n have := h - (spanningSets (μ + ν) n) (measurable_spanningSets _ _) + (spanningSets (μ + ν) n) (measurableSet_spanningSets _ _) ((self_le_add_right _ _).trans_lt (measure_spanningSets_lt_top (μ + ν) _)) ((self_le_add_left _ _).trans_lt (measure_spanningSets_lt_top (μ + ν) _)) - exact (ae_restrict_iff' (measurable_spanningSets _ _)).mp this + exact (ae_restrict_iff' (measurableSet_spanningSets _ _)).mp this filter_upwards [ae_all_iff.2 this] with _ hx using hx _ (mem_spanningSetsIndex _ _) /-- To prove something for almost all `x` w.r.t. a σ-finite measure, it is sufficient to show that @@ -1434,7 +1463,7 @@ theorem exists_open_superset_measure_lt_top (h : IsCompact s) (μ : Measure α) theorem measure_lt_top_of_nhdsWithin (h : IsCompact s) (hμ : ∀ x ∈ s, μ.FiniteAtFilter (𝓝[s] x)) : μ s < ∞ := - IsCompact.induction_on h (by simp) (fun s t hst ht => (measure_mono hst).trans_lt ht) + IsCompact.induction_on h (by simp) (fun _ _ hst ht => (measure_mono hst).trans_lt ht) (fun s t hs ht => (measure_union_le s t).trans_lt (ENNReal.add_lt_top.2 ⟨hs, ht⟩)) hμ theorem measure_zero_of_nhdsWithin (hs : IsCompact s) : diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index 50bf902e8d3cf..e5e7a7d55a5d6 100644 --- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean @@ -96,7 +96,7 @@ theorem coe_injective : @Function.Injective (VectorMeasure α M) (Set α → M) congr theorem ext_iff' (v w : VectorMeasure α M) : v = w ↔ ∀ i : Set α, v i = w i := by - rw [← coe_injective.eq_iff, Function.funext_iff] + rw [← coe_injective.eq_iff, funext_iff] theorem ext_iff (v w : VectorMeasure α M) : v = w ↔ ∀ i : Set α, MeasurableSet i → v i = w i := by constructor @@ -237,7 +237,7 @@ def add (v w : VectorMeasure α M) : VectorMeasure α M where measureOf' := v + w empty' := by simp not_measurable' _ hi := by rw [Pi.add_apply, v.not_measurable hi, w.not_measurable hi, add_zero] - m_iUnion' f hf₁ hf₂ := HasSum.add (v.m_iUnion hf₁ hf₂) (w.m_iUnion hf₁ hf₂) + m_iUnion' _ hf₁ hf₂ := HasSum.add (v.m_iUnion hf₁ hf₂) (w.m_iUnion hf₁ hf₂) instance instAdd : Add (VectorMeasure α M) := ⟨add⟩ @@ -268,7 +268,7 @@ def neg (v : VectorMeasure α M) : VectorMeasure α M where measureOf' := -v empty' := by simp not_measurable' _ hi := by rw [Pi.neg_apply, neg_eq_zero, v.not_measurable hi] - m_iUnion' f hf₁ hf₂ := HasSum.neg <| v.m_iUnion hf₁ hf₂ + m_iUnion' _ hf₁ hf₂ := HasSum.neg <| v.m_iUnion hf₁ hf₂ instance instNeg : Neg (VectorMeasure α M) := ⟨neg⟩ @@ -283,7 +283,7 @@ def sub (v w : VectorMeasure α M) : VectorMeasure α M where measureOf' := v - w empty' := by simp not_measurable' _ hi := by rw [Pi.sub_apply, v.not_measurable hi, w.not_measurable hi, sub_zero] - m_iUnion' f hf₁ hf₂ := HasSum.sub (v.m_iUnion hf₁ hf₂) (w.m_iUnion hf₁ hf₂) + m_iUnion' _ hf₁ hf₂ := HasSum.sub (v.m_iUnion hf₁ hf₂) (w.m_iUnion hf₁ hf₂) instance instSub : Sub (VectorMeasure α M) := ⟨sub⟩ @@ -462,7 +462,7 @@ def map (v : VectorMeasure α M) (f : α → β) : VectorMeasure β M := if hf : Measurable f then { measureOf' := fun s => if MeasurableSet s then v (f ⁻¹' s) else 0 empty' := by simp - not_measurable' := fun i hi => if_neg hi + not_measurable' := fun _ hi => if_neg hi m_iUnion' := by intro g hg₁ hg₂ simp only @@ -500,7 +500,7 @@ def mapRange (v : VectorMeasure α M) (f : M →+ N) (hf : Continuous f) : Vecto measureOf' s := f (v s) empty' := by simp only; rw [empty, AddMonoidHom.map_zero] not_measurable' i hi := by simp only; rw [not_measurable v hi, AddMonoidHom.map_zero] - m_iUnion' g hg₁ hg₂ := HasSum.map (v.m_iUnion hg₁ hg₂) f hf + m_iUnion' _ hg₁ hg₂ := HasSum.map (v.m_iUnion hg₁ hg₂) f hf @[simp] theorem mapRange_apply {f : M →+ N} (hf : Continuous f) {s : Set α} : v.mapRange f hf s = f (v s) := @@ -561,7 +561,7 @@ def restrict (v : VectorMeasure α M) (i : Set α) : VectorMeasure α M := if hi : MeasurableSet i then { measureOf' := fun s => if MeasurableSet s then v (s ∩ i) else 0 empty' := by simp - not_measurable' := fun i hi => if_neg hi + not_measurable' := fun _ hi => if_neg hi m_iUnion' := by intro f hf₁ hf₂ simp only @@ -694,11 +694,11 @@ variable {M : Type*} [TopologicalSpace M] [AddCommMonoid M] [PartialOrder M] This definition is consistent with `Measure.instPartialOrder`. -/ instance instPartialOrder : PartialOrder (VectorMeasure α M) where le v w := ∀ i, MeasurableSet i → v i ≤ w i - le_refl v i _ := le_rfl - le_trans u v w h₁ h₂ i hi := le_trans (h₁ i hi) (h₂ i hi) - le_antisymm v w h₁ h₂ := ext fun i hi => le_antisymm (h₁ i hi) (h₂ i hi) + le_refl _ _ _ := le_rfl + le_trans _ _ _ h₁ h₂ i hi := le_trans (h₁ i hi) (h₂ i hi) + le_antisymm _ _ h₁ h₂ := ext fun i hi => le_antisymm (h₁ i hi) (h₂ i hi) -variable {u v w : VectorMeasure α M} +variable {v w : VectorMeasure α M} theorem le_iff : v ≤ w ↔ ∀ i, MeasurableSet i → v i ≤ w i := Iff.rfl @@ -880,10 +880,9 @@ end section variable {M : Type*} [TopologicalSpace M] [AddCommMonoid M] [PartialOrder M] - [CovariantClass M M (· + ·) (· ≤ ·)] [ContinuousAdd M] + [AddLeftMono M] [ContinuousAdd M] -instance covariant_add_le : - CovariantClass (VectorMeasure α M) (VectorMeasure α M) (· + ·) (· ≤ ·) := +instance instAddLeftMono : AddLeftMono (VectorMeasure α M) := ⟨fun _ _ _ h i hi => add_le_add_left (h i hi) _⟩ end diff --git a/Mathlib/MeasureTheory/Measure/WithDensity.lean b/Mathlib/MeasureTheory/Measure/WithDensity.lean index 4af7da3eaff23..d343307b3e3fc 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensity.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensity.lean @@ -32,7 +32,7 @@ variable {α : Type*} {m0 : MeasurableSpace α} {μ : Measure α} measure such that for a measurable set `s` we have `μ.withDensity f s = ∫⁻ a in s, f a ∂μ`. -/ noncomputable def Measure.withDensity {m : MeasurableSpace α} (μ : Measure α) (f : α → ℝ≥0∞) : Measure α := - Measure.ofMeasurable (fun s _ => ∫⁻ a in s, f a ∂μ) (by simp) fun s hs hd => + Measure.ofMeasurable (fun s _ => ∫⁻ a in s, f a ∂μ) (by simp) fun _ hs hd => lintegral_iUnion hs hd _ @[simp] @@ -170,7 +170,7 @@ theorem withDensity_tsum {ι : Type*} [Countable ι] {f : ι → α → ℝ≥0 theorem withDensity_indicator {s : Set α} (hs : MeasurableSet s) (f : α → ℝ≥0∞) : μ.withDensity (s.indicator f) = (μ.restrict s).withDensity f := by ext1 t ht - rw [withDensity_apply _ ht, lintegral_indicator _ hs, restrict_comm hs, ← + rw [withDensity_apply _ ht, lintegral_indicator hs, restrict_comm hs, ← withDensity_apply _ ht] theorem withDensity_indicator_one {s : Set α} (hs : MeasurableSet s) : @@ -615,8 +615,8 @@ instance Measure.withDensity.instSFinite [SFinite μ] {f : α → ℝ≥0∞} : · rcases exists_measurable_le_withDensity_eq μ f with ⟨g, hgm, -, h⟩ exact h ▸ this hgm wlog hμ : IsFiniteMeasure μ generalizing μ - · rw [← sum_sFiniteSeq μ, withDensity_sum] - have (n : ℕ) : SFinite ((sFiniteSeq μ n).withDensity f) := this inferInstance + · rw [← sum_sfiniteSeq μ, withDensity_sum] + have (n : ℕ) : SFinite ((sfiniteSeq μ n).withDensity f) := this inferInstance infer_instance set s := {x | f x = ∞} have hs : MeasurableSet s := hfm (measurableSet_singleton _) diff --git a/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean b/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean index 955c03a3c1454..21abd06cd6cee 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean @@ -9,16 +9,16 @@ import Mathlib.Probability.ConditionalProbability /-! # s-finite measures can be written as `withDensity` of a finite measure -If `μ` is an s-finite measure, then there exists a finite measure `μ.toFinite` and a measurable -function `densityToFinite μ` such that `μ = μ.toFinite.withDensity μ.densityToFinite`. If `μ` is -zero this is the zero measure, and otherwise we can choose a probability measure for `μ.toFinite`. +If `μ` is an s-finite measure, then there exists a finite measure `μ.toFinite` +such that a set is `μ`-null iff it is `μ.toFinite`-null. +In particular, `MeasureTheory.ae μ.toFinite = MeasureTheory.ae μ` and `μ.toFinite = 0` iff `μ = 0`. +As a corollary, `μ` can be represented as `μ.toFinite.withDensity (μ.rnDeriv μ.toFinite)`. -That measure is not unique, and in particular our implementation leads to `μ.toFinite ≠ μ` even if -`μ` is a probability measure. +Our definition of `MeasureTheory.Measure.toFinite` ensures some extra properties: -We use this construction to define a set `μ.sigmaFiniteSet`, such that `μ.restrict μ.sigmaFiniteSet` -is sigma-finite, and for all measurable sets `s ⊆ μ.sigmaFiniteSetᶜ`, either `μ s = 0` -or `μ s = ∞`. +- if `μ` is a finite measure, then `μ.toFinite = μ[|univ] = (μ univ)⁻¹ • μ`; +- in particular, `μ.toFinite = μ` for a probability measure; +- if `μ ≠ 0`, then `μ.toFinite` is a probability measure. ## Main definitions @@ -26,18 +26,19 @@ In these definitions and the results below, `μ` is an s-finite measure (`SFinit * `MeasureTheory.Measure.toFinite`: a finite measure with `μ ≪ μ.toFinite` and `μ.toFinite ≪ μ`. If `μ ≠ 0`, this is a probability measure. -* `MeasureTheory.Measure.densityToFinite`: a measurable function such that - `μ = μ.toFinite.withDensity μ.densityToFinite`. +* `MeasureTheory.Measure.densityToFinite` (deprecated, use `MeasureTheory.Measure.rnDeriv`): + the Radon-Nikodym derivative of `μ.toFinite` with respect to `μ`. ## Main statements * `absolutelyContinuous_toFinite`: `μ ≪ μ.toFinite`. * `toFinite_absolutelyContinuous`: `μ.toFinite ≪ μ`. -* `withDensity_densitytoFinite`: `μ.toFinite.withDensity μ.densityToFinite = μ`. +* `ae_toFinite`: `ae μ.toFinite = ae μ`. -/ -open scoped ENNReal +open Set +open scoped ENNReal ProbabilityTheory namespace MeasureTheory @@ -45,129 +46,101 @@ variable {α : Type*} {mα : MeasurableSpace α} {μ : Measure α} /-- Auxiliary definition for `MeasureTheory.Measure.toFinite`. -/ noncomputable def Measure.toFiniteAux (μ : Measure α) [SFinite μ] : Measure α := - Measure.sum (fun n ↦ (2 ^ (n + 1) * sFiniteSeq μ n Set.univ)⁻¹ • sFiniteSeq μ n) + letI := Classical.dec + if IsFiniteMeasure μ then μ else (exists_isFiniteMeasure_absolutelyContinuous μ).choose /-- A finite measure obtained from an s-finite measure `μ`, such that `μ = μ.toFinite.withDensity μ.densityToFinite` (see `withDensity_densitytoFinite`). If `μ` is non-zero, this is a probability measure. -/ noncomputable def Measure.toFinite (μ : Measure α) [SFinite μ] : Measure α := - ProbabilityTheory.cond μ.toFiniteAux Set.univ + μ.toFiniteAux[|univ] + +@[local simp] +lemma ae_toFiniteAux [SFinite μ] : ae μ.toFiniteAux = ae μ := by + rw [Measure.toFiniteAux] + split_ifs + · simp + · obtain ⟨_, h₁, h₂⟩ := (exists_isFiniteMeasure_absolutelyContinuous μ).choose_spec + exact h₂.ae_le.antisymm h₁.ae_le + +@[local instance] +theorem isFiniteMeasure_toFiniteAux [SFinite μ] : IsFiniteMeasure μ.toFiniteAux := by + rw [Measure.toFiniteAux] + split_ifs + · assumption + · exact (exists_isFiniteMeasure_absolutelyContinuous μ).choose_spec.1 -lemma toFiniteAux_apply (μ : Measure α) [SFinite μ] (s : Set α) : - μ.toFiniteAux s = ∑' n, (2 ^ (n + 1) * sFiniteSeq μ n Set.univ)⁻¹ * sFiniteSeq μ n s := by - rw [Measure.toFiniteAux, Measure.sum_apply_of_countable]; rfl - -lemma toFinite_apply (μ : Measure α) [SFinite μ] (s : Set α) : - μ.toFinite s = (μ.toFiniteAux Set.univ)⁻¹ * μ.toFiniteAux s := by - rw [Measure.toFinite, ProbabilityTheory.cond_apply _ MeasurableSet.univ, Set.univ_inter] - -lemma toFiniteAux_zero : Measure.toFiniteAux (0 : Measure α) = 0 := by - ext s - simp [toFiniteAux_apply] +@[simp] +lemma ae_toFinite [SFinite μ] : ae μ.toFinite = ae μ := by + simp [Measure.toFinite, ProbabilityTheory.cond] @[simp] -lemma toFinite_zero : Measure.toFinite (0 : Measure α) = 0 := by - simp [Measure.toFinite, toFiniteAux_zero] - -lemma toFiniteAux_eq_zero_iff [SFinite μ] : μ.toFiniteAux = 0 ↔ μ = 0 := by - refine ⟨fun h ↦ ?_, fun h ↦ by simp [h, toFiniteAux_zero]⟩ - ext s hs - rw [Measure.ext_iff] at h - specialize h s hs - simp only [toFiniteAux_apply, Measure.coe_zero, Pi.zero_apply, - ENNReal.tsum_eq_zero, mul_eq_zero, ENNReal.inv_eq_zero] at h - rw [← sum_sFiniteSeq μ, Measure.sum_apply _ hs] - simp only [Measure.coe_zero, Pi.zero_apply, ENNReal.tsum_eq_zero] - intro n - specialize h n - simpa [ENNReal.mul_eq_top, measure_ne_top] using h - -lemma toFiniteAux_univ_le_one (μ : Measure α) [SFinite μ] : μ.toFiniteAux Set.univ ≤ 1 := by - rw [toFiniteAux_apply] - have h_le_pow : ∀ n, (2 ^ (n + 1) * sFiniteSeq μ n Set.univ)⁻¹ * sFiniteSeq μ n Set.univ - ≤ (2 ^ (n + 1))⁻¹ := by - intro n - by_cases h_zero : sFiniteSeq μ n = 0 - · simp [h_zero] - · rw [ENNReal.le_inv_iff_mul_le, mul_assoc, mul_comm (sFiniteSeq μ n Set.univ), - ENNReal.inv_mul_cancel] - · simp [h_zero] - · exact ENNReal.mul_ne_top (by simp) (measure_ne_top _ _) - refine (tsum_le_tsum h_le_pow ENNReal.summable ENNReal.summable).trans ?_ - simp [ENNReal.inv_pow, ENNReal.tsum_geometric_add_one, ENNReal.inv_mul_cancel] - -instance [SFinite μ] : IsFiniteMeasure μ.toFiniteAux := - ⟨(toFiniteAux_univ_le_one μ).trans_lt ENNReal.one_lt_top⟩ +lemma toFinite_apply_eq_zero_iff [SFinite μ] {s : Set α} : μ.toFinite s = 0 ↔ μ s = 0 := by + simp only [← compl_mem_ae_iff, ae_toFinite] @[simp] lemma toFinite_eq_zero_iff [SFinite μ] : μ.toFinite = 0 ↔ μ = 0 := by - simp [Measure.toFinite, measure_ne_top μ.toFiniteAux Set.univ, toFiniteAux_eq_zero_iff] + simp_rw [← Measure.measure_univ_eq_zero, toFinite_apply_eq_zero_iff] + +@[simp] +lemma toFinite_zero : Measure.toFinite (0 : Measure α) = 0 := by simp + +lemma toFinite_eq_self [IsProbabilityMeasure μ] : μ.toFinite = μ := by + rw [Measure.toFinite, Measure.toFiniteAux, if_pos, ProbabilityTheory.cond_univ] + infer_instance instance [SFinite μ] : IsFiniteMeasure μ.toFinite := by rw [Measure.toFinite] infer_instance -instance [SFinite μ] [h_zero : NeZero μ] : IsProbabilityMeasure μ.toFinite := by - refine ProbabilityTheory.cond_isProbabilityMeasure μ.toFiniteAux ?_ - simp [toFiniteAux_eq_zero_iff, h_zero.out] - -lemma sFiniteSeq_absolutelyContinuous_toFiniteAux (μ : Measure α) [SFinite μ] (n : ℕ) : - sFiniteSeq μ n ≪ μ.toFiniteAux := by - refine Measure.absolutelyContinuous_sum_right n (Measure.absolutelyContinuous_smul ?_) - simp only [ne_eq, ENNReal.inv_eq_zero] - exact ENNReal.mul_ne_top (by simp) (measure_ne_top _ _) +instance [SFinite μ] [NeZero μ] : IsProbabilityMeasure μ.toFinite := by + apply ProbabilityTheory.cond_isProbabilityMeasure + simp [ne_eq, ← compl_mem_ae_iff, ae_toFiniteAux] -lemma toFiniteAux_absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] : - μ.toFiniteAux ≪ μ.toFinite := ProbabilityTheory.absolutelyContinuous_cond_univ +lemma absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] : μ ≪ μ.toFinite := + Measure.ae_le_iff_absolutelyContinuous.mp ae_toFinite.ge -lemma sFiniteSeq_absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] (n : ℕ) : - sFiniteSeq μ n ≪ μ.toFinite := - (sFiniteSeq_absolutelyContinuous_toFiniteAux μ n).trans - (toFiniteAux_absolutelyContinuous_toFinite μ) +lemma sfiniteSeq_absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] (n : ℕ) : + sfiniteSeq μ n ≪ μ.toFinite := + (sfiniteSeq_le μ n).absolutelyContinuous.trans (absolutelyContinuous_toFinite μ) -lemma absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] : μ ≪ μ.toFinite := by - conv_lhs => rw [← sum_sFiniteSeq μ] - exact Measure.absolutelyContinuous_sum_left (sFiniteSeq_absolutelyContinuous_toFinite μ) +@[deprecated (since := "2024-10-11")] +alias sFiniteSeq_absolutelyContinuous_toFinite := sfiniteSeq_absolutelyContinuous_toFinite -lemma toFinite_absolutelyContinuous (μ : Measure α) [SFinite μ] : μ.toFinite ≪ μ := by - conv_rhs => rw [← sum_sFiniteSeq μ] - refine Measure.AbsolutelyContinuous.mk (fun s hs hs0 ↦ ?_) - simp only [Measure.sum_apply _ hs, ENNReal.tsum_eq_zero] at hs0 - simp [toFinite_apply, toFiniteAux_apply, hs0] +lemma toFinite_absolutelyContinuous (μ : Measure α) [SFinite μ] : μ.toFinite ≪ μ := + Measure.ae_le_iff_absolutelyContinuous.mp ae_toFinite.le /-- A measurable function such that `μ.toFinite.withDensity μ.densityToFinite = μ`. See `withDensity_densitytoFinite`. -/ -noncomputable -def Measure.densityToFinite (μ : Measure α) [SFinite μ] (a : α) : ℝ≥0∞ := - ∑' n, (sFiniteSeq μ n).rnDeriv μ.toFinite a +@[deprecated rnDeriv (since := "2024-10-04")] +noncomputable def Measure.densityToFinite (μ : Measure α) [SFinite μ] (a : α) : ℝ≥0∞ := + μ.rnDeriv μ.toFinite a +set_option linter.deprecated false in +@[deprecated (since := "2024-10-04")] lemma densityToFinite_def (μ : Measure α) [SFinite μ] : - μ.densityToFinite = fun a ↦ ∑' n, (sFiniteSeq μ n).rnDeriv μ.toFinite a := rfl + μ.densityToFinite = μ.rnDeriv μ.toFinite := + rfl +set_option linter.deprecated false in +@[deprecated Measure.measurable_rnDeriv (since := "2024-10-04")] lemma measurable_densityToFinite (μ : Measure α) [SFinite μ] : Measurable μ.densityToFinite := - Measurable.ennreal_tsum fun _ ↦ Measure.measurable_rnDeriv _ _ + Measure.measurable_rnDeriv _ _ +set_option linter.deprecated false in +@[deprecated Measure.withDensity_rnDeriv_eq (since := "2024-10-04")] theorem withDensity_densitytoFinite (μ : Measure α) [SFinite μ] : - μ.toFinite.withDensity μ.densityToFinite = μ := by - have : (μ.toFinite.withDensity fun a ↦ ∑' n, (sFiniteSeq μ n).rnDeriv μ.toFinite a) - = μ.toFinite.withDensity (∑' n, (sFiniteSeq μ n).rnDeriv μ.toFinite) := by - congr with a - rw [ENNReal.tsum_apply] - rw [densityToFinite_def, this, withDensity_tsum (fun i ↦ Measure.measurable_rnDeriv _ _)] - conv_rhs => rw [← sum_sFiniteSeq μ] - congr with n - rw [Measure.withDensity_rnDeriv_eq] - exact sFiniteSeq_absolutelyContinuous_toFinite μ n + μ.toFinite.withDensity μ.densityToFinite = μ := + Measure.withDensity_rnDeriv_eq _ _ (absolutelyContinuous_toFinite _) +set_option linter.deprecated false in +@[deprecated Measure.rnDeriv_lt_top (since := "2024-10-04")] lemma densityToFinite_ae_lt_top (μ : Measure α) [SigmaFinite μ] : - ∀ᵐ x ∂μ, μ.densityToFinite x < ∞ := by - refine ae_of_forall_measure_lt_top_ae_restrict _ (fun s _ hμs ↦ ?_) - suffices ∀ᵐ x ∂μ.toFinite.restrict s, μ.densityToFinite x < ∞ from - (absolutelyContinuous_toFinite μ).restrict _ this - refine ae_lt_top (measurable_densityToFinite μ) ?_ - rw [← withDensity_apply', withDensity_densitytoFinite] - exact hμs.ne + ∀ᵐ x ∂μ, μ.densityToFinite x < ∞ := + (absolutelyContinuous_toFinite μ).ae_le <| Measure.rnDeriv_lt_top _ _ +set_option linter.deprecated false in +@[deprecated Measure.rnDeriv_ne_top (since := "2024-10-04")] lemma densityToFinite_ae_ne_top (μ : Measure α) [SigmaFinite μ] : ∀ᵐ x ∂μ, μ.densityToFinite x ≠ ∞ := (densityToFinite_ae_lt_top μ).mono (fun _ hx ↦ hx.ne) diff --git a/Mathlib/MeasureTheory/Measure/WithDensityVectorMeasure.lean b/Mathlib/MeasureTheory/Measure/WithDensityVectorMeasure.lean index 91e480a646863..095d95dd608a0 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensityVectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensityVectorMeasure.lean @@ -26,13 +26,13 @@ noncomputable section open scoped MeasureTheory NNReal ENNReal -variable {α β : Type*} {m : MeasurableSpace α} +variable {α : Type*} {m : MeasurableSpace α} namespace MeasureTheory open TopologicalSpace -variable {μ ν : Measure α} +variable {μ : Measure α} variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] open Classical in @@ -42,7 +42,7 @@ def Measure.withDensityᵥ {m : MeasurableSpace α} (μ : Measure α) (f : α if hf : Integrable f μ then { measureOf' := fun s => if MeasurableSet s then ∫ x in s, f x ∂μ else 0 empty' := by simp - not_measurable' := fun s hs => if_neg hs + not_measurable' := fun _ hs => if_neg hs m_iUnion' := fun s hs₁ hs₂ => by dsimp only convert hasSum_integral_iUnion hs₁ hs₂ hf.integrableOn with n diff --git a/Mathlib/MeasureTheory/Order/UpperLower.lean b/Mathlib/MeasureTheory/Order/UpperLower.lean index 6e04d112e9d58..3813db3c363dd 100644 --- a/Mathlib/MeasureTheory/Order/UpperLower.lean +++ b/Mathlib/MeasureTheory/Order/UpperLower.lean @@ -48,7 +48,7 @@ Generalize so that it also applies to `ℝ × ℝ`, for example. open Filter MeasureTheory Metric Set open scoped Topology -variable {ι : Type*} [Fintype ι] {s : Set (ι → ℝ)} {x y : ι → ℝ} {δ : ℝ} +variable {ι : Type*} [Fintype ι] {s : Set (ι → ℝ)} {x : ι → ℝ} /-- If we can fit a small ball inside a set `s` intersected with any neighborhood of `x`, then the density of `s` near `x` is not `0`. diff --git a/Mathlib/MeasureTheory/OuterMeasure/Defs.lean b/Mathlib/MeasureTheory/OuterMeasure/Defs.lean index e1169e732155e..a776ff90e2c9c 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/Defs.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/Defs.lean @@ -62,9 +62,6 @@ instance : FunLike (OuterMeasure α) (Set α) ℝ≥0∞ where coe m := m.measureOf coe_injective' | ⟨_, _, _, _⟩, ⟨_, _, _, _⟩, rfl => rfl -instance instCoeFun : CoeFun (OuterMeasure α) (fun _ => Set α → ℝ≥0∞) := - inferInstance - @[simp] theorem measureOf_eq_coe (m : OuterMeasure α) : m.measureOf = m := rfl instance : OuterMeasureClass (OuterMeasure α) α where diff --git a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean index 7e859de1147fc..ac7e4d2a1aaca 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean @@ -57,7 +57,7 @@ protected def ofFunction (m : Set α → ℝ≥0∞) (m_empty : m ∅ = 0) : Out le_antisymm ((iInf_le_of_le fun _ => ∅) <| iInf_le_of_le (empty_subset _) <| by simp [m_empty]) (zero_le _) - mono := fun {s₁ s₂} hs => iInf_mono fun f => iInf_mono' fun hb => ⟨hs.trans hb, le_rfl⟩ + mono := fun {_ _} hs => iInf_mono fun _ => iInf_mono' fun hb => ⟨hs.trans hb, le_rfl⟩ iUnion_nat := fun s _ => ENNReal.le_of_forall_pos_le_add <| by intro ε hε (hb : (∑' i, μ (s i)) < ∞) diff --git a/Mathlib/MeasureTheory/OuterMeasure/Operations.lean b/Mathlib/MeasureTheory/OuterMeasure/Operations.lean index 7dba544ed01e3..5362183b1260a 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/Operations.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/Operations.lean @@ -38,7 +38,7 @@ instance instZero : Zero (OuterMeasure α) := ⟨{ measureOf := fun _ => 0 empty := rfl mono := by intro _ _ _; exact le_refl 0 - iUnion_nat := fun s _ => zero_le _ }⟩ + iUnion_nat := fun _ _ => zero_le _ }⟩ @[simp] theorem coe_zero : ⇑(0 : OuterMeasure α) = 0 := @@ -51,7 +51,7 @@ instance instAdd : Add (OuterMeasure α) := ⟨fun m₁ m₂ => { measureOf := fun s => m₁ s + m₂ s empty := show m₁ ∅ + m₂ ∅ = 0 by simp [OuterMeasure.empty] - mono := fun {s₁ s₂} h => add_le_add (m₁.mono h) (m₂.mono h) + mono := fun {_ _} h => add_le_add (m₁.mono h) (m₂.mono h) iUnion_nat := fun s _ => calc m₁ (⋃ i, s i) + m₂ (⋃ i, s i) ≤ (∑' i, m₁ (s i)) + ∑' i, m₂ (s i) := @@ -135,9 +135,9 @@ theorem coe_bot : (⊥ : OuterMeasure α) = 0 := instance instPartialOrder : PartialOrder (OuterMeasure α) where le m₁ m₂ := ∀ s, m₁ s ≤ m₂ s - le_refl a s := le_rfl - le_trans a b c hab hbc s := le_trans (hab s) (hbc s) - le_antisymm a b hab hba := ext fun s => le_antisymm (hab s) (hba s) + le_refl _ _ := le_rfl + le_trans _ _ _ hab hbc s := le_trans (hab s) (hbc s) + le_antisymm _ _ hab hba := ext fun s => le_antisymm (hab s) (hba s) instance orderBot : OrderBot (OuterMeasure α) := { bot := 0, @@ -152,7 +152,7 @@ instance instSupSet : SupSet (OuterMeasure α) := ⟨fun ms => { measureOf := fun s => ⨆ m ∈ ms, (m : OuterMeasure α) s empty := nonpos_iff_eq_zero.1 <| iSup₂_le fun m _ => le_of_eq m.empty - mono := fun {s₁ s₂} hs => iSup₂_mono fun m _ => m.mono hs + mono := fun {_ _} hs => iSup₂_mono fun m _ => m.mono hs iUnion_nat := fun f _ => iSup₂_le fun m hm => calc @@ -164,7 +164,7 @@ instance instSupSet : SupSet (OuterMeasure α) := instance instCompleteLattice : CompleteLattice (OuterMeasure α) := { OuterMeasure.orderBot, completeLatticeOfSup (OuterMeasure α) fun ms => - ⟨fun m hm s => by apply le_iSup₂ m hm, fun m hm s => iSup₂_le fun m' hm' => hm hm' s⟩ with } + ⟨fun m hm s => by apply le_iSup₂ m hm, fun _ hm s => iSup₂_le fun _ hm' => hm hm' s⟩ with } @[simp] theorem sSup_apply (ms : Set (OuterMeasure α)) (s : Set α) : @@ -200,10 +200,10 @@ def map {β} (f : α → β) : OuterMeasure α →ₗ[ℝ≥0∞] OuterMeasure toFun m := { measureOf := fun s => m (f ⁻¹' s) empty := m.empty - mono := fun {s t} h => m.mono (preimage_mono h) + mono := fun {_ _} h => m.mono (preimage_mono h) iUnion_nat := fun s _ => by simpa using measure_iUnion_le fun i => f ⁻¹' s i } - map_add' m₁ m₂ := coe_fn_injective rfl - map_smul' c m := coe_fn_injective rfl + map_add' _ _ := coe_fn_injective rfl + map_smul' _ _ := coe_fn_injective rfl @[simp] theorem map_apply {β} (f : α → β) (m : OuterMeasure α) (s : Set β) : map f m s = m (f ⁻¹' s) := @@ -237,7 +237,7 @@ instance instLawfulFunctor : LawfulFunctor OuterMeasure := by constructor <;> in def dirac (a : α) : OuterMeasure α where measureOf s := indicator s (fun _ => 1) a empty := by simp - mono {s t} h := indicator_le_indicator_of_subset h (fun _ => zero_le _) a + mono {_ _} h := indicator_le_indicator_of_subset h (fun _ => zero_le _) a iUnion_nat s _ := calc indicator (⋃ n, s n) 1 a = ⨆ n, indicator (s n) 1 a := indicator_iUnion_apply (M := ℝ≥0∞) rfl _ _ _ @@ -251,7 +251,7 @@ theorem dirac_apply (a : α) (s : Set α) : dirac a s = indicator s (fun _ => 1) def sum {ι} (f : ι → OuterMeasure α) : OuterMeasure α where measureOf s := ∑' i, f i s empty := by simp - mono {s t} h := ENNReal.tsum_le_tsum fun i => measure_mono h + mono {_ _} h := ENNReal.tsum_le_tsum fun _ => measure_mono h iUnion_nat s _ := by rw [ENNReal.tsum_comm]; exact ENNReal.tsum_le_tsum fun i => measure_iUnion_le _ @@ -268,10 +268,10 @@ def comap {β} (f : α → β) : OuterMeasure β →ₗ[ℝ≥0∞] OuterMeasure toFun m := { measureOf := fun s => m (f '' s) empty := by simp - mono := fun {s t} h => m.mono <| image_subset f h + mono := fun {_ _} h => m.mono <| image_subset f h iUnion_nat := fun s _ => by simpa only [image_iUnion] using measure_iUnion_le _ } - map_add' m₁ m₂ := rfl - map_smul' c m := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl @[simp] theorem comap_apply {β} (f : α → β) (m : OuterMeasure β) (s : Set α) : comap f m s = m (f '' s) := @@ -341,7 +341,7 @@ theorem top_apply {s : Set α} (h : s.Nonempty) : (⊤ : OuterMeasure α) s = let ⟨a, as⟩ := h top_unique <| le_trans (by simp [smul_dirac_apply, as]) (le_iSup₂ (∞ • dirac a) trivial) -theorem top_apply' (s : Set α) : (⊤ : OuterMeasure α) s = ⨅ h : s = ∅, 0 := +theorem top_apply' (s : Set α) : (⊤ : OuterMeasure α) s = ⨅ _ : s = ∅, 0 := s.eq_empty_or_nonempty.elim (fun h => by simp [h]) fun h => by simp [h, h.ne_empty] @[simp] diff --git a/Mathlib/MeasureTheory/PiSystem.lean b/Mathlib/MeasureTheory/PiSystem.lean index aed108095fc15..2f16137420ef0 100644 --- a/Mathlib/MeasureTheory/PiSystem.lean +++ b/Mathlib/MeasureTheory/PiSystem.lean @@ -58,10 +58,12 @@ open MeasurableSpace Set open MeasureTheory +variable {α β : Type*} + /-- A π-system is a collection of subsets of `α` that is closed under binary intersection of non-disjoint sets. Usually it is also required that the collection is nonempty, but we don't do that here. -/ -def IsPiSystem {α} (C : Set (Set α)) : Prop := +def IsPiSystem (C : Set (Set α)) : Prop := ∀ᵉ (s ∈ C) (t ∈ C), (s ∩ t : Set α).Nonempty → s ∩ t ∈ C namespace MeasurableSpace @@ -71,12 +73,12 @@ theorem isPiSystem_measurableSet {α : Type*} [MeasurableSpace α] : end MeasurableSpace -theorem IsPiSystem.singleton {α} (S : Set α) : IsPiSystem ({S} : Set (Set α)) := by +theorem IsPiSystem.singleton (S : Set α) : IsPiSystem ({S} : Set (Set α)) := by intro s h_s t h_t _ rw [Set.mem_singleton_iff.1 h_s, Set.mem_singleton_iff.1 h_t, Set.inter_self, Set.mem_singleton_iff] -theorem IsPiSystem.insert_empty {α} {S : Set (Set α)} (h_pi : IsPiSystem S) : +theorem IsPiSystem.insert_empty {S : Set (Set α)} (h_pi : IsPiSystem S) : IsPiSystem (insert ∅ S) := by intro s hs t ht hst cases' hs with hs hs @@ -85,7 +87,7 @@ theorem IsPiSystem.insert_empty {α} {S : Set (Set α)} (h_pi : IsPiSystem S) : · simp [ht] · exact Set.mem_insert_of_mem _ (h_pi s hs t ht hst) -theorem IsPiSystem.insert_univ {α} {S : Set (Set α)} (h_pi : IsPiSystem S) : +theorem IsPiSystem.insert_univ {S : Set (Set α)} (h_pi : IsPiSystem S) : IsPiSystem (insert Set.univ S) := by intro s hs t ht hst cases' hs with hs hs @@ -114,9 +116,16 @@ theorem isPiSystem_iUnion_of_monotone {α ι} [SemilatticeSup ι] (p : ι → Se (hp_pi : ∀ n, IsPiSystem (p n)) (hp_mono : Monotone p) : IsPiSystem (⋃ n, p n) := isPiSystem_iUnion_of_directed_le p hp_pi (Monotone.directed_le hp_mono) +/-- Rectangles formed by π-systems form a π-system. -/ +lemma IsPiSystem.prod {C : Set (Set α)} {D : Set (Set β)} (hC : IsPiSystem C) (hD : IsPiSystem D) : + IsPiSystem (image2 (· ×ˢ ·) C D) := by + rintro _ ⟨s₁, hs₁, t₁, ht₁, rfl⟩ _ ⟨s₂, hs₂, t₂, ht₂, rfl⟩ hst + rw [prod_inter_prod] at hst ⊢; rw [prod_nonempty_iff] at hst + exact mem_image2_of_mem (hC _ hs₁ _ hs₂ hst.1) (hD _ ht₁ _ ht₂ hst.2) + section Order -variable {α : Type*} {ι ι' : Sort*} [LinearOrder α] +variable {ι ι' : Sort*} [LinearOrder α] theorem isPiSystem_image_Iio (s : Set α) : IsPiSystem (Iio '' s) := by rintro _ ⟨a, ha, rfl⟩ _ ⟨b, hb, rfl⟩ - @@ -194,45 +203,45 @@ end Order /-- Given a collection `S` of subsets of `α`, then `generatePiSystem S` is the smallest π-system containing `S`. -/ -inductive generatePiSystem {α} (S : Set (Set α)) : Set (Set α) +inductive generatePiSystem (S : Set (Set α)) : Set (Set α) | base {s : Set α} (h_s : s ∈ S) : generatePiSystem S s | inter {s t : Set α} (h_s : generatePiSystem S s) (h_t : generatePiSystem S t) (h_nonempty : (s ∩ t).Nonempty) : generatePiSystem S (s ∩ t) -theorem isPiSystem_generatePiSystem {α} (S : Set (Set α)) : IsPiSystem (generatePiSystem S) := +theorem isPiSystem_generatePiSystem (S : Set (Set α)) : IsPiSystem (generatePiSystem S) := fun _ h_s _ h_t h_nonempty => generatePiSystem.inter h_s h_t h_nonempty -theorem subset_generatePiSystem_self {α} (S : Set (Set α)) : S ⊆ generatePiSystem S := fun _ => +theorem subset_generatePiSystem_self (S : Set (Set α)) : S ⊆ generatePiSystem S := fun _ => generatePiSystem.base -theorem generatePiSystem_subset_self {α} {S : Set (Set α)} (h_S : IsPiSystem S) : +theorem generatePiSystem_subset_self {S : Set (Set α)} (h_S : IsPiSystem S) : generatePiSystem S ⊆ S := fun x h => by induction h with | base h_s => exact h_s | inter _ _ h_nonempty h_s h_u => exact h_S _ h_s _ h_u h_nonempty -theorem generatePiSystem_eq {α} {S : Set (Set α)} (h_pi : IsPiSystem S) : generatePiSystem S = S := +theorem generatePiSystem_eq {S : Set (Set α)} (h_pi : IsPiSystem S) : generatePiSystem S = S := Set.Subset.antisymm (generatePiSystem_subset_self h_pi) (subset_generatePiSystem_self S) -theorem generatePiSystem_mono {α} {S T : Set (Set α)} (hST : S ⊆ T) : +theorem generatePiSystem_mono {S T : Set (Set α)} (hST : S ⊆ T) : generatePiSystem S ⊆ generatePiSystem T := fun t ht => by induction ht with | base h_s => exact generatePiSystem.base (Set.mem_of_subset_of_mem hST h_s) | inter _ _ h_nonempty h_s h_u => exact isPiSystem_generatePiSystem T _ h_s _ h_u h_nonempty -theorem generatePiSystem_measurableSet {α} [M : MeasurableSpace α] {S : Set (Set α)} +theorem generatePiSystem_measurableSet [M : MeasurableSpace α] {S : Set (Set α)} (h_meas_S : ∀ s ∈ S, MeasurableSet s) (t : Set α) (h_in_pi : t ∈ generatePiSystem S) : MeasurableSet t := by induction h_in_pi with | base h_s => apply h_meas_S _ h_s | inter _ _ _ h_s h_u => apply MeasurableSet.inter h_s h_u -theorem generateFrom_measurableSet_of_generatePiSystem {α} {g : Set (Set α)} (t : Set α) +theorem generateFrom_measurableSet_of_generatePiSystem {g : Set (Set α)} (t : Set α) (ht : t ∈ generatePiSystem g) : MeasurableSet[generateFrom g] t := @generatePiSystem_measurableSet α (generateFrom g) g (fun _ h_s_in_g => measurableSet_generateFrom h_s_in_g) t ht -theorem generateFrom_generatePiSystem_eq {α} {g : Set (Set α)} : +theorem generateFrom_generatePiSystem_eq {g : Set (Set α)} : generateFrom (generatePiSystem g) = generateFrom g := by apply le_antisymm <;> apply generateFrom_le · exact fun t h_t => generateFrom_measurableSet_of_generatePiSystem t h_t @@ -535,14 +544,14 @@ theorem has_diff {s₁ s₂ : Set α} (h₁ : d.Has s₁) (h₂ : d.Has s₂) (h instance instLEDynkinSystem : LE (DynkinSystem α) where le m₁ m₂ := m₁.Has ≤ m₂.Has -theorem le_def {α} {a b : DynkinSystem α} : a ≤ b ↔ a.Has ≤ b.Has := +theorem le_def {a b : DynkinSystem α} : a ≤ b ↔ a.Has ≤ b.Has := Iff.rfl instance : PartialOrder (DynkinSystem α) := { DynkinSystem.instLEDynkinSystem with - le_refl := fun a b => le_rfl - le_trans := fun a b c hab hbc => le_def.mpr (le_trans hab hbc) - le_antisymm := fun a b h₁ h₂ => ext fun s => ⟨h₁ s, h₂ s⟩ } + le_refl := fun _ _ => le_rfl + le_trans := fun _ _ _ hab hbc => le_def.mpr (le_trans hab hbc) + le_antisymm := fun _ _ h₁ h₂ => ext fun s => ⟨h₁ s, h₂ s⟩ } /-- Every measurable space (σ-algebra) forms a Dynkin system -/ def ofMeasurableSpace (m : MeasurableSpace α) : DynkinSystem α where @@ -588,7 +597,7 @@ def toMeasurableSpace (h_inter : ∀ s₁ s₂, d.Has s₁ → d.Has s₂ → d. MeasurableSpace α where MeasurableSet' := d.Has measurableSet_empty := d.has_empty - measurableSet_compl s h := d.has_compl h + measurableSet_compl _ h := d.has_compl h measurableSet_iUnion f hf := by rw [← iUnion_disjointed] exact @@ -647,7 +656,7 @@ theorem generate_inter {s : Set (Set α)} (hs : IsPiSystem s) {t₁ t₂ : Set additionally that it is non-empty, but we drop this condition in the formalization). -/ theorem generateFrom_eq {s : Set (Set α)} (hs : IsPiSystem s) : - generateFrom s = (generate s).toMeasurableSpace fun t₁ t₂ => generate_inter hs := + generateFrom s = (generate s).toMeasurableSpace fun _ _ => generate_inter hs := le_antisymm (generateFrom_le fun t ht => GenerateHas.basic t ht) (ofMeasurableSpace_le_ofMeasurableSpace_iff.mp <| by rw [ofMeasurableSpace_toMeasurableSpace] diff --git a/Mathlib/MeasureTheory/SetSemiring.lean b/Mathlib/MeasureTheory/SetSemiring.lean index 0727d10d8f8f5..9df3fa00df048 100644 --- a/Mathlib/MeasureTheory/SetSemiring.lean +++ b/Mathlib/MeasureTheory/SetSemiring.lean @@ -291,7 +291,7 @@ lemma inter_mem (hC : IsSetRing C) (hs : s ∈ C) (ht : t ∈ C) : s ∩ t ∈ C lemma isSetSemiring (hC : IsSetRing C) : IsSetSemiring C where empty_mem := hC.empty_mem - inter_mem := fun s hs t ht => hC.inter_mem hs ht + inter_mem := fun _ hs _ ht => hC.inter_mem hs ht diff_eq_sUnion' := by refine fun s hs t ht => ⟨{s \ t}, ?_, ?_, ?_⟩ · simp only [coe_singleton, Set.singleton_subset_iff] diff --git a/Mathlib/ModelTheory/Algebra/Field/CharP.lean b/Mathlib/ModelTheory/Algebra/Field/CharP.lean index 03491be723527..021b368387935 100644 --- a/Mathlib/ModelTheory/Algebra/Field/CharP.lean +++ b/Mathlib/ModelTheory/Algebra/Field/CharP.lean @@ -4,8 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.Algebra.CharP.Defs -import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Algebra.CharP.Basic import Mathlib.ModelTheory.Algebra.Ring.FreeCommRing import Mathlib.ModelTheory.Algebra.Field.Basic diff --git a/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean b/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean index 2d7efbda8ea35..54708abe18b61 100644 --- a/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean +++ b/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean @@ -49,7 +49,7 @@ namespace FirstOrder namespace Field -open Ring FreeCommRing BigOperators Polynomial Language +open Ring FreeCommRing Polynomial Language /-- A generic monic polynomial of degree `n` as an element of the free commutative ring in `n+1` variables, with a variable for each diff --git a/Mathlib/ModelTheory/Basic.lean b/Mathlib/ModelTheory/Basic.lean index baa0ada8d4271..08419dda7c6f0 100644 --- a/Mathlib/ModelTheory/Basic.lean +++ b/Mathlib/ModelTheory/Basic.lean @@ -296,9 +296,6 @@ instance homClass : HomClass L (M →[L] N) M N where instance [L.IsAlgebraic] : StrongHomClass L (M →[L] N) M N := HomClass.strongHomClassOfIsAlgebraic -instance hasCoeToFun : CoeFun (M →[L] N) fun _ => M → N := - DFunLike.hasCoeToFun - @[simp] theorem toFun_eq_coe {f : M →[L] N} : f.toFun = (f : M → N) := rfl @@ -379,7 +376,7 @@ instance funLike : FunLike (M ↪[L] N) M N where cases g congr ext x - exact Function.funext_iff.1 h x + exact funext_iff.1 h x instance embeddingLike : EmbeddingLike (M ↪[L] N) M N where injective' f := f.toEmbedding.injective @@ -416,7 +413,7 @@ theorem coe_injective : @Function.Injective (M ↪[L] N) (M → N) (↑) cases g congr ext x - exact Function.funext_iff.1 h x + exact funext_iff.1 h x @[ext] theorem ext ⦃f g : M ↪[L] N⦄ (h : ∀ x, f x = g x) : f = g := @@ -537,7 +534,7 @@ instance : EquivLike (M ≃[L] N) M N where cases g simp only [mk.injEq] ext x - exact Function.funext_iff.1 h₁ x + exact funext_iff.1 h₁ x instance : StrongHomClass L (M ≃[L] N) M N where map_fun := map_fun' @@ -557,9 +554,6 @@ def symm (f : M ≃[L] N) : N ≃[L] M := refine (f.map_rel' r (f.toEquiv.symm ∘ x)).symm.trans ?_ rw [← Function.comp_assoc, Equiv.toFun_as_coe, Equiv.self_comp_symm, Function.id_comp] } -instance hasCoeToFun : CoeFun (M ≃[L] N) fun _ => M → N := - DFunLike.hasCoeToFun - @[simp] theorem symm_symm (f : M ≃[L] N) : f.symm.symm = f := diff --git a/Mathlib/ModelTheory/Complexity.lean b/Mathlib/ModelTheory/Complexity.lean index e4d9bfc7ef31f..a44a3ddcd67f9 100644 --- a/Mathlib/ModelTheory/Complexity.lean +++ b/Mathlib/ModelTheory/Complexity.lean @@ -34,11 +34,8 @@ namespace FirstOrder namespace Language -variable {L : Language.{u, v}} {L' : Language} -variable {M : Type w} {N P : Type*} [L.Structure M] [L.Structure N] [L.Structure P] -variable {α : Type u'} {β : Type v'} {γ : Type*} -variable {n l : ℕ} {φ ψ : L.BoundedFormula α l} {θ : L.BoundedFormula α l.succ} -variable {v : α → M} {xs : Fin l → M} +variable {L : Language.{u, v}} {M : Type w} [L.Structure M] {α : Type u'} {β : Type v'} +variable {n l : ℕ} {φ : L.BoundedFormula α l} open FirstOrder Structure Fin diff --git a/Mathlib/ModelTheory/DirectLimit.lean b/Mathlib/ModelTheory/DirectLimit.lean index 3a74358878660..bc5cfde3f62f1 100644 --- a/Mathlib/ModelTheory/DirectLimit.lean +++ b/Mathlib/ModelTheory/DirectLimit.lean @@ -7,6 +7,7 @@ import Mathlib.Data.Fintype.Order import Mathlib.Algebra.DirectLimit import Mathlib.ModelTheory.Quotients import Mathlib.ModelTheory.FinitelyGenerated +import Mathlib.Data.Finite.Sum /-! # Direct Limits of First-Order Structures @@ -72,7 +73,7 @@ theorem coe_natLERec (m n : ℕ) (h : m ≤ n) : Embedding.comp_apply, ih] instance natLERec.directedSystem : DirectedSystem G' fun i j h => natLERec f' i j h := - ⟨fun i x _ => congr (congr rfl (Nat.leRecOn_self _)) rfl, + ⟨fun _ _ _ => congr (congr rfl (Nat.leRecOn_self _)) rfl, fun hij hjk => by simp [Nat.leRecOn_trans hij hjk]⟩ end DirectedSystem @@ -104,7 +105,7 @@ variable [DirectedSystem G fun i j h => f i j h] @[simp] theorem unify_sigma_mk_self {α : Type*} {i : ι} {x : α → G i} : - (unify f (fun a => .mk f i (x a)) i fun j ⟨a, hj⟩ => + (unify f (fun a => .mk f i (x a)) i fun _ ⟨_, hj⟩ => _root_.trans (le_of_eq hj.symm) (refl _)) = x := by ext a rw [unify] @@ -127,7 +128,7 @@ namespace DirectLimit def setoid [DirectedSystem G fun i j h => f i j h] [IsDirected ι (· ≤ ·)] : Setoid (Σˣ f) where r := fun ⟨i, x⟩ ⟨j, y⟩ => ∃ (k : ι) (ik : i ≤ k) (jk : j ≤ k), f i k ik x = f j k jk y iseqv := - ⟨fun ⟨i, x⟩ => ⟨i, refl i, refl i, rfl⟩, @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, ik, jk, h⟩ => + ⟨fun ⟨i, _⟩ => ⟨i, refl i, refl i, rfl⟩, @fun ⟨_, _⟩ ⟨_, _⟩ ⟨k, ik, jk, h⟩ => ⟨k, jk, ik, h.symm⟩, @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, z⟩ ⟨ij, hiij, hjij, hij⟩ ⟨jk, hjjk, hkjk, hjk⟩ => by obtain ⟨ijk, hijijk, hjkijk⟩ := directed_of (· ≤ ·) ij jk @@ -348,7 +349,7 @@ def lift (g : ∀ i, G i ↪[L] P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i rw [← Quotient.out_eq x, ← Quotient.out_eq y, Quotient.lift_mk, Quotient.lift_mk] at xy obtain ⟨i, hx, hy⟩ := directed_of (· ≤ ·) x.out.1 y.out.1 rw [← Hg x.out.1 i hx, ← Hg y.out.1 i hy] at xy - rw [← Quotient.out_eq x, ← Quotient.out_eq y, Quotient.eq, equiv_iff G f hx hy] + rw [← Quotient.out_eq x, ← Quotient.out_eq y, Quotient.eq_iff_equiv, equiv_iff G f hx hy] exact (g i).injective xy map_fun' F x := by obtain ⟨i, y, rfl⟩ := exists_quotient_mk'_sigma_mk'_eq G f x diff --git a/Mathlib/ModelTheory/ElementaryMaps.lean b/Mathlib/ModelTheory/ElementaryMaps.lean index 54428842a22a5..a8c9fc2716718 100644 --- a/Mathlib/ModelTheory/ElementaryMaps.lean +++ b/Mathlib/ModelTheory/ElementaryMaps.lean @@ -65,10 +65,7 @@ instance instFunLike : FunLike (M ↪ₑ[L] N) M N where cases g simp only [ElementaryEmbedding.mk.injEq] ext x - exact Function.funext_iff.1 h x - -instance : CoeFun (M ↪ₑ[L] N) fun _ => M → N := - DFunLike.hasCoeToFun + exact funext_iff.1 h x @[simp] theorem map_boundedFormula (f : M ↪ₑ[L] N) {α : Type*} {n : ℕ} (φ : L.BoundedFormula α n) diff --git a/Mathlib/ModelTheory/ElementarySubstructures.lean b/Mathlib/ModelTheory/ElementarySubstructures.lean index e0a575f7c8a3d..c2321b14f9d6a 100644 --- a/Mathlib/ModelTheory/ElementarySubstructures.lean +++ b/Mathlib/ModelTheory/ElementarySubstructures.lean @@ -29,8 +29,7 @@ namespace Language open Structure -variable {L : Language} {M : Type*} {N : Type*} {P : Type*} {Q : Type*} -variable [L.Structure M] [L.Structure N] [L.Structure P] [L.Structure Q] +variable {L : Language} {M : Type*} [L.Structure M] /-- A substructure is elementary when every formula applied to a tuple in the substructure agrees with its value in the overall structure. -/ diff --git a/Mathlib/ModelTheory/Encoding.lean b/Mathlib/ModelTheory/Encoding.lean index a9157aba577e8..8e4da06e5a48a 100644 --- a/Mathlib/ModelTheory/Encoding.lean +++ b/Mathlib/ModelTheory/Encoding.lean @@ -6,7 +6,7 @@ Authors: Aaron Anderson import Mathlib.Computability.Encoding import Mathlib.Logic.Small.List import Mathlib.ModelTheory.Syntax -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic /-! # Encodings and Cardinality of First-Order Syntax @@ -33,15 +33,14 @@ import Mathlib.SetTheory.Cardinal.Ordinal -/ -universe u v w u' v' +universe u v w u' namespace FirstOrder namespace Language variable {L : Language.{u, v}} -variable {M : Type w} {N P : Type*} [L.Structure M] [L.Structure N] [L.Structure P] -variable {α : Type u'} {β : Type v'} +variable {α : Type u'} open FirstOrder Cardinal diff --git a/Mathlib/ModelTheory/Graph.lean b/Mathlib/ModelTheory/Graph.lean index c4ce433290e9c..ed3a509c17c55 100644 --- a/Mathlib/ModelTheory/Graph.lean +++ b/Mathlib/ModelTheory/Graph.lean @@ -21,7 +21,7 @@ This file defines first-order languages, structures, and theories in graph theor of the theory of simple graphs. -/ -universe u v +universe u namespace FirstOrder @@ -31,7 +31,7 @@ open FirstOrder open Structure -variable {α : Type u} {V : Type v} {n : ℕ} +variable {V : Type u} {n : ℕ} /-! ### Simple Graphs -/ diff --git a/Mathlib/ModelTheory/Order.lean b/Mathlib/ModelTheory/Order.lean index af11c905aa569..775c86094849c 100644 --- a/Mathlib/ModelTheory/Order.lean +++ b/Mathlib/ModelTheory/Order.lean @@ -312,7 +312,7 @@ theorem realize_denselyOrdered [h : DenselyOrdered M] : variable (L) (M) -theorem denselyOrdered_of_dlo [h: M ⊨ L.dlo] : DenselyOrdered M := +theorem denselyOrdered_of_dlo [M ⊨ L.dlo] : DenselyOrdered M := realize_denselyOrdered_iff.1 (L.dlo.realize_sentence_of_mem (by simp only [dlo, Set.union_insert, Set.union_singleton, Set.mem_insert_iff, true_or, or_true])) @@ -533,7 +533,7 @@ theorem dlo_isComplete : Language.order.dlo.IsComplete := ⟨by letI : Language.order.Structure ℚ := orderStructure ℚ exact Theory.ModelType.of _ ℚ⟩ - fun M => inferInstance + fun _ => inferInstance end Fraisse diff --git a/Mathlib/ModelTheory/PartialEquiv.lean b/Mathlib/ModelTheory/PartialEquiv.lean index 3db2f33308397..49e73c8f359f2 100644 --- a/Mathlib/ModelTheory/PartialEquiv.lean +++ b/Mathlib/ModelTheory/PartialEquiv.lean @@ -40,8 +40,8 @@ namespace FirstOrder namespace Language -variable (L : Language.{u, v}) (M : Type w) (N : Type w') {P : Type*} -variable [L.Structure M] [L.Structure N] [L.Structure P] +variable (L : Language.{u, v}) (M : Type w) (N : Type w') +variable [L.Structure M] [L.Structure N] open FirstOrder Structure Substructure diff --git a/Mathlib/ModelTheory/Semantics.lean b/Mathlib/ModelTheory/Semantics.lean index 3da6c40283d18..f493fa1523a09 100644 --- a/Mathlib/ModelTheory/Semantics.lean +++ b/Mathlib/ModelTheory/Semantics.lean @@ -339,7 +339,7 @@ theorem realize_mapTermRel_add_castLe [L'.Structure M] {k : ℕ} (ft n t).realize (Sum.elim v' xs') = t.realize (Sum.elim (v xs') (xs' ∘ Fin.natAdd _))) (h2 : ∀ (n) (R : L.Relations n) (x : Fin n → M), RelMap (fr n R) x = RelMap R x) (hv : ∀ (n) (xs : Fin (k + n) → M) (x : M), @v (n + 1) (snoc xs x : Fin _ → M) = v xs) : - (φ.mapTermRel ft fr fun n => castLE (add_assoc _ _ _).symm.le).Realize v' xs ↔ + (φ.mapTermRel ft fr fun _ => castLE (add_assoc _ _ _).symm.le).Realize v' xs ↔ φ.Realize (v xs) (xs ∘ Fin.natAdd _) := by induction φ with | falsum => rfl @@ -466,10 +466,8 @@ theorem realize_all_liftAt_one_self {n : ℕ} {φ : L.BoundedFormula α n} {v : end BoundedFormula - --- Porting note: no `protected` attribute in Lean4 +-- Porting note: in Lean 3 we used these unprotected above, and then protected them here. -- attribute [protected] bounded_formula.falsum bounded_formula.equal bounded_formula.rel - -- attribute [protected] bounded_formula.imp bounded_formula.all namespace LHom @@ -492,11 +490,6 @@ theorem realize_onBoundedFormula [L'.Structure M] (φ : L →ᴸ L') [φ.IsExpan end LHom --- Porting note: no `protected` attribute in Lean4 --- attribute [protected] bounded_formula.falsum bounded_formula.equal bounded_formula.rel - --- attribute [protected] bounded_formula.imp bounded_formula.all - namespace Formula /-- A formula can be evaluated as true or false by giving values to each free variable. -/ diff --git a/Mathlib/ModelTheory/Substructures.lean b/Mathlib/ModelTheory/Substructures.lean index 0fc0993999295..8c088e8675107 100644 --- a/Mathlib/ModelTheory/Substructures.lean +++ b/Mathlib/ModelTheory/Substructures.lean @@ -635,7 +635,7 @@ def topEquiv : (⊤ : L.Substructure M) ≃[L] M where toFun := subtype ⊤ invFun m := ⟨m, mem_top m⟩ left_inv m := by simp - right_inv m := rfl + right_inv _ := rfl @[simp] theorem coe_topEquiv : @@ -684,7 +684,7 @@ def substructureReduct (φ : L →ᴸ L') [φ.IsExpansionOn M] : inj' S T h := by simp only [SetLike.coe_set_eq, Substructure.mk.injEq] at h exact h - map_rel_iff' {S T} := Iff.rfl + map_rel_iff' {_ _} := Iff.rfl variable (φ : L →ᴸ L') [φ.IsExpansionOn M] @@ -757,7 +757,7 @@ hom `M → p`. -/ def codRestrict (p : L.Substructure N) (f : M →[L] N) (h : ∀ c, f c ∈ p) : M →[L] p where toFun c := ⟨f c, h c⟩ map_fun' {n} f x := by aesop - map_rel' {n} R x h := f.map_rel R x h + map_rel' {_} R x h := f.map_rel R x h @[simp] theorem comp_codRestrict (f : M →[L] N) (g : N →[L] P) (p : L.Substructure P) (h : ∀ b, g b ∈ p) : @@ -847,8 +847,8 @@ theorem domRestrict_apply (f : M ↪[L] N) (p : L.Substructure M) (x : p) : f.do to an embedding `M → p`. -/ def codRestrict (p : L.Substructure N) (f : M ↪[L] N) (h : ∀ c, f c ∈ p) : M ↪[L] p where toFun := f.toHom.codRestrict p h - inj' a b ab := f.injective (Subtype.mk_eq_mk.1 ab) - map_fun' {n} F x := (f.toHom.codRestrict p h).map_fun' F x + inj' _ _ ab := f.injective (Subtype.mk_eq_mk.1 ab) + map_fun' {_} F x := (f.toHom.codRestrict p h).map_fun' F x map_rel' {n} r x := by simp only rw [← p.subtype.map_rel] @@ -888,7 +888,7 @@ noncomputable def substructureEquivMap (f : M ↪[L] N) (s : L.Substructure M) : (Classical.choose_spec (codRestrict (s.map f.toHom) (f.domRestrict s) (fun ⟨m, hm⟩ => ⟨m, hm, rfl⟩) ⟨m, hm⟩).2).2) - right_inv := fun ⟨n, hn⟩ => Subtype.mk_eq_mk.2 (Classical.choose_spec hn).2 + right_inv := fun ⟨_, hn⟩ => Subtype.mk_eq_mk.2 (Classical.choose_spec hn).2 map_fun' {n} f x := by aesop map_rel' {n} R x := by aesop @@ -908,7 +908,7 @@ theorem subtype_substructureEquivMap (f : M ↪[L] N) (s : L.Substructure M) : invFun n := Classical.choose n.2 left_inv m := f.injective (Classical.choose_spec (codRestrict f.toHom.range f f.toHom.mem_range_self m).2) - right_inv := fun ⟨n, hn⟩ => Subtype.mk_eq_mk.2 (Classical.choose_spec hn) + right_inv := fun ⟨_, hn⟩ => Subtype.mk_eq_mk.2 (Classical.choose_spec hn) map_fun' {n} f x := by aesop map_rel' {n} R x := by aesop diff --git a/Mathlib/ModelTheory/Syntax.lean b/Mathlib/ModelTheory/Syntax.lean index 7fa52ce76edb5..a70ace4f16815 100644 --- a/Mathlib/ModelTheory/Syntax.lean +++ b/Mathlib/ModelTheory/Syntax.lean @@ -61,8 +61,7 @@ namespace FirstOrder namespace Language variable (L : Language.{u, v}) {L' : Language} -variable {M : Type w} {N P : Type*} [L.Structure M] [L.Structure N] [L.Structure P] -variable {α : Type u'} {β : Type v'} {γ : Type*} +variable {M : Type w} {α : Type u'} {β : Type v'} {γ : Type*} open FirstOrder @@ -86,7 +85,7 @@ instance instDecidableEq [DecidableEq α] [∀ n, DecidableEq (L.Functions n)] : letI : DecidableEq (L.Term α) := instDecidableEq decidable_of_iff (f = h ▸ g ∧ ∀ i : Fin m, xs i = ys (Fin.cast h i)) <| by subst h - simp [Function.funext_iff] + simp [funext_iff] else .isFalse <| by simp [h] | .var _, .func _ _ | .func _ _, .var _ => .isFalse <| by simp @@ -472,8 +471,8 @@ def mapTermRel {g : ℕ → ℕ} (ft : ∀ n, L.Term (α ⊕ (Fin n)) → L'.Ter /-- Raises all of the `Fin`-indexed variables of a formula greater than or equal to `m` by `n'`. -/ def liftAt : ∀ {n : ℕ} (n' _m : ℕ), L.BoundedFormula α n → L.BoundedFormula α (n + n') := - fun {n} n' m φ => - φ.mapTermRel (fun k t => t.liftAt n' m) (fun _ => id) fun _ => + fun {_} n' m φ => + φ.mapTermRel (fun _ t => t.liftAt n' m) (fun _ => id) fun _ => castLE (by rw [add_assoc, add_comm 1, add_assoc]) @[simp] diff --git a/Mathlib/ModelTheory/Ultraproducts.lean b/Mathlib/ModelTheory/Ultraproducts.lean index c7c3922d198a4..dbe1d5d34724f 100644 --- a/Mathlib/ModelTheory/Ultraproducts.lean +++ b/Mathlib/ModelTheory/Ultraproducts.lean @@ -46,8 +46,8 @@ namespace Ultraproduct instance setoidPrestructure : L.Prestructure ((u : Filter α).productSetoid M) := { (u : Filter α).productSetoid M with toStructure := - { funMap := fun {n} f x a => funMap f fun i => x i a - RelMap := fun {n} r x => ∀ᶠ a : α in u, RelMap r fun i => x i a } + { funMap := fun {_} f x a => funMap f fun i => x i a + RelMap := fun {_} r x => ∀ᶠ a : α in u, RelMap r fun i => x i a } fun_equiv := fun {n} f x y xy => by refine mem_of_superset (iInter_mem.2 xy) fun a ha => ?_ simp only [Set.mem_iInter, Set.mem_setOf_eq] at ha @@ -153,7 +153,7 @@ it is true in is in the ultrafilter. -/ theorem sentence_realize (φ : L.Sentence) : (u : Filter α).Product M ⊨ φ ↔ ∀ᶠ a : α in u, M a ⊨ φ := by simp_rw [Sentence.Realize] - erw [← realize_formula_cast φ, iff_eq_eq] + rw [← realize_formula_cast φ, iff_eq_eq] exact congr rfl (Subsingleton.elim _ _) nonrec instance Product.instNonempty : Nonempty ((u : Filter α).Product M) := diff --git a/Mathlib/NumberTheory/ADEInequality.lean b/Mathlib/NumberTheory/ADEInequality.lean index aabf630647bb3..f6cf4a0e5c35e 100644 --- a/Mathlib/NumberTheory/ADEInequality.lean +++ b/Mathlib/NumberTheory/ADEInequality.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.Algebra.Order.Field.Basic import Mathlib.Algebra.Order.Ring.Rat import Mathlib.Data.Multiset.Sort import Mathlib.Data.PNat.Basic @@ -157,15 +156,15 @@ theorem lt_three {p q r : ℕ+} (hpq : p ≤ q) (hqr : q ≤ r) (H : 1 < sumInv have h3q := H.trans hpq have h3r := h3q.trans hqr have hp : (p : ℚ)⁻¹ ≤ 3⁻¹ := by - rw [inv_le_inv _ h3] + rw [inv_le_inv₀ _ h3] · assumption_mod_cast · norm_num have hq : (q : ℚ)⁻¹ ≤ 3⁻¹ := by - rw [inv_le_inv _ h3] + rw [inv_le_inv₀ _ h3] · assumption_mod_cast · norm_num have hr : (r : ℚ)⁻¹ ≤ 3⁻¹ := by - rw [inv_le_inv _ h3] + rw [inv_le_inv₀ _ h3] · assumption_mod_cast · norm_num calc @@ -178,11 +177,11 @@ theorem lt_four {q r : ℕ+} (hqr : q ≤ r) (H : 1 < sumInv {2, q, r}) : q < 4 rw [sumInv_pqr] have h4r := H.trans hqr have hq : (q : ℚ)⁻¹ ≤ 4⁻¹ := by - rw [inv_le_inv _ h4] + rw [inv_le_inv₀ _ h4] · assumption_mod_cast · norm_num have hr : (r : ℚ)⁻¹ ≤ 4⁻¹ := by - rw [inv_le_inv _ h4] + rw [inv_le_inv₀ _ h4] · assumption_mod_cast · norm_num calc @@ -194,7 +193,7 @@ theorem lt_six {r : ℕ+} (H : 1 < sumInv {2, 3, r}) : r < 6 := by contrapose! H rw [sumInv_pqr] have hr : (r : ℚ)⁻¹ ≤ 6⁻¹ := by - rw [inv_le_inv _ h6] + rw [inv_le_inv₀ _ h6] · assumption_mod_cast · norm_num calc diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index 9e6e2e67edaef..f954d1b9acb24 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -92,7 +92,6 @@ section Zero variable [Zero R] --- porting note: used to be `CoeFun` instance : FunLike (ArithmeticFunction R) ℕ R := inferInstanceAs (FunLike (ZeroHom ℕ R) ℕ R) @@ -823,7 +822,7 @@ theorem sigma_one_apply_prime_pow {p i : ℕ} (hp : p.Prime) : σ 1 (p ^ i) = ∑ k in .range (i + 1), p ^ k := by simp [sigma_apply_prime_pow hp] -theorem sigma_zero_apply (n : ℕ) : σ 0 n = (divisors n).card := by simp [sigma_apply] +theorem sigma_zero_apply (n : ℕ) : σ 0 n = #n.divisors := by simp [sigma_apply] theorem sigma_zero_apply_prime_pow {p i : ℕ} (hp : p.Prime) : σ 0 (p ^ i) = i + 1 := by simp [sigma_apply_prime_pow hp] @@ -1287,13 +1286,13 @@ theorem prod_eq_iff_prod_pow_moebius_eq_on_of_nonzero [CommGroupWithZero R] end SpecialFunctions theorem _root_.Nat.card_divisors {n : ℕ} (hn : n ≠ 0) : - n.divisors.card = n.primeFactors.prod (n.factorization · + 1) := by + #n.divisors = n.primeFactors.prod (n.factorization · + 1) := by rw [← sigma_zero_apply, isMultiplicative_sigma.multiplicative_factorization _ hn] exact Finset.prod_congr n.support_factorization fun _ h => sigma_zero_apply_prime_pow <| Nat.prime_of_mem_primeFactors h @[deprecated (since := "2024-06-09")] theorem card_divisors (n : ℕ) (hn : n ≠ 0) : - n.divisors.card = n.primeFactors.prod (n.factorization · + 1) := Nat.card_divisors hn + #n.divisors = n.primeFactors.prod (n.factorization · + 1) := Nat.card_divisors hn theorem _root_.Nat.sum_divisors {n : ℕ} (hn : n ≠ 0) : ∑ d ∈ n.divisors, d = ∏ p ∈ n.primeFactors, ∑ k ∈ .range (n.factorization p + 1), p ^ k := by @@ -1308,7 +1307,7 @@ namespace Nat.Coprime open ArithmeticFunction theorem card_divisors_mul {m n : ℕ} (hmn : m.Coprime n) : - (m * n).divisors.card = m.divisors.card * n.divisors.card := by + #(m * n).divisors = #m.divisors * #n.divisors := by simp only [← sigma_zero_apply, isMultiplicative_sigma.map_mul_of_coprime hmn] theorem sum_divisors_mul {m n : ℕ} (hmn : m.Coprime n) : diff --git a/Mathlib/NumberTheory/Basic.lean b/Mathlib/NumberTheory/Basic.lean index 5efc33f2496d9..c90ca141f49a5 100644 --- a/Mathlib/NumberTheory/Basic.lean +++ b/Mathlib/NumberTheory/Basic.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Kenny Lau -/ import Mathlib.Algebra.GeomSum -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Defs +import Mathlib.RingTheory.Ideal.Span /-! # Basic results in number theory diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index bda018aa1e2ea..be1f4f3f725a8 100644 --- a/Mathlib/NumberTheory/Bernoulli.lean +++ b/Mathlib/NumberTheory/Bernoulli.lean @@ -181,7 +181,7 @@ def bernoulli (n : ℕ) : ℚ := (-1) ^ n * bernoulli' n theorem bernoulli'_eq_bernoulli (n : ℕ) : bernoulli' n = (-1) ^ n * bernoulli n := by - simp [bernoulli, ← mul_assoc, ← sq, ← pow_mul, mul_comm n 2, pow_mul] + simp [bernoulli, ← mul_assoc, ← sq, ← pow_mul, mul_comm n 2] @[simp] theorem bernoulli_zero : bernoulli 0 = 1 := by simp [bernoulli] diff --git a/Mathlib/NumberTheory/ClassNumber/FunctionField.lean b/Mathlib/NumberTheory/ClassNumber/FunctionField.lean index e45f913fd3b2e..04ead5e691263 100644 --- a/Mathlib/NumberTheory/ClassNumber/FunctionField.lean +++ b/Mathlib/NumberTheory/ClassNumber/FunctionField.lean @@ -24,7 +24,7 @@ namespace FunctionField open scoped Polynomial -variable (Fq F : Type) [Field Fq] [Fintype Fq] [Field F] +variable (Fq F : Type*) [Field Fq] [Fintype Fq] [Field F] variable [Algebra Fq[X] F] [Algebra (RatFunc Fq) F] variable [IsScalarTower Fq[X] (RatFunc Fq) F] variable [FunctionField Fq F] [Algebra.IsSeparable (RatFunc Fq) F] diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index 3c95d15cc13ee..8140cd702670f 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -129,9 +129,10 @@ theorem trans (C : Type w) [CommRing C] [Algebra A C] [Algebra B C] [IsScalarTow refine ⟨algebraMap B C b, ?_⟩ exact hb.map_of_injective h · exact ((isCyclotomicExtension_iff _ _ _).1 hT).1 hn - · refine adjoin_induction (((isCyclotomicExtension_iff T B _).1 hT).2 x) + · refine adjoin_induction (hx := ((isCyclotomicExtension_iff T B _).1 hT).2 x) (fun c ⟨n, hn⟩ => subset_adjoin ⟨n, Or.inr hn.1, hn.2⟩) (fun b => ?_) - (fun x y hx hy => Subalgebra.add_mem _ hx hy) fun x y hx hy => Subalgebra.mul_mem _ hx hy + (fun x y _ _ hx hy => Subalgebra.add_mem _ hx hy) + fun x y _ _ hx hy => Subalgebra.mul_mem _ hx hy let f := IsScalarTower.toAlgHom A B C have hb : f b ∈ (adjoin A {b : B | ∃ a : ℕ+, a ∈ S ∧ b ^ (a : ℕ) = 1}).map f := ⟨b, ((isCyclotomicExtension_iff _ _ _).1 hS).2 b, rfl⟩ @@ -386,11 +387,11 @@ theorem _root_.IsPrimitiveRoot.adjoin_isCyclotomicExtension {ζ : B} {n : ℕ+} rw [Set.mem_singleton_iff] at hi refine ⟨⟨ζ, subset_adjoin <| Set.mem_singleton ζ⟩, ?_⟩ rwa [← IsPrimitiveRoot.coe_submonoidClass_iff, Subtype.coe_mk, hi] - adjoin_roots := fun x => by + adjoin_roots := fun ⟨x, hx⟩ => by refine - adjoin_induction' - (x := x) (fun b hb => ?_) (fun a => ?_) (fun b₁ b₂ hb₁ hb₂ => ?_) - (fun b₁ b₂ hb₁ hb₂ => ?_) + adjoin_induction + (hx := hx) (fun b hb => ?_) (fun a => ?_) (fun b₁ b₂ _ _ hb₁ hb₂ => ?_) + (fun b₁ b₂ _ _ hb₁ hb₂ => ?_) · rw [Set.mem_singleton_iff] at hb refine subset_adjoin ?_ simp only [mem_singleton_iff, exists_eq_left, mem_setOf_eq, hb] @@ -614,8 +615,10 @@ instance isCyclotomicExtension [IsFractionRing A K] [NeZero ((n : ℕ) : A)] : rwa [← isRoot_cyclotomic_iff] at hμ · rwa [← IsPrimitiveRoot.coe_submonoidClass_iff, Subtype.coe_mk] adjoin_roots x := by + obtain ⟨x, hx⟩ := x refine - adjoin_induction' (fun y hy => ?_) (fun a => ?_) (fun y z hy hz => ?_) (fun y z hy hz => ?_) x + adjoin_induction (fun y hy => ?_) (fun a => ?_) (fun y z _ _ hy hz => ?_) + (fun y z _ _ hy hz => ?_) hx · refine subset_adjoin ?_ simp only [mem_singleton_iff, exists_eq_left, mem_setOf_eq] rwa [← Subalgebra.coe_eq_one, Subalgebra.coe_pow, Subtype.coe_mk] @@ -634,9 +637,8 @@ instance [IsFractionRing A K] [IsDomain A] [NeZero ((n : ℕ) : A)] : letI : NeZero ((n : ℕ) : K) := NeZero.nat_of_injective (IsFractionRing.injective A K) refine Algebra.adjoin_induction - (((IsCyclotomicExtension.iff_singleton n K (CyclotomicField n K)).1 - (CyclotomicField.isCyclotomicExtension n K)).2 - x) + (hx := ((IsCyclotomicExtension.iff_singleton n K (CyclotomicField n K)).1 + (CyclotomicField.isCyclotomicExtension n K)).2 x) (fun y hy => ?_) (fun k => ?_) ?_ ?_ -- Porting note: the last goal was `by simpa` that now fails. · exact ⟨⟨⟨y, subset_adjoin hy⟩, 1⟩, by simp; rfl⟩ @@ -650,12 +652,12 @@ instance [IsFractionRing A K] [IsDomain A] [NeZero ((n : ℕ) : A)] : rw [← IsScalarTower.algebraMap_apply, ← IsScalarTower.algebraMap_apply, @IsScalarTower.algebraMap_apply A K _ _ _ _ _ (_root_.CyclotomicField.algebra n K) _ _ w, ← RingHom.map_mul, hw, ← IsScalarTower.algebraMap_apply] - · rintro y z ⟨a, ha⟩ ⟨b, hb⟩ + · rintro y z - - ⟨a, ha⟩ ⟨b, hb⟩ refine ⟨⟨a.1 * b.2 + b.1 * a.2, a.2 * b.2, mul_mem_nonZeroDivisors.2 ⟨a.2.2, b.2.2⟩⟩, ?_⟩ rw [RingHom.map_mul, add_mul, ← mul_assoc, ha, mul_comm ((algebraMap (CyclotomicRing n A K) _) ↑a.2), ← mul_assoc, hb] simp only [map_add, map_mul] - · rintro y z ⟨a, ha⟩ ⟨b, hb⟩ + · rintro y z - - ⟨a, ha⟩ ⟨b, hb⟩ refine ⟨⟨a.1 * b.1, a.2 * b.2, mul_mem_nonZeroDivisors.2 ⟨a.2.2, b.2.2⟩⟩, ?_⟩ rw [RingHom.map_mul, mul_comm ((algebraMap (CyclotomicRing n A K) _) ↑a.2), mul_assoc, ← mul_assoc z, hb, ← mul_comm ((algebraMap (CyclotomicRing n A K) _) ↑a.2), ← mul_assoc, ha] diff --git a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean index c4b31c98a929a..0e61f7398af63 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ import Mathlib.NumberTheory.Cyclotomic.PrimitiveRoots -import Mathlib.NumberTheory.NumberField.Discriminant +import Mathlib.RingTheory.DedekindDomain.Dvr +import Mathlib.NumberTheory.NumberField.Discriminant.Defs /-! # Discriminant of cyclotomic fields diff --git a/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean b/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean index 642d6933fad59..a6b2d1fc27387 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean @@ -30,7 +30,7 @@ of `K`. -/ theorem nrRealPlaces_eq_zero [IsCyclotomicExtension {n} ℚ K] (hn : 2 < n) : haveI := IsCyclotomicExtension.numberField {n} ℚ K - NrRealPlaces K = 0 := by + nrRealPlaces K = 0 := by have := IsCyclotomicExtension.numberField {n} ℚ K apply (IsCyclotomicExtension.zeta_spec n ℚ K).nrRealPlaces_eq_zero_of_two_lt hn @@ -40,7 +40,7 @@ variable (n) of `K`. Note that this uses `1 / 2 = 0` in the cases `n = 1, 2`. -/ theorem nrComplexPlaces_eq_totient_div_two [h : IsCyclotomicExtension {n} ℚ K] : haveI := IsCyclotomicExtension.numberField {n} ℚ K - NrComplexPlaces K = φ n / 2 := by + nrComplexPlaces K = φ n / 2 := by have := IsCyclotomicExtension.numberField {n} ℚ K by_cases hn : 2 < n · obtain ⟨k, hk : φ n = k + k⟩ := totient_even hn diff --git a/Mathlib/NumberTheory/Cyclotomic/Gal.lean b/Mathlib/NumberTheory/Cyclotomic/Gal.lean index fb381459d36cf..c5f27c52696f2 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Gal.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Gal.lean @@ -152,7 +152,7 @@ end IsCyclotomicExtension section Gal -variable [Field L] (hμ : IsPrimitiveRoot μ n) [Algebra K L] [IsCyclotomicExtension {n} K L] +variable [Field L] [Algebra K L] [IsCyclotomicExtension {n} K L] (h : Irreducible (cyclotomic n K)) {K} /-- `IsCyclotomicExtension.autEquivPow` repackaged in terms of `Gal`. diff --git a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean index e4a82b6a04edb..0e8d24cf92d00 100644 --- a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean +++ b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean @@ -153,8 +153,8 @@ noncomputable def embeddingsEquivPrimitiveRoots (C : Type*) [CommRing C] [IsDoma rwa [aeval_def, eval₂_eq_eval_map, hζ.powerBasis_gen K, ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, map_cyclotomic, ← IsRoot.def, isRoot_cyclotomic_iff, ← mem_primitiveRoots n.pos] - left_inv := fun x => Subtype.ext rfl - right_inv := fun x => Subtype.ext rfl } + left_inv := fun _ => Subtype.ext rfl + right_inv := fun _ => Subtype.ext rfl } -- Porting note: renamed argument `φ`: "expected '_' or identifier" @[simp] @@ -489,8 +489,7 @@ theorem norm_pow_sub_one_two {k : ℕ} (hζ : IsPrimitiveRoot ζ (2 ^ (k + 1))) have H : (-1 : L) - (1 : L) = algebraMap K L (-2) := by simp only [map_neg, map_ofNat] ring --- Porting note: `simpa using hirr` was `simp [hirr]`. - replace hirr : Irreducible (cyclotomic ((2 : ℕ+) ^ (k + 1) : ℕ+) K) := by simpa using hirr + replace hirr : Irreducible (cyclotomic ((2 : ℕ+) ^ (k + 1) : ℕ+) K) := by simp [hirr] -- Porting note: the proof is slightly different because of coercions. rw [this.eq_neg_one_of_two_right, H, Algebra.norm_algebraMap, IsCyclotomicExtension.finrank L hirr, pow_coe, show ((2 : ℕ+) : ℕ) = 2 from rfl, @@ -506,10 +505,8 @@ theorem norm_sub_one_two {k : ℕ} (hζ : IsPrimitiveRoot ζ (2 ^ k)) (hk : 2 simp only [← coe_lt_coe, one_coe, pow_coe] nth_rw 1 [← pow_one 2] exact pow_lt_pow_right one_lt_two (lt_of_lt_of_le one_lt_two hk) --- Porting note: `simpa using hirr` was `simp [hirr]`_ - replace hirr : Irreducible (cyclotomic ((2 : ℕ+) ^ k : ℕ+) K) := by simpa using hirr --- Porting note: `simpa using hζ` was `simp [hζ]`_ - replace hζ : IsPrimitiveRoot ζ (2 ^ k : ℕ+) := by simpa using hζ + replace hirr : Irreducible (cyclotomic ((2 : ℕ+) ^ k : ℕ+) K) := by simp [hirr] + replace hζ : IsPrimitiveRoot ζ (2 ^ k : ℕ+) := by simp [hζ] obtain ⟨k₁, hk₁⟩ := exists_eq_succ_of_ne_zero (lt_of_lt_of_le zero_lt_two hk).ne.symm -- Porting note: the proof is slightly different because of coercions. simpa [hk₁, show ((2 : ℕ+) : ℕ) = 2 from rfl] using sub_one_norm_eq_eval_cyclotomic hζ this hirr diff --git a/Mathlib/NumberTheory/Cyclotomic/Rat.lean b/Mathlib/NumberTheory/Cyclotomic/Rat.lean index 39cdf61a38935..eae82d89db9ff 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Rat.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Rat.lean @@ -214,6 +214,13 @@ theorem integralPowerBasis_gen [hcycl : IsCyclotomicExtension {p ^ k} ℚ K] simp only [adjoinEquivRingOfIntegers_apply, IsIntegralClosure.algebraMap_lift] rfl +#adaptation_note +/-- +We name `hcycl` so it can be used as a named argument, +but since https://github.com/leanprover/lean4/pull/5338, this is considered unused, +so we need to disable the linter. +-/ +set_option linter.unusedVariables false in @[simp] theorem integralPowerBasis_dim [hcycl : IsCyclotomicExtension {p ^ k} ℚ K] (hζ : IsPrimitiveRoot ζ ↑(p ^ k)) : hζ.integralPowerBasis.dim = φ (p ^ k) := by diff --git a/Mathlib/NumberTheory/Dioph.lean b/Mathlib/NumberTheory/Dioph.lean index 721b81b5271ba..6c7c378d55eb4 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -67,7 +67,7 @@ Note that this duplicates `MvPolynomial`. section Polynomials -variable {α β γ : Type*} +variable {α β : Type*} /-- A predicate asserting that a function is a multivariate integer polynomial. (We are being a bit lazy here by allowing many representations for multiplication, @@ -432,7 +432,7 @@ end section -variable {α β : Type} {n : ℕ} +variable {α : Type} {n : ℕ} open Vector3 diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index 946ac3af1f703..604980a89620e 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -113,7 +113,7 @@ theorem exists_int_int_abs_mul_sub_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) : simpa only [neg_add_cancel_comm_assoc] using hf' · -- Porting note(https://github.com/leanprover-community/mathlib4/issues/5127): added `not_and` simp_rw [not_exists, not_and] at H - have hD : (Ico (0 : ℤ) n).card < D.card := by rw [card_Icc, card_Ico]; exact lt_add_one n + have hD : #(Ico (0 : ℤ) n) < #D := by rw [card_Icc, card_Ico]; exact lt_add_one n have hfu' : ∀ m, f m ≤ n := fun m => lt_add_one_iff.mp (floor_lt.mpr (mod_cast hfu m)) have hwd : ∀ m : ℤ, m ∈ D → f m ∈ Ico (0 : ℤ) n := fun x hx => mem_Ico.mpr @@ -406,8 +406,7 @@ private theorem aux₁ : 0 < fract ξ := by refine fract_pos.mpr fun hf => ?_ rw [hf] at h have H : (2 * v - 1 : ℝ) < 1 := by - refine - (mul_lt_iff_lt_one_right hv₀).mp ((inv_lt_inv hv₀ (mul_pos hv₁ hv₂)).mp (lt_of_le_of_lt ?_ h)) + refine (mul_lt_iff_lt_one_right hv₀).1 ((inv_lt_inv₀ hv₀ (mul_pos hv₁ hv₂)).1 (h.trans_le' ?_)) have h' : (⌊ξ⌋ : ℝ) - u / v = (⌊ξ⌋ * v - u) / v := by field_simp rw [h', abs_div, abs_of_pos hv₀, ← one_div, div_le_div_right hv₀] norm_cast @@ -490,7 +489,7 @@ private theorem aux₃ : _ < ((v : ℝ) * (2 * v - 1))⁻¹ * (v / u' / fract ξ) := (mul_lt_mul_right H₁).mpr h' _ = (u' * (2 * v - 1) * fract ξ)⁻¹ := help₂ hξ₀.ne' Hv.ne' Hv'.ne' Hu.ne' _ ≤ ((u' : ℝ) * (2 * u' - 1))⁻¹ := by - rwa [inv_le_inv (mul_pos (mul_pos Hu Hv') hξ₀) <| mul_pos Hu Hu', mul_assoc, + rwa [inv_le_inv₀ (mul_pos (mul_pos Hu Hv') hξ₀) <| mul_pos Hu Hu', mul_assoc, mul_le_mul_left Hu] -- The conditions `ass ξ u v` persist in the inductive step. @@ -506,7 +505,7 @@ private theorem invariant : ContfracLegendre.Ass (fract ξ)⁻¹ v (u - ⌊ξ⌋ have h' := (abs_sub_lt_iff.mp h.2.2).1 rw [Huv, ← sub_sub, sub_lt_iff_lt_add, self_sub_floor, Hv] at h' rwa [lt_sub_iff_add_lt', (by ring : (v : ℝ) + -(1 / 2) = (2 * v - 1) / 2), - lt_inv (div_pos hv₀' zero_lt_two) (aux₁ hv h), inv_div] + lt_inv_comm₀ (div_pos hv₀' zero_lt_two) (aux₁ hv h), inv_div] end @@ -538,8 +537,8 @@ theorem exists_rat_eq_convergent' {v : ℕ} (h : ContfracLegendre.Ass ξ u v) : · rw [Hξ, hξ₁, cast_sub, cast_one, ← sub_eq_add_neg, sub_lt_sub_iff_left] at h₁ exact False.elim (lt_irrefl _ <| h₁.trans one_half_lt_one) · have hξ₂ : ⌊(fract ξ)⁻¹⌋ = 1 := by - rw [floor_eq_iff, cast_one, le_inv zero_lt_one (fract_pos.mpr Hξ), inv_one, - one_add_one_eq_two, inv_lt (fract_pos.mpr Hξ) zero_lt_two] + rw [floor_eq_iff, cast_one, le_inv_comm₀ zero_lt_one (fract_pos.mpr Hξ), inv_one, + one_add_one_eq_two, inv_lt_comm₀ (fract_pos.mpr Hξ) zero_lt_two] refine ⟨(fract_lt_one ξ).le, ?_⟩ rw [fract, hξ₁, cast_sub, cast_one, lt_sub_iff_add_lt', sub_add] convert h₁ using 1 diff --git a/Mathlib/NumberTheory/DirichletCharacter/Basic.lean b/Mathlib/NumberTheory/DirichletCharacter/Basic.lean index 9fbae12e56bcd..8780485d9254f 100644 --- a/Mathlib/NumberTheory/DirichletCharacter/Basic.lean +++ b/Mathlib/NumberTheory/DirichletCharacter/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Ashvni Narayanan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Ashvni Narayanan, Moritz Firsching, Michael Stoll -/ +import Mathlib.Algebra.Group.EvenFunction import Mathlib.Data.ZMod.Units import Mathlib.NumberTheory.MulChar.Basic @@ -159,6 +160,10 @@ instance : Subsingleton (DirichletCharacter R 1) := by noncomputable instance : Unique (DirichletCharacter R 1) := Unique.mk' (DirichletCharacter R 1) +/-- A Dirichlet character of modulus `≠ 1` maps `0` to `0`. -/ +lemma map_zero' (hn : n ≠ 1) : χ 0 = 0 := + have := ZMod.nontrivial_iff.mpr hn; χ.map_zero + lemma changeLevel_one {d : ℕ} (h : d ∣ n) : changeLevel h (1 : DirichletCharacter R d) = 1 := by simp @@ -287,7 +292,7 @@ lemma primitive_mul_isPrimitive {m : ℕ} (ψ : DirichletCharacter R m) : section CommRing -variable {S : Type} [CommRing S] {m : ℕ} (ψ : DirichletCharacter S m) +variable {S : Type*} [CommRing S] {m : ℕ} (ψ : DirichletCharacter S m) /-- A Dirichlet character is odd if its value at -1 is -1. -/ def Odd : Prop := ψ (-1) = -1 @@ -299,6 +304,16 @@ lemma even_or_odd [NoZeroDivisors S] : ψ.Even ∨ ψ.Odd := by suffices ψ (-1) ^ 2 = 1 by convert sq_eq_one_iff.mp this rw [← map_pow _, neg_one_sq, map_one] +lemma not_even_and_odd [NeZero (2 : S)] : ¬(ψ.Even ∧ ψ.Odd) := by + rintro ⟨(h : _ = 1), (h' : _ = -1)⟩ + simp only [h', neg_eq_iff_add_eq_zero, one_add_one_eq_two, two_ne_zero] at h + +lemma Even.not_odd [NeZero (2 : S)] (hψ : Even ψ) : ¬Odd ψ := + not_and.mp ψ.not_even_and_odd hψ + +lemma Odd.not_even [NeZero (2 : S)] (hψ : Odd ψ) : ¬Even ψ := + not_and'.mp ψ.not_even_and_odd hψ + lemma Odd.toUnitHom_eval_neg_one (hψ : ψ.Odd) : ψ.toUnitHom (-1) = -1 := by rw [← Units.eq_iff, MulChar.coe_toUnitHom] exact hψ @@ -317,6 +332,14 @@ lemma Even.eval_neg (x : ZMod m) (hψ : ψ.Even) : ψ (- x) = ψ x := by rw [← neg_one_mul, map_mul] simp [hψ] +/-- An even Dirichlet character is an even function. -/ +lemma Even.to_fun {χ : DirichletCharacter S m} (hχ : Even χ) : Function.Even χ := + fun _ ↦ by rw [← neg_one_mul, map_mul, hχ, one_mul] + +/-- An odd Dirichlet character is an odd function. -/ +lemma Odd.to_fun {χ : DirichletCharacter S m} (hχ : Odd χ) : Function.Odd χ := + fun _ ↦ by rw [← neg_one_mul, map_mul, hχ, neg_one_mul] + end CommRing end DirichletCharacter diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 0c98cefad6ecd..e2bfeafb8e217 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.Nat.PrimeFin import Mathlib.Order.Interval.Finset.Nat @@ -36,30 +36,27 @@ namespace Nat variable (n : ℕ) /-- `divisors n` is the `Finset` of divisors of `n`. As a special case, `divisors 0 = ∅`. -/ -def divisors : Finset ℕ := - Finset.filter (fun x : ℕ => x ∣ n) (Finset.Ico 1 (n + 1)) +def divisors : Finset ℕ := {d ∈ Ico 1 (n + 1) | d ∣ n} /-- `properDivisors n` is the `Finset` of divisors of `n`, other than `n`. As a special case, `properDivisors 0 = ∅`. -/ -def properDivisors : Finset ℕ := - Finset.filter (fun x : ℕ => x ∣ n) (Finset.Ico 1 n) +def properDivisors : Finset ℕ := {d ∈ Ico 1 n | d ∣ n} /-- `divisorsAntidiagonal n` is the `Finset` of pairs `(x,y)` such that `x * y = n`. As a special case, `divisorsAntidiagonal 0 = ∅`. -/ def divisorsAntidiagonal : Finset (ℕ × ℕ) := - Finset.filter (fun x => x.fst * x.snd = n) (Ico 1 (n + 1) ×ˢ Ico 1 (n + 1)) + {x ∈ Ico 1 (n + 1) ×ˢ Ico 1 (n + 1) | x.fst * x.snd = n} variable {n} @[simp] -theorem filter_dvd_eq_divisors (h : n ≠ 0) : (Finset.range n.succ).filter (· ∣ n) = n.divisors := by +theorem filter_dvd_eq_divisors (h : n ≠ 0) : {d ∈ range n.succ | d ∣ n} = n.divisors := by ext simp only [divisors, mem_filter, mem_range, mem_Ico, and_congr_left_iff, iff_and_self] exact fun ha _ => succ_le_iff.mpr (pos_of_dvd_of_pos ha h.bot_lt) @[simp] -theorem filter_dvd_eq_properDivisors (h : n ≠ 0) : - (Finset.range n).filter (· ∣ n) = n.properDivisors := by +theorem filter_dvd_eq_properDivisors (h : n ≠ 0) : {d ∈ range n | d ∣ n} = n.properDivisors := by ext simp only [properDivisors, mem_filter, mem_range, mem_Ico, and_congr_left_iff, iff_and_self] exact fun ha _ => succ_le_iff.mpr (pos_of_dvd_of_pos ha h.bot_lt) @@ -147,7 +144,7 @@ theorem divisors_subset_properDivisors {m : ℕ} (hzero : n ≠ 0) (h : m ∣ n) (lt_of_le_of_ne (divisor_le (Nat.mem_divisors.2 ⟨h, hzero⟩)) hdiff)⟩ lemma divisors_filter_dvd_of_dvd {n m : ℕ} (hn : n ≠ 0) (hm : m ∣ n) : - (n.divisors.filter (· ∣ m)) = m.divisors := by + {d ∈ n.divisors | d ∣ m} = m.divisors := by ext k simp_rw [mem_filter, mem_divisors] exact ⟨fun ⟨_, hkm⟩ ↦ ⟨hkm, ne_zero_of_dvd_ne_zero hn hm⟩, fun ⟨hk, _⟩ ↦ ⟨⟨hk.trans hm, hn⟩, hk⟩⟩ @@ -281,7 +278,7 @@ theorem image_snd_divisorsAntidiagonal : (divisorsAntidiagonal n).image Prod.snd exact image_fst_divisorsAntidiagonal theorem map_div_right_divisors : - n.divisors.map ⟨fun d => (d, n / d), fun p₁ p₂ => congr_arg Prod.fst⟩ = + n.divisors.map ⟨fun d => (d, n / d), fun _ _ => congr_arg Prod.fst⟩ = n.divisorsAntidiagonal := by ext ⟨d, nd⟩ simp only [mem_map, mem_divisorsAntidiagonal, Function.Embedding.coeFn_mk, mem_divisors, @@ -294,7 +291,7 @@ theorem map_div_right_divisors : exact ⟨⟨dvd_mul_right _ _, hn⟩, Nat.mul_div_cancel_left _ (left_ne_zero_of_mul hn).bot_lt⟩ theorem map_div_left_divisors : - n.divisors.map ⟨fun d => (n / d, d), fun p₁ p₂ => congr_arg Prod.snd⟩ = + n.divisors.map ⟨fun d => (n / d, d), fun _ _ => congr_arg Prod.snd⟩ = n.divisorsAntidiagonal := by apply Finset.map_injective (Equiv.prodComm _ _).toEmbedding ext @@ -471,7 +468,7 @@ theorem prod_divisorsAntidiagonal' {M : Type*} [CommMonoid M] (f : ℕ → ℕ /-- The factors of `n` are the prime divisors -/ theorem primeFactors_eq_to_filter_divisors_prime (n : ℕ) : - n.primeFactors = (divisors n).filter Prime := by + n.primeFactors = {p ∈ divisors n | p.Prime} := by rcases n.eq_zero_or_pos with (rfl | hn) · simp · ext q @@ -481,7 +478,7 @@ theorem primeFactors_eq_to_filter_divisors_prime (n : ℕ) : alias prime_divisors_eq_to_filter_divisors_prime := primeFactors_eq_to_filter_divisors_prime lemma primeFactors_filter_dvd_of_dvd {m n : ℕ} (hn : n ≠ 0) (hmn : m ∣ n) : - n.primeFactors.filter (· ∣ m) = m.primeFactors := by + {p ∈ n.primeFactors | p ∣ m} = m.primeFactors := by simp_rw [primeFactors_eq_to_filter_divisors_prime, filter_comm, divisors_filter_dvd_of_dvd hn hmn] diff --git a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean index b48aa4e66e245..541332309d477 100644 --- a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean +++ b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean @@ -113,12 +113,12 @@ def preNormEDS' (b c d : R) : ℕ → R have h4 : m + 4 < n + 5 := Nat.lt_succ.mpr <| add_le_add_right (n.div_le_self 2) 4 have h3 : m + 3 < n + 5 := (lt_add_one _).trans h4 have h2 : m + 2 < n + 5 := (lt_add_one _).trans h3 - have h1 : m + 1 < n + 5 := (lt_add_one _).trans h2 + have _ : m + 1 < n + 5 := (lt_add_one _).trans h2 if hn : Even n then 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) else - have h5 : m + 5 < n + 5 := add_lt_add_right + have _ : m + 5 < n + 5 := add_lt_add_right (Nat.div_lt_self (Nat.not_even_iff_odd.1 hn).pos <| Nat.lt_succ_self 1) 5 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 diff --git a/Mathlib/NumberTheory/EulerProduct/Basic.lean b/Mathlib/NumberTheory/EulerProduct/Basic.lean index 1b6b6f551ed15..be623e1cac957 100644 --- a/Mathlib/NumberTheory/EulerProduct/Basic.lean +++ b/Mathlib/NumberTheory/EulerProduct/Basic.lean @@ -81,7 +81,7 @@ lemma summable_and_hasSum_factoredNumbers_prod_filter_prime_tsum (hsum : ∀ {p : ℕ}, p.Prime → Summable (fun n : ℕ ↦ ‖f (p ^ n)‖)) (s : Finset ℕ) : Summable (fun m : factoredNumbers s ↦ ‖f m‖) ∧ HasSum (fun m : factoredNumbers s ↦ f m) - (∏ p ∈ s.filter Nat.Prime, ∑' n : ℕ, f (p ^ n)) := by + (∏ p ∈ s with p.Prime, ∑' n : ℕ, f (p ^ n)) := by induction' s using Finset.induction with p s hp ih · rw [factoredNumbers_empty] simp only [not_mem_empty, IsEmpty.forall_iff, forall_const, filter_true_of_mem, prod_empty] @@ -93,7 +93,7 @@ lemma summable_and_hasSum_factoredNumbers_prod_filter_prime_tsum equivProdNatFactoredNumbers_apply', factoredNumbers.map_prime_pow_mul hmul hpp hp] refine Summable.of_nonneg_of_le (fun _ ↦ norm_nonneg _) (fun _ ↦ norm_mul_le ..) ?_ apply Summable.mul_of_nonneg (hsum hpp) ih.1 <;> exact fun n ↦ norm_nonneg _ - · have hp' : p ∉ s.filter Nat.Prime := mt (mem_of_mem_filter p) hp + · have hp' : p ∉ {p ∈ s | p.Prime} := mt (mem_of_mem_filter p) hp rw [prod_insert hp', ← (equivProdNatFactoredNumbers hpp hp).hasSum_iff, Function.comp_def] conv => enter [1, x] @@ -108,7 +108,7 @@ include hf₁ hmul in /-- A version of `EulerProduct.summable_and_hasSum_factoredNumbers_prod_filter_prime_tsum` in terms of the value of the series. -/ lemma prod_filter_prime_tsum_eq_tsum_factoredNumbers (hsum : Summable (‖f ·‖)) (s : Finset ℕ) : - ∏ p ∈ s.filter Nat.Prime, ∑' n : ℕ, f (p ^ n) = ∑' m : factoredNumbers s, f m := + ∏ p ∈ s with p.Prime, ∑' n : ℕ, f (p ^ n) = ∑' m : factoredNumbers s, f m := (summable_and_hasSum_factoredNumbers_prod_filter_prime_tsum hf₁ hmul (fun hp ↦ hsum.comp_injective <| Nat.pow_right_injective hp.one_lt) _).2.tsum_eq.symm @@ -175,7 +175,7 @@ theorem eulerProduct_hasProd (hsum : Summable (‖f ·‖)) (hf₀ : f 0 = 0) : intro ε hε obtain ⟨N₀, hN₀⟩ := norm_tsum_factoredNumbers_sub_tsum_lt hsum.of_norm hf₀ hε refine ⟨range N₀, fun s hs ↦ ?_⟩ - have : ∏ p ∈ s, {p | Nat.Prime p}.mulIndicator F p = ∏ p ∈ s.filter Nat.Prime, F p := + have : ∏ p ∈ s, {p | Nat.Prime p}.mulIndicator F p = ∏ p ∈ s with p.Prime, F p := prod_mulIndicator_eq_prod_filter s (fun _ ↦ F) _ id rw [this, dist_eq_norm, prod_filter_prime_tsum_eq_tsum_factoredNumbers hf₁ hmul hsum, norm_sub_rev] @@ -292,10 +292,10 @@ we show that the sum involved converges absolutely. -/ lemma summable_and_hasSum_factoredNumbers_prod_filter_prime_geometric {f : ℕ →* F} (h : ∀ {p : ℕ}, p.Prime → ‖f p‖ < 1) (s : Finset ℕ) : Summable (fun m : factoredNumbers s ↦ ‖f m‖) ∧ - HasSum (fun m : factoredNumbers s ↦ f m) (∏ p ∈ s.filter Nat.Prime, (1 - f p)⁻¹) := by + HasSum (fun m : factoredNumbers s ↦ f m) (∏ p ∈ s with p.Prime, (1 - f p)⁻¹) := by have hmul {m n} (_ : Nat.Coprime m n) := f.map_mul m n have H₁ : - ∏ p ∈ s.filter Nat.Prime, ∑' n : ℕ, f (p ^ n) = ∏ p ∈ s.filter Nat.Prime, (1 - f p)⁻¹ := by + ∏ p ∈ s with p.Prime, ∑' n : ℕ, f (p ^ n) = ∏ p ∈ s with p.Prime, (1 - f p)⁻¹ := by refine prod_congr rfl fun p hp ↦ ?_ simp only [map_pow] exact tsum_geometric_of_norm_lt_one <| h (mem_filter.mp hp).2 @@ -310,7 +310,7 @@ lemma summable_and_hasSum_factoredNumbers_prod_filter_prime_geometric {f : ℕ in terms of the value of the series. -/ lemma prod_filter_prime_geometric_eq_tsum_factoredNumbers {f : ℕ →* F} (hsum : Summable f) (s : Finset ℕ) : - ∏ p ∈ s.filter Nat.Prime, (1 - f p)⁻¹ = ∑' m : factoredNumbers s, f m := by + ∏ p ∈ s with p.Prime, (1 - f p)⁻¹ = ∑' m : factoredNumbers s, f m := by refine (summable_and_hasSum_factoredNumbers_prod_filter_prime_geometric ?_ s).2.tsum_eq.symm exact fun {_} hp ↦ hsum.norm_lt_one hp.one_lt diff --git a/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean b/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean index ba72ec28fdfcd..e3b05fad3ebd6 100644 --- a/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean +++ b/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean @@ -127,3 +127,49 @@ theorem dirichletLSeries_eulerProduct {N : ℕ} (χ : DirichletCharacter ℂ N) (𝓝 (L ↗χ s)) := by rw [← tsum_dirichletSummand χ hs] apply eulerProduct_completely_multiplicative <| summable_dirichletSummand χ hs + + +/-! +### Changing the level of a Dirichlet `L`-series +-/ + +/-- If `χ` is a Dirichlet character and its level `M` divides `N`, then we obtain the L-series +of `χ` considered as a Dirichlet character of level `N` from the L-series of `χ` by multiplying +with `∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s))`. -/ +lemma DirichletCharacter.LSeries_changeLevel {M N : ℕ} [NeZero N] + (hMN : M ∣ N) (χ : DirichletCharacter ℂ M) {s : ℂ} (hs : 1 < s.re) : + LSeries ↗(changeLevel hMN χ) s = + LSeries ↗χ s * ∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s)) := by + rw [prod_eq_tprod_mulIndicator, ← dirichletLSeries_eulerProduct_tprod _ hs, + ← dirichletLSeries_eulerProduct_tprod _ hs] + -- convert to a form suitable for `tprod_subtype` + have (f : Primes → ℂ) : ∏' (p : Primes), f p = ∏' (p : ↑{p : ℕ | p.Prime}), f p := rfl + rw [this, tprod_subtype _ fun p : ℕ ↦ (1 - (changeLevel hMN χ) p * p ^ (-s))⁻¹, + this, tprod_subtype _ fun p : ℕ ↦ (1 - χ p * p ^ (-s))⁻¹, ← tprod_mul] + rotate_left -- deal with convergence goals first + · exact multipliable_subtype_iff_mulIndicator.mp + (dirichletLSeries_eulerProduct_hasProd χ hs).multipliable + · exact multipliable_subtype_iff_mulIndicator.mp Multipliable.of_finite + · congr 1 with p + simp only [Set.mulIndicator_apply, Set.mem_setOf_eq, Finset.mem_coe, Nat.mem_primeFactors, + ne_eq, mul_ite, ite_mul, one_mul, mul_one] + by_cases h : p.Prime; swap + · simp only [h, false_and, if_false] + simp only [h, true_and, if_true] + by_cases hp' : p ∣ N; swap + · simp only [hp', false_and, ↓reduceIte, inv_inj, sub_right_inj, mul_eq_mul_right_iff, + cpow_eq_zero_iff, Nat.cast_eq_zero, h.ne_zero, ne_eq, neg_eq_zero, or_false] + have hq : IsUnit (p : ZMod N) := (ZMod.isUnit_prime_iff_not_dvd h).mpr hp' + simp only [hq.unit_spec ▸ DirichletCharacter.changeLevel_eq_cast_of_dvd χ hMN hq.unit, + ZMod.cast_natCast hMN] + · simp only [hp', NeZero.ne N, not_false_eq_true, and_self, ↓reduceIte] + have : ¬IsUnit (p : ZMod N) := by rwa [ZMod.isUnit_prime_iff_not_dvd h, not_not] + rw [MulChar.map_nonunit _ this, zero_mul, sub_zero, inv_one] + refine (inv_mul_cancel₀ ?_).symm + rw [sub_ne_zero, ne_comm] + -- Remains to show `χ p * p ^ (-s) ≠ 1`. We show its norm is strictly `< 1`. + apply_fun (‖·‖) + simp only [norm_mul, norm_one] + have ha : ‖χ p‖ ≤ 1 := χ.norm_le_one p + have hb : ‖(p : ℂ) ^ (-s)‖ ≤ 1 / 2 := norm_prime_cpow_le_one_half ⟨p, h⟩ hs + exact ((mul_le_mul ha hb (norm_nonneg _) zero_le_one).trans_lt (by norm_num)).ne diff --git a/Mathlib/NumberTheory/FLT/Three.lean b/Mathlib/NumberTheory/FLT/Three.lean index 555bad3224e64..05013ac559c40 100644 --- a/Mathlib/NumberTheory/FLT/Three.lean +++ b/Mathlib/NumberTheory/FLT/Three.lean @@ -215,21 +215,20 @@ lemma Solution'.multiplicity_lambda_c_finite : section DecidableRel -variable [DecidableRel fun (a b : 𝓞 K) ↦ a ∣ b] - /-- Given `S' : Solution'`, `S'.multiplicity` is the multiplicity of `λ` in `S'.c`, as a natural number. -/ -def Solution'.multiplicity := - (_root_.multiplicity (hζ.toInteger - 1) S'.c).get (multiplicity_lambda_c_finite S') +noncomputable def Solution'.multiplicity := + _root_.multiplicity (hζ.toInteger - 1) S'.c /-- Given `S : Solution`, `S.multiplicity` is the multiplicity of `λ` in `S.c`, as a natural number. -/ -def Solution.multiplicity := S.toSolution'.multiplicity +noncomputable def Solution.multiplicity := S.toSolution'.multiplicity /-- We say that `S : Solution` is minimal if for all `S₁ : Solution`, the multiplicity of `λ` in `S.c` is less or equal than the multiplicity in `S₁.c`. -/ def Solution.isMinimal : Prop := ∀ (S₁ : Solution hζ), S.multiplicity ≤ S₁.multiplicity +omit [NumberField K] [IsCyclotomicExtension {3} ℚ K] in include S in /-- If there is a solution then there is a minimal one. -/ lemma Solution.exists_minimal : ∃ (S₁ : Solution hζ), S₁.isMinimal := by @@ -281,29 +280,25 @@ lemma lambda_pow_four_dvd_c_cube : λ ^ 4 ∣ S'.c ^ 3 := by section DecidableRel -variable [DecidableRel fun (a b : 𝓞 K) ↦ a ∣ b] - /-- Given `S' : Solution'`, we have that `λ ^ 2` divides `S'.c`. -/ lemma lambda_sq_dvd_c : λ ^ 2 ∣ S'.c := by have hm := S'.multiplicity_lambda_c_finite - suffices 2 ≤ (multiplicity ((hζ.toInteger - 1)) S'.c).get hm by - obtain ⟨x, hx⟩ := multiplicity.pow_multiplicity_dvd hm - refine ⟨λ ^ ((multiplicity ((hζ.toInteger - 1)) S'.c).get hm - 2) * x, ?_⟩ + suffices 2 ≤ multiplicity (hζ.toInteger - 1) S'.c by + obtain ⟨x, hx⟩ := pow_multiplicity_dvd (hζ.toInteger - 1) S'.c + refine ⟨λ ^ (multiplicity (hζ.toInteger - 1) S'.c - 2) * x, ?_⟩ rw [← mul_assoc, ← pow_add] convert hx using 3 simp [this] have := lambda_pow_four_dvd_c_cube S' - have hm1 : (multiplicity (hζ.toInteger - 1) (S'.c ^ 3)).get - (multiplicity.finite_pow hζ.zeta_sub_one_prime' hm) = - multiplicity (hζ.toInteger - 1) (S'.c ^ 3) := by simp - rw [multiplicity.pow_dvd_iff_le_multiplicity, ← hm1, multiplicity.pow' hζ.zeta_sub_one_prime' hm, - Nat.cast_ofNat, Nat.ofNat_le_cast] at this + rw [pow_dvd_iff_le_emultiplicity, emultiplicity_pow hζ.zeta_sub_one_prime', + hm.emultiplicity_eq_multiplicity] at this + norm_cast at this omega /-- Given `S' : Solution'`, we have that `2 ≤ S'.multiplicity`. -/ lemma Solution'.two_le_multiplicity : 2 ≤ S'.multiplicity := by - simpa [← PartENat.coe_le_coe, Solution'.multiplicity] using - multiplicity.le_multiplicity_of_pow_dvd (lambda_sq_dvd_c S') + simpa [Solution'.multiplicity] using + S'.multiplicity_lambda_c_finite.le_multiplicity_of_pow_dvd (lambda_sq_dvd_c S') /-- Given `S : Solution`, we have that `2 ≤ S.multiplicity`. -/ lemma Solution.two_le_multiplicity : 2 ≤ S.multiplicity := @@ -333,28 +328,25 @@ lemma lambda_sq_dvd_or_dvd_or_dvd : λ ^ 2 ∣ S'.a + S'.b ∨ λ ^ 2 ∣ S'.a + η * S'.b ∨ λ ^ 2 ∣ S'.a + η ^ 2 * S'.b := by by_contra! h rcases h with ⟨h1, h2, h3⟩ - rw [← multiplicity.multiplicity_lt_iff_not_dvd] at h1 h2 h3 + rw [← emultiplicity_lt_iff_not_dvd] at h1 h2 h3 have h1' : multiplicity.Finite (hζ.toInteger - 1) (S'.a + S'.b) := - multiplicity.ne_top_iff_finite.1 (fun ht ↦ by simp [ht] at h1) + 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 multiplicity.ne_top_iff_finite.1 (fun ht ↦ ?_) + refine finite_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 multiplicity.ne_top_iff_finite.1 (fun ht ↦ ?_) + refine finite_iff_emultiplicity_ne_top.2 (fun ht ↦ ?_) rw [coe_eta] at ht simp [ht] at h3 - replace h1' : (multiplicity (hζ.toInteger - 1) (S'.a + S'.b)).get h1' = - multiplicity (hζ.toInteger - 1) (S'.a + S'.b) := by simp - replace h2' : (multiplicity (hζ.toInteger - 1) (S'.a + η * S'.b)).get h2' = - multiplicity (hζ.toInteger - 1) (S'.a + η * S'.b) := by simp - replace h3' : (multiplicity (hζ.toInteger - 1) (S'.a + η ^ 2 * S'.b)).get h3' = - multiplicity (hζ.toInteger - 1) (S'.a + η ^ 2 * S'.b) := by simp - rw [← h1', coe_lt_coe] at h1; rw [← h2', coe_lt_coe] at h2; rw [← h3', coe_lt_coe] at h3 + rw [h1'.emultiplicity_eq_multiplicity, Nat.cast_lt] at h1 + rw [h2'.emultiplicity_eq_multiplicity, Nat.cast_lt] at h2 + rw [h3'.emultiplicity_eq_multiplicity, Nat.cast_lt] at h3 have := (pow_dvd_pow_of_dvd (lambda_sq_dvd_c S') 3).mul_left S'.u - rw [← pow_mul, ← S'.H, a_cube_add_b_cube_eq_mul, multiplicity.pow_dvd_iff_le_multiplicity, - multiplicity.mul hζ.zeta_sub_one_prime', multiplicity.mul hζ.zeta_sub_one_prime', ← h1', ← h2', - ← h3', ← Nat.cast_add, ← Nat.cast_add, coe_le_coe] at this + rw [← pow_mul, ← S'.H, a_cube_add_b_cube_eq_mul, pow_dvd_iff_le_emultiplicity, + emultiplicity_mul hζ.zeta_sub_one_prime', emultiplicity_mul hζ.zeta_sub_one_prime', + h1'.emultiplicity_eq_multiplicity, h2'.emultiplicity_eq_multiplicity, + h3'.emultiplicity_eq_multiplicity, ← Nat.cast_add, ← Nat.cast_add, Nat.cast_le] at this omega open Units in @@ -501,11 +493,9 @@ private lemma lambda_not_dvd_z : ¬ λ ∣ S.z := fun h ↦ by section DecidableRel -variable [DecidableRel fun (a b : 𝓞 K) ↦ a ∣ b] - /-- We have that `λ ^ (3*S.multiplicity-2)` divides `S.a + S.b`. -/ private lemma lambda_pow_dvd_a_add_b : λ ^ (3 * S.multiplicity - 2) ∣ S.a + S.b := by - have h : λ ^ S.multiplicity ∣ S.c := multiplicity.pow_multiplicity_dvd _ + have h : λ ^ S.multiplicity ∣ S.c := pow_multiplicity_dvd _ _ replace h : (λ ^ multiplicity S) ^ 3 ∣ S.u * S.c ^ 3 := by simp [h] rw [← S.H, a_cube_add_b_cube_eq_mul, ← pow_mul, mul_comm, y_spec, z_spec] at h apply hζ.zeta_sub_one_prime'.pow_dvd_of_dvd_mul_left _ S.lambda_not_dvd_z @@ -524,13 +514,14 @@ private lemma x_spec : S.a + S.b = λ ^ (3 * S.multiplicity - 2) * S.x := /-- Given `S : Solution`, we let `S.w` be any element such that `S.c = λ ^ S.multiplicity * S.w` -/ private noncomputable def w := - (multiplicity.pow_multiplicity_dvd S.toSolution'.multiplicity_lambda_c_finite).choose + (pow_multiplicity_dvd (hζ.toInteger - 1) S.c).choose +omit [NumberField K] [IsCyclotomicExtension {3} ℚ K] in private lemma w_spec : S.c = λ ^ S.multiplicity * S.w := - (multiplicity.pow_multiplicity_dvd S.toSolution'.multiplicity_lambda_c_finite).choose_spec + (pow_multiplicity_dvd (hζ.toInteger - 1) S.c).choose_spec private lemma lambda_not_dvd_w : ¬ λ ∣ S.w := fun h ↦ by - refine multiplicity.is_greatest' S.toSolution'.multiplicity_lambda_c_finite + refine S.toSolution'.multiplicity_lambda_c_finite.not_pow_dvd_of_multiplicity_lt (lt_add_one S.multiplicity) ?_ rw [pow_succ', mul_comm] exact S.w_spec ▸ (mul_dvd_mul_left (λ ^ S.multiplicity) h) @@ -574,8 +565,6 @@ private lemma isCoprime_y_z : IsCoprime S.y S.z := (associated_of_dvd_a_add_eta_mul_b_of_dvd_a_add_eta_sq_mul_b S) (fun hq ↦ y_spec S ▸ hq.mul_left _) (fun hq ↦ z_spec S ▸ hq.mul_left _) -variable [DecidableRel fun (a b : 𝓞 K) ↦ a ∣ b] - private lemma x_mul_y_mul_z_eq_u_mul_w_cube : S.x * S.y * S.z = S.u * S.w ^ 3 := by suffices hh : λ ^ (3 * S.multiplicity - 2) * S.x * λ * S.y * λ * S.z = S.u * λ ^ (3 * S.multiplicity) * S.w ^ 3 by @@ -595,7 +584,7 @@ private lemma x_mul_y_mul_z_eq_u_mul_w_cube : S.x * S.y * S.z = S.u * S.w ^ 3 := private lemma exists_cube_associated : (∃ X, Associated (X ^ 3) S.x) ∧ (∃ Y, Associated (Y ^ 3) S.y) ∧ - ∃ Z, Associated (Z ^ 3) S.z := by + ∃ Z, Associated (Z ^ 3) S.z := by classical have h₁ := S.isCoprime_x_z.mul_left S.isCoprime_y_z have h₂ : Associated (S.w ^ 3) (S.x * S.y * S.z) := ⟨S.u, by rw [x_mul_y_mul_z_eq_u_mul_w_cube S, mul_comm]⟩ @@ -734,7 +723,8 @@ noncomputable def Solution'_descent : Solution' hζ where /-- We have that `S.Solution'_descent.multiplicity = S.multiplicity - 1`. -/ lemma Solution'_descent_multiplicity : S.Solution'_descent.multiplicity = S.multiplicity - 1 := by - refine (multiplicity.unique' (by simp [Solution'_descent]) (fun h ↦ S.lambda_not_dvd_X ?_)).symm + refine multiplicity_eq_of_dvd_of_not_dvd + (by simp [Solution'_descent]) (fun h ↦ S.lambda_not_dvd_X ?_) obtain ⟨k, hk : λ^(S.multiplicity-1)*S.X=λ^(S.multiplicity-1+1)*k⟩ := h rw [pow_succ, mul_assoc] at hk simp only [mul_eq_mul_left_iff, pow_eq_zero_iff', hζ.zeta_sub_one_prime'.ne_zero, ne_eq, @@ -750,7 +740,7 @@ lemma Solution'_descent_multiplicity_lt : /-- Given any `S : Solution`, there is another `S₁ : Solution` such that `S₁.multiplicity < S.multiplicity` -/ theorem exists_Solution_multiplicity_lt : - ∃ S₁ : Solution hζ, S₁.multiplicity < S.multiplicity := by + ∃ S₁ : Solution hζ, S₁.multiplicity < S.multiplicity := by classical obtain ⟨S', hS'⟩ := exists_Solution_of_Solution' (Solution'_descent S) exact ⟨S', hS' ▸ Solution'_descent_multiplicity_lt S⟩ diff --git a/Mathlib/NumberTheory/Fermat.lean b/Mathlib/NumberTheory/Fermat.lean new file mode 100644 index 0000000000000..0e3ab436b2414 --- /dev/null +++ b/Mathlib/NumberTheory/Fermat.lean @@ -0,0 +1,109 @@ +/- +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.Group.Finset +import Mathlib.Algebra.Order.Ring.Basic +import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Algebra.Order.Star.Basic +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Tactic.Ring.RingNF +import Mathlib.Tactic.Linarith + + +/-! +# Fermat numbers + +The Fermat numbers are a sequence of natural numbers defined as `Nat.fermatNumber n = 2^(2^n) + 1`, +for all natural numbers `n`. + +## Main theorems + +- `Nat.coprime_fermatNumber_fermatNumber`: two distinct Fermat numbers are coprime. +-/ + +namespace Nat + +open Finset + +/-- Fermat numbers: the `n`-th Fermat number is defined as `2^(2^n) + 1`. -/ +def fermatNumber (n : ℕ) : ℕ := 2 ^ (2 ^ n) + 1 + +@[simp] theorem fermatNumber_zero : fermatNumber 0 = 3 := rfl +@[simp] theorem fermatNumber_one : fermatNumber 1 = 5 := rfl +@[simp] theorem fermatNumber_two : fermatNumber 2 = 17 := rfl + +theorem strictMono_fermatNumber : StrictMono fermatNumber := by + intro m n + simp only [fermatNumber, add_lt_add_iff_right, pow_lt_pow_iff_right (one_lt_two : 1 < 2), + imp_self] + +theorem two_lt_fermatNumber (n : ℕ) : 2 < fermatNumber n := by + cases n + · simp + · exact lt_of_succ_lt <| strictMono_fermatNumber <| zero_lt_succ _ + +theorem odd_fermatNumber (n : ℕ) : Odd (fermatNumber n) := + (even_pow.mpr ⟨even_two, (pow_pos two_pos n).ne'⟩).add_one + +theorem fermatNumber_product (n : ℕ) : ∏ k in range n, fermatNumber k = fermatNumber n - 2 := by + induction' n with n hn + · rfl + rw [prod_range_succ, hn, fermatNumber, fermatNumber, mul_comm, + (show 2 ^ 2 ^ n + 1 - 2 = 2 ^ 2 ^ n - 1 by omega), ← sq_sub_sq] + ring_nf + omega + +theorem fermatNumber_eq_prod_add_two (n : ℕ) : + fermatNumber n = (∏ k in range n, fermatNumber k) + 2 := by + rw [fermatNumber_product, Nat.sub_add_cancel] + exact le_of_lt <| two_lt_fermatNumber _ + +theorem fermatNumber_succ (n : ℕ) : fermatNumber (n + 1) = (fermatNumber n - 1) ^ 2 + 1 := by + rw [fermatNumber, pow_succ, mul_comm, Nat.pow_mul'] + rfl + +theorem two_mul_fermatNumber_sub_one_sq_le_fermatNumber_sq (n : ℕ) : + 2 * (fermatNumber n - 1) ^ 2 ≤ (fermatNumber (n + 1)) ^ 2 := by + simp only [fermatNumber, add_tsub_cancel_right] + have : 0 ≤ 1 + 2 ^ (2 ^ n * 4) := le_add_left 0 (Nat.add 1 _) + ring_nf + linarith + +theorem fermatNumber_eq_fermatNumber_sq_sub_two_mul_fermatNumber_sub_one_sq (n : ℕ) : + fermatNumber (n + 2) = (fermatNumber (n + 1)) ^ 2 - 2 * (fermatNumber n - 1) ^ 2 := by + simp only [fermatNumber, add_sub_self_right] + rw [← add_sub_self_right (2 ^ 2 ^ (n + 2) + 1) <| 2 * 2 ^ 2 ^ (n + 1)] + ring_nf + +end Nat + +open Nat + +theorem Int.fermatNumber_eq_fermatNumber_sq_sub_two_mul_fermatNumber_sub_one_sq (n : ℕ) : + (fermatNumber (n + 2) : ℤ) = (fermatNumber (n + 1)) ^ 2 - 2 * (fermatNumber n - 1) ^ 2 := by + rw [Nat.fermatNumber_eq_fermatNumber_sq_sub_two_mul_fermatNumber_sub_one_sq, + Nat.cast_sub <| two_mul_fermatNumber_sub_one_sq_le_fermatNumber_sq n] + simp only [fermatNumber, push_cast, add_tsub_cancel_right] + +namespace Nat + +open Finset +/-- +**Goldbach's theorem** : no two distinct Fermat numbers share a common factor greater than one. + +From a letter to Euler, see page 37 in [juskevic2022]. +-/ +theorem coprime_fermatNumber_fermatNumber {k n : ℕ} (h : k ≠ n) : + Coprime (fermatNumber n) (fermatNumber k) := by + wlog hkn : k < n + · simpa only [coprime_comm] using this h.symm (by omega) + let m := (fermatNumber n).gcd (fermatNumber k) + have h_n : m ∣ fermatNumber n := (fermatNumber n).gcd_dvd_left (fermatNumber k) + have h_m : m ∣ 2 := (Nat.dvd_add_right <| (gcd_dvd_right _ _).trans <| dvd_prod_of_mem _ + <| mem_range.mpr hkn).mp <| fermatNumber_eq_prod_add_two _ ▸ h_n + refine ((dvd_prime prime_two).mp h_m).elim id (fun h_two ↦ ?_) + exact ((odd_fermatNumber _).not_two_dvd_nat (h_two ▸ h_n)).elim + +end Nat diff --git a/Mathlib/NumberTheory/FunctionField.lean b/Mathlib/NumberTheory/FunctionField.lean index 425189bfa3c7b..cd2a6cc65454d 100644 --- a/Mathlib/NumberTheory/FunctionField.lean +++ b/Mathlib/NumberTheory/FunctionField.lean @@ -44,7 +44,7 @@ noncomputable section open scoped nonZeroDivisors Polynomial Multiplicative -variable (Fq F : Type) [Field Fq] [Field F] +variable (Fq F : Type*) [Field Fq] [Field F] /-- `F` is a function field over the finite field `Fq` if it is a finite extension of the field of rational functions in one variable over `Fq`. @@ -54,7 +54,6 @@ Note that `F` can be a function field over multiple, non-isomorphic, `Fq`. abbrev FunctionField [Algebra (RatFunc Fq) F] : Prop := FiniteDimensional (RatFunc Fq) F --- Porting note: Removed `protected` /-- `F` is a function field over `Fq` iff it is a finite extension of `Fq(t)`. -/ theorem functionField_iff (Fqt : Type*) [Field Fqt] [Algebra Fq[X] Fqt] [IsFractionRing Fq[X] Fqt] [Algebra (RatFunc Fq) F] [Algebra Fqt F] [Algebra Fq[X] F] diff --git a/Mathlib/NumberTheory/Harmonic/Defs.lean b/Mathlib/NumberTheory/Harmonic/Defs.lean index a7887fff3ff84..effef54ba3920 100644 --- a/Mathlib/NumberTheory/Harmonic/Defs.lean +++ b/Mathlib/NumberTheory/Harmonic/Defs.lean @@ -4,9 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Koundinya Vajjha, Thomas Browning -/ import Mathlib.Algebra.BigOperators.Intervals -import Mathlib.Algebra.Order.BigOperators.Ring.Finset -import Mathlib.Algebra.Order.Field.Basic -import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity.Finset /-! diff --git a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean index 99e63c94ec211..1d28455e91d2f 100644 --- a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean +++ b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean @@ -58,7 +58,7 @@ lemma term_nonneg (n : ℕ) (s : ℝ) : 0 ≤ term n s := by lemma term_welldef {n : ℕ} (hn : 0 < n) {s : ℝ} (hs : 0 < s) : IntervalIntegrable (fun x : ℝ ↦ (x - n) / x ^ (s + 1)) volume n (n + 1) := by rw [intervalIntegrable_iff_integrableOn_Icc_of_le (by linarith)] - refine (ContinuousAt.continuousOn fun x hx ↦ ContinuousAt.div ?_ ?_ ?_).integrableOn_Icc + refine (continuousOn_of_forall_continuousAt fun x hx ↦ ContinuousAt.div ?_ ?_ ?_).integrableOn_Icc · fun_prop · apply continuousAt_id.rpow_const (Or.inr <| by linarith) · exact (rpow_pos_of_pos ((Nat.cast_pos.mpr hn).trans_le hx.1) _).ne' @@ -261,7 +261,7 @@ lemma continuousOn_term (n : ℕ) : exact_mod_cast term_welldef (by linarith : 0 < (n + 1)) zero_lt_one · rw [ae_restrict_iff' measurableSet_Ioc] filter_upwards with x hx - refine ContinuousAt.continuousOn (fun s (hs : 1 ≤ s) ↦ continuousAt_const.div ?_ ?_) + refine continuousOn_of_forall_continuousAt (fun s (hs : 1 ≤ s) ↦ continuousAt_const.div ?_ ?_) · exact continuousAt_const.rpow (continuousAt_id.add continuousAt_const) (Or.inr (by linarith)) · exact (rpow_pos_of_pos ((Nat.cast_pos.mpr (by simp)).trans hx.1) _).ne' diff --git a/Mathlib/NumberTheory/JacobiSum/Basic.lean b/Mathlib/NumberTheory/JacobiSum/Basic.lean index 9088bfbe869f8..2de42f2e7d95b 100644 --- a/Mathlib/NumberTheory/JacobiSum/Basic.lean +++ b/Mathlib/NumberTheory/JacobiSum/Basic.lean @@ -28,7 +28,7 @@ but generalize where appropriate. This is based on Lean code written as part of the bachelor's thesis of Alexander Spahl. -/ -open BigOperators Finset +open Finset /-! ### Jacobi sums: definition and first properties @@ -107,7 +107,7 @@ theorem jacobiSum_trivial_trivial : simpa only [isUnit_iff_ne_zero, mul_ne_zero_iff, ne_eq, sub_eq_zero, @eq_comm _ _ x] using hx calc ∑ x ∈ univ \ {0, 1}, (MulChar.trivial F R) x * (MulChar.trivial F R) (1 - x) _ = ∑ _ ∈ univ \ {0, 1}, 1 := sum_congr rfl this - _ = Finset.card (univ \ {0, 1}) := (cast_card _).symm + _ = #(univ \ {0, 1}) := (cast_card _).symm _ = Fintype.card F - 2 := by rw [card_sdiff (subset_univ _), card_univ, card_pair zero_ne_one, Nat.cast_sub <| Nat.add_one_le_of_lt Fintype.one_lt_card, Nat.cast_two] @@ -269,7 +269,7 @@ lemma MulChar.exists_apply_sub_one_mul_apply_sub_one {n : ℕ} (hn : n ≠ 0) { /-- If `χ` and `ψ` are multiplicative characters of order dividing `n` on a finite field `F` with values in an integral domain `R` and `μ` is a primitive `n`th root of unity in `R`, then `J(χ,ψ) = -1 + z*(μ - 1)^2` for some `z ∈ ℤ[μ] ⊆ R`. (We assume that `#F ≡ 1 mod n`.) -Note that we do not state this as a divisbility in `R`, as this would give a weaker statement. -/ +Note that we do not state this as a divisibility in `R`, as this would give a weaker statement. -/ lemma exists_jacobiSum_eq_neg_one_add {n : ℕ} (hn : 2 < n) {χ ψ : MulChar F R} {μ : R} (hχ : χ ^ n = 1) (hψ : ψ ^ n = 1) (hn' : n ∣ Fintype.card F - 1) (hμ : IsPrimitiveRoot μ n) : diff --git a/Mathlib/NumberTheory/KummerDedekind.lean b/Mathlib/NumberTheory/KummerDedekind.lean index b93799f8bfa38..f3827e812c309 100644 --- a/Mathlib/NumberTheory/KummerDedekind.lean +++ b/Mathlib/NumberTheory/KummerDedekind.lean @@ -258,16 +258,16 @@ noncomputable def normalizedFactorsMapEquivNormalizedFactorsMinPolyMk (hI : IsMa open Classical in /-- The second half of the **Kummer-Dedekind Theorem** in the monogenic case, stating that the bijection `FactorsEquiv'` defined in the first half preserves multiplicities. -/ -theorem multiplicity_factors_map_eq_multiplicity +theorem emultiplicity_factors_map_eq_emultiplicity (hI : IsMaximal I) (hI' : I ≠ ⊥) (hx : (conductor R x).comap (algebraMap R S) ⊔ I = ⊤) (hx' : IsIntegral R x) {J : Ideal S} (hJ : J ∈ normalizedFactors (I.map (algebraMap R S))) : - multiplicity J (I.map (algebraMap R S)) = - multiplicity (↑(normalizedFactorsMapEquivNormalizedFactorsMinPolyMk hI hI' hx hx' ⟨J, hJ⟩)) + emultiplicity J (I.map (algebraMap R S)) = + emultiplicity (↑(normalizedFactorsMapEquivNormalizedFactorsMinPolyMk hI hI' hx hx' ⟨J, hJ⟩)) (Polynomial.map (Ideal.Quotient.mk I) (minpoly R x)) := by rw [normalizedFactorsMapEquivNormalizedFactorsMinPolyMk, Equiv.coe_trans, Function.comp_apply, - multiplicity_normalizedFactorsEquivSpanNormalizedFactors_symm_eq_multiplicity, - normalizedFactorsEquivOfQuotEquiv_multiplicity_eq_multiplicity] + emultiplicity_normalizedFactorsEquivSpanNormalizedFactors_symm_eq_emultiplicity, + normalizedFactorsEquivOfQuotEquiv_emultiplicity_eq_emultiplicity] open Classical in /-- The **Kummer-Dedekind Theorem**. -/ @@ -288,10 +288,10 @@ theorem normalizedFactors_ideal_map_eq_normalizedFactors_min_poly_mk_map (hI : I exact hJ ((normalizedFactorsMapEquivNormalizedFactorsMinPolyMk hI hI' hx hx').symm J').prop -- Then we just have to compare the multiplicities, which we already proved are equal. - have := multiplicity_factors_map_eq_multiplicity hI hI' hx hx' hJ - rw [multiplicity_eq_count_normalizedFactors, multiplicity_eq_count_normalizedFactors, + have := emultiplicity_factors_map_eq_emultiplicity hI hI' hx hx' hJ + rw [emultiplicity_eq_count_normalizedFactors, emultiplicity_eq_count_normalizedFactors, UniqueFactorizationMonoid.normalize_normalized_factor _ hJ, - UniqueFactorizationMonoid.normalize_normalized_factor, PartENat.natCast_inj] at this + UniqueFactorizationMonoid.normalize_normalized_factor, Nat.cast_inj] at this · refine this.trans ?_ -- Get rid of the `map` by applying the equiv to both sides. generalize hJ' : diff --git a/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean b/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean index 6c8bfa2572edc..493dc137e80c5 100644 --- a/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean +++ b/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean @@ -167,7 +167,7 @@ lemma hf_zero' (P : WeakFEPair E) : filter_upwards [eventually_le_nhds zero_lt_one] with x hx' (hx : 0 < x) apply le_mul_of_one_le_right (norm_nonneg _) rw [norm_of_nonneg (rpow_pos_of_pos hx _).le, rpow_neg hx.le] - exact one_le_inv (rpow_pos_of_pos hx _) (rpow_le_one hx.le hx' P.hk.le) + exact (one_le_inv₀ (rpow_pos_of_pos hx _)).2 (rpow_le_one hx.le hx' P.hk.le) end WeakFEPair @@ -226,8 +226,8 @@ theorem functional_equation (s : ℂ) : have step3 := mellin_const_smul (fun t ↦ (t : ℂ) ^ (-P.k : ℂ) • P.g (1 / t)) (P.k - s) P.ε rw [step2] at step3 rw [← step3] - -- now the integrand matches `P.h_feq'` on `Ioi 0`, so we can apply `setIntegral_congr` - refine setIntegral_congr measurableSet_Ioi (fun t ht ↦ ?_) + -- now the integrand matches `P.h_feq'` on `Ioi 0`, so we can apply `setIntegral_congr_fun` + refine setIntegral_congr_fun measurableSet_Ioi (fun t ht ↦ ?_) simp_rw [P.h_feq' t ht, ← mul_smul] -- some simple `cpow` arithmetic to finish rw [cpow_neg, ofReal_cpow (le_of_lt ht)] @@ -261,7 +261,7 @@ lemma hf_modif_int : LocallyIntegrableOn P.f_modif (Ioi 0) := by have : LocallyIntegrableOn (fun x : ℝ ↦ (P.ε * ↑(x ^ (-P.k))) • P.g₀) (Ioi 0) := by refine ContinuousOn.locallyIntegrableOn ?_ measurableSet_Ioi - refine ContinuousAt.continuousOn (fun x (hx : 0 < x) ↦ ?_) + refine continuousOn_of_forall_continuousAt (fun x (hx : 0 < x) ↦ ?_) refine (continuousAt_const.mul ?_).smul continuousAt_const exact continuous_ofReal.continuousAt.comp (continuousAt_rpow_const _ _ (Or.inl hx.ne')) refine LocallyIntegrableOn.add (fun x hx ↦ ?_) (fun x hx ↦ ?_) @@ -343,7 +343,7 @@ lemma f_modif_aux2 [CompleteSpace E] {s : ℂ} (hs : P.k < re s) : _ = ∫ (x : ℝ) in Ioi 0, (x : ℂ) ^ (s - 1) • ((Ioo 0 1).indicator (fun t : ℝ ↦ P.f₀ - (P.ε * ↑(t ^ (-P.k))) • P.g₀) x + ({1} : Set ℝ).indicator (fun _ ↦ P.f₀ - P.f 1) x) := - setIntegral_congr measurableSet_Ioi (fun x hx ↦ by simp [f_modif_aux1 P hx]) + setIntegral_congr_fun measurableSet_Ioi (fun x hx ↦ by simp [f_modif_aux1 P hx]) _ = ∫ (x : ℝ) in Ioi 0, (x : ℂ) ^ (s - 1) • ((Ioo 0 1).indicator (fun t : ℝ ↦ P.f₀ - (P.ε * ↑(t ^ (-P.k))) • P.g₀) x) := by refine setIntegral_congr_ae measurableSet_Ioi (eventually_of_mem (U := {1}ᶜ) @@ -353,7 +353,7 @@ lemma f_modif_aux2 [CompleteSpace E] {s : ℂ} (hs : P.k < re s) : simp_rw [← indicator_smul, setIntegral_indicator measurableSet_Ioo, inter_eq_right.mpr Ioo_subset_Ioi_self, integral_Ioc_eq_integral_Ioo] _ = ∫ x : ℝ in Ioc 0 1, ((x : ℂ) ^ (s - 1) • P.f₀ - P.ε • (x : ℂ) ^ (s - P.k - 1) • P.g₀) := by - refine setIntegral_congr measurableSet_Ioc (fun x ⟨hx, _⟩ ↦ ?_) + refine setIntegral_congr_fun measurableSet_Ioc (fun x ⟨hx, _⟩ ↦ ?_) rw [ofReal_cpow hx.le, ofReal_neg, smul_sub, ← mul_smul, mul_comm, mul_assoc, mul_smul, mul_comm, ← cpow_add _ _ (ofReal_ne_zero.mpr hx.ne'), ← sub_eq_add_neg, sub_right_comm] _ = (∫ (x : ℝ) in Ioc 0 1, (x : ℂ) ^ (s - 1)) • P.f₀ diff --git a/Mathlib/NumberTheory/LSeries/Basic.lean b/Mathlib/NumberTheory/LSeries/Basic.lean index 7221b06b0360f..99720f95d8532 100644 --- a/Mathlib/NumberTheory/LSeries/Basic.lean +++ b/Mathlib/NumberTheory/LSeries/Basic.lean @@ -111,6 +111,20 @@ lemma norm_term_le_of_re_le_re (f : ℕ → ℂ) {s s' : ℂ} (h : s.re ≤ s'.r next => rfl next hn => gcongr; exact Nat.one_le_cast.mpr <| Nat.one_le_iff_ne_zero.mpr hn +section positivity + +open scoped ComplexOrder + +lemma term_nonneg {a : ℕ → ℂ} {n : ℕ} (h : 0 ≤ a n) (x : ℝ) : 0 ≤ term a x n := by + rw [term_def] + split_ifs with hn + exacts [le_rfl, mul_nonneg h (inv_natCast_cpow_ofReal_pos hn x).le] + +lemma term_pos {a : ℕ → ℂ} {n : ℕ} (hn : n ≠ 0) (h : 0 < a n) (x : ℝ) : 0 < term a x n := by + simpa only [term_of_ne_zero hn] using mul_pos h <| inv_natCast_cpow_ofReal_pos hn x + +end positivity + end LSeries /-! diff --git a/Mathlib/NumberTheory/LSeries/Dirichlet.lean b/Mathlib/NumberTheory/LSeries/Dirichlet.lean index 6e6fed2c20936..f82517ccefe5d 100644 --- a/Mathlib/NumberTheory/LSeries/Dirichlet.lean +++ b/Mathlib/NumberTheory/LSeries/Dirichlet.lean @@ -329,7 +329,7 @@ lemma convolution_vonMangoldt_zeta : ↗Λ ⍟ ↗ζ = ↗Complex.log := by ext n simpa only [zeta_apply, apply_ite, cast_zero, cast_one, LSeries.convolution_def, mul_zero, mul_one, mul_apply, natCoe_apply, ofReal_sum, ofReal_zero, log_apply, ofReal_log n.cast_nonneg] - using congr_arg (ofReal' <| · n) vonMangoldt_mul_zeta + using congr_arg (ofReal <| · n) vonMangoldt_mul_zeta lemma convolution_vonMangoldt_const_one : ↗Λ ⍟ 1 = ↗Complex.log := (convolution_one_eq_convolution_zeta _).trans convolution_vonMangoldt_zeta diff --git a/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean index dd4b132bc5130..c6286c93a9c72 100644 --- a/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean +++ b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean @@ -1,31 +1,46 @@ /- Copyright (c) 2024 David Loeffler. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: David Loeffler +Authors: David Loeffler, Michael Stoll -/ import Mathlib.NumberTheory.LSeries.ZMod import Mathlib.NumberTheory.DirichletCharacter.Basic +import Mathlib.NumberTheory.EulerProduct.DirichletLSeries /-! # Analytic continuation of Dirichlet L-functions We show that if `χ` is a Dirichlet character `ZMod N → ℂ`, for a positive integer `N`, then the -L-series of `χ` has analytic continuation (away from a pole at `s = 1` if `χ` is trivial). +L-series of `χ` has analytic continuation (away from a pole at `s = 1` if `χ` is trivial), and +similarly for completed L-functions. All definitions and theorems are in the `DirichletCharacter` namespace. ## Main definitions * `LFunction χ s`: the L-function, defined as a linear combination of Hurwitz zeta functions. +* `completedLFunction χ s`: the completed L-function, which for *almost* all `s` is equal to + `LFunction χ s * gammaFactor χ s` where `gammaFactor χ s` is the archimedean Gamma-factor. +* `rootNumber`: the global root number of the L-series of `χ` (for `χ` primitive; junk otherwise). ## Main theorems * `LFunction_eq_LSeries`: if `1 < re s` then the `LFunction` coincides with the naive `LSeries`. * `differentiable_LFunction`: if `χ` is nontrivial then `LFunction χ s` is differentiable everywhere. +* `LFunction_eq_completed_div_gammaFactor`: we have + `LFunction χ s = completedLFunction χ s / gammaFactor χ s`, unless `s = 0` and `χ` is the trivial + character modulo 1. +* `differentiable_completedLFunction`: if `χ` is nontrivial then `completedLFunction χ s` is + differentiable everywhere. +* `IsPrimitive.completedLFunction_one_sub`: the **functional equation** for Dirichlet L-functions, + showing that if `χ` is primitive modulo `N`, then + `completedLFunction χ s = N ^ (s - 1 / 2) * rootNumber χ * completedLFunction χ⁻¹ s`. -/ -open Complex +open HurwitzZeta Complex Finset Classical ZMod Filter + +open scoped Real Topology namespace DirichletCharacter @@ -38,13 +53,16 @@ latter is convergent. This is constructed as a linear combination of Hurwitz zet Note that this is not the same as `LSeries χ`: they agree in the convergence range, but `LSeries χ s` is defined to be `0` if `re s ≤ 1`. -/ +@[pp_nodot] noncomputable def LFunction (χ : DirichletCharacter ℂ N) (s : ℂ) : ℂ := ZMod.LFunction χ s -/-- The L-function of the (unique) Dirichlet character mod 1 is the Riemann zeta function. -(Compare `DirichletCharacter.LSeries_modOne_eq`.) -/ +/-- +The L-function of the (unique) Dirichlet character mod 1 is the Riemann zeta function. +(Compare `DirichletCharacter.LSeries_modOne_eq`.) +-/ @[simp] lemma LFunction_modOne_eq {χ : DirichletCharacter ℂ 1} : LFunction χ = riemannZeta := by - ext1; rw [LFunction, ZMod.LFunction_modOne_eq, (by rfl : (0 : ZMod 1) = 1), map_one, one_mul] + ext; rw [LFunction, ZMod.LFunction_modOne_eq, (by rfl : (0 : ZMod 1) = 1), map_one, one_mul] /-- For `1 < re s` the L-function of a Dirichlet character agrees with the sum of the naive Dirichlet @@ -67,4 +85,217 @@ lemma differentiable_LFunction {χ : DirichletCharacter ℂ N} (hχ : χ ≠ 1) Differentiable ℂ (LFunction χ) := (differentiableAt_LFunction _ · <| Or.inr hχ) +/-- The L-function of an even Dirichlet character vanishes at strictly negative even integers. -/ +@[simp] +lemma Even.LFunction_neg_two_mul_nat_add_one {χ : DirichletCharacter ℂ N} (hχ : Even χ) (n : ℕ) : + LFunction χ (-(2 * (n + 1))) = 0 := + ZMod.LFunction_neg_two_mul_nat_add_one hχ.to_fun n + +/-- The L-function of an even Dirichlet character vanishes at strictly negative even integers. -/ +@[simp] +lemma Even.LFunction_neg_two_mul_nat {χ : DirichletCharacter ℂ N} (hχ : Even χ) (n : ℕ) [NeZero n] : + LFunction χ (-(2 * n)) = 0 := by + obtain ⟨m, rfl⟩ := Nat.exists_eq_succ_of_ne_zero (NeZero.ne n) + exact_mod_cast hχ.LFunction_neg_two_mul_nat_add_one m + +/-- The L-function of an odd Dirichlet character vanishes at negative odd integers. -/ +@[simp] lemma Odd.LFunction_neg_two_mul_nat_sub_one + {χ : DirichletCharacter ℂ N} (hχ : Odd χ) (n : ℕ) : + LFunction χ (-(2 * n) - 1) = 0 := + ZMod.LFunction_neg_two_mul_nat_sub_one hχ.to_fun n + +/-! +## Results on changing levels +-/ + +private lemma LFunction_changeLevel_aux {M N : ℕ} [NeZero M] [NeZero N] (hMN : M ∣ N) + (χ : DirichletCharacter ℂ M) {s : ℂ} (hs : s ≠ 1) : + LFunction (changeLevel hMN χ) s = + LFunction χ s * ∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s)) := by + have hpc : IsPreconnected ({1}ᶜ : Set ℂ) := + (isConnected_compl_singleton_of_one_lt_rank (rank_real_complex ▸ Nat.one_lt_ofNat) _) + |>.isPreconnected + have hne : 2 ∈ ({1}ᶜ : Set ℂ) := by norm_num + refine AnalyticOnNhd.eqOn_of_preconnected_of_eventuallyEq (𝕜 := ℂ) + (g := fun s ↦ LFunction χ s * ∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s))) ?_ ?_ hpc hne ?_ hs + · refine DifferentiableOn.analyticOnNhd (fun s hs ↦ ?_) isOpen_compl_singleton + exact (differentiableAt_LFunction _ _ (.inl hs)).differentiableWithinAt + · refine DifferentiableOn.analyticOnNhd (fun s hs ↦ ?_) isOpen_compl_singleton + refine ((differentiableAt_LFunction _ _ (.inl hs)).mul ?_).differentiableWithinAt + refine .finset_prod fun i h ↦ ?_ + have : NeZero i := ⟨(Nat.pos_of_mem_primeFactors h).ne'⟩ + fun_prop + · refine eventually_of_mem ?_ (fun t (ht : 1 < t.re) ↦ ?_) + · exact (continuous_re.isOpen_preimage _ isOpen_Ioi).mem_nhds (by norm_num : 1 < (2 : ℂ).re) + · simpa only [LFunction_eq_LSeries _ ht] using LSeries_changeLevel hMN χ ht + +/-- If `χ` is a Dirichlet character and its level `M` divides `N`, then we obtain the L function +of `χ` considered as a Dirichlet character of level `N` from the L function of `χ` by multiplying +with `∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s))`. +(Note that `1 - χ p * p ^ (-s) = 1` when `p` divides `M`). -/ +lemma LFunction_changeLevel {M N : ℕ} [NeZero M] [NeZero N] (hMN : M ∣ N) + (χ : DirichletCharacter ℂ M) {s : ℂ} (h : χ ≠ 1 ∨ s ≠ 1) : + LFunction (changeLevel hMN χ) s = + LFunction χ s * ∏ p ∈ N.primeFactors, (1 - χ p * p ^ (-s)) := by + rcases h with h | h + · have hχ : changeLevel hMN χ ≠ 1 := h ∘ (changeLevel_eq_one_iff hMN).mp + have h' : Continuous fun s ↦ LFunction χ s * ∏ p ∈ N.primeFactors, (1 - χ p * ↑p ^ (-s)) := + (differentiable_LFunction h).continuous.mul <| continuous_finset_prod _ fun p hp ↦ by + have : NeZero p := ⟨(Nat.prime_of_mem_primeFactors hp).ne_zero⟩ + fun_prop + exact congrFun ((differentiable_LFunction hχ).continuous.ext_on + (dense_compl_singleton 1) h' (fun _ h ↦ LFunction_changeLevel_aux hMN χ h)) s + · exact LFunction_changeLevel_aux hMN χ h + +/-! +## The `L`-function of the trivial character mod `N` +-/ + +/-- The `L`-function of the trivial character mod `N`. -/ +noncomputable abbrev LFunctionTrivChar (N : ℕ) [NeZero N] := + (1 : DirichletCharacter ℂ N).LFunction + +/-- The L function of the trivial Dirichlet character mod `N` is obtained from the Riemann +zeta function by multiplying with `∏ p ∈ N.primeFactors, (1 - (p : ℂ) ^ (-s))`. -/ +lemma LFunctionTrivChar_eq_mul_riemannZeta {s : ℂ} (hs : s ≠ 1) : + LFunctionTrivChar N s = (∏ p ∈ N.primeFactors, (1 - (p : ℂ) ^ (-s))) * riemannZeta s := by + rw [← LFunction_modOne_eq (χ := 1), LFunctionTrivChar, ← changeLevel_one N.one_dvd, mul_comm] + convert LFunction_changeLevel N.one_dvd 1 (.inr hs) using 4 with p + rw [MulChar.one_apply <| isUnit_of_subsingleton _, one_mul] + +/-- The L function of the trivial Dirichlet character mod `N` has a simple pole with +residue `∏ p ∈ N.primeFactors, (1 - p⁻¹)` at `s = 1`. -/ +lemma LFunctionTrivChar_residue_one : + Tendsto (fun s ↦ (s - 1) * LFunctionTrivChar N s) (𝓝[≠] 1) + (𝓝 <| ∏ p ∈ N.primeFactors, (1 - (p : ℂ)⁻¹)) := by + have H : (fun s ↦ (s - 1) * LFunctionTrivChar N s) =ᶠ[𝓝[≠] 1] + fun s ↦ (∏ p ∈ N.primeFactors, (1 - (p : ℂ) ^ (-s))) * ((s - 1) * riemannZeta s) := by + refine Set.EqOn.eventuallyEq_nhdsWithin fun s hs ↦ ?_ + rw [mul_left_comm, LFunctionTrivChar_eq_mul_riemannZeta hs] + rw [tendsto_congr' H] + conv => enter [3, 1]; rw [← mul_one <| Finset.prod ..]; enter [1, 2, p]; rw [← cpow_neg_one] + refine .mul (f := fun s ↦ ∏ p ∈ N.primeFactors, _) ?_ riemannZeta_residue_one + refine tendsto_nhdsWithin_of_tendsto_nhds <| Continuous.tendsto ?_ 1 + exact continuous_finset_prod _ fun p hp ↦ by + have : NeZero p := ⟨(Nat.prime_of_mem_primeFactors hp).ne_zero⟩ + fun_prop + +/-! +## Completed L-functions and the functional equation +-/ + +section gammaFactor + +omit [NeZero N] -- not required for these declarations + +/-- The Archimedean Gamma factor: `Gammaℝ s` if `χ` is even, and `Gammaℝ (s + 1)` otherwise. -/ +noncomputable def gammaFactor (χ : DirichletCharacter ℂ N) (s : ℂ) := + if χ.Even then Gammaℝ s else Gammaℝ (s + 1) + +lemma Even.gammaFactor_def {χ : DirichletCharacter ℂ N} (hχ : χ.Even) (s : ℂ) : + gammaFactor χ s = Gammaℝ s := by + simp only [gammaFactor, hχ, ↓reduceIte] + +lemma Odd.gammaFactor_def {χ : DirichletCharacter ℂ N} (hχ : χ.Odd) (s : ℂ) : + gammaFactor χ s = Gammaℝ (s + 1) := by + simp only [gammaFactor, hχ.not_even, ↓reduceIte] + +end gammaFactor + +/-- +The completed L-function of a Dirichlet character, almost everywhere equal to +`LFunction χ s * gammaFactor χ s`. +-/ +@[pp_nodot] noncomputable def completedLFunction (χ : DirichletCharacter ℂ N) (s : ℂ) : ℂ := + ZMod.completedLFunction χ s + +/-- +The completed L-function of the (unique) Dirichlet character mod 1 is the completed Riemann zeta +function. +-/ +lemma completedLFunction_modOne_eq {χ : DirichletCharacter ℂ 1} : + completedLFunction χ = completedRiemannZeta := by + ext; rw [completedLFunction, ZMod.completedLFunction_modOne_eq, map_one, one_mul] + +/-- +The completed L-function of a Dirichlet character is differentiable, with the following +exceptions: at `s = 1` if `χ` is the trivial character (to any modulus); and at `s = 0` if the +modulus is 1. This result is best possible. + +Note both `χ` and `s` are explicit arguments: we will always be able to infer one or other +of them from the hypotheses, but it's not clear which! +-/ +lemma differentiableAt_completedLFunction (χ : DirichletCharacter ℂ N) (s : ℂ) + (hs₀ : s ≠ 0 ∨ N ≠ 1) (hs₁ : s ≠ 1 ∨ χ ≠ 1) : + DifferentiableAt ℂ (completedLFunction χ) s := + ZMod.differentiableAt_completedLFunction _ _ (by have := χ.map_zero'; tauto) + (by have := χ.sum_eq_zero_of_ne_one; tauto) + +/-- The completed L-function of a non-trivial Dirichlet character is differentiable everywhere. -/ +lemma differentiable_completedLFunction {χ : DirichletCharacter ℂ N} (hχ : χ ≠ 1) : + Differentiable ℂ (completedLFunction χ) := by + refine fun s ↦ differentiableAt_completedLFunction _ _ (Or.inr ?_) (Or.inr hχ) + exact hχ ∘ level_one' _ + +/-- +Relation between the completed L-function and the usual one. We state it this way around so +it holds at the poles of the gamma factor as well. +-/ +lemma LFunction_eq_completed_div_gammaFactor (χ : DirichletCharacter ℂ N) (s : ℂ) + (h : s ≠ 0 ∨ N ≠ 1) : LFunction χ s = completedLFunction χ s / gammaFactor χ s := by + rcases χ.even_or_odd with hχ | hχ <;> + rw [hχ.gammaFactor_def] + · exact LFunction_eq_completed_div_gammaFactor_even hχ.to_fun _ (h.imp_right χ.map_zero') + · apply LFunction_eq_completed_div_gammaFactor_odd hχ.to_fun + +/-- +Global root number of `χ` (for `χ` primitive; junk otherwise). Defined as +`gaussSum χ stdAddChar / I ^ a / N ^ (1 / 2)`, where `a = 0` if even, `a = 1` if odd. (The factor +`1 / I ^ a` is the Archimedean root number.) This is a complex number of absolute value 1. +-/ +noncomputable def rootNumber (χ : DirichletCharacter ℂ N) : ℂ := + gaussSum χ stdAddChar / I ^ (if χ.Even then 0 else 1) / N ^ (1 / 2 : ℂ) + +/-- The root number of the unique Dirichlet character modulo 1 is 1. -/ +lemma rootNumber_modOne (χ : DirichletCharacter ℂ 1) : rootNumber χ = 1 := by + simp only [rootNumber, gaussSum, ← singleton_eq_univ (1 : ZMod 1), sum_singleton, map_one, + (show stdAddChar (1 : ZMod 1) = 1 from AddChar.map_zero_eq_one _), one_mul, + (show χ.Even from map_one _), ite_true, pow_zero, div_one, Nat.cast_one, one_cpow] + +namespace IsPrimitive + +/-- **Functional equation** for primitive Dirichlet L-functions. -/ +theorem completedLFunction_one_sub {χ : DirichletCharacter ℂ N} (hχ : IsPrimitive χ) (s : ℂ) : + completedLFunction χ (1 - s) = N ^ (s - 1 / 2) * rootNumber χ * completedLFunction χ⁻¹ s := by + -- First handle special case of Riemann zeta + rcases eq_or_ne N 1 with rfl | hN + · simp only [completedLFunction_modOne_eq, completedRiemannZeta_one_sub, Nat.cast_one, one_cpow, + rootNumber_modOne, one_mul] + -- facts about `χ` as function + have h_sum : ∑ j, χ j = 0 := by + refine χ.sum_eq_zero_of_ne_one (fun h ↦ hN.symm ?_) + rwa [IsPrimitive, h, conductor_one (NeZero.ne _)] at hχ + let ε := I ^ (if χ.Even then 0 else 1) + -- gather up powers of N + rw [rootNumber, ← mul_comm_div, ← mul_comm_div, ← cpow_sub _ _ (NeZero.ne _), sub_sub, add_halves] + calc completedLFunction χ (1 - s) + _ = N ^ (s - 1) * χ (-1) / ε * ZMod.completedLFunction (𝓕 χ) s := by + simp only [ε] + split_ifs with h + · rw [pow_zero, div_one, h, mul_one, completedLFunction, + completedLFunction_one_sub_even h.to_fun _ (.inr h_sum) (.inr <| χ.map_zero' hN)] + · replace h : χ.Odd := χ.even_or_odd.resolve_left h + rw [completedLFunction, completedLFunction_one_sub_odd h.to_fun, + pow_one, h, div_I, mul_neg_one, ← neg_mul, neg_neg] + _ = (_) * ZMod.completedLFunction (fun j ↦ χ⁻¹ (-1) * gaussSum χ stdAddChar * χ⁻¹ j) s := by + congr 2 with j + rw [hχ.fourierTransform_eq_inv_mul_gaussSum, ← neg_one_mul j, map_mul, mul_right_comm] + _ = N ^ (s - 1) / ε * gaussSum χ stdAddChar * completedLFunction χ⁻¹ s * (χ (-1) * χ⁻¹ (-1)):= by + rw [completedLFunction, completedLFunction_const_mul] + ring + _ = N ^ (s - 1) / ε * gaussSum χ stdAddChar * completedLFunction χ⁻¹ s := by + rw [← MulChar.mul_apply, mul_inv_cancel, MulChar.one_apply (isUnit_one.neg), mul_one] + +end IsPrimitive + end DirichletCharacter diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean index ac307e2324e77..32584ac967cdb 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean @@ -119,7 +119,7 @@ lemma continuousOn_evenKernel (a : UnitAddCircle) : ContinuousOn (evenKernel a) induction' a using QuotientAddGroup.induction_on with a' apply continuous_re.comp_continuousOn (f := fun x ↦ (evenKernel a' x : ℂ)) simp only [evenKernel_def a'] - refine ContinuousAt.continuousOn (fun x hx ↦ ((Continuous.continuousAt ?_).mul ?_)) + refine continuousOn_of_forall_continuousAt (fun x hx ↦ ((Continuous.continuousAt ?_).mul ?_)) · exact Complex.continuous_exp.comp (continuous_const.mul continuous_ofReal) · have h := continuousAt_jacobiTheta₂ (a' * I * x) (?_ : 0 < im (I * x)) · exact h.comp (f := fun u : ℝ ↦ (a' * I * u, I * u)) (by fun_prop) @@ -129,7 +129,7 @@ lemma continuousOn_cosKernel (a : UnitAddCircle) : ContinuousOn (cosKernel a) (I induction' a using QuotientAddGroup.induction_on with a' apply continuous_re.comp_continuousOn (f := fun x ↦ (cosKernel a' x : ℂ)) simp only [cosKernel_def] - refine ContinuousAt.continuousOn (fun x hx ↦ ?_) + refine continuousOn_of_forall_continuousAt (fun x hx ↦ ?_) have : 0 < im (I * x) := by rwa [mul_im, I_re, I_im, zero_mul, one_mul, zero_add, ofReal_re] exact (continuousAt_jacobiTheta₂ a' this).comp (f := fun u : ℝ ↦ (_, I * u)) (by fun_prop) @@ -269,8 +269,8 @@ section FEPair /-- A `WeakFEPair` structure with `f = evenKernel a` and `g = cosKernel a`. -/ def hurwitzEvenFEPair (a : UnitAddCircle) : WeakFEPair ℂ where - f := ofReal' ∘ evenKernel a - g := ofReal' ∘ cosKernel a + f := ofReal ∘ evenKernel a + g := ofReal ∘ cosKernel a hf_int := (continuous_ofReal.comp_continuousOn (continuousOn_evenKernel a)).locallyIntegrableOn measurableSet_Ioi hg_int := (continuous_ofReal.comp_continuousOn (continuousOn_cosKernel a)).locallyIntegrableOn @@ -288,7 +288,7 @@ def hurwitzEvenFEPair (a : UnitAddCircle) : WeakFEPair ℂ where hg_top r := by obtain ⟨p, hp, hp'⟩ := isBigO_atTop_cosKernel_sub a rw [← isBigO_norm_left] at hp' ⊢ - have (x : ℝ) : ‖(ofReal' ∘ cosKernel a) x - 1‖ = ‖cosKernel a x - 1‖ := by + have (x : ℝ) : ‖(ofReal ∘ cosKernel a) x - 1‖ = ‖cosKernel a x - 1‖ := by rw [← norm_real, ofReal_sub, ofReal_one, Function.comp_apply] simp only [this] exact hp'.trans (isLittleO_exp_neg_mul_rpow_atTop hp _).isBigO @@ -555,7 +555,7 @@ lemma hasSum_int_completedHurwitzZetaEven (a : ℝ) {s : ℂ} (hs : 1 < re s) : · rw [mul_comm, mul_one_div] rw [show completedHurwitzZetaEven a s = mellin (fun t ↦ ((evenKernel (↑a) t : ℂ) - ↑(if (a : UnitAddCircle) = 0 then 1 else 0 : ℝ)) / 2) (s / 2) by - simp_rw [mellin_div_const, apply_ite ofReal', ofReal_one, ofReal_zero] + simp_rw [mellin_div_const, apply_ite ofReal, ofReal_one, ofReal_zero] refine congr_arg (· / 2) ((hurwitzEvenFEPair a).hasMellin (?_ : 1 / 2 < (s / 2).re)).2.symm rwa [div_ofNat_re, div_lt_div_right two_pos]] refine (hasSum_mellin_pi_mul_sq (zero_lt_one.trans hs) hF ?_).congr_fun fun n ↦ ?_ diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean index cf70f0a830ee7..7d60dc787c117 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean @@ -177,7 +177,7 @@ lemma continuousOn_sinKernel (a : UnitAddCircle) : ContinuousOn (sinKernel a) (I suffices ContinuousOn (fun x ↦ (sinKernel a x : ℂ)) (Ioi 0) from (continuous_re.comp_continuousOn this).congr fun a _ ↦ (ofReal_re _).symm simp_rw [sinKernel_def] - apply (ContinuousAt.continuousOn (fun x hx ↦ ?_)).div_const + apply (continuousOn_of_forall_continuousAt (fun x hx ↦ ?_)).div_const have h := continuousAt_jacobiTheta₂' a (by rwa [I_mul_im, ofReal_re]) fun_prop @@ -302,8 +302,8 @@ section FEPair /-- A `StrongFEPair` structure with `f = oddKernel a` and `g = sinKernel a`. -/ @[simps] def hurwitzOddFEPair (a : UnitAddCircle) : StrongFEPair ℂ where - f := ofReal' ∘ oddKernel a - g := ofReal' ∘ sinKernel a + f := ofReal ∘ oddKernel a + g := ofReal ∘ sinKernel a hf_int := (continuous_ofReal.comp_continuousOn (continuousOn_oddKernel a)).locallyIntegrableOn measurableSet_Ioi hg_int := (continuous_ofReal.comp_continuousOn (continuousOn_sinKernel a)).locallyIntegrableOn diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaValues.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaValues.lean index 7f86bf4003157..a4fa533e22e11 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaValues.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaValues.lean @@ -51,7 +51,7 @@ theorem cosZeta_two_mul_nat (hk : k ≠ 0) (hx : x ∈ Icc 0 1) : ((Polynomial.bernoulli (2 * k)).map (algebraMap ℚ ℂ)).eval (x : ℂ) := by rw [← (hasSum_nat_cosZeta x (?_ : 1 < re (2 * k))).tsum_eq] · refine Eq.trans ?_ <| - (congr_arg ofReal' (hasSum_one_div_nat_pow_mul_cos hk hx).tsum_eq).trans ?_ + (congr_arg ofReal (hasSum_one_div_nat_pow_mul_cos hk hx).tsum_eq).trans ?_ · rw [ofReal_tsum] refine tsum_congr fun n ↦ ?_ rw [mul_comm (1 / _), mul_one_div, ofReal_div, mul_assoc (2 * π), mul_comm x n, ← mul_assoc, @@ -60,8 +60,8 @@ theorem cosZeta_two_mul_nat (hk : k ≠ 0) (hx : x ∈ Icc 0 1) : ofReal_neg, ofReal_one] congr 1 have : (Polynomial.bernoulli (2 * k)).map (algebraMap ℚ ℂ) = _ := - (Polynomial.map_map (algebraMap ℚ ℝ) ofReal _).symm - rw [this, ← ofReal_eq_coe, ← ofReal_eq_coe] + (Polynomial.map_map (algebraMap ℚ ℝ) ofRealHom _).symm + rw [this, ← ofRealHom_eq_coe, ← ofRealHom_eq_coe] apply Polynomial.map_aeval_eq_aeval_map simp only [Algebra.id.map_eq_id, RingHomCompTriple.comp_eq] · rw [← Nat.cast_ofNat, ← Nat.cast_one, ← Nat.cast_mul, natCast_re, Nat.cast_lt] @@ -79,7 +79,7 @@ theorem sinZeta_two_mul_nat_add_one (hk : k ≠ 0) (hx : x ∈ Icc 0 1) : ((Polynomial.bernoulli (2 * k + 1)).map (algebraMap ℚ ℂ)).eval (x : ℂ) := by rw [← (hasSum_nat_sinZeta x (?_ : 1 < re (2 * k + 1))).tsum_eq] · refine Eq.trans ?_ <| - (congr_arg ofReal' (hasSum_one_div_nat_pow_mul_sin hk hx).tsum_eq).trans ?_ + (congr_arg ofReal (hasSum_one_div_nat_pow_mul_sin hk hx).tsum_eq).trans ?_ · rw [ofReal_tsum] refine tsum_congr fun n ↦ ?_ rw [mul_comm (1 / _), mul_one_div, ofReal_div, mul_assoc (2 * π), mul_comm x n, ← mul_assoc] @@ -90,8 +90,8 @@ theorem sinZeta_two_mul_nat_add_one (hk : k ≠ 0) (hx : x ∈ Icc 0 1) : ofReal_neg, ofReal_one] congr 1 have : (Polynomial.bernoulli (2 * k + 1)).map (algebraMap ℚ ℂ) = _ := - (Polynomial.map_map (algebraMap ℚ ℝ) ofReal _).symm - rw [this, ← ofReal_eq_coe, ← ofReal_eq_coe] + (Polynomial.map_map (algebraMap ℚ ℝ) ofRealHom _).symm + rw [this, ← ofRealHom_eq_coe, ← ofRealHom_eq_coe] apply Polynomial.map_aeval_eq_aeval_map simp only [Algebra.id.map_eq_id, RingHomCompTriple.comp_eq] · rw [← Nat.cast_ofNat, ← Nat.cast_one, ← Nat.cast_mul, ← Nat.cast_add_one, natCast_re, diff --git a/Mathlib/NumberTheory/LSeries/MellinEqDirichlet.lean b/Mathlib/NumberTheory/LSeries/MellinEqDirichlet.lean index 7f8d7a14ef207..94e639487495f 100644 --- a/Mathlib/NumberTheory/LSeries/MellinEqDirichlet.lean +++ b/Mathlib/NumberTheory/LSeries/MellinEqDirichlet.lean @@ -23,7 +23,7 @@ lemma hasSum_mellin {a : ι → ℂ} {p : ι → ℝ} {F : ℝ → ℂ} {s : ℂ (hF : ∀ t ∈ Ioi 0, HasSum (fun i ↦ a i * rexp (-p i * t)) (F t)) (h_sum : Summable fun i ↦ ‖a i‖ / (p i) ^ s.re) : HasSum (fun i ↦ Gamma s * a i / p i ^ s) (mellin F s) := by - simp_rw [mellin, smul_eq_mul, ← setIntegral_congr measurableSet_Ioi + simp_rw [mellin, smul_eq_mul, ← setIntegral_congr_fun measurableSet_Ioi (fun t ht ↦ congr_arg _ (hF t ht).tsum_eq), ← tsum_mul_left] convert hasSum_integral_of_summable_integral_norm (F := fun i t ↦ t ^ (s - 1) * (a i * rexp (-p i * t))) (fun i ↦ ?_) ?_ using 2 with i @@ -56,7 +56,7 @@ lemma hasSum_mellin {a : ι → ℂ} {p : ι → ℝ} {F : ℝ → ℂ} {s : ℂ have := Real.integral_rpow_mul_exp_neg_mul_Ioi hs hpi simp_rw [← neg_mul (p i), one_div, inv_rpow hpi.le, ← div_eq_inv_mul] at this rw [norm_of_nonneg (integral_nonneg (fun _ ↦ norm_nonneg _)), ← this] - refine setIntegral_congr measurableSet_Ioi (fun t ht ↦ ?_) + refine setIntegral_congr_fun measurableSet_Ioi (fun t ht ↦ ?_) rw [norm_mul, norm_real, Real.norm_eq_abs, Real.abs_exp, Complex.norm_eq_abs, abs_cpow_eq_rpow_re_of_pos ht, sub_re, one_re] @@ -92,7 +92,7 @@ lemma hasSum_mellin_pi_mul₀ {a : ι → ℂ} {p : ι → ℝ} {F : ℝ → ℂ let a' i := if p i = 0 then 0 else a i have hp' i : a' i = 0 ∨ 0 < p i := by simp only [a'] - split_ifs with h <;> tauto + split_ifs with h <;> try tauto exact Or.inr (lt_of_le_of_ne (hp i) (Ne.symm h)) have (i t) : (if p i = 0 then 0 else a i * rexp (-π * p i * t)) = a' i * rexp (-π * p i * t) := by @@ -142,7 +142,7 @@ lemma hasSum_mellin_pi_mul_sq' {a : ι → ℂ} {r : ι → ℝ} {F : ℝ → · rcases eq_or_ne (r i) 0 with h | h · rw [h, abs_zero, ofReal_zero, zero_cpow hs₁, zero_cpow hs₃, div_zero, div_zero] · rw [cpow_add _ _ (ofReal_ne_zero.mpr <| abs_ne_zero.mpr h), cpow_one] - conv_rhs => enter [1]; rw [← sign_mul_abs (r i), ofReal_mul, ← ofReal_eq_coe, + conv_rhs => enter [1]; rw [← sign_mul_abs (r i), ofReal_mul, ← ofRealHom_eq_coe, SignType.map_cast] field_simp [h] ring_nf diff --git a/Mathlib/NumberTheory/LSeries/Positivity.lean b/Mathlib/NumberTheory/LSeries/Positivity.lean new file mode 100644 index 0000000000000..b21893b9ed342 --- /dev/null +++ b/Mathlib/NumberTheory/LSeries/Positivity.lean @@ -0,0 +1,109 @@ +/- +Copyright (c) 2024 Michael Stoll. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck, David Loeffler, Michael Stoll +-/ +import Mathlib.Analysis.Complex.TaylorSeries +import Mathlib.Analysis.Complex.Positivity +import Mathlib.NumberTheory.ArithmeticFunction +import Mathlib.NumberTheory.LSeries.Deriv + +/-! +# Positivity of values of L-series + +The main results of this file are as follows. + +* If `a : ℕ → ℂ` takes nonnegative real values and `a 1 > 0`, then `L a x > 0` + when `x : ℝ` is in the open half-plane of absolute convergence; see + `LSeries.positive` and `ArithmeticFunction.LSeries_positive`. + +* If in addition the L_series of `a` agrees on some open right half-plane where it + converges with an entire function `f`, then `f` is positive on the real axis; + see `LSeries.positive_of_eq_differentiable` and + `ArithmeticFunction.LSeries_positive_of_eq_differentiable`. +-/ + +open scoped ComplexOrder + +open Complex + +namespace LSeries + +/-- If all values of a `ℂ`-valued arithmetic function are nonnegative reals and `x` is a +real number in the domain of absolute convergence, then the `n`th iterated derivative +of the associated L-series is nonnegative real when `n` is even and nonpositive real +when `n` is odd. -/ +lemma iteratedDeriv_alternating {a : ℕ → ℂ} (hn : 0 ≤ a) {x : ℝ} + (h : LSeries.abscissaOfAbsConv a < x) (n : ℕ) : + 0 ≤ (-1) ^ n * iteratedDeriv n (LSeries a) x := by + rw [LSeries_iteratedDeriv _ h, LSeries, ← mul_assoc, ← pow_add, Even.neg_one_pow ⟨n, rfl⟩, + one_mul] + refine tsum_nonneg fun k ↦ ?_ + rw [LSeries.term_def] + split + · exact le_rfl + · refine mul_nonneg ?_ <| (inv_natCast_cpow_ofReal_pos (by assumption) x).le + induction n with + | zero => simpa only [Function.iterate_zero, id_eq] using hn k + | succ n IH => + rw [Function.iterate_succ_apply'] + refine mul_nonneg ?_ IH + simp only [← natCast_log, zero_le_real, Real.log_natCast_nonneg] + +/-- If all values of `a : ℕ → ℂ` are nonnegative reals and `a 1` is positive, +then `L a x` is positive real for all real `x` larger than `abscissaOfAbsConv a`. -/ +lemma positive {a : ℕ → ℂ} (ha₀ : 0 ≤ a) (ha₁ : 0 < a 1) {x : ℝ} (hx : abscissaOfAbsConv a < x) : + 0 < LSeries a x := by + rw [LSeries] + refine tsum_pos ?_ (fun n ↦ term_nonneg (ha₀ n) x) 1 <| term_pos one_ne_zero ha₁ x + exact LSeriesSummable_of_abscissaOfAbsConv_lt_re <| by simpa only [ofReal_re] using hx + +/-- If all values of `a : ℕ → ℂ` are nonnegative reals and `a 1` +is positive, and the L-series of `a` agrees with an entire function `f` on some open +right half-plane where it converges, then `f` is real and positive on `ℝ`. -/ +lemma positive_of_differentiable_of_eqOn {a : ℕ → ℂ} (ha₀ : 0 ≤ a) (ha₁ : 0 < a 1) {f : ℂ → ℂ} + (hf : Differentiable ℂ f) {x : ℝ} (hx : abscissaOfAbsConv a ≤ x) + (hf' : {s | x < s.re}.EqOn f (LSeries a)) (y : ℝ) : + 0 < f y := by + have hxy : x < max x y + 1 := (le_max_left x y).trans_lt (lt_add_one _) + have hxy' : abscissaOfAbsConv a < max x y + 1 := hx.trans_lt <| mod_cast hxy + have hys : (max x y + 1 : ℂ) ∈ {s | x < s.re} := by + simp only [Set.mem_setOf_eq, add_re, ofReal_re, one_re, hxy] + have hfx : 0 < f (max x y + 1) := by + simpa only [hf' hys, ofReal_add, ofReal_one] using positive ha₀ ha₁ hxy' + refine (hfx.trans_le <| hf.apply_le_of_iteratedDeriv_alternating (fun n _ ↦ ?_) ?_) + · have hs : IsOpen {s : ℂ | x < s.re} := continuous_re.isOpen_preimage _ isOpen_Ioi + simpa only [hf'.iteratedDeriv_of_isOpen hs n hys, ofReal_add, ofReal_one] using + iteratedDeriv_alternating ha₀ hxy' n + · exact_mod_cast (le_max_right x y).trans (lt_add_one _).le + +end LSeries + +namespace ArithmeticFunction + +/-- If all values of a `ℂ`-valued arithmetic function are nonnegative reals and `x` is a +real number in the domain of absolute convergence, then the `n`th iterated derivative +of the associated L-series is nonnegative real when `n` is even and nonpositive real +when `n` is odd. -/ +lemma iteratedDeriv_LSeries_alternating (a : ArithmeticFunction ℂ) (hn : ∀ n, 0 ≤ a n) {x : ℝ} + (h : LSeries.abscissaOfAbsConv a < x) (n : ℕ) : + 0 ≤ (-1) ^ n * iteratedDeriv n (LSeries (a ·)) x := + LSeries.iteratedDeriv_alternating hn h n + +/-- If all values of a `ℂ`-valued arithmetic function `a` are nonnegative reals and `a 1` is +positive, then `L a x` is positive real for all real `x` larger than `abscissaOfAbsConv a`. -/ +lemma LSeries_positive {a : ℕ → ℂ} (ha₀ : 0 ≤ a) (ha₁ : 0 < a 1) {x : ℝ} + (hx : LSeries.abscissaOfAbsConv a < x) : + 0 < LSeries a x := + LSeries.positive ha₀ ha₁ hx + +/-- If all values of a `ℂ`-valued arithmetic function `a` are nonnegative reals and `a 1` +is positive, and the L-series of `a` agrees with an entire function `f` on some open +right half-plane where it converges, then `f` is real and positive on `ℝ`. -/ +lemma LSeries_positive_of_differentiable_of_eqOn {a : ArithmeticFunction ℂ} (ha₀ : 0 ≤ (a ·)) + (ha₁ : 0 < a 1) {f : ℂ → ℂ} (hf : Differentiable ℂ f) {x : ℝ} + (hx : LSeries.abscissaOfAbsConv a ≤ x) (hf' : {s | x < s.re}.EqOn f (LSeries a)) (y : ℝ) : + 0 < f y := + LSeries.positive_of_differentiable_of_eqOn ha₀ ha₁ hf hx hf' y + +end ArithmeticFunction diff --git a/Mathlib/NumberTheory/LSeries/RiemannZeta.lean b/Mathlib/NumberTheory/LSeries/RiemannZeta.lean index bcc35496bf6f6..0b29f4b14b30a 100644 --- a/Mathlib/NumberTheory/LSeries/RiemannZeta.lean +++ b/Mathlib/NumberTheory/LSeries/RiemannZeta.lean @@ -202,6 +202,25 @@ theorem zeta_nat_eq_tsum_of_gt_one {k : ℕ} (hk : 1 < k) : lemma riemannZeta_residue_one : Tendsto (fun s ↦ (s - 1) * riemannZeta s) (𝓝[≠] 1) (𝓝 1) := by exact hurwitzZetaEven_residue_one 0 +/-- The residue of `ζ(s)` at `s = 1` is equal to 1, expressed using `tsum`. -/ +theorem tendsto_sub_mul_tsum_nat_cpow : + Tendsto (fun s : ℂ ↦ (s - 1) * ∑' (n : ℕ), 1 / (n : ℂ) ^ s) (𝓝[{s | 1 < re s}] 1) (𝓝 1) := by + refine (tendsto_nhdsWithin_mono_left ?_ riemannZeta_residue_one).congr' ?_ + · simp only [subset_compl_singleton_iff, mem_setOf_eq, one_re, not_lt, le_refl] + · filter_upwards [eventually_mem_nhdsWithin] with s hs using + congr_arg _ <| zeta_eq_tsum_one_div_nat_cpow hs + +/-- The residue of `ζ(s)` at `s = 1` is equal to 1 expressed using `tsum` and for a +real variable. -/ +theorem tendsto_sub_mul_tsum_nat_rpow : + Tendsto (fun s : ℝ ↦ (s - 1) * ∑' (n : ℕ), 1 / (n : ℝ) ^ s) (𝓝[>] 1) (𝓝 1) := by + rw [← tendsto_ofReal_iff, ofReal_one] + have : Tendsto (fun s : ℝ ↦ (s : ℂ)) (𝓝[>] 1) (𝓝[{s | 1 < re s}] 1) := + continuous_ofReal.continuousWithinAt.tendsto_nhdsWithin (fun _ _ ↦ by aesop) + apply (tendsto_sub_mul_tsum_nat_cpow.comp this).congr fun s ↦ ?_ + simp only [one_div, Function.comp_apply, ofReal_mul, ofReal_sub, ofReal_one, ofReal_tsum, + ofReal_inv, ofReal_cpow (Nat.cast_nonneg _), ofReal_natCast] + /- naming scheme was changed from `riemannCompletedZeta` to `completedRiemannZeta`; add aliases for the old names -/ section aliases diff --git a/Mathlib/NumberTheory/LSeries/ZMod.lean b/Mathlib/NumberTheory/LSeries/ZMod.lean index 2ef6c910b132d..a7b7dd924fbf6 100644 --- a/Mathlib/NumberTheory/LSeries/ZMod.lean +++ b/Mathlib/NumberTheory/LSeries/ZMod.lean @@ -118,7 +118,7 @@ lemma LFunction_eq_LSeries (Φ : ZMod N → ℂ) {s : ℂ} (hs : 1 < re s) : lemma differentiableAt_LFunction (Φ : ZMod N → ℂ) (s : ℂ) (hs : s ≠ 1 ∨ ∑ j, Φ j = 0) : DifferentiableAt ℂ (LFunction Φ) s := by - apply (differentiable_neg.const_cpow (Or.inl <| NeZero.ne _) s).mul + refine .mul (by fun_prop) ?_ rcases ne_or_eq s 1 with hs' | rfl · exact .sum fun j _ ↦ (differentiableAt_hurwitzZeta _ hs').const_mul _ · have := DifferentiableAt.sum (u := univ) fun j _ ↦ @@ -294,6 +294,11 @@ noncomputable def completedLFunction (Φ : ZMod N → ℂ) (s : ℂ) : ℂ := @[simp] lemma completedLFunction_zero (s : ℂ) : completedLFunction (0 : ZMod N → ℂ) s = 0 := by simp only [completedLFunction, Pi.zero_apply, zero_mul, sum_const_zero, mul_zero, zero_add] +lemma completedLFunction_const_mul (a : ℂ) (Φ : ZMod N → ℂ) (s : ℂ) : + completedLFunction (fun j ↦ a * Φ j) s = a * completedLFunction Φ s := by + simp only [completedLFunction, mul_add, mul_sum] + congr with i <;> ring + lemma completedLFunction_def_even (hΦ : Φ.Even) (s : ℂ) : completedLFunction Φ s = N ^ (-s) * ∑ j, Φ j * completedHurwitzZetaEven (toAddCircle j) s := by suffices ∑ j, Φ j * completedHurwitzZetaOdd (toAddCircle j) s = 0 by @@ -330,7 +335,7 @@ noncomputable def completedLFunction₀ (Φ : ZMod N → ℂ) (s : ℂ) : ℂ := lemma differentiable_completedLFunction₀ (Φ : ZMod N → ℂ) : Differentiable ℂ (completedLFunction₀ Φ) := by refine .add ?_ ?_ <;> - refine (differentiable_neg.const_cpow <| .inl <| NeZero.ne _).mul (.sum fun i _ ↦ .const_mul ?_ _) + refine .mul (by fun_prop) (.sum fun i _ ↦ .const_mul ?_ _) exacts [differentiable_completedHurwitzZetaEven₀ _, differentiable_completedHurwitzZetaOdd _] lemma completedLFunction_eq (Φ : ZMod N → ℂ) (s : ℂ) : @@ -352,12 +357,12 @@ lemma differentiableAt_completedLFunction (Φ : ZMod N → ℂ) (s : ℂ) (hs₀ -- correction terms from `completedLFunction_eq` are differentiable at `s`. refine ((differentiable_completedLFunction₀ _ _).sub ?_).sub ?_ · -- term with `1 / s` - refine ((differentiable_neg.const_cpow <| .inl <| NeZero.ne _) s).mul (hs₀.elim ?_ ?_) + refine .mul (by fun_prop) (hs₀.elim ?_ ?_) · exact fun h ↦ (differentiableAt_const _).div differentiableAt_id h · exact fun h ↦ by simp only [h, funext zero_div, differentiableAt_const] · -- term with `1 / (1 - s)` - refine ((differentiable_neg.const_cpow <| .inl <| NeZero.ne _) s).mul (hs₁.elim ?_ ?_) - · exact fun h ↦ (differentiableAt_const _).div (by fun_prop) (by rwa [sub_ne_zero, ne_comm]) + refine .mul (by fun_prop) (hs₁.elim ?_ ?_) + · exact fun h ↦ .div (by fun_prop) (by fun_prop) (by rwa [sub_ne_zero, ne_comm]) · exact fun h ↦ by simp only [h, zero_div, differentiableAt_const] /-- diff --git a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean index 392736e26084d..1faaafe97442e 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean @@ -3,8 +3,9 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.NumberTheory.LegendreSymbol.Basic import Mathlib.Analysis.Normed.Field.Lemmas +import Mathlib.Data.Nat.Prime.Factorial +import Mathlib.NumberTheory.LegendreSymbol.Basic /-! # Lemmas of Gauss and Eisenstein @@ -49,18 +50,17 @@ theorem Ico_map_valMinAbs_natAbs_eq_Ico_map_id (p : ℕ) [hp : Fact p.Prime] (a · apply lt_succ_of_le; apply natAbs_valMinAbs_le · rw [natCast_natAbs_valMinAbs] split_ifs - · erw [mul_div_cancel₀ _ hap, valMinAbs_def_pos, val_cast_of_lt (hep hb), + · rw [mul_div_cancel₀ _ hap, valMinAbs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat] - · erw [mul_neg, mul_div_cancel₀ _ hap, natAbs_valMinAbs_neg, valMinAbs_def_pos, + · rw [mul_neg, mul_div_cancel₀ _ hap, natAbs_valMinAbs_neg, valMinAbs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat] exact Multiset.map_eq_map_of_bij_of_nodup _ _ (Finset.nodup _) (Finset.nodup _) (fun x _ => (a * x : ZMod p).valMinAbs.natAbs) hmem (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj (fun _ _ => rfl) -private theorem gauss_lemma_aux₁ (p : ℕ) [Fact p.Prime] {a : ℤ} - (hap : (a : ZMod p) ≠ 0) : (a ^ (p / 2) * (p / 2)! : ZMod p) = - (-1 : ZMod p) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => - ¬(a * x : ZMod p).val ≤ p / 2).card * (p / 2)! := +private theorem gauss_lemma_aux₁ (p : ℕ) [Fact p.Prime] {a : ℤ} (hap : (a : ZMod p) ≠ 0) : + (a ^ (p / 2) * (p / 2)! : ZMod p) = + (-1 : ZMod p) ^ #{x ∈ Ico 1 (p / 2).succ | ¬ (a * x.cast : ZMod p).val ≤ p / 2} * (p / 2)! := calc (a ^ (p / 2) * (p / 2)! : ZMod p) = ∏ x ∈ Ico 1 (p / 2).succ, a * x := by rw [prod_mul_distrib, ← prod_natCast, prod_Ico_id_eq_factorial, prod_const, card_Ico, @@ -71,26 +71,25 @@ private theorem gauss_lemma_aux₁ (p : ℕ) [Fact p.Prime] {a : ℤ} (prod_congr rfl fun _ _ => by simp only [natCast_natAbs_valMinAbs] split_ifs <;> simp) - _ = (-1 : ZMod p) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => - ¬(a * x : ZMod p).val ≤ p / 2).card * ∏ x ∈ Ico 1 (p / 2).succ, - ↑((a * x : ZMod p).valMinAbs.natAbs) := by + _ = (-1 : ZMod p) ^ #{x ∈ Ico 1 (p / 2).succ | ¬(a * x.cast : ZMod p).val ≤ p / 2} * + ∏ x ∈ Ico 1 (p / 2).succ, ↑((a * x : ZMod p).valMinAbs.natAbs) := by have : (∏ x ∈ Ico 1 (p / 2).succ, if (a * x : ZMod p).val ≤ p / 2 then (1 : ZMod p) else -1) = - ∏ x ∈ (Ico 1 (p / 2).succ).filter fun x : ℕ => ¬(a * x : ZMod p).val ≤ p / 2, -1 := + ∏ x ∈ Ico 1 (p / 2).succ with ¬(a * x.cast : ZMod p).val ≤ p / 2, -1 := prod_bij_ne_one (fun x _ _ => x) (fun x => by split_ifs <;> (dsimp; simp_all)) (fun _ _ _ _ _ _ => id) (fun b h _ => ⟨b, by simp_all [-not_le]⟩) (by intros; split_ifs at * <;> simp_all) rw [prod_mul_distrib, this, prod_const] - _ = (-1 : ZMod p) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => - ¬(a * x : ZMod p).val ≤ p / 2).card * (p / 2)! := by + _ = (-1 : ZMod p) ^ #{x ∈ Ico 1 (p / 2).succ | ¬(a * x.cast : ZMod p).val ≤ p / 2} * + (p / 2)! := by rw [← prod_natCast, Finset.prod_eq_multiset_prod, Ico_map_valMinAbs_natAbs_eq_Ico_map_id p a hap, ← Finset.prod_eq_multiset_prod, prod_Ico_id_eq_factorial] -theorem gauss_lemma_aux (p : ℕ) [hp : Fact p.Prime] {a : ℤ} - (hap : (a : ZMod p) ≠ 0) : (↑a ^ (p / 2) : ZMod p) = - ((-1) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card :) := +theorem gauss_lemma_aux (p : ℕ) [hp : Fact p.Prime] {a : ℤ} (hap : (a : ZMod p) ≠ 0) : + (a ^ (p / 2) : ZMod p) = + ((-1) ^ #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} :) := (mul_left_inj' (show ((p / 2)! : ZMod p) ≠ 0 by rw [Ne, CharP.cast_eq_zero_iff (ZMod p) p, hp.1.dvd_factorial, not_le] exact Nat.div_lt_self hp.1.pos (by decide))).1 <| by @@ -99,21 +98,20 @@ theorem gauss_lemma_aux (p : ℕ) [hp : Fact p.Prime] {a : ℤ} /-- **Gauss' lemma**. The Legendre symbol can be computed by considering the number of naturals less than `p/2` such that `(a * x) % p > p / 2`. -/ theorem gauss_lemma {p : ℕ} [h : Fact p.Prime] {a : ℤ} (hp : p ≠ 2) (ha0 : (a : ZMod p) ≠ 0) : - legendreSym p a = (-1) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => - p / 2 < (a * x : ZMod p).val).card := by + legendreSym p a = (-1) ^ #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} := by replace hp : Odd p := h.out.odd_of_ne_two hp - have : (legendreSym p a : ZMod p) = (((-1) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => - p / 2 < (a * x : ZMod p).val).card : ℤ) : ZMod p) := by + have : (legendreSym p a : ZMod p) = + (((-1) ^ #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} : ℤ) : ZMod p) := by rw [legendreSym.eq_pow, gauss_lemma_aux p ha0] cases legendreSym.eq_one_or_neg_one p ha0 <;> - cases neg_one_pow_eq_or ℤ - ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card <;> + cases neg_one_pow_eq_or ℤ #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} <;> simp_all [ne_neg_self hp one_ne_zero, (ne_neg_self hp one_ne_zero).symm] private theorem eisenstein_lemma_aux₁ (p : ℕ) [Fact p.Prime] [hp2 : Fact (p % 2 = 1)] {a : ℕ} - (hap : (a : ZMod p) ≠ 0) : ((∑ x ∈ Ico 1 (p / 2).succ, a * x : ℕ) : ZMod 2) = - ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card + - ∑ x ∈ Ico 1 (p / 2).succ, x + (∑ x ∈ Ico 1 (p / 2).succ, a * x / p : ℕ) := + (hap : (a : ZMod p) ≠ 0) : + ((∑ x ∈ Ico 1 (p / 2).succ, a * x : ℕ) : ZMod 2) = + #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} + + ∑ x ∈ Ico 1 (p / 2).succ, x + (∑ x ∈ Ico 1 (p / 2).succ, a * x / p : ℕ) := have hp2 : (p : ZMod 2) = (1 : ℕ) := (eq_iff_modEq_nat _).2 hp2.1 calc ((∑ x ∈ Ico 1 (p / 2).succ, a * x : ℕ) : ZMod 2) = @@ -130,8 +128,8 @@ private theorem eisenstein_lemma_aux₁ (p : ℕ) [Fact p.Prime] [hp2 : Fact (p ∑ x ∈ Ico 1 (p / 2).succ, (((a * x : ZMod p).valMinAbs + if (a * x : ZMod p).val ≤ p / 2 then 0 else p : ℤ) : ZMod 2) := by simp only [(val_eq_ite_valMinAbs _).symm]; simp [Nat.cast_sum] - _ = ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card + - (∑ x ∈ Ico 1 (p / 2).succ, (a * x : ZMod p).valMinAbs.natAbs : ℕ) := by + _ = #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} + + (∑ x ∈ Ico 1 (p / 2).succ, (a * x.cast : ZMod p).valMinAbs.natAbs : ℕ) := by simp [add_comm, sum_add_distrib, Finset.sum_ite, hp2, Nat.cast_sum] _ = _ := by rw [Finset.sum_eq_multiset_sum, Ico_map_valMinAbs_natAbs_eq_Ico_map_id p a hap, ← @@ -140,7 +138,7 @@ private theorem eisenstein_lemma_aux₁ (p : ℕ) [Fact p.Prime] [hp2 : Fact (p theorem eisenstein_lemma_aux (p : ℕ) [Fact p.Prime] [Fact (p % 2 = 1)] {a : ℕ} (ha2 : a % 2 = 1) (hap : (a : ZMod p) ≠ 0) : - ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card ≡ + #{x ∈ Ico 1 (p / 2).succ | p / 2 < (a * x.cast : ZMod p).val} ≡ ∑ x ∈ Ico 1 (p / 2).succ, x * a / p [MOD 2] := have ha2 : (a : ZMod 2) = (1 : ℕ) := (eq_iff_modEq_nat _).2 ha2 (eq_iff_modEq_nat 2).1 <| sub_eq_zero.1 <| by @@ -149,10 +147,10 @@ theorem eisenstein_lemma_aux (p : ℕ) [Fact p.Prime] [Fact (p % 2 = 1)] {a : Eq.symm (eisenstein_lemma_aux₁ p hap) theorem div_eq_filter_card {a b c : ℕ} (hb0 : 0 < b) (hc : a / b ≤ c) : - a / b = ((Ico 1 c.succ).filter fun x => x * b ≤ a).card := + a / b = #{x ∈ Ico 1 c.succ | x * b ≤ a} := calc - a / b = (Ico 1 (a / b).succ).card := by simp - _ = ((Ico 1 c.succ).filter fun x => x * b ≤ a).card := + a / b = #(Ico 1 (a / b).succ) := by simp + _ = #{x ∈ Ico 1 c.succ | x * b ≤ a} := congr_arg _ <| Finset.ext fun x => by have : x * b ≤ a → x ≤ c := fun h => le_trans (by rwa [le_div_iff_mul_le hb0]) hc simp [Nat.lt_succ_iff, le_div_iff_mul_le hb0]; tauto @@ -161,13 +159,12 @@ theorem div_eq_filter_card {a b c : ℕ} (hb0 : 0 < b) (hc : a / b ≤ c) : rectangle `(0, p/2) × (0, q/2)`. -/ private theorem sum_Ico_eq_card_lt {p q : ℕ} : ∑ a ∈ Ico 1 (p / 2).succ, a * q / p = - ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => - x.2 * p ≤ x.1 * q).card := + #{x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.2 * p ≤ x.1 * q} := if hp0 : p = 0 then by simp [hp0, Finset.ext_iff] else calc ∑ a ∈ Ico 1 (p / 2).succ, a * q / p = - ∑ a ∈ Ico 1 (p / 2).succ, ((Ico 1 (q / 2).succ).filter fun x => x * p ≤ a * q).card := + ∑ a ∈ Ico 1 (p / 2).succ, #{x ∈ Ico 1 (q / 2).succ | x * p ≤ a * q} := Finset.sum_congr rfl fun x hx => div_eq_filter_card (Nat.pos_of_ne_zero hp0) <| calc x * q / p ≤ p / 2 * q / p := by have := le_of_lt_succ (mem_Ico.mp hx).2; gcongr @@ -187,16 +184,15 @@ theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 ∑ a ∈ Ico 1 (p / 2).succ, a * q / p + ∑ a ∈ Ico 1 (q / 2).succ, a * p / q = p / 2 * (q / 2) := by have hswap : - ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card = - ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => - x.1 * q ≤ x.2 * p).card := + #{x ∈ Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ | x.2 * q ≤ x.1 * p} = + #{x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.1 * q ≤ x.2 * p} := card_equiv (Equiv.prodComm _ _) (fun ⟨_, _⟩ => by simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk, forall_true_iff, mem_product, Equiv.prodComm_apply, and_assoc, and_left_comm]) have hdisj : - Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q) - ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by + Disjoint {x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.2 * p ≤ x.1 * q} + {x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.1 * q ≤ x.2 * p} := by apply disjoint_filter.2 fun x hx hpq hqp => ?_ have hxp : x.1 < p := lt_of_le_of_lt (show x.1 ≤ p / 2 by simp_all only [Nat.lt_succ_iff, mem_Ico, mem_product]) @@ -207,8 +203,8 @@ theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 rw [val_cast_of_lt hxp, val_zero] at this simp only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and, mem_product] at hx have hunion : - (((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q) ∪ - (Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) = + {x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.2 * p ≤ x.1 * q} ∪ + {x ∈ Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ | x.1 * q ≤ x.2 * p} = Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ := Finset.ext fun x => by have := le_total (x.2 * p) (x.1 * q) diff --git a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean index c4b313daf7c59..f408526e3fb67 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean @@ -156,20 +156,14 @@ theorem mul_left (a₁ a₂ : ℤ) (b : ℕ) : J(a₁ * a₂ | b) = J(a₁ | b) (f := fun x ↦ @legendreSym x {out := prime_of_mem_primeFactorsList x.2} a₁) (g := fun x ↦ @legendreSym x {out := prime_of_mem_primeFactorsList x.2} a₂) -#adaptation_note -/-- -After nightly-2024-09-06 we can remove the `_root_` prefixes below. --/ /-- The symbol `J(a | b)` vanishes iff `a` and `b` are not coprime (assuming `b ≠ 0`). -/ theorem eq_zero_iff_not_coprime {a : ℤ} {b : ℕ} [NeZero b] : J(a | b) = 0 ↔ a.gcd b ≠ 1 := List.prod_eq_zero_iff.trans (by rw [List.mem_pmap, Int.gcd_eq_natAbs, Ne, Prime.not_coprime_iff_dvd] - -- Porting note: Initially, `and_assoc'` and `and_comm'` were used on line 164 but they have - -- been deprecated so we replace them with `and_assoc` and `and_comm` simp_rw [legendreSym.eq_zero_iff _ _, intCast_zmod_eq_zero_iff_dvd, mem_primeFactorsList (NeZero.ne b), ← Int.natCast_dvd, Int.natCast_dvd_natCast, exists_prop, - _root_.and_assoc, _root_.and_comm]) + and_assoc, _root_.and_comm]) /-- The symbol `J(a | b)` is nonzero when `a` and `b` are coprime. -/ protected theorem ne_zero {a : ℤ} {b : ℕ} (h : a.gcd b = 1) : J(a | b) ≠ 0 := by @@ -558,7 +552,7 @@ private theorem fastJacobiSymAux.eq_jacobiSym {a b : ℕ} {flip : Bool} {ha0 : a private def fastJacobiSym (a : ℤ) (b : ℕ) : ℤ := if hb0 : b = 0 then 1 - else if hb2 : b % 2 = 0 then + else if _ : b % 2 = 0 then if a % 2 = 0 then 0 else diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean index 9ba104ca9690a..b25bd5ca4f8ea 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean @@ -129,7 +129,6 @@ variable {F} theorem quadraticChar_eq_zero_iff {a : F} : quadraticChar F a = 0 ↔ a = 0 := quadraticCharFun_eq_zero_iff --- @[simp] -- Porting note (#10618): simp can prove this theorem quadraticChar_zero : quadraticChar F 0 = 0 := by simp only [quadraticChar_apply, quadraticCharFun_zero] @@ -223,7 +222,7 @@ theorem quadraticChar_isNontrivial (hF : ringChar F ≠ 2) : (quadraticChar F).I open Finset in /-- The number of solutions to `x^2 = a` is determined by the quadratic character. -/ theorem quadraticChar_card_sqrts (hF : ringChar F ≠ 2) (a : F) : - ↑{x : F | x ^ 2 = a}.toFinset.card = quadraticChar F a + 1 := by + #{x : F | x ^ 2 = a}.toFinset = quadraticChar F a + 1 := by -- we consider the cases `a = 0`, `a` is a nonzero square and `a` is a nonsquare in turn by_cases h₀ : a = 0 · simp only [h₀, sq_eq_zero_iff, Set.setOf_eq_eq_singleton, Set.toFinset_card, diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean index 49a8325713112..093de3c611294 100644 --- a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean +++ b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean @@ -114,7 +114,7 @@ theorem remainder_lt' (n : ℕ) {m : ℝ} (m1 : 1 < m) : -- 3. the first series is summable (remainder_summable m1 n) -- 4. the second series is summable, since its terms grow quickly - (summable_one_div_pow_of_le m1 fun j => le_self_add) + (summable_one_div_pow_of_le m1 fun _ => le_self_add) -- split the sum in the exponent and massage _ = ∑' i : ℕ, (1 / m) ^ i * (1 / m ^ (n + 1)!) := by simp only [pow_add, one_div, mul_inv, inv_pow] diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean index 26c83fc23c3a5..12ed3466ca3dc 100644 --- a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean +++ b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean @@ -64,7 +64,7 @@ theorem liouvilleWith_one (x : ℝ) : LiouvilleWith 1 x := by namespace LiouvilleWith -variable {p q x y : ℝ} {r : ℚ} {m : ℤ} {n : ℕ} +variable {p q x : ℝ} {r : ℚ} {m : ℤ} {n : ℕ} /-- The constant `C` provided by the definition of `LiouvilleWith` can be made positive. We also add `1 ≤ n` to the list of assumptions about the denominator. While it is equivalent to diff --git a/Mathlib/NumberTheory/Liouville/Measure.lean b/Mathlib/NumberTheory/Liouville/Measure.lean index 618b456b25505..55c85ab7d9a3d 100644 --- a/Mathlib/NumberTheory/Liouville/Measure.lean +++ b/Mathlib/NumberTheory/Liouville/Measure.lean @@ -107,7 +107,7 @@ theorem ae_not_liouvilleWith : ∀ᵐ x, ∀ p > (2 : ℝ), ¬LiouvilleWith p x volume_iUnion_setOf_liouvilleWith theorem ae_not_liouville : ∀ᵐ x, ¬Liouville x := - ae_not_liouvilleWith.mono fun x h₁ h₂ => h₁ 3 (by norm_num) (h₂.liouvilleWith 3) + ae_not_liouvilleWith.mono fun _ h₁ h₂ => h₁ 3 (by norm_num) (h₂.liouvilleWith 3) /-- The set of Liouville numbers has Lebesgue measure zero. -/ @[simp] diff --git a/Mathlib/NumberTheory/Liouville/Residual.lean b/Mathlib/NumberTheory/Liouville/Residual.lean index 38feb5335e927..151dd1af3c8f8 100644 --- a/Mathlib/NumberTheory/Liouville/Residual.lean +++ b/Mathlib/NumberTheory/Liouville/Residual.lean @@ -38,7 +38,7 @@ theorem IsGδ.setOf_liouville : IsGδ { x | Liouville x } := by theorem setOf_liouville_eq_irrational_inter_iInter_iUnion : { x | Liouville x } = - { x | Irrational x } ∩ ⋂ n : ℕ, ⋃ (a : ℤ) (b : ℤ) (hb : 1 < b), + { x | Irrational x } ∩ ⋂ n : ℕ, ⋃ (a : ℤ) (b : ℤ) (_ : 1 < b), ball (a / b) (1 / (b : ℝ) ^ n) := by refine Subset.antisymm ?_ ?_ · refine subset_inter (fun x hx => hx.irrational) ?_ diff --git a/Mathlib/NumberTheory/LucasLehmer.lean b/Mathlib/NumberTheory/LucasLehmer.lean index fd4fbbd8441a4..7990d0b3b0785 100644 --- a/Mathlib/NumberTheory/LucasLehmer.lean +++ b/Mathlib/NumberTheory/LucasLehmer.lean @@ -506,21 +506,21 @@ open Qq Lean Elab.Tactic Mathlib.Meta.NormNum /-- Version of `sMod` that is `ℕ`-valued. One should have `q = 2 ^ p - 1`. This can be reduced by the kernel. -/ -def sMod' (q : ℕ) : ℕ → ℕ +def sModNat (q : ℕ) : ℕ → ℕ | 0 => 4 % q - | i + 1 => (sMod' q i ^ 2 + (q - 2)) % q + | i + 1 => (sModNat q i ^ 2 + (q - 2)) % q -theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by +theorem sModNat_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sModNat (2 ^ p - 1) k : ℤ) = sMod p k := by have h1 := calc 4 = 2 ^ 2 := by norm_num _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp have h2 : 1 ≤ 2 ^ p := by omega induction k with | zero => - rw [sMod', sMod, Int.ofNat_emod] + rw [sModNat, sMod, Int.ofNat_emod] simp [h2] | succ k ih => - rw [sMod', sMod, ← ih] + rw [sModNat, sMod, ← ih] have h3 : 2 ≤ 2 ^ p - 1 := by zify [h2] calc @@ -530,17 +530,55 @@ theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = rw [← add_sub_assoc, sub_eq_add_neg, add_assoc, add_comm _ (-2), ← add_assoc, Int.add_emod_self, ← sub_eq_add_neg] -lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sMod' (2 ^ p - 1) (p - 2) = 0) : +/-- Tail-recursive version of `sModNat`. -/ +def sModNatTR (q : ℕ) (k : Nat) : ℕ := + go k (4 % q) +where + /-- Helper function for `sMod''`. -/ + go : ℕ → ℕ → ℕ + | 0, acc => acc + | n + 1, acc => go n ((acc ^ 2 + (q - 2)) % q) + +/-- +Generalization of `sModNat` with arbitrary base case, +useful for proving `sModNatTR` and `sModNat` agree. +-/ +def sModNat_aux (b : ℕ) (q : ℕ) : ℕ → ℕ + | 0 => b + | i + 1 => (sModNat_aux b q i ^ 2 + (q - 2)) % q + +theorem sModNat_aux_eq (q k : ℕ) : sModNat_aux (4 % q) q k = sModNat q k := by + induction k with + | zero => rfl + | succ k ih => rw [sModNat_aux, ih, sModNat, ← ih] + +theorem sModNatTR_eq_sModNat (q : ℕ) (i : ℕ) : sModNatTR q i = sModNat q i := by + rw [sModNatTR, helper, sModNat_aux_eq] +where + helper b q k : sModNatTR.go q k b = sModNat_aux b q k := by + induction k generalizing b with + | zero => rfl + | succ k ih => + rw [sModNatTR.go, ih, sModNat_aux] + clear ih + induction k with + | zero => rfl + | succ k ih => + rw [sModNat_aux, ih, sModNat_aux] + +lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sModNatTR (2 ^ p - 1) (p - 2) = 0) : LucasLehmerTest p := by rw [Nat.blt_eq] at hp - rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp, h] + rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sModNat_eq_sMod p _ hp, + ← sModNatTR_eq_sModNat, h] rfl lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true) - (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by + (h : Nat.ble 1 (sModNatTR (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by rw [Nat.blt_eq] at hp rw [Nat.ble_eq, Nat.succ_le, Nat.pos_iff_ne_zero] at h - rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp] + rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sModNat_eq_sMod p _ hp, + ← sModNatTR_eq_sModNat] simpa using h theorem isNat_lucasLehmerTest : {p np : ℕ} → @@ -554,20 +592,20 @@ theorem isNat_not_lucasLehmerTest : {p np : ℕ} → /-- Calculate `LucasLehmer.LucasLehmerTest p` for `2 ≤ p` by using kernel reduction for the `sMod'` function. -/ @[norm_num LucasLehmer.LucasLehmerTest (_ : ℕ)] -def evalLucasLehmerTest : NormNumExt where eval {u α} e := do +def evalLucasLehmerTest : NormNumExt where eval {_ _} e := do let .app _ (p : Q(ℕ)) ← Meta.whnfR e | failure let ⟨ep, hp⟩ ← deriveNat p _ let np := ep.natLit! unless 1 < np do failure haveI' h1ltp : Nat.blt 1 $ep =Q true := ⟨⟩ - if sMod' (2 ^ np - 1) (np - 2) = 0 then - haveI' hs : sMod' (2 ^ $ep - 1) ($ep - 2) =Q 0 := ⟨⟩ + if sModNatTR (2 ^ np - 1) (np - 2) = 0 then + haveI' hs : sModNatTR (2 ^ $ep - 1) ($ep - 2) =Q 0 := ⟨⟩ have pf : Q(LucasLehmerTest $ep) := q(testTrueHelper $ep $h1ltp $hs) have pf' : Q(LucasLehmerTest $p) := q(isNat_lucasLehmerTest $hp $pf) return .isTrue pf' else - haveI' hs : Nat.ble 1 (sMod' (2 ^ $ep - 1) ($ep - 2)) =Q true := ⟨⟩ + haveI' hs : Nat.ble 1 (sModNatTR (2 ^ $ep - 1) ($ep - 2)) =Q true := ⟨⟩ have pf : Q(¬ LucasLehmerTest $ep) := q(testFalseHelper $ep $h1ltp $hs) have pf' : Q(¬ LucasLehmerTest $p) := q(isNat_not_lucasLehmerTest $hp $pf) return .isFalse pf' diff --git a/Mathlib/NumberTheory/LucasPrimality.lean b/Mathlib/NumberTheory/LucasPrimality.lean index 2f2f71e0b2bae..47887d769b36b 100644 --- a/Mathlib/NumberTheory/LucasPrimality.lean +++ b/Mathlib/NumberTheory/LucasPrimality.lean @@ -3,10 +3,6 @@ Copyright (c) 2020 Bolton Bailey. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bolton Bailey -/ -import Mathlib.Data.Fintype.Basic -import Mathlib.GroupTheory.OrderOfElement -import Mathlib.Tactic.Zify -import Mathlib.Data.Nat.Totient import Mathlib.RingTheory.IntegralDomain /-! diff --git a/Mathlib/NumberTheory/MaricaSchoenheim.lean b/Mathlib/NumberTheory/MaricaSchoenheim.lean index 4ce9d2d8bf921..a88458695d67d 100644 --- a/Mathlib/NumberTheory/MaricaSchoenheim.lean +++ b/Mathlib/NumberTheory/MaricaSchoenheim.lean @@ -40,9 +40,9 @@ lemma grahamConjecture_of_squarefree {n : ℕ} (f : ℕ → ℕ) (hf' : ∀ k < fun i hi j ↦ (hf' _ hi).squarefree_of_dvd <| div_dvd_of_dvd <| gcd_dvd_left _ _ refine lt_irrefl n ?_ calc - n = 𝒜.card := ?_ - _ ≤ (𝒜 \\ 𝒜).card := 𝒜.card_le_card_diffs - _ ≤ (Ioo 0 n).card := card_le_card_of_injOn (fun s ↦ ∏ p ∈ s, p) ?_ ?_ + n = #𝒜 := ?_ + _ ≤ #(𝒜 \\ 𝒜) := 𝒜.card_le_card_diffs + _ ≤ #(Ioo 0 n) := card_le_card_of_injOn (fun s ↦ ∏ p ∈ s, p) ?_ ?_ _ = n - 1 := by rw [card_Ioo, tsub_zero] _ < n := tsub_lt_self hn.bot_lt zero_lt_one · rw [Finset.card_image_of_injOn, card_Iio] diff --git a/Mathlib/NumberTheory/Modular.lean b/Mathlib/NumberTheory/Modular.lean index 7ee6f2f7441bb..2de3f4663396e 100644 --- a/Mathlib/NumberTheory/Modular.lean +++ b/Mathlib/NumberTheory/Modular.lean @@ -8,6 +8,7 @@ import Mathlib.LinearAlgebra.GeneralLinearGroup import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Basic import Mathlib.Topology.Instances.Matrix import Mathlib.Topology.Algebra.Module.FiniteDimension +import Mathlib.Topology.Instances.ZMultiples /-! # The action of the modular group SL(2, ℤ) on the upper half-plane @@ -113,7 +114,7 @@ attribute [local simp] ContinuousLinearMap.coe_smul theorem tendsto_normSq_coprime_pair : Filter.Tendsto (fun p : Fin 2 → ℤ => normSq ((p 0 : ℂ) * z + p 1)) cofinite atTop := by -- using this instance rather than the automatic `Function.module` makes unification issues in - -- `LinearEquiv.closedEmbedding_of_injective` less bad later in the proof. + -- `LinearEquiv.isClosedEmbedding_of_injective` less bad later in the proof. letI : Module ℝ (Fin 2 → ℝ) := NormedSpace.toModule let π₀ : (Fin 2 → ℝ) →ₗ[ℝ] ℝ := LinearMap.proj 0 let π₁ : (Fin 2 → ℝ) →ₗ[ℝ] ℝ := LinearMap.proj 1 @@ -149,7 +150,7 @@ theorem tendsto_normSq_coprime_pair : rw [f_def, RingHom.map_add, RingHom.map_mul, mul_add, mul_left_comm, mul_conj, conj_ofReal, conj_ofReal, ← ofReal_mul, add_im, ofReal_im, zero_add, inv_mul_eq_iff_eq_mul₀ hz] simp only [ofReal_im, ofReal_re, mul_im, zero_add, mul_zero] - have hf' : ClosedEmbedding f := f.closedEmbedding_of_injective hf + have hf' : IsClosedEmbedding f := f.isClosedEmbedding_of_injective hf have h₂ : Tendsto (fun p : Fin 2 → ℤ => ((↑) : ℤ → ℝ) ∘ p) cofinite (cocompact _) := by convert Tendsto.pi_map_coprodᵢ fun _ => Int.tendsto_coe_cofinite · rw [coprodᵢ_cofinite] @@ -207,8 +208,8 @@ theorem tendsto_lcRow0 {cd : Fin 2 → ℤ} (hcd : IsCoprime (cd 0) (cd 1)) : Tendsto.pi_map_coprodᵢ fun _ : Fin 2 => Int.tendsto_coe_cofinite have hf₁ : Tendsto f₁ cofinite (cocompact _) := cocompact_ℝ_to_cofinite_ℤ_matrix.comp Subtype.coe_injective.tendsto_cofinite - have hf₂ : ClosedEmbedding (lcRow0Extend hcd) := - (lcRow0Extend hcd).toContinuousLinearEquiv.toHomeomorph.closedEmbedding + have hf₂ : IsClosedEmbedding (lcRow0Extend hcd) := + (lcRow0Extend hcd).toContinuousLinearEquiv.toHomeomorph.isClosedEmbedding convert hf₂.tendsto_cocompact.comp (hf₁.comp Subtype.coe_injective.tendsto_cofinite) using 1 ext ⟨g, rfl⟩ i j : 3 fin_cases i <;> [fin_cases j; skip] @@ -258,7 +259,7 @@ theorem tendsto_abs_re_smul {p : Fin 2 → ℤ} (hp : IsCoprime (p 0) (p 1)) : let f := Homeomorph.mulRight₀ _ this let ff := Homeomorph.addRight (((p 1 : ℂ) * z - p 0) / (((p 0 : ℂ) ^ 2 + (p 1 : ℂ) ^ 2) * (p 0 * z + p 1))).re - convert (f.trans ff).closedEmbedding.tendsto_cocompact.comp (tendsto_lcRow0 hp) with _ _ g + convert (f.trans ff).isClosedEmbedding.tendsto_cocompact.comp (tendsto_lcRow0 hp) with _ _ g change ((g : SL(2, ℤ)) • z).re = lcRow0 p ↑(↑g : SL(2, ℝ)) / ((p 0 : ℝ) ^ 2 + (p 1 : ℝ) ^ 2) + @@ -351,7 +352,7 @@ theorem g_eq_of_c_eq_one (hc : (↑ₘg) 1 0 = 1) : g = T ^ (↑ₘg) 0 0 * S * /-- If `1 < |z|`, then `|S • z| < 1`. -/ theorem normSq_S_smul_lt_one (h : 1 < normSq z) : normSq ↑(S • z) < 1 := by - simpa [coe_S, num, denom] using (inv_lt_inv z.normSq_pos zero_lt_one).mpr h + simpa [coe_S, num, denom] using (inv_lt_inv₀ z.normSq_pos zero_lt_one).mpr h /-- If `|z| < 1`, then applying `S` strictly decreases `im`. -/ theorem im_lt_im_S_smul (h : normSq z < 1) : z.im < (S • z).im := by diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index 77d18bd72f999..98c3a39f3ae39 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -134,7 +134,7 @@ namespace ModularForm open SlashInvariantForm -variable {F : Type*} {Γ : Subgroup SL(2, ℤ)} {k : ℤ} +variable {Γ : Subgroup SL(2, ℤ)} {k : ℤ} instance add : Add (ModularForm Γ k) := ⟨fun f g => @@ -152,7 +152,7 @@ theorem add_apply (f g : ModularForm Γ k) (z : ℍ) : (f + g) z = f z + g z := instance instZero : Zero (ModularForm Γ k) := ⟨ { toSlashInvariantForm := 0 - holo' := fun _ => mdifferentiableAt_const 𝓘(ℂ, ℂ) 𝓘(ℂ, ℂ) + holo' := fun _ => mdifferentiableAt_const bdd_at_infty' := fun A => by simpa using zero_form_isBoundedAtImInfty } ⟩ @[simp] @@ -245,7 +245,7 @@ theorem mul_coe {k_1 k_2 : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : ModularForm Γ k @[simps! (config := .asFn) toFun toSlashInvariantForm] def const (x : ℂ) : ModularForm Γ 0 where toSlashInvariantForm := .const x - holo' x := mdifferentiableAt_const 𝓘(ℂ, ℂ) 𝓘(ℂ, ℂ) + holo' _ := mdifferentiableAt_const bdd_at_infty' A := by simpa only [SlashInvariantForm.const_toFun, ModularForm.is_invariant_const] using atImInfty.const_boundedAtFilter x @@ -301,7 +301,7 @@ theorem add_apply (f g : CuspForm Γ k) (z : ℍ) : (f + g) z = f z + g z := instance instZero : Zero (CuspForm Γ k) := ⟨ { toSlashInvariantForm := 0 - holo' := fun _ => mdifferentiableAt_const 𝓘(ℂ, ℂ) 𝓘(ℂ, ℂ) + holo' := fun _ => mdifferentiableAt_const zero_at_infty' := by simpa using Filter.zero_zeroAtFilter _ } ⟩ @[simp] @@ -407,20 +407,20 @@ instance (Γ : Subgroup SL(2, ℤ)) : GradedMonoid.GMul (ModularForm Γ) where mul f g := f.mul g instance instGCommRing (Γ : Subgroup SL(2, ℤ)) : DirectSum.GCommRing (ModularForm Γ) where - one_mul a := gradedMonoid_eq_of_cast (zero_add _) (ext fun _ => one_mul _) - mul_one a := gradedMonoid_eq_of_cast (add_zero _) (ext fun _ => mul_one _) - mul_assoc a b c := gradedMonoid_eq_of_cast (add_assoc _ _ _) (ext fun _ => mul_assoc _ _ _) - mul_zero {i j} f := ext fun _ => mul_zero _ - zero_mul {i j} f := ext fun _ => zero_mul _ - mul_add {i j} f g h := ext fun _ => mul_add _ _ _ - add_mul {i j} f g h := ext fun _ => add_mul _ _ _ - mul_comm a b := gradedMonoid_eq_of_cast (add_comm _ _) (ext fun _ => mul_comm _ _) + one_mul _ := gradedMonoid_eq_of_cast (zero_add _) (ext fun _ => one_mul _) + mul_one _ := gradedMonoid_eq_of_cast (add_zero _) (ext fun _ => mul_one _) + mul_assoc _ _ _ := gradedMonoid_eq_of_cast (add_assoc _ _ _) (ext fun _ => mul_assoc _ _ _) + mul_zero {_ _} _ := ext fun _ => mul_zero _ + zero_mul {_ _} _ := ext fun _ => zero_mul _ + mul_add {_ _} _ _ _ := ext fun _ => mul_add _ _ _ + add_mul {_ _} _ _ _ := ext fun _ => add_mul _ _ _ + mul_comm _ _ := gradedMonoid_eq_of_cast (add_comm _ _) (ext fun _ => mul_comm _ _) natCast := Nat.cast natCast_zero := ext fun _ => Nat.cast_zero - natCast_succ n := ext fun _ => Nat.cast_succ _ + natCast_succ _ := ext fun _ => Nat.cast_succ _ intCast := Int.cast - intCast_ofNat n := ext fun _ => AddGroupWithOne.intCast_ofNat _ - intCast_negSucc_ofNat n := ext fun _ => AddGroupWithOne.intCast_negSucc _ + intCast_ofNat _ := ext fun _ => AddGroupWithOne.intCast_ofNat _ + intCast_negSucc_ofNat _ := ext fun _ => AddGroupWithOne.intCast_negSucc _ instance instGAlgebra (Γ : Subgroup SL(2, ℤ)) : DirectSum.GAlgebra ℂ (ModularForm Γ) where toFun := { toFun := const, map_zero' := rfl, map_add' := fun _ _ => rfl } diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean index 2ff96d352b04b..408d7863a320a 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean @@ -78,7 +78,7 @@ lemma r_lower_bound_on_verticalStrip {A B : ℝ} (h : 0 < B) (hz : z ∈ vertica apply min_le_min hz.2 rw [Real.sqrt_le_sqrt_iff (by apply (r1_pos z).le)] simp only [r1_eq, div_pow, one_div] - rw [inv_le_inv (by positivity) (by positivity), add_le_add_iff_right] + rw [inv_le_inv₀ (by positivity) (by positivity), add_le_add_iff_right] apply div_le_div (sq_nonneg _) _ (by positivity) (pow_le_pow_left h.le hz.2 2) simpa only [even_two.pow_abs] using pow_le_pow_left (abs_nonneg _) hz.1 2 @@ -190,7 +190,7 @@ lemma eisensteinSeries_tendstoLocallyUniformlyOn {k : ℤ} {N : ℕ} (hk : 3 ≤ apply TendstoLocallyUniformlyOn.comp (s := ⊤) _ _ _ (PartialHomeomorph.continuousOn_symm _) · simp only [SlashInvariantForm.toFun_eq_coe, Set.top_eq_univ, tendstoLocallyUniformlyOn_univ] apply eisensteinSeries_tendstoLocallyUniformly hk - · simp only [OpenEmbedding.toPartialHomeomorph_target, Set.top_eq_univ, mapsTo_range_iff, + · simp only [IsOpenEmbedding.toPartialHomeomorph_target, Set.top_eq_univ, mapsTo_range_iff, Set.mem_univ, forall_const] end summability diff --git a/Mathlib/NumberTheory/MulChar/Basic.lean b/Mathlib/NumberTheory/MulChar/Basic.lean index e4ed0932f9876..80a2bffa5b849 100644 --- a/Mathlib/NumberTheory/MulChar/Basic.lean +++ b/Mathlib/NumberTheory/MulChar/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Stoll -/ import Mathlib.Algebra.CharP.Basic +import Mathlib.Algebra.CharP.Lemmas import Mathlib.Data.Fintype.Units import Mathlib.GroupTheory.OrderOfElement @@ -311,7 +312,6 @@ theorem inv_apply' {R : Type*} [Field R] (χ : MulChar R R') (a : R) : χ⁻¹ a (inv_apply χ a).trans <| congr_arg _ (Ring.inverse_eq_inv a) /-- The product of a character with its inverse is the trivial character. -/ --- Porting note (#10618): @[simp] can prove this (later) theorem inv_mul (χ : MulChar R R') : χ⁻¹ * χ = 1 := by ext x rw [coeToFun_mul, Pi.mul_apply, inv_apply_eq_inv] @@ -502,7 +502,7 @@ theorem IsQuadratic.pow_char {χ : MulChar R R'} (hχ : χ.IsQuadratic) (p : ℕ rcases hχ x with (hx | hx | hx) <;> rw [hx] · rw [zero_pow (@Fact.out p.Prime).ne_zero] · rw [one_pow] - · exact CharP.neg_one_pow_char R' p + · exact neg_one_pow_char R' p /-- The `n`th power of a quadratic character is the trivial character, when `n` is even. -/ theorem IsQuadratic.pow_even {χ : MulChar R R'} (hχ : χ.IsQuadratic) {n : ℕ} (hn : Even n) : diff --git a/Mathlib/NumberTheory/Multiplicity.lean b/Mathlib/NumberTheory/Multiplicity.lean index 43de4a819a527..15f1ffc7f450f 100644 --- a/Mathlib/NumberTheory/Multiplicity.lean +++ b/Mathlib/NumberTheory/Multiplicity.lean @@ -6,9 +6,11 @@ Authors: Tian Chen, Mantas Bakšys import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Algebra.Ring.Int +import Mathlib.Data.Nat.Choose.Sum +import Mathlib.Data.Nat.Prime.Int import Mathlib.NumberTheory.Padics.PadicVal.Defs -import Mathlib.RingTheory.Ideal.Quotient -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.RingTheory.Ideal.Quotient.Defs +import Mathlib.RingTheory.Ideal.Span /-! # Multiplicity in Number Theory @@ -143,19 +145,19 @@ namespace multiplicity section IntegralDomain -variable [IsDomain R] [@DecidableRel R (· ∣ ·)] +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) : multiplicity p (x ^ n - y ^ n) = multiplicity p (x - y) := by - rw [← geom_sum₂_mul, multiplicity.mul hp, multiplicity_eq_zero.2 (not_dvd_geom_sum₂ hp hxy hx hn), - zero_add] + {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] 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 : multiplicity (↑p) (∑ i ∈ range p, x ^ i * y ^ (p - 1 - i)) = 1 := by +theorem geom_sum₂_eq_one : emultiplicity (↑p) (∑ i ∈ range p, x ^ i * y ^ (p - 1 - i)) = 1 := by rw [← Nat.cast_one] - refine multiplicity.eq_coe_iff.2 ⟨?_, ?_⟩ + refine emultiplicity_eq_coe.2 ⟨?_, ?_⟩ · rw [pow_one] exact dvd_geom_sum₂_self hxy rw [dvd_iff_dvd_of_dvd_sub hxy] at hx @@ -166,11 +168,11 @@ theorem geom_sum₂_eq_one : multiplicity (↑p) (∑ i ∈ range p, x ^ i * y ^ exact mt hp.dvd_of_dvd_pow hx theorem pow_prime_sub_pow_prime : - multiplicity (↑p) (x ^ p - y ^ p) = multiplicity (↑p) (x - y) + 1 := by - rw [← geom_sum₂_mul, multiplicity.mul hp, geom_sum₂_eq_one hp hp1 hxy hx, add_comm] + 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] theorem pow_prime_pow_sub_pow_prime_pow (a : ℕ) : - multiplicity (↑p) (x ^ p ^ a - y ^ p ^ a) = multiplicity (↑p) (x - y) + a := by + 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] @@ -188,15 +190,16 @@ 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 : ℕ) : - multiplicity (↑p) (x ^ n - y ^ n) = multiplicity (↑p) (x - y) + multiplicity p n := by + emultiplicity (↑p) (x ^ n - y ^ n) = emultiplicity (↑p) (x - y) + emultiplicity p n := by cases' n with n - · simp only [multiplicity.zero, add_top, pow_zero, sub_self] - have h : (multiplicity _ _).Dom := finite_nat_iff.mpr ⟨hp.ne_one, n.succ_pos⟩ + · simp only [emultiplicity_zero, add_top, pow_zero, sub_self] + have h : Finite _ _ := Nat.multiplicity_finite_iff.mpr ⟨hp.ne_one, n.succ_pos⟩ simp only [Nat.succ_eq_add_one] at h - rcases eq_coe_iff.mp (PartENat.natCast_get h).symm with ⟨⟨k, hk⟩, hpn⟩ + 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, PartENat.natCast_get] + rw [pow_sub_pow_of_prime hp, 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) @@ -206,27 +209,26 @@ theorem Int.pow_sub_pow {x y : ℤ} (hxy : ↑p ∣ x - y) (hx : ¬↑p ∣ x) ( rwa [pow_succ, mul_assoc] theorem Int.pow_add_pow {x y : ℤ} (hxy : ↑p ∣ x + y) (hx : ¬↑p ∣ x) {n : ℕ} (hn : Odd n) : - multiplicity (↑p) (x ^ n + y ^ n) = multiplicity (↑p) (x + y) + multiplicity p n := by + 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 theorem Nat.pow_sub_pow {x y : ℕ} (hxy : p ∣ x - y) (hx : ¬p ∣ x) (n : ℕ) : - multiplicity p (x ^ n - y ^ n) = multiplicity p (x - y) + multiplicity p n := by + 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_multiplicity] + · iterate 2 rw [← Int.natCast_emultiplicity] rw [Int.ofNat_sub (Nat.pow_le_pow_left hyx 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 - · simp only [Nat.sub_eq_zero_iff_le.mpr hyx, - Nat.sub_eq_zero_iff_le.mpr (Nat.pow_le_pow_left hyx n), multiplicity.zero, - PartENat.top_add] + · 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) : - multiplicity p (x ^ n + y ^ n) = multiplicity p (x + y) + multiplicity p n := by - iterate 2 rw [← Int.natCast_multiplicity] + 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 @@ -256,11 +258,11 @@ theorem Int.sq_mod_four_eq_one_of_odd {x : ℤ} : Odd x → x ^ 2 % 4 = 1 := by decide theorem Int.two_pow_two_pow_add_two_pow_two_pow {x y : ℤ} (hx : ¬2 ∣ x) (hxy : 4 ∣ x - y) (i : ℕ) : - multiplicity 2 (x ^ 2 ^ i + y ^ 2 ^ i) = ↑(1 : ℕ) := by + emultiplicity 2 (x ^ 2 ^ i + y ^ 2 ^ i) = ↑(1 : ℕ) := by have hx_odd : Odd x := by rwa [← Int.not_even_iff_odd, even_iff_two_dvd] have hxy_even : Even (x - y) := even_iff_two_dvd.mpr (dvd_trans (by decide) hxy) have hy_odd : Odd y := by simpa using hx_odd.sub_even hxy_even - refine multiplicity.eq_coe_iff.mpr ⟨?_, ?_⟩ + refine emultiplicity_eq_coe.mpr ⟨?_, ?_⟩ · rw [pow_one, ← even_iff_two_dvd] exact hx_odd.pow.add_odd hy_odd.pow cases' i with i @@ -280,24 +282,25 @@ theorem Int.two_pow_two_pow_add_two_pow_two_pow {x y : ℤ} (hx : ¬2 ∣ x) (hx rw [pow_succ', mul_comm, pow_mul, Int.sq_mod_four_eq_one_of_odd hx.pow] theorem Int.two_pow_two_pow_sub_pow_two_pow {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x - y) (hx : ¬2 ∣ x) : - multiplicity 2 (x ^ 2 ^ n - y ^ 2 ^ n) = multiplicity 2 (x - y) + n := by - simp only [pow_two_pow_sub_pow_two_pow n, multiplicity.mul Int.prime_two, - multiplicity.Finset.prod Int.prime_two, add_comm, Nat.cast_one, Finset.sum_const, + emultiplicity 2 (x ^ 2 ^ n - y ^ 2 ^ n) = emultiplicity 2 (x - y) + n := by + simp only [pow_two_pow_sub_pow_two_pow n, emultiplicity_mul Int.prime_two, + Finset.emultiplicity_prod Int.prime_two, add_comm, Nat.cast_one, Finset.sum_const, Finset.card_range, nsmul_one, Int.two_pow_two_pow_add_two_pow_two_pow hx hxy] theorem Int.two_pow_sub_pow' {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x - y) (hx : ¬2 ∣ x) : - multiplicity 2 (x ^ n - y ^ n) = multiplicity 2 (x - y) + multiplicity (2 : ℤ) n := by + emultiplicity 2 (x ^ n - y ^ n) = emultiplicity 2 (x - y) + emultiplicity (2 : ℤ) n := by have hx_odd : Odd x := by rwa [← Int.not_even_iff_odd, even_iff_two_dvd] have hxy_even : Even (x - y) := even_iff_two_dvd.mpr (dvd_trans (by decide) hxy) have hy_odd : Odd y := by simpa using hx_odd.sub_even hxy_even cases' n with n - · simp only [pow_zero, sub_self, multiplicity.zero, Int.ofNat_zero, add_top] - have h : (multiplicity 2 n.succ).Dom := multiplicity.finite_nat_iff.mpr ⟨by norm_num, n.succ_pos⟩ + · 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⟩ simp only [Nat.succ_eq_add_one] at h - rcases multiplicity.eq_coe_iff.mp (PartENat.natCast_get h).symm with ⟨⟨k, hk⟩, hpn⟩ + 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, - Int.two_pow_two_pow_sub_pow_two_pow _ hxy hx, ← hk, PartENat.natCast_get] + Int.two_pow_two_pow_sub_pow_two_pow _ hxy hx, ← hk] · norm_cast + rw [h.emultiplicity_eq_multiplicity] · exact Int.prime_two · simpa only [even_iff_two_dvd] using hx_odd.pow.sub_odd hy_odd.pow · simpa only [even_iff_two_dvd, ← Int.not_even_iff_odd] using hx_odd.pow @@ -310,8 +313,8 @@ theorem Int.two_pow_sub_pow' {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x - y) (hx : ¬2 /-- **Lifting the exponent lemma** for `p = 2` -/ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) (hn : Even n) : - multiplicity 2 (x ^ n - y ^ n) + 1 = - multiplicity 2 (x + y) + multiplicity 2 (x - y) + multiplicity (2 : ℤ) n := by + emultiplicity 2 (x ^ n - y ^ n) + 1 = + emultiplicity 2 (x + y) + emultiplicity 2 (x - y) + emultiplicity (2 : ℤ) n := by have hy : Odd y := by rw [← even_iff_two_dvd, Int.not_even_iff_odd] at hx replace hxy := (@even_neg _ _ (x - y)).mpr (even_iff_two_dvd.mpr hxy) @@ -325,33 +328,32 @@ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 Int.sq_mod_four_eq_one_of_odd hy] · norm_num · simp only [← Int.not_even_iff_odd, even_iff_two_dvd, hx, not_false_iff] - rw [Int.two_pow_sub_pow' d hxy4 _, sq_sub_sq, ← Int.ofNat_mul_out, multiplicity.mul Int.prime_two, - multiplicity.mul Int.prime_two] - · suffices multiplicity (2 : ℤ) ↑(2 : ℕ) = 1 by rw [this, add_comm (1 : PartENat), ← add_assoc] + rw [Int.two_pow_sub_pow' d hxy4 _, sq_sub_sq, ← Int.ofNat_mul_out, + 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.multiplicity_self _ _] - · apply Prime.not_unit - simp only [← Nat.prime_iff, Nat.prime_two] - · exact two_ne_zero + rw [multiplicity.Finite.emultiplicity_self] + rw [Nat.multiplicity_finite_iff] + decide · rw [← even_iff_two_dvd, Int.not_even_iff_odd] apply Odd.pow simp only [← Int.not_even_iff_odd, even_iff_two_dvd, hx, not_false_iff] theorem Nat.two_pow_sub_pow {x y : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n : ℕ} (hn : Even n) : - multiplicity 2 (x ^ n - y ^ n) + 1 = - multiplicity 2 (x + y) + multiplicity 2 (x - y) + multiplicity 2 n := by + emultiplicity 2 (x ^ n - y ^ n) + 1 = + emultiplicity 2 (x + y) + emultiplicity 2 (x - y) + emultiplicity 2 n := by obtain hyx | hyx := le_total y x - · iterate 3 rw [← multiplicity.Int.natCast_multiplicity] + · iterate 3 rw [← Int.natCast_emultiplicity] simp only [Int.ofNat_sub hyx, Int.ofNat_sub (pow_le_pow_left' hyx _), Int.ofNat_add, Int.natCast_pow] rw [← Int.natCast_dvd_natCast] at hx rw [← Int.natCast_dvd_natCast, Int.ofNat_sub hyx] at hxy convert Int.two_pow_sub_pow hxy hx hn using 2 - rw [← multiplicity.Int.natCast_multiplicity] + rw [← Int.natCast_emultiplicity] rfl · simp only [Nat.sub_eq_zero_iff_le.mpr hyx, - Nat.sub_eq_zero_iff_le.mpr (pow_le_pow_left' hyx n), multiplicity.zero, - PartENat.top_add, PartENat.add_top] + Nat.sub_eq_zero_iff_le.mpr (pow_le_pow_left' hyx n), emultiplicity_zero, + top_add, add_top] namespace padicValNat @@ -361,9 +363,9 @@ theorem pow_two_sub_pow (hyx : y < x) (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n : (hneven : Even n) : padicValNat 2 (x ^ n - y ^ n) + 1 = padicValNat 2 (x + y) + padicValNat 2 (x - y) + padicValNat 2 n := by - simp only [← PartENat.natCast_inj, Nat.cast_add] - iterate 4 rw [padicValNat_def, PartENat.natCast_get] - · convert Nat.two_pow_sub_pow hxy hx hneven using 2 + simp only [← Nat.cast_inj (R := ℕ∞), Nat.cast_add] + iterate 4 rw [padicValNat_eq_emultiplicity] + · exact Nat.two_pow_sub_pow hxy hx hneven · exact hn.bot_lt · exact Nat.sub_pos_of_lt hyx · omega @@ -374,8 +376,8 @@ include hp hp1 theorem pow_sub_pow (hyx : y < x) (hxy : p ∣ x - y) (hx : ¬p ∣ x) {n : ℕ} (hn : n ≠ 0) : padicValNat p (x ^ n - y ^ n) = padicValNat p (x - y) + padicValNat p n := by - rw [← PartENat.natCast_inj, Nat.cast_add] - iterate 3 rw [padicValNat_def, PartENat.natCast_get] + 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 hn.bot_lt · exact Nat.sub_pos_of_lt hyx @@ -385,8 +387,8 @@ theorem pow_add_pow (hxy : p ∣ x + y) (hx : ¬p ∣ x) {n : ℕ} (hn : Odd n) padicValNat p (x ^ n + y ^ n) = padicValNat p (x + y) + padicValNat p n := by cases' y with y · contradiction - rw [← PartENat.natCast_inj, Nat.cast_add] - iterate 3 rw [padicValNat_def, PartENat.natCast_get] + 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 Odd.pos hn · simp only [add_pos_iff, Nat.succ_pos', or_true] diff --git a/Mathlib/NumberTheory/NumberField/Basic.lean b/Mathlib/NumberTheory/NumberField/Basic.lean index cd142c881c370..64c8f95606e20 100644 --- a/Mathlib/NumberTheory/NumberField/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Basic.lean @@ -59,6 +59,23 @@ protected theorem isAlgebraic [NumberField K] : Algebra.IsAlgebraic ℚ K := instance [NumberField K] [NumberField L] [Algebra K L] : FiniteDimensional K L := Module.Finite.of_restrictScalars_finite ℚ K L +/-- A finite extension of a number field is a number field. -/ +theorem of_module_finite [NumberField K] [Algebra K L] [Module.Finite K L] : NumberField L where + to_charZero := charZero_of_injective_algebraMap (algebraMap K L).injective + to_finiteDimensional := + letI := charZero_of_injective_algebraMap (algebraMap K L).injective + Module.Finite.trans K L + +variable {K} {L} in +instance of_intermediateField [NumberField K] [NumberField L] [Algebra K L] + (E : IntermediateField K L) : NumberField E := + of_module_finite K E + +theorem of_tower [NumberField K] [NumberField L] [Algebra K L] (E : Type*) [Field E] + [Algebra K E] [Algebra E L] [IsScalarTower K E L] : NumberField E := + letI := Module.Finite.left K E L + of_module_finite K E + /-- The ring of integers (or number ring) corresponding to a number field is the integral closure of ℤ in the number field. @@ -89,7 +106,7 @@ instance : Nontrivial (𝓞 K) := inferInstanceAs (Nontrivial (integralClosure _ _)) instance {L : Type*} [Ring L] [Algebra K L] : Algebra (𝓞 K) L := inferInstanceAs (Algebra (integralClosure _ _) L) -instance {L : Type*} [Ring L] [Algebra K L] : IsScalarTower (𝓞 K) K L := +instance {L : Type*} [Ring L] [Algebra K L] : IsScalarTower (𝓞 K) K L := inferInstanceAs (IsScalarTower (integralClosure _ _) K L) variable {K} @@ -222,6 +239,9 @@ instance [NumberField K] : IsFractionRing (𝓞 K) K := instance : IsIntegralClosure (𝓞 K) ℤ K := integralClosure.isIntegralClosure _ _ +instance : Algebra.IsIntegral ℤ (𝓞 K) := + IsIntegralClosure.isIntegral_algebra ℤ K + instance [NumberField K] : IsIntegrallyClosed (𝓞 K) := integralClosure.isIntegrallyClosedOfFiniteExtension ℚ @@ -283,6 +303,48 @@ def restrict_monoidHom [MulOneClass M] (f : M →* K) (h : ∀ x, IsIntegral ℤ map_one' := by simp only [restrict, map_one, mk_one] map_mul' x y := by simp only [restrict, map_mul, mk_mul_mk _] +section extension + +variable (K L : Type*) [Field K] [Field L] [Algebra K L] + +instance : IsScalarTower (𝓞 K) (𝓞 L) L := + IsScalarTower.of_algebraMap_eq' rfl + +instance : IsIntegralClosure (𝓞 L) (𝓞 K) L := + IsIntegralClosure.tower_top (R := ℤ) + +/-- The ring of integers of `L` is isomorphic to any integral closure of `𝓞 K` in `L` -/ +protected noncomputable def algEquiv (R : Type*) [CommRing R] [Algebra (𝓞 K) R] [Algebra R L] + [IsScalarTower (𝓞 K) R L] [IsIntegralClosure R (𝓞 K) L] : 𝓞 L ≃ₐ[𝓞 K] R := + (IsIntegralClosure.equiv (𝓞 K) R L _).symm + +/-- Any extension between ring of integers is integral. -/ +instance extension_algebra_isIntegral : Algebra.IsIntegral (𝓞 K) (𝓞 L) := + IsIntegralClosure.isIntegral_algebra (𝓞 K) L + +/-- Any extension between ring of integers of number fields is noetherian. -/ +instance extension_isNoetherian [NumberField K] [NumberField L] : IsNoetherian (𝓞 K) (𝓞 L) := + IsIntegralClosure.isNoetherian (𝓞 K) K L (𝓞 L) + +/-- The kernel of the algebraMap between ring of integers is `⊥`. -/ +theorem ker_algebraMap_eq_bot : RingHom.ker (algebraMap (𝓞 K) (𝓞 L)) = ⊥ := + (RingHom.ker_eq_bot_iff_eq_zero (algebraMap (𝓞 K) (𝓞 L))).mpr <| fun x hx => by + have h : (algebraMap K L) x = (algebraMap (𝓞 K) (𝓞 L)) x := rfl + simp only [hx, map_zero, map_eq_zero, RingOfIntegers.coe_eq_zero_iff] at h + exact h + +/-- The algebraMap between ring of integers is injective. -/ +theorem algebraMap.injective : Function.Injective (algebraMap (𝓞 K) (𝓞 L)) := + (RingHom.injective_iff_ker_eq_bot (algebraMap (𝓞 K) (𝓞 L))).mpr (ker_algebraMap_eq_bot K L) + +instance : NoZeroSMulDivisors (𝓞 K) (𝓞 L) := + NoZeroSMulDivisors.of_algebraMap_injective (algebraMap.injective K L) + +instance : NoZeroSMulDivisors (𝓞 K) L := + NoZeroSMulDivisors.trans (𝓞 K) (𝓞 L) L + +end extension + end RingOfIntegers variable [NumberField K] diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean index c62e465bc30d5..2254a38cd75ae 100644 --- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ import Mathlib.Algebra.Module.ZLattice.Basic +import Mathlib.MeasureTheory.Measure.Haar.Unique import Mathlib.NumberTheory.NumberField.FractionalIdeal import Mathlib.NumberTheory.NumberField.Units.Basic @@ -57,7 +58,7 @@ that `conj x_φ = x_(conj φ)` for all `∀ φ : K →+* ℂ`. -/ theorem conj_apply {x : ((K →+* ℂ) → ℂ)} (φ : K →+* ℂ) (hx : x ∈ Submodule.span ℝ (Set.range (canonicalEmbedding K))) : conj (x φ) = x (ComplexEmbedding.conjugate φ) := by - refine Submodule.span_induction hx ?_ ?_ (fun _ _ hx hy => ?_) (fun a _ hx => ?_) + refine Submodule.span_induction ?_ ?_ (fun _ _ _ _ hx hy => ?_) (fun a _ _ hx => ?_) hx · rintro _ ⟨x, rfl⟩ rw [apply_at, apply_at, ComplexEmbedding.conjugate_coe_eq] · rw [Pi.zero_apply, Pi.zero_apply, map_zero] @@ -137,7 +138,7 @@ theorem latticeBasis_apply [NumberField K] (i : Free.ChooseBasisIndex ℤ (𝓞 simp only [latticeBasis, integralBasis_apply, coe_basisOfLinearIndependentOfCardEqFinrank, Function.comp_apply, Equiv.apply_symm_apply] -theorem mem_span_latticeBasis [NumberField K] (x : (K →+* ℂ) → ℂ) : +theorem mem_span_latticeBasis [NumberField K] {x : (K →+* ℂ) → ℂ} : x ∈ Submodule.span ℤ (Set.range (latticeBasis K)) ↔ x ∈ ((canonicalEmbedding K).comp (algebraMap (𝓞 K) K)).range := by rw [show Set.range (latticeBasis K) = @@ -208,7 +209,7 @@ instance [NumberField K] : Nontrivial (mixedSpace K) := by protected theorem finrank [NumberField K] : finrank ℝ (mixedSpace K) = finrank ℚ K := by classical rw [finrank_prod, finrank_pi, finrank_pi_fintype, Complex.finrank_real_complex, sum_const, - card_univ, ← NrRealPlaces, ← NrComplexPlaces, ← card_real_embeddings, Algebra.id.smul_eq_mul, + card_univ, ← nrRealPlaces, ← nrComplexPlaces, ← card_real_embeddings, Algebra.id.smul_eq_mul, mul_comm, ← card_complex_embeddings, ← NumberField.Embeddings.card K ℂ, Fintype.card_subtype_compl, Nat.add_sub_of_le (Fintype.card_subtype_le _)] @@ -216,6 +217,39 @@ theorem _root_.NumberField.mixedEmbedding_injective [NumberField K] : Function.Injective (NumberField.mixedEmbedding K) := by exact RingHom.injective _ +section Measure + +open MeasureTheory.Measure MeasureTheory + +variable [NumberField K] + +open Classical in +instance : IsAddHaarMeasure (volume : Measure (mixedSpace K)) := + prod.instIsAddHaarMeasure volume volume + +open Classical in +instance : NoAtoms (volume : Measure (mixedSpace K)) := by + obtain ⟨w⟩ := (inferInstance : Nonempty (InfinitePlace K)) + by_cases hw : IsReal w + · have : NoAtoms (volume : Measure ({w : InfinitePlace K // IsReal w} → ℝ)) := pi_noAtoms ⟨w, hw⟩ + exact prod.instNoAtoms_fst + · have : NoAtoms (volume : Measure ({w : InfinitePlace K // IsComplex w} → ℂ)) := + pi_noAtoms ⟨w, not_isReal_iff_isComplex.mp hw⟩ + exact prod.instNoAtoms_snd + +variable {K} in +open Classical in +/-- The set of points in the mixedSpace that are equal to `0` at a fixed (real) place has +volume zero. -/ +theorem volume_eq_zero (w : {w // IsReal w}) : + volume ({x : mixedSpace K | x.1 w = 0}) = 0 := by + let A : AffineSubspace ℝ (mixedSpace K) := + Submodule.toAffineSubspace (Submodule.mk ⟨⟨{x | x.1 w = 0}, by aesop⟩, rfl⟩ (by aesop)) + convert Measure.addHaar_affineSubspace volume A fun h ↦ ?_ + simpa [A] using (h ▸ Set.mem_univ _ : 1 ∈ A) + +end Measure + section commMap /-- The linear map that makes `canonicalEmbedding` and `mixedEmbedding` commute, see @@ -517,7 +551,7 @@ def matrixToStdBasis : Matrix (index K) (index K) ℂ := (blockDiagonal (fun _ => (2 : ℂ)⁻¹ • !![1, 1; - I, I])) theorem det_matrixToStdBasis : - (matrixToStdBasis K).det = (2⁻¹ * I) ^ NrComplexPlaces K := + (matrixToStdBasis K).det = (2⁻¹ * I) ^ nrComplexPlaces K := calc _ = ∏ _k : { w : InfinitePlace K // IsComplex w }, det ((2 : ℂ)⁻¹ • !![1, 1; -I, I]) := by rw [matrixToStdBasis, det_fromBlocks_zero₂₁, det_diagonal, prod_const_one, one_mul, @@ -590,8 +624,8 @@ def latticeBasis : -- and it's a basis since it has the right cardinality refine basisOfLinearIndependentOfCardEqFinrank this ?_ rw [← finrank_eq_card_chooseBasisIndex, RingOfIntegers.rank, finrank_prod, finrank_pi, - finrank_pi_fintype, Complex.finrank_real_complex, sum_const, card_univ, ← NrRealPlaces, - ← NrComplexPlaces, ← card_real_embeddings, Algebra.id.smul_eq_mul, mul_comm, + finrank_pi_fintype, Complex.finrank_real_complex, sum_const, card_univ, ← nrRealPlaces, + ← nrComplexPlaces, ← card_real_embeddings, Algebra.id.smul_eq_mul, mul_comm, ← card_complex_embeddings, ← NumberField.Embeddings.card K ℂ, Fintype.card_subtype_compl, Nat.add_sub_of_le (Fintype.card_subtype_le _)] @@ -601,9 +635,9 @@ theorem latticeBasis_apply (i : ChooseBasisIndex ℤ (𝓞 K)) : simp only [latticeBasis, coe_basisOfLinearIndependentOfCardEqFinrank, Function.comp_apply, canonicalEmbedding.latticeBasis_apply, integralBasis_apply, commMap_canonical_eq_mixed] -theorem mem_span_latticeBasis (x : (mixedSpace K)) : +theorem mem_span_latticeBasis {x : (mixedSpace K)} : x ∈ Submodule.span ℤ (Set.range (latticeBasis K)) ↔ - x ∈ ((mixedEmbedding K).comp (algebraMap (𝓞 K) K)).range := by + x ∈ mixedEmbedding.integerLattice K := by rw [show Set.range (latticeBasis K) = (mixedEmbedding K).toIntAlgHom.toLinearMap '' (Set.range (integralBasis K)) by rw [← Set.range_comp]; exact congrArg Set.range (funext (fun i => latticeBasis_apply K i))] @@ -614,7 +648,7 @@ theorem mem_span_latticeBasis (x : (mixedSpace K)) : theorem span_latticeBasis : Submodule.span ℤ (Set.range (latticeBasis K)) = mixedEmbedding.integerLattice K := - Submodule.ext_iff.mpr (mem_span_latticeBasis K) + Submodule.ext_iff.mpr fun _ ↦ mem_span_latticeBasis K instance : DiscreteTopology (mixedEmbedding.integerLattice K) := by classical @@ -626,6 +660,13 @@ instance : IsZLattice ℝ (mixedEmbedding.integerLattice K) := by simp_rw [← span_latticeBasis] exact ZSpan.isZLattice (latticeBasis K) +open Classical in +theorem fundamentalDomain_integerLattice : + MeasureTheory.IsAddFundamentalDomain (mixedEmbedding.integerLattice K) + (ZSpan.fundamentalDomain (latticeBasis K)) := by + rw [← span_latticeBasis] + exact ZSpan.isAddFundamentalDomain (latticeBasis K) _ + theorem mem_rat_span_latticeBasis (x : K) : mixedEmbedding K x ∈ Submodule.span ℚ (Set.range (latticeBasis K)) := by rw [← Basis.sum_repr (integralBasis K) x, map_sum] @@ -652,6 +693,14 @@ theorem latticeBasis_repr_apply (x : K) (i : ChooseBasisIndex ℤ (𝓞 K)) : variable (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) +/-- The image of the fractional ideal `I` in the mixed space. -/ +abbrev idealLattice : Submodule ℤ (mixedSpace K) := LinearMap.range <| + (mixedEmbedding K).toIntAlgHom.toLinearMap ∘ₗ ((I : Submodule (𝓞 K) K).subtype.restrictScalars ℤ) + +theorem mem_idealLattice {x : mixedSpace K} : + x ∈ idealLattice K I ↔ ∃ y, y ∈ (I : Set K) ∧ mixedEmbedding K y = x := by + simp [idealLattice] + /-- The generalized index of the lattice generated by `I` in the lattice generated by `𝓞 K` is equal to the norm of the ideal `I`. The result is stated in terms of base change determinant and is the translation of `NumberField.det_basisOfFractionalIdeal_eq_absNorm` in @@ -694,7 +743,7 @@ theorem fractionalIdealLatticeBasis_apply (i : ChooseBasisIndex ℤ I) : simp only [fractionalIdealLatticeBasis, Basis.coe_reindex, Basis.coe_mk, Function.comp_apply, Equiv.apply_symm_apply] -theorem mem_span_fractionalIdealLatticeBasis (x : (mixedSpace K)) : +theorem mem_span_fractionalIdealLatticeBasis {x : (mixedSpace K)} : x ∈ Submodule.span ℤ (Set.range (fractionalIdealLatticeBasis K I)) ↔ x ∈ mixedEmbedding K '' I := by rw [show Set.range (fractionalIdealLatticeBasis K I) = @@ -706,6 +755,239 @@ theorem mem_span_fractionalIdealLatticeBasis (x : (mixedSpace K)) : ext; erw [mem_span_basisOfFractionalIdeal]] rfl +theorem span_idealLatticeBasis : + (Submodule.span ℤ (Set.range (fractionalIdealLatticeBasis K I))) = + (mixedEmbedding.idealLattice K I) := by + ext x + simp [mem_span_fractionalIdealLatticeBasis] + +instance : DiscreteTopology (mixedEmbedding.idealLattice K I) := by + classical + rw [← span_idealLatticeBasis] + infer_instance + +open Classical in +instance : IsZLattice ℝ (mixedEmbedding.idealLattice K I) := by + simp_rw [← span_idealLatticeBasis] + exact ZSpan.isZLattice (fractionalIdealLatticeBasis K I) + +open Classical in +theorem fundamentalDomain_idealLattice : + MeasureTheory.IsAddFundamentalDomain (mixedEmbedding.idealLattice K I) + (ZSpan.fundamentalDomain (fractionalIdealLatticeBasis K I)) := by + rw [← span_idealLatticeBasis] + exact ZSpan.isAddFundamentalDomain (fractionalIdealLatticeBasis K I) _ + end integerLattice +noncomputable section plusPart + +open ContinuousLinearEquiv + +variable {K} (s : Set {w : InfinitePlace K // IsReal w}) + +open Classical in +/-- Let `s` be a set of real places, define the continuous linear equiv of the mixed space that +swaps sign at places in `s` and leaves the rest unchanged. -/ +def negAt : + (mixedSpace K) ≃L[ℝ] (mixedSpace K) := + (piCongrRight fun w ↦ if w ∈ s then neg ℝ else ContinuousLinearEquiv.refl ℝ ℝ).prod + (ContinuousLinearEquiv.refl ℝ _) + +variable {s} + +@[simp] +theorem negAt_apply_of_isReal_and_mem (x : mixedSpace K) {w : {w // IsReal w}} (hw : w ∈ s) : + (negAt s x).1 w = - x.1 w := by + simp_rw [negAt, ContinuousLinearEquiv.prod_apply, piCongrRight_apply, if_pos hw, + ContinuousLinearEquiv.neg_apply] + +@[simp] +theorem negAt_apply_of_isReal_and_not_mem (x : mixedSpace K) {w : {w // IsReal w}} (hw : w ∉ s) : + (negAt s x).1 w = x.1 w := by + simp_rw [negAt, ContinuousLinearEquiv.prod_apply, piCongrRight_apply, if_neg hw, + ContinuousLinearEquiv.refl_apply] + +@[simp] +theorem negAt_apply_of_isComplex (x : mixedSpace K) (w : {w // IsComplex w}) : + (negAt s x).2 w = x.2 w := rfl + +@[simp] +theorem negAt_apply_snd (x : mixedSpace K) : + (negAt s x).2 = x.2 := rfl + +@[simp] +theorem negAt_apply_abs_of_isReal (x : mixedSpace K) (w : {w // IsReal w}) : + |(negAt s x).1 w| = |x.1 w| := by + by_cases hw : w ∈ s <;> simp [hw] + +open MeasureTheory Classical in +/-- `negAt` preserves the volume . -/ +theorem volume_preserving_negAt [NumberField K] : + MeasurePreserving (negAt s) := by + refine MeasurePreserving.prod (volume_preserving_pi fun w ↦ ?_) (MeasurePreserving.id _) + by_cases hw : w ∈ s + · simp_rw [if_pos hw] + exact Measure.measurePreserving_neg _ + · simp_rw [if_neg hw] + exact MeasurePreserving.id _ + +variable (s) in +/-- `negAt` preserves `normAtPlace`. -/ +@[simp] +theorem normAtPlace_negAt (x : mixedSpace K) (w : InfinitePlace K) : + normAtPlace w (negAt s x) = normAtPlace w x := by + obtain hw | hw := isReal_or_isComplex w + · simp_rw [normAtPlace_apply_isReal hw, Real.norm_eq_abs, negAt_apply_abs_of_isReal] + · simp_rw [normAtPlace_apply_isComplex hw, negAt_apply_of_isComplex] + +/-- `negAt` preserves the `norm`. -/ +@[simp] +theorem norm_negAt [NumberField K] (x : mixedSpace K) : + mixedEmbedding.norm (negAt s x) = mixedEmbedding.norm x := + norm_eq_of_normAtPlace_eq (fun w ↦ normAtPlace_negAt _ _ w) + +/-- `negAt` is its own inverse. -/ +@[simp] +theorem negAt_symm : + (negAt s).symm = negAt s := by + ext x w + · by_cases hw : w ∈ s + · simp_rw [negAt_apply_of_isReal_and_mem _ hw, negAt, prod_symm, + ContinuousLinearEquiv.prod_apply, piCongrRight_symm_apply, if_pos hw, symm_neg, neg_apply] + · simp_rw [negAt_apply_of_isReal_and_not_mem _ hw, negAt, prod_symm, + ContinuousLinearEquiv.prod_apply, piCongrRight_symm_apply, if_neg hw, refl_symm, refl_apply] + · rfl + +/-- For `x : mixedSpace K`, the set `signSet x` is the set of real places `w` s.t. `x w ≤ 0`. -/ +def signSet (x : mixedSpace K) : Set {w : InfinitePlace K // IsReal w} := {w | x.1 w ≤ 0} + +@[simp] +theorem negAt_signSet_apply_of_isReal (x : mixedSpace K) (w : {w // IsReal w}) : + (negAt (signSet x) x).1 w = |x.1 w| := by + by_cases hw : x.1 w ≤ 0 + · rw [negAt_apply_of_isReal_and_mem _ hw, abs_of_nonpos hw] + · rw [negAt_apply_of_isReal_and_not_mem _ hw, abs_of_pos (lt_of_not_ge hw)] + +@[simp] +theorem negAt_signSet_apply_of_isComplex (x : mixedSpace K) (w : {w // IsComplex w}) : + (negAt (signSet x) x).2 w = x.2 w := rfl + +variable (A : Set (mixedSpace K)) {x : mixedSpace K} + +variable (s) in + /-- `negAt s A` is also equal to the preimage of `A` by `negAt s`. This fact is used to simplify + some proofs. -/ + theorem negAt_preimage : + negAt s ⁻¹' A = negAt s '' A := by + rw [ContinuousLinearEquiv.image_eq_preimage, negAt_symm] + +/-- The `plusPart` of a subset `A` of the `mixedSpace` is the set of points in `A` that are +positive at all real places. -/ +abbrev plusPart : Set (mixedSpace K) := A ∩ {x | ∀ w, 0 < x.1 w} + +theorem neg_of_mem_negA_plusPart (hx : x ∈ negAt s '' (plusPart A)) {w : {w // IsReal w}} + (hw : w ∈ s) : x.1 w < 0 := by + obtain ⟨y, hy, rfl⟩ := hx + rw [negAt_apply_of_isReal_and_mem _ hw, neg_lt_zero] + exact hy.2 w + + theorem pos_of_not_mem_negAt_plusPart (hx : x ∈ negAt s '' (plusPart A)) {w : {w // IsReal w}} + (hw : w ∉ s) : 0 < x.1 w := by + obtain ⟨y, hy, rfl⟩ := hx + rw [negAt_apply_of_isReal_and_not_mem _ hw] + exact hy.2 w + + /-- The images of `plusPart` by `negAt` are pairwise disjoint. -/ + theorem disjoint_negAt_plusPart : Pairwise (Disjoint on (fun s ↦ negAt s '' (plusPart A))) := by + intro s t hst + refine Set.disjoint_left.mpr fun _ hx hx' ↦ ?_ + obtain ⟨w, hw | hw⟩ : ∃ w, (w ∈ s ∧ w ∉ t) ∨ (w ∈ t ∧ w ∉ s) := by + exact Set.symmDiff_nonempty.mpr hst + · exact lt_irrefl _ <| + (neg_of_mem_negA_plusPart A hx hw.1).trans (pos_of_not_mem_negAt_plusPart A hx' hw.2) + · exact lt_irrefl _ <| + (neg_of_mem_negA_plusPart A hx' hw.1).trans (pos_of_not_mem_negAt_plusPart A hx hw.2) + +-- We will assume from now that `A` is symmetric at real places +variable (hA : ∀ x, x ∈ A ↔ (fun w ↦ |x.1 w|, x.2) ∈ A) + +include hA in +theorem mem_negAt_plusPart_of_mem (hx₁ : x ∈ A) (hx₂ : ∀ w, x.1 w ≠ 0) : + x ∈ negAt s '' (plusPart A) ↔ (∀ w, w ∈ s → x.1 w < 0) ∧ (∀ w, w ∉ s → x.1 w > 0) := by + refine ⟨fun hx ↦ ⟨fun _ hw ↦ neg_of_mem_negA_plusPart A hx hw, + fun _ hw ↦ pos_of_not_mem_negAt_plusPart A hx hw⟩, + fun ⟨h₁, h₂⟩ ↦ ⟨(fun w ↦ |x.1 w|, x.2), ⟨(hA x).mp hx₁, fun w ↦ abs_pos.mpr (hx₂ w)⟩, ?_⟩⟩ + ext w + · by_cases hw : w ∈ s + · simp only [negAt_apply_of_isReal_and_mem _ hw, abs_of_neg (h₁ w hw), neg_neg] + · simp only [negAt_apply_of_isReal_and_not_mem _ hw, abs_of_pos (h₂ w hw)] + · rfl + +include hA in +/-- Assume that `A` is symmetric at real places then, the union of the images of `plusPart` +by `negAt` and of the set of elements of `A` that are zero at at least one real place +is equal to `A`. -/ +theorem iUnion_negAt_plusPart_union : + (⋃ s, negAt s '' (plusPart A)) ∪ (A ∩ (⋃ w, {x | x.1 w = 0})) = A := by + ext x + rw [Set.mem_union, Set.mem_inter_iff, Set.mem_iUnion, Set.mem_iUnion] + refine ⟨?_, fun h ↦ ?_⟩ + · rintro (⟨s, ⟨x, ⟨hx, _⟩, rfl⟩⟩ | h) + · simp_rw (config := {singlePass := true}) [hA, negAt_apply_abs_of_isReal, negAt_apply_snd] + rwa [← hA] + · exact h.left + · obtain hx | hx := exists_or_forall_not (fun w ↦ x.1 w = 0) + · exact Or.inr ⟨h, hx⟩ + · refine Or.inl ⟨signSet x, + (mem_negAt_plusPart_of_mem A hA h hx).mpr ⟨fun w hw ↦ ?_, fun w hw ↦ ?_⟩⟩ + · exact lt_of_le_of_ne hw (hx w) + · exact lt_of_le_of_ne (lt_of_not_ge hw).le (Ne.symm (hx w)) + +open MeasureTheory + +variable [NumberField K] + +include hA in +open Classical in +theorem iUnion_negAt_plusPart_ae : + ⋃ s, negAt s '' (plusPart A) =ᵐ[volume] A := by + nth_rewrite 2 [← iUnion_negAt_plusPart_union A hA] + refine (MeasureTheory.union_ae_eq_left_of_ae_eq_empty (ae_eq_empty.mpr ?_)).symm + exact measure_mono_null Set.inter_subset_right + (measure_iUnion_null_iff.mpr fun _ ↦ volume_eq_zero _) + +variable {A} in +theorem measurableSet_plusPart (hm : MeasurableSet A) : + MeasurableSet (plusPart A) := by + convert_to MeasurableSet (A ∩ (⋂ w, {x | 0 < x.1 w})) + · ext; simp + · refine hm.inter (MeasurableSet.iInter fun _ ↦ ?_) + exact measurableSet_lt measurable_const ((measurable_pi_apply _).comp' measurable_fst) + +variable (s) in +theorem measurableSet_negAt_plusPart (hm : MeasurableSet A) : + MeasurableSet (negAt s '' (plusPart A)) := + negAt_preimage s _ ▸ (measurableSet_plusPart hm).preimage (negAt s).continuous.measurable + +open Classical in +/-- The image of the `plusPart` of `A` by `negAt` have all the same volume as `plusPart A`. -/ +theorem volume_negAt_plusPart (hm : MeasurableSet A) : + volume (negAt s '' (plusPart A)) = volume (plusPart A) := by + rw [← negAt_symm, ContinuousLinearEquiv.image_symm_eq_preimage, + volume_preserving_negAt.measure_preimage (measurableSet_plusPart hm).nullMeasurableSet] + +include hA in +open Classical in +/-- If a subset `A` of the `mixedSpace` is symmetric at real places, then its volume is +`2^ nrRealPlaces K` times the volume of its `plusPart`. -/ +theorem volume_eq_two_pow_mul_volume_plusPart (hm : MeasurableSet A) : + volume A = 2 ^ nrRealPlaces K * volume (plusPart A) := by + simp only [← measure_congr (iUnion_negAt_plusPart_ae A hA), + measure_iUnion (disjoint_negAt_plusPart A) (fun _ ↦ measurableSet_negAt_plusPart _ A hm), + volume_negAt_plusPart _ hm, tsum_fintype, sum_const, card_univ, Fintype.card_set, nsmul_eq_mul, + Nat.cast_pow, Nat.cast_ofNat, nrRealPlaces] + +end plusPart + end NumberField.mixedEmbedding diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean index 36a06aabe738b..ff9af2b825008 100644 --- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean +++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean @@ -77,18 +77,9 @@ open scoped Classical variable [NumberField K] -instance : IsAddHaarMeasure (volume : Measure (mixedSpace K)) := prod.instIsAddHaarMeasure _ _ - -instance : NoAtoms (volume : Measure (mixedSpace K)) := by - obtain ⟨w⟩ := (inferInstance : Nonempty (InfinitePlace K)) - by_cases hw : IsReal w - · exact @prod.instNoAtoms_fst _ _ _ _ volume volume _ (pi_noAtoms ⟨w, hw⟩) - · exact @prod.instNoAtoms_snd _ _ _ _ volume volume _ - (pi_noAtoms ⟨w, not_isReal_iff_isComplex.mp hw⟩) - /-- The fudge factor that appears in the formula for the volume of `convexBodyLT`. -/ noncomputable abbrev convexBodyLTFactor : ℝ≥0 := - (2 : ℝ≥0) ^ NrRealPlaces K * NNReal.pi ^ NrComplexPlaces K + (2 : ℝ≥0) ^ nrRealPlaces K * NNReal.pi ^ nrComplexPlaces K theorem convexBodyLTFactor_ne_zero : convexBodyLTFactor K ≠ 0 := mul_ne_zero (pow_ne_zero _ two_ne_zero) (pow_ne_zero _ pi_ne_zero) @@ -104,10 +95,10 @@ theorem convexBodyLT_volume : _ = (∏ x : {w // InfinitePlace.IsReal w}, ENNReal.ofReal (2 * (f x.val))) * ∏ x : {w // InfinitePlace.IsComplex w}, ENNReal.ofReal (f x.val) ^ 2 * NNReal.pi := by simp_rw [volume_eq_prod, prod_prod, volume_pi, pi_pi, Real.volume_ball, Complex.volume_ball] - _ = ((2 : ℝ≥0) ^ NrRealPlaces K + _ = ((2 : ℝ≥0) ^ nrRealPlaces K * (∏ x : {w // InfinitePlace.IsReal w}, ENNReal.ofReal (f x.val))) * ((∏ x : {w // IsComplex w}, ENNReal.ofReal (f x.val) ^ 2) * - NNReal.pi ^ NrComplexPlaces K) := by + NNReal.pi ^ nrComplexPlaces K) := by simp_rw [ofReal_mul (by norm_num : 0 ≤ (2 : ℝ)), Finset.prod_mul_distrib, Finset.prod_const, Finset.card_univ, ofReal_ofNat, ofReal_coe_nnreal, coe_ofNat] _ = (convexBodyLTFactor K) * ((∏ x : {w // InfinitePlace.IsReal w}, .ofReal (f x.val)) * @@ -205,7 +196,7 @@ variable [NumberField K] /-- The fudge factor that appears in the formula for the volume of `convexBodyLT'`. -/ noncomputable abbrev convexBodyLT'Factor : ℝ≥0 := - (2 : ℝ≥0) ^ (NrRealPlaces K + 2) * NNReal.pi ^ (NrComplexPlaces K - 1) + (2 : ℝ≥0) ^ (nrRealPlaces K + 2) * NNReal.pi ^ (nrComplexPlaces K - 1) theorem convexBodyLT'Factor_ne_zero : convexBodyLT'Factor K ≠ 0 := mul_ne_zero (pow_ne_zero _ two_ne_zero) (pow_ne_zero _ pi_ne_zero) @@ -238,10 +229,10 @@ theorem convexBodyLT'_volume : · refine Finset.prod_congr rfl (fun w' hw' ↦ ?_) rw [if_neg (Finset.ne_of_mem_erase hw'), Complex.volume_ball] · simpa only [ite_true] using vol_box (f w₀) - _ = ((2 : ℝ≥0) ^ NrRealPlaces K * + _ = ((2 : ℝ≥0) ^ nrRealPlaces K * (∏ x : {w // InfinitePlace.IsReal w}, ENNReal.ofReal (f x.val))) * ((∏ x ∈ Finset.univ.erase w₀, ENNReal.ofReal (f x.val) ^ 2) * - ↑pi ^ (NrComplexPlaces K - 1) * (4 * (f w₀) ^ 2)) := by + ↑pi ^ (nrComplexPlaces K - 1) * (4 * (f w₀) ^ 2)) := by simp_rw [ofReal_mul (by norm_num : 0 ≤ (2 : ℝ)), Finset.prod_mul_distrib, Finset.prod_const, Finset.card_erase_of_mem (Finset.mem_univ _), Finset.card_univ, ofReal_ofNat, ofReal_coe_nnreal, coe_ofNat] @@ -385,7 +376,7 @@ theorem convexBodySum_compact : IsCompact (convexBodySum K B) := by /-- The fudge factor that appears in the formula for the volume of `convexBodyLt`. -/ noncomputable abbrev convexBodySumFactor : ℝ≥0 := - (2 : ℝ≥0) ^ NrRealPlaces K * (NNReal.pi / 2) ^ NrComplexPlaces K / (finrank ℚ K).factorial + (2 : ℝ≥0) ^ nrRealPlaces K * (NNReal.pi / 2) ^ nrComplexPlaces K / (finrank ℚ K).factorial theorem convexBodySumFactor_ne_zero : convexBodySumFactor K ≠ 0 := by refine div_ne_zero ?_ <| Nat.cast_ne_zero.mpr (Nat.factorial_ne_zero _) @@ -418,7 +409,7 @@ theorem convexBodySum_volume : simp_rw [mixedEmbedding.finrank, div_one, Gamma_nat_eq_factorial, ofReal_div_of_pos (Nat.cast_pos.mpr (Nat.factorial_pos _)), Real.rpow_one, ofReal_natCast] suffices ∫ x : mixedSpace K, exp (-convexBodySumFun x) = - (2 : ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K by + (2 : ℝ) ^ nrRealPlaces K * (π / 2) ^ nrComplexPlaces K by rw [this, convexBodySumFactor, ofReal_mul (by positivity), ofReal_pow zero_le_two, ofReal_pow (by positivity), ofReal_div_of_pos zero_lt_two, ofReal_ofNat, ← NNReal.coe_real_pi, ofReal_coe_nnreal, coe_div (Nat.cast_ne_zero.mpr @@ -429,17 +420,17 @@ theorem convexBodySum_volume : (∫ x : {w : InfinitePlace K // IsComplex w} → ℂ, ∏ w, exp (- 2 * ‖x w‖)) := by simp_rw [convexBodySumFun_apply', neg_add, ← neg_mul, Finset.mul_sum, ← Finset.sum_neg_distrib, exp_add, exp_sum, ← integral_prod_mul, volume_eq_prod] - _ = (∫ x : ℝ, exp (-|x|)) ^ NrRealPlaces K * - (∫ x : ℂ, Real.exp (-2 * ‖x‖)) ^ NrComplexPlaces K := by + _ = (∫ x : ℝ, exp (-|x|)) ^ nrRealPlaces K * + (∫ x : ℂ, Real.exp (-2 * ‖x‖)) ^ nrComplexPlaces K := by rw [integral_fintype_prod_eq_pow _ (fun x => exp (- ‖x‖)), integral_fintype_prod_eq_pow _ (fun x => exp (- 2 * ‖x‖))] simp_rw [norm_eq_abs] - _ = (2 * Gamma (1 / 1 + 1)) ^ NrRealPlaces K * - (π * (2 : ℝ) ^ (-(2 : ℝ) / 1) * Gamma (2 / 1 + 1)) ^ NrComplexPlaces K := by + _ = (2 * Gamma (1 / 1 + 1)) ^ nrRealPlaces K * + (π * (2 : ℝ) ^ (-(2 : ℝ) / 1) * Gamma (2 / 1 + 1)) ^ nrComplexPlaces K := by rw [integral_comp_abs (f := fun x => exp (- x)), ← integral_exp_neg_rpow zero_lt_one, ← Complex.integral_exp_neg_mul_rpow le_rfl zero_lt_two] simp_rw [Real.rpow_one] - _ = (2 : ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K := by + _ = (2 : ℝ) ^ nrRealPlaces K * (π / 2) ^ nrComplexPlaces K := by simp_rw [div_one, one_add_one_eq_two, Gamma_add_one two_ne_zero, Gamma_two, mul_one, mul_assoc, ← Real.rpow_add_one two_ne_zero, show (-2 : ℝ) + 1 = -1 by norm_num, Real.rpow_neg_one] diff --git a/Mathlib/NumberTheory/NumberField/ClassNumber.lean b/Mathlib/NumberTheory/NumberField/ClassNumber.lean index 06ed53e2b5316..0c87862166478 100644 --- a/Mathlib/NumberTheory/NumberField/ClassNumber.lean +++ b/Mathlib/NumberTheory/NumberField/ClassNumber.lean @@ -5,7 +5,7 @@ Authors: Anne Baanen -/ import Mathlib.NumberTheory.ClassNumber.AdmissibleAbs import Mathlib.NumberTheory.ClassNumber.Finite -import Mathlib.NumberTheory.NumberField.Discriminant +import Mathlib.NumberTheory.NumberField.Discriminant.Basic /-! # Class numbers of number fields @@ -19,7 +19,6 @@ on the class number. cardinality of the class group of its ring of integers -/ - namespace NumberField variable (K : Type*) [Field K] [NumberField K] @@ -47,7 +46,7 @@ open scoped nonZeroDivisors Real theorem exists_ideal_in_class_of_norm_le (C : ClassGroup (𝓞 K)) : ∃ I : (Ideal (𝓞 K))⁰, ClassGroup.mk0 I = C ∧ - Ideal.absNorm (I : Ideal (𝓞 K)) ≤ (4 / π) ^ NrComplexPlaces K * + Ideal.absNorm (I : Ideal (𝓞 K)) ≤ (4 / π) ^ nrComplexPlaces K * ((finrank ℚ K).factorial / (finrank ℚ K) ^ (finrank ℚ K) * Real.sqrt |discr K|) := by obtain ⟨J, hJ⟩ := ClassGroup.mk0_surjective C⁻¹ obtain ⟨_, ⟨a, ha, rfl⟩, h_nz, h_nm⟩ := @@ -71,7 +70,7 @@ theorem exists_ideal_in_class_of_norm_le (C : ClassGroup (𝓞 K)) : exact Nat.cast_pos.mpr <| Nat.pos_of_ne_zero <| Ideal.absNorm_ne_zero_of_nonZeroDivisors J theorem _root_.RingOfIntegers.isPrincipalIdealRing_of_abs_discr_lt - (h : |discr K| < (2 * (π / 4) ^ NrComplexPlaces K * + (h : |discr K| < (2 * (π / 4) ^ nrComplexPlaces K * ((finrank ℚ K) ^ (finrank ℚ K) / (finrank ℚ K).factorial)) ^ 2) : IsPrincipalIdealRing (𝓞 K) := by have : 0 < finrank ℚ K := finrank_pos -- Lean needs to know that for positivity to succeed diff --git a/Mathlib/NumberTheory/NumberField/Discriminant.lean b/Mathlib/NumberTheory/NumberField/Discriminant/Basic.lean similarity index 79% rename from Mathlib/NumberTheory/NumberField/Discriminant.lean rename to Mathlib/NumberTheory/NumberField/Discriminant/Basic.lean index 52a08d5551c4a..013f14fce60b1 100644 --- a/Mathlib/NumberTheory/NumberField/Discriminant.lean +++ b/Mathlib/NumberTheory/NumberField/Discriminant/Basic.lean @@ -3,18 +3,16 @@ 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.Algebra.Module.ZLattice.Covolume import Mathlib.Data.Real.Pi.Bounds import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.ConvexBody import Mathlib.Tactic.Rify +import Mathlib.NumberTheory.NumberField.Discriminant.Defs /-! # Number field discriminant This file defines the discriminant of a number field. -## Main definitions - -* `NumberField.discr`: the absolute discriminant of a number field. - ## Main result * `NumberField.abs_discr_gt_two`: **Hermite-Minkowski Theorem**. A nontrivial number field has @@ -38,47 +36,19 @@ open scoped Classical Real nonZeroDivisors variable (K : Type*) [Field K] [NumberField K] -/-- The absolute discriminant of a number field. -/ -noncomputable abbrev discr : ℤ := Algebra.discr ℤ (RingOfIntegers.basis K) - -theorem coe_discr : (discr K : ℚ) = Algebra.discr ℚ (integralBasis K) := - (Algebra.discr_localizationLocalization ℤ _ K (RingOfIntegers.basis K)).symm - -theorem discr_ne_zero : discr K ≠ 0 := by - rw [← (Int.cast_injective (α := ℚ)).ne_iff, coe_discr] - exact Algebra.discr_not_zero_of_basis ℚ (integralBasis K) - -theorem discr_eq_discr {ι : Type*} [Fintype ι] [DecidableEq ι] (b : Basis ι ℤ (𝓞 K)) : - Algebra.discr ℤ b = discr K := by - let b₀ := Basis.reindex (RingOfIntegers.basis K) (Basis.indexEquiv (RingOfIntegers.basis K) b) - rw [Algebra.discr_eq_discr (𝓞 K) b b₀, Basis.coe_reindex, Algebra.discr_reindex] - -theorem discr_eq_discr_of_algEquiv {L : Type*} [Field L] [NumberField L] (f : K ≃ₐ[ℚ] L) : - discr K = discr L := by - let f₀ : 𝓞 K ≃ₗ[ℤ] 𝓞 L := (f.restrictScalars ℤ).mapIntegralClosure.toLinearEquiv - rw [← Rat.intCast_inj, coe_discr, Algebra.discr_eq_discr_of_algEquiv (integralBasis K) f, - ← discr_eq_discr L ((RingOfIntegers.basis K).map f₀)] - change _ = algebraMap ℤ ℚ _ - rw [← Algebra.discr_localizationLocalization ℤ (nonZeroDivisors ℤ) L] - congr - ext - simp only [Function.comp_apply, integralBasis_apply, Basis.localizationLocalization_apply, - Basis.map_apply] - rfl - open MeasureTheory MeasureTheory.Measure ZSpan NumberField.mixedEmbedding NumberField.InfinitePlace ENNReal NNReal Complex theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis : volume (fundamentalDomain (latticeBasis K)) = - (2 : ℝ≥0∞)⁻¹ ^ NrComplexPlaces K * sqrt ‖discr K‖₊ := by + (2 : ℝ≥0∞)⁻¹ ^ nrComplexPlaces K * sqrt ‖discr K‖₊ := by let f : Module.Free.ChooseBasisIndex ℤ (𝓞 K) ≃ (K →+* ℂ) := (canonicalEmbedding.latticeBasis K).indexEquiv (Pi.basisFun ℂ _) let e : (index K) ≃ Module.Free.ChooseBasisIndex ℤ (𝓞 K) := (indexEquiv K).trans f.symm let M := (mixedEmbedding.stdBasis K).toMatrix ((latticeBasis K).reindex e.symm) let N := Algebra.embeddingsMatrixReindex ℚ ℂ (integralBasis K ∘ f.symm) RingHom.equivRatAlgHom - suffices M.map Complex.ofReal = (matrixToStdBasis K) * + suffices M.map ofRealHom = matrixToStdBasis K * (Matrix.reindex (indexEquiv K).symm (indexEquiv K).symm N).transpose by calc volume (fundamentalDomain (latticeBasis K)) _ = ‖((mixedEmbedding.stdBasis K).toMatrix ((latticeBasis K).reindex e.symm)).det‖₊ := by @@ -86,7 +56,7 @@ theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis ((latticeBasis K).reindex e.symm), volume_fundamentalDomain_stdBasis, mul_one] rfl _ = ‖(matrixToStdBasis K).det * N.det‖₊ := by - rw [← nnnorm_real, ← ofReal_eq_coe, RingHom.map_det, RingHom.mapMatrix_apply, this, + rw [← nnnorm_real, ← ofRealHom_eq_coe, RingHom.map_det, RingHom.mapMatrix_apply, this, det_mul, det_transpose, det_reindex_self] _ = (2 : ℝ≥0∞)⁻¹ ^ Fintype.card {w : InfinitePlace K // IsComplex w} * sqrt ‖N.det ^ 2‖₊ := by have : ‖Complex.I‖₊ = 1 := by rw [← norm_toNNReal, norm_eq_abs, abs_I, Real.toNNReal_one] @@ -99,13 +69,31 @@ theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis ext : 2 dsimp only [M] rw [Matrix.map_apply, Basis.toMatrix_apply, Basis.coe_reindex, Function.comp_apply, - Equiv.symm_symm, latticeBasis_apply, ← commMap_canonical_eq_mixed, Complex.ofReal_eq_coe, + Equiv.symm_symm, latticeBasis_apply, ← commMap_canonical_eq_mixed, Complex.ofRealHom_eq_coe, stdBasis_repr_eq_matrixToStdBasis_mul K _ (fun _ => rfl)] rfl +theorem _root_.NumberField.mixedEmbedding.covolume_integerLattice : + ZLattice.covolume (mixedEmbedding.integerLattice K) = + (2 ⁻¹) ^ nrComplexPlaces K * √|discr K| := by + rw [ZLattice.covolume_eq_measure_fundamentalDomain _ _ (fundamentalDomain_integerLattice K), + volume_fundamentalDomain_latticeBasis, ENNReal.toReal_mul, ENNReal.toReal_pow, + ENNReal.toReal_inv, toReal_ofNat, ENNReal.coe_toReal, Real.coe_sqrt, coe_nnnorm, + Int.norm_eq_abs] + +theorem _root_.NumberField.mixedEmbedding.covolume_idealLattice (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) : + ZLattice.covolume (mixedEmbedding.idealLattice K I) = + (FractionalIdeal.absNorm (I : FractionalIdeal (𝓞 K)⁰ K)) * + (2 ⁻¹) ^ nrComplexPlaces K * √|discr K| := by + rw [ZLattice.covolume_eq_measure_fundamentalDomain _ _ (fundamentalDomain_idealLattice K I), + volume_fundamentalDomain_fractionalIdealLatticeBasis, volume_fundamentalDomain_latticeBasis, + ENNReal.toReal_mul, ENNReal.toReal_mul, ENNReal.toReal_pow, ENNReal.toReal_inv, toReal_ofNat, + ENNReal.coe_toReal, Real.coe_sqrt, coe_nnnorm, Int.norm_eq_abs, + ENNReal.toReal_ofReal (Rat.cast_nonneg.mpr (FractionalIdeal.absNorm_nonneg I.val)), mul_assoc] + theorem exists_ne_zero_mem_ideal_of_norm_le_mul_sqrt_discr (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) : ∃ a ∈ (I : FractionalIdeal (𝓞 K)⁰ K), a ≠ 0 ∧ - |Algebra.norm ℚ (a : K)| ≤ FractionalIdeal.absNorm I.1 * (4 / π) ^ NrComplexPlaces K * + |Algebra.norm ℚ (a : K)| ≤ FractionalIdeal.absNorm I.1 * (4 / π) ^ nrComplexPlaces K * (finrank ℚ K).factorial / (finrank ℚ K) ^ (finrank ℚ K) * Real.sqrt |discr K| := by -- The smallest possible value for `exists_ne_zero_mem_ideal_of_norm_le` let B := (minkowskiBound K I * (convexBodySumFactor K)⁻¹).toReal ^ (1 / (finrank ℚ K : ℝ)) @@ -123,8 +111,8 @@ theorem exists_ne_zero_mem_ideal_of_norm_le_mul_sqrt_discr (I : (FractionalIdeal congr 1 rw [eq_comm] calc - _ = FractionalIdeal.absNorm I.1 * (2 : ℝ)⁻¹ ^ NrComplexPlaces K * sqrt ‖discr K‖₊ * - (2 : ℝ) ^ finrank ℚ K * ((2 : ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K / + _ = FractionalIdeal.absNorm I.1 * (2 : ℝ)⁻¹ ^ nrComplexPlaces K * sqrt ‖discr K‖₊ * + (2 : ℝ) ^ finrank ℚ K * ((2 : ℝ) ^ nrRealPlaces K * (π / 2) ^ nrComplexPlaces K / (Nat.factorial (finrank ℚ K)))⁻¹ := by simp_rw [minkowskiBound, convexBodySumFactor, volume_fundamentalDomain_fractionalIdealLatticeBasis, @@ -133,19 +121,19 @@ theorem exists_ne_zero_mem_ideal_of_norm_le_mul_sqrt_discr (I : (FractionalIdeal rw [ENNReal.toReal_ofReal (Rat.cast_nonneg.mpr (FractionalIdeal.absNorm_nonneg I.1))] simp_rw [NNReal.coe_inv, NNReal.coe_div, NNReal.coe_mul, NNReal.coe_pow, NNReal.coe_div, coe_real_pi, NNReal.coe_ofNat, NNReal.coe_natCast] - _ = FractionalIdeal.absNorm I.1 * (2 : ℝ) ^ (finrank ℚ K - NrComplexPlaces K - NrRealPlaces K + - NrComplexPlaces K : ℤ) * Real.sqrt ‖discr K‖ * Nat.factorial (finrank ℚ K) * - π⁻¹ ^ (NrComplexPlaces K) := by + _ = FractionalIdeal.absNorm I.1 * (2 : ℝ) ^ (finrank ℚ K - nrComplexPlaces K - nrRealPlaces K + + nrComplexPlaces K : ℤ) * Real.sqrt ‖discr K‖ * Nat.factorial (finrank ℚ K) * + π⁻¹ ^ (nrComplexPlaces K) := by simp_rw [inv_div, div_eq_mul_inv, mul_inv, ← zpow_neg_one, ← zpow_natCast, mul_zpow, ← zpow_mul, neg_one_mul, mul_neg_one, neg_neg, Real.coe_sqrt, coe_nnnorm, sub_eq_add_neg, zpow_add₀ (two_ne_zero : (2 : ℝ) ≠ 0)] ring - _ = FractionalIdeal.absNorm I.1 * (2 : ℝ) ^ (2 * NrComplexPlaces K : ℤ) * Real.sqrt ‖discr K‖ * - Nat.factorial (finrank ℚ K) * π⁻¹ ^ (NrComplexPlaces K) := by + _ = FractionalIdeal.absNorm I.1 * (2 : ℝ) ^ (2 * nrComplexPlaces K : ℤ) * Real.sqrt ‖discr K‖ * + Nat.factorial (finrank ℚ K) * π⁻¹ ^ (nrComplexPlaces K) := by congr rw [← card_add_two_mul_card_eq_rank, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat] ring - _ = FractionalIdeal.absNorm I.1 * (4 / π) ^ NrComplexPlaces K * (finrank ℚ K).factorial * + _ = FractionalIdeal.absNorm I.1 * (4 / π) ^ nrComplexPlaces K * (finrank ℚ K).factorial * Real.sqrt |discr K| := by rw [Int.norm_eq_abs, zpow_mul, show (2 : ℝ) ^ (2 : ℤ) = 4 by norm_cast, div_pow, inv_eq_one_div, div_pow, one_pow, zpow_natCast] @@ -153,7 +141,7 @@ theorem exists_ne_zero_mem_ideal_of_norm_le_mul_sqrt_discr (I : (FractionalIdeal theorem exists_ne_zero_mem_ringOfIntegers_of_norm_le_mul_sqrt_discr : ∃ (a : 𝓞 K), a ≠ 0 ∧ - |Algebra.norm ℚ (a : K)| ≤ (4 / π) ^ NrComplexPlaces K * + |Algebra.norm ℚ (a : K)| ≤ (4 / π) ^ nrComplexPlaces K * (finrank ℚ K).factorial / (finrank ℚ K) ^ (finrank ℚ K) * Real.sqrt |discr K| := by obtain ⟨_, h_mem, h_nz, h_nm⟩ := exists_ne_zero_mem_ideal_of_norm_le_mul_sqrt_discr K ↑1 obtain ⟨a, rfl⟩ := (FractionalIdeal.mem_one_iff _).mp h_mem @@ -308,7 +296,7 @@ theorem minkowskiBound_lt_boundOfDiscBdd : minkowskiBound K ↑1 < boundOfDiscBd coe_mul, ENNReal.coe_pow, coe_ofNat, show sqrt N = (1 : ℝ≥0∞) * sqrt N by rw [one_mul]] gcongr · exact pow_le_one₀ (by positivity) (by norm_num) - · rwa [sqrt_le_sqrt, ← NNReal.coe_le_coe, coe_nnnorm, Int.norm_eq_abs, ← Int.cast_abs, + · rwa [← NNReal.coe_le_coe, coe_nnnorm, Int.norm_eq_abs, ← Int.cast_abs, NNReal.coe_natCast, ← Int.cast_natCast, Int.cast_le] · exact one_le_two · exact rank_le_rankOfDiscrBdd hK @@ -360,7 +348,7 @@ theorem finite_of_discr_bdd_of_isReal : · exact (Nat.choose_le_choose _ (rank_le_rankOfDiscrBdd hK₂)).trans (Nat.choose_le_middle _ _) · refine mem_rootSet.mpr ⟨minpoly.ne_zero hx, ?_⟩ - exact (aeval_algebraMap_eq_zero_iff _ _ _).mpr (minpoly.aeval ℤ (x : K)) + exact (aeval_algebraMap_eq_zero_iff A (x : K) _).mpr (minpoly.aeval ℤ (x : K)) · rw [← (IntermediateField.lift_injective _).eq_iff, eq_comm] at hx₁ convert hx₁ · simp only [IntermediateField.lift_top] @@ -409,7 +397,7 @@ theorem finite_of_discr_bdd_of_isComplex : exact (Nat.choose_le_choose _ (rank_le_rankOfDiscrBdd hK₂)).trans (Nat.choose_le_middle _ _) · refine mem_rootSet.mpr ⟨minpoly.ne_zero hx, ?_⟩ - exact (aeval_algebraMap_eq_zero_iff _ _ _).mpr (minpoly.aeval ℤ (x : K)) + exact (aeval_algebraMap_eq_zero_iff A (x : K) _).mpr (minpoly.aeval ℤ (x : K)) · rw [← (IntermediateField.lift_injective _).eq_iff, eq_comm] at hx₁ convert hx₁ · simp only [IntermediateField.lift_top] @@ -441,61 +429,3 @@ theorem _root_.NumberField.finite_of_discr_bdd : end hermiteTheorem end NumberField - -namespace Rat - -open NumberField - -/-- The absolute discriminant of the number field `ℚ` is 1. -/ -@[simp] -theorem numberField_discr : discr ℚ = 1 := by - let b : Basis (Fin 1) ℤ (𝓞 ℚ) := - Basis.map (Basis.singleton (Fin 1) ℤ) ringOfIntegersEquiv.toAddEquiv.toIntLinearEquiv.symm - calc NumberField.discr ℚ - _ = Algebra.discr ℤ b := by convert (discr_eq_discr ℚ b).symm - _ = Algebra.trace ℤ (𝓞 ℚ) (b default * b default) := by - rw [Algebra.discr_def, Matrix.det_unique, Algebra.traceMatrix_apply, Algebra.traceForm_apply] - _ = Algebra.trace ℤ (𝓞 ℚ) 1 := by - rw [Basis.map_apply, RingEquiv.toAddEquiv_eq_coe, AddEquiv.toIntLinearEquiv_symm, - AddEquiv.coe_toIntLinearEquiv, Basis.singleton_apply, - show (AddEquiv.symm ↑ringOfIntegersEquiv) (1 : ℤ) = ringOfIntegersEquiv.symm 1 by rfl, - map_one, mul_one] - _ = 1 := by rw [Algebra.trace_eq_matrix_trace b]; norm_num - -alias _root_.NumberField.discr_rat := numberField_discr - -end Rat - -variable {ι ι'} (K) [Field K] [DecidableEq ι] [DecidableEq ι'] [Fintype ι] [Fintype ι'] - -/-- If `b` and `b'` are `ℚ`-bases of a number field `K` such that -`∀ i j, IsIntegral ℤ (b.toMatrix b' i j)` and `∀ i j, IsIntegral ℤ (b'.toMatrix b i j)` then -`discr ℚ b = discr ℚ b'`. -/ -theorem Algebra.discr_eq_discr_of_toMatrix_coeff_isIntegral [NumberField K] - {b : Basis ι ℚ K} {b' : Basis ι' ℚ K} (h : ∀ i j, IsIntegral ℤ (b.toMatrix b' i j)) - (h' : ∀ i j, IsIntegral ℤ (b'.toMatrix b i j)) : discr ℚ b = discr ℚ b' := by - replace h' : ∀ i j, IsIntegral ℤ (b'.toMatrix (b.reindex (b.indexEquiv b')) i j) := by - intro i j - convert h' i ((b.indexEquiv b').symm j) - simp [Basis.toMatrix_apply] - classical - rw [← (b.reindex (b.indexEquiv b')).toMatrix_map_vecMul b', discr_of_matrix_vecMul, - ← one_mul (discr ℚ b), Basis.coe_reindex, discr_reindex] - congr - have hint : IsIntegral ℤ ((b.reindex (b.indexEquiv b')).toMatrix b').det := - IsIntegral.det fun i j => h _ _ - obtain ⟨r, hr⟩ := IsIntegrallyClosed.isIntegral_iff.1 hint - have hunit : IsUnit r := by - have : IsIntegral ℤ (b'.toMatrix (b.reindex (b.indexEquiv b'))).det := - IsIntegral.det fun i j => h' _ _ - obtain ⟨r', hr'⟩ := IsIntegrallyClosed.isIntegral_iff.1 this - refine isUnit_iff_exists_inv.2 ⟨r', ?_⟩ - suffices algebraMap ℤ ℚ (r * r') = 1 by - rw [← RingHom.map_one (algebraMap ℤ ℚ)] at this - exact (IsFractionRing.injective ℤ ℚ) this - rw [RingHom.map_mul, hr, hr', ← Matrix.det_mul, - Basis.toMatrix_mul_toMatrix_flip, Matrix.det_one] - rw [← RingHom.map_one (algebraMap ℤ ℚ), ← hr] - cases' Int.isUnit_iff.1 hunit with hp hm - · simp [hp] - · simp [hm] diff --git a/Mathlib/NumberTheory/NumberField/Discriminant/Defs.lean b/Mathlib/NumberTheory/NumberField/Discriminant/Defs.lean new file mode 100644 index 0000000000000..f9ccf3c816e85 --- /dev/null +++ b/Mathlib/NumberTheory/NumberField/Discriminant/Defs.lean @@ -0,0 +1,119 @@ +/- +Copyright (c) 2023 Xavier Roblot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Xavier Roblot +-/ +import Init.Data.ULift +import Init.Data.Fin.Fold +import Init.Data.List.Nat.Pairwise +import Init.Data.List.Nat.Range +import Mathlib.NumberTheory.NumberField.Basic +import Mathlib.RingTheory.Localization.NormTrace +import Mathlib.Analysis.Normed.Field.Lemmas + +/-! +# Number field discriminant +This file defines the discriminant of a number field. + +## Main definitions + +* `NumberField.discr`: the absolute discriminant of a number field. + +## Tags +number field, discriminant +-/ + +-- TODO. Rewrite some of the FLT results on the disciminant using the definitions and results of +-- this file + +namespace NumberField + +variable (K : Type*) [Field K] [NumberField K] + +/-- The absolute discriminant of a number field. -/ +noncomputable abbrev discr : ℤ := Algebra.discr ℤ (RingOfIntegers.basis K) + +theorem coe_discr : (discr K : ℚ) = Algebra.discr ℚ (integralBasis K) := + (Algebra.discr_localizationLocalization ℤ _ K (RingOfIntegers.basis K)).symm + +theorem discr_ne_zero : discr K ≠ 0 := by + rw [← (Int.cast_injective (α := ℚ)).ne_iff, coe_discr] + exact Algebra.discr_not_zero_of_basis ℚ (integralBasis K) + +theorem discr_eq_discr {ι : Type*} [Fintype ι] [DecidableEq ι] (b : Basis ι ℤ (𝓞 K)) : + Algebra.discr ℤ b = discr K := by + let b₀ := Basis.reindex (RingOfIntegers.basis K) (Basis.indexEquiv (RingOfIntegers.basis K) b) + rw [Algebra.discr_eq_discr (𝓞 K) b b₀, Basis.coe_reindex, Algebra.discr_reindex] + +theorem discr_eq_discr_of_algEquiv {L : Type*} [Field L] [NumberField L] (f : K ≃ₐ[ℚ] L) : + discr K = discr L := by + let f₀ : 𝓞 K ≃ₗ[ℤ] 𝓞 L := (f.restrictScalars ℤ).mapIntegralClosure.toLinearEquiv + rw [← Rat.intCast_inj, coe_discr, Algebra.discr_eq_discr_of_algEquiv (integralBasis K) f, + ← discr_eq_discr L ((RingOfIntegers.basis K).map f₀)] + change _ = algebraMap ℤ ℚ _ + rw [← Algebra.discr_localizationLocalization ℤ (nonZeroDivisors ℤ) L] + congr + ext + simp only [Function.comp_apply, integralBasis_apply, Basis.localizationLocalization_apply, + Basis.map_apply] + rfl + +end NumberField + +namespace Rat + +open NumberField + +/-- The absolute discriminant of the number field `ℚ` is 1. -/ +@[simp] +theorem numberField_discr : discr ℚ = 1 := by + let b : Basis (Fin 1) ℤ (𝓞 ℚ) := + Basis.map (Basis.singleton (Fin 1) ℤ) ringOfIntegersEquiv.toAddEquiv.toIntLinearEquiv.symm + calc NumberField.discr ℚ + _ = Algebra.discr ℤ b := by convert (discr_eq_discr ℚ b).symm + _ = Algebra.trace ℤ (𝓞 ℚ) (b default * b default) := by + rw [Algebra.discr_def, Matrix.det_unique, Algebra.traceMatrix_apply, Algebra.traceForm_apply] + _ = Algebra.trace ℤ (𝓞 ℚ) 1 := by + rw [Basis.map_apply, RingEquiv.toAddEquiv_eq_coe, AddEquiv.toIntLinearEquiv_symm, + AddEquiv.coe_toIntLinearEquiv, Basis.singleton_apply, + show (AddEquiv.symm ↑ringOfIntegersEquiv) (1 : ℤ) = ringOfIntegersEquiv.symm 1 by rfl, + map_one, mul_one] + _ = 1 := by rw [Algebra.trace_eq_matrix_trace b]; norm_num + +alias _root_.NumberField.discr_rat := numberField_discr + +end Rat + +variable {ι ι'} (K) [Field K] [DecidableEq ι] [DecidableEq ι'] [Fintype ι] [Fintype ι'] + +/-- If `b` and `b'` are `ℚ`-bases of a number field `K` such that +`∀ i j, IsIntegral ℤ (b.toMatrix b' i j)` and `∀ i j, IsIntegral ℤ (b'.toMatrix b i j)` then +`discr ℚ b = discr ℚ b'`. -/ +theorem Algebra.discr_eq_discr_of_toMatrix_coeff_isIntegral [NumberField K] + {b : Basis ι ℚ K} {b' : Basis ι' ℚ K} (h : ∀ i j, IsIntegral ℤ (b.toMatrix b' i j)) + (h' : ∀ i j, IsIntegral ℤ (b'.toMatrix b i j)) : discr ℚ b = discr ℚ b' := by + replace h' : ∀ i j, IsIntegral ℤ (b'.toMatrix (b.reindex (b.indexEquiv b')) i j) := by + intro i j + convert h' i ((b.indexEquiv b').symm j) + simp [Basis.toMatrix_apply] + classical + rw [← (b.reindex (b.indexEquiv b')).toMatrix_map_vecMul b', discr_of_matrix_vecMul, + ← one_mul (discr ℚ b), Basis.coe_reindex, discr_reindex] + congr + have hint : IsIntegral ℤ ((b.reindex (b.indexEquiv b')).toMatrix b').det := + IsIntegral.det fun i j => h _ _ + obtain ⟨r, hr⟩ := IsIntegrallyClosed.isIntegral_iff.1 hint + have hunit : IsUnit r := by + have : IsIntegral ℤ (b'.toMatrix (b.reindex (b.indexEquiv b'))).det := + IsIntegral.det fun i j => h' _ _ + obtain ⟨r', hr'⟩ := IsIntegrallyClosed.isIntegral_iff.1 this + refine isUnit_iff_exists_inv.2 ⟨r', ?_⟩ + suffices algebraMap ℤ ℚ (r * r') = 1 by + rw [← RingHom.map_one (algebraMap ℤ ℚ)] at this + exact (IsFractionRing.injective ℤ ℚ) this + rw [RingHom.map_mul, hr, hr', ← Matrix.det_mul, + Basis.toMatrix_mul_toMatrix_flip, Matrix.det_one] + rw [← RingHom.map_one (algebraMap ℤ ℚ), ← hr] + cases' Int.isUnit_iff.1 hunit with hp hm + · simp [hp] + · simp [hm] diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 9e1f2fc310559..f041f1b899502 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -32,7 +32,7 @@ for `x ∈ K`, we have `Π_w ‖x‖_w = |norm(x)|` where the product is over th number field, embeddings, places, infinite places -/ -open scoped Classical +open scoped Classical Finset namespace NumberField.Embeddings @@ -432,8 +432,7 @@ theorem one_le_mult {w : InfinitePlace K} : (1 : ℝ) ≤ mult w := by rw [← Nat.cast_one, Nat.cast_le] exact mult_pos -theorem card_filter_mk_eq [NumberField K] (w : InfinitePlace K) : - (Finset.univ.filter fun φ => mk φ = w).card = mult w := by +theorem card_filter_mk_eq [NumberField K] (w : InfinitePlace K) : #{φ | mk φ = w} = mult w := by conv_lhs => congr; congr; ext rw [← mk_embedding w, mk_eq_iff, ComplexEmbedding.conjugate, star_involutive.eq_iff] @@ -489,12 +488,9 @@ theorem prod_eq_abs_norm (x : K) : convert (congr_arg Complex.abs (@Algebra.norm_eq_prod_embeddings ℚ _ _ _ _ ℂ _ _ _ _ _ x)).symm · rw [map_prod, ← Fintype.prod_equiv RingHom.equivRatAlgHom (fun f => Complex.abs (f x)) (fun φ => Complex.abs (φ x)) fun _ => by simp [RingHom.equivRatAlgHom_apply]; rfl] - rw [← Finset.prod_fiberwise Finset.univ (fun φ => mk φ) (fun φ => Complex.abs (φ x))] - have : ∀ w : InfinitePlace K, ∀ φ ∈ Finset.filter (fun a ↦ mk a = w) Finset.univ, - Complex.abs (φ x) = w x := by - intro _ _ hφ - rw [← (Finset.mem_filter.mp hφ).2] - rfl + rw [← Finset.prod_fiberwise Finset.univ mk (fun φ => Complex.abs (φ x))] + have (w : InfinitePlace K) (φ) (hφ : φ ∈ ({φ | mk φ = w} : Finset _)) : + Complex.abs (φ x) = w x := by rw [← (Finset.mem_filter.mp hφ).2, apply] simp_rw [Finset.prod_congr rfl (this _), Finset.prod_const, card_filter_mk_eq] · rw [eq_ratCast, Rat.cast_abs, ← Complex.abs_ofReal, Complex.ofReal_ratCast] @@ -555,24 +551,28 @@ section NumberField variable [NumberField K] /-- The number of infinite real places of the number field `K`. -/ -noncomputable abbrev NrRealPlaces := card { w : InfinitePlace K // IsReal w } +noncomputable abbrev nrRealPlaces := card { w : InfinitePlace K // IsReal w } + +@[deprecated (since := "2024-10-24")] alias NrRealPlaces := nrRealPlaces /-- The number of infinite complex places of the number field `K`. -/ -noncomputable abbrev NrComplexPlaces := card { w : InfinitePlace K // IsComplex w } +noncomputable abbrev nrComplexPlaces := card { w : InfinitePlace K // IsComplex w } + +@[deprecated (since := "2024-10-24")] alias NrComplexPlaces := nrComplexPlaces theorem card_real_embeddings : - card { φ : K →+* ℂ // ComplexEmbedding.IsReal φ } = NrRealPlaces K := Fintype.card_congr mkReal + card { φ : K →+* ℂ // ComplexEmbedding.IsReal φ } = nrRealPlaces K := Fintype.card_congr mkReal theorem card_eq_nrRealPlaces_add_nrComplexPlaces : - Fintype.card (InfinitePlace K) = NrRealPlaces K + NrComplexPlaces K := by + Fintype.card (InfinitePlace K) = nrRealPlaces K + nrComplexPlaces K := by convert Fintype.card_subtype_or_disjoint (IsReal (K := K)) (IsComplex (K := K)) (disjoint_isReal_isComplex K) using 1 exact (Fintype.card_of_subtype _ (fun w ↦ ⟨fun _ ↦ isReal_or_isComplex w, fun _ ↦ by simp⟩)).symm theorem card_complex_embeddings : - card { φ : K →+* ℂ // ¬ComplexEmbedding.IsReal φ } = 2 * NrComplexPlaces K := by - suffices ∀ w : { w : InfinitePlace K // IsComplex w }, (Finset.univ.filter - fun φ : { φ // ¬ ComplexEmbedding.IsReal φ } => mkComplex φ = w).card = 2 by + card { φ : K →+* ℂ // ¬ComplexEmbedding.IsReal φ } = 2 * nrComplexPlaces K := by + suffices ∀ w : { w : InfinitePlace K // IsComplex w }, + #{φ : {φ //¬ ComplexEmbedding.IsReal φ} | mkComplex φ = w} = 2 by rw [Fintype.card, Finset.card_eq_sum_ones, ← Finset.sum_fiberwise _ (fun φ => mkComplex φ)] simp_rw [Finset.sum_const, this, smul_eq_mul, mul_one, Fintype.card, Finset.card_eq_sum_ones, Finset.mul_sum, Finset.sum_const, smul_eq_mul, mul_one] @@ -587,7 +587,7 @@ theorem card_complex_embeddings : · simp_rw [mult, not_isReal_iff_isComplex.mpr hw, ite_false] theorem card_add_two_mul_card_eq_rank : - NrRealPlaces K + 2 * NrComplexPlaces K = finrank ℚ K := by + nrRealPlaces K + 2 * nrComplexPlaces K = finrank ℚ K := by rw [← card_real_embeddings, ← card_complex_embeddings, Fintype.card_subtype_compl, ← Embeddings.card K ℂ, Nat.add_sub_of_le] exact Fintype.card_subtype_le _ @@ -595,10 +595,10 @@ theorem card_add_two_mul_card_eq_rank : variable {K} theorem nrComplexPlaces_eq_zero_of_finrank_eq_one (h : finrank ℚ K = 1) : - NrComplexPlaces K = 0 := by linarith [card_add_two_mul_card_eq_rank K] + nrComplexPlaces K = 0 := by linarith [card_add_two_mul_card_eq_rank K] theorem nrRealPlaces_eq_one_of_finrank_eq_one (h : finrank ℚ K = 1) : - NrRealPlaces K = 1 := by + nrRealPlaces K = 1 := by have := card_add_two_mul_card_eq_rank K rwa [nrComplexPlaces_eq_zero_of_finrank_eq_one h, h, mul_zero, add_zero] at this @@ -930,16 +930,16 @@ variable [NumberField K] open Finset in lemma card_isUnramified [NumberField k] [IsGalois k K] : - Finset.card (univ.filter <| IsUnramified k (K := K)) = - Finset.card (univ.filter <| IsUnramifiedIn K (k := k)) * (finrank k K) := by + #{w : InfinitePlace K | w.IsUnramified k} = + #{w : InfinitePlace k | w.IsUnramifiedIn K} * finrank k K := by letI := Module.Finite.of_restrictScalars_finite ℚ k K rw [← IsGalois.card_aut_eq_finrank, Finset.card_eq_sum_card_fiberwise (f := (comap · (algebraMap k K))) - (t := (univ.filter <| IsUnramifiedIn K (k := k))), ← smul_eq_mul, ← sum_const] + (t := {w : InfinitePlace k | w.IsUnramifiedIn K}), ← smul_eq_mul, ← sum_const] · refine sum_congr rfl (fun w hw ↦ ?_) obtain ⟨w, rfl⟩ := comap_surjective (K := K) w simp only [mem_univ, forall_true_left, mem_filter, true_and] at hw - trans Finset.card (MulAction.orbit (K ≃ₐ[k] K) w).toFinset + trans #(MulAction.orbit (K ≃ₐ[k] K) w).toFinset · congr; ext w' simp only [mem_univ, forall_true_left, filter_congr_decidable, mem_filter, true_and, Set.mem_toFinset, mem_orbit_iff, @eq_comm _ (comap w' _), and_iff_right_iff_imp] @@ -952,12 +952,12 @@ lemma card_isUnramified [NumberField k] [IsGalois k K] : open Finset in lemma card_isUnramified_compl [NumberField k] [IsGalois k K] : - Finset.card (univ.filter <| IsUnramified k (K := K))ᶜ = - Finset.card (univ.filter <| IsUnramifiedIn K (k := k))ᶜ * (finrank k K / 2) := by + #({w : InfinitePlace K | w.IsUnramified k} : Finset _)ᶜ = + #({w : InfinitePlace k | w.IsUnramifiedIn K} : Finset _)ᶜ * (finrank k K / 2) := by letI := Module.Finite.of_restrictScalars_finite ℚ k K rw [← IsGalois.card_aut_eq_finrank, Finset.card_eq_sum_card_fiberwise (f := (comap · (algebraMap k K))) - (t := (univ.filter <| IsUnramifiedIn K (k := k))ᶜ), ← smul_eq_mul, ← sum_const] + (t := ({w : InfinitePlace k | w.IsUnramifiedIn K}: Finset _)ᶜ), ← smul_eq_mul, ← sum_const] · refine sum_congr rfl (fun w hw ↦ ?_) obtain ⟨w, rfl⟩ := comap_surjective (K := K) w simp only [mem_univ, forall_true_left, compl_filter, not_not, mem_filter, true_and] at hw @@ -974,8 +974,8 @@ lemma card_isUnramified_compl [NumberField k] [IsGalois k K] : lemma card_eq_card_isUnramifiedIn [NumberField k] [IsGalois k K] : Fintype.card (InfinitePlace K) = - Finset.card (Finset.univ.filter <| IsUnramifiedIn K (k := k)) * finrank k K + - Finset.card (Finset.univ.filter <| IsUnramifiedIn K (k := k))ᶜ * (finrank k K / 2) := by + #{w : InfinitePlace k | w.IsUnramifiedIn K} * finrank k K + + #({w : InfinitePlace k | w.IsUnramifiedIn K} : Finset _)ᶜ * (finrank k K / 2) := by rw [← card_isUnramified, ← card_isUnramified_compl, Finset.card_add_card_compl] end NumberField.InfinitePlace @@ -1046,7 +1046,7 @@ namespace IsPrimitiveRoot variable {K : Type*} [Field K] [NumberField K] {ζ : K} {k : ℕ} theorem nrRealPlaces_eq_zero_of_two_lt (hk : 2 < k) (hζ : IsPrimitiveRoot ζ k) : - NumberField.InfinitePlace.NrRealPlaces K = 0 := by + NumberField.InfinitePlace.nrRealPlaces K = 0 := by refine (@Fintype.card_eq_zero_iff _ (_)).2 ⟨fun ⟨w, hwreal⟩ ↦ ?_⟩ rw [NumberField.InfinitePlace.isReal_iff] at hwreal let f := w.embedding diff --git a/Mathlib/NumberTheory/NumberField/EquivReindex.lean b/Mathlib/NumberTheory/NumberField/EquivReindex.lean index 0226ce9f8e5d5..76ece2db3d216 100644 --- a/Mathlib/NumberTheory/NumberField/EquivReindex.lean +++ b/Mathlib/NumberTheory/NumberField/EquivReindex.lean @@ -11,8 +11,9 @@ import Mathlib.NumberTheory.NumberField.CanonicalEmbedding.Basic This file introduces an equivalence between the set of embeddings of `K` into `ℂ` and the index set of the chosen basis of the ring of integers of `K`. -## Tagshouse -number field, algebraic number +## Tags + +house, number field, algebraic number -/ variable (K : Type*) [Field K] [NumberField K] diff --git a/Mathlib/NumberTheory/NumberField/House.lean b/Mathlib/NumberTheory/NumberField/House.lean index d56eb4d18c668..f5cd7772f5a6a 100644 --- a/Mathlib/NumberTheory/NumberField/House.lean +++ b/Mathlib/NumberTheory/NumberField/House.lean @@ -15,7 +15,7 @@ the largest of the modulus of its conjugates. ## References * [D. Marcus, *Number Fields*][marcus1977number] -* [Keng, H. L, *Introduction to number theory*][keng1982house] +* [Hua, L.-K., *Introduction to number theory*][hua1982house] ## Tagshouse number field, algebraic number, house @@ -132,7 +132,7 @@ include ha in private theorem asiegel_ne_0 : asiegel K a ≠ 0 := by simp (config := { unfoldPartialApp := true }) only [asiegel, a'] simp only [ne_eq] - rw [Function.funext_iff]; intros hs + rw [funext_iff]; intros hs simp only [Prod.forall] at hs; apply ha rw [← Matrix.ext_iff]; intros k' l @@ -141,7 +141,7 @@ private theorem asiegel_ne_0 : asiegel K a ≠ 0 := by have := ((newBasis K).repr.map_eq_zero_iff (x := (a k' l * (newBasis K) b))).1 <| by ext b' specialize hs b' - rw [Function.funext_iff] at hs + rw [funext_iff] at hs simp only [Prod.forall] at hs apply hs simp only [mul_eq_zero] at this @@ -157,7 +157,7 @@ private theorem ξ_ne_0 : ξ K x ≠ 0 := by intro H apply hxl ext ⟨l, r⟩ - rw [Function.funext_iff] at H + rw [funext_iff] at H have hblin := Basis.linearIndependent (newBasis K) simp only [zsmul_eq_mul, Fintype.linearIndependent_iff] at hblin exact hblin (fun r ↦ x (l,r)) (H _) r @@ -175,9 +175,9 @@ private theorem ξ_mulVec_eq_0 : a *ᵥ ξ K x = 0 := by have lin_0 : ∀ u, ∑ r, ∑ l, (a' K a k l r u * x (l, r) : 𝓞 K) = 0 := by intros u have hξ := ξ_ne_0 K x hxl - rw [Ne, Function.funext_iff, not_forall] at hξ + rw [Ne, funext_iff, not_forall] at hξ rcases hξ with ⟨l, hξ⟩ - rw [Function.funext_iff] at hmulvec0 + rw [funext_iff] at hmulvec0 specialize hmulvec0 ⟨k, u⟩ simp only [Fintype.sum_prod_type, mulVec, dotProduct, asiegel] at hmulvec0 rw [sum_comm] at hmulvec0 diff --git a/Mathlib/NumberTheory/NumberField/Units/Basic.lean b/Mathlib/NumberTheory/NumberField/Units/Basic.lean index eaabbc19a44f8..7907293a0c950 100644 --- a/Mathlib/NumberTheory/NumberField/Units/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Units/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ import Mathlib.NumberTheory.NumberField.Embeddings +import Mathlib.RingTheory.LocalRing.RingHom.Basic /-! # Units of a number field diff --git a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean index 12b15e1ddd7d7..068bff159224a 100644 --- a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean +++ b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean @@ -40,7 +40,7 @@ open scoped NumberField noncomputable section -open NumberField NumberField.InfinitePlace NumberField.Units BigOperators +open NumberField NumberField.InfinitePlace NumberField.Units variable (K : Type*) [Field K] @@ -250,10 +250,6 @@ def seq : ℕ → { x : 𝓞 K // x ≠ 0 } theorem seq_ne_zero (n : ℕ) : algebraMap (𝓞 K) K (seq K w₁ hB n) ≠ 0 := RingOfIntegers.coe_ne_zero_iff.mpr (seq K w₁ hB n).prop -/-- The terms of the sequence have nonzero norm. -/ -theorem seq_norm_ne_zero (n : ℕ) : Algebra.norm ℤ (seq K w₁ hB n : 𝓞 K) ≠ 0 := - Algebra.norm_ne_zero_iff.mpr (Subtype.coe_ne_coe.1 (seq_ne_zero K w₁ hB n)) - /-- The sequence is strictly decreasing at infinite places distinct from `w₁`. -/ theorem seq_decreasing {n m : ℕ} (h : n < m) (w : InfinitePlace K) (hw : w ≠ w₁) : w (algebraMap (𝓞 K) K (seq K w₁ hB m)) < w (algebraMap (𝓞 K) K (seq K w₁ hB n)) := by @@ -301,20 +297,15 @@ theorem exists_unit (w₁ : InfinitePlace K) : _ = w (algebraMap (𝓞 K) K (seq K w₁ hB m) * (algebraMap (𝓞 K) K (seq K w₁ hB n))⁻¹) := by rw [← congr_arg (algebraMap (𝓞 K) K) hu.choose_spec, mul_comm, map_mul (algebraMap _ _), ← mul_assoc, inv_mul_cancel₀ (seq_ne_zero K w₁ hB n), one_mul] - _ = w (algebraMap (𝓞 K) K (seq K w₁ hB m)) * w (algebraMap (𝓞 K) K (seq K w₁ hB n))⁻¹ := - _root_.map_mul _ _ _ - _ < 1 := by - rw [map_inv₀, mul_inv_lt_iff₀ (pos_iff.mpr (seq_ne_zero K w₁ hB n)), one_mul] - exact seq_decreasing K w₁ hB hnm w hw - refine Set.Finite.exists_lt_map_eq_of_forall_mem - (t := { I : Ideal (𝓞 K) | 1 ≤ Ideal.absNorm I ∧ Ideal.absNorm I ≤ B }) - (fun n => ?_) ?_ - · rw [Set.mem_setOf_eq, Ideal.absNorm_span_singleton] - refine ⟨?_, seq_norm_le K w₁ hB n⟩ - exact Nat.one_le_iff_ne_zero.mpr (Int.natAbs_ne_zero.mpr (seq_norm_ne_zero K w₁ hB n)) - · rw [show { I : Ideal (𝓞 K) | 1 ≤ Ideal.absNorm I ∧ Ideal.absNorm I ≤ B } = - (⋃ n ∈ Set.Icc 1 B, { I : Ideal (𝓞 K) | Ideal.absNorm I = n }) by ext; simp] - exact Set.Finite.biUnion (Set.finite_Icc _ _) (fun n hn => Ideal.finite_setOf_absNorm_eq hn.1) + _ = w (algebraMap (𝓞 K) K (seq K w₁ hB m)) * w (algebraMap (𝓞 K) K (seq K w₁ hB n))⁻¹ := + _root_.map_mul _ _ _ + _ < 1 := by + rw [map_inv₀, mul_inv_lt_iff₀' (pos_iff.mpr (seq_ne_zero K w₁ hB n)), mul_one] + exact seq_decreasing K w₁ hB hnm w hw + refine Set.Finite.exists_lt_map_eq_of_forall_mem (t := {I : Ideal (𝓞 K) | Ideal.absNorm I ≤ B}) + (fun n ↦ ?_) (Ideal.finite_setOf_absNorm_le B) + rw [Set.mem_setOf_eq, Ideal.absNorm_span_singleton] + exact seq_norm_le K w₁ hB n theorem unitLattice_span_eq_top : Submodule.span ℝ (unitLattice K : Set ({w : InfinitePlace K // w ≠ w₀} → ℝ)) = ⊤ := by @@ -423,7 +414,7 @@ set_option maxSynthPendingDepth 2 -- Note this is active for the remainder of th def logEmbeddingEquiv : Additive ((𝓞 K)ˣ ⧸ (torsion K)) ≃ₗ[ℤ] (unitLattice K) := LinearEquiv.ofBijective ((logEmbeddingQuot K).codRestrict (unitLattice K) - (Quotient.ind fun x ↦ logEmbeddingQuot_apply K _ ▸ + (Quotient.ind fun _ ↦ logEmbeddingQuot_apply K _ ▸ Submodule.mem_map_of_mem trivial)).toIntLinearMap ⟨fun _ _ ↦ by rw [AddMonoidHom.coe_toIntLinearMap, AddMonoidHom.codRestrict_apply, diff --git a/Mathlib/NumberTheory/NumberField/Units/Regulator.lean b/Mathlib/NumberTheory/NumberField/Units/Regulator.lean index 34d7ce2339491..cd7cb76b5bf07 100644 --- a/Mathlib/NumberTheory/NumberField/Units/Regulator.lean +++ b/Mathlib/NumberTheory/NumberField/Units/Regulator.lean @@ -32,7 +32,7 @@ namespace NumberField.Units variable (K : Type*) [Field K] -open MeasureTheory Classical BigOperators NumberField.InfinitePlace +open MeasureTheory Classical NumberField.InfinitePlace NumberField NumberField.Units.dirichletUnitTheorem variable [NumberField K] diff --git a/Mathlib/NumberTheory/Ostrowski.lean b/Mathlib/NumberTheory/Ostrowski.lean index de32a03798da5..892af836b3bec 100644 --- a/Mathlib/NumberTheory/Ostrowski.lean +++ b/Mathlib/NumberTheory/Ostrowski.lean @@ -7,27 +7,84 @@ Francesco Veneziano -/ import Mathlib.Analysis.Normed.Field.Lemmas -import Mathlib.Analysis.SpecialFunctions.Log.Base -import Mathlib.Analysis.SpecialFunctions.Pow.Real import Mathlib.Analysis.Normed.Ring.Seminorm +import Mathlib.Analysis.SpecialFunctions.Log.Base +import Mathlib.Analysis.SpecialFunctions.Pow.Asymptotics +import Mathlib.Analysis.SpecialFunctions.Pow.Continuity import Mathlib.NumberTheory.Padics.PadicNorm /-! # Ostrowski’s Theorem -The goal of this file is to prove Ostrowski’s Theorem which gives a list of all the nontrivial -absolute values on a number field up to equivalence. (TODO) +Ostrowski's Theorem for the field `ℚ`: every absolute value on `ℚ` is equivalent to either a +`p`-adic absolute value or to the standard Archimedean (Euclidean) absolute value. + +## Main results + +- `mulRingNorm_equiv_standard_or_padic`: given an absolute value on `ℚ`, it is equivalent to the +standard Archimedean (Euclidean) absolute value or to a `p`-adic absolute value for some prime +number `p`. + +## TODO + +Extend to arbitrary number fields. ## References -* [K. Conrad, *Ostroski's Theorem for Q*][conradQ] -* [K. Conrad, *Ostroski for number fields*][conradnumbfield] -* [J. W. S. Cassels, *Local fields*][cassels1986local] +* [K. Conrad, *Ostrowski's Theorem for Q*][conradQ] +* [K. Conrad, *Ostrowski for number fields*][conradnumbfield] +* [J. W. S. Cassels, *Local fields*][cassels1986local] ## Tags -ring_norm, ostrowski + +ring norm, ostrowski -/ +/- ## Preliminary lemmas on limits and lists -/ + + +open Filter Nat Real Topology + +-- For any `C > 0`, the limit of `C ^ (1/k)` is 1 as `k → ∞` +private lemma tendsto_root_atTop_nhds_one {C : ℝ} (hC : 0 < C) : + Tendsto (fun k : ℕ ↦ C ^ (k : ℝ)⁻¹) atTop (𝓝 1) := by + convert_to Tendsto ((fun k ↦ C ^ k) ∘ (fun k : ℝ ↦ k⁻¹) ∘ (Nat.cast)) + atTop (𝓝 1) + exact Tendsto.comp (Continuous.tendsto' (continuous_iff_continuousAt.2 + (fun a ↦ continuousAt_const_rpow hC.ne')) 0 1 (rpow_zero C)) + <| Tendsto.comp tendsto_inv_atTop_zero tendsto_natCast_atTop_atTop + +--extends the lemma `tendsto_rpow_div` when the function has natural input +private lemma tendsto_nat_rpow_div : + Tendsto (fun k : ℕ ↦ (k : ℝ) ^ (k : ℝ)⁻¹) atTop (𝓝 1) := by + convert_to Tendsto ((fun k : ℝ ↦ k ^ k⁻¹) ∘ Nat.cast) atTop (𝓝 1) + apply Tendsto.comp _ tendsto_natCast_atTop_atTop + simp_rw [← one_div] + exact tendsto_rpow_div + +-- Multiplication by a constant moves in a List.sum +private lemma list_mul_sum {R : Type*} [CommSemiring R] {T : Type*} (l : List T) (y : R) : ∀ x : R, + List.sum (List.mapIdx (fun i _ => x * y ^ i) (l)) = + x * List.sum (List.mapIdx (fun i _ => y ^ i) (l)) := by + induction l with + | nil => simp only [List.mapIdx_nil, List.sum_nil, mul_zero, forall_const] + | cons head tail ih => + intro x + simp_rw [List.mapIdx_cons, pow_zero, mul_one, List.sum_cons, mul_add, mul_one] + have (a : ℕ) : y ^ (a + 1) = y * y ^ a := by ring + simp_rw [this, ← mul_assoc, ih, ← mul_assoc] + +-- Geometric sum for lists +private lemma list_geom {T : Type*} {F : Type*} [Field F] (l : List T) {y : F} (hy : y ≠ 1) : + List.sum (List.mapIdx (fun i _ => y ^ i) l) = (y ^ l.length - 1) / (y - 1) := by + induction l with + | nil => simp only [List.mapIdx_nil, List.sum_nil, List.length_nil, pow_zero, sub_self, zero_div] + | cons head tail ih => + simp only [List.mapIdx_cons, pow_zero, List.sum_cons, List.length_cons] + have (a : ℕ ) : y ^ (a + 1) = y * y ^ a := by ring + simp_rw [this, list_mul_sum, ih] + simp only [mul_div, ← same_add_div (sub_ne_zero.2 hy), mul_sub, mul_one, sub_add_sub_cancel'] + namespace Rat.MulRingNorm open Int @@ -53,15 +110,17 @@ lemma equiv_on_nat_iff_equiv : (∃ c : ℝ, 0 < c ∧ (∀ n : ℕ , (f n) ^ c f.equiv g := by refine ⟨fun ⟨c, hc, h⟩ ↦ ⟨c, ⟨hc, ?_⟩⟩, fun ⟨c, hc, h⟩ ↦ ⟨c, ⟨hc, fun n ↦ by rw [← h]⟩⟩⟩ ext x - rw [← Rat.num_div_den x, map_div₀, map_div₀, Real.div_rpow (apply_nonneg f _) - (apply_nonneg f _), h x.den, ← MulRingNorm.apply_natAbs_eq,← MulRingNorm.apply_natAbs_eq, - h (natAbs x.num)] + rw [← Rat.num_div_den x, map_div₀, map_div₀, div_rpow (by positivity) (by positivity), h x.den, + ← MulRingNorm.apply_natAbs_eq,← MulRingNorm.apply_natAbs_eq, h (natAbs x.num)] open Rat.MulRingNorm section Non_archimedean --- ## Non-archimedean case +/-! ## Non-archimedean case + +Every bounded absolute value is equivalent to a `p`-adic absolute value +-/ /-- The mulRingNorm corresponding to the p-adic norm on `ℚ`. -/ def mulRingNorm_padic (p : ℕ) [Fact p.Prime] : MulRingNorm ℚ := @@ -154,7 +213,7 @@ lemma mulRingNorm_eq_one_of_not_dvd {m : ℕ} (hpm : ¬ p ∣ m) : f m = 1 := by exact lt_add_of_le_of_pos (Nat.le_ceil (M.logb (1 / 2))) zero_lt_one _ ≤ x ^ x.logb (1 / 2) := by apply rpow_le_rpow_of_exponent_ge hx0 (le_of_lt hx1) - simp only [one_div, ← log_div_log, Real.log_inv, neg_div, ← div_neg, hM] + simp only [one_div, ← log_div_log, log_inv, neg_div, ← div_neg, hM] gcongr simp only [Left.neg_pos_iff] exact log_neg (lt_sup_iff.2 <| Or.inl hp0) (sup_lt_iff.2 ⟨hp1, hm⟩) @@ -190,7 +249,7 @@ lemma exists_pos_mulRingNorm_eq_pow_neg : ∃ t : ℝ, 0 < t ∧ f p = p ^ (-t) include hf_nontriv bdd in /-- If `f` is bounded and not trivial, then it is equivalent to a p-adic absolute value. -/ theorem mulRingNorm_equiv_padic_of_bounded : - ∃! p, ∃ (hp : Fact (p.Prime)), MulRingNorm.equiv f (mulRingNorm_padic p) := by + ∃! p, ∃ (_ : Fact (p.Prime)), MulRingNorm.equiv f (mulRingNorm_padic p) := by obtain ⟨p, hfp, hmin⟩ := exists_minimal_nat_zero_lt_mulRingNorm_lt_one hf_nontriv bdd have hprime := is_prime_of_minimal_nat_zero_lt_mulRingNorm_lt_one hfp.1 hfp.2 hmin have hprime_fact : Fact (p.Prime) := ⟨hprime⟩ @@ -228,4 +287,237 @@ theorem mulRingNorm_equiv_padic_of_bounded : end Non_archimedean +section Archimedean + +/-! ## Archimedean case + +Every unbounded absolute value is equivalent to the standard absolute value +-/ + +/-- The usual absolute value on ℚ. -/ +def mulRingNorm_real : MulRingNorm ℚ := +{ toFun := fun x : ℚ ↦ |x| + map_zero' := by simp only [Rat.cast_zero, abs_zero] + add_le' := norm_add_le + neg' := norm_neg + eq_zero_of_map_eq_zero' := by simp only [abs_eq_zero, Rat.cast_eq_zero, imp_self, forall_const] + map_one' := by simp only [Rat.cast_one, abs_one] + map_mul' := by + simp only [Rat.cast_mul] + exact_mod_cast abs_mul +} + +@[simp] lemma mul_ring_norm_eq_abs (r : ℚ) : mulRingNorm_real r = |r| := by + simp only [Rat.cast_abs] + rfl + +-- ## Preliminary result + +/-- Given an two integers `n, m` with `m > 1` the mulRingNorm of `n` is bounded by +`m + m * f m + m * (f m) ^ 2 + ... + m * (f m) ^ d` where `d` is the number of digits of the +expansion of `n` in base `m`. -/ +lemma mulRingNorm_apply_le_sum_digits (n : ℕ) {m : ℕ} (hm : 1 < m) : + f n ≤ ((Nat.digits m n).mapIdx fun i _ ↦ m * (f m) ^ i).sum := by + set L := Nat.digits m n + set L' : List ℚ := List.map Nat.cast (L.mapIdx fun i a ↦ (a * m ^ i)) with hL' + -- If `c` is a digit in the expansion of `n` in base `m`, then `f c` is less than `m`. + have hcoef {c : ℕ} (hc : c ∈ Nat.digits m n) : f c < m := + lt_of_le_of_lt (MulRingNorm_nat_le_nat c f) (mod_cast Nat.digits_lt_base hm hc) + calc + f n = f ((Nat.ofDigits m L : ℕ) : ℚ) := by rw [Nat.ofDigits_digits m n] + _ = f (L'.sum) := by rw [Nat.ofDigits_eq_sum_mapIdx]; norm_cast + _ ≤ (L'.map f).sum := mulRingNorm_sum_le_sum_mulRingNorm L' f + _ ≤ (L.mapIdx fun i _ ↦ m * (f m) ^ i).sum := ?_ + simp only [hL', List.mapIdx_eq_enum_map, List.map_map] + apply List.sum_le_sum + rintro ⟨i, a⟩ hia + dsimp [Function.uncurry] + replace hia := List.mem_enumFrom hia + push_cast + rw [map_mul, map_pow] + gcongr + simp only [zero_le, zero_add, tsub_zero, true_and] at hia + exact (hcoef (List.mem_iff_get.mpr ⟨⟨i, hia.1⟩, hia.2.symm⟩)).le + +-- ## Step 1: if f is a MulRingNorm and f n > 1 for some natural n, then f n > 1 for all n ≥ 2 + +/-- If `f n > 1` for some `n` then `f n > 1` for all `n ≥ 2` -/ +lemma one_lt_of_not_bounded (notbdd : ¬ ∀ n : ℕ, f n ≤ 1) {n₀ : ℕ} (hn₀ : 1 < n₀) : 1 < f n₀ := by + contrapose! notbdd with h + intro n + have h_ineq1 {m : ℕ} (hm : 1 ≤ m) : f m ≤ n₀ * (logb n₀ m + 1) := by + /- L is the string of digits of `n` in the base `n₀`-/ + set L := Nat.digits n₀ m + calc + f m ≤ (L.mapIdx fun i _ ↦ n₀ * f n₀ ^ i).sum := mulRingNorm_apply_le_sum_digits m hn₀ + _ ≤ (L.mapIdx fun _ _ ↦ (n₀ : ℝ)).sum := by + simp only [List.mapIdx_eq_enum_map, List.map_map] + apply List.sum_le_sum + rintro ⟨i, a⟩ _ + simp only [Function.comp_apply, Function.uncurry_apply_pair] + exact mul_le_of_le_of_le_one' (mod_cast le_refl n₀) (pow_le_one₀ (by positivity) h) + (by positivity) (by positivity) + _ = n₀ * (Nat.log n₀ m + 1) := by + rw [List.mapIdx_eq_enum_map, List.eq_replicate_of_mem (a := (n₀ : ℝ)) + (l := List.map (Function.uncurry fun _ _ ↦ n₀) (List.enum L)), + List.sum_replicate, List.length_map, List.enum_length, nsmul_eq_mul, mul_comm, + Nat.digits_len n₀ m hn₀ (not_eq_zero_of_lt hm), Nat.cast_add_one] + simp (config := { contextual := true }) + _ ≤ n₀ * (logb n₀ m + 1) := by gcongr; exact natLog_le_logb .. + -- For h_ineq2 we need to exclude the case n = 0. + rcases eq_or_ne n 0 with rfl | h₀ + · simp only [CharP.cast_eq_zero, map_zero, zero_le_one] + have h_ineq2 (k : ℕ) (hk : 0 < k) : + f n ≤ (n₀ * (logb n₀ n + 1)) ^ (k : ℝ)⁻¹ * k ^ (k : ℝ)⁻¹ := by + have : 0 ≤ logb n₀ n := logb_nonneg (one_lt_cast.2 hn₀) (mod_cast Nat.one_le_of_lt h₀.bot_lt) + calc + f n = (f ↑(n ^ k)) ^ (k : ℝ)⁻¹ := by + rw [Nat.cast_pow, map_pow, ← rpow_natCast, rpow_rpow_inv (by positivity) (by positivity)] + _ ≤ (n₀ * (logb n₀ ↑(n ^ k) + 1)) ^ (k : ℝ)⁻¹ := by + gcongr + exact h_ineq1 <| one_le_pow₀ (one_le_iff_ne_zero.mpr h₀) + _ = (n₀ * (k * logb n₀ n + 1)) ^ (k : ℝ)⁻¹ := by + rw [Nat.cast_pow, logb_pow (mod_cast h₀.bot_lt)] + _ ≤ (n₀ * ( k * logb n₀ n + k)) ^ (k : ℝ)⁻¹ := by + gcongr + exact one_le_cast.mpr hk + _ = (n₀ * (logb n₀ n + 1)) ^ (k : ℝ)⁻¹ * k ^ (k : ℝ)⁻¹ := by + rw [← mul_rpow (by positivity) (by positivity), mul_assoc, add_mul, one_mul, + mul_comm _ (k : ℝ)] +-- For 0 < logb n₀ n below we also need to exclude n = 1. + rcases eq_or_ne n 1 with rfl | h₁ + · simp only [Nat.cast_one, map_one, le_refl] + refine le_of_tendsto_of_tendsto tendsto_const_nhds ?_ (eventually_atTop.2 ⟨1, h_ineq2⟩) + nth_rw 2 [← mul_one 1] + have : 0 < logb n₀ n := logb_pos (mod_cast hn₀) (by norm_cast; omega) + have hnlim : Tendsto (fun k : ℕ ↦ (n₀ * (logb n₀ n + 1)) ^ (k : ℝ)⁻¹) atTop (𝓝 1) := + tendsto_root_atTop_nhds_one (by positivity) + exact hnlim.mul tendsto_nat_rpow_div + +-- ## Step 2: given m,n ≥ 2 and |m|=m^s, |n|=n^t for s,t > 0, we have t ≤ s + +variable {m n : ℕ} (hm : 1 < m) (hn : 1 < n) (notbdd : ¬ ∀ (n : ℕ), f n ≤ 1) + +include hm notbdd in +private lemma expr_pos : 0 < m * f m / (f m - 1) := by + apply div_pos (mul_pos (mod_cast zero_lt_of_lt hm) + (map_pos_of_ne_zero f (mod_cast ne_zero_of_lt hm))) + linarith only [one_lt_of_not_bounded notbdd hm] + +include hn hm notbdd in +private lemma param_upperbound {k : ℕ} (hk : k ≠ 0) : + f n ≤ (m * f m / (f m - 1)) ^ (k : ℝ)⁻¹ * (f m) ^ (logb m n) := by + have h_ineq1 {m n : ℕ} (hm : 1 < m) (hn : 1 < n) : + f n ≤ (m * f m / (f m - 1)) * (f m) ^ (logb m n) := by + let d := Nat.log m n + calc + f n ≤ ((Nat.digits m n).mapIdx fun i _ ↦ m * f m ^ i).sum := + mulRingNorm_apply_le_sum_digits n hm + _ = m * ((Nat.digits m n).mapIdx fun i _ ↦ (f m) ^ i).sum := list_mul_sum (m.digits n) (f m) m + _ = m * ((f m ^ (d + 1) - 1) / (f m - 1)) := by + rw [list_geom _ (ne_of_gt (one_lt_of_not_bounded notbdd hm)), + (Nat.digits_len m n hm (not_eq_zero_of_lt hn)).symm] + _ ≤ m * ((f m ^ (d + 1))/(f m - 1)) := by + gcongr + · linarith only [one_lt_of_not_bounded notbdd hm] + · simp only [tsub_le_iff_right, le_add_iff_nonneg_right, zero_le_one] + _ = ↑m * f ↑m / (f ↑m - 1) * f ↑m ^ d := by ring + _ ≤ ↑m * f ↑m / (f ↑m - 1) * f ↑m ^ logb ↑m ↑n := by + gcongr + · exact le_of_lt (expr_pos hm notbdd) + · rw [← Real.rpow_natCast, Real.rpow_le_rpow_left_iff (one_lt_of_not_bounded notbdd hm)] + exact natLog_le_logb n m + apply le_of_pow_le_pow_left hk (mul_nonneg (rpow_nonneg + (le_of_lt (expr_pos hm notbdd)) (k : ℝ)⁻¹) (rpow_nonneg (apply_nonneg f ↑m) (logb m n))) + nth_rw 2 [← Real.rpow_natCast] + rw [mul_rpow (rpow_nonneg (le_of_lt (expr_pos hm notbdd)) (k : ℝ)⁻¹) + (rpow_nonneg (apply_nonneg f ↑m) (logb ↑m ↑n)), ← rpow_mul (le_of_lt (expr_pos hm notbdd)), + ← rpow_mul (apply_nonneg f ↑m), inv_mul_cancel₀ (mod_cast hk), rpow_one, mul_comm (logb ↑m ↑n)] + calc + (f n) ^ k = f ↑(n ^ k) := by simp only [Nat.cast_pow, map_pow] + _ ≤ (m * f m / (f m - 1)) * (f m) ^ (logb m ↑(n ^ k)) := h_ineq1 hm (Nat.one_lt_pow hk hn) + _ = (m * f m / (f m - 1)) * (f m) ^ (k * logb m n) := by + rw [Nat.cast_pow, Real.logb_pow] + exact_mod_cast zero_lt_of_lt hn + +include hm hn notbdd in +/-- Given two natural numbers `n, m` greater than 1 we have `f n ≤ f m ^ logb m n`. -/ +lemma mulRingNorm_le_mulRingNorm_pow_log : f n ≤ f m ^ logb m n := by + have : Tendsto (fun k : ℕ ↦ (m * f m / (f m - 1)) ^ (k : ℝ)⁻¹ * (f m) ^ (logb m n)) + atTop (𝓝 ((f m) ^ (logb m n))) := by + nth_rw 2 [← one_mul (f ↑m ^ logb ↑m ↑n)] + exact Tendsto.mul_const _ (tendsto_root_atTop_nhds_one (expr_pos hm notbdd)) + exact le_of_tendsto_of_tendsto (tendsto_const_nhds (x:= f ↑n)) this ((eventually_atTop.2 ⟨2, + fun b hb ↦ param_upperbound hm hn notbdd (not_eq_zero_of_lt hb)⟩)) + +include hm hn notbdd in +/-- Given `m,n ≥ 2` and `f m = m ^ s`, `f n = n ^ t` for `s, t > 0`, we have `t ≤ s`. -/ +lemma le_of_mulRingNorm_eq {s t : ℝ} (hfm : f m = m ^ s) (hfn : f n = n ^ t) : t ≤ s := by + have hmn : f n ≤ f m ^ Real.logb m n := mulRingNorm_le_mulRingNorm_pow_log hm hn notbdd + rw [← Real.rpow_le_rpow_left_iff (x:=n) (mod_cast hn), ← hfn] + apply le_trans hmn + rw [hfm, ← Real.rpow_mul (Nat.cast_nonneg m), mul_comm, Real.rpow_mul (Nat.cast_nonneg m), + Real.rpow_logb (mod_cast zero_lt_of_lt hm) (mod_cast Nat.ne_of_lt' hm) + (mod_cast zero_lt_of_lt hn)] + +include hm hn notbdd in +private lemma symmetric_roles {s t : ℝ} (hfm : f m = m ^ s) (hfn : f n = n ^ t) : s = t := + le_antisymm (le_of_mulRingNorm_eq hn hm notbdd hfn hfm) + (le_of_mulRingNorm_eq hm hn notbdd hfm hfn) + +-- ## Archimedean case: end goal + +include notbdd in +/-- If `f` is not bounded and not trivial, then it is equivalent to the standard absolute value on +`ℚ`. -/ +theorem mulRingNorm_equiv_standard_of_unbounded : MulRingNorm.equiv f mulRingNorm_real := by + obtain ⟨m, hm⟩ := Classical.exists_not_of_not_forall notbdd + have oneltm : 1 < m := by + by_contra! + apply hm + replace this : m = 0 ∨ m = 1 := by omega + rcases this with (rfl | rfl) + all_goals simp only [CharP.cast_eq_zero, map_zero, zero_le_one, Nat.cast_one, map_one, le_refl] + rw [← equiv_on_nat_iff_equiv] + set s := Real.logb m (f m) with hs + use s⁻¹ + refine ⟨inv_pos.2 (Real.logb_pos (Nat.one_lt_cast.2 oneltm) + (one_lt_of_not_bounded notbdd oneltm)), ?_⟩ + intro n + by_cases h1 : n ≤ 1 + · by_cases h2 : n = 1 + · simp only [h2, Nat.cast_one, map_one, one_rpow, abs_one, cast_one] + · have : n = 0 := by omega + rw [this, hs] + simp only [CharP.cast_eq_zero, map_zero] + rw [Real.rpow_eq_zero le_rfl] + simp only [ne_eq, inv_eq_zero, logb_eq_zero, Nat.cast_eq_zero, Nat.cast_eq_one, map_eq_zero, + not_or] + push_neg + exact ⟨not_eq_zero_of_lt oneltm, Nat.ne_of_lt' oneltm, mod_cast (fun a ↦ a), + not_eq_zero_of_lt oneltm, ne_of_not_le hm, by linarith only [apply_nonneg f ↑m]⟩ + · simp only [mul_ring_norm_eq_abs, abs_cast, Rat.cast_natCast] + rw [Real.rpow_inv_eq (apply_nonneg f ↑n) (Nat.cast_nonneg n) + (Real.logb_ne_zero_of_pos_of_ne_one (one_lt_cast.mpr oneltm) (by linarith only [hm]) + (by linarith only [hm]))] + simp only [not_le] at h1 + have hfm : f m = m ^ s := by rw [Real.rpow_logb (mod_cast zero_lt_of_lt oneltm) + (mod_cast Nat.ne_of_lt' oneltm) (by linarith only [hm])] + have hfn : f n = n ^ (Real.logb n (f n)) := by + rw [Real.rpow_logb (mod_cast zero_lt_of_lt h1) (mod_cast Nat.ne_of_lt' h1) + (by apply map_pos_of_ne_zero; exact_mod_cast not_eq_zero_of_lt h1)] + rwa [← hs, symmetric_roles oneltm h1 notbdd hfm hfn] + +end Archimedean + +/-- **Ostrowski's Theorem** -/ +theorem mulRingNorm_equiv_standard_or_padic (f : MulRingNorm ℚ) (hf_nontriv : f ≠ 1) : + (MulRingNorm.equiv f mulRingNorm_real) ∨ + ∃! p, ∃ (hp : Fact (p.Prime)), MulRingNorm.equiv f (mulRingNorm_padic p) := by + by_cases bdd : ∀ n : ℕ, f n ≤ 1 + · right + exact mulRingNorm_equiv_padic_of_bounded hf_nontriv bdd + · left + exact mulRingNorm_equiv_standard_of_unbounded bdd + end Rat.MulRingNorm diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index 05f97027ce268..614c690370a02 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -227,7 +227,7 @@ private def ih_n {n : ℕ} {z : ℤ_[p]} (hz : ih n z) : { z' : ℤ_[p] // ih (n rw [sub_eq_add_neg, ← hz.1, ← norm_neg (F.derivative.eval z)] at hdist have := PadicInt.norm_eq_of_norm_add_lt_right hdist rwa [norm_neg, hz.1] at this - let ⟨q, heq⟩ := calc_eval_z' hnorm rfl hz h1 rfl + let ⟨_, heq⟩ := calc_eval_z' hnorm rfl hz h1 rfl have hnle : ‖F.eval z'‖ ≤ ‖F.derivative.eval a‖ ^ 2 * T ^ 2 ^ (n + 1) := calc_eval_z'_norm hz heq h1 rfl ⟨hfeq, hnle⟩⟩ diff --git a/Mathlib/NumberTheory/Padics/PadicIntegers.lean b/Mathlib/NumberTheory/Padics/PadicIntegers.lean index 06fae1357239d..798a8c9d36b41 100644 --- a/Mathlib/NumberTheory/Padics/PadicIntegers.lean +++ b/Mathlib/NumberTheory/Padics/PadicIntegers.lean @@ -304,7 +304,7 @@ variable (p : ℕ) [hp : Fact p.Prime] theorem exists_pow_neg_lt {ε : ℝ} (hε : 0 < ε) : ∃ k : ℕ, (p : ℝ) ^ (-(k : ℤ)) < ε := by obtain ⟨k, hk⟩ := exists_nat_gt ε⁻¹ use k - rw [← inv_lt_inv hε (_root_.zpow_pos_of_pos _ _)] + rw [← inv_lt_inv₀ hε (zpow_pos _ _)] · rw [zpow_neg, inv_inv, zpow_natCast] apply lt_of_lt_of_le hk norm_cast @@ -356,7 +356,7 @@ theorem valuation_nonneg (x : ℤ_[p]) : 0 ≤ x.valuation := by by_cases hx : x = 0 · simp [hx] have h : (1 : ℝ) < p := mod_cast hp.1.one_lt - rw [← neg_nonpos, ← (zpow_strictMono h).le_iff_le] + rw [← neg_nonpos, ← (zpow_right_strictMono₀ h).le_iff_le] show (p : ℝ) ^ (-valuation x) ≤ (p : ℝ) ^ (0 : ℤ) rw [← norm_eq_pow_val hx] simpa using x.property @@ -373,7 +373,7 @@ theorem valuation_p_pow_mul (n : ℕ) (c : ℤ_[p]) (hc : c ≠ 0) : exact_mod_cast pow_eq_zero hc · exact hc rwa [norm_eq_pow_val aux, norm_p_pow, norm_eq_pow_val hc, ← zpow_add₀, ← neg_add, - zpow_inj, neg_inj] at this + zpow_right_inj₀, neg_inj] at this · exact mod_cast hp.1.pos · exact mod_cast hp.1.ne_one · exact mod_cast hp.1.ne_zero @@ -433,8 +433,7 @@ See `unitCoeff_spec`. -/ def unitCoeff {x : ℤ_[p]} (hx : x ≠ 0) : ℤ_[p]ˣ := let u : ℚ_[p] := x * (p : ℚ_[p]) ^ (-x.valuation) have hu : ‖u‖ = 1 := by - simp [u, hx, Nat.zpow_ne_zero_of_pos (mod_cast hp.1.pos) x.valuation, norm_eq_pow_val, - zpow_neg, inv_mul_cancel] + simp [u, hx, zpow_ne_zero (G₀ := ℝ) _ (Nat.cast_ne_zero.2 hp.1.pos.ne'), norm_eq_pow_val] mkUnits hu @[simp] @@ -468,7 +467,7 @@ theorem norm_le_pow_iff_le_valuation (x : ℤ_[p]) (hx : x ≠ 0) (n : ℕ) : intro m refine pow_pos ?_ m exact mod_cast hp.1.pos - rw [inv_le_inv (aux _) (aux _)] + rw [inv_le_inv₀ (aux _) (aux _)] have : p ^ n ≤ p ^ k ↔ n ≤ k := (pow_right_strictMono hp.1.one_lt).le_iff_le rw [← this] norm_cast @@ -528,7 +527,7 @@ instance : LocalRing ℤ_[p] := LocalRing.of_nonunits_add <| by simp only [mem_nonunits]; exact fun x y => norm_lt_one_add theorem p_nonnunit : (p : ℤ_[p]) ∈ nonunits ℤ_[p] := by - have : (p : ℝ)⁻¹ < 1 := inv_lt_one <| mod_cast hp.1.one_lt + have : (p : ℝ)⁻¹ < 1 := inv_lt_one_of_one_lt₀ <| mod_cast hp.1.one_lt rwa [← norm_p, ← mem_nonunits] at this theorem maximalIdeal_eq_span_p : maximalIdeal ℤ_[p] = Ideal.span {(p : ℤ_[p])} := by @@ -569,7 +568,7 @@ instance : IsAdicComplete (maximalIdeal ℤ_[p]) ℤ_[p] where exact hx hn · refine ⟨x'.lim, fun n => ?_⟩ have : (0 : ℝ) < (p : ℝ) ^ (-n : ℤ) := by - apply zpow_pos_of_pos + apply zpow_pos exact mod_cast hp.1.pos obtain ⟨i, hi⟩ := equiv_def₃ (equiv_lim x') this by_cases hin : i ≤ n diff --git a/Mathlib/NumberTheory/Padics/PadicNorm.lean b/Mathlib/NumberTheory/Padics/PadicNorm.lean index 9a46b58826307..a50570c41e9f1 100644 --- a/Mathlib/NumberTheory/Padics/PadicNorm.lean +++ b/Mathlib/NumberTheory/Padics/PadicNorm.lean @@ -3,7 +3,6 @@ Copyright (c) 2018 Robert Y. Lewis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis -/ -import Mathlib.Algebra.Order.Field.Power import Mathlib.NumberTheory.Padics.PadicVal.Basic /-! @@ -65,7 +64,6 @@ protected theorem nonneg (q : ℚ) : 0 ≤ padicNorm p q := protected theorem zero : padicNorm p 0 = 0 := by simp [padicNorm] /-- The `p`-adic norm of `1` is `1`. -/ --- @[simp] -- Porting note (#10618): simp can prove this protected theorem one : padicNorm p 1 = 1 := by simp [padicNorm] /-- The `p`-adic norm of `p` is `p⁻¹` if `p > 1`. @@ -92,7 +90,7 @@ theorem padicNorm_of_prime_of_ne {q : ℕ} [p_prime : Fact p.Prime] [q_prime : F See also `padicNorm.padicNorm_p_lt_one_of_prime` for a version assuming `p` is prime. -/ theorem padicNorm_p_lt_one (hp : 1 < p) : padicNorm p p < 1 := by - rw [padicNorm_p hp, inv_lt_one_iff] + rw [padicNorm_p hp, inv_lt_one_iff₀] exact mod_cast Or.inr hp /-- The `p`-adic norm of `p` is less than `1` if `p` is prime. @@ -143,17 +141,11 @@ protected theorem div (q r : ℚ) : padicNorm p (q / r) = padicNorm p q / padicN else eq_div_of_mul_eq (padicNorm.nonzero hr) (by rw [← padicNorm.mul, div_mul_cancel₀ _ hr]) /-- The `p`-adic norm of an integer is at most `1`. -/ -protected theorem of_int (z : ℤ) : padicNorm p z ≤ 1 := - if hz : z = 0 then by simp [hz, zero_le_one] - else by - unfold padicNorm - rw [if_neg _] - · refine zpow_le_one_of_nonpos ?_ ?_ - · exact mod_cast le_of_lt hp.1.one_lt - · rw [padicValRat.of_int, neg_nonpos] - norm_cast - simp - exact mod_cast hz +protected theorem of_int (z : ℤ) : padicNorm p z ≤ 1 := by + obtain rfl | hz := eq_or_ne z 0 + · simp + · rw [padicNorm, if_neg (mod_cast hz)] + exact zpow_le_one_of_nonpos₀ (mod_cast hp.1.one_le) (by simp) private theorem nonarchimedean_aux {q r : ℚ} (h : padicValRat p q ≤ padicValRat p r) : padicNorm p (q + r) ≤ max (padicNorm p q) (padicNorm p r) := @@ -168,7 +160,7 @@ private theorem nonarchimedean_aux {q r : ℚ} (h : padicValRat p q ≤ padicVal unfold padicNorm; split_ifs apply le_max_iff.2 left - apply zpow_le_of_le + apply zpow_le_zpow_right₀ · exact mod_cast le_of_lt hp.1.one_lt · apply neg_le_neg have : padicValRat p q = min (padicValRat p q) (padicValRat p r) := (min_eq_left h).symm @@ -232,13 +224,14 @@ theorem dvd_iff_norm_le {n : ℕ} {z : ℤ} : ↑(p ^ n) ∣ z ↔ padicNorm p z unfold padicNorm; split_ifs with hz · norm_cast at hz simp [hz] - · rw [zpow_le_iff_le, neg_le_neg_iff, padicValRat.of_int, + · 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 [← PartENat.coe_le_coe, PartENat.natCast_get, ← multiplicity.pow_dvd_iff_le_multiplicity, - Nat.cast_pow] - exact mod_cast hz - · exact mod_cast hp.1.one_lt + rw [← multiplicity.Finite.pow_dvd_iff_le_multiplicity] + · norm_cast + · apply Int.multiplicity_finite_iff.2 ⟨by simp [hp.out.ne_one], mod_cast hz⟩ + · exact_mod_cast hz + · exact_mod_cast hp.out.one_lt /-- The `p`-adic norm of an integer `m` is one iff `p` doesn't divide `m`. -/ theorem int_eq_one_iff (m : ℤ) : padicNorm p m = 1 ↔ ¬(p : ℤ) ∣ m := by @@ -246,7 +239,7 @@ theorem int_eq_one_iff (m : ℤ) : padicNorm p m = 1 ↔ ¬(p : ℤ) ∣ m := by simp only [dvd_iff_norm_le, Int.cast_natCast, Nat.cast_one, zpow_neg, zpow_one, not_le] constructor · intro h - rw [h, inv_lt_one_iff_of_pos] <;> norm_cast + rw [h, inv_lt_one₀] <;> norm_cast · exact Nat.Prime.one_lt Fact.out · exact Nat.Prime.pos Fact.out · simp only [padicNorm] @@ -255,10 +248,10 @@ theorem int_eq_one_iff (m : ℤ) : padicNorm p m = 1 ↔ ¬(p : ℤ) ∣ m := by intro h exact (Nat.not_lt_zero p h).elim · have : 1 < (p : ℚ) := by norm_cast; exact Nat.Prime.one_lt (Fact.out : Nat.Prime p) - rw [← zpow_neg_one, zpow_lt_iff_lt this] + rw [← zpow_neg_one, zpow_lt_zpow_iff_right₀ this] have : 0 ≤ padicValRat p m := by simp only [of_int, Nat.cast_nonneg] intro h - rw [← zpow_zero (p : ℚ), zpow_inj] <;> linarith + rw [← zpow_zero (p : ℚ), zpow_right_inj₀] <;> linarith theorem int_lt_one_iff (m : ℤ) : padicNorm p m < 1 ↔ (p : ℤ) ∣ m := by rw [← not_iff_not, ← int_eq_one_iff, eq_iff_le_not_lt] diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index abccff73fbb92..d86fe1b155206 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -211,7 +211,7 @@ theorem norm_eq_pow_val {f : PadicSeq p} (hf : ¬f ≈ 0) : f.norm = (p : ℚ) ^ theorem val_eq_iff_norm_eq {f g : PadicSeq p} (hf : ¬f ≈ 0) (hg : ¬g ≈ 0) : f.valuation = g.valuation ↔ f.norm = g.norm := by - rw [norm_eq_pow_val hf, norm_eq_pow_val hg, ← neg_inj, zpow_inj] + rw [norm_eq_pow_val hf, norm_eq_pow_val hg, ← neg_inj, zpow_right_inj₀] · exact mod_cast (Fact.out : p.Prime).pos · exact mod_cast (Fact.out : p.Prime).ne_one @@ -779,8 +779,7 @@ theorem norm_p : ‖(p : ℚ_[p])‖ = (p : ℝ)⁻¹ := by theorem norm_p_lt_one : ‖(p : ℚ_[p])‖ < 1 := by rw [norm_p] - apply inv_lt_one - exact mod_cast hp.1.one_lt + exact inv_lt_one_of_one_lt₀ <| mod_cast hp.1.one_lt -- Porting note: Linter thinks this is a duplicate simp lemma, so `priority` is assigned @[simp (high)] @@ -833,7 +832,7 @@ theorem norm_rat_le_one : ∀ {q : ℚ} (_ : ¬p ∣ q.den), ‖(q : ℚ_[p])‖ -- Porting note: `Nat.cast_zero` instead of another `norm_cast` call rw [padicNorm.eq_zpow_of_nonzero hnz', padicValRat, neg_sub, padicValNat.eq_zero_of_not_dvd hq, Nat.cast_zero, zero_sub, zpow_neg, zpow_natCast] - apply inv_le_one + apply inv_le_one_of_one_le₀ norm_cast apply one_le_pow exact hp.1.pos @@ -860,8 +859,7 @@ theorem norm_int_lt_one_iff_dvd (k : ℤ) : ‖(k : ℚ_[p])‖ < 1 ↔ ↑p ∣ mul_le_mul le_rfl (by simpa using norm_int_le_one _) (norm_nonneg _) (norm_nonneg _) _ < 1 := by rw [mul_one, padicNormE.norm_p] - apply inv_lt_one - exact mod_cast hp.1.one_lt + exact inv_lt_one_of_one_lt₀ <| mod_cast hp.1.one_lt theorem norm_int_le_pow_iff_dvd (k : ℤ) (n : ℕ) : ‖(k : ℚ_[p])‖ ≤ (p : ℝ) ^ (-n : ℤ) ↔ (p ^ n : ℤ) ∣ k := by @@ -947,16 +945,6 @@ def valuation : ℚ_[p] → ℤ := theorem valuation_zero : valuation (0 : ℚ_[p]) = 0 := dif_pos ((const_equiv p).2 rfl) -@[simp] -theorem valuation_one : valuation (1 : ℚ_[p]) = 0 := by - classical - change dite (CauSeq.const (padicNorm p) 1 ≈ _) _ _ = _ - have h : ¬CauSeq.const (padicNorm p) 1 ≈ 0 := by - rw [← const_zero, const_equiv p] - exact one_ne_zero - rw [dif_neg h] - simp - theorem norm_eq_pow_val {x : ℚ_[p]} : x ≠ 0 → ‖x‖ = (p : ℝ) ^ (-x.valuation) := by refine Quotient.inductionOn' x fun f hf => ?_ change (PadicSeq.norm _ : ℝ) = (p : ℝ) ^ (-PadicSeq.valuation _) @@ -971,26 +959,45 @@ theorem norm_eq_pow_val {x : ℚ_[p]} : x ≠ 0 → ‖x‖ = (p : ℝ) ^ (-x.va simpa using hf' @[simp] -theorem valuation_p : valuation (p : ℚ_[p]) = 1 := by - have h : (1 : ℝ) < p := mod_cast (Fact.out : p.Prime).one_lt - refine neg_injective ((zpow_strictMono h).injective <| (norm_eq_pow_val ?_).symm.trans ?_) - · exact mod_cast (Fact.out : p.Prime).ne_zero - · simp +lemma valuation_ratCast (q : ℚ) : valuation (q : ℚ_[p]) = padicValRat p q := by + rcases eq_or_ne q 0 with rfl | hq + · simp only [Rat.cast_zero, valuation_zero, padicValRat.zero] + refine neg_injective ((zpow_right_strictMono₀ (mod_cast hp.out.one_lt)).injective + <| (norm_eq_pow_val (mod_cast hq)).symm.trans ?_) + rw [padicNormE.eq_padicNorm, ← Rat.cast_natCast, ← Rat.cast_zpow, Rat.cast_inj] + exact padicNorm.eq_zpow_of_nonzero hq + +@[simp] +lemma valuation_intCast (n : ℤ) : valuation (n : ℚ_[p]) = padicValInt p n := by + rw [← Rat.cast_intCast, valuation_ratCast, padicValRat.of_int] + +@[simp] +lemma valuation_natCast (n : ℕ) : valuation (n : ℚ_[p]) = padicValNat p n := by + rw [← Rat.cast_natCast, valuation_ratCast, padicValRat.of_nat] + +-- See note [no_index around OfNat.ofNat] +@[simp] +lemma valuation_ofNat (n : ℕ) [n.AtLeastTwo] : + valuation (no_index (OfNat.ofNat n : ℚ_[p])) = padicValNat p n := + valuation_natCast n + +@[simp] +lemma valuation_one : valuation (1 : ℚ_[p]) = 0 := by + rw [← Nat.cast_one, valuation_natCast, padicValNat.one, cast_zero] + +-- not @[simp], since simp can prove it +lemma valuation_p : valuation (p : ℚ_[p]) = 1 := by + rw [valuation_natCast, padicValNat_self, cast_one] theorem valuation_map_add {x y : ℚ_[p]} (hxy : x + y ≠ 0) : min (valuation x) (valuation y) ≤ valuation (x + y : ℚ_[p]) := by by_cases hx : x = 0 - · rw [hx, zero_add] - exact min_le_right _ _ - · by_cases hy : y = 0 - · rw [hy, add_zero] - exact min_le_left _ _ - · have h_norm : ‖x + y‖ ≤ max ‖x‖ ‖y‖ := padicNormE.nonarchimedean x y - have hp_one : (1 : ℝ) < p := by - rw [← Nat.cast_one, Nat.cast_lt] - exact Nat.Prime.one_lt hp.elim - rwa [norm_eq_pow_val hx, norm_eq_pow_val hy, norm_eq_pow_val hxy, - zpow_le_max_iff_min_le hp_one] at h_norm + · simpa only [hx, zero_add] using min_le_right _ _ + by_cases hy : y = 0 + · simpa only [hy, add_zero] using min_le_left _ _ + have : ‖x + y‖ ≤ max ‖x‖ ‖y‖ := padicNormE.nonarchimedean x y + simpa only [norm_eq_pow_val hxy, norm_eq_pow_val hx, norm_eq_pow_val hy, le_max_iff, + zpow_le_zpow_iff_right₀ (mod_cast hp.out.one_lt : 1 < (p : ℝ)), neg_le_neg_iff, ← min_le_iff] @[simp] theorem valuation_map_mul {x y : ℚ_[p]} (hx : x ≠ 0) (hy : y ≠ 0) : @@ -1003,7 +1010,7 @@ theorem valuation_map_mul {x y : ℚ_[p]} (hx : x ≠ 0) (hy : y ≠ 0) : rw [← Nat.cast_zero, Nat.cast_lt] exact Nat.Prime.pos hp.elim rw [norm_eq_pow_val hx, norm_eq_pow_val hy, norm_eq_pow_val (mul_ne_zero hx hy), ← - zpow_add₀ (ne_of_gt hp_pos), zpow_inj hp_pos hp_ne_one, ← neg_add, neg_inj] at h_norm + zpow_add₀ (ne_of_gt hp_pos), zpow_right_inj₀ hp_pos hp_ne_one, ← neg_add, neg_inj] at h_norm exact h_norm open Classical in @@ -1061,14 +1068,12 @@ section NormLEIff theorem norm_le_pow_iff_norm_lt_pow_add_one (x : ℚ_[p]) (n : ℤ) : ‖x‖ ≤ (p : ℝ) ^ n ↔ ‖x‖ < (p : ℝ) ^ (n + 1) := by - have aux : ∀ n : ℤ, 0 < ((p : ℝ) ^ n) := by - apply Nat.zpow_pos_of_pos - exact hp.1.pos + have aux (n : ℤ) : 0 < ((p : ℝ) ^ n) := zpow_pos (mod_cast hp.1.pos) _ by_cases hx0 : x = 0 · simp [hx0, norm_zero, aux, le_of_lt (aux _)] rw [norm_eq_pow_val hx0] have h1p : 1 < (p : ℝ) := mod_cast hp.1.one_lt - have H := zpow_strictMono h1p + have H := zpow_right_strictMono₀ h1p rw [H.le_iff_le, H.lt_iff_lt, Int.lt_add_one_iff] theorem norm_lt_pow_iff_norm_le_pow_sub_one (x : ℚ_[p]) (n : ℤ) : @@ -1078,7 +1083,7 @@ theorem norm_lt_pow_iff_norm_le_pow_sub_one (x : ℚ_[p]) (n : ℤ) : theorem norm_le_one_iff_val_nonneg (x : ℚ_[p]) : ‖x‖ ≤ 1 ↔ 0 ≤ x.valuation := by by_cases hx : x = 0 · simp only [hx, norm_zero, valuation_zero, zero_le_one, le_refl] - · rw [norm_eq_pow_val hx, ← zpow_zero (p : ℝ), zpow_le_iff_le, Right.neg_nonpos_iff] + · rw [norm_eq_pow_val hx, ← zpow_zero (p : ℝ), zpow_le_zpow_iff_right₀, Right.neg_nonpos_iff] exact Nat.one_lt_cast.2 (Nat.Prime.one_lt' p).1 end NormLEIff diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean index a50d9d73886f6..d2df11023e6f1 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.NumberTheory.Divisors import Mathlib.NumberTheory.Padics.PadicVal.Defs import Mathlib.Data.Nat.MaxPowDiv import Mathlib.Data.Nat.Multiplicity +import Mathlib.Data.Nat.Prime.Int /-! # `p`-adic Valuation @@ -76,34 +77,31 @@ variable {p : ℕ} /-- If `p ≠ 0` and `p ≠ 1`, then `padicValNat p p` is `1`. -/ @[simp] theorem self (hp : 1 < p) : padicValNat p p = 1 := by - have neq_one : ¬p = 1 ↔ True := iff_of_true hp.ne' trivial - have eq_zero_false : p = 0 ↔ False := iff_false_intro (zero_lt_one.trans hp).ne' - simp [padicValNat, neq_one, eq_zero_false] + simp [padicValNat_def', zero_lt_one.trans hp, hp.ne'] theorem eq_zero_of_not_dvd {n : ℕ} (h : ¬p ∣ n) : padicValNat p n = 0 := eq_zero_iff.2 <| Or.inr <| Or.inr h open Nat.maxPowDiv -theorem maxPowDiv_eq_multiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) : - p.maxPowDiv n = multiplicity p n := by - apply multiplicity.unique <| pow_dvd p n +theorem maxPowDiv_eq_emultiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) : + p.maxPowDiv n = emultiplicity p n := by + apply (emultiplicity_eq_of_dvd_of_not_dvd (pow_dvd p n) _).symm intro h apply Nat.not_lt.mpr <| le_of_dvd hp hn h simp -theorem maxPowDiv_eq_multiplicity_get {p n : ℕ} (hp : 1 < p) (hn : 0 < n) (h : Finite p n) : - p.maxPowDiv n = (multiplicity p n).get h := by - rw [PartENat.get_eq_iff_eq_coe.mpr] - apply maxPowDiv_eq_multiplicity hp hn|>.symm +theorem maxPowDiv_eq_multiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) (h : Finite p n) : + p.maxPowDiv n = multiplicity p n := by + exact_mod_cast h.emultiplicity_eq_multiplicity ▸ maxPowDiv_eq_emultiplicity hp hn /-- Allows for more efficient code for `padicValNat` -/ @[csimp] theorem padicValNat_eq_maxPowDiv : @padicValNat = @maxPowDiv := by ext p n by_cases h : 1 < p ∧ 0 < n - · dsimp [padicValNat] - rw [dif_pos ⟨Nat.ne_of_gt h.1,h.2⟩, maxPowDiv_eq_multiplicity_get h.1 h.2] + · 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⟩ · simp only [not_and_or,not_gt_eq,Nat.le_zero] at h apply h.elim · intro h @@ -128,13 +126,9 @@ open multiplicity variable {p : ℕ} theorem of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : - padicValInt p z = - (multiplicity (p : ℤ) z).get - (by - apply multiplicity.finite_int_iff.2 - simp [hp, hz]) := by - rw [padicValInt, padicValNat, dif_pos (And.intro hp (Int.natAbs_pos.mpr hz))] - simp only [multiplicity.Int.natAbs p z] + padicValInt p z = multiplicity (p : ℤ) z:= by + rw [padicValInt, padicValNat_def' hp (Int.natAbs_pos.mpr hz)] + apply Int.multiplicity_natAbs /-- `padicValInt p 0` is `0` for any `p`. -/ @[simp] @@ -152,8 +146,9 @@ theorem of_nat {n : ℕ} : padicValInt p n = padicValNat p n := by simp [padicVa theorem self (hp : 1 < p) : padicValInt p p = 1 := by simp [padicValNat.self hp] theorem eq_zero_of_not_dvd {z : ℤ} (h : ¬(p : ℤ) ∣ z) : padicValInt p z = 0 := by - rw [padicValInt, padicValNat] - split_ifs <;> simp [multiplicity.Int.natAbs, multiplicity_eq_zero.2 h] + rw [padicValInt, padicValNat.eq_zero_iff] + right; right + rwa [← Int.ofNat_dvd_left] end padicValInt @@ -191,19 +186,13 @@ theorem of_int {z : ℤ} : padicValRat p z = padicValInt p z := by simp [padicVa /-- The `p`-adic value of an integer `z ≠ 0` is the multiplicity of `p` in `z`. -/ theorem of_int_multiplicity {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : - padicValRat p (z : ℚ) = (multiplicity (p : ℤ) z).get (finite_int_iff.2 ⟨hp, hz⟩) := by + padicValRat p (z : ℚ) = multiplicity (p : ℤ) z := by rw [of_int, padicValInt.of_ne_one_ne_zero hp hz] theorem multiplicity_sub_multiplicity {q : ℚ} (hp : p ≠ 1) (hq : q ≠ 0) : - padicValRat p q = - (multiplicity (p : ℤ) q.num).get (finite_int_iff.2 ⟨hp, Rat.num_ne_zero.2 hq⟩) - - (multiplicity p q.den).get - (by - rw [← finite_iff_dom, finite_nat_iff] - exact ⟨hp, q.pos⟩) := by - rw [padicValRat, padicValInt.of_ne_one_ne_zero hp, padicValNat, dif_pos] - · exact ⟨hp, q.pos⟩ - · exact Rat.num_ne_zero.2 hq + padicValRat p q = multiplicity (p : ℤ) q.num - multiplicity p q.den := by + rw [padicValRat, padicValInt.of_ne_one_ne_zero hp (Rat.num_ne_zero.2 hq), + padicValNat_def' hp q.pos] /-- The `p`-adic value of an integer `z ≠ 0` is its `p`-adic value as a rational. -/ @[simp] @@ -231,8 +220,8 @@ theorem padicValNat_self [Fact p.Prime] : padicValNat p p = 1 := by theorem one_le_padicValNat_of_dvd {n : ℕ} [hp : Fact p.Prime] (hn : 0 < n) (div : p ∣ n) : 1 ≤ padicValNat p n := by - rwa [← PartENat.coe_le_coe, padicValNat_def' hp.out.ne_one hn, ← pow_dvd_iff_le_multiplicity, - pow_one] + rwa [← WithTop.coe_le_coe, ENat.some_eq_coe, padicValNat_eq_emultiplicity hn, + ← pow_dvd_iff_le_emultiplicity, pow_one] theorem dvd_iff_padicValNat_ne_zero {p n : ℕ} [Fact p.Prime] (hn0 : n ≠ 0) : p ∣ n ↔ padicValNat p n ≠ 0 := @@ -249,28 +238,23 @@ 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 [finite_int_iff, hp.1.ne_one] + simp [Int.multiplicity_finite_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) (qdf : q = n /. d) : - padicValRat p q = - (multiplicity (p : ℤ) n).get - (finite_int_iff.2 ⟨hp.1.ne_one, fun hn => by simp_all⟩) - - (multiplicity (p : ℤ) d).get - (finite_int_iff.2 ⟨hp.1.ne_one, fun hd => by simp_all⟩) := by + padicValRat p q = multiplicity (p : ℤ) n - multiplicity (p : ℤ) d := by have hd : d ≠ 0 := Rat.mk_denom_ne_zero_of_ne_zero hqz qdf let ⟨c, hc1, hc2⟩ := Rat.num_den_mk hd qdf rw [padicValRat.multiplicity_sub_multiplicity hp.1.ne_one hqz] simp only [Nat.isUnit_iff, hc1, hc2] - rw [multiplicity.mul' (Nat.prime_iff_prime_int.1 hp.1), - multiplicity.mul' (Nat.prime_iff_prime_int.1 hp.1)] - rw [Nat.cast_add, Nat.cast_add] - simp_rw [Int.natCast_multiplicity p q.den] - ring - -- Porting note: was - -- simp only [hc1, hc2, multiplicity.mul' (Nat.prime_iff_prime_int.1 hp.1), - -- hp.1.ne_one, hqz, pos_iff_ne_zero, Int.natCast_multiplicity p q.den + rw [multiplicity_mul (Nat.prime_iff_prime_int.1 hp.1), + multiplicity_mul (Nat.prime_iff_prime_int.1 hp.1)] + · rw [Nat.cast_add, Nat.cast_add] + simp_rw [Int.natCast_multiplicity p q.den] + ring + · simpa [finite_int_prime_iff, hc2] using hd + · simpa [finite_int_prime_iff, hqz, hc2] using hd /-- A rewrite lemma for `padicValRat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ protected theorem mul {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : @@ -283,10 +267,10 @@ protected theorem mul {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : rw [padicValRat.defn p (mul_ne_zero hq hr) this] conv_rhs => rw [← q.num_divInt_den, padicValRat.defn p hq', ← r.num_divInt_den, padicValRat.defn p hr'] - rw [multiplicity.mul' hp', multiplicity.mul' hp', Nat.cast_add, Nat.cast_add] - ring - -- Porting note: was - -- simp [add_comm, add_left_comm, sub_eq_add_neg] + rw [multiplicity_mul hp', multiplicity_mul hp', Nat.cast_add, Nat.cast_add] + · ring + · simp [finite_int_prime_iff] + · simp [finite_int_prime_iff, hq, hr] /-- A rewrite lemma for `padicValRat p (q^k)` with condition `q ≠ 0`. -/ protected theorem pow {q : ℚ} (hq : q ≠ 0) {k : ℕ} : @@ -320,9 +304,9 @@ theorem padicValRat_le_padicValRat_iff {n₁ n₂ d₁ d₂ : ℤ} (hn₁ : n₁ padicValRat.defn p (Rat.divInt_ne_zero_of_ne_zero hn₂ hd₂) rfl, sub_le_iff_le_add', ← add_sub_assoc, _root_.le_sub_iff_add_le] norm_cast - rw [← multiplicity.mul' (Nat.prime_iff_prime_int.1 hp.1) hf1, add_comm, ← - multiplicity.mul' (Nat.prime_iff_prime_int.1 hp.1) hf2, PartENat.get_le_get, - multiplicity_le_multiplicity_iff] + rw [← multiplicity_mul (Nat.prime_iff_prime_int.1 hp.1) hf1, add_comm, + ← multiplicity_mul (Nat.prime_iff_prime_int.1 hp.1) hf2, + hf1.multiplicity_le_multiplicity_iff hf2] /-- Sufficient conditions to show that the `p`-adic valuation of `q` is less than or equal to the `p`-adic valuation of `q + r`. -/ @@ -340,22 +324,21 @@ theorem le_padicValRat_add_of_le {q r : ℚ} (hqr : q + r ≠ 0) have hqrd : q.num * r.den + q.den * r.num ≠ 0 := Rat.mk_num_ne_zero_of_ne_zero hqr hqreq conv_lhs => rw [← q.num_divInt_den] rw [hqreq, padicValRat_le_padicValRat_iff hqn hqrd hqd (mul_ne_zero hqd hrd), ← - multiplicity_le_multiplicity_iff, mul_left_comm, - multiplicity.mul (Nat.prime_iff_prime_int.1 hp.1), add_mul] + emultiplicity_le_emultiplicity_iff, mul_left_comm, + emultiplicity_mul (Nat.prime_iff_prime_int.1 hp.1), add_mul] rw [← q.num_divInt_den, ← r.num_divInt_den, padicValRat_le_padicValRat_iff hqn hrn hqd hrd, ← - multiplicity_le_multiplicity_iff] at h + emultiplicity_le_emultiplicity_iff] at h calc _ ≤ - min (multiplicity (↑p) (q.num * r.den * q.den)) - (multiplicity (↑p) (↑q.den * r.num * ↑q.den)) := + min (emultiplicity (↑p) (q.num * r.den * q.den)) + (emultiplicity (↑p) (↑q.den * r.num * ↑q.den)) := le_min - (by rw [@multiplicity.mul _ _ _ _ (_ * _) _ (Nat.prime_iff_prime_int.1 hp.1), add_comm]) + (by rw [emultiplicity_mul (a :=_ * _) (Nat.prime_iff_prime_int.1 hp.1), add_comm]) (by rw [mul_assoc, - @multiplicity.mul _ _ _ _ (q.den : ℤ) (_ * _) - (Nat.prime_iff_prime_int.1 hp.1)] + emultiplicity_mul (b := _ * _) (Nat.prime_iff_prime_int.1 hp.1)] exact add_le_add_left h _) - _ ≤ _ := min_le_multiplicity_add + _ ≤ _ := min_le_emultiplicity_add /-- The minimum of the valuations of `q` and `r` is at most the valuation of `q + r`. -/ theorem min_le_padicValRat_add {q r : ℚ} (hqr : q + r ≠ 0) : @@ -476,11 +459,13 @@ theorem dvd_of_one_le_padicValNat {n : ℕ} (hp : 1 ≤ padicValNat p n) : p ∣ theorem pow_padicValNat_dvd {n : ℕ} : p ^ padicValNat p n ∣ n := by rcases n.eq_zero_or_pos with (rfl | hn); · simp rcases eq_or_ne p 1 with (rfl | hp); · simp - rw [multiplicity.pow_dvd_iff_le_multiplicity, padicValNat_def'] <;> assumption + apply pow_dvd_of_le_multiplicity + rw [padicValNat_def'] <;> assumption theorem padicValNat_dvd_iff_le [hp : Fact p.Prime] {a n : ℕ} (ha : a ≠ 0) : p ^ n ∣ a ↔ n ≤ padicValNat p a := by - rw [pow_dvd_iff_le_multiplicity, ← padicValNat_def' hp.out.ne_one ha.bot_lt, PartENat.coe_le_coe] + rw [pow_dvd_iff_le_emultiplicity, ← padicValNat_eq_emultiplicity (Nat.pos_of_ne_zero ha), + Nat.cast_le] theorem padicValNat_dvd_iff (n : ℕ) [hp : Fact p.Prime] (a : ℕ) : p ^ n ∣ a ↔ a = 0 ∨ n ≤ padicValNat p a := by @@ -569,10 +554,10 @@ theorem range_pow_padicValNat_subset_divisors' {n : ℕ} [hp : Fact p.Prime] : /-- The `p`-adic valuation of `(p * n)!` is `n` more than that of `n!`. -/ theorem padicValNat_factorial_mul (n : ℕ) [hp : Fact p.Prime] : padicValNat p (p * n) ! = padicValNat p n ! + n := by - refine PartENat.natCast_inj.mp ?_ - rw [padicValNat_def' (Nat.Prime.ne_one hp.out) <| factorial_pos (p * n), Nat.cast_add, - padicValNat_def' (Nat.Prime.ne_one hp.out) <| factorial_pos n] - exact Prime.multiplicity_factorial_mul hp.out + apply Nat.cast_injective (R := ℕ∞) + rw [padicValNat_eq_emultiplicity <| factorial_pos (p * n), Nat.cast_add, + padicValNat_eq_emultiplicity <| factorial_pos n] + exact Prime.emultiplicity_factorial_mul hp.out /-- The `p`-adic valuation of `m` equals zero if it is between `p * k` and `p * (k + 1)` for some `k`. -/ @@ -604,9 +589,9 @@ largest multiple of `p` below `n`, i.e. `(p * ⌊n / p⌋)!`. -/ The `p`-adic valuation of `n!` is the sum of the quotients `n / p ^ i`. This sum is expressed over the finset `Ico 1 b` where `b` is any bound greater than `log p n`. -/ theorem padicValNat_factorial {n b : ℕ} [hp : Fact p.Prime] (hnb : log p n < b) : - padicValNat p (n !) = ∑ i ∈ Finset.Ico 1 b, n / p ^ i := - PartENat.natCast_inj.mp ((padicValNat_def' (Nat.Prime.ne_one hp.out) <| factorial_pos _) ▸ - Prime.multiplicity_factorial hp.out hnb) + padicValNat p (n !) = ∑ i ∈ Finset.Ico 1 b, n / p ^ i := by + exact_mod_cast ((padicValNat_eq_emultiplicity (p := p) <| factorial_pos _) ▸ + Prime.emultiplicity_factorial hp.out hnb) /-- **Legendre's Theorem** @@ -626,9 +611,9 @@ in base `p`. This sum is expressed over the finset `Ico 1 b` where `b` is any bo `log p n`. -/ theorem padicValNat_choose {n k b : ℕ} [hp : Fact p.Prime] (hkn : k ≤ n) (hnb : log p n < b) : padicValNat p (choose n k) = - ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i).card := - PartENat.natCast_inj.mp <| (padicValNat_def' (Nat.Prime.ne_one hp.out) <| choose_pos hkn) ▸ - Prime.multiplicity_choose hp.out hkn hnb + ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + (n - k) % p ^ i).card := by + exact_mod_cast (padicValNat_eq_emultiplicity (p := p) <| choose_pos hkn) ▸ + Prime.emultiplicity_choose hp.out hkn hnb /-- **Kummer's Theorem** @@ -637,9 +622,9 @@ in base `p`. This sum is expressed over the finset `Ico 1 b` where `b` is any bo `log p (n + k)`. -/ theorem padicValNat_choose' {n k b : ℕ} [hp : Fact p.Prime] (hnb : log p (n + k) < b) : padicValNat p (choose (n + k) k) = - ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + n % p ^ i).card := - PartENat.natCast_inj.mp <| (padicValNat_def' (Nat.Prime.ne_one hp.out) <| choose_pos <| - Nat.le_add_left k n)▸ Prime.multiplicity_choose' hp.out hnb + ((Finset.Ico 1 b).filter fun i => p ^ i ≤ k % p ^ i + n % p ^ i).card := by + exact_mod_cast (padicValNat_eq_emultiplicity (p := p) <| choose_pos <| + Nat.le_add_left k n)▸ Prime.emultiplicity_choose' hp.out hnb /-- **Kummer's Theorem** Taking (`p - 1`) times the `p`-adic valuation of the binomial `n + k` over `k` equals the sum of the diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean index 1a6910baae3ae..cba87c009c504 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean @@ -29,16 +29,25 @@ 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 (multiplicity p n).get (multiplicity.finite_nat_iff.2 h) else 0 + if h : p ≠ 1 ∧ 0 < n then Nat.find (multiplicity_finite_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⟩] + convert (WithTop.untop'_coe ..).symm /-- A simplification of `padicValNat` when one input is prime, by analogy with `padicValRat_def`. -/ theorem padicValNat_def [hp : Fact p.Prime] {n : ℕ} (hn : 0 < n) : - padicValNat p n = (multiplicity p n).get (multiplicity.finite_nat_iff.2 ⟨hp.out.ne_one, hn⟩) := - dif_pos ⟨hp.out.ne_one, hn⟩ + padicValNat p n = multiplicity p n := + padicValNat_def' hp.out.ne_one hn -theorem padicValNat_def' {n : ℕ} (hp : p ≠ 1) (hn : 0 < n) : - ↑(padicValNat p n) = multiplicity p n := by simp [padicValNat, hp, hn] +/-- A simplification of `padicValNat` when one input is prime, by analogy with +`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] + exact_mod_cast padicValNat_def hn namespace padicValNat @@ -52,36 +61,34 @@ protected theorem zero : padicValNat p 0 = 0 := by simp [padicValNat] /-- `padicValNat p 1` is `0` for any `p`. -/ @[simp] -protected theorem one : padicValNat p 1 = 0 := by - unfold padicValNat - split_ifs - · simp - · rfl +protected theorem one : padicValNat p 1 = 0 := by simp [padicValNat] @[simp] theorem eq_zero_iff {n : ℕ} : padicValNat p n = 0 ↔ p = 1 ∨ n = 0 ∨ ¬p ∣ n := by - simp only [padicValNat, dite_eq_right_iff, PartENat.get_eq_iff_eq_coe, Nat.cast_zero, - multiplicity_eq_zero, and_imp, pos_iff_ne_zero, Ne, ← or_iff_not_imp_left] + simp only [padicValNat, ne_eq, pos_iff_ne_zero, dite_eq_right_iff, find_eq_zero, zero_add, + pow_one, and_imp, ← or_iff_not_imp_left] end padicValNat open List -theorem le_multiplicity_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : ℕ} (ha : a.Prime) +theorem le_emultiplicity_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : ℕ} (ha : a.Prime) (hb : b ≠ 0) : - ↑n ≤ multiplicity a b ↔ replicate n a <+~ b.primeFactorsList := + ↑n ≤ emultiplicity a b ↔ replicate n a <+~ b.primeFactorsList := (replicate_subperm_primeFactorsList_iff ha hb).trans - multiplicity.pow_dvd_iff_le_multiplicity |>.symm + pow_dvd_iff_le_emultiplicity |>.symm @[deprecated (since := "2024-07-17")] alias le_multiplicity_iff_replicate_subperm_factors := - le_multiplicity_iff_replicate_subperm_primeFactorsList + le_emultiplicity_iff_replicate_subperm_primeFactorsList theorem le_padicValNat_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : ℕ} (ha : a.Prime) (hb : b ≠ 0) : n ≤ padicValNat a b ↔ replicate n a <+~ b.primeFactorsList := by - rw [← le_multiplicity_iff_replicate_subperm_primeFactorsList ha hb, - ← padicValNat_def' ha.ne_one (Nat.pos_of_ne_zero hb), Nat.cast_le] + rw [← le_emultiplicity_iff_replicate_subperm_primeFactorsList ha hb, + Nat.multiplicity_finite_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] @[deprecated (since := "2024-07-17")] alias le_padicValNat_iff_replicate_subperm_factors := diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean index 8f65a9cbc788e..9458144550aaf 100644 --- a/Mathlib/NumberTheory/Padics/RingHoms.lean +++ b/Mathlib/NumberTheory/Padics/RingHoms.lean @@ -589,7 +589,7 @@ theorem lift_sub_val_mem_span (r : R) (n : ℕ) : lift f_compat r - (f n r).val ∈ (Ideal.span {(p : ℤ_[p]) ^ n}) := by obtain ⟨k, hk⟩ := limNthHom_spec f_compat r _ - (show (0 : ℝ) < (p : ℝ) ^ (-n : ℤ) from Nat.zpow_pos_of_pos hp_prime.1.pos _) + (show (0 : ℝ) < (p : ℝ) ^ (-n : ℤ) from zpow_pos (mod_cast hp_prime.1.pos) _) have := le_of_lt (hk (max n k) (le_max_right _ _)) rw [norm_le_pow_iff_mem_span_pow] at this dsimp [lift] diff --git a/Mathlib/NumberTheory/PellMatiyasevic.lean b/Mathlib/NumberTheory/PellMatiyasevic.lean index b931db03869a5..8d9f990a8b7df 100644 --- a/Mathlib/NumberTheory/PellMatiyasevic.lean +++ b/Mathlib/NumberTheory/PellMatiyasevic.lean @@ -129,10 +129,8 @@ theorem xn_succ (n : ℕ) : xn a1 (n + 1) = xn a1 n * a + d a1 * yn a1 n := theorem yn_succ (n : ℕ) : yn a1 (n + 1) = xn a1 n + yn a1 n * a := rfl ---@[simp] Porting note (#10618): `simp` can prove it theorem xn_one : xn a1 1 = a := by simp ---@[simp] Porting note (#10618): `simp` can prove it theorem yn_one : yn a1 1 = 1 := by simp /-- The Pell `x` sequence, considered as an integer sequence. -/ @@ -249,7 +247,7 @@ theorem x_pos (n) : 0 < xn a1 n := theorem eq_pell_lem : ∀ (n) (b : ℤ√(d a1)), 1 ≤ b → IsPell b → b ≤ pellZd a1 n → ∃ n, b = pellZd a1 n - | 0, b => fun h1 _ hl => ⟨0, @Zsqrtd.le_antisymm _ (dnsq a1) _ _ hl h1⟩ + | 0, _ => fun h1 _ hl => ⟨0, @Zsqrtd.le_antisymm _ (dnsq a1) _ _ hl h1⟩ | n + 1, b => fun h1 hp h => have a1p : (0 : ℤ√(d a1)) ≤ ⟨a, 1⟩ := trivial have am1p : (0 : ℤ√(d a1)) ≤ ⟨a, -1⟩ := show (_ : Nat) ≤ _ by simp; exact Nat.pred_le _ @@ -273,14 +271,14 @@ theorem eq_pell_lem : ∀ (n) (b : ℤ√(d a1)), 1 ≤ b → IsPell b → have y0l : (0 : ℤ√d a1) < ⟨x - x, y - -y⟩ := sub_lt_sub h1l fun hn : (1 : ℤ√d a1) ≤ ⟨x, -y⟩ => by have t := mul_le_mul_of_nonneg_left hn (le_trans zero_le_one h1) - erw [bm, mul_one] at t + rw [bm, mul_one] at t exact h1l t have yl2 : (⟨_, _⟩ : ℤ√_) < ⟨_, _⟩ := show (⟨x, y⟩ - ⟨x, -y⟩ : ℤ√d a1) < ⟨a, 1⟩ - ⟨a, -1⟩ from sub_lt_sub ha fun hn : (⟨x, -y⟩ : ℤ√d a1) ≤ ⟨a, -1⟩ => by have t := mul_le_mul_of_nonneg_right (mul_le_mul_of_nonneg_left hn (le_trans zero_le_one h1)) a1p - erw [bm, one_mul, mul_assoc, Eq.trans (mul_comm _ _) a1m, mul_one] at t + rw [bm, one_mul, mul_assoc, Eq.trans (mul_comm _ _) a1m, mul_one] at t exact ha t simp only [sub_self, sub_neg_eq_add] at y0l; simp only [Zsqrtd.neg_re, add_neg_cancel, Zsqrtd.neg_im, neg_neg] at yl2 @@ -353,7 +351,7 @@ theorem xy_coprime (n) : (xn a1 n).Coprime (yn a1 n) := exact Nat.dvd_sub (le_of_lt <| Nat.lt_of_sub_eq_succ p) (kx.mul_left _) (ky.mul_left _) theorem strictMono_y : StrictMono (yn a1) - | m, 0, h => absurd h <| Nat.not_lt_zero _ + | _, 0, h => absurd h <| Nat.not_lt_zero _ | m, n + 1, h => by have : yn a1 m ≤ yn a1 n := Or.elim (lt_or_eq_of_le <| Nat.le_of_succ_le_succ h) (fun hl => le_of_lt <| strictMono_y hl) @@ -363,7 +361,7 @@ theorem strictMono_y : StrictMono (yn a1) exact mul_le_mul this (le_of_lt a1) (Nat.zero_le _) (Nat.zero_le _) theorem strictMono_x : StrictMono (xn a1) - | m, 0, h => absurd h <| Nat.not_lt_zero _ + | _, 0, h => absurd h <| Nat.not_lt_zero _ | m, n + 1, h => by have : xn a1 m ≤ xn a1 n := Or.elim (lt_or_eq_of_le <| Nat.le_of_succ_le_succ h) (fun hl => le_of_lt <| strictMono_x hl) @@ -657,7 +655,7 @@ theorem eq_of_xn_modEq_lem3 {i n} (npos : 0 < n) : (fun h => lt_trans (eq_of_xn_modEq_lem3 npos h (le_of_lt (Nat.lt_of_succ_le j2n)) jn - fun ⟨a1, n1, i0, j2⟩ => by + fun ⟨_, n1, _, j2⟩ => by rw [n1, j2] at j2n; exact absurd j2n (by decide)) s) fun h => by rw [h]; exact s @@ -703,8 +701,8 @@ theorem eq_of_xn_modEq' {i j n} (ipos : 0 < i) (hin : i ≤ n) (j4n : j ≤ 4 * have i2n : i ≤ 2 * n := by apply le_trans hin; rw [two_mul]; apply Nat.le_add_left (le_or_gt j (2 * n)).imp (fun j2n : j ≤ 2 * n => - eq_of_xn_modEq a1 j2n i2n h fun a2 n1 => - ⟨fun j0 i2 => by rw [n1, i2] at hin; exact absurd hin (by decide), fun _ i0 => + eq_of_xn_modEq a1 j2n i2n h fun _ n1 => + ⟨fun _ i2 => by rw [n1, i2] at hin; exact absurd hin (by decide), fun _ i0 => _root_.ne_of_gt ipos i0⟩) fun j2n : 2 * n < j => suffices i = 4 * n - j by rw [this, add_tsub_cancel_of_le j4n] @@ -713,7 +711,7 @@ theorem eq_of_xn_modEq' {i j n} (ipos : 0 < i) (hin : i ≤ n) (j4n : j ≤ 4 * (h.symm.trans <| by let t := xn_modEq_x4n_sub a1 j42n rwa [tsub_tsub_cancel_of_le j4n] at t) - fun a2 n1 => + fun _ n1 => ⟨fun i0 => absurd i0 (_root_.ne_of_gt ipos), fun i2 => by rw [n1, i2] at hin exact absurd hin (by decide)⟩ diff --git a/Mathlib/NumberTheory/PrimeCounting.lean b/Mathlib/NumberTheory/PrimeCounting.lean index 3005d0cb7165a..fa1a732eddcb9 100644 --- a/Mathlib/NumberTheory/PrimeCounting.lean +++ b/Mathlib/NumberTheory/PrimeCounting.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Bolton Bailey. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bolton Bailey, Ralf Stephan -/ -import Mathlib.Data.Nat.Nth +import Mathlib.Data.Nat.Prime.Nth import Mathlib.Data.Nat.Totient import Mathlib.NumberTheory.SmoothNumbers @@ -70,12 +70,9 @@ theorem monotone_primeCounting : Monotone primeCounting := theorem primeCounting'_nth_eq (n : ℕ) : π' (nth Prime n) = n := count_nth_of_infinite infinite_setOf_prime _ -@[simp] -theorem zeroth_prime_eq_two : nth Prime 0 = 2 := nth_count prime_two - /-- The `n`th prime is greater or equal to `n + 2`. -/ theorem add_two_le_nth_prime (n : ℕ) : n + 2 ≤ nth Prime n := - zeroth_prime_eq_two ▸ (nth_strictMono infinite_setOf_prime).add_le_nat n 0 + nth_prime_zero_eq_two ▸ (nth_strictMono infinite_setOf_prime).add_le_nat n 0 theorem surjective_primeCounting' : Function.Surjective π' := Nat.surjective_count_of_infinite_setOf infinite_setOf_prime @@ -99,9 +96,25 @@ theorem tensto_primeCounting : Tendsto π atTop atTop := theorem prime_nth_prime (n : ℕ) : Prime (nth Prime n) := nth_mem_of_infinite infinite_setOf_prime _ +@[simp] +lemma primeCounting'_eq_zero_iff {n : ℕ} : n.primeCounting' = 0 ↔ n ≤ 2 := by + rw [primeCounting', Nat.count_eq_zero ⟨_, Nat.prime_two⟩, Nat.nth_prime_zero_eq_two] + +@[simp] +lemma primeCounting_eq_zero_iff {n : ℕ} : n.primeCounting = 0 ↔ n ≤ 1 := by + simp [primeCounting] + +@[simp] +lemma primeCounting_zero : primeCounting 0 = 0 := + primeCounting_eq_zero_iff.mpr zero_le_one + +@[simp] +lemma primeCounting_one : primeCounting 1 = 0 := + primeCounting_eq_zero_iff.mpr le_rfl + /-- The cardinality of the finset `primesBelow n` equals the counting function `primeCounting'` at `n`. -/ -theorem primesBelow_card_eq_primeCounting' (n : ℕ) : n.primesBelow.card = primeCounting' n := by +theorem primesBelow_card_eq_primeCounting' (n : ℕ) : #n.primesBelow = primeCounting' n := by simp only [primesBelow, primeCounting'] exact (count_eq_card_filter_range Prime n).symm @@ -109,13 +122,13 @@ theorem primesBelow_card_eq_primeCounting' (n : ℕ) : n.primesBelow.card = prim theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) : π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) := calc - π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by + π' (k + n) ≤ #{p ∈ range k | p.Prime} + #{p ∈ Ico k (k + n) | p.Prime} := by rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ← Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union] apply card_union_le - _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by + _ ≤ π' k + #{p ∈ Ico k (k + n) | p.Prime} := by rw [primeCounting', count_eq_card_filter_range] - _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by + _ ≤ π' k + #{b ∈ Ico k (k + n) | a.Coprime b} := by refine add_le_add_left (card_le_card ?_) k.primeCounting' simp only [subset_iff, and_imp, mem_filter, mem_Ico] intro p succ_k_le_p p_lt_n p_prime diff --git a/Mathlib/NumberTheory/Primorial.lean b/Mathlib/NumberTheory/Primorial.lean index 8bc67a5f611f7..3867a3aa0f893 100644 --- a/Mathlib/NumberTheory/Primorial.lean +++ b/Mathlib/NumberTheory/Primorial.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Order.BigOperators.Ring.Finset import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Data.Nat.Choose.Sum import Mathlib.Data.Nat.Choose.Dvd -import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.Prime.Basic /-! # Primorial @@ -31,8 +31,7 @@ open Nat /-- The primorial `n#` of `n` is the product of the primes less than or equal to `n`. -/ -def primorial (n : ℕ) : ℕ := - ∏ p ∈ filter Nat.Prime (range (n + 1)), p +def primorial (n : ℕ) : ℕ := ∏ p ∈ range (n + 1) with p.Prime, p local notation x "#" => primorial x @@ -45,17 +44,17 @@ theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := exact fun h ↦ h.even_sub_one <| mt succ.inj hn1 theorem primorial_add (m n : ℕ) : - (m + n)# = m# * ∏ p ∈ filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := by + (m + n)# = m# * ∏ p ∈ Ico (m + 1) (m + n + 1) with p.Prime, p := by rw [primorial, primorial, ← Ico_zero_eq_range, ← prod_union, ← filter_union, Ico_union_Ico_eq_Ico] exacts [Nat.zero_le _, add_le_add_right (Nat.le_add_right _ _) _, disjoint_filter_filter <| Ico_disjoint_Ico_consecutive _ _ _] theorem primorial_add_dvd {m n : ℕ} (h : n ≤ m) : (m + n)# ∣ m# * choose (m + n) m := calc - (m + n)# = m# * ∏ p ∈ filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := primorial_add _ _ + (m + n)# = m# * ∏ p ∈ Ico (m + 1) (m + n + 1) with p.Prime, p := primorial_add _ _ _ ∣ m# * choose (m + n) m := mul_dvd_mul_left _ <| - prod_primes_dvd _ (fun k hk ↦ (mem_filter.1 hk).2.prime) fun p hp ↦ by + prod_primes_dvd _ (fun _ hk ↦ (mem_filter.1 hk).2.prime) fun p hp ↦ by rw [mem_filter, mem_Ico] at hp exact hp.2.dvd_choose_add hp.1.1 (h.trans_lt (m.lt_succ_self.trans_le hp.1.1)) (Nat.lt_succ_iff.1 hp.1.2) diff --git a/Mathlib/NumberTheory/RamificationInertia.lean b/Mathlib/NumberTheory/RamificationInertia.lean index 670a2c3ba24a8..cd2da449ce790 100644 --- a/Mathlib/NumberTheory/RamificationInertia.lean +++ b/Mathlib/NumberTheory/RamificationInertia.lean @@ -124,6 +124,19 @@ theorem le_comap_pow_ramificationIdx : p ≤ comap f (P ^ ramificationIdx f p P) theorem le_comap_of_ramificationIdx_ne_zero (h : ramificationIdx f p P ≠ 0) : p ≤ comap f P := Ideal.map_le_iff_le_comap.mp <| le_pow_ramificationIdx.trans <| Ideal.pow_le_self <| h +variable {S₁: Type*} [CommRing S₁] [Algebra R S₁] + +lemma ramificationIdx_comap_eq [Algebra R S] (e : S ≃ₐ[R] S₁) (P : Ideal S₁) : + ramificationIdx (algebraMap R S) p (P.comap e) = ramificationIdx (algebraMap R S₁) p P := by + dsimp only [ramificationIdx] + congr + ext n + simp only [Set.mem_setOf_eq, Ideal.map_le_iff_le_comap] + rw [← comap_coe e, ← e.toRingEquiv_toRingHom, comap_coe, ← RingEquiv.symm_symm (e : S ≃+* S₁), + ← map_comap_of_equiv, ← Ideal.map_pow, map_comap_of_equiv, ← comap_coe (RingEquiv.symm _), + comap_comap, RingEquiv.symm_symm, e.toRingEquiv_toRingHom, ← e.toAlgHom_toRingHom, + AlgHom.comp_algebraMap] + namespace IsDedekindDomain variable [IsDedekindDomain S] @@ -202,6 +215,30 @@ theorem inertiaDeg_algebraMap [Algebra R S] [Algebra (R ⧸ p) (S ⧸ P)] rw [Ideal.Quotient.lift_mk, ← Ideal.Quotient.algebraMap_eq P, ← IsScalarTower.algebraMap_eq, ← Ideal.Quotient.algebraMap_eq, ← IsScalarTower.algebraMap_apply] +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 + dsimp only [Ideal.inertiaDeg] + have : (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] + split + swap + · rw [dif_neg]; rwa [← this] + rw [dif_pos (this.mp ‹_›)] + apply (config := { allowSynthFailures := true }) LinearEquiv.finrank_eq + have E := quotientEquivAlg (P.comap e) P e (map_comap_of_surjective _ e.surjective P).symm + apply (config := {allowSynthFailures := true }) LinearEquiv.mk + case toLinearMap => + apply (config := {allowSynthFailures := true }) LinearMap.mk + swap + · exact E.toLinearMap.toAddHom + · intro r x + show E (_ * _) = _ * (E x) + obtain ⟨r, rfl⟩ := Ideal.Quotient.mk_surjective r + simp only [Quotient.mk_comp_algebraMap, Quotient.lift_mk, _root_.map_mul, AlgEquiv.commutes, + RingHomCompTriple.comp_apply] + · exact E.left_inv + · exact E.right_inv + end DecEq section FinrankQuotientMap @@ -476,7 +513,7 @@ noncomputable def quotientToQuotientRangePowQuotSuccAux {i : ℕ} {a : S} (a_mem (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion f 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_r_def] at h ⊢ + rw [Submodule.quotientRel_def] at h ⊢ simp only [_root_.map_mul, LinearMap.mem_range] refine ⟨⟨_, Ideal.mem_map_of_mem _ (Ideal.mul_mem_mul a_mem h)⟩, ?_⟩ ext @@ -588,7 +625,7 @@ theorem rank_pow_quot_aux [IsDedekindDomain S] [p.IsMaximal] [P.IsPrime] (hP0 : letI : Field (R ⧸ p) := Ideal.Quotient.field _ rw [← rank_range_of_injective _ (powQuotSuccInclusion_injective f p P i), (quotientRangePowQuotSuccInclusionEquiv f p P hP0 hi).symm.rank_eq] - exact (rank_quotient_add_rank (LinearMap.range (powQuotSuccInclusion f p P i))).symm + exact (Submodule.rank_quotient_add_rank (LinearMap.range (powQuotSuccInclusion f p P i))).symm theorem rank_pow_quot [IsDedekindDomain S] [p.IsMaximal] [P.IsPrime] (hP0 : P ≠ ⊥) (i : ℕ) (hi : i ≤ e) : @@ -639,7 +676,7 @@ theorem finrank_prime_pow_ramificationIdx [IsDedekindDomain S] (hP0 : P ≠ ⊥) by_cases hP : FiniteDimensional (R ⧸ p) (S ⧸ P) · haveI := hP haveI := (finiteDimensional_iff_of_rank_eq_nsmul he hdim).mpr hP - refine Cardinal.natCast_injective ?_ + apply @Nat.cast_injective Cardinal rw [finrank_eq_rank', Nat.cast_mul, finrank_eq_rank', hdim, nsmul_eq_mul] have hPe := mt (finiteDimensional_iff_of_rank_eq_nsmul he hdim).mp hP simp only [finrank_of_infinite_dimensional hP, finrank_of_infinite_dimensional hPe, diff --git a/Mathlib/NumberTheory/Rayleigh.lean b/Mathlib/NumberTheory/Rayleigh.lean index 0e29615583c61..3e9f0e29d51b9 100644 --- a/Mathlib/NumberTheory/Rayleigh.lean +++ b/Mathlib/NumberTheory/Rayleigh.lean @@ -55,7 +55,7 @@ noncomputable def beattySeq' (r : ℝ) : ℤ → ℤ := namespace Beatty -variable {r s : ℝ} {j k : ℤ} +variable {r s : ℝ} {j : ℤ} /-- Let `r > 1` and `1/r + 1/s = 1`. Then `B_r` and `B'_s` are disjoint (i.e. no collision exists). -/ diff --git a/Mathlib/NumberTheory/SiegelsLemma.lean b/Mathlib/NumberTheory/SiegelsLemma.lean index 998f8940d66b9..688fa4547d8c0 100644 --- a/Mathlib/NumberTheory/SiegelsLemma.lean +++ b/Mathlib/NumberTheory/SiegelsLemma.lean @@ -38,8 +38,7 @@ open Matrix Finset namespace Int.Matrix -variable {α β : Type*} [Fintype α] [Fintype β] - (A : Matrix α β ℤ) (v : β → ℤ) +variable {α β : Type*} [Fintype α] [Fintype β] (A : Matrix α β ℤ) -- Some definitions and relative properties @@ -61,7 +60,7 @@ section preparation /- In order to apply Pigeonhole we need: # Step 1: ∀ v ∈ T, A *ᵥ v ∈ S and -# Step 2: S.card < T.card +# Step 2: #S < #T Pigeonhole will give different x and y in T with A.mulVec x = A.mulVec y in S Their difference is the solution we are looking for -/ @@ -91,12 +90,12 @@ private lemma image_T_subset_S [DecidableEq α] [DecidableEq β] (v) (hv : v ∈ -- # Preparation for Step 2 -private lemma card_T_eq [DecidableEq β] : (T).card = (B + 1) ^ n := by +private lemma card_T_eq [DecidableEq β] : #T = (B + 1) ^ n := by rw [Pi.card_Icc 0 B'] simp only [Pi.zero_apply, card_Icc, sub_zero, toNat_ofNat_add_one, prod_const, card_univ, add_pos_iff, zero_lt_one, or_true] --- This lemma is necessary to be able to apply the formula (Icc a b).card = b + 1 - a +-- This lemma is necessary to be able to apply the formula #(Icc a b) = b + 1 - a private lemma N_le_P_add_one (i : α) : N i ≤ P i + 1 := by calc N i _ ≤ 0 := by @@ -109,7 +108,7 @@ private lemma N_le_P_add_one (i : α) : N i ≤ P i + 1 := by intro j _ exact mul_nonneg (Nat.cast_nonneg B) (posPart_nonneg (A i j)) -private lemma card_S_eq [DecidableEq α] : (Finset.Icc N P).card = ∏ i : α, (P i - N i + 1) := by +private lemma card_S_eq [DecidableEq α] : #(Finset.Icc N P) = ∏ i : α, (P i - N i + 1) := by rw [Pi.card_Icc N P, Nat.cast_prod] congr ext i @@ -128,13 +127,13 @@ lemma one_le_norm_A_of_ne_zero (hA : A ≠ 0) : 1 ≤ ‖A‖ := by norm_cast at h exact Int.abs_lt_one_iff.1 h --- # Step 2: S.card < T.card +-- # Step 2: #S < #T open Real Nat private lemma card_S_lt_card_T [DecidableEq α] [DecidableEq β] (hn : Fintype.card α < Fintype.card β) (hm : 0 < Fintype.card α) : - (S).card < (T).card := by + #S < #T := by zify -- This is necessary to use card_S_eq rw [card_T_eq A, card_S_eq] rify -- This is necessary because ‖A‖ is a real number diff --git a/Mathlib/NumberTheory/Zsqrtd/Basic.lean b/Mathlib/NumberTheory/Zsqrtd/Basic.lean index c73a74bb7a6b6..914914db4f6cb 100644 --- a/Mathlib/NumberTheory/Zsqrtd/Basic.lean +++ b/Mathlib/NumberTheory/Zsqrtd/Basic.lean @@ -217,9 +217,9 @@ theorem star_im (z : ℤ√d) : (star z).im = -z.im := rfl instance : StarRing (ℤ√d) where - star_involutive x := Zsqrtd.ext rfl (neg_neg _) + star_involutive _ := Zsqrtd.ext rfl (neg_neg _) star_mul a b := by ext <;> simp <;> ring - star_add a b := Zsqrtd.ext rfl (neg_add _ _) + star_add _ _ := Zsqrtd.ext rfl (neg_add _ _) -- Porting note: proof was `by decide` instance nontrivial : Nontrivial (ℤ√d) := @@ -654,7 +654,7 @@ instance preorder : Preorder (ℤ√d) where le_refl a := show Nonneg (a - a) by simp only [sub_self]; trivial le_trans a b c hab hbc := by simpa [sub_add_sub_cancel'] using hab.add hbc lt := (· < ·) - lt_iff_le_not_le a b := (and_iff_right_of_imp (Zsqrtd.le_total _ _).resolve_left).symm + lt_iff_le_not_le _ _ := (and_iff_right_of_imp (Zsqrtd.le_total _ _).resolve_left).symm open Int in theorem le_arch (a : ℤ√d) : ∃ n : ℕ, a ≤ n := by @@ -805,12 +805,12 @@ theorem not_divides_sq (x y) : (x + 1) * (x + 1) ≠ d * (y + 1) * (y + 1) := fu open Int in theorem nonneg_antisymm : ∀ {a : ℤ√d}, Nonneg a → Nonneg (-a) → a = 0 | ⟨0, 0⟩, _, _ => rfl - | ⟨-[x+1], -[y+1]⟩, xy, _ => False.elim xy - | ⟨(x + 1 : Nat), (y + 1 : Nat)⟩, _, yx => False.elim yx - | ⟨-[x+1], 0⟩, xy, _ => absurd xy (not_sqLe_succ _ _ _ (by decide)) - | ⟨(x + 1 : Nat), 0⟩, _, yx => absurd yx (not_sqLe_succ _ _ _ (by decide)) - | ⟨0, -[y+1]⟩, xy, _ => absurd xy (not_sqLe_succ _ _ _ d_pos) - | ⟨0, (y + 1 : Nat)⟩, _, yx => absurd yx (not_sqLe_succ _ _ _ d_pos) + | ⟨-[_+1], -[_+1]⟩, xy, _ => False.elim xy + | ⟨(_ + 1 : Nat), (_ + 1 : Nat)⟩, _, yx => False.elim yx + | ⟨-[_+1], 0⟩, xy, _ => absurd xy (not_sqLe_succ _ _ _ (by decide)) + | ⟨(_ + 1 : Nat), 0⟩, _, yx => absurd yx (not_sqLe_succ _ _ _ (by decide)) + | ⟨0, -[_+1]⟩, xy, _ => absurd xy (not_sqLe_succ _ _ _ d_pos) + | ⟨0, (_ + 1 : Nat)⟩, _, yx => absurd yx (not_sqLe_succ _ _ _ d_pos) | ⟨(x + 1 : Nat), -[y+1]⟩, (xy : SqLe _ _ _ _), (yx : SqLe _ _ _ _) => by let t := le_antisymm yx xy rw [one_mul] at t @@ -931,8 +931,7 @@ def lift {d : ℤ} : { r : R // r * r = ↑d } ≃ (ℤ√d →+* R) where ext simp right_inv f := by - -- Porting note: was `ext` - refine hom_ext _ _ ?_ + ext simp /-- `lift r` is injective if `d` is non-square, and R has characteristic zero (that is, the map from diff --git a/Mathlib/NumberTheory/Zsqrtd/GaussianInt.lean b/Mathlib/NumberTheory/Zsqrtd/GaussianInt.lean index 6ade04820260d..a2da9ffabe073 100644 --- a/Mathlib/NumberTheory/Zsqrtd/GaussianInt.lean +++ b/Mathlib/NumberTheory/Zsqrtd/GaussianInt.lean @@ -89,27 +89,21 @@ theorem toComplex_re (x y : ℤ) : ((⟨x, y⟩ : ℤ[i]) : ℂ).re = x := by si @[simp] theorem toComplex_im (x y : ℤ) : ((⟨x, y⟩ : ℤ[i]) : ℂ).im = y := by simp [toComplex_def] --- Porting note (#10618): @[simp] can prove this theorem toComplex_add (x y : ℤ[i]) : ((x + y : ℤ[i]) : ℂ) = x + y := toComplex.map_add _ _ --- Porting note (#10618): @[simp] can prove this theorem toComplex_mul (x y : ℤ[i]) : ((x * y : ℤ[i]) : ℂ) = x * y := toComplex.map_mul _ _ --- Porting note (#10618): @[simp] can prove this theorem toComplex_one : ((1 : ℤ[i]) : ℂ) = 1 := toComplex.map_one --- Porting note (#10618): @[simp] can prove this theorem toComplex_zero : ((0 : ℤ[i]) : ℂ) = 0 := toComplex.map_zero --- Porting note (#10618): @[simp] can prove this theorem toComplex_neg (x : ℤ[i]) : ((-x : ℤ[i]) : ℂ) = -x := toComplex.map_neg _ --- Porting note (#10618): @[simp] can prove this theorem toComplex_sub (x y : ℤ[i]) : ((x - y : ℤ[i]) : ℂ) = x - y := toComplex.map_sub _ _ @@ -250,7 +244,7 @@ instance : EuclideanDomain ℤ[i] := r := _ r_wellFounded := (measure (Int.natAbs ∘ norm)).wf remainder_lt := natAbs_norm_mod_lt - mul_left_not_lt := fun a b hb0 => not_lt_of_ge <| norm_le_norm_mul_left a hb0 } + mul_left_not_lt := fun a _ hb0 => not_lt_of_ge <| norm_le_norm_mul_left a hb0 } open PrincipalIdealRing diff --git a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean index 413c023dba9e7..e77bb9da4988f 100644 --- a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean +++ b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean @@ -80,13 +80,13 @@ theorem mod_four_eq_three_of_nat_prime_of_prime (p : ℕ) [hp : Fact p.Prime] clear_aux_decl tauto -theorem prime_of_nat_prime_of_mod_four_eq_three (p : ℕ) [hp : Fact p.Prime] (hp3 : p % 4 = 3) : +theorem prime_of_nat_prime_of_mod_four_eq_three (p : ℕ) [Fact p.Prime] (hp3 : p % 4 = 3) : Prime (p : ℤ[i]) := irreducible_iff_prime.1 <| by_contradiction fun hpi => let ⟨a, b, hab⟩ := sq_add_sq_of_nat_prime_of_not_irreducible p hpi have : ∀ a b : ZMod 4, a ^ 2 + b ^ 2 ≠ (p : ZMod 4) := by - erw [← ZMod.natCast_mod p 4, hp3]; decide + rw [← ZMod.natCast_mod p 4, hp3]; decide this a b (hab ▸ by simp) /-- A prime natural number is prime in `ℤ[i]` if and only if it is `3` mod `4` -/ diff --git a/Mathlib/Order/Antichain.lean b/Mathlib/Order/Antichain.lean index cdfcbf4009f47..4548a1da022cf 100644 --- a/Mathlib/Order/Antichain.lean +++ b/Mathlib/Order/Antichain.lean @@ -180,12 +180,12 @@ theorem IsAntichain.not_lt (hs : IsAntichain (· ≤ ·) s) (ha : a ∈ s) (hb : fun h => hs ha hb h.ne h.le theorem isAntichain_and_least_iff : IsAntichain (· ≤ ·) s ∧ IsLeast s a ↔ s = {a} := - ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun b hb => h.1.eq' hb h.2.1 (h.2.2 hb)⟩, by + ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun _ hb => h.1.eq' hb h.2.1 (h.2.2 hb)⟩, by rintro rfl exact ⟨isAntichain_singleton _ _, isLeast_singleton⟩⟩ theorem isAntichain_and_greatest_iff : IsAntichain (· ≤ ·) s ∧ IsGreatest s a ↔ s = {a} := - ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun b hb => h.1.eq hb h.2.1 (h.2.2 hb)⟩, by + ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun _ hb => h.1.eq hb h.2.1 (h.2.2 hb)⟩, by rintro rfl exact ⟨isAntichain_singleton _ _, isGreatest_singleton⟩⟩ @@ -297,7 +297,7 @@ end General section Pi variable {ι : Type*} {α : ι → Type*} [∀ i, Preorder (α i)] {s t : Set (∀ i, α i)} - {a b c : ∀ i, α i} + {a b : ∀ i, α i} @[inherit_doc] diff --git a/Mathlib/Order/Antisymmetrization.lean b/Mathlib/Order/Antisymmetrization.lean index e5205df7dc3be..685d82061d1d5 100644 --- a/Mathlib/Order/Antisymmetrization.lean +++ b/Mathlib/Order/Antisymmetrization.lean @@ -119,11 +119,11 @@ theorem AntisymmRel.image {a b : α} (h : AntisymmRel (· ≤ ·) a b) {f : α ⟨hf h.1, hf h.2⟩ instance instPartialOrderAntisymmetrization : PartialOrder (Antisymmetrization α (· ≤ ·)) where - le a b := - (Quotient.liftOn₂' a b (· ≤ ·)) fun (_ _ _ _ : α) h₁ h₂ => + le := + Quotient.lift₂ (· ≤ ·) fun (_ _ _ _ : α) h₁ h₂ => propext ⟨fun h => h₁.2.trans <| h.trans h₂.1, fun h => h₁.1.trans <| h.trans h₂.2⟩ - lt a b := - (Quotient.liftOn₂' a b (· < ·)) fun (_ _ _ _ : α) h₁ h₂ => + lt := + Quotient.lift₂ (· < ·) fun (_ _ _ _ : α) h₁ h₂ => propext ⟨fun h => h₁.2.trans_lt <| h.trans_le h₂.1, fun h => h₁.1.trans_lt <| h.trans_le h₂.2⟩ le_refl a := Quotient.inductionOn' a <| le_refl @@ -138,11 +138,11 @@ theorem antisymmetrization_fibration : theorem acc_antisymmetrization_iff : Acc (· < ·) (@toAntisymmetrization α (· ≤ ·) _ a) ↔ Acc (· < ·) a := - acc_liftOn₂'_iff + acc_lift₂_iff theorem wellFounded_antisymmetrization_iff : WellFounded (@LT.lt (Antisymmetrization α (· ≤ ·)) _) ↔ WellFounded (@LT.lt α _) := - wellFounded_liftOn₂'_iff + wellFounded_lift₂_iff instance [WellFoundedLT α] : WellFoundedLT (Antisymmetrization α (· ≤ ·)) := ⟨wellFounded_antisymmetrization_iff.2 IsWellFounded.wf⟩ @@ -167,12 +167,12 @@ theorem toAntisymmetrization_lt_toAntisymmetrization_iff : @[simp] theorem ofAntisymmetrization_le_ofAntisymmetrization_iff {a b : Antisymmetrization α (· ≤ ·)} : ofAntisymmetrization (· ≤ ·) a ≤ ofAntisymmetrization (· ≤ ·) b ↔ a ≤ b := - (Quotient.out'RelEmbedding _).map_rel_iff + (Quotient.outRelEmbedding _).map_rel_iff @[simp] theorem ofAntisymmetrization_lt_ofAntisymmetrization_iff {a b : Antisymmetrization α (· ≤ ·)} : ofAntisymmetrization (· ≤ ·) a < ofAntisymmetrization (· ≤ ·) b ↔ a < b := - (Quotient.out'RelEmbedding _).map_rel_iff + (Quotient.outRelEmbedding _).map_rel_iff @[mono] theorem toAntisymmetrization_mono : Monotone (@toAntisymmetrization α (· ≤ ·) _) := fun _ _ => id @@ -209,7 +209,7 @@ variable (α) /-- `ofAntisymmetrization` as an order embedding. -/ @[simps] noncomputable def OrderEmbedding.ofAntisymmetrization : Antisymmetrization α (· ≤ ·) ↪o α := - { Quotient.out'RelEmbedding _ with toFun := _root_.ofAntisymmetrization _ } + { Quotient.outRelEmbedding _ with toFun := _root_.ofAntisymmetrization _ } /-- `Antisymmetrization` and `orderDual` commute. -/ def OrderIso.dualAntisymmetrization : @@ -218,7 +218,7 @@ def OrderIso.dualAntisymmetrization : invFun := (Quotient.map' id) fun _ _ => And.symm left_inv a := Quotient.inductionOn' a fun a => by simp_rw [Quotient.map'_mk'', id] right_inv a := Quotient.inductionOn' a fun a => by simp_rw [Quotient.map'_mk'', id] - map_rel_iff' := @fun a b => Quotient.inductionOn₂' a b fun a b => Iff.rfl + map_rel_iff' := @fun a b => Quotient.inductionOn₂' a b fun _ _ => Iff.rfl @[simp] theorem OrderIso.dualAntisymmetrization_apply (a : α) : diff --git a/Mathlib/Order/Atoms.lean b/Mathlib/Order/Atoms.lean index bcafc0ff30746..6d4b89c1b3df3 100644 --- a/Mathlib/Order/Atoms.lean +++ b/Mathlib/Order/Atoms.lean @@ -8,6 +8,7 @@ import Mathlib.Order.ModularLattice import Mathlib.Order.SuccPred.Basic import Mathlib.Order.WellFounded import Mathlib.Tactic.Nontriviality +import Mathlib.Order.ConditionallyCompleteLattice.Indexed /-! # Atoms, Coatoms, and Simple Lattices @@ -512,7 +513,7 @@ theorem sSup_atoms_eq_top : sSup { a : α | IsAtom a } = ⊤ := by exact (and_iff_left le_top).symm theorem le_iff_atom_le_imp {a b : α} : a ≤ b ↔ ∀ c : α, IsAtom c → c ≤ a → c ≤ b := - ⟨fun ab c _ ca => le_trans ca ab, fun h => by + ⟨fun ab _ _ ca => le_trans ca ab, fun h => by rw [← sSup_atoms_le_eq a, ← sSup_atoms_le_eq b] exact sSup_le_sSup fun c hc => ⟨hc.1, h c hc.1 hc.2⟩⟩ @@ -1090,7 +1091,7 @@ theorem isAtom_iff {f : ∀ i, π i} [∀ i, PartialOrder (π i)] [∀ i, OrderB theorem isAtom_single {i : ι} [DecidableEq ι] [∀ i, PartialOrder (π i)] [∀ i, OrderBot (π i)] {a : π i} (h : IsAtom a) : IsAtom (Function.update (⊥ : ∀ i, π i) i a) := - isAtom_iff.2 ⟨i, by simpa, fun j hji => Function.update_noteq hji _ _⟩ + isAtom_iff.2 ⟨i, by simpa, fun _ hji => Function.update_noteq hji _ _⟩ theorem isAtom_iff_eq_single [DecidableEq ι] [∀ i, PartialOrder (π i)] [∀ i, OrderBot (π i)] {f : ∀ i, π i} : diff --git a/Mathlib/Order/Atoms/Finite.lean b/Mathlib/Order/Atoms/Finite.lean index c17782a493d32..93cca39127a7d 100644 --- a/Mathlib/Order/Atoms/Finite.lean +++ b/Mathlib/Order/Atoms/Finite.lean @@ -22,23 +22,26 @@ variable {α β : Type*} namespace IsSimpleOrder +variable [LE α] [BoundedOrder α] [IsSimpleOrder α] + section DecidableEq /- It is important that `IsSimpleOrder` is the last type-class argument of this instance, so that type-class inference fails quickly if it doesn't apply. -/ -instance (priority := 200) {α} [DecidableEq α] [LE α] [BoundedOrder α] [IsSimpleOrder α] : - Fintype α := +instance (priority := 200) [DecidableEq α] : Fintype α := Fintype.ofEquiv Bool equivBool.symm end DecidableEq +instance (priority := 200) : Finite α := by classical infer_instance + end IsSimpleOrder namespace Fintype namespace IsSimpleOrder -variable [PartialOrder α] [BoundedOrder α] [IsSimpleOrder α] [DecidableEq α] +variable [LE α] [BoundedOrder α] [IsSimpleOrder α] [DecidableEq α] theorem univ : (Finset.univ : Finset α) = {⊤, ⊥} := by change Finset.map _ (Finset.univ : Finset Bool) = _ diff --git a/Mathlib/Order/Basic.lean b/Mathlib/Order/Basic.lean index 08b21b2de4986..fb57460b6d250 100644 --- a/Mathlib/Order/Basic.lean +++ b/Mathlib/Order/Basic.lean @@ -754,6 +754,11 @@ instance IsIrrefl.compl (r) [IsIrrefl α r] : IsRefl α rᶜ := instance IsRefl.compl (r) [IsRefl α r] : IsIrrefl α rᶜ := ⟨fun a ↦ not_not_intro (refl a)⟩ +theorem compl_lt [LinearOrder α] : (· < · : α → α → _)ᶜ = (· ≥ ·) := by ext; simp [compl] +theorem compl_le [LinearOrder α] : (· ≤ · : α → α → _)ᶜ = (· > ·) := by ext; simp [compl] +theorem compl_gt [LinearOrder α] : (· > · : α → α → _)ᶜ = (· ≤ ·) := by ext; simp [compl] +theorem compl_ge [LinearOrder α] : (· ≥ · : α → α → _)ᶜ = (· < ·) := by ext; simp [compl] + /-! ### Order instances on the function space -/ @@ -767,7 +772,7 @@ theorem Pi.le_def [∀ i, LE (π i)] {x y : ∀ i, π i} : instance Pi.preorder [∀ i, Preorder (π i)] : Preorder (∀ i, π i) where __ := inferInstanceAs (LE (∀ i, π i)) le_refl := fun a i ↦ le_refl (a i) - le_trans := fun a b c h₁ h₂ i ↦ le_trans (h₁ i) (h₂ i) + le_trans := fun _ _ _ h₁ h₂ i ↦ le_trans (h₁ i) (h₂ i) theorem Pi.lt_def [∀ i, Preorder (π i)] {x y : ∀ i, π i} : x < y ↔ x ≤ y ∧ ∃ i, x i < y i := by @@ -1126,7 +1131,7 @@ variable [Preorder α] [Preorder β] {a a₁ a₂ : α} {b b₁ b₂ : β} {x y instance (α β : Type*) [Preorder α] [Preorder β] : Preorder (α × β) where __ := inferInstanceAs (LE (α × β)) le_refl := fun ⟨a, b⟩ ↦ ⟨le_refl a, le_refl b⟩ - le_trans := fun ⟨a, b⟩ ⟨c, d⟩ ⟨e, f⟩ ⟨hac, hbd⟩ ⟨hce, hdf⟩ ↦ ⟨le_trans hac hce, le_trans hbd hdf⟩ + le_trans := fun ⟨_, _⟩ ⟨_, _⟩ ⟨_, _⟩ ⟨hac, hbd⟩ ⟨hce, hdf⟩ ↦ ⟨le_trans hac hce, le_trans hbd hdf⟩ @[simp] theorem swap_lt_swap : x.swap < y.swap ↔ x < y := @@ -1283,11 +1288,9 @@ theorem max_eq : max a b = unit := theorem min_eq : min a b = unit := rfl --- Porting note (#10618): simp can prove this @[simp] protected theorem le : a ≤ b := trivial --- Porting note (#10618): simp can prove this @[simp] theorem not_lt : ¬a < b := not_false diff --git a/Mathlib/Order/Birkhoff.lean b/Mathlib/Order/Birkhoff.lean index 03f815acdee3c..efa0574e44665 100644 --- a/Mathlib/Order/Birkhoff.lean +++ b/Mathlib/Order/Birkhoff.lean @@ -185,7 +185,7 @@ open Classical in lattice is isomorphic to the lattice of lower sets of its sup-irreducible elements. -/ noncomputable def OrderIso.lowerSetSupIrred [OrderBot α] : α ≃o LowerSet {a : α // SupIrred a} := Equiv.toOrderIso - { toFun := fun a ↦ ⟨{b | ↑b ≤ a}, fun b c hcb hba ↦ hba.trans' hcb⟩ + { toFun := fun a ↦ ⟨{b | ↑b ≤ a}, fun _ _ hcb hba ↦ hba.trans' hcb⟩ invFun := fun s ↦ (s : Set {a : α // SupIrred a}).toFinset.sup (↑) left_inv := fun a ↦ by refine le_antisymm (Finset.sup_le fun b ↦ Set.mem_toFinset.1) ?_ @@ -200,7 +200,7 @@ noncomputable def OrderIso.lowerSetSupIrred [OrderBot α] : α ≃o LowerSet {a exact s.lower ha (Set.mem_toFinset.1 hi) · dsimp exact le_sup (Set.mem_toFinset.2 ha) } - (fun b c hbc d ↦ le_trans' hbc) fun s t hst ↦ Finset.sup_mono <| Set.toFinset_mono hst + (fun _ _ hbc _ ↦ le_trans' hbc) fun _ _ hst ↦ Finset.sup_mono <| Set.toFinset_mono hst namespace OrderEmbedding diff --git a/Mathlib/Order/BooleanAlgebra.lean b/Mathlib/Order/BooleanAlgebra.lean index 509ef845db9a3..ba0cb4558f27b 100644 --- a/Mathlib/Order/BooleanAlgebra.lean +++ b/Mathlib/Order/BooleanAlgebra.lean @@ -58,7 +58,7 @@ open Function OrderDual universe u v -variable {α : Type u} {β : Type*} {w x y z : α} +variable {α : Type u} {β : Type*} {x y z : α} /-! ### Generalized Boolean algebras @@ -359,6 +359,11 @@ theorem sdiff_eq_comm (hy : y ≤ x) (hz : z ≤ x) : x \ y = z ↔ x \ z = y := theorem eq_of_sdiff_eq_sdiff (hxz : x ≤ z) (hyz : y ≤ z) (h : z \ x = z \ y) : x = y := by rw [← sdiff_sdiff_eq_self hxz, h, sdiff_sdiff_eq_self hyz] +theorem sdiff_le_sdiff_iff_le (hx : x ≤ z) (hy : y ≤ z) : z \ x ≤ z \ y ↔ y ≤ x := by + refine ⟨fun h ↦ ?_, sdiff_le_sdiff_left⟩ + rw [← sdiff_sdiff_eq_self hx, ← sdiff_sdiff_eq_self hy] + exact sdiff_le_sdiff_left h + theorem sdiff_sdiff_left' : (x \ y) \ z = x \ y ⊓ x \ z := by rw [sdiff_sdiff_left, sdiff_sup] theorem sdiff_sdiff_sup_sdiff : z \ (x \ y ⊔ y \ x) = z ⊓ (z \ x ⊔ y) ⊓ (z \ y ⊔ x) := @@ -692,8 +697,8 @@ instance Prop.instBooleanAlgebra : BooleanAlgebra Prop where __ := Prop.instHeytingAlgebra __ := GeneralizedHeytingAlgebra.toDistribLattice compl := Not - himp_eq p q := propext imp_iff_or_not - inf_compl_le_bot p H := H.2 H.1 + himp_eq _ _ := propext imp_iff_or_not + inf_compl_le_bot _ H := H.2 H.1 top_le_sup_compl p _ := Classical.em p instance Prod.instBooleanAlgebra [BooleanAlgebra α] [BooleanAlgebra β] : @@ -745,8 +750,8 @@ protected abbrev Function.Injective.generalizedBooleanAlgebra [Sup α] [Inf α] GeneralizedBooleanAlgebra α where __ := hf.generalizedCoheytingAlgebra f map_sup map_inf map_bot map_sdiff __ := hf.distribLattice f map_sup map_inf - sup_inf_sdiff a b := hf <| by erw [map_sup, map_sdiff, map_inf, sup_inf_sdiff] - inf_inf_sdiff a b := hf <| by erw [map_inf, map_sdiff, map_inf, inf_inf_sdiff, map_bot] + sup_inf_sdiff a b := hf <| by rw [map_sup, map_sdiff, map_inf, sup_inf_sdiff] + inf_inf_sdiff a b := hf <| by rw [map_inf, map_sdiff, map_inf, inf_inf_sdiff, map_bot] -- See note [reducible non-instances] /-- Pullback a `BooleanAlgebra` along an injection. -/ @@ -760,8 +765,8 @@ protected abbrev Function.Injective.booleanAlgebra [Sup α] [Inf α] [Top α] [B compl := compl himp := himp top := ⊤ - le_top a := (@le_top β _ _ _).trans map_top.ge - bot_le a := map_bot.le.trans bot_le + le_top _ := (@le_top β _ _ _).trans map_top.ge + bot_le _ := map_bot.le.trans bot_le inf_compl_le_bot a := ((map_inf _ _).trans <| by rw [map_compl, inf_compl_eq_bot, map_bot]).le top_le_sup_compl a := ((map_sup _ _).trans <| by rw [map_compl, sup_compl_eq_top, map_top]).ge sdiff_eq a b := by @@ -779,7 +784,7 @@ instance PUnit.instBooleanAlgebra : BooleanAlgebra PUnit where namespace DistribLattice -variable (α : Type*) [DistribLattice α] +variable (α) [DistribLattice α] /-- An alternative constructor for boolean algebras: diff --git a/Mathlib/Order/Booleanisation.lean b/Mathlib/Order/Booleanisation.lean index aa7f7370581b4..1b2c1d9c34ad8 100644 --- a/Mathlib/Order/Booleanisation.lean +++ b/Mathlib/Order/Booleanisation.lean @@ -168,13 +168,13 @@ instance instPreorder : Preorder (Booleanisation α) where | comp a, lift b => by simp | comp a, comp b => by simp [lt_iff_le_not_le] le_refl x := match x with - | lift a => LE.lift le_rfl - | comp a => LE.comp le_rfl + | lift _ => LE.lift le_rfl + | comp _ => LE.comp le_rfl le_trans x y z hxy hyz := match x, y, z, hxy, hyz with - | lift a, lift b, lift c, LE.lift hab, LE.lift hbc => LE.lift <| hab.trans hbc - | lift a, lift b, comp c, LE.lift hab, LE.sep hbc => LE.sep <| hbc.mono_left hab - | lift a, comp b, comp c, LE.sep hab, LE.comp hcb => LE.sep <| hab.mono_right hcb - | comp a, comp b, comp c, LE.comp hba, LE.comp hcb => LE.comp <| hcb.trans hba + | lift _, lift _, lift _, LE.lift hab, LE.lift hbc => LE.lift <| hab.trans hbc + | lift _, lift _, comp _, LE.lift hab, LE.sep hbc => LE.sep <| hbc.mono_left hab + | lift _, comp _, comp _, LE.sep hab, LE.comp hcb => LE.sep <| hab.mono_right hcb + | comp _, comp _, comp _, LE.comp hba, LE.comp hcb => LE.comp <| hcb.trans hba instance instPartialOrder : PartialOrder (Booleanisation α) where le_antisymm x y hxy hyx := match x, y, hxy, hyx with @@ -226,7 +226,7 @@ instance instDistribLattice : DistribLattice (Booleanisation α) where inf_le_right _ _ := inf_le_right le_inf _ _ _ := le_inf le_sup_inf x y z := match x, y, z with - | lift a, lift b, lift c => LE.lift le_sup_inf + | lift _, lift _, lift _ => LE.lift le_sup_inf | lift a, lift b, comp c => LE.lift <| by simp [sup_left_comm, sup_comm] | lift a, comp b, lift c => LE.lift <| by simp [sup_left_comm (a := b \ a), sup_comm (a := b \ a)] @@ -234,7 +234,7 @@ instance instDistribLattice : DistribLattice (Booleanisation α) where | comp a, lift b, lift c => LE.comp <| by rw [sdiff_inf] | comp a, lift b, comp c => LE.comp <| by rw [sdiff_sdiff_right'] | comp a, comp b, lift c => LE.comp <| by rw [sdiff_sdiff_right', sup_comm] - | comp a, comp b, comp c => LE.comp (inf_sup_left _ _ _).le + | comp _, comp _, comp _ => LE.comp (inf_sup_left _ _ _).le -- The linter significantly hinders readability here. set_option linter.unusedVariables false in diff --git a/Mathlib/Order/BoundedOrder.lean b/Mathlib/Order/BoundedOrder.lean index 985a68cdf8068..a96688135d066 100644 --- a/Mathlib/Order/BoundedOrder.lean +++ b/Mathlib/Order/BoundedOrder.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl import Mathlib.Order.Lattice import Mathlib.Order.ULift import Mathlib.Tactic.PushNeg +import Mathlib.Tactic.Finiteness.Attr /-! # ⊤ and ⊥, bounded lattices and variants @@ -33,7 +34,7 @@ open Function OrderDual universe u v -variable {α : Type u} {β : Type v} {γ δ : Type*} +variable {α : Type u} {β : Type v} /-! ### Top, bottom element -/ @@ -89,6 +90,10 @@ theorem lt_top_of_lt (h : a < b) : a < ⊤ := alias LT.lt.lt_top := lt_top_of_lt +attribute [aesop (rule_sets := [finiteness]) unsafe 20%] ne_top_of_lt +-- would have been better to implement this as a "safe" "forward" rule, why doesn't this work? +-- attribute [aesop (rule_sets := [finiteness]) safe forward] ne_top_of_lt + end Preorder variable [PartialOrder α] [OrderTop α] [Preorder β] {f : α → β} {a b : α} @@ -134,6 +139,7 @@ theorem not_lt_top_iff : ¬a < ⊤ ↔ a = ⊤ := theorem eq_top_or_lt_top (a : α) : a = ⊤ ∨ a < ⊤ := le_top.eq_or_lt +@[aesop (rule_sets := [finiteness]) safe apply] theorem Ne.lt_top (h : a ≠ ⊤) : a < ⊤ := lt_top_iff_ne_top.mpr h @@ -503,6 +509,11 @@ theorem exists_ge_and_iff_exists {P : α → Prop} {x₀ : α} (hP : Monotone P) (∃ x, x₀ ≤ x ∧ P x) ↔ ∃ x, P x := ⟨fun h => h.imp fun _ h => h.2, fun ⟨x, hx⟩ => ⟨x ⊔ x₀, le_sup_right, hP le_sup_left hx⟩⟩ +lemma exists_and_iff_of_monotone {P Q : α → Prop} (hP : Monotone P) (hQ : Monotone Q) : + ((∃ x, P x) ∧ ∃ x, Q x) ↔ (∃ x, P x ∧ Q x) := + ⟨fun ⟨⟨x, hPx⟩, ⟨y, hQx⟩⟩ ↦ ⟨x ⊔ y, ⟨hP le_sup_left hPx, hQ le_sup_right hQx⟩⟩, + fun ⟨x, hPx, hQx⟩ ↦ ⟨⟨x, hPx⟩, ⟨x, hQx⟩⟩⟩ + end SemilatticeSup section SemilatticeInf @@ -513,6 +524,11 @@ theorem exists_le_and_iff_exists {P : α → Prop} {x₀ : α} (hP : Antitone P) (∃ x, x ≤ x₀ ∧ P x) ↔ ∃ x, P x := exists_ge_and_iff_exists <| hP.dual_left +lemma exists_and_iff_of_antitone {P Q : α → Prop} (hP : Antitone P) (hQ : Antitone Q) : + ((∃ x, P x) ∧ ∃ x, Q x) ↔ (∃ x, P x ∧ Q x) := + ⟨fun ⟨⟨x, hPx⟩, ⟨y, hQx⟩⟩ ↦ ⟨x ⊓ y, ⟨hP inf_le_left hPx, hQ inf_le_right hQx⟩⟩, + fun ⟨x, hPx, hQx⟩ ↦ ⟨⟨x, hPx⟩, ⟨x, hQx⟩⟩⟩ + end SemilatticeInf end Logic diff --git a/Mathlib/Order/Bounds/Basic.lean b/Mathlib/Order/Bounds/Basic.lean index 86984514ba3e7..66d0f19bb54b8 100644 --- a/Mathlib/Order/Bounds/Basic.lean +++ b/Mathlib/Order/Bounds/Basic.lean @@ -3,26 +3,18 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Yury Kudryashov -/ -import Mathlib.Order.Interval.Set.Basic -import Mathlib.Data.Set.NAry +import Mathlib.Order.Bounds.Defs import Mathlib.Order.Directed +import Mathlib.Order.Interval.Set.Basic /-! # Upper / lower bounds -In this file we define: -* `upperBounds`, `lowerBounds` : the set of upper bounds (resp., lower bounds) of a set; -* `BddAbove s`, `BddBelow s` : the set `s` is bounded above (resp., below), i.e., the set of upper - (resp., lower) bounds of `s` is nonempty; -* `IsLeast s a`, `IsGreatest s a` : `a` is a least (resp., greatest) element of `s`; - for a partial order, it is unique if exists; -* `IsLUB s a`, `IsGLB s a` : `a` is a least upper bound (resp., a greatest lower bound) - of `s`; for a partial order, it is unique if exists. -We also prove various lemmas about monotonicity, behaviour under `∪`, `∩`, `insert`, and provide -formulas for `∅`, `univ`, and intervals. +In this file we prove various lemmas about upper/lower bounds of a set: +monotonicity, behaviour under `∪`, `∩`, `insert`, +and provide formulas for `∅`, `univ`, and intervals. -/ - open Function Set open OrderDual (toDual ofDual) @@ -33,44 +25,7 @@ variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} section -variable [Preorder α] [Preorder β] {s t : Set α} {a b : α} - -/-! -### Definitions --/ - - -/-- The set of upper bounds of a set. -/ -def upperBounds (s : Set α) : Set α := - { x | ∀ ⦃a⦄, a ∈ s → a ≤ x } - -/-- The set of lower bounds of a set. -/ -def lowerBounds (s : Set α) : Set α := - { x | ∀ ⦃a⦄, a ∈ s → x ≤ a } - -/-- A set is bounded above if there exists an upper bound. -/ -def BddAbove (s : Set α) := - (upperBounds s).Nonempty - -/-- A set is bounded below if there exists a lower bound. -/ -def BddBelow (s : Set α) := - (lowerBounds s).Nonempty - -/-- `a` is a least element of a set `s`; for a partial order, it is unique if exists. -/ -def IsLeast (s : Set α) (a : α) : Prop := - a ∈ s ∧ a ∈ lowerBounds s - -/-- `a` is a greatest element of a set `s`; for a partial order, it is unique if exists. -/ -def IsGreatest (s : Set α) (a : α) : Prop := - a ∈ s ∧ a ∈ upperBounds s - -/-- `a` is a least upper bound of a set `s`; for a partial order, it is unique if exists. -/ -def IsLUB (s : Set α) : α → Prop := - IsLeast (upperBounds s) - -/-- `a` is a greatest lower bound of a set `s`; for a partial order, it is unique if exists. -/ -def IsGLB (s : Set α) : α → Prop := - IsGreatest (lowerBounds s) +variable [Preorder α] {s t : Set α} {a b : α} theorem mem_upperBounds : a ∈ upperBounds s ↔ ∀ x ∈ s, x ≤ a := Iff.rfl @@ -608,7 +563,7 @@ section variable [SemilatticeSup γ] [DenselyOrdered γ] theorem isGLB_Ioo {a b : γ} (h : a < b) : IsGLB (Ioo a b) a := - ⟨fun x hx => hx.1.le, fun x hx => by + ⟨fun _ hx => hx.1.le, fun x hx => by rcases eq_or_lt_of_le (le_sup_right : a ≤ x ⊔ a) with h₁ | h₂ · exact h₁.symm ▸ le_sup_left obtain ⟨y, lty, ylt⟩ := exists_between h₂ @@ -949,484 +904,3 @@ theorem IsGLB.exists_between' (h : IsGLB s a) (h' : a ∉ s) (hb : a < b) : ∃ ⟨c, hcs, hac.lt_of_ne fun hac => h' <| hac.symm ▸ hcs, hcb⟩ end LinearOrder - -/-! -### Images of upper/lower bounds under monotone functions --/ - - -namespace MonotoneOn - -variable [Preorder α] [Preorder β] {f : α → β} {s t : Set α} {a : α} - -theorem mem_upperBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) (Has : a ∈ upperBounds s) - (Hat : a ∈ t) : f a ∈ upperBounds (f '' s) := - forall_mem_image.2 fun _ H => Hf (Hst H) Hat (Has H) - -theorem mem_upperBounds_image_self (Hf : MonotoneOn f t) : - a ∈ upperBounds t → a ∈ t → f a ∈ upperBounds (f '' t) := - Hf.mem_upperBounds_image subset_rfl - -theorem mem_lowerBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) (Has : a ∈ lowerBounds s) - (Hat : a ∈ t) : f a ∈ lowerBounds (f '' s) := - forall_mem_image.2 fun _ H => Hf Hat (Hst H) (Has H) - -theorem mem_lowerBounds_image_self (Hf : MonotoneOn f t) : - a ∈ lowerBounds t → a ∈ t → f a ∈ lowerBounds (f '' t) := - Hf.mem_lowerBounds_image subset_rfl - -theorem image_upperBounds_subset_upperBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) : - f '' (upperBounds s ∩ t) ⊆ upperBounds (f '' s) := by - rintro _ ⟨a, ha, rfl⟩ - exact Hf.mem_upperBounds_image Hst ha.1 ha.2 - -theorem image_lowerBounds_subset_lowerBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) : - f '' (lowerBounds s ∩ t) ⊆ lowerBounds (f '' s) := - Hf.dual.image_upperBounds_subset_upperBounds_image Hst - -/-- The image under a monotone function on a set `t` of a subset which has an upper bound in `t` - is bounded above. -/ -theorem map_bddAbove (Hf : MonotoneOn f t) (Hst : s ⊆ t) : - (upperBounds s ∩ t).Nonempty → BddAbove (f '' s) := fun ⟨C, hs, ht⟩ => - ⟨f C, Hf.mem_upperBounds_image Hst hs ht⟩ - -/-- The image under a monotone function on a set `t` of a subset which has a lower bound in `t` - is bounded below. -/ -theorem map_bddBelow (Hf : MonotoneOn f t) (Hst : s ⊆ t) : - (lowerBounds s ∩ t).Nonempty → BddBelow (f '' s) := fun ⟨C, hs, ht⟩ => - ⟨f C, Hf.mem_lowerBounds_image Hst hs ht⟩ - -/-- A monotone map sends a least element of a set to a least element of its image. -/ -theorem map_isLeast (Hf : MonotoneOn f t) (Ha : IsLeast t a) : IsLeast (f '' t) (f a) := - ⟨mem_image_of_mem _ Ha.1, Hf.mem_lowerBounds_image_self Ha.2 Ha.1⟩ - -/-- A monotone map sends a greatest element of a set to a greatest element of its image. -/ -theorem map_isGreatest (Hf : MonotoneOn f t) (Ha : IsGreatest t a) : IsGreatest (f '' t) (f a) := - ⟨mem_image_of_mem _ Ha.1, Hf.mem_upperBounds_image_self Ha.2 Ha.1⟩ - -end MonotoneOn - -namespace AntitoneOn - -variable [Preorder α] [Preorder β] {f : α → β} {s t : Set α} {a : α} - -theorem mem_upperBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) (Has : a ∈ lowerBounds s) : - a ∈ t → f a ∈ upperBounds (f '' s) := - Hf.dual_right.mem_lowerBounds_image Hst Has - -theorem mem_upperBounds_image_self (Hf : AntitoneOn f t) : - a ∈ lowerBounds t → a ∈ t → f a ∈ upperBounds (f '' t) := - Hf.dual_right.mem_lowerBounds_image_self - -theorem mem_lowerBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : - a ∈ upperBounds s → a ∈ t → f a ∈ lowerBounds (f '' s) := - Hf.dual_right.mem_upperBounds_image Hst - -theorem mem_lowerBounds_image_self (Hf : AntitoneOn f t) : - a ∈ upperBounds t → a ∈ t → f a ∈ lowerBounds (f '' t) := - Hf.dual_right.mem_upperBounds_image_self - -theorem image_lowerBounds_subset_upperBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : - f '' (lowerBounds s ∩ t) ⊆ upperBounds (f '' s) := - Hf.dual_right.image_lowerBounds_subset_lowerBounds_image Hst - -theorem image_upperBounds_subset_lowerBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : - f '' (upperBounds s ∩ t) ⊆ lowerBounds (f '' s) := - Hf.dual_right.image_upperBounds_subset_upperBounds_image Hst - -/-- The image under an antitone function of a set which is bounded above is bounded below. -/ -theorem map_bddAbove (Hf : AntitoneOn f t) (Hst : s ⊆ t) : - (upperBounds s ∩ t).Nonempty → BddBelow (f '' s) := - Hf.dual_right.map_bddAbove Hst - -/-- The image under an antitone function of a set which is bounded below is bounded above. -/ -theorem map_bddBelow (Hf : AntitoneOn f t) (Hst : s ⊆ t) : - (lowerBounds s ∩ t).Nonempty → BddAbove (f '' s) := - Hf.dual_right.map_bddBelow Hst - -/-- An antitone map sends a greatest element of a set to a least element of its image. -/ -theorem map_isGreatest (Hf : AntitoneOn f t) : IsGreatest t a → IsLeast (f '' t) (f a) := - Hf.dual_right.map_isGreatest - -/-- An antitone map sends a least element of a set to a greatest element of its image. -/ -theorem map_isLeast (Hf : AntitoneOn f t) : IsLeast t a → IsGreatest (f '' t) (f a) := - Hf.dual_right.map_isLeast - -end AntitoneOn - -namespace Monotone - -variable [Preorder α] [Preorder β] {f : α → β} (Hf : Monotone f) {a : α} {s : Set α} - -include Hf - -theorem mem_upperBounds_image (Ha : a ∈ upperBounds s) : f a ∈ upperBounds (f '' s) := - forall_mem_image.2 fun _ H => Hf (Ha H) - -theorem mem_lowerBounds_image (Ha : a ∈ lowerBounds s) : f a ∈ lowerBounds (f '' s) := - forall_mem_image.2 fun _ H => Hf (Ha H) - -theorem image_upperBounds_subset_upperBounds_image : - f '' upperBounds s ⊆ upperBounds (f '' s) := by - rintro _ ⟨a, ha, rfl⟩ - exact Hf.mem_upperBounds_image ha - -theorem image_lowerBounds_subset_lowerBounds_image : f '' lowerBounds s ⊆ lowerBounds (f '' s) := - Hf.dual.image_upperBounds_subset_upperBounds_image - -/-- The image under a monotone function of a set which is bounded above is bounded above. See also -`BddAbove.image2`. -/ -theorem map_bddAbove : BddAbove s → BddAbove (f '' s) - | ⟨C, hC⟩ => ⟨f C, Hf.mem_upperBounds_image hC⟩ - -/-- The image under a monotone function of a set which is bounded below is bounded below. See also -`BddBelow.image2`. -/ -theorem map_bddBelow : BddBelow s → BddBelow (f '' s) - | ⟨C, hC⟩ => ⟨f C, Hf.mem_lowerBounds_image hC⟩ - -/-- A monotone map sends a least element of a set to a least element of its image. -/ -theorem map_isLeast (Ha : IsLeast s a) : IsLeast (f '' s) (f a) := - ⟨mem_image_of_mem _ Ha.1, Hf.mem_lowerBounds_image Ha.2⟩ - -/-- A monotone map sends a greatest element of a set to a greatest element of its image. -/ -theorem map_isGreatest (Ha : IsGreatest s a) : IsGreatest (f '' s) (f a) := - ⟨mem_image_of_mem _ Ha.1, Hf.mem_upperBounds_image Ha.2⟩ - -end Monotone - -namespace Antitone - -variable [Preorder α] [Preorder β] {f : α → β} (hf : Antitone f) {a : α} {s : Set α} - -include hf - -theorem mem_upperBounds_image : a ∈ lowerBounds s → f a ∈ upperBounds (f '' s) := - hf.dual_right.mem_lowerBounds_image - -theorem mem_lowerBounds_image : a ∈ upperBounds s → f a ∈ lowerBounds (f '' s) := - hf.dual_right.mem_upperBounds_image - -theorem image_lowerBounds_subset_upperBounds_image : f '' lowerBounds s ⊆ upperBounds (f '' s) := - hf.dual_right.image_lowerBounds_subset_lowerBounds_image - -theorem image_upperBounds_subset_lowerBounds_image : f '' upperBounds s ⊆ lowerBounds (f '' s) := - hf.dual_right.image_upperBounds_subset_upperBounds_image - -/-- The image under an antitone function of a set which is bounded above is bounded below. -/ -theorem map_bddAbove : BddAbove s → BddBelow (f '' s) := - hf.dual_right.map_bddAbove - -/-- The image under an antitone function of a set which is bounded below is bounded above. -/ -theorem map_bddBelow : BddBelow s → BddAbove (f '' s) := - hf.dual_right.map_bddBelow - -/-- An antitone map sends a greatest element of a set to a least element of its image. -/ -theorem map_isGreatest : IsGreatest s a → IsLeast (f '' s) (f a) := - hf.dual_right.map_isGreatest - -/-- An antitone map sends a least element of a set to a greatest element of its image. -/ -theorem map_isLeast : IsLeast s a → IsGreatest (f '' s) (f a) := - hf.dual_right.map_isLeast - -end Antitone - -section Image2 - -variable [Preorder α] [Preorder β] [Preorder γ] {f : α → β → γ} {s : Set α} {t : Set β} {a : α} - {b : β} - -section MonotoneMonotone - -variable (h₀ : ∀ b, Monotone (swap f b)) (h₁ : ∀ a, Monotone (f a)) - -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 - -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 - -theorem image2_upperBounds_upperBounds_subset : - image2 f (upperBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ mem_upperBounds_image2 h₀ h₁ ha hb - -theorem image2_lowerBounds_lowerBounds_subset : - image2 f (lowerBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ mem_lowerBounds_image2 h₀ h₁ ha hb - -/-- See also `Monotone.map_bddAbove`. -/ -protected theorem BddAbove.image2 : - BddAbove s → BddAbove t → BddAbove (image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_upperBounds_image2 h₀ h₁ ha hb⟩ - -/-- See also `Monotone.map_bddBelow`. -/ -protected theorem BddBelow.image2 : - BddBelow s → BddBelow t → BddBelow (image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_lowerBounds_image2 h₀ h₁ ha hb⟩ - -protected theorem IsGreatest.image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : - IsGreatest (image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, mem_upperBounds_image2 h₀ h₁ ha.2 hb.2⟩ - -protected theorem IsLeast.image2 (ha : IsLeast s a) (hb : IsLeast t b) : - IsLeast (image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, mem_lowerBounds_image2 h₀ h₁ ha.2 hb.2⟩ - -end MonotoneMonotone - -section MonotoneAntitone - -variable (h₀ : ∀ b, Monotone (swap f b)) (h₁ : ∀ a, Antitone (f a)) - -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 - -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 - -theorem image2_upperBounds_lowerBounds_subset_upperBounds_image2 : - image2 f (upperBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb - -theorem image2_lowerBounds_upperBounds_subset_lowerBounds_image2 : - image2 f (lowerBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb - -theorem BddAbove.bddAbove_image2_of_bddBelow : - BddAbove s → BddBelow t → BddAbove (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb⟩ - -theorem BddBelow.bddBelow_image2_of_bddAbove : - BddBelow s → BddAbove t → BddBelow (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb⟩ - -theorem IsGreatest.isGreatest_image2_of_isLeast (ha : IsGreatest s a) (hb : IsLeast t b) : - IsGreatest (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, - mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ - -theorem IsLeast.isLeast_image2_of_isGreatest (ha : IsLeast s a) (hb : IsGreatest t b) : - IsLeast (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, - mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ - -end MonotoneAntitone - -section AntitoneAntitone - -variable (h₀ : ∀ b, Antitone (swap f b)) (h₁ : ∀ a, Antitone (f a)) - -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 - -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 - -theorem image2_upperBounds_upperBounds_subset_upperBounds_image2 : - image2 f (lowerBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb - -theorem image2_lowerBounds_lowerBounds_subset_lowerBounds_image2 : - image2 f (upperBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb - -theorem BddBelow.image2_bddAbove : BddBelow s → BddBelow t → BddAbove (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb⟩ - -theorem BddAbove.image2_bddBelow : BddAbove s → BddAbove t → BddBelow (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb⟩ - -theorem IsLeast.isGreatest_image2 (ha : IsLeast s a) (hb : IsLeast t b) : - IsGreatest (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ - -theorem IsGreatest.isLeast_image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : - IsLeast (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ - -end AntitoneAntitone - -section AntitoneMonotone - -variable (h₀ : ∀ b, Antitone (swap f b)) (h₁ : ∀ a, Monotone (f a)) - -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 - -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 - -theorem image2_lowerBounds_upperBounds_subset_upperBounds_image2 : - image2 f (lowerBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb - -theorem image2_upperBounds_lowerBounds_subset_lowerBounds_image2 : - image2 f (upperBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := - image2_subset_iff.2 fun _ ha _ hb ↦ - mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb - -theorem BddBelow.bddAbove_image2_of_bddAbove : - BddBelow s → BddAbove t → BddAbove (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb⟩ - -theorem BddAbove.bddBelow_image2_of_bddAbove : - BddAbove s → BddBelow t → BddBelow (Set.image2 f s t) := by - rintro ⟨a, ha⟩ ⟨b, hb⟩ - exact ⟨f a b, mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb⟩ - -theorem IsLeast.isGreatest_image2_of_isGreatest (ha : IsLeast s a) (hb : IsGreatest t b) : - IsGreatest (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, - mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ - -theorem IsGreatest.isLeast_image2_of_isLeast (ha : IsGreatest s a) (hb : IsLeast t b) : - IsLeast (Set.image2 f s t) (f a b) := - ⟨mem_image2_of_mem ha.1 hb.1, - mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ - -end AntitoneMonotone - -end Image2 - -section Prod - -variable {α β : Type*} [Preorder α] [Preorder β] - -lemma bddAbove_prod {s : Set (α × β)} : - BddAbove s ↔ BddAbove (Prod.fst '' s) ∧ BddAbove (Prod.snd '' s) := - ⟨fun ⟨p, hp⟩ ↦ ⟨⟨p.1, forall_mem_image.2 fun _q hq ↦ (hp hq).1⟩, - ⟨p.2, forall_mem_image.2 fun _q hq ↦ (hp hq).2⟩⟩, - fun ⟨⟨x, hx⟩, ⟨y, hy⟩⟩ ↦ ⟨⟨x, y⟩, fun _p hp ↦ - ⟨hx <| mem_image_of_mem _ hp, hy <| mem_image_of_mem _ hp⟩⟩⟩ - -lemma bddBelow_prod {s : Set (α × β)} : - BddBelow s ↔ BddBelow (Prod.fst '' s) ∧ BddBelow (Prod.snd '' s) := - bddAbove_prod (α := αᵒᵈ) (β := βᵒᵈ) - -lemma bddAbove_range_prod {F : ι → α × β} : - BddAbove (range F) ↔ BddAbove (range <| Prod.fst ∘ F) ∧ BddAbove (range <| Prod.snd ∘ F) := by - simp only [bddAbove_prod, ← range_comp] - -lemma bddBelow_range_prod {F : ι → α × β} : - BddBelow (range F) ↔ BddBelow (range <| Prod.fst ∘ F) ∧ BddBelow (range <| Prod.snd ∘ F) := - bddAbove_range_prod (α := αᵒᵈ) (β := βᵒᵈ) - -theorem isLUB_prod {s : Set (α × β)} (p : α × β) : - IsLUB s p ↔ IsLUB (Prod.fst '' s) p.1 ∧ IsLUB (Prod.snd '' s) p.2 := by - refine - ⟨fun H => - ⟨⟨monotone_fst.mem_upperBounds_image H.1, fun a ha => ?_⟩, - ⟨monotone_snd.mem_upperBounds_image H.1, fun a ha => ?_⟩⟩, - fun H => ⟨?_, ?_⟩⟩ - · suffices h : (a, p.2) ∈ upperBounds s from (H.2 h).1 - exact fun q hq => ⟨ha <| mem_image_of_mem _ hq, (H.1 hq).2⟩ - · suffices h : (p.1, a) ∈ upperBounds s from (H.2 h).2 - exact fun q hq => ⟨(H.1 hq).1, ha <| mem_image_of_mem _ hq⟩ - · exact fun q hq => ⟨H.1.1 <| mem_image_of_mem _ hq, H.2.1 <| mem_image_of_mem _ hq⟩ - · exact fun q hq => - ⟨H.1.2 <| monotone_fst.mem_upperBounds_image hq, - H.2.2 <| monotone_snd.mem_upperBounds_image hq⟩ - -theorem isGLB_prod {s : Set (α × β)} (p : α × β) : - IsGLB s p ↔ IsGLB (Prod.fst '' s) p.1 ∧ IsGLB (Prod.snd '' s) p.2 := - @isLUB_prod αᵒᵈ βᵒᵈ _ _ _ _ - -end Prod - - -section Pi - -variable {π : α → Type*} [∀ a, Preorder (π a)] - -lemma bddAbove_pi {s : Set (∀ a, π a)} : - BddAbove s ↔ ∀ a, BddAbove (Function.eval a '' s) := - ⟨fun ⟨f, hf⟩ a ↦ ⟨f a, forall_mem_image.2 fun _ hg ↦ hf hg a⟩, - fun h ↦ ⟨fun a ↦ (h a).some, fun _ hg a ↦ (h a).some_mem <| mem_image_of_mem _ hg⟩⟩ - -lemma bddBelow_pi {s : Set (∀ a, π a)} : - BddBelow s ↔ ∀ a, BddBelow (Function.eval a '' s) := - bddAbove_pi (π := fun a ↦ (π a)ᵒᵈ) - -lemma bddAbove_range_pi {F : ι → ∀ a, π a} : - BddAbove (range F) ↔ ∀ a, BddAbove (range fun i ↦ F i a) := by - simp only [bddAbove_pi, ← range_comp] - rfl - -lemma bddBelow_range_pi {F : ι → ∀ a, π a} : - BddBelow (range F) ↔ ∀ a, BddBelow (range fun i ↦ F i a) := - bddAbove_range_pi (π := fun a ↦ (π a)ᵒᵈ) - -theorem isLUB_pi {s : Set (∀ a, π a)} {f : ∀ a, π a} : - IsLUB s f ↔ ∀ a, IsLUB (Function.eval a '' s) (f a) := by - classical - refine - ⟨fun H a => ⟨(Function.monotone_eval a).mem_upperBounds_image H.1, fun b hb => ?_⟩, fun H => - ⟨?_, ?_⟩⟩ - · suffices h : Function.update f a b ∈ upperBounds s from Function.update_same a b f ▸ H.2 h a - exact fun g hg => le_update_iff.2 ⟨hb <| mem_image_of_mem _ hg, fun i _ => H.1 hg i⟩ - · exact fun g hg a => (H a).1 (mem_image_of_mem _ hg) - · exact fun g hg a => (H a).2 ((Function.monotone_eval a).mem_upperBounds_image hg) - -theorem isGLB_pi {s : Set (∀ a, π a)} {f : ∀ a, π a} : - IsGLB s f ↔ ∀ a, IsGLB (Function.eval a '' s) (f a) := - @isLUB_pi α (fun a => (π a)ᵒᵈ) _ s f - -end Pi - -theorem IsGLB.of_image [Preorder α] [Preorder β] {f : α → β} (hf : ∀ {x y}, f x ≤ f y ↔ x ≤ y) - {s : Set α} {x : α} (hx : IsGLB (f '' s) (f x)) : IsGLB s x := - ⟨fun _ hy => hf.1 <| hx.1 <| mem_image_of_mem _ hy, fun _ hy => - hf.1 <| hx.2 <| Monotone.mem_lowerBounds_image (fun _ _ => hf.2) hy⟩ - -theorem IsLUB.of_image [Preorder α] [Preorder β] {f : α → β} (hf : ∀ {x y}, f x ≤ f y ↔ x ≤ y) - {s : Set α} {x : α} (hx : IsLUB (f '' s) (f x)) : IsLUB s x := - ⟨fun _ hy => hf.1 <| hx.1 <| mem_image_of_mem _ hy, fun _ hy => - hf.1 <| hx.2 <| Monotone.mem_upperBounds_image (fun _ _ => hf.2) hy⟩ - -lemma BddAbove.range_mono [Preorder β] {f : α → β} (g : α → β) (h : ∀ a, f a ≤ g a) - (hbdd : BddAbove (range g)) : BddAbove (range f) := by - obtain ⟨C, hC⟩ := hbdd - use C - rintro - ⟨x, rfl⟩ - exact (h x).trans (hC <| mem_range_self x) - -lemma BddBelow.range_mono [Preorder β] (f : α → β) {g : α → β} (h : ∀ a, f a ≤ g a) - (hbdd : BddBelow (range f)) : BddBelow (range g) := - BddAbove.range_mono (β := βᵒᵈ) f h hbdd - -lemma BddAbove.range_comp {γ : Type*} [Preorder β] [Preorder γ] {f : α → β} {g : β → γ} - (hf : BddAbove (range f)) (hg : Monotone g) : BddAbove (range (fun x => g (f x))) := by - change BddAbove (range (g ∘ f)) - simpa only [Set.range_comp] using hg.map_bddAbove hf - -lemma BddBelow.range_comp {γ : Type*} [Preorder β] [Preorder γ] {f : α → β} {g : β → γ} - (hf : BddBelow (range f)) (hg : Monotone g) : BddBelow (range (fun x => g (f x))) := by - change BddBelow (range (g ∘ f)) - simpa only [Set.range_comp] using hg.map_bddBelow hf diff --git a/Mathlib/Order/Bounds/Defs.lean b/Mathlib/Order/Bounds/Defs.lean new file mode 100644 index 0000000000000..3ade7ed08f03d --- /dev/null +++ b/Mathlib/Order/Bounds/Defs.lean @@ -0,0 +1,55 @@ +/- +Copyright (c) 2017 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Yury Kudryashov +-/ +import Mathlib.Data.Set.Defs +import Mathlib.Tactic.TypeStar + +/-! +# Definitions about upper/lower bounds + +In this file we define: +* `upperBounds`, `lowerBounds` : the set of upper bounds (resp., lower bounds) of a set; +* `BddAbove s`, `BddBelow s` : the set `s` is bounded above (resp., below), i.e., the set of upper + (resp., lower) bounds of `s` is nonempty; +* `IsLeast s a`, `IsGreatest s a` : `a` is a least (resp., greatest) element of `s`; + for a partial order, it is unique if exists; +* `IsLUB s a`, `IsGLB s a` : `a` is a least upper bound (resp., a greatest lower bound) + of `s`; for a partial order, it is unique if exists. +-/ + +variable {α : Type*} [LE α] + +/-- The set of upper bounds of a set. -/ +def upperBounds (s : Set α) : Set α := + { x | ∀ ⦃a⦄, a ∈ s → a ≤ x } + +/-- The set of lower bounds of a set. -/ +def lowerBounds (s : Set α) : Set α := + { x | ∀ ⦃a⦄, a ∈ s → x ≤ a } + +/-- A set is bounded above if there exists an upper bound. -/ +def BddAbove (s : Set α) := + (upperBounds s).Nonempty + +/-- A set is bounded below if there exists a lower bound. -/ +def BddBelow (s : Set α) := + (lowerBounds s).Nonempty + +/-- `a` is a least element of a set `s`; for a partial order, it is unique if exists. -/ +def IsLeast (s : Set α) (a : α) : Prop := + a ∈ s ∧ a ∈ lowerBounds s + +/-- `a` is a greatest element of a set `s`; for a partial order, it is unique if exists. -/ +def IsGreatest (s : Set α) (a : α) : Prop := + a ∈ s ∧ a ∈ upperBounds s + +/-- `a` is a least upper bound of a set `s`; for a partial order, it is unique if exists. -/ +def IsLUB (s : Set α) : α → Prop := + IsLeast (upperBounds s) + +/-- `a` is a greatest lower bound of a set `s`; for a partial order, it is unique if exists. -/ +def IsGLB (s : Set α) : α → Prop := + IsGreatest (lowerBounds s) + diff --git a/Mathlib/Order/Bounds/Image.lean b/Mathlib/Order/Bounds/Image.lean new file mode 100644 index 0000000000000..910c466332520 --- /dev/null +++ b/Mathlib/Order/Bounds/Image.lean @@ -0,0 +1,498 @@ +/- +Copyright (c) 2017 Paul Lezeau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Yury Kudryashov, Paul Lezeau +-/ +import Mathlib.Data.Set.NAry +import Mathlib.Order.Bounds.Defs + +/-! + +# Images of upper/lower bounds under monotone functions + +In this file we prove various results about the behaviour of bounds under monotone/antitone maps. +-/ + +open Function Set + +open OrderDual (toDual ofDual) + +universe u v w x + +variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} + +namespace MonotoneOn + +variable [Preorder α] [Preorder β] {f : α → β} {s t : Set α} {a : α} + +theorem mem_upperBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) (Has : a ∈ upperBounds s) + (Hat : a ∈ t) : f a ∈ upperBounds (f '' s) := + forall_mem_image.2 fun _ H => Hf (Hst H) Hat (Has H) + +theorem mem_upperBounds_image_self (Hf : MonotoneOn f t) : + a ∈ upperBounds t → a ∈ t → f a ∈ upperBounds (f '' t) := + Hf.mem_upperBounds_image subset_rfl + +theorem mem_lowerBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) (Has : a ∈ lowerBounds s) + (Hat : a ∈ t) : f a ∈ lowerBounds (f '' s) := + forall_mem_image.2 fun _ H => Hf Hat (Hst H) (Has H) + +theorem mem_lowerBounds_image_self (Hf : MonotoneOn f t) : + a ∈ lowerBounds t → a ∈ t → f a ∈ lowerBounds (f '' t) := + Hf.mem_lowerBounds_image subset_rfl + +theorem image_upperBounds_subset_upperBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) : + f '' (upperBounds s ∩ t) ⊆ upperBounds (f '' s) := by + rintro _ ⟨a, ha, rfl⟩ + exact Hf.mem_upperBounds_image Hst ha.1 ha.2 + +theorem image_lowerBounds_subset_lowerBounds_image (Hf : MonotoneOn f t) (Hst : s ⊆ t) : + f '' (lowerBounds s ∩ t) ⊆ lowerBounds (f '' s) := + Hf.dual.image_upperBounds_subset_upperBounds_image Hst + +/-- The image under a monotone function on a set `t` of a subset which has an upper bound in `t` + is bounded above. -/ +theorem map_bddAbove (Hf : MonotoneOn f t) (Hst : s ⊆ t) : + (upperBounds s ∩ t).Nonempty → BddAbove (f '' s) := fun ⟨C, hs, ht⟩ => + ⟨f C, Hf.mem_upperBounds_image Hst hs ht⟩ + +/-- The image under a monotone function on a set `t` of a subset which has a lower bound in `t` + is bounded below. -/ +theorem map_bddBelow (Hf : MonotoneOn f t) (Hst : s ⊆ t) : + (lowerBounds s ∩ t).Nonempty → BddBelow (f '' s) := fun ⟨C, hs, ht⟩ => + ⟨f C, Hf.mem_lowerBounds_image Hst hs ht⟩ + +/-- A monotone map sends a least element of a set to a least element of its image. -/ +theorem map_isLeast (Hf : MonotoneOn f t) (Ha : IsLeast t a) : IsLeast (f '' t) (f a) := + ⟨mem_image_of_mem _ Ha.1, Hf.mem_lowerBounds_image_self Ha.2 Ha.1⟩ + +/-- A monotone map sends a greatest element of a set to a greatest element of its image. -/ +theorem map_isGreatest (Hf : MonotoneOn f t) (Ha : IsGreatest t a) : IsGreatest (f '' t) (f a) := + ⟨mem_image_of_mem _ Ha.1, Hf.mem_upperBounds_image_self Ha.2 Ha.1⟩ + +end MonotoneOn + +namespace AntitoneOn + +variable [Preorder α] [Preorder β] {f : α → β} {s t : Set α} {a : α} + +theorem mem_upperBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) (Has : a ∈ lowerBounds s) : + a ∈ t → f a ∈ upperBounds (f '' s) := + Hf.dual_right.mem_lowerBounds_image Hst Has + +theorem mem_upperBounds_image_self (Hf : AntitoneOn f t) : + a ∈ lowerBounds t → a ∈ t → f a ∈ upperBounds (f '' t) := + Hf.dual_right.mem_lowerBounds_image_self + +theorem mem_lowerBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : + a ∈ upperBounds s → a ∈ t → f a ∈ lowerBounds (f '' s) := + Hf.dual_right.mem_upperBounds_image Hst + +theorem mem_lowerBounds_image_self (Hf : AntitoneOn f t) : + a ∈ upperBounds t → a ∈ t → f a ∈ lowerBounds (f '' t) := + Hf.dual_right.mem_upperBounds_image_self + +theorem image_lowerBounds_subset_upperBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : + f '' (lowerBounds s ∩ t) ⊆ upperBounds (f '' s) := + Hf.dual_right.image_lowerBounds_subset_lowerBounds_image Hst + +theorem image_upperBounds_subset_lowerBounds_image (Hf : AntitoneOn f t) (Hst : s ⊆ t) : + f '' (upperBounds s ∩ t) ⊆ lowerBounds (f '' s) := + Hf.dual_right.image_upperBounds_subset_upperBounds_image Hst + +/-- The image under an antitone function of a set which is bounded above is bounded below. -/ +theorem map_bddAbove (Hf : AntitoneOn f t) (Hst : s ⊆ t) : + (upperBounds s ∩ t).Nonempty → BddBelow (f '' s) := + Hf.dual_right.map_bddAbove Hst + +/-- The image under an antitone function of a set which is bounded below is bounded above. -/ +theorem map_bddBelow (Hf : AntitoneOn f t) (Hst : s ⊆ t) : + (lowerBounds s ∩ t).Nonempty → BddAbove (f '' s) := + Hf.dual_right.map_bddBelow Hst + +/-- An antitone map sends a greatest element of a set to a least element of its image. -/ +theorem map_isGreatest (Hf : AntitoneOn f t) : IsGreatest t a → IsLeast (f '' t) (f a) := + Hf.dual_right.map_isGreatest + +/-- An antitone map sends a least element of a set to a greatest element of its image. -/ +theorem map_isLeast (Hf : AntitoneOn f t) : IsLeast t a → IsGreatest (f '' t) (f a) := + Hf.dual_right.map_isLeast + +end AntitoneOn + +namespace Monotone + +variable [Preorder α] [Preorder β] {f : α → β} (Hf : Monotone f) {a : α} {s : Set α} + +include Hf + +theorem mem_upperBounds_image (Ha : a ∈ upperBounds s) : f a ∈ upperBounds (f '' s) := + forall_mem_image.2 fun _ H => Hf (Ha H) + +theorem mem_lowerBounds_image (Ha : a ∈ lowerBounds s) : f a ∈ lowerBounds (f '' s) := + forall_mem_image.2 fun _ H => Hf (Ha H) + +theorem image_upperBounds_subset_upperBounds_image : + f '' upperBounds s ⊆ upperBounds (f '' s) := by + rintro _ ⟨a, ha, rfl⟩ + exact Hf.mem_upperBounds_image ha + +theorem image_lowerBounds_subset_lowerBounds_image : f '' lowerBounds s ⊆ lowerBounds (f '' s) := + Hf.dual.image_upperBounds_subset_upperBounds_image + +/-- The image under a monotone function of a set which is bounded above is bounded above. See also +`BddAbove.image2`. -/ +theorem map_bddAbove : BddAbove s → BddAbove (f '' s) + | ⟨C, hC⟩ => ⟨f C, Hf.mem_upperBounds_image hC⟩ + +/-- The image under a monotone function of a set which is bounded below is bounded below. See also +`BddBelow.image2`. -/ +theorem map_bddBelow : BddBelow s → BddBelow (f '' s) + | ⟨C, hC⟩ => ⟨f C, Hf.mem_lowerBounds_image hC⟩ + +/-- A monotone map sends a least element of a set to a least element of its image. -/ +theorem map_isLeast (Ha : IsLeast s a) : IsLeast (f '' s) (f a) := + ⟨mem_image_of_mem _ Ha.1, Hf.mem_lowerBounds_image Ha.2⟩ + +/-- A monotone map sends a greatest element of a set to a greatest element of its image. -/ +theorem map_isGreatest (Ha : IsGreatest s a) : IsGreatest (f '' s) (f a) := + ⟨mem_image_of_mem _ Ha.1, Hf.mem_upperBounds_image Ha.2⟩ + +end Monotone + +namespace Antitone + +variable [Preorder α] [Preorder β] {f : α → β} (hf : Antitone f) {a : α} {s : Set α} + +include hf + +theorem mem_upperBounds_image : a ∈ lowerBounds s → f a ∈ upperBounds (f '' s) := + hf.dual_right.mem_lowerBounds_image + +theorem mem_lowerBounds_image : a ∈ upperBounds s → f a ∈ lowerBounds (f '' s) := + hf.dual_right.mem_upperBounds_image + +theorem image_lowerBounds_subset_upperBounds_image : f '' lowerBounds s ⊆ upperBounds (f '' s) := + hf.dual_right.image_lowerBounds_subset_lowerBounds_image + +theorem image_upperBounds_subset_lowerBounds_image : f '' upperBounds s ⊆ lowerBounds (f '' s) := + hf.dual_right.image_upperBounds_subset_upperBounds_image + +/-- The image under an antitone function of a set which is bounded above is bounded below. -/ +theorem map_bddAbove : BddAbove s → BddBelow (f '' s) := + hf.dual_right.map_bddAbove + +/-- The image under an antitone function of a set which is bounded below is bounded above. -/ +theorem map_bddBelow : BddBelow s → BddAbove (f '' s) := + hf.dual_right.map_bddBelow + +/-- An antitone map sends a greatest element of a set to a least element of its image. -/ +theorem map_isGreatest : IsGreatest s a → IsLeast (f '' s) (f a) := + hf.dual_right.map_isGreatest + +/-- An antitone map sends a least element of a set to a greatest element of its image. -/ +theorem map_isLeast : IsLeast s a → IsGreatest (f '' s) (f a) := + hf.dual_right.map_isLeast + +end Antitone + +section Image2 + +variable [Preorder α] [Preorder β] [Preorder γ] {f : α → β → γ} {s : Set α} {t : Set β} {a : α} + {b : β} + +section MonotoneMonotone + +variable (h₀ : ∀ b, Monotone (swap f b)) (h₁ : ∀ a, Monotone (f a)) + +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 + +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 + +theorem image2_upperBounds_upperBounds_subset : + image2 f (upperBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ mem_upperBounds_image2 h₀ h₁ ha hb + +theorem image2_lowerBounds_lowerBounds_subset : + image2 f (lowerBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ mem_lowerBounds_image2 h₀ h₁ ha hb + +/-- See also `Monotone.map_bddAbove`. -/ +protected theorem BddAbove.image2 : + BddAbove s → BddAbove t → BddAbove (image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_upperBounds_image2 h₀ h₁ ha hb⟩ + +/-- See also `Monotone.map_bddBelow`. -/ +protected theorem BddBelow.image2 : + BddBelow s → BddBelow t → BddBelow (image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_lowerBounds_image2 h₀ h₁ ha hb⟩ + +protected theorem IsGreatest.image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : + IsGreatest (image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, mem_upperBounds_image2 h₀ h₁ ha.2 hb.2⟩ + +protected theorem IsLeast.image2 (ha : IsLeast s a) (hb : IsLeast t b) : + IsLeast (image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, mem_lowerBounds_image2 h₀ h₁ ha.2 hb.2⟩ + +end MonotoneMonotone + +section MonotoneAntitone + +variable (h₀ : ∀ b, Monotone (swap f b)) (h₁ : ∀ a, Antitone (f a)) + +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 + +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 + +theorem image2_upperBounds_lowerBounds_subset_upperBounds_image2 : + image2 f (upperBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb + +theorem image2_lowerBounds_upperBounds_subset_lowerBounds_image2 : + image2 f (lowerBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb + +theorem BddAbove.bddAbove_image2_of_bddBelow : + BddAbove s → BddBelow t → BddAbove (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb⟩ + +theorem BddBelow.bddBelow_image2_of_bddAbove : + BddBelow s → BddAbove t → BddBelow (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb⟩ + +theorem IsGreatest.isGreatest_image2_of_isLeast (ha : IsGreatest s a) (hb : IsLeast t b) : + IsGreatest (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, + mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ + +theorem IsLeast.isLeast_image2_of_isGreatest (ha : IsLeast s a) (hb : IsGreatest t b) : + IsLeast (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ + +end MonotoneAntitone + +section AntitoneAntitone + +variable (h₀ : ∀ b, Antitone (swap f b)) (h₁ : ∀ a, Antitone (f a)) + +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 + +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 + +theorem image2_upperBounds_upperBounds_subset_upperBounds_image2 : + image2 f (lowerBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb + +theorem image2_lowerBounds_lowerBounds_subset_lowerBounds_image2 : + image2 f (upperBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb + +theorem BddBelow.image2_bddAbove : BddBelow s → BddBelow t → BddAbove (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb⟩ + +theorem BddAbove.image2_bddBelow : BddAbove s → BddAbove t → BddBelow (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb⟩ + +theorem IsLeast.isGreatest_image2 (ha : IsLeast s a) (hb : IsLeast t b) : + IsGreatest (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ + +theorem IsGreatest.isLeast_image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : + IsLeast (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ + +end AntitoneAntitone + +section AntitoneMonotone + +variable (h₀ : ∀ b, Antitone (swap f b)) (h₁ : ∀ a, Monotone (f a)) + +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 + +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 + +theorem image2_lowerBounds_upperBounds_subset_upperBounds_image2 : + image2 f (lowerBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb + +theorem image2_upperBounds_lowerBounds_subset_lowerBounds_image2 : + image2 f (upperBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb + +theorem BddBelow.bddAbove_image2_of_bddAbove : + BddBelow s → BddAbove t → BddAbove (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb⟩ + +theorem BddAbove.bddBelow_image2_of_bddAbove : + BddAbove s → BddBelow t → BddBelow (Set.image2 f s t) := by + rintro ⟨a, ha⟩ ⟨b, hb⟩ + exact ⟨f a b, mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb⟩ + +theorem IsLeast.isGreatest_image2_of_isGreatest (ha : IsLeast s a) (hb : IsGreatest t b) : + IsGreatest (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, + mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha.2 hb.2⟩ + +theorem IsGreatest.isLeast_image2_of_isLeast (ha : IsGreatest s a) (hb : IsLeast t b) : + IsLeast (Set.image2 f s t) (f a b) := + ⟨mem_image2_of_mem ha.1 hb.1, + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha.2 hb.2⟩ + +end AntitoneMonotone + +end Image2 + +section Prod + +variable {α β : Type*} [Preorder α] [Preorder β] + +lemma bddAbove_prod {s : Set (α × β)} : + BddAbove s ↔ BddAbove (Prod.fst '' s) ∧ BddAbove (Prod.snd '' s) := + ⟨fun ⟨p, hp⟩ ↦ ⟨⟨p.1, forall_mem_image.2 fun _q hq ↦ (hp hq).1⟩, + ⟨p.2, forall_mem_image.2 fun _q hq ↦ (hp hq).2⟩⟩, + fun ⟨⟨x, hx⟩, ⟨y, hy⟩⟩ ↦ ⟨⟨x, y⟩, fun _p hp ↦ + ⟨hx <| mem_image_of_mem _ hp, hy <| mem_image_of_mem _ hp⟩⟩⟩ + +lemma bddBelow_prod {s : Set (α × β)} : + BddBelow s ↔ BddBelow (Prod.fst '' s) ∧ BddBelow (Prod.snd '' s) := + bddAbove_prod (α := αᵒᵈ) (β := βᵒᵈ) + +lemma bddAbove_range_prod {F : ι → α × β} : + BddAbove (range F) ↔ BddAbove (range <| Prod.fst ∘ F) ∧ BddAbove (range <| Prod.snd ∘ F) := by + simp only [bddAbove_prod, ← range_comp] + +lemma bddBelow_range_prod {F : ι → α × β} : + BddBelow (range F) ↔ BddBelow (range <| Prod.fst ∘ F) ∧ BddBelow (range <| Prod.snd ∘ F) := + bddAbove_range_prod (α := αᵒᵈ) (β := βᵒᵈ) + +theorem isLUB_prod {s : Set (α × β)} (p : α × β) : + IsLUB s p ↔ IsLUB (Prod.fst '' s) p.1 ∧ IsLUB (Prod.snd '' s) p.2 := by + refine + ⟨fun H => + ⟨⟨monotone_fst.mem_upperBounds_image H.1, fun a ha => ?_⟩, + ⟨monotone_snd.mem_upperBounds_image H.1, fun a ha => ?_⟩⟩, + fun H => ⟨?_, ?_⟩⟩ + · suffices h : (a, p.2) ∈ upperBounds s from (H.2 h).1 + exact fun q hq => ⟨ha <| mem_image_of_mem _ hq, (H.1 hq).2⟩ + · suffices h : (p.1, a) ∈ upperBounds s from (H.2 h).2 + exact fun q hq => ⟨(H.1 hq).1, ha <| mem_image_of_mem _ hq⟩ + · exact fun q hq => ⟨H.1.1 <| mem_image_of_mem _ hq, H.2.1 <| mem_image_of_mem _ hq⟩ + · exact fun q hq => + ⟨H.1.2 <| monotone_fst.mem_upperBounds_image hq, + H.2.2 <| monotone_snd.mem_upperBounds_image hq⟩ + +theorem isGLB_prod {s : Set (α × β)} (p : α × β) : + IsGLB s p ↔ IsGLB (Prod.fst '' s) p.1 ∧ IsGLB (Prod.snd '' s) p.2 := + @isLUB_prod αᵒᵈ βᵒᵈ _ _ _ _ + +end Prod + + +section Pi + +variable {π : α → Type*} [∀ a, Preorder (π a)] + +lemma bddAbove_pi {s : Set (∀ a, π a)} : + BddAbove s ↔ ∀ a, BddAbove (Function.eval a '' s) := + ⟨fun ⟨f, hf⟩ a ↦ ⟨f a, forall_mem_image.2 fun _ hg ↦ hf hg a⟩, + fun h ↦ ⟨fun a ↦ (h a).some, fun _ hg a ↦ (h a).some_mem <| mem_image_of_mem _ hg⟩⟩ + +lemma bddBelow_pi {s : Set (∀ a, π a)} : + BddBelow s ↔ ∀ a, BddBelow (Function.eval a '' s) := + bddAbove_pi (π := fun a ↦ (π a)ᵒᵈ) + +lemma bddAbove_range_pi {F : ι → ∀ a, π a} : + BddAbove (range F) ↔ ∀ a, BddAbove (range fun i ↦ F i a) := by + simp only [bddAbove_pi, ← range_comp] + rfl + +lemma bddBelow_range_pi {F : ι → ∀ a, π a} : + BddBelow (range F) ↔ ∀ a, BddBelow (range fun i ↦ F i a) := + bddAbove_range_pi (π := fun a ↦ (π a)ᵒᵈ) + +theorem isLUB_pi {s : Set (∀ a, π a)} {f : ∀ a, π a} : + IsLUB s f ↔ ∀ a, IsLUB (Function.eval a '' s) (f a) := by + classical + refine + ⟨fun H a => ⟨(Function.monotone_eval a).mem_upperBounds_image H.1, fun b hb => ?_⟩, fun H => + ⟨?_, ?_⟩⟩ + · suffices h : Function.update f a b ∈ upperBounds s from Function.update_same a b f ▸ H.2 h a + exact fun g hg => le_update_iff.2 ⟨hb <| mem_image_of_mem _ hg, fun i _ => H.1 hg i⟩ + · exact fun g hg a => (H a).1 (mem_image_of_mem _ hg) + · exact fun g hg a => (H a).2 ((Function.monotone_eval a).mem_upperBounds_image hg) + +theorem isGLB_pi {s : Set (∀ a, π a)} {f : ∀ a, π a} : + IsGLB s f ↔ ∀ a, IsGLB (Function.eval a '' s) (f a) := + @isLUB_pi α (fun a => (π a)ᵒᵈ) _ s f + +end Pi + +theorem IsGLB.of_image [Preorder α] [Preorder β] {f : α → β} (hf : ∀ {x y}, f x ≤ f y ↔ x ≤ y) + {s : Set α} {x : α} (hx : IsGLB (f '' s) (f x)) : IsGLB s x := + ⟨fun _ hy => hf.1 <| hx.1 <| mem_image_of_mem _ hy, fun _ hy => + hf.1 <| hx.2 <| Monotone.mem_lowerBounds_image (fun _ _ => hf.2) hy⟩ + +theorem IsLUB.of_image [Preorder α] [Preorder β] {f : α → β} (hf : ∀ {x y}, f x ≤ f y ↔ x ≤ y) + {s : Set α} {x : α} (hx : IsLUB (f '' s) (f x)) : IsLUB s x := + ⟨fun _ hy => hf.1 <| hx.1 <| mem_image_of_mem _ hy, fun _ hy => + hf.1 <| hx.2 <| Monotone.mem_upperBounds_image (fun _ _ => hf.2) hy⟩ + +lemma BddAbove.range_mono [Preorder β] {f : α → β} (g : α → β) (h : ∀ a, f a ≤ g a) + (hbdd : BddAbove (range g)) : BddAbove (range f) := by + obtain ⟨C, hC⟩ := hbdd + use C + rintro - ⟨x, rfl⟩ + exact (h x).trans (hC <| mem_range_self x) + +lemma BddBelow.range_mono [Preorder β] (f : α → β) {g : α → β} (h : ∀ a, f a ≤ g a) + (hbdd : BddBelow (range f)) : BddBelow (range g) := + BddAbove.range_mono (β := βᵒᵈ) f h hbdd + +lemma BddAbove.range_comp {γ : Type*} [Preorder β] [Preorder γ] {f : α → β} {g : β → γ} + (hf : BddAbove (range f)) (hg : Monotone g) : BddAbove (range (fun x => g (f x))) := by + change BddAbove (range (g ∘ f)) + simpa only [Set.range_comp] using hg.map_bddAbove hf + +lemma BddBelow.range_comp {γ : Type*} [Preorder β] [Preorder γ] {f : α → β} {g : β → γ} + (hf : BddBelow (range f)) (hg : Monotone g) : BddBelow (range (fun x => g (f x))) := by + change BddBelow (range (g ∘ f)) + simpa only [Set.range_comp] using hg.map_bddBelow hf diff --git a/Mathlib/Order/Bounds/OrderIso.lean b/Mathlib/Order/Bounds/OrderIso.lean index 913266a83c0cc..d3fda94252a64 100644 --- a/Mathlib/Order/Bounds/OrderIso.lean +++ b/Mathlib/Order/Bounds/OrderIso.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Yury Kudryashov -/ -import Mathlib.Order.Bounds.Basic +import Mathlib.Order.Bounds.Image import Mathlib.Order.Hom.Set /-! diff --git a/Mathlib/Order/Category/BddDistLat.lean b/Mathlib/Order/Category/BddDistLat.lean index 55bd9eb054737..3ead1db99b5ec 100644 --- a/Mathlib/Order/Category/BddDistLat.lean +++ b/Mathlib/Order/Category/BddDistLat.lean @@ -68,7 +68,7 @@ instance hasForgetToDistLat : HasForget₂ BddDistLat DistLat where -- Porting note: was `⟨X⟩` -- see https://github.com/leanprover-community/mathlib4/issues/4998 { obj := fun X => { α := X } - map := fun {X Y} => BoundedLatticeHom.toLatticeHom } + map := fun {_ _} => BoundedLatticeHom.toLatticeHom } instance hasForgetToBddLat : HasForget₂ BddDistLat BddLat := InducedCategory.hasForget₂ toBddLat @@ -91,7 +91,7 @@ def Iso.mk {α β : BddDistLat.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : BddDistLat ⥤ BddDistLat where obj X := of Xᵒᵈ - map {X Y} := BoundedLatticeHom.dual + map {_ _} := BoundedLatticeHom.dual /-- The equivalence between `BddDistLat` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] diff --git a/Mathlib/Order/Category/BddLat.lean b/Mathlib/Order/Category/BddLat.lean index 45b49280d263e..b1f4e2931ddcb 100644 --- a/Mathlib/Order/Category/BddLat.lean +++ b/Mathlib/Order/Category/BddLat.lean @@ -71,23 +71,23 @@ instance : ConcreteCategory BddLat where instance hasForgetToBddOrd : HasForget₂ BddLat BddOrd where forget₂ := { obj := fun X => BddOrd.of X - map := fun {X Y} => BoundedLatticeHom.toBoundedOrderHom } + map := fun {_ _} => BoundedLatticeHom.toBoundedOrderHom } instance hasForgetToLat : HasForget₂ BddLat Lat where forget₂ := -- Porting note: was `⟨X⟩`, see https://github.com/leanprover-community/mathlib4/issues/4998 { obj := fun X => {α := X} - map := fun {X Y} => BoundedLatticeHom.toLatticeHom } + map := fun {_ _} => BoundedLatticeHom.toLatticeHom } instance hasForgetToSemilatSup : HasForget₂ BddLat SemilatSupCat where forget₂ := { obj := fun X => ⟨X⟩ - map := fun {X Y} => BoundedLatticeHom.toSupBotHom } + map := fun {_ _} => BoundedLatticeHom.toSupBotHom } instance hasForgetToSemilatInf : HasForget₂ BddLat SemilatInfCat where forget₂ := { obj := fun X => ⟨X⟩ - map := fun {X Y} => BoundedLatticeHom.toInfTopHom } + map := fun {_ _} => BoundedLatticeHom.toInfTopHom } @[simp] theorem coe_forget_to_bddOrd (X : BddLat) : ↥((forget₂ BddLat BddOrd).obj X) = ↥X := @@ -135,7 +135,7 @@ def Iso.mk {α β : BddLat.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : BddLat ⥤ BddLat where obj X := of Xᵒᵈ - map {X Y} := BoundedLatticeHom.dual + map {_ _} := BoundedLatticeHom.dual /-- The equivalence between `BddLat` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] @@ -177,7 +177,7 @@ def latToBddLat : Lat.{u} ⥤ BddLat where functor from `Lat` to `BddLat`. -/ def latToBddLatForgetAdjunction : latToBddLat.{u} ⊣ forget₂ BddLat Lat := Adjunction.mkOfHomEquiv - { homEquiv := fun X Y => + { homEquiv := fun X _ => { toFun := fun f => { toFun := f ∘ some ∘ some map_sup' := fun a b => (congr_arg f <| by rfl).trans (f.map_sup' _ _) @@ -188,15 +188,15 @@ def latToBddLatForgetAdjunction : latToBddLat.{u} ⊣ forget₂ BddLat Lat := match a with | none => f.map_top'.symm | some none => f.map_bot'.symm - | some (some a) => rfl - right_inv := fun f => LatticeHom.ext fun a => rfl } - homEquiv_naturality_left_symm := fun f g => + | some (some _) => rfl + right_inv := fun _ => LatticeHom.ext fun _ => rfl } + homEquiv_naturality_left_symm := fun _ _ => BoundedLatticeHom.ext fun a => match a with | none => rfl | some none => rfl - | some (some a) => rfl - homEquiv_naturality_right := fun f g => LatticeHom.ext fun a => rfl } + | some (some _) => rfl + homEquiv_naturality_right := fun _ _ => LatticeHom.ext fun _ => rfl } /-- `latToBddLat` and `OrderDual` commute. -/ -- Porting note: the `simpNF` linter is not happy as it simplifies something that does not diff --git a/Mathlib/Order/Category/BddOrd.lean b/Mathlib/Order/Category/BddOrd.lean index 2bab27e953235..89e1c988b0e68 100644 --- a/Mathlib/Order/Category/BddOrd.lean +++ b/Mathlib/Order/Category/BddOrd.lean @@ -68,7 +68,7 @@ instance concreteCategory : ConcreteCategory BddOrd where instance hasForgetToPartOrd : HasForget₂ BddOrd PartOrd where forget₂ := { obj := fun X => X.toPartOrd - map := fun {X Y} => BoundedOrderHom.toOrderHom } + map := fun {_ _} => BoundedOrderHom.toOrderHom } instance hasForgetToBipointed : HasForget₂ BddOrd Bipointed where forget₂ := @@ -80,7 +80,7 @@ instance hasForgetToBipointed : HasForget₂ BddOrd Bipointed where @[simps] def dual : BddOrd ⥤ BddOrd where obj X := of Xᵒᵈ - map {X Y} := BoundedOrderHom.dual + map {_ _} := BoundedOrderHom.dual /-- Constructs an equivalence between bounded orders from an order isomorphism between them. -/ @[simps] diff --git a/Mathlib/Order/Category/BoolAlg.lean b/Mathlib/Order/Category/BoolAlg.lean index e90e6e55aed90..42c66fcc0c103 100644 --- a/Mathlib/Order/Category/BoolAlg.lean +++ b/Mathlib/Order/Category/BoolAlg.lean @@ -86,7 +86,7 @@ def Iso.mk {α β : BoolAlg.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : BoolAlg ⥤ BoolAlg where obj X := of Xᵒᵈ - map {X Y} := BoundedLatticeHom.dual + map {_ _} := BoundedLatticeHom.dual /-- The equivalence between `BoolAlg` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] diff --git a/Mathlib/Order/Category/CompleteLat.lean b/Mathlib/Order/Category/CompleteLat.lean index 801b4f828293c..f888d4a94b0f5 100644 --- a/Mathlib/Order/Category/CompleteLat.lean +++ b/Mathlib/Order/Category/CompleteLat.lean @@ -54,7 +54,7 @@ instance : ConcreteCategory CompleteLat := by instance hasForgetToBddLat : HasForget₂ CompleteLat BddLat where forget₂ := { obj := fun X => BddLat.of X - map := fun {X Y} => CompleteLatticeHom.toBoundedLatticeHom } + map := fun {_ _} => CompleteLatticeHom.toBoundedLatticeHom } forget_comp := rfl /-- Constructs an isomorphism of complete lattices from an order isomorphism between them. -/ @@ -69,7 +69,7 @@ def Iso.mk {α β : CompleteLat.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : CompleteLat ⥤ CompleteLat where obj X := of Xᵒᵈ - map {X Y} := CompleteLatticeHom.dual + map {_ _} := CompleteLatticeHom.dual /-- The equivalence between `CompleteLat` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] diff --git a/Mathlib/Order/Category/FinBddDistLat.lean b/Mathlib/Order/Category/FinBddDistLat.lean index b3dab1d7a23b9..0747d3df364a1 100644 --- a/Mathlib/Order/Category/FinBddDistLat.lean +++ b/Mathlib/Order/Category/FinBddDistLat.lean @@ -82,7 +82,7 @@ example {X Y : FinBddDistLat} : (X ⟶ Y) = BoundedLatticeHom X Y := @[simps] def dual : FinBddDistLat ⥤ FinBddDistLat where obj X := of Xᵒᵈ - map {X Y} := BoundedLatticeHom.dual + map {_ _} := BoundedLatticeHom.dual /-- The equivalence between `FinBddDistLat` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] diff --git a/Mathlib/Order/Category/FinBoolAlg.lean b/Mathlib/Order/Category/FinBoolAlg.lean index 174cc8c0a1c03..58791b31ec741 100644 --- a/Mathlib/Order/Category/FinBoolAlg.lean +++ b/Mathlib/Order/Category/FinBoolAlg.lean @@ -126,7 +126,7 @@ def Iso.mk {α β : FinBoolAlg.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : FinBoolAlg ⥤ FinBoolAlg where obj X := of Xᵒᵈ - map {X Y} := BoundedLatticeHom.dual + map {_ _} := BoundedLatticeHom.dual /-- The equivalence between `FinBoolAlg` and itself induced by `OrderDual` both ways. -/ @[simps functor inverse] diff --git a/Mathlib/Order/Category/FinPartOrd.lean b/Mathlib/Order/Category/FinPartOrd.lean index 5b90c8fa7d59d..e520e1b739927 100644 --- a/Mathlib/Order/Category/FinPartOrd.lean +++ b/Mathlib/Order/Category/FinPartOrd.lean @@ -83,7 +83,7 @@ def Iso.mk {α β : FinPartOrd.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : FinPartOrd ⥤ FinPartOrd where obj X := of Xᵒᵈ - map {X Y} := OrderHom.dual + map {_ _} := OrderHom.dual /-- The equivalence between `FinPartOrd` and itself induced by `OrderDual` both ways. -/ @[simps] diff --git a/Mathlib/Order/Category/Frm.lean b/Mathlib/Order/Category/Frm.lean index 4ece737931718..f09b81f241c54 100644 --- a/Mathlib/Order/Category/Frm.lean +++ b/Mathlib/Order/Category/Frm.lean @@ -68,7 +68,7 @@ instance : ConcreteCategory Frm := by instance hasForgetToLat : HasForget₂ Frm Lat where forget₂ := { obj := fun X => ⟨X, _⟩ - map := fun {X Y} => FrameHom.toLatticeHom } + map := fun {_ _} => FrameHom.toLatticeHom } /-- Constructs an isomorphism of frames from an order isomorphism between them. -/ @[simps] @@ -89,7 +89,7 @@ end Frm def topCatOpToFrm : TopCatᵒᵖ ⥤ Frm where obj X := Frm.of (Opens (unop X : TopCat)) map f := Opens.comap <| Quiver.Hom.unop f - map_id X := Opens.comap_id + map_id _ := Opens.comap_id -- Note, `CompHaus` is too strong. We only need `T0Space`. instance CompHausOpToFrame.faithful : (compHausToTop.op ⋙ topCatOpToFrm.{u}).Faithful := diff --git a/Mathlib/Order/Category/NonemptyFinLinOrd.lean b/Mathlib/Order/Category/NonemptyFinLinOrd.lean index 02b1bfe0adc42..29ef2f1dc61d2 100644 --- a/Mathlib/Order/Category/NonemptyFinLinOrd.lean +++ b/Mathlib/Order/Category/NonemptyFinLinOrd.lean @@ -86,7 +86,7 @@ instance hasForgetToLinOrd : HasForget₂ NonemptyFinLinOrd LinOrd := instance hasForgetToFinPartOrd : HasForget₂ NonemptyFinLinOrd FinPartOrd where forget₂ := { obj := fun X => FinPartOrd.of X - map := @fun X Y => id } + map := @fun _ _ => id } /-- Constructs an equivalence between nonempty finite linear orders from an order isomorphism between them. -/ @@ -121,7 +121,6 @@ instance {A B : NonemptyFinLinOrd.{u}} : FunLike (A ⟶ B) A B where ext x exact congr_fun h x --- porting note (#10670): this instance was not necessary in mathlib instance {A B : NonemptyFinLinOrd.{u}} : OrderHomClass (A ⟶ B) A B where map_rel f _ _ h := f.monotone h @@ -235,3 +234,6 @@ def nonemptyFinLinOrdDualCompForgetToFinPartOrd : forget₂ NonemptyFinLinOrd FinPartOrd ⋙ FinPartOrd.dual where hom := { app := fun X => OrderHom.id } inv := { app := fun X => OrderHom.id } + +/-- The generating arrow `i ⟶ i+1` in the category `Fin n`.-/ +def Fin.hom_succ {n} (i : Fin n) : i.castSucc ⟶ i.succ := homOfLE (Fin.castSucc_le_succ i) diff --git a/Mathlib/Order/Category/OmegaCompletePartialOrder.lean b/Mathlib/Order/Category/OmegaCompletePartialOrder.lean index c92cacfbb73ae..7f8ab62dfc249 100644 --- a/Mathlib/Order/Category/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/Category/OmegaCompletePartialOrder.lean @@ -78,14 +78,14 @@ def product {J : Type v} (f : J → ωCPO.{v}) : Fan f := def isProduct (J : Type v) (f : J → ωCPO) : IsLimit (product f) where lift s := -- Porting note: Original proof didn't have `.toFun` - ⟨⟨fun t j => (s.π.app ⟨j⟩).toFun t, fun x y h j => (s.π.app ⟨j⟩).monotone h⟩, + ⟨⟨fun t j => (s.π.app ⟨j⟩).toFun t, fun _ _ h j => (s.π.app ⟨j⟩).monotone h⟩, fun x => funext fun j => (s.π.app ⟨j⟩).continuous x⟩ uniq s m w := by - ext t; funext j -- Porting note: Originally `ext t j` + ext t; funext j -- Porting note (#11041): Originally `ext t j` change m.toFun t j = (s.π.app ⟨j⟩).toFun t rw [← w ⟨j⟩] rfl - fac s j := rfl + fac _ _ := rfl instance (J : Type v) (f : J → ωCPO.{v}) : HasProduct f := HasLimit.mk ⟨_, isProduct _ f⟩ @@ -98,7 +98,7 @@ instance omegaCompletePartialOrderEqualizer {α β : Type*} [OmegaCompletePartia OmegaCompletePartialOrder.subtype _ fun c hc => by rw [f.continuous, g.continuous] congr 1 - apply OrderHom.ext; funext x -- Porting note: Originally `ext` + apply OrderHom.ext; funext x -- Porting note (#11041): Originally `ext` apply hc _ ⟨_, rfl⟩ namespace HasEqualizers @@ -119,10 +119,10 @@ def isEqualizer {X Y : ωCPO.{v}} (f g : X ⟶ Y) : IsLimit (equalizer f g) := Fork.IsLimit.mk' _ fun s => -- Porting note: Changed `s.ι x` to `s.ι.toFun x` ⟨{ toFun := fun x => ⟨s.ι.toFun x, by apply ContinuousHom.congr_fun s.condition⟩ - monotone' := fun x y h => s.ι.monotone h + monotone' := fun _ _ h => s.ι.monotone h map_ωSup' := fun x => Subtype.ext (s.ι.continuous x) }, by ext; rfl, fun hm => by - apply ContinuousHom.ext _ _ fun x => Subtype.ext ?_ -- Porting note: Originally `ext` + apply ContinuousHom.ext _ _ fun x => Subtype.ext ?_ -- Porting note (#11041): Originally `ext` apply ContinuousHom.congr_fun hm⟩ end HasEqualizers diff --git a/Mathlib/Order/Category/Semilat.lean b/Mathlib/Order/Category/Semilat.lean index 1d896ad622d2d..9456230940237 100644 --- a/Mathlib/Order/Category/Semilat.lean +++ b/Mathlib/Order/Category/Semilat.lean @@ -152,7 +152,7 @@ def Iso.mk {α β : SemilatSupCat.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : SemilatSupCat ⥤ SemilatInfCat where obj X := SemilatInfCat.of Xᵒᵈ - map {X Y} := SupBotHom.dual + map {_ _} := SupBotHom.dual end SemilatSupCat @@ -170,7 +170,7 @@ def Iso.mk {α β : SemilatInfCat.{u}} (e : α ≃o β) : α ≅ β where @[simps] def dual : SemilatInfCat ⥤ SemilatSupCat where obj X := SemilatSupCat.of Xᵒᵈ - map {X Y} := InfTopHom.dual + map {_ _} := InfTopHom.dual end SemilatInfCat diff --git a/Mathlib/Order/Chain.lean b/Mathlib/Order/Chain.lean index 2f086f7f4f276..f83b31886b200 100644 --- a/Mathlib/Order/Chain.lean +++ b/Mathlib/Order/Chain.lean @@ -52,7 +52,7 @@ 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₂ c₃ s t : Set α} {a b x y : α} +variable {r} {c c₁ c₂ s t : Set α} {a x y : α} theorem isChain_empty : IsChain r ∅ := Set.pairwise_empty _ @@ -279,8 +279,6 @@ instance : SetLike (Flag α) α where theorem ext : (s : Set α) = t → s = t := SetLike.ext' --- Porting note (#10618): `simp` can now prove this --- @[simp] theorem mem_coe_iff : a ∈ (s : Set α) ↔ a ∈ s := Iff.rfl diff --git a/Mathlib/Order/Circular.lean b/Mathlib/Order/Circular.lean index 3757b6709e94b..cf1950b1cf1c7 100644 --- a/Mathlib/Order/Circular.lean +++ b/Mathlib/Order/Circular.lean @@ -346,7 +346,7 @@ See note [reducible non-instances]. -/ abbrev Preorder.toCircularPreorder (α : Type*) [Preorder α] : CircularPreorder α where btw a b c := a ≤ b ∧ b ≤ c ∨ b ≤ c ∧ c ≤ a ∨ c ≤ a ∧ a ≤ b sbtw a b c := a < b ∧ b < c ∨ b < c ∧ c < a ∨ c < a ∧ a < b - btw_refl a := Or.inl ⟨le_rfl, le_rfl⟩ + btw_refl _ := Or.inl ⟨le_rfl, le_rfl⟩ btw_cyclic_left {a b c} h := by dsimp rwa [← or_assoc, or_comm] diff --git a/Mathlib/Order/Closure.lean b/Mathlib/Order/Closure.lean index 4005f3290f47d..0759232ea5236 100644 --- a/Mathlib/Order/Closure.lean +++ b/Mathlib/Order/Closure.lean @@ -202,7 +202,7 @@ theorem ext_isClosed (c₁ c₂ : ClosureOperator α) /-- A closure operator is equal to the closure operator obtained by feeding `c.closed` into the `ofPred` constructor. -/ theorem eq_ofPred_closed (c : ClosureOperator α) : - c = ofPred c c.IsClosed c.le_closure c.isClosed_closure fun x y ↦ closure_min := by + c = ofPred c c.IsClosed c.le_closure c.isClosed_closure fun _ _ ↦ closure_min := by ext rfl @@ -248,15 +248,15 @@ end SemilatticeSup section CompleteLattice -variable [CompleteLattice α] (c : ClosureOperator α) {p : α → Prop} +variable [CompleteLattice α] (c : ClosureOperator α) /-- Define a closure operator from a predicate that's preserved under infima. -/ @[simps!] def ofCompletePred (p : α → Prop) (hsinf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : ClosureOperator α := ofPred (fun a ↦ ⨅ b : {b // a ≤ b ∧ p b}, b) p - (fun a ↦ by set_option tactic.skipAssignedInstances false in simp [forall_swap]) - (fun a ↦ hsinf _ <| forall_mem_range.2 fun b ↦ b.2.2) - (fun a b hab hb ↦ iInf_le_of_le ⟨b, hab, hb⟩ le_rfl) + (fun a ↦ by simp [forall_swap]) + (fun _ ↦ hsinf _ <| forall_mem_range.2 fun b ↦ b.2.2) + (fun _ b hab hb ↦ iInf_le_of_le ⟨b, hab, hb⟩ le_rfl) theorem sInf_isClosed {c : ClosureOperator α} {S : Set α} (H : ∀ x ∈ S, c.IsClosed x) : c.IsClosed (sInf S) := diff --git a/Mathlib/Order/CompactlyGenerated/Basic.lean b/Mathlib/Order/CompactlyGenerated/Basic.lean index 60620cc7187cf..f3bc338a1d2ea 100644 --- a/Mathlib/Order/CompactlyGenerated/Basic.lean +++ b/Mathlib/Order/CompactlyGenerated/Basic.lean @@ -189,10 +189,10 @@ theorem isCompactElement_finsetSup {α β : Type*} [CompleteLattice α] {f : β specialize h d hemp hdir (le_trans (Finset.le_sup hps) hsup) simpa only [exists_prop] -theorem WellFounded.isSupFiniteCompact (h : WellFounded ((· > ·) : α → α → Prop)) : +theorem WellFoundedGT.isSupFiniteCompact [WellFoundedGT α] : IsSupFiniteCompact α := fun s => by let S := { x | ∃ t : Finset α, ↑t ⊆ s ∧ t.sup id = x } - obtain ⟨m, ⟨t, ⟨ht₁, rfl⟩⟩, hm⟩ := h.has_min S ⟨⊥, ∅, by simp⟩ + obtain ⟨m, ⟨t, ⟨ht₁, rfl⟩⟩, hm⟩ := wellFounded_gt.has_min S ⟨⊥, ∅, by simp⟩ refine ⟨t, ht₁, (sSup_le _ _ fun y hy => ?_).antisymm ?_⟩ · classical rw [eq_of_le_of_not_lt (Finset.sup_mono (t.subset_insert y)) @@ -212,25 +212,26 @@ theorem IsSupFiniteCompact.isSupClosedCompact (h : IsSupFiniteCompact α) : · rw [ht₂] exact hsc.finsetSup_mem h ht₁ -theorem IsSupClosedCompact.wellFounded (h : IsSupClosedCompact α) : - WellFounded ((· > ·) : α → α → Prop) := by - refine RelEmbedding.wellFounded_iff_no_descending_seq.mpr ⟨fun a => ?_⟩ - suffices sSup (Set.range a) ∈ Set.range a by - obtain ⟨n, hn⟩ := Set.mem_range.mp this - have h' : sSup (Set.range a) < a (n + 1) := by - change _ > _ - simp [← hn, a.map_rel_iff] - apply lt_irrefl (a (n + 1)) - apply lt_of_le_of_lt _ h' - apply le_sSup - apply Set.mem_range_self - apply h (Set.range a) - · use a 37 - apply Set.mem_range_self - · rintro x ⟨m, hm⟩ y ⟨n, hn⟩ - use m ⊔ n - rw [← hm, ← hn] - apply RelHomClass.map_sup a +theorem IsSupClosedCompact.wellFoundedGT (h : IsSupClosedCompact α) : + WellFoundedGT α where + wf := by + refine RelEmbedding.wellFounded_iff_no_descending_seq.mpr ⟨fun a => ?_⟩ + suffices sSup (Set.range a) ∈ Set.range a by + obtain ⟨n, hn⟩ := Set.mem_range.mp this + have h' : sSup (Set.range a) < a (n + 1) := by + change _ > _ + simp [← hn, a.map_rel_iff] + apply lt_irrefl (a (n + 1)) + apply lt_of_le_of_lt _ h' + apply le_sSup + apply Set.mem_range_self + apply h (Set.range a) + · use a 37 + apply Set.mem_range_self + · rintro x ⟨m, hm⟩ y ⟨n, hn⟩ + use m ⊔ n + rw [← hm, ← hn] + apply RelHomClass.map_sup a theorem isSupFiniteCompact_iff_all_elements_compact : IsSupFiniteCompact α ↔ ∀ k : α, IsCompactElement k := by @@ -247,39 +248,38 @@ theorem isSupFiniteCompact_iff_all_elements_compact : exact ⟨t, hts, this⟩ open List in -theorem wellFounded_characterisations : List.TFAE - [WellFounded ((· > ·) : α → α → Prop), - IsSupFiniteCompact α, IsSupClosedCompact α, ∀ k : α, IsCompactElement k] := by - tfae_have 1 → 2 := WellFounded.isSupFiniteCompact α +theorem wellFoundedGT_characterisations : List.TFAE + [WellFoundedGT α, IsSupFiniteCompact α, IsSupClosedCompact α, ∀ k : α, IsCompactElement k] := by + tfae_have 1 → 2 := @WellFoundedGT.isSupFiniteCompact α _ tfae_have 2 → 3 := IsSupFiniteCompact.isSupClosedCompact α - tfae_have 3 → 1 := IsSupClosedCompact.wellFounded α + tfae_have 3 → 1 := IsSupClosedCompact.wellFoundedGT α tfae_have 2 ↔ 4 := isSupFiniteCompact_iff_all_elements_compact α tfae_finish -theorem wellFounded_iff_isSupFiniteCompact : - WellFounded ((· > ·) : α → α → Prop) ↔ IsSupFiniteCompact α := - (wellFounded_characterisations α).out 0 1 +theorem wellFoundedGT_iff_isSupFiniteCompact : + WellFoundedGT α ↔ IsSupFiniteCompact α := + (wellFoundedGT_characterisations α).out 0 1 theorem isSupFiniteCompact_iff_isSupClosedCompact : IsSupFiniteCompact α ↔ IsSupClosedCompact α := - (wellFounded_characterisations α).out 1 2 + (wellFoundedGT_characterisations α).out 1 2 -theorem isSupClosedCompact_iff_wellFounded : - IsSupClosedCompact α ↔ WellFounded ((· > ·) : α → α → Prop) := - (wellFounded_characterisations α).out 2 0 +theorem isSupClosedCompact_iff_wellFoundedGT : + IsSupClosedCompact α ↔ WellFoundedGT α := + (wellFoundedGT_characterisations α).out 2 0 -alias ⟨_, IsSupFiniteCompact.wellFounded⟩ := wellFounded_iff_isSupFiniteCompact +alias ⟨_, IsSupFiniteCompact.wellFoundedGT⟩ := wellFoundedGT_iff_isSupFiniteCompact alias ⟨_, IsSupClosedCompact.isSupFiniteCompact⟩ := isSupFiniteCompact_iff_isSupClosedCompact -alias ⟨_, _root_.WellFounded.isSupClosedCompact⟩ := isSupClosedCompact_iff_wellFounded +alias ⟨_, WellFoundedGT.isSupClosedCompact⟩ := isSupClosedCompact_iff_wellFoundedGT variable {α} -theorem WellFounded.finite_of_setIndependent (h : WellFounded ((· > ·) : α → α → Prop)) {s : Set α} +theorem WellFoundedGT.finite_of_setIndependent [WellFoundedGT α] {s : Set α} (hs : SetIndependent s) : s.Finite := by classical refine Set.not_infinite.mp fun contra => ?_ - obtain ⟨t, ht₁, ht₂⟩ := WellFounded.isSupFiniteCompact α h s + obtain ⟨t, ht₁, ht₂⟩ := WellFoundedGT.isSupFiniteCompact α s replace contra : ∃ x : α, x ∈ s ∧ x ≠ ⊥ ∧ x ∉ t := by have : (s \ (insert ⊥ t : Finset α)).Infinite := contra.diff (Finset.finite_toSet _) obtain ⟨x, hx₁, hx₂⟩ := this.nonempty @@ -292,14 +292,36 @@ theorem WellFounded.finite_of_setIndependent (h : WellFounded ((· > ·) : α rw [← hs, eq_comm, inf_eq_left] exact le_sSup _ _ hx₀ -theorem WellFounded.finite_ne_bot_of_independent (hwf : WellFounded ((· > ·) : α → α → Prop)) +theorem WellFoundedGT.finite_ne_bot_of_independent [WellFoundedGT α] {ι : Type*} {t : ι → α} (ht : Independent t) : Set.Finite {i | t i ≠ ⊥} := by refine Finite.of_finite_image (Finite.subset ?_ (image_subset_range t _)) ht.injOn - exact WellFounded.finite_of_setIndependent hwf ht.setIndependent_range + exact WellFoundedGT.finite_of_setIndependent ht.setIndependent_range -theorem WellFounded.finite_of_independent (hwf : WellFounded ((· > ·) : α → α → Prop)) {ι : Type*} +theorem WellFoundedGT.finite_of_independent [WellFoundedGT α] {ι : Type*} {t : ι → α} (ht : Independent t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Finite ι := - haveI := (WellFounded.finite_of_setIndependent hwf ht.setIndependent_range).to_subtype + haveI := (WellFoundedGT.finite_of_setIndependent ht.setIndependent_range).to_subtype + Finite.of_injective_finite_range (ht.injective h_ne_bot) + +theorem WellFoundedLT.finite_of_setIndependent [WellFoundedLT α] {s : Set α} + (hs : SetIndependent s) : s.Finite := by + by_contra inf + let e := (Infinite.diff inf <| finite_singleton ⊥).to_subtype.natEmbedding + let a n := ⨆ i ≥ n, (e i).1 + have sup_le n : (e n).1 ⊔ a (n + 1) ≤ a n := sup_le_iff.mpr ⟨le_iSup₂_of_le n le_rfl le_rfl, + iSup₂_le fun i hi ↦ le_iSup₂_of_le i (n.le_succ.trans hi) le_rfl⟩ + have lt n : a (n + 1) < a n := (Disjoint.right_lt_sup_of_left_ne_bot + ((hs (e n).2.1).mono_right <| iSup₂_le fun i hi ↦ le_sSup _ _ ?_) (e n).2.2).trans_le (sup_le n) + · exact (RelEmbedding.natGT a lt).not_wellFounded_of_decreasing_seq wellFounded_lt + exact ⟨(e i).2.1, fun h ↦ n.lt_succ_self.not_le <| hi.trans_eq <| e.2 <| Subtype.val_injective h⟩ + +theorem WellFoundedLT.finite_ne_bot_of_independent [WellFoundedLT α] + {ι : Type*} {t : ι → α} (ht : Independent t) : Set.Finite {i | t i ≠ ⊥} := by + refine Finite.of_finite_image (Finite.subset ?_ (image_subset_range t _)) ht.injOn + exact WellFoundedLT.finite_of_setIndependent ht.setIndependent_range + +theorem WellFoundedLT.finite_of_independent [WellFoundedLT α] {ι : Type*} + {t : ι → α} (ht : Independent t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Finite ι := + haveI := (WellFoundedLT.finite_of_setIndependent ht.setIndependent_range).to_subtype Finite.of_injective_finite_range (ht.injective h_ne_bot) end CompleteLattice @@ -313,7 +335,7 @@ class IsCompactlyGenerated (α : Type*) [CompleteLattice α] : Prop where section -variable [IsCompactlyGenerated α] {a b : α} {s : Set α} +variable [IsCompactlyGenerated α] {a : α} {s : Set α} @[simp] theorem sSup_compact_le_eq (b) : @@ -328,7 +350,7 @@ theorem sSup_compact_eq_top : sSup { a : α | CompleteLattice.IsCompactElement a theorem le_iff_compact_le_imp {a b : α} : a ≤ b ↔ ∀ c : α, CompleteLattice.IsCompactElement c → c ≤ a → c ≤ b := - ⟨fun ab c _ ca => le_trans ca ab, fun h => by + ⟨fun ab _ _ ca => le_trans ca ab, fun h => by rw [← sSup_compact_le_eq a, ← sSup_compact_le_eq b] exact sSup_le_sSup fun c hc => ⟨hc.1, h c hc.1 hc.2⟩⟩ @@ -394,7 +416,7 @@ theorem inf_sSup_eq_iSup_inf_sup_finset : theorem CompleteLattice.setIndependent_iff_finite {s : Set α} : CompleteLattice.SetIndependent s ↔ ∀ t : Finset α, ↑t ⊆ s → CompleteLattice.SetIndependent (↑t : Set α) := - ⟨fun hs t ht => hs.mono ht, fun h a ha => by + ⟨fun hs _ ht => hs.mono ht, fun h a ha => by rw [disjoint_iff, inf_sSup_eq_iSup_inf_sup_finset, iSup_eq_bot] intro t rw [iSup_eq_bot, Finset.sup_id_eq_sSup] @@ -452,12 +474,35 @@ end namespace CompleteLattice -theorem isCompactlyGenerated_of_wellFounded (h : WellFounded ((· > ·) : α → α → Prop)) : +theorem isCompactlyGenerated_of_wellFoundedGT [h : WellFoundedGT α] : IsCompactlyGenerated α := by - rw [wellFounded_iff_isSupFiniteCompact, isSupFiniteCompact_iff_all_elements_compact] at h + rw [wellFoundedGT_iff_isSupFiniteCompact, isSupFiniteCompact_iff_all_elements_compact] at h -- x is the join of the set of compact elements {x} exact ⟨fun x => ⟨{x}, ⟨fun x _ => h x, sSup_singleton⟩⟩⟩ +@[deprecated (since := "2024-10-07")] +alias WellFounded.isSupFiniteCompact := WellFoundedGT.isSupFiniteCompact +@[deprecated (since := "2024-10-07")] +alias IsSupClosedCompact.wellFounded := IsSupClosedCompact.wellFoundedGT +@[deprecated (since := "2024-10-07")] +alias wellFounded_characterisations := wellFoundedGT_characterisations +@[deprecated (since := "2024-10-07")] +alias wellFounded_iff_isSupFiniteCompact := wellFoundedGT_iff_isSupFiniteCompact +@[deprecated (since := "2024-10-07")] +alias isSupClosedCompact_iff_wellFounded := isSupClosedCompact_iff_wellFoundedGT +@[deprecated (since := "2024-10-07")] +alias IsSupFiniteCompact.wellFounded := IsSupFiniteCompact.wellFoundedGT +@[deprecated (since := "2024-10-07")] +alias _root_.WellFounded.isSupClosedCompact := WellFoundedGT.isSupClosedCompact +@[deprecated (since := "2024-10-07")] +alias WellFounded.finite_of_setIndependent := WellFoundedGT.finite_of_setIndependent +@[deprecated (since := "2024-10-07")] +alias WellFounded.finite_ne_bot_of_independent := WellFoundedGT.finite_ne_bot_of_independent +@[deprecated (since := "2024-10-07")] +alias WellFounded.finite_of_independent := WellFoundedGT.finite_of_independent +@[deprecated (since := "2024-10-07")] +alias isCompactlyGenerated_of_wellFounded := isCompactlyGenerated_of_wellFoundedGT + /-- A compact element `k` has the property that any `b < k` lies below a "maximal element below `k`", which is to say `[⊥, k]` is coatomic. -/ theorem Iic_coatomic_of_compact_element {k : α} (h : IsCompactElement k) : diff --git a/Mathlib/Order/Compare.lean b/Mathlib/Order/Compare.lean index 0fc1605e23a0d..9fd8b1100315f 100644 --- a/Mathlib/Order/Compare.lean +++ b/Mathlib/Order/Compare.lean @@ -52,18 +52,18 @@ theorem swap_eq_iff_eq_swap {o o' : Ordering} : o.swap = o' ↔ o = o'.swap := b rw [← swap_inj, swap_swap] theorem Compares.eq_lt [Preorder α] : ∀ {o} {a b : α}, Compares o a b → (o = lt ↔ a < b) - | lt, a, b, h => ⟨fun _ => h, fun _ => rfl⟩ + | lt, _, _, h => ⟨fun _ => h, fun _ => rfl⟩ | eq, a, b, h => ⟨fun h => by injection h, fun h' => (ne_of_lt h' h).elim⟩ | gt, a, b, h => ⟨fun h => by injection h, fun h' => (lt_asymm h h').elim⟩ theorem Compares.ne_lt [Preorder α] : ∀ {o} {a b : α}, Compares o a b → (o ≠ lt ↔ b ≤ a) - | lt, a, b, h => ⟨absurd rfl, fun h' => (not_le_of_lt h h').elim⟩ - | eq, a, b, h => ⟨fun _ => ge_of_eq h, fun _ h => by injection h⟩ - | gt, a, b, h => ⟨fun _ => le_of_lt h, fun _ h => by injection h⟩ + | lt, _, _, h => ⟨absurd rfl, fun h' => (not_le_of_lt h h').elim⟩ + | eq, _, _, h => ⟨fun _ => ge_of_eq h, fun _ h => by injection h⟩ + | gt, _, _, h => ⟨fun _ => le_of_lt h, fun _ h => by injection h⟩ theorem Compares.eq_eq [Preorder α] : ∀ {o} {a b : α}, Compares o a b → (o = eq ↔ a = b) | lt, a, b, h => ⟨fun h => by injection h, fun h' => (ne_of_lt h h').elim⟩ - | eq, a, b, h => ⟨fun _ => h, fun _ => rfl⟩ + | eq, _, _, h => ⟨fun _ => h, fun _ => rfl⟩ | gt, a, b, h => ⟨fun h => by injection h, fun h' => (ne_of_gt h h').elim⟩ theorem Compares.eq_gt [Preorder α] {o} {a b : α} (h : Compares o a b) : o = gt ↔ b < a := diff --git a/Mathlib/Order/CompleteBooleanAlgebra.lean b/Mathlib/Order/CompleteBooleanAlgebra.lean index 38fc91ba70639..8a3e49b9fc5b8 100644 --- a/Mathlib/Order/CompleteBooleanAlgebra.lean +++ b/Mathlib/Order/CompleteBooleanAlgebra.lean @@ -157,7 +157,7 @@ This sets `a ⇨ b := sSup {c | c ⊓ a ≤ b}` and `aᶜ := a ⇨ ⊥`. -/ abbrev ofMinimalAxioms (minAx : MinimalAxioms α) : Frame α where __ := minAx himp a b := sSup {c | c ⊓ a ≤ b} - le_himp_iff a b c := + le_himp_iff _ b c := ⟨fun h ↦ (inf_le_inf_right _ h).trans (by simp [minAx.sSup_inf_eq]), fun h ↦ le_sSup h⟩ himp_bot _ := rfl @@ -193,14 +193,14 @@ This sets `a \ b := sInf {c | a ≤ b ⊔ c}` and `¬a := ⊤ \ a`. -/ abbrev ofMinimalAxioms (minAx : MinimalAxioms α) : Coframe α where __ := minAx sdiff a b := sInf {c | a ≤ b ⊔ c} - sdiff_le_iff a b c := + sdiff_le_iff a b _ := ⟨fun h ↦ (sup_le_sup_left h _).trans' (by simp [minAx.sup_sInf_eq]), fun h ↦ sInf_le h⟩ top_sdiff _ := rfl end Order.Coframe namespace CompleteDistribLattice.MinimalAxioms -variable (minAx : MinimalAxioms α) {s : Set α} {a b : α} +variable (minAx : MinimalAxioms α) /-- The `CompleteDistribLattice.MinimalAxioms` element corresponding to a complete distrib lattice. -/ @@ -502,7 +502,7 @@ end Coframe section CompleteDistribLattice -variable [CompleteDistribLattice α] {a b : α} {s t : Set α} +variable [CompleteDistribLattice α] instance OrderDual.instCompleteDistribLattice [CompleteDistribLattice α] : CompleteDistribLattice αᵒᵈ where @@ -578,7 +578,7 @@ instance OrderDual.instCompleteBooleanAlgebra [CompleteBooleanAlgebra α] : section CompleteBooleanAlgebra -variable [CompleteBooleanAlgebra α] {a b : α} {s : Set α} {f : ι → α} +variable [CompleteBooleanAlgebra α] {s : Set α} {f : ι → α} theorem compl_iInf : (iInf f)ᶜ = ⨆ i, (f i)ᶜ := le_antisymm @@ -821,7 +821,7 @@ end lift namespace PUnit -variable (s : Set PUnit.{u + 1}) (x y : PUnit.{u + 1}) +variable (s : Set PUnit.{u + 1}) instance instCompleteAtomicBooleanAlgebra : CompleteAtomicBooleanAlgebra PUnit where __ := PUnit.instBooleanAlgebra diff --git a/Mathlib/Order/CompleteLattice.lean b/Mathlib/Order/CompleteLattice.lean index 9e2df5ddb29f1..e900ae14df1c3 100644 --- a/Mathlib/Order/CompleteLattice.lean +++ b/Mathlib/Order/CompleteLattice.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl -/ import Mathlib.Data.Bool.Set import Mathlib.Data.Nat.Set +import Mathlib.Data.Set.NAry import Mathlib.Data.Set.Prod import Mathlib.Data.ULift import Mathlib.Order.Bounds.Basic @@ -45,7 +46,7 @@ In lemma names, open Function OrderDual Set -variable {α β β₂ γ : Type*} {ι ι' : Sort*} {κ : ι → Sort*} {κ' : ι' → Sort*} +variable {α β γ : Type*} {ι ι' : Sort*} {κ : ι → Sort*} {κ' : ι' → Sort*} @[simp] lemma iSup_ulift {ι : Type*} [SupSet α] (f : ULift ι → α) : ⨆ i : ULift ι, f i = ⨆ i, f (.up i) := by simp [iSup]; congr with x; simp @@ -204,7 +205,7 @@ def completeLatticeOfInf (α : Type*) [H1 : PartialOrder α] [H2 : InfSet α] (isGLB_sInf : ∀ s : Set α, IsGLB s (sInf s)) : CompleteLattice α where __ := H1; __ := H2 bot := sInf univ - bot_le x := (isGLB_sInf univ).1 trivial + bot_le _ := (isGLB_sInf univ).1 trivial top := sInf ∅ le_top a := (isGLB_sInf ∅).2 <| by simp sup a b := sInf { x : α | a ≤ x ∧ b ≤ x } @@ -212,16 +213,16 @@ def completeLatticeOfInf (α : Type*) [H1 : PartialOrder α] [H2 : InfSet α] le_inf a b c hab hac := by apply (isGLB_sInf _).2 simp [*] - inf_le_right a b := (isGLB_sInf _).1 <| mem_insert_of_mem _ <| mem_singleton _ - inf_le_left a b := (isGLB_sInf _).1 <| mem_insert _ _ + inf_le_right _ _ := (isGLB_sInf _).1 <| mem_insert_of_mem _ <| mem_singleton _ + inf_le_left _ _ := (isGLB_sInf _).1 <| mem_insert _ _ sup_le a b c hac hbc := (isGLB_sInf _).1 <| by simp [*] - le_sup_left a b := (isGLB_sInf _).2 fun x => And.left - le_sup_right a b := (isGLB_sInf _).2 fun x => And.right - le_sInf s a ha := (isGLB_sInf s).2 ha - sInf_le s a ha := (isGLB_sInf s).1 ha + le_sup_left _ _ := (isGLB_sInf _).2 fun _ => And.left + le_sup_right _ _ := (isGLB_sInf _).2 fun _ => And.right + le_sInf s _ ha := (isGLB_sInf s).2 ha + sInf_le s _ ha := (isGLB_sInf s).1 ha sSup s := sInf (upperBounds s) - le_sSup s a ha := (isGLB_sInf (upperBounds s)).2 fun b hb => hb ha - sSup_le s a ha := (isGLB_sInf (upperBounds s)).1 ha + le_sSup s _ ha := (isGLB_sInf (upperBounds s)).2 fun _ hb => hb ha + sSup_le s _ ha := (isGLB_sInf (upperBounds s)).1 ha /-- Any `CompleteSemilatticeInf` is in fact a `CompleteLattice`. @@ -251,22 +252,22 @@ def completeLatticeOfSup (α : Type*) [H1 : PartialOrder α] [H2 : SupSet α] (isLUB_sSup : ∀ s : Set α, IsLUB s (sSup s)) : CompleteLattice α where __ := H1; __ := H2 top := sSup univ - le_top x := (isLUB_sSup univ).1 trivial + le_top _ := (isLUB_sSup univ).1 trivial bot := sSup ∅ bot_le x := (isLUB_sSup ∅).2 <| by simp sup a b := sSup {a, b} sup_le a b c hac hbc := (isLUB_sSup _).2 (by simp [*]) - le_sup_left a b := (isLUB_sSup _).1 <| mem_insert _ _ - le_sup_right a b := (isLUB_sSup _).1 <| mem_insert_of_mem _ <| mem_singleton _ + le_sup_left _ _ := (isLUB_sSup _).1 <| mem_insert _ _ + le_sup_right _ _ := (isLUB_sSup _).1 <| mem_insert_of_mem _ <| mem_singleton _ inf a b := sSup { x | x ≤ a ∧ x ≤ b } le_inf a b c hab hac := (isLUB_sSup _).1 <| by simp [*] - inf_le_left a b := (isLUB_sSup _).2 fun x => And.left - inf_le_right a b := (isLUB_sSup _).2 fun x => And.right + inf_le_left _ _ := (isLUB_sSup _).2 fun _ => And.left + inf_le_right _ _ := (isLUB_sSup _).2 fun _ => And.right sInf s := sSup (lowerBounds s) - sSup_le s a ha := (isLUB_sSup s).2 ha - le_sSup s a ha := (isLUB_sSup s).1 ha - sInf_le s a ha := (isLUB_sSup (lowerBounds s)).2 fun b hb => hb ha - le_sInf s a ha := (isLUB_sSup (lowerBounds s)).1 ha + sSup_le s _ ha := (isLUB_sSup s).2 ha + le_sSup s _ ha := (isLUB_sSup s).1 ha + sInf_le s _ ha := (isLUB_sSup (lowerBounds s)).2 fun _ hb => hb ha + le_sInf s _ ha := (isLUB_sSup (lowerBounds s)).1 ha /-- Any `CompleteSemilatticeSup` is in fact a `CompleteLattice`. @@ -362,7 +363,7 @@ theorem ofDual_iInf [SupSet α] (f : ι → αᵒᵈ) : ofDual (⨅ i, f i) = end OrderDual -variable [CompleteLattice α] {s t : Set α} {a b : α} +variable [CompleteLattice α] {s t : Set α} {b : α} theorem sInf_le_sSup (hs : s.Nonempty) : sInf s ≤ sSup s := isGLB_le_isLUB (isGLB_sInf s) (isLUB_sSup s) hs @@ -468,7 +469,7 @@ end section CompleteLinearOrder -variable [CompleteLinearOrder α] {s t : Set α} {a b : α} +variable [CompleteLinearOrder α] {s : Set α} {a b : α} theorem lt_sSup_iff : b < sSup s ↔ ∃ a ∈ s, b < a := lt_isLUB_iff <| isLUB_sSup s @@ -616,7 +617,7 @@ end InfSet section -variable [CompleteLattice α] {f g s t : ι → α} {a b : α} +variable [CompleteLattice α] {f g s : ι → α} {a b : α} theorem le_iSup (f : ι → α) (i : ι) : f i ≤ iSup f := le_sSup ⟨i, rfl⟩ @@ -1072,6 +1073,41 @@ theorem inf_biInf {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, (a ⊓ ⨅ (i) (h : p i), f i h) = ⨅ (i) (h : p i), a ⊓ f i h := @sup_biSup αᵒᵈ ι _ p f _ h +lemma biSup_lt_eq_iSup {ι : Type*} [LT ι] [NoMaxOrder ι] {f : ι → α} : + ⨆ (i) (j < i), f j = ⨆ i, f i := by + apply le_antisymm + · exact iSup_le fun _ ↦ iSup₂_le fun _ _ ↦ le_iSup _ _ + · refine iSup_le fun j ↦ ?_ + obtain ⟨i, jlt⟩ := exists_gt j + exact le_iSup_of_le i (le_iSup₂_of_le j jlt le_rfl) + +lemma biSup_le_eq_iSup {ι : Type*} [Preorder ι] {f : ι → α} : + ⨆ (i) (j ≤ i), f j = ⨆ i, f i := by + apply le_antisymm + · exact iSup_le fun _ ↦ iSup₂_le fun _ _ ↦ le_iSup _ _ + · exact iSup_le fun j ↦ le_iSup_of_le j (le_iSup₂_of_le j le_rfl le_rfl) + +lemma biInf_lt_eq_iInf {ι : Type*} [LT ι] [NoMaxOrder ι] {f : ι → α} : + ⨅ (i) (j < i), f j = ⨅ i, f i := + biSup_lt_eq_iSup (α := αᵒᵈ) + +lemma biInf_le_eq_iInf {ι : Type*} [Preorder ι] {f : ι → α} : ⨅ (i) (j ≤ i), f j = ⨅ i, f i := + biSup_le_eq_iSup (α := αᵒᵈ) + +lemma biSup_gt_eq_iSup {ι : Type*} [LT ι] [NoMinOrder ι] {f : ι → α} : + ⨆ (i) (j > i), f j = ⨆ i, f i := + biSup_lt_eq_iSup (ι := ιᵒᵈ) + +lemma biSup_ge_eq_iSup {ι : Type*} [Preorder ι] {f : ι → α} : ⨆ (i) (j ≥ i), f j = ⨆ i, f i := + biSup_le_eq_iSup (ι := ιᵒᵈ) + +lemma biInf_gt_eq_iInf {ι : Type*} [LT ι] [NoMinOrder ι] {f : ι → α} : + ⨅ (i) (j > i), f j = ⨅ i, f i := + biInf_lt_eq_iInf (ι := ιᵒᵈ) + +lemma biInf_ge_eq_iInf {ι : Type*} [Preorder ι] {f : ι → α} : ⨅ (i) (j ≥ i), f j = ⨅ i, f i := + biInf_le_eq_iInf (ι := ιᵒᵈ) + /-! ### `iSup` and `iInf` under `Prop` -/ @@ -1227,7 +1263,8 @@ theorem iInf_pair {f : β → α} {a b : β} : ⨅ x ∈ ({a, b} : Set β), f x rw [iInf_insert, iInf_singleton] theorem iSup_image {γ} {f : β → γ} {g : γ → α} {t : Set β} : - ⨆ c ∈ f '' t, g c = ⨆ b ∈ t, g (f b) := by rw [← sSup_image, ← sSup_image, ← image_comp]; rfl + ⨆ c ∈ f '' t, g c = ⨆ b ∈ t, g (f b) := by + rw [← sSup_image, ← sSup_image, ← image_comp, comp_def] theorem iInf_image : ∀ {γ} {f : β → γ} {g : γ → α} {t : Set β}, ⨅ c ∈ f '' t, g c = ⨅ b ∈ t, g (f b) := @@ -1326,6 +1363,14 @@ theorem biInf_prod {f : β × γ → α} {s : Set β} {t : Set γ} : ⨅ x ∈ s ×ˢ t, f x = ⨅ (a ∈ s) (b ∈ t), f (a, b) := @biSup_prod αᵒᵈ _ _ _ _ _ _ +theorem iSup_image2 {γ δ} (f : β → γ → δ) (s : Set β) (t : Set γ) (g : δ → α) : + ⨆ d ∈ image2 f s t, g d = ⨆ b ∈ s, ⨆ c ∈ t, g (f b c) := by + rw [← image_prod, iSup_image, biSup_prod] + +theorem iInf_image2 {γ δ} (f : β → γ → δ) (s : Set β) (t : Set γ) (g : δ → α) : + ⨅ d ∈ image2 f s t, g d = ⨅ b ∈ s, ⨅ c ∈ t, g (f b c) := + iSup_image2 f s t (toDual ∘ g) + theorem iSup_sum {f : β ⊕ γ → α} : ⨆ x, f x = (⨆ i, f (Sum.inl i)) ⊔ ⨆ j, f (Sum.inr j) := eq_of_forall_ge_iff fun c => by simp only [sup_le_iff, iSup_le_iff, Sum.forall] @@ -1539,7 +1584,7 @@ theorem binary_relation_sInf_iff {α β : Type*} (s : Set (α → β → Prop)) section CompleteLattice -variable {ι : Sort*} [Preorder α] [CompleteLattice β] {s : Set (α → β)} {f : ι → α → β} +variable [Preorder α] [CompleteLattice β] {s : Set (α → β)} {f : ι → α → β} protected lemma Monotone.sSup (hs : ∀ f ∈ s, Monotone f) : Monotone (sSup s) := fun _ _ h ↦ iSup_mono fun f ↦ hs f f.2 h diff --git a/Mathlib/Order/CompleteLattice/Finset.lean b/Mathlib/Order/CompleteLattice/Finset.lean index b96b173756c62..b02e5eb918efa 100644 --- a/Mathlib/Order/CompleteLattice/Finset.lean +++ b/Mathlib/Order/CompleteLattice/Finset.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Data.Finset.Option -import Mathlib.Order.Minimal +import Mathlib.Data.Set.Lattice /-! # Lattice operations on finsets diff --git a/Mathlib/Order/CompleteLatticeIntervals.lean b/Mathlib/Order/CompleteLatticeIntervals.lean index 149df0ed5225d..814ddc87ae3d5 100644 --- a/Mathlib/Order/CompleteLatticeIntervals.lean +++ b/Mathlib/Order/CompleteLatticeIntervals.lean @@ -241,10 +241,10 @@ variable [CompleteLattice α] {a : α} instance instCompleteLattice : CompleteLattice (Iic a) where sSup S := ⟨sSup ((↑) '' S), by simpa using fun b hb _ ↦ hb⟩ sInf S := ⟨a ⊓ sInf ((↑) '' S), by simp⟩ - le_sSup S b hb := le_sSup <| mem_image_of_mem Subtype.val hb - sSup_le S b hb := sSup_le <| fun c' ⟨c, hc, hc'⟩ ↦ hc' ▸ hb c hc - sInf_le S b hb := inf_le_of_right_le <| sInf_le <| mem_image_of_mem Subtype.val hb - le_sInf S b hb := le_inf_iff.mpr ⟨b.property, le_sInf fun d' ⟨d, hd, hd'⟩ ↦ hd' ▸ hb d hd⟩ + le_sSup _ _ hb := le_sSup <| mem_image_of_mem Subtype.val hb + sSup_le _ _ hb := sSup_le <| fun _ ⟨c, hc, hc'⟩ ↦ hc' ▸ hb c hc + sInf_le _ _ hb := inf_le_of_right_le <| sInf_le <| mem_image_of_mem Subtype.val hb + le_sInf _ b hb := le_inf_iff.mpr ⟨b.property, le_sInf fun _ ⟨d, hd, hd'⟩ ↦ hd' ▸ hb d hd⟩ le_top := by simp bot_le := by simp diff --git a/Mathlib/Order/Concept.lean b/Mathlib/Order/Concept.lean index b4818c18d6fc2..59acc56d37fcc 100644 --- a/Mathlib/Order/Concept.lean +++ b/Mathlib/Order/Concept.lean @@ -37,8 +37,7 @@ concept, formal concept analysis, intent, extend, attribute open Function OrderDual Set -variable {ι : Sort*} {α β γ : Type*} {κ : ι → Sort*} (r : α → β → Prop) {s s₁ s₂ : Set α} - {t t₁ t₂ : Set β} +variable {ι : Sort*} {α β : Type*} {κ : ι → Sort*} (r : α → β → Prop) {s : Set α} {t : Set β} /-! ### Intent and extent -/ @@ -223,8 +222,8 @@ theorem strictAnti_snd : StrictAnti (Prod.snd ∘ toProd : Concept α β r → S instance instLatticeConcept : Lattice (Concept α β r) := { Concept.instSemilatticeInfConcept with sup := (· ⊔ ·) - le_sup_left := fun c d => snd_subset_snd_iff.1 inter_subset_left - le_sup_right := fun c d => snd_subset_snd_iff.1 inter_subset_right + le_sup_left := fun _ _ => snd_subset_snd_iff.1 inter_subset_left + le_sup_right := fun _ _ => snd_subset_snd_iff.1 inter_subset_right sup_le := fun c d e => by simp_rw [← snd_subset_snd_iff] exact subset_inter } diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 9f80770bcdc85..718526c723f5e 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -10,7 +10,7 @@ import Mathlib.Order.Interval.Set.Basic import Mathlib.Data.Set.Lattice /-! -# Theory of conditionally complete lattices. +# Theory of conditionally complete lattices A conditionally complete lattice is a lattice in which every non-empty bounded subset `s` has a least upper bound and a greatest lower bound, denoted below by `sSup s` and `sInf s`. @@ -18,9 +18,8 @@ Typical examples are `ℝ`, `ℕ`, and `ℤ` with their usual orders. The theory is very comparable to the theory of complete lattices, except that suitable boundedness and nonemptiness assumptions have to be added to most statements. -We introduce two predicates `BddAbove` and `BddBelow` to express this boundedness, prove -their basic properties, and then go on to prove most useful properties of `sSup` and `sInf` -in conditionally complete lattices. +We express these using the `BddAbove` and `BddBelow` predicates, which we use to prove +most useful properties of `sSup` and `sInf` in conditionally complete lattices. To differentiate the statements between complete lattices and conditionally complete lattices, we prefix `sInf` and `sSup` in the statements by `c`, giving `csInf` and `csSup`. @@ -82,10 +81,6 @@ theorem WithBot.sSup_eq [SupSet α] {s : Set (WithBot α)} (hs : ¬s ⊆ {⊥}) theorem WithTop.sInf_empty [InfSet α] : sInf (∅ : Set (WithTop α)) = ⊤ := if_pos <| by simp -@[simp] -theorem WithTop.iInf_empty [IsEmpty ι] [InfSet α] (f : ι → WithTop α) : - ⨅ i, f i = ⊤ := by rw [iInf, range_eq_empty, WithTop.sInf_empty] - theorem WithTop.coe_sInf' [InfSet α] {s : Set α} (hs : s.Nonempty) (h's : BddBelow s) : ↑(sInf s) = (sInf ((fun (a : α) ↦ ↑a) '' s) : WithTop α) := by classical @@ -98,11 +93,6 @@ theorem WithTop.coe_sInf' [InfSet α] {s : Set α} (hs : s.Nonempty) (h's : BddB · rw [preimage_image_eq] exact Option.some_injective _ -@[norm_cast] -theorem WithTop.coe_iInf [Nonempty ι] [InfSet α] {f : ι → α} (hf : BddBelow (range f)) : - ↑(⨅ i, f i) = (⨅ i, f i : WithTop α) := by - rw [iInf, iInf, WithTop.coe_sInf' (range_nonempty f) hf, ← range_comp, Function.comp_def] - theorem WithTop.coe_sSup' [SupSet α] {s : Set α} (hs : BddAbove s) : ↑(sSup s) = (sSup ((fun (a : α) ↦ ↑a) '' s) : WithTop α) := by classical @@ -111,42 +101,22 @@ theorem WithTop.coe_sSup' [SupSet α] {s : Set α} (hs : BddAbove s) : · exact Option.some_injective _ · rintro ⟨x, _, ⟨⟩⟩ -@[norm_cast] -theorem WithTop.coe_iSup [SupSet α] (f : ι → α) (h : BddAbove (Set.range f)) : - ↑(⨆ i, f i) = (⨆ i, f i : WithTop α) := by - rw [iSup, iSup, WithTop.coe_sSup' h, ← range_comp, Function.comp_def] - @[simp] theorem WithBot.sSup_empty [SupSet α] : sSup (∅ : Set (WithBot α)) = ⊥ := WithTop.sInf_empty (α := αᵒᵈ) @[deprecated (since := "2024-06-10")] alias WithBot.csSup_empty := WithBot.sSup_empty -@[simp] -theorem WithBot.ciSup_empty [IsEmpty ι] [SupSet α] (f : ι → WithBot α) : - ⨆ i, f i = ⊥ := - WithTop.iInf_empty (α := αᵒᵈ) _ - @[norm_cast] theorem WithBot.coe_sSup' [SupSet α] {s : Set α} (hs : s.Nonempty) (h's : BddAbove s) : ↑(sSup s) = (sSup ((fun (a : α) ↦ ↑a) '' s) : WithBot α) := WithTop.coe_sInf' (α := αᵒᵈ) hs h's -@[norm_cast] -theorem WithBot.coe_iSup [Nonempty ι] [SupSet α] {f : ι → α} (hf : BddAbove (range f)) : - ↑(⨆ i, f i) = (⨆ i, f i : WithBot α) := - WithTop.coe_iInf (α := αᵒᵈ) hf - @[norm_cast] theorem WithBot.coe_sInf' [InfSet α] {s : Set α} (hs : BddBelow s) : ↑(sInf s) = (sInf ((fun (a : α) ↦ ↑a) '' s) : WithBot α) := WithTop.coe_sSup' (α := αᵒᵈ) hs -@[norm_cast] -theorem WithBot.coe_iInf [InfSet α] (f : ι → α) (h : BddBelow (Set.range f)) : - ↑(⨅ i, f i) = (⨅ i, f i : WithBot α) := - WithTop.coe_iSup (α := αᵒᵈ) _ h - end /-- A conditionally complete lattice is a lattice in which @@ -219,16 +189,12 @@ complete linear orders, we prefix `sInf` and `sSup` by a `c` everywhere. The sam hold in both worlds, sometimes with additional assumptions of nonemptiness or boundedness. -/ class ConditionallyCompleteLinearOrderBot (α : Type*) extends ConditionallyCompleteLinearOrder α, - Bot α where - /-- `⊥` is the least element -/ - bot_le : ∀ x : α, ⊥ ≤ x - /-- The supremum of the empty set is `⊥` -/ + OrderBot α where + /-- The supremum of the empty set is special-cased to `⊥` -/ csSup_empty : sSup ∅ = ⊥ -- see Note [lower instance priority] -instance (priority := 100) ConditionallyCompleteLinearOrderBot.toOrderBot - [h : ConditionallyCompleteLinearOrderBot α] : OrderBot α := - { h with } +attribute [instance 100] ConditionallyCompleteLinearOrderBot.toOrderBot -- see Note [lower instance priority] /-- A complete lattice is a conditionally complete lattice, as there are no restrictions @@ -460,52 +426,12 @@ theorem csInf_le_iff (h : BddBelow s) (hs : s.Nonempty) : sInf s ≤ a ↔ ∀ b theorem isLUB_csSup (ne : s.Nonempty) (H : BddAbove s) : IsLUB s (sSup s) := ⟨fun _ => le_csSup H, fun _ => csSup_le ne⟩ -theorem isLUB_ciSup [Nonempty ι] {f : ι → α} (H : BddAbove (range f)) : - IsLUB (range f) (⨆ i, f i) := - isLUB_csSup (range_nonempty f) H - -theorem isLUB_ciSup_set {f : β → α} {s : Set β} (H : BddAbove (f '' s)) (Hne : s.Nonempty) : - IsLUB (f '' s) (⨆ i : s, f i) := by - rw [← sSup_image'] - exact isLUB_csSup (Hne.image _) H - theorem isGLB_csInf (ne : s.Nonempty) (H : BddBelow s) : IsGLB s (sInf s) := ⟨fun _ => csInf_le H, fun _ => le_csInf ne⟩ -theorem isGLB_ciInf [Nonempty ι] {f : ι → α} (H : BddBelow (range f)) : - IsGLB (range f) (⨅ i, f i) := - isGLB_csInf (range_nonempty f) H - -theorem isGLB_ciInf_set {f : β → α} {s : Set β} (H : BddBelow (f '' s)) (Hne : s.Nonempty) : - IsGLB (f '' s) (⨅ i : s, f i) := - isLUB_ciSup_set (α := αᵒᵈ) H Hne - -theorem ciSup_le_iff [Nonempty ι] {f : ι → α} {a : α} (hf : BddAbove (range f)) : - iSup f ≤ a ↔ ∀ i, f i ≤ a := - (isLUB_le_iff <| isLUB_ciSup hf).trans forall_mem_range - -theorem le_ciInf_iff [Nonempty ι] {f : ι → α} {a : α} (hf : BddBelow (range f)) : - a ≤ iInf f ↔ ∀ i, a ≤ f i := - (le_isGLB_iff <| isGLB_ciInf hf).trans forall_mem_range - -theorem ciSup_set_le_iff {ι : Type*} {s : Set ι} {f : ι → α} {a : α} (hs : s.Nonempty) - (hf : BddAbove (f '' s)) : ⨆ i : s, f i ≤ a ↔ ∀ i ∈ s, f i ≤ a := - (isLUB_le_iff <| isLUB_ciSup_set hf hs).trans forall_mem_image - -theorem le_ciInf_set_iff {ι : Type*} {s : Set ι} {f : ι → α} {a : α} (hs : s.Nonempty) - (hf : BddBelow (f '' s)) : (a ≤ ⨅ i : s, f i) ↔ ∀ i ∈ s, a ≤ f i := - (le_isGLB_iff <| isGLB_ciInf_set hf hs).trans forall_mem_image - theorem IsLUB.csSup_eq (H : IsLUB s a) (ne : s.Nonempty) : sSup s = a := (isLUB_csSup ne ⟨a, H.1⟩).unique H -theorem IsLUB.ciSup_eq [Nonempty ι] {f : ι → α} (H : IsLUB (range f) a) : ⨆ i, f i = a := - H.csSup_eq (range_nonempty f) - -theorem IsLUB.ciSup_set_eq {s : Set β} {f : β → α} (H : IsLUB (f '' s) a) (Hne : s.Nonempty) : - ⨆ i : s, f i = a := - IsLUB.csSup_eq (image_eq_range f s ▸ H) (image_eq_range f s ▸ Hne.image f) - /-- A greatest element of a set is the supremum of this set. -/ theorem IsGreatest.csSup_eq (H : IsGreatest s a) : sSup s = a := H.isLUB.csSup_eq H.nonempty @@ -516,13 +442,6 @@ theorem IsGreatest.csSup_mem (H : IsGreatest s a) : sSup s ∈ s := theorem IsGLB.csInf_eq (H : IsGLB s a) (ne : s.Nonempty) : sInf s = a := (isGLB_csInf ne ⟨a, H.1⟩).unique H -theorem IsGLB.ciInf_eq [Nonempty ι] {f : ι → α} (H : IsGLB (range f) a) : ⨅ i, f i = a := - H.csInf_eq (range_nonempty f) - -theorem IsGLB.ciInf_set_eq {s : Set β} {f : β → α} (H : IsGLB (f '' s) a) (Hne : s.Nonempty) : - ⨅ i : s, f i = a := - IsGLB.csInf_eq (image_eq_range f s ▸ H) (image_eq_range f s ▸ Hne.image f) - /-- A least element of a set is the infimum of this set. -/ theorem IsLeast.csInf_eq (H : IsLeast s a) : sInf s = a := H.isGLB.csInf_eq H.nonempty @@ -704,145 +623,6 @@ theorem csSup_Ioc (h : a < b) : sSup (Ioc a b) = b := theorem csSup_Ioo [DenselyOrdered α] (h : a < b) : sSup (Ioo a b) = b := (isLUB_Ioo h).csSup_eq (nonempty_Ioo.2 h) -/-- The indexed supremum of a function is bounded above by a uniform bound -/ -theorem ciSup_le [Nonempty ι] {f : ι → α} {c : α} (H : ∀ x, f x ≤ c) : iSup f ≤ c := - csSup_le (range_nonempty f) (by rwa [forall_mem_range]) - -/-- The indexed supremum of a function is bounded below by the value taken at one point -/ -theorem le_ciSup {f : ι → α} (H : BddAbove (range f)) (c : ι) : f c ≤ iSup f := - le_csSup H (mem_range_self _) - -theorem le_ciSup_of_le {f : ι → α} (H : BddAbove (range f)) (c : ι) (h : a ≤ f c) : a ≤ iSup f := - le_trans h (le_ciSup H c) - -/-- The indexed suprema of two functions are comparable if the functions are pointwise comparable -/ -theorem ciSup_mono {f g : ι → α} (B : BddAbove (range g)) (H : ∀ x, f x ≤ g x) : - iSup f ≤ iSup g := by - cases isEmpty_or_nonempty ι - · rw [iSup_of_empty', iSup_of_empty'] - · exact ciSup_le fun x => le_ciSup_of_le B x (H x) - -theorem le_ciSup_set {f : β → α} {s : Set β} (H : BddAbove (f '' s)) {c : β} (hc : c ∈ s) : - f c ≤ ⨆ i : s, f i := - (le_csSup H <| mem_image_of_mem f hc).trans_eq sSup_image' - -/-- The indexed infimum of two functions are comparable if the functions are pointwise comparable -/ -theorem ciInf_mono {f g : ι → α} (B : BddBelow (range f)) (H : ∀ x, f x ≤ g x) : iInf f ≤ iInf g := - ciSup_mono (α := αᵒᵈ) B H - -/-- The indexed minimum of a function is bounded below by a uniform lower bound -/ -theorem le_ciInf [Nonempty ι] {f : ι → α} {c : α} (H : ∀ x, c ≤ f x) : c ≤ iInf f := - ciSup_le (α := αᵒᵈ) H - -/-- The indexed infimum of a function is bounded above by the value taken at one point -/ -theorem ciInf_le {f : ι → α} (H : BddBelow (range f)) (c : ι) : iInf f ≤ f c := - le_ciSup (α := αᵒᵈ) H c - -theorem ciInf_le_of_le {f : ι → α} (H : BddBelow (range f)) (c : ι) (h : f c ≤ a) : iInf f ≤ a := - le_ciSup_of_le (α := αᵒᵈ) H c h - -theorem ciInf_set_le {f : β → α} {s : Set β} (H : BddBelow (f '' s)) {c : β} (hc : c ∈ s) : - ⨅ i : s, f i ≤ f c := - le_ciSup_set (α := αᵒᵈ) H hc - -@[simp] -theorem ciSup_const [hι : Nonempty ι] {a : α} : ⨆ _ : ι, a = a := by - rw [iSup, range_const, csSup_singleton] - -@[simp] -theorem ciInf_const [Nonempty ι] {a : α} : ⨅ _ : ι, a = a := - ciSup_const (α := αᵒᵈ) - -@[simp] -theorem ciSup_unique [Unique ι] {s : ι → α} : ⨆ i, s i = s default := by - have : ∀ i, s i = s default := fun i => congr_arg s (Unique.eq_default i) - simp only [this, ciSup_const] - -@[simp] -theorem ciInf_unique [Unique ι] {s : ι → α} : ⨅ i, s i = s default := - ciSup_unique (α := αᵒᵈ) - -theorem ciSup_subsingleton [Subsingleton ι] (i : ι) (s : ι → α) : ⨆ i, s i = s i := - @ciSup_unique α ι _ ⟨⟨i⟩, fun j => Subsingleton.elim j i⟩ _ - -theorem ciInf_subsingleton [Subsingleton ι] (i : ι) (s : ι → α) : ⨅ i, s i = s i := - @ciInf_unique α ι _ ⟨⟨i⟩, fun j => Subsingleton.elim j i⟩ _ - -@[simp] -theorem ciSup_pos {p : Prop} {f : p → α} (hp : p) : ⨆ h : p, f h = f hp := - ciSup_subsingleton hp f - -@[simp] -theorem ciInf_pos {p : Prop} {f : p → α} (hp : p) : ⨅ h : p, f h = f hp := - ciSup_pos (α := αᵒᵈ) hp - -lemma ciSup_neg {p : Prop} {f : p → α} (hp : ¬ p) : - ⨆ (h : p), f h = sSup (∅ : Set α) := by - rw [iSup] - congr - rwa [range_eq_empty_iff, isEmpty_Prop] - -lemma ciInf_neg {p : Prop} {f : p → α} (hp : ¬ p) : - ⨅ (h : p), f h = sInf (∅ : Set α) := - ciSup_neg (α := αᵒᵈ) hp - -lemma ciSup_eq_ite {p : Prop} [Decidable p] {f : p → α} : - (⨆ h : p, f h) = if h : p then f h else sSup (∅ : Set α) := by - by_cases H : p <;> simp [ciSup_neg, H] - -lemma ciInf_eq_ite {p : Prop} [Decidable p] {f : p → α} : - (⨅ h : p, f h) = if h : p then f h else sInf (∅ : Set α) := - ciSup_eq_ite (α := αᵒᵈ) - -theorem cbiSup_eq_of_forall {p : ι → Prop} {f : Subtype p → α} (hp : ∀ i, p i) : - ⨆ (i) (h : p i), f ⟨i, h⟩ = iSup f := by - simp only [hp, ciSup_unique] - simp only [iSup] - congr - apply Subset.antisymm - · rintro - ⟨i, rfl⟩ - simp [hp i] - · rintro - ⟨i, rfl⟩ - simp - -theorem cbiInf_eq_of_forall {p : ι → Prop} {f : Subtype p → α} (hp : ∀ i, p i) : - ⨅ (i) (h : p i), f ⟨i, h⟩ = iInf f := - cbiSup_eq_of_forall (α := αᵒᵈ) hp - -/-- Introduction rule to prove that `b` is the supremum of `f`: it suffices to check that `b` -is larger than `f i` for all `i`, and that this is not the case of any `w exists_range_iff.mpr <| h₂ w hw - --- Porting note: in mathlib3 `by exact` is not needed -/-- Introduction rule to prove that `b` is the infimum of `f`: it suffices to check that `b` -is smaller than `f i` for all `i`, and that this is not the case of any `w>b`. -See `iInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in complete lattices. -/ -theorem ciInf_eq_of_forall_ge_of_forall_gt_exists_lt [Nonempty ι] {f : ι → α} (h₁ : ∀ i, b ≤ f i) - (h₂ : ∀ w, b < w → ∃ i, f i < w) : ⨅ i : ι, f i = b := by - exact ciSup_eq_of_forall_le_of_forall_lt_exists_gt (α := αᵒᵈ) (f := ‹_›) ‹_› ‹_› - -/-- **Nested intervals lemma**: if `f` is a monotone sequence, `g` is an antitone sequence, and -`f n ≤ g n` for all `n`, then `⨆ n, f n` belongs to all the intervals `[f n, g n]`. -/ -theorem Monotone.ciSup_mem_iInter_Icc_of_antitone [SemilatticeSup β] {f g : β → α} (hf : Monotone f) - (hg : Antitone g) (h : f ≤ g) : (⨆ n, f n) ∈ ⋂ n, Icc (f n) (g n) := by - refine mem_iInter.2 fun n => ?_ - haveI : Nonempty β := ⟨n⟩ - have : ∀ m, f m ≤ g n := fun m => hf.forall_le_of_antitone hg h m n - exact ⟨le_ciSup ⟨g <| n, forall_mem_range.2 this⟩ _, ciSup_le this⟩ - -/-- Nested intervals lemma: if `[f n, g n]` is an antitone sequence of nonempty -closed intervals, then `⨆ n, f n` belongs to all the intervals `[f n, g n]`. -/ -theorem ciSup_mem_iInter_Icc_of_antitone_Icc [SemilatticeSup β] {f g : β → α} - (h : Antitone fun n => Icc (f n) (g n)) (h' : ∀ n, f n ≤ g n) : - (⨆ n, f n) ∈ ⋂ n, Icc (f n) (g n) := - Monotone.ciSup_mem_iInter_Icc_of_antitone - (fun _ n hmn => ((Icc_subset_Icc_iff (h' n)).1 (h hmn)).1) - (fun _ n hmn => ((Icc_subset_Icc_iff (h' n)).1 (h hmn)).2) h' - /-- Introduction rule to prove that `b` is the supremum of `s`: it suffices to check that 1) `b` is an upper bound 2) every other upper bound `b'` satisfies `b ≤ b'`. -/ @@ -850,127 +630,26 @@ theorem csSup_eq_of_is_forall_le_of_forall_le_imp_ge (hs : s.Nonempty) (h_is_ub (h_b_le_ub : ∀ ub, (∀ a ∈ s, a ≤ ub) → b ≤ ub) : sSup s = b := (csSup_le hs h_is_ub).antisymm ((h_b_le_ub _) fun _ => le_csSup ⟨b, h_is_ub⟩) -lemma Set.Iic_ciInf [Nonempty ι] {f : ι → α} (hf : BddBelow (range f)) : - Iic (⨅ i, f i) = ⋂ i, Iic (f i) := by - apply Subset.antisymm - · rintro x hx - ⟨i, rfl⟩ - exact hx.trans (ciInf_le hf _) - · rintro x hx - apply le_ciInf - simpa using hx - -lemma Set.Ici_ciSup [Nonempty ι] {f : ι → α} (hf : BddAbove (range f)) : - Ici (⨆ i, f i) = ⋂ i, Ici (f i) := - Iic_ciInf (α := αᵒᵈ) hf - lemma sup_eq_top_of_top_mem [OrderTop α] (h : ⊤ ∈ s) : sSup s = ⊤ := top_unique <| le_csSup (OrderTop.bddAbove s) h lemma inf_eq_bot_of_bot_mem [OrderBot α] (h : ⊥ ∈ s) : sInf s = ⊥ := bot_unique <| csInf_le (OrderBot.bddBelow s) h -theorem ciSup_subtype [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : Subtype p → α} - (hf : BddAbove (Set.range f)) (hf' : sSup ∅ ≤ iSup f) : - iSup f = ⨆ (i) (h : p i), f ⟨i, h⟩ := by - classical - refine le_antisymm (ciSup_le ?_) ?_ - · intro ⟨i, h⟩ - have : f ⟨i, h⟩ = (fun i : ι ↦ ⨆ (h : p i), f ⟨i, h⟩) i := by simp [h] - rw [this] - refine le_ciSup (f := (fun i : ι ↦ ⨆ (h : p i), f ⟨i, h⟩)) ?_ i - simp_rw [ciSup_eq_ite] - refine (hf.union (bddAbove_singleton (a := sSup ∅))).mono ?_ - intro - simp only [Set.mem_range, Set.union_singleton, Set.mem_insert_iff, Subtype.exists, - forall_exists_index] - intro b hb - split_ifs at hb - · exact Or.inr ⟨_, _, hb⟩ - · simp_all - · refine ciSup_le fun i ↦ ?_ - simp_rw [ciSup_eq_ite] - split_ifs - · exact le_ciSup hf ?_ - · exact hf' - -theorem ciInf_subtype [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : Subtype p → α} - (hf : BddBelow (Set.range f)) (hf' : iInf f ≤ sInf ∅) : - iInf f = ⨅ (i) (h : p i), f ⟨i, h⟩ := - ciSup_subtype (α := αᵒᵈ) hf hf' - -theorem ciSup_subtype' [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : ∀ i, p i → α} - (hf : BddAbove (Set.range (fun i : Subtype p ↦ f i i.prop))) - (hf' : sSup ∅ ≤ ⨆ (i : Subtype p), f i i.prop) : - ⨆ (i) (h), f i h = ⨆ x : Subtype p, f x x.property := - (ciSup_subtype (f := fun x => f x.val x.property) hf hf').symm - -theorem ciInf_subtype' [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : ∀ i, p i → α} - (hf : BddBelow (Set.range (fun i : Subtype p ↦ f i i.prop))) - (hf' : ⨅ (i : Subtype p), f i i.prop ≤ sInf ∅) : - ⨅ (i) (h), f i h = ⨅ x : Subtype p, f x x.property := - (ciInf_subtype (f := fun x => f x.val x.property) hf hf').symm - -theorem ciSup_subtype'' {ι} [Nonempty ι] {s : Set ι} (hs : s.Nonempty) {f : ι → α} - (hf : BddAbove (Set.range fun i : s ↦ f i)) (hf' : sSup ∅ ≤ ⨆ i : s, f i) : - ⨆ i : s, f i = ⨆ (t : ι) (_ : t ∈ s), f t := - haveI : Nonempty s := Set.Nonempty.to_subtype hs - ciSup_subtype hf hf' - -theorem ciInf_subtype'' {ι} [Nonempty ι] {s : Set ι} (hs : s.Nonempty) {f : ι → α} - (hf : BddBelow (Set.range fun i : s ↦ f i)) (hf' : ⨅ i : s, f i ≤ sInf ∅) : - ⨅ i : s, f i = ⨅ (t : ι) (_ : t ∈ s), f t := - haveI : Nonempty s := Set.Nonempty.to_subtype hs - ciInf_subtype hf hf' - -theorem csSup_image [Nonempty β] {s : Set β} (hs : s.Nonempty) {f : β → α} - (hf : BddAbove (Set.range fun i : s ↦ f i)) (hf' : sSup ∅ ≤ ⨆ i : s, f i) : - sSup (f '' s) = ⨆ a ∈ s, f a := by - rw [← ciSup_subtype'' hs hf hf', iSup, Set.image_eq_range] - -theorem csInf_image [Nonempty β] {s : Set β} (hs : s.Nonempty) {f : β → α} - (hf : BddBelow (Set.range fun i : s ↦ f i)) (hf' : ⨅ i : s, f i ≤ sInf ∅) : - sInf (f '' s) = ⨅ a ∈ s, f a := - csSup_image (α := αᵒᵈ) hs hf hf' - -lemma ciSup_image {α ι ι' : Type*} [ConditionallyCompleteLattice α] [Nonempty ι] [Nonempty ι'] - {s : Set ι} (hs : s.Nonempty) {f : ι → ι'} {g : ι' → α} - (hf : BddAbove (Set.range fun i : s ↦ g (f i))) (hg' : sSup ∅ ≤ ⨆ i : s, g (f i)) : - ⨆ i ∈ (f '' s), g i = ⨆ x ∈ s, g (f x) := by - have hg : BddAbove (Set.range fun i : f '' s ↦ g i) := by - simpa [bddAbove_def] using hf - have hf' : sSup ∅ ≤ ⨆ i : f '' s, g i := by - refine hg'.trans ?_ - have : Nonempty s := Set.Nonempty.to_subtype hs - refine ciSup_le ?_ - intro ⟨i, h⟩ - obtain ⟨t, ht⟩ : ∃ t : f '' s, g t = g (f (Subtype.mk i h)) := by - have : f i ∈ f '' s := Set.mem_image_of_mem _ h - exact ⟨⟨f i, this⟩, by simp [this]⟩ - rw [← ht] - refine le_ciSup_set ?_ t.prop - simpa [bddAbove_def] using hf - rw [← csSup_image (by simpa using hs) hg hf', ← csSup_image hs hf hg', ← Set.image_comp, comp_def] - -lemma ciInf_image {α ι ι' : Type*} [ConditionallyCompleteLattice α] [Nonempty ι] [Nonempty ι'] - {s : Set ι} (hs : s.Nonempty) {f : ι → ι'} {g : ι' → α} - (hf : BddBelow (Set.range fun i : s ↦ g (f i))) (hg' : ⨅ i : s, g (f i) ≤ sInf ∅) : - ⨅ i ∈ (f '' s), g i = ⨅ x ∈ s, g (f x) := - ciSup_image (α := αᵒᵈ) hs hf hg' - end ConditionallyCompleteLattice instance Pi.conditionallyCompleteLattice {ι : Type*} {α : ι → Type*} [∀ i, ConditionallyCompleteLattice (α i)] : ConditionallyCompleteLattice (∀ i, α i) := { Pi.instLattice, Pi.supSet, Pi.infSet with - le_csSup := fun s f ⟨g, hg⟩ hf i => - le_csSup ⟨g i, Set.forall_mem_range.2 fun ⟨f', hf'⟩ => hg hf' i⟩ ⟨⟨f, hf⟩, rfl⟩ - csSup_le := fun s f hs hf i => - (csSup_le (by haveI := hs.to_subtype; apply range_nonempty)) fun b ⟨⟨g, hg⟩, hb⟩ => + le_csSup := fun _ f ⟨g, hg⟩ hf i => + le_csSup ⟨g i, Set.forall_mem_range.2 fun ⟨_, hf'⟩ => hg hf' i⟩ ⟨⟨f, hf⟩, rfl⟩ + csSup_le := fun s _ hs hf i => + (csSup_le (by haveI := hs.to_subtype; apply range_nonempty)) fun _ ⟨⟨_, hg⟩, hb⟩ => hb ▸ hf hg i - csInf_le := fun s f ⟨g, hg⟩ hf i => - csInf_le ⟨g i, Set.forall_mem_range.2 fun ⟨f', hf'⟩ => hg hf' i⟩ ⟨⟨f, hf⟩, rfl⟩ - le_csInf := fun s f hs hf i => - (le_csInf (by haveI := hs.to_subtype; apply range_nonempty)) fun b ⟨⟨g, hg⟩, hb⟩ => + csInf_le := fun _ f ⟨g, hg⟩ hf i => + csInf_le ⟨g i, Set.forall_mem_range.2 fun ⟨_, hf'⟩ => hg hf' i⟩ ⟨⟨f, hf⟩, rfl⟩ + le_csInf := fun s _ hs hf i => + (le_csInf (by haveI := hs.to_subtype; apply range_nonempty)) fun _ ⟨⟨_, hg⟩, hb⟩ => hb ▸ hf hg i } section ConditionallyCompleteLinearOrder @@ -983,23 +662,16 @@ theorem exists_lt_of_lt_csSup (hs : s.Nonempty) (hb : b < sSup s) : ∃ a ∈ s, contrapose! hb exact csSup_le hs hb -/-- Indexed version of the above lemma `exists_lt_of_lt_csSup`. -When `b < iSup f`, there is an element `i` such that `b < f i`. --/ -theorem exists_lt_of_lt_ciSup [Nonempty ι] {f : ι → α} (h : b < iSup f) : ∃ i, b < f i := - let ⟨_, ⟨i, rfl⟩, h⟩ := exists_lt_of_lt_csSup (range_nonempty f) h - ⟨i, h⟩ - /-- When `sInf s < b`, there is an element `a` in `s` with `a < b`, if `s` is nonempty and the order is a linear order. -/ theorem exists_lt_of_csInf_lt (hs : s.Nonempty) (hb : sInf s < b) : ∃ a ∈ s, a < b := exists_lt_of_lt_csSup (α := αᵒᵈ) hs hb -/-- Indexed version of the above lemma `exists_lt_of_csInf_lt` -When `iInf f < a`, there is an element `i` such that `f i < a`. --/ -theorem exists_lt_of_ciInf_lt [Nonempty ι] {f : ι → α} (h : iInf f < a) : ∃ i, f i < a := - exists_lt_of_lt_ciSup (α := αᵒᵈ) h +theorem lt_csSup_iff (hb : BddAbove s) (hs : s.Nonempty) : a < sSup s ↔ ∃ b ∈ s, a < b := by + simpa only [not_le, not_forall₂, exists_prop] using (csSup_le_iff hb hs (a := a)).not + +theorem csInf_lt_iff (hb : BddBelow s) (hs : s.Nonempty) : sInf s < a ↔ ∃ b ∈ s, b < a := by + simpa only [not_le, not_forall₂, exists_prop] using (le_csInf_iff hb hs).not theorem csSup_of_not_bddAbove {s : Set α} (hs : ¬BddAbove s) : sSup s = sSup ∅ := ConditionallyCompleteLinearOrder.csSup_of_not_bddAbove s hs @@ -1065,50 +737,11 @@ lemma sSup_iUnion_Iic (f : ι → α) : sSup (⋃ (i : ι), Iic (f i)) = ⨆ i, lemma sInf_iUnion_Ici (f : ι → α) : sInf (⋃ (i : ι), Ici (f i)) = ⨅ i, f i := sSup_iUnion_Iic (α := αᵒᵈ) f -theorem cbiSup_eq_of_not_forall {p : ι → Prop} {f : Subtype p → α} (hp : ¬ (∀ i, p i)) : - ⨆ (i) (h : p i), f ⟨i, h⟩ = iSup f ⊔ sSup ∅ := by - classical - rcases not_forall.1 hp with ⟨i₀, hi₀⟩ - have : Nonempty ι := ⟨i₀⟩ - simp only [ciSup_eq_ite] - by_cases H : BddAbove (range f) - · have B : BddAbove (range fun i ↦ if h : p i then f ⟨i, h⟩ else sSup ∅) := by - rcases H with ⟨c, hc⟩ - refine ⟨c ⊔ sSup ∅, ?_⟩ - rintro - ⟨i, rfl⟩ - by_cases hi : p i - · simp only [hi, dite_true, le_sup_iff, hc (mem_range_self _), true_or] - · simp only [hi, dite_false, le_sup_right] - apply le_antisymm - · apply ciSup_le (fun i ↦ ?_) - by_cases hi : p i - · simp only [hi, dite_true, le_sup_iff] - left - exact le_ciSup H _ - · simp [hi] - · apply sup_le - · rcases isEmpty_or_nonempty (Subtype p) with hp|hp - · rw [iSup_of_empty'] - convert le_ciSup B i₀ - simp [hi₀] - · apply ciSup_le - rintro ⟨i, hi⟩ - convert le_ciSup B i - simp [hi] - · convert le_ciSup B i₀ - simp [hi₀] - · have : iSup f = sSup (∅ : Set α) := csSup_of_not_bddAbove H - simp only [this, le_refl, sup_of_le_left] - apply csSup_of_not_bddAbove - contrapose! H - apply H.mono - rintro - ⟨i, rfl⟩ - convert mem_range_self i.1 - simp [i.2] - -theorem cbiInf_eq_of_not_forall {p : ι → Prop} {f : Subtype p → α} (hp : ¬ (∀ i, p i)) : - ⨅ (i) (h : p i), f ⟨i, h⟩ = iInf f ⊓ sInf ∅ := - cbiSup_eq_of_not_forall (α := αᵒᵈ) hp +theorem csInf_eq_bot_of_bot_mem [OrderBot α] {s : Set α} (hs : ⊥ ∈ s) : sInf s = ⊥ := + eq_bot_iff.2 <| csInf_le (OrderBot.bddBelow s) hs + +theorem csSup_eq_top_of_top_mem [OrderTop α] {s : Set α} (hs : ⊤ ∈ s) : sSup s = ⊤ := + csInf_eq_bot_of_bot_mem (α := αᵒᵈ) hs open Function @@ -1127,9 +760,6 @@ theorem le_csInf_iff' (hs : s.Nonempty) : b ≤ sInf s ↔ b ∈ lowerBounds s : theorem csInf_mem (hs : s.Nonempty) : sInf s ∈ s := (isLeast_csInf hs).1 -theorem ciInf_mem [Nonempty ι] (f : ι → α) : iInf f ∈ range f := - csInf_mem (range_nonempty f) - theorem MonotoneOn.map_csInf {β : Type*} [ConditionallyCompleteLattice β] {f : α → β} (hf : MonotoneOn f s) (hs : s.Nonempty) : f (sInf s) = sInf (f '' s) := (hf.map_isLeast (isLeast_csInf hs)).csInf_eq.symm @@ -1159,66 +789,41 @@ variable [ConditionallyCompleteLinearOrderBot α] {s : Set α} {f : ι → α} { theorem csSup_empty : (sSup ∅ : α) = ⊥ := ConditionallyCompleteLinearOrderBot.csSup_empty -@[simp] -theorem ciSup_of_empty [IsEmpty ι] (f : ι → α) : ⨆ i, f i = ⊥ := by - rw [iSup_of_empty', csSup_empty] - -theorem ciSup_false (f : False → α) : ⨆ i, f i = ⊥ := - ciSup_of_empty f - theorem isLUB_csSup' {s : Set α} (hs : BddAbove s) : IsLUB s (sSup s) := by rcases eq_empty_or_nonempty s with (rfl | hne) · simp only [csSup_empty, isLUB_empty] · exact isLUB_csSup hne hs +/-- In conditionally complete orders with a bottom element, the nonempty condition can be omitted +from `csSup_le_iff`. -/ theorem csSup_le_iff' {s : Set α} (hs : BddAbove s) {a : α} : sSup s ≤ a ↔ ∀ x ∈ s, x ≤ a := isLUB_le_iff (isLUB_csSup' hs) theorem csSup_le' {s : Set α} {a : α} (h : a ∈ upperBounds s) : sSup s ≤ a := (csSup_le_iff' ⟨a, h⟩).2 h +/-- In conditionally complete orders with a bottom element, the nonempty condition can be omitted +from `lt_csSup_iff`. -/ +theorem lt_csSup_iff' (hb : BddAbove s) : a < sSup s ↔ ∃ b ∈ s, a < b := by + simpa only [not_le, not_forall₂, exists_prop] using (csSup_le_iff' hb).not + theorem le_csSup_iff' {s : Set α} {a : α} (h : BddAbove s) : a ≤ sSup s ↔ ∀ b, b ∈ upperBounds s → a ≤ b := ⟨fun h _ hb => le_trans h (csSup_le' hb), fun hb => hb _ fun _ => le_csSup h⟩ -theorem le_ciSup_iff' {s : ι → α} {a : α} (h : BddAbove (range s)) : - a ≤ iSup s ↔ ∀ b, (∀ i, s i ≤ b) → a ≤ b := by simp [iSup, h, le_csSup_iff', upperBounds] - theorem le_csInf_iff'' {s : Set α} {a : α} (ne : s.Nonempty) : a ≤ sInf s ↔ ∀ b : α, b ∈ s → a ≤ b := le_csInf_iff (OrderBot.bddBelow _) ne -theorem le_ciInf_iff' [Nonempty ι] {f : ι → α} {a : α} : a ≤ iInf f ↔ ∀ i, a ≤ f i := - le_ciInf_iff (OrderBot.bddBelow _) - theorem csInf_le' (h : a ∈ s) : sInf s ≤ a := csInf_le (OrderBot.bddBelow _) h -theorem ciInf_le' (f : ι → α) (i : ι) : iInf f ≤ f i := ciInf_le (OrderBot.bddBelow _) _ - -lemma ciInf_le_of_le' (c : ι) : f c ≤ a → iInf f ≤ a := ciInf_le_of_le (OrderBot.bddBelow _) _ - theorem exists_lt_of_lt_csSup' {s : Set α} {a : α} (h : a < sSup s) : ∃ b ∈ s, a < b := by contrapose! h exact csSup_le' h -theorem ciSup_le_iff' {f : ι → α} (h : BddAbove (range f)) {a : α} : - ⨆ i, f i ≤ a ↔ ∀ i, f i ≤ a := - (csSup_le_iff' h).trans forall_mem_range - -theorem ciSup_le' {f : ι → α} {a : α} (h : ∀ i, f i ≤ a) : ⨆ i, f i ≤ a := - csSup_le' <| forall_mem_range.2 h - -theorem exists_lt_of_lt_ciSup' {f : ι → α} {a : α} (h : a < ⨆ i, f i) : ∃ i, a < f i := by - contrapose! h - exact ciSup_le' h - theorem not_mem_of_lt_csInf' {x : α} {s : Set α} (h : x < sInf s) : x ∉ s := not_mem_of_lt_csInf h (OrderBot.bddBelow s) -theorem ciSup_mono' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove (range g)) - (h : ∀ i, ∃ i', f i ≤ g i') : iSup f ≤ iSup g := - ciSup_le' fun i => Exists.elim (h i) (le_ciSup_of_le hg) - theorem csInf_le_csInf' {s t : Set α} (h₁ : t.Nonempty) (h₂ : t ⊆ s) : sInf s ≤ sInf t := csInf_le_csInf (OrderBot.bddBelow s) h₁ h₂ @@ -1228,14 +833,6 @@ theorem csSup_le_csSup' {s t : Set α} (h₁ : BddAbove t) (h₂ : s ⊆ t) : sS exact bot_le · exact csSup_le_csSup h₁ h h₂ -lemma ciSup_or' (p q : Prop) (f : p ∨ q → α) : - ⨆ (h : p ∨ q), f h = (⨆ h : p, f (.inl h)) ⊔ ⨆ h : q, f (.inr h) := by - by_cases hp : p <;> by_cases hq : q - · simp [hp, hq] - · simp [hp, hq] - · simp [hp, hq] - · simp [hp, hq] - end ConditionallyCompleteLinearOrderBot namespace WithTop @@ -1401,83 +998,6 @@ theorem le_csInf_image {s : Set α} (hs : s.Nonempty) {B : α} (hB : B ∈ lower end Monotone -namespace GaloisConnection - -variable [ConditionallyCompleteLattice α] [ConditionallyCompleteLattice β] [Nonempty ι] {l : α → β} - {u : β → α} - -theorem l_csSup (gc : GaloisConnection l u) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : - l (sSup s) = ⨆ x : s, l x := - Eq.symm <| IsLUB.ciSup_set_eq (gc.isLUB_l_image <| isLUB_csSup hne hbdd) hne - -theorem l_csSup' (gc : GaloisConnection l u) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : - l (sSup s) = sSup (l '' s) := by rw [gc.l_csSup hne hbdd, sSup_image'] - -theorem l_ciSup (gc : GaloisConnection l u) {f : ι → α} (hf : BddAbove (range f)) : - l (⨆ i, f i) = ⨆ i, l (f i) := by rw [iSup, gc.l_csSup (range_nonempty _) hf, iSup_range'] - -theorem l_ciSup_set (gc : GaloisConnection l u) {s : Set γ} {f : γ → α} (hf : BddAbove (f '' s)) - (hne : s.Nonempty) : l (⨆ i : s, f i) = ⨆ i : s, l (f i) := by - haveI := hne.to_subtype - rw [image_eq_range] at hf - exact gc.l_ciSup hf - -theorem u_csInf (gc : GaloisConnection l u) {s : Set β} (hne : s.Nonempty) (hbdd : BddBelow s) : - u (sInf s) = ⨅ x : s, u x := - gc.dual.l_csSup hne hbdd - -theorem u_csInf' (gc : GaloisConnection l u) {s : Set β} (hne : s.Nonempty) (hbdd : BddBelow s) : - u (sInf s) = sInf (u '' s) := - gc.dual.l_csSup' hne hbdd - -theorem u_ciInf (gc : GaloisConnection l u) {f : ι → β} (hf : BddBelow (range f)) : - u (⨅ i, f i) = ⨅ i, u (f i) := - gc.dual.l_ciSup hf - -theorem u_ciInf_set (gc : GaloisConnection l u) {s : Set γ} {f : γ → β} (hf : BddBelow (f '' s)) - (hne : s.Nonempty) : u (⨅ i : s, f i) = ⨅ i : s, u (f i) := - gc.dual.l_ciSup_set hf hne - -end GaloisConnection - -namespace OrderIso - -variable [ConditionallyCompleteLattice α] [ConditionallyCompleteLattice β] [Nonempty ι] - -theorem map_csSup (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : - e (sSup s) = ⨆ x : s, e x := - e.to_galoisConnection.l_csSup hne hbdd - -theorem map_csSup' (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : - e (sSup s) = sSup (e '' s) := - e.to_galoisConnection.l_csSup' hne hbdd - -theorem map_ciSup (e : α ≃o β) {f : ι → α} (hf : BddAbove (range f)) : - e (⨆ i, f i) = ⨆ i, e (f i) := - e.to_galoisConnection.l_ciSup hf - -theorem map_ciSup_set (e : α ≃o β) {s : Set γ} {f : γ → α} (hf : BddAbove (f '' s)) - (hne : s.Nonempty) : e (⨆ i : s, f i) = ⨆ i : s, e (f i) := - e.to_galoisConnection.l_ciSup_set hf hne - -theorem map_csInf (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddBelow s) : - e (sInf s) = ⨅ x : s, e x := - e.dual.map_csSup hne hbdd - -theorem map_csInf' (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddBelow s) : - e (sInf s) = sInf (e '' s) := - e.dual.map_csSup' hne hbdd - -theorem map_ciInf (e : α ≃o β) {f : ι → α} (hf : BddBelow (range f)) : - e (⨅ i, f i) = ⨅ i, e (f i) := - e.dual.map_ciSup hf - -theorem map_ciInf_set (e : α ≃o β) {s : Set γ} {f : γ → α} (hf : BddBelow (f '' s)) - (hne : s.Nonempty) : e (⨅ i : s, f i) = ⨅ i : s, e (f i) := - e.dual.map_ciSup_set hf hne - -end OrderIso - /-! ### Supremum/infimum of `Set.image2` @@ -1485,7 +1005,6 @@ A collection of lemmas showing what happens to the suprema/infima of `s` and `t` a binary function whose partial evaluations are lower/upper adjoints of Galois connections. -/ - section variable [ConditionallyCompleteLattice α] [ConditionallyCompleteLattice β] @@ -1582,7 +1101,7 @@ open Classical in noncomputable instance WithTop.WithBot.completeLattice {α : Type*} [ConditionallyCompleteLattice α] : CompleteLattice (WithTop (WithBot α)) := { instInfSet, instSupSet, boundedOrder, lattice with - le_sSup := fun S a haS => (WithTop.isLUB_sSup' ⟨a, haS⟩).1 haS + le_sSup := fun _ a haS => (WithTop.isLUB_sSup' ⟨a, haS⟩).1 haS sSup_le := fun S a ha => by rcases S.eq_empty_or_nonempty with h | h · show ite _ _ _ ≤ a @@ -1614,7 +1133,7 @@ noncomputable instance WithTop.WithBot.completeLattice {α : Type*} use ⊥ intro b _ exact bot_le - le_sInf := fun S a haS => (WithTop.isGLB_sInf' ⟨a, haS⟩).2 haS } + le_sInf := fun _ a haS => (WithTop.isGLB_sInf' ⟨a, haS⟩).2 haS } noncomputable instance WithTop.WithBot.completeLinearOrder {α : Type*} [ConditionallyCompleteLinearOrder α] : CompleteLinearOrder (WithTop (WithBot α)) := @@ -1633,26 +1152,4 @@ noncomputable instance WithBot.WithTop.completeLinearOrder {α : Type*} [ConditionallyCompleteLinearOrder α] : CompleteLinearOrder (WithBot (WithTop α)) := { completeLattice, linearOrder, LinearOrder.toBiheytingAlgebra with } -namespace WithTop -variable [ConditionallyCompleteLinearOrderBot α] {f : ι → α} - -lemma iSup_coe_eq_top : ⨆ x, (f x : WithTop α) = ⊤ ↔ ¬BddAbove (range f) := by - rw [iSup_eq_top, not_bddAbove_iff] - refine ⟨fun hf r => ?_, fun hf a ha => ?_⟩ - · rcases hf r (WithTop.coe_lt_top r) with ⟨i, hi⟩ - exact ⟨f i, ⟨i, rfl⟩, WithTop.coe_lt_coe.mp hi⟩ - · rcases hf (a.untop ha.ne) with ⟨-, ⟨i, rfl⟩, hi⟩ - exact ⟨i, by simpa only [WithTop.coe_untop _ ha.ne] using WithTop.coe_lt_coe.mpr hi⟩ - -lemma iSup_coe_lt_top : ⨆ x, (f x : WithTop α) < ⊤ ↔ BddAbove (range f) := - lt_top_iff_ne_top.trans iSup_coe_eq_top.not_left - -lemma iInf_coe_eq_top : ⨅ x, (f x : WithTop α) = ⊤ ↔ IsEmpty ι := by simp [isEmpty_iff] - -lemma iInf_coe_lt_top : ⨅ i, (f i : WithTop α) < ⊤ ↔ Nonempty ι := by - rw [lt_top_iff_ne_top, Ne, iInf_coe_eq_top, not_isEmpty_iff] - -end WithTop end WithTopBot - -set_option linter.style.longFile 1700 diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index c493a2324fc8c..984c9aa53741f 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 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.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Data.Set.Finite /-! diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Group.lean b/Mathlib/Order/ConditionallyCompleteLattice/Group.lean index 70a7b16d5447a..6d0082e85feca 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Group.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Group.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 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.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Algebra.Order.Group.Unbundled.Basic import Mathlib.Algebra.Order.Monoid.Unbundled.OrderDual @@ -19,34 +19,32 @@ variable {α : Type*} {ι : Sort*} {ι' : Sort*} [Nonempty ι] [Nonempty ι'] [ConditionallyCompleteLattice α] [Group α] @[to_additive] -theorem le_mul_ciInf [CovariantClass α α (· * ·) (· ≤ ·)] {a : α} {g : α} {h : ι → α} +theorem le_mul_ciInf [MulLeftMono α] {a : α} {g : α} {h : ι → α} (H : ∀ j, a ≤ g * h j) : a ≤ g * iInf h := inv_mul_le_iff_le_mul.mp <| le_ciInf fun _ => inv_mul_le_iff_le_mul.mpr <| H _ @[to_additive] -theorem mul_ciSup_le [CovariantClass α α (· * ·) (· ≤ ·)] {a : α} {g : α} {h : ι → α} +theorem mul_ciSup_le [MulLeftMono α] {a : α} {g : α} {h : ι → α} (H : ∀ j, g * h j ≤ a) : g * iSup h ≤ a := le_mul_ciInf (α := αᵒᵈ) H @[to_additive] -theorem le_ciInf_mul [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a : α} {g : ι → α} +theorem le_ciInf_mul [MulRightMono α] {a : α} {g : ι → α} {h : α} (H : ∀ i, a ≤ g i * h) : a ≤ iInf g * h := mul_inv_le_iff_le_mul.mp <| le_ciInf fun _ => mul_inv_le_iff_le_mul.mpr <| H _ @[to_additive] -theorem ciSup_mul_le [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a : α} {g : ι → α} +theorem ciSup_mul_le [MulRightMono α] {a : α} {g : ι → α} {h : α} (H : ∀ i, g i * h ≤ a) : iSup g * h ≤ a := le_ciInf_mul (α := αᵒᵈ) H @[to_additive] -theorem le_ciInf_mul_ciInf [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a : α} {g : ι → α} {h : ι' → α} +theorem le_ciInf_mul_ciInf [MulLeftMono α] [MulRightMono α] {a : α} {g : ι → α} {h : ι' → α} (H : ∀ i j, a ≤ g i * h j) : a ≤ iInf g * iInf h := le_ciInf_mul fun _ => le_mul_ciInf <| H _ @[to_additive] -theorem ciSup_mul_ciSup_le [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a : α} {g : ι → α} {h : ι' → α} +theorem ciSup_mul_ciSup_le [MulLeftMono α] [MulRightMono α] {a : α} {g : ι → α} {h : ι' → α} (H : ∀ i j, g i * h j ≤ a) : iSup g * iSup h ≤ a := ciSup_mul_le fun _ => mul_ciSup_le <| H _ diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean b/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean new file mode 100644 index 0000000000000..667d696dff1b2 --- /dev/null +++ b/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean @@ -0,0 +1,596 @@ +/- +Copyright (c) 2018 Sébastian Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastian Gouëzel +-/ +import Mathlib.Order.ConditionallyCompleteLattice.Basic + +/-! +# Indexed sup / inf in conditionally complete lattices + +This file proves lemmas about `iSup` and `iInf` for functions valued in a conditionally complete, +rather than complete, lattice. We add a prefix `c` to distinguish them from the versions for +complete lattices, giving names `ciSup_xxx` or `ciInf_xxx`. +-/ + +-- Guard against import creep +assert_not_exists Multiset + +open Function OrderDual Set + +variable {α β γ : Type*} {ι : Sort*} + +section + +/-! +Extension of `iSup` and `iInf` from a preorder `α` to `WithTop α` and `WithBot α` +-/ + +variable [Preorder α] + +@[simp] +theorem WithTop.iInf_empty [IsEmpty ι] [InfSet α] (f : ι → WithTop α) : + ⨅ i, f i = ⊤ := by rw [iInf, range_eq_empty, WithTop.sInf_empty] + +@[norm_cast] +theorem WithTop.coe_iInf [Nonempty ι] [InfSet α] {f : ι → α} (hf : BddBelow (range f)) : + ↑(⨅ i, f i) = (⨅ i, f i : WithTop α) := by + rw [iInf, iInf, WithTop.coe_sInf' (range_nonempty f) hf, ← range_comp, Function.comp_def] + +@[norm_cast] +theorem WithTop.coe_iSup [SupSet α] (f : ι → α) (h : BddAbove (Set.range f)) : + ↑(⨆ i, f i) = (⨆ i, f i : WithTop α) := by + rw [iSup, iSup, WithTop.coe_sSup' h, ← range_comp, Function.comp_def] + +@[simp] +theorem WithBot.ciSup_empty [IsEmpty ι] [SupSet α] (f : ι → WithBot α) : + ⨆ i, f i = ⊥ := + WithTop.iInf_empty (α := αᵒᵈ) _ + +@[norm_cast] +theorem WithBot.coe_iSup [Nonempty ι] [SupSet α] {f : ι → α} (hf : BddAbove (range f)) : + ↑(⨆ i, f i) = (⨆ i, f i : WithBot α) := + WithTop.coe_iInf (α := αᵒᵈ) hf + +@[norm_cast] +theorem WithBot.coe_iInf [InfSet α] (f : ι → α) (h : BddBelow (Set.range f)) : + ↑(⨅ i, f i) = (⨅ i, f i : WithBot α) := + WithTop.coe_iSup (α := αᵒᵈ) _ h + +end + +section ConditionallyCompleteLattice + +variable [ConditionallyCompleteLattice α] {s t : Set α} {a b : α} + +theorem isLUB_ciSup [Nonempty ι] {f : ι → α} (H : BddAbove (range f)) : + IsLUB (range f) (⨆ i, f i) := + isLUB_csSup (range_nonempty f) H + +theorem isLUB_ciSup_set {f : β → α} {s : Set β} (H : BddAbove (f '' s)) (Hne : s.Nonempty) : + IsLUB (f '' s) (⨆ i : s, f i) := by + rw [← sSup_image'] + exact isLUB_csSup (Hne.image _) H + +theorem isGLB_ciInf [Nonempty ι] {f : ι → α} (H : BddBelow (range f)) : + IsGLB (range f) (⨅ i, f i) := + isGLB_csInf (range_nonempty f) H + +theorem isGLB_ciInf_set {f : β → α} {s : Set β} (H : BddBelow (f '' s)) (Hne : s.Nonempty) : + IsGLB (f '' s) (⨅ i : s, f i) := + isLUB_ciSup_set (α := αᵒᵈ) H Hne + +theorem ciSup_le_iff [Nonempty ι] {f : ι → α} {a : α} (hf : BddAbove (range f)) : + iSup f ≤ a ↔ ∀ i, f i ≤ a := + (isLUB_le_iff <| isLUB_ciSup hf).trans forall_mem_range + +theorem le_ciInf_iff [Nonempty ι] {f : ι → α} {a : α} (hf : BddBelow (range f)) : + a ≤ iInf f ↔ ∀ i, a ≤ f i := + (le_isGLB_iff <| isGLB_ciInf hf).trans forall_mem_range + +theorem ciSup_set_le_iff {ι : Type*} {s : Set ι} {f : ι → α} {a : α} (hs : s.Nonempty) + (hf : BddAbove (f '' s)) : ⨆ i : s, f i ≤ a ↔ ∀ i ∈ s, f i ≤ a := + (isLUB_le_iff <| isLUB_ciSup_set hf hs).trans forall_mem_image + +theorem le_ciInf_set_iff {ι : Type*} {s : Set ι} {f : ι → α} {a : α} (hs : s.Nonempty) + (hf : BddBelow (f '' s)) : (a ≤ ⨅ i : s, f i) ↔ ∀ i ∈ s, a ≤ f i := + (le_isGLB_iff <| isGLB_ciInf_set hf hs).trans forall_mem_image + +theorem IsLUB.ciSup_eq [Nonempty ι] {f : ι → α} (H : IsLUB (range f) a) : ⨆ i, f i = a := + H.csSup_eq (range_nonempty f) + +theorem IsLUB.ciSup_set_eq {s : Set β} {f : β → α} (H : IsLUB (f '' s) a) (Hne : s.Nonempty) : + ⨆ i : s, f i = a := + IsLUB.csSup_eq (image_eq_range f s ▸ H) (image_eq_range f s ▸ Hne.image f) + +theorem IsGLB.ciInf_eq [Nonempty ι] {f : ι → α} (H : IsGLB (range f) a) : ⨅ i, f i = a := + H.csInf_eq (range_nonempty f) + +theorem IsGLB.ciInf_set_eq {s : Set β} {f : β → α} (H : IsGLB (f '' s) a) (Hne : s.Nonempty) : + ⨅ i : s, f i = a := + IsGLB.csInf_eq (image_eq_range f s ▸ H) (image_eq_range f s ▸ Hne.image f) + +/-- The indexed supremum of a function is bounded above by a uniform bound -/ +theorem ciSup_le [Nonempty ι] {f : ι → α} {c : α} (H : ∀ x, f x ≤ c) : iSup f ≤ c := + csSup_le (range_nonempty f) (by rwa [forall_mem_range]) + +/-- The indexed supremum of a function is bounded below by the value taken at one point -/ +theorem le_ciSup {f : ι → α} (H : BddAbove (range f)) (c : ι) : f c ≤ iSup f := + le_csSup H (mem_range_self _) + +theorem le_ciSup_of_le {f : ι → α} (H : BddAbove (range f)) (c : ι) (h : a ≤ f c) : a ≤ iSup f := + le_trans h (le_ciSup H c) + +/-- The indexed suprema of two functions are comparable if the functions are pointwise comparable -/ +theorem ciSup_mono {f g : ι → α} (B : BddAbove (range g)) (H : ∀ x, f x ≤ g x) : + iSup f ≤ iSup g := by + cases isEmpty_or_nonempty ι + · rw [iSup_of_empty', iSup_of_empty'] + · exact ciSup_le fun x => le_ciSup_of_le B x (H x) + +theorem le_ciSup_set {f : β → α} {s : Set β} (H : BddAbove (f '' s)) {c : β} (hc : c ∈ s) : + f c ≤ ⨆ i : s, f i := + (le_csSup H <| mem_image_of_mem f hc).trans_eq sSup_image' + +/-- The indexed infimum of two functions are comparable if the functions are pointwise comparable -/ +theorem ciInf_mono {f g : ι → α} (B : BddBelow (range f)) (H : ∀ x, f x ≤ g x) : iInf f ≤ iInf g := + ciSup_mono (α := αᵒᵈ) B H + +/-- The indexed minimum of a function is bounded below by a uniform lower bound -/ +theorem le_ciInf [Nonempty ι] {f : ι → α} {c : α} (H : ∀ x, c ≤ f x) : c ≤ iInf f := + ciSup_le (α := αᵒᵈ) H + +/-- The indexed infimum of a function is bounded above by the value taken at one point -/ +theorem ciInf_le {f : ι → α} (H : BddBelow (range f)) (c : ι) : iInf f ≤ f c := + le_ciSup (α := αᵒᵈ) H c + +theorem ciInf_le_of_le {f : ι → α} (H : BddBelow (range f)) (c : ι) (h : f c ≤ a) : iInf f ≤ a := + le_ciSup_of_le (α := αᵒᵈ) H c h + +theorem ciInf_set_le {f : β → α} {s : Set β} (H : BddBelow (f '' s)) {c : β} (hc : c ∈ s) : + ⨅ i : s, f i ≤ f c := + le_ciSup_set (α := αᵒᵈ) H hc + +@[simp] +theorem ciSup_const [hι : Nonempty ι] {a : α} : ⨆ _ : ι, a = a := by + rw [iSup, range_const, csSup_singleton] + +@[simp] +theorem ciInf_const [Nonempty ι] {a : α} : ⨅ _ : ι, a = a := + ciSup_const (α := αᵒᵈ) + +@[simp] +theorem ciSup_unique [Unique ι] {s : ι → α} : ⨆ i, s i = s default := by + have : ∀ i, s i = s default := fun i => congr_arg s (Unique.eq_default i) + simp only [this, ciSup_const] + +@[simp] +theorem ciInf_unique [Unique ι] {s : ι → α} : ⨅ i, s i = s default := + ciSup_unique (α := αᵒᵈ) + +theorem ciSup_subsingleton [Subsingleton ι] (i : ι) (s : ι → α) : ⨆ i, s i = s i := + @ciSup_unique α ι _ ⟨⟨i⟩, fun j => Subsingleton.elim j i⟩ _ + +theorem ciInf_subsingleton [Subsingleton ι] (i : ι) (s : ι → α) : ⨅ i, s i = s i := + @ciInf_unique α ι _ ⟨⟨i⟩, fun j => Subsingleton.elim j i⟩ _ + +@[simp] +theorem ciSup_pos {p : Prop} {f : p → α} (hp : p) : ⨆ h : p, f h = f hp := + ciSup_subsingleton hp f + +@[simp] +theorem ciInf_pos {p : Prop} {f : p → α} (hp : p) : ⨅ h : p, f h = f hp := + ciSup_pos (α := αᵒᵈ) hp + +lemma ciSup_neg {p : Prop} {f : p → α} (hp : ¬ p) : + ⨆ (h : p), f h = sSup (∅ : Set α) := by + rw [iSup] + congr + rwa [range_eq_empty_iff, isEmpty_Prop] + +lemma ciInf_neg {p : Prop} {f : p → α} (hp : ¬ p) : + ⨅ (h : p), f h = sInf (∅ : Set α) := + ciSup_neg (α := αᵒᵈ) hp + +lemma ciSup_eq_ite {p : Prop} [Decidable p] {f : p → α} : + (⨆ h : p, f h) = if h : p then f h else sSup (∅ : Set α) := by + by_cases H : p <;> simp [ciSup_neg, H] + +lemma ciInf_eq_ite {p : Prop} [Decidable p] {f : p → α} : + (⨅ h : p, f h) = if h : p then f h else sInf (∅ : Set α) := + ciSup_eq_ite (α := αᵒᵈ) + +theorem cbiSup_eq_of_forall {p : ι → Prop} {f : Subtype p → α} (hp : ∀ i, p i) : + ⨆ (i) (h : p i), f ⟨i, h⟩ = iSup f := by + simp only [hp, ciSup_unique] + simp only [iSup] + congr + apply Subset.antisymm + · rintro - ⟨i, rfl⟩ + simp [hp i] + · rintro - ⟨i, rfl⟩ + simp + +theorem cbiInf_eq_of_forall {p : ι → Prop} {f : Subtype p → α} (hp : ∀ i, p i) : + ⨅ (i) (h : p i), f ⟨i, h⟩ = iInf f := + cbiSup_eq_of_forall (α := αᵒᵈ) hp + +/-- Introduction rule to prove that `b` is the supremum of `f`: it suffices to check that `b` +is larger than `f i` for all `i`, and that this is not the case of any `w exists_range_iff.mpr <| h₂ w hw + +-- Porting note: in mathlib3 `by exact` is not needed +/-- Introduction rule to prove that `b` is the infimum of `f`: it suffices to check that `b` +is smaller than `f i` for all `i`, and that this is not the case of any `w>b`. +See `iInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in complete lattices. -/ +theorem ciInf_eq_of_forall_ge_of_forall_gt_exists_lt [Nonempty ι] {f : ι → α} (h₁ : ∀ i, b ≤ f i) + (h₂ : ∀ w, b < w → ∃ i, f i < w) : ⨅ i : ι, f i = b := by + exact ciSup_eq_of_forall_le_of_forall_lt_exists_gt (α := αᵒᵈ) (f := ‹_›) ‹_› ‹_› + +/-- **Nested intervals lemma**: if `f` is a monotone sequence, `g` is an antitone sequence, and +`f n ≤ g n` for all `n`, then `⨆ n, f n` belongs to all the intervals `[f n, g n]`. -/ +theorem Monotone.ciSup_mem_iInter_Icc_of_antitone [SemilatticeSup β] {f g : β → α} (hf : Monotone f) + (hg : Antitone g) (h : f ≤ g) : (⨆ n, f n) ∈ ⋂ n, Icc (f n) (g n) := by + refine mem_iInter.2 fun n => ?_ + haveI : Nonempty β := ⟨n⟩ + have : ∀ m, f m ≤ g n := fun m => hf.forall_le_of_antitone hg h m n + exact ⟨le_ciSup ⟨g <| n, forall_mem_range.2 this⟩ _, ciSup_le this⟩ + +/-- Nested intervals lemma: if `[f n, g n]` is an antitone sequence of nonempty +closed intervals, then `⨆ n, f n` belongs to all the intervals `[f n, g n]`. -/ +theorem ciSup_mem_iInter_Icc_of_antitone_Icc [SemilatticeSup β] {f g : β → α} + (h : Antitone fun n => Icc (f n) (g n)) (h' : ∀ n, f n ≤ g n) : + (⨆ n, f n) ∈ ⋂ n, Icc (f n) (g n) := + Monotone.ciSup_mem_iInter_Icc_of_antitone + (fun _ n hmn => ((Icc_subset_Icc_iff (h' n)).1 (h hmn)).1) + (fun _ n hmn => ((Icc_subset_Icc_iff (h' n)).1 (h hmn)).2) h' + +lemma Set.Iic_ciInf [Nonempty ι] {f : ι → α} (hf : BddBelow (range f)) : + Iic (⨅ i, f i) = ⋂ i, Iic (f i) := by + apply Subset.antisymm + · rintro x hx - ⟨i, rfl⟩ + exact hx.trans (ciInf_le hf _) + · rintro x hx + apply le_ciInf + simpa using hx + +lemma Set.Ici_ciSup [Nonempty ι] {f : ι → α} (hf : BddAbove (range f)) : + Ici (⨆ i, f i) = ⋂ i, Ici (f i) := + Iic_ciInf (α := αᵒᵈ) hf + +theorem ciSup_subtype [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : Subtype p → α} + (hf : BddAbove (Set.range f)) (hf' : sSup ∅ ≤ iSup f) : + iSup f = ⨆ (i) (h : p i), f ⟨i, h⟩ := by + classical + refine le_antisymm (ciSup_le ?_) ?_ + · intro ⟨i, h⟩ + have : f ⟨i, h⟩ = (fun i : ι ↦ ⨆ (h : p i), f ⟨i, h⟩) i := by simp [h] + rw [this] + refine le_ciSup (f := (fun i : ι ↦ ⨆ (h : p i), f ⟨i, h⟩)) ?_ i + simp_rw [ciSup_eq_ite] + refine (hf.union (bddAbove_singleton (a := sSup ∅))).mono ?_ + intro + simp only [Set.mem_range, Set.union_singleton, Set.mem_insert_iff, Subtype.exists, + forall_exists_index] + intro b hb + split_ifs at hb + · exact Or.inr ⟨_, _, hb⟩ + · simp_all + · refine ciSup_le fun i ↦ ?_ + simp_rw [ciSup_eq_ite] + split_ifs + · exact le_ciSup hf ?_ + · exact hf' + +theorem ciInf_subtype [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : Subtype p → α} + (hf : BddBelow (Set.range f)) (hf' : iInf f ≤ sInf ∅) : + iInf f = ⨅ (i) (h : p i), f ⟨i, h⟩ := + ciSup_subtype (α := αᵒᵈ) hf hf' + +theorem ciSup_subtype' [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : ∀ i, p i → α} + (hf : BddAbove (Set.range (fun i : Subtype p ↦ f i i.prop))) + (hf' : sSup ∅ ≤ ⨆ (i : Subtype p), f i i.prop) : + ⨆ (i) (h), f i h = ⨆ x : Subtype p, f x x.property := + (ciSup_subtype (f := fun x => f x.val x.property) hf hf').symm + +theorem ciInf_subtype' [Nonempty ι] {p : ι → Prop} [Nonempty (Subtype p)] {f : ∀ i, p i → α} + (hf : BddBelow (Set.range (fun i : Subtype p ↦ f i i.prop))) + (hf' : ⨅ (i : Subtype p), f i i.prop ≤ sInf ∅) : + ⨅ (i) (h), f i h = ⨅ x : Subtype p, f x x.property := + (ciInf_subtype (f := fun x => f x.val x.property) hf hf').symm + +theorem ciSup_subtype'' {ι} [Nonempty ι] {s : Set ι} (hs : s.Nonempty) {f : ι → α} + (hf : BddAbove (Set.range fun i : s ↦ f i)) (hf' : sSup ∅ ≤ ⨆ i : s, f i) : + ⨆ i : s, f i = ⨆ (t : ι) (_ : t ∈ s), f t := + haveI : Nonempty s := Set.Nonempty.to_subtype hs + ciSup_subtype hf hf' + +theorem ciInf_subtype'' {ι} [Nonempty ι] {s : Set ι} (hs : s.Nonempty) {f : ι → α} + (hf : BddBelow (Set.range fun i : s ↦ f i)) (hf' : ⨅ i : s, f i ≤ sInf ∅) : + ⨅ i : s, f i = ⨅ (t : ι) (_ : t ∈ s), f t := + haveI : Nonempty s := Set.Nonempty.to_subtype hs + ciInf_subtype hf hf' + +theorem csSup_image [Nonempty β] {s : Set β} (hs : s.Nonempty) {f : β → α} + (hf : BddAbove (Set.range fun i : s ↦ f i)) (hf' : sSup ∅ ≤ ⨆ i : s, f i) : + sSup (f '' s) = ⨆ a ∈ s, f a := by + rw [← ciSup_subtype'' hs hf hf', iSup, Set.image_eq_range] + +theorem csInf_image [Nonempty β] {s : Set β} (hs : s.Nonempty) {f : β → α} + (hf : BddBelow (Set.range fun i : s ↦ f i)) (hf' : ⨅ i : s, f i ≤ sInf ∅) : + sInf (f '' s) = ⨅ a ∈ s, f a := + csSup_image (α := αᵒᵈ) hs hf hf' + +lemma ciSup_image {α ι ι' : Type*} [ConditionallyCompleteLattice α] [Nonempty ι] [Nonempty ι'] + {s : Set ι} (hs : s.Nonempty) {f : ι → ι'} {g : ι' → α} + (hf : BddAbove (Set.range fun i : s ↦ g (f i))) (hg' : sSup ∅ ≤ ⨆ i : s, g (f i)) : + ⨆ i ∈ (f '' s), g i = ⨆ x ∈ s, g (f x) := by + have hg : BddAbove (Set.range fun i : f '' s ↦ g i) := by + simpa [bddAbove_def] using hf + have hf' : sSup ∅ ≤ ⨆ i : f '' s, g i := by + refine hg'.trans ?_ + have : Nonempty s := Set.Nonempty.to_subtype hs + refine ciSup_le ?_ + intro ⟨i, h⟩ + obtain ⟨t, ht⟩ : ∃ t : f '' s, g t = g (f (Subtype.mk i h)) := by + have : f i ∈ f '' s := Set.mem_image_of_mem _ h + exact ⟨⟨f i, this⟩, by simp [this]⟩ + rw [← ht] + refine le_ciSup_set ?_ t.prop + simpa [bddAbove_def] using hf + rw [← csSup_image (by simpa using hs) hg hf', ← csSup_image hs hf hg', ← Set.image_comp, comp_def] + +lemma ciInf_image {α ι ι' : Type*} [ConditionallyCompleteLattice α] [Nonempty ι] [Nonempty ι'] + {s : Set ι} (hs : s.Nonempty) {f : ι → ι'} {g : ι' → α} + (hf : BddBelow (Set.range fun i : s ↦ g (f i))) (hg' : ⨅ i : s, g (f i) ≤ sInf ∅) : + ⨅ i ∈ (f '' s), g i = ⨅ x ∈ s, g (f x) := + ciSup_image (α := αᵒᵈ) hs hf hg' + +end ConditionallyCompleteLattice + +section ConditionallyCompleteLinearOrder + +variable [ConditionallyCompleteLinearOrder α] {s t : Set α} {a b : α} + +/-- Indexed version of `exists_lt_of_lt_csSup`. +When `b < iSup f`, there is an element `i` such that `b < f i`. +-/ +theorem exists_lt_of_lt_ciSup [Nonempty ι] {f : ι → α} (h : b < iSup f) : ∃ i, b < f i := + let ⟨_, ⟨i, rfl⟩, h⟩ := exists_lt_of_lt_csSup (range_nonempty f) h + ⟨i, h⟩ + +/-- Indexed version of `exists_lt_of_csInf_lt`. +When `iInf f < a`, there is an element `i` such that `f i < a`. +-/ +theorem exists_lt_of_ciInf_lt [Nonempty ι] {f : ι → α} (h : iInf f < a) : ∃ i, f i < a := + exists_lt_of_lt_ciSup (α := αᵒᵈ) h + +theorem lt_ciSup_iff [Nonempty ι] {f : ι → α} (hb : BddAbove (range f)) : + a < iSup f ↔ ∃ i, a < f i := by + simpa only [mem_range, exists_exists_eq_and] using lt_csSup_iff hb (range_nonempty _) + +theorem ciInf_lt_iff [Nonempty ι] {f : ι → α} (hb : BddBelow (range f)) : + iInf f < a ↔ ∃ i, f i < a := by + simpa only [mem_range, exists_exists_eq_and] using csInf_lt_iff hb (range_nonempty _) + +theorem cbiSup_eq_of_not_forall {p : ι → Prop} {f : Subtype p → α} (hp : ¬ (∀ i, p i)) : + ⨆ (i) (h : p i), f ⟨i, h⟩ = iSup f ⊔ sSup ∅ := by + classical + rcases not_forall.1 hp with ⟨i₀, hi₀⟩ + have : Nonempty ι := ⟨i₀⟩ + simp only [ciSup_eq_ite] + by_cases H : BddAbove (range f) + · have B : BddAbove (range fun i ↦ if h : p i then f ⟨i, h⟩ else sSup ∅) := by + rcases H with ⟨c, hc⟩ + refine ⟨c ⊔ sSup ∅, ?_⟩ + rintro - ⟨i, rfl⟩ + by_cases hi : p i + · simp only [hi, dite_true, le_sup_iff, hc (mem_range_self _), true_or] + · simp only [hi, dite_false, le_sup_right] + apply le_antisymm + · apply ciSup_le (fun i ↦ ?_) + by_cases hi : p i + · simp only [hi, dite_true, le_sup_iff] + left + exact le_ciSup H _ + · simp [hi] + · apply sup_le + · rcases isEmpty_or_nonempty (Subtype p) with hp|hp + · rw [iSup_of_empty'] + convert le_ciSup B i₀ + simp [hi₀] + · apply ciSup_le + rintro ⟨i, hi⟩ + convert le_ciSup B i + simp [hi] + · convert le_ciSup B i₀ + simp [hi₀] + · have : iSup f = sSup (∅ : Set α) := csSup_of_not_bddAbove H + simp only [this, le_refl, sup_of_le_left] + apply csSup_of_not_bddAbove + contrapose! H + apply H.mono + rintro - ⟨i, rfl⟩ + convert mem_range_self i.1 + simp [i.2] + +theorem cbiInf_eq_of_not_forall {p : ι → Prop} {f : Subtype p → α} (hp : ¬ (∀ i, p i)) : + ⨅ (i) (h : p i), f ⟨i, h⟩ = iInf f ⊓ sInf ∅ := + cbiSup_eq_of_not_forall (α := αᵒᵈ) hp + +theorem ciInf_eq_bot_of_bot_mem [OrderBot α] {f : ι → α} (hs : ⊥ ∈ range f) : iInf f = ⊥ := + csInf_eq_bot_of_bot_mem hs + +theorem ciInf_eq_top_of_top_mem [OrderTop α] {f : ι → α} (hs : ⊤ ∈ range f) : iSup f = ⊤ := + csSup_eq_top_of_top_mem hs + +variable [WellFoundedLT α] + +theorem ciInf_mem [Nonempty ι] (f : ι → α) : iInf f ∈ range f := + csInf_mem (range_nonempty f) + +end ConditionallyCompleteLinearOrder + +/-! +### Lemmas about a conditionally complete linear order with bottom element + +In this case we have `Sup ∅ = ⊥`, so we can drop some `Nonempty`/`Set.Nonempty` assumptions. +-/ + + +section ConditionallyCompleteLinearOrderBot + +variable [ConditionallyCompleteLinearOrderBot α] {s : Set α} {f : ι → α} {a : α} + +@[simp] +theorem ciSup_of_empty [IsEmpty ι] (f : ι → α) : ⨆ i, f i = ⊥ := by + rw [iSup_of_empty', csSup_empty] + +theorem ciSup_false (f : False → α) : ⨆ i, f i = ⊥ := + ciSup_of_empty f + +theorem le_ciSup_iff' {s : ι → α} {a : α} (h : BddAbove (range s)) : + a ≤ iSup s ↔ ∀ b, (∀ i, s i ≤ b) → a ≤ b := by simp [iSup, h, le_csSup_iff', upperBounds] + +theorem le_ciInf_iff' [Nonempty ι] {f : ι → α} {a : α} : a ≤ iInf f ↔ ∀ i, a ≤ f i := + le_ciInf_iff (OrderBot.bddBelow _) + +theorem ciInf_le' (f : ι → α) (i : ι) : iInf f ≤ f i := ciInf_le (OrderBot.bddBelow _) _ + +lemma ciInf_le_of_le' (c : ι) : f c ≤ a → iInf f ≤ a := ciInf_le_of_le (OrderBot.bddBelow _) _ + +/-- In conditionally complete orders with a bottom element, the nonempty condition can be omitted +from `ciSup_le_iff`. -/ +theorem ciSup_le_iff' {f : ι → α} (h : BddAbove (range f)) {a : α} : + ⨆ i, f i ≤ a ↔ ∀ i, f i ≤ a := + (csSup_le_iff' h).trans forall_mem_range + +theorem ciSup_le' {f : ι → α} {a : α} (h : ∀ i, f i ≤ a) : ⨆ i, f i ≤ a := + csSup_le' <| forall_mem_range.2 h + +/-- In conditionally complete orders with a bottom element, the nonempty condition can be omitted +from `lt_ciSup_iff`. -/ +theorem lt_ciSup_iff' {f : ι → α} (h : BddAbove (range f)) : a < iSup f ↔ ∃ i, a < f i := by + simpa only [not_le, not_forall] using (ciSup_le_iff' h).not + +theorem exists_lt_of_lt_ciSup' {f : ι → α} {a : α} (h : a < ⨆ i, f i) : ∃ i, a < f i := by + contrapose! h + exact ciSup_le' h + +theorem ciSup_mono' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove (range g)) + (h : ∀ i, ∃ i', f i ≤ g i') : iSup f ≤ iSup g := + ciSup_le' fun i => Exists.elim (h i) (le_ciSup_of_le hg) + +lemma ciSup_or' (p q : Prop) (f : p ∨ q → α) : + ⨆ (h : p ∨ q), f h = (⨆ h : p, f (.inl h)) ⊔ ⨆ h : q, f (.inr h) := by + by_cases hp : p <;> + by_cases hq : q <;> + simp [hp, hq] + +end ConditionallyCompleteLinearOrderBot + +namespace GaloisConnection + +variable [ConditionallyCompleteLattice α] [ConditionallyCompleteLattice β] [Nonempty ι] {l : α → β} + {u : β → α} + +theorem l_csSup (gc : GaloisConnection l u) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : + l (sSup s) = ⨆ x : s, l x := + Eq.symm <| IsLUB.ciSup_set_eq (gc.isLUB_l_image <| isLUB_csSup hne hbdd) hne + +theorem l_csSup' (gc : GaloisConnection l u) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : + l (sSup s) = sSup (l '' s) := by rw [gc.l_csSup hne hbdd, sSup_image'] + +theorem l_ciSup (gc : GaloisConnection l u) {f : ι → α} (hf : BddAbove (range f)) : + l (⨆ i, f i) = ⨆ i, l (f i) := by rw [iSup, gc.l_csSup (range_nonempty _) hf, iSup_range'] + +theorem l_ciSup_set (gc : GaloisConnection l u) {s : Set γ} {f : γ → α} (hf : BddAbove (f '' s)) + (hne : s.Nonempty) : l (⨆ i : s, f i) = ⨆ i : s, l (f i) := by + haveI := hne.to_subtype + rw [image_eq_range] at hf + exact gc.l_ciSup hf + +theorem u_csInf (gc : GaloisConnection l u) {s : Set β} (hne : s.Nonempty) (hbdd : BddBelow s) : + u (sInf s) = ⨅ x : s, u x := + gc.dual.l_csSup hne hbdd + +theorem u_csInf' (gc : GaloisConnection l u) {s : Set β} (hne : s.Nonempty) (hbdd : BddBelow s) : + u (sInf s) = sInf (u '' s) := + gc.dual.l_csSup' hne hbdd + +theorem u_ciInf (gc : GaloisConnection l u) {f : ι → β} (hf : BddBelow (range f)) : + u (⨅ i, f i) = ⨅ i, u (f i) := + gc.dual.l_ciSup hf + +theorem u_ciInf_set (gc : GaloisConnection l u) {s : Set γ} {f : γ → β} (hf : BddBelow (f '' s)) + (hne : s.Nonempty) : u (⨅ i : s, f i) = ⨅ i : s, u (f i) := + gc.dual.l_ciSup_set hf hne + +end GaloisConnection + +namespace OrderIso + +variable [ConditionallyCompleteLattice α] [ConditionallyCompleteLattice β] [Nonempty ι] + +theorem map_csSup (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : + e (sSup s) = ⨆ x : s, e x := + e.to_galoisConnection.l_csSup hne hbdd + +theorem map_csSup' (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddAbove s) : + e (sSup s) = sSup (e '' s) := + e.to_galoisConnection.l_csSup' hne hbdd + +theorem map_ciSup (e : α ≃o β) {f : ι → α} (hf : BddAbove (range f)) : + e (⨆ i, f i) = ⨆ i, e (f i) := + e.to_galoisConnection.l_ciSup hf + +theorem map_ciSup_set (e : α ≃o β) {s : Set γ} {f : γ → α} (hf : BddAbove (f '' s)) + (hne : s.Nonempty) : e (⨆ i : s, f i) = ⨆ i : s, e (f i) := + e.to_galoisConnection.l_ciSup_set hf hne + +theorem map_csInf (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddBelow s) : + e (sInf s) = ⨅ x : s, e x := + e.dual.map_csSup hne hbdd + +theorem map_csInf' (e : α ≃o β) {s : Set α} (hne : s.Nonempty) (hbdd : BddBelow s) : + e (sInf s) = sInf (e '' s) := + e.dual.map_csSup' hne hbdd + +theorem map_ciInf (e : α ≃o β) {f : ι → α} (hf : BddBelow (range f)) : + e (⨅ i, f i) = ⨅ i, e (f i) := + e.dual.map_ciSup hf + +theorem map_ciInf_set (e : α ≃o β) {s : Set γ} {f : γ → α} (hf : BddBelow (f '' s)) + (hne : s.Nonempty) : e (⨅ i : s, f i) = ⨅ i : s, e (f i) := + e.dual.map_ciSup_set hf hne + +end OrderIso + +section WithTopBot + +namespace WithTop +variable [ConditionallyCompleteLinearOrderBot α] {f : ι → α} + +lemma iSup_coe_eq_top : ⨆ x, (f x : WithTop α) = ⊤ ↔ ¬BddAbove (range f) := by + rw [iSup_eq_top, not_bddAbove_iff] + refine ⟨fun hf r => ?_, fun hf a ha => ?_⟩ + · rcases hf r (WithTop.coe_lt_top r) with ⟨i, hi⟩ + exact ⟨f i, ⟨i, rfl⟩, WithTop.coe_lt_coe.mp hi⟩ + · rcases hf (a.untop ha.ne) with ⟨-, ⟨i, rfl⟩, hi⟩ + exact ⟨i, by simpa only [WithTop.coe_untop _ ha.ne] using WithTop.coe_lt_coe.mpr hi⟩ + +lemma iSup_coe_lt_top : ⨆ x, (f x : WithTop α) < ⊤ ↔ BddAbove (range f) := + lt_top_iff_ne_top.trans iSup_coe_eq_top.not_left + +lemma iInf_coe_eq_top : ⨅ x, (f x : WithTop α) = ⊤ ↔ IsEmpty ι := by simp [isEmpty_iff] + +lemma iInf_coe_lt_top : ⨅ i, (f i : WithTop α) < ⊤ ↔ Nonempty ι := by + rw [lt_top_iff_ne_top, Ne, iInf_coe_eq_top, not_isEmpty_iff] + +end WithTop + +end WithTopBot diff --git a/Mathlib/Order/CountableDenseLinearOrder.lean b/Mathlib/Order/CountableDenseLinearOrder.lean index 1ab3a1faebbc2..52b1a34e4be76 100644 --- a/Mathlib/Order/CountableDenseLinearOrder.lean +++ b/Mathlib/Order/CountableDenseLinearOrder.lean @@ -82,16 +82,16 @@ lemma exists_orderEmbedding_insert [DenselyOrdered β] [NoMinOrder β] [NoMaxOrd then if hyS : y ∈ S then simpa only [hxS, hyS, ↓reduceDIte, OrderEmbedding.lt_iff_lt, Subtype.mk_lt_mk] else - obtain rfl := Finset.eq_of_not_mem_of_mem_insert hy hyS + obtain rfl := Finset.eq_of_mem_insert_of_not_mem hy hyS simp only [hxS, hyS, ↓reduceDIte] exact hb _ (Finset.mem_image_of_mem _ (Finset.mem_filter.2 ⟨Finset.mem_attach _ _, hxy⟩)) else - obtain rfl := Finset.eq_of_not_mem_of_mem_insert hx hxS + obtain rfl := Finset.eq_of_mem_insert_of_not_mem hx hxS if hyS : y ∈ S then simp only [hxS, hyS, ↓reduceDIte] exact hb' _ (Finset.mem_image_of_mem _ (Finset.mem_filter.2 ⟨Finset.mem_attach _ _, hxy⟩)) - else simp only [Finset.eq_of_not_mem_of_mem_insert hy hyS, lt_self_iff_false] at hxy + else simp only [Finset.eq_of_mem_insert_of_not_mem hy hyS, lt_self_iff_false] at hxy · ext x simp only [Finset.coe_sort_coe, OrderEmbedding.coe_ofStrictMono, Finset.insert_val, Function.comp_apply, Finset.coe_mem, ↓reduceDIte, Subtype.coe_eta] diff --git a/Mathlib/Order/Cover.lean b/Mathlib/Order/Cover.lean index 17ba059d015c4..cf13cbab95f7f 100644 --- a/Mathlib/Order/Cover.lean +++ b/Mathlib/Order/Cover.lean @@ -591,3 +591,19 @@ variable [Preorder α] {a b : α} simp only [wcovBy_iff_Ioo_eq, ← image_coe_Iio, bot_le, image_eq_empty, true_and, Iio_eq_empty_iff] end WithBot + +section WellFounded + +variable [Preorder α] + +lemma exists_covBy_of_wellFoundedLT [wf : WellFoundedLT α] ⦃a : α⦄ (h : ¬ IsMax a) : + ∃ a', a ⋖ a' := by + rw [not_isMax_iff] at h + exact ⟨_, wellFounded_lt.min_mem _ h, fun a' ↦ wf.wf.not_lt_min _ h⟩ + +lemma exists_covBy_of_wellFoundedGT [wf : WellFoundedGT α] ⦃a : α⦄ (h : ¬ IsMin a) : + ∃ a', a' ⋖ a := by + rw [not_isMin_iff] at h + exact ⟨_, wf.wf.min_mem _ h, fun a' h₁ h₂ ↦ wf.wf.not_lt_min _ h h₂ h₁⟩ + +end WellFounded diff --git a/Mathlib/Order/Defs.lean b/Mathlib/Order/Defs.lean index 1bdaefb9a2491..339a1a55bc927 100644 --- a/Mathlib/Order/Defs.lean +++ b/Mathlib/Order/Defs.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ import Batteries.Classes.Order +import Batteries.Tactic.Trans import Mathlib.Data.Ordering.Basic import Mathlib.Tactic.Lemma -import Mathlib.Tactic.Relation.Trans import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.TypeStar @@ -125,6 +125,38 @@ instance (priority := 90) isAsymm_of_isTrans_of_isIrrefl [IsTrans α r] [IsIrref IsAsymm α r := ⟨fun a _b h₁ h₂ => absurd (_root_.trans h₁ h₂) (irrefl a)⟩ +instance IsIrrefl.decide [DecidableRel r] [IsIrrefl α r] : + IsIrrefl α (fun a b => decide (r a b) = true) where + irrefl := fun a => by simpa using irrefl a + +instance IsRefl.decide [DecidableRel r] [IsRefl α r] : + IsRefl α (fun a b => decide (r a b) = true) where + refl := fun a => by simpa using refl a + +instance IsTrans.decide [DecidableRel r] [IsTrans α r] : + IsTrans α (fun a b => decide (r a b) = true) where + trans := fun a b c => by simpa using trans a b c + +instance IsSymm.decide [DecidableRel r] [IsSymm α r] : + IsSymm α (fun a b => decide (r a b) = true) where + symm := fun a b => by simpa using symm a b + +instance IsAntisymm.decide [DecidableRel r] [IsAntisymm α r] : + IsAntisymm α (fun a b => decide (r a b) = true) where + antisymm := fun a b h₁ h₂ => antisymm _ _ (by simpa using h₁) (by simpa using h₂) + +instance IsAsymm.decide [DecidableRel r] [IsAsymm α r] : + IsAsymm α (fun a b => decide (r a b) = true) where + asymm := fun a b => by simpa using asymm a b + +instance IsTotal.decide [DecidableRel r] [IsTotal α r] : + IsTotal α (fun a b => decide (r a b) = true) where + total := fun a b => by simpa using total a b + +instance IsTrichotomous.decide [DecidableRel r] [IsTrichotomous α r] : + IsTrichotomous α (fun a b => decide (r a b) = true) where + trichotomous := fun a b => by simpa using trichotomous a b + variable (r) @[elab_without_expected_type] lemma irrefl_of [IsIrrefl α r] (a : α) : ¬a ≺ a := irrefl a @@ -184,6 +216,32 @@ end end +/-! ### Minimal and maximal -/ + +section LE + +variable {α : Type*} [LE α] {P : α → Prop} {x y : α} + +/-- `Minimal P x` means that `x` is a minimal element satisfying `P`. -/ +def Minimal (P : α → Prop) (x : α) : Prop := P x ∧ ∀ ⦃y⦄, P y → y ≤ x → x ≤ y + +/-- `Maximal P x` means that `x` is a maximal element satisfying `P`. -/ +def Maximal (P : α → Prop) (x : α) : Prop := P x ∧ ∀ ⦃y⦄, P y → x ≤ y → y ≤ x + +lemma Minimal.prop (h : Minimal P x) : P x := + h.1 + +lemma Maximal.prop (h : Maximal P x) : P x := + h.1 + +lemma Minimal.le_of_le (h : Minimal P x) (hy : P y) (hle : y ≤ x) : x ≤ y := + h.2 hy hle + +lemma Maximal.le_of_ge (h : Maximal P x) (hy : P y) (hge : x ≤ y) : y ≤ x := + h.2 hy hge + +end LE + /-! ### Bundled classes -/ variable {α : Type*} @@ -357,7 +415,7 @@ macro "compareOfLessAndEq_rfl" : tactic => /-- A linear order is reflexive, transitive, antisymmetric and total relation `≤`. We assume that every linear ordered type has decidable `(≤)`, `(<)`, and `(=)`. -/ -class LinearOrder (α : Type*) extends PartialOrder α, Min α, Max α, Ord α := +class LinearOrder (α : Type*) extends PartialOrder α, Min α, Max α, Ord α where /-- A linear order is total. -/ le_total (a b : α) : a ≤ b ∨ b ≤ a /-- In a linearly ordered type, we assume the order relations are all decidable. -/ @@ -595,7 +653,17 @@ lemma compare_iff (a b : α) {o : Ordering} : compare a b = o ↔ o.Compares a b · exact compare_eq_iff_eq · exact compare_gt_iff_gt -instance : Batteries.TransCmp (compare (α := α)) where +theorem cmp_eq_compare (a b : α) : cmp a b = compare a b := by + refine ((compare_iff ..).2 ?_).symm + unfold cmp cmpUsing; split_ifs with h1 h2 + · exact h1 + · exact h2 + · exact le_antisymm (not_lt.1 h2) (not_lt.1 h1) + +theorem cmp_eq_compareOfLessAndEq (a b : α) : cmp a b = compareOfLessAndEq a b := + (cmp_eq_compare ..).trans (LinearOrder.compare_eq_compareOfLessAndEq ..) + +instance : Batteries.LawfulCmp (compare (α := α)) where symm a b := by cases h : compare a b <;> simp only [Ordering.swap] <;> symm @@ -604,6 +672,9 @@ instance : Batteries.TransCmp (compare (α := α)) where · exact compare_lt_iff_lt.2 <| compare_gt_iff_gt.1 h le_trans := fun h₁ h₂ ↦ compare_le_iff_le.2 <| le_trans (compare_le_iff_le.1 h₁) (compare_le_iff_le.1 h₂) + cmp_iff_beq := by simp [compare_eq_iff_eq] + cmp_iff_lt := by simp [compare_lt_iff_lt] + cmp_iff_le := by simp [compare_le_iff_le] end Ord diff --git a/Mathlib/Order/Directed.lean b/Mathlib/Order/Directed.lean index 29285fca18124..b2eab1b12898c 100644 --- a/Mathlib/Order/Directed.lean +++ b/Mathlib/Order/Directed.lean @@ -58,11 +58,7 @@ alias ⟨DirectedOn.directed_val, _⟩ := directedOn_iff_directed theorem directedOn_range {f : ι → α} : Directed r f ↔ DirectedOn r (Set.range f) := by simp_rw [Directed, DirectedOn, Set.forall_mem_range, Set.exists_range_iff] --- Porting note: This alias was misplaced in `order/compactly_generated.lean` in mathlib3 -alias ⟨Directed.directedOn_range, _⟩ := directedOn_range - --- Porting note: `attribute [protected]` doesn't work --- attribute [protected] Directed.directedOn_range +protected alias ⟨Directed.directedOn_range, _⟩ := directedOn_range theorem directedOn_image {s : Set β} {f : β → α} : DirectedOn r (f '' s) ↔ DirectedOn (f ⁻¹'o r) s := by diff --git a/Mathlib/Order/Disjoint.lean b/Mathlib/Order/Disjoint.lean index 98aa260c7eaa2..b49a00f24c125 100644 --- a/Mathlib/Order/Disjoint.lean +++ b/Mathlib/Order/Disjoint.lean @@ -155,6 +155,10 @@ theorem Disjoint.of_disjoint_inf_of_le' (h : Disjoint (a ⊓ b) c) (hle : b ≤ end SemilatticeInfBot +theorem Disjoint.right_lt_sup_of_left_ne_bot [SemilatticeSup α] [OrderBot α] {a b : α} + (h : Disjoint a b) (ha : a ≠ ⊥) : b < a ⊔ b := + le_sup_right.lt_of_ne fun eq ↦ ha (le_bot_iff.mp <| h le_rfl <| sup_eq_right.mp eq.symm) + section DistribLatticeBot variable [DistribLattice α] [OrderBot α] {a b c : α} @@ -582,6 +586,10 @@ class ComplementedLattice (α) [Lattice α] [BoundedOrder α] : Prop where /-- In a `ComplementedLattice`, every element admits a complement. -/ exists_isCompl : ∀ a : α, ∃ b : α, IsCompl a b +lemma complementedLattice_iff (α) [Lattice α] [BoundedOrder α] : + ComplementedLattice α ↔ ∀ a : α, ∃ b : α, IsCompl a b := + ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + export ComplementedLattice (exists_isCompl) instance Subsingleton.instComplementedLattice diff --git a/Mathlib/Order/Extension/Well.lean b/Mathlib/Order/Extension/Well.lean index 6c7088100dd59..1b5175e593d0c 100644 --- a/Mathlib/Order/Extension/Well.lean +++ b/Mathlib/Order/Extension/Well.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Junyan Xu -/ import Mathlib.Data.Prod.Lex -import Mathlib.SetTheory.Ordinal.Arithmetic +import Mathlib.SetTheory.Ordinal.Rank /-! # Extend a well-founded order to a well-order @@ -16,7 +16,7 @@ well-founded order. We can map our order into two well-orders: * the first map respects the order but isn't necessarily injective. Namely, this is the *rank* - function `WellFounded.rank : α → Ordinal`. + function `IsWellFounded.rank : α → Ordinal`. * the second map is injective but doesn't necessarily respect the order. This is an arbitrary embedding into `Cardinal` given by `embeddingToCardinal`. @@ -38,8 +38,40 @@ universe u variable {α : Type u} {r : α → α → Prop} +namespace IsWellFounded + +variable {α : Type u} (r : α → α → Prop) [IsWellFounded α r] + +/-- An arbitrary well order on `α` that extends `r`. + +The construction maps `r` into two well-orders: the first map is `IsWellFounded.rank`, which is not +necessarily injective but respects the order `r`; the other map is the identity (with an arbitrarily +chosen well-order on `α`), which is injective but doesn't respect `r`. + +By taking the lexicographic product of the two, we get both properties, so we can pull it back and +get a well-order that extend our original order `r`. Another way to view this is that we choose an +arbitrary well-order to serve as a tiebreak between two elements of same rank. +-/ +noncomputable def wellOrderExtension : LinearOrder α := + @LinearOrder.lift' α (Ordinal ×ₗ Cardinal) _ (fun a : α => (rank r a, embeddingToCardinal a)) + fun _ _ h => embeddingToCardinal.injective <| congr_arg Prod.snd h + +instance wellOrderExtension.isWellFounded_lt : IsWellFounded α (wellOrderExtension r).lt := + ⟨InvImage.wf (fun a : α => (rank r a, embeddingToCardinal a)) <| + Ordinal.lt_wf.prod_lex Cardinal.lt_wf⟩ + +instance wellOrderExtension.isWellOrder_lt : IsWellOrder α (wellOrderExtension r).lt where + +/-- Any well-founded relation can be extended to a well-ordering on that type. -/ +theorem exists_well_order_ge : ∃ s, r ≤ s ∧ IsWellOrder α s := + ⟨(wellOrderExtension r).lt, fun _ _ h => Prod.Lex.left _ _ (rank_lt_of_rel h), ⟨⟩⟩ + +end IsWellFounded + namespace WellFounded +set_option linter.deprecated false + variable (hwf : WellFounded r) /-- An arbitrary well order on `α` that extends `r`. @@ -52,16 +84,19 @@ By taking the lexicographic product of the two, we get both properties, so we ca get a well-order that extend our original order `r`. Another way to view this is that we choose an arbitrary well-order to serve as a tiebreak between two elements of same rank. -/ +@[deprecated IsWellFounded.wellOrderExtension (since := "2024-09-07")] noncomputable def wellOrderExtension : LinearOrder α := @LinearOrder.lift' α (Ordinal ×ₗ Cardinal) _ (fun a : α => (hwf.rank a, embeddingToCardinal a)) fun _ _ h => embeddingToCardinal.injective <| congr_arg Prod.snd h +@[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 /-- 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 := ⟨hwf.wellOrderExtension.lt, fun _ _ h => Prod.Lex.left _ _ (hwf.rank_lt_of_rel h), ⟨⟩⟩ @@ -76,13 +111,13 @@ instance [Inhabited α] : Inhabited (WellOrderExtension α) := ‹_› def toWellOrderExtension : α ≃ WellOrderExtension α := Equiv.refl _ -noncomputable instance [LT α] [WellFoundedLT α] : LinearOrder (WellOrderExtension α) := - (IsWellFounded.wf : @WellFounded α (· < ·)).wellOrderExtension +noncomputable instance [LT α] [h : WellFoundedLT α] : LinearOrder (WellOrderExtension α) := + h.wellOrderExtension instance WellOrderExtension.wellFoundedLT [LT α] [WellFoundedLT α] : WellFoundedLT (WellOrderExtension α) := - WellFounded.wellOrderExtension.isWellFounded_lt _ + IsWellFounded.wellOrderExtension.isWellFounded_lt (α := α) (· < ·) theorem toWellOrderExtension_strictMono [Preorder α] [WellFoundedLT α] : StrictMono (toWellOrderExtension : α → WellOrderExtension α) := fun _ _ h => - Prod.Lex.left _ _ <| WellFounded.rank_lt_of_rel _ h + Prod.Lex.left _ _ <| IsWellFounded.rank_lt_of_rel h diff --git a/Mathlib/Order/Filter/AtTopBot.lean b/Mathlib/Order/Filter/AtTopBot.lean index 3c655dfe83a3b..fc058972b73f4 100644 --- a/Mathlib/Order/Filter/AtTopBot.lean +++ b/Mathlib/Order/Filter/AtTopBot.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jeremy Avigad, Yury Kudryashov, Patrick Massot -/ import Mathlib.Data.Finset.Preimage -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Order.Filter.Bases +import Mathlib.Order.Filter.Prod import Mathlib.Order.Interval.Set.Disjoint +import Mathlib.Order.Interval.Set.OrderIso /-! # `Filter.atTop` and `Filter.atBot` filters on preorders, monoids and groups. @@ -976,12 +978,12 @@ theorem tendsto_comp_val_Iic_atBot [Preorder α] [IsDirected α (· ≥ ·)] tendsto_comp_val_Ici_atTop (α := αᵒᵈ) theorem map_add_atTop_eq_nat (k : ℕ) : map (fun a => a + k) atTop = atTop := - map_atTop_eq_of_gc (· - k) k (fun a b h => Nat.add_le_add_right h k) - (fun a b h => (Nat.le_sub_iff_add_le h).symm) fun a h => by rw [Nat.sub_add_cancel h] + map_atTop_eq_of_gc (· - k) k (fun _ _ h => Nat.add_le_add_right h k) + (fun _ _ h => (Nat.le_sub_iff_add_le h).symm) fun a h => by rw [Nat.sub_add_cancel h] theorem map_sub_atTop_eq_nat (k : ℕ) : map (fun a => a - k) atTop = atTop := - map_atTop_eq_of_gc (· + k) 0 (fun a b h => Nat.sub_le_sub_right h _) - (fun a b _ => Nat.sub_le_iff_le_add) fun b _ => by rw [Nat.add_sub_cancel_right] + map_atTop_eq_of_gc (· + k) 0 (fun _ _ h => Nat.sub_le_sub_right h _) + (fun _ _ _ => Nat.sub_le_iff_le_add) fun b _ => by rw [Nat.add_sub_cancel_right] theorem tendsto_add_atTop_nat (k : ℕ) : Tendsto (fun a => a + k) atTop atTop := le_of_eq (map_add_atTop_eq_nat k) @@ -995,7 +997,7 @@ theorem tendsto_add_atTop_iff_nat {f : ℕ → α} {l : Filter α} (k : ℕ) : rw [← tendsto_map'_iff, map_add_atTop_eq_nat] theorem map_div_atTop_eq_nat (k : ℕ) (hk : 0 < k) : map (fun a => a / k) atTop = atTop := - map_atTop_eq_of_gc (fun b => k * b + (k - 1)) 1 (fun a b h => Nat.div_le_div_right h) + map_atTop_eq_of_gc (fun b => k * b + (k - 1)) 1 (fun _ _ h => Nat.div_le_div_right h) -- Porting note: there was a parse error in `calc`, use `simp` instead (fun a b _ => by rw [Nat.div_le_iff_le_mul_add_pred hk]) fun b _ => by rw [Nat.mul_add_div hk, Nat.div_eq_of_lt, add_zero]; omega diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean index d6a8a22e8a8d6..ffd5fe2a6c9e4 100644 --- a/Mathlib/Order/Filter/Bases.lean +++ b/Mathlib/Order/Filter/Bases.lean @@ -5,8 +5,7 @@ Authors: Yury Kudryashov, Johannes Hölzl, Mario Carneiro, Patrick Massot -/ import Mathlib.Data.Prod.PProd import Mathlib.Data.Set.Countable -import Mathlib.Order.Filter.Prod -import Mathlib.Order.Filter.Ker +import Mathlib.Order.Filter.Basic /-! # Filter bases @@ -632,10 +631,6 @@ alias ⟨_, _root_.Disjoint.filter_principal⟩ := disjoint_principal_principal theorem disjoint_pure_pure {x y : α} : Disjoint (pure x : Filter α) (pure y) ↔ x ≠ y := by simp only [← principal_singleton, disjoint_principal_principal, disjoint_singleton] -@[simp] -theorem compl_diagonal_mem_prod {l₁ l₂ : Filter α} : (diagonal α)ᶜ ∈ l₁ ×ˢ l₂ ↔ Disjoint l₁ l₂ := by - simp only [mem_prod_iff, Filter.disjoint_iff, prod_subset_compl_diagonal_iff_disjoint] - -- Porting note: use `∃ i, p i ∧ _` instead of `∃ i (hi : p i), _`. theorem HasBasis.disjoint_iff_left (h : l.HasBasis p s) : Disjoint l l' ↔ ∃ i, p i ∧ (s i)ᶜ ∈ l' := by @@ -722,7 +717,7 @@ protected theorem HasBasis.biInter_mem {f : Set α → Set β} (h : HasBasis l p h.biInf_mem hf protected theorem HasBasis.ker (h : HasBasis l p s) : l.ker = ⋂ (i) (_ : p i), s i := - l.ker_def.trans <| h.biInter_mem monotone_id + sInter_eq_biInter.trans <| h.biInter_mem monotone_id variable {ι'' : Type*} [Preorder ι''] (l) (s'' : ι'' → Set α) diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index d73d46a740880..3587c2a0fa469 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -4,24 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jeremy Avigad -/ import Mathlib.Data.Set.Finite +import Mathlib.Order.Filter.Defs /-! # Theory of filters on sets -## Main definitions - -* `Filter` : filters on a set; -* `Filter.principal` : filter of all sets containing a given set; -* `Filter.map`, `Filter.comap` : operations on filters; -* `Filter.Tendsto` : limit with respect to filters; -* `Filter.Eventually` : `f.eventually p` means `{x | p x} ∈ f`; -* `Filter.Frequently` : `f.frequently p` means `{x | ¬p x} ∉ f`; -* `filter_upwards [h₁, ..., hₙ]` : - a tactic that takes a list of proofs `hᵢ : sᵢ ∈ f`, - and replaces a goal `s ∈ f` with `∀ x, x ∈ s₁ → ... → x ∈ sₙ → x ∈ s`; -* `Filter.NeBot f` : a utility class stating that `f` is a non-trivial filter. - -Filters on a type `X` are sets of sets of `X` satisfying three conditions. They are mostly used to +A *filter* on a type `α` is a collection of sets of `α` which contains the whole `α`, +is upwards-closed, and is stable under intersection. They are mostly used to abstract two related kinds of ideas: * *limits*, including finite or infinite limits of sequences, finite or infinite limits of functions at a point or at infinity, etc... @@ -30,8 +19,10 @@ abstract two related kinds of ideas: sense of measure theory. Dually, filters can also express the idea of *things happening often*: for arbitrarily large `n`, or at a point in any neighborhood of given a point etc... -In this file, we define the type `Filter X` of filters on `X`, and endow it with a complete lattice -structure. This structure is lifted from the lattice structure on `Set (Set X)` using the Galois +## Main definitions + +In this file, we endow `Filter α` it with a complete lattice structure. +This structure is lifted from the lattice structure on `Set (Set X)` using the Galois insertion which maps a filter to its elements in one direction, and an arbitrary set of sets to the smallest filter containing it in the other direction. We also prove `Filter` is a monadic functor, with a push-forward operation @@ -46,17 +37,9 @@ The examples of filters appearing in the description of the two motivating ideas * `MeasureTheory.ae` : made of sets whose complement has zero measure with respect to `μ` (defined in `Mathlib/MeasureTheory/OuterMeasure/AE`) -The general notion of limit of a map with respect to filters on the source and target types -is `Filter.Tendsto`. It is defined in terms of the order and the push-forward operation. The predicate "happening eventually" is `Filter.Eventually`, and "happening often" is `Filter.Frequently`, whose definitions are immediate after `Filter` is defined (but they come rather late in this file in order to immediately relate them to the lattice structure). - -For instance, anticipating on Topology.Basic, the statement: "if a sequence `u` converges to -some `x` and `u n` belongs to a set `M` for `n` large enough then `x` is in the closure of -`M`" is formalized as: `Tendsto u atTop (𝓝 x) → (∀ᶠ n in atTop, u n ∈ M) → x ∈ closure M`, -which is a special case of `mem_closure_of_tendsto` from Topology.Basic. - ## Notations * `∀ᶠ x in f, p x` : `f.Eventually p`; @@ -82,69 +65,30 @@ open scoped symmDiff universe u v w x y -/-- A filter `F` on a type `α` is a collection of sets of `α` which contains the whole `α`, -is upwards-closed, and is stable under intersection. We do not forbid this collection to be -all sets of `α`. -/ -structure Filter (α : Type*) where - /-- The set of sets that belong to the filter. -/ - sets : Set (Set α) - /-- The set `Set.univ` belongs to any filter. -/ - univ_sets : Set.univ ∈ sets - /-- If a set belongs to a filter, then its superset belongs to the filter as well. -/ - sets_of_superset {x y} : x ∈ sets → x ⊆ y → y ∈ sets - /-- If two sets belong to a filter, then their intersection belongs to the filter as well. -/ - inter_sets {x y} : x ∈ sets → y ∈ sets → x ∩ y ∈ sets - -/-- If `F` is a filter on `α`, and `U` a subset of `α` then we can write `U ∈ F` as on paper. -/ -instance {α : Type*} : Membership (Set α) (Filter α) := - ⟨fun F U => U ∈ F.sets⟩ - namespace Filter variable {α : Type u} {f g : Filter α} {s t : Set α} -@[simp] -protected theorem mem_mk {t : Set (Set α)} {h₁ h₂ h₃} : s ∈ mk t h₁ h₂ h₃ ↔ s ∈ t := - Iff.rfl - -@[simp] -protected theorem mem_sets : s ∈ f.sets ↔ s ∈ f := - Iff.rfl - instance inhabitedMem : Inhabited { s : Set α // s ∈ f } := ⟨⟨univ, f.univ_sets⟩⟩ -theorem filter_eq : ∀ {f g : Filter α}, f.sets = g.sets → f = g - | ⟨_, _, _, _⟩, ⟨_, _, _, _⟩, rfl => rfl - theorem filter_eq_iff : f = g ↔ f.sets = g.sets := ⟨congr_arg _, filter_eq⟩ -@[ext] -protected theorem ext (h : ∀ s, s ∈ f ↔ s ∈ g) : f = g := by - simpa [filter_eq_iff, Set.ext_iff, Filter.mem_sets] +@[simp] theorem sets_subset_sets : f.sets ⊆ g.sets ↔ g ≤ f := .rfl +@[simp] theorem sets_ssubset_sets : f.sets ⊂ g.sets ↔ g < f := .rfl /-- An extensionality lemma that is useful for filters with good lemmas about `sᶜ ∈ f` (e.g., `Filter.comap`, `Filter.coprod`, `Filter.Coprod`, `Filter.cofinite`). -/ protected theorem coext (h : ∀ s, sᶜ ∈ f ↔ sᶜ ∈ g) : f = g := Filter.ext <| compl_surjective.forall.2 h -@[simp] -theorem univ_mem : univ ∈ f := - f.univ_sets - -theorem mem_of_superset {x y : Set α} (hx : x ∈ f) (hxy : x ⊆ y) : y ∈ f := - f.sets_of_superset hx hxy - instance : Trans (· ⊇ ·) ((· ∈ ·) : Set α → Filter α → Prop) (· ∈ ·) where trans h₁ h₂ := mem_of_superset h₂ h₁ instance : Trans Membership.mem (· ⊆ ·) (Membership.mem : Filter α → Set α → Prop) where trans h₁ h₂ := mem_of_superset h₁ h₂ -theorem inter_mem {s t : Set α} (hs : s ∈ f) (ht : t ∈ f) : s ∩ t ∈ f := - f.inter_sets hs ht - @[simp] theorem inter_mem_iff {s t : Set α} : s ∩ t ∈ f ↔ s ∈ f ∧ t ∈ f := ⟨fun h => ⟨mem_of_superset h inter_subset_left, mem_of_superset h inter_subset_right⟩, @@ -153,27 +97,12 @@ theorem inter_mem_iff {s t : Set α} : s ∩ t ∈ f ↔ s ∈ f ∧ t ∈ f := theorem diff_mem {s t : Set α} (hs : s ∈ f) (ht : tᶜ ∈ f) : s \ t ∈ f := inter_mem hs ht -theorem univ_mem' (h : ∀ a, a ∈ s) : s ∈ f := - mem_of_superset univ_mem fun x _ => h x - -theorem mp_mem (hs : s ∈ f) (h : { x | x ∈ s → x ∈ t } ∈ f) : t ∈ f := - mem_of_superset (inter_mem hs h) fun _ ⟨h₁, h₂⟩ => h₂ h₁ - theorem congr_sets (h : { x | x ∈ s ↔ x ∈ t } ∈ f) : s ∈ f ↔ t ∈ f := ⟨fun hs => mp_mem hs (mem_of_superset h fun _ => Iff.mp), fun hs => mp_mem hs (mem_of_superset h fun _ => Iff.mpr)⟩ -/-- Override `sets` field of a filter to provide better definitional equality. -/ -protected def copy (f : Filter α) (S : Set (Set α)) (hmem : ∀ s, s ∈ S ↔ s ∈ f) : Filter α where - sets := S - univ_sets := (hmem _).2 univ_mem - sets_of_superset h hsub := (hmem _).2 <| mem_of_superset ((hmem _).1 h) hsub - inter_sets h₁ h₂ := (hmem _).2 <| inter_mem ((hmem _).1 h₁) ((hmem _).1 h₂) - lemma copy_eq {S} (hmem : ∀ s, s ∈ S ↔ s ∈ f) : f.copy S hmem = f := Filter.ext hmem -@[simp] lemma mem_copy {S hmem} : s ∈ f.copy S hmem ↔ s ∈ S := Iff.rfl - @[simp] theorem biInter_mem {β : Type v} {s : β → Set α} {is : Set β} (hf : is.Finite) : (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := @@ -217,100 +146,17 @@ theorem forall_in_swap {β : Type*} {p : Set α → β → Prop} : end Filter -namespace Mathlib.Tactic - -open Lean Meta Elab Tactic - -/-- -`filter_upwards [h₁, ⋯, hₙ]` replaces a goal of the form `s ∈ f` and terms -`h₁ : t₁ ∈ f, ⋯, hₙ : tₙ ∈ f` with `∀ x, x ∈ t₁ → ⋯ → x ∈ tₙ → x ∈ s`. -The list is an optional parameter, `[]` being its default value. - -`filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ` is a short form for -`{ filter_upwards [h₁, ⋯, hₙ], intros a₁ a₂ ⋯ aₖ }`. - -`filter_upwards [h₁, ⋯, hₙ] using e` is a short form for -`{ filter_upwards [h1, ⋯, hn], exact e }`. - -Combining both shortcuts is done by writing `filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ using e`. -Note that in this case, the `aᵢ` terms can be used in `e`. --/ -syntax (name := filterUpwards) "filter_upwards" (" [" term,* "]")? - (" with" (ppSpace colGt term:max)*)? (" using " term)? : tactic - -elab_rules : tactic -| `(tactic| filter_upwards $[[$[$args],*]]? $[with $wth*]? $[using $usingArg]?) => do - let config : ApplyConfig := {newGoals := ApplyNewGoals.nonDependentOnly} - for e in args.getD #[] |>.reverse do - let goal ← getMainGoal - replaceMainGoal <| ← goal.withContext <| runTermElab do - let m ← mkFreshExprMVar none - let lem ← Term.elabTermEnsuringType - (← ``(Filter.mp_mem $e $(← Term.exprToSyntax m))) (← goal.getType) - goal.assign lem - return [m.mvarId!] - liftMetaTactic fun goal => do - goal.apply (← mkConstWithFreshMVarLevels ``Filter.univ_mem') config - evalTactic <|← `(tactic| dsimp (config := {zeta := false}) only [Set.mem_setOf_eq]) - if let some l := wth then - evalTactic <|← `(tactic| intro $[$l]*) - if let some e := usingArg then - evalTactic <|← `(tactic| exact $e) - -end Mathlib.Tactic namespace Filter variable {α : Type u} {β : Type v} {γ : Type w} {δ : Type*} {ι : Sort x} -section Principal - -/-- The principal filter of `s` is the collection of all supersets of `s`. -/ -def principal (s : Set α) : Filter α where - sets := { t | s ⊆ t } - univ_sets := subset_univ s - sets_of_superset hx := Subset.trans hx - inter_sets := subset_inter - -@[inherit_doc] -scoped notation "𝓟" => Filter.principal - -@[simp] theorem mem_principal {s t : Set α} : s ∈ 𝓟 t ↔ t ⊆ s := Iff.rfl - theorem mem_principal_self (s : Set α) : s ∈ 𝓟 s := Subset.rfl -end Principal - -open Filter - -section Join - -/-- The join of a filter of filters is defined by the relation `s ∈ join f ↔ {t | s ∈ t} ∈ f`. -/ -def join (f : Filter (Filter α)) : Filter α where - sets := { s | { t : Filter α | s ∈ t } ∈ f } - univ_sets := by simp only [mem_setOf_eq, univ_sets, ← Filter.mem_sets, setOf_true] - sets_of_superset hx xy := mem_of_superset hx fun f h => mem_of_superset h xy - inter_sets hx hy := mem_of_superset (inter_mem hx hy) fun f ⟨h₁, h₂⟩ => inter_mem h₁ h₂ - -@[simp] -theorem mem_join {s : Set α} {f : Filter (Filter α)} : s ∈ join f ↔ { t | s ∈ t } ∈ f := - Iff.rfl - -end Join - section Lattice variable {f g : Filter α} {s t : Set α} -instance : PartialOrder (Filter α) where - le f g := ∀ ⦃U : Set α⦄, U ∈ g → U ∈ f - le_antisymm a b h₁ h₂ := filter_eq <| Subset.antisymm h₂ h₁ - le_refl a := Subset.rfl - le_trans a b c h₁ h₂ := Subset.trans h₂ h₁ - -theorem le_def : f ≤ g ↔ ∀ x ∈ g, x ∈ f := - Iff.rfl - protected theorem not_le : ¬f ≤ g ↔ ∃ s ∈ g, s ∉ f := by simp_rw [le_def, not_forall, exists_prop] /-- `GenerateSets g s`: `s` is in the filter closure of `g`. -/ @@ -378,23 +224,6 @@ def giGenerate (α : Type*) : choice s hs := Filter.mkOfClosure s (le_antisymm hs <| le_generate_iff.1 <| le_rfl) choice_eq _ _ := mkOfClosure_sets -/-- The infimum of filters is the filter generated by intersections - of elements of the two filters. -/ -instance : Inf (Filter α) := - ⟨fun f g : Filter α => - { sets := { s | ∃ a ∈ f, ∃ b ∈ g, s = a ∩ b } - univ_sets := ⟨_, univ_mem, _, univ_mem, by simp⟩ - sets_of_superset := by - rintro x y ⟨a, ha, b, hb, rfl⟩ xy - refine - ⟨a ∪ y, mem_of_superset ha subset_union_left, b ∪ y, - mem_of_superset hb subset_union_left, ?_⟩ - rw [← inter_union_distrib_right, union_eq_self_of_subset_left xy] - inter_sets := by - rintro x y ⟨a, ha, b, hb, rfl⟩ ⟨c, hc, d, hd, rfl⟩ - refine ⟨a ∩ c, inter_mem ha hc, b ∩ d, inter_mem hb hd, ?_⟩ - ac_rfl }⟩ - theorem mem_inf_iff {f g : Filter α} {s : Set α} : s ∈ f ⊓ g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, s = t₁ ∩ t₂ := Iff.rfl @@ -417,51 +246,27 @@ theorem mem_inf_iff_superset {f g : Filter α} {s : Set α} : ⟨fun ⟨t₁, h₁, t₂, h₂, Eq⟩ => ⟨t₁, h₁, t₂, h₂, Eq ▸ Subset.rfl⟩, fun ⟨_, h₁, _, h₂, sub⟩ => mem_inf_of_inter h₁ h₂ sub⟩ -instance : Top (Filter α) := - ⟨{ sets := { s | ∀ x, x ∈ s } - univ_sets := fun x => mem_univ x - sets_of_superset := fun hx hxy a => hxy (hx a) - inter_sets := fun hx hy _ => mem_inter (hx _) (hy _) }⟩ - -theorem mem_top_iff_forall {s : Set α} : s ∈ (⊤ : Filter α) ↔ ∀ x, x ∈ s := - Iff.rfl - -@[simp] -theorem mem_top {s : Set α} : s ∈ (⊤ : Filter α) ↔ s = univ := by - rw [mem_top_iff_forall, eq_univ_iff_forall] - section CompleteLattice -/- We lift the complete lattice along the Galois connection `generate` / `sets`. Unfortunately, - we want to have different definitional equalities for some lattice operations. So we define them - upfront and change the lattice operations for the complete lattice instance. -/ -instance instCompleteLatticeFilter : CompleteLattice (Filter α) := - { @OrderDual.instCompleteLattice _ (giGenerate α).liftCompleteLattice with - le := (· ≤ ·) - top := ⊤ - le_top := fun _ _s hs => (mem_top.1 hs).symm ▸ univ_mem - inf := (· ⊓ ·) - inf_le_left := fun _ _ _ => mem_inf_of_left - inf_le_right := fun _ _ _ => mem_inf_of_right - le_inf := fun _ _ _ h₁ h₂ _s ⟨_a, ha, _b, hb, hs⟩ => hs.symm ▸ inter_mem (h₁ ha) (h₂ hb) - sSup := join ∘ 𝓟 - le_sSup := fun _ _f hf _s hs => hs hf - sSup_le := fun _ _f hf _s hs _g hg => hf _ hg hs } +/- Complete lattice structure on `Filter α`. -/ +instance instCompleteLatticeFilter : CompleteLattice (Filter α) where + le_sup_left _ _ _ h := h.1 + le_sup_right _ _ _ h := h.2 + sup_le _ _ _ h₁ h₂ _ h := ⟨h₁ h, h₂ h⟩ + inf_le_left _ _ _ := mem_inf_of_left + inf_le_right _ _ _ := mem_inf_of_right + le_inf := fun _ _ _ h₁ h₂ _s ⟨_a, ha, _b, hb, hs⟩ => hs.symm ▸ inter_mem (h₁ ha) (h₂ hb) + le_sSup _ _ h₁ _ h₂ := h₂ h₁ + sSup_le _ _ h₁ _ h₂ _ h₃ := h₁ _ h₃ h₂ + sInf_le _ _ h₁ _ h₂ := by rw [← Filter.sSup_lowerBounds]; exact fun _ h₃ ↦ h₃ h₁ h₂ + le_sInf _ _ h₁ _ h₂ := by rw [← Filter.sSup_lowerBounds] at h₂; exact h₂ h₁ + le_top _ _ := univ_mem' + bot_le _ _ _ := trivial instance : Inhabited (Filter α) := ⟨⊥⟩ end CompleteLattice -/-- A filter is `NeBot` if it is not equal to `⊥`, or equivalently the empty set does not belong to -the filter. Bourbaki include this assumption in the definition of a filter but we prefer to have a -`CompleteLattice` structure on `Filter _`, so we use a typeclass argument in lemmas instead. -/ -class NeBot (f : Filter α) : Prop where - /-- The filter is nontrivial: `f ≠ ⊥` or equivalently, `∅ ∉ f`. -/ - ne' : f ≠ ⊥ - -theorem neBot_iff {f : Filter α} : NeBot f ↔ f ≠ ⊥ := - ⟨fun h => h.1, fun h => ⟨h⟩⟩ - theorem NeBot.ne {f : Filter α} (hf : NeBot f) : f ≠ ⊥ := hf.ne' @[simp] theorem not_neBot {f : Filter α} : ¬f.NeBot ↔ f = ⊥ := neBot_iff.not_left @@ -506,10 +311,6 @@ theorem generate_iUnion {s : ι → Set (Set α)} : Filter.generate (⋃ i, s i) = ⨅ i, Filter.generate (s i) := (giGenerate α).gc.l_iSup -@[simp] -theorem mem_bot {s : Set α} : s ∈ (⊥ : Filter α) := - trivial - @[simp] theorem mem_sup {f g : Filter α} {s : Set α} : s ∈ f ⊔ g ↔ s ∈ f ∧ s ∈ g := Iff.rfl @@ -517,10 +318,6 @@ theorem mem_sup {f g : Filter α} {s : Set α} : s ∈ f ⊔ g ↔ s ∈ f ∧ s theorem union_mem_sup {f g : Filter α} {s t : Set α} (hs : s ∈ f) (ht : t ∈ g) : s ∪ t ∈ f ⊔ g := ⟨mem_of_superset hs subset_union_left, mem_of_superset ht subset_union_right⟩ -@[simp] -theorem mem_sSup {x : Set α} {s : Set (Filter α)} : x ∈ sSup s ↔ ∀ f ∈ s, x ∈ (f : Filter α) := - Iff.rfl - @[simp] theorem mem_iSup {x : Set α} {f : ι → Filter α} : x ∈ iSup f ↔ ∀ i, x ∈ f i := by simp only [← Filter.mem_sets, iSup_sets_eq, mem_iInter] @@ -530,7 +327,7 @@ theorem iSup_neBot {f : ι → Filter α} : (⨆ i, f i).NeBot ↔ ∃ i, (f i). simp [neBot_iff] theorem iInf_eq_generate (s : ι → Filter α) : iInf s = generate (⋃ i, (s i).sets) := - show generate _ = generate _ from congr_arg _ <| congr_arg sSup <| (range_comp _ _).symm + eq_of_forall_le_iff fun _ ↦ by simp [le_generate_iff] theorem mem_iInf_of_mem {f : ι → Filter α} (i : ι) {s} (hs : s ∈ f i) : s ∈ ⨅ i, f i := iInf_le f i hs @@ -791,7 +588,7 @@ abbrev coframeMinimalAxioms : Coframe.MinimalAxioms (Filter α) := iInf_sup_le_sup_sInf := fun f s t ⟨h₁, h₂⟩ => by classical rw [iInf_subtype'] - rw [sInf_eq_iInf', iInf_sets_eq_finite, mem_iUnion] at h₂ + rw [sInf_eq_iInf', ← Filter.mem_sets, iInf_sets_eq_finite, mem_iUnion] at h₂ obtain ⟨u, hu⟩ := h₂ rw [← Finset.inf_eq_iInf] at hu suffices ⨅ i : s, f ⊔ ↑i ≤ f ⊔ u.inf fun i => ↑i from this ⟨h₁, hu⟩ @@ -950,14 +747,6 @@ theorem join_mono {f₁ f₂ : Filter (Filter α)} (h : f₁ ≤ f₂) : join f /-! ### Eventually -/ -/-- `f.Eventually p` or `∀ᶠ x in f, p x` mean that `{x | p x} ∈ f`. E.g., `∀ᶠ x in atTop, p x` -means that `p` holds true for sufficiently large `x`. -/ -protected def Eventually (p : α → Prop) (f : Filter α) : Prop := - { x | p x } ∈ f - -@[inherit_doc Filter.Eventually] -notation3 "∀ᶠ "(...)" in "f", "r:(scoped p => Filter.Eventually p f) => r - theorem eventually_iff {f : Filter α} {P : α → Prop} : (∀ᶠ x in f, P x) ↔ { x | P x } ∈ f := Iff.rfl @@ -1106,14 +895,6 @@ theorem eventually_inf_principal {f : Filter α} {p : α → Prop} {s : Set α} /-! ### Frequently -/ -/-- `f.Frequently p` or `∃ᶠ x in f, p x` mean that `{x | ¬p x} ∉ f`. E.g., `∃ᶠ x in atTop, p x` -means that there exist arbitrarily large `x` for which `p` holds true. -/ -protected def Frequently (p : α → Prop) (f : Filter α) : Prop := - ¬∀ᶠ x in f, ¬p x - -@[inherit_doc Filter.Frequently] -notation3 "∃ᶠ "(...)" in "f", "r:(scoped p => Filter.Frequently p f) => r - theorem Eventually.frequently {f : Filter α} [NeBot f] {p : α → Prop} (h : ∀ᶠ x in f, p x) : ∃ᶠ x in f, p x := compl_not_mem h @@ -1163,7 +944,7 @@ lemma frequently_mem_iff_neBot {l : Filter α} {s : Set α} : (∃ᶠ x in l, x theorem frequently_iff_forall_eventually_exists_and {p : α → Prop} {f : Filter α} : (∃ᶠ x in f, p x) ↔ ∀ {q : α → Prop}, (∀ᶠ x in f, q x) → ∃ x, p x ∧ q x := - ⟨fun hp q hq => (hp.and_eventually hq).exists, fun H hp => by + ⟨fun hp _ hq => (hp.and_eventually hq).exists, fun H hp => by simpa only [and_not_self_iff, exists_false] using H hp⟩ theorem frequently_iff {f : Filter α} {P : α → Prop} : @@ -1210,7 +991,7 @@ theorem frequently_imp_distrib_left {f : Filter α} [NeBot f] {p : Prop} {q : α theorem frequently_imp_distrib_right {f : Filter α} [NeBot f] {p : α → Prop} {q : Prop} : (∃ᶠ x in f, p x → q) ↔ (∀ᶠ x in f, p x) → q := by - set_option tactic.skipAssignedInstances false in simp [frequently_imp_distrib] + simp only [frequently_imp_distrib, frequently_const] theorem eventually_imp_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} : (∀ᶠ x in f, p x → q) ↔ (∃ᶠ x in f, p x) → q := by @@ -1266,17 +1047,9 @@ theorem Eventually.choice {r : α → β → Prop} {l : Filter α} [l.NeBot] (h ### Relation “eventually equal” -/ -/-- Two functions `f` and `g` are *eventually equal* along a filter `l` if the set of `x` such that -`f x = g x` belongs to `l`. -/ -def EventuallyEq (l : Filter α) (f g : α → β) : Prop := - ∀ᶠ x in l, f x = g x - section EventuallyEq variable {l : Filter α} {f g : α → β} -@[inherit_doc] -notation:50 f " =ᶠ[" l:50 "] " g:50 => EventuallyEq l f g - theorem EventuallyEq.eventually (h : f =ᶠ[l] g) : ∀ᶠ x in l, f x = g x := h @[simp] lemma eventuallyEq_top : f =ᶠ[⊤] g ↔ f = g := by simp [EventuallyEq, funext_iff] @@ -1449,13 +1222,6 @@ section LE variable [LE β] {l : Filter α} -/-- A function `f` is eventually less than or equal to a function `g` at a filter `l`. -/ -def EventuallyLE (l : Filter α) (f g : α → β) : Prop := - ∀ᶠ x in l, f x ≤ g x - -@[inherit_doc] -notation:50 f " ≤ᶠ[" l:50 "] " g:50 => EventuallyLE l f g - theorem EventuallyLE.congr {f f' g g' : α → β} (H : f ≤ᶠ[l] g) (hf : f =ᶠ[l] f') (hg : g =ᶠ[l] g') : f' ≤ᶠ[l] g' := H.mp <| hg.mp <| hf.mono fun x hf hg H => by rwa [hf, hg] at H @@ -1654,13 +1420,6 @@ end EventuallyEq section Map -/-- The forward map of a filter -/ -def map (m : α → β) (f : Filter α) : Filter β where - sets := preimage m ⁻¹' f.sets - univ_sets := univ_mem - sets_of_superset hs st := mem_of_superset hs <| preimage_mono st - inter_sets hs ht := inter_mem hs ht - @[simp] theorem map_principal {s : Set α} {f : α → β} : map f (𝓟 s) = 𝓟 (Set.image f s) := Filter.ext fun _ => image_subset_iff.symm @@ -1725,25 +1484,11 @@ end Map section Comap -/-- The inverse map of a filter. A set `s` belongs to `Filter.comap m f` if either of the following -equivalent conditions hold. - -1. There exists a set `t ∈ f` such that `m ⁻¹' t ⊆ s`. This is used as a definition. -2. The set `kernImage m s = {y | ∀ x, m x = y → x ∈ s}` belongs to `f`, see `Filter.mem_comap'`. -3. The set `(m '' sᶜ)ᶜ` belongs to `f`, see `Filter.mem_comap_iff_compl` and -`Filter.compl_mem_comap`. -/ -def comap (m : α → β) (f : Filter β) : Filter α where - sets := { s | ∃ t ∈ f, m ⁻¹' t ⊆ s } - univ_sets := ⟨univ, univ_mem, by simp only [subset_univ, preimage_univ]⟩ - sets_of_superset := fun ⟨a', ha', ma'a⟩ ab => ⟨a', ha', ma'a.trans ab⟩ - inter_sets := fun ⟨a', ha₁, ha₂⟩ ⟨b', hb₁, hb₂⟩ => - ⟨a' ∩ b', inter_mem ha₁ hb₁, inter_subset_inter ha₂ hb₂⟩ - variable {f : α → β} {l : Filter β} {p : α → Prop} {s : Set α} theorem mem_comap' : s ∈ comap f l ↔ { y | ∀ ⦃x⦄, f x = y → x ∈ s } ∈ l := ⟨fun ⟨t, ht, hts⟩ => mem_of_superset ht fun y hy x hx => hts <| mem_preimage.2 <| by rwa [hx], - fun h => ⟨_, h, fun x hx => hx rfl⟩⟩ + fun h => ⟨_, h, fun _ hx => hx rfl⟩⟩ -- TODO: it would be nice to use `kernImage` much more to take advantage of common name and API, -- and then this would become `mem_comap'` @@ -1809,37 +1554,6 @@ theorem compl_mem_kernMap {s : Set β} : sᶜ ∈ kernMap m f ↔ ∃ t, tᶜ end KernMap -/-- 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 -applicative instance. -/ -def bind (f : Filter α) (m : α → Filter β) : Filter β := - join (map m f) - -/-- The applicative sequentiation operation. This is not induced by the bind operation. -/ -def seq (f : Filter (α → β)) (g : Filter α) : Filter β where - sets := { s | ∃ u ∈ f, ∃ t ∈ g, ∀ m ∈ u, ∀ x ∈ t, (m : α → β) x ∈ s } - univ_sets := ⟨univ, univ_mem, univ, univ_mem, fun _ _ _ _ => trivial⟩ - sets_of_superset := fun ⟨t₀, t₁, h₀, h₁, h⟩ hst => - ⟨t₀, t₁, h₀, h₁, fun _ hx _ hy => hst <| h _ hx _ hy⟩ - inter_sets := fun ⟨t₀, ht₀, t₁, ht₁, ht⟩ ⟨u₀, hu₀, u₁, hu₁, hu⟩ => - ⟨t₀ ∩ u₀, inter_mem ht₀ hu₀, t₁ ∩ u₁, inter_mem ht₁ hu₁, fun _ ⟨hx₀, hx₁⟩ _ ⟨hy₀, hy₁⟩ => - ⟨ht _ hx₀ _ hy₀, hu _ hx₁ _ hy₁⟩⟩ - -/-- `pure x` is the set of sets that contain `x`. It is equal to `𝓟 {x}` but -with this definition we have `s ∈ pure a` defeq `a ∈ s`. -/ -instance : Pure Filter := - ⟨fun x => - { sets := { s | x ∈ s } - inter_sets := And.intro - sets_of_superset := fun hs hst => hst hs - univ_sets := trivial }⟩ - -instance : Bind Filter := - ⟨@Filter.bind⟩ - -instance : Functor Filter where map := @Filter.map - instance : LawfulFunctor (Filter : Type u → Type u) where id_map _ := map_id comp_map _ _ _ := map_map.symm @@ -1848,10 +1562,6 @@ instance : LawfulFunctor (Filter : Type u → Type u) where theorem pure_sets (a : α) : (pure a : Filter α).sets = { s | a ∈ s } := rfl -@[simp] -theorem mem_pure {a : α} {s : Set α} : s ∈ (pure a : Filter α) ↔ a ∈ s := - Iff.rfl - @[simp] theorem eventually_pure {a : α} {p : α → Prop} : (∀ᶠ x in pure a, p x) ↔ p a := Iff.rfl @@ -2594,263 +2304,6 @@ theorem principal_bind {s : Set α} {f : α → Filter β} : bind (𝓟 s) f = end Bind -/-! ### Limits -/ - -/-- `Filter.Tendsto` is the generic "limit of a function" predicate. - `Tendsto f l₁ l₂` asserts that for every `l₂` neighborhood `a`, - the `f`-preimage of `a` is an `l₁` neighborhood. -/ -def Tendsto (f : α → β) (l₁ : Filter α) (l₂ : Filter β) := - l₁.map f ≤ l₂ - -theorem tendsto_def {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : - Tendsto f l₁ l₂ ↔ ∀ s ∈ l₂, f ⁻¹' s ∈ l₁ := - Iff.rfl - -theorem tendsto_iff_eventually {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : - Tendsto f l₁ l₂ ↔ ∀ ⦃p : β → Prop⦄, (∀ᶠ y in l₂, p y) → ∀ᶠ x in l₁, p (f x) := - Iff.rfl - -theorem tendsto_iff_forall_eventually_mem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : - Tendsto f l₁ l₂ ↔ ∀ s ∈ l₂, ∀ᶠ x in l₁, f x ∈ s := - Iff.rfl - -lemma Tendsto.eventually_mem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {s : Set β} - (hf : Tendsto f l₁ l₂) (h : s ∈ l₂) : ∀ᶠ x in l₁, f x ∈ s := - hf h - -theorem Tendsto.eventually {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {p : β → Prop} - (hf : Tendsto f l₁ l₂) (h : ∀ᶠ y in l₂, p y) : ∀ᶠ x in l₁, p (f x) := - hf h - -theorem not_tendsto_iff_exists_frequently_nmem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : - ¬Tendsto f l₁ l₂ ↔ ∃ s ∈ l₂, ∃ᶠ x in l₁, f x ∉ s := by - simp only [tendsto_iff_forall_eventually_mem, not_forall, exists_prop, not_eventually] - -theorem Tendsto.frequently {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {p : β → Prop} - (hf : Tendsto f l₁ l₂) (h : ∃ᶠ x in l₁, p (f x)) : ∃ᶠ y in l₂, p y := - mt hf.eventually h - -theorem Tendsto.frequently_map {l₁ : Filter α} {l₂ : Filter β} {p : α → Prop} {q : β → Prop} - (f : α → β) (c : Filter.Tendsto f l₁ l₂) (w : ∀ x, p x → q (f x)) (h : ∃ᶠ x in l₁, p x) : - ∃ᶠ y in l₂, q y := - c.frequently (h.mono w) - -@[simp] -theorem tendsto_bot {f : α → β} {l : Filter β} : Tendsto f ⊥ l := by simp [Tendsto] - -@[simp] theorem tendsto_top {f : α → β} {l : Filter α} : Tendsto f l ⊤ := le_top - -theorem le_map_of_right_inverse {mab : α → β} {mba : β → α} {f : Filter α} {g : Filter β} - (h₁ : mab ∘ mba =ᶠ[g] id) (h₂ : Tendsto mba g f) : g ≤ map mab f := by - rw [← @map_id _ g, ← map_congr h₁, ← map_map] - exact map_mono h₂ - -theorem tendsto_of_isEmpty [IsEmpty α] {f : α → β} {la : Filter α} {lb : Filter β} : - Tendsto f la lb := by simp only [filter_eq_bot_of_isEmpty la, tendsto_bot] - -theorem eventuallyEq_of_left_inv_of_right_inv {f : α → β} {g₁ g₂ : β → α} {fa : Filter α} - {fb : Filter β} (hleft : ∀ᶠ x in fa, g₁ (f x) = x) (hright : ∀ᶠ y in fb, f (g₂ y) = y) - (htendsto : Tendsto g₂ fb fa) : g₁ =ᶠ[fb] g₂ := - (htendsto.eventually hleft).mp <| hright.mono fun _ hr hl => (congr_arg g₁ hr.symm).trans hl - -theorem tendsto_iff_comap {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : - Tendsto f l₁ l₂ ↔ l₁ ≤ l₂.comap f := - map_le_iff_le_comap - -alias ⟨Tendsto.le_comap, _⟩ := tendsto_iff_comap - -protected theorem Tendsto.disjoint {f : α → β} {la₁ la₂ : Filter α} {lb₁ lb₂ : Filter β} - (h₁ : Tendsto f la₁ lb₁) (hd : Disjoint lb₁ lb₂) (h₂ : Tendsto f la₂ lb₂) : Disjoint la₁ la₂ := - (disjoint_comap hd).mono h₁.le_comap h₂.le_comap - -theorem tendsto_congr' {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (hl : f₁ =ᶠ[l₁] f₂) : - Tendsto f₁ l₁ l₂ ↔ Tendsto f₂ l₁ l₂ := by rw [Tendsto, Tendsto, map_congr hl] - -theorem Tendsto.congr' {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (hl : f₁ =ᶠ[l₁] f₂) - (h : Tendsto f₁ l₁ l₂) : Tendsto f₂ l₁ l₂ := - (tendsto_congr' hl).1 h - -theorem tendsto_congr {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (h : ∀ x, f₁ x = f₂ x) : - Tendsto f₁ l₁ l₂ ↔ Tendsto f₂ l₁ l₂ := - tendsto_congr' (univ_mem' h) - -theorem Tendsto.congr {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (h : ∀ x, f₁ x = f₂ x) : - Tendsto f₁ l₁ l₂ → Tendsto f₂ l₁ l₂ := - (tendsto_congr h).1 - -theorem tendsto_id' {x y : Filter α} : Tendsto id x y ↔ x ≤ y := - Iff.rfl - -theorem tendsto_id {x : Filter α} : Tendsto id x x := - le_refl x - -theorem Tendsto.comp {f : α → β} {g : β → γ} {x : Filter α} {y : Filter β} {z : Filter γ} - (hg : Tendsto g y z) (hf : Tendsto f x y) : Tendsto (g ∘ f) x z := fun _ hs => hf (hg hs) - -protected theorem Tendsto.iterate {f : α → α} {l : Filter α} (h : Tendsto f l l) : - ∀ n, Tendsto (f^[n]) l l - | 0 => tendsto_id - | (n + 1) => (h.iterate n).comp h - -theorem Tendsto.mono_left {f : α → β} {x y : Filter α} {z : Filter β} (hx : Tendsto f x z) - (h : y ≤ x) : Tendsto f y z := - (map_mono h).trans hx - -theorem Tendsto.mono_right {f : α → β} {x : Filter α} {y z : Filter β} (hy : Tendsto f x y) - (hz : y ≤ z) : Tendsto f x z := - le_trans hy hz - -theorem Tendsto.neBot {f : α → β} {x : Filter α} {y : Filter β} (h : Tendsto f x y) [hx : NeBot x] : - NeBot y := - (hx.map _).mono h - -theorem tendsto_map {f : α → β} {x : Filter α} : Tendsto f x (map f x) := - le_refl (map f x) - -@[simp] -theorem tendsto_map'_iff {f : β → γ} {g : α → β} {x : Filter α} {y : Filter γ} : - Tendsto f (map g x) y ↔ Tendsto (f ∘ g) x y := by - rw [Tendsto, Tendsto, map_map] - -alias ⟨_, tendsto_map'⟩ := tendsto_map'_iff - -theorem tendsto_comap {f : α → β} {x : Filter β} : Tendsto f (comap f x) x := - map_comap_le - -@[simp] -theorem tendsto_comap_iff {f : α → β} {g : β → γ} {a : Filter α} {c : Filter γ} : - Tendsto f a (c.comap g) ↔ Tendsto (g ∘ f) a c := - ⟨fun h => tendsto_comap.comp h, fun h => map_le_iff_le_comap.mp <| by rwa [map_map]⟩ - -theorem tendsto_comap'_iff {m : α → β} {f : Filter α} {g : Filter β} {i : γ → α} (h : range i ∈ f) : - Tendsto (m ∘ i) (comap i f) g ↔ Tendsto m f g := by - rw [Tendsto, ← map_compose] - simp only [(· ∘ ·), map_comap_of_mem h, Tendsto] - -theorem Tendsto.of_tendsto_comp {f : α → β} {g : β → γ} {a : Filter α} {b : Filter β} {c : Filter γ} - (hfg : Tendsto (g ∘ f) a c) (hg : comap g c ≤ b) : Tendsto f a b := by - rw [tendsto_iff_comap] at hfg ⊢ - calc - a ≤ comap (g ∘ f) c := hfg - _ ≤ comap f b := by simpa [comap_comap] using comap_mono hg - -theorem comap_eq_of_inverse {f : Filter α} {g : Filter β} {φ : α → β} (ψ : β → α) (eq : ψ ∘ φ = id) - (hφ : Tendsto φ f g) (hψ : Tendsto ψ g f) : comap φ g = f := by - refine ((comap_mono <| map_le_iff_le_comap.1 hψ).trans ?_).antisymm (map_le_iff_le_comap.1 hφ) - rw [comap_comap, eq, comap_id] - -theorem map_eq_of_inverse {f : Filter α} {g : Filter β} {φ : α → β} (ψ : β → α) (eq : φ ∘ ψ = id) - (hφ : Tendsto φ f g) (hψ : Tendsto ψ g f) : map φ f = g := by - refine le_antisymm hφ (le_trans ?_ (map_mono hψ)) - rw [map_map, eq, map_id] - -theorem tendsto_inf {f : α → β} {x : Filter α} {y₁ y₂ : Filter β} : - Tendsto f x (y₁ ⊓ y₂) ↔ Tendsto f x y₁ ∧ Tendsto f x y₂ := by - simp only [Tendsto, le_inf_iff] - -theorem tendsto_inf_left {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} (h : Tendsto f x₁ y) : - Tendsto f (x₁ ⊓ x₂) y := - le_trans (map_mono inf_le_left) h - -theorem tendsto_inf_right {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} (h : Tendsto f x₂ y) : - Tendsto f (x₁ ⊓ x₂) y := - le_trans (map_mono inf_le_right) h - -theorem Tendsto.inf {f : α → β} {x₁ x₂ : Filter α} {y₁ y₂ : Filter β} (h₁ : Tendsto f x₁ y₁) - (h₂ : Tendsto f x₂ y₂) : Tendsto f (x₁ ⊓ x₂) (y₁ ⊓ y₂) := - tendsto_inf.2 ⟨tendsto_inf_left h₁, tendsto_inf_right h₂⟩ - -@[simp] -theorem tendsto_iInf {f : α → β} {x : Filter α} {y : ι → Filter β} : - Tendsto f x (⨅ i, y i) ↔ ∀ i, Tendsto f x (y i) := by - simp only [Tendsto, le_iInf_iff] - -theorem tendsto_iInf' {f : α → β} {x : ι → Filter α} {y : Filter β} (i : ι) - (hi : Tendsto f (x i) y) : Tendsto f (⨅ i, x i) y := - hi.mono_left <| iInf_le _ _ - -theorem tendsto_iInf_iInf {f : α → β} {x : ι → Filter α} {y : ι → Filter β} - (h : ∀ i, Tendsto f (x i) (y i)) : Tendsto f (iInf x) (iInf y) := - tendsto_iInf.2 fun i => tendsto_iInf' i (h i) - -@[simp] -theorem tendsto_sup {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} : - Tendsto f (x₁ ⊔ x₂) y ↔ Tendsto f x₁ y ∧ Tendsto f x₂ y := by - simp only [Tendsto, map_sup, sup_le_iff] - -theorem Tendsto.sup {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} : - Tendsto f x₁ y → Tendsto f x₂ y → Tendsto f (x₁ ⊔ x₂) y := fun h₁ h₂ => tendsto_sup.mpr ⟨h₁, h₂⟩ - -theorem Tendsto.sup_sup {f : α → β} {x₁ x₂ : Filter α} {y₁ y₂ : Filter β} - (h₁ : Tendsto f x₁ y₁) (h₂ : Tendsto f x₂ y₂) : Tendsto f (x₁ ⊔ x₂) (y₁ ⊔ y₂) := - tendsto_sup.mpr ⟨h₁.mono_right le_sup_left, h₂.mono_right le_sup_right⟩ - -@[simp] -theorem tendsto_iSup {f : α → β} {x : ι → Filter α} {y : Filter β} : - Tendsto f (⨆ i, x i) y ↔ ∀ i, Tendsto f (x i) y := by simp only [Tendsto, map_iSup, iSup_le_iff] - -theorem tendsto_iSup_iSup {f : α → β} {x : ι → Filter α} {y : ι → Filter β} - (h : ∀ i, Tendsto f (x i) (y i)) : Tendsto f (iSup x) (iSup y) := - tendsto_iSup.2 fun i => (h i).mono_right <| le_iSup _ _ - -@[simp] theorem tendsto_principal {f : α → β} {l : Filter α} {s : Set β} : - Tendsto f l (𝓟 s) ↔ ∀ᶠ a in l, f a ∈ s := by - simp only [Tendsto, le_principal_iff, mem_map', Filter.Eventually] - --- Porting note: was a `simp` lemma -theorem tendsto_principal_principal {f : α → β} {s : Set α} {t : Set β} : - Tendsto f (𝓟 s) (𝓟 t) ↔ ∀ a ∈ s, f a ∈ t := by - simp only [tendsto_principal, eventually_principal] - -@[simp] theorem tendsto_pure {f : α → β} {a : Filter α} {b : β} : - Tendsto f a (pure b) ↔ ∀ᶠ x in a, f x = b := by - simp only [Tendsto, le_pure_iff, mem_map', mem_singleton_iff, Filter.Eventually] - -theorem tendsto_pure_pure (f : α → β) (a : α) : Tendsto f (pure a) (pure (f a)) := - tendsto_pure.2 rfl - -theorem tendsto_const_pure {a : Filter α} {b : β} : Tendsto (fun _ => b) a (pure b) := - tendsto_pure.2 <| univ_mem' fun _ => rfl - -theorem pure_le_iff {a : α} {l : Filter α} : pure a ≤ l ↔ ∀ s ∈ l, a ∈ s := - Iff.rfl - -theorem tendsto_pure_left {f : α → β} {a : α} {l : Filter β} : - Tendsto f (pure a) l ↔ ∀ s ∈ l, f a ∈ s := - Iff.rfl - -@[simp] -theorem map_inf_principal_preimage {f : α → β} {s : Set β} {l : Filter α} : - map f (l ⊓ 𝓟 (f ⁻¹' s)) = map f l ⊓ 𝓟 s := - Filter.ext fun t => by simp only [mem_map', mem_inf_principal, mem_setOf_eq, mem_preimage] - -/-- If two filters are disjoint, then a function cannot tend to both of them along a non-trivial -filter. -/ -theorem Tendsto.not_tendsto {f : α → β} {a : Filter α} {b₁ b₂ : Filter β} (hf : Tendsto f a b₁) - [NeBot a] (hb : Disjoint b₁ b₂) : ¬Tendsto f a b₂ := fun hf' => - (tendsto_inf.2 ⟨hf, hf'⟩).neBot.ne hb.eq_bot - -protected theorem Tendsto.if {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} {p : α → Prop} - [∀ x, Decidable (p x)] (h₀ : Tendsto f (l₁ ⊓ 𝓟 { x | p x }) l₂) - (h₁ : Tendsto g (l₁ ⊓ 𝓟 { x | ¬p x }) l₂) : - Tendsto (fun x => if p x then f x else g x) l₁ l₂ := by - simp only [tendsto_def, mem_inf_principal] at * - intro s hs - filter_upwards [h₀ s hs, h₁ s hs] with x hp₀ hp₁ - rw [mem_preimage] - split_ifs with h - exacts [hp₀ h, hp₁ h] - -protected theorem Tendsto.if' {α β : Type*} {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} - {p : α → Prop} [DecidablePred p] (hf : Tendsto f l₁ l₂) (hg : Tendsto g l₁ l₂) : - Tendsto (fun a => if p a then f a else g a) l₁ l₂ := - (tendsto_inf_left hf).if (tendsto_inf_left hg) - -protected theorem Tendsto.piecewise {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} {s : Set α} - [∀ x, Decidable (x ∈ s)] (h₀ : Tendsto f (l₁ ⊓ 𝓟 s) l₂) (h₁ : Tendsto g (l₁ ⊓ 𝓟 sᶜ) l₂) : - Tendsto (piecewise s f g) l₁ l₂ := - Tendsto.if h₀ h₁ - end Filter open Filter @@ -2865,29 +2318,8 @@ theorem Set.EqOn.eventuallyEq_of_mem {α β} {s : Set α} {l : Filter α} {f g : theorem HasSubset.Subset.eventuallyLE {α} {l : Filter α} {s t : Set α} (h : s ⊆ t) : s ≤ᶠ[l] t := Filter.Eventually.of_forall h -theorem Set.MapsTo.tendsto {α β} {s : Set α} {t : Set β} {f : α → β} (h : MapsTo f s t) : - Filter.Tendsto f (𝓟 s) (𝓟 t) := - Filter.tendsto_principal_principal.2 h - -theorem Filter.EventuallyEq.comp_tendsto {α β γ : Type*} {l : Filter α} {f : α → β} {f' : α → β} - (H : f =ᶠ[l] f') {g : γ → α} {lc : Filter γ} (hg : Tendsto g lc l) : - f ∘ g =ᶠ[lc] f' ∘ g := - hg.eventually H - variable {α β : Type*} {F : Filter α} {G : Filter β} -theorem Filter.map_mapsTo_Iic_iff_tendsto {m : α → β} : - MapsTo (map m) (Iic F) (Iic G) ↔ Tendsto m F G := - ⟨fun hm ↦ hm right_mem_Iic, fun hm _ ↦ hm.mono_left⟩ - -alias ⟨_, Filter.Tendsto.map_mapsTo_Iic⟩ := Filter.map_mapsTo_Iic_iff_tendsto - -theorem Filter.map_mapsTo_Iic_iff_mapsTo {s : Set α} {t : Set β} {m : α → β} : - MapsTo (map m) (Iic <| 𝓟 s) (Iic <| 𝓟 t) ↔ MapsTo m s t := by - rw [map_mapsTo_Iic_iff_tendsto, tendsto_principal_principal, MapsTo] - -alias ⟨_, Set.MapsTo.filter_map_Iic⟩ := Filter.map_mapsTo_Iic_iff_mapsTo - -- TODO(Anatole): unify with the global case theorem Filter.map_surjOn_Iic_iff_le_map {m : α → β} : SurjOn (map m) (Iic F) (Iic G) ↔ G ≤ map m F := by @@ -2915,25 +2347,10 @@ alias ⟨_, Set.InjOn.filter_map_Iic⟩ := Filter.filter_injOn_Iic_iff_injOn namespace Filter -/-- Construct a filter from a property that is stable under finite unions. -A set `s` belongs to `Filter.comk p _ _ _` iff its complement satisfies the predicate `p`. -This constructor is useful to define filters like `Filter.cofinite`. -/ -def comk (p : Set α → Prop) (he : p ∅) (hmono : ∀ t, p t → ∀ s ⊆ t, p s) - (hunion : ∀ s, p s → ∀ t, p t → p (s ∪ t)) : Filter α where - sets := {t | p tᶜ} - univ_sets := by simpa - sets_of_superset := fun ht₁ ht => hmono _ ht₁ _ (compl_subset_compl.2 ht) - inter_sets := fun ht₁ ht₂ => by simp [compl_inter, hunion _ ht₁ _ ht₂] - -@[simp] -lemma mem_comk {p : Set α → Prop} {he hmono hunion s} : - s ∈ comk p he hmono hunion ↔ p sᶜ := - .rfl - lemma compl_mem_comk {p : Set α → Prop} {he hmono hunion s} : sᶜ ∈ comk p he hmono hunion ↔ p s := by simp end Filter -set_option linter.style.longFile 3000 +set_option linter.style.longFile 2500 diff --git a/Mathlib/Order/Filter/CardinalInter.lean b/Mathlib/Order/Filter/CardinalInter.lean index df6c37ffccbb7..22967d8a816b3 100644 --- a/Mathlib/Order/Filter/CardinalInter.lean +++ b/Mathlib/Order/Filter/CardinalInter.lean @@ -3,9 +3,9 @@ Copyright (c) 2024 Josha Dekker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Josha Dekker -/ -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto import Mathlib.Order.Filter.CountableInter -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Cofinality /-! @@ -17,11 +17,11 @@ their intersection belongs to `l` as well. # Main results * `Filter.cardinalInterFilter_aleph0` establishes that every filter `l` is a - `CardinalInterFilter l aleph0` + `CardinalInterFilter l ℵ₀` * `CardinalInterFilter.toCountableInterFilter` establishes that every `CardinalInterFilter l c` with - `c > aleph0` is a `CountableInterFilter`. + `c > ℵ₀` is a `CountableInterFilter`. * `CountableInterFilter.toCardinalInterFilter` establishes that every `CountableInterFilter l` is a - `CardinalInterFilter l aleph1`. + `CardinalInterFilter l ℵ₁`. * `CardinalInterFilter.of_CardinalInterFilter_of_lt` establishes that we have `CardinalInterFilter l c` → `CardinalInterFilter l a` for all `a < c`. @@ -48,26 +48,26 @@ theorem cardinal_sInter_mem {S : Set (Set α)} [CardinalInterFilter l c] (hSc : ⋂₀ S ∈ l ↔ ∀ s ∈ S, s ∈ l := ⟨fun hS _s hs => mem_of_superset hS (sInter_subset_of_mem hs), CardinalInterFilter.cardinal_sInter_mem _ hSc⟩ -/-- Every filter is a CardinalInterFilter with c = aleph0 -/ -theorem _root_.Filter.cardinalInterFilter_aleph0 (l : Filter α) : CardinalInterFilter l aleph0 where +/-- Every filter is a CardinalInterFilter with c = ℵ₀ -/ +theorem _root_.Filter.cardinalInterFilter_aleph0 (l : Filter α) : CardinalInterFilter l ℵ₀ where cardinal_sInter_mem := by simp_all only [aleph_zero, lt_aleph0_iff_subtype_finite, setOf_mem_eq, sInter_mem, implies_true, forall_const] -/-- Every CardinalInterFilter with c > aleph0 is a CountableInterFilter -/ +/-- Every CardinalInterFilter with c > ℵ₀ is a CountableInterFilter -/ theorem CardinalInterFilter.toCountableInterFilter (l : Filter α) [CardinalInterFilter l c] - (hc : aleph0 < c) : CountableInterFilter l where + (hc : ℵ₀ < c) : CountableInterFilter l where countable_sInter_mem S hS a := CardinalInterFilter.cardinal_sInter_mem S (lt_of_le_of_lt (Set.Countable.le_aleph0 hS) hc) a -/-- Every CountableInterFilter is a CardinalInterFilter with c = aleph 1-/ +/-- Every CountableInterFilter is a CardinalInterFilter with c = ℵ₁ -/ instance CountableInterFilter.toCardinalInterFilter (l : Filter α) [CountableInterFilter l] : - CardinalInterFilter l (aleph 1) where + CardinalInterFilter l ℵ₁ where cardinal_sInter_mem S hS a := CountableInterFilter.countable_sInter_mem S ((countable_iff_lt_aleph_one S).mpr hS) a theorem cardinalInterFilter_aleph_one_iff : - CardinalInterFilter l (aleph 1) ↔ CountableInterFilter l := + CardinalInterFilter l ℵ₁ ↔ CountableInterFilter l := ⟨fun _ ↦ ⟨fun S h a ↦ CardinalInterFilter.cardinal_sInter_mem S ((countable_iff_lt_aleph_one S).1 h) a⟩, fun _ ↦ CountableInterFilter.toCardinalInterFilter l⟩ diff --git a/Mathlib/Order/Filter/Cocardinal.lean b/Mathlib/Order/Filter/Cocardinal.lean index ede785eb18061..25e10e20a8fa3 100644 --- a/Mathlib/Order/Filter/Cocardinal.lean +++ b/Mathlib/Order/Filter/Cocardinal.lean @@ -6,7 +6,7 @@ Authors: Josha Dekker import Mathlib.Order.Filter.Cofinite import Mathlib.Order.Filter.CountableInter import Mathlib.Order.Filter.CardinalInter -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Cofinality import Mathlib.Order.Filter.Bases @@ -22,9 +22,7 @@ In this file we define `Filter.cocardinal hc`: the filter of sets with cardinali open Set Filter Cardinal universe u -variable {ι : Type u} {α β : Type u} -variable {c : Cardinal.{u}} {hreg : c.IsRegular} -variable {l : Filter α} +variable {α : Type u} {c : Cardinal.{u}} {hreg : c.IsRegular} namespace Filter diff --git a/Mathlib/Order/Filter/Cofinite.lean b/Mathlib/Order/Filter/Cofinite.lean index 03cc4bdf98814..94c269c447ffa 100644 --- a/Mathlib/Order/Filter/Cofinite.lean +++ b/Mathlib/Order/Filter/Cofinite.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jeremy Avigad, Yury Kudryashov -/ import Mathlib.Order.Filter.AtTopBot +import Mathlib.Order.Filter.Ker import Mathlib.Order.Filter.Pi /-! diff --git a/Mathlib/Order/Filter/CountableInter.lean b/Mathlib/Order/Filter/CountableInter.lean index b9d5d1ef60f8d..829b92767118e 100644 --- a/Mathlib/Order/Filter/CountableInter.lean +++ b/Mathlib/Order/Filter/CountableInter.lean @@ -21,8 +21,8 @@ and provide instances for some basic constructions (`⊥`, `⊤`, `Filter.princi that deduces two axioms of a `Filter` from the countable intersection property. Note that there also exists a typeclass `CardinalInterFilter`, and thus an alternative spelling of -`CountableInterFilter` as `CardinalInterFilter l (aleph 1)`. The former (defined here) is the -preferred spelling; it has the advantage of not requiring the user to import the theory ordinals. +`CountableInterFilter` as `CardinalInterFilter l ℵ₁`. The former (defined here) is the +preferred spelling; it has the advantage of not requiring the user to import the theory of ordinals. ## Tags filter, countable diff --git a/Mathlib/Order/Filter/Curry.lean b/Mathlib/Order/Filter/Curry.lean index 561f48bd033b3..7f91d3cc76ef9 100644 --- a/Mathlib/Order/Filter/Curry.lean +++ b/Mathlib/Order/Filter/Curry.lean @@ -49,13 +49,6 @@ namespace Filter variable {α β γ : Type*} -/-- This filter is characterized by `Filter.eventually_curry_iff`: -`(∀ᶠ (x : α × β) in f.curry g, p x) ↔ ∀ᶠ (x : α) in f, ∀ᶠ (y : β) in g, p (x, y)`. Useful -in adding quantifiers to the middle of `Tendsto`s. See -`hasFDerivAt_of_tendstoUniformlyOnFilter`. -/ -def curry (f : Filter α) (g : Filter β) : Filter (α × β) := - bind f fun a ↦ map (a, ·) g - 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) := Iff.rfl diff --git a/Mathlib/Order/Filter/Defs.lean b/Mathlib/Order/Filter/Defs.lean new file mode 100644 index 0000000000000..a91d2c91457f3 --- /dev/null +++ b/Mathlib/Order/Filter/Defs.lean @@ -0,0 +1,395 @@ +/- +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 +-/ +import Mathlib.Order.SetNotation +import Mathlib.Order.Bounds.Defs +import Mathlib.Data.Set.Basic + +/-! +# Definitions about filters + +A *filter* on a type `α` is a collection of sets of `α` which contains the whole `α`, +is upwards-closed, and is stable under intersection. Filters are mostly used to +abstract two related kinds of ideas: +* *limits*, including finite or infinite limits of sequences, finite or infinite limits of functions + at a point or at infinity, etc... +* *things happening eventually*, including things happening for large enough `n : ℕ`, or near enough + a point `x`, or for close enough pairs of points, or things happening almost everywhere in the + sense of measure theory. Dually, filters can also express the idea of *things happening often*: + for arbitrarily large `n`, or at a point in any neighborhood of given a point etc... + +## Main definitions + +* `Filter` : filters on a set; +* `Filter.principal`, `𝓟 s` : filter of all sets containing a given set; +* `Filter.map`, `Filter.comap` : operations on filters; +* `Filter.Tendsto` : limit with respect to filters; +* `Filter.Eventually` : `f.Eventually p` means `{x | p x} ∈ f`; +* `Filter.Frequently` : `f.Frequently p` means `{x | ¬p x} ∉ f`; +* `filter_upwards [h₁, ..., hₙ]` : + a tactic that takes a list of proofs `hᵢ : sᵢ ∈ f`, + and replaces a goal `s ∈ f` with `∀ x, x ∈ s₁ → ... → x ∈ sₙ → x ∈ s`; +* `Filter.NeBot f` : a utility class stating that `f` is a non-trivial filter. + +## Notations + +* `∀ᶠ x in f, p x` : `f.Eventually p`; +* `∃ᶠ x in f, p x` : `f.Frequently p`; +* `f =ᶠ[l] g` : `∀ᶠ x in l, f x = g x`; +* `f ≤ᶠ[l] g` : `∀ᶠ x in l, f x ≤ g x`; +* `𝓟 s` : `Filter.Principal s`, localized in `Filter`. + +## Implementation Notes + +Important note: Bourbaki requires that a filter on `X` cannot contain all sets of `X`, +which we do *not* require. +This gives `Filter X` better formal properties, +in particular a bottom element `⊥` for its lattice structure, +at the cost of including the assumption `[NeBot f]` in a number of lemmas and definitions. + +## References + +* [N. Bourbaki, *General Topology*][bourbaki1966] +-/ + +open Set + +/-- A filter `F` on a type `α` is a collection of sets of `α` which contains the whole `α`, +is upwards-closed, and is stable under intersection. We do not forbid this collection to be +all sets of `α`. -/ +structure Filter (α : Type*) where + /-- The set of sets that belong to the filter. -/ + sets : Set (Set α) + /-- The set `Set.univ` belongs to any filter. -/ + univ_sets : Set.univ ∈ sets + /-- If a set belongs to a filter, then its superset belongs to the filter as well. -/ + sets_of_superset {x y} : x ∈ sets → x ⊆ y → y ∈ sets + /-- If two sets belong to a filter, then their intersection belongs to the filter as well. -/ + inter_sets {x y} : x ∈ sets → y ∈ sets → x ∩ y ∈ sets + +namespace Filter + +variable {α β : Type*} {f g : Filter α} {s t : Set α} + +theorem filter_eq : ∀ {f g : Filter α}, f.sets = g.sets → f = g + | ⟨_, _, _, _⟩, ⟨_, _, _, _⟩, rfl => rfl + +/-- If `F` is a filter on `α`, and `U` a subset of `α` then we can write `U ∈ F` as on paper. -/ +instance instMembership : Membership (Set α) (Filter α) := ⟨fun F U => U ∈ F.sets⟩ + +@[ext] +protected theorem ext (h : ∀ s, s ∈ f ↔ s ∈ g) : f = g := filter_eq <| Set.ext h + +@[simp] +protected theorem mem_mk {t : Set (Set α)} {h₁ h₂ h₃} : s ∈ mk t h₁ h₂ h₃ ↔ s ∈ t := + Iff.rfl + +@[simp] +protected theorem mem_sets : s ∈ f.sets ↔ s ∈ f := + Iff.rfl + +@[simp] +theorem univ_mem : univ ∈ f := + f.univ_sets + +theorem mem_of_superset {x y : Set α} (hx : x ∈ f) (hxy : x ⊆ y) : y ∈ f := + f.sets_of_superset hx hxy + +theorem univ_mem' (h : ∀ a, a ∈ s) : s ∈ f := + mem_of_superset univ_mem fun x _ => h x + +theorem inter_mem (hs : s ∈ f) (ht : t ∈ f) : s ∩ t ∈ f := + f.inter_sets hs ht + +theorem mp_mem (hs : s ∈ f) (h : { x | x ∈ s → x ∈ t } ∈ f) : t ∈ f := + mem_of_superset (inter_mem hs h) fun _ ⟨h₁, h₂⟩ => h₂ h₁ + +/-- Override `sets` field of a filter to provide better definitional equality. -/ +protected def copy (f : Filter α) (S : Set (Set α)) (hmem : ∀ s, s ∈ S ↔ s ∈ f) : Filter α where + sets := S + univ_sets := (hmem _).2 univ_mem + sets_of_superset h hsub := (hmem _).2 <| mem_of_superset ((hmem _).1 h) hsub + inter_sets h₁ h₂ := (hmem _).2 <| inter_mem ((hmem _).1 h₁) ((hmem _).1 h₂) + +@[simp] theorem mem_copy {S hmem} : s ∈ f.copy S hmem ↔ s ∈ S := Iff.rfl + +/-- Construct a filter from a property that is stable under finite unions. +A set `s` belongs to `Filter.comk p _ _ _` iff its complement satisfies the predicate `p`. +This constructor is useful to define filters like `Filter.cofinite`. -/ +def comk (p : Set α → Prop) (he : p ∅) (hmono : ∀ t, p t → ∀ s ⊆ t, p s) + (hunion : ∀ s, p s → ∀ t, p t → p (s ∪ t)) : Filter α where + sets := {t | p tᶜ} + univ_sets := by simpa + sets_of_superset := fun ht₁ ht => hmono _ ht₁ _ (compl_subset_compl.2 ht) + inter_sets := fun ht₁ ht₂ => by simp [compl_inter, hunion _ ht₁ _ ht₂] + +@[simp] +lemma mem_comk {p : Set α → Prop} {he hmono hunion s} : + s ∈ comk p he hmono hunion ↔ p sᶜ := + .rfl + +/-- The principal filter of `s` is the collection of all supersets of `s`. -/ +def principal (s : Set α) : Filter α where + sets := { t | s ⊆ t } + univ_sets := subset_univ s + sets_of_superset hx := Subset.trans hx + inter_sets := subset_inter + +@[inherit_doc] +scoped notation "𝓟" => Filter.principal + +@[simp] theorem mem_principal : s ∈ 𝓟 t ↔ t ⊆ s := Iff.rfl + +/-- `pure x` is the set of sets that contain `x`. It is equal to `𝓟 {x}` but +with this definition we have `s ∈ pure a` defeq `a ∈ s`. -/ +instance : Pure Filter where + pure x := .copy (𝓟 {x}) {s | x ∈ s} fun _ ↦ by simp + +@[simp] +theorem mem_pure {a : α} {s : Set α} : s ∈ (pure a : Filter α) ↔ a ∈ s := + Iff.rfl + +/-- The *kernel* of a filter is the intersection of all its sets. -/ +def ker (f : Filter α) : Set α := ⋂₀ f.sets + +/-- The join of a filter of filters is defined by the relation `s ∈ join f ↔ {t | s ∈ t} ∈ f`. -/ +def join (f : Filter (Filter α)) : Filter α where + sets := { s | { t : Filter α | s ∈ t } ∈ f } + univ_sets := by simp only [mem_setOf_eq, univ_mem, setOf_true] + sets_of_superset hx xy := mem_of_superset hx fun f h => mem_of_superset h xy + inter_sets hx hy := mem_of_superset (inter_mem hx hy) fun f ⟨h₁, h₂⟩ => inter_mem h₁ h₂ + +@[simp] +theorem mem_join {s : Set α} {f : Filter (Filter α)} : s ∈ join f ↔ { t | s ∈ t } ∈ f := + Iff.rfl + +instance : PartialOrder (Filter α) where + le f g := ∀ ⦃U : Set α⦄, U ∈ g → U ∈ f + le_antisymm a b h₁ h₂ := filter_eq <| Subset.antisymm h₂ h₁ + le_refl a := Subset.rfl + le_trans a b c h₁ h₂ := Subset.trans h₂ h₁ + +theorem le_def : f ≤ g ↔ ∀ x ∈ g, x ∈ f := + Iff.rfl + +instance instSupSet : SupSet (Filter α) where + sSup S := join (𝓟 S) + +@[simp] theorem mem_sSup {S : Set (Filter α)} : s ∈ sSup S ↔ ∀ f ∈ S, s ∈ f := .rfl + +/-- Infimum of a set of filters. +This definition is marked as irreducible +so that Lean doesn't try to unfold it when unifying expressions. -/ +@[irreducible] +protected def sInf (s : Set (Filter α)) : Filter α := sSup (lowerBounds s) + +instance instInfSet : InfSet (Filter α) where + sInf := Filter.sInf + +protected theorem sSup_lowerBounds (s : Set (Filter α)) : sSup (lowerBounds s) = sInf s := by + simp [sInf, Filter.sInf] + +instance : Top (Filter α) where + top := .copy (sSup (Set.range pure)) {s | ∀ x, x ∈ s} <| by simp + +theorem mem_top_iff_forall {s : Set α} : s ∈ (⊤ : Filter α) ↔ ∀ x, x ∈ s := + Iff.rfl + +@[simp] +theorem mem_top {s : Set α} : s ∈ (⊤ : Filter α) ↔ s = univ := by + rw [mem_top_iff_forall, eq_univ_iff_forall] + +instance : Bot (Filter α) where + bot := .copy (sSup ∅) univ <| by simp + +@[simp] +theorem mem_bot {s : Set α} : s ∈ (⊥ : Filter α) := + trivial + +/-- The infimum of filters is the filter generated by intersections + of elements of the two filters. -/ +instance instInf : Inf (Filter α) := + ⟨fun f g : Filter α => + { sets := { s | ∃ a ∈ f, ∃ b ∈ g, s = a ∩ b } + univ_sets := ⟨_, univ_mem, _, univ_mem, by simp⟩ + sets_of_superset := by + rintro x y ⟨a, ha, b, hb, rfl⟩ xy + refine ⟨a ∪ y, mem_of_superset ha subset_union_left, b ∪ y, + mem_of_superset hb subset_union_left, ?_⟩ + rw [← inter_union_distrib_right, union_eq_self_of_subset_left xy] + inter_sets := by + rintro x y ⟨a, ha, b, hb, rfl⟩ ⟨c, hc, d, hd, rfl⟩ + refine ⟨a ∩ c, inter_mem ha hc, b ∩ d, inter_mem hb hd, ?_⟩ + ac_rfl }⟩ + +/-- The supremum of two filters is the filter that contains sets that belong to both filters. -/ +instance instSup : Sup (Filter α) where + sup f g := .copy (sSup {f, g}) {s | s ∈ f ∧ s ∈ g} <| by simp + +/-- A filter is `NeBot` if it is not equal to `⊥`, or equivalently the empty set does not belong to +the filter. Bourbaki include this assumption in the definition of a filter but we prefer to have a +`CompleteLattice` structure on `Filter _`, so we use a typeclass argument in lemmas instead. -/ +class NeBot (f : Filter α) : Prop where + /-- The filter is nontrivial: `f ≠ ⊥` or equivalently, `∅ ∉ f`. -/ + ne' : f ≠ ⊥ + +theorem neBot_iff {f : Filter α} : NeBot f ↔ f ≠ ⊥ := + ⟨fun h => h.1, fun h => ⟨h⟩⟩ + +/-- `f.Eventually p` or `∀ᶠ x in f, p x` mean that `{x | p x} ∈ f`. E.g., `∀ᶠ x in atTop, p x` +means that `p` holds true for sufficiently large `x`. -/ +protected def Eventually (p : α → Prop) (f : Filter α) : Prop := + { x | p x } ∈ f + +@[inherit_doc Filter.Eventually] +notation3 "∀ᶠ "(...)" in "f", "r:(scoped p => Filter.Eventually p f) => r + +/-- `f.Frequently p` or `∃ᶠ x in f, p x` mean that `{x | ¬p x} ∉ f`. E.g., `∃ᶠ x in atTop, p x` +means that there exist arbitrarily large `x` for which `p` holds true. -/ +protected def Frequently (p : α → Prop) (f : Filter α) : Prop := + ¬∀ᶠ x in f, ¬p x + +@[inherit_doc Filter.Frequently] +notation3 "∃ᶠ "(...)" in "f", "r:(scoped p => Filter.Frequently p f) => r + +/-- Two functions `f` and `g` are *eventually equal* along a filter `l` if the set of `x` such that +`f x = g x` belongs to `l`. -/ +def EventuallyEq (l : Filter α) (f g : α → β) : Prop := + ∀ᶠ x in l, f x = g x + +@[inherit_doc] +notation:50 f " =ᶠ[" l:50 "] " g:50 => EventuallyEq l f g + +/-- A function `f` is eventually less than or equal to a function `g` at a filter `l`. -/ +def EventuallyLE [LE β] (l : Filter α) (f g : α → β) : Prop := + ∀ᶠ x in l, f x ≤ g x + +@[inherit_doc] +notation:50 f " ≤ᶠ[" l:50 "] " g:50 => EventuallyLE l f g + +/-- The forward map of a filter -/ +def map (m : α → β) (f : Filter α) : Filter β where + sets := preimage m ⁻¹' f.sets + univ_sets := univ_mem + sets_of_superset hs st := mem_of_superset hs fun _x hx ↦ st hx + inter_sets hs ht := inter_mem hs ht + +/-- `Filter.Tendsto` is the generic "limit of a function" predicate. + `Tendsto f l₁ l₂` asserts that for every `l₂` neighborhood `a`, + the `f`-preimage of `a` is an `l₁` neighborhood. -/ +def Tendsto (f : α → β) (l₁ : Filter α) (l₂ : Filter β) := + l₁.map f ≤ l₂ + +/-- The inverse map of a filter. A set `s` belongs to `Filter.comap m f` if either of the following +equivalent conditions hold. + +1. There exists a set `t ∈ f` such that `m ⁻¹' t ⊆ s`. This is used as a definition. +2. The set `kernImage m s = {y | ∀ x, m x = y → x ∈ s}` belongs to `f`, see `Filter.mem_comap'`. +3. The set `(m '' sᶜ)ᶜ` belongs to `f`, see `Filter.mem_comap_iff_compl` and +`Filter.compl_mem_comap`. -/ +def comap (m : α → β) (f : Filter β) : Filter α where + sets := { s | ∃ t ∈ f, m ⁻¹' t ⊆ s } + univ_sets := ⟨univ, univ_mem, subset_univ _⟩ + sets_of_superset := fun ⟨a', ha', ma'a⟩ ab => ⟨a', ha', ma'a.trans ab⟩ + 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 + +instance instSProd : SProd (Filter α) (Filter β) (Filter (α × β)) where + sprod := Filter.prod + +theorem prod_eq_inf (f : Filter α) (g : Filter β) : f ×ˢ g = f.comap Prod.fst ⊓ g.comap Prod.snd := + rfl + +/-- 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 +applicative instance. -/ +def bind (f : Filter α) (m : α → Filter β) : Filter β := + join (map m f) + +/-- The applicative sequentiation operation. This is not induced by the bind operation. -/ +def seq (f : Filter (α → β)) (g : Filter α) : Filter β where + sets := { s | ∃ u ∈ f, ∃ t ∈ g, ∀ m ∈ u, ∀ x ∈ t, (m : α → β) x ∈ s } + univ_sets := ⟨univ, univ_mem, univ, univ_mem, fun _ _ _ _ => trivial⟩ + sets_of_superset := fun ⟨t₀, t₁, h₀, h₁, h⟩ hst => + ⟨t₀, t₁, h₀, h₁, fun _ hx _ hy => hst <| h _ hx _ hy⟩ + inter_sets := fun ⟨t₀, ht₀, t₁, ht₁, ht⟩ ⟨u₀, hu₀, u₁, hu₁, hu⟩ => + ⟨t₀ ∩ u₀, inter_mem ht₀ hu₀, t₁ ∩ u₁, inter_mem ht₁ hu₁, fun _ ⟨hx₀, hx₁⟩ _ ⟨hy₀, hy₁⟩ => + ⟨ht _ hx₀ _ hy₀, hu _ hx₁ _ hy₁⟩⟩ + +/-- This filter is characterized by `Filter.eventually_curry_iff`: +`(∀ᶠ (x : α × β) in f.curry g, p x) ↔ ∀ᶠ (x : α) in f, ∀ᶠ (y : β) in g, p (x, y)`. Useful +in adding quantifiers to the middle of `Tendsto`s. See +`hasFDerivAt_of_tendstoUniformlyOnFilter`. -/ +def curry (f : Filter α) (g : Filter β) : Filter (α × β) := + bind f fun a ↦ map (a, ·) g + +instance : Bind Filter := + ⟨@Filter.bind⟩ + +instance : Functor Filter where map := @Filter.map + +/-- A variant on `bind` using a function `g` taking a set instead of a member of `α`. +This is essentially a push-forward along a function mapping each set to a filter. -/ +protected def lift (f : Filter α) (g : Set α → Filter β) := + ⨅ s ∈ f, g s + +/-- Specialize `lift` to functions `Set α → Set β`. This can be viewed as a generalization of `map`. +This is essentially a push-forward along a function mapping each set to a set. -/ +protected def lift' (f : Filter α) (h : Set α → Set β) := + f.lift (𝓟 ∘ h) + +end Filter + +namespace Mathlib.Tactic + +open Lean Meta Elab Tactic + +/-- +`filter_upwards [h₁, ⋯, hₙ]` replaces a goal of the form `s ∈ f` and terms +`h₁ : t₁ ∈ f, ⋯, hₙ : tₙ ∈ f` with `∀ x, x ∈ t₁ → ⋯ → x ∈ tₙ → x ∈ s`. +The list is an optional parameter, `[]` being its default value. + +`filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ` is a short form for +`{ filter_upwards [h₁, ⋯, hₙ], intros a₁ a₂ ⋯ aₖ }`. + +`filter_upwards [h₁, ⋯, hₙ] using e` is a short form for +`{ filter_upwards [h1, ⋯, hn], exact e }`. + +Combining both shortcuts is done by writing `filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ using e`. +Note that in this case, the `aᵢ` terms can be used in `e`. +-/ +syntax (name := filterUpwards) "filter_upwards" (" [" term,* "]")? + (" with" (ppSpace colGt term:max)*)? (" using " term)? : tactic + +elab_rules : tactic +| `(tactic| filter_upwards $[[$[$args],*]]? $[with $wth*]? $[using $usingArg]?) => do + let config : ApplyConfig := {newGoals := ApplyNewGoals.nonDependentOnly} + for e in args.getD #[] |>.reverse do + let goal ← getMainGoal + replaceMainGoal <| ← goal.withContext <| runTermElab do + let m ← mkFreshExprMVar none + let lem ← Term.elabTermEnsuringType + (← ``(Filter.mp_mem $e $(← Term.exprToSyntax m))) (← goal.getType) + goal.assign lem + return [m.mvarId!] + liftMetaTactic fun goal => do + goal.apply (← mkConstWithFreshMVarLevels ``Filter.univ_mem') config + evalTactic <|← `(tactic| dsimp (config := {zeta := false}) only [Set.mem_setOf_eq]) + if let some l := wth then + evalTactic <|← `(tactic| intro $[$l]*) + if let some e := usingArg then + evalTactic <|← `(tactic| exact $e) + +end Mathlib.Tactic diff --git a/Mathlib/Order/Filter/ENNReal.lean b/Mathlib/Order/Filter/ENNReal.lean index 8acfdf4fae082..e6578ed67d021 100644 --- a/Mathlib/Order/Filter/ENNReal.lean +++ b/Mathlib/Order/Filter/ENNReal.lean @@ -62,6 +62,7 @@ theorem limsup_const_mul [CountableInterFilter f] {u : α → ℝ≥0∞} {a : have hfu : f.limsup u ≠ 0 := mt limsup_eq_zero_iff.1 hu simp only [ha_top, top_mul', h_top_le, hfu, ite_false] +/-- See also `limsup_mul_le'`.-/ theorem limsup_mul_le [CountableInterFilter f] (u v : α → ℝ≥0∞) : f.limsup (u * v) ≤ f.limsup u * f.limsup v := calc diff --git a/Mathlib/Order/Filter/EventuallyConst.lean b/Mathlib/Order/Filter/EventuallyConst.lean index be981a5e72142..3ec97fbbb5501 100644 --- a/Mathlib/Order/Filter/EventuallyConst.lean +++ b/Mathlib/Order/Filter/EventuallyConst.lean @@ -155,7 +155,7 @@ end EventuallyConst lemma eventuallyConst_atTop [SemilatticeSup α] [Nonempty α] : EventuallyConst f atTop ↔ (∃ i, ∀ j, i ≤ j → f j = f i) := - (atTop_basis.eventuallyConst_iff' fun i _ ↦ left_mem_Ici).trans <| by + (atTop_basis.eventuallyConst_iff' fun _ _ ↦ left_mem_Ici).trans <| by simp only [true_and, mem_Ici] lemma eventuallyConst_atTop_nat {f : ℕ → α} : diff --git a/Mathlib/Order/Filter/Extr.lean b/Mathlib/Order/Filter/Extr.lean index aa4829ffbd4a4..ba1e7c93d0896 100644 --- a/Mathlib/Order/Filter/Extr.lean +++ b/Mathlib/Order/Filter/Extr.lean @@ -3,8 +3,8 @@ Copyright (c) 2019 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Order.Filter.Basic -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.Filter.Tendsto +import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Algebra.Order.Group.Defs /-! diff --git a/Mathlib/Order/Filter/FilterProduct.lean b/Mathlib/Order/Filter/FilterProduct.lean index 4e69166e08aea..c36a347ed094f 100644 --- a/Mathlib/Order/Filter/FilterProduct.lean +++ b/Mathlib/Order/Filter/FilterProduct.lean @@ -39,20 +39,20 @@ instance instGroupWithZero [GroupWithZero β] : GroupWithZero β* where __ := instDivInvMonoid __ := instMonoidWithZero mul_inv_cancel f := inductionOn f fun f hf ↦ coe_eq.2 <| (φ.em fun y ↦ f y = 0).elim - (fun H ↦ (hf <| coe_eq.2 H).elim) fun H ↦ H.mono fun x ↦ mul_inv_cancel₀ + (fun H ↦ (hf <| coe_eq.2 H).elim) fun H ↦ H.mono fun _ ↦ mul_inv_cancel₀ inv_zero := coe_eq.2 <| by simp only [Function.comp_def, inv_zero, EventuallyEq.rfl] instance instDivisionSemiring [DivisionSemiring β] : DivisionSemiring β* where toSemiring := instSemiring __ := instGroupWithZero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl instance instDivisionRing [DivisionRing β] : DivisionRing β* where __ := instRing __ := instDivisionSemiring qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl instance instSemifield [Semifield β] : Semifield β* where __ := instCommSemiring diff --git a/Mathlib/Order/Filter/Germ/Basic.lean b/Mathlib/Order/Filter/Germ/Basic.lean index dee43bb2b8c71..e4c6a4146b4b0 100644 --- a/Mathlib/Order/Filter/Germ/Basic.lean +++ b/Mathlib/Order/Filter/Germ/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, Abhimanyu Pallavi Sudhir -/ -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto import Mathlib.Algebra.Module.Pi /-! @@ -79,7 +79,6 @@ def productSetoid (l : Filter α) (ε : α → Type*) : Setoid ((a : _) → ε a /-- The filter product `(a : α) → ε a` at a filter `l`. This is a dependent version of `Filter.Germ`. -/ --- Porting note: removed @[protected] def Product (l : Filter α) (ε : α → Type*) : Type _ := Quotient (productSetoid l ε) @@ -118,7 +117,7 @@ def IsConstant {l : Filter α} (P : Germ l β) : Prop := exact fun f g b hfg hf ↦ (hfg.symm).trans hf theorem isConstant_coe {l : Filter α} {b} (h : ∀ x', f x' = b) : (↑f : Germ l β).IsConstant := - ⟨b, Eventually.of_forall (fun x ↦ h x)⟩ + ⟨b, Eventually.of_forall h⟩ @[simp] theorem isConstant_coe_const {l : Filter α} {b : β} : (fun _ : α ↦ b : Germ l β).IsConstant := by @@ -690,7 +689,7 @@ theorem const_le_iff [LE β] [NeBot l] {x y : β} : (↑x : Germ l β) ≤ ↑y instance instPreorder [Preorder β] : Preorder (Germ l β) where le := (· ≤ ·) le_refl f := inductionOn f <| EventuallyLE.refl l - le_trans f₁ f₂ f₃ := inductionOn₃ f₁ f₂ f₃ fun f₁ f₂ f₃ => EventuallyLE.trans + le_trans f₁ f₂ f₃ := inductionOn₃ f₁ f₂ f₃ fun _ _ _ => EventuallyLE.trans instance instPartialOrder [PartialOrder β] : PartialOrder (Germ l β) where le_antisymm f g := inductionOn₂ f g fun _ _ h₁ h₂ ↦ (EventuallyLE.antisymm h₁ h₂).germ_eq diff --git a/Mathlib/Order/Filter/Ker.lean b/Mathlib/Order/Filter/Ker.lean index 29f0a9d1d3129..ee06f9c53a8d1 100644 --- a/Mathlib/Order/Filter/Ker.lean +++ b/Mathlib/Order/Filter/Ker.lean @@ -21,9 +21,6 @@ namespace Filter variable {ι : Sort*} {α β : Type*} {f g : Filter α} {s : Set α} {a : α} -/-- The *kernel* of a filter is the intersection of all its sets. -/ -def ker (f : Filter α) : Set α := ⋂₀ f.sets - lemma ker_def (f : Filter α) : f.ker = ⋂ s ∈ f, s := sInter_eq_biInter @[simp] lemma mem_ker : a ∈ f.ker ↔ ∀ s ∈ f, a ∈ s := mem_sInter @@ -41,9 +38,9 @@ lemma ker_surjective : Surjective (ker : Filter α → Set α) := gi_principal_k @[simp] lemma ker_top : ker (⊤ : Filter α) = univ := gi_principal_ker.gc.u_top @[simp] lemma ker_eq_univ : ker f = univ ↔ f = ⊤ := gi_principal_ker.gc.u_eq_top.trans <| by simp @[simp] lemma ker_inf (f g : Filter α) : ker (f ⊓ g) = ker f ∩ ker g := gi_principal_ker.gc.u_inf -@[simp] lemma ker_iInf (f : ι → Filter α) : ker (⨅ i, f i) = ⨅ i, ker (f i) := +@[simp] lemma ker_iInf (f : ι → Filter α) : ker (⨅ i, f i) = ⋂ i, ker (f i) := gi_principal_ker.gc.u_iInf -@[simp] lemma ker_sInf (S : Set (Filter α)) : ker (sInf S) = ⨅ f ∈ S, ker f := +@[simp] lemma ker_sInf (S : Set (Filter α)) : ker (sInf S) = ⋂ f ∈ S, ker f := gi_principal_ker.gc.u_sInf @[simp] lemma ker_principal (s : Set α) : ker (𝓟 s) = s := gi_principal_ker.u_l_eq _ diff --git a/Mathlib/Order/Filter/Lift.lean b/Mathlib/Order/Filter/Lift.lean index d292896c54051..f485af84c1df0 100644 --- a/Mathlib/Order/Filter/Lift.lean +++ b/Mathlib/Order/Filter/Lift.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import Mathlib.Order.Filter.Bases +import Mathlib.Order.Filter.Prod import Mathlib.Order.ConditionallyCompleteLattice.Basic /-! @@ -18,11 +19,6 @@ variable {α β γ : Type*} {ι : Sort*} section lift -/-- A variant on `bind` using a function `g` taking a set instead of a member of `α`. -This is essentially a push-forward along a function mapping each set to a filter. -/ -protected def lift (f : Filter α) (g : Set α → Filter β) := - ⨅ s ∈ f, g s - variable {f f₁ f₂ : Filter α} {g g₁ g₂ : Set α → Filter β} @[simp] @@ -199,11 +195,6 @@ end lift section Lift' -/-- Specialize `lift` to functions `Set α → Set β`. This can be viewed as a generalization of `map`. -This is essentially a push-forward along a function mapping each set to a set. -/ -protected def lift' (f : Filter α) (h : Set α → Set β) := - f.lift (𝓟 ∘ h) - variable {f f₁ f₂ : Filter α} {h h₁ h₂ : Set α → Set β} @[simp] diff --git a/Mathlib/Order/Filter/NAry.lean b/Mathlib/Order/Filter/NAry.lean index 881c3b3ed2461..933e6da7c6646 100644 --- a/Mathlib/Order/Filter/NAry.lean +++ b/Mathlib/Order/Filter/NAry.lean @@ -29,8 +29,8 @@ open Filter namespace Filter variable {α α' β β' γ γ' δ δ' ε ε' : Type*} {m : α → β → γ} {f f₁ f₂ : Filter α} - {g g₁ g₂ : Filter β} {h h₁ h₂ : Filter γ} {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {u : Set γ} - {v : Set δ} {a : α} {b : β} {c : γ} + {g g₁ g₂ : Filter β} {h : Filter γ} {s : Set α} {t : Set β} {u : Set γ} + {a : α} {b : β} /-- The image of a binary function `m : α → β → γ` as a function `Filter α → Filter β → Filter γ`. Mathematically this should be thought of as the image of the corresponding function `α × β → γ`. -/ @@ -51,7 +51,7 @@ theorem map_prod_eq_map₂ (m : α → β → γ) (f : Filter α) (g : Filter β theorem map_prod_eq_map₂' (m : α × β → γ) (f : Filter α) (g : Filter β) : Filter.map m (f ×ˢ g) = map₂ (fun a b => m (a, b)) f g := - map_prod_eq_map₂ (curry m) f g + map_prod_eq_map₂ m.curry f g @[simp] theorem map₂_mk_eq_prod (f : Filter α) (g : Filter β) : map₂ Prod.mk f g = f ×ˢ g := by @@ -60,12 +60,15 @@ theorem map₂_mk_eq_prod (f : Filter α) (g : Filter β) : map₂ Prod.mk f g = -- lemma image2_mem_map₂_iff (hm : injective2 m) : image2 m s t ∈ map₂ m f g ↔ s ∈ f ∧ t ∈ g := -- ⟨by { rintro ⟨u, v, hu, hv, h⟩, rw image2_subset_image2_iff hm at h, -- exact ⟨mem_of_superset hu h.1, mem_of_superset hv h.2⟩ }, fun h ↦ image2_mem_map₂ h.1 h.2⟩ +@[gcongr] theorem map₂_mono (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : map₂ m f₁ g₁ ≤ map₂ m f₂ g₂ := fun _ ⟨s, hs, t, ht, hst⟩ => ⟨s, hf hs, t, hg ht, hst⟩ +@[gcongr] theorem map₂_mono_left (h : g₁ ≤ g₂) : map₂ m f g₁ ≤ map₂ m f g₂ := map₂_mono Subset.rfl h +@[gcongr] theorem map₂_mono_right (h : f₁ ≤ f₂) : map₂ m f₁ g ≤ map₂ m f₂ g := map₂_mono h Subset.rfl @@ -145,7 +148,7 @@ theorem map₂_map_right (m : α → γ → δ) (n : β → γ) : @[simp] theorem map₂_curry (m : α × β → γ) (f : Filter α) (g : Filter β) : - map₂ (curry m) f g = (f ×ˢ g).map m := + map₂ m.curry f g = (f ×ˢ g).map m := (map_prod_eq_map₂' _ _ _).symm @[simp] diff --git a/Mathlib/Order/Filter/Partial.lean b/Mathlib/Order/Filter/Partial.lean index 05453a60c9e88..b09c3cd41ecad 100644 --- a/Mathlib/Order/Filter/Partial.lean +++ b/Mathlib/Order/Filter/Partial.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad -/ -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto import Mathlib.Data.PFun /-! diff --git a/Mathlib/Order/Filter/Pi.lean b/Mathlib/Order/Filter/Pi.lean index 147840d30d026..df2bc56ec23bb 100644 --- a/Mathlib/Order/Filter/Pi.lean +++ b/Mathlib/Order/Filter/Pi.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Alex Kontorovich -/ import Mathlib.Order.Filter.Bases +import Mathlib.Order.Filter.Tendsto /-! # (Co)product of a family of filters @@ -152,7 +153,7 @@ theorem pi_inf_principal_pi_neBot [∀ i, NeBot (f i)] {I : Set ι} : instance PiInfPrincipalPi.neBot [h : ∀ i, NeBot (f i ⊓ 𝓟 (s i))] {I : Set ι} : NeBot (pi f ⊓ 𝓟 (I.pi s)) := (pi_inf_principal_univ_pi_neBot.2 ‹_›).mono <| - inf_le_inf_left _ <| principal_mono.2 fun x hx i _ => hx i trivial + inf_le_inf_left _ <| principal_mono.2 fun _ hx i _ => hx i trivial @[simp] theorem pi_eq_bot : pi f = ⊥ ↔ ∃ i, f i = ⊥ := by diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index a1c46ad3a9f3f..987d9fae9f218 100644 --- a/Mathlib/Order/Filter/Pointwise.lean +++ b/Mathlib/Order/Filter/Pointwise.lean @@ -312,11 +312,11 @@ theorem le_mul_iff : h ≤ f * g ↔ ∀ ⦃s⦄, s ∈ f → ∀ ⦃t⦄, t ∈ le_map₂_iff @[to_additive] -instance covariant_mul : CovariantClass (Filter α) (Filter α) (· * ·) (· ≤ ·) := +instance mulLeftMono : MulLeftMono (Filter α) := ⟨fun _ _ _ => map₂_mono_left⟩ @[to_additive] -instance covariant_swap_mul : CovariantClass (Filter α) (Filter α) (swap (· * ·)) (· ≤ ·) := +instance mulRightMono : MulRightMono (Filter α) := ⟨fun _ _ _ => map₂_mono_right⟩ @[to_additive] @@ -612,11 +612,11 @@ protected theorem mul_eq_one_iff : f * g = 1 ↔ ∃ a b, f = pure a ∧ g = pur `α` is."] protected def divisionMonoid : DivisionMonoid (Filter α) := { Filter.monoid, Filter.instInvolutiveInv, Filter.instDiv, Filter.instZPow (α := α) with - mul_inv_rev := fun s t => map_map₂_antidistrib mul_inv_rev + mul_inv_rev := fun _ _ => map_map₂_antidistrib mul_inv_rev inv_eq_of_mul := fun s t h => by obtain ⟨a, b, rfl, rfl, hab⟩ := Filter.mul_eq_one_iff.1 h rw [inv_pure, inv_eq_of_mul_eq_one_right hab] - div_eq_mul_inv := fun f g => map_map₂_distrib_right div_eq_mul_inv } + div_eq_mul_inv := fun _ _ => map_map₂_distrib_right div_eq_mul_inv } @[to_additive] theorem isUnit_iff : IsUnit f ↔ ∃ a, f = pure a ∧ IsUnit a := by @@ -1043,7 +1043,7 @@ instance isCentralScalar [SMul α β] [SMul αᵐᵒᵖ β] [IsCentralScalar α of `Filter α` on `Filter β`"] protected def mulAction [Monoid α] [MulAction α β] : MulAction (Filter α) (Filter β) where one_smul f := map₂_pure_left.trans <| by simp_rw [one_smul, map_id'] - mul_smul f g h := map₂_assoc mul_smul + mul_smul _ _ _ := map₂_assoc mul_smul /-- A multiplicative action of a monoid on a type `β` gives a multiplicative action on `Filter β`. -/ diff --git a/Mathlib/Order/Filter/Prod.lean b/Mathlib/Order/Filter/Prod.lean index 4cf3233718cf7..5a1d1ab10faa6 100644 --- a/Mathlib/Order/Filter/Prod.lean +++ b/Mathlib/Order/Filter/Prod.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Patrick Massot, Yury Kudryashov, Kevin H. Wilson, Heather Macbeth -/ -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto /-! # Product and coproduct filters @@ -46,17 +46,6 @@ section Prod variable {s : Set α} {t : Set β} {f : Filter α} {g : Filter β} -/-- 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 - -instance instSProd : SProd (Filter α) (Filter β) (Filter (α × β)) where - sprod := Filter.prod - -theorem prod_eq_inf (f : Filter α) (g : Filter β) : f ×ˢ g = f.comap Prod.fst ⊓ g.comap Prod.snd := - rfl - theorem prod_mem_prod (hs : s ∈ f) (ht : t ∈ g) : s ×ˢ t ∈ f ×ˢ g := inter_mem_inf (preimage_mem_comap hs) (preimage_mem_comap ht) @@ -69,6 +58,10 @@ theorem mem_prod_iff {s : Set (α × β)} {f : Filter α} {g : Filter β} : · rintro ⟨t₁, ht₁, t₂, ht₂, h⟩ exact mem_inf_of_inter (preimage_mem_comap ht₁) (preimage_mem_comap ht₂) h +@[simp] +theorem compl_diagonal_mem_prod {l₁ l₂ : Filter α} : (diagonal α)ᶜ ∈ l₁ ×ˢ l₂ ↔ Disjoint l₁ l₂ := by + simp only [mem_prod_iff, Filter.disjoint_iff, prod_subset_compl_diagonal_iff_disjoint] + @[simp] theorem prod_mem_prod_iff [f.NeBot] [g.NeBot] : s ×ˢ t ∈ f ×ˢ g ↔ s ∈ f ∧ t ∈ g := ⟨fun h => @@ -436,10 +429,6 @@ section Coprod variable {f : Filter α} {g : Filter β} -/-- Coproduct of filters. -/ -protected def coprod (f : Filter α) (g : Filter β) : Filter (α × β) := - f.comap Prod.fst ⊔ g.comap Prod.snd - theorem coprod_eq_prod_top_sup_top_prod (f : Filter α) (g : Filter β) : Filter.coprod f g = f ×ˢ ⊤ ⊔ ⊤ ×ˢ g := by rw [prod_top, top_prod] diff --git a/Mathlib/Order/Filter/Ring.lean b/Mathlib/Order/Filter/Ring.lean index 3a1e434b51dd2..e6b7875f4e4ad 100644 --- a/Mathlib/Order/Filter/Ring.lean +++ b/Mathlib/Order/Filter/Ring.lean @@ -23,8 +23,8 @@ theorem EventuallyLE.mul_le_mul [MulZeroClass β] [PartialOrder β] [PosMulMono filter_upwards [hf, hg, hg₀, hf₀] with x using _root_.mul_le_mul @[to_additive EventuallyLE.add_le_add] -theorem EventuallyLE.mul_le_mul' [Mul β] [Preorder β] [CovariantClass β β (· * ·) (· ≤ ·)] - [CovariantClass β β (swap (· * ·)) (· ≤ ·)] {l : Filter α} {f₁ f₂ g₁ g₂ : α → β} +theorem EventuallyLE.mul_le_mul' [Mul β] [Preorder β] [MulLeftMono β] + [MulRightMono β] {l : Filter α} {f₁ f₂ g₁ g₂ : α → β} (hf : f₁ ≤ᶠ[l] f₂) (hg : g₁ ≤ᶠ[l] g₂) : f₁ * g₁ ≤ᶠ[l] f₂ * g₂ := by filter_upwards [hf, hg] with x hfx hgx using _root_.mul_le_mul' hfx hgx diff --git a/Mathlib/Order/Filter/SmallSets.lean b/Mathlib/Order/Filter/SmallSets.lean index fe284b82bd719..1e40a2da092eb 100644 --- a/Mathlib/Order/Filter/SmallSets.lean +++ b/Mathlib/Order/Filter/SmallSets.lean @@ -150,7 +150,7 @@ theorem eventually_smallSets_eventually {p : α → Prop} : (∀ᶠ s in l.smallSets, ∀ᶠ x in l', x ∈ s → p x) ↔ ∀ᶠ x in l ⊓ l', p x := calc _ ↔ ∃ s ∈ l, ∀ᶠ x in l', x ∈ s → p x := - eventually_smallSets' fun s t hst ht => ht.mono fun x hx hs => hx (hst hs) + eventually_smallSets' fun _ _ hst ht => ht.mono fun _ hx hs => hx (hst hs) _ ↔ ∃ s ∈ l, ∃ t ∈ l', ∀ x, x ∈ t → x ∈ s → p x := by simp only [eventually_iff_exists_mem] _ ↔ ∀ᶠ x in l ⊓ l', p x := by simp only [eventually_inf, and_comm, mem_inter_iff, ← and_imp] diff --git a/Mathlib/Order/Filter/Tendsto.lean b/Mathlib/Order/Filter/Tendsto.lean new file mode 100644 index 0000000000000..64e557baca965 --- /dev/null +++ b/Mathlib/Order/Filter/Tendsto.lean @@ -0,0 +1,304 @@ +/- +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 +-/ +import Mathlib.Order.Filter.Basic + +/-! +# Convergence in terms of filters + +The general notion of limit of a map with respect to filters on the source and target types +is `Filter.Tendsto`. It is defined in terms of the order and the push-forward operation. + +For instance, anticipating on Topology.Basic, the statement: "if a sequence `u` converges to +some `x` and `u n` belongs to a set `M` for `n` large enough then `x` is in the closure of +`M`" is formalized as: `Tendsto u atTop (𝓝 x) → (∀ᶠ n in atTop, u n ∈ M) → x ∈ closure M`, +which is a special case of `mem_closure_of_tendsto` from `Topology/Basic`. +-/ + +open Set Filter + +variable {α β γ : Type*} {ι : Sort*} + +namespace Filter + +theorem tendsto_def {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : + Tendsto f l₁ l₂ ↔ ∀ s ∈ l₂, f ⁻¹' s ∈ l₁ := + Iff.rfl + +theorem tendsto_iff_eventually {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : + Tendsto f l₁ l₂ ↔ ∀ ⦃p : β → Prop⦄, (∀ᶠ y in l₂, p y) → ∀ᶠ x in l₁, p (f x) := + Iff.rfl + +theorem tendsto_iff_forall_eventually_mem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : + Tendsto f l₁ l₂ ↔ ∀ s ∈ l₂, ∀ᶠ x in l₁, f x ∈ s := + Iff.rfl + +lemma Tendsto.eventually_mem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {s : Set β} + (hf : Tendsto f l₁ l₂) (h : s ∈ l₂) : ∀ᶠ x in l₁, f x ∈ s := + hf h + +theorem Tendsto.eventually {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {p : β → Prop} + (hf : Tendsto f l₁ l₂) (h : ∀ᶠ y in l₂, p y) : ∀ᶠ x in l₁, p (f x) := + hf h + +theorem not_tendsto_iff_exists_frequently_nmem {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : + ¬Tendsto f l₁ l₂ ↔ ∃ s ∈ l₂, ∃ᶠ x in l₁, f x ∉ s := by + simp only [tendsto_iff_forall_eventually_mem, not_forall, exists_prop, not_eventually] + +theorem Tendsto.frequently {f : α → β} {l₁ : Filter α} {l₂ : Filter β} {p : β → Prop} + (hf : Tendsto f l₁ l₂) (h : ∃ᶠ x in l₁, p (f x)) : ∃ᶠ y in l₂, p y := + mt hf.eventually h + +theorem Tendsto.frequently_map {l₁ : Filter α} {l₂ : Filter β} {p : α → Prop} {q : β → Prop} + (f : α → β) (c : Filter.Tendsto f l₁ l₂) (w : ∀ x, p x → q (f x)) (h : ∃ᶠ x in l₁, p x) : + ∃ᶠ y in l₂, q y := + c.frequently (h.mono w) + +@[simp] +theorem tendsto_bot {f : α → β} {l : Filter β} : Tendsto f ⊥ l := by simp [Tendsto] + +theorem Tendsto.of_neBot_imp {f : α → β} {la : Filter α} {lb : Filter β} + (h : NeBot la → Tendsto f la lb) : Tendsto f la lb := by + rcases eq_or_neBot la with rfl | hla + · exact tendsto_bot + · exact h hla + +@[simp] theorem tendsto_top {f : α → β} {l : Filter α} : Tendsto f l ⊤ := le_top + +theorem le_map_of_right_inverse {mab : α → β} {mba : β → α} {f : Filter α} {g : Filter β} + (h₁ : mab ∘ mba =ᶠ[g] id) (h₂ : Tendsto mba g f) : g ≤ map mab f := by + rw [← @map_id _ g, ← map_congr h₁, ← map_map] + exact map_mono h₂ + +theorem tendsto_of_isEmpty [IsEmpty α] {f : α → β} {la : Filter α} {lb : Filter β} : + Tendsto f la lb := by simp only [filter_eq_bot_of_isEmpty la, tendsto_bot] + +theorem eventuallyEq_of_left_inv_of_right_inv {f : α → β} {g₁ g₂ : β → α} {fa : Filter α} + {fb : Filter β} (hleft : ∀ᶠ x in fa, g₁ (f x) = x) (hright : ∀ᶠ y in fb, f (g₂ y) = y) + (htendsto : Tendsto g₂ fb fa) : g₁ =ᶠ[fb] g₂ := + (htendsto.eventually hleft).mp <| hright.mono fun _ hr hl => (congr_arg g₁ hr.symm).trans hl + +theorem tendsto_iff_comap {f : α → β} {l₁ : Filter α} {l₂ : Filter β} : + Tendsto f l₁ l₂ ↔ l₁ ≤ l₂.comap f := + map_le_iff_le_comap + +alias ⟨Tendsto.le_comap, _⟩ := tendsto_iff_comap + +protected theorem Tendsto.disjoint {f : α → β} {la₁ la₂ : Filter α} {lb₁ lb₂ : Filter β} + (h₁ : Tendsto f la₁ lb₁) (hd : Disjoint lb₁ lb₂) (h₂ : Tendsto f la₂ lb₂) : Disjoint la₁ la₂ := + (disjoint_comap hd).mono h₁.le_comap h₂.le_comap + +theorem tendsto_congr' {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (hl : f₁ =ᶠ[l₁] f₂) : + Tendsto f₁ l₁ l₂ ↔ Tendsto f₂ l₁ l₂ := by rw [Tendsto, Tendsto, map_congr hl] + +theorem Tendsto.congr' {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (hl : f₁ =ᶠ[l₁] f₂) + (h : Tendsto f₁ l₁ l₂) : Tendsto f₂ l₁ l₂ := + (tendsto_congr' hl).1 h + +theorem tendsto_congr {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (h : ∀ x, f₁ x = f₂ x) : + Tendsto f₁ l₁ l₂ ↔ Tendsto f₂ l₁ l₂ := + tendsto_congr' (univ_mem' h) + +theorem Tendsto.congr {f₁ f₂ : α → β} {l₁ : Filter α} {l₂ : Filter β} (h : ∀ x, f₁ x = f₂ x) : + Tendsto f₁ l₁ l₂ → Tendsto f₂ l₁ l₂ := + (tendsto_congr h).1 + +theorem tendsto_id' {x y : Filter α} : Tendsto id x y ↔ x ≤ y := + Iff.rfl + +theorem tendsto_id {x : Filter α} : Tendsto id x x := + le_refl x + +theorem Tendsto.comp {f : α → β} {g : β → γ} {x : Filter α} {y : Filter β} {z : Filter γ} + (hg : Tendsto g y z) (hf : Tendsto f x y) : Tendsto (g ∘ f) x z := fun _ hs => hf (hg hs) + +protected theorem Tendsto.iterate {f : α → α} {l : Filter α} (h : Tendsto f l l) : + ∀ n, Tendsto (f^[n]) l l + | 0 => tendsto_id + | (n + 1) => (h.iterate n).comp h + +theorem Tendsto.mono_left {f : α → β} {x y : Filter α} {z : Filter β} (hx : Tendsto f x z) + (h : y ≤ x) : Tendsto f y z := + (map_mono h).trans hx + +theorem Tendsto.mono_right {f : α → β} {x : Filter α} {y z : Filter β} (hy : Tendsto f x y) + (hz : y ≤ z) : Tendsto f x z := + le_trans hy hz + +theorem Tendsto.neBot {f : α → β} {x : Filter α} {y : Filter β} (h : Tendsto f x y) [hx : NeBot x] : + NeBot y := + (hx.map _).mono h + +theorem tendsto_map {f : α → β} {x : Filter α} : Tendsto f x (map f x) := + le_refl (map f x) + +@[simp] +theorem tendsto_map'_iff {f : β → γ} {g : α → β} {x : Filter α} {y : Filter γ} : + Tendsto f (map g x) y ↔ Tendsto (f ∘ g) x y := by + rw [Tendsto, Tendsto, map_map] + +alias ⟨_, tendsto_map'⟩ := tendsto_map'_iff + +theorem tendsto_comap {f : α → β} {x : Filter β} : Tendsto f (comap f x) x := + map_comap_le + +@[simp] +theorem tendsto_comap_iff {f : α → β} {g : β → γ} {a : Filter α} {c : Filter γ} : + Tendsto f a (c.comap g) ↔ Tendsto (g ∘ f) a c := + ⟨fun h => tendsto_comap.comp h, fun h => map_le_iff_le_comap.mp <| by rwa [map_map]⟩ + +theorem tendsto_comap'_iff {m : α → β} {f : Filter α} {g : Filter β} {i : γ → α} (h : range i ∈ f) : + Tendsto (m ∘ i) (comap i f) g ↔ Tendsto m f g := by + rw [Tendsto, ← map_compose] + simp only [(· ∘ ·), map_comap_of_mem h, Tendsto] + +theorem Tendsto.of_tendsto_comp {f : α → β} {g : β → γ} {a : Filter α} {b : Filter β} {c : Filter γ} + (hfg : Tendsto (g ∘ f) a c) (hg : comap g c ≤ b) : Tendsto f a b := by + rw [tendsto_iff_comap] at hfg ⊢ + calc + a ≤ comap (g ∘ f) c := hfg + _ ≤ comap f b := by simpa [comap_comap] using comap_mono hg + +theorem comap_eq_of_inverse {f : Filter α} {g : Filter β} {φ : α → β} (ψ : β → α) (eq : ψ ∘ φ = id) + (hφ : Tendsto φ f g) (hψ : Tendsto ψ g f) : comap φ g = f := by + refine ((comap_mono <| map_le_iff_le_comap.1 hψ).trans ?_).antisymm (map_le_iff_le_comap.1 hφ) + rw [comap_comap, eq, comap_id] + +theorem map_eq_of_inverse {f : Filter α} {g : Filter β} {φ : α → β} (ψ : β → α) (eq : φ ∘ ψ = id) + (hφ : Tendsto φ f g) (hψ : Tendsto ψ g f) : map φ f = g := by + refine le_antisymm hφ (le_trans ?_ (map_mono hψ)) + rw [map_map, eq, map_id] + +theorem tendsto_inf {f : α → β} {x : Filter α} {y₁ y₂ : Filter β} : + Tendsto f x (y₁ ⊓ y₂) ↔ Tendsto f x y₁ ∧ Tendsto f x y₂ := by + simp only [Tendsto, le_inf_iff] + +theorem tendsto_inf_left {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} (h : Tendsto f x₁ y) : + Tendsto f (x₁ ⊓ x₂) y := + le_trans (map_mono inf_le_left) h + +theorem tendsto_inf_right {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} (h : Tendsto f x₂ y) : + Tendsto f (x₁ ⊓ x₂) y := + le_trans (map_mono inf_le_right) h + +theorem Tendsto.inf {f : α → β} {x₁ x₂ : Filter α} {y₁ y₂ : Filter β} (h₁ : Tendsto f x₁ y₁) + (h₂ : Tendsto f x₂ y₂) : Tendsto f (x₁ ⊓ x₂) (y₁ ⊓ y₂) := + tendsto_inf.2 ⟨tendsto_inf_left h₁, tendsto_inf_right h₂⟩ + +@[simp] +theorem tendsto_iInf {f : α → β} {x : Filter α} {y : ι → Filter β} : + Tendsto f x (⨅ i, y i) ↔ ∀ i, Tendsto f x (y i) := by + simp only [Tendsto, le_iInf_iff] + +theorem tendsto_iInf' {f : α → β} {x : ι → Filter α} {y : Filter β} (i : ι) + (hi : Tendsto f (x i) y) : Tendsto f (⨅ i, x i) y := + hi.mono_left <| iInf_le _ _ + +theorem tendsto_iInf_iInf {f : α → β} {x : ι → Filter α} {y : ι → Filter β} + (h : ∀ i, Tendsto f (x i) (y i)) : Tendsto f (iInf x) (iInf y) := + tendsto_iInf.2 fun i => tendsto_iInf' i (h i) + +@[simp] +theorem tendsto_sup {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} : + Tendsto f (x₁ ⊔ x₂) y ↔ Tendsto f x₁ y ∧ Tendsto f x₂ y := by + simp only [Tendsto, map_sup, sup_le_iff] + +theorem Tendsto.sup {f : α → β} {x₁ x₂ : Filter α} {y : Filter β} : + Tendsto f x₁ y → Tendsto f x₂ y → Tendsto f (x₁ ⊔ x₂) y := fun h₁ h₂ => tendsto_sup.mpr ⟨h₁, h₂⟩ + +theorem Tendsto.sup_sup {f : α → β} {x₁ x₂ : Filter α} {y₁ y₂ : Filter β} + (h₁ : Tendsto f x₁ y₁) (h₂ : Tendsto f x₂ y₂) : Tendsto f (x₁ ⊔ x₂) (y₁ ⊔ y₂) := + tendsto_sup.mpr ⟨h₁.mono_right le_sup_left, h₂.mono_right le_sup_right⟩ + +@[simp] +theorem tendsto_iSup {f : α → β} {x : ι → Filter α} {y : Filter β} : + Tendsto f (⨆ i, x i) y ↔ ∀ i, Tendsto f (x i) y := by simp only [Tendsto, map_iSup, iSup_le_iff] + +theorem tendsto_iSup_iSup {f : α → β} {x : ι → Filter α} {y : ι → Filter β} + (h : ∀ i, Tendsto f (x i) (y i)) : Tendsto f (iSup x) (iSup y) := + tendsto_iSup.2 fun i => (h i).mono_right <| le_iSup _ _ + +@[simp] theorem tendsto_principal {f : α → β} {l : Filter α} {s : Set β} : + Tendsto f l (𝓟 s) ↔ ∀ᶠ a in l, f a ∈ s := by + simp only [Tendsto, le_principal_iff, mem_map', Filter.Eventually] + +-- Porting note: was a `simp` lemma +theorem tendsto_principal_principal {f : α → β} {s : Set α} {t : Set β} : + Tendsto f (𝓟 s) (𝓟 t) ↔ ∀ a ∈ s, f a ∈ t := by + simp only [tendsto_principal, eventually_principal] + +@[simp] theorem tendsto_pure {f : α → β} {a : Filter α} {b : β} : + Tendsto f a (pure b) ↔ ∀ᶠ x in a, f x = b := by + simp only [Tendsto, le_pure_iff, mem_map', mem_singleton_iff, Filter.Eventually] + +theorem tendsto_pure_pure (f : α → β) (a : α) : Tendsto f (pure a) (pure (f a)) := + tendsto_pure.2 rfl + +theorem tendsto_const_pure {a : Filter α} {b : β} : Tendsto (fun _ => b) a (pure b) := + tendsto_pure.2 <| univ_mem' fun _ => rfl + +theorem pure_le_iff {a : α} {l : Filter α} : pure a ≤ l ↔ ∀ s ∈ l, a ∈ s := + Iff.rfl + +theorem tendsto_pure_left {f : α → β} {a : α} {l : Filter β} : + Tendsto f (pure a) l ↔ ∀ s ∈ l, f a ∈ s := + Iff.rfl + +@[simp] +theorem map_inf_principal_preimage {f : α → β} {s : Set β} {l : Filter α} : + map f (l ⊓ 𝓟 (f ⁻¹' s)) = map f l ⊓ 𝓟 s := + Filter.ext fun t => by simp only [mem_map', mem_inf_principal, mem_setOf_eq, mem_preimage] + +/-- If two filters are disjoint, then a function cannot tend to both of them along a non-trivial +filter. -/ +theorem Tendsto.not_tendsto {f : α → β} {a : Filter α} {b₁ b₂ : Filter β} (hf : Tendsto f a b₁) + [NeBot a] (hb : Disjoint b₁ b₂) : ¬Tendsto f a b₂ := fun hf' => + (tendsto_inf.2 ⟨hf, hf'⟩).neBot.ne hb.eq_bot + +protected theorem Tendsto.if {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} {p : α → Prop} + [∀ x, Decidable (p x)] (h₀ : Tendsto f (l₁ ⊓ 𝓟 { x | p x }) l₂) + (h₁ : Tendsto g (l₁ ⊓ 𝓟 { x | ¬p x }) l₂) : + Tendsto (fun x => if p x then f x else g x) l₁ l₂ := by + simp only [tendsto_def, mem_inf_principal] at * + intro s hs + filter_upwards [h₀ s hs, h₁ s hs] with x hp₀ hp₁ + rw [mem_preimage] + split_ifs with h + exacts [hp₀ h, hp₁ h] + +protected theorem Tendsto.if' {α β : Type*} {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} + {p : α → Prop} [DecidablePred p] (hf : Tendsto f l₁ l₂) (hg : Tendsto g l₁ l₂) : + Tendsto (fun a => if p a then f a else g a) l₁ l₂ := + (tendsto_inf_left hf).if (tendsto_inf_left hg) + +protected theorem Tendsto.piecewise {l₁ : Filter α} {l₂ : Filter β} {f g : α → β} {s : Set α} + [∀ x, Decidable (x ∈ s)] (h₀ : Tendsto f (l₁ ⊓ 𝓟 s) l₂) (h₁ : Tendsto g (l₁ ⊓ 𝓟 sᶜ) l₂) : + Tendsto (piecewise s f g) l₁ l₂ := + Tendsto.if h₀ h₁ + +end Filter + +theorem Set.MapsTo.tendsto {s : Set α} {t : Set β} {f : α → β} (h : MapsTo f s t) : + Filter.Tendsto f (𝓟 s) (𝓟 t) := + Filter.tendsto_principal_principal.2 h + +theorem Filter.EventuallyEq.comp_tendsto {l : Filter α} {f : α → β} {f' : α → β} + (H : f =ᶠ[l] f') {g : γ → α} {lc : Filter γ} (hg : Tendsto g lc l) : + f ∘ g =ᶠ[lc] f' ∘ g := + hg.eventually H + +variable {F : Filter α} {G : Filter β} + +theorem Filter.map_mapsTo_Iic_iff_tendsto {m : α → β} : + MapsTo (map m) (Iic F) (Iic G) ↔ Tendsto m F G := + ⟨fun hm ↦ hm right_mem_Iic, fun hm _ ↦ hm.mono_left⟩ + +alias ⟨_, Filter.Tendsto.map_mapsTo_Iic⟩ := Filter.map_mapsTo_Iic_iff_tendsto + +theorem Filter.map_mapsTo_Iic_iff_mapsTo {s : Set α} {t : Set β} {m : α → β} : + MapsTo (map m) (Iic <| 𝓟 s) (Iic <| 𝓟 t) ↔ MapsTo m s t := by + rw [map_mapsTo_Iic_iff_tendsto, tendsto_principal_principal, MapsTo] + +alias ⟨_, Set.MapsTo.filter_map_Iic⟩ := Filter.map_mapsTo_Iic_iff_mapsTo diff --git a/Mathlib/Order/Filter/Ultrafilter.lean b/Mathlib/Order/Filter/Ultrafilter.lean index 6f238409f1d35..e480d43fb294c 100644 --- a/Mathlib/Order/Filter/Ultrafilter.lean +++ b/Mathlib/Order/Filter/Ultrafilter.lean @@ -119,7 +119,7 @@ theorem diff_mem_iff (f : Ultrafilter α) : s \ t ∈ f ↔ s ∈ f ∧ t ∉ f def ofComplNotMemIff (f : Filter α) (h : ∀ s, sᶜ ∉ f ↔ s ∈ f) : Ultrafilter α where toFilter := f neBot' := ⟨fun hf => by simp [hf] at h⟩ - le_of_le g hg hgf s hs := (h s).1 fun hsc => compl_not_mem hs (hgf hsc) + le_of_le _ _ hgf s hs := (h s).1 fun hsc => compl_not_mem hs (hgf hsc) /-- If `f : Filter α` is an atom, then it is an ultrafilter. -/ def ofAtom (f : Filter α) (hf : IsAtom f) : Ultrafilter α where diff --git a/Mathlib/Order/GaloisConnection.lean b/Mathlib/Order/GaloisConnection.lean index 95ba690deb3fb..5995f271ba962 100644 --- a/Mathlib/Order/GaloisConnection.lean +++ b/Mathlib/Order/GaloisConnection.lean @@ -6,7 +6,7 @@ Authors: Johannes Hölzl import Mathlib.Order.CompleteLattice import Mathlib.Order.Synonym import Mathlib.Order.Hom.Set -import Mathlib.Order.Bounds.Basic +import Mathlib.Order.Bounds.Image /-! # Galois connections, insertions and coinsertions @@ -50,8 +50,8 @@ open Function OrderDual Set universe u v w x -variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} {κ : ι → Sort*} {a a₁ a₂ : α} - {b b₁ b₂ : β} +variable {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} {κ : ι → Sort*} {a₁ a₂ : α} + {b₁ b₂ : β} /-- A Galois connection is a pair of functions `l` and `u` satisfying `l a ≤ b ↔ a ≤ u b`. They are special cases of adjoint functors in category theory, @@ -337,7 +337,7 @@ theorem gc_Ici_sInf [CompleteSemilatticeInf α] : GaloisConnection (toDual ∘ Ici : α → (Set α)ᵒᵈ) (sInf ∘ ofDual : (Set α)ᵒᵈ → α) := fun _ _ ↦ le_sInf_iff.symm -variable [CompleteLattice α] [CompleteLattice β] [CompleteLattice γ] {f : α → β → γ} {s : Set α} +variable [CompleteLattice α] [CompleteLattice β] [CompleteLattice γ] {s : Set α} {t : Set β} {l u : α → β → γ} {l₁ u₁ : β → γ → α} {l₂ u₂ : α → γ → β} theorem sSup_image2_eq_sSup_sSup (h₁ : ∀ b, GaloisConnection (swap l b) (u₁ b)) @@ -551,7 +551,7 @@ abbrev liftSemilatticeSup [SemilatticeSup α] (gi : GaloisInsertion l u) : Semil sup := fun a b => l (u a ⊔ u b) le_sup_left := fun a _ => (gi.le_l_u a).trans <| gi.gc.monotone_l <| le_sup_left le_sup_right := fun _ b => (gi.le_l_u b).trans <| gi.gc.monotone_l <| le_sup_right - sup_le := fun a b c hac hbc => + sup_le := fun _ _ _ hac hbc => gi.gc.l_le <| sup_le (gi.gc.monotone_u hac) (gi.gc.monotone_u hbc) } -- See note [reducible non instances] @@ -593,8 +593,8 @@ abbrev liftBoundedOrder [Preorder α] [BoundedOrder α] (gi : GaloisInsertion l abbrev liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β := { gi.liftBoundedOrder, gi.liftLattice with sSup := fun s => l (sSup (u '' s)) - sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2 - le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1 + sSup_le := fun _ => (gi.isLUB_of_u_image (isLUB_sSup _)).2 + le_sSup := fun _ => (gi.isLUB_of_u_image (isLUB_sSup _)).1 sInf := fun s => gi.choice (sInf (u '' s)) <| (isGLB_sInf _).2 <| diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index 913803105f8c0..392c6569e8911 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -183,7 +183,7 @@ abbrev HeytingAlgebra.ofHImp [DistribLattice α] [BoundedOrder α] (himp : α himp, compl := fun a => himp a ⊥, le_himp_iff, - himp_bot := fun a => rfl } + himp_bot := fun _ => rfl } -- See note [reducible non-instances] /-- Construct a Heyting algebra from the lattice structure and complement operator alone. -/ @@ -202,7 +202,7 @@ abbrev CoheytingAlgebra.ofSDiff [DistribLattice α] [BoundedOrder α] (sdiff : sdiff, hnot := fun a => sdiff ⊤ a, sdiff_le_iff, - top_sdiff := fun a => rfl } + top_sdiff := fun _ => rfl } -- See note [reducible non-instances] /-- Construct a co-Heyting algebra from the difference and Heyting negation alone. -/ @@ -589,7 +589,7 @@ end GeneralizedCoheytingAlgebra section HeytingAlgebra -variable [HeytingAlgebra α] {a b c : α} +variable [HeytingAlgebra α] {a b : α} @[simp] theorem himp_bot (a : α) : a ⇨ ⊥ = aᶜ := @@ -760,7 +760,7 @@ end HeytingAlgebra section CoheytingAlgebra -variable [CoheytingAlgebra α] {a b c : α} +variable [CoheytingAlgebra α] {a b : α} @[simp] theorem top_sdiff' (a : α) : ⊤ \ a = ¬a := @@ -943,14 +943,14 @@ abbrev LinearOrder.toBiheytingAlgebra [LinearOrder α] [BoundedOrder α] : Bihey split_ifs with h · exact iff_of_true le_top (inf_le_of_right_le h) · rw [inf_le_iff, or_iff_left h], - himp_bot := fun a => if_congr le_bot_iff rfl rfl, sdiff := fun a b => if a ≤ b then ⊥ else a, + himp_bot := fun _ => if_congr le_bot_iff rfl rfl, sdiff := fun a b => if a ≤ b then ⊥ else a, hnot := fun a => if a = ⊤ then ⊥ else ⊤, sdiff_le_iff := fun a b c => by change ite _ _ _ ≤ _ ↔ _ split_ifs with h · exact iff_of_true bot_le (le_sup_of_le_left h) · rw [le_sup_iff, or_iff_right h], - top_sdiff := fun a => if_congr top_le_iff rfl rfl } + top_sdiff := fun _ => if_congr top_le_iff rfl rfl } instance OrderDual.instBiheytingAlgebra [BiheytingAlgebra α] : BiheytingAlgebra αᵒᵈ where __ := instHeytingAlgebra @@ -983,7 +983,7 @@ protected abbrev Function.Injective.generalizedHeytingAlgebra [Sup α] [Inf α] exact le_top, le_himp_iff := fun a b c => by change f _ ≤ _ ↔ f _ ≤ _ - erw [map_himp, map_inf, le_himp_iff] } + rw [map_himp, map_inf, le_himp_iff] } -- See note [reducible non-instances] /-- Pullback a `GeneralizedCoheytingAlgebra` along an injection. -/ @@ -1001,7 +1001,7 @@ protected abbrev Function.Injective.generalizedCoheytingAlgebra [Sup α] [Inf α exact bot_le, sdiff_le_iff := fun a b c => by change f _ ≤ _ ↔ f _ ≤ _ - erw [map_sdiff, map_sup, sdiff_le_iff] } + rw [map_sdiff, map_sup, sdiff_le_iff] } -- See note [reducible non-instances] /-- Pullback a `HeytingAlgebra` along an injection. -/ @@ -1017,7 +1017,7 @@ protected abbrev Function.Injective.heytingAlgebra [Sup α] [Inf α] [Top α] [B change f _ ≤ _ rw [map_bot] exact bot_le, - himp_bot := fun a => hf <| by erw [map_himp, map_compl, map_bot, himp_bot] } + himp_bot := fun a => hf <| by rw [map_himp, map_compl, map_bot, himp_bot] } -- See note [reducible non-instances] /-- Pullback a `CoheytingAlgebra` along an injection. -/ @@ -1033,7 +1033,7 @@ protected abbrev Function.Injective.coheytingAlgebra [Sup α] [Inf α] [Top α] change f _ ≤ _ rw [map_top] exact le_top, - top_sdiff := fun a => hf <| by erw [map_sdiff, map_hnot, map_top, top_sdiff'] } + top_sdiff := fun a => hf <| by rw [map_sdiff, map_hnot, map_top, top_sdiff'] } -- See note [reducible non-instances] /-- Pullback a `BiheytingAlgebra` along an injection. -/ diff --git a/Mathlib/Order/Heyting/Hom.lean b/Mathlib/Order/Heyting/Hom.lean index 6b0940817f6d3..6a1e4f16688ce 100644 --- a/Mathlib/Order/Heyting/Hom.lean +++ b/Mathlib/Order/Heyting/Hom.lean @@ -99,8 +99,8 @@ section Hom variable [FunLike F α β] -/- Porting note: `[HeytingAlgebra α, β]` -> `{ _ : HeytingAlgebra α, β}` as a dangerous instance fix -similar for Coheyting & Biheyting instances -/ +/-! This section passes in some instances implicitly. See note [implicit instance arguments] -/ + -- See note [lower instance priority] instance (priority := 100) HeytingHomClass.toBoundedLatticeHomClass [HeytingAlgebra α] { _ : HeytingAlgebra β} [HeytingHomClass F α β] : BoundedLatticeHomClass F α β := @@ -246,13 +246,6 @@ instance instHeytingHomClass : HeytingHomClass (HeytingHom α β) α β where map_bot f := f.map_bot' map_himp := HeytingHom.map_himp' - --- Porting note: CoeFun undesired here in lean 4 --- /-- Helper instance for when there's too many metavariables to apply `DFunLike.CoeFun` --- directly. -/ --- instance : CoeFun (HeytingHom α β) fun _ => α → β := --- DFunLike.hasCoeToFun - -- @[simp] -- Porting note: not in simp-nf, simp can simplify lhs. Added aux simp lemma theorem toFun_eq_coe {f : HeytingHom α β} : f.toFun = ⇑f := rfl diff --git a/Mathlib/Order/Heyting/Regular.lean b/Mathlib/Order/Heyting/Regular.lean index ed41e246a1c47..6b8a0c8a59808 100644 --- a/Mathlib/Order/Heyting/Regular.lean +++ b/Mathlib/Order/Heyting/Regular.lean @@ -76,13 +76,13 @@ protected theorem IsRegular.disjoint_compl_right_iff (hb : IsRegular b) : abbrev _root_.BooleanAlgebra.ofRegular (h : ∀ a : α, IsRegular (a ⊔ aᶜ)) : BooleanAlgebra α := have : ∀ a : α, IsCompl a aᶜ := fun a => ⟨disjoint_compl_right, - codisjoint_iff.2 <| by erw [← (h a), compl_sup, inf_compl_eq_bot, compl_bot]⟩ + codisjoint_iff.2 <| by rw [← (h a), compl_sup, inf_compl_eq_bot, compl_bot]⟩ { ‹HeytingAlgebra α›, GeneralizedHeytingAlgebra.toDistribLattice with - himp_eq := fun a b => + himp_eq := fun _ _ => eq_of_forall_le_iff fun _ => le_himp_iff.trans (this _).le_sup_right_iff_inf_left_le.symm - inf_compl_le_bot := fun a => (this _).1.le_bot - top_le_sup_compl := fun a => (this _).2.top_le } + inf_compl_le_bot := fun _ => (this _).1.le_bot + top_le_sup_compl := fun _ => (this _).2.top_le } variable (α) @@ -198,7 +198,7 @@ instance : BooleanAlgebra (Regular α) := coe_le_coe.1 <| by dsimp rw [sup_inf_left, compl_compl_inf_distrib] - inf_compl_le_bot := fun a => coe_le_coe.1 <| disjoint_iff_inf_le.1 disjoint_compl_right + inf_compl_le_bot := fun _ => coe_le_coe.1 <| disjoint_iff_inf_le.1 disjoint_compl_right top_le_sup_compl := fun a => coe_le_coe.1 <| by dsimp diff --git a/Mathlib/Order/Hom/Basic.lean b/Mathlib/Order/Hom/Basic.lean index 356b8c434a945..038a9e1b51ebd 100644 --- a/Mathlib/Order/Hom/Basic.lean +++ b/Mathlib/Order/Hom/Basic.lean @@ -148,6 +148,9 @@ protected theorem monotone (f : F) : Monotone f := fun _ _ => map_rel f protected theorem mono (f : F) : Monotone f := fun _ _ => map_rel f +@[gcongr] protected lemma GCongr.mono (f : F) {a b : α} (hab : a ≤ b) : f a ≤ f b := + OrderHomClass.mono f hab + /-- Turn an element of a type `F` satisfying `OrderHomClass F α β` into an actual `OrderHom`. This is declared as the default coercion from `F` to `α →o β`. -/ @[coe] @@ -752,8 +755,6 @@ protected theorem injective (e : α ≃o β) : Function.Injective e := protected theorem surjective (e : α ≃o β) : Function.Surjective e := e.toEquiv.surjective --- Porting note (#10618): simp can prove this --- @[simp] theorem apply_eq_iff_eq (e : α ≃o β) {x y : α} : e x = e y ↔ x = y := e.toEquiv.apply_eq_iff_eq @@ -915,12 +916,13 @@ open Set section LE -variable [LE α] [LE β] [LE γ] +variable [LE α] [LE β] ---@[simp] Porting note (#10618): simp can prove it theorem le_iff_le (e : α ≃o β) {x y : α} : e x ≤ e y ↔ x ≤ y := e.map_rel_iff +@[gcongr] protected alias ⟨_, GCongr.orderIso_apply_le_apply⟩ := le_iff_le + theorem le_symm_apply (e : α ≃o β) {x : α} {y : β} : x ≤ e.symm y ↔ e x ≤ y := e.rel_symm_apply @@ -929,7 +931,7 @@ theorem symm_apply_le (e : α ≃o β) {x : α} {y : β} : e.symm y ≤ x ↔ y end LE -variable [Preorder α] [Preorder β] [Preorder γ] +variable [Preorder α] [Preorder β] protected theorem monotone (e : α ≃o β) : Monotone e := e.toOrderEmbedding.monotone @@ -941,6 +943,8 @@ protected theorem strictMono (e : α ≃o β) : StrictMono e := theorem lt_iff_lt (e : α ≃o β) {x y : α} : e x < e y ↔ x < y := e.toOrderEmbedding.lt_iff_lt +@[gcongr] protected alias ⟨_, GCongr.orderIso_apply_lt_apply⟩ := lt_iff_lt + /-- Converts an `OrderIso` into a `RelIso (<) (<)`. -/ def toRelIsoLT (e : α ≃o β) : ((· < ·) : α → α → Prop) ≃r ((· < ·) : β → β → Prop) := ⟨e.toEquiv, lt_iff_lt e⟩ @@ -1053,7 +1057,7 @@ end Equiv namespace StrictMono variable [LinearOrder α] [Preorder β] -variable (f : α → β) (h_mono : StrictMono f) (h_surj : Function.Surjective f) +variable (f : α → β) (h_mono : StrictMono f) /-- A strictly monotone function with a right inverse is an order isomorphism. -/ @[simps (config := .asFn)] diff --git a/Mathlib/Order/Hom/CompleteLattice.lean b/Mathlib/Order/Hom/CompleteLattice.lean index 8fecfd2875b9b..125753699728c 100644 --- a/Mathlib/Order/Hom/CompleteLattice.lean +++ b/Mathlib/Order/Hom/CompleteLattice.lean @@ -592,12 +592,6 @@ def tosSupHom (f : CompleteLatticeHom α β) : sSupHom α β := def toBoundedLatticeHom (f : CompleteLatticeHom α β) : BoundedLatticeHom α β := f --- Porting note: We do not want CoeFun for this in lean 4 --- /-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_toFun` --- directly. -/ --- instance : CoeFun (CompleteLatticeHom α β) fun _ => α → β := --- DFunLike.hasCoeToFun - lemma toFun_eq_coe (f : CompleteLatticeHom α β) : f.toFun = f := rfl @[simp] lemma coe_tosInfHom (f : CompleteLatticeHom α β) : ⇑f.tosInfHom = f := rfl diff --git a/Mathlib/Order/Hom/Lattice.lean b/Mathlib/Order/Hom/Lattice.lean index 94af3f7566504..4179afdc3722b 100644 --- a/Mathlib/Order/Hom/Lattice.lean +++ b/Mathlib/Order/Hom/Lattice.lean @@ -1567,7 +1567,6 @@ theorem withTop_id : (SupHom.id α).withTop = SupHom.id _ := DFunLike.coe_inject @[simp] theorem withTop_comp (f : SupHom β γ) (g : SupHom α β) : (f.comp g).withTop = f.withTop.comp g.withTop := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊥` to the domain and codomain of a `SupHom`. -/ @@ -1588,7 +1587,6 @@ theorem withBot_id : (SupHom.id α).withBot = SupBotHom.id _ := DFunLike.coe_inj @[simp] theorem withBot_comp (f : SupHom β γ) (g : SupHom α β) : (f.comp g).withBot = f.withBot.comp g.withBot := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊤` to the codomain of a `SupHom`. -/ @@ -1638,7 +1636,6 @@ theorem withTop_id : (InfHom.id α).withTop = InfTopHom.id _ := DFunLike.coe_inj @[simp] theorem withTop_comp (f : InfHom β γ) (g : InfHom α β) : (f.comp g).withTop = f.withTop.comp g.withTop := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊥` to the domain and codomain of an `InfHom`. -/ @@ -1658,7 +1655,6 @@ theorem withBot_id : (InfHom.id α).withBot = InfHom.id _ := DFunLike.coe_inject @[simp] theorem withBot_comp (f : InfHom β γ) (g : InfHom α β) : (f.comp g).withBot = f.withBot.comp g.withBot := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊤` to the codomain of an `InfHom`. -/ @@ -1708,7 +1704,6 @@ theorem withTop_id : (LatticeHom.id α).withTop = LatticeHom.id _ := @[simp] theorem withTop_comp (f : LatticeHom β γ) (g : LatticeHom α β) : (f.comp g).withTop = f.withTop.comp g.withTop := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊥` to the domain and codomain of a `LatticeHom`. -/ @@ -1729,7 +1724,6 @@ theorem withBot_id : (LatticeHom.id α).withBot = LatticeHom.id _ := @[simp] theorem withBot_comp (f : LatticeHom β γ) (g : LatticeHom α β) : (f.comp g).withBot = f.withBot.comp g.withBot := --- Porting note: Proof was `DFunLike.coe_injective (Option.map_comp_map _ _).symm` DFunLike.coe_injective <| Eq.symm <| Option.map_comp_map _ _ /-- Adjoins a `⊤` and `⊥` to the domain and codomain of a `LatticeHom`. -/ diff --git a/Mathlib/Order/Hom/Order.lean b/Mathlib/Order/Hom/Order.lean index c2db9e632bb02..a1bc51bc10dd5 100644 --- a/Mathlib/Order/Hom/Order.lean +++ b/Mathlib/Order/Hom/Order.lean @@ -116,10 +116,10 @@ instance [CompleteLattice β] : CompleteLattice (α →o β) := -- sSup := SupSet.sSup -- Porting note: removed, unnecessary? -- Porting note: Added `by apply`, was `fun s f hf x => le_iSup_of_le f (le_iSup _ hf)` le_sSup := fun s f hf x => le_iSup_of_le f (by apply le_iSup _ hf) - sSup_le := fun s f hf x => iSup₂_le fun g hg => hf g hg x + sSup_le := fun _ _ hf x => iSup₂_le fun g hg => hf g hg x --inf := sInf -- Porting note: removed, unnecessary? - le_sInf := fun s f hf x => le_iInf₂ fun g hg => hf g hg x - sInf_le := fun s f hf x => iInf_le_of_le f (iInf_le _ hf) + le_sInf := fun _ _ hf x => le_iInf₂ fun g hg => hf g hg x + sInf_le := fun _ f hf _ => iInf_le_of_le f (iInf_le _ hf) } theorem iterate_sup_le_sup_iff {α : Type*} [SemilatticeSup α] (f : α →o α) : diff --git a/Mathlib/Order/Hom/Set.lean b/Mathlib/Order/Hom/Set.lean index 382a2354e4f5d..df6730da16330 100644 --- a/Mathlib/Order/Hom/Set.lean +++ b/Mathlib/Order/Hom/Set.lean @@ -8,13 +8,14 @@ import Mathlib.Logic.Equiv.Set import Mathlib.Data.Set.Monotone import Mathlib.Data.Set.Image import Mathlib.Order.WellFounded +import Mathlib.Order.Interval.Set.Basic /-! # Order homomorphisms and sets -/ -open OrderDual +open OrderDual Set variable {α β : Type*} @@ -159,6 +160,36 @@ instance subsingleton_of_wellFoundedGT' [LinearOrder β] [WellFoundedGT β] [Pre instance unique_of_wellFoundedGT [LinearOrder α] [WellFoundedGT α] : Unique (α ≃o α) := Unique.mk' _ +/-- An order isomorphism between lattices induces an order isomorphism between corresponding +interval sublattices. -/ +protected def Iic [Lattice α] [Lattice β] (e : α ≃o β) (x : α) : + Iic x ≃o Iic (e x) where + toFun y := ⟨e y, (map_le_map_iff _).mpr y.property⟩ + invFun y := ⟨e.symm y, e.symm_apply_le.mpr y.property⟩ + left_inv y := by simp + right_inv y := by simp + map_rel_iff' := by simp + +/-- An order isomorphism between lattices induces an order isomorphism between corresponding +interval sublattices. -/ +protected def Ici [Lattice α] [Lattice β] (e : α ≃o β) (x : α) : + Ici x ≃o Ici (e x) where + toFun y := ⟨e y, (map_le_map_iff _).mpr y.property⟩ + invFun y := ⟨e.symm y, e.le_symm_apply.mpr y.property⟩ + left_inv y := by simp + right_inv y := by simp + map_rel_iff' := by simp + +/-- An order isomorphism between lattices induces an order isomorphism between corresponding +interval sublattices. -/ +protected def Icc [Lattice α] [Lattice β] (e : α ≃o β) (x y : α) : + Icc x y ≃o Icc (e x) (e y) where + toFun z := ⟨e z, by simp only [mem_Icc, map_le_map_iff]; exact z.property⟩ + invFun z := ⟨e.symm z, by simp only [mem_Icc, e.le_symm_apply, e.symm_apply_le]; exact z.property⟩ + left_inv y := by simp + right_inv y := by simp + map_rel_iff' := by simp + end OrderIso section BooleanAlgebra diff --git a/Mathlib/Order/Ideal.lean b/Mathlib/Order/Ideal.lean index 3e6b195981b8f..7c8fe0e4ef08f 100644 --- a/Mathlib/Order/Ideal.lean +++ b/Mathlib/Order/Ideal.lean @@ -92,7 +92,7 @@ variable [LE P] section -variable {I J s t : Ideal P} {x y : P} +variable {I s t : Ideal P} {x : P} theorem toLowerSet_injective : Injective (toLowerSet : Ideal P → LowerSet P) := fun s t _ ↦ by cases s @@ -134,11 +134,9 @@ theorem mem_compl_of_ge {x y : P} : x ≤ y → x ∈ (I : Set P)ᶜ → y ∈ ( instance instPartialOrderIdeal : PartialOrder (Ideal P) := PartialOrder.lift SetLike.coe SetLike.coe_injective --- @[simp] -- Porting note (#10618): simp can prove this theorem coe_subset_coe : (s : Set P) ⊆ t ↔ s ≤ t := Iff.rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem coe_ssubset_coe : (s : Set P) ⊂ t ↔ s < t := Iff.rfl @@ -249,7 +247,7 @@ variable [Preorder P] section -variable {I J : Ideal P} {x y : P} +variable {I : Ideal P} {x y : P} /-- The smallest ideal containing a given element. -/ @[simps] @@ -318,7 +316,7 @@ end SemilatticeSup section SemilatticeSupDirected -variable [SemilatticeSup P] [IsDirected P (· ≥ ·)] {x : P} {I J K s t : Ideal P} +variable [SemilatticeSup P] [IsDirected P (· ≥ ·)] {x : P} {I J s t : Ideal P} /-- The infimum of two ideals of a co-directed order is their intersection. -/ instance : Inf (Ideal P) := @@ -345,7 +343,7 @@ instance : Sup (Ideal P) := y ≤ yi ⊔ yj := ‹_› _ ≤ xi ⊔ yi ⊔ (xj ⊔ yj) := sup_le_sup le_sup_right le_sup_right)⟩, le_sup_left, le_sup_right⟩ - lower' := fun x y h ⟨yi, hi, yj, hj, hxy⟩ ↦ ⟨yi, hi, yj, hj, h.trans hxy⟩ }⟩ + lower' := fun _ _ h ⟨yi, hi, yj, hj, hxy⟩ ↦ ⟨yi, hi, yj, hj, h.trans hxy⟩ }⟩ instance : Lattice (Ideal P) := { Ideal.instPartialOrderIdeal with @@ -387,7 +385,7 @@ end SemilatticeSupDirected section SemilatticeSupOrderBot -variable [SemilatticeSup P] [OrderBot P] {x : P} {I J K : Ideal P} +variable [SemilatticeSup P] [OrderBot P] {x : P} instance : InfSet (Ideal P) := ⟨fun S ↦ diff --git a/Mathlib/Order/InitialSeg.lean b/Mathlib/Order/InitialSeg.lean index 83ab64a3e5d24..b1e211077acf2 100644 --- a/Mathlib/Order/InitialSeg.lean +++ b/Mathlib/Order/InitialSeg.lean @@ -1,12 +1,12 @@ /- 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 +Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios -/ +import Mathlib.Data.Sum.Order import Mathlib.Logic.Equiv.Set import Mathlib.Order.RelIso.Set import Mathlib.Order.WellFounded -import Mathlib.Data.Sum.Order /-! # Initial and principal segments @@ -21,12 +21,18 @@ This file defines initial and principal segments. segment, i.e., an interval of the form `(-∞, top)` for some element `top`. It is denoted by `r ≺i s`. +The lemmas `Ordinal.type_le_iff` and `Ordinal.type_lt_iff` tell us that `≼i` corresponds to the `≤` +relation on ordinals, while `≺i` corresponds to the `<` relation. This prompts us to think of +`PrincipalSeg` as a "strict" version of `InitialSeg`. + ## Notations These notations belong to the `InitialSeg` locale. * `r ≼i s`: the type of initial segment embeddings of `r` into `s`. * `r ≺i s`: the type of principal segment embeddings of `r` into `s`. +* `α ≤i β` is an abbreviation for `(· < ·) ≼i (· < ·)`. +* `α InitialSeg +/-- An `InitialSeg` between the `<` relations of two types. -/ +notation:25 α:24 " ≤i " β:25 => @InitialSeg α β (· < ·) (· < ·) + namespace InitialSeg instance : Coe (r ≼i s) (r ↪r s) := @@ -71,6 +78,24 @@ instance : FunLike (r ≼i s) α β where instance : EmbeddingLike (r ≼i s) α β where injective' f := f.inj' +/-- An initial segment embedding between the `<` relations of two partial orders is an order +embedding. -/ +def toOrderEmbedding [PartialOrder α] [PartialOrder β] (f : α ≤i β) : α ↪o β := + f.orderEmbeddingOfLTEmbedding + +@[simp] +theorem toOrderEmbedding_apply [PartialOrder α] [PartialOrder β] (f : α ≤i β) (x : α) : + f.toOrderEmbedding x = f x := + rfl + +@[simp] +theorem coe_toOrderEmbedding [PartialOrder α] [PartialOrder β] (f : α ≤i β) : + (f.toOrderEmbedding : α → β) = f := + rfl + +instance [PartialOrder α] [PartialOrder β] : OrderHomClass (α ≤i β) α β where + map_rel f := f.toOrderEmbedding.map_rel_iff.2 + @[ext] lemma ext {f g : r ≼i s} (h : ∀ x, f x = g x) : f = g := DFunLike.ext f g h @@ -87,11 +112,14 @@ alias init := mem_range_of_rel theorem map_rel_iff {a b : α} (f : r ≼i s) : s (f a) (f b) ↔ r a b := f.map_rel_iff' +theorem inj (f : r ≼i s) {a b : α} : f a = f b ↔ a = b := + f.toRelEmbedding.inj + theorem exists_eq_iff_rel (f : r ≼i s) {a : α} {b : β} : s b (f a) ↔ ∃ a', f a' = b ∧ r a' a := ⟨fun h => by rcases f.mem_range_of_rel h with ⟨a', rfl⟩ exact ⟨a', rfl, f.map_rel_iff.1 h⟩, - fun ⟨a', e, h⟩ => e ▸ f.map_rel_iff.2 h⟩ + fun ⟨_, e, h⟩ => e ▸ f.map_rel_iff.2 h⟩ @[deprecated exists_eq_iff_rel (since := "2024-09-21")] alias init_iff := exists_eq_iff_rel @@ -158,16 +186,19 @@ theorem antisymm_symm [IsWellOrder α r] [IsWellOrder β s] (f : r ≼i s) (g : RelIso.coe_fn_injective rfl theorem eq_or_principal [IsWellOrder β s] (f : r ≼i s) : - Surjective f ∨ ∃ b, ∀ x, s x b ↔ ∃ y, f y = x := - or_iff_not_imp_right.2 fun h b => - Acc.recOn (IsWellFounded.wf.apply b : Acc s b) fun x _ IH => - not_forall_not.1 fun hn => - h - ⟨x, fun y => - ⟨IH _, fun ⟨a, e⟩ => by - rw [← e] - exact (trichotomous _ _).resolve_right - (not_or_intro (hn a) fun hl => not_exists.2 hn (f.mem_range_of_rel hl))⟩⟩ + Surjective f ∨ ∃ b, ∀ x, x ∈ Set.range f ↔ s x b := by + apply or_iff_not_imp_right.2 + intro h b + push_neg at h + apply IsWellFounded.induction s b + intro x IH + obtain ⟨y, ⟨hy, hs⟩ | ⟨hy, hs⟩⟩ := h x + · obtain (rfl | h) := (trichotomous y x).resolve_left hs + · exact hy + · obtain ⟨z, rfl⟩ := hy + exact f.mem_range_of_rel h + · obtain ⟨z, rfl⟩ := IH y hs + cases hy (Set.mem_range_self z) /-- Restrict the codomain of an initial segment -/ def codRestrict (p : Set β) (f : r ≼i s) (H : ∀ a, f a ∈ p) : r ≼i Subrel s p := @@ -216,15 +247,16 @@ embeddings are called principal segments -/ structure PrincipalSeg {α β : Type*} (r : α → α → Prop) (s : β → β → Prop) extends r ↪r s where /-- The supremum of the principal segment -/ top : β - /-- The image of the order embedding is the set of elements `b` such that `s b top` -/ - down' : ∀ b, s b top ↔ ∃ a, toRelEmbedding a = b + /-- The range of the order embedding is the set of elements `b` such that `s b top` -/ + mem_range_iff_rel' : ∀ b, b ∈ Set.range toRelEmbedding ↔ s b top -- Porting note: deleted `scoped[InitialSeg]` -/-- If `r` is a relation on `α` and `s` in a relation on `β`, then `f : r ≺i s` is an order -embedding whose range is an open interval `(-∞, top)` for some element `top` of `β`. Such order -embeddings are called principal segments -/ +@[inherit_doc] infixl:25 " ≺i " => PrincipalSeg +/-- A `PrincipalSeg` between the `<` relations of two types. -/ +notation:25 α:24 " @PrincipalSeg α β (· < ·) (· < ·) + namespace PrincipalSeg instance : CoeOut (r ≺i s) (r ↪r s) := @@ -237,19 +269,30 @@ instance : CoeFun (r ≺i s) fun _ => α → β := theorem coe_fn_mk (f : r ↪r s) (t o) : (@PrincipalSeg.mk _ _ r s f t o : α → β) = f := rfl +theorem mem_range_iff_rel (f : r ≺i s) : ∀ {b : β}, b ∈ Set.range f ↔ s b f.top := + f.mem_range_iff_rel' _ + +@[deprecated mem_range_iff_rel (since := "2024-10-07")] theorem down (f : r ≺i s) : ∀ {b : β}, s b f.top ↔ ∃ a, f a = b := - f.down' _ + f.mem_range_iff_rel.symm theorem lt_top (f : r ≺i s) (a : α) : s (f a) f.top := - f.down.2 ⟨_, rfl⟩ + f.mem_range_iff_rel.1 ⟨_, rfl⟩ + +theorem mem_range_of_rel_top (f : r ≺i s) {b : β} (h : s b f.top) : b ∈ Set.range f := + f.mem_range_iff_rel.2 h theorem mem_range_of_rel [IsTrans β s] (f : r ≺i s) {a : α} {b : β} (h : s b (f a)) : b ∈ Set.range f := - f.down.1 <| _root_.trans h <| f.lt_top _ + f.mem_range_of_rel_top <| _root_.trans h <| f.lt_top _ @[deprecated mem_range_of_rel (since := "2024-09-21")] alias init := mem_range_of_rel +theorem surjOn (f : r ≺i s) : Set.SurjOn f Set.univ { b | s b f.top } := by + intro b h + simpa using mem_range_of_rel_top _ h + /-- A principal segment is in particular an initial segment. -/ instance hasCoeInitialSeg [IsTrans β s] : Coe (r ≺i s) (r ≼i s) := ⟨fun f => ⟨f.toRelEmbedding, fun _ _ => f.mem_range_of_rel⟩⟩ @@ -267,8 +310,7 @@ alias init_iff := exists_eq_iff_rel /-- A principal segment is the same as a non-surjective initial segment. -/ noncomputable def _root_.InitialSeg.toPrincipalSeg [IsWellOrder β s] (f : r ≼i s) (hf : ¬ Surjective f) : r ≺i s := - letI H := f.eq_or_principal.resolve_left hf - ⟨f, Classical.choose H, Classical.choose_spec H⟩ + ⟨f, _, Classical.choose_spec (f.eq_or_principal.resolve_left hf)⟩ @[simp] theorem _root_.InitialSeg.toPrincipalSeg_apply [IsWellOrder β s] (f : r ≼i s) @@ -286,8 +328,7 @@ instance (r : α → α → Prop) [IsWellOrder α r] : IsEmpty (r ≺i r) := /-- Composition of a principal segment with an initial segment, as a principal segment -/ def ltLe (f : r ≺i s) (g : s ≼i t) : r ≺i t := ⟨@RelEmbedding.trans _ _ _ r s t f g, g f.top, fun a => by - simp only [g.exists_eq_iff_rel, PrincipalSeg.down, exists_and_left.symm, exists_swap, - RelEmbedding.trans_apply, exists_eq_right', InitialSeg.coe_coe_fn]⟩ + simp [g.exists_eq_iff_rel, ← PrincipalSeg.mem_range_iff_rel, exists_swap, ← exists_and_left]⟩ @[simp] theorem lt_le_apply (f : r ≺i s) (g : s ≼i t) (a : α) : (f.ltLe g) a = g (f a) := @@ -313,17 +354,17 @@ theorem trans_top [IsTrans γ t] (f : r ≺i s) (g : s ≺i t) : (f.trans g).top /-- Composition of an order isomorphism with a principal segment, as a principal segment -/ def equivLT (f : r ≃r s) (g : s ≺i t) : r ≺i t := ⟨@RelEmbedding.trans _ _ _ r s t f g, g.top, fun c => - suffices (∃ a : β, g a = c) ↔ ∃ a : α, g (f a) = c by simpa [PrincipalSeg.down] + suffices (∃ a, g a = c) ↔ ∃ a, g (f a) = c by simp [← PrincipalSeg.mem_range_iff_rel] ⟨fun ⟨b, h⟩ => ⟨f.symm b, by simp only [h, RelIso.apply_symm_apply]⟩, fun ⟨a, h⟩ => ⟨f a, h⟩⟩⟩ /-- Composition of a principal segment with an order isomorphism, as a principal segment -/ -def ltEquiv {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} (f : PrincipalSeg r s) - (g : s ≃r t) : PrincipalSeg r t := +def ltEquiv {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} (f : r ≺i s) (g : s ≃r t) : + r ≺i t := ⟨@RelEmbedding.trans _ _ _ r s t f g, g f.top, by intro x - rw [← g.apply_symm_apply x, g.map_rel_iff, f.down', exists_congr] - intro y; exact ⟨congr_arg g, fun h => g.toEquiv.bijective.1 h⟩⟩ + rw [← g.apply_symm_apply x, g.map_rel_iff, ← f.mem_range_iff_rel] + exact exists_congr <| fun _ ↦ ⟨fun h => g.toEquiv.bijective.1 h, congr_arg g⟩⟩ @[simp] theorem equivLT_apply (f : r ≃r s) (g : s ≺i t) (a : α) : (equivLT f g) a = g (f a) := @@ -341,22 +382,28 @@ instance [IsWellOrder β s] : Subsingleton (r ≺i s) := rw [@Subsingleton.elim _ _ (f : r ≼i s) g] have et : f.top = g.top := by refine extensional_of_trichotomous_of_irrefl s fun x => ?_ - simp only [PrincipalSeg.down, ef] + simp only [← PrincipalSeg.mem_range_iff_rel, ef] cases f cases g have := RelEmbedding.coe_fn_injective ef; congr ⟩ +protected theorem eq [IsWellOrder β s] (f g : r ≺i s) (a) : f a = g a := by + rw [Subsingleton.elim f g] + theorem top_eq [IsWellOrder γ t] (e : r ≃r s) (f : r ≺i t) (g : s ≺i t) : f.top = g.top := by rw [Subsingleton.elim f (PrincipalSeg.equivLT e g)]; rfl -theorem topLTTop {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} [IsWellOrder γ t] - (f : PrincipalSeg r s) (g : PrincipalSeg s t) (h : PrincipalSeg r t) : t h.top g.top := by +theorem top_rel_top {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} [IsWellOrder γ t] + (f : r ≺i s) (g : s ≺i t) (h : r ≺i t) : t h.top g.top := by rw [Subsingleton.elim h (f.trans g)] apply PrincipalSeg.lt_top +@[deprecated top_rel_top (since := "2024-10-10")] +alias topLTTop := top_rel_top + /-- Any element of a well order yields a principal segment -/ def ofElement {α : Type*} (r : α → α → Prop) (a : α) : Subrel r { b | r b a } ≺i r := - ⟨Subrel.relEmbedding _ _, a, fun _ => ⟨fun h => ⟨⟨_, h⟩, rfl⟩, fun ⟨⟨_, h⟩, rfl⟩ => h⟩⟩ + ⟨Subrel.relEmbedding _ _, a, fun _ => ⟨fun ⟨⟨_, h⟩, rfl⟩ => h, fun h => ⟨⟨_, h⟩, rfl⟩⟩⟩ -- This lemma was always bad, but the linter only noticed after lean4#2644 @[simp, nolint simpNF] @@ -372,7 +419,7 @@ theorem ofElement_top {α : Type*} (r : α → α → Prop) (a : α) : (ofElemen noncomputable def subrelIso (f : r ≺i s) : Subrel s {b | s b f.top} ≃r r := RelIso.symm { toEquiv := ((Equiv.ofInjective f f.injective).trans (Equiv.setCongr - (funext fun _ ↦ propext f.down.symm))), + (funext fun _ ↦ propext f.mem_range_iff_rel))), map_rel_iff' := f.map_rel_iff } -- This lemma was always bad, but the linter only noticed after lean4#2644 @@ -386,15 +433,12 @@ theorem apply_subrelIso (f : r ≺i s) (b : {b | s b f.top}) : -- This lemma was always bad, but the linter only noticed after lean4#2644 @[simp, nolint simpNF] -theorem subrelIso_apply (f : r ≺i s) (a : α) : - f.subrelIso ⟨f a, f.down.mpr ⟨a, rfl⟩⟩ = a := +theorem subrelIso_apply (f : r ≺i s) (a : α) : f.subrelIso ⟨f a, f.lt_top a⟩ = a := Equiv.ofInjective_symm_apply f.injective _ /-- Restrict the codomain of a principal segment -/ def codRestrict (p : Set β) (f : r ≺i s) (H : ∀ a, f a ∈ p) (H₂ : f.top ∈ p) : r ≺i Subrel s p := - ⟨RelEmbedding.codRestrict p f H, ⟨f.top, H₂⟩, fun ⟨_, _⟩ => - f.down.trans <| - exists_congr fun a => show (⟨f a, H a⟩ : p).1 = _ ↔ _ from ⟨Subtype.eq, congr_arg _⟩⟩ + ⟨RelEmbedding.codRestrict p f H, ⟨f.top, H₂⟩, fun ⟨_, _⟩ => by simp [← f.mem_range_iff_rel]⟩ @[simp] theorem codRestrict_apply (p) (f : r ≺i s) (H H₂ a) : codRestrict p f H H₂ a = ⟨f a, H a⟩ := @@ -408,7 +452,7 @@ theorem codRestrict_top (p) (f : r ≺i s) (H H₂) : (codRestrict p f H H₂).t def ofIsEmpty (r : α → α → Prop) [IsEmpty α] {b : β} (H : ∀ b', ¬s b' b) : r ≺i s := { RelEmbedding.ofIsEmpty r s with top := b - down' := by simp [H] } + mem_range_iff_rel' := by simp [H] } @[simp] theorem ofIsEmpty_top (r : α → α → Prop) [IsEmpty α] {b : β} (H : ∀ b', ¬s b' b) : @@ -424,20 +468,6 @@ protected theorem acc [IsTrans β s] (f : r ≺i s) (a : α) : Acc r a ↔ Acc s end PrincipalSeg -/-- A relation is well-founded iff every principal segment of it is well-founded. - -In this lemma we use `Subrel` to indicate its principal segments because it's usually more -convenient to use. --/ -theorem wellFounded_iff_wellFounded_subrel {β : Type*} {s : β → β → Prop} [IsTrans β s] : - WellFounded s ↔ ∀ b, WellFounded (Subrel s { b' | s b' b }) := by - refine - ⟨fun wf b => ⟨fun b' => ((PrincipalSeg.ofElement _ b).acc b').mpr (wf.apply b')⟩, fun wf => - ⟨fun b => Acc.intro _ fun b' hb' => ?_⟩⟩ - let f := PrincipalSeg.ofElement s b - obtain ⟨b', rfl⟩ := f.down.mp ((PrincipalSeg.ofElement_top s b).symm ▸ hb' : s b' f.top) - exact (f.acc b').mp ((wf b).apply b') - theorem wellFounded_iff_principalSeg.{u} {β : Type u} {s : β → β → Prop} [IsTrans β s] : WellFounded s ↔ ∀ (α : Type u) (r : α → α → Prop) (_ : r ≺i s), WellFounded r := ⟨fun wf _ _ f => RelHomClass.wellFounded f.toRelEmbedding wf, fun h => @@ -456,17 +486,14 @@ noncomputable def ltOrEq [IsWellOrder β s] (f : r ≼i s) : (r ≺i s) ⊕ (r · exact Sum.inr (RelIso.ofSurjective f h) · exact Sum.inl (f.toPrincipalSeg h) -theorem ltOrEq_apply_left [IsWellOrder β s] (f : r ≼i s) (g : r ≺i s) (a : α) : - g a = f a := +theorem ltOrEq_apply_left [IsWellOrder β s] (f : r ≼i s) (g : r ≺i s) (a : α) : g a = f a := @InitialSeg.eq α β r s _ g f a -theorem ltOrEq_apply_right [IsWellOrder β s] (f : r ≼i s) (g : r ≃r s) (a : α) : - g a = f a := +theorem ltOrEq_apply_right [IsWellOrder β s] (f : r ≼i s) (g : r ≃r s) (a : α) : g a = f a := InitialSeg.eq (InitialSeg.ofIso g) f a /-- Composition of an initial segment taking values in a well order and a principal segment. -/ -noncomputable def leLT [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) : - r ≺i t := +noncomputable def leLT [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) : r ≺i t := match f.ltOrEq with | Sum.inl f' => f'.trans g | Sum.inr f' => PrincipalSeg.equivLT f' g @@ -474,9 +501,10 @@ noncomputable def leLT [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s @[simp] theorem leLT_apply [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) (a : α) : (f.leLT g) a = g (f a) := by - delta InitialSeg.leLT; cases' f.ltOrEq with f' f' - · simp only [PrincipalSeg.trans_apply, f.ltOrEq_apply_left] - · simp only [PrincipalSeg.equivLT_apply, f.ltOrEq_apply_right] + rw [InitialSeg.leLT] + obtain f' | f' := f.ltOrEq + · rw [PrincipalSeg.trans_apply, f.ltOrEq_apply_left] + · rw [PrincipalSeg.equivLT_apply, f.ltOrEq_apply_right] end InitialSeg @@ -512,7 +540,7 @@ theorem collapseF.not_lt [IsWellOrder β s] (f : r ↪r s) (a : α) {b} to fill the gaps. -/ noncomputable def collapse [IsWellOrder β s] (f : r ↪r s) : r ≼i s := haveI := RelEmbedding.isWellOrder f - ⟨RelEmbedding.ofMonotone (fun a => (collapseF f a).1) fun a b => collapseF.lt f, fun a b => + ⟨RelEmbedding.ofMonotone (fun a => (collapseF f a).1) fun _ _ => collapseF.lt f, fun a b => Acc.recOn (IsWellFounded.wf.apply b : Acc s b) (fun b _ _ a h => by rcases (@IsWellFounded.wf _ r).has_min { a | ¬s (collapseF f a).1 b } @@ -547,3 +575,80 @@ noncomputable def InitialSeg.total (r s) [IsWellOrder α r] [IsWellOrder β s] : attribute [nolint simpNF] PrincipalSeg.ofElement_apply PrincipalSeg.subrelIso_symm_apply PrincipalSeg.apply_subrelIso PrincipalSeg.subrelIso_apply + +/-! ### Initial or principal segments with `<` -/ + +namespace InitialSeg + +variable [PartialOrder β] {a a' : α} {b : β} + +theorem mem_range_of_le [Preorder α] (f : α ≤i β) (h : b ≤ f a) : b ∈ Set.range f := by + obtain rfl | hb := h.eq_or_lt + exacts [⟨a, rfl⟩, f.mem_range_of_rel hb] + +-- TODO: this would follow immediately if we had a `RelEmbeddingClass` +@[simp] +theorem le_iff_le [PartialOrder α] (f : α ≤i β) : f a ≤ f a' ↔ a ≤ a' := + f.toOrderEmbedding.le_iff_le + +-- TODO: this would follow immediately if we had a `RelEmbeddingClass` +@[simp] +theorem lt_iff_lt [PartialOrder α] (f : α ≤i β) : f a < f a' ↔ a < a' := + f.toOrderEmbedding.lt_iff_lt + +theorem monotone [PartialOrder α] (f : α ≤i β) : Monotone f := + f.toOrderEmbedding.monotone + +theorem strictMono [PartialOrder α] (f : α ≤i β) : StrictMono f := + f.toOrderEmbedding.strictMono + +theorem le_apply_iff [LinearOrder α] (f : α ≤i β) : b ≤ f a ↔ ∃ c ≤ a, f c = b := by + constructor + · intro h + obtain ⟨c, hc⟩ := f.mem_range_of_le h + refine ⟨c, ?_, hc⟩ + rwa [← hc, f.le_iff_le] at h + · rintro ⟨c, hc, rfl⟩ + exact f.monotone hc + +theorem lt_apply_iff [LinearOrder α] (f : α ≤i β) : b < f a ↔ ∃ a' < a, f a' = b := by + constructor + · intro h + obtain ⟨c, hc⟩ := f.mem_range_of_rel h + refine ⟨c, ?_, hc⟩ + rwa [← hc, f.lt_iff_lt] at h + · rintro ⟨c, hc, rfl⟩ + exact f.strictMono hc + +end InitialSeg + +namespace PrincipalSeg + +variable [PartialOrder β] {a a' : α} {b : β} + +theorem mem_range_of_le [Preorder α] (f : α bot_le | ⊥, some _ => bot_le - | some s, ⊥ => bot_le + | some _, ⊥ => bot_le | some s, some t => by change dite _ _ _ ≤ _ split_ifs @@ -480,7 +479,7 @@ instance lattice : Lattice (Interval α) := inf_le_right := fun s t => match s, t with | ⊥, ⊥ => bot_le - | ⊥, some t => bot_le + | ⊥, some _ => bot_le | some _, ⊥ => bot_le | some s, some t => by change dite _ _ _ ≤ _ @@ -489,7 +488,7 @@ instance lattice : Lattice (Interval α) := · exact bot_le le_inf := fun s t c => match s, t, c with - | ⊥, t, c => fun _ _ => bot_le + | ⊥, _, _ => fun _ _ => bot_le | (s : NonemptyInterval α), t, c => fun hb hc => by lift t to NonemptyInterval α using ne_bot_of_le_ne_bot WithBot.coe_ne_bot hb lift c to NonemptyInterval α using ne_bot_of_le_ne_bot WithBot.coe_ne_bot hc diff --git a/Mathlib/Order/Interval/Finset/Basic.lean b/Mathlib/Order/Interval/Finset/Basic.lean index 53ccb40f79265..e8a5116a9e300 100644 --- a/Mathlib/Order/Interval/Finset/Basic.lean +++ b/Mathlib/Order/Interval/Finset/Basic.lean @@ -120,36 +120,20 @@ theorem Ioc_eq_empty_of_le (h : b ≤ a) : Ioc a b = ∅ := theorem Ioo_eq_empty_of_le (h : b ≤ a) : Ioo a b = ∅ := Ioo_eq_empty h.not_lt --- porting note (#10618): simp can prove this --- @[simp] theorem left_mem_Icc : a ∈ Icc a b ↔ a ≤ b := by simp only [mem_Icc, true_and, le_rfl] --- porting note (#10618): simp can prove this --- @[simp] theorem left_mem_Ico : a ∈ Ico a b ↔ a < b := by simp only [mem_Ico, true_and, le_refl] --- porting note (#10618): simp can prove this --- @[simp] theorem right_mem_Icc : b ∈ Icc a b ↔ a ≤ b := by simp only [mem_Icc, and_true, le_rfl] --- porting note (#10618): simp can prove this --- @[simp] theorem right_mem_Ioc : b ∈ Ioc a b ↔ a < b := by simp only [mem_Ioc, and_true, le_rfl] --- porting note (#10618): simp can prove this --- @[simp] theorem left_not_mem_Ioc : a ∉ Ioc a b := fun h => lt_irrefl _ (mem_Ioc.1 h).1 --- porting note (#10618): simp can prove this --- @[simp] theorem left_not_mem_Ioo : a ∉ Ioo a b := fun h => lt_irrefl _ (mem_Ioo.1 h).1 --- porting note (#10618): simp can prove this --- @[simp] theorem right_not_mem_Ico : b ∉ Ico a b := fun h => lt_irrefl _ (mem_Ico.1 h).2 --- porting note (#10618): simp can prove this --- @[simp] theorem right_not_mem_Ioo : b ∉ Ioo a b := fun h => lt_irrefl _ (mem_Ioo.1 h).2 theorem Icc_subset_Icc (ha : a₂ ≤ a₁) (hb : b₁ ≤ b₂) : Icc a₁ b₁ ⊆ Icc a₂ b₂ := by @@ -244,18 +228,12 @@ theorem Icc_ssubset_Icc_right (hI : a₂ ≤ b₂) (ha : a₂ ≤ a₁) (hb : b variable (a) --- porting note (#10618): simp can prove this --- @[simp] theorem Ico_self : Ico a a = ∅ := Ico_eq_empty <| lt_irrefl _ --- porting note (#10618): simp can prove this --- @[simp] theorem Ioc_self : Ioc a a = ∅ := Ioc_eq_empty <| lt_irrefl _ --- porting note (#10618): simp can prove this --- @[simp] theorem Ioo_self : Ioo a a = ∅ := Ioo_eq_empty <| lt_irrefl _ @@ -269,66 +247,58 @@ def _root_.Set.fintypeOfMemBounds {s : Set α} [DecidablePred (· ∈ s)] (ha : section Filter theorem Ico_filter_lt_of_le_left [DecidablePred (· < c)] (hca : c ≤ a) : - (Ico a b).filter (· < c) = ∅ := + {x ∈ Ico a b | x < c} = ∅ := filter_false_of_mem fun _ hx => (hca.trans (mem_Ico.1 hx).1).not_lt theorem Ico_filter_lt_of_right_le [DecidablePred (· < c)] (hbc : b ≤ c) : - (Ico a b).filter (· < c) = Ico a b := + {x ∈ Ico a b | x < c} = Ico a b := filter_true_of_mem fun _ hx => (mem_Ico.1 hx).2.trans_le hbc theorem Ico_filter_lt_of_le_right [DecidablePred (· < c)] (hcb : c ≤ b) : - (Ico a b).filter (· < c) = Ico a c := by + {x ∈ Ico a b | x < c} = Ico a c := by ext x rw [mem_filter, mem_Ico, mem_Ico, and_right_comm] exact and_iff_left_of_imp fun h => h.2.trans_le hcb theorem Ico_filter_le_of_le_left {a b c : α} [DecidablePred (c ≤ ·)] (hca : c ≤ a) : - (Ico a b).filter (c ≤ ·) = Ico a b := + {x ∈ Ico a b | c ≤ x} = Ico a b := filter_true_of_mem fun _ hx => hca.trans (mem_Ico.1 hx).1 theorem Ico_filter_le_of_right_le {a b : α} [DecidablePred (b ≤ ·)] : - (Ico a b).filter (b ≤ ·) = ∅ := + {x ∈ Ico a b | b ≤ x} = ∅ := filter_false_of_mem fun _ hx => (mem_Ico.1 hx).2.not_le theorem Ico_filter_le_of_left_le {a b c : α} [DecidablePred (c ≤ ·)] (hac : a ≤ c) : - (Ico a b).filter (c ≤ ·) = Ico c b := by + {x ∈ Ico a b | c ≤ x} = Ico c b := by ext x rw [mem_filter, mem_Ico, mem_Ico, and_comm, and_left_comm] exact and_iff_right_of_imp fun h => hac.trans h.1 theorem Icc_filter_lt_of_lt_right {a b c : α} [DecidablePred (· < c)] (h : b < c) : - (Icc a b).filter (· < c) = Icc a b := + {x ∈ Icc a b | x < c} = Icc a b := filter_true_of_mem fun _ hx => lt_of_le_of_lt (mem_Icc.1 hx).2 h theorem Ioc_filter_lt_of_lt_right {a b c : α} [DecidablePred (· < c)] (h : b < c) : - (Ioc a b).filter (· < c) = Ioc a b := + {x ∈ Ioc a b | x < c} = Ioc a b := filter_true_of_mem fun _ hx => lt_of_le_of_lt (mem_Ioc.1 hx).2 h theorem Iic_filter_lt_of_lt_right {α} [Preorder α] [LocallyFiniteOrderBot α] {a c : α} - [DecidablePred (· < c)] (h : a < c) : (Iic a).filter (· < c) = Iic a := + [DecidablePred (· < c)] (h : a < c) : {x ∈ Iic a | x < c} = Iic a := filter_true_of_mem fun _ hx => lt_of_le_of_lt (mem_Iic.1 hx) h variable (a b) [Fintype α] theorem filter_lt_lt_eq_Ioo [DecidablePred fun j => a < j ∧ j < b] : - (univ.filter fun j => a < j ∧ j < b) = Ioo a b := by - ext - simp + ({j | a < j ∧ j < b} : Finset _) = Ioo a b := by ext; simp theorem filter_lt_le_eq_Ioc [DecidablePred fun j => a < j ∧ j ≤ b] : - (univ.filter fun j => a < j ∧ j ≤ b) = Ioc a b := by - ext - simp + ({j | a < j ∧ j ≤ b} : Finset _) = Ioc a b := by ext; simp theorem filter_le_lt_eq_Ico [DecidablePred fun j => a ≤ j ∧ j < b] : - (univ.filter fun j => a ≤ j ∧ j < b) = Ico a b := by - ext - simp + ({j | a ≤ j ∧ j < b} : Finset _) = Ico a b := by ext; simp theorem filter_le_le_eq_Icc [DecidablePred fun j => a ≤ j ∧ j ≤ b] : - (univ.filter fun j => a ≤ j ∧ j ≤ b) = Icc a b := by - ext - simp + ({j | a ≤ j ∧ j ≤ b} : Finset _) = Icc a b := by ext; simp end Filter @@ -430,13 +400,8 @@ theorem _root_.Set.Infinite.not_bddBelow {s : Set α} : s.Infinite → ¬BddBelo variable [Fintype α] -theorem filter_lt_eq_Ioi [DecidablePred (a < ·)] : univ.filter (a < ·) = Ioi a := by - ext - simp - -theorem filter_le_eq_Ici [DecidablePred (a ≤ ·)] : univ.filter (a ≤ ·) = Ici a := by - ext - simp +theorem filter_lt_eq_Ioi [DecidablePred (a < ·)] : ({x | a < x} : Finset _) = Ioi a := by ext; simp +theorem filter_le_eq_Ici [DecidablePred (a ≤ ·)] : ({x | a ≤ x} : Finset _) = Ici a := by ext; simp end LocallyFiniteOrderTop @@ -455,13 +420,8 @@ theorem _root_.Set.Infinite.not_bddAbove {s : Set α} : s.Infinite → ¬BddAbov variable [Fintype α] -theorem filter_gt_eq_Iio [DecidablePred (· < a)] : univ.filter (· < a) = Iio a := by - ext - simp - -theorem filter_ge_eq_Iic [DecidablePred (· ≤ a)] : univ.filter (· ≤ a) = Iic a := by - ext - simp +theorem filter_gt_eq_Iio [DecidablePred (· < a)] : ({x | x < a} : Finset _) = Iio a := by ext; simp +theorem filter_ge_eq_Iic [DecidablePred (· ≤ a)] : ({x | x ≤ a} : Finset _) = Iic a := by ext; simp end LocallyFiniteOrderBot @@ -561,32 +521,32 @@ theorem Ico_eq_cons_Ioo (h : a < b) : Ico a b = (Ioo a b).cons a left_not_mem_Io classical rw [cons_eq_insert, Ioo_insert_left h] theorem Ico_filter_le_left {a b : α} [DecidablePred (· ≤ a)] (hab : a < b) : - ((Ico a b).filter fun x => x ≤ a) = {a} := by + {x ∈ Ico a b | x ≤ a} = {a} := by ext x rw [mem_filter, mem_Ico, mem_singleton, and_right_comm, ← le_antisymm_iff, eq_comm] exact and_iff_left_of_imp fun h => h.le.trans_lt hab -theorem card_Ico_eq_card_Icc_sub_one (a b : α) : (Ico a b).card = (Icc a b).card - 1 := by +theorem card_Ico_eq_card_Icc_sub_one (a b : α) : #(Ico a b) = #(Icc a b) - 1 := by classical by_cases h : a ≤ b · rw [Icc_eq_cons_Ico h, card_cons] exact (Nat.add_sub_cancel _ _).symm · rw [Ico_eq_empty fun h' => h h'.le, Icc_eq_empty h, card_empty, Nat.zero_sub] -theorem card_Ioc_eq_card_Icc_sub_one (a b : α) : (Ioc a b).card = (Icc a b).card - 1 := +theorem card_Ioc_eq_card_Icc_sub_one (a b : α) : #(Ioc a b) = #(Icc a b) - 1 := @card_Ico_eq_card_Icc_sub_one αᵒᵈ _ _ _ _ -theorem card_Ioo_eq_card_Ico_sub_one (a b : α) : (Ioo a b).card = (Ico a b).card - 1 := by +theorem card_Ioo_eq_card_Ico_sub_one (a b : α) : #(Ioo a b) = #(Ico a b) - 1 := by classical by_cases h : a < b · rw [Ico_eq_cons_Ioo h, card_cons] exact (Nat.add_sub_cancel _ _).symm · rw [Ioo_eq_empty h, Ico_eq_empty h, card_empty, Nat.zero_sub] -theorem card_Ioo_eq_card_Ioc_sub_one (a b : α) : (Ioo a b).card = (Ioc a b).card - 1 := +theorem card_Ioo_eq_card_Ioc_sub_one (a b : α) : #(Ioo a b) = #(Ioc a b) - 1 := @card_Ioo_eq_card_Ico_sub_one αᵒᵈ _ _ _ _ -theorem card_Ioo_eq_card_Icc_sub_two (a b : α) : (Ioo a b).card = (Icc a b).card - 2 := by +theorem card_Ioo_eq_card_Icc_sub_two (a b : α) : #(Ioo a b) = #(Icc a b) - 2 := by rw [card_Ioo_eq_card_Ico_sub_one, card_Ico_eq_card_Icc_sub_one] rfl @@ -610,8 +570,6 @@ theorem Ioi_insert [DecidableEq α] (a : α) : insert a (Ioi a) = Ici a := by ext simp_rw [Finset.mem_insert, mem_Ici, mem_Ioi, le_iff_lt_or_eq, or_comm, eq_comm] --- porting note (#10618): simp can prove this --- @[simp] theorem not_mem_Ioi_self {b : α} : b ∉ Ioi b := fun h => lt_irrefl _ (mem_Ioi.1 h) -- Purposefully written the other way around @@ -619,7 +577,7 @@ theorem not_mem_Ioi_self {b : α} : b ∉ Ioi b := fun h => lt_irrefl _ (mem_Ioi theorem Ici_eq_cons_Ioi (a : α) : Ici a = (Ioi a).cons a not_mem_Ioi_self := by classical rw [cons_eq_insert, Ioi_insert] -theorem card_Ioi_eq_card_Ici_sub_one (a : α) : (Ioi a).card = (Ici a).card - 1 := by +theorem card_Ioi_eq_card_Ici_sub_one (a : α) : #(Ioi a) = #(Ici a) - 1 := by rw [Ici_eq_cons_Ioi, card_cons, Nat.add_sub_cancel_right] end OrderTop @@ -638,8 +596,6 @@ theorem Iio_insert [DecidableEq α] (b : α) : insert b (Iio b) = Iic b := by ext simp_rw [Finset.mem_insert, mem_Iic, mem_Iio, le_iff_lt_or_eq, or_comm] --- porting note (#10618): simp can prove this --- @[simp] theorem not_mem_Iio_self {b : α} : b ∉ Iio b := fun h => lt_irrefl _ (mem_Iio.1 h) -- Purposefully written the other way around @@ -647,7 +603,7 @@ theorem not_mem_Iio_self {b : α} : b ∉ Iio b := fun h => lt_irrefl _ (mem_Iio theorem Iic_eq_cons_Iio (b : α) : Iic b = (Iio b).cons b not_mem_Iio_self := by classical rw [cons_eq_insert, Iio_insert] -theorem card_Iio_eq_card_Iic_sub_one (a : α) : (Iio a).card = (Iic a).card - 1 := by +theorem card_Iio_eq_card_Iic_sub_one (a : α) : #(Iio a) = #(Iic a) - 1 := by rw [Iic_eq_cons_Iio, card_cons, Nat.add_sub_cancel_right] end OrderBot @@ -715,25 +671,25 @@ theorem Ico_inter_Ico {a b c d : α} : Ico a b ∩ Ico c d = Ico (max a c) (min Set.Ico_inter_Ico] @[simp] -theorem Ico_filter_lt (a b c : α) : ((Ico a b).filter fun x => x < c) = Ico a (min b c) := by +theorem Ico_filter_lt (a b c : α) : {x ∈ Ico a b | x < c} = Ico a (min b c) := by cases le_total b c with | inl h => rw [Ico_filter_lt_of_right_le h, min_eq_left h] | inr h => rw [Ico_filter_lt_of_le_right h, min_eq_right h] @[simp] -theorem Ico_filter_le (a b c : α) : ((Ico a b).filter fun x => c ≤ x) = Ico (max a c) b := by +theorem Ico_filter_le (a b c : α) : {x ∈ Ico a b | c ≤ x} = Ico (max a c) b := by cases le_total a c with | inl h => rw [Ico_filter_le_of_left_le h, max_eq_right h] | inr h => rw [Ico_filter_le_of_le_left h, max_eq_left h] @[simp] -theorem Ioo_filter_lt (a b c : α) : (Ioo a b).filter (· < c) = Ioo a (min b c) := by +theorem Ioo_filter_lt (a b c : α) : {x ∈ Ioo a b | x < c} = Ioo a (min b c) := by ext simp [and_assoc] @[simp] theorem Iio_filter_lt {α} [LinearOrder α] [LocallyFiniteOrderBot α] (a b : α) : - (Iio a).filter (· < b) = Iio (min a b) := by + {x ∈ Iio a | x < b} = Iio (min a b) := by ext simp [and_assoc] @@ -806,8 +762,6 @@ theorem uIcc_of_ge (h : b ≤ a) : [[a, b]] = Icc b a := by theorem uIcc_comm (a b : α) : [[a, b]] = [[b, a]] := by rw [uIcc, uIcc, inf_comm, sup_comm] --- porting note (#10618): simp can prove this --- @[simp] theorem uIcc_self : [[a, a]] = {a} := by simp [uIcc] @[simp] @@ -820,13 +774,9 @@ theorem Icc_subset_uIcc : Icc a b ⊆ [[a, b]] := theorem Icc_subset_uIcc' : Icc b a ⊆ [[a, b]] := Icc_subset_Icc inf_le_right le_sup_left --- porting note (#10618): simp can prove this --- @[simp] theorem left_mem_uIcc : a ∈ [[a, b]] := mem_Icc.2 ⟨inf_le_left, le_sup_left⟩ --- porting note (#10618): simp can prove this --- @[simp] theorem right_mem_uIcc : b ∈ [[a, b]] := mem_Icc.2 ⟨inf_le_right, le_sup_right⟩ @@ -933,7 +883,7 @@ lemma transGen_wcovBy_of_le [Preorder α] [LocallyFiniteOrder α] {x y : α} (hx TransGen (· ⩿ ·) x y := by -- We proceed by well-founded induction on the cardinality of `Icc x y`. -- It's impossible for the cardinality to be zero since `x ≤ y` - have : (Ico x y).card < (Icc x y).card := card_lt_card <| + have : #(Ico x y) < #(Icc x y) := card_lt_card <| ⟨Ico_subset_Icc_self, not_subset.mpr ⟨y, ⟨right_mem_Icc.mpr hxy, right_not_mem_Ico⟩⟩⟩ by_cases hxy' : y ≤ x -- If `y ≤ x`, then `x ⩿ y` @@ -943,16 +893,15 @@ lemma transGen_wcovBy_of_le [Preorder α] [LocallyFiniteOrder α] {x y : α} (hx induction hypothesis to show that `Relation.TransGen (· ⩿ ·) x z`. -/ · have h_non : (Ico x y).Nonempty := ⟨x, mem_Ico.mpr ⟨le_rfl, lt_of_le_not_le hxy hxy'⟩⟩ obtain ⟨z, z_mem, hz⟩ := (Ico x y).exists_maximal h_non - have z_card : (Icc x z).card <(Icc x y).card := calc - (Icc x z).card ≤ (Ico x y).card := - card_le_card <| Icc_subset_Ico_right (mem_Ico.mp z_mem).2 - _ < (Icc x y).card := this + have z_card := calc + #(Icc x z) ≤ #(Ico x y) := card_le_card <| Icc_subset_Ico_right (mem_Ico.mp z_mem).2 + _ < #(Icc x y) := this have h₁ := transGen_wcovBy_of_le (mem_Ico.mp z_mem).1 have h₂ : z ⩿ y := by refine ⟨(mem_Ico.mp z_mem).2.le, fun c hzc hcy ↦ hz c ?_ hzc⟩ exact mem_Ico.mpr <| ⟨(mem_Ico.mp z_mem).1.trans hzc.le, hcy⟩ exact .tail h₁ h₂ -termination_by (Icc x y).card +termination_by #(Icc x y) /-- In a locally finite preorder, `≤` is the transitive closure of `⩿`. -/ lemma le_iff_transGen_wcovBy [Preorder α] [LocallyFiniteOrder α] {x y : α} : @@ -976,7 +925,7 @@ lemma transGen_covBy_of_lt [Preorder α] [LocallyFiniteOrder α] {x y : α} (hxy -- `Ico x y` is a nonempty finset and so contains a maximal element `z` and -- `Ico x z` has cardinality strictly less than the cardinality of `Ico x y` obtain ⟨z, z_mem, hz⟩ := (Ico x y).exists_maximal h_non - have z_card : (Ico x z).card < (Ico x y).card := card_lt_card <| ssubset_iff_of_subset + have z_card : #(Ico x z) < #(Ico x y) := card_lt_card <| ssubset_iff_of_subset (Ico_subset_Ico le_rfl (mem_Ico.mp z_mem).2.le) |>.mpr ⟨z, z_mem, right_not_mem_Ico⟩ /- Since `z` is maximal in `Ico x y`, `z ⋖ y`. -/ have hzy : z ⋖ y := by @@ -990,7 +939,7 @@ lemma transGen_covBy_of_lt [Preorder α] [LocallyFiniteOrder α] {x y : α} (hxy `x ≤ z`), and since `z ⋖ y` we conclude that `x ⋖ y` , then `Relation.TransGen.single`. -/ · simp only [lt_iff_le_not_le, not_and, not_not] at hxz exact .single (hzy.of_le_of_lt (hxz (mem_Ico.mp z_mem).1) hxy) -termination_by (Ico x y).card +termination_by #(Ico x y) /-- In a locally finite preorder, `<` is the transitive closure of `⋖`. -/ lemma lt_iff_transGen_covBy [Preorder α] [LocallyFiniteOrder α] {x y : α} : diff --git a/Mathlib/Order/Interval/Finset/Box.lean b/Mathlib/Order/Interval/Finset/Box.lean index ae26532a1a735..902ac28210bbd 100644 --- a/Mathlib/Order/Interval/Finset/Box.lean +++ b/Mathlib/Order/Interval/Finset/Box.lean @@ -65,9 +65,9 @@ variable {α β : Type*} [OrderedRing α] [OrderedRing β] [LocallyFiniteOrder [DecidableEq α] [DecidableEq β] [@DecidableRel (α × β) (· ≤ ·)] @[simp] lemma card_box_succ (n : ℕ) : - (box (n + 1) : Finset (α × β)).card = - (Icc (-n.succ : α) n.succ).card * (Icc (-n.succ : β) n.succ).card - - (Icc (-n : α) n).card * (Icc (-n : β) n).card := by + #(box (n + 1) : Finset (α × β)) = + #(Icc (-n.succ : α) n.succ) * #(Icc (-n.succ : β) n.succ) - + #(Icc (-n : α) n) * #(Icc (-n : β) n) := by rw [box_succ_eq_sdiff, card_sdiff (Icc_neg_mono n.le_succ), Finset.card_Icc_prod, Finset.card_Icc_prod] rfl @@ -81,7 +81,7 @@ variable {n : ℕ} {x : ℤ × ℤ} attribute [norm_cast] toNat_ofNat -lemma card_box : ∀ {n}, n ≠ 0 → (box n : Finset (ℤ × ℤ)).card = 8 * n +lemma card_box : ∀ {n}, n ≠ 0 → #(box n : Finset (ℤ × ℤ)) = 8 * n | n + 1, _ => by simp_rw [Prod.card_box_succ, card_Icc, sub_neg_eq_add] norm_cast diff --git a/Mathlib/Order/Interval/Finset/Defs.lean b/Mathlib/Order/Interval/Finset/Defs.lean index 0a306c3345be5..625bd3be33b31 100644 --- a/Mathlib/Order/Interval/Finset/Defs.lean +++ b/Mathlib/Order/Interval/Finset/Defs.lean @@ -70,7 +70,7 @@ Provide the `LocallyFiniteOrder` instance for `α →₀ β` where `β` is local From `LinearOrder α`, `NoMaxOrder α`, `LocallyFiniteOrder α`, we can also define an order isomorphism `α ≃ ℕ` or `α ≃ ℤ`, depending on whether we have `OrderBot α` or -`NoMinOrder α` and `Nonempty α`. When `OrderBot α`, we can match `a : α` to `(Iio a).card`. +`NoMinOrder α` and `Nonempty α`. When `OrderBot α`, we can match `a : α` to `#(Iio a)`. We can provide `SuccOrder α` from `LinearOrder α` and `LocallyFiniteOrder α` using @@ -146,79 +146,76 @@ the ends. As opposed to `LocallyFiniteOrder.ofIcc`, this one requires `Decidable only `Preorder`. -/ def LocallyFiniteOrder.ofIcc' (α : Type*) [Preorder α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (finsetIcc : α → α → Finset α) (mem_Icc : ∀ a b x, x ∈ finsetIcc a b ↔ a ≤ x ∧ x ≤ b) : - LocallyFiniteOrder α := - { finsetIcc - finsetIco := fun a b => (finsetIcc a b).filter fun x => ¬b ≤ x - finsetIoc := fun a b => (finsetIcc a b).filter fun x => ¬x ≤ a - finsetIoo := fun a b => (finsetIcc a b).filter fun x => ¬x ≤ a ∧ ¬b ≤ x - finset_mem_Icc := mem_Icc - finset_mem_Ico := fun a b x => by rw [Finset.mem_filter, mem_Icc, and_assoc, lt_iff_le_not_le] - finset_mem_Ioc := fun a b x => by - rw [Finset.mem_filter, mem_Icc, and_right_comm, lt_iff_le_not_le] - finset_mem_Ioo := fun a b x => by - rw [Finset.mem_filter, mem_Icc, and_and_and_comm, lt_iff_le_not_le, lt_iff_le_not_le] } + LocallyFiniteOrder α where + finsetIcc := finsetIcc + finsetIco a b := {x ∈ finsetIcc a b | ¬b ≤ x} + finsetIoc a b := {x ∈ finsetIcc a b | ¬x ≤ a} + finsetIoo a b := {x ∈ finsetIcc a b | ¬x ≤ a ∧ ¬b ≤ x} + finset_mem_Icc := mem_Icc + finset_mem_Ico a b x := by rw [Finset.mem_filter, mem_Icc, and_assoc, lt_iff_le_not_le] + finset_mem_Ioc a b x := by rw [Finset.mem_filter, mem_Icc, and_right_comm, lt_iff_le_not_le] + finset_mem_Ioo a b x := by + rw [Finset.mem_filter, mem_Icc, and_and_and_comm, lt_iff_le_not_le, lt_iff_le_not_le] /-- A constructor from a definition of `Finset.Icc` alone, the other ones being derived by removing the ends. As opposed to `LocallyFiniteOrder.ofIcc'`, this one requires `PartialOrder` but only `DecidableEq`. -/ def LocallyFiniteOrder.ofIcc (α : Type*) [PartialOrder α] [DecidableEq α] (finsetIcc : α → α → Finset α) (mem_Icc : ∀ a b x, x ∈ finsetIcc a b ↔ a ≤ x ∧ x ≤ b) : - LocallyFiniteOrder α := - { finsetIcc - finsetIco := fun a b => (finsetIcc a b).filter fun x => x ≠ b - finsetIoc := fun a b => (finsetIcc a b).filter fun x => a ≠ x - finsetIoo := fun a b => (finsetIcc a b).filter fun x => a ≠ x ∧ x ≠ b - finset_mem_Icc := mem_Icc - finset_mem_Ico := fun a b x => by rw [Finset.mem_filter, mem_Icc, and_assoc, lt_iff_le_and_ne] - finset_mem_Ioc := fun a b x => by - rw [Finset.mem_filter, mem_Icc, and_right_comm, lt_iff_le_and_ne] - finset_mem_Ioo := fun a b x => by - rw [Finset.mem_filter, mem_Icc, and_and_and_comm, lt_iff_le_and_ne, lt_iff_le_and_ne] } + LocallyFiniteOrder α where + finsetIcc := finsetIcc + finsetIco a b := {x ∈ finsetIcc a b | x ≠ b} + finsetIoc a b := {x ∈ finsetIcc a b | a ≠ x} + finsetIoo a b := {x ∈ finsetIcc a b | a ≠ x ∧ x ≠ b} + finset_mem_Icc := mem_Icc + finset_mem_Ico a b x := by rw [Finset.mem_filter, mem_Icc, and_assoc, lt_iff_le_and_ne] + finset_mem_Ioc a b x := by rw [Finset.mem_filter, mem_Icc, and_right_comm, lt_iff_le_and_ne] + finset_mem_Ioo a b x := by + rw [Finset.mem_filter, mem_Icc, and_and_and_comm, lt_iff_le_and_ne, lt_iff_le_and_ne] /-- A constructor from a definition of `Finset.Ici` alone, the other ones being derived by removing the ends. As opposed to `LocallyFiniteOrderTop.ofIci`, this one requires `DecidableRel (· ≤ ·)` but only `Preorder`. -/ def LocallyFiniteOrderTop.ofIci' (α : Type*) [Preorder α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (finsetIci : α → Finset α) (mem_Ici : ∀ a x, x ∈ finsetIci a ↔ a ≤ x) : - LocallyFiniteOrderTop α := - { finsetIci - finsetIoi := fun a => (finsetIci a).filter fun x => ¬x ≤ a - finset_mem_Ici := mem_Ici - finset_mem_Ioi := fun a x => by rw [mem_filter, mem_Ici, lt_iff_le_not_le] } + LocallyFiniteOrderTop α where + finsetIci := finsetIci + finsetIoi a := {x ∈ finsetIci a | ¬x ≤ a} + finset_mem_Ici := mem_Ici + finset_mem_Ioi a x := by rw [mem_filter, mem_Ici, lt_iff_le_not_le] /-- A constructor from a definition of `Finset.Ici` alone, the other ones being derived by removing the ends. As opposed to `LocallyFiniteOrderTop.ofIci'`, this one requires `PartialOrder` but only `DecidableEq`. -/ def LocallyFiniteOrderTop.ofIci (α : Type*) [PartialOrder α] [DecidableEq α] (finsetIci : α → Finset α) (mem_Ici : ∀ a x, x ∈ finsetIci a ↔ a ≤ x) : - LocallyFiniteOrderTop α := - { finsetIci - finsetIoi := fun a => (finsetIci a).filter fun x => a ≠ x - finset_mem_Ici := mem_Ici - finset_mem_Ioi := fun a x => by rw [mem_filter, mem_Ici, lt_iff_le_and_ne] } + LocallyFiniteOrderTop α where + finsetIci := finsetIci + finsetIoi a := {x ∈ finsetIci a | a ≠ x} + finset_mem_Ici := mem_Ici + finset_mem_Ioi a x := by rw [mem_filter, mem_Ici, lt_iff_le_and_ne] /-- A constructor from a definition of `Finset.Iic` alone, the other ones being derived by removing the ends. As opposed to `LocallyFiniteOrderBot.ofIic`, this one requires `DecidableRel (· ≤ ·)` but only `Preorder`. -/ def LocallyFiniteOrderBot.ofIic' (α : Type*) [Preorder α] [DecidableRel ((· ≤ ·) : α → α → Prop)] (finsetIic : α → Finset α) (mem_Iic : ∀ a x, x ∈ finsetIic a ↔ x ≤ a) : - LocallyFiniteOrderBot α := - { finsetIic - finsetIio := fun a => (finsetIic a).filter fun x => ¬a ≤ x - finset_mem_Iic := mem_Iic - finset_mem_Iio := fun a x => by rw [mem_filter, mem_Iic, lt_iff_le_not_le] } + LocallyFiniteOrderBot α where + finsetIic := finsetIic + finsetIio a := {x ∈ finsetIic a | ¬a ≤ x} + finset_mem_Iic := mem_Iic + finset_mem_Iio a x := by rw [mem_filter, mem_Iic, lt_iff_le_not_le] /-- A constructor from a definition of `Finset.Iic` alone, the other ones being derived by removing the ends. As opposed to `LocallyFiniteOrderBot.ofIic'`, this one requires `PartialOrder` but only `DecidableEq`. -/ def LocallyFiniteOrderBot.ofIic (α : Type*) [PartialOrder α] [DecidableEq α] (finsetIic : α → Finset α) (mem_Iic : ∀ a x, x ∈ finsetIic a ↔ x ≤ a) : - LocallyFiniteOrderBot α := - { finsetIic - finsetIio := fun a => (finsetIic a).filter fun x => x ≠ a - finset_mem_Iic := mem_Iic - finset_mem_Iio := fun a x => by rw [mem_filter, mem_Iic, lt_iff_le_and_ne] } --- Note: this was in the wrong namespace in Mathlib 3. + LocallyFiniteOrderBot α where + finsetIic := finsetIic + finsetIio a := {x ∈ finsetIic a | x ≠ a} + finset_mem_Iic := mem_Iic + finset_mem_Iio a x := by rw [mem_filter, mem_Iic, lt_iff_le_and_ne] variable {α β : Type*} @@ -271,23 +268,23 @@ section LocallyFiniteOrder variable [LocallyFiniteOrder α] {a b x : α} -/-- The finset of elements `x` such that `a ≤ x` and `x ≤ b`. Basically `Set.Icc a b` as a finset. --/ +/-- The finset $[a, b]$ of elements `x` such that `a ≤ x` and `x ≤ b`. Basically `Set.Icc a b` as a +finset. -/ def Icc (a b : α) : Finset α := LocallyFiniteOrder.finsetIcc a b -/-- The finset of elements `x` such that `a ≤ x` and `x < b`. Basically `Set.Ico a b` as a finset. --/ +/-- The finset $[a, b)$ of elements `x` such that `a ≤ x` and `x < b`. Basically `Set.Ico a b` as a +finset. -/ def Ico (a b : α) : Finset α := LocallyFiniteOrder.finsetIco a b -/-- The finset of elements `x` such that `a < x` and `x ≤ b`. Basically `Set.Ioc a b` as a finset. --/ +/-- The finset $(a, b]$ of elements `x` such that `a < x` and `x ≤ b`. Basically `Set.Ioc a b` as a +finset. -/ def Ioc (a b : α) : Finset α := LocallyFiniteOrder.finsetIoc a b -/-- The finset of elements `x` such that `a < x` and `x < b`. Basically `Set.Ioo a b` as a finset. --/ +/-- The finset $(a, b)$ of elements `x` such that `a < x` and `x < b`. Basically `Set.Ioo a b` as a +finset. -/ def Ioo (a b : α) : Finset α := LocallyFiniteOrder.finsetIoo a b @@ -329,11 +326,11 @@ section LocallyFiniteOrderTop variable [LocallyFiniteOrderTop α] {a x : α} -/-- The finset of elements `x` such that `a ≤ x`. Basically `Set.Ici a` as a finset. -/ +/-- The finset $[a, ∞)$ of elements `x` such that `a ≤ x`. Basically `Set.Ici a` as a finset. -/ def Ici (a : α) : Finset α := LocallyFiniteOrderTop.finsetIci a -/-- The finset of elements `x` such that `a < x`. Basically `Set.Ioi a` as a finset. -/ +/-- The finset $(a, ∞)$ of elements `x` such that `a < x`. Basically `Set.Ioi a` as a finset. -/ def Ioi (a : α) : Finset α := LocallyFiniteOrderTop.finsetIoi a @@ -359,13 +356,13 @@ section LocallyFiniteOrderBot variable [LocallyFiniteOrderBot α] {a x : α} -/-- The finset of elements `x` such that `a ≤ x`. Basically `Set.Iic a` as a finset. -/ -def Iic (a : α) : Finset α := - LocallyFiniteOrderBot.finsetIic a +/-- The finset $(-∞, b]$ of elements `x` such that `x ≤ b`. Basically `Set.Iic b` as a finset. -/ +def Iic (b : α) : Finset α := + LocallyFiniteOrderBot.finsetIic b -/-- The finset of elements `x` such that `a < x`. Basically `Set.Iio a` as a finset. -/ -def Iio (a : α) : Finset α := - LocallyFiniteOrderBot.finsetIio a +/-- The finset $(-∞, b)$ of elements `x` such that `x < b`. Basically `Set.Iio b` as a finset. -/ +def Iio (b : α) : Finset α := + LocallyFiniteOrderBot.finsetIio b @[simp] theorem mem_Iic : x ∈ Iic a ↔ x ≤ a := @@ -786,8 +783,8 @@ lemma Finset.Icc_prod_def (x y : α × β) : Icc x y = Icc x.1 y.1 ×ˢ Icc x.2 lemma Finset.Icc_product_Icc (a₁ a₂ : α) (b₁ b₂ : β) : Icc a₁ a₂ ×ˢ Icc b₁ b₂ = Icc (a₁, b₁) (a₂, b₂) := rfl -lemma Finset.card_Icc_prod (x y : α × β) : - (Icc x y).card = (Icc x.1 y.1).card * (Icc x.2 y.2).card := card_product _ _ +lemma Finset.card_Icc_prod (x y : α × β) : #(Icc x y) = #(Icc x.1 y.1) * #(Icc x.2 y.2) := + card_product .. end LocallyFiniteOrder @@ -800,7 +797,7 @@ instance Prod.instLocallyFiniteOrderTop : LocallyFiniteOrderTop (α × β) := lemma Finset.Ici_prod_def (x : α × β) : Ici x = Ici x.1 ×ˢ Ici x.2 := rfl lemma Finset.Ici_product_Ici (a : α) (b : β) : Ici a ×ˢ Ici b = Ici (a, b) := rfl -lemma Finset.card_Ici_prod (x : α × β) : (Ici x).card = (Ici x.1).card * (Ici x.2).card := +lemma Finset.card_Ici_prod (x : α × β) : #(Ici x) = #(Ici x.1) * #(Ici x.2) := card_product _ _ end LocallyFiniteOrderTop @@ -814,8 +811,7 @@ instance Prod.instLocallyFiniteOrderBot : LocallyFiniteOrderBot (α × β) := lemma Finset.Iic_prod_def (x : α × β) : Iic x = Iic x.1 ×ˢ Iic x.2 := rfl lemma Finset.Iic_product_Iic (a : α) (b : β) : Iic a ×ˢ Iic b = Iic (a, b) := rfl -lemma Finset.card_Iic_prod (x : α × β) : (Iic x).card = (Iic x.1).card * (Iic x.2).card := - card_product _ _ +lemma Finset.card_Iic_prod (x : α × β) : #(Iic x) = #(Iic x.1) * #(Iic x.2) := card_product .. end LocallyFiniteOrderBot end Preorder @@ -829,8 +825,8 @@ lemma Finset.uIcc_prod_def (x y : α × β) : uIcc x y = uIcc x.1 y.1 ×ˢ uIcc lemma Finset.uIcc_product_uIcc (a₁ a₂ : α) (b₁ b₂ : β) : uIcc a₁ a₂ ×ˢ uIcc b₁ b₂ = uIcc (a₁, b₁) (a₂, b₂) := rfl -lemma Finset.card_uIcc_prod (x y : α × β) : - (uIcc x y).card = (uIcc x.1 y.1).card * (uIcc x.2 y.2).card := card_product _ _ +lemma Finset.card_uIcc_prod (x y : α × β) : #(uIcc x y) = #(uIcc x.1 y.1) * #(uIcc x.2 y.2) := + card_product .. end Lattice @@ -875,8 +871,8 @@ instance locallyFiniteOrder : LocallyFiniteOrder (WithTop α) where -- Porting note: the proofs below got much worse finset_mem_Icc a b x := match a, b, x with - | ⊤, ⊤, x => mem_singleton.trans (le_antisymm_iff.trans and_comm) - | ⊤, (b : α), x => + | ⊤, ⊤, _ => mem_singleton.trans (le_antisymm_iff.trans and_comm) + | ⊤, (b : α), _ => iff_of_false (not_mem_empty _) fun h => (h.1.trans h.2).not_lt <| coe_lt_top _ | (a : α), ⊤, ⊤ => by simp [WithTop.some, WithTop.top, insertNone] | (a : α), ⊤, (x : α) => by @@ -891,7 +887,7 @@ instance locallyFiniteOrder : LocallyFiniteOrder (WithTop α) where erw [aux] finset_mem_Ico a b x := match a, b, x with - | ⊤, b, x => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans_lt h.2 + | ⊤, _, _ => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans_lt h.2 | (a : α), ⊤, ⊤ => by simp [some, Embedding.some] | (a : α), ⊤, (x : α) => by simp only [Embedding.some, mem_map, mem_Ici, Embedding.coeFn_mk, coe_le_coe, aux, @@ -905,7 +901,7 @@ instance locallyFiniteOrder : LocallyFiniteOrder (WithTop α) where erw [aux] finset_mem_Ioc a b x := match a, b, x with - | ⊤, b, x => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans_le h.2 + | ⊤, _, _ => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans_le h.2 | (a : α), ⊤, ⊤ => by simp [some, insertNone, top] | (a : α), ⊤, (x : α) => by simp [some, Embedding.some, insertNone, aux] -- This used to be in the above `simp` before @@ -918,7 +914,7 @@ instance locallyFiniteOrder : LocallyFiniteOrder (WithTop α) where erw [aux] finset_mem_Ioo a b x := match a, b, x with - | ⊤, b, x => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans h.2 + | ⊤, _, _ => iff_of_false (not_mem_empty _) fun h => not_top_lt <| h.1.trans h.2 | (a : α), ⊤, ⊤ => by simp [some, Embedding.some, insertNone] | (a : α), ⊤, (x : α) => by simp [some, Embedding.some, insertNone, aux, top] -- This used to be in the above `simp` before diff --git a/Mathlib/Order/Interval/Finset/Fin.lean b/Mathlib/Order/Interval/Finset/Fin.lean index f0a6f5f7b6aef..6bf13b1b52462 100644 --- a/Mathlib/Order/Interval/Finset/Fin.lean +++ b/Mathlib/Order/Interval/Finset/Fin.lean @@ -85,42 +85,30 @@ theorem map_subtype_embedding_uIcc : (uIcc a b).map valEmbedding = uIcc ↑a ↑ map_valEmbedding_Icc _ _ @[simp] -theorem card_Icc : (Icc a b).card = b + 1 - a := by - rw [← Nat.card_Icc, ← map_valEmbedding_Icc, card_map] +lemma card_Icc : #(Icc a b) = b + 1 - a := by rw [← Nat.card_Icc, ← map_valEmbedding_Icc, card_map] @[simp] -theorem card_Ico : (Ico a b).card = b - a := by - rw [← Nat.card_Ico, ← map_valEmbedding_Ico, card_map] +lemma card_Ico : #(Ico a b) = b - a := by rw [← Nat.card_Ico, ← map_valEmbedding_Ico, card_map] @[simp] -theorem card_Ioc : (Ioc a b).card = b - a := by - rw [← Nat.card_Ioc, ← map_valEmbedding_Ioc, card_map] +lemma card_Ioc : #(Ioc a b) = b - a := by rw [← Nat.card_Ioc, ← map_valEmbedding_Ioc, card_map] @[simp] -theorem card_Ioo : (Ioo a b).card = b - a - 1 := by - rw [← Nat.card_Ioo, ← map_valEmbedding_Ioo, card_map] +lemma card_Ioo : #(Ioo a b) = b - a - 1 := by rw [← Nat.card_Ioo, ← map_valEmbedding_Ioo, card_map] @[simp] -theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := by +theorem card_uIcc : #(uIcc a b) = (b - a : ℤ).natAbs + 1 := by rw [← Nat.card_uIcc, ← map_subtype_embedding_uIcc, card_map] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIcc : Fintype.card (Set.Icc a b) = b + 1 - a := by rw [← card_Icc, Fintype.card_ofFinset] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIco : Fintype.card (Set.Ico a b) = b - a := by rw [← card_Ico, Fintype.card_ofFinset] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIoc : Fintype.card (Set.Ioc a b) = b - a := by rw [← card_Ioc, Fintype.card_ofFinset] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIoo : Fintype.card (Set.Ioo a b) = b - a - 1 := by rw [← card_Ioo, Fintype.card_ofFinset] @@ -172,41 +160,30 @@ theorem map_valEmbedding_Iio : (Iio b).map Fin.valEmbedding = Iio ↑b := by simp [Iio_eq_finset_subtype, Finset.fin, Finset.map_map] @[simp] -theorem card_Ici : (Ici a).card = n - a := by +theorem card_Ici : #(Ici a) = n - a := by cases n with | zero => exact Fin.elim0 a | succ => rw [← card_map, map_valEmbedding_Ici, Nat.card_Icc, Nat.add_one_sub_one] @[simp] -theorem card_Ioi : (Ioi a).card = n - 1 - a := by - rw [← card_map, map_valEmbedding_Ioi, Nat.card_Ioc] +theorem card_Ioi : #(Ioi a) = n - 1 - a := by rw [← card_map, map_valEmbedding_Ioi, Nat.card_Ioc] @[simp] -theorem card_Iic : (Iic b).card = b + 1 := by - rw [← Nat.card_Iic b, ← map_valEmbedding_Iic, card_map] +theorem card_Iic : #(Iic b) = b + 1 := by rw [← Nat.card_Iic b, ← map_valEmbedding_Iic, card_map] @[simp] -theorem card_Iio : (Iio b).card = b := by - rw [← Nat.card_Iio b, ← map_valEmbedding_Iio, card_map] +theorem card_Iio : #(Iio b) = b := by rw [← Nat.card_Iio b, ← map_valEmbedding_Iio, card_map] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIci : Fintype.card (Set.Ici a) = n - a := by rw [Fintype.card_ofFinset, card_Ici] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIoi : Fintype.card (Set.Ioi a) = n - 1 - a := by rw [Fintype.card_ofFinset, card_Ioi] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIic : Fintype.card (Set.Iic b) = b + 1 := by rw [Fintype.card_ofFinset, card_Iic] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIio : Fintype.card (Set.Iio b) = b := by rw [Fintype.card_ofFinset, card_Iio] diff --git a/Mathlib/Order/Interval/Finset/Nat.lean b/Mathlib/Order/Interval/Finset/Nat.lean index 8be56194d6481..e23c82c9f5caa 100644 --- a/Mathlib/Order/Interval/Finset/Nat.lean +++ b/Mathlib/Order/Interval/Finset/Nat.lean @@ -65,59 +65,36 @@ lemma range_eq_Icc_zero_sub_one (n : ℕ) (hn : n ≠ 0) : range n = Icc 0 (n - theorem _root_.Finset.range_eq_Ico : range = Ico 0 := Ico_zero_eq_range.symm -@[simp] -theorem card_Icc : (Icc a b).card = b + 1 - a := - List.length_range' _ _ _ - -@[simp] -theorem card_Ico : (Ico a b).card = b - a := - List.length_range' _ _ _ - -@[simp] -theorem card_Ioc : (Ioc a b).card = b - a := - List.length_range' _ _ _ - -@[simp] -theorem card_Ioo : (Ioo a b).card = b - a - 1 := - List.length_range' _ _ _ +@[simp] lemma card_Icc : #(Icc a b) = b + 1 - a := List.length_range' .. +@[simp] lemma card_Ico : #(Ico a b) = b - a := List.length_range' .. +@[simp] lemma card_Ioc : #(Ioc a b) = b - a := List.length_range' .. +@[simp] lemma card_Ioo : #(Ioo a b) = b - a - 1 := List.length_range' .. @[simp] -theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := +theorem card_uIcc : #(uIcc a b) = (b - a : ℤ).natAbs + 1 := (card_Icc _ _).trans <| by rw [← Int.natCast_inj, sup_eq_max, inf_eq_min, Int.ofNat_sub] <;> omega @[simp] -lemma card_Iic : (Iic b).card = b + 1 := by rw [Iic_eq_Icc, card_Icc, Nat.bot_eq_zero, Nat.sub_zero] +lemma card_Iic : #(Iic b) = b + 1 := by rw [Iic_eq_Icc, card_Icc, Nat.bot_eq_zero, Nat.sub_zero] @[simp] -theorem card_Iio : (Iio b).card = b := by rw [Iio_eq_Ico, card_Ico, Nat.bot_eq_zero, Nat.sub_zero] +theorem card_Iio : #(Iio b) = b := by rw [Iio_eq_Ico, card_Ico, Nat.bot_eq_zero, Nat.sub_zero] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIcc : Fintype.card (Set.Icc a b) = b + 1 - a := by rw [Fintype.card_ofFinset, card_Icc] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIco : Fintype.card (Set.Ico a b) = b - a := by rw [Fintype.card_ofFinset, card_Ico] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIoc : Fintype.card (Set.Ioc a b) = b - a := by rw [Fintype.card_ofFinset, card_Ioc] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIoo : Fintype.card (Set.Ioo a b) = b - a - 1 := by rw [Fintype.card_ofFinset, card_Ioo] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIic : Fintype.card (Set.Iic b) = b + 1 := by rw [Fintype.card_ofFinset, card_Iic] --- Porting note (#10618): simp can prove this --- @[simp] theorem card_fintypeIio : Fintype.card (Set.Iio b) = b := by rw [Fintype.card_ofFinset, card_Iio] -- TODO@Yaël: Generalize all the following lemmas to `SuccOrder` diff --git a/Mathlib/Order/Interval/Multiset.lean b/Mathlib/Order/Interval/Multiset.lean index b8aafdc08f17c..28d6b71306ac8 100644 --- a/Mathlib/Order/Interval/Multiset.lean +++ b/Mathlib/Order/Interval/Multiset.lean @@ -156,13 +156,10 @@ theorem Ioo_eq_zero_of_le (h : b ≤ a) : Ioo a b = 0 := variable (a) --- Porting note (#10618): simp can prove this -- @[simp] theorem Ico_self : Ico a a = 0 := by rw [Ico, Finset.Ico_self, Finset.empty_val] --- Porting note (#10618): simp can prove this -- @[simp] theorem Ioc_self : Ioc a a = 0 := by rw [Ioc, Finset.Ioc_self, Finset.empty_val] --- Porting note (#10618): simp can prove this -- @[simp] theorem Ioo_self : Ioo a a = 0 := by rw [Ioo, Finset.Ioo_self, Finset.empty_val] variable {a} @@ -179,19 +176,15 @@ theorem right_mem_Icc : b ∈ Icc a b ↔ a ≤ b := theorem right_mem_Ioc : b ∈ Ioc a b ↔ a < b := Finset.right_mem_Ioc --- Porting note (#10618): simp can prove this -- @[simp] theorem left_not_mem_Ioc : a ∉ Ioc a b := Finset.left_not_mem_Ioc --- Porting note (#10618): simp can prove this -- @[simp] theorem left_not_mem_Ioo : a ∉ Ioo a b := Finset.left_not_mem_Ioo --- Porting note (#10618): simp can prove this -- @[simp] theorem right_not_mem_Ico : b ∉ Ico a b := Finset.right_not_mem_Ico --- Porting note (#10618): simp can prove this -- @[simp] theorem right_not_mem_Ioo : b ∉ Ioo a b := Finset.right_not_mem_Ioo diff --git a/Mathlib/Order/Interval/Set/Basic.lean b/Mathlib/Order/Interval/Set/Basic.lean index 66feeca1fd5ef..0c9a2428277fb 100644 --- a/Mathlib/Order/Interval/Set/Basic.lean +++ b/Mathlib/Order/Interval/Set/Basic.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot, Yury Kudryashov, Rémy import Mathlib.Order.MinMax import Mathlib.Data.Set.Subsingleton import Mathlib.Tactic.Says +import Mathlib.Tactic.Contrapose /-! # Intervals @@ -38,35 +39,35 @@ section Preorder variable [Preorder α] {a a₁ a₂ b b₁ b₂ c x : α} -/-- Left-open right-open interval -/ +/-- `Ioo a b` is the left-open right-open interval $(a, b)$. -/ def Ioo (a b : α) := { x | a < x ∧ x < b } -/-- Left-closed right-open interval -/ +/-- `Ico a b` is the left-closed right-open interval $[a, b)$. -/ def Ico (a b : α) := { x | a ≤ x ∧ x < b } -/-- Left-infinite right-open interval -/ -def Iio (a : α) := - { x | x < a } +/-- `Iio b` is the left-infinite right-open interval $(-∞, b)$. -/ +def Iio (b : α) := + { x | x < b } -/-- Left-closed right-closed interval -/ +/-- `Icc a b` is the left-closed right-closed interval $[a, b]$. -/ def Icc (a b : α) := { x | a ≤ x ∧ x ≤ b } -/-- Left-infinite right-closed interval -/ +/-- `Iic b` is the left-infinite right-closed interval $(-∞, b]$. -/ def Iic (b : α) := { x | x ≤ b } -/-- Left-open right-closed interval -/ +/-- `Ioc a b` is the left-open right-closed interval $(a, b]$. -/ def Ioc (a b : α) := { x | a < x ∧ x ≤ b } -/-- Left-closed right-infinite interval -/ +/-- `Ici a` is the left-closed right-infinite interval $[a, ∞)$. -/ def Ici (a : α) := { x | a ≤ x } -/-- Left-open right-infinite interval -/ +/-- `Ioi a` is the left-open right-infinite interval $(a, ∞)$. -/ def Ioi (a : α) := { x | a < x } @@ -142,38 +143,22 @@ instance decidableMemIci [Decidable (a ≤ x)] : Decidable (x ∈ Ici a) := by a instance decidableMemIoi [Decidable (a < x)] : Decidable (x ∈ Ioi a) := by assumption --- Porting note (#10618): `simp` can prove this --- @[simp] theorem left_mem_Ioo : a ∈ Ioo a b ↔ False := by simp [lt_irrefl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem left_mem_Ico : a ∈ Ico a b ↔ a < b := by simp [le_refl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem left_mem_Icc : a ∈ Icc a b ↔ a ≤ b := by simp [le_refl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem left_mem_Ioc : a ∈ Ioc a b ↔ False := by simp [lt_irrefl] theorem left_mem_Ici : a ∈ Ici a := by simp --- Porting note (#10618): `simp` can prove this --- @[simp] theorem right_mem_Ioo : b ∈ Ioo a b ↔ False := by simp [lt_irrefl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem right_mem_Ico : b ∈ Ico a b ↔ False := by simp [lt_irrefl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem right_mem_Icc : b ∈ Icc a b ↔ a ≤ b := by simp [le_refl] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem right_mem_Ioc : b ∈ Ioc a b ↔ a < b := by simp [le_refl] theorem right_mem_Iic : a ∈ Iic a := by simp @@ -318,18 +303,12 @@ theorem Ioc_eq_empty_of_le (h : b ≤ a) : Ioc a b = ∅ := theorem Ioo_eq_empty_of_le (h : b ≤ a) : Ioo a b = ∅ := Ioo_eq_empty h.not_lt --- Porting note (#10618): `simp` can prove this --- @[simp] theorem Ico_self (a : α) : Ico a a = ∅ := Ico_eq_empty <| lt_irrefl _ --- Porting note (#10618): `simp` can prove this --- @[simp] theorem Ioc_self (a : α) : Ioc a a = ∅ := Ioc_eq_empty <| lt_irrefl _ --- Porting note (#10618): `simp` can prove this --- @[simp] theorem Ioo_self (a : α) : Ioo a a = ∅ := Ioo_eq_empty <| lt_irrefl _ @@ -585,12 +564,8 @@ theorem not_mem_Ico_of_lt (ha : c < a) : c ∉ Ico a b := fun h => ha.not_le h.1 theorem not_mem_Ioc_of_gt (hb : b < c) : c ∉ Ioc a b := fun h => hb.not_le h.2 --- Porting note (#10618): `simp` can prove this --- @[simp] theorem not_mem_Ioi_self : a ∉ Ioi a := lt_irrefl _ --- Porting note (#10618): `simp` can prove this --- @[simp] theorem not_mem_Iio_self : b ∉ Iio b := lt_irrefl _ theorem not_mem_Ioc_of_le (ha : c ≤ a) : c ∉ Ioc a b := fun h => lt_irrefl _ <| h.1.trans_le ha @@ -693,13 +668,9 @@ theorem Ici_diff_Ioi_same : Ici a \ Ioi a = {a} := by theorem Iic_diff_Iio_same : Iic a \ Iio a = {a} := by rw [← Iic_diff_right, diff_diff_cancel_left (singleton_subset_iff.2 right_mem_Iic)] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem Ioi_union_left : Ioi a ∪ {a} = Ici a := ext fun x => by simp [eq_comm, le_iff_eq_or_lt] --- Porting note (#10618): `simp` can prove this --- @[simp] theorem Iio_union_right : Iio a ∪ {a} = Iic a := ext fun _ => le_iff_lt_or_eq.symm @@ -753,7 +724,7 @@ theorem mem_Ici_Ioi_of_subset_of_subset {s : Set α} (ho : Ioi a ⊆ s) (hc : s (fun h : a ∈ s => Or.inl <| Subset.antisymm hc <| by rw [← Ioi_union_left, union_subset_iff]; simp [*]) fun h => - Or.inr <| Subset.antisymm (fun x hx => lt_of_le_of_ne (hc hx) fun heq => h <| heq.symm ▸ hx) ho + Or.inr <| Subset.antisymm (fun _ hx => lt_of_le_of_ne (hc hx) fun heq => h <| heq.symm ▸ hx) ho theorem mem_Iic_Iio_of_subset_of_subset {s : Set α} (ho : Iio a ⊆ s) (hc : s ⊆ Iic a) : s ∈ ({Iic a, Iio a} : Set (Set α)) := @@ -1481,7 +1452,7 @@ end Lattice section LinearOrder -variable [LinearOrder α] [LinearOrder β] {f : α → β} {a a₁ a₂ b b₁ b₂ c d : α} +variable [LinearOrder α] {a a₁ a₂ b b₁ b₂ c : α} @[simp] theorem Ioi_inter_Ioi : Ioi a ∩ Ioi b = Ioi (a ⊔ b) := diff --git a/Mathlib/Order/Interval/Set/Monotone.lean b/Mathlib/Order/Interval/Set/Monotone.lean index 6b8430931f6c7..f2f3f914fb9c1 100644 --- a/Mathlib/Order/Interval/Set/Monotone.lean +++ b/Mathlib/Order/Interval/Set/Monotone.lean @@ -164,58 +164,22 @@ variable {α β : Type*} [PartialOrder α] [Preorder β] {ψ : α → β} /-- A function `ψ` on a `SuccOrder` is strictly monotone before some `n` if for all `m` such that `m < n`, we have `ψ m < ψ (succ m)`. -/ theorem strictMonoOn_Iic_of_lt_succ [SuccOrder α] [IsSuccArchimedean α] {n : α} - (hψ : ∀ m, m < n → ψ m < ψ (succ m)) : StrictMonoOn ψ (Set.Iic n) := by - intro x hx y hy hxy - obtain ⟨i, rfl⟩ := hxy.le.exists_succ_iterate - induction' i with k ih - · simp at hxy - cases' k with k - · exact hψ _ (lt_of_lt_of_le hxy hy) - rw [Set.mem_Iic] at * - simp only [Function.iterate_succ', Function.comp_apply] at ih hxy hy ⊢ - by_cases hmax : IsMax (succ^[k] x) - · rw [succ_eq_iff_isMax.2 hmax] at hxy ⊢ - exact ih (le_trans (le_succ _) hy) hxy - by_cases hmax' : IsMax (succ (succ^[k] x)) - · rw [succ_eq_iff_isMax.2 hmax'] at hxy ⊢ - exact ih (le_trans (le_succ _) hy) hxy - refine - lt_trans - (ih (le_trans (le_succ _) hy) - (lt_of_le_of_lt (le_succ_iterate k _) (lt_succ_iff_not_isMax.2 hmax))) - ?_ - rw [← Function.comp_apply (f := succ), ← Function.iterate_succ'] - refine hψ _ (lt_of_lt_of_le ?_ hy) - rwa [Function.iterate_succ', Function.comp_apply, lt_succ_iff_not_isMax] - -theorem strictMono_of_lt_succ [SuccOrder α] [IsSuccArchimedean α] - (hψ : ∀ m, ψ m < ψ (succ m)) : StrictMono ψ := fun _ _ h ↦ - (strictMonoOn_Iic_of_lt_succ fun m _ ↦ hψ m) h.le le_rfl h + (hψ : ∀ m, m < n → ψ m < ψ (succ m)) : StrictMonoOn ψ (Set.Iic n) := + strictMonoOn_of_lt_succ ordConnected_Iic fun _a ha' _ ha ↦ + hψ _ <| (succ_le_iff_of_not_isMax ha').1 ha theorem strictAntiOn_Iic_of_succ_lt [SuccOrder α] [IsSuccArchimedean α] {n : α} (hψ : ∀ m, m < n → ψ (succ m) < ψ m) : StrictAntiOn ψ (Set.Iic n) := fun i hi j hj hij => @strictMonoOn_Iic_of_lt_succ α βᵒᵈ _ _ ψ _ _ n hψ i hi j hj hij -theorem strictAnti_of_succ_lt [SuccOrder α] [IsSuccArchimedean α] - (hψ : ∀ m, ψ (succ m) < ψ m) : StrictAnti ψ := fun _ _ h ↦ - (strictAntiOn_Iic_of_succ_lt fun m _ ↦ hψ m) h.le le_rfl h - theorem strictMonoOn_Ici_of_pred_lt [PredOrder α] [IsPredArchimedean α] {n : α} (hψ : ∀ m, n < m → ψ (pred m) < ψ m) : StrictMonoOn ψ (Set.Ici n) := fun i hi j hj hij => @strictMonoOn_Iic_of_lt_succ αᵒᵈ βᵒᵈ _ _ ψ _ _ n hψ j hj i hi hij -theorem strictMono_of_pred_lt [PredOrder α] [IsPredArchimedean α] - (hψ : ∀ m, ψ (pred m) < ψ m) : StrictMono ψ := fun _ _ h ↦ - (strictMonoOn_Ici_of_pred_lt fun m _ ↦ hψ m) le_rfl h.le h - theorem strictAntiOn_Ici_of_lt_pred [PredOrder α] [IsPredArchimedean α] {n : α} (hψ : ∀ m, n < m → ψ m < ψ (pred m)) : StrictAntiOn ψ (Set.Ici n) := fun i hi j hj hij => @strictAntiOn_Iic_of_succ_lt αᵒᵈ βᵒᵈ _ _ ψ _ _ n hψ j hj i hi hij -theorem strictAnti_of_lt_pred [PredOrder α] [IsPredArchimedean α] - (hψ : ∀ m, ψ m < ψ (pred m)) : StrictAnti ψ := fun _ _ h ↦ - (strictAntiOn_Ici_of_lt_pred fun m _ ↦ hψ m) le_rfl h.le h - end SuccOrder section LinearOrder diff --git a/Mathlib/Order/Interval/Set/OrdConnected.lean b/Mathlib/Order/Interval/Set/OrdConnected.lean index 85255d6b9f744..cf733bc167f20 100644 --- a/Mathlib/Order/Interval/Set/OrdConnected.lean +++ b/Mathlib/Order/Interval/Set/OrdConnected.lean @@ -27,7 +27,7 @@ namespace Set section Preorder -variable {α β : Type*} [Preorder α] [Preorder β] {s t : Set α} +variable {α β : Type*} [Preorder α] [Preorder β] {s : Set α} /-- We say that a set `s : Set α` is `OrdConnected` if for all `x y ∈ s` it includes the interval `[[x, y]]`. If `α` is a `DenselyOrdered` `ConditionallyCompleteLinearOrder` with @@ -101,7 +101,7 @@ namespace Set section Preorder -variable {α β : Type*} [Preorder α] [Preorder β] {s t : Set α} +variable {α β : Type*} [Preorder α] [Preorder β] @[simp] lemma image_subtype_val_Icc {s : Set α} [OrdConnected s] (x y : s) : diff --git a/Mathlib/Order/Interval/Set/OrderIso.lean b/Mathlib/Order/Interval/Set/OrderIso.lean index e125b788f0d48..b23c2799a05f4 100644 --- a/Mathlib/Order/Interval/Set/OrderIso.lean +++ b/Mathlib/Order/Interval/Set/OrderIso.lean @@ -90,12 +90,12 @@ end Preorder /-- Order isomorphism between `Iic (⊤ : α)` and `α` when `α` has a top element -/ def IicTop {α : Type*} [Preorder α] [OrderTop α] : Iic (⊤ : α) ≃o α := - { @Equiv.subtypeUnivEquiv α (Iic (⊤ : α)) fun x => le_top with + { @Equiv.subtypeUnivEquiv α (Iic (⊤ : α)) fun _ => le_top with map_rel_iff' := @fun x y => by rfl } /-- Order isomorphism between `Ici (⊥ : α)` and `α` when `α` has a bottom element -/ def IciBot {α : Type*} [Preorder α] [OrderBot α] : Ici (⊥ : α) ≃o α := - { @Equiv.subtypeUnivEquiv α (Ici (⊥ : α)) fun x => bot_le with + { @Equiv.subtypeUnivEquiv α (Ici (⊥ : α)) fun _ => bot_le with map_rel_iff' := @fun x y => by rfl } end OrderIso diff --git a/Mathlib/Order/Interval/Set/Pi.lean b/Mathlib/Order/Interval/Set/Pi.lean index 524744496cce6..3d63a7437ca29 100644 --- a/Mathlib/Order/Interval/Set/Pi.lean +++ b/Mathlib/Order/Interval/Set/Pi.lean @@ -51,7 +51,7 @@ theorem piecewise_mem_Icc' {s : Set ι} [∀ j, Decidable (j ∈ s)] {f₁ f₂ section Nonempty -theorem pi_univ_Ioi_subset [Nonempty ι]: (pi univ fun i ↦ Ioi (x i)) ⊆ Ioi x := fun z hz ↦ +theorem pi_univ_Ioi_subset [Nonempty ι]: (pi univ fun i ↦ Ioi (x i)) ⊆ Ioi x := fun _ hz ↦ ⟨fun i ↦ le_of_lt <| hz i trivial, fun h ↦ (‹Nonempty ι›.elim) fun i ↦ not_lt_of_le (h i) (hz i trivial)⟩ diff --git a/Mathlib/Order/Interval/Set/UnorderedInterval.lean b/Mathlib/Order/Interval/Set/UnorderedInterval.lean index ea241a7fbf3dc..22ca451903d02 100644 --- a/Mathlib/Order/Interval/Set/UnorderedInterval.lean +++ b/Mathlib/Order/Interval/Set/UnorderedInterval.lean @@ -74,8 +74,6 @@ lemma uIcc_comm (a b : α) : [[a, b]] = [[b, a]] := by simp_rw [uIcc, inf_comm, lemma uIcc_of_lt (h : a < b) : [[a, b]] = Icc a b := uIcc_of_le h.le lemma uIcc_of_gt (h : b < a) : [[a, b]] = Icc b a := uIcc_of_ge h.le --- Porting note (#10618): `simp` can prove this --- @[simp] lemma uIcc_self : [[a, a]] = {a} := by simp [uIcc] @[simp] lemma nonempty_uIcc : [[a, b]].Nonempty := nonempty_Icc.2 inf_le_sup diff --git a/Mathlib/Order/Irreducible.lean b/Mathlib/Order/Irreducible.lean index ecc3744d96ae4..56f92e33d2c0b 100644 --- a/Mathlib/Order/Irreducible.lean +++ b/Mathlib/Order/Irreducible.lean @@ -161,11 +161,9 @@ theorem InfPrime.inf_le (ha : InfPrime a) : b ⊓ c ≤ a ↔ b ≤ a ∨ c ≤ variable [OrderTop α] {s : Finset ι} {f : ι → α} --- @[simp] Porting note (#10618): simp can prove this. theorem not_infIrred_top : ¬InfIrred (⊤ : α) := isMax_top.not_infIrred --- @[simp] Porting note (#10618): simp can prove this. theorem not_infPrime_top : ¬InfPrime (⊤ : α) := isMax_top.not_infPrime @@ -251,7 +249,7 @@ end SemilatticeInf section DistribLattice -variable [DistribLattice α] {a b c : α} +variable [DistribLattice α] {a : α} @[simp] theorem supPrime_iff_supIrred : SupPrime a ↔ SupIrred a := @@ -263,11 +261,8 @@ theorem infPrime_iff_infIrred : InfPrime a ↔ InfIrred a := ⟨InfPrime.infIrred, And.imp_right fun h b c => by simp_rw [← sup_eq_left, sup_inf_left]; exact @h _ _⟩ -alias ⟨_, SupIrred.supPrime⟩ := supPrime_iff_supIrred - -alias ⟨_, InfIrred.infPrime⟩ := infPrime_iff_infIrred - --- Porting note: was attribute [protected] SupIrred.supPrime InfIrred.infPrime +protected alias ⟨_, SupIrred.supPrime⟩ := supPrime_iff_supIrred +protected alias ⟨_, InfIrred.infPrime⟩ := infPrime_iff_infIrred end DistribLattice @@ -275,11 +270,9 @@ section LinearOrder variable [LinearOrder α] {a : α} --- @[simp] Porting note (#10618): simp can prove this theorem supPrime_iff_not_isMin : SupPrime a ↔ ¬IsMin a := and_iff_left <| by simp --- @[simp] Porting note (#10618): simp can prove thisrove this theorem infPrime_iff_not_isMax : InfPrime a ↔ ¬IsMax a := and_iff_left <| by simp diff --git a/Mathlib/Order/IsWellOrderLimitElement.lean b/Mathlib/Order/IsWellOrderLimitElement.lean deleted file mode 100644 index 2d6bde7b9282b..0000000000000 --- a/Mathlib/Order/IsWellOrderLimitElement.lean +++ /dev/null @@ -1,98 +0,0 @@ -/- -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.Order.Group.Nat -import Mathlib.Order.WellFounded - -/-! -# Limit elements in well-ordered types - -This file introduces two main definitions: -- `wellOrderSucc a`: the successor of an element `a` in a well-ordered type -- the typeclass `IsWellOrderLimitElement a` which asserts that an element `a` (in a -well-ordered type) is neither a successor nor the smallest element, i.e. `a` is a limit element - -Then, the lemma `eq_bot_or_eq_succ_or_isWellOrderLimitElement` shows that an element -in a well-ordered type is either `⊥`, a successor, or a limit element. - --/ - -variable {α : Type*} [LinearOrder α] - -section -variable [IsWellOrder α (· < ·)] - -/-- Given an element `a : α` in a well ordered set, this is the successor of `a`, -i.e. the smallest element strictly greater than `a` if it exists (or `a` itself otherwise). -/ -noncomputable def wellOrderSucc (a : α) : α := - (IsWellFounded.wf (r := (· < ·))).succ a - -lemma self_le_wellOrderSucc (a : α) : a ≤ wellOrderSucc a := by - by_cases h : ∃ b, a < b - · exact (IsWellFounded.wf.lt_succ h).le - · dsimp [wellOrderSucc, WellFounded.succ] - rw [dif_neg h] - -lemma wellOrderSucc_le {a b : α} (ha : a < b) : wellOrderSucc a ≤ b := by - dsimp [wellOrderSucc, WellFounded.succ] - rw [dif_pos ⟨_, ha⟩] - exact WellFounded.min_le _ ha - -lemma self_lt_wellOrderSucc {a b : α} (h : a < b) : a < wellOrderSucc a := - IsWellFounded.wf.lt_succ ⟨b, h⟩ - -lemma le_of_lt_wellOrderSucc {a b : α} (h : a < wellOrderSucc b) : a ≤ b := by - by_contra! - simpa using lt_of_lt_of_le h (wellOrderSucc_le this) - -/-- This property of an element `a : α` in a well-ordered type holds iff `a` is a -limit element, i.e. it is not a successor and it is not the smallest element of `α`. -/ -class IsWellOrderLimitElement (a : α) : Prop where - not_bot : ∃ (b : α), b < a - not_succ (b : α) (hb : b < a) : ∃ (c : α), b < c ∧ c < a - -end - -variable (a : α) [ha : IsWellOrderLimitElement a] - -lemma IsWellOrderLimitElement.neq_bot [OrderBot α] : a ≠ ⊥ := by - rintro rfl - obtain ⟨b, hb⟩ := ha.not_bot - simp at hb - -lemma IsWellOrderLimitElement.bot_lt [OrderBot α] : ⊥ < a := by - obtain h|h := eq_or_lt_of_le (@bot_le _ _ _ a) - · exact (IsWellOrderLimitElement.neq_bot a h.symm).elim - · exact h - -variable {a} -variable [IsWellOrder α (· < ·)] - -lemma IsWellOrderLimitElement.wellOrderSucc_lt {b : α} (hb : b < a) : - wellOrderSucc b < a := by - obtain ⟨c, hc₁, hc₂⟩ := ha.not_succ b hb - exact lt_of_le_of_lt (wellOrderSucc_le hc₁) hc₂ - -lemma eq_bot_or_eq_succ_or_isWellOrderLimitElement [OrderBot α] (a : α) : - a = ⊥ ∨ (∃ b, a = wellOrderSucc b ∧ b < a) ∨ IsWellOrderLimitElement a := by - refine or_iff_not_imp_left.2 <| fun h₁ ↦ or_iff_not_imp_left.2 <| fun h₂ ↦ ?_ - refine (IsWellOrderLimitElement.mk ⟨⊥, Ne.bot_lt h₁⟩ fun b hb ↦ ?_) - obtain rfl | h₃ := eq_or_lt_of_le (wellOrderSucc_le hb) - · exact (h₂ ⟨b, rfl, hb⟩).elim - · exact ⟨wellOrderSucc b, self_lt_wellOrderSucc hb, h₃⟩ - -lemma IsWellOrderLimitElement.neq_succ (a : α) (ha : a < wellOrderSucc a) - [IsWellOrderLimitElement (wellOrderSucc a)] : False := by - simpa using IsWellOrderLimitElement.wellOrderSucc_lt ha - -@[simp] -lemma Nat.wellOrderSucc_eq (a : ℕ) : wellOrderSucc a = succ a := - le_antisymm (wellOrderSucc_le (Nat.lt_succ_self a)) - (Nat.succ_le.1 (self_lt_wellOrderSucc (Nat.lt_succ_self a))) - -lemma Nat.not_isWellOrderLimitElement (a : ℕ) [IsWellOrderLimitElement a] : False := by - obtain _|a := a - · simpa using IsWellOrderLimitElement.neq_bot (0 : ℕ) - · simpa using IsWellOrderLimitElement.wellOrderSucc_lt (Nat.lt_succ_self a) diff --git a/Mathlib/Order/KonigLemma.lean b/Mathlib/Order/KonigLemma.lean index b38fa275198d5..3e2ecf7719504 100644 --- a/Mathlib/Order/KonigLemma.lean +++ b/Mathlib/Order/KonigLemma.lean @@ -51,7 +51,7 @@ Formulate the lemma as a statement about graphs. open Set section Sequence -variable {α : Type*} [PartialOrder α] [IsStronglyAtomic α] {a b : α} +variable {α : Type*} [PartialOrder α] [IsStronglyAtomic α] {b : α} /-- **Kőnig's infinity lemma** : if each element in a strongly atomic order is covered by only finitely many others, and `b` is an element with infinitely many things above it, diff --git a/Mathlib/Order/LatticeIntervals.lean b/Mathlib/Order/LatticeIntervals.lean index 7be5390c9e2a4..92761688d3430 100644 --- a/Mathlib/Order/LatticeIntervals.lean +++ b/Mathlib/Order/LatticeIntervals.lean @@ -126,6 +126,16 @@ protected lemma isCompl_iff [Lattice α] [BoundedOrder α] {x y : Iic a} : IsCompl x y ↔ Disjoint (x : α) (y : α) ∧ (x : α) ⊔ (y : α) = a := by rw [_root_.isCompl_iff, Iic.disjoint_iff, Iic.codisjoint_iff] +protected lemma complementedLattice_iff [Lattice α] [BoundedOrder α] : + ComplementedLattice (Iic a) ↔ ∀ b, b ≤ a → ∃ c ≤ a, b ⊓ c = ⊥ ∧ b ⊔ c = a := by + refine ⟨fun h b hb ↦ ?_, fun h ↦ ⟨fun ⟨x, hx⟩ ↦ ?_⟩⟩ + · obtain ⟨⟨c, hc₁⟩, hc⟩ := exists_isCompl (⟨b, hb⟩ : Iic a) + obtain ⟨hc₂, hc₃⟩ := Set.Iic.isCompl_iff.mp hc + exact ⟨c, hc₁, disjoint_iff.mp hc₂, hc₃⟩ + · simp_rw [Set.Iic.isCompl_iff] + obtain ⟨c, hc₁, hc₂, hc₃⟩ := h x hx + exact ⟨⟨c, hc₁⟩, disjoint_iff.mpr hc₂, hc₃⟩ + end Iic namespace Ici diff --git a/Mathlib/Order/LiminfLimsup.lean b/Mathlib/Order/LiminfLimsup.lean index 0d6faea4d46f6..a83f19741bce1 100644 --- a/Mathlib/Order/LiminfLimsup.lean +++ b/Mathlib/Order/LiminfLimsup.lean @@ -285,7 +285,7 @@ end Relation section add_and_sum -open Filter BigOperators Set +open Filter Set variable {α : Type*} {f : Filter α} variable {R : Type*} @@ -305,8 +305,7 @@ lemma isBoundedUnder_sum {κ : Type*} [AddCommMonoid R] {r : R → R → Prop} variable [Preorder R] -lemma isBoundedUnder_ge_add [Add R] - [CovariantClass R R (fun a b ↦ a + b) (· ≤ ·)] [CovariantClass R R (fun a b ↦ b + a) (· ≤ ·)] +lemma isBoundedUnder_ge_add [Add R] [AddLeftMono R] [AddRightMono R] {u v : α → R} (u_bdd_ge : f.IsBoundedUnder (· ≥ ·) u) (v_bdd_ge : f.IsBoundedUnder (· ≥ ·) v) : f.IsBoundedUnder (· ≥ ·) (u + v) := by obtain ⟨U, hU⟩ := u_bdd_ge @@ -315,8 +314,7 @@ lemma isBoundedUnder_ge_add [Add R] simp only [eventually_map, Pi.add_apply] at hU hV ⊢ filter_upwards [hU, hV] with a hu hv using add_le_add hu hv -lemma isBoundedUnder_le_add [Add R] - [CovariantClass R R (fun a b ↦ a + b) (· ≤ ·)] [CovariantClass R R (fun a b ↦ b + a) (· ≤ ·)] +lemma isBoundedUnder_le_add [Add R] [AddLeftMono R] [AddRightMono R] {u v : α → R} (u_bdd_le : f.IsBoundedUnder (· ≤ ·) u) (v_bdd_le : f.IsBoundedUnder (· ≤ ·) v) : f.IsBoundedUnder (· ≤ ·) (u + v) := by obtain ⟨U, hU⟩ := u_bdd_le @@ -325,14 +323,12 @@ lemma isBoundedUnder_le_add [Add R] simp only [eventually_map, Pi.add_apply] at hU hV ⊢ filter_upwards [hU, hV] with a hu hv using add_le_add hu hv -lemma isBoundedUnder_le_sum {κ : Type*} [AddCommMonoid R] - [CovariantClass R R (fun a b ↦ a + b) (· ≤ ·)] [CovariantClass R R (fun a b ↦ b + a) (· ≤ ·)] +lemma isBoundedUnder_le_sum {κ : Type*} [AddCommMonoid R] [AddLeftMono R] [AddRightMono R] {u : κ → α → R} (s : Finset κ) : (∀ k ∈ s, f.IsBoundedUnder (· ≤ ·) (u k)) → f.IsBoundedUnder (· ≤ ·) (∑ k ∈ s, u k) := by apply isBoundedUnder_sum (fun _ _ ↦ isBoundedUnder_le_add) le_rfl -lemma isBoundedUnder_ge_sum {κ : Type*} [AddCommMonoid R] - [CovariantClass R R (fun a b ↦ a + b) (· ≤ ·)] [CovariantClass R R (fun a b ↦ b + a) (· ≤ ·)] +lemma isBoundedUnder_ge_sum {κ : Type*} [AddCommMonoid R] [AddLeftMono R] [AddRightMono R] {u : κ → α → R} (s : Finset κ) : (∀ k ∈ s, f.IsBoundedUnder (· ≥ ·) (u k)) → f.IsBoundedUnder (· ≥ ·) (∑ k ∈ s, u k) := by diff --git a/Mathlib/Order/Max.lean b/Mathlib/Order/Max.lean index 61f5b1037d505..36518a3cb4aa5 100644 --- a/Mathlib/Order/Max.lean +++ b/Mathlib/Order/Max.lean @@ -158,7 +158,7 @@ theorem NoMaxOrder.not_acc [LT α] [NoMaxOrder α] (a : α) : ¬Acc (· > ·) a section LE -variable [LE α] {a b : α} +variable [LE α] {a : α} /-- `a : α` is a bottom element of `α` if it is less than or equal to any other element of `α`. This predicate is roughly an unbundled version of `OrderBot`, except that a preorder may have diff --git a/Mathlib/Order/MinMax.lean b/Mathlib/Order/MinMax.lean index f815d61f44816..d43fc960d2020 100644 --- a/Mathlib/Order/MinMax.lean +++ b/Mathlib/Order/MinMax.lean @@ -3,7 +3,6 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Init.Logic import Mathlib.Logic.OpClass import Mathlib.Order.Lattice @@ -244,18 +243,4 @@ instance instAssociativeMin : Std.Associative (α := α) min where assoc := min_ theorem max_left_commutative : LeftCommutative (max : α → α → α) := ⟨max_left_comm⟩ theorem min_left_commutative : LeftCommutative (min : α → α → α) := ⟨min_left_comm⟩ -section deprecated -set_option linter.deprecated false - -@[deprecated instCommutativeMax (since := "2024-09-12")] -theorem max_commutative : Commutative (α := α) max := max_comm -@[deprecated instAssociativeMax (since := "2024-09-12")] -theorem max_associative : Associative (α := α) max := max_assoc -@[deprecated instCommutativeMin (since := "2024-09-12")] -theorem min_commutative : Commutative (α := α) min := min_comm -@[deprecated instAssociativeMin (since := "2024-09-12")] -theorem min_associative : Associative (α := α) min := min_assoc - -end deprecated - end diff --git a/Mathlib/Order/Minimal.lean b/Mathlib/Order/Minimal.lean index 728087a7dbdf4..688801c79c497 100644 --- a/Mathlib/Order/Minimal.lean +++ b/Mathlib/Order/Minimal.lean @@ -10,13 +10,8 @@ import Mathlib.Order.Interval.Set.Basic /-! # Minimality and Maximality -This file defines minimality and maximality of an element with respect to a predicate `P` on -an ordered type `α`. - -## Main declarations - -* `Minimal P x`: `x` is minimal satisfying `P`. -* `Maximal P x`: `x` is maximal satisfying `P`. +This file proves basic facts about minimality and maximality +of an element with respect to a predicate `P` on an ordered type `α`. ## Implementation Details @@ -52,24 +47,6 @@ section LE variable [LE α] -/-- `Minimal P x` means that `x` is a minimal element satisfying `P`. -/ -def Minimal (P : α → Prop) (x : α) : Prop := P x ∧ ∀ ⦃y⦄, P y → y ≤ x → x ≤ y - -/-- `Maximal P x` means that `x` is a maximal element satisfying `P`. -/ -def Maximal (P : α → Prop) (x : α) : Prop := P x ∧ ∀ ⦃y⦄, P y → x ≤ y → y ≤ x - -lemma Minimal.prop (h : Minimal P x) : P x := - h.1 - -lemma Maximal.prop (h : Maximal P x) : P x := - h.1 - -lemma Minimal.le_of_le (h : Minimal P x) (hy : P y) (hle : y ≤ x) : x ≤ y := - h.2 hy hle - -lemma Maximal.le_of_ge (h : Maximal P x) (hy : P y) (hge : x ≤ y) : y ≤ x := - h.2 hy hge - @[simp] theorem minimal_toDual : Minimal (fun x ↦ P (ofDual x)) (toDual x) ↔ Maximal P x := Iff.rfl @@ -621,15 +598,17 @@ theorem map_maximal_mem (f : s ≃o t) (hx : Maximal (· ∈ s) x) : def mapSetOfMinimal (f : s ≃o t) : {x | Minimal (· ∈ s) x} ≃o {x | Minimal (· ∈ t) x} where toFun x := ⟨f ⟨x, x.2.1⟩, f.map_minimal_mem x.2⟩ invFun x := ⟨f.symm ⟨x, x.2.1⟩, f.symm.map_minimal_mem x.2⟩ - left_inv x := Subtype.ext (by apply congr_arg Subtype.val <| f.left_inv ⟨x, x.2.1⟩) - right_inv x := Subtype.ext (by apply congr_arg Subtype.val <| f.right_inv ⟨x, x.2.1⟩) - map_rel_iff' {_ _} := f.map_rel_iff + left_inv x := Subtype.ext (congr_arg Subtype.val <| f.left_inv ⟨x, x.2.1⟩ :) + right_inv x := Subtype.ext (congr_arg Subtype.val <| f.right_inv ⟨x, x.2.1⟩ :) + map_rel_iff' := f.map_rel_iff /-- If two sets are order isomorphic, their maximals are also order isomorphic. -/ def mapSetOfMaximal (f : s ≃o t) : {x | Maximal (· ∈ s) x} ≃o {x | Maximal (· ∈ t) x} where toFun x := ⟨f ⟨x, x.2.1⟩, f.map_maximal_mem x.2⟩ invFun x := ⟨f.symm ⟨x, x.2.1⟩, f.symm.map_maximal_mem x.2⟩ - __ := (show OrderDual.ofDual ⁻¹' s ≃o OrderDual.ofDual ⁻¹' t from f.dual).mapSetOfMinimal + left_inv x := Subtype.ext (congr_arg Subtype.val <| f.left_inv ⟨x, x.2.1⟩ :) + right_inv x := Subtype.ext (congr_arg Subtype.val <| f.right_inv ⟨x, x.2.1⟩ :) + map_rel_iff' := f.map_rel_iff /-- If two sets are antitonically order isomorphic, their minimals/maximals are too. -/ def setOfMinimalIsoSetOfMaximal (f : s ≃o tᵒᵈ) : diff --git a/Mathlib/Order/Monotone/Basic.lean b/Mathlib/Order/Monotone/Basic.lean index d2edb733b59cc..bafac4b6ac367 100644 --- a/Mathlib/Order/Monotone/Basic.lean +++ b/Mathlib/Order/Monotone/Basic.lean @@ -66,7 +66,6 @@ open Function OrderDual universe u v w variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {δ : Type*} {π : ι → Type*} - {r : α → α → Prop} section MonotoneDef @@ -1074,7 +1073,7 @@ theorem const_strictMono [Nonempty β] : StrictMono (const β : α → β → α end Function section apply -variable {ι α : Type*} {β : ι → Type*} [∀ i, Preorder (β i)] [Preorder α] {f : α → ∀ i, β i} +variable {β : ι → Type*} [∀ i, Preorder (β i)] [Preorder α] {f : α → ∀ i, β i} lemma monotone_iff_apply₂ : Monotone f ↔ ∀ i, Monotone (f · i) := by simp [Monotone, Pi.le_def, @forall_swap ι] diff --git a/Mathlib/Order/Monotone/Extension.lean b/Mathlib/Order/Monotone/Extension.lean index 7d56c6bba761f..6576bde8e49da 100644 --- a/Mathlib/Order/Monotone/Extension.lean +++ b/Mathlib/Order/Monotone/Extension.lean @@ -16,7 +16,6 @@ monotone extension to the whole space. open Set variable {α β : Type*} [LinearOrder α] [ConditionallyCompleteLinearOrder β] {f : α → β} {s : Set α} - {a b : α} /-- If a function is monotone and is bounded on a set `s`, then it admits a monotone extension to the whole space. -/ diff --git a/Mathlib/Order/Monotone/Monovary.lean b/Mathlib/Order/Monotone/Monovary.lean index 4c25c914b2698..9dcfecb90a91f 100644 --- a/Mathlib/Order/Monotone/Monovary.lean +++ b/Mathlib/Order/Monotone/Monovary.lean @@ -31,7 +31,7 @@ variable {ι ι' α β γ : Type*} section Preorder -variable [Preorder α] [Preorder β] [Preorder γ] {f : ι → α} {f' : α → γ} {g : ι → β} {g' : β → γ} +variable [Preorder α] [Preorder β] [Preorder γ] {f : ι → α} {f' : α → γ} {g : ι → β} {s t : Set ι} /-- `f` monovaries with `g` if `g i < g j` implies `f i ≤ f j`. -/ @@ -282,7 +282,7 @@ end Preorder section LinearOrder -variable [Preorder α] [LinearOrder β] [Preorder γ] {f : ι → α} {f' : α → γ} {g : ι → β} {g' : β → γ} +variable [Preorder α] [LinearOrder β] [Preorder γ] {f : ι → α} {g : ι → β} {g' : β → γ} {s : Set ι} theorem MonovaryOn.comp_monotoneOn_right (h : MonovaryOn f g s) (hg : MonotoneOn g' (g '' s)) : diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index 911cd139607e1..179530a5796f4 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -72,7 +72,6 @@ variable [Preorder α] [Preorder β] [Preorder γ] instance : FunLike (Chain α) ℕ α := inferInstanceAs <| FunLike (ℕ →o α) ℕ α instance : OrderHomClass (Chain α) ℕ α := inferInstanceAs <| OrderHomClass (ℕ →o α) ℕ α -instance : CoeFun (Chain α) fun _ => ℕ → α := ⟨DFunLike.coe⟩ instance [Inhabited α] : Inhabited (Chain α) := ⟨⟨default, fun _ _ _ => le_rfl⟩⟩ @@ -462,11 +461,11 @@ open OmegaCompletePartialOrder OmegaCompletePartialOrder.Chain instance [∀ a, OmegaCompletePartialOrder (β a)] : OmegaCompletePartialOrder (∀ a, β a) where ωSup c a := ωSup (c.map (Pi.evalOrderHom a)) - ωSup_le c f hf a := + ωSup_le _ _ hf a := ωSup_le _ _ <| by rintro i apply hf - le_ωSup c i x := le_ωSup_of_le _ <| le_rfl + le_ωSup _ _ _ := le_ωSup_of_le _ <| le_rfl namespace OmegaCompletePartialOrder @@ -480,7 +479,7 @@ lemma ωScottContinuous.apply₂ (hf : ωScottContinuous f) (a : α) : ωScottCo lemma ωScottContinuous.of_apply₂ (hf : ∀ a, ωScottContinuous (f · a)) : ωScottContinuous f := ωScottContinuous.of_monotone_map_ωSup - ⟨fun x y h a ↦ (hf a).monotone h, fun c ↦ by ext a; apply (hf a).map_ωSup c⟩ + ⟨fun _ _ h a ↦ (hf a).monotone h, fun c ↦ by ext a; apply (hf a).map_ωSup c⟩ lemma ωScottContinuous_iff_apply₂ : ωScottContinuous f ↔ ∀ a, ωScottContinuous (f · a) := ⟨ωScottContinuous.apply₂, ωScottContinuous.of_apply₂⟩ @@ -495,7 +494,7 @@ theorem flip₁_continuous' (f : ∀ x : α, γ → β x) (a : α) (hf : Continu @[deprecated ωScottContinuous.of_apply₂ (since := "2024-05-29")] theorem flip₂_continuous' (f : γ → ∀ x, β x) (hf : ∀ x, Continuous' fun g => f g x) : Continuous' f := - Continuous.of_bundled _ (fun x y h a => (hf a).to_monotone h) + Continuous.of_bundled _ (fun _ _ h a => (hf a).to_monotone h) (by intro c; ext a; apply (hf a).to_bundled _ c) end OmegaCompletePartialOrder @@ -936,7 +935,7 @@ theorem ωSup_apply_ωSup (c₀ : Chain (α →𝒄 β)) (c₁ : Chain α) : @[simps] def flip {α : Type*} (f : α → β →𝒄 γ) : β →𝒄 α → γ where toFun x y := f y x - monotone' x y h a := (f a).monotone h + monotone' _ _ h a := (f a).monotone h map_ωSup' _ := by ext x; change f _ _ = _; rw [(f _).continuous]; rfl /-- `Part.bind` as a continuous function. -/ diff --git a/Mathlib/Order/OrdContinuous.lean b/Mathlib/Order/OrdContinuous.lean index 1af016fa24c89..ac0e1eab6eac1 100644 --- a/Mathlib/Order/OrdContinuous.lean +++ b/Mathlib/Order/OrdContinuous.lean @@ -231,7 +231,7 @@ namespace OrderIso section Preorder -variable [Preorder α] [Preorder β] (e : α ≃o β) {s : Set α} {x : α} +variable [Preorder α] [Preorder β] (e : α ≃o β) protected theorem leftOrdContinuous : LeftOrdContinuous e := fun _ _ hx => ⟨Monotone.mem_upperBounds_image (fun _ _ => e.map_rel_iff.2) hx.1, fun _ hy => diff --git a/Mathlib/Order/OrderIsoNat.lean b/Mathlib/Order/OrderIsoNat.lean index 5eddb07567f64..da0fabb452ad3 100644 --- a/Mathlib/Order/OrderIsoNat.lean +++ b/Mathlib/Order/OrderIsoNat.lean @@ -232,3 +232,20 @@ theorem WellFounded.iSup_eq_monotonicSequenceLimit [CompleteLattice α] · cases' WellFounded.monotone_chain_condition'.1 h a with n hn have : n ∈ {n | ∀ m, n ≤ m → a n = a m} := fun k hk => (a.mono hk).eq_of_not_lt (hn k hk) exact (Nat.sInf_mem ⟨n, this⟩ m hm.le).ge + +theorem exists_covBy_seq_of_wellFoundedLT_wellFoundedGT (α) [Preorder α] + [Nonempty α] [wfl : WellFoundedLT α] [wfg : WellFoundedGT α] : + ∃ a : ℕ → α, IsMin (a 0) ∧ ∃ n, IsMax (a n) ∧ ∀ i < n, a i ⋖ a (i + 1) := by + choose next hnext using exists_covBy_of_wellFoundedLT (α := α) + have hα := Set.nonempty_iff_univ_nonempty.mp ‹_› + classical + let a : ℕ → α := Nat.rec (wfl.wf.min _ hα) fun _n a ↦ if ha : IsMax a then a else next ha + refine ⟨a, isMin_iff_forall_not_lt.mpr fun _ ↦ wfl.wf.not_lt_min _ hα trivial, ?_⟩ + have cov n (hn : ¬ IsMax (a n)) : a n ⋖ a (n + 1) := by + change a n ⋖ if ha : IsMax (a n) then a n else _ + rw [dif_neg hn] + exact hnext hn + have H : ∃ n, IsMax (a n) := by + by_contra! + exact (RelEmbedding.natGT a fun n ↦ (cov n (this n)).1).not_wellFounded_of_decreasing_seq wfg.wf + exact ⟨_, wellFounded_lt.min_mem _ H, fun i h ↦ cov _ fun h' ↦ wellFounded_lt.not_lt_min _ H h' h⟩ diff --git a/Mathlib/Order/PFilter.lean b/Mathlib/Order/PFilter.lean index 5e663221d21fc..d461174544550 100644 --- a/Mathlib/Order/PFilter.lean +++ b/Mathlib/Order/PFilter.lean @@ -143,7 +143,7 @@ end SemilatticeInf section CompleteSemilatticeInf -variable [CompleteSemilatticeInf P] {F : PFilter P} +variable [CompleteSemilatticeInf P] theorem sInf_gc : GaloisConnection (fun x => toDual (principal x)) fun F => sInf (ofDual F : PFilter P) := diff --git a/Mathlib/Order/PartialSups.lean b/Mathlib/Order/PartialSups.lean index 5fbe0f73945d5..e40824d604869 100644 --- a/Mathlib/Order/PartialSups.lean +++ b/Mathlib/Order/PartialSups.lean @@ -6,7 +6,7 @@ Authors: Kim Morrison import Mathlib.Data.Finset.Lattice import Mathlib.Order.Hom.Basic import Mathlib.Data.Set.Finite -import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Indexed /-! # The monotone sequence of partial supremums of a sequence @@ -174,7 +174,6 @@ lemma partialSups_eq_biUnion_range (s : ℕ → Set α) (n : ℕ) : variable [CompleteLattice α] --- Porting note (#10618): simp can prove this @[simp] theorem iSup_partialSups_eq (f : ℕ → α) : ⨆ n, partialSups f n = ⨆ n, f n := ciSup_partialSups_eq <| OrderTop.bddAbove _ diff --git a/Mathlib/Order/Partition/Equipartition.lean b/Mathlib/Order/Partition/Equipartition.lean index 7833e98aa3fe8..4cd1f1579f339 100644 --- a/Mathlib/Order/Partition/Equipartition.lean +++ b/Mathlib/Order/Partition/Equipartition.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Yaël Dillies, Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ +import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.Set.Equitable import Mathlib.Logic.Equiv.Fin import Mathlib.Order.Partition.Finpartition @@ -34,44 +35,41 @@ def IsEquipartition : Prop := theorem isEquipartition_iff_card_parts_eq_average : P.IsEquipartition ↔ - ∀ a : Finset α, - a ∈ P.parts → a.card = s.card / P.parts.card ∨ a.card = s.card / P.parts.card + 1 := by + ∀ a : Finset α, a ∈ P.parts → #a = #s / #P.parts ∨ #a = #s / #P.parts + 1 := by simp_rw [IsEquipartition, Finset.equitableOn_iff, P.sum_card_parts] variable {P} lemma not_isEquipartition : - ¬P.IsEquipartition ↔ ∃ a ∈ P.parts, ∃ b ∈ P.parts, b.card + 1 < a.card := - Set.not_equitableOn + ¬P.IsEquipartition ↔ ∃ a ∈ P.parts, ∃ b ∈ P.parts, #b + 1 < #a := Set.not_equitableOn theorem _root_.Set.Subsingleton.isEquipartition (h : (P.parts : Set (Finset α)).Subsingleton) : P.IsEquipartition := Set.Subsingleton.equitableOn h _ theorem IsEquipartition.card_parts_eq_average (hP : P.IsEquipartition) (ht : t ∈ P.parts) : - t.card = s.card / P.parts.card ∨ t.card = s.card / P.parts.card + 1 := + #t = #s / #P.parts ∨ #t = #s / #P.parts + 1 := P.isEquipartition_iff_card_parts_eq_average.1 hP _ ht theorem IsEquipartition.card_part_eq_average_iff (hP : P.IsEquipartition) (ht : t ∈ P.parts) : - t.card = s.card / P.parts.card ↔ t.card ≠ s.card / P.parts.card + 1 := by + #t = #s / #P.parts ↔ #t ≠ #s / #P.parts + 1 := by have a := hP.card_parts_eq_average ht - have b : ¬(t.card = s.card / P.parts.card ∧ t.card = s.card / P.parts.card + 1) := by + have b : ¬(#t = #s / #P.parts ∧ #t = #s / #P.parts + 1) := by by_contra h; exact absurd (h.1 ▸ h.2) (lt_add_one _).ne tauto theorem IsEquipartition.average_le_card_part (hP : P.IsEquipartition) (ht : t ∈ P.parts) : - s.card / P.parts.card ≤ t.card := by + #s / #P.parts ≤ #t := by rw [← P.sum_card_parts] exact Finset.EquitableOn.le hP ht theorem IsEquipartition.card_part_le_average_add_one (hP : P.IsEquipartition) (ht : t ∈ P.parts) : - t.card ≤ s.card / P.parts.card + 1 := by + #t ≤ #s / #P.parts + 1 := by rw [← P.sum_card_parts] exact Finset.EquitableOn.le_add_one hP ht theorem IsEquipartition.filter_ne_average_add_one_eq_average (hP : P.IsEquipartition) : - P.parts.filter (fun p ↦ ¬p.card = s.card / P.parts.card + 1) = - P.parts.filter (fun p ↦ p.card = s.card / P.parts.card) := by + {p ∈ P.parts | ¬#p = #s / #P.parts + 1} = {p ∈ P.parts | #p = #s / #P.parts} := by ext p simp only [mem_filter, and_congr_right_iff] exact fun hp ↦ (hP.card_part_eq_average_iff hp).symm @@ -79,75 +77,70 @@ theorem IsEquipartition.filter_ne_average_add_one_eq_average (hP : P.IsEquiparti /-- An equipartition of a finset with `n` elements into `k` parts has `n % k` parts of size `n / k + 1`. -/ theorem IsEquipartition.card_large_parts_eq_mod (hP : P.IsEquipartition) : - (P.parts.filter fun p ↦ p.card = s.card / P.parts.card + 1).card = s.card % P.parts.card := by + #{p ∈ P.parts | #p = #s / #P.parts + 1} = #s % #P.parts := by have z := P.sum_card_parts - rw [← sum_filter_add_sum_filter_not (s := P.parts) - (p := fun x ↦ x.card = s.card / P.parts.card + 1), - hP.filter_ne_average_add_one_eq_average, - sum_const_nat (m := s.card / P.parts.card + 1) (by simp), - sum_const_nat (m := s.card / P.parts.card) (by simp), - ← hP.filter_ne_average_add_one_eq_average, - mul_add, add_comm, ← add_assoc, ← add_mul, mul_one, add_comm (Finset.card _), + rw [← sum_filter_add_sum_filter_not (s := P.parts) (p := fun x ↦ #x = #s / #P.parts + 1), + hP.filter_ne_average_add_one_eq_average, sum_const_nat (m := #s / #P.parts + 1) (by simp), + sum_const_nat (m := #s / #P.parts) (by simp), ← hP.filter_ne_average_add_one_eq_average, + mul_add, add_comm, ← add_assoc, ← add_mul, mul_one, add_comm #_, filter_card_add_filter_neg_card_eq_card, add_comm] at z rw [← add_left_inj, Nat.mod_add_div, z] /-- An equipartition of a finset with `n` elements into `k` parts has `n - n % k` parts of size `n / k`. -/ theorem IsEquipartition.card_small_parts_eq_mod (hP : P.IsEquipartition) : - (P.parts.filter fun p ↦ p.card = s.card / P.parts.card).card = - P.parts.card - s.card % P.parts.card := by + #{p ∈ P.parts | #p = #s / #P.parts} = #P.parts - #s % #P.parts := by conv_rhs => arg 1 - rw [← filter_card_add_filter_neg_card_eq_card (p := fun p ↦ p.card = s.card / P.parts.card + 1)] + rw [← filter_card_add_filter_neg_card_eq_card (p := fun p ↦ #p = #s / #P.parts + 1)] rw [hP.card_large_parts_eq_mod, add_tsub_cancel_left, hP.filter_ne_average_add_one_eq_average] /-- There exists an enumeration of an equipartition's parts where larger parts map to smaller numbers and vice versa. -/ theorem IsEquipartition.exists_partsEquiv (hP : P.IsEquipartition) : - ∃ f : P.parts ≃ Fin P.parts.card, - ∀ t, t.1.card = s.card / P.parts.card + 1 ↔ f t < s.card % P.parts.card := by - let el := (P.parts.filter fun p ↦ p.card = s.card / P.parts.card + 1).equivFin - let es := (P.parts.filter fun p ↦ p.card = s.card / P.parts.card).equivFin + ∃ f : P.parts ≃ Fin #P.parts, ∀ t, #t.1 = #s / #P.parts + 1 ↔ f t < #s % #P.parts := by + let el := {p ∈ P.parts | #p = #s / #P.parts + 1}.equivFin + let es := {p ∈ P.parts | #p = #s / #P.parts}.equivFin simp_rw [mem_filter, hP.card_large_parts_eq_mod] at el simp_rw [mem_filter, hP.card_small_parts_eq_mod] at es - let sneg : { x // x ∈ P.parts ∧ ¬x.card = s.card / P.parts.card + 1 } ≃ - { x // x ∈ P.parts ∧ x.card = s.card / P.parts.card } := by + let sneg : + {x // x ∈ P.parts ∧ ¬#x = #s / #P.parts + 1} ≃ {x // x ∈ P.parts ∧ #x = #s / #P.parts} := by apply (Equiv.refl _).subtypeEquiv simp only [Equiv.refl_apply, and_congr_right_iff] exact fun _ ha ↦ by rw [hP.card_part_eq_average_iff ha, ne_eq] - replace el : { x : P.parts // x.1.card = s.card / P.parts.card + 1 } ≃ - Fin (s.card % P.parts.card) := (Equiv.Set.sep ..).symm.trans el - replace es : { x : P.parts // ¬x.1.card = s.card / P.parts.card + 1 } ≃ - Fin (P.parts.card - s.card % P.parts.card) := (Equiv.Set.sep ..).symm.trans (sneg.trans es) + replace el : { x : P.parts // #x.1 = #s / #P.parts + 1 } ≃ + Fin (#s % #P.parts) := (Equiv.Set.sep ..).symm.trans el + replace es : { x : P.parts // ¬#x.1 = #s / #P.parts + 1 } ≃ + Fin (#P.parts - #s % #P.parts) := (Equiv.Set.sep ..).symm.trans (sneg.trans es) let f := (Equiv.sumCompl _).symm.trans ((el.sumCongr es).trans finSumFinEquiv) use f.trans (finCongr (Nat.add_sub_of_le P.card_mod_card_parts_le)) intro ⟨p, _⟩ simp_rw [f, Equiv.trans_apply, Equiv.sumCongr_apply, finCongr_apply, Fin.coe_cast] - by_cases hc : p.card = s.card / P.parts.card + 1 <;> simp [hc] + by_cases hc : #p = #s / #P.parts + 1 <;> simp [hc] /-- Given a finset equipartitioned into `k` parts, its elements can be enumerated such that elements in the same part have congruent indices modulo `k`. -/ -theorem IsEquipartition.exists_partPreservingEquiv (hP : P.IsEquipartition) : ∃ f : s ≃ Fin s.card, - ∀ a b : s, P.part a = P.part b ↔ f a % P.parts.card = f b % P.parts.card := by +theorem IsEquipartition.exists_partPreservingEquiv (hP : P.IsEquipartition) : ∃ f : s ≃ Fin #s, + ∀ a b : s, P.part a = P.part b ↔ f a % #P.parts = f b % #P.parts := by obtain ⟨f, hf⟩ := P.exists_enumeration obtain ⟨g, hg⟩ := hP.exists_partsEquiv - let z := fun a ↦ P.parts.card * (f a).2 + g (f a).1 + let z := fun a ↦ #P.parts * (f a).2 + g (f a).1 have gl := fun a ↦ (g (f a).1).2 - have less : ∀ a, z a < s.card := fun a ↦ by + have less : ∀ a, z a < #s := fun a ↦ by rcases hP.card_parts_eq_average (f a).1.2 with (c | c) · calc - _ < P.parts.card * ((f a).2 + 1) := add_lt_add_left (gl a) _ - _ ≤ P.parts.card * (s.card / P.parts.card) := mul_le_mul_left' (c ▸ (f a).2.2) _ - _ ≤ P.parts.card * (s.card / P.parts.card) + s.card % P.parts.card := Nat.le_add_right .. + _ < #P.parts * ((f a).2 + 1) := add_lt_add_left (gl a) _ + _ ≤ #P.parts * (#s / #P.parts) := mul_le_mul_left' (c ▸ (f a).2.2) _ + _ ≤ #P.parts * (#s / #P.parts) + #s % #P.parts := Nat.le_add_right .. _ = _ := Nat.div_add_mod .. - · rw [← Nat.div_add_mod s.card P.parts.card] + · rw [← Nat.div_add_mod #s #P.parts] exact add_lt_add_of_le_of_lt (mul_le_mul_left' (by omega) _) ((hg (f a).1).mp c) - let z' : s → Fin s.card := fun a ↦ ⟨z a, less a⟩ + let z' : s → Fin #s := fun a ↦ ⟨z a, less a⟩ have bij : z'.Bijective := by refine (bijective_iff_injective_and_card z').mpr ⟨fun a b e ↦ ?_, by simp⟩ - simp_rw [z', z, Fin.mk.injEq, mul_comm P.parts.card] at e - haveI : NeZero P.parts.card := ⟨((Nat.zero_le _).trans_lt (gl a)).ne'⟩ - change P.parts.card.divModEquiv.symm (_, _) = P.parts.card.divModEquiv.symm (_, _) at e + simp_rw [z', z, Fin.mk.injEq, mul_comm #P.parts] at e + haveI : NeZero #P.parts := ⟨((Nat.zero_le _).trans_lt (gl a)).ne'⟩ + change (#P.parts).divModEquiv.symm (_, _) = (#P.parts).divModEquiv.symm (_, _) at e simp only [Equiv.apply_eq_iff_eq, Prod.mk.injEq] at e apply_fun f exact Sigma.ext e.2 <| (Fin.heq_ext_iff (by rw [e.2])).mpr e.1 diff --git a/Mathlib/Order/Partition/Finpartition.lean b/Mathlib/Order/Partition/Finpartition.lean index 91dbd15b3b57b..177343bd87766 100644 --- a/Mathlib/Order/Partition/Finpartition.lean +++ b/Mathlib/Order/Partition/Finpartition.lean @@ -64,16 +64,13 @@ structure Finpartition [Lattice α] [OrderBot α] (a : α) where /-- The elements of the finite partition of `a` -/ parts : Finset α /-- The partition is supremum-independent -/ - supIndep : parts.SupIndep id + protected supIndep : parts.SupIndep id /-- The supremum of the partition is `a` -/ sup_parts : parts.sup id = a /-- No element of the partition is bottom -/ not_bot_mem : ⊥ ∉ parts deriving DecidableEq --- Porting note: attribute [protected] doesn't work --- attribute [protected] Finpartition.supIndep - namespace Finpartition section Lattice @@ -221,8 +218,8 @@ instance : LE (Finpartition a) := instance : PartialOrder (Finpartition a) := { (inferInstance : LE (Finpartition a)) with - le_refl := fun P b hb ↦ ⟨b, hb, le_rfl⟩ - le_trans := fun P Q R hPQ hQR b hb ↦ by + le_refl := fun _ b hb ↦ ⟨b, hb, le_rfl⟩ + le_trans := fun _ Q R hPQ hQR b hb ↦ by obtain ⟨c, hc, hbc⟩ := hPQ hb obtain ⟨d, hd, hcd⟩ := hQR hc exact ⟨d, hd, hbc.trans hcd⟩ @@ -338,7 +335,7 @@ theorem exists_le_of_le {a b : α} {P Q : Finpartition a} (h : P ≤ Q) (hb : b simp only [not_exists, not_and] at H exact H _ hc hcd -theorem card_mono {a : α} {P Q : Finpartition a} (h : P ≤ Q) : Q.parts.card ≤ P.parts.card := by +theorem card_mono {a : α} {P Q : Finpartition a} (h : P ≤ Q) : #Q.parts ≤ #P.parts := by classical have : ∀ b ∈ Q.parts, ∃ c ∈ P.parts, c ≤ b := fun b ↦ exists_le_of_le h choose f hP hf using this @@ -389,7 +386,7 @@ theorem mem_bind : b ∈ (P.bind Q).parts ↔ ∃ A hA, b ∈ (Q A hA).parts := exact ⟨⟨A, hA⟩, mem_attach _ ⟨A, hA⟩, h⟩ theorem card_bind (Q : ∀ i ∈ P.parts, Finpartition i) : - (P.bind Q).parts.card = ∑ A ∈ P.parts.attach, (Q _ A.2).parts.card := by + #(P.bind Q).parts = ∑ A ∈ P.parts.attach, #(Q _ A.2).parts := by apply card_biUnion rintro ⟨b, hb⟩ - ⟨c, hc⟩ - hbc rw [Finset.disjoint_left] @@ -414,7 +411,7 @@ def extend (P : Finpartition a) (hb : b ≠ ⊥) (hab : Disjoint a b) (hc : a not_bot_mem h := (mem_insert.1 h).elim hb.symm P.not_bot_mem theorem card_extend (P : Finpartition a) (b c : α) {hb : b ≠ ⊥} {hab : Disjoint a b} - {hc : a ⊔ b = c} : (P.extend hb hab hc).parts.card = P.parts.card + 1 := + {hc : a ⊔ b = c} : #(P.extend hb hab hc).parts = #P.parts + 1 := card_insert_of_not_mem fun h ↦ hb <| hab.symm.eq_bot_of_le <| P.le h end DistribLattice @@ -428,7 +425,7 @@ variable [GeneralizedBooleanAlgebra α] [DecidableEq α] {a b c : α} (P : Finpa def avoid (b : α) : Finpartition (a \ b) := ofErase (P.parts.image (· \ b)) - (P.disjoint.image_finset_of_le fun a ↦ sdiff_le).supIndep + (P.disjoint.image_finset_of_le fun _ ↦ sdiff_le).supIndep (by rw [sup_image, id_comp, Finset.sup_sdiff_right, ← Function.id_def, P.sup_parts]) @[simp] @@ -506,12 +503,12 @@ def equivSigmaParts : s ≃ Σ t : P.parts, t.1 where rw [P.part_eq_of_mem mp mf] · simp -lemma exists_enumeration : ∃ f : s ≃ Σ t : P.parts, Fin t.1.card, +lemma exists_enumeration : ∃ f : s ≃ Σ t : P.parts, Fin #t.1, ∀ a b : s, P.part a = P.part b ↔ (f a).1 = (f b).1 := by use P.equivSigmaParts.trans ((Equiv.refl _).sigmaCongr (fun t ↦ t.1.equivFin)) simp [equivSigmaParts, Equiv.sigmaCongr, Equiv.sigmaCongrLeft] -theorem sum_card_parts : ∑ i ∈ P.parts, i.card = s.card := by +theorem sum_card_parts : ∑ i ∈ P.parts, #i = #s := by convert congr_arg Finset.card P.biUnion_parts rw [card_biUnion P.supIndep.pairwiseDisjoint] rfl @@ -532,8 +529,7 @@ theorem parts_bot (s : Finset α) : (⊥ : Finpartition s).parts = s.map ⟨singleton, singleton_injective⟩ := rfl -theorem card_bot (s : Finset α) : (⊥ : Finpartition s).parts.card = s.card := - Finset.card_map _ +theorem card_bot (s : Finset α) : #(⊥ : Finpartition s).parts = #s := Finset.card_map _ theorem mem_bot_iff : t ∈ (⊥ : Finpartition s).parts ↔ ∃ a ∈ s, {a} = t := mem_map @@ -546,15 +542,15 @@ instance (s : Finset α) : OrderBot (Finpartition s) := obtain ⟨t, ht, hat⟩ := P.exists_mem ha exact ⟨t, ht, singleton_subset_iff.2 hat⟩ } -theorem card_parts_le_card : P.parts.card ≤ s.card := by +theorem card_parts_le_card : #P.parts ≤ #s := by rw [← card_bot s] exact card_mono bot_le -lemma card_mod_card_parts_le : s.card % P.parts.card ≤ P.parts.card := by - rcases P.parts.card.eq_zero_or_pos with h | h - · have h' := h - rw [Finset.card_eq_zero, parts_eq_empty_iff, bot_eq_empty, ← Finset.card_eq_zero] at h' - rw [h, h'] +lemma card_mod_card_parts_le : #s % #P.parts ≤ #P.parts := by + obtain h | h := (#P.parts).eq_zero_or_pos + · rw [h] + rw [Finset.card_eq_zero, parts_eq_empty_iff, bot_eq_empty, ← Finset.card_eq_zero] at h + rw [h] · exact (Nat.mod_lt _ h).le section Setoid @@ -564,7 +560,7 @@ variable [Fintype α] /-- A setoid over a finite type induces a finpartition of the type's elements, where the parts are the setoid's equivalence classes. -/ def ofSetoid (s : Setoid α) [DecidableRel s.r] : Finpartition (univ : Finset α) where - parts := univ.image fun a => univ.filter (s.r a) + parts := univ.image fun a ↦ ({b | s.r a b} : Finset α) supIndep := by simp only [mem_univ, forall_true_left, supIndep_iff_pairwiseDisjoint, Set.PairwiseDisjoint, Set.Pairwise, coe_image, coe_univ, Set.image_univ, Set.mem_range, ne_eq, @@ -581,12 +577,12 @@ def ofSetoid (s : Setoid α) [DecidableRel s.r] : Finpartition (univ : Finset α sup_parts := by ext a simp only [sup_image, Function.id_comp, mem_univ, mem_sup, mem_filter, true_and, iff_true] - use a; exact s.refl a + use a not_bot_mem := by rw [bot_eq_empty, mem_image, not_exists] intro a simp only [filter_eq_empty_iff, not_forall, mem_univ, forall_true_left, true_and, not_not] - use a; exact s.refl a + use a theorem mem_part_ofSetoid_iff_rel {s : Setoid α} [DecidableRel s.r] {b : α} : b ∈ (ofSetoid s).part a ↔ s.r a b := by @@ -605,7 +601,7 @@ section Atomise /-- Cuts `s` along the finsets in `F`: Two elements of `s` will be in the same part if they are in the same finsets of `F`. -/ def atomise (s : Finset α) (F : Finset (Finset α)) : Finpartition s := - ofErase (F.powerset.image fun Q ↦ s.filter fun i ↦ ∀ t ∈ F, t ∈ Q ↔ i ∈ t) + ofErase (F.powerset.image fun Q ↦ {i ∈ s | ∀ t ∈ F, t ∈ Q ↔ i ∈ t}) (Set.PairwiseDisjoint.supIndep fun x hx y hy h ↦ disjoint_left.mpr fun z hz1 hz2 ↦ h (by @@ -614,8 +610,7 @@ def atomise (s : Finset α) (F : Finset (Finset α)) : Finpartition s := obtain ⟨R, hR, rfl⟩ := hy suffices h' : Q = R by subst h' - exact of_eq_true (eq_self ( - filter (fun i ↦ ∀ (t : Finset α), t ∈ F → (t ∈ Q ↔ i ∈ t)) s)) + exact of_eq_true (eq_self {i ∈ s | ∀ t ∈ F, t ∈ Q ↔ i ∈ t}) rw [id, mem_filter] at hz1 hz2 rw [mem_powerset] at hQ hR ext i @@ -629,7 +624,7 @@ def atomise (s : Finset α) (F : Finset (Finset α)) : Finpartition s := exact s.filter_subset _ · rw [mem_sup] refine - ⟨s.filter fun i ↦ ∀ t, t ∈ F → ((t ∈ F.filter fun u ↦ a ∈ u) ↔ i ∈ t), + ⟨{i ∈ s | ∀ t ∈ F, t ∈ {u ∈ F | a ∈ u} ↔ i ∈ t}, mem_image_of_mem _ (mem_powerset.2 <| filter_subset _ _), mem_filter.2 ⟨ha, fun t ht ↦ ?_⟩⟩ rw [mem_filter] @@ -639,7 +634,7 @@ variable {F : Finset (Finset α)} theorem mem_atomise : t ∈ (atomise s F).parts ↔ - t.Nonempty ∧ ∃ Q ⊆ F, (s.filter fun i ↦ ∀ u ∈ F, u ∈ Q ↔ i ∈ u) = t := by + t.Nonempty ∧ ∃ Q ⊆ F, {i ∈ s | ∀ u ∈ F, u ∈ Q ↔ i ∈ u} = t := by simp only [atomise, ofErase, bot_eq_empty, mem_erase, mem_image, nonempty_iff_ne_empty, mem_singleton, and_comm, mem_powerset, exists_prop] @@ -648,11 +643,11 @@ theorem atomise_empty (hs : s.Nonempty) : (atomise s ∅).parts = {s} := by imp_true_iff, filter_True] exact erase_eq_of_not_mem (not_mem_singleton.2 hs.ne_empty.symm) -theorem card_atomise_le : (atomise s F).parts.card ≤ 2 ^ F.card := +theorem card_atomise_le : #(atomise s F).parts ≤ 2 ^ #F := (card_le_card <| erase_subset _ _).trans <| Finset.card_image_le.trans (card_powerset _).le theorem biUnion_filter_atomise (ht : t ∈ F) (hts : t ⊆ s) : - ((atomise s F).parts.filter fun u ↦ u ⊆ t ∧ u.Nonempty).biUnion id = t := by + {u ∈ (atomise s F).parts | u ⊆ t ∧ u.Nonempty}.biUnion id = t := by ext a refine mem_biUnion.trans ⟨fun ⟨u, hu, ha⟩ ↦ (mem_filter.1 hu).2.1 ha, fun ha ↦ ?_⟩ obtain ⟨u, hu, hau⟩ := (atomise s F).exists_mem (hts ha) @@ -662,10 +657,10 @@ theorem biUnion_filter_atomise (ht : t ∈ F) (hts : t ⊆ s) : rwa [← hb.2 _ ht, hau.2 _ ht] theorem card_filter_atomise_le_two_pow (ht : t ∈ F) : - ((atomise s F).parts.filter fun u ↦ u ⊆ t ∧ u.Nonempty).card ≤ 2 ^ (F.card - 1) := by + #{u ∈ (atomise s F).parts | u ⊆ t ∧ u.Nonempty} ≤ 2 ^ (#F - 1) := by suffices h : - ((atomise s F).parts.filter fun u ↦ u ⊆ t ∧ u.Nonempty) ⊆ - (F.erase t).powerset.image fun P ↦ s.filter fun i ↦ ∀ x ∈ F, x ∈ insert t P ↔ i ∈ x by + {u ∈ (atomise s F).parts | u ⊆ t ∧ u.Nonempty} ⊆ + (F.erase t).powerset.image fun P ↦ {i ∈ s | ∀ x ∈ F, x ∈ insert t P ↔ i ∈ x} by refine (card_le_card h).trans (card_image_le.trans ?_) rw [card_powerset, card_erase_of_mem ht] rw [subset_iff] diff --git a/Mathlib/Order/PiLex.lean b/Mathlib/Order/PiLex.lean index b9228f4db92e0..4fd435168435e 100644 --- a/Mathlib/Order/PiLex.lean +++ b/Mathlib/Order/PiLex.lean @@ -57,7 +57,7 @@ theorem lex_lt_of_lt_of_preorder [∀ i, Preorder (β i)] {r} (hwf : WellFounded ⟨i, fun j hj => ⟨h'.1 j, not_not.1 fun h => hl j (lt_of_le_not_le (h'.1 j) h) hj⟩, hi⟩ theorem lex_lt_of_lt [∀ i, PartialOrder (β i)] {r} (hwf : WellFounded r) {x y : ∀ i, β i} - (hlt : x < y) : Pi.Lex r (@fun i => (· < ·)) x y := by + (hlt : x < y) : Pi.Lex r (@fun _ => (· < ·)) x y := by simp_rw [Pi.Lex, le_antisymm_iff] exact lex_lt_of_lt_of_preorder hwf hlt @@ -101,7 +101,7 @@ noncomputable instance [LinearOrder ι] [IsWellOrder ι (· < ·)] [∀ a, Linea section PartialOrder -variable [LinearOrder ι] [IsWellOrder ι (· < ·)] [∀ i, PartialOrder (β i)] {x y : ∀ i, β i} {i : ι} +variable [LinearOrder ι] [IsWellOrder ι (· < ·)] [∀ i, PartialOrder (β i)] {x : ∀ i, β i} {i : ι} {a : β i} open Function @@ -205,7 +205,7 @@ instance [LinearOrder ι] [IsWellOrder ι (· < ·)] [Nonempty ι] [∀ i, Parti smaller than the original function. -/ theorem lex_desc {α} [Preorder ι] [DecidableEq ι] [Preorder α] {f : ι → α} {i j : ι} (h₁ : i ≤ j) (h₂ : f j < f i) : toLex (f ∘ Equiv.swap i j) < toLex f := - ⟨i, fun k hik => congr_arg f (Equiv.swap_apply_of_ne_of_ne hik.ne (hik.trans_le h₁).ne), by + ⟨i, fun _ hik => congr_arg f (Equiv.swap_apply_of_ne_of_ne hik.ne (hik.trans_le h₁).ne), by simpa only [Pi.toLex_apply, Function.comp_apply, Equiv.swap_apply_left] using h₂⟩ end Pi diff --git a/Mathlib/Order/PrimeIdeal.lean b/Mathlib/Order/PrimeIdeal.lean index e8b6364e05f7b..aef2ade7bdfd4 100644 --- a/Mathlib/Order/PrimeIdeal.lean +++ b/Mathlib/Order/PrimeIdeal.lean @@ -101,7 +101,7 @@ end Preorder section SemilatticeInf -variable [SemilatticeInf P] {x y : P} {I : Ideal P} +variable [SemilatticeInf P] {I : Ideal P} theorem IsPrime.mem_or_mem (hI : IsPrime I) {x y : P} : x ⊓ y ∈ I → x ∈ I ∨ y ∈ I := by contrapose! diff --git a/Mathlib/Order/Rel/GaloisConnection.lean b/Mathlib/Order/Rel/GaloisConnection.lean index 0edf015bf7466..9666eb999ee6b 100644 --- a/Mathlib/Order/Rel/GaloisConnection.lean +++ b/Mathlib/Order/Rel/GaloisConnection.lean @@ -51,7 +51,7 @@ def rightDual (I : Set β) : Set α := {a : α | ∀ ⦃b⦄, b ∈ I → R a b} /-- The pair of functions `toDual ∘ leftDual` and `rightDual ∘ ofDual` forms a Galois connection. -/ theorem gc_leftDual_rightDual : GaloisConnection (toDual ∘ R.leftDual) (R.rightDual ∘ ofDual) := - fun J I ↦ ⟨fun h a ha b hb ↦ h (by simpa) ha, fun h b hb a ha ↦ h (by simpa) hb⟩ + fun _ _ ↦ ⟨fun h _ ha _ hb ↦ h (by simpa) ha, fun h _ hb _ ha ↦ h (by simpa) hb⟩ /-! ### Induced equivalences between fixed points -/ diff --git a/Mathlib/Order/RelClasses.lean b/Mathlib/Order/RelClasses.lean index be726cd3e66f4..2e5d1f0e9e0d3 100644 --- a/Mathlib/Order/RelClasses.lean +++ b/Mathlib/Order/RelClasses.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro, Yury Kudryashov -/ import Mathlib.Data.Nat.Defs -import Mathlib.Init.Algebra.Classes import Mathlib.Logic.IsEmpty import Mathlib.Order.Basic import Mathlib.Tactic.MkIffOfInductiveProp @@ -90,10 +89,6 @@ theorem IsStrictOrder.swap (r) [IsStrictOrder α r] : IsStrictOrder α (swap r) theorem IsPartialOrder.swap (r) [IsPartialOrder α r] : IsPartialOrder α (swap r) := { @IsPreorder.swap α r _, @IsAntisymm.swap α r _ with } -@[deprecated (since := "2024-07-30")] -theorem IsTotalPreorder.swap (r) [IsTotalPreorder α r] : IsTotalPreorder α (swap r) := - { @IsPreorder.swap α r _, @IsTotal.swap α r _ with } - @[deprecated (since := "2024-07-30")] theorem IsLinearOrder.swap (r) [IsLinearOrder α r] : IsLinearOrder α (swap r) := { @IsPartialOrder.swap α r _, @IsTotal.swap α r _ with } @@ -159,7 +154,7 @@ See note [reducible non-instances]. -/ abbrev partialOrderOfSO (r) [IsStrictOrder α r] : PartialOrder α where le x y := x = y ∨ r x y lt := r - le_refl x := Or.inl rfl + le_refl _ := Or.inl rfl le_trans x y z h₁ h₂ := match y, z, h₁, h₂ with | _, _, Or.inl rfl, h₂ => h₂ @@ -185,7 +180,7 @@ abbrev linearOrderOfSTO (r) [IsStrictTotalOrder α r] [∀ x y, Decidable ¬r x { __ := partialOrderOfSO r le_total := fun x y => match y, trichotomous_of r x y with - | y, Or.inl h => Or.inl (Or.inr h) + | _, Or.inl h => Or.inl (Or.inr h) | _, Or.inr (Or.inl rfl) => Or.inl (Or.inl rfl) | _, Or.inr (Or.inr h) => Or.inr (Or.inr h), toMin := minOfLe, @@ -777,9 +772,6 @@ instance LE.isTotal [LinearOrder α] : IsTotal α (· ≤ ·) := instance [LinearOrder α] : IsTotal α (· ≥ ·) := IsTotal.swap _ -@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where -@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where - instance [LinearOrder α] : IsLinearOrder α (· ≤ ·) where instance [LinearOrder α] : IsLinearOrder α (· ≥ ·) where @@ -800,9 +792,6 @@ instance [LinearOrder α] : IsStrictTotalOrder α (· < ·) where instance [LinearOrder α] : IsOrderConnected α (· < ·) := by infer_instance -@[deprecated (since := "2024-07-30")] -instance [LinearOrder α] : IsIncompTrans α (· < ·) := by infer_instance - @[deprecated (since := "2024-07-30")] instance [LinearOrder α] : IsStrictWeakOrder α (· < ·) := by infer_instance diff --git a/Mathlib/Order/RelIso/Basic.lean b/Mathlib/Order/RelIso/Basic.lean index 4c5eb975fb749..ae6e5fc6d18b7 100644 --- a/Mathlib/Order/RelIso/Basic.lean +++ b/Mathlib/Order/RelIso/Basic.lean @@ -349,15 +349,15 @@ instance Subtype.wellFoundedGT [LT α] [WellFoundedGT α] (p : α → Prop) : WellFoundedGT (Subtype p) := (Subtype.relEmbedding (· > ·) p).isWellFounded -/-- `Quotient.mk'` as a relation homomorphism between the relation and the lift of a relation. -/ +/-- `Quotient.mk` as a relation homomorphism between the relation and the lift of a relation. -/ @[simps] -def Quotient.mkRelHom [Setoid α] {r : α → α → Prop} +def Quotient.mkRelHom {_ : Setoid α} {r : α → α → Prop} (H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂) : r →r Quotient.lift₂ r H := - ⟨@Quotient.mk' α _, id⟩ + ⟨Quotient.mk _, id⟩ /-- `Quotient.out` as a relation embedding between the lift of a relation and the relation. -/ @[simps!] -noncomputable def Quotient.outRelEmbedding [Setoid α] {r : α → α → Prop} +noncomputable def Quotient.outRelEmbedding {_ : Setoid α} {r : α → α → Prop} (H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂) : Quotient.lift₂ r H ↪r r := ⟨Embedding.quotientOut α, by refine @fun x y => Quotient.inductionOn₂ x y fun a b => ?_ @@ -371,7 +371,7 @@ noncomputable def Quotient.out'RelEmbedding {_ : Setoid α} {r : α → α → P { Quotient.outRelEmbedding H with toFun := Quotient.out' } @[simp] -theorem acc_lift₂_iff [Setoid α] {r : α → α → Prop} +theorem acc_lift₂_iff {_ : Setoid α} {r : α → α → Prop} {H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂} {a} : Acc (Quotient.lift₂ r H) ⟦a⟧ ↔ Acc r a := by constructor @@ -389,7 +389,7 @@ theorem acc_liftOn₂'_iff {s : Setoid α} {r : α → α → Prop} {H} {a} : /-- A relation is well founded iff its lift to a quotient is. -/ @[simp] -theorem wellFounded_lift₂_iff [Setoid α] {r : α → α → Prop} +theorem wellFounded_lift₂_iff {_ : Setoid α} {r : α → α → Prop} {H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂} : WellFounded (Quotient.lift₂ r H) ↔ WellFounded r := by constructor diff --git a/Mathlib/Order/RelIso/Group.lean b/Mathlib/Order/RelIso/Group.lean index 352ac47981f5a..73cd157bc3f54 100644 --- a/Mathlib/Order/RelIso/Group.lean +++ b/Mathlib/Order/RelIso/Group.lean @@ -19,9 +19,9 @@ instance : Group (r ≃r r) where one := RelIso.refl r mul f₁ f₂ := f₂.trans f₁ inv := RelIso.symm - mul_assoc f₁ f₂ f₃ := rfl - one_mul f := ext fun _ => rfl - mul_one f := ext fun _ => rfl + mul_assoc _ _ _ := rfl + one_mul _ := ext fun _ => rfl + mul_one _ := ext fun _ => rfl inv_mul_cancel f := ext f.symm_apply_apply @[simp] diff --git a/Mathlib/Order/RelIso/Set.lean b/Mathlib/Order/RelIso/Set.lean index fbf5dd9ac208e..ec7b62b18b16f 100644 --- a/Mathlib/Order/RelIso/Set.lean +++ b/Mathlib/Order/RelIso/Set.lean @@ -19,8 +19,7 @@ open Function universe u v w -variable {α β γ δ : Type*} {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} - {u : δ → δ → Prop} +variable {α β : Type*} {r : α → α → Prop} {s : β → β → Prop} namespace RelHomClass @@ -92,8 +91,6 @@ theorem RelEmbedding.codRestrict_apply (p) (f : r ↪r s) (H a) : section image -variable {α β : Type*} {r : α → α → Prop} {s : β → β → Prop} - theorem RelIso.image_eq_preimage_symm (e : r ≃r s) (t : Set α) : e '' t = e.symm ⁻¹' t := e.toEquiv.image_eq_preimage t @@ -101,3 +98,14 @@ theorem RelIso.preimage_eq_image_symm (e : r ≃r s) (t : Set β) : e ⁻¹' t = rw [e.symm.image_eq_preimage_symm]; rfl end image + +theorem Acc.of_subrel {r : α → α → Prop} [IsTrans α r] {b : α} (a : { a // r a b }) + (h : Acc (Subrel r { a | r a b }) a) : Acc r a.1 := + h.recOn fun a _ IH ↦ ⟨_, fun _ hb ↦ IH ⟨_, _root_.trans hb a.2⟩ hb⟩ + +/-- A relation `r` is well-founded iff every downward-interval `{ a | r a b }` of it is +well-founded. -/ +theorem wellFounded_iff_wellFounded_subrel {r : α → α → Prop} [IsTrans α r] : + WellFounded r ↔ ∀ b, WellFounded (Subrel r { a | r a b }) where + mp h _ := InvImage.wf Subtype.val h + mpr h := ⟨fun a ↦ ⟨_, fun b hr ↦ ((h a).apply _).of_subrel ⟨b, hr⟩⟩⟩ diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index d01a0e54fc8ee..b2c41395b294b 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -704,7 +704,7 @@ def injStrictMono (n : ℕ) : simp_rw [Subtype.mk_eq_mk, Sigma.mk.inj_iff, heq_eq_eq, true_and] have feq := fun i ↦ congr($(e).toFun i) simp_rw [mk_toFun lf f mf, mk_toFun lf g mg, mk_length lf f mf] at feq - rwa [Function.funext_iff] + rwa [funext_iff] /-- For two preorders `α, β`, if `f : α → β` is strictly monotonic, then a strict chain of `α` diff --git a/Mathlib/Order/ScottContinuity.lean b/Mathlib/Order/ScottContinuity.lean index 511092cd0a000..5ed5137f7bd16 100644 --- a/Mathlib/Order/ScottContinuity.lean +++ b/Mathlib/Order/ScottContinuity.lean @@ -32,8 +32,8 @@ open Set variable {α β : Type*} section ScottContinuous -variable [Preorder α] [Preorder β] {D D₁ D₂ : Set (Set α)} {E : Set (Set β)} - {f : α → β} {a : α} +variable [Preorder α] [Preorder β] {D D₁ D₂ : Set (Set α)} + {f : α → β} /-- A function between preorders is said to be Scott continuous on a set `D` of directed sets if it preserves `IsLUB` on elements of `D`. @@ -109,7 +109,7 @@ end ScottContinuous section SemilatticeSup -variable [Preorder α] [SemilatticeSup β] +variable [SemilatticeSup β] lemma ScottContinuousOn.sup₂ {D : Set (Set (β × β))} : ScottContinuousOn D fun (a, b) => (a ⊔ b : β) := by diff --git a/Mathlib/Order/SemiconjSup.lean b/Mathlib/Order/SemiconjSup.lean index ebadc1795ef66..a5fa1eb1ef1fa 100644 --- a/Mathlib/Order/SemiconjSup.lean +++ b/Mathlib/Order/SemiconjSup.lean @@ -6,7 +6,6 @@ Authors: Yury Kudryashov import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Logic.Function.Conjugate import Mathlib.Order.Bounds.OrderIso -import Mathlib.Order.ConditionallyCompleteLattice.Basic import Mathlib.Order.OrdContinuous import Mathlib.Order.RelIso.Group diff --git a/Mathlib/Order/SuccPred/Archimedean.lean b/Mathlib/Order/SuccPred/Archimedean.lean index 6a225c713afdc..4ba2d38f22bdc 100644 --- a/Mathlib/Order/SuccPred/Archimedean.lean +++ b/Mathlib/Order/SuccPred/Archimedean.lean @@ -68,6 +68,19 @@ theorem Succ.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (succ a)) {a b obtain ⟨n, rfl⟩ := h.exists_succ_iterate exact Iterate.rec (fun b => p a ↔ p b) (fun c hc => hc.trans (hsucc _)) Iff.rfl n +lemma le_total_of_codirected {r v₁ v₂ : α} (h₁ : r ≤ v₁) (h₂ : r ≤ v₂) : v₁ ≤ v₂ ∨ v₂ ≤ v₁ := by + obtain ⟨n, rfl⟩ := h₁.exists_succ_iterate + obtain ⟨m, rfl⟩ := h₂.exists_succ_iterate + clear h₁ h₂ + wlog h : n ≤ m + · rw [Or.comm] + apply this + exact Nat.le_of_not_ge h + left + obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h + rw [Nat.add_comm, Function.iterate_add, Function.comp_apply] + apply Order.le_succ_iterate + end SuccOrder section PredOrder @@ -93,10 +106,59 @@ theorem Pred.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) {a b p a ↔ p b := (Succ.rec_iff (α := αᵒᵈ) hsucc h).symm +lemma le_total_of_directed {r v₁ v₂ : α} (h₁ : v₁ ≤ r) (h₂ : v₂ ≤ r) : v₁ ≤ v₂ ∨ v₂ ≤ v₁ := + Or.symm (le_total_of_codirected (α := αᵒᵈ) h₁ h₂) + end PredOrder end Preorder +section PartialOrder + +variable [PartialOrder α] + +lemma lt_or_le_of_codirected [SuccOrder α] [IsSuccArchimedean α] {r v₁ v₂ : α} (h₁ : r ≤ v₁) + (h₂ : r ≤ v₂) : v₁ < v₂ ∨ v₂ ≤ v₁ := by + rw [Classical.or_iff_not_imp_right] + intro nh + rcases le_total_of_codirected h₁ h₂ with h | h + · apply lt_of_le_of_ne h (ne_of_not_le nh).symm + · contradiction + +/-- +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 + le_total a b := + have ⟨c, ha, hb⟩ := directed_of (· ≥ ·) a b + le_total_of_codirected ha hb + decidableEq := inferInstance + decidableLE := inferInstance + decidableLT := inferInstance + +lemma lt_or_le_of_directed [PredOrder α] [IsPredArchimedean α] {r v₁ v₂ : α} (h₁ : v₁ ≤ r) + (h₂ : v₂ ≤ r) : v₁ < v₂ ∨ v₂ ≤ v₁ := by + rw [Classical.or_iff_not_imp_right] + intro nh + rcases le_total_of_directed h₁ h₂ with h | h + · apply lt_of_le_of_ne h (ne_of_not_le nh).symm + · contradiction + +/-- +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 α := + letI : LinearOrder αᵒᵈ := IsSuccArchimedean.linearOrder + inferInstanceAs (LinearOrder αᵒᵈᵒᵈ) + +end PartialOrder + section LinearOrder variable [LinearOrder α] @@ -234,6 +296,39 @@ lemma SuccOrder.forall_ne_bot_iff simp only [Function.iterate_succ', Function.comp_apply] apply h +section IsLeast + +-- TODO: generalize to PartialOrder and `DirectedOn` after #16272 +lemma BddAbove.exists_isGreatest_of_nonempty {X : Type*} [LinearOrder X] [SuccOrder X] + [IsSuccArchimedean X] {S : Set X} (hS : BddAbove S) (hS' : S.Nonempty) : + ∃ x, IsGreatest S x := by + obtain ⟨m, hm⟩ := hS + obtain ⟨n, hn⟩ := hS' + by_cases hm' : m ∈ S + · exact ⟨_, hm', hm⟩ + have hn' := hm hn + revert hn hm hm' + refine Succ.rec ?_ ?_ hn' + · simp (config := {contextual := true}) + intro m _ IH hm hn hm' + rw [mem_upperBounds] at IH hm + simp_rw [Order.le_succ_iff_eq_or_le] at hm + replace hm : ∀ x ∈ S, x ≤ m := by + intro x hx + refine (hm x hx).resolve_left ?_ + rintro rfl + exact hm' hx + by_cases hmS : m ∈ S + · exact ⟨m, hmS, hm⟩ + · exact IH hm hn hmS + +lemma BddBelow.exists_isLeast_of_nonempty {X : Type*} [LinearOrder X] [PredOrder X] + [IsPredArchimedean X] {S : Set X} (hS : BddBelow S) (hS' : S.Nonempty) : + ∃ x, IsLeast S x := + hS.dual.exists_isGreatest_of_nonempty hS' + +end IsLeast + section OrderIso variable {X Y : Type*} [PartialOrder X] [PartialOrder Y] @@ -265,3 +360,153 @@ protected lemma IsPredArchimedean.of_orderIso [PredOrder X] [IsPredArchimedean X | succ n IH => simp only [Function.iterate_succ', Function.comp_apply, IH, f.map_pred] end OrderIso + +section OrdConnected + +variable [PartialOrder α] + +instance Set.OrdConnected.isPredArchimedean [PredOrder α] [IsPredArchimedean α] + (s : Set α) [s.OrdConnected] : IsPredArchimedean s where + exists_pred_iterate_of_le := @fun ⟨b, hb⟩ ⟨c, hc⟩ hbc ↦ by classical + simp only [Subtype.mk_le_mk] at hbc + obtain ⟨n, hn⟩ := hbc.exists_pred_iterate + use n + induction n generalizing c with + | zero => simp_all + | succ n hi => + simp_all only [Function.iterate_succ, Function.comp_apply] + change Order.pred^[n] (dite ..) = _ + split_ifs with h + · dsimp only at h ⊢ + apply hi _ _ _ hn + · rw [← hn] + apply Order.pred_iterate_le + · have : Order.pred (⟨c, hc⟩ : s) = ⟨c, hc⟩ := by + change dite .. = _ + simp [h] + rw [Function.iterate_fixed] + · simp only [Order.pred_eq_iff_isMin] at this + apply (this.eq_of_le _).symm + exact hbc + · exact this + +instance Set.OrdConnected.isSuccArchimedean [SuccOrder α] [IsSuccArchimedean α] + (s : Set α) [s.OrdConnected] : IsSuccArchimedean s := + letI : IsPredArchimedean sᵒᵈ := inferInstanceAs (IsPredArchimedean (OrderDual.ofDual ⁻¹' s)) + inferInstanceAs (IsSuccArchimedean sᵒᵈᵒᵈ) + +end OrdConnected + +section Monotone +variable {α β : Type*} [PartialOrder α] [Preorder β] + +section SuccOrder +variable [SuccOrder α] [IsSuccArchimedean α] {s : Set α} {f : α → β} + +lemma monotoneOn_of_le_succ (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMax a → a ∈ s → succ a ∈ s → f a ≤ f (succ a)) : MonotoneOn f s := by + rintro a ha b hb hab + obtain ⟨n, rfl⟩ := exists_succ_iterate_of_le hab + clear hab + induction' n with n hn + · simp + rw [Function.iterate_succ_apply'] at hb ⊢ + have : succ^[n] a ∈ s := hs.1 ha hb ⟨le_succ_iterate .., le_succ _⟩ + by_cases hb' : IsMax (succ^[n] a) + · rw [succ_eq_iff_isMax.2 hb'] + exact hn this + · exact (hn this).trans (hf _ hb' this hb) + +lemma antitoneOn_of_succ_le (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMax a → a ∈ s → succ a ∈ s → f (succ a) ≤ f a) : AntitoneOn f s := + monotoneOn_of_le_succ (β := βᵒᵈ) hs hf + +lemma strictMonoOn_of_lt_succ (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMax a → a ∈ s → succ a ∈ s → f a < f (succ a)) : StrictMonoOn f s := by + rintro a ha b hb hab + obtain ⟨n, rfl⟩ := exists_succ_iterate_of_le hab.le + obtain _ | n := n + · simp at hab + apply not_isMax_of_lt at hab + induction' n with n hn + · simpa using hf _ hab ha hb + rw [Function.iterate_succ_apply'] at hb ⊢ + have : succ^[n + 1] a ∈ s := hs.1 ha hb ⟨le_succ_iterate .., le_succ _⟩ + by_cases hb' : IsMax (succ^[n + 1] a) + · rw [succ_eq_iff_isMax.2 hb'] + exact hn this + · exact (hn this).trans (hf _ hb' this hb) + +lemma strictAntiOn_of_succ_lt (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMax a → a ∈ s → succ a ∈ s → f (succ a) < f a) : StrictAntiOn f s := + strictMonoOn_of_lt_succ (β := βᵒᵈ) hs hf + +lemma monotone_of_le_succ (hf : ∀ a, ¬ IsMax a → f a ≤ f (succ a)) : Monotone f := by + simpa using monotoneOn_of_le_succ Set.ordConnected_univ (by simpa using hf) + +lemma antitone_of_succ_le (hf : ∀ a, ¬ IsMax a → f (succ a) ≤ f a) : Antitone f := by + simpa using antitoneOn_of_succ_le Set.ordConnected_univ (by simpa using hf) + +lemma strictMono_of_lt_succ (hf : ∀ a, ¬ IsMax a → f a < f (succ a)) : StrictMono f := by + simpa using strictMonoOn_of_lt_succ Set.ordConnected_univ (by simpa using hf) + +lemma strictAnti_of_succ_lt (hf : ∀ a, ¬ IsMax a → f (succ a) < f a) : StrictAnti f := by + simpa using strictAntiOn_of_succ_lt Set.ordConnected_univ (by simpa using hf) + +end SuccOrder + +section PredOrder +variable [PredOrder α] [IsPredArchimedean α] {s : Set α} {f : α → β} + +lemma monotoneOn_of_pred_le (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMin a → a ∈ s → pred a ∈ s → f (pred a) ≤ f a) : MonotoneOn f s := by + rintro a ha b hb hab + obtain ⟨n, rfl⟩ := exists_pred_iterate_of_le hab + clear hab + induction' n with n hn + · simp + rw [Function.iterate_succ_apply'] at ha ⊢ + have : pred^[n] b ∈ s := hs.1 ha hb ⟨pred_le _, pred_iterate_le ..⟩ + by_cases ha' : IsMin (pred^[n] b) + · rw [pred_eq_iff_isMin.2 ha'] + exact hn this + · exact (hn this).trans' (hf _ ha' this ha) + +lemma antitoneOn_of_le_pred (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMin a → a ∈ s → pred a ∈ s → f a ≤ f (pred a)) : AntitoneOn f s := + monotoneOn_of_pred_le (β := βᵒᵈ) hs hf + +lemma strictMonoOn_of_pred_lt (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMin a → a ∈ s → pred a ∈ s → f (pred a) < f a) : StrictMonoOn f s := by + rintro a ha b hb hab + obtain ⟨n, rfl⟩ := exists_pred_iterate_of_le hab.le + obtain _ | n := n + · simp at hab + apply not_isMin_of_lt at hab + induction' n with n hn + · simpa using hf _ hab hb ha + rw [Function.iterate_succ_apply'] at ha ⊢ + have : pred^[n + 1] b ∈ s := hs.1 ha hb ⟨pred_le _, pred_iterate_le ..⟩ + by_cases ha' : IsMin (pred^[n + 1] b) + · rw [pred_eq_iff_isMin.2 ha'] + exact hn this + · exact (hn this).trans' (hf _ ha' this ha) + +lemma strictAntiOn_of_lt_pred (hs : s.OrdConnected) + (hf : ∀ a, ¬ IsMin a → a ∈ s → pred a ∈ s → f a < f (pred a)) : StrictAntiOn f s := + strictMonoOn_of_pred_lt (β := βᵒᵈ) hs hf + +lemma monotone_of_pred_le (hf : ∀ a, ¬ IsMin a → f (pred a) ≤ f a) : Monotone f := by + simpa using monotoneOn_of_pred_le Set.ordConnected_univ (by simpa using hf) + +lemma antitone_of_le_pred (hf : ∀ a, ¬ IsMin a → f a ≤ f (pred a)) : Antitone f := by + simpa using antitoneOn_of_le_pred Set.ordConnected_univ (by simpa using hf) + +lemma strictMono_of_pred_lt (hf : ∀ a, ¬ IsMin a → f (pred a) < f a) : StrictMono f := by + simpa using strictMonoOn_of_pred_lt Set.ordConnected_univ (by simpa using hf) + +lemma strictAnti_of_lt_pred (hf : ∀ a, ¬ IsMin a → f a < f (pred a)) : StrictAnti f := by + simpa using strictAntiOn_of_lt_pred Set.ordConnected_univ (by simpa using hf) + +end PredOrder +end Monotone diff --git a/Mathlib/Order/SuccPred/Basic.lean b/Mathlib/Order/SuccPred/Basic.lean index aef647a6f8d31..55b6157d4a5db 100644 --- a/Mathlib/Order/SuccPred/Basic.lean +++ b/Mathlib/Order/SuccPred/Basic.lean @@ -24,7 +24,7 @@ order... Maximal elements don't have a sensible successor. Thus the naïve typeclass ```lean -class NaiveSuccOrder (α : Type*) [Preorder α] := +class NaiveSuccOrder (α : Type*) [Preorder α] where (succ : α → α) (succ_le_iff : ∀ {a b}, succ a ≤ b ↔ a < b) (lt_succ_iff : ∀ {a b}, a < succ b ↔ a ≤ b) @@ -143,7 +143,7 @@ noncomputable def SuccOrder.ofLinearWellFoundedLT [WellFoundedLT α] : SuccOrder rw [not_isMax_iff] at ha simp_rw [Set.Nonempty, mem_Ioi, dif_pos ha] exact ⟨(wellFounded_lt.min_le · ha), lt_of_lt_of_le (wellFounded_lt.min_mem _ ha)⟩) - fun a ha ↦ dif_neg (not_not_intro ha <| not_isMax_iff.mpr ·) + fun _ ha ↦ dif_neg (not_not_intro ha <| not_isMax_iff.mpr ·) /-- A linear order with well-founded greater-than relation is a `PredOrder`. -/ noncomputable def PredOrder.ofLinearWellFoundedGT (α) [LinearOrder α] [WellFoundedGT α] : @@ -1237,3 +1237,78 @@ protected abbrev PredOrder.ofOrderIso [PredOrder X] (f : X ≃o Y) : le_pred_of_lt h := by rw [← map_inv_le_iff]; exact le_pred_of_lt (by simp [h]) end OrderIso + +section OrdConnected + +variable {α : Type*} [PartialOrder α] {s : Set α} [s.OrdConnected] + +open scoped Classical in +noncomputable instance Set.OrdConnected.predOrder [PredOrder α] : + PredOrder s where + pred x := if h : Order.pred x.1 ∈ s then ⟨Order.pred x.1, h⟩ else x + pred_le := fun ⟨x, hx⟩ ↦ by dsimp; split <;> simp_all [Order.pred_le] + min_of_le_pred := @fun ⟨x, hx⟩ h ↦ by + dsimp at h + split_ifs at h with h' + · simp only [Subtype.mk_le_mk, Order.le_pred_iff_isMin] at h + rintro ⟨y, _⟩ hy + simp [h hy] + · rintro ⟨y, hy⟩ h + rcases h.lt_or_eq with h | h + · simp only [Subtype.mk_lt_mk] at h + have := h.le_pred + absurd h' + apply out' hy hx + simp [this, Order.pred_le] + · simp [h] + le_pred_of_lt := @fun ⟨b, hb⟩ ⟨c, hc⟩ h ↦ by + rw [Subtype.mk_lt_mk] at h + dsimp only + split + · exact h.le_pred + · exact h.le + +@[simp, norm_cast] +lemma coe_pred_of_mem [PredOrder α] {a : s} (h : pred a.1 ∈ s) : + (pred a).1 = pred ↑a := by classical + change Subtype.val (dite ..) = _ + simp [h] + +lemma isMin_of_not_pred_mem [PredOrder α] {a : s} (h : pred ↑a ∉ s) : IsMin a := by classical + rw [← pred_eq_iff_isMin] + change dite .. = _ + simp [h] + +lemma not_pred_mem_iff_isMin [PredOrder α] [NoMinOrder α] {a : s} : + pred ↑a ∉ s ↔ IsMin a where + mp := isMin_of_not_pred_mem + mpr h nh := by + replace h := congr($h.pred_eq.1) + rw [coe_pred_of_mem nh] at h + simp at h + +noncomputable instance Set.OrdConnected.succOrder [SuccOrder α] : + SuccOrder s := + letI : PredOrder sᵒᵈ := inferInstanceAs (PredOrder (OrderDual.ofDual ⁻¹' s)) + inferInstanceAs (SuccOrder sᵒᵈᵒᵈ) + +@[simp, norm_cast] +lemma coe_succ_of_mem [SuccOrder α] {a : s} (h : succ ↑a ∈ s) : + (succ a).1 = succ ↑a := by classical + change Subtype.val (dite ..) = _ + split_ifs <;> trivial + +lemma isMax_of_not_succ_mem [SuccOrder α] {a : s} (h : succ ↑a ∉ s) : IsMax a := by classical + rw [← succ_eq_iff_isMax] + change dite .. = _ + split_ifs <;> trivial + +lemma not_succ_mem_iff_isMax [SuccOrder α] [NoMaxOrder α] {a : s} : + succ ↑a ∉ s ↔ IsMax a where + mp := isMax_of_not_succ_mem + mpr h nh := by + replace h := congr($h.succ_eq.1) + rw [coe_succ_of_mem nh] at h + simp at h + +end OrdConnected diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index 6b8b1de8ce9f3..c8ab06d7b669a 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.Order.SuccPred.Limit -import Mathlib.Order.ConditionallyCompleteLattice.Basic /-! diff --git a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean index f721b4e776979..e758ae8c0f2f4 100644 --- a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean +++ b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean @@ -185,7 +185,7 @@ end LinearLocallyFiniteOrder section toZ -- Requiring either of `IsSuccArchimedean` or `IsPredArchimedean` is equivalent. -variable [SuccOrder ι] [IsSuccArchimedean ι] [P : PredOrder ι] {i0 i : ι} +variable [SuccOrder ι] [IsSuccArchimedean ι] [PredOrder ι] {i0 i : ι} -- For "to_Z" @@ -200,7 +200,7 @@ theorem toZ_of_ge (hi : i0 ≤ i) : toZ i0 i = Nat.find (exists_succ_iterate_of_ dif_pos hi theorem toZ_of_lt (hi : i < i0) : - toZ i0 i = -Nat.find (@exists_pred_iterate_of_le _ _ P _ _ _ hi.le) := + toZ i0 i = -Nat.find (exists_pred_iterate_of_le (α := ι) hi.le) := dif_neg (not_le.mpr hi) @[simp] @@ -311,8 +311,8 @@ theorem toZ_mono {i j : ι} (h_le : i ≤ j) : toZ i0 i ≤ toZ i0 j := by · exact le_of_not_le h · exact absurd h_le (not_le.mpr (hj.trans_le hi)) · exact (toZ_neg hi).le.trans (toZ_nonneg hj) - · let m := Nat.find (@exists_pred_iterate_of_le _ _ P _ _ _ h_le) - have hm : pred^[m] j = i := Nat.find_spec (exists_pred_iterate_of_le h_le) + · let m := Nat.find (exists_pred_iterate_of_le (α := ι) h_le) + have hm : pred^[m] j = i := Nat.find_spec (exists_pred_iterate_of_le (α := ι) h_le) have hj_eq : i = pred^[(-toZ i0 j).toNat + m] i0 := by rw [← hm, add_comm] nth_rw 1 [← iterate_pred_toZ j hj] diff --git a/Mathlib/Order/SuccPred/Tree.lean b/Mathlib/Order/SuccPred/Tree.lean new file mode 100644 index 0000000000000..ea7ab54e7fb12 --- /dev/null +++ b/Mathlib/Order/SuccPred/Tree.lean @@ -0,0 +1,228 @@ +/- +Copyright (c) 2024 Daniel Weber. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Daniel Weber +-/ + +import Mathlib.Order.SuccPred.Archimedean +import Mathlib.Data.Nat.Find +import Mathlib.Order.Atoms +import Mathlib.Data.SetLike.Basic + +/-! +# Rooted trees + +This file proves basic results about rooted trees, represented using the ancestorship order. +This is a `PartialOrder`, with `PredOrder` with the immediate parent as a predecessor, and an +`OrderBot` which is the root. We also have an `IsPredArchimedean` assumption to prevent infinite +dangling chains. + +--/ + +variable {α : Type*} [PartialOrder α] [PredOrder α] [IsPredArchimedean α] + +namespace IsPredArchimedean + +variable [OrderBot α] + +section DecidableEq + +variable [DecidableEq α] + +/-- +The unique atom less than an element in an `OrderBot` with archimedean predecessor. +-/ +def findAtom (r : α) : α := + Order.pred^[Nat.find (bot_le (a := r)).exists_pred_iterate - 1] r + +@[simp] +lemma findAtom_le (r : α) : findAtom r ≤ r := + Order.pred_iterate_le _ _ + +@[simp] +lemma findAtom_bot : findAtom (⊥ : α) = ⊥ := by + apply Function.iterate_fixed + simp + +@[simp] +lemma pred_findAtom (r : α) : Order.pred (findAtom r) = ⊥ := by + unfold findAtom + generalize h : Nat.find (bot_le (a := r)).exists_pred_iterate = n + cases n + · have : Order.pred^[0] r = ⊥ := by + rw [← h] + apply Nat.find_spec (bot_le (a := r)).exists_pred_iterate + simp only [Function.iterate_zero, id_eq] at this + simp [this] + · simp only [Nat.add_sub_cancel_right, ← Function.iterate_succ_apply', Nat.succ_eq_add_one] + rw [← h] + apply Nat.find_spec (bot_le (a := r)).exists_pred_iterate + +@[simp] +lemma findAtom_eq_bot {r : α} : + findAtom r = ⊥ ↔ r = ⊥ where + mp h := by + unfold findAtom at h + have := Nat.find_min' (bot_le (a := r)).exists_pred_iterate h + replace : Nat.find (bot_le (a := r)).exists_pred_iterate = 0 := by omega + simpa [this] using h + mpr h := by simp [h] + +lemma findAtom_ne_bot {r : α} : + findAtom r ≠ ⊥ ↔ r ≠ ⊥ := findAtom_eq_bot.not + +lemma isAtom_findAtom {r : α} (hr : r ≠ ⊥) : + IsAtom (findAtom r) := by + constructor + · simp [hr] + · intro b hb + apply Order.le_pred_of_lt at hb + simpa using hb + +@[simp] +lemma isAtom_findAtom_iff {r : α} : + IsAtom (findAtom r) ↔ r ≠ ⊥ where + mpr := isAtom_findAtom + mp h nh := by simp only [nh, findAtom_bot] at h; exact h.1 rfl + +end DecidableEq + +instance instIsAtomic : IsAtomic α where + eq_bot_or_exists_atom_le b := by classical + rw [or_iff_not_imp_left] + intro hb + use findAtom b, isAtom_findAtom hb, findAtom_le b + +end IsPredArchimedean + +/-- +The type of rooted trees. +-/ +structure RootedTree where + /-- The type representing the elements in the tree. -/ + α : Type* + /-- The type should be a `SemilatticeInf`, + where `inf` is the least common ancestor in the tree. -/ + [semilatticeInf : SemilatticeInf α] + /-- The type should have a bottom, the root. -/ + [orderBot : OrderBot α] + /-- The type should have a predecessor for every element, its parent. -/ + [predOrder : PredOrder α] + /-- The predecessor relationship should be archimedean. -/ + [isPredArchimedean : IsPredArchimedean α] + +attribute [coe] RootedTree.α + +instance : CoeSort RootedTree Type* := ⟨RootedTree.α⟩ + +attribute [instance] RootedTree.semilatticeInf RootedTree.predOrder + RootedTree.orderBot RootedTree.isPredArchimedean + +/-- +A subtree is represented by its root, therefore this is a type synonym. +-/ +def SubRootedTree (t : RootedTree) : Type* := t + +/-- +The root of a `SubRootedTree`. +-/ +def SubRootedTree.root {t : RootedTree} (v : SubRootedTree t) : t := v + +/-- +The `SubRootedTree` rooted at a given node. +-/ +def RootedTree.subtree (t : RootedTree) (r : t) : SubRootedTree t := r + +@[simp] +lemma RootedTree.root_subtree (t : RootedTree) (r : t) : (t.subtree r).root = r := rfl + +@[simp] +lemma RootedTree.subtree_root (t : RootedTree) (v : SubRootedTree t) : t.subtree v.root = v := rfl + +@[ext] +lemma SubRootedTree.ext {t : RootedTree} {v₁ v₂ : SubRootedTree t} + (h : v₁.root = v₂.root) : v₁ = v₂ := h + +instance (t : RootedTree) : SetLike (SubRootedTree t) t where + coe v := Set.Ici v.root + coe_injective' a₁ a₂ h := by + simpa only [Set.Ici_inj, ← SubRootedTree.ext_iff] using h + +lemma SubRootedTree.mem_iff {t : RootedTree} {r : SubRootedTree t} {v : t} : + v ∈ r ↔ r.root ≤ v := Iff.rfl + +/-- +The coercion from a `SubRootedTree` to a `RootedTree`. +-/ +@[coe, reducible] +noncomputable def SubRootedTree.coeTree {t : RootedTree} (r : SubRootedTree t) : RootedTree where + α := Set.Ici r.root + +noncomputable instance (t : RootedTree) : CoeOut (SubRootedTree t) RootedTree := + ⟨SubRootedTree.coeTree⟩ + +@[simp] +lemma SubRootedTree.bot_mem_iff {t : RootedTree} (r : SubRootedTree t) : + ⊥ ∈ r ↔ r.root = ⊥ := by + simp [mem_iff] + +/-- +All of the immediate subtrees of a given rooted tree, that is subtrees which are rooted at a direct +child of the root (or, order theoretically, at an atom). +-/ +def RootedTree.subtrees (t : RootedTree) : Set (SubRootedTree t) := + {x | IsAtom x.root} + +variable {t : RootedTree} + +lemma SubRootedTree.root_ne_bot_of_mem_subtrees (r : SubRootedTree t) (hr : r ∈ t.subtrees) : + r.root ≠ ⊥ := by + simp only [RootedTree.subtrees, Set.mem_setOf_eq] at hr + exact hr.1 + +lemma RootedTree.mem_subtrees_disjoint_iff {t₁ t₂ : SubRootedTree t} + (ht₁ : t₁ ∈ t.subtrees) (ht₂ : t₂ ∈ t.subtrees) (v₁ v₂ : t) (h₁ : v₁ ∈ t₁) + (h₂ : v₂ ∈ t₂) : + Disjoint v₁ v₂ ↔ t₁ ≠ t₂ where + mp h := by + intro nh + have : t₁.root ≤ (v₁ : t) ⊓ (v₂ : t) := by + simp only [le_inf_iff] + exact ⟨h₁, nh ▸ h₂⟩ + rw [h.eq_bot] at this + simp only [le_bot_iff] at this + exact t₁.root_ne_bot_of_mem_subtrees ht₁ this + mpr h := by + rw [SubRootedTree.mem_iff] at h₁ h₂ + contrapose! h + rw [disjoint_iff, ← ne_eq, ← bot_lt_iff_ne_bot] at h + rcases lt_or_le_of_directed (by simp : v₁ ⊓ v₂ ≤ v₁) h₁ with oh | oh + · simp_all [RootedTree.subtrees, IsAtom.lt_iff] + rw [le_inf_iff] at oh + ext + simpa only [ht₂.le_iff_eq ht₁.1, ht₁.le_iff_eq ht₂.1, eq_comm, or_self] using + le_total_of_directed oh.2 h₂ + +lemma RootedTree.subtrees_disjoint : t.subtrees.PairwiseDisjoint ((↑) : _ → Set t) := by + intro t₁ ht₁ t₂ ht₂ h + rw [Function.onFun_apply, Set.disjoint_left] + intro a ha hb + rw [← mem_subtrees_disjoint_iff ht₁ ht₂ a a ha hb, disjoint_self] at h + subst h + simp only [SetLike.mem_coe, SubRootedTree.bot_mem_iff] at ha + exact t₁.root_ne_bot_of_mem_subtrees ht₁ ha + +/-- +The immediate subtree of `t` containing `v`, or all of `t` if `v` is the root. +-/ +def RootedTree.subtreeOf (t : RootedTree) [DecidableEq t] (v : t) : SubRootedTree t := + t.subtree (IsPredArchimedean.findAtom v) + +@[simp] +lemma RootedTree.mem_subtreeOf [DecidableEq t] {v : t} : + v ∈ t.subtreeOf v := by + simp [SubRootedTree.mem_iff, RootedTree.subtreeOf] + +lemma RootedTree.subtreeOf_mem_subtrees [DecidableEq t] {v : t} (hr : v ≠ ⊥) : + t.subtreeOf v ∈ t.subtrees := by + simpa [RootedTree.subtrees, RootedTree.subtreeOf] diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index 998929ca5eab3..1e09bd963d671 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -306,7 +306,7 @@ lemma supClosure_min : s ⊆ t → SupClosed t → supClosure s ⊆ t := supClos protected lemma Set.Finite.supClosure (hs : s.Finite) : (supClosure s).Finite := by lift s to Finset α using hs classical - refine ((s.powerset.filter Finset.Nonempty).attach.image + refine ({t ∈ s.powerset | t.Nonempty}.attach.image fun t ↦ t.1.sup' (mem_filter.1 t.2).2 id).finite_toSet.subset ?_ rintro _ ⟨t, ht, hts, rfl⟩ simp only [id_eq, coe_image, mem_image, mem_coe, mem_attach, true_and, Subtype.exists, @@ -378,7 +378,7 @@ lemma infClosure_min : s ⊆ t → InfClosed t → infClosure s ⊆ t := infClos protected lemma Set.Finite.infClosure (hs : s.Finite) : (infClosure s).Finite := by lift s to Finset α using hs classical - refine ((s.powerset.filter Finset.Nonempty).attach.image + refine ({t ∈ s.powerset | t.Nonempty}.attach.image fun t ↦ t.1.inf' (mem_filter.1 t.2).2 id).finite_toSet.subset ?_ rintro _ ⟨t, ht, hts, rfl⟩ simp only [id_eq, coe_image, mem_image, mem_coe, mem_attach, true_and, Subtype.exists, @@ -469,7 +469,7 @@ end DistribLattice def SemilatticeSup.toCompleteSemilatticeSup [SemilatticeSup α] (sSup : Set α → α) (h : ∀ s, SupClosed s → IsLUB s (sSup s)) : CompleteSemilatticeSup α where sSup := fun s => sSup (supClosure s) - le_sSup s a ha := (h _ supClosed_supClosure).1 <| subset_supClosure ha + le_sSup _ _ ha := (h _ supClosed_supClosure).1 <| subset_supClosure ha sSup_le s a ha := (isLUB_le_iff <| h _ supClosed_supClosure).2 <| by rwa [upperBounds_supClosure] /-- A meet-semilattice where every inf-closed set has a greatest lower bound is automatically @@ -477,5 +477,5 @@ complete. -/ def SemilatticeInf.toCompleteSemilatticeInf [SemilatticeInf α] (sInf : Set α → α) (h : ∀ s, InfClosed s → IsGLB s (sInf s)) : CompleteSemilatticeInf α where sInf := fun s => sInf (infClosure s) - sInf_le s a ha := (h _ infClosed_infClosure).1 <| subset_infClosure ha + 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] diff --git a/Mathlib/Order/SupIndep.lean b/Mathlib/Order/SupIndep.lean index cb3c3c12cac6a..19f1467d5960c 100644 --- a/Mathlib/Order/SupIndep.lean +++ b/Mathlib/Order/SupIndep.lean @@ -94,6 +94,29 @@ theorem supIndep_iff_disjoint_erase [DecidableEq ι] : ⟨fun hs _ hi => hs (erase_subset _ _) hi (not_mem_erase _ _), fun hs _ ht i hi hit => (hs i hi).mono_right (sup_mono fun _ hj => mem_erase.2 ⟨ne_of_mem_of_not_mem hj hit, ht hj⟩)⟩ +theorem supIndep_antimono_fun {g : ι → α} (h : ∀ x ∈ s, f x ≤ g x) (h : s.SupIndep g) : + s.SupIndep f := by + classical + induction s using Finset.induction_on with + | empty => apply Finset.supIndep_empty + | @insert i s his IH => + rename_i hle + rw [Finset.supIndep_iff_disjoint_erase] at h ⊢ + intro j hj + simp_all only [Finset.mem_insert, or_true, implies_true, true_implies, forall_eq_or_imp, + Finset.erase_insert_eq_erase, not_false_eq_true, Finset.erase_eq_of_not_mem] + obtain rfl | hj := hj + · simp only [Finset.erase_insert_eq_erase] + apply h.left.mono hle.left + apply (Finset.sup_mono _).trans (Finset.sup_mono_fun hle.right) + exact Finset.erase_subset _ _ + · apply (h.right j hj).mono (hle.right j hj) (Finset.sup_mono_fun _) + intro k hk + simp only [Finset.mem_erase, ne_eq, Finset.mem_insert] at hk + obtain ⟨-, rfl | hk⟩ := hk + · exact hle.left + · exact hle.right k hk + theorem SupIndep.image [DecidableEq ι] {s : Finset ι'} {g : ι' → ι} (hs : s.SupIndep (f ∘ g)) : (s.image g).SupIndep f := by intro t ht i hi hit diff --git a/Mathlib/Order/SymmDiff.lean b/Mathlib/Order/SymmDiff.lean index fa8d23d3aa081..439253b07c5a3 100644 --- a/Mathlib/Order/SymmDiff.lean +++ b/Mathlib/Order/SymmDiff.lean @@ -89,7 +89,7 @@ theorem Bool.symmDiff_eq_xor : ∀ p q : Bool, p ∆ q = xor p q := by decide section GeneralizedCoheytingAlgebra -variable [GeneralizedCoheytingAlgebra α] (a b c d : α) +variable [GeneralizedCoheytingAlgebra α] (a b c : α) @[simp] theorem toDual_symmDiff : toDual (a ∆ b) = toDual a ⇔ toDual b := @@ -192,7 +192,7 @@ end GeneralizedCoheytingAlgebra section GeneralizedHeytingAlgebra -variable [GeneralizedHeytingAlgebra α] (a b c d : α) +variable [GeneralizedHeytingAlgebra α] (a b c : α) @[simp] theorem toDual_bihimp : toDual (a ⇔ b) = toDual a ∆ toDual b := diff --git a/Mathlib/Order/Synonym.lean b/Mathlib/Order/Synonym.lean index 1ff3b4dca5241..35decae0e1c87 100644 --- a/Mathlib/Order/Synonym.lean +++ b/Mathlib/Order/Synonym.lean @@ -34,7 +34,7 @@ This file is similar to `Algebra.Group.TypeTags`. -/ -variable {α β γ : Type*} +variable {α : Type*} /-! ### Order dual -/ @@ -170,6 +170,18 @@ theorem toLex_inj {a b : α} : toLex a = toLex b ↔ a = b := theorem ofLex_inj {a b : Lex α} : ofLex a = ofLex b ↔ a = b := Iff.rfl +instance (α : Type*) [BEq α] : BEq (Lex α) where + beq a b := ofLex a == ofLex b + +instance (α : Type*) [BEq α] [LawfulBEq α] : LawfulBEq (Lex α) := + inferInstanceAs (LawfulBEq α) + +instance (α : Type*) [DecidableEq α] : DecidableEq (Lex α) := + inferInstanceAs (DecidableEq α) + +instance (α : Type*) [Inhabited α] : Inhabited (Lex α) := + inferInstanceAs (Inhabited α) + /-- A recursor for `Lex`. Use as `induction x`. -/ @[elab_as_elim, induction_eliminator, cases_eliminator] protected def Lex.rec {β : Lex α → Sort*} (h : ∀ a, β (toLex a)) : ∀ a, β a := fun a => h (ofLex a) diff --git a/Mathlib/Order/ULift.lean b/Mathlib/Order/ULift.lean index b3fa9d2fcbc4c..05f7ece9dd38b 100644 --- a/Mathlib/Order/ULift.lean +++ b/Mathlib/Order/ULift.lean @@ -14,6 +14,8 @@ the corresponding `Prod` instances. namespace ULift +open Batteries + universe v u variable {α : Type u} @@ -28,6 +30,11 @@ instance [LT α] : LT (ULift.{v} α) where lt x y := x.down < y.down @[simp] theorem up_lt [LT α] {a b : α} : up a < up b ↔ a < b := Iff.rfl @[simp] theorem down_lt [LT α] {a b : ULift α} : down a < down b ↔ a < b := Iff.rfl +instance [BEq α] : BEq (ULift.{v} α) where beq x y := x.down == y.down + +@[simp] theorem up_beq [BEq α] (a b : α) : (up a == up b) = (a == b) := rfl +@[simp] theorem down_beq [BEq α] (a b : ULift α) : (down a == down b) = (a == b) := rfl + instance [Ord α] : Ord (ULift.{v} α) where compare x y := compare x.down y.down @[simp] theorem up_compare [Ord α] (a b : α) : compare (up a) (up b) = compare a b := rfl @@ -54,6 +61,25 @@ instance [HasCompl α] : HasCompl (ULift.{v} α) where compl x := up <| x.down @[simp] theorem up_compl [HasCompl α] (a : α) : up (aᶜ) = (up a)ᶜ := rfl @[simp] theorem down_compl [HasCompl α] (a : ULift α) : down aᶜ = (down a)ᶜ := rfl +instance [Ord α] [inst : OrientedOrd α] : OrientedOrd (ULift.{v} α) where + symm _ _ := inst.symm .. + +instance [Ord α] [inst : TransOrd α] : TransOrd (ULift.{v} α) where + le_trans := inst.le_trans + +instance [BEq α] [Ord α] [inst : BEqOrd α] : BEqOrd (ULift.{v} α) where + cmp_iff_beq := inst.cmp_iff_beq + +instance [LT α] [Ord α] [inst : LTOrd α] : LTOrd (ULift.{v} α) where + cmp_iff_lt := inst.cmp_iff_lt + +instance [LE α] [Ord α] [inst : LEOrd α] : LEOrd (ULift.{v} α) where + cmp_iff_le := inst.cmp_iff_le + +instance [LE α] [LT α] [BEq α] [Ord α] [inst : LawfulOrd α] : LawfulOrd (ULift.{v} α) where + cmp_iff_lt := inst.cmp_iff_lt + cmp_iff_le := inst.cmp_iff_le + instance [Preorder α] : Preorder (ULift.{v} α) := Preorder.lift ULift.down diff --git a/Mathlib/Order/UpperLower/Basic.lean b/Mathlib/Order/UpperLower/Basic.lean index 1c2dbcf53ed26..09c1126722f1f 100644 --- a/Mathlib/Order/UpperLower/Basic.lean +++ b/Mathlib/Order/UpperLower/Basic.lean @@ -51,7 +51,7 @@ variable {α β γ : Type*} {ι : Sort*} {κ : ι → Sort*} section LE -variable [LE α] [LE β] {s t : Set α} {a : α} +variable [LE α] {s t : Set α} {a : α} /-- An upper set in an order `α` is a set such that any element greater than one of its members is also a member. Also called up-set, upward-closed set. -/ @@ -984,7 +984,7 @@ end UpperSet namespace LowerSet -variable {f : α ≃o β} {s t : LowerSet α} {a : α} {b : β} +variable {f : α ≃o β} {s t : LowerSet α} {a : α} /-- An order isomorphism of Preorders induces an order isomorphism of their lower sets. -/ def map (f : α ≃o β) : LowerSet α ≃o LowerSet β where @@ -1602,7 +1602,7 @@ variable [Preorder α] [Preorder β] section -variable {s : Set α} {t : Set β} {x : α × β} +variable {s : Set α} {t : Set β} theorem IsUpperSet.prod (hs : IsUpperSet s) (ht : IsUpperSet t) : IsUpperSet (s ×ˢ t) := fun _ _ h ha => ⟨hs h.1 ha.1, ht h.2 ha.2⟩ diff --git a/Mathlib/Order/WellFounded.lean b/Mathlib/Order/WellFounded.lean index 613d28890f078..1c5e905b8da09 100644 --- a/Mathlib/Order/WellFounded.lean +++ b/Mathlib/Order/WellFounded.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro -/ import Mathlib.Data.Set.Function -import Mathlib.Order.Bounds.Basic +import Mathlib.Order.Bounds.Defs /-! # Well-founded relations diff --git a/Mathlib/Order/WellFoundedSet.lean b/Mathlib/Order/WellFoundedSet.lean index 5c7e684d6af00..e6c840cc1936d 100644 --- a/Mathlib/Order/WellFoundedSet.lean +++ b/Mathlib/Order/WellFoundedSet.lean @@ -838,7 +838,7 @@ theorem Set.WellFoundedOn.prod_lex_of_wellFoundedOn_fiber (hα : s.WellFoundedOn (hβ : ∀ a, (s ∩ f ⁻¹' {a}).WellFoundedOn (rβ on g)) : s.WellFoundedOn (Prod.Lex rα rβ on fun c => (f c, g c)) := WellFounded.prod_lex_of_wellFoundedOn_fiber hα - fun a ↦ ((hβ a).onFun (f := fun x => ⟨x, x.1.2, x.2⟩)).mono (fun b c h ↦ ‹_›) + fun a ↦ ((hβ a).onFun (f := fun x => ⟨x, x.1.2, x.2⟩)).mono (fun _ _ h ↦ ‹_›) end ProdLex diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index e9c5896a6d456..b78132bdc9a95 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -293,8 +293,8 @@ instance preorder [Preorder α] : Preorder (WithBot α) where lt_iff_le_not_le := by intros a b cases a <;> cases b <;> simp [lt_iff_le_not_le] - le_refl o a ha := ⟨a, ha, le_rfl⟩ - le_trans o₁ o₂ o₃ h₁ h₂ a ha := + le_refl _ a ha := ⟨a, ha, le_rfl⟩ + le_trans _ _ _ h₁ h₂ a ha := let ⟨b, hb, ab⟩ := h₁ a ha let ⟨c, hc, bc⟩ := h₂ b hb ⟨c, hc, le_trans ab bc⟩ @@ -434,7 +434,7 @@ instance decidableEq [DecidableEq α] : DecidableEq (WithBot α) := inferInstanceAs <| DecidableEq (Option α) instance decidableLE [LE α] [@DecidableRel α (· ≤ ·)] : @DecidableRel (WithBot α) (· ≤ ·) - | none, x => isTrue fun a h => Option.noConfusion h + | 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, ⟨_⟩, _⟩ @@ -469,7 +469,7 @@ instance instWellFoundedLT [LT α] [WellFoundedLT α] : WellFoundedLT (WithBot have acc_bot := ⟨_, by simp [not_lt_bot]⟩ .intro fun | ⊥ => acc_bot - | (a : α) => (wellFounded_lt.1 a).rec fun a _ ih => + | (a : α) => (wellFounded_lt.1 a).rec fun _ _ ih => .intro _ fun | ⊥, _ => acc_bot | (b : α), hlt => ih _ (coe_lt_coe.1 hlt) @@ -933,7 +933,7 @@ lemma ge_of_forall_gt_iff_ge [LinearOrder α] [DenselyOrdered α] [NoMinOrder α section LE -variable [LE α] {a b : α} +variable [LE α] theorem toDual_le_iff {a : WithBot α} {b : WithTop αᵒᵈ} : WithBot.toDual a ≤ b ↔ WithTop.ofDual b ≤ a := @@ -963,7 +963,7 @@ end LE section LT -variable [LT α] {a b : α} +variable [LT α] theorem toDual_lt_iff {a : WithBot α} {b : WithTop αᵒᵈ} : WithBot.toDual a < b ↔ WithTop.ofDual b < a := @@ -1088,7 +1088,7 @@ alias ⟨_, _root_.StrictMono.withTop_map⟩ := strictMono_map_iff theorem map_le_iff (f : α → β) (a b : WithTop α) (mono_iff : ∀ {a b}, f a ≤ f b ↔ a ≤ b) : a.map f ≤ b.map f ↔ a ≤ b := by - erw [← toDual_le_toDual_iff, toDual_map, toDual_map, WithBot.map_le_iff, toDual_le_toDual_iff] + rw [← toDual_le_toDual_iff, toDual_map, toDual_map, WithBot.map_le_iff, toDual_le_toDual_iff] simp [mono_iff] theorem coe_untop'_le (a : WithTop α) (b : α) : a.untop' b ≤ a := diff --git a/Mathlib/Order/Zorn.lean b/Mathlib/Order/Zorn.lean index 8c519e1bbaec1..b0418fa34a94b 100644 --- a/Mathlib/Order/Zorn.lean +++ b/Mathlib/Order/Zorn.lean @@ -112,7 +112,7 @@ theorem zorn_le₀ (s : Set α) (ih : ∀ c ⊆ s, IsChain (· ≤ ·) c → ∃ (by rintro _ ⟨p, hpc, rfl⟩ _ ⟨q, hqc, rfl⟩ hpq exact hc hpc hqc fun t => hpq (Subtype.ext_iff.1 t)) - ⟨⟨ub, hubs⟩, fun ⟨y, hy⟩ hc => hub _ ⟨_, hc, rfl⟩⟩ + ⟨⟨ub, hubs⟩, fun ⟨_, _⟩ hc => hub _ ⟨_, hc, rfl⟩⟩ ⟨m, hms, fun z hzs hmz => @h ⟨z, hzs⟩ hmz⟩ theorem zorn_le_nonempty₀ (s : Set α) diff --git a/Mathlib/Probability/CondCount.lean b/Mathlib/Probability/CondCount.lean deleted file mode 100644 index 1ea9812d6c2f6..0000000000000 --- a/Mathlib/Probability/CondCount.lean +++ /dev/null @@ -1,186 +0,0 @@ -/- -Copyright (c) 2022 Kexing Ying. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kexing Ying, Bhavik Mehta --/ -import Mathlib.Probability.ConditionalProbability -import Mathlib.MeasureTheory.Measure.Count - -/-! -# Classical probability - -The classical formulation of probability states that the probability of an event occurring in a -finite probability space is the ratio of that event to all possible events. -This notion can be expressed with measure theory using -the counting measure. In particular, given the sets `s` and `t`, we define the probability of `t` -occurring in `s` to be `|s|⁻¹ * |s ∩ t|`. With this definition, we recover the probability over -the entire sample space when `s = Set.univ`. - -Classical probability is often used in combinatorics and we prove some useful lemmas in this file -for that purpose. - -## Main definition - -* `ProbabilityTheory.condCount`: given a set `s`, `condCount s` is the counting measure - conditioned on `s`. This is a probability measure when `s` is finite and nonempty. - -## Notes - -The original aim of this file is to provide a measure theoretic method of describing the -probability an element of a set `s` satisfies some predicate `P`. Our current formulation still -allow us to describe this by abusing the definitional equality of sets and predicates by simply -writing `condCount s P`. We should avoid this however as none of the lemmas are written for -predicates. --/ - - -noncomputable section - -open ProbabilityTheory - -open MeasureTheory MeasurableSpace - -namespace ProbabilityTheory - -variable {Ω : Type*} [MeasurableSpace Ω] - -/-- Given a set `s`, `condCount s` is the counting measure conditioned on `s`. In particular, -`condCount s t` is the proportion of `s` that is contained in `t`. - -This is a probability measure when `s` is finite and nonempty and is given by -`ProbabilityTheory.condCount_isProbabilityMeasure`. -/ -def condCount (s : Set Ω) : Measure Ω := - Measure.count[|s] - -instance {s : Set Ω} : IsZeroOrProbabilityMeasure (condCount s) := by - unfold condCount; infer_instance - -@[simp] -theorem condCount_empty_meas : (condCount ∅ : Measure Ω) = 0 := by simp [condCount] - -theorem condCount_empty {s : Set Ω} : condCount s ∅ = 0 := by simp - -theorem finite_of_condCount_ne_zero {s t : Set Ω} (h : condCount s t ≠ 0) : s.Finite := by - by_contra hs' - simp [condCount, cond, Measure.count_apply_infinite hs'] at h - -theorem condCount_univ [Fintype Ω] {s : Set Ω} : - condCount Set.univ s = Measure.count s / Fintype.card Ω := by - rw [condCount, cond_apply _ MeasurableSet.univ, ← ENNReal.div_eq_inv_mul, Set.univ_inter] - congr - rw [← Finset.coe_univ, Measure.count_apply, Finset.univ.tsum_subtype' fun _ => (1 : ENNReal)] - · simp [Finset.card_univ] - · exact (@Finset.coe_univ Ω _).symm ▸ MeasurableSet.univ - -variable [MeasurableSingletonClass Ω] - -theorem condCount_isProbabilityMeasure {s : Set Ω} (hs : s.Finite) (hs' : s.Nonempty) : - IsProbabilityMeasure (condCount s) := by - apply cond_isProbabilityMeasure_of_finite - · exact fun h => hs'.ne_empty <| Measure.empty_of_count_eq_zero h - · exact (Measure.count_apply_lt_top.2 hs).ne - -theorem condCount_singleton (ω : Ω) (t : Set Ω) [Decidable (ω ∈ t)] : - condCount {ω} t = if ω ∈ t then 1 else 0 := by - rw [condCount, cond_apply _ (measurableSet_singleton ω), Measure.count_singleton, inv_one, - one_mul] - split_ifs - · rw [(by simpa : ({ω} : Set Ω) ∩ t = {ω}), Measure.count_singleton] - · rw [(by simpa : ({ω} : Set Ω) ∩ t = ∅), Measure.count_empty] - -variable {s t u : Set Ω} - -theorem condCount_inter_self (hs : s.Finite) : condCount s (s ∩ t) = condCount s t := by - rw [condCount, cond_inter_self _ hs.measurableSet] - -theorem condCount_self (hs : s.Finite) (hs' : s.Nonempty) : condCount s s = 1 := by - rw [condCount, cond_apply _ hs.measurableSet, Set.inter_self, ENNReal.inv_mul_cancel] - · exact fun h => hs'.ne_empty <| Measure.empty_of_count_eq_zero h - · exact (Measure.count_apply_lt_top.2 hs).ne - -theorem condCount_eq_one_of (hs : s.Finite) (hs' : s.Nonempty) (ht : s ⊆ t) : - condCount s t = 1 := by - haveI := condCount_isProbabilityMeasure hs hs' - refine eq_of_le_of_not_lt prob_le_one ?_ - rw [not_lt, ← condCount_self hs hs'] - exact measure_mono ht - -theorem pred_true_of_condCount_eq_one (h : condCount s t = 1) : s ⊆ t := by - have hsf := finite_of_condCount_ne_zero (by rw [h]; exact one_ne_zero) - rw [condCount, cond_apply _ hsf.measurableSet, mul_comm] at h - replace h := ENNReal.eq_inv_of_mul_eq_one_left h - rw [inv_inv, Measure.count_apply_finite _ hsf, Measure.count_apply_finite _ (hsf.inter_of_left _), - Nat.cast_inj] at h - suffices s ∩ t = s by exact this ▸ fun x hx => hx.2 - rw [← @Set.Finite.toFinset_inj _ _ _ (hsf.inter_of_left _) hsf] - exact Finset.eq_of_subset_of_card_le (Set.Finite.toFinset_mono s.inter_subset_left) h.ge - -theorem condCount_eq_zero_iff (hs : s.Finite) : condCount s t = 0 ↔ s ∩ t = ∅ := by - simp [condCount, cond_apply _ hs.measurableSet, Measure.count_apply_eq_top, Set.not_infinite.2 hs, - Measure.count_apply_finite _ (hs.inter_of_left _)] - -theorem condCount_of_univ (hs : s.Finite) (hs' : s.Nonempty) : condCount s Set.univ = 1 := - condCount_eq_one_of hs hs' s.subset_univ - -theorem condCount_inter (hs : s.Finite) : - condCount s (t ∩ u) = condCount (s ∩ t) u * condCount s t := by - by_cases hst : s ∩ t = ∅ - · rw [hst, condCount_empty_meas, Measure.coe_zero, Pi.zero_apply, zero_mul, - condCount_eq_zero_iff hs, ← Set.inter_assoc, hst, Set.empty_inter] - rw [condCount, condCount, cond_apply _ hs.measurableSet, cond_apply _ hs.measurableSet, - cond_apply _ (hs.inter_of_left _).measurableSet, mul_comm _ (Measure.count (s ∩ t)), - ← mul_assoc, mul_comm _ (Measure.count (s ∩ t)), ← mul_assoc, ENNReal.mul_inv_cancel, one_mul, - mul_comm, Set.inter_assoc] - · rwa [← Measure.count_eq_zero_iff] at hst - · exact (Measure.count_apply_lt_top.2 <| hs.inter_of_left _).ne - -theorem condCount_inter' (hs : s.Finite) : - condCount s (t ∩ u) = condCount (s ∩ u) t * condCount s u := by - rw [← Set.inter_comm] - exact condCount_inter hs - -theorem condCount_union (hs : s.Finite) (htu : Disjoint t u) : - condCount s (t ∪ u) = condCount s t + condCount s u := by - rw [condCount, cond_apply _ hs.measurableSet, cond_apply _ hs.measurableSet, - cond_apply _ hs.measurableSet, Set.inter_union_distrib_left, measure_union, mul_add] - exacts [htu.mono inf_le_right inf_le_right, (hs.inter_of_left _).measurableSet] - -theorem condCount_compl (t : Set Ω) (hs : s.Finite) (hs' : s.Nonempty) : - condCount s t + condCount s tᶜ = 1 := by - rw [← condCount_union hs disjoint_compl_right, Set.union_compl_self, - (condCount_isProbabilityMeasure hs hs').measure_univ] - -theorem condCount_disjoint_union (hs : s.Finite) (ht : t.Finite) (hst : Disjoint s t) : - condCount s u * condCount (s ∪ t) s + condCount t u * condCount (s ∪ t) t = - condCount (s ∪ t) u := by - rcases s.eq_empty_or_nonempty with (rfl | hs') <;> rcases t.eq_empty_or_nonempty with (rfl | ht') - · simp - · simp [condCount_self ht ht'] - · simp [condCount_self hs hs'] - rw [condCount, condCount, condCount, cond_apply _ hs.measurableSet, - cond_apply _ ht.measurableSet, cond_apply _ (hs.union ht).measurableSet, - cond_apply _ (hs.union ht).measurableSet, cond_apply _ (hs.union ht).measurableSet] - conv_lhs => - rw [Set.union_inter_cancel_left, Set.union_inter_cancel_right, - mul_comm (Measure.count (s ∪ t))⁻¹, mul_comm (Measure.count (s ∪ t))⁻¹, ← mul_assoc, - ← mul_assoc, mul_comm _ (Measure.count s), mul_comm _ (Measure.count t), ← mul_assoc, - ← mul_assoc] - rw [ENNReal.mul_inv_cancel, ENNReal.mul_inv_cancel, one_mul, one_mul, ← add_mul, ← measure_union, - Set.union_inter_distrib_right, mul_comm] - exacts [hst.mono inf_le_left inf_le_left, (ht.inter_of_left _).measurableSet, - Measure.count_ne_zero ht', (Measure.count_apply_lt_top.2 ht).ne, Measure.count_ne_zero hs', - (Measure.count_apply_lt_top.2 hs).ne] - -/-- A version of the law of total probability for counting probabilities. -/ -theorem condCount_add_compl_eq (u t : Set Ω) (hs : s.Finite) : - condCount (s ∩ u) t * condCount s u + condCount (s ∩ uᶜ) t * condCount s uᶜ = - condCount s t := by - -- Porting note: The original proof used `conv_rhs`. However, that tactic timed out. - have : condCount s t = (condCount (s ∩ u) t * condCount (s ∩ u ∪ s ∩ uᶜ) (s ∩ u) + - condCount (s ∩ uᶜ) t * condCount (s ∩ u ∪ s ∩ uᶜ) (s ∩ uᶜ)) := by - rw [condCount_disjoint_union (hs.inter_of_left _) (hs.inter_of_left _) - (disjoint_compl_right.mono inf_le_right inf_le_right), Set.inter_union_compl] - rw [this] - simp [condCount_inter_self hs] - -end ProbabilityTheory diff --git a/Mathlib/Probability/ConditionalProbability.lean b/Mathlib/Probability/ConditionalProbability.lean index aa9148f363412..64c784c227353 100644 --- a/Mathlib/Probability/ConditionalProbability.lean +++ b/Mathlib/Probability/ConditionalProbability.lean @@ -58,21 +58,18 @@ noncomputable section open ENNReal MeasureTheory MeasureTheory.Measure MeasurableSpace Set -variable {Ω Ω' α : Type*} {m : MeasurableSpace Ω} {m' : MeasurableSpace Ω'} (μ : Measure Ω) +variable {Ω Ω' α : Type*} {m : MeasurableSpace Ω} {m' : MeasurableSpace Ω'} {μ : Measure Ω} {s t : Set Ω} namespace ProbabilityTheory -section Definitions - +variable (μ) in /-- The conditional probability measure of measure `μ` on set `s` is `μ` restricted to `s` and scaled by the inverse of `μ s` (to make it a probability measure): `(μ s)⁻¹ • μ.restrict s`. -/ def cond (s : Set Ω) : Measure Ω := (μ s)⁻¹ • μ.restrict s -end Definitions - @[inherit_doc] scoped notation μ "[" s "|" t "]" => ProbabilityTheory.cond μ t s @[inherit_doc] scoped notation:max μ "[|" t "]" => ProbabilityTheory.cond μ t @@ -95,7 +92,7 @@ theorem cond_isProbabilityMeasure_of_finite (hcs : μ s ≠ 0) (hs : μ s ≠ /-- The conditional probability measure of any finite measure on any set of positive measure is a probability measure. -/ theorem cond_isProbabilityMeasure [IsFiniteMeasure μ] (hcs : μ s ≠ 0) : - IsProbabilityMeasure μ[|s] := cond_isProbabilityMeasure_of_finite μ hcs (measure_ne_top μ s) + IsProbabilityMeasure μ[|s] := cond_isProbabilityMeasure_of_finite hcs (measure_ne_top μ s) instance : IsZeroOrProbabilityMeasure μ[|s] := by constructor @@ -107,6 +104,7 @@ instance : IsZeroOrProbabilityMeasure μ[|s] := by · simp [h'] simp [ENNReal.div_self h h'] +variable (μ) in theorem cond_toMeasurable_eq : μ[|(toMeasurable μ s)] = μ[|s] := by unfold cond @@ -114,11 +112,9 @@ theorem cond_toMeasurable_eq : · simp [hnt] · simp [Measure.restrict_toMeasurable hnt] -variable {μ} in lemma cond_absolutelyContinuous : μ[|s] ≪ μ := smul_absolutelyContinuous.trans restrict_le_self.absolutelyContinuous -variable {μ} in lemma absolutelyContinuous_cond_univ [IsFiniteMeasure μ] : μ ≪ μ[|univ] := by rw [cond, restrict_univ] refine absolutelyContinuous_smul ?_ @@ -126,11 +122,11 @@ lemma absolutelyContinuous_cond_univ [IsFiniteMeasure μ] : μ ≪ μ[|univ] := section Bayes -@[simp] -theorem cond_empty : μ[|∅] = 0 := by simp [cond] +variable (μ) in +@[simp] lemma cond_empty : μ[|∅] = 0 := by simp [cond] -@[simp] -theorem cond_univ [IsProbabilityMeasure μ] : μ[|Set.univ] = μ := by +variable (μ) in +@[simp] lemma cond_univ [IsProbabilityMeasure μ] : μ[|Set.univ] = μ := by simp [cond, measure_univ, Measure.restrict_univ] @[simp] lemma cond_eq_zero (hμs : μ s ≠ ⊤) : μ[|s] = 0 ↔ μ s = 0 := by simp [cond, hμs] @@ -138,33 +134,35 @@ theorem cond_univ [IsProbabilityMeasure μ] : μ[|Set.univ] = μ := by lemma cond_eq_zero_of_meas_eq_zero (hμs : μ s = 0) : μ[|s] = 0 := by simp [hμs] /-- The axiomatic definition of conditional probability derived from a measure-theoretic one. -/ -theorem cond_apply (hms : MeasurableSet s) (t : Set Ω) : μ[t|s] = (μ s)⁻¹ * μ (s ∩ t) := by +theorem cond_apply (hms : MeasurableSet s) (μ : Measure Ω) (t : Set Ω) : + μ[t|s] = (μ s)⁻¹ * μ (s ∩ t) := by rw [cond, Measure.smul_apply, Measure.restrict_apply' hms, Set.inter_comm, smul_eq_mul] -theorem cond_apply' {t : Set Ω} (hA : MeasurableSet t) : μ[t|s] = (μ s)⁻¹ * μ (s ∩ t) := by - rw [cond, Measure.smul_apply, Measure.restrict_apply hA, Set.inter_comm, smul_eq_mul] +theorem cond_apply' (ht : MeasurableSet t) (μ : Measure Ω) : μ[t|s] = (μ s)⁻¹ * μ (s ∩ t) := by + rw [cond, Measure.smul_apply, Measure.restrict_apply ht, Set.inter_comm, smul_eq_mul] @[simp] lemma cond_apply_self (hs₀ : μ s ≠ 0) (hs : μ s ≠ ∞) : μ[s|s] = 1 := by simpa [cond] using ENNReal.inv_mul_cancel hs₀ hs -theorem cond_inter_self (hms : MeasurableSet s) (t : Set Ω) : μ[s ∩ t|s] = μ[t|s] := by - rw [cond_apply _ hms, ← Set.inter_assoc, Set.inter_self, ← cond_apply _ hms] +theorem cond_inter_self (hms : MeasurableSet s) (t : Set Ω) (μ : Measure Ω) : + μ[s ∩ t|s] = μ[t|s] := by + rw [cond_apply hms, ← Set.inter_assoc, Set.inter_self, ← cond_apply hms] theorem inter_pos_of_cond_ne_zero (hms : MeasurableSet s) (hcst : μ[t|s] ≠ 0) : 0 < μ (s ∩ t) := by refine pos_iff_ne_zero.mpr (right_ne_zero_of_mul (a := (μ s)⁻¹) ?_) convert hcst simp [hms, Set.inter_comm, cond] -theorem cond_pos_of_inter_ne_zero [IsFiniteMeasure μ] - (hms : MeasurableSet s) (hci : μ (s ∩ t) ≠ 0) : 0 < μ[|s] t := by - rw [cond_apply _ hms] +lemma cond_pos_of_inter_ne_zero [IsFiniteMeasure μ] (hms : MeasurableSet s) (hci : μ (s ∩ t) ≠ 0) : + 0 < μ[|s] t := by + rw [cond_apply hms] refine ENNReal.mul_pos ?_ hci exact ENNReal.inv_ne_zero.mpr (measure_ne_top _ _) lemma cond_cond_eq_cond_inter' (hms : MeasurableSet s) (hmt : MeasurableSet t) (hcs : μ s ≠ ∞) : μ[|s][|t] = μ[|s ∩ t] := by ext u - rw [cond_apply _ hmt, cond_apply _ hms, cond_apply _ hms, cond_apply _ (hms.inter hmt)] + rw [cond_apply hmt, cond_apply hms, cond_apply hms, cond_apply (hms.inter hmt)] obtain hst | hst := eq_or_ne (μ (s ∩ t)) 0 · have : μ (s ∩ t ∩ u) = 0 := measure_mono_null Set.inter_subset_left hst simp [this, ← Set.inter_assoc] @@ -175,30 +173,30 @@ lemma cond_cond_eq_cond_inter' (hms : MeasurableSet s) (hmt : MeasurableSet t) ( /-- Conditioning first on `s` and then on `t` results in the same measure as conditioning on `s ∩ t`. -/ -theorem cond_cond_eq_cond_inter [IsFiniteMeasure μ] (hms : MeasurableSet s) - (hmt : MeasurableSet t) : μ[|s][|t] = μ[|s ∩ t] := - cond_cond_eq_cond_inter' μ hms hmt (measure_ne_top μ s) +theorem cond_cond_eq_cond_inter (hms : MeasurableSet s) (hmt : MeasurableSet t) (μ : Measure Ω) + [IsFiniteMeasure μ] : μ[|s][|t] = μ[|s ∩ t] := + cond_cond_eq_cond_inter' hms hmt (measure_ne_top μ s) theorem cond_mul_eq_inter' (hms : MeasurableSet s) (hcs' : μ s ≠ ∞) (t : Set Ω) : μ[t|s] * μ s = μ (s ∩ t) := by obtain hcs | hcs := eq_or_ne (μ s) 0 · simp [hcs, measure_inter_null_of_null_left] - · rw [cond_apply μ hms t, mul_comm, ← mul_assoc, ENNReal.mul_inv_cancel hcs hcs', one_mul] + · rw [cond_apply hms, mul_comm, ← mul_assoc, ENNReal.mul_inv_cancel hcs hcs', one_mul] -theorem cond_mul_eq_inter [IsFiniteMeasure μ] (hms : MeasurableSet s) (t : Set Ω) : - μ[t|s] * μ s = μ (s ∩ t) := cond_mul_eq_inter' μ hms (measure_ne_top _ s) t +theorem cond_mul_eq_inter (hms : MeasurableSet s) (t : Set Ω) (μ : Measure Ω) [IsFiniteMeasure μ] : + μ[t|s] * μ s = μ (s ∩ t) := cond_mul_eq_inter' hms (measure_ne_top _ s) t /-- A version of the law of total probability. -/ -theorem cond_add_cond_compl_eq [IsFiniteMeasure μ] (hms : MeasurableSet s) : +theorem cond_add_cond_compl_eq (hms : MeasurableSet s) (μ : Measure Ω) [IsFiniteMeasure μ] : μ[t|s] * μ s + μ[t|sᶜ] * μ sᶜ = μ t := by - rw [cond_mul_eq_inter μ hms, cond_mul_eq_inter μ hms.compl, Set.inter_comm _ t, + rw [cond_mul_eq_inter hms, cond_mul_eq_inter hms.compl, Set.inter_comm _ t, Set.inter_comm _ t] exact measure_inter_add_diff t hms /-- **Bayes' Theorem** -/ -theorem cond_eq_inv_mul_cond_mul [IsFiniteMeasure μ] - (hms : MeasurableSet s) (hmt : MeasurableSet t) : μ[t|s] = (μ s)⁻¹ * μ[s|t] * μ t := by - rw [mul_assoc, cond_mul_eq_inter μ hmt s, Set.inter_comm, cond_apply _ hms] +theorem cond_eq_inv_mul_cond_mul (hms : MeasurableSet s) (hmt : MeasurableSet t) (μ : Measure Ω) + [IsFiniteMeasure μ] : μ[t|s] = (μ s)⁻¹ * μ[s|t] * μ t := by + rw [mul_assoc, cond_mul_eq_inter hmt s, Set.inter_comm, cond_apply hms] end Bayes @@ -229,7 +227,7 @@ lemma sum_meas_smul_cond_fiber {X : Ω → α} (hX : Measurable X) (μ : Measure _ = ∑ x, μ (X ⁻¹' {x} ∩ E) := by simp only [Measure.coe_finset_sum, Measure.coe_smul, Finset.sum_apply, Pi.smul_apply, smul_eq_mul] - simp_rw [mul_comm (μ _), cond_mul_eq_inter _ (hX (.singleton _))] + simp_rw [mul_comm (μ _), cond_mul_eq_inter (hX (.singleton _))] _ = _ := by have : ⋃ x ∈ Finset.univ, X ⁻¹' {x} ∩ E = E := by ext; simp rw [← measure_biUnion_finset _ fun _ _ ↦ (hX (.singleton _)).inter hE, this] diff --git a/Mathlib/Probability/Distributions/Uniform.lean b/Mathlib/Probability/Distributions/Uniform.lean index c639f53703f5b..77f3a13bb4a8c 100644 --- a/Mathlib/Probability/Distributions/Uniform.lean +++ b/Mathlib/Probability/Distributions/Uniform.lean @@ -48,7 +48,7 @@ noncomputable section namespace MeasureTheory -variable {E : Type*} [MeasurableSpace E] {m : Measure E} {μ : Measure E} +variable {E : Type*} [MeasurableSpace E] {μ : Measure E} namespace pdf @@ -155,7 +155,7 @@ theorem mul_pdf_integrable (hcs : IsCompact s) (huX : IsUniform X s ℙ) : set ind := (volume s)⁻¹ • (1 : ℝ → ℝ≥0∞) have : ∀ x, ↑‖x‖₊ * s.indicator ind x = s.indicator (fun x => ‖x‖₊ * ind x) x := fun x => (s.indicator_mul_right (fun x => ↑‖x‖₊) ind).symm - simp only [ind, this, lintegral_indicator _ hcs.measurableSet, mul_one, Algebra.id.smul_eq_mul, + simp only [ind, this, lintegral_indicator hcs.measurableSet, mul_one, Algebra.id.smul_eq_mul, Pi.one_apply, Pi.smul_apply] rw [lintegral_mul_const _ measurable_nnnorm.coe_nnreal_ennreal] exact ENNReal.mul_ne_top (setLIntegral_lt_top_of_isCompact hnt.2 hcs continuous_nnnorm).ne @@ -206,7 +206,7 @@ end MeasureTheory namespace PMF -variable {α β γ : Type*} +variable {α : Type*} open scoped Classical NNReal ENNReal @@ -257,7 +257,7 @@ theorem toOuterMeasure_uniformOfFinset_apply : _ = ∑' x, if x ∈ s ∧ x ∈ t then (s.card : ℝ≥0∞)⁻¹ else 0 := (tsum_congr fun x => by simp_rw [uniformOfFinset_apply, ← ite_and, and_comm]) _ = ∑ x ∈ s.filter (· ∈ t), if x ∈ s ∧ x ∈ t then (s.card : ℝ≥0∞)⁻¹ else 0 := - (tsum_eq_sum fun x hx => if_neg fun h => hx (Finset.mem_filter.2 h)) + (tsum_eq_sum fun _ hx => if_neg fun h => hx (Finset.mem_filter.2 h)) _ = ∑ _x ∈ s.filter (· ∈ t), (s.card : ℝ≥0∞)⁻¹ := (Finset.sum_congr rfl fun x hx => by let this : x ∈ s ∧ x ∈ t := by simpa using hx diff --git a/Mathlib/Probability/Independence/Basic.lean b/Mathlib/Probability/Independence/Basic.lean index cf6f2aebad8a9..cfa5d0c19e7b7 100644 --- a/Mathlib/Probability/Independence/Basic.lean +++ b/Mathlib/Probability/Independence/Basic.lean @@ -563,6 +563,11 @@ theorem iIndepFun_iff_measure_inter_preimage_eq_mul {ι : Type*} {β : ι → Ty alias ⟨iIndepFun.measure_inter_preimage_eq_mul, _⟩ := iIndepFun_iff_measure_inter_preimage_eq_mul +nonrec lemma iIndepFun.comp {β γ : ι → Type*} {mβ : ∀ i, MeasurableSpace (β i)} + {mγ : ∀ i, MeasurableSpace (γ i)} {f : ∀ i, Ω → β i} + (h : iIndepFun mβ f μ) (g : ∀ i, β i → γ i) (hg : ∀ i, Measurable (g i)) : + iIndepFun mγ (fun i ↦ g i ∘ f i) μ := h.comp _ hg + theorem indepFun_iff_indepSet_preimage {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} [IsZeroOrProbabilityMeasure μ] (hf : Measurable f) (hg : Measurable g) : IndepFun f g μ ↔ diff --git a/Mathlib/Probability/Independence/Conditional.lean b/Mathlib/Probability/Independence/Conditional.lean index 0b5e3f0b6dcaf..6456d37f340cf 100644 --- a/Mathlib/Probability/Independence/Conditional.lean +++ b/Mathlib/Probability/Independence/Conditional.lean @@ -734,7 +734,7 @@ lemma iCondIndepFun.condIndepFun_prod_mk_prod_mk (h_indep : iCondIndepFun m' hm' end iCondIndepFun section Mul -variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} +variable {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} @[to_additive] lemma iCondIndepFun.indepFun_mul_left (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) @@ -758,7 +758,7 @@ lemma iCondIndepFun.indepFun_mul_mul (hf_indep : iCondIndepFun m' hm' (fun _ ↦ end Mul section Div -variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} +variable {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} @[to_additive] lemma iCondIndepFun.indepFun_div_left (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) @@ -782,7 +782,7 @@ lemma iCondIndepFun.indepFun_div_div (hf_indep : iCondIndepFun m' hm' (fun _ ↦ end Div section CommMonoid -variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} +variable {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} @[to_additive] theorem iCondIndepFun.condIndepFun_finset_prod_of_not_mem diff --git a/Mathlib/Probability/Independence/Kernel.lean b/Mathlib/Probability/Independence/Kernel.lean index 146667d5bfbdb..cf48a19edc339 100644 --- a/Mathlib/Probability/Independence/Kernel.lean +++ b/Mathlib/Probability/Independence/Kernel.lean @@ -827,7 +827,7 @@ theorem IndepSets.indepSet_of_mem {_m0 : MeasurableSpace Ω} (hs : s ∈ S) (ht IndepSet s t κ μ := (indepSet_iff_measure_inter_eq_mul hs_meas ht_meas κ μ).mpr (h_indep s t hs ht) -theorem Indep.indepSet_of_measurableSet {m₁ m₂ m0 : MeasurableSpace Ω} {κ : Kernel α Ω} +theorem Indep.indepSet_of_measurableSet {m₁ m₂ _ : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} (h_indep : Indep m₁ m₂ κ μ) {s t : Set Ω} (hs : MeasurableSet[m₁] s) (ht : MeasurableSet[m₂] t) : @@ -907,6 +907,17 @@ theorem iIndepFun_iff_measure_inter_preimage_eq_mul {ι : Type*} {β : ι → Ty alias ⟨iIndepFun.measure_inter_preimage_eq_mul, _⟩ := iIndepFun_iff_measure_inter_preimage_eq_mul +lemma iIndepFun.comp {β γ : ι → Type*} {mβ : ∀ i, MeasurableSpace (β i)} + {mγ : ∀ i, MeasurableSpace (γ i)} {f : ∀ i, Ω → β i} + (h : iIndepFun mβ f κ μ) (g : ∀ i, β i → γ i) (hg : ∀ i, Measurable (g i)) : + iIndepFun mγ (fun i ↦ g i ∘ f i) κ μ := by + rw [iIndepFun_iff_measure_inter_preimage_eq_mul] at h ⊢ + refine fun t s hs ↦ ?_ + have := h t (sets := fun i ↦ g i ⁻¹' (s i)) (fun i a ↦ hg i (hs i a)) + filter_upwards [this] with a ha + simp_rw [Set.preimage_comp] + exact ha + theorem indepFun_iff_indepSet_preimage {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} [IsZeroOrMarkovKernel κ] (hf : Measurable f) (hg : Measurable g) : IndepFun f g κ μ ↔ diff --git a/Mathlib/Probability/Integration.lean b/Mathlib/Probability/Integration.lean index ad5bc0600a169..3d42e69819c63 100644 --- a/Mathlib/Probability/Integration.lean +++ b/Mathlib/Probability/Integration.lean @@ -51,8 +51,8 @@ theorem lintegral_mul_indicator_eq_lintegral_mul_lintegral_indicator {Mf mΩ : M apply @Measurable.ennreal_induction _ Mf · intro c' s' h_meas_s' simp_rw [← inter_indicator_mul] - rw [lintegral_indicator _ (MeasurableSet.inter (hMf _ h_meas_s') h_meas_T), - lintegral_indicator _ (hMf _ h_meas_s'), lintegral_indicator _ h_meas_T] + rw [lintegral_indicator (MeasurableSet.inter (hMf _ h_meas_s') h_meas_T), + lintegral_indicator (hMf _ h_meas_s'), lintegral_indicator h_meas_T] simp only [measurable_const, lintegral_const, univ_inter, lintegral_const_mul, MeasurableSet.univ, Measure.restrict_apply] rw [IndepSets_iff] at h_ind diff --git a/Mathlib/Probability/Kernel/Basic.lean b/Mathlib/Probability/Kernel/Basic.lean index 3fc42e7dc57d2..b4ac72bc2f810 100644 --- a/Mathlib/Probability/Kernel/Basic.lean +++ b/Mathlib/Probability/Kernel/Basic.lean @@ -124,7 +124,7 @@ instance const.instIsFiniteKernel {μβ : Measure β} [IsFiniteMeasure μβ] : instance const.instIsSFiniteKernel {μβ : Measure β} [SFinite μβ] : IsSFiniteKernel (const α μβ) := - ⟨fun n ↦ const α (sFiniteSeq μβ n), fun n ↦ inferInstance, by rw [sum_const, sum_sFiniteSeq]⟩ + ⟨fun n ↦ const α (sfiniteSeq μβ n), fun n ↦ inferInstance, by rw [sum_const, sum_sfiniteSeq]⟩ instance const.instIsMarkovKernel {μβ : Measure β} [hμβ : IsProbabilityMeasure μβ] : IsMarkovKernel (const α μβ) := diff --git a/Mathlib/Probability/Kernel/Composition.lean b/Mathlib/Probability/Kernel/Composition.lean index 513325918f94f..5dbebd1c9f25c 100644 --- a/Mathlib/Probability/Kernel/Composition.lean +++ b/Mathlib/Probability/Kernel/Composition.lean @@ -65,7 +65,7 @@ namespace ProbabilityTheory namespace Kernel -variable {α β ι : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} +variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} section CompositionProduct @@ -208,8 +208,8 @@ theorem compProd_of_not_isSFiniteKernel_right (κ : Kernel α β) (η : Kernel ( rw [compProd, dif_neg] simp [h] -theorem compProd_apply (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel (α × β) γ) - [IsSFiniteKernel η] (a : α) (hs : MeasurableSet s) : +theorem compProd_apply (hs : MeasurableSet s) (κ : Kernel α β) [IsSFiniteKernel κ] + (η : Kernel (α × β) γ) [IsSFiniteKernel η] (a : α) : (κ ⊗ₖ η) a s = ∫⁻ b, η (a, b) {c | (b, c) ∈ s} ∂κ a := compProd_apply_eq_compProdFun κ η a hs @@ -229,7 +229,7 @@ lemma compProd_zero_left (κ : Kernel (α × β) γ) : (0 : Kernel α β) ⊗ₖ κ = 0 := by by_cases h : IsSFiniteKernel κ · ext a s hs - rw [Kernel.compProd_apply _ _ _ hs] + rw [Kernel.compProd_apply hs] simp · rw [Kernel.compProd_of_not_isSFiniteKernel_right _ _ h] @@ -238,10 +238,42 @@ lemma compProd_zero_right (κ : Kernel α β) (γ : Type*) {mγ : MeasurableSpac κ ⊗ₖ (0 : Kernel (α × β) γ) = 0 := by by_cases h : IsSFiniteKernel κ · ext a s hs - rw [Kernel.compProd_apply _ _ _ hs] + rw [Kernel.compProd_apply hs] simp · rw [Kernel.compProd_of_not_isSFiniteKernel_left _ _ h] +lemma compProd_preimage_fst {s : Set β} (hs : MeasurableSet s) (κ : Kernel α β) + (η : Kernel (α × β) γ) [IsSFiniteKernel κ] [IsMarkovKernel η] (x : α) : + (κ ⊗ₖ η) x (Prod.fst ⁻¹' s) = κ x s := by + rw [compProd_apply (measurable_fst hs)] + simp only [Set.mem_preimage] + classical + have : ∀ b : β, η (x, b) {_c | b ∈ s} = s.indicator (fun _ ↦ 1) b := by + intro b + by_cases hb : b ∈ s <;> simp [hb] + simp_rw [this] + rw [lintegral_indicator_const hs, one_mul] + +lemma compProd_deterministic_apply [MeasurableSingletonClass γ] {f : α × β → γ} (hf : Measurable f) + {s : Set (β × γ)} (hs : MeasurableSet s) (κ : Kernel α β) [IsSFiniteKernel κ] (x : α) : + (κ ⊗ₖ deterministic f hf) x s = κ x {b | (b, f (x, b)) ∈ s} := by + simp only [deterministic_apply, measurableSet_setOf, Set.mem_setOf_eq, Measure.dirac_apply, + Set.mem_setOf_eq, Set.indicator_apply, Pi.one_apply, compProd_apply hs] + let t := {b | (b, f (x, b)) ∈ s} + have ht : MeasurableSet t := (measurable_id.prod_mk (hf.comp measurable_prod_mk_left)) hs + rw [← lintegral_add_compl _ ht] + convert add_zero _ + · suffices ∀ b ∈ tᶜ, (if (b, f (x, b)) ∈ s then (1 : ℝ≥0∞) else 0) = 0 by + rw [setLIntegral_congr_fun ht.compl (ae_of_all _ this), lintegral_zero] + intro b hb + simp only [t, Set.mem_compl_iff, Set.mem_setOf_eq] at hb + simp [hb] + · suffices ∀ b ∈ t, (if (b, f (x, b)) ∈ s then (1 : ℝ≥0∞) else 0) = 1 by + rw [setLIntegral_congr_fun ht (ae_of_all _ this), setLIntegral_one] + intro b hb + simp only [t, Set.mem_setOf_eq] at hb + simp [hb] + section Ae /-! ### `ae` filter of the composition-product -/ @@ -257,14 +289,14 @@ theorem ae_kernel_lt_top (a : α) (h2s : (κ ⊗ₖ η) a s ≠ ∞) : have ht : MeasurableSet t := measurableSet_toMeasurable _ _ have h2t : (κ ⊗ₖ η) a t ≠ ∞ := by rwa [measure_toMeasurable] have ht_lt_top : ∀ᵐ b ∂κ a, η (a, b) (Prod.mk b ⁻¹' t) < ∞ := by - rw [Kernel.compProd_apply _ _ _ ht] at h2t + rw [Kernel.compProd_apply ht] at h2t exact ae_lt_top (Kernel.measurable_kernel_prod_mk_left' ht a) h2t filter_upwards [ht_lt_top] with b hb exact (this b).trans_lt hb theorem compProd_null (a : α) (hs : MeasurableSet s) : (κ ⊗ₖ η) a s = 0 ↔ (fun b => η (a, b) (Prod.mk b ⁻¹' s)) =ᵐ[κ a] 0 := by - rw [Kernel.compProd_apply _ _ _ hs, lintegral_eq_zero_iff] + rw [Kernel.compProd_apply hs, lintegral_eq_zero_iff] · rfl · exact Kernel.measurable_kernel_prod_mk_left' hs a @@ -303,13 +335,13 @@ end Ae section Restrict -variable {κ : Kernel α β} [IsSFiniteKernel κ] {η : Kernel (α × β) γ} [IsSFiniteKernel η] {a : α} +variable {κ : Kernel α β} [IsSFiniteKernel κ] {η : Kernel (α × β) γ} [IsSFiniteKernel η] theorem compProd_restrict {s : Set β} {t : Set γ} (hs : MeasurableSet s) (ht : MeasurableSet t) : Kernel.restrict κ hs ⊗ₖ Kernel.restrict η ht = Kernel.restrict (κ ⊗ₖ η) (hs.prod ht) := by ext a u hu - rw [compProd_apply _ _ _ hu, restrict_apply' _ _ _ hu, - compProd_apply _ _ _ (hu.inter (hs.prod ht))] + rw [compProd_apply hu, restrict_apply' _ _ _ hu, + compProd_apply (hu.inter (hs.prod ht))] simp only [Kernel.restrict_apply, Measure.restrict_apply' ht, Set.mem_inter_iff, Set.prod_mk_mem_set_prod_eq] have : @@ -323,7 +355,7 @@ theorem compProd_restrict {s : Set β} {t : Set γ} (hs : MeasurableSet s) (ht : · simp only [h, true_and, Set.inter_def, Set.mem_setOf] · simp only [h, false_and, and_false, Set.setOf_false, measure_empty] simp_rw [this] - rw [lintegral_indicator _ hs] + rw [lintegral_indicator hs] theorem compProd_restrict_left {s : Set β} (hs : MeasurableSet s) : Kernel.restrict κ hs ⊗ₖ η = Kernel.restrict (κ ⊗ₖ η) (hs.prod MeasurableSet.univ) := by @@ -383,7 +415,7 @@ theorem lintegral_compProd' (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kerne simp (config := { unfoldPartialApp := true }) only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_const, SimpleFunc.coe_zero, Set.piecewise_eq_indicator, Function.const, lintegral_indicator_const hs] - rw [compProd_apply κ η _ hs, ← lintegral_const_mul c _] + rw [compProd_apply hs, ← lintegral_const_mul c _] swap · exact (measurable_kernel_prod_mk_left ((measurable_fst.snd.prod_mk measurable_snd) hs)).comp measurable_prod_mk_left @@ -485,11 +517,8 @@ theorem compProd_eq_sum_compProd_right (κ : Kernel α β) (η : Kernel (α × rw [Kernel.sum_comm] instance IsMarkovKernel.compProd (κ : Kernel α β) [IsMarkovKernel κ] (η : Kernel (α × β) γ) - [IsMarkovKernel η] : IsMarkovKernel (κ ⊗ₖ η) := - ⟨fun a => - ⟨by - rw [compProd_apply κ η a MeasurableSet.univ] - simp only [Set.mem_univ, Set.setOf_true, measure_univ, lintegral_one]⟩⟩ + [IsMarkovKernel η] : IsMarkovKernel (κ ⊗ₖ η) where + isProbabilityMeasure a := ⟨by simp [compProd_apply]⟩ theorem compProd_apply_univ_le (κ : Kernel α β) (η : Kernel (α × β) γ) [IsFiniteKernel η] (a : α) : (κ ⊗ₖ η) a Set.univ ≤ κ a Set.univ * IsFiniteKernel.bound η := by @@ -497,7 +526,7 @@ theorem compProd_apply_univ_le (κ : Kernel α β) (η : Kernel (α × β) γ) [ swap · rw [compProd_of_not_isSFiniteKernel_left _ _ hκ] simp - rw [compProd_apply κ η a MeasurableSet.univ] + rw [compProd_apply .univ] simp only [Set.mem_univ, Set.setOf_true] let Cη := IsFiniteKernel.bound η calc @@ -530,13 +559,13 @@ instance IsSFiniteKernel.compProd (κ : Kernel α β) (η : Kernel (α × β) γ lemma compProd_add_left (μ κ : Kernel α β) (η : Kernel (α × β) γ) [IsSFiniteKernel μ] [IsSFiniteKernel κ] [IsSFiniteKernel η] : - (μ + κ) ⊗ₖ η = μ ⊗ₖ η + κ ⊗ₖ η := by ext _ _ hs; simp [compProd_apply _ _ _ hs] + (μ + κ) ⊗ₖ η = μ ⊗ₖ η + κ ⊗ₖ η := by ext _ _ hs; simp [compProd_apply hs] lemma compProd_add_right (μ : Kernel α β) (κ η : Kernel (α × β) γ) [IsSFiniteKernel μ] [IsSFiniteKernel κ] [IsSFiniteKernel η] : μ ⊗ₖ (κ + η) = μ ⊗ₖ κ + μ ⊗ₖ η := by ext a s hs - simp only [compProd_apply _ _ _ hs, coe_add, Pi.add_apply, Measure.coe_add] + simp only [compProd_apply hs, coe_add, Pi.add_apply, Measure.coe_add] rw [lintegral_add_left] exact measurable_kernel_prod_mk_left' hs a @@ -545,7 +574,7 @@ lemma comapRight_compProd_id_prod {δ : Type*} {mδ : MeasurableSpace δ} {f : δ → γ} (hf : MeasurableEmbedding f) : comapRight (κ ⊗ₖ η) (MeasurableEmbedding.id.prod_mk hf) = κ ⊗ₖ (comapRight η hf) := by ext a t ht - rw [comapRight_apply' _ _ _ ht, compProd_apply, compProd_apply _ _ _ ht] + rw [comapRight_apply' _ _ _ ht, compProd_apply, compProd_apply ht] swap; · exact (MeasurableEmbedding.id.prod_mk hf).measurableSet_image.mpr ht refine lintegral_congr (fun b ↦ ?_) simp only [id_eq, Set.mem_image, Prod.mk.injEq, Prod.exists] @@ -663,6 +692,9 @@ def comap (κ : Kernel α β) (g : γ → α) (hg : Measurable g) : Kernel γ β toFun a := κ (g a) measurable' := κ.measurable.comp hg +@[simp, norm_cast] +lemma coe_comap (κ : Kernel α β) (g : γ → α) (hg : Measurable g) : κ.comap g hg = κ ∘ g := rfl + theorem comap_apply (κ : Kernel α β) (hg : Measurable g) (c : γ) : comap κ g hg c = κ (g c) := rfl @@ -727,7 +759,7 @@ def prodMkLeft (γ : Type*) [MeasurableSpace γ] (κ : Kernel α β) : Kernel ( def prodMkRight (γ : Type*) [MeasurableSpace γ] (κ : Kernel α β) : Kernel (α × γ) β := comap κ Prod.fst measurable_fst -variable {γ : Type*} {mγ : MeasurableSpace γ} {f : β → γ} {g : γ → α} +variable {γ : Type*} {mγ : MeasurableSpace γ} @[simp] theorem prodMkLeft_apply (κ : Kernel α β) (ca : γ × α) : prodMkLeft γ κ ca = κ ca.snd := @@ -1029,7 +1061,7 @@ section Comp /-! ### Composition of two kernels -/ -variable {γ : Type*} {mγ : MeasurableSpace γ} {f : β → γ} {g : γ → α} +variable {γ δ : Type*} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {f : β → γ} {g : γ → α} /-- Composition of two kernels. -/ noncomputable def comp (η : Kernel β γ) (κ : Kernel α β) : Kernel α γ where @@ -1046,6 +1078,10 @@ theorem comp_apply' (η : Kernel β γ) (κ : Kernel α β) (a : α) {s : Set γ (η ∘ₖ κ) a s = ∫⁻ b, η b s ∂κ a := by rw [comp_apply, Measure.bind_apply hs (Kernel.measurable _)] +@[simp] lemma zero_comp (κ : Kernel α β) : (0 : Kernel β γ) ∘ₖ κ = 0 := by ext; simp [comp_apply] + +@[simp] lemma comp_zero (κ : Kernel β γ) : κ ∘ₖ (0 : Kernel α β) = 0 := by ext; simp [comp_apply] + theorem comp_eq_snd_compProd (η : Kernel β γ) [IsSFiniteKernel η] (κ : Kernel α β) [IsSFiniteKernel κ] : η ∘ₖ κ = snd (κ ⊗ₖ prodMkLeft α η) := by ext a s hs @@ -1085,6 +1121,10 @@ theorem comp_deterministic_eq_comap (κ : Kernel α β) (hg : Measurable g) : simp_rw [comap_apply' _ _ _ s, comp_apply' _ _ _ hs, deterministic_apply hg a, lintegral_dirac' _ (Kernel.measurable_coe κ hs)] +lemma deterministic_comp_deterministic (hf : Measurable f) (hg : Measurable g) : + (deterministic g hg) ∘ₖ (deterministic f hf) = deterministic (g ∘ f) (hg.comp hf) := by + ext; simp [comp_deterministic_eq_comap, comap_apply, deterministic_apply] + lemma const_comp (μ : Measure γ) (κ : Kernel α β) : const β μ ∘ₖ κ = fun a ↦ (κ a) Set.univ • μ := by ext _ _ hs @@ -1096,14 +1136,36 @@ lemma const_comp' (μ : Measure γ) (κ : Kernel α β) [IsMarkovKernel κ] : const β μ ∘ₖ κ = const α μ := by ext; simp_rw [const_comp, measure_univ, one_smul, const_apply] +lemma map_comp (κ : Kernel α β) (η : Kernel β γ) (f : γ → δ) : + (η ∘ₖ κ).map f = (η.map f) ∘ₖ κ := by + by_cases hf : Measurable f + · ext a s hs + rw [map_apply' _ hf _ hs, comp_apply', comp_apply' _ _ _ hs] + · simp_rw [map_apply' _ hf _ hs] + · exact hf hs + · simp [map_of_not_measurable _ hf] + +lemma fst_comp (κ : Kernel α β) (η : Kernel β (γ × δ)) : (η ∘ₖ κ).fst = η.fst ∘ₖ κ := by + simp [fst_eq, map_comp κ η _] + +lemma snd_comp (κ : Kernel α β) (η : Kernel β (γ × δ)) : (η ∘ₖ κ).snd = η.snd ∘ₖ κ := by + simp_rw [snd_eq, map_comp κ η _] + +@[simp] lemma snd_compProd_prodMkLeft + (κ : Kernel α β) (η : Kernel β γ) [IsSFiniteKernel κ] [IsSFiniteKernel η] : + snd (κ ⊗ₖ prodMkLeft α η) = η ∘ₖ κ := by + ext a s hs + rw [snd_apply' _ _ hs, compProd_apply, comp_apply' _ _ _ hs] + · rfl + · exact measurable_snd hs + end Comp section Prod /-! ### Product of two kernels -/ - -variable {γ : Type*} {mγ : MeasurableSpace γ} +variable {γ δ : Type*} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} /-- Product of two kernels. This is meaningful only when the kernels are s-finite. -/ noncomputable def prod (κ : Kernel α β) (η : Kernel α γ) : Kernel α (β × γ) := @@ -1114,7 +1176,7 @@ scoped[ProbabilityTheory] infixl:100 " ×ₖ " => ProbabilityTheory.Kernel.prod theorem prod_apply' (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel α γ) [IsSFiniteKernel η] (a : α) {s : Set (β × γ)} (hs : MeasurableSet s) : (κ ×ₖ η) a s = ∫⁻ b : β, (η a) {c : γ | (b, c) ∈ s} ∂κ a := by - simp_rw [prod, compProd_apply _ _ _ hs, swapLeft_apply _ _, prodMkLeft_apply, Prod.swap_prod_mk] + simp_rw [prod, compProd_apply hs, swapLeft_apply _ _, prodMkLeft_apply, Prod.swap_prod_mk] lemma prod_apply (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel α γ) [IsSFiniteKernel η] (a : α) : @@ -1158,6 +1220,34 @@ instance IsSFiniteKernel.prod (κ : Kernel α β) (η : Kernel α γ) : snd (κ ×ₖ η) = η := by ext x; simp [snd_apply, prod_apply] +lemma comap_prod_swap (κ : Kernel α β) (η : Kernel γ δ) [IsSFiniteKernel κ] [IsSFiniteKernel η] : + comap (prodMkRight α η ×ₖ prodMkLeft γ κ) Prod.swap measurable_swap + = map (prodMkRight γ κ ×ₖ prodMkLeft α η) Prod.swap := by + rw [ext_fun_iff] + intro x f hf + rw [lintegral_comap, lintegral_map _ measurable_swap _ hf, lintegral_prod _ _ _ hf, + lintegral_prod] + swap; · exact hf.comp measurable_swap + simp only [prodMkRight_apply, Prod.fst_swap, Prod.swap_prod_mk, lintegral_prodMkLeft, + Prod.snd_swap] + refine (lintegral_lintegral_swap ?_).symm + exact (hf.comp measurable_swap).aemeasurable + +lemma map_prod_swap (κ : Kernel α β) (η : Kernel α γ) [IsSFiniteKernel κ] [IsSFiniteKernel η] : + map (κ ×ₖ η) Prod.swap = η ×ₖ κ := by + rw [ext_fun_iff] + intro x f hf + rw [lintegral_map _ measurable_swap _ hf, lintegral_prod, lintegral_prod _ _ _ hf] + swap; · exact hf.comp measurable_swap + refine (lintegral_lintegral_swap ?_).symm + exact hf.aemeasurable + +lemma deterministic_prod_deterministic {f : α → β} {g : α → γ} + (hf : Measurable f) (hg : Measurable g) : + deterministic f hf ×ₖ deterministic g hg + = deterministic (fun a ↦ (f a, g a)) (hf.prod_mk hg) := by + ext; simp_rw [prod_apply, deterministic_apply, Measure.dirac_prod_dirac] + end Prod end Kernel end ProbabilityTheory diff --git a/Mathlib/Probability/Kernel/Defs.lean b/Mathlib/Probability/Kernel/Defs.lean index 707e45278f5bc..df3b0dacc3a32 100644 --- a/Mathlib/Probability/Kernel/Defs.lean +++ b/Mathlib/Probability/Kernel/Defs.lean @@ -165,7 +165,7 @@ theorem Kernel.measure_le_bound (κ : Kernel α β) [h : IsFiniteKernel κ] (a : κ a s ≤ IsFiniteKernel.bound κ := (measure_mono (Set.subset_univ s)).trans (h.exists_univ_le.choose_spec.2 a) -instance isFiniteKernel_zero (α β : Type*) {mα : MeasurableSpace α} {mβ : MeasurableSpace β} : +instance isFiniteKernel_zero (α β : Type*) {_ : MeasurableSpace α} {_ : MeasurableSpace β} : IsFiniteKernel (0 : Kernel α β) := ⟨⟨0, ENNReal.coe_lt_top, fun _ => by simp only [Kernel.zero_apply, Measure.coe_zero, Pi.zero_apply, le_zero_iff]⟩⟩ diff --git a/Mathlib/Probability/Kernel/Disintegration/Basic.lean b/Mathlib/Probability/Kernel/Disintegration/Basic.lean index 0b385aef78547..22934beefaf08 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Basic.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Basic.lean @@ -79,7 +79,7 @@ private lemma IsCondKernel.apply_of_ne_zero_of_measurableSet [MeasurableSingleto have : Prod.mk a ⁻¹' (Prod.mk x '' s) = ∅ := by ext y; simp [Ne.symm hax] simp only [this, measure_empty] simp_rw [this] - rw [MeasureTheory.lintegral_indicator _ (measurableSet_singleton x)] + rw [MeasureTheory.lintegral_indicator (measurableSet_singleton x)] simp only [Measure.restrict_singleton, lintegral_smul_measure, lintegral_dirac] rw [← mul_assoc, ENNReal.inv_mul_cancel hx (measure_ne_top _ _), one_mul] @@ -163,7 +163,7 @@ instance condKernelCountable.instIsCondKernel [∀ a, IsMarkovKernel (κCond a)] constructor ext a s hs conv_rhs => rw [← (κ a).disintegrate (κCond a)] - simp_rw [compProd_apply _ _ _ hs, condKernelCountable_apply, Measure.compProd_apply hs] + simp_rw [compProd_apply hs, condKernelCountable_apply, Measure.compProd_apply hs] congr end Countable diff --git a/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean index 5b8e36ae7d2f4..24c15a8c5b0bb 100644 --- a/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean @@ -63,7 +63,8 @@ to `ν` if is measurable, if `fun b ↦ f (a, b) x` is `(ν a)`-integrable for a and for all measurable sets `s : Set β`, `∫ b in s, f (a, b) x ∂(ν a) = (κ a (s ×ˢ Iic x)).toReal`. Also the `ℚ → ℝ` function `f (a, b)` should satisfy the properties of a Sieltjes function for `(ν a)`-almost all `b : β`. -/ -structure IsRatCondKernelCDF (f : α × β → ℚ → ℝ) (κ : Kernel α (β × ℝ)) (ν : Kernel α β) : Prop := +structure IsRatCondKernelCDF (f : α × β → ℚ → ℝ) (κ : Kernel α (β × ℝ)) (ν : Kernel α β) : + Prop where measurable : Measurable f isRatStieltjesPoint_ae (a : α) : ∀ᵐ b ∂(ν a), IsRatStieltjesPoint f (a, b) integrable (a : α) (q : ℚ) : Integrable (fun b ↦ f (a, b) q) (ν a) @@ -222,7 +223,7 @@ lemma integral_stieltjesOfMeasurableRat [IsFiniteKernel κ] (hf : IsRatCondKerne (a : α) (x : ℝ) : ∫ b, stieltjesOfMeasurableRat f hf.measurable (a, b) x ∂(ν a) = (κ a (univ ×ˢ Iic x)).toReal := by - rw [← integral_univ, setIntegral_stieltjesOfMeasurableRat hf _ _ MeasurableSet.univ] + rw [← setIntegral_univ, setIntegral_stieltjesOfMeasurableRat hf _ _ MeasurableSet.univ] end stieltjesOfMeasurableRat @@ -234,7 +235,7 @@ variable {f : α × β → ℚ → ℝ} conditions are the same, but the limit properties of `IsRatCondKernelCDF` are replaced by limits of integrals. -/ structure IsRatCondKernelCDFAux (f : α × β → ℚ → ℝ) (κ : Kernel α (β × ℝ)) (ν : Kernel α β) : - Prop := + Prop where measurable : Measurable f mono' (a : α) {q r : ℚ} (_hqr : q ≤ r) : ∀ᵐ c ∂(ν a), f (a, c) q ≤ f (a, c) r nonneg' (a : α) (q : ℚ) : ∀ᵐ c ∂(ν a), 0 ≤ f (a, c) q @@ -332,7 +333,7 @@ lemma IsRatCondKernelCDFAux.integrable_iInf_rat_gt (hf : IsRatCondKernelCDFAux f [IsFiniteKernel ν] (a : α) (q : ℚ) : Integrable (fun t ↦ ⨅ r : Ioi q, f (a, t) r) (ν a) := by rw [← memℒp_one_iff_integrable] - refine ⟨(measurable_iInf fun i ↦ hf.measurable_right a _).aestronglyMeasurable, ?_⟩ + refine ⟨(Measurable.iInf fun i ↦ hf.measurable_right a _).aestronglyMeasurable, ?_⟩ refine (?_ : _ ≤ (ν a univ : ℝ≥0∞)).trans_lt (measure_lt_top _ _) refine (eLpNorm_le_of_ae_bound (C := 1) ?_).trans (by simp) filter_upwards [hf.bddBelow_range a, hf.nonneg a, hf.le_one a] @@ -424,7 +425,7 @@ respect to `ν` if it is measurable, tends to 0 at -∞ and to 1 at +∞ for all `fun b ↦ f (a, b) x` is `(ν a)`-integrable for all `a : α` and `x : ℝ` and for all measurable sets `s : Set β`, `∫ b in s, f (a, b) x ∂(ν a) = (κ a (s ×ˢ Iic x)).toReal`. -/ structure IsCondKernelCDF (f : α × β → StieltjesFunction) (κ : Kernel α (β × ℝ)) (ν : Kernel α β) : - Prop := + Prop where measurable (x : ℝ) : Measurable fun p ↦ f p x integrable (a : α) (x : ℝ) : Integrable (fun b ↦ f (a, b) x) (ν a) tendsto_atTop_one (p : α × β) : Tendsto (f p) atTop (𝓝 1) @@ -683,7 +684,7 @@ lemma lintegral_toKernel_mem [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ ν) lemma compProd_toKernel [IsFiniteKernel κ] [IsSFiniteKernel ν] (hf : IsCondKernelCDF f κ ν) : ν ⊗ₖ hf.toKernel f = κ := by ext a s hs - rw [Kernel.compProd_apply _ _ _ hs, lintegral_toKernel_mem hf a hs] + rw [Kernel.compProd_apply hs, lintegral_toKernel_mem hf a hs] end diff --git a/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean b/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean index 22bfd49d0e410..c02e122e3cff2 100644 --- a/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean +++ b/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean @@ -42,7 +42,7 @@ open scoped NNReal ENNReal MeasureTheory Topology namespace MeasureTheory.Measure -variable {α β : Type*} {mα : MeasurableSpace α} (ρ : Measure (α × ℝ)) +variable {α : Type*} {mα : MeasurableSpace α} (ρ : Measure (α × ℝ)) /-- Measure on `α` such that for a measurable set `s`, `ρ.IicSnd r s = ρ (s ×ˢ Iic r)`. -/ noncomputable def IicSnd (r : ℝ) : Measure α := @@ -112,7 +112,7 @@ open MeasureTheory namespace ProbabilityTheory -variable {α β ι : Type*} {mα : MeasurableSpace α} +variable {α : Type*} {mα : MeasurableSpace α} attribute [local instance] MeasureTheory.Measure.IsFiniteMeasure.IicSnd @@ -192,7 +192,7 @@ alias set_integral_preCDF_fst := setIntegral_preCDF_fst lemma integral_preCDF_fst (ρ : Measure (α × ℝ)) (r : ℚ) [IsFiniteMeasure ρ] : ∫ x, (preCDF ρ r x).toReal ∂ρ.fst = (ρ.IicSnd r univ).toReal := by - rw [← integral_univ, setIntegral_preCDF_fst ρ _ MeasurableSet.univ] + rw [← setIntegral_univ, setIntegral_preCDF_fst ρ _ MeasurableSet.univ] lemma integrable_preCDF (ρ : Measure (α × ℝ)) [IsFiniteMeasure ρ] (x : ℚ) : Integrable (fun a ↦ (preCDF ρ x a).toReal) ρ.fst := by diff --git a/Mathlib/Probability/Kernel/Disintegration/Density.lean b/Mathlib/Probability/Kernel/Disintegration/Density.lean index 1e1d4fe17ac12..e66eaa2f6fe3f 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Density.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Density.lean @@ -276,7 +276,7 @@ alias set_integral_densityProcess := setIntegral_densityProcess lemma integral_densityProcess (hκν : fst κ ≤ ν) [IsFiniteKernel ν] (n : ℕ) (a : α) {s : Set β} (hs : MeasurableSet s) : ∫ x, densityProcess κ ν n a x s ∂(ν a) = (κ a (univ ×ˢ s)).toReal := by - rw [← integral_univ, setIntegral_densityProcess hκν _ _ hs MeasurableSet.univ] + rw [← setIntegral_univ, setIntegral_densityProcess hκν _ _ hs MeasurableSet.univ] lemma setIntegral_densityProcess_of_le (hκν : fst κ ≤ ν) [IsFiniteKernel ν] {n m : ℕ} (hnm : n ≤ m) (a : α) {s : Set β} (hs : MeasurableSet s) @@ -484,7 +484,7 @@ lemma tendsto_m_density (hκν : fst κ ≤ ν) (a : α) [IsFiniteKernel ν] lemma measurable_density (κ : Kernel α (γ × β)) (ν : Kernel α γ) {s : Set β} (hs : MeasurableSet s) : Measurable (fun (p : α × γ) ↦ density κ ν p.1 p.2 s) := - measurable_limsup (fun n ↦ measurable_densityProcess κ ν n hs) + .limsup (fun n ↦ measurable_densityProcess κ ν n hs) lemma measurable_density_left (κ : Kernel α (γ × β)) (ν : Kernel α γ) (x : γ) {s : Set β} (hs : MeasurableSet s) : @@ -576,7 +576,7 @@ alias set_integral_density_of_measurableSet := setIntegral_density_of_measurable lemma integral_density (hκν : fst κ ≤ ν) [IsFiniteKernel ν] (a : α) {s : Set β} (hs : MeasurableSet s) : ∫ x, density κ ν a x s ∂(ν a) = (κ a (univ ×ˢ s)).toReal := by - rw [← integral_univ, setIntegral_density_of_measurableSet hκν 0 a hs MeasurableSet.univ] + rw [← setIntegral_univ, setIntegral_density_of_measurableSet hκν 0 a hs MeasurableSet.univ] lemma setIntegral_density (hκν : fst κ ≤ ν) [IsFiniteKernel ν] (a : α) {s : Set β} (hs : MeasurableSet s) {A : Set γ} (hA : MeasurableSet A) : diff --git a/Mathlib/Probability/Kernel/Disintegration/Integral.lean b/Mathlib/Probability/Kernel/Disintegration/Integral.lean index 026257adcaf92..b3b312597fb26 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Integral.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Integral.lean @@ -39,21 +39,21 @@ variable [CountableOrCountablyGenerated α β] {κ : Kernel α (β × Ω)} [IsFi lemma lintegral_condKernel_mem (a : α) {s : Set (β × Ω)} (hs : MeasurableSet s) : ∫⁻ x, Kernel.condKernel κ (a, x) {y | (x, y) ∈ s} ∂(Kernel.fst κ a) = κ a s := by conv_rhs => rw [← κ.disintegrate κ.condKernel] - simp_rw [Kernel.compProd_apply _ _ _ hs] + simp_rw [Kernel.compProd_apply hs] lemma setLIntegral_condKernel_eq_measure_prod (a : α) {s : Set β} (hs : MeasurableSet s) {t : Set Ω} (ht : MeasurableSet t) : ∫⁻ b in s, Kernel.condKernel κ (a, b) t ∂(Kernel.fst κ a) = κ a (s ×ˢ t) := by have : κ a (s ×ˢ t) = (Kernel.fst κ ⊗ₖ Kernel.condKernel κ) a (s ×ˢ t) := by congr; exact (κ.disintegrate _).symm - rw [this, Kernel.compProd_apply _ _ _ (hs.prod ht)] + rw [this, Kernel.compProd_apply (hs.prod ht)] classical have : ∀ b, Kernel.condKernel κ (a, b) {c | (b, c) ∈ s ×ˢ t} = s.indicator (fun b ↦ Kernel.condKernel κ (a, b) t) b := by intro b by_cases hb : b ∈ s <;> simp [hb] simp_rw [this] - rw [lintegral_indicator _ hs] + rw [lintegral_indicator hs] @[deprecated (since := "2024-06-29")] alias set_lintegral_condKernel_eq_measure_prod := setLIntegral_condKernel_eq_measure_prod @@ -172,7 +172,7 @@ lemma setLIntegral_condKernel_eq_measure_prod {s : Set β} (hs : MeasurableSet s intro b by_cases hb : b ∈ s <;> simp [hb] simp_rw [this] - rw [lintegral_indicator _ hs] + rw [lintegral_indicator hs] @[deprecated (since := "2024-06-29")] alias set_lintegral_condKernel_eq_measure_prod := setLIntegral_condKernel_eq_measure_prod diff --git a/Mathlib/Probability/Kernel/Disintegration/MeasurableStieltjes.lean b/Mathlib/Probability/Kernel/Disintegration/MeasurableStieltjes.lean index fce06642b56a2..251bef27aec44 100644 --- a/Mathlib/Probability/Kernel/Disintegration/MeasurableStieltjes.lean +++ b/Mathlib/Probability/Kernel/Disintegration/MeasurableStieltjes.lean @@ -3,7 +3,6 @@ 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.Data.Complex.Abs import Mathlib.MeasureTheory.Measure.GiryMonad import Mathlib.MeasureTheory.Measure.Stieltjes import Mathlib.Analysis.Normed.Order.Lattice @@ -48,7 +47,7 @@ open scoped NNReal ENNReal MeasureTheory Topology namespace ProbabilityTheory -variable {α β ι : Type*} +variable {α : Type*} section IsMeasurableRatCDF @@ -84,7 +83,7 @@ lemma measurableSet_isRatStieltjesPoint [MeasurableSpace α] (hf : Measurable f) have h4 : MeasurableSet {a | ∀ t : ℚ, ⨅ r : Ioi t, f a r = f a t} := by rw [Set.setOf_forall] refine MeasurableSet.iInter (fun q ↦ ?_) - exact measurableSet_eq_fun (measurable_iInf fun _ ↦ hf.eval) hf.eval + exact measurableSet_eq_fun (.iInf fun _ ↦ hf.eval) hf.eval suffices {a | IsRatStieltjesPoint f a} = ({a | Monotone (f a)} ∩ {a | Tendsto (f a) atTop (𝓝 1)} ∩ {a | Tendsto (f a) atBot (𝓝 0)} ∩ {a | ∀ t : ℚ, ⨅ r : Ioi t, f a r = f a t}) by @@ -388,7 +387,7 @@ lemma IsMeasurableRatCDF.measurable_stieltjesFunction (x : ℝ) : congr with q rw [stieltjesFunction_eq] rw [this] - exact measurable_iInf (fun q ↦ hf.measurable.eval) + exact .iInf (fun q ↦ hf.measurable.eval) lemma IsMeasurableRatCDF.stronglyMeasurable_stieltjesFunction (x : ℝ) : StronglyMeasurable fun a ↦ hf.stieltjesFunction a x := diff --git a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean index c9a1f8966a14e..b6934d43877ad 100644 --- a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean @@ -81,8 +81,8 @@ lemma isRatCondKernelCDFAux_density_Iic (κ : Kernel α (γ × ℝ)) [IsFiniteKe measurable := measurable_pi_iff.mpr fun _ ↦ measurable_density κ (fst κ) measurableSet_Iic mono' a q r hqr := ae_of_all _ fun c ↦ density_mono_set le_rfl a c (Iic_subset_Iic.mpr (by exact_mod_cast hqr)) - nonneg' a q := ae_of_all _ fun c ↦ density_nonneg le_rfl _ _ _ - le_one' a q := ae_of_all _ fun c ↦ density_le_one le_rfl _ _ _ + nonneg' _ _ := ae_of_all _ fun _ ↦ density_nonneg le_rfl _ _ _ + le_one' _ _ := ae_of_all _ fun _ ↦ density_le_one le_rfl _ _ _ tendsto_integral_of_antitone a s hs_anti hs_tendsto := by let s' : ℕ → Set ℝ := fun n ↦ Iic (s n) refine tendsto_integral_density_of_antitone le_rfl a s' ?_ ?_ (fun _ ↦ measurableSet_Iic) @@ -108,8 +108,8 @@ lemma isRatCondKernelCDFAux_density_Iic (κ : Kernel α (γ × ℝ)) [IsFiniteKe obtain ⟨i, hi⟩ := hs_tendsto q refine ⟨i, hq.le.trans ?_⟩ exact mod_cast hi i le_rfl - integrable a q := integrable_density le_rfl a measurableSet_Iic - setIntegral a A hA q := setIntegral_density le_rfl a measurableSet_Iic hA + integrable a _ := integrable_density le_rfl a measurableSet_Iic + setIntegral a _ hA _ := setIntegral_density le_rfl a measurableSet_Iic hA /-- Taking the kernel density of intervals `Iic q` for `q : ℚ` gives a function with the property `isRatCondKernelCDF`. -/ @@ -259,7 +259,7 @@ lemma compProd_fst_borelMarkovFromReal_eq_comapRight_compProd congr rw [h_fst] ext a t ht : 2 - simp_rw [compProd_apply _ _ _ ht] + simp_rw [compProd_apply ht] refine lintegral_congr_ae ?_ have h_ae : ∀ᵐ t ∂(fst κ a), (a, t) ∈ {p : α × β | η p (range e)ᶜ = 0} := by rw [← h_fst] diff --git a/Mathlib/Probability/Kernel/Disintegration/Unique.lean b/Mathlib/Probability/Kernel/Disintegration/Unique.lean index e1b79719abfe1..786669c638b32 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Unique.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Unique.lean @@ -50,7 +50,7 @@ theorem eq_condKernel_of_measure_eq_compProd' (κ : Kernel α Ω) [IsSFiniteKern refine ae_eq_of_forall_setLIntegral_eq_of_sigmaFinite (Kernel.measurable_coe κ hs) (Kernel.measurable_coe ρ.condKernel hs) (fun t ht _ ↦ ?_) conv_rhs => rw [Measure.setLIntegral_condKernel_eq_measure_prod ht hs, hκ] - simp only [Measure.compProd_apply (ht.prod hs), Set.mem_prod, ← lintegral_indicator _ ht] + simp only [Measure.compProd_apply (ht.prod hs), Set.mem_prod, ← lintegral_indicator ht] congr with x by_cases hx : x ∈ t all_goals simp [hx] @@ -134,7 +134,7 @@ lemma Kernel.apply_eq_measure_condKernel_of_compProd_eq have : ρ a = (ρ a).fst ⊗ₘ Kernel.comap κ (fun b ↦ (a, b)) measurable_prod_mk_left := by ext s hs conv_lhs => rw [← hκ] - rw [Measure.compProd_apply hs, Kernel.compProd_apply _ _ _ hs] + rw [Measure.compProd_apply hs, Kernel.compProd_apply hs] rfl have h := eq_condKernel_of_measure_eq_compProd _ this rw [Kernel.fst_apply] diff --git a/Mathlib/Probability/Kernel/Integral.lean b/Mathlib/Probability/Kernel/Integral.lean index f259203acbe03..e97ef25407719 100644 --- a/Mathlib/Probability/Kernel/Integral.lean +++ b/Mathlib/Probability/Kernel/Integral.lean @@ -91,7 +91,7 @@ end Const section Restrict -variable {s t : Set β} +variable {s : Set β} @[simp] theorem integral_restrict (hs : MeasurableSet s) : diff --git a/Mathlib/Probability/Kernel/IntegralCompProd.lean b/Mathlib/Probability/Kernel/IntegralCompProd.lean index a8ad7e64ece6c..e88e7a0f5f916 100644 --- a/Mathlib/Probability/Kernel/IntegralCompProd.lean +++ b/Mathlib/Probability/Kernel/IntegralCompProd.lean @@ -234,7 +234,7 @@ theorem integral_compProd : rotate_left · exact (Kernel.measurable_kernel_prod_mk_left' hs _).aemeasurable · exact ae_kernel_lt_top a h2s.ne - rw [Kernel.compProd_apply _ _ _ hs] + rw [Kernel.compProd_apply hs] rfl · intro f g _ i_f i_g hf hg simp_rw [integral_add' i_f i_g, Kernel.integral_integral_add' i_f i_g, hf, hg] diff --git a/Mathlib/Probability/Kernel/Invariance.lean b/Mathlib/Probability/Kernel/Invariance.lean index 58d1a2185d16b..e9d40e85a0dd9 100644 --- a/Mathlib/Probability/Kernel/Invariance.lean +++ b/Mathlib/Probability/Kernel/Invariance.lean @@ -30,7 +30,7 @@ open scoped MeasureTheory ENNReal ProbabilityTheory namespace ProbabilityTheory -variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} +variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} namespace Kernel diff --git a/Mathlib/Probability/Kernel/MeasurableIntegral.lean b/Mathlib/Probability/Kernel/MeasurableIntegral.lean index dc0acc26cac82..63c99fb77ebfa 100644 --- a/Mathlib/Probability/Kernel/MeasurableIntegral.lean +++ b/Mathlib/Probability/Kernel/MeasurableIntegral.lean @@ -152,7 +152,7 @@ theorem _root_.Measurable.lintegral_kernel_prod_right {f : α → β → ℝ≥0 · exact fun n => (F n).measurable.comp measurable_prod_mk_left · exact fun i j hij b => SimpleFunc.monotone_eapprox (uncurry f) hij _ simp_rw [this] - refine measurable_iSup fun n => ?_ + refine .iSup fun n => ?_ refine SimpleFunc.induction (P := fun f => Measurable (fun (a : α) => ∫⁻ (b : β), f (a, b) ∂κ a)) ?_ ?_ (F n) · intro c t ht @@ -166,7 +166,7 @@ theorem _root_.Measurable.lintegral_kernel_prod_right {f : α → β → ℝ≥0 (fun a => ∫⁻ b, g₁ (a, b) ∂κ a) + fun a => ∫⁻ b, g₂ (a, b) ∂κ a := by ext1 a rw [Pi.add_apply] - -- Porting note (#10691): was `rw` (`Function.comp` reducibility) + -- Porting note (#11224): was `rw` (`Function.comp` reducibility) erw [lintegral_add_left (g₁.measurable.comp measurable_prod_mk_left)] simp_rw [Function.comp_apply] rw [h_add] @@ -231,7 +231,7 @@ alias _root_.Measurable.set_lintegral_kernel := _root_.Measurable.setLIntegral_k end Lintegral -variable {E : Type*} [NormedAddCommGroup E] [IsSFiniteKernel κ] [IsSFiniteKernel η] +variable {E : Type*} [NormedAddCommGroup E] [IsSFiniteKernel κ] theorem measurableSet_kernel_integrable ⦃f : α → β → E⦄ (hf : StronglyMeasurable (uncurry f)) : MeasurableSet {x | Integrable (f x) (κ x)} := by diff --git a/Mathlib/Probability/Kernel/MeasureCompProd.lean b/Mathlib/Probability/Kernel/MeasureCompProd.lean index b2bf06645a1a6..b2e9841c037ba 100644 --- a/Mathlib/Probability/Kernel/MeasureCompProd.lean +++ b/Mathlib/Probability/Kernel/MeasureCompProd.lean @@ -55,13 +55,13 @@ lemma compProd_of_not_isSFiniteKernel (μ : Measure α) (κ : Kernel α β) (h : lemma compProd_apply [SFinite μ] [IsSFiniteKernel κ] {s : Set (α × β)} (hs : MeasurableSet s) : (μ ⊗ₘ κ) s = ∫⁻ a, κ a (Prod.mk a ⁻¹' s) ∂μ := by - simp_rw [compProd, Kernel.compProd_apply _ _ _ hs, Kernel.const_apply, Kernel.prodMkLeft_apply'] + simp_rw [compProd, Kernel.compProd_apply hs, Kernel.const_apply, Kernel.prodMkLeft_apply'] rfl lemma compProd_apply_prod [SFinite μ] [IsSFiniteKernel κ] {s : Set α} {t : Set β} (hs : MeasurableSet s) (ht : MeasurableSet t) : (μ ⊗ₘ κ) (s ×ˢ t) = ∫⁻ a in s, κ a t ∂μ := by - rw [compProd_apply (hs.prod ht), ← lintegral_indicator _ hs] + rw [compProd_apply (hs.prod ht), ← lintegral_indicator hs] congr with a classical rw [Set.indicator_apply] diff --git a/Mathlib/Probability/Kernel/RadonNikodym.lean b/Mathlib/Probability/Kernel/RadonNikodym.lean index d99f2e27d910e..4966a4d770e7c 100644 --- a/Mathlib/Probability/Kernel/RadonNikodym.lean +++ b/Mathlib/Probability/Kernel/RadonNikodym.lean @@ -402,6 +402,8 @@ lemma rnDeriv_add_singularPart (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFin zero_add, withDensity_rnDeriv_of_subset_compl_mutuallySingularSetSlice (hs.diff hm) (diff_subset_iff.mpr (by simp)), add_comm] +section EqZeroIff + lemma singularPart_eq_zero_iff_apply_eq_zero (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] (a : α) : singularPart κ η a = 0 ↔ singularPart κ η a (mutuallySingularSetSlice κ η a) = 0 := by @@ -466,6 +468,8 @@ lemma withDensity_rnDeriv_eq_zero_iff_measure_eq_zero (κ η : Kernel α γ) rw [← h_eq_add] exact withDensity_rnDeriv_eq_zero_iff_apply_eq_zero κ η a +end EqZeroIff + /-- The set of points `a : α` such that `κ a ≪ η a` is measurable. -/ @[measurability] lemma measurableSet_absolutelyContinuous (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] : @@ -484,4 +488,132 @@ lemma measurableSet_mutuallySingular (κ η : Kernel α γ) [IsFiniteKernel κ] exact measurable_kernel_prod_mk_left (measurableSet_mutuallySingularSet κ η).compl (measurableSet_singleton 0) +@[simp] +lemma singularPart_self (κ : Kernel α γ) [IsFiniteKernel κ] : κ.singularPart κ = 0 := by + ext : 1; rw [zero_apply, singularPart_eq_zero_iff_absolutelyContinuous] + +section Unique + +variable {ξ : Kernel α γ} {f : α → γ → ℝ≥0∞} [IsFiniteKernel η] + +omit hαγ in +lemma eq_rnDeriv_measure (h : κ = η.withDensity f + ξ) + (hf : Measurable (Function.uncurry f)) (a : α) (hξ : ξ a ⟂ₘ η a) : + f a =ᵐ[η a] ∂(κ a)/∂(η a) := by + have : κ a = ξ a + (η a).withDensity (f a) := by + rw [h, coe_add, Pi.add_apply, η.withDensity_apply hf, add_comm] + exact (κ a).eq_rnDeriv₀ (hf.comp measurable_prod_mk_left).aemeasurable hξ this + +omit hαγ in +lemma eq_singularPart_measure (h : κ = η.withDensity f + ξ) + (hf : Measurable (Function.uncurry f)) (a : α) (hξ : ξ a ⟂ₘ η a) : + ξ a = (κ a).singularPart (η a) := by + have : κ a = ξ a + (η a).withDensity (f a) := by + rw [h, coe_add, Pi.add_apply, η.withDensity_apply hf, add_comm] + exact (κ a).eq_singularPart (hf.comp measurable_prod_mk_left) hξ this + +variable [IsFiniteKernel κ] {a : α} + +lemma rnDeriv_eq_rnDeriv_measure : rnDeriv κ η a =ᵐ[η a] ∂(κ a)/∂(η a) := + eq_rnDeriv_measure (rnDeriv_add_singularPart κ η).symm (measurable_rnDeriv κ η) a + (mutuallySingular_singularPart κ η a) + +lemma singularPart_eq_singularPart_measure : singularPart κ η a = (κ a).singularPart (η a) := + eq_singularPart_measure (rnDeriv_add_singularPart κ η).symm (measurable_rnDeriv κ η) a + (mutuallySingular_singularPart κ η a) + +lemma eq_rnDeriv (h : κ = η.withDensity f + ξ) + (hf : Measurable (Function.uncurry f)) (a : α) (hξ : ξ a ⟂ₘ η a) : + f a =ᵐ[η a] rnDeriv κ η a := + (eq_rnDeriv_measure h hf a hξ).trans rnDeriv_eq_rnDeriv_measure.symm + +lemma eq_singularPart (h : κ = η.withDensity f + ξ) + (hf : Measurable (Function.uncurry f)) (a : α) (hξ : ξ a ⟂ₘ η a) : + ξ a = singularPart κ η a := + (eq_singularPart_measure h hf a hξ).trans singularPart_eq_singularPart_measure.symm + +end Unique + +instance [hκ : IsFiniteKernel κ] [IsFiniteKernel η] : + IsFiniteKernel (withDensity η (rnDeriv κ η)) := by + refine ⟨hκ.bound, hκ.bound_lt_top, fun a ↦ ?_⟩ + rw [Kernel.withDensity_apply', setLIntegral_univ] + swap; · exact measurable_rnDeriv κ η + rw [lintegral_congr_ae rnDeriv_eq_rnDeriv_measure] + exact Measure.lintegral_rnDeriv_le.trans (measure_le_bound _ _ _) + +instance [hκ : IsFiniteKernel κ] [IsFiniteKernel η] : IsFiniteKernel (singularPart κ η) := by + refine ⟨hκ.bound, hκ.bound_lt_top, fun a ↦ ?_⟩ + have h : withDensity η (rnDeriv κ η) a univ + singularPart κ η a univ = κ a univ := by + conv_rhs => rw [← rnDeriv_add_singularPart κ η] + simp + exact (self_le_add_left _ _).trans (h.le.trans (measure_le_bound _ _ _)) + +/-- For two kernels `κ, η`, the singular part of `κ a` with respect to `η a` is a measurable +function of `a`. -/ +lemma measurable_singularPart (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] : + Measurable (fun a ↦ (κ a).singularPart (η a)) := by + refine Measure.measurable_of_measurable_coe _ (fun s hs ↦ ?_) + simp_rw [← κ.singularPart_eq_singularPart_measure, κ.singularPart_def η] + exact Kernel.measurable_coe _ hs + +lemma rnDeriv_self (κ : Kernel α γ) [IsFiniteKernel κ] (a : α) : rnDeriv κ κ a =ᵐ[κ a] 1 := + (κ.rnDeriv_eq_rnDeriv_measure).trans (κ a).rnDeriv_self + +lemma rnDeriv_singularPart (κ ν : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel ν] (a : α) : + rnDeriv (singularPart κ ν) ν a =ᵐ[ν a] 0 := by + filter_upwards [(singularPart κ ν).rnDeriv_eq_rnDeriv_measure, + (Measure.rnDeriv_eq_zero _ _).mpr (mutuallySingular_singularPart κ ν a)] with x h1 h2 + rw [h1, h2] + +lemma rnDeriv_lt_top (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} : + ∀ᵐ x ∂(η a), rnDeriv κ η a x < ∞ := by + filter_upwards [κ.rnDeriv_eq_rnDeriv_measure, (κ a).rnDeriv_ne_top _] + with x heq htop using heq ▸ htop.lt_top + +lemma rnDeriv_ne_top (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} : + ∀ᵐ x ∂(η a), rnDeriv κ η a x ≠ ∞ := by + filter_upwards [κ.rnDeriv_lt_top η] with a h using h.ne + +lemma rnDeriv_pos [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} (ha : κ a ≪ η a) : + ∀ᵐ x ∂(κ a), 0 < rnDeriv κ η a x := by + filter_upwards [ha.ae_le κ.rnDeriv_eq_rnDeriv_measure, Measure.rnDeriv_pos ha] + with x heq hpos using heq ▸ hpos + +lemma rnDeriv_toReal_pos [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} (h : κ a ≪ η a) : + ∀ᵐ x ∂(κ a), 0 < (rnDeriv κ η a x).toReal := by + filter_upwards [rnDeriv_pos h, h.ae_le (rnDeriv_ne_top κ _)] with x h0 htop + simp_all only [pos_iff_ne_zero, ne_eq, ENNReal.toReal_pos, not_false_eq_true, and_self] + +lemma rnDeriv_add (κ ν η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel ν] [IsFiniteKernel η] + (a : α) : + rnDeriv (κ + ν) η a =ᵐ[η a] rnDeriv κ η a + rnDeriv ν η a := by + filter_upwards [(κ + ν).rnDeriv_eq_rnDeriv_measure, κ.rnDeriv_eq_rnDeriv_measure, + ν.rnDeriv_eq_rnDeriv_measure, (κ a).rnDeriv_add (ν a) (η a)] with x h1 h2 h3 h4 + rw [h1, Pi.add_apply, h2, h3, coe_add, Pi.add_apply, h4, Pi.add_apply] + +lemma withDensity_rnDeriv_le (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] (a : α) : + η.withDensity (κ.rnDeriv η) a ≤ κ a := by + refine Measure.le_intro (fun s hs _ ↦ ?_) + rw [Kernel.withDensity_apply'] + swap; · exact κ.measurable_rnDeriv _ + rw [setLIntegral_congr_fun hs ((κ.rnDeriv_eq_rnDeriv_measure).mono (fun x hx _ ↦ hx)), + ← withDensity_apply _ hs] + exact (κ a).withDensity_rnDeriv_le _ _ + +lemma withDensity_rnDeriv_eq [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} (h : κ a ≪ η a) : + η.withDensity (κ.rnDeriv η) a = κ a := by + rw [Kernel.withDensity_apply] + swap; · exact κ.measurable_rnDeriv _ + have h_ae := κ.rnDeriv_eq_rnDeriv_measure (η := η) (a := a) + rw [MeasureTheory.withDensity_congr_ae h_ae, (κ a).withDensity_rnDeriv_eq _ h] + +lemma rnDeriv_withDensity [IsFiniteKernel κ] {f : α → γ → ℝ≥0∞} [IsFiniteKernel (withDensity κ f)] + (hf : Measurable (Function.uncurry f)) (a : α) : + (κ.withDensity f).rnDeriv κ a =ᵐ[κ a] f a := by + have h_ae := (κ.withDensity f).rnDeriv_eq_rnDeriv_measure (η := κ) (a := a) + have hf' : ∀ a, Measurable (f a) := fun _ ↦ hf.of_uncurry_left + filter_upwards [h_ae, (κ a).rnDeriv_withDensity (hf' a)] with x hx1 hx2 + rw [hx1, κ.withDensity_apply hf, hx2] + end ProbabilityTheory.Kernel diff --git a/Mathlib/Probability/Martingale/Basic.lean b/Mathlib/Probability/Martingale/Basic.lean index 08032df92e947..1693e5117c3b3 100644 --- a/Mathlib/Probability/Martingale/Basic.lean +++ b/Mathlib/Probability/Martingale/Basic.lean @@ -161,7 +161,7 @@ theorem setIntegral_le [SigmaFiniteFiltration μ ℱ] {f : ι → Ω → ℝ} (h @[deprecated (since := "2024-04-17")] alias set_integral_le := setIntegral_le -theorem add [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Supermartingale f ℱ μ) +theorem add [Preorder E] [AddLeftMono E] (hf : Supermartingale f ℱ μ) (hg : Supermartingale g ℱ μ) : Supermartingale (f + g) ℱ μ := by refine ⟨hf.1.add hg.1, fun i j hij => ?_, fun i => (hf.2.2 i).add (hg.2.2 i)⟩ refine (condexp_add (hf.integrable j) (hg.integrable j)).le.trans ?_ @@ -169,11 +169,11 @@ theorem add [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Superm intros refine add_le_add ?_ ?_ <;> assumption -theorem add_martingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] +theorem add_martingale [Preorder E] [AddLeftMono E] (hf : Supermartingale f ℱ μ) (hg : Martingale g ℱ μ) : Supermartingale (f + g) ℱ μ := hf.add hg.supermartingale -theorem neg [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Supermartingale f ℱ μ) : +theorem neg [Preorder E] [AddLeftMono E] (hf : Supermartingale f ℱ μ) : Submartingale (-f) ℱ μ := by refine ⟨hf.1.neg, fun i j hij => ?_, fun i => (hf.2.2 i).neg⟩ refine EventuallyLE.trans ?_ (condexp_neg (f j)).symm.le @@ -198,7 +198,7 @@ theorem ae_le_condexp [LE E] (hf : Submartingale f ℱ μ) {i j : ι} (hij : i f i ≤ᵐ[μ] μ[f j|ℱ i] := hf.2.1 i j hij -theorem add [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Submartingale f ℱ μ) +theorem add [Preorder E] [AddLeftMono E] (hf : Submartingale f ℱ μ) (hg : Submartingale g ℱ μ) : Submartingale (f + g) ℱ μ := by refine ⟨hf.1.add hg.1, fun i j hij => ?_, fun i => (hf.2.2 i).add (hg.2.2 i)⟩ refine EventuallyLE.trans ?_ (condexp_add (hf.integrable j) (hg.integrable j)).symm.le @@ -206,11 +206,11 @@ theorem add [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Submar intros refine add_le_add ?_ ?_ <;> assumption -theorem add_martingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Submartingale f ℱ μ) +theorem add_martingale [Preorder E] [AddLeftMono E] (hf : Submartingale f ℱ μ) (hg : Martingale g ℱ μ) : Submartingale (f + g) ℱ μ := hf.add hg.submartingale -theorem neg [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Submartingale f ℱ μ) : +theorem neg [Preorder E] [AddLeftMono E] (hf : Submartingale f ℱ μ) : Supermartingale (-f) ℱ μ := by refine ⟨hf.1.neg, fun i j hij => (condexp_neg (f j)).le.trans ?_, fun i => (hf.2.2 i).neg⟩ filter_upwards [hf.2.1 i j hij] with _ _ @@ -226,11 +226,11 @@ theorem setIntegral_le [SigmaFiniteFiltration μ ℱ] {f : ι → Ω → ℝ} (h @[deprecated (since := "2024-04-17")] alias set_integral_le := setIntegral_le -theorem sub_supermartingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] +theorem sub_supermartingale [Preorder E] [AddLeftMono E] (hf : Submartingale f ℱ μ) (hg : Supermartingale g ℱ μ) : Submartingale (f - g) ℱ μ := by rw [sub_eq_add_neg]; exact hf.add hg.neg -theorem sub_martingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] (hf : Submartingale f ℱ μ) +theorem sub_martingale [Preorder E] [AddLeftMono E] (hf : Submartingale f ℱ μ) (hg : Martingale g ℱ μ) : Submartingale (f - g) ℱ μ := hf.sub_supermartingale hg.supermartingale @@ -299,11 +299,11 @@ end Submartingale namespace Supermartingale -theorem sub_submartingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] +theorem sub_submartingale [Preorder E] [AddLeftMono E] (hf : Supermartingale f ℱ μ) (hg : Submartingale g ℱ μ) : Supermartingale (f - g) ℱ μ := by rw [sub_eq_add_neg]; exact hf.add hg.neg -theorem sub_martingale [Preorder E] [CovariantClass E E (· + ·) (· ≤ ·)] +theorem sub_martingale [Preorder E] [AddLeftMono E] (hf : Supermartingale f ℱ μ) (hg : Martingale g ℱ μ) : Supermartingale (f - g) ℱ μ := hf.sub_submartingale hg.submartingale diff --git a/Mathlib/Probability/Martingale/BorelCantelli.lean b/Mathlib/Probability/Martingale/BorelCantelli.lean index fffa57f7af53e..0f483a8596a0b 100644 --- a/Mathlib/Probability/Martingale/BorelCantelli.lean +++ b/Mathlib/Probability/Martingale/BorelCantelli.lean @@ -34,12 +34,11 @@ and `ProbabilityTheory.measure_limsup_eq_one` for the second (which does). open Filter -open scoped NNReal ENNReal MeasureTheory ProbabilityTheory BigOperators Topology +open scoped NNReal ENNReal MeasureTheory ProbabilityTheory Topology namespace MeasureTheory variable {Ω : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} {ℱ : Filtration ℕ m0} {f : ℕ → Ω → ℝ} - {ω : Ω} /-! ### One sided martingale bound @@ -127,7 +126,7 @@ theorem Submartingale.stoppedValue_leastGE_eLpNorm_le [IsFiniteMeasure μ] (hf : eLpNorm (stoppedValue f (leastGE f r i)) 1 μ ≤ 2 * μ Set.univ * ENNReal.ofReal (r + R) := by refine eLpNorm_one_le_of_le' ((hf.stoppedValue_leastGE r).integrable _) ?_ (norm_stoppedValue_leastGE_le hr hf0 hbdd i) - rw [← integral_univ] + rw [← setIntegral_univ] refine le_trans ?_ ((hf.stoppedValue_leastGE r).setIntegral_le (zero_le _) MeasurableSet.univ) simp_rw [stoppedValue, leastGE, hitting_of_le le_rfl, hf0, integral_zero', le_rfl] diff --git a/Mathlib/Probability/Martingale/Centering.lean b/Mathlib/Probability/Martingale/Centering.lean index a02deed0fd1c2..57697df89952a 100644 --- a/Mathlib/Probability/Martingale/Centering.lean +++ b/Mathlib/Probability/Martingale/Centering.lean @@ -36,7 +36,7 @@ open scoped NNReal ENNReal MeasureTheory ProbabilityTheory namespace MeasureTheory variable {Ω E : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} [NormedAddCommGroup E] - [NormedSpace ℝ E] [CompleteSpace E] {f : ℕ → Ω → E} {ℱ : Filtration ℕ m0} {n : ℕ} + [NormedSpace ℝ E] [CompleteSpace E] {f : ℕ → Ω → E} {ℱ : Filtration ℕ m0} /-- Any `ℕ`-indexed stochastic process can be written as the sum of a martingale and a predictable process. This is the predictable process. See `martingalePart` for the martingale. -/ diff --git a/Mathlib/Probability/Martingale/Convergence.lean b/Mathlib/Probability/Martingale/Convergence.lean index 5cbec74af7d1e..cd3dced4e0672 100644 --- a/Mathlib/Probability/Martingale/Convergence.lean +++ b/Mathlib/Probability/Martingale/Convergence.lean @@ -48,7 +48,7 @@ open scoped NNReal ENNReal MeasureTheory ProbabilityTheory Topology namespace MeasureTheory -variable {Ω ι : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} {ℱ : Filtration ℕ m0} +variable {Ω : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} {ℱ : Filtration ℕ m0} variable {a b : ℝ} {f : ℕ → Ω → ℝ} {ω : Ω} {R : ℝ≥0} section AeConvergence @@ -191,7 +191,7 @@ theorem Submartingale.exists_ae_tendsto_of_bdd [IsFiniteMeasure μ] (hf : Submar theorem Submartingale.exists_ae_trim_tendsto_of_bdd [IsFiniteMeasure μ] (hf : Submartingale f ℱ μ) (hbdd : ∀ n, eLpNorm (f n) 1 μ ≤ R) : - ∀ᵐ ω ∂μ.trim (sSup_le fun m ⟨n, hn⟩ => hn ▸ ℱ.le _ : ⨆ n, ℱ n ≤ m0), + ∀ᵐ ω ∂μ.trim (sSup_le fun _ ⟨_, hn⟩ => hn ▸ ℱ.le _ : ⨆ n, ℱ n ≤ m0), ∃ c, Tendsto (fun n => f n ω) atTop (𝓝 c) := by letI := (⨆ n, ℱ n) rw [ae_iff, trim_measurableSet_eq] @@ -399,8 +399,8 @@ theorem Integrable.tendsto_ae_condexp (hg : Integrable g μ) setIntegral_trim hle stronglyMeasurable_limitProcess htmeas.compl, hgeq, hheq, ← setIntegral_trim hle hgmeas htmeas, ← setIntegral_trim hle stronglyMeasurable_limitProcess htmeas, ← integral_trim hle hgmeas, ← - integral_trim hle stronglyMeasurable_limitProcess, ← integral_univ, - this 0 _ MeasurableSet.univ, integral_univ, ht (measure_lt_top _ _)] + integral_trim hle stronglyMeasurable_limitProcess, ← setIntegral_univ, + this 0 _ MeasurableSet.univ, setIntegral_univ, ht (measure_lt_top _ _)] · rintro f hf hfmeas heq - rw [integral_iUnion (fun n => hle _ (hfmeas n)) hf hg.integrableOn, integral_iUnion (fun n => hle _ (hfmeas n)) hf hlimint.integrableOn] diff --git a/Mathlib/Probability/Martingale/OptionalSampling.lean b/Mathlib/Probability/Martingale/OptionalSampling.lean index 535963b759aba..90b9489aaa39c 100644 --- a/Mathlib/Probability/Martingale/OptionalSampling.lean +++ b/Mathlib/Probability/Martingale/OptionalSampling.lean @@ -143,11 +143,11 @@ and is a measurable space with the Borel σ-algebra. -/ variable {ι : Type*} [LinearOrder ι] [LocallyFiniteOrder ι] [OrderBot ι] [TopologicalSpace ι] [DiscreteTopology ι] [MeasurableSpace ι] [BorelSpace ι] [MeasurableSpace E] [BorelSpace E] - [SecondCountableTopology E] {ℱ : Filtration ι m} {τ σ : Ω → ι} {f : ι → Ω → E} {i n : ι} + [SecondCountableTopology E] {ℱ : Filtration ι m} {τ σ : Ω → ι} {f : ι → Ω → E} {i : ι} theorem condexp_stoppedValue_stopping_time_ae_eq_restrict_le (h : Martingale f ℱ μ) (hτ : IsStoppingTime ℱ τ) (hσ : IsStoppingTime ℱ σ) [SigmaFinite (μ.trim hσ.measurableSpace_le)] - (hτ_le : ∀ x, τ x ≤ n) : + (hτ_le : ∀ x, τ x ≤ i) : μ[stoppedValue f τ|hσ.measurableSpace] =ᵐ[μ.restrict {x : Ω | τ x ≤ σ x}] stoppedValue f τ := by rw [ae_eq_restrict_iff_indicator_ae_eq (hτ.measurableSpace_le _ (hτ.measurableSet_le_stopping_time hσ))] diff --git a/Mathlib/Probability/Martingale/OptionalStopping.lean b/Mathlib/Probability/Martingale/OptionalStopping.lean index fee8f4ea1c1a3..c047618b86b01 100644 --- a/Mathlib/Probability/Martingale/OptionalStopping.lean +++ b/Mathlib/Probability/Martingale/OptionalStopping.lean @@ -144,8 +144,8 @@ theorem maximal_ineq [IsFiniteMeasure μ] (hsub : Submartingale f 𝒢 μ) (hnon (∫ ω in {ω | ↑ε ≤ (range (n+1)).sup' nonempty_range_succ fun k => f k ω}, f n ω ∂μ) + ENNReal.ofReal (∫ ω in {ω | ((range (n+1)).sup' nonempty_range_succ fun k => f k ω) < ↑ε}, f n ω ∂μ) := by - rw [← ENNReal.ofReal_add, ← integral_union] - · rw [← integral_univ] + rw [← ENNReal.ofReal_add, ← setIntegral_union] + · rw [← setIntegral_univ] convert rfl ext ω change (ε : ℝ) ≤ _ ∨ _ < (ε : ℝ) ↔ _ @@ -186,8 +186,8 @@ theorem maximal_ineq [IsFiniteMeasure μ] (hsub : Submartingale f 𝒢 μ) (hnon ((not_le.2 hω) ((le_sup'_iff _).2 ⟨m, mem_range.2 (Nat.lt_succ_of_le hm.2), hεm⟩)) simp_rw [stoppedValue, this, le_rfl] _ = ENNReal.ofReal (∫ ω, stoppedValue f (hitting f {y : ℝ | ↑ε ≤ y} 0 n) ω ∂μ) := by - rw [← ENNReal.ofReal_add, ← integral_union] - · rw [← integral_univ (μ := μ)] + rw [← ENNReal.ofReal_add, ← setIntegral_union] + · rw [← setIntegral_univ (μ := μ)] convert rfl ext ω change _ ↔ (ε : ℝ) ≤ _ ∨ _ < (ε : ℝ) diff --git a/Mathlib/Probability/Martingale/Upcrossing.lean b/Mathlib/Probability/Martingale/Upcrossing.lean index a1694af83142d..f4b820cc62dbc 100644 --- a/Mathlib/Probability/Martingale/Upcrossing.lean +++ b/Mathlib/Probability/Martingale/Upcrossing.lean @@ -148,7 +148,7 @@ noncomputable def lowerCrossingTime [Preorder ι] [OrderBot ι] [InfSet ι] (a b section variable [Preorder ι] [OrderBot ι] [InfSet ι] -variable {a b : ℝ} {f : ι → Ω → ℝ} {N : ι} {n m : ℕ} {ω : Ω} +variable {a b : ℝ} {f : ι → Ω → ℝ} {N : ι} {n : ℕ} {ω : Ω} @[simp] theorem upperCrossingTime_zero : upperCrossingTime a b f N 0 = ⊥ := @@ -389,7 +389,7 @@ theorem Submartingale.sum_mul_upcrossingStrat_le [IsFiniteMeasure μ] (hf : Subm have h₁ : (0 : ℝ) ≤ μ[∑ k ∈ Finset.range n, (1 - upcrossingStrat a b f N k) * (f (k + 1) - f k)] := by have := (hf.sum_sub_upcrossingStrat_mul a b N).setIntegral_le (zero_le n) MeasurableSet.univ - rw [integral_univ, integral_univ] at this + rw [setIntegral_univ, setIntegral_univ] at this refine le_trans ?_ this simp only [Finset.range_zero, Finset.sum_empty, integral_zero', le_refl] have h₂ : μ[∑ k ∈ Finset.range n, (1 - upcrossingStrat a b f N k) * (f (k + 1) - f k)] = @@ -762,7 +762,7 @@ noncomputable def upcrossings [Preorder ι] [OrderBot ι] [InfSet ι] (a b : ℝ theorem Adapted.measurable_upcrossings (hf : Adapted ℱ f) (hab : a < b) : Measurable (upcrossings a b f) := - measurable_iSup fun _ => measurable_from_top.comp (hf.measurable_upcrossingsBefore hab) + .iSup fun _ => measurable_from_top.comp (hf.measurable_upcrossingsBefore hab) theorem upcrossings_lt_top_iff : upcrossings a b f ω < ∞ ↔ ∃ k, ∀ N, upcrossingsBefore a b f N ω ≤ k := by diff --git a/Mathlib/Probability/Moments.lean b/Mathlib/Probability/Moments.lean index 3ad21345e302f..1433dc8119e43 100644 --- a/Mathlib/Probability/Moments.lean +++ b/Mathlib/Probability/Moments.lean @@ -244,7 +244,7 @@ theorem IndepFun.integrable_exp_mul_add {X Y : Ω → ℝ} (h_indep : IndepFun X exact (h_indep.exp_mul t t).integrable_mul h_int_X h_int_Y theorem iIndepFun.integrable_exp_mul_sum [IsFiniteMeasure μ] {X : ι → Ω → ℝ} - (h_indep : iIndepFun (fun i => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) + (h_indep : iIndepFun (fun _ => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) {s : Finset ι} (h_int : ∀ i ∈ s, Integrable (fun ω => exp (t * X i ω)) μ) : Integrable (fun ω => exp (t * (∑ i ∈ s, X i) ω)) μ := by classical @@ -259,7 +259,7 @@ theorem iIndepFun.integrable_exp_mul_sum [IsFiniteMeasure μ] {X : ι → Ω → exact (h_indep.indepFun_finset_sum_of_not_mem h_meas hi_notin_s).symm theorem iIndepFun.mgf_sum {X : ι → Ω → ℝ} - (h_indep : iIndepFun (fun i => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) + (h_indep : iIndepFun (fun _ => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) (s : Finset ι) : mgf (∑ i ∈ s, X i) μ t = ∏ i ∈ s, mgf (X i) μ t := by have : IsProbabilityMeasure μ := h_indep.isProbabilityMeasure classical @@ -273,7 +273,7 @@ theorem iIndepFun.mgf_sum {X : ι → Ω → ℝ} h_rec, prod_insert hi_notin_s] theorem iIndepFun.cgf_sum {X : ι → Ω → ℝ} - (h_indep : iIndepFun (fun i => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) + (h_indep : iIndepFun (fun _ => inferInstance) X μ) (h_meas : ∀ i, Measurable (X i)) {s : Finset ι} (h_int : ∀ i ∈ s, Integrable (fun ω => exp (t * X i ω)) μ) : cgf (∑ i ∈ s, X i) μ t = ∑ i ∈ s, cgf (X i) μ t := by have : IsProbabilityMeasure μ := h_indep.isProbabilityMeasure diff --git a/Mathlib/Probability/ProbabilityMassFunction/Basic.lean b/Mathlib/Probability/ProbabilityMassFunction/Basic.lean index 877ecc41e7f9d..14593d136558b 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Basic.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Basic.lean @@ -32,7 +32,7 @@ probability mass function, discrete probability measure noncomputable section -variable {α β γ : Type*} +variable {α : Type*} open scoped Classical open NNReal ENNReal MeasureTheory @@ -132,7 +132,7 @@ open MeasureTheory MeasureTheory.OuterMeasure def toOuterMeasure (p : PMF α) : OuterMeasure α := OuterMeasure.sum fun x : α => p x • dirac x -variable (p : PMF α) (s t : Set α) +variable (p : PMF α) (s : Set α) theorem toOuterMeasure_apply : p.toOuterMeasure s = ∑' x, s.indicator p x := tsum_congr fun x => smul_dirac_apply (p x) x s @@ -165,7 +165,7 @@ theorem toOuterMeasure_inj {p q : PMF α} : p.toOuterMeasure = q.toOuterMeasure theorem toOuterMeasure_apply_eq_zero_iff : p.toOuterMeasure s = 0 ↔ Disjoint p.support s := by rw [toOuterMeasure_apply, ENNReal.tsum_eq_zero] - exact Function.funext_iff.symm.trans Set.indicator_eq_zero' + exact funext_iff.symm.trans Set.indicator_eq_zero' theorem toOuterMeasure_apply_eq_one_iff : p.toOuterMeasure s = 1 ↔ p.support ⊆ s := by refine (p.toOuterMeasure_apply s).symm ▸ ⟨fun h a hap => ?_, fun h => ?_⟩ @@ -210,7 +210,7 @@ open MeasureTheory def toMeasure [MeasurableSpace α] (p : PMF α) : Measure α := p.toOuterMeasure.toMeasure ((toOuterMeasure_caratheodory p).symm ▸ le_top) -variable [MeasurableSpace α] (p : PMF α) (s t : Set α) +variable [MeasurableSpace α] (p : PMF α) (s : Set α) theorem toOuterMeasure_apply_le_toMeasure_apply : p.toOuterMeasure s ≤ p.toMeasure s := le_toMeasure_apply p.toOuterMeasure _ s @@ -333,8 +333,7 @@ instance toMeasure.isProbabilityMeasure [MeasurableSpace α] (p : PMF α) : simpa only [MeasurableSet.univ, toMeasure_apply_eq_toOuterMeasure_apply, Set.indicator_univ, toOuterMeasure_apply, ENNReal.coe_eq_one] using tsum_coe p⟩ -variable [Countable α] [MeasurableSpace α] [MeasurableSingletonClass α] (p : PMF α) (μ : Measure α) - [IsProbabilityMeasure μ] +variable [Countable α] [MeasurableSpace α] [MeasurableSingletonClass α] (p : PMF α) @[simp] theorem toMeasure_toPMF : p.toMeasure.toPMF = p := diff --git a/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean b/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean index 165c6a9ec6008..bb40a90012017 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Joachim Breitner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joachim Breitner -/ +import Mathlib.Data.Nat.Choose.Sum import Mathlib.Probability.ProbabilityMassFunction.Constructions import Mathlib.Tactic.FinCases diff --git a/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean b/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean index 9ae6765fb79bd..71cc19f51f1b7 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean @@ -32,7 +32,7 @@ noncomputable section variable {α β γ : Type*} open scoped Classical -open NNReal ENNReal +open NNReal ENNReal Finset MeasureTheory section Map @@ -82,13 +82,19 @@ variable (s : Set β) theorem toOuterMeasure_map_apply : (p.map f).toOuterMeasure s = p.toOuterMeasure (f ⁻¹' s) := by simp [map, Set.indicator, toOuterMeasure_apply p (f ⁻¹' s)] +variable {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + @[simp] -theorem toMeasure_map_apply [MeasurableSpace α] [MeasurableSpace β] (hf : Measurable f) +theorem toMeasure_map_apply (hf : Measurable f) (hs : MeasurableSet s) : (p.map f).toMeasure s = p.toMeasure (f ⁻¹' s) := by rw [toMeasure_apply_eq_toOuterMeasure_apply _ s hs, toMeasure_apply_eq_toOuterMeasure_apply _ (f ⁻¹' s) (measurableSet_preimage hf hs)] exact toOuterMeasure_map_apply f p s +@[simp] +lemma toMeasure_map (p : PMF α) (hf : Measurable f) : p.toMeasure.map f = (p.map f).toMeasure := by + ext s hs : 1; rw [PMF.toMeasure_map_apply _ _ _ hf hs, Measure.map_apply hf hs] + end Measure end Map @@ -123,7 +129,7 @@ instance : LawfulFunctor PMF where comp_map _ _ _ := (map_comp _ _ _).symm instance : LawfulMonad PMF := LawfulMonad.mk' - (bind_pure_comp := fun f x => rfl) + (bind_pure_comp := fun _ _ => rfl) (id_map := id_map) (pure_bind := pure_bind) (bind_assoc := bind_bind) @@ -185,6 +191,14 @@ theorem support_ofFintype : (ofFintype f h).support = Function.support f := rfl theorem mem_support_ofFintype_iff (a : α) : a ∈ (ofFintype f h).support ↔ f a ≠ 0 := Iff.rfl +@[simp] +lemma map_ofFintype [Fintype β] (f : α → ℝ≥0∞) (h : ∑ a, f a = 1) (g : α → β) : + (ofFintype f h).map g = ofFintype (fun b ↦ ∑ a with g a = b, f a) + (by simpa [Finset.sum_fiberwise_eq_sum_filter univ univ g f]) := by + ext b : 1 + simp only [sum_filter, eq_comm, map_apply, ofFintype_apply] + exact tsum_eq_sum fun _ h ↦ (h <| mem_univ _).elim + section Measure variable (s : Set α) @@ -247,7 +261,7 @@ theorem support_filter : (p.filter s h).support = s ∩ p.support := Set.ext fun _ => mem_support_filter_iff _ theorem filter_apply_eq_zero_iff (a : α) : (p.filter s h) a = 0 ↔ a ∉ s ∨ a ∉ p.support := by - erw [apply_eq_zero_iff, support_filter, Set.mem_inter_iff, not_and_or] + rw [apply_eq_zero_iff, support_filter, Set.mem_inter_iff, not_and_or] theorem filter_apply_ne_zero_iff (a : α) : (p.filter s h) a ≠ 0 ↔ a ∈ s ∧ a ∈ p.support := by rw [Ne, filter_apply_eq_zero_iff, not_or, Classical.not_not, Classical.not_not] diff --git a/Mathlib/Probability/ProbabilityMassFunction/Monad.lean b/Mathlib/Probability/ProbabilityMassFunction/Monad.lean index 31a9cbfa903d1..acf07b214fb38 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Monad.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Monad.lean @@ -48,7 +48,6 @@ theorem support_pure : (pure a).support = {a} := theorem mem_support_pure_iff : a' ∈ (pure a).support ↔ a' = a := by simp --- @[simp] -- Porting note (#10618): simp can prove this theorem pure_apply_self : pure a a = 1 := if_pos rfl @@ -156,7 +155,7 @@ theorem toOuterMeasure_bind_apply : _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := tsum_congr fun b => by split_ifs <;> simp _ = ∑' (a) (b), p a * if b ∈ s then f a b else 0 := (tsum_comm' ENNReal.summable (fun _ => ENNReal.summable) fun _ => ENNReal.summable) - _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := tsum_congr fun a => ENNReal.tsum_mul_left + _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := tsum_congr fun _ => ENNReal.tsum_mul_left _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := (tsum_congr fun a => (congr_arg fun x => p a * x) <| tsum_congr fun b => by split_ifs <;> rfl) _ = ∑' a, p a * (f a).toOuterMeasure s := diff --git a/Mathlib/Probability/Process/Filtration.lean b/Mathlib/Probability/Process/Filtration.lean index eaa870240f64e..853bae3ead907 100644 --- a/Mathlib/Probability/Process/Filtration.lean +++ b/Mathlib/Probability/Process/Filtration.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Kexing Ying. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kexing Ying, Rémy Degenne -/ +import Mathlib.MeasureTheory.Constructions.Cylinders import Mathlib.MeasureTheory.Function.ConditionalExpectation.Real /-! @@ -156,19 +157,19 @@ theorem sInf_def (s : Set (Filtration ι m)) (i : ι) : noncomputable instance instCompleteLattice : CompleteLattice (Filtration ι m) where le := (· ≤ ·) - le_refl f i := le_rfl - le_trans f g h h_fg h_gh i := (h_fg i).trans (h_gh i) - le_antisymm f g h_fg h_gf := Filtration.ext <| funext fun i => (h_fg i).antisymm (h_gf i) + le_refl _ _ := le_rfl + le_trans _ _ _ h_fg h_gh i := (h_fg i).trans (h_gh i) + le_antisymm _ _ h_fg h_gf := Filtration.ext <| funext fun i => (h_fg i).antisymm (h_gf i) sup := (· ⊔ ·) - le_sup_left f g i := le_sup_left - le_sup_right f g i := le_sup_right - sup_le f g h h_fh h_gh i := sup_le (h_fh i) (h_gh _) + le_sup_left _ _ _ := le_sup_left + le_sup_right _ _ _ := le_sup_right + sup_le _ _ _ h_fh h_gh i := sup_le (h_fh i) (h_gh _) inf := (· ⊓ ·) - inf_le_left f g i := inf_le_left - inf_le_right f g i := inf_le_right - le_inf f g h h_fg h_fh i := le_inf (h_fg i) (h_fh i) + inf_le_left _ _ _ := inf_le_left + inf_le_right _ _ _ := inf_le_right + le_inf _ _ _ h_fg h_fh i := le_inf (h_fg i) (h_fh i) sSup := sSup - le_sSup s f hf_mem i := le_sSup ⟨f, hf_mem, rfl⟩ + le_sSup _ f hf_mem _ := le_sSup ⟨f, hf_mem, rfl⟩ sSup_le s f h_forall i := sSup_le fun m' hm' => by obtain ⟨g, hg_mem, hfm'⟩ := hm' @@ -188,7 +189,7 @@ noncomputable instance instCompleteLattice : CompleteLattice (Filtration ι m) w top := ⊤ bot := ⊥ le_top f i := f.le' i - bot_le f i := bot_le + bot_le _ _ := bot_le end Filtration @@ -247,7 +248,7 @@ of σ-algebras such that that sequence of functions is measurable with respect t the filtration. -/ def natural (u : ι → Ω → β) (hum : ∀ i, StronglyMeasurable (u i)) : Filtration ι m where seq i := ⨆ j ≤ i, MeasurableSpace.comap (u j) mβ - mono' i j hij := biSup_mono fun k => ge_trans hij + mono' _ _ hij := biSup_mono fun _ => ge_trans hij le' i := by refine iSup₂_le ?_ rintro j _ s ⟨t, ht, rfl⟩ @@ -328,6 +329,14 @@ alias memℒp_limitProcess_of_snorm_bdd := memℒp_limitProcess_of_eLpNorm_bdd end Limit +variable {α : Type*} + +/-- The exterior σ-algebras of finite sets of `α` form a cofiltration indexed by `Finset α`. -/ +def cylinderEventsCompl : Filtration (Finset α)ᵒᵈ (.pi (π := fun _ : α ↦ Ω)) where + seq Λ := cylinderEvents (↑(OrderDual.ofDual Λ))ᶜ + mono' _ _ h := cylinderEvents_mono <| Set.compl_subset_compl_of_subset h + le' _ := cylinderEvents_le_pi + end Filtration end MeasureTheory diff --git a/Mathlib/Probability/Process/HittingTime.lean b/Mathlib/Probability/Process/HittingTime.lean index 161d19118807f..4cf0ce22da61f 100644 --- a/Mathlib/Probability/Process/HittingTime.lean +++ b/Mathlib/Probability/Process/HittingTime.lean @@ -260,7 +260,7 @@ theorem isStoppingTime_hitting_isStoppingTime [ConditionallyCompleteLinearOrder section CompleteLattice -variable [CompleteLattice ι] {u : ι → Ω → β} {s : Set β} {f : Filtration ι m} +variable [CompleteLattice ι] {u : ι → Ω → β} {s : Set β} theorem hitting_eq_sInf (ω : Ω) : hitting u s ⊥ ⊤ ω = sInf {i : ι | u i ω ∈ s} := by simp only [hitting, Set.mem_Icc, bot_le, le_top, and_self_iff, exists_true_left, Set.Icc_bot, @@ -276,7 +276,7 @@ end CompleteLattice section ConditionallyCompleteLinearOrderBot variable [ConditionallyCompleteLinearOrderBot ι] [IsWellOrder ι (· < ·)] -variable {u : ι → Ω → β} {s : Set β} {f : Filtration ℕ m} +variable {u : ι → Ω → β} {s : Set β} theorem hitting_bot_le_iff {i n : ι} {ω : Ω} (hx : ∃ j, j ≤ n ∧ u j ω ∈ s) : hitting u s ⊥ n ω ≤ i ↔ ∃ j ≤ i, u j ω ∈ s := by diff --git a/Mathlib/Probability/Process/Stopping.lean b/Mathlib/Probability/Process/Stopping.lean index 0b6419fc37ae6..40bf2069437c8 100644 --- a/Mathlib/Probability/Process/Stopping.lean +++ b/Mathlib/Probability/Process/Stopping.lean @@ -245,8 +245,8 @@ protected theorem min_const [LinearOrder ι] {f : Filtration ι m} {τ : Ω → (hτ : IsStoppingTime f τ) (i : ι) : IsStoppingTime f fun ω => min (τ ω) i := hτ.min (isStoppingTime_const f i) -theorem add_const [AddGroup ι] [Preorder ι] [CovariantClass ι ι (Function.swap (· + ·)) (· ≤ ·)] - [CovariantClass ι ι (· + ·) (· ≤ ·)] {f : Filtration ι m} {τ : Ω → ι} (hτ : IsStoppingTime f τ) +theorem add_const [AddGroup ι] [Preorder ι] [AddRightMono ι] + [AddLeftMono ι] {f : Filtration ι m} {τ : Ω → ι} (hτ : IsStoppingTime f τ) {i : ι} (hi : 0 ≤ i) : IsStoppingTime f fun ω => τ ω + i := by intro j simp_rw [← le_sub_iff_add_le] @@ -387,8 +387,7 @@ theorem measurableSet_inter_eq_iff (hτ : IsStoppingTime f τ) (s : Set Ω) (i : by_cases hij : i ≤ j · simp only [hij, Set.setOf_true, Set.inter_univ] exact f.mono hij _ h - · set_option tactic.skipAssignedInstances false in simp [hij] - convert @MeasurableSet.empty _ (Filtration.seq f j) + · simp [hij] theorem measurableSpace_le_of_le_const (hτ : IsStoppingTime f τ) {i : ι} (hτ_le : ∀ ω, τ ω ≤ i) : hτ.measurableSpace ≤ f i := @@ -805,7 +804,7 @@ end LinearOrder section StoppedValueOfMemFinset -variable {μ : Measure Ω} {τ σ : Ω → ι} {E : Type*} {p : ℝ≥0∞} {u : ι → Ω → E} +variable {μ : Measure Ω} {τ : Ω → ι} {E : Type*} {p : ℝ≥0∞} {u : ι → Ω → E} theorem stoppedValue_eq_of_mem_finset [AddCommMonoid E] {s : Finset ι} (hbdd : ∀ ω, τ ω ∈ s) : stoppedValue u τ = ∑ i ∈ s, Set.indicator {ω | τ ω = i} (u i) := by @@ -956,7 +955,7 @@ section Nat open Filtration -variable {f : Filtration ℕ m} {u : ℕ → Ω → β} {τ π : Ω → ℕ} +variable {u : ℕ → Ω → β} {τ π : Ω → ℕ} theorem stoppedValue_sub_eq_sum [AddCommGroup β] (hle : τ ≤ π) : stoppedValue u π - stoppedValue u τ = fun ω => diff --git a/Mathlib/Probability/StrongLaw.lean b/Mathlib/Probability/StrongLaw.lean index 34d9233a9272f..4158b48564a82 100644 --- a/Mathlib/Probability/StrongLaw.lean +++ b/Mathlib/Probability/StrongLaw.lean @@ -420,8 +420,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : exact (hident j).aestronglyMeasurable_fst.memℒp_truncation · intro k _ l _ hkl exact (hindep hkl).comp (A k).measurable (A l).measurable - _ = ∑ j ∈ range (u (N - 1)), - (∑ i ∈ (range N).filter fun i => j < u i, ((u i : ℝ) ^ 2)⁻¹) * Var[Y j] := by + _ = ∑ j ∈ range (u (N - 1)), (∑ i ∈ range N with j < u i, ((u i : ℝ) ^ 2)⁻¹) * Var[Y j] := by simp_rw [mul_sum, sum_mul, sum_sigma'] refine sum_nbij' (fun p ↦ ⟨p.2, p.1⟩) (fun p ↦ ⟨p.2, p.1⟩) ?_ ?_ ?_ ?_ ?_ · simp only [mem_sigma, mem_range, filter_congr_decidable, mem_filter, and_imp, @@ -603,10 +602,12 @@ identically distributed integrable real-valued random variables, then `∑ i ∈ converges almost surely to `𝔼[X 0]`. We give here the strong version, due to Etemadi, that only requires pairwise independence. Superseded by `strong_law_ae`, which works for random variables taking values in any Banach space. -/ -theorem strong_law_ae_real {Ω : Type*} [MeasureSpace Ω] - (X : ℕ → Ω → ℝ) (hint : Integrable (X 0)) - (hindep : Pairwise fun i j => IndepFun (X i) (X j)) (hident : ∀ i, IdentDistrib (X i) (X 0)) : - ∀ᵐ ω, Tendsto (fun n : ℕ => (∑ i ∈ range n, X i ω) / n) atTop (𝓝 𝔼[X 0]) := by +theorem strong_law_ae_real {Ω : Type*} {m : MeasurableSpace Ω} {μ : Measure Ω} + (X : ℕ → Ω → ℝ) (hint : Integrable (X 0) μ) + (hindep : Pairwise fun i j => IndepFun (X i) (X j) μ) + (hident : ∀ i, IdentDistrib (X i) (X 0) μ μ) : + ∀ᵐ ω ∂μ, Tendsto (fun n : ℕ => (∑ i ∈ range n, X i ω) / n) atTop (𝓝 (μ [X 0])) := by + let mΩ : MeasureSpace Ω := ⟨μ⟩ -- first get rid of the trivial case where the space is not a probability space by_cases h : ∀ᵐ ω, X 0 ω = 0 · have I : ∀ᵐ ω, ∀ i, X i ω = 0 := by @@ -615,7 +616,7 @@ theorem strong_law_ae_real {Ω : Type*} [MeasureSpace Ω] exact (hident i).symm.ae_snd (p := fun x ↦ x = 0) measurableSet_eq h filter_upwards [I] with ω hω simpa [hω] using (integral_eq_zero_of_ae h).symm - have : IsProbabilityMeasure (ℙ : Measure Ω) := + have : IsProbabilityMeasure μ := hint.isProbabilityMeasure_of_indepFun (X 0) (X 1) h (hindep zero_ne_one) -- then consider separately the positive and the negative part, and apply the result -- for nonnegative functions to them. @@ -630,17 +631,17 @@ theorem strong_law_ae_real {Ω : Type*} [MeasureSpace Ω] strong_law_aux7 _ hint.neg_part (fun i j hij => (hindep hij).comp negm negm) (fun i => (hident i).comp negm) fun i ω => le_max_right _ _ filter_upwards [A, B] with ω hωpos hωneg - convert hωpos.sub hωneg using 1 + 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] + Function.comp_apply, mΩ] end StrongLawAeReal section StrongLawVectorSpace -variable {Ω : Type*} [MeasureSpace Ω] [IsProbabilityMeasure (ℙ : Measure Ω)] +variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {μ : Measure Ω} [IsProbabilityMeasure μ] {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] [MeasurableSpace E] @@ -650,22 +651,23 @@ open Set TopologicalSpace the composition of the random variables with a simple function satisfies the strong law of large numbers. -/ lemma strong_law_ae_simpleFunc_comp (X : ℕ → Ω → E) (h' : Measurable (X 0)) - (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j))) (hident : ∀ i, IdentDistrib (X i) (X 0)) - (φ : SimpleFunc E E) : ∀ᵐ ω, - Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, φ (X i ω))) atTop (𝓝 𝔼[φ ∘ (X 0)]) := by + (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j) μ)) + (hident : ∀ i, IdentDistrib (X i) (X 0) μ μ) (φ : SimpleFunc E E) : + ∀ᵐ ω ∂μ, + Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, φ (X i ω))) atTop (𝓝 (μ [φ ∘ (X 0)])) := by -- this follows from the one-dimensional version when `φ` takes a single value, and is then -- extended to the general case by linearity. classical - refine SimpleFunc.induction (P := fun ψ ↦ ∀ᵐ ω, - Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, ψ (X i ω))) atTop (𝓝 𝔼[ψ ∘ (X 0)])) ?_ ?_ φ + refine SimpleFunc.induction (P := fun ψ ↦ ∀ᵐ ω ∂μ, + Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, ψ (X i ω))) atTop (𝓝 (μ [ψ ∘ (X 0)]))) ?_ ?_ φ · intro c s hs simp only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_const, SimpleFunc.coe_zero, piecewise_eq_indicator, Function.comp_apply] let F : E → ℝ := indicator s 1 have F_meas : Measurable F := (measurable_indicator_const_iff 1).2 hs let Y : ℕ → Ω → ℝ := fun n ↦ F ∘ (X n) - have : ∀ᵐ (ω : Ω), Tendsto (fun (n : ℕ) ↦ (n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y i ω) - atTop (𝓝 𝔼[Y 0]) := by + have : ∀ᵐ (ω : Ω) ∂μ, Tendsto (fun (n : ℕ) ↦ (n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y i ω) + atTop (𝓝 (μ [Y 0])) := by simp only [Function.const_one, smul_eq_mul, ← div_eq_inv_mul] apply strong_law_ae_real · exact SimpleFunc.integrable_of_isFiniteMeasure @@ -699,9 +701,10 @@ variable [BorelSpace E] assuming measurability in addition to integrability. This is weakened to ae measurability in the full version `ProbabilityTheory.strong_law_ae`. -/ lemma strong_law_ae_of_measurable - (X : ℕ → Ω → E) (hint : Integrable (X 0)) (h' : StronglyMeasurable (X 0)) - (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j))) (hident : ∀ i, IdentDistrib (X i) (X 0)) : - ∀ᵐ ω, Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) atTop (𝓝 𝔼[X 0]) := by + (X : ℕ → Ω → E) (hint : Integrable (X 0) μ) (h' : StronglyMeasurable (X 0)) + (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j) μ)) + (hident : ∀ i, IdentDistrib (X i) (X 0) μ μ) : + ∀ᵐ ω ∂μ, Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) atTop (𝓝 (μ [X 0])) := by /- Choose a simple function `φ` such that `φ (X 0)` approximates well enough `X 0` -- this is possible as `X 0` is strongly measurable. Then `φ (X n)` approximates well `X n`. Then the strong law for `φ (X n)` implies the strong law for `X n`, up to a small @@ -717,12 +720,12 @@ lemma strong_law_ae_of_measurable SimpleFunc.nearestPt (fun k => Nat.casesOn k 0 ((↑) ∘ denseSeq s) : ℕ → E) let Y : ℕ → ℕ → Ω → E := fun k i ↦ (φ k) ∘ (X i) -- strong law for `φ (X n)` - have A : ∀ᵐ ω, ∀ k, - Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, Y k i ω)) atTop (𝓝 𝔼[Y k 0]) := + have A : ∀ᵐ ω ∂μ, ∀ k, + Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, Y k i ω)) atTop (𝓝 (μ [Y k 0])) := ae_all_iff.2 (fun k ↦ strong_law_ae_simpleFunc_comp X h'.measurable hindep hident (φ k)) -- strong law for the error `‖X i - φ (X i)‖` - have B : ∀ᵐ ω, ∀ k, Tendsto (fun n : ℕ ↦ (∑ i ∈ range n, ‖(X i - Y k i) ω‖) / n) - atTop (𝓝 𝔼[(fun ω ↦ ‖(X 0 - Y k 0) ω‖)]) := by + have B : ∀ᵐ ω ∂μ, ∀ k, Tendsto (fun n : ℕ ↦ (∑ i ∈ range n, ‖(X i - Y k i) ω‖) / n) + atTop (𝓝 (μ [(fun ω ↦ ‖(X 0 - Y k 0) ω‖)])) := by apply ae_all_iff.2 (fun k ↦ ?_) let G : ℕ → E → ℝ := fun k x ↦ ‖x - φ k x‖ have G_meas : ∀ k, Measurable (G k) := @@ -745,33 +748,33 @@ lemma strong_law_ae_of_measurable obtain ⟨δ, δpos, hδ⟩ : ∃ δ, 0 < δ ∧ δ + δ + δ < ε := ⟨ε/4, by positivity, by linarith⟩ -- choose `k` large enough so that `φₖ (X 0)` approximates well enough `X 0`, up to the -- precision `δ`. - obtain ⟨k, hk⟩ : ∃ k, ∫ ω, ‖(X 0 - Y k 0) ω‖ < δ := by + obtain ⟨k, hk⟩ : ∃ k, ∫ ω, ‖(X 0 - Y k 0) ω‖ ∂μ < δ := by simp_rw [Pi.sub_apply, norm_sub_rev (X 0 _)] exact ((tendsto_order.1 (tendsto_integral_norm_approxOn_sub h'.measurable hint)).2 δ δpos).exists - have : ‖𝔼[Y k 0] - 𝔼[X 0]‖ < δ := by + have : ‖μ [Y k 0] - μ [X 0]‖ < δ := by rw [norm_sub_rev, ← integral_sub hint] · exact (norm_integral_le_integral_norm _).trans_lt hk · exact ((φ k).comp (X 0) h'.measurable).integrable_of_isFiniteMeasure -- consider `n` large enough for which the above convergences have taken place within `δ`. have I : ∀ᶠ n in atTop, (∑ i ∈ range n, ‖(X i - Y k i) ω‖) / n < δ := (tendsto_order.1 (h'ω k)).2 δ hk - have J : ∀ᶠ (n : ℕ) in atTop, ‖(n : ℝ) ⁻¹ • (∑ i ∈ range n, Y k i ω) - 𝔼[Y k 0]‖ < δ := by + have J : ∀ᶠ (n : ℕ) in atTop, ‖(n : ℝ) ⁻¹ • (∑ i ∈ range n, Y k i ω) - μ [Y k 0]‖ < δ := by specialize hω k rw [tendsto_iff_norm_sub_tendsto_zero] at hω exact (tendsto_order.1 hω).2 δ δpos filter_upwards [I, J] with n hn h'n -- at such an `n`, the strong law is realized up to `ε`. calc - ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, X i ω - 𝔼[X 0]‖ + ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, X i ω - μ [X 0]‖ = ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, (X i ω - Y k i ω) + - ((n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y k i ω - 𝔼[Y k 0]) + (𝔼[Y k 0] - 𝔼[X 0])‖ := by + ((n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y k i ω - μ [Y k 0]) + (μ [Y k 0] - μ [X 0])‖ := by congr simp only [Function.comp_apply, sum_sub_distrib, smul_sub] abel _ ≤ ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, (X i ω - Y k i ω)‖ + - ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y k i ω - 𝔼[Y k 0]‖ + ‖𝔼[Y k 0] - 𝔼[X 0]‖ := - norm_add₃_le _ _ _ + ‖(n : ℝ)⁻¹ • ∑ i ∈ Finset.range n, Y k i ω - μ [Y k 0]‖ + ‖μ [Y k 0] - μ [X 0]‖ := + norm_add₃_le _ ≤ (∑ i ∈ Finset.range n, ‖X i ω - Y k i ω‖) / n + δ + δ := by gcongr simp only [Function.comp_apply, norm_smul, norm_inv, RCLike.norm_natCast, @@ -783,37 +786,39 @@ lemma strong_law_ae_of_measurable exact hn.le _ < ε := hδ +omit [IsProbabilityMeasure μ] in /-- **Strong law of large numbers**, almost sure version: if `X n` is a sequence of independent identically distributed integrable random variables taking values in a Banach space, then `n⁻¹ • ∑ i ∈ range n, X i` converges almost surely to `𝔼[X 0]`. We give here the strong version, due to Etemadi, that only requires pairwise independence. -/ -theorem strong_law_ae {Ω : Type*} [MeasureSpace Ω] - (X : ℕ → Ω → E) (hint : Integrable (X 0)) - (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j))) (hident : ∀ i, IdentDistrib (X i) (X 0)) : - ∀ᵐ ω, Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) atTop (𝓝 𝔼[X 0]) := by +theorem strong_law_ae (X : ℕ → Ω → E) (hint : Integrable (X 0) μ) + (hindep : Pairwise (fun i j ↦ IndepFun (X i) (X j) μ)) + (hident : ∀ i, IdentDistrib (X i) (X 0) μ μ) : + ∀ᵐ ω ∂μ, Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) atTop (𝓝 (μ [X 0])) := by -- First exclude the trivial case where the space is not a probability space - by_cases h : ∀ᵐ ω, X 0 ω = 0 - · have I : ∀ᵐ ω, ∀ i, X i ω = 0 := by + by_cases h : ∀ᵐ ω ∂μ, X 0 ω = 0 + · have I : ∀ᵐ ω ∂μ, ∀ i, X i ω = 0 := by rw [ae_all_iff] intro i exact (hident i).symm.ae_snd (p := fun x ↦ x = 0) measurableSet_eq h filter_upwards [I] with ω hω simpa [hω] using (integral_eq_zero_of_ae h).symm - have : IsProbabilityMeasure (ℙ : Measure Ω) := + have : IsProbabilityMeasure μ := hint.isProbabilityMeasure_of_indepFun (X 0) (X 1) h (hindep zero_ne_one) -- we reduce to the case of strongly measurable random variables, by using `Y i` which is strongly -- measurable and ae equal to `X i`. - have A : ∀ i, Integrable (X i) := fun i ↦ (hident i).integrable_iff.2 hint + have A : ∀ i, Integrable (X i) μ := fun i ↦ (hident i).integrable_iff.2 hint let Y : ℕ → Ω → E := fun i ↦ (A i).1.mk (X i) - have B : ∀ᵐ ω, ∀ n, X n ω = Y n ω := + have B : ∀ᵐ ω ∂μ, ∀ n, X n ω = Y n ω := ae_all_iff.2 (fun i ↦ AEStronglyMeasurable.ae_eq_mk (A i).1) - have Yint : Integrable (Y 0) := Integrable.congr hint (AEStronglyMeasurable.ae_eq_mk (A 0).1) - have C : ∀ᵐ ω, Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, Y i ω)) atTop (𝓝 𝔼[Y 0]) := by + have Yint : Integrable (Y 0) μ := Integrable.congr hint (AEStronglyMeasurable.ae_eq_mk (A 0).1) + have C : ∀ᵐ ω ∂μ, + Tendsto (fun n : ℕ ↦ (n : ℝ) ⁻¹ • (∑ i ∈ range n, Y i ω)) atTop (𝓝 (μ [Y 0])) := by apply strong_law_ae_of_measurable Y Yint ((A 0).1.stronglyMeasurable_mk) (fun i j hij ↦ IndepFun.ae_eq (hindep hij) (A i).1.ae_eq_mk (A j).1.ae_eq_mk) (fun i ↦ ((A i).1.identDistrib_mk.symm.trans (hident i)).trans (A 0).1.identDistrib_mk) filter_upwards [B, C] with ω h₁ h₂ - have : 𝔼[X 0] = 𝔼[Y 0] := integral_congr_ae (AEStronglyMeasurable.ae_eq_mk (A 0).1) + have : μ [X 0] = μ [Y 0] := integral_congr_ae (AEStronglyMeasurable.ae_eq_mk (A 0).1) rw [this] apply Tendsto.congr (fun n ↦ ?_) h₂ congr with i @@ -823,39 +828,39 @@ end StrongLawVectorSpace section StrongLawLp -variable {Ω : Type*} [MeasureSpace Ω] +variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {μ : Measure Ω} {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] [MeasurableSpace E] [BorelSpace E] /-- **Strong law of large numbers**, Lᵖ version: if `X n` is a sequence of independent identically distributed random variables in Lᵖ, then `n⁻¹ • ∑ i ∈ range n, X i` converges in `Lᵖ` to `𝔼[X 0]`. -/ -theorem strong_law_Lp {p : ℝ≥0∞} (hp : 1 ≤ p) (hp' : p ≠ ∞) (X : ℕ → Ω → E) (hℒp : Memℒp (X 0) p) - (hindep : Pairwise fun i j => IndepFun (X i) (X j)) (hident : ∀ i, IdentDistrib (X i) (X 0)) : - Tendsto (fun (n : ℕ) => eLpNorm (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω) - 𝔼[X 0]) p) +theorem strong_law_Lp {p : ℝ≥0∞} (hp : 1 ≤ p) (hp' : p ≠ ∞) (X : ℕ → Ω → E) + (hℒp : Memℒp (X 0) p μ) (hindep : Pairwise fun i j => IndepFun (X i) (X j) μ) + (hident : ∀ i, IdentDistrib (X i) (X 0) μ μ) : + Tendsto (fun (n : ℕ) => eLpNorm (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω) - μ [X 0]) p μ) atTop (𝓝 0) := by -- First exclude the trivial case where the space is not a probability space - by_cases h : ∀ᵐ ω, X 0 ω = 0 - · have I : ∀ᵐ ω, ∀ i, X i ω = 0 := by + by_cases h : ∀ᵐ ω ∂μ, X 0 ω = 0 + · have I : ∀ᵐ ω ∂μ, ∀ i, X i ω = 0 := by rw [ae_all_iff] intro i exact (hident i).symm.ae_snd (p := fun x ↦ x = 0) measurableSet_eq h - have A (n : ℕ) : eLpNorm (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω) - 𝔼[X 0]) p ℙ = 0 := by + have A (n : ℕ) : eLpNorm (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω) - μ [X 0]) p μ = 0 := by simp only [integral_eq_zero_of_ae h, sub_zero] apply eLpNorm_eq_zero_of_ae_zero filter_upwards [I] with ω hω simp [hω] simp [A] -- Then use ae convergence and uniform integrability - have : IsProbabilityMeasure (ℙ : Measure Ω) := Memℒp.isProbabilityMeasure_of_indepFun + have : IsProbabilityMeasure μ := Memℒp.isProbabilityMeasure_of_indepFun (X 0) (X 1) (zero_lt_one.trans_le hp).ne' hp' hℒp h (hindep zero_ne_one) - have hmeas : ∀ i, AEStronglyMeasurable (X i) ℙ := fun i => + have hmeas : ∀ i, AEStronglyMeasurable (X i) μ := fun i => (hident i).aestronglyMeasurable_iff.2 hℒp.1 - have hint : Integrable (X 0) ℙ := hℒp.integrable hp - have havg : ∀ (n : ℕ), - AEStronglyMeasurable (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) ℙ := by - intro n - exact AEStronglyMeasurable.const_smul (aestronglyMeasurable_sum _ fun i _ => hmeas i) _ + have hint : Integrable (X 0) μ := hℒp.integrable hp + have havg (n : ℕ) : + AEStronglyMeasurable (fun ω => (n : ℝ) ⁻¹ • (∑ i ∈ range n, X i ω)) μ := + AEStronglyMeasurable.const_smul (aestronglyMeasurable_sum _ fun i _ => hmeas i) _ refine tendsto_Lp_finite_of_tendstoInMeasure hp hp' havg (memℒp_const _) ?_ (tendstoInMeasure_of_tendsto_ae havg (strong_law_ae _ hint hindep hident)) rw [(_ : (fun (n : ℕ) ω => (n : ℝ)⁻¹ • (∑ i ∈ range n, X i ω)) diff --git a/Mathlib/Probability/UniformOn.lean b/Mathlib/Probability/UniformOn.lean new file mode 100644 index 0000000000000..524e33e17554c --- /dev/null +++ b/Mathlib/Probability/UniformOn.lean @@ -0,0 +1,244 @@ +/- +Copyright (c) 2022 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying, Bhavik Mehta +-/ +import Mathlib.Probability.ConditionalProbability +import Mathlib.MeasureTheory.Measure.Count + +/-! +# Classical probability + +The classical formulation of probability states that the probability of an event occurring in a +finite probability space is the ratio of that event to all possible events. +This notion can be expressed with measure theory using +the counting measure. In particular, given the sets `s` and `t`, we define the probability of `t` +occurring in `s` to be `|s|⁻¹ * |s ∩ t|`. With this definition, we recover the probability over +the entire sample space when `s = Set.univ`. + +Classical probability is often used in combinatorics and we prove some useful lemmas in this file +for that purpose. + +## Main definition + +* `ProbabilityTheory.uniformOn`: given a set `s`, `uniformOn s` is the counting measure + conditioned on `s`. This is a probability measure when `s` is finite and nonempty. + +## Notes + +The original aim of this file is to provide a measure theoretic method of describing the +probability an element of a set `s` satisfies some predicate `P`. Our current formulation still +allow us to describe this by abusing the definitional equality of sets and predicates by simply +writing `uniformOn s P`. We should avoid this however as none of the lemmas are written for +predicates. +-/ + + +noncomputable section + +open ProbabilityTheory + +open MeasureTheory MeasurableSpace + +namespace ProbabilityTheory + +variable {Ω : Type*} [MeasurableSpace Ω] + +/-- Given a set `s`, `uniformOn s` is the uniform measure on `s`, defined as the counting measure +conditioned by `s`. One should think of `uniformOn s t` as the proportion of `s` that is contained +in `t`. + +This is a probability measure when `s` is finite and nonempty and is given by +`ProbabilityTheory.uniformOn_isProbabilityMeasure`. -/ +def uniformOn (s : Set Ω) : Measure Ω := + Measure.count[|s] + +@[deprecated (since := "2024-10-09")] +noncomputable alias condCount := uniformOn + +instance {s : Set Ω} : IsZeroOrProbabilityMeasure (uniformOn s) := by + unfold uniformOn; infer_instance + +@[simp] +theorem uniformOn_empty_meas : (uniformOn ∅ : Measure Ω) = 0 := by simp [uniformOn] + +@[deprecated (since := "2024-10-09")] +alias condCount_empty_meas := uniformOn_empty_meas + +theorem uniformOn_empty {s : Set Ω} : uniformOn s ∅ = 0 := by simp + +@[deprecated (since := "2024-10-09")] +alias condCount_empty := uniformOn_empty + +theorem finite_of_uniformOn_ne_zero {s t : Set Ω} (h : uniformOn s t ≠ 0) : s.Finite := by + by_contra hs' + simp [uniformOn, cond, Measure.count_apply_infinite hs'] at h + +@[deprecated (since := "2024-10-09")] +alias finite_of_condCount_ne_zero := finite_of_uniformOn_ne_zero + +theorem uniformOn_univ [Fintype Ω] {s : Set Ω} : + uniformOn Set.univ s = Measure.count s / Fintype.card Ω := by + rw [uniformOn, cond_apply MeasurableSet.univ, ← ENNReal.div_eq_inv_mul, Set.univ_inter] + congr + rw [← Finset.coe_univ, Measure.count_apply, Finset.univ.tsum_subtype' fun _ => (1 : ENNReal)] + · simp [Finset.card_univ] + · exact (@Finset.coe_univ Ω _).symm ▸ MeasurableSet.univ + +@[deprecated (since := "2024-10-09")] +alias condCount_univ := uniformOn_univ + +variable [MeasurableSingletonClass Ω] + +theorem uniformOn_isProbabilityMeasure {s : Set Ω} (hs : s.Finite) (hs' : s.Nonempty) : + IsProbabilityMeasure (uniformOn s) := by + apply cond_isProbabilityMeasure_of_finite + · exact fun h => hs'.ne_empty <| Measure.empty_of_count_eq_zero h + · exact (Measure.count_apply_lt_top.2 hs).ne + +@[deprecated (since := "2024-10-09")] +alias condCount_isProbabilityMeasure := uniformOn_isProbabilityMeasure + +theorem uniformOn_singleton (ω : Ω) (t : Set Ω) [Decidable (ω ∈ t)] : + uniformOn {ω} t = if ω ∈ t then 1 else 0 := by + rw [uniformOn, cond_apply (measurableSet_singleton ω), Measure.count_singleton, inv_one, + one_mul] + split_ifs + · rw [(by simpa : ({ω} : Set Ω) ∩ t = {ω}), Measure.count_singleton] + · rw [(by simpa : ({ω} : Set Ω) ∩ t = ∅), Measure.count_empty] + +@[deprecated (since := "2024-10-09")] +alias condCount_singleton := uniformOn_singleton + +variable {s t u : Set Ω} + +theorem uniformOn_inter_self (hs : s.Finite) : uniformOn s (s ∩ t) = uniformOn s t := by + rw [uniformOn, cond_inter_self hs.measurableSet] + +@[deprecated (since := "2024-10-09")] +alias condCount_inter_self := uniformOn_inter_self + +theorem uniformOn_self (hs : s.Finite) (hs' : s.Nonempty) : uniformOn s s = 1 := by + rw [uniformOn, cond_apply hs.measurableSet, Set.inter_self, ENNReal.inv_mul_cancel] + · exact fun h => hs'.ne_empty <| Measure.empty_of_count_eq_zero h + · exact (Measure.count_apply_lt_top.2 hs).ne + +@[deprecated (since := "2024-10-09")] +alias condCount_self := uniformOn_self + +theorem uniformOn_eq_one_of (hs : s.Finite) (hs' : s.Nonempty) (ht : s ⊆ t) : + uniformOn s t = 1 := by + haveI := uniformOn_isProbabilityMeasure hs hs' + refine eq_of_le_of_not_lt prob_le_one ?_ + rw [not_lt, ← uniformOn_self hs hs'] + exact measure_mono ht + +@[deprecated (since := "2024-10-09")] +alias condCount_eq_one_of := uniformOn_eq_one_of + +theorem pred_true_of_uniformOn_eq_one (h : uniformOn s t = 1) : s ⊆ t := by + have hsf := finite_of_uniformOn_ne_zero (by rw [h]; exact one_ne_zero) + rw [uniformOn, cond_apply hsf.measurableSet, mul_comm] at h + replace h := ENNReal.eq_inv_of_mul_eq_one_left h + rw [inv_inv, Measure.count_apply_finite _ hsf, Measure.count_apply_finite _ (hsf.inter_of_left _), + Nat.cast_inj] at h + suffices s ∩ t = s by exact this ▸ fun x hx => hx.2 + rw [← @Set.Finite.toFinset_inj _ _ _ (hsf.inter_of_left _) hsf] + exact Finset.eq_of_subset_of_card_le (Set.Finite.toFinset_mono s.inter_subset_left) h.ge + +@[deprecated (since := "2024-10-09")] +alias pred_true_of_condCount_eq_one := pred_true_of_uniformOn_eq_one + +theorem uniformOn_eq_zero_iff (hs : s.Finite) : uniformOn s t = 0 ↔ s ∩ t = ∅ := by + simp [uniformOn, cond_apply hs.measurableSet, Measure.count_apply_eq_top, Set.not_infinite.2 hs, + Measure.count_apply_finite _ (hs.inter_of_left _)] + +@[deprecated (since := "2024-10-09")] +alias condCount_eq_zero_iff := uniformOn_eq_zero_iff + +theorem uniformOn_of_univ (hs : s.Finite) (hs' : s.Nonempty) : uniformOn s Set.univ = 1 := + uniformOn_eq_one_of hs hs' s.subset_univ + +@[deprecated (since := "2024-10-09")] +alias condCount_of_univ := uniformOn_of_univ + +theorem uniformOn_inter (hs : s.Finite) : + uniformOn s (t ∩ u) = uniformOn (s ∩ t) u * uniformOn s t := by + by_cases hst : s ∩ t = ∅ + · rw [hst, uniformOn_empty_meas, Measure.coe_zero, Pi.zero_apply, zero_mul, + uniformOn_eq_zero_iff hs, ← Set.inter_assoc, hst, Set.empty_inter] + rw [uniformOn, uniformOn, cond_apply hs.measurableSet, cond_apply hs.measurableSet, + cond_apply (hs.inter_of_left _).measurableSet, mul_comm _ (Measure.count (s ∩ t)), + ← mul_assoc, mul_comm _ (Measure.count (s ∩ t)), ← mul_assoc, ENNReal.mul_inv_cancel, one_mul, + mul_comm, Set.inter_assoc] + · rwa [← Measure.count_eq_zero_iff] at hst + · exact (Measure.count_apply_lt_top.2 <| hs.inter_of_left _).ne + +@[deprecated (since := "2024-10-09")] +alias condCount_inter := uniformOn_inter + +theorem uniformOn_inter' (hs : s.Finite) : + uniformOn s (t ∩ u) = uniformOn (s ∩ u) t * uniformOn s u := by + rw [← Set.inter_comm] + exact uniformOn_inter hs + +@[deprecated (since := "2024-10-09")] +alias condCount_inter' := uniformOn_inter' + +theorem uniformOn_union (hs : s.Finite) (htu : Disjoint t u) : + uniformOn s (t ∪ u) = uniformOn s t + uniformOn s u := by + rw [uniformOn, cond_apply hs.measurableSet, cond_apply hs.measurableSet, + cond_apply hs.measurableSet, Set.inter_union_distrib_left, measure_union, mul_add] + exacts [htu.mono inf_le_right inf_le_right, (hs.inter_of_left _).measurableSet] + +@[deprecated (since := "2024-10-09")] +alias condCount_union := uniformOn_union + +theorem uniformOn_compl (t : Set Ω) (hs : s.Finite) (hs' : s.Nonempty) : + uniformOn s t + uniformOn s tᶜ = 1 := by + rw [← uniformOn_union hs disjoint_compl_right, Set.union_compl_self, + (uniformOn_isProbabilityMeasure hs hs').measure_univ] + +@[deprecated (since := "2024-10-09")] +alias condCount_compl := uniformOn_compl + +theorem uniformOn_disjoint_union (hs : s.Finite) (ht : t.Finite) (hst : Disjoint s t) : + uniformOn s u * uniformOn (s ∪ t) s + uniformOn t u * uniformOn (s ∪ t) t = + uniformOn (s ∪ t) u := by + rcases s.eq_empty_or_nonempty with (rfl | hs') <;> rcases t.eq_empty_or_nonempty with (rfl | ht') + · simp + · simp [uniformOn_self ht ht'] + · simp [uniformOn_self hs hs'] + rw [uniformOn, uniformOn, uniformOn, cond_apply hs.measurableSet, + cond_apply ht.measurableSet, cond_apply (hs.union ht).measurableSet, + cond_apply (hs.union ht).measurableSet, cond_apply (hs.union ht).measurableSet] + conv_lhs => + rw [Set.union_inter_cancel_left, Set.union_inter_cancel_right, + mul_comm (Measure.count (s ∪ t))⁻¹, mul_comm (Measure.count (s ∪ t))⁻¹, ← mul_assoc, + ← mul_assoc, mul_comm _ (Measure.count s), mul_comm _ (Measure.count t), ← mul_assoc, + ← mul_assoc] + rw [ENNReal.mul_inv_cancel, ENNReal.mul_inv_cancel, one_mul, one_mul, ← add_mul, ← measure_union, + Set.union_inter_distrib_right, mul_comm] + exacts [hst.mono inf_le_left inf_le_left, (ht.inter_of_left _).measurableSet, + Measure.count_ne_zero ht', (Measure.count_apply_lt_top.2 ht).ne, Measure.count_ne_zero hs', + (Measure.count_apply_lt_top.2 hs).ne] + +@[deprecated (since := "2024-10-09")] +alias condCount_disjoint_union := uniformOn_disjoint_union + +/-- A version of the law of total probability for counting probabilities. -/ +theorem uniformOn_add_compl_eq (u t : Set Ω) (hs : s.Finite) : + uniformOn (s ∩ u) t * uniformOn s u + uniformOn (s ∩ uᶜ) t * uniformOn s uᶜ = + uniformOn s t := by + -- Porting note: The original proof used `conv_rhs`. However, that tactic timed out. + have : uniformOn s t = (uniformOn (s ∩ u) t * uniformOn (s ∩ u ∪ s ∩ uᶜ) (s ∩ u) + + uniformOn (s ∩ uᶜ) t * uniformOn (s ∩ u ∪ s ∩ uᶜ) (s ∩ uᶜ)) := by + rw [uniformOn_disjoint_union (hs.inter_of_left _) (hs.inter_of_left _) + (disjoint_compl_right.mono inf_le_right inf_le_right), Set.inter_union_compl] + rw [this] + simp [uniformOn_inter_self hs] + +@[deprecated (since := "2024-10-09")] +alias condCount_add_compl_eq := uniformOn_add_compl_eq + +end ProbabilityTheory diff --git a/Mathlib/Probability/Variance.lean b/Mathlib/Probability/Variance.lean index 9b0a9bcb2fe5c..00263fc96ac34 100644 --- a/Mathlib/Probability/Variance.lean +++ b/Mathlib/Probability/Variance.lean @@ -30,9 +30,12 @@ We define the variance of a real-valued random variable as `Var[X] = 𝔼[(X - random variables is the sum of the variances. * `ProbabilityTheory.IndepFun.variance_sum`: the variance of a finite sum of pairwise independent random variables is the sum of the variances. +* `ProbabilityTheory.variance_le_sub_mul_sub`: the variance of a random variable `X` satisfying + `a ≤ X ≤ b` almost everywhere is at most `(b - 𝔼 X) * (𝔼 X - a)`. +* `ProbabilityTheory.variance_le_sq_of_bounded`: the variance of a random variable `X` satisfying + `a ≤ X ≤ b` almost everywhere is at most`((b - a) / 2) ^ 2`. -/ - open MeasureTheory Filter Finset noncomputable section @@ -178,44 +181,42 @@ theorem variance_smul' {A : Type*} [CommSemiring A] [Algebra A ℝ] (c : A) (X : scoped notation "Var[" X "]" => ProbabilityTheory.variance X MeasureTheory.MeasureSpace.volume -variable [MeasureSpace Ω] - -theorem variance_def' [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → ℝ} (hX : Memℒp X 2) : - Var[X] = 𝔼[X ^ 2] - 𝔼[X] ^ 2 := by +theorem variance_def' [IsProbabilityMeasure μ] {X : Ω → ℝ} (hX : Memℒp X 2 μ) : + variance X μ = μ[X ^ 2] - μ[X] ^ 2 := by rw [hX.variance_eq, sub_sq', integral_sub', integral_add']; rotate_left · exact hX.integrable_sq - · convert @integrable_const Ω ℝ (_) ℙ _ _ (𝔼[X] ^ 2) + · apply integrable_const · apply hX.integrable_sq.add - convert @integrable_const Ω ℝ (_) ℙ _ _ (𝔼[X] ^ 2) + apply integrable_const · exact ((hX.integrable one_le_two).const_mul 2).mul_const' _ simp only [Pi.pow_apply, integral_const, measure_univ, ENNReal.one_toReal, smul_eq_mul, one_mul, Pi.mul_apply, Pi.ofNat_apply, Nat.cast_ofNat, integral_mul_right, integral_mul_left] ring -theorem variance_le_expectation_sq [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → ℝ} - (hm : AEStronglyMeasurable X ℙ) : Var[X] ≤ 𝔼[X ^ 2] := by - by_cases hX : Memℒp X 2 +theorem variance_le_expectation_sq [IsProbabilityMeasure μ] {X : Ω → ℝ} + (hm : AEStronglyMeasurable X μ) : variance X μ ≤ μ[X ^ 2] := by + by_cases hX : Memℒp X 2 μ · rw [variance_def' hX] simp only [sq_nonneg, sub_le_self_iff] rw [variance, evariance_eq_lintegral_ofReal, ← integral_eq_lintegral_of_nonneg_ae] - · by_cases hint : Integrable X; swap + · by_cases hint : Integrable X μ; swap · simp only [integral_undef hint, Pi.pow_apply, Pi.sub_apply, sub_zero] exact le_rfl · rw [integral_undef] · exact integral_nonneg fun a => sq_nonneg _ intro h - have A : Memℒp (X - fun ω : Ω => 𝔼[X]) 2 ℙ := + have A : Memℒp (X - fun ω : Ω => μ[X]) 2 μ := (memℒp_two_iff_integrable_sq (hint.aestronglyMeasurable.sub aestronglyMeasurable_const)).2 h - have B : Memℒp (fun _ : Ω => 𝔼[X]) 2 ℙ := memℒp_const _ + have B : Memℒp (fun _ : Ω => μ[X]) 2 μ := memℒp_const _ apply hX convert A.add B simp · exact Eventually.of_forall fun x => sq_nonneg _ · exact (AEMeasurable.pow_const (hm.aemeasurable.sub_const _) _).aestronglyMeasurable -theorem evariance_def' [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → ℝ} (hX : AEStronglyMeasurable X ℙ) : - eVar[X] = (∫⁻ ω, (‖X ω‖₊ ^ 2 :)) - ENNReal.ofReal (𝔼[X] ^ 2) := by - by_cases hℒ : Memℒp X 2 +theorem evariance_def' [IsProbabilityMeasure μ] {X : Ω → ℝ} (hX : AEStronglyMeasurable X μ) : + evariance X μ = (∫⁻ ω, (‖X ω‖₊ ^ 2 :) ∂μ) - ENNReal.ofReal (μ[X] ^ 2) := by + by_cases hℒ : Memℒp X 2 μ · rw [← hℒ.ofReal_variance_eq, variance_def' hℒ, ENNReal.ofReal_sub _ (sq_nonneg _)] congr rw [lintegral_coe_eq_integral] @@ -233,11 +234,11 @@ theorem evariance_def' [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → ℝ} (hX : A exact mod_cast hℒ fun _ => zero_le_two /-- **Chebyshev's inequality** for `ℝ≥0∞`-valued variance. -/ -theorem meas_ge_le_evariance_div_sq {X : Ω → ℝ} (hX : AEStronglyMeasurable X ℙ) {c : ℝ≥0} - (hc : c ≠ 0) : ℙ {ω | ↑c ≤ |X ω - 𝔼[X]|} ≤ eVar[X] / c ^ 2 := by +theorem meas_ge_le_evariance_div_sq {X : Ω → ℝ} (hX : AEStronglyMeasurable X μ) {c : ℝ≥0} + (hc : c ≠ 0) : μ {ω | ↑c ≤ |X ω - μ[X]|} ≤ evariance X μ / c ^ 2 := by have A : (c : ℝ≥0∞) ≠ 0 := by rwa [Ne, ENNReal.coe_eq_zero] - have B : AEStronglyMeasurable (fun _ : Ω => 𝔼[X]) ℙ := aestronglyMeasurable_const - convert meas_ge_le_mul_pow_eLpNorm ℙ two_ne_zero ENNReal.two_ne_top (hX.sub B) A using 1 + have B : AEStronglyMeasurable (fun _ : Ω => μ[X]) μ := aestronglyMeasurable_const + convert meas_ge_le_mul_pow_eLpNorm μ two_ne_zero ENNReal.two_ne_top (hX.sub B) A using 1 · congr simp only [Pi.sub_apply, ENNReal.coe_le_coe, ← Real.norm_eq_abs, ← coe_nnnorm, NNReal.coe_le_coe, ENNReal.ofReal_coe_nnreal] @@ -251,22 +252,22 @@ theorem meas_ge_le_evariance_div_sq {X : Ω → ℝ} (hX : AEStronglyMeasurable /-- **Chebyshev's inequality**: one can control the deviation probability of a real random variable from its expectation in terms of the variance. -/ -theorem meas_ge_le_variance_div_sq [@IsFiniteMeasure Ω _ ℙ] {X : Ω → ℝ} (hX : Memℒp X 2) {c : ℝ} - (hc : 0 < c) : ℙ {ω | c ≤ |X ω - 𝔼[X]|} ≤ ENNReal.ofReal (Var[X] / c ^ 2) := by +theorem meas_ge_le_variance_div_sq [IsFiniteMeasure μ] {X : Ω → ℝ} (hX : Memℒp X 2 μ) {c : ℝ} + (hc : 0 < c) : μ {ω | c ≤ |X ω - μ[X]|} ≤ ENNReal.ofReal (variance X μ / c ^ 2) := by rw [ENNReal.ofReal_div_of_pos (sq_pos_of_ne_zero hc.ne.symm), hX.ofReal_variance_eq] - convert @meas_ge_le_evariance_div_sq _ _ _ hX.1 c.toNNReal (by simp [hc]) using 1 + convert @meas_ge_le_evariance_div_sq _ _ _ _ hX.1 c.toNNReal (by simp [hc]) using 1 · simp only [Real.coe_toNNReal', max_le_iff, abs_nonneg, and_true] · rw [ENNReal.ofReal_pow hc.le] rfl -- Porting note: supplied `MeasurableSpace Ω` argument of `h` by unification /-- The variance of the sum of two independent random variables is the sum of the variances. -/ -theorem IndepFun.variance_add [@IsProbabilityMeasure Ω _ ℙ] {X Y : Ω → ℝ} (hX : Memℒp X 2) - (hY : Memℒp Y 2) (h : @IndepFun _ _ _ (_) _ _ X Y ℙ) : Var[X + Y] = Var[X] + Var[Y] := +theorem IndepFun.variance_add [IsProbabilityMeasure μ] {X Y : Ω → ℝ} (hX : Memℒp X 2 μ) + (hY : Memℒp Y 2 μ) (h : IndepFun X Y μ) : variance (X + Y) μ = variance X μ + variance Y μ := calc - Var[X + Y] = 𝔼[fun a => X a ^ 2 + Y a ^ 2 + 2 * X a * Y a] - 𝔼[X + Y] ^ 2 := by + variance (X + Y) μ = μ[fun a => X a ^ 2 + Y a ^ 2 + 2 * X a * Y a] - μ[X + Y] ^ 2 := by simp [variance_def' (hX.add hY), add_sq'] - _ = 𝔼[X ^ 2] + 𝔼[Y ^ 2] + (2 : ℝ) * 𝔼[X * Y] - (𝔼[X] + 𝔼[Y]) ^ 2 := by + _ = μ[X ^ 2] + μ[Y ^ 2] + (2 : ℝ) * μ[X * Y] - (μ[X] + μ[Y]) ^ 2 := by simp only [Pi.add_apply, Pi.pow_apply, Pi.mul_apply, mul_assoc] rw [integral_add, integral_add, integral_add, integral_mul_left] · exact hX.integrable one_le_two @@ -276,27 +277,27 @@ theorem IndepFun.variance_add [@IsProbabilityMeasure Ω _ ℙ] {X Y : Ω → ℝ · exact hX.integrable_sq.add hY.integrable_sq · apply Integrable.const_mul exact h.integrable_mul (hX.integrable one_le_two) (hY.integrable one_le_two) - _ = 𝔼[X ^ 2] + 𝔼[Y ^ 2] + 2 * (𝔼[X] * 𝔼[Y]) - (𝔼[X] + 𝔼[Y]) ^ 2 := by + _ = μ[X ^ 2] + μ[Y ^ 2] + 2 * (μ[X] * μ[Y]) - (μ[X] + μ[Y]) ^ 2 := by congr exact h.integral_mul_of_integrable (hX.integrable one_le_two) (hY.integrable one_le_two) - _ = Var[X] + Var[Y] := by simp only [variance_def', hX, hY, Pi.pow_apply]; ring + _ = variance X μ + variance Y μ := by simp only [variance_def', hX, hY, Pi.pow_apply]; ring -- Porting note: supplied `MeasurableSpace Ω` argument of `hs`, `h` by unification /-- The variance of a finite sum of pairwise independent random variables is the sum of the variances. -/ -theorem IndepFun.variance_sum [@IsProbabilityMeasure Ω _ ℙ] {ι : Type*} {X : ι → Ω → ℝ} - {s : Finset ι} (hs : ∀ i ∈ s, @Memℒp _ _ _ (_) (X i) 2 ℙ) - (h : Set.Pairwise ↑s fun i j => @IndepFun _ _ _ (_) _ _ (X i) (X j) ℙ) : - Var[∑ i ∈ s, X i] = ∑ i ∈ s, Var[X i] := by +theorem IndepFun.variance_sum [IsProbabilityMeasure μ] {ι : Type*} {X : ι → Ω → ℝ} + {s : Finset ι} (hs : ∀ i ∈ s, Memℒp (X i) 2 μ) + (h : Set.Pairwise ↑s fun i j => IndepFun (X i) (X j) μ) : + variance (∑ i ∈ s, X i) μ = ∑ i ∈ s, variance (X i) μ := by classical induction' s using Finset.induction_on with k s ks IH · simp only [Finset.sum_empty, variance_zero] rw [variance_def' (memℒp_finset_sum' _ hs), sum_insert ks, sum_insert ks] simp only [add_sq'] calc - 𝔼[X k ^ 2 + (∑ i ∈ s, X i) ^ 2 + 2 * X k * ∑ i ∈ s, X i] - 𝔼[X k + ∑ i ∈ s, X i] ^ 2 = - 𝔼[X k ^ 2] + 𝔼[(∑ i ∈ s, X i) ^ 2] + 𝔼[2 * X k * ∑ i ∈ s, X i] - - (𝔼[X k] + 𝔼[∑ i ∈ s, X i]) ^ 2 := by + μ[(X k ^ 2 + (∑ i ∈ s, X i) ^ 2 + 2 * X k * ∑ i ∈ s, X i : Ω → ℝ)] - μ[X k + ∑ i ∈ s, X i] ^ 2 = + μ[X k ^ 2] + μ[(∑ i ∈ s, X i) ^ 2] + μ[2 * X k * ∑ i ∈ s, X i] - + (μ[X k] + μ[∑ i ∈ s, X i]) ^ 2 := by rw [integral_add', integral_add', integral_add'] · exact Memℒp.integrable one_le_two (hs _ (mem_insert_self _ _)) · apply integrable_finset_sum' _ fun i hi => ?_ @@ -316,12 +317,12 @@ theorem IndepFun.variance_sum [@IsProbabilityMeasure Ω _ ℙ] {ι : Type*} {X : (Memℒp.integrable one_le_two (hs _ (mem_insert_of_mem hi))) apply h (mem_insert_self _ _) (mem_insert_of_mem hi) exact fun hki => ks (hki.symm ▸ hi) - _ = Var[X k] + Var[∑ i ∈ s, X i] + - (𝔼[2 * X k * ∑ i ∈ s, X i] - 2 * 𝔼[X k] * 𝔼[∑ i ∈ s, X i]) := by + _ = variance (X k) μ + variance (∑ i ∈ s, X i) μ + + (μ[2 * X k * ∑ i ∈ s, X i] - 2 * μ[X k] * μ[∑ i ∈ s, X i]) := by rw [variance_def' (hs _ (mem_insert_self _ _)), variance_def' (memℒp_finset_sum' _ fun i hi => hs _ (mem_insert_of_mem hi))] ring - _ = Var[X k] + Var[∑ i ∈ s, X i] := by + _ = variance (X k) μ + variance (∑ i ∈ s, X i) μ := by simp_rw [Pi.mul_apply, Pi.ofNat_apply, Nat.cast_ofNat, sum_apply, mul_sum, mul_assoc, add_right_eq_self] rw [integral_finset_sum s fun i hi => ?_]; swap @@ -339,8 +340,53 @@ theorem IndepFun.variance_sum [@IsProbabilityMeasure Ω _ ℙ] {ι : Type*} {X : exact fun hki => ks (hki.symm ▸ hi) · exact Memℒp.aestronglyMeasurable (hs _ (mem_insert_self _ _)) · exact Memℒp.aestronglyMeasurable (hs _ (mem_insert_of_mem hi)) - _ = Var[X k] + ∑ i ∈ s, Var[X i] := by + _ = variance (X k) μ + ∑ i ∈ s, variance (X i) μ := by rw [IH (fun i hi => hs i (mem_insert_of_mem hi)) (h.mono (by simp only [coe_insert, Set.subset_insert]))] +/-- **The Bhatia-Davis inequality on variance** + +The variance of a random variable `X` satisfying `a ≤ X ≤ b` almost everywhere is at most +`(b - 𝔼 X) * (𝔼 X - a)`. -/ +lemma variance_le_sub_mul_sub [IsProbabilityMeasure μ] {a b : ℝ} {X : Ω → ℝ} + (h : ∀ᵐ ω ∂μ, X ω ∈ Set.Icc a b) (hX : AEMeasurable X μ) : + variance X μ ≤ (b - μ[X]) * (μ[X] - a) := by + have ha : ∀ᵐ ω ∂μ, a ≤ X ω := h.mono fun ω h => h.1 + have hb : ∀ᵐ ω ∂μ, X ω ≤ b := h.mono fun ω h => h.2 + have hX_int₂ : Integrable (fun ω ↦ -X ω ^ 2) μ := + (memℒp_of_bounded h hX.aestronglyMeasurable 2).integrable_sq.neg + have hX_int₁ : Integrable (fun ω ↦ (a + b) * X ω) μ := + ((integrable_const (max |a| |b|)).mono' hX.aestronglyMeasurable + (by filter_upwards [ha, hb] with ω using abs_le_max_abs_abs)).const_mul (a + b) + have h0 : 0 ≤ - μ[X ^ 2] + (a + b) * μ[X] - a * b := + calc + _ ≤ ∫ ω, (b - X ω) * (X ω - a) ∂μ := by + apply integral_nonneg_of_ae + filter_upwards [ha, hb] with ω ha' hb' + exact mul_nonneg (by linarith : 0 ≤ b - X ω) (by linarith : 0 ≤ X ω - a) + _ = ∫ ω, - X ω ^ 2 + (a + b) * X ω - a * b ∂μ := + integral_congr_ae <| ae_of_all μ fun ω ↦ by ring + _ = ∫ ω, - X ω ^ 2 + (a + b) * X ω ∂μ - ∫ _, a * b ∂μ := + integral_sub (hX_int₂.add hX_int₁) (integrable_const (a * b)) + _ = ∫ ω, - X ω ^ 2 + (a + b) * X ω ∂μ - a * b := by simp + _ = - μ[X ^ 2] + (a + b) * μ[X] - a * b := by + simp [← integral_neg, ← integral_mul_left, integral_add hX_int₂ hX_int₁] + calc + _ ≤ (a + b) * μ[X] - a * b - μ[X] ^ 2 := by + rw [variance_def' (memℒp_of_bounded h hX.aestronglyMeasurable 2)] + linarith + _ = (b - μ[X]) * (μ[X] - a) := by ring + +/-- **Popoviciu's inequality on variance** + +The variance of a random variable `X` satisfying `a ≤ X ≤ b` almost everywhere is at most +`((b - a) / 2) ^ 2`. -/ +lemma variance_le_sq_of_bounded [IsProbabilityMeasure μ] {a b : ℝ} {X : Ω → ℝ} + (h : ∀ᵐ ω ∂μ, X ω ∈ Set.Icc a b) (hX : AEMeasurable X μ) : + variance X μ ≤ ((b - a) / 2) ^ 2 := + calc + _ ≤ (b - μ[X]) * (μ[X] - a) := variance_le_sub_mul_sub h hX + _ = ((b - a) / 2) ^ 2 - (μ[X] - (b + a) / 2) ^ 2 := by ring + _ ≤ ((b - a) / 2) ^ 2 := sub_le_self _ (sq_nonneg _) + end ProbabilityTheory diff --git a/Mathlib/RepresentationTheory/Action/Basic.lean b/Mathlib/RepresentationTheory/Action/Basic.lean index e09c00af54f4e..2f15639455bdf 100644 --- a/Mathlib/RepresentationTheory/Action/Basic.lean +++ b/Mathlib/RepresentationTheory/Action/Basic.lean @@ -16,7 +16,7 @@ import Mathlib.CategoryTheory.Conj The prototypical example is `V = ModuleCat R`, where `Action (ModuleCat R) G` is the category of `R`-linear representations of `G`. -We check `Action V G ≌ (singleObj G ⥤ V)`, +We check `Action V G ≌ (CategoryTheory.singleObj G ⥤ V)`, and construct the restriction functors `res {G H : MonCat} (f : G ⟶ H) : Action V H ⥤ Action V G`. -/ @@ -111,7 +111,6 @@ instance : Category (Action V G) where id M := Hom.id M comp f g := Hom.comp f g --- Porting note: added because `Hom.ext` is not triggered automatically @[ext] lemma hom_ext {M N : Action V G} (φ₁ φ₂ : M ⟶ N) (h : φ₁.hom = φ₂.hom) : φ₁ = φ₂ := Hom.ext h @@ -196,7 +195,7 @@ def unitIso : 𝟭 (Action V G) ≅ functor ⋙ inverse := /-- Auxiliary definition for `functorCategoryEquivalence`. -/ @[simps!] def counitIso : inverse ⋙ functor ≅ 𝟭 (SingleObj G ⥤ V) := - NatIso.ofComponents fun M => NatIso.ofComponents fun X => Iso.refl _ + NatIso.ofComponents fun M => NatIso.ofComponents fun _ => Iso.refl _ end FunctorCategoryEquivalence @@ -284,7 +283,7 @@ def actionPunitEquivalence : Action V (MonCat.of PUnit) ≌ V where simp only [MonCat.oneHom_apply, MonCat.one_of, End.one_def, id_eq, Functor.comp_obj, forget_obj, Iso.refl_hom, Category.comp_id] exact ρ_one X - counitIso := NatIso.ofComponents fun X => Iso.refl _ + counitIso := NatIso.ofComponents fun _ => Iso.refl _ variable (V) diff --git a/Mathlib/RepresentationTheory/Action/Concrete.lean b/Mathlib/RepresentationTheory/Action/Concrete.lean index e2ebc3a42dff7..16750cee24335 100644 --- a/Mathlib/RepresentationTheory/Action/Concrete.lean +++ b/Mathlib/RepresentationTheory/Action/Concrete.lean @@ -6,7 +6,7 @@ Authors: Kim Morrison import Mathlib.Algebra.Group.Action.Pi import Mathlib.CategoryTheory.FintypeCat import Mathlib.GroupTheory.GroupAction.Quotient -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.RepresentationTheory.Action.Basic /-! @@ -38,7 +38,7 @@ def ofMulActionLimitCone {ι : Type v} (G : Type max v u) [Monoid G] (F : ι → LimitCone (Discrete.functor fun i : ι => Action.ofMulAction G (F i)) where cone := { pt := Action.ofMulAction G (∀ i : ι, F i) - π := Discrete.natTrans (fun i => ⟨fun x => x i.as, fun g => rfl⟩) } + π := Discrete.natTrans (fun i => ⟨fun x => x i.as, fun _ => rfl⟩) } isLimit := { lift := fun s => { hom := fun x i => (s.π.app ⟨i⟩).hom x @@ -46,7 +46,7 @@ def ofMulActionLimitCone {ι : Type v} (G : Type max v u) [Monoid G] (F : ι → ext x funext j exact congr_fun ((s.π.app ⟨j⟩).comm g) x } - fac := fun s j => rfl + fac := fun _ _ => rfl uniq := fun s f h => by ext x funext j @@ -149,7 +149,7 @@ lemma quotientToEndHom_mk [N.Normal] (x : H) (g : G) : /-- If `N` and `H` are subgroups of a group `G` with `N ≤ H`, this is the canonical `G`-morphism `G ⧸ N ⟶ G ⧸ H`. -/ def quotientToQuotientOfLE [Fintype (G ⧸ H)] (h : N ≤ H) : (G ⧸ₐ N) ⟶ (G ⧸ₐ H) where - hom := Quotient.lift _ <| fun a b hab ↦ Quotient.sound <| + hom := Quotient.lift _ <| fun _ _ hab ↦ Quotient.sound <| (QuotientGroup.leftRel_apply).mpr (h <| (QuotientGroup.leftRel_apply).mp hab) comm g := by ext (x : G ⧸ N) diff --git a/Mathlib/RepresentationTheory/Action/Monoidal.lean b/Mathlib/RepresentationTheory/Action/Monoidal.lean index e9ebdc2e143b1..3eecdddcbe909 100644 --- a/Mathlib/RepresentationTheory/Action/Monoidal.lean +++ b/Mathlib/RepresentationTheory/Action/Monoidal.lean @@ -71,7 +71,7 @@ variable (V G) def forgetMonoidal : MonoidalFunctor (Action V G) V := { toFunctor := Action.forget _ _ ε := 𝟙 _ - μ := fun X Y => 𝟙 _ } + μ := fun _ _ => 𝟙 _ } instance forgetMonoidal_faithful : (forgetMonoidal V G).Faithful := by change (forget V G).Faithful; infer_instance @@ -245,7 +245,7 @@ noncomputable def leftRegularTensorIso (G : Type u) [Group G] (X : Action (Type dsimp -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [leftRegular_ρ_apply] - erw [map_mul] + rw [map_mul] rfl } hom_inv_id := by apply Hom.ext diff --git a/Mathlib/RepresentationTheory/Basic.lean b/Mathlib/RepresentationTheory/Basic.lean index 979151b7da507..ec67d8f8cb669 100644 --- a/Mathlib/RepresentationTheory/Basic.lean +++ b/Mathlib/RepresentationTheory/Basic.lean @@ -13,11 +13,10 @@ representations. ## Main definitions - * Representation.Representation - * Representation.character - * Representation.tprod - * Representation.linHom - * Representation.dual + * `Representation` + * `Representation.tprod` + * `Representation.linHom` + * `Representation.dual` ## Implementation notes @@ -26,7 +25,7 @@ homomorphisms `G →* (V →ₗ[k] V)`. We use the abbreviation `Representation` The theorem `asAlgebraHom_def` constructs a module over the group `k`-algebra of `G` (implemented as `MonoidAlgebra k G`) corresponding to a representation. If `ρ : Representation k G V`, this -module can be accessed via `ρ.asModule`. Conversely, given a `MonoidAlgebra k G-module `M` +module can be accessed via `ρ.asModule`. Conversely, given a `MonoidAlgebra k G`-module `M`, `M.ofModule` is the associociated representation seen as a homomorphism. -/ @@ -449,7 +448,7 @@ theorem dual_apply (g : G) : (dual ρV) g = Module.Dual.transpose (R := k) (ρV rfl /-- Given $k$-modules $V, W$, there is a homomorphism $φ : V^* ⊗ W → Hom_k(V, W)$ -(implemented by `LinearAlgebra.Contraction.dualTensorHom`). +(implemented by `dualTensorHom` in `Mathlib.LinearAlgebra.Contraction`). Given representations of $G$ on $V$ and $W$,there are representations of $G$ on $V^* ⊗ W$ and on $Hom_k(V, W)$. This lemma says that $φ$ is $G$-linear. diff --git a/Mathlib/RepresentationTheory/Character.lean b/Mathlib/RepresentationTheory/Character.lean index b629a2dc92e8b..5479f9417977f 100644 --- a/Mathlib/RepresentationTheory/Character.lean +++ b/Mathlib/RepresentationTheory/Character.lean @@ -19,8 +19,8 @@ is the theorem `char_orthonormal` ## Implementation notes -Irreducible representations are implemented categorically, using the `Simple` class defined in -`Mathlib.CategoryTheory.Simple` +Irreducible representations are implemented categorically, using the `CategoryTheory.Simple` class +defined in `Mathlib.CategoryTheory.Simple` ## TODO * Once we have the monoidal closed structure on `FdRep k G` and a better API for the rigid @@ -89,7 +89,7 @@ variable [Fintype G] [Invertible (Fintype.card G : k)] theorem average_char_eq_finrank_invariants (V : FDRep k G) : ⅟ (Fintype.card G : k) • ∑ g : G, V.character g = finrank k (invariants V.ρ) := by - erw [← (isProj_averageMap V.ρ).trace] -- Porting note: Changed `rw` to `erw` + rw [← (isProj_averageMap V.ρ).trace] simp [character, GroupAlgebra.average, _root_.map_sum] end Group diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean index d12b7df3e9055..4e6c54c0981d0 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean @@ -30,8 +30,8 @@ $\mathrm{H}^n(G, A) \cong \mathrm{Ext}^n(k, A),$ where $\mathrm{Ext}$ is taken i `Rep k G`. To talk about cohomology in low degree, please see the file -`RepresentationTheory.GroupCohomology.LowDegree`, which gives simpler expressions for `H⁰, H¹, H²` -than the definition `groupCohomology` in this file. +`Mathlib.RepresentationTheory.GroupCohomology.LowDegree`, which gives simpler expressions for +`H⁰`, `H¹`, `H²` than the definition `groupCohomology` in this file. ## Main definitions @@ -146,8 +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 - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [diagonalHomEquiv_apply, Action.comp_hom, ModuleCat.comp_def, LinearMap.comp_apply, + rw [diagonalHomEquiv_apply, Action.comp_hom, ModuleCat.comp_def, LinearMap.comp_apply, resolution.d_eq] erw [resolution.d_of (Fin.partialProd g)] simp only [map_sum, ← Finsupp.smul_single_one _ ((-1 : k) ^ _)] diff --git a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean index 2b83e2348e8b1..e5fead4c21a6d 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean @@ -2,7 +2,6 @@ Copyright (c) 2023 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston, Joël Riou - -/ import Mathlib.Algebra.Homology.ShortComplex.ModuleCat import Mathlib.RepresentationTheory.GroupCohomology.Basic @@ -99,7 +98,7 @@ def dZero : A →ₗ[k] G → A where theorem dZero_ker_eq_invariants : LinearMap.ker (dZero A) = invariants A.ρ := by ext x - simp only [LinearMap.mem_ker, mem_invariants, ← @sub_eq_zero _ _ _ x, Function.funext_iff] + simp only [LinearMap.mem_ker, mem_invariants, ← @sub_eq_zero _ _ _ x, funext_iff] rfl @[simp] theorem dZero_eq_zero [A.IsTrivial] : dZero A = 0 := by @@ -202,9 +201,9 @@ theorem dOne_comp_dZero : dOne A ∘ₗ dZero A = 0 := by rfl theorem dTwo_comp_dOne : dTwo A ∘ₗ dOne A = 0 := by - show ModuleCat.ofHom (dOne A) ≫ ModuleCat.ofHom (dTwo A) = _ - have h1 : _ ≫ ModuleCat.ofHom (dOne A) = _ ≫ _ := congr_arg ModuleCat.ofHom (dOne_comp_eq A) - have h2 : _ ≫ ModuleCat.ofHom (dTwo A) = _ ≫ _ := congr_arg ModuleCat.ofHom (dTwo_comp_eq A) + 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] @@ -227,7 +226,7 @@ variable {A} theorem mem_oneCocycles_def (f : G → A) : f ∈ oneCocycles A ↔ ∀ g h : G, A.ρ g (f h) - f (g * h) + f g = 0 := LinearMap.mem_ker.trans <| by - rw [Function.funext_iff] + rw [funext_iff] simp only [dOne_apply, Pi.zero_apply, Prod.forall] theorem mem_oneCocycles_iff (f : G → A) : @@ -264,8 +263,8 @@ group homs `G → A`. -/ { toFun := f.1 ∘ Additive.toMul map_zero' := oneCocycles_map_one f map_add' := oneCocycles_map_mul_of_isTrivial f } - map_add' x y := rfl - map_smul' r x := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl invFun f := { val := f property := mem_oneCocycles_of_addMonoidHom f } @@ -278,7 +277,7 @@ theorem mem_twoCocycles_def (f : G × G → A) : f ∈ twoCocycles A ↔ ∀ g h j : G, A.ρ g (f (h, j)) - f (g * h, j) + f (g, h * j) - f (g, h) = 0 := LinearMap.mem_ker.trans <| by - rw [Function.funext_iff] + rw [funext_iff] simp only [dTwo_apply, Prod.mk.eta, Pi.zero_apply, Prod.forall] theorem mem_twoCocycles_iff (f : G × G → A) : @@ -492,7 +491,7 @@ def twoCoboundariesOfIsTwoCoboundary {f : G × G → A} (hf : IsTwoCoboundary f) theorem isTwoCoboundary_of_twoCoboundaries (f : twoCoboundaries (Rep.ofDistribMulAction k G A)) : IsTwoCoboundary (A := A) f.1.1 := by rcases mem_range_of_mem_twoCoboundaries f.2 with ⟨x, hx⟩ - exact ⟨x, fun g h => Function.funext_iff.1 hx (g, h)⟩ + exact ⟨x, fun g h => funext_iff.1 hx (g, h)⟩ end ofDistribMulAction @@ -617,7 +616,7 @@ theorem isMulTwoCoboundary_of_twoCoboundaries (f : twoCoboundaries (Rep.ofMulDistribMulAction G M)) : IsMulTwoCoboundary (M := M) (Additive.toMul ∘ f.1.1) := by rcases mem_range_of_mem_twoCoboundaries f.2 with ⟨x, hx⟩ - exact ⟨x, fun g h => Function.funext_iff.1 hx (g, h)⟩ + exact ⟨x, fun g h => funext_iff.1 hx (g, h)⟩ end ofMulDistribMulAction @@ -716,7 +715,7 @@ 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.ofHom (dZero A)) := + Arrow.mk (ModuleCat.asHom (dZero A)) := Arrow.isoMk (zeroCochainsLequiv A).toModuleIso (oneCochainsLequiv A).toModuleIso (dZero_comp_eq A) @@ -764,7 +763,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.ofHom (oneCocycles A).subtype = + (isoOneCocycles A).hom ≫ ModuleCat.asHom (oneCocycles A).subtype = iCocycles A 1 ≫ (oneCochainsLequiv A).toModuleIso.hom := by dsimp [isoOneCocycles] rw [Category.assoc, Category.assoc] @@ -774,7 +773,7 @@ lemma isoOneCocycles_hom_comp_subtype : lemma toCocycles_comp_isoOneCocycles_hom : toCocycles A 0 1 ≫ (isoOneCocycles A).hom = (zeroCochainsLequiv A).toModuleIso.hom ≫ - ModuleCat.ofHom (shortComplexH1 A).moduleCatToCycles := by + ModuleCat.asHom (shortComplexH1 A).moduleCatToCycles := by simp [isoOneCocycles] rfl @@ -812,7 +811,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.ofHom (twoCocycles A).subtype = + (isoTwoCocycles A).hom ≫ ModuleCat.asHom (twoCocycles A).subtype = iCocycles A 2 ≫ (twoCochainsLequiv A).toModuleIso.hom := by dsimp [isoTwoCocycles] rw [Category.assoc, Category.assoc] @@ -822,7 +821,7 @@ lemma isoTwoCocycles_hom_comp_subtype : lemma toCocycles_comp_isoTwoCocycles_hom : toCocycles A 1 2 ≫ (isoTwoCocycles A).hom = (oneCochainsLequiv A).toModuleIso.hom ≫ - ModuleCat.ofHom (shortComplexH2 A).moduleCatToCycles := by + ModuleCat.asHom (shortComplexH2 A).moduleCatToCycles := by simp [isoTwoCocycles] rfl diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean index b7e92987380e6..d067b4a921437 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean @@ -23,9 +23,9 @@ This allows us to define a `k[G]`-basis on `k[Gⁿ⁺¹]`, by mapping the natura We then define the standard resolution of `k` as a trivial representation, by taking the alternating face map complex associated to an appropriate simplicial `k`-linear -`G`-representation. This simplicial object is the `linearization` of the simplicial `G`-set given -by the universal cover of the classifying space of `G`, `EG`. We prove this simplicial `G`-set `EG` -is isomorphic to the Čech nerve of the natural arrow of `G`-sets `G ⟶ {pt}`. +`G`-representation. This simplicial object is the `Rep.linearization` of the simplicial `G`-set +given by the universal cover of the classifying space of `G`, `EG`. We prove this simplicial +`G`-set `EG` is isomorphic to the Čech nerve of the natural arrow of `G`-sets `G ⟶ {pt}`. We then use this isomorphism to deduce that as a complex of `k`-modules, the standard resolution of `k` as a trivial `G`-representation is homotopy equivalent to the complex with `k` at 0 and 0 @@ -214,42 +214,20 @@ theorem diagonalSucc_inv_single_left (g : G) (f : Gⁿ →₀ k) (r : k) : (diagonalSucc k G n).inv.hom (Finsupp.single g r ⊗ₜ f) = Finsupp.lift (Gⁿ⁺¹ →₀ k) k Gⁿ (fun f => single (g • partialProd f) r) f := by refine f.induction ?_ ?_ -/- Porting note (#11039): broken proof was · simp only [TensorProduct.tmul_zero, map_zero] - · intro a b x ha hb hx + · intro a b x _ _ hx simp only [lift_apply, smul_single', mul_one, TensorProduct.tmul_add, map_add, diagonalSucc_inv_single_single, hx, Finsupp.sum_single_index, mul_comm b, - zero_mul, single_zero] -/ - · rw [TensorProduct.tmul_zero, map_zero] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [map_zero] - · intro _ _ _ _ _ hx - rw [TensorProduct.tmul_add, map_add]; erw [map_add, hx] - simp_rw [lift_apply, smul_single, smul_eq_mul] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [diagonalSucc_inv_single_single] - rw [sum_single_index, mul_comm] - rw [zero_mul, single_zero] + zero_mul, single_zero] theorem diagonalSucc_inv_single_right (g : G →₀ k) (f : Gⁿ) (r : k) : (diagonalSucc k G n).inv.hom (g ⊗ₜ Finsupp.single f r) = Finsupp.lift _ k G (fun a => single (a • partialProd f) r) g := by refine g.induction ?_ ?_ -/- Porting note (#11039): broken proof was · simp only [TensorProduct.zero_tmul, map_zero] - · intro a b x ha hb hx + · intro a b x _ _ hx simp only [lift_apply, smul_single', map_add, hx, diagonalSucc_inv_single_single, - TensorProduct.add_tmul, Finsupp.sum_single_index, zero_mul, single_zero] -/ - · rw [TensorProduct.zero_tmul, map_zero] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [map_zero] - · intro _ _ _ _ _ hx - rw [TensorProduct.add_tmul, map_add]; erw [map_add, hx] - simp_rw [lift_apply, smul_single'] - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [diagonalSucc_inv_single_single] - rw [sum_single_index] - rw [zero_mul, single_zero] + TensorProduct.add_tmul, Finsupp.sum_single_index, zero_mul, single_zero] end Rep @@ -266,8 +244,7 @@ def ofMulActionBasisAux : (ofMulAction k G (Fin (n + 1) → G)).asModule := { (Rep.equivalenceModuleMonoidAlgebra.1.mapIso (diagonalSucc k G n).symm).toLinearEquiv with map_smul' := fun r x => by - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [RingHom.id_apply, LinearEquiv.toFun_eq_coe, ← LinearEquiv.map_smul] + rw [RingHom.id_apply, LinearEquiv.toFun_eq_coe, ← LinearEquiv.map_smul] congr 1 /- Porting note (#11039): broken proof was refine' x.induction_on _ (fun x y => _) fun y z hy hz => _ @@ -357,21 +334,23 @@ theorem diagonalHomEquiv_symm_apply (f : (Fin n → G) → A) (x : Fin (n + 1) 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. - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [ModuleCat.coe_comp] + rw [ModuleCat.coe_comp] simp only [ModuleCat.coe_comp, Function.comp_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [diagonalSucc_hom_single] - erw [TensorProduct.uncurry_apply, Finsupp.lift_apply, Finsupp.sum_single_index] - · simp only [one_smul] - erw [Representation.linHom_apply] - simp only [LinearMap.comp_apply, MonoidHom.one_apply, LinearMap.one_apply] - erw [Finsupp.llift_apply] - rw [Finsupp.lift_apply] - erw [Finsupp.sum_single_index] - · rw [one_smul] + -- The prototype linter that checks if `erw` could be replaced with `rw` would time out + -- if it replaces the next `erw`s with `rw`s. So we focus down on the relevant part. + conv_lhs => + erw [TensorProduct.uncurry_apply, Finsupp.lift_apply, Finsupp.sum_single_index] + · simp only [one_smul] + erw [Representation.linHom_apply] + simp only [LinearMap.comp_apply, MonoidHom.one_apply, LinearMap.one_apply] + erw [Finsupp.llift_apply] + rw [Finsupp.lift_apply] + erw [Finsupp.sum_single_index] + · rw [one_smul] + · rw [zero_smul] · rw [zero_smul] - · rw [zero_smul] /-- Auxiliary lemma for defining group cohomology, used to show that the isomorphism `diagonalHomEquiv` commutes with the differentials in two complexes which compute @@ -411,7 +390,7 @@ variable [Monoid G] isomorphic to `EG`, the universal cover of the classifying space of `G` as a simplicial `G`-set. -/ def cechNerveTerminalFromIso : cechNerveTerminalFrom (Action.ofMulAction G G) ≅ classifyingSpaceUniversalCover G := - NatIso.ofComponents (fun n => limit.isoLimitCone (Action.ofMulActionLimitCone _ _)) fun f => by + NatIso.ofComponents (fun _ => limit.isoLimitCone (Action.ofMulActionLimitCone _ _)) fun f => by refine IsLimit.hom_ext (Action.ofMulActionLimitCone.{u, 0} G fun _ => G).2 fun j => ?_ dsimp only [cechNerveTerminalFrom, Pi.lift] rw [Category.assoc, limit.isoLimitCone_hom_π, limit.lift_π, Category.assoc] @@ -584,8 +563,7 @@ theorem forget₂ToModuleCatHomotopyEquiv_f_0_eq : · 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 _)) - · dsimp - erw [Finsupp.lmapDomain_linearCombination (α := Fin 1 → G) (R := k) (α' := ⊤_ Type u) + · erw [Finsupp.lmapDomain_linearCombination (α := Fin 1 → G) (R := k) (α' := ⊤_ Type u) (v := fun _ => (1 : k)) (v' := fun _ => (1 : k)) (terminal.from ((classifyingSpaceUniversalCover G).obj (Opposite.op (SimplexCategory.mk 0))).V) diff --git a/Mathlib/RepresentationTheory/Invariants.lean b/Mathlib/RepresentationTheory/Invariants.lean index fa62df0a43948..898d8d3427513 100644 --- a/Mathlib/RepresentationTheory/Invariants.lean +++ b/Mathlib/RepresentationTheory/Invariants.lean @@ -134,7 +134,7 @@ def invariantsEquivRepHom (X Y : Rep k G) : (linHom X.ρ Y.ρ).invariants ≃ₗ map_add' _ _ := rfl map_smul' _ _ := rfl invFun f := ⟨f.hom, fun g => (mem_invariants_iff_comm _ g).2 (f.comm g)⟩ - left_inv _ := by apply Subtype.ext; ext; rfl -- Porting note: Added `apply Subtype.ext` + left_inv _ := by ext; rfl right_inv _ := by ext; rfl end Rep diff --git a/Mathlib/RepresentationTheory/Maschke.lean b/Mathlib/RepresentationTheory/Maschke.lean index 7eaec76c225f9..a3351fef477c7 100644 --- a/Mathlib/RepresentationTheory/Maschke.lean +++ b/Mathlib/RepresentationTheory/Maschke.lean @@ -12,19 +12,18 @@ import Mathlib.RingTheory.SimpleModule We prove **Maschke's theorem** for finite groups, in the formulation that every submodule of a `k[G]` module has a complement, -when `k` is a field with `Invertible (Fintype.card G : k)`. +when `k` is a field with `Fintype.card G` invertible in `k`. We do the core computation in greater generality. -For any `[CommRing k]` in which `[Invertible (Fintype.card G : k)]`, +For any commutative ring `k` in which `Fintype.card G` is invertible, and a `k[G]`-linear map `i : V → W` which admits a `k`-linear retraction `π`, we produce a `k[G]`-linear retraction by taking the average over `G` of the conjugates of `π`. ## Implementation Notes -* These results assume `Invertible (Fintype.card G : k)` which is equivalent to the more -familiar `¬(ringChar k ∣ Fintype.card G)`. It is possible to convert between them using -`invertibleOfRingCharNotDvd` and `not_ringChar_dvd_of_invertible`. +* These results assume `IsUnit (Fintype.card G : k)` which is equivalent to the more + familiar `¬(ringChar k ∣ Fintype.card G)`. ## Future work It's not so far to give the usual statement, that every finite dimensional representation @@ -55,7 +54,7 @@ namespace LinearMap -- At first we work with any `[CommRing k]`, and add the assumption that --- `[Invertible (Fintype.card G : k)]` when it is required. +-- `IsUnit (Fintype.card G : k)` when it is required. variable {k : Type u} [CommRing k] {G : Type u} [Group G] variable {V : Type v} [AddCommGroup V] [Module k V] [Module (MonoidAlgebra k G) V] variable [IsScalarTower k (MonoidAlgebra k G) V] @@ -65,7 +64,7 @@ variable (π : W →ₗ[k] V) /-- We define the conjugate of `π` by `g`, as a `k`-linear map. -/ def conjugate (g : G) : W →ₗ[k] V := - .comp (.comp (GroupSMul.linearMap k V g⁻¹) π) (GroupSMul.linearMap k W g) + GroupSMul.linearMap k V g⁻¹ ∘ₗ π ∘ₗ GroupSMul.linearMap k W g theorem conjugate_apply (g : G) (v : W) : π.conjugate g v = MonoidAlgebra.single g⁻¹ (1 : k) • π (MonoidAlgebra.single g (1 : k) • v) := @@ -75,7 +74,7 @@ variable (i : V →ₗ[MonoidAlgebra k G] W) section -theorem conjugate_i (h : ∀ v : V, (π : W → V) (i v) = v) (g : G) (v : V) : +theorem conjugate_i (h : ∀ v : V, π (i v) = v) (g : G) (v : V) : (conjugate π g : W → V) (i v) = v := by rw [conjugate_apply, ← i.map_smul, h, ← mul_smul, single_mul_single, mul_one, inv_mul_cancel, ← one_def, one_smul] @@ -108,24 +107,22 @@ theorem sumOfConjugatesEquivariant_apply (v : W) : section -variable [Invertible (Fintype.card G : k)] - /-- We construct our `k[G]`-linear retraction of `i` as $$ \frac{1}{|G|} \sum_{g \in G} g⁻¹ • π(g • -). $$ -/ def equivariantProjection : W →ₗ[MonoidAlgebra k G] V := - ⅟(Fintype.card G : k) • π.sumOfConjugatesEquivariant G + Ring.inverse (Fintype.card G : k) • π.sumOfConjugatesEquivariant G theorem equivariantProjection_apply (v : W) : - π.equivariantProjection G v = ⅟(Fintype.card G : k) • ∑ g : G, π.conjugate g v := by + π.equivariantProjection G v = Ring.inverse (Fintype.card G : k) • ∑ g : G, π.conjugate g v := by simp only [equivariantProjection, smul_apply, sumOfConjugatesEquivariant_apply] -theorem equivariantProjection_condition (h : ∀ v : V, (π : W → V) (i v) = v) (v : V) : - (π.equivariantProjection G) (i v) = v := by +theorem equivariantProjection_condition (hcard : IsUnit (Fintype.card G : k)) + (h : ∀ v : V, π (i v) = v) (v : V) : (π.equivariantProjection G) (i v) = v := by rw [equivariantProjection_apply] simp only [conjugate_i π i h] rw [Finset.sum_const, Finset.card_univ, ← Nat.cast_smul_eq_nsmul k, smul_smul, - Invertible.invOf_mul_self, one_smul] + Ring.inverse_mul_cancel _ hcard, one_smul] end @@ -136,13 +133,13 @@ end namespace MonoidAlgebra -- Now we work over a `[Field k]`. -variable {k : Type u} [Field k] {G : Type u} [Fintype G] [Invertible (Fintype.card G : k)] +variable {k : Type u} [Field k] {G : Type u} [Fintype G] [NeZero (Fintype.card G : k)] variable [Group G] variable {V : Type u} [AddCommGroup V] [Module (MonoidAlgebra k G) V] variable {W : Type u} [AddCommGroup W] [Module (MonoidAlgebra k G) W] -theorem exists_leftInverse_of_injective (f : V →ₗ[MonoidAlgebra k G] W) - (hf : LinearMap.ker f = ⊥) : +theorem exists_leftInverse_of_injective + (f : V →ₗ[MonoidAlgebra k G] W) (hf : LinearMap.ker f = ⊥) : ∃ g : W →ₗ[MonoidAlgebra k G] V, g.comp f = LinearMap.id := by let A := MonoidAlgebra k G letI : Module k W := .compHom W (algebraMap k A) @@ -152,7 +149,7 @@ theorem exists_leftInverse_of_injective (f : V →ₗ[MonoidAlgebra k G] W) obtain ⟨φ, hφ⟩ := (f.restrictScalars k).exists_leftInverse_of_injective <| by simp only [hf, Submodule.restrictScalars_bot, LinearMap.ker_restrictScalars] refine ⟨φ.equivariantProjection G, DFunLike.ext _ _ ?_⟩ - exact φ.equivariantProjection_condition G _ <| DFunLike.congr_fun hφ + exact φ.equivariantProjection_condition G _ (.mk0 _ <| NeZero.ne _) <| DFunLike.congr_fun hφ namespace Submodule @@ -167,7 +164,7 @@ instance complementedLattice : ComplementedLattice (Submodule (MonoidAlgebra k G ⟨exists_isCompl⟩ instance [AddGroup G] : IsSemisimpleRing (AddMonoidAlgebra k G) := - letI : Invertible (Fintype.card (Multiplicative G) : k) := by + haveI : NeZero (Fintype.card (Multiplicative G) : k) := by rwa [Fintype.card_congr Multiplicative.toAdd] (AddMonoidAlgebra.toMultiplicativeAlgEquiv k G (R := ℕ)).toRingEquiv.symm.isSemisimpleRing diff --git a/Mathlib/RepresentationTheory/Rep.lean b/Mathlib/RepresentationTheory/Rep.lean index 223f8229607a1..e6d2b8e5cd51e 100644 --- a/Mathlib/RepresentationTheory/Rep.lean +++ b/Mathlib/RepresentationTheory/Rep.lean @@ -183,13 +183,9 @@ theorem linearization_μ_hom (X Y : Action (Type u) (MonCat.of G)) : @[simp] theorem linearization_μ_inv_hom (X Y : Action (Type u) (MonCat.of G)) : (inv ((linearization k G).μ X Y)).hom = (finsuppTensorFinsupp' k X.V Y.V).symm.toLinearMap := by --- Porting note (#11039): broken proof was -/- simp_rw [← Action.forget_map, Functor.map_inv, Action.forget_map, linearization_μ_hom] - apply IsIso.inv_eq_of_hom_inv_id _ - exact LinearMap.ext fun x => LinearEquiv.symm_apply_apply _ _-/ rw [← Action.forget_map, Functor.map_inv] apply IsIso.inv_eq_of_hom_inv_id - exact LinearMap.ext fun x => LinearEquiv.symm_apply_apply (finsuppTensorFinsupp' k X.V Y.V) x + exact LinearMap.ext fun x ↦ LinearEquiv.symm_apply_apply _ _ @[simp] theorem linearization_ε_hom : (linearization k G).ε.hom = Finsupp.lsingle PUnit.unit := @@ -293,8 +289,8 @@ representation morphisms `Hom(k[G], A)` and `A`. -/ @[simps] noncomputable def leftRegularHomEquiv (A : Rep k G) : (Rep.ofMulAction k G G ⟶ A) ≃ₗ[k] A where toFun f := f.hom (Finsupp.single 1 1) - map_add' x y := rfl - map_smul' r x := rfl + map_add' _ _ := rfl + 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 ?_) @@ -332,7 +328,7 @@ 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.ofHom (LinearMap.llcomp k _ _ _ f.hom) + { hom := ModuleCat.asHom (LinearMap.llcomp k _ _ _ f.hom) comm := fun g => LinearMap.ext fun x => LinearMap.ext fun y => by show f.hom (X.ρ g _) = _ simp only [hom_comm_apply]; rfl } @@ -371,9 +367,9 @@ def homEquiv (A B C : Rep k G) : (A ⊗ B ⟶ C) ≃ (B ⟶ (Rep.ihom A).obj C) Rep.ihom_obj_ρ_apply, LinearMap.comp_apply, LinearMap.comp_apply] --, ρ_inv_self_apply (A := C)] dsimp - erw [ρ_inv_self_apply] + rw [ρ_inv_self_apply] rfl} - left_inv f := Action.Hom.ext (TensorProduct.ext' fun _ _ => rfl) + left_inv _ := Action.Hom.ext (TensorProduct.ext' fun _ _ => rfl) right_inv f := by ext; rfl variable {A B C} @@ -569,7 +565,7 @@ theorem unit_iso_comm (V : Rep k G) (g : G) (x : V) : /- 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] -/ - erw [Representation.asModuleEquiv_symm_map_rho] + rw [Representation.asModuleEquiv_symm_map_rho] rfl /-- Auxiliary definition for `equivalenceModuleMonoidAlgebra`. -/ diff --git a/Mathlib/RingTheory/AdicCompletion/Algebra.lean b/Mathlib/RingTheory/AdicCompletion/Algebra.lean index 4a2de3765231a..6f7c6168e2c6c 100644 --- a/Mathlib/RingTheory/AdicCompletion/Algebra.lean +++ b/Mathlib/RingTheory/AdicCompletion/Algebra.lean @@ -197,10 +197,10 @@ theorem smul_mk {m n : ℕ} (hmn : m ≤ n) (r : AdicCauchySequence I R) good definitional behaviour for the module instance on adic completions -/ instance : SMul (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R M)) where smul r x := - Quotient.liftOn r (· • x) fun b₁ b₂ (h : Setoid.Rel _ b₁ b₂) ↦ by + Quotient.liftOn r (· • x) fun b₁ b₂ h ↦ by refine Quotient.inductionOn' x (fun x ↦ ?_) have h : b₁ - b₂ ∈ (I : Submodule R R) := by - rwa [show I = I • ⊤ by simp, ← Submodule.quotientRel_r_def] + rwa [show I = I • ⊤ by simp, ← Submodule.quotientRel_def] rw [← sub_eq_zero, ← sub_smul, Submodule.Quotient.mk''_eq_mk, ← Submodule.Quotient.mk_smul, Submodule.Quotient.mk_eq_zero] exact Submodule.smul_mem_smul h mem_top diff --git a/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean b/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean index afc24e101812b..1c4dfed5cf15a 100644 --- a/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean +++ b/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean @@ -241,17 +241,17 @@ private instance : AddCommGroup (AdicCompletion I R ⊗[R] (LinearMap.ker f)) := private def firstRow : ComposableArrows (ModuleCat (AdicCompletion I R)) 4 := ComposableArrows.mk₄ - (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)) + (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)) private def secondRow : ComposableArrows (ModuleCat (AdicCompletion I R)) 4 := ComposableArrows.mk₄ - (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)) + (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)) include hf @@ -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.ofHom (ofTensorProduct I (LinearMap.ker f))) - (ModuleCat.ofHom (ofTensorProduct I (ι → R))) - (ModuleCat.ofHom (ofTensorProduct I M)) - (ModuleCat.ofHom 0) - (ModuleCat.ofHom 0) + (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 rfl rfl private lemma ofTensorProduct_iso [Fintype ι] [IsNoetherianRing R] : - IsIso (ModuleCat.ofHom (ofTensorProduct I M)) := by + IsIso (ModuleCat.asHom (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.ofHom 0) + · show IsIso (ModuleCat.asHom 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.ofHom (ofTensorProduct I M)) := + have : IsIso (ModuleCat.asHom (ofTensorProduct I M)) := ofTensorProduct_iso I M f hf - exact ConcreteCategory.bijective_of_isIso (ModuleCat.ofHom (ofTensorProduct I M)) + exact ConcreteCategory.bijective_of_isIso (ModuleCat.asHom (ofTensorProduct I M)) end diff --git a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean index 671d719a25adf..03b236a454123 100644 --- a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean +++ b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean @@ -145,7 +145,7 @@ theorem map_ext {N} {f g : AdicCompletion I M → N} f (AdicCompletion.mk I M a) = g (AdicCompletion.mk I M a)) : f = g := by ext x - apply induction_on I M x (fun a ↦ h a) + apply induction_on I M x h /-- Equality of linear maps out of an adic completion can be checked on Cauchy sequences. -/ @[ext] @@ -154,7 +154,7 @@ theorem map_ext' {f g : AdicCompletion I M →ₗ[AdicCompletion I R] T} f (AdicCompletion.mk I M a) = g (AdicCompletion.mk I M a)) : f = g := by ext x - apply induction_on I M x (fun a ↦ h a) + apply induction_on I M x h /-- Equality of linear maps out of an adic completion can be checked on Cauchy sequences. -/ @[ext] diff --git a/Mathlib/RingTheory/Adjoin/Basic.lean b/Mathlib/RingTheory/Adjoin/Basic.lean index 83e58942dce2b..9daf1551d8672 100644 --- a/Mathlib/RingTheory/Adjoin/Basic.lean +++ b/Mathlib/RingTheory/Adjoin/Basic.lean @@ -69,66 +69,71 @@ theorem adjoin_attach_biUnion [DecidableEq A] {α : Type*} {s : Finset α} (f : adjoin R (s.attach.biUnion f : Set A) = ⨆ x, adjoin R (f x) := by simp [adjoin_iUnion] @[elab_as_elim] -theorem adjoin_induction {p : A → Prop} {x : A} (h : x ∈ adjoin R s) (mem : ∀ x ∈ s, p x) - (algebraMap : ∀ r, p (algebraMap R A r)) (add : ∀ x y, p x → p y → p (x + y)) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := +theorem adjoin_induction {p : (x : A) → x ∈ adjoin R s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_adjoin hx)) + (algebraMap : ∀ r, p (algebraMap R A r) (algebraMap_mem _ r)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + {x : A} (hx : x ∈ adjoin R s) : p x hx := let S : Subalgebra R A := - { carrier := p - mul_mem' := mul _ _ - add_mem' := add _ _ - algebraMap_mem' := algebraMap } - adjoin_le (show s ≤ S from mem) h + { carrier := { x | ∃ hx, p x hx } + mul_mem' := by rintro _ _ ⟨_, hpx⟩ ⟨_, hpy⟩; exact ⟨_, mul _ _ _ _ hpx hpy⟩ + add_mem' := by rintro _ _ ⟨_, hpx⟩ ⟨_, hpy⟩; exact ⟨_, add _ _ _ _ hpx hpy⟩ + algebraMap_mem' := fun r ↦ ⟨_, algebraMap r⟩ } + adjoin_le (S := S) (fun y hy ↦ ⟨subset_adjoin hy, mem y hy⟩) hx |>.elim fun _ ↦ _root_.id + +@[deprecated adjoin_induction (since := "2024-10-10")] +alias adjoin_induction'' := adjoin_induction /-- Induction principle for the algebra generated by a set `s`: show that `p x y` holds for any `x y ∈ adjoin R s` given that it holds for `x y ∈ s` and that it satisfies a number of natural properties. -/ @[elab_as_elim] -theorem adjoin_induction₂ {p : A → A → Prop} {a b : A} (ha : a ∈ adjoin R s) (hb : b ∈ adjoin R s) - (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (Halg : ∀ r₁ r₂, p (algebraMap R A r₁) (algebraMap R A r₂)) - (Halg_left : ∀ (r), ∀ x ∈ s, p (algebraMap R A r) x) - (Halg_right : ∀ (r), ∀ x ∈ s, p x (algebraMap R A r)) - (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) : p a b := by - refine adjoin_induction hb ?_ (fun r => ?_) (Hadd_right a) (Hmul_right a) - · exact adjoin_induction ha Hs Halg_left - (fun x y Hx Hy z hz => Hadd_left x y z (Hx z hz) (Hy z hz)) - fun x y Hx Hy z hz => Hmul_left x y z (Hx z hz) (Hy z hz) - · exact adjoin_induction ha (Halg_right r) (fun r' => Halg r' r) - (fun x y => Hadd_left x y ((algebraMap R A) r)) - fun x y => Hmul_left x y ((algebraMap R A) r) +theorem adjoin_induction₂ {s : Set A} {p : (x y : A) → x ∈ adjoin R s → y ∈ adjoin R s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_adjoin hx) (subset_adjoin hy)) + (algebraMap_both : ∀ r₁ r₂, p (algebraMap R A r₁) (algebraMap R A r₂) (algebraMap_mem _ r₁) + (algebraMap_mem _ r₂)) + (algebraMap_left : ∀ (r) (x) (hx : x ∈ s), p (algebraMap R A r) x (algebraMap_mem _ r) + (subset_adjoin hx)) + (algebraMap_right : ∀ (r) (x) (hx : x ∈ s), p x (algebraMap R A r) (subset_adjoin hx) + (algebraMap_mem _ r)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + {x y : A} (hx : x ∈ adjoin R s) (hy : y ∈ adjoin R s) : + p x y hx hy := by + induction hy using adjoin_induction with + | mem z hz => induction hx using adjoin_induction with + | mem _ h => exact mem_mem _ _ h hz + | algebraMap _ => exact algebraMap_left _ _ hz + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | algebraMap r => + induction hx using adjoin_induction with + | mem _ h => exact algebraMap_right _ _ h + | algebraMap _ => exact algebraMap_both _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ /-- The difference with `Algebra.adjoin_induction` is that this acts on the subtype. -/ -@[elab_as_elim] +@[elab_as_elim, deprecated adjoin_induction (since := "2024-10-11")] theorem adjoin_induction' {p : adjoin R s → Prop} (mem : ∀ (x) (h : x ∈ s), p ⟨x, subset_adjoin h⟩) (algebraMap : ∀ r, p (algebraMap R _ r)) (add : ∀ x y, p x → p y → p (x + y)) (mul : ∀ x y, p x → p y → p (x * y)) (x : adjoin R s) : p x := Subtype.recOn x fun x hx => by - refine Exists.elim ?_ fun (hx : x ∈ adjoin R s) (hc : p ⟨x, hx⟩) => hc - exact adjoin_induction hx (fun x hx => ⟨subset_adjoin hx, mem x hx⟩) - (fun r => ⟨Subalgebra.algebraMap_mem _ r, algebraMap r⟩) - (fun x y hx hy => - Exists.elim hx fun hx' hx => - Exists.elim hy fun hy' hy => ⟨Subalgebra.add_mem _ hx' hy', add _ _ hx hy⟩) - fun x y hx hy => - Exists.elim hx fun hx' hx => - Exists.elim hy fun hy' hy => ⟨Subalgebra.mul_mem _ hx' hy', mul _ _ hx hy⟩ - -@[elab_as_elim] -theorem adjoin_induction'' {x : A} (hx : x ∈ adjoin R s) - {p : (x : A) → x ∈ adjoin R s → Prop} (mem : ∀ x (h : x ∈ s), p x (subset_adjoin h)) - (algebraMap : ∀ (r : R), p (algebraMap R A r) (algebraMap_mem _ r)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) - (mul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) : - p x hx := by - refine adjoin_induction' mem algebraMap ?_ ?_ ⟨x, hx⟩ (p := fun x : adjoin R s ↦ p x.1 x.2) - exacts [fun x y ↦ add x.1 x.2 y.1 y.2, fun x y ↦ mul x.1 x.2 y.1 y.2] + induction hx using adjoin_induction with + | mem _ h => exact mem _ h + | algebraMap _ => exact algebraMap _ + | mul _ _ _ _ h₁ h₂ => exact mul _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add _ _ h₁ h₂ @[simp] theorem adjoin_adjoin_coe_preimage {s : Set A} : adjoin R (((↑) : adjoin R s → A) ⁻¹' s) = ⊤ := by - refine eq_top_iff.2 fun x ↦ - adjoin_induction' (fun a ha ↦ ?_) (fun r ↦ ?_) (fun _ _ ↦ ?_) (fun _ _ ↦ ?_) x + refine eq_top_iff.2 fun ⟨x, hx⟩ ↦ + adjoin_induction (fun a ha ↦ ?_) (fun r ↦ ?_) (fun _ _ _ _ ↦ ?_) (fun _ _ _ _ ↦ ?_) hx · exact subset_adjoin ha · exact Subalgebra.algebraMap_mem _ r · exact Subalgebra.add_mem _ @@ -219,16 +224,16 @@ theorem adjoin_prod_le (s : Set A) (t : Set B) : theorem mem_adjoin_of_map_mul {s} {x : A} {f : A →ₗ[R] B} (hf : ∀ a₁ a₂, f (a₁ * a₂) = f a₁ * f a₂) (h : x ∈ adjoin R s) : f x ∈ adjoin R (f '' (s ∪ {1})) := by - refine - @adjoin_induction R A _ _ _ _ (fun a => f a ∈ adjoin R (f '' (s ∪ {1}))) x h - (fun a ha => subset_adjoin ⟨a, ⟨Set.subset_union_left ha, rfl⟩⟩) (fun r => ?_) - (fun y z hy hz => by simpa [hy, hz] using Subalgebra.add_mem _ hy hz) fun y z hy hz => by - simpa [hy, hz, hf y z] using Subalgebra.mul_mem _ hy hz - have : f 1 ∈ adjoin R (f '' (s ∪ {1})) := - subset_adjoin ⟨1, ⟨Set.subset_union_right <| Set.mem_singleton 1, rfl⟩⟩ - convert Subalgebra.smul_mem (adjoin R (f '' (s ∪ {1}))) this r - rw [algebraMap_eq_smul_one] - exact f.map_smul _ _ + induction h using adjoin_induction with + | mem a ha => exact subset_adjoin ⟨a, ⟨Set.subset_union_left ha, rfl⟩⟩ + | algebraMap r => + have : f 1 ∈ adjoin R (f '' (s ∪ {1})) := + subset_adjoin ⟨1, ⟨Set.subset_union_right <| Set.mem_singleton 1, rfl⟩⟩ + convert Subalgebra.smul_mem (adjoin R (f '' (s ∪ {1}))) this r + rw [algebraMap_eq_smul_one] + exact f.map_smul _ _ + | add y z _ _ hy hz => simpa [hy, hz] using Subalgebra.add_mem _ hy hz + | mul y z _ _ hy hz => simpa [hf, hy, hz] using Subalgebra.mul_mem _ hy hz theorem adjoin_inl_union_inr_eq_prod (s) (t) : adjoin R (LinearMap.inl R A B '' (s ∪ {1}) ∪ LinearMap.inr R A B '' (t ∪ {1})) = @@ -255,23 +260,29 @@ semiring. -/ def adjoinCommSemiringOfComm {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommSemiring (adjoin R s) := { (adjoin R s).toSemiring with - mul_comm := fun x y => by + mul_comm := fun ⟨x, hx⟩ ⟨y, hy⟩ => by ext - simp only [Subalgebra.coe_mul] - exact adjoin_induction₂ x.prop y.prop hcomm (fun _ _ => by rw [commutes]) - (fun r x _hx => commutes r x) (fun r x _hx => (commutes r x).symm) - (fun _ _ _ h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun _ _ _ h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x₁ x₂ y₁ h₁ h₂ => by rw [mul_assoc, h₂, ← mul_assoc y₁, ← h₁, mul_assoc x₁]) - fun x₁ x₂ y₁ h₁ h₂ => by rw [mul_assoc x₂, ← h₂, ← mul_assoc x₂, ← h₁, ← mul_assoc] } + simp only [MulMemClass.mk_mul_mk] + induction hx, hy using adjoin_induction₂ with + | mem_mem x y hx hy => exact hcomm x hx y hy + | algebraMap_both r₁ r₂ => exact commutes r₁ <| algebraMap R A r₂ + | algebraMap_left r x _ => exact commutes r x + | algebraMap_right r x _ => exact commutes r x |>.symm + | mul_left _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_left h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_right h₁ h₂ + | add_left _ _ _ _ _ _ h₁ h₂ => exact Commute.add_left h₁ h₂ + | add_right _ _ _ _ _ _ h₁ h₂ => exact Commute.add_right h₁ h₂ } variable {R} lemma commute_of_mem_adjoin_of_forall_mem_commute {a b : A} {s : Set A} (hb : b ∈ adjoin R s) (h : ∀ b ∈ s, Commute a b) : - Commute a b := - adjoin_induction hb h (fun r ↦ commute_algebraMap_right r a) (fun _ _ ↦ Commute.add_right) - (fun _ _ ↦ Commute.mul_right) + Commute a b := by + induction hb using adjoin_induction with + | mem x hx => exact h x hx + | algebraMap r => exact commutes r a |>.symm + | add y z _ _ hy hz => exact hy.add_right hz + | mul y z _ _ hy hz => exact hy.mul_right hz lemma commute_of_mem_adjoin_singleton_of_commute {a b c : A} (hc : c ∈ adjoin R {b}) (h : Commute a b) : @@ -388,8 +399,8 @@ variable [Algebra R A] {s t : Set A} theorem mem_adjoin_iff {s : Set A} {x : A} : x ∈ adjoin R s ↔ x ∈ Subring.closure (Set.range (algebraMap R A) ∪ s) := ⟨fun hx => - Subsemiring.closure_induction hx Subring.subset_closure (Subring.zero_mem _) (Subring.one_mem _) - (fun _ _ => Subring.add_mem _) fun _ _ => Subring.mul_mem _, + Subsemiring.closure_induction Subring.subset_closure (Subring.zero_mem _) (Subring.one_mem _) + (fun _ _ _ _ => Subring.add_mem _) (fun _ _ _ _ => Subring.mul_mem _) hx, suffices Subring.closure (Set.range (algebraMap R A) ∪ s) ≤ (adjoin R s).toSubring from (show (_ : Set A) ⊆ _ from this) (a := x) -- Porting note: Lean doesn't seem to recognize the defeq between the order on subobjects and diff --git a/Mathlib/RingTheory/Adjoin/FG.lean b/Mathlib/RingTheory/Adjoin/FG.lean index 1256cc4e9a973..fdbe2c43cbbaa 100644 --- a/Mathlib/RingTheory/Adjoin/FG.lean +++ b/Mathlib/RingTheory/Adjoin/FG.lean @@ -103,7 +103,7 @@ theorem fg_of_fg_toSubmodule {S : Subalgebra R A} : S.toSubmodule.FG → S.FG := fun ⟨t, ht⟩ ↦ ⟨t, le_antisymm (Algebra.adjoin_le fun x hx ↦ show x ∈ Subalgebra.toSubmodule S from ht ▸ subset_span hx) <| show Subalgebra.toSubmodule S ≤ Subalgebra.toSubmodule (Algebra.adjoin R ↑t) from fun x hx ↦ - span_le.mpr (fun x hx ↦ Algebra.subset_adjoin hx) + span_le.mpr (fun _ hx ↦ Algebra.subset_adjoin hx) (show x ∈ span R ↑t by rw [ht] exact hx)⟩ diff --git a/Mathlib/RingTheory/Adjoin/Field.lean b/Mathlib/RingTheory/Adjoin/Field.lean index 4463b01947e1f..25bf90e6eb79c 100644 --- a/Mathlib/RingTheory/Adjoin/Field.lean +++ b/Mathlib/RingTheory/Adjoin/Field.lean @@ -97,10 +97,26 @@ theorem IsIntegral.mem_range_algebraMap_of_minpoly_splits [Algebra K L] [IsScala x ∈ (algebraMap K L).range := int.mem_range_algHom_of_minpoly_splits h (IsScalarTower.toAlgHom R K L) +theorem minpoly_add_algebraMap_splits [Algebra K L] {x : L} (r : K) + (g : (minpoly K x).Splits (algebraMap K L)) : + (minpoly K (x + algebraMap K L r)).Splits (algebraMap K L) := by + simpa [minpoly.add_algebraMap] using g.comp_X_sub_C r + +theorem minpoly_sub_algebraMap_splits [Algebra K L] {x : L} (r : K) + (g : (minpoly K x).Splits (algebraMap K L)) : + (minpoly K (x - algebraMap K L r)).Splits (algebraMap K L) := by + simpa only [sub_eq_add_neg, map_neg] using minpoly_add_algebraMap_splits (-r) g + +theorem minpoly_algebraMap_add_splits [Algebra K L] {x : L} (r : K) + (g : (minpoly K x).Splits (algebraMap K L)) : + (minpoly K (algebraMap K L r + x)).Splits (algebraMap K L) := by + simpa only [add_comm] using minpoly_add_algebraMap_splits r g + end variable [Algebra K M] [IsScalarTower R K M] {x : M} +/-- The `RingHom` version of `IsIntegral.minpoly_splits_tower_top`. -/ theorem IsIntegral.minpoly_splits_tower_top' (int : IsIntegral R x) {f : K →+* L} (h : Splits (f.comp <| algebraMap R K) (minpoly R x)) : Splits f (minpoly K x) := diff --git a/Mathlib/RingTheory/Adjoin/Tower.lean b/Mathlib/RingTheory/Adjoin/Tower.lean index 131178ee351d3..c916d29572648 100644 --- a/Mathlib/RingTheory/Adjoin/Tower.lean +++ b/Mathlib/RingTheory/Adjoin/Tower.lean @@ -126,8 +126,8 @@ theorem exists_subalgebra_of_fg (hAC : (⊤ : Subalgebra A C).FG) (hBC : (⊤ : rw [restrictScalars_top, eq_top_iff, ← Algebra.top_toSubmodule, ← hx, Algebra.adjoin_eq_span, span_le] refine fun r hr => - Submonoid.closure_induction hr (fun c hc => hxy c hc) (subset_span <| mem_insert_self _ _) - fun p q hp hq => hyy <| Submodule.mul_mem_mul hp hq + Submonoid.closure_induction (fun c hc => hxy c hc) (subset_span <| mem_insert_self _ _) + (fun p q _ _ hp hq => hyy <| Submodule.mul_mem_mul hp hq) hr end Semiring diff --git a/Mathlib/RingTheory/AdjoinRoot.lean b/Mathlib/RingTheory/AdjoinRoot.lean index bba7f1e3e7457..c9b8dee4c1568 100644 --- a/Mathlib/RingTheory/AdjoinRoot.lean +++ b/Mathlib/RingTheory/AdjoinRoot.lean @@ -9,9 +9,9 @@ import Mathlib.FieldTheory.Minpoly.Basic import Mathlib.RingTheory.Adjoin.Basic import Mathlib.RingTheory.FinitePresentation import Mathlib.RingTheory.FiniteType +import Mathlib.RingTheory.Ideal.Quotient.Noetherian import Mathlib.RingTheory.PowerBasis import Mathlib.RingTheory.PrincipalIdealDomain -import Mathlib.RingTheory.QuotientNoetherian import Mathlib.RingTheory.Polynomial.Quotient /-! @@ -205,7 +205,6 @@ theorem aeval_eq (p : R[X]) : aeval (root f) p = mk f p := rw [_root_.map_mul, aeval_C, map_pow, aeval_X, RingHom.map_mul, mk_C, RingHom.map_pow, mk_X] rfl --- Porting note: the following proof was partly in term-mode, but I was not able to fix it. theorem adjoinRoot_eq_top : Algebra.adjoin R ({root f} : Set (AdjoinRoot f)) = ⊤ := by refine Algebra.eq_top_iff.2 fun x => ?_ induction x using AdjoinRoot.induction_on with @@ -402,7 +401,6 @@ def modByMonicHom (hg : g.Monic) : AdjoinRoot g →ₗ[R] R[X] := theorem modByMonicHom_mk (hg : g.Monic) (f : R[X]) : modByMonicHom hg (mk g f) = f %ₘ g := rfl --- Porting note: the following proof was partly in term-mode, but I was not able to fix it. theorem mk_leftInverse (hg : g.Monic) : Function.LeftInverse (mk g) (modByMonicHom hg) := by intro f induction f using AdjoinRoot.induction_on @@ -716,7 +714,6 @@ def quotAdjoinRootEquivQuotPolynomialQuot : ((Ideal.quotEquivOfEq (by rw [map_span, Set.image_singleton])).trans (Polynomial.quotQuotEquivComm I f).symm)) --- Porting note: mathlib3 proof was a long `rw` that timeouts. @[simp] theorem quotAdjoinRootEquivQuotPolynomialQuot_mk_of (p : R[X]) : quotAdjoinRootEquivQuotPolynomialQuot I f (Ideal.Quotient.mk (I.map (of f)) (mk f p)) = diff --git a/Mathlib/RingTheory/AlgebraTower.lean b/Mathlib/RingTheory/AlgebraTower.lean index ac5c55707ae21..5f05a3121b52f 100644 --- a/Mathlib/RingTheory/AlgebraTower.lean +++ b/Mathlib/RingTheory/AlgebraTower.lean @@ -94,7 +94,7 @@ open scoped Classical universe v₁ w₁ variable {R S A} -variable [Semiring R] [Semiring S] [AddCommMonoid A] +variable [Ring R] [Ring S] [AddCommGroup A] variable [Module R S] [Module S A] [Module R A] [IsScalarTower R S A] theorem linearIndependent_smul {ι : Type v₁} {b : ι → S} {ι' : Type w₁} {c : ι' → A} diff --git a/Mathlib/RingTheory/Algebraic.lean b/Mathlib/RingTheory/Algebraic.lean index 2f80a41c0e3cb..1d1e4ac64d686 100644 --- a/Mathlib/RingTheory/Algebraic.lean +++ b/Mathlib/RingTheory/Algebraic.lean @@ -5,6 +5,7 @@ Authors: Johan Commelin -/ import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Basic import Mathlib.RingTheory.Polynomial.IntegralNormalization +import Mathlib.RingTheory.LocalRing.Basic /-! # Algebraic elements and algebraic extensions @@ -39,6 +40,63 @@ theorem is_transcendental_of_subsingleton [Subsingleton R] (x : A) : Transcenden 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 + +variable (R) in +theorem Polynomial.transcendental_X : Transcendental R (X (R := R)) := by + simp [transcendental_iff] + +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 + obtain ⟨p, h1, h2⟩ := H + have : (p.comp f).coeff (p.natDegree * f.natDegree) ≠ 0 := fun h ↦ h1 <| by + rwa [coeff_comp_degree_mul_degree hf, + mul_right_mem_nonZeroDivisors_eq_zero_iff (pow_mem hf' _), + leadingCoeff_eq_zero] at h + exact ⟨p.comp f, fun h ↦ this (by simp [h]), by rwa [aeval_comp]⟩ + +theorem Transcendental.aeval {r : A} (H : Transcendental R r) (f : R[X]) (hf : f.natDegree ≠ 0) + (hf' : f.leadingCoeff ∈ nonZeroDivisors R) : + Transcendental R (aeval r f) := fun h ↦ H (h.of_aeval f hf hf') + +theorem Polynomial.transcendental (f : R[X]) (hf : f.natDegree ≠ 0) + (hf' : f.leadingCoeff ∈ nonZeroDivisors R) : + 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 := @@ -47,11 +105,11 @@ def Subalgebra.IsAlgebraic (S : Subalgebra R A) : Prop := variable (R A) /-- An algebra is algebraic if all its elements are algebraic. -/ -protected class Algebra.IsAlgebraic : Prop := +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 := +protected class Algebra.Transcendental : Prop where transcendental : ∃ x : A, Transcendental R x variable {R A} @@ -68,7 +126,7 @@ theorem Algebra.transcendental_iff_not_isAlgebraic : /-- 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 _ _ S.algebra := by + 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 ?_ @@ -85,10 +143,18 @@ 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] +/-- An element `x` is transcendental over `R` if and only if the map `Polynomial.aeval x` +is injective. This is similar to `algebraicIndependent_iff_injective_aeval`. -/ theorem transcendental_iff_injective {x : A} : Transcendental R x ↔ Function.Injective (Polynomial.aeval x : R[X] →ₐ[R] A) := isAlgebraic_iff_not_injective.not_left +/-- An element `x` is transcendental over `R` if and only if the kernel of the ring homomorphism +`Polynomial.aeval x` is the zero ideal. This is similar to `algebraicIndependent_iff_ker_eq_bot`. -/ +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] + end section zero_ne_one @@ -173,6 +239,10 @@ theorem isAlgebraic_algebraMap_iff {a : S} (h : Function.Injective (algebraMap S IsAlgebraic R (algebraMap S A a) ↔ IsAlgebraic R a := isAlgebraic_algHom_iff (IsScalarTower.toAlgHom R S A) h +theorem transcendental_algebraMap_iff {a : S} (h : Function.Injective (algebraMap S A)) : + Transcendental R (algebraMap S A a) ↔ Transcendental R a := by + simp_rw [Transcendental, isAlgebraic_algebraMap_iff h] + 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 @@ -226,6 +296,12 @@ alias ⟨IsAlgebraic.isIntegral, _⟩ := isAlgebraic_iff_isIntegral 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) + end Field section @@ -254,6 +330,12 @@ theorem Algebra.IsAlgebraic.tower_top_of_injective (hinj : Function.Injective (a [Algebra.IsAlgebraic R A] : Algebra.IsAlgebraic S A := ⟨fun _ ↦ _root_.IsAlgebraic.tower_top_of_injective hinj (Algebra.IsAlgebraic.isAlgebraic _)⟩ +theorem Algebra.IsAlgebraic.tower_bot_of_injective [Algebra.IsAlgebraic R A] + (hinj : Function.Injective (algebraMap S A)) : + Algebra.IsAlgebraic R S where + isAlgebraic x := by + simpa [isAlgebraic_algebraMap_iff hinj] using isAlgebraic (R := R) (A := A) (algebraMap _ _ x) + end CommRing section Field @@ -282,6 +364,12 @@ variable (A) instance Algebra.IsAlgebraic.of_finite [FiniteDimensional K A] : Algebra.IsAlgebraic K A := (IsIntegral.of_finite K A).isAlgebraic +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] + [Nontrivial A] [Algebra.IsAlgebraic K A] : + Algebra.IsAlgebraic K L := + tower_bot_of_injective (algebraMap L A).injective + end Field end Ring diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean index 0e358adaa9418..f92865083dda4 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent.lean @@ -9,6 +9,7 @@ import Mathlib.LinearAlgebra.LinearIndependent import Mathlib.RingTheory.Adjoin.Basic import Mathlib.RingTheory.Algebraic import Mathlib.RingTheory.MvPolynomial.Basic +import Mathlib.Data.Fin.Tuple.Reflection /-! # Algebraic Independence @@ -47,11 +48,9 @@ open scoped Classical universe x u v w variable {ι : Type*} {ι' : Type*} (R : Type*) {K : Type*} -variable {A : Type*} {A' A'' : Type*} {V : Type u} {V' : Type*} +variable {A : Type*} {A' : Type*} variable (x : ι → A) -variable [CommRing R] [CommRing A] [CommRing A'] [CommRing A''] -variable [Algebra R A] [Algebra R A'] [Algebra R A''] -variable {a b : R} +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 @@ -84,6 +83,24 @@ 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)) : @@ -140,8 +157,28 @@ theorem map {f : A →ₐ[R] A'} (hf_inj : Set.InjOn f (adjoin R (range x))) : 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] + end AlgebraicIndependent +namespace MvPolynomial + +variable (σ R : Type*) [CommRing R] + +theorem algebraicIndependent_X : AlgebraicIndependent R (X (R := R) (σ := σ)) := by + rw [AlgebraicIndependent, aeval_X_left] + exact injective_id + +variable {σ} in +theorem transcendental_X (i : σ) : Transcendental R (X (R := R) i) := + (algebraicIndependent_X σ R).transcendental i + +end MvPolynomial + open AlgebraicIndependent theorem AlgHom.algebraicIndependent_iff (f : A →ₐ[R] A') (hf : Injective f) : @@ -365,22 +402,24 @@ theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply (aeval (fun o : Option ι => o.elim Polynomial.X fun s : ι => Polynomial.C (X s)) y) := rfl ---@[simp] Porting note: removing simp because the linter complains about deterministic timeout +/-- `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 + simp [aevalEquiv] + theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_C (hx : AlgebraicIndependent R x) (r) : hx.mvPolynomialOptionEquivPolynomialAdjoin (C r) = Polynomial.C (algebraMap _ _ r) := by - rw [AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply, aeval_C, - IsScalarTower.algebraMap_apply R (MvPolynomial ι R), ← Polynomial.C_eq_algebraMap, - Polynomial.map_C, RingHom.coe_coe, AlgEquiv.commutes] + simp ---@[simp] Porting note (#10618): simp can prove it 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] ---@[simp] Porting note (#10618): simp can prove it theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_X_some (hx : AlgebraicIndependent R x) (i) : hx.mvPolynomialOptionEquivPolynomialAdjoin (X (some i)) = @@ -409,13 +448,26 @@ theorem AlgebraicIndependent.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin theorem AlgebraicIndependent.option_iff (hx : AlgebraicIndependent R x) (a : A) : (AlgebraicIndependent R fun o : Option ι => o.elim a x) ↔ - ¬IsAlgebraic (adjoin R (Set.range x)) a := by - rw [algebraicIndependent_iff_injective_aeval, isAlgebraic_iff_not_injective, Classical.not_not, ← - AlgHom.coe_toRingHom, ← hx.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin, + 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] + variable (R) /-- A family is a transcendence basis if it is a maximal algebraically independent subset. -/ @@ -432,6 +484,13 @@ theorem exists_isTranscendenceBasis (h : Injective (algebraMap R A)) : 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] diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index e3f2bcd132e70..6942b8afeb66c 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -97,9 +97,15 @@ instance isArtinian_of_quotient_of_artinian variable {M} +instance isArtinian_range (f : M →ₗ[R] P) [IsArtinian R M] : IsArtinian R (LinearMap.range f) := + isArtinian_of_surjective _ _ f.surjective_rangeRestrict + theorem isArtinian_of_linearEquiv (f : M ≃ₗ[R] P) [IsArtinian R M] : IsArtinian R P := isArtinian_of_surjective _ f.toLinearMap f.toEquiv.surjective +theorem LinearEquiv.isArtinian_iff (f : M ≃ₗ[R] P) : IsArtinian R M ↔ IsArtinian R P := + ⟨fun _ ↦ isArtinian_of_linearEquiv f, fun _ ↦ isArtinian_of_linearEquiv f.symm⟩ + theorem isArtinian_of_range_eq_ker [IsArtinian R M] [IsArtinian R P] (f : M →ₗ[R] N) (g : N →ₗ[R] P) (h : LinearMap.range f = LinearMap.ker g) : IsArtinian R N := wellFounded_lt_exact_sequence (LinearMap.range f) (Submodule.map (f.ker.liftQ f le_rfl)) @@ -125,8 +131,15 @@ instance (priority := 100) isArtinian_of_finite [Finite M] : IsArtinian R M := -- Porting note: elab_as_elim can only be global and cannot be changed on an imported decl -- attribute [local elab_as_elim] Finite.induction_empty_option -instance isArtinian_pi {R ι : Type*} [Finite ι] : - ∀ {M : ι → Type*} [Ring R] [∀ i, AddCommGroup (M i)] +instance isArtinian_sup (M₁ M₂ : Submodule R P) [IsArtinian R M₁] [IsArtinian R M₂] : + IsArtinian R ↥(M₁ ⊔ M₂) := by + have := isArtinian_range (M₁.subtype.coprod M₂.subtype) + rwa [LinearMap.range_coprod, Submodule.range_subtype, Submodule.range_subtype] at this + +variable {ι : Type*} [Finite ι] + +instance isArtinian_pi : + ∀ {M : ι → Type*} [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [∀ i, IsArtinian R (M i)], IsArtinian R (∀ i, M i) := by apply Finite.induction_empty_option _ _ _ ι · exact fun e h ↦ isArtinian_of_linearEquiv (LinearEquiv.piCongrLeft R _ e) @@ -136,15 +149,20 @@ instance isArtinian_pi {R ι : Type*} [Finite ι] : /-- A version of `isArtinian_pi` for non-dependent functions. We need this instance because sometimes Lean fails to apply the dependent version in non-dependent settings (e.g., it fails to prove that `ι → ℝ` is finite dimensional over `ℝ`). -/ -instance isArtinian_pi' {R ι M : Type*} [Ring R] [AddCommGroup M] [Module R M] [Finite ι] - [IsArtinian R M] : IsArtinian R (ι → M) := +instance isArtinian_pi' [IsArtinian R M] : IsArtinian R (ι → M) := isArtinian_pi --porting note (#10754): new instance -instance isArtinian_finsupp {R ι M : Type*} [Ring R] [AddCommGroup M] [Module R M] [Finite ι] - [IsArtinian R M] : IsArtinian R (ι →₀ M) := +instance isArtinian_finsupp [IsArtinian R M] : IsArtinian R (ι →₀ M) := isArtinian_of_linearEquiv (Finsupp.linearEquivFunOnFinite _ _ _).symm +instance isArtinian_iSup : + ∀ {M : ι → Submodule R P} [∀ i, IsArtinian R (M i)], IsArtinian R ↥(⨆ i, M i) := by + apply Finite.induction_empty_option _ _ _ ι + · intro _ _ e h _ _; rw [← e.iSup_comp]; apply h + · intros; rw [iSup_of_empty]; infer_instance + · intro _ _ ih _ _; rw [iSup_option]; infer_instance + end open Submodule Function @@ -522,7 +540,4 @@ instance [IsReduced R] : DecompositionMonoid (Polynomial R) := theorem isSemisimpleRing_of_isReduced [IsReduced R] : IsSemisimpleRing R := (equivPi R).symm.isSemisimpleRing -proof_wanted IsSemisimpleRing.isArtinianRing (R : Type*) [CommRing R] [IsSemisimpleRing R] : - IsArtinianRing R - end IsArtinianRing diff --git a/Mathlib/RingTheory/Bezout.lean b/Mathlib/RingTheory/Bezout.lean index 37aef0df9ae66..6bc38c5db39ce 100644 --- a/Mathlib/RingTheory/Bezout.lean +++ b/Mathlib/RingTheory/Bezout.lean @@ -51,7 +51,7 @@ theorem TFAE [IsBezout R] [IsDomain R] : [IsNoetherianRing R, IsPrincipalIdealRing R, UniqueFactorizationMonoid R, WfDvdMonoid R] := by classical tfae_have 1 → 2 - | H => ⟨fun I => isPrincipal_of_FG _ (IsNoetherian.noetherian _)⟩ + | _ => inferInstance tfae_have 2 → 3 | _ => inferInstance tfae_have 3 → 4 diff --git a/Mathlib/RingTheory/Bialgebra/Hom.lean b/Mathlib/RingTheory/Bialgebra/Hom.lean index f1b2923cd334c..bbb6a66995f90 100644 --- a/Mathlib/RingTheory/Bialgebra/Hom.lean +++ b/Mathlib/RingTheory/Bialgebra/Hom.lean @@ -275,10 +275,10 @@ theorem map_smul_of_tower {R'} [SMul R' A] [SMul R' B] [LinearMap.CompatibleSMul @[simps (config := .lemmasOnly) toSemigroup_toMul_mul toOne_one] instance End : Monoid (A →ₐc[R] A) where mul := comp - mul_assoc ϕ ψ χ := rfl + mul_assoc _ _ _ := rfl one := BialgHom.id R A - one_mul ϕ := ext fun x => rfl - mul_one ϕ := ext fun x => rfl + one_mul _ := ext fun _ => rfl + mul_one _ := ext fun _ => rfl @[simp] theorem one_apply (x : A) : (1 : A →ₐc[R] A) x = x := diff --git a/Mathlib/RingTheory/Bialgebra/TensorProduct.lean b/Mathlib/RingTheory/Bialgebra/TensorProduct.lean new file mode 100644 index 0000000000000..1a461c3252fab --- /dev/null +++ b/Mathlib/RingTheory/Bialgebra/TensorProduct.lean @@ -0,0 +1,180 @@ +/- +Copyright (c) 2024 Amelia Livingston. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Amelia Livingston +-/ +import Mathlib.RingTheory.Bialgebra.Equiv +import Mathlib.RingTheory.Coalgebra.TensorProduct +import Mathlib.RingTheory.TensorProduct.Basic + +/-! +# Tensor products of bialgebras + +We define the data in the monoidal structure on the category of bialgebras - e.g. the bialgebra +instance on a tensor product of bialgebras, and the tensor product of two `BialgHom`s as a +`BialgHom`. This is done by combining the corresponding API for coalgebras and algebras. + +## Implementation notes + +Since the coalgebra instance on a tensor product of coalgebras is defined using a universe +monomorphic monoidal category structure on `ModuleCat R`, we require our bialgebras to be in the +same universe as the base ring `R` here too. Any contribution that achieves universe polymorphism +would be welcome. For instance, the tensor product of bialgebras in the +[FLT repo](https://github.com/ImperialCollegeLondon/FLT/blob/eef74b4538c8852363936dfaad23e6ffba72eca5/FLT/mathlibExperiments/Coalgebra/TensorProduct.lean) +is already universe polymorphic since it does not go via category theory. + +-/ + +universe v u + +open scoped TensorProduct + +namespace Bialgebra.TensorProduct + +variable (R A B : Type*) [CommRing R] [Ring A] [Ring B] [Bialgebra R A] [Bialgebra R B] + +lemma counit_eq_algHom_toLinearMap : + Coalgebra.counit (R := R) (A := A ⊗[R] B) = + ((Algebra.TensorProduct.lmul' R).comp (Algebra.TensorProduct.map + (Bialgebra.counitAlgHom R A) (Bialgebra.counitAlgHom R B))).toLinearMap := by + rfl + +lemma comul_eq_algHom_toLinearMap : + Coalgebra.comul (R := R) (A := A ⊗[R] B) = + ((Algebra.TensorProduct.tensorTensorTensorComm R A A B B).toAlgHom.comp + (Algebra.TensorProduct.map (Bialgebra.comulAlgHom R A) + (Bialgebra.comulAlgHom R B))).toLinearMap := by + rfl + +end Bialgebra.TensorProduct + +noncomputable instance TensorProduct.instBialgebra + {R A B : Type u} [CommRing R] [Ring A] [Ring B] + [Bialgebra R A] [Bialgebra R B] : Bialgebra R (A ⊗[R] B) := by + have hcounit := congr(DFunLike.coe $(Bialgebra.TensorProduct.counit_eq_algHom_toLinearMap R A B)) + have hcomul := congr(DFunLike.coe $(Bialgebra.TensorProduct.comul_eq_algHom_toLinearMap R A B)) + refine Bialgebra.mk' R (A ⊗[R] B) ?_ (fun {x y} => ?_) ?_ (fun {x y} => ?_) <;> + simp_all only [AlgHom.toLinearMap_apply] <;> + simp only [_root_.map_one, _root_.map_mul] + +namespace Bialgebra.TensorProduct + +variable {R A B C D : Type u} [CommRing R] [Ring A] [Ring B] [Ring C] [Ring D] + [Bialgebra R A] [Bialgebra R B] [Bialgebra R C] [Bialgebra R D] + +/-- The tensor product of two bialgebra morphisms as a bialgebra morphism. -/ +noncomputable def map (f : A →ₐc[R] B) (g : C →ₐc[R] D) : + A ⊗[R] C →ₐc[R] B ⊗[R] D := + { Coalgebra.TensorProduct.map (f : A →ₗc[R] B) (g : C →ₗc[R] D), + Algebra.TensorProduct.map (f : A →ₐ[R] B) (g : C →ₐ[R] D) with } + +@[simp] +theorem map_tmul (f : A →ₐc[R] B) (g : C →ₐc[R] D) (x : A) (y : C) : + map f g (x ⊗ₜ y) = f x ⊗ₜ g y := + rfl + +@[simp] +theorem map_toCoalgHom (f : A →ₐc[R] B) (g : C →ₐc[R] D) : + map f g = Coalgebra.TensorProduct.map (f : A →ₗc[R] B) (g : C →ₗc[R] D) := rfl + +@[simp] +theorem map_toAlgHom (f : A →ₐc[R] B) (g : C →ₐc[R] D) : + (map f g : A ⊗[R] C →ₐ[R] B ⊗[R] D) = + Algebra.TensorProduct.map (f : A →ₐ[R] B) (g : C →ₐ[R] D) := + rfl + +variable (R A B C) in +/-- The associator for tensor products of R-bialgebras, as a bialgebra equivalence. -/ +protected noncomputable def assoc : + (A ⊗[R] B) ⊗[R] C ≃ₐc[R] A ⊗[R] (B ⊗[R] C) := + { Coalgebra.TensorProduct.assoc R A B C, Algebra.TensorProduct.assoc R A B C with } + +@[simp] +theorem assoc_tmul (x : A) (y : B) (z : C) : + Bialgebra.TensorProduct.assoc R A B C ((x ⊗ₜ y) ⊗ₜ z) = x ⊗ₜ (y ⊗ₜ z) := + rfl + +@[simp] +theorem assoc_symm_tmul (x : A) (y : B) (z : C) : + (Bialgebra.TensorProduct.assoc R A B C).symm (x ⊗ₜ (y ⊗ₜ z)) = (x ⊗ₜ y) ⊗ₜ z := + rfl + +@[simp] +theorem assoc_toCoalgEquiv : + (Bialgebra.TensorProduct.assoc R A B C : _ ≃ₗc[R] _) = + Coalgebra.TensorProduct.assoc R A B C := rfl + +@[simp] +theorem assoc_toAlgEquiv : + (Bialgebra.TensorProduct.assoc R A B C : _ ≃ₐ[R] _) = + Algebra.TensorProduct.assoc R A B C := rfl + +variable (R A) in +/-- The base ring is a left identity for the tensor product of bialgebras, up to +bialgebra equivalence. -/ +protected noncomputable def lid : R ⊗[R] A ≃ₐc[R] A := + { Coalgebra.TensorProduct.lid R A, Algebra.TensorProduct.lid R A with } + +@[simp] +theorem lid_toCoalgEquiv : + (Bialgebra.TensorProduct.lid R A : R ⊗[R] A ≃ₗc[R] A) = Coalgebra.TensorProduct.lid R A := rfl + +@[simp] +theorem lid_toAlgEquiv : + (Bialgebra.TensorProduct.lid R A : R ⊗[R] A ≃ₐ[R] A) = Algebra.TensorProduct.lid R A := rfl + +@[simp] +theorem lid_tmul (r : R) (a : A) : Bialgebra.TensorProduct.lid R A (r ⊗ₜ a) = r • a := rfl + +@[simp] +theorem lid_symm_apply (a : A) : (Bialgebra.TensorProduct.lid R A).symm a = 1 ⊗ₜ a := rfl + +/- TODO: make this defeq, which would involve adding a heterobasic version of +`Coalgebra.TensorProduct.rid`. -/ +theorem coalgebra_rid_eq_algebra_rid_apply (x : A ⊗[R] R) : + Coalgebra.TensorProduct.rid R A x = Algebra.TensorProduct.rid R R A x := + congr($((TensorProduct.AlgebraTensorModule.rid_eq_rid R A).symm) x) + +variable (R A) in +/-- The base ring is a right identity for the tensor product of bialgebras, up to +bialgebra equivalence. -/ +protected noncomputable def rid : A ⊗[R] R ≃ₐc[R] A where + toCoalgEquiv := Coalgebra.TensorProduct.rid R A + map_mul' x y := by + simp only [CoalgEquiv.toCoalgHom_eq_coe, CoalgHom.toLinearMap_eq_coe, AddHom.toFun_eq_coe, + LinearMap.coe_toAddHom, CoalgHom.coe_toLinearMap, CoalgHom.coe_coe, + coalgebra_rid_eq_algebra_rid_apply, map_mul] + +@[simp] +theorem rid_toCoalgEquiv : + (Bialgebra.TensorProduct.rid R A : A ⊗[R] R ≃ₗc[R] A) = Coalgebra.TensorProduct.rid R A := rfl + +@[simp] +theorem rid_toAlgEquiv : + (Bialgebra.TensorProduct.rid R A : A ⊗[R] R ≃ₐ[R] A) = Algebra.TensorProduct.rid R R A := by + ext x + exact coalgebra_rid_eq_algebra_rid_apply x + +@[simp] +theorem rid_tmul (r : R) (a : A) : Bialgebra.TensorProduct.rid R A (a ⊗ₜ r) = r • a := rfl + +@[simp] +theorem rid_symm_apply (a : A) : (Bialgebra.TensorProduct.rid R A).symm a = a ⊗ₜ 1 := rfl + +end Bialgebra.TensorProduct +namespace BialgHom + +variable {R A B C : Type u} [CommRing R] [Ring A] [Ring B] [Ring C] + [Bialgebra R A] [Bialgebra R B] [Bialgebra R C] + +variable (A) + +/-- `lTensor A f : A ⊗ B →ₐc A ⊗ C` is the natural bialgebra morphism induced by `f : B →ₐc C`. -/ +noncomputable abbrev lTensor (f : B →ₐc[R] C) : A ⊗[R] B →ₐc[R] A ⊗[R] C := + Bialgebra.TensorProduct.map (BialgHom.id R A) f + +/-- `rTensor A f : B ⊗ A →ₐc C ⊗ A` is the natural bialgebra morphism induced by `f : B →ₐc C`. -/ +noncomputable abbrev rTensor (f : B →ₐc[R] C) : B ⊗[R] A →ₐc[R] C ⊗[R] A := + Bialgebra.TensorProduct.map f (BialgHom.id R A) + +end BialgHom diff --git a/Mathlib/RingTheory/Binomial.lean b/Mathlib/RingTheory/Binomial.lean index 45bbba6501dad..ad5a0893a9a04 100644 --- a/Mathlib/RingTheory/Binomial.lean +++ b/Mathlib/RingTheory/Binomial.lean @@ -175,7 +175,7 @@ theorem ascPochhammer_smeval_cast (R : Type*) [Semiring R] {S : Type*} [NonAssoc simp only [← C_eq_natCast, smeval_C_mul, hn, Nat.cast_smul_eq_nsmul R n] simp only [nsmul_eq_mul, Nat.cast_id] -variable {R S : Type*} +variable {R : Type*} theorem ascPochhammer_smeval_eq_eval [Semiring R] (r : R) (n : ℕ) : (ascPochhammer ℕ n).smeval r = (ascPochhammer R n).eval r := by @@ -225,7 +225,7 @@ section Basic_Instances open Polynomial instance Nat.instBinomialRing : BinomialRing ℕ where - nsmul_right_injective n hn r s hrs := Nat.eq_of_mul_eq_mul_left (Nat.pos_of_ne_zero hn) hrs + 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 factorial_nsmul_multichoose r n := by rw [smul_eq_mul, ← Nat.descFactorial_eq_factorial_mul_choose, @@ -238,7 +238,7 @@ def Int.multichoose (n : ℤ) (k : ℕ) : ℤ := | negSucc n => (-1) ^ k * Nat.choose (n + 1) k instance Int.instBinomialRing : BinomialRing ℤ where - nsmul_right_injective n hn r s 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] diff --git a/Mathlib/RingTheory/ChainOfDivisors.lean b/Mathlib/RingTheory/ChainOfDivisors.lean index 684edca6086c9..c188aa8e7b497 100644 --- a/Mathlib/RingTheory/ChainOfDivisors.lean +++ b/Mathlib/RingTheory/ChainOfDivisors.lean @@ -302,32 +302,28 @@ theorem mem_normalizedFactors_factor_orderIso_of_mem_normalizedFactors {m p : As rw [associated_iff_eq] at hq' rwa [hq'] -variable [DecidableRel ((· ∣ ·) : M → M → Prop)] [DecidableRel ((· ∣ ·) : N → N → Prop)] - -theorem multiplicity_prime_le_multiplicity_image_by_factor_orderIso {m p : Associates M} +theorem emultiplicity_prime_le_emultiplicity_image_by_factor_orderIso {m p : Associates M} {n : Associates N} (hp : p ∈ normalizedFactors m) (d : Set.Iic m ≃o Set.Iic n) : - multiplicity p m ≤ multiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n := by + emultiplicity p m ≤ emultiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n := by by_cases hn : n = 0 · simp [hn] by_cases hm : m = 0 · simp [hm] at hp - rw [← - PartENat.natCast_get - (finite_iff_dom.1 <| finite_prime_left (prime_of_normalized_factor p hp) hm), - ← pow_dvd_iff_le_multiplicity] - exact pow_image_of_prime_by_factor_orderIso_dvd hn hp d (pow_multiplicity_dvd _) + rw [(finite_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 multiplicity_prime_eq_multiplicity_image_by_factor_orderIso {m p : Associates M} +theorem emultiplicity_prime_eq_emultiplicity_image_by_factor_orderIso {m p : Associates M} {n : Associates N} (hn : n ≠ 0) (hp : p ∈ normalizedFactors m) (d : Set.Iic m ≃o Set.Iic n) : - multiplicity p m = multiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n := by - refine le_antisymm (multiplicity_prime_le_multiplicity_image_by_factor_orderIso hp d) ?_ - suffices multiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n ≤ - multiplicity (↑(d.symm (d ⟨p, dvd_of_mem_normalizedFactors hp⟩))) m by + emultiplicity p m = emultiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n := by + refine le_antisymm (emultiplicity_prime_le_emultiplicity_image_by_factor_orderIso hp d) ?_ + suffices emultiplicity (↑(d ⟨p, dvd_of_mem_normalizedFactors hp⟩)) n ≤ + emultiplicity (↑(d.symm (d ⟨p, dvd_of_mem_normalizedFactors hp⟩))) m by rw [d.symm_apply_apply ⟨p, dvd_of_mem_normalizedFactors hp⟩, Subtype.coe_mk] at this exact this letI := Classical.decEq (Associates N) simpa only [Subtype.coe_eta] using - multiplicity_prime_le_multiplicity_image_by_factor_orderIso + emultiplicity_prime_le_emultiplicity_image_by_factor_orderIso (mem_normalizedFactors_factor_orderIso_of_mem_normalizedFactors hn hp d) d.symm end @@ -401,17 +397,15 @@ theorem mem_normalizedFactors_factor_dvd_iso_of_mem_normalizedFactors {m p : M} (mk_le_mk_of_dvd (dvd_of_mem_normalizedFactors hp)) simpa only [associated_iff_eq.mp hq', associatesEquivOfUniqueUnits_symm_apply] using hq -variable [DecidableRel ((· ∣ ·) : M → M → Prop)] [DecidableRel ((· ∣ ·) : N → N → Prop)] - -theorem multiplicity_factor_dvd_iso_eq_multiplicity_of_mem_normalizedFactors {m p : M} {n : N} +theorem emultiplicity_factor_dvd_iso_eq_emultiplicity_of_mem_normalizedFactors {m p : M} {n : N} (hm : m ≠ 0) (hn : n ≠ 0) (hp : p ∈ normalizedFactors m) {d : { l : M // l ∣ m } ≃ { l : N // l ∣ n }} (hd : ∀ l l', (d l : N) ∣ d l' ↔ (l : M) ∣ l') : - multiplicity (d ⟨p, dvd_of_mem_normalizedFactors hp⟩ : N) n = multiplicity p m := by + emultiplicity (d ⟨p, dvd_of_mem_normalizedFactors hp⟩ : N) n = emultiplicity p m := by apply Eq.symm - suffices multiplicity (Associates.mk p) (Associates.mk m) = multiplicity (Associates.mk + suffices emultiplicity (Associates.mk p) (Associates.mk m) = emultiplicity (Associates.mk ↑(d ⟨associatesEquivOfUniqueUnits (associatesEquivOfUniqueUnits.symm p), by simp [dvd_of_mem_normalizedFactors hp]⟩)) (Associates.mk n) by - simpa only [multiplicity_mk_eq_multiplicity, associatesEquivOfUniqueUnits_symm_apply, + simpa only [emultiplicity_mk_eq_emultiplicity, associatesEquivOfUniqueUnits_symm_apply, associatesEquivOfUniqueUnits_apply, out_mk, normalize_eq] using this have : Associates.mk (d ⟨associatesEquivOfUniqueUnits (associatesEquivOfUniqueUnits.symm p), by simp only [dvd_of_mem_normalizedFactors hp, associatesEquivOfUniqueUnits_symm_apply, @@ -422,7 +416,7 @@ theorem multiplicity_factor_dvd_iso_eq_multiplicity_of_mem_normalizedFactors {m rw [mkFactorOrderIsoOfFactorDvdEquiv_apply_coe] rw [this] refine - multiplicity_prime_eq_multiplicity_image_by_factor_orderIso (mk_ne_zero.mpr hn) ?_ + emultiplicity_prime_eq_emultiplicity_image_by_factor_orderIso (mk_ne_zero.mpr hn) ?_ (mkFactorOrderIsoOfFactorDvdEquiv hd) obtain ⟨q, hq, hq'⟩ := exists_mem_normalizedFactors_of_dvd (mk_ne_zero.mpr hm) diff --git a/Mathlib/RingTheory/ClassGroup.lean b/Mathlib/RingTheory/ClassGroup.lean index 1fee05b58a3b4..5080c842c49b5 100644 --- a/Mathlib/RingTheory/ClassGroup.lean +++ b/Mathlib/RingTheory/ClassGroup.lean @@ -27,11 +27,7 @@ identical no matter the choice of field of fractions for `R`. -/ -variable {R K L : Type*} [CommRing R] -variable [Field K] [Field L] [DecidableEq L] -variable [Algebra R K] [IsFractionRing R K] -variable [Algebra K L] [FiniteDimensional K L] -variable [Algebra R L] [IsScalarTower R K L] +variable {R K : Type*} [CommRing R] [Field K] [Algebra R K] [IsFractionRing R K] open scoped nonZeroDivisors diff --git a/Mathlib/RingTheory/Coalgebra/Basic.lean b/Mathlib/RingTheory/Coalgebra/Basic.lean index 643086a03c0e1..bb611315a00d3 100644 --- a/Mathlib/RingTheory/Coalgebra/Basic.lean +++ b/Mathlib/RingTheory/Coalgebra/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Ali Ramsey, Eric Wieser -/ import Mathlib.Algebra.Algebra.Bilinear -import Mathlib.LinearAlgebra.Finsupp +import Mathlib.LinearAlgebra.DFinsupp import Mathlib.LinearAlgebra.Prod import Mathlib.LinearAlgebra.TensorProduct.Finiteness @@ -15,7 +15,7 @@ In this file we define `Coalgebra`, and provide instances for: * Commutative semirings: `CommSemiring.toCoalgebra` * Binary products: `Prod.instCoalgebra` -* Finitely supported functions: `Finsupp.instCoalgebra` +* Finitely supported functions: `DFinsupp.instCoalgebra`, `Finsupp.instCoalgebra` ## References @@ -259,6 +259,68 @@ instance instCoalgebra : Coalgebra R (A × B) where end Prod +namespace DFinsupp +variable (R : Type u) (ι : Type v) (A : ι → Type w) +variable [DecidableEq ι] +variable [CommSemiring R] [∀ i, AddCommMonoid (A i)] [∀ i, Module R (A i)] [∀ i, Coalgebra R (A i)] + +open LinearMap + +instance instCoalgebraStruct : CoalgebraStruct R (Π₀ i, A i) where + comul := DFinsupp.lsum R fun i => + TensorProduct.map (DFinsupp.lsingle i) (DFinsupp.lsingle i) ∘ₗ comul + counit := DFinsupp.lsum R fun _ => counit + +@[simp] +theorem comul_single (i : ι) (a : A i) : + comul (R := R) (DFinsupp.single i a) = + (TensorProduct.map (DFinsupp.lsingle i) (DFinsupp.lsingle i) : _ →ₗ[R] _) (comul a) := + lsum_single _ _ _ _ + +@[simp] +theorem counit_single (i : ι) (a : A i) : counit (DFinsupp.single i a) = counit (R := R) a := + lsum_single _ _ _ _ + +theorem comul_comp_lsingle (i : ι) : + comul ∘ₗ (lsingle i : A i →ₗ[R] _) = TensorProduct.map (lsingle i) (lsingle i) ∘ₗ comul := by + ext; simp + +theorem comul_comp_lapply (i : ι) : + comul ∘ₗ (lapply i : _ →ₗ[R] A i) = TensorProduct.map (lapply i) (lapply i) ∘ₗ comul := by + ext j : 1 + conv_rhs => rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, ← TensorProduct.map_comp] + obtain rfl | hij := eq_or_ne i j + · rw [comp_assoc, lapply_comp_lsingle_same, comp_id, TensorProduct.map_id, id_comp] + · rw [comp_assoc, lapply_comp_lsingle_of_ne _ _ hij, comp_zero, TensorProduct.map_zero_left, + zero_comp] + +@[simp] theorem counit_comp_lsingle (i : ι) : counit ∘ₗ (lsingle i : A i →ₗ[R] _) = counit := by + ext; simp + +/-- The `R`-module whose elements are dependent functions `(i : ι) → A i` which are zero on all but +finitely many elements of `ι` has a coalgebra structure. + +The coproduct `Δ` is given by `Δ(fᵢ a) = fᵢ a₁ ⊗ fᵢ a₂` where `Δ(a) = a₁ ⊗ a₂` and the counit `ε` +by `ε(fᵢ a) = ε(a)`, where `fᵢ a` is the function sending `i` to `a` and all other elements of `ι` +to zero. -/ +instance instCoalgebra : Coalgebra R (Π₀ i, A i) where + rTensor_counit_comp_comul := by + ext : 1 + rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, rTensor_comp_map, counit_comp_lsingle, + ← lTensor_comp_rTensor, comp_assoc, rTensor_counit_comp_comul, lTensor_comp_mk] + lTensor_counit_comp_comul := by + ext : 1 + rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, lTensor_comp_map, counit_comp_lsingle, + ← rTensor_comp_lTensor, comp_assoc, lTensor_counit_comp_comul, rTensor_comp_flip_mk] + coassoc := by + ext i : 1 + simp_rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, lTensor_comp_map, comul_comp_lsingle, + comp_assoc, ← comp_assoc comul, rTensor_comp_map, comul_comp_lsingle, ← map_comp_rTensor, + ← map_comp_lTensor, comp_assoc, ← coassoc, ← comp_assoc comul, ← comp_assoc, + TensorProduct.map_map_comp_assoc_eq] + +end DFinsupp + namespace Finsupp variable (R : Type u) (ι : Type v) (A : Type w) variable [CommSemiring R] [AddCommMonoid A] [Module R A] [Coalgebra R A] diff --git a/Mathlib/RingTheory/Coalgebra/Hom.lean b/Mathlib/RingTheory/Coalgebra/Hom.lean index c6c26e0bf65b9..2c15ce54d3b1a 100644 --- a/Mathlib/RingTheory/Coalgebra/Hom.lean +++ b/Mathlib/RingTheory/Coalgebra/Hom.lean @@ -241,10 +241,10 @@ theorem map_smul_of_tower {R'} [SMul R' A] [SMul R' B] [LinearMap.CompatibleSMul @[simps (config := .lemmasOnly) toSemigroup_toMul_mul toOne_one] instance End : Monoid (A →ₗc[R] A) where mul := comp - mul_assoc ϕ ψ χ := rfl + mul_assoc _ _ _ := rfl one := CoalgHom.id R A - one_mul ϕ := ext fun x => rfl - mul_one ϕ := ext fun x => rfl + one_mul _ := ext fun _ => rfl + mul_one _ := ext fun _ => rfl @[simp] theorem one_apply (x : A) : (1 : A →ₗc[R] A) x = x := diff --git a/Mathlib/RingTheory/Coalgebra/TensorProduct.lean b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean index dcd8d8d13df2e..5226e76ef5d0e 100644 --- a/Mathlib/RingTheory/Coalgebra/TensorProduct.lean +++ b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean @@ -58,7 +58,7 @@ noncomputable instance TensorProduct.instCoalgebra : Coalgebra R (M ⊗[R] N) := rw [CoalgebraCat.ofComonObjCoalgebraStruct_comul] simp [-Mon_.monMonoidalStruct_tensorObj_X, ModuleCat.MonoidalCategory.instMonoidalCategoryStruct_tensorHom, - ModuleCat.comp_def, ModuleCat.of, ModuleCat.ofHom, + ModuleCat.comp_def, ModuleCat.of, ModuleCat.asHom, ModuleCat.MonoidalCategory.tensor_μ_eq_tensorTensorTensorComm] } end diff --git a/Mathlib/RingTheory/Congruence/Basic.lean b/Mathlib/RingTheory/Congruence/Basic.lean index 131575077c37b..71c5a38f0e9a6 100644 --- a/Mathlib/RingTheory/Congruence/Basic.lean +++ b/Mathlib/RingTheory/Congruence/Basic.lean @@ -4,15 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Ring.Action.Basic -import Mathlib.Algebra.Ring.Hom.Defs -import Mathlib.Algebra.Ring.InjSurj import Mathlib.GroupTheory.Congruence.Basic +import Mathlib.RingTheory.Congruence.Defs /-! # Congruence relations on rings -This file defines congruence relations on rings, which extend `Con` and `AddCon` on monoids and -additive monoids. +This file contains basic results concerning congruence relations on rings, +which extend `Con` and `AddCon` on monoids and additive monoids. Most of the time you likely want to use the `Ideal.Quotient` API that is built on top of this. @@ -28,206 +27,19 @@ Most of the time you likely want to use the `Ideal.Quotient` API that is built o * Copy across more API from `Con` and `AddCon` in `GroupTheory/Congruence.lean`. -/ - -/-- A congruence relation on a type with an addition and multiplication is an equivalence relation -which preserves both. -/ -structure RingCon (R : Type*) [Add R] [Mul R] extends Con R, AddCon R where - -/-- The induced multiplicative congruence from a `RingCon`. -/ -add_decl_doc RingCon.toCon - -/-- The induced additive congruence from a `RingCon`. -/ -add_decl_doc RingCon.toAddCon - variable {α R : Type*} -/-- The inductively defined smallest ring congruence relation containing a given binary - relation. -/ -inductive RingConGen.Rel [Add R] [Mul R] (r : R → R → Prop) : R → R → Prop - | of : ∀ x y, r x y → RingConGen.Rel r x y - | refl : ∀ x, RingConGen.Rel r x x - | symm : ∀ {x y}, RingConGen.Rel r x y → RingConGen.Rel r y x - | trans : ∀ {x y z}, RingConGen.Rel r x y → RingConGen.Rel r y z → RingConGen.Rel r x z - | add : ∀ {w x y z}, RingConGen.Rel r w x → RingConGen.Rel r y z → - RingConGen.Rel r (w + y) (x + z) - | mul : ∀ {w x y z}, RingConGen.Rel r w x → RingConGen.Rel r y z → - RingConGen.Rel r (w * y) (x * z) - -/-- The inductively defined smallest ring congruence relation containing a given binary - relation. -/ -def ringConGen [Add R] [Mul R] (r : R → R → Prop) : RingCon R where - r := RingConGen.Rel r - iseqv := ⟨RingConGen.Rel.refl, @RingConGen.Rel.symm _ _ _ _, @RingConGen.Rel.trans _ _ _ _⟩ - add' := RingConGen.Rel.add - mul' := RingConGen.Rel.mul - namespace RingCon -section Basic - -variable [Add R] [Mul R] (c : RingCon R) - -/-- A coercion from a congruence relation to its underlying binary relation. -/ -instance : FunLike (RingCon R) R (R → Prop) where - coe c := c.r - coe_injective' x y h := by - rcases x with ⟨⟨x, _⟩, _⟩ - rcases y with ⟨⟨y, _⟩, _⟩ - congr! - rw [Setoid.ext_iff, (show x.Rel = y.Rel from h)] - simp - -theorem rel_eq_coe : c.r = c := - rfl - -@[simp] -theorem toCon_coe_eq_coe : (c.toCon : R → R → Prop) = c := - rfl - -protected theorem refl (x) : c x x := - c.refl' x - -protected theorem symm {x y} : c x y → c y x := - c.symm' - -protected theorem trans {x y z} : c x y → c y z → c x z := - c.trans' - -protected theorem add {w x y z} : c w x → c y z → c (w + y) (x + z) := - c.add' - -protected theorem mul {w x y z} : c w x → c y z → c (w * y) (x * z) := - c.mul' - -protected theorem sub {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) - {a b c d : S} (h : t a b) (h' : t c d) : t (a - c) (b - d) := t.toAddCon.sub h h' - -protected theorem neg {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) - {a b} (h : t a b) : t (-a) (-b) := t.toAddCon.neg h - -protected theorem nsmul {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) - (m : ℕ) {x y : S} (hx : t x y) : t (m • x) (m • y) := t.toAddCon.nsmul m hx - -protected theorem zsmul {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) - (z : ℤ) {x y : S} (hx : t x y) : t (z • x) (z • y) := t.toAddCon.zsmul z hx - -instance : Inhabited (RingCon R) := - ⟨ringConGen EmptyRelation⟩ - -@[simp] -theorem rel_mk {s : Con R} {h a b} : RingCon.mk s h a b ↔ s a b := - Iff.rfl - -/-- The map sending a congruence relation to its underlying binary relation is injective. -/ -theorem ext' {c d : RingCon R} (H : ⇑c = ⇑d) : c = d := DFunLike.coe_injective H - -/-- Extensionality rule for congruence relations. -/ -theorem ext {c d : RingCon R} (H : ∀ x y, c x y ↔ d x y) : c = d := - ext' <| by ext; apply H - -/-- -Pulling back a `RingCon` across a ring homomorphism. --/ -def comap {R R' F : Type*} [Add R] [Add R'] - [FunLike F R R'] [AddHomClass F R R'] [Mul R] [Mul R'] [MulHomClass F R R'] - (J : RingCon R') (f : F) : - RingCon R where - __ := J.toCon.comap f (map_mul f) - __ := J.toAddCon.comap f (map_add f) - -end Basic - section Quotient -section Basic - -variable [Add R] [Mul R] (c : RingCon R) - -/-- Defining the quotient by a congruence relation of a type with addition and multiplication. -/ -protected def Quotient := - Quotient c.toSetoid - -variable {c} - -/-- The morphism into the quotient by a congruence relation -/ -@[coe] def toQuotient (r : R) : c.Quotient := - @Quotient.mk'' _ c.toSetoid r - -variable (c) - -/-- Coercion from a type with addition and multiplication to its quotient by a congruence relation. - -See Note [use has_coe_t]. -/ -instance : CoeTC R c.Quotient := - ⟨toQuotient⟩ - --- Lower the priority since it unifies with any quotient type. -/-- The quotient by a decidable congruence relation has decidable equality. -/ -instance (priority := 500) [_d : ∀ a b, Decidable (c a b)] : DecidableEq c.Quotient := - inferInstanceAs (DecidableEq (Quotient c.toSetoid)) - -@[simp] -theorem quot_mk_eq_coe (x : R) : Quot.mk c x = (x : c.Quotient) := - rfl - -/-- Two elements are related by a congruence relation `c` iff they are represented by the same -element of the quotient by `c`. -/ -@[simp] -protected theorem eq {a b : R} : (a : c.Quotient) = (b : c.Quotient) ↔ c a b := - Quotient.eq'' - -end Basic +section Algebraic -/-! ### Basic notation +/-! ### Scalar multiplication -The basic algebraic notation, `0`, `1`, `+`, `*`, `-`, `^`, descend naturally under the quotient +The operation of scalar multiplication `•` descends naturally to the quotient. -/ - -section Data - -section add_mul - -variable [Add R] [Mul R] (c : RingCon R) - -instance : Add c.Quotient := inferInstanceAs (Add c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_add (x y : R) : (↑(x + y) : c.Quotient) = ↑x + ↑y := - rfl - -instance : Mul c.Quotient := inferInstanceAs (Mul c.toCon.Quotient) - -@[simp, norm_cast] -theorem coe_mul (x y : R) : (↑(x * y) : c.Quotient) = ↑x * ↑y := - rfl - -end add_mul - -section Zero - -variable [AddZeroClass R] [Mul R] (c : RingCon R) - -instance : Zero c.Quotient := inferInstanceAs (Zero c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_zero : (↑(0 : R) : c.Quotient) = 0 := - rfl - -end Zero - -section One - -variable [Add R] [MulOneClass R] (c : RingCon R) - -instance : One c.Quotient := inferInstanceAs (One c.toCon.Quotient) - -@[simp, norm_cast] -theorem coe_one : (↑(1 : R) : c.Quotient) = 1 := - rfl - -end One - section SMul variable [Add R] [MulOneClass R] [SMul α R] [IsScalarTower α R R] (c : RingCon R) @@ -240,142 +52,6 @@ theorem coe_smul (a : α) (x : R) : (↑(a • x) : c.Quotient) = a • (x : c.Q end SMul -section NegSubZSMul - -variable [AddGroup R] [Mul R] (c : RingCon R) - -instance : Neg c.Quotient := inferInstanceAs (Neg c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_neg (x : R) : (↑(-x) : c.Quotient) = -x := - rfl - -instance : Sub c.Quotient := inferInstanceAs (Sub c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_sub (x y : R) : (↑(x - y) : c.Quotient) = x - y := - rfl - -instance hasZSMul : SMul ℤ c.Quotient := inferInstanceAs (SMul ℤ c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_zsmul (z : ℤ) (x : R) : (↑(z • x) : c.Quotient) = z • (x : c.Quotient) := - rfl - -end NegSubZSMul - -section NSMul - -variable [AddMonoid R] [Mul R] (c : RingCon R) - -instance hasNSMul : SMul ℕ c.Quotient := inferInstanceAs (SMul ℕ c.toAddCon.Quotient) - -@[simp, norm_cast] -theorem coe_nsmul (n : ℕ) (x : R) : (↑(n • x) : c.Quotient) = n • (x : c.Quotient) := - rfl - -end NSMul - -section Pow - -variable [Add R] [Monoid R] (c : RingCon R) - -instance : Pow c.Quotient ℕ := inferInstanceAs (Pow c.toCon.Quotient ℕ) - -@[simp, norm_cast] -theorem coe_pow (x : R) (n : ℕ) : (↑(x ^ n) : c.Quotient) = (x : c.Quotient) ^ n := - rfl - -end Pow - -section NatCast - -variable [AddMonoidWithOne R] [Mul R] (c : RingCon R) - -instance : NatCast c.Quotient := - ⟨fun n => ↑(n : R)⟩ - -@[simp, norm_cast] -theorem coe_natCast (n : ℕ) : (↑(n : R) : c.Quotient) = n := - rfl - -@[deprecated (since := "2024-04-17")] -alias coe_nat_cast := coe_natCast - -end NatCast - -section IntCast - -variable [AddGroupWithOne R] [Mul R] (c : RingCon R) - -instance : IntCast c.Quotient := - ⟨fun z => ↑(z : R)⟩ - -@[simp, norm_cast] -theorem coe_intCast (n : ℕ) : (↑(n : R) : c.Quotient) = n := - rfl - -@[deprecated (since := "2024-04-17")] -alias coe_int_cast := coe_intCast - -end IntCast - -instance [Inhabited R] [Add R] [Mul R] (c : RingCon R) : Inhabited c.Quotient := - ⟨↑(default : R)⟩ - -end Data - -/-! ### Algebraic structure - -The operations above on the quotient by `c : RingCon R` preserve the algebraic structure of `R`. --/ - - -section Algebraic - -instance [NonUnitalNonAssocSemiring R] (c : RingCon R) : NonUnitalNonAssocSemiring c.Quotient := - Function.Surjective.nonUnitalNonAssocSemiring _ Quotient.surjective_Quotient_mk'' rfl - (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl - -instance [NonAssocSemiring R] (c : RingCon R) : NonAssocSemiring c.Quotient := - Function.Surjective.nonAssocSemiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl - -instance [NonUnitalSemiring R] (c : RingCon R) : NonUnitalSemiring c.Quotient := - Function.Surjective.nonUnitalSemiring _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) - (fun _ _ => rfl) fun _ _ => rfl - -instance [Semiring R] (c : RingCon R) : Semiring c.Quotient := - Function.Surjective.semiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl - -instance [CommSemiring R] (c : RingCon R) : CommSemiring c.Quotient := - Function.Surjective.commSemiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl - -instance [NonUnitalNonAssocRing R] (c : RingCon R) : NonUnitalNonAssocRing c.Quotient := - Function.Surjective.nonUnitalNonAssocRing _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl - -instance [NonAssocRing R] (c : RingCon R) : NonAssocRing c.Quotient := - Function.Surjective.nonAssocRing _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) - (fun _ => rfl) fun _ => rfl - -instance [NonUnitalRing R] (c : RingCon R) : NonUnitalRing c.Quotient := - Function.Surjective.nonUnitalRing _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl - -instance [Ring R] (c : RingCon R) : Ring c.Quotient := - Function.Surjective.ring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl - -instance [CommRing R] (c : RingCon R) : CommRing c.Quotient := - Function.Surjective.commRing _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) - (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl - instance isScalarTower_right [Add R] [MulOneClass R] [SMul α R] [IsScalarTower α R R] (c : RingCon R) : IsScalarTower α c.Quotient c.Quotient where smul_assoc _ := Quotient.ind₂' fun _ _ => congr_arg Quotient.mk'' <| smul_mul_assoc _ _ _ @@ -403,14 +79,6 @@ instance [Monoid α] [Semiring R] [MulSemiringAction α R] [IsScalarTower α R R end Algebraic -/-- The natural homomorphism from a ring to its quotient by a congruence relation. -/ -def mk' [NonAssocSemiring R] (c : RingCon R) : R →+* c.Quotient where - toFun := toQuotient - map_zero' := rfl - map_one' := rfl - map_add' _ _ := rfl - map_mul' _ _ := rfl - end Quotient /-! ### Lattice structure @@ -445,7 +113,7 @@ instance : InfSet (RingCon R) where /-- The infimum of a set of congruence relations is the same as the infimum of the set's image under the map to the underlying equivalence relation. -/ theorem sInf_toSetoid (S : Set (RingCon R)) : (sInf S).toSetoid = sInf ((·.toSetoid) '' S) := - Setoid.ext' fun x y => + Setoid.ext fun x y => ⟨fun h r ⟨c, hS, hr⟩ => by rw [← hr]; exact h c hS, fun h c hS => h c.toSetoid ⟨c, hS, rfl⟩⟩ /-- The infimum of a set of congruence relations is the same as the infimum of the set's image diff --git a/Mathlib/RingTheory/Congruence/BigOperators.lean b/Mathlib/RingTheory/Congruence/BigOperators.lean index e509e77a15ad2..52d8c1aaa155f 100644 --- a/Mathlib/RingTheory/Congruence/BigOperators.lean +++ b/Mathlib/RingTheory/Congruence/BigOperators.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.GroupTheory.Congruence.BigOperators -import Mathlib.RingTheory.Congruence.Basic +import Mathlib.RingTheory.Congruence.Defs /-! # Interactions between `∑, ∏` and `RingCon` diff --git a/Mathlib/RingTheory/Congruence/Defs.lean b/Mathlib/RingTheory/Congruence/Defs.lean new file mode 100644 index 0000000000000..a23284f428ff7 --- /dev/null +++ b/Mathlib/RingTheory/Congruence/Defs.lean @@ -0,0 +1,378 @@ +/- +Copyright (c) 2022 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Algebra.Ring.Hom.Defs +import Mathlib.Algebra.Ring.InjSurj +import Mathlib.GroupTheory.Congruence.Defs + +/-! +# Congruence relations on rings + +This file defines congruence relations on rings, which extend `Con` and `AddCon` on monoids and +additive monoids. + +Most of the time you likely want to use the `Ideal.Quotient` API that is built on top of this. + +## Main Definitions + +* `RingCon R`: the type of congruence relations respecting `+` and `*`. +* `RingConGen r`: the inductively defined smallest ring congruence relation containing a given + binary relation. + +## TODO + +* Use this for `RingQuot` too. +* Copy across more API from `Con` and `AddCon` in `GroupTheory/Congruence.lean`. +-/ + + +/-- A congruence relation on a type with an addition and multiplication is an equivalence relation +which preserves both. -/ +structure RingCon (R : Type*) [Add R] [Mul R] extends Con R, AddCon R where + +/-- The induced multiplicative congruence from a `RingCon`. -/ +add_decl_doc RingCon.toCon + +/-- The induced additive congruence from a `RingCon`. -/ +add_decl_doc RingCon.toAddCon + +variable {α R : Type*} + +/-- The inductively defined smallest ring congruence relation containing a given binary + relation. -/ +inductive RingConGen.Rel [Add R] [Mul R] (r : R → R → Prop) : R → R → Prop + | of : ∀ x y, r x y → RingConGen.Rel r x y + | refl : ∀ x, RingConGen.Rel r x x + | symm : ∀ {x y}, RingConGen.Rel r x y → RingConGen.Rel r y x + | trans : ∀ {x y z}, RingConGen.Rel r x y → RingConGen.Rel r y z → RingConGen.Rel r x z + | add : ∀ {w x y z}, RingConGen.Rel r w x → RingConGen.Rel r y z → + RingConGen.Rel r (w + y) (x + z) + | mul : ∀ {w x y z}, RingConGen.Rel r w x → RingConGen.Rel r y z → + RingConGen.Rel r (w * y) (x * z) + +/-- The inductively defined smallest ring congruence relation containing a given binary + relation. -/ +def ringConGen [Add R] [Mul R] (r : R → R → Prop) : RingCon R where + r := RingConGen.Rel r + iseqv := ⟨RingConGen.Rel.refl, @RingConGen.Rel.symm _ _ _ _, @RingConGen.Rel.trans _ _ _ _⟩ + add' := RingConGen.Rel.add + mul' := RingConGen.Rel.mul + +namespace RingCon + +section Basic + +variable [Add R] [Mul R] (c : RingCon R) + +/-- A coercion from a congruence relation to its underlying binary relation. -/ +instance : FunLike (RingCon R) R (R → Prop) where + coe c := c.r + coe_injective' x y h := by + rcases x with ⟨⟨x, _⟩, _⟩ + rcases y with ⟨⟨y, _⟩, _⟩ + congr! + rw [Setoid.ext_iff, (show ⇑x = ⇑y from h)] + simp + +theorem rel_eq_coe : c.r = c := + rfl + +@[simp] +theorem toCon_coe_eq_coe : (c.toCon : R → R → Prop) = c := + rfl + +protected theorem refl (x) : c x x := + c.refl' x + +protected theorem symm {x y} : c x y → c y x := + c.symm' + +protected theorem trans {x y z} : c x y → c y z → c x z := + c.trans' + +protected theorem add {w x y z} : c w x → c y z → c (w + y) (x + z) := + c.add' + +protected theorem mul {w x y z} : c w x → c y z → c (w * y) (x * z) := + c.mul' + +protected theorem sub {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) + {a b c d : S} (h : t a b) (h' : t c d) : t (a - c) (b - d) := t.toAddCon.sub h h' + +protected theorem neg {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) + {a b} (h : t a b) : t (-a) (-b) := t.toAddCon.neg h + +protected theorem nsmul {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) + (m : ℕ) {x y : S} (hx : t x y) : t (m • x) (m • y) := t.toAddCon.nsmul m hx + +protected theorem zsmul {S : Type*} [AddGroup S] [Mul S] (t : RingCon S) + (z : ℤ) {x y : S} (hx : t x y) : t (z • x) (z • y) := t.toAddCon.zsmul z hx + +instance : Inhabited (RingCon R) := + ⟨ringConGen EmptyRelation⟩ + +@[simp] +theorem rel_mk {s : Con R} {h a b} : RingCon.mk s h a b ↔ s a b := + Iff.rfl + +/-- The map sending a congruence relation to its underlying binary relation is injective. -/ +theorem ext' {c d : RingCon R} (H : ⇑c = ⇑d) : c = d := DFunLike.coe_injective H + +/-- Extensionality rule for congruence relations. -/ +theorem ext {c d : RingCon R} (H : ∀ x y, c x y ↔ d x y) : c = d := + ext' <| by ext; apply H + +/-- +Pulling back a `RingCon` across a ring homomorphism. +-/ +def comap {R R' F : Type*} [Add R] [Add R'] + [FunLike F R R'] [AddHomClass F R R'] [Mul R] [Mul R'] [MulHomClass F R R'] + (J : RingCon R') (f : F) : + RingCon R where + __ := J.toCon.comap f (map_mul f) + __ := J.toAddCon.comap f (map_add f) + +end Basic + +section Quotient + +section Basic + +variable [Add R] [Mul R] (c : RingCon R) + +/-- Defining the quotient by a congruence relation of a type with addition and multiplication. -/ +protected def Quotient := + Quotient c.toSetoid + +variable {c} + +/-- The morphism into the quotient by a congruence relation -/ +@[coe] def toQuotient (r : R) : c.Quotient := + @Quotient.mk'' _ c.toSetoid r + +variable (c) + +/-- Coercion from a type with addition and multiplication to its quotient by a congruence relation. + +See Note [use has_coe_t]. -/ +instance : CoeTC R c.Quotient := + ⟨toQuotient⟩ + +-- Lower the priority since it unifies with any quotient type. +/-- The quotient by a decidable congruence relation has decidable equality. -/ +instance (priority := 500) [_d : ∀ a b, Decidable (c a b)] : DecidableEq c.Quotient := + inferInstanceAs (DecidableEq (Quotient c.toSetoid)) + +@[simp] +theorem quot_mk_eq_coe (x : R) : Quot.mk c x = (x : c.Quotient) := + rfl + +/-- Two elements are related by a congruence relation `c` iff they are represented by the same +element of the quotient by `c`. -/ +@[simp] +protected theorem eq {a b : R} : (a : c.Quotient) = (b : c.Quotient) ↔ c a b := + Quotient.eq'' + +end Basic + +/-! ### Basic notation + +The basic algebraic notation, `0`, `1`, `+`, `*`, `-`, `^`, descend naturally under the quotient +-/ + + +section Data + +section add_mul + +variable [Add R] [Mul R] (c : RingCon R) + +instance : Add c.Quotient := inferInstanceAs (Add c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_add (x y : R) : (↑(x + y) : c.Quotient) = ↑x + ↑y := + rfl + +instance : Mul c.Quotient := inferInstanceAs (Mul c.toCon.Quotient) + +@[simp, norm_cast] +theorem coe_mul (x y : R) : (↑(x * y) : c.Quotient) = ↑x * ↑y := + rfl + +end add_mul + +section Zero + +variable [AddZeroClass R] [Mul R] (c : RingCon R) + +instance : Zero c.Quotient := inferInstanceAs (Zero c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_zero : (↑(0 : R) : c.Quotient) = 0 := + rfl + +end Zero + +section One + +variable [Add R] [MulOneClass R] (c : RingCon R) + +instance : One c.Quotient := inferInstanceAs (One c.toCon.Quotient) + +@[simp, norm_cast] +theorem coe_one : (↑(1 : R) : c.Quotient) = 1 := + rfl + +end One + +section NegSubZSMul + +variable [AddGroup R] [Mul R] (c : RingCon R) + +instance : Neg c.Quotient := inferInstanceAs (Neg c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_neg (x : R) : (↑(-x) : c.Quotient) = -x := + rfl + +instance : Sub c.Quotient := inferInstanceAs (Sub c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_sub (x y : R) : (↑(x - y) : c.Quotient) = x - y := + rfl + +instance hasZSMul : SMul ℤ c.Quotient := inferInstanceAs (SMul ℤ c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_zsmul (z : ℤ) (x : R) : (↑(z • x) : c.Quotient) = z • (x : c.Quotient) := + rfl + +end NegSubZSMul + +section NSMul + +variable [AddMonoid R] [Mul R] (c : RingCon R) + +instance hasNSMul : SMul ℕ c.Quotient := inferInstanceAs (SMul ℕ c.toAddCon.Quotient) + +@[simp, norm_cast] +theorem coe_nsmul (n : ℕ) (x : R) : (↑(n • x) : c.Quotient) = n • (x : c.Quotient) := + rfl + +end NSMul + +section Pow + +variable [Add R] [Monoid R] (c : RingCon R) + +instance : Pow c.Quotient ℕ := inferInstanceAs (Pow c.toCon.Quotient ℕ) + +@[simp, norm_cast] +theorem coe_pow (x : R) (n : ℕ) : (↑(x ^ n) : c.Quotient) = (x : c.Quotient) ^ n := + rfl + +end Pow + +section NatCast + +variable [AddMonoidWithOne R] [Mul R] (c : RingCon R) + +instance : NatCast c.Quotient := + ⟨fun n => ↑(n : R)⟩ + +@[simp, norm_cast] +theorem coe_natCast (n : ℕ) : (↑(n : R) : c.Quotient) = n := + rfl + +@[deprecated (since := "2024-04-17")] +alias coe_nat_cast := coe_natCast + +end NatCast + +section IntCast + +variable [AddGroupWithOne R] [Mul R] (c : RingCon R) + +instance : IntCast c.Quotient := + ⟨fun z => ↑(z : R)⟩ + +@[simp, norm_cast] +theorem coe_intCast (n : ℕ) : (↑(n : R) : c.Quotient) = n := + rfl + +@[deprecated (since := "2024-04-17")] +alias coe_int_cast := coe_intCast + +end IntCast + +instance [Inhabited R] [Add R] [Mul R] (c : RingCon R) : Inhabited c.Quotient := + ⟨↑(default : R)⟩ + +end Data + +/-! ### Algebraic structure + +The operations above on the quotient by `c : RingCon R` preserve the algebraic structure of `R`. +-/ + + +section Algebraic + +instance [NonUnitalNonAssocSemiring R] (c : RingCon R) : NonUnitalNonAssocSemiring c.Quotient := + Function.Surjective.nonUnitalNonAssocSemiring _ Quotient.surjective_Quotient_mk'' rfl + (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl + +instance [NonAssocSemiring R] (c : RingCon R) : NonAssocSemiring c.Quotient := + Function.Surjective.nonAssocSemiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl + +instance [NonUnitalSemiring R] (c : RingCon R) : NonUnitalSemiring c.Quotient := + Function.Surjective.nonUnitalSemiring _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) + (fun _ _ => rfl) fun _ _ => rfl + +instance [Semiring R] (c : RingCon R) : Semiring c.Quotient := + Function.Surjective.semiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl + +instance [CommSemiring R] (c : RingCon R) : CommSemiring c.Quotient := + Function.Surjective.commSemiring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl + +instance [NonUnitalNonAssocRing R] (c : RingCon R) : NonUnitalNonAssocRing c.Quotient := + Function.Surjective.nonUnitalNonAssocRing _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl + +instance [NonAssocRing R] (c : RingCon R) : NonAssocRing c.Quotient := + Function.Surjective.nonAssocRing _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ => rfl) fun _ => rfl + +instance [NonUnitalRing R] (c : RingCon R) : NonUnitalRing c.Quotient := + Function.Surjective.nonUnitalRing _ Quotient.surjective_Quotient_mk'' rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl + +instance [Ring R] (c : RingCon R) : Ring c.Quotient := + Function.Surjective.ring _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl + +instance [CommRing R] (c : RingCon R) : CommRing c.Quotient := + Function.Surjective.commRing _ Quotient.surjective_Quotient_mk'' rfl rfl (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl + +end Algebraic + +/-- The natural homomorphism from a ring to its quotient by a congruence relation. -/ +def mk' [NonAssocSemiring R] (c : RingCon R) : R →+* c.Quotient where + toFun := toQuotient + map_zero' := rfl + map_one' := rfl + map_add' _ _ := rfl + map_mul' _ _ := rfl + +end Quotient + +end RingCon diff --git a/Mathlib/RingTheory/DedekindDomain/Basic.lean b/Mathlib/RingTheory/DedekindDomain/Basic.lean index b48609974c7b3..aae1db626fae1 100644 --- a/Mathlib/RingTheory/DedekindDomain/Basic.lean +++ b/Mathlib/RingTheory/DedekindDomain/Basic.lean @@ -49,7 +49,7 @@ variable (R A K : Type*) [CommRing R] [CommRing A] [Field K] open scoped nonZeroDivisors Polynomial /-- A ring `R` has Krull dimension at most one if all nonzero prime ideals are maximal. -/ -class Ring.DimensionLEOne : Prop := +class Ring.DimensionLEOne : Prop where (maximalOfPrime : ∀ {p : Ideal R}, p ≠ ⊥ → p.IsPrime → p.IsMaximal) open Ideal Ring diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index 915f686f016f1..0abb74d5ac750 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -7,6 +7,8 @@ import Mathlib.RingTheory.DedekindDomain.Ideal import Mathlib.RingTheory.Discriminant import Mathlib.RingTheory.DedekindDomain.IntegralClosure import Mathlib.NumberTheory.KummerDedekind +import Mathlib.RingTheory.IntegralClosure.IntegralRestrict +import Mathlib.RingTheory.Trace.Quotient /-! # The different ideal @@ -57,7 +59,7 @@ namespace Submodule lemma mem_traceDual {I : Submodule B L} {x} : x ∈ Iᵛ ↔ ∀ a ∈ I, traceForm K L x a ∈ (algebraMap A K).range := - Iff.rfl + forall₂_congr fun _ _ ↦ mem_one lemma le_traceDual_iff_map_le_one {I J : Submodule B L} : I ≤ Jᵛ ↔ ((I * J : Submodule B L).restrictScalars A).map @@ -147,14 +149,15 @@ variable [IsIntegrallyClosed A] lemma Submodule.mem_traceDual_iff_isIntegral {I : Submodule B L} {x} : x ∈ Iᵛ ↔ ∀ a ∈ I, IsIntegral A (traceForm K L x a) := - forall₂_congr (fun _ _ ↦ IsIntegrallyClosed.isIntegral_iff.symm) + forall₂_congr fun _ _ ↦ mem_one.trans IsIntegrallyClosed.isIntegral_iff.symm variable [FiniteDimensional K L] [IsIntegralClosure B A L] lemma Submodule.one_le_traceDual_one : (1 : Submodule B L) ≤ 1ᵛ := by - rw [le_traceDual_iff_map_le_one, mul_one] + rw [le_traceDual_iff_map_le_one, mul_one, one_eq_range] rintro _ ⟨x, ⟨x, rfl⟩, rfl⟩ + rw [mem_one] apply IsIntegrallyClosed.isIntegral_iff.mp apply isIntegral_trace rw [IsIntegralClosure.isIntegral_iff (A := B)] @@ -260,7 +263,7 @@ variable {A K L B} lemma mem_dual (hI : I ≠ 0) {x} : x ∈ dual A K I ↔ ∀ a ∈ I, traceForm K L x a ∈ (algebraMap A K).range := by - rw [dual, dif_neg hI]; rfl + rw [dual, dif_neg hI]; exact forall₂_congr fun _ _ ↦ mem_one variable (A K) @@ -298,6 +301,7 @@ lemma le_dual_inv_aux (hI : I ≠ 0) (hIJ : I * J ≤ 1) : J ≤ dual A K I := by rw [dual, dif_neg hI] intro x hx y hy + rw [mem_one] apply IsIntegrallyClosed.isIntegral_iff.mp apply isIntegral_trace rw [IsIntegralClosure.isIntegral_iff (A := B)] @@ -410,7 +414,7 @@ lemma coeSubmodule_differentIdeal_fractionRing simp only [← one_div, FractionalIdeal.val_eq_coe] at this rw [FractionalIdeal.coe_div (FractionalIdeal.dual_ne_zero _ _ _), FractionalIdeal.coe_dual] at this - · simpa only [FractionalIdeal.coe_one] using this + · simpa only [FractionalIdeal.coe_one, Submodule.one_eq_range] using this · exact one_ne_zero · exact one_ne_zero @@ -557,7 +561,7 @@ lemma conductor_mul_differentIdeal [NoZeroSMulDivisors A B] derivative_map, aeval_map_algebraMap, aeval_algebraMap_apply, mul_assoc, FractionalIdeal.mem_one_iff, forall_exists_index, forall_apply_eq_imp_iff] simp_rw [← IsScalarTower.toAlgHom_apply A B L x, ← AlgHom.map_adjoin_singleton] - simp only [Subalgebra.mem_map, IsScalarTower.coe_toAlgHom', + simp only [Subalgebra.mem_map, IsScalarTower.coe_toAlgHom', Submodule.one_eq_range, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, ← _root_.map_mul] exact ⟨fun H b ↦ (mul_one b) ▸ H b 1 (one_mem _), fun H _ _ _ ↦ H _⟩ @@ -568,3 +572,70 @@ lemma aeval_derivative_mem_differentIdeal [NoZeroSMulDivisors A B] refine SetLike.le_def.mp ?_ (Ideal.mem_span_singleton_self _) rw [← conductor_mul_differentIdeal A K L x hx] exact Ideal.mul_le_left + +section + +include K L in +lemma pow_sub_one_dvd_differentIdeal_aux [IsFractionRing B L] [IsDedekindDomain A] + [NoZeroSMulDivisors A B] [Module.Finite A B] + {p : Ideal A} [p.IsMaximal] (P : Ideal B) {e : ℕ} (he : e ≠ 0) (hp : p ≠ ⊥) + (hP : P ^ e ∣ p.map (algebraMap A B)) : P ^ (e - 1) ∣ differentIdeal A B := by + obtain ⟨a, ha⟩ := (pow_dvd_pow _ (Nat.sub_le e 1)).trans hP + have hp' := (Ideal.map_eq_bot_iff_of_injective + (NoZeroSMulDivisors.algebraMap_injective A B)).not.mpr hp + have habot : a ≠ ⊥ := fun ha' ↦ hp' (by simpa [ha'] using ha) + have hPbot : P ≠ ⊥ := by + rintro rfl; apply hp' + rwa [← Ideal.zero_eq_bot, zero_pow he, zero_dvd_iff, Ideal.zero_eq_bot] at hP + have : p.map (algebraMap A B) ∣ a ^ e := by + obtain ⟨b, hb⟩ := hP + apply_fun (· ^ e : Ideal B → _) at ha + apply_fun (· ^ (e - 1) : Ideal B → _) at hb + simp only [mul_pow, ← pow_mul, mul_comm e] at ha hb + conv_lhs at ha => rw [← Nat.sub_add_cancel (Nat.one_le_iff_ne_zero.mpr he)] + rw [pow_add, hb, mul_assoc, mul_right_inj' (pow_ne_zero _ hPbot), pow_one, mul_comm] at ha + exact ⟨_, ha.symm⟩ + suffices ∀ x ∈ a, intTrace A B x ∈ p by + have hP : ((P ^ (e - 1) : _)⁻¹ : FractionalIdeal B⁰ L) = a / p.map (algebraMap A B) := by + apply inv_involutive.injective + simp only [inv_inv, ha, FractionalIdeal.coeIdeal_mul, inv_div, ne_eq, + FractionalIdeal.coeIdeal_eq_zero, mul_div_assoc] + rw [div_self (by simpa), mul_one] + rw [Ideal.dvd_iff_le, differentialIdeal_le_iff (K := K) (L := L) (pow_ne_zero _ hPbot), hP, + Submodule.map_le_iff_le_comap] + intro x hx + rw [Submodule.restrictScalars_mem, FractionalIdeal.mem_coe, + FractionalIdeal.mem_div_iff_of_nonzero (by simpa using hp')] at hx + rw [Submodule.mem_comap, LinearMap.coe_restrictScalars, ← FractionalIdeal.coe_one, + ← div_self (G₀ := FractionalIdeal A⁰ K) (a := p) (by simpa using hp), + FractionalIdeal.mem_coe, FractionalIdeal.mem_div_iff_of_nonzero (by simpa using hp)] + simp only [FractionalIdeal.mem_coeIdeal, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂] at hx + intro y hy' + obtain ⟨y, hy, rfl : algebraMap A K _ = _⟩ := (FractionalIdeal.mem_coeIdeal _).mp hy' + obtain ⟨z, hz, hz'⟩ := hx _ (Ideal.mem_map_of_mem _ hy) + have : trace K L (algebraMap B L z) ∈ (p : FractionalIdeal A⁰ K) := by + rw [← algebraMap_intTrace (A := A)] + exact ⟨intTrace A B z, this z hz, rfl⟩ + rwa [mul_comm, ← smul_eq_mul, ← LinearMap.map_smul, smul_def, mul_comm, + ← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply A B L, ← hz'] + intros x hx + rw [← Ideal.Quotient.eq_zero_iff_mem, ← trace_quotient_eq_of_isDedekindDomain, + ← isNilpotent_iff_eq_zero] + refine trace_isNilpotent_of_isNilpotent ⟨e, ?_⟩ + rw [← map_pow, Ideal.Quotient.eq_zero_iff_mem] + exact (Ideal.dvd_iff_le.mp this) <| Ideal.pow_mem_pow hx _ + +lemma pow_sub_one_dvd_differentIdeal [IsDedekindDomain A] [NoZeroSMulDivisors A B] + [Module.Finite A B] [Algebra.IsSeparable (FractionRing A) (FractionRing B)] + {p : Ideal A} [p.IsMaximal] (P : Ideal B) (e : ℕ) (hp : p ≠ ⊥) + (hP : P ^ e ∣ p.map (algebraMap A B)) : P ^ (e - 1) ∣ differentIdeal A B := by + have : IsLocalization (algebraMapSubmonoid B A⁰) (FractionRing B) := + IsIntegralClosure.isLocalization _ (FractionRing A) _ _ + have : FiniteDimensional (FractionRing A) (FractionRing B) := + Module.Finite_of_isLocalization A B _ _ A⁰ + by_cases he : e = 0 + · rw [he, pow_zero]; exact one_dvd _ + exact pow_sub_one_dvd_differentIdeal_aux A (FractionRing A) (FractionRing B) _ he hp hP + +end diff --git a/Mathlib/RingTheory/DedekindDomain/Dvr.lean b/Mathlib/RingTheory/DedekindDomain/Dvr.lean index 2edc66bfc7bfa..c7086a988650b 100644 --- a/Mathlib/RingTheory/DedekindDomain/Dvr.lean +++ b/Mathlib/RingTheory/DedekindDomain/Dvr.lean @@ -43,7 +43,7 @@ dedekind domain, dedekind ring -/ -variable (R A K : Type*) [CommRing R] [CommRing A] [IsDomain A] [Field K] +variable (A : Type*) [CommRing A] [IsDomain A] open scoped nonZeroDivisors Polynomial diff --git a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean index 9cd04bf371ef8..2046eac05440a 100644 --- a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean +++ b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean @@ -106,11 +106,11 @@ def Coe.addMonoidHom : AddMonoidHom (R_hat R K) (K_hat R K) where toFun := (↑) map_zero' := rfl map_add' x y := by - -- Porting note: was `ext v` + -- Porting note (#11041): was `ext v` refine funext fun v => ?_ simp only [coe_apply, Pi.add_apply, Subring.coe_add] -- Porting note: added - erw [Pi.add_apply, Pi.add_apply, Subring.coe_add] + rw [Pi.add_apply, Pi.add_apply, Subring.coe_add] /-- The inclusion of `R_hat` in `K_hat` as a ring homomorphism. -/ @[simps] @@ -119,11 +119,11 @@ def Coe.ringHom : RingHom (R_hat R K) (K_hat R K) := toFun := (↑) map_one' := rfl map_mul' := fun x y => by - -- Porting note: was `ext p` + -- Porting note (#11041): was `ext p` refine funext fun p => ?_ simp only [Pi.mul_apply, Subring.coe_mul] -- Porting note: added - erw [Pi.mul_apply, Pi.mul_apply, Subring.coe_mul] } + rw [Pi.mul_apply, Pi.mul_apply, Subring.coe_mul] } end FiniteIntegralAdeles @@ -175,7 +175,7 @@ end FiniteIntegralAdeles /-! ### The finite adèle ring of a Dedekind domain We define the finite adèle ring of `R` as the restricted product over all maximal ideals `v` of `R` of `adicCompletion` with respect to `adicCompletionIntegers`. We prove that it is a commutative -ring. TODO: show that it is a topological ring with the restricted product topology. -/ +ring. -/ namespace ProdAdicCompletions @@ -355,7 +355,7 @@ instance : Algebra (R_hat R K) (FiniteAdeleRing R K) where map_zero' := by ext; rfl map_add' _ _ := by ext; rfl commutes' _ _ := mul_comm _ _ - smul_def' r x := rfl + smul_def' _ _ := rfl instance : CoeFun (FiniteAdeleRing R K) (fun _ ↦ ∀ (v : HeightOneSpectrum R), adicCompletion K v) where @@ -429,7 +429,7 @@ theorem submodulesRingBasis : SubmodulesRingBasis instance : TopologicalSpace (FiniteAdeleRing R K) := SubmodulesRingBasis.topology (submodulesRingBasis R K) --- the point of the above: this now works +-- the point of `submodulesRingBasis` above: this now works example : TopologicalRing (FiniteAdeleRing R K) := inferInstance end Topology diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 426d939612987..b4067b230ce8c 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -562,7 +562,7 @@ noncomputable instance FractionalIdeal.semifield : Semifield (FractionalIdeal A div_eq_mul_inv := FractionalIdeal.div_eq_mul_inv mul_inv_cancel _ := FractionalIdeal.mul_inv_cancel nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl /-- Fractional ideals have cancellative multiplication in a Dedekind domain. @@ -763,11 +763,11 @@ theorem Ideal.exist_integer_multiples_not_mem {J : Ideal A} (hJ : J ≠ ⊤) {ι · contrapose! hpI -- And if all `a`-multiples of `I` are an element of `J`, -- then `a` is actually an element of `J / I`, contradiction. - refine (mem_div_iff_of_nonzero hI0).mpr fun y hy => Submodule.span_induction hy ?_ ?_ ?_ ?_ + refine (mem_div_iff_of_nonzero hI0).mpr fun y hy => Submodule.span_induction ?_ ?_ ?_ ?_ hy · rintro _ ⟨i, hi, rfl⟩; exact hpI i hi · rw [mul_zero]; exact Submodule.zero_mem _ - · intro x y hx hy; rw [mul_add]; exact Submodule.add_mem _ hx hy - · intro b x hx; rw [mul_smul_comm]; exact Submodule.smul_mem _ b hx + · intro x y _ _ hx hy; rw [mul_add]; exact Submodule.add_mem _ hx hy + · intro b x _ hx; rw [mul_smul_comm]; exact Submodule.smul_mem _ b hx -- To show the inclusion of `J / I` into `I⁻¹ = 1 / I`, note that `J < I`. calc ↑J / I = ↑J * I⁻¹ := div_eq_mul_inv (↑J) I @@ -897,24 +897,27 @@ theorem irreducible_pow_sup [DecidableEq (Ideal T)] (hI : I ≠ ⊥) (hJ : Irred rw [sup_eq_prod_inf_factors (pow_ne_zero n hJ.ne_zero) hI, min_comm, normalizedFactors_of_irreducible_pow hJ, normalize_eq J, replicate_inter, prod_replicate] -theorem irreducible_pow_sup_of_le [DecidableRel fun (x : Ideal T) x_1 ↦ x ∣ x_1] - (hJ : Irreducible J) (n : ℕ) (hn : ↑n ≤ multiplicity J I) : +theorem irreducible_pow_sup_of_le (hJ : Irreducible J) (n : ℕ) (hn : n ≤ emultiplicity J I) : J ^ n ⊔ I = J ^ n := by classical by_cases hI : I = ⊥ · simp_all rw [irreducible_pow_sup hI hJ, min_eq_right] - rwa [multiplicity_eq_count_normalizedFactors hJ hI, PartENat.coe_le_coe, normalize_eq J] at hn + rw [emultiplicity_eq_count_normalizedFactors hJ hI, normalize_eq J] at hn + exact_mod_cast hn -theorem irreducible_pow_sup_of_ge [DecidableRel fun (x : Ideal T) x_1 ↦ x ∣ x_1] - (hI : I ≠ ⊥) (hJ : Irreducible J) (n : ℕ) (hn : multiplicity J I ≤ n) : - J ^ n ⊔ I = J ^ (multiplicity J I).get (PartENat.dom_of_le_natCast hn) := by +theorem irreducible_pow_sup_of_ge (hI : I ≠ ⊥) (hJ : Irreducible J) (n : ℕ) + (hn : emultiplicity J I ≤ n) : J ^ n ⊔ I = J ^ multiplicity J I := by classical rw [irreducible_pow_sup hI hJ, min_eq_left] · congr - rw [← PartENat.natCast_inj, PartENat.natCast_get, - multiplicity_eq_count_normalizedFactors hJ hI, normalize_eq J] - · rwa [multiplicity_eq_count_normalizedFactors hJ hI, PartENat.coe_le_coe, normalize_eq J] at hn + rw [← Nat.cast_inj (R := ℕ∞), ← multiplicity.Finite.emultiplicity_eq_multiplicity, + emultiplicity_eq_count_normalizedFactors hJ hI, normalize_eq J] + rw [← emultiplicity_lt_top] + apply hn.trans_lt + simp + · rw [emultiplicity_eq_count_normalizedFactors hJ hI, normalize_eq J] at hn + exact_mod_cast hn theorem Ideal.eq_prime_pow_mul_coprime [DecidableEq (Ideal T)] {I : Ideal T} (hI : I ≠ ⊥) (P : Ideal T) [hpm : P.IsMaximal] : @@ -1119,15 +1122,12 @@ theorem normalizedFactorsEquivOfQuotEquiv_symm (hI : I ≠ ⊥) (hJ : J ≠ ⊥) (normalizedFactorsEquivOfQuotEquiv f hI hJ).symm = normalizedFactorsEquivOfQuotEquiv f.symm hJ hI := rfl -variable [DecidableRel ((· ∣ ·) : Ideal R → Ideal R → Prop)] -variable [DecidableRel ((· ∣ ·) : Ideal A → Ideal A → Prop)] - /-- The map `normalizedFactorsEquivOfQuotEquiv` preserves multiplicities. -/ -theorem normalizedFactorsEquivOfQuotEquiv_multiplicity_eq_multiplicity (hI : I ≠ ⊥) (hJ : J ≠ ⊥) +theorem normalizedFactorsEquivOfQuotEquiv_emultiplicity_eq_emultiplicity (hI : I ≠ ⊥) (hJ : J ≠ ⊥) (L : Ideal R) (hL : L ∈ normalizedFactors I) : - multiplicity (↑(normalizedFactorsEquivOfQuotEquiv f hI hJ ⟨L, hL⟩)) J = multiplicity L I := by + emultiplicity (↑(normalizedFactorsEquivOfQuotEquiv f hI hJ ⟨L, hL⟩)) J = emultiplicity L I := by rw [normalizedFactorsEquivOfQuotEquiv, Equiv.coe_fn_mk, Subtype.coe_mk] - refine multiplicity_factor_dvd_iso_eq_multiplicity_of_mem_normalizedFactors hI hJ hL + refine emultiplicity_factor_dvd_iso_eq_emultiplicity_of_mem_normalizedFactors hI hJ hL (d := (idealFactorsEquivOfQuotEquiv f).toEquiv) ?_ exact fun ⟨l, hl⟩ ⟨l', hl'⟩ => idealFactorsEquivOfQuotEquiv_is_dvd_iso f hl hl' @@ -1245,7 +1245,7 @@ noncomputable def IsDedekindDomain.quotientEquivPiFactors {I : Ideal R} (hI : I R ⧸ I ≃+* ∀ P : (factors I).toFinset, R ⧸ (P : Ideal R) ^ (Multiset.count ↑P (factors I)) := IsDedekindDomain.quotientEquivPiOfProdEq _ _ _ (fun P : (factors I).toFinset => prime_of_factor _ (Multiset.mem_toFinset.mp P.prop)) - (fun i j hij => Subtype.coe_injective.ne hij) + (fun _ _ hij => Subtype.coe_injective.ne hij) (calc (∏ P : (factors I).toFinset, (P : Ideal R) ^ (factors I).count (P : Ideal R)) = ∏ P ∈ (factors I).toFinset, P ^ (factors I).count P := @@ -1341,23 +1341,20 @@ theorem singleton_span_mem_normalizedFactors_of_mem_normalizedFactors [Normaliza · by_contra h exact (prime_of_normalized_factor a ha).ne_zero (span_singleton_eq_bot.mp h) -theorem multiplicity_eq_multiplicity_span [DecidableRel ((· ∣ ·) : R → R → Prop)] - [DecidableRel ((· ∣ ·) : Ideal R → Ideal R → Prop)] {a b : R} : - multiplicity (Ideal.span {a}) (Ideal.span ({b} : Set R)) = multiplicity a b := by +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 - · rw [← PartENat.natCast_get (finite_iff_dom.mp h)] - refine (multiplicity.unique - (show Ideal.span {a} ^ (multiplicity a b).get h ∣ Ideal.span {b} from ?_) ?_).symm <;> + · 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 h - · exact multiplicity.is_greatest - ((PartENat.lt_coe_iff _ _).mpr (Exists.intro (finite_iff_dom.mp h) (Nat.lt_succ_self _))) + · 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 - rw [finite_iff_dom, PartENat.not_dom_iff_eq_top] at h this - rw [h, this] - exact not_finite_iff_forall.mpr fun n => by + rw [emultiplicity_eq_top.2 h, emultiplicity_eq_top.2 this] + exact Finite.not_iff_forall.mpr fun n => by rw [Ideal.span_singleton_pow, span_singleton_dvd_span_singleton_iff_dvd] - exact not_finite_iff_forall.mp h n + exact Finite.not_iff_forall.mp h n section NormalizationMonoid variable [NormalizationMonoid R] @@ -1389,29 +1386,27 @@ noncomputable def normalizedFactorsEquivSpanNormalizedFactors {r : R} (hr : r ((show Ideal.span {r} ≤ i from dvd_iff_le.mp (dvd_of_mem_normalizedFactors hi)) (mem_span_singleton.mpr (dvd_refl r))) -variable [DecidableRel ((· ∣ ·) : R → R → Prop)] [DecidableRel ((· ∣ ·) : Ideal R → Ideal R → Prop)] - /-- The bijection `normalizedFactorsEquivSpanNormalizedFactors` between the set of prime factors of `r` and the set of prime factors of the ideal `⟨r⟩` preserves multiplicities. See `count_normalizedFactorsSpan_eq_count` for the version stated in terms of multisets `count`.-/ -theorem multiplicity_normalizedFactorsEquivSpanNormalizedFactors_eq_multiplicity {r d : R} +theorem emultiplicity_normalizedFactorsEquivSpanNormalizedFactors_eq_emultiplicity {r d : R} (hr : r ≠ 0) (hd : d ∈ normalizedFactors r) : - multiplicity d r = - multiplicity (normalizedFactorsEquivSpanNormalizedFactors hr ⟨d, hd⟩ : Ideal R) + emultiplicity d r = + emultiplicity (normalizedFactorsEquivSpanNormalizedFactors hr ⟨d, hd⟩ : Ideal R) (Ideal.span {r}) := by - simp only [normalizedFactorsEquivSpanNormalizedFactors, multiplicity_eq_multiplicity_span, + simp only [normalizedFactorsEquivSpanNormalizedFactors, emultiplicity_eq_emultiplicity_span, Subtype.coe_mk, Equiv.ofBijective_apply] /-- The bijection `normalized_factors_equiv_span_normalized_factors.symm` between the set of prime factors of the ideal `⟨r⟩` and the set of prime factors of `r` preserves multiplicities. -/ -theorem multiplicity_normalizedFactorsEquivSpanNormalizedFactors_symm_eq_multiplicity {r : R} +theorem emultiplicity_normalizedFactorsEquivSpanNormalizedFactors_symm_eq_emultiplicity {r : R} (hr : r ≠ 0) (I : { I : Ideal R | I ∈ normalizedFactors (Ideal.span ({r} : Set R)) }) : - multiplicity ((normalizedFactorsEquivSpanNormalizedFactors hr).symm I : R) r = - multiplicity (I : Ideal R) (Ideal.span {r}) := by + emultiplicity ((normalizedFactorsEquivSpanNormalizedFactors hr).symm I : R) r = + emultiplicity (I : Ideal R) (Ideal.span {r}) := by obtain ⟨x, hx⟩ := (normalizedFactorsEquivSpanNormalizedFactors hr).surjective I obtain ⟨a, ha⟩ := x rw [hx.symm, Equiv.symm_apply_apply, Subtype.coe_mk, - multiplicity_normalizedFactorsEquivSpanNormalizedFactors_eq_multiplicity hr ha] + emultiplicity_normalizedFactorsEquivSpanNormalizedFactors_eq_emultiplicity hr ha] variable [DecidableEq R] [DecidableEq (Ideal R)] @@ -1422,9 +1417,9 @@ variable [DecidableEq R] [DecidableEq (Ideal R)] theorem count_span_normalizedFactors_eq {r X : R} (hr : r ≠ 0) (hX : Prime X) : Multiset.count (Ideal.span {X} : Ideal R) (normalizedFactors (Ideal.span {r})) = Multiset.count (normalize X) (normalizedFactors r) := by - have := multiplicity_eq_multiplicity_span (R := R) (a := X) (b := r) - rw [multiplicity_eq_count_normalizedFactors (Prime.irreducible hX) hr, - multiplicity_eq_count_normalizedFactors (Prime.irreducible ?_), normalize_apply, + have := emultiplicity_eq_emultiplicity_span (R := R) (a := X) (b := r) + rw [emultiplicity_eq_count_normalizedFactors (Prime.irreducible hX) hr, + emultiplicity_eq_count_normalizedFactors (Prime.irreducible ?_), normalize_apply, normUnit_eq_one, Units.val_one, one_eq_top, mul_top, Nat.cast_inj] at this · simp only [normalize_apply, this] · simp only [Submodule.zero_eq_bot, ne_eq, span_singleton_eq_bot, hr, not_false_eq_true] @@ -1434,7 +1429,7 @@ theorem count_span_normalizedFactors_eq_of_normUnit {r X : R} (hr : r ≠ 0) (hX₁ : normUnit X = 1) (hX : Prime X) : Multiset.count (Ideal.span {X} : Ideal R) (normalizedFactors (Ideal.span {r})) = Multiset.count X (normalizedFactors r) := by - simpa [hX₁] using count_span_normalizedFactors_eq hr hX + simpa [hX₁, normalize_apply] using count_span_normalizedFactors_eq hr hX end NormalizationMonoid diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 86796148fbcf3..77679db0fe1c6 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -36,7 +36,7 @@ dedekind domain, dedekind ring -/ -variable (R A K : Type*) [CommRing R] [CommRing A] [Field K] +variable (A K : Type*) [CommRing A] [Field K] open scoped nonZeroDivisors Polynomial @@ -95,7 +95,7 @@ theorem IsIntegralClosure.range_le_span_dualBasis [Algebra.IsSeparable K L] {ι rintro _ ⟨i, rfl⟩ _ ⟨y, rfl⟩ simp only [LinearMap.coe_restrictScalars, linearMap_apply, LinearMap.BilinForm.flip_apply, traceForm_apply] - refine IsIntegrallyClosed.isIntegral_iff.mp ?_ + refine Submodule.mem_one.mpr <| IsIntegrallyClosed.isIntegral_iff.mp ?_ exact isIntegral_trace ((IsIntegralClosure.isIntegral A L y).algebraMap.mul (hb_int i)) theorem integralClosure_le_span_dualBasis [Algebra.IsSeparable K L] {ι : Type*} [Fintype ι] diff --git a/Mathlib/RingTheory/DedekindDomain/PID.lean b/Mathlib/RingTheory/DedekindDomain/PID.lean index 258435cca7f9a..6bc5095ed0a68 100644 --- a/Mathlib/RingTheory/DedekindDomain/PID.lean +++ b/Mathlib/RingTheory/DedekindDomain/PID.lean @@ -42,7 +42,6 @@ theorem Ideal.eq_span_singleton_of_mem_of_not_mem_sq_of_not_mem_prime_ne {P : Id exact hxP2 (zero_mem _) by_cases hP0 : P = ⊥ · subst hP0 - -- Porting note: was `simpa using hxP2` but that hypothesis didn't even seem relevant in Lean 3 rwa [eq_comm, span_singleton_eq_bot, ← mem_bot] have hspan0 : span ({x} : Set R) ≠ ⊥ := mt Ideal.span_singleton_eq_bot.mp hx0 have span_le := (Ideal.span_singleton_le_iff_mem _).mpr x_mem diff --git a/Mathlib/RingTheory/DedekindDomain/SInteger.lean b/Mathlib/RingTheory/DedekindDomain/SInteger.lean index b80cad635c1d7..83b4fe6cf9021 100644 --- a/Mathlib/RingTheory/DedekindDomain/SInteger.lean +++ b/Mathlib/RingTheory/DedekindDomain/SInteger.lean @@ -69,9 +69,7 @@ def integer : Subalgebra R K := theorem integer_eq : (S.integer K).toSubring = ⨅ (v) (_ : v ∉ S), (v : HeightOneSpectrum R).valuation.valuationSubring.toSubring := - SetLike.ext' <| by - -- Porting note: was `simpa only [integer, Subring.copy_eq]` - ext; simp + SetLike.ext' <| by ext; simp theorem integer_valuation_le_one (x : S.integer K) {v : HeightOneSpectrum R} (hv : v ∉ S) : v.valuation (x : K) ≤ 1 := diff --git a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean index 3ac49f7143a12..964dfa3fb3639 100644 --- a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean +++ b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean @@ -172,7 +172,7 @@ theorem monotone (hS : S ≤ S') : K⟮S,n⟯ ≤ K⟮S',n⟯ := fun _ hx v => h /-- The multiplicative `v`-adic valuations on `K⟮S, n⟯` for all `v ∈ S`. -/ def valuation : K⟮S,n⟯ →* S → Multiplicative (ZMod n) where toFun x v := (v : HeightOneSpectrum R).valuationOfNeZeroMod n (x : K/n) - map_one' := funext fun v => map_one _ + map_one' := funext fun _ => map_one _ map_mul' x y := by simp only [Subgroup.coe_mul, map_mul]; rfl theorem valuation_ker_eq : diff --git a/Mathlib/RingTheory/Derivation/Basic.lean b/Mathlib/RingTheory/Derivation/Basic.lean index 6a97903473082..6ff64b463c840 100644 --- a/Mathlib/RingTheory/Derivation/Basic.lean +++ b/Mathlib/RingTheory/Derivation/Basic.lean @@ -151,9 +151,10 @@ theorem map_aeval (P : R[X]) (x : A) : · simp [add_smul, *] · simp [mul_smul, ← Nat.cast_smul_eq_nsmul A] -theorem eqOn_adjoin {s : Set A} (h : Set.EqOn D1 D2 s) : Set.EqOn D1 D2 (adjoin R s) := fun x hx => - Algebra.adjoin_induction hx h (fun r => (D1.map_algebraMap r).trans (D2.map_algebraMap r).symm) - (fun x y hx hy => by simp only [map_add, *]) fun x y hx hy => by simp only [leibniz, *] +theorem eqOn_adjoin {s : Set A} (h : Set.EqOn D1 D2 s) : Set.EqOn D1 D2 (adjoin R s) := fun _ hx => + Algebra.adjoin_induction (hx := hx) h + (fun r => (D1.map_algebraMap r).trans (D2.map_algebraMap r).symm) + (fun x y _ _ hx hy => by simp only [map_add, *]) fun x y _ _ hx hy => by simp only [leibniz, *] /-- If adjoin of a set is the whole algebra, then any two derivations equal on this set are equal on the whole algebra. -/ diff --git a/Mathlib/RingTheory/Derivation/MapCoeffs.lean b/Mathlib/RingTheory/Derivation/MapCoeffs.lean index 01ab5a9134a4a..ec1b10e49cb27 100644 --- a/Mathlib/RingTheory/Derivation/MapCoeffs.lean +++ b/Mathlib/RingTheory/Derivation/MapCoeffs.lean @@ -22,7 +22,7 @@ open Polynomial Module namespace Derivation variable {R A M : Type*} [CommRing R] [CommRing A] [Algebra R A] [AddCommGroup M] - [Module A M] [Module R M] (d : Derivation R A M) (a : A) + [Module A M] [Module R M] (d : Derivation R A M) /-- The `R`-derivation from `A[X]` to `M[X]` which applies the derivative to each diff --git a/Mathlib/RingTheory/Derivation/ToSquareZero.lean b/Mathlib/RingTheory/Derivation/ToSquareZero.lean index 398d75d13c3f9..e99816f3014ce 100644 --- a/Mathlib/RingTheory/Derivation/ToSquareZero.lean +++ b/Mathlib/RingTheory/Derivation/ToSquareZero.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Nicolò Cavalleri, Andrew Yang -/ import Mathlib.RingTheory.Derivation.Basic -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations /-! # Results diff --git a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean index 214213dcd11a6..8257492736d5b 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean @@ -365,31 +365,28 @@ theorem unit_mul_pow_congr_unit {ϖ : R} (hirr : Irreducible ϖ) (u v : Rˣ) (m /-! ## The additive valuation on a DVR -/ -open multiplicity open Classical in -/-- The `PartENat`-valued additive valuation on a DVR. -/ +/-- The `ℕ∞`-valued additive valuation on a DVR. -/ noncomputable def addVal (R : Type u) [CommRing R] [IsDomain R] [DiscreteValuationRing R] : - AddValuation R PartENat := - addValuation (Classical.choose_spec (exists_prime R)) + AddValuation R ℕ∞ := + multiplicity_addValuation (Classical.choose_spec (exists_prime R)) theorem addVal_def (r : R) (u : Rˣ) {ϖ : R} (hϖ : Irreducible ϖ) (n : ℕ) (hr : r = u * ϖ ^ n) : addVal R r = n := by classical - rw [addVal, addValuation_apply, hr, eq_of_associated_left + rw [addVal, multiplicity_addValuation_apply, hr, emultiplicity_eq_of_associated_left (associated_of_irreducible R hϖ (Classical.choose_spec (exists_prime R)).irreducible), - eq_of_associated_right (Associated.symm ⟨u, mul_comm _ _⟩), - multiplicity_pow_self_of_prime (irreducible_iff_prime.1 hϖ)] + emultiplicity_eq_of_associated_right (Associated.symm ⟨u, mul_comm _ _⟩), + emultiplicity_pow_self_of_prime (irreducible_iff_prime.1 hϖ)] theorem addVal_def' (u : Rˣ) {ϖ : R} (hϖ : Irreducible ϖ) (n : ℕ) : addVal R ((u : R) * ϖ ^ n) = n := addVal_def _ u hϖ n rfl ---@[simp] Porting note (#10618): simp can prove it theorem addVal_zero : addVal R 0 = ⊤ := (addVal R).map_zero ---@[simp] Porting note (#10618): simp can prove it theorem addVal_one : addVal R 1 = 0 := (addVal R).map_one @@ -398,7 +395,6 @@ theorem addVal_uniformizer {ϖ : R} (hϖ : Irreducible ϖ) : addVal R ϖ = 1 := simpa only [one_mul, eq_self_iff_true, Units.val_one, pow_one, forall_true_left, Nat.cast_one] using addVal_def ϖ 1 hϖ 1 ---@[simp] Porting note (#10618): simp can prove it theorem addVal_mul {a b : R} : addVal R (a * b) = addVal R a + addVal R b := (addVal R).map_mul _ _ @@ -418,7 +414,7 @@ theorem addVal_eq_top_iff {a : R} : addVal R a = ⊤ ↔ a = 0 := by obtain ⟨n, ha⟩ := associated_pow_irreducible h hi obtain ⟨u, rfl⟩ := ha.symm rw [mul_comm, addVal_def' u hi n] - exact PartENat.natCast_ne_top _ + nofun · rintro rfl exact addVal_zero @@ -431,10 +427,11 @@ theorem addVal_le_iff_dvd {a b : R} : addVal R a ≤ addVal R b ↔ a ∣ b := b rw [h] apply dvd_zero obtain ⟨n, ha⟩ := associated_pow_irreducible ha0 hp.irreducible - rw [addVal, addValuation_apply, addValuation_apply, multiplicity_le_multiplicity_iff] at h + rw [addVal, multiplicity_addValuation_apply, multiplicity_addValuation_apply, + emultiplicity_le_emultiplicity_iff] at h exact ha.dvd.trans (h n ha.symm.dvd) - · rw [addVal, addValuation_apply, addValuation_apply] - exact multiplicity_le_multiplicity_of_dvd_right h + · rw [addVal, multiplicity_addValuation_apply, multiplicity_addValuation_apply] + exact emultiplicity_le_emultiplicity_of_dvd_right h theorem addVal_add {a b : R} : min (addVal R a) (addVal R b) ≤ addVal R (a + b) := (addVal R).map_add _ _ @@ -447,7 +444,7 @@ instance (R : Type*) [CommRing R] [IsDomain R] [DiscreteValuationRing R] : obtain ⟨ϖ, hϖ⟩ := exists_irreducible R simp only [← Ideal.one_eq_top, smul_eq_mul, mul_one, SModEq.zero, hϖ.maximalIdeal_eq, Ideal.span_singleton_pow, Ideal.mem_span_singleton, ← addVal_le_iff_dvd, hϖ.addVal_pow] at hx - rwa [← addVal_eq_top_iff, PartENat.eq_top_iff_forall_le] + rwa [← addVal_eq_top_iff, ← WithTop.forall_ge_iff_eq_top] end DiscreteValuationRing diff --git a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean index 5957f090f0b89..763ee85bc69d5 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean @@ -25,7 +25,7 @@ Also see `tfae_of_isNoetherianRing_of_localRing_of_isDomain` for a version witho -/ -variable (R : Type*) [CommRing R] (K : Type*) [Field K] [Algebra R K] [IsFractionRing R K] +variable (R : Type*) [CommRing R] open scoped Multiplicative diff --git a/Mathlib/RingTheory/DualNumber.lean b/Mathlib/RingTheory/DualNumber.lean new file mode 100644 index 0000000000000..cf0ac64836b99 --- /dev/null +++ b/Mathlib/RingTheory/DualNumber.lean @@ -0,0 +1,168 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.Algebra.DualNumber +import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic + +/-! +# Algebraic properties of dual numbers + +## Main results + +* `DualNumber.instLocalRing`: The dual numbers over a field `K` form a local ring. +* `DualNumber.instPrincipalIdealRing`: The dual numbers over a field `K` form a principal ideal + ring. + +-/ + +namespace TrivSqZeroExt + +variable {R M : Type*} + +section Semiring +variable [Semiring R] [AddCommMonoid M] [Module R M] [Module Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] + +lemma isNilpotent_iff_isNilpotent_fst {x : TrivSqZeroExt R M} : + IsNilpotent x ↔ IsNilpotent x.fst := by + constructor <;> rintro ⟨n, hn⟩ + · refine ⟨n, ?_⟩ + rw [← fst_pow, hn, fst_zero] + · refine ⟨n * 2, ?_⟩ + rw [pow_mul] + ext + · rw [fst_pow, fst_pow, hn, zero_pow two_ne_zero, fst_zero] + · rw [pow_two, snd_mul, fst_pow, hn, MulOpposite.op_zero, zero_smul, zero_smul, zero_add, + snd_zero] + +@[simp] +lemma isNilpotent_inl_iff (r : R) : IsNilpotent (.inl r : TrivSqZeroExt R M) ↔ IsNilpotent r := by + rw [isNilpotent_iff_isNilpotent_fst, fst_inl] + +@[simp] +lemma isNilpotent_inr (x : M) : IsNilpotent (.inr x : TrivSqZeroExt R M) := by + refine ⟨2, by simp [pow_two]⟩ + +end Semiring + +lemma isUnit_or_isNilpotent_of_isMaximal_isNilpotent [CommSemiring R] [AddCommGroup M] + [Module R M] [Module Rᵐᵒᵖ M] [IsCentralScalar R M] + (h : ∀ I : Ideal R, I.IsMaximal → IsNilpotent I) + (a : TrivSqZeroExt R M) : + IsUnit a ∨ IsNilpotent a := by + rw [isUnit_iff_isUnit_fst, isNilpotent_iff_isNilpotent_fst] + refine (em _).imp_right fun ha ↦ ?_ + obtain ⟨I, hI, haI⟩ := exists_max_ideal_of_mem_nonunits (mem_nonunits_iff.mpr ha) + refine (h _ hI).imp fun n hn ↦ ?_ + exact hn.le (Ideal.pow_mem_pow haI _) + +lemma isUnit_or_isNilpotent [DivisionSemiring R] [AddCommGroup M] + [Module R M] [Module Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] + (a : TrivSqZeroExt R M) : + IsUnit a ∨ IsNilpotent a := by + simp [isUnit_iff_isUnit_fst, isNilpotent_iff_isNilpotent_fst, em'] + +end TrivSqZeroExt + +namespace DualNumber +variable {R : Type*} + +lemma fst_eq_zero_iff_eps_dvd [Semiring R] {x : R[ε]} : + x.fst = 0 ↔ ε ∣ x := by + simp_rw [dvd_def, TrivSqZeroExt.ext_iff, TrivSqZeroExt.fst_mul, TrivSqZeroExt.snd_mul, + fst_eps, snd_eps, zero_mul, zero_smul, zero_add, MulOpposite.smul_eq_mul_unop, + MulOpposite.unop_op, one_mul, exists_and_left, iff_self_and] + intro + exact ⟨.inl x.snd, rfl⟩ + +lemma isNilpotent_eps [Semiring R] : + IsNilpotent (ε : R[ε]) := + TrivSqZeroExt.isNilpotent_inr 1 + +open TrivSqZeroExt + +lemma isNilpotent_iff_eps_dvd [DivisionSemiring R] {x : R[ε]} : + IsNilpotent x ↔ ε ∣ x := by + simp only [isNilpotent_iff_isNilpotent_fst, isNilpotent_iff_eq_zero, fst_eq_zero_iff_eps_dvd] + +section Field + +variable {K : Type*} + +instance [DivisionRing K] : LocalRing K[ε] where + isUnit_or_isUnit_of_add_one {a b} h := by + rw [add_comm, ← eq_sub_iff_add_eq] at h + rcases eq_or_ne (fst a) 0 with ha|ha <;> + simp [isUnit_iff_isUnit_fst, h, ha] + +lemma ideal_trichotomy [DivisionRing K] (I : Ideal K[ε]) : + I = ⊥ ∨ I = .span {ε} ∨ I = ⊤ := by + refine (eq_or_ne I ⊥).imp_right fun hb ↦ ?_ + refine (eq_or_ne I ⊤).symm.imp_left fun ht ↦ ?_ + have hd : ∀ x ∈ I, ε ∣ x := by + intro x hxI + rcases isUnit_or_isNilpotent x with hx|hx + · exact absurd (Ideal.eq_top_of_isUnit_mem _ hxI hx) ht + · rwa [← isNilpotent_iff_eps_dvd] + have hd' : ∀ x ∈ I, x ≠ 0 → ∃ r, ε = r * x := by + intro x hxI hx0 + obtain ⟨r, rfl⟩ := hd _ hxI + have : ε * r = (fst r) • ε := by ext <;> simp + rw [this] at hxI hx0 ⊢ + have hr : fst r ≠ 0 := by + contrapose! hx0 + simp [hx0] + refine ⟨r⁻¹, ?_⟩ + simp [TrivSqZeroExt.ext_iff, inv_mul_cancel₀ hr] + refine le_antisymm ?_ ?_ <;> intro x <;> + simp_rw [Ideal.mem_span_singleton', (commute_eps_right _).eq, eq_comm, ← dvd_def] + · intro hx + simp_rw [hd _ hx] + · intro hx + obtain ⟨p, rfl⟩ := hx + obtain ⟨y, hyI, hy0⟩ := Submodule.exists_mem_ne_zero_of_ne_bot hb + obtain ⟨r, hr⟩ := hd' _ hyI hy0 + rw [(commute_eps_left _).eq, hr, ← mul_assoc] + exact Ideal.mul_mem_left _ _ hyI + +lemma isMaximal_span_singleton_eps [DivisionRing K] : + (Ideal.span {ε} : Ideal K[ε]).IsMaximal := by + refine ⟨?_, fun I hI ↦ ?_⟩ + · simp [ne_eq, Ideal.eq_top_iff_one, Ideal.mem_span_singleton', TrivSqZeroExt.ext_iff] + · rcases ideal_trichotomy I with rfl|rfl|rfl <;> + first | simp at hI | simp + +lemma maximalIdeal_eq_span_singleton_eps [Field K] : + LocalRing.maximalIdeal K[ε] = Ideal.span {ε} := + (LocalRing.eq_maximalIdeal isMaximal_span_singleton_eps).symm + +instance [DivisionRing K] : IsPrincipalIdealRing K[ε] where + principal I := by + rcases ideal_trichotomy I with rfl|rfl|rfl + · exact bot_isPrincipal + · exact ⟨_, rfl⟩ + · exact top_isPrincipal + +lemma exists_mul_left_or_mul_right [DivisionRing K] (a b : K[ε]) : + ∃ c, a * c = b ∨ b * c = a := by + rcases isUnit_or_isNilpotent a with ha|ha + · lift a to K[ε]ˣ using ha + exact ⟨a⁻¹ * b, by simp⟩ + rcases isUnit_or_isNilpotent b with hb|hb + · lift b to K[ε]ˣ using hb + exact ⟨b⁻¹ * a, by simp⟩ + rw [isNilpotent_iff_eps_dvd] at ha hb + obtain ⟨x, rfl⟩ := ha + obtain ⟨y, rfl⟩ := hb + suffices ∃ c, fst x * fst c = fst y ∨ fst y * fst c = fst x by + simpa [TrivSqZeroExt.ext_iff] using this + rcases eq_or_ne (fst x) 0 with hx|hx + · refine ⟨ε, Or.inr ?_⟩ + simp [hx] + refine ⟨inl ((fst x)⁻¹ * fst y), ?_⟩ + simp [← inl_mul, ← mul_assoc, mul_inv_cancel₀ hx] + +end Field + +end DualNumber diff --git a/Mathlib/RingTheory/EisensteinCriterion.lean b/Mathlib/RingTheory/EisensteinCriterion.lean index 1fcc31f3e3076..216ad0c0c0a4d 100644 --- a/Mathlib/RingTheory/EisensteinCriterion.lean +++ b/Mathlib/RingTheory/EisensteinCriterion.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Data.Nat.Cast.WithTop -import Mathlib.RingTheory.Prime +import Mathlib.RingTheory.Ideal.Quotient.Basic import Mathlib.RingTheory.Polynomial.Content -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.RingTheory.Prime /-! # Eisenstein's criterion @@ -34,8 +34,7 @@ theorem map_eq_C_mul_X_pow_of_forall_coeff_mem {f : R[X]} {P : Ideal R} by_cases hf0 : f = 0 · simp [hf0] rcases lt_trichotomy (n : WithBot ℕ) (degree f) with (h | h | h) - · erw [coeff_map, eq_zero_iff_mem.2 (hfP n h), coeff_C_mul, coeff_X_pow, if_neg, - mul_zero] + · rw [coeff_map, eq_zero_iff_mem.2 (hfP n h), coeff_C_mul, coeff_X_pow, if_neg, mul_zero] rintro rfl exact not_lt_of_ge degree_le_natDegree h · have : natDegree f = n := natDegree_eq_of_degree_eq_some h.symm diff --git a/Mathlib/RingTheory/EssentialFiniteness.lean b/Mathlib/RingTheory/EssentialFiniteness.lean index c23b4328ea0fb..195e86ad43bdf 100644 --- a/Mathlib/RingTheory/EssentialFiniteness.lean +++ b/Mathlib/RingTheory/EssentialFiniteness.lean @@ -109,7 +109,7 @@ lemma EssFiniteType.aux (σ : Subalgebra R S) (hσ : ∀ s : S, ∃ t ∈ σ, IsUnit t ∧ s * t ∈ σ) (τ : Set T) (t : T) (ht : t ∈ Algebra.adjoin S τ) : ∃ s ∈ σ, IsUnit s ∧ s • t ∈ σ.map (IsScalarTower.toAlgHom R S T) ⊔ Algebra.adjoin R τ := by - refine Algebra.adjoin_induction ht ?_ ?_ ?_ ?_ + refine Algebra.adjoin_induction ?_ ?_ ?_ ?_ ht · intro t ht exact ⟨1, Subalgebra.one_mem _, isUnit_one, (one_smul S t).symm ▸ Algebra.mem_sup_right (Algebra.subset_adjoin ht)⟩ @@ -118,13 +118,13 @@ lemma EssFiniteType.aux (σ : Subalgebra R S) refine ⟨_, hs₁, hs₂, Algebra.mem_sup_left ?_⟩ rw [Algebra.smul_def, ← map_mul, mul_comm] exact ⟨_, hs₃, rfl⟩ - · rintro x y ⟨sx, hsx, hsx', hsx''⟩ ⟨sy, hsy, hsy', hsy''⟩ + · rintro x y - - ⟨sx, hsx, hsx', hsx''⟩ ⟨sy, hsy, hsy', hsy''⟩ refine ⟨_, σ.mul_mem hsx hsy, hsx'.mul hsy', ?_⟩ rw [smul_add, mul_smul, mul_smul, Algebra.smul_def sx (sy • y), smul_comm, Algebra.smul_def sy (sx • x)] apply add_mem (mul_mem _ hsx'') (mul_mem _ hsy'') <;> exact Algebra.mem_sup_left ⟨_, ‹_›, rfl⟩ - · rintro x y ⟨sx, hsx, hsx', hsx''⟩ ⟨sy, hsy, hsy', hsy''⟩ + · rintro x y - - ⟨sx, hsx, hsx', hsx''⟩ ⟨sy, hsy, hsy', hsy''⟩ refine ⟨_, σ.mul_mem hsx hsy, hsx'.mul hsy', ?_⟩ rw [mul_smul, ← smul_eq_mul, smul_comm sy x, ← smul_assoc, smul_eq_mul] exact mul_mem hsx'' hsy'' @@ -212,12 +212,12 @@ lemma EssFiniteType.algHom_ext [EssFiniteType R S] ext; exact AlgHom.congr_fun this _ apply AlgHom.ext_of_adjoin_eq_top (s := { x | x.1 ∈ finset R S }) · rw [← top_le_iff] - rintro x _ - refine Algebra.adjoin_induction' ?_ ?_ ?_ ?_ x + rintro ⟨x, hx⟩ _ + refine Algebra.adjoin_induction ?_ ?_ ?_ ?_ hx · intro x hx; exact Algebra.subset_adjoin hx · intro r; exact Subalgebra.algebraMap_mem _ _ - · intro x y hx hy; exact add_mem hx hy - · intro x y hx hy; exact mul_mem hx hy + · intro x y _ _ hx hy; exact add_mem hx hy + · intro x y _ _ hx hy; exact mul_mem hx hy · rintro ⟨x, hx⟩ hx'; exact H x hx' end Algebra diff --git a/Mathlib/RingTheory/Etale/Basic.lean b/Mathlib/RingTheory/Etale/Basic.lean index 171f57f41c31c..ca33968558ff3 100644 --- a/Mathlib/RingTheory/Etale/Basic.lean +++ b/Mathlib/RingTheory/Etale/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.RingTheory.QuotientNilpotent +import Mathlib.RingTheory.Ideal.Quotient.Nilpotent import Mathlib.RingTheory.Smooth.Basic import Mathlib.RingTheory.Unramified.Basic @@ -34,8 +34,8 @@ namespace Algebra section -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [Semiring A] [Algebra R A] +variable (R : Type u) [CommRing R] +variable (A : Type u) [CommRing A] [Algebra R A] /-- An `R` algebra `A` is formally étale if for every `R`-algebra, every square-zero ideal `I : Ideal B` and `f : A →ₐ[R] B ⧸ I`, there exists exactly one lift `A →ₐ[R] B`. @@ -54,13 +54,12 @@ namespace FormallyEtale section -variable {R : Type u} [CommSemiring R] -variable {A : Type u} [Semiring A] [Algebra R A] -variable {B : Type u} [CommRing B] [Algebra R B] (I : Ideal B) +variable {R : Type u} [CommRing R] +variable {A : Type u} [CommRing A] [Algebra R A] theorem iff_unramified_and_smooth : FormallyEtale R A ↔ FormallyUnramified R A ∧ FormallySmooth R A := by - rw [formallyUnramified_iff, formallySmooth_iff, formallyEtale_iff] + rw [FormallyUnramified.iff_comp_injective, formallySmooth_iff, formallyEtale_iff] simp_rw [← forall_and, Function.Bijective] instance (priority := 100) to_unramified [h : FormallyEtale R A] : @@ -78,20 +77,23 @@ end section OfEquiv -variable {R : Type u} [CommSemiring R] -variable {A B : Type u} [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] +variable {R : Type u} [CommRing R] +variable {A B : Type u} [CommRing A] [Algebra R A] [CommRing B] [Algebra R B] theorem of_equiv [FormallyEtale R A] (e : A ≃ₐ[R] B) : FormallyEtale R B := FormallyEtale.iff_unramified_and_smooth.mpr ⟨FormallyUnramified.of_equiv e, FormallySmooth.of_equiv e⟩ +theorem iff_of_equiv (e : A ≃ₐ[R] B) : FormallyEtale R A ↔ FormallyEtale R B := + ⟨fun _ ↦ of_equiv e, fun _ ↦ of_equiv e.symm⟩ + end OfEquiv section Comp -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [CommSemiring A] [Algebra R A] -variable (B : Type u) [Semiring B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] +variable (R : Type u) [CommRing R] +variable (A : Type u) [CommRing A] [Algebra R A] +variable (B : Type u) [CommRing B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] theorem comp [FormallyEtale R A] [FormallyEtale A B] : FormallyEtale R B := FormallyEtale.iff_unramified_and_smooth.mpr @@ -103,9 +105,9 @@ section BaseChange open scoped TensorProduct -variable {R : Type u} [CommSemiring R] -variable {A : Type u} [Semiring A] [Algebra R A] -variable (B : Type u) [CommSemiring B] [Algebra R B] +variable {R : Type u} [CommRing R] +variable {A : Type u} [CommRing A] [Algebra R A] +variable (B : Type u) [CommRing B] [Algebra R B] instance base_change [FormallyEtale R A] : FormallyEtale B (B ⊗[R] A) := FormallyEtale.iff_unramified_and_smooth.mpr ⟨inferInstance, inferInstance⟩ @@ -164,8 +166,8 @@ end FormallyEtale section -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [Semiring A] [Algebra R A] +variable (R : Type u) [CommRing R] +variable (A : Type u) [CommRing A] [Algebra R A] /-- An `R`-algebra `A` is étale if it is formally étale and of finite presentation. diff --git a/Mathlib/RingTheory/Etale/Field.lean b/Mathlib/RingTheory/Etale/Field.lean new file mode 100644 index 0000000000000..3e6b3bd1c7814 --- /dev/null +++ b/Mathlib/RingTheory/Etale/Field.lean @@ -0,0 +1,151 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.Etale.Basic +import Mathlib.RingTheory.Unramified.Field + +/-! +# Etale algebras over fields + +## Main results + +Let `K` be a field, `A` be a `K`-algebra and `L` be a field extension of `K`. + +- `Algebra.FormallyEtale.of_isSeparable`: + If `L` is separable over `K`, then `L` is formally etale over `K`. +- `Algebra.FormallyEtale.iff_isSeparable`: + If `L` is (essentially) of finite type over `K`, then `L/K` is etale iff `L/K` is separable. + +## References + +- [B. Iversen, *Generic Local Structure of the Morphisms in Commutative Algebra*][iversen] + +-/ + + +universe u + +variable (K L : Type u) [Field K] [Field L] [Algebra K L] + +open Algebra Polynomial + +open scoped TensorProduct + +namespace Algebra.FormallyEtale + +/-- +This is a weaker version of `of_isSeparable` that additionally assumes `EssFiniteType K L`. +Use that instead. + +This is Iversen Corollary II.5.3. +-/ +theorem of_isSeparable_aux [Algebra.IsSeparable K L] [EssFiniteType K L] : + FormallyEtale K L := by + -- We already know that for field extensions + -- IsSeparable + EssFiniteType => FormallyUnramified + Finite + have := FormallyUnramified.of_isSeparable K L + have := FormallyUnramified.finite_of_free (R := K) (S := L) + constructor + -- We shall show that any `f : L → B/I` can be lifted to `L → B` if `I^2 = ⊥` + intros B _ _ I h + refine ⟨FormallyUnramified.iff_comp_injective.mp (FormallyUnramified.of_isSeparable K L) I h, ?_⟩ + intro f + -- By separability and finiteness, we may assume `L = K(α)` with `p` the minpoly of `α`. + let pb := Field.powerBasisOfFiniteOfSeparable K L + -- Let `x : B` such that `f(α) = x` in `B / I`. + obtain ⟨x, hx⟩ := Ideal.Quotient.mk_surjective (f pb.gen) + have helper : ∀ x, IsScalarTower.toAlgHom K B (B ⧸ I) x = Ideal.Quotient.mk I x := fun _ ↦ rfl + -- Then `p(x) = 0 mod I`, and the goal is to find some `ε ∈ I` such that + -- `p(x + ε) = p(x) + ε p'(x) = 0`, and we will get our lift into `B`. + have hx' : Ideal.Quotient.mk I (aeval x (minpoly K pb.gen)) = 0 := by + rw [← helper, ← aeval_algHom_apply, helper, hx, aeval_algHom_apply, minpoly.aeval, map_zero] + -- Since `p` is separable, `-p'(x)` is invertible in `B ⧸ I`, + obtain ⟨u, hu⟩ : ∃ u, (aeval x) (derivative (minpoly K pb.gen)) * u + 1 ∈ I := by + have := (isUnit_iff_ne_zero.mpr ((Algebra.IsSeparable.isSeparable K + pb.gen).aeval_derivative_ne_zero (minpoly.aeval K _))).map f + rw [← aeval_algHom_apply, ← hx, ← helper, aeval_algHom_apply, helper] at this + obtain ⟨u, hu⟩ := Ideal.Quotient.mk_surjective (-this.unit⁻¹ : B ⧸ I) + use u + rw [← Ideal.Quotient.eq_zero_iff_mem, map_add, map_mul, map_one, hu, mul_neg, + IsUnit.mul_val_inv, neg_add_cancel] + -- And `ε = p(x)/(-p'(x))` works. + use pb.liftEquiv.symm ⟨x + u * aeval x (minpoly K pb.gen), ?_⟩ + · apply pb.algHom_ext + simp [hx, hx'] + · rw [← eval_map_algebraMap, Polynomial.eval_add_of_sq_eq_zero, derivative_map, + ← one_mul (eval x _), eval_map_algebraMap, eval_map_algebraMap, ← mul_assoc, ← add_mul, + ← Ideal.mem_bot, ← h, pow_two, add_comm] + · exact Ideal.mul_mem_mul hu (Ideal.Quotient.eq_zero_iff_mem.mp hx') + rw [← Ideal.mem_bot, ← h] + apply Ideal.pow_mem_pow + rw [← Ideal.Quotient.eq_zero_iff_mem, map_mul, hx', mul_zero] + +open scoped IntermediateField in +lemma of_isSeparable [Algebra.IsSeparable K L] : FormallyEtale K L := by + constructor + intros B _ _ I h + -- We shall show that any `f : L → B/I` can be lifted to `L → B` if `I^2 = ⊥`. + -- But we already know that there exists a unique lift for every finite subfield of `L` + -- by `of_isSeparable_aux`, so we can glue them all together. + refine ⟨FormallyUnramified.iff_comp_injective.mp (FormallyUnramified.of_isSeparable K L) I h, ?_⟩ + intro f + have : ∀ k : L, ∃! g : K⟮k⟯ →ₐ[K] B, + (Ideal.Quotient.mkₐ K I).comp g = f.comp (IsScalarTower.toAlgHom K _ L) := by + intro k + have := IsSeparable.of_algHom _ _ (IsScalarTower.toAlgHom K (K⟮k⟯) L) + have := IntermediateField.adjoin.finiteDimensional + (Algebra.IsSeparable.isSeparable K k).isIntegral + have := FormallyEtale.of_isSeparable_aux K (K⟮k⟯) + have := FormallyEtale.comp_bijective (R := K) (A := K⟮k⟯) I h + exact this.existsUnique _ + choose g hg₁ hg₂ using this + have hg₃ : ∀ x y (h : x ∈ K⟮y⟯), g y ⟨x, h⟩ = g x (IntermediateField.AdjoinSimple.gen K x) := by + intro x y h + have e : K⟮x⟯ ≤ K⟮y⟯ := by + rw [IntermediateField.adjoin_le_iff] + rintro _ rfl + exact h + rw [← hg₂ _ ((g _).comp (IntermediateField.inclusion e))] + · rfl + apply AlgHom.ext + intro ⟨a, _⟩ + rw [← AlgHom.comp_assoc, hg₁, AlgHom.comp_assoc] + simp + have H : ∀ x y : L, ∃ α : L, x ∈ K⟮α⟯ ∧ y ∈ K⟮α⟯ := by + intro x y + have : FiniteDimensional K K⟮x, y⟯ := by + apply IntermediateField.finiteDimensional_adjoin + intro x _; exact (Algebra.IsSeparable.isSeparable K x).isIntegral + have := IsSeparable.of_algHom _ _ (IsScalarTower.toAlgHom K (K⟮x, y⟯) L) + obtain ⟨⟨α, hα⟩, e⟩ := Field.exists_primitive_element K K⟮x,y⟯ + apply_fun (IntermediateField.map (IntermediateField.val _)) at e + rw [IntermediateField.adjoin_map, ← AlgHom.fieldRange_eq_map] at e + simp only [IntermediateField.coe_val, Set.image_singleton, + IntermediateField.fieldRange_val] at e + have hx : x ∈ K⟮α⟯ := e ▸ IntermediateField.subset_adjoin K {x, y} (by simp) + have hy : y ∈ K⟮α⟯ := e ▸ IntermediateField.subset_adjoin K {x, y} (by simp) + exact ⟨α, hx, hy⟩ + refine ⟨⟨⟨⟨⟨fun x ↦ g x (IntermediateField.AdjoinSimple.gen K x), ?_⟩, ?_⟩, ?_, ?_⟩, ?_⟩, ?_⟩ + · show g 1 1 = 1; rw [map_one] + · intros x y + obtain ⟨α, hx, hy⟩ := H x y + simp only [← hg₃ _ _ hx, ← hg₃ _ _ hy, ← map_mul, ← hg₃ _ _ (mul_mem hx hy)] + rfl + · show g 0 0 = 0; rw [map_zero] + · intros x y + obtain ⟨α, hx, hy⟩ := H x y + simp only [← hg₃ _ _ hx, ← hg₃ _ _ hy, ← map_add, ← hg₃ _ _ (add_mem hx hy)] + rfl + · intro r + show g _ (algebraMap K _ r) = _ + rw [AlgHom.commutes] + · ext x + simpa using AlgHom.congr_fun (hg₁ x) (IntermediateField.AdjoinSimple.gen K x) + +theorem iff_isSeparable [EssFiniteType K L] : + FormallyEtale K L ↔ Algebra.IsSeparable K L := + ⟨fun _ ↦ FormallyUnramified.isSeparable K L, fun _ ↦ of_isSeparable K L⟩ + +end Algebra.FormallyEtale diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index 8ce8b760670a3..8b38d3cb2ddca 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -238,7 +238,7 @@ variable (F F') protected def submodule : Submodule (reesAlgebra I) (PolynomialModule R M) where carrier := { f | ∀ i, f i ∈ F.N i } add_mem' hf hg i := Submodule.add_mem _ (hf i) (hg i) - zero_mem' i := Submodule.zero_mem _ + zero_mem' _ := Submodule.zero_mem _ smul_mem' r f hf i := by rw [Subalgebra.smul_def, PolynomialModule.smul_apply] apply Submodule.sum_mem diff --git a/Mathlib/RingTheory/FiniteLength.lean b/Mathlib/RingTheory/FiniteLength.lean new file mode 100644 index 0000000000000..b1cf98eb550b8 --- /dev/null +++ b/Mathlib/RingTheory/FiniteLength.lean @@ -0,0 +1,104 @@ +/- +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.RingTheory.Artinian + +/-! +# Modules of finite length + +We define modules of finite length (`IsFiniteLength`) to be finite iterated extensions of +simple modules, and show that a module is of finite length iff it is both Noetherian and Artinian, +iff it admits a composition series. +We do not make `IsFiniteLength` a class, instead we use `[IsNoetherian R M] [IsArtinian R M]`. + +## Tag + +Finite length, Composition series +-/ + +universe u + +variable (R : Type*) [Ring R] + +/-- A module of finite length is either trivial or a simple extension of a module known +to be of finite length. -/ +inductive IsFiniteLength : ∀ (M : Type u) [AddCommGroup M] [Module R M], Prop + | of_subsingleton {M} [AddCommGroup M] [Module R M] [Subsingleton M] : IsFiniteLength M + | of_simple_quotient {M} [AddCommGroup M] [Module R M] {N : Submodule R M} + [IsSimpleModule R (M ⧸ N)] : IsFiniteLength N → IsFiniteLength M + +variable {R} {M N : Type*} [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + +theorem LinearEquiv.isFiniteLength (e : M ≃ₗ[R] N) + (h : IsFiniteLength R M) : IsFiniteLength R N := by + induction' h with M _ _ _ M _ _ S _ _ ih generalizing N + · have := e.symm.toEquiv.subsingleton; exact .of_subsingleton + · have : IsSimpleModule R (N ⧸ Submodule.map (e : M →ₗ[R] N) S) := + IsSimpleModule.congr (Submodule.Quotient.equiv S _ e rfl).symm + exact .of_simple_quotient (ih <| e.submoduleMap S) + +variable (R M) in +theorem exists_compositionSeries_of_isNoetherian_isArtinian [IsNoetherian R M] [IsArtinian R M] : + ∃ s : CompositionSeries (Submodule R M), s.head = ⊥ ∧ s.last = ⊤ := by + obtain ⟨f, f0, n, hn⟩ := exists_covBy_seq_of_wellFoundedLT_wellFoundedGT (Submodule R M) + exact ⟨⟨n, fun i ↦ f i, fun i ↦ hn.2 i i.2⟩, f0.eq_bot, hn.1.eq_top⟩ + +theorem isFiniteLength_of_exists_compositionSeries + (h : ∃ s : CompositionSeries (Submodule R M), s.head = ⊥ ∧ s.last = ⊤) : + IsFiniteLength R M := + Submodule.topEquiv.isFiniteLength <| by + obtain ⟨s, s_head, s_last⟩ := h + rw [← s_last] + suffices ∀ i, IsFiniteLength R (s i) from this (Fin.last _) + intro i + induction' i using Fin.induction with i ih + · change IsFiniteLength R s.head; rw [s_head]; exact .of_subsingleton + let cov := s.step i + have := (covBy_iff_quot_is_simple cov.le).mp cov + have := ((s i.castSucc).comap (s i.succ).subtype).equivMapOfInjective + _ (Submodule.injective_subtype _) + rw [Submodule.map_comap_subtype, inf_of_le_right cov.le] at this + exact .of_simple_quotient (this.symm.isFiniteLength ih) + +theorem isFiniteLength_iff_isNoetherian_isArtinian : + IsFiniteLength R M ↔ IsNoetherian R M ∧ IsArtinian R M := + ⟨fun h ↦ h.rec (fun {M} _ _ _ ↦ ⟨inferInstance, inferInstance⟩) fun M _ _ {N} _ _ ⟨_, _⟩ ↦ + ⟨(isNoetherian_iff_submodule_quotient N).mpr ⟨‹_›, isNoetherian_iff'.mpr inferInstance⟩, + (isArtinian_iff_submodule_quotient N).mpr ⟨‹_›, inferInstance⟩⟩, + fun ⟨_, _⟩ ↦ isFiniteLength_of_exists_compositionSeries + (exists_compositionSeries_of_isNoetherian_isArtinian R M)⟩ + +theorem isFiniteLength_iff_exists_compositionSeries : + IsFiniteLength R M ↔ ∃ s : CompositionSeries (Submodule R M), s.head = ⊥ ∧ s.last = ⊤ := + ⟨fun h ↦ have ⟨_, _⟩ := isFiniteLength_iff_isNoetherian_isArtinian.mp h + exists_compositionSeries_of_isNoetherian_isArtinian R M, + isFiniteLength_of_exists_compositionSeries⟩ + +theorem IsSemisimpleModule.finite_tfae [IsSemisimpleModule R M] : + List.TFAE [Module.Finite R M, IsNoetherian R M, IsArtinian R M, IsFiniteLength R M, + ∃ s : Set (Submodule R M), s.Finite ∧ CompleteLattice.SetIndependent s ∧ + sSup s = ⊤ ∧ ∀ m ∈ s, IsSimpleModule R m] := by + rw [isFiniteLength_iff_isNoetherian_isArtinian] + obtain ⟨s, hs⟩ := IsSemisimpleModule.exists_setIndependent_sSup_simples_eq_top R M + tfae_have 1 ↔ 2 := ⟨fun _ ↦ inferInstance, fun _ ↦ inferInstance⟩ + tfae_have 2 → 5 := fun _ ↦ ⟨s, CompleteLattice.WellFoundedGT.finite_of_setIndependent hs.1, hs⟩ + tfae_have 3 → 5 := fun _ ↦ ⟨s, CompleteLattice.WellFoundedLT.finite_of_setIndependent hs.1, hs⟩ + tfae_have 5 → 4 := fun ⟨s, fin, _, sSup_eq_top, simple⟩ ↦ by + rw [← isNoetherian_top_iff, ← Submodule.topEquiv.isArtinian_iff, + ← sSup_eq_top, sSup_eq_iSup, ← iSup_subtype''] + rw [SetCoe.forall'] at simple + have := fin.to_subtype + exact ⟨isNoetherian_iSup, isArtinian_iSup⟩ + tfae_have 4 → 2 := And.left + tfae_have 4 → 3 := And.right + tfae_finish + +instance [IsSemisimpleModule R M] [Module.Finite R M] : IsArtinian R M := + (IsSemisimpleModule.finite_tfae.out 0 2).mp ‹_› + +/- The following instances are now automatic: +example [IsSemisimpleRing R] : IsNoetherianRing R := inferInstance +example [IsSemisimpleRing R] : IsArtinianRing R := inferInstance +-/ diff --git a/Mathlib/RingTheory/FinitePresentation.lean b/Mathlib/RingTheory/FinitePresentation.lean index b5f8a9e4728c8..566a54bf9738d 100644 --- a/Mathlib/RingTheory/FinitePresentation.lean +++ b/Mathlib/RingTheory/FinitePresentation.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ import Mathlib.RingTheory.FiniteType +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.MvPolynomial.Tower -import Mathlib.RingTheory.Ideal.QuotientOperations /-! # Finiteness conditions in commutative algebra @@ -261,7 +261,7 @@ theorem of_restrict_scalars_finitePresentation [Algebra A B] [IsScalarTower R A (Ideal.span s₀).toAddSubmonoid := by have : x ∈ (⊤ : Subalgebra R AX) := trivial rw [← ht''] at this - refine adjoin_induction this ?_ ?_ ?_ ?_ + refine adjoin_induction ?_ ?_ ?_ ?_ this · rintro _ (⟨x, hx, rfl⟩ | ⟨i, rfl⟩) · rw [MvPolynomial.algebraMap_eq, ← sub_add_cancel (MvPolynomial.C x) (map (algebraMap R A) (t' ⟨x, hx⟩)), add_comm] @@ -275,9 +275,9 @@ theorem of_restrict_scalars_finitePresentation [Algebra A B] [IsScalarTower R A · intro r apply AddSubmonoid.mem_sup_left exact ⟨C r, map_C _ _⟩ - · intro _ _ h₁ h₂ + · intro _ _ _ _ h₁ h₂ exact add_mem h₁ h₂ - · intro x₁ x₂ h₁ h₂ + · intro x₁ x₂ _ _ h₁ h₂ obtain ⟨_, ⟨p₁, rfl⟩, q₁, hq₁, rfl⟩ := AddSubmonoid.mem_sup.mp h₁ obtain ⟨_, ⟨p₂, rfl⟩, q₂, hq₂, rfl⟩ := AddSubmonoid.mem_sup.mp h₂ rw [add_mul, mul_add, add_assoc, ← map_mul] @@ -340,7 +340,7 @@ theorem ker_fg_of_mvPolynomial {n : ℕ} (f : MvPolynomial (Fin n) R →ₐ[R] A have : x ∈ adjoin R (Set.range X : Set RXn) := by rw [adjoin_range_X] trivial - refine adjoin_induction this ?_ ?_ ?_ ?_ + refine adjoin_induction ?_ ?_ ?_ ?_ this · rintro _ ⟨i, rfl⟩ rw [← sub_add_cancel (X i) (aeval h (g i)), add_comm] apply AddSubmonoid.add_mem_sup @@ -351,9 +351,9 @@ theorem ker_fg_of_mvPolynomial {n : ℕ} (f : MvPolynomial (Fin n) R →ₐ[R] A · intro r apply AddSubmonoid.mem_sup_left exact ⟨C r, aeval_C _ _⟩ - · intro _ _ h₁ h₂ + · intro _ _ _ _ h₁ h₂ exact add_mem h₁ h₂ - · intro p₁ p₂ h₁ h₂ + · intro p₁ p₂ _ _ h₁ h₂ obtain ⟨_, ⟨x₁, rfl⟩, y₁, hy₁, rfl⟩ := AddSubmonoid.mem_sup.mp h₁ obtain ⟨_, ⟨x₂, rfl⟩, y₂, hy₂, rfl⟩ := AddSubmonoid.mem_sup.mp h₂ rw [mul_add, add_mul, add_assoc, ← map_mul] diff --git a/Mathlib/RingTheory/FiniteType.lean b/Mathlib/RingTheory/FiniteType.lean index ed78e1a416de7..2f5d0d3bf7abf 100644 --- a/Mathlib/RingTheory/FiniteType.lean +++ b/Mathlib/RingTheory/FiniteType.lean @@ -3,7 +3,9 @@ Copyright (c) 2020 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ +import Mathlib.Algebra.FreeAlgebra import Mathlib.RingTheory.Adjoin.Tower +import Mathlib.RingTheory.Ideal.Quotient.Operations /-! # Finiteness conditions in commutative algebra @@ -111,6 +113,10 @@ theorem trans [Algebra S A] [IsScalarTower R S A] (hRS : FiniteType R S) (hSA : FiniteType R A := ⟨fg_trans' hRS.1 hSA.1⟩ +instance quotient (R : Type*) {S : Type*} [CommSemiring R] [CommRing S] [Algebra R S] (I : Ideal S) + [h : Algebra.FiniteType R S] : Algebra.FiniteType R (S ⧸ I) := + Algebra.FiniteType.trans h inferInstance + /-- An algebra is finitely generated if and only if it is a quotient of a free algebra whose variables are indexed by a finset. -/ theorem iff_quotient_freeAlgebra : @@ -403,10 +409,10 @@ theorem mvPolynomial_aeval_of_surjective_of_closure [AddCommMonoid M] [CommSemir intro f induction' f using induction_on with m f g ihf ihg r f ih · have : m ∈ closure S := hS.symm ▸ mem_top _ - refine AddSubmonoid.closure_induction this (fun m hm => ?_) ?_ ?_ + refine AddSubmonoid.closure_induction (fun m hm => ?_) ?_ ?_ this · exact ⟨MvPolynomial.X ⟨m, hm⟩, MvPolynomial.aeval_X _ _⟩ · exact ⟨1, map_one _⟩ - · rintro m₁ m₂ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ + · rintro m₁ m₂ _ _ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ exact ⟨P₁ * P₂, by rw [map_mul, hP₁, hP₂, of_apply, of_apply, of_apply, single_mul_single, @@ -428,10 +434,10 @@ theorem freeAlgebra_lift_of_surjective_of_closure [CommSemiring R] {S : Set M} intro f induction' f using induction_on with m f g ihf ihg r f ih · have : m ∈ closure S := hS.symm ▸ mem_top _ - refine AddSubmonoid.closure_induction this (fun m hm => ?_) ?_ ?_ + refine AddSubmonoid.closure_induction (fun m hm => ?_) ?_ ?_ this · exact ⟨FreeAlgebra.ι R ⟨m, hm⟩, FreeAlgebra.lift_ι_apply _ _⟩ · exact ⟨1, map_one _⟩ - · rintro m₁ m₂ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ + · rintro m₁ m₂ _ _ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ exact ⟨P₁ * P₂, by rw [map_mul, hP₁, hP₂, of_apply, of_apply, of_apply, single_mul_single, @@ -571,10 +577,10 @@ theorem mvPolynomial_aeval_of_surjective_of_closure [CommMonoid M] [CommSemiring intro f induction' f using induction_on with m f g ihf ihg r f ih · have : m ∈ closure S := hS.symm ▸ mem_top _ - refine Submonoid.closure_induction this (fun m hm => ?_) ?_ ?_ + refine Submonoid.closure_induction (fun m hm => ?_) ?_ ?_ this · exact ⟨MvPolynomial.X ⟨m, hm⟩, MvPolynomial.aeval_X _ _⟩ · exact ⟨1, map_one _⟩ - · rintro m₁ m₂ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ + · rintro m₁ m₂ _ _ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ exact ⟨P₁ * P₂, by rw [map_mul, hP₁, hP₂, of_apply, of_apply, of_apply, single_mul_single, one_mul]⟩ @@ -595,10 +601,10 @@ theorem freeAlgebra_lift_of_surjective_of_closure [CommSemiring R] {S : Set M} intro f induction' f using induction_on with m f g ihf ihg r f ih · have : m ∈ closure S := hS.symm ▸ mem_top _ - refine Submonoid.closure_induction this (fun m hm => ?_) ?_ ?_ + refine Submonoid.closure_induction (fun m hm => ?_) ?_ ?_ this · exact ⟨FreeAlgebra.ι R ⟨m, hm⟩, FreeAlgebra.lift_ι_apply _ _⟩ · exact ⟨1, map_one _⟩ - · rintro m₁ m₂ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ + · rintro m₁ m₂ _ _ ⟨P₁, hP₁⟩ ⟨P₂, hP₂⟩ exact ⟨P₁ * P₂, by rw [map_mul, hP₁, hP₂, of_apply, of_apply, of_apply, single_mul_single, one_mul]⟩ @@ -682,7 +688,7 @@ instance (priority := 100) CommRing.orzechProperty ((f.restrictScalars A).restrict fun x hx ↦ ?_ : N' →ₗ[A] M') (fun _ _ h ↦ injective_subtype _ (hi congr(($h).1))) fun ⟨x, hx⟩ ↦ ?_) ⟨n, (subset_span (by simp))⟩ (Subtype.val_injective hn)).1) - · induction hx using span_induction' with + · induction hx using span_induction with | mem x hx => change i x ∈ M' simp only [Set.singleton_union, Set.mem_insert_iff, Set.mem_range] at hx @@ -701,7 +707,7 @@ instance (priority := 100) CommRing.orzechProperty | zero => simp | add x _ y _ hx hy => rw [map_add]; exact add_mem hx hy | smul a x _ hx => rw [map_smul]; exact smul_mem _ _ hx - · induction hx using span_induction' with + · induction hx using span_induction with | mem x hx => change f x ∈ M' simp only [Set.singleton_union, Set.mem_insert_iff, Set.mem_range] at hx @@ -714,12 +720,12 @@ instance (priority := 100) CommRing.orzechProperty suffices x ∈ LinearMap.range ((f.restrictScalars A).domRestrict N') by obtain ⟨a, ha⟩ := this exact ⟨a, Subtype.val_injective ha⟩ - induction hx using span_induction' with + induction hx using span_induction with | mem x hx => obtain ⟨j, rfl⟩ := hx exact ⟨⟨nj j, subset_span (by simp)⟩, hnj j⟩ | zero => exact zero_mem _ - | add x _ y _ hx hy => exact add_mem hx hy + | add x y _ _ hx hy => exact add_mem hx hy | smul a x _ hx => exact smul_mem _ a hx end Orzech diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index 0039e1437e417..74a7408d863d7 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -5,12 +5,12 @@ Authors: Johan Commelin -/ import Mathlib.Algebra.Algebra.RestrictScalars import Mathlib.Algebra.Algebra.Subalgebra.Basic -import Mathlib.LinearAlgebra.Quotient -import Mathlib.LinearAlgebra.StdBasis import Mathlib.GroupTheory.Finiteness +import Mathlib.LinearAlgebra.Basis.Cardinality +import Mathlib.LinearAlgebra.Quotient.Defs +import Mathlib.LinearAlgebra.StdBasis import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Nilpotent.Defs -import Mathlib.LinearAlgebra.Basis.Cardinality import Mathlib.Tactic.Algebraize /-! @@ -194,7 +194,7 @@ variable {f} theorem fg_of_fg_map_injective (f : M →ₗ[R] P) (hf : Function.Injective f) {N : Submodule R M} (hfn : (N.map f).FG) : N.FG := let ⟨t, ht⟩ := hfn - ⟨t.preimage f fun x _ y _ h => hf h, + ⟨t.preimage f fun _ _ _ _ h => hf h, Submodule.map_injective_of_injective hf <| by rw [map_span, Finset.coe_preimage, Set.image_preimage_eq_inter_range, Set.inter_eq_self_of_subset_left, ht] @@ -493,6 +493,34 @@ theorem exists_radical_pow_le_of_fg {R : Type*} [CommSemiring R] (I : Ideal R) ( rw [add_comm, Nat.add_sub_assoc h.le] apply Nat.le_add_right +theorem exists_pow_le_of_le_radical_of_fg_radical {R : Type*} [CommSemiring R] {I J : Ideal R} + (hIJ : I ≤ J.radical) (hJ : J.radical.FG) : + ∃ k : ℕ, I ^ k ≤ J := by + obtain ⟨k, hk⟩ := J.exists_radical_pow_le_of_fg hJ + use k + calc + I ^ k ≤ J.radical ^ k := Ideal.pow_right_mono hIJ _ + _ ≤ J := hk + +@[deprecated (since := "2024-10-24")] +alias exists_pow_le_of_le_radical_of_fG := exists_pow_le_of_le_radical_of_fg_radical + +lemma exists_pow_le_of_le_radical_of_fg {R : Type*} [CommSemiring R] {I J : Ideal R} + (h' : I ≤ J.radical) (h : I.FG) : + ∃ n : ℕ, I ^ n ≤ J := by + revert h' + apply Submodule.fg_induction _ _ _ _ _ I h + · intro x hJ + simp only [Ideal.submodule_span_eq, Ideal.span_le, + Set.singleton_subset_iff, SetLike.mem_coe] at hJ + obtain ⟨n, hn⟩ := hJ + refine ⟨n, by simpa [Ideal.span_singleton_pow, Ideal.span_le]⟩ + · intros I₁ I₂ h₁ h₂ hJ + obtain ⟨n₁, hn₁⟩ := h₁ (le_sup_left.trans hJ) + obtain ⟨n₂, hn₂⟩ := h₂ (le_sup_right.trans hJ) + use n₁ + n₂ + exact Ideal.sup_pow_add_le_pow_sup_pow.trans (sup_le hn₁ hn₂) + end Ideal section ModuleAndAlgebra @@ -537,6 +565,22 @@ lemma exists_fin' [Module.Finite R M] : ∃ (n : ℕ) (f : (Fin n → R) →ₗ[ refine ⟨n, Basis.constr (Pi.basisFun R _) ℕ s, ?_⟩ rw [← LinearMap.range_eq_top, Basis.constr_range, hs] +variable (R) in +lemma _root_.Module.finite_of_finite [Finite R] [Module.Finite R M] : Finite M := by + obtain ⟨n, f, hf⟩ := exists_fin' R M; exact .of_surjective f hf + +@[deprecated (since := "2024-10-13")] +alias _root_.FiniteDimensional.finite_of_finite := finite_of_finite + +-- See note [lower instance priority] +instance (priority := 100) of_finite [Finite M] : Module.Finite R M := by + cases nonempty_fintype M + exact ⟨⟨Finset.univ, by rw [Finset.coe_univ]; exact Submodule.span_univ⟩⟩ + +/-- A module over a finite ring has finite dimension iff it is finite. -/ +lemma _root_.Module.finite_iff_finite [Finite R] : Module.Finite R M ↔ Finite M := + ⟨fun _ ↦ finite_of_finite R, fun _ ↦ .of_finite⟩ + theorem of_surjective [hM : Module.Finite R M] (f : M →ₗ[R] N) (hf : Surjective f) : Module.Finite R N := ⟨by @@ -620,6 +664,12 @@ instance span_singleton (x : M) : Module.Finite R (R ∙ x) := instance span_finset (s : Finset M) : Module.Finite R (span R (s : Set M)) := ⟨(Submodule.fg_top _).mpr ⟨s, rfl⟩⟩ +lemma _root_.Set.Finite.submoduleSpan [Finite R] {s : Set M} (hs : s.Finite) : + (Submodule.span R s : Set M).Finite := by + lift s to Finset M using hs + rw [Set.Finite, ← Module.finite_iff_finite (R := R)] + dsimp + infer_instance theorem Module.End.isNilpotent_iff_of_finite {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] [Module.Finite R M] {f : End R M} : @@ -630,7 +680,7 @@ theorem Module.End.isNilpotent_iff_of_finite {R M : Type*} [CommSemiring R] [Add use Finset.sup S g ext m have hm : m ∈ Submodule.span R S := by simp [hS] - induction hm using Submodule.span_induction' with + induction hm using Submodule.span_induction with | mem x hx => exact LinearMap.pow_map_zero_of_le (Finset.le_sup hx) (hg x) | zero => simp | add => simp_all @@ -702,7 +752,7 @@ instance Module.Finite.tensorProduct [CommSemiring R] [AddCommMonoid M] [Module out := (TensorProduct.map₂_mk_top_top_eq_top R M N).subst (hM.out.map₂ _ hN.out) /-- If a free module is finite, then any arbitrary basis is finite. -/ -lemma Module.Finite.finite_basis {R M} [Semiring R] [Nontrivial R] [AddCommGroup M] [Module R M] +lemma Module.Finite.finite_basis {R M} [Semiring R] [Nontrivial R] [AddCommMonoid M] [Module R M] {ι} [Module.Finite R M] (b : Basis ι R M) : _root_.Finite ι := let ⟨s, hs⟩ := ‹Module.Finite R M› diff --git a/Mathlib/RingTheory/Flat/Basic.lean b/Mathlib/RingTheory/Flat/Basic.lean index 813b32f84d0ac..9c3da85861bf3 100644 --- a/Mathlib/RingTheory/Flat/Basic.lean +++ b/Mathlib/RingTheory/Flat/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johan Commelin, Jujian Zhang +Authors: Johan Commelin, Jujian Zhang, Yongle Hu -/ import Mathlib.Algebra.DirectSum.Finsupp import Mathlib.Algebra.DirectSum.Module @@ -39,14 +39,13 @@ See . * `Module.Flat.preserves_injective_linearMap`: If `M` is a flat module then tensoring with `M` preserves injectivity of linear maps. This lemma is fully universally polymorphic in all arguments, i.e. `R`, `M` and linear maps `N → N'` can all have different universe levels. -* `Module.Flat.iff_rTensor_preserves_injective_linearMap`: a module is flat iff tensoring preserves - injectivity in the ring's universe (or higher). - -## Implementation notes -In `Module.Flat.iff_rTensor_preserves_injective_linearMap`, we require that the universe level of -the ring is lower than or equal to that of the module. This requirement is to make sure ideals of -the ring can be lifted to the universe of the module. It is unclear if this lemma also holds -when the module lives in a lower universe. +* `Module.Flat.iff_rTensor_preserves_injective_linearMap`: a module is flat iff tensoring modules + in the higher universe preserves injectivity . +* `Module.Flat.lTensor_exact`: If `M` is a flat module then tensoring with `M` is an exact + functor. This lemma is fully universally polymorphic in all arguments, i.e. + `R`, `M` and linear maps `N → N' → N''` can all have different universe levels. +* `Module.Flat.iff_lTensor_exact`: a module is flat iff tensoring modules + in the higher universe is an exact functor. ## TODO @@ -55,7 +54,7 @@ when the module lives in a lower universe. -/ -universe u v w +universe v' u v w namespace Module @@ -144,6 +143,24 @@ lemma of_linearEquiv [f : Flat R M] (e : N ≃ₗ[R] M) : Flat R N := by have h : e.symm.toLinearMap.comp e.toLinearMap = LinearMap.id := by simp exact of_retract _ _ _ e.toLinearMap e.symm.toLinearMap h +/-- If an `R`-module `M` is linearly equivalent to another `R`-module `N`, then `M` is flat + if and only if `N` is flat. -/ +lemma equiv_iff (e : M ≃ₗ[R] N) : Flat R M ↔ Flat R N := + ⟨fun _ => of_linearEquiv R M N e.symm, fun _ => of_linearEquiv R N M e⟩ + +instance ulift [Module.Flat R M] : Module.Flat R (ULift.{v'} M) := + of_linearEquiv R M (ULift.{v'} M) ULift.moduleEquiv + +instance (priority := 100) of_ulift [Module.Flat R (ULift.{v'} M)] : Module.Flat R M := + of_linearEquiv R (ULift.{v'} M) M ULift.moduleEquiv.symm + +instance shrink [Small.{v'} M] [Module.Flat R M] : Module.Flat R (Shrink.{v'} M) := + of_linearEquiv R M (Shrink.{v'} M) (Shrink.linearEquiv M R) + +instance (priority := 100) of_shrink [Small.{v'} M] [Module.Flat R (Shrink.{v'} M)] : + Module.Flat R M := + of_linearEquiv R (Shrink.{v'} M) M (Shrink.linearEquiv M R).symm + /-- A direct sum of flat `R`-modules is flat. -/ instance directSum (ι : Type v) (M : ι → Type w) [(i : ι) → AddCommGroup (M i)] [(i : ι) → Module R (M i)] [F : (i : ι) → (Flat R (M i))] : Flat R (⨁ i, M i) := by @@ -250,28 +267,55 @@ theorem lTensor_preserves_injective_linearMap {N' : Type*} [AddCommGroup N'] [Mo (L.lTensor_inj_iff_rTensor_inj M).2 (rTensor_preserves_injective_linearMap L hL) variable (R M) in -/-- -M is flat if and only if `f ⊗ 𝟙 M` is injective whenever `f` is an injective linear map. --/ -lemma iff_rTensor_preserves_injective_linearMap [Small.{v} R] : - Flat R M ↔ - ∀ ⦃N N' : Type v⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] - (L : N →ₗ[R] N'), Function.Injective L → Function.Injective (L.rTensor M) := by - rw [iff_characterModule_injective, - injective_characterModule_iff_rTensor_preserves_injective_linearMap] +/-- `M` is flat if and only if `f ⊗ 𝟙 M` is injective whenever `f` is an injective linear map. + See `Module.Flat.iff_rTensor_preserves_injective_linearMap` to specialize the universe of + `N, N', N''` to `Type (max u v)`. -/ +lemma iff_rTensor_preserves_injective_linearMap' [Small.{v'} R] [Small.{v'} M] : Flat R M ↔ + ∀ ⦃N N' : Type v'⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] + (f : N →ₗ[R] N') (_ : Function.Injective f), Function.Injective (f.rTensor M) := + (Module.Flat.equiv_iff R M (Shrink.{v'} M) (Shrink.linearEquiv M R).symm).trans <| + iff_characterModule_injective.trans <| + (injective_characterModule_iff_rTensor_preserves_injective_linearMap R (Shrink.{v'} M)).trans + <| forall₅_congr <| fun N N' _ _ _ => forall₃_congr <| fun _ f _ => + let frmu := f.rTensor (Shrink.{v'} M) + let frm := f.rTensor M + let emn := TensorProduct.congr (LinearEquiv.refl R N) (Shrink.linearEquiv M R) + let emn' := TensorProduct.congr (LinearEquiv.refl R N') (Shrink.linearEquiv M R) + have h : emn'.toLinearMap.comp frmu = frm.comp emn.toLinearMap := TensorProduct.ext rfl + (EquivLike.comp_injective frmu emn').symm.trans <| + (congrArg Function.Injective (congrArg DFunLike.coe h)).to_iff.trans <| + EquivLike.injective_comp emn frm variable (R M) in -/-- -M is flat if and only if `𝟙 M ⊗ f` is injective whenever `f` is an injective linear map. --/ -lemma iff_lTensor_preserves_injective_linearMap [Small.{v} R] : - Flat R M ↔ - ∀ ⦃N N' : Type v⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] +/-- `M` is flat if and only if `f ⊗ 𝟙 M` is injective whenever `f` is an injective linear map. + See `Module.Flat.iff_rTensor_preserves_injective_linearMap'` to generalize the universe of + `N, N', N''` to any universe that is higher than `R` and `M`. -/ +lemma iff_rTensor_preserves_injective_linearMap : Flat R M ↔ + ∀ ⦃N N' : Type (max u v)⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] + (f : N →ₗ[R] N') (_ : Function.Injective f), Function.Injective (f.rTensor M) := + iff_rTensor_preserves_injective_linearMap'.{max u v} R M + +variable (R M) in +/-- `M` is flat if and only if `𝟙 M ⊗ f` is injective whenever `f` is an injective linear map. + See `Module.Flat.iff_lTensor_preserves_injective_linearMap` to specialize the universe of + `N, N', N''` to `Type (max u v)`. -/ +lemma iff_lTensor_preserves_injective_linearMap' [Small.{v'} R] [Small.{v'} M] : Flat R M ↔ + ∀ ⦃N N' : Type v'⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] (L : N →ₗ[R] N'), Function.Injective L → Function.Injective (L.lTensor M) := by - simp_rw [iff_rTensor_preserves_injective_linearMap, LinearMap.lTensor_inj_iff_rTensor_inj] + simp_rw [iff_rTensor_preserves_injective_linearMap', LinearMap.lTensor_inj_iff_rTensor_inj] + +variable (R M) in +/-- `M` is flat if and only if `𝟙 M ⊗ f` is injective whenever `f` is an injective linear map. + See `Module.Flat.iff_lTensor_preserves_injective_linearMap'` to generalize the universe of + `N, N', N''` to any universe that is higher than `R` and `M`. -/ +lemma iff_lTensor_preserves_injective_linearMap : Flat R M ↔ + ∀ ⦃N N' : Type (max u v)⦄ [AddCommGroup N] [AddCommGroup N'] [Module R N] [Module R N'] + (f : N →ₗ[R] N') (_ : Function.Injective f), Function.Injective (f.lTensor M) := + iff_lTensor_preserves_injective_linearMap'.{max u v} R M variable (M) in -lemma lTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ +/-- If `M` is flat then `M ⊗ -` is an exact functor. -/ +lemma lTensor_exact [Flat R M] ⦃N N' N'' : Type*⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄ (exact : Function.Exact f g) : Function.Exact (f.lTensor M) (g.lTensor M) := by @@ -280,18 +324,15 @@ lemma lTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ Submodule.subtype _ ∘ₗ (LinearMap.quotKerEquivRange g).toLinearMap ∘ₗ Submodule.quotEquivOfEq (LinearMap.range f) (LinearMap.ker g) (LinearMap.exact_iff.mp exact).symm - suffices exact1 : Function.Exact (f.lTensor M) (π.lTensor M) by - rw [show g = ι.comp π by aesop, lTensor_comp] - exact exact1.comp_injective - (inj := iff_lTensor_preserves_injective_linearMap R M |>.mp flat _ <| by - simpa [ι] using Subtype.val_injective) - (h0 := map_zero _) - + rw [show g = ι.comp π from rfl, lTensor_comp] + exact exact1.comp_injective _ (lTensor_preserves_injective_linearMap ι <| by + simpa [ι] using Subtype.val_injective) (map_zero _) exact _root_.lTensor_exact _ (fun x => by simp [π]) Quotient.surjective_Quotient_mk'' variable (M) in -lemma rTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ +/-- If `M` is flat then `- ⊗ M` is an exact functor. -/ +lemma rTensor_exact [Flat R M] ⦃N N' N'' : Type*⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄ (exact : Function.Exact f g) : Function.Exact (f.rTensor M) (g.rTensor M) := by @@ -300,41 +341,55 @@ lemma rTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ Submodule.subtype _ ∘ₗ (LinearMap.quotKerEquivRange g).toLinearMap ∘ₗ Submodule.quotEquivOfEq (LinearMap.range f) (LinearMap.ker g) (LinearMap.exact_iff.mp exact).symm - suffices exact1 : Function.Exact (f.rTensor M) (π.rTensor M) by - rw [show g = ι.comp π by aesop, rTensor_comp] - exact exact1.comp_injective - (inj := iff_rTensor_preserves_injective_linearMap R M |>.mp flat _ <| by - simpa [ι] using Subtype.val_injective) - (h0 := map_zero _) - - exact _root_.rTensor_exact _ (fun x => by simp [π]) Quotient.surjective_Quotient_mk'' - -/-- -M is flat if and only if `M ⊗ -` is a left exact functor. --/ -lemma iff_lTensor_exact [Small.{v} R] : - Flat R M ↔ - ∀ ⦃N N' N'' : Type v⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] + rw [show g = ι.comp π from rfl, rTensor_comp] + exact exact1.comp_injective _ (rTensor_preserves_injective_linearMap ι <| by + simpa [ι] using Subtype.val_injective) (map_zero _) + exact _root_.rTensor_exact M (fun x => by simp [π]) Quotient.surjective_Quotient_mk'' + +/-- `M` is flat if and only if `M ⊗ -` is an exact functor. See + `Module.Flat.iff_lTensor_exact` to specialize the universe of `N, N', N''` to `Type (max u v)`. -/ +theorem iff_lTensor_exact' [Small.{v'} R] [Small.{v'} M] : Flat R M ↔ + ∀ ⦃N N' N'' : Type v'⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄, Function.Exact f g → Function.Exact (f.lTensor M) (g.lTensor M) := by - refine ⟨fun _ => lTensor_exact M, fun H => iff_lTensor_preserves_injective_linearMap R M |>.mpr + refine ⟨fun _ => lTensor_exact M, fun H => iff_lTensor_preserves_injective_linearMap' R M |>.mpr fun N' N'' _ _ _ _ L hL => LinearMap.ker_eq_bot |>.mp <| eq_bot_iff |>.mpr fun x (hx : _ = 0) => ?_⟩ - simpa [Eq.comm] using @H PUnit N' N'' _ _ _ _ _ _ 0 L (fun x => by aesop) x |>.mp hx + simpa [Eq.comm] using @H PUnit N' N'' _ _ _ _ _ _ 0 L (fun x => by + simp_rw [Set.mem_range, LinearMap.zero_apply, exists_const] + exact (L.map_eq_zero_iff hL).trans eq_comm) x |>.mp hx + +/-- `M` is flat if and only if `M ⊗ -` is an exact functor. + See `Module.Flat.iff_lTensor_exact'` to generalize the universe of + `N, N', N''` to any universe that is higher than `R` and `M`. -/ +theorem iff_lTensor_exact : Flat R M ↔ + ∀ ⦃N N' N'' : Type (max u v)⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] + [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄, + Function.Exact f g → Function.Exact (f.lTensor M) (g.lTensor M) := + iff_lTensor_exact'.{max u v} -/-- -M is flat if and only if `- ⊗ M` is a left exact functor. --/ -lemma iff_rTensor_exact [Small.{v} R] : - Flat R M ↔ - ∀ ⦃N N' N'' : Type v⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] +/-- `M` is flat if and only if `- ⊗ M` is an exact functor. See + `Module.Flat.iff_rTensor_exact` to specialize the universe of `N, N', N''` to `Type (max u v)`. -/ +theorem iff_rTensor_exact' [Small.{v'} R] [Small.{v'} M] : Flat R M ↔ + ∀ ⦃N N' N'' : Type v'⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄, Function.Exact f g → Function.Exact (f.rTensor M) (g.rTensor M) := by - refine ⟨fun _ => rTensor_exact M, fun H => iff_rTensor_preserves_injective_linearMap R M |>.mpr + refine ⟨fun _ => rTensor_exact M, fun H => iff_rTensor_preserves_injective_linearMap' R M |>.mpr fun N' N'' _ _ _ _ L hL => LinearMap.ker_eq_bot |>.mp <| eq_bot_iff |>.mpr fun x (hx : _ = 0) => ?_⟩ - simpa [Eq.comm] using @H PUnit N' N'' _ _ _ _ _ _ 0 L (fun x => by aesop) x |>.mp hx + simpa [Eq.comm] using @H PUnit N' N'' _ _ _ _ _ _ 0 L (fun x => by + simp_rw [Set.mem_range, LinearMap.zero_apply, exists_const] + exact (L.map_eq_zero_iff hL).trans eq_comm) x |>.mp hx + +/-- `M` is flat if and only if `- ⊗ M` is an exact functor. + See `Module.Flat.iff_rTensor_exact'` to generalize the universe of + `N, N', N''` to any universe that is higher than `R` and `M`. -/ +theorem iff_rTensor_exact : Flat R M ↔ + ∀ ⦃N N' N'' : Type (max u v)⦄ [AddCommGroup N] [AddCommGroup N'] [AddCommGroup N''] + [Module R N] [Module R N'] [Module R N''] ⦃f : N →ₗ[R] N'⦄ ⦃g : N' →ₗ[R] N''⦄, + Function.Exact f g → Function.Exact (f.rTensor M) (g.rTensor M) := + iff_rTensor_exact'.{max u v} end Flat diff --git a/Mathlib/RingTheory/Flat/CategoryTheory.lean b/Mathlib/RingTheory/Flat/CategoryTheory.lean index ea7bc816d2f57..ea6d1442dad38 100644 --- a/Mathlib/RingTheory/Flat/CategoryTheory.lean +++ b/Mathlib/RingTheory/Flat/CategoryTheory.lean @@ -52,7 +52,7 @@ 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.ofHom f) (ModuleCat.ofHom g) + H (.mk (ModuleCat.asHom f) (ModuleCat.asHom g) (DFunLike.ext _ _ h.apply_apply_eq_zero)) (moduleCat_exact_iff_function_exact _ |>.2 h)⟩ @@ -62,7 +62,7 @@ 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.ofHom f) (ModuleCat.ofHom g) + H (.mk (ModuleCat.asHom f) (ModuleCat.asHom g) (DFunLike.ext _ _ h.apply_apply_eq_zero)) (moduleCat_exact_iff_function_exact _ |>.2 h)⟩ diff --git a/Mathlib/RingTheory/Flat/FaithfullyFlat.lean b/Mathlib/RingTheory/Flat/FaithfullyFlat.lean new file mode 100644 index 0000000000000..8cd4172217363 --- /dev/null +++ b/Mathlib/RingTheory/Flat/FaithfullyFlat.lean @@ -0,0 +1,480 @@ +/- +Copyright (c) 2024 Judith Ludwig, Florent Schaffhauser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Judith Ludwig, Florent Schaffhauser, Yunzhou Xie, Jujian Zhang +-/ + +import Mathlib.LinearAlgebra.TensorProduct.Quotient +import Mathlib.RingTheory.Flat.Stability +import Mathlib.RingTheory.Ideal.Quotient.Basic + +/-! +# Faithfully flat modules + +A module `M` over a commutative ring `R` is *faithfully flat* if it is flat and `IM ≠ M` whenever +`I` is a maximal ideal of `R`. + +## Main declaration + +- `Module.FaithfullyFlat`: the predicate asserting that an `R`-module `M` is faithfully flat. + +## Main theorems + +- `Module.FaithfullyFlat.iff_flat_and_proper_ideal`: an `R`-module `M` is faithfully flat iff it is + flat and for all proper ideals `I` of `R`, `I • M ≠ M`. +- `Module.FaithfullyFlat.iff_flat_and_rTensor_faithful`: an `R`-module `M` is faithfully flat iff it + is flat and tensoring with `M` is faithful, i.e. `N ≠ 0` implies `N ⊗ M ≠ 0`. +- `Module.FaithfullyFlat.iff_flat_and_lTensor_faithful`: an `R`-module `M` is faithfully flat iff it + is flat and tensoring with `M` is faithful, i.e. `N ≠ 0` implies `M ⊗ N ≠ 0`. +- `Module.FaithfullyFlat.iff_exact_iff_rTensor_exact`: an `R`-module `M` is faithfully flat iff + tensoring with `M` preserves and reflects exact sequences, i.e. the sequence `N₁ → N₂ → N₃` is + exact *iff* the sequence `N₁ ⊗ M → N₂ ⊗ M → N₃ ⊗ M` is exact. +- `Module.FaithfullyFlat.iff_exact_iff_lTensor_exact`: an `R`-module `M` is faithfully flat iff + tensoring with `M` preserves and reflects exact sequences, i.e. the sequence `N₁ → N₂ → N₃` is + exact *iff* the sequence `M ⊗ N₁ → M ⊗ N₂ → M ⊗ N₃` is exact. +- `Module.FaithfullyFlat.iff_zero_iff_lTensor_zero`: an `R`-module `M` is faithfully flat iff for + all linear maps `f : N → N'`, `f = 0` iff `M ⊗ f = 0`. +- `Module.FaithfullyFlat.iff_zero_iff_rTensor_zero`: an `R`-module `M` is faithfully flat iff for + all linear maps `f : N → N'`, `f = 0` iff `f ⊗ M = 0`. + +- `Module.FaithfullyFlat.of_linearEquiv`: modules linearly equivalent to a flat modules are flat +- `Module.FaithfullyFlat.comp`: if `S` is `R`-faithfully flat and `M` is `S`-faithfully flat, then + `M` is `R`-faithfully flat. + +- `Module.FaithfullyFlat.self`: the `R`-module `R` is faithfully flat. + +-/ + +universe u v + +open TensorProduct + +namespace Module + +variable (R : Type u) (M : Type v) [CommRing R] [AddCommGroup M] [Module R M] + +/-- +A module `M` over a commutative ring `R` is *faithfully flat* if it is flat and, +for all `R`-module homomorphism `f : N → N'` such that `id ⊗ f = 0`, we have `f = 0`. +-/ +@[mk_iff] class FaithfullyFlat extends Module.Flat R M : Prop where + submodule_ne_top : ∀ ⦃m : Ideal R⦄ (_ : Ideal.IsMaximal m), m • (⊤ : Submodule R M) ≠ ⊤ + +namespace FaithfullyFlat +instance self : FaithfullyFlat R R where + submodule_ne_top m h r := Ideal.eq_top_iff_one _ |>.not.1 h.ne_top <| by + simpa using show 1 ∈ (m • ⊤ : Ideal R) from r.symm ▸ ⟨⟩ + +section proper_ideal + +lemma iff_flat_and_proper_ideal : + FaithfullyFlat R M ↔ + (Flat R M ∧ ∀ (I : Ideal R), I ≠ ⊤ → I • (⊤ : Submodule R M) ≠ ⊤) := by + rw [faithfullyFlat_iff] + refine ⟨fun ⟨flat, h⟩ => ⟨flat, fun I hI r => ?_⟩, fun h => ⟨h.1, fun m hm => h.2 _ hm.ne_top⟩⟩ + obtain ⟨m, hm, le⟩ := I.exists_le_maximal hI + exact h hm <| eq_top_iff.2 <| show ⊤ ≤ m • ⊤ from r ▸ Submodule.smul_mono le (by simp [r]) + +lemma iff_flat_and_ideal_smul_eq_top : + FaithfullyFlat R M ↔ + (Flat R M ∧ ∀ (I : Ideal R), I • (⊤ : Submodule R M) = ⊤ → I = ⊤) := + iff_flat_and_proper_ideal R M |>.trans <| and_congr_right_iff.2 fun _ => iff_of_eq <| + forall_congr fun I => eq_iff_iff.2 <| by tauto + +end proper_ideal + +section faithful + +instance rTensor_nontrivial + [fl: FaithfullyFlat R M] (N : Type*) [AddCommGroup N] [Module R N] [Nontrivial N] : + Nontrivial (N ⊗[R] M) := by + obtain ⟨n, hn⟩ := nontrivial_iff_exists_ne (0 : N) |>.1 inferInstance + let I := (Submodule.span R {n}).annihilator + by_cases I_ne_top : I = ⊤ + · rw [Ideal.eq_top_iff_one, Submodule.mem_annihilator_span_singleton, one_smul] at I_ne_top + contradiction + let inc : R ⧸ I →ₗ[R] N := Submodule.liftQ _ ((LinearMap.lsmul R N).flip n) <| fun r hr => by + simpa only [LinearMap.mem_ker, LinearMap.flip_apply, LinearMap.lsmul_apply, + Submodule.mem_annihilator_span_singleton, I] using hr + have injective_inc : Function.Injective inc := LinearMap.ker_eq_bot.1 <| eq_bot_iff.2 <| by + intro r hr + induction r using Quotient.inductionOn' with | h r => + simpa only [Submodule.Quotient.mk''_eq_mk, Submodule.mem_bot, Submodule.Quotient.mk_eq_zero, + Submodule.mem_annihilator_span_singleton, LinearMap.mem_ker, Submodule.liftQ_apply, + LinearMap.flip_apply, LinearMap.lsmul_apply, I, inc] using hr + have ne_top := iff_flat_and_proper_ideal R M |>.1 fl |>.2 I I_ne_top + refine subsingleton_or_nontrivial _ |>.resolve_left fun rid => ?_ + exact False.elim <| ne_top <| Submodule.subsingleton_quotient_iff_eq_top.1 <| + Function.Injective.comp (g := LinearMap.rTensor M inc) + (fl.toFlat.rTensor_preserves_injective_linearMap inc injective_inc) + ((quotTensorEquivQuotSMul M I).symm.injective) |>.subsingleton + +instance lTensor_nontrivial + [FaithfullyFlat R M] (N : Type*) [AddCommGroup N] [Module R N] [Nontrivial N] : + Nontrivial (M ⊗[R] N) := + TensorProduct.comm R M N |>.toEquiv.nontrivial + +lemma rTensor_reflects_triviality + [FaithfullyFlat R M] (N : Type*) [AddCommGroup N] [Module R N] + [h : Subsingleton (N ⊗[R] M)] : Subsingleton N := by + revert h; change _ → _; contrapose + simp only [not_subsingleton_iff_nontrivial] + intro h + infer_instance + +lemma lTensor_reflects_triviality + [FaithfullyFlat R M] (N : Type*) [AddCommGroup N] [Module R N] + [Subsingleton (M ⊗[R] N)] : + Subsingleton N := by + haveI : Subsingleton (N ⊗[R] M) := (TensorProduct.comm R N M).toEquiv.injective.subsingleton + apply rTensor_reflects_triviality R M + +attribute [-simp] Ideal.Quotient.mk_eq_mk in +lemma iff_flat_and_rTensor_faithful : + FaithfullyFlat R M ↔ + (Flat R M ∧ + ∀ (N : Type max u v) [AddCommGroup N] [Module R N], + Nontrivial N → Nontrivial (N ⊗[R] M)) := by + refine ⟨fun fl => ⟨inferInstance, rTensor_nontrivial R M⟩, fun ⟨flat, faithful⟩ => ⟨?_⟩⟩ + intro m hm rid + specialize faithful (ULift (R ⧸ m)) inferInstance + haveI : Nontrivial ((R ⧸ m) ⊗[R] M) := + (congr (ULift.moduleEquiv : ULift (R ⧸ m) ≃ₗ[R] R ⧸ m) + (LinearEquiv.refl R M)).symm.toEquiv.nontrivial + have := (quotTensorEquivQuotSMul M m).toEquiv.symm.nontrivial + haveI H : Subsingleton (M ⧸ m • (⊤ : Submodule R M)) := by + rwa [Submodule.subsingleton_quotient_iff_eq_top] + rw [← not_nontrivial_iff_subsingleton] at H + contradiction + +lemma iff_flat_and_rTensor_reflects_triviality : + FaithfullyFlat R M ↔ + (Flat R M ∧ + ∀ (N : Type max u v) [AddCommGroup N] [Module R N], + Subsingleton (N ⊗[R] M) → Subsingleton N) := + iff_flat_and_rTensor_faithful R M |>.trans <| and_congr_right_iff.2 fun _ => iff_of_eq <| + forall_congr fun N => forall_congr fun _ => forall_congr fun _ => iff_iff_eq.1 <| by + simp only [← not_subsingleton_iff_nontrivial]; tauto + +lemma iff_flat_and_lTensor_faithful : + FaithfullyFlat R M ↔ + (Flat R M ∧ + ∀ (N : Type max u v) [AddCommGroup N] [Module R N], + Nontrivial N → Nontrivial (M ⊗[R] N)) := + iff_flat_and_rTensor_faithful R M |>.trans + ⟨fun ⟨flat, faithful⟩ => ⟨flat, fun N _ _ _ => + letI := faithful N inferInstance; (TensorProduct.comm R M N).toEquiv.nontrivial⟩, + fun ⟨flat, faithful⟩ => ⟨flat, fun N _ _ _ => + letI := faithful N inferInstance; (TensorProduct.comm R M N).symm.toEquiv.nontrivial⟩⟩ + +lemma iff_flat_and_lTensor_reflects_triviality : + FaithfullyFlat R M ↔ + (Flat R M ∧ + ∀ (N : Type max u v) [AddCommGroup N] [Module R N], + Subsingleton (M ⊗[R] N) → Subsingleton N) := + iff_flat_and_lTensor_faithful R M |>.trans <| and_congr_right_iff.2 fun _ => iff_of_eq <| + forall_congr fun N => forall_congr fun _ => forall_congr fun _ => iff_iff_eq.1 <| by + simp only [← not_subsingleton_iff_nontrivial]; tauto + +end faithful + +section exact + +/-! +### Faithfully flat modules and exact sequences + +In this section we prove that an `R`-module `M` is faithfully flat iff tensoring with `M` +preserves and reflects exact sequences. + +Let `N₁ -l₁₂-> N₂ -l₂₃-> N₃` be two linear maps. +- We first show that if `N₁ ⊗ M -> N₂ ⊗ M -> N₃ ⊗ M` is exact, then `N₁ -l₁₂-> N₂ -l₂₃-> N₃` is a + complex, i.e. `range l₁₂ ≤ ker l₂₃`. + This is `range_le_ker_of_exact_rTensor`. +- Then in `rTensor_reflects_exact`, we show `ker l₂₃ = range l₁₂` by considering the cohomology + `ker l₂₃ ⧸ range l₁₂`. +This shows that when `M` is faithfully flat, `- ⊗ M` reflects exact sequences. For details, see +comments in the proof. Since `M` is flat, `- ⊗ M` preserves exact sequences. + +On the other hand, if `- ⊗ M` preserves and reflects exact sequences, then `M` is faithfully flat. +- `M` is flat because `- ⊗ M` preserves exact sequences. +- We need to show that if `N ⊗ M = 0` then `N = 0`. Consider the sequence `N -0-> N -0-> 0`. After + tensoring with `M`, we get `N ⊗ M -0-> N ⊗ M -0-> 0` which is exact because `N ⊗ M = 0`. + Since `- ⊗ M` reflects exact sequences, `N = 0`. +-/ + +section arbitrary_universe + +variable {N1 : Type*} [AddCommGroup N1] [Module R N1] +variable {N2 : Type*} [AddCommGroup N2] [Module R N2] +variable {N3 : Type*} [AddCommGroup N3] [Module R N3] +variable (l12 : N1 →ₗ[R] N2) (l23 : N2 →ₗ[R] N3) + +/-- +If `M` is faithfully flat, then exactness of `N₁ ⊗ M -> N₂ ⊗ M -> N₃ ⊗ M` implies that the +composition `N₁ -> N₂ -> N₃` is `0`. + +Implementation detail, please use `rTensor_reflects_exact` instead. +-/ +lemma range_le_ker_of_exact_rTensor [fl : FaithfullyFlat R M] + (ex : Function.Exact (l12.rTensor M) (l23.rTensor M)) : + LinearMap.range l12 ≤ LinearMap.ker l23 := by + -- let `n1 ∈ N1`. We need to show `l23 (l12 n1) = 0`. Suppose this is not the case. + rintro _ ⟨n1, rfl⟩ + rw [LinearMap.mem_ker] + by_contra! hn1 + -- Let `E` be the submodule spanned by `l23 (l12 n1)`. Then because `l23 (l12 n1) ≠ 0`, we have + -- `E ≠ 0`. + let E : Submodule R N3 := Submodule.span R {l23 (l12 n1)} + have hE : Nontrivial E := + ⟨0, ⟨⟨l23 (l12 n1), Submodule.mem_span_singleton_self _⟩, Subtype.coe_ne_coe.1 hn1.symm⟩⟩ + + -- Since `N1 ⊗ M -> N2 ⊗ M -> N3 ⊗ M` is exact, we have `l23 (l12 n1) ⊗ₜ m = 0` for all `m : M`. + have eq1 : ∀ (m : M), l23 (l12 n1) ⊗ₜ[R] m = 0 := fun m ↦ + ex.apply_apply_eq_zero (n1 ⊗ₜ[R] m) + -- Then `E ⊗ M = 0`. Indeed, + have eq0 : (⊤ : Submodule R (E ⊗[R] M)) = ⊥ := by + -- suppose `x ∈ E ⊗ M`. We will show `x = 0`. + ext x + simp only [Submodule.mem_top, Submodule.mem_bot, true_iff] + have mem : x ∈ (⊤ : Submodule R _) := ⟨⟩ + rw [← TensorProduct.span_tmul_eq_top, mem_span_set] at mem + obtain ⟨c, hc, rfl⟩ := mem + choose b a hy using hc + let r : ⦃a : E ⊗[R] M⦄ → a ∈ ↑c.support → R := fun a ha => + Submodule.mem_span_singleton.1 (b ha).2 |>.choose + have hr : ∀ ⦃i : E ⊗[R] M⦄ (hi : i ∈ c.support), b hi = + r hi • ⟨l23 (l12 n1), Submodule.mem_span_singleton_self _⟩ := fun a ha => + Subtype.ext <| Submodule.mem_span_singleton.1 (b ha).2 |>.choose_spec.symm + -- Since `M` is flat and `E -> N1` is injective, we only need to check that x = 0 + -- in `N1 ⊗ M`. We write `x = ∑ μᵢ • (l23 (l12 n1)) ⊗ mᵢ = ∑ μᵢ • 0 = 0` + -- (remember `E = span {l23 (l12 n1)}` and `eq1`) + refine Finset.sum_eq_zero fun i hi => show c i • i = 0 from + (Module.Flat.rTensor_preserves_injective_linearMap (M := M) E.subtype <| + Submodule.injective_subtype E) ?_ + rw [← hy hi, hr hi, smul_tmul, map_smul, LinearMap.rTensor_tmul, Submodule.subtype_apply, eq1, + smul_zero, map_zero] + have : Subsingleton (E ⊗[R] M) := subsingleton_iff_forall_eq 0 |>.2 fun x => + show x ∈ (⊥ : Submodule R _) from eq0 ▸ ⟨⟩ + + -- but `E ⊗ M = 0` implies `E = 0` because `M` is faithfully flat and this is a contradiction. + exact not_subsingleton_iff_nontrivial.2 inferInstance <| fl.rTensor_reflects_triviality R M E + +lemma rTensor_reflects_exact [fl : FaithfullyFlat R M] + (ex : Function.Exact (l12.rTensor M) (l23.rTensor M)) : + Function.Exact l12 l23 := LinearMap.exact_iff.2 <| by + have complex : LinearMap.range l12 ≤ LinearMap.ker l23 := range_le_ker_of_exact_rTensor R M _ _ ex + -- By the previous lemma we have that range l12 ≤ ker l23 and hence the quotient + -- H := ker l23 ⧸ range l12 makes sense. + -- Hence our goal ker l23 = range l12 follows from the claim that H = 0. + let H := LinearMap.ker l23 ⧸ LinearMap.range (Submodule.inclusion complex) + suffices triv_coh : Subsingleton H by + rw [Submodule.subsingleton_quotient_iff_eq_top, Submodule.range_inclusion, + Submodule.comap_subtype_eq_top] at triv_coh + exact le_antisymm triv_coh complex + + -- Since `M` is faithfully flat, we need only to show that `H ⊗ M` is trivial. + suffices Subsingleton (H ⊗[R] M) from rTensor_reflects_triviality R M H + let e : H ⊗[R] M ≃ₗ[R] _ := TensorProduct.quotientTensorEquiv _ _ + -- Note that `H ⊗ M` is isomorphic to `ker l12 ⊗ M ⧸ range ((range l12 ⊗ M) -> (ker l23 ⊗ M))`. + -- So the problem is reduced to proving surjectivity of `range l12 ⊗ M → ker l23 ⊗ M`. + rw [e.toEquiv.subsingleton_congr, Submodule.subsingleton_quotient_iff_eq_top, + LinearMap.range_eq_top] + intro x + induction x using TensorProduct.induction_on with + | zero => exact ⟨0, by simp⟩ + -- let `x ⊗ m` be an element in `ker l23 ⊗ M`, then `x ⊗ m` is in the kernel of `l23 ⊗ 𝟙M`. + -- Since `N1 ⊗ M -l12 ⊗ M-> N2 ⊗ M -l23 ⊗ M-> N3 ⊗ M` is exact, we have that `x ⊗ m` is in + -- the range of `l12 ⊗ 𝟙M`, i.e. `x ⊗ m = (l12 ⊗ 𝟙M) y` for some `y ∈ N1 ⊗ M` as elements of + -- `N2 ⊗ M`. We need to prove that `x ⊗ m = (l12 ⊗ 𝟙M) y` still holds in `(ker l23) ⊗ M`. + -- This is okay because `M` is flat and `ker l23 -> N2` is injective. + | tmul x m => + rcases x with ⟨x, (hx : l23 x = 0)⟩ + have mem : x ⊗ₜ[R] m ∈ LinearMap.ker (l23.rTensor M) := by simp [hx] + rw [LinearMap.exact_iff.1 ex] at mem + obtain ⟨y, hy⟩ := mem + + refine ⟨LinearMap.rTensor M (LinearMap.rangeRestrict _ ∘ₗ LinearMap.rangeRestrict l12) y, + Module.Flat.rTensor_preserves_injective_linearMap (LinearMap.ker l23).subtype + Subtype.val_injective ?_⟩ + simp only [LinearMap.comp_codRestrict, LinearMap.rTensor_tmul, Submodule.coe_subtype, ← hy] + rw [← LinearMap.comp_apply] + erw [← LinearMap.rTensor_comp] + rw [← LinearMap.comp_apply, ← LinearMap.rTensor_comp, LinearMap.comp_assoc, + LinearMap.subtype_comp_codRestrict, ← LinearMap.comp_assoc, Submodule.subtype_comp_inclusion, + LinearMap.subtype_comp_codRestrict] + | add x y hx hy => + obtain ⟨x, rfl⟩ := hx; obtain ⟨y, rfl⟩ := hy + exact ⟨x + y, by simp⟩ + +lemma lTensor_reflects_exact [fl : FaithfullyFlat R M] + (ex : Function.Exact (l12.lTensor M) (l23.lTensor M)) : + Function.Exact l12 l23 := + rTensor_reflects_exact R M _ _ <| ex.of_ladder_linearEquiv_of_exact + (e₁ := TensorProduct.comm _ _ _) (e₂ := TensorProduct.comm _ _ _) + (e₃ := TensorProduct.comm _ _ _) (by ext; rfl) (by ext; rfl) + +end arbitrary_universe + +section fixed_universe + +lemma exact_iff_rTensor_exact [fl : FaithfullyFlat R M] + {N1 : Type max u v} [AddCommGroup N1] [Module R N1] + {N2 : Type max u v} [AddCommGroup N2] [Module R N2] + {N3 : Type max u v} [AddCommGroup N3] [Module R N3] + (l12 : N1 →ₗ[R] N2) (l23 : N2 →ₗ[R] N3) : + Function.Exact l12 l23 ↔ Function.Exact (l12.rTensor M) (l23.rTensor M) := + ⟨fun e => Module.Flat.iff_rTensor_exact.1 fl.toFlat e, + fun ex => rTensor_reflects_exact R M l12 l23 ex⟩ + +lemma iff_exact_iff_rTensor_exact : + FaithfullyFlat R M ↔ + (∀ {N1 : Type max u v} [AddCommGroup N1] [Module R N1] + {N2 : Type max u v} [AddCommGroup N2] [Module R N2] + {N3 : Type max u v} [AddCommGroup N3] [Module R N3] + (l12 : N1 →ₗ[R] N2) (l23 : N2 →ₗ[R] N3), + Function.Exact l12 l23 ↔ Function.Exact (l12.rTensor M) (l23.rTensor M)) := + ⟨fun fl => exact_iff_rTensor_exact R M, fun iff_exact => + iff_flat_and_rTensor_reflects_triviality _ _ |>.2 ⟨Flat.iff_rTensor_exact.2 <| by aesop, + fun N _ _ h => subsingleton_iff_forall_eq 0 |>.2 <| fun y => by + simpa [eq_comm] using (iff_exact (0 : PUnit →ₗ[R] N) (0 : N →ₗ[R] PUnit) |>.2 fun x => by + simpa using Subsingleton.elim _ _) y⟩⟩ + +lemma iff_exact_iff_lTensor_exact : + FaithfullyFlat R M ↔ + (∀ {N1 : Type max u v} [AddCommGroup N1] [Module R N1] + {N2 : Type max u v} [AddCommGroup N2] [Module R N2] + {N3 : Type max u v} [AddCommGroup N3] [Module R N3] + (l12 : N1 →ₗ[R] N2) (l23 : N2 →ₗ[R] N3), + Function.Exact l12 l23 ↔ Function.Exact (l12.lTensor M) (l23.lTensor M)) := by + simp only [iff_exact_iff_rTensor_exact, LinearMap.rTensor_exact_iff_lTensor_exact] + +end fixed_universe + +end exact + +section linearMap + +/-! +### Faithfully flat modules and linear maps + +In this section we prove that an `R`-module `M` is faithfully flat iff the following holds: + +- `M` is flat +- for any `R`-linear map `f : N → N'`, `f` = 0 iff `f ⊗ 𝟙M = 0` iff `𝟙M ⊗ f = 0` + +-/ + +section arbitrary_universe + +/-- +If `M` is a faithfully flat module, then for all linear maps `f`, the map `id ⊗ f = 0`, if and only +if `f = 0`. -/ +lemma zero_iff_lTensor_zero [h: FaithfullyFlat R M] + {N : Type*} [AddCommGroup N] [Module R N] + {N' : Type*} [AddCommGroup N'] [Module R N'] (f : N →ₗ[R] N') : + f = 0 ↔ LinearMap.lTensor M f = 0 := + ⟨fun hf => hf.symm ▸ LinearMap.lTensor_zero M, fun hf => by + have := lTensor_reflects_exact R M f LinearMap.id (by + rw [LinearMap.exact_iff, hf, LinearMap.range_zero, LinearMap.ker_eq_bot] + apply Module.Flat.lTensor_preserves_injective_linearMap + exact fun _ _ h => h) + ext x; simpa using this (f x)⟩ + + +/-- +If `M` is a faithfully flat module, then for all linear maps `f`, the map `f ⊗ id = 0`, if and only +if `f = 0`. -/ +lemma zero_iff_rTensor_zero [h: FaithfullyFlat R M] + {N : Type*} [AddCommGroup N] [Module R N] + {N' : Type*} [AddCommGroup N'] [Module R N'] + (f : N →ₗ[R] N') : + f = 0 ↔ LinearMap.rTensor M f = 0 := + zero_iff_lTensor_zero R M f |>.trans + ⟨fun h => by ext n m; exact (TensorProduct.comm R N' M).injective <| + (by simpa using congr($h (m ⊗ₜ n))), fun h => by + ext m n; exact (TensorProduct.comm R M N').injective <| (by simpa using congr($h (n ⊗ₜ m)))⟩ + +end arbitrary_universe + +section fixed_universe + +/-- +An `R`-module `M` is faithfully flat iff it is flat and for all linear maps `f`, the map +`id ⊗ f = 0`, if and only if `f = 0`. -/ +lemma iff_zero_iff_lTensor_zero : + FaithfullyFlat R M ↔ + (Module.Flat R M ∧ + (∀ {N : Type max u v} [AddCommGroup N] [Module R N] + {N' : Type max u v} [AddCommGroup N'] [Module R N'] + (f : N →ₗ[R] N'), f.lTensor M = 0 ↔ f = 0)) := + ⟨fun fl => ⟨inferInstance, fun f => zero_iff_lTensor_zero R M f |>.symm⟩, + fun ⟨flat, Z⟩ => iff_flat_and_lTensor_reflects_triviality R M |>.2 ⟨flat, fun N _ _ _ => by + have := Z (LinearMap.id : N →ₗ[R] N) |>.1 (by ext; exact Subsingleton.elim _ _) + rw [subsingleton_iff_forall_eq 0] + exact fun y => congr($this y)⟩⟩ + +/-- +An `R`-module `M` is faithfully flat iff it is flat and for all linear maps `f`, the map +`id ⊗ f = 0`, if and only if `f = 0`. -/ +lemma iff_zero_iff_rTensor_zero : + FaithfullyFlat R M ↔ + (Module.Flat R M ∧ + (∀ {N : Type max u v} [AddCommGroup N] [Module R N] + {N' : Type max u v} [AddCommGroup N'] [Module R N'] + (f : N →ₗ[R] N'), f.rTensor M = 0 ↔ (f = 0))) := + ⟨fun fl => ⟨inferInstance, fun f => zero_iff_rTensor_zero R M f |>.symm⟩, + fun ⟨flat, Z⟩ => iff_flat_and_rTensor_reflects_triviality R M |>.2 ⟨flat, fun N _ _ _ => by + have := Z (LinearMap.id : N →ₗ[R] N) |>.1 (by ext; exact Subsingleton.elim _ _) + rw [subsingleton_iff_forall_eq 0] + exact fun y => congr($this y)⟩⟩ + +end fixed_universe + +end linearMap + +/-- An `R`-module linearly equivalent to a faithfully flat `R`-module is faithfully flat. -/ +lemma of_linearEquiv [fl : FaithfullyFlat R M] + (M' : Type*) [AddCommGroup M'] [Module R M'] (e : M' ≃ₗ[R] M) : + FaithfullyFlat R M' := by + classical + haveI : Module.Flat R M' := Module.Flat.of_linearEquiv _ _ _ e + refine ⟨fun m hm rid => fl.2 hm ?_⟩ + rw [eq_top_iff] at rid ⊢ + rintro x - + specialize @rid (e.symm x) ⟨⟩ + rw [← Submodule.coe_set_smul, Submodule.mem_set_smul] at rid + obtain ⟨c, hc, eq⟩ := rid + apply_fun e at eq + simp only [LinearEquiv.apply_symm_apply, Finsupp.sum, AddSubmonoidClass.coe_finset_sum, + SetLike.val_smul, map_sum, map_smul] at eq + exact eq ▸ Submodule.sum_mem _ fun i hi => Submodule.apply_mem_map₂ (hm := hc hi) (hn := ⟨⟩) _ + +section comp + +open TensorProduct LinearMap + +variable (R : Type*) [CommRing R] +variable (S : Type*) [CommRing S] [Algebra R S] +variable (M : Type*) [AddCommGroup M] [Module R M] [Module S M] [IsScalarTower R S M] +variable [FaithfullyFlat R S] [FaithfullyFlat S M] + +include S in +/-- If `S` is a faithfully flat `R`-algebra, then any faithfully flat `S`-Module is faithfully flat +as an `R`-module. -/ +theorem comp : + FaithfullyFlat R M := by + rw [iff_zero_iff_lTensor_zero] + refine ⟨Module.Flat.comp R S M, @fun N _ _ N' _ _ f => ⟨fun aux => ?_, fun eq => eq ▸ by simp⟩⟩ + rw [zero_iff_lTensor_zero (R:= R) (M := S) f, + show f.lTensor S = (AlgebraTensorModule.map (A:= S) LinearMap.id f).restrictScalars R by aesop, + show (0 : S ⊗[R] N →ₗ[R] S ⊗[R] N') = (0 : S ⊗[R] N →ₗ[S] S ⊗[R] N').restrictScalars R by rfl, + restrictScalars_inj, zero_iff_lTensor_zero (R:= S) (M := M)] + ext m n + apply_fun AlgebraTensorModule.cancelBaseChange R S S M N' using LinearEquiv.injective _ + simpa using congr($aux (m ⊗ₜ[R] n)) + +end comp + +end FaithfullyFlat + +end Module diff --git a/Mathlib/RingTheory/Flat/Stability.lean b/Mathlib/RingTheory/Flat/Stability.lean index 57de113408f23..8b0e1c14b0fa9 100644 --- a/Mathlib/RingTheory/Flat/Stability.lean +++ b/Mathlib/RingTheory/Flat/Stability.lean @@ -153,7 +153,7 @@ section Localization variable {R : Type u} {M Mp : Type*} (Rp : Type v) [CommRing R] [AddCommGroup M] [Module R M] [CommRing Rp] [Algebra R Rp] - [AddCommGroup Mp] [Module R Mp] [Module Rp Mp] [IsScalarTower R Rp Mp] (f : M →ₗ[R] Mp) + [AddCommGroup Mp] [Module R Mp] [Module Rp Mp] [IsScalarTower R Rp Mp] instance localizedModule [Module.Flat R M] (S : Submonoid R) : Module.Flat (Localization S) (LocalizedModule S M) := by diff --git a/Mathlib/RingTheory/FractionalIdeal/Basic.lean b/Mathlib/RingTheory/FractionalIdeal/Basic.lean index 4ebe1fa201f1f..4056634b451c7 100644 --- a/Mathlib/RingTheory/FractionalIdeal/Basic.lean +++ b/Mathlib/RingTheory/FractionalIdeal/Basic.lean @@ -215,7 +215,7 @@ theorem isFractional_of_le_one (I : Submodule R P) (h : I ≤ 1) : IsFractional use 1, S.one_mem intro b hb rw [one_smul] - obtain ⟨b', b'_mem, rfl⟩ := h hb + obtain ⟨b', b'_mem, rfl⟩ := mem_one.mp (h hb) exact Set.mem_range_self b' theorem isFractional_of_le {I : Submodule R P} {J : FractionalIdeal S P} (hIJ : I ≤ J) : diff --git a/Mathlib/RingTheory/FractionalIdeal/Extended.lean b/Mathlib/RingTheory/FractionalIdeal/Extended.lean index c2dcadde7c9b5..f3b9bc6f62288 100644 --- a/Mathlib/RingTheory/FractionalIdeal/Extended.lean +++ b/Mathlib/RingTheory/FractionalIdeal/Extended.lean @@ -45,8 +45,8 @@ def extended (I : FractionalIdeal M K) : FractionalIdeal N L where property := by have ⟨a, ha, frac⟩ := I.isFractional refine ⟨f a, hf ha, fun b hb ↦ ?_⟩ - refine span_induction hb (fun x hx ↦ ?_) ⟨0, by simp⟩ - (fun x y hx hy ↦ smul_add (f a) x y ▸ isInteger_add hx hy) (fun b c hc ↦ ?_) + refine span_induction (fun x hx ↦ ?_) ⟨0, by simp⟩ + (fun x y _ _ hx hy ↦ smul_add (f a) x y ▸ isInteger_add hx hy) (fun b c _ hc ↦ ?_) hb · rcases hx with ⟨k, kI, rfl⟩ obtain ⟨c, hc⟩ := frac k kI exact ⟨f c, by simp [← IsLocalization.map_smul, ← hc]⟩ @@ -69,8 +69,8 @@ theorem extended_zero : extended L hf (0 : FractionalIdeal M K) = 0 := @[simp] theorem extended_one : extended L hf (1 : FractionalIdeal M K) = 1 := by - refine coeToSubmodule_injective <| Submodule.ext fun x ↦ ⟨fun hx ↦ span_induction hx - ?_ (zero_mem _) (fun y z hy hz ↦ add_mem hy hz) (fun b y hy ↦ smul_mem _ b hy), ?_⟩ + refine coeToSubmodule_injective <| Submodule.ext fun x ↦ ⟨fun hx ↦ span_induction + ?_ (zero_mem _) (fun y z _ _ hy hz ↦ add_mem hy hz) (fun b y _ hy ↦ smul_mem _ b hy) hx, ?_⟩ · rintro ⟨b, _, rfl⟩ rw [Algebra.linearMap_apply, Algebra.algebraMap_eq_smul_one] exact smul_mem _ _ <| subset_span ⟨1, by simp [one_mem_one]⟩ @@ -98,7 +98,8 @@ theorem extended_mul : (I * J).extended L hf = (I.extended L hf) * (J.extended L · rcases h with ⟨x, hx, rfl⟩ replace hx : x ∈ (I : Submodule A K) * (J : Submodule A K) := coe_mul I J ▸ hx rw [Submodule.mul_eq_span_mul_set] at hx - refine span_induction hx (fun y hy ↦ ?_) (by simp) (fun y z hy hz ↦ ?_) (fun a y hy ↦ ?_) + refine span_induction (fun y hy ↦ ?_) (by simp) (fun y z _ _ hy hz ↦ ?_) + (fun a y _ hy ↦ ?_) hx · rcases Set.mem_mul.mp hy with ⟨i, hi, j, hj, rfl⟩ exact subset_span <| Set.mem_mul.mpr ⟨map_f i, ⟨i, hi, by simp [hi]⟩, map_f j, ⟨j, hj, by simp [hj]⟩, by simp⟩ diff --git a/Mathlib/RingTheory/FractionalIdeal/Operations.lean b/Mathlib/RingTheory/FractionalIdeal/Operations.lean index 50c15f91c6b62..75d74307abf32 100644 --- a/Mathlib/RingTheory/FractionalIdeal/Operations.lean +++ b/Mathlib/RingTheory/FractionalIdeal/Operations.lean @@ -5,6 +5,7 @@ Authors: Anne Baanen, Filippo A. E. Nuccio -/ import Mathlib.RingTheory.FractionalIdeal.Basic import Mathlib.RingTheory.IntegralClosure.IsIntegral.Basic +import Mathlib.RingTheory.LocalRing.Basic /-! # More operations on fractional ideals @@ -153,15 +154,15 @@ theorem mapEquiv_refl : mapEquiv AlgEquiv.refl = RingEquiv.refl (FractionalIdeal theorem isFractional_span_iff {s : Set P} : IsFractional S (span R s) ↔ ∃ a ∈ S, ∀ b : P, b ∈ s → IsInteger R (a • b) := ⟨fun ⟨a, a_mem, h⟩ => ⟨a, a_mem, fun b hb => h b (subset_span hb)⟩, fun ⟨a, a_mem, h⟩ => - ⟨a, a_mem, fun b hb => - span_induction hb h + ⟨a, a_mem, fun _ hb => + span_induction (hx := hb) h (by rw [smul_zero] exact isInteger_zero) - (fun x y hx hy => by + (fun x y _ _ hx hy => by rw [smul_add] exact isInteger_add hx hy) - fun s x hx => by + fun s x _ hx => by rw [smul_comm] exact isInteger_smul hx⟩⟩ @@ -205,7 +206,7 @@ noncomputable irreducible_def canonicalEquiv : FractionalIdeal S P ≃+* Fractio mapEquiv { ringEquivOfRingEquiv P P' (RingEquiv.refl R) (show S.map _ = S by rw [RingEquiv.toMonoidHom_refl, Submonoid.map_id]) with - commutes' := fun r => ringEquivOfRingEquiv_eq _ _ } + commutes' := fun _ => ringEquivOfRingEquiv_eq _ _ } @[simp] theorem mem_canonicalEquiv_apply {I : FractionalIdeal S P} {x : P'} : @@ -515,15 +516,15 @@ variable (R₁) def spanFinset {ι : Type*} (s : Finset ι) (f : ι → K) : FractionalIdeal R₁⁰ K := ⟨Submodule.span R₁ (f '' s), by obtain ⟨a', ha'⟩ := IsLocalization.exist_integer_multiples R₁⁰ s f - refine ⟨a', a'.2, fun x hx => Submodule.span_induction hx ?_ ?_ ?_ ?_⟩ + refine ⟨a', a'.2, fun x hx => Submodule.span_induction ?_ ?_ ?_ ?_ hx⟩ · rintro _ ⟨i, hi, rfl⟩ exact ha' i hi · rw [smul_zero] exact IsLocalization.isInteger_zero - · intro x y hx hy + · intro x y _ _ hx hy rw [smul_add] exact IsLocalization.isInteger_add hx hy - · intro c x hx + · intro c x _ hx rw [smul_comm] exact IsLocalization.isInteger_smul hx⟩ @@ -792,7 +793,7 @@ instance isPrincipal {R} [CommRing R] [IsDomain R] [IsPrincipalIdealRing R] [Alg theorem le_spanSingleton_mul_iff {x : P} {I J : FractionalIdeal S P} : I ≤ spanSingleton S x * J ↔ ∀ zI ∈ I, ∃ zJ ∈ J, x * zJ = zI := - show (∀ {zI} (hzI : zI ∈ I), zI ∈ spanSingleton _ x * J) ↔ ∀ zI ∈ I, ∃ zJ ∈ J, x * zJ = zI by + show (∀ {zI} (_ : zI ∈ I), zI ∈ spanSingleton _ x * J) ↔ ∀ zI ∈ I, ∃ zJ ∈ J, x * zJ = zI by simp only [mem_singleton_mul, eq_comm] theorem spanSingleton_mul_le_iff {x : P} {I J : FractionalIdeal S P} : diff --git a/Mathlib/RingTheory/FreeCommRing.lean b/Mathlib/RingTheory/FreeCommRing.lean index eeaec370fa743..6efc6c11c1cd6 100644 --- a/Mathlib/RingTheory/FreeCommRing.lean +++ b/Mathlib/RingTheory/FreeCommRing.lean @@ -80,6 +80,20 @@ theorem of_injective : Function.Injective (of : α → FreeCommRing α) := FreeAbelianGroup.of_injective.comp fun _ _ => (Multiset.coe_eq_coe.trans List.singleton_perm_singleton).mp +@[simp] +theorem of_ne_zero (x : α) : of x ≠ 0 := FreeAbelianGroup.of_ne_zero _ + +@[simp] +theorem zero_ne_of (x : α) : 0 ≠ of x := FreeAbelianGroup.zero_ne_of _ + +@[simp] +theorem of_ne_one (x : α) : of x ≠ 1 := + FreeAbelianGroup.of_injective.ne <| Multiset.singleton_ne_zero _ + +@[simp] +theorem one_ne_of (x : α) : 1 ≠ of x := + FreeAbelianGroup.of_injective.ne <| Multiset.zero_ne_singleton _ + -- Porting note: added to ease a proof in `Algebra.DirectLimit` lemma of_cons (a : α) (m : Multiset α) : (FreeAbelianGroup.of (Multiplicative.ofAdd (a ::ₘ m))) = @HMul.hMul _ (FreeCommRing α) (FreeCommRing α) _ (of a) @@ -98,7 +112,7 @@ protected theorem induction_on {C : FreeCommRing α → Prop} (z : FreeCommRing (fun m => Multiset.induction_on m h1 fun a m ih => by convert hm (of a) _ (hb a) ih apply of_cons) - (fun m ih => hn _ ih) ha + (fun _ ih => hn _ ih) ha section lift diff --git a/Mathlib/RingTheory/FreeRing.lean b/Mathlib/RingTheory/FreeRing.lean index 1ec0166f4f531..757be62b9b327 100644 --- a/Mathlib/RingTheory/FreeRing.lean +++ b/Mathlib/RingTheory/FreeRing.lean @@ -40,6 +40,9 @@ instance (α : Type u) : Inhabited (FreeRing α) := by dsimp only [FreeRing] infer_instance +instance (α : Type u) : Nontrivial (FreeRing α) := + inferInstanceAs <| Nontrivial (FreeAbelianGroup _) + namespace FreeRing variable {α : Type u} @@ -51,6 +54,18 @@ def of (x : α) : FreeRing α := theorem of_injective : Function.Injective (of : α → FreeRing α) := FreeAbelianGroup.of_injective.comp FreeMonoid.of_injective +@[simp] +theorem of_ne_zero (x : α) : of x ≠ 0 := FreeAbelianGroup.of_ne_zero _ + +@[simp] +theorem zero_ne_of (x : α) : 0 ≠ of x := FreeAbelianGroup.zero_ne_of _ + +@[simp] +theorem of_ne_one (x : α) : of x ≠ 1 := FreeAbelianGroup.of_injective.ne <| FreeMonoid.of_ne_one _ + +@[simp] +theorem one_ne_of (x : α) : 1 ≠ of x := FreeAbelianGroup.of_injective.ne <| FreeMonoid.one_ne_of _ + @[elab_as_elim, induction_eliminator] protected theorem induction_on {C : FreeRing α → Prop} (z : FreeRing α) (hn1 : C (-1)) (hb : ∀ b, C (of b)) (ha : ∀ x y, C x → C y → C (x + y)) (hm : ∀ x y, C x → C y → C (x * y)) : @@ -63,7 +78,7 @@ protected theorem induction_on {C : FreeRing α → Prop} (z : FreeRing α) (hn1 convert hm _ _ (hb a) ih rw [of, ← FreeAbelianGroup.of_mul] rfl) - (fun m ih => hn _ ih) ha + (fun _ ih => hn _ ih) ha section lift diff --git a/Mathlib/RingTheory/GradedAlgebra/Basic.lean b/Mathlib/RingTheory/GradedAlgebra/Basic.lean index 0d6693692b34f..0121091f00ac2 100644 --- a/Mathlib/RingTheory/GradedAlgebra/Basic.lean +++ b/Mathlib/RingTheory/GradedAlgebra/Basic.lean @@ -310,7 +310,7 @@ theorem coe_decompose_mul_of_right_mem_of_not_le (b_mem : b ∈ 𝒜 i) (h : ¬i lift b to 𝒜 i using b_mem rwa [decompose_mul, decompose_coe, coe_mul_of_apply_of_not_le] -variable [Sub ι] [OrderedSub ι] [ContravariantClass ι ι (· + ·) (· ≤ ·)] +variable [Sub ι] [OrderedSub ι] [AddLeftReflectLE ι] theorem coe_decompose_mul_of_left_mem_of_le (a_mem : a ∈ 𝒜 i) (h : i ≤ n) : (decompose 𝒜 (a * b) n : A) = a * decompose 𝒜 b (n - i) := by diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean index dc2ec96afc47a..a87561a7ee276 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean @@ -44,7 +44,7 @@ open SetLike DirectSum Set open Pointwise DirectSum -variable {ι σ R A : Type*} +variable {ι σ A : Type*} section HomogeneousDef @@ -146,7 +146,7 @@ theorem Ideal.mul_homogeneous_element_mem_of_mem {I : Ideal A} (r x : A) (hx₁ obtain ⟨i, hi⟩ := hx₁ have mem₁ : (DirectSum.decompose 𝒜 r k : A) * x ∈ 𝒜 (k + i) := GradedMul.mul_mem (SetLike.coe_mem _) hi - erw [GradedRing.proj_apply, DirectSum.decompose_of_mem 𝒜 mem₁, coe_of_apply] + rw [GradedRing.proj_apply, DirectSum.decompose_of_mem 𝒜 mem₁, coe_of_apply] split_ifs · exact I.mul_mem_left _ hx₂ · exact I.zero_mem @@ -359,12 +359,10 @@ theorem toIdeal_iInf {κ : Sort*} (s : κ → HomogeneousIdeal 𝒜) : (⨅ i, s i).toIdeal = ⨅ i, (s i).toIdeal := by rw [iInf, toIdeal_sInf, iInf_range] --- @[simp] -- Porting note (#10618): simp can prove this theorem toIdeal_iSup₂ {κ : Sort*} {κ' : κ → Sort*} (s : ∀ i, κ' i → HomogeneousIdeal 𝒜) : (⨆ (i) (j), s i j).toIdeal = ⨆ (i) (j), (s i j).toIdeal := by simp_rw [toIdeal_iSup] --- @[simp] -- Porting note (#10618): simp can prove this theorem toIdeal_iInf₂ {κ : Sort*} {κ' : κ → Sort*} (s : ∀ i, κ' i → HomogeneousIdeal 𝒜) : (⨅ (i) (j), s i j).toIdeal = ⨅ (i) (j), (s i j).toIdeal := by simp_rw [toIdeal_iInf] diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean index c3721f85c4ec5..f7b816f728486 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean @@ -228,10 +228,10 @@ theorem den_add (c1 c2 : NumDenSameDeg 𝒜 x) : ((c1 + c2).den : A) = c1.den * instance : CommMonoid (NumDenSameDeg 𝒜 x) where one := 1 mul := (· * ·) - mul_assoc c1 c2 c3 := ext _ (add_assoc _ _ _) (mul_assoc _ _ _) (mul_assoc _ _ _) - one_mul c := ext _ (zero_add _) (one_mul _) (one_mul _) - mul_one c := ext _ (add_zero _) (mul_one _) (mul_one _) - mul_comm c1 c2 := ext _ (add_comm _ _) (mul_comm _ _) (mul_comm _ _) + mul_assoc _ _ _ := ext _ (add_assoc _ _ _) (mul_assoc _ _ _) (mul_assoc _ _ _) + one_mul _ := ext _ (zero_add _) (one_mul _) (one_mul _) + mul_one _ := ext _ (add_zero _) (mul_one _) (mul_one _) + mul_comm _ _ := ext _ (add_comm _ _) (mul_comm _ _) (mul_comm _ _) instance : Pow (NumDenSameDeg 𝒜 x) ℕ where pow c n := @@ -353,7 +353,7 @@ instance hasPow : Pow (HomogeneousLocalization 𝒜 x) ℕ where (Quotient.map' (· ^ n) fun c1 c2 (h : Localization.mk _ _ = Localization.mk _ _) => by change Localization.mk _ _ = Localization.mk _ _ simp only [num_pow, den_pow] - convert congr_arg (fun z : at x => z ^ n) h <;> erw [Localization.mk_pow] <;> rfl : + convert congr_arg (fun z : at x => z ^ n) h <;> rw [Localization.mk_pow] <;> rfl : HomogeneousLocalization 𝒜 x → HomogeneousLocalization 𝒜 x) z @@ -366,7 +366,7 @@ instance : Add (HomogeneousLocalization 𝒜 x) where (h' : Localization.mk _ _ = Localization.mk _ _) => by change Localization.mk _ _ = Localization.mk _ _ simp only [num_add, den_add, ← Localization.add_mk] - convert congr_arg₂ (· + ·) h h' <;> erw [Localization.add_mk] <;> rfl + convert congr_arg₂ (· + ·) h h' <;> rw [Localization.add_mk] <;> rfl @[simp] lemma mk_add (i j : NumDenSameDeg 𝒜 x) : mk (i + j) = mk i + mk j := rfl @@ -379,7 +379,7 @@ instance : Mul (HomogeneousLocalization 𝒜 x) where (h' : Localization.mk _ _ = Localization.mk _ _) => by change Localization.mk _ _ = Localization.mk _ _ simp only [num_mul, den_mul] - convert congr_arg₂ (· * ·) h h' <;> erw [Localization.mk_mul] <;> rfl + convert congr_arg₂ (· * ·) h h' <;> rw [Localization.mk_mul] <;> rfl @[simp] lemma mk_mul (i j : NumDenSameDeg 𝒜 x) : mk (i * j) = mk i * mk j := rfl @@ -528,7 +528,7 @@ theorem isUnit_iff_isUnit_val (f : HomogeneousLocalization.AtPrime 𝒜 𝔭) : (hc ▸ Ideal.mul_mem_left _ c.1 (Ideal.mul_mem_right b _ h)) refine isUnit_of_mul_eq_one _ (Quotient.mk'' ⟨f.1, f.3, f.2, this⟩) ?_ rw [← mk_mul, ext_iff_val, val_mk] - simp [mul_comm f.den.1] + simp [mul_comm f.den.1, Localization.mk_eq_monoidOf_mk'] instance : Nontrivial (HomogeneousLocalization.AtPrime 𝒜 𝔭) := ⟨⟨0, 1, fun r => by simp [ext_iff_val, val_zero, val_one, zero_ne_one] at r⟩⟩ diff --git a/Mathlib/RingTheory/GradedAlgebra/Radical.lean b/Mathlib/RingTheory/GradedAlgebra/Radical.lean index 976b7748f818d..72e6ad6f51e2b 100644 --- a/Mathlib/RingTheory/GradedAlgebra/Radical.lean +++ b/Mathlib/RingTheory/GradedAlgebra/Radical.lean @@ -66,10 +66,10 @@ theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI This is a contradiction, because both `proj (max₁ + max₂) (x * y) ∈ I` and the sum on the right hand side is in `I` however `proj max₁ x * proj max₂ y` is not in `I`. -/ - set set₁ := (decompose 𝒜 x).support.filter (fun i => proj 𝒜 i x ∉ I) with set₁_eq - set set₂ := (decompose 𝒜 y).support.filter (fun i => proj 𝒜 i y ∉ I) with set₂_eq + set set₁ := {i ∈ (decompose 𝒜 x).support | proj 𝒜 i x ∉ I} with set₁_eq + set set₂ := {i ∈ (decompose 𝒜 y).support | proj 𝒜 i y ∉ I} with set₂_eq have nonempty : - ∀ x : A, x ∉ I → ((decompose 𝒜 x).support.filter (fun i => proj 𝒜 i x ∉ I)).Nonempty := by + ∀ x : A, x ∉ I → {i ∈ (decompose 𝒜 x).support | proj 𝒜 i x ∉ I}.Nonempty := by intro x hx rw [filter_nonempty_iff] contrapose! hx @@ -83,8 +83,8 @@ theorem Ideal.IsHomogeneous.isPrime_of_homogeneous_mem_or_mem {I : Ideal A} (hI replace hxy : proj 𝒜 (max₁ + max₂) (x * y) ∈ I := hI _ hxy have mem_I : proj 𝒜 max₁ x * proj 𝒜 max₂ y ∈ I := by set antidiag := - ((decompose 𝒜 x).support ×ˢ (decompose 𝒜 y).support).filter (fun z : ι × ι => - z.1 + z.2 = max₁ + max₂) with ha + {z ∈ (decompose 𝒜 x).support ×ˢ (decompose 𝒜 y).support | z.1 + z.2 = max₁ + max₂} + with ha have mem_antidiag : (max₁, max₂) ∈ antidiag := by simp only [antidiag, add_sum_erase, mem_filter, mem_product] exact ⟨⟨mem_of_mem_filter _ mem_max₁, mem_of_mem_filter _ mem_max₂⟩, trivial⟩ diff --git a/Mathlib/RingTheory/HahnSeries/Addition.lean b/Mathlib/RingTheory/HahnSeries/Addition.lean index 61a63a5fceb4a..a7e06d6663a72 100644 --- a/Mathlib/RingTheory/HahnSeries/Addition.lean +++ b/Mathlib/RingTheory/HahnSeries/Addition.lean @@ -28,7 +28,7 @@ open scoped Classical noncomputable section -variable {Γ R : Type*} +variable {Γ Γ' R S U V : Type*} namespace HahnSeries @@ -66,6 +66,16 @@ theorem add_coeff' {x y : HahnSeries Γ R} : (x + y).coeff = x.coeff + y.coeff : theorem add_coeff {x y : HahnSeries Γ R} {a : Γ} : (x + y).coeff a = x.coeff a + y.coeff a := rfl +@[simp] +theorem nsmul_coeff {x : HahnSeries Γ R} {n : ℕ} : (n • x).coeff = n • x.coeff := by + induction n with + | zero => simp + | succ n ih => simp [add_nsmul, ih] + +@[simp] +protected lemma map_add [AddMonoid S] (f : R →+ S) {x y : HahnSeries Γ R} : + ((x + y).map f : HahnSeries Γ S) = x.map f + y.map f := by + ext; simp /-- `addOppositeEquiv` is an additive monoid isomorphism between Hahn series over `Γ` with coefficients in the opposite additive monoid `Rᵃᵒᵖ` @@ -102,7 +112,7 @@ lemma addOppositeEquiv_orderTop (x : HahnSeries Γ (Rᵃᵒᵖ)) : simp only [orderTop, AddOpposite.unop_op, mk_eq_zero, AddEquivClass.map_eq_zero_iff, addOppositeEquiv_support, ne_eq] simp only [addOppositeEquiv_apply, AddOpposite.unop_op, mk_eq_zero, zero_coeff] - simp_rw [HahnSeries.ext_iff, Function.funext_iff] + simp_rw [HahnSeries.ext_iff, funext_iff] simp only [Pi.zero_apply, AddOpposite.unop_eq_zero_iff, zero_coeff] @[simp] @@ -116,7 +126,7 @@ lemma addOppositeEquiv_leadingCoeff (x : HahnSeries Γ (Rᵃᵒᵖ)) : simp only [leadingCoeff, AddOpposite.unop_op, mk_eq_zero, AddEquivClass.map_eq_zero_iff, addOppositeEquiv_support, ne_eq] simp only [addOppositeEquiv_apply, AddOpposite.unop_op, mk_eq_zero, zero_coeff] - simp_rw [HahnSeries.ext_iff, Function.funext_iff] + simp_rw [HahnSeries.ext_iff, funext_iff] simp only [Pi.zero_apply, AddOpposite.unop_eq_zero_iff, zero_coeff] split <;> rfl @@ -210,7 +220,7 @@ def coeff.addMonoidHom (g : Γ) : HahnSeries Γ R →+ R where section Domain -variable {Γ' : Type*} [PartialOrder Γ'] +variable [PartialOrder Γ'] theorem embDomain_add (f : Γ ↪o Γ') (x y : HahnSeries Γ R) : embDomain f (x + y) = embDomain f x + embDomain f y := by @@ -261,12 +271,9 @@ theorem support_neg {x : HahnSeries Γ R} : (-x).support = x.support := by simp @[simp] -theorem sub_coeff' {x y : HahnSeries Γ R} : (x - y).coeff = x.coeff - y.coeff := by - ext - simp [sub_eq_add_neg] - -theorem sub_coeff {x y : HahnSeries Γ R} {a : Γ} : (x - y).coeff a = x.coeff a - y.coeff a := by - simp +protected lemma map_neg [AddGroup S] (f : R →+ S) {x : HahnSeries Γ R} : + ((-x).map f : HahnSeries Γ S) = -(x.map f) := by + ext; simp theorem orderTop_neg {x : HahnSeries Γ R} : (-x).orderTop = x.orderTop := by simp only [orderTop, support_neg, neg_eq_zero] @@ -277,6 +284,19 @@ theorem order_neg [Zero Γ] {f : HahnSeries Γ R} : (-f).order = f.order := by · simp only [hf, neg_zero] simp only [order, support_neg, neg_eq_zero] +@[simp] +theorem sub_coeff' {x y : HahnSeries Γ R} : (x - y).coeff = x.coeff - y.coeff := by + ext + simp [sub_eq_add_neg] + +theorem sub_coeff {x y : HahnSeries Γ R} {a : Γ} : (x - y).coeff a = x.coeff a - y.coeff a := by + simp + +@[simp] +protected lemma map_sub [AddGroup S] (f : R →+ S) {x y : HahnSeries Γ R} : + ((x - y).map f : HahnSeries Γ S) = x.map f - y.map f := by + ext; simp + theorem min_orderTop_le_orderTop_sub {Γ} [LinearOrder Γ] {x y : HahnSeries Γ R} : min x.orderTop y.orderTop ≤ (x - y).orderTop := by rw [sub_eq_add_neg, ← orderTop_neg (x := y)] @@ -377,7 +397,7 @@ end DistribMulAction section Module -variable [PartialOrder Γ] [Semiring R] {V : Type*} [AddCommMonoid V] [Module R V] +variable [PartialOrder Γ] [Semiring R] [AddCommMonoid V] [Module R V] instance : Module R (HahnSeries Γ V) := { inferInstanceAs (DistribMulAction R (HahnSeries Γ V)) with @@ -401,9 +421,14 @@ def single.linearMap (a : Γ) : V →ₗ[R] HahnSeries Γ V := def coeff.linearMap (g : Γ) : HahnSeries Γ V →ₗ[R] V := { coeff.addMonoidHom g with map_smul' := fun _ _ => rfl } +@[simp] +protected lemma map_smul [AddCommMonoid U] [Module R U] (f : U →ₗ[R] V) {r : R} + {x : HahnSeries Γ U} : (r • x).map f = r • ((x.map f) : HahnSeries Γ V) := by + ext; simp + section Domain -variable {Γ' : Type*} [PartialOrder Γ'] +variable [PartialOrder Γ'] theorem embDomain_smul (f : Γ ↪o Γ') (r : R) (x : HahnSeries Γ R) : embDomain f (r • x) = r • embDomain f x := by diff --git a/Mathlib/RingTheory/HahnSeries/Basic.lean b/Mathlib/RingTheory/HahnSeries/Basic.lean index b063204680d7f..74452d2da238a 100644 --- a/Mathlib/RingTheory/HahnSeries/Basic.lean +++ b/Mathlib/RingTheory/HahnSeries/Basic.lean @@ -25,6 +25,8 @@ in the file `RingTheory/LaurentSeries`. coefficient if `x ≠ 0`, and is `⊤` when `x = 0`. * `order x` is a minimal element of `Γ` where `x` has a nonzero coefficient if `x ≠ 0`, and is zero when `x = 0`. +* `map` takes each coefficient of a Hahn series to its target under a zero-preserving map. +* `embDomain` preserves coefficients, but embeds the index set `Γ` in a larger poset. ## References - [J. van der Hoeven, *Operators on Generalized Power Series*][van_der_hoeven] @@ -43,7 +45,7 @@ structure HahnSeries (Γ : Type*) (R : Type*) [PartialOrder Γ] [Zero R] where coeff : Γ → R isPWO_support' : (Function.support coeff).IsPWO -variable {Γ : Type*} {R : Type*} +variable {Γ Γ' R S : Type*} namespace HahnSeries @@ -108,8 +110,20 @@ nonrec theorem support_nonempty_iff {x : HahnSeries Γ R} : x.support.Nonempty theorem support_eq_empty_iff {x : HahnSeries Γ R} : x.support = ∅ ↔ x = 0 := Function.support_eq_empty_iff.trans coeff_fun_eq_zero_iff +/-- The map of Hahn series induced by applying a zero-preserving map to each coefficient. -/ +@[simps] +def map [Zero S] (x : HahnSeries Γ R) {F : Type*} [FunLike F R S] [ZeroHomClass F R S] (f : F) : + HahnSeries Γ S where + coeff g := f (x.coeff g) + isPWO_support' := x.isPWO_support.mono <| Function.support_comp_subset (ZeroHomClass.map_zero f) _ + +@[simp] +protected lemma map_zero [Zero S] (f : ZeroHom R S) : + (0 : HahnSeries Γ R).map f = 0 := by + ext; simp + /-- Change a HahnSeries with coefficients in HahnSeries to a HahnSeries on the Lex product. -/ -def ofIterate {Γ' : Type*} [PartialOrder Γ'] (x : HahnSeries Γ (HahnSeries Γ' R)) : +def ofIterate [PartialOrder Γ'] (x : HahnSeries Γ (HahnSeries Γ' R)) : HahnSeries (Γ ×ₗ Γ') R where coeff := fun g => coeff (coeff x g.1) g.2 isPWO_support' := by @@ -125,7 +139,7 @@ lemma mk_eq_zero (f : Γ → R) (h) : HahnSeries.mk f h = 0 ↔ f = 0 := by rfl /-- Change a Hahn series on a lex product to a Hahn series with coefficients in a Hahn series. -/ -def toIterate {Γ' : Type*} [PartialOrder Γ'] (x : HahnSeries (Γ ×ₗ Γ') R) : +def toIterate [PartialOrder Γ'] (x : HahnSeries (Γ ×ₗ Γ') R) : HahnSeries Γ (HahnSeries Γ' R) where coeff := fun g => { coeff := fun g' => coeff x (g, g') @@ -141,7 +155,7 @@ def toIterate {Γ' : Type*} [PartialOrder Γ'] (x : HahnSeries (Γ ×ₗ Γ') R) /-- The equivalence between iterated Hahn series and Hahn series on the lex product. -/ @[simps] -def iterateEquiv {Γ' : Type*} [PartialOrder Γ'] : +def iterateEquiv [PartialOrder Γ'] : HahnSeries Γ (HahnSeries Γ' R) ≃ HahnSeries (Γ ×ₗ Γ') R where toFun := ofIterate invFun := toIterate @@ -180,7 +194,6 @@ theorem support_single_subset : support (single a r) ⊆ {a} := by theorem eq_of_mem_support_single {b : Γ} (h : b ∈ support (single a r)) : b = a := support_single_subset h ---@[simp] Porting note (#10618): simp can prove it theorem single_eq_zero : single a (0 : R) = 0 := (single a).map_zero @@ -194,6 +207,11 @@ theorem single_ne_zero (h : r ≠ 0) : single a r ≠ 0 := fun con => theorem single_eq_zero_iff {a : Γ} {r : R} : single a r = 0 ↔ r = 0 := map_eq_zero_iff _ <| single_injective a +@[simp] +protected lemma map_single [Zero S] (f : ZeroHom R S) : (single a r).map f = single a (f r) := by + ext g + by_cases h : g = a <;> simp [h] + instance [Nonempty Γ] [Nontrivial R] : Nontrivial (HahnSeries Γ R) := ⟨by obtain ⟨r, s, rs⟩ := exists_pair_ne R @@ -364,7 +382,7 @@ end Order section Domain -variable {Γ' : Type*} [PartialOrder Γ'] +variable [PartialOrder Γ'] open Classical in /-- Extends the domain of a `HahnSeries` by an `OrderEmbedding`. -/ @@ -427,7 +445,7 @@ theorem embDomain_single {f : Γ ↪o Γ'} {g : Γ} {r : R} : theorem embDomain_injective {f : Γ ↪o Γ'} : Function.Injective (embDomain f : HahnSeries Γ R → HahnSeries Γ' R) := fun x y xy => by ext g - rw [HahnSeries.ext_iff, Function.funext_iff] at xy + rw [HahnSeries.ext_iff, funext_iff] at xy have xyg := xy (f g) rwa [embDomain_coeff, embDomain_coeff] at xyg diff --git a/Mathlib/RingTheory/HahnSeries/Multiplication.lean b/Mathlib/RingTheory/HahnSeries/Multiplication.lean index 153ac24993c5d..7719c9ebf8a30 100644 --- a/Mathlib/RingTheory/HahnSeries/Multiplication.lean +++ b/Mathlib/RingTheory/HahnSeries/Multiplication.lean @@ -37,7 +37,7 @@ open Finset Function Pointwise noncomputable section -variable {Γ Γ' R V : Type*} +variable {Γ Γ' R S V : Type*} namespace HahnSeries @@ -74,6 +74,12 @@ theorem order_one [MulZeroOneClass R] : order (1 : HahnSeries Γ R) = 0 := by theorem leadingCoeff_one [MulZeroOneClass R] : (1 : HahnSeries Γ R).leadingCoeff = 1 := by simp [leadingCoeff_eq] +@[simp] +protected lemma map_one [MonoidWithZero R] [MonoidWithZero S] (f : R →*₀ S) : + (1 : HahnSeries Γ R).map f = (1 : HahnSeries Γ S) := by + ext g + by_cases h : g = 0 <;> simp [h] + end HahnSeries /-- We introduce a type alias for `HahnSeries` in order to work with scalar multiplication by @@ -348,6 +354,19 @@ theorem mul_coeff [NonUnitalNonAssocSemiring R] {x y : HahnSeries Γ R} {a : Γ} ∑ ij ∈ addAntidiagonal x.isPWO_support y.isPWO_support a, x.coeff ij.fst * y.coeff ij.snd := rfl +protected lemma map_mul [NonUnitalNonAssocSemiring R] [NonUnitalNonAssocSemiring S] (f : R →ₙ+* S) + {x y : HahnSeries Γ R} : (x * y).map f = (x.map f : HahnSeries Γ S) * (y.map f) := by + ext + simp only [map_coeff, mul_coeff, ZeroHom.coe_coe, map_sum, map_mul] + refine Eq.symm (sum_subset (fun gh hgh => ?_) (fun gh hgh hz => ?_)) + · simp_all only [mem_addAntidiagonal, mem_support, map_coeff, ZeroHom.coe_coe, ne_eq, and_true] + exact ⟨fun h => hgh.1 (map_zero f ▸ congrArg f h), fun h => hgh.2.1 (map_zero f ▸ congrArg f h)⟩ + · simp_all only [mem_addAntidiagonal, mem_support, ne_eq, map_coeff, ZeroHom.coe_coe, and_true, + not_and, not_not] + by_cases h : f (x.coeff gh.1) = 0 + · exact mul_eq_zero_of_left h (f (y.coeff gh.2)) + · exact mul_eq_zero_of_right (f (x.coeff gh.1)) (hz h) + theorem mul_coeff_left' [NonUnitalNonAssocSemiring R] {x y : HahnSeries Γ R} {a : Γ} {s : Set Γ} (hs : s.IsPWO) (hxs : x.support ⊆ s) : (x * y).coeff a = @@ -535,7 +554,7 @@ instance instNoZeroSMulDivisors {Γ} [LinearOrderedCancelAddCommMonoid Γ] [Zero eq_zero_or_eq_zero_of_smul_eq_zero {x y} hxy := by contrapose! hxy simp only [ne_eq] - rw [HahnModule.ext_iff, Function.funext_iff, not_forall] + rw [HahnModule.ext_iff, funext_iff, not_forall] refine ⟨x.order + ((of R).symm y).order, ?_⟩ rw [smul_coeff_order_add_order x y, of_symm_zero, HahnSeries.zero_coeff, smul_eq_zero, not_or] constructor @@ -634,17 +653,20 @@ def C : R →+* HahnSeries Γ R where by_cases h : a = 0 <;> simp [h] map_mul' x y := by rw [single_mul_single, zero_add] ---@[simp] Porting note (#10618): simp can prove it theorem C_zero : C (0 : R) = (0 : HahnSeries Γ R) := C.map_zero ---@[simp] Porting note (#10618): simp can prove it theorem C_one : C (1 : R) = (1 : HahnSeries Γ R) := C.map_one +theorem map_C [NonAssocSemiring S] (a : R) (f : R →+* S) : + ((C a).map f : HahnSeries Γ S) = C (f a) := by + ext g + by_cases h : g = 0 <;> simp [h] + theorem C_injective : Function.Injective (C : R → HahnSeries Γ R) := by intro r s rs - rw [HahnSeries.ext_iff, Function.funext_iff] at rs + rw [HahnSeries.ext_iff, funext_iff] at rs have h := rs 0 rwa [C_apply, single_coeff_same, C_apply, single_coeff_same] at h @@ -756,7 +778,7 @@ instance [Nontrivial Γ] [Nontrivial R] : Nontrivial (Subalgebra R (HahnSeries refine ⟨single a 1, ?_⟩ simp only [Algebra.mem_bot, not_exists, Set.mem_range, iff_true, Algebra.mem_top] intro x - rw [HahnSeries.ext_iff, Function.funext_iff, not_forall] + rw [HahnSeries.ext_iff, funext_iff, not_forall] refine ⟨a, ?_⟩ rw [single_coeff_same, algebraMap_apply, C_apply, single_coeff_of_ne ha] exact zero_ne_one⟩⟩ diff --git a/Mathlib/RingTheory/HahnSeries/PowerSeries.lean b/Mathlib/RingTheory/HahnSeries/PowerSeries.lean index 094a71acddd64..7a70d9e119bf8 100644 --- a/Mathlib/RingTheory/HahnSeries/PowerSeries.lean +++ b/Mathlib/RingTheory/HahnSeries/PowerSeries.lean @@ -37,7 +37,7 @@ open Finset Function Pointwise Polynomial noncomputable section -variable {Γ : Type*} {R : Type*} +variable {Γ R : Type*} namespace HahnSeries @@ -113,7 +113,7 @@ theorem ofPowerSeries_C (r : R) : ofPowerSeries Γ R (PowerSeries.C R r) = HahnS single_coeff] split_ifs with hn · subst hn - convert @embDomain_coeff ℕ R _ _ Γ _ _ _ 0 <;> simp + convert embDomain_coeff (a := 0) <;> simp · rw [embDomain_notin_image_support] simp only [not_exists, Set.mem_image, toPowerSeries_symm_apply_coeff, mem_support, PowerSeries.coeff_C] @@ -126,7 +126,7 @@ theorem ofPowerSeries_X : ofPowerSeries Γ R PowerSeries.X = single 1 1 := by simp only [single_coeff, ofPowerSeries_apply, RingHom.coe_mk] split_ifs with hn · rw [hn] - convert @embDomain_coeff ℕ R _ _ Γ _ _ _ 1 <;> simp + convert embDomain_coeff (a := 1) <;> simp · rw [embDomain_notin_image_support] simp only [not_exists, Set.mem_image, toPowerSeries_symm_apply_coeff, mem_support, PowerSeries.coeff_X] diff --git a/Mathlib/RingTheory/HahnSeries/Summable.lean b/Mathlib/RingTheory/HahnSeries/Summable.lean index 871e001eae93b..c9ea82db6087b 100644 --- a/Mathlib/RingTheory/HahnSeries/Summable.lean +++ b/Mathlib/RingTheory/HahnSeries/Summable.lean @@ -3,7 +3,6 @@ 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.Algebra.BigOperators.Finprod import Mathlib.RingTheory.HahnSeries.Multiplication /-! @@ -29,7 +28,6 @@ commutative domain. * Remove unnecessary domain hypotheses. * More general summable families, e.g., define the evaluation homomorphism from a power series ring taking `X` to a positive order element. - * Generalize `SMul` to Hahn modules. ## References - [J. van der Hoeven, *Operators on Generalized Power Series*][van_der_hoeven] @@ -42,7 +40,7 @@ open Pointwise noncomputable section -variable {Γ : Type*} {R : Type*} +variable {Γ Γ' R V α β : Type*} namespace HahnSeries @@ -61,13 +59,11 @@ theorem isPWO_iUnion_support_powers [LinearOrderedCancelAddCommMonoid Γ] [Ring section -variable (Γ) (R) [PartialOrder Γ] [AddCommMonoid R] - /-- A family of Hahn series whose formal coefficient-wise sum is a Hahn series. For each coefficient of the sum to be well-defined, we require that only finitely many series are nonzero at any given coefficient. For the formal sum to be a Hahn series, we require that the union of the supports of the constituent series is partially well-ordered. -/ -structure SummableFamily (α : Type*) where +structure SummableFamily (Γ) (R) [PartialOrder Γ] [AddCommMonoid R] (α : Type*) where /-- A parametrized family of Hahn series. -/ toFun : α → HahnSeries Γ R isPWO_iUnion_support' : Set.IsPWO (⋃ a : α, (toFun a).support) @@ -79,7 +75,7 @@ namespace SummableFamily section AddCommMonoid -variable [PartialOrder Γ] [AddCommMonoid R] {α : Type*} +variable [PartialOrder Γ] [AddCommMonoid R] instance : FunLike (SummableFamily Γ R α) α (HahnSeries Γ R) where coe := toFun @@ -152,6 +148,17 @@ instance : AddCommMonoid (SummableFamily Γ R α) where ext apply add_assoc +/-- The coefficient function of a summable family, as a finsupp on the parameter type. -/ +@[simps] +def coeff (s : SummableFamily Γ R α) (g : Γ) : α →₀ R where + support := (s.finite_co_support g).toFinset + toFun a := (s a).coeff g + mem_support_toFun a := by simp + +@[simp] +theorem coeff_def (s : SummableFamily Γ R α) (a : α) (g : Γ) : s.coeff g a = (s a).coeff g := + rfl + /-- The infinite sum of a `SummableFamily` of Hahn series. -/ def hsum (s : SummableFamily Γ R α) : HahnSeries Γ R where coeff g := ∑ᶠ i, (s i).coeff g @@ -180,11 +187,50 @@ theorem hsum_add {s t : SummableFamily Γ R α} : (s + t).hsum = s.hsum + t.hsum simp only [hsum_coeff, add_coeff, add_apply] exact finsum_add_distrib (s.finite_co_support _) (t.finite_co_support _) +theorem hsum_coeff_eq_sum_of_subset {s : SummableFamily Γ R α} {g : Γ} {t : Finset α} + (h : { a | (s a).coeff g ≠ 0 } ⊆ t) : s.hsum.coeff g = ∑ i ∈ t, (s i).coeff g := by + simp only [hsum_coeff, finsum_eq_sum _ (s.finite_co_support _)] + exact sum_subset (Set.Finite.toFinset_subset.mpr h) (by simp) + +theorem hsum_coeff_eq_sum {s : SummableFamily Γ R α} {g : Γ} : + s.hsum.coeff g = ∑ i ∈ (s.coeff g).support, (s i).coeff g := by + simp only [hsum_coeff, finsum_eq_sum _ (s.finite_co_support _), coeff_support] + +/-- The summable family made of a single Hahn series. -/ +@[simps] +def single (x : HahnSeries Γ R) : SummableFamily Γ R Unit where + toFun _ := x + isPWO_iUnion_support' := + Eq.mpr (congrArg (fun s ↦ s.IsPWO) (Set.iUnion_const x.support)) x.isPWO_support + finite_co_support' g := Set.toFinite {a | ((fun _ ↦ x) a).coeff g ≠ 0} + +@[simp] +theorem hsum_single (x : HahnSeries Γ R) : (single x).hsum = x := by + ext g + simp only [hsum_coeff, single_toFun, finsum_unique] + +/-- A summable family induced by an equivalence of the parametrizing type. -/ +@[simps] +def Equiv (e : α ≃ β) (s : SummableFamily Γ R α) : SummableFamily Γ R β where + toFun b := s (e.symm b) + isPWO_iUnion_support' := by + refine Set.IsPWO.mono s.isPWO_iUnion_support fun g => ?_ + simp only [Set.mem_iUnion, mem_support, ne_eq, forall_exists_index] + exact fun b hg => Exists.intro (e.symm b) hg + finite_co_support' g := + (Equiv.set_finite_iff e.subtypeEquivOfSubtype').mp <| s.finite_co_support' g + +@[simp] +theorem hsum_equiv (e : α ≃ β) (s : SummableFamily Γ R α) : (Equiv e s).hsum = s.hsum := by + ext g + simp only [hsum_coeff, Equiv_toFun] + exact finsum_eq_of_bijective e.symm (Equiv.bijective e.symm) fun x => rfl + end AddCommMonoid section AddCommGroup -variable [PartialOrder Γ] [AddCommGroup R] {α : Type*} {s t : SummableFamily Γ R α} {a : α} +variable [PartialOrder Γ] [AddCommGroup R] {s t : SummableFamily Γ R α} {a : α} instance : Neg (SummableFamily Γ R α) := ⟨fun s => @@ -219,73 +265,155 @@ theorem sub_apply : (s - t) a = s a - t a := end AddCommGroup -section Semiring - -variable [OrderedCancelAddCommMonoid Γ] [Semiring R] {α : Type*} - -instance : SMul (HahnSeries Γ R) (SummableFamily Γ R α) where - smul x s := - { toFun := fun a => x * s a - isPWO_iUnion_support' := by - apply (x.isPWO_support.add s.isPWO_iUnion_support).mono - refine Set.Subset.trans (Set.iUnion_mono fun a => support_mul_subset_add_support) ?_ - intro g - simp only [Set.mem_iUnion, exists_imp] - exact fun a ha => (Set.add_subset_add (Set.Subset.refl _) (Set.subset_iUnion _ a)) ha - finite_co_support' := fun g => by - apply ((addAntidiagonal x.isPWO_support s.isPWO_iUnion_support g).finite_toSet.biUnion' - fun ij _ => ?_).subset fun a ha => ?_ - · exact fun ij _ => Function.support fun a => (s a).coeff ij.2 - · apply s.finite_co_support - · obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support ha - simp only [exists_prop, Set.mem_iUnion, mem_addAntidiagonal, mul_coeff, mem_support, - isPWO_support, Prod.exists] - exact ⟨i, j, mem_coe.2 (mem_addAntidiagonal.2 ⟨hi, Set.mem_iUnion.2 ⟨a, hj⟩, rfl⟩), hj⟩ } +section SMul + +variable [PartialOrder Γ] [PartialOrder Γ'] [AddCommMonoid R] [AddCommMonoid V] [SMulWithZero R V] + +theorem smul_support_subset_prod (s : SummableFamily Γ R α) + (t : SummableFamily Γ' V β) (gh : Γ × Γ') : + (Function.support fun (i : α × β) ↦ (s i.1).coeff gh.1 • (t i.2).coeff gh.2) ⊆ + ((s.finite_co_support' gh.1).prod (t.finite_co_support' gh.2)).toFinset := by + intro _ hab + simp_all only [Function.mem_support, ne_eq, Set.Finite.coe_toFinset, Set.mem_prod, + Set.mem_setOf_eq] + exact ⟨left_ne_zero_of_smul hab, right_ne_zero_of_smul hab⟩ + +theorem smul_support_finite (s : SummableFamily Γ R α) + (t : SummableFamily Γ' V β) (gh : Γ × Γ') : + (Function.support fun (i : α × β) ↦ (s i.1).coeff gh.1 • (t i.2).coeff gh.2).Finite := + Set.Finite.subset (Set.toFinite ((s.finite_co_support' gh.1).prod + (t.finite_co_support' gh.2)).toFinset) (smul_support_subset_prod s t gh) + +variable [VAdd Γ Γ'] [IsOrderedCancelVAdd Γ Γ'] + +open HahnModule + +theorem isPWO_iUnion_support_prod_smul {s : α → HahnSeries Γ R} {t : β → HahnSeries Γ' V} + (hs : (⋃ a, (s a).support).IsPWO) (ht : (⋃ b, (t b).support).IsPWO) : + (⋃ (a : α × β), ((fun a ↦ (of R).symm + ((s a.1) • (of R) (t a.2))) a).support).IsPWO := by + apply (hs.vadd ht).mono + have hsupp : ∀ ab : α × β, support ((fun ab ↦ (of R).symm (s ab.1 • (of R) (t ab.2))) ab) ⊆ + (s ab.1).support +ᵥ (t ab.2).support := by + intro ab + refine Set.Subset.trans (fun x hx => ?_) (support_vaddAntidiagonal_subset_vadd + (hs := (s ab.1).isPWO_support) (ht := (t ab.2).isPWO_support)) + contrapose! hx + simp only [Set.mem_setOf_eq, not_nonempty_iff_eq_empty] at hx + rw [mem_support, not_not, HahnModule.smul_coeff, hx, sum_empty] + refine Set.Subset.trans (Set.iUnion_mono fun a => (hsupp a)) ?_ + simp_all only [Set.iUnion_subset_iff, Prod.forall] + exact fun a b => Set.vadd_subset_vadd (Set.subset_iUnion_of_subset a fun x y ↦ y) + (Set.subset_iUnion_of_subset b fun x y ↦ y) + +theorem finite_co_support_prod_smul (s : SummableFamily Γ R α) + (t : SummableFamily Γ' V β) (g : Γ') : + Finite {(ab : α × β) | + ((fun (ab : α × β) ↦ (of R).symm (s ab.1 • (of R) (t ab.2))) ab).coeff g ≠ 0} := by + apply ((VAddAntidiagonal s.isPWO_iUnion_support t.isPWO_iUnion_support g).finite_toSet.biUnion' + (fun gh _ => smul_support_finite s t gh)).subset _ + exact fun ab hab => by + simp only [smul_coeff, ne_eq, Set.mem_setOf_eq] at hab + obtain ⟨ij, hij⟩ := Finset.exists_ne_zero_of_sum_ne_zero hab + simp only [mem_coe, mem_vaddAntidiagonal, Set.mem_iUnion, mem_support, ne_eq, + Function.mem_support, exists_prop, Prod.exists] + exact ⟨ij.1, ij.2, ⟨⟨ab.1, left_ne_zero_of_smul hij.2⟩, ⟨ab.2, right_ne_zero_of_smul hij.2⟩, + ((mem_vaddAntidiagonal _ _ _).mp hij.1).2.2⟩, hij.2⟩ + +/-- An elementwise scalar multiplication of one summable family on another. -/ +@[simps] +def FamilySMul (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 + +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 • + (t a.2).coeff x.2 = ∑ x ∈ VAddAntidiagonal s.isPWO_iUnion_support' t.isPWO_iUnion_support' g, + (s a.1).coeff x.1 • (t a.2).coeff x.2 := by + refine sum_subset (fun gh hgh => ?_) fun gh hgh h => ?_ + · simp_all only [mem_vaddAntidiagonal, Function.mem_support, Set.mem_iUnion, mem_support] + exact ⟨Exists.intro a.1 hgh.1, Exists.intro a.2 hgh.2.1, trivial⟩ + · by_cases hs : (s a.1).coeff gh.1 = 0 + · 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] + (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) (g : Γ') : + (FamilySMul 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_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 _ => ?_ + rw [finsum_eq_sum _ (smul_support_finite s t gh), ← sum_product_right'] + refine sum_subset (fun ab hab => ?_) (fun ab _ hab => by simp_all) + have hsupp := smul_support_subset_prod s t gh + simp_all only [mem_vaddAntidiagonal, Set.mem_iUnion, mem_support, ne_eq, Set.Finite.mem_toFinset, + Function.mem_support, Set.Finite.coe_toFinset, support_subset_iff, Set.mem_prod, + 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] + (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) : + (FamilySMul 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] + 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] + constructor + · rw [hsum_coeff_eq_sum] at hgh + have h' := Finset.exists_ne_zero_of_sum_ne_zero hgh.1 + simpa using h' + · by_contra hi + simp_all + · simp only [Set.image_id', mem_coe, mem_vaddAntidiagonal, mem_support, ne_eq, not_and] at hgh + by_cases h : s.hsum.coeff gh.1 = 0 + · exact smul_eq_zero_of_left h (t.hsum.coeff gh.2) + · simp_all + +instance [AddCommMonoid R] [SMulWithZero R V] : SMul (HahnSeries Γ R) (SummableFamily Γ' V β) where + smul x t := Equiv (Equiv.punitProd β) <| FamilySMul (single x) t + +theorem smul_eq {x : HahnSeries Γ R} {t : SummableFamily Γ' V β} : + x • t = Equiv (Equiv.punitProd β) (FamilySMul (single x) t) := + rfl @[simp] -theorem smul_apply {x : HahnSeries Γ R} {s : SummableFamily Γ R α} {a : α} : (x • s) a = x * s a := +theorem smul_apply {x : HahnSeries Γ R} {s : SummableFamily Γ' V α} {a : α} : + (x • s) a = (of R).symm (x • of R (s a)) := rfl -instance : Module (HahnSeries Γ R) (SummableFamily Γ R α) where +@[simp] +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] + +end SMul + +section Semiring + +variable [OrderedCancelAddCommMonoid Γ] [PartialOrder Γ'] [AddAction Γ Γ'] + [IsOrderedCancelVAdd Γ Γ'] [Semiring R] + +instance [AddCommMonoid V] [Module R V] : Module (HahnSeries Γ R) (SummableFamily Γ' V α) where smul := (· • ·) - smul_zero _ := ext fun _ => mul_zero _ - zero_smul _ := ext fun _ => zero_mul _ - one_smul _ := ext fun _ => one_mul _ - add_smul _ _ _ := ext fun _ => add_mul _ _ _ - smul_add _ _ _ := ext fun _ => mul_add _ _ _ - mul_smul _ _ _ := ext fun _ => mul_assoc _ _ _ + smul_zero _ := ext fun _ => by simp + zero_smul _ := ext fun _ => by simp + one_smul _ := ext fun _ => by rw [smul_apply, HahnModule.one_smul', Equiv.symm_apply_apply] + add_smul _ _ _ := ext fun _ => by simp [add_smul] + smul_add _ _ _ := ext fun _ => by simp + mul_smul _ _ _ := ext fun _ => by simp [HahnModule.instModule.mul_smul] -@[simp] -theorem hsum_smul {x : HahnSeries Γ R} {s : SummableFamily Γ R α} : (x • s).hsum = x * s.hsum := by - ext g - simp only [mul_coeff, hsum_coeff, smul_apply] - refine - (Eq.trans (finsum_congr fun a => ?_) - (finsum_sum_comm (addAntidiagonal x.isPWO_support s.isPWO_iUnion_support g) - (fun i ij => x.coeff (Prod.fst ij) * (s i).coeff ij.snd) ?_)).trans - ?_ - · refine sum_subset (addAntidiagonal_mono_right - (Set.subset_iUnion (fun j => support (toFun s j)) a)) ?_ - rintro ⟨i, j⟩ hU ha - rw [mem_addAntidiagonal] at * - rw [Classical.not_not.1 fun con => ha ⟨hU.1, con, hU.2.2⟩, mul_zero] - · rintro ⟨i, j⟩ _ - refine (s.finite_co_support j).subset ?_ - simp_rw [Function.support_subset_iff', Function.mem_support, Classical.not_not] - intro a ha - rw [ha, mul_zero] - · refine (sum_congr rfl ?_).trans (sum_subset (addAntidiagonal_mono_right ?_) ?_).symm - · rintro ⟨i, j⟩ _ - rw [mul_finsum] - apply s.finite_co_support - · intro x hx - simp only [Set.mem_iUnion, Ne, mem_support] - contrapose! hx - simp [hx] - · rintro ⟨i, j⟩ hU ha - rw [mem_addAntidiagonal] at * - rw [← hsum_coeff, Classical.not_not.1 fun con => ha ⟨hU.1, con, hU.2.2⟩, - mul_zero] +theorem hsum_smul {x : HahnSeries Γ R} {s : SummableFamily Γ R α} : + (x • s).hsum = x * s.hsum := by + rw [hsum_smul_module, of_symm_smul_of_eq_mul] /-- The summation of a `summable_family` as a `LinearMap`. -/ @[simps] @@ -393,6 +521,7 @@ section powers variable [LinearOrderedCancelAddCommMonoid Γ] [CommRing R] [IsDomain R] /-- The powers of an element of positive valuation form a summable family. -/ +@[simps] def powers (x : HahnSeries Γ R) (hx : 0 < x.orderTop) : SummableFamily Γ R ℕ where toFun n := x ^ n isPWO_iUnion_support' := isPWO_iUnion_support_powers hx @@ -438,8 +567,8 @@ theorem embDomain_succ_smul_powers : rw [Set.mem_range, not_exists] exact Nat.succ_ne_zero · refine Eq.trans (embDomain_image _ ⟨Nat.succ, Nat.succ_injective⟩) ?_ - simp only [pow_succ', coe_powers, coe_sub, smul_apply, coe_ofFinsupp, Pi.sub_apply] - rw [Finsupp.single_eq_of_ne n.succ_ne_zero.symm, sub_zero] + rw [smul_apply, powers_toFun, coe_sub, coe_powers, Pi.sub_apply, coe_ofFinsupp, pow_succ', + Finsupp.single_eq_of_ne (Nat.zero_ne_add_one n), sub_zero, of_symm_smul_of_eq_mul] theorem one_sub_self_mul_hsum_powers : (1 - x) * (powers x hx).hsum = 1 := by rw [← hsum_smul, sub_smul 1 x (powers x hx), one_smul, hsum_sub, ← @@ -512,9 +641,9 @@ instance instField [Field R] : Field (HahnSeries Γ R) where rw [sub_sub_cancel] at h rw [← mul_assoc, mul_comm x, h] nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl end Inversion diff --git a/Mathlib/RingTheory/HahnSeries/Valuation.lean b/Mathlib/RingTheory/HahnSeries/Valuation.lean index 95c72f7dfe144..c1aec5076a7f1 100644 --- a/Mathlib/RingTheory/HahnSeries/Valuation.lean +++ b/Mathlib/RingTheory/HahnSeries/Valuation.lean @@ -37,7 +37,7 @@ variable (Γ R) [LinearOrderedCancelAddCommMonoid Γ] [Ring R] [IsDomain R] /-- The additive valuation on `HahnSeries Γ R`, returning the smallest index at which a Hahn Series has a nonzero coefficient, or `⊤` for the 0 series. -/ def addVal : AddValuation (HahnSeries Γ R) (WithTop Γ) := - AddValuation.of orderTop orderTop_zero (orderTop_one) (fun x y => min_orderTop_le_orderTop_add) + AddValuation.of orderTop orderTop_zero (orderTop_one) (fun _ _ => min_orderTop_le_orderTop_add) fun x y => by by_cases hx : x = 0; · simp [hx] by_cases hy : y = 0; · simp [hy] diff --git a/Mathlib/RingTheory/Henselian.lean b/Mathlib/RingTheory/Henselian.lean index c439259451ff0..42918161d3de0 100644 --- a/Mathlib/RingTheory/Henselian.lean +++ b/Mathlib/RingTheory/Henselian.lean @@ -60,8 +60,8 @@ universe u v open Polynomial LocalRing Polynomial Function List -theorem isLocalRingHom_of_le_jacobson_bot {R : Type*} [CommRing R] (I : Ideal R) - (h : I ≤ Ideal.jacobson ⊥) : IsLocalRingHom (Ideal.Quotient.mk I) := by +theorem isLocalHom_of_le_jacobson_bot {R : Type*} [CommRing R] (I : Ideal R) + (h : I ≤ Ideal.jacobson ⊥) : IsLocalHom (Ideal.Quotient.mk I) := by constructor intro a h have : IsUnit (Ideal.Quotient.mk (Ideal.jacobson ⊥) a) := by @@ -79,6 +79,9 @@ theorem isLocalRingHom_of_le_jacobson_bot {R : Type*} [CommRing R] (I : Ideal R) simp? at h1 says simp only [mul_one, sub_add_cancel, IsUnit.mul_iff] at h1 exact h1.1 +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_of_le_jacobson_bot := isLocalHom_of_le_jacobson_bot + /-- A ring `R` is *Henselian* at an ideal `I` if the following condition holds: for every polynomial `f` over `R`, with a *simple* root `a₀` over the quotient ring `R/I`, there exists a lift `a : R` of `a₀` that is a root of `f`. @@ -193,8 +196,8 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] exact (ih.eval f).trans h₁ have hf'c : ∀ n, IsUnit (f'.eval (c n)) := by intro n - haveI := isLocalRingHom_of_le_jacobson_bot I (IsAdicComplete.le_jacobson_bot I) - apply isUnit_of_map_unit (Ideal.Quotient.mk I) + haveI := isLocalHom_of_le_jacobson_bot I (IsAdicComplete.le_jacobson_bot I) + apply IsUnit.of_map (Ideal.Quotient.mk I) convert h₂ using 1 exact SModEq.def.mp ((hc_mod n).eval _) have hfcI : ∀ n, f.eval (c n) ∈ I ^ (n + 1) := by @@ -229,13 +232,7 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] clear hmn induction' k with k ih · rw [add_zero] - rw [← add_assoc] - #adaptation_note /-- nightly-2024-03-11 - I'm not sure why the `erw` is now needed here. It looks like it should work. - It looks like a diamond between `instHAdd` on `Nat` and `AddSemigroup.toAdd` which is - used by `instHAdd` -/ - erw [hc] - rw [← add_zero (c m), sub_eq_add_neg] + rw [← add_assoc, hc, ← add_zero (c m), sub_eq_add_neg] refine ih.add ?_ symm rw [SModEq.zero, Ideal.neg_mem_iff] diff --git a/Mathlib/RingTheory/Ideal/AssociatedPrime.lean b/Mathlib/RingTheory/Ideal/AssociatedPrime.lean index b4ddec4e36127..d71a198dceeba 100644 --- a/Mathlib/RingTheory/Ideal/AssociatedPrime.lean +++ b/Mathlib/RingTheory/Ideal/AssociatedPrime.lean @@ -5,7 +5,7 @@ Authors: Andrew Yang -/ import Mathlib.LinearAlgebra.Span import Mathlib.RingTheory.Ideal.IsPrimary -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Noetherian /-! @@ -148,7 +148,8 @@ theorem IsAssociatedPrime.eq_radical (hI : I.IsPrimary) (h : IsAssociatedPrime J Ideal.Quotient.mkₐ_eq_mk, ← Ideal.Quotient.mk_eq_mk, Submodule.Quotient.mk_eq_zero] apply le_antisymm · intro y hy - exact (hI.2 <| e.mp hy).resolve_left ((Submodule.Quotient.mk_eq_zero I).not.mp this) + exact ((Ideal.isPrimary_iff.1 hI).2 <| e.mp hy).resolve_left + ((Submodule.Quotient.mk_eq_zero I).not.mp this) · rw [hJ.radical_le_iff] intro y hy exact e.mpr (I.mul_mem_left x hy) diff --git a/Mathlib/RingTheory/Ideal/Basic.lean b/Mathlib/RingTheory/Ideal/Basic.lean index 36081a3d2b091..2ce325801033f 100644 --- a/Mathlib/RingTheory/Ideal/Basic.lean +++ b/Mathlib/RingTheory/Ideal/Basic.lean @@ -3,17 +3,19 @@ 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.Tactic.FinCases +import Mathlib.Algebra.Associated.Basic +import Mathlib.Algebra.Field.IsField import Mathlib.Data.Nat.Choose.Sum import Mathlib.LinearAlgebra.Finsupp -import Mathlib.Algebra.Field.IsField -import Mathlib.Tactic.Abel +import Mathlib.RingTheory.Ideal.Maximal +import Mathlib.Tactic.FinCases /-! # Ideals over a ring -This file defines `Ideal R`, the type of (left) ideals over a ring `R`. +This file contains an assortment of definitions and results for `Ideal R`, +the type of (left) ideals over a ring `R`. Note that over commutative rings, left ideals and two-sided ideals are equivalent. ## Implementation notes @@ -28,360 +30,18 @@ Support right ideals, and two-sided ideals over non-commutative rings. universe u v w -variable {α : Type u} {β : Type v} +variable {α : Type u} {β : Type v} {F : Type w} open Set Function open Pointwise -/-- A (left) ideal in a semiring `R` is an additive submonoid `s` such that -`a * b ∈ s` whenever `b ∈ s`. If `R` is a ring, then `s` is an additive subgroup. -/ -abbrev Ideal (R : Type u) [Semiring R] := - Submodule R R - -/-- A ring is a principal ideal ring if all (left) ideals are principal. -/ -@[mk_iff] -class IsPrincipalIdealRing (R : Type u) [Semiring R] : Prop where - principal : ∀ S : Ideal R, S.IsPrincipal - -attribute [instance] IsPrincipalIdealRing.principal - section Semiring namespace Ideal variable [Semiring α] (I : Ideal α) {a b : α} -protected theorem zero_mem : (0 : α) ∈ I := - Submodule.zero_mem I - -protected theorem add_mem : a ∈ I → b ∈ I → a + b ∈ I := - Submodule.add_mem I - -variable (a) - -theorem mul_mem_left : b ∈ I → a * b ∈ I := - Submodule.smul_mem I a - -variable {a} - -@[ext] -theorem ext {I J : Ideal α} (h : ∀ x, x ∈ I ↔ x ∈ J) : I = J := - Submodule.ext h - -theorem sum_mem (I : Ideal α) {ι : Type*} {t : Finset ι} {f : ι → α} : - (∀ c ∈ t, f c ∈ I) → (∑ i ∈ t, f i) ∈ I := - Submodule.sum_mem I - -theorem eq_top_of_unit_mem (x y : α) (hx : x ∈ I) (h : y * x = 1) : I = ⊤ := - eq_top_iff.2 fun z _ => - calc - z * y * x ∈ I := I.mul_mem_left _ hx - _ = z * (y * x) := mul_assoc z y x - _ = z := by rw [h, mul_one] - -theorem eq_top_of_isUnit_mem {x} (hx : x ∈ I) (h : IsUnit x) : I = ⊤ := - let ⟨y, hy⟩ := h.exists_left_inv - eq_top_of_unit_mem I x y hx hy - -theorem eq_top_iff_one : I = ⊤ ↔ (1 : α) ∈ I := - ⟨by rintro rfl; trivial, fun h => eq_top_of_unit_mem _ _ 1 h (by simp)⟩ - -theorem ne_top_iff_one : I ≠ ⊤ ↔ (1 : α) ∉ I := - not_congr I.eq_top_iff_one - -@[simp] -theorem unit_mul_mem_iff_mem {x y : α} (hy : IsUnit y) : y * x ∈ I ↔ x ∈ I := by - refine ⟨fun h => ?_, fun h => I.mul_mem_left y h⟩ - obtain ⟨y', hy'⟩ := hy.exists_left_inv - have := I.mul_mem_left y' h - rwa [← mul_assoc, hy', one_mul] at this - -/-- The ideal generated by a subset of a ring -/ -def span (s : Set α) : Ideal α := - Submodule.span α s - -@[simp] -theorem submodule_span_eq {s : Set α} : Submodule.span α s = Ideal.span s := - rfl - -@[simp] -theorem span_empty : span (∅ : Set α) = ⊥ := - Submodule.span_empty - -@[simp] -theorem span_univ : span (Set.univ : Set α) = ⊤ := - Submodule.span_univ - -theorem span_union (s t : Set α) : span (s ∪ t) = span s ⊔ span t := - Submodule.span_union _ _ - -theorem span_iUnion {ι} (s : ι → Set α) : span (⋃ i, s i) = ⨆ i, span (s i) := - Submodule.span_iUnion _ - -theorem mem_span {s : Set α} (x) : x ∈ span s ↔ ∀ p : Ideal α, s ⊆ p → x ∈ p := - mem_iInter₂ - -theorem subset_span {s : Set α} : s ⊆ span s := - Submodule.subset_span - -theorem span_le {s : Set α} {I} : span s ≤ I ↔ s ⊆ I := - Submodule.span_le - -theorem span_mono {s t : Set α} : s ⊆ t → span s ≤ span t := - Submodule.span_mono - -@[simp] -theorem span_eq : span (I : Set α) = I := - Submodule.span_eq _ - -@[simp] -theorem span_singleton_one : span ({1} : Set α) = ⊤ := - (eq_top_iff_one _).2 <| subset_span <| mem_singleton _ - -theorem isCompactElement_top : CompleteLattice.IsCompactElement (⊤ : Ideal α) := by - simpa only [← span_singleton_one] using Submodule.singleton_span_isCompactElement 1 - -theorem mem_span_insert {s : Set α} {x y} : - x ∈ span (insert y s) ↔ ∃ a, ∃ z ∈ span s, x = a * y + z := - Submodule.mem_span_insert - -theorem mem_span_singleton' {x y : α} : x ∈ span ({y} : Set α) ↔ ∃ a, a * y = x := - Submodule.mem_span_singleton - -theorem mem_span_singleton_self (x : α) : x ∈ span ({x} : Set α) := - Submodule.mem_span_singleton_self x - -theorem span_singleton_le_iff_mem {x : α} : span {x} ≤ I ↔ x ∈ I := - Submodule.span_singleton_le_iff_mem _ _ - -theorem span_singleton_mul_left_unit {a : α} (h2 : IsUnit a) (x : α) : - span ({a * x} : Set α) = span {x} := by - apply le_antisymm <;> rw [span_singleton_le_iff_mem, mem_span_singleton'] - exacts [⟨a, rfl⟩, ⟨_, h2.unit.inv_mul_cancel_left x⟩] - -theorem span_insert (x) (s : Set α) : span (insert x s) = span ({x} : Set α) ⊔ span s := - Submodule.span_insert x s - -theorem span_eq_bot {s : Set α} : span s = ⊥ ↔ ∀ x ∈ s, (x : α) = 0 := - Submodule.span_eq_bot - -@[simp] -theorem span_singleton_eq_bot {x} : span ({x} : Set α) = ⊥ ↔ x = 0 := - Submodule.span_singleton_eq_bot - -theorem span_singleton_ne_top {α : Type*} [CommSemiring α] {x : α} (hx : ¬IsUnit x) : - Ideal.span ({x} : Set α) ≠ ⊤ := - (Ideal.ne_top_iff_one _).mpr fun h1 => - let ⟨y, hy⟩ := Ideal.mem_span_singleton'.mp h1 - hx ⟨⟨x, y, mul_comm y x ▸ hy, hy⟩, rfl⟩ - -@[simp] -theorem span_zero : span (0 : Set α) = ⊥ := by rw [← Set.singleton_zero, span_singleton_eq_bot] - -@[simp] -theorem span_one : span (1 : Set α) = ⊤ := by rw [← Set.singleton_one, span_singleton_one] - -theorem span_eq_top_iff_finite (s : Set α) : - span s = ⊤ ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ span (s' : Set α) = ⊤ := by - simp_rw [eq_top_iff_one] - exact ⟨Submodule.mem_span_finite_of_mem_span, fun ⟨s', h₁, h₂⟩ => span_mono h₁ h₂⟩ - -theorem mem_span_singleton_sup {x y : α} {I : Ideal α} : - x ∈ Ideal.span {y} ⊔ I ↔ ∃ a : α, ∃ b ∈ I, a * y + b = x := by - rw [Submodule.mem_sup] - constructor - · rintro ⟨ya, hya, b, hb, rfl⟩ - obtain ⟨a, rfl⟩ := mem_span_singleton'.mp hya - exact ⟨a, b, hb, rfl⟩ - · rintro ⟨a, b, hb, rfl⟩ - exact ⟨a * y, Ideal.mem_span_singleton'.mpr ⟨a, rfl⟩, b, hb, rfl⟩ - -/-- The ideal generated by an arbitrary binary relation. --/ -def ofRel (r : α → α → Prop) : Ideal α := - Submodule.span α { x | ∃ a b, r a b ∧ x + b = a } - -/-- An ideal `P` of a ring `R` is prime if `P ≠ R` and `xy ∈ P → x ∈ P ∨ y ∈ P` -/ -class IsPrime (I : Ideal α) : Prop where - /-- The prime ideal is not the entire ring. -/ - ne_top' : I ≠ ⊤ - /-- If a product lies in the prime ideal, then at least one element lies in the prime ideal. -/ - mem_or_mem' : ∀ {x y : α}, x * y ∈ I → x ∈ I ∨ y ∈ I - -theorem isPrime_iff {I : Ideal α} : IsPrime I ↔ I ≠ ⊤ ∧ ∀ {x y : α}, x * y ∈ I → x ∈ I ∨ y ∈ I := - ⟨fun h => ⟨h.1, h.2⟩, fun h => ⟨h.1, h.2⟩⟩ - -theorem IsPrime.ne_top {I : Ideal α} (hI : I.IsPrime) : I ≠ ⊤ := - hI.1 - -theorem IsPrime.mem_or_mem {I : Ideal α} (hI : I.IsPrime) {x y : α} : x * y ∈ I → x ∈ I ∨ y ∈ I := - hI.2 - -theorem IsPrime.mem_or_mem_of_mul_eq_zero {I : Ideal α} (hI : I.IsPrime) {x y : α} (h : x * y = 0) : - x ∈ I ∨ y ∈ I := - hI.mem_or_mem (h.symm ▸ I.zero_mem) - -theorem IsPrime.mem_of_pow_mem {I : Ideal α} (hI : I.IsPrime) {r : α} (n : ℕ) (H : r ^ n ∈ I) : - r ∈ I := by - induction n with - | zero => - rw [pow_zero] at H - exact (mt (eq_top_iff_one _).2 hI.1).elim H - | succ n ih => - rw [pow_succ] at H - exact Or.casesOn (hI.mem_or_mem H) ih id - -theorem not_isPrime_iff {I : Ideal α} : - ¬I.IsPrime ↔ I = ⊤ ∨ ∃ (x : α) (_hx : x ∉ I) (y : α) (_hy : y ∉ I), x * y ∈ I := by - simp_rw [Ideal.isPrime_iff, not_and_or, Ne, Classical.not_not, not_forall, not_or] - exact - or_congr Iff.rfl - ⟨fun ⟨x, y, hxy, hx, hy⟩ => ⟨x, hx, y, hy, hxy⟩, fun ⟨x, hx, y, hy, hxy⟩ => - ⟨x, y, hxy, hx, hy⟩⟩ - -theorem zero_ne_one_of_proper {I : Ideal α} (h : I ≠ ⊤) : (0 : α) ≠ 1 := fun hz => - I.ne_top_iff_one.1 h <| hz ▸ I.zero_mem - -theorem bot_prime [IsDomain α] : (⊥ : Ideal α).IsPrime := - ⟨fun h => one_ne_zero (α := α) (by rwa [Ideal.eq_top_iff_one, Submodule.mem_bot] at h), fun h => - mul_eq_zero.mp (by simpa only [Submodule.mem_bot] using h)⟩ - -/-- An ideal is maximal if it is maximal in the collection of proper ideals. -/ -class IsMaximal (I : Ideal α) : Prop where - /-- The maximal ideal is a coatom in the ordering on ideals; that is, it is not the entire ring, - and there are no other proper ideals strictly containing it. -/ - out : IsCoatom I - -theorem isMaximal_def {I : Ideal α} : I.IsMaximal ↔ IsCoatom I := - ⟨fun h => h.1, fun h => ⟨h⟩⟩ - -theorem IsMaximal.ne_top {I : Ideal α} (h : I.IsMaximal) : I ≠ ⊤ := - (isMaximal_def.1 h).1 - -theorem isMaximal_iff {I : Ideal α} : - I.IsMaximal ↔ (1 : α) ∉ I ∧ ∀ (J : Ideal α) (x), I ≤ J → x ∉ I → x ∈ J → (1 : α) ∈ J := - isMaximal_def.trans <| - and_congr I.ne_top_iff_one <| - forall_congr' fun J => by - rw [lt_iff_le_not_le] - exact - ⟨fun H x h hx₁ hx₂ => J.eq_top_iff_one.1 <| H ⟨h, not_subset.2 ⟨_, hx₂, hx₁⟩⟩, - fun H ⟨h₁, h₂⟩ => - let ⟨x, xJ, xI⟩ := not_subset.1 h₂ - J.eq_top_iff_one.2 <| H x h₁ xI xJ⟩ - -theorem IsMaximal.eq_of_le {I J : Ideal α} (hI : I.IsMaximal) (hJ : J ≠ ⊤) (IJ : I ≤ J) : I = J := - eq_iff_le_not_lt.2 ⟨IJ, fun h => hJ (hI.1.2 _ h)⟩ - -instance : IsCoatomic (Ideal α) := by - apply CompleteLattice.coatomic_of_top_compact - rw [← span_singleton_one] - exact Submodule.singleton_span_isCompactElement 1 - -theorem IsMaximal.coprime_of_ne {M M' : Ideal α} (hM : M.IsMaximal) (hM' : M'.IsMaximal) - (hne : M ≠ M') : M ⊔ M' = ⊤ := by - contrapose! hne with h - exact hM.eq_of_le hM'.ne_top (le_sup_left.trans_eq (hM'.eq_of_le h le_sup_right).symm) - -/-- **Krull's theorem**: if `I` is an ideal that is not the whole ring, then it is included in some - maximal ideal. -/ -theorem exists_le_maximal (I : Ideal α) (hI : I ≠ ⊤) : ∃ M : Ideal α, M.IsMaximal ∧ I ≤ M := - let ⟨m, hm⟩ := (eq_top_or_exists_le_coatom I).resolve_left hI - ⟨m, ⟨⟨hm.1⟩, hm.2⟩⟩ - -variable (α) - -/-- Krull's theorem: a nontrivial ring has a maximal ideal. -/ -theorem exists_maximal [Nontrivial α] : ∃ M : Ideal α, M.IsMaximal := - let ⟨I, ⟨hI, _⟩⟩ := exists_le_maximal (⊥ : Ideal α) bot_ne_top - ⟨I, hI⟩ - -variable {α} - -instance [Nontrivial α] : Nontrivial (Ideal α) := by - rcases@exists_maximal α _ _ with ⟨M, hM, _⟩ - exact nontrivial_of_ne M ⊤ hM - -/-- If P is not properly contained in any maximal ideal then it is not properly contained - in any proper ideal -/ -theorem maximal_of_no_maximal {P : Ideal α} - (hmax : ∀ m : Ideal α, P < m → ¬IsMaximal m) (J : Ideal α) (hPJ : P < J) : J = ⊤ := by - by_contra hnonmax - rcases exists_le_maximal J hnonmax with ⟨M, hM1, hM2⟩ - exact hmax M (lt_of_lt_of_le hPJ hM2) hM1 - -theorem span_pair_comm {x y : α} : (span {x, y} : Ideal α) = span {y, x} := by - simp only [span_insert, sup_comm] - -theorem mem_span_pair {x y z : α} : z ∈ span ({x, y} : Set α) ↔ ∃ a b, a * x + b * y = z := - Submodule.mem_span_pair - -@[simp] -theorem span_pair_add_mul_left {R : Type u} [CommRing R] {x y : R} (z : R) : - (span {x + y * z, y} : Ideal R) = span {x, y} := by - ext - rw [mem_span_pair, mem_span_pair] - exact - ⟨fun ⟨a, b, h⟩ => - ⟨a, b + a * z, by - rw [← h] - ring1⟩, - fun ⟨a, b, h⟩ => - ⟨a, b - a * z, by - rw [← h] - ring1⟩⟩ - -@[simp] -theorem span_pair_add_mul_right {R : Type u} [CommRing R] {x y : R} (z : R) : - (span {x, y + x * z} : Ideal R) = span {x, y} := by - rw [span_pair_comm, span_pair_add_mul_left, span_pair_comm] - -theorem IsMaximal.exists_inv {I : Ideal α} (hI : I.IsMaximal) {x} (hx : x ∉ I) : - ∃ y, ∃ i ∈ I, y * x + i = 1 := by - cases' isMaximal_iff.1 hI with H₁ H₂ - rcases mem_span_insert.1 - (H₂ (span (insert x I)) x (Set.Subset.trans (subset_insert _ _) subset_span) hx - (subset_span (mem_insert _ _))) with - ⟨y, z, hz, hy⟩ - refine ⟨y, z, ?_, hy.symm⟩ - rwa [← span_eq I] - -section Lattice - -variable {R : Type u} [Semiring R] - --- Porting note: is this the right approach? or is there a better way to prove? (next 4 decls) -theorem mem_sup_left {S T : Ideal R} : ∀ {x : R}, x ∈ S → x ∈ S ⊔ T := - @le_sup_left _ _ S T - -theorem mem_sup_right {S T : Ideal R} : ∀ {x : R}, x ∈ T → x ∈ S ⊔ T := - @le_sup_right _ _ S T - -theorem mem_iSup_of_mem {ι : Sort*} {S : ι → Ideal R} (i : ι) : ∀ {x : R}, x ∈ S i → x ∈ iSup S := - @le_iSup _ _ _ S _ - -theorem mem_sSup_of_mem {S : Set (Ideal R)} {s : Ideal R} (hs : s ∈ S) : - ∀ {x : R}, x ∈ s → x ∈ sSup S := - @le_sSup _ _ _ _ hs - -theorem mem_sInf {s : Set (Ideal R)} {x : R} : x ∈ sInf s ↔ ∀ ⦃I⦄, I ∈ s → x ∈ I := - ⟨fun hx I his => hx I ⟨I, iInf_pos his⟩, fun H _I ⟨_J, hij⟩ => hij ▸ fun _S ⟨hj, hS⟩ => hS ▸ H hj⟩ - -@[simp 1001] -- Porting note: increased priority to appease `simpNF` -theorem mem_inf {I J : Ideal R} {x : R} : x ∈ I ⊓ J ↔ x ∈ I ∧ x ∈ J := - Iff.rfl - -@[simp 1001] -- Porting note: increased priority to appease `simpNF` -theorem mem_iInf {ι : Sort*} {I : ι → Ideal R} {x : R} : x ∈ iInf I ↔ ∀ i, x ∈ I i := - Submodule.mem_iInf _ - -@[simp 1001] -- Porting note: increased priority to appease `simpNF` -theorem mem_bot {x : R} : x ∈ (⊥ : Ideal R) ↔ x = 0 := - Submodule.mem_bot _ - -end Lattice - section Pi variable (ι : Type v) @@ -398,21 +58,6 @@ theorem mem_pi (x : ι → α) : x ∈ I.pi ι ↔ ∀ i, x i ∈ I := end Pi -theorem sInf_isPrime_of_isChain {s : Set (Ideal α)} (hs : s.Nonempty) (hs' : IsChain (· ≤ ·) s) - (H : ∀ p ∈ s, Ideal.IsPrime p) : (sInf s).IsPrime := - ⟨fun e => - let ⟨x, hx⟩ := hs - (H x hx).ne_top (eq_top_iff.mpr (e.symm.trans_le (sInf_le hx))), - fun e => - or_iff_not_imp_left.mpr fun hx => by - rw [Ideal.mem_sInf] at hx e ⊢ - push_neg at hx - obtain ⟨I, hI, hI'⟩ := hx - intro J hJ - cases' hs'.total hI hJ with h h - · exact h (((H I hI).mem_or_mem (e hI)).resolve_left hI') - · exact ((H J hJ).mem_or_mem (e hJ)).resolve_left fun x => hI' <| h x⟩ - end Ideal end Semiring @@ -427,80 +72,6 @@ namespace Ideal variable [CommSemiring α] (I : Ideal α) -@[simp] -theorem mul_unit_mem_iff_mem {x y : α} (hy : IsUnit y) : x * y ∈ I ↔ x ∈ I := - mul_comm y x ▸ unit_mul_mem_iff_mem I hy - -theorem mem_span_singleton {x y : α} : x ∈ span ({y} : Set α) ↔ y ∣ x := - mem_span_singleton'.trans <| exists_congr fun _ => by rw [eq_comm, mul_comm] - -theorem span_singleton_le_span_singleton {x y : α} : - span ({x} : Set α) ≤ span ({y} : Set α) ↔ y ∣ x := - span_le.trans <| singleton_subset_iff.trans mem_span_singleton - -theorem span_singleton_eq_span_singleton {α : Type u} [CommRing α] [IsDomain α] {x y : α} : - span ({x} : Set α) = span ({y} : Set α) ↔ Associated x y := by - rw [← dvd_dvd_iff_associated, le_antisymm_iff, and_comm] - apply and_congr <;> rw [span_singleton_le_span_singleton] - -theorem span_singleton_mul_right_unit {a : α} (h2 : IsUnit a) (x : α) : - span ({x * a} : Set α) = span {x} := by rw [mul_comm, span_singleton_mul_left_unit h2] - -@[simp] -theorem span_singleton_eq_top {x} : span ({x} : Set α) = ⊤ ↔ IsUnit x := by - rw [isUnit_iff_dvd_one, ← span_singleton_le_span_singleton, span_singleton_one, eq_top_iff] - -theorem span_singleton_prime {p : α} (hp : p ≠ 0) : IsPrime (span ({p} : Set α)) ↔ Prime p := by - simp [isPrime_iff, Prime, span_singleton_eq_top, hp, mem_span_singleton] - -theorem IsMaximal.isPrime {I : Ideal α} (H : I.IsMaximal) : I.IsPrime := - ⟨H.1.1, @fun x y hxy => - or_iff_not_imp_left.2 fun hx => by - let J : Ideal α := Submodule.span α (insert x ↑I) - have IJ : I ≤ J := Set.Subset.trans (subset_insert _ _) subset_span - have xJ : x ∈ J := Ideal.subset_span (Set.mem_insert x I) - cases' isMaximal_iff.1 H with _ oJ - specialize oJ J x IJ hx xJ - rcases Submodule.mem_span_insert.mp oJ with ⟨a, b, h, oe⟩ - obtain F : y * 1 = y * (a • x + b) := congr_arg (fun g : α => y * g) oe - rw [← mul_one y, F, mul_add, mul_comm, smul_eq_mul, mul_assoc] - refine Submodule.add_mem I (I.mul_mem_left a hxy) (Submodule.smul_mem I y ?_) - rwa [Submodule.span_eq] at h⟩ - --- see Note [lower instance priority] -instance (priority := 100) IsMaximal.isPrime' (I : Ideal α) : ∀ [_H : I.IsMaximal], I.IsPrime := - @IsMaximal.isPrime _ _ _ - -theorem span_singleton_lt_span_singleton [IsDomain α] {x y : α} : - span ({x} : Set α) < span ({y} : Set α) ↔ DvdNotUnit y x := by - rw [lt_iff_le_not_le, span_singleton_le_span_singleton, span_singleton_le_span_singleton, - dvd_and_not_dvd_iff] - -theorem factors_decreasing [IsDomain α] (b₁ b₂ : α) (h₁ : b₁ ≠ 0) (h₂ : ¬IsUnit b₂) : - span ({b₁ * b₂} : Set α) < span {b₁} := - lt_of_le_not_le - (Ideal.span_le.2 <| singleton_subset_iff.2 <| Ideal.mem_span_singleton.2 ⟨b₂, rfl⟩) fun h => - h₂ <| isUnit_of_dvd_one <| - (mul_dvd_mul_iff_left h₁).1 <| by rwa [mul_one, ← Ideal.span_singleton_le_span_singleton] - -variable (b) - -theorem mul_mem_right (h : a ∈ I) : a * b ∈ I := - mul_comm b a ▸ I.mul_mem_left b h - -variable {b} - -lemma mem_of_dvd (hab : a ∣ b) (ha : a ∈ I) : b ∈ I := by - obtain ⟨c, rfl⟩ := hab; exact I.mul_mem_right _ ha - -theorem pow_mem_of_mem (ha : a ∈ I) (n : ℕ) (hn : 0 < n) : a ^ n ∈ I := - Nat.casesOn n (Not.elim (by decide)) - (fun m _hm => (pow_succ a m).symm ▸ I.mul_mem_left (a ^ m) ha) hn - -theorem pow_mem_of_pow_mem {m n : ℕ} (ha : a ^ m ∈ I) (h : m ≤ n) : a ^ n ∈ I := by - rw [← Nat.add_sub_of_le h, pow_add] - exact I.mul_mem_right _ ha - theorem add_pow_mem_of_pow_mem_of_le {m n k : ℕ} (ha : a ^ m ∈ I) (hb : b ^ n ∈ I) (hk : m + n ≤ k + 1) : (a + b) ^ k ∈ I := by @@ -523,16 +94,6 @@ theorem add_pow_add_pred_mem_of_pow_mem {m n : ℕ} (a + b) ^ (m + n - 1) ∈ I := I.add_pow_mem_of_pow_mem_of_le ha hb <| by rw [← Nat.sub_le_iff_le_add] -theorem IsPrime.mul_mem_iff_mem_or_mem {I : Ideal α} (hI : I.IsPrime) : - ∀ {x y : α}, x * y ∈ I ↔ x ∈ I ∨ y ∈ I := @fun x y => - ⟨hI.mem_or_mem, by - rintro (h | h) - exacts [I.mul_mem_right y h, I.mul_mem_left x h]⟩ - -theorem IsPrime.pow_mem_iff_mem {I : Ideal α} (hI : I.IsPrime) {r : α} (n : ℕ) (hn : 0 < n) : - r ^ n ∈ I ↔ r ∈ I := - ⟨hI.mem_of_pow_mem n, fun hr => I.pow_mem_of_mem hr n hn⟩ - theorem pow_multiset_sum_mem_span_pow [DecidableEq α] (s : Multiset α) (n : ℕ) : s.sum ^ (Multiset.card s * n + 1) ∈ span ((s.map fun (x : α) ↦ x ^ (n + 1)).toFinset : Set α) := by @@ -589,82 +150,16 @@ theorem span_pow_eq_top (s : Set α) (hs : span s = ⊤) (n : ℕ) : rw [mul_pow, mem_span_singleton] exact ⟨f x ^ (n + 1), mul_comm _ _⟩ -lemma isPrime_of_maximally_disjoint (I : Ideal α) - (S : Submonoid α) - (disjoint : Disjoint (I : Set α) S) - (maximally_disjoint : ∀ (J : Ideal α), I < J → ¬ Disjoint (J : Set α) S) : - I.IsPrime where - ne_top' := by - rintro rfl - have : 1 ∈ (S : Set α) := S.one_mem - aesop - mem_or_mem' {x y} hxy := by - by_contra! rid - have hx := maximally_disjoint (I ⊔ span {x}) (Submodule.lt_sup_iff_not_mem.mpr rid.1) - have hy := maximally_disjoint (I ⊔ span {y}) (Submodule.lt_sup_iff_not_mem.mpr rid.2) - simp only [Set.not_disjoint_iff, mem_inter_iff, SetLike.mem_coe, Submodule.mem_sup, - mem_span_singleton] at hx hy - obtain ⟨s₁, ⟨i₁, hi₁, ⟨_, ⟨r₁, rfl⟩, hr₁⟩⟩, hs₁⟩ := hx - obtain ⟨s₂, ⟨i₂, hi₂, ⟨_, ⟨r₂, rfl⟩, hr₂⟩⟩, hs₂⟩ := hy - refine disjoint.ne_of_mem - (I.add_mem (I.mul_mem_left (i₁ + x * r₁) hi₂) <| I.add_mem (I.mul_mem_right (y * r₂) hi₁) <| - I.mul_mem_right (r₁ * r₂) hxy) - (S.mul_mem hs₁ hs₂) ?_ - rw [← hr₁, ← hr₂] - ring - end Ideal end CommSemiring -section Ring - -namespace Ideal - -variable [Ring α] (I : Ideal α) {a b : α} - -protected theorem neg_mem_iff : -a ∈ I ↔ a ∈ I := - Submodule.neg_mem_iff I - -protected theorem add_mem_iff_left : b ∈ I → (a + b ∈ I ↔ a ∈ I) := - Submodule.add_mem_iff_left I - -protected theorem add_mem_iff_right : a ∈ I → (a + b ∈ I ↔ b ∈ I) := - Submodule.add_mem_iff_right I - -protected theorem sub_mem : a ∈ I → b ∈ I → a - b ∈ I := - Submodule.sub_mem I - -theorem mem_span_insert' {s : Set α} {x y} : x ∈ span (insert y s) ↔ ∃ a, x + a * y ∈ span s := - Submodule.mem_span_insert' - -@[simp] -theorem span_singleton_neg (x : α) : (span {-x} : Ideal α) = span {x} := by - ext - simp only [mem_span_singleton'] - exact ⟨fun ⟨y, h⟩ => ⟨-y, h ▸ neg_mul_comm y x⟩, fun ⟨y, h⟩ => ⟨-y, h ▸ neg_mul_neg y x⟩⟩ - -end Ideal - -end Ring - section DivisionSemiring variable {K : Type u} [DivisionSemiring K] (I : Ideal K) namespace Ideal -/-- All ideals in a division (semi)ring are trivial. -/ -theorem eq_bot_or_top : I = ⊥ ∨ I = ⊤ := by - rw [or_iff_not_imp_right] - change _ ≠ _ → _ - rw [Ideal.ne_top_iff_one] - intro h1 - rw [eq_bot_iff] - intro r hr - by_cases H : r = 0; · simpa - simpa [H, h1] using I.mul_mem_left r⁻¹ hr - variable (K) in /-- A bijection between (left) ideals of a division ring and `{0, 1}`, sending `⊥` to `0` and `⊤` to `1`. -/ @@ -681,30 +176,10 @@ this automatically gives an `IsSimpleModule K` instance. -/ instance isSimpleOrder : IsSimpleOrder (Ideal K) := ⟨eq_bot_or_top⟩ -theorem eq_bot_of_prime [h : I.IsPrime] : I = ⊥ := - or_iff_not_imp_right.mp I.eq_bot_or_top h.1 - -theorem bot_isMaximal : IsMaximal (⊥ : Ideal K) := - ⟨⟨fun h => absurd ((eq_top_iff_one (⊤ : Ideal K)).mp rfl) (by rw [← h]; simp), fun I hI => - or_iff_not_imp_left.mp (eq_bot_or_top I) (ne_of_gt hI)⟩⟩ - end Ideal end DivisionSemiring -section CommRing - -namespace Ideal - -theorem mul_sub_mul_mem {R : Type*} [CommRing R] (I : Ideal R) {a b c d : R} (h1 : a - b ∈ I) - (h2 : c - d ∈ I) : a * c - b * d ∈ I := by - rw [show a * c - b * d = (a - b) * c + b * (c - d) by rw [sub_mul, mul_sub]; abel] - exact I.add_mem (I.mul_mem_right _ h1) (I.mul_mem_left _ h2) - -end Ideal - -end CommRing - -- TODO: consider moving the lemmas below out of the `Ring` namespace since they are -- about `CommSemiring`s. namespace Ring @@ -805,6 +280,12 @@ theorem zero_mem_nonunits [Semiring α] : 0 ∈ nonunits α ↔ (0 : α) ≠ 1 : theorem one_not_mem_nonunits [Monoid α] : (1 : α) ∉ nonunits α := not_not_intro isUnit_one +-- Porting note : as this can be proved by other `simp` lemmas, this is marked as high priority. +@[simp (high)] +theorem map_mem_nonunits_iff [Monoid α] [Monoid β] [FunLike F α β] [MonoidHomClass F α β] (f : F) + [IsLocalHom f] (a) : f a ∈ nonunits β ↔ a ∈ nonunits α := + ⟨fun h ha => h <| ha.map f, fun h ha => h <| ha.of_map⟩ + theorem coe_subset_nonunits [Semiring α] {I : Ideal α} (h : I ≠ ⊤) : (I : Set α) ⊆ nonunits α := fun _x hx hu => h <| I.eq_top_of_isUnit_mem hx hu diff --git a/Mathlib/RingTheory/Ideal/Basis.lean b/Mathlib/RingTheory/Ideal/Basis.lean index 70d55368a9142..4453148c5170a 100644 --- a/Mathlib/RingTheory/Ideal/Basis.lean +++ b/Mathlib/RingTheory/Ideal/Basis.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.Algebra.Algebra.Bilinear -import Mathlib.RingTheory.Ideal.Basic import Mathlib.LinearAlgebra.Basis.Defs +import Mathlib.RingTheory.Ideal.Span /-! # The basis of ideals diff --git a/Mathlib/RingTheory/Ideal/Colon.lean b/Mathlib/RingTheory/Ideal/Colon.lean index 903322d97d3f7..aaffa3c7acc57 100644 --- a/Mathlib/RingTheory/Ideal/Colon.lean +++ b/Mathlib/RingTheory/Ideal/Colon.lean @@ -3,8 +3,8 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ -import Mathlib.LinearAlgebra.Quotient -import Mathlib.RingTheory.Ideal.Operations +import Mathlib.LinearAlgebra.Quotient.Defs +import Mathlib.RingTheory.Ideal.Maps /-! # The colon ideal diff --git a/Mathlib/RingTheory/Ideal/Defs.lean b/Mathlib/RingTheory/Ideal/Defs.lean new file mode 100644 index 0000000000000..31b86fee3e98f --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Defs.lean @@ -0,0 +1,146 @@ +/- +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.Module.Submodule.Basic +import Mathlib.Tactic.Abel + +/-! + +# Ideals over a ring + +This file defines `Ideal R`, the type of (left) ideals over a ring `R`. +Note that over commutative rings, left ideals and two-sided ideals are equivalent. + +## Implementation notes + +`Ideal R` is implemented using `Submodule R R`, where `•` is interpreted as `*`. + +## TODO + +Support right ideals, and two-sided ideals over non-commutative rings. +-/ + + +universe u v w + +variable {α : Type u} {β : Type v} {F : Type w} + +open Set Function + +open Pointwise + +/-- A (left) ideal in a semiring `R` is an additive submonoid `s` such that +`a * b ∈ s` whenever `b ∈ s`. If `R` is a ring, then `s` is an additive subgroup. -/ +abbrev Ideal (R : Type u) [Semiring R] := + Submodule R R + +section Semiring + +namespace Ideal + +variable [Semiring α] (I : Ideal α) {a b : α} + +protected theorem zero_mem : (0 : α) ∈ I := + Submodule.zero_mem I + +protected theorem add_mem : a ∈ I → b ∈ I → a + b ∈ I := + Submodule.add_mem I + +variable (a) + +theorem mul_mem_left : b ∈ I → a * b ∈ I := + Submodule.smul_mem I a + +variable {a} + +@[ext] +theorem ext {I J : Ideal α} (h : ∀ x, x ∈ I ↔ x ∈ J) : I = J := + Submodule.ext h + +theorem sum_mem (I : Ideal α) {ι : Type*} {t : Finset ι} {f : ι → α} : + (∀ c ∈ t, f c ∈ I) → (∑ i ∈ t, f i) ∈ I := + Submodule.sum_mem I + +@[simp] +theorem unit_mul_mem_iff_mem {x y : α} (hy : IsUnit y) : y * x ∈ I ↔ x ∈ I := by + refine ⟨fun h => ?_, fun h => I.mul_mem_left y h⟩ + obtain ⟨y', hy'⟩ := hy.exists_left_inv + have := I.mul_mem_left y' h + rwa [← mul_assoc, hy', one_mul] at this + +end Ideal + +end Semiring + +section CommSemiring + +variable {a b : α} + +-- A separate namespace definition is needed because the variables were historically in a different +-- order. +namespace Ideal + +variable [CommSemiring α] (I : Ideal α) + +@[simp] +theorem mul_unit_mem_iff_mem {x y : α} (hy : IsUnit y) : x * y ∈ I ↔ x ∈ I := + mul_comm y x ▸ unit_mul_mem_iff_mem I hy + +variable (b) + +theorem mul_mem_right (h : a ∈ I) : a * b ∈ I := + mul_comm b a ▸ I.mul_mem_left b h + +variable {b} + +lemma mem_of_dvd (hab : a ∣ b) (ha : a ∈ I) : b ∈ I := by + obtain ⟨c, rfl⟩ := hab; exact I.mul_mem_right _ ha + +theorem pow_mem_of_mem (ha : a ∈ I) (n : ℕ) (hn : 0 < n) : a ^ n ∈ I := + Nat.casesOn n (Not.elim (by decide)) + (fun m _hm => (pow_succ a m).symm ▸ I.mul_mem_left (a ^ m) ha) hn + +theorem pow_mem_of_pow_mem {m n : ℕ} (ha : a ^ m ∈ I) (h : m ≤ n) : a ^ n ∈ I := by + rw [← Nat.add_sub_of_le h, pow_add] + exact I.mul_mem_right _ ha + +end Ideal + +end CommSemiring + +section Ring + +namespace Ideal + +variable [Ring α] (I : Ideal α) {a b : α} + +protected theorem neg_mem_iff : -a ∈ I ↔ a ∈ I := + Submodule.neg_mem_iff I + +protected theorem add_mem_iff_left : b ∈ I → (a + b ∈ I ↔ a ∈ I) := + Submodule.add_mem_iff_left I + +protected theorem add_mem_iff_right : a ∈ I → (a + b ∈ I ↔ b ∈ I) := + Submodule.add_mem_iff_right I + +protected theorem sub_mem : a ∈ I → b ∈ I → a - b ∈ I := + Submodule.sub_mem I + +end Ideal + +end Ring + +section CommRing + +namespace Ideal + +theorem mul_sub_mul_mem {R : Type*} [CommRing R] (I : Ideal R) {a b c d : R} (h1 : a - b ∈ I) + (h2 : c - d ∈ I) : a * c - b * d ∈ I := by + rw [show a * c - b * d = (a - b) * c + b * (c - d) by rw [sub_mul, mul_sub]; abel] + exact I.add_mem (I.mul_mem_right _ h1) (I.mul_mem_left _ h2) + +end Ideal + +end CommRing diff --git a/Mathlib/RingTheory/Ideal/IsPrimary.lean b/Mathlib/RingTheory/Ideal/IsPrimary.lean index ab59abec6b816..69e4e7426b5ce 100644 --- a/Mathlib/RingTheory/Ideal/IsPrimary.lean +++ b/Mathlib/RingTheory/Ideal/IsPrimary.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2019 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kenny Lau +Authors: Kenny Lau, Yakov Pechersky -/ +import Mathlib.RingTheory.IsPrimary import Mathlib.RingTheory.Ideal.Operations /-! @@ -14,36 +15,70 @@ A proper ideal `I` is primary iff `xy ∈ I` implies `x ∈ I` or `y ∈ radical - `Ideal.IsPrimary` +## Implementation details + +Uses a specialized phrasing of `Submodule.IsPrimary` to have better API-piercing usage. + -/ namespace Ideal variable {R : Type*} [CommSemiring R] +/-- A proper ideal `I` is primary as a submodule. -/ +abbrev IsPrimary (I : Ideal R) : Prop := + Submodule.IsPrimary I + /-- A proper ideal `I` is primary iff `xy ∈ I` implies `x ∈ I` or `y ∈ radical I`. -/ -def IsPrimary (I : Ideal R) : Prop := - I ≠ ⊤ ∧ ∀ {x y : R}, x * y ∈ I → x ∈ I ∨ y ∈ radical I +lemma isPrimary_iff {I : Ideal R} : + I.IsPrimary ↔ I ≠ ⊤ ∧ ∀ {x y : R}, x * y ∈ I → x ∈ I ∨ y ∈ radical I := by + rw [IsPrimary, Submodule.IsPrimary, forall_comm] + simp only [mul_comm, mem_radical_iff, and_congr_right_iff, + ← Submodule.ideal_span_singleton_smul, smul_eq_mul, mul_top, span_singleton_le_iff_mem] -theorem IsPrime.isPrimary {I : Ideal R} (hi : IsPrime I) : IsPrimary I := +theorem IsPrime.isPrimary {I : Ideal R} (hi : IsPrime I) : I.IsPrimary := + isPrimary_iff.mpr ⟨hi.1, fun {_ _} hxy => (hi.mem_or_mem hxy).imp id fun hyi => le_radical hyi⟩ -theorem isPrime_radical {I : Ideal R} (hi : IsPrimary I) : IsPrime (radical I) := +theorem isPrime_radical {I : Ideal R} (hi : I.IsPrimary) : IsPrime (radical I) := ⟨mt radical_eq_top.1 hi.1, fun {x y} ⟨m, hxy⟩ => by - rw [mul_pow] at hxy; cases' hi.2 hxy with h h + rw [mul_pow] at hxy; cases' (isPrimary_iff.mp hi).2 hxy with h h · exact Or.inl ⟨m, h⟩ · exact Or.inr (mem_radical_of_pow_mem h)⟩ -theorem isPrimary_inf {I J : Ideal R} (hi : IsPrimary I) (hj : IsPrimary J) - (hij : radical I = radical J) : IsPrimary (I ⊓ J) := +theorem isPrimary_inf {I J : Ideal R} (hi : I.IsPrimary) (hj : J.IsPrimary) + (hij : radical I = radical J) : (I ⊓ J).IsPrimary := + isPrimary_iff.mpr ⟨ne_of_lt <| lt_of_le_of_lt inf_le_left (lt_top_iff_ne_top.2 hi.1), fun {x y} ⟨hxyi, hxyj⟩ => by rw [radical_inf, hij, inf_idem] - cases' hi.2 hxyi with hxi hyi - · cases' hj.2 hxyj with hxj hyj + cases' (isPrimary_iff.mp hi).2 hxyi with hxi hyi + · cases' (isPrimary_iff.mp hj).2 hxyj with hxj hyj · exact Or.inl ⟨hxi, hxj⟩ · exact Or.inr hyj · rw [hij] at hyi exact Or.inr hyi⟩ +open Finset in +lemma isPrimary_finset_inf {ι} {s : Finset ι} {f : ι → Ideal R} {i : ι} (hi : i ∈ s) + (hs : ∀ ⦃y⦄, y ∈ s → (f y).IsPrimary) + (hs' : ∀ ⦃y⦄, y ∈ s → (f y).radical = (f i).radical) : + IsPrimary (s.inf f) := by + classical + induction s using Finset.induction_on generalizing i with + | empty => simp at hi + | @insert a s ha IH => + rcases s.eq_empty_or_nonempty with rfl|⟨y, hy⟩ + · simp only [insert_emptyc_eq, mem_singleton] at hi + simpa [hi] using hs + simp only [inf_insert] + have H : ∀ ⦃x : ι⦄, x ∈ s → (f x).radical = (f y).radical := by + intro x hx + rw [hs' (mem_insert_of_mem hx), hs' (mem_insert_of_mem hy)] + refine isPrimary_inf (hs (by simp)) (IH hy ?_ H) ?_ + · intro x hx + exact hs (by simp [hx]) + · rw [radical_finset_inf hy H, hs' (mem_insert_self _ _), hs' (mem_insert_of_mem hy)] + end Ideal diff --git a/Mathlib/RingTheory/Ideal/IsPrincipalPowQuotient.lean b/Mathlib/RingTheory/Ideal/IsPrincipalPowQuotient.lean new file mode 100644 index 0000000000000..90482f9f393cd --- /dev/null +++ b/Mathlib/RingTheory/Ideal/IsPrincipalPowQuotient.lean @@ -0,0 +1,86 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.LinearAlgebra.Isomorphisms +import Mathlib.RingTheory.Ideal.Operations +import Mathlib.RingTheory.Ideal.Quotient.Defs + +/-! +# Quotients of powers of principal ideals + +This file deals with taking quotients of powers of principal ideals. + +## Main definitions and results + +* `Ideal.quotEquivPowQuotPowSucc`: for a principal ideal `I`, `R ⧸ I ≃ₗ[R] I ^ n ⧸ I ^ (n + 1)` + +## Implementation details + +At site of usage, calling `LinearEquiv.toEquiv` can cause timeouts in the search for a complex +synthesis like `Module 𝒪[K] 𝓀[k]`, so the plain equiv versions are provided. + +These equivs are defined here as opposed to in the quotients file since they cannot be +formed as ring equivs. + +-/ + + +namespace Ideal + +section IsPrincipal + +variable {R : Type*} [CommRing R] [IsDomain R] {I : Ideal R} + +/-- For a principal ideal `I`, `R ⧸ I ≃ₗ[R] I ^ n ⧸ I ^ (n + 1)`. To convert into a form +that uses the ideal of `R ⧸ I ^ (n + 1)`, compose with +`Ideal.powQuotPowSuccLinearEquivMapMkPowSuccPow`. -/ +noncomputable +def quotEquivPowQuotPowSucc (h : I.IsPrincipal) (h': I ≠ ⊥) (n : ℕ) : + (R ⧸ I) ≃ₗ[R] (I ^ n : Ideal R) ⧸ (I • ⊤ : Submodule R (I ^ n : Ideal R)) := by + let f : (I ^ n : Ideal R) →ₗ[R] (I ^ n : Ideal R) ⧸ (I • ⊤ : Submodule R (I ^ n : Ideal R)) := + Submodule.mkQ _ + let ϖ := h.principal'.choose + have hI : I = Ideal.span {ϖ} := h.principal'.choose_spec + have hϖ : ϖ ^ n ∈ I ^ n := hI ▸ (Ideal.pow_mem_pow (Ideal.mem_span_singleton_self _) n) + let g : R →ₗ[R] (I ^ n : Ideal R) := (LinearMap.mulRight R ϖ^n).codRestrict _ fun x ↦ by + simp only [LinearMap.pow_mulRight, LinearMap.mulRight_apply, Ideal.submodule_span_eq] + -- TODO: change argument of Ideal.pow_mem_of_mem + exact Ideal.mul_mem_left _ _ hϖ + have : I = LinearMap.ker (f.comp g) := by + ext x + simp only [LinearMap.codRestrict, LinearMap.pow_mulRight, LinearMap.mulRight_apply, + LinearMap.mem_ker, LinearMap.coe_comp, LinearMap.coe_mk, AddHom.coe_mk, Function.comp_apply, + Submodule.mkQ_apply, Submodule.Quotient.mk_eq_zero, Submodule.mem_smul_top_iff, smul_eq_mul, + f, g] + constructor <;> intro hx + · exact Submodule.mul_mem_mul hx hϖ + · rw [← pow_succ', hI, Ideal.span_singleton_pow, Ideal.mem_span_singleton] at hx + obtain ⟨y, hy⟩ := hx + rw [mul_comm, pow_succ, mul_assoc, mul_right_inj' (pow_ne_zero _ _)] at hy + · rw [hI, Ideal.mem_span_singleton] + exact ⟨y, hy⟩ + · contrapose! h' + rw [hI, h', Ideal.span_singleton_eq_bot] + let e : (R ⧸ I) ≃ₗ[R] R ⧸ (LinearMap.ker (f.comp g)) := + Submodule.quotEquivOfEq I (LinearMap.ker (f ∘ₗ g)) this + refine e.trans ((f.comp g).quotKerEquivOfSurjective ?_) + refine (Submodule.mkQ_surjective _).comp ?_ + rintro ⟨x, hx⟩ + rw [hI, Ideal.span_singleton_pow, Ideal.mem_span_singleton] at hx + refine hx.imp ?_ + simp [g, LinearMap.codRestrict, eq_comm, mul_comm] + +/-- For a principal ideal `I`, `R ⧸ I ≃ I ^ n ⧸ I ^ (n + 1)`. Supplied as a plain equiv to bypass +typeclass synthesis issues on complex `Module` goals. To convert into a form +that uses the ideal of `R ⧸ I ^ (n + 1)`, compose with +`Ideal.powQuotPowSuccEquivMapMkPowSuccPow`. -/ +noncomputable +def quotEquivPowQuotPowSuccEquiv (h : I.IsPrincipal) (h': I ≠ ⊥) (n : ℕ) : + (R ⧸ I) ≃ (I ^ n : Ideal R) ⧸ (I • ⊤ : Submodule R (I ^ n : Ideal R)) := + quotEquivPowQuotPowSucc h h' n + +end IsPrincipal + +end Ideal diff --git a/Mathlib/RingTheory/Ideal/Lattice.lean b/Mathlib/RingTheory/Ideal/Lattice.lean new file mode 100644 index 0000000000000..1be75b0570396 --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Lattice.lean @@ -0,0 +1,110 @@ +/- +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.Module.Submodule.Lattice +import Mathlib.RingTheory.Ideal.Defs +import Mathlib.Tactic.Ring + +/-! +# The lattice of ideals in a ring + +Some basic results on lattice operations on ideals: `⊥`, `⊤`, `⊔`, `⊓`. + +## TODO + +Support right ideals, and two-sided ideals over non-commutative rings. +-/ + + +universe u v w + +variable {α : Type u} {β : Type v} {F : Type w} + +open Set Function + +open Pointwise + +section Semiring + +namespace Ideal + +variable [Semiring α] (I : Ideal α) {a b : α} + +theorem eq_top_of_unit_mem (x y : α) (hx : x ∈ I) (h : y * x = 1) : I = ⊤ := + eq_top_iff.2 fun z _ => + calc + z * y * x ∈ I := I.mul_mem_left _ hx + _ = z * (y * x) := mul_assoc z y x + _ = z := by rw [h, mul_one] + +theorem eq_top_of_isUnit_mem {x} (hx : x ∈ I) (h : IsUnit x) : I = ⊤ := + let ⟨y, hy⟩ := h.exists_left_inv + eq_top_of_unit_mem I x y hx hy + +theorem eq_top_iff_one : I = ⊤ ↔ (1 : α) ∈ I := + ⟨by rintro rfl; trivial, fun h => eq_top_of_unit_mem _ _ 1 h (by simp)⟩ + +theorem ne_top_iff_one : I ≠ ⊤ ↔ (1 : α) ∉ I := + not_congr I.eq_top_iff_one + +section Lattice + +variable {R : Type u} [Semiring R] + +-- Porting note: is this the right approach? or is there a better way to prove? (next 4 decls) +theorem mem_sup_left {S T : Ideal R} : ∀ {x : R}, x ∈ S → x ∈ S ⊔ T := + @le_sup_left _ _ S T + +theorem mem_sup_right {S T : Ideal R} : ∀ {x : R}, x ∈ T → x ∈ S ⊔ T := + @le_sup_right _ _ S T + +theorem mem_iSup_of_mem {ι : Sort*} {S : ι → Ideal R} (i : ι) : ∀ {x : R}, x ∈ S i → x ∈ iSup S := + @le_iSup _ _ _ S _ + +theorem mem_sSup_of_mem {S : Set (Ideal R)} {s : Ideal R} (hs : s ∈ S) : + ∀ {x : R}, x ∈ s → x ∈ sSup S := + @le_sSup _ _ _ _ hs + +theorem mem_sInf {s : Set (Ideal R)} {x : R} : x ∈ sInf s ↔ ∀ ⦃I⦄, I ∈ s → x ∈ I := + ⟨fun hx I his => hx I ⟨I, iInf_pos his⟩, fun H _I ⟨_J, hij⟩ => hij ▸ fun _S ⟨hj, hS⟩ => hS ▸ H hj⟩ + +@[simp 1001] -- Porting note: increased priority to appease `simpNF` +theorem mem_inf {I J : Ideal R} {x : R} : x ∈ I ⊓ J ↔ x ∈ I ∧ x ∈ J := + Iff.rfl + +@[simp 1001] -- Porting note: increased priority to appease `simpNF` +theorem mem_iInf {ι : Sort*} {I : ι → Ideal R} {x : R} : x ∈ iInf I ↔ ∀ i, x ∈ I i := + Submodule.mem_iInf _ + +@[simp 1001] -- Porting note: increased priority to appease `simpNF` +theorem mem_bot {x : R} : x ∈ (⊥ : Ideal R) ↔ x = 0 := + Submodule.mem_bot _ + +end Lattice + +end Ideal + +end Semiring + +section DivisionSemiring + +variable {K : Type u} [DivisionSemiring K] (I : Ideal K) + +namespace Ideal + +/-- All ideals in a division (semi)ring are trivial. -/ +theorem eq_bot_or_top : I = ⊥ ∨ I = ⊤ := by + rw [or_iff_not_imp_right] + change _ ≠ _ → _ + rw [Ideal.ne_top_iff_one] + intro h1 + rw [eq_bot_iff] + intro r hr + by_cases H : r = 0; · simpa + simpa [H, h1] using I.mul_mem_left r⁻¹ hr + +end Ideal + +end DivisionSemiring diff --git a/Mathlib/RingTheory/Ideal/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index 5a46dd702e132..03586e143f746 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -7,6 +7,9 @@ import Mathlib.RingTheory.Ideal.Operations /-! # Maps on modules and ideals + +Main definitions include `Ideal.map`, `Ideal.comap`, `RingHom.ker`, `Module.annihilator` +and `Submodule.annihilator`. -/ assert_not_exists Basis -- See `RingTheory.Ideal.Basis` @@ -48,6 +51,8 @@ def comap [RingHomClass F R S] (I : Ideal S) : Ideal R where @[simp] theorem coe_comap [RingHomClass F R S] (I : Ideal S) : (comap f I : Set R) = f ⁻¹' I := rfl +lemma comap_coe [RingHomClass F R S] (I : Ideal S) : I.comap (f : R →+* S) = I.comap f := rfl + variable {f} theorem map_mono (h : I ≤ J) : map f I ≤ map f J := @@ -209,8 +214,9 @@ theorem comap_sInf (s : Set (Ideal S)) : (sInf s).comap f = ⨅ I ∈ s, (I : Id theorem comap_sInf' (s : Set (Ideal S)) : (sInf s).comap f = ⨅ I ∈ comap f '' s, I := _root_.trans (comap_sInf f s) (by rw [iInf_image]) +/-- Variant of `Ideal.IsPrime.comap` where ideal is explicit rather than implicit. -/ theorem comap_isPrime [H : IsPrime K] : IsPrime (comap f K) := - ⟨comap_ne_top f H.ne_top, fun {x y} h => H.mem_or_mem <| by rwa [mem_comap, map_mul] at h⟩ + H.comap f variable {I J K L} @@ -294,10 +300,10 @@ theorem map_iInf_comap_of_surjective (K : ι → Ideal S) : (⨅ i, (K i).comap (giMapComap f hf).l_iInf_u _ theorem mem_image_of_mem_map_of_surjective {I : Ideal R} {y} (H : y ∈ map f I) : y ∈ f '' I := - Submodule.span_induction H (fun _ => id) ⟨0, I.zero_mem, map_zero f⟩ - (fun _ _ ⟨x1, hx1i, hxy1⟩ ⟨x2, hx2i, hxy2⟩ => + Submodule.span_induction (hx := H) (fun _ => id) ⟨0, I.zero_mem, map_zero f⟩ + (fun _ _ _ _ ⟨x1, hx1i, hxy1⟩ ⟨x2, hx2i, hxy2⟩ => ⟨x1 + x2, I.add_mem hx1i hx2i, hxy1 ▸ hxy2 ▸ map_add f _ _⟩) - fun c _ ⟨x, hxi, hxy⟩ => + fun c _ _ ⟨x, hxi, hxy⟩ => let ⟨d, hdc⟩ := hf c ⟨d * x, I.mul_mem_left _ hxi, hdc ▸ hxy ▸ map_mul f _ _⟩ @@ -330,7 +336,7 @@ end Injective /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `map f.symm (map f I) = I`. -/ @[simp] -theorem map_of_equiv (I : Ideal R) (f : R ≃+* S) : +theorem map_of_equiv {I : Ideal R} (f : R ≃+* S) : (I.map (f : R →+* S)).map (f.symm : S →+* R) = I := by rw [← RingEquiv.toRingHom_eq_coe, ← RingEquiv.toRingHom_eq_coe, map_map, RingEquiv.toRingHom_eq_coe, RingEquiv.toRingHom_eq_coe, RingEquiv.symm_comp, map_id] @@ -338,27 +344,34 @@ theorem map_of_equiv (I : Ideal R) (f : R ≃+* S) : /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `comap f (comap f.symm I) = I`. -/ @[simp] -theorem comap_of_equiv (I : Ideal R) (f : R ≃+* S) : +theorem comap_of_equiv {I : Ideal R} (f : R ≃+* S) : (I.comap (f.symm : S →+* R)).comap (f : R →+* S) = I := by rw [← RingEquiv.toRingHom_eq_coe, ← RingEquiv.toRingHom_eq_coe, comap_comap, RingEquiv.toRingHom_eq_coe, RingEquiv.toRingHom_eq_coe, RingEquiv.symm_comp, comap_id] /-- 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 := +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' _)) /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `comap f.symm I = map f I`. -/ @[simp] -theorem comap_symm (I : Ideal R) (f : R ≃+* S) : I.comap f.symm = I.map f := - (map_comap_of_equiv I f).symm +theorem comap_symm {I : Ideal R} (f : R ≃+* S) : I.comap f.symm = I.map f := + (map_comap_of_equiv f).symm /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `map f.symm I = comap f I`. -/ @[simp] -theorem map_symm (I : Ideal S) (f : R ≃+* S) : I.map f.symm = I.comap f := - map_comap_of_equiv I (RingEquiv.symm f) - - +theorem map_symm {I : Ideal S} (f : R ≃+* S) : I.map f.symm = I.comap f := + map_comap_of_equiv (RingEquiv.symm f) + +theorem mem_map_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e : E) + {I : Ideal R} (y : S) : y ∈ map e I ↔ ∃ x ∈ I, e x = y := by + constructor + · intro h + simp_rw [show map e I = _ from map_comap_of_equiv (e : R ≃+* S)] at h + exact ⟨(e : R ≃+* S).symm y, h, (e : R ≃+* S).apply_symm_apply y⟩ + · rintro ⟨x, hx, rfl⟩ + exact mem_map_of_mem e hx end Semiring @@ -421,6 +434,11 @@ theorem comap_isMaximal_of_surjective (hf : Function.Surjective f) {K : Ideal S} rw [comap_map_of_surjective _ hf, sup_eq_left] exact le_trans (comap_mono bot_le) (le_of_lt hJ) +/-- The pullback of a maximal ideal under a ring isomorphism is a maximal ideal. -/ +instance comap_isMaximal_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e : E) + {p : Ideal S} [p.IsMaximal] : (comap e p).IsMaximal := + comap_isMaximal_of_surjective e (EquivLike.surjective e) + theorem comap_le_comap_iff_of_surjective (hf : Function.Surjective f) (I J : Ideal S) : comap f I ≤ comap f J ↔ I ≤ J := ⟨fun h => (map_comap_of_surjective f hf I).symm.le.trans (map_le_of_le_comap h), fun h => @@ -459,6 +477,11 @@ theorem map.isMaximal (hf : Function.Bijective f) {I : Ideal R} (H : IsMaximal I _ = 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) : @@ -483,8 +506,8 @@ theorem map_mul : map f (I * J) = map f I * map f J := show (f (r * s)) ∈ map f I * map f J by rw [_root_.map_mul]; exact mul_mem_mul (mem_map_of_mem f hri) (mem_map_of_mem f hsj)) (span_mul_span (↑f '' ↑I) (↑f '' ↑J) ▸ (span_le.2 <| - Set.iUnion₂_subset fun i ⟨r, hri, hfri⟩ => - Set.iUnion₂_subset fun j ⟨s, hsj, hfsj⟩ => + Set.iUnion₂_subset fun _ ⟨r, hri, hfri⟩ => + Set.iUnion₂_subset fun _ ⟨s, hsj, hfsj⟩ => Set.singleton_subset_iff.2 <| hfri ▸ hfsj ▸ by rw [← _root_.map_mul]; exact mem_map_of_mem f (mul_mem_mul hri hsj))) @@ -570,7 +593,7 @@ theorem ker_ne_top [Nontrivial S] (f : F) : ker f ≠ ⊤ := lemma _root_.Pi.ker_ringHom {ι : Type*} {R : ι → Type*} [∀ i, Semiring (R i)] (φ : ∀ i, S →+* R i) : ker (Pi.ringHom φ) = ⨅ i, ker (φ i) := by ext x - simp [mem_ker, Ideal.mem_iInf, Function.funext_iff] + simp [mem_ker, Ideal.mem_iInf, funext_iff] @[simp] theorem ker_rangeSRestrict (f : R →+* S) : ker f.rangeSRestrict = ker f := @@ -637,6 +660,112 @@ theorem ker_isMaximal_of_surjective {R K F : Type*} [Ring R] [Field K] end RingHom +section annihilator + +section Semiring + +variable {R M M' : Type*} +variable [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid M'] [Module R M'] + +variable (R M) in +/-- `Module.annihilator R M` is the ideal of all elements `r : R` such that `r • M = 0`. -/ +def Module.annihilator : Ideal R := RingHom.ker (Module.toAddMonoidEnd R M) + +theorem Module.mem_annihilator {r} : r ∈ Module.annihilator R M ↔ ∀ m : M, r • m = 0 := + ⟨fun h ↦ (congr($h ·)), (AddMonoidHom.ext ·)⟩ + +theorem LinearMap.annihilator_le_of_injective (f : M →ₗ[R] M') (hf : Function.Injective f) : + Module.annihilator R M' ≤ Module.annihilator R M := fun x h ↦ by + rw [Module.mem_annihilator] at h ⊢; exact fun m ↦ hf (by rw [map_smul, h, f.map_zero]) + +theorem LinearMap.annihilator_le_of_surjective (f : M →ₗ[R] M') + (hf : Function.Surjective f) : Module.annihilator R M ≤ Module.annihilator R M' := fun x h ↦ by + rw [Module.mem_annihilator] at h ⊢ + intro m; obtain ⟨m, rfl⟩ := hf m + rw [← map_smul, h, f.map_zero] + +theorem LinearEquiv.annihilator_eq (e : M ≃ₗ[R] M') : + Module.annihilator R M = Module.annihilator R M' := + (e.annihilator_le_of_surjective e.surjective).antisymm (e.annihilator_le_of_injective e.injective) + +namespace Submodule + +/-- `N.annihilator` is the ideal of all elements `r : R` such that `r • N = 0`. -/ +abbrev annihilator (N : Submodule R M) : Ideal R := + Module.annihilator R N + +theorem annihilator_top : (⊤ : Submodule R M).annihilator = Module.annihilator R M := + topEquiv.annihilator_eq + +variable {I J : Ideal R} {N P : Submodule R M} + +theorem mem_annihilator {r} : r ∈ N.annihilator ↔ ∀ n ∈ N, r • n = (0 : M) := by + simp_rw [annihilator, Module.mem_annihilator, Subtype.forall, Subtype.ext_iff]; rfl + +theorem annihilator_bot : (⊥ : Submodule R M).annihilator = ⊤ := + top_le_iff.mp fun _ _ ↦ mem_annihilator.mpr fun _ ↦ by rintro rfl; rw [smul_zero] + +theorem annihilator_eq_top_iff : N.annihilator = ⊤ ↔ N = ⊥ := + ⟨fun H ↦ + eq_bot_iff.2 fun (n : M) hn => + (mem_bot R).2 <| one_smul R n ▸ mem_annihilator.1 ((Ideal.eq_top_iff_one _).1 H) n hn, + fun H ↦ H.symm ▸ annihilator_bot⟩ + +theorem annihilator_mono (h : N ≤ P) : P.annihilator ≤ N.annihilator := fun _ hrp => + mem_annihilator.2 fun n hn => mem_annihilator.1 hrp n <| h hn + +theorem annihilator_iSup (ι : Sort w) (f : ι → Submodule R M) : + annihilator (⨆ i, f i) = ⨅ i, annihilator (f i) := + le_antisymm (le_iInf fun _ => annihilator_mono <| le_iSup _ _) fun r H => + mem_annihilator.2 fun n hn ↦ iSup_induction f (C := (r • · = 0)) hn + (fun i ↦ mem_annihilator.1 <| (mem_iInf _).mp H i) (smul_zero _) + fun m₁ m₂ h₁ h₂ ↦ by simp_rw [smul_add, h₁, h₂, add_zero] + +end Submodule + +end Semiring + +namespace Submodule + +variable {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] {N : Submodule R M} + +theorem mem_annihilator' {r} : r ∈ N.annihilator ↔ N ≤ comap (r • (LinearMap.id : M →ₗ[R] M)) ⊥ := + mem_annihilator.trans ⟨fun H n hn => (mem_bot R).2 <| H n hn, fun H _ hn => (mem_bot R).1 <| H hn⟩ + +theorem mem_annihilator_span (s : Set M) (r : R) : + r ∈ (Submodule.span R s).annihilator ↔ ∀ n : s, r • (n : M) = 0 := by + rw [Submodule.mem_annihilator] + constructor + · intro h n + exact h _ (Submodule.subset_span n.prop) + · intro h n hn + refine Submodule.span_induction ?_ ?_ ?_ ?_ hn + · intro x hx + exact h ⟨x, hx⟩ + · exact smul_zero _ + · intro x y _ _ hx hy + rw [smul_add, hx, hy, zero_add] + · intro a x _ hx + rw [smul_comm, hx, smul_zero] + +theorem mem_annihilator_span_singleton (g : M) (r : R) : + r ∈ (Submodule.span R ({g} : Set M)).annihilator ↔ r • g = 0 := by simp [mem_annihilator_span] + +@[simp] +theorem annihilator_smul (N : Submodule R M) : annihilator N • N = ⊥ := + eq_bot_iff.2 (smul_le.2 fun _ => mem_annihilator.1) + +@[simp] +theorem annihilator_mul (I : Ideal R) : annihilator I * I = ⊥ := + annihilator_smul I + +@[simp] +theorem mul_annihilator (I : Ideal R) : I * annihilator I = ⊥ := by rw [mul_comm, annihilator_mul] + +end Submodule + +end annihilator + namespace Ideal variable {R : Type*} {S : Type*} {F : Type*} @@ -651,10 +780,11 @@ theorem map_eq_bot_iff_le_ker {I : Ideal R} (f : F) : I.map f = ⊥ ↔ I ≤ Ri theorem ker_le_comap {K : Ideal S} (f : F) : RingHom.ker f ≤ comap f K := fun _ hx => mem_comap.2 (RingHom.mem_ker.1 hx ▸ K.zero_mem) -theorem map_isPrime_of_equiv {F' : Type*} [EquivLike F' R S] [RingEquivClass F' R S] +/-- A ring isomorphism sends a prime ideal to a prime ideal. -/ +instance map_isPrime_of_equiv {F' : Type*} [EquivLike F' R S] [RingEquivClass F' R S] (f : F') {I : Ideal R} [IsPrime I] : IsPrime (map f I) := by have h : I.map f = I.map ((f : R ≃+* S) : R →+* S) := rfl - rw [h, map_comap_of_equiv I (f : R ≃+* S)] + rw [h, map_comap_of_equiv (f : R ≃+* S)] exact Ideal.IsPrime.comap (RingEquiv.symm (f : R ≃+* S)) end Semiring @@ -846,3 +976,19 @@ def idealMap (I : Ideal R) : I →ₗ[R] I.map (algebraMap R S) := (fun _ ↦ Ideal.mem_map_of_mem _) end Algebra + +namespace NoZeroSMulDivisors + +theorem of_ker_algebraMap_eq_bot (R A : Type*) [CommRing R] [Semiring A] [Algebra R A] + [NoZeroDivisors A] (h : RingHom.ker (algebraMap R A) = ⊥) : NoZeroSMulDivisors R A := + of_algebraMap_injective ((RingHom.injective_iff_ker_eq_bot _).mpr h) + +theorem ker_algebraMap_eq_bot (R A : Type*) [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] + [NoZeroSMulDivisors R A] : RingHom.ker (algebraMap R A) = ⊥ := + (RingHom.injective_iff_ker_eq_bot _).mp (algebraMap_injective R A) + +theorem iff_ker_algebraMap_eq_bot {R A : Type*} [CommRing R] [Ring A] [IsDomain A] [Algebra R A] : + NoZeroSMulDivisors R A ↔ RingHom.ker (algebraMap R A) = ⊥ := + iff_algebraMap_injective.trans (RingHom.injective_iff_ker_eq_bot (algebraMap R A)) + +end NoZeroSMulDivisors diff --git a/Mathlib/RingTheory/Ideal/Maximal.lean b/Mathlib/RingTheory/Ideal/Maximal.lean new file mode 100644 index 0000000000000..591bb5e34a064 --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Maximal.lean @@ -0,0 +1,210 @@ +/- +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.Ideal.Prime +import Mathlib.RingTheory.Ideal.Span + +/-! + +# Ideals over a ring + +This file contains an assortment of definitions and results for `Ideal R`, +the type of (left) ideals over a ring `R`. +Note that over commutative rings, left ideals and two-sided ideals are equivalent. + +## Implementation notes + +`Ideal R` is implemented using `Submodule R R`, where `•` is interpreted as `*`. + +## TODO + +Support right ideals, and two-sided ideals over non-commutative rings. +-/ + + +universe u v w + +variable {α : Type u} {β : Type v} {F : Type w} + +open Set Function + +open Pointwise + +section Semiring + +namespace Ideal + +variable [Semiring α] (I : Ideal α) {a b : α} + +/-- An ideal is maximal if it is maximal in the collection of proper ideals. -/ +class IsMaximal (I : Ideal α) : Prop where + /-- The maximal ideal is a coatom in the ordering on ideals; that is, it is not the entire ring, + and there are no other proper ideals strictly containing it. -/ + out : IsCoatom I + +theorem isMaximal_def {I : Ideal α} : I.IsMaximal ↔ IsCoatom I := + ⟨fun h => h.1, fun h => ⟨h⟩⟩ + +theorem IsMaximal.ne_top {I : Ideal α} (h : I.IsMaximal) : I ≠ ⊤ := + (isMaximal_def.1 h).1 + +theorem isMaximal_iff {I : Ideal α} : + I.IsMaximal ↔ (1 : α) ∉ I ∧ ∀ (J : Ideal α) (x), I ≤ J → x ∉ I → x ∈ J → (1 : α) ∈ J := + isMaximal_def.trans <| + and_congr I.ne_top_iff_one <| + forall_congr' fun J => by + rw [lt_iff_le_not_le] + exact + ⟨fun H x h hx₁ hx₂ => J.eq_top_iff_one.1 <| H ⟨h, not_subset.2 ⟨_, hx₂, hx₁⟩⟩, + fun H ⟨h₁, h₂⟩ => + let ⟨x, xJ, xI⟩ := not_subset.1 h₂ + J.eq_top_iff_one.2 <| H x h₁ xI xJ⟩ + +theorem IsMaximal.eq_of_le {I J : Ideal α} (hI : I.IsMaximal) (hJ : J ≠ ⊤) (IJ : I ≤ J) : I = J := + eq_iff_le_not_lt.2 ⟨IJ, fun h => hJ (hI.1.2 _ h)⟩ + +instance : IsCoatomic (Ideal α) := by + apply CompleteLattice.coatomic_of_top_compact + rw [← span_singleton_one] + exact Submodule.singleton_span_isCompactElement 1 + +theorem IsMaximal.coprime_of_ne {M M' : Ideal α} (hM : M.IsMaximal) (hM' : M'.IsMaximal) + (hne : M ≠ M') : M ⊔ M' = ⊤ := by + contrapose! hne with h + exact hM.eq_of_le hM'.ne_top (le_sup_left.trans_eq (hM'.eq_of_le h le_sup_right).symm) + +/-- **Krull's theorem**: if `I` is an ideal that is not the whole ring, then it is included in some + maximal ideal. -/ +theorem exists_le_maximal (I : Ideal α) (hI : I ≠ ⊤) : ∃ M : Ideal α, M.IsMaximal ∧ I ≤ M := + let ⟨m, hm⟩ := (eq_top_or_exists_le_coatom I).resolve_left hI + ⟨m, ⟨⟨hm.1⟩, hm.2⟩⟩ + +variable (α) + +/-- Krull's theorem: a nontrivial ring has a maximal ideal. -/ +theorem exists_maximal [Nontrivial α] : ∃ M : Ideal α, M.IsMaximal := + let ⟨I, ⟨hI, _⟩⟩ := exists_le_maximal (⊥ : Ideal α) bot_ne_top + ⟨I, hI⟩ + +variable {α} + +instance [Nontrivial α] : Nontrivial (Ideal α) := by + rcases@exists_maximal α _ _ with ⟨M, hM, _⟩ + exact nontrivial_of_ne M ⊤ hM + +/-- If P is not properly contained in any maximal ideal then it is not properly contained + in any proper ideal -/ +theorem maximal_of_no_maximal {P : Ideal α} + (hmax : ∀ m : Ideal α, P < m → ¬IsMaximal m) (J : Ideal α) (hPJ : P < J) : J = ⊤ := by + by_contra hnonmax + rcases exists_le_maximal J hnonmax with ⟨M, hM1, hM2⟩ + exact hmax M (lt_of_lt_of_le hPJ hM2) hM1 + +theorem IsMaximal.exists_inv {I : Ideal α} (hI : I.IsMaximal) {x} (hx : x ∉ I) : + ∃ y, ∃ i ∈ I, y * x + i = 1 := by + cases' isMaximal_iff.1 hI with H₁ H₂ + rcases mem_span_insert.1 + (H₂ (span (insert x I)) x (Set.Subset.trans (subset_insert _ _) subset_span) hx + (subset_span (mem_insert _ _))) with + ⟨y, z, hz, hy⟩ + refine ⟨y, z, ?_, hy.symm⟩ + rwa [← span_eq I] + +theorem sInf_isPrime_of_isChain {s : Set (Ideal α)} (hs : s.Nonempty) (hs' : IsChain (· ≤ ·) s) + (H : ∀ p ∈ s, Ideal.IsPrime p) : (sInf s).IsPrime := + ⟨fun e => + let ⟨x, hx⟩ := hs + (H x hx).ne_top (eq_top_iff.mpr (e.symm.trans_le (sInf_le hx))), + fun e => + or_iff_not_imp_left.mpr fun hx => by + rw [Ideal.mem_sInf] at hx e ⊢ + push_neg at hx + obtain ⟨I, hI, hI'⟩ := hx + intro J hJ + cases' hs'.total hI hJ with h h + · exact h (((H I hI).mem_or_mem (e hI)).resolve_left hI') + · exact ((H J hJ).mem_or_mem (e hJ)).resolve_left fun x => hI' <| h x⟩ + +end Ideal + +end Semiring + +section CommSemiring + +variable {a b : α} + +-- A separate namespace definition is needed because the variables were historically in a different +-- order. +namespace Ideal + +variable [CommSemiring α] (I : Ideal α) + +theorem span_singleton_prime {p : α} (hp : p ≠ 0) : IsPrime (span ({p} : Set α)) ↔ Prime p := by + simp [isPrime_iff, Prime, span_singleton_eq_top, hp, mem_span_singleton] + +theorem IsMaximal.isPrime {I : Ideal α} (H : I.IsMaximal) : I.IsPrime := + ⟨H.1.1, @fun x y hxy => + or_iff_not_imp_left.2 fun hx => by + let J : Ideal α := Submodule.span α (insert x ↑I) + have IJ : I ≤ J := Set.Subset.trans (subset_insert _ _) subset_span + have xJ : x ∈ J := Ideal.subset_span (Set.mem_insert x I) + cases' isMaximal_iff.1 H with _ oJ + specialize oJ J x IJ hx xJ + rcases Submodule.mem_span_insert.mp oJ with ⟨a, b, h, oe⟩ + obtain F : y * 1 = y * (a • x + b) := congr_arg (fun g : α => y * g) oe + rw [← mul_one y, F, mul_add, mul_comm, smul_eq_mul, mul_assoc] + refine Submodule.add_mem I (I.mul_mem_left a hxy) (Submodule.smul_mem I y ?_) + rwa [Submodule.span_eq] at h⟩ + +-- see Note [lower instance priority] +instance (priority := 100) IsMaximal.isPrime' (I : Ideal α) : ∀ [_H : I.IsMaximal], I.IsPrime := + @IsMaximal.isPrime _ _ _ + +theorem span_singleton_lt_span_singleton [IsDomain α] {x y : α} : + span ({x} : Set α) < span ({y} : Set α) ↔ DvdNotUnit y x := by + rw [lt_iff_le_not_le, span_singleton_le_span_singleton, span_singleton_le_span_singleton, + dvd_and_not_dvd_iff] + +lemma isPrime_of_maximally_disjoint (I : Ideal α) + (S : Submonoid α) + (disjoint : Disjoint (I : Set α) S) + (maximally_disjoint : ∀ (J : Ideal α), I < J → ¬ Disjoint (J : Set α) S) : + I.IsPrime where + ne_top' := by + rintro rfl + have : 1 ∈ (S : Set α) := S.one_mem + aesop + mem_or_mem' {x y} hxy := by + by_contra! rid + have hx := maximally_disjoint (I ⊔ span {x}) (Submodule.lt_sup_iff_not_mem.mpr rid.1) + have hy := maximally_disjoint (I ⊔ span {y}) (Submodule.lt_sup_iff_not_mem.mpr rid.2) + simp only [Set.not_disjoint_iff, mem_inter_iff, SetLike.mem_coe, Submodule.mem_sup, + mem_span_singleton] at hx hy + obtain ⟨s₁, ⟨i₁, hi₁, ⟨_, ⟨r₁, rfl⟩, hr₁⟩⟩, hs₁⟩ := hx + obtain ⟨s₂, ⟨i₂, hi₂, ⟨_, ⟨r₂, rfl⟩, hr₂⟩⟩, hs₂⟩ := hy + refine disjoint.ne_of_mem + (I.add_mem (I.mul_mem_left (i₁ + x * r₁) hi₂) <| I.add_mem (I.mul_mem_right (y * r₂) hi₁) <| + I.mul_mem_right (r₁ * r₂) hxy) + (S.mul_mem hs₁ hs₂) ?_ + rw [← hr₁, ← hr₂] + ring + +end Ideal + +end CommSemiring + +section DivisionSemiring + +variable {K : Type u} [DivisionSemiring K] (I : Ideal K) + +namespace Ideal + +theorem bot_isMaximal : IsMaximal (⊥ : Ideal K) := + ⟨⟨fun h => absurd ((eq_top_iff_one (⊤ : Ideal K)).mp rfl) (by rw [← h]; simp), fun I hI => + or_iff_not_imp_left.mp (eq_bot_or_top I) (ne_of_gt hI)⟩⟩ + +end Ideal + +end DivisionSemiring diff --git a/Mathlib/RingTheory/Ideal/Norm.lean b/Mathlib/RingTheory/Ideal/Norm.lean index 6e1a0aa1de64f..ae759f8605dbe 100644 --- a/Mathlib/RingTheory/Ideal/Norm.lean +++ b/Mathlib/RingTheory/Ideal/Norm.lean @@ -4,15 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen, Alex J. Best -/ import Mathlib.Algebra.CharP.Quotient -import Mathlib.Algebra.GroupWithZero.NonZeroDivisors -import Mathlib.Data.Finsupp.Fintype import Mathlib.Data.Int.AbsoluteValue import Mathlib.Data.Int.Associated import Mathlib.LinearAlgebra.FreeModule.Determinant import Mathlib.LinearAlgebra.FreeModule.IdealQuotient import Mathlib.RingTheory.DedekindDomain.PID -import Mathlib.RingTheory.Ideal.Basis -import Mathlib.RingTheory.LocalProperties.Basic import Mathlib.RingTheory.Localization.NormTrace /-! @@ -391,24 +387,66 @@ theorem absNorm_eq_zero_iff {I : Ideal S} : Ideal.absNorm I = 0 ↔ I = ⊥ := b · rintro rfl exact absNorm_bot -theorem absNorm_ne_zero_of_nonZeroDivisors (I : (Ideal S)⁰) : Ideal.absNorm (I : Ideal S) ≠ 0 := - Ideal.absNorm_eq_zero_iff.not.mpr <| nonZeroDivisors.coe_ne_zero _ +theorem absNorm_ne_zero_iff_mem_nonZeroDivisors {I : Ideal S} : + absNorm I ≠ 0 ↔ I ∈ (Ideal S)⁰ := by + simp_rw [ne_eq, Ideal.absNorm_eq_zero_iff, mem_nonZeroDivisors_iff_ne_zero, Submodule.zero_eq_bot] -theorem finite_setOf_absNorm_eq [CharZero S] {n : ℕ} (hn : 0 < n) : +theorem absNorm_pos_iff_mem_nonZeroDivisors {I : Ideal S} : + 0 < absNorm I ↔ I ∈ (Ideal S)⁰ := by + rw [← absNorm_ne_zero_iff_mem_nonZeroDivisors, Nat.pos_iff_ne_zero] + +theorem absNorm_ne_zero_of_nonZeroDivisors (I : (Ideal S)⁰) : absNorm (I : Ideal S) ≠ 0 := + absNorm_ne_zero_iff_mem_nonZeroDivisors.mpr (SetLike.coe_mem I) + +theorem absNorm_pos_of_nonZeroDivisors (I : (Ideal S)⁰) : 0 < absNorm (I : Ideal S) := + absNorm_pos_iff_mem_nonZeroDivisors.mpr (SetLike.coe_mem I) + +theorem finite_setOf_absNorm_eq [CharZero S] (n : ℕ) : {I : Ideal S | Ideal.absNorm I = n}.Finite := by - let f := fun I : Ideal S => Ideal.map (Ideal.Quotient.mk (@Ideal.span S _ {↑n})) I - refine @Set.Finite.of_finite_image _ _ _ f ?_ ?_ - · suffices Finite (S ⧸ @Ideal.span S _ {↑n}) by - let g := ((↑) : Ideal (S ⧸ @Ideal.span S _ {↑n}) → Set (S ⧸ @Ideal.span S _ {↑n})) - refine @Set.Finite.of_finite_image _ _ _ g ?_ SetLike.coe_injective.injOn - exact Set.Finite.subset (@Set.finite_univ _ (@Set.finite' _ this)) (Set.subset_univ _) - rw [← absNorm_ne_zero_iff, absNorm_span_singleton] - simpa only [Ne, Int.natAbs_eq_zero, Algebra.norm_eq_zero_iff, Nat.cast_eq_zero] using - ne_of_gt hn - · intro I hI J hJ h - rw [← comap_map_mk (span_singleton_absNorm_le I), ← hI.symm, ← - comap_map_mk (span_singleton_absNorm_le J), ← hJ.symm] - congr + obtain hn | hn := Nat.eq_zero_or_pos n + · simp only [hn, absNorm_eq_zero_iff, Set.setOf_eq_eq_singleton, Set.finite_singleton] + · let f := fun I : Ideal S => Ideal.map (Ideal.Quotient.mk (@Ideal.span S _ {↑n})) I + refine Set.Finite.of_finite_image (f := f) ?_ ?_ + · suffices Finite (S ⧸ @Ideal.span S _ {↑n}) by + let g := ((↑) : Ideal (S ⧸ @Ideal.span S _ {↑n}) → Set (S ⧸ @Ideal.span S _ {↑n})) + refine Set.Finite.of_finite_image (f := g) ?_ SetLike.coe_injective.injOn + exact Set.Finite.subset Set.finite_univ (Set.subset_univ _) + rw [← absNorm_ne_zero_iff, absNorm_span_singleton] + simpa only [Ne, Int.natAbs_eq_zero, Algebra.norm_eq_zero_iff, Nat.cast_eq_zero] using + ne_of_gt hn + · intro I hI J hJ h + rw [← comap_map_mk (span_singleton_absNorm_le I), ← hI.symm, ← + comap_map_mk (span_singleton_absNorm_le J), ← hJ.symm] + congr + +theorem finite_setOf_absNorm_le [CharZero S] (n : ℕ) : + {I : Ideal S | Ideal.absNorm I ≤ n}.Finite := by + rw [show {I : Ideal S | Ideal.absNorm I ≤ n} = + (⋃ i ∈ Set.Icc 0 n, {I : Ideal S | Ideal.absNorm I = i}) by ext; simp] + refine Set.Finite.biUnion (Set.finite_Icc 0 n) (fun i _ => Ideal.finite_setOf_absNorm_eq i) + +theorem card_norm_le_eq_card_norm_le_add_one (n : ℕ) [CharZero S] : + Nat.card {I : Ideal S // absNorm I ≤ n} = + Nat.card {I : (Ideal S)⁰ // absNorm (I : Ideal S) ≤ n} + 1 := by + classical + have : Finite {I : Ideal S // I ∈ (Ideal S)⁰ ∧ absNorm I ≤ n} := + (finite_setOf_absNorm_le n).subset fun _ ⟨_, h⟩ ↦ h + have : Finite {I : Ideal S // I ∉ (Ideal S)⁰ ∧ absNorm I ≤ n} := + (finite_setOf_absNorm_le n).subset fun _ ⟨_, h⟩ ↦ h + rw [Nat.card_congr (Equiv.subtypeSubtypeEquivSubtypeInter (fun I ↦ I ∈ (Ideal S)⁰) + (fun I ↦ absNorm I ≤ n))] + let e : {I : Ideal S // absNorm I ≤ n} ≃ {I : Ideal S // I ∈ (Ideal S)⁰ ∧ absNorm I ≤ n} ⊕ + {I : Ideal S // I ∉ (Ideal S)⁰ ∧ absNorm I ≤ n} := by + refine (Equiv.subtypeEquivRight ?_).trans (subtypeOrEquiv _ _ ?_) + · intro _ + simp_rw [← or_and_right, em, true_and] + · exact Pi.disjoint_iff.mpr fun I ↦ Prop.disjoint_iff.mpr (by tauto) + simp_rw [Nat.card_congr e, Nat.card_sum, add_right_inj] + conv_lhs => + enter [1, 1, I] + rw [← absNorm_ne_zero_iff_mem_nonZeroDivisors, ne_eq, not_not, and_iff_left_iff_imp.mpr + (fun h ↦ by rw [h]; exact Nat.zero_le n), absNorm_eq_zero_iff] + rw [Nat.card_unique] theorem norm_dvd_iff {x : S} (hx : Prime (Algebra.norm ℤ x)) {y : ℤ} : Algebra.norm ℤ x ∣ y ↔ x ∣ y := by diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 952cf0b1f19a1..68e27eee2e14e 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -6,6 +6,7 @@ Authors: Kenny Lau import Mathlib.Algebra.Algebra.Operations import Mathlib.Data.Fintype.Lattice import Mathlib.RingTheory.Coprime.Lemmas +import Mathlib.RingTheory.Ideal.Basic import Mathlib.RingTheory.NonUnitalSubring.Basic import Mathlib.RingTheory.NonUnitalSubsemiring.Basic @@ -38,81 +39,8 @@ apply. -/ protected theorem _root_.Ideal.smul_eq_mul (I J : Ideal R) : I • J = I * J := rfl -variable (R M) in -/-- `Module.annihilator R M` is the ideal of all elements `r : R` such that `r • M = 0`. -/ -def _root_.Module.annihilator : Ideal R := LinearMap.ker (LinearMap.lsmul R M) - -theorem _root_.Module.mem_annihilator {r} : r ∈ Module.annihilator R M ↔ ∀ m : M, r • m = 0 := - ⟨fun h ↦ (congr($h ·)), (LinearMap.ext ·)⟩ - -theorem _root_.LinearMap.annihilator_le_of_injective (f : M →ₗ[R] M') (hf : Function.Injective f) : - Module.annihilator R M' ≤ Module.annihilator R M := fun x h ↦ by - rw [Module.mem_annihilator] at h ⊢; exact fun m ↦ hf (by rw [map_smul, h, f.map_zero]) - -theorem _root_.LinearMap.annihilator_le_of_surjective (f : M →ₗ[R] M') - (hf : Function.Surjective f) : Module.annihilator R M ≤ Module.annihilator R M' := fun x h ↦ by - rw [Module.mem_annihilator] at h ⊢ - intro m; obtain ⟨m, rfl⟩ := hf m - rw [← map_smul, h, f.map_zero] - -theorem _root_.LinearEquiv.annihilator_eq (e : M ≃ₗ[R] M') : - Module.annihilator R M = Module.annihilator R M' := - (e.annihilator_le_of_surjective e.surjective).antisymm (e.annihilator_le_of_injective e.injective) - -/-- `N.annihilator` is the ideal of all elements `r : R` such that `r • N = 0`. -/ -abbrev annihilator (N : Submodule R M) : Ideal R := - Module.annihilator R N - -theorem annihilator_top : (⊤ : Submodule R M).annihilator = Module.annihilator R M := - topEquiv.annihilator_eq - variable {I J : Ideal R} {N P : Submodule R M} -theorem mem_annihilator {r} : r ∈ N.annihilator ↔ ∀ n ∈ N, r • n = (0 : M) := by - simp_rw [annihilator, Module.mem_annihilator, Subtype.forall, Subtype.ext_iff]; rfl - -theorem mem_annihilator' {r} : r ∈ N.annihilator ↔ N ≤ comap (r • (LinearMap.id : M →ₗ[R] M)) ⊥ := - mem_annihilator.trans ⟨fun H n hn => (mem_bot R).2 <| H n hn, fun H _ hn => (mem_bot R).1 <| H hn⟩ - -theorem mem_annihilator_span (s : Set M) (r : R) : - r ∈ (Submodule.span R s).annihilator ↔ ∀ n : s, r • (n : M) = 0 := by - rw [Submodule.mem_annihilator] - constructor - · intro h n - exact h _ (Submodule.subset_span n.prop) - · intro h n hn - refine Submodule.span_induction hn ?_ ?_ ?_ ?_ - · intro x hx - exact h ⟨x, hx⟩ - · exact smul_zero _ - · intro x y hx hy - rw [smul_add, hx, hy, zero_add] - · intro a x hx - rw [smul_comm, hx, smul_zero] - -theorem mem_annihilator_span_singleton (g : M) (r : R) : - r ∈ (Submodule.span R ({g} : Set M)).annihilator ↔ r • g = 0 := by simp [mem_annihilator_span] - -theorem annihilator_bot : (⊥ : Submodule R M).annihilator = ⊤ := - (Ideal.eq_top_iff_one _).2 <| mem_annihilator'.2 bot_le - -theorem annihilator_eq_top_iff : N.annihilator = ⊤ ↔ N = ⊥ := - ⟨fun H => - eq_bot_iff.2 fun (n : M) hn => - (mem_bot R).2 <| one_smul R n ▸ mem_annihilator.1 ((Ideal.eq_top_iff_one _).1 H) n hn, - fun H => H.symm ▸ annihilator_bot⟩ - -theorem annihilator_mono (h : N ≤ P) : P.annihilator ≤ N.annihilator := fun _ hrp => - mem_annihilator.2 fun n hn => mem_annihilator.1 hrp n <| h hn - -theorem annihilator_iSup (ι : Sort w) (f : ι → Submodule R M) : - annihilator (⨆ i, f i) = ⨅ i, annihilator (f i) := - le_antisymm (le_iInf fun _ => annihilator_mono <| le_iSup _ _) fun _ H => - mem_annihilator'.2 <| - iSup_le fun i => - have := (mem_iInf _).1 H i - mem_annihilator'.1 this - theorem smul_mem_smul {r} {n} (hr : r ∈ I) (hn : n ∈ N) : r • n ∈ I • N := apply_mem_map₂ _ hr hn @@ -148,12 +76,12 @@ theorem mem_smul_span_singleton {I : Ideal R} {m : M} {x : M} : x ∈ I • span R ({m} : Set M) ↔ ∃ y ∈ I, y • m = x := ⟨fun hx => smul_induction_on hx - (fun r hri n hnm => + (fun r hri _ hnm => let ⟨s, hs⟩ := mem_span_singleton.1 hnm ⟨r * s, I.mul_mem_right _ hri, hs ▸ mul_smul r s m⟩) fun m1 m2 ⟨y1, hyi1, hy1⟩ ⟨y2, hyi2, hy2⟩ => ⟨y1 + y2, I.add_mem hyi1 hyi2, by rw [add_smul, hy1, hy2]⟩, - fun ⟨y, hyi, hy⟩ => hy ▸ smul_mem_smul hyi (subset_span <| Set.mem_singleton m)⟩ + fun ⟨_, hyi, hy⟩ => hy ▸ smul_mem_smul hyi (subset_span <| Set.mem_singleton m)⟩ theorem smul_le_right : I • N ≤ N := smul_le.2 fun r _ _ => N.smul_mem r @@ -177,17 +105,6 @@ theorem map_le_smul_top (I : Ideal R) (f : R →ₗ[R] M) : rw [← mul_one y, ← smul_eq_mul, f.map_smul] exact smul_mem_smul hy mem_top -@[simp] -theorem annihilator_smul (N : Submodule R M) : annihilator N • N = ⊥ := - eq_bot_iff.2 (smul_le.2 fun _ => mem_annihilator.1) - -@[simp] -theorem annihilator_mul (I : Ideal R) : annihilator I * I = ⊥ := - annihilator_smul I - -@[simp] -theorem mul_annihilator (I : Ideal R) : I * annihilator I = ⊥ := by rw [mul_comm, annihilator_mul] - variable (I J N P) @[simp] @@ -304,7 +221,7 @@ theorem mem_ideal_smul_span_iff_exists_sum {ι : Type*} (f : ι → M) (x : M) : constructor; swap · rintro ⟨a, ha, rfl⟩ exact Submodule.sum_mem _ fun c _ => smul_mem_smul (ha c) <| subset_span <| Set.mem_range_self _ - refine fun hx => span_induction (mem_smul_span.mp hx) ?_ ?_ ?_ ?_ + refine fun hx => span_induction ?_ ?_ ?_ ?_ (mem_smul_span.mp hx) · simp only [Set.mem_iUnion, Set.mem_range, Set.mem_singleton_iff] rintro x ⟨y, hy, x, ⟨i, rfl⟩, rfl⟩ refine ⟨Finsupp.single i y, fun j => ?_, ?_⟩ @@ -316,10 +233,10 @@ theorem mem_ideal_smul_span_iff_exists_sum {ι : Type*} (f : ι → M) (x : M) : refine @Finsupp.sum_single_index ι R M _ _ i _ (fun i y => y • f i) ?_ simp · exact ⟨0, fun _ => I.zero_mem, Finsupp.sum_zero_index⟩ - · rintro x y ⟨ax, hax, rfl⟩ ⟨ay, hay, rfl⟩ + · rintro x y - - ⟨ax, hax, rfl⟩ ⟨ay, hay, rfl⟩ refine ⟨ax + ay, fun i => I.add_mem (hax i) (hay i), Finsupp.sum_add_index' ?_ ?_⟩ <;> intros <;> simp only [zero_smul, add_smul] - · rintro c x ⟨a, ha, rfl⟩ + · rintro c x - ⟨a, ha, rfl⟩ refine ⟨c • a, fun i => I.mul_mem_left c (ha i), ?_⟩ rw [Finsupp.sum_smul_index, Finsupp.smul_sum] <;> intros <;> simp only [zero_smul, mul_smul] @@ -605,7 +522,7 @@ theorem mul_sup_eq_of_coprime_right (h : K ⊔ J = ⊤) : I * K ⊔ J = I ⊔ J theorem sup_prod_eq_top {s : Finset ι} {J : ι → Ideal R} (h : ∀ i, i ∈ s → I ⊔ J i = ⊤) : (I ⊔ ∏ i ∈ s, J i) = ⊤ := Finset.prod_induction _ (fun J => I ⊔ J = ⊤) - (fun J K hJ hK => (sup_mul_eq_of_coprime_left hJ).trans hK) + (fun _ _ hJ hK => (sup_mul_eq_of_coprime_left hJ).trans hK) (by simp_rw [one_eq_top, sup_top_eq]) h theorem sup_multiset_prod_eq_top {s : Multiset (Ideal R)} (h : ∀ p ∈ s, I ⊔ p = ⊤) : @@ -638,10 +555,8 @@ theorem pow_sup_pow_eq_top {m n : ℕ} (h : I ⊔ J = ⊤) : I ^ m ⊔ J ^ n = variable (I) --- @[simp] -- Porting note (#10618): simp can prove this theorem mul_bot : I * ⊥ = ⊥ := by simp --- @[simp] -- Porting note (#10618): simp can prove thisrove this theorem bot_mul : ⊥ * I = ⊥ := by simp @[simp] @@ -689,13 +604,27 @@ theorem pow_right_mono {I J : Ideal R} (e : I ≤ J) (n : ℕ) : I ^ n ≤ J ^ n · rw [pow_succ, pow_succ] exact Ideal.mul_mono hn e +lemma sup_pow_add_le_pow_sup_pow {R} [CommSemiring R] {I J : Ideal R} {n m : ℕ} : + (I ⊔ J) ^ (n + m) ≤ I ^ n ⊔ J ^ m := by + rw [← Ideal.add_eq_sup, ← Ideal.add_eq_sup, add_pow, Ideal.sum_eq_sup] + apply Finset.sup_le + intros i hi + by_cases hn : n ≤ i + · exact (Ideal.mul_le_right.trans (Ideal.mul_le_right.trans + ((Ideal.pow_le_pow_right hn).trans le_sup_left))) + · refine (Ideal.mul_le_right.trans (Ideal.mul_le_left.trans + ((Ideal.pow_le_pow_right ?_).trans le_sup_right))) + simp only [Finset.mem_range, Nat.lt_succ] at hi + rw [Nat.le_sub_iff_add_le hi] + nlinarith + @[simp] theorem mul_eq_bot {R : Type*} [CommSemiring R] [NoZeroDivisors R] {I J : Ideal R} : I * J = ⊥ ↔ I = ⊥ ∨ J = ⊥ := ⟨fun hij => or_iff_not_imp_left.mpr fun I_ne_bot => - J.eq_bot_iff.mpr fun j hj => - let ⟨i, hi, ne0⟩ := I.ne_bot_iff.mp I_ne_bot + J.eq_bot_iff.mpr fun _ hj => + let ⟨_, hi, ne0⟩ := I.ne_bot_iff.mp I_ne_bot Or.resolve_left (mul_eq_zero.mp ((I * J).eq_bot_iff.mp hij _ (mul_mem_mul hi hj))) ne0, fun h => by cases' h with h h <;> rw [← Ideal.mul_bot, h, Ideal.mul_comm]⟩ @@ -883,6 +812,22 @@ variable {I J} in theorem IsRadical.inf (hI : IsRadical I) (hJ : IsRadical J) : IsRadical (I ⊓ J) := by rw [IsRadical, radical_inf]; exact inf_le_inf hI hJ +/-- `Ideal.radical` as an `InfTopHom`, bundling in that it distributes over `inf`. -/ +def radicalInfTopHom : InfTopHom (Ideal R) (Ideal R) where + toFun := radical + map_inf' := radical_inf + map_top' := radical_top _ + +@[simp] +lemma radicalInfTopHom_apply (I : Ideal R) : radicalInfTopHom I = radical I := rfl + +open Finset in +lemma radical_finset_inf {ι} {s : Finset ι} {f : ι → Ideal R} {i : ι} (hi : i ∈ s) + (hs : ∀ ⦃y⦄, y ∈ s → (f y).radical = (f i).radical) : + (s.inf f).radical = (f i).radical := by + rw [← radicalInfTopHom_apply, map_finset_inf, ← Finset.inf'_eq_inf ⟨_, hi⟩] + exact Finset.inf'_eq_of_forall _ _ hs + /-- The reverse inclusion does not hold for e.g. `I := fun n : ℕ ↦ Ideal.span {(2 ^ n : ℤ)}`. -/ theorem radical_iInf_le {ι} (I : ι → Ideal R) : radical (⨅ i, I i) ≤ ⨅ i, radical (I i) := le_iInf fun _ ↦ radical_mono (iInf_le _ _) @@ -903,15 +848,15 @@ theorem IsPrime.radical_le_iff (hJ : IsPrime J) : I.radical ≤ J ↔ I ≤ J := IsRadical.radical_le_iff hJ.isRadical theorem radical_eq_sInf (I : Ideal R) : radical I = sInf { J : Ideal R | I ≤ J ∧ IsPrime J } := - le_antisymm (le_sInf fun J hJ ↦ hJ.2.radical_le_iff.2 hJ.1) fun r hr ↦ + le_antisymm (le_sInf fun _ hJ ↦ hJ.2.radical_le_iff.2 hJ.1) fun r hr ↦ by_contradiction fun hri ↦ let ⟨m, hIm, hm⟩ := zorn_le_nonempty₀ { K : Ideal R | r ∉ radical K } (fun c hc hcc y hyc => ⟨sSup c, fun ⟨n, hrnc⟩ => - let ⟨y, hyc, hrny⟩ := (Submodule.mem_sSup_of_directed ⟨y, hyc⟩ hcc.directedOn).1 hrnc + let ⟨_, hyc, hrny⟩ := (Submodule.mem_sSup_of_directed ⟨y, hyc⟩ hcc.directedOn).1 hrnc hc hyc ⟨n, hrny⟩, - fun z => le_sSup⟩) + fun _ => le_sSup⟩) I hri have hrm : r ∉ radical m := hm.prop have : ∀ x ∉ m, r ∈ radical (m ⊔ span {x}) := fun x hxm => @@ -1070,8 +1015,8 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι rw [Finset.coe_insert] at h ⊢ rw [Finset.coe_insert] at h simp only [Set.biUnion_insert] at h ⊢ - rw [← Set.union_assoc (f i : Set R)] at h - erw [Set.union_eq_self_of_subset_right hfji] at h + rw [← Set.union_assoc (f i : Set R), + Set.union_eq_self_of_subset_right hfji] at h exact h specialize ih hp' hn' h' refine ih.imp id (Or.imp id (Exists.imp fun k => ?_)) @@ -1079,8 +1024,8 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι by_cases Ha : f a ≤ f i · have h' : (I : Set R) ⊆ f i ∪ f b ∪ ⋃ j ∈ (↑t : Set ι), f j := by rw [Finset.coe_insert, Set.biUnion_insert, ← Set.union_assoc, - Set.union_right_comm (f a : Set R)] at h - erw [Set.union_eq_self_of_subset_left Ha] at h + Set.union_right_comm (f a : Set R), + Set.union_eq_self_of_subset_left Ha] at h exact h specialize ih hp.2 hn h' right @@ -1091,8 +1036,8 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι by_cases Hb : f b ≤ f i · have h' : (I : Set R) ⊆ f a ∪ f i ∪ ⋃ j ∈ (↑t : Set ι), f j := by rw [Finset.coe_insert, Set.biUnion_insert, ← Set.union_assoc, - Set.union_assoc (f a : Set R)] at h - erw [Set.union_eq_self_of_subset_left Hb] at h + Set.union_assoc (f a : Set R), + Set.union_eq_self_of_subset_left Hb] at h exact h specialize ih hp.2 hn h' rcases ih with (ih | ih | ⟨k, hkt, ih⟩) diff --git a/Mathlib/RingTheory/Ideal/Over.lean b/Mathlib/RingTheory/Ideal/Over.lean index f8586e0f2559a..b5adc93c0c078 100644 --- a/Mathlib/RingTheory/Ideal/Over.lean +++ b/Mathlib/RingTheory/Ideal/Over.lean @@ -3,7 +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.RingTheory.Algebraic +import Mathlib.RingTheory.Ideal.Pointwise import Mathlib.RingTheory.Localization.AtPrime import Mathlib.RingTheory.Localization.Integral @@ -29,11 +29,9 @@ variable {R : Type*} [CommRing R] namespace Ideal -open Polynomial +open Polynomial Submodule -open Polynomial - -open Submodule +open scoped Pointwise section CommRing @@ -429,4 +427,135 @@ lemma map_eq_top_iff {R S} [CommRing R] [CommRing S] end IsDomain +section ideal_liesOver + +section Semiring + +variable (A : Type*) [CommSemiring A] {B : Type*} [Semiring B] [Algebra A B] + (P : Ideal B) (p : Ideal A) + +/-- The ideal obtained by pulling back the ideal `P` from `B` to `A`. -/ +abbrev under : Ideal A := Ideal.comap (algebraMap A B) P + +theorem under_def : P.under A = Ideal.comap (algebraMap A B) P := rfl + +instance IsPrime.under [hP : P.IsPrime] : (P.under A).IsPrime := + hP.comap (algebraMap A B) + +@[simp] +lemma under_smul {G : Type*} [Group G] [MulSemiringAction G B] [SMulCommClass G A B] (g : G) : + (g • P : Ideal B).under A = P.under A := by + ext a + rw [mem_comap, mem_comap, mem_pointwise_smul_iff_inv_smul_mem, smul_algebraMap] + +variable {A} + +/-- `P` lies over `p` if `p` is the preimage of `P` of the `algebraMap`. -/ +class LiesOver : Prop where + over : p = P.under A + +instance over_under : P.LiesOver (P.under A) where over := rfl + +theorem over_def [P.LiesOver p] : p = P.under A := LiesOver.over + +theorem mem_of_liesOver [P.LiesOver p] (x : A) : x ∈ p ↔ algebraMap A B x ∈ P := by + rw [P.over_def p] + rfl + +end Semiring + +section CommSemiring + +variable {A : Type*} [CommSemiring A] {B : Type*} [CommSemiring B] {C : Type*} [Semiring C] + [Algebra A B] [Algebra B C] [Algebra A C] [IsScalarTower A B C] + (𝔓 : Ideal C) (P : Ideal B) (p : Ideal A) + +@[simp] +theorem under_under : (𝔓.under B).under A = 𝔓.under A := by + simp_rw [comap_comap, ← IsScalarTower.algebraMap_eq] + +theorem LiesOver.trans [𝔓.LiesOver P] [P.LiesOver p] : 𝔓.LiesOver p where + over := by rw [P.over_def p, 𝔓.over_def P, under_under] + +theorem LiesOver.tower_bot [hp : 𝔓.LiesOver p] [hP : 𝔓.LiesOver P] : P.LiesOver p where + over := by rw [𝔓.over_def p, 𝔓.over_def P, under_under] + +variable (B) + +instance under_liesOver_of_liesOver [𝔓.LiesOver p] : (𝔓.under B).LiesOver p := + LiesOver.tower_bot 𝔓 (𝔓.under B) p + +end CommSemiring + +section CommRing + +namespace Quotient + +variable (R : Type*) [CommSemiring R] {A B : Type*} [CommRing A] [CommRing B] [Algebra A B] + [Algebra R A] [Algebra R B] [IsScalarTower R A B] (P : Ideal B) (p : Ideal A) [P.LiesOver p] + +/-- If `P` lies over `p`, then canonically `B ⧸ P` is a `A ⧸ p`-algebra. -/ +instance algebraOfLiesOver : Algebra (A ⧸ p) (B ⧸ P) := + algebraQuotientOfLEComap (le_of_eq (P.over_def p)) + +instance isScalarTower_of_liesOver : IsScalarTower R (A ⧸ p) (B ⧸ P) := + IsScalarTower.of_algebraMap_eq' <| + congrArg (algebraMap B (B ⧸ P)).comp (IsScalarTower.algebraMap_eq R A B) + +/-- `B ⧸ P` is a finite `A ⧸ p`-module if `B` is a finite `A`-module. -/ +instance module_finite_of_liesOver [Module.Finite A B] : Module.Finite (A ⧸ p) (B ⧸ P) := + Module.Finite.of_restrictScalars_finite A (A ⧸ p) (B ⧸ P) + +example [Module.Finite A B] : Module.Finite (A ⧸ P.under A) (B ⧸ P) := inferInstance + +/-- `B ⧸ P` is a finitely generated `A ⧸ p`-algebra if `B` is a finitely generated `A`-algebra. -/ +instance algebra_finiteType_of_liesOver [Algebra.FiniteType A B] : + Algebra.FiniteType (A ⧸ p) (B ⧸ P) := + Algebra.FiniteType.of_restrictScalars_finiteType A (A ⧸ p) (B ⧸ P) + +/-- `B ⧸ P` is a Noetherian `A ⧸ p`-module if `B` is a Noetherian `A`-module. -/ +instance isNoetherian_of_liesOver [IsNoetherian A B] : IsNoetherian (A ⧸ p) (B ⧸ P) := + isNoetherian_of_tower A inferInstance + +theorem algebraMap_injective_of_liesOver : + Function.Injective (algebraMap (A ⧸ p) (B ⧸ P)) := by + rintro ⟨a⟩ ⟨b⟩ hab + apply Quotient.eq.mpr ((mem_of_liesOver P p (a - b)).mpr _) + rw [RingHom.map_sub] + exact Quotient.eq.mp hab + +instance [P.IsPrime] : NoZeroSMulDivisors (A ⧸ p) (B ⧸ P) := + NoZeroSMulDivisors.of_algebraMap_injective (Quotient.algebraMap_injective_of_liesOver P p) + +end Quotient + +end CommRing + +section IsIntegral + +variable {A : Type*} [CommRing A] {B : Type*} [CommRing B] [Algebra A B] [Algebra.IsIntegral A B] + (P : Ideal B) (p : Ideal A) [P.LiesOver p] + +variable (A) in +/-- If `B` is an integral `A`-algebra, `P` is a maximal ideal of `B`, then the pull back of + `P` is also a maximal ideal of `A`. -/ +instance IsMaximal.under [P.IsMaximal] : (P.under A).IsMaximal := + isMaximal_comap_of_isIntegral_of_isMaximal P + +theorem IsMaximal.of_liesOver_isMaximal [hpm : p.IsMaximal] [P.IsPrime] : P.IsMaximal := by + rw [P.over_def p] at hpm + exact isMaximal_of_isIntegral_of_isMaximal_comap P hpm + +theorem IsMaximal.of_isMaximal_liesOver [P.IsMaximal] : p.IsMaximal := by + rw [P.over_def p] + exact isMaximal_comap_of_isIntegral_of_isMaximal P + +/-- `B ⧸ P` is an integral `A ⧸ p`-algebra if `B` is a integral `A`-algebra. -/ +instance Quotient.algebra_isIntegral_of_liesOver : Algebra.IsIntegral (A ⧸ p) (B ⧸ P) := + Algebra.IsIntegral.tower_top A + +end IsIntegral + +end ideal_liesOver + end Ideal diff --git a/Mathlib/RingTheory/Ideal/Pointwise.lean b/Mathlib/RingTheory/Ideal/Pointwise.lean index aca8181312f7a..5116083a5f52f 100644 --- a/Mathlib/RingTheory/Ideal/Pointwise.lean +++ b/Mathlib/RingTheory/Ideal/Pointwise.lean @@ -28,26 +28,34 @@ namespace Ideal section Monoid -variable [Monoid M] [CommRing R] [MulSemiringAction M R] +variable [Monoid M] [Semiring R] [MulSemiringAction M R] /-- The action on an ideal corresponding to applying the action to every element. This is available as an instance in the `Pointwise` locale. -/ -protected def pointwiseMulSemiringAction : MulSemiringAction M (Ideal R) where +protected def pointwiseDistribMulAction : DistribMulAction M (Ideal R) where smul a := Ideal.map (MulSemiringAction.toRingHom _ _ a) one_smul I := congr_arg (I.map ·) (RingHom.ext <| one_smul M) |>.trans I.map_id - mul_smul a₁ a₂ I := + mul_smul _ _ I := congr_arg (I.map ·) (RingHom.ext <| mul_smul _ _) |>.trans (I.map_map _ _).symm + smul_zero _ := Ideal.map_bot + smul_add _ I J := Ideal.map_sup _ I J + +scoped[Pointwise] attribute [instance] Ideal.pointwiseDistribMulAction + +open Pointwise + +/-- The action on an ideal corresponding to applying the action to every element. + +This is available as an instance in the `Pointwise` locale. -/ +protected def pointwiseMulSemiringAction {R : Type*} [CommRing R] [MulSemiringAction M R] : + MulSemiringAction M (Ideal R) where smul_one a := by simp only [Ideal.one_eq_top]; exact Ideal.map_top _ smul_mul a I J := Ideal.map_mul (MulSemiringAction.toRingHom _ _ a) I J - smul_add a I J := Ideal.map_sup _ I J - smul_zero a := Ideal.map_bot scoped[Pointwise] attribute [instance] Ideal.pointwiseMulSemiringAction -open Pointwise - theorem pointwise_smul_def {a : M} (S : Ideal R) : a • S = S.map (MulSemiringAction.toRingHom _ _ a) := rfl @@ -76,12 +84,25 @@ instance pointwise_central_scalar [MulSemiringAction Mᵐᵒᵖ R] [IsCentralSca IsCentralScalar M (Ideal R) := ⟨fun _ S => (congr_arg fun f => S.map f) <| RingHom.ext <| op_smul_eq_smul _⟩ +@[simp] +theorem pointwise_smul_toAddSubmonoid (a : M) (S : Ideal R) + (ha : Function.Surjective fun r : R => a • r) : + (a • S).toAddSubmonoid = a • S.toAddSubmonoid := by + ext + exact Ideal.mem_map_iff_of_surjective _ <| by exact ha + +@[simp] +theorem pointwise_smul_toAddSubGroup {R : Type*} [Ring R] [MulSemiringAction M R] + (a : M) (S : Ideal R) (ha : Function.Surjective fun r : R => a • r) : + (a • S).toAddSubgroup = a • S.toAddSubgroup := by + ext + exact Ideal.mem_map_iff_of_surjective _ <| by exact ha + end Monoid section Group -variable [Group M] [CommRing R] [MulSemiringAction M R] - +variable [Group M] [Semiring R] [MulSemiringAction M R] open Pointwise @@ -100,20 +121,6 @@ theorem mem_pointwise_smul_iff_inv_smul_mem {a : M} {S : Ideal R} {x : R} : ⟨fun h => by simpa using smul_mem_pointwise_smul a⁻¹ _ _ h, fun h => by simpa using smul_mem_pointwise_smul a _ _ h⟩ -@[simp] -theorem pointwise_smul_toAddSubmonoid (a : M) (S : Ideal R) - (ha : Function.Surjective fun r : R => a • r) : - (a • S).toAddSubmonoid = a • S.toAddSubmonoid := by - ext - exact Ideal.mem_map_iff_of_surjective _ <| by exact ha - -@[simp] -theorem pointwise_smul_toAddSubGroup (a : M) (S : Ideal R) - (ha : Function.Surjective fun r : R => a • r) : - (a • S).toAddSubgroup = a • S.toAddSubgroup := by - ext - exact Ideal.mem_map_iff_of_surjective _ <| by exact ha - theorem mem_inv_pointwise_smul_iff {a : M} {S : Ideal R} {x : R} : x ∈ a⁻¹ • S ↔ a • x ∈ S := by rw [mem_pointwise_smul_iff_inv_smul_mem, inv_inv] @@ -127,6 +134,14 @@ theorem pointwise_smul_subset_iff {a : M} {S T : Ideal R} : a • S ≤ T ↔ S theorem subset_pointwise_smul_iff {a : M} {S T : Ideal R} : S ≤ a • T ↔ a⁻¹ • S ≤ T := by rw [← pointwise_smul_le_pointwise_smul_iff (a := a⁻¹), inv_smul_smul] +theorem IsPrime.smul {I : Ideal R} [H : I.IsPrime] (g : M) : (g • I).IsPrime := by + rw [I.pointwise_smul_eq_comap] + apply H.comap + +@[simp] +theorem IsPrime.smul_iff {I : Ideal R} (g : M) : (g • I).IsPrime ↔ I.IsPrime := + ⟨fun H ↦ inv_smul_smul g I ▸ H.smul g⁻¹, fun H ↦ H.smul g⟩ + /-! TODO: add `equivSMul` like we have for subgroup. -/ end Group diff --git a/Mathlib/RingTheory/Ideal/Prime.lean b/Mathlib/RingTheory/Ideal/Prime.lean new file mode 100644 index 0000000000000..321e1b9b104eb --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Prime.lean @@ -0,0 +1,116 @@ +/- +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 + +/-! + +# Prime ideals + +This file contains the definition of `Ideal.IsPrime` for prime ideals. + +## TODO + +Support right ideals, and two-sided ideals over non-commutative rings. +-/ + + +universe u v w + +variable {α : Type u} {β : Type v} {F : Type w} + +open Set Function + +open Pointwise + +section Semiring + +namespace Ideal + +variable [Semiring α] (I : Ideal α) {a b : α} + +/-- An ideal `P` of a ring `R` is prime if `P ≠ R` and `xy ∈ P → x ∈ P ∨ y ∈ P` -/ +class IsPrime (I : Ideal α) : Prop where + /-- The prime ideal is not the entire ring. -/ + ne_top' : I ≠ ⊤ + /-- If a product lies in the prime ideal, then at least one element lies in the prime ideal. -/ + mem_or_mem' : ∀ {x y : α}, x * y ∈ I → x ∈ I ∨ y ∈ I + +theorem isPrime_iff {I : Ideal α} : IsPrime I ↔ I ≠ ⊤ ∧ ∀ {x y : α}, x * y ∈ I → x ∈ I ∨ y ∈ I := + ⟨fun h => ⟨h.1, h.2⟩, fun h => ⟨h.1, h.2⟩⟩ + +theorem IsPrime.ne_top {I : Ideal α} (hI : I.IsPrime) : I ≠ ⊤ := + hI.1 + +theorem IsPrime.mem_or_mem {I : Ideal α} (hI : I.IsPrime) {x y : α} : x * y ∈ I → x ∈ I ∨ y ∈ I := + hI.2 + +theorem IsPrime.mem_or_mem_of_mul_eq_zero {I : Ideal α} (hI : I.IsPrime) {x y : α} (h : x * y = 0) : + x ∈ I ∨ y ∈ I := + hI.mem_or_mem (h.symm ▸ I.zero_mem) + +theorem IsPrime.mem_of_pow_mem {I : Ideal α} (hI : I.IsPrime) {r : α} (n : ℕ) (H : r ^ n ∈ I) : + r ∈ I := by + induction n with + | zero => + rw [pow_zero] at H + exact (mt (eq_top_iff_one _).2 hI.1).elim H + | succ n ih => + rw [pow_succ] at H + exact Or.casesOn (hI.mem_or_mem H) ih id + +theorem not_isPrime_iff {I : Ideal α} : + ¬I.IsPrime ↔ I = ⊤ ∨ ∃ (x : α) (_hx : x ∉ I) (y : α) (_hy : y ∉ I), x * y ∈ I := by + simp_rw [Ideal.isPrime_iff, not_and_or, Ne, Classical.not_not, not_forall, not_or] + exact + or_congr Iff.rfl + ⟨fun ⟨x, y, hxy, hx, hy⟩ => ⟨x, hx, y, hy, hxy⟩, fun ⟨x, hx, y, hy, hxy⟩ => + ⟨x, y, hxy, hx, hy⟩⟩ + +theorem bot_prime [IsDomain α] : (⊥ : Ideal α).IsPrime := + ⟨fun h => one_ne_zero (α := α) (by rwa [Ideal.eq_top_iff_one, Submodule.mem_bot] at h), fun h => + mul_eq_zero.mp (by simpa only [Submodule.mem_bot] using h)⟩ + +end Ideal + +end Semiring + +section CommSemiring + +variable {a b : α} + +-- A separate namespace definition is needed because the variables were historically in a different +-- order. +namespace Ideal + +variable [CommSemiring α] (I : Ideal α) + +theorem IsPrime.mul_mem_iff_mem_or_mem {I : Ideal α} (hI : I.IsPrime) : + ∀ {x y : α}, x * y ∈ I ↔ x ∈ I ∨ y ∈ I := @fun x y => + ⟨hI.mem_or_mem, by + rintro (h | h) + exacts [I.mul_mem_right y h, I.mul_mem_left x h]⟩ + +theorem IsPrime.pow_mem_iff_mem {I : Ideal α} (hI : I.IsPrime) {r : α} (n : ℕ) (hn : 0 < n) : + r ^ n ∈ I ↔ r ∈ I := + ⟨hI.mem_of_pow_mem n, fun hr => I.pow_mem_of_mem hr n hn⟩ + +end Ideal + +end CommSemiring + +section DivisionSemiring + +variable {K : Type u} [DivisionSemiring K] (I : Ideal K) + +namespace Ideal + +theorem eq_bot_of_prime [h : I.IsPrime] : I = ⊥ := + or_iff_not_imp_right.mp I.eq_bot_or_top h.1 + +end Ideal + +end DivisionSemiring diff --git a/Mathlib/RingTheory/Ideal/Quotient.lean b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean similarity index 58% rename from Mathlib/RingTheory/Ideal/Quotient.lean rename to Mathlib/RingTheory/Ideal/Quotient/Basic.lean index a8a6b587bf0f9..190587bcc84f3 100644 --- a/Mathlib/RingTheory/Ideal/Quotient.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean @@ -3,9 +3,11 @@ 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, Anne Baanen -/ -import Mathlib.LinearAlgebra.Quotient +import Mathlib.GroupTheory.QuotientGroup.Finite +import Mathlib.LinearAlgebra.Quotient.Defs import Mathlib.RingTheory.Congruence.Basic import Mathlib.RingTheory.Ideal.Basic +import Mathlib.RingTheory.Ideal.Quotient.Defs import Mathlib.Tactic.FinCases /-! @@ -32,41 +34,10 @@ open Set variable {R : Type u} [CommRing R] (I : Ideal R) {a b : R} variable {S : Type v} --- Note that at present `Ideal` means a left-ideal, --- so this quotient is only useful in a commutative ring. --- We should develop quotients by two-sided ideals as well. -/-- The quotient `R/I` of a ring `R` by an ideal `I`. - -The ideal quotient of `I` is defined to equal the quotient of `I` as an `R`-submodule of `R`. -This definition uses `abbrev` so that typeclass instances can be shared between -`Ideal.Quotient I` and `Submodule.Quotient I`. --/ -@[instance] abbrev instHasQuotient : HasQuotient R (Ideal R) := - Submodule.hasQuotient - namespace Quotient variable {I} {x y : R} -instance one (I : Ideal R) : One (R ⧸ I) := - ⟨Submodule.Quotient.mk 1⟩ - -/-- On `Ideal`s, `Submodule.quotientRel` is a ring congruence. -/ -protected def ringCon (I : Ideal R) : RingCon R := - { QuotientAddGroup.con I.toAddSubgroup with - mul' := fun {a₁ b₁ a₂ b₂} h₁ h₂ => by - rw [Submodule.quotientRel_r_def] at h₁ h₂ ⊢ - have F := I.add_mem (I.mul_mem_left a₂ h₁) (I.mul_mem_right b₁ h₂) - have : a₁ * a₂ - b₁ * b₂ = a₂ * (a₁ - b₁) + (a₂ - b₂) * b₁ := by - rw [mul_sub, sub_mul, sub_add_sub_cancel, mul_comm, mul_comm b₁] - rwa [← this] at F } - -instance commRing (I : Ideal R) : CommRing (R ⧸ I) := - inferInstanceAs (CommRing (Quotient.ringCon I).Quotient) - --- Sanity test to make sure no diamonds have emerged in `commRing` -example : (commRing I).toAddCommGroup = Submodule.Quotient.addCommGroup I := rfl - -- this instance is harder to find than the one via `Algebra α (R ⧸ I)`, so use a lower priority instance (priority := 100) isScalarTower_right {α} [SMul α R] [IsScalarTower α R R] : IsScalarTower α (R ⧸ I) (R ⧸ I) := @@ -80,38 +51,6 @@ instance smulCommClass' {α} [SMul α R] [IsScalarTower α R R] [SMulCommClass R SMulCommClass (R ⧸ I) α (R ⧸ I) := (Quotient.ringCon I).smulCommClass' -/-- The ring homomorphism from a ring `R` to a quotient ring `R/I`. -/ -def mk (I : Ideal R) : R →+* R ⧸ I where - toFun a := Submodule.Quotient.mk a - map_zero' := rfl - map_one' := rfl - map_mul' _ _ := rfl - map_add' _ _ := rfl - -instance {I : Ideal R} : Coe R (R ⧸ I) := - ⟨Ideal.Quotient.mk I⟩ - -/-- Two `RingHom`s from the quotient by an ideal are equal if their -compositions with `Ideal.Quotient.mk'` are equal. - -See note [partially-applied ext lemmas]. -/ -@[ext 1100] -theorem ringHom_ext [NonAssocSemiring S] ⦃f g : R ⧸ I →+* S⦄ (h : f.comp (mk I) = g.comp (mk I)) : - f = g := - RingHom.ext fun x => Quotient.inductionOn' x <| (RingHom.congr_fun h : _) - -instance inhabited : Inhabited (R ⧸ I) := - ⟨mk I 37⟩ - -protected theorem eq : mk I x = mk I y ↔ x - y ∈ I := - Submodule.Quotient.eq I - -@[simp] -theorem mk_eq_mk (x : R) : (Submodule.Quotient.mk x : R ⧸ I) = mk I x := rfl - -theorem eq_zero_iff_mem {I : Ideal R} : mk I a = 0 ↔ a ∈ I := - Submodule.Quotient.mk_eq_zero _ - theorem eq_zero_iff_dvd (x y : R) : Ideal.Quotient.mk (Ideal.span ({x} : Set R)) y = 0 ↔ x ∣ y := by rw [Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton] @@ -119,9 +58,6 @@ theorem eq_zero_iff_dvd (x y : R) : Ideal.Quotient.mk (Ideal.span ({x} : Set R)) lemma mk_singleton_self (x : R) : mk (Ideal.span {x}) x = 0 := by rw [eq_zero_iff_dvd] -theorem mk_eq_mk_iff_sub_mem (x y : R) : mk I x = mk I y ↔ x - y ∈ I := by - rw [← eq_zero_iff_mem, map_sub, sub_eq_zero] - theorem zero_eq_one_iff {I : Ideal R} : (0 : R ⧸ I) = 1 ↔ I = ⊤ := eq_comm.trans <| eq_zero_iff_mem.trans (eq_top_iff_one _).symm @@ -138,22 +74,6 @@ theorem subsingleton_iff {I : Ideal R} : Subsingleton (R ⧸ I) ↔ I = ⊤ := b instance : Unique (R ⧸ (⊤ : Ideal R)) := ⟨⟨0⟩, by rintro ⟨x⟩; exact Quotient.eq_zero_iff_mem.mpr Submodule.mem_top⟩ -theorem mk_surjective : Function.Surjective (mk I) := fun y => - Quotient.inductionOn' y fun x => Exists.intro x rfl - -instance : RingHomSurjective (mk I) := - ⟨mk_surjective⟩ - -/-- If `I` is an ideal of a commutative ring `R`, if `q : R → R/I` is the quotient map, and if -`s ⊆ R` is a subset, then `q⁻¹(q(s)) = ⋃ᵢ(i + s)`, the union running over all `i ∈ I`. -/ -theorem quotient_ring_saturate (I : Ideal R) (s : Set R) : - mk I ⁻¹' (mk I '' s) = ⋃ x : I, (fun y => x.1 + y) '' s := by - ext x - simp only [mem_preimage, mem_image, mem_iUnion, Ideal.Quotient.eq] - exact - ⟨fun ⟨a, a_in, h⟩ => ⟨⟨_, I.neg_mem h⟩, a, a_in, by simp⟩, fun ⟨⟨i, hi⟩, a, ha, Eq⟩ => - ⟨a, ha, by rw [← Eq, sub_add_eq_sub_sub_swap, sub_self, zero_sub]; exact I.neg_mem hi⟩⟩ - instance noZeroDivisors (I : Ideal R) [hI : I.IsPrime] : NoZeroDivisors (R ⧸ I) where eq_zero_or_eq_zero_of_mul_eq_zero {a b} := Quotient.inductionOn₂' a b fun {_ _} hab => (hI.mem_or_mem (eq_zero_iff_mem.1 hab)).elim (Or.inl ∘ eq_zero_iff_mem.2) @@ -177,7 +97,7 @@ theorem exists_inv {I : Ideal R} [hI : I.IsMaximal] : rcases hI.exists_inv (mt eq_zero_iff_mem.2 h) with ⟨b, c, hc, abc⟩ rw [mul_comm] at abc refine ⟨mk _ b, Quot.sound ?_⟩ - simp only [Submodule.quotientRel_r_def] + simp only [Submodule.quotientRel_def] rw [← eq_sub_iff_add_eq'] at abc rwa [abc, ← neg_mem_iff (G := R) (H := I), neg_sub] at hc @@ -197,13 +117,13 @@ protected noncomputable abbrev groupWithZero (I : Ideal R) [hI : I.IsMaximal] : will have computable inverses (and `qsmul`, `ratCast`) in some applications. See note [reducible non-instances]. -/ -protected noncomputable abbrev field (I : Ideal R) [hI : I.IsMaximal] : Field (R ⧸ I) where +protected noncomputable abbrev field (I : Ideal R) [I.IsMaximal] : Field (R ⧸ I) where __ := commRing _ __ := Quotient.groupWithZero _ nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q x => rfl + qsmul_def := fun _ _ => rfl /-- If the quotient by an ideal is a field, then the ideal is maximal. -/ theorem maximal_of_isField (I : Ideal R) (hqf : IsField (R ⧸ I)) : I.IsMaximal := by @@ -224,63 +144,8 @@ theorem maximal_ideal_iff_isField_quotient (I : Ideal R) : I.IsMaximal ↔ IsFie Field.toIsField _, maximal_of_isField _⟩ -variable [Semiring S] - -/-- Given a ring homomorphism `f : R →+* S` sending all elements of an ideal to zero, -lift it to the quotient by this ideal. -/ -def lift (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : R ⧸ I →+* S := - { QuotientAddGroup.lift I.toAddSubgroup f.toAddMonoidHom H with - map_one' := f.map_one - map_mul' := fun a₁ a₂ => Quotient.inductionOn₂' a₁ a₂ f.map_mul } - -@[simp] -theorem lift_mk (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : - lift I f H (mk I a) = f a := - rfl - -theorem lift_surjective_of_surjective (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) - (hf : Function.Surjective f) : Function.Surjective (Ideal.Quotient.lift I f H) := by - intro y - obtain ⟨x, rfl⟩ := hf y - use Ideal.Quotient.mk I x - simp only [Ideal.Quotient.lift_mk] - -/-- The ring homomorphism from the quotient by a smaller ideal to the quotient by a larger ideal. - -This is the `Ideal.Quotient` version of `Quot.Factor` -/ -def factor (S T : Ideal R) (H : S ≤ T) : R ⧸ S →+* R ⧸ T := - Ideal.Quotient.lift S (mk T) fun _ hx => eq_zero_iff_mem.2 (H hx) - -@[simp] -theorem factor_mk (S T : Ideal R) (H : S ≤ T) (x : R) : factor S T H (mk S x) = mk T x := - rfl - -@[simp] -theorem factor_comp_mk (S T : Ideal R) (H : S ≤ T) : (factor S T H).comp (mk S) = mk T := by - ext x - rw [RingHom.comp_apply, factor_mk] - end Quotient -/-- Quotienting by equal ideals gives equivalent rings. - -See also `Submodule.quotEquivOfEq` and `Ideal.quotientEquivAlgOfEq`. --/ -def quotEquivOfEq {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : R ⧸ I ≃+* R ⧸ J := - { Submodule.quotEquivOfEq I J h with - map_mul' := by - rintro ⟨x⟩ ⟨y⟩ - rfl } - -@[simp] -theorem quotEquivOfEq_mk {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) (x : R) : - quotEquivOfEq h (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J x := - rfl - -@[simp] -theorem quotEquivOfEq_symm {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : - (Ideal.quotEquivOfEq h).symm = Ideal.quotEquivOfEq h.symm := by ext; rfl - section Pi variable (ι : Type v) @@ -291,7 +156,7 @@ instance modulePi : Module (R ⧸ I) ((ι → R) ⧸ I.pi ι) where Quotient.liftOn₂' c m (fun r m => Submodule.Quotient.mk <| r • m) <| by intro c₁ m₁ c₂ m₂ hc hm apply Ideal.Quotient.eq.2 - rw [Submodule.quotientRel_r_def] at hc hm + rw [Submodule.quotientRel_def] at hc hm intro i exact I.mul_sub_mul_mem hc (hm i) one_smul := by @@ -322,7 +187,7 @@ instance modulePi : Module (R ⧸ I) ((ι → R) ⧸ I.pi ι) where /-- `R^n/I^n` is isomorphic to `(R/I)^n` as an `R/I`-module. -/ noncomputable def piQuotEquiv : ((ι → R) ⧸ I.pi ι) ≃ₗ[R ⧸ I] ι → (R ⧸ I) where toFun := fun x ↦ - Quotient.liftOn' x (fun f i => Ideal.Quotient.mk I (f i)) fun a b hab => + Quotient.liftOn' x (fun f i => Ideal.Quotient.mk I (f i)) fun _ _ hab => funext fun i => (Submodule.Quotient.eq' _).2 (QuotientAddGroup.leftRel_apply.mp hab i) map_add' := by rintro ⟨_⟩ ⟨_⟩; rfl map_smul' := by rintro ⟨_⟩ ⟨_⟩; rfl @@ -348,4 +213,14 @@ theorem map_pi {ι : Type*} [Finite ι] {ι' : Type w} (x : ι → R) (hi : ∀ end Pi +open scoped Pointwise in +/-- A ring is made up of a disjoint union of cosets of an ideal. -/ +lemma univ_eq_iUnion_image_add {R : Type*} [Ring R] (I : Ideal R) : + (Set.univ (α := R)) = ⋃ x : R ⧸ I, x.out' +ᵥ (I : Set R) := + QuotientAddGroup.univ_eq_iUnion_vadd I.toAddSubgroup + +lemma _root_.Finite.of_finite_quot_finite_ideal {R : Type*} [Ring R] {I : Ideal R} + [hI : Finite I] [h : Finite (R ⧸ I)] : Finite R := + @Finite.of_finite_quot_finite_addSubgroup _ _ _ hI h + end Ideal diff --git a/Mathlib/RingTheory/Ideal/Quotient/Defs.lean b/Mathlib/RingTheory/Ideal/Quotient/Defs.lean new file mode 100644 index 0000000000000..16ccd620390d8 --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Quotient/Defs.lean @@ -0,0 +1,180 @@ +/- +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, Anne Baanen +-/ +import Mathlib.LinearAlgebra.Quotient.Defs +import Mathlib.RingTheory.Congruence.Defs +import Mathlib.RingTheory.Ideal.Defs + +/-! +# Ideal quotients + +This file defines ideal quotients as a special case of submodule quotients and proves some basic +results about these quotients. + +See `Algebra.RingQuot` for quotients of non-commutative rings. + +## Main definitions + + - `Ideal.instHasQuotient`: the quotient of a commutative ring `R` by an ideal `I : Ideal R` + - `Ideal.Quotient.commRing`: the ring structure of the ideal quotient + - `Ideal.Quotient.mk`: map an element of `R` to the quotient `R ⧸ I` + - `Ideal.Quotient.lift`: turn a map `R → S` into a map `R ⧸ I → S` + - `Ideal.quotEquivOfEq`: quotienting by equal ideals gives isomorphic rings +-/ + + +universe u v w + +namespace Ideal + +open Set + +variable {R : Type u} [CommRing R] (I : Ideal R) {a b : R} +variable {S : Type v} + +-- Note that at present `Ideal` means a left-ideal, +-- so this quotient is only useful in a commutative ring. +-- We should develop quotients by two-sided ideals as well. +/-- The quotient `R/I` of a ring `R` by an ideal `I`. + +The ideal quotient of `I` is defined to equal the quotient of `I` as an `R`-submodule of `R`. +This definition uses `abbrev` so that typeclass instances can be shared between +`Ideal.Quotient I` and `Submodule.Quotient I`. +-/ +@[instance] abbrev instHasQuotient : HasQuotient R (Ideal R) := + Submodule.hasQuotient + +namespace Quotient + +variable {I} {x y : R} + +instance one (I : Ideal R) : One (R ⧸ I) := + ⟨Submodule.Quotient.mk 1⟩ + +/-- On `Ideal`s, `Submodule.quotientRel` is a ring congruence. -/ +protected def ringCon (I : Ideal R) : RingCon R := + { QuotientAddGroup.con I.toAddSubgroup with + mul' := fun {a₁ b₁ a₂ b₂} h₁ h₂ => by + rw [Submodule.quotientRel_def] at h₁ h₂ ⊢ + have F := I.add_mem (I.mul_mem_left a₂ h₁) (I.mul_mem_right b₁ h₂) + have : a₁ * a₂ - b₁ * b₂ = a₂ * (a₁ - b₁) + (a₂ - b₂) * b₁ := by + rw [mul_sub, sub_mul, sub_add_sub_cancel, mul_comm, mul_comm b₁] + rwa [← this] at F } + +instance commRing (I : Ideal R) : CommRing (R ⧸ I) := + inferInstanceAs (CommRing (Quotient.ringCon I).Quotient) + +-- Sanity test to make sure no diamonds have emerged in `commRing` +example : (commRing I).toAddCommGroup = Submodule.Quotient.addCommGroup I := rfl + +/-- The ring homomorphism from a ring `R` to a quotient ring `R/I`. -/ +def mk (I : Ideal R) : R →+* R ⧸ I where + toFun a := Submodule.Quotient.mk a + map_zero' := rfl + map_one' := rfl + map_mul' _ _ := rfl + map_add' _ _ := rfl + +instance {I : Ideal R} : Coe R (R ⧸ I) := + ⟨Ideal.Quotient.mk I⟩ + +/-- Two `RingHom`s from the quotient by an ideal are equal if their +compositions with `Ideal.Quotient.mk'` are equal. + +See note [partially-applied ext lemmas]. -/ +@[ext 1100] +theorem ringHom_ext [NonAssocSemiring S] ⦃f g : R ⧸ I →+* S⦄ (h : f.comp (mk I) = g.comp (mk I)) : + f = g := + RingHom.ext fun x => Quotient.inductionOn' x <| (RingHom.congr_fun h : _) + +instance inhabited : Inhabited (R ⧸ I) := + ⟨mk I 37⟩ + +protected theorem eq : mk I x = mk I y ↔ x - y ∈ I := + Submodule.Quotient.eq I + +@[simp] +theorem mk_eq_mk (x : R) : (Submodule.Quotient.mk x : R ⧸ I) = mk I x := rfl + +theorem eq_zero_iff_mem {I : Ideal R} : mk I a = 0 ↔ a ∈ I := + Submodule.Quotient.mk_eq_zero _ + +theorem mk_eq_mk_iff_sub_mem (x y : R) : mk I x = mk I y ↔ x - y ∈ I := by + rw [← eq_zero_iff_mem, map_sub, sub_eq_zero] + +theorem mk_surjective : Function.Surjective (mk I) := fun y => + Quotient.inductionOn' y fun x => Exists.intro x rfl + +instance : RingHomSurjective (mk I) := + ⟨mk_surjective⟩ + +/-- If `I` is an ideal of a commutative ring `R`, if `q : R → R/I` is the quotient map, and if +`s ⊆ R` is a subset, then `q⁻¹(q(s)) = ⋃ᵢ(i + s)`, the union running over all `i ∈ I`. -/ +theorem quotient_ring_saturate (I : Ideal R) (s : Set R) : + mk I ⁻¹' (mk I '' s) = ⋃ x : I, (fun y => x.1 + y) '' s := by + ext x + simp only [mem_preimage, mem_image, mem_iUnion, Ideal.Quotient.eq] + exact + ⟨fun ⟨a, a_in, h⟩ => ⟨⟨_, I.neg_mem h⟩, a, a_in, by simp⟩, fun ⟨⟨i, hi⟩, a, ha, Eq⟩ => + ⟨a, ha, by rw [← Eq, sub_add_eq_sub_sub_swap, sub_self, zero_sub]; exact I.neg_mem hi⟩⟩ + +variable [Semiring S] + +/-- Given a ring homomorphism `f : R →+* S` sending all elements of an ideal to zero, +lift it to the quotient by this ideal. -/ +def lift (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : R ⧸ I →+* S := + { QuotientAddGroup.lift I.toAddSubgroup f.toAddMonoidHom H with + map_one' := f.map_one + map_mul' := fun a₁ a₂ => Quotient.inductionOn₂' a₁ a₂ f.map_mul } + +@[simp] +theorem lift_mk (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : + lift I f H (mk I a) = f a := + rfl + +theorem lift_surjective_of_surjective (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) + (hf : Function.Surjective f) : Function.Surjective (Ideal.Quotient.lift I f H) := by + intro y + obtain ⟨x, rfl⟩ := hf y + use Ideal.Quotient.mk I x + simp only [Ideal.Quotient.lift_mk] + +/-- The ring homomorphism from the quotient by a smaller ideal to the quotient by a larger ideal. + +This is the `Ideal.Quotient` version of `Quot.Factor` -/ +def factor (S T : Ideal R) (H : S ≤ T) : R ⧸ S →+* R ⧸ T := + Ideal.Quotient.lift S (mk T) fun _ hx => eq_zero_iff_mem.2 (H hx) + +@[simp] +theorem factor_mk (S T : Ideal R) (H : S ≤ T) (x : R) : factor S T H (mk S x) = mk T x := + rfl + +@[simp] +theorem factor_comp_mk (S T : Ideal R) (H : S ≤ T) : (factor S T H).comp (mk S) = mk T := by + ext x + rw [RingHom.comp_apply, factor_mk] + +end Quotient + +/-- Quotienting by equal ideals gives equivalent rings. + +See also `Submodule.quotEquivOfEq` and `Ideal.quotientEquivAlgOfEq`. +-/ +def quotEquivOfEq {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : R ⧸ I ≃+* R ⧸ J := + { Submodule.quotEquivOfEq I J h with + map_mul' := by + rintro ⟨x⟩ ⟨y⟩ + rfl } + +@[simp] +theorem quotEquivOfEq_mk {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) (x : R) : + quotEquivOfEq h (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J x := + rfl + +@[simp] +theorem quotEquivOfEq_symm {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : + (Ideal.quotEquivOfEq h).symm = Ideal.quotEquivOfEq h.symm := by ext; rfl + +end Ideal diff --git a/Mathlib/RingTheory/QuotientNilpotent.lean b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean similarity index 98% rename from Mathlib/RingTheory/QuotientNilpotent.lean rename to Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean index 79300ab5bd018..f37051e0c6331 100644 --- a/Mathlib/RingTheory/QuotientNilpotent.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Nilpotent.Lemmas -import Mathlib.RingTheory.Ideal.QuotientOperations /-! # Nilpotent elements in quotient rings diff --git a/Mathlib/RingTheory/QuotientNoetherian.lean b/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean similarity index 89% rename from Mathlib/RingTheory/QuotientNoetherian.lean rename to Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean index b8a7d3337c213..e60aaec70aca0 100644 --- a/Mathlib/RingTheory/QuotientNoetherian.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Noetherian -import Mathlib.RingTheory.Ideal.QuotientOperations /-! # Noetherian quotient rings and quotient modules diff --git a/Mathlib/RingTheory/Ideal/QuotientOperations.lean b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean similarity index 94% rename from Mathlib/RingTheory/Ideal/QuotientOperations.lean rename to Mathlib/RingTheory/Ideal/Quotient/Operations.lean index 5fb624f6f2143..20fe91eb1a90e 100644 --- a/Mathlib/RingTheory/Ideal/QuotientOperations.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean @@ -5,7 +5,8 @@ Authors: Kenny Lau, Patrick Massot -/ import Mathlib.Algebra.Algebra.Subalgebra.Operations import Mathlib.Algebra.Ring.Fin -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic +import Mathlib.RingTheory.Ideal.Quotient.Basic /-! # More operations on modules and ideals related to quotients @@ -479,6 +480,12 @@ theorem quotientMap_comp_mk {J : Ideal R} {I : Ideal S} {f : R →+* S} (H : J (quotientMap I f H).comp (Quotient.mk J) = (Quotient.mk I).comp f := RingHom.ext fun x => by simp only [Function.comp_apply, RingHom.coe_comp, Ideal.quotientMap_mk] +lemma ker_quotientMap_mk {I J : Ideal R} : + RingHom.ker (quotientMap (J.map _) (Quotient.mk I) le_comap_map) = I.map (Quotient.mk J) := by + rw [Ideal.quotientMap, Ideal.ker_quotient_lift, ← RingHom.comap_ker, Ideal.mk_ker, + Ideal.comap_map_of_surjective _ Ideal.Quotient.mk_surjective, + ← RingHom.ker_eq_comap_bot, Ideal.mk_ker, Ideal.map_sup, Ideal.map_quotient_self, bot_sup_eq] + /-- The ring equiv `R/I ≃+* S/J` induced by a ring equiv `f : R ≃+* S`, where `J = f(I)`. -/ @[simps] def quotientEquiv (I : Ideal R) (J : Ideal S) (f : R ≃+* S) (hIJ : J = I.map (f : R →+* S)) : @@ -492,7 +499,7 @@ def quotientEquiv (I : Ideal R) (J : Ideal S) (f : R ≃+* S) (hIJ : J = I.map ( quotientMap I (↑f.symm) (by rw [hIJ] - exact le_of_eq (map_comap_of_equiv I f)) + exact le_of_eq (map_comap_of_equiv f)) left_inv := by rintro ⟨r⟩ simp only [Submodule.Quotient.quot_mk_eq_mk, Quotient.mk_eq_mk, RingHom.toFun_eq_coe, @@ -932,3 +939,47 @@ theorem quotQuotEquivQuotOfLE_symm_comp_mkₐ (h : I ≤ J) : end AlgebraQuotient end DoubleQuot + +namespace Ideal + +section PowQuot + +variable {R : Type*} [CommRing R] (I : Ideal R) (n : ℕ) + +/-- `I ^ n ⧸ I ^ (n + 1)` can be viewed as a quotient module and as ideal of `R ⧸ I ^ (n + 1)`. +This definition gives the `R`-linear equivalence between the two. -/ +noncomputable +def powQuotPowSuccLinearEquivMapMkPowSuccPow : + ((I ^ n : Ideal R) ⧸ (I • ⊤ : Submodule R (I ^ n : Ideal R))) ≃ₗ[R] + Ideal.map (Ideal.Quotient.mk (I ^ (n + 1))) (I ^ n) := by + refine { LinearMap.codRestrict + (Submodule.restrictScalars _ (Ideal.map (Ideal.Quotient.mk (I ^ (n + 1))) (I ^ n))) + (Submodule.mapQ (I • ⊤) (I ^ (n + 1)) (Submodule.subtype (I ^ n)) ?_) ?_, + Equiv.ofBijective _ ⟨?_, ?_⟩ with } + · intro + simp [Submodule.mem_smul_top_iff, pow_succ'] + · intro x + obtain ⟨⟨y, hy⟩, rfl⟩ := Submodule.Quotient.mk_surjective _ x + simp [Ideal.mem_sup_left hy] + · intro a b + obtain ⟨⟨x, hx⟩, rfl⟩ := Submodule.Quotient.mk_surjective _ a + obtain ⟨⟨y, hy⟩, rfl⟩ := Submodule.Quotient.mk_surjective _ b + simp [Ideal.Quotient.eq, Submodule.Quotient.eq, Submodule.mem_smul_top_iff, pow_succ'] + · intro ⟨x, hx⟩ + rw [Ideal.mem_map_iff_of_surjective _ Ideal.Quotient.mk_surjective] at hx + obtain ⟨y, hy, rfl⟩ := hx + refine ⟨Submodule.Quotient.mk ⟨y, hy⟩, ?_⟩ + simp + +/-- `I ^ n ⧸ I ^ (n + 1)` can be viewed as a quotient module and as ideal of `R ⧸ I ^ (n + 1)`. +This definition gives the equivalence between the two, instead of the `R`-linear equivalence, +to bypass typeclass synthesis issues on complex `Module` goals. -/ +noncomputable +def powQuotPowSuccEquivMapMkPowSuccPow : + ((I ^ n : Ideal R) ⧸ (I • ⊤ : Submodule R (I ^ n : Ideal R))) ≃ + Ideal.map (Ideal.Quotient.mk (I ^ (n + 1))) (I ^ n) := + powQuotPowSuccLinearEquivMapMkPowSuccPow I n + +end PowQuot + +end Ideal diff --git a/Mathlib/RingTheory/Ideal/Span.lean b/Mathlib/RingTheory/Ideal/Span.lean new file mode 100644 index 0000000000000..938dbdc642954 --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Span.lean @@ -0,0 +1,239 @@ +/- +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.Associated.Basic +import Mathlib.Algebra.Ring.Regular +import Mathlib.LinearAlgebra.Span +import Mathlib.RingTheory.Ideal.Lattice +import Mathlib.Tactic.Ring + +/-! +# Ideals generated by a set of elements + +This file defines `Ideal.span s` as the ideal generated by the subset `s` of the ring. + +## TODO + +Support right ideals, and two-sided ideals over non-commutative rings. +-/ + + +universe u v w + +variable {α : Type u} {β : Type v} {F : Type w} + +open Set Function + +open Pointwise + +/-- A ring is a principal ideal ring if all (left) ideals are principal. -/ +@[mk_iff] +class IsPrincipalIdealRing (R : Type u) [Semiring R] : Prop where + principal : ∀ S : Ideal R, S.IsPrincipal + +attribute [instance] IsPrincipalIdealRing.principal + +section Semiring + +namespace Ideal + +variable [Semiring α] (I : Ideal α) {a b : α} + +/-- The ideal generated by a subset of a ring -/ +def span (s : Set α) : Ideal α := + Submodule.span α s + +@[simp] +theorem submodule_span_eq {s : Set α} : Submodule.span α s = Ideal.span s := + rfl + +@[simp] +theorem span_empty : span (∅ : Set α) = ⊥ := + Submodule.span_empty + +@[simp] +theorem span_univ : span (Set.univ : Set α) = ⊤ := + Submodule.span_univ + +theorem span_union (s t : Set α) : span (s ∪ t) = span s ⊔ span t := + Submodule.span_union _ _ + +theorem span_iUnion {ι} (s : ι → Set α) : span (⋃ i, s i) = ⨆ i, span (s i) := + Submodule.span_iUnion _ + +theorem mem_span {s : Set α} (x) : x ∈ span s ↔ ∀ p : Ideal α, s ⊆ p → x ∈ p := + mem_iInter₂ + +theorem subset_span {s : Set α} : s ⊆ span s := + Submodule.subset_span + +theorem span_le {s : Set α} {I} : span s ≤ I ↔ s ⊆ I := + Submodule.span_le + +theorem span_mono {s t : Set α} : s ⊆ t → span s ≤ span t := + Submodule.span_mono + +@[simp] +theorem span_eq : span (I : Set α) = I := + Submodule.span_eq _ + +@[simp] +theorem span_singleton_one : span ({1} : Set α) = ⊤ := + (eq_top_iff_one _).2 <| subset_span <| mem_singleton _ + +theorem isCompactElement_top : CompleteLattice.IsCompactElement (⊤ : Ideal α) := by + simpa only [← span_singleton_one] using Submodule.singleton_span_isCompactElement 1 + +theorem mem_span_insert {s : Set α} {x y} : + x ∈ span (insert y s) ↔ ∃ a, ∃ z ∈ span s, x = a * y + z := + Submodule.mem_span_insert + +theorem mem_span_singleton' {x y : α} : x ∈ span ({y} : Set α) ↔ ∃ a, a * y = x := + Submodule.mem_span_singleton + +theorem mem_span_singleton_self (x : α) : x ∈ span ({x} : Set α) := + Submodule.mem_span_singleton_self x + +theorem span_singleton_le_iff_mem {x : α} : span {x} ≤ I ↔ x ∈ I := + Submodule.span_singleton_le_iff_mem _ _ + +theorem span_singleton_mul_left_unit {a : α} (h2 : IsUnit a) (x : α) : + span ({a * x} : Set α) = span {x} := by + apply le_antisymm <;> rw [span_singleton_le_iff_mem, mem_span_singleton'] + exacts [⟨a, rfl⟩, ⟨_, h2.unit.inv_mul_cancel_left x⟩] + +theorem span_insert (x) (s : Set α) : span (insert x s) = span ({x} : Set α) ⊔ span s := + Submodule.span_insert x s + +theorem span_eq_bot {s : Set α} : span s = ⊥ ↔ ∀ x ∈ s, (x : α) = 0 := + Submodule.span_eq_bot + +@[simp] +theorem span_singleton_eq_bot {x} : span ({x} : Set α) = ⊥ ↔ x = 0 := + Submodule.span_singleton_eq_bot + +theorem span_singleton_ne_top {α : Type*} [CommSemiring α] {x : α} (hx : ¬IsUnit x) : + Ideal.span ({x} : Set α) ≠ ⊤ := + (Ideal.ne_top_iff_one _).mpr fun h1 => + let ⟨y, hy⟩ := Ideal.mem_span_singleton'.mp h1 + hx ⟨⟨x, y, mul_comm y x ▸ hy, hy⟩, rfl⟩ + +@[simp] +theorem span_zero : span (0 : Set α) = ⊥ := by rw [← Set.singleton_zero, span_singleton_eq_bot] + +@[simp] +theorem span_one : span (1 : Set α) = ⊤ := by rw [← Set.singleton_one, span_singleton_one] + +theorem span_eq_top_iff_finite (s : Set α) : + span s = ⊤ ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ span (s' : Set α) = ⊤ := by + simp_rw [eq_top_iff_one] + exact ⟨Submodule.mem_span_finite_of_mem_span, fun ⟨s', h₁, h₂⟩ => span_mono h₁ h₂⟩ + +theorem mem_span_singleton_sup {x y : α} {I : Ideal α} : + x ∈ Ideal.span {y} ⊔ I ↔ ∃ a : α, ∃ b ∈ I, a * y + b = x := by + rw [Submodule.mem_sup] + constructor + · rintro ⟨ya, hya, b, hb, rfl⟩ + obtain ⟨a, rfl⟩ := mem_span_singleton'.mp hya + exact ⟨a, b, hb, rfl⟩ + · rintro ⟨a, b, hb, rfl⟩ + exact ⟨a * y, Ideal.mem_span_singleton'.mpr ⟨a, rfl⟩, b, hb, rfl⟩ + +/-- The ideal generated by an arbitrary binary relation. +-/ +def ofRel (r : α → α → Prop) : Ideal α := + Submodule.span α { x | ∃ a b, r a b ∧ x + b = a } + +theorem zero_ne_one_of_proper {I : Ideal α} (h : I ≠ ⊤) : (0 : α) ≠ 1 := fun hz => + I.ne_top_iff_one.1 h <| hz ▸ I.zero_mem + +theorem span_pair_comm {x y : α} : (span {x, y} : Ideal α) = span {y, x} := by + simp only [span_insert, sup_comm] + +theorem mem_span_pair {x y z : α} : z ∈ span ({x, y} : Set α) ↔ ∃ a b, a * x + b * y = z := + Submodule.mem_span_pair + +@[simp] +theorem span_pair_add_mul_left {R : Type u} [CommRing R] {x y : R} (z : R) : + (span {x + y * z, y} : Ideal R) = span {x, y} := by + ext + rw [mem_span_pair, mem_span_pair] + exact + ⟨fun ⟨a, b, h⟩ => + ⟨a, b + a * z, by + rw [← h] + ring1⟩, + fun ⟨a, b, h⟩ => + ⟨a, b - a * z, by + rw [← h] + ring1⟩⟩ + +@[simp] +theorem span_pair_add_mul_right {R : Type u} [CommRing R] {x y : R} (z : R) : + (span {x, y + x * z} : Ideal R) = span {x, y} := by + rw [span_pair_comm, span_pair_add_mul_left, span_pair_comm] + +end Ideal + +end Semiring + +section CommSemiring + +variable {a b : α} + +-- A separate namespace definition is needed because the variables were historically in a different +-- order. +namespace Ideal + +variable [CommSemiring α] (I : Ideal α) + +theorem mem_span_singleton {x y : α} : x ∈ span ({y} : Set α) ↔ y ∣ x := + mem_span_singleton'.trans <| exists_congr fun _ => by rw [eq_comm, mul_comm] + +theorem span_singleton_le_span_singleton {x y : α} : + span ({x} : Set α) ≤ span ({y} : Set α) ↔ y ∣ x := + span_le.trans <| singleton_subset_iff.trans mem_span_singleton + +theorem span_singleton_eq_span_singleton {α : Type u} [CommRing α] [IsDomain α] {x y : α} : + span ({x} : Set α) = span ({y} : Set α) ↔ Associated x y := by + rw [← dvd_dvd_iff_associated, le_antisymm_iff, and_comm] + apply and_congr <;> rw [span_singleton_le_span_singleton] + +theorem span_singleton_mul_right_unit {a : α} (h2 : IsUnit a) (x : α) : + span ({x * a} : Set α) = span {x} := by rw [mul_comm, span_singleton_mul_left_unit h2] + +@[simp] +theorem span_singleton_eq_top {x} : span ({x} : Set α) = ⊤ ↔ IsUnit x := by + rw [isUnit_iff_dvd_one, ← span_singleton_le_span_singleton, span_singleton_one, eq_top_iff] + +theorem factors_decreasing [IsDomain α] (b₁ b₂ : α) (h₁ : b₁ ≠ 0) (h₂ : ¬IsUnit b₂) : + span ({b₁ * b₂} : Set α) < span {b₁} := + lt_of_le_not_le + (Ideal.span_le.2 <| singleton_subset_iff.2 <| Ideal.mem_span_singleton.2 ⟨b₂, rfl⟩) fun h => + h₂ <| isUnit_of_dvd_one <| + (mul_dvd_mul_iff_left h₁).1 <| by rwa [mul_one, ← Ideal.span_singleton_le_span_singleton] + +end Ideal + +end CommSemiring + +section Ring + +namespace Ideal + +variable [Ring α] (I : Ideal α) {a b : α} + +theorem mem_span_insert' {s : Set α} {x y} : x ∈ span (insert y s) ↔ ∃ a, x + a * y ∈ span s := + Submodule.mem_span_insert' + +@[simp] +theorem span_singleton_neg (x : α) : (span {-x} : Ideal α) = span {x} := by + ext + simp only [mem_span_singleton'] + exact ⟨fun ⟨y, h⟩ => ⟨-y, h ▸ neg_mul_comm y x⟩, fun ⟨y, h⟩ => ⟨-y, h ▸ neg_mul_neg y x⟩⟩ + +end Ideal + +end Ring diff --git a/Mathlib/RingTheory/Idempotents.lean b/Mathlib/RingTheory/Idempotents.lean index 2e8db654b863c..ffc85853ec287 100644 --- a/Mathlib/RingTheory/Idempotents.lean +++ b/Mathlib/RingTheory/Idempotents.lean @@ -5,7 +5,7 @@ Authors: Andrew Yang -/ import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Polynomial.AlgebraMap -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Nilpotent.Defs /-! @@ -214,8 +214,6 @@ A family `{ eᵢ }` of idempotent elements is complete orthogonal if structure CompleteOrthogonalIdempotents (e : I → R) extends OrthogonalIdempotents e : Prop where complete : ∑ i, e i = 1 -variable (he : CompleteOrthogonalIdempotents e) - lemma CompleteOrthogonalIdempotents.unique_iff [Unique I] : CompleteOrthogonalIdempotents e ↔ e default = 1 := by rw [completeOrthogonalIdempotents_iff, OrthogonalIdempotents.unique, Fintype.sum_unique, @@ -404,7 +402,7 @@ lemma CompleteOrthogonalIdempotents.bijective_pi (he : CompleteOrthogonalIdempot refine ⟨?_, he.1.surjective_pi⟩ rw [injective_iff_map_eq_zero] intro x hx - simp [Function.funext_iff, Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton] at hx + simp [funext_iff, Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton] at hx suffices ∀ s : Finset I, (∏ i in s, (1 - e i)) * x = x by rw [← this Finset.univ, he.prod_one_sub, zero_mul] refine fun s ↦ Finset.induction_on s (by simp) ?_ diff --git a/Mathlib/RingTheory/Int/Basic.lean b/Mathlib/RingTheory/Int/Basic.lean index 2f194c3abb9aa..be4be78dc6d35 100644 --- a/Mathlib/RingTheory/Int/Basic.lean +++ b/Mathlib/RingTheory/Int/Basic.lean @@ -5,9 +5,9 @@ Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson -/ import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.Algebra.EuclideanDomain.Int -import Mathlib.RingTheory.PrincipalIdealDomain import Mathlib.Algebra.GCDMonoid.Nat -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Int +import Mathlib.RingTheory.PrincipalIdealDomain /-! # Divisibility over ℕ and ℤ diff --git a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean index 37343ddf2c611..0f9874f3e5ae8 100644 --- a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean @@ -28,15 +28,22 @@ variable {R A B S : Type*} variable [CommRing R] [CommRing A] [Ring B] [CommRing S] variable [Algebra R A] [Algebra R B] (f : R →+* S) +theorem Subalgebra.isIntegral_iff (S : Subalgebra R A) : + Algebra.IsIntegral R S ↔ ∀ x ∈ S, IsIntegral R x := + Algebra.isIntegral_def.trans <| .trans + (forall_congr' fun _ ↦ (isIntegral_algHom_iff S.val Subtype.val_injective).symm) Subtype.forall + section variable {A B : Type*} [Ring A] [Ring B] [Algebra R A] [Algebra R B] -variable (f : A →ₐ[R] B) (hf : Function.Injective f) -theorem Algebra.IsIntegral.of_injective (hf : Function.Injective f) [Algebra.IsIntegral R B] : - Algebra.IsIntegral R A := +theorem Algebra.IsIntegral.of_injective (f : A →ₐ[R] B) (hf : Function.Injective f) + [Algebra.IsIntegral R B] : Algebra.IsIntegral R A := ⟨fun _ ↦ (isIntegral_algHom_iff f hf).mp (isIntegral _)⟩ +theorem AlgEquiv.isIntegral_iff (e : A ≃ₐ[R] B) : Algebra.IsIntegral R A ↔ Algebra.IsIntegral R B := + ⟨fun h ↦ h.of_injective e.symm e.symm.injective, fun h ↦ h.of_injective e e.injective⟩ + end instance Module.End.isIntegral {M : Type*} [AddCommGroup M] [Module R M] [Module.Finite R M] : @@ -57,8 +64,8 @@ instance Algebra.IsIntegral.of_finite [Module.Finite R B] : Algebra.IsIntegral R /-- If `S` is a sub-`R`-algebra of `A` and `S` is finitely-generated as an `R`-module, then all elements of `S` are integral over `R`. -/ -theorem IsIntegral.of_mem_of_fg {A} [Ring A] [Algebra R A] (S : Subalgebra R A) - (HS : S.toSubmodule.FG) (x : A) (hx : x ∈ S) : IsIntegral R x := +theorem IsIntegral.of_mem_of_fg (S : Subalgebra R B) + (HS : S.toSubmodule.FG) (x : B) (hx : x ∈ S) : IsIntegral R x := have : Module.Finite R S := ⟨(fg_top _).mpr HS⟩ (isIntegral_algHom_iff S.val Subtype.val_injective).mpr (.of_finite R (⟨x, hx⟩ : S)) diff --git a/Mathlib/RingTheory/IntegralClosure/Algebra/Defs.lean b/Mathlib/RingTheory/IntegralClosure/Algebra/Defs.lean index 8e9ef7deed80b..58e184777c8f9 100644 --- a/Mathlib/RingTheory/IntegralClosure/Algebra/Defs.lean +++ b/Mathlib/RingTheory/IntegralClosure/Algebra/Defs.lean @@ -29,7 +29,7 @@ variable [Algebra R A] (R) variable (A) /-- An algebra is integral if every element of the extension is integral over the base ring. -/ -protected class Algebra.IsIntegral : Prop := +protected class Algebra.IsIntegral : Prop where isIntegral : ∀ x : A, IsIntegral R x variable {R A} diff --git a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean index c987ccc2c77c5..e4a5c700b65ef 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.RingTheory.Localization.Integral +import Mathlib.RingTheory.Localization.LocalizationLocalization /-! # Integrally closed rings @@ -275,6 +276,27 @@ theorem isIntegrallyClosedOfFiniteExtension [IsDomain R] [FiniteDimensional K L] end integralClosure +section localization + +variable {R : Type*} (S : Type*) [CommRing R] [CommRing S] [Algebra R S] + +lemma isIntegrallyClosed_of_isLocalization [IsIntegrallyClosed R] [IsDomain R] (M : Submonoid R) + (hM : M ≤ R⁰) [IsLocalization M S] : IsIntegrallyClosed S := by + let K := FractionRing R + let g : S →+* K := IsLocalization.map _ (T := R⁰) (RingHom.id R) hM + letI := g.toAlgebra + have : IsScalarTower R S K := IsScalarTower.of_algebraMap_eq' + (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, RingHomCompTriple.comp_eq]) + have := IsFractionRing.isFractionRing_of_isDomain_of_isLocalization M S K + refine (isIntegrallyClosed_iff_isIntegralClosure (K := K)).mpr + ⟨IsFractionRing.injective _ _, fun {x} ↦ ⟨?_, fun e ↦ e.choose_spec ▸ isIntegral_algebraMap⟩⟩ + intro hx + obtain ⟨⟨y, y_mem⟩, hy⟩ := hx.exists_multiple_integral_of_isLocalization M _ + obtain ⟨z, hz⟩ := (isIntegrallyClosed_iff _).mp ‹_› hy + refine ⟨IsLocalization.mk' S z ⟨y, y_mem⟩, (IsLocalization.lift_mk'_spec _ _ _ _).mpr ?_⟩ + rw [RingHom.comp_id, hz, ← Algebra.smul_def, Submonoid.mk_smul] + +end localization /-- Any field is integral closed. -/ /- Although `infer_instance` can find this if you import Mathlib, in this file they have not been proven yet. However, it is used to prove a fundamental property of `IsIntegrallyClosed`, diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean index 146fc3d8f12a9..eabc18718c598 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean @@ -19,6 +19,58 @@ We prove basic properties of `IsIntegralClosure`. open scoped Classical open Polynomial Submodule +section inv + +open Algebra + +variable {R S : Type*} + +/-- A nonzero element in a domain integral over a field is a unit. -/ +theorem IsIntegral.isUnit [Field R] [Ring S] [IsDomain S] [Algebra R S] {x : S} + (int : IsIntegral R x) (h0 : x ≠ 0) : IsUnit x := + have : FiniteDimensional R (adjoin R {x}) := ⟨(Submodule.fg_top _).mpr int.fg_adjoin_singleton⟩ + (FiniteDimensional.isUnit R (K := adjoin R {x}) + (x := ⟨x, subset_adjoin rfl⟩) <| mt Subtype.ext_iff.mp h0).map (adjoin R {x}).val + +/-- A commutative domain that is an integral algebra over a field is a field. -/ +theorem isField_of_isIntegral_of_isField' [CommRing R] [CommRing S] [IsDomain S] + [Algebra R S] [Algebra.IsIntegral R S] (hR : IsField R) : IsField S where + exists_pair_ne := ⟨0, 1, zero_ne_one⟩ + mul_comm := mul_comm + mul_inv_cancel {x} hx := by + letI := hR.toField + obtain ⟨y, rfl⟩ := (Algebra.IsIntegral.isIntegral (R := R) x).isUnit hx + exact ⟨y.inv, y.val_inv⟩ + +variable [Field R] [DivisionRing S] [Algebra R S] {x : S} {A : Subalgebra R S} + +theorem IsIntegral.inv_mem_adjoin (int : IsIntegral R x) : x⁻¹ ∈ adjoin R {x} := by + obtain rfl | h0 := eq_or_ne x 0 + · rw [inv_zero]; exact Subalgebra.zero_mem _ + have : FiniteDimensional R (adjoin R {x}) := ⟨(Submodule.fg_top _).mpr int.fg_adjoin_singleton⟩ + obtain ⟨⟨y, hy⟩, h1⟩ := FiniteDimensional.exists_mul_eq_one R + (K := adjoin R {x}) (x := ⟨x, subset_adjoin rfl⟩) (mt Subtype.ext_iff.mp h0) + rwa [← mul_left_cancel₀ h0 ((Subtype.ext_iff.mp h1).trans (mul_inv_cancel₀ h0).symm)] + +/-- The inverse of an integral element in a subalgebra of a division ring over a field + also lies in that subalgebra. -/ +theorem IsIntegral.inv_mem (int : IsIntegral R x) (hx : x ∈ A) : x⁻¹ ∈ A := + adjoin_le_iff.mpr (Set.singleton_subset_iff.mpr hx) int.inv_mem_adjoin + +/-- An integral subalgebra of a division ring over a field is closed under inverses. -/ +theorem Algebra.IsIntegral.inv_mem [Algebra.IsIntegral R A] (hx : x ∈ A) : x⁻¹ ∈ A := + ((isIntegral_algHom_iff A.val Subtype.val_injective).mpr <| + Algebra.IsIntegral.isIntegral (⟨x, hx⟩ : A)).inv_mem hx + +/-- The inverse of an integral element in a division ring over a field is also integral. -/ +theorem IsIntegral.inv (int : IsIntegral R x) : IsIntegral R x⁻¹ := + .of_mem_of_fg _ int.fg_adjoin_singleton _ int.inv_mem_adjoin + +theorem IsIntegral.mem_of_inv_mem (int : IsIntegral R x) (inv_mem : x⁻¹ ∈ A) : x ∈ A := by + rw [← inv_inv x]; exact int.inv.inv_mem inv_mem + +end inv + section variable {R A B S : Type*} @@ -78,10 +130,22 @@ theorem le_integralClosure_iff_isIntegral {S : Subalgebra R A} : isIntegral_algebraMap_iff Subtype.coe_injective).trans Algebra.isIntegral_def.symm +theorem Algebra.IsIntegral.adjoin {S : Set A} (hS : ∀ x ∈ S, IsIntegral R x) : + Algebra.IsIntegral R (Algebra.adjoin R S) := + le_integralClosure_iff_isIntegral.mp <| adjoin_le_iff.mpr hS + +theorem integralClosure_eq_top_iff : integralClosure R A = ⊤ ↔ Algebra.IsIntegral R A := by + rw [← top_le_iff, le_integralClosure_iff_isIntegral, + (Subalgebra.topEquiv (R := R) (A := A)).isIntegral_iff] -- explicit arguments for speedup + theorem Algebra.isIntegral_sup {S T : Subalgebra R A} : Algebra.IsIntegral R (S ⊔ T : Subalgebra R A) ↔ Algebra.IsIntegral R S ∧ Algebra.IsIntegral R T := by - simp only [← le_integralClosure_iff_isIntegral, sup_le_iff] + simp_rw [← le_integralClosure_iff_isIntegral, sup_le_iff] + +theorem Algebra.isIntegral_iSup {ι} (S : ι → Subalgebra R A) : + Algebra.IsIntegral R ↑(iSup S) ↔ ∀ i, Algebra.IsIntegral R (S i) := by + simp_rw [← le_integralClosure_iff_isIntegral, iSup_le_iff] /-- Mapping an integral closure along an `AlgEquiv` gives the integral closure. -/ theorem integralClosure_map_algEquiv [Algebra R S] (f : A ≃ₐ[R] S) : @@ -142,8 +206,8 @@ theorem RingHom.IsIntegralElem.of_mul_unit (x y : S) (r : R) (hr : f r * y = 1) /-- Generalization of `IsIntegral.of_mem_closure` bootstrapped up from that lemma -/ theorem IsIntegral.of_mem_closure' (G : Set A) (hG : ∀ x ∈ G, IsIntegral R x) : ∀ x ∈ Subring.closure G, IsIntegral R x := fun _ hx ↦ - Subring.closure_induction hx hG isIntegral_zero isIntegral_one (fun _ _ ↦ IsIntegral.add) - (fun _ ↦ IsIntegral.neg) fun _ _ ↦ IsIntegral.mul + Subring.closure_induction hG isIntegral_zero isIntegral_one (fun _ _ _ _ ↦ IsIntegral.add) + (fun _ _ ↦ IsIntegral.neg) (fun _ _ _ _ ↦ IsIntegral.mul) hx theorem IsIntegral.of_mem_closure'' {S : Type*} [CommRing S] {f : R →+* S} (G : Set S) (hG : ∀ x ∈ G, f.IsIntegralElem x) : ∀ x ∈ Subring.closure G, f.IsIntegralElem x := fun x hx => @@ -360,6 +424,12 @@ theorem mk'_algebraMap [Algebra R A] [IsScalarTower R A B] (x : R) IsIntegralClosure.mk' A (algebraMap R B x) h = algebraMap R A x := algebraMap_injective A R B <| by rw [algebraMap_mk', ← IsScalarTower.algebraMap_apply] +/-- The integral closure of a field in a commutative domain is always a field. -/ +theorem isField [Algebra R A] [IsScalarTower R A B] [IsDomain A] (hR : IsField R) : + IsField A := + have := IsIntegralClosure.isIntegral_algebra R (A := A) B + isField_of_isIntegral_of_isField' hR + section lift variable (B) {S : Type*} [CommRing S] [Algebra R S] @@ -488,6 +558,18 @@ nonrec theorem RingHom.IsIntegral.tower_bot (hg : Function.Injective g) haveI : IsScalarTower R S T := IsScalarTower.of_algebraMap_eq fun _ ↦ rfl fun x ↦ IsIntegral.tower_bot hg (hfg (g x)) +variable (T) in +/-- Let `T / S / R` be a tower of algebras, `T` is non-trivial and is a torsion free `S`-module, + then if `T` is an integral `R`-algebra, then `S` is an integral `R`-algebra. -/ +theorem Algebra.IsIntegral.tower_bot [Algebra R S] [Algebra R T] [Algebra S T] + [NoZeroSMulDivisors S T] [Nontrivial T] [IsScalarTower R S T] + [h : Algebra.IsIntegral R T] : Algebra.IsIntegral R S where + isIntegral := by + apply RingHom.IsIntegral.tower_bot (algebraMap R S) (algebraMap S T) + (NoZeroSMulDivisors.algebraMap_injective S T) + rw [← IsScalarTower.algebraMap_eq R S T] + exact h.isIntegral + theorem IsIntegral.tower_bot_of_field {R A B : Type*} [CommRing R] [Field A] [CommRing B] [Nontrivial B] [Algebra R A] [Algebra A B] [Algebra R B] [IsScalarTower R A B] {x : A} (h : IsIntegral R (algebraMap A B x)) : IsIntegral R x := @@ -501,6 +583,16 @@ theorem RingHom.isIntegralElem.of_comp {x : T} (h : (g.comp f).IsIntegralElem x) theorem RingHom.IsIntegral.tower_top (h : (g.comp f).IsIntegral) : g.IsIntegral := fun x ↦ RingHom.isIntegralElem.of_comp f g (h x) +variable (R) in +/-- Let `T / S / R` be a tower of algebras, `T` is an integral `R`-algebra, then it is integral + as an `S`-algebra. -/ +theorem Algebra.IsIntegral.tower_top [Algebra R S] [Algebra R T] [Algebra S T] [IsScalarTower R S T] + [h : Algebra.IsIntegral R T] : Algebra.IsIntegral S T where + isIntegral := by + apply RingHom.IsIntegral.tower_top (algebraMap R S) (algebraMap S T) + rw [← IsScalarTower.algebraMap_eq R S T] + exact h.isIntegral + theorem RingHom.IsIntegral.quotient {I : Ideal S} (hf : f.IsIntegral) : (Ideal.quotientMap I f le_rfl).IsIntegral := by rintro ⟨x⟩ @@ -508,6 +600,9 @@ theorem RingHom.IsIntegral.quotient {I : Ideal S} (hf : f.IsIntegral) : refine ⟨p.map (Ideal.Quotient.mk _), p_monic.map _, ?_⟩ simpa only [hom_eval₂, eval₂_map] using congr_arg (Ideal.Quotient.mk I) hpx +instance {I : Ideal A} [Algebra.IsIntegral R A] : Algebra.IsIntegral R (A ⧸ I) := + Algebra.IsIntegral.trans A + instance Algebra.IsIntegral.quotient {I : Ideal A} [Algebra.IsIntegral R A] : Algebra.IsIntegral (R ⧸ I.comap (algebraMap R A)) (A ⧸ I) := ⟨RingHom.IsIntegral.quotient (algebraMap R A) Algebra.IsIntegral.isIntegral⟩ @@ -543,16 +638,6 @@ theorem isField_of_isIntegral_of_isField {R S : Type*} [CommRing R] [CommRing S] ← (injective_iff_map_eq_zero' _).mp hRS, ← aeval_algebraMap_apply_eq_algebraMap_eval] rwa [← eval₂_reverse_eq_zero_iff] at hp -theorem isField_of_isIntegral_of_isField' {R S : Type*} [CommRing R] [CommRing S] [IsDomain S] - [Algebra R S] [Algebra.IsIntegral R S] (hR : IsField R) : IsField S := by - refine ⟨⟨0, 1, zero_ne_one⟩, mul_comm, fun {x} hx ↦ ?_⟩ - have : Module.Finite R (adjoin R {x}) := ⟨(Submodule.fg_top _).mpr - (Algebra.IsIntegral.isIntegral x).fg_adjoin_singleton⟩ - letI := hR.toField - obtain ⟨y, hy⟩ := FiniteDimensional.exists_mul_eq_one R - (K := adjoin R {x}) (x := ⟨x, subset_adjoin rfl⟩) (mt Subtype.ext_iff.mp hx) - exact ⟨y, Subtype.ext_iff.mp hy⟩ - theorem Algebra.IsIntegral.isField_iff_isField {R S : Type*} [CommRing R] [CommRing S] [IsDomain S] [Algebra R S] [Algebra.IsIntegral R S] (hRS : Function.Injective (algebraMap R S)) : IsField R ↔ IsField S := diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index 2d5e9ee2a2c51..b292e8b1c1ffc 100644 --- a/Mathlib/RingTheory/IntegralDomain.lean +++ b/Mathlib/RingTheory/IntegralDomain.lean @@ -92,9 +92,9 @@ def Fintype.divisionRingOfIsDomain (R : Type*) [Ring R] [IsDomain R] [DecidableE __ := Fintype.groupWithZeroOfCancel R __ := ‹Ring R› nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl /-- Every finite commutative domain is a field. More generally, commutativity is not required: this can be found in `Mathlib.RingTheory.LittleWedderburn`. -/ @@ -109,14 +109,12 @@ end Ring variable [CommRing R] [IsDomain R] [Group G] --- Porting note: Finset doesn't seem to have `{g ∈ univ | g^n = g₀}` notation anymore, --- so we have to use `Finset.filter` instead theorem card_nthRoots_subgroup_units [Fintype G] [DecidableEq G] (f : G →* R) (hf : Injective f) {n : ℕ} (hn : 0 < n) (g₀ : G) : - Finset.card (Finset.univ.filter (fun g ↦ g^n = g₀)) ≤ Multiset.card (nthRoots n (f g₀)) := by + #{g | g ^ n = g₀} ≤ Multiset.card (nthRoots n (f g₀)) := by haveI : DecidableEq R := Classical.decEq _ calc - _ ≤ (nthRoots n (f g₀)).toFinset.card := card_le_card_of_injOn f (by aesop) hf.injOn + _ ≤ #(nthRoots n (f g₀)).toFinset := card_le_card_of_injOn f (by aesop) hf.injOn _ ≤ _ := (nthRoots n (f g₀)).toFinset_card_le /-- A finite subgroup of the unit group of an integral domain is cyclic. -/ @@ -194,12 +192,11 @@ theorem sum_hom_units_eq_zero (f : G →* R) (hf : f ≠ 1) : ∑ g : G, f g = 0 eq_comm] at hn replace hx1 : (x.val : R) - 1 ≠ 0 := -- Porting note: was `(x : R)` fun h => hx1 (Subtype.eq (Units.ext (sub_eq_zero.1 h))) - let c := (univ.filter fun g => f.toHomUnits g = 1).card + let c := #{g | f.toHomUnits g = 1} calc ∑ g : G, f g = ∑ g : G, (f.toHomUnits g : R) := rfl - _ = ∑ u ∈ univ.image f.toHomUnits, - (univ.filter fun g => f.toHomUnits g = u).card • (u : R) := - (sum_comp ((↑) : Rˣ → R) f.toHomUnits) + _ = ∑ u ∈ univ.image f.toHomUnits, #{g | f.toHomUnits g = u} • (u : R) := + sum_comp ((↑) : Rˣ → R) f.toHomUnits _ = ∑ u ∈ univ.image f.toHomUnits, c • (u : R) := (sum_congr rfl fun u hu => congr_arg₂ _ ?_ rfl) -- remaining goal 1, proven below @@ -211,7 +208,7 @@ theorem sum_hom_units_eq_zero (f : G →* R) (hf : f ≠ 1) : ∑ g : G, f g = 0 -- remaining goal 2, proven below _ = (0 : R) := smul_zero _ · -- remaining goal 1 - show (univ.filter fun g : G => f.toHomUnits g = u).card = c + show #{g : G | f.toHomUnits g = u} = c apply MonoidHom.card_fiber_eq_of_mem_range f.toHomUnits · simpa only [mem_image, mem_univ, true_and, Set.mem_range] using hu · exact ⟨1, f.toHomUnits.map_one⟩ diff --git a/Mathlib/RingTheory/IsAdjoinRoot.lean b/Mathlib/RingTheory/IsAdjoinRoot.lean index 1b153b9e33498..32da2faaaf6e3 100644 --- a/Mathlib/RingTheory/IsAdjoinRoot.lean +++ b/Mathlib/RingTheory/IsAdjoinRoot.lean @@ -141,7 +141,6 @@ theorem aeval_eq (h : IsAdjoinRoot S f) (p : R[X]) : aeval h.root p = h.map p := rw [map_mul, aeval_C, map_pow, aeval_X, RingHom.map_mul, ← h.algebraMap_apply, RingHom.map_pow, map_X] --- @[simp] -- Porting note (#10618): simp can prove this theorem aeval_root (h : IsAdjoinRoot S f) : aeval h.root f = 0 := by rw [aeval_eq, map_self] /-- Choose an arbitrary representative so that `h.map (h.repr x) = x`. diff --git a/Mathlib/RingTheory/IsPrimary.lean b/Mathlib/RingTheory/IsPrimary.lean new file mode 100644 index 0000000000000..f4444541b209d --- /dev/null +++ b/Mathlib/RingTheory/IsPrimary.lean @@ -0,0 +1,69 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.LinearAlgebra.Quotient.Basic +import Mathlib.RingTheory.Ideal.Operations + +/-! +# Primary submodules + +A proper submodule `S : Submodule R M` is primary iff + `r • x ∈ S` implies `x ∈ S` or `∃ n : ℕ, r ^ n • (⊤ : Submodule R M) ≤ S`. + +## Main results + +* `Submodule.isPrimary_iff_zero_divisor_quotient_imp_nilpotent_smul`: + A `N : Submodule R M` is primary if any zero divisor on `M ⧸ N` is nilpotent. + See `https://mathoverflow.net/questions/3910/primary-decomposition-for-modules` + for a comparison of this definition (a la Atiyah-Macdonald) vs "locally nilpotent" (Matsumura). + +## Implementation details + +This is a generalization of `Ideal.IsPrimary`. For brevity, the pointwise instances are used +to define the nilpotency of `r : R`. + +## References + +* [M. F. Atiyah and I. G. Macdonald, *Introduction to commutative algebra*][atiyah-macdonald] + Chapter 4, Exercise 21. + +-/ + +open Pointwise + +namespace Submodule + +section CommSemiring + +variable {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + +/-- A proper submodule `S : Submodule R M` is primary iff + `r • x ∈ S` implies `x ∈ S` or `∃ n : ℕ, r ^ n • (⊤ : Submodule R M) ≤ S`. + This generalizes `Ideal.IsPrimary`. -/ +protected def IsPrimary (S : Submodule R M) : Prop := + S ≠ ⊤ ∧ ∀ {r : R} {x : M}, r • x ∈ S → x ∈ S ∨ ∃ n : ℕ, (r ^ n • ⊤ : Submodule R M) ≤ S + +variable {S : Submodule R M} + +lemma IsPrimary.ne_top (h : S.IsPrimary) : S ≠ ⊤ := h.left + +end CommSemiring + +section CommRing + +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] {S : Submodule R M} + +lemma isPrimary_iff_zero_divisor_quotient_imp_nilpotent_smul : + S.IsPrimary ↔ S ≠ ⊤ ∧ ∀ (r : R) (x : M ⧸ S), x ≠ 0 → r • x = 0 → + ∃ n : ℕ, r ^ n • (⊤ : Submodule R (M ⧸ S)) = ⊥ := by + refine (and_congr_right fun _ ↦ ?_) + simp_rw [S.mkQ_surjective.forall, ← map_smul, ne_eq, ← LinearMap.mem_ker, ker_mkQ] + congr! 2 + rw [forall_comm, ← or_iff_not_imp_left, ← LinearMap.range_eq_top.mpr S.mkQ_surjective, ← map_top] + simp_rw [eq_bot_iff, ← map_pointwise_smul, map_le_iff_le_comap, comap_bot, ker_mkQ] + +end CommRing + +end Submodule diff --git a/Mathlib/RingTheory/Jacobson.lean b/Mathlib/RingTheory/Jacobson.lean index 29cd5339dde32..aaa724fa39606 100644 --- a/Mathlib/RingTheory/Jacobson.lean +++ b/Mathlib/RingTheory/Jacobson.lean @@ -144,7 +144,7 @@ section Localization open IsLocalization Submonoid -variable {R S : Type*} [CommRing R] [CommRing S] {I : Ideal R} +variable {R S : Type*} [CommRing R] [CommRing S] variable (y : R) [Algebra R S] [IsLocalization.Away y S] variable (S) @@ -285,8 +285,8 @@ theorem isIntegral_isLocalization_polynomial_quotient [IsLocalization.Away (pX.map (Quotient.mk (P.comap (C : R →+* R[X])))).leadingCoeff Rₘ] [Algebra (R[X] ⧸ P) Sₘ] [IsLocalization ((Submonoid.powers (pX.map (Quotient.mk (P.comap (C : R →+* R[X])))).leadingCoeff).map (quotientMap P C le_rfl) : Submonoid (R[X] ⧸ P)) Sₘ] : - (IsLocalization.map Sₘ (quotientMap P C le_rfl) (Submonoid.powers (pX.map (Quotient.mk (P.comap - (C : R →+* R[X])))).leadingCoeff).le_comap_map : Rₘ →+* Sₘ).IsIntegral := by + (IsLocalization.map Sₘ (quotientMap P C le_rfl) (Submonoid.powers (pX.map (Quotient.mk + (P.comap (C : R →+* R[X])))).leadingCoeff).le_comap_map : Rₘ →+* Sₘ).IsIntegral := by let P' : Ideal R := P.comap C let M : Submonoid (R ⧸ P') := Submonoid.powers (pX.map (Quotient.mk (P.comap (C : R →+* R[X])))).leadingCoeff diff --git a/Mathlib/RingTheory/JacobsonIdeal.lean b/Mathlib/RingTheory/JacobsonIdeal.lean index 5f513287fa395..0597e9532b91d 100644 --- a/Mathlib/RingTheory/JacobsonIdeal.lean +++ b/Mathlib/RingTheory/JacobsonIdeal.lean @@ -4,7 +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 +import Mathlib.RingTheory.Ideal.Quotient.Basic import Mathlib.RingTheory.Polynomial.Quotient import Mathlib.RingTheory.TwoSidedIdeal.Operations @@ -412,10 +412,11 @@ theorem IsLocal.mem_jacobson_or_exists_inv {I : Ideal R} (hi : IsLocal I) (x : R end IsLocal theorem isPrimary_of_isMaximal_radical [CommRing R] {I : Ideal R} (hi : IsMaximal (radical I)) : - IsPrimary I := + I.IsPrimary := have : radical I = jacobson I := - le_antisymm (le_sInf fun M ⟨him, hm⟩ => hm.isPrime.radical_le_iff.2 him) + le_antisymm (le_sInf fun _ ⟨him, hm⟩ => hm.isPrime.radical_le_iff.2 him) (sInf_le ⟨le_radical, hi⟩) + isPrimary_iff.mpr ⟨ne_top_of_lt <| lt_of_le_of_lt le_radical (lt_top_iff_ne_top.2 hi.1.1), fun {x y} hxy => ((isLocal_of_isMaximal_radical hi).mem_jacobson_or_exists_inv y).symm.imp (fun ⟨z, hz⟩ => by diff --git a/Mathlib/RingTheory/Kaehler/Basic.lean b/Mathlib/RingTheory/Kaehler/Basic.lean index 09bc7c6dc0c45..d53431a854a9c 100644 --- a/Mathlib/RingTheory/Kaehler/Basic.lean +++ b/Mathlib/RingTheory/Kaehler/Basic.lean @@ -229,14 +229,14 @@ theorem KaehlerDifferential.span_range_derivation : suffices ∃ hx, (KaehlerDifferential.ideal R S).toCotangent ⟨x, hx⟩ ∈ Submodule.span S (Set.range <| KaehlerDifferential.D R S) by exact this.choose_spec - refine Submodule.span_induction this ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ this · rintro _ ⟨x, rfl⟩ refine ⟨KaehlerDifferential.one_smul_sub_smul_one_mem_ideal R x, ?_⟩ apply Submodule.subset_span exact ⟨x, KaehlerDifferential.DLinearMap_apply R S x⟩ · exact ⟨zero_mem _, Submodule.zero_mem _⟩ - · rintro x y ⟨hx₁, hx₂⟩ ⟨hy₁, hy₂⟩; exact ⟨add_mem hx₁ hy₁, Submodule.add_mem _ hx₂ hy₂⟩ - · rintro r x ⟨hx₁, hx₂⟩ + · rintro x y - - ⟨hx₁, hx₂⟩ ⟨hy₁, hy₂⟩; exact ⟨add_mem hx₁ hy₁, Submodule.add_mem _ hx₂ hy₂⟩ + · rintro r x - ⟨hx₁, hx₂⟩ exact ⟨((KaehlerDifferential.ideal R S).restrictScalars S).smul_mem r hx₁, Submodule.smul_mem _ r hx₂⟩ @@ -291,11 +291,11 @@ theorem Derivation.liftKaehlerDifferential_unique (f f' : Ω[S⁄R] →ₗ[S] M) intro x have : x ∈ Submodule.span S (Set.range <| KaehlerDifferential.D R S) := by rw [KaehlerDifferential.span_range_derivation]; trivial - refine Submodule.span_induction this ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ this · rintro _ ⟨x, rfl⟩; exact congr_arg (fun D : Derivation R S M => D x) hf · rw [map_zero, map_zero] - · intro x y hx hy; rw [map_add, map_add, hx, hy] - · intro a x e; simp [e] + · intro x y _ _ hx hy; rw [map_add, map_add, hx, hy] + · intro a x _ e; simp [e] variable (R S) @@ -471,11 +471,11 @@ instance KaehlerDifferential.finite [EssFiniteType R S] : have : ∀ x ∈ adjoin R (EssFiniteType.finset R S).toSet, .D _ _ x ∈ Submodule.span S s.toSet := by intro x hx - refine adjoin_induction hx ?_ ?_ ?_ ?_ + refine adjoin_induction ?_ ?_ ?_ ?_ hx · exact fun x hx ↦ Submodule.subset_span (Finset.mem_image_of_mem _ hx) · simp - · exact fun x y hx hy ↦ (D R S).map_add x y ▸ add_mem hx hy - · intro x y hx hy + · exact fun x y _ _ hx hy ↦ (D R S).map_add x y ▸ add_mem hx hy + · intro x y _ _ hx hy simp only [Derivation.leibniz] exact add_mem (Submodule.smul_mem _ _ hy) (Submodule.smul_mem _ _ hx) obtain ⟨t, ht, ht', hxt⟩ := (essFiniteType_cond_iff R S (EssFiniteType.finset R S)).mp @@ -545,8 +545,8 @@ theorem KaehlerDifferential.kerTotal_mkQ_single_smul (r : R) (x y) : (y𝖣r • noncomputable def KaehlerDifferential.derivationQuotKerTotal : Derivation R S ((S →₀ S) ⧸ KaehlerDifferential.kerTotal R S) where toFun x := 1𝖣x - map_add' x y := KaehlerDifferential.kerTotal_mkQ_single_add _ _ _ _ _ - map_smul' r s := KaehlerDifferential.kerTotal_mkQ_single_smul _ _ _ _ _ + map_add' _ _ := KaehlerDifferential.kerTotal_mkQ_single_add _ _ _ _ _ + map_smul' _ _ := KaehlerDifferential.kerTotal_mkQ_single_smul _ _ _ _ _ map_one_eq_zero' := KaehlerDifferential.kerTotal_mkQ_single_algebraMap_one _ _ _ leibniz' a b := (KaehlerDifferential.kerTotal_mkQ_single_mul _ _ _ _ _).trans @@ -799,7 +799,7 @@ lemma KaehlerDifferential.exact_mapBaseChange_map : end -/-- The map `I → B ⊗[A] B ⊗[A] Ω[A⁄R]` where `I = ker(A → B)`. -/ +/-- The map `I → B ⊗[A] Ω[A⁄R]` where `I = ker(A → B)`. -/ @[simps] noncomputable def KaehlerDifferential.kerToTensor : @@ -811,7 +811,7 @@ def KaehlerDifferential.kerToTensor : algebraMap_eq_smul_one, RingHom.mem_ker.mp x.prop, TensorProduct.zero_tmul, add_zero, RingHom.id_apply] -/-- The map `I/I² → B ⊗[A] B ⊗[A] Ω[A⁄R]` where `I = ker(A → B)`. -/ +/-- The map `I/I² → B ⊗[A] Ω[A⁄R]` where `I = ker(A → B)`. -/ noncomputable def KaehlerDifferential.kerCotangentToTensor : (RingHom.ker (algebraMap A B)).Cotangent →ₗ[A] B ⊗[A] Ω[A⁄R] := diff --git a/Mathlib/RingTheory/Kaehler/CotangentComplex.lean b/Mathlib/RingTheory/Kaehler/CotangentComplex.lean index bcdc42a93b266..cd899098a4f46 100644 --- a/Mathlib/RingTheory/Kaehler/CotangentComplex.lean +++ b/Mathlib/RingTheory/Kaehler/CotangentComplex.lean @@ -22,6 +22,10 @@ defined by `I`), we may define the (naive) cotangent complex `I/I² → ⨁ᵢ S - `Algebra.Generators.exact_cotangentComplex_toKaehler`: `I/I² → ⨁ᵢ S dxᵢ → Ω[S/R]` is exact. - `Algebra.Generators.Hom.Sub`: If `f` and `g` are two maps between presentations, `f - g` induces a map `⨁ᵢ S dxᵢ → I/I²` that makes `f` and `g` homotopic. +- `Algebra.Generators.H1Cotangent`: The first homology of the (naive) cotangent complex + of `S` over `R`, induced by a given presentation. +- `Algebra.H1Cotangent`: `H¹(L_{S/R})`, + the first homology of the (naive) cotangent complex of `S` over `R`. -/ open KaehlerDifferential TensorProduct MvPolynomial @@ -83,6 +87,16 @@ attribute [local instance] SMulCommClass.of_commMonoid variable {P P'} +universe w'' u'' v'' + +variable {R'' : Type u''} {S'' : Type v''} [CommRing R''] [CommRing S''] [Algebra R'' S''] +variable {P'' : Generators.{w''} R'' S''} +variable [Algebra R R''] [Algebra S S''] [Algebra R S''] + [IsScalarTower R R'' S''] [IsScalarTower R S S''] +variable [Algebra R' R''] [Algebra S' S''] [Algebra R' S''] + [IsScalarTower R' R'' S''] [IsScalarTower R' S' S''] +variable [IsScalarTower S S' S''] + namespace CotangentSpace /-- @@ -114,16 +128,6 @@ lemma repr_map (f : Hom P P') (i j) : simp only [cotangentSpaceBasis_apply, map_tmul, map_one, Hom.toAlgHom_X, cotangentSpaceBasis_repr_one_tmul] -universe w'' u'' v'' - -variable {R'' : Type u''} {S'' : Type v''} [CommRing R''] [CommRing S''] [Algebra R'' S''] -variable {P'' : Generators.{w''} R'' S''} -variable [Algebra R R''] [Algebra S S''] [Algebra R S''] - [IsScalarTower R R'' S''] [IsScalarTower R S S''] -variable [Algebra R' R''] [Algebra S' S''] [Algebra R' S''] - [IsScalarTower R' R'' S''] [IsScalarTower R' S' S''] -variable [IsScalarTower S S' S''] - @[simp] lemma map_id : CotangentSpace.map (.id P) = LinearMap.id := by @@ -157,10 +161,6 @@ lemma map_comp_cotangentComplex (f : Hom P P') : end CotangentSpace -universe uT - -variable {T : Type uT} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] - lemma Hom.sub_aux (f g : Hom P P') (x y) : letI := ((algebraMap S S').comp (algebraMap P.Ring S)).toAlgebra f.toAlgHom (x * y) - g.toAlgHom (x * y) - @@ -279,6 +279,114 @@ lemma toKaehler_surjective : Function.Surjective P.toKaehler := lemma exact_cotangentComplex_toKaehler : Function.Exact P.cotangentComplex P.toKaehler := exact_kerCotangentToTensor_mapBaseChange _ _ _ P.algebraMap_surjective +variable (P) in +/-- +The first homology of the (naive) cotangent complex of `S` over `R`, +induced by a given presentation `0 → I → P → R → 0`, +defined as the kernel of `I/I² → S ⊗[P] Ω[P⁄R]`. +-/ +protected noncomputable +def H1Cotangent : Type _ := LinearMap.ker P.cotangentComplex + +variable {P : Generators R S} + +noncomputable +instance : AddCommGroup P.H1Cotangent := by delta Generators.H1Cotangent; infer_instance + +noncomputable +instance {R₀} [CommRing R₀] [Algebra R₀ S] [Module R₀ P.Cotangent] + [IsScalarTower R₀ S P.Cotangent] : Module R₀ P.H1Cotangent := by + delta Generators.H1Cotangent; infer_instance + +@[simp] lemma H1Cotangent.val_add (x y : P.H1Cotangent) : (x + y).1 = x.1 + y.1 := rfl +@[simp] lemma H1Cotangent.val_zero : (0 : P.H1Cotangent).1 = 0 := rfl +@[simp] lemma H1Cotangent.val_smul {R₀} [CommRing R₀] [Algebra R₀ S] [Module R₀ P.Cotangent] + [IsScalarTower R₀ S P.Cotangent] (r : R₀) (x : P.H1Cotangent) : (r • x).1 = r • x.1 := rfl + +noncomputable +instance {R₁ R₂} [CommRing R₁] [CommRing R₂] [Algebra R₁ R₂] + [Algebra R₁ S] [Algebra R₂ S] + [Module R₁ P.Cotangent] [IsScalarTower R₁ S P.Cotangent] + [Module R₂ P.Cotangent] [IsScalarTower R₂ S P.Cotangent] + [IsScalarTower R₁ R₂ P.Cotangent] : + IsScalarTower R₁ R₂ P.H1Cotangent := by + delta Generators.H1Cotangent; infer_instance + +lemma subsingleton_h1Cotangent (P : Generators R S) : + Subsingleton P.H1Cotangent ↔ Function.Injective P.cotangentComplex := by + delta Generators.H1Cotangent + rw [← LinearMap.ker_eq_bot, Submodule.eq_bot_iff, subsingleton_iff_forall_eq 0, Subtype.forall'] + simp only [Subtype.ext_iff, Submodule.coe_zero] + +/-- The inclusion of `H¹(L_{S/R})` into the conormal space of a presentation. -/ +@[simps!] def h1Cotangentι : P.H1Cotangent →ₗ[S] P.Cotangent := Submodule.subtype _ + +lemma h1Cotangentι_injective : Function.Injective P.h1Cotangentι := Subtype.val_injective + +@[ext] lemma h1Cotangentι_ext (x y : P.H1Cotangent) (e : x.1 = y.1) : x = y := Subtype.ext e + +/-- +The induced map on the first homology of the (naive) cotangent complex. +-/ +@[simps!] +noncomputable +def H1Cotangent.map (f : Hom P P') : P.H1Cotangent →ₗ[S] P'.H1Cotangent := by + refine (Cotangent.map f).restrict (p := LinearMap.ker P.cotangentComplex) + (q := (LinearMap.ker P'.cotangentComplex).restrictScalars S) fun x hx ↦ ?_ + simp only [LinearMap.mem_ker, Submodule.restrictScalars_mem] at hx ⊢ + apply_fun (CotangentSpace.map f) at hx + rw [CotangentSpace.map_cotangentComplex] at hx + rw [hx] + exact LinearMap.map_zero _ + +lemma H1Cotangent.map_eq (f g : Hom P P') : map f = map g := by + ext x + simp only [map_apply_coe] + rw [← sub_eq_zero, ← Cotangent.val_sub, ← LinearMap.sub_apply, Cotangent.map_sub_map] + simp only [LinearMap.coe_comp, Function.comp_apply, LinearMap.map_coe_ker, map_zero, + Cotangent.val_zero] + +@[simp] lemma H1Cotangent.map_id : map (.id P) = LinearMap.id := by ext; simp + +lemma H1Cotangent.map_comp [IsScalarTower R R' R''] (f : Hom P P') (g : Hom P' P'') : + map (g.comp f) = (map g).restrictScalars S ∘ₗ map f := by ext; simp [Cotangent.map_comp] + +/-- `H¹(L_{S/R})` is independent of the presentation chosen. -/ +@[simps! apply] +noncomputable +def H1Cotangent.equiv (P : Generators.{w} R S) (P' : Generators.{w'} R S) : + P.H1Cotangent ≃ₗ[S] P'.H1Cotangent where + __ := map default + invFun := map default + left_inv x := + show ((map (defaultHom P' P)) ∘ₗ (map (defaultHom P P'))) x = LinearMap.id x by + rw [← map_id, eq_comm, map_eq _ ((defaultHom P' P).comp (defaultHom P P')), map_comp]; rfl + right_inv x := + show ((map (defaultHom P P')) ∘ₗ (map (defaultHom P' P))) x = LinearMap.id x by + rw [← map_id, eq_comm, map_eq _ ((defaultHom P P').comp (defaultHom P' P)), map_comp]; rfl + end Generators +variable {S' : Type*} [CommRing S'] [Algebra R S'] +variable {T : Type w} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] +variable [Algebra S' T] [IsScalarTower R S' T] + +variable (R S S' T) + +/-- `H¹(L_{S/R})`, the first homology of the (naive) cotangent complex of `S` over `R`. -/ +abbrev H1Cotangent : Type _ := (Generators.self R S).H1Cotangent + +/-- The induced map on the first homology of the (naive) cotangent complex of `S` over `R`. -/ +noncomputable +def H1Cotangent.map : H1Cotangent R S' →ₗ[S'] H1Cotangent S T := + Generators.H1Cotangent.map (Generators.defaultHom _ _) + +variable {R S S' T} + +/-- `H¹(L_{S/R})` is independent of the presentation chosen. -/ +noncomputable +abbrev Generators.equivH1Cotangent (P : Generators.{w} R S) : + P.H1Cotangent ≃ₗ[S] H1Cotangent R S := + Generators.H1Cotangent.equiv _ _ + end Algebra diff --git a/Mathlib/RingTheory/Kaehler/Polynomial.lean b/Mathlib/RingTheory/Kaehler/Polynomial.lean index c5e94eaca9de6..688733e7fd0c5 100644 --- a/Mathlib/RingTheory/Kaehler/Polynomial.lean +++ b/Mathlib/RingTheory/Kaehler/Polynomial.lean @@ -16,7 +16,7 @@ open Algebra universe u v -variable (R : Type u) (S : Type v) [CommRing R] [CommRing S] [Algebra R S] +variable (R : Type u) [CommRing R] suppress_compilation diff --git a/Mathlib/RingTheory/Kaehler/TensorProduct.lean b/Mathlib/RingTheory/Kaehler/TensorProduct.lean new file mode 100644 index 0000000000000..6999913ad12a4 --- /dev/null +++ b/Mathlib/RingTheory/Kaehler/TensorProduct.lean @@ -0,0 +1,233 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.Kaehler.Basic +import Mathlib.RingTheory.Localization.BaseChange + +/-! +# Kaehler differential module under base change + +## Main results +- `KaehlerDifferential.tensorKaehlerEquiv`: `(S ⊗[R] Ω[A⁄R]) ≃ₗ[S] Ω[B⁄S]` for `B = S ⊗[R] A`. +- `KaehlerDifferential.isLocalizedModule_of_isLocalizedModule`: + `Ω[Aₚ/Rₚ]` is the localization of `Ω[A/R]` at `p`. + +-/ + +variable (R S A B : Type*) [CommRing R] [CommRing S] [Algebra R S] [CommRing A] [CommRing B] +variable [Algebra R A] [Algebra R B] +variable [Algebra A B] [Algebra S B] [IsScalarTower R A B] [IsScalarTower R S B] + +open TensorProduct + +attribute [local instance] SMulCommClass.of_commMonoid + +namespace KaehlerDifferential + +/-- (Implementation). `A`-action on `S ⊗[R] Ω[A⁄R]`. -/ +noncomputable +abbrev mulActionBaseChange : + MulAction A (S ⊗[R] Ω[A⁄R]) := (TensorProduct.comm R S (Ω[A⁄R])).toEquiv.mulAction A + +attribute [local instance] mulActionBaseChange + +@[simp] +lemma mulActionBaseChange_smul_tmul (a : A) (s : S) (x : Ω[A⁄R]) : + a • (s ⊗ₜ[R] x) = s ⊗ₜ (a • x) := rfl + +@[local simp] +lemma mulActionBaseChange_smul_zero (a : A) : + a • (0 : S ⊗[R] Ω[A⁄R]) = 0 := by + rw [← zero_tmul _ (0 : Ω[A⁄R]), mulActionBaseChange_smul_tmul, smul_zero] + +@[local simp] +lemma mulActionBaseChange_smul_add (a : A) (x y : S ⊗[R] Ω[A⁄R]) : + a • (x + y) = a • x + a • y := by + show (TensorProduct.comm R S (Ω[A⁄R])).symm (a • (TensorProduct.comm R S (Ω[A⁄R])) (x + y)) = _ + rw [map_add, smul_add, map_add] + rfl + +/-- (Implementation). `A`-module structure on `S ⊗[R] Ω[A⁄R]`. -/ +noncomputable +abbrev moduleBaseChange : + Module A (S ⊗[R] Ω[A⁄R]) where + __ := (TensorProduct.comm R S (Ω[A⁄R])).toEquiv.mulAction A + add_smul r s x := by induction x <;> simp [add_smul, tmul_add, *, add_add_add_comm] + zero_smul x := by induction x <;> simp [*] + smul_zero := by simp + smul_add := by simp + +attribute [local instance] moduleBaseChange + +instance : IsScalarTower R A (S ⊗[R] Ω[A⁄R]) := by + apply IsScalarTower.of_algebraMap_smul + intro r x + induction x + · simp only [smul_zero] + · rw [mulActionBaseChange_smul_tmul, algebraMap_smul, tmul_smul] + · simp only [smul_add, *] + +instance : SMulCommClass S A (S ⊗[R] Ω[A⁄R]) where + smul_comm s a x := by + induction x + · simp only [smul_zero] + · rw [mulActionBaseChange_smul_tmul, smul_tmul', smul_tmul', mulActionBaseChange_smul_tmul] + · simp only [smul_add, *] + +instance : SMulCommClass A S (S ⊗[R] Ω[A⁄R]) where + smul_comm s a x := by rw [← smul_comm] + +/-- (Implementation). `B = S ⊗[R] A`-module structure on `S ⊗[R] Ω[A⁄R]`. -/ +@[reducible] noncomputable +def moduleBaseChange' [Algebra.IsPushout R S A B] : + Module B (S ⊗[R] Ω[A⁄R]) := + Module.compHom _ (Algebra.pushoutDesc B (Algebra.lsmul R (A := S) S (S ⊗[R] Ω[A⁄R])) + (Algebra.lsmul R (A := A) _ _) (LinearMap.ext <| smul_comm · ·)).toRingHom + +attribute [local instance] moduleBaseChange' + +instance [Algebra.IsPushout R S A B] : + IsScalarTower A B (S ⊗[R] Ω[A⁄R]) := by + apply IsScalarTower.of_algebraMap_smul + intro r x + show (Algebra.pushoutDesc B (Algebra.lsmul R (A := S) S (S ⊗[R] Ω[A⁄R])) + (Algebra.lsmul R (A := A) _ _) (LinearMap.ext <| smul_comm · ·) + (algebraMap A B r)) • x = r • x + simp only [Algebra.pushoutDesc_right, LinearMap.smul_def, Algebra.lsmul_coe] + +instance [Algebra.IsPushout R S A B] : + IsScalarTower S B (S ⊗[R] Ω[A⁄R]) := by + apply IsScalarTower.of_algebraMap_smul + intro r x + show (Algebra.pushoutDesc B (Algebra.lsmul R (A := S) S (S ⊗[R] Ω[A⁄R])) + (Algebra.lsmul R (A := A) _ _) (LinearMap.ext <| smul_comm · ·) + (algebraMap S B r)) • x = r • x + simp only [Algebra.pushoutDesc_left, LinearMap.smul_def, Algebra.lsmul_coe] + +lemma map_liftBaseChange_smul [h : Algebra.IsPushout R S A B] (b : B) (x) : + ((map R S A B).restrictScalars R).liftBaseChange S (b • x) = + b • ((map R S A B).restrictScalars R).liftBaseChange S x := by + induction b using h.1.inductionOn with + | h₁ => simp only [zero_smul, map_zero] + | h₃ s b e => rw [smul_assoc, map_smul, e, smul_assoc] + | h₄ b₁ b₂ e₁ e₂ => simp only [map_add, e₁, e₂, add_smul] + | h₂ a => + induction x + · simp only [smul_zero, map_zero] + · simp [smul_comm] + · simp only [map_add, smul_add, *] + +/-- (Implementation). +The `S`-derivation `B = S ⊗[R] A` to `S ⊗[R] Ω[A⁄R]` sending `a ⊗ b` to `a ⊗ d b`. -/ +noncomputable +def derivationTensorProduct [h : Algebra.IsPushout R S A B] : + Derivation S B (S ⊗[R] Ω[A⁄R]) where + __ := h.out.lift ((TensorProduct.mk R S (Ω[A⁄R]) 1).comp (D R A).toLinearMap) + map_one_eq_zero' := by + rw [← (algebraMap A B).map_one] + refine (h.out.lift_eq _ _).trans ?_ + dsimp + rw [Derivation.map_one_eq_zero, TensorProduct.tmul_zero] + leibniz' a b := by + dsimp + induction a using h.out.inductionOn with + | h₁ => rw [map_zero, zero_smul, smul_zero, zero_add, zero_mul, map_zero] + | h₃ x y e => + rw [smul_mul_assoc, map_smul, e, map_smul, smul_add, + smul_comm x b, smul_assoc] + | h₄ b₁ b₂ e₁ e₂ => simp only [add_mul, add_smul, map_add, e₁, e₂, smul_add, add_add_add_comm] + | h₂ z => + dsimp + induction b using h.out.inductionOn with + | h₁ => rw [map_zero, zero_smul, smul_zero, zero_add, mul_zero, map_zero] + | h₂ => + simp only [AlgHom.toLinearMap_apply, IsScalarTower.coe_toAlgHom', + algebraMap_smul, ← map_mul] + erw [h.out.lift_eq, h.out.lift_eq, h.out.lift_eq] + simp only [LinearMap.coe_comp, Derivation.coeFn_coe, Function.comp_apply, + Derivation.leibniz, mk_apply, mulActionBaseChange_smul_tmul, TensorProduct.tmul_add] + | h₃ _ _ e => + rw [mul_comm, smul_mul_assoc, map_smul, mul_comm, e, + map_smul, smul_add, smul_comm, smul_assoc] + | h₄ _ _ e₁ e₂ => simp only [mul_add, add_smul, map_add, e₁, e₂, smul_add, add_add_add_comm] + +lemma derivationTensorProduct_algebraMap [Algebra.IsPushout R S A B] (x) : + derivationTensorProduct R S A B (algebraMap A B x) = + 1 ⊗ₜ D _ _ x := +IsBaseChange.lift_eq _ _ _ + +lemma tensorKaehlerEquiv_left_inv [Algebra.IsPushout R S A B] : + ((derivationTensorProduct R S A B).liftKaehlerDifferential.restrictScalars S).comp + (((map R S A B).restrictScalars R).liftBaseChange S) = LinearMap.id := by + refine LinearMap.restrictScalars_injective R ?_ + apply TensorProduct.ext' + intro x y + obtain ⟨y, rfl⟩ := tensorProductTo_surjective _ _ y + induction y + · simp only [map_zero, TensorProduct.tmul_zero] + · simp only [LinearMap.restrictScalars_comp, Derivation.tensorProductTo_tmul, LinearMap.coe_comp, + LinearMap.coe_restrictScalars, Function.comp_apply, LinearMap.liftBaseChange_tmul, map_smul, + map_D, LinearMap.map_smul_of_tower, Derivation.liftKaehlerDifferential_comp_D, + LinearMap.id_coe, id_eq, derivationTensorProduct_algebraMap] + rw [smul_comm, TensorProduct.smul_tmul', smul_eq_mul, mul_one] + rfl + · simp only [map_add, TensorProduct.tmul_add, *] + +/-- The canonical isomorphism `(S ⊗[R] Ω[A⁄R]) ≃ₗ[S] Ω[B⁄S]` for `B = S ⊗[R] A`. -/ +@[simps! symm_apply] noncomputable +def tensorKaehlerEquiv [h : Algebra.IsPushout R S A B] : + (S ⊗[R] Ω[A⁄R]) ≃ₗ[S] Ω[B⁄S] where + __ := ((map R S A B).restrictScalars R).liftBaseChange S + invFun := (derivationTensorProduct R S A B).liftKaehlerDifferential + left_inv := LinearMap.congr_fun (tensorKaehlerEquiv_left_inv R S A B) + right_inv x := by + obtain ⟨x, rfl⟩ := tensorProductTo_surjective _ _ x + dsimp + induction x with + | zero => simp + | add x y e₁ e₂ => simp only [map_add, e₁, e₂] + | tmul x y => + dsimp + simp only [Derivation.tensorProductTo_tmul, LinearMap.map_smul, + Derivation.liftKaehlerDifferential_comp_D, map_liftBaseChange_smul] + induction y using h.1.inductionOn + · simp only [map_zero, smul_zero] + · simp only [AlgHom.toLinearMap_apply, IsScalarTower.coe_toAlgHom', + derivationTensorProduct_algebraMap, LinearMap.liftBaseChange_tmul, + LinearMap.coe_restrictScalars, map_D, one_smul] + · simp only [Derivation.map_smul, LinearMap.map_smul, *, smul_comm x] + · simp only [map_add, smul_add, *] + +@[simp] +lemma tensorKaehlerEquiv_tmul [Algebra.IsPushout R S A B] (a b) : + tensorKaehlerEquiv R S A B (a ⊗ₜ b) = a • map R S A B b := + LinearMap.liftBaseChange_tmul _ _ _ _ + +/-- +If `B` is the tensor product of `S` and `A` over `R`, +then `Ω[B⁄S]` is the base change of `Ω[A⁄R]` along `R → S`. +-/ +lemma isBaseChange [h : Algebra.IsPushout R S A B] : + IsBaseChange S ((map R S A B).restrictScalars R) := by + convert (TensorProduct.isBaseChange R (Ω[A⁄R]) S).comp + (IsBaseChange.ofEquiv (tensorKaehlerEquiv R S A B)) + refine LinearMap.ext fun x ↦ ?_ + simp only [LinearMap.coe_restrictScalars, LinearMap.coe_comp, LinearEquiv.coe_coe, + Function.comp_apply, mk_apply, tensorKaehlerEquiv_tmul, one_smul] + +instance isLocalizedModule (p : Submonoid R) [IsLocalization p S] + [IsLocalization (Algebra.algebraMapSubmonoid A p) B] : + IsLocalizedModule p ((map R S A B).restrictScalars R) := + have := (Algebra.isPushout_of_isLocalization p S A B).symm + (isLocalizedModule_iff_isBaseChange p S _).mpr (isBaseChange R S A B) + +instance isLocalizedModule_of_isLocalizedModule (p : Submonoid R) [IsLocalization p S] + [IsLocalizedModule p (IsScalarTower.toAlgHom R A B).toLinearMap] : + IsLocalizedModule p ((map R S A B).restrictScalars R) := + have : IsLocalization (Algebra.algebraMapSubmonoid A p) B := + isLocalizedModule_iff_isLocalization.mp inferInstance + inferInstance + +end KaehlerDifferential diff --git a/Mathlib/RingTheory/Lasker.lean b/Mathlib/RingTheory/Lasker.lean new file mode 100644 index 0000000000000..c2cfa35d3753d --- /dev/null +++ b/Mathlib/RingTheory/Lasker.lean @@ -0,0 +1,166 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky +-/ +import Mathlib.Order.Irreducible +import Mathlib.RingTheory.Ideal.Colon +import Mathlib.RingTheory.Ideal.IsPrimary +import Mathlib.RingTheory.Noetherian + +/-! +# Lasker ring + +## Main declarations + +- `IsLasker`: A ring `R` satisfies `IsLasker R` when any `I : Ideal R` can be decomposed into + finitely many primary ideals. +- `IsLasker.minimal`: Any `I : Ideal R` in a ring `R` satisifying `IsLasker R` can be + decomposed into primary ideals, such that the decomposition is minimal: + each primary ideal is necessary, and each primary ideal has an indepedent radical. +- `Ideal.isLasker`: Every Noetherian commutative ring is a Lasker ring. + +## Implementation details + +There is a generalization for submodules that needs to be implemented. +Also, one needs to prove that the radicals of minimal decompositions are independent of the + precise decomposition. + +-/ + +section IsLasker + +variable (R : Type*) [CommSemiring R] + +/-- A ring `R` satisfies `IsLasker R` when any `I : Ideal R` can be decomposed into +finitely many primary ideals.-/ +def IsLasker : Prop := + ∀ I : Ideal R, ∃ s : Finset (Ideal R), s.inf id = I ∧ ∀ ⦃J⦄, J ∈ s → J.IsPrimary + +variable {R} + +namespace Ideal + +lemma decomposition_erase_inf [DecidableEq (Ideal R)] {I : Ideal R} + {s : Finset (Ideal R)} (hs : s.inf id = I) : + ∃ t : Finset (Ideal R), t ⊆ s ∧ t.inf id = I ∧ (∀ ⦃J⦄, J ∈ t → ¬ (t.erase J).inf id ≤ J) := by + induction s using Finset.strongInductionOn + rename_i _ s IH + by_cases H : ∀ J ∈ s, ¬ (s.erase J).inf id ≤ J + · exact ⟨s, le_rfl, hs, H⟩ + push_neg at H + obtain ⟨J, hJ, hJ'⟩ := H + refine (IH (s.erase J) (Finset.erase_ssubset hJ) ?_).imp + fun t ↦ And.imp_left (fun ht ↦ ht.trans (Finset.erase_subset _ _)) + rw [← Finset.insert_erase hJ] at hs + simp [← hs, hJ'] + +lemma isPrimary_decomposition_pairwise_ne_radical {I : Ideal R} + {s : Finset (Ideal R)} (hs : s.inf id = I) (hs' : ∀ ⦃J⦄, J ∈ s → J.IsPrimary) : + ∃ t : Finset (Ideal R), t.inf id = I ∧ (∀ ⦃J⦄, J ∈ t → J.IsPrimary) ∧ + (t : Set (Ideal R)).Pairwise ((· ≠ ·) on radical) := by + classical + refine ⟨(s.image (fun J ↦ s.filter (fun I ↦ I.radical = J.radical))).image fun t ↦ t.inf id, + ?_, ?_, ?_⟩ + · rw [← hs] + refine le_antisymm ?_ ?_ <;> intro x hx + · simp only [Finset.inf_image, CompTriple.comp_eq, Submodule.mem_finset_inf, + Function.comp_apply, Finset.mem_filter, id_eq, and_imp] at hx ⊢ + intro J hJ + exact hx J hJ J hJ rfl + · simp only [Submodule.mem_finset_inf, id_eq, Finset.inf_image, CompTriple.comp_eq, + Function.comp_apply, Finset.mem_filter, and_imp] at hx ⊢ + intro J _ K hK _ + exact hx K hK + · simp only [Finset.mem_image, exists_exists_and_eq_and, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂] + intro J hJ + refine isPrimary_finset_inf (i := J) ?_ ?_ (by simp) + · simp [hJ] + · simp only [Finset.mem_filter, id_eq, and_imp] + intro y hy + simp [hs' hy] + · intro I hI J hJ hIJ + simp only [Finset.coe_image, Set.mem_image, Finset.mem_coe, exists_exists_and_eq_and] at hI hJ + obtain ⟨I', hI', hI⟩ := hI + obtain ⟨J', hJ', hJ⟩ := hJ + simp only [Function.onFun, ne_eq] + contrapose! hIJ + suffices I'.radical = J'.radical by + rw [← hI, ← hJ, this] + · rw [← hI, radical_finset_inf (i := I') (by simp [hI']) (by simp), id_eq] at hIJ + rw [hIJ, ← hJ, radical_finset_inf (i := J') (by simp [hJ']) (by simp), id_eq] + +lemma exists_minimal_isPrimary_decomposition_of_isPrimary_decomposition [DecidableEq (Ideal R)] + {I : Ideal R} {s : Finset (Ideal R)} (hs : s.inf id = I) (hs' : ∀ ⦃J⦄, J ∈ s → J.IsPrimary) : + ∃ t : Finset (Ideal R), t.inf id = I ∧ (∀ ⦃J⦄, J ∈ t → J.IsPrimary) ∧ + ((t : Set (Ideal R)).Pairwise ((· ≠ ·) on radical)) ∧ + (∀ ⦃J⦄, J ∈ t → ¬ (t.erase J).inf id ≤ J) := by + obtain ⟨t, ht, ht', ht''⟩ := isPrimary_decomposition_pairwise_ne_radical hs hs' + obtain ⟨u, hut, hu, hu'⟩ := decomposition_erase_inf ht + exact ⟨u, hu, fun _ hi ↦ ht' (hut hi), ht''.mono hut, hu'⟩ + +lemma IsLasker.minimal [DecidableEq (Ideal R)] (h : IsLasker R) (I : Ideal R) : + ∃ t : Finset (Ideal R), t.inf id = I ∧ (∀ ⦃J⦄, J ∈ t → J.IsPrimary) ∧ + ((t : Set (Ideal R)).Pairwise ((· ≠ ·) on radical)) ∧ + (∀ ⦃J⦄, J ∈ t → ¬ (t.erase J).inf id ≤ J) := by + obtain ⟨s, hs, hs'⟩ := h I + exact exists_minimal_isPrimary_decomposition_of_isPrimary_decomposition hs hs' + +end Ideal + +end IsLasker + +namespace Ideal + +section Noetherian + +variable {R : Type*} [CommRing R] [IsNoetherianRing R] + +lemma _root_.InfIrred.isPrimary {I : Ideal R} (h : InfIrred I) : I.IsPrimary := by + rw [Ideal.isPrimary_iff] + refine ⟨h.ne_top, fun {a b} hab ↦ ?_⟩ + let f : ℕ → Ideal R := fun n ↦ (I.colon (span {b ^ n})) + have hf : Monotone f := by + intro n m hnm + simp_rw [f] + exact (Submodule.colon_mono le_rfl (Ideal.span_singleton_le_span_singleton.mpr + (pow_dvd_pow b hnm))) + obtain ⟨n, hn⟩ := monotone_stabilizes_iff_noetherian.mpr ‹_› ⟨f, hf⟩ + rcases h with ⟨-, h⟩ + specialize @h (I.colon (span {b ^ n})) (I + (span {b ^ n})) ?_ + · refine le_antisymm (fun r ↦ ?_) (le_inf (fun _ ↦ ?_) ?_) + · simp only [Submodule.add_eq_sup, sup_comm I, mem_inf, mem_colon_singleton, + mem_span_singleton_sup, and_imp, forall_exists_index] + rintro hrb t s hs rfl + refine add_mem ?_ hs + have := hn (n + n) (by simp) + simp only [OrderHom.coe_mk, f] at this + rw [add_mul, mul_assoc, ← pow_add] at hrb + rwa [← mem_colon_singleton, this, mem_colon_singleton, + ← Ideal.add_mem_iff_left _ (Ideal.mul_mem_right _ _ hs)] + · simpa only [mem_colon_singleton] using mul_mem_right _ _ + · simp + rcases h with (h|h) + · replace h : I = I.colon (span {b}) := by + rcases eq_or_ne n 0 with rfl|hn' + · simpa [f] using hn 1 zero_le_one + refine le_antisymm ?_ (h.le.trans' (Submodule.colon_mono le_rfl ?_)) + · intro + simpa only [mem_colon_singleton] using mul_mem_right _ _ + · exact span_singleton_le_span_singleton.mpr (dvd_pow_self b hn') + rw [← mem_colon_singleton, ← h] at hab + exact Or.inl hab + · rw [← h] + refine Or.inr ⟨n, ?_⟩ + simpa using mem_sup_right (mem_span_singleton_self _) + +variable (R) in +/-- The Lasker--Noether theorem: every ideal in a Noetherian ring admits a decomposition into + primary ideals. -/ +lemma isLasker : IsLasker R := fun I ↦ + (exists_infIrred_decomposition I).imp fun _ h ↦ h.imp_right fun h' _ ht ↦ (h' ht).isPrimary + +end Noetherian + +end Ideal diff --git a/Mathlib/RingTheory/LaurentSeries.lean b/Mathlib/RingTheory/LaurentSeries.lean index eea4d59465c7d..14f5ca19d8a36 100644 --- a/Mathlib/RingTheory/LaurentSeries.lean +++ b/Mathlib/RingTheory/LaurentSeries.lean @@ -4,23 +4,25 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson, María Inés de Frutos-Fernández, Filippo A. E. Nuccio -/ import Mathlib.Data.Int.Interval +import Mathlib.FieldTheory.RatFunc.AsPolynomial import Mathlib.RingTheory.Binomial -import Mathlib.RingTheory.DedekindDomain.Basic import Mathlib.RingTheory.HahnSeries.PowerSeries import Mathlib.RingTheory.HahnSeries.Summable import Mathlib.RingTheory.PowerSeries.Inverse -import Mathlib.FieldTheory.RatFunc.AsPolynomial import Mathlib.RingTheory.Localization.FractionRing import Mathlib.Topology.UniformSpace.Cauchy /-! # Laurent Series +In this file we define `LaurentSeries R`, the formal Laurent series over `R` here an *arbitrary* +type with a zero. It is denoted `R⸨X⸩`. + ## Main Definitions + * Defines `LaurentSeries` as an abbreviation for `HahnSeries ℤ`. * Defines `hasseDeriv` of a Laurent series with coefficients in a module over a ring. -* Provides a coercion `PowerSeries R` into `LaurentSeries R` given by - `HahnSeries.ofPowerSeries`. +* Provides a coercion `from power series `R⟦X⟧` into `R⸨X⸩` given by `HahnSeries.ofPowerSeries`. * Defines `LaurentSeries.powerSeriesPart` * Defines the localization map `LaurentSeries.of_powerSeries_localization` which evaluates to `HahnSeries.ofPowerSeries`. @@ -28,12 +30,13 @@ import Mathlib.Topology.UniformSpace.Cauchy the underlying `RatFunc.coeAlgHom`. * Study of the `X`-Adic valuation on the ring of Laurent series over a field * In `LaurentSeries.uniformContinuous_coeff` we show that sending a Laurent series to its `d`th -coefficient is uniformly continuous, ensuring that it sends a Cauchy filter `ℱ` in `LaurentSeries K` +coefficient is uniformly continuous, ensuring that it sends a Cauchy filter `ℱ` in `K⸨X⸩` to a Cauchy filter in `K`: since this latter is given the discrete topology, this provides an element `LaurentSeries.Cauchy.coeff ℱ d` in `K` that serves as `d`th coefficient of the Laurent series to which the filter `ℱ` converges. ## Main Results + * Basic properties of Hasse derivatives ### About the `X`-Adic valuation: * The (integral) valuation of a power series is the order of the first non-zero coefficient, see @@ -46,19 +49,23 @@ series to which the filter `ℱ` converges. `instLaurentSeriesComplete`. ## Implementation details + * Since `LaurentSeries` is just an abbreviation of `HahnSeries ℤ _`, the definition of the coefficients is given in terms of `HahnSeries.coeff` and this forces sometimes to go back-and-forth -from `X : LaurentSeries _` to `single 1 1 : HahnSeries ℤ _`. +from `X : _⸨X⸩` to `single 1 1 : HahnSeries ℤ _`. -/ universe u -open scoped Classical +open scoped Classical PowerSeries open HahnSeries Polynomial noncomputable section -/-- A `LaurentSeries` is implemented as a `HahnSeries` with value group `ℤ`. -/ +/-- `LaurentSeries R` is the type of formal Laurent series with coefficients in `R`, denoted `R⸨X⸩`. + + It is implemented as a `HahnSeries` with value group `ℤ`. +-/ abbrev LaurentSeries (R : Type u) [Zero R] := HahnSeries ℤ R @@ -66,12 +73,20 @@ variable {R : Type*} namespace LaurentSeries +section + +/-- +`R⸨X⸩` is notation for `LaurentSeries R`, +-/ +scoped notation:9000 R "⸨X⸩" => LaurentSeries R + +end + section HasseDeriv /-- The Hasse derivative of Laurent series, as a linear map. -/ -@[simps] def hasseDeriv (R : Type*) {V : Type*} [AddCommGroup V] [Semiring R] [Module R V] (k : ℕ) : - LaurentSeries V →ₗ[R] LaurentSeries V where + V⸨X⸩ →ₗ[R] V⸨X⸩ where toFun f := HahnSeries.ofSuppBddBelow (fun (n : ℤ) => (Ring.choose (n + k) k) • f.coeff (n + k)) (forallLTEqZero_supp_BddBelow _ (f.order - k : ℤ) (fun _ h_lt ↦ by rw [coeff_eq_zero_of_lt_order <| lt_sub_iff_add_lt.mp h_lt, smul_zero])) @@ -84,47 +99,104 @@ def hasseDeriv (R : Type*) {V : Type*} [AddCommGroup V] [Semiring R] [Module R V variable [Semiring R] {V : Type*} [AddCommGroup V] [Module R V] +@[simp] theorem hasseDeriv_coeff (k : ℕ) (f : LaurentSeries V) (n : ℤ) : (hasseDeriv R k f).coeff n = Ring.choose (n + k) k • f.coeff (n + k) := rfl +@[simp] +theorem hasseDeriv_zero : hasseDeriv R 0 = LinearMap.id (M := LaurentSeries V) := by + ext f n + simp + +theorem hasseDeriv_single_add (k : ℕ) (n : ℤ) (x : V) : + hasseDeriv R k (single (n + k) x) = single n ((Ring.choose (n + k) k) • x) := by + ext m + dsimp only [hasseDeriv_coeff] + by_cases h : m = n + · simp [h] + · simp [h, show m + k ≠ n + k by omega] + +@[simp] +theorem hasseDeriv_single (k : ℕ) (n : ℤ) (x : V) : + hasseDeriv R k (single n x) = single (n - k) ((Ring.choose n k) • x) := by + rw [← Int.sub_add_cancel n k, hasseDeriv_single_add, Int.sub_add_cancel n k] + +theorem hasseDeriv_comp_coeff (k l : ℕ) (f : LaurentSeries V) (n : ℤ) : + (hasseDeriv R k (hasseDeriv R l f)).coeff n = + ((Nat.choose (k + l) k) • hasseDeriv R (k + l) f).coeff n := by + rw [nsmul_coeff] + simp only [hasseDeriv_coeff, Pi.smul_apply, Nat.cast_add] + rw [smul_smul, mul_comm, ← Ring.choose_add_smul_choose (n + k), add_assoc, Nat.choose_symm_add, + smul_assoc] + +@[simp] +theorem hasseDeriv_comp (k l : ℕ) (f : LaurentSeries V) : + hasseDeriv R k (hasseDeriv R l f) = (k + l).choose k • hasseDeriv R (k + l) f := by + ext n + simp [hasseDeriv_comp_coeff k l f n] + +/-- The derivative of a Laurent series. -/ +def derivative (R : Type*) {V : Type*} [AddCommGroup V] [Semiring R] [Module R V] : + LaurentSeries V →ₗ[R] LaurentSeries V := + hasseDeriv R 1 + +@[simp] +theorem derivative_apply (f : LaurentSeries V) : derivative R f = hasseDeriv R 1 f := by + exact rfl + +theorem derivative_iterate (k : ℕ) (f : LaurentSeries V) : + (derivative R)^[k] f = k.factorial • (hasseDeriv R k f) := by + ext n + induction k generalizing f with + | zero => simp + | succ k ih => + rw [Function.iterate_succ, Function.comp_apply, ih, derivative_apply, hasseDeriv_comp, + Nat.choose_symm_add, Nat.choose_one_right, Nat.factorial, mul_nsmul] + +@[simp] +theorem derivative_iterate_coeff (k : ℕ) (f : LaurentSeries V) (n : ℤ) : + ((derivative R)^[k] f).coeff n = (descPochhammer ℤ k).smeval (n + k) • f.coeff (n + k) := by + rw [derivative_iterate, nsmul_coeff, Pi.smul_apply, hasseDeriv_coeff, + Ring.descPochhammer_eq_factorial_smul_choose, smul_assoc] + end HasseDeriv section Semiring variable [Semiring R] -instance : Coe (PowerSeries R) (LaurentSeries R) := +instance : Coe R⟦X⟧ R⸨X⸩ := ⟨HahnSeries.ofPowerSeries ℤ R⟩ /- Porting note: now a syntactic tautology and not needed elsewhere -theorem coe_powerSeries (x : PowerSeries R) : - (x : LaurentSeries R) = HahnSeries.ofPowerSeries ℤ R x := +theorem coe_powerSeries (x : R⟦X⟧) : + (x : R⸨X⸩) = HahnSeries.ofPowerSeries ℤ R x := rfl -/ @[simp] -theorem coeff_coe_powerSeries (x : PowerSeries R) (n : ℕ) : - HahnSeries.coeff (x : LaurentSeries R) n = PowerSeries.coeff R n x := by +theorem coeff_coe_powerSeries (x : R⟦X⟧) (n : ℕ) : + HahnSeries.coeff (x : R⸨X⸩) n = PowerSeries.coeff R n x := by rw [ofPowerSeries_apply_coeff] /-- This is a power series that can be multiplied by an integer power of `X` to give our Laurent series. If the Laurent series is nonzero, `powerSeriesPart` has a nonzero constant term. -/ -def powerSeriesPart (x : LaurentSeries R) : PowerSeries R := +def powerSeriesPart (x : R⸨X⸩) : R⟦X⟧ := PowerSeries.mk fun n => x.coeff (x.order + n) @[simp] -theorem powerSeriesPart_coeff (x : LaurentSeries R) (n : ℕ) : +theorem powerSeriesPart_coeff (x : R⸨X⸩) (n : ℕ) : PowerSeries.coeff R n x.powerSeriesPart = x.coeff (x.order + n) := PowerSeries.coeff_mk _ _ @[simp] -theorem powerSeriesPart_zero : powerSeriesPart (0 : LaurentSeries R) = 0 := by +theorem powerSeriesPart_zero : powerSeriesPart (0 : R⸨X⸩) = 0 := by ext simp [(PowerSeries.coeff _ _).map_zero] -- Note: this doesn't get picked up any more @[simp] -theorem powerSeriesPart_eq_zero (x : LaurentSeries R) : x.powerSeriesPart = 0 ↔ x = 0 := by +theorem powerSeriesPart_eq_zero (x : R⸨X⸩) : x.powerSeriesPart = 0 ↔ x = 0 := by constructor · contrapose! simp only [ne_eq] @@ -136,8 +208,8 @@ theorem powerSeriesPart_eq_zero (x : LaurentSeries R) : x.powerSeriesPart = 0 simp @[simp] -theorem single_order_mul_powerSeriesPart (x : LaurentSeries R) : - (single x.order 1 : LaurentSeries R) * x.powerSeriesPart = x := by +theorem single_order_mul_powerSeriesPart (x : R⸨X⸩) : + (single x.order 1 : R⸨X⸩) * x.powerSeriesPart = x := by ext n rw [← sub_add_cancel n x.order, single_mul_coeff_add, sub_add_cancel, one_mul] by_cases h : x.order ≤ n @@ -153,25 +225,24 @@ theorem single_order_mul_powerSeriesPart (x : LaurentSeries R) : rw [← sub_nonneg, ← hm] simp only [Nat.cast_nonneg] -theorem ofPowerSeries_powerSeriesPart (x : LaurentSeries R) : +theorem ofPowerSeries_powerSeriesPart (x : R⸨X⸩) : ofPowerSeries ℤ R x.powerSeriesPart = single (-x.order) 1 * x := by refine Eq.trans ?_ (congr rfl x.single_order_mul_powerSeriesPart) rw [← mul_assoc, single_mul_single, neg_add_cancel, mul_one, ← C_apply, C_one, one_mul] end Semiring -instance [CommSemiring R] : Algebra (PowerSeries R) (LaurentSeries R) := - (HahnSeries.ofPowerSeries ℤ R).toAlgebra +instance [CommSemiring R] : Algebra R⟦X⟧ R⸨X⸩ := (HahnSeries.ofPowerSeries ℤ R).toAlgebra @[simp] theorem coe_algebraMap [CommSemiring R] : - ⇑(algebraMap (PowerSeries R) (LaurentSeries R)) = HahnSeries.ofPowerSeries ℤ R := + ⇑(algebraMap R⟦X⟧ R⸨X⸩) = HahnSeries.ofPowerSeries ℤ R := rfl /-- The localization map from power series to Laurent series. -/ @[simps (config := { rhsMd := .all, simpRhs := true })] instance of_powerSeries_localization [CommRing R] : - IsLocalization (Submonoid.powers (PowerSeries.X : PowerSeries R)) (LaurentSeries R) where + IsLocalization (Submonoid.powers (PowerSeries.X : R⟦X⟧)) R⸨X⸩ where map_units' := by rintro ⟨_, n, rfl⟩ refine ⟨⟨single (n : ℤ) 1, single (-n : ℤ) 1, ?_, ?_⟩, ?_⟩ @@ -195,8 +266,8 @@ instance of_powerSeries_localization [CommRing R] : rintro rfl exact ⟨1, rfl⟩ -instance {K : Type*} [Field K] : IsFractionRing (PowerSeries K) (LaurentSeries K) := - IsLocalization.of_le (Submonoid.powers (PowerSeries.X : PowerSeries K)) _ +instance {K : Type*} [Field K] : IsFractionRing K⟦X⟧ K⸨X⸩ := + IsLocalization.of_le (Submonoid.powers (PowerSeries.X : K⟦X⟧)) _ (powers_le_nonZeroDivisors_of_noZeroDivisors PowerSeries.X_ne_zero) fun _ hf => isUnit_of_mem_nonZeroDivisors <| map_mem_nonZeroDivisors _ HahnSeries.ofPowerSeries_injective hf @@ -206,34 +277,34 @@ namespace PowerSeries open LaurentSeries -variable {R' : Type*} [Semiring R] [Ring R'] (f g : PowerSeries R) (f' g' : PowerSeries R') +variable {R' : Type*} [Semiring R] [Ring R'] (f g : R⟦X⟧) (f' g' : R'⟦X⟧) -@[norm_cast] -- Porting note (#10618): simp can prove this -theorem coe_zero : ((0 : PowerSeries R) : LaurentSeries R) = 0 := +@[norm_cast] +theorem coe_zero : ((0 : R⟦X⟧) : R⸨X⸩) = 0 := (ofPowerSeries ℤ R).map_zero -@[norm_cast] -- Porting note (#10618): simp can prove this -theorem coe_one : ((1 : PowerSeries R) : LaurentSeries R) = 1 := +@[norm_cast] +theorem coe_one : ((1 : R⟦X⟧) : R⸨X⸩) = 1 := (ofPowerSeries ℤ R).map_one -@[norm_cast] -- Porting note (#10618): simp can prove this -theorem coe_add : ((f + g : PowerSeries R) : LaurentSeries R) = f + g := +@[norm_cast] +theorem coe_add : ((f + g : R⟦X⟧) : R⸨X⸩) = f + g := (ofPowerSeries ℤ R).map_add _ _ @[norm_cast] -theorem coe_sub : ((f' - g' : PowerSeries R') : LaurentSeries R') = f' - g' := +theorem coe_sub : ((f' - g' : R'⟦X⟧) : R'⸨X⸩) = f' - g' := (ofPowerSeries ℤ R').map_sub _ _ @[norm_cast] -theorem coe_neg : ((-f' : PowerSeries R') : LaurentSeries R') = -f' := +theorem coe_neg : ((-f' : R'⟦X⟧) : R'⸨X⸩) = -f' := (ofPowerSeries ℤ R').map_neg _ -@[norm_cast] -- Porting note (#10618): simp can prove this -theorem coe_mul : ((f * g : PowerSeries R) : LaurentSeries R) = f * g := +@[norm_cast] +theorem coe_mul : ((f * g : R⟦X⟧) : R⸨X⸩) = f * g := (ofPowerSeries ℤ R).map_mul _ _ theorem coeff_coe (i : ℤ) : - ((f : PowerSeries R) : LaurentSeries R).coeff i = + ((f : R⟦X⟧) : R⸨X⸩).coeff i = if i < 0 then 0 else PowerSeries.coeff R i.natAbs f := by cases i · rw [Int.ofNat_eq_coe, coeff_coe_powerSeries, if_neg (Int.natCast_nonneg _).not_lt, @@ -243,59 +314,58 @@ theorem coeff_coe (i : ℤ) : Ne, toPowerSeries_symm_apply_coeff, mem_support, imp_true_iff, not_false_iff, reduceCtorEq] --- Porting note (#10618): simp can prove this --- Porting note: removed norm_cast attribute -theorem coe_C (r : R) : ((C R r : PowerSeries R) : LaurentSeries R) = HahnSeries.C r := +theorem coe_C (r : R) : ((C R r : R⟦X⟧) : R⸨X⸩) = HahnSeries.C r := ofPowerSeries_C _ --- @[simp] -- Porting note (#10618): simp can prove this -theorem coe_X : ((X : PowerSeries R) : LaurentSeries R) = single 1 1 := +theorem coe_X : ((X : R⟦X⟧) : R⸨X⸩) = single 1 1 := ofPowerSeries_X @[simp, norm_cast] -theorem coe_smul {S : Type*} [Semiring S] [Module R S] (r : R) (x : PowerSeries S) : - ((r • x : PowerSeries S) : LaurentSeries S) = r • (ofPowerSeries ℤ S x) := by +theorem coe_smul {S : Type*} [Semiring S] [Module R S] (r : R) (x : S⟦X⟧) : + ((r • x : S⟦X⟧) : S⸨X⸩) = r • (ofPowerSeries ℤ S x) := by ext simp [coeff_coe, coeff_smul, smul_ite] -- Porting note: RingHom.map_bit0 and RingHom.map_bit1 no longer exist @[norm_cast] -theorem coe_pow (n : ℕ) : ((f ^ n : PowerSeries R) : LaurentSeries R) = (ofPowerSeries ℤ R f) ^ n := +theorem coe_pow (n : ℕ) : ((f ^ n : R⟦X⟧) : R⸨X⸩) = (ofPowerSeries ℤ R f) ^ n := (ofPowerSeries ℤ R).map_pow _ _ end PowerSeries namespace RatFunc +open scoped LaurentSeries + variable {F : Type u} [Field F] (p q : F[X]) (f g : RatFunc F) -/-- The coercion `RatFunc F → LaurentSeries F` as bundled alg hom. -/ -def coeAlgHom (F : Type u) [Field F] : RatFunc F →ₐ[F[X]] LaurentSeries F := +/-- The coercion `RatFunc F → F⸨X⸩` as bundled alg hom. -/ +def coeAlgHom (F : Type u) [Field F] : RatFunc F →ₐ[F[X]] F⸨X⸩ := liftAlgHom (Algebra.ofId _ _) <| nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ <| Polynomial.algebraMap_hahnSeries_injective _ -/-- The coercion `RatFunc F → LaurentSeries F` as a function. +/-- The coercion `RatFunc F → F⸨X⸩` as a function. This is the implementation of `coeToLaurentSeries`. -/ @[coe] -def coeToLaurentSeries_fun {F : Type u} [Field F] : RatFunc F → LaurentSeries F := +def coeToLaurentSeries_fun {F : Type u} [Field F] : RatFunc F → F⸨X⸩ := coeAlgHom F -instance coeToLaurentSeries : Coe (RatFunc F) (LaurentSeries F) := +instance coeToLaurentSeries : Coe (RatFunc F) F⸨X⸩ := ⟨coeToLaurentSeries_fun⟩ -theorem coe_def : (f : LaurentSeries F) = coeAlgHom F f := +theorem coe_def : (f : F⸨X⸩) = coeAlgHom F f := rfl attribute [-instance] RatFunc.instCoePolynomial in -- avoids a diamond, see https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/compiling.20behaviour.20within.20one.20file -theorem coe_num_denom : (f : LaurentSeries F) = f.num / f.denom := +theorem coe_num_denom : (f : F⸨X⸩) = f.num / f.denom := liftAlgHom_apply _ _ f -theorem coe_injective : Function.Injective ((↑) : RatFunc F → LaurentSeries F) := +theorem coe_injective : Function.Injective ((↑) : RatFunc F → F⸨X⸩) := liftAlgHom_injective _ (Polynomial.algebraMap_hahnSeries_injective _) -- Porting note: removed the `norm_cast` tag: @@ -305,47 +375,46 @@ theorem coe_apply : coeAlgHom F f = f := rfl -- avoids a diamond, see https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/compiling.20behaviour.20within.20one.20file -theorem coe_coe (P : Polynomial F) : ((P : PowerSeries F) : LaurentSeries F) = (P : RatFunc F) := by +theorem coe_coe (P : Polynomial F) : ((P : F⟦X⟧) : F⸨X⸩) = (P : RatFunc F) := by simp only [coePolynomial, coe_def, AlgHom.commutes, algebraMap_hahnSeries_apply] @[simp, norm_cast] -theorem coe_zero : ((0 : RatFunc F) : LaurentSeries F) = 0 := +theorem coe_zero : ((0 : RatFunc F) : F⸨X⸩) = 0 := map_zero (coeAlgHom F) -theorem coe_ne_zero {f : Polynomial F} (hf : f ≠ 0) : (↑f : PowerSeries F) ≠ 0 := by +theorem coe_ne_zero {f : Polynomial F} (hf : f ≠ 0) : (↑f : F⟦X⟧) ≠ 0 := by simp only [ne_eq, Polynomial.coe_eq_zero_iff, hf, not_false_eq_true] @[simp, norm_cast] -theorem coe_one : ((1 : RatFunc F) : LaurentSeries F) = 1 := +theorem coe_one : ((1 : RatFunc F) : F⸨X⸩) = 1 := map_one (coeAlgHom F) @[simp, norm_cast] -theorem coe_add : ((f + g : RatFunc F) : LaurentSeries F) = f + g := +theorem coe_add : ((f + g : RatFunc F) : F⸨X⸩) = f + g := map_add (coeAlgHom F) _ _ @[simp, norm_cast] -theorem coe_sub : ((f - g : RatFunc F) : LaurentSeries F) = f - g := +theorem coe_sub : ((f - g : RatFunc F) : F⸨X⸩) = f - g := map_sub (coeAlgHom F) _ _ @[simp, norm_cast] -theorem coe_neg : ((-f : RatFunc F) : LaurentSeries F) = -f := +theorem coe_neg : ((-f : RatFunc F) : F⸨X⸩) = -f := map_neg (coeAlgHom F) _ @[simp, norm_cast] -theorem coe_mul : ((f * g : RatFunc F) : LaurentSeries F) = f * g := +theorem coe_mul : ((f * g : RatFunc F) : F⸨X⸩) = f * g := map_mul (coeAlgHom F) _ _ @[simp, norm_cast] -theorem coe_pow (n : ℕ) : ((f ^ n : RatFunc F) : LaurentSeries F) = (f : LaurentSeries F) ^ n := +theorem coe_pow (n : ℕ) : ((f ^ n : RatFunc F) : F⸨X⸩) = (f : F⸨X⸩) ^ n := map_pow (coeAlgHom F) _ _ @[simp, norm_cast] -theorem coe_div : - ((f / g : RatFunc F) : LaurentSeries F) = (f : LaurentSeries F) / (g : LaurentSeries F) := +theorem coe_div : ((f / g : RatFunc F) : F⸨X⸩) = (f : F⸨X⸩) / (g : F⸨X⸩) := map_div₀ (coeAlgHom F) _ _ @[simp, norm_cast] -theorem coe_C (r : F) : ((RatFunc.C r : RatFunc F) : LaurentSeries F) = HahnSeries.C r := by +theorem coe_C (r : F) : ((RatFunc.C r : RatFunc F) : F⸨X⸩) = HahnSeries.C r := by rw [coe_num_denom, num_C, denom_C, Polynomial.coe_C, -- Porting note: removed `coe_C` Polynomial.coe_one, PowerSeries.coe_one, div_one] @@ -353,13 +422,13 @@ theorem coe_C (r : F) : ((RatFunc.C r : RatFunc F) : LaurentSeries F) = HahnSeri -- TODO: generalize over other modules @[simp, norm_cast] -theorem coe_smul (r : F) : ((r • f : RatFunc F) : LaurentSeries F) = r • (f : LaurentSeries F) := by +theorem coe_smul (r : F) : ((r • f : RatFunc F) : F⸨X⸩) = r • (f : F⸨X⸩) := by rw [RatFunc.smul_eq_C_mul, ← C_mul_eq_smul, coe_mul, coe_C] -- Porting note: removed `norm_cast` because "badly shaped lemma, rhs can't start with coe" -- even though `single 1 1` is a bundled function application, not a "real" coercion @[simp] -theorem coe_X : ((X : RatFunc F) : LaurentSeries F) = single 1 1 := by +theorem coe_X : ((X : RatFunc F) : F⸨X⸩) = single 1 1 := by rw [coe_num_denom, num_X, denom_X, Polynomial.coe_X, -- Porting note: removed `coe_C` Polynomial.coe_one, PowerSeries.coe_one, div_one] @@ -385,18 +454,18 @@ theorem single_zpow (n : ℤ) : single_inv (n_neg + 1 : ℤ) one_ne_zero, zpow_neg, ← Nat.cast_one, ← Int.ofNat_add, Nat.cast_one, inv_inj, zpow_natCast, single_one_eq_pow, inv_one] -instance : Algebra (RatFunc F) (LaurentSeries F) := +instance : Algebra (RatFunc F) F⸨X⸩ := RingHom.toAlgebra (coeAlgHom F).toRingHom theorem algebraMap_apply_div : - algebraMap (RatFunc F) (LaurentSeries F) (algebraMap _ _ p / algebraMap _ _ q) = - algebraMap F[X] (LaurentSeries F) p / algebraMap _ _ q := by + algebraMap (RatFunc F) F⸨X⸩ (algebraMap _ _ p / algebraMap _ _ q) = + algebraMap F[X] F⸨X⸩ p / algebraMap _ _ q := by -- Porting note: had to supply implicit arguments to `convert` convert coe_div (algebraMap F[X] (RatFunc F) p) (algebraMap F[X] (RatFunc F) q) <;> rw [← mk_one, coe_def, coeAlgHom, mk_eq_div, liftAlgHom_apply_div, map_one, div_one, Algebra.ofId_apply] -instance : IsScalarTower F[X] (RatFunc F) (LaurentSeries F) := +instance : IsScalarTower F[X] (RatFunc F) F⸨X⸩ := ⟨fun x y z => by ext simp⟩ @@ -409,8 +478,7 @@ open scoped Multiplicative variable (K : Type*) [Field K] namespace PowerSeries -/-- The prime ideal `(X)` of `PowerSeries K`, when `K` is a field, as a term of the -`HeightOneSpectrum`. -/ +/-- The prime ideal `(X)` of `K⟦X⟧`, when `K` is a field, as a term of the `HeightOneSpectrum`. -/ def idealX : IsDedekindDomain.HeightOneSpectrum K⟦X⟧ where asIdeal := Ideal.span {X} isPrime := PowerSeries.span_X_isPrime @@ -456,13 +524,14 @@ end PowerSeries namespace RatFunc open IsDedekindDomain.HeightOneSpectrum PowerSeries +open scoped LaurentSeries theorem valuation_eq_LaurentSeries_valuation (P : RatFunc K) : - (Polynomial.idealX K).valuation P = (PowerSeries.idealX K).valuation (P : LaurentSeries K) := by + (Polynomial.idealX K).valuation P = (PowerSeries.idealX K).valuation (P : K⸨X⸩) := by refine RatFunc.induction_on' P ?_ intro f g h rw [Polynomial.valuation_of_mk K f h, RatFunc.mk_eq_mk' f h, Eq.comm] - convert @valuation_of_mk' (PowerSeries K) _ _ (LaurentSeries K) _ _ _ (PowerSeries.idealX K) f + convert @valuation_of_mk' K⟦X⟧ _ _ K⸨X⸩ _ _ _ (PowerSeries.idealX K) f ⟨g, mem_nonZeroDivisors_iff_ne_zero.2 <| coe_ne_zero h⟩ · simp only [IsFractionRing.mk'_eq_div, coe_div, LaurentSeries.coe_algebraMap, coe_coe] rfl @@ -475,18 +544,18 @@ namespace LaurentSeries open IsDedekindDomain.HeightOneSpectrum PowerSeries RatFunc -instance : Valued (LaurentSeries K) ℤₘ₀ := Valued.mk' (PowerSeries.idealX K).valuation +instance : Valued K⸨X⸩ ℤₘ₀ := Valued.mk' (PowerSeries.idealX K).valuation theorem valuation_X_pow (s : ℕ) : - Valued.v (((X : K⟦X⟧) : LaurentSeries K) ^ s) = Multiplicative.ofAdd (-(s : ℤ)) := by + Valued.v (((X : K⟦X⟧) : K⸨X⸩) ^ s) = Multiplicative.ofAdd (-(s : ℤ)) := by erw [map_pow, ← one_mul (s : ℤ), ← neg_mul (1 : ℤ) s, Int.ofAdd_mul, WithZero.coe_zpow, ofAdd_neg, WithZero.coe_inv, zpow_natCast, valuation_of_algebraMap, intValuation_toFun, intValuation_X, ofAdd_neg, WithZero.coe_inv, inv_pow] theorem valuation_single_zpow (s : ℤ) : - Valued.v (HahnSeries.single s (1 : K) : LaurentSeries K) = + Valued.v (HahnSeries.single s (1 : K) : K⸨X⸩) = Multiplicative.ofAdd (-(s : ℤ)) := by - have : Valued.v (1 : LaurentSeries K) = (1 : ℤₘ₀) := Valued.v.map_one + have : Valued.v (1 : K⸨X⸩) = (1 : ℤₘ₀) := Valued.v.map_one rw [← single_zero_one, ← add_neg_cancel s, ← mul_one 1, ← single_mul_single, map_mul, mul_eq_one_iff_eq_inv₀] at this · rw [this] @@ -499,18 +568,18 @@ theorem valuation_single_zpow (s : ℤ) : /- The coefficients of a power series vanish in degree strictly less than its valuation. -/ theorem coeff_zero_of_lt_intValuation {n d : ℕ} {f : K⟦X⟧} - (H : Valued.v (f : LaurentSeries K) ≤ Multiplicative.ofAdd (-d : ℤ)) : + (H : Valued.v (f : K⸨X⸩) ≤ Multiplicative.ofAdd (-d : ℤ)) : n < d → coeff K n f = 0 := by intro hnd apply (PowerSeries.X_pow_dvd_iff).mp _ n hnd erw [← span_singleton_dvd_span_singleton_iff_dvd, ← Ideal.span_singleton_pow, ← (intValuation_le_pow_iff_dvd (PowerSeries.idealX K) f d), ← intValuation_apply, - ← valuation_of_algebraMap (R := K⟦X⟧) (K := (LaurentSeries K))] + ← valuation_of_algebraMap (R := K⟦X⟧) (K := K⸨X⸩)] exact H /- The valuation of a power series is the order of the first non-zero coefficient. -/ theorem intValuation_le_iff_coeff_lt_eq_zero {d : ℕ} (f : K⟦X⟧) : - Valued.v (f : LaurentSeries K) ≤ Multiplicative.ofAdd (-d : ℤ) ↔ + Valued.v (f : K⸨X⸩) ≤ Multiplicative.ofAdd (-d : ℤ) ↔ ∀ n : ℕ, n < d → coeff K n f = 0 := by have : PowerSeries.X ^ d ∣ f ↔ ∀ n : ℕ, n < d → (PowerSeries.coeff K n) f = 0 := ⟨PowerSeries.X_pow_dvd_iff.mp, PowerSeries.X_pow_dvd_iff.mpr⟩ @@ -519,7 +588,7 @@ theorem intValuation_le_iff_coeff_lt_eq_zero {d : ℕ} (f : K⟦X⟧) : apply intValuation_le_pow_iff_dvd /- The coefficients of a Laurent series vanish in degree strictly less than its valuation. -/ -theorem coeff_zero_of_lt_valuation {n D : ℤ} {f : LaurentSeries K} +theorem coeff_zero_of_lt_valuation {n D : ℤ} {f : K⸨X⸩} (H : Valued.v f ≤ Multiplicative.ofAdd (-D)) : n < D → f.coeff n = 0 := by intro hnd by_cases h_n_ord : n < f.order @@ -547,7 +616,7 @@ theorem coeff_zero_of_lt_valuation {n D : ℤ} {f : LaurentSeries K} mul_le_mul_left (by simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff, zero_lt_iff])] /- The valuation of a Laurent series is the order of the first non-zero coefficient. -/ -theorem valuation_le_iff_coeff_lt_eq_zero {D : ℤ} {f : LaurentSeries K} : +theorem valuation_le_iff_coeff_lt_eq_zero {D : ℤ} {f : K⸨X⸩} : Valued.v f ≤ ↑(Multiplicative.ofAdd (-D : ℤ)) ↔ ∀ n : ℤ, n < D → f.coeff n = 0 := by refine ⟨fun hnD n hn => coeff_zero_of_lt_valuation K hnD hn, fun h_val_f => ?_⟩ let F := powerSeriesPart f @@ -589,18 +658,18 @@ theorem valuation_le_iff_coeff_lt_eq_zero {D : ℤ} {f : LaurentSeries K} : /- Two Laurent series whose difference has small valuation have the same coefficients for small enough indices. -/ -theorem eq_coeff_of_valuation_sub_lt {d n : ℤ} {f g : LaurentSeries K} +theorem eq_coeff_of_valuation_sub_lt {d n : ℤ} {f g : K⸨X⸩} (H : Valued.v (g - f) ≤ ↑(Multiplicative.ofAdd (-d))) : n < d → g.coeff n = f.coeff n := by by_cases triv : g = f · exact fun _ => by rw [triv] · intro hn apply eq_of_sub_eq_zero - erw [← HahnSeries.sub_coeff] + rw [← HahnSeries.sub_coeff] apply coeff_zero_of_lt_valuation K H hn /- Every Laurent series of valuation less than `(1 : ℤₘ₀)` comes from a power series. -/ -theorem val_le_one_iff_eq_coe (f : LaurentSeries K) : Valued.v f ≤ (1 : ℤₘ₀) ↔ - ∃ F : PowerSeries K, F = f := by +theorem val_le_one_iff_eq_coe (f : K⸨X⸩) : Valued.v f ≤ (1 : ℤₘ₀) ↔ + ∃ F : K⟦X⟧, F = f := by rw [← WithZero.coe_one, ← ofAdd_zero, ← neg_zero, valuation_le_iff_coeff_lt_eq_zero] refine ⟨fun h => ⟨PowerSeries.mk fun n => f.coeff n, ?_⟩, ?_⟩ on_goal 1 => ext (_ | n) @@ -630,23 +699,23 @@ variable {K : Type*} [Field K] /- Sending a Laurent series to its `d`-th coefficient is uniformly continuous (independently of the uniformity with which `K` is endowed). -/ theorem uniformContinuous_coeff {uK : UniformSpace K} (d : ℤ) : - UniformContinuous fun f : LaurentSeries K ↦ f.coeff d := by + UniformContinuous fun f : K⸨X⸩ ↦ f.coeff d := by refine uniformContinuous_iff_eventually.mpr fun S hS ↦ eventually_iff_exists_mem.mpr ?_ let γ : ℤₘ₀ˣ := Units.mk0 (↑(Multiplicative.ofAdd (-(d + 1)))) WithZero.coe_ne_zero use {P | Valued.v (P.snd - P.fst) < ↑γ} - refine ⟨(Valued.hasBasis_uniformity (LaurentSeries K) ℤₘ₀).mem_of_mem (by tauto), fun P hP ↦ ?_⟩ + refine ⟨(Valued.hasBasis_uniformity K⸨X⸩ ℤₘ₀).mem_of_mem (by tauto), fun P hP ↦ ?_⟩ rw [eq_coeff_of_valuation_sub_lt K (le_of_lt hP) (lt_add_one _)] exact mem_uniformity_of_eq hS rfl /-- Since extracting coefficients is uniformly continuous, every Cauchy filter in -`laurentSeries K` gives rise to a Cauchy filter in `K` for every `d : ℤ`, and such Cauchy filter +`K⸨X⸩` gives rise to a Cauchy filter in `K` for every `d : ℤ`, and such Cauchy filter in `K` converges to a principal filter -/ -def Cauchy.coeff {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : ℤ → K := +def Cauchy.coeff {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : ℤ → K := let _ : UniformSpace K := ⊥ fun d ↦ UniformSpace.DiscreteUnif.cauchyConst rfl <| hℱ.map (uniformContinuous_coeff d) -theorem Cauchy.coeff_tendsto {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) (D : ℤ) : - Tendsto (fun f : LaurentSeries K ↦ f.coeff D) ℱ (𝓟 {coeff hℱ D}) := +theorem Cauchy.coeff_tendsto {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) (D : ℤ) : + Tendsto (fun f : K⸨X⸩ ↦ f.coeff D) ℱ (𝓟 {coeff hℱ D}) := let _ : UniformSpace K := ⊥ le_of_eq <| UniformSpace.DiscreteUnif.eq_const_of_cauchy (by rfl) (hℱ.map (uniformContinuous_coeff D)) ▸ (principal_singleton _).symm @@ -660,16 +729,16 @@ beyond the special case `Γ = ℤ`, that corresponds to Laurent Series: neverthe does not generalise, as it relies on the study of the `X`-adic valuation attached to the height-one prime `X`, and this is peculiar to the one-variable setting. In the future we should prove this result in full generality and deduce the case `Γ = ℤ` from that one.-/ -lemma Cauchy.exists_lb_eventual_support {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : - ∃ N, ∀ᶠ f : LaurentSeries K in ℱ, ∀ n < N, f.coeff n = (0 : K) := by - let entourage : Set (LaurentSeries K × LaurentSeries K) := - {P : LaurentSeries K × LaurentSeries K | +lemma Cauchy.exists_lb_eventual_support {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : + ∃ N, ∀ᶠ f : K⸨X⸩ in ℱ, ∀ n < N, f.coeff n = (0 : K) := by + let entourage : Set (K⸨X⸩ × K⸨X⸩) := + {P : K⸨X⸩ × K⸨X⸩ | Valued.v (P.snd - P.fst) < ((Multiplicative.ofAdd 0 : Multiplicative ℤ) : ℤₘ₀)} let ζ := Units.mk0 (G₀ := ℤₘ₀) _ (WithZero.coe_ne_zero (a := (Multiplicative.ofAdd 0))) obtain ⟨S, ⟨hS, ⟨T, ⟨hT, H⟩⟩⟩⟩ := mem_prod_iff.mp <| Filter.le_def.mp hℱ.2 entourage - <| (Valued.hasBasis_uniformity (LaurentSeries K) ℤₘ₀).mem_of_mem (i := ζ) (by tauto) + <| (Valued.hasBasis_uniformity K⸨X⸩ ℤₘ₀).mem_of_mem (i := ζ) (by tauto) obtain ⟨f, hf⟩ := forall_mem_nonempty_iff_neBot.mpr hℱ.1 (S ∩ T) (inter_mem_iff.mpr ⟨hS, hT⟩) - obtain ⟨N, hN⟩ : ∃ N : ℤ, ∀ g : LaurentSeries K, + obtain ⟨N, hN⟩ : ∃ N : ℤ, ∀ g : K⸨X⸩, Valued.v (g - f) ≤ ↑(Multiplicative.ofAdd (0 : ℤ)) → ∀ n < N, g.coeff n = 0 := by by_cases hf : f = 0 · refine ⟨0, fun x hg ↦ ?_⟩ @@ -689,7 +758,7 @@ lemma Cauchy.exists_lb_eventual_support {ℱ : Filter (LaurentSeries K)} (hℱ : exact hN g (le_of_lt h_prod) /- The support of `Cauchy.coeff` has a lower bound. -/ -theorem Cauchy.exists_lb_support {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : +theorem Cauchy.exists_lb_support {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : ∃ N, ∀ n, n < N → coeff hℱ n = 0 := by let _ : UniformSpace K := ⊥ obtain ⟨N, hN⟩ := exists_lb_eventual_support hℱ @@ -699,36 +768,36 @@ theorem Cauchy.exists_lb_support {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy apply Filter.mem_of_superset hN (fun _ ha ↦ ha _ hn) /- The support of `Cauchy.coeff` is bounded below -/ -theorem Cauchy.coeff_support_bddBelow {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : +theorem Cauchy.coeff_support_bddBelow {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : BddBelow (coeff hℱ).support := by refine ⟨(exists_lb_support hℱ).choose, fun d hd ↦ ?_⟩ by_contra hNd exact hd ((exists_lb_support hℱ).choose_spec d (not_le.mp hNd)) -/-- To any Cauchy filter ℱ of `LaurentSeries K`, we can attach a laurent series that is the limit +/-- To any Cauchy filter ℱ of `K⸨X⸩`, we can attach a laurent series that is the limit of the filter. Its `d`-th coefficient is defined as the limit of `Cauchy.coeff hℱ d`, which is again Cauchy but valued in the discrete space `K`. That sufficiently negative coefficients vanish follows from `Cauchy.coeff_support_bddBelow` -/ -def Cauchy.limit {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : LaurentSeries K := +def Cauchy.limit {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : K⸨X⸩ := HahnSeries.mk (coeff hℱ) <| Set.IsWF.isPWO (coeff_support_bddBelow _).wellFoundedOn_lt /- The following lemma shows that for every `d` smaller than the minimum between the integers produced in `Cauchy.exists_lb_eventual_support` and `Cauchy.exists_lb_support`, for almost all series in `ℱ` the `d`th coefficient coincides with the `d`th coefficient of `Cauchy.coeff hℱ`. -/ -theorem Cauchy.exists_lb_coeff_ne {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) : - ∃ N, ∀ᶠ f : LaurentSeries K in ℱ, ∀ d < N, coeff hℱ d = f.coeff d := by +theorem Cauchy.exists_lb_coeff_ne {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) : + ∃ N, ∀ᶠ f : K⸨X⸩ in ℱ, ∀ d < N, coeff hℱ d = f.coeff d := by obtain ⟨⟨N₁, hN₁⟩, ⟨N₂, hN₂⟩⟩ := exists_lb_eventual_support hℱ, exists_lb_support hℱ refine ⟨min N₁ N₂, ℱ.3 hN₁ fun _ hf d hd ↦ ?_⟩ rw [hf d (lt_of_lt_of_le hd (min_le_left _ _)), hN₂ d (lt_of_lt_of_le hd (min_le_right _ _))] /- Given a Cauchy filter `ℱ` in the Laurent Series and a bound `D`, for almost all series in the filter the coefficients below `D` coincide with `Caucy.coeff hℱ`-/ -theorem Cauchy.coeff_eventually_equal {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) {D : ℤ} : - ∀ᶠ f : LaurentSeries K in ℱ, ∀ d, d < D → coeff hℱ d = f.coeff d := by +theorem Cauchy.coeff_eventually_equal {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) {D : ℤ} : + ∀ᶠ f : K⸨X⸩ in ℱ, ∀ d, d < D → coeff hℱ d = f.coeff d := by -- `φ` sends `d` to the set of Laurent Series having `d`th coefficient equal to `ℱ.coeff`. - let φ : ℤ → Set (LaurentSeries K) := fun d ↦ {f | coeff hℱ d = f.coeff d} + let φ : ℤ → Set K⸨X⸩ := fun d ↦ {f | coeff hℱ d = f.coeff d} have intersec₁ : - (⋂ n ∈ Set.Iio D, φ n) ⊆ {x : LaurentSeries K | ∀ d : ℤ, d < D → coeff hℱ d = x.coeff d} := by + (⋂ n ∈ Set.Iio D, φ n) ⊆ {x : K⸨X⸩ | ∀ d : ℤ, d < D → coeff hℱ d = x.coeff d} := by intro _ hf simpa only [Set.mem_iInter] using hf -- The goal is now to show that the intersection of all `φ d` (for `d < D`) is in `ℱ`. @@ -761,10 +830,10 @@ theorem Cauchy.coeff_eventually_equal {ℱ : Filter (LaurentSeries K)} (hℱ : C open scoped Topology /- The main result showing that the Cauchy filter tends to the `Cauchy.limit`-/ -theorem Cauchy.eventually_mem_nhds {ℱ : Filter (LaurentSeries K)} (hℱ : Cauchy ℱ) - {U : Set (LaurentSeries K)} (hU : U ∈ 𝓝 (Cauchy.limit hℱ)) : ∀ᶠ f in ℱ, f ∈ U := by +theorem Cauchy.eventually_mem_nhds {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) + {U : Set K⸨X⸩} (hU : U ∈ 𝓝 (Cauchy.limit hℱ)) : ∀ᶠ f in ℱ, f ∈ U := by obtain ⟨γ, hU₁⟩ := Valued.mem_nhds.mp hU - suffices ∀ᶠ f in ℱ, f ∈ {y : LaurentSeries K | Valued.v (y - limit hℱ) < ↑γ} by + suffices ∀ᶠ f in ℱ, f ∈ {y : K⸨X⸩ | Valued.v (y - limit hℱ) < ↑γ} by apply this.mono fun _ hf ↦ hU₁ hf set D := -(Multiplicative.toAdd (WithZero.unzero γ.ne_zero) - 1) with hD₀ have hD : ((Multiplicative.ofAdd (-D) : Multiplicative ℤ) : ℤₘ₀) < γ := by @@ -778,7 +847,7 @@ theorem Cauchy.eventually_mem_nhds {ℱ : Filter (LaurentSeries K)} (hℱ : Cauc rw [HahnSeries.sub_coeff, sub_eq_zero, hf n hn |>.symm]; rfl /- Laurent Series with coefficients in a field are complete w.r.t. the `X`-adic valuation -/ -instance instLaurentSeriesComplete : CompleteSpace (LaurentSeries K) := +instance instLaurentSeriesComplete : CompleteSpace K⸨X⸩ := ⟨fun hℱ ↦ ⟨Cauchy.limit hℱ, fun _ hS ↦ Cauchy.eventually_mem_nhds hℱ hS⟩⟩ end Complete diff --git a/Mathlib/RingTheory/LinearDisjoint.lean b/Mathlib/RingTheory/LinearDisjoint.lean new file mode 100644 index 0000000000000..09364c45df136 --- /dev/null +++ b/Mathlib/RingTheory/LinearDisjoint.lean @@ -0,0 +1,604 @@ +/- +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.LinearDisjoint +import Mathlib.LinearAlgebra.TensorProduct.Subalgebra +import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.Algebra.Algebra.Subalgebra.MulOpposite +import Mathlib.Algebra.Algebra.Subalgebra.Rank +import Mathlib.RingTheory.IntegralClosure.Algebra.Defs +import Mathlib.RingTheory.IntegralClosure.IsIntegral.Basic + +/-! + +# Linearly disjoint subalgebras + +This file contains basics about linearly disjoint subalgebras. +We adapt the definitions in . +See the file `Mathlib/LinearAlgebra/LinearDisjoint.lean` for details. + +## Main definitions + +- `Subalgebra.LinearDisjoint`: two subalgebras are linearly disjoint, if they are + linearly disjoint as submodules (`Submodule.LinearDisjoint`). + +- `Subalgebra.LinearDisjoint.mulMap`: if two subalgebras `A` and `B` of `S / R` are + linearly disjoint, then there is `A ⊗[R] B ≃ₐ[R] A ⊔ B` induced by multiplication in `S`. + +## Main results + +### Equivalent characterization of linearly disjointness + +- `Subalgebra.LinearDisjoint.linearIndependent_left_of_flat`: + if `A` and `B` are linearly disjoint, and if `B` is a flat `R`-module, then for any family of + `R`-linearly independent elements of `A`, they are also `B`-linearly independent. + +- `Subalgebra.LinearDisjoint.of_basis_left_op`: + conversely, if a basis of `A` is also `B`-linearly independent, then `A` and `B` are + linearly disjoint. + +- `Subalgebra.LinearDisjoint.linearIndependent_right_of_flat`: + if `A` and `B` are linearly disjoint, and if `A` is a flat `R`-module, then for any family of + `R`-linearly independent elements of `B`, they are also `A`-linearly independent. + +- `Subalgebra.LinearDisjoint.of_basis_right`: + conversely, if a basis of `B` is also `A`-linearly independent, + then `A` and `B` are linearly disjoint. + +- `Subalgebra.LinearDisjoint.linearIndependent_mul_of_flat`: + if `A` and `B` are linearly disjoint, and if one of `A` and `B` is flat, then for any family of + `R`-linearly independent elements `{ a_i }` of `A`, and any family of + `R`-linearly independent elements `{ b_j }` of `B`, the family `{ a_i * b_j }` in `S` is + also `R`-linearly independent. + +- `Subalgebra.LinearDisjoint.of_basis_mul`: + conversely, if `{ a_i }` is an `R`-basis of `A`, if `{ b_j }` is an `R`-basis of `B`, + such that the family `{ a_i * b_j }` in `S` is `R`-linearly independent, + then `A` and `B` are linearly disjoint. + +### Other main results + +- `Subalgebra.LinearDisjoint.symm_of_commute`, `Subalgebra.linearDisjoint_symm_of_commute`: + linearly disjoint is symmetric under some commutative conditions. + +- `Subalgebra.LinearDisjoint.bot_left`, `Subalgebra.LinearDisjoint.bot_right`: + the image of `R` in `S` is linearly disjoint with any other subalgebras. + +- `Subalgebra.LinearDisjoint.sup_free_of_free`: the compositum of two linearly disjoint + subalgebras is a free module, if two subalgebras are also free modules. + +- `Subalgebra.LinearDisjoint.rank_sup_of_free`, + `Subalgebra.LinearDisjoint.finrank_sup_of_free`: + if subalgebras `A` and `B` are linearly disjoint and they are + free modules, then the rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`. + +- `Subalgebra.LinearDisjoint.of_finrank_sup_of_free`: + conversely, if `A` and `B` are subalgebras which are free modules of finite rank, + such that rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`, + then `A` and `B` are linearly disjoint. + +- `Subalgebra.LinearDisjoint.adjoin_rank_eq_rank_left`: + `Subalgebra.LinearDisjoint.adjoin_rank_eq_rank_right`: + if `A` and `B` are linearly disjoint, if `A` is free and `B` is flat (resp. `B` is free and + `A` is flat), then `[B[A] : B] = [A : R]` (resp. `[A[B] : A] = [B : R]`). + See also `Subalgebra.adjoin_rank_le`. + +- `Subalgebra.LinearDisjoint.of_finrank_coprime_of_free`: + if the rank of `A` and `B` are coprime, and they satisfy some freeness condition, + then `A` and `B` are linearly disjoint. + +- `Subalgebra.LinearDisjoint.inf_eq_bot_of_commute`, `Subalgebra.LinearDisjoint.inf_eq_bot`: + if `A` and `B` are linearly disjoint, under suitable technical conditions, they are disjoint. + +The results with name containing "of_commute" also have corresponding specialized versions +assuming `S` is commutative. + +## Tags + +linearly disjoint, linearly independent, tensor product + +-/ + +open scoped Classical TensorProduct + +noncomputable section + +universe u v w + +namespace Subalgebra + +variable {R : Type u} {S : Type v} + +section Semiring + +variable [CommSemiring R] [Semiring S] [Algebra R S] + +variable (A B : Subalgebra R S) + +/-- If `A` and `B` are subalgebras of `S / R`, +then `A` and `B` are linearly disjoint, if they are linearly disjoint as submodules of `S`. -/ +protected abbrev LinearDisjoint : Prop := (toSubmodule A).LinearDisjoint (toSubmodule B) + +theorem linearDisjoint_iff : A.LinearDisjoint B ↔ (toSubmodule A).LinearDisjoint (toSubmodule B) := + Iff.rfl + +variable {A B} + +@[nontriviality] +theorem LinearDisjoint.of_subsingleton [Subsingleton R] : A.LinearDisjoint B := + Submodule.LinearDisjoint.of_subsingleton + +/-- Linearly disjoint is symmetric if elements in the module commute. -/ +theorem LinearDisjoint.symm_of_commute (H : A.LinearDisjoint B) + (hc : ∀ (a : A) (b : B), Commute a.1 b.1) : B.LinearDisjoint A := + Submodule.LinearDisjoint.symm_of_commute H hc + +/-- Linearly disjoint is symmetric if elements in the module commute. -/ +theorem linearDisjoint_symm_of_commute + (hc : ∀ (a : A) (b : B), Commute a.1 b.1) : A.LinearDisjoint B ↔ B.LinearDisjoint A := + ⟨fun H ↦ H.symm_of_commute hc, fun H ↦ H.symm_of_commute fun _ _ ↦ (hc _ _).symm⟩ + +namespace LinearDisjoint + +variable (A B) + +/-- The image of `R` in `S` is linearly disjoint with any other subalgebras. -/ +theorem bot_left : (⊥ : Subalgebra R S).LinearDisjoint B := by + rw [Subalgebra.LinearDisjoint, Algebra.toSubmodule_bot] + exact Submodule.LinearDisjoint.one_left _ + +/-- The image of `R` in `S` is linearly disjoint with any other subalgebras. -/ +theorem bot_right : A.LinearDisjoint ⊥ := by + rw [Subalgebra.LinearDisjoint, Algebra.toSubmodule_bot] + exact Submodule.LinearDisjoint.one_right _ + +end LinearDisjoint + +end Semiring + +section CommSemiring + +variable [CommSemiring R] [CommSemiring S] [Algebra R S] + +variable {A B : Subalgebra R S} + +/-- Linearly disjoint is symmetric in a commutative ring. -/ +theorem LinearDisjoint.symm (H : A.LinearDisjoint B) : B.LinearDisjoint A := + H.symm_of_commute fun _ _ ↦ mul_comm _ _ + +/-- Linearly disjoint is symmetric in a commutative ring. -/ +theorem linearDisjoint_symm : A.LinearDisjoint B ↔ B.LinearDisjoint A := + ⟨LinearDisjoint.symm, LinearDisjoint.symm⟩ + +namespace LinearDisjoint + +variable (H : A.LinearDisjoint B) +include H + +/-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are +linearly disjoint, then there is the natural isomorphism +`A ⊗[R] B ≃ₐ[R] A ⊔ B` induced by multiplication in `S`. -/ +protected def mulMap := + (AlgEquiv.ofInjective (A.mulMap B) H.injective).trans (equivOfEq _ _ (mulMap_range A B)) + +@[simp] +theorem val_mulMap_tmul (a : A) (b : B) : (H.mulMap (a ⊗ₜ[R] b) : S) = a.1 * b.1 := rfl + +/-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are +linearly disjoint, and if they are free `R`-modules, then `A ⊔ B` is also a free `R`-module. -/ +theorem sup_free_of_free [Module.Free R A] [Module.Free R B] : Module.Free R ↥(A ⊔ B) := + Module.Free.of_equiv H.mulMap.toLinearEquiv + +end LinearDisjoint + +end CommSemiring + +section Ring + +namespace LinearDisjoint + +variable [CommRing R] [Ring S] [Algebra R S] + +variable (A B : Subalgebra R S) + +set_option maxSynthPendingDepth 2 in +lemma mulLeftMap_ker_eq_bot_iff_linearIndependent_op {ι : Type*} (a : ι → A) : + LinearMap.ker (Submodule.mulLeftMap (M := toSubmodule A) (toSubmodule B) a) = ⊥ ↔ + LinearIndependent B.op (MulOpposite.op ∘ A.val ∘ a) := by + simp_rw [LinearIndependent, LinearMap.ker_eq_bot] + let i : (ι →₀ B) →ₗ[R] S := Submodule.mulLeftMap (M := toSubmodule A) (toSubmodule B) a + let j : (ι →₀ B) →ₗ[R] S := (MulOpposite.opLinearEquiv _).symm.toLinearMap ∘ₗ + (Finsupp.linearCombination B.op (MulOpposite.op ∘ A.val ∘ a)).restrictScalars R ∘ₗ + (Finsupp.mapRange.linearEquiv (linearEquivOp B)).toLinearMap + suffices i = j by + change Function.Injective i ↔ _ + simp_rw [this, j, LinearMap.coe_comp, LinearEquiv.coe_coe, EquivLike.comp_injective, + EquivLike.injective_comp, LinearMap.coe_restrictScalars] + ext + simp only [LinearMap.coe_comp, Function.comp_apply, Finsupp.lsingle_apply, coe_val, + Finsupp.mapRange.linearEquiv_toLinearMap, LinearEquiv.coe_coe, + MulOpposite.coe_opLinearEquiv_symm, LinearMap.coe_restrictScalars, + Finsupp.mapRange.linearMap_apply, Finsupp.mapRange_single, Finsupp.linearCombination_single, + MulOpposite.unop_smul, MulOpposite.unop_op, i, j] + exact Submodule.mulLeftMap_apply_single _ _ _ + +variable {A B} in +/-- If `A` and `B` are linearly disjoint, if `B` is a flat `R`-module, then for any family of +`R`-linearly independent elements of `A`, they are also `B`-linearly independent +in the opposite ring. -/ +theorem linearIndependent_left_op_of_flat (H : A.LinearDisjoint B) [Module.Flat R B] + {ι : Type*} {a : ι → A} (ha : LinearIndependent R a) : + LinearIndependent B.op (MulOpposite.op ∘ A.val ∘ a) := by + have h := Submodule.LinearDisjoint.linearIndependent_left_of_flat H ha + rwa [mulLeftMap_ker_eq_bot_iff_linearIndependent_op] at h + +/-- If a basis of `A` is also `B`-linearly independent in the opposite ring, +then `A` and `B` are linearly disjoint. -/ +theorem of_basis_left_op {ι : Type*} (a : Basis ι R A) + (H : LinearIndependent B.op (MulOpposite.op ∘ A.val ∘ a)) : + A.LinearDisjoint B := by + rw [← mulLeftMap_ker_eq_bot_iff_linearIndependent_op] at H + exact Submodule.LinearDisjoint.of_basis_left _ _ a H + +set_option maxSynthPendingDepth 2 in +lemma mulRightMap_ker_eq_bot_iff_linearIndependent {ι : Type*} (b : ι → B) : + LinearMap.ker (Submodule.mulRightMap (toSubmodule A) (N := toSubmodule B) b) = ⊥ ↔ + LinearIndependent A (B.val ∘ b) := by + simp_rw [LinearIndependent, LinearMap.ker_eq_bot] + let i : (ι →₀ A) →ₗ[R] S := Submodule.mulRightMap (toSubmodule A) (N := toSubmodule B) b + let j : (ι →₀ A) →ₗ[R] S := (Finsupp.linearCombination A (B.val ∘ b)).restrictScalars R + suffices i = j by change Function.Injective i ↔ Function.Injective j; rw [this] + ext + simp only [LinearMap.coe_comp, Function.comp_apply, Finsupp.lsingle_apply, coe_val, + LinearMap.coe_restrictScalars, Finsupp.linearCombination_single, i, j] + exact Submodule.mulRightMap_apply_single _ _ _ + +variable {A B} in +/-- If `A` and `B` are linearly disjoint, if `A` is a flat `R`-module, then for any family of +`R`-linearly independent elements of `B`, they are also `A`-linearly independent. -/ +theorem linearIndependent_right_of_flat (H : A.LinearDisjoint B) [Module.Flat R A] + {ι : Type*} {b : ι → B} (hb : LinearIndependent R b) : + LinearIndependent A (B.val ∘ b) := by + have h := Submodule.LinearDisjoint.linearIndependent_right_of_flat H hb + rwa [mulRightMap_ker_eq_bot_iff_linearIndependent] at h + +/-- If a basis of `B` is also `A`-linearly independent, then `A` and `B` are linearly disjoint. -/ +theorem of_basis_right {ι : Type*} (b : Basis ι R B) + (H : LinearIndependent A (B.val ∘ b)) : A.LinearDisjoint B := by + rw [← mulRightMap_ker_eq_bot_iff_linearIndependent] at H + exact Submodule.LinearDisjoint.of_basis_right _ _ b H + +variable {A B} in +/-- If `A` and `B` are linearly disjoint and their elements commute, if `B` is a flat `R`-module, +then for any family of `R`-linearly independent elements of `A`, +they are also `B`-linearly independent. -/ +theorem linearIndependent_left_of_flat_of_commute (H : A.LinearDisjoint B) [Module.Flat R B] + {ι : Type*} {a : ι → A} (ha : LinearIndependent R a) + (hc : ∀ (a : A) (b : B), Commute a.1 b.1) : LinearIndependent B (A.val ∘ a) := + (H.symm_of_commute hc).linearIndependent_right_of_flat ha + +/-- If a basis of `A` is also `B`-linearly independent, if elements in `A` and `B` commute, +then `A` and `B` are linearly disjoint. -/ +theorem of_basis_left_of_commute {ι : Type*} (a : Basis ι R A) + (H : LinearIndependent B (A.val ∘ a)) (hc : ∀ (a : A) (b : B), Commute a.1 b.1) : + A.LinearDisjoint B := + (of_basis_right B A a H).symm_of_commute fun _ _ ↦ (hc _ _).symm + +variable {A B} in +/-- If `A` and `B` are linearly disjoint, if `A` is flat, then for any family of +`R`-linearly independent elements `{ a_i }` of `A`, and any family of +`R`-linearly independent elements `{ b_j }` of `B`, the family `{ a_i * b_j }` in `S` is +also `R`-linearly independent. -/ +theorem linearIndependent_mul_of_flat_left (H : A.LinearDisjoint B) [Module.Flat R A] + {κ ι : Type*} {a : κ → A} {b : ι → B} (ha : LinearIndependent R a) + (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := + Submodule.LinearDisjoint.linearIndependent_mul_of_flat_left H ha hb + +variable {A B} in +/-- If `A` and `B` are linearly disjoint, if `B` is flat, then for any family of +`R`-linearly independent elements `{ a_i }` of `A`, and any family of +`R`-linearly independent elements `{ b_j }` of `B`, the family `{ a_i * b_j }` in `S` is +also `R`-linearly independent. -/ +theorem linearIndependent_mul_of_flat_right (H : A.LinearDisjoint B) [Module.Flat R B] + {κ ι : Type*} {a : κ → A} {b : ι → B} (ha : LinearIndependent R a) + (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := + Submodule.LinearDisjoint.linearIndependent_mul_of_flat_right H ha hb + +variable {A B} in +/-- If `A` and `B` are linearly disjoint, if one of `A` and `B` is flat, then for any family of +`R`-linearly independent elements `{ a_i }` of `A`, and any family of +`R`-linearly independent elements `{ b_j }` of `B`, the family `{ a_i * b_j }` in `S` is +also `R`-linearly independent. -/ +theorem linearIndependent_mul_of_flat (H : A.LinearDisjoint B) + (hf : Module.Flat R A ∨ Module.Flat R B) + {κ ι : Type*} {a : κ → A} {b : ι → B} (ha : LinearIndependent R a) + (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := + Submodule.LinearDisjoint.linearIndependent_mul_of_flat H hf ha hb + +/-- If `{ a_i }` is an `R`-basis of `A`, if `{ b_j }` is an `R`-basis of `B`, +such that the family `{ a_i * b_j }` in `S` is `R`-linearly independent, +then `A` and `B` are linearly disjoint. -/ +theorem of_basis_mul {κ ι : Type*} (a : Basis κ R A) (b : Basis ι R B) + (H : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1) : A.LinearDisjoint B := + Submodule.LinearDisjoint.of_basis_mul _ _ a b H + +variable {A B} + +section + +variable (H : A.LinearDisjoint B) +include H + +theorem of_le_left_of_flat {A' : Subalgebra R S} + (h : A' ≤ A) [Module.Flat R B] : A'.LinearDisjoint B := + Submodule.LinearDisjoint.of_le_left_of_flat H h + +theorem of_le_right_of_flat {B' : Subalgebra R S} + (h : B' ≤ B) [Module.Flat R A] : A.LinearDisjoint B' := + Submodule.LinearDisjoint.of_le_right_of_flat H h + +theorem of_le_of_flat_right {A' B' : Subalgebra R S} + (ha : A' ≤ A) (hb : B' ≤ B) [Module.Flat R B] [Module.Flat R A'] : + A'.LinearDisjoint B' := (H.of_le_left_of_flat ha).of_le_right_of_flat hb + +theorem of_le_of_flat_left {A' B' : Subalgebra R S} + (ha : A' ≤ A) (hb : B' ≤ B) [Module.Flat R A] [Module.Flat R B'] : + A'.LinearDisjoint B' := (H.of_le_right_of_flat hb).of_le_left_of_flat ha + +theorem rank_inf_eq_one_of_commute_of_flat_of_inj (hf : Module.Flat R A ∨ Module.Flat R B) + (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := by + nontriviality R + refine le_antisymm (Submodule.LinearDisjoint.rank_inf_le_one_of_commute_of_flat H hf hc) ?_ + have : Cardinal.lift.{u} (Module.rank R (⊥ : Subalgebra R S)) = + Cardinal.lift.{v} (Module.rank R R) := + lift_rank_range_of_injective (Algebra.linearMap R S) hinj + rw [Module.rank_self, Cardinal.lift_one, Cardinal.lift_eq_one] at this + rw [← this] + change Module.rank R (toSubmodule (⊥ : Subalgebra R S)) ≤ + Module.rank R (toSubmodule (A ⊓ B)) + exact Submodule.rank_mono (bot_le : (⊥ : Subalgebra R S) ≤ A ⊓ B) + +theorem rank_inf_eq_one_of_commute_of_flat_left_of_inj [Module.Flat R A] + (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := + H.rank_inf_eq_one_of_commute_of_flat_of_inj (Or.inl ‹_›) hc hinj + +theorem rank_inf_eq_one_of_commute_of_flat_right_of_inj [Module.Flat R B] + (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := + H.rank_inf_eq_one_of_commute_of_flat_of_inj (Or.inr ‹_›) hc hinj + +end + +theorem rank_eq_one_of_commute_of_flat_of_self_of_inj (H : A.LinearDisjoint A) [Module.Flat R A] + (hc : ∀ (a b : A), Commute a.1 b.1) + (hinj : Function.Injective (algebraMap R S)) : Module.rank R A = 1 := by + rw [← inf_of_le_left (le_refl A)] at hc ⊢ + exact H.rank_inf_eq_one_of_commute_of_flat_left_of_inj hc hinj + +end LinearDisjoint + +end Ring + +section CommRing + +namespace LinearDisjoint + +variable [CommRing R] [CommRing S] [Algebra R S] + +variable (A B : Subalgebra R S) + +variable {A B} in +/-- In a commutative ring, if `A` and `B` are linearly disjoint, if `B` is a flat `R`-module, +then for any family of `R`-linearly independent elements of `A`, +they are also `B`-linearly independent. -/ +theorem linearIndependent_left_of_flat (H : A.LinearDisjoint B) [Module.Flat R B] + {ι : Type*} {a : ι → A} (ha : LinearIndependent R a) : LinearIndependent B (A.val ∘ a) := + H.linearIndependent_left_of_flat_of_commute ha fun _ _ ↦ mul_comm _ _ + +/-- In a commutative ring, if a basis of `A` is also `B`-linearly independent, +then `A` and `B` are linearly disjoint. -/ +theorem of_basis_left {ι : Type*} (a : Basis ι R A) + (H : LinearIndependent B (A.val ∘ a)) : A.LinearDisjoint B := + of_basis_left_of_commute A B a H fun _ _ ↦ mul_comm _ _ + +variable {A B} + +variable (H : A.LinearDisjoint B) + +include H in +theorem rank_inf_eq_one_of_flat_of_inj (hf : Module.Flat R A ∨ Module.Flat R B) + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := + H.rank_inf_eq_one_of_commute_of_flat_of_inj hf (fun _ _ ↦ mul_comm _ _) hinj + +include H in +theorem rank_inf_eq_one_of_flat_left_of_inj [Module.Flat R A] + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := + H.rank_inf_eq_one_of_commute_of_flat_left_of_inj (fun _ _ ↦ mul_comm _ _) hinj + +include H in +theorem rank_inf_eq_one_of_flat_right_of_inj [Module.Flat R B] + (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := + H.rank_inf_eq_one_of_commute_of_flat_right_of_inj (fun _ _ ↦ mul_comm _ _) hinj + +theorem rank_eq_one_of_flat_of_self_of_inj (H : A.LinearDisjoint A) [Module.Flat R A] + (hinj : Function.Injective (algebraMap R S)) : Module.rank R A = 1 := + H.rank_eq_one_of_commute_of_flat_of_self_of_inj (fun _ _ ↦ mul_comm _ _) hinj + +include H in +/-- In a commutative ring, if subalgebras `A` and `B` are linearly disjoint and they are +free modules, then the rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`. -/ +theorem rank_sup_of_free [Module.Free R A] [Module.Free R B] : + Module.rank R ↥(A ⊔ B) = Module.rank R A * Module.rank R B := by + nontriviality R + rw [← rank_tensorProduct', H.mulMap.toLinearEquiv.rank_eq] + +include H in +/-- In a commutative ring, if subalgebras `A` and `B` are linearly disjoint and they are +free modules, then the rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`. -/ +theorem finrank_sup_of_free [Module.Free R A] [Module.Free R B] : + Module.finrank R ↥(A ⊔ B) = Module.finrank R A * Module.finrank R B := by + simpa only [map_mul] using congr(Cardinal.toNat $(H.rank_sup_of_free)) + +/-- In a commutative ring, if `A` and `B` are subalgebras which are free modules of finite rank, +such that rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`, +then `A` and `B` are linearly disjoint. -/ +theorem of_finrank_sup_of_free [Module.Free R A] [Module.Free R B] + [Module.Finite R A] [Module.Finite R B] + (H : Module.finrank R ↥(A ⊔ B) = Module.finrank R A * Module.finrank R B) : + A.LinearDisjoint B := by + nontriviality R + rw [← Module.finrank_tensorProduct] at H + obtain ⟨j, hj⟩ := exists_linearIndependent_of_le_finrank H.ge + rw [LinearIndependent] at hj + let j' := Finsupp.linearCombination R j ∘ₗ + (LinearEquiv.ofFinrankEq (A ⊗[R] B) _ (by simp)).toLinearMap + replace hj : Function.Injective j' := by simpa [j'] + have hf : Function.Surjective (mulMap' A B).toLinearMap := mulMap'_surjective A B + haveI := Subalgebra.finite_sup A B + rw [linearDisjoint_iff, Submodule.linearDisjoint_iff] + exact Subtype.val_injective.comp (OrzechProperty.injective_of_surjective_of_injective j' _ hj hf) + +include H in +/-- If `A` and `B` are linearly disjoint, if `A` is free and `B` is flat, +then `[B[A] : B] = [A : R]`. See also `Subalgebra.adjoin_rank_le`. -/ +theorem adjoin_rank_eq_rank_left [Module.Free R A] [Module.Flat R B] + [Nontrivial R] [Nontrivial S] : + Module.rank B (Algebra.adjoin B (A : Set S)) = Module.rank R A := by + rw [← rank_toSubmodule, Module.Free.rank_eq_card_chooseBasisIndex R A, + A.adjoin_eq_span_basis B (Module.Free.chooseBasis R A)] + change Module.rank B (Submodule.span B (Set.range (A.val ∘ Module.Free.chooseBasis R A))) = _ + have := H.linearIndependent_left_of_flat (Module.Free.chooseBasis R A).linearIndependent + rw [rank_span this, Cardinal.mk_range_eq _ this.injective] + +include H in +/-- If `A` and `B` are linearly disjoint, if `B` is free and `A` is flat, +then `[A[B] : A] = [B : R]`. See also `Subalgebra.adjoin_rank_le`. -/ +theorem adjoin_rank_eq_rank_right [Module.Free R B] [Module.Flat R A] + [Nontrivial R] [Nontrivial S] : + Module.rank A (Algebra.adjoin A (B : Set S)) = Module.rank R B := + H.symm.adjoin_rank_eq_rank_left + +/-- If the rank of `A` and `B` are coprime, and they satisfy some freeness condition, +then `A` and `B` are linearly disjoint. -/ +theorem of_finrank_coprime_of_free [Module.Free R A] [Module.Free R B] + [Module.Free A (Algebra.adjoin A (B : Set S))] [Module.Free B (Algebra.adjoin B (A : Set S))] + (H : (Module.finrank R A).Coprime (Module.finrank R B)) : A.LinearDisjoint B := by + nontriviality R + by_cases h1 : Module.finrank R A = 0 + · rw [h1, Nat.coprime_zero_left] at H + rw [eq_bot_of_finrank_one H] + exact bot_right _ + by_cases h2 : Module.finrank R B = 0 + · rw [h2, Nat.coprime_zero_right] at H + rw [eq_bot_of_finrank_one H] + exact bot_left _ + haveI := Module.finite_of_finrank_pos (Nat.pos_of_ne_zero h1) + haveI := Module.finite_of_finrank_pos (Nat.pos_of_ne_zero h2) + haveI := finite_sup A B + have : Module.finrank R A ≤ Module.finrank R ↥(A ⊔ B) := + LinearMap.finrank_le_finrank_of_injective <| + Submodule.inclusion_injective (show toSubmodule A ≤ toSubmodule (A ⊔ B) by simp) + exact of_finrank_sup_of_free <| (finrank_sup_le_of_free A B).antisymm <| + Nat.le_of_dvd (lt_of_lt_of_le (Nat.pos_of_ne_zero h1) this) <| H.mul_dvd_of_dvd_of_dvd + (finrank_left_dvd_finrank_sup_of_free A B) (finrank_right_dvd_finrank_sup_of_free A B) + +variable (A B) + +/-- If `A/R` is integral, such that `A'` and `B` are linearly disjoint for all subalgebras `A'` +of `A` which are finitely generated `R`-modules, then `A` and `B` are linearly disjoint. -/ +theorem of_linearDisjoint_finite_left [Algebra.IsIntegral R A] + (H : ∀ A' : Subalgebra R S, A' ≤ A → [Module.Finite R A'] → A'.LinearDisjoint B) : + A.LinearDisjoint B := by + rw [linearDisjoint_iff, Submodule.linearDisjoint_iff] + intro x y hxy + obtain ⟨M', hM, hf, h⟩ := + TensorProduct.exists_finite_submodule_left_of_finite' {x, y} (Set.toFinite _) + obtain ⟨s, hs⟩ := Module.Finite.iff_fg.1 hf + have hs' : (s : Set S) ⊆ A := by rwa [← hs, Submodule.span_le] at hM + let A' := Algebra.adjoin R (s : Set S) + have hf' : Submodule.FG (toSubmodule A') := fg_adjoin_of_finite s.finite_toSet fun x hx ↦ + (isIntegral_algHom_iff A.val Subtype.val_injective).2 + (Algebra.IsIntegral.isIntegral (R := R) (A := A) ⟨x, hs' hx⟩) + replace hf' : Module.Finite R A' := Module.Finite.iff_fg.2 hf' + have hA : toSubmodule A' ≤ toSubmodule A := Algebra.adjoin_le_iff.2 hs' + replace h : {x, y} ⊆ (LinearMap.range (LinearMap.rTensor (toSubmodule B) + (Submodule.inclusion hA)) : Set _) := fun _ hx ↦ by + have : Submodule.inclusion hM = Submodule.inclusion hA ∘ₗ Submodule.inclusion + (show M' ≤ toSubmodule A' by + rw [← hs, Submodule.span_le]; exact Algebra.adjoin_le_iff.1 (le_refl _)) := rfl + rw [this, LinearMap.rTensor_comp] at h + exact LinearMap.range_comp_le_range _ _ (h hx) + obtain ⟨x', hx'⟩ := h (show x ∈ {x, y} by simp) + obtain ⟨y', hy'⟩ := h (show y ∈ {x, y} by simp) + rw [← hx', ← hy']; congr + exact (H A' hA).injective (by simp [← Submodule.mulMap_comp_rTensor _ hA, hx', hy', hxy]) + +/-- If `B/R` is integral, such that `A` and `B'` are linearly disjoint for all subalgebras `B'` +of `B` which are finitely generated `R`-modules, then `A` and `B` are linearly disjoint. -/ +theorem of_linearDisjoint_finite_right [Algebra.IsIntegral R B] + (H : ∀ B' : Subalgebra R S, B' ≤ B → [Module.Finite R B'] → A.LinearDisjoint B') : + A.LinearDisjoint B := + (of_linearDisjoint_finite_left B A fun B' hB' _ ↦ (H B' hB').symm).symm + +variable {A B} + +/-- If `A/R` and `B/R` are integral, such that any finite subalgebras in `A` and `B` are +linearly disjoint, then `A` and `B` are linearly disjoint. -/ +theorem of_linearDisjoint_finite + [Algebra.IsIntegral R A] [Algebra.IsIntegral R B] + (H : ∀ (A' B' : Subalgebra R S), A' ≤ A → B' ≤ B → + [Module.Finite R A'] → [Module.Finite R B'] → A'.LinearDisjoint B') : + A.LinearDisjoint B := + of_linearDisjoint_finite_left A B fun _ hA' _ ↦ + of_linearDisjoint_finite_right _ B fun _ hB' _ ↦ H _ _ hA' hB' + +end LinearDisjoint + +end CommRing + +section FieldAndRing + +namespace LinearDisjoint + +variable [Field R] [Ring S] [Algebra R S] + +variable {A B : Subalgebra R S} + +theorem inf_eq_bot_of_commute (H : A.LinearDisjoint B) + (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) : A ⊓ B = ⊥ := + eq_bot_of_rank_le_one (Submodule.LinearDisjoint.rank_inf_le_one_of_commute_of_flat_left H hc) + +theorem eq_bot_of_commute_of_self (H : A.LinearDisjoint A) + (hc : ∀ (a b : A), Commute a.1 b.1) : A = ⊥ := by + rw [← inf_of_le_left (le_refl A)] at hc ⊢ + exact H.inf_eq_bot_of_commute hc + +end LinearDisjoint + +end FieldAndRing + +section FieldAndCommRing + +namespace LinearDisjoint + +variable [Field R] [CommRing S] [Algebra R S] + +variable {A B : Subalgebra R S} + +theorem inf_eq_bot (H : A.LinearDisjoint B) : A ⊓ B = ⊥ := + H.inf_eq_bot_of_commute fun _ _ ↦ mul_comm _ _ + +theorem eq_bot_of_self (H : A.LinearDisjoint A) : A = ⊥ := + H.eq_bot_of_commute_of_self fun _ _ ↦ mul_comm _ _ + +end LinearDisjoint + +end FieldAndCommRing + +end Subalgebra diff --git a/Mathlib/RingTheory/LocalProperties/Basic.lean b/Mathlib/RingTheory/LocalProperties/Basic.lean index a3ece3c9a9726..1bc5294a8e5f1 100644 --- a/Mathlib/RingTheory/LocalProperties/Basic.lean +++ b/Mathlib/RingTheory/LocalProperties/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.RingTheory.Localization.AtPrime +import Mathlib.RingTheory.Localization.BaseChange import Mathlib.RingTheory.Localization.Submodule import Mathlib.RingTheory.RingHomProperties @@ -43,8 +44,8 @@ open scoped Pointwise Classical universe u -variable {R S : Type u} [CommRing R] [CommRing S] (M : Submonoid R) (f : R →+* S) -variable (N : Submonoid S) (R' S' : Type u) [CommRing R'] [CommRing S'] +variable {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) +variable (R' S' : Type u) [CommRing R'] [CommRing S'] variable [Algebra R R'] [Algebra S S'] section Properties @@ -201,19 +202,23 @@ lemma RingHom.HoldsForLocalizationAway.containsIdentities (hPl : HoldsForLocaliz introv R exact hPl.of_bijective _ _ Function.bijective_id -theorem RingHom.PropertyIsLocal.respectsIso (hP : RingHom.PropertyIsLocal @P) : - RingHom.RespectsIso @P := by - constructor - · intro R S T _ _ _ f e hf +lemma RingHom.StableUnderCompositionWithLocalizationAway.respectsIso + (hP : StableUnderCompositionWithLocalizationAway P) : + RespectsIso P where + left {R S T} _ _ _ f e hf := by letI := e.toRingHom.toAlgebra have : IsLocalization.Away (1 : S) T := IsLocalization.away_of_isUnit_of_bijective _ isUnit_one e.bijective - exact hP.StableUnderCompositionWithLocalizationAway.left T (1 : S) f hf - · intro R S T _ _ _ f e hf + exact hP.left T (1 : S) f hf + right {R S T} _ _ _ f e hf := by letI := e.toRingHom.toAlgebra have : IsLocalization.Away (1 : R) S := IsLocalization.away_of_isUnit_of_bijective _ isUnit_one e.bijective - exact hP.StableUnderCompositionWithLocalizationAway.right S (1 : R) f hf + exact hP.right S (1 : R) f hf + +theorem RingHom.PropertyIsLocal.respectsIso (hP : RingHom.PropertyIsLocal @P) : + RingHom.RespectsIso @P := + hP.StableUnderCompositionWithLocalizationAway.respectsIso -- Almost all arguments are implicit since this is not intended to use mid-proof. theorem RingHom.LocalizationPreserves.away (H : RingHom.LocalizationPreserves @P) (r : R) @@ -257,6 +262,43 @@ lemma RingHom.OfLocalizationSpanTarget.ofIsLocalization AlgEquiv.toRingEquiv_toRingHom, Localization.coe_algEquiv_symm, IsLocalization.map_comp, RingHom.comp_id] +section + +variable (hP : RingHom.StableUnderBaseChange @P) +variable {R S Rᵣ Sᵣ : Type u} [CommRing R] [CommRing S] [CommRing Rᵣ] [CommRing Sᵣ] [Algebra R Rᵣ] + [Algebra S Sᵣ] + +include hP + +/-- Let `S` be an `R`-algebra and `Sᵣ` and `Rᵣ` be the respective localizations at a submonoid +`M` of `R`. If `P` is stable under base change and `P` holds for `algebraMap R S`, then +`P` holds for `algebraMap Rᵣ Sᵣ`. -/ +lemma RingHom.StableUnderBaseChange.of_isLocalization [Algebra R S] [Algebra R Sᵣ] [Algebra Rᵣ Sᵣ] + [IsScalarTower R S Sᵣ] [IsScalarTower R Rᵣ Sᵣ] + (M : Submonoid R) [IsLocalization M Rᵣ] [IsLocalization (Algebra.algebraMapSubmonoid S M) Sᵣ] + (h : P (algebraMap R S)) : P (algebraMap Rᵣ Sᵣ) := + letI : Algebra.IsPushout R S Rᵣ Sᵣ := Algebra.isPushout_of_isLocalization M Rᵣ S Sᵣ + hP R S Rᵣ Sᵣ h + +/-- If `P` is stable under base change and holds for `f`, then `P` holds for `f` localized +at any submonoid `M` of `R`. -/ +lemma RingHom.StableUnderBaseChange.isLocalization_map (M : Submonoid R) [IsLocalization M Rᵣ] + (f : R →+* S) [IsLocalization (M.map f) Sᵣ] (hf : P f) : + P (IsLocalization.map Sᵣ f M.le_comap_map : Rᵣ →+* Sᵣ) := by + algebraize [f, IsLocalization.map (S := Rᵣ) Sᵣ f M.le_comap_map, + (IsLocalization.map (S := Rᵣ) Sᵣ f M.le_comap_map).comp (algebraMap R Rᵣ)] + haveI : IsScalarTower R S Sᵣ := IsScalarTower.of_algebraMap_eq' + (IsLocalization.map_comp M.le_comap_map) + haveI : IsLocalization (Algebra.algebraMapSubmonoid S M) Sᵣ := + inferInstanceAs <| IsLocalization (M.map f) Sᵣ + apply hP.of_isLocalization M hf + +lemma RingHom.StableUnderBaseChange.localizationPreserves : LocalizationPreserves P := by + introv R hf + exact hP.isLocalization_map _ _ hf + +end + end RingHom end Properties @@ -268,7 +310,7 @@ open scoped nonZeroDivisors /-- Let `I J : Ideal R`. If the localization of `I` at each maximal ideal `P` is included in the localization of `J` at `P`, then `I ≤ J`. -/ theorem Ideal.le_of_localization_maximal {I J : Ideal R} - (h : ∀ (P : Ideal R) (hP : P.IsMaximal), + (h : ∀ (P : Ideal R) (_ : P.IsMaximal), Ideal.map (algebraMap R (Localization.AtPrime P)) I ≤ Ideal.map (algebraMap R (Localization.AtPrime P)) J) : I ≤ J := by @@ -300,7 +342,7 @@ theorem Ideal.eq_of_localization_maximal {I J : Ideal R} /-- An ideal is trivial if its localization at every maximal ideal is trivial. -/ theorem ideal_eq_bot_of_localization' (I : Ideal R) - (h : ∀ (J : Ideal R) (hJ : J.IsMaximal), + (h : ∀ (J : Ideal R) (_ : J.IsMaximal), Ideal.map (algebraMap R (Localization.AtPrime J)) I = ⊥) : I = ⊥ := Ideal.eq_of_localization_maximal fun P hP => by simpa using h P hP @@ -309,7 +351,7 @@ theorem ideal_eq_bot_of_localization' (I : Ideal R) -- localized modules. /-- An ideal is trivial if its localization at every maximal ideal is trivial. -/ theorem ideal_eq_bot_of_localization (I : Ideal R) - (h : ∀ (J : Ideal R) (hJ : J.IsMaximal), + (h : ∀ (J : Ideal R) (_ : J.IsMaximal), IsLocalization.coeSubmodule (Localization.AtPrime J) I = ⊥) : I = ⊥ := ideal_eq_bot_of_localization' _ fun P hP => @@ -318,7 +360,7 @@ theorem ideal_eq_bot_of_localization (I : Ideal R) exact ⟨x, hx, rfl⟩ theorem eq_zero_of_localization (r : R) - (h : ∀ (J : Ideal R) (hJ : J.IsMaximal), algebraMap R (Localization.AtPrime J) r = 0) : + (h : ∀ (J : Ideal R) (_ : J.IsMaximal), algebraMap R (Localization.AtPrime J) r = 0) : r = 0 := by rw [← Ideal.span_singleton_eq_bot] apply ideal_eq_bot_of_localization diff --git a/Mathlib/RingTheory/LocalProperties/Reduced.lean b/Mathlib/RingTheory/LocalProperties/Reduced.lean index 65df178848887..5a7cb0ef69937 100644 --- a/Mathlib/RingTheory/LocalProperties/Reduced.lean +++ b/Mathlib/RingTheory/LocalProperties/Reduced.lean @@ -20,7 +20,7 @@ Let `R` be a commutative ring, `M` be a submonoid of `R`. -/ /-- `M⁻¹R` is reduced if `R` is reduced. -/ -theorem isReduced_localizationPreserves : LocalizationPreserves fun R hR => IsReduced R := by +theorem isReduced_localizationPreserves : LocalizationPreserves fun R _ => IsReduced R := by introv R _ _ constructor rintro x ⟨_ | n, e⟩ @@ -43,7 +43,7 @@ instance {R : Type*} [CommRing R] (M : Submonoid R) [IsReduced R] : IsReduced (L isReduced_localizationPreserves M _ inferInstance /-- `R` is reduced if `Rₘ` is reduced for all maximal ideal `m`. -/ -theorem isReduced_ofLocalizationMaximal : OfLocalizationMaximal fun R hR => IsReduced R := by +theorem isReduced_ofLocalizationMaximal : OfLocalizationMaximal fun R _ => IsReduced R := by introv R h constructor intro x hx diff --git a/Mathlib/RingTheory/LocalRing/Defs.lean b/Mathlib/RingTheory/LocalRing/Defs.lean index c74c7f0f9a930..511c0f31a6438 100644 --- a/Mathlib/RingTheory/LocalRing/Defs.lean +++ b/Mathlib/RingTheory/LocalRing/Defs.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.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Defs import Mathlib.Algebra.Ring.Defs /-! diff --git a/Mathlib/RingTheory/LocalRing/Module.lean b/Mathlib/RingTheory/LocalRing/Module.lean index 332bccee7c8f5..d446db6698308 100644 --- a/Mathlib/RingTheory/LocalRing/Module.lean +++ b/Mathlib/RingTheory/LocalRing/Module.lean @@ -28,7 +28,7 @@ This file gathers various results about finite modules over a local ring `(R, `l` is a split injection if and only if `k ⊗ l` is a (split) injection. -/ -variable {R S} [CommRing R] [CommRing S] [Algebra R S] +variable {R} [CommRing R] section diff --git a/Mathlib/RingTheory/LocalRing/Quotient.lean b/Mathlib/RingTheory/LocalRing/Quotient.lean new file mode 100644 index 0000000000000..98bf4b58c3ace --- /dev/null +++ b/Mathlib/RingTheory/LocalRing/Quotient.lean @@ -0,0 +1,105 @@ +/- +Copyright (c) 2024 Riccardo Brasca. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang, Riccardo Brasca +-/ + +import Mathlib.LinearAlgebra.Dimension.DivisionRing +import Mathlib.LinearAlgebra.FreeModule.PID +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition +import Mathlib.RingTheory.Ideal.Over +import Mathlib.RingTheory.Nakayama +import Mathlib.RingTheory.Valuation.ValuationRing + +/-! + +We gather results about the quotients of local rings. + +-/ + +open Submodule FiniteDimensional Module + +variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] [LocalRing R] [Module.Finite R S] + +namespace LocalRing + +local notation "p" => maximalIdeal R +local notation "pS" => Ideal.map (algebraMap R S) p + +theorem quotient_span_eq_top_iff_span_eq_top (s : Set S) : + span (R ⧸ p) ((Ideal.Quotient.mk (I := pS)) '' s) = ⊤ ↔ span R s = ⊤ := by + have H : (span (R ⧸ p) ((Ideal.Quotient.mk (I := pS)) '' s)).restrictScalars R = + (span R s).map (IsScalarTower.toAlgHom R S (S ⧸ pS)) := by + rw [map_span, ← restrictScalars_span R (R ⧸ p) Ideal.Quotient.mk_surjective, + IsScalarTower.coe_toAlgHom', Ideal.Quotient.algebraMap_eq] + constructor + · intro hs + rw [← top_le_iff] + apply le_of_le_smul_of_le_jacobson_bot + · exact Module.finite_def.mp ‹_› + · exact (jacobson_eq_maximalIdeal ⊥ bot_ne_top).ge + · rw [Ideal.smul_top_eq_map] + rintro x - + have : LinearMap.ker (IsScalarTower.toAlgHom R S (S ⧸ pS)) = + restrictScalars R pS := by + ext; simp [Ideal.Quotient.eq_zero_iff_mem] + rw [← this, ← comap_map_eq, mem_comap, ← H, hs, restrictScalars_top] + exact mem_top + · intro hs + rwa [hs, Submodule.map_top, LinearMap.range_eq_top.mpr, restrictScalars_eq_top_iff] at H + rw [IsScalarTower.coe_toAlgHom', Ideal.Quotient.algebraMap_eq] + exact Ideal.Quotient.mk_surjective + +attribute [local instance] Ideal.Quotient.field + +variable [Module.Free R S] {ι : Type*} + +theorem finrank_quotient_map : + finrank (R ⧸ p) (S ⧸ pS) = finrank R S := by + classical + have : Module.Finite R (S ⧸ pS) := Module.Finite.of_surjective + (IsScalarTower.toAlgHom R S (S ⧸ pS)).toLinearMap (Ideal.Quotient.mk_surjective (I := pS)) + have : Module.Finite (R ⧸ p) (S ⧸ pS) := Module.Finite.of_restrictScalars_finite R _ _ + apply le_antisymm + · let b := Module.Free.chooseBasis R S + conv_rhs => rw [finrank_eq_card_chooseBasisIndex] + apply finrank_le_of_span_eq_top + rw [Set.range_comp] + apply (quotient_span_eq_top_iff_span_eq_top _).mpr b.span_eq + · let b := Module.Free.chooseBasis (R ⧸ p) (S ⧸ pS) + choose b' hb' using fun i ↦ Ideal.Quotient.mk_surjective (b i) + conv_rhs => rw [finrank_eq_card_chooseBasisIndex] + refine finrank_le_of_span_eq_top (v := b') ?_ + apply (quotient_span_eq_top_iff_span_eq_top _).mp + rw [← Set.range_comp, show Ideal.Quotient.mk pS ∘ b' = ⇑b from funext hb'] + exact b.span_eq + +/-- Given a basis of `S`, the induced basis of `S / Ideal.map (algebraMap R S) p`. -/ +noncomputable +def basisQuotient [Fintype ι] (b : Basis ι R S) : Basis ι (R ⧸ p) (S ⧸ pS) := + basisOfTopLeSpanOfCardEqFinrank (Ideal.Quotient.mk pS ∘ b) + (by + rw [Set.range_comp] + exact ((quotient_span_eq_top_iff_span_eq_top _).mpr b.span_eq).ge) + (by rw [finrank_quotient_map, finrank_eq_card_basis b]) + +lemma basisQuotient_apply [Fintype ι] (b : Basis ι R S) (i) : + (basisQuotient b) i = Ideal.Quotient.mk pS (b i) := by + delta basisQuotient + rw [coe_basisOfTopLeSpanOfCardEqFinrank, Function.comp_apply] + +lemma basisQuotient_repr {ι} [Fintype ι] (b : Basis ι R S) (x) (i) : + (basisQuotient b).repr (Ideal.Quotient.mk pS x) i = + Ideal.Quotient.mk p (b.repr x i) := by + refine congr_fun (g := Ideal.Quotient.mk p ∘ b.repr x) ?_ i + apply (Finsupp.linearEquivFunOnFinite (R ⧸ p) _ _).symm.injective + apply (basisQuotient b).repr.symm.injective + simp only [Finsupp.linearEquivFunOnFinite_symm_coe, LinearEquiv.symm_apply_apply, + Basis.repr_symm_apply] + rw [Finsupp.linearCombination_eq_fintype_linearCombination_apply _ (R ⧸ p), + Fintype.linearCombination_apply] + simp only [Function.comp_apply, basisQuotient_apply, + Ideal.Quotient.mk_smul_mk_quotient_map_quotient, ← Algebra.smul_def] + rw [← map_sum, Basis.sum_repr b x] + +end LocalRing diff --git a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean index 885d727ff53f4..5dc19df864940 100644 --- a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean @@ -41,7 +41,7 @@ instance ResidueField.algebra : Algebra R (ResidueField R) := theorem ResidueField.algebraMap_eq : algebraMap R (ResidueField R) = residue R := rfl -instance : IsLocalRingHom (LocalRing.residue R) := +instance : IsLocalHom (LocalRing.residue R) := ⟨fun _ ha => Classical.not_not.mp (Ideal.Quotient.eq_zero_iff_mem.not.mp (isUnit_iff_ne_zero.mp ha))⟩ @@ -50,22 +50,22 @@ variable {R} namespace ResidueField /-- A local ring homomorphism into a field can be descended onto the residue field. -/ -def lift {R S : Type*} [CommRing R] [LocalRing R] [Field S] (f : R →+* S) [IsLocalRingHom f] : +def lift {R S : Type*} [CommRing R] [LocalRing R] [Field S] (f : R →+* S) [IsLocalHom f] : LocalRing.ResidueField R →+* S := Ideal.Quotient.lift _ f fun a ha => by_contradiction fun h => ha (isUnit_of_map_unit f a (isUnit_iff_ne_zero.mpr h)) theorem lift_comp_residue {R S : Type*} [CommRing R] [LocalRing R] [Field S] (f : R →+* S) - [IsLocalRingHom f] : (lift f).comp (residue R) = f := + [IsLocalHom f] : (lift f).comp (residue R) = f := RingHom.ext fun _ => rfl @[simp] theorem lift_residue_apply {R S : Type*} [CommRing R] [LocalRing R] [Field S] (f : R →+* S) - [IsLocalRingHom f] (x) : lift f (residue R x) = f x := + [IsLocalHom f] (x) : lift f (residue R x) = f x := rfl /-- The map on residue fields induced by a local homomorphism between local rings -/ -def map (f : R →+* S) [IsLocalRingHom f] : ResidueField R →+* ResidueField S := +def map (f : R →+* S) [IsLocalHom f] : ResidueField R →+* ResidueField S := Ideal.Quotient.lift (maximalIdeal R) ((Ideal.Quotient.mk _).comp f) fun a ha => by erw [Ideal.Quotient.eq_zero_iff_mem] exact map_nonunit f a ha @@ -79,16 +79,16 @@ theorem map_id : /-- The composite of two `LocalRing.ResidueField.map`s is the `LocalRing.ResidueField.map` of the composite. -/ -theorem map_comp (f : T →+* R) (g : R →+* S) [IsLocalRingHom f] [IsLocalRingHom g] : +theorem map_comp (f : T →+* R) (g : R →+* S) [IsLocalHom f] [IsLocalHom g] : LocalRing.ResidueField.map (g.comp f) = (LocalRing.ResidueField.map g).comp (LocalRing.ResidueField.map f) := Ideal.Quotient.ringHom_ext <| RingHom.ext fun _ => rfl -theorem map_comp_residue (f : R →+* S) [IsLocalRingHom f] : +theorem map_comp_residue (f : R →+* S) [IsLocalHom f] : (ResidueField.map f).comp (residue R) = (residue S).comp f := rfl -theorem map_residue (f : R →+* S) [IsLocalRingHom f] (r : R) : +theorem map_residue (f : R →+* S) [IsLocalHom f] (r : R) : ResidueField.map f (residue R r) = residue S (f r) := rfl @@ -96,8 +96,8 @@ theorem map_id_apply (x : ResidueField R) : map (RingHom.id R) x = x := DFunLike.congr_fun map_id x @[simp] -theorem map_map (f : R →+* S) (g : S →+* T) (x : ResidueField R) [IsLocalRingHom f] - [IsLocalRingHom g] : map g (map f x) = map (g.comp f) x := +theorem map_map (f : R →+* S) (g : S →+* T) (x : ResidueField R) [IsLocalHom f] + [IsLocalHom g] : map g (map f x) = map (g.comp f) x := DFunLike.congr_fun (map_comp f g).symm x /-- A ring isomorphism defines an isomorphism of residue fields. -/ @@ -147,7 +147,7 @@ end MulSemiringAction section FiniteDimensional -variable [Algebra R S] [IsLocalRingHom (algebraMap R S)] +variable [Algebra R S] [IsLocalHom (algebraMap R S)] noncomputable instance : Algebra (ResidueField R) (ResidueField S) := (ResidueField.map (algebraMap R S)).toAlgebra @@ -166,22 +166,25 @@ instance finiteDimensional_of_noetherian [IsNoetherian R S] : (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 lemma finite_of_finite [IsNoetherian R S] (hfin : Finite (ResidueField R)) : - Finite (ResidueField S) := by - have := @finiteDimensional_of_noetherian R S - exact FiniteDimensional.finite_of_finite (ResidueField R) (ResidueField S) + Finite (ResidueField S) := Module.finite_of_finite (ResidueField R) end FiniteDimensional end ResidueField -theorem isLocalRingHom_residue : IsLocalRingHom (LocalRing.residue R) := by +theorem isLocalHom_residue : IsLocalHom (LocalRing.residue R) := by constructor intro a ha by_contra h erw [Ideal.Quotient.eq_zero_iff_mem.mpr ((LocalRing.mem_maximalIdeal _).mpr h)] at ha exact ha.ne_zero rfl +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_residue := isLocalHom_residue + end end LocalRing diff --git a/Mathlib/RingTheory/LocalRing/ResidueField/Defs.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Defs.lean index 77da457b5bff8..0d585ff2970c0 100644 --- a/Mathlib/RingTheory/LocalRing/ResidueField/Defs.lean +++ b/Mathlib/RingTheory/LocalRing/ResidueField/Defs.lean @@ -3,8 +3,8 @@ 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.Ideal.Quotient.Basic import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic -import Mathlib.RingTheory.Ideal.Quotient /-! diff --git a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean index 7dd4c8dade367..f14d328b4582a 100644 --- a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/RingHom/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.LocalRing.RingHom.Defs +import Mathlib.Algebra.Group.Units.Hom import Mathlib.RingTheory.LocalRing.MaximalIdeal.Defs import Mathlib.RingTheory.Ideal.Maps import Mathlib.Logic.Equiv.TransferInstance @@ -21,45 +21,40 @@ section variable [Semiring R] [Semiring S] [Semiring T] -instance isLocalRingHom_id (R : Type*) [Semiring R] : IsLocalRingHom (RingHom.id R) where +@[instance] +theorem isLocalHom_id (R : Type*) [Semiring R] : IsLocalHom (RingHom.id R) where map_nonunit _ := id -@[simp] -theorem isUnit_map_iff (f : R →+* S) [IsLocalRingHom f] (a) : IsUnit (f a) ↔ IsUnit a := - ⟨IsLocalRingHom.map_nonunit a, f.isUnit_map⟩ - --- Porting note: as this can be proved by other `simp` lemmas, this is marked as high priority. -@[simp (high)] -theorem map_mem_nonunits_iff (f : R →+* S) [IsLocalRingHom f] (a) : - f a ∈ nonunits S ↔ a ∈ nonunits R := - ⟨fun h ha => h <| (isUnit_map_iff f a).mpr ha, fun h ha => h <| (isUnit_map_iff f a).mp ha⟩ - -instance isLocalRingHom_comp (g : S →+* T) (f : R →+* S) [IsLocalRingHom g] [IsLocalRingHom f] : - IsLocalRingHom (g.comp f) where - map_nonunit a := IsLocalRingHom.map_nonunit a ∘ IsLocalRingHom.map_nonunit (f a) - -instance isLocalRingHom_equiv (f : R ≃+* S) : IsLocalRingHom (f : R →+* S) where - map_nonunit a ha := by - convert RingHom.isUnit_map (f.symm : S →+* R) ha - exact (RingEquiv.symm_apply_apply f a).symm - -@[simp] -theorem isUnit_of_map_unit (f : R →+* S) [IsLocalRingHom f] (a) (h : IsUnit (f a)) : IsUnit a := - IsLocalRingHom.map_nonunit a h - -theorem of_irreducible_map (f : R →+* S) [h : IsLocalRingHom f] {x} (hfx : Irreducible (f x)) : - Irreducible x := - ⟨fun h => hfx.not_unit <| IsUnit.map f h, fun p q hx => - let ⟨H⟩ := h - Or.imp (H p) (H q) <| hfx.isUnit_or_isUnit <| f.map_mul p q ▸ congr_arg f hx⟩ - -theorem isLocalRingHom_of_comp (f : R →+* S) (g : S →+* T) [IsLocalRingHom (g.comp f)] : - IsLocalRingHom f := +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_id := isLocalHom_id + +-- see note [lower instance priority] +@[instance 100] +theorem isLocalHom_toRingHom {F : Type*} [FunLike F R S] + [RingHomClass F R S] (f : F) [IsLocalHom f] : IsLocalHom (f : R →+* S) := + ⟨IsLocalHom.map_nonunit (f := f)⟩ + +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_toRingHom := isLocalHom_toRingHom + +@[instance] +theorem RingHom.isLocalHom_comp (g : S →+* T) (f : R →+* S) [IsLocalHom g] + [IsLocalHom f] : IsLocalHom (g.comp f) where + map_nonunit a := IsLocalHom.map_nonunit a ∘ IsLocalHom.map_nonunit (f := g) (f a) + +@[deprecated (since := "2024-10-10")] +alias RingHom.isLocalRingHom_comp := RingHom.isLocalHom_comp + +theorem isLocalHom_of_comp (f : R →+* S) (g : S →+* T) [IsLocalHom (g.comp f)] : + IsLocalHom f := ⟨fun _ ha => (isUnit_map_iff (g.comp f) _).mp (g.isUnit_map ha)⟩ +@[deprecated (since := "2024-10-10")] +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_localRing {R S : Type*} [CommSemiring R] [CommSemiring S] [H : LocalRing S] - (f : R →+* S) [IsLocalRingHom f] : LocalRing R := by + (f : R →+* S) [IsLocalHom f] : LocalRing R := by haveI : Nontrivial R := pullback_nonzero f f.map_zero f.map_one apply LocalRing.of_nonunits_add intro a b @@ -77,7 +72,7 @@ variable [CommSemiring R] [LocalRing R] [CommSemiring S] [LocalRing S] /-- The image of the maximal ideal of the source is contained within the maximal ideal of the target. -/ -theorem map_nonunit (f : R →+* S) [IsLocalRingHom f] (a : R) (h : a ∈ maximalIdeal R) : +theorem map_nonunit (f : R →+* S) [IsLocalHom f] (a : R) (h : a ∈ maximalIdeal R) : f a ∈ maximalIdeal S := fun H => h <| isUnit_of_map_unit f a H end @@ -93,7 +88,7 @@ i.e. any preimage of a unit is still a unit. https://stacks.math.columbia.edu/ta -/ theorem local_hom_TFAE (f : R →+* S) : List.TFAE - [IsLocalRingHom f, f '' (maximalIdeal R).1 ⊆ maximalIdeal S, + [IsLocalHom f, f '' (maximalIdeal R).1 ⊆ maximalIdeal S, (maximalIdeal R).map f ≤ maximalIdeal S, maximalIdeal R ≤ (maximalIdeal S).comap f, (maximalIdeal S).comap f = maximalIdeal R] := by tfae_have 1 → 2 @@ -109,19 +104,19 @@ theorem local_hom_TFAE (f : R →+* S) : end theorem of_surjective [CommSemiring R] [LocalRing R] [CommSemiring S] [Nontrivial S] (f : R →+* S) - [IsLocalRingHom f] (hf : Function.Surjective f) : LocalRing S := + [IsLocalHom f] (hf : Function.Surjective f) : LocalRing S := of_isUnit_or_isUnit_of_isUnit_add (by intro a b hab obtain ⟨a, rfl⟩ := hf a obtain ⟨b, rfl⟩ := hf b rw [← map_add] at hab exact - (isUnit_or_isUnit_of_isUnit_add <| IsLocalRingHom.map_nonunit _ hab).imp f.isUnit_map + (isUnit_or_isUnit_of_isUnit_add <| IsLocalHom.map_nonunit _ hab).imp f.isUnit_map f.isUnit_map) /-- If `f : R →+* S` is a surjective local ring hom, then the induced units map is surjective. -/ theorem surjective_units_map_of_local_ringHom [CommRing R] [CommRing S] (f : R →+* S) - (hf : Function.Surjective f) (h : IsLocalRingHom f) : + (hf : Function.Surjective f) (h : IsLocalHom f) : Function.Surjective (Units.map <| f.toMonoidHom) := by intro a obtain ⟨b, hb⟩ := hf (a : S) @@ -133,7 +128,7 @@ theorem surjective_units_map_of_local_ringHom [CommRing R] [CommRing S] (f : R /-- Every ring hom `f : K →+* R` from a division ring `K` to a nontrivial ring `R` is a local ring hom. -/ instance (priority := 100) {K R} [DivisionRing K] [CommRing R] [Nontrivial R] - (f : K →+* R) : IsLocalRingHom f where + (f : K →+* R) : IsLocalHom f where map_nonunit r hr := by simpa only [isUnit_iff_ne_zero, ne_eq, map_eq_zero] using hr.ne_zero end LocalRing diff --git a/Mathlib/RingTheory/LocalRing/RingHom/Defs.lean b/Mathlib/RingTheory/LocalRing/RingHom/Defs.lean deleted file mode 100644 index 5949c6dcab0ff..0000000000000 --- a/Mathlib/RingTheory/LocalRing/RingHom/Defs.lean +++ /dev/null @@ -1,28 +0,0 @@ -/- -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.Group.Units -import Mathlib.Algebra.Ring.Hom.Defs - -/-! - -# Local rings homomorphisms - -We Define local ring homomorhpisms. - -## Main definitions - -* `IsLocalRingHom`: A predicate on semiring homomorphisms, requiring that it maps nonunits - to nonunits. For local rings, this means that the image of the unique maximal ideal is again - contained in the unique maximal ideal. - --/ - -/-- A local ring homomorphism is a homomorphism `f` between local rings such that `a` in the domain - is a unit if `f a` is a unit for any `a`. See `LocalRing.local_hom_TFAE` for other equivalent - definitions. -/ -class IsLocalRingHom {R S : Type*} [Semiring R] [Semiring S] (f : R →+* S) : Prop where - /-- A local ring homomorphism `f : R ⟶ S` will send nonunits of `R` to nonunits of `S`. -/ - map_nonunit : ∀ a, IsUnit (f a) → IsUnit a diff --git a/Mathlib/RingTheory/Localization/AtPrime.lean b/Mathlib/RingTheory/Localization/AtPrime.lean index a52c0df699d51..90a63bac86990 100644 --- a/Mathlib/RingTheory/Localization/AtPrime.lean +++ b/Mathlib/RingTheory/Localization/AtPrime.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan -/ import Mathlib.RingTheory.Localization.Ideal import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic -import Mathlib.RingTheory.LocalRing.RingHom.Defs +import Mathlib.Algebra.Group.Units.Hom /-! # Localizations of commutative rings at the complement of a prime ideal @@ -44,7 +44,7 @@ namespace Ideal def primeCompl : Submonoid R where carrier := (Pᶜ : Set R) one_mem' := by convert P.ne_top_iff_one.1 hp.1 - mul_mem' {x y} hnx hny hxy := Or.casesOn (hp.mem_or_mem hxy) hnx hny + mul_mem' {_ _} hnx hny hxy := Or.casesOn (hp.mem_or_mem hxy) hnx hny theorem primeCompl_le_nonZeroDivisors [NoZeroDivisors R] : P.primeCompl ≤ nonZeroDivisors R := le_nonZeroDivisors_of_noZeroDivisors <| not_not_intro P.zero_mem @@ -188,12 +188,12 @@ theorem AtPrime.map_eq_maximalIdeal : -- Porting note: can not find `hI` rw [map_comap I.primeCompl] -theorem le_comap_primeCompl_iff {J : Ideal P} [hJ : J.IsPrime] {f : R →+* P} : +theorem le_comap_primeCompl_iff {J : Ideal P} [J.IsPrime] {f : R →+* P} : I.primeCompl ≤ J.primeCompl.comap f ↔ J.comap f ≤ I := ⟨fun h x hx => by contrapose! hx exact h hx, - fun h x hx hfxJ => hx (h hfxJ)⟩ + fun h _ hx hfxJ => hx (h hfxJ)⟩ variable (I) @@ -218,14 +218,18 @@ theorem localRingHom_mk' (J : Ideal P) [J.IsPrime] (f : R →+* P) (hIJ : I = J. (⟨f y, le_comap_primeCompl_iff.mpr (ge_of_eq hIJ) y.2⟩ : J.primeCompl) := map_mk' _ _ _ -instance isLocalRingHom_localRingHom (J : Ideal P) [hJ : J.IsPrime] (f : R →+* P) - (hIJ : I = J.comap f) : IsLocalRingHom (localRingHom I J f hIJ) := - IsLocalRingHom.mk fun x hx => by +@[instance] +theorem isLocalHom_localRingHom (J : Ideal P) [hJ : J.IsPrime] (f : R →+* P) + (hIJ : I = J.comap f) : IsLocalHom (localRingHom I J f hIJ) := + IsLocalHom.mk fun x hx => by rcases IsLocalization.mk'_surjective I.primeCompl x with ⟨r, s, rfl⟩ rw [localRingHom_mk'] at hx rw [AtPrime.isUnit_mk'_iff] at hx ⊢ exact fun hr => hx ((SetLike.ext_iff.mp hIJ r).mp hr) +@[deprecated (since := "2024-10-10")] +alias isLocalRingHom_localRingHom := isLocalHom_localRingHom + theorem localRingHom_unique (J : Ideal P) [J.IsPrime] (f : R →+* P) (hIJ : I = J.comap f) {j : Localization.AtPrime I →+* Localization.AtPrime J} (hj : ∀ x : R, j (algebraMap _ _ x) = algebraMap _ _ (f x)) : localRingHom I J f hIJ = j := diff --git a/Mathlib/RingTheory/Localization/Away/Basic.lean b/Mathlib/RingTheory/Localization/Away/Basic.lean index eaaebda203892..3c1532d750273 100644 --- a/Mathlib/RingTheory/Localization/Away/Basic.lean +++ b/Mathlib/RingTheory/Localization/Away/Basic.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: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen -/ +import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.RingTheory.UniqueFactorizationDomain import Mathlib.RingTheory.Localization.Basic @@ -231,6 +232,18 @@ lemma mul' (T : Type*) [CommSemiring T] [Algebra S T] [Algebra R T] [IsScalarTow IsLocalization.Away (x * y) T := mul_comm x y ▸ mul S T x y +/-- Localizing the localization of `R` at `x` at the image of `y` is the same as localizing +`R` at `y * x`. -/ +instance (x y : R) [IsLocalization.Away x S] : + IsLocalization.Away (y * x) (Localization.Away (algebraMap R S y)) := + IsLocalization.Away.mul S (Localization.Away (algebraMap R S y)) _ _ + +/-- Localizing the localization of `R` at `x` at the image of `y` is the same as localizing +`R` at `x * y`. -/ +instance (x y : R) [IsLocalization.Away x S] : + IsLocalization.Away (x * y) (Localization.Away (algebraMap R S y)) := + IsLocalization.Away.mul' S (Localization.Away (algebraMap R S y)) _ _ + /-- If `S₁` is the localization of `R` away from `f` and `S₂` is the localization away from `g`, then any localization `T` of `S₂` away from `f` is also a localization of `S₁` away from `g`. -/ lemma commutes {R : Type*} [CommSemiring R] (S₁ S₂ T : Type*) [CommSemiring S₁] @@ -275,7 +288,7 @@ theorem away_of_isUnit_of_bijective {R : Type*} (S : Type*) [CommRing R] [CommRi obtain ⟨z', rfl⟩ := H.2 z exact ⟨⟨z', 1⟩, by simp⟩ exists_of_eq := fun {x y} => by - erw [H.1.eq_iff] + rw [H.1.eq_iff] rintro rfl exact ⟨1, rfl⟩ } diff --git a/Mathlib/RingTheory/Localization/BaseChange.lean b/Mathlib/RingTheory/Localization/BaseChange.lean index fcb23d52941ff..999592d5ff587 100644 --- a/Mathlib/RingTheory/Localization/BaseChange.lean +++ b/Mathlib/RingTheory/Localization/BaseChange.lean @@ -47,3 +47,12 @@ theorem isLocalizedModule_iff_isBaseChange : IsLocalizedModule S f ↔ IsBaseCha rw [LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, LinearEquiv.restrictScalars_apply, LinearEquiv.trans_apply, IsBaseChange.equiv_symm_apply, IsBaseChange.equiv_tmul, one_smul] + +variable (T B : Type*) [CommSemiring T] [CommSemiring B] + [Algebra R T] [Algebra T B] [Algebra R B] [Algebra A B] [IsScalarTower R T B] + [IsScalarTower R A B] + +lemma Algebra.isPushout_of_isLocalization [IsLocalization (Algebra.algebraMapSubmonoid T S) B] : + Algebra.IsPushout R T A B := by + rw [Algebra.IsPushout.comm, Algebra.isPushout_iff] + apply IsLocalizedModule.isBaseChange S diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index ee3d1fbf1a3d4..acec79b4a06bb 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -4,14 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen -/ 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 -import Mathlib.RingTheory.Ideal.Basic /-! # Localizations of commutative rings +This file contains various basic results on localizations. + We characterize the localization of a commutative ring `R` at a submonoid `M` up to isomorphism; that is, a commutative ring `S` is the localization of `R` at `M` iff we can find a ring homomorphism `f : R →+* S` satisfying 3 properties: @@ -29,26 +33,9 @@ variable [Algebra R S] [Algebra P Q] (M : Submonoid R) (T : Submonoid P) ## Main definitions - * `IsLocalization (M : Submonoid R) (S : Type*)` is a typeclass expressing that `S` is a - localization of `R` at `M`, i.e. the canonical map `algebraMap R S : R →+* S` is a - localization map (satisfying the above properties). - * `IsLocalization.mk' S` is a surjection sending `(x, y) : R × M` to `f x * (f y)⁻¹` - * `IsLocalization.lift` is the ring homomorphism from `S` induced by a homomorphism from `R` - which maps elements of `M` to invertible elements of the codomain. - * `IsLocalization.map S Q` is the ring homomorphism from `S` to `Q` which maps elements - of `M` to elements of `T` - * `IsLocalization.ringEquivOfRingEquiv`: if `R` and `P` are isomorphic by an isomorphism - sending `M` to `T`, then `S` and `Q` are isomorphic * `IsLocalization.algEquiv`: if `Q` is another localization of `R` at `M`, then `S` and `Q` are isomorphic as `R`-algebras -## Main results - - * `Localization M S`, a construction of the localization as a quotient type, defined in - `GroupTheory.MonoidLocalization`, has `CommRing`, `Algebra R` and `IsLocalization M` - instances if `R` is a ring. `Localization.Away`, `Localization.AtPrime` and `FractionRing` - are abbreviations for `Localization`s and have their corresponding `IsLocalization` instances - ## Implementation notes In maths it is natural to reason up to isomorphism, but in Lean we cannot naturally `rewrite` one @@ -86,225 +73,15 @@ open Function section CommSemiring -variable {R : Type*} [CommSemiring R] (M : Submonoid R) (S : Type*) [CommSemiring S] +variable {R : Type*} [CommSemiring R] {M : Submonoid R} {S : Type*} [CommSemiring S] variable [Algebra R S] {P : Type*} [CommSemiring P] -/-- The typeclass `IsLocalization (M : Submonoid R) S` where `S` is an `R`-algebra -expresses that `S` is isomorphic to the localization of `R` at `M`. -/ -@[mk_iff] class IsLocalization : Prop where - -- Porting note: add ' to fields, and made new versions of these with either `S` or `M` explicit. - /-- Everything in the image of `algebraMap` is a unit -/ - map_units' : ∀ y : M, IsUnit (algebraMap R S y) - /-- The `algebraMap` is surjective -/ - surj' : ∀ z : S, ∃ x : R × M, z * algebraMap R S x.2 = algebraMap R S x.1 - /-- The kernel of `algebraMap` is contained in the annihilator of `M`; - it is then equal to the annihilator by `map_units'` -/ - exists_of_eq : ∀ {x y}, algebraMap R S x = algebraMap R S y → ∃ c : M, ↑c * x = ↑c * y - -variable {M} - namespace IsLocalization section IsLocalization variable [IsLocalization M S] -section - -@[inherit_doc IsLocalization.map_units'] -theorem map_units : ∀ y : M, IsUnit (algebraMap R S y) := - IsLocalization.map_units' - -variable (M) {S} -@[inherit_doc IsLocalization.surj'] -theorem surj : ∀ z : S, ∃ x : R × M, z * algebraMap R S x.2 = algebraMap R S x.1 := - IsLocalization.surj' - -variable (S) -@[inherit_doc IsLocalization.exists_of_eq] -theorem eq_iff_exists {x y} : algebraMap R S x = algebraMap R S y ↔ ∃ c : M, ↑c * x = ↑c * y := - Iff.intro IsLocalization.exists_of_eq fun ⟨c, h⟩ ↦ by - apply_fun algebraMap R S at h - rw [map_mul, map_mul] at h - exact (IsLocalization.map_units S c).mul_right_inj.mp h - -variable {S} -theorem of_le (N : Submonoid R) (h₁ : M ≤ N) (h₂ : ∀ r ∈ N, IsUnit (algebraMap R S r)) : - IsLocalization N S where - map_units' r := h₂ r r.2 - surj' s := - have ⟨⟨x, y, hy⟩, H⟩ := IsLocalization.surj M s - ⟨⟨x, y, h₁ hy⟩, H⟩ - exists_of_eq {x y} := by - rw [IsLocalization.eq_iff_exists M] - rintro ⟨c, hc⟩ - exact ⟨⟨c, h₁ c.2⟩, hc⟩ - -variable (S) - -/-- `IsLocalization.toLocalizationWithZeroMap M S` shows `S` is the monoid localization of -`R` at `M`. -/ -@[simps] -def toLocalizationWithZeroMap : Submonoid.LocalizationWithZeroMap M S where - __ := algebraMap R S - toFun := algebraMap R S - map_units' := IsLocalization.map_units _ - surj' := IsLocalization.surj _ - exists_of_eq _ _ := IsLocalization.exists_of_eq - -/-- `IsLocalization.toLocalizationMap M S` shows `S` is the monoid localization of `R` at `M`. -/ -abbrev toLocalizationMap : Submonoid.LocalizationMap M S := - (toLocalizationWithZeroMap M S).toLocalizationMap - -@[simp] -theorem toLocalizationMap_toMap : (toLocalizationMap M S).toMap = (algebraMap R S : R →*₀ S) := - rfl - -theorem toLocalizationMap_toMap_apply (x) : (toLocalizationMap M S).toMap x = algebraMap R S x := - rfl - -theorem surj₂ : ∀ z w : S, ∃ z' w' : R, ∃ d : M, - (z * algebraMap R S d = algebraMap R S z') ∧ (w * algebraMap R S d = algebraMap R S w') := - (toLocalizationMap M S).surj₂ - -end - -variable (M) {S} - -/-- Given a localization map `f : M →* N`, a section function sending `z : N` to some -`(x, y) : M × S` such that `f x * (f y)⁻¹ = z`. -/ -noncomputable def sec (z : S) : R × M := - Classical.choose <| IsLocalization.surj _ z - -@[simp] -theorem toLocalizationMap_sec : (toLocalizationMap M S).sec = sec M := - rfl - -/-- Given `z : S`, `IsLocalization.sec M z` is defined to be a pair `(x, y) : R × M` such -that `z * f y = f x` (so this lemma is true by definition). -/ -theorem sec_spec (z : S) : - z * algebraMap R S (IsLocalization.sec M z).2 = algebraMap R S (IsLocalization.sec M z).1 := - Classical.choose_spec <| IsLocalization.surj _ z - -/-- Given `z : S`, `IsLocalization.sec M z` is defined to be a pair `(x, y) : R × M` such -that `z * f y = f x`, so this lemma is just an application of `S`'s commutativity. -/ -theorem sec_spec' (z : S) : - algebraMap R S (IsLocalization.sec M z).1 = algebraMap R S (IsLocalization.sec M z).2 * z := by - rw [mul_comm, sec_spec] - -variable {M} - -/-- If `M` contains `0` then the localization at `M` is trivial. -/ -theorem subsingleton (h : 0 ∈ M) : Subsingleton S := (toLocalizationMap M S).subsingleton h - -theorem map_right_cancel {x y} {c : M} (h : algebraMap R S (c * x) = algebraMap R S (c * y)) : - algebraMap R S x = algebraMap R S y := - (toLocalizationMap M S).map_right_cancel h - -theorem map_left_cancel {x y} {c : M} (h : algebraMap R S (x * c) = algebraMap R S (y * c)) : - algebraMap R S x = algebraMap R S y := - (toLocalizationMap M S).map_left_cancel h - -theorem eq_zero_of_fst_eq_zero {z x} {y : M} (h : z * algebraMap R S y = algebraMap R S x) - (hx : x = 0) : z = 0 := by - rw [hx, (algebraMap R S).map_zero] at h - exact (IsUnit.mul_left_eq_zero (IsLocalization.map_units S y)).1 h - -variable (M S) - -theorem map_eq_zero_iff (r : R) : algebraMap R S r = 0 ↔ ∃ m : M, ↑m * r = 0 := by - constructor - · intro h - obtain ⟨m, hm⟩ := (IsLocalization.eq_iff_exists M S).mp ((algebraMap R S).map_zero.trans h.symm) - exact ⟨m, by simpa using hm.symm⟩ - · rintro ⟨m, hm⟩ - rw [← (IsLocalization.map_units S m).mul_right_inj, mul_zero, ← RingHom.map_mul, hm, - RingHom.map_zero] - -variable {M} - -/-- `IsLocalization.mk' S` is the surjection sending `(x, y) : R × M` to -`f x * (f y)⁻¹`. -/ -noncomputable def mk' (x : R) (y : M) : S := - (toLocalizationMap M S).mk' x y - -@[simp] -theorem mk'_sec (z : S) : mk' S (IsLocalization.sec M z).1 (IsLocalization.sec M z).2 = z := - (toLocalizationMap M S).mk'_sec _ - -theorem mk'_mul (x₁ x₂ : R) (y₁ y₂ : M) : mk' S (x₁ * x₂) (y₁ * y₂) = mk' S x₁ y₁ * mk' S x₂ y₂ := - (toLocalizationMap M S).mk'_mul _ _ _ _ - -theorem mk'_one (x) : mk' S x (1 : M) = algebraMap R S x := - (toLocalizationMap M S).mk'_one _ - -@[simp] -theorem mk'_spec (x) (y : M) : mk' S x y * algebraMap R S y = algebraMap R S x := - (toLocalizationMap M S).mk'_spec _ _ - -@[simp] -theorem mk'_spec' (x) (y : M) : algebraMap R S y * mk' S x y = algebraMap R S x := - (toLocalizationMap M S).mk'_spec' _ _ - -@[simp] -theorem mk'_spec_mk (x) (y : R) (hy : y ∈ M) : - mk' S x ⟨y, hy⟩ * algebraMap R S y = algebraMap R S x := - mk'_spec S x ⟨y, hy⟩ - -@[simp] -theorem mk'_spec'_mk (x) (y : R) (hy : y ∈ M) : - algebraMap R S y * mk' S x ⟨y, hy⟩ = algebraMap R S x := - mk'_spec' S x ⟨y, hy⟩ - -variable {S} - -theorem eq_mk'_iff_mul_eq {x} {y : M} {z} : - z = mk' S x y ↔ z * algebraMap R S y = algebraMap R S x := - (toLocalizationMap M S).eq_mk'_iff_mul_eq - -theorem eq_mk'_of_mul_eq {x : R} {y : M} {z : R} (h : z * y = x) : (algebraMap R S) z = mk' S x y := - eq_mk'_iff_mul_eq.mpr (by rw [← h, map_mul]) - -theorem mk'_eq_iff_eq_mul {x} {y : M} {z} : - mk' S x y = z ↔ algebraMap R S x = z * algebraMap R S y := - (toLocalizationMap M S).mk'_eq_iff_eq_mul - -theorem mk'_add_eq_iff_add_mul_eq_mul {x} {y : M} {z₁ z₂} : - mk' S x y + z₁ = z₂ ↔ algebraMap R S x + z₁ * algebraMap R S y = z₂ * algebraMap R S y := by - rw [← mk'_spec S x y, ← IsUnit.mul_left_inj (IsLocalization.map_units S y), right_distrib] - -theorem mk'_pow (x : R) (y : M) (n : ℕ) : mk' S (x ^ n) (y ^ n) = mk' S x y ^ n := by - simp_rw [IsLocalization.mk'_eq_iff_eq_mul, SubmonoidClass.coe_pow, map_pow, ← mul_pow] - simp - -variable (M) - -theorem mk'_surjective (z : S) : ∃ (x : _) (y : M), mk' S x y = z := - let ⟨r, hr⟩ := IsLocalization.surj _ z - ⟨r.1, r.2, (eq_mk'_iff_mul_eq.2 hr).symm⟩ - -variable (S) - -/-- The localization of a `Fintype` is a `Fintype`. Cannot be an instance. -/ -noncomputable def fintype' [Fintype R] : Fintype S := - have := Classical.propDecidable - Fintype.ofSurjective (Function.uncurry <| IsLocalization.mk' S) fun a => - Prod.exists'.mpr <| IsLocalization.mk'_surjective M a - -variable {M S} - -/-- Localizing at a submonoid with 0 inside it leads to the trivial ring. -/ -def uniqueOfZeroMem (h : (0 : R) ∈ M) : Unique S := - uniqueOfZeroEqOne <| by simpa using IsLocalization.map_units S ⟨0, h⟩ - -theorem mk'_eq_iff_eq {x₁ x₂} {y₁ y₂ : M} : - mk' S x₁ y₁ = mk' S x₂ y₂ ↔ algebraMap R S (y₂ * x₁) = algebraMap R S (y₁ * x₂) := - (toLocalizationMap M S).mk'_eq_iff_eq - -theorem mk'_eq_iff_eq' {x₁ x₂} {y₁ y₂ : M} : - mk' S x₁ y₁ = mk' S x₂ y₂ ↔ algebraMap R S (x₁ * y₂) = algebraMap R S (x₂ * y₁) := - (toLocalizationMap M S).mk'_eq_iff_eq' - 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] @@ -314,198 +91,10 @@ theorem mk'_mem_iff {x} {y : M} {I : Ideal S} : mk' S x y ∈ I ↔ algebraMap R have := I.mul_mem_left b h rwa [mul_comm, mul_assoc, hb, mul_one] at this -protected theorem eq {a₁ b₁} {a₂ b₂ : M} : - mk' S a₁ a₂ = mk' S b₁ b₂ ↔ ∃ c : M, ↑c * (↑b₂ * a₁) = c * (a₂ * b₁) := - (toLocalizationMap M S).eq - -theorem mk'_eq_zero_iff (x : R) (s : M) : mk' S x s = 0 ↔ ∃ m : M, ↑m * x = 0 := by - rw [← (map_units S s).mul_left_inj, mk'_spec, zero_mul, map_eq_zero_iff M] - -@[simp] -theorem mk'_zero (s : M) : IsLocalization.mk' S 0 s = 0 := by - rw [eq_comm, IsLocalization.eq_mk'_iff_mul_eq, zero_mul, map_zero] - -theorem ne_zero_of_mk'_ne_zero {x : R} {y : M} (hxy : IsLocalization.mk' S x y ≠ 0) : x ≠ 0 := by - rintro rfl - exact hxy (IsLocalization.mk'_zero _) - -section Ext - -theorem eq_iff_eq [Algebra R P] [IsLocalization M P] {x y} : - algebraMap R S x = algebraMap R S y ↔ algebraMap R P x = algebraMap R P y := - (toLocalizationMap M S).eq_iff_eq (toLocalizationMap M P) - -theorem mk'_eq_iff_mk'_eq [Algebra R P] [IsLocalization M P] {x₁ x₂} {y₁ y₂ : M} : - mk' S x₁ y₁ = mk' S x₂ y₂ ↔ mk' P x₁ y₁ = mk' P x₂ y₂ := - (toLocalizationMap M S).mk'_eq_iff_mk'_eq (toLocalizationMap M P) - -theorem mk'_eq_of_eq {a₁ b₁ : R} {a₂ b₂ : M} (H : ↑a₂ * b₁ = ↑b₂ * a₁) : - mk' S a₁ a₂ = mk' S b₁ b₂ := - (toLocalizationMap M S).mk'_eq_of_eq H - -theorem mk'_eq_of_eq' {a₁ b₁ : R} {a₂ b₂ : M} (H : b₁ * ↑a₂ = a₁ * ↑b₂) : - mk' S a₁ a₂ = mk' S b₁ b₂ := - (toLocalizationMap M S).mk'_eq_of_eq' H - -theorem mk'_cancel (a : R) (b c : M) : - mk' S (a * c) (b * c) = mk' S a b := (toLocalizationMap M S).mk'_cancel _ _ _ - -variable (S) - -@[simp] -theorem mk'_self {x : R} (hx : x ∈ M) : mk' S x ⟨x, hx⟩ = 1 := - (toLocalizationMap M S).mk'_self _ hx - -@[simp] -theorem mk'_self' {x : M} : mk' S (x : R) x = 1 := - (toLocalizationMap M S).mk'_self' _ - -theorem mk'_self'' {x : M} : mk' S x.1 x = 1 := - mk'_self' _ - -end Ext - -theorem mul_mk'_eq_mk'_of_mul (x y : R) (z : M) : - (algebraMap R S) x * mk' S y z = mk' S (x * y) z := - (toLocalizationMap M S).mul_mk'_eq_mk'_of_mul _ _ _ - -theorem mk'_eq_mul_mk'_one (x : R) (y : M) : mk' S x y = (algebraMap R S) x * mk' S 1 y := - ((toLocalizationMap M S).mul_mk'_one_eq_mk' _ _).symm - -@[simp] -theorem mk'_mul_cancel_left (x : R) (y : M) : mk' S (y * x : R) y = (algebraMap R S) x := - (toLocalizationMap M S).mk'_mul_cancel_left _ _ - -theorem mk'_mul_cancel_right (x : R) (y : M) : mk' S (x * y) y = (algebraMap R S) x := - (toLocalizationMap M S).mk'_mul_cancel_right _ _ - -@[simp] -theorem mk'_mul_mk'_eq_one (x y : M) : mk' S (x : R) y * mk' S (y : R) x = 1 := by - rw [← mk'_mul, mul_comm]; exact mk'_self _ _ - -theorem mk'_mul_mk'_eq_one' (x : R) (y : M) (h : x ∈ M) : mk' S x y * mk' S (y : R) ⟨x, h⟩ = 1 := - mk'_mul_mk'_eq_one ⟨x, h⟩ _ - -theorem smul_mk' (x y : R) (m : M) : x • mk' S y m = mk' S (x * y) m := by - nth_rw 2 [← one_mul m] - rw [mk'_mul, mk'_one, Algebra.smul_def] - -@[simp] theorem smul_mk'_one (x : R) (m : M) : x • mk' S 1 m = mk' S x m := by - rw [smul_mk', mul_one] - -@[simp] lemma smul_mk'_self {m : M} {r : R} : - (m : R) • mk' S r m = algebraMap R S r := by - rw [smul_mk', mk'_mul_cancel_left] - -@[simps] -instance invertible_mk'_one (s : M) : Invertible (IsLocalization.mk' S (1 : R) s) where - invOf := algebraMap R S s - invOf_mul_self := by simp - mul_invOf_self := by simp - -section - -variable (M) - -theorem isUnit_comp (j : S →+* P) (y : M) : IsUnit (j.comp (algebraMap R S) y) := - (toLocalizationMap M S).isUnit_comp j.toMonoidHom _ - -end - -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s -`g : R →+* P` such that `g(M) ⊆ Units P`, `f x = f y → g x = g y` for all `x y : R`. -/ -theorem eq_of_eq {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) {x y} - (h : (algebraMap R S) x = (algebraMap R S) y) : g x = g y := - Submonoid.LocalizationMap.eq_of_eq (toLocalizationMap M S) (g := g.toMonoidHom) hg h - -theorem mk'_add (x₁ x₂ : R) (y₁ y₂ : M) : - mk' S (x₁ * y₂ + x₂ * y₁) (y₁ * y₂) = mk' S x₁ y₁ + mk' S x₂ y₂ := - mk'_eq_iff_eq_mul.2 <| - Eq.symm - (by - rw [mul_comm (_ + _), mul_add, mul_mk'_eq_mk'_of_mul, mk'_add_eq_iff_add_mul_eq_mul, - mul_comm (_ * _), ← mul_assoc, add_comm, ← map_mul, mul_mk'_eq_mk'_of_mul, - mk'_add_eq_iff_add_mul_eq_mul] - simp only [map_add, Submonoid.coe_mul, map_mul] - ring) - -theorem mul_add_inv_left {g : R →+* P} (h : ∀ y : M, IsUnit (g y)) (y : M) (w z₁ z₂ : P) : - w * ↑(IsUnit.liftRight (g.toMonoidHom.restrict M) h y)⁻¹ + z₁ = - z₂ ↔ w + g y * z₁ = g y * z₂ := by - rw [mul_comm, ← one_mul z₁, ← Units.inv_mul (IsUnit.liftRight (g.toMonoidHom.restrict M) h y), - mul_assoc, ← mul_add, Units.inv_mul_eq_iff_eq_mul, Units.inv_mul_cancel_left, - IsUnit.coe_liftRight] - simp [RingHom.toMonoidHom_eq_coe, MonoidHom.restrict_apply] - -theorem lift_spec_mul_add {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) (z w w' v) : - ((toLocalizationWithZeroMap M S).lift g.toMonoidWithZeroHom hg) z * w + w' = v ↔ - g ((toLocalizationMap M S).sec z).1 * w + g ((toLocalizationMap M S).sec z).2 * w' = - g ((toLocalizationMap M S).sec z).2 * v := by - erw [mul_comm, ← mul_assoc, mul_add_inv_left hg, mul_comm] - rfl - -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s -`g : R →+* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from -`S` to `P` sending `z : S` to `g x * (g y)⁻¹`, where `(x, y) : R × M` are such that -`z = f x * (f y)⁻¹`. -/ -noncomputable def lift {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) : S →+* P := - { Submonoid.LocalizationWithZeroMap.lift (toLocalizationWithZeroMap M S) - g.toMonoidWithZeroHom hg with - map_add' := by - intro x y - erw [(toLocalizationMap M S).lift_spec, mul_add, mul_comm, eq_comm, lift_spec_mul_add, - add_comm, mul_comm, mul_assoc, mul_comm, mul_assoc, lift_spec_mul_add] - simp_rw [← mul_assoc] - show g _ * g _ * g _ + g _ * g _ * g _ = g _ * g _ * g _ - simp_rw [← map_mul g, ← map_add g] - apply eq_of_eq (S := S) hg - simp only [sec_spec', toLocalizationMap_sec, map_add, map_mul] - ring } - variable {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s -`g : R →* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from -`S` to `P` maps `f x * (f y)⁻¹` to `g x * (g y)⁻¹` for all `x : R, y ∈ M`. -/ -theorem lift_mk' (x y) : - lift hg (mk' S x y) = g x * ↑(IsUnit.liftRight (g.toMonoidHom.restrict M) hg y)⁻¹ := - (toLocalizationMap M S).lift_mk' _ _ _ - -theorem lift_mk'_spec (x v) (y : M) : lift hg (mk' S x y) = v ↔ g x = g y * v := - (toLocalizationMap M S).lift_mk'_spec _ _ _ _ - -@[simp] -theorem lift_eq (x : R) : lift hg ((algebraMap R S) x) = g x := - (toLocalizationMap M S).lift_eq _ _ - -theorem lift_eq_iff {x y : R × M} : - lift hg (mk' S x.1 x.2) = lift hg (mk' S y.1 y.2) ↔ g (x.1 * y.2) = g (y.1 * x.2) := - (toLocalizationMap M S).lift_eq_iff _ - -@[simp] -theorem lift_comp : (lift hg).comp (algebraMap R S) = g := - RingHom.ext <| (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| (toLocalizationMap M S).lift_comp _ - -@[simp] -theorem lift_of_comp (j : S →+* P) : lift (isUnit_comp M j) = j := - RingHom.ext <| (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| - (toLocalizationMap M S).lift_of_comp j.toMonoidHom - -variable (M) - -section -include M - -/-- See note [partially-applied ext lemmas] -/ -theorem monoidHom_ext ⦃j k : S →* P⦄ - (h : j.comp (algebraMap R S : R →* S) = k.comp (algebraMap R S)) : j = k := - Submonoid.LocalizationMap.epic_of_localizationMap (toLocalizationMap M S) <| DFunLike.congr_fun h - -/-- See note [partially-applied ext lemmas] -/ -theorem ringHom_ext ⦃j k : S →+* P⦄ (h : j.comp (algebraMap R S) = k.comp (algebraMap R S)) : - j = k := - RingHom.coe_monoidHom_injective <| monoidHom_ext M <| MonoidHom.ext <| RingHom.congr_fun h - +variable (M) in +include M in /- This is not an instance because the submonoid `M` would become a metavariable in typeclass search. -/ theorem algHom_subsingleton [Algebra R P] : Subsingleton (S →ₐ[R] P) := @@ -513,154 +102,6 @@ theorem algHom_subsingleton [Algebra R P] : Subsingleton (S →ₐ[R] P) := AlgHom.coe_ringHom_injective <| IsLocalization.ringHom_ext M <| by rw [f.comp_algebraMap, g.comp_algebraMap]⟩ -/-- To show `j` and `k` agree on the whole localization, it suffices to show they agree -on the image of the base ring, if they preserve `1` and `*`. -/ -protected theorem ext (j k : S → P) (hj1 : j 1 = 1) (hk1 : k 1 = 1) - (hjm : ∀ a b, j (a * b) = j a * j b) (hkm : ∀ a b, k (a * b) = k a * k b) - (h : ∀ a, j (algebraMap R S a) = k (algebraMap R S a)) : j = k := - let j' : MonoidHom S P := - { toFun := j, map_one' := hj1, map_mul' := hjm } - let k' : MonoidHom S P := - { toFun := k, map_one' := hk1, map_mul' := hkm } - have : j' = k' := monoidHom_ext M (MonoidHom.ext h) - show j'.toFun = k'.toFun by rw [this] -end - -variable {M} - -theorem lift_unique {j : S →+* P} (hj : ∀ x, j ((algebraMap R S) x) = g x) : lift hg = j := - RingHom.ext <| - (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| - Submonoid.LocalizationMap.lift_unique (toLocalizationMap M S) (g := g.toMonoidHom) hg - (j := j.toMonoidHom) hj - -@[simp] -theorem lift_id (x) : lift (map_units S : ∀ _ : M, IsUnit _) x = x := - (toLocalizationMap M S).lift_id _ - -theorem lift_surjective_iff : - Surjective (lift hg : S → P) ↔ ∀ v : P, ∃ x : R × M, v * g x.2 = g x.1 := - (toLocalizationMap M S).lift_surjective_iff hg - -theorem lift_injective_iff : - Injective (lift hg : S → P) ↔ ∀ x y, algebraMap R S x = algebraMap R S y ↔ g x = g y := - (toLocalizationMap M S).lift_injective_iff hg - -section Map - -variable {T : Submonoid P} {Q : Type*} [CommSemiring Q] -variable [Algebra P Q] [IsLocalization T Q] - -section - -variable (Q) - -/-- Map a homomorphism `g : R →+* P` to `S →+* Q`, where `S` and `Q` are -localizations of `R` and `P` at `M` and `T` respectively, -such that `g(M) ⊆ T`. - -We send `z : S` to `algebraMap P Q (g x) * (algebraMap P Q (g y))⁻¹`, where -`(x, y) : R × M` are such that `z = f x * (f y)⁻¹`. -/ -noncomputable def map (g : R →+* P) (hy : M ≤ T.comap g) : S →+* Q := - lift (M := M) (g := (algebraMap P Q).comp g) fun y => map_units _ ⟨g y, hy y.2⟩ - -end - -section -variable (hy : M ≤ T.comap g) -include hy - --- Porting note: added `simp` attribute, since it proves very similar lemmas marked `simp` -@[simp] -theorem map_eq (x) : map Q g hy ((algebraMap R S) x) = algebraMap P Q (g x) := - lift_eq (fun y => map_units _ ⟨g y, hy y.2⟩) x - -@[simp] -theorem map_comp : (map Q g hy).comp (algebraMap R S) = (algebraMap P Q).comp g := - lift_comp fun y => map_units _ ⟨g y, hy y.2⟩ - -theorem map_mk' (x) (y : M) : map Q g hy (mk' S x y) = mk' Q (g x) ⟨g y, hy y.2⟩ := - Submonoid.LocalizationMap.map_mk' (toLocalizationMap M S) (g := g.toMonoidHom) - (fun y => hy y.2) (k := toLocalizationMap T Q) .. - -theorem map_unique (j : S →+* Q) (hj : ∀ x : R, j (algebraMap R S x) = algebraMap P Q (g x)) : - map Q g hy = j := - lift_unique (fun y => map_units _ ⟨g y, hy y.2⟩) hj - -/-- If `CommSemiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition -of the induced maps equals the map of localizations induced by `l ∘ g`. -/ -theorem map_comp_map {A : Type*} [CommSemiring A] {U : Submonoid A} {W} [CommSemiring W] - [Algebra A W] [IsLocalization U W] {l : P →+* A} (hl : T ≤ U.comap l) : - (map W l hl).comp (map Q g hy : S →+* _) = map W (l.comp g) fun _ hx => hl (hy hx) := - RingHom.ext fun x => - Submonoid.LocalizationMap.map_map (P := P) (toLocalizationMap M S) (fun y => hy y.2) - (toLocalizationMap U W) (fun w => hl w.2) x - -/-- If `CommSemiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition -of the induced maps equals the map of localizations induced by `l ∘ g`. -/ -theorem map_map {A : Type*} [CommSemiring A] {U : Submonoid A} {W} [CommSemiring W] [Algebra A W] - [IsLocalization U W] {l : P →+* A} (hl : T ≤ U.comap l) (x : S) : - map W l hl (map Q g hy x) = map W (l.comp g) (fun x hx => hl (hy hx)) x := by - rw [← map_comp_map (Q := Q) hy hl]; rfl - -theorem map_smul (x : S) (z : R) : map Q g hy (z • x : S) = g z • map Q g hy x := by - rw [Algebra.smul_def, Algebra.smul_def, RingHom.map_mul, map_eq] - -end - -@[simp] -theorem map_id_mk' {Q : Type*} [CommSemiring Q] [Algebra R Q] [IsLocalization M Q] (x) (y : M) : - map Q (RingHom.id R) (le_refl M) (mk' S x y) = mk' Q x y := - map_mk' .. - -@[simp] -theorem map_id (z : S) (h : M ≤ M.comap (RingHom.id R) := le_refl M) : - map S (RingHom.id _) h z = z := - lift_id _ - -section - -variable (S Q) - -/-- If `S`, `Q` are localizations of `R` and `P` at submonoids `M, T` respectively, an -isomorphism `j : R ≃+* P` such that `j(M) = T` induces an isomorphism of localizations -`S ≃+* Q`. -/ -@[simps] -noncomputable def ringEquivOfRingEquiv (h : R ≃+* P) (H : M.map h.toMonoidHom = T) : S ≃+* Q := - have H' : T.map h.symm.toMonoidHom = M := by - rw [← M.map_id, ← H, Submonoid.map_map] - congr - ext - apply h.symm_apply_apply - { map Q (h : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) with - toFun := map Q (h : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) - invFun := map S (h.symm : P →+* R) (T.le_comap_of_map_le (le_of_eq H')) - left_inv := fun x => by - rw [map_map, map_unique _ (RingHom.id _), RingHom.id_apply] - simp - right_inv := fun x => by - rw [map_map, map_unique _ (RingHom.id _), RingHom.id_apply] - simp } - -end - -theorem ringEquivOfRingEquiv_eq_map {j : R ≃+* P} (H : M.map j.toMonoidHom = T) : - (ringEquivOfRingEquiv S Q j H : S →+* Q) = - map Q (j : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) := - rfl - --- Porting note (#10618): removed `simp`, `simp` can prove it -theorem ringEquivOfRingEquiv_eq {j : R ≃+* P} (H : M.map j.toMonoidHom = T) (x) : - ringEquivOfRingEquiv S Q j H ((algebraMap R S) x) = algebraMap P Q (j x) := by - simp - -theorem ringEquivOfRingEquiv_mk' {j : R ≃+* P} (H : M.map j.toMonoidHom = T) (x : R) (y : M) : - ringEquivOfRingEquiv S Q j H (mk' S x y) = - mk' Q (j x) ⟨j y, show j y ∈ T from H ▸ Set.mem_image_of_mem j y.2⟩ := by - simp [map_mk'] - -end Map - section AlgEquiv variable {Q : Type*} [CommSemiring Q] [Algebra R Q] [IsLocalization M Q] @@ -678,11 +119,9 @@ noncomputable def algEquiv : S ≃ₐ[R] Q := end --- Porting note (#10618): removed `simp`, `simp` can prove it theorem algEquiv_mk' (x : R) (y : M) : algEquiv M S Q (mk' S x y) = mk' Q x y := by simp --- Porting note (#10618): removed `simp`, `simp` can prove it theorem algEquiv_symm_mk' (x : R) (y : M) : (algEquiv M S Q).symm (mk' Q x y) = mk' S x y := by simp variable (M) in @@ -696,11 +135,6 @@ protected lemma bijective (f : S →+* Q) (hf : f.comp (algebraMap R S) = algebr end AlgEquiv section at_units -lemma at_units (S : Submonoid R) - (hS : S ≤ IsUnit.submonoid R) : IsLocalization S R where - map_units' y := hS y.prop - surj' := fun s ↦ ⟨⟨s, 1⟩, by simp⟩ - exists_of_eq := fun {x y} (e : x = y) ↦ ⟨1, e ▸ rfl⟩ variable (R M) @@ -721,27 +155,11 @@ noncomputable def atUnits (H : M ≤ IsUnit.submonoid R) : R ≃ₐ[R] S := by end at_units -section - -variable (M S) (Q : Type*) [CommSemiring Q] [Algebra P Q] - -/-- Injectivity of a map descends to the map induced on localizations. -/ -theorem map_injective_of_injective (h : Function.Injective g) [IsLocalization (M.map g) Q] : - Function.Injective (map Q g M.le_comap_map : S → Q) := - (toLocalizationMap M S).map_injective_of_injective h (toLocalizationMap (M.map g) Q) - -/-- Surjectivity of a map descends to the map induced on localizations. -/ -theorem map_surjective_of_surjective (h : Function.Surjective g) [IsLocalization (M.map g) Q] : - Function.Surjective (map Q g M.le_comap_map : S → Q) := - (toLocalizationMap M S).map_surjective_of_surjective h (toLocalizationMap (M.map g) Q) - -end - end IsLocalization section -variable (M) {S} +variable (M) theorem isLocalization_of_algEquiv [Algebra R P] [IsLocalization M S] (h : S ≃ₐ[R] P) : IsLocalization M P := by @@ -769,65 +187,10 @@ theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : letI := (h.toRingHom.comp <| algebraMap R S).toAlgebra isLocalization_iff_of_algEquiv M { h with commutes' := fun _ => rfl } -variable (S) - -theorem isLocalization_of_base_ringEquiv [IsLocalization M S] (h : R ≃+* P) : - haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra - IsLocalization (M.map h.toMonoidHom) S := by - letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra - constructor - · rintro ⟨_, ⟨y, hy, rfl⟩⟩ - convert IsLocalization.map_units S ⟨y, hy⟩ - dsimp only [RingHom.algebraMap_toAlgebra, RingHom.comp_apply] - exact congr_arg _ (h.symm_apply_apply _) - · intro y - obtain ⟨⟨x, s⟩, e⟩ := IsLocalization.surj M y - refine ⟨⟨h x, _, _, s.prop, rfl⟩, ?_⟩ - dsimp only [RingHom.algebraMap_toAlgebra, RingHom.comp_apply] at e ⊢ - convert e <;> exact h.symm_apply_apply _ - · intro x y - rw [RingHom.algebraMap_toAlgebra, RingHom.comp_apply, RingHom.comp_apply, - IsLocalization.eq_iff_exists M S] - simp_rw [← h.toEquiv.apply_eq_iff_eq] - change (∃ c : M, h (c * h.symm x) = h (c * h.symm y)) → _ - simp only [RingEquiv.apply_symm_apply, RingEquiv.map_mul] - exact fun ⟨c, e⟩ ↦ ⟨⟨_, _, c.prop, rfl⟩, e⟩ - -theorem isLocalization_iff_of_base_ringEquiv (h : R ≃+* P) : - IsLocalization M S ↔ - haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra - IsLocalization (M.map h.toMonoidHom) S := by - letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra - refine ⟨fun _ => isLocalization_of_base_ringEquiv M S h, ?_⟩ - intro H - convert isLocalization_of_base_ringEquiv (Submonoid.map (RingEquiv.toMonoidHom h) M) S h.symm - · erw [Submonoid.map_equiv_eq_comap_symm, Submonoid.comap_map_eq_of_injective] - exact h.toEquiv.injective - rw [RingHom.algebraMap_toAlgebra, RingHom.comp_assoc] - simp only [RingHom.comp_id, RingEquiv.symm_symm, RingEquiv.symm_toRingHom_comp_toRingHom] - apply Algebra.algebra_ext - intro r - rw [RingHom.algebraMap_toAlgebra] - end variable (M) -theorem nonZeroDivisors_le_comap [IsLocalization M S] : - nonZeroDivisors R ≤ (nonZeroDivisors S).comap (algebraMap R S) := by - rintro a ha b (e : b * algebraMap R S a = 0) - obtain ⟨x, s, rfl⟩ := mk'_surjective M b - rw [← @mk'_one R _ M, ← mk'_mul, ← (algebraMap R S).map_zero, ← @mk'_one R _ M, - IsLocalization.eq] at e - obtain ⟨c, e⟩ := e - rw [mul_zero, mul_zero, Submonoid.coe_one, one_mul, ← mul_assoc] at e - rw [mk'_eq_zero_iff] - exact ⟨c, ha _ e⟩ - -theorem map_nonZeroDivisors_le [IsLocalization M S] : - (nonZeroDivisors R).map (algebraMap R S) ≤ nonZeroDivisors S := - Submonoid.map_le_iff_le_comap.mpr (nonZeroDivisors_le_comap M S) - /-- If `S₁` is the localization of `R` at `M₁` and `S₂` is the localization of `R` at `M₂`, then every localization `T` of `S₂` at `M₁` is also a localization of `S₁` at `M₂`, in other words `M₁⁻¹M₂⁻¹R` can be identified with `M₂⁻¹M₁⁻¹R`. -/ @@ -876,74 +239,6 @@ namespace Localization open IsLocalization -/-! ### Constructing a localization at a given submonoid -/ - -section - -instance instUniqueLocalization [Subsingleton R] : Unique (Localization M) where - uniq a := by - with_unfolding_all show a = mk 1 1 - exact Localization.induction_on a fun _ => by - congr <;> apply Subsingleton.elim - -theorem add_mk (a b c d) : (mk a b : Localization M) + mk c d = - mk ((b : R) * c + (d : R) * a) (b * d) := by - rw [add_comm (b * c) (d * a), mul_comm b d] - exact OreLocalization.oreDiv_add_oreDiv - -theorem add_mk_self (a b c) : (mk a b : Localization M) + mk c b = mk (a + c) b := by - rw [add_mk, mk_eq_mk_iff, r_eq_r'] - refine (r' M).symm ⟨1, ?_⟩ - simp only [Submonoid.coe_one, Submonoid.coe_mul] - ring - -/-- For any given denominator `b : M`, the map `a ↦ a / b` is an `AddMonoidHom` from `R` to - `Localization M`-/ -@[simps] -def mkAddMonoidHom (b : M) : R →+ Localization M where - toFun a := mk a b - map_zero' := mk_zero _ - map_add' _ _ := (add_mk_self _ _ _).symm - -theorem mk_sum {ι : Type*} (f : ι → R) (s : Finset ι) (b : M) : - mk (∑ i ∈ s, f i) b = ∑ i ∈ s, mk (f i) b := - map_sum (mkAddMonoidHom b) f s - -theorem mk_list_sum (l : List R) (b : M) : mk l.sum b = (l.map fun a => mk a b).sum := - map_list_sum (mkAddMonoidHom b) l - -theorem mk_multiset_sum (l : Multiset R) (b : M) : mk l.sum b = (l.map fun a => mk a b).sum := - (mkAddMonoidHom b).map_multiset_sum l - -instance isLocalization : IsLocalization M (Localization M) where - map_units' := (Localization.monoidOf M).map_units - surj' := (Localization.monoidOf M).surj - exists_of_eq := (Localization.monoidOf M).eq_iff_exists.mp - -end - -@[simp] -theorem toLocalizationMap_eq_monoidOf : toLocalizationMap M (Localization M) = monoidOf M := - rfl - -theorem monoidOf_eq_algebraMap (x) : (monoidOf M).toMap x = algebraMap R (Localization M) x := - rfl - -theorem mk_one_eq_algebraMap (x) : mk x 1 = algebraMap R (Localization M) x := - rfl - -theorem mk_eq_mk'_apply (x y) : mk x y = IsLocalization.mk' (Localization M) x y := by - rw [mk_eq_monoidOf_mk'_apply, mk', toLocalizationMap_eq_monoidOf] - --- Porting note: removed `simp`. Left hand side can be simplified; not clear what normal form should ---be. -theorem mk_eq_mk' : (mk : R → M → Localization M) = IsLocalization.mk' (Localization M) := - mk_eq_monoidOf_mk' - -theorem mk_algebraMap {A : Type*} [CommSemiring A] [Algebra A R] (m : A) : - mk (algebraMap A R m) 1 = algebraMap A (Localization M) m := by - rw [mk_eq_mk', mk'_eq_iff_eq_mul, Submonoid.coe_one, map_one, mul_one]; rfl - theorem mk_natCast (m : ℕ) : (mk m 1 : Localization M) = m := by simpa using mk_algebraMap (R := R) (A := ℕ) _ @@ -954,7 +249,7 @@ variable [IsLocalization M S] section -variable (M) +variable (S) (M) /-- The localization of `R` at `M` as a quotient type is isomorphic to any other localization. -/ @[simps!] @@ -969,11 +264,9 @@ noncomputable def _root_.IsLocalization.unique (R Rₘ) [CommSemiring R] [CommSe end --- Porting note (#10618): removed `simp`, `simp` can prove it nonrec theorem algEquiv_mk' (x : R) (y : M) : algEquiv M S (mk' (Localization M) x y) = mk' S x y := algEquiv_mk' _ _ --- Porting note (#10618): removed `simp`, `simp` can prove it nonrec theorem algEquiv_symm_mk' (x : R) (y : M) : (algEquiv M S).symm (mk' S x y) = mk' (Localization M) x y := algEquiv_symm_mk' _ _ @@ -1002,12 +295,6 @@ variable [Algebra R S] {P : Type*} [CommRing P] namespace Localization -theorem neg_mk (a b) : -(mk a b : Localization M) = mk (-a) b := OreLocalization.neg_def _ _ - -theorem sub_mk (a c) (b d) : (mk a b : Localization M) - mk c d = - mk ((d : R) * a - b * c) (b * d) := by - rw [sub_eq_add_neg, neg_mk, add_mk, add_comm, mul_neg, ← sub_eq_add_neg] - theorem mk_intCast (m : ℤ) : (mk m 1 : Localization M) = m := by simpa using mk_algebraMap (R := R) (A := ℤ) _ @@ -1016,80 +303,6 @@ alias mk_int_cast := mk_intCast end Localization -namespace IsLocalization - -variable {K : Type*} [IsLocalization M S] - -theorem to_map_eq_zero_iff {x : R} (hM : M ≤ nonZeroDivisors R) : algebraMap R S x = 0 ↔ x = 0 := by - rw [← (algebraMap R S).map_zero] - constructor <;> intro h - · cases' (eq_iff_exists M S).mp h with c hc - rw [mul_zero, mul_comm] at hc - exact hM c.2 x hc - · rw [h] - -protected theorem injective (hM : M ≤ nonZeroDivisors R) : Injective (algebraMap R S) := by - rw [injective_iff_map_eq_zero (algebraMap R S)] - intro a ha - rwa [to_map_eq_zero_iff S hM] at ha - -protected theorem to_map_ne_zero_of_mem_nonZeroDivisors [Nontrivial R] (hM : M ≤ nonZeroDivisors R) - {x : R} (hx : x ∈ nonZeroDivisors R) : algebraMap R S x ≠ 0 := - show (algebraMap R S).toMonoidWithZeroHom x ≠ 0 from - map_ne_zero_of_mem_nonZeroDivisors (algebraMap R S) (IsLocalization.injective S hM) hx - -variable {S} - -theorem sec_snd_ne_zero [Nontrivial R] (hM : M ≤ nonZeroDivisors R) (x : S) : - ((sec M x).snd : R) ≠ 0 := - nonZeroDivisors.coe_ne_zero ⟨(sec M x).snd.val, hM (sec M x).snd.property⟩ - -theorem sec_fst_ne_zero [Nontrivial R] [NoZeroDivisors S] (hM : M ≤ nonZeroDivisors R) {x : S} - (hx : x ≠ 0) : (sec M x).fst ≠ 0 := by - have hsec := sec_spec M x - intro hfst - rw [hfst, map_zero, mul_eq_zero, _root_.map_eq_zero_iff] at hsec - · exact Or.elim hsec hx (sec_snd_ne_zero hM x) - · exact IsLocalization.injective S hM - -variable {Q : Type*} [CommRing Q] {g : R →+* P} [Algebra P Q] -variable (A : Type*) [CommRing A] [IsDomain A] - -/-- A `CommRing` `S` which is the localization of a ring `R` without zero divisors at a subset of -non-zero elements does not have zero divisors. -/ -theorem noZeroDivisors_of_le_nonZeroDivisors [Algebra A S] {M : Submonoid A} [IsLocalization M S] - (hM : M ≤ nonZeroDivisors A) : NoZeroDivisors S := - { eq_zero_or_eq_zero_of_mul_eq_zero := by - intro z w h - cases' surj M z with x hx - cases' surj M w with y hy - have : - z * w * algebraMap A S y.2 * algebraMap A S x.2 = algebraMap A S x.1 * algebraMap A S y.1 := - by rw [mul_assoc z, hy, ← hx]; ring - rw [h, zero_mul, zero_mul, ← (algebraMap A S).map_mul] at this - cases' eq_zero_or_eq_zero_of_mul_eq_zero ((to_map_eq_zero_iff S hM).mp this.symm) with H H - · exact Or.inl (eq_zero_of_fst_eq_zero hx H) - · exact Or.inr (eq_zero_of_fst_eq_zero hy H) } - -/-- A `CommRing` `S` which is the localization of an integral domain `R` at a subset of -non-zero elements is an integral domain. -/ -theorem isDomain_of_le_nonZeroDivisors [Algebra A S] {M : Submonoid A} [IsLocalization M S] - (hM : M ≤ nonZeroDivisors A) : IsDomain S := by - apply @NoZeroDivisors.to_isDomain _ _ (id _) (id _) - · exact - ⟨⟨(algebraMap A S) 0, (algebraMap A S) 1, fun h => - zero_ne_one (IsLocalization.injective S hM h)⟩⟩ - · exact noZeroDivisors_of_le_nonZeroDivisors _ hM - -variable {A} - -/-- The localization of an integral domain to a set of non-zero elements is an integral domain. -/ -theorem isDomain_localization {M : Submonoid A} (hM : M ≤ nonZeroDivisors A) : - IsDomain (Localization M) := - isDomain_of_le_nonZeroDivisors _ hM - -end IsLocalization - open IsLocalization /-- If `R` is a field, then localizing at a submonoid not containing `0` adds no new elements. -/ @@ -1101,7 +314,7 @@ theorem IsField.localization_map_bijective {R Rₘ : Type*} [CommRing R] [CommRi refine ⟨IsLocalization.injective _ hM, fun x => ?_⟩ obtain ⟨r, ⟨m, hm⟩, rfl⟩ := mk'_surjective M x obtain ⟨n, hn⟩ := hR.mul_inv_cancel (nonZeroDivisors.ne_zero <| hM hm) - exact ⟨r * n, by erw [eq_mk'_iff_mul_eq, ← map_mul, mul_assoc, _root_.mul_comm n, hn, mul_one]⟩ + exact ⟨r * n, by rw [eq_mk'_iff_mul_eq, ← map_mul, mul_assoc, _root_.mul_comm n, hn, mul_one]⟩ /-- If `R` is a field, then localizing at a submonoid not containing `0` adds no new elements. -/ theorem Field.localization_map_bijective {K Kₘ : Type*} [Field K] [CommRing Kₘ] {M : Submonoid K} diff --git a/Mathlib/RingTheory/Localization/Cardinality.lean b/Mathlib/RingTheory/Localization/Cardinality.lean index bc4e2828f5f1b..e9b4b98bb4e46 100644 --- a/Mathlib/RingTheory/Localization/Cardinality.lean +++ b/Mathlib/RingTheory/Localization/Cardinality.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Eric Rodriguez. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.RingTheory.Artinian /-! @@ -36,7 +36,7 @@ theorem card_le (S : Submonoid R) [IsLocalization S L] : #L ≤ #R := by classical cases fintypeOrInfinite R · exact Cardinal.mk_le_of_surjective (IsArtinianRing.localization_surjective S _) - erw [← Cardinal.mul_eq_self <| Cardinal.aleph0_le_mk R] + rw [← Cardinal.mul_eq_self <| Cardinal.aleph0_le_mk R] set f : R × R → L := fun aa => IsLocalization.mk' _ aa.1 (if h : aa.2 ∈ S then ⟨aa.2, h⟩ else 1) refine @Cardinal.mk_le_of_surjective _ _ f fun a => ?_ obtain ⟨x, y, h⟩ := IsLocalization.mk'_surjective S a @@ -51,3 +51,7 @@ theorem card (S : Submonoid R) [IsLocalization S L] (hS : S ≤ R⁰) : #R = #L (Cardinal.mk_le_of_injective (IsLocalization.injective L hS)).antisymm (card_le S) end IsLocalization + +@[simp] +theorem Cardinal.mk_fractionRing (R : Type u) [CommRing R] : #(FractionRing R) = #R := + IsLocalization.card (FractionRing R) R⁰ le_rfl |>.symm diff --git a/Mathlib/RingTheory/Localization/Defs.lean b/Mathlib/RingTheory/Localization/Defs.lean new file mode 100644 index 0000000000000..3d6a50bf16c29 --- /dev/null +++ b/Mathlib/RingTheory/Localization/Defs.lean @@ -0,0 +1,918 @@ +/- +Copyright (c) 2018 Kenny Lau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen +-/ +import Mathlib.GroupTheory.MonoidLocalization.MonoidWithZero +import Mathlib.RingTheory.OreLocalization.Ring +import Mathlib.Tactic.Ring + +/-! +# Localizations of commutative rings + +We characterize the localization of a commutative ring `R` at a submonoid `M` up to +isomorphism; that is, a commutative ring `S` is the localization of `R` at `M` iff we can find a +ring homomorphism `f : R →+* S` satisfying 3 properties: +1. For all `y ∈ M`, `f y` is a unit; +2. For all `z : S`, there exists `(x, y) : R × M` such that `z * f y = f x`; +3. For all `x, y : R` such that `f x = f y`, there exists `c ∈ M` such that `x * c = y * c`. + (The converse is a consequence of 1.) + +In the following, let `R, P` be commutative rings, `S, Q` be `R`- and `P`-algebras +and `M, T` be submonoids of `R` and `P` respectively, e.g.: +``` +variable (R S P Q : Type*) [CommRing R] [CommRing S] [CommRing P] [CommRing Q] +variable [Algebra R S] [Algebra P Q] (M : Submonoid R) (T : Submonoid P) +``` + +## Main definitions + + * `IsLocalization (M : Submonoid R) (S : Type*)` is a typeclass expressing that `S` is a + localization of `R` at `M`, i.e. the canonical map `algebraMap R S : R →+* S` is a + localization map (satisfying the above properties). + * `IsLocalization.mk' S` is a surjection sending `(x, y) : R × M` to `f x * (f y)⁻¹` + * `IsLocalization.lift` is the ring homomorphism from `S` induced by a homomorphism from `R` + which maps elements of `M` to invertible elements of the codomain. + * `IsLocalization.map S Q` is the ring homomorphism from `S` to `Q` which maps elements + of `M` to elements of `T` + * `IsLocalization.ringEquivOfRingEquiv`: if `R` and `P` are isomorphic by an isomorphism + sending `M` to `T`, then `S` and `Q` are isomorphic + +## Main results + + * `Localization M S`, a construction of the localization as a quotient type, defined in + `GroupTheory.MonoidLocalization`, has `CommRing`, `Algebra R` and `IsLocalization M` + instances if `R` is a ring. `Localization.Away`, `Localization.AtPrime` and `FractionRing` + are abbreviations for `Localization`s and have their corresponding `IsLocalization` instances + +## Implementation notes + +In maths it is natural to reason up to isomorphism, but in Lean we cannot naturally `rewrite` one +structure with an isomorphic one; one way around this is to isolate a predicate characterizing +a structure up to isomorphism, and reason about things that satisfy the predicate. + +A previous version of this file used a fully bundled type of ring localization maps, +then used a type synonym `f.codomain` for `f : LocalizationMap M S` to instantiate the +`R`-algebra structure on `S`. This results in defining ad-hoc copies for everything already +defined on `S`. By making `IsLocalization` a predicate on the `algebraMap R S`, +we can ensure the localization map commutes nicely with other `algebraMap`s. + +To prove most lemmas about a localization map `algebraMap R S` in this file we invoke the +corresponding proof for the underlying `CommMonoid` localization map +`IsLocalization.toLocalizationMap M S`, which can be found in `GroupTheory.MonoidLocalization` +and the namespace `Submonoid.LocalizationMap`. + +To reason about the localization as a quotient type, use `mk_eq_of_mk'` and associated lemmas. +These show the quotient map `mk : R → M → Localization M` equals the surjection +`LocalizationMap.mk'` induced by the map `algebraMap : R →+* Localization M`. +The lemma `mk_eq_of_mk'` hence gives you access to the results in the rest of the file, +which are about the `LocalizationMap.mk'` induced by any localization map. + +The proof that "a `CommRing` `K` which is the localization of an integral domain `R` at `R \ {0}` +is a field" is a `def` rather than an `instance`, so if you want to reason about a field of +fractions `K`, assume `[Field K]` instead of just `[CommRing K]`. + +## Tags +localization, ring localization, commutative ring localization, characteristic predicate, +commutative ring, field of fractions +-/ + +assert_not_exists AlgHom +assert_not_exists Ideal + +open Function + +section CommSemiring + +variable {R : Type*} [CommSemiring R] (M : Submonoid R) (S : Type*) [CommSemiring S] +variable [Algebra R S] {P : Type*} [CommSemiring P] + +/-- The typeclass `IsLocalization (M : Submonoid R) S` where `S` is an `R`-algebra +expresses that `S` is isomorphic to the localization of `R` at `M`. -/ +@[mk_iff] class IsLocalization : Prop where + -- Porting note: add ' to fields, and made new versions of these with either `S` or `M` explicit. + /-- Everything in the image of `algebraMap` is a unit -/ + map_units' : ∀ y : M, IsUnit (algebraMap R S y) + /-- The `algebraMap` is surjective -/ + surj' : ∀ z : S, ∃ x : R × M, z * algebraMap R S x.2 = algebraMap R S x.1 + /-- The kernel of `algebraMap` is contained in the annihilator of `M`; + it is then equal to the annihilator by `map_units'` -/ + exists_of_eq : ∀ {x y}, algebraMap R S x = algebraMap R S y → ∃ c : M, ↑c * x = ↑c * y + +variable {M} + +namespace IsLocalization + +section IsLocalization + +variable [IsLocalization M S] + +section + +@[inherit_doc IsLocalization.map_units'] +theorem map_units : ∀ y : M, IsUnit (algebraMap R S y) := + IsLocalization.map_units' + +variable (M) {S} +@[inherit_doc IsLocalization.surj'] +theorem surj : ∀ z : S, ∃ x : R × M, z * algebraMap R S x.2 = algebraMap R S x.1 := + IsLocalization.surj' + +variable (S) +@[inherit_doc IsLocalization.exists_of_eq] +theorem eq_iff_exists {x y} : algebraMap R S x = algebraMap R S y ↔ ∃ c : M, ↑c * x = ↑c * y := + Iff.intro IsLocalization.exists_of_eq fun ⟨c, h⟩ ↦ by + apply_fun algebraMap R S at h + rw [map_mul, map_mul] at h + exact (IsLocalization.map_units S c).mul_right_inj.mp h + +variable {S} +theorem of_le (N : Submonoid R) (h₁ : M ≤ N) (h₂ : ∀ r ∈ N, IsUnit (algebraMap R S r)) : + IsLocalization N S where + map_units' r := h₂ r r.2 + surj' s := + have ⟨⟨x, y, hy⟩, H⟩ := IsLocalization.surj M s + ⟨⟨x, y, h₁ hy⟩, H⟩ + exists_of_eq {x y} := by + rw [IsLocalization.eq_iff_exists M] + rintro ⟨c, hc⟩ + exact ⟨⟨c, h₁ c.2⟩, hc⟩ + +variable (S) + +/-- `IsLocalization.toLocalizationWithZeroMap M S` shows `S` is the monoid localization of +`R` at `M`. -/ +@[simps] +def toLocalizationWithZeroMap : Submonoid.LocalizationWithZeroMap M S where + __ := algebraMap R S + toFun := algebraMap R S + map_units' := IsLocalization.map_units _ + surj' := IsLocalization.surj _ + exists_of_eq _ _ := IsLocalization.exists_of_eq + +/-- `IsLocalization.toLocalizationMap M S` shows `S` is the monoid localization of `R` at `M`. -/ +abbrev toLocalizationMap : Submonoid.LocalizationMap M S := + (toLocalizationWithZeroMap M S).toLocalizationMap + +@[simp] +theorem toLocalizationMap_toMap : (toLocalizationMap M S).toMap = (algebraMap R S : R →*₀ S) := + rfl + +theorem toLocalizationMap_toMap_apply (x) : (toLocalizationMap M S).toMap x = algebraMap R S x := + rfl + +theorem surj₂ : ∀ z w : S, ∃ z' w' : R, ∃ d : M, + (z * algebraMap R S d = algebraMap R S z') ∧ (w * algebraMap R S d = algebraMap R S w') := + (toLocalizationMap M S).surj₂ + +end + +variable (M) {S} + +/-- Given a localization map `f : M →* N`, a section function sending `z : N` to some +`(x, y) : M × S` such that `f x * (f y)⁻¹ = z`. -/ +noncomputable def sec (z : S) : R × M := + Classical.choose <| IsLocalization.surj _ z + +@[simp] +theorem toLocalizationMap_sec : (toLocalizationMap M S).sec = sec M := + rfl + +/-- Given `z : S`, `IsLocalization.sec M z` is defined to be a pair `(x, y) : R × M` such +that `z * f y = f x` (so this lemma is true by definition). -/ +theorem sec_spec (z : S) : + z * algebraMap R S (IsLocalization.sec M z).2 = algebraMap R S (IsLocalization.sec M z).1 := + Classical.choose_spec <| IsLocalization.surj _ z + +/-- Given `z : S`, `IsLocalization.sec M z` is defined to be a pair `(x, y) : R × M` such +that `z * f y = f x`, so this lemma is just an application of `S`'s commutativity. -/ +theorem sec_spec' (z : S) : + algebraMap R S (IsLocalization.sec M z).1 = algebraMap R S (IsLocalization.sec M z).2 * z := by + rw [mul_comm, sec_spec] + +variable {M} + +/-- If `M` contains `0` then the localization at `M` is trivial. -/ +theorem subsingleton (h : 0 ∈ M) : Subsingleton S := (toLocalizationMap M S).subsingleton h + +theorem map_right_cancel {x y} {c : M} (h : algebraMap R S (c * x) = algebraMap R S (c * y)) : + algebraMap R S x = algebraMap R S y := + (toLocalizationMap M S).map_right_cancel h + +theorem map_left_cancel {x y} {c : M} (h : algebraMap R S (x * c) = algebraMap R S (y * c)) : + algebraMap R S x = algebraMap R S y := + (toLocalizationMap M S).map_left_cancel h + +theorem eq_zero_of_fst_eq_zero {z x} {y : M} (h : z * algebraMap R S y = algebraMap R S x) + (hx : x = 0) : z = 0 := by + rw [hx, (algebraMap R S).map_zero] at h + exact (IsUnit.mul_left_eq_zero (IsLocalization.map_units S y)).1 h + +variable (M S) + +theorem map_eq_zero_iff (r : R) : algebraMap R S r = 0 ↔ ∃ m : M, ↑m * r = 0 := by + constructor + · intro h + obtain ⟨m, hm⟩ := (IsLocalization.eq_iff_exists M S).mp ((algebraMap R S).map_zero.trans h.symm) + exact ⟨m, by simpa using hm.symm⟩ + · rintro ⟨m, hm⟩ + rw [← (IsLocalization.map_units S m).mul_right_inj, mul_zero, ← RingHom.map_mul, hm, + RingHom.map_zero] + +variable {M} + +/-- `IsLocalization.mk' S` is the surjection sending `(x, y) : R × M` to +`f x * (f y)⁻¹`. -/ +noncomputable def mk' (x : R) (y : M) : S := + (toLocalizationMap M S).mk' x y + +@[simp] +theorem mk'_sec (z : S) : mk' S (IsLocalization.sec M z).1 (IsLocalization.sec M z).2 = z := + (toLocalizationMap M S).mk'_sec _ + +theorem mk'_mul (x₁ x₂ : R) (y₁ y₂ : M) : mk' S (x₁ * x₂) (y₁ * y₂) = mk' S x₁ y₁ * mk' S x₂ y₂ := + (toLocalizationMap M S).mk'_mul _ _ _ _ + +theorem mk'_one (x) : mk' S x (1 : M) = algebraMap R S x := + (toLocalizationMap M S).mk'_one _ + +@[simp] +theorem mk'_spec (x) (y : M) : mk' S x y * algebraMap R S y = algebraMap R S x := + (toLocalizationMap M S).mk'_spec _ _ + +@[simp] +theorem mk'_spec' (x) (y : M) : algebraMap R S y * mk' S x y = algebraMap R S x := + (toLocalizationMap M S).mk'_spec' _ _ + +@[simp] +theorem mk'_spec_mk (x) (y : R) (hy : y ∈ M) : + mk' S x ⟨y, hy⟩ * algebraMap R S y = algebraMap R S x := + mk'_spec S x ⟨y, hy⟩ + +@[simp] +theorem mk'_spec'_mk (x) (y : R) (hy : y ∈ M) : + algebraMap R S y * mk' S x ⟨y, hy⟩ = algebraMap R S x := + mk'_spec' S x ⟨y, hy⟩ + +variable {S} + +theorem eq_mk'_iff_mul_eq {x} {y : M} {z} : + z = mk' S x y ↔ z * algebraMap R S y = algebraMap R S x := + (toLocalizationMap M S).eq_mk'_iff_mul_eq + +theorem eq_mk'_of_mul_eq {x : R} {y : M} {z : R} (h : z * y = x) : (algebraMap R S) z = mk' S x y := + eq_mk'_iff_mul_eq.mpr (by rw [← h, map_mul]) + +theorem mk'_eq_iff_eq_mul {x} {y : M} {z} : + mk' S x y = z ↔ algebraMap R S x = z * algebraMap R S y := + (toLocalizationMap M S).mk'_eq_iff_eq_mul + +theorem mk'_add_eq_iff_add_mul_eq_mul {x} {y : M} {z₁ z₂} : + mk' S x y + z₁ = z₂ ↔ algebraMap R S x + z₁ * algebraMap R S y = z₂ * algebraMap R S y := by + rw [← mk'_spec S x y, ← IsUnit.mul_left_inj (IsLocalization.map_units S y), right_distrib] + +theorem mk'_pow (x : R) (y : M) (n : ℕ) : mk' S (x ^ n) (y ^ n) = mk' S x y ^ n := by + simp_rw [IsLocalization.mk'_eq_iff_eq_mul, SubmonoidClass.coe_pow, map_pow, ← mul_pow] + simp + +variable (M) + +theorem mk'_surjective (z : S) : ∃ (x : _) (y : M), mk' S x y = z := + let ⟨r, hr⟩ := IsLocalization.surj _ z + ⟨r.1, r.2, (eq_mk'_iff_mul_eq.2 hr).symm⟩ + +variable (S) + +/-- The localization of a `Fintype` is a `Fintype`. Cannot be an instance. -/ +noncomputable def fintype' [Fintype R] : Fintype S := + have := Classical.propDecidable + Fintype.ofSurjective (Function.uncurry <| IsLocalization.mk' S) fun a => + Prod.exists'.mpr <| IsLocalization.mk'_surjective M a + +variable {M S} + +/-- Localizing at a submonoid with 0 inside it leads to the trivial ring. -/ +def uniqueOfZeroMem (h : (0 : R) ∈ M) : Unique S := + uniqueOfZeroEqOne <| by simpa using IsLocalization.map_units S ⟨0, h⟩ + +theorem mk'_eq_iff_eq {x₁ x₂} {y₁ y₂ : M} : + mk' S x₁ y₁ = mk' S x₂ y₂ ↔ algebraMap R S (y₂ * x₁) = algebraMap R S (y₁ * x₂) := + (toLocalizationMap M S).mk'_eq_iff_eq + +theorem mk'_eq_iff_eq' {x₁ x₂} {y₁ y₂ : M} : + mk' S x₁ y₁ = mk' S x₂ y₂ ↔ algebraMap R S (x₁ * y₂) = algebraMap R S (x₂ * y₁) := + (toLocalizationMap M S).mk'_eq_iff_eq' + +protected theorem eq {a₁ b₁} {a₂ b₂ : M} : + mk' S a₁ a₂ = mk' S b₁ b₂ ↔ ∃ c : M, ↑c * (↑b₂ * a₁) = c * (a₂ * b₁) := + (toLocalizationMap M S).eq + +theorem mk'_eq_zero_iff (x : R) (s : M) : mk' S x s = 0 ↔ ∃ m : M, ↑m * x = 0 := by + rw [← (map_units S s).mul_left_inj, mk'_spec, zero_mul, map_eq_zero_iff M] + +@[simp] +theorem mk'_zero (s : M) : IsLocalization.mk' S 0 s = 0 := by + rw [eq_comm, IsLocalization.eq_mk'_iff_mul_eq, zero_mul, map_zero] + +theorem ne_zero_of_mk'_ne_zero {x : R} {y : M} (hxy : IsLocalization.mk' S x y ≠ 0) : x ≠ 0 := by + rintro rfl + exact hxy (IsLocalization.mk'_zero _) + +section Ext + +theorem eq_iff_eq [Algebra R P] [IsLocalization M P] {x y} : + algebraMap R S x = algebraMap R S y ↔ algebraMap R P x = algebraMap R P y := + (toLocalizationMap M S).eq_iff_eq (toLocalizationMap M P) + +theorem mk'_eq_iff_mk'_eq [Algebra R P] [IsLocalization M P] {x₁ x₂} {y₁ y₂ : M} : + mk' S x₁ y₁ = mk' S x₂ y₂ ↔ mk' P x₁ y₁ = mk' P x₂ y₂ := + (toLocalizationMap M S).mk'_eq_iff_mk'_eq (toLocalizationMap M P) + +theorem mk'_eq_of_eq {a₁ b₁ : R} {a₂ b₂ : M} (H : ↑a₂ * b₁ = ↑b₂ * a₁) : + mk' S a₁ a₂ = mk' S b₁ b₂ := + (toLocalizationMap M S).mk'_eq_of_eq H + +theorem mk'_eq_of_eq' {a₁ b₁ : R} {a₂ b₂ : M} (H : b₁ * ↑a₂ = a₁ * ↑b₂) : + mk' S a₁ a₂ = mk' S b₁ b₂ := + (toLocalizationMap M S).mk'_eq_of_eq' H + +theorem mk'_cancel (a : R) (b c : M) : + mk' S (a * c) (b * c) = mk' S a b := (toLocalizationMap M S).mk'_cancel _ _ _ + +variable (S) + +@[simp] +theorem mk'_self {x : R} (hx : x ∈ M) : mk' S x ⟨x, hx⟩ = 1 := + (toLocalizationMap M S).mk'_self _ hx + +@[simp] +theorem mk'_self' {x : M} : mk' S (x : R) x = 1 := + (toLocalizationMap M S).mk'_self' _ + +theorem mk'_self'' {x : M} : mk' S x.1 x = 1 := + mk'_self' _ + +end Ext + +theorem mul_mk'_eq_mk'_of_mul (x y : R) (z : M) : + (algebraMap R S) x * mk' S y z = mk' S (x * y) z := + (toLocalizationMap M S).mul_mk'_eq_mk'_of_mul _ _ _ + +theorem mk'_eq_mul_mk'_one (x : R) (y : M) : mk' S x y = (algebraMap R S) x * mk' S 1 y := + ((toLocalizationMap M S).mul_mk'_one_eq_mk' _ _).symm + +@[simp] +theorem mk'_mul_cancel_left (x : R) (y : M) : mk' S (y * x : R) y = (algebraMap R S) x := + (toLocalizationMap M S).mk'_mul_cancel_left _ _ + +theorem mk'_mul_cancel_right (x : R) (y : M) : mk' S (x * y) y = (algebraMap R S) x := + (toLocalizationMap M S).mk'_mul_cancel_right _ _ + +@[simp] +theorem mk'_mul_mk'_eq_one (x y : M) : mk' S (x : R) y * mk' S (y : R) x = 1 := by + rw [← mk'_mul, mul_comm]; exact mk'_self _ _ + +theorem mk'_mul_mk'_eq_one' (x : R) (y : M) (h : x ∈ M) : mk' S x y * mk' S (y : R) ⟨x, h⟩ = 1 := + mk'_mul_mk'_eq_one ⟨x, h⟩ _ + +theorem smul_mk' (x y : R) (m : M) : x • mk' S y m = mk' S (x * y) m := by + nth_rw 2 [← one_mul m] + rw [mk'_mul, mk'_one, Algebra.smul_def] + +@[simp] theorem smul_mk'_one (x : R) (m : M) : x • mk' S 1 m = mk' S x m := by + rw [smul_mk', mul_one] + +@[simp] lemma smul_mk'_self {m : M} {r : R} : + (m : R) • mk' S r m = algebraMap R S r := by + rw [smul_mk', mk'_mul_cancel_left] + +@[simps] +instance invertible_mk'_one (s : M) : Invertible (IsLocalization.mk' S (1 : R) s) where + invOf := algebraMap R S s + invOf_mul_self := by simp + mul_invOf_self := by simp + +section + +variable (M) + +theorem isUnit_comp (j : S →+* P) (y : M) : IsUnit (j.comp (algebraMap R S) y) := + (toLocalizationMap M S).isUnit_comp j.toMonoidHom _ + +end + +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s +`g : R →+* P` such that `g(M) ⊆ Units P`, `f x = f y → g x = g y` for all `x y : R`. -/ +theorem eq_of_eq {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) {x y} + (h : (algebraMap R S) x = (algebraMap R S) y) : g x = g y := + Submonoid.LocalizationMap.eq_of_eq (toLocalizationMap M S) (g := g.toMonoidHom) hg h + +theorem mk'_add (x₁ x₂ : R) (y₁ y₂ : M) : + mk' S (x₁ * y₂ + x₂ * y₁) (y₁ * y₂) = mk' S x₁ y₁ + mk' S x₂ y₂ := + mk'_eq_iff_eq_mul.2 <| + Eq.symm + (by + rw [mul_comm (_ + _), mul_add, mul_mk'_eq_mk'_of_mul, mk'_add_eq_iff_add_mul_eq_mul, + mul_comm (_ * _), ← mul_assoc, add_comm, ← map_mul, mul_mk'_eq_mk'_of_mul, + mk'_add_eq_iff_add_mul_eq_mul] + simp only [map_add, Submonoid.coe_mul, map_mul] + ring) + +theorem mul_add_inv_left {g : R →+* P} (h : ∀ y : M, IsUnit (g y)) (y : M) (w z₁ z₂ : P) : + w * ↑(IsUnit.liftRight (g.toMonoidHom.restrict M) h y)⁻¹ + z₁ = + z₂ ↔ w + g y * z₁ = g y * z₂ := by + rw [mul_comm, ← one_mul z₁, ← Units.inv_mul (IsUnit.liftRight (g.toMonoidHom.restrict M) h y), + mul_assoc, ← mul_add, Units.inv_mul_eq_iff_eq_mul, Units.inv_mul_cancel_left, + IsUnit.coe_liftRight] + simp [RingHom.toMonoidHom_eq_coe, MonoidHom.restrict_apply] + +theorem lift_spec_mul_add {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) (z w w' v) : + ((toLocalizationWithZeroMap M S).lift g.toMonoidWithZeroHom hg) z * w + w' = v ↔ + g ((toLocalizationMap M S).sec z).1 * w + g ((toLocalizationMap M S).sec z).2 * w' = + g ((toLocalizationMap M S).sec z).2 * v := by + erw [mul_comm, ← mul_assoc, mul_add_inv_left hg, mul_comm] + rfl + +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s +`g : R →+* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from +`S` to `P` sending `z : S` to `g x * (g y)⁻¹`, where `(x, y) : R × M` are such that +`z = f x * (f y)⁻¹`. -/ +noncomputable def lift {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) : S →+* P := + { Submonoid.LocalizationWithZeroMap.lift (toLocalizationWithZeroMap M S) + g.toMonoidWithZeroHom hg with + map_add' := by + intro x y + erw [(toLocalizationMap M S).lift_spec, mul_add, mul_comm, eq_comm, lift_spec_mul_add, + add_comm, mul_comm, mul_assoc, mul_comm, mul_assoc, lift_spec_mul_add] + simp_rw [← mul_assoc] + show g _ * g _ * g _ + g _ * g _ * g _ = g _ * g _ * g _ + simp_rw [← map_mul g, ← map_add g] + apply eq_of_eq (S := S) hg + simp only [sec_spec', toLocalizationMap_sec, map_add, map_mul] + ring } + +variable {g : R →+* P} (hg : ∀ y : M, IsUnit (g y)) + +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `CommSemiring`s +`g : R →* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from +`S` to `P` maps `f x * (f y)⁻¹` to `g x * (g y)⁻¹` for all `x : R, y ∈ M`. -/ +theorem lift_mk' (x y) : + lift hg (mk' S x y) = g x * ↑(IsUnit.liftRight (g.toMonoidHom.restrict M) hg y)⁻¹ := + (toLocalizationMap M S).lift_mk' _ _ _ + +theorem lift_mk'_spec (x v) (y : M) : lift hg (mk' S x y) = v ↔ g x = g y * v := + (toLocalizationMap M S).lift_mk'_spec _ _ _ _ + +@[simp] +theorem lift_eq (x : R) : lift hg ((algebraMap R S) x) = g x := + (toLocalizationMap M S).lift_eq _ _ + +theorem lift_eq_iff {x y : R × M} : + lift hg (mk' S x.1 x.2) = lift hg (mk' S y.1 y.2) ↔ g (x.1 * y.2) = g (y.1 * x.2) := + (toLocalizationMap M S).lift_eq_iff _ + +@[simp] +theorem lift_comp : (lift hg).comp (algebraMap R S) = g := + RingHom.ext <| (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| (toLocalizationMap M S).lift_comp _ + +@[simp] +theorem lift_of_comp (j : S →+* P) : lift (isUnit_comp M j) = j := + RingHom.ext <| (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| + (toLocalizationMap M S).lift_of_comp j.toMonoidHom + +variable (M) + +section +include M + +/-- See note [partially-applied ext lemmas] -/ +theorem monoidHom_ext ⦃j k : S →* P⦄ + (h : j.comp (algebraMap R S : R →* S) = k.comp (algebraMap R S)) : j = k := + Submonoid.LocalizationMap.epic_of_localizationMap (toLocalizationMap M S) <| DFunLike.congr_fun h + +/-- See note [partially-applied ext lemmas] -/ +theorem ringHom_ext ⦃j k : S →+* P⦄ (h : j.comp (algebraMap R S) = k.comp (algebraMap R S)) : + j = k := + RingHom.coe_monoidHom_injective <| monoidHom_ext M <| MonoidHom.ext <| RingHom.congr_fun h + +/-- To show `j` and `k` agree on the whole localization, it suffices to show they agree +on the image of the base ring, if they preserve `1` and `*`. -/ +protected theorem ext (j k : S → P) (hj1 : j 1 = 1) (hk1 : k 1 = 1) + (hjm : ∀ a b, j (a * b) = j a * j b) (hkm : ∀ a b, k (a * b) = k a * k b) + (h : ∀ a, j (algebraMap R S a) = k (algebraMap R S a)) : j = k := + let j' : MonoidHom S P := + { toFun := j, map_one' := hj1, map_mul' := hjm } + let k' : MonoidHom S P := + { toFun := k, map_one' := hk1, map_mul' := hkm } + have : j' = k' := monoidHom_ext M (MonoidHom.ext h) + show j'.toFun = k'.toFun by rw [this] +end + +variable {M} + +theorem lift_unique {j : S →+* P} (hj : ∀ x, j ((algebraMap R S) x) = g x) : lift hg = j := + RingHom.ext <| + (DFunLike.ext_iff (F := MonoidHom _ _)).1 <| + Submonoid.LocalizationMap.lift_unique (toLocalizationMap M S) (g := g.toMonoidHom) hg + (j := j.toMonoidHom) hj + +@[simp] +theorem lift_id (x) : lift (map_units S : ∀ _ : M, IsUnit _) x = x := + (toLocalizationMap M S).lift_id _ + +theorem lift_surjective_iff : + Surjective (lift hg : S → P) ↔ ∀ v : P, ∃ x : R × M, v * g x.2 = g x.1 := + (toLocalizationMap M S).lift_surjective_iff hg + +theorem lift_injective_iff : + Injective (lift hg : S → P) ↔ ∀ x y, algebraMap R S x = algebraMap R S y ↔ g x = g y := + (toLocalizationMap M S).lift_injective_iff hg + +variable (M) in +include M in +lemma injective_iff_map_algebraMap_eq {T} [CommRing T] (f : S →+* T) : + Function.Injective f ↔ ∀ x y, + algebraMap R S x = algebraMap R S y ↔ f (algebraMap R S x) = f (algebraMap R S y) := by + rw [← IsLocalization.lift_of_comp (M := M) f, IsLocalization.lift_injective_iff] + simp + +section Map + +variable {T : Submonoid P} {Q : Type*} [CommSemiring Q] +variable [Algebra P Q] [IsLocalization T Q] + +section + +variable (Q) + +/-- Map a homomorphism `g : R →+* P` to `S →+* Q`, where `S` and `Q` are +localizations of `R` and `P` at `M` and `T` respectively, +such that `g(M) ⊆ T`. + +We send `z : S` to `algebraMap P Q (g x) * (algebraMap P Q (g y))⁻¹`, where +`(x, y) : R × M` are such that `z = f x * (f y)⁻¹`. -/ +noncomputable def map (g : R →+* P) (hy : M ≤ T.comap g) : S →+* Q := + lift (M := M) (g := (algebraMap P Q).comp g) fun y => map_units _ ⟨g y, hy y.2⟩ + +end + +section +variable (hy : M ≤ T.comap g) +include hy + +-- Porting note: added `simp` attribute, since it proves very similar lemmas marked `simp` +@[simp] +theorem map_eq (x) : map Q g hy ((algebraMap R S) x) = algebraMap P Q (g x) := + lift_eq (fun y => map_units _ ⟨g y, hy y.2⟩) x + +@[simp] +theorem map_comp : (map Q g hy).comp (algebraMap R S) = (algebraMap P Q).comp g := + lift_comp fun y => map_units _ ⟨g y, hy y.2⟩ + +theorem map_mk' (x) (y : M) : map Q g hy (mk' S x y) = mk' Q (g x) ⟨g y, hy y.2⟩ := + Submonoid.LocalizationMap.map_mk' (toLocalizationMap M S) (g := g.toMonoidHom) + (fun y => hy y.2) (k := toLocalizationMap T Q) .. + +theorem map_unique (j : S →+* Q) (hj : ∀ x : R, j (algebraMap R S x) = algebraMap P Q (g x)) : + map Q g hy = j := + lift_unique (fun y => map_units _ ⟨g y, hy y.2⟩) hj + +/-- If `CommSemiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition +of the induced maps equals the map of localizations induced by `l ∘ g`. -/ +theorem map_comp_map {A : Type*} [CommSemiring A] {U : Submonoid A} {W} [CommSemiring W] + [Algebra A W] [IsLocalization U W] {l : P →+* A} (hl : T ≤ U.comap l) : + (map W l hl).comp (map Q g hy : S →+* _) = map W (l.comp g) fun _ hx => hl (hy hx) := + RingHom.ext fun x => + Submonoid.LocalizationMap.map_map (P := P) (toLocalizationMap M S) (fun y => hy y.2) + (toLocalizationMap U W) (fun w => hl w.2) x + +/-- If `CommSemiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition +of the induced maps equals the map of localizations induced by `l ∘ g`. -/ +theorem map_map {A : Type*} [CommSemiring A] {U : Submonoid A} {W} [CommSemiring W] [Algebra A W] + [IsLocalization U W] {l : P →+* A} (hl : T ≤ U.comap l) (x : S) : + map W l hl (map Q g hy x) = map W (l.comp g) (fun _ hx => hl (hy hx)) x := by + rw [← map_comp_map (Q := Q) hy hl]; rfl + +theorem map_smul (x : S) (z : R) : map Q g hy (z • x : S) = g z • map Q g hy x := by + rw [Algebra.smul_def, Algebra.smul_def, RingHom.map_mul, map_eq] + +end + +@[simp] +theorem map_id_mk' {Q : Type*} [CommSemiring Q] [Algebra R Q] [IsLocalization M Q] (x) (y : M) : + map Q (RingHom.id R) (le_refl M) (mk' S x y) = mk' Q x y := + map_mk' .. + +@[simp] +theorem map_id (z : S) (h : M ≤ M.comap (RingHom.id R) := le_refl M) : + map S (RingHom.id _) h z = z := + lift_id _ + +section + +variable (S Q) + +/-- If `S`, `Q` are localizations of `R` and `P` at submonoids `M, T` respectively, an +isomorphism `j : R ≃+* P` such that `j(M) = T` induces an isomorphism of localizations +`S ≃+* Q`. -/ +@[simps] +noncomputable def ringEquivOfRingEquiv (h : R ≃+* P) (H : M.map h.toMonoidHom = T) : S ≃+* Q := + have H' : T.map h.symm.toMonoidHom = M := by + rw [← M.map_id, ← H, Submonoid.map_map] + congr + ext + apply h.symm_apply_apply + { map Q (h : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) with + toFun := map Q (h : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) + invFun := map S (h.symm : P →+* R) (T.le_comap_of_map_le (le_of_eq H')) + left_inv := fun x => by + rw [map_map, map_unique _ (RingHom.id _), RingHom.id_apply] + simp + right_inv := fun x => by + rw [map_map, map_unique _ (RingHom.id _), RingHom.id_apply] + simp } + +end + +theorem ringEquivOfRingEquiv_eq_map {j : R ≃+* P} (H : M.map j.toMonoidHom = T) : + (ringEquivOfRingEquiv S Q j H : S →+* Q) = + map Q (j : R →+* P) (M.le_comap_of_map_le (le_of_eq H)) := + rfl + +theorem ringEquivOfRingEquiv_eq {j : R ≃+* P} (H : M.map j.toMonoidHom = T) (x) : + ringEquivOfRingEquiv S Q j H ((algebraMap R S) x) = algebraMap P Q (j x) := by + simp + +theorem ringEquivOfRingEquiv_mk' {j : R ≃+* P} (H : M.map j.toMonoidHom = T) (x : R) (y : M) : + ringEquivOfRingEquiv S Q j H (mk' S x y) = + mk' Q (j x) ⟨j y, show j y ∈ T from H ▸ Set.mem_image_of_mem j y.2⟩ := by + simp [map_mk'] + +end Map + +section at_units +lemma at_units (S : Submonoid R) + (hS : S ≤ IsUnit.submonoid R) : IsLocalization S R where + map_units' y := hS y.prop + surj' := fun s ↦ ⟨⟨s, 1⟩, by simp⟩ + exists_of_eq := fun {x y} (e : x = y) ↦ ⟨1, e ▸ rfl⟩ + +end at_units + +section + +variable (M S) (Q : Type*) [CommSemiring Q] [Algebra P Q] + +/-- Injectivity of a map descends to the map induced on localizations. -/ +theorem map_injective_of_injective (h : Function.Injective g) [IsLocalization (M.map g) Q] : + Function.Injective (map Q g M.le_comap_map : S → Q) := + (toLocalizationMap M S).map_injective_of_injective h (toLocalizationMap (M.map g) Q) + +/-- Surjectivity of a map descends to the map induced on localizations. -/ +theorem map_surjective_of_surjective (h : Function.Surjective g) [IsLocalization (M.map g) Q] : + Function.Surjective (map Q g M.le_comap_map : S → Q) := + (toLocalizationMap M S).map_surjective_of_surjective h (toLocalizationMap (M.map g) Q) + +end + +end IsLocalization + +section + +variable (M) + +theorem isLocalization_of_base_ringEquiv [IsLocalization M S] (h : R ≃+* P) : + haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra + IsLocalization (M.map h.toMonoidHom) S := by + letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra + constructor + · rintro ⟨_, ⟨y, hy, rfl⟩⟩ + convert IsLocalization.map_units S ⟨y, hy⟩ + dsimp only [RingHom.algebraMap_toAlgebra, RingHom.comp_apply] + exact congr_arg _ (h.symm_apply_apply _) + · intro y + obtain ⟨⟨x, s⟩, e⟩ := IsLocalization.surj M y + refine ⟨⟨h x, _, _, s.prop, rfl⟩, ?_⟩ + dsimp only [RingHom.algebraMap_toAlgebra, RingHom.comp_apply] at e ⊢ + convert e <;> exact h.symm_apply_apply _ + · intro x y + rw [RingHom.algebraMap_toAlgebra, RingHom.comp_apply, RingHom.comp_apply, + IsLocalization.eq_iff_exists M S] + simp_rw [← h.toEquiv.apply_eq_iff_eq] + change (∃ c : M, h (c * h.symm x) = h (c * h.symm y)) → _ + simp only [RingEquiv.apply_symm_apply, RingEquiv.map_mul] + exact fun ⟨c, e⟩ ↦ ⟨⟨_, _, c.prop, rfl⟩, e⟩ + +theorem isLocalization_iff_of_base_ringEquiv (h : R ≃+* P) : + IsLocalization M S ↔ + haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra + IsLocalization (M.map h.toMonoidHom) S := by + letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra + refine ⟨fun _ => isLocalization_of_base_ringEquiv M S h, ?_⟩ + intro H + convert isLocalization_of_base_ringEquiv (Submonoid.map (RingEquiv.toMonoidHom h) M) S h.symm + · erw [Submonoid.map_equiv_eq_comap_symm, Submonoid.comap_map_eq_of_injective] + exact h.toEquiv.injective + rw [RingHom.algebraMap_toAlgebra, RingHom.comp_assoc] + simp only [RingHom.comp_id, RingEquiv.symm_symm, RingEquiv.symm_toRingHom_comp_toRingHom] + apply Algebra.algebra_ext + intro r + rw [RingHom.algebraMap_toAlgebra] + +end + +variable (M) + +theorem nonZeroDivisors_le_comap [IsLocalization M S] : + nonZeroDivisors R ≤ (nonZeroDivisors S).comap (algebraMap R S) := by + rintro a ha b (e : b * algebraMap R S a = 0) + obtain ⟨x, s, rfl⟩ := mk'_surjective M b + rw [← @mk'_one R _ M, ← mk'_mul, ← (algebraMap R S).map_zero, ← @mk'_one R _ M, + IsLocalization.eq] at e + obtain ⟨c, e⟩ := e + rw [mul_zero, mul_zero, Submonoid.coe_one, one_mul, ← mul_assoc] at e + rw [mk'_eq_zero_iff] + exact ⟨c, ha _ e⟩ + +theorem map_nonZeroDivisors_le [IsLocalization M S] : + (nonZeroDivisors R).map (algebraMap R S) ≤ nonZeroDivisors S := + Submonoid.map_le_iff_le_comap.mpr (nonZeroDivisors_le_comap M S) + +end IsLocalization + +namespace Localization + +open IsLocalization + +/-! ### Constructing a localization at a given submonoid -/ + +section + +instance instUniqueLocalization [Subsingleton R] : Unique (Localization M) where + uniq a := by + with_unfolding_all show a = mk 1 1 + exact Localization.induction_on a fun _ => by + congr <;> apply Subsingleton.elim + +theorem add_mk (a b c d) : (mk a b : Localization M) + mk c d = + mk ((b : R) * c + (d : R) * a) (b * d) := by + rw [add_comm (b * c) (d * a), mul_comm b d] + exact OreLocalization.oreDiv_add_oreDiv + +theorem add_mk_self (a b c) : (mk a b : Localization M) + mk c b = mk (a + c) b := by + rw [add_mk, mk_eq_mk_iff, r_eq_r'] + refine (r' M).symm ⟨1, ?_⟩ + simp only [Submonoid.coe_one, Submonoid.coe_mul] + ring + +/-- For any given denominator `b : M`, the map `a ↦ a / b` is an `AddMonoidHom` from `R` to + `Localization M`-/ +@[simps] +def mkAddMonoidHom (b : M) : R →+ Localization M where + toFun a := mk a b + map_zero' := mk_zero _ + map_add' _ _ := (add_mk_self _ _ _).symm + +theorem mk_sum {ι : Type*} (f : ι → R) (s : Finset ι) (b : M) : + mk (∑ i ∈ s, f i) b = ∑ i ∈ s, mk (f i) b := + map_sum (mkAddMonoidHom b) f s + +theorem mk_list_sum (l : List R) (b : M) : mk l.sum b = (l.map fun a => mk a b).sum := + map_list_sum (mkAddMonoidHom b) l + +theorem mk_multiset_sum (l : Multiset R) (b : M) : mk l.sum b = (l.map fun a => mk a b).sum := + (mkAddMonoidHom b).map_multiset_sum l + +instance isLocalization : IsLocalization M (Localization M) where + map_units' := (Localization.monoidOf M).map_units + surj' := (Localization.monoidOf M).surj + exists_of_eq := (Localization.monoidOf M).eq_iff_exists.mp + +end + +@[simp] +theorem toLocalizationMap_eq_monoidOf : toLocalizationMap M (Localization M) = monoidOf M := + rfl + +theorem monoidOf_eq_algebraMap (x) : (monoidOf M).toMap x = algebraMap R (Localization M) x := + rfl + +theorem mk_one_eq_algebraMap (x) : mk x 1 = algebraMap R (Localization M) x := + rfl + +theorem mk_eq_mk'_apply (x y) : mk x y = IsLocalization.mk' (Localization M) x y := by + rw [mk_eq_monoidOf_mk'_apply, mk', toLocalizationMap_eq_monoidOf] + +-- Porting note: removed `simp`. Left hand side can be simplified; not clear what normal form should +--be. +theorem mk_eq_mk' : (mk : R → M → Localization M) = IsLocalization.mk' (Localization M) := + mk_eq_monoidOf_mk' + +theorem mk_algebraMap {A : Type*} [CommSemiring A] [Algebra A R] (m : A) : + mk (algebraMap A R m) 1 = algebraMap A (Localization M) m := by + rw [mk_eq_mk', mk'_eq_iff_eq_mul, Submonoid.coe_one, map_one, mul_one]; rfl + +end Localization + +end CommSemiring + +section CommRing + +variable {R : Type*} [CommRing R] {M : Submonoid R} (S : Type*) [CommRing S] +variable [Algebra R S] {P : Type*} [CommRing P] + +namespace Localization + +theorem neg_mk (a b) : -(mk a b : Localization M) = mk (-a) b := OreLocalization.neg_def _ _ + +theorem sub_mk (a c) (b d) : (mk a b : Localization M) - mk c d = + mk ((d : R) * a - b * c) (b * d) := by + rw [sub_eq_add_neg, neg_mk, add_mk, add_comm, mul_neg, ← sub_eq_add_neg] + +end Localization + +namespace IsLocalization + +variable {K : Type*} [IsLocalization M S] + +include M in +lemma injective_of_map_algebraMap_zero {T} [CommRing T] (f : S →+* T) + (h : ∀ x, f (algebraMap R S x) = 0 → algebraMap R S x = 0) : + Function.Injective f := by + rw [IsLocalization.injective_iff_map_algebraMap_eq M] + refine fun x y ↦ ⟨fun hz ↦ hz ▸ rfl, fun hz ↦ ?_⟩ + rw [← sub_eq_zero, ← map_sub, ← map_sub] at hz + apply h at hz + rwa [map_sub, sub_eq_zero] at hz + +theorem to_map_eq_zero_iff {x : R} (hM : M ≤ nonZeroDivisors R) : algebraMap R S x = 0 ↔ x = 0 := by + rw [← (algebraMap R S).map_zero] + constructor <;> intro h + · cases' (eq_iff_exists M S).mp h with c hc + rw [mul_zero, mul_comm] at hc + exact hM c.2 x hc + · rw [h] + +protected theorem injective (hM : M ≤ nonZeroDivisors R) : Injective (algebraMap R S) := by + rw [injective_iff_map_eq_zero (algebraMap R S)] + intro a ha + rwa [to_map_eq_zero_iff S hM] at ha + +protected theorem to_map_ne_zero_of_mem_nonZeroDivisors [Nontrivial R] (hM : M ≤ nonZeroDivisors R) + {x : R} (hx : x ∈ nonZeroDivisors R) : algebraMap R S x ≠ 0 := + show (algebraMap R S).toMonoidWithZeroHom x ≠ 0 from + map_ne_zero_of_mem_nonZeroDivisors (algebraMap R S) (IsLocalization.injective S hM) hx + +variable {S} + +theorem sec_snd_ne_zero [Nontrivial R] (hM : M ≤ nonZeroDivisors R) (x : S) : + ((sec M x).snd : R) ≠ 0 := + nonZeroDivisors.coe_ne_zero ⟨(sec M x).snd.val, hM (sec M x).snd.property⟩ + +theorem sec_fst_ne_zero [Nontrivial R] [NoZeroDivisors S] (hM : M ≤ nonZeroDivisors R) {x : S} + (hx : x ≠ 0) : (sec M x).fst ≠ 0 := by + have hsec := sec_spec M x + intro hfst + rw [hfst, map_zero, mul_eq_zero, _root_.map_eq_zero_iff] at hsec + · exact Or.elim hsec hx (sec_snd_ne_zero hM x) + · exact IsLocalization.injective S hM + +variable {Q : Type*} [CommRing Q] {g : R →+* P} [Algebra P Q] +variable (A : Type*) [CommRing A] [IsDomain A] + +/-- A `CommRing` `S` which is the localization of a ring `R` without zero divisors at a subset of +non-zero elements does not have zero divisors. -/ +theorem noZeroDivisors_of_le_nonZeroDivisors [Algebra A S] {M : Submonoid A} [IsLocalization M S] + (hM : M ≤ nonZeroDivisors A) : NoZeroDivisors S := + { eq_zero_or_eq_zero_of_mul_eq_zero := by + intro z w h + cases' surj M z with x hx + cases' surj M w with y hy + have : + z * w * algebraMap A S y.2 * algebraMap A S x.2 = algebraMap A S x.1 * algebraMap A S y.1 := + by rw [mul_assoc z, hy, ← hx]; ring + rw [h, zero_mul, zero_mul, ← (algebraMap A S).map_mul] at this + cases' eq_zero_or_eq_zero_of_mul_eq_zero ((to_map_eq_zero_iff S hM).mp this.symm) with H H + · exact Or.inl (eq_zero_of_fst_eq_zero hx H) + · exact Or.inr (eq_zero_of_fst_eq_zero hy H) } + +/-- A `CommRing` `S` which is the localization of an integral domain `R` at a subset of +non-zero elements is an integral domain. -/ +theorem isDomain_of_le_nonZeroDivisors [Algebra A S] {M : Submonoid A} [IsLocalization M S] + (hM : M ≤ nonZeroDivisors A) : IsDomain S := by + apply @NoZeroDivisors.to_isDomain _ _ (id _) (id _) + · exact + ⟨⟨(algebraMap A S) 0, (algebraMap A S) 1, fun h => + zero_ne_one (IsLocalization.injective S hM h)⟩⟩ + · exact noZeroDivisors_of_le_nonZeroDivisors _ hM + +variable {A} + +/-- The localization of an integral domain to a set of non-zero elements is an integral domain. -/ +theorem isDomain_localization {M : Submonoid A} (hM : M ≤ nonZeroDivisors A) : + IsDomain (Localization M) := + isDomain_of_le_nonZeroDivisors _ hM + +end IsLocalization + +end CommRing diff --git a/Mathlib/RingTheory/Localization/Finiteness.lean b/Mathlib/RingTheory/Localization/Finiteness.lean index ab340bfec9330..4998718519d38 100644 --- a/Mathlib/RingTheory/Localization/Finiteness.lean +++ b/Mathlib/RingTheory/Localization/Finiteness.lean @@ -59,7 +59,7 @@ lemma of_isLocalizedModule [Module.Finite R M] : Module.Finite Rₚ Mₚ := by end -variable {R : Type u} [CommRing R] (S : Submonoid R) {M : Type w} [AddCommMonoid M] [Module R M] +variable {R : Type u} [CommRing R] {M : Type w} [AddCommMonoid M] [Module R M] /-- If there exists a finite set `{ r }` of `R` such that `Mᵣ` is `Rᵣ`-finite for each `r`, diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index f4b231a725789..5ba8201e865fb 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -4,8 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen -/ import Mathlib.Algebra.Algebra.Tower -import Mathlib.RingTheory.Localization.Basic import Mathlib.Algebra.Field.Equiv +import Mathlib.Algebra.Order.Field.Rat +import Mathlib.Algebra.Order.Ring.Int +import Mathlib.RingTheory.Localization.Basic /-! # Fraction ring / fraction field Frac(R) as localization @@ -126,9 +128,9 @@ noncomputable abbrev toField : Field K where mul_inv_cancel := IsFractionRing.mul_inv_cancel A inv_zero := show IsFractionRing.inv A (0 : K) = 0 by rw [IsFractionRing.inv]; exact dif_pos rfl nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun a x => rfl + qsmul_def := fun _ _ => rfl lemma surjective_iff_isField [IsDomain R] : Function.Surjective (algebraMap R K) ↔ IsField R where mp h := (RingEquiv.ofBijective (algebraMap R K) diff --git a/Mathlib/RingTheory/Localization/Ideal.lean b/Mathlib/RingTheory/Localization/Ideal.lean index 3882ffbd9f01a..4d5fd06147aed 100644 --- a/Mathlib/RingTheory/Localization/Ideal.lean +++ b/Mathlib/RingTheory/Localization/Ideal.lean @@ -3,7 +3,8 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen -/ -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.GroupTheory.MonoidLocalization.Away +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Localization.Basic /-! @@ -200,9 +201,7 @@ theorem surjective_quotientMap_of_maximal_of_localization {I : Ideal S} [I.IsPri (Ideal.Quotient.eq_zero_iff_mem.2 (Ideal.mem_comap.2 (Ideal.Quotient.eq_zero_iff_mem.1 hn)))) (_root_.trans hn ?_)) - -- Porting note (#10691): was `rw`, but this took extremely long. - refine Eq.trans ?_ (RingHom.map_mul (Ideal.Quotient.mk I) (algebraMap R S m) (mk' S 1 ⟨m, hm⟩)) - rw [← mk'_eq_mul_mk'_one, mk'_self, RingHom.map_one] + rw [← map_mul, ← mk'_eq_mul_mk'_one, mk'_self, RingHom.map_one] open nonZeroDivisors diff --git a/Mathlib/RingTheory/Localization/Integer.lean b/Mathlib/RingTheory/Localization/Integer.lean index 8c368cd7d7f3a..57e98b9913356 100644 --- a/Mathlib/RingTheory/Localization/Integer.lean +++ b/Mathlib/RingTheory/Localization/Integer.lean @@ -3,7 +3,9 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baanen -/ -import Mathlib.RingTheory.Localization.Basic +import Mathlib.Algebra.Group.Pointwise.Set.Basic +import Mathlib.Algebra.Ring.Subsemiring.Basic +import Mathlib.RingTheory.Localization.Defs /-! # Integer elements of a localization diff --git a/Mathlib/RingTheory/Localization/Integral.lean b/Mathlib/RingTheory/Localization/Integral.lean index c2f2e77d4b431..2c8a8157c19db 100644 --- a/Mathlib/RingTheory/Localization/Integral.lean +++ b/Mathlib/RingTheory/Localization/Integral.lean @@ -182,7 +182,7 @@ theorem RingHom.isIntegralElem_localization_at_leadingCoeff {R S : Type*} [CommR refine fun hfp => zero_ne_one (_root_.trans (zero_mul b).symm (hfp ▸ hb) : (0 : Rₘ) = 1) · refine eval₂_mul_eq_zero_of_left _ _ _ ?_ - erw [eval₂_map, IsLocalization.map_comp, ← hom_eval₂ _ f (algebraMap S Sₘ) x] + rw [eval₂_map, IsLocalization.map_comp, ← hom_eval₂ _ f (algebraMap S Sₘ) x] exact _root_.trans (congr_arg (algebraMap S Sₘ) hf) (RingHom.map_zero _) /-- Given a particular witness to an element being algebraic over an algebra `R → S`, diff --git a/Mathlib/RingTheory/Localization/InvSubmonoid.lean b/Mathlib/RingTheory/Localization/InvSubmonoid.lean index 109f4df1315f9..d5dbb6258b500 100644 --- a/Mathlib/RingTheory/Localization/InvSubmonoid.lean +++ b/Mathlib/RingTheory/Localization/InvSubmonoid.lean @@ -26,7 +26,7 @@ commutative ring, field of fractions variable {R : Type*} [CommRing R] (M : Submonoid R) (S : Type*) [CommRing S] -variable [Algebra R S] {P : Type*} [CommRing P] +variable [Algebra R S] open Function diff --git a/Mathlib/RingTheory/Localization/LocalizationLocalization.lean b/Mathlib/RingTheory/Localization/LocalizationLocalization.lean index a8796591c0f6c..62db6f2a12761 100644 --- a/Mathlib/RingTheory/Localization/LocalizationLocalization.lean +++ b/Mathlib/RingTheory/Localization/LocalizationLocalization.lean @@ -231,7 +231,7 @@ theorem isLocalization_of_is_exists_mul_mem (M N : Submonoid R) [IsLocalization { map_units' := fun y => by obtain ⟨m, hm⟩ := h' y have := IsLocalization.map_units S ⟨_, hm⟩ - erw [map_mul] at this + rw [map_mul] at this exact (IsUnit.mul_iff.mp this).2 surj' := fun z => by obtain ⟨⟨y, s⟩, e⟩ := IsLocalization.surj M z diff --git a/Mathlib/RingTheory/Localization/Module.lean b/Mathlib/RingTheory/Localization/Module.lean index 92f8b221b0cbb..70da0d848ded1 100644 --- a/Mathlib/RingTheory/Localization/Module.lean +++ b/Mathlib/RingTheory/Localization/Module.lean @@ -28,12 +28,12 @@ This file contains some results about vector spaces over the field of fractions open nonZeroDivisors section Localization - -variable {R : Type*} (Rₛ : Type*) [CommSemiring R] (S : Submonoid R) +variable {R : Type*} (Rₛ : Type*) section IsLocalizedModule section AddCommMonoid +variable [CommSemiring R] (S : Submonoid R) open Submodule @@ -53,6 +53,18 @@ theorem span_eq_top_of_isLocalizedModule {v : Set M} (hv : span R v = ⊤) : rw [← LinearMap.coe_restrictScalars R, ← LinearMap.map_span, hv] exact mem_map_of_mem mem_top +end AddCommMonoid + +section AddCommGroup + +variable {R : Type*} (Rₛ : Type*) [CommRing R] (S : Submonoid R) +variable [CommRing Rₛ] [Algebra R Rₛ] [hT : IsLocalization S Rₛ] +variable {M M' : Type*} [AddCommGroup M] [Module R M] + [AddCommGroup M'] [Module R M'] [Module Rₛ M'] [IsScalarTower R Rₛ M'] (f : M →ₗ[R] M') + [IsLocalizedModule S f] + +include S + theorem LinearIndependent.of_isLocalizedModule {ι : Type*} {v : ι → M} (hv : LinearIndependent R v) : LinearIndependent Rₛ (f ∘ v) := by rw [linearIndependent_iff'] at hv ⊢ @@ -77,7 +89,10 @@ theorem LinearIndependent.localization {ι : Type*} {b : ι → M} (hli : Linear have := isLocalizedModule_id S M Rₛ exact hli.of_isLocalizedModule Rₛ S .id -end AddCommMonoid +end AddCommGroup + + +variable [CommRing R] (S : Submonoid R) section Basis @@ -123,7 +138,7 @@ end IsLocalizedModule section LocalizationLocalization -variable [CommRing Rₛ] [Algebra R Rₛ] +variable [CommRing R] (S : Submonoid R) [CommRing Rₛ] [Algebra R Rₛ] variable [hT : IsLocalization S Rₛ] variable {A : Type*} [CommRing A] [Algebra R A] variable (Aₛ : Type*) [CommRing Aₛ] [Algebra A Aₛ] @@ -213,6 +228,70 @@ def LinearMap.extendScalarsOfIsLocalization (f : M →ₗ[R] N) : M →ₗ[A] N @[simp] lemma LinearMap.extendScalarsOfIsLocalization_apply' (f : M →ₗ[R] N) (x : M) : (f.extendScalarsOfIsLocalization S A) x = f x := rfl +/-- The `S⁻¹R`-linear maps between two `S⁻¹R`-modules are exactly the `R`-linear maps. -/ +@[simps] +def LinearMap.extendScalarsOfIsLocalizationEquiv : (M →ₗ[R] N) ≃ₗ[A] (M →ₗ[A] N) where + toFun := LinearMap.extendScalarsOfIsLocalization S A + invFun := LinearMap.restrictScalars R + map_add' := by intros; ext; simp + map_smul' := by intros; ext; simp + left_inv := by intros _; ext; simp + right_inv := by intros _; ext; simp + end end Localization + +namespace IsLocalizedModule + +variable {R : Type*} [CommSemiring R] (S : Submonoid R) +variable {M M' : Type*} [AddCommMonoid M] [AddCommMonoid M'] +variable [Module R M] [Module R M'] +variable (f : M →ₗ[R] M') [IsLocalizedModule S f] +variable {N N'} [AddCommMonoid N] [AddCommMonoid N'] [Module R N] [Module R N'] +variable (g : N →ₗ[R] N') [IsLocalizedModule S g] +variable (Rₛ) [CommSemiring Rₛ] [Algebra R Rₛ] [Module Rₛ M'] [Module Rₛ N'] +variable [IsScalarTower R Rₛ M'] [IsScalarTower R Rₛ N'] [IsLocalization S Rₛ] + +/-- A linear map `M →ₗ[R] N` gives a map between localized modules `Mₛ →ₗ[Rₛ] Nₛ`. -/ +@[simps!] +noncomputable +def mapExtendScalars : (M →ₗ[R] N) →ₗ[R] (M' →ₗ[Rₛ] N') := + ((LinearMap.extendScalarsOfIsLocalizationEquiv + S Rₛ).restrictScalars R).toLinearMap.comp (map S f g) + +end IsLocalizedModule + +section LocalizedModule + +variable {R : Type*} [CommSemiring R] (S : Submonoid R) +variable {M : Type*} [AddCommMonoid M] [Module R M] +variable {N} [AddCommMonoid N] [Module R N] + +/-- A linear map `M →ₗ[R] N` gives a map between localized modules `Mₛ →ₗ[Rₛ] Nₛ`. -/ +noncomputable +def LocalizedModule.map : + (M →ₗ[R] N) →ₗ[R] (LocalizedModule S M →ₗ[Localization S] LocalizedModule S N) := + IsLocalizedModule.mapExtendScalars S (LocalizedModule.mkLinearMap S M) + (LocalizedModule.mkLinearMap S N) (Localization S) + +@[simp] +lemma LocalizedModule.map_mk (f : M →ₗ[R] N) (x y) : + map S f (.mk x y) = LocalizedModule.mk (f x) y := by + rw [IsLocalizedModule.mk_eq_mk', IsLocalizedModule.mk_eq_mk'] + exact IsLocalizedModule.map_mk' _ _ _ _ _ _ + +@[simp] +lemma LocalizedModule.map_id : + LocalizedModule.map S (.id (R := R) (M := M)) = LinearMap.id := + LinearMap.ext fun x ↦ LinearMap.congr_fun (IsLocalizedModule.map_id S (mkLinearMap S M)) x + +lemma LocalizedModule.map_injective (l : M →ₗ[R] N) (hl : Function.Injective l) : + Function.Injective (map S l) := + IsLocalizedModule.map_injective S (mkLinearMap S M) (mkLinearMap S N) l hl + +lemma LocalizedModule.map_surjective (l : M →ₗ[R] N) (hl : Function.Surjective l) : + Function.Surjective (map S l) := + IsLocalizedModule.map_surjective S (mkLinearMap S M) (mkLinearMap S N) l hl + +end LocalizedModule diff --git a/Mathlib/RingTheory/Localization/NumDen.lean b/Mathlib/RingTheory/Localization/NumDen.lean index 07a87d3552ccd..d9d828d11ba3f 100644 --- a/Mathlib/RingTheory/Localization/NumDen.lean +++ b/Mathlib/RingTheory/Localization/NumDen.lean @@ -42,7 +42,7 @@ theorem exists_reduced_fraction (x : K) : refine ⟨a', ⟨b', b'_nonzero⟩, no_factor, ?_⟩ refine mul_left_cancel₀ (IsFractionRing.to_map_ne_zero_of_mem_nonZeroDivisors b_nonzero) ?_ simp only [Subtype.coe_mk, RingHom.map_mul, Algebra.smul_def] at * - erw [← hab, mul_assoc, mk'_spec' _ a' ⟨b', b'_nonzero⟩] + rw [← hab, mul_assoc, mk'_spec' _ a' ⟨b', b'_nonzero⟩] /-- `f.num x` is the numerator of `x : f.codomain` as a reduced fraction. -/ noncomputable def num (x : K) : A := diff --git a/Mathlib/RingTheory/Localization/Submodule.lean b/Mathlib/RingTheory/Localization/Submodule.lean index b1cda5e8116b6..1d9412e648572 100644 --- a/Mathlib/RingTheory/Localization/Submodule.lean +++ b/Mathlib/RingTheory/Localization/Submodule.lean @@ -21,7 +21,7 @@ commutative ring, field of fractions variable {R : Type*} [CommRing R] (M : Submonoid R) (S : Type*) [CommRing S] -variable [Algebra R S] {P : Type*} [CommRing P] +variable [Algebra R S] namespace IsLocalization @@ -67,14 +67,10 @@ theorem coeSubmodule_span (s : Set R) : rw [IsLocalization.coeSubmodule, Ideal.span, Submodule.map_span] rfl --- @[simp] -- Porting note (#10618): simp can prove this theorem coeSubmodule_span_singleton (x : R) : coeSubmodule S (Ideal.span {x}) = Submodule.span R {(algebraMap R S) x} := by rw [coeSubmodule_span, Set.image_singleton] -variable {g : R →+* P} -variable {T : Submonoid P} (hy : M ≤ T.comap g) {Q : Type*} [CommRing Q] -variable [Algebra P Q] [IsLocalization T Q] variable [IsLocalization M S] include M in @@ -120,11 +116,11 @@ theorem mem_span_iff {N : Type*} [AddCommGroup N] [Module R N] [Module S N] [IsS x ∈ Submodule.span S a ↔ ∃ y ∈ Submodule.span R a, ∃ z : M, x = mk' S 1 z • y := by constructor · intro h - refine Submodule.span_induction h ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ h · rintro x hx exact ⟨x, Submodule.subset_span hx, 1, by rw [mk'_one, map_one, one_smul]⟩ · exact ⟨0, Submodule.zero_mem _, 1, by rw [mk'_one, map_one, one_smul]⟩ - · rintro _ _ ⟨y, hy, z, rfl⟩ ⟨y', hy', z', rfl⟩ + · rintro _ _ _ _ ⟨y, hy, z, rfl⟩ ⟨y', hy', z', rfl⟩ refine ⟨(z' : R) • y + (z : R) • y', Submodule.add_mem _ (Submodule.smul_mem _ _ hy) (Submodule.smul_mem _ _ hy'), z * z', ?_⟩ @@ -133,7 +129,7 @@ theorem mem_span_iff {N : Type*} [AddCommGroup N] [Module R N] [Module S N] [IsS congr 1 · rw [← mul_one (1 : R), mk'_mul, mul_assoc, mk'_spec, map_one, mul_one, mul_one] · rw [← mul_one (1 : R), mk'_mul, mul_right_comm, mk'_spec, map_one, mul_one, one_mul] - · rintro a _ ⟨y, hy, z, rfl⟩ + · rintro a _ _ ⟨y, hy, z, rfl⟩ obtain ⟨y', z', rfl⟩ := mk'_surjective M a refine ⟨y' • y, Submodule.smul_mem _ _ hy, z' * z, ?_⟩ rw [← IsScalarTower.algebraMap_smul S y', smul_smul, ← mk'_mul, smul_smul, @@ -159,11 +155,11 @@ namespace IsFractionRing open IsLocalization -variable {A K : Type*} [CommRing A] +variable {K : Type*} section CommRing -variable [CommRing K] [Algebra R K] [IsFractionRing R K] [Algebra A K] [IsFractionRing A K] +variable [CommRing K] [Algebra R K] [IsFractionRing R K] @[simp, mono] theorem coeSubmodule_le_coeSubmodule {I J : Ideal R} : diff --git a/Mathlib/RingTheory/MatrixAlgebra.lean b/Mathlib/RingTheory/MatrixAlgebra.lean index 4a71967b89d79..0750d23424344 100644 --- a/Mathlib/RingTheory/MatrixAlgebra.lean +++ b/Mathlib/RingTheory/MatrixAlgebra.lean @@ -99,13 +99,11 @@ theorem invFun_algebraMap (M : Matrix n n R) : invFun R A n (M.map (algebraMap R convert Finset.sum_product (β := Matrix n n R) ..; simp theorem right_inv (M : Matrix n n A) : (toFunAlgHom R A n) (invFun R A n M) = M := by - simp only [invFun, map_sum, stdBasisMatrix, apply_ite ↑(algebraMap R A), smul_eq_mul, - mul_boole, toFunAlgHom_apply, RingHom.map_zero, RingHom.map_one, Matrix.map_apply, - Pi.smul_def] + simp only [invFun, map_sum, toFunAlgHom_apply] convert Finset.sum_product (β := Matrix n n A) .. conv_lhs => rw [matrix_eq_sum_stdBasisMatrix M] refine Finset.sum_congr rfl fun i _ => Finset.sum_congr rfl fun j _ => Matrix.ext fun a b => ?_ - simp only [stdBasisMatrix, smul_apply, Matrix.map_apply] + dsimp [stdBasisMatrix] split_ifs <;> aesop theorem left_inv (M : A ⊗[R] Matrix n n R) : invFun R A n (toFunAlgHom R A n M) = M := by diff --git a/Mathlib/RingTheory/Multiplicity.lean b/Mathlib/RingTheory/Multiplicity.lean index 457a6e35fcef7..42f7495bb32f1 100644 --- a/Mathlib/RingTheory/Multiplicity.lean +++ b/Mathlib/RingTheory/Multiplicity.lean @@ -1,13 +1,12 @@ /- Copyright (c) 2018 Robert Y. Lewis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Robert Y. Lewis, Chris Hughes +Authors: Robert Y. Lewis, Chris Hughes, Daniel Weber -/ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.Finset -import Mathlib.Algebra.SMulWithZero -import Mathlib.Data.Nat.PartENat import Mathlib.Tactic.Linarith +import Mathlib.Data.ENat.Basic /-! # Multiplicity of a divisor @@ -17,237 +16,388 @@ several basic results on it. ## Main definitions -* `multiplicity a b`: for two elements `a` and `b` of a commutative monoid returns the largest +* `emultiplicity a b`: for two elements `a` and `b` of a commutative monoid returns the largest number `n` such that `a ^ n ∣ b` or infinity, written `⊤`, if `a ^ n ∣ b` for all natural numbers `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. -/ variable {α β : Type*} -open Nat Part +open Nat -/-- `multiplicity a b` returns the largest natural number `n` such that - `a ^ n ∣ b`, as a `PartENat` or natural with infinity. If `∀ n, a ^ n ∣ b`, - then it returns `⊤`-/ -def multiplicity [Monoid α] [DecidableRel ((· ∣ ·) : α → α → Prop)] (a b : α) : PartENat := - PartENat.find fun n => ¬a ^ (n + 1) ∣ b +/-- `multiplicity.Finite a b` indicates that the multiplicity of `a` in `b` is finite. -/ +abbrev multiplicity.Finite [Monoid α] (a b : α) : Prop := + ∃ n : ℕ, ¬a ^ (n + 1) ∣ b + +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 ⊤ -namespace multiplicity +/-- 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 β] +variable [Monoid α] [Monoid β] {a b : α} -/-- `multiplicity.Finite a b` indicates that the multiplicity of `a` in `b` is finite. -/ -abbrev Finite (a b : α) : Prop := - ∃ n : ℕ, ¬a ^ (n + 1) ∣ b +@[simp] +theorem emultiplicity_eq_top : + emultiplicity a b = ⊤ ↔ ¬Finite a b := by + simp [emultiplicity] + +theorem emultiplicity_lt_top {a b : α} : emultiplicity a b < ⊤ ↔ Finite 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 + +alias ⟨Finite.emultiplicity_ne_top, _⟩ := finite_iff_emultiplicity_ne_top + +theorem finite_of_emultiplicity_eq_natCast {n : ℕ} (h : emultiplicity a b = n) : + Finite a b := by + by_contra! nh + rw [← emultiplicity_eq_top, h] at nh + trivial + +theorem multiplicity_eq_of_emultiplicity_eq_some {n : ℕ} (h : emultiplicity a b = n) : + multiplicity a b = n := by + simp [multiplicity, h] + rfl + +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) : + 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 + simp [h.emultiplicity_eq_multiplicity] + +theorem emultiplicity_eq_iff_multiplicity_eq_of_ne_one {n : ℕ} (h : n ≠ 1) : + emultiplicity a b = n ↔ multiplicity a b = n := by + constructor + · exact multiplicity_eq_of_emultiplicity_eq_some + · intro h₂ + simpa [multiplicity, WithTop.untop'_eq_iff, h] using h₂ + +theorem emultiplicity_eq_zero_iff_multiplicity_eq_zero : + emultiplicity a b = 0 ↔ multiplicity a b = 0 := + emultiplicity_eq_iff_multiplicity_eq_of_ne_one zero_ne_one -theorem finite_iff_dom [DecidableRel ((· ∣ ·) : α → α → Prop)] {a b : α} : - Finite a b ↔ (multiplicity a b).Dom := - Iff.rfl +@[simp] +theorem multiplicity_eq_one_of_not_finite (h : ¬Finite a b) : + multiplicity a b = 1 := by + simp [multiplicity, emultiplicity_eq_top.2 h] + +@[simp] +theorem multiplicity_le_emultiplicity : + multiplicity a b ≤ emultiplicity a b := by + by_cases hf : Finite a b + · simp [hf.emultiplicity_eq_multiplicity] + · simp [hf, emultiplicity_eq_top.2] -theorem finite_def {a b : α} : Finite a b ↔ ∃ n : ℕ, ¬a ^ (n + 1) ∣ b := +@[simp] +theorem multiplicity_eq_of_emultiplicity_eq {c d : β} + (h : emultiplicity a b = emultiplicity c d) : multiplicity a b = multiplicity c d := by + unfold multiplicity + rw [h] + +theorem multiplicity_le_of_emultiplicity_le {n : ℕ} (h : emultiplicity a b ≤ n) : + 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) + {n : ℕ} (h : multiplicity a b ≤ n) : emultiplicity a b ≤ n := by + rw [emultiplicity_eq_multiplicity hfin] + assumption_mod_cast + +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) + {n : ℕ} (h : n ≤ emultiplicity a b) : n ≤ multiplicity a b := by + rw [emultiplicity_eq_multiplicity hfin] at h + assumption_mod_cast + +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) + {n : ℕ} (h : multiplicity a b < n) : emultiplicity a b < n := by + rw [emultiplicity_eq_multiplicity hfin] + assumption_mod_cast + +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) + {n : ℕ} (h : n < emultiplicity a b) : n < multiplicity a b := by + rw [emultiplicity_eq_multiplicity hfin] at h + assumption_mod_cast + +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 := Iff.rfl -theorem not_dvd_one_of_finite_one_right {a : α} : Finite a 1 → ¬a ∣ 1 := fun ⟨n, hn⟩ ⟨d, hd⟩ => +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⟩ @[norm_cast] -theorem Int.natCast_multiplicity (a b : ℕ) : multiplicity (a : ℤ) (b : ℤ) = multiplicity a b := by - apply Part.ext' - · rw [← @finite_iff_dom ℕ, @finite_def ℕ, ← @finite_iff_dom ℤ, @finite_def ℤ] - norm_cast - · intro h1 h2 - apply _root_.le_antisymm <;> - · apply Nat.find_mono - norm_cast - simp +theorem Int.natCast_emultiplicity (a b : ℕ) : + emultiplicity (a : ℤ) (b : ℤ) = emultiplicity a b := by + unfold emultiplicity multiplicity.Finite + congr! <;> norm_cast + +@[norm_cast] +theorem Int.natCast_multiplicity (a b : ℕ) : multiplicity (a : ℤ) (b : ℤ) = multiplicity a b := + multiplicity_eq_of_emultiplicity_eq (natCast_emultiplicity a b) @[deprecated (since := "2024-04-05")] alias Int.coe_nat_multiplicity := Int.natCast_multiplicity -theorem not_finite_iff_forall {a b : α} : ¬Finite a b ↔ ∀ n : ℕ, a ^ n ∣ b := +theorem multiplicity.Finite.not_iff_forall : ¬Finite a b ↔ ∀ n : ℕ, a ^ n ∣ b := ⟨fun h n => Nat.casesOn n (by rw [_root_.pow_zero] exact one_dvd _) - (by simpa [Finite, Classical.not_not] using h), - by simp [Finite, multiplicity, Classical.not_not]; tauto⟩ + (by simpa [multiplicity.Finite, Classical.not_not] using h), + by simp [multiplicity.Finite, multiplicity, Classical.not_not]; tauto⟩ -theorem not_unit_of_finite {a b : α} (h : Finite a b) : ¬IsUnit a := +theorem multiplicity.Finite.not_unit (h : Finite a b) : ¬IsUnit a := let ⟨n, hn⟩ := h hn ∘ IsUnit.dvd ∘ IsUnit.pow (n + 1) -theorem finite_of_finite_mul_right {a b c : α} : Finite a (b * c) → Finite a b := fun ⟨n, hn⟩ => +theorem multiplicity.Finite.mul_left {c : α} : Finite a (b * c) → Finite a b := fun ⟨n, hn⟩ => ⟨n, fun h => hn (h.trans (dvd_mul_right _ _))⟩ -variable [DecidableRel ((· ∣ ·) : α → α → Prop)] [DecidableRel ((· ∣ ·) : β → β → Prop)] - -theorem pow_dvd_of_le_multiplicity {a b : α} {k : ℕ} : - (k : PartENat) ≤ multiplicity a b → a ^ k ∣ b := by - rw [← PartENat.some_eq_natCast] - exact - Nat.casesOn k - (fun _ => by - rw [_root_.pow_zero] - exact one_dvd _) - fun k ⟨_, h₂⟩ => by_contradiction fun hk => Nat.find_min _ (lt_of_succ_le (h₂ ⟨k, hk⟩)) hk - -theorem pow_multiplicity_dvd {a b : α} (h : Finite a b) : a ^ get (multiplicity a b) h ∣ b := - pow_dvd_of_le_multiplicity (by rw [PartENat.natCast_get]) +theorem pow_dvd_of_le_emultiplicity {k : ℕ} (hk : k ≤ emultiplicity a b) : + a ^ k ∣ b := by classical + cases k + · simp + unfold emultiplicity at hk + split at hk + · norm_cast at hk + simpa using (Nat.find_min _ (lt_of_succ_le hk)) + · apply Finite.not_iff_forall.mp ‹_› -theorem is_greatest {a b : α} {m : ℕ} (hm : multiplicity a b < m) : ¬a ^ m ∣ b := fun h => by - rw [PartENat.lt_coe_iff] at hm; exact Nat.find_spec hm.fst ((pow_dvd_pow _ hm.snd).trans h) +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) -theorem is_greatest' {a b : α} {m : ℕ} (h : Finite a b) (hm : get (multiplicity a b) h < m) : - ¬a ^ m ∣ b := - is_greatest (by rwa [← PartENat.coe_lt_coe, PartENat.natCast_get] at hm) - -theorem pos_of_dvd {a b : α} (hfin : Finite a b) (hdiv : a ∣ b) : - 0 < (multiplicity a b).get hfin := by +@[simp] +theorem pow_multiplicity_dvd (a b : α) : a ^ (multiplicity a b) ∣ b := + pow_dvd_of_le_multiplicity le_rfl + +theorem not_pow_dvd_of_emultiplicity_lt {m : ℕ} (hm : emultiplicity a b < m) : + ¬a ^ m ∣ b := fun nh => by + unfold emultiplicity at hm + split at hm + · simp only [cast_lt, find_lt_iff] at hm + obtain ⟨n, hn1, hn2⟩ := hm + 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 : ℕ} + (hm : multiplicity a b < m) : ¬a ^ m ∣ b := by + apply not_pow_dvd_of_emultiplicity_lt + rw [hf.emultiplicity_eq_multiplicity] + norm_cast + +theorem multiplicity_pos_of_dvd (hdiv : a ∣ b) : 0 < multiplicity a b := by refine zero_lt_iff.2 fun h => ?_ - simpa [hdiv] using is_greatest' hfin (lt_one_iff.mpr h) - -theorem unique {a b : α} {k : ℕ} (hk : a ^ k ∣ b) (hsucc : ¬a ^ (k + 1) ∣ b) : - (k : PartENat) = multiplicity a b := - le_antisymm (le_of_not_gt fun hk' => is_greatest hk' hk) <| by - have : Finite a b := ⟨k, hsucc⟩ - rw [PartENat.le_coe_iff] - exact ⟨this, Nat.find_min' _ hsucc⟩ - -theorem unique' {a b : α} {k : ℕ} (hk : a ^ k ∣ b) (hsucc : ¬a ^ (k + 1) ∣ b) : - k = get (multiplicity a b) ⟨k, hsucc⟩ := by - rw [← PartENat.natCast_inj, PartENat.natCast_get, unique hk hsucc] - -theorem le_multiplicity_of_pow_dvd {a b : α} {k : ℕ} (hk : a ^ k ∣ b) : - (k : PartENat) ≤ multiplicity a b := - le_of_not_gt fun hk' => is_greatest hk' hk - -theorem pow_dvd_iff_le_multiplicity {a b : α} {k : ℕ} : - a ^ k ∣ b ↔ (k : PartENat) ≤ multiplicity a b := - ⟨le_multiplicity_of_pow_dvd, pow_dvd_of_le_multiplicity⟩ + simpa [hdiv] using Finite.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 := + lt_emultiplicity_of_lt_multiplicity (multiplicity_pos_of_dvd hdiv) + +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⟩ + 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 + +theorem multiplicity_eq_of_dvd_of_not_dvd {k : ℕ} (hk : a ^ k ∣ b) (hsucc : ¬a ^ (k + 1) ∣ b) : + multiplicity a b = k := + multiplicity_eq_of_emultiplicity_eq_some (emultiplicity_eq_of_dvd_of_not_dvd hk hsucc) + +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 := + hf.le_multiplicity_of_le_emultiplicity (le_emultiplicity_of_pow_dvd hk) + +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 : ℕ} : + a ^ k ∣ b ↔ k ≤ multiplicity a b := by + exact_mod_cast hf.emultiplicity_eq_multiplicity ▸ pow_dvd_iff_le_emultiplicity + +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) : + multiplicity a b < k ↔ ¬a ^ k ∣ b := by rw [hf.pow_dvd_iff_le_multiplicity, not_le] + +theorem emultiplicity_eq_coe {n : ℕ} : + emultiplicity a b = n ↔ a ^ n ∣ b ∧ ¬a ^ (n + 1) ∣ b := by + constructor + · intro h + constructor + · apply pow_dvd_of_le_emultiplicity + simp [h] + · apply not_pow_dvd_of_emultiplicity_lt + rw [h] + norm_cast + simp + · rw [and_imp] + apply emultiplicity_eq_of_dvd_of_not_dvd -theorem multiplicity_lt_iff_not_dvd {a b : α} {k : ℕ} : - multiplicity a b < (k : PartENat) ↔ ¬a ^ k ∣ b := by rw [pow_dvd_iff_le_multiplicity, not_le] - -theorem eq_coe_iff {a b : α} {n : ℕ} : - multiplicity a b = (n : PartENat) ↔ a ^ n ∣ b ∧ ¬a ^ (n + 1) ∣ b := by - rw [← PartENat.some_eq_natCast] - exact - ⟨fun h => - let ⟨h₁, h₂⟩ := eq_some_iff.1 h - h₂ ▸ ⟨pow_multiplicity_dvd _, is_greatest (by - rw [PartENat.lt_coe_iff] - exact ⟨h₁, lt_succ_self _⟩)⟩, - fun h => eq_some_iff.2 ⟨⟨n, h.2⟩, Eq.symm <| unique' h.1 h.2⟩⟩ - -theorem eq_top_iff {a b : α} : multiplicity a b = ⊤ ↔ ∀ n : ℕ, a ^ n ∣ b := - (PartENat.find_eq_top_iff _).trans <| by - simp only [Classical.not_not] - exact - ⟨fun h n => - Nat.casesOn n - (by - rw [_root_.pow_zero] - exact one_dvd _) - fun n => h _, - fun h n => h _⟩ +theorem multiplicity.Finite.multiplicity_eq_iff (hf : Finite a b) {n : ℕ} : + multiplicity a b = n ↔ a ^ n ∣ b ∧ ¬a ^ (n + 1) ∣ b := by + simp [← emultiplicity_eq_coe, hf.emultiplicity_eq_multiplicity] @[simp] -theorem isUnit_left {a : α} (b : α) (ha : IsUnit a) : multiplicity a b = ⊤ := - eq_top_iff.2 fun _ => IsUnit.dvd (ha.pow _) +theorem multiplicity.Finite.not_of_isUnit_left (b : α) (ha : IsUnit a) : ¬Finite a b := + (·.not_unit ha) --- @[simp] Porting note (#10618): simp can prove this -theorem one_left (b : α) : multiplicity 1 b = ⊤ := - isUnit_left b isUnit_one +theorem multiplicity.Finite.not_of_one_left (b : α) : ¬ Finite 1 b := by simp @[simp] -theorem get_one_right {a : α} (ha : Finite a 1) : get (multiplicity a 1) ha = 0 := by - rw [PartENat.get_eq_iff_eq_coe, eq_coe_iff, _root_.pow_zero] - simp [not_dvd_one_of_finite_one_right ha] - --- @[simp] Porting note (#10618): simp can prove this -theorem unit_left (a : α) (u : αˣ) : multiplicity (u : α) a = ⊤ := - isUnit_left a u.isUnit - -theorem multiplicity_eq_zero {a b : α} : multiplicity a b = 0 ↔ ¬a ∣ b := by - rw [← Nat.cast_zero, eq_coe_iff] - simp only [_root_.pow_zero, isUnit_one, IsUnit.dvd, zero_add, pow_one, true_and] - -theorem multiplicity_ne_zero {a b : α} : multiplicity a b ≠ 0 ↔ a ∣ b := - multiplicity_eq_zero.not_left - -theorem eq_top_iff_not_finite {a b : α} : multiplicity a b = ⊤ ↔ ¬Finite a b := - Part.eq_none_iff' - -theorem ne_top_iff_finite {a b : α} : multiplicity a b ≠ ⊤ ↔ Finite a b := by - rw [Ne, eq_top_iff_not_finite, Classical.not_not] +theorem emultiplicity_one_left (b : α) : emultiplicity 1 b = ⊤ := + emultiplicity_eq_top.2 (Finite.not_of_one_left _) -theorem lt_top_iff_finite {a b : α} : multiplicity a b < ⊤ ↔ Finite a b := by - rw [lt_top_iff_ne_top, ne_top_iff_finite] - -theorem exists_eq_pow_mul_and_not_dvd {a b : α} (hfin : Finite a b) : - ∃ c : α, b = a ^ (multiplicity a b).get hfin * c ∧ ¬a ∣ c := by - obtain ⟨c, hc⟩ := multiplicity.pow_multiplicity_dvd hfin +@[simp] +theorem multiplicity.Finite.one_right (ha : Finite 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 + +theorem emultiplicity_eq_zero : + emultiplicity a b = 0 ↔ ¬a ∣ b := by + by_cases hf : Finite a b + · rw [← ENat.coe_zero, emultiplicity_eq_coe] + simp + · simpa [emultiplicity_eq_top.2 hf] using Finite.not_iff_forall.1 hf 1 + +theorem multiplicity_eq_zero : + multiplicity a b = 0 ↔ ¬a ∣ b := + (emultiplicity_eq_iff_multiplicity_eq_of_ne_one zero_ne_one).symm.trans emultiplicity_eq_zero + +theorem emultiplicity_ne_zero : + emultiplicity a b ≠ 0 ↔ a ∣ b := by + simp [emultiplicity_eq_zero] + +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) : + ∃ c : α, b = a ^ multiplicity a b * c ∧ ¬a ∣ c := by + obtain ⟨c, hc⟩ := pow_multiplicity_dvd a b refine ⟨c, hc, ?_⟩ rintro ⟨k, hk⟩ rw [hk, ← mul_assoc, ← _root_.pow_succ] at hc - have h₁ : a ^ ((multiplicity a b).get hfin + 1) ∣ b := ⟨k, hc⟩ - exact (multiplicity.eq_coe_iff.1 (by simp)).2 h₁ - -theorem multiplicity_le_multiplicity_iff {a b : α} {c d : β} : - multiplicity a b ≤ multiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b → c ^ n ∣ d := - ⟨fun h n hab => pow_dvd_of_le_multiplicity (le_trans (le_multiplicity_of_pow_dvd hab) h), fun h => - letI := Classical.dec (Finite a b) - if hab : Finite a b then by - rw [← PartENat.natCast_get (finite_iff_dom.1 hab)] - exact le_multiplicity_of_pow_dvd (h _ (pow_multiplicity_dvd _)) - else by - have : ∀ n : ℕ, c ^ n ∣ d := fun n => h n (not_finite_iff_forall.1 hab _) - rw [eq_top_iff_not_finite.2 hab, eq_top_iff_not_finite.2 (not_finite_iff_forall.2 this)]⟩ - -theorem multiplicity_eq_multiplicity_iff {a b : α} {c d : β} : - multiplicity a b = multiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b ↔ c ^ n ∣ d := + have h₁ : a ^ (multiplicity a b + 1) ∣ b := ⟨k, hc⟩ + exact (hfin.multiplicity_eq_iff.1 (by simp)).2 h₁ + +theorem emultiplicity_le_emultiplicity_iff {c d : β} : + emultiplicity a b ≤ emultiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b → c ^ n ∣ d := by classical + constructor + · exact fun h n hab ↦ pow_dvd_of_le_emultiplicity (le_trans (le_emultiplicity_of_pow_dvd hab) h) + · intro h + unfold emultiplicity + -- aesop? says + split + next h_1 => + obtain ⟨w, h_1⟩ := h_1 + split + next h_2 => + simp_all only [cast_le, le_find_iff, lt_find_iff, Decidable.not_not, le_refl, + not_true_eq_false, not_false_eq_true, implies_true] + next h_2 => simp_all only [not_exists, Decidable.not_not, le_top] + next h_1 => + 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 + rw [← WithTop.coe_le_coe, ENat.some_eq_coe, ← hab.emultiplicity_eq_multiplicity, + ← hcd.emultiplicity_eq_multiplicity] + apply emultiplicity_le_emultiplicity_iff + +theorem emultiplicity_eq_emultiplicity_iff {c d : β} : + emultiplicity a b = emultiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b ↔ c ^ n ∣ d := ⟨fun h n => - ⟨multiplicity_le_multiplicity_iff.mp h.le n, multiplicity_le_multiplicity_iff.mp h.ge n⟩, - fun h => - le_antisymm (multiplicity_le_multiplicity_iff.mpr fun n => (h n).mp) - (multiplicity_le_multiplicity_iff.mpr fun n => (h n).mpr)⟩ + ⟨emultiplicity_le_emultiplicity_iff.1 h.le n, emultiplicity_le_emultiplicity_iff.1 h.ge n⟩, + fun h => le_antisymm (emultiplicity_le_emultiplicity_iff.2 fun n => (h n).mp) + (emultiplicity_le_emultiplicity_iff.2 fun n => (h n).mpr)⟩ -theorem le_multiplicity_map {F : Type*} [FunLike F α β] [MonoidHomClass F α β] - (f : F) {a b : α} : multiplicity a b ≤ multiplicity (f a) (f b) := - multiplicity_le_multiplicity_iff.mpr fun n ↦ by rw [← map_pow]; exact map_dvd f +theorem le_emultiplicity_map {F : Type*} [FunLike F α β] [MonoidHomClass F α β] + (f : F) {a b : α} : + emultiplicity a b ≤ emultiplicity (f a) (f b) := + emultiplicity_le_emultiplicity_iff.2 fun n ↦ by rw [← map_pow]; exact map_dvd f + +theorem emultiplicity_map_eq {F : Type*} [EquivLike F α β] [MulEquivClass F α β] + (f : F) {a b : α} : emultiplicity (f a) (f b) = emultiplicity a b := by + simp [emultiplicity_eq_emultiplicity_iff, ← map_pow, map_dvd_iff] theorem multiplicity_map_eq {F : Type*} [EquivLike F α β] [MulEquivClass F α β] (f : F) {a b : α} : multiplicity (f a) (f b) = multiplicity a b := - multiplicity_eq_multiplicity_iff.mpr fun n ↦ by rw [← map_pow]; exact map_dvd_iff f + multiplicity_eq_of_emultiplicity_eq (emultiplicity_map_eq f) + +theorem emultiplicity_le_emultiplicity_of_dvd_right {a b c : α} (h : b ∣ c) : + emultiplicity a b ≤ emultiplicity a c := + emultiplicity_le_emultiplicity_iff.2 fun _ hb => hb.trans h -theorem multiplicity_le_multiplicity_of_dvd_right {a b c : α} (h : b ∣ c) : - multiplicity a b ≤ multiplicity a c := - multiplicity_le_multiplicity_iff.2 fun _ hb => hb.trans h +theorem emultiplicity_eq_of_associated_right {a b c : α} (h : Associated b c) : + emultiplicity a b = emultiplicity a c := + le_antisymm (emultiplicity_le_emultiplicity_of_dvd_right h.dvd) + (emultiplicity_le_emultiplicity_of_dvd_right h.symm.dvd) -theorem eq_of_associated_right {a b c : α} (h : Associated b c) : +theorem multiplicity_eq_of_associated_right {a b c : α} (h : Associated b c) : multiplicity a b = multiplicity a c := - le_antisymm (multiplicity_le_multiplicity_of_dvd_right h.dvd) - (multiplicity_le_multiplicity_of_dvd_right h.symm.dvd) - -theorem dvd_of_multiplicity_pos {a b : α} (h : (0 : PartENat) < multiplicity a b) : a ∣ b := by - rw [← pow_one a] - apply pow_dvd_of_le_multiplicity - simpa only [Nat.cast_one, PartENat.pos_iff_one_le] using h - -theorem dvd_iff_multiplicity_pos {a b : α} : (0 : PartENat) < multiplicity a b ↔ a ∣ b := - ⟨dvd_of_multiplicity_pos, fun hdvd => - lt_of_le_of_ne (zero_le _) fun heq => - is_greatest - (show multiplicity a b < ↑1 by - simpa only [heq, Nat.cast_zero] using PartENat.coe_lt_coe.mpr zero_lt_one) - (by rwa [pow_one a])⟩ - -theorem finite_nat_iff {a b : ℕ} : Finite a b ↔ a ≠ 1 ∧ 0 < b := by - rw [← not_iff_not, not_finite_iff_forall, not_and_or, Ne, Classical.not_not, not_lt, + multiplicity_eq_of_emultiplicity_eq (emultiplicity_eq_of_associated_right h) + +theorem dvd_of_emultiplicity_pos {a b : α} (h : 0 < emultiplicity a b) : a ∣ b := + pow_one a ▸ pow_dvd_of_le_emultiplicity (Order.add_one_le_of_lt h) + +theorem dvd_of_multiplicity_pos {a b : α} (h : 0 < multiplicity a b) : a ∣ b := + dvd_of_emultiplicity_pos (lt_emultiplicity_of_lt_multiplicity h) + +theorem dvd_iff_multiplicity_pos {a b : α} : 0 < multiplicity a b ↔ a ∣ b := + ⟨dvd_of_multiplicity_pos, fun hdvd => Nat.pos_of_ne_zero (by simpa [multiplicity_eq_zero])⟩ + +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, Nat.le_zero] exact ⟨fun h => @@ -263,7 +413,7 @@ theorem finite_nat_iff {a b : ℕ} : Finite a b ↔ a ≠ 1 ∧ 0 < b := by not_lt_of_ge (le_of_dvd (Nat.pos_of_ne_zero hb) (h b)) (lt_pow_self ha_gt_one b), fun h => by cases h <;> simp [*]⟩ -alias ⟨_, _root_.has_dvd.dvd.multiplicity_pos⟩ := dvd_iff_multiplicity_pos +alias ⟨_, Dvd.multiplicity_pos⟩ := dvd_iff_multiplicity_pos end Monoid @@ -271,36 +421,45 @@ section CommMonoid variable [CommMonoid α] -theorem finite_of_finite_mul_left {a b c : α} : Finite a (b * c) → Finite a c := by - rw [mul_comm]; exact finite_of_finite_mul_right +theorem multiplicity.Finite.mul_right {a b c : α} (hf : Finite a (b * c)) : Finite a c := + (mul_comm b c ▸ hf).mul_left + +theorem emultiplicity_of_isUnit_right {a b : α} (ha : ¬IsUnit a) + (hb : IsUnit b) : emultiplicity a b = 0 := + emultiplicity_eq_zero.mpr fun h ↦ ha (isUnit_of_dvd_unit h hb) + +theorem multiplicity_of_isUnit_right {a b : α} (ha : ¬IsUnit a) + (hb : IsUnit b) : multiplicity a b = 0 := + multiplicity_eq_zero.mpr fun h ↦ ha (isUnit_of_dvd_unit h hb) -variable [DecidableRel ((· ∣ ·) : α → α → Prop)] +theorem emultiplicity_of_one_right {a : α} (ha : ¬IsUnit a) : emultiplicity a 1 = 0 := + emultiplicity_of_isUnit_right ha isUnit_one -theorem isUnit_right {a b : α} (ha : ¬IsUnit a) (hb : IsUnit b) : multiplicity a b = 0 := - eq_coe_iff.2 - ⟨show a ^ 0 ∣ b by simp only [_root_.pow_zero, one_dvd], by - rw [pow_one] - exact fun h => mt (isUnit_of_dvd_unit h) ha hb⟩ +theorem multiplicity_of_one_right {a : α} (ha : ¬IsUnit a) : multiplicity a 1 = 0 := + multiplicity_of_isUnit_right ha isUnit_one -theorem one_right {a : α} (ha : ¬IsUnit a) : multiplicity a 1 = 0 := - isUnit_right ha isUnit_one +theorem emultiplicity_of_unit_right {a : α} (ha : ¬IsUnit a) (u : αˣ) : emultiplicity a u = 0 := + emultiplicity_of_isUnit_right ha u.isUnit -theorem unit_right {a : α} (ha : ¬IsUnit a) (u : αˣ) : multiplicity a u = 0 := - isUnit_right ha u.isUnit +theorem multiplicity_of_unit_right {a : α} (ha : ¬IsUnit a) (u : αˣ) : multiplicity a u = 0 := + multiplicity_of_isUnit_right ha u.isUnit -open scoped Classical +theorem emultiplicity_le_emultiplicity_of_dvd_left {a b c : α} (hdvd : a ∣ b) : + emultiplicity b c ≤ emultiplicity a c := + emultiplicity_le_emultiplicity_iff.2 fun n h => (pow_dvd_pow_of_dvd hdvd n).trans h -theorem multiplicity_le_multiplicity_of_dvd_left {a b c : α} (hdvd : a ∣ b) : - multiplicity b c ≤ multiplicity a c := - multiplicity_le_multiplicity_iff.2 fun n h => (pow_dvd_pow_of_dvd hdvd n).trans h +theorem emultiplicity_eq_of_associated_left {a b c : α} (h : Associated a b) : + emultiplicity b c = emultiplicity a c := + le_antisymm (emultiplicity_le_emultiplicity_of_dvd_left h.dvd) + (emultiplicity_le_emultiplicity_of_dvd_left h.symm.dvd) -theorem eq_of_associated_left {a b c : α} (h : Associated a b) : +theorem multiplicity_eq_of_associated_left {a b c : α} (h : Associated a b) : multiplicity b c = multiplicity a c := - le_antisymm (multiplicity_le_multiplicity_of_dvd_left h.dvd) - (multiplicity_le_multiplicity_of_dvd_left h.symm.dvd) + multiplicity_eq_of_emultiplicity_eq (emultiplicity_eq_of_associated_left h) --- Porting note: this was doing nothing in mathlib3 also --- alias dvd_iff_multiplicity_pos ↔ _ _root_.has_dvd.dvd.multiplicity_pos +theorem emultiplicity_mk_eq_emultiplicity {a b : α} : + emultiplicity (Associates.mk a) (Associates.mk b) = emultiplicity a b := by + simp [emultiplicity_eq_emultiplicity_iff, ← Associates.mk_pow, Associates.mk_dvd_mk] end CommMonoid @@ -308,111 +467,124 @@ section MonoidWithZero variable [MonoidWithZero α] -theorem ne_zero_of_finite {a b : α} (h : Finite a b) : b ≠ 0 := +theorem multiplicity.Finite.ne_zero {a b : α} (h : Finite a b) : b ≠ 0 := let ⟨n, hn⟩ := h fun hb => by simp [hb] at hn -variable [DecidableRel ((· ∣ ·) : α → α → Prop)] +@[simp] +theorem emultiplicity_zero (a : α) : emultiplicity a 0 = ⊤ := + emultiplicity_eq_top.2 (fun v ↦ v.ne_zero rfl) @[simp] -protected theorem zero (a : α) : multiplicity a 0 = ⊤ := - Part.eq_none_iff.2 fun _ ⟨⟨_, hk⟩, _⟩ => hk (dvd_zero _) +theorem emultiplicity_zero_eq_zero_of_ne_zero (a : α) (ha : a ≠ 0) : emultiplicity 0 a = 0 := + emultiplicity_eq_zero.2 <| mt zero_dvd_iff.1 ha @[simp] theorem multiplicity_zero_eq_zero_of_ne_zero (a : α) (ha : a ≠ 0) : multiplicity 0 a = 0 := - multiplicity.multiplicity_eq_zero.2 <| mt zero_dvd_iff.1 ha + multiplicity_eq_zero.2 <| mt zero_dvd_iff.1 ha end MonoidWithZero -section CommMonoidWithZero - -variable [CommMonoidWithZero α] -variable [DecidableRel ((· ∣ ·) : α → α → Prop)] - -theorem multiplicity_mk_eq_multiplicity - [DecidableRel ((· ∣ ·) : Associates α → Associates α → Prop)] {a b : α} : - multiplicity (Associates.mk a) (Associates.mk b) = multiplicity a b := by - by_cases h : Finite a b - · rw [← PartENat.natCast_get (finite_iff_dom.mp h)] - refine - (multiplicity.unique - (show Associates.mk a ^ (multiplicity a b).get h ∣ Associates.mk b from ?_) ?_).symm <;> - rw [← Associates.mk_pow, Associates.mk_dvd_mk] - · exact pow_multiplicity_dvd h - · exact is_greatest - ((PartENat.lt_coe_iff _ _).mpr (Exists.intro (finite_iff_dom.mp h) (Nat.lt_succ_self _))) - · suffices ¬Finite (Associates.mk a) (Associates.mk b) by - rw [finite_iff_dom, PartENat.not_dom_iff_eq_top] at h this - rw [h, this] - refine - not_finite_iff_forall.mpr fun n => by - rw [← Associates.mk_pow, Associates.mk_dvd_mk] - exact not_finite_iff_forall.mp h n - -end CommMonoidWithZero - section Semiring -variable [Semiring α] [DecidableRel ((· ∣ ·) : α → α → Prop)] +variable [Semiring α] -theorem min_le_multiplicity_add {p a b : α} : - min (multiplicity p a) (multiplicity p b) ≤ multiplicity p (a + b) := - (le_total (multiplicity p a) (multiplicity p b)).elim - (fun h ↦ by - rw [min_eq_left h, multiplicity_le_multiplicity_iff] - exact fun n hn => dvd_add hn (multiplicity_le_multiplicity_iff.1 h n hn)) - fun h ↦ by - rw [min_eq_right h, multiplicity_le_multiplicity_iff] - exact fun n hn => dvd_add (multiplicity_le_multiplicity_iff.1 h n hn) hn +theorem multiplicity.Finite.or_of_add {p a b : α} (hf : Finite p (a + b)) : + Finite p a ∨ Finite p b := by + by_contra! nh + obtain ⟨c, hc⟩ := hf + simp_all [dvd_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) + · simp only [top_le_iff, min_eq_top, emultiplicity_eq_top] at hm ⊢ + contrapose hm + simp only [not_and_or, not_not] at hm ⊢ + exact hm.or_of_add + · apply le_emultiplicity_of_pow_dvd + simp [dvd_add, pow_dvd_of_le_emultiplicity, ← hm] end Semiring section Ring -variable [Ring α] [DecidableRel ((· ∣ ·) : α → α → Prop)] +variable [Ring α] @[simp] -protected theorem neg (a b : α) : multiplicity a (-b) = multiplicity a b := - Part.ext' (by simp only [multiplicity, PartENat.find, dvd_neg]) fun h₁ h₂ => - PartENat.natCast_inj.1 (by - rw [PartENat.natCast_get] - exact Eq.symm - (unique (pow_multiplicity_dvd _).neg_right - (mt dvd_neg.1 (is_greatest' _ (lt_succ_self _))))) - -theorem Int.natAbs (a : ℕ) (b : ℤ) : multiplicity a b.natAbs = multiplicity (a : ℤ) b := by - cases' Int.natAbs_eq b with h h <;> conv_rhs => rw [h] - · rw [Int.natCast_multiplicity] - · rw [multiplicity.neg, Int.natCast_multiplicity] - -theorem multiplicity_add_of_gt {p a b : α} (h : multiplicity p b < multiplicity p a) : - multiplicity p (a + b) = multiplicity p b := by - apply le_antisymm - · apply PartENat.le_of_lt_add_one - cases' PartENat.ne_top_iff.mp (PartENat.ne_top_of_lt h) with k hk - rw [hk] - rw_mod_cast [multiplicity_lt_iff_not_dvd, dvd_add_right] - · intro h_dvd - apply multiplicity.is_greatest _ h_dvd - rw [hk, ← Nat.succ_eq_add_one] - norm_cast - apply Nat.lt_succ_self k - · rw [pow_dvd_iff_le_multiplicity, Nat.cast_add, ← hk, Nat.cast_one] - exact PartENat.add_one_le_of_lt h - · have := @min_le_multiplicity_add α _ _ p a b - rwa [← min_eq_right (le_of_lt h)] +theorem multiplicity.Finite.neg_iff {a b : α} : Finite a (-b) ↔ Finite a b := by + unfold Finite + congr! 3 + simp only [dvd_neg] -theorem multiplicity_sub_of_gt {p a b : α} (h : multiplicity p b < multiplicity p a) : - multiplicity p (a - b) = multiplicity p b := by - rw [sub_eq_add_neg, multiplicity_add_of_gt] <;> rw [multiplicity.neg]; assumption +alias ⟨_, multiplicity.Finite.neg⟩ := Finite.neg_iff -theorem multiplicity_add_eq_min {p a b : α} (h : multiplicity p a ≠ multiplicity p b) : +@[simp] +theorem emultiplicity_neg (a b : α) : emultiplicity a (-b) = emultiplicity a b := by + rw [emultiplicity_eq_emultiplicity_iff] + simp + +@[simp] +theorem multiplicity_neg (a b : α) : multiplicity a (-b) = multiplicity a b := + multiplicity_eq_of_emultiplicity_eq (emultiplicity_neg a b) + +theorem Int.emultiplicity_natAbs (a : ℕ) (b : ℤ) : + emultiplicity a b.natAbs = emultiplicity (a : ℤ) b := by + cases' Int.natAbs_eq b with h h <;> conv_rhs => rw [h] + · rw [Int.natCast_emultiplicity] + · rw [emultiplicity_neg, Int.natCast_emultiplicity] + +theorem Int.multiplicity_natAbs (a : ℕ) (b : ℤ) : + multiplicity a b.natAbs = multiplicity (a : ℤ) b := + multiplicity_eq_of_emultiplicity_eq (Int.emultiplicity_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) + rw [this.emultiplicity_eq_multiplicity] at * + apply emultiplicity_eq_of_dvd_of_not_dvd + · apply dvd_add + · apply pow_dvd_of_le_emultiplicity + exact h.le + · simp + · rw [dvd_add_right] + · apply this.not_pow_dvd_of_multiplicity_lt + simp + 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) + (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) + +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 + rw [sub_eq_add_neg, hfin.neg.multiplicity_add_of_gt] <;> rw [multiplicity_neg]; assumption + +theorem emultiplicity_add_eq_min {p a b : α} + (h : emultiplicity p a ≠ emultiplicity p b) : + emultiplicity p (a + b) = min (emultiplicity p a) (emultiplicity p b) := by + rcases lt_trichotomy (emultiplicity p a) (emultiplicity p b) with (hab | _ | hab) + · rw [add_comm, emultiplicity_add_of_gt hab, min_eq_left] + exact le_of_lt hab + · contradiction + · 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) : multiplicity p (a + b) = min (multiplicity p a) (multiplicity p b) := by - rcases lt_trichotomy (multiplicity p a) (multiplicity p b) with (hab | hab | hab) - · rw [add_comm, multiplicity_add_of_gt hab, min_eq_left] + rcases lt_trichotomy (multiplicity p a) (multiplicity p b) with (hab | _ | hab) + · rw [add_comm, ha.multiplicity_add_of_gt hab, min_eq_left] exact le_of_lt hab · contradiction - · rw [multiplicity_add_of_gt hab, min_eq_right] + · rw [hb.multiplicity_add_of_gt hab, min_eq_right] exact le_of_lt hab end Ring @@ -423,7 +595,7 @@ variable [CancelCommMonoidWithZero α] /- Porting note: Pulled a b intro parameters since Lean parses that more easily -/ -theorem finite_mul_aux {p : α} (hp : Prime p) {a b : α} : +theorem multiplicity.finite_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]⟩ @@ -455,102 +627,97 @@ theorem finite_mul_aux {p : α} (hp : Prime p) {a b : α} : 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 finite_mul {p a b : α} (hp : Prime p) : Finite p a → Finite p b → Finite p (a * b) := +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⟩ -theorem finite_mul_iff {p a b : α} (hp : Prime p) : Finite p (a * b) ↔ Finite p a ∧ Finite p b := - ⟨fun h => ⟨finite_of_finite_mul_right h, finite_of_finite_mul_left h⟩, fun h => - finite_mul hp h.1 h.2⟩ +theorem multiplicity.Finite.mul_iff {p a b : α} (hp : Prime p) : + Finite p (a * b) ↔ Finite p a ∧ Finite p b := + ⟨fun h => ⟨h.mul_left, h.mul_right⟩, fun h => + hp.multiplicity_finite_mul h.1 h.2⟩ -theorem finite_pow {p a : α} (hp : Prime p) : ∀ {k : ℕ} (_ : Finite p a), Finite p (a ^ k) +theorem multiplicity.Finite.pow {p a : α} (hp : Prime p) + (hfin : Finite p a) {k : ℕ} : Finite 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 finite_mul hp ha (finite_pow hp ha) - -variable [DecidableRel ((· ∣ ·) : α → α → Prop)] + | k + 1, ha => by rw [_root_.pow_succ']; exact hp.multiplicity_finite_mul ha (ha.pow hp) @[simp] -theorem multiplicity_self {a : α} (ha : ¬IsUnit a) (ha0 : a ≠ 0) : multiplicity a a = 1 := by - rw [← Nat.cast_one] - exact eq_coe_iff.2 ⟨by simp, fun ⟨b, hb⟩ => ha (isUnit_iff_dvd_one.2 - ⟨b, mul_left_cancel₀ ha0 <| by simpa [_root_.pow_succ, mul_assoc] using hb⟩)⟩ +theorem multiplicity_self {a : α} : multiplicity a a = 1 := by + by_cases ha : Finite a a + · rw [ha.multiplicity_eq_iff] + simp only [pow_one, dvd_refl, reduceAdd, true_and] + rintro ⟨v, hv⟩ + nth_rw 1 [← mul_one a] at hv + simp only [sq, mul_assoc, mul_eq_mul_left_iff] at hv + obtain hv | rfl := hv + · have : IsUnit a := isUnit_of_mul_eq_one a v hv.symm + simpa [this] using ha.not_unit + · simpa using ha.ne_zero + · simp [ha] @[simp] -theorem get_multiplicity_self {a : α} (ha : Finite a a) : get (multiplicity a a) ha = 1 := - PartENat.get_eq_iff_eq_coe.2 - (eq_coe_iff.2 - ⟨by simp, fun ⟨b, hb⟩ => by - rw [← mul_one a, pow_add, pow_one, mul_assoc, mul_assoc, - mul_right_inj' (ne_zero_of_finite ha)] at hb - exact mt isUnit_iff_dvd_one.2 (not_unit_of_finite ha) ⟨b, by simp_all⟩⟩) - -protected theorem mul' {p a b : α} (hp : Prime p) (h : (multiplicity p (a * b)).Dom) : - get (multiplicity p (a * b)) h = - get (multiplicity p a) ((finite_mul_iff hp).1 h).1 + - get (multiplicity p b) ((finite_mul_iff hp).1 h).2 := by - have hdiva : p ^ get (multiplicity p a) ((finite_mul_iff hp).1 h).1 ∣ a := pow_multiplicity_dvd _ - have hdivb : p ^ get (multiplicity p b) ((finite_mul_iff hp).1 h).2 ∣ b := pow_multiplicity_dvd _ - have hpoweq : - p ^ (get (multiplicity p a) ((finite_mul_iff hp).1 h).1 + - get (multiplicity p b) ((finite_mul_iff hp).1 h).2) = - p ^ get (multiplicity p a) ((finite_mul_iff hp).1 h).1 * - p ^ get (multiplicity p b) ((finite_mul_iff hp).1 h).2 := by - simp [pow_add] - have hdiv : - p ^ (get (multiplicity p a) ((finite_mul_iff hp).1 h).1 + - get (multiplicity p b) ((finite_mul_iff hp).1 h).2) ∣ - a * b := by - rw [hpoweq]; apply mul_dvd_mul <;> assumption - have hsucc : - ¬p ^ (get (multiplicity p a) ((finite_mul_iff hp).1 h).1 + - get (multiplicity p b) ((finite_mul_iff hp).1 h).2 + - 1) ∣ - a * b := +theorem multiplicity.Finite.emultiplicity_self {a : α} (hfin : Finite 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)) : + 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 .. + have hdiv : p ^ (multiplicity p a + multiplicity p b) ∣ a * b := by + rw [pow_add]; apply mul_dvd_mul <;> assumption + have hsucc : ¬p ^ (multiplicity p a + multiplicity p b + 1) ∣ a * b := fun h => - not_or_intro (is_greatest' _ (lt_succ_self _)) (is_greatest' _ (lt_succ_self _)) + not_or_intro (hfin.mul_left.not_pow_dvd_of_multiplicity_lt (lt_succ_self _)) + (hfin.mul_right.not_pow_dvd_of_multiplicity_lt (lt_succ_self _)) (_root_.succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul hp hdiva hdivb h) - rw [← PartENat.natCast_inj, PartENat.natCast_get, eq_coe_iff]; exact ⟨hdiv, hsucc⟩ - -open scoped Classical - -protected theorem mul {p a b : α} (hp : Prime p) : - multiplicity p (a * b) = multiplicity p a + multiplicity p b := - if h : Finite p a ∧ Finite p b then by - rw [← PartENat.natCast_get (finite_iff_dom.1 h.1), ← - PartENat.natCast_get (finite_iff_dom.1 h.2), ← - PartENat.natCast_get (finite_iff_dom.1 (finite_mul hp h.1 h.2)), ← Nat.cast_add, - PartENat.natCast_inj, multiplicity.mul' hp] - else by - rw [eq_top_iff_not_finite.2 (mt (finite_mul_iff hp).1 h)] - cases' not_and_or.1 h with h h <;> simp [eq_top_iff_not_finite.2 h] - -theorem Finset.prod {β : Type*} {p : α} (hp : Prime p) (s : Finset β) (f : β → α) : - multiplicity p (∏ x ∈ s, f x) = ∑ x ∈ s, multiplicity p (f x) := by - classical + rw [hfin.multiplicity_eq_iff] + exact ⟨hdiv, hsucc⟩ + +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) + · 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 + +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 induction' s using Finset.induction with a s has ih h · simp only [Finset.sum_empty, Finset.prod_empty] - convert one_right hp.not_unit - · simpa [has, ← ih] using multiplicity.mul hp + exact emultiplicity_of_one_right hp.not_unit + · simpa [has, ← ih] using emultiplicity_mul hp --- Porting note: with protected could not use pow' k in the succ branch -protected theorem pow' {p a : α} (hp : Prime p) (ha : Finite p a) : - ∀ {k : ℕ}, get (multiplicity p (a ^ k)) (finite_pow hp ha) = k * get (multiplicity p a) ha := by - intro k +theorem emultiplicity_pow {p a : α} (hp : Prime p) {k : ℕ} : + emultiplicity p (a ^ k) = k * emultiplicity p a := by induction' k with k hk - · simp [one_right hp.not_unit] - · have : multiplicity p (a ^ (k + 1)) = multiplicity p (a * a ^ k) := by rw [_root_.pow_succ'] - rw [get_eq_get_of_eq _ _ this, - multiplicity.mul' hp, hk, add_mul, one_mul, add_comm] + · simp [emultiplicity_of_one_right hp.not_unit] + · simp [pow_succ, emultiplicity_mul hp, hk, add_mul] -theorem pow {p a : α} (hp : Prime p) : ∀ {k : ℕ}, multiplicity p (a ^ k) = k • multiplicity p a - | 0 => by simp [one_right hp.not_unit] - | succ k => by simp [_root_.pow_succ, succ_nsmul, pow hp, multiplicity.mul hp] +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 + exact_mod_cast (ha.pow hp).emultiplicity_eq_multiplicity ▸ + ha.emultiplicity_eq_multiplicity ▸ emultiplicity_pow hp + +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 + · rfl + · rw [pow_dvd_pow_iff h0 hu] + apply Nat.not_succ_le_self theorem multiplicity_pow_self {p : α} (h0 : p ≠ 0) (hu : ¬IsUnit p) (n : ℕ) : - multiplicity p (p ^ n) = n := by - rw [eq_coe_iff] - use dvd_rfl - rw [pow_dvd_pow_iff h0 hu] - apply Nat.not_succ_le_self + multiplicity p (p ^ n) = n := + multiplicity_eq_of_emultiplicity_eq_some (emultiplicity_pow_self h0 hu n) + +theorem emultiplicity_pow_self_of_prime {p : α} (hp : Prime p) (n : ℕ) : + emultiplicity p (p ^ n) = n := + emultiplicity_pow_self hp.ne_zero hp.not_unit n theorem multiplicity_pow_self_of_prime {p : α} (hp : Prime p) (n : ℕ) : multiplicity p (p ^ n) = n := @@ -558,36 +725,32 @@ theorem multiplicity_pow_self_of_prime {p : α} (hp : Prime p) (n : ℕ) : end CancelCommMonoidWithZero -end multiplicity - 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 - rw [multiplicity_le_multiplicity_iff] at hle - rw [← nonpos_iff_eq_zero, ← not_lt, PartENat.pos_iff_one_le, ← Nat.cast_one, ← - pow_dvd_iff_le_multiplicity] - intro h - have := Nat.dvd_gcd h (hle _ h) - rw [Coprime.gcd_eq_one hab, Nat.dvd_one, pow_one] at this + apply Nat.eq_zero_of_not_pos + intro nh + have da : p ∣ a := by simpa [multiplicity_eq_zero] using nh.ne.symm + have db : p ∣ b := by simpa [multiplicity_eq_zero] using (nh.trans_le hle).ne.symm + have := Nat.dvd_gcd da db + rw [Coprime.gcd_eq_one hab, Nat.dvd_one] at this exact hp this end Nat -namespace multiplicity - -theorem finite_int_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 finite_int_iff {a b : ℤ} : Finite a b ↔ a.natAbs ≠ 1 ∧ b ≠ 0 := by - rw [finite_int_iff_natAbs_finite, finite_nat_iff, pos_iff_ne_zero, Int.natAbs_ne_zero] +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] -instance decidableNat : DecidableRel fun a b : ℕ => (multiplicity a b).Dom := fun _ _ => - decidable_of_iff _ finite_nat_iff.symm +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, + pos_iff_ne_zero, Int.natAbs_ne_zero] -instance decidableInt : DecidableRel fun a b : ℤ => (multiplicity a b).Dom := fun _ _ => - decidable_of_iff _ finite_int_iff.symm +instance Nat.decidableMultiplicityFinite : DecidableRel fun a b : ℕ => Finite a b := fun _ _ => + decidable_of_iff' _ Nat.multiplicity_finite_iff -end multiplicity +instance Int.decidableMultiplicityFinite : DecidableRel fun a b : ℤ => Finite a b := fun _ _ => + decidable_of_iff' _ Int.multiplicity_finite_iff diff --git a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean index 4772bb3e6107b..64a1bbcd81c41 100644 --- a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean @@ -64,7 +64,7 @@ def homogeneousSubmodule (n : ℕ) : Submodule R (MvPolynomial σ R) where apply hc rw [h] exact smul_zero r - zero_mem' d hd := False.elim (hd <| coeff_zero _) + zero_mem' _ hd := False.elim (hd <| coeff_zero _) add_mem' {a b} ha hb c hc := by rw [coeff_add] at hc obtain h | h : coeff c a ≠ 0 ∨ coeff c b ≠ 0 := by @@ -457,8 +457,7 @@ theorem coeff_homogeneousComponent (d : σ →₀ ℕ) : convert coeff_weightedHomogeneousComponent n φ d theorem homogeneousComponent_apply : - homogeneousComponent n φ = - ∑ d ∈ φ.support.filter fun d => d.degree = n, monomial d (coeff d φ) := by + homogeneousComponent n φ = ∑ d ∈ φ.support with d.degree = n, monomial d (coeff d φ) := by simp_rw [degree_eq_weight_one] convert weightedHomogeneousComponent_apply n φ diff --git a/Mathlib/RingTheory/MvPolynomial/Localization.lean b/Mathlib/RingTheory/MvPolynomial/Localization.lean index 9f1b0b51970ce..2a8977ca29026 100644 --- a/Mathlib/RingTheory/MvPolynomial/Localization.lean +++ b/Mathlib/RingTheory/MvPolynomial/Localization.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Christian Merten -/ import Mathlib.Algebra.MvPolynomial.CommRing -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Localization.Away.Basic import Mathlib.RingTheory.Localization.Basic import Mathlib.RingTheory.MvPolynomial.Basic @@ -91,13 +91,13 @@ private noncomputable def auxHom : (MvPolynomial Unit R) ⧸ (Ideal.span { C r * X () - 1 }) →ₐ[R] S := Ideal.Quotient.liftₐ (Ideal.span { C r * X () - 1}) (aeval (fun _ ↦ invSelf r)) <| by intro p hp - refine Submodule.span_induction hp ?_ ?_ ?_ ?_ + refine Submodule.span_induction ?_ ?_ ?_ ?_ hp · rintro p ⟨q, rfl⟩ simp · simp - · intro p q hp hq + · intro p q _ _ hp hq simp [hp, hq] - · intro a x hx + · intro a x _ hx simp [hx] @[simp] diff --git a/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean index 691265878f204..093790197e63a 100644 --- a/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean +++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean @@ -71,6 +71,15 @@ theorem _root_.Finset.esymm_map_val {σ} (f : σ → R) (s : Finset σ) (n : ℕ simp only [esymm, powersetCard_map, ← Finset.map_val_val_powersetCard, map_map] rfl +lemma pow_smul_esymm {S : Type*} [Monoid S] [DistribMulAction S R] [IsScalarTower S R R] + [SMulCommClass S R R] (s : S) (n : ℕ) (m : Multiset R) : + s ^ n • m.esymm n = (m.map (s • ·)).esymm n := by + rw [esymm, smul_sum, map_map] + trans ((powersetCard n m).map (fun x : Multiset R ↦ s ^ card x • x.prod)).sum + · refine congr_arg _ (map_congr rfl (fun x hx ↦ ?_)) + rw [Function.comp_apply, (mem_powersetCard.1 hx).2] + · simp_rw [smul_prod, esymm, powersetCard_map, map_map, Function.comp_def] + end Multiset namespace MvPolynomial @@ -189,7 +198,7 @@ theorem aeval_esymm_eq_multiset_esymm [Algebra R S] (n : ℕ) (f : σ → S) : /-- We can define `esymm σ R n` by summing over a subtype instead of over `powerset_len`. -/ theorem esymm_eq_sum_subtype (n : ℕ) : - esymm σ R n = ∑ t : { s : Finset σ // s.card = n }, ∏ i ∈ (t : Finset σ), X i := + esymm σ R n = ∑ t : {s : Finset σ // #s = n}, ∏ i ∈ (t : Finset σ), X i := sum_subtype _ (fun _ => mem_powersetCard_univ) _ /-- We can define `esymm σ R n` as a sum over explicit monomials -/ diff --git a/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean index b003422369bc5..b822840d8c9ce 100644 --- a/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean +++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean @@ -60,8 +60,8 @@ section accumulate /-- The `j`th entry of `accumulate n m t` is the sum of `t i` over all `i ≥ j`. -/ @[simps] def accumulate (n m : ℕ) : (Fin n → ℕ) →+ (Fin m → ℕ) where - toFun t j := ∑ i in univ.filter (fun i : Fin n ↦ (j : ℕ) ≤ i), t i - map_zero' := funext <| fun j ↦ sum_eq_zero <| fun h _ ↦ rfl + toFun t j := ∑ i : Fin n with j.val ≤ i.val, t i + map_zero' := funext <| fun _ ↦ sum_eq_zero <| fun _ _ ↦ rfl map_add' t₁ t₂ := funext <| fun j ↦ by dsimp only; exact sum_add_distrib /-- The `i`th entry of `invAccumulate n m s` is `s i - s (i+1)`, where `s j = 0` if `j ≥ m`. -/ @@ -146,7 +146,7 @@ variable (σ) in noncomputable def esymmAlgHomMonomial (t : Fin n →₀ ℕ) (r : R) : MvPolynomial σ R := (esymmAlgHom σ R n <| monomial t r).val -variable {i : Fin n} {j : Fin m} {r : R} +variable {i : Fin n} {r : R} lemma isSymmetric_esymmAlgHomMonomial (t : Fin n →₀ ℕ) (r : R) : (esymmAlgHomMonomial σ t r).IsSymmetric := (esymmAlgHom _ _ _ _).2 @@ -178,7 +178,7 @@ private lemma supDegree_monic_esymm [Nontrivial R] {i : ℕ} (him : i < m) : supDegree_single_ne_zero _ one_ne_zero, leadingCoeff_single toLex.injective] at this · exact mem_powersetCard.2 ⟨subset_univ _, Fin.card_Iic _⟩ intro t ht hne - have ht' : t.card = (Iic (⟨i, him⟩ : Fin m)).card := by + have ht' : #t = #(Iic (⟨i, him⟩ : Fin m)) := by rw [(mem_powersetCard.1 ht).2, Fin.card_Iic] simp_rw [← single_eq_monomial, supDegree_single_ne_zero _ one_ne_zero, ← Finsupp.indicator_eq_sum_single] diff --git a/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean index 3aa09ead7b4ab..802d25319935b 100644 --- a/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean +++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean @@ -87,15 +87,15 @@ private theorem pairMap_involutive : (pairMap σ).Involutive := by variable [Fintype σ] private def pairs (k : ℕ) : Finset (Finset σ × σ) := - univ.filter (fun t ↦ card t.fst ≤ k ∧ (card t.fst = k → t.snd ∈ t.fst)) + {t | #t.1 ≤ k ∧ (#t.1 = k → t.snd ∈ t.fst)} @[simp] private lemma mem_pairs (k : ℕ) (t : Finset σ × σ) : - t ∈ pairs σ k ↔ card t.fst ≤ k ∧ (card t.fst = k → t.snd ∈ t.fst) := by + t ∈ pairs σ k ↔ #t.1 ≤ k ∧ (#t.1 = k → t.snd ∈ t.fst) := by simp [pairs] private def weight (k : ℕ) (t : Finset σ × σ) : MvPolynomial σ R := - (-1) ^ card t.fst * ((∏ a ∈ t.fst, X a) * X t.snd ^ (k - card t.fst)) + (-1) ^ #t.1 * ((∏ a ∈ t.fst, X a) * X t.snd ^ (k - #t.1)) private theorem pairMap_mem_pairs {k : ℕ} (t : Finset σ × σ) (h : t ∈ pairs σ k) : pairMap σ t ∈ pairs σ k := by @@ -126,16 +126,16 @@ private theorem weight_add_weight_pairMap {k : ℕ} (t : Finset σ × σ) (h : t mul_assoc (∏ a ∈ erase t.fst t.snd, X a), card_erase_of_mem h1] nth_rewrite 1 [← pow_one (X t.snd)] simp only [← pow_add, add_comm] - have h3 : 1 ≤ card t.fst := lt_iff_add_one_le.mp (card_pos.mpr ⟨t.snd, h1⟩) - rw [← tsub_tsub_assoc h.left h3, ← neg_neg ((-1 : MvPolynomial σ R) ^ (card t.fst - 1)), - h2 (card t.fst - 1), Nat.sub_add_cancel h3] + have h3 : 1 ≤ #t.1 := lt_iff_add_one_le.mp (card_pos.mpr ⟨t.snd, h1⟩) + rw [← tsub_tsub_assoc h.left h3, ← neg_neg ((-1 : MvPolynomial σ R) ^ (#t.1 - 1)), + h2 (#t.1 - 1), Nat.sub_add_cancel h3] simp · rw [pairMap_of_snd_nmem_fst σ h1] simp only [mul_comm, mul_assoc (∏ a ∈ t.fst, X a), card_cons, prod_cons] nth_rewrite 2 [← pow_one (X t.snd)] simp only [← pow_add, ← Nat.add_sub_assoc (Nat.lt_of_le_of_ne h.left (mt h.right h1)), add_comm, Nat.succ_eq_add_one, Nat.add_sub_add_right] - rw [← neg_neg ((-1 : MvPolynomial σ R) ^ card t.fst), h2] + rw [← neg_neg ((-1 : MvPolynomial σ R) ^ #t.1), h2] simp private theorem weight_sum (k : ℕ) : ∑ t ∈ pairs σ k, weight σ R k t = 0 := @@ -145,45 +145,40 @@ private theorem weight_sum (k : ℕ) : ∑ t ∈ pairs σ k, weight σ R k t = 0 private theorem sum_filter_pairs_eq_sum_powersetCard_sum (k : ℕ) (f : Finset σ × σ → MvPolynomial σ R) : - (∑ t ∈ filter (fun t ↦ card t.fst = k) (pairs σ k), f t) = - ∑ A ∈ powersetCard k univ, (∑ j ∈ A, f (A, j)) := by + ∑ t ∈ pairs σ k with #t.1 = k, f t = ∑ A ∈ powersetCard k univ, ∑ j ∈ A, f (A, j) := by apply sum_finset_product aesop private theorem sum_filter_pairs_eq_sum_powersetCard_mem_filter_antidiagonal_sum (k : ℕ) (a : ℕ × ℕ) - (ha : a ∈ (antidiagonal k).filter (fun a ↦ a.fst < k)) (f : Finset σ × σ → MvPolynomial σ R) : - (∑ t ∈ filter (fun t ↦ card t.fst = a.fst) (pairs σ k), f t) = - ∑ A ∈ powersetCard a.fst univ, (∑ j, f (A, j)) := by + (ha : a ∈ {a ∈ antidiagonal k | a.fst < k}) (f : Finset σ × σ → MvPolynomial σ R) : + ∑ t ∈ pairs σ k with #t.1 = a.1, f t = ∑ A ∈ powersetCard a.1 univ, ∑ j, f (A, j) := by apply sum_finset_product simp only [mem_filter, mem_powersetCard_univ, mem_univ, and_true, and_iff_right_iff_imp] rintro p hp - have : card p.fst ≤ k := by apply le_of_lt; aesop + have : #p.fst ≤ k := by apply le_of_lt; aesop aesop private lemma filter_pairs_lt (k : ℕ) : - (pairs σ k).filter (fun (s, _) ↦ s.card < k) = + (pairs σ k).filter (fun (s, _) ↦ #s < k) = (range k).disjiUnion (powersetCard · univ) ((pairwise_disjoint_powersetCard _).set_pairwise _) ×ˢ univ := by ext; aesop (add unsafe le_of_lt) private theorem sum_filter_pairs_eq_sum_filter_antidiagonal_powersetCard_sum (k : ℕ) (f : Finset σ × σ → MvPolynomial σ R) : - ∑ t ∈ (pairs σ k).filter fun t ↦ card t.fst < k, f t = - ∑ a ∈ (antidiagonal k).filter fun a ↦ a.fst < k, - ∑ A ∈ powersetCard a.fst univ, ∑ j, f (A, j) := by + ∑ t ∈ pairs σ k with #t.1 < k, f t = + ∑ a ∈ antidiagonal k with a.fst < k, ∑ A ∈ powersetCard a.fst univ, ∑ j, f (A, j) := by rw [filter_pairs_lt, sum_product, sum_disjiUnion] refine sum_nbij' (fun n ↦ (n, k - n)) Prod.fst ?_ ?_ ?_ ?_ ?_ <;> simp (config := { contextual := true }) [@eq_comm _ _ k, Nat.add_sub_cancel', le_of_lt] private theorem disjoint_filter_pairs_lt_filter_pairs_eq (k : ℕ) : - Disjoint (filter (fun t ↦ card t.fst < k) (pairs σ k)) - (filter (fun t ↦ card t.fst = k) (pairs σ k)) := by + Disjoint {t ∈ pairs σ k | #t.1 < k} {t ∈ pairs σ k | #t.1 = k} := by rw [disjoint_filter] exact fun _ _ h1 h2 ↦ lt_irrefl _ (h2.symm.subst h1) private theorem disjUnion_filter_pairs_eq_pairs (k : ℕ) : - disjUnion (filter (fun t ↦ card t.fst < k) (pairs σ k)) - (filter (fun t ↦ card t.fst = k) (pairs σ k)) (disjoint_filter_pairs_lt_filter_pairs_eq σ k) = - pairs σ k := by + disjUnion {t ∈ pairs σ k | #t.1 < k} {t ∈ pairs σ k | #t.1 = k} + (disjoint_filter_pairs_lt_filter_pairs_eq σ k) = pairs σ k := by simp only [disjUnion_eq_union, Finset.ext_iff, pairs, filter_filter, mem_filter] intro a rw [← filter_or, mem_filter] @@ -200,7 +195,7 @@ private theorem esymm_summand_to_weight (k : ℕ) (A : Finset σ) (h : A ∈ pow simp [weight, mem_powersetCard_univ.mp h, mul_assoc] private theorem esymm_to_weight [DecidableEq σ] (k : ℕ) : k * esymm σ R k = - (-1) ^ k * ∑ t ∈ filter (fun t ↦ card t.fst = k) (pairs σ k), weight σ R k t := by + (-1) ^ k * ∑ t ∈ pairs σ k with #t.1 = k, weight σ R k t := by rw [esymm, sum_filter_pairs_eq_sum_powersetCard_sum σ R k (fun t ↦ weight σ R k t), sum_congr rfl (esymm_summand_to_weight σ R k), mul_comm (k : MvPolynomial σ R) ((-1) ^ k), ← mul_sum, ← mul_assoc, ← mul_assoc, ← pow_add, Even.neg_one_pow ⟨k, rfl⟩, one_mul] @@ -216,9 +211,8 @@ private theorem esymm_mul_psum_summand_to_weight (k : ℕ) (a : ℕ × ℕ) (ha rw [mem_powersetCard_univ.mp hs, ← mem_antidiagonal.mp ha, add_sub_self_left] private theorem esymm_mul_psum_to_weight [DecidableEq σ] (k : ℕ) : - ∑ a ∈ (antidiagonal k).filter (fun a ↦ a.fst < k), - (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd = - ∑ t ∈ filter (fun t ↦ card t.fst < k) (pairs σ k), weight σ R k t := by + ∑ a ∈ antidiagonal k with a.fst < k, (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd = + ∑ t ∈ pairs σ k with #t.1 < k, weight σ R k t := by rw [← sum_congr rfl (fun a ha ↦ esymm_mul_psum_summand_to_weight σ R k a (mem_filter.mp ha).left), sum_filter_pairs_eq_sum_filter_antidiagonal_powersetCard_sum σ R k] @@ -228,9 +222,9 @@ variable (σ : Type*) [Fintype σ] (R : Type*) [CommRing R] /-- **Newton's identities** give a recurrence relation for the kth elementary symmetric polynomial in terms of lower degree elementary symmetric polynomials and power sums. -/ -theorem mul_esymm_eq_sum (k : ℕ) : k * esymm σ R k = - (-1) ^ (k + 1) * ∑ a ∈ (antidiagonal k).filter (fun a ↦ a.fst < k), - (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd := by +theorem mul_esymm_eq_sum (k : ℕ) : + k * esymm σ R k = (-1) ^ (k + 1) * + ∑ a ∈ antidiagonal k with a.1 < k, (-1) ^ a.1 * esymm σ R a.1 * psum σ R a.2 := by classical rw [NewtonIdentities.esymm_to_weight σ R k, NewtonIdentities.esymm_mul_psum_to_weight σ R k, eq_comm, ← sub_eq_zero, sub_eq_add_neg, neg_mul_eq_neg_mul, @@ -252,23 +246,22 @@ theorem sum_antidiagonal_card_esymm_psum_eq_zero : /-- A version of Newton's identities which may be more useful in the case that we know the values of the elementary symmetric polynomials and would like to calculate the values of the power sums. -/ -theorem psum_eq_mul_esymm_sub_sum (k : ℕ) (h : 0 < k) : psum σ R k = - (-1) ^ (k + 1) * k * esymm σ R k - - ∑ a ∈ (antidiagonal k).filter (fun a ↦ a.fst ∈ Set.Ioo 0 k), - (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd := by +theorem psum_eq_mul_esymm_sub_sum (k : ℕ) (h : 0 < k) : + psum σ R k = (-1) ^ (k + 1) * k * esymm σ R k - + ∑ a ∈ antidiagonal k with a.1 ∈ Set.Ioo 0 k, (-1) ^ a.fst * esymm σ R a.1 * psum σ R a.2 := by simp only [Set.Ioo, Set.mem_setOf_eq, and_comm] have hesymm := mul_esymm_eq_sum σ R k - rw [← (sum_filter_add_sum_filter_not ((antidiagonal k).filter (fun a ↦ a.fst < k)) + rw [← (sum_filter_add_sum_filter_not {a ∈ antidiagonal k | a.fst < k} (fun a ↦ 0 < a.fst) (fun a ↦ (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd))] at hesymm have sub_both_sides := congrArg (· - (-1 : MvPolynomial σ R) ^ (k + 1) * - ∑ a ∈ ((antidiagonal k).filter (fun a ↦ a.fst < k)).filter (fun a ↦ 0 < a.fst), + ∑ a ∈ {a ∈ antidiagonal k | a.fst < k} with 0 < a.fst, (-1) ^ a.fst * esymm σ R a.fst * psum σ R a.snd) hesymm simp only [left_distrib, add_sub_cancel_left] at sub_both_sides have sub_both_sides := congrArg ((-1 : MvPolynomial σ R) ^ (k + 1) * ·) sub_both_sides simp only [mul_sub_left_distrib, ← mul_assoc, ← pow_add, Even.neg_one_pow ⟨k + 1, rfl⟩, one_mul, not_le, lt_one_iff, filter_filter (fun a : ℕ × ℕ ↦ a.fst < k) (fun a ↦ ¬0 < a.fst)] at sub_both_sides - have : filter (fun a ↦ a.fst < k ∧ ¬0 < a.fst) (antidiagonal k) = {(0, k)} := by + have : {a ∈ antidiagonal k | a.fst < k ∧ ¬0 < a.fst} = {(0, k)} := by ext a rw [mem_filter, mem_antidiagonal, mem_singleton] refine ⟨?_, by rintro rfl; omega⟩ diff --git a/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean b/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean index a5d6459f7d56f..18bd357e9e117 100644 --- a/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean @@ -130,7 +130,7 @@ def weightedHomogeneousSubmodule (w : σ → M) (m : M) : Submodule R (MvPolynom smul_mem' r a ha c hc := by rw [coeff_smul] at hc exact ha (right_ne_zero_of_mul hc) - zero_mem' d hd := False.elim (hd <| coeff_zero _) + zero_mem' _ hd := False.elim (hd <| coeff_zero _) add_mem' {a} {b} ha hb c hc := by rw [coeff_add] at hc obtain h | h : coeff c a ≠ 0 ∨ coeff c b ≠ 0 := by @@ -309,7 +309,7 @@ theorem coeff_weightedHomogeneousComponent [DecidableEq M] (d : σ →₀ ℕ) : theorem weightedHomogeneousComponent_apply [DecidableEq M] : weightedHomogeneousComponent w n φ = - ∑ d ∈ φ.support.filter fun d => weight w d = n, monomial d (coeff d φ) := + ∑ d ∈ φ.support with weight w d = n, monomial d (coeff d φ) := letI := Classical.decEq M Finsupp.filter_eq_sum (fun d : σ →₀ ℕ => weight w d = n) φ |>.trans <| by convert rfl diff --git a/Mathlib/RingTheory/MvPowerSeries/Basic.lean b/Mathlib/RingTheory/MvPowerSeries/Basic.lean index 3e649d881d0c8..a9a882a935dd4 100644 --- a/Mathlib/RingTheory/MvPowerSeries/Basic.lean +++ b/Mathlib/RingTheory/MvPowerSeries/Basic.lean @@ -177,8 +177,7 @@ theorem eq_of_coeff_monomial_ne_zero {m n : σ →₀ ℕ} {a : R} (h : coeff R theorem coeff_comp_monomial (n : σ →₀ ℕ) : (coeff R n).comp (monomial R n) = LinearMap.id := LinearMap.ext <| coeff_monomial_same n --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem coeff_zero (n : σ →₀ ℕ) : coeff R n (0 : MvPowerSeries σ R) = 0 := rfl @@ -434,13 +433,11 @@ theorem constantCoeff_C (a : R) : constantCoeff σ R (C σ R a) = a := theorem constantCoeff_comp_C : (constantCoeff σ R).comp (C σ R) = RingHom.id R := rfl --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem constantCoeff_zero : constantCoeff σ R 0 = 0 := rfl --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem constantCoeff_one : constantCoeff σ R 1 = 1 := rfl @@ -454,8 +451,7 @@ theorem isUnit_constantCoeff (φ : MvPowerSeries σ R) (h : IsUnit φ) : IsUnit (constantCoeff σ R φ) := h.map _ --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem coeff_smul (f : MvPowerSeries σ R) (n) (a : R) : coeff _ n (a • f) = a * coeff _ n f := rfl @@ -671,7 +667,7 @@ theorem coeff_eq_zero_of_constantCoeff_nilpotent apply sum_eq_zero intro k hk rw [mem_finsuppAntidiag] at hk - set s := (range n).filter fun i ↦ k i = 0 with hs_def + set s := {i ∈ range n | k i = 0} with hs_def have hs : s ⊆ range n := filter_subset _ _ have hs' (i : ℕ) (hi : i ∈ s) : coeff R (k i) f = constantCoeff σ R f := by simp only [hs_def, mem_filter] at hi @@ -682,10 +678,10 @@ theorem coeff_eq_zero_of_constantCoeff_nilpotent rw [← prod_sdiff (s₁ := s) (filter_subset _ _)] apply mul_eq_zero_of_right rw [prod_congr rfl hs', prod_const] - suffices m ≤ s.card by + suffices m ≤ #s by obtain ⟨m', hm'⟩ := Nat.exists_eq_add_of_le this rw [hm', pow_add, hf, MulZeroClass.zero_mul] - rw [← Nat.add_le_add_iff_right, add_comm s.card, + rw [← Nat.add_le_add_iff_right, add_comm #s, Finset.card_sdiff_add_card_eq_card (filter_subset _ _), card_range] apply le_trans _ hn simp only [add_comm m, Nat.add_le_add_iff_right, ← hk.1, diff --git a/Mathlib/RingTheory/MvPowerSeries/Inverse.lean b/Mathlib/RingTheory/MvPowerSeries/Inverse.lean index a7e076eb389ea..db252318811bf 100644 --- a/Mathlib/RingTheory/MvPowerSeries/Inverse.lean +++ b/Mathlib/RingTheory/MvPowerSeries/Inverse.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Kenny Lau -/ -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.RingTheory.MvPowerSeries.Basic import Mathlib.RingTheory.MvPowerSeries.NoZeroDivisors -import Mathlib.RingTheory.LocalRing.RingHom.Basic +import Mathlib.RingTheory.LocalRing.Basic /-! # Formal (multivariate) power series - Inverses @@ -31,7 +31,7 @@ Instances are defined: * Formal power series over a local ring form a local ring. * The morphism `MvPowerSeries.map σ f : MvPowerSeries σ A →* MvPowerSeries σ B` - induced by a local morphism `f : A →+* B` (`IsLocalRingHom f`) + induced by a local morphism `f : A →+* B` (`IsLocalHom f`) of commutative rings is a *local* morphism. -/ @@ -167,13 +167,14 @@ end CommRing section LocalRing -variable {S : Type*} [CommRing R] [CommRing S] (f : R →+* S) [IsLocalRingHom f] +variable {S : Type*} [CommRing R] [CommRing S] (f : R →+* S) [IsLocalHom f] -- Thanks to the linter for informing us that this instance does -- not actually need R and S to be local rings! /-- The map between multivariate formal power series over the same indexing set induced by a local ring hom `A → B` is local -/ -instance map.isLocalRingHom : IsLocalRingHom (map σ f) := +@[instance] +theorem map.isLocalHom : IsLocalHom (map σ f) := ⟨by rintro φ ⟨ψ, h⟩ replace h := congr_arg (constantCoeff σ S) h @@ -183,6 +184,9 @@ instance map.isLocalRingHom : IsLocalRingHom (map σ f) := rcases isUnit_of_map_unit f _ this with ⟨c, hc⟩ exact isUnit_of_mul_eq_one φ (invOfUnit φ c) (mul_invOfUnit φ c hc.symm)⟩ +@[deprecated (since := "2024-10-10")] +alias map.isLocalRingHom := map.isLocalHom + end LocalRing section Field @@ -224,8 +228,7 @@ theorem inv_eq_zero {φ : MvPowerSeries σ k} : φ⁻¹ = 0 ↔ constantCoeff σ theorem zero_inv : (0 : MvPowerSeries σ k)⁻¹ = 0 := by rw [inv_eq_zero, constantCoeff_zero] --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem invOfUnit_eq (φ : MvPowerSeries σ k) (h : constantCoeff σ k φ ≠ 0) : invOfUnit φ (Units.mk0 _ h) = φ⁻¹ := rfl diff --git a/Mathlib/RingTheory/Nilpotent/Basic.lean b/Mathlib/RingTheory/Nilpotent/Basic.lean index 0080e768a4300..9eddb6417010a 100644 --- a/Mathlib/RingTheory/Nilpotent/Basic.lean +++ b/Mathlib/RingTheory/Nilpotent/Basic.lean @@ -7,7 +7,7 @@ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Group.Action.Prod import Mathlib.Algebra.GroupWithZero.NonZeroDivisors -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.NoZeroSMulDivisors.Defs import Mathlib.Algebra.SMulWithZero import Mathlib.Data.Nat.Choose.Sum import Mathlib.Data.Nat.Lattice @@ -82,6 +82,15 @@ theorem IsNilpotent.isUnit_add_right_of_commute [Ring R] {r u : R} IsUnit (r + u) := add_comm r u ▸ hnil.isUnit_add_left_of_commute hu h_comm +lemma IsUnit.not_isNilpotent [Ring R] [Nontrivial R] {x : R} (hx : IsUnit x) : + ¬ IsNilpotent x := by + intro H + simpa using H.isUnit_add_right_of_commute hx.neg (by simp) + +lemma IsNilpotent.not_isUnit [Ring R] [Nontrivial R] {x : R} (hx : IsNilpotent x) : + ¬ IsUnit x := + mt IsUnit.not_isNilpotent (by simpa only [not_not] using hx) + instance [Zero R] [Pow R ℕ] [Zero S] [Pow S ℕ] [IsReduced R] [IsReduced S] : IsReduced (R × S) where eq_zero _ := fun ⟨n, hn⟩ ↦ have hn := Prod.ext_iff.1 hn Prod.ext (IsReduced.eq_zero _ ⟨n, hn.1⟩) (IsReduced.eq_zero _ ⟨n, hn.2⟩) diff --git a/Mathlib/RingTheory/Nilpotent/Lemmas.lean b/Mathlib/RingTheory/Nilpotent/Lemmas.lean index fdbae3b577172..cfafb9cea8b59 100644 --- a/Mathlib/RingTheory/Nilpotent/Lemmas.lean +++ b/Mathlib/RingTheory/Nilpotent/Lemmas.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ import Mathlib.LinearAlgebra.Matrix.ToLin -import Mathlib.LinearAlgebra.Quotient +import Mathlib.LinearAlgebra.Quotient.Basic import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Nilpotent.Defs diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean index 62188f744de54..54ede4abbaac0 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -112,9 +112,15 @@ theorem isNoetherian_of_surjective (f : M →ₗ[R] P) (hf : LinearMap.range f = variable {M} -instance isNoetherian_quotient {R} [Ring R] {M} [AddCommGroup M] [Module R M] - (N : Submodule R M) [IsNoetherian R M] : IsNoetherian R (M ⧸ N) := - isNoetherian_of_surjective _ _ (LinearMap.range_eq_top.mpr N.mkQ_surjective) +instance isNoetherian_range (f : M →ₗ[R] P) [IsNoetherian R M] : + IsNoetherian R (LinearMap.range f) := + isNoetherian_of_surjective _ _ f.range_rangeRestrict + +instance isNoetherian_quotient {A M : Type*} [Ring A] [AddCommGroup M] [SMul R A] [Module R M] + [Module A M] [IsScalarTower R A M] (N : Submodule A M) [IsNoetherian R M] : + IsNoetherian R (M ⧸ N) := + isNoetherian_of_surjective M ((Submodule.mkQ N).restrictScalars R) <| + LinearMap.range_eq_top.mpr N.mkQ_surjective @[deprecated (since := "2024-04-27"), nolint defLemma] alias Submodule.Quotient.isNoetherian := isNoetherian_quotient @@ -122,10 +128,11 @@ alias Submodule.Quotient.isNoetherian := isNoetherian_quotient theorem isNoetherian_of_linearEquiv (f : M ≃ₗ[R] P) [IsNoetherian R M] : IsNoetherian R P := isNoetherian_of_surjective _ f.toLinearMap f.range -theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by - constructor <;> intro h - · exact isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl) - · exact isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl).symm +theorem LinearEquiv.isNoetherian_iff (f : M ≃ₗ[R] P) : IsNoetherian R M ↔ IsNoetherian R P := + ⟨fun _ ↦ isNoetherian_of_linearEquiv f, fun _ ↦ isNoetherian_of_linearEquiv f.symm⟩ + +theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := + Submodule.topEquiv.isNoetherian_iff theorem isNoetherian_of_injective [IsNoetherian R P] (f : M →ₗ[R] P) (hf : Function.Injective f) : IsNoetherian R M := @@ -188,8 +195,15 @@ instance isNoetherian_prod [IsNoetherian R M] [IsNoetherian R P] : IsNoetherian fun x ⟨_, hx2⟩ => ⟨x.1, Prod.ext rfl <| Eq.symm <| LinearMap.mem_ker.1 hx2⟩ Submodule.map_comap_eq_self this ▸ (noetherian _).map _⟩ -instance isNoetherian_pi {R ι : Type*} [Finite ι] : - ∀ {M : ι → Type*} [Ring R] [∀ i, AddCommGroup (M i)] +instance isNoetherian_sup (M₁ M₂ : Submodule R P) [IsNoetherian R M₁] [IsNoetherian R M₂] : + IsNoetherian R ↥(M₁ ⊔ M₂) := by + have := isNoetherian_range (M₁.subtype.coprod M₂.subtype) + rwa [LinearMap.range_coprod, Submodule.range_subtype, Submodule.range_subtype] at this + +variable {ι : Type*} [Finite ι] + +instance isNoetherian_pi : + ∀ {M : ι → Type*} [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [∀ i, IsNoetherian R (M i)], IsNoetherian R (∀ i, M i) := by apply Finite.induction_empty_option _ _ _ ι · exact fun e h ↦ isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R _ e) @@ -199,10 +213,16 @@ instance isNoetherian_pi {R ι : Type*} [Finite ι] : /-- A version of `isNoetherian_pi` for non-dependent functions. We need this instance because sometimes Lean fails to apply the dependent version in non-dependent settings (e.g., it fails to prove that `ι → ℝ` is finite dimensional over `ℝ`). -/ -instance isNoetherian_pi' {R ι M : Type*} [Ring R] [AddCommGroup M] [Module R M] [Finite ι] - [IsNoetherian R M] : IsNoetherian R (ι → M) := +instance isNoetherian_pi' [IsNoetherian R M] : IsNoetherian R (ι → M) := isNoetherian_pi +instance isNoetherian_iSup : + ∀ {M : ι → Submodule R P} [∀ i, IsNoetherian R (M i)], IsNoetherian R ↥(⨆ i, M i) := by + apply Finite.induction_empty_option _ _ _ ι + · intro _ _ e h _ _; rw [← e.iSup_comp]; apply h + · intros; rw [iSup_of_empty]; infer_instance + · intro _ _ ih _ _; rw [iSup_option]; infer_instance + end section CommRing @@ -229,19 +249,19 @@ universe w variable {R M P : Type*} {N : Type w} [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid N] [Module R N] [AddCommMonoid P] [Module R P] -theorem isNoetherian_iff : - IsNoetherian R M ↔ WellFounded ((· > ·) : Submodule R M → Submodule R M → Prop) := by - have := (CompleteLattice.wellFounded_characterisations <| Submodule R M).out 0 3 +theorem isNoetherian_iff' : IsNoetherian R M ↔ WellFoundedGT (Submodule R M) := by + have := (CompleteLattice.wellFoundedGT_characterisations <| Submodule R M).out 0 3 -- Porting note: inlining this makes rw complain about it being a metavariable rw [this] exact ⟨fun ⟨h⟩ => fun k => (fg_iff_compact k).mp (h k), fun h => ⟨fun k => (fg_iff_compact k).mpr (h k)⟩⟩ -alias ⟨IsNoetherian.wf, _⟩ := isNoetherian_iff +theorem isNoetherian_iff : + IsNoetherian R M ↔ WellFounded ((· > ·) : Submodule R M → Submodule R M → Prop) := by + rw [isNoetherian_iff', ← isWellFounded_iff] -theorem isNoetherian_iff' : IsNoetherian R M ↔ WellFoundedGT (Submodule R M) := by - rw [isNoetherian_iff, ← isWellFounded_iff] +alias ⟨IsNoetherian.wf, _⟩ := isNoetherian_iff alias ⟨IsNoetherian.wellFoundedGT, isNoetherian_mk⟩ := isNoetherian_iff' @@ -303,14 +323,13 @@ variable {R M P : Type*} {N : Type w} [Ring R] [AddCommGroup M] [Module R M] [Ad lemma Submodule.finite_ne_bot_of_independent {ι : Type*} {N : ι → Submodule R M} (h : CompleteLattice.Independent N) : Set.Finite {i | N i ≠ ⊥} := - CompleteLattice.WellFounded.finite_ne_bot_of_independent - (IsWellFounded.wf) h + CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent h /-- A linearly-independent family of vectors in a module over a non-trivial ring must be finite if the module is Noetherian. -/ theorem LinearIndependent.finite_of_isNoetherian [Nontrivial R] {ι} {v : ι → M} (hv : LinearIndependent R v) : Finite ι := by - refine CompleteLattice.WellFounded.finite_of_independent IsWellFounded.wf + refine CompleteLattice.WellFoundedGT.finite_of_independent hv.independent_span_singleton fun i contra => ?_ apply hv.ne_zero i diff --git a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean index f71dbda3f4e85..0833ddfb38894 100644 --- a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean @@ -671,89 +671,104 @@ theorem closure_eq_of_le {s : Set R} {t : NonUnitalSubring R} (h₁ : s ⊆ t) ( of `s`, and is preserved under addition, negation, and multiplication, then `p` holds for all elements of the closure of `s`. -/ @[elab_as_elim] -theorem closure_induction {s : Set R} {p : R → Prop} {x} (h : x ∈ closure s) (mem : ∀ x ∈ s, p x) - (zero : p 0) (add : ∀ x y, p x → p y → p (x + y)) (neg : ∀ x : R, p x → p (-x)) - (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨⟨⟨⟨p, add _ _⟩, zero⟩, mul _ _⟩, neg _⟩).2 mem h +theorem closure_induction {s : Set R} {p : (x : R) → x ∈ closure s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_closure hx)) (zero : p 0 (zero_mem _)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (neg : ∀ x hx, p x hx → p (-x) (neg_mem hx)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + {x} (hx : x ∈ closure s) : p x hx := + let K : NonUnitalSubring R := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ + add_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, add _ _ _ _ hpx hpy⟩ + neg_mem' := fun ⟨_, hpx⟩ ↦ ⟨_, neg _ _ hpx⟩ + zero_mem' := ⟨_, zero⟩ } + closure_le (t := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id /-- The difference with `NonUnitalSubring.closure_induction` is that this acts on the subtype. -/ -@[elab_as_elim] +@[elab_as_elim, deprecated closure_induction (since := "2024-10-11")] theorem closure_induction' {s : Set R} {p : closure s → Prop} (a : closure s) (mem : ∀ (x) (hx : x ∈ s), p ⟨x, subset_closure hx⟩) (zero : p 0) (add : ∀ x y, p x → p y → p (x + y)) (neg : ∀ x, p x → p (-x)) (mul : ∀ x y, p x → p y → p (x * y)) : p a := Subtype.recOn a fun b hb => by - refine Exists.elim ?_ fun (hb : b ∈ closure s) (hc : p ⟨b, hb⟩) => hc - refine - closure_induction hb (fun x hx => ⟨subset_closure hx, mem x hx⟩) - ⟨zero_mem (closure s), zero⟩ ?_ ?_ ?_ - · rintro x y ⟨hx, hpx⟩ ⟨hy, hpy⟩ - exact ⟨add_mem hx hy, add _ _ hpx hpy⟩ - · rintro x ⟨hx, hpx⟩ - exact ⟨neg_mem hx, neg _ hpx⟩ - · rintro x y ⟨hx, hpx⟩ ⟨hy, hpy⟩ - exact ⟨mul_mem hx hy, mul _ _ hpx hpy⟩ + induction hb using closure_induction with + | mem x hx => exact mem x hx + | zero => exact zero + | add x y hx hy h₁ h₂ => exact add _ _ h₁ h₂ + | neg x hx h => exact neg _ h + | mul x y hx hy h₁ h₂ => exact mul _ _ h₁ h₂ /-- An induction principle for closure membership, for predicates with two arguments. -/ @[elab_as_elim] -theorem closure_induction₂ {s : Set R} {p : R → R → Prop} {a b : R} (ha : a ∈ closure s) - (hb : b ∈ closure s) (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H0_left : ∀ x, p 0 x) - (H0_right : ∀ x, p x 0) (Hneg_left : ∀ x y, p x y → p (-x) y) - (Hneg_right : ∀ x y, p x y → p x (-y)) (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) : p a b := by - refine closure_induction hb ?_ (H0_right _) (Hadd_right a) (Hneg_right a) (Hmul_right a) - refine closure_induction ha Hs (fun x _ => H0_left x) ?_ ?_ ?_ - · exact fun x y H₁ H₂ z zs => Hadd_left x y z (H₁ z zs) (H₂ z zs) - · exact fun x hx z zs => Hneg_left x z (hx z zs) - · exact fun x y H₁ H₂ z zs => Hmul_left x y z (H₁ z zs) (H₂ z zs) +theorem closure_induction₂ {s : Set R} {p : (x y : R) → x ∈ closure s → y ∈ closure s → Prop} + (mem_mem : ∀ (x) (y) (hx : x ∈ s) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (zero_left : ∀ x hx, p 0 x (zero_mem _) hx) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (neg_left : ∀ x y hx hy, p x y hx hy → p (-x) y (neg_mem hx) hy) + (neg_right : ∀ x y hx hy, p x y hx hy → p x (-y) hx (neg_mem hy)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + {x y : R} (hx : x ∈ closure s) (hy : y ∈ closure s) : + p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem_mem _ _ h hz + | zero => exact zero_left _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | neg _ _ h => exact neg_left _ _ _ _ h + | zero => exact zero_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ + | neg _ _ h => exact neg_right _ _ _ _ h theorem mem_closure_iff {s : Set R} {x} : x ∈ closure s ↔ x ∈ AddSubgroup.closure (Subsemigroup.closure s : Set R) := - ⟨fun h => - closure_induction h (fun x hx => AddSubgroup.subset_closure <| Subsemigroup.subset_closure hx) - (AddSubgroup.zero_mem _) (fun x y hx hy => AddSubgroup.add_mem _ hx hy) - (fun x hx => AddSubgroup.neg_mem _ hx) fun x y hx hy => - AddSubgroup.closure_induction hy - (fun q hq => - AddSubgroup.closure_induction hx - (fun p hp => AddSubgroup.subset_closure ((Subsemigroup.closure s).mul_mem hp hq)) - (by rw [zero_mul q]; apply AddSubgroup.zero_mem _) - (fun p₁ p₂ ihp₁ ihp₂ => by rw [add_mul p₁ p₂ q]; apply AddSubgroup.add_mem _ ihp₁ ihp₂) - fun x hx => by - have f : -x * q = -(x * q) := by simp - rw [f]; apply AddSubgroup.neg_mem _ hx) - (by rw [mul_zero x]; apply AddSubgroup.zero_mem _) - (fun q₁ q₂ ihq₁ ihq₂ => by rw [mul_add x q₁ q₂]; apply AddSubgroup.add_mem _ ihq₁ ihq₂) - fun z hz => by - have f : x * -z = -(x * z) := by simp - rw [f]; apply AddSubgroup.neg_mem _ hz, - fun h => - AddSubgroup.closure_induction h - (fun x hx => - Subsemigroup.closure_induction hx (fun x hx => subset_closure hx) fun x y hx hy => - mul_mem hx hy) - (zero_mem _) (fun x y hx hy => add_mem hx hy) fun x hx => neg_mem hx⟩ + ⟨fun h => by + induction h using closure_induction with + | mem _ hx => exact AddSubgroup.subset_closure (Subsemigroup.subset_closure hx) + | zero => exact zero_mem _ + | add _ _ _ _ hx hy => exact add_mem hx hy + | neg x _ hx => exact neg_mem hx + | mul _ _ _hx _hy hx hy => + clear _hx _hy + induction hx, hy using AddSubgroup.closure_induction₂ with + | mem _ _ hx hy => exact AddSubgroup.subset_closure (mul_mem hx hy) + | one_left => simpa using zero_mem _ + | one_right => simpa using zero_mem _ + | mul_left _ _ _ _ _ _ h₁ h₂ => simpa [add_mul] using add_mem h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => simpa [mul_add] using add_mem h₁ h₂ + | inv_left _ _ _ _ h => simpa [neg_mul] using neg_mem h + | inv_right _ _ _ _ h => simpa [mul_neg] using neg_mem h, + fun h => by + induction h using AddSubgroup.closure_induction with + | mem _ hx => induction hx using Subsemigroup.closure_induction with + | mem _ h => exact subset_closure h + | mul _ _ _ _ h₁ h₂ => exact mul_mem h₁ h₂ + | one => exact zero_mem _ + | mul _ _ _ _ h₁ h₂ => exact add_mem h₁ h₂ + | inv _ _ h => exact neg_mem h⟩ /-- If all elements of `s : Set A` commute pairwise, then `closure s` is a commutative ring. -/ def closureNonUnitalCommRingOfComm {R : Type u} [NonUnitalRing R] {s : Set R} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : NonUnitalCommRing (closure s) := { (closure s).toNonUnitalRing with - mul_comm := fun x y => by + mul_comm := fun ⟨x, hx⟩ ⟨y, hy⟩ => by ext - simp only [NonUnitalSubring.val_mul] - refine - closure_induction₂ x.prop y.prop hcomm - (fun x => by simp only [mul_zero, zero_mul]) - (fun x => by simp only [mul_zero, zero_mul]) - (fun x y hxy => by simp only [mul_neg, neg_mul, hxy]) - (fun x y hxy => by simp only [mul_neg, neg_mul, hxy]) - (fun x₁ x₂ y h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x₁ x₂ y h₁ h₂ => by simp only [add_mul, mul_add, h₁, h₂]) - (fun x₁ x₂ y h₁ h₂ => by rw [← mul_assoc, ← h₁, mul_assoc x₁ y x₂, ← h₂, mul_assoc]) - fun x₁ x₂ y h₁ h₂ => by rw [← mul_assoc, h₁, mul_assoc, h₂, ← mul_assoc] } + simp only [MulMemClass.mk_mul_mk] + induction hx, hy using closure_induction₂ with + | mem_mem x y hx hy => exact hcomm x hx y hy + | zero_left x _ => exact Commute.zero_left x + | zero_right x _ => exact Commute.zero_right x + | mul_left _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_left h₁ h₂ + | mul_right _ _ _ _ _ _ h₁ h₂ => exact Commute.mul_right h₁ h₂ + | add_left _ _ _ _ _ _ h₁ h₂ => exact Commute.add_left h₁ h₂ + | add_right _ _ _ _ _ _ h₁ h₂ => exact Commute.add_right h₁ h₂ + | neg_left _ _ _ _ h => exact Commute.neg_left h + | neg_right _ _ _ _ h => exact Commute.neg_right h } variable (R) diff --git a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean index 891e01b70140c..223521ff5f3a5 100644 --- a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean @@ -5,6 +5,7 @@ Authors: Jireh Loreaux -/ import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Group.Subsemigroup.Membership +import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.GroupWithZero.Center import Mathlib.Algebra.Ring.Center import Mathlib.Algebra.Ring.Centralizer @@ -621,21 +622,38 @@ theorem closure_addSubmonoid_closure {s : Set R} : of `s`, and is preserved under addition and multiplication, then `p` holds for all elements of the closure of `s`. -/ @[elab_as_elim] -theorem closure_induction {s : Set R} {p : R → Prop} {x} (h : x ∈ closure s) (mem : ∀ x ∈ s, p x) - (zero : p 0) (add : ∀ x y, p x → p y → p (x + y)) (mul : ∀ x y, p x → p y → p (x * y)) : p x := - (@closure_le _ _ _ ⟨⟨⟨p, fun {a b} => add a b⟩, zero⟩, fun {a b} => mul a b⟩).2 mem h +theorem closure_induction {s : Set R} {p : (x : R) → x ∈ closure s → Prop} + (mem : ∀ (x) (hx : x ∈ s), p x (subset_closure hx)) (zero : p 0 (zero_mem _)) + (add : ∀ x y hx hy, p x hx → p y hy → p (x + y) (add_mem hx hy)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + {x} (hx : x ∈ closure s) : p x hx := + let K : NonUnitalSubsemiring R := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩ + add_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, add _ _ _ _ hpx hpy⟩ + zero_mem' := ⟨_, zero⟩ } + closure_le (t := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id /-- An induction principle for closure membership for predicates with two arguments. -/ @[elab_as_elim] -theorem closure_induction₂ {s : Set R} {p : R → R → Prop} {x} {y : R} (hx : x ∈ closure s) - (hy : y ∈ closure s) (Hs : ∀ x ∈ s, ∀ y ∈ s, p x y) (H0_left : ∀ x, p 0 x) - (H0_right : ∀ x, p x 0) (Hadd_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ + x₂) y) - (Hadd_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ + y₂)) - (Hmul_left : ∀ x₁ x₂ y, p x₁ y → p x₂ y → p (x₁ * x₂) y) - (Hmul_right : ∀ x y₁ y₂, p x y₁ → p x y₂ → p x (y₁ * y₂)) : p x y := - closure_induction hx - (fun x₁ x₁s => closure_induction hy (Hs x₁ x₁s) (H0_right x₁) (Hadd_right x₁) (Hmul_right x₁)) - (H0_left y) (fun z z' => Hadd_left z z' y) fun z z' => Hmul_left z z' y +theorem closure_induction₂ {s : Set R} {p : (x y : R) → x ∈ closure s → y ∈ closure s → Prop} + (mem_mem : ∀ (x) (hx : x ∈ s) (y) (hy : y ∈ s), p x y (subset_closure hx) (subset_closure hy)) + (zero_left : ∀ x hx, p 0 x (zero_mem _) hx) (zero_right : ∀ x hx, p x 0 hx (zero_mem _)) + (add_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x + y) z (add_mem hx hy) hz) + (add_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y + z) hx (add_mem hy hz)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ x y z hx hy hz, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + {x y : R} (hx : x ∈ closure s) (hy : y ∈ closure s) : + p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem_mem _ h _ hz + | zero => exact zero_left _ _ + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_left _ _ _ _ _ _ h₁ h₂ + | zero => exact zero_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ _ h₁ h₂ + | add _ _ _ _ h₁ h₂ => exact add_right _ _ _ _ _ _ h₁ h₂ variable (R) diff --git a/Mathlib/RingTheory/Norm/Defs.lean b/Mathlib/RingTheory/Norm/Defs.lean index b7f2ce47f5c97..14f2d89676a6d 100644 --- a/Mathlib/RingTheory/Norm/Defs.lean +++ b/Mathlib/RingTheory/Norm/Defs.lean @@ -35,10 +35,9 @@ See also `Algebra.trace`, which is defined similarly as the trace of universe u v w -variable {R S T : Type*} [CommRing R] [Ring S] +variable {R S : Type*} [CommRing R] [Ring S] variable [Algebra R S] -variable {K L F : Type*} [Field K] [Field L] [Field F] -variable [Algebra K L] [Algebra K F] +variable {K : Type*} [Field K] variable {ι : Type w} open Module diff --git a/Mathlib/RingTheory/Nullstellensatz.lean b/Mathlib/RingTheory/Nullstellensatz.lean index 2e6928088762c..4b18643ff516f 100644 --- a/Mathlib/RingTheory/Nullstellensatz.lean +++ b/Mathlib/RingTheory/Nullstellensatz.lean @@ -57,7 +57,7 @@ theorem zeroLocus_top : zeroLocus (⊤ : Ideal (MvPolynomial σ k)) = ⊥ := /-- Ideal of polynomials with common zeroes at all elements of a set -/ def vanishingIdeal (V : Set (σ → k)) : Ideal (MvPolynomial σ k) where carrier := {p | ∀ x ∈ V, eval x p = 0} - zero_mem' x _ := RingHom.map_zero _ + zero_mem' _ _ := RingHom.map_zero _ add_mem' {p q} hp hq x hx := by simp only [hq x hx, hp x hx, add_zero, RingHom.map_add] smul_mem' p q hq x hx := by simp only [hq x hx, Algebra.id.smul_eq_mul, mul_zero, RingHom.map_mul] @@ -131,14 +131,14 @@ def pointToPoint (x : σ → k) : PrimeSpectrum (MvPolynomial σ k) := theorem vanishingIdeal_pointToPoint (V : Set (σ → k)) : PrimeSpectrum.vanishingIdeal (pointToPoint '' V) = MvPolynomial.vanishingIdeal V := le_antisymm - (fun p hp x hx => + (fun _ hp x hx => (((PrimeSpectrum.mem_vanishingIdeal _ _).1 hp) ⟨vanishingIdeal {x}, by infer_instance⟩ <| by exact ⟨x, ⟨hx, rfl⟩⟩) -- Porting note: tactic mode code compiles but term mode does not x rfl) - fun p hp => - (PrimeSpectrum.mem_vanishingIdeal _ _).2 fun I hI => + fun _ hp => + (PrimeSpectrum.mem_vanishingIdeal _ _).2 fun _ hI => let ⟨x, hx⟩ := hI - hx.2 ▸ fun x' hx' => (Set.mem_singleton_iff.1 hx').symm ▸ hp x hx.1 + hx.2 ▸ fun _ hx' => (Set.mem_singleton_iff.1 hx').symm ▸ hp x hx.1 theorem pointToPoint_zeroLocus_le (I : Ideal (MvPolynomial σ k)) : pointToPoint '' MvPolynomial.zeroLocus I ≤ PrimeSpectrum.zeroLocus ↑I := fun J hJ => diff --git a/Mathlib/RingTheory/OreLocalization/Basic.lean b/Mathlib/RingTheory/OreLocalization/Basic.lean index 04732f2a57a29..2ae4ee073b5f8 100644 --- a/Mathlib/RingTheory/OreLocalization/Basic.lean +++ b/Mathlib/RingTheory/OreLocalization/Basic.lean @@ -4,20 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob von Raumer, Kevin Klinge, Andrew Yang -/ import Mathlib.Algebra.Group.Submonoid.DistribMulAction -import Mathlib.RingTheory.OreLocalization.OreSet +import Mathlib.GroupTheory.OreLocalization.Basic /-! # Localization over left Ore sets. -This file defines the localization of a monoid over a left Ore set and proves its universal -mapping property. - -## Notations - -Introduces the notation `R[S⁻¹]` for the Ore localization of a monoid `R` at a right Ore -subset `S`. Also defines a new heterogeneous division notation `r /ₒ s` for a numerator `r : R` and -a denominator `s : S`. +This file proves results on the localization of rings (monoids with zeros) over a left Ore set. ## References @@ -37,605 +30,6 @@ open OreLocalization namespace OreLocalization -variable {R : Type*} [Monoid R] (S : Submonoid R) [OreSet S] (X) [MulAction R X] - -/-- The setoid on `R × S` used for the Ore localization. -/ -@[to_additive AddOreLocalization.oreEqv "The setoid on `R × S` used for the Ore localization."] -def oreEqv : Setoid (X × S) where - r rs rs' := ∃ (u : S) (v : R), u • rs'.1 = v • rs.1 ∧ u * rs'.2 = v * rs.2 - iseqv := by - refine ⟨fun _ => ⟨1, 1, by simp⟩, ?_, ?_⟩ - · rintro ⟨r, s⟩ ⟨r', s'⟩ ⟨u, v, hru, hsu⟩; dsimp only at * - rcases oreCondition (s : R) s' with ⟨r₂, s₂, h₁⟩ - rcases oreCondition r₂ u with ⟨r₃, s₃, h₂⟩ - have : r₃ * v * s = s₃ * s₂ * s := by - -- Porting note: the proof used `assoc_rw` - rw [mul_assoc _ (s₂ : R), h₁, ← mul_assoc, h₂, mul_assoc, ← hsu, ← mul_assoc] - rcases ore_right_cancel (r₃ * v) (s₃ * s₂) s this with ⟨w, hw⟩ - refine ⟨w * (s₃ * s₂), w * (r₃ * u), ?_, ?_⟩ <;> - simp only [Submonoid.coe_mul, Submonoid.smul_def, ← hw] - · simp only [mul_smul, hru, ← Submonoid.smul_def] - · simp only [mul_assoc, hsu] - · rintro ⟨r₁, s₁⟩ ⟨r₂, s₂⟩ ⟨r₃, s₃⟩ ⟨u, v, hur₁, hs₁u⟩ ⟨u', v', hur₂, hs₂u⟩ - rcases oreCondition v' u with ⟨r', s', h⟩; dsimp only at * - refine ⟨s' * u', r' * v, ?_, ?_⟩ <;> - simp only [Submonoid.smul_def, Submonoid.coe_mul, mul_smul, mul_assoc] at * - · rw [hur₂, smul_smul, h, mul_smul, hur₁] - · rw [hs₂u, ← mul_assoc, h, mul_assoc, hs₁u] - -end OreLocalization - -/-- The Ore localization of a monoid and a submonoid fulfilling the Ore condition. -/ -@[to_additive AddOreLocalization "The Ore localization of an additive monoid and a submonoid -fulfilling the Ore condition."] -def OreLocalization {R : Type*} [Monoid R] (S : Submonoid R) [OreSet S] - (X : Type*) [MulAction R X] := - Quotient (OreLocalization.oreEqv S X) - -namespace OreLocalization - -section Monoid - -variable (R : Type*) [Monoid R] (S : Submonoid R) [OreSet S] - -@[inherit_doc OreLocalization] -scoped syntax:1075 term noWs atomic("[" term "⁻¹" noWs "]") : term -macro_rules | `($R[$S⁻¹]) => ``(OreLocalization $S $R) - -attribute [local instance] oreEqv - -variable {R S} -variable {X} [MulAction R X] - -/-- The division in the Ore localization `X[S⁻¹]`, as a fraction of an element of `X` and `S`. -/ -@[to_additive "The subtraction in the Ore localization, -as a difference of an element of `X` and `S`."] -def oreDiv (r : X) (s : S) : X[S⁻¹] := - Quotient.mk' (r, s) - -@[inherit_doc] -infixl:70 " /ₒ " => oreDiv - -@[inherit_doc] -infixl:65 " -ₒ " => _root_.AddOreLocalization.oreSub - -@[to_additive (attr := elab_as_elim, cases_eliminator, induction_eliminator)] -protected theorem ind {β : X[S⁻¹] → Prop} - (c : ∀ (r : X) (s : S), β (r /ₒ s)) : ∀ q, β q := by - apply Quotient.ind - rintro ⟨r, s⟩ - exact c r s - -@[to_additive] -theorem oreDiv_eq_iff {r₁ r₂ : X} {s₁ s₂ : S} : - r₁ /ₒ s₁ = r₂ /ₒ s₂ ↔ ∃ (u : S) (v : R), u • r₂ = v • r₁ ∧ u * s₂ = v * s₁ := - Quotient.eq'' - -/-- A fraction `r /ₒ s` is equal to its expansion by an arbitrary factor `t` if `t * s ∈ S`. -/ -@[to_additive "A difference `r -ₒ s` is equal to its expansion by an -arbitrary translation `t` if `t + s ∈ S`."] -protected theorem expand (r : X) (s : S) (t : R) (hst : t * (s : R) ∈ S) : - r /ₒ s = t • r /ₒ ⟨t * s, hst⟩ := by - apply Quotient.sound - exact ⟨s, s * t, by rw [mul_smul, Submonoid.smul_def], by rw [← mul_assoc]⟩ - -/-- A fraction is equal to its expansion by a factor from `S`. -/ -@[to_additive "A difference is equal to its expansion by a summand from `S`."] -protected theorem expand' (r : X) (s s' : S) : r /ₒ s = s' • r /ₒ (s' * s) := - OreLocalization.expand r s s' (by norm_cast; apply SetLike.coe_mem) - -/-- Fractions which differ by a factor of the numerator can be proven equal if -those factors expand to equal elements of `R`. -/ -@[to_additive "Differences whose minuends differ by a common summand can be proven equal if -those summands expand to equal elements of `R`."] -protected theorem eq_of_num_factor_eq {r r' r₁ r₂ : R} {s t : S} (h : t * r = t * r') : - r₁ * r * r₂ /ₒ s = r₁ * r' * r₂ /ₒ s := by - rcases oreCondition r₁ t with ⟨r₁', t', hr₁⟩ - rw [OreLocalization.expand' _ s t', OreLocalization.expand' _ s t'] - congr 1 - -- Porting note (#11215): TODO: use `assoc_rw`? - calc (t' : R) * (r₁ * r * r₂) - = t' * r₁ * r * r₂ := by simp [← mul_assoc] - _ = r₁' * t * r * r₂ := by rw [hr₁] - _ = r₁' * (t * r) * r₂ := by simp [← mul_assoc] - _ = r₁' * (t * r') * r₂ := by rw [h] - _ = r₁' * t * r' * r₂ := by simp [← mul_assoc] - _ = t' * r₁ * r' * r₂ := by rw [hr₁] - _ = t' * (r₁ * r' * r₂) := by simp [← mul_assoc] - -/-- A function or predicate over `X` and `S` can be lifted to `X[S⁻¹]` if it is invariant -under expansion on the left. -/ -@[to_additive "A function or predicate over `X` and `S` can be lifted to the localizaton if it is -invariant under expansion on the left."] -def liftExpand {C : Sort*} (P : X → S → C) - (hP : ∀ (r : X) (t : R) (s : S) (ht : t * s ∈ S), P r s = P (t • r) ⟨t * s, ht⟩) : - X[S⁻¹] → C := - Quotient.lift (fun p : X × S => P p.1 p.2) fun (r₁, s₁) (r₂, s₂) ⟨u, v, hr₂, hs₂⟩ => by - dsimp at * - have s₁vS : v * s₁ ∈ S := by - rw [← hs₂, ← S.coe_mul] - exact SetLike.coe_mem (u * s₂) - replace hs₂ : u * s₂ = ⟨_, s₁vS⟩ := by ext; simp [hs₂] - rw [hP r₁ v s₁ s₁vS, hP r₂ u s₂ (by norm_cast; rwa [hs₂]), ← hr₂] - simp only [← hs₂]; rfl - -@[to_additive (attr := simp)] -theorem liftExpand_of {C : Sort*} {P : X → S → C} - {hP : ∀ (r : X) (t : R) (s : S) (ht : t * s ∈ S), P r s = P (t • r) ⟨t * s, ht⟩} (r : X) - (s : S) : liftExpand P hP (r /ₒ s) = P r s := - rfl - -/-- A version of `liftExpand` used to simultaneously lift functions with two arguments -in `X[S⁻¹]`. -/ -@[to_additive "A version of `liftExpand` used to simultaneously lift functions with two arguments"] -def lift₂Expand {C : Sort*} (P : X → S → X → S → C) - (hP : - ∀ (r₁ : X) (t₁ : R) (s₁ : S) (ht₁ : t₁ * s₁ ∈ S) (r₂ : X) (t₂ : R) (s₂ : S) - (ht₂ : t₂ * s₂ ∈ S), - P r₁ s₁ r₂ s₂ = P (t₁ • r₁) ⟨t₁ * s₁, ht₁⟩ (t₂ • r₂) ⟨t₂ * s₂, ht₂⟩) : - X[S⁻¹] → X[S⁻¹] → C := - liftExpand - (fun r₁ s₁ => liftExpand (P r₁ s₁) fun r₂ t₂ s₂ ht₂ => by - have := hP r₁ 1 s₁ (by simp) r₂ t₂ s₂ ht₂ - simp [this]) - fun r₁ t₁ s₁ ht₁ => by - ext x; induction' x with r₂ s₂ - dsimp only - rw [liftExpand_of, liftExpand_of, hP r₁ t₁ s₁ ht₁ r₂ 1 s₂ (by simp)]; simp - -@[to_additive (attr := simp)] -theorem lift₂Expand_of {C : Sort*} {P : X → S → X → S → C} - {hP : - ∀ (r₁ : X) (t₁ : R) (s₁ : S) (ht₁ : t₁ * s₁ ∈ S) (r₂ : X) (t₂ : R) (s₂ : S) - (ht₂ : t₂ * s₂ ∈ S), - P r₁ s₁ r₂ s₂ = P (t₁ • r₁) ⟨t₁ * s₁, ht₁⟩ (t₂ • r₂) ⟨t₂ * s₂, ht₂⟩} - (r₁ : X) (s₁ : S) (r₂ : X) (s₂ : S) : lift₂Expand P hP (r₁ /ₒ s₁) (r₂ /ₒ s₂) = P r₁ s₁ r₂ s₂ := - rfl - -@[to_additive] -private def smul' (r₁ : R) (s₁ : S) (r₂ : X) (s₂ : S) : X[S⁻¹] := - oreNum r₁ s₂ • r₂ /ₒ (oreDenom r₁ s₂ * s₁) - -@[to_additive] -private theorem smul'_char (r₁ : R) (r₂ : X) (s₁ s₂ : S) (u : S) (v : R) (huv : u * r₁ = v * s₂) : - OreLocalization.smul' r₁ s₁ r₂ s₂ = v • r₂ /ₒ (u * s₁) := by - -- Porting note: `assoc_rw` was not ported yet - simp only [smul'] - have h₀ := ore_eq r₁ s₂; set v₀ := oreNum r₁ s₂; set u₀ := oreDenom r₁ s₂ - rcases oreCondition (u₀ : R) u with ⟨r₃, s₃, h₃⟩ - have := - calc - r₃ * v * s₂ = r₃ * (u * r₁) := by rw [mul_assoc, ← huv] - _ = s₃ * (u₀ * r₁) := by rw [← mul_assoc, ← mul_assoc, h₃] - _ = s₃ * v₀ * s₂ := by rw [mul_assoc, h₀] - rcases ore_right_cancel _ _ _ this with ⟨s₄, hs₄⟩ - symm; rw [oreDiv_eq_iff] - use s₄ * s₃ - use s₄ * r₃ - simp only [Submonoid.coe_mul, Submonoid.smul_def, smul_eq_mul] - constructor - · rw [smul_smul, mul_assoc (c := v₀), ← hs₄] - simp only [smul_smul, mul_assoc] - · rw [← mul_assoc (b := (u₀ : R)), mul_assoc (c := (u₀ : R)), h₃] - simp only [mul_assoc] - -/-- The multiplication on the Ore localization of monoids. -/ -@[to_additive] -private def smul'' (r : R) (s : S) : X[S⁻¹] → X[S⁻¹] := - liftExpand (smul' r s) fun r₁ r₂ s' hs => by - rcases oreCondition r s' with ⟨r₁', s₁', h₁⟩ - rw [smul'_char _ _ _ _ _ _ h₁] - rcases oreCondition r ⟨_, hs⟩ with ⟨r₂', s₂', h₂⟩ - rw [smul'_char _ _ _ _ _ _ h₂] - rcases oreCondition (s₁' : R) (s₂') with ⟨r₃', s₃', h₃⟩ - have : s₃' * r₁' * s' = (r₃' * r₂' * r₂) * s' := by - rw [mul_assoc, ← h₁, ← mul_assoc, h₃, mul_assoc, h₂] - simp [mul_assoc] - rcases ore_right_cancel _ _ _ this with ⟨s₄', h₄⟩ - have : (s₄' * r₃') * (s₂' * s) ∈ S := by - rw [mul_assoc, ← mul_assoc r₃', ← h₃] - exact (s₄' * (s₃' * s₁' * s)).2 - rw [OreLocalization.expand' _ _ (s₄' * s₃'), OreLocalization.expand _ (s₂' * s) _ this] - simp only [Submonoid.smul_def, Submonoid.coe_mul, smul_smul, mul_assoc, h₄] - congr 1 - ext; simp only [Submonoid.coe_mul, ← mul_assoc] - rw [mul_assoc (s₄' : R), h₃, ← mul_assoc] - -/-- The scalar multiplication on the Ore localization of monoids. -/ -@[to_additive (attr := irreducible) - "the vector addition on the Ore localization of additive monoids."] -protected def smul : R[S⁻¹] → X[S⁻¹] → X[S⁻¹] := - liftExpand smul'' fun r₁ r₂ s hs => by - ext x - induction' x with x s₂ - show OreLocalization.smul' r₁ s x s₂ = OreLocalization.smul' (r₂ * r₁) ⟨_, hs⟩ x s₂ - rcases oreCondition r₁ s₂ with ⟨r₁', s₁', h₁⟩ - rw [smul'_char _ _ _ _ _ _ h₁] - rcases oreCondition (r₂ * r₁) s₂ with ⟨r₂', s₂', h₂⟩ - rw [smul'_char _ _ _ _ _ _ h₂] - rcases oreCondition (s₂' * r₂) (s₁') with ⟨r₃', s₃', h₃⟩ - have : s₃' * r₂' * s₂ = r₃' * r₁' * s₂ := by - rw [mul_assoc, ← h₂, ← mul_assoc _ r₂, ← mul_assoc, h₃, mul_assoc, h₁, mul_assoc] - rcases ore_right_cancel _ _ _ this with ⟨s₄', h₄⟩ - have : (s₄' * r₃') * (s₁' * s) ∈ S := by - rw [← mul_assoc, mul_assoc _ r₃', ← h₃, ← mul_assoc, ← mul_assoc, mul_assoc] - exact mul_mem (s₄' * s₃' * s₂').2 hs - rw [OreLocalization.expand' (r₂' • x) _ (s₄' * s₃'), OreLocalization.expand _ _ _ this] - simp only [Submonoid.smul_def, Submonoid.coe_mul, smul_smul, mul_assoc, h₄] - congr 1 - ext; simp only [Submonoid.coe_mul, ← mul_assoc] - rw [mul_assoc _ r₃', ← h₃, ← mul_assoc, ← mul_assoc] - -@[to_additive] -instance : SMul R[S⁻¹] X[S⁻¹] := - ⟨OreLocalization.smul⟩ - -@[to_additive] -instance : Mul R[S⁻¹] := - ⟨OreLocalization.smul⟩ - -@[to_additive] -theorem oreDiv_smul_oreDiv {r₁ : R} {r₂ : X} {s₁ s₂ : S} : - (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = oreNum r₁ s₂ • r₂ /ₒ (oreDenom r₁ s₂ * s₁) := by - with_unfolding_all rfl - -@[to_additive] -theorem oreDiv_mul_oreDiv {r₁ : R} {r₂ : R} {s₁ s₂ : S} : - (r₁ /ₒ s₁) * (r₂ /ₒ s₂) = oreNum r₁ s₂ * r₂ /ₒ (oreDenom r₁ s₂ * s₁) := by - with_unfolding_all rfl - -/-- A characterization lemma for the scalar multiplication on the Ore localization, -allowing for a choice of Ore numerator and Ore denominator. -/ -@[to_additive "A characterization lemma for the vector addition on the Ore localization, -allowing for a choice of Ore minuend and Ore subtrahend."] -theorem oreDiv_smul_char (r₁ : R) (r₂ : X) (s₁ s₂ : S) (r' : R) (s' : S) (huv : s' * r₁ = r' * s₂) : - (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = r' • r₂ /ₒ (s' * s₁) := by - with_unfolding_all exact smul'_char r₁ r₂ s₁ s₂ s' r' huv - -/-- A characterization lemma for the multiplication on the Ore localization, allowing for a choice -of Ore numerator and Ore denominator. -/ -@[to_additive "A characterization lemma for the addition on the Ore localization, -allowing for a choice of Ore minuend and Ore subtrahend."] -theorem oreDiv_mul_char (r₁ r₂ : R) (s₁ s₂ : S) (r' : R) (s' : S) (huv : s' * r₁ = r' * s₂) : - r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r' * r₂ /ₒ (s' * s₁) := by - with_unfolding_all exact smul'_char r₁ r₂ s₁ s₂ s' r' huv - -/-- Another characterization lemma for the scalar multiplication on the Ore localizaion delivering -Ore witnesses and conditions bundled in a sigma type. -/ -@[to_additive "Another characterization lemma for the vector addition on the - Ore localizaion delivering Ore witnesses and conditions bundled in a sigma type."] -def oreDivSMulChar' (r₁ : R) (r₂ : X) (s₁ s₂ : S) : - Σ'r' : R, Σ's' : S, s' * r₁ = r' * s₂ ∧ (r₁ /ₒ s₁) • (r₂ /ₒ s₂) = r' • r₂ /ₒ (s' * s₁) := - ⟨oreNum r₁ s₂, oreDenom r₁ s₂, ore_eq r₁ s₂, oreDiv_smul_oreDiv⟩ - -/-- Another characterization lemma for the multiplication on the Ore localizaion delivering -Ore witnesses and conditions bundled in a sigma type. -/ -@[to_additive "Another characterization lemma for the addition on the Ore localizaion delivering - Ore witnesses and conditions bundled in a sigma type."] -def oreDivMulChar' (r₁ r₂ : R) (s₁ s₂ : S) : - Σ'r' : R, Σ's' : S, s' * r₁ = r' * s₂ ∧ r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r' * r₂ /ₒ (s' * s₁) := - ⟨oreNum r₁ s₂, oreDenom r₁ s₂, ore_eq r₁ s₂, oreDiv_mul_oreDiv⟩ - -/-- `1` in the localization, defined as `1 /ₒ 1`. -/ -@[to_additive (attr := irreducible) "`0` in the additive localization, defined as `0 -ₒ 0`."] -protected def one : R[S⁻¹] := 1 /ₒ 1 - -@[to_additive] -instance : One R[S⁻¹] := - ⟨OreLocalization.one⟩ - -@[to_additive] -protected theorem one_def : (1 : R[S⁻¹]) = 1 /ₒ 1 := by - with_unfolding_all rfl - -@[to_additive] -instance : Inhabited R[S⁻¹] := - ⟨1⟩ - -@[to_additive (attr := simp)] -protected theorem div_eq_one' {r : R} (hr : r ∈ S) : r /ₒ ⟨r, hr⟩ = 1 := by - rw [OreLocalization.one_def, oreDiv_eq_iff] - exact ⟨⟨r, hr⟩, 1, by simp, by simp⟩ - -@[to_additive (attr := simp)] -protected theorem div_eq_one {s : S} : (s : R) /ₒ s = 1 := - OreLocalization.div_eq_one' _ - -@[to_additive] -protected theorem one_smul (x : X[S⁻¹]) : (1 : R[S⁻¹]) • x = x := by - induction' x with r s - simp [OreLocalization.one_def, oreDiv_smul_char 1 r 1 s 1 s (by simp)] - -@[to_additive] -protected theorem one_mul (x : R[S⁻¹]) : 1 * x = x := - OreLocalization.one_smul x - -@[to_additive] -protected theorem mul_one (x : R[S⁻¹]) : x * 1 = x := by - induction' x with r s - simp [OreLocalization.one_def, oreDiv_mul_char r (1 : R) s (1 : S) r 1 (by simp)] - -@[to_additive] -protected theorem mul_smul (x y : R[S⁻¹]) (z : X[S⁻¹]) : (x * y) • z = x • y • z := by - -- Porting note: `assoc_rw` was not ported yet - induction' x with r₁ s₁ - induction' y with r₂ s₂ - induction' z with r₃ s₃ - rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha' - rcases oreDivSMulChar' r₂ r₃ s₂ s₃ with ⟨rb, sb, hb, hb'⟩; rw [hb']; clear hb' - rcases oreCondition ra sb with ⟨rc, sc, hc⟩ - rw [oreDiv_smul_char (ra * r₂) r₃ (sa * s₁) s₃ (rc * rb) sc]; swap - · rw [← mul_assoc _ ra, hc, mul_assoc, hb, ← mul_assoc] - rw [← mul_assoc, mul_smul] - symm; apply oreDiv_smul_char - rw [Submonoid.coe_mul, Submonoid.coe_mul, ← mul_assoc, ← hc, mul_assoc _ ra, ← ha, mul_assoc] - -@[to_additive] -protected theorem mul_assoc (x y z : R[S⁻¹]) : x * y * z = x * (y * z) := - OreLocalization.mul_smul x y z - -/-- `npow` of `OreLocalization` -/ -@[to_additive (attr := irreducible) "`nsmul` of `AddOreLocalization`"] -protected def npow : ℕ → R[S⁻¹] → R[S⁻¹] := npowRec - -unseal OreLocalization.npow in -@[to_additive] -instance : Monoid R[S⁻¹] where - one_mul := OreLocalization.one_mul - mul_one := OreLocalization.mul_one - mul_assoc := OreLocalization.mul_assoc - npow := OreLocalization.npow - -@[to_additive] -instance instMulActionOreLocalization : MulAction R[S⁻¹] X[S⁻¹] where - one_smul := OreLocalization.one_smul - mul_smul := OreLocalization.mul_smul - -@[to_additive] -protected theorem mul_inv (s s' : S) : ((s : R) /ₒ s') * ((s' : R) /ₒ s) = 1 := by - simp [oreDiv_mul_char (s : R) s' s' s 1 1 (by simp)] - -@[to_additive (attr := simp)] -protected theorem one_div_smul {r : X} {s t : S} : ((1 : R) /ₒ t) • (r /ₒ s) = r /ₒ (s * t) := by - simp [oreDiv_smul_char 1 r t s 1 s (by simp)] - -@[to_additive (attr := simp)] -protected theorem one_div_mul {r : R} {s t : S} : (1 /ₒ t) * (r /ₒ s) = r /ₒ (s * t) := by - simp [oreDiv_mul_char 1 r t s 1 s (by simp)] - -@[to_additive (attr := simp)] -protected theorem smul_cancel {r : X} {s t : S} : ((s : R) /ₒ t) • (r /ₒ s) = r /ₒ t := by - simp [oreDiv_smul_char s.1 r t s 1 1 (by simp)] - -@[to_additive (attr := simp)] -protected theorem mul_cancel {r : R} {s t : S} : ((s : R) /ₒ t) * (r /ₒ s) = r /ₒ t := by - simp [oreDiv_mul_char s.1 r t s 1 1 (by simp)] - -@[to_additive (attr := simp)] -protected theorem smul_cancel' {r₁ : R} {r₂ : X} {s t : S} : - ((r₁ * s) /ₒ t) • (r₂ /ₒ s) = (r₁ • r₂) /ₒ t := by - simp [oreDiv_smul_char (r₁ * s) r₂ t s r₁ 1 (by simp)] - -@[to_additive (attr := simp)] -protected theorem mul_cancel' {r₁ r₂ : R} {s t : S} : - ((r₁ * s) /ₒ t) * (r₂ /ₒ s) = (r₁ * r₂) /ₒ t := by - simp [oreDiv_mul_char (r₁ * s) r₂ t s r₁ 1 (by simp)] - -@[to_additive (attr := simp)] -theorem smul_div_one {p : R} {r : X} {s : S} : (p /ₒ s) • (r /ₒ 1) = (p • r) /ₒ s := by - simp [oreDiv_smul_char p r s 1 p 1 (by simp)] - -@[to_additive (attr := simp)] -theorem mul_div_one {p r : R} {s : S} : (p /ₒ s) * (r /ₒ 1) = (p * r) /ₒ s := by - --TODO use coercion r ↦ r /ₒ 1 - simp [oreDiv_mul_char p r s 1 p 1 (by simp)] - -/-- The fraction `s /ₒ 1` as a unit in `R[S⁻¹]`, where `s : S`. -/ -@[to_additive "The difference `s -ₒ 0` as a an additive unit."] -def numeratorUnit (s : S) : Units R[S⁻¹] where - val := (s : R) /ₒ 1 - inv := (1 : R) /ₒ s - val_inv := OreLocalization.mul_inv s 1 - inv_val := OreLocalization.mul_inv 1 s - -/-- The multiplicative homomorphism from `R` to `R[S⁻¹]`, mapping `r : R` to the -fraction `r /ₒ 1`. -/ -@[to_additive "The additive homomorphism from `R` to `AddOreLocalization R S`, - mapping `r : R` to the difference `r -ₒ 0`."] -def numeratorHom : R →* R[S⁻¹] where - toFun r := r /ₒ 1 - map_one' := by with_unfolding_all rfl - map_mul' _ _ := mul_div_one.symm - -@[to_additive] -theorem numeratorHom_apply {r : R} : numeratorHom r = r /ₒ (1 : S) := - rfl - -@[to_additive] -theorem numerator_isUnit (s : S) : IsUnit (numeratorHom (s : R) : R[S⁻¹]) := - ⟨numeratorUnit s, rfl⟩ - -section UMP - -variable {T : Type*} [Monoid T] -variable (f : R →* T) (fS : S →* Units T) - -/-- The universal lift from a morphism `R →* T`, which maps elements of `S` to units of `T`, -to a morphism `R[S⁻¹] →* T`. -/ -@[to_additive "The universal lift from a morphism `R →+ T`, which maps elements of `S` to - additive-units of `T`, to a morphism `AddOreLocalization R S →+ T`."] -def universalMulHom (hf : ∀ s : S, f s = fS s) : R[S⁻¹] →* T where - -- Porting note(#12129): additional beta reduction needed - toFun x := - x.liftExpand (fun r s => ((fS s)⁻¹ : Units T) * f r) fun r t s ht => by - simp only [smul_eq_mul] - have : (fS ⟨t * s, ht⟩ : T) = f t * fS s := by - simp only [← hf, MonoidHom.map_mul] - conv_rhs => - rw [MonoidHom.map_mul, ← one_mul (f r), ← Units.val_one, ← mul_inv_cancel (fS s)] - rw [Units.val_mul, mul_assoc, ← mul_assoc _ (fS s : T), ← this, ← mul_assoc] - simp only [one_mul, Units.inv_mul] - map_one' := by beta_reduce; rw [OreLocalization.one_def, liftExpand_of]; simp - map_mul' x y := by - -- Porting note: `simp only []` required, not just for beta reductions - beta_reduce - simp only [] -- TODO more! - induction' x with r₁ s₁ - induction' y with r₂ s₂ - rcases oreDivMulChar' r₁ r₂ s₁ s₂ with ⟨ra, sa, ha, ha'⟩; rw [ha']; clear ha' - rw [liftExpand_of, liftExpand_of, liftExpand_of, Units.inv_mul_eq_iff_eq_mul, map_mul, map_mul, - Units.val_mul, mul_assoc, ← mul_assoc (fS s₁ : T), ← mul_assoc (fS s₁ : T), Units.mul_inv, - one_mul, ← hf, ← mul_assoc, ← map_mul _ _ r₁, ha, map_mul, hf s₂, mul_assoc, - ← mul_assoc (fS s₂ : T), (fS s₂).mul_inv, one_mul] - -variable (hf : ∀ s : S, f s = fS s) - -@[to_additive] -theorem universalMulHom_apply {r : R} {s : S} : - universalMulHom f fS hf (r /ₒ s) = ((fS s)⁻¹ : Units T) * f r := - rfl - -@[to_additive] -theorem universalMulHom_commutes {r : R} : universalMulHom f fS hf (numeratorHom r) = f r := by - simp [numeratorHom_apply, universalMulHom_apply] - -/-- The universal morphism `universalMulHom` is unique. -/ -@[to_additive "The universal morphism `universalAddHom` is unique."] -theorem universalMulHom_unique (φ : R[S⁻¹] →* T) (huniv : ∀ r : R, φ (numeratorHom r) = f r) : - φ = universalMulHom f fS hf := by - ext x; induction' x with r s - rw [universalMulHom_apply, ← huniv r, numeratorHom_apply, ← one_mul (φ (r /ₒ s)), ← - Units.val_one, ← inv_mul_cancel (fS s), Units.val_mul, mul_assoc, ← hf, ← huniv, ← φ.map_mul, - numeratorHom_apply, OreLocalization.mul_cancel] - -end UMP - -end Monoid - -section SMul - -variable {R R' M X : Type*} [Monoid M] {S : Submonoid M} [OreSet S] [MulAction M X] -variable [SMul R X] [SMul R M] [IsScalarTower R M M] [IsScalarTower R M X] -variable [SMul R' X] [SMul R' M] [IsScalarTower R' M M] [IsScalarTower R' M X] -variable [SMul R R'] [IsScalarTower R R' M] - -/-- Scalar multiplication in a monoid localization. -/ -@[to_additive (attr := irreducible) "Vector addition in an additive monoid localization."] -protected def hsmul (c : R) : - X[S⁻¹] → X[S⁻¹] := - liftExpand (fun m s ↦ oreNum (c • 1) s • m /ₒ oreDenom (c • 1) s) (fun r t s ht ↦ by - dsimp only - rw [← mul_one (oreDenom (c • 1) s), ← oreDiv_smul_oreDiv, ← mul_one (oreDenom (c • 1) _), - ← oreDiv_smul_oreDiv, ← OreLocalization.expand]) - -/- Warning: This gives an diamond on `SMul R[S⁻¹] M[S⁻¹][S⁻¹]`, but we will almost never localize -at the same monoid twice. -/ -/- Although the definition does not require `IsScalarTower R M X`, -it does not make sense without it. -/ -@[to_additive (attr := nolint unusedArguments)] -instance [SMul R X] [SMul R M] [IsScalarTower R M X] [IsScalarTower R M M] : SMul R (X[S⁻¹]) where - smul := OreLocalization.hsmul - -@[to_additive] -theorem smul_oreDiv (r : R) (x : X) (s : S) : - r • (x /ₒ s) = oreNum (r • 1) s • x /ₒ oreDenom (r • 1) s := by with_unfolding_all rfl - -@[to_additive (attr := simp)] -theorem oreDiv_one_smul (r : M) (x : X[S⁻¹]) : (r /ₒ (1 : S)) • x = r • x := by - induction' x using OreLocalization.ind with r' s - rw [smul_oreDiv, oreDiv_smul_oreDiv, mul_one, smul_eq_mul, mul_one] - -@[to_additive] -theorem smul_one_smul (r : R) (x : X[S⁻¹]) : (r • 1 : M) • x = r • x := by - induction' x using OreLocalization.ind with r' s - simp only [smul_oreDiv, smul_eq_mul, mul_one] - -@[to_additive] -theorem smul_one_oreDiv_one_smul (r : R) (x : X[S⁻¹]) : - ((r • 1 : M) /ₒ (1 : S)) • x = r • x := by - rw [oreDiv_one_smul, smul_one_smul] - -@[to_additive] -instance : IsScalarTower R R' X[S⁻¹] where - smul_assoc r m x := by - rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, - ← mul_smul, mul_div_one] - simp only [smul_eq_mul, mul_one, smul_mul_assoc, smul_assoc, one_mul] - -@[to_additive] -instance [SMulCommClass R R' M] : SMulCommClass R R' X[S⁻¹] where - smul_comm r m x := by - rw [← smul_one_smul m, ← smul_assoc, smul_comm, smul_assoc, smul_one_smul] - -@[to_additive] -instance : IsScalarTower R M[S⁻¹] X[S⁻¹] where - smul_assoc r m x := by - rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, ← mul_smul, smul_eq_mul] - -@[to_additive] -instance [SMulCommClass R M M] : SMulCommClass R M[S⁻¹] X[S⁻¹] where - smul_comm r x y := by - induction' x using OreLocalization.ind with r₁ s₁ - induction' y using OreLocalization.ind with r₂ s₂ - rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, smul_smul, smul_smul, - mul_div_one, oreDiv_mul_char _ _ _ _ (r • 1) s₁ (by simp), mul_one] - simp - -@[to_additive] -instance [SMul Rᵐᵒᵖ M] [SMul Rᵐᵒᵖ X] [IsScalarTower Rᵐᵒᵖ M M] [IsScalarTower Rᵐᵒᵖ M X] - [IsCentralScalar R M] : IsCentralScalar R X[S⁻¹] where - op_smul_eq_smul r x := by - rw [← smul_one_oreDiv_one_smul, ← smul_one_oreDiv_one_smul, op_smul_eq_smul] - -@[to_additive] -instance {R} [Monoid R] [MulAction R M] [IsScalarTower R M M] - [MulAction R X] [IsScalarTower R M X] : MulAction R X[S⁻¹] where - one_smul := OreLocalization.ind fun x s ↦ by - rw [← smul_one_oreDiv_one_smul, one_smul, ← OreLocalization.one_def, one_smul] - mul_smul s₁ s₂ x := by rw [← smul_eq_mul, smul_assoc] - -@[to_additive] -theorem smul_oreDiv_one (r : R) (x : X) : r • (x /ₒ (1 : S)) = (r • x) /ₒ (1 : S) := by - rw [← smul_one_oreDiv_one_smul, smul_div_one, smul_assoc, one_smul] - -end SMul - -section CommMonoid - -variable {R : Type*} [CommMonoid R] {S : Submonoid R} [OreSet S] - -@[to_additive] -theorem oreDiv_mul_oreDiv_comm {r₁ r₂ : R} {s₁ s₂ : S} : - r₁ /ₒ s₁ * (r₂ /ₒ s₂) = r₁ * r₂ /ₒ (s₁ * s₂) := by - rw [oreDiv_mul_char r₁ r₂ s₁ s₂ r₁ s₂ (by simp [mul_comm]), mul_comm s₂] - -@[to_additive] -instance : CommMonoid R[S⁻¹] where - mul_comm := fun x y => by - induction' x with r₁ s₁ - induction' y with r₂ s₂ - rw [oreDiv_mul_oreDiv_comm, oreDiv_mul_oreDiv_comm, mul_comm r₁, mul_comm s₁] - -end CommMonoid - -section Zero - -variable {R : Type*} [Monoid R] {S : Submonoid R} [OreSet S] {X : Type*} [Zero X] -variable [MulAction R X] - - -/-- `0` in the localization, defined as `0 /ₒ 1`. -/ -@[irreducible] -protected def zero : X[S⁻¹] := 0 /ₒ 1 - -instance : Zero X[S⁻¹] := - ⟨OreLocalization.zero⟩ - -protected theorem zero_def : (0 : X[S⁻¹]) = 0 /ₒ 1 := by - with_unfolding_all rfl - -end Zero - section MonoidWithZero variable {R : Type*} [MonoidWithZero R] {S : Submonoid R} [OreSet S] diff --git a/Mathlib/RingTheory/OreLocalization/OreSet.lean b/Mathlib/RingTheory/OreLocalization/OreSet.lean index 5c7b9e4f91dab..27bf74cc46864 100644 --- a/Mathlib/RingTheory/OreLocalization/OreSet.lean +++ b/Mathlib/RingTheory/OreLocalization/OreSet.lean @@ -3,15 +3,16 @@ Copyright (c) 2022 Jakob von Raumer. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob von Raumer, Kevin Klinge -/ -import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.GroupWithZero.Basic import Mathlib.Algebra.Ring.Regular +import Mathlib.GroupTheory.OreLocalization.OreSet /-! -# (Left) Ore sets +# (Left) Ore sets and rings -This defines left Ore sets on arbitrary monoids. +This file contains results on left Ore sets for rings and monoids with zero. ## References @@ -19,106 +20,8 @@ This defines left Ore sets on arbitrary monoids. -/ -namespace AddOreLocalization - -/-- A submonoid `S` of an additive monoid `R` is (left) Ore if common summands on the right can be -turned into common summands on the left, and if each pair of `r : R` and `s : S` admits an Ore -minuend `v : R` and an Ore subtrahend `u : S` such that `u + r = v + s`. -/ -class AddOreSet {R : Type*} [AddMonoid R] (S : AddSubmonoid R) where - /-- Common summands on the right can be turned into common summands on the left, a weak form of -cancellability. -/ - ore_right_cancel : ∀ (r₁ r₂ : R) (s : S), r₁ + s = r₂ + s → ∃ s' : S, s' + r₁ = s' + r₂ - /-- The Ore minuend of a difference. -/ - oreMin : R → S → R - /-- The Ore subtrahend of a difference. -/ - oreSubtra : R → S → S - /-- The Ore condition of a difference, expressed in terms of `oreMin` and `oreSubtra`. -/ - ore_eq : ∀ (r : R) (s : S), oreSubtra r s + r = oreMin r s + s - -end AddOreLocalization - namespace OreLocalization -section Monoid - -/-- A submonoid `S` of a monoid `R` is (left) Ore if common factors on the right can be turned -into common factors on the left, and if each pair of `r : R` and `s : S` admits an Ore numerator -`v : R` and an Ore denominator `u : S` such that `u * r = v * s`. -/ -@[to_additive AddOreLocalization.AddOreSet] -class OreSet {R : Type*} [Monoid R] (S : Submonoid R) where - /-- Common factors on the right can be turned into common factors on the left, a weak form of -cancellability. -/ - ore_right_cancel : ∀ (r₁ r₂ : R) (s : S), r₁ * s = r₂ * s → ∃ s' : S, s' * r₁ = s' * r₂ - /-- The Ore numerator of a fraction. -/ - oreNum : R → S → R - /-- The Ore denominator of a fraction. -/ - oreDenom : R → S → S - /-- The Ore condition of a fraction, expressed in terms of `oreNum` and `oreDenom`. -/ - ore_eq : ∀ (r : R) (s : S), oreDenom r s * r = oreNum r s * s - --- TODO: use this once it's available. --- run_cmd to_additive.map_namespace `OreLocalization `AddOreLocalization - -variable {R : Type*} [Monoid R] {S : Submonoid R} [OreSet S] - -/-- Common factors on the right can be turned into common factors on the left, a weak form of -cancellability. -/ -@[to_additive AddOreLocalization.ore_right_cancel] -theorem ore_right_cancel (r₁ r₂ : R) (s : S) (h : r₁ * s = r₂ * s) : ∃ s' : S, s' * r₁ = s' * r₂ := - OreSet.ore_right_cancel r₁ r₂ s h - -/-- The Ore numerator of a fraction. -/ -@[to_additive AddOreLocalization.oreMin "The Ore minuend of a difference."] -def oreNum (r : R) (s : S) : R := - OreSet.oreNum r s - -/-- The Ore denominator of a fraction. -/ -@[to_additive AddOreLocalization.oreSubtra "The Ore subtrahend of a difference."] -def oreDenom (r : R) (s : S) : S := - OreSet.oreDenom r s - -/-- The Ore condition of a fraction, expressed in terms of `oreNum` and `oreDenom`. -/ -@[to_additive AddOreLocalization.add_ore_eq - "The Ore condition of a difference, expressed in terms of `oreMin` and `oreSubtra`."] -theorem ore_eq (r : R) (s : S) : oreDenom r s * r = oreNum r s * s := - OreSet.ore_eq r s - -/-- The Ore condition bundled in a sigma type. This is useful in situations where we want to obtain -both witnesses and the condition for a given fraction. -/ -@[to_additive AddOreLocalization.addOreCondition - "The Ore condition bundled in a sigma type. This is useful in situations where we want to obtain -both witnesses and the condition for a given difference."] -def oreCondition (r : R) (s : S) : Σ'r' : R, Σ's' : S, s' * r = r' * s := - ⟨oreNum r s, oreDenom r s, ore_eq r s⟩ - -/-- The trivial submonoid is an Ore set. -/ -@[to_additive AddOreLocalization.addOreSetBot] -instance oreSetBot : OreSet (⊥ : Submonoid R) where - ore_right_cancel _ _ s h := - ⟨s, by - rcases s with ⟨s, hs⟩ - rw [Submonoid.mem_bot] at hs - subst hs - rw [mul_one, mul_one] at h - subst h - rfl⟩ - oreNum r _ := r - oreDenom _ s := s - ore_eq _ s := by - rcases s with ⟨s, hs⟩ - rw [Submonoid.mem_bot] at hs - simp [hs] - -/-- Every submonoid of a commutative monoid is an Ore set. -/ -@[to_additive AddOreLocalization.addOreSetComm] -instance (priority := 100) oreSetComm {R} [CommMonoid R] (S : Submonoid R) : OreSet S where - ore_right_cancel m n s h := ⟨s, by rw [mul_comm (s : R) n, mul_comm (s : R) m, h]⟩ - oreNum r _ := r - oreDenom _ s := s - ore_eq r s := by rw [mul_comm] - -end Monoid - /-- Cancellability in monoids with zeros can act as a replacement for the `ore_right_cancel` condition of an ore set. -/ def oreSetOfCancelMonoidWithZero {R : Type*} [CancelMonoidWithZero R] {S : Submonoid R} diff --git a/Mathlib/RingTheory/OreLocalization/Ring.lean b/Mathlib/RingTheory/OreLocalization/Ring.lean index 2a911ebd37017..d76032bfbc512 100644 --- a/Mathlib/RingTheory/OreLocalization/Ring.lean +++ b/Mathlib/RingTheory/OreLocalization/Ring.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob von Raumer, Kevin Klinge, Andrew Yang -/ -import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.Algebra.Algebra.Defs import Mathlib.Algebra.Field.Defs +import Mathlib.Algebra.GroupWithZero.NonZeroDivisors +import Mathlib.Algebra.Module.End import Mathlib.RingTheory.OreLocalization.Basic /-! @@ -275,9 +276,9 @@ instance : DivisionRing R[R⁰⁻¹] where mul_inv_cancel := OreLocalization.mul_inv_cancel inv_zero := OreLocalization.inv_zero nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl end DivisionRing diff --git a/Mathlib/RingTheory/Perfection.lean b/Mathlib/RingTheory/Perfection.lean index 341d08d64c115..4206fc2c57b98 100644 --- a/Mathlib/RingTheory/Perfection.lean +++ b/Mathlib/RingTheory/Perfection.lean @@ -3,6 +3,7 @@ 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.CharP.ExpChar import Mathlib.Algebra.CharP.Pi import Mathlib.Algebra.CharP.Quotient import Mathlib.Algebra.CharP.Subring @@ -165,14 +166,14 @@ noncomputable def lift (R : Type u₁) [CommSemiring R] [CharP R p] [PerfectRing toFun f := { toFun := fun r => ⟨fun n => f (((frobeniusEquiv R p).symm : R →+* R)^[n] r), fun n => by erw [← f.map_pow, Function.iterate_succ_apply', frobeniusEquiv_symm_pow_p]⟩ - map_one' := ext fun n => (congr_arg f <| iterate_map_one _ _).trans f.map_one - map_mul' := fun x y => - ext fun n => (congr_arg f <| iterate_map_mul _ _ _ _).trans <| f.map_mul _ _ - map_zero' := ext fun n => (congr_arg f <| iterate_map_zero _ _).trans f.map_zero - map_add' := fun x y => - ext fun n => (congr_arg f <| iterate_map_add _ _ _ _).trans <| f.map_add _ _ } + map_one' := ext fun _ => (congr_arg f <| iterate_map_one _ _).trans f.map_one + map_mul' := fun _ _ => + ext fun _ => (congr_arg f <| iterate_map_mul _ _ _ _).trans <| f.map_mul _ _ + map_zero' := ext fun _ => (congr_arg f <| iterate_map_zero _ _).trans f.map_zero + map_add' := fun _ _ => + ext fun _ => (congr_arg f <| iterate_map_add _ _ _ _).trans <| f.map_add _ _ } invFun := RingHom.comp <| coeff S p 0 - left_inv f := RingHom.ext fun r => rfl + left_inv _ := RingHom.ext fun _ => rfl right_inv f := RingHom.ext fun r => ext fun n => show coeff S p 0 (f (((frobeniusEquiv R p).symm)^[n] r)) = coeff S p n (f r) by rw [← coeff_iterate_frobenius _ 0 n, zero_add, ← RingHom.map_iterate_frobenius, @@ -190,9 +191,9 @@ variable {R} {S : Type u₂} [CommSemiring S] [CharP S p] def map (φ : R →+* S) : Ring.Perfection R p →+* Ring.Perfection S p where toFun f := ⟨fun n => φ (coeff R p n f), fun n => by rw [← φ.map_pow, coeff_pow_p']⟩ map_one' := Subtype.eq <| funext fun _ => φ.map_one - map_mul' f g := Subtype.eq <| funext fun n => φ.map_mul _ _ + map_mul' _ _ := Subtype.eq <| funext fun _ => φ.map_mul _ _ map_zero' := Subtype.eq <| funext fun _ => φ.map_zero - map_add' f g := Subtype.eq <| funext fun n => φ.map_add _ _ + map_add' _ _ := Subtype.eq <| funext fun _ => φ.map_add _ _ theorem coeff_map (φ : R →+* S) (f : Ring.Perfection R p) (n : ℕ) : coeff S p n (map p φ f) = φ (coeff R p n f) := rfl @@ -237,7 +238,7 @@ theorem of : PerfectionMap p (Perfection.coeff R p 0) := /-- For a perfect ring, it itself is the perfection. -/ theorem id [PerfectRing R p] : PerfectionMap p (RingHom.id R) := - { injective := fun x y hxy => hxy 0 + { injective := fun _ _ hxy => hxy 0 surjective := fun f hf => ⟨f 0, fun n => show ((frobeniusEquiv R p).symm)^[n] (f 0) = f n from diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index ab6d03ba20af2..4a7e163739c83 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -3,7 +3,8 @@ 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.CharP.ExpChar +import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.GeomSum import Mathlib.Algebra.MvPolynomial.CommRing import Mathlib.Algebra.MvPolynomial.Equiv import Mathlib.RingTheory.Polynomial.Content @@ -581,7 +582,7 @@ theorem mem_map_C_iff {I : Ideal R} {f : R[X]} : f ∈ (Ideal.map (C : R →+* R[X]) I : Ideal R[X]) ↔ ∀ n : ℕ, f.coeff n ∈ I := by constructor · intro hf - apply @Submodule.span_induction _ _ _ _ _ f _ _ hf + refine Submodule.span_induction ?_ ?_ ?_ ?_ hf · intro f hf n cases' (Set.mem_image _ _ _).mp hf with x hx rw [← hx.right, coeff_C] @@ -589,8 +590,8 @@ theorem mem_map_C_iff {I : Ideal R} {f : R[X]} : · simpa [h] using hx.left · simp [h] · simp - · exact fun f g hf hg n => by simp [I.add_mem (hf n) (hg n)] - · refine fun f g hg n => ?_ + · exact fun f g _ _ hf hg n => by simp [I.add_mem (hf n) (hg n)] + · refine fun f g _ hg n => ?_ rw [smul_eq_mul, coeff_mul] exact I.sum_mem fun c _ => I.mul_mem_left (f.coeff c.fst) (hg c.snd) · intro hf @@ -788,7 +789,7 @@ variable (σ) {r : R} namespace Polynomial theorem prime_C_iff : Prime (C r) ↔ Prime r := - ⟨comap_prime C (evalRingHom (0 : R)) fun r => eval_C, fun hr => by + ⟨comap_prime C (evalRingHom (0 : R)) fun _ => eval_C, fun hr => by have := hr.1 rw [← Ideal.span_singleton_prime] at hr ⊢ · rw [← Set.image_singleton, ← Ideal.map_span] @@ -912,7 +913,7 @@ protected theorem Polynomial.isNoetherianRing [inst : IsNoetherianRing R] : IsNo let ⟨N, HN⟩ := hm let ⟨s, hs⟩ := I.is_fg_degreeLE N have hm2 : ∀ k, I.leadingCoeffNth k ≤ M := fun k => - Or.casesOn (le_or_lt k N) (fun h => HN ▸ I.leadingCoeffNth_mono h) fun h x hx => + Or.casesOn (le_or_lt k N) (fun h => HN ▸ I.leadingCoeffNth_mono h) fun h _ hx => Classical.by_contradiction fun hxm => haveI : IsNoetherian R R := inst have : ¬M < I.leadingCoeffNth k := by @@ -920,8 +921,8 @@ protected theorem Polynomial.isNoetherianRing [inst : IsNoetherianRing R] : IsNo this ⟨HN ▸ I.leadingCoeffNth_mono (le_of_lt h), fun H => hxm (H hx)⟩ have hs2 : ∀ {x}, x ∈ I.degreeLE N → x ∈ Ideal.span (↑s : Set R[X]) := hs ▸ fun hx => - Submodule.span_induction hx (fun _ hx => Ideal.subset_span hx) (Ideal.zero_mem _) - (fun _ _ => Ideal.add_mem _) fun c f hf => f.C_mul' c ▸ Ideal.mul_mem_left _ _ hf + Submodule.span_induction (hx := hx) (fun _ hx => Ideal.subset_span hx) (Ideal.zero_mem _) + (fun _ _ _ _ => Ideal.add_mem _) fun c f _ hf => f.C_mul' c ▸ Ideal.mul_mem_left _ _ hf ⟨s, le_antisymm (Ideal.span_le.2 fun x hx => have : x ∈ I.degreeLE N := hs ▸ Submodule.subset_span hx this.2) <| by @@ -1183,7 +1184,7 @@ theorem mem_map_C_iff {I : Ideal R} {f : MvPolynomial σ R} : classical constructor · intro hf - apply @Submodule.span_induction _ _ _ _ Semiring.toModule f _ _ hf + refine Submodule.span_induction ?_ ?_ ?_ ?_ hf · intro f hf n cases' (Set.mem_image _ _ _).mp hf with x hx rw [← hx.right, coeff_C] @@ -1191,8 +1192,8 @@ theorem mem_map_C_iff {I : Ideal R} {f : MvPolynomial σ R} : · simpa [h] using hx.left · simp [Ne.symm h] · simp - · exact fun f g hf hg n => by simp [I.add_mem (hf n) (hg n)] - · refine fun f g hg n => ?_ + · exact fun f g _ _ hf hg n => by simp [I.add_mem (hf n) (hg n)] + · refine fun f g _ hg n => ?_ rw [smul_eq_mul, coeff_mul] exact I.sum_mem fun c _ => I.mul_mem_left (f.coeff c.fst) (hg c.snd) · intro hf diff --git a/Mathlib/RingTheory/Polynomial/Bernstein.lean b/Mathlib/RingTheory/Polynomial/Bernstein.lean index 8cae9a4f38a0d..640f8b722b5e6 100644 --- a/Mathlib/RingTheory/Polynomial/Bernstein.lean +++ b/Mathlib/RingTheory/Polynomial/Bernstein.lean @@ -246,13 +246,13 @@ theorem linearIndependent_aux (n k : ℕ) (h : k ≤ n + 1) : suffices (Polynomial.derivative^[n - k] p).eval 1 = 0 by rw [this] exact (iterate_derivative_at_1_ne_zero ℚ n k h).symm - refine span_induction m ?_ ?_ ?_ ?_ + refine span_induction ?_ ?_ ?_ ?_ m · simp only [Set.mem_range, forall_exists_index, forall_apply_eq_imp_iff] rintro ⟨a, w⟩; simp only [Fin.val_mk] rw [iterate_derivative_at_1_eq_zero_of_lt ℚ n ((tsub_lt_tsub_iff_left_of_le h).mpr w)] · simp - · intro x y hx hy; simp [hx, hy] - · intro a x h; simp [h] + · intro x y _ _ hx hy; simp [hx, hy] + · intro a x _ h; simp [h] /-- The Bernstein polynomials are linearly independent. diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean index 1d3ab8d7d15d0..65b40dc6f9351 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean @@ -584,4 +584,15 @@ theorem orderOf_root_cyclotomic_dvd {n : ℕ} (hpos : 0 < n) {p : ℕ} [Fact p.P end Order +section miscellaneous + +lemma dvd_C_mul_X_sub_one_pow_add_one {R : Type*} [CommRing R] {p : ℕ} (hpri : p.Prime) + (hp : p ≠ 2) (a r : R) (h₁ : r ∣ a ^ p) (h₂ : r ∣ p * a) : C r ∣ (C a * X - 1) ^ p + 1 := by + have := hpri.dvd_add_pow_sub_pow_of_dvd (C a * X) (-1) (r := C r) ?_ ?_ + · rwa [← sub_eq_add_neg, (hpri.odd_of_ne_two hp).neg_pow, one_pow, sub_neg_eq_add] at this + · simp only [mul_pow, ← map_pow, dvd_mul_right, (_root_.map_dvd C h₁).trans] + simp only [map_mul, map_natCast, ← mul_assoc, dvd_mul_right, (_root_.map_dvd C h₂).trans] + +end miscellaneous + end Polynomial diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean index 4a1ad15664ee8..4729d0aab257a 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean @@ -29,7 +29,6 @@ theorem eval_one_cyclotomic_prime {R : Type*} [CommRing R] {p : ℕ} [hn : Fact simp only [cyclotomic_prime, eval_X, one_pow, Finset.sum_const, eval_pow, eval_finset_sum, Finset.card_range, smul_one_eq_cast] --- @[simp] -- Porting note (#10618): simp already proves this theorem eval₂_one_cyclotomic_prime {R S : Type*} [CommRing R] [Semiring S] (f : R →+* S) {p : ℕ} [Fact p.Prime] : eval₂ f 1 (cyclotomic p R) = p := by simp @@ -39,7 +38,6 @@ theorem eval_one_cyclotomic_prime_pow {R : Type*} [CommRing R] {p : ℕ} (k : simp only [cyclotomic_prime_pow_eq_geom_sum hn.out, eval_X, one_pow, Finset.sum_const, eval_pow, eval_finset_sum, Finset.card_range, smul_one_eq_cast] --- @[simp] -- Porting note (#10618): simp already proves this theorem eval₂_one_cyclotomic_prime_pow {R S : Type*} [CommRing R] [Semiring S] (f : R →+* S) {p : ℕ} (k : ℕ) [Fact p.Prime] : eval₂ f 1 (cyclotomic (p ^ (k + 1)) R) = p := by simp @@ -212,7 +210,7 @@ theorem sub_one_pow_totient_le_cyclotomic_eval {q : ℝ} (hq' : 1 < q) : ∀ n, (q - 1) ^ totient n ≤ (cyclotomic n ℝ).eval q | 0 => by simp only [totient_zero, _root_.pow_zero, cyclotomic_zero, eval_one, le_refl] | 1 => by simp only [totient_one, pow_one, cyclotomic_one, eval_sub, eval_X, eval_one, le_refl] - | n + 2 => (sub_one_pow_totient_lt_cyclotomic_eval le_add_self hq').le + | _ + 2 => (sub_one_pow_totient_lt_cyclotomic_eval le_add_self hq').le theorem cyclotomic_eval_lt_add_one_pow_totient {n : ℕ} {q : ℝ} (hn' : 3 ≤ n) (hq' : 1 < q) : (cyclotomic n ℝ).eval q < (q + 1) ^ totient n := by @@ -285,7 +283,7 @@ theorem cyclotomic_eval_le_add_one_pow_totient {q : ℝ} (hq' : 1 < q) : | 0 => by simp | 1 => by simp [add_assoc, add_nonneg, zero_le_one] | 2 => by simp - | n + 3 => (cyclotomic_eval_lt_add_one_pow_totient le_add_self hq').le + | _ + 3 => (cyclotomic_eval_lt_add_one_pow_totient le_add_self hq').le theorem sub_one_pow_totient_lt_natAbs_cyclotomic_eval {n : ℕ} {q : ℕ} (hn' : 1 < n) (hq : q ≠ 1) : (q - 1) ^ totient n < ((cyclotomic n ℤ).eval ↑q).natAbs := by diff --git a/Mathlib/RingTheory/Polynomial/Dickson.lean b/Mathlib/RingTheory/Polynomial/Dickson.lean index fdb6b3b533b34..bf67e4ffe8272 100644 --- a/Mathlib/RingTheory/Polynomial/Dickson.lean +++ b/Mathlib/RingTheory/Polynomial/Dickson.lean @@ -7,7 +7,7 @@ import Mathlib.Algebra.CharP.Invertible import Mathlib.Data.ZMod.Basic import Mathlib.RingTheory.Localization.FractionRing import Mathlib.RingTheory.Polynomial.Chebyshev -import Mathlib.Algebra.CharP.Basic +import Mathlib.Algebra.CharP.Lemmas import Mathlib.Algebra.EuclideanDomain.Field import Mathlib.Algebra.Polynomial.Roots @@ -200,9 +200,8 @@ theorem dickson_one_one_zmod_p (p : ℕ) [Fact p.Prime] : dickson 1 (1 : ZMod p) -- The two polynomials agree on all `x` of the form `x = y + y⁻¹`. apply @Set.Infinite.mono _ { x : K | ∃ y, x = y + y⁻¹ ∧ y ≠ 0 } · rintro _ ⟨x, rfl, hx⟩ - simp only [eval_X, eval_pow, Set.mem_setOf_eq, @add_pow_char K _ p, - dickson_one_one_eval_add_inv _ _ (mul_inv_cancel₀ hx), inv_pow, ZMod.castHom_apply, - ZMod.cast_one'] + simp only [eval_X, eval_pow, Set.mem_setOf_eq, ZMod.cast_one', add_pow_char, + dickson_one_one_eval_add_inv _ _ (mul_inv_cancel₀ hx), ZMod.castHom_apply] -- Now we need to show that the set of such `x` is infinite. -- If the set is finite, then we will show that `K` is also finite. · intro h diff --git a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean index 6f7d2d23edce3..fa81775947129 100644 --- a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean @@ -60,8 +60,6 @@ theorem hermite_eq_iterate (n : ℕ) : hermite n = (fun p => X * p - derivative theorem hermite_zero : hermite 0 = C 1 := rfl --- Porting note (#10618): There was initially @[simp] on this line but it was removed --- because simp can prove this theorem theorem hermite_one : hermite 1 = X := by rw [hermite_succ, hermite_zero] simp only [map_one, mul_one, derivative_one, sub_zero] diff --git a/Mathlib/RingTheory/Polynomial/IrreducibleRing.lean b/Mathlib/RingTheory/Polynomial/IrreducibleRing.lean index c2e72452a8f8e..fde8375d8c35a 100644 --- a/Mathlib/RingTheory/Polynomial/IrreducibleRing.lean +++ b/Mathlib/RingTheory/Polynomial/IrreducibleRing.lean @@ -3,7 +3,6 @@ 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.Algebra.Polynomial.RingDivision import Mathlib.RingTheory.Polynomial.Nilpotent /-! diff --git a/Mathlib/RingTheory/Polynomial/Nilpotent.lean b/Mathlib/RingTheory/Polynomial/Nilpotent.lean index 1579b65f458f9..a921d48c10bc8 100644 --- a/Mathlib/RingTheory/Polynomial/Nilpotent.lean +++ b/Mathlib/RingTheory/Polynomial/Nilpotent.lean @@ -6,10 +6,10 @@ Authors: Emilie Uthaiwat, Oliver Nash import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.Algebra.Polynomial.Div import Mathlib.Algebra.Polynomial.Identities -import Mathlib.RingTheory.Ideal.QuotientOperations +import Mathlib.RingTheory.Ideal.Quotient.Operations +import Mathlib.RingTheory.Nilpotent.Basic import Mathlib.RingTheory.Nilpotent.Lemmas import Mathlib.RingTheory.Polynomial.Tower -import Mathlib.RingTheory.Nilpotent.Basic /-! # Nilpotency in polynomial rings. diff --git a/Mathlib/RingTheory/Polynomial/Pochhammer.lean b/Mathlib/RingTheory/Polynomial/Pochhammer.lean index a96e49ebd3495..a3dc6084fd575 100644 --- a/Mathlib/RingTheory/Polynomial/Pochhammer.lean +++ b/Mathlib/RingTheory/Polynomial/Pochhammer.lean @@ -3,10 +3,9 @@ Copyright (c) 2020 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.Algebra.Polynomial.Degree.Definitions -import Mathlib.Algebra.Polynomial.Eval -import Mathlib.Algebra.Polynomial.Monic -import Mathlib.Algebra.Polynomial.RingDivision +import Mathlib.Algebra.Algebra.Basic +import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.Polynomial.Degree.Lemmas import Mathlib.Tactic.Abel /-! @@ -24,6 +23,8 @@ that are focused on `Nat` can be found in `Data.Nat.Factorial` as `Nat.ascFactor As with many other families of polynomials, even though the coefficients are always in `ℕ` or `ℤ` , we define the polynomial with coefficients in any `[Semiring S]` or `[Ring R]`. +In an integral domain `S`, we show that `ascPochhammer S n` is zero iff +`n` is a sufficiently large non-positive integer. ## TODO @@ -372,4 +373,38 @@ theorem descPochhammer_int_eq_ascFactorial (a b : ℕ) : rw [← Nat.cast_add, descPochhammer_eval_eq_descFactorial ℤ (a + b) b, Nat.add_descFactorial_eq_ascFactorial] +variable {R} + +/-- The Pochhammer polynomial of degree `n` has roots at `0`, `-1`, ..., `-(n - 1)`. -/ +theorem ascPochhammer_eval_neg_coe_nat_of_lt {n k : ℕ} (h : k < n) : + (ascPochhammer R n).eval (-(k : R)) = 0 := by + induction n with + | zero => contradiction + | succ n ih => + rw [ascPochhammer_succ_eval] + rcases lt_trichotomy k n with hkn | rfl | hkn + · simp [ih hkn] + · simp + · omega + +/-- Over an integral domain, the Pochhammer polynomial of degree `n` has roots *only* at +`0`, `-1`, ..., `-(n - 1)`. -/ +@[simp] +theorem ascPochhammer_eval_eq_zero_iff [IsDomain R] + (n : ℕ) (r : R) : (ascPochhammer R n).eval r = 0 ↔ ∃ k < n, k = -r := by + refine ⟨fun zero' ↦ ?_, fun hrn ↦ ?_⟩ + · induction n with + | zero => simp only [ascPochhammer_zero, Polynomial.eval_one, one_ne_zero] at zero' + | succ n ih => + rw [ascPochhammer_succ_eval, mul_eq_zero] at zero' + cases zero' with + | inl h => + obtain ⟨rn, hrn, rrn⟩ := ih h + exact ⟨rn, by omega, rrn⟩ + | inr h => + exact ⟨n, lt_add_one n, eq_neg_of_add_eq_zero_right h⟩ + · obtain ⟨rn, hrn, rnn⟩ := hrn + convert ascPochhammer_eval_neg_coe_nat_of_lt hrn + simp [rnn] + end Ring diff --git a/Mathlib/RingTheory/Polynomial/Quotient.lean b/Mathlib/RingTheory/Polynomial/Quotient.lean index 1f6608a4850b7..7b81b10264dcd 100644 --- a/Mathlib/RingTheory/Polynomial/Quotient.lean +++ b/Mathlib/RingTheory/Polynomial/Quotient.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, David Kurniadi Angdinata, Devon Tuma, Riccardo Brasca -/ import Mathlib.Algebra.Polynomial.Div +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Polynomial.Basic -import Mathlib.RingTheory.Ideal.QuotientOperations /-! # Quotients of polynomial rings @@ -211,10 +211,10 @@ lemma quotientEquivQuotientMvPolynomial_rightInverse (I : Ideal R) : Function.RightInverse (eval₂ (Ideal.Quotient.lift I ((Ideal.Quotient.mk (Ideal.map C I : Ideal (MvPolynomial σ R))).comp C) - fun i hi => quotient_map_C_eq_zero hi) + fun _ hi => quotient_map_C_eq_zero hi) fun i => Ideal.Quotient.mk (Ideal.map C I : Ideal (MvPolynomial σ R)) (X i)) (Ideal.Quotient.lift (Ideal.map C I : Ideal (MvPolynomial σ R)) - (eval₂Hom (C.comp (Ideal.Quotient.mk I)) X) fun a ha => eval₂_C_mk_eq_zero ha) := by + (eval₂Hom (C.comp (Ideal.Quotient.mk I)) X) fun _ ha => eval₂_C_mk_eq_zero ha) := by intro f apply induction_on f · intro r @@ -233,10 +233,10 @@ lemma quotientEquivQuotientMvPolynomial_leftInverse (I : Ideal R) : Function.LeftInverse (eval₂ (Ideal.Quotient.lift I ((Ideal.Quotient.mk (Ideal.map C I : Ideal (MvPolynomial σ R))).comp C) - fun i hi => quotient_map_C_eq_zero hi) + fun _ hi => quotient_map_C_eq_zero hi) fun i => Ideal.Quotient.mk (Ideal.map C I : Ideal (MvPolynomial σ R)) (X i)) (Ideal.Quotient.lift (Ideal.map C I : Ideal (MvPolynomial σ R)) - (eval₂Hom (C.comp (Ideal.Quotient.mk I)) X) fun a ha => eval₂_C_mk_eq_zero ha) := by + (eval₂Hom (C.comp (Ideal.Quotient.mk I)) X) fun _ ha => eval₂_C_mk_eq_zero ha) := by intro f obtain ⟨f, rfl⟩ := Ideal.Quotient.mk_surjective f apply induction_on f @@ -244,7 +244,7 @@ lemma quotientEquivQuotientMvPolynomial_leftInverse (I : Ideal R) : rw [Ideal.Quotient.lift_mk, eval₂Hom_C, RingHom.comp_apply, eval₂_C, Ideal.Quotient.lift_mk, RingHom.comp_apply] · intros p q hp hq - erw [Ideal.Quotient.lift_mk] at hp hq ⊢ + rw [Ideal.Quotient.lift_mk] at hp hq ⊢ simp only [Submodule.Quotient.quot_mk_eq_mk, eval₂_add, RingHom.map_add, coe_eval₂Hom, Ideal.Quotient.lift_mk, Ideal.Quotient.mk_eq_mk] at hp hq ⊢ rw [hp, hq] diff --git a/Mathlib/RingTheory/Polynomial/SeparableDegree.lean b/Mathlib/RingTheory/Polynomial/SeparableDegree.lean index 6d5e04ba59670..dbe6bd9a2047e 100644 --- a/Mathlib/RingTheory/Polynomial/SeparableDegree.lean +++ b/Mathlib/RingTheory/Polynomial/SeparableDegree.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob Scholbach -/ import Mathlib.Algebra.Algebra.Defs -import Mathlib.Algebra.CharP.ExpChar import Mathlib.FieldTheory.Separable /-! diff --git a/Mathlib/RingTheory/Polynomial/Vieta.lean b/Mathlib/RingTheory/Polynomial/Vieta.lean index 6ad52b3eb26ac..6df36b563f3c0 100644 --- a/Mathlib/RingTheory/Polynomial/Vieta.lean +++ b/Mathlib/RingTheory/Polynomial/Vieta.lean @@ -22,13 +22,10 @@ we derive `Polynomial.coeff_eq_esymm_roots_of_card`, the relationship between th the roots of `p` for a polynomial `p` that splits (i.e. having as many roots as its degree). -/ - -open Polynomial +open Finset Polynomial namespace Multiset -open Polynomial - section Semiring variable {R : Type*} [CommSemiring R] @@ -70,8 +67,8 @@ theorem prod_X_add_C_coeff' {σ} (s : Multiset σ) (r : σ → R) {k : ℕ} (h : (s.map fun i => X + C (r i)).prod.coeff k = (s.map r).esymm (Multiset.card s - k) := by erw [← map_map (fun r => X + C r) r, prod_X_add_C_coeff] <;> rw [s.card_map r]; assumption -theorem _root_.Finset.prod_X_add_C_coeff {σ} (s : Finset σ) (r : σ → R) {k : ℕ} (h : k ≤ s.card) : - (∏ i ∈ s, (X + C (r i))).coeff k = ∑ t ∈ s.powersetCard (s.card - k), ∏ i ∈ t, r i := by +theorem _root_.Finset.prod_X_add_C_coeff {σ} (s : Finset σ) (r : σ → R) {k : ℕ} (h : k ≤ #s) : + (∏ i ∈ s, (X + C (r i))).coeff k = ∑ t ∈ s.powersetCard (#s - k), ∏ i ∈ t, r i := by rw [Finset.prod, prod_X_add_C_coeff' _ r h, Finset.esymm_map_val] rfl diff --git a/Mathlib/RingTheory/PolynomialAlgebra.lean b/Mathlib/RingTheory/PolynomialAlgebra.lean index 410b46c3aec39..278543baf82c4 100644 --- a/Mathlib/RingTheory/PolynomialAlgebra.lean +++ b/Mathlib/RingTheory/PolynomialAlgebra.lean @@ -251,7 +251,7 @@ theorem matPolyEquiv_coeff_apply (m : Matrix n n R[X]) (k : ℕ) (i j : n) : · intro p q hp hq simp [hp, hq] · intro i' j' x - erw [matPolyEquiv_coeff_apply_aux_2] + rw [matPolyEquiv_coeff_apply_aux_2] dsimp [stdBasisMatrix] split_ifs <;> rename_i h · rcases h with ⟨rfl, rfl⟩ diff --git a/Mathlib/RingTheory/PowerBasis.lean b/Mathlib/RingTheory/PowerBasis.lean index a9cf86b0049c1..f410b20ade48b 100644 --- a/Mathlib/RingTheory/PowerBasis.lean +++ b/Mathlib/RingTheory/PowerBasis.lean @@ -308,7 +308,7 @@ noncomputable def liftEquiv (pb : PowerBasis A S) : (S →ₐ[A] S') ≃ { y : S' // aeval y (minpoly A pb.gen) = 0 } where toFun f := ⟨f pb.gen, by rw [aeval_algHom_apply, minpoly.aeval, map_zero]⟩ invFun y := pb.lift y y.2 - left_inv f := pb.algHom_ext <| lift_gen _ _ _ + left_inv _ := pb.algHom_ext <| lift_gen _ _ _ right_inv y := Subtype.ext <| lift_gen _ _ y.prop /-- `pb.liftEquiv'` states that elements of the root set of the minimal @@ -442,7 +442,6 @@ noncomputable def map (pb : PowerBasis R S) (e : S ≃ₐ[R] S') : PowerBasis R variable [Algebra A S] [Algebra A S'] --- @[simp] -- Porting note (#10618): simp can prove this theorem minpolyGen_map (pb : PowerBasis A S) (e : S ≃ₐ[A] S') : (pb.map e).minpolyGen = pb.minpolyGen := by dsimp only [minpolyGen, map_dim] diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index 57422669ec4cd..795804f9c1eed 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -145,7 +145,7 @@ def monomial (n : ℕ) : R →ₗ[R] R⟦X⟧ := variable {R} theorem coeff_def {s : Unit →₀ ℕ} {n : ℕ} (h : s () = n) : coeff R n = MvPowerSeries.coeff R s := by - erw [coeff, ← h, ← Finsupp.unique_single s] + rw [coeff, ← h, ← Finsupp.unique_single s] /-- Two formal power series are equal if all their coefficients are equal. -/ @[ext] @@ -214,8 +214,9 @@ theorem coeff_zero_eq_constantCoeff_apply (φ : R⟦X⟧) : coeff R 0 φ = const @[simp] theorem monomial_zero_eq_C : ⇑(monomial R 0) = C R := by - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [monomial, Finsupp.single_zero, MvPowerSeries.monomial_zero_eq_C] + -- This used to be `rw`, but we need `rw; rfl` after leanprover/lean4#2644 + rw [monomial, Finsupp.single_zero, MvPowerSeries.monomial_zero_eq_C] + rfl theorem monomial_zero_eq_C_apply (a : R) : monomial R 0 a = C R a := by simp @@ -251,8 +252,7 @@ theorem coeff_X (n : ℕ) : coeff R n (X : R⟦X⟧) = if n = 1 then 1 else 0 := @[simp] theorem coeff_zero_X : coeff R 0 (X : R⟦X⟧) = 0 := by - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [coeff, Finsupp.single_zero, X, MvPowerSeries.coeff_zero_X] + rw [coeff, Finsupp.single_zero, X, MvPowerSeries.coeff_zero_X] @[simp] theorem coeff_one_X : coeff R 1 (X : R⟦X⟧) = 1 := by rw [coeff_X, if_pos rfl] @@ -327,13 +327,11 @@ theorem constantCoeff_C (a : R) : constantCoeff R (C R a) = a := theorem constantCoeff_comp_C : (constantCoeff R).comp (C R) = RingHom.id R := rfl --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem constantCoeff_zero : constantCoeff R 0 = 0 := rfl --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem constantCoeff_one : constantCoeff R 1 = 1 := rfl @@ -760,17 +758,19 @@ namespace Polynomial open Finsupp Polynomial -variable {σ : Type*} {R : Type*} [CommSemiring R] (φ ψ : R[X]) +variable {R : Type*} [CommSemiring R] (φ ψ : R[X]) -- Porting note: added so we can add the `@[coe]` attribute /-- The natural inclusion from polynomials into formal power series. -/ @[coe] -def ToPowerSeries : R[X] → (PowerSeries R) := fun φ => +def toPowerSeries : R[X] → (PowerSeries R) := fun φ => PowerSeries.mk fun n => coeff φ n +@[deprecated (since := "2024-10-27")] alias ToPowerSeries := toPowerSeries + /-- The natural inclusion from polynomials into formal power series. -/ instance coeToPowerSeries : Coe R[X] (PowerSeries R) := - ⟨ToPowerSeries⟩ + ⟨toPowerSeries⟩ theorem coe_def : (φ : PowerSeries R) = PowerSeries.mk (coeff φ) := rfl diff --git a/Mathlib/RingTheory/PowerSeries/Inverse.lean b/Mathlib/RingTheory/PowerSeries/Inverse.lean index a8d96e7a4b2ac..660923cc4da32 100644 --- a/Mathlib/RingTheory/PowerSeries/Inverse.lean +++ b/Mathlib/RingTheory/PowerSeries/Inverse.lean @@ -54,8 +54,7 @@ theorem coeff_inv_aux (n : ℕ) (a : R) (φ : R⟦X⟧) : -a * ∑ x ∈ antidiagonal n, if x.2 < n then coeff R x.1 φ * coeff R x.2 (inv.aux a φ) else 0 := by - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [coeff, inv.aux, MvPowerSeries.coeff_inv_aux] + rw [coeff, inv.aux, MvPowerSeries.coeff_inv_aux] simp only [Finsupp.single_eq_zero] split_ifs; · rfl congr 1 @@ -151,8 +150,7 @@ theorem inv_eq_zero {φ : k⟦X⟧} : φ⁻¹ = 0 ↔ constantCoeff k φ = 0 := theorem zero_inv : (0 : k⟦X⟧)⁻¹ = 0 := MvPowerSeries.zero_inv --- Porting note (#10618): simp can prove this. --- @[simp] +@[simp] theorem invOfUnit_eq (φ : k⟦X⟧) (h : constantCoeff k φ ≠ 0) : invOfUnit φ (Units.mk0 _ h) = φ⁻¹ := MvPowerSeries.invOfUnit_eq _ _ @@ -267,12 +265,16 @@ end Field section LocalRing -variable {S : Type*} [CommRing R] [CommRing S] (f : R →+* S) [IsLocalRingHom f] +variable {S : Type*} [CommRing R] [CommRing S] (f : R →+* S) [IsLocalHom f] + +@[instance] +theorem map.isLocalHom : IsLocalHom (map f) := + MvPowerSeries.map.isLocalHom f -instance map.isLocalRingHom : IsLocalRingHom (map f) := - MvPowerSeries.map.isLocalRingHom f +@[deprecated (since := "2024-10-10")] +alias map.isLocalRingHom := map.isLocalHom -variable [LocalRing R] [LocalRing S] +variable [LocalRing R] instance : LocalRing R⟦X⟧ := { inferInstanceAs <| LocalRing <| MvPowerSeries Unit R with } @@ -353,10 +355,10 @@ theorem normalized_count_X_eq_of_coe {P : k[X]} (hP : P ≠ 0) : Multiset.count PowerSeries.X (normalizedFactors (P : k⟦X⟧)) = Multiset.count Polynomial.X (normalizedFactors P) := by apply eq_of_forall_le_iff - simp only [← PartENat.coe_le_coe] - rw [X_eq_normalize, PowerSeries.X_eq_normalizeX, ← multiplicity_eq_count_normalizedFactors - irreducible_X hP, ← multiplicity_eq_count_normalizedFactors X_irreducible] <;> - simp only [← multiplicity.pow_dvd_iff_le_multiplicity, Polynomial.X_pow_dvd_iff, + simp only [← Nat.cast_le (α := ℕ∞)] + rw [X_eq_normalize, PowerSeries.X_eq_normalizeX, ← emultiplicity_eq_count_normalizedFactors + irreducible_X hP, ← emultiplicity_eq_count_normalizedFactors X_irreducible] <;> + simp only [← pow_dvd_iff_le_emultiplicity, Polynomial.X_pow_dvd_iff, PowerSeries.X_pow_dvd_iff, Polynomial.coeff_coe P, implies_true, ne_eq, coe_eq_zero_iff, hP, not_false_eq_true] diff --git a/Mathlib/RingTheory/PowerSeries/Order.lean b/Mathlib/RingTheory/PowerSeries/Order.lean index cec9d16a7d726..ab2aa878e6585 100644 --- a/Mathlib/RingTheory/PowerSeries/Order.lean +++ b/Mathlib/RingTheory/PowerSeries/Order.lean @@ -7,6 +7,7 @@ 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 @@ -249,27 +250,30 @@ theorem X_pow_order_dvd (h : (order φ).Dom) : X ^ (order φ).get h ∣ φ := by refine coeff_of_lt_order _ ?_ simpa [PartENat.coe_lt_iff] using fun _ => hn -theorem order_eq_multiplicity_X {R : Type*} [Semiring R] [@DecidableRel R⟦X⟧ (· ∣ ·)] (φ : R⟦X⟧) : - order φ = multiplicity X φ := by +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] - refine - le_antisymm (le_multiplicity_of_pow_dvd <| X_pow_order_dvd (order_finite_iff_ne_zero.mpr hφ)) - (PartENat.find_le _ _ ?_) - 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 _ + 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 _ /-- 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 -/ @@ -321,8 +325,12 @@ 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_multiplicity_X] - exact multiplicity.mul X_prime + 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 -- Dividing `X` by the maximal power of `X` dividing it leaves `1`. @[simp] diff --git a/Mathlib/RingTheory/PowerSeries/WellKnown.lean b/Mathlib/RingTheory/PowerSeries/WellKnown.lean index 8b3ce3c34a0ce..292659bb8862f 100644 --- a/Mathlib/RingTheory/PowerSeries/WellKnown.lean +++ b/Mathlib/RingTheory/PowerSeries/WellKnown.lean @@ -18,8 +18,9 @@ In this file we define the following power series: It is given by `∑ n, x ^ n /ₚ u ^ (n + 1)`. * `PowerSeries.invOneSubPow`: given a commutative ring `S` and a number `d : ℕ`, - `PowerSeries.invOneSubPow d : S⟦X⟧ˣ` is the power series `∑ n, Nat.choose (d + n) d` - whose multiplicative inverse is `(1 - X) ^ (d + 1)`. + `PowerSeries.invOneSubPow S d` is the multiplicative inverse of `(1 - X) ^ d` in `S⟦X⟧ˣ`. + When `d` is `0`, `PowerSeries.invOneSubPow S d` will just be `1`. When `d` is positive, + `PowerSeries.invOneSubPow S d` will be `∑ n, Nat.choose (d - 1 + n) (d - 1)`. * `PowerSeries.sin`, `PowerSeries.cos`, `PowerSeries.exp` : power series for sin, cosine, and exponential functions. @@ -64,7 +65,7 @@ end Ring section invOneSubPow -variable {S : Type*} [CommRing S] (d : ℕ) +variable (S : Type*) [CommRing S] (d : ℕ) /-- (1 + X + X^2 + ...) * (1 - X) = 1. @@ -97,39 +98,68 @@ theorem mk_one_pow_eq_mk_choose_add : add_right_comm] /-- -The power series `mk fun n => Nat.choose (d + n) d`, whose multiplicative inverse is -`(1 - X) ^ (d + 1)`. +Given a natural number `d : ℕ` and a commutative ring `S`, `PowerSeries.invOneSubPow S d` is the +multiplicative inverse of `(1 - X) ^ d` in `S⟦X⟧ˣ`. When `d` is `0`, `PowerSeries.invOneSubPow S d` +will just be `1`. When `d` is positive, `PowerSeries.invOneSubPow S d` will be the power series +`mk fun n => Nat.choose (d - 1 + n) (d - 1)`. -/ -noncomputable def invOneSubPow : S⟦X⟧ˣ where - val := mk fun n => Nat.choose (d + n) d - inv := (1 - X) ^ (d + 1) - val_inv := by - rw [← mk_one_pow_eq_mk_choose_add, ← mul_pow, mk_one_mul_one_sub_eq_one, one_pow] - inv_val := by - rw [← mk_one_pow_eq_mk_choose_add, ← mul_pow, mul_comm, mk_one_mul_one_sub_eq_one, one_pow] - -theorem invOneSubPow_val_eq_mk_choose_add : - (invOneSubPow d).val = (mk fun n => Nat.choose (d + n) d : S⟦X⟧) := rfl - -theorem invOneSubPow_val_zero_eq_invUnitSub_one : - (invOneSubPow 0).val = invUnitsSub (1 : Sˣ) := by +noncomputable def invOneSubPow : ℕ → S⟦X⟧ˣ + | 0 => 1 + | d + 1 => { + val := mk fun n => Nat.choose (d + n) d + inv := (1 - X) ^ (d + 1) + val_inv := by + rw [← mk_one_pow_eq_mk_choose_add, ← mul_pow, mk_one_mul_one_sub_eq_one, one_pow] + inv_val := by + rw [← mk_one_pow_eq_mk_choose_add, ← mul_pow, mul_comm, mk_one_mul_one_sub_eq_one, one_pow] + } + +theorem invOneSubPow_zero : invOneSubPow S 0 = 1 := by + delta invOneSubPow + simp only [Units.val_one] + +theorem invOneSubPow_val_eq_mk_sub_one_add_choose_of_pos (h : 0 < d) : + (invOneSubPow S d).val = (mk fun n => Nat.choose (d - 1 + n) (d - 1) : S⟦X⟧) := by + rw [← Nat.sub_one_add_one_eq_of_pos h, invOneSubPow, add_tsub_cancel_right] + +theorem invOneSubPow_val_succ_eq_mk_add_choose : + (invOneSubPow S (d + 1)).val = (mk fun n => Nat.choose (d + n) d : S⟦X⟧) := rfl + +theorem invOneSubPow_val_one_eq_invUnitSub_one : + (invOneSubPow S 1).val = invUnitsSub (1 : Sˣ) := by simp [invOneSubPow, invUnitsSub] /-- The theorem `PowerSeries.mk_one_mul_one_sub_eq_one` implies that `1 - X` is a unit in `S⟦X⟧` whose inverse is the power series `1 + X + X^2 + ...`. This theorem states that for any `d : ℕ`, -`PowerSeries.invOneSubPow d` is equal to `(1 - X)⁻¹ ^ (d + 1)`. +`PowerSeries.invOneSubPow S d` is equal to `(1 - X)⁻¹ ^ d`. -/ theorem invOneSubPow_eq_inv_one_sub_pow : - invOneSubPow d = (Units.mkOfMulEqOne (1 - X) (mk 1 : S⟦X⟧) - <| Eq.trans (mul_comm _ _) mk_one_mul_one_sub_eq_one)⁻¹ ^ (d + 1) := by - rw [inv_pow] - exact (DivisionMonoid.inv_eq_of_mul _ (invOneSubPow d) <| by - rw [← Units.val_eq_one, Units.val_mul, Units.val_pow_eq_pow_val] - exact (invOneSubPow d).inv_val).symm + invOneSubPow S d = + (Units.mkOfMulEqOne (1 - X) (mk 1 : S⟦X⟧) <| + Eq.trans (mul_comm _ _) (mk_one_mul_one_sub_eq_one S))⁻¹ ^ d := by + induction d with + | zero => exact Eq.symm <| pow_zero _ + | succ d _ => + rw [inv_pow] + exact (DivisionMonoid.inv_eq_of_mul _ (invOneSubPow S (d + 1)) <| by + rw [← Units.val_eq_one, Units.val_mul, Units.val_pow_eq_pow_val] + exact (invOneSubPow S (d + 1)).inv_val).symm theorem invOneSubPow_inv_eq_one_sub_pow : - (invOneSubPow d).inv = (1 - X : S⟦X⟧) ^ (d + 1) := rfl + (invOneSubPow S d).inv = (1 - X : S⟦X⟧) ^ d := by + induction d with + | 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 + delta invOneSubPow + simp only [h, 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 end invOneSubPow diff --git a/Mathlib/RingTheory/Presentation.lean b/Mathlib/RingTheory/Presentation.lean index 2cdda618659b5..8cdc5f61d50d6 100644 --- a/Mathlib/RingTheory/Presentation.lean +++ b/Mathlib/RingTheory/Presentation.lean @@ -236,7 +236,7 @@ private lemma span_range_relation_eq_ker_baseChange : | h_C a => simp only [Generators.algebraMap_apply, algHom_C, TensorProduct.algebraMap_apply, id.map_eq_id, RingHom.id_apply, e] - erw [← MvPolynomial.algebraMap_eq, AlgEquiv.commutes] + rw [← MvPolynomial.algebraMap_eq, AlgEquiv.commutes] simp only [TensorProduct.algebraMap_apply, id.map_eq_id, RingHom.id_apply, TensorProduct.map_tmul, AlgHom.coe_id, id_eq, map_one, algebraMap_eq] erw [aeval_C] @@ -248,7 +248,7 @@ private lemma span_range_relation_eq_ker_baseChange : congr erw [aeval_X] rw [Generators.baseChange_val] - erw [H] at H' + rw [H] at H' replace H' : e.symm x ∈ Ideal.map TensorProduct.includeRight P.ker := H' erw [← P.span_range_relation_eq_ker, ← Ideal.mem_comap, Ideal.comap_symm, Ideal.map_map, Ideal.map_span, ← Set.range_comp] at H' diff --git a/Mathlib/RingTheory/Prime.lean b/Mathlib/RingTheory/Prime.lean index eba40fbe15828..331460fc59ec6 100644 --- a/Mathlib/RingTheory/Prime.lean +++ b/Mathlib/RingTheory/Prime.lean @@ -3,10 +3,11 @@ Copyright (c) 2020 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Algebra.Order.Group.Unbundled.Abs +import Mathlib.Algebra.Prime.Defs +import Mathlib.Algebra.Ring.Units /-! # Prime elements in rings @@ -50,7 +51,7 @@ theorem mul_eq_mul_prime_pow {x y a p : R} {n : ℕ} (hp : Prime p) (hx : x * y rcases mul_eq_mul_prime_prod (fun _ _ ↦ hp) (show x * y = a * (range n).prod fun _ ↦ p by simpa) with ⟨t, u, b, c, htus, htu, rfl, rfl, rfl⟩ - exact ⟨t.card, u.card, b, c, by rw [← card_union_of_disjoint htu, htus, card_range], by simp⟩ + exact ⟨#t, #u, b, c, by rw [← card_union_of_disjoint htu, htus, card_range], by simp⟩ end CancelCommMonoidWithZero diff --git a/Mathlib/RingTheory/PrincipalIdealDomain.lean b/Mathlib/RingTheory/PrincipalIdealDomain.lean index 40c180a84813b..f4dab1aafaff0 100644 --- a/Mathlib/RingTheory/PrincipalIdealDomain.lean +++ b/Mathlib/RingTheory/PrincipalIdealDomain.lean @@ -22,7 +22,7 @@ Theorems about PID's are in the `principal_ideal_ring` namespace. - `IsPrincipalIdealRing`: a predicate on rings, saying that every left ideal is principal. - `IsBezout`: the predicate saying that every finitely generated left ideal is principal. - `generator`: a generator of a principal ideal (or more generally submodule) -- `to_unique_factorization_monoid`: a PID is a unique factorization domain +- `to_uniqueFactorizationMonoid`: a PID is a unique factorization domain # Main results @@ -43,7 +43,7 @@ open Submodule section -variable [Ring R] [AddCommGroup M] [Module R M] +variable [Semiring R] [AddCommGroup M] [Module R M] instance bot_isPrincipal : (⊥ : Submodule R M).IsPrincipal := ⟨⟨0, by simp⟩⟩ @@ -72,11 +72,11 @@ end namespace Submodule.IsPrincipal -variable [AddCommGroup M] +variable [AddCommMonoid M] -section Ring +section Semiring -variable [Ring R] [Module R M] +variable [Semiring R] [Module R M] /-- `generator I`, if `I` is a principal submodule, is an `x ∈ M` such that `span R {x} = I` -/ noncomputable def generator (S : Submodule R M) [S.IsPrincipal] : M := @@ -103,7 +103,20 @@ theorem mem_iff_eq_smul_generator (S : Submodule R M) [S.IsPrincipal] {x : M} : theorem eq_bot_iff_generator_eq_zero (S : Submodule R M) [S.IsPrincipal] : S = ⊥ ↔ generator S = 0 := by rw [← @span_singleton_eq_bot R M, span_singleton_generator] -end Ring +protected lemma fg {S : Submodule R M} (h : S.IsPrincipal) : S.FG := + ⟨{h.generator}, by simp only [Finset.coe_singleton, span_singleton_generator]⟩ + +-- See note [lower instance priority] +instance (priority := 100) _root_.PrincipalIdealRing.isNoetherianRing [IsPrincipalIdealRing R] : + IsNoetherianRing R where + noetherian S := (IsPrincipalIdealRing.principal S).fg + +-- See note [lower instance priority] +instance (priority := 100) _root_.IsPrincipalIdealRing.of_isNoetherianRing_of_isBezout + [IsNoetherianRing R] [IsBezout R] : IsPrincipalIdealRing R where + principal S := IsBezout.isPrincipal_of_FG S (IsNoetherian.noetherian S) + +end Semiring section CommRing @@ -278,15 +291,6 @@ namespace PrincipalIdealRing open IsPrincipalIdealRing --- see Note [lower instance priority] -instance (priority := 100) isNoetherianRing [Ring R] [IsPrincipalIdealRing R] : - IsNoetherianRing R := - isNoetherianRing_iff.2 - ⟨fun s : Ideal R => by - rcases (IsPrincipalIdealRing.principal s).principal with ⟨a, rfl⟩ - rw [← Finset.coe_singleton] - exact ⟨{a}, SetLike.coe_injective rfl⟩⟩ - theorem isMaximal_of_irreducible [CommRing R] [IsPrincipalIdealRing R] {p : R} (hp : Irreducible p) : Ideal.IsMaximal (span R ({p} : Set R)) := ⟨⟨mt Ideal.span_singleton_eq_top.1 hp.1, fun I hI => by @@ -348,23 +352,32 @@ section Surjective open Submodule -variable {S N : Type*} [Ring R] [AddCommGroup M] [AddCommGroup N] [Ring S] -variable [Module R M] [Module R N] +variable {S N F : Type*} [Ring R] [AddCommGroup M] [AddCommGroup N] [Ring S] +variable [Module R M] [Module R N] [FunLike F R S] [RingHomClass F R S] + +theorem Submodule.IsPrincipal.map (f : M →ₗ[R] N) {S : Submodule R M} + (hI : IsPrincipal S) : IsPrincipal (map f S) := + ⟨⟨f (IsPrincipal.generator S), by + rw [← Set.image_singleton, ← map_span, span_singleton_generator]⟩⟩ theorem Submodule.IsPrincipal.of_comap (f : M →ₗ[R] N) (hf : Function.Surjective f) - (S : Submodule R N) [hI : IsPrincipal (S.comap f)] : IsPrincipal S := - ⟨⟨f (IsPrincipal.generator (S.comap f)), by - rw [← Set.image_singleton, ← Submodule.map_span, IsPrincipal.span_singleton_generator, - Submodule.map_comap_eq_of_surjective hf]⟩⟩ - -theorem Ideal.IsPrincipal.of_comap (f : R →+* S) (hf : Function.Surjective f) (I : Ideal S) - [hI : IsPrincipal (I.comap f)] : IsPrincipal I := - ⟨⟨f (IsPrincipal.generator (I.comap f)), by + (S : Submodule R N) [hI : IsPrincipal (S.comap f)] : IsPrincipal S := by + rw [← Submodule.map_comap_eq_of_surjective hf S] + exact hI.map f + +theorem Submodule.IsPrincipal.map_ringHom (f : F) {I : Ideal R} + (hI : IsPrincipal I) : IsPrincipal (Ideal.map f I) := + ⟨⟨f (IsPrincipal.generator I), by rw [Ideal.submodule_span_eq, ← Set.image_singleton, ← Ideal.map_span, - Ideal.span_singleton_generator, Ideal.map_comap_of_surjective f hf]⟩⟩ + Ideal.span_singleton_generator]⟩⟩ + +theorem Ideal.IsPrincipal.of_comap (f : F) (hf : Function.Surjective f) (I : Ideal S) + [hI : IsPrincipal (I.comap f)] : IsPrincipal I := by + rw [← map_comap_of_surjective f hf I] + exact hI.map_ringHom f /-- The surjective image of a principal ideal ring is again a principal ideal ring. -/ -theorem IsPrincipalIdealRing.of_surjective [IsPrincipalIdealRing R] (f : R →+* S) +theorem IsPrincipalIdealRing.of_surjective [IsPrincipalIdealRing R] (f : F) (hf : Function.Surjective f) : IsPrincipalIdealRing S := ⟨fun I => Ideal.IsPrincipal.of_comap f hf I⟩ diff --git a/Mathlib/RingTheory/QuotSMulTop.lean b/Mathlib/RingTheory/QuotSMulTop.lean index 50ffb52e03183..2b2dfe48be108 100644 --- a/Mathlib/RingTheory/QuotSMulTop.lean +++ b/Mathlib/RingTheory/QuotSMulTop.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Brendan Murphy -/ import Mathlib.LinearAlgebra.TensorProduct.RightExactness +import Mathlib.LinearAlgebra.TensorProduct.Quotient /-! # Reducing a module modulo an element of the ring diff --git a/Mathlib/RingTheory/Radical.lean b/Mathlib/RingTheory/Radical.lean index c86cee4872a46..0e8777e07f247 100644 --- a/Mathlib/RingTheory/Radical.lean +++ b/Mathlib/RingTheory/Radical.lean @@ -46,6 +46,12 @@ variable {M : Type*} [CancelCommMonoidWithZero M] [NormalizationMonoid M] def primeFactors (a : M) : Finset M := (normalizedFactors a).toFinset +theorem _root_.Associated.primeFactors_eq {a b : M} (h : Associated a b) : + primeFactors a = primeFactors b := by + unfold primeFactors + rw [h.normalizedFactors_eq] + + /-- Radical of an element `a` in a unique factorization monoid is the product of the prime factors of `a`. @@ -62,10 +68,8 @@ theorem radical_one_eq : radical (1 : M) = 1 := by rw [radical, primeFactors, normalizedFactors_one, Multiset.toFinset_zero, Finset.prod_empty] theorem radical_eq_of_associated {a b : M} (h : Associated a b) : radical a = radical b := by - rcases iff_iff_and_or_not_and_not.mp h.eq_zero_iff with (⟨rfl, rfl⟩ | ⟨ha, hb⟩) - · rfl - · simp_rw [radical, primeFactors] - rw [(associated_iff_normalizedFactors_eq_normalizedFactors ha hb).mp h] + unfold radical + rw [h.primeFactors_eq] theorem radical_unit_eq_one {a : M} (h : IsUnit a) : radical a = 1 := (radical_eq_of_associated (associated_one_iff_isUnit.mpr h)).trans radical_one_eq @@ -104,4 +108,63 @@ theorem radical_pow_of_prime {a : M} (ha : Prime a) {n : ℕ} (hn : 0 < n) : rw [radical_pow a hn] exact radical_of_prime ha +theorem radical_ne_zero (a : M) [Nontrivial M] : radical a ≠ 0 := by + rw [radical, ← Finset.prod_val] + apply Multiset.prod_ne_zero + rw [primeFactors] + simp only [Multiset.toFinset_val, Multiset.mem_dedup] + exact zero_not_mem_normalizedFactors _ + end UniqueFactorizationMonoid + +open UniqueFactorizationMonoid + +namespace UniqueFactorizationDomain +-- Theorems for UFDs + +variable {R : Type*} [CommRing R] [IsDomain R] [NormalizationMonoid R] + [UniqueFactorizationMonoid R] + +/-- Coprime elements have disjoint prime factors (as multisets). -/ +theorem disjoint_normalizedFactors {a b : R} (hc : IsCoprime a b) : + (normalizedFactors a).Disjoint (normalizedFactors b) := by + intro x hxa hxb + have x_dvd_a := dvd_of_mem_normalizedFactors hxa + have x_dvd_b := dvd_of_mem_normalizedFactors hxb + have xp := prime_of_normalized_factor x hxa + exact xp.not_unit (hc.isUnit_of_dvd' x_dvd_a x_dvd_b) + +/-- Coprime elements have disjoint prime factors (as finsets). -/ +theorem disjoint_primeFactors {a b : R} (hc : IsCoprime a b) : + Disjoint (primeFactors a) (primeFactors b) := + Multiset.disjoint_toFinset.mpr (disjoint_normalizedFactors hc) + +theorem mul_primeFactors_disjUnion {a b : R} (ha : a ≠ 0) (hb : b ≠ 0) + (hc : IsCoprime a b) : + primeFactors (a * b) = + (primeFactors a).disjUnion (primeFactors b) (disjoint_primeFactors hc) := by + rw [Finset.disjUnion_eq_union] + simp_rw [primeFactors] + rw [normalizedFactors_mul ha hb, Multiset.toFinset_add] + +@[simp] +theorem radical_neg_one : radical (-1 : R) = 1 := + radical_unit_eq_one isUnit_one.neg + +/-- Radical is multiplicative for coprime elements. -/ +theorem radical_mul {a b : R} (hc : IsCoprime a b) : + radical (a * b) = (radical a) * (radical b) := by + by_cases ha : a = 0 + · subst ha; rw [isCoprime_zero_left] at hc + simp only [zero_mul, radical_zero_eq, one_mul, radical_unit_eq_one hc] + by_cases hb : b = 0 + · subst hb; rw [isCoprime_zero_right] at hc + simp only [mul_zero, radical_zero_eq, mul_one, radical_unit_eq_one hc] + simp_rw [radical] + rw [mul_primeFactors_disjUnion ha hb hc] + rw [Finset.prod_disjUnion (disjoint_primeFactors hc)] + +theorem radical_neg {a : R} : radical (-a) = radical a := + radical_eq_of_associated Associated.rfl.neg_left + +end UniqueFactorizationDomain diff --git a/Mathlib/RingTheory/ReesAlgebra.lean b/Mathlib/RingTheory/ReesAlgebra.lean index 8aaec4c3b41b3..6fe710e881b77 100644 --- a/Mathlib/RingTheory/ReesAlgebra.lean +++ b/Mathlib/RingTheory/ReesAlgebra.lean @@ -50,7 +50,7 @@ def reesAlgebra : Subalgebra R R[X] where add_mem' hf hg i := by rw [coeff_add] exact Ideal.add_mem _ (hf i) (hg i) - zero_mem' i := Ideal.zero_mem _ + zero_mem' _ := Ideal.zero_mem _ algebraMap_mem' r i := by rw [algebraMap_apply, coeff_C] split_ifs with h diff --git a/Mathlib/RingTheory/Regular/IsSMulRegular.lean b/Mathlib/RingTheory/Regular/IsSMulRegular.lean index efe4d52d7cef9..3619263bfda72 100644 --- a/Mathlib/RingTheory/Regular/IsSMulRegular.lean +++ b/Mathlib/RingTheory/Regular/IsSMulRegular.lean @@ -136,7 +136,7 @@ open Submodule Pointwise variable (M) [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup M'] [Module R M'] [AddCommGroup M''] [Module R M''] - (I : Ideal R) (N : Submodule R M) (r : R) + (N : Submodule R M) (r : R) variable (R) in lemma biUnion_associatedPrimes_eq_compl_regular [IsNoetherianRing R] : diff --git a/Mathlib/RingTheory/Regular/RegularSequence.lean b/Mathlib/RingTheory/Regular/RegularSequence.lean index a1e81fdf08b75..5477dd102ec5b 100644 --- a/Mathlib/RingTheory/Regular/RegularSequence.lean +++ b/Mathlib/RingTheory/Regular/RegularSequence.lean @@ -333,7 +333,7 @@ def recIterModByRegularWithRing {R : Type u} → [CommRing R] → {M : Type v} → [AddCommGroup M] → [Module R M] → {rs : List R} → (h : IsWeaklyRegular M rs) → motive R M rs h | R, _, M, _, _, [], _ => nil R M - | R, _, M, _, _, r :: rs, h => + | _, _, M, _, _, r :: rs, h => let ⟨h1, h2⟩ := (isWeaklyRegular_cons_iff' M r rs).mp h cons r rs h1 h2 (recIterModByRegularWithRing nil cons h2) termination_by _ _ _ _ _ rs => List.length rs diff --git a/Mathlib/RingTheory/RingHom/Locally.lean b/Mathlib/RingTheory/RingHom/Locally.lean index fc54b147cef5b..d4adb0bedebb7 100644 --- a/Mathlib/RingTheory/RingHom/Locally.lean +++ b/Mathlib/RingTheory/RingHom/Locally.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Christian Merten -/ import Mathlib.RingTheory.LocalProperties.Basic +import Mathlib.RingTheory.Localization.BaseChange import Mathlib.RingTheory.Localization.Away.Lemmas /-! @@ -25,6 +26,15 @@ composition, base change, etc., so is `Locally P`. ## Main results - `RingHom.locally_ofLocalizationSpanTarget`: `Locally P` is local on the target. +- `RingHom.locally_holdsForLocalizationAway`: `Locally P` holds for localization away maps + if `P` does. +- `RingHom.locally_stableUnderBaseChange`: `Locally P` is stable under base change if `P` is. +- `RingHom.locally_stableUnderComposition`: `Locally P` is stable under composition + if `P` is and `P` is preserved under localizations. +- `RingHom.locally_stableUnderCompositionWithLocalizationAway`: `Locally P` is stable under + composition with localization away maps if `P` is. +- `RingHom.locally_localizationPreserves`: If `P` is preserved by localizations, then so is + `Locally P`. -/ @@ -143,4 +153,196 @@ lemma locally_ofLocalizationSpanTarget (hP : RespectsIso P) : end OfLocalizationSpanTarget +section Stability + +/-- If `P` respects isomorphism, so does `Locally P`. -/ +lemma locally_respectsIso (hPi : RespectsIso P) : RespectsIso (Locally P) where + left {R S T} _ _ _ f e := fun ⟨s, hsone, hs⟩ ↦ by + refine ⟨e '' s, ?_, ?_⟩ + · rw [← Ideal.map_span, hsone, Ideal.map_top] + · rintro - ⟨a, ha, rfl⟩ + let e' : Localization.Away a ≃+* Localization.Away (e a) := + IsLocalization.ringEquivOfRingEquiv _ _ e (Submonoid.map_powers e a) + have : (algebraMap T (Localization.Away (e a))).comp e.toRingHom = + e'.toRingHom.comp (algebraMap S (Localization.Away a)) := by + ext x + simp [e'] + rw [← RingHom.comp_assoc, this, RingHom.comp_assoc] + apply hPi.left + exact hs a ha + right {R S T} _ _ _ f e := fun ⟨s, hsone, hs⟩ ↦ + ⟨s, hsone, fun a ha ↦ (RingHom.comp_assoc _ _ _).symm ▸ hPi.right _ _ (hs a ha)⟩ + +/-- If `P` holds for localization away maps, then so does `Locally P`. -/ +lemma locally_holdsForLocalizationAway (hPa : HoldsForLocalizationAway P) : + HoldsForLocalizationAway (Locally P) := by + introv R _ + use {1} + simp only [Set.mem_singleton_iff, forall_eq, Ideal.span_singleton_one, exists_const] + let e : S ≃ₐ[R] (Localization.Away (1 : S)) := + (IsLocalization.atUnits S (Submonoid.powers 1) (by simp)).restrictScalars R + haveI : IsLocalization.Away r (Localization.Away (1 : S)) := + IsLocalization.isLocalization_of_algEquiv (Submonoid.powers r) e + rw [← IsScalarTower.algebraMap_eq] + apply hPa _ r + +/-- If `P` preserves localizations, then `Locally P` is stable under composition if `P` is. -/ +lemma locally_stableUnderComposition (hPi : RespectsIso P) (hPl : LocalizationPreserves P) + (hPc : StableUnderComposition P) : + StableUnderComposition (Locally P) := by + classical + intro R S T _ _ _ f g hf hg + rw [locally_iff_finite] at hf hg + obtain ⟨sf, hsfone, hsf⟩ := hf + obtain ⟨sg, hsgone, hsg⟩ := hg + rw [locally_iff_exists hPi] + refine ⟨sf × sg, fun (a, b) ↦ g a * b, ?_, + fun (a, b) ↦ Localization.Away ((algebraMap T (Localization.Away b.val)) (g a.val)), + inferInstance, inferInstance, inferInstance, ?_⟩ + · rw [eq_top_iff, ← hsgone, Ideal.span_le] + intro t ht + have : 1 ∈ Ideal.span (Set.range <| fun a : sf ↦ a.val) := by simp [hsfone] + simp only [mem_ideal_span_range_iff_exists_fun, SetLike.mem_coe] at this ⊢ + obtain ⟨cf, hcf⟩ := this + let cg : sg → T := Pi.single ⟨t, ht⟩ 1 + use fun (a, b) ↦ g (cf a) * cg b + simp [cg, Pi.single_apply, Fintype.sum_prod_type, ← mul_assoc, ← Finset.sum_mul, ← map_mul, + ← map_sum, hcf] at hcf ⊢ + · intro ⟨a, b⟩ + let g' := (algebraMap T (Localization.Away b.val)).comp g + let a' := (algebraMap T (Localization.Away b.val)) (g a.val) + have : (algebraMap T <| Localization.Away a').comp (g.comp f) = + (Localization.awayMap g' a.val).comp ((algebraMap S (Localization.Away a.val)).comp f) := by + ext x + simp only [coe_comp, Function.comp_apply, a'] + change _ = Localization.awayMap g' a.val (algebraMap S _ (f x)) + simp only [Localization.awayMap, IsLocalization.Away.map, IsLocalization.map_eq] + rfl + simp only [this] + apply hPc _ _ (hsf a.val a.property) + apply @hPl _ _ _ _ g' _ _ _ _ _ _ _ _ ?_ (hsg b.val b.property) + exact IsLocalization.Away.instMapRingHomPowersOfCoe (Localization.Away (g' a.val)) a.val + +/-- If `P` is stable under composition with localization away maps, then so is `Locally P`. -/ +lemma locally_stableUnderCompositionWithLocalizationAway + (hPa : StableUnderCompositionWithLocalizationAway P) : + StableUnderCompositionWithLocalizationAway (Locally P) where + left R S T _ _ _ _ t _ f hf := by + simp only [locally_iff_isLocalization (hPa.respectsIso) f] at hf + obtain ⟨s, hsone, hs⟩ := hf + refine ⟨algebraMap S T '' s, ?_, ?_⟩ + · rw [← Ideal.map_span, hsone, Ideal.map_top] + · rintro - ⟨a, ha, rfl⟩ + letI : Algebra (Localization.Away a) (Localization.Away (algebraMap S T a)) := + (IsLocalization.Away.map _ _ (algebraMap S T) a).toAlgebra + have : (algebraMap (Localization.Away a) (Localization.Away (algebraMap S T a))).comp + (algebraMap S (Localization.Away a)) = + (algebraMap T (Localization.Away (algebraMap S T a))).comp (algebraMap S T) := by + simp [algebraMap_toAlgebra, IsLocalization.Away.map] + rw [← comp_assoc, ← this, comp_assoc] + haveI : IsScalarTower S (Localization.Away a) (Localization.Away ((algebraMap S T) a)) := by + apply IsScalarTower.of_algebraMap_eq + intro x + simp [algebraMap_toAlgebra, IsLocalization.Away.map, ← IsScalarTower.algebraMap_apply] + haveI : IsLocalization.Away (algebraMap S (Localization.Away a) t) + (Localization.Away (algebraMap S T a)) := + IsLocalization.Away.commutes _ T ((Localization.Away (algebraMap S T a))) a t + apply hPa.left _ (algebraMap S (Localization.Away a) t) + apply hs a ha + right R S T _ _ _ _ r _ f := fun ⟨s, hsone, hs⟩ ↦ by + refine ⟨s, hsone, fun t ht ↦ ?_⟩ + rw [← comp_assoc] + exact hPa.right _ r _ (hs t ht) + +attribute [local instance] Algebra.TensorProduct.rightAlgebra in +/-- If `P` is stable under base change, then so is `Locally P`. -/ +lemma locally_stableUnderBaseChange (hPi : RespectsIso P) (hPb : StableUnderBaseChange P) : + StableUnderBaseChange (Locally P) := by + apply StableUnderBaseChange.mk _ (locally_respectsIso hPi) + introv hf + obtain ⟨s, hsone, hs⟩ := hf + rw [locally_iff_exists hPi] + letI (a : s) : Algebra (S ⊗[R] T) (S ⊗[R] Localization.Away a.val) := + (Algebra.TensorProduct.map (AlgHom.id R S) (IsScalarTower.toAlgHom R _ _)).toRingHom.toAlgebra + letI (a : s) : Algebra T (S ⊗[R] Localization.Away a.val) := + ((algebraMap _ (S ⊗[R] Localization.Away a.val)).comp (algebraMap T (S ⊗[R] T))).toAlgebra + haveI (a : s) : IsScalarTower T (S ⊗[R] T) (S ⊗[R] Localization.Away a.val) := + IsScalarTower.of_algebraMap_eq' rfl + haveI (a : s) : IsScalarTower T (Localization.Away a.val) (S ⊗[R] Localization.Away a.val) := + IsScalarTower.of_algebraMap_eq' rfl + haveI (a : s) : IsScalarTower S (S ⊗[R] T) (S ⊗[R] Localization.Away a.val) := + IsScalarTower.of_algebraMap_eq <| by + intro x + simp [RingHom.algebraMap_toAlgebra] + haveI (a : s) : Algebra.IsPushout T (Localization.Away a.val) (S ⊗[R] T) + (S ⊗[R] Localization.Away a.val) := by + rw [← Algebra.IsPushout.comp_iff (R := R) (R' := S)] + infer_instance + refine ⟨s, fun a ↦ Algebra.TensorProduct.includeRight a.val, ?_, + fun a ↦ (S ⊗[R] Localization.Away a.val), inferInstance, inferInstance, ?_, ?_⟩ + · rw [← Set.image_eq_range, ← Ideal.map_span, hsone, Ideal.map_top] + · intro a + convert_to IsLocalization (Algebra.algebraMapSubmonoid (S ⊗[R] T) (Submonoid.powers a.val)) + (S ⊗[R] Localization.Away a.val) + · simp only [Algebra.TensorProduct.includeRight_apply, Algebra.algebraMapSubmonoid, + Submonoid.map_powers] + rfl + · rw [← isLocalizedModule_iff_isLocalization, isLocalizedModule_iff_isBaseChange + (S := Submonoid.powers a.val) (A := Localization.Away a.val)] + exact Algebra.IsPushout.out + · intro a + have : (algebraMap (S ⊗[R] T) (S ⊗[R] Localization.Away a.val)).comp + Algebra.TensorProduct.includeLeftRingHom = + Algebra.TensorProduct.includeLeftRingHom := by + ext x + simp [RingHom.algebraMap_toAlgebra] + rw [this] + apply hPb R (Localization.Away a.val) + rw [IsScalarTower.algebraMap_eq R T (Localization.Away a.val)] + apply hs a a.property + +/-- If `P` is preserved by localizations, then so is `Locally P`. -/ +lemma locally_localizationPreserves (hPi : RespectsIso P) (hPl : LocalizationPreserves P) : + LocalizationPreserves (Locally P) := by + introv R hf + obtain ⟨s, hsone, hs⟩ := hf + rw [locally_iff_exists hPi] + let Mₐ (a : s) : Submonoid (Localization.Away a.val) := + (M.map f).map (algebraMap S (Localization.Away a.val)) + let Sₐ (a : s) := Localization (Mₐ a) + have hM (a : s) : M.map ((algebraMap S (Localization.Away a.val)).comp f) = Mₐ a := + (M.map_map _ _).symm + haveI (a : s) : + IsLocalization (M.map ((algebraMap S (Localization.Away a.val)).comp f)) (Sₐ a) := by + rw [hM] + infer_instance + haveI (a : s) : + IsLocalization (Algebra.algebraMapSubmonoid (Localization.Away a.val) (M.map f)) (Sₐ a) := + inferInstanceAs <| IsLocalization (Mₐ a) (Sₐ a) + letI (a : s) : Algebra S' (Sₐ a) := + (IsLocalization.map (Sₐ a) (algebraMap S (Localization.Away a.val)) + (M.map f).le_comap_map).toAlgebra + haveI (a : s) : IsScalarTower S S' (Sₐ a) := + IsScalarTower.of_algebraMap_eq' (IsLocalization.map_comp (M.map f).le_comap_map).symm + refine ⟨s, fun a ↦ algebraMap S S' a.val, ?_, Sₐ, + inferInstance, inferInstance, fun a ↦ ?_, fun a ↦ ?_⟩ + · rw [← Set.image_eq_range, ← Ideal.map_span, hsone, Ideal.map_top] + · convert IsLocalization.commutes (T := Sₐ a) (M₁ := M.map f) (S₁ := S') + (S₂ := Localization.Away a.val) (M₂ := Submonoid.powers a.val) + simp [Algebra.algebraMapSubmonoid] + · rw [algebraMap_toAlgebra, IsLocalization.map_comp_map] + apply hPl + exact hs a.val a.property + +/-- If `P` is preserved by localizations and stable under composition with localization +away maps, then `Locally P` is a local property of ring homomorphisms. -/ +lemma locally_propertyIsLocal (hPl : LocalizationPreserves P) + (hPa : StableUnderCompositionWithLocalizationAway P) : PropertyIsLocal (Locally P) where + LocalizationPreserves := locally_localizationPreserves hPa.respectsIso hPl + StableUnderCompositionWithLocalizationAway := + locally_stableUnderCompositionWithLocalizationAway hPa + OfLocalizationSpanTarget := locally_ofLocalizationSpanTarget hPa.respectsIso + +end Stability + end RingHom diff --git a/Mathlib/RingTheory/RingHom/StandardSmooth.lean b/Mathlib/RingTheory/RingHom/StandardSmooth.lean new file mode 100644 index 0000000000000..4bc826b41f2c7 --- /dev/null +++ b/Mathlib/RingTheory/RingHom/StandardSmooth.lean @@ -0,0 +1,174 @@ +/- +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.LocalProperties.Basic +import Mathlib.RingTheory.Smooth.StandardSmooth +import Mathlib.Tactic.Algebraize + +/-! +# Standard smooth ring homomorphisms + +In this file we define standard smooth ring homomorphisms and show their +meta properties. + +## Notes + +This contribution was created as part of the AIM workshop "Formalizing algebraic geometry" +in June 2024. + +-/ + +universe t t' w w' u v + +variable (n m : ℕ) + +open TensorProduct + +namespace RingHom + +variable {R : Type u} {S : Type v} [CommRing R] [CommRing S] + +/-- A ring homomorphism `R →+* S` is standard smooth if `S` is standard smooth as `R`-algebra. -/ +@[algebraize RingHom.IsStandardSmooth.toAlgebra] +def IsStandardSmooth (f : R →+* S) : Prop := + @Algebra.IsStandardSmooth.{t, w} _ _ _ _ f.toAlgebra + +/-- Helper lemma for the `algebraize` tactic.-/ +lemma IsStandardSmooth.toAlgebra {f : R →+* S} (hf : IsStandardSmooth.{t, w} f) : + @Algebra.IsStandardSmooth.{t, w} R S _ _ f.toAlgebra := hf + +/-- A ring homomorphism `R →+* S` is standard smooth of relative dimension `n` if +`S` is standard smooth of relative dimension `n` as `R`-algebra. -/ +@[algebraize RingHom.IsStandardSmoothOfRelativeDimension.toAlgebra] +def IsStandardSmoothOfRelativeDimension (f : R →+* S) : Prop := + @Algebra.IsStandardSmoothOfRelativeDimension.{t, w} n _ _ _ _ f.toAlgebra + +/-- Helper lemma for the `algebraize` tactic.-/ +lemma IsStandardSmoothOfRelativeDimension.toAlgebra {f : R →+* S} + (hf : IsStandardSmoothOfRelativeDimension.{t, w} n f) : + @Algebra.IsStandardSmoothOfRelativeDimension.{t, w} n R S _ _ f.toAlgebra := hf + +lemma IsStandardSmoothOfRelativeDimension.isStandardSmooth (f : R →+* S) + (hf : IsStandardSmoothOfRelativeDimension.{t, w} n f) : + IsStandardSmooth.{t, w} f := by + algebraize [f] + exact Algebra.IsStandardSmoothOfRelativeDimension.isStandardSmooth n + +variable {n m} + +variable (R) in +lemma IsStandardSmoothOfRelativeDimension.id : + IsStandardSmoothOfRelativeDimension.{t, w} 0 (RingHom.id R) := + Algebra.IsStandardSmoothOfRelativeDimension.id R + +lemma IsStandardSmoothOfRelativeDimension.equiv (e : R ≃+* S) : + IsStandardSmoothOfRelativeDimension.{t, w} 0 (e : R →+* S) := by + algebraize [e.toRingHom] + exact Algebra.IsStandardSmoothOfRelativeDimension.of_algebraMap_bijective e.bijective + +variable {T : Type*} [CommRing T] + +lemma IsStandardSmooth.comp {g : S →+* T} {f : R →+* S} + (hg : IsStandardSmooth.{t', w'} g) (hf : IsStandardSmooth.{t, w} f) : + IsStandardSmooth.{max t t', max w w'} (g.comp f) := by + rw [IsStandardSmooth] + algebraize [f, g, (g.comp f)] + exact Algebra.IsStandardSmooth.trans.{t, t', w, w'} R S T + +lemma IsStandardSmoothOfRelativeDimension.comp {g : S →+* T} {f : R →+* S} + (hg : IsStandardSmoothOfRelativeDimension.{t', w'} n g) + (hf : IsStandardSmoothOfRelativeDimension.{t, w} m f) : + IsStandardSmoothOfRelativeDimension.{max t t', max w w'} (n + m) (g.comp f) := by + rw [IsStandardSmoothOfRelativeDimension] + algebraize [f, g, (g.comp f)] + exact Algebra.IsStandardSmoothOfRelativeDimension.trans m n R S T + +lemma isStandardSmooth_stableUnderComposition : + StableUnderComposition @IsStandardSmooth.{t, w} := + fun _ _ _ _ _ _ _ _ hf hg ↦ hg.comp hf + +lemma isStandardSmooth_respectsIso : RespectsIso @IsStandardSmooth.{t, w} := by + apply isStandardSmooth_stableUnderComposition.respectsIso + introv + exact (IsStandardSmoothOfRelativeDimension.equiv e).isStandardSmooth + +lemma isStandardSmoothOfRelativeDimension_respectsIso : + RespectsIso (@IsStandardSmoothOfRelativeDimension.{t, w} n) where + left {R S T _ _ _} f e hf := by + rw [← zero_add n] + exact (IsStandardSmoothOfRelativeDimension.equiv e).comp hf + right {R S T _ _ _} f e hf := by + rw [← add_zero n] + exact hf.comp (IsStandardSmoothOfRelativeDimension.equiv e) + +lemma isStandardSmooth_stableUnderBaseChange : StableUnderBaseChange @IsStandardSmooth.{t, w} := by + apply StableUnderBaseChange.mk + · exact isStandardSmooth_respectsIso + · introv h + replace h : Algebra.IsStandardSmooth R T := by + rw [RingHom.IsStandardSmooth] at h; convert h; ext; simp_rw [Algebra.smul_def]; rfl + suffices Algebra.IsStandardSmooth S (S ⊗[R] T) by + rw [RingHom.IsStandardSmooth]; convert this; ext; simp_rw [Algebra.smul_def]; rfl + infer_instance + +variable (n) + +lemma isStandardSmoothOfRelativeDimension_stableUnderBaseChange : + StableUnderBaseChange (@IsStandardSmoothOfRelativeDimension.{t, w} n) := by + apply StableUnderBaseChange.mk + · exact isStandardSmoothOfRelativeDimension_respectsIso + · introv h + replace h : Algebra.IsStandardSmoothOfRelativeDimension n R T := by + rw [RingHom.IsStandardSmoothOfRelativeDimension] at h + convert h; ext; simp_rw [Algebra.smul_def]; rfl + suffices Algebra.IsStandardSmoothOfRelativeDimension n S (S ⊗[R] T) by + rw [RingHom.IsStandardSmoothOfRelativeDimension] + convert this; ext; simp_rw [Algebra.smul_def]; rfl + infer_instance + +lemma IsStandardSmoothOfRelativeDimension.algebraMap_isLocalizationAway {Rᵣ : Type*} [CommRing Rᵣ] + [Algebra R Rᵣ] (r : R) [IsLocalization.Away r Rᵣ] : + IsStandardSmoothOfRelativeDimension.{0, 0} 0 (algebraMap R Rᵣ) := by + have : (algebraMap R Rᵣ).toAlgebra = ‹Algebra R Rᵣ› := by + ext + rw [Algebra.smul_def] + rfl + rw [IsStandardSmoothOfRelativeDimension, this] + exact Algebra.IsStandardSmoothOfRelativeDimension.localization_away r + +lemma isStandardSmooth_localizationPreserves : LocalizationPreserves IsStandardSmooth.{t, w} := + isStandardSmooth_stableUnderBaseChange.localizationPreserves + +lemma isStandardSmoothOfRelativeDimension_localizationPreserves : + LocalizationPreserves (IsStandardSmoothOfRelativeDimension.{t, w} n) := + (isStandardSmoothOfRelativeDimension_stableUnderBaseChange n).localizationPreserves + +lemma isStandardSmooth_holdsForLocalizationAway : + HoldsForLocalizationAway IsStandardSmooth.{0, 0} := by + introv R h + exact (IsStandardSmoothOfRelativeDimension.algebraMap_isLocalizationAway r).isStandardSmooth + +lemma isStandardSmoothOfRelativeDimension_holdsForLocalizationAway : + HoldsForLocalizationAway (IsStandardSmoothOfRelativeDimension.{0, 0} 0) := by + introv R h + exact IsStandardSmoothOfRelativeDimension.algebraMap_isLocalizationAway r + +lemma isStandardSmooth_stableUnderCompositionWithLocalizationAway : + StableUnderCompositionWithLocalizationAway IsStandardSmooth.{0, 0} := + isStandardSmooth_stableUnderComposition.stableUnderCompositionWithLocalizationAway + isStandardSmooth_holdsForLocalizationAway + +lemma isStandardSmoothOfRelativeDimension_stableUnderCompositionWithLocalizationAway : + StableUnderCompositionWithLocalizationAway (IsStandardSmoothOfRelativeDimension.{0, 0} n) where + left _ S T _ _ _ _ s _ _ hf := + have : (algebraMap S T).IsStandardSmoothOfRelativeDimension 0 := + IsStandardSmoothOfRelativeDimension.algebraMap_isLocalizationAway s + zero_add n ▸ IsStandardSmoothOfRelativeDimension.comp this hf + right R S _ _ _ _ _ r _ _ hf := + have : (algebraMap R S).IsStandardSmoothOfRelativeDimension 0 := + IsStandardSmoothOfRelativeDimension.algebraMap_isLocalizationAway r + add_zero n ▸ IsStandardSmoothOfRelativeDimension.comp hf this + +end RingHom diff --git a/Mathlib/RingTheory/RingInvo.lean b/Mathlib/RingTheory/RingInvo.lean index 0ebf763f2a467..70f40d0a35201 100644 --- a/Mathlib/RingTheory/RingInvo.lean +++ b/Mathlib/RingTheory/RingInvo.lean @@ -83,10 +83,6 @@ def mk' (f : R →+* Rᵐᵒᵖ) (involution : ∀ r, (f (f r).unop).unop = r) : right_inv := fun _ => MulOpposite.unop_injective <| involution _ involution' := involution } --- Porting note: removed CoeFun instance, undesired in lean4 --- instance : CoeFun (RingInvo R) fun _ => R → Rᵐᵒᵖ := --- ⟨fun f => f.toRingEquiv.toFun⟩ - @[simp] theorem involution (f : RingInvo R) (x : R) : (f (f x).unop).unop = x := f.involution' x @@ -99,8 +95,6 @@ theorem involution (f : RingInvo R) (x : R) : (f (f x).unop).unop = x := theorem coe_ringEquiv (f : RingInvo R) (a : R) : (f : R ≃+* Rᵐᵒᵖ) a = f a := rfl --- porting note (#10618): simp can prove this --- @[simp] theorem map_eq_zero_iff (f : RingInvo R) {x : R} : f x = 0 ↔ x = 0 := f.toRingEquiv.map_eq_zero_iff diff --git a/Mathlib/RingTheory/RootsOfUnity/Basic.lean b/Mathlib/RingTheory/RootsOfUnity/Basic.lean index fbfd625bc62c1..b90cc6d9efb53 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Basic.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Basic.lean @@ -583,10 +583,10 @@ theorem primitiveRoots_one : primitiveRoots 1 R = {(1 : R)} := by theorem neZero' {n : ℕ+} (hζ : IsPrimitiveRoot ζ n) : NeZero ((n : ℕ) : R) := by let p := ringChar R - have hfin := multiplicity.finite_nat_iff.2 ⟨CharP.char_ne_one R p, n.pos⟩ - obtain ⟨m, hm⟩ := multiplicity.exists_eq_pow_mul_and_not_dvd hfin + have hfin := Nat.multiplicity_finite_iff.2 ⟨CharP.char_ne_one R p, n.pos⟩ + 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 hfin hp).ne' + · obtain ⟨k, hk⟩ := Nat.exists_eq_succ_of_ne_zero (multiplicity_pos_of_dvd hp).ne' haveI : NeZero p := NeZero.of_pos (Nat.pos_of_dvd_of_pos hp n.pos) haveI hpri : Fact p.Prime := CharP.char_is_prime_of_pos R p have := hζ.pow_eq_one @@ -856,14 +856,14 @@ theorem nthRoots_one_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : @[simp] theorem card_nthRootsFinset {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : - (nthRootsFinset n R).card = n := by + #(nthRootsFinset n R) = n := by rw [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_one_nodup h), card_mk, h.card_nthRoots_one] open scoped Nat /-- If an integral domain has a primitive `k`-th root of unity, then it has `φ k` of them. -/ theorem card_primitiveRoots {ζ : R} {k : ℕ} (h : IsPrimitiveRoot ζ k) : - (primitiveRoots k R).card = φ k := by + #(primitiveRoots k R) = φ k := by by_cases h0 : k = 0 · simp [h0] symm diff --git a/Mathlib/RingTheory/RootsOfUnity/Lemmas.lean b/Mathlib/RingTheory/RootsOfUnity/Lemmas.lean index e6fded4815f54..75a39566c1fe5 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Lemmas.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Lemmas.lean @@ -23,7 +23,7 @@ variable {R : Type*} [CommRing R] [IsDomain R] namespace IsPrimitiveRoot -open Finset Polynomial BigOperators +open Finset Polynomial /-- If `μ` is a primitive `n`th root of unity in `R`, then `∏(1≤k enter [2, 2, 2]; rw [← card_range k] - rw [← prod_range_mul_prod_Ico _ (Nat.le_add_left k m), mul_comm _ (_ ^ card _), ← mul_assoc, + rw [← prod_range_mul_prod_Ico _ (Nat.le_add_left k m), mul_comm _ (_ ^ #_), ← mul_assoc, prod_mul_pow_card] conv => enter [2, 1, 2, j]; rw [← (Zdef _).2] diff --git a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean index fddcf3946281c..fb0735bdeb50b 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean @@ -143,13 +143,13 @@ theorem minpoly_eq_pow {p : ℕ} [hprime : Fact p.Prime] (hdiv : ¬p ∣ n) : have habs : map (Int.castRingHom (ZMod p)) P ^ 2 ∣ map (Int.castRingHom (ZMod p)) P ^ 2 * R := by use R replace habs := - lt_of_lt_of_le (PartENat.coe_lt_coe.2 one_lt_two) - (multiplicity.le_multiplicity_of_pow_dvd (dvd_trans habs prod)) + lt_of_lt_of_le (Nat.cast_lt.2 one_lt_two) + (le_emultiplicity_of_pow_dvd (dvd_trans habs prod)) have hfree : Squarefree (X ^ n - 1 : (ZMod p)[X]) := (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_multiplicity_le_one (X ^ n - 1)).1 hfree + (multiplicity.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 diff --git a/Mathlib/RingTheory/SimpleModule.lean b/Mathlib/RingTheory/SimpleModule.lean index 86e5d7e807588..1eddfcca1ca75 100644 --- a/Mathlib/RingTheory/SimpleModule.lean +++ b/Mathlib/RingTheory/SimpleModule.lean @@ -5,6 +5,7 @@ Authors: Aaron Anderson -/ import Mathlib.LinearAlgebra.Isomorphisms import Mathlib.LinearAlgebra.Projection +import Mathlib.Order.Atoms.Finite import Mathlib.Order.JordanHolder import Mathlib.Order.CompactlyGenerated.Intervals import Mathlib.LinearAlgebra.FiniteDimensional @@ -123,6 +124,8 @@ theorem ker_toSpanSingleton_isMaximal {m : M} (hm : m ≠ 0) : rw [Ideal.isMaximal_def, ← isSimpleModule_iff_isCoatom] exact congr (quotKerEquivOfSurjective _ <| toSpanSingleton_surjective R hm) +instance : IsNoetherian R M := isNoetherian_iff'.mpr inferInstance + end IsSimpleModule open IsSimpleModule in @@ -194,6 +197,13 @@ theorem exists_simple_submodule [Nontrivial M] : ∃ m : Submodule R M, IsSimple theorem sSup_simples_eq_top : sSup { m : Submodule R M | IsSimpleModule R m } = ⊤ := by simpa only [isSimpleModule_iff_isAtom] using sSup_atoms_eq_top +theorem exists_setIndependent_sSup_simples_eq_top : + ∃ s : Set (Submodule R M), CompleteLattice.SetIndependent s ∧ + sSup s = ⊤ ∧ ∀ m ∈ s, IsSimpleModule R m := by + have := sSup_simples_eq_top R M + simp_rw [isSimpleModule_iff_isAtom] at this ⊢ + exact exists_setIndependent_of_sSup_atoms_eq_top this + /-- The annihilator of a semisimple module over a commutative ring is a radical ideal. -/ theorem annihilator_isRadical (R) [CommRing R] [Module R M] [IsSemisimpleModule R M] : (Module.annihilator R M).IsRadical := by @@ -213,6 +223,10 @@ instance quotient : IsSemisimpleModule R (M ⧸ m) := have ⟨P, compl⟩ := exists_isCompl m .congr (m.quotientEquivOfIsCompl P compl) +instance (priority := low) [Module.Finite R M] : IsNoetherian R M where + noetherian m := have ⟨P, compl⟩ := exists_isCompl m + Module.Finite.iff_fg.mp (Module.Finite.equiv <| P.quotientEquivOfIsCompl m compl.symm) + -- does not work as an instance, not sure why protected theorem range (f : M →ₗ[R] N) : IsSemisimpleModule R (range f) := .congr (quotKerEquivRange _).symm @@ -338,7 +352,7 @@ variable (ι R) proof_wanted IsSemisimpleRing.mulOpposite [IsSemisimpleRing R] : IsSemisimpleRing Rᵐᵒᵖ -proof_wanted IsSemisimpleRing.module_end [IsSemisimpleRing R] [Module.Finite R M] : +proof_wanted IsSemisimpleRing.module_end [IsSemisimpleModule R M] [Module.Finite R M] : IsSemisimpleRing (Module.End R M) proof_wanted IsSemisimpleRing.matrix [Fintype ι] [DecidableEq ι] [IsSemisimpleRing R] : @@ -398,9 +412,9 @@ noncomputable instance _root_.Module.End.divisionRing exact (LinearEquiv.ofBijective _ <| bijective_of_ne_zero a0).right_inv _ inv_zero := dif_pos rfl nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun q a => rfl + qsmul_def := fun _ _ => rfl end LinearMap diff --git a/Mathlib/RingTheory/Smooth/Basic.lean b/Mathlib/RingTheory/Smooth/Basic.lean index d61b49519ff71..2f26235f7f9cd 100644 --- a/Mathlib/RingTheory/Smooth/Basic.lean +++ b/Mathlib/RingTheory/Smooth/Basic.lean @@ -3,13 +3,13 @@ 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.Ideal.Cotangent -import Mathlib.RingTheory.QuotientNilpotent -import Mathlib.RingTheory.TensorProduct.Basic import Mathlib.RingTheory.FinitePresentation import Mathlib.RingTheory.FiniteStability -import Mathlib.RingTheory.Localization.Away.Basic +import Mathlib.RingTheory.Ideal.Cotangent +import Mathlib.RingTheory.Ideal.Quotient.Nilpotent import Mathlib.RingTheory.Localization.Away.AdjoinRoot +import Mathlib.RingTheory.Localization.Away.Basic +import Mathlib.RingTheory.TensorProduct.Basic /-! @@ -60,7 +60,7 @@ section variable {R : Type u} [CommSemiring R] variable {A : Type u} [Semiring A] [Algebra R A] -variable {B : Type u} [CommRing B] [Algebra R B] (I : Ideal B) +variable {B : Type u} [CommRing B] [Algebra R B] theorem exists_lift {B : Type u} [CommRing B] [_RB : Algebra R B] [FormallySmooth R A] (I : Ideal B) (hI : IsNilpotent I) (g : A →ₐ[R] B ⧸ I) : @@ -142,6 +142,9 @@ theorem of_equiv [FormallySmooth R A] (e : A ≃ₐ[R] B) : FormallySmooth R B : rw [← AlgHom.comp_assoc, FormallySmooth.comp_lift, AlgHom.comp_assoc, AlgEquiv.comp_symm, AlgHom.comp_id] +theorem iff_of_equiv (e : A ≃ₐ[R] B) : FormallySmooth R A ↔ FormallySmooth R B := + ⟨fun _ ↦ of_equiv e, fun _ ↦ of_equiv e.symm⟩ + end OfEquiv section Polynomial @@ -187,9 +190,9 @@ end Comp section OfSurjective -variable {R S : Type u} [CommRing R] [CommSemiring S] +variable {R : Type u} [CommRing R] variable {P A : Type u} [CommRing A] [Algebra R A] [CommRing P] [Algebra R P] -variable (I : Ideal P) (f : P →ₐ[R] A) +variable (f : P →ₐ[R] A) theorem of_split [FormallySmooth R P] (g : A →ₐ[R] P ⧸ (RingHom.ker f.toRingHom) ^ 2) (hg : f.kerSquareLift.comp g = AlgHom.id R A) : FormallySmooth R A := by diff --git a/Mathlib/RingTheory/Smooth/Pi.lean b/Mathlib/RingTheory/Smooth/Pi.lean new file mode 100644 index 0000000000000..cfb4cf1dd16df --- /dev/null +++ b/Mathlib/RingTheory/Smooth/Pi.lean @@ -0,0 +1,121 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.Idempotents +import Mathlib.RingTheory.Smooth.Basic + +/-! + +# Formal-smoothness of finite products of rings + +## Main result + +- `Algebra.FormallySmooth.pi_iff`: If `I` is finite, `Π i : I, A i` is `R`-formally-smooth + if and only if each `A i` is `R`-formally-smooth. + +-/ + +universe u v + +namespace Algebra.FormallySmooth + +variable {R : Type (max u v)} {I : Type u} (A : I → Type (max u v)) +variable [CommRing R] [∀ i, CommRing (A i)] [∀ i, Algebra R (A i)] + +theorem of_pi [FormallySmooth R (Π i, A i)] (i) : + FormallySmooth R (A i) := by + classical + fapply FormallySmooth.of_split (Pi.evalAlgHom R A i) + · apply AlgHom.ofLinearMap + ((Ideal.Quotient.mkₐ R _).toLinearMap.comp (LinearMap.single _ _ i)) + · show Ideal.Quotient.mk _ (Pi.single i 1) = 1 + rw [← (Ideal.Quotient.mk _).map_one, ← sub_eq_zero, ← map_sub, + Ideal.Quotient.eq_zero_iff_mem] + have : Pi.single i 1 - 1 ∈ RingHom.ker (Pi.evalAlgHom R A i).toRingHom := by + simp [RingHom.mem_ker] + convert neg_mem (Ideal.pow_mem_pow this 2) using 1 + simp [pow_two, sub_mul, mul_sub, ← Pi.single_mul] + · intro x y + show Ideal.Quotient.mk _ _ = Ideal.Quotient.mk _ _ * Ideal.Quotient.mk _ _ + simp only [AlgHom.toRingHom_eq_coe, LinearMap.coe_single, Pi.single_mul, map_mul] + · ext x + show (Pi.single i x) i = x + simp + +theorem pi_iff [Finite I] : + FormallySmooth R (Π i, A i) ↔ ∀ i, FormallySmooth R (A i) := by + classical + cases nonempty_fintype I + constructor + · exact fun _ ↦ of_pi A + · intro H + constructor + intros B _ _ J hJ g + have hJ' (x) (hx : x ∈ RingHom.ker (Ideal.Quotient.mk J)) : IsNilpotent x := by + refine ⟨2, show x ^ 2 ∈ (⊥ : Ideal B) from ?_⟩ + rw [← hJ] + exact Ideal.pow_mem_pow (by simpa using hx) 2 + obtain ⟨e, he, he'⟩ := ((CompleteOrthogonalIdempotents.single A).map + g.toRingHom).lift_of_isNilpotent_ker (Ideal.Quotient.mk J) hJ' + fun _ ↦ Ideal.Quotient.mk_surjective _ + replace he' : ∀ i, Ideal.Quotient.mk J (e i) = g (Pi.single i 1) := congr_fun he' + let iso : B ≃ₐ[R] ∀ i, B ⧸ Ideal.span {1 - e i} := + { __ := Pi.algHom _ _ fun i ↦ Ideal.Quotient.mkₐ R _ + __ := Equiv.ofBijective _ he.bijective_pi } + let J' := fun i ↦ J.map (Ideal.Quotient.mk (Ideal.span {1 - e i})) + let ι : ∀ i, (B ⧸ J →ₐ[R] (B ⧸ _) ⧸ J' i) := fun i ↦ Ideal.quotientMapₐ _ + (IsScalarTower.toAlgHom R B _) Ideal.le_comap_map + have hι : ∀ i x, ι i x = 0 → (e i) * x = 0 := by + intros i x hix + have : x ∈ (Ideal.span {1 - e i}).map (Ideal.Quotient.mk J) := by + rw [← Ideal.ker_quotientMap_mk]; exact hix + rw [Ideal.map_span, Set.image_singleton, Ideal.mem_span_singleton] at this + obtain ⟨c, rfl⟩ := this + rw [← mul_assoc, ← map_mul, mul_sub, mul_one, (he.idem i).eq, sub_self, map_zero, zero_mul] + have : ∀ i : I, ∃ a : A i →ₐ[R] B ⧸ Ideal.span {1 - e i}, ∀ x, + Ideal.Quotient.mk (J' i) (a x) = ι i (g (Pi.single i x)) := by + intro i + let g' : A i →ₐ[R] (B ⧸ _) ⧸ (J' i) := by + apply AlgHom.ofLinearMap (((ι i).comp g).toLinearMap ∘ₗ LinearMap.single _ _ i) + · suffices Ideal.Quotient.mk (Ideal.span {1 - e i}) (e i) = 1 by simp [ι, ← he', this] + rw [← (Ideal.Quotient.mk _).map_one, eq_comm, Ideal.Quotient.mk_eq_mk_iff_sub_mem, + Ideal.mem_span_singleton] + · intros x y; simp [Pi.single_mul] + obtain ⟨a, ha⟩ := FormallySmooth.comp_surjective (I := J' i) + (by rw [← Ideal.map_pow, hJ, Ideal.map_bot]) g' + exact ⟨a, AlgHom.congr_fun ha⟩ + choose a ha using this + use iso.symm.toAlgHom.comp (Pi.algHom _ _ fun i ↦ (a i).comp (Pi.evalAlgHom R A i)) + ext x; rw [← AlgHom.toLinearMap_apply, ← AlgHom.toLinearMap_apply]; congr 1 + ext i x + simp only [AlgEquiv.toAlgHom_eq_coe, AlgHom.comp_toLinearMap, AlgEquiv.toAlgHom_toLinearMap, + LinearMap.coe_comp, LinearMap.coe_single, Function.comp_apply, AlgHom.toLinearMap_apply, + AlgEquiv.toLinearMap_apply, Ideal.Quotient.mkₐ_eq_mk] + obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (a i x) + have hy' : Ideal.Quotient.mk (Ideal.span {1 - e i}) (y * e i) = a i x := by + have : Ideal.Quotient.mk (Ideal.span {1 - e i}) (e i) = 1 := by + rw [← (Ideal.Quotient.mk _).map_one, eq_comm, Ideal.Quotient.mk_eq_mk_iff_sub_mem, + Ideal.mem_span_singleton] + rw [map_mul, this, hy, mul_one] + trans Ideal.Quotient.mk J (y * e i) + · congr 1; apply iso.injective; ext j + suffices a j (Pi.single i x j) = Ideal.Quotient.mk _ (y * e i) by simpa using this + by_cases hij : i = j + · subst hij + rw [Pi.single_eq_same, hy'] + · have : Ideal.Quotient.mk (Ideal.span {1 - e j}) (e i) = 0 := by + rw [Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton] + refine ⟨e i, by simp [he.ortho (Ne.symm hij), sub_mul]⟩ + rw [Pi.single_eq_of_ne (Ne.symm hij), map_zero, map_mul, this, mul_zero] + · have : ι i (Ideal.Quotient.mk J (y * e i)) = ι i (g (Pi.single i x)) := by + rw [← ha, ← hy'] + simp only [Ideal.quotient_map_mkₐ, IsScalarTower.coe_toAlgHom', + Ideal.Quotient.algebraMap_eq, Ideal.Quotient.mkₐ_eq_mk, ι] + rw [← sub_eq_zero, ← map_sub] at this + replace this := hι _ _ this + rwa [mul_sub, ← map_mul, mul_comm, mul_assoc, (he.idem i).eq, he', ← map_mul, ← Pi.single_mul, + one_mul, sub_eq_zero] at this + +end Algebra.FormallySmooth diff --git a/Mathlib/RingTheory/Smooth/StandardSmooth.lean b/Mathlib/RingTheory/Smooth/StandardSmooth.lean index 988a61b9c879e..8d4159379686e 100644 --- a/Mathlib/RingTheory/Smooth/StandardSmooth.lean +++ b/Mathlib/RingTheory/Smooth/StandardSmooth.lean @@ -89,8 +89,7 @@ variable (n m : ℕ) namespace Algebra -variable (R : Type u) [CommRing R] -variable (S : Type v) [CommRing S] [Algebra R S] +variable (R : Type u) (S : Type v) [CommRing R] [CommRing S] [Algebra R S] /-- A `PreSubmersivePresentation` of an `R`-algebra `S` is a `Presentation` @@ -556,26 +555,3 @@ instance IsStandardSmoothOfRelativeDimension.baseChange end BaseChange end Algebra - -namespace RingHom - -variable {R : Type u} [CommRing R] -variable {S : Type v} [CommRing S] - -/-- A ring homomorphism `R →+* S` is standard smooth if `S` is standard smooth as `R`-algebra. -/ -def IsStandardSmooth (f : R →+* S) : Prop := - @Algebra.IsStandardSmooth.{t, w} _ _ _ _ f.toAlgebra - -/-- A ring homomorphism `R →+* S` is standard smooth of relative dimension `n` if -`S` is standard smooth of relative dimension `n` as `R`-algebra. -/ -def IsStandardSmoothOfRelativeDimension (f : R →+* S) : Prop := - @Algebra.IsStandardSmoothOfRelativeDimension.{t, w} n _ _ _ _ f.toAlgebra - -lemma IsStandardSmoothOfRelativeDimension.isStandardSmooth (f : R →+* S) - (hf : IsStandardSmoothOfRelativeDimension.{t, w} n f) : - IsStandardSmooth.{t, w} f := - letI : Algebra R S := f.toAlgebra - letI : Algebra.IsStandardSmoothOfRelativeDimension.{t, w} n R S := hf - Algebra.IsStandardSmoothOfRelativeDimension.isStandardSmooth n - -end RingHom diff --git a/Mathlib/RingTheory/SurjectiveOnStalks.lean b/Mathlib/RingTheory/SurjectiveOnStalks.lean index 67f0451472874..c8c8f65ad3cba 100644 --- a/Mathlib/RingTheory/SurjectiveOnStalks.lean +++ b/Mathlib/RingTheory/SurjectiveOnStalks.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.RingTheory.Localization.AtPrime -import Mathlib.RingTheory.LocalRing.RingHom.Basic import Mathlib.RingTheory.TensorProduct.Basic /-! @@ -175,7 +174,7 @@ lemma SurjectiveOnStalks.baseChange one_mul, mul_one, id_apply, ← e] rw [Algebra.algebraMap_eq_smul_one, ← smul_tmul', smul_mul_assoc] -lemma surjectiveOnStalks_iff_of_isLocalRingHom [LocalRing S] [IsLocalRingHom f] : +lemma surjectiveOnStalks_iff_of_isLocalHom [LocalRing S] [IsLocalHom f] : f.SurjectiveOnStalks ↔ Function.Surjective f := by refine ⟨fun H x ↦ ?_, fun h ↦ surjectiveOnStalks_of_surjective h⟩ obtain ⟨y, r, c, hc, hr, e⟩ := @@ -186,4 +185,7 @@ lemma surjectiveOnStalks_iff_of_isLocalRingHom [LocalRing S] [IsLocalRingHom f] apply hc.mul_right_injective simp only [← _root_.map_mul, ← mul_assoc, IsUnit.mul_val_inv, one_mul, e] +@[deprecated (since := "2024-10-10")] +alias surjectiveOnStalks_iff_of_isLocalRingHom := surjectiveOnStalks_iff_of_isLocalHom + end RingHom diff --git a/Mathlib/RingTheory/TensorProduct/Basic.lean b/Mathlib/RingTheory/TensorProduct/Basic.lean index 3bddb995b0910..15539b8a077a5 100644 --- a/Mathlib/RingTheory/TensorProduct/Basic.lean +++ b/Mathlib/RingTheory/TensorProduct/Basic.lean @@ -576,12 +576,22 @@ instance instCommRing : CommRing (A ⊗[R] B) := { toRing := inferInstance mul_comm := mul_comm } +end CommRing + section RightAlgebra +variable [CommSemiring R] +variable [Semiring A] [Algebra R A] +variable [CommSemiring B] [Algebra R B] + /-- `S ⊗[R] T` has a `T`-algebra structure. This is not a global instance or else the action of `S` on `S ⊗[R] S` would be ambiguous. -/ abbrev rightAlgebra : Algebra B (A ⊗[R] B) := - (Algebra.TensorProduct.includeRight.toRingHom : B →+* A ⊗[R] B).toAlgebra + includeRight.toRingHom.toAlgebra' fun b x => by + suffices LinearMap.mulLeft R (includeRight b) = LinearMap.mulRight R (includeRight b) from + congr($this x) + ext xa xb + simp [mul_comm] attribute [local instance] TensorProduct.rightAlgebra @@ -590,8 +600,6 @@ instance right_isScalarTower : IsScalarTower R B (A ⊗[R] B) := end RightAlgebra -end CommRing - /-- Verify that typeclass search finds the ring structure on `A ⊗[ℤ] B` when `A` and `B` are merely rings, by treating both as `ℤ`-algebras. -/ @@ -692,8 +700,8 @@ def lift (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) ( (AlgebraTensorModule.lift <| letI restr : (C →ₗ[S] C) →ₗ[S] _ := { toFun := (·.restrictScalars R) - map_add' := fun f g => LinearMap.ext fun x => rfl - map_smul' := fun c g => LinearMap.ext fun x => rfl } + map_add' := fun _ _ => LinearMap.ext fun _ => rfl + map_smul' := fun _ _ => LinearMap.ext fun _ => rfl } LinearMap.flip <| (restr ∘ₗ LinearMap.mul S C ∘ₗ f.toLinearMap).flip ∘ₗ g) (fun a₁ a₂ b₁ b₂ => show f (a₁ * a₂) * g (b₁ * b₂) = f a₁ * g b₁ * (f a₂ * g b₂) by rw [map_mul, map_mul, (hfg a₂ b₁).mul_mul_mul_comm]) @@ -707,7 +715,7 @@ theorem lift_tmul (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commut @[simp] theorem lift_includeLeft_includeRight : - lift includeLeft includeRight (fun a b => (Commute.one_right _).tmul (Commute.one_left _)) = + lift includeLeft includeRight (fun _ _ => (Commute.one_right _).tmul (Commute.one_left _)) = .id S (A ⊗[R] B) := by ext <;> simp @@ -733,7 +741,7 @@ algebra. -/ def liftEquiv : {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)} ≃ ((A ⊗[R] B) →ₐ[S] C) where toFun fg := lift fg.val.1 fg.val.2 fg.prop - invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y => + invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun _ _ => ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩ left_inv fg := by ext <;> simp right_inv f' := by ext <;> simp @@ -948,6 +956,55 @@ theorem congr_trans [Algebra S C] [IsScalarTower R S C] theorem congr_symm (f : A ≃ₐ[S] B) (g : C ≃ₐ[R] D) : congr f.symm g.symm = (congr f g).symm := rfl +variable (R A B C) in +/-- Tensor product of algebras analogue of `mul_left_comm`. + +This is the algebra version of `TensorProduct.leftComm`. -/ +def leftComm : A ⊗[R] B ⊗[R] C ≃ₐ[R] B ⊗[R] A ⊗[R] C := + let e₁ := (Algebra.TensorProduct.assoc R A B C).symm + let e₂ := congr (Algebra.TensorProduct.comm R A B) (1 : C ≃ₐ[R] C) + let e₃ := Algebra.TensorProduct.assoc R B A C + e₁.trans (e₂.trans e₃) + +@[simp] +theorem leftComm_tmul (m : A) (n : B) (p : C) : + leftComm R A B C (m ⊗ₜ (n ⊗ₜ p)) = n ⊗ₜ (m ⊗ₜ p) := + rfl + +@[simp] +theorem leftComm_symm_tmul (m : A) (n : B) (p : C) : + (leftComm R A B C).symm (n ⊗ₜ (m ⊗ₜ p)) = m ⊗ₜ (n ⊗ₜ p) := + rfl + +@[simp] +theorem leftComm_toLinearEquiv : + (leftComm R A B C : _ ≃ₗ[R] _) = _root_.TensorProduct.leftComm R A B C := rfl + +variable (R A B C D) in +/-- Tensor product of algebras analogue of `mul_mul_mul_comm`. + +This is the algebra version of `TensorProduct.tensorTensorTensorComm`. -/ +def tensorTensorTensorComm : (A ⊗[R] B) ⊗[R] C ⊗[R] D ≃ₐ[R] (A ⊗[R] C) ⊗[R] B ⊗[R] D := + let e₁ := Algebra.TensorProduct.assoc R A B (C ⊗[R] D) + let e₂ := congr (1 : A ≃ₐ[R] A) (leftComm R B C D) + let e₃ := (Algebra.TensorProduct.assoc R A C (B ⊗[R] D)).symm + e₁.trans (e₂.trans e₃) + +@[simp] +theorem tensorTensorTensorComm_tmul (m : A) (n : B) (p : C) (q : D) : + tensorTensorTensorComm R A B C D (m ⊗ₜ n ⊗ₜ (p ⊗ₜ q)) = m ⊗ₜ p ⊗ₜ (n ⊗ₜ q) := + rfl + +@[simp] +theorem tensorTensorTensorComm_symm : + (tensorTensorTensorComm R A B C D).symm = tensorTensorTensorComm R A C B D := by + ext; rfl + +@[simp] +theorem tensorTensorTensorComm_toLinearEquiv : + (tensorTensorTensorComm R A B C D : _ ≃ₗ[R] _) = + _root_.TensorProduct.tensorTensorTensorComm R A B C D := rfl + end end Monoidal diff --git a/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean b/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean index 5b8ae61882f73..529b84b2a297c 100644 --- a/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean +++ b/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean @@ -37,7 +37,7 @@ Let `Semiring R`, `Algebra R S` and `Module R N`. -/ -universe u v w +universe u v noncomputable section @@ -47,8 +47,7 @@ open DirectSum TensorProduct open Set LinearMap Submodule -variable {R : Type u} {M : Type v} {N : Type w} - [CommSemiring R] [AddCommMonoid M] [Module R M] +variable {R : Type u} {N : Type v} [CommSemiring R] variable {σ : Type*} diff --git a/Mathlib/RingTheory/Trace/Basic.lean b/Mathlib/RingTheory/Trace/Basic.lean index e06b0141ff923..5d15d4fac0ac3 100644 --- a/Mathlib/RingTheory/Trace/Basic.lean +++ b/Mathlib/RingTheory/Trace/Basic.lean @@ -483,3 +483,22 @@ lemma traceForm_dualBasis_powerBasis_eq [FiniteDimensional K L] [Algebra.IsSepar ring end DetNeZero + +section isNilpotent + +namespace Algebra + +/-- The trace of a nilpotent element is nilpotent. -/ +lemma trace_isNilpotent_of_isNilpotent {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] {x : S} + (hx : IsNilpotent x) : IsNilpotent (trace R S x) := by + by_cases hS : ∃ s : Finset S, Nonempty (Basis s R S) + · obtain ⟨s, ⟨b⟩⟩ := hS + have := Module.Finite.of_basis b + have := (Module.free_def R S).mpr ⟨s, ⟨b⟩⟩ + apply LinearMap.isNilpotent_trace_of_isNilpotent (hx.map (lmul R S)) + · rw [trace_eq_zero_of_not_exists_basis _ hS, LinearMap.zero_apply] + exact IsNilpotent.zero + +end Algebra + +end isNilpotent diff --git a/Mathlib/RingTheory/Trace/Defs.lean b/Mathlib/RingTheory/Trace/Defs.lean index 8d961bf7c82e6..936a15a3b644d 100644 --- a/Mathlib/RingTheory/Trace/Defs.lean +++ b/Mathlib/RingTheory/Trace/Defs.lean @@ -42,11 +42,11 @@ For now, the definitions assume `S` is commutative, so the choice doesn't matter -/ -universe u v w z +universe w variable {R S T : Type*} [CommRing R] [CommRing S] [CommRing T] variable [Algebra R S] [Algebra R T] -variable {ι κ : Type w} [Fintype ι] +variable {ι : Type w} [Fintype ι] open Module diff --git a/Mathlib/RingTheory/Trace/Quotient.lean b/Mathlib/RingTheory/Trace/Quotient.lean new file mode 100644 index 0000000000000..4986caa0081a5 --- /dev/null +++ b/Mathlib/RingTheory/Trace/Quotient.lean @@ -0,0 +1,233 @@ +/- +Copyright (c) 2024 Riccardo Brasca. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang, Riccardo Brasca +-/ + +import Mathlib.RingTheory.DedekindDomain.Dvr +import Mathlib.RingTheory.IntegralClosure.IntegralRestrict +import Mathlib.RingTheory.LocalRing.Quotient + +/-! + +We gather results about the relations between the trace map on `B → A` and the trace map on +quotients and localizations. + +## Main Results + +* `Algebra.trace_quotient_eq_of_isDedekindDomain` : The trace map on `B → A` coincides with the + trace map on `B⧸pB → A⧸p`. + +-/ + +variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] + +open LocalRing FiniteDimensional Submodule + +section LocalRing + +local notation "p" => maximalIdeal R +local notation "pS" => Ideal.map (algebraMap R S) p + +variable [Module.Free R S] [Module.Finite R S] + +attribute [local instance] Ideal.Quotient.field + +lemma Algebra.trace_quotient_mk [LocalRing R] (x : S) : + Algebra.trace (R ⧸ p) (S ⧸ pS) (Ideal.Quotient.mk pS x) = + Ideal.Quotient.mk p (Algebra.trace R S x) := by + classical + let ι := Module.Free.ChooseBasisIndex R S + let b : Basis ι R S := Module.Free.chooseBasis R S + rw [trace_eq_matrix_trace b, trace_eq_matrix_trace (basisQuotient b), AddMonoidHom.map_trace] + congr 1 + ext i j + simp only [leftMulMatrix_apply, coe_lmul_eq_mul, LinearMap.toMatrix_apply, + basisQuotient_apply, LinearMap.mul_apply', RingHom.toAddMonoidHom_eq_coe, + AddMonoidHom.mapMatrix_apply, AddMonoidHom.coe_coe, Matrix.map_apply, ← map_mul, + basisQuotient_repr] + +end LocalRing + +section IsDedekindDomain + +variable (p : Ideal R) [p.IsMaximal] +variable {Rₚ Sₚ : Type*} [CommRing Rₚ] [CommRing Sₚ] [Algebra R Rₚ] [IsLocalization.AtPrime Rₚ p] +variable [LocalRing Rₚ] [Algebra S Sₚ] [Algebra R Sₚ] [Algebra Rₚ Sₚ] +variable [IsLocalization (Algebra.algebraMapSubmonoid S p.primeCompl) Sₚ] +variable [IsScalarTower R S Sₚ] [IsScalarTower R Rₚ Sₚ] + +variable (Rₚ) + +attribute [local instance] Ideal.Quotient.field + +/-- The isomorphism `R ⧸ p ≃+* Rₚ ⧸ maximalIdeal Rₚ`, where `Rₚ` satisfies +`IsLocalization.AtPrime Rₚ p`. In particular, localization preserves the residue field. -/ +noncomputable +def equivQuotMaximalIdealOfIsLocalization : R ⧸ p ≃+* Rₚ ⧸ maximalIdeal Rₚ := by + refine (Ideal.quotEquivOfEq ?_).trans + (RingHom.quotientKerEquivOfSurjective (f := algebraMap R (Rₚ ⧸ maximalIdeal Rₚ)) ?_) + · rw [IsScalarTower.algebraMap_eq R Rₚ, ← RingHom.comap_ker, + Ideal.Quotient.algebraMap_eq, Ideal.mk_ker, IsLocalization.AtPrime.comap_maximalIdeal Rₚ p] + · intro x + obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective p.primeCompl x + obtain ⟨s', hs⟩ := Ideal.Quotient.mk_surjective (I := p) (Ideal.Quotient.mk p s)⁻¹ + simp only [IsScalarTower.algebraMap_eq R Rₚ (Rₚ ⧸ _), + Ideal.Quotient.algebraMap_eq, RingHom.comp_apply] + use x * s' + rw [← sub_eq_zero, ← map_sub, Ideal.Quotient.eq_zero_iff_mem] + have : algebraMap R Rₚ s ∉ maximalIdeal Rₚ := by + rw [← Ideal.mem_comap, IsLocalization.AtPrime.comap_maximalIdeal Rₚ p] + exact s.prop + refine ((inferInstanceAs <| (maximalIdeal Rₚ).IsPrime).mem_or_mem ?_).resolve_left this + rw [mul_sub, IsLocalization.mul_mk'_eq_mk'_of_mul, IsLocalization.mk'_mul_cancel_left, + ← map_mul, ← map_sub, ← Ideal.mem_comap, IsLocalization.AtPrime.comap_maximalIdeal Rₚ p, + mul_left_comm, ← Ideal.Quotient.eq_zero_iff_mem, map_sub, map_mul, map_mul, hs, + mul_inv_cancel₀, mul_one, sub_self] + rw [Ne, Ideal.Quotient.eq_zero_iff_mem] + exact s.prop + +lemma IsLocalization.AtPrime.map_eq_maximalIdeal : + p.map (algebraMap R Rₚ) = maximalIdeal Rₚ := by + convert congr_arg (Ideal.map (algebraMap R Rₚ)) + (IsLocalization.AtPrime.comap_maximalIdeal Rₚ p).symm + rw [map_comap p.primeCompl] + +local notation "pS" => Ideal.map (algebraMap R S) p +local notation "pSₚ" => Ideal.map (algebraMap Rₚ Sₚ) (maximalIdeal Rₚ) + +lemma comap_map_eq_map_of_isLocalization_algebraMapSubmonoid : + (Ideal.map (algebraMap R Sₚ) p).comap (algebraMap S Sₚ) = pS := by + rw [IsScalarTower.algebraMap_eq R S Sₚ, ← Ideal.map_map, eq_comm] + apply Ideal.le_comap_map.antisymm + intro x hx + obtain ⟨α, hα, hαx⟩ : ∃ α ∉ p, α • x ∈ pS := by + have ⟨⟨y, s⟩, hy⟩ := (IsLocalization.mem_map_algebraMap_iff + (Algebra.algebraMapSubmonoid S p.primeCompl) Sₚ).mp hx + rw [← map_mul, + IsLocalization.eq_iff_exists (Algebra.algebraMapSubmonoid S p.primeCompl)] at hy + obtain ⟨c, hc⟩ := hy + obtain ⟨α, hα, e⟩ := (c * s).prop + refine ⟨α, hα, ?_⟩ + rw [Algebra.smul_def, e, Submonoid.coe_mul, mul_assoc, mul_comm _ x, hc] + exact Ideal.mul_mem_left _ _ y.prop + obtain ⟨β, γ, hγ, hβ⟩ : ∃ β γ, γ ∈ p ∧ β * α = 1 + γ := by + obtain ⟨β, hβ⟩ := Ideal.Quotient.mk_surjective (I := p) (Ideal.Quotient.mk p α)⁻¹ + refine ⟨β, β * α - 1, ?_, ?_⟩ + · rw [← Ideal.Quotient.eq_zero_iff_mem, map_sub, map_one, + map_mul, hβ, inv_mul_cancel₀, sub_self] + rwa [Ne, Ideal.Quotient.eq_zero_iff_mem] + · rw [add_sub_cancel] + have := Ideal.mul_mem_left _ (algebraMap _ _ β) hαx + rw [← Algebra.smul_def, smul_smul, hβ, add_smul, one_smul] at this + refine (Submodule.add_mem_iff_left _ ?_).mp this + rw [Algebra.smul_def] + apply Ideal.mul_mem_right + exact Ideal.mem_map_of_mem _ hγ + +variable (S Sₚ) + +/-- The isomorphism `S ⧸ pS ≃+* Sₚ ⧸ pSₚ`. -/ +noncomputable +def quotMapEquivQuotMapMaximalIdealOfIsLocalization : S ⧸ pS ≃+* Sₚ ⧸ pSₚ := by + haveI h : pSₚ = Ideal.map (algebraMap S Sₚ) pS := by + rw [← IsLocalization.AtPrime.map_eq_maximalIdeal p Rₚ, Ideal.map_map, + ← IsScalarTower.algebraMap_eq, Ideal.map_map, ← IsScalarTower.algebraMap_eq] + refine (Ideal.quotEquivOfEq ?_).trans + (RingHom.quotientKerEquivOfSurjective (f := algebraMap S (Sₚ ⧸ pSₚ)) ?_) + · rw [IsScalarTower.algebraMap_eq S Sₚ, Ideal.Quotient.algebraMap_eq, ← RingHom.comap_ker, + Ideal.mk_ker, h, Ideal.map_map, ← IsScalarTower.algebraMap_eq, + comap_map_eq_map_of_isLocalization_algebraMapSubmonoid] + · intro x + obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective + (Algebra.algebraMapSubmonoid S p.primeCompl) x + obtain ⟨α, hα : α ∉ p, e⟩ := s.prop + obtain ⟨β, γ, hγ, hβ⟩ : ∃ β γ, γ ∈ p ∧ α * β = 1 + γ := by + obtain ⟨β, hβ⟩ := Ideal.Quotient.mk_surjective (I := p) (Ideal.Quotient.mk p α)⁻¹ + refine ⟨β, α * β - 1, ?_, ?_⟩ + · rw [← Ideal.Quotient.eq_zero_iff_mem, map_sub, map_one, + map_mul, hβ, mul_inv_cancel₀, sub_self] + rwa [Ne, Ideal.Quotient.eq_zero_iff_mem] + · rw [add_sub_cancel] + use β • x + rw [IsScalarTower.algebraMap_eq S Sₚ (Sₚ ⧸ pSₚ), Ideal.Quotient.algebraMap_eq, + RingHom.comp_apply, ← sub_eq_zero, ← map_sub, Ideal.Quotient.eq_zero_iff_mem] + rw [h, IsLocalization.mem_map_algebraMap_iff + (Algebra.algebraMapSubmonoid S p.primeCompl) Sₚ] + refine ⟨⟨⟨γ • x, ?_⟩, s⟩, ?_⟩ + · rw [Algebra.smul_def] + apply Ideal.mul_mem_right + exact Ideal.mem_map_of_mem _ hγ + simp only + rw [mul_comm, mul_sub, IsLocalization.mul_mk'_eq_mk'_of_mul, + IsLocalization.mk'_mul_cancel_left, ← map_mul, ← e, ← Algebra.smul_def, smul_smul, + hβ, ← map_sub, add_smul, one_smul, add_comm x, add_sub_cancel_right] + +lemma trace_quotient_eq_trace_localization_quotient (x) : + Algebra.trace (R ⧸ p) (S ⧸ pS) (Ideal.Quotient.mk pS x) = + (equivQuotMaximalIdealOfIsLocalization p Rₚ).symm + (Algebra.trace (Rₚ ⧸ maximalIdeal Rₚ) (Sₚ ⧸ pSₚ) (algebraMap S _ x)) := by + have : IsScalarTower R (Rₚ ⧸ maximalIdeal Rₚ) (Sₚ ⧸ pSₚ) := by + apply IsScalarTower.of_algebraMap_eq' + rw [IsScalarTower.algebraMap_eq R Rₚ (Rₚ ⧸ _), IsScalarTower.algebraMap_eq R Rₚ (Sₚ ⧸ _), + ← RingHom.comp_assoc, ← IsScalarTower.algebraMap_eq Rₚ] + rw [Algebra.trace_eq_of_equiv_equiv (equivQuotMaximalIdealOfIsLocalization p Rₚ) + (quotMapEquivQuotMapMaximalIdealOfIsLocalization S p Rₚ Sₚ)] + · congr + · ext x + simp only [equivQuotMaximalIdealOfIsLocalization, RingHom.quotientKerEquivOfSurjective, + RingEquiv.coe_ringHom_trans, RingHom.coe_comp, RingHom.coe_coe, Function.comp_apply, + Ideal.quotEquivOfEq_mk, RingHom.quotientKerEquivOfRightInverse.apply, RingHom.kerLift_mk, + quotMapEquivQuotMapMaximalIdealOfIsLocalization, + Ideal.Quotient.algebraMap_quotient_map_quotient] + rw [← IsScalarTower.algebraMap_apply, ← IsScalarTower.algebraMap_apply] + +open nonZeroDivisors in +/-- The trace map on `B → A` coincides with the trace map on `B⧸pB → A⧸p`. -/ +lemma Algebra.trace_quotient_eq_of_isDedekindDomain (x) [IsDedekindDomain R] [IsDomain S] + [NoZeroSMulDivisors R S] [Module.Finite R S] [IsIntegrallyClosed S] : + Algebra.trace (R ⧸ p) (S ⧸ pS) (Ideal.Quotient.mk pS x) = + Ideal.Quotient.mk p (Algebra.intTrace R S x) := by + let Rₚ := Localization.AtPrime p + let Sₚ := Localization (Algebra.algebraMapSubmonoid S p.primeCompl) + letI : Algebra Rₚ Sₚ := localizationAlgebra p.primeCompl S + haveI : IsScalarTower R Rₚ Sₚ := IsScalarTower.of_algebraMap_eq' + (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, ← IsScalarTower.algebraMap_eq]) + haveI : IsLocalization (Submonoid.map (algebraMap R S) (Ideal.primeCompl p)) Sₚ := + inferInstanceAs (IsLocalization (Algebra.algebraMapSubmonoid S p.primeCompl) Sₚ) + have e : Algebra.algebraMapSubmonoid S p.primeCompl ≤ S⁰ := + Submonoid.map_le_of_le_comap _ <| p.primeCompl_le_nonZeroDivisors.trans + (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ + (NoZeroSMulDivisors.algebraMap_injective _ _)) + haveI : IsDomain Sₚ := IsLocalization.isDomain_of_le_nonZeroDivisors S e + haveI : NoZeroSMulDivisors Rₚ Sₚ := by + rw [NoZeroSMulDivisors.iff_algebraMap_injective, RingHom.injective_iff_ker_eq_bot, + RingHom.ker_eq_bot_iff_eq_zero] + intro x hx + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective p.primeCompl x + simp only [RingHom.algebraMap_toAlgebra, IsLocalization.map_mk', IsLocalization.mk'_eq_zero_iff, + mul_eq_zero, Subtype.exists, exists_prop] at hx ⊢ + obtain ⟨_, ⟨a, ha, rfl⟩, H⟩ := hx + simp only [(injective_iff_map_eq_zero' _).mp (NoZeroSMulDivisors.algebraMap_injective R S)] at H + refine ⟨a, ha, H⟩ + haveI : Module.Finite Rₚ Sₚ := Module.Finite_of_isLocalization R S _ _ p.primeCompl + haveI : IsIntegrallyClosed Sₚ := isIntegrallyClosed_of_isLocalization _ _ e + have : IsPrincipalIdealRing Rₚ := by + by_cases hp : p = ⊥ + · infer_instance + · have := (IsDedekindDomain.isDedekindDomainDvr R).2 p hp inferInstance + infer_instance + haveI : Module.Free Rₚ Sₚ := Module.free_of_finite_type_torsion_free' + apply (equivQuotMaximalIdealOfIsLocalization p Rₚ).injective + rw [trace_quotient_eq_trace_localization_quotient S p Rₚ Sₚ, IsScalarTower.algebraMap_eq S Sₚ, + RingHom.comp_apply, Ideal.Quotient.algebraMap_eq, Algebra.trace_quotient_mk, + RingEquiv.apply_symm_apply, ← Algebra.intTrace_eq_trace, + ← Algebra.intTrace_eq_of_isLocalization R S p.primeCompl (Aₘ := Rₚ) (Bₘ := Sₚ) x, + ← Ideal.Quotient.algebraMap_eq, ← IsScalarTower.algebraMap_apply] + simp only [equivQuotMaximalIdealOfIsLocalization, RingHom.quotientKerEquivOfSurjective, + RingEquiv.coe_trans, Function.comp_apply, Ideal.quotEquivOfEq_mk, + RingHom.quotientKerEquivOfRightInverse.apply, RingHom.kerLift_mk] + +end IsDedekindDomain diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean b/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean index dd7cee192929b..532582ec88dd8 100644 --- a/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean +++ b/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean @@ -8,6 +8,7 @@ import Mathlib.Tactic.Abel import Mathlib.GroupTheory.GroupAction.SubMulAction import Mathlib.RingTheory.Congruence.Basic import Mathlib.Algebra.Module.LinearMap.Defs +import Mathlib.Algebra.Module.Opposite /-! # Two Sided Ideals diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean index 78ccd01d0a217..b8295f7547e9c 100644 --- a/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean +++ b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean @@ -4,12 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang, Jireh Loreaux -/ -import Mathlib.RingTheory.TwoSidedIdeal.Lattice -import Mathlib.RingTheory.Congruence.Opposite -import Mathlib.Algebra.BigOperators.Ring -import Mathlib.Data.Fintype.BigOperators -import Mathlib.RingTheory.Ideal.Basic +import Mathlib.Algebra.Module.Submodule.Lattice import Mathlib.Order.GaloisConnection +import Mathlib.Order.OmegaCompletePartialOrder +import Mathlib.RingTheory.Congruence.Opposite +import Mathlib.RingTheory.Ideal.Defs +import Mathlib.RingTheory.TwoSidedIdeal.Lattice /-! # Operations on two-sided ideals @@ -141,10 +141,10 @@ lemma mem_span_iff_mem_addSubgroup_closure_absorbing {s : Set R} induction principle for `AddSubgroup`, we must also have `z ∈ J`. -/ case mem_ideal_of_subset => simp only [I, SetLike.mem_coe, mem_mk'] at hz - induction hz using closure_induction' with + induction hz using closure_induction with | mem x hx => exact hJ hx | one => exact zero_mem _ - | mul x _ y _ hx hy => exact J.add_mem hx hy + | mul x y _ _ hx hy => exact J.add_mem hx hy | inv x _ hx => exact J.neg_mem hx open Pointwise Set diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain.lean b/Mathlib/RingTheory/UniqueFactorizationDomain.lean index ee5e511abe687..3f8b848b1c56e 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain.lean @@ -101,7 +101,7 @@ theorem induction_on_irreducible {P : α → Prop} (a : α) (h0 : P 0) (hu : ∀ theorem exists_factors (a : α) : a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ Associated f.prod a := induction_on_irreducible a (fun h => (h rfl).elim) - (fun u hu _ => ⟨0, fun _ h => False.elim (Multiset.not_mem_zero _ h), hu.unit, one_mul _⟩) + (fun _ hu _ => ⟨0, fun _ h => False.elim (Multiset.not_mem_zero _ h), hu.unit, one_mul _⟩) fun a i ha0 hi ih _ => let ⟨s, hs⟩ := ih ha0 ⟨i ::ₘ s, fun b H => (Multiset.mem_cons.1 H).elim (fun h => h.symm ▸ hi) (hs.1 b), by @@ -118,7 +118,7 @@ theorem not_unit_iff_exists_factors_eq (a : α) (hn0 : a ≠ 0) : · obtain rfl | ha := Multiset.mem_cons.1 ha exacts [Associated.irreducible ⟨u, rfl⟩ (hi b h), hi a (Multiset.mem_of_mem_erase ha)] · rw [Multiset.prod_cons, mul_comm b, mul_assoc, Multiset.prod_erase h, mul_comm], - fun ⟨f, hi, he, hne⟩ => + fun ⟨_, hi, he, hne⟩ => let ⟨b, h⟩ := Multiset.exists_mem_of_ne_zero hne not_isUnit_of_not_isUnit_dvd (hi b h).not_unit <| he ▸ Multiset.dvd_prod h⟩ @@ -195,7 +195,6 @@ class UniqueFactorizationMonoid (α : Type*) [CancelCommMonoidWithZero α] exten IsWellFounded α DvdNotUnit : Prop where protected irreducible_iff_prime : ∀ {a : α}, Irreducible a ↔ Prime a -/-- Can't be an instance because it would cause a loop `ufm → WfDvdMonoid → ufm → ...`. -/ instance (priority := 100) ufm_of_decomposition_of_wfDvdMonoid [CancelCommMonoidWithZero α] [WfDvdMonoid α] [DecompositionMonoid α] : UniqueFactorizationMonoid α := @@ -494,7 +493,7 @@ theorem exists_mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p have hb0 : b ≠ 0 := fun hb0 => by simp_all have : Multiset.Rel Associated (p ::ₘ factors b) (factors a) := factors_unique - (fun x hx => (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_factor _)) + (fun _ hx => (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_factor _)) irreducible_of_factor (Associated.symm <| calc @@ -554,6 +553,13 @@ theorem factors_pow_count_prod [DecidableEq α] {x : α} (hx : x ≠ 0) : _ = prod (factors x) := by rw [toFinset_sum_count_nsmul_eq (factors x)] _ ~ᵤ x := factors_prod hx +theorem factors_rel_of_associated {a b : α} (h : Associated a b) : + Multiset.Rel Associated (factors a) (factors b) := by + rcases iff_iff_and_or_not_and_not.mp h.eq_zero_iff with (⟨rfl, rfl⟩ | ⟨ha, hb⟩) + · simp + · refine factors_unique irreducible_of_factor irreducible_of_factor ?_ + exact ((factors_prod ha).trans h).trans (factors_prod hb).symm + end UniqueFactorizationMonoid namespace UniqueFactorizationMonoid @@ -627,7 +633,7 @@ theorem exists_mem_normalizedFactors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irr have hb0 : b ≠ 0 := fun hb0 => by simp_all have : Multiset.Rel Associated (p ::ₘ normalizedFactors b) (normalizedFactors a) := factors_unique - (fun x hx => + (fun _ hx => (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_normalized_factor _)) irreducible_of_normalized_factor (Associated.symm <| @@ -721,13 +727,17 @@ theorem dvd_iff_normalizedFactors_le_normalizedFactors {x y : α} (hx : x ≠ 0) (normalizedFactors_prod hy).dvd_iff_dvd_right] apply Multiset.prod_dvd_prod_of_le +theorem _root_.Associated.normalizedFactors_eq {a b : α} (h : Associated a b) : + normalizedFactors a = normalizedFactors b := by + unfold normalizedFactors + have h' : ⇑(normalize (α := α)) = Associates.out ∘ Associates.mk := funext Associates.out_mk + rw [h', ← Multiset.map_map, ← Multiset.map_map, + Associates.rel_associated_iff_map_eq_map.mp (factors_rel_of_associated h)] + theorem associated_iff_normalizedFactors_eq_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - x ~ᵤ y ↔ normalizedFactors x = normalizedFactors y := by - refine - ⟨fun h => ?_, fun h => - (normalizedFactors_prod hx).symm.trans (_root_.trans (by rw [h]) (normalizedFactors_prod hy))⟩ - apply le_antisymm <;> rw [← dvd_iff_normalizedFactors_le_normalizedFactors] - all_goals simp [*, h.dvd, h.symm.dvd] + x ~ᵤ y ↔ normalizedFactors x = normalizedFactors y := + ⟨Associated.normalizedFactors_eq, fun h => + (normalizedFactors_prod hx).symm.trans (_root_.trans (by rw [h]) (normalizedFactors_prod hy))⟩ theorem normalizedFactors_of_irreducible_pow {p : α} (hp : Irreducible p) (k : ℕ) : normalizedFactors (p ^ k) = Multiset.replicate k (normalize p) := by @@ -923,15 +933,14 @@ section multiplicity variable [NormalizationMonoid R] -open multiplicity Multiset +open Multiset section -variable [DecidableRel (Dvd.dvd : R → R → Prop)] -theorem le_multiplicity_iff_replicate_le_normalizedFactors {a b : R} {n : ℕ} (ha : Irreducible a) +theorem le_emultiplicity_iff_replicate_le_normalizedFactors {a b : R} {n : ℕ} (ha : Irreducible a) (hb : b ≠ 0) : - ↑n ≤ multiplicity a b ↔ replicate n (normalize a) ≤ normalizedFactors b := by - rw [← pow_dvd_iff_le_multiplicity] + ↑n ≤ emultiplicity a b ↔ replicate n (normalize a) ≤ normalizedFactors b := by + rw [← pow_dvd_iff_le_emultiplicity] revert b induction' n with n ih; · simp intro b hb @@ -952,14 +961,14 @@ the normalized factor occurs in the `normalizedFactors`. See also `count_normalizedFactors_eq` which expands the definition of `multiplicity` to produce a specification for `count (normalizedFactors _) _`.. -/ -theorem multiplicity_eq_count_normalizedFactors [DecidableEq R] {a b : R} (ha : Irreducible a) - (hb : b ≠ 0) : multiplicity a b = (normalizedFactors b).count (normalize a) := by +theorem emultiplicity_eq_count_normalizedFactors [DecidableEq R] {a b : R} (ha : Irreducible a) + (hb : b ≠ 0) : emultiplicity a b = (normalizedFactors b).count (normalize a) := by apply le_antisymm - · apply PartENat.le_of_lt_add_one + · apply Order.le_of_lt_add_one rw [← Nat.cast_one, ← Nat.cast_add, lt_iff_not_ge, ge_iff_le, - le_multiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] + le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] simp - rw [le_multiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] + rw [le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] end @@ -970,14 +979,13 @@ See also `multiplicity_eq_count_normalizedFactors` if `n` is given by `multiplic -/ theorem count_normalizedFactors_eq [DecidableEq R] {p x : R} (hp : Irreducible p) (hnorm : normalize p = p) {n : ℕ} (hle : p ^ n ∣ x) (hlt : ¬p ^ (n + 1) ∣ x) : - (normalizedFactors x).count p = n := by - letI : DecidableRel ((· ∣ ·) : R → R → Prop) := fun _ _ => Classical.propDecidable _ + (normalizedFactors x).count p = n := by classical by_cases hx0 : x = 0 · simp [hx0] at hlt - rw [← PartENat.natCast_inj] - convert (multiplicity_eq_count_normalizedFactors hp hx0).symm + apply Nat.cast_injective (R := ℕ∞) + convert (emultiplicity_eq_count_normalizedFactors hp hx0).symm · exact hnorm.symm - exact (multiplicity.eq_coe_iff.mpr ⟨hle, hlt⟩).symm + exact (emultiplicity_eq_coe.mpr ⟨hle, hlt⟩).symm /-- The number of times an irreducible factor `p` appears in `normalizedFactors x` is defined by the number of times it divides `x`. This is a slightly more general version of @@ -1027,7 +1035,7 @@ theorem prime_pow_coprime_prod_of_coprime_insert [DecidableEq α] {s : Finset α /-- If `P` holds for units and powers of primes, and `P x ∧ P y` for coprime `x, y` implies `P (x * y)`, then `P` holds on a product of powers of distinct primes. -/ --- @[elab_as_elim] Porting note: commented out +@[elab_as_elim] theorem induction_on_prime_power {P : α → Prop} (s : Finset α) (i : α → ℕ) (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q) (h1 : ∀ {x}, IsUnit x → P x) (hpr : ∀ {p} (i : ℕ), Prime p → P (p ^ i)) @@ -1066,7 +1074,6 @@ theorem induction_on_coprime {P : α → Prop} (a : α) (h0 : P 0) (h1 : ∀ {x} /-- If `f` maps `p ^ i` to `(f p) ^ i` for primes `p`, and `f` is multiplicative on coprime elements, then `f` is multiplicative on all products of primes. -/ --- @[elab_as_elim] Porting note: commented out theorem multiplicative_prime_power {f : α → β} (s : Finset α) (i j : α → ℕ) (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q) (h1 : ∀ {x y}, IsUnit y → f (x * y) = f x * f y) @@ -1202,7 +1209,7 @@ theorem prod_mono : ∀ {a b : FactorSet α}, a ≤ b → a.prod ≤ b.prod have : b = ⊤ := top_unique h rw [this, prod_top] | a, ⊤, _ => show a.prod ≤ (⊤ : FactorSet α).prod by simp - | WithTop.some a, WithTop.some b, h => + | WithTop.some _, WithTop.some _, h => prod_le_prod <| Multiset.map_le_map <| WithTop.coe_le_coe.1 <| h theorem FactorSet.prod_eq_zero_iff [Nontrivial α] (p : FactorSet α) : p.prod = 0 ↔ p = ⊤ := by diff --git a/Mathlib/RingTheory/Unramified/Basic.lean b/Mathlib/RingTheory/Unramified/Basic.lean index baf22e56e7160..73ca2ac3c5f04 100644 --- a/Mathlib/RingTheory/Unramified/Basic.lean +++ b/Mathlib/RingTheory/Unramified/Basic.lean @@ -3,20 +3,19 @@ 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.FinitePresentation import Mathlib.RingTheory.FiniteStability -import Mathlib.RingTheory.Localization.Away.Basic +import Mathlib.RingTheory.Ideal.Quotient.Nilpotent +import Mathlib.RingTheory.Kaehler.Basic import Mathlib.RingTheory.Localization.Away.AdjoinRoot -import Mathlib.RingTheory.QuotientNilpotent -import Mathlib.RingTheory.TensorProduct.Basic /-! # Unramified morphisms -An `R`-algebra `A` is formally unramified if for every `R`-algebra, +An `R`-algebra `A` is formally unramified if `Ω[A⁄R]` is trivial. +This is equivalent to the standard definition "for every `R`-algebra, every square-zero ideal `I : Ideal B` and `f : A →ₐ[R] B ⧸ I`, there exists -at most one lift `A →ₐ[R] B`. +at most one lift `A →ₐ[R] B`". It is unramified if it is formally unramified and of finite type. Note that there are multiple definitions in the literature. The definition we give is equivalent to @@ -34,25 +33,28 @@ localization at an element. -- Porting note: added to make the syntax work below. open scoped TensorProduct -universe u +universe u v w namespace Algebra section -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [Semiring A] [Algebra R A] +variable (R : Type v) [CommRing R] +variable (A : Type u) [CommRing A] [Algebra R A] -/-- An `R`-algebra `A` is formally unramified if for every `R`-algebra, every square-zero ideal -`I : Ideal B` and `f : A →ₐ[R] B ⧸ I`, there exists at most one lift `A →ₐ[R] B`. +/-- +An `R`-algebra `A` is formally unramified if `Ω[A⁄R]` is trivial. + +This is equivalent to "for every `R`-algebra, every square-zero ideal +`I : Ideal B` and `f : A →ₐ[R] B ⧸ I`, there exists at most one lift `A →ₐ[R] B`". +See `Algebra.FormallyUnramified.iff_comp_injective`. See . -/ @[mk_iff] class FormallyUnramified : Prop where - comp_injective : - ∀ ⦃B : Type u⦄ [CommRing B], - ∀ [Algebra R B] (I : Ideal B) (_ : I ^ 2 = ⊥), - Function.Injective ((Ideal.Quotient.mkₐ R I).comp : (A →ₐ[R] B) → A →ₐ[R] B ⧸ I) + subsingleton_kaehlerDifferential : Subsingleton (Ω[A⁄R]) + +attribute [instance] FormallyUnramified.subsingleton_kaehlerDifferential end @@ -60,16 +62,48 @@ namespace FormallyUnramified section -variable {R : Type u} [CommSemiring R] -variable {A : Type u} [Semiring A] [Algebra R A] -variable {B : Type u} [CommRing B] [Algebra R B] (I : Ideal B) - -theorem lift_unique {B : Type u} [CommRing B] [_RB : Algebra R B] +variable {R : Type v} [CommRing R] +variable {A : Type u} [CommRing A] [Algebra R A] +variable {B : Type w} [CommRing B] [Algebra R B] (I : Ideal B) + +theorem comp_injective [FormallyUnramified R A] (hI : I ^ 2 = ⊥) : + Function.Injective ((Ideal.Quotient.mkₐ R I).comp : (A →ₐ[R] B) → A →ₐ[R] B ⧸ I) := by + intro f₁ f₂ e + letI := f₁.toRingHom.toAlgebra + haveI := IsScalarTower.of_algebraMap_eq' f₁.comp_algebraMap.symm + have := + ((KaehlerDifferential.linearMapEquivDerivation R A).toEquiv.trans + (derivationToSquareZeroEquivLift I hI)).surjective.subsingleton + exact Subtype.ext_iff.mp (@Subsingleton.elim _ this ⟨f₁, rfl⟩ ⟨f₂, e.symm⟩) + +theorem iff_comp_injective : + FormallyUnramified R A ↔ + ∀ ⦃B : Type u⦄ [CommRing B], + ∀ [Algebra R B] (I : Ideal B) (_ : I ^ 2 = ⊥), + Function.Injective ((Ideal.Quotient.mkₐ R I).comp : (A →ₐ[R] B) → A →ₐ[R] B ⧸ I) := by + constructor + · intros; exact comp_injective _ ‹_› + · intro H + constructor + rw [← not_nontrivial_iff_subsingleton] + intro h + obtain ⟨f₁, f₂, e⟩ := (KaehlerDifferential.endEquiv R A).injective.nontrivial + apply e + ext1 + refine H + (RingHom.ker (TensorProduct.lmul' R (S := A)).kerSquareLift.toRingHom) ?_ ?_ + · rw [AlgHom.ker_kerSquareLift] + exact Ideal.cotangentIdeal_square _ + · ext x + apply RingHom.kerLift_injective (TensorProduct.lmul' R (S := A)).kerSquareLift.toRingHom + simpa using DFunLike.congr_fun (f₁.2.trans f₂.2.symm) x + +theorem lift_unique [FormallyUnramified R A] (I : Ideal B) (hI : IsNilpotent I) (g₁ g₂ : A →ₐ[R] B) (h : (Ideal.Quotient.mkₐ R I).comp g₁ = (Ideal.Quotient.mkₐ R I).comp g₂) : g₁ = g₂ := by revert g₁ g₂ change Function.Injective (Ideal.Quotient.mkₐ R I).comp - revert _RB + revert ‹Algebra R B› apply Ideal.IsNilpotent.induction_on (S := B) I hI · intro B _ I hI _; exact FormallyUnramified.comp_injective I hI · intro B _ I J hIJ h₁ h₂ _ g₁ g₂ e @@ -84,7 +118,7 @@ theorem ext [FormallyUnramified R A] (hI : IsNilpotent I) {g₁ g₂ : A →ₐ[ (H : ∀ x, Ideal.Quotient.mk I (g₁ x) = Ideal.Quotient.mk I (g₂ x)) : g₁ = g₂ := FormallyUnramified.lift_unique I hI g₁ g₂ (AlgHom.ext H) -theorem lift_unique_of_ringHom [FormallyUnramified R A] {C : Type u} [CommRing C] +theorem lift_unique_of_ringHom [FormallyUnramified R A] {C : Type*} [CommRing C] (f : B →+* C) (hf : IsNilpotent <| RingHom.ker f) (g₁ g₂ : A →ₐ[R] B) (h : f.comp ↑g₁ = f.comp (g₂ : A →+* B)) : g₁ = g₂ := FormallyUnramified.lift_unique _ hf _ _ @@ -94,32 +128,48 @@ theorem lift_unique_of_ringHom [FormallyUnramified R A] {C : Type u} [CommRing C simpa only [Ideal.Quotient.eq, Function.comp_apply, AlgHom.coe_comp, Ideal.Quotient.mkₐ_eq_mk, RingHom.mem_ker, map_sub, sub_eq_zero]) -theorem ext' [FormallyUnramified R A] {C : Type u} [CommRing C] (f : B →+* C) +theorem ext' [FormallyUnramified R A] {C : Type*} [CommRing C] (f : B →+* C) (hf : IsNilpotent <| RingHom.ker f) (g₁ g₂ : A →ₐ[R] B) (h : ∀ x, f (g₁ x) = f (g₂ x)) : g₁ = g₂ := FormallyUnramified.lift_unique_of_ringHom f hf g₁ g₂ (RingHom.ext h) -theorem lift_unique' [FormallyUnramified R A] {C : Type u} [CommRing C] +theorem lift_unique' [FormallyUnramified R A] {C : Type*} [CommRing C] [Algebra R C] (f : B →ₐ[R] C) (hf : IsNilpotent <| RingHom.ker (f : B →+* C)) (g₁ g₂ : A →ₐ[R] B) (h : f.comp g₁ = f.comp g₂) : g₁ = g₂ := FormallyUnramified.ext' _ hf g₁ g₂ (AlgHom.congr_fun h) -instance : FormallyUnramified R R := by - constructor +end + +instance {R : Type*} [CommRing R] : FormallyUnramified R R := by + rw [iff_comp_injective] intros B _ _ _ _ f₁ f₂ _ exact Subsingleton.elim _ _ -end +section OfEquiv + +variable {R : Type*} [CommRing R] +variable {A B : Type*} [CommRing A] [Algebra R A] [CommRing B] [Algebra R B] + +theorem of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) : + FormallyUnramified R B := by + rw [iff_comp_injective] + intro C _ _ I hI f₁ f₂ e' + rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc] + congr 1 + refine FormallyUnramified.comp_injective I hI ?_ + rw [← AlgHom.comp_assoc, e', AlgHom.comp_assoc] + +end OfEquiv section Comp -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [CommSemiring A] [Algebra R A] -variable (B : Type u) [Semiring B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] +variable (R : Type*) [CommRing R] +variable (A : Type*) [CommRing A] [Algebra R A] +variable (B : Type*) [CommRing B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] theorem comp [FormallyUnramified R A] [FormallyUnramified A B] : FormallyUnramified R B := by - constructor + rw [iff_comp_injective] intro C _ _ I hI f₁ f₂ e have e' := FormallyUnramified.lift_unique I ⟨2, hI⟩ (f₁.comp <| IsScalarTower.toAlgHom R A B) @@ -133,7 +183,7 @@ theorem comp [FormallyUnramified R A] [FormallyUnramified A B] : exact FormallyUnramified.ext I ⟨2, hI⟩ (AlgHom.congr_fun e) theorem of_comp [FormallyUnramified R B] : FormallyUnramified A B := by - constructor + rw [iff_comp_injective] intro Q _ _ I e f₁ f₂ e' letI := ((algebraMap A Q).comp (algebraMap R A)).toAlgebra letI : IsScalarTower R A Q := IsScalarTower.of_algebraMap_eq' rfl @@ -146,13 +196,13 @@ end Comp section of_surjective -variable {R : Type u} [CommSemiring R] -variable {A B : Type u} [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] +variable {R : Type*} [CommRing R] +variable {A B : Type*} [CommRing A] [Algebra R A] [CommRing B] [Algebra R B] /-- This holds in general for epimorphisms. -/ theorem of_surjective [FormallyUnramified R A] (f : A →ₐ[R] B) (H : Function.Surjective f) : FormallyUnramified R B := by - constructor + rw [iff_comp_injective] intro Q _ _ I hI f₁ f₂ e ext x obtain ⟨x, rfl⟩ := H x @@ -163,11 +213,10 @@ theorem of_surjective [FormallyUnramified R A] (f : A →ₐ[R] B) (H : Function instance quotient {A} [CommRing A] [Algebra R A] [FormallyUnramified R A] (I : Ideal A) : FormallyUnramified R (A ⧸ I) := - FormallyUnramified.of_surjective (IsScalarTower.toAlgHom _ _ _) Ideal.Quotient.mk_surjective + FormallyUnramified.of_surjective (IsScalarTower.toAlgHom R A (A ⧸ I)) Ideal.Quotient.mk_surjective -theorem of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) : - FormallyUnramified R B := - of_surjective e.toAlgHom e.surjective +theorem iff_of_equiv (e : A ≃ₐ[R] B) : FormallyUnramified R A ↔ FormallyUnramified R B := + ⟨fun _ ↦ of_equiv e, fun _ ↦ of_equiv e.symm⟩ end of_surjective @@ -175,13 +224,13 @@ section BaseChange open scoped TensorProduct -variable {R : Type u} [CommSemiring R] -variable {A : Type u} [Semiring A] [Algebra R A] -variable (B : Type u) [CommSemiring B] [Algebra R B] +variable {R : Type*} [CommRing R] +variable {A : Type*} [CommRing A] [Algebra R A] +variable (B : Type*) [CommRing B] [Algebra R B] instance base_change [FormallyUnramified R A] : FormallyUnramified B (B ⊗[R] A) := by - constructor + rw [iff_comp_injective] intro C _ _ I hI f₁ f₂ e letI := ((algebraMap B C).comp (algebraMap R B)).toAlgebra haveI : IsScalarTower R B C := IsScalarTower.of_algebraMap_eq' rfl @@ -193,7 +242,7 @@ end BaseChange section Localization -variable {R S Rₘ Sₘ : Type u} [CommRing R] [CommRing S] [CommRing Rₘ] [CommRing Sₘ] +variable {R S Rₘ Sₘ : Type*} [CommRing R] [CommRing S] [CommRing Rₘ] [CommRing Sₘ] variable (M : Submonoid R) variable [Algebra R S] [Algebra R Sₘ] [Algebra S Sₘ] [Algebra R Rₘ] [Algebra Rₘ Sₘ] variable [IsScalarTower R Rₘ Sₘ] [IsScalarTower R S Sₘ] @@ -205,7 +254,7 @@ include M /-- This holds in general for epimorphisms. -/ theorem of_isLocalization [IsLocalization M Rₘ] : FormallyUnramified R Rₘ := by - constructor + rw [iff_comp_injective] intro Q _ _ I _ f₁ f₂ _ apply AlgHom.coe_ringHom_injective refine IsLocalization.ringHom_ext M ?_ @@ -236,8 +285,8 @@ end FormallyUnramified section -variable (R : Type u) [CommSemiring R] -variable (A : Type u) [Semiring A] [Algebra R A] +variable (R : Type*) [CommRing R] +variable (A : Type*) [CommRing A] [Algebra R A] /-- An `R`-algebra `A` is unramified if it is formally unramified and of finite type. @@ -255,8 +304,8 @@ namespace Unramified attribute [instance] formallyUnramified finiteType -variable {R : Type u} [CommRing R] -variable {A B : Type u} [CommRing A] [Algebra R A] [CommRing B] [Algebra R B] +variable {R : Type*} [CommRing R] +variable {A B : Type*} [CommRing A] [Algebra R A] [CommRing B] [Algebra R B] /-- Being unramified is transported via algebra isomorphisms. -/ theorem of_equiv [Unramified R A] (e : A ≃ₐ[R] B) : Unramified R B where diff --git a/Mathlib/RingTheory/Unramified/Derivations.lean b/Mathlib/RingTheory/Unramified/Derivations.lean deleted file mode 100644 index 76feabb3ef6be..0000000000000 --- a/Mathlib/RingTheory/Unramified/Derivations.lean +++ /dev/null @@ -1,48 +0,0 @@ -/- -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.Kaehler.Basic -import Mathlib.RingTheory.Unramified.Basic - -/-! - -# Differential properties of formally unramified algebras - -We show that `R`-algebra `A` is formally unramified iff the Kaehler differentials vanish. - --/ - -universe u - -namespace Algebra - -variable {R S : Type u} [CommRing R] [CommRing S] [Algebra R S] - -instance FormallyUnramified.subsingleton_kaehlerDifferential [FormallyUnramified R S] : - Subsingleton (Ω[S⁄R]) := by - rw [← not_nontrivial_iff_subsingleton] - intro h - obtain ⟨f₁, f₂, e⟩ := (KaehlerDifferential.endEquiv R S).injective.nontrivial - apply e - ext1 - apply FormallyUnramified.lift_unique' _ _ _ _ (f₁.2.trans f₂.2.symm) - rw [← AlgHom.toRingHom_eq_coe, AlgHom.ker_kerSquareLift] - exact ⟨_, Ideal.cotangentIdeal_square _⟩ - -theorem FormallyUnramified.iff_subsingleton_kaehlerDifferential : - FormallyUnramified R S ↔ Subsingleton (Ω[S⁄R]) := by - constructor - · intros; infer_instance - · intro H - constructor - intro B _ _ I hI f₁ f₂ e - letI := f₁.toRingHom.toAlgebra - haveI := IsScalarTower.of_algebraMap_eq' f₁.comp_algebraMap.symm - have := - ((KaehlerDifferential.linearMapEquivDerivation R S).toEquiv.trans - (derivationToSquareZeroEquivLift I hI)).surjective.subsingleton - exact Subtype.ext_iff.mp (@Subsingleton.elim _ this ⟨f₁, rfl⟩ ⟨f₂, e.symm⟩) - -end Algebra diff --git a/Mathlib/RingTheory/Unramified/Field.lean b/Mathlib/RingTheory/Unramified/Field.lean index 3a0152d738c1c..b2faae3e80dec 100644 --- a/Mathlib/RingTheory/Unramified/Field.lean +++ b/Mathlib/RingTheory/Unramified/Field.lean @@ -40,7 +40,7 @@ open scoped TensorProduct namespace Algebra.FormallyUnramified theorem of_isSeparable [Algebra.IsSeparable K L] : FormallyUnramified K L := by - constructor + rw [iff_comp_injective] intros B _ _ I hI f₁ f₂ e ext x have : f₁ x - f₂ x ∈ I := by @@ -206,7 +206,7 @@ theorem isSeparable : Algebra.IsSeparable K L := by rw [← range_eq_top_of_isPurelyInseparable (separableClosure K L) L] simp -theorem iff_isSeparable (L) [Field L] [Algebra K L] [EssFiniteType K L] : +theorem iff_isSeparable (L : Type u) [Field L] [Algebra K L] [EssFiniteType K L] : FormallyUnramified K L ↔ Algebra.IsSeparable K L := ⟨fun _ ↦ isSeparable K L, fun _ ↦ of_isSeparable K L⟩ diff --git a/Mathlib/RingTheory/Unramified/Finite.lean b/Mathlib/RingTheory/Unramified/Finite.lean index 8652ea0e4337f..59c67331b55c7 100644 --- a/Mathlib/RingTheory/Unramified/Finite.lean +++ b/Mathlib/RingTheory/Unramified/Finite.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.RingTheory.Ideal.IdempotentFG -import Mathlib.RingTheory.Unramified.Derivations +import Mathlib.RingTheory.Unramified.Basic import Mathlib.RingTheory.Flat.Stability /-! @@ -48,7 +48,7 @@ A finite-type `R`-algebra `S` is (formally) unramified iff there exists a `t : S theorem iff_exists_tensorProduct [EssFiniteType R S] : FormallyUnramified R S ↔ ∃ t : S ⊗[R] S, (∀ s, ((1 : S) ⊗ₜ[R] s - s ⊗ₜ[R] (1 : S)) * t = 0) ∧ TensorProduct.lmul' R t = 1 := by - rw [iff_subsingleton_kaehlerDifferential, KaehlerDifferential, + rw [formallyUnramified_iff, KaehlerDifferential, Ideal.cotangent_subsingleton_iff, Ideal.isIdempotentElem_iff_of_fg _ (KaehlerDifferential.ideal_fg R S)] have : ∀ t : S ⊗[R] S, TensorProduct.lmul' R t = 1 ↔ 1 - t ∈ KaehlerDifferential.ideal R S := by diff --git a/Mathlib/RingTheory/Unramified/Pi.lean b/Mathlib/RingTheory/Unramified/Pi.lean index dc1d2ec8c816b..755c16a601f58 100644 --- a/Mathlib/RingTheory/Unramified/Pi.lean +++ b/Mathlib/RingTheory/Unramified/Pi.lean @@ -31,7 +31,7 @@ theorem pi_iff : · intro _ i exact FormallyUnramified.of_surjective (Pi.evalAlgHom R f i) (Function.surjective_eval i) · intro H - constructor + rw [iff_comp_injective] intros B _ _ J hJ f₁ f₂ e ext g rw [← Finset.univ_sum_single g, map_sum, map_sum] diff --git a/Mathlib/RingTheory/Valuation/Basic.lean b/Mathlib/RingTheory/Valuation/Basic.lean index 83c9f045e79f8..54e29458ccc66 100644 --- a/Mathlib/RingTheory/Valuation/Basic.lean +++ b/Mathlib/RingTheory/Valuation/Basic.lean @@ -141,15 +141,12 @@ variable (v : Valuation R Γ₀) {x y z : R} @[simp, norm_cast] theorem coe_coe : ⇑(v : R →*₀ Γ₀) = v := rfl --- @[simp] Porting note (#10618): simp can prove this theorem map_zero : v 0 = 0 := v.map_zero' --- @[simp] Porting note (#10618): simp can prove this theorem map_one : v 1 = 1 := v.map_one' --- @[simp] Porting note (#10618): simp can prove this theorem map_mul : ∀ x y, v (x * y) = v x * v y := v.map_mul' @@ -189,7 +186,6 @@ theorem map_sum_lt' {ι : Type*} {s : Finset ι} {f : ι → R} {g : Γ₀} (hg (hf : ∀ i ∈ s, v (f i) < g) : v (∑ i ∈ s, f i) < g := v.map_sum_lt (ne_of_gt hg) hf --- @[simp] Porting note (#10618): simp can prove this theorem map_pow : ∀ (x) (n : ℕ), v (x ^ n) = v x ^ n := v.toMonoidWithZeroHom.toMonoidHom.map_pow @@ -200,13 +196,15 @@ def toPreorder : Preorder R := Preorder.lift v /-- If `v` is a valuation on a division ring then `v(x) = 0` iff `x = 0`. -/ --- @[simp] Porting note (#10618): simp can prove this theorem zero_iff [Nontrivial Γ₀] (v : Valuation K Γ₀) {x : K} : v x = 0 ↔ x = 0 := map_eq_zero v theorem ne_zero_iff [Nontrivial Γ₀] (v : Valuation K Γ₀) {x : K} : v x ≠ 0 ↔ x ≠ 0 := map_ne_zero v +lemma pos_iff [Nontrivial Γ₀] (v : Valuation K Γ₀) {x : K} : 0 < v x ↔ x ≠ 0 := by + rw [zero_lt_iff, ne_zero_iff] + theorem unit_map_eq (u : Rˣ) : (Units.map (v : R →* Γ₀) u : Γ₀) = v u := rfl @@ -322,17 +320,16 @@ theorem map_one_sub_of_lt (h : v x < 1) : v (1 - x) = 1 := by simpa only [v.map_one, v.map_neg] using v.map_add_eq_of_lt_left h theorem one_lt_val_iff (v : Valuation K Γ₀) {x : K} (h : x ≠ 0) : 1 < v x ↔ v x⁻¹ < 1 := by - simpa using (inv_lt_inv₀ (v.ne_zero_iff.2 h) one_ne_zero).symm + simp [inv_lt_one₀ (v.pos_iff.2 h)] theorem one_le_val_iff (v : Valuation K Γ₀) {x : K} (h : x ≠ 0) : 1 ≤ v x ↔ v x⁻¹ ≤ 1 := by - convert (one_lt_val_iff v (inv_ne_zero h)).symm.not <;> - push_neg <;> simp only [inv_inv] + simp [inv_le_one₀ (v.pos_iff.2 h)] theorem val_lt_one_iff (v : Valuation K Γ₀) {x : K} (h : x ≠ 0) : v x < 1 ↔ 1 < v x⁻¹ := by - simpa only [inv_inv] using (one_lt_val_iff v (inv_ne_zero h)).symm + simp [one_lt_inv₀ (v.pos_iff.2 h)] theorem val_le_one_iff (v : Valuation K Γ₀) {x : K} (h : x ≠ 0) : v x ≤ 1 ↔ 1 ≤ v x⁻¹ := by - simpa [inv_inv] using (one_le_val_iff v (inv_ne_zero h)).symm + simp [one_le_inv₀ (v.pos_iff.2 h)] theorem val_eq_one_iff (v : Valuation K Γ₀) {x : K} : v x = 1 ↔ v x⁻¹ = 1 := by by_cases h : x = 0 diff --git a/Mathlib/RingTheory/Valuation/Integral.lean b/Mathlib/RingTheory/Valuation/Integral.lean index 35bd2ff83d00d..c8e1a11e3d970 100644 --- a/Mathlib/RingTheory/Valuation/Integral.lean +++ b/Mathlib/RingTheory/Valuation/Integral.lean @@ -38,7 +38,7 @@ theorem mem_of_integral {x : R} (hx : IsIntegral O x) : x ∈ v.integer := one_mul (v x ^ p.natDegree)] cases' (hv.2 <| p.coeff i).lt_or_eq with hvpi hvpi · exact mul_lt_mul₀ hvpi (pow_lt_pow_right₀ hvx <| Finset.mem_range.1 hi) - · erw [hvpi]; rw [one_mul, one_mul]; exact pow_lt_pow_right₀ hvx (Finset.mem_range.1 hi) + · rw [hvpi, one_mul, one_mul]; exact pow_lt_pow_right₀ hvx (Finset.mem_range.1 hi) protected theorem integralClosure : integralClosure O R = ⊥ := bot_unique fun _ hr => diff --git a/Mathlib/RingTheory/Valuation/PrimeMultiplicity.lean b/Mathlib/RingTheory/Valuation/PrimeMultiplicity.lean index 53376819d6002..835372b91040e 100644 --- a/Mathlib/RingTheory/Valuation/PrimeMultiplicity.lean +++ b/Mathlib/RingTheory/Valuation/PrimeMultiplicity.lean @@ -10,14 +10,14 @@ import Mathlib.RingTheory.Valuation.Basic # `multiplicity` of a prime in an integral domain as an additive valuation -/ -variable {R : Type*} [CommRing R] [IsDomain R] {p : R} [DecidableRel (Dvd.dvd : R → R → Prop)] +variable {R : Type*} [CommRing R] [IsDomain R] {p : R} -/-- `multiplicity` of a prime in an integral domain as an additive valuation to `PartENat`. -/ -noncomputable def multiplicity.addValuation (hp : Prime p) : AddValuation R PartENat := - AddValuation.of (multiplicity p) (multiplicity.zero _) (one_right hp.not_unit) - (fun _ _ => min_le_multiplicity_add) fun _ _ => multiplicity.mul hp +/-- `multiplicity` of a prime in an integral domain as an additive valuation to `ℕ∞`. -/ +noncomputable def multiplicity_addValuation (hp : Prime p) : AddValuation R ℕ∞ := + AddValuation.of (emultiplicity p) (emultiplicity_zero _) (emultiplicity_of_one_right hp.not_unit) + (fun _ _ => min_le_emultiplicity_add) fun _ _ => emultiplicity_mul hp @[simp] -theorem multiplicity.addValuation_apply {hp : Prime p} {r : R} : - addValuation hp r = multiplicity p r := +theorem multiplicity_addValuation_apply {hp : Prime p} {r : R} : + multiplicity_addValuation hp r = emultiplicity p r := rfl diff --git a/Mathlib/RingTheory/Valuation/Quotient.lean b/Mathlib/RingTheory/Valuation/Quotient.lean index c246dfce6f64c..a39ad50baf226 100644 --- a/Mathlib/RingTheory/Valuation/Quotient.lean +++ b/Mathlib/RingTheory/Valuation/Quotient.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kevin Buzzard, Johan Commelin, Patrick Massot -/ +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Valuation.Basic -import Mathlib.RingTheory.Ideal.QuotientOperations /-! # The valuation on a quotient ring diff --git a/Mathlib/RingTheory/Valuation/RankOne.lean b/Mathlib/RingTheory/Valuation/RankOne.lean index f052ac9fa18e6..1180c6e8cae8c 100644 --- a/Mathlib/RingTheory/Valuation/RankOne.lean +++ b/Mathlib/RingTheory/Valuation/RankOne.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 María Inés de Frutos-Fernández. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: María Inés de Frutos-Fernández -/ -import Mathlib.Data.NNReal.Basic +import Mathlib.Data.NNReal.Defs import Mathlib.RingTheory.Valuation.Basic /-! diff --git a/Mathlib/RingTheory/Valuation/ValExtension.lean b/Mathlib/RingTheory/Valuation/ValExtension.lean index 888369fc04bb9..11ee048743d9c 100644 --- a/Mathlib/RingTheory/Valuation/ValExtension.lean +++ b/Mathlib/RingTheory/Valuation/ValExtension.lean @@ -4,8 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jiedong Jiang, Bichang Lei -/ import Mathlib.RingTheory.Valuation.Integers -import Mathlib.RingTheory.LocalRing.RingHom.Basic -import Mathlib.RingTheory.LocalRing.RingHom.Defs +import Mathlib.Algebra.Group.Units.Hom /-! # Extension of Valuation @@ -53,7 +52,7 @@ variable {R A ΓR ΓA : Type*} [CommRing R] [Ring A] /-- The class `IsValExtension R A` states that the valuation of `A` is an extension of the valuation -on `R`. More precisely, the valuation on `R` is equivlent to the comap of the valuation on `A`. +on `R`. More precisely, the valuation on `R` is equivalent to the comap of the valuation on `A`. -/ class IsValExtension : Prop where /-- The valuation on `R` is equivalent to the comap of the valuation on `A` -/ @@ -144,16 +143,20 @@ theorem algebraMap_injective [IsValExtension vK vA] [Nontrivial A] : ext apply RingHom.injective (algebraMap K A) h -instance instIsLocalRingHomValuationInteger {S ΓS: Type*} [CommRing S] +@[instance] +theorem instIsLocalHomValuationInteger {S ΓS: Type*} [CommRing S] [LinearOrderedCommGroupWithZero ΓS] - [Algebra R S] [IsLocalRingHom (algebraMap R S)] {vS : Valuation S ΓS} - [IsValExtension vR vS] : IsLocalRingHom (algebraMap vR.integer vS.integer) where + [Algebra R S] [IsLocalHom (algebraMap R S)] {vS : Valuation S ΓS} + [IsValExtension vR vS] : IsLocalHom (algebraMap vR.integer vS.integer) where map_nonunit r hr := by apply (Valuation.integer.integers (v := vR)).isUnit_of_one · exact (isUnit_map_iff (algebraMap R S) _).mp (hr.map (algebraMap _ S)) · apply (Valuation.integer.integers (v := vS)).one_of_isUnit at hr exact (val_map_eq_one_iff vR vS _).mp hr +@[deprecated (since := "2024-10-10")] +alias instIsLocalRingHomValuationInteger := instIsLocalHomValuationInteger + end integer end IsValExtension diff --git a/Mathlib/RingTheory/Valuation/ValuationRing.lean b/Mathlib/RingTheory/Valuation/ValuationRing.lean index 864d73e5b39e6..266cd8e9d5884 100644 --- a/Mathlib/RingTheory/Valuation/ValuationRing.lean +++ b/Mathlib/RingTheory/Valuation/ValuationRing.lean @@ -142,22 +142,22 @@ noncomputable instance linearOrder : LinearOrder (ValueGroup A K) where noncomputable instance linearOrderedCommGroupWithZero : LinearOrderedCommGroupWithZero (ValueGroup A K) := { linearOrder .. with - mul_assoc := by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩; apply Quotient.sound'; rw [mul_assoc]; apply Setoid.refl' - one_mul := by rintro ⟨a⟩; apply Quotient.sound'; rw [one_mul]; apply Setoid.refl' - mul_one := by rintro ⟨a⟩; apply Quotient.sound'; rw [mul_one]; apply Setoid.refl' - mul_comm := by rintro ⟨a⟩ ⟨b⟩; apply Quotient.sound'; rw [mul_comm]; apply Setoid.refl' + mul_assoc := by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩; apply Quotient.sound'; rw [mul_assoc] + one_mul := by rintro ⟨a⟩; apply Quotient.sound'; rw [one_mul] + mul_one := by rintro ⟨a⟩; apply Quotient.sound'; rw [mul_one] + mul_comm := by rintro ⟨a⟩ ⟨b⟩; apply Quotient.sound'; rw [mul_comm] mul_le_mul_left := by rintro ⟨a⟩ ⟨b⟩ ⟨c, rfl⟩ ⟨d⟩ use c; simp only [Algebra.smul_def]; ring - zero_mul := by rintro ⟨a⟩; apply Quotient.sound'; rw [zero_mul]; apply Setoid.refl' - mul_zero := by rintro ⟨a⟩; apply Quotient.sound'; rw [mul_zero]; apply Setoid.refl' + zero_mul := by rintro ⟨a⟩; apply Quotient.sound'; rw [zero_mul] + mul_zero := by rintro ⟨a⟩; apply Quotient.sound'; rw [mul_zero] zero_le_one := ⟨0, by rw [zero_smul]⟩ exists_pair_ne := by use 0, 1 intro c; obtain ⟨d, hd⟩ := Quotient.exact' c apply_fun fun t => d⁻¹ • t at hd simp only [inv_smul_smul, smul_zero, one_ne_zero] at hd - inv_zero := by apply Quotient.sound'; rw [inv_zero]; apply Setoid.refl' + inv_zero := by apply Quotient.sound'; rw [inv_zero] mul_inv_cancel := by rintro ⟨a⟩ ha apply Quotient.sound' @@ -335,8 +335,8 @@ instance (priority := 100) [ValuationRing R] : IsBezout R := by intro x y rw [Ideal.span_insert] rcases le_total (Ideal.span {x} : Ideal R) (Ideal.span {y}) with h | h - · erw [sup_eq_right.mpr h]; exact ⟨⟨_, rfl⟩⟩ - · erw [sup_eq_left.mpr h]; exact ⟨⟨_, rfl⟩⟩ + · rw [sup_eq_right.mpr h]; exact ⟨⟨_, rfl⟩⟩ + · rw [sup_eq_left.mpr h]; exact ⟨⟨_, rfl⟩⟩ instance (priority := 100) [LocalRing R] [IsBezout R] : ValuationRing R := by classical diff --git a/Mathlib/RingTheory/Valuation/ValuationSubring.lean b/Mathlib/RingTheory/Valuation/ValuationSubring.lean index 066bed0604120..d6d738435853c 100644 --- a/Mathlib/RingTheory/Valuation/ValuationSubring.lean +++ b/Mathlib/RingTheory/Valuation/ValuationSubring.lean @@ -227,7 +227,7 @@ def subtype (R : ValuationSubring K) : R →+* K := /-- The canonical map on value groups induced by a coarsening of valuation rings. -/ def mapOfLE (R S : ValuationSubring K) (h : R ≤ S) : R.ValueGroup →*₀ S.ValueGroup where - toFun := Quotient.map' id fun x y ⟨u, hu⟩ => ⟨Units.map (R.inclusion S h).toMonoidHom u, hu⟩ + toFun := Quotient.map' id fun _ _ ⟨u, hu⟩ => ⟨Units.map (R.inclusion S h).toMonoidHom u, hu⟩ map_zero' := rfl map_one' := rfl map_mul' := by rintro ⟨⟩ ⟨⟩; rfl @@ -300,9 +300,8 @@ theorem ofPrime_idealOfLE (R S : ValuationSubring K) (h : R ≤ S) : · rintro ⟨a, r, hr, rfl⟩; apply mul_mem; · exact h a.2 · rw [← valuation_le_one_iff, map_inv₀, ← inv_one, inv_le_inv₀] · exact not_lt.1 ((not_iff_not.2 <| valuation_lt_one_iff S _).1 hr) - · intro hh; erw [Valuation.zero_iff, Subring.coe_eq_zero_iff] at hh - apply hr; rw [hh]; apply Ideal.zero_mem (R.idealOfLE S h) - · exact one_ne_zero + · simpa [Valuation.pos_iff] using fun hr₀ ↦ hr₀ ▸ hr <| Ideal.zero_mem (R.idealOfLE S h) + · exact zero_lt_one · intro hx; by_cases hr : x ∈ R; · exact R.le_ofPrime _ hr have : x ≠ 0 := fun h => hr (by rw [h]; exact R.zero_mem) replace hr := (R.mem_or_inv_mem x).resolve_left hr @@ -350,7 +349,7 @@ def primeSpectrumOrderEquiv : (PrimeSpectrum A)ᵒᵈ ≃o {S // A ≤ S} := instance linearOrderOverring : LinearOrder {S // A ≤ S} := { (inferInstance : PartialOrder _) with le_total := - let i : IsTotal (PrimeSpectrum A) (· ≤ ·) := ⟨fun ⟨x, _⟩ ⟨y, _⟩ => LE.isTotal.total x y⟩ + let _ : IsTotal (PrimeSpectrum A) (· ≤ ·) := ⟨fun ⟨x, _⟩ ⟨y, _⟩ => LE.isTotal.total x y⟩ (primeSpectrumOrderEquiv A).symm.toRelEmbedding.isTotal.total decidableLE := inferInstance } @@ -530,7 +529,7 @@ theorem mem_nonunits_iff_exists_mem_maximalIdeal {a : K} : theorem image_maximalIdeal : ((↑) : A → K) '' LocalRing.maximalIdeal A = A.nonunits := by ext a simp only [Set.mem_image, SetLike.mem_coe, mem_nonunits_iff_exists_mem_maximalIdeal] - erw [Subtype.exists] + rw [Subtype.exists] simp_rw [exists_and_right, exists_eq_right] end nonunits @@ -614,7 +613,7 @@ def principalUnitGroupEquiv : rw [A.coe_mem_principalUnitGroup_iff]; simp⟩ left_inv x := by simp right_inv x := by simp - map_mul' x y := rfl + map_mul' _ _ := rfl theorem principalUnitGroupEquiv_apply (a : A.principalUnitGroup) : (((principalUnitGroupEquiv A a : Aˣ) : A) : K) = (a : Kˣ) := @@ -647,7 +646,7 @@ theorem ker_unitGroupToResidueFieldUnits : theorem surjective_unitGroupToResidueFieldUnits : Function.Surjective A.unitGroupToResidueFieldUnits := (LocalRing.surjective_units_map_of_local_ringHom _ Ideal.Quotient.mk_surjective - LocalRing.isLocalRingHom_residue).comp + LocalRing.isLocalHom_residue).comp (MulEquiv.surjective _) /-- The quotient of the unit group of `A` by the principal unit group of `A` agrees with diff --git a/Mathlib/RingTheory/WittVector/Basic.lean b/Mathlib/RingTheory/WittVector/Basic.lean index 5630d6a00254e..e2c5bfed3057c 100644 --- a/Mathlib/RingTheory/WittVector/Basic.lean +++ b/Mathlib/RingTheory/WittVector/Basic.lean @@ -49,7 +49,7 @@ noncomputable section open MvPolynomial Function -variable {p : ℕ} {R S T : Type*} [CommRing R] [CommRing S] [CommRing T] +variable {p : ℕ} {R S : Type*} [CommRing R] [CommRing S] variable {α : Type*} {β : Type*} local notation "𝕎" => WittVector p diff --git a/Mathlib/RingTheory/WittVector/Defs.lean b/Mathlib/RingTheory/WittVector/Defs.lean index 53b4f06f4f2d8..859c75ad0e563 100644 --- a/Mathlib/RingTheory/WittVector/Defs.lean +++ b/Mathlib/RingTheory/WittVector/Defs.lean @@ -72,7 +72,7 @@ theorem ext {x y : 𝕎 R} (h : ∀ n, x.coeff n = y.coeff n) : x = y := by cases x cases y simp only at h - simp [Function.funext_iff, h] + simp [funext_iff, h] variable (p) @@ -156,8 +156,6 @@ evaluating this at `(x₀, x₁)` gives us the sum of two Witt vectors `x₀ + x def eval {k : ℕ} (φ : ℕ → MvPolynomial (Fin k × ℕ) ℤ) (x : Fin k → 𝕎 R) : 𝕎 R := mk p fun n => peval (φ n) fun i => (x i).coeff -variable (R) [Fact p.Prime] - instance : Zero (𝕎 R) := ⟨eval (wittZero p) ![]⟩ diff --git a/Mathlib/RingTheory/WittVector/Frobenius.lean b/Mathlib/RingTheory/WittVector/Frobenius.lean index 0d989e4ecdebe..91f21547ab839 100644 --- a/Mathlib/RingTheory/WittVector/Frobenius.lean +++ b/Mathlib/RingTheory/WittVector/Frobenius.lean @@ -48,7 +48,7 @@ and bundle it into `WittVector.frobenius`. namespace WittVector -variable {p : ℕ} {R S : Type*} [hp : Fact p.Prime] [CommRing R] [CommRing S] +variable {p : ℕ} {R : Type*} [hp : Fact p.Prime] [CommRing R] local notation "𝕎" => WittVector p -- type as `\bbW` @@ -70,12 +70,7 @@ theorem bind₁_frobeniusPolyRat_wittPolynomial (n : ℕ) : delta frobeniusPolyRat rw [← bind₁_bind₁, bind₁_xInTermsOfW_wittPolynomial, bind₁_X_right, Function.comp_apply] -/-- An auxiliary definition, to avoid an excessive amount of finiteness proofs -for `multiplicity p n`. -/ -private def pnat_multiplicity (n : ℕ+) : ℕ := - (multiplicity p n).get <| multiplicity.finite_nat_iff.mpr <| ⟨ne_of_gt hp.1.one_lt, n.2⟩ - -local notation "v" => pnat_multiplicity +local notation "v" => multiplicity /-- An auxiliary polynomial over the integers, that satisfies `p * (frobeniusPolyAux p n) + X n ^ p = frobeniusPoly p n`. @@ -86,16 +81,17 @@ noncomputable def frobeniusPolyAux : ℕ → MvPolynomial ℕ ℤ ∑ j ∈ range (p ^ (n - i)), (((X (i : ℕ) ^ p) ^ (p ^ (n - (i : ℕ)) - (j + 1)) : MvPolynomial ℕ ℤ) * (frobeniusPolyAux i) ^ (j + 1)) * - C (((p ^ (n - i)).choose (j + 1) / (p ^ (n - i - v p ⟨j + 1, Nat.succ_pos j⟩)) - * ↑p ^ (j - v p ⟨j + 1, Nat.succ_pos j⟩) : ℕ) : ℤ) + C (((p ^ (n - i)).choose (j + 1) / (p ^ (n - i - v p (j + 1))) + * ↑p ^ (j - v p (j + 1)) : ℕ) : ℤ) +omit hp in theorem frobeniusPolyAux_eq (n : ℕ) : frobeniusPolyAux p n = X (n + 1) - ∑ i ∈ range n, ∑ j ∈ range (p ^ (n - i)), (X i ^ p) ^ (p ^ (n - i) - (j + 1)) * frobeniusPolyAux p i ^ (j + 1) * - C ↑((p ^ (n - i)).choose (j + 1) / p ^ (n - i - v p ⟨j + 1, Nat.succ_pos j⟩) * - ↑p ^ (j - v p ⟨j + 1, Nat.succ_pos j⟩) : ℕ) := by + C ↑((p ^ (n - i)).choose (j + 1) / p ^ (n - i - v p (j + 1)) * + ↑p ^ (j - v p (j + 1)) : ℕ) := by rw [frobeniusPolyAux, ← Fin.sum_univ_eq_sum_range] /-- The polynomials that give the coefficients of `frobenius x`, @@ -114,20 +110,19 @@ and then using the following two key facts at the right point. -/ /-- A key divisibility fact for the proof of `WittVector.map_frobeniusPoly`. -/ theorem map_frobeniusPoly.key₁ (n j : ℕ) (hj : j < p ^ n) : - p ^ (n - v p ⟨j + 1, j.succ_pos⟩) ∣ (p ^ n).choose (j + 1) := by - apply multiplicity.pow_dvd_of_le_multiplicity - rw [hp.out.multiplicity_choose_prime_pow hj j.succ_ne_zero] - rfl + p ^ (n - v p (j + 1)) ∣ (p ^ n).choose (j + 1) := by + apply pow_dvd_of_le_emultiplicity + rw [hp.out.emultiplicity_choose_prime_pow hj j.succ_ne_zero] /-- A key numerical identity needed for the proof of `WittVector.map_frobeniusPoly`. -/ theorem map_frobeniusPoly.key₂ {n i j : ℕ} (hi : i ≤ n) (hj : j < p ^ (n - i)) : - j - v p ⟨j + 1, j.succ_pos⟩ + n = i + j + (n - i - v p ⟨j + 1, j.succ_pos⟩) := by - generalize h : v p ⟨j + 1, j.succ_pos⟩ = m + j - v p (j + 1) + n = i + j + (n - i - v p (j + 1)) := by + generalize h : v p (j + 1) = m rsuffices ⟨h₁, h₂⟩ : m ≤ n - i ∧ m ≤ j · rw [tsub_add_eq_add_tsub h₂, add_comm i j, add_tsub_assoc_of_le (h₁.trans (Nat.sub_le n i)), add_assoc, tsub_right_comm, add_comm i, tsub_add_cancel_of_le (le_tsub_of_add_le_right ((le_tsub_iff_left hi).mp h₁))] - have hle : p ^ m ≤ j + 1 := h ▸ Nat.le_of_dvd j.succ_pos (multiplicity.pow_multiplicity_dvd _) + have hle : p ^ m ≤ j + 1 := h ▸ Nat.le_of_dvd j.succ_pos (pow_multiplicity_dvd _ _) exact ⟨(pow_le_pow_iff_right hp.1.one_lt).1 (hle.trans hj), Nat.le_of_lt_succ ((Nat.lt_pow_self hp.1.one_lt m).trans_le hle)⟩ @@ -173,9 +168,9 @@ theorem map_frobeniusPoly (n : ℕ) : rw [Rat.natCast_div _ _ (map_frobeniusPoly.key₁ p (n - i) j hj)] simp only [Nat.cast_pow, pow_add, pow_one] suffices - (((p ^ (n - i)).choose (j + 1) : ℚ) * (p : ℚ) ^ (j - v p ⟨j + 1, j.succ_pos⟩) * p * (p ^ n : ℚ)) + (((p ^ (n - i)).choose (j + 1) : ℚ) * (p : ℚ) ^ (j - v p (j + 1)) * p * (p ^ n : ℚ)) = (p : ℚ) ^ j * p * ↑((p ^ (n - i)).choose (j + 1) * p ^ i) * - (p : ℚ) ^ (n - i - v p ⟨j + 1, j.succ_pos⟩) by + (p : ℚ) ^ (n - i - v p (j + 1)) by have aux : ∀ k : ℕ, (p : ℚ)^ k ≠ 0 := by intro; apply pow_ne_zero; exact mod_cast hp.1.ne_zero simpa [aux, -one_div, -pow_eq_zero_iff', field_simps] using this.symm @@ -202,6 +197,7 @@ variable {p} def frobeniusFun (x : 𝕎 R) : 𝕎 R := mk p fun n => MvPolynomial.aeval x.coeff (frobeniusPoly p n) +omit hp in theorem coeff_frobeniusFun (x : 𝕎 R) (n : ℕ) : coeff (frobeniusFun x) n = MvPolynomial.aeval x.coeff (frobeniusPoly p n) := by rw [frobeniusFun, coeff_mk] @@ -212,7 +208,7 @@ variable (p) See also `frobenius_isPoly`. -/ -- Porting note: replaced `@[is_poly]` with `instance`. -instance frobeniusFun_isPoly : IsPoly p fun R _Rcr => @frobeniusFun p R _ _Rcr := +instance frobeniusFun_isPoly : IsPoly p fun R _ Rcr => @frobeniusFun p R _ Rcr := ⟨⟨frobeniusPoly p, by intros; funext n; apply coeff_frobeniusFun⟩⟩ variable {p} @@ -246,8 +242,8 @@ def frobenius : 𝕎 R →+* 𝕎 R where (@IsPoly.comp p _ _ WittVector.oneIsPoly (frobeniusFun_isPoly p)) ?_ _ 0 simp only [Function.comp_apply, map_one, forall_const] ghost_simp - map_add' := by ghost_calc _ _; ghost_simp - map_mul' := by ghost_calc _ _; ghost_simp + map_add' := by dsimp only; ghost_calc _ _; ghost_simp + map_mul' := by dsimp only; ghost_calc _ _; ghost_simp theorem coeff_frobenius (x : 𝕎 R) (n : ℕ) : coeff (frobenius x) n = MvPolynomial.aeval x.coeff (frobeniusPoly p n) := diff --git a/Mathlib/RingTheory/WittVector/IsPoly.lean b/Mathlib/RingTheory/WittVector/IsPoly.lean index ef5430b614c18..87bd44d9849c4 100644 --- a/Mathlib/RingTheory/WittVector/IsPoly.lean +++ b/Mathlib/RingTheory/WittVector/IsPoly.lean @@ -92,7 +92,7 @@ namespace WittVector universe u -variable {p : ℕ} {R S : Type u} {σ idx : Type*} [CommRing R] [CommRing S] +variable {p : ℕ} {R S : Type u} {idx : Type*} [CommRing R] [CommRing S] local notation "𝕎" => WittVector p -- type as `\bbW` @@ -113,7 +113,7 @@ theorem poly_eq_of_wittPolynomial_bind_eq' [Fact p.Prime] (f g : ℕ → MvPolyn (h : ∀ n, bind₁ f (wittPolynomial p _ n) = bind₁ g (wittPolynomial p _ n)) : f = g := by ext1 n apply MvPolynomial.map_injective (Int.castRingHom ℚ) Int.cast_injective - rw [← Function.funext_iff] at h + rw [← funext_iff] at h replace h := congr_arg (fun fam => bind₁ (MvPolynomial.map (Int.castRingHom ℚ) ∘ fam) (xInTermsOfW p ℚ n)) h simpa only [Function.comp_def, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, @@ -123,7 +123,7 @@ theorem poly_eq_of_wittPolynomial_bind_eq [Fact p.Prime] (f g : ℕ → MvPolyno (h : ∀ n, bind₁ f (wittPolynomial p _ n) = bind₁ g (wittPolynomial p _ n)) : f = g := by ext1 n apply MvPolynomial.map_injective (Int.castRingHom ℚ) Int.cast_injective - rw [← Function.funext_iff] at h + rw [← funext_iff] at h replace h := congr_arg (fun fam => bind₁ (MvPolynomial.map (Int.castRingHom ℚ) ∘ fam) (xInTermsOfW p ℚ n)) h simpa only [Function.comp_def, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, @@ -220,7 +220,7 @@ variable {p} /-- The composition of polynomial functions is polynomial. -/ -- Porting note (#10754): made this an instance instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] : - IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by + IsPoly₂ p fun _ _Rcr x y => h (f x) (g y) := by obtain ⟨φ, hf⟩ := hf obtain ⟨ψ, hg⟩ := hg obtain ⟨χ, hh⟩ := hh @@ -238,7 +238,7 @@ instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsP /-- The composition of a polynomial function with a binary polynomial function is polynomial. -/ -- Porting note (#10754): made this an instance instance IsPoly.comp₂ {g f} [hg : IsPoly p g] [hf : IsPoly₂ p f] : - IsPoly₂ p fun R _Rcr x y => g (f x y) := by + IsPoly₂ p fun _ _Rcr x y => g (f x y) := by obtain ⟨φ, hf⟩ := hf obtain ⟨ψ, hg⟩ := hg use fun n => bind₁ φ (ψ n) @@ -247,7 +247,7 @@ instance IsPoly.comp₂ {g f} [hg : IsPoly p g] [hf : IsPoly₂ p f] : /-- The diagonal `fun x ↦ f x x` of a polynomial function `f` is polynomial. -/ -- Porting note (#10754): made this an instance -instance IsPoly₂.diag {f} [hf : IsPoly₂ p f] : IsPoly p fun R _Rcr x => f x x := by +instance IsPoly₂.diag {f} [hf : IsPoly₂ p f] : IsPoly p fun _ _Rcr x => f x x := by obtain ⟨φ, hf⟩ := hf refine ⟨⟨fun n => bind₁ (uncurry ![X, X]) (φ n), ?_⟩⟩ intros; funext n @@ -311,15 +311,11 @@ end ZeroOne /-- Addition of Witt vectors is a polynomial function. -/ -- Porting note: replaced `@[is_poly]` with `instance`. instance addIsPoly₂ [Fact p.Prime] : IsPoly₂ p fun _ _ => (· + ·) := - -- porting note: the proof was - -- `⟨⟨wittAdd p, by intros; dsimp only [WittVector.hasAdd]; simp [eval]⟩⟩` ⟨⟨wittAdd p, by intros; ext; exact add_coeff _ _ _⟩⟩ /-- Multiplication of Witt vectors is a polynomial function. -/ -- Porting note: replaced `@[is_poly]` with `instance`. instance mulIsPoly₂ [Fact p.Prime] : IsPoly₂ p fun _ _ => (· * ·) := - -- porting note: the proof was - -- `⟨⟨wittMul p, by intros; dsimp only [WittVector.hasMul]; simp [eval]⟩⟩` ⟨⟨wittMul p, by intros; ext; exact mul_coeff _ _ _⟩⟩ -- unfortunately this is not universe polymorphic, merely because `f` isn't diff --git a/Mathlib/RingTheory/WittVector/MulP.lean b/Mathlib/RingTheory/WittVector/MulP.lean index 6cdf37a89f03d..099970cef0ee6 100644 --- a/Mathlib/RingTheory/WittVector/MulP.lean +++ b/Mathlib/RingTheory/WittVector/MulP.lean @@ -59,7 +59,7 @@ variable (p) /-- Multiplication by `n` is a polynomial function. -/ @[is_poly] -theorem mulN_isPoly (n : ℕ) : IsPoly p fun R _Rcr x => x * n := +theorem mulN_isPoly (n : ℕ) : IsPoly p fun _ _Rcr x => x * n := ⟨⟨wittMulN p n, fun R _Rcr x => by funext k; exact mulN_coeff n x k⟩⟩ @[simp] diff --git a/Mathlib/RingTheory/WittVector/Truncated.lean b/Mathlib/RingTheory/WittVector/Truncated.lean index ad0dab556c7ae..4fa06dc3e127b 100644 --- a/Mathlib/RingTheory/WittVector/Truncated.lean +++ b/Mathlib/RingTheory/WittVector/Truncated.lean @@ -482,7 +482,7 @@ def liftEquiv : { f : ∀ k, S →+* TruncatedWittVector p k R // ∀ (k₁ k₂ intro _ _ h simp only [← RingHom.comp_assoc, truncate_comp_wittVector_truncate]⟩ left_inv := by rintro ⟨f, hf⟩; simp only [truncate_comp_lift] - right_inv g := lift_unique _ _ fun _ => rfl + right_inv _ := lift_unique _ _ fun _ => rfl theorem hom_ext (g₁ g₂ : S →+* 𝕎 R) (h : ∀ k, (truncate k).comp g₁ = (truncate k).comp g₂) : g₁ = g₂ := diff --git a/Mathlib/SetTheory/Cardinal/Aleph.lean b/Mathlib/SetTheory/Cardinal/Aleph.lean new file mode 100644 index 0000000000000..78df9ea23c7e0 --- /dev/null +++ b/Mathlib/SetTheory/Cardinal/Aleph.lean @@ -0,0 +1,726 @@ +/- +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.Order.Bounded +import Mathlib.SetTheory.Cardinal.PartENat +import Mathlib.SetTheory.Ordinal.Enum + +/-! +# Omega, aleph, and beth functions + +* The function `Ordinal.preOmega` enumerates the initial ordinals, i.e. the smallest ordinals with + any given cardinality. Thus `preOmega n = n`, `preOmega ω = ω`, `preOmega (ω + 1) = ω₁`, etc. + `Ordinal.omega` is the more standard function which skips over finite ordinals. +* The function `Cardinal.preAleph` is an order isomorphism between ordinals and cardinals. Thus + `preAleph n = n`, `preAleph ω = ℵ₀`, `preAleph (ω + 1) = ℵ₁`, etc. `Cardinal.aleph` is the more + standard function which skips over finite ordinals. +* The function `Cardinal.beth` enumerates the Beth cardinals. `beth 0 = ℵ₀`, + `beth (succ o) = 2 ^ beth o`, and for a limit ordinal `o`, `beth o` is the supremum of `beth a` + for `a < o`. + +## Notation + +The following notations are scoped to the `Ordinal` namespace. + +- `ω_ o` is notation for `Ordinal.omega o`. `ω₁` is notation for `ω_ 1`. + +The following notations are scoped to the `Cardinal` namespace. + +- `ℵ_ o` is notation for `aleph o`. `ℵ₁` is notation for `ℵ_ 1`. +- `ℶ_ o` is notation for `beth o`. The value `ℶ_ 1` equals the continuum `𝔠`, which is defined in + `Mathlib.SetTheory.Cardinal.Continuum`. +-/ + +assert_not_exists Module +assert_not_exists Finsupp +assert_not_exists Cardinal.mul_eq_self + +noncomputable section + +open Function Set Cardinal Equiv Order Ordinal + +universe u v w + +/-! ### Omega ordinals -/ + +namespace Ordinal + +/-- An ordinal is initial when it is the first ordinal with a given cardinality. + +This is written as `o.card.ord = o`, i.e. `o` is the smallest ordinal with cardinality `o.card`. -/ +def IsInitial (o : Ordinal) : Prop := + o.card.ord = o + +theorem IsInitial.ord_card {o : Ordinal} (h : IsInitial o) : o.card.ord = o := h + +theorem IsInitial.card_le_card {a b : Ordinal} (ha : IsInitial a) : a.card ≤ b.card ↔ a ≤ b := by + refine ⟨fun h ↦ ?_, Ordinal.card_le_card⟩ + rw [← ord_le_ord, ha.ord_card] at h + exact h.trans (ord_card_le b) + +theorem IsInitial.card_lt_card {a b : Ordinal} (hb : IsInitial b) : a.card < b.card ↔ a < b := + lt_iff_lt_of_le_iff_le hb.card_le_card + +theorem isInitial_ord (c : Cardinal) : IsInitial c.ord := by + rw [IsInitial, card_ord] + +theorem isInitial_natCast (n : ℕ) : IsInitial n := by + rw [IsInitial, card_nat, ord_nat] + +theorem isInitial_zero : IsInitial 0 := by + exact_mod_cast isInitial_natCast 0 + +theorem isInitial_one : IsInitial 1 := by + exact_mod_cast isInitial_natCast 1 + +theorem isInitial_omega0 : IsInitial ω := by + rw [IsInitial, card_omega0, ord_aleph0] + +theorem not_bddAbove_isInitial : ¬ BddAbove {x | IsInitial x} := by + rintro ⟨a, ha⟩ + have := ha (isInitial_ord (succ a.card)) + rw [ord_le] at this + exact (lt_succ _).not_le this + +/-- Initial ordinals are order-isomorphic to the cardinals. -/ +@[simps!] +def isInitialIso : {x // IsInitial x} ≃o Cardinal where + toFun x := x.1.card + invFun x := ⟨x.ord, isInitial_ord _⟩ + left_inv x := Subtype.ext x.2.ord_card + right_inv x := card_ord x + map_rel_iff' {a _} := a.2.card_le_card + +/-- The "pre-omega" function gives the initial ordinals listed by their ordinal index. +`preOmega n = n`, `preOmega ω = ω`, `preOmega (ω + 1) = ω₁`, etc. + +For the more common omega function skipping over finite ordinals, see `Ordinal.omega`. -/ +def preOmega : Ordinal.{u} ↪o Ordinal.{u} where + toFun := enumOrd {x | IsInitial x} + inj' _ _ h := enumOrd_injective not_bddAbove_isInitial h + map_rel_iff' := enumOrd_le_enumOrd not_bddAbove_isInitial + +theorem coe_preOmega : preOmega = enumOrd {x | IsInitial x} := + rfl + +theorem preOmega_strictMono : StrictMono preOmega := + preOmega.strictMono + +theorem preOmega_lt_preOmega {o₁ o₂ : Ordinal} : preOmega o₁ < preOmega o₂ ↔ o₁ < o₂ := + preOmega.lt_iff_lt + +theorem preOmega_le_preOmega {o₁ o₂ : Ordinal} : preOmega o₁ ≤ preOmega o₂ ↔ o₁ ≤ o₂ := + preOmega.le_iff_le + +theorem preOmega_max (o₁ o₂ : Ordinal) : preOmega (max o₁ o₂) = max (preOmega o₁) (preOmega o₂) := + preOmega.monotone.map_max + +theorem isInitial_preOmega (o : Ordinal) : IsInitial (preOmega o) := + enumOrd_mem not_bddAbove_isInitial o + +theorem le_preOmega_self (o : Ordinal) : o ≤ preOmega o := + preOmega_strictMono.le_apply + +@[simp] +theorem preOmega_zero : preOmega 0 = 0 := by + rw [coe_preOmega, enumOrd_zero] + exact csInf_eq_bot_of_bot_mem isInitial_zero + +@[simp] +theorem preOmega_natCast (n : ℕ) : preOmega n = n := by + induction n with + | zero => exact preOmega_zero + | succ n IH => + apply (le_preOmega_self _).antisymm' + apply enumOrd_succ_le not_bddAbove_isInitial (isInitial_natCast _) (IH.trans_lt _) + rw [Nat.cast_lt] + exact lt_succ n + +-- See note [no_index around OfNat.ofNat] +@[simp] +theorem preOmega_ofNat (n : ℕ) [n.AtLeastTwo] : preOmega (no_index (OfNat.ofNat n)) = n := + preOmega_natCast n + +theorem preOmega_le_of_forall_lt {o a : Ordinal} (ha : IsInitial a) (H : ∀ b < o, preOmega b < a) : + preOmega o ≤ a := + enumOrd_le_of_forall_lt ha H + +theorem isNormal_preOmega : IsNormal preOmega := by + rw [isNormal_iff_strictMono_limit] + refine ⟨preOmega_strictMono, fun o ho a ha ↦ + (preOmega_le_of_forall_lt (isInitial_ord _) fun b hb ↦ ?_).trans (ord_card_le a)⟩ + rw [← (isInitial_ord _).card_lt_card, card_ord] + apply lt_of_lt_of_le _ (card_le_card <| ha _ (ho.succ_lt hb)) + rw [(isInitial_preOmega _).card_lt_card, preOmega_lt_preOmega] + exact lt_succ b + +@[simp] +theorem range_preOmega : range preOmega = {x | IsInitial x} := + range_enumOrd not_bddAbove_isInitial + +theorem mem_range_preOmega_iff {x : Ordinal} : x ∈ range preOmega ↔ IsInitial x := by + rw [range_preOmega, mem_setOf] + +alias ⟨_, IsInitial.mem_range_preOmega⟩ := mem_range_preOmega_iff + +@[simp] +theorem preOmega_omega0 : preOmega ω = ω := by + simp_rw [← isNormal_preOmega.apply_omega0, preOmega_natCast, iSup_natCast] + +@[simp] +theorem omega0_le_preOmega_iff {x : Ordinal} : ω ≤ preOmega x ↔ ω ≤ x := by + conv_lhs => rw [← preOmega_omega0, preOmega_le_preOmega] + +@[simp] +theorem omega0_lt_preOmega_iff {x : Ordinal} : ω < preOmega x ↔ ω < x := by + conv_lhs => rw [← preOmega_omega0, preOmega_lt_preOmega] + +/-- The `omega` function gives the infinite initial ordinals listed by their ordinal index. +`omega 0 = ω`, `omega 1 = ω₁` is the first uncountable ordinal, and so on. + +This is not to be confused with the first infinite ordinal `Ordinal.omega0`. + +For a version including finite ordinals, see `Ordinal.preOmega`. -/ +def omega : Ordinal ↪o Ordinal := + (OrderEmbedding.addLeft ω).trans preOmega + +@[inherit_doc] +scoped notation "ω_ " => omega + +/-- `ω₁` is the first uncountable ordinal. -/ +scoped notation "ω₁" => ω_ 1 + +theorem omega_eq_preOmega (o : Ordinal) : ω_ o = preOmega (ω + o) := + rfl + +theorem omega_strictMono : StrictMono omega := + omega.strictMono + +theorem omega_lt_omega {o₁ o₂ : Ordinal} : ω_ o₁ < ω_ o₂ ↔ o₁ < o₂ := + omega.lt_iff_lt + +theorem omega_le_omega {o₁ o₂ : Ordinal} : ω_ o₁ ≤ ω_ o₂ ↔ o₁ ≤ o₂ := + omega.le_iff_le + +theorem omega_max (o₁ o₂ : Ordinal) : ω_ (max o₁ o₂) = max (ω_ o₁) (ω_ o₂) := + omega.monotone.map_max + +theorem isInitial_omega (o : Ordinal) : IsInitial (omega o) := + isInitial_preOmega _ + +theorem le_omega_self (o : Ordinal) : o ≤ omega o := + omega_strictMono.le_apply + +@[simp] +theorem omega_zero : ω_ 0 = ω := by + rw [omega_eq_preOmega, add_zero, preOmega_omega0] + +theorem omega0_le_omega (o : Ordinal) : ω ≤ ω_ o := by + rw [← omega_zero, omega_le_omega] + exact Ordinal.zero_le o + +theorem omega0_lt_omega1 : ω < ω₁ := by + rw [← omega_zero, omega_lt_omega] + exact zero_lt_one + +@[deprecated omega0_lt_omega1 (since := "2024-10-11")] +alias omega_lt_omega1 := omega0_lt_omega1 + +theorem isNormal_omega : IsNormal omega := + isNormal_preOmega.trans (isNormal_add_right _) + +@[simp] +theorem range_omega : range omega = {x | ω ≤ x ∧ IsInitial x} := by + ext x + constructor + · rintro ⟨a, rfl⟩ + exact ⟨omega0_le_omega a, isInitial_omega a⟩ + · rintro ⟨ha', ha⟩ + obtain ⟨a, rfl⟩ := ha.mem_range_preOmega + use a - ω + rw [omega0_le_preOmega_iff] at ha' + rw [omega_eq_preOmega, Ordinal.add_sub_cancel_of_le ha'] + +theorem mem_range_omega_iff {x : Ordinal} : x ∈ range omega ↔ ω ≤ x ∧ IsInitial x := by + rw [range_omega, mem_setOf] + +end Ordinal + +/-! ### Aleph cardinals -/ + +namespace Cardinal + +/-- The "pre-aleph" function gives the cardinals listed by their ordinal index. `preAleph n = n`, +`preAleph ω = ℵ₀`, `preAleph (ω + 1) = succ ℵ₀`, etc. + +For the more common aleph function skipping over finite cardinals, see `Cardinal.aleph`. -/ +def preAleph : Ordinal.{u} ≃o Cardinal.{u} := by + let f := RelEmbedding.collapse Cardinal.ord.orderEmbedding.ltEmbedding.{u} + refine (OrderIso.ofRelIsoLT <| RelIso.ofSurjective f ?_).symm + apply f.eq_or_principal.resolve_right + rintro ⟨o, e⟩ + have : ∀ c, f c < o := fun c => (e _).1 ⟨_, rfl⟩ + refine Ordinal.inductionOn o ?_ this + intro α r _ h + let s := ⨆ a, invFun f (Ordinal.typein r a) + apply (lt_succ s).not_le + have I : Injective f := f.toEmbedding.injective + simpa only [typein_enum, leftInverse_invFun I (succ s)] using + le_ciSup + (Cardinal.bddAbove_range.{u, u} fun a : α => invFun f (Ordinal.typein r a)) + (Ordinal.enum r ⟨_, h (succ s)⟩) + +@[simp] +theorem type_cardinal : @type Cardinal (· < ·) _ = Ordinal.univ.{u, u + 1} := by + rw [Ordinal.univ_id] + exact Quotient.sound ⟨preAleph.symm.toRelIsoLT⟩ + +@[simp] +theorem mk_cardinal : #Cardinal = univ.{u, u + 1} := by + simpa only [card_type, card_univ] using congr_arg card type_cardinal + +theorem preAleph_lt_preAleph {o₁ o₂ : Ordinal} : preAleph o₁ < preAleph o₂ ↔ o₁ < o₂ := + preAleph.lt_iff_lt + +theorem preAleph_le_preAleph {o₁ o₂ : Ordinal} : preAleph o₁ ≤ preAleph o₂ ↔ o₁ ≤ o₂ := + preAleph.le_iff_le + +theorem preAleph_max (o₁ o₂ : Ordinal) : preAleph (max o₁ o₂) = max (preAleph o₁) (preAleph o₂) := + preAleph.monotone.map_max + +@[simp] +theorem preAleph_zero : preAleph 0 = 0 := + preAleph.map_bot + +@[simp] +theorem preAleph_succ (o : Ordinal) : preAleph (succ o) = succ (preAleph o) := + preAleph.map_succ o + +@[simp] +theorem preAleph_nat : ∀ n : ℕ, preAleph n = n + | 0 => preAleph_zero + | n + 1 => show preAleph (succ n) = n.succ by rw [preAleph_succ, preAleph_nat n, nat_succ] + +theorem preAleph_pos {o : Ordinal} : 0 < preAleph o ↔ 0 < o := by + rw [← preAleph_zero, preAleph_lt_preAleph] + +@[simp] +theorem lift_preAleph (o : Ordinal.{u}) : lift.{v} (preAleph o) = preAleph (Ordinal.lift.{v} o) := + ((InitialSeg.ofIso preAleph.toRelIsoLT).trans liftInitialSeg).eq + (Ordinal.liftInitialSeg.trans (InitialSeg.ofIso preAleph.toRelIsoLT)) o + +theorem preAleph_le_of_isLimit {o : Ordinal} (l : o.IsLimit) {c} : + preAleph o ≤ c ↔ ∀ o' < o, preAleph o' ≤ c := + ⟨fun h o' h' => (preAleph_le_preAleph.2 <| h'.le).trans h, fun h => by + rw [← preAleph.apply_symm_apply c, preAleph_le_preAleph, limit_le l] + intro x h' + rw [← preAleph_le_preAleph, preAleph.apply_symm_apply] + exact h _ h'⟩ + +theorem preAleph_limit {o : Ordinal} (ho : o.IsLimit) : preAleph o = ⨆ a : Iio o, preAleph a := by + refine le_antisymm ?_ (ciSup_le' fun i => preAleph_le_preAleph.2 i.2.le) + rw [preAleph_le_of_isLimit ho] + exact fun a ha => le_ciSup (bddAbove_of_small _) (⟨a, ha⟩ : Iio o) + +@[simp] +theorem preAleph_omega0 : preAleph ω = ℵ₀ := + eq_of_forall_ge_iff fun c => by + simp only [preAleph_le_of_isLimit isLimit_omega0, lt_omega0, exists_imp, aleph0_le] + exact forall_swap.trans (forall_congr' fun n => by simp only [forall_eq, preAleph_nat]) + +@[simp] +theorem aleph0_le_preAleph {o : Ordinal} : ℵ₀ ≤ preAleph o ↔ ω ≤ o := by + rw [← preAleph_omega0, preAleph_le_preAleph] + +/-- The `aleph` function gives the infinite cardinals listed by their ordinal index. `aleph 0 = ℵ₀`, +`aleph 1 = succ ℵ₀` is the first uncountable cardinal, and so on. + +For a version including finite cardinals, see `Cardinal.aleph'`. -/ +def aleph : Ordinal ↪o Cardinal := + (OrderEmbedding.addLeft ω).trans preAleph.toOrderEmbedding + +@[inherit_doc] +scoped notation "ℵ_ " => aleph + +/-- `ℵ₁` is the first uncountable cardinal. -/ +scoped notation "ℵ₁" => ℵ_ 1 + +theorem aleph_eq_preAleph (o : Ordinal) : ℵ_ o = preAleph (ω + o) := + rfl + +theorem aleph_lt_aleph {o₁ o₂ : Ordinal} : ℵ_ o₁ < ℵ_ o₂ ↔ o₁ < o₂ := + aleph.lt_iff_lt + +@[deprecated aleph_lt_aleph (since := "2024-10-22")] +alias aleph_lt := aleph_lt_aleph + +theorem aleph_le_aleph {o₁ o₂ : Ordinal} : ℵ_ o₁ ≤ ℵ_ o₂ ↔ o₁ ≤ o₂ := + aleph.le_iff_le + +@[deprecated aleph_le_aleph (since := "2024-10-22")] +alias aleph_le := aleph_le_aleph + +theorem aleph_max (o₁ o₂ : Ordinal) : ℵ_ (max o₁ o₂) = max (ℵ_ o₁) (ℵ_ o₂) := + aleph.monotone.map_max + +@[deprecated aleph_max (since := "2024-08-28")] +theorem max_aleph_eq (o₁ o₂ : Ordinal) : max (ℵ_ o₁) (ℵ_ o₂) = ℵ_ (max o₁ o₂) := + (aleph_max o₁ o₂).symm + +@[simp] +theorem aleph_succ (o : Ordinal) : ℵ_ (succ o) = succ (ℵ_ o) := by + rw [aleph_eq_preAleph, add_succ, preAleph_succ, aleph_eq_preAleph] + +@[simp] +theorem aleph_zero : ℵ_ 0 = ℵ₀ := by rw [aleph_eq_preAleph, add_zero, preAleph_omega0] + +@[simp] +theorem lift_aleph (o : Ordinal.{u}) : lift.{v} (aleph o) = aleph (Ordinal.lift.{v} o) := by + simp [aleph_eq_preAleph] + +theorem aleph_limit {o : Ordinal} (ho : o.IsLimit) : ℵ_ o = ⨆ a : Iio o, ℵ_ a := by + apply le_antisymm _ (ciSup_le' _) + · rw [aleph_eq_preAleph, preAleph_limit (ho.add _)] + refine ciSup_mono' (bddAbove_of_small _) ?_ + rintro ⟨i, hi⟩ + cases' lt_or_le i ω with h h + · rcases lt_omega0.1 h with ⟨n, rfl⟩ + use ⟨0, ho.pos⟩ + simpa using (nat_lt_aleph0 n).le + · exact ⟨⟨_, (sub_lt_of_le h).2 hi⟩, preAleph_le_preAleph.2 (le_add_sub _ _)⟩ + · exact fun i => aleph_le_aleph.2 i.2.le + +theorem aleph0_le_aleph (o : Ordinal) : ℵ₀ ≤ ℵ_ o := by + rw [aleph_eq_preAleph, aleph0_le_preAleph] + apply Ordinal.le_add_right + +theorem aleph_pos (o : Ordinal) : 0 < ℵ_ o := + aleph0_pos.trans_le (aleph0_le_aleph o) + +@[simp] +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 + +instance nonempty_toType_aleph (o : Ordinal) : Nonempty (ℵ_ o).ord.toType := by + rw [toType_nonempty_iff_ne_zero, ← ord_zero] + exact fun h => (ord_injective h).not_gt (aleph_pos o) + +theorem ord_aleph_isLimit (o : Ordinal) : (ℵ_ o).ord.IsLimit := + isLimit_ord <| aleph0_le_aleph _ + +instance (o : Ordinal) : NoMaxOrder (ℵ_ o).ord.toType := + toType_noMax_of_succ_lt (ord_aleph_isLimit o).2 + +theorem exists_aleph {c : Cardinal} : ℵ₀ ≤ c ↔ ∃ o, c = ℵ_ o := + ⟨fun h => + ⟨preAleph.symm c - ω, by + rw [aleph_eq_preAleph, Ordinal.add_sub_cancel_of_le, preAleph.apply_symm_apply] + rwa [← aleph0_le_preAleph, preAleph.apply_symm_apply]⟩, + fun ⟨o, e⟩ => e.symm ▸ aleph0_le_aleph _⟩ + +theorem preAleph_isNormal : IsNormal (ord ∘ preAleph) := + ⟨fun o => ord_lt_ord.2 <| preAleph_lt_preAleph.2 <| lt_succ o, fun o l a => by + simp [ord_le, preAleph_le_of_isLimit l]⟩ + +theorem aleph_isNormal : IsNormal (ord ∘ aleph) := + preAleph_isNormal.trans <| isNormal_add_right ω + +theorem succ_aleph0 : succ ℵ₀ = ℵ₁ := by rw [← aleph_zero, ← aleph_succ, Ordinal.succ_zero] + +theorem aleph0_lt_aleph_one : ℵ₀ < ℵ₁ := by + rw [← succ_aleph0] + apply lt_succ + +theorem countable_iff_lt_aleph_one {α : Type*} (s : Set α) : s.Countable ↔ #s < ℵ₁ := by + rw [← succ_aleph0, lt_succ_iff, le_aleph0_iff_set_countable] + +@[simp] +theorem aleph1_le_lift {c : Cardinal.{u}} : ℵ₁ ≤ lift.{v} c ↔ ℵ₁ ≤ c := by + simpa using lift_le (a := ℵ₁) + +@[simp] +theorem lift_le_aleph1 {c : Cardinal.{u}} : lift.{v} c ≤ ℵ₁ ↔ c ≤ ℵ₁ := by + simpa using lift_le (b := ℵ₁) + +@[simp] +theorem aleph1_lt_lift {c : Cardinal.{u}} : ℵ₁ < lift.{v} c ↔ ℵ₁ < c := by + simpa using lift_lt (a := ℵ₁) + +@[simp] +theorem lift_lt_aleph1 {c : Cardinal.{u}} : lift.{v} c < ℵ₁ ↔ c < ℵ₁ := by + simpa using lift_lt (b := ℵ₁) + +@[simp] +theorem aleph1_eq_lift {c : Cardinal.{u}} : ℵ₁ = lift.{v} c ↔ ℵ₁ = c := by + simpa using lift_inj (a := ℵ₁) + +@[simp] +theorem lift_eq_aleph1 {c : Cardinal.{u}} : lift.{v} c = ℵ₁ ↔ c = ℵ₁ := by + simpa using lift_inj (b := ℵ₁) + +section deprecated + +set_option linter.deprecated false +set_option linter.docPrime false + +@[deprecated preAleph (since := "2024-10-22")] +noncomputable alias aleph' := preAleph + +/-- 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 ω = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + In this definition, we register additionally that this function is an initial segment, + i.e., it is order preserving and its range is an initial segment of the ordinals. + For the basic function version, see `alephIdx`. + For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ +@[deprecated preAleph (since := "2024-08-28")] +def alephIdx.initialSeg : @InitialSeg Cardinal Ordinal (· < ·) (· < ·) := + @RelEmbedding.collapse Cardinal Ordinal (· < ·) (· < ·) _ Cardinal.ord.orderEmbedding.ltEmbedding + +/-- 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 ℵ₀ = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + In this version, we register additionally that this function is an order isomorphism + between cardinals and ordinals. + For the basic function version, see `alephIdx`. -/ +@[deprecated preAleph (since := "2024-08-28")] +def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := + aleph'.symm.toRelIsoLT + +/-- 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 ω = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def alephIdx : Cardinal → Ordinal := + aleph'.symm + +@[deprecated (since := "2024-08-28")] +theorem alephIdx.initialSeg_coe : (alephIdx.initialSeg : Cardinal → Ordinal) = alephIdx := + rfl + +@[deprecated (since := "2024-08-28")] +theorem alephIdx_lt {a b} : alephIdx a < alephIdx b ↔ a < b := + alephIdx.initialSeg.toRelEmbedding.map_rel_iff + +@[deprecated (since := "2024-08-28")] +theorem alephIdx_le {a b} : alephIdx a ≤ alephIdx b ↔ a ≤ b := by + rw [← not_lt, ← not_lt, alephIdx_lt] + +@[deprecated (since := "2024-08-28")] +theorem alephIdx.init {a b} : b < alephIdx a → ∃ c, alephIdx c = b := + alephIdx.initialSeg.init + +@[deprecated (since := "2024-08-28")] +theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephIdx := + rfl + +/-- 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. + In this version, we register additionally that this function is an order isomorphism + between ordinals and cardinals. + For the basic function version, see `aleph'`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def Aleph'.relIso := + aleph' + +@[deprecated (since := "2024-08-28")] +theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' := + rfl + +@[deprecated preAleph_lt_preAleph (since := "2024-10-22")] +theorem aleph'_lt {o₁ o₂ : Ordinal} : aleph' o₁ < aleph' o₂ ↔ o₁ < o₂ := + aleph'.lt_iff_lt + +@[deprecated preAleph_le_preAleph (since := "2024-10-22")] +theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ ≤ o₂ := + aleph'.le_iff_le + +@[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 + +@[deprecated (since := "2024-08-28")] +theorem aleph'_alephIdx (c : Cardinal) : aleph' c.alephIdx = c := + Cardinal.alephIdx.relIso.toEquiv.symm_apply_apply c + +@[deprecated (since := "2024-08-28")] +theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o := + Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o + +@[deprecated preAleph_zero (since := "2024-10-22")] +theorem aleph'_zero : aleph' 0 = 0 := + aleph'.map_bot + +@[deprecated preAleph_succ (since := "2024-10-22")] +theorem aleph'_succ (o : Ordinal) : aleph' (succ o) = succ (aleph' o) := + aleph'.map_succ o + +@[deprecated preAleph_nat (since := "2024-10-22")] +theorem aleph'_nat : ∀ n : ℕ, aleph' n = n := + preAleph_nat + +@[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 + +@[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 + +@[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 + +@[deprecated preAleph_omega0 (since := "2024-10-22")] +theorem aleph'_omega0 : aleph' ω = ℵ₀ := + preAleph_omega0 + +@[deprecated (since := "2024-09-30")] +alias aleph'_omega := aleph'_omega0 + +/-- `aleph'` and `aleph_idx` form an equivalence between `Ordinal` and `Cardinal` -/ +@[deprecated aleph' (since := "2024-08-28")] +def aleph'Equiv : Ordinal ≃ Cardinal := + ⟨aleph', alephIdx, alephIdx_aleph', aleph'_alephIdx⟩ + +theorem aleph_eq_aleph' (o : Ordinal) : ℵ_ o = preAleph (ω + o) := + rfl + +@[deprecated aleph0_le_preAleph (since := "2024-10-22")] +theorem aleph0_le_aleph' {o : Ordinal} : ℵ₀ ≤ aleph' o ↔ ω ≤ o := by + rw [← aleph'_omega0, aleph'_le] + +@[deprecated preAleph_pos (since := "2024-10-22")] +theorem aleph'_pos {o : Ordinal} (ho : 0 < o) : 0 < aleph' o := by + rwa [← aleph'_zero, aleph'_lt] + +@[deprecated preAleph_isNormal (since := "2024-10-22")] +theorem aleph'_isNormal : IsNormal (ord ∘ aleph') := + preAleph_isNormal + +-- TODO: these lemmas should be stated in terms of the `ω` function and of an `IsInitial` predicate, +-- neither of which currently exist. +-- +-- They should also use `¬ BddAbove` instead of `Unbounded (· < ·)`. + +/-- Ordinals that are cardinals are unbounded. -/ +@[deprecated (since := "2024-09-24")] +theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b } := + unbounded_lt_iff.2 fun a => + ⟨_, + ⟨by + dsimp + rw [card_ord], (lt_ord_succ_card a).le⟩⟩ + +@[deprecated (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⟩ + +/-- Infinite ordinals that are cardinals are unbounded. -/ +@[deprecated (since := "2024-09-24")] +theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := + (unbounded_lt_inter_le ω).2 ord_card_unbounded + +@[deprecated (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 + cases' eq_aleph'_of_eq_card_ord ho with a ha + use a - ω + rwa [aleph_eq_aleph', Ordinal.add_sub_cancel_of_le] + rwa [← aleph0_le_aleph', ← ord_le_ord, ha, ord_aleph0] + +end deprecated + +/-! ### Beth cardinals -/ + +/-- Beth numbers are defined so that `beth 0 = ℵ₀`, `beth (succ o) = 2 ^ beth o`, and when `o` is +a limit ordinal, `beth o` is the supremum of `beth o'` for `o' < o`. + +Assuming the generalized continuum hypothesis, which is undecidable in ZFC, `beth o = aleph o` for +every `o`. -/ +def beth (o : Ordinal.{u}) : Cardinal.{u} := + limitRecOn o ℵ₀ (fun _ x => 2 ^ x) fun a _ IH => ⨆ b : Iio a, IH b.1 b.2 + +@[inherit_doc] +scoped notation "ℶ_ " => beth + +@[simp] +theorem beth_zero : ℶ_ 0 = ℵ₀ := + limitRecOn_zero _ _ _ + +@[simp] +theorem beth_succ (o : Ordinal) : ℶ_ (succ o) = 2 ^ beth o := + limitRecOn_succ _ _ _ _ + +theorem beth_limit {o : Ordinal} : o.IsLimit → ℶ_ o = ⨆ a : Iio o, ℶ_ a := + limitRecOn_limit _ _ _ _ + +theorem beth_strictMono : StrictMono beth := by + intro a b + induction' b using Ordinal.induction with b IH generalizing a + intro h + rcases zero_or_succ_or_limit b with (rfl | ⟨c, rfl⟩ | hb) + · exact (Ordinal.not_lt_zero a h).elim + · rw [lt_succ_iff] at h + rw [beth_succ] + apply lt_of_le_of_lt _ (cantor _) + rcases eq_or_lt_of_le h with (rfl | h) + · rfl + exact (IH c (lt_succ c) h).le + · apply (cantor _).trans_le + rw [beth_limit hb, ← beth_succ] + exact le_ciSup (bddAbove_of_small _) (⟨_, hb.succ_lt h⟩ : Iio b) + +theorem beth_mono : Monotone beth := + beth_strictMono.monotone + +@[simp] +theorem beth_lt {o₁ o₂ : Ordinal} : ℶ_ o₁ < ℶ_ o₂ ↔ o₁ < o₂ := + beth_strictMono.lt_iff_lt + +@[simp] +theorem beth_le {o₁ o₂ : Ordinal} : ℶ_ o₁ ≤ ℶ_ o₂ ↔ o₁ ≤ o₂ := + beth_strictMono.le_iff_le + +theorem aleph_le_beth (o : Ordinal) : ℵ_ o ≤ ℶ_ o := by + induction o using limitRecOn with + | H₁ => simp + | H₂ o h => + rw [aleph_succ, beth_succ, succ_le_iff] + exact (cantor _).trans_le (power_le_power_left two_ne_zero h) + | H₃ o ho IH => + rw [aleph_limit ho, beth_limit ho] + exact ciSup_mono (bddAbove_of_small _) fun x => IH x.1 x.2 + +theorem aleph0_le_beth (o : Ordinal) : ℵ₀ ≤ ℶ_ o := + (aleph0_le_aleph o).trans <| aleph_le_beth o + +theorem beth_pos (o : Ordinal) : 0 < ℶ_ o := + aleph0_pos.trans_le <| aleph0_le_beth o + +theorem beth_ne_zero (o : Ordinal) : ℶ_ o ≠ 0 := + (beth_pos o).ne' + +theorem isNormal_beth : IsNormal (ord ∘ beth) := by + refine (isNormal_iff_strictMono_limit _).2 + ⟨ord_strictMono.comp beth_strictMono, fun o ho a ha ↦ ?_⟩ + rw [comp_apply, beth_limit ho, ord_le] + exact ciSup_le' fun b => ord_le.1 (ha _ b.2) + +@[deprecated isNormal_beth (since := "2024-10-11")] +theorem beth_normal : IsNormal.{u} fun o => (beth o).ord := + isNormal_beth + +end Cardinal diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Arithmetic.lean similarity index 55% rename from Mathlib/SetTheory/Cardinal/Ordinal.lean rename to Mathlib/SetTheory/Cardinal/Arithmetic.lean index 53142d747495b..0bdbc4b83972d 100644 --- a/Mathlib/SetTheory/Cardinal/Ordinal.lean +++ b/Mathlib/SetTheory/Cardinal/Arithmetic.lean @@ -3,36 +3,22 @@ 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.Order.Bounded -import Mathlib.SetTheory.Cardinal.PartENat +import Mathlib.SetTheory.Cardinal.Aleph import Mathlib.SetTheory.Ordinal.Principal import Mathlib.Tactic.Linarith /-! -# Cardinals and ordinals +# Cardinal arithmetic -Relationships between cardinals and ordinals, properties of cardinals that are proved -using ordinals. - -## Main definitions - -* The function `Cardinal.aleph'` gives the cardinals listed by their ordinal index. - `aleph' n = n`, `aleph' ω = ℵ₀`, `aleph' (ω + 1) = succ ℵ₀`, etc. - It is an order isomorphism between ordinals and cardinals. -* The function `Cardinal.aleph` gives the infinite cardinals listed by their - ordinal index. `aleph 0 = ℵ₀`, `aleph 1 = succ ℵ₀` is the first - uncountable cardinal, and so on. The notation `ω_` combines the latter with `Cardinal.ord`, - giving an enumeration of (infinite) initial ordinals. - Thus `ω_ 0 = ω` and `ω₁ = ω_ 1` is the first uncountable ordinal. -* The function `Cardinal.beth` enumerates the Beth cardinals. `beth 0 = ℵ₀`, - `beth (succ o) = 2 ^ beth o`, and for a limit ordinal `o`, `beth o` is the supremum of `beth a` - for `a < o`. +Arithmetic operations on cardinals are defined in `SetTheory/Cardinal/Basic.lean`. However, proving +the important theorem `c * c = c` for infinite cardinals and its corollaries requires the use of +ordinal numbers. This is done within this file. ## Main statements * `Cardinal.mul_eq_max` and `Cardinal.add_eq_max` state that the product (resp. sum) of two infinite cardinals is just their maximum. Several variations around this fact are also given. -* `Cardinal.mk_list_eq_mk` : when `α` is infinite, `α` and `List α` have the same cardinality. +* `Cardinal.mk_list_eq_mk`: when `α` is infinite, `α` and `List α` have the same cardinality. ## Tags @@ -50,426 +36,14 @@ universe u v w namespace Cardinal -section UsingOrdinals - -theorem ord_isLimit {c} (co : ℵ₀ ≤ c) : (ord c).IsLimit := by - 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 - · rw [ord_le] at h ⊢ - rwa [← @add_one_of_aleph0_le (card a), ← card_succ] - rw [← ord_le, ← le_succ_of_isLimit, ord_le] - · exact co.trans h - · rw [ord_aleph0] - exact omega0_isLimit - -theorem noMaxOrder {c} (h : ℵ₀ ≤ c) : NoMaxOrder c.ord.toType := - toType_noMax_of_succ_lt (ord_isLimit h).2 - -/-! ### Aleph cardinals -/ - -section aleph - -/-- The `aleph'` function gives the cardinals listed by their ordinal index. `aleph' n = n`, -`aleph' ω = ℵ₀`, `aleph' (ω + 1) = succ ℵ₀`, etc. - -For the more common aleph function skipping over finite cardinals, see `Cardinal.aleph`. -/ -def aleph' : Ordinal.{u} ≃o Cardinal.{u} := by - let f := RelEmbedding.collapse Cardinal.ord.orderEmbedding.ltEmbedding.{u} - refine (OrderIso.ofRelIsoLT <| RelIso.ofSurjective f ?_).symm - apply f.eq_or_principal.resolve_right - rintro ⟨o, e⟩ - have : ∀ c, f c < o := fun c => (e _).2 ⟨_, rfl⟩ - refine Ordinal.inductionOn o ?_ this - intro α r _ h - let s := ⨆ a, invFun f (Ordinal.typein r a) - apply (lt_succ s).not_le - have I : Injective f := f.toEmbedding.injective - simpa only [typein_enum, leftInverse_invFun I (succ s)] using - le_ciSup - (Cardinal.bddAbove_range.{u, u} fun a : α => invFun f (Ordinal.typein r a)) - (Ordinal.enum r ⟨_, h (succ s)⟩) - -/-- 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 ω = ω`, - `alephIdx ℵ₁ = ω + 1` and so on.) - In this definition, we register additionally that this function is an initial segment, - i.e., it is order preserving and its range is an initial segment of the ordinals. - For the basic function version, see `alephIdx`. - For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ -@[deprecated aleph' (since := "2024-08-28")] -def alephIdx.initialSeg : @InitialSeg Cardinal Ordinal (· < ·) (· < ·) := - @RelEmbedding.collapse Cardinal Ordinal (· < ·) (· < ·) _ Cardinal.ord.orderEmbedding.ltEmbedding - -/-- 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 ℵ₀ = ω`, - `alephIdx ℵ₁ = ω + 1` and so on.) - In this version, we register additionally that this function is an order isomorphism - between cardinals and ordinals. - For the basic function version, see `alephIdx`. -/ -@[deprecated aleph' (since := "2024-08-28")] -def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := - aleph'.symm.toRelIsoLT - -/-- 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 ω = ω`, - `alephIdx ℵ₁ = ω + 1` and so on.) - For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ -@[deprecated aleph' (since := "2024-08-28")] -def alephIdx : Cardinal → Ordinal := - aleph'.symm - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem alephIdx.initialSeg_coe : (alephIdx.initialSeg : Cardinal → Ordinal) = alephIdx := - rfl - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem alephIdx_lt {a b} : alephIdx a < alephIdx b ↔ a < b := - alephIdx.initialSeg.toRelEmbedding.map_rel_iff - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem alephIdx_le {a b} : alephIdx a ≤ alephIdx b ↔ a ≤ b := by - rw [← not_lt, ← not_lt, alephIdx_lt] - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem alephIdx.init {a b} : b < alephIdx a → ∃ c, alephIdx c = b := - alephIdx.initialSeg.init - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephIdx := - rfl - -@[simp] -theorem type_cardinal : @type Cardinal (· < ·) _ = Ordinal.univ.{u, u + 1} := by - rw [Ordinal.univ_id] - exact Quotient.sound ⟨aleph'.symm.toRelIsoLT⟩ - -@[simp] -theorem mk_cardinal : #Cardinal = univ.{u, u + 1} := by - simpa only [card_type, card_univ] using congr_arg card type_cardinal - -/-- 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. - In this version, we register additionally that this function is an order isomorphism - between ordinals and cardinals. - For the basic function version, see `aleph'`. -/ -@[deprecated aleph' (since := "2024-08-28")] -def Aleph'.relIso := - aleph' - -set_option linter.deprecated false in -@[deprecated (since := "2024-08-28")] -theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' := - rfl - -theorem aleph'_lt {o₁ o₂ : Ordinal} : aleph' o₁ < aleph' o₂ ↔ o₁ < o₂ := - aleph'.lt_iff_lt - -theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ ≤ o₂ := - aleph'.le_iff_le - -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 (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 (since := "2024-08-28")] -theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o := - Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o - -@[simp] -theorem aleph'_zero : aleph' 0 = 0 := - aleph'.map_bot - -@[simp] -theorem aleph'_succ (o : Ordinal) : aleph' (succ o) = succ (aleph' o) := - aleph'.map_succ o - -@[simp] -theorem aleph'_nat : ∀ n : ℕ, aleph' n = n - | 0 => aleph'_zero - | n + 1 => show aleph' (succ n) = n.succ by rw [aleph'_succ, aleph'_nat n, nat_succ] - -theorem aleph'_le_of_limit {o : Ordinal} (l : o.IsLimit) {c} : - aleph' o ≤ c ↔ ∀ o' < o, aleph' o' ≤ c := - ⟨fun h o' h' => (aleph'_le.2 <| h'.le).trans h, fun h => by - rw [← aleph'.apply_symm_apply c, aleph'_le, limit_le l] - intro x h' - rw [← aleph'_le, aleph'.apply_symm_apply] - exact h _ h'⟩ - -theorem aleph'_limit {o : Ordinal} (ho : o.IsLimit) : aleph' o = ⨆ a : Iio o, aleph' a := by - refine le_antisymm ?_ (ciSup_le' fun i => aleph'_le.2 (le_of_lt i.2)) - rw [aleph'_le_of_limit ho] - exact fun a ha => le_ciSup (bddAbove_of_small _) (⟨a, ha⟩ : Iio o) - -@[simp] -theorem aleph'_omega0 : aleph' ω = ℵ₀ := - eq_of_forall_ge_iff fun c => by - simp only [aleph'_le_of_limit omega0_isLimit, lt_omega0, exists_imp, aleph0_le] - exact forall_swap.trans (forall_congr' fun n => by simp only [forall_eq, aleph'_nat]) - -@[deprecated (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 := - ⟨aleph', alephIdx, alephIdx_aleph', aleph'_alephIdx⟩ - -/-- The `aleph` function gives the infinite cardinals listed by their ordinal index. `aleph 0 = ℵ₀`, -`aleph 1 = succ ℵ₀` is the first uncountable cardinal, and so on. - -For a version including finite cardinals, see `Cardinal.aleph'`. -/ -def aleph : Ordinal ↪o Cardinal := - (OrderEmbedding.addLeft ω).trans aleph'.toOrderEmbedding - -theorem aleph_eq_aleph' (o : Ordinal) : aleph o = aleph' (ω + o) := - rfl - -theorem aleph_lt {o₁ o₂ : Ordinal} : aleph o₁ < aleph o₂ ↔ o₁ < o₂ := - aleph.lt_iff_lt - -theorem aleph_le {o₁ o₂ : Ordinal} : aleph o₁ ≤ aleph o₂ ↔ o₁ ≤ o₂ := - aleph.le_iff_le - -theorem aleph_max (o₁ o₂ : Ordinal) : aleph (max o₁ o₂) = max (aleph o₁) (aleph o₂) := - aleph.monotone.map_max - -@[deprecated aleph_max (since := "2024-08-28")] -theorem max_aleph_eq (o₁ o₂ : Ordinal) : max (aleph o₁) (aleph o₂) = aleph (max o₁ o₂) := - (aleph_max o₁ o₂).symm - -@[simp] -theorem aleph_succ (o : Ordinal) : aleph (succ o) = succ (aleph o) := by - rw [aleph_eq_aleph', add_succ, aleph'_succ, aleph_eq_aleph'] - -@[simp] -theorem aleph_zero : aleph 0 = ℵ₀ := by rw [aleph_eq_aleph', add_zero, aleph'_omega0] - -theorem aleph_limit {o : Ordinal} (ho : o.IsLimit) : aleph o = ⨆ a : Iio o, aleph a := by - apply le_antisymm _ (ciSup_le' _) - · rw [aleph_eq_aleph', aleph'_limit (ho.add _)] - refine ciSup_mono' (bddAbove_of_small _) ?_ - rintro ⟨i, hi⟩ - cases' lt_or_le i ω with h h - · rcases lt_omega0.1 h with ⟨n, rfl⟩ - use ⟨0, ho.pos⟩ - simpa using (nat_lt_aleph0 n).le - · exact ⟨⟨_, (sub_lt_of_le h).2 hi⟩, aleph'_le.2 (le_add_sub _ _)⟩ - · exact fun i => aleph_le.2 (le_of_lt i.2) - -theorem aleph0_le_aleph' {o : Ordinal} : ℵ₀ ≤ aleph' o ↔ ω ≤ o := by rw [← aleph'_omega0, aleph'_le] - -theorem aleph0_le_aleph (o : Ordinal) : ℵ₀ ≤ aleph o := by - rw [aleph_eq_aleph', aleph0_le_aleph'] - apply Ordinal.le_add_right - -theorem aleph'_pos {o : Ordinal} (ho : 0 < o) : 0 < aleph' o := by rwa [← aleph'_zero, aleph'_lt] - -theorem aleph_pos (o : Ordinal) : 0 < aleph o := - aleph0_pos.trans_le (aleph0_le_aleph o) - -@[simp] -theorem aleph_toNat (o : Ordinal) : toNat (aleph o) = 0 := - toNat_apply_of_aleph0_le <| aleph0_le_aleph o - -@[simp] -theorem aleph_toPartENat (o : Ordinal) : toPartENat (aleph o) = ⊤ := - toPartENat_apply_of_aleph0_le <| aleph0_le_aleph o - -instance nonempty_toType_aleph (o : Ordinal) : Nonempty (aleph o).ord.toType := by - rw [toType_nonempty_iff_ne_zero, ← ord_zero] - exact fun h => (ord_injective h).not_gt (aleph_pos o) - -theorem ord_aleph_isLimit (o : Ordinal) : (aleph o).ord.IsLimit := - ord_isLimit <| aleph0_le_aleph _ - -instance (o : Ordinal) : NoMaxOrder (aleph o).ord.toType := - toType_noMax_of_succ_lt (ord_aleph_isLimit o).2 - -theorem exists_aleph {c : Cardinal} : ℵ₀ ≤ c ↔ ∃ o, c = aleph o := - ⟨fun h => - ⟨aleph'.symm c - ω, by - rw [aleph_eq_aleph', Ordinal.add_sub_cancel_of_le, aleph'.apply_symm_apply] - rwa [← aleph0_le_aleph', aleph'.apply_symm_apply]⟩, - fun ⟨o, e⟩ => e.symm ▸ aleph0_le_aleph _⟩ - -theorem aleph'_isNormal : IsNormal (ord ∘ aleph') := - ⟨fun o => ord_lt_ord.2 <| aleph'_lt.2 <| lt_succ o, fun o l a => by - simp [ord_le, aleph'_le_of_limit l]⟩ - -theorem aleph_isNormal : IsNormal (ord ∘ aleph) := - aleph'_isNormal.trans <| add_isNormal ω - -theorem succ_aleph0 : succ ℵ₀ = aleph 1 := by rw [← aleph_zero, ← aleph_succ, Ordinal.succ_zero] - -theorem aleph0_lt_aleph_one : ℵ₀ < aleph 1 := by - rw [← succ_aleph0] - apply lt_succ - -theorem countable_iff_lt_aleph_one {α : Type*} (s : Set α) : s.Countable ↔ #s < aleph 1 := by - rw [← succ_aleph0, lt_succ_iff, le_aleph0_iff_set_countable] - -section deprecated - -set_option linter.deprecated false - --- TODO: these lemmas should be stated in terms of the `ω` function and of an `IsInitial` predicate, --- neither of which currently exist. --- --- They should also use `¬ BddAbove` instead of `Unbounded (· < ·)`. - -/-- Ordinals that are cardinals are unbounded. -/ -@[deprecated (since := "2024-09-24")] -theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b } := - unbounded_lt_iff.2 fun a => - ⟨_, - ⟨by - dsimp - rw [card_ord], (lt_ord_succ_card a).le⟩⟩ - -@[deprecated (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⟩ - -/-- `ord ∘ aleph'` enumerates the ordinals that are cardinals. -/ -@[deprecated (since := "2024-09-24")] -theorem ord_aleph'_eq_enum_card : ord ∘ aleph' = enumOrd { b : Ordinal | b.card.ord = b } := by - rw [← eq_enumOrd _ ord_card_unbounded, range_eq_iff] - exact - ⟨aleph'_isNormal.strictMono, - ⟨fun a => by - dsimp - rw [card_ord], fun b hb => eq_aleph'_of_eq_card_ord hb⟩⟩ - -/-- Infinite ordinals that are cardinals are unbounded. -/ -@[deprecated (since := "2024-09-24")] -theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := - (unbounded_lt_inter_le ω).2 ord_card_unbounded - -@[deprecated (since := "2024-09-24")] -theorem eq_aleph_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) (ho' : ω ≤ o) : - ∃ a, (aleph a).ord = o := by - cases' eq_aleph'_of_eq_card_ord ho with a ha - use a - ω - rwa [aleph_eq_aleph', Ordinal.add_sub_cancel_of_le] - rwa [← aleph0_le_aleph', ← ord_le_ord, ha, ord_aleph0] - -/-- `ord ∘ aleph` enumerates the infinite ordinals that are cardinals. -/ -@[deprecated (since := "2024-09-24")] -theorem ord_aleph_eq_enum_card : - ord ∘ aleph = enumOrd { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := by - rw [← eq_enumOrd _ ord_card_unbounded'] - use aleph_isNormal.strictMono - rw [range_eq_iff] - refine ⟨fun a => ⟨?_, ?_⟩, fun b hb => eq_aleph_of_eq_card_ord hb.1 hb.2⟩ - · rw [Function.comp_apply, card_ord] - · rw [← ord_aleph0, Function.comp_apply, ord_le_ord] - exact aleph0_le_aleph _ - -end deprecated - -end aleph - -/-! ### Beth cardinals -/ -section beth - -/-- Beth numbers are defined so that `beth 0 = ℵ₀`, `beth (succ o) = 2 ^ (beth o)`, and when `o` is -a limit ordinal, `beth o` is the supremum of `beth o'` for `o' < o`. - -Assuming the generalized continuum hypothesis, which is undecidable in ZFC, `beth o = aleph o` for -every `o`. -/ -def beth (o : Ordinal.{u}) : Cardinal.{u} := - limitRecOn o aleph0 (fun _ x => (2 : Cardinal) ^ x) fun a _ IH => ⨆ b : Iio a, IH b.1 b.2 - -@[simp] -theorem beth_zero : beth 0 = aleph0 := - limitRecOn_zero _ _ _ - -@[simp] -theorem beth_succ (o : Ordinal) : beth (succ o) = 2 ^ beth o := - limitRecOn_succ _ _ _ _ - -theorem beth_limit {o : Ordinal} : o.IsLimit → beth o = ⨆ a : Iio o, beth a := - limitRecOn_limit _ _ _ _ - -theorem beth_strictMono : StrictMono beth := by - intro a b - induction' b using Ordinal.induction with b IH generalizing a - intro h - rcases zero_or_succ_or_limit b with (rfl | ⟨c, rfl⟩ | hb) - · exact (Ordinal.not_lt_zero a h).elim - · rw [lt_succ_iff] at h - rw [beth_succ] - apply lt_of_le_of_lt _ (cantor _) - rcases eq_or_lt_of_le h with (rfl | h) - · rfl - exact (IH c (lt_succ c) h).le - · apply (cantor _).trans_le - rw [beth_limit hb, ← beth_succ] - exact le_ciSup (bddAbove_of_small _) (⟨_, hb.succ_lt h⟩ : Iio b) - -theorem beth_mono : Monotone beth := - beth_strictMono.monotone - -@[simp] -theorem beth_lt {o₁ o₂ : Ordinal} : beth o₁ < beth o₂ ↔ o₁ < o₂ := - beth_strictMono.lt_iff_lt - -@[simp] -theorem beth_le {o₁ o₂ : Ordinal} : beth o₁ ≤ beth o₂ ↔ o₁ ≤ o₂ := - beth_strictMono.le_iff_le - -theorem aleph_le_beth (o : Ordinal) : aleph o ≤ beth o := by - induction o using limitRecOn with - | H₁ => simp - | H₂ o h => - rw [aleph_succ, beth_succ, succ_le_iff] - exact (cantor _).trans_le (power_le_power_left two_ne_zero h) - | H₃ o ho IH => - rw [aleph_limit ho, beth_limit ho] - exact ciSup_mono (bddAbove_of_small _) fun x => IH x.1 x.2 - -theorem aleph0_le_beth (o : Ordinal) : ℵ₀ ≤ beth o := - (aleph0_le_aleph o).trans <| aleph_le_beth o - -theorem beth_pos (o : Ordinal) : 0 < beth o := - aleph0_pos.trans_le <| aleph0_le_beth o - -theorem beth_ne_zero (o : Ordinal) : beth o ≠ 0 := - (beth_pos o).ne' - -theorem beth_normal : IsNormal.{u} fun o => (beth o).ord := - (isNormal_iff_strictMono_limit _).2 - ⟨ord_strictMono.comp beth_strictMono, fun o ho a ha => by - rw [beth_limit ho, ord_le] - exact ciSup_le' fun b => ord_le.1 (ha _ b.2)⟩ - -end beth - /-! ### Properties of `mul` -/ -section mulOrdinals +section mul /-- If `α` is an infinite type, then `α × α` and `α` have the same cardinality. -/ theorem mul_eq_self {c : Cardinal} (h : ℵ₀ ≤ c) : c * c = c := by refine le_antisymm ?_ (by simpa only [mul_one] using mul_le_mul_left' (one_le_aleph0.trans h) c) -- the only nontrivial part is `c * c ≤ c`. We prove it inductively. - refine Acc.recOn (Cardinal.lt_wf.apply c) (fun c _ => Quotient.inductionOn c fun α IH ol => ?_) h + refine Acc.recOn (Cardinal.lt_wf.apply c) (fun c _ => Cardinal.inductionOn c fun α IH ol => ?_) h -- consider the minimal well-order `r` on `α` (a type with cardinality `c`). rcases ord_eq α with ⟨r, wo, e⟩ classical @@ -506,19 +80,12 @@ theorem mul_eq_self {c : Cardinal} (h : ℵ₀ ≤ c) : c * c = c := by apply @irrefl _ r cases' lt_or_le (card (succ (typein (· < ·) (g p)))) ℵ₀ with qo qo · exact (mul_lt_aleph0 qo qo).trans_le ol - · suffices (succ (typein LT.lt (g p))).card < ⟦α⟧ from (IH _ this qo).trans_lt this + · suffices (succ (typein LT.lt (g p))).card < #α from (IH _ this qo).trans_lt this rw [← lt_ord] - apply (ord_isLimit ol).2 - rw [mk'_def, e] + apply (isLimit_ord ol).2 + rw [e] apply typein_lt_type -end mulOrdinals - -end UsingOrdinals - -/-! Properties of `mul`, not requiring ordinals -/ -section mul - /-- If `α` and `β` are infinite types, then the cardinality of `α × β` is the maximum of the cardinalities of `α` and `β`. -/ theorem mul_eq_max {a b : Cardinal} (ha : ℵ₀ ≤ a) (hb : ℵ₀ ≤ b) : a * b = max a b := @@ -533,7 +100,7 @@ theorem mul_mk_eq_max {α β : Type u} [Infinite α] [Infinite β] : #α * #β = mul_eq_max (aleph0_le_mk α) (aleph0_le_mk β) @[simp] -theorem aleph_mul_aleph (o₁ o₂ : Ordinal) : aleph o₁ * aleph o₂ = aleph (max o₁ o₂) := by +theorem aleph_mul_aleph (o₁ o₂ : Ordinal) : ℵ_ o₁ * ℵ_ o₂ = ℵ_ (max o₁ o₂) := by rw [Cardinal.mul_eq_max (aleph0_le_aleph o₁) (aleph0_le_aleph o₂), aleph_max] @[simp] @@ -544,20 +111,18 @@ theorem aleph0_mul_eq {a : Cardinal} (ha : ℵ₀ ≤ a) : ℵ₀ * a = a := theorem mul_aleph0_eq {a : Cardinal} (ha : ℵ₀ ≤ a) : a * ℵ₀ = a := (mul_eq_max ha le_rfl).trans (max_eq_left ha) --- Porting note (#10618): removed `simp`, `simp` can prove it theorem aleph0_mul_mk_eq {α : Type*} [Infinite α] : ℵ₀ * #α = #α := aleph0_mul_eq (aleph0_le_mk α) --- Porting note (#10618): removed `simp`, `simp` can prove it theorem mk_mul_aleph0_eq {α : Type*} [Infinite α] : #α * ℵ₀ = #α := mul_aleph0_eq (aleph0_le_mk α) @[simp] -theorem aleph0_mul_aleph (o : Ordinal) : ℵ₀ * aleph o = aleph o := +theorem aleph0_mul_aleph (o : Ordinal) : ℵ₀ * ℵ_ o = ℵ_ o := aleph0_mul_eq (aleph0_le_aleph o) @[simp] -theorem aleph_mul_aleph0 (o : Ordinal) : aleph o * ℵ₀ = aleph o := +theorem aleph_mul_aleph0 (o : Ordinal) : ℵ_ o * ℵ₀ = ℵ_ o := mul_aleph0_eq (aleph0_le_aleph o) theorem mul_lt_of_lt {a b c : Cardinal} (hc : ℵ₀ ≤ c) (h1 : a < c) (h2 : b < c) : a * b < c := @@ -758,7 +323,6 @@ theorem nat_add_eq {a : Cardinal} (n : ℕ) (ha : ℵ₀ ≤ a) : n + a = a := b theorem add_one_eq {a : Cardinal} (ha : ℵ₀ ≤ a) : a + 1 = a := add_one_of_aleph0_le ha --- Porting note (#10618): removed `simp`, `simp` can prove it theorem mk_add_one_eq {α : Type*} [Infinite α] : #α + 1 = #α := add_one_eq (aleph0_le_mk α) @@ -789,6 +353,7 @@ protected theorem eq_of_add_eq_add_right {a b c : Cardinal} (h : a + b = c + b) end add +/-! ### Properties of `ciSup` -/ section ciSup variable {ι : Type u} {ι' : Type w} (f : ι → Cardinal.{v}) @@ -849,8 +414,11 @@ protected theorem ciSup_mul_ciSup (g : ι' → Cardinal.{v}) : end ciSup +/-! ### Properties of `aleph` -/ +section aleph + @[simp] -theorem aleph_add_aleph (o₁ o₂ : Ordinal) : aleph o₁ + aleph o₂ = aleph (max o₁ o₂) := by +theorem aleph_add_aleph (o₁ o₂ : Ordinal) : ℵ_ o₁ + ℵ_ o₂ = ℵ_ (max o₁ o₂) := by rw [Cardinal.add_eq_max (aleph0_le_aleph o₁), aleph_max] theorem principal_add_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : Ordinal.Principal (· + ·) c.ord := @@ -858,7 +426,7 @@ theorem principal_add_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : Ordinal.Principal rw [lt_ord, Ordinal.card_add] at * exact add_lt_of_lt hc ha hb -theorem principal_add_aleph (o : Ordinal) : Ordinal.Principal (· + ·) (aleph o).ord := +theorem principal_add_aleph (o : Ordinal) : Ordinal.Principal (· + ·) (ℵ_ o).ord := principal_add_ord <| aleph0_le_aleph o theorem add_right_inj_of_lt_aleph0 {α β γ : Cardinal} (γ₀ : γ < aleph0) : α + γ = β + γ ↔ α = β := @@ -893,8 +461,10 @@ theorem add_one_le_add_one_iff {α β : Cardinal} : α + 1 ≤ β + 1 ↔ α ≤ @[deprecated (since := "2024-02-12")] alias add_one_le_add_one_iff_of_lt_aleph_0 := add_one_le_add_one_iff -/-! ### Properties about power -/ -section pow +end aleph + +/-! ### Properties about `power` -/ +section power theorem pow_le {κ μ : Cardinal.{u}} (H1 : ℵ₀ ≤ κ) (H2 : μ < ℵ₀) : κ ^ μ ≤ κ := let ⟨n, H3⟩ := lt_aleph0.1 H2 @@ -969,7 +539,7 @@ theorem powerlt_aleph0_le (c : Cardinal) : c ^< ℵ₀ ≤ max c ℵ₀ := by rw [powerlt_le] exact fun c' hc' => (power_lt_aleph0 h hc').le.trans (le_max_right _ _) -end pow +end power /-! ### Computing cardinality of various types -/ section computing @@ -1213,6 +783,7 @@ theorem mk_compl_eq_mk_compl_finite_same {α : Type u} [Finite α] {s t : Set α end compl /-! ### Extending an injection to an equiv -/ +section extend theorem extend_function {α β : Type*} {s : Set α} (f : s ↪ β) (h : Nonempty ((sᶜ : Set α) ≃ ((range f)ᶜ : Set β))) : ∃ g : α ≃ β, ∀ x : s, g x = f x := by @@ -1242,234 +813,17 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : rwa [mk_compl_of_infinite s hs, mk_compl_of_infinite] rwa [← lift_lt, mk_range_eq_of_injective f.injective, ← h, lift_lt] - --- Porting note: we no longer express literals as `bit0` and `bit1` in Lean 4, so we can't use this --- section Bit - --- /-! --- This section proves inequalities for `bit0` and `bit1`, enabling `simp` to solve inequalities --- for numeral cardinals. The complexity of the resulting algorithm is not good, as in some cases --- `simp` reduces an inequality to a disjunction of two situations, depending on whether a cardinal --- is finite or infinite. Since the evaluation of the branches is not lazy, this is bad. It is good --- enough for practical situations, though. - --- For specific numbers, these inequalities could also be deduced from the corresponding --- inequalities of natural numbers using `norm_cast`: --- ``` --- example : (37 : cardinal) < 42 := --- by { norm_cast, norm_num } --- ``` --- -/ - - --- theorem bit0_ne_zero (a : Cardinal) : ¬bit0 a = 0 ↔ ¬a = 0 := by simp [bit0] - --- @[simp] --- theorem bit1_ne_zero (a : Cardinal) : ¬bit1 a = 0 := by simp [bit1] - --- @[simp] --- theorem zero_lt_bit0 (a : Cardinal) : 0 < bit0 a ↔ 0 < a := by --- rw [← not_iff_not] --- simp [bit0] - --- @[simp] --- theorem zero_lt_bit1 (a : Cardinal) : 0 < bit1 a := --- zero_lt_one.trans_le (self_le_add_left _ _) - --- @[simp] --- theorem one_le_bit0 (a : Cardinal) : 1 ≤ bit0 a ↔ 0 < a := --- ⟨fun h => (zero_lt_bit0 a).mp (zero_lt_one.trans_le h), fun h => --- (one_le_iff_pos.mpr h).trans (self_le_add_left a a)⟩ - --- @[simp] --- theorem one_le_bit1 (a : Cardinal) : 1 ≤ bit1 a := --- self_le_add_left _ _ - --- theorem bit0_eq_self {c : Cardinal} (h : ℵ₀ ≤ c) : bit0 c = c := --- add_eq_self h - --- @[simp] --- theorem bit0_lt_aleph0 {c : Cardinal} : bit0 c < ℵ₀ ↔ c < ℵ₀ := --- by simp [bit0, add_lt_aleph_0_iff] - --- @[simp] --- theorem aleph0_le_bit0 {c : Cardinal} : ℵ₀ ≤ bit0 c ↔ ℵ₀ ≤ c := by --- rw [← not_iff_not] --- simp - --- @[simp] --- theorem bit1_eq_self_iff {c : Cardinal} : bit1 c = c ↔ ℵ₀ ≤ c := by --- by_cases h : ℵ₀ ≤ c --- · simp only [bit1, bit0_eq_self h, h, eq_self_iff_true, add_one_of_aleph_0_le] --- · refine' iff_of_false (ne_of_gt _) h --- rcases lt_aleph_0.1 (not_le.1 h) with ⟨n, rfl⟩ --- norm_cast --- dsimp [bit1, bit0] --- linarith - --- @[simp] --- theorem bit1_lt_aleph0 {c : Cardinal} : bit1 c < ℵ₀ ↔ c < ℵ₀ := by --- simp [bit1, bit0, add_lt_aleph_0_iff, one_lt_aleph_0] - --- @[simp] --- theorem aleph0_le_bit1 {c : Cardinal} : ℵ₀ ≤ bit1 c ↔ ℵ₀ ≤ c := by --- rw [← not_iff_not] --- simp - --- @[simp] --- theorem bit0_le_bit0 {a b : Cardinal} : bit0 a ≤ bit0 b ↔ a ≤ b := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · rw [bit0_eq_self ha, bit0_eq_self hb] --- · rw [bit0_eq_self ha] --- refine' iff_of_false (fun h => _) (hb.trans_le ha).not_le --- have A : bit0 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans_le h) --- · rw [bit0_eq_self hb] --- exact iff_of_true ((bit0_lt_aleph_0.2 ha).le.trans hb) (ha.le.trans hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- exact bit0_le_bit0 - --- @[simp] --- theorem bit0_le_bit1 {a b : Cardinal} : bit0 a ≤ bit1 b ↔ a ≤ b := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · rw [bit0_eq_self ha, bit1_eq_self_iff.2 hb] --- · rw [bit0_eq_self ha] --- refine' iff_of_false (fun h => _) (hb.trans_le ha).not_le --- have A : bit1 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans_le h) --- · rw [bit1_eq_self_iff.2 hb] --- exact iff_of_true ((bit0_lt_aleph_0.2 ha).le.trans hb) (ha.le.trans hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- exact Nat.bit0_le_bit1_iff - --- @[simp] --- theorem bit1_le_bit1 {a b : Cardinal} : bit1 a ≤ bit1 b ↔ a ≤ b := --- ⟨fun h => bit0_le_bit1.1 ((self_le_add_right (bit0 a) 1).trans h), fun h => --- (add_le_add_right (add_le_add_left h a) 1).trans (add_le_add_right (add_le_add_right h b) 1)⟩ - --- @[simp] --- theorem bit1_le_bit0 {a b : Cardinal} : bit1 a ≤ bit0 b ↔ a < b ∨ a ≤ b ∧ ℵ₀ ≤ a := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · simp only [bit1_eq_self_iff.mpr ha, bit0_eq_self hb, ha, and_true_iff] --- refine' ⟨fun h => Or.inr h, fun h => _⟩ --- cases h --- · exact le_of_lt h --- · exact h --- · rw [bit1_eq_self_iff.2 ha] --- refine' iff_of_false (fun h => _) fun h => _ --- · have A : bit0 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans_le h) --- · exact not_le_of_lt (hb.trans_le ha) (h.elim le_of_lt And.left) --- · rw [bit0_eq_self hb] --- exact iff_of_true ((bit1_lt_aleph_0.2 ha).le.trans hb) (Or.inl <| ha.trans_le hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- simp [not_le.mpr ha] - --- @[simp] --- theorem bit0_lt_bit0 {a b : Cardinal} : bit0 a < bit0 b ↔ a < b := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · rw [bit0_eq_self ha, bit0_eq_self hb] --- · rw [bit0_eq_self ha] --- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt --- have A : bit0 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans h) --- · rw [bit0_eq_self hb] --- exact iff_of_true ((bit0_lt_aleph_0.2 ha).trans_le hb) (ha.trans_le hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- exact bit0_lt_bit0 - --- @[simp] --- theorem bit1_lt_bit0 {a b : Cardinal} : bit1 a < bit0 b ↔ a < b := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · rw [bit1_eq_self_iff.2 ha, bit0_eq_self hb] --- · rw [bit1_eq_self_iff.2 ha] --- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt --- have A : bit0 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans h) --- · rw [bit0_eq_self hb] --- exact iff_of_true ((bit1_lt_aleph_0.2 ha).trans_le hb) (ha.trans_le hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- exact Nat.bit1_lt_bit0_iff - --- @[simp] --- theorem bit1_lt_bit1 {a b : Cardinal} : bit1 a < bit1 b ↔ a < b := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · rw [bit1_eq_self_iff.2 ha, bit1_eq_self_iff.2 hb] --- · rw [bit1_eq_self_iff.2 ha] --- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt --- have A : bit1 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans h) --- · rw [bit1_eq_self_iff.2 hb] --- exact iff_of_true ((bit1_lt_aleph_0.2 ha).trans_le hb) (ha.trans_le hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- exact bit1_lt_bit1 - --- @[simp] --- theorem bit0_lt_bit1 {a b : Cardinal} : bit0 a < bit1 b ↔ a < b ∨ a ≤ b ∧ a < ℵ₀ := by --- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb --- · simp [bit0_eq_self ha, bit1_eq_self_iff.2 hb, not_lt.mpr ha] --- · rw [bit0_eq_self ha] --- refine' iff_of_false (fun h => _) fun h => _ --- · have A : bit1 b < ℵ₀ := by simpa using hb --- exact lt_irrefl _ ((A.trans_le ha).trans h) --- · exact (hb.trans_le ha).not_le (h.elim le_of_lt And.left) --- · rw [bit1_eq_self_iff.2 hb] --- exact iff_of_true ((bit0_lt_aleph_0.2 ha).trans_le hb) (Or.inl <| ha.trans_le hb) --- · rcases lt_aleph_0.1 ha with ⟨m, rfl⟩ --- rcases lt_aleph_0.1 hb with ⟨n, rfl⟩ --- norm_cast --- simp only [ha, and_true_iff, Nat.bit0_lt_bit1_iff, or_iff_right_of_imp le_of_lt] - --- theorem one_lt_two : (1 : Cardinal) < 2 := by --- -- This strategy works generally to prove inequalities between numerals in `cardinality`. --- norm_cast --- norm_num - --- @[simp] --- theorem one_lt_bit0 {a : Cardinal} : 1 < bit0 a ↔ 0 < a := by simp [← bit1_zero] - --- @[simp] --- theorem one_lt_bit1 (a : Cardinal) : 1 < bit1 a ↔ 0 < a := by simp [← bit1_zero] - --- end Bit +end extend end Cardinal -section Initial - -namespace Ordinal - -/-- -`ω_ o` is a notation for the *initial ordinal* of cardinality -`aleph o`. Thus, for example `ω_ 0 = ω`. --/ -scoped notation "ω_" o => ord <| aleph o - -/-- -`ω₁` is the first uncountable ordinal. --/ -scoped notation "ω₁" => ord <| aleph 1 - -lemma omega0_lt_omega1 : ω < ω₁ := ord_aleph0.symm.trans_lt (ord_lt_ord.mpr (aleph0_lt_aleph_one)) - -section OrdinalIndices /-! ### Cardinal operations with ordinal indices Results on cardinality of ordinal-indexed families of sets. -/ + +namespace Ordinal namespace Cardinal open scoped Cardinal @@ -1487,9 +841,4 @@ lemma mk_iUnion_Ordinal_le_of_le {β : Type*} {o : Ordinal} {c : Cardinal} exact mul_le_mul' ho <| ciSup_le' <| (hA _ <| typein_lt_self ·) end Cardinal - -end OrdinalIndices - end Ordinal - -end Initial diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 2a607f4838215..ff45f9744bc0b 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -3,13 +3,15 @@ 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.Nat.Cast.Order.Basic import Mathlib.Data.Set.Countable import Mathlib.Logic.Small.Set +import Mathlib.Order.ConditionallyCompleteLattice.Indexed +import Mathlib.Order.InitialSeg import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.SetTheory.Cardinal.SchroederBernstein -import Mathlib.Algebra.Order.Ring.Nat -import Mathlib.Data.Nat.Cast.Order.Basic /-! # Cardinal Numbers @@ -79,7 +81,7 @@ Cantor's theorem, König's theorem, Konig's theorem assert_not_exists Field open Mathlib (Vector) -open Function Set Order +open Function Order Set noncomputable section @@ -139,7 +141,8 @@ theorem induction_on_pi {ι : Type u} {p : (ι → Cardinal.{v}) → Prop} protected theorem eq : #α = #β ↔ Nonempty (α ≃ β) := Quotient.eq' -@[simp] +/-- Avoid using `Quotient.mk` to construct a `Cardinal` directly -/ +@[deprecated (since := "2024-10-24")] theorem mk'_def (α : Type u) : @Eq Cardinal ⟦α⟧ #α := rfl @@ -257,8 +260,6 @@ theorem lift_id (a : Cardinal) : lift.{u, u} a = a := lift_id'.{u, u} a /-- A cardinal lifted to the zero universe equals itself. -/ --- porting note (#10618): simp can prove this --- @[simp] theorem lift_uzero (a : Cardinal.{u}) : lift.{0} a = a := lift_id'.{0, u} a @@ -266,6 +267,10 @@ theorem lift_uzero (a : Cardinal.{u}) : lift.{0} a = a := theorem lift_lift.{u_1} (a : Cardinal.{u_1}) : lift.{w} (lift.{v} a) = lift.{max v w} a := inductionOn a fun _ => (Equiv.ulift.trans <| Equiv.ulift.trans Equiv.ulift.symm).cardinal_eq +theorem out_lift_equiv (a : Cardinal.{u}) : Nonempty ((lift.{v} a).out ≃ a.out) := by + rw [← mk_out a, ← mk_uLift, mk_out] + exact ⟨outMkEquiv.trans Equiv.ulift⟩ + @[simp] lemma mk_preimage_down {s : Set α} : #(ULift.down.{v} ⁻¹' s) = lift.{v} (#s) := by rw [← mk_uLift, Cardinal.eq] @@ -276,9 +281,7 @@ lemma mk_preimage_down {s : Set α} : #(ULift.down.{v} ⁻¹' s) = lift.{v} (#s) exact Equiv.ofBijective f this theorem out_embedding {c c' : Cardinal} : c ≤ c' ↔ Nonempty (c.out ↪ c'.out) := by - trans - · rw [← Quotient.out_eq c, ← Quotient.out_eq c'] - · rw [mk'_def, mk'_def, le_def] + 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 (α ↪ β) := @@ -305,12 +308,6 @@ we provide this statement separately so you don't have to solve the specializati theorem lift_mk_eq' {α : Type u} {β : Type v} : lift.{v} #α = lift.{u} #β ↔ Nonempty (α ≃ β) := lift_mk_eq.{u, v, 0} -@[simp] -theorem lift_le {a b : Cardinal.{v}} : lift.{u, v} a ≤ lift.{u, v} b ↔ a ≤ b := - inductionOn₂ a b fun α β => by - rw [← lift_umax] - exact lift_mk_le.{u} - -- Porting note: simpNF is not happy with universe levels. @[simp, nolint simpNF] theorem lift_mk_shrink (α : Type u) [Small.{v} α] : @@ -327,32 +324,48 @@ 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] +/-- `Cardinal.lift` as an `InitialSeg`. -/ +@[simps!] +def liftInitialSeg : Cardinal.{u} ≤i Cardinal.{max u v} := by + refine ⟨(OrderEmbedding.ofMapLEIff lift ?_).ltEmbedding, ?_⟩ <;> intro a b + · refine inductionOn₂ a b fun _ _ ↦ ?_ + rw [← lift_umax, lift_mk_le.{v, u, u}, le_def] + · refine inductionOn₂ a b fun α β h ↦ ?_ + obtain ⟨e⟩ := h.le + replace e := e.congr (Equiv.refl β) Equiv.ulift + refine ⟨#(range e), mk_congr (Equiv.ulift.trans <| Equiv.symm ?_)⟩ + apply (e.codRestrict _ mem_range_self).equivOfSurjective + rintro ⟨a, ⟨b, rfl⟩⟩ + exact ⟨b, rfl⟩ + +theorem mem_range_lift_of_le {a : Cardinal.{u}} {b : Cardinal.{max u v}} : + b ≤ lift.{v, u} a → b ∈ Set.range lift.{v, u} := + liftInitialSeg.mem_range_of_le + +@[deprecated mem_range_lift_of_le (since := "2024-10-07")] theorem lift_down {a : Cardinal.{u}} {b : Cardinal.{max u v}} : - b ≤ lift.{v,u} a → ∃ a', lift.{v,u} a' = b := - inductionOn₂ a b fun α β => by - rw [← lift_id #β, ← lift_umax, ← lift_umax.{u, v}, lift_mk_le.{v}] - exact fun ⟨f⟩ => - ⟨#(Set.range f), - Eq.symm <| lift_mk_eq.{_, _, v}.2 - ⟨Function.Embedding.equivOfSurjective (Embedding.codRestrict _ f Set.mem_range_self) - fun ⟨a, ⟨b, e⟩⟩ => ⟨b, Subtype.eq e⟩⟩⟩ - --- Porting note: changed `simps` to `simps!` because the linter told to do so. + b ≤ lift.{v, u} a → ∃ a', lift.{v, u} a' = b := + mem_range_lift_of_le + /-- `Cardinal.lift` as an `OrderEmbedding`. -/ -@[simps! (config := .asFn)] +@[deprecated Cardinal.liftInitialSeg (since := "2024-10-07")] def liftOrderEmbedding : Cardinal.{v} ↪o Cardinal.{max v u} := - OrderEmbedding.ofMapLEIff lift.{u, v} fun _ _ => lift_le + liftInitialSeg.toOrderEmbedding theorem lift_injective : Injective lift.{u, v} := - liftOrderEmbedding.injective + liftInitialSeg.injective @[simp] theorem lift_inj {a b : Cardinal.{u}} : lift.{v, u} a = lift.{v, u} b ↔ a = b := lift_injective.eq_iff +@[simp] +theorem lift_le {a b : Cardinal.{v}} : lift.{u} a ≤ lift.{u} b ↔ a ≤ b := + liftInitialSeg.le_iff_le + @[simp] theorem lift_lt {a b : Cardinal.{u}} : lift.{v, u} a < lift.{v, u} b ↔ a < b := - liftOrderEmbedding.lt_iff_lt + liftInitialSeg.lt_iff_lt theorem lift_strictMono : StrictMono lift := fun _ _ => lift_lt.2 @@ -374,18 +387,12 @@ theorem lift_umax_eq {a : Cardinal.{u}} {b : Cardinal.{v}} : rw [← lift_lift.{v, w, u}, ← lift_lift.{u, w, v}, lift_inj] theorem le_lift_iff {a : Cardinal.{u}} {b : Cardinal.{max u v}} : - b ≤ lift.{v, u} a ↔ ∃ a', lift.{v, u} a' = b ∧ a' ≤ a := - ⟨fun h => - let ⟨a', e⟩ := lift_down h - ⟨a', e, lift_le.1 <| e.symm ▸ h⟩, - fun ⟨_, e, h⟩ => e ▸ lift_le.2 h⟩ + b ≤ lift.{v, u} a ↔ ∃ a' ≤ a, lift.{v, u} a' = b := + liftInitialSeg.le_apply_iff theorem lt_lift_iff {a : Cardinal.{u}} {b : Cardinal.{max u v}} : - b < lift.{v, u} a ↔ ∃ a', lift.{v, u} a' = b ∧ a' < a := - ⟨fun h => - let ⟨a', e⟩ := lift_down h.le - ⟨a', e, lift_lt.1 <| e.symm ▸ h⟩, - fun ⟨_, e, h⟩ => e ▸ lift_lt.2 h⟩ + b < lift.{v, u} a ↔ ∃ a' < a, lift.{v, u} a' = b := + liftInitialSeg.lt_apply_iff /-! ### Basic cardinals -/ @@ -427,8 +434,8 @@ instance : One Cardinal.{u} := instance : Nontrivial Cardinal.{u} := ⟨⟨1, 0, mk_ne_zero _⟩⟩ -theorem mk_eq_one (α : Type u) [Unique α] : #α = 1 := - (Equiv.equivOfUnique α (ULift (Fin 1))).cardinal_eq +theorem mk_eq_one (α : Type u) [Subsingleton α] [Nonempty α] : #α = 1 := + let ⟨_⟩ := nonempty_unique α; (Equiv.equivOfUnique α (ULift (Fin 1))).cardinal_eq theorem le_one_iff_subsingleton {α : Type u} : #α ≤ 1 ↔ Subsingleton α := ⟨fun ⟨f⟩ => ⟨fun _ _ => f.injective (Subsingleton.elim _ _)⟩, fun ⟨h⟩ => @@ -515,8 +522,8 @@ instance commSemiring : CommSemiring Cardinal.{u} where add_zero a := inductionOn a fun α => mk_congr <| Equiv.sumEmpty α _ add_assoc a b c := inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.sumAssoc α β γ add_comm a b := inductionOn₂ a b fun α β => mk_congr <| Equiv.sumComm α β - zero_mul a := inductionOn a fun α => mk_eq_zero _ - mul_zero a := inductionOn a fun α => mk_eq_zero _ + zero_mul a := inductionOn a fun _ => mk_eq_zero _ + mul_zero a := inductionOn a fun _ => mk_eq_zero _ one_mul a := inductionOn a fun α => mk_congr <| Equiv.uniqueProd α _ mul_one a := inductionOn a fun α => mk_congr <| Equiv.prodUnique α _ mul_assoc a b c := inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.prodAssoc α β γ @@ -535,12 +542,8 @@ instance commSemiring : CommSemiring Cardinal.{u} where theorem one_power {a : Cardinal} : (1 : Cardinal) ^ a = 1 := inductionOn a fun _ => mk_eq_one _ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_bool : #Bool = 2 := by simp --- porting note (#10618): simp can prove this --- @[simp] theorem mk_Prop : #Prop = 2 := by simp @[simp] @@ -563,10 +566,13 @@ theorem power_mul {a b c : Cardinal} : a ^ (b * c) = (a ^ b) ^ c := by rw [mul_comm b c] exact inductionOn₃ a b c fun α β γ => mk_congr <| Equiv.curry γ β α -@[simp] -theorem pow_cast_right (a : Cardinal.{u}) (n : ℕ) : a ^ (↑n : Cardinal.{u}) = a ^ n := +@[simp, norm_cast] +theorem power_natCast (a : Cardinal.{u}) (n : ℕ) : a ^ (↑n : Cardinal.{u}) = a ^ n := rfl +@[deprecated (since := "2024-10-16")] +alias power_cast_right := power_natCast + @[simp] theorem lift_one : lift 1 = 1 := mk_eq_one _ @@ -607,10 +613,10 @@ protected theorem zero_le : ∀ a : Cardinal, 0 ≤ a := by private theorem add_le_add' : ∀ {a b c d : Cardinal}, a ≤ b → c ≤ d → a + c ≤ b + d := by rintro ⟨α⟩ ⟨β⟩ ⟨γ⟩ ⟨δ⟩ ⟨e₁⟩ ⟨e₂⟩; exact ⟨e₁.sumMap e₂⟩ -instance add_covariantClass : CovariantClass Cardinal Cardinal (· + ·) (· ≤ ·) := +instance addLeftMono : AddLeftMono Cardinal := ⟨fun _ _ _ => add_le_add' le_rfl⟩ -instance add_swap_covariantClass : CovariantClass Cardinal Cardinal (swap (· + ·)) (· ≤ ·) := +instance addRightMono : AddRightMono Cardinal := ⟨fun _ _ _ h => add_le_add' h le_rfl⟩ instance canonicallyOrderedCommSemiring : CanonicallyOrderedCommSemiring Cardinal.{u} := @@ -618,7 +624,7 @@ instance canonicallyOrderedCommSemiring : CanonicallyOrderedCommSemiring Cardina Cardinal.partialOrder with bot := 0 bot_le := Cardinal.zero_le - add_le_add_left := fun a b => add_le_add_left + add_le_add_left := fun _ _ => add_le_add_left exists_add_of_le := fun {a b} => inductionOn₂ a b fun α β ⟨⟨f, hf⟩⟩ => have : α ⊕ ((range f)ᶜ : Set β) ≃ β := by @@ -626,7 +632,7 @@ instance canonicallyOrderedCommSemiring : CanonicallyOrderedCommSemiring Cardina exact (Equiv.sumCongr (Equiv.ofInjective f hf) (Equiv.refl _)).trans <| Equiv.Set.sumCompl (range f) ⟨#(↥(range f)ᶜ), mk_congr this.symm⟩ - le_self_add := fun a b => (add_zero a).ge.trans <| add_le_add_left (Cardinal.zero_le _) _ + le_self_add := fun a _ => (add_zero a).ge.trans <| add_le_add_left (Cardinal.zero_le _) _ eq_zero_or_eq_zero_of_mul_eq_zero := fun {a b} => inductionOn₂ a b fun α β => by simpa only [mul_def, mk_eq_zero_iff, isEmpty_prod] using id } @@ -784,7 +790,7 @@ theorem add_one_le_succ (c : Cardinal.{u}) : c + 1 ≤ succ c := by theorem lift_succ (a) : lift.{v, u} (succ a) = succ (lift.{v, u} a) := le_antisymm (le_of_not_gt fun h => by - rcases lt_lift_iff.1 h with ⟨b, e, h⟩ + rcases lt_lift_iff.1 h with ⟨b, h, e⟩ rw [lt_succ_iff, ← lift_le, e] at h exact h.not_lt (lt_succ _)) (succ_le_of_lt <| lift_lt.2 <| lt_succ a) @@ -847,6 +853,34 @@ theorem iSup_le_sum {ι} (f : ι → Cardinal) : iSup f ≤ sum f := theorem mk_sigma {ι} (f : ι → Type*) : #(Σ i, f i) = sum fun i => #(f i) := mk_congr <| Equiv.sigmaCongrRight fun _ => outMkEquiv.symm +theorem mk_sigma_congr_lift {ι : Type v} {ι' : Type v'} {f : ι → Type w} {g : ι' → Type w'} + (e : ι ≃ ι') (h : ∀ i, lift.{w'} #(f i) = lift.{w} #(g (e i))) : + lift.{max v' w'} #(Σ i, f i) = lift.{max v w} #(Σ i, g i) := + Cardinal.lift_mk_eq'.2 ⟨.sigmaCongr e fun i ↦ Classical.choice <| Cardinal.lift_mk_eq'.1 (h i)⟩ + +theorem mk_sigma_congr {ι ι' : Type u} {f : ι → Type v} {g : ι' → Type v} (e : ι ≃ ι') + (h : ∀ i, #(f i) = #(g (e i))) : #(Σ i, f i) = #(Σ i, g i) := + mk_congr <| Equiv.sigmaCongr e fun i ↦ Classical.choice <| Cardinal.eq.mp (h i) + +/-- Similar to `mk_sigma_congr` with indexing types in different universes. This is not a strict +generalization. -/ +theorem mk_sigma_congr' {ι : Type u} {ι' : Type v} {f : ι → Type max w (max u v)} + {g : ι' → Type max w (max u v)} (e : ι ≃ ι') + (h : ∀ i, #(f i) = #(g (e i))) : #(Σ i, f i) = #(Σ i, g i) := + mk_congr <| Equiv.sigmaCongr e fun i ↦ Classical.choice <| Cardinal.eq.mp (h i) + +theorem mk_sigma_congrRight {ι : Type u} {f g : ι → Type v} (h : ∀ i, #(f i) = #(g i)) : + #(Σ i, f i) = #(Σ i, g i) := + mk_sigma_congr (Equiv.refl ι) h + +theorem mk_psigma_congrRight {ι : Type u} {f g : ι → Type v} (h : ∀ i, #(f i) = #(g i)) : + #(Σ' i, f i) = #(Σ' i, g i) := + mk_congr <| .psigmaCongrRight fun i => Classical.choice <| Cardinal.eq.mp (h i) + +theorem mk_psigma_congrRight_prop {ι : Prop} {f g : ι → Type v} (h : ∀ i, #(f i) = #(g i)) : + #(Σ' i, f i) = #(Σ' i, g i) := + mk_congr <| .psigmaCongrRight fun i => Classical.choice <| Cardinal.eq.mp (h i) + theorem mk_sigma_arrow {ι} (α : Type*) (f : ι → Type*) : #(Sigma f → α) = #(Π i, f i → α) := mk_congr <| Equiv.piCurry fun _ _ ↦ α @@ -940,6 +974,12 @@ instance WellOrderingRel.isWellOrder : IsWellOrder α WellOrderingRel := instance IsWellOrder.subtype_nonempty : Nonempty { r // IsWellOrder α r } := ⟨⟨WellOrderingRel, inferInstance⟩⟩ +variable (α) in +/-- The **well-ordering theorem** (or **Zermelo's theorem**): every type has a well-order -/ +theorem exists_wellOrder : ∃ (_ : LinearOrder α), WellFoundedLT α := by + classical + exact ⟨linearOrderOfSTO WellOrderingRel, WellOrderingRel.isWellOrder.toIsWellFounded⟩ + /-! ### Small sets of cardinals -/ namespace Cardinal @@ -965,7 +1005,7 @@ instance small_Ioo (a b : Cardinal.{u}) : Small.{u} (Ioo a b) := small_subset Io /-- A set of cardinals is bounded above iff it's small, i.e. it corresponds to a usual ZFC set. -/ theorem bddAbove_iff_small {s : Set Cardinal.{u}} : BddAbove s ↔ Small.{u} s := - ⟨fun ⟨a, ha⟩ => @small_subset _ (Iic a) s (fun x h => ha h) _, by + ⟨fun ⟨a, ha⟩ => @small_subset _ (Iic a) s (fun _ h => ha h) _, by rintro ⟨ι, ⟨e⟩⟩ suffices (range fun x : ι => (e.symm x).1) = s by rw [← this] @@ -1006,7 +1046,7 @@ theorem lift_sSup {s : Set Cardinal} (hs : BddAbove s) : apply ((le_csSup_iff' (bddAbove_image.{_,u} _ hs)).2 fun c hc => _).antisymm (csSup_le' _) · intro c hc by_contra h - obtain ⟨d, rfl⟩ := Cardinal.lift_down (not_le.1 h).le + obtain ⟨d, rfl⟩ := Cardinal.mem_range_lift_of_le (not_le.1 h).le simp_rw [lift_le] at h hc rw [csSup_le_iff' hs] at h exact h fun a ha => lift_le.1 <| hc (mem_image_of_mem _ ha) @@ -1093,6 +1133,34 @@ def prod {ι : Type u} (f : ι → Cardinal) : Cardinal := theorem mk_pi {ι : Type u} (α : ι → Type v) : #(Π i, α i) = prod fun i => #(α i) := mk_congr <| Equiv.piCongrRight fun _ => outMkEquiv.symm +theorem mk_pi_congr_lift {ι : Type v} {ι' : Type v'} {f : ι → Type w} {g : ι' → Type w'} + (e : ι ≃ ι') (h : ∀ i, lift.{w'} #(f i) = lift.{w} #(g (e i))) : + lift.{max v' w'} #(Π i, f i) = lift.{max v w} #(Π i, g i) := + Cardinal.lift_mk_eq'.2 ⟨.piCongr e fun i ↦ Classical.choice <| Cardinal.lift_mk_eq'.1 (h i)⟩ + +theorem mk_pi_congr {ι ι' : Type u} {f : ι → Type v} {g : ι' → Type v} (e : ι ≃ ι') + (h : ∀ i, #(f i) = #(g (e i))) : #(Π i, f i) = #(Π i, g i) := + mk_congr <| Equiv.piCongr e fun i ↦ Classical.choice <| Cardinal.eq.mp (h i) + +theorem mk_pi_congr_prop {ι ι' : Prop} {f : ι → Type v} {g : ι' → Type v} (e : ι ↔ ι') + (h : ∀ i, #(f i) = #(g (e.mp i))) : #(Π i, f i) = #(Π i, g i) := + mk_congr <| Equiv.piCongr (.ofIff e) fun i ↦ Classical.choice <| Cardinal.eq.mp (h i) + +/-- Similar to `mk_pi_congr` with indexing types in different universes. This is not a strict +generalization. -/ +theorem mk_pi_congr' {ι : Type u} {ι' : Type v} {f : ι → Type max w (max u v)} + {g : ι' → Type max w (max u v)} (e : ι ≃ ι') + (h : ∀ i, #(f i) = #(g (e i))) : #(Π i, f i) = #(Π i, g i) := + mk_congr <| Equiv.piCongr e fun i ↦ Classical.choice <| Cardinal.eq.mp (h i) + +theorem mk_pi_congrRight {ι : Type u} {f g : ι → Type v} (h : ∀ i, #(f i) = #(g i)) : + #(Π i, f i) = #(Π i, g i) := + mk_pi_congr (Equiv.refl ι) h + +theorem mk_pi_congrRight_prop {ι : Prop} {f g : ι → Type v} (h : ∀ i, #(f i) = #(g i)) : + #(Π i, f i) = #(Π i, g i) := + mk_pi_congr_prop Iff.rfl h + @[simp] theorem prod_const (ι : Type u) (a : Cardinal.{v}) : (prod fun _ : ι => a) = lift.{u} a ^ lift.{v} #ι := @@ -1189,24 +1257,30 @@ theorem lift_aleph0 : lift ℵ₀ = ℵ₀ := @[simp] theorem aleph0_le_lift {c : Cardinal.{u}} : ℵ₀ ≤ lift.{v} c ↔ ℵ₀ ≤ c := by - rw [← lift_aleph0.{v, u}, lift_le] + simpa using lift_le (a := ℵ₀) @[simp] theorem lift_le_aleph0 {c : Cardinal.{u}} : lift.{v} c ≤ ℵ₀ ↔ c ≤ ℵ₀ := by - rw [← lift_aleph0.{v, u}, lift_le] + simpa using lift_le (b := ℵ₀) @[simp] theorem aleph0_lt_lift {c : Cardinal.{u}} : ℵ₀ < lift.{v} c ↔ ℵ₀ < c := by - rw [← lift_aleph0.{v, u}, lift_lt] + simpa using lift_lt (a := ℵ₀) @[simp] theorem lift_lt_aleph0 {c : Cardinal.{u}} : lift.{v} c < ℵ₀ ↔ c < ℵ₀ := by - rw [← lift_aleph0.{v, u}, lift_lt] + simpa using lift_lt (b := ℵ₀) + +@[simp] +theorem aleph0_eq_lift {c : Cardinal.{u}} : ℵ₀ = lift.{v} c ↔ ℵ₀ = c := by + simpa using lift_inj (a := ℵ₀) + +@[simp] +theorem lift_eq_aleph0 {c : Cardinal.{u}} : lift.{v} c = ℵ₀ ↔ c = ℵ₀ := by + simpa using lift_inj (b := ℵ₀) /-! ### Properties about the cast from `ℕ` -/ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_fin (n : ℕ) : #(Fin n) = n := by simp @[simp] @@ -1319,42 +1393,33 @@ theorem mk_finset_of_fintype [Fintype α] : #(Finset α) = 2 ^ Fintype.card α : theorem card_le_of_finset {α} (s : Finset α) : (s.card : Cardinal) ≤ #α := @mk_coe_finset _ s ▸ mk_set_le _ --- Porting note: was `simp`. LHS is not normal form. --- @[simp, norm_cast] -@[norm_cast] -theorem natCast_pow {m n : ℕ} : (↑(m ^ n) : Cardinal) = (↑m : Cardinal) ^ (↑n : Cardinal) := by - induction n <;> simp [pow_succ, power_add, *, Pow.pow] +instance : CharZero Cardinal := by + refine ⟨fun a b h ↦ ?_⟩ + rwa [← lift_mk_fin, ← lift_mk_fin, lift_inj, Cardinal.eq, ← Fintype.card_eq, + Fintype.card_fin, Fintype.card_fin] at h --- porting note (#10618): simp can prove this --- @[simp, norm_cast] -@[norm_cast] -theorem natCast_le {m n : ℕ} : (m : Cardinal) ≤ n ↔ m ≤ n := by - rw [← lift_mk_fin, ← lift_mk_fin, lift_le, le_def, Function.Embedding.nonempty_iff_card_le, - Fintype.card_fin, Fintype.card_fin] +@[deprecated Nat.cast_le (since := "2024-10-16")] +theorem natCast_le {m n : ℕ} : (m : Cardinal) ≤ n ↔ m ≤ n := Nat.cast_le --- porting note (#10618): simp can prove this --- @[simp, norm_cast] -@[norm_cast] -theorem natCast_lt {m n : ℕ} : (m : Cardinal) < n ↔ m < n := by - rw [lt_iff_le_not_le, ← not_le] - simp only [natCast_le, not_le, and_iff_right_iff_imp] - exact fun h ↦ le_of_lt h +@[deprecated Nat.cast_lt (since := "2024-10-16")] +theorem natCast_lt {m n : ℕ} : (m : Cardinal) < n ↔ m < n := Nat.cast_lt -instance : CharZero Cardinal := - ⟨StrictMono.injective fun _ _ => natCast_lt.2⟩ +@[deprecated Nat.cast_inj (since := "2024-10-16")] +theorem natCast_inj {m n : ℕ} : (m : Cardinal) = n ↔ m = n := Nat.cast_inj -theorem natCast_inj {m n : ℕ} : (m : Cardinal) = n ↔ m = n := - Nat.cast_inj +@[deprecated Nat.cast_injective (since := "2024-10-16")] +theorem natCast_injective : Injective ((↑) : ℕ → Cardinal) := Nat.cast_injective -theorem natCast_injective : Injective ((↑) : ℕ → Cardinal) := - Nat.cast_injective +@[deprecated Nat.cast_pow (since := "2024-10-16")] +theorem natCast_pow {m n : ℕ} : (↑(m ^ n) : Cardinal) = (↑m : Cardinal) ^ (↑n : Cardinal) := + Nat.cast_pow m n @[norm_cast] theorem nat_succ (n : ℕ) : (n.succ : Cardinal) = succ ↑n := by rw [Nat.cast_succ] refine (add_one_le_succ _).antisymm (succ_le_of_lt ?_) rw [← Nat.cast_succ] - exact natCast_lt.2 (Nat.lt_succ_self _) + exact Nat.cast_lt.2 (Nat.lt_succ_self _) lemma succ_natCast (n : ℕ) : Order.succ (n : Cardinal) = n + 1 := by rw [← Cardinal.nat_succ] @@ -1370,6 +1435,9 @@ lemma two_le_iff_one_lt {c : Cardinal} : 2 ≤ c ↔ 1 < c := by @[simp] theorem succ_zero : succ (0 : Cardinal) = 1 := by norm_cast +-- This works generally to prove inequalities between numeric cardinals. +theorem one_lt_two : (1 : Cardinal) < 2 := by norm_cast + theorem exists_finset_le_card (α : Type*) (n : ℕ) (h : n ≤ #α) : ∃ s : Finset α, n ≤ s.card := by obtain hα|hα := finite_or_infinite α @@ -1409,29 +1477,30 @@ theorem nat_lt_aleph0 (n : ℕ) : (n : Cardinal.{u}) < ℵ₀ := @[simp] theorem one_lt_aleph0 : 1 < ℵ₀ := by simpa using nat_lt_aleph0 1 +@[simp] theorem one_le_aleph0 : 1 ≤ ℵ₀ := one_lt_aleph0.le theorem lt_aleph0 {c : Cardinal} : c < ℵ₀ ↔ ∃ n : ℕ, c = n := ⟨fun h => by - rcases lt_lift_iff.1 h with ⟨c, rfl, h'⟩ + rcases lt_lift_iff.1 h with ⟨c, h', rfl⟩ rcases le_mk_iff_exists_set.1 h'.1 with ⟨S, rfl⟩ suffices S.Finite by lift S to Finset ℕ using this simp contrapose! h' haveI := Infinite.to_subtype h' - exact ⟨Infinite.natEmbedding S⟩, fun ⟨n, e⟩ => e.symm ▸ nat_lt_aleph0 _⟩ + exact ⟨Infinite.natEmbedding S⟩, fun ⟨_, e⟩ => e.symm ▸ nat_lt_aleph0 _⟩ lemma succ_eq_of_lt_aleph0 {c : Cardinal} (h : c < ℵ₀) : Order.succ c = c + 1 := by obtain ⟨n, hn⟩ := Cardinal.lt_aleph0.mp h rw [hn, succ_natCast] theorem aleph0_le {c : Cardinal} : ℵ₀ ≤ c ↔ ∀ n : ℕ, ↑n ≤ c := - ⟨fun h n => (nat_lt_aleph0 _).le.trans h, fun h => + ⟨fun h _ => (nat_lt_aleph0 _).le.trans h, fun h => le_of_not_lt fun hn => by rcases lt_aleph0.1 hn with ⟨n, rfl⟩ - exact (Nat.lt_succ_self _).not_le (natCast_le.1 (h (n + 1)))⟩ + exact (Nat.lt_succ_self _).not_le (Nat.cast_le.1 (h (n + 1)))⟩ theorem isSuccPrelimit_aleph0 : IsSuccPrelimit ℵ₀ := isSuccPrelimit_of_succ_lt fun a ha => by @@ -1496,8 +1565,6 @@ theorem lt_aleph0_iff_fintype {α : Type u} : #α < ℵ₀ ↔ Nonempty (Fintype theorem lt_aleph0_of_finite (α : Type u) [Finite α] : #α < ℵ₀ := lt_aleph0_iff_finite.2 ‹_› --- porting note (#10618): simp can prove this --- @[simp] theorem lt_aleph0_iff_set_finite {S : Set α} : #S < ℵ₀ ↔ S.Finite := lt_aleph0_iff_finite.trans finite_coe_iff @@ -1514,8 +1581,6 @@ theorem mk_le_aleph0_iff : #α ≤ ℵ₀ ↔ Countable α := by theorem mk_le_aleph0 [Countable α] : #α ≤ ℵ₀ := mk_le_aleph0_iff.mpr ‹_› --- porting note (#10618): simp can prove this --- @[simp] theorem le_aleph0_iff_set_countable {s : Set α} : #s ≤ ℵ₀ ↔ s.Countable := mk_le_aleph0_iff alias ⟨_, _root_.Set.Countable.le_aleph0⟩ := le_aleph0_iff_set_countable @@ -1591,7 +1656,7 @@ theorem mul_lt_aleph0_iff_of_ne_zero {a b : Cardinal} (ha : a ≠ 0) (hb : b ≠ theorem power_lt_aleph0 {a b : Cardinal} (ha : a < ℵ₀) (hb : b < ℵ₀) : a ^ b < ℵ₀ := match a, b, lt_aleph0.1 ha, lt_aleph0.1 hb with - | _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by rw [← natCast_pow]; apply nat_lt_aleph0 + | _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by rw [power_natCast, ← Nat.cast_pow]; apply nat_lt_aleph0 theorem eq_one_iff_unique {α : Type*} : #α = 1 ↔ Subsingleton α ∧ Nonempty α := calc @@ -1618,8 +1683,6 @@ theorem denumerable_iff {α : Type u} : Nonempty (Denumerable α) ↔ #α = ℵ cases' Quotient.exact h with f exact ⟨Denumerable.mk' <| f.trans Equiv.ulift⟩⟩ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_denumerable (α : Type u) [Denumerable α] : #α = ℵ₀ := denumerable_iff.1 ⟨‹_›⟩ @@ -1638,7 +1701,7 @@ theorem aleph0_mul_aleph0 : ℵ₀ * ℵ₀ = ℵ₀ := theorem nat_mul_aleph0 {n : ℕ} (hn : n ≠ 0) : ↑n * ℵ₀ = ℵ₀ := le_antisymm (lift_mk_fin n ▸ mk_le_aleph0) <| le_mul_of_one_le_left (zero_le _) <| by - rwa [← Nat.cast_one, natCast_le, Nat.one_le_iff_ne_zero] + rwa [← Nat.cast_one, Nat.cast_le, Nat.one_le_iff_ne_zero] @[simp] theorem aleph0_mul_nat {n : ℕ} (hn : n ≠ 0) : ℵ₀ * n = ℵ₀ := by rw [mul_comm, nat_mul_aleph0 hn] @@ -1687,36 +1750,31 @@ theorem mk_pNat : #ℕ+ = ℵ₀ := /-! ### Cardinalities of basic sets and types -/ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_empty : #Empty = 0 := mk_eq_zero _ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_pempty : #PEmpty = 0 := mk_eq_zero _ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_punit : #PUnit = 1 := mk_eq_one PUnit theorem mk_unit : #Unit = 1 := mk_punit --- porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem mk_additive : #(Additive α) = #α := rfl + +@[simp] theorem mk_multiplicative : #(Multiplicative α) = #α := rfl + +@[to_additive (attr := simp)] theorem mk_mulOpposite : #(MulOpposite α) = #α := + mk_congr MulOpposite.opEquiv.symm + theorem mk_singleton {α : Type u} (x : α) : #({x} : Set α) = 1 := mk_eq_one _ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_plift_true : #(PLift True) = 1 := mk_eq_one _ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_plift_false : #(PLift False) = 0 := mk_eq_zero _ @@ -1739,8 +1797,6 @@ theorem mk_subtype_le_of_subset {α : Type u} {p q : α → Prop} (h : ∀ ⦃x #(Subtype p) ≤ #(Subtype q) := ⟨Embedding.subtypeMap (Embedding.refl α) h⟩ --- porting note (#10618): simp can prove this --- @[simp] theorem mk_emptyCollection (α : Type u) : #(∅ : Set α) = 0 := mk_eq_zero _ @@ -1756,9 +1812,17 @@ theorem mk_emptyCollection_iff {α : Type u} {s : Set α} : #s = 0 ↔ s = ∅ : theorem mk_univ {α : Type u} : #(@univ α) = #α := mk_congr (Equiv.Set.univ α) +@[simp] lemma mk_setProd {α β : Type u} (s : Set α) (t : Set β) : #(s ×ˢ t) = #s * #t := by + rw [mul_def, mk_congr (Equiv.Set.prod ..)] + theorem mk_image_le {α β : Type u} {f : α → β} {s : Set α} : #(f '' s) ≤ #s := mk_le_of_surjective surjective_onto_image +lemma mk_image2_le {α β γ : Type u} {f : α → β → γ} {s : Set α} {t : Set β} : + #(image2 f s t) ≤ #s * #t := by + rw [← image_uncurry_prod, ← mk_setProd] + exact mk_image_le + theorem mk_image_le_lift {α : Type u} {β : Type v} {f : α → β} {s : Set α} : lift.{u} #(f '' s) ≤ lift.{v} #s := lift_mk_le.{0}.mpr ⟨Embedding.ofSurjective _ surjective_onto_image⟩ @@ -1890,7 +1954,7 @@ theorem mk_union_le {α : Type u} (S T : Set α) : #(S ∪ T : Set α) ≤ #S + theorem mk_union_of_disjoint {α : Type u} {S T : Set α} (H : Disjoint S T) : #(S ∪ T : Set α) = #S + #T := by classical - exact Quot.sound ⟨Equiv.Set.union H.le_bot⟩ + exact Quot.sound ⟨Equiv.Set.union H⟩ theorem mk_insert {α : Type u} {s : Set α} {a : α} (h : a ∉ s) : #(insert a s : Set α) = #s + 1 := by @@ -2025,7 +2089,7 @@ theorem exists_not_mem_of_length_lt {α : Type*} (l : List α) (h : ↑l.length #α = #(Set.univ : Set α) := mk_univ.symm _ ≤ #l.toFinset := mk_le_mk_of_subset fun x _ => List.mem_toFinset.mpr (h x) _ = l.toFinset.card := Cardinal.mk_coe_finset - _ ≤ l.length := Cardinal.natCast_le.mpr (List.toFinset_card_le l) + _ ≤ l.length := Nat.cast_le.mpr (List.toFinset_card_le l) theorem three_le {α : Type*} (h : 3 ≤ #α) (x : α) (y : α) : ∃ z : α, z ≠ x ∧ z ≠ y := by have : ↑(3 : ℕ) ≤ #α := by simpa using h diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index 53bfb76a4a06e..3e7d59f172e0d 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality.lean @@ -3,7 +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.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Ordinal.FixedPoint /-! @@ -79,21 +79,17 @@ theorem le_cof {r : α → α → Prop} [IsRefl α r] (c : Cardinal) : end Order theorem RelIso.cof_le_lift {α : Type u} {β : Type v} {r : α → α → Prop} {s} [IsRefl β s] - (f : r ≃r s) : Cardinal.lift.{max u v} (Order.cof r) ≤ - Cardinal.lift.{max u v} (Order.cof s) := by - rw [Order.cof, Order.cof, lift_sInf, lift_sInf, - le_csInf_iff'' ((Order.cof_nonempty s).image _)] + (f : r ≃r s) : Cardinal.lift.{v} (Order.cof r) ≤ Cardinal.lift.{u} (Order.cof s) := by + rw [Order.cof, Order.cof, lift_sInf, lift_sInf, le_csInf_iff'' ((Order.cof_nonempty s).image _)] rintro - ⟨-, ⟨u, H, rfl⟩, rfl⟩ apply csInf_le' - refine - ⟨_, ⟨f.symm '' u, fun a => ?_, rfl⟩, - lift_mk_eq.{u, v, max u v}.2 ⟨(f.symm.toEquiv.image u).symm⟩⟩ + refine ⟨_, ⟨f.symm '' u, fun a => ?_, rfl⟩, lift_mk_eq'.2 ⟨(f.symm.toEquiv.image u).symm⟩⟩ rcases H (f a) with ⟨b, hb, hb'⟩ refine ⟨f.symm b, mem_image_of_mem _ hb, f.map_rel_iff.1 ?_⟩ rwa [RelIso.apply_symm_apply] theorem RelIso.cof_eq_lift {α : Type u} {β : Type v} {r s} [IsRefl α r] [IsRefl β s] (f : r ≃r s) : - Cardinal.lift.{max u v} (Order.cof r) = Cardinal.lift.{max u v} (Order.cof s) := + Cardinal.lift.{v} (Order.cof r) = Cardinal.lift.{u} (Order.cof s) := (RelIso.cof_le_lift f).antisymm (RelIso.cof_le_lift f.symm) theorem RelIso.cof_le {α β : Type u} {r : α → α → Prop} {s} [IsRefl β s] (f : r ≃r s) : @@ -124,19 +120,11 @@ namespace Ordinal `∀ a, ∃ b ∈ S, a ≤ b`. It is defined for all ordinals, but `cof 0 = 0` and `cof (succ o) = 1`, so it is only really interesting on limit ordinals (when it is an infinite cardinal). -/ -def cof (o : Ordinal.{u}) : Cardinal.{u} := - o.liftOn (fun a => StrictOrder.cof a.r) - (by - rintro ⟨α, r, wo₁⟩ ⟨β, s, wo₂⟩ ⟨⟨f, hf⟩⟩ - haveI := wo₁; haveI := wo₂ - dsimp only - apply @RelIso.cof_eq _ _ _ _ ?_ ?_ - · constructor - exact @fun a b => not_iff_not.2 hf - · dsimp only [swap] - exact ⟨fun _ => irrefl _⟩ - · dsimp only [swap] - exact ⟨fun _ => irrefl _⟩) +def cof (o : Ordinal.{u}) : Cardinal.{u} := by + refine o.liftOn (fun a => StrictOrder.cof a.r) ?_ + rintro ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨⟨f, hf⟩⟩ + refine @RelIso.cof_eq _ _ _ _ ?_ ?_ ⟨_, not_iff_not.2 hf⟩ <;> + exact ⟨fun _ => irrefl _⟩ theorem cof_type (r : α → α → Prop) [IsWellOrder α r] : (type r).cof = StrictOrder.cof r := rfl @@ -206,7 +194,7 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = sInf { a : Cardinal | ∃ (ι : Type u) (f : ι → Ordinal), lsub.{u, u} f = o ∧ #ι = a } := by refine le_antisymm (le_csInf (cof_lsub_def_nonempty o) ?_) (csInf_le' ?_) · rintro a ⟨ι, f, hf, rfl⟩ - rw [← type_lt o] + rw [← type_toType o] refine (cof_type_le fun a => ?_).trans (@mk_le_of_injective _ _ @@ -220,7 +208,7 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = simp_rw [← hf, lt_lsub_iff] at this cases' this with i hi refine ⟨enum (α := o.toType) (· < ·) ⟨f i, ?_⟩, ?_, ?_⟩ - · rw [type_lt, ← hf] + · rw [type_toType, ← hf] apply lt_lsub · rw [mem_preimage, typein_enum] exact mem_range_self i @@ -228,8 +216,8 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = · rcases cof_eq (α := o.toType) (· < ·) with ⟨S, hS, hS'⟩ let f : S → Ordinal := fun s => typein LT.lt s.val refine ⟨S, f, le_antisymm (lsub_le fun i => typein_lt_self (o := o) i) - (le_of_forall_lt fun a ha => ?_), by rwa [type_lt o] at hS'⟩ - rw [← type_lt o] at ha + (le_of_forall_lt fun a ha => ?_), by rwa [type_toType o] at hS'⟩ + rw [← type_toType o] at ha rcases hS (enum (· < ·) ⟨a, ha⟩) with ⟨b, hb, hb'⟩ rw [← typein_le_typein, typein_enum] at hb' exact hb'.trans_lt (lt_lsub.{u, u} f ⟨b, hb⟩) @@ -381,7 +369,7 @@ theorem nfpFamily_lt_ord {ι} {f : ι → Ordinal → Ordinal} {c} (hc : ℵ₀ theorem nfpBFamily_lt_ord_lift {o : Ordinal} {f : ∀ a < o, Ordinal → Ordinal} {c} (hc : ℵ₀ < cof c) (hc' : Cardinal.lift.{v, u} o.card < cof c) (hf : ∀ (i hi), ∀ b < c, f i hi b < c) {a} : a < c → nfpBFamily.{u, v} o f a < c := - nfpFamily_lt_ord_lift hc (by rwa [mk_toType]) fun i => hf _ _ + nfpFamily_lt_ord_lift hc (by rwa [mk_toType]) fun _ => hf _ _ theorem nfpBFamily_lt_ord {o : Ordinal} {f : ∀ a < o, Ordinal → Ordinal} {c} (hc : ℵ₀ < cof c) (hc' : o.card < cof c) (hf : ∀ (i hi), ∀ b < c, f i hi b < c) {a} : @@ -456,11 +444,11 @@ theorem cof_zero : cof 0 = 0 := by @[simp] theorem cof_eq_zero {o} : cof o = 0 ↔ o = 0 := - ⟨inductionOn o fun α r _ z => - let ⟨S, hl, e⟩ := cof_eq r + ⟨inductionOn o fun _ r _ z => + let ⟨_, hl, e⟩ := cof_eq r type_eq_zero_iff_isEmpty.2 <| ⟨fun a => - let ⟨b, h, _⟩ := hl a + let ⟨_, h, _⟩ := hl a (mk_eq_zero_iff.1 (e.trans z)).elim' ⟨_, h⟩⟩, fun e => by simp [e]⟩ @@ -541,7 +529,7 @@ theorem id_of_le_cof (h : o ≤ o.cof.ord) : IsFundamentalSequence o o fun a _ = ⟨h, @fun _ _ _ _ => id, blsub_id o⟩ protected theorem zero {f : ∀ b < (0 : Ordinal), Ordinal} : IsFundamentalSequence 0 0 f := - ⟨by rw [cof_zero, ord_zero], @fun i j hi => (Ordinal.not_lt_zero i hi).elim, blsub_zero f⟩ + ⟨by rw [cof_zero, ord_zero], @fun i _ hi => (Ordinal.not_lt_zero i hi).elim, blsub_zero f⟩ protected theorem succ : IsFundamentalSequence (succ o) 1 fun _ _ => o := by refine ⟨?_, @fun i j hi hj h => ?_, blsub_const Ordinal.one_ne_zero o⟩ @@ -652,7 +640,7 @@ theorem cof_add (a b : Ordinal) : b ≠ 0 → cof (a + b) = cof b := fun h => by rcases zero_or_succ_or_limit b with (rfl | ⟨c, rfl⟩ | hb) · contradiction · rw [add_succ, cof_succ, cof_succ] - · exact (add_isNormal a).cof_eq hb + · exact (isNormal_add_right a).cof_eq hb theorem aleph0_le_cof {o} : ℵ₀ ≤ cof o ↔ IsLimit o := by rcases zero_or_succ_or_limit o with (rfl | ⟨o, rfl⟩ | l) @@ -672,16 +660,21 @@ theorem aleph0_le_cof {o} : ℵ₀ ≤ cof o ↔ IsLimit o := by exact not_succ_isLimit _ l @[simp] +theorem preAleph_cof {o : Ordinal} (ho : o.IsLimit) : (preAleph o).ord.cof = o.cof := + preAleph_isNormal.cof_eq ho + +set_option linter.deprecated false in +@[deprecated preAleph_cof (since := "2024-10-22")] theorem aleph'_cof {o : Ordinal} (ho : o.IsLimit) : (aleph' o).ord.cof = o.cof := aleph'_isNormal.cof_eq ho @[simp] -theorem aleph_cof {o : Ordinal} (ho : o.IsLimit) : (aleph o).ord.cof = o.cof := +theorem aleph_cof {o : Ordinal} (ho : o.IsLimit) : (ℵ_ o).ord.cof = o.cof := aleph_isNormal.cof_eq ho @[simp] theorem cof_omega0 : cof ω = ℵ₀ := - (aleph0_le_cof.2 omega0_isLimit).antisymm' <| by + (aleph0_le_cof.2 isLimit_omega0).antisymm' <| by rw [← card_omega0] apply cof_le_card @@ -712,7 +705,7 @@ theorem cof_univ : cof univ.{u, v} = Cardinal.univ.{u, v} := rcases @cof_eq Ordinal.{u} (· < ·) _ with ⟨S, H, Se⟩ rw [univ, ← lift_cof, ← Cardinal.lift_lift.{u+1, v, u}, Cardinal.lift_lt, ← Se] refine lt_of_not_ge fun h => ?_ - cases' Cardinal.lift_down h with a e + cases' Cardinal.mem_range_lift_of_le h with a e refine Quotient.inductionOn a (fun α e => ?_) e cases' Quotient.exact e with f have f := Equiv.ulift.symm.trans f @@ -825,7 +818,7 @@ set_option linter.deprecated false in theorem IsStrongLimit.isLimit {c} (H : IsStrongLimit c) : IsLimit c := ⟨H.ne_zero, H.isSuccPrelimit⟩ -theorem isStrongLimit_beth {o : Ordinal} (H : IsSuccPrelimit o) : IsStrongLimit (beth o) := by +theorem isStrongLimit_beth {o : Ordinal} (H : IsSuccPrelimit o) : IsStrongLimit (ℶ_ o) := by rcases eq_or_ne o 0 with (rfl | h) · rw [beth_zero] exact isStrongLimit_aleph0 @@ -862,7 +855,7 @@ theorem mk_bounded_subset {α : Type*} (h : ∀ x < #α, (2^x) < #α) {r : α · refine @mk_le_of_injective α _ (fun x => Subtype.mk {x} ?_) ?_ · apply bounded_singleton rw [← hr] - apply ord_isLimit ha + apply isLimit_ord ha · intro a b hab simpa [singleton_eq_singleton_iff] using hab @@ -881,7 +874,7 @@ theorem mk_subset_mk_lt_cof {α : Type*} (h : ∀ x < #α, (2^x) < #α) : exact lt_cof_type hs · refine @mk_le_of_injective α _ (fun x => Subtype.mk {x} ?_) ?_ · rw [mk_singleton] - exact one_lt_aleph0.trans_le (aleph0_le_cof.2 (ord_isLimit h'.aleph0_le)) + exact one_lt_aleph0.trans_le (aleph0_le_cof.2 (isLimit_ord h'.aleph0_le)) · intro a b hab simpa [singleton_eq_singleton_iff] using hab @@ -915,9 +908,10 @@ theorem isRegular_succ {c : Cardinal.{u}} (h : ℵ₀ ≤ c) : IsRegular (succ c ⟨h.trans (le_succ c), succ_le_of_lt (by - cases' Quotient.exists_rep (@succ Cardinal _ _ c) with α αe; simp only [mk'_def] at αe + have αe := Cardinal.mk_out (succ c) + set α := (succ c).out rcases ord_eq α with ⟨r, wo, re⟩ - have := ord_isLimit (h.trans (le_succ _)) + have := isLimit_ord (h.trans (le_succ _)) rw [← αe, re] at this ⊢ rcases cof_eq' r this with ⟨S, H, Se⟩ rw [← Se] @@ -932,15 +926,21 @@ theorem isRegular_succ {c : Cardinal.{u}} (h : ℵ₀ ≤ c) : IsRegular (succ c · rw [← lt_succ_iff, ← lt_ord, ← αe, re] apply typein_lt_type)⟩ -theorem isRegular_aleph_one : IsRegular (aleph 1) := by +theorem isRegular_aleph_one : IsRegular ℵ₁ := by rw [← succ_aleph0] exact isRegular_succ le_rfl +theorem isRegular_preAleph_succ {o : Ordinal} (h : ω ≤ o) : IsRegular (preAleph (succ o)) := by + rw [preAleph_succ] + exact isRegular_succ (aleph0_le_preAleph.2 h) + +set_option linter.deprecated false in +@[deprecated isRegular_preAleph_succ (since := "2024-10-22")] theorem isRegular_aleph'_succ {o : Ordinal} (h : ω ≤ o) : IsRegular (aleph' (succ o)) := by rw [aleph'_succ] exact isRegular_succ (aleph0_le_aleph'.2 h) -theorem isRegular_aleph_succ (o : Ordinal) : IsRegular (aleph (succ o)) := by +theorem isRegular_aleph_succ (o : Ordinal) : IsRegular (ℵ_ (succ o)) := by rw [aleph_succ] exact isRegular_succ (aleph0_le_aleph o) @@ -1091,7 +1091,7 @@ theorem nfpBFamily_lt_ord_lift_of_isRegular {o : Ordinal} {f : ∀ a < o, Ordina (hc : IsRegular c) (ho : Cardinal.lift.{v, u} o.card < c) (hc' : c ≠ ℵ₀) (hf : ∀ (i hi), ∀ b < c.ord, f i hi b < c.ord) {a} : a < c.ord → nfpBFamily.{u, v} o f a < c.ord := - nfpFamily_lt_ord_lift_of_isRegular hc (by rwa [mk_toType]) hc' fun i => hf _ _ + nfpFamily_lt_ord_lift_of_isRegular hc (by rwa [mk_toType]) hc' fun _ => hf _ _ theorem nfpBFamily_lt_ord_of_isRegular {o : Ordinal} {f : ∀ a < o, Ordinal → Ordinal} {c} (hc : IsRegular c) (ho : o.card < c) (hc' : c ≠ ℵ₀) @@ -1123,7 +1123,7 @@ theorem derivFamily_lt_ord_lift {ι} {f : ι → Ordinal → Ordinal} {c} (hc : rw [derivFamily_succ] exact nfpFamily_lt_ord_lift hω (by rwa [hc.cof_eq]) hf - ((ord_isLimit hc.1).2 _ (hb ((lt_succ b).trans hb'))) + ((isLimit_ord hc.1).2 _ (hb ((lt_succ b).trans hb'))) | H₃ b hb H => intro hb' rw [derivFamily_limit f hb] @@ -1140,7 +1140,7 @@ theorem derivBFamily_lt_ord_lift {o : Ordinal} {f : ∀ a < o, Ordinal → Ordin (hc : IsRegular c) (hι : Cardinal.lift.{v, u} o.card < c) (hc' : c ≠ ℵ₀) (hf : ∀ (i hi), ∀ b < c.ord, f i hi b < c.ord) {a} : a < c.ord → derivBFamily.{u, v} o f a < c.ord := - derivFamily_lt_ord_lift hc (by rwa [mk_toType]) hc' fun i => hf _ _ + derivFamily_lt_ord_lift hc (by rwa [mk_toType]) hc' fun _ => hf _ _ theorem derivBFamily_lt_ord {o : Ordinal} {f : ∀ a < o, Ordinal → Ordinal} {c} (hc : IsRegular c) (hι : o.card < c) (hc' : c ≠ ℵ₀) (hf : ∀ (i hi), ∀ b < c.ord, f i hi b < c.ord) {a} : @@ -1168,10 +1168,10 @@ theorem univ_inaccessible : IsInaccessible univ.{u, v} := apply lift_lt_univ' theorem lt_power_cof {c : Cardinal.{u}} : ℵ₀ ≤ c → c < (c^cof c.ord) := - Quotient.inductionOn c fun α h => by + Cardinal.inductionOn c fun α h => by rcases ord_eq α with ⟨r, wo, re⟩ - have := ord_isLimit h - rw [mk'_def, re] at this ⊢ + have := isLimit_ord h + rw [re] at this ⊢ rcases cof_eq' r this with ⟨S, H, Se⟩ have := sum_lt_prod (fun a : S => #{ x // r x a }) (fun _ => #α) fun i => ?_ · simp only [Cardinal.prod_const, Cardinal.lift_id, ← Se, ← mk_sigma, power_def] at this ⊢ @@ -1199,22 +1199,14 @@ namespace Ordinal open Cardinal open scoped Ordinal --- TODO: generalize universes +-- TODO: generalize universes, and use ω₁. lemma iSup_sequence_lt_omega1 {α : Type u} [Countable α] - (o : α → Ordinal.{max u v}) (ho : ∀ n, o n < ω₁) : - iSup o < ω₁ := by + (o : α → Ordinal.{max u v}) (ho : ∀ n, o n < (aleph 1).ord) : + iSup o < (aleph 1).ord := by apply iSup_lt_ord_lift _ ho rw [Cardinal.isRegular_aleph_one.cof_eq] exact lt_of_le_of_lt mk_le_aleph0 aleph0_lt_aleph_one -set_option linter.deprecated false in -@[deprecated iSup_sequence_lt_omega1 (since := "2024-08-27")] -lemma sup_sequence_lt_omega1 {α} [Countable α] (o : α → Ordinal) (ho : ∀ n, o n < ω₁) : - sup o < ω₁ := by - apply sup_lt_ord_lift _ ho - rw [Cardinal.isRegular_aleph_one.cof_eq] - exact lt_of_le_of_lt mk_le_aleph0 aleph0_lt_aleph_one - end Ordinal end Omega1 diff --git a/Mathlib/SetTheory/Cardinal/Continuum.lean b/Mathlib/SetTheory/Cardinal/Continuum.lean index 9aeb9a15becb8..b05977809225d 100644 --- a/Mathlib/SetTheory/Cardinal/Continuum.lean +++ b/Mathlib/SetTheory/Cardinal/Continuum.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic /-! # Cardinality of continuum @@ -23,14 +23,14 @@ universe u v open Cardinal -/-- Cardinality of continuum. -/ +/-- Cardinality of the continuum. -/ def continuum : Cardinal.{u} := 2 ^ ℵ₀ scoped notation "𝔠" => Cardinal.continuum @[simp] -theorem two_power_aleph0 : 2 ^ aleph0.{u} = continuum.{u} := +theorem two_power_aleph0 : 2 ^ ℵ₀ = 𝔠 := rfl @[simp] @@ -65,7 +65,7 @@ theorem aleph0_le_continuum : ℵ₀ ≤ 𝔠 := aleph0_lt_continuum.le @[simp] -theorem beth_one : beth 1 = 𝔠 := by simpa using beth_succ 0 +theorem beth_one : ℶ_ 1 = 𝔠 := by simpa using beth_succ 0 theorem nat_lt_continuum (n : ℕ) : ↑n < 𝔠 := (nat_lt_aleph0 n).trans aleph0_lt_continuum @@ -78,7 +78,7 @@ theorem continuum_pos : 0 < 𝔠 := theorem continuum_ne_zero : 𝔠 ≠ 0 := continuum_pos.ne' -theorem aleph_one_le_continuum : aleph 1 ≤ 𝔠 := by +theorem aleph_one_le_continuum : ℵ₁ ≤ 𝔠 := by rw [← succ_aleph0] exact Order.succ_le_of_lt aleph0_lt_continuum diff --git a/Mathlib/SetTheory/Cardinal/CountableCover.lean b/Mathlib/SetTheory/Cardinal/CountableCover.lean index 65caa5dd364f5..16eb4b46b329c 100644 --- a/Mathlib/SetTheory/Cardinal/CountableCover.lean +++ b/Mathlib/SetTheory/Cardinal/CountableCover.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 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.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.Order.Filter.Basic /-! diff --git a/Mathlib/SetTheory/Cardinal/Divisibility.lean b/Mathlib/SetTheory/Cardinal/Divisibility.lean index 4dac7f8531de2..6a176f3246b65 100644 --- a/Mathlib/SetTheory/Cardinal/Divisibility.lean +++ b/Mathlib/SetTheory/Cardinal/Divisibility.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ import Mathlib.Algebra.IsPrimePow -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.Tactic.WLOG /-! diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean index 08b850cedaa5a..350d46ef5b8f2 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -95,10 +95,6 @@ protected theorem bijective_iff_injective_and_card [Finite β] (f : α → β) : rw [← and_congr_right_iff, ← Bijective, card_eq_fintype_card, card_eq_fintype_card, Fintype.bijective_iff_injective_and_card] -#adaptation_note -/-- -After nightly-2024-09-06 we can remove the `_root_` prefixes below. --/ protected theorem bijective_iff_surjective_and_card [Finite α] (f : α → β) : Bijective f ↔ Surjective f ∧ Nat.card α = Nat.card β := by classical @@ -107,7 +103,7 @@ protected theorem bijective_iff_surjective_and_card [Finite α] (f : α → β) have := Fintype.ofFinite α have := Fintype.ofSurjective f h revert h - rw [← and_congr_left_iff, ← Bijective, ← _root_.and_comm, + rw [← and_congr_left_iff, ← Bijective, ← and_comm, card_eq_fintype_card, card_eq_fintype_card, Fintype.bijective_iff_surjective_and_card] theorem _root_.Function.Injective.bijective_of_nat_card_le [Finite β] {f : α → β} @@ -177,13 +173,13 @@ theorem card_of_subsingleton (a : α) [Subsingleton α] : Nat.card α = 1 := by letI := Fintype.ofSubsingleton a rw [card_eq_fintype_card, Fintype.card_ofSubsingleton a] --- @[simp] -- Porting note (#10618): simp can prove this -theorem card_unique [Unique α] : Nat.card α = 1 := - card_of_subsingleton default - theorem card_eq_one_iff_unique : Nat.card α = 1 ↔ Subsingleton α ∧ Nonempty α := Cardinal.toNat_eq_one_iff_unique +@[simp] +theorem card_unique [Nonempty α] [Subsingleton α] : Nat.card α = 1 := by + simp [card_eq_one_iff_unique, *] + theorem card_eq_one_iff_exists : Nat.card α = 1 ↔ ∃ x : α, ∀ y : α, y = x := by rw [card_eq_one_iff_unique] exact ⟨fun ⟨s, ⟨a⟩⟩ ↦ ⟨a, fun x ↦ s.elim x a⟩, fun ⟨x, h⟩ ↦ ⟨subsingleton_of_forall_eq x h, ⟨x⟩⟩⟩ diff --git a/Mathlib/SetTheory/Cardinal/Finsupp.lean b/Mathlib/SetTheory/Cardinal/Finsupp.lean index d62685c418254..b8d207a955820 100644 --- a/Mathlib/SetTheory/Cardinal/Finsupp.lean +++ b/Mathlib/SetTheory/Cardinal/Finsupp.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios, Junyan Xu -/ -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.Data.Finsupp.Basic import Mathlib.Data.Finsupp.Multiset diff --git a/Mathlib/SetTheory/Cardinal/Free.lean b/Mathlib/SetTheory/Cardinal/Free.lean new file mode 100644 index 0000000000000..e7625bb0358b5 --- /dev/null +++ b/Mathlib/SetTheory/Cardinal/Free.lean @@ -0,0 +1,115 @@ +/- +Copyright (c) 2024 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser, Daniel Weber +-/ +import Mathlib.Data.Finsupp.Fintype +import Mathlib.GroupTheory.FreeAbelianGroupFinsupp +import Mathlib.RingTheory.FreeCommRing +import Mathlib.SetTheory.Cardinal.Arithmetic +import Mathlib.SetTheory.Cardinal.Finsupp + +/-! +# Cardinalities of free constructions + +This file shows that all the free constructions over `α` have cardinality `max #α ℵ₀`, +and are thus infinite. + +Combined with the ring `Fin n` for the finite cases, this lets us show that there is a `CommRing` of +any cardinality. +-/ + +universe u +variable (α : Type u) + +section Infinite + +@[to_additive] +instance [Nonempty α] : Infinite (FreeMonoid α) := inferInstanceAs <| Infinite (List α) + +@[to_additive] +instance [Nonempty α] : Infinite (FreeGroup α) := by + classical + exact Infinite.of_surjective FreeGroup.norm FreeGroup.norm_surjective + +instance [Nonempty α] : Infinite (FreeAbelianGroup α) := + (FreeAbelianGroup.equivFinsupp α).toEquiv.infinite_iff.2 inferInstance + +instance : Infinite (FreeRing α) := by unfold FreeRing; infer_instance + +instance : Infinite (FreeCommRing α) := by unfold FreeCommRing; infer_instance + +end Infinite + +namespace Cardinal + +theorem mk_abelianization_le (G : Type u) [Group G] : + #(Abelianization G) ≤ #G := Cardinal.mk_le_of_surjective <| surjective_quotient_mk _ + +@[to_additive (attr := simp)] +theorem mk_freeMonoid [Nonempty α] : #(FreeMonoid α) = max #α ℵ₀ := + Cardinal.mk_list_eq_max_mk_aleph0 _ + +@[to_additive (attr := simp)] +theorem mk_freeGroup [Nonempty α] : #(FreeGroup α) = max #α ℵ₀ := by + classical + apply le_antisymm + · apply (mk_le_of_injective (FreeGroup.toWord_injective (α := α))).trans_eq + simp [Cardinal.mk_list_eq_max_mk_aleph0] + obtain hα | hα := lt_or_le #α ℵ₀ + · simp only [hα.le, max_eq_right, max_eq_right_iff] + exact (mul_lt_aleph0 hα (nat_lt_aleph0 2)).le + · rw [max_eq_left hα, max_eq_left (hα.trans <| Cardinal.le_mul_right two_ne_zero), + Cardinal.mul_eq_left hα _ (by simp)] + exact (nat_lt_aleph0 2).le.trans hα + · apply max_le + · exact mk_le_of_injective FreeGroup.of_injective + · simp + +@[simp] +theorem mk_freeAbelianGroup [Nonempty α] : #(FreeAbelianGroup α) = max #α ℵ₀ := by + rw [Cardinal.mk_congr (FreeAbelianGroup.equivFinsupp α).toEquiv] + simp + +@[simp] +theorem mk_freeRing : #(FreeRing α) = max #α ℵ₀ := by + cases isEmpty_or_nonempty α <;> simp [FreeRing] + +@[simp] +theorem mk_freeCommRing : #(FreeCommRing α) = max #α ℵ₀ := by + cases isEmpty_or_nonempty α <;> simp [FreeCommRing] + +end Cardinal + +section Nonempty + +/-- A commutative ring can be constructed on any non-empty type. + +See also `Infinite.nonempty_field`. -/ +instance nonempty_commRing [Nonempty α] : Nonempty (CommRing α) := by + obtain hR | hR := finite_or_infinite α + · obtain ⟨x⟩ := nonempty_fintype α + have : NeZero (Fintype.card α) := ⟨by inhabit α; simp⟩ + classical + obtain ⟨e⟩ := Fintype.truncEquivFin α + exact ⟨e.commRing⟩ + · have ⟨e⟩ : Nonempty (α ≃ FreeCommRing α) := by simp [← Cardinal.eq] + exact ⟨e.commRing⟩ + +@[simp] +theorem nonempty_commRing_iff : Nonempty (CommRing α) ↔ Nonempty α := + ⟨Nonempty.map (·.zero), fun _ => nonempty_commRing _⟩ + +@[simp] +theorem nonempty_ring_iff : Nonempty (Ring α) ↔ Nonempty α := + ⟨Nonempty.map (·.zero), fun _ => (nonempty_commRing _).map (·.toRing)⟩ + +@[simp] +theorem nonempty_commSemiring_iff : Nonempty (CommSemiring α) ↔ Nonempty α := + ⟨Nonempty.map (·.zero), fun _ => (nonempty_commRing _).map (·.toCommSemiring)⟩ + +@[simp] +theorem nonempty_semiring_iff : Nonempty (Semiring α) ↔ Nonempty α := + ⟨Nonempty.map (·.zero), fun _ => (nonempty_commRing _).map (·.toSemiring)⟩ + +end Nonempty diff --git a/Mathlib/SetTheory/Cardinal/ToNat.lean b/Mathlib/SetTheory/Cardinal/ToNat.lean index f37fdaa87cbf3..44953f885edf7 100644 --- a/Mathlib/SetTheory/Cardinal/ToNat.lean +++ b/Mathlib/SetTheory/Cardinal/ToNat.lean @@ -116,8 +116,7 @@ theorem aleph0_toNat : toNat ℵ₀ = 0 := theorem mk_toNat_eq_card [Fintype α] : toNat #α = Fintype.card α := by simp --- porting note (#10618): simp can prove this --- @[simp] +@[simp] theorem zero_toNat : toNat 0 = 0 := map_zero _ theorem one_toNat : toNat 1 = 1 := map_one _ diff --git a/Mathlib/SetTheory/Cardinal/UnivLE.lean b/Mathlib/SetTheory/Cardinal/UnivLE.lean index b5241ecd1cddb..dbc592b08c9b4 100644 --- a/Mathlib/SetTheory/Cardinal/UnivLE.lean +++ b/Mathlib/SetTheory/Cardinal/UnivLE.lean @@ -26,6 +26,14 @@ theorem univLE_iff_cardinal_le : UnivLE.{u, v} ↔ univ.{u, v+1} ≤ univ.{v, u+ rw [univ_umax.{v,u}, ← lift_le.{u+1}, lift_univ, lift_lift] exact h.le +theorem univLE_iff_exists_embedding : UnivLE.{u, v} ↔ Nonempty (Ordinal.{u} ↪ Ordinal.{v}) := by + rw [univLE_iff_cardinal_le] + exact lift_mk_le' + +theorem Ordinal.univLE_of_injective {f : Ordinal.{u} → Ordinal.{v}} (h : f.Injective) : + UnivLE.{u, v} := + univLE_iff_exists_embedding.2 ⟨f, h⟩ + /-- Together with transitivity, this shows UnivLE "IsTotalPreorder". -/ theorem univLE_total : UnivLE.{u, v} ∨ UnivLE.{v, u} := by simp_rw [univLE_iff_cardinal_le]; apply le_total diff --git a/Mathlib/SetTheory/Game/Basic.lean b/Mathlib/SetTheory/Game/Basic.lean index 8c72765907e52..c7ac5c82b8191 100644 --- a/Mathlib/SetTheory/Game/Basic.lean +++ b/Mathlib/SetTheory/Game/Basic.lean @@ -82,7 +82,7 @@ theorem zero_def : (0 : Game) = ⟦0⟧ := rfl instance instPartialOrderGame : PartialOrder Game where - le := Quotient.lift₂ (· ≤ ·) fun x₁ y₁ x₂ y₂ hx hy => propext (le_congr hx hy) + le := Quotient.lift₂ (· ≤ ·) fun _ _ _ _ hx hy => propext (le_congr hx hy) le_refl := by rintro ⟨x⟩ exact le_refl x @@ -93,7 +93,7 @@ instance instPartialOrderGame : PartialOrder Game where rintro ⟨x⟩ ⟨y⟩ h₁ h₂ apply Quot.sound exact ⟨h₁, h₂⟩ - lt := Quotient.lift₂ (· < ·) fun x₁ y₁ x₂ y₂ hx hy => propext (lt_congr hx hy) + lt := Quotient.lift₂ (· < ·) fun _ _ _ _ hx hy => propext (lt_congr hx hy) lt_iff_le_not_le := by rintro ⟨x⟩ ⟨y⟩ exact @lt_iff_le_not_le _ _ x y @@ -164,22 +164,22 @@ namespace Game local infixl:50 " ⧏ " => LF local infixl:50 " ‖ " => Fuzzy -instance covariantClass_add_le : CovariantClass Game Game (· + ·) (· ≤ ·) := +instance addLeftMono : AddLeftMono Game := ⟨by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h exact @add_le_add_left _ _ _ _ b c h a⟩ -instance covariantClass_swap_add_le : CovariantClass Game Game (swap (· + ·)) (· ≤ ·) := +instance addRightMono : AddRightMono Game := ⟨by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h exact @add_le_add_right _ _ _ _ b c h a⟩ -instance covariantClass_add_lt : CovariantClass Game Game (· + ·) (· < ·) := +instance addLeftStrictMono : AddLeftStrictMono Game := ⟨by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h exact @add_lt_add_left _ _ _ _ b c h a⟩ -instance covariantClass_swap_add_lt : CovariantClass Game Game (swap (· + ·)) (· < ·) := +instance addRightStrictMono : AddRightStrictMono Game := ⟨by rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h exact @add_lt_add_right _ _ _ _ b c h a⟩ @@ -194,7 +194,7 @@ theorem add_lf_add_left : ∀ {b c : Game} (_ : b ⧏ c) (a), (a + b : Game) ⧏ instance orderedAddCommGroup : OrderedAddCommGroup Game := { Game.instAddCommGroupWithOneGame, Game.instPartialOrderGame with - add_le_add_left := @add_le_add_left _ _ _ Game.covariantClass_add_le } + add_le_add_left := @add_le_add_left _ _ _ Game.addLeftMono } /-- A small family of games is bounded above. -/ lemma bddAbove_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → Game.{u}) : @@ -247,7 +247,7 @@ Hence we define them here. -/ /-- The product of `x = {xL | xR}` and `y = {yL | yR}` is -`{xL*y + x*yL - xL*yL, xR*y + x*yR - xR*yR | xL*y + x*yR - xL*yR, x*yL + xR*y - xR*yL }`. -/ +`{xL*y + x*yL - xL*yL, xR*y + x*yR - xR*yR | xL*y + x*yR - xL*yR, xR*y + x*yL - xR*yL}`. -/ instance : Mul PGame.{u} := ⟨fun x y => by induction x generalizing y with | mk xl xr _ _ IHxl IHxr => _ diff --git a/Mathlib/SetTheory/Game/Birthday.lean b/Mathlib/SetTheory/Game/Birthday.lean index 016fd8366eb3a..c211b6f8b75e4 100644 --- a/Mathlib/SetTheory/Game/Birthday.lean +++ b/Mathlib/SetTheory/Game/Birthday.lean @@ -126,7 +126,7 @@ theorem le_birthday : ∀ x : PGame, x ≤ x.birthday.toPGame Or.inl ⟨toLeftMovesToPGame ⟨_, birthday_moveLeft_lt i⟩, by simp [le_birthday (xL i)]⟩, isEmptyElim⟩ -variable (a b x : PGame.{u}) +variable (x : PGame.{u}) theorem neg_birthday_le : -x.birthday.toPGame ≤ x := by simpa only [birthday_neg, ← neg_le_iff] using le_birthday (-x) diff --git a/Mathlib/SetTheory/Game/Nim.lean b/Mathlib/SetTheory/Game/Nim.lean index 46bd9ae9c794e..7bf6c35a662b1 100644 --- a/Mathlib/SetTheory/Game/Nim.lean +++ b/Mathlib/SetTheory/Game/Nim.lean @@ -3,9 +3,9 @@ Copyright (c) 2020 Fox Thomson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Fox Thomson, Markus Himmel -/ -import Mathlib.Data.Nat.Bitwise import Mathlib.SetTheory.Game.Birthday import Mathlib.SetTheory.Game.Impartial +import Mathlib.SetTheory.Ordinal.Nimber /-! # Nim and the Sprague-Grundy theorem @@ -14,8 +14,8 @@ This file contains the definition for nim for any ordinal `o`. In the game of `n may move to `nim o₂` for any `o₂ < o₁`. We also define a Grundy value for an impartial game `G` and prove the Sprague-Grundy theorem, that `G` is equivalent to `nim (grundyValue G)`. -Finally, we compute the sum of finite Grundy numbers: if `G` and `H` have Grundy values `n` and `m`, -where `n` and `m` are natural numbers, then `G + H` has the Grundy value `n xor m`. +Finally, we prove that the grundy value of a sum `G + H` corresponds to the nimber sum of the +individual grundy values. ## Implementation details @@ -37,7 +37,7 @@ universe u namespace SetTheory open scoped PGame -open Ordinal +open Ordinal Nimber namespace PGame @@ -209,8 +209,12 @@ theorem nim_equiv_iff_eq {o₁ o₂ : Ordinal} : (nim o₁ ≈ nim o₂) ↔ o /-- The Grundy value of an impartial game is recursively defined as the minimum excluded value (the infimum of the complement) of the Grundy values of either its left or right options. -This is the ordinal which corresponds to the game of nim that the game is equivalent to. -/ -noncomputable def grundyValue (G : PGame.{u}) : Ordinal.{u} := +This is the ordinal which corresponds to the game of nim that the game is equivalent to. + +This function takes a value in `Nimber`. This is a type synonym for the ordinals which has the same +ordering, but addition in `Nimber` is such that it corresponds to the grundy value of the addition +of games. See that file for more information on nimbers and their arithmetic. -/ +noncomputable def grundyValue (G : PGame.{u}) : Nimber.{u} := sInf (Set.range fun i => grundyValue (G.moveLeft i))ᶜ termination_by G @@ -218,6 +222,7 @@ theorem grundyValue_eq_sInf_moveLeft (G : PGame) : grundyValue G = sInf (Set.range (grundyValue ∘ G.moveLeft))ᶜ := by rw [grundyValue]; rfl +set_option linter.deprecated false in @[deprecated grundyValue_eq_sInf_moveLeft (since := "2024-09-16")] theorem grundyValue_eq_mex_left (G : PGame) : grundyValue G = Ordinal.mex fun i => grundyValue (G.moveLeft i) := @@ -231,26 +236,27 @@ theorem grundyValue_ne_moveLeft {G : PGame} (i : G.LeftMoves) : rw [Set.mem_compl_iff, Set.mem_range, not_exists] at this exact this _ -theorem le_grundyValue_of_Iio_subset_moveLeft {G : PGame} {o : Ordinal} +theorem le_grundyValue_of_Iio_subset_moveLeft {G : PGame} {o : Nimber} (h : Set.Iio o ⊆ Set.range (grundyValue ∘ G.moveLeft)) : o ≤ grundyValue G := by by_contra! ho obtain ⟨i, hi⟩ := h ho exact grundyValue_ne_moveLeft i hi -theorem exists_grundyValue_moveLeft_of_lt {G : PGame} {o : Ordinal} (h : o < grundyValue G) : +theorem exists_grundyValue_moveLeft_of_lt {G : PGame} {o : Nimber} (h : o < grundyValue G) : ∃ i, grundyValue (G.moveLeft i) = o := by rw [grundyValue_eq_sInf_moveLeft] at h by_contra ha exact h.not_le (csInf_le' ha) -theorem grundyValue_le_of_forall_moveLeft {G : PGame} {o : Ordinal} +theorem grundyValue_le_of_forall_moveLeft {G : PGame} {o : Nimber} (h : ∀ i, grundyValue (G.moveLeft i) ≠ o) : G.grundyValue ≤ o := by contrapose! h exact exists_grundyValue_moveLeft_of_lt h /-- The **Sprague-Grundy theorem** states that every impartial game is equivalent to a game of nim, namely the game of nim corresponding to the game's Grundy value. -/ -theorem equiv_nim_grundyValue (G : PGame.{u}) [G.Impartial] : G ≈ nim (grundyValue G) := by +theorem equiv_nim_grundyValue (G : PGame.{u}) [G.Impartial] : + G ≈ nim (toOrdinal (grundyValue G)) := by rw [Impartial.equiv_iff_add_equiv_zero, ← Impartial.forall_leftMoves_fuzzy_iff_equiv_zero] intro x apply leftMoves_add_cases x <;> @@ -266,13 +272,13 @@ theorem equiv_nim_grundyValue (G : PGame.{u}) [G.Impartial] : G ≈ nim (grundyV exact Equiv.trans (add_congr_left (equiv_nim_grundyValue _)) (hj ▸ Impartial.add_self _) termination_by G -theorem grundyValue_eq_iff_equiv_nim {G : PGame} [G.Impartial] {o : Ordinal} : - grundyValue G = o ↔ G ≈ nim o := +theorem grundyValue_eq_iff_equiv_nim {G : PGame} [G.Impartial] {o : Nimber} : + grundyValue G = o ↔ G ≈ nim (toOrdinal o) := ⟨by rintro rfl; exact equiv_nim_grundyValue G, by intro h; rw [← nim_equiv_iff_eq]; exact Equiv.trans (Equiv.symm (equiv_nim_grundyValue G)) h⟩ @[simp] -theorem nim_grundyValue (o : Ordinal.{u}) : grundyValue (nim o) = o := +theorem nim_grundyValue (o : Ordinal.{u}) : grundyValue (nim o) = ∗o := grundyValue_eq_iff_equiv_nim.2 PGame.equiv_rfl theorem grundyValue_eq_iff_equiv (G H : PGame) [G.Impartial] [H.Impartial] : @@ -283,7 +289,7 @@ theorem grundyValue_eq_iff_equiv (G H : PGame) [G.Impartial] [H.Impartial] : theorem grundyValue_zero : grundyValue 0 = 0 := grundyValue_eq_iff_equiv_nim.2 (Equiv.symm nim_zero_equiv) -theorem grundyValue_iff_equiv_zero (G : PGame) [G.Impartial] : grundyValue G = 0 ↔ (G ≈ 0) := by +theorem grundyValue_iff_equiv_zero (G : PGame) [G.Impartial] : grundyValue G = 0 ↔ G ≈ 0 := by rw [← grundyValue_eq_iff_equiv, grundyValue_zero] @[simp] @@ -302,6 +308,7 @@ theorem grundyValue_eq_sInf_moveRight (G : PGame) [G.Impartial] : ext i exact @grundyValue_neg _ (@Impartial.moveRight_impartial ⟨l, r, L, R⟩ _ _) +set_option linter.deprecated false in @[deprecated grundyValue_eq_sInf_moveRight (since := "2024-09-16")] theorem grundyValue_eq_mex_right (G : PGame) [G.Impartial] : grundyValue G = Ordinal.mex.{u, u} fun i => grundyValue (G.moveRight i) := @@ -311,68 +318,51 @@ theorem grundyValue_ne_moveRight {G : PGame} [G.Impartial] (i : G.RightMoves) : grundyValue (G.moveRight i) ≠ grundyValue G := by convert grundyValue_ne_moveLeft (toLeftMovesNeg i) using 1 <;> simp -theorem le_grundyValue_of_Iio_subset_moveRight {G : PGame} [G.Impartial] {o : Ordinal} +theorem le_grundyValue_of_Iio_subset_moveRight {G : PGame} [G.Impartial] {o : Nimber} (h : Set.Iio o ⊆ Set.range (grundyValue ∘ G.moveRight)) : o ≤ grundyValue G := by by_contra! ho obtain ⟨i, hi⟩ := h ho exact grundyValue_ne_moveRight i hi -theorem exists_grundyValue_moveRight_of_lt {G : PGame} [G.Impartial] {o : Ordinal} +theorem exists_grundyValue_moveRight_of_lt {G : PGame} [G.Impartial] {o : Nimber} (h : o < grundyValue G) : ∃ i, grundyValue (G.moveRight i) = o := by rw [← grundyValue_neg] at h obtain ⟨i, hi⟩ := exists_grundyValue_moveLeft_of_lt h use toLeftMovesNeg.symm i rwa [← grundyValue_neg, ← moveLeft_neg'] -theorem grundyValue_le_of_forall_moveRight {G : PGame} [G.Impartial] {o : Ordinal} +theorem grundyValue_le_of_forall_moveRight {G : PGame} [G.Impartial] {o : Nimber} (h : ∀ i, grundyValue (G.moveRight i) ≠ o) : G.grundyValue ≤ o := by contrapose! h exact exists_grundyValue_moveRight_of_lt h --- Todo: redefine `grundyValue` as a nimber, and prove `grundyValue (nim a + nim b) = a + b` for all --- nimbers. - -/-- The Grundy value of the sum of two nim games with natural numbers of piles equals their bitwise -xor. -/ -@[simp] -theorem grundyValue_nim_add_nim (n m : ℕ) : grundyValue (nim.{u} n + nim.{u} m) = n ^^^ m := by +/-- The Grundy value of the sum of two nim games equals their nimber addition. -/ +theorem grundyValue_nim_add_nim (x y : Ordinal) : grundyValue (nim x + nim y) = ∗x + ∗y := by apply (grundyValue_le_of_forall_moveLeft _).antisymm (le_grundyValue_of_Iio_subset_moveLeft _) - -- Since XOR is injective, no left moves of `nim n + nim m` will have `n ^^^ m` as a Grundy value. · intro i - apply leftMoves_add_cases i - all_goals - intro j - have hj := toLeftMovesNim_symm_lt j - obtain ⟨k, hk⟩ := lt_omega0.1 (hj.trans (nat_lt_omega0 _)) - rw [hk, Nat.cast_lt] at hj - have := hj.ne - have := hj -- The termination checker doesn't work without this. - · rwa [add_moveLeft_inl, moveLeft_nim', ne_eq, hk, grundyValue_nim_add_nim, Nat.cast_inj, - Nat.xor_left_inj] - · rwa [add_moveLeft_inr, moveLeft_nim', ne_eq, hk, grundyValue_nim_add_nim, Nat.cast_inj, - Nat.xor_right_inj] - -- For any `k < n ^^^ m`, either `nim (k ^^^ m) + nim m` or `nim n + nim (k ^^^ n)` is a left - -- option with Grundy value `k`. + apply leftMoves_add_cases i <;> intro j <;> have := (toLeftMovesNim_symm_lt j).ne + · simpa [grundyValue_nim_add_nim (toLeftMovesNim.symm j) y] + · simpa [grundyValue_nim_add_nim x (toLeftMovesNim.symm j)] · intro k hk - obtain ⟨k, rfl⟩ := Ordinal.lt_omega0.1 (hk.trans (Ordinal.nat_lt_omega0 _)) - rw [Set.mem_Iio, Nat.cast_lt] at hk - obtain hk | hk := Nat.lt_xor_cases hk <;> rw [← natCast_lt] at hk - · use toLeftMovesAdd (Sum.inl (toLeftMovesNim ⟨_, hk⟩)) - rw [Function.comp_apply, add_moveLeft_inl, moveLeft_nim', Equiv.symm_apply_apply, - grundyValue_nim_add_nim, Nat.xor_cancel_right] - · use toLeftMovesAdd (Sum.inr (toLeftMovesNim ⟨_, hk⟩)) - rw [Function.comp_apply, add_moveLeft_inr, moveLeft_nim', Equiv.symm_apply_apply, - grundyValue_nim_add_nim, Nat.xor_comm, Nat.xor_cancel_right] -termination_by (n, m) - -theorem nim_add_nim_equiv {n m : ℕ} : nim n + nim m ≈ nim (n ^^^ m) := by + obtain h | h := Nimber.lt_add_cases hk + · let a := toOrdinal (k + ∗y) + use toLeftMovesAdd (Sum.inl (toLeftMovesNim ⟨a, h⟩)) + simp [a, grundyValue_nim_add_nim a y] + · let a := toOrdinal (k + ∗x) + use toLeftMovesAdd (Sum.inr (toLeftMovesNim ⟨a, h⟩)) + simp [a, grundyValue_nim_add_nim x a, add_comm (∗x)] +termination_by (x, y) + +theorem nim_add_nim_equiv (x y : Ordinal) : + nim x + nim y ≈ nim (toOrdinal (∗x + ∗y)) := by rw [← grundyValue_eq_iff_equiv_nim, grundyValue_nim_add_nim] -theorem grundyValue_add (G H : PGame) [G.Impartial] [H.Impartial] {n m : ℕ} (hG : grundyValue G = n) - (hH : grundyValue H = m) : grundyValue (G + H) = n ^^^ m := by - rw [← nim_grundyValue (n ^^^ m), grundyValue_eq_iff_equiv] - refine Equiv.trans ?_ nim_add_nim_equiv - convert add_congr (equiv_nim_grundyValue G) (equiv_nim_grundyValue H) <;> simp only [hG, hH] +@[simp] +theorem grundyValue_add (G H : PGame) [G.Impartial] [H.Impartial] : + grundyValue (G + H) = grundyValue G + grundyValue H := by + rw [← (grundyValue G).toOrdinal_toNimber, ← (grundyValue H).toOrdinal_toNimber, + ← grundyValue_nim_add_nim, grundyValue_eq_iff_equiv] + exact add_congr (equiv_nim_grundyValue G) (equiv_nim_grundyValue H) end PGame diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index 55a01998f3b98..f67af28a88468 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Kim Morrison -/ import Mathlib.Algebra.Order.ZeroLEOne -import Mathlib.Data.List.InsertNth +import Mathlib.Data.List.InsertIdx import Mathlib.Logic.Relation import Mathlib.Logic.Small.Defs import Mathlib.Order.GameAdd @@ -23,6 +23,9 @@ takes two types (thought of as indexing the possible moves for the players Left pair of functions out of these types to `SetTheory.PGame` (thought of as describing the resulting game after making a move). +We may denote a game as $\{L | R\}$, where $L$ and $R$ stand for the collections of left and right +moves. This notation is not currently used in Mathlib. + Combinatorial games themselves, as a quotient of pregames, are constructed in `Game.lean`. ## Conway induction @@ -349,15 +352,17 @@ instance isEmpty_one_rightMoves : IsEmpty (RightMoves 1) := /-- The less or equal relation on pre-games. -If `0 ≤ x`, then Left can win `x` as the second player. -/ +If `0 ≤ x`, then Left can win `x` as the second player. `x ≤ y` means that `0 ≤ y - x`. +See `PGame.le_iff_sub_nonneg`. -/ instance le : LE PGame := ⟨Sym2.GameAdd.fix wf_isOption fun x y le => (∀ i, ¬le y (x.moveLeft i) (Sym2.GameAdd.snd_fst <| IsOption.moveLeft i)) ∧ ∀ j, ¬le (y.moveRight j) x (Sym2.GameAdd.fst_snd <| IsOption.moveRight j)⟩ -/-- The less or fuzzy relation on pre-games. +/-- The less or fuzzy relation on pre-games. `x ⧏ y` is defined as `¬ y ≤ x`. -If `0 ⧏ x`, then Left can win `x` as the first player. -/ +If `0 ⧏ x`, then Left can win `x` as the first player. `x ⧏ y` means that `0 ⧏ y - x`. +See `PGame.lf_iff_sub_zero_lf`. -/ def LF (x y : PGame) : Prop := ¬y ≤ x @@ -997,7 +1002,7 @@ def moveRightSymm : /-- The identity relabelling. -/ @[refl] def refl (x : PGame) : x ≡r x := - ⟨Equiv.refl _, Equiv.refl _, fun i => refl _, fun j => refl _⟩ + ⟨Equiv.refl _, Equiv.refl _, fun _ => refl _, fun _ => refl _⟩ termination_by x instance (x : PGame) : Inhabited (x ≡r x) := @@ -1542,10 +1547,10 @@ private theorem add_le_add_right' : ∀ {x y z : PGame}, x ≤ y → x + z ≤ y Or.inr ⟨@toRightMovesAdd _ ⟨_, _, _, _⟩ (Sum.inr i), add_le_add_right' h⟩ termination_by x y z => (x, y, z) -instance covariantClass_swap_add_le : CovariantClass PGame PGame (swap (· + ·)) (· ≤ ·) := +instance addRightMono : AddRightMono PGame := ⟨fun _ _ _ => add_le_add_right'⟩ -instance covariantClass_add_le : CovariantClass PGame PGame (· + ·) (· ≤ ·) := +instance addLeftMono : AddLeftMono PGame := ⟨fun x _ _ h => (add_comm_le.trans (add_le_add_right h x)).trans add_comm_le⟩ theorem add_lf_add_right {y z : PGame} (h : y ⧏ z) (x) : y + x ⧏ z + x := @@ -1566,10 +1571,10 @@ theorem add_lf_add_left {y z : PGame} (h : y ⧏ z) (x) : x + y ⧏ x + z := by rw [lf_congr add_comm_equiv add_comm_equiv] apply add_lf_add_right h -instance covariantClass_swap_add_lt : CovariantClass PGame PGame (swap (· + ·)) (· < ·) := +instance addRightStrictMono : AddRightStrictMono PGame := ⟨fun x _ _ h => ⟨add_le_add_right h.1 x, add_lf_add_right h.2 x⟩⟩ -instance covariantClass_add_lt : CovariantClass PGame PGame (· + ·) (· < ·) := +instance addLeftStrictMono : AddLeftStrictMono PGame := ⟨fun x _ _ h => ⟨add_le_add_left h.1 x, add_lf_add_left h.2 x⟩⟩ theorem add_lf_add_of_lf_of_le {w x y z : PGame} (hwx : w ⧏ x) (hyz : y ≤ z) : w + y ⧏ x + z := diff --git a/Mathlib/SetTheory/Game/Short.lean b/Mathlib/SetTheory/Game/Short.lean index 03c8ecbda2c5b..37fa7839716d3 100644 --- a/Mathlib/SetTheory/Game/Short.lean +++ b/Mathlib/SetTheory/Game/Short.lean @@ -219,11 +219,8 @@ instance shortNat : ∀ n : ℕ, Short n instance shortOfNat (n : ℕ) [Nat.AtLeastTwo n] : Short (no_index (OfNat.ofNat n)) := shortNat n --- Porting note: `bit0` and `bit1` are deprecated so these instances can probably be removed. -set_option linter.deprecated false in instance shortBit0 (x : PGame.{u}) [Short x] : Short (x + x) := by infer_instance -set_option linter.deprecated false in instance shortBit1 (x : PGame.{u}) [Short x] : Short ((x + x) + 1) := shortAdd _ _ /-- Auxiliary construction of decidability instances. diff --git a/Mathlib/SetTheory/Game/State.lean b/Mathlib/SetTheory/Game/State.lean index d7871744adc58..01df81444246b 100644 --- a/Mathlib/SetTheory/Game/State.lean +++ b/Mathlib/SetTheory/Game/State.lean @@ -206,7 +206,7 @@ instance shortOfStateAux : ∀ (n : ℕ) {s : S} (h : turnBound s ≤ n), Short have j := (rightMovesOfStateAux _ _).toFun j exfalso exact turnBound_ne_zero_of_right_move j.2 (nonpos_iff_eq_zero.mp h) - | n + 1, s, h => + | n + 1, _, h => Short.mk' (fun i => shortOfRelabelling (relabellingMoveLeftAux (n + 1) h i).symm (shortOfStateAux n _)) diff --git a/Mathlib/SetTheory/Lists.lean b/Mathlib/SetTheory/Lists.lean index cd2aeac9c7722..46a4329656919 100644 --- a/Mathlib/SetTheory/Lists.lean +++ b/Mathlib/SetTheory/Lists.lean @@ -174,7 +174,7 @@ theorem mem_of_subset' {a} : ∀ {l₁ l₂ : Lists' α true} (_ : l₁ ⊆ l₂ · exact mem_of_subset' s h theorem subset_def {l₁ l₂ : Lists' α true} : l₁ ⊆ l₂ ↔ ∀ a ∈ l₁.toList, a ∈ l₂ := - ⟨fun H a => mem_of_subset' H, fun H => by + ⟨fun H _ => mem_of_subset' H, fun H => by rw [← of_toList l₁] revert H; induction' toList l₁ with h t t_ih <;> intro H · exact Subset.nil @@ -336,7 +336,7 @@ mutual exact decidable_of_iff' _ Equiv.antisymm_iff termination_by x y => sizeOf x + sizeOf y instance Subset.decidable : ∀ l₁ l₂ : Lists' α true, Decidable (l₁ ⊆ l₂) - | Lists'.nil, l₂ => isTrue Lists'.Subset.nil + | Lists'.nil, _ => isTrue Lists'.Subset.nil | @Lists'.cons' _ b a l₁, l₂ => by haveI := have : sizeOf (⟨b, a⟩ : Lists α) < 1 + 1 + sizeOf a + sizeOf l₁ := by simp [sizeof_pos] diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index edc763c29c234..865bd245f7301 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -6,6 +6,7 @@ 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.SetTheory.Cardinal.UnivLE /-! # Ordinal arithmetic @@ -40,7 +41,6 @@ Some properties of the operations are also used to discuss general tools on ordi * `IsNormal`: a function `f : Ordinal → Ordinal` satisfies `IsNormal` if it is strictly increasing and order-continuous, i.e., the image `f o` of a limit ordinal `o` is the sup of `f a` for `a < o`. -* `enumOrd`: enumerates an unbounded set of ordinals by the ordinals themselves. * `sup`, `lsub`: the supremum / least strict upper bound of an indexed family of ordinals in `Type u`, as an ordinal in `Type u`. * `bsup`, `blsub`: the supremum / least strict upper bound of a set of ordinals indexed by ordinals @@ -61,8 +61,7 @@ universe u v w namespace Ordinal -variable {α : Type*} {β : Type*} {γ : Type*} {r : α → α → Prop} {s : β → β → Prop} - {t : γ → γ → Prop} +variable {α β γ : Type*} {r : α → α → Prop} {s : β → β → Prop} {t : γ → γ → Prop} /-! ### Further properties of addition on ordinals -/ @@ -78,38 +77,21 @@ theorem lift_succ (a : Ordinal.{v}) : lift.{u} (succ a) = succ (lift.{u} a) := b rw [← add_one_eq_succ, lift_add, lift_one] rfl -instance add_contravariantClass_le : ContravariantClass Ordinal.{u} Ordinal.{u} (· + ·) (· ≤ ·) := - ⟨fun a b c => - inductionOn a fun α r hr => - inductionOn b fun β₁ s₁ hs₁ => - inductionOn c fun β₂ s₂ hs₂ ⟨f⟩ => - ⟨have fl : ∀ a, f (Sum.inl a) = Sum.inl a := fun a => by - simpa only [InitialSeg.trans_apply, InitialSeg.leAdd_apply] using - @InitialSeg.eq _ _ _ _ _ - ((InitialSeg.leAdd r s₁).trans f) (InitialSeg.leAdd r s₂) a - have : ∀ b, { b' // f (Sum.inr b) = Sum.inr b' } := by - intro b; cases e : f (Sum.inr b) - · rw [← fl] at e - have := f.inj' e - contradiction - · exact ⟨_, rfl⟩ - let g (b) := (this b).1 - have fr : ∀ b, f (Sum.inr b) = Sum.inr (g b) := fun b => (this b).2 - ⟨⟨⟨g, fun x y h => by - injection f.inj' (by rw [fr, fr, h] : f (Sum.inr x) = f (Sum.inr y))⟩, - @fun a b => by - -- Porting note: - -- `relEmbedding.coe_fn_to_embedding` & `initial_seg.coe_fn_to_rel_embedding` - -- → `InitialSeg.coe_coe_fn` - simpa only [Sum.lex_inr_inr, fr, InitialSeg.coe_coe_fn, Embedding.coeFn_mk] using - @RelEmbedding.map_rel_iff _ _ _ _ f.toRelEmbedding (Sum.inr a) (Sum.inr b)⟩, - fun a b H => by - rcases f.mem_range_of_rel (by rw [fr] <;> exact Sum.lex_inr_inr.2 H) with - ⟨a' | a', h⟩ - · rw [fl] at h - cases h - · rw [fr] at h - exact ⟨a', Sum.inr.inj h⟩⟩⟩⟩ +instance instAddLeftReflectLE : + AddLeftReflectLE Ordinal.{u} where + elim c a b := by + refine inductionOn₃ a b c fun α r _ β s _ γ t _ ⟨f⟩ ↦ ?_ + have H₁ a : f (Sum.inl a) = Sum.inl a := by + simpa using ((InitialSeg.leAdd t r).trans f).eq (InitialSeg.leAdd t s) a + have H₂ a : ∃ b, f (Sum.inr a) = Sum.inr b := by + generalize hx : f (Sum.inr a) = x + obtain x | x := x + · rw [← H₁, f.inj] at hx + contradiction + · exact ⟨x, rfl⟩ + choose g hg using H₂ + refine (RelEmbedding.ofMonotone g fun _ _ h ↦ ?_).ordinal_type_le + rwa [← @Sum.lex_inr_inr _ t _ s, ← hg, ← hg, f.map_rel_iff, Sum.lex_inr_inr] theorem add_left_cancel (a) {b c : Ordinal} : a + b = a + c ↔ b = c := by simp only [le_antisymm_iff, add_le_add_iff_left] @@ -117,15 +99,14 @@ theorem add_left_cancel (a) {b c : Ordinal} : a + b = a + c ↔ b = c := by private theorem add_lt_add_iff_left' (a) {b c : Ordinal} : a + b < a + c ↔ b < c := by rw [← not_le, ← not_le, add_le_add_iff_left] -instance add_covariantClass_lt : CovariantClass Ordinal.{u} Ordinal.{u} (· + ·) (· < ·) := - ⟨fun a _b _c => (add_lt_add_iff_left' a).2⟩ +instance instAddLeftStrictMono : AddLeftStrictMono Ordinal.{u} := + ⟨fun a _b _c ↦ (add_lt_add_iff_left' a).2⟩ -instance add_contravariantClass_lt : ContravariantClass Ordinal.{u} Ordinal.{u} (· + ·) (· < ·) := - ⟨fun a _b _c => (add_lt_add_iff_left' a).1⟩ +instance instAddLeftReflectLT : AddLeftReflectLT Ordinal.{u} := + ⟨fun a _b _c ↦ (add_lt_add_iff_left' a).1⟩ -instance add_swap_contravariantClass_lt : - ContravariantClass Ordinal.{u} Ordinal.{u} (swap (· + ·)) (· < ·) := - ⟨fun _a _b _c => lt_imp_lt_of_le_imp_le fun h => add_le_add_right h _⟩ +instance instAddRightReflectLT : AddRightReflectLT Ordinal.{u} := + ⟨fun _a _b _c ↦ lt_imp_lt_of_le_imp_le fun h => add_le_add_right h _⟩ theorem add_le_add_iff_right {a b : Ordinal} : ∀ n : ℕ, a + n ≤ b + n ↔ a ≤ b | 0 => by simp @@ -136,10 +117,9 @@ theorem add_right_cancel {a b : Ordinal} (n : ℕ) : a + n = b + n ↔ a = b := simp only [le_antisymm_iff, add_le_add_iff_right] theorem add_eq_zero_iff {a b : Ordinal} : a + b = 0 ↔ a = 0 ∧ b = 0 := - inductionOn a fun α r _ => - inductionOn b fun β s _ => by - simp_rw [← type_sum_lex, type_eq_zero_iff_isEmpty] - exact isEmpty_sum + inductionOn₂ a b fun α r _ β s _ => by + simp_rw [← type_sum_lex, type_eq_zero_iff_isEmpty] + exact isEmpty_sum theorem left_eq_zero_of_add_eq_zero {a b : Ordinal} (h : a + b = 0) : a = 0 := (add_eq_zero_iff.1 h).1 @@ -200,7 +180,7 @@ theorem pred_le {a b} : pred a ≤ b ↔ a ≤ succ b := @[simp] theorem lift_is_succ {o : Ordinal.{v}} : (∃ a, lift.{u} o = succ a) ↔ ∃ a, o = succ a := ⟨fun ⟨a, h⟩ => - let ⟨b, e⟩ := lift_down <| show a ≤ lift.{u} o from le_of_lt <| h.symm ▸ lt_succ a + let ⟨b, e⟩ := mem_range_lift_of_le <| show a ≤ lift.{u} o from le_of_lt <| h.symm ▸ lt_succ a ⟨b, (lift_inj.{u,v}).1 <| by rw [h, ← e, lift_succ]⟩, fun ⟨a, h⟩ => ⟨lift.{u} a, by simp only [h, lift_succ]⟩⟩ @@ -261,7 +241,7 @@ 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⟩ := lift_down h.le + obtain ⟨a', rfl⟩ := mem_range_lift_of_le h.le rw [← lift_succ, lift_lt] exact H a' (lift_lt.1 h)⟩ @@ -282,6 +262,19 @@ theorem zero_or_succ_or_limit (o : Ordinal) : o = 0 ∨ (∃ a, o = succ a) ∨ 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⟩ +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 + +-- TODO: this is an iff with `IsSuccPrelimit` +theorem IsLimit.sSup_Iio {o : Ordinal} (h : IsLimit o) : sSup (Iio o) = o := by + apply (csSup_le' (fun a ha ↦ le_of_lt ha)).antisymm + apply le_of_forall_lt + intro a ha + exact (lt_succ a).trans_le (le_csSup bddAbove_Iio (h.succ_lt ha)) + +theorem IsLimit.iSup_Iio {o : Ordinal} (h : IsLimit o) : ⨆ a : Iio o, a.1 = o := by + rw [← sSup_eq_iSup', h.sSup_Iio] + /-- Main induction principle of ordinals: if one can prove a property by induction at successor ordinals and at limit ordinals, then it holds for all ordinals. -/ @[elab_as_elim] @@ -336,7 +329,7 @@ instance orderTopToTypeSucc (o : Ordinal) : OrderTop (succ o).toType := @OrderTop.mk _ _ (Top.mk _) le_enum_succ theorem enum_succ_eq_top {o : Ordinal} : - enum (α := (succ o).toType) (· < ·) ⟨o, by rw [type_lt]; exact lt_succ o⟩ = ⊤ := + enum (α := (succ o).toType) (· < ·) ⟨o, type_toType _ ▸ lt_succ o⟩ = ⊤ := rfl theorem has_succ_of_type_succ_lt {α} {r : α → α → Prop} [wo : IsWellOrder α r] @@ -347,7 +340,7 @@ theorem has_succ_of_type_succ_lt {α} {r : α → α → Prop} [wo : IsWellOrder · rw [Subtype.mk_lt_mk, lt_succ_iff] theorem toType_noMax_of_succ_lt {o : Ordinal} (ho : ∀ a < o, succ a < o) : NoMaxOrder o.toType := - ⟨has_succ_of_type_succ_lt (by rwa [type_lt])⟩ + ⟨has_succ_of_type_succ_lt (type_toType _ ▸ ho)⟩ @[deprecated toType_noMax_of_succ_lt (since := "2024-08-26")] alias out_no_max_of_succ_lt := toType_noMax_of_succ_lt @@ -440,7 +433,7 @@ theorem IsNormal.le_iff_eq {f} (H : IsNormal f) {a} : f a ≤ a ↔ f a = a := theorem IsNormal.le_set {f o} (H : IsNormal f) (p : Set Ordinal) (p0 : p.Nonempty) (b) (H₂ : ∀ o, b ≤ o ↔ ∀ a ∈ p, a ≤ o) : f b ≤ o ↔ ∀ a ∈ p, f a ≤ o := - ⟨fun h a pa => (H.le_iff.2 ((H₂ _).1 le_rfl _ pa)).trans h, fun h => by + ⟨fun h _ pa => (H.le_iff.2 ((H₂ _).1 le_rfl _ pa)).trans h, fun h => by -- Porting note: `refine'` didn't work well so `induction` is used induction b using limitRecOn with | H₁ => @@ -473,7 +466,7 @@ theorem IsNormal.isLimit {f} (H : IsNormal f) {o} (l : IsLimit o) : IsLimit (f o (succ_le_of_lt h₂).trans_lt (H.lt_iff.2 h₁)⟩ theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a + b ≤ c ↔ ∀ b' < b, a + b' ≤ c := - ⟨fun h b' l => (add_le_add_left l.le _).trans h, fun H => + ⟨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. induction a using inductionOn with @@ -499,11 +492,17 @@ theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a + b ≤ c ↔ ∀ · rcases a with ⟨a | a, h₁⟩ <;> rcases b with ⟨b | b, h₂⟩ <;> cases h₁ <;> cases h₂ <;> rintro ⟨⟩ <;> constructor <;> assumption⟩ -theorem add_isNormal (a : Ordinal) : IsNormal (a + ·) := +theorem isNormal_add_right (a : Ordinal) : IsNormal (a + ·) := ⟨fun b => (add_lt_add_iff_left a).2 (lt_succ b), fun _b l _c => add_le_of_limit l⟩ -theorem add_isLimit (a) {b} : IsLimit b → IsLimit (a + b) := - (add_isNormal a).isLimit +@[deprecated isNormal_add_right (since := "2024-10-11")] +alias add_isNormal := isNormal_add_right + +theorem isLimit_add (a) {b} : IsLimit b → IsLimit (a + b) := + (isNormal_add_right a).isLimit + +@[deprecated isLimit_add (since := "2024-10-11")] +alias add_isLimit := isLimit_add alias IsLimit.add := add_isLimit @@ -574,11 +573,13 @@ theorem sub_sub (a b c : Ordinal) : a - b - c = a - (b + c) := theorem add_sub_add_cancel (a b c : Ordinal) : a + b - (a + c) = b - c := by rw [← sub_sub, add_sub_cancel] -theorem sub_isLimit {a b} (l : IsLimit a) (h : b < a) : IsLimit (a - 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)⟩ --- @[simp] -- Porting note (#10618): simp can prove this +@[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] @@ -608,10 +609,9 @@ alias one_add_of_omega_le := one_add_of_omega0_le instance monoid : Monoid Ordinal.{u} where mul a b := Quotient.liftOn₂ a b - (fun ⟨α, r, wo⟩ ⟨β, s, wo'⟩ => ⟦⟨β × α, Prod.Lex s r, inferInstance⟩⟧ : + (fun ⟨α, r, _⟩ ⟨β, s, _⟩ => ⟦⟨β × α, Prod.Lex s r, inferInstance⟩⟧ : WellOrder → WellOrder → Ordinal) - fun ⟨α₁, r₁, o₁⟩ ⟨α₂, r₂, o₂⟩ ⟨β₁, s₁, p₁⟩ ⟨β₂, s₂, p₂⟩ ⟨f⟩ ⟨g⟩ => - Quot.sound ⟨RelIso.prodLexCongr g f⟩ + fun ⟨_, _, _⟩ _ _ _ ⟨f⟩ ⟨g⟩ => Quot.sound ⟨RelIso.prodLexCongr g f⟩ one := 1 mul_assoc a b c := Quotient.inductionOn₃ a b c fun ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ => @@ -684,7 +684,7 @@ instance leftDistribClass : LeftDistribClass Ordinal.{u} := theorem mul_succ (a b : Ordinal) : a * succ b = a * b + a := mul_add_one a b -instance mul_covariantClass_le : CovariantClass Ordinal.{u} Ordinal.{u} (· * ·) (· ≤ ·) := +instance mulLeftMono : MulLeftMono Ordinal.{u} := ⟨fun c a b => Quotient.inductionOn₃ a b c fun ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ ⟨f⟩ => by refine @@ -693,8 +693,7 @@ instance mul_covariantClass_le : CovariantClass Ordinal.{u} Ordinal.{u} (· * · · exact Prod.Lex.left _ _ (f.toRelEmbedding.map_rel_iff.2 h') · exact Prod.Lex.right _ h'⟩ -instance mul_swap_covariantClass_le : - CovariantClass Ordinal.{u} Ordinal.{u} (swap (· * ·)) (· ≤ ·) := +instance mulRightMono : MulRightMono Ordinal.{u} := ⟨fun c a b => Quotient.inductionOn₃ a b c fun ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ ⟨f⟩ => by refine @@ -750,7 +749,7 @@ private theorem mul_le_of_limit_aux {α β r s} [IsWellOrder α r] [IsWellOrder Sum.lex_inl_inl] using h theorem mul_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a * b ≤ c ↔ ∀ b' < b, a * b' ≤ c := - ⟨fun h b' l => (mul_le_mul_left' l.le _).trans h, fun H => + ⟨fun h _ l => (mul_le_mul_left' l.le _).trans h, fun H => -- Porting note: `induction` tactics are required because of the parser bug. le_of_not_lt <| by induction a using inductionOn with @@ -759,23 +758,26 @@ theorem mul_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a * b ≤ c ↔ ∀ | H β s => exact mul_le_of_limit_aux h H⟩ -theorem mul_isNormal {a : Ordinal} (h : 0 < a) : IsNormal (a * ·) := +theorem isNormal_mul_right {a : Ordinal} (h : 0 < a) : IsNormal (a * ·) := -- Porting note(#12129): additional beta reduction needed ⟨fun b => by beta_reduce rw [mul_succ] simpa only [add_zero] using (add_lt_add_iff_left (a * b)).2 h, - fun b l c => mul_le_of_limit l⟩ + fun _ l _ => mul_le_of_limit l⟩ + +@[deprecated isNormal_mul_right (since := "2024-10-11")] +alias mul_isNormal := isNormal_mul_right theorem lt_mul_of_limit {a b c : Ordinal} (h : IsLimit c) : a < b * c ↔ ∃ c' < c, a < b * c' := by -- Porting note: `bex_def` is required. simpa only [not_forall₂, not_le, bex_def] using not_congr (@mul_le_of_limit b c a h) theorem mul_lt_mul_iff_left {a b c : Ordinal} (a0 : 0 < a) : a * b < a * c ↔ b < c := - (mul_isNormal a0).lt_iff + (isNormal_mul_right a0).lt_iff theorem mul_le_mul_iff_left {a b c : Ordinal} (a0 : 0 < a) : a * b ≤ a * c ↔ b ≤ c := - (mul_isNormal a0).le_iff + (isNormal_mul_right a0).le_iff theorem mul_lt_mul_of_pos_left {a b c : Ordinal} (h : a < b) (c0 : 0 < c) : c * a < c * b := (mul_lt_mul_iff_left c0).2 h @@ -790,17 +792,23 @@ theorem le_of_mul_le_mul_left {a b c : Ordinal} (h : c * a ≤ c * b) (h0 : 0 < le_imp_le_of_lt_imp_lt (fun h' => mul_lt_mul_of_pos_left h' h0) h theorem mul_right_inj {a b c : Ordinal} (a0 : 0 < a) : a * b = a * c ↔ b = c := - (mul_isNormal a0).inj + (isNormal_mul_right a0).inj + +theorem isLimit_mul {a b : Ordinal} (a0 : 0 < a) : IsLimit b → IsLimit (a * b) := + (isNormal_mul_right a0).isLimit -theorem mul_isLimit {a b : Ordinal} (a0 : 0 < a) : IsLimit b → IsLimit (a * b) := - (mul_isNormal a0).isLimit +@[deprecated isLimit_mul (since := "2024-10-11")] +alias mul_isLimit := isLimit_mul -theorem mul_isLimit_left {a b : Ordinal} (l : IsLimit a) (b0 : 0 < b) : IsLimit (a * b) := by +theorem isLimit_mul_left {a b : Ordinal} (l : IsLimit a) (b0 : 0 < b) : IsLimit (a * b) := by rcases zero_or_succ_or_limit b with (rfl | ⟨b, rfl⟩ | lb) · exact b0.false.elim · rw [mul_succ] - exact add_isLimit _ l - · exact mul_isLimit l.pos lb + exact isLimit_add _ l + · exact isLimit_mul l.pos lb + +@[deprecated isLimit_mul_left (since := "2024-10-11")] +alias mul_isLimit_left := isLimit_mul_left theorem smul_eq_mul : ∀ (n : ℕ) (a : Ordinal), n • a = a * n | 0, a => by rw [zero_nsmul, Nat.cast_zero, mul_zero] @@ -867,6 +875,12 @@ theorem zero_div (a : Ordinal) : 0 / a = 0 := theorem mul_div_le (a b : Ordinal) : b * (a / b) ≤ a := if b0 : b = 0 then by simp only [b0, zero_mul, Ordinal.zero_le] else (le_div b0).1 le_rfl +theorem div_le_left {a b : Ordinal} (h : a ≤ b) (c : Ordinal) : a / c ≤ b / c := by + obtain rfl | hc := eq_or_ne c 0 + · rw [div_zero, div_zero] + · rw [le_div hc] + exact (mul_div_le a c).trans h + theorem mul_add_div (a) {b : Ordinal} (b0 : b ≠ 0) (c) : (b * a + c) / b = a + c / b := by apply le_antisymm · apply (div_le b0).2 @@ -924,11 +938,11 @@ theorem isLimit_add_iff {a b} : IsLimit (a + b) ↔ IsLimit b ∨ b = 0 ∧ IsLi exact ⟨h', h⟩ left rw [← add_sub_cancel a b] - apply sub_isLimit h + apply isLimit_sub h suffices a + 0 < a + b by simpa only [add_zero] using this rwa [add_lt_add_iff_left, Ordinal.pos_iff_ne_zero] rcases h with (h | ⟨rfl, h⟩) - · exact add_isLimit a h + · exact isLimit_add a h · simpa only [add_zero] theorem dvd_add_iff : ∀ {a b c : Ordinal}, a ∣ b → (a ∣ b + c ↔ a ∣ c) @@ -1068,7 +1082,7 @@ def familyOfBFamily' {ι : Type u} (r : ι → ι → Prop) [IsWellOrder ι r] { /-- Converts a family indexed by an `Ordinal.{u}` to one indexed by a `Type u` using a well-ordering given by the axiom of choice. -/ def familyOfBFamily (o : Ordinal) (f : ∀ a < o, α) : o.toType → α := - familyOfBFamily' (· < ·) (type_lt o) f + familyOfBFamily' (· < ·) (type_toType o) f @[simp] theorem bfamilyOfFamily'_typein {ι} (r : ι → ι → Prop) [IsWellOrder ι r] (f : ι → α) (i) : @@ -1088,8 +1102,9 @@ theorem familyOfBFamily'_enum {ι : Type u} (r : ι → ι → Prop) [IsWellOrde @[simp, nolint simpNF] -- Porting note (#10959): simp cannot prove this theorem familyOfBFamily_enum (o : Ordinal) (f : ∀ a < o, α) (i hi) : - familyOfBFamily o f (enum (α := o.toType) (· < ·) ⟨i, hi.trans_eq (type_lt _).symm⟩) = f i hi := - familyOfBFamily'_enum _ (type_lt o) f _ _ + familyOfBFamily o f (enum (α := o.toType) (· < ·) ⟨i, hi.trans_eq (type_toType _).symm⟩) + = f i hi := + familyOfBFamily'_enum _ (type_toType o) f _ _ /-- The range of a family indexed by ordinals. -/ def brange (o : Ordinal) (f : ∀ a < o, α) : Set α := @@ -1170,27 +1185,48 @@ theorem bddAbove_range {ι : Type u} (f : ι → Ordinal.{max u v}) : BddAbove ( exact le_of_lt (Cardinal.lt_ord.2 ((lt_succ _).trans_le (le_ciSup (Cardinal.bddAbove_range.{_, v} _) _)))⟩ -/-- `le_ciSup` whenever the outputs live in a higher universe than the inputs. -/ -protected theorem le_iSup {ι : Type u} (f : ι → Ordinal.{max u v}) : ∀ i, f i ≤ iSup f := - le_ciSup (bddAbove_range f) +theorem bddAbove_of_small (s : Set Ordinal.{u}) [h : Small.{u} s] : BddAbove s := by + obtain ⟨a, ha⟩ := bddAbove_range (fun x => ((@equivShrink s h).symm x).val) + use a + intro b hb + simpa using ha (mem_range_self (equivShrink s ⟨b, hb⟩)) + +theorem bddAbove_iff_small {s : Set Ordinal.{u}} : BddAbove s ↔ Small.{u} s := + ⟨fun ⟨a, h⟩ => small_subset <| show s ⊆ Iic a from fun _ hx => h hx, fun _ => + bddAbove_of_small _⟩ + +theorem bddAbove_image {s : Set Ordinal.{u}} (hf : BddAbove s) + (f : Ordinal.{u} → Ordinal.{max u v}) : BddAbove (f '' s) := by + rw [bddAbove_iff_small] at hf ⊢ + exact small_lift _ + +theorem bddAbove_range_comp {ι : Type u} {f : ι → Ordinal.{v}} (hf : BddAbove (range f)) + (g : Ordinal.{v} → Ordinal.{max v w}) : BddAbove (range (g ∘ f)) := by + rw [range_comp] + exact bddAbove_image hf g + +/-- `le_ciSup` whenever the input type is small in the output universe. This lemma sometimes +fails to infer `f` in simple cases and needs it to be given explicitly. -/ +protected theorem le_iSup {ι} (f : ι → Ordinal.{u}) [Small.{u} ι] : ∀ i, f i ≤ iSup f := + le_ciSup (bddAbove_of_small _) set_option linter.deprecated false in @[deprecated Ordinal.le_iSup (since := "2024-08-27")] theorem le_sup {ι : Type u} (f : ι → Ordinal.{max u v}) : ∀ i, f i ≤ sup.{_, v} f := fun i => Ordinal.le_iSup f i -/-- `ciSup_le_iff'` whenever the outputs live in a higher universe than the inputs. -/ -protected theorem iSup_le_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : +/-- `ciSup_le_iff'` whenever the input type is small in the output universe. -/ +protected theorem iSup_le_iff {ι} {f : ι → Ordinal.{u}} {a : Ordinal.{u}} [Small.{u} ι] : iSup f ≤ a ↔ ∀ i, f i ≤ a := - ciSup_le_iff' (bddAbove_range f) + ciSup_le_iff' (bddAbove_of_small _) set_option linter.deprecated false in @[deprecated Ordinal.iSup_le_iff (since := "2024-08-27")] theorem sup_le_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : sup.{_, v} f ≤ a ↔ ∀ i, f i ≤ a := Ordinal.iSup_le_iff -/-- `ciSup_le'` whenever the outputs live in a higher universe than the inputs. -/ -protected theorem iSup_le {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : +/-- An alias of `ciSup_le'` for discoverability. -/ +protected theorem iSup_le {ι} {f : ι → Ordinal} {a} : (∀ i, f i ≤ a) → iSup f ≤ a := ciSup_le' @@ -1199,11 +1235,10 @@ set_option linter.deprecated false in theorem sup_le {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : (∀ i, f i ≤ a) → sup.{_, v} f ≤ a := Ordinal.iSup_le --- TODO: generalize to conditionally complete linear orders. -protected theorem lt_iSup {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : - a < iSup f ↔ ∃ i, a < f i := by - rw [← not_iff_not] - simpa using Ordinal.iSup_le_iff +/-- `lt_ciSup_iff'` whenever the input type is small in the output universe. -/ +protected theorem lt_iSup {ι} {f : ι → Ordinal.{u}} {a : Ordinal.{u}} [Small.{u} ι] : + a < iSup f ↔ ∃ i, a < f i := + lt_ciSup_iff' (bddAbove_of_small _) set_option linter.deprecated false in @[deprecated Ordinal.lt_iSup (since := "2024-08-27")] @@ -1222,7 +1257,7 @@ theorem ne_sup_iff_lt_sup {ι : Type u} {f : ι → Ordinal.{max u v}} : ne_iSup_iff_lt_iSup -- TODO: state in terms of `IsSuccLimit`. -theorem succ_lt_iSup_of_ne_iSup {ι : Type u} {f : ι → Ordinal.{max u v}} +theorem succ_lt_iSup_of_ne_iSup {ι} {f : ι → Ordinal.{u}} [Small.{u} ι] (hf : ∀ i, f i ≠ iSup f) {a} (hao : a < iSup f) : succ a < iSup f := by by_contra! hoa exact hao.not_le (Ordinal.iSup_le fun i => le_of_lt_succ <| @@ -1237,7 +1272,7 @@ theorem sup_not_succ_of_ne_sup {ι : Type u} {f : ι → Ordinal.{max u v}} hao.not_le (sup_le fun i => le_of_lt_succ <| (lt_of_le_of_ne (le_sup _ _) (hf i)).trans_le hoa) -- TODO: generalize to conditionally complete lattices. -theorem iSup_eq_zero_iff {ι : Type u} {f : ι → Ordinal.{max u v}} : +theorem iSup_eq_zero_iff {ι} {f : ι → Ordinal.{u}} [Small.{u} ι] : iSup f = 0 ↔ ∀ i, f i = 0 := by refine ⟨fun h i => ?_, fun h => @@ -1255,24 +1290,6 @@ theorem sup_eq_zero_iff {ι : Type u} {f : ι → Ordinal.{max u v}} : rw [← Ordinal.le_zero, ← h] exact le_sup f i --- TODO: generalize universes, make sSup version. -theorem IsNormal.map_iSup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {ι : Type u} - (g : ι → Ordinal.{max u v}) [Nonempty ι] : f (⨆ i, g i) = ⨆ i, f (g i) := by - apply eq_of_forall_ge_iff - intro a - rw [H.le_set' Set.univ Set.univ_nonempty g] - · rw [Ordinal.iSup_le_iff] - simp - · intro o - rw [Ordinal.iSup_le_iff] - simp - -set_option linter.deprecated false in -@[deprecated IsNormal.map_iSup (since := "2024-08-27")] -theorem IsNormal.sup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {ι : Type u} - (g : ι → Ordinal.{max u v}) [Nonempty ι] : f (sup.{_, v} g) = sup.{_, w} (f ∘ g) := - H.map_iSup g - set_option linter.deprecated false in @[deprecated ciSup_of_empty (since := "2024-08-27")] theorem sup_empty {ι} [IsEmpty ι] (f : ι → Ordinal) : sup f = 0 := @@ -1307,14 +1324,14 @@ theorem sup_eq_of_range_eq {ι : Type u} {ι' : Type v} Ordinal.iSup_eq_of_range_eq h -- TODO: generalize to conditionally complete lattices -theorem iSup_sum {α : Type u} {β : Type v} (f : α ⊕ β → Ordinal.{max u v w}) : +theorem iSup_sum {α β} (f : α ⊕ β → Ordinal.{u}) [Small.{u} α] [Small.{u} β]: iSup f = max (⨆ a, f (Sum.inl a)) (⨆ b, f (Sum.inr b)) := by apply (Ordinal.iSup_le _).antisymm (max_le _ _) · rintro (i | i) - · exact le_max_of_le_left (Ordinal.le_iSup.{u, max u v w} _ i) - · exact le_max_of_le_right (Ordinal.le_iSup.{v, max u v w} _ i) + · exact le_max_of_le_left (Ordinal.le_iSup (fun x ↦ f (Sum.inl x)) i) + · exact le_max_of_le_right (Ordinal.le_iSup (fun x ↦ f (Sum.inr x)) i) all_goals - apply csSup_le_csSup' (bddAbove_range _) + apply csSup_le_csSup' (bddAbove_of_small _) rintro i ⟨a, rfl⟩ apply mem_range_self @@ -1352,17 +1369,43 @@ theorem le_sup_shrink_equiv {s : Set Ordinal.{u}} (hs : Small.{u} s) (a) (ha : a convert le_sup.{u, u} (fun x => ((@equivShrink s hs).symm x).val) ((@equivShrink s hs) ⟨a, ha⟩) rw [symm_apply_apply] --- TODO: move this together with `bddAbove_range`. +theorem IsNormal.map_iSup_of_bddAbove {f : Ordinal.{u} → Ordinal.{v}} (H : IsNormal f) + {ι : Type*} (g : ι → Ordinal.{u}) (hg : BddAbove (range g)) + [Nonempty ι] : f (⨆ i, g i) = ⨆ i, f (g i) := eq_of_forall_ge_iff fun a ↦ by + have := bddAbove_iff_small.mp hg + have := univLE_of_injective H.strictMono.injective + have := Small.trans_univLE.{u, v} (range g) + have hfg : BddAbove (range (f ∘ g)) := bddAbove_iff_small.mpr <| by + rw [range_comp] + exact small_image f (range g) + change _ ↔ ⨆ i, (f ∘ g) i ≤ a + rw [ciSup_le_iff hfg, H.le_set' _ Set.univ_nonempty g] <;> simp [ciSup_le_iff hg] + +theorem IsNormal.map_iSup {f : Ordinal.{u} → Ordinal.{v}} (H : IsNormal f) + {ι : Type w} (g : ι → Ordinal.{u}) [Small.{u} ι] [Nonempty ι] : + f (⨆ i, g i) = ⨆ i, f (g i) := + H.map_iSup_of_bddAbove g (bddAbove_of_small _) + +theorem IsNormal.map_sSup_of_bddAbove {f : Ordinal.{u} → Ordinal.{v}} (H : IsNormal f) + {s : Set Ordinal.{u}} (hs : BddAbove s) (hn : s.Nonempty) : f (sSup s) = sSup (f '' s) := by + have := hn.to_subtype + rw [sSup_eq_iSup', sSup_image', H.map_iSup_of_bddAbove] + rwa [Subtype.range_coe_subtype, setOf_mem_eq] + +theorem IsNormal.map_sSup {f : Ordinal.{u} → Ordinal.{v}} (H : IsNormal f) + {s : Set Ordinal.{u}} (hn : s.Nonempty) [Small.{u} s] : f (sSup s) = sSup (f '' s) := + H.map_sSup_of_bddAbove (bddAbove_of_small s) hn -theorem bddAbove_of_small (s : Set Ordinal.{u}) [h : Small.{u} s] : BddAbove s := by - obtain ⟨a, ha⟩ := bddAbove_range (fun x => ((@equivShrink s h).symm x).val) - use a - intro b hb - simpa using ha (mem_range_self (equivShrink s ⟨b, hb⟩)) +set_option linter.deprecated false in +@[deprecated IsNormal.map_iSup (since := "2024-08-27")] +theorem IsNormal.sup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {ι : Type u} + (g : ι → Ordinal.{max u v}) [Nonempty ι] : f (sup.{_, v} g) = sup.{_, w} (f ∘ g) := + H.map_iSup g -theorem bddAbove_iff_small {s : Set Ordinal.{u}} : BddAbove s ↔ Small.{u} s := - ⟨fun ⟨a, h⟩ => small_subset <| show s ⊆ Iic a from fun _ hx => h hx, fun _ => - bddAbove_of_small _⟩ +theorem IsNormal.apply_of_isLimit {f : Ordinal.{u} → Ordinal.{v}} (H : IsNormal f) {o : Ordinal} + (ho : IsLimit o) : f o = ⨆ a : Iio o, f a := by + have : Nonempty (Iio o) := ⟨0, ho.pos⟩ + rw [← H.map_iSup, ho.iSup_Iio] set_option linter.deprecated false in @[deprecated (since := "2024-08-27")] @@ -1387,6 +1430,22 @@ theorem iSup_ord {ι} {f : ι → Cardinal} (hf : BddAbove (range f)) : conv_lhs => change range (ord ∘ f) rw [range_comp] +theorem sInf_compl_lt_lift_ord_succ {ι : Type u} (f : ι → Ordinal.{max u v}) : + sInf (range f)ᶜ < lift.{v} (succ #ι).ord := by + by_contra! h + have : Iio (lift.{v} (succ #ι).ord) ⊆ range f := by + intro o ho + have := not_mem_of_lt_csInf' (ho.trans_le h) + rwa [not_mem_compl_iff] at this + have := mk_le_mk_of_subset this + rw [mk_Iio_ordinal, ← lift_card, Cardinal.lift_lift, card_ord, Cardinal.lift_succ, + succ_le_iff, ← Cardinal.lift_id'.{u, max (u + 1) (v + 1)} #_] at this + exact this.not_le mk_range_le_lift + +theorem sInf_compl_lt_ord_succ {ι : Type u} (f : ι → Ordinal.{u}) : + sInf (range f)ᶜ < (succ #ι).ord := + lift_id (succ #ι).ord ▸ sInf_compl_lt_lift_ord_succ f + -- TODO: remove `bsup` in favor of `iSup` in a future refactor. section bsup @@ -1461,7 +1520,7 @@ 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 rw [← familyOfBFamily_enum o f] - exact h _, fun h i => h _ _⟩ + exact h _, fun h _ => h _ _⟩ theorem bsup_le {o : Ordinal} {f : ∀ b < o, Ordinal} {a} : (∀ i h, f i h ≤ a) → bsup.{u, v} o f ≤ a := @@ -1908,12 +1967,15 @@ theorem IsNormal.eq_iff_zero_and_succ {f g : Ordinal.{u} → Ordinal.{u}} (hf : exact H b hb⟩ /-- A two-argument version of `Ordinal.blsub`. -We don't develop a full API for this, since it's only used in a handful of existence results. -/ + +Deprecated. If you need this value explicitly, write it in terms of `iSup`. If you just want an +upper bound for the image of `op`, use that `Iio a ×ˢ Iio b` is a small set. -/ +@[deprecated (since := "2024-10-11")] def blsub₂ (o₁ o₂ : Ordinal) (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) : Ordinal := lsub (fun x : o₁.toType × o₂.toType => op (typein_lt_self x.1) (typein_lt_self x.2)) --- TODO: deprecate this, and replace the arguments using it by arguments about small sets. +@[deprecated (since := "2024-10-11")] theorem lt_blsub₂ {o₁ o₂ : Ordinal} (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) {a b : Ordinal} (ha : a < o₁) (hb : b < o₂) : op ha hb < blsub₂ o₁ o₂ op := by @@ -1923,8 +1985,6 @@ theorem lt_blsub₂ {o₁ o₂ : Ordinal} end blsub --- TODO: deprecate in favor of `sInf sᶜ`. - section mex set_option linter.deprecated false @@ -1932,30 +1992,38 @@ set_option linter.deprecated false /-- The minimum excluded ordinal in a family of ordinals. -/ +@[deprecated "use sInf sᶜ instead" (since := "2024-09-20")] def mex {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal := sInf (Set.range f)ᶜ +@[deprecated (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) +@[deprecated (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) +@[deprecated (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 +@[deprecated (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]) +@[deprecated (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') +@[deprecated (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) +@[deprecated (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 refine mex_le_of_ne fun i hi => ?_ @@ -1963,6 +2031,7 @@ theorem mex_monotone {α β : Type u} {f : α → Ordinal.{max u v}} {g : β → rw [← hj] at hi exact ne_mex g j hi +@[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 by_contra! h @@ -1983,18 +2052,22 @@ theorem mex_lt_ord_succ_mk {ι : Type u} (f : ι → Ordinal.{u}) : `familyOfBFamily`. This is to `mex` as `bsup` is to `sup`. -/ +@[deprecated "use sInf sᶜ instead" (since := "2024-09-20")] def bmex (o : Ordinal) (f : ∀ a < o, Ordinal) : Ordinal := mex (familyOfBFamily o f) +@[deprecated (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 +@[deprecated (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) +@[deprecated (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 convert (config := {transparency := .default}) @@ -2002,24 +2075,29 @@ theorem ne_bmex {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {i} (hi) : -- Porting note: `familyOfBFamily_enum` → `typein_enum` rw [typein_enum] +@[deprecated (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 _ _ +@[deprecated (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⟩ +@[deprecated (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 _ +@[deprecated (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]) +@[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 rw [← mk_toType] @@ -2057,133 +2135,14 @@ theorem Ordinal.not_bddAbove_compl_of_small (s : Set Ordinal.{u}) [hs : Small.{u rw [union_compl_self, small_univ_iff] at this exact not_small_ordinal this -/-! ### Enumerating unbounded sets of ordinals with ordinals -/ +/-! ### Casting naturals into ordinals, compatibility with operations -/ namespace Ordinal -section - -/-- Enumerator function for an unbounded set of ordinals. -/ -def enumOrd (S : Set Ordinal.{u}) : Ordinal → Ordinal := - lt_wf.fix fun o f => sInf (S ∩ Set.Ici (blsub.{u, u} o f)) - -variable {S : Set Ordinal.{u}} - -/-- The equation that characterizes `enumOrd` definitionally. This isn't the nicest expression to - work with, so consider using `enumOrd_def` instead. -/ -theorem enumOrd_def' (o) : - enumOrd S o = sInf (S ∩ Set.Ici (blsub.{u, u} o fun a _ => enumOrd S a)) := - lt_wf.fix_eq _ _ - -/-- The set in `enumOrd_def'` is nonempty. -/ -theorem enumOrd_def'_nonempty (hS : Unbounded (· < ·) S) (a) : (S ∩ Set.Ici a).Nonempty := - let ⟨b, hb, hb'⟩ := hS a - ⟨b, hb, le_of_not_gt hb'⟩ - -private theorem enumOrd_mem_aux (hS : Unbounded (· < ·) S) (o) : - enumOrd S o ∈ S ∩ Set.Ici (blsub.{u, u} o fun c _ => enumOrd S c) := by - rw [enumOrd_def'] - exact csInf_mem (enumOrd_def'_nonempty hS _) - -theorem enumOrd_mem (hS : Unbounded (· < ·) S) (o) : enumOrd S o ∈ S := - (enumOrd_mem_aux hS o).left - -theorem blsub_le_enumOrd (hS : Unbounded (· < ·) S) (o) : - (blsub.{u, u} o fun c _ => enumOrd S c) ≤ enumOrd S o := - (enumOrd_mem_aux hS o).right - -theorem enumOrd_strictMono (hS : Unbounded (· < ·) S) : StrictMono (enumOrd S) := fun _ _ h => - (lt_blsub.{u, u} _ _ h).trans_le (blsub_le_enumOrd hS _) - -/-- A more workable definition for `enumOrd`. -/ -theorem enumOrd_def (o) : enumOrd S o = sInf (S ∩ { b | ∀ c, c < o → enumOrd S c < b }) := by - rw [enumOrd_def'] - congr; ext - exact ⟨fun h a hao => (lt_blsub.{u, u} _ _ hao).trans_le h, blsub_le⟩ - -/-- The set in `enumOrd_def` is nonempty. -/ -theorem enumOrd_def_nonempty (hS : Unbounded (· < ·) S) {o} : - { x | x ∈ S ∧ ∀ c, c < o → enumOrd S c < x }.Nonempty := - ⟨_, enumOrd_mem hS o, fun _ b => enumOrd_strictMono hS b⟩ - -@[simp] -theorem enumOrd_range {f : Ordinal → Ordinal} (hf : StrictMono f) : enumOrd (range f) = f := - funext fun o => by - apply Ordinal.induction o - intro a H - rw [enumOrd_def a] - have Hfa : f a ∈ range f ∩ { b | ∀ c, c < a → enumOrd (range f) c < b } := - ⟨mem_range_self a, fun b hb => by - rw [H b hb] - exact hf hb⟩ - refine (csInf_le' Hfa).antisymm ((le_csInf_iff'' ⟨_, Hfa⟩).2 ?_) - rintro _ ⟨⟨c, rfl⟩, hc : ∀ b < a, enumOrd (range f) b < f c⟩ - rw [hf.le_iff_le] - contrapose! hc - exact ⟨c, hc, (H c hc).ge⟩ - -@[simp] -theorem enumOrd_univ : enumOrd Set.univ = id := by - rw [← range_id] - exact enumOrd_range strictMono_id - -@[simp] -theorem enumOrd_zero : enumOrd S 0 = sInf S := by - rw [enumOrd_def] - simp [Ordinal.not_lt_zero] - -theorem enumOrd_succ_le {a b} (hS : Unbounded (· < ·) S) (ha : a ∈ S) (hb : enumOrd S b < a) : - enumOrd S (succ b) ≤ a := by - rw [enumOrd_def] - exact - csInf_le' ⟨ha, fun c hc => ((enumOrd_strictMono hS).monotone (le_of_lt_succ hc)).trans_lt hb⟩ - -theorem enumOrd_le_of_subset {S T : Set Ordinal} (hS : Unbounded (· < ·) S) (hST : S ⊆ T) (a) : - enumOrd T a ≤ enumOrd S a := by - apply Ordinal.induction a - intro b H - rw [enumOrd_def] - exact csInf_le' ⟨hST (enumOrd_mem hS b), fun c h => (H c h).trans_lt (enumOrd_strictMono hS h)⟩ - -theorem enumOrd_surjective (hS : Unbounded (· < ·) S) : ∀ s ∈ S, ∃ a, enumOrd S a = s := fun s hs => - ⟨sSup { a | enumOrd S a ≤ s }, by - apply le_antisymm - · rw [enumOrd_def] - refine csInf_le' ⟨hs, fun a ha => ?_⟩ - have : enumOrd S 0 ≤ s := by - rw [enumOrd_zero] - exact csInf_le' hs - -- Porting note: `flip` is required to infer a metavariable. - rcases flip exists_lt_of_lt_csSup ha ⟨0, this⟩ with ⟨b, hb, hab⟩ - exact (enumOrd_strictMono hS hab).trans_le hb - · by_contra! h - exact (le_csSup ⟨s, fun a => ((enumOrd_strictMono hS).id_le a).trans⟩ - (enumOrd_succ_le hS hs h)).not_lt (lt_succ _)⟩ - -/-- An order isomorphism between an unbounded set of ordinals and the ordinals. -/ -def enumOrdOrderIso (hS : Unbounded (· < ·) S) : Ordinal ≃o S := - StrictMono.orderIsoOfSurjective (fun o => ⟨_, enumOrd_mem hS o⟩) (enumOrd_strictMono hS) fun s => - let ⟨a, ha⟩ := enumOrd_surjective hS s s.prop - ⟨a, Subtype.eq ha⟩ - -theorem range_enumOrd (hS : Unbounded (· < ·) S) : range (enumOrd S) = S := by - rw [range_eq_iff] - exact ⟨enumOrd_mem hS, enumOrd_surjective hS⟩ - -/-- A characterization of `enumOrd`: it is the unique strict monotonic function with range `S`. -/ -theorem eq_enumOrd (f : Ordinal → Ordinal) (hS : Unbounded (· < ·) S) : - StrictMono f ∧ range f = S ↔ f = enumOrd S := by - constructor - · rintro ⟨h₁, h₂⟩ - rwa [← h₁.range_inj (enumOrd_strictMono hS), range_enumOrd hS] - · rintro rfl - exact ⟨enumOrd_strictMono hS, range_enumOrd hS⟩ - -end - -/-! ### Casting naturals into ordinals, compatibility with operations -/ - +instance instCharZero : CharZero Ordinal := by + refine ⟨fun a b h ↦ ?_⟩ + rwa [← Cardinal.ord_nat, ← Cardinal.ord_nat, Cardinal.ord_inj, Nat.cast_inj] at h @[simp] theorem one_add_natCast (m : ℕ) : 1 + (m : Ordinal) = succ m := by @@ -2207,42 +2166,37 @@ theorem natCast_mul (m : ℕ) : ∀ n : ℕ, ((m * n : ℕ) : Ordinal) = m * n @[deprecated (since := "2024-04-17")] alias nat_cast_mul := natCast_mul -/-- Alias of `Nat.cast_le`, specialized to `Ordinal` --/ -theorem natCast_le {m n : ℕ} : (m : Ordinal) ≤ n ↔ m ≤ n := by - rw [← Cardinal.ord_nat, ← Cardinal.ord_nat, Cardinal.ord_le_ord, Cardinal.natCast_le] +@[deprecated Nat.cast_le (since := "2024-10-17")] +theorem natCast_le {m n : ℕ} : (m : Ordinal) ≤ n ↔ m ≤ n := Nat.cast_le @[deprecated (since := "2024-04-17")] alias nat_cast_le := natCast_le -/-- Alias of `Nat.cast_inj`, specialized to `Ordinal` --/ -theorem natCast_inj {m n : ℕ} : (m : Ordinal) = n ↔ m = n := by - simp only [le_antisymm_iff, natCast_le] +@[deprecated Nat.cast_inj (since := "2024-10-17")] +theorem natCast_inj {m n : ℕ} : (m : Ordinal) = n ↔ m = n := Nat.cast_inj @[deprecated (since := "2024-04-17")] alias nat_cast_inj := natCast_inj -instance charZero : CharZero Ordinal where - cast_injective _ _ := natCast_inj.mp - -/-- Alias of `Nat.cast_lt`, specialized to `Ordinal` --/ +@[deprecated Nat.cast_lt (since := "2024-10-17")] theorem natCast_lt {m n : ℕ} : (m : Ordinal) < n ↔ m < n := Nat.cast_lt @[deprecated (since := "2024-04-17")] alias nat_cast_lt := natCast_lt -/-- Alias of `Nat.cast_eq_zero`, specialized to `Ordinal` --/ +@[deprecated Nat.cast_eq_zero (since := "2024-10-17")] theorem natCast_eq_zero {n : ℕ} : (n : Ordinal) = 0 ↔ n = 0 := Nat.cast_eq_zero @[deprecated (since := "2024-04-17")] alias nat_cast_eq_zero := natCast_eq_zero -/-- Alias of `Nat.cast_eq_zero`, specialized to `Ordinal` --/ +@[deprecated Nat.cast_ne_zero (since := "2024-10-17")] theorem natCast_ne_zero {n : ℕ} : (n : Ordinal) ≠ 0 ↔ n ≠ 0 := Nat.cast_ne_zero @[deprecated (since := "2024-04-17")] alias nat_cast_ne_zero := natCast_ne_zero -/-- Alias of `Nat.cast_pos'`, specialized to `Ordinal` --/ +@[deprecated Nat.cast_pos' (since := "2024-10-17")] theorem natCast_pos {n : ℕ} : (0 : Ordinal) < n ↔ 0 < n := Nat.cast_pos' @[deprecated (since := "2024-04-17")] @@ -2251,10 +2205,10 @@ alias nat_cast_pos := natCast_pos @[simp, norm_cast] theorem natCast_sub (m n : ℕ) : ((m - n : ℕ) : Ordinal) = m - n := by rcases le_total m n with h | h - · rw [tsub_eq_zero_iff_le.2 h, Ordinal.sub_eq_zero_iff_le.2 (natCast_le.2 h)] + · rw [tsub_eq_zero_iff_le.2 h, Ordinal.sub_eq_zero_iff_le.2 (Nat.cast_le.2 h)] rfl · apply (add_left_cancel n).1 - rw [← Nat.cast_add, add_tsub_cancel_of_le h, Ordinal.add_sub_cancel_of_le (natCast_le.2 h)] + rw [← Nat.cast_add, add_tsub_cancel_of_le h, Ordinal.add_sub_cancel_of_le (Nat.cast_le.2 h)] @[deprecated (since := "2024-04-17")] alias nat_cast_sub := natCast_sub @@ -2263,12 +2217,12 @@ alias nat_cast_sub := natCast_sub theorem natCast_div (m n : ℕ) : ((m / n : ℕ) : Ordinal) = m / n := by rcases eq_or_ne n 0 with (rfl | hn) · simp - · have hn' := natCast_ne_zero.2 hn + · have hn' : (n : Ordinal) ≠ 0 := Nat.cast_ne_zero.2 hn apply le_antisymm - · rw [le_div hn', ← natCast_mul, natCast_le, mul_comm] + · rw [le_div hn', ← natCast_mul, Nat.cast_le, mul_comm] apply Nat.div_mul_le_self - · rw [div_le hn', ← add_one_eq_succ, ← Nat.cast_succ, ← natCast_mul, natCast_lt, mul_comm, ← - Nat.div_lt_iff_lt_mul (Nat.pos_of_ne_zero hn)] + · rw [div_le hn', ← add_one_eq_succ, ← Nat.cast_succ, ← natCast_mul, Nat.cast_lt, mul_comm, + ← Nat.div_lt_iff_lt_mul (Nat.pos_of_ne_zero hn)] apply Nat.lt_succ_self @[deprecated (since := "2024-04-17")] @@ -2305,14 +2259,6 @@ namespace Cardinal open Ordinal -@[simp] -theorem ord_aleph0 : ord.{u} ℵ₀ = ω := - le_antisymm (ord_le.2 <| le_rfl) <| - le_of_forall_lt fun o h => by - rcases Ordinal.lt_lift_iff.1 h with ⟨o, rfl, h'⟩ - rw [lt_ord, ← lift_card, lift_lt_aleph0, ← typein_enum (· < ·) h'] - exact lt_aleph0_iff_fintype.2 ⟨Set.fintypeLTNat _⟩ - @[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] @@ -2325,7 +2271,7 @@ 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. - rw [← IsNormal.bsup_eq.{u, u} (add_isNormal b) h, lt_bsup, bex_def] + rw [← IsNormal.bsup_eq.{u, u} (isNormal_add_right b) h, lt_bsup, bex_def] theorem lt_omega0 {o : Ordinal} : o < ω ↔ ∃ n : ℕ, o = n := by simp_rw [← Cardinal.ord_aleph0, Cardinal.lt_ord, lt_aleph0, card_eq_nat] @@ -2357,13 +2303,16 @@ theorem one_lt_omega0 : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omeg @[deprecated (since := "2024-09-30")] alias one_lt_omega := one_lt_omega0 -theorem omega0_isLimit : IsLimit ω := +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)⟩ +@[deprecated (since := "2024-10-14")] +alias omega0_isLimit := isLimit_omega0 + @[deprecated (since := "2024-09-30")] -alias omega_isLimit := omega0_isLimit +alias omega_isLimit := isLimit_omega0 theorem omega0_le {o : Ordinal} : ω ≤ o ↔ ∀ n : ℕ, ↑n ≤ o := ⟨fun h n => (nat_lt_omega0 _).le.trans h, fun H => @@ -2400,14 +2349,14 @@ theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ refine ⟨fun l => ⟨l.1, ⟨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 omega0_isLimit] + add_le_of_limit isLimit_omega0] intro b hb rcases lt_omega0.1 hb with ⟨n, rfl⟩ exact (add_le_add_right (mul_div_le _ _) _).trans - (lt_sub.1 <| nat_lt_limit (sub_isLimit l hx) _).le + (lt_sub.1 <| nat_lt_limit (isLimit_sub l hx) _).le · rcases h with ⟨a0, b, rfl⟩ - refine mul_isLimit_left omega0_isLimit (Ordinal.pos_iff_ne_zero.2 <| mt ?_ a0) + refine isLimit_mul_left isLimit_omega0 (Ordinal.pos_iff_ne_zero.2 <| mt ?_ a0) intro e simp only [e, mul_zero] @@ -2460,19 +2409,19 @@ alias IsNormal.apply_omega := IsNormal.apply_omega0 @[simp] theorem iSup_add_nat (o : Ordinal) : ⨆ n : ℕ, o + n = o + ω := - (add_isNormal o).apply_omega0 + (isNormal_add_right o).apply_omega0 set_option linter.deprecated false in @[deprecated iSup_add_nat (since := "2024-08-27")] theorem sup_add_nat (o : Ordinal) : (sup fun n : ℕ => o + n) = o + ω := - (add_isNormal o).apply_omega0 + (isNormal_add_right o).apply_omega0 @[simp] theorem iSup_mul_nat (o : Ordinal) : ⨆ n : ℕ, o * n = o * ω := by rcases eq_zero_or_pos o with (rfl | ho) · rw [zero_mul] exact iSup_eq_zero_iff.2 fun n => zero_mul (n : Ordinal) - · exact (mul_isNormal ho).apply_omega0 + · exact (isNormal_mul_right ho).apply_omega0 set_option linter.deprecated false in @[deprecated iSup_add_nat (since := "2024-08-27")] @@ -2484,54 +2433,27 @@ theorem sup_mul_nat (o : Ordinal) : (sup fun n : ℕ => o * n) = o * ω := by end Ordinal -variable {α : Type u} {r : α → α → Prop} {a b : α} - -namespace Acc - -/-- The rank of an element `a` accessible under a relation `r` is defined inductively as the -smallest ordinal greater than the ranks of all elements below it (i.e. elements `b` such that -`r b a`). -/ -noncomputable def rank (h : Acc r a) : Ordinal.{u} := - Acc.recOn h fun a _h ih => ⨆ b : { b // r b a }, Order.succ (ih b b.2) - -theorem rank_eq (h : Acc r a) : - h.rank = ⨆ b : { b // r b a }, Order.succ (h.inv b.2).rank := by - change (Acc.intro a fun _ => h.inv).rank = _ - rfl - -/-- if `r a b` then the rank of `a` is less than the rank of `b`. -/ -theorem rank_lt_of_rel (hb : Acc r b) (h : r a b) : (hb.inv h).rank < hb.rank := - (Order.lt_succ _).trans_le <| by - rw [hb.rank_eq] - refine le_trans ?_ (Ordinal.le_iSup _ ⟨a, h⟩) - rfl - -end Acc - -namespace WellFounded - -variable (hwf : WellFounded r) - -/-- The rank of an element `a` under a well-founded relation `r` is defined inductively as the -smallest ordinal greater than the ranks of all elements below it (i.e. elements `b` such that -`r b a`). -/ -noncomputable def rank (a : α) : Ordinal.{u} := - (hwf.apply a).rank +namespace Cardinal -theorem rank_eq : - hwf.rank a = ⨆ b : { b // r b a }, Order.succ (hwf.rank b) := by - rw [rank, Acc.rank_eq] - rfl +open Ordinal -theorem rank_lt_of_rel (h : r a b) : hwf.rank a < hwf.rank b := - Acc.rank_lt_of_rel _ h +theorem isLimit_ord {c} (co : ℵ₀ ≤ c) : (ord c).IsLimit := by + 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 + · rw [ord_le] at h ⊢ + rwa [← @add_one_of_aleph0_le (card a), ← card_succ] + rw [← ord_le, ← le_succ_of_isLimit, ord_le] + · exact co.trans h + · rw [ord_aleph0] + exact Ordinal.isLimit_omega0 -theorem rank_strictMono [Preorder α] [WellFoundedLT α] : - StrictMono (rank <| @wellFounded_lt α _ _) := fun _ _ => rank_lt_of_rel _ +@[deprecated (since := "2024-10-14")] +alias ord_isLimit := isLimit_ord -theorem rank_strictAnti [Preorder α] [WellFoundedGT α] : - StrictAnti (rank <| @wellFounded_gt α _ _) := fun _ _ => rank_lt_of_rel wellFounded_gt +theorem noMaxOrder {c} (h : ℵ₀ ≤ c) : NoMaxOrder c.ord.toType := + toType_noMax_of_succ_lt (isLimit_ord h).2 -end WellFounded +end Cardinal -set_option linter.style.longFile 2700 +set_option linter.style.longFile 2600 diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean index ffe4d081350be..c4925eb265a0c 100644 --- a/Mathlib/SetTheory/Ordinal/Basic.lean +++ b/Mathlib/SetTheory/Ordinal/Basic.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Floris van Doorn -/ import Mathlib.Algebra.Order.SuccPred import Mathlib.Data.Sum.Order -import Mathlib.Order.InitialSeg import Mathlib.SetTheory.Cardinal.Basic import Mathlib.Tactic.PPWithUniv @@ -140,11 +139,6 @@ instance inhabited : Inhabited Ordinal := instance one : One Ordinal := ⟨type <| @EmptyRelation PUnit⟩ -/-- The order type of an element inside a well order. For the embedding as a principal segment, see -`typein.principalSeg`. -/ -def typein (r : α → α → Prop) [IsWellOrder α r] (a : α) : Ordinal := - type (Subrel r { b | r b a }) - @[simp] theorem type_def' (w : WellOrder) : ⟦w⟧ = type w.r := by cases w @@ -155,12 +149,16 @@ theorem type_def (r) [wo : IsWellOrder α r] : (⟦⟨α, r, wo⟩⟧ : Ordinal) rfl @[simp] +theorem type_toType (o : Ordinal) : type (α := o.toType) (· < ·) = o := + (type_def' _).symm.trans <| Quotient.out_eq o + +@[deprecated type_toType (since := "2024-10-22")] theorem type_lt (o : Ordinal) : type (α := o.toType) (· < ·) = o := (type_def' _).symm.trans <| Quotient.out_eq o -@[deprecated type_lt (since := "2024-08-26")] +@[deprecated type_toType (since := "2024-08-26")] theorem type_out (o : Ordinal) : Ordinal.type o.out.r = o := - type_lt o + type_toType o theorem type_eq {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] : type r = type s ↔ Nonempty (r ≃r s) := @@ -191,15 +189,14 @@ theorem type_pEmpty : type (@EmptyRelation PEmpty) = 0 := theorem type_empty : type (@EmptyRelation Empty) = 0 := type_eq_zero_of_empty _ -theorem type_eq_one_of_unique (r) [IsWellOrder α r] [Unique α] : type r = 1 := - (RelIso.relIsoOfUniqueOfIrrefl r _).ordinal_type_eq +theorem type_eq_one_of_unique (r) [IsWellOrder α r] [Nonempty α] [Subsingleton α] : type r = 1 := by + cases nonempty_unique α + exact (RelIso.relIsoOfUniqueOfIrrefl r _).ordinal_type_eq @[simp] theorem type_eq_one_iff_unique [IsWellOrder α r] : type r = 1 ↔ Nonempty (Unique α) := - ⟨fun h => - let ⟨s⟩ := type_eq.1 h - ⟨s.toEquiv.unique⟩, - fun ⟨h⟩ => @type_eq_one_of_unique α r _ h⟩ + ⟨fun h ↦ let ⟨s⟩ := type_eq.1 h; ⟨s.toEquiv.unique⟩, + fun ⟨_⟩ ↦ type_eq_one_of_unique r⟩ theorem type_pUnit : type (@EmptyRelation PUnit) = 1 := rfl @@ -209,7 +206,7 @@ theorem type_unit : type (@EmptyRelation Unit) = 1 := @[simp] theorem toType_empty_iff_eq_zero {o : Ordinal} : IsEmpty o.toType ↔ o = 0 := by - rw [← @type_eq_zero_iff_isEmpty o.toType (· < ·), type_lt] + rw [← @type_eq_zero_iff_isEmpty o.toType (· < ·), type_toType] @[deprecated toType_empty_iff_eq_zero (since := "2024-08-26")] alias out_empty_iff_eq_zero := toType_empty_iff_eq_zero @@ -223,7 +220,7 @@ instance isEmpty_toType_zero : IsEmpty (toType 0) := @[simp] theorem toType_nonempty_iff_ne_zero {o : Ordinal} : Nonempty o.toType ↔ o ≠ 0 := by - rw [← @type_ne_zero_iff_nonempty o.toType (· < ·), type_lt] + rw [← @type_ne_zero_iff_nonempty o.toType (· < ·), type_toType] @[deprecated toType_nonempty_iff_ne_zero (since := "2024-08-26")] alias out_nonempty_iff_ne_zero := toType_nonempty_iff_ne_zero @@ -248,6 +245,18 @@ theorem inductionOn {C : Ordinal → Prop} (o : Ordinal) (H : ∀ (α r) [IsWellOrder α r], C (type r)) : C o := Quot.inductionOn o fun ⟨α, r, wo⟩ => @H α r wo +@[elab_as_elim] +theorem inductionOn₂ {C : Ordinal → Ordinal → Prop} (o₁ o₂ : Ordinal) + (H : ∀ (α r) [IsWellOrder α r] (β s) [IsWellOrder β s], C (type r) (type s)) : C o₁ o₂ := + Quotient.inductionOn₂ o₁ o₂ fun ⟨α, r, wo₁⟩ ⟨β, s, wo₂⟩ => @H α r wo₁ β s wo₂ + +@[elab_as_elim] +theorem inductionOn₃ {C : Ordinal → Ordinal → Ordinal → Prop} (o₁ o₂ o₃ : Ordinal) + (H : ∀ (α r) [IsWellOrder α r] (β s) [IsWellOrder β s] (γ t) [IsWellOrder γ t], + C (type r) (type s) (type t)) : C o₁ o₂ o₃ := + Quotient.inductionOn₃ o₁ o₂ o₃ fun ⟨α, r, wo₁⟩ ⟨β, s, wo₂⟩ ⟨γ, t, wo₃⟩ => + @H α r wo₁ β s wo₂ γ t wo₃ + /-! ### The order on ordinals -/ /-- @@ -287,7 +296,7 @@ instance partialOrder : PartialOrder Ordinal where instance linearOrder : LinearOrder Ordinal := {inferInstanceAs (PartialOrder Ordinal) with - le_total := fun a b => Quotient.inductionOn₂ a b fun ⟨α, r, _⟩ ⟨β, s, _⟩ => + le_total := fun a b => Quotient.inductionOn₂ a b fun ⟨_, r, _⟩ ⟨_, s, _⟩ => (InitialSeg.total r s).recOn (fun f => Or.inl ⟨f⟩) fun f => Or.inr ⟨f⟩ decidableLE := Classical.decRel _ } @@ -349,89 +358,89 @@ instance NeZero.one : NeZero (1 : Ordinal) := /-- Given two ordinals `α ≤ β`, then `initialSegToType α β` is the initial segment embedding of `α.toType` into `β.toType`. -/ -def initialSegToType {α β : Ordinal} (h : α ≤ β) : - @InitialSeg α.toType β.toType (· < ·) (· < ·) := by - change α.out.r ≼i β.out.r - rw [← Quotient.out_eq α, ← Quotient.out_eq β] at h; revert h - cases Quotient.out α; cases Quotient.out β; exact Classical.choice +def initialSegToType {α β : Ordinal} (h : α ≤ β) : α.toType ≤i β.toType := by + apply Classical.choice (type_le_iff.mp _) + rwa [type_toType, type_toType] @[deprecated initialSegToType (since := "2024-08-26")] noncomputable alias initialSegOut := initialSegToType /-- Given two ordinals `α < β`, then `principalSegToType α β` is the principal segment embedding of `α.toType` into `β.toType`. -/ -def principalSegToType {α β : Ordinal} (h : α < β) : - @PrincipalSeg α.toType β.toType (· < ·) (· < ·) := by - change α.out.r ≺i β.out.r - rw [← Quotient.out_eq α, ← Quotient.out_eq β] at h; revert h - cases Quotient.out α; cases Quotient.out β; exact Classical.choice +def principalSegToType {α β : Ordinal} (h : α < β) : α.toType by - rcases f.down.1 h with ⟨b, rfl⟩; exact ⟨b, rfl⟩⟩ - -@[simp] -theorem typein_apply {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] - (f : r ≼i s) (a : α) : Ordinal.typein s (f a) = Ordinal.typein r a := - Eq.symm <| - Quotient.sound - ⟨RelIso.ofSurjective - (RelEmbedding.codRestrict _ ((Subrel.relEmbedding _ _).trans f) fun ⟨x, h⟩ => by - rw [RelEmbedding.trans_apply]; exact f.toRelEmbedding.map_rel_iff.2 h) - fun ⟨y, h⟩ => by - rcases f.mem_range_of_rel h with ⟨a, rfl⟩ - exact ⟨⟨a, f.toRelEmbedding.map_rel_iff.1 h⟩, - Subtype.eq <| RelEmbedding.trans_apply _ _ _⟩⟩ +theorem typein_top {α β} {r : α → α → Prop} {s : β → β → Prop} + [IsWellOrder α r] [IsWellOrder β s] (f : r ≺i s) : typein s f.top = type r := + f.subrelIso.ordinal_type_eq @[simp] theorem typein_lt_typein (r : α → α → Prop) [IsWellOrder α r] {a b : α} : typein r a < typein r b ↔ r a b := - ⟨fun ⟨f⟩ => by - have : f.top.1 = a := by - let f' := PrincipalSeg.ofElement r a - let g' := f.trans (PrincipalSeg.ofElement r b) - have : g'.top = f'.top := by rw [Subsingleton.elim f' g'] - exact this - rw [← this] - exact f.top.2, fun h => - ⟨PrincipalSeg.codRestrict _ (PrincipalSeg.ofElement r a) (fun x => @trans _ r _ _ _ _ x.2 h) h⟩⟩ + (typein r).map_rel_iff + +theorem mem_range_typein_iff (r : α → α → Prop) [IsWellOrder α r] {o} : + o ∈ Set.range (typein r) ↔ o < type r := + (typein r).mem_range_iff_rel theorem typein_surj (r : α → α → Prop) [IsWellOrder α r] {o} (h : o < type r) : - ∃ a, typein r a = o := - inductionOn o (fun _ _ _ ⟨f⟩ => ⟨f.top, typein_top _⟩) h + o ∈ Set.range (typein r) := + (typein r).mem_range_of_rel_top h + +theorem typein_surjOn (r : α → α → Prop) [IsWellOrder α r] : + Set.SurjOn (typein r) Set.univ (Set.Iio (type r)) := + (typein r).surjOn theorem typein_injective (r : α → α → Prop) [IsWellOrder α r] : Injective (typein r) := - injective_of_increasing r (· < ·) (typein r) (typein_lt_typein r).2 + (typein r).injective -@[simp] theorem typein_inj (r : α → α → Prop) [IsWellOrder α r] {a b} : typein r a = typein r b ↔ a = b := - (typein_injective r).eq_iff - -/-- Principal segment version of the `typein` function, embedding a well order into ordinals as a -principal segment. -/ -def typein.principalSeg {α : Type u} (r : α → α → Prop) [IsWellOrder α r] : - @PrincipalSeg α Ordinal.{u} r (· < ·) := - ⟨⟨⟨typein r, typein_injective r⟩, typein_lt_typein r⟩, type r, - fun _ ↦ ⟨typein_surj r, fun ⟨a, h⟩ ↦ h ▸ typein_lt_type r a⟩⟩ - -@[simp] -theorem typein.principalSeg_coe (r : α → α → Prop) [IsWellOrder α r] : - (typein.principalSeg r : α → Ordinal) = typein r := - rfl + (typein r).inj /-! ### Enumerating elements in a well-order with ordinals. -/ @@ -443,17 +452,17 @@ the elements of `α`. -/ -- The explicit typing is required in order for `simp` to work properly. @[simps! symm_apply_coe] def enum (r : α → α → Prop) [IsWellOrder α r] : - @RelIso (Subtype fun o => o < type r) α (Subrel (· < · ) _) r := - (typein.principalSeg r).subrelIso + @RelIso { o // o < type r } α (Subrel (· < ·) { o | o < type r }) r := + (typein r).subrelIso @[simp] theorem typein_enum (r : α → α → Prop) [IsWellOrder α r] {o} (h : o < type r) : typein r (enum r ⟨o, h⟩) = o := - (typein.principalSeg r).apply_subrelIso _ + (typein r).apply_subrelIso _ theorem enum_type {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] (f : s ≺i r) {h : type s < type r} : enum r ⟨type s, h⟩ = f.top := - (typein.principalSeg r).injective <| (typein_enum _ _).trans (typein_top _).symm + (typein r).injective <| (typein_enum _ _).trans (typein_top _).symm @[simp] theorem enum_typein (r : α → α → Prop) [IsWellOrder α r] (a : α) : @@ -496,6 +505,10 @@ theorem induction {p : Ordinal.{u} → Prop} (i : Ordinal.{u}) (h : ∀ j, (∀ p i := lt_wf.induction i h +theorem typein_apply {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] + (f : r ≼i s) (a : α) : typein s (f a) = typein r a := by + rw [← f.leLT_apply _ a, (f.leLT _).eq] + /-! ### Cardinality of ordinals -/ @@ -587,13 +600,6 @@ theorem lift_id : ∀ a, lift.{u, u} a = a := theorem lift_uzero (a : Ordinal.{u}) : lift.{0} a = a := lift_id' a -@[simp] -theorem lift_lift (a : Ordinal) : lift.{w} (lift.{v} a) = lift.{max v w} a := - inductionOn a fun _ _ _ => - Quotient.sound - ⟨(RelIso.preimage Equiv.ulift _).trans <| - (RelIso.preimage Equiv.ulift _).trans (RelIso.preimage Equiv.ulift _).symm⟩ - theorem lift_type_le {α : Type u} {β : Type v} {r s} [IsWellOrder α r] [IsWellOrder β s] : lift.{max v w} (type r) ≤ lift.{max u w} (type s) ↔ Nonempty (r ≼i s) := ⟨fun ⟨f⟩ => @@ -625,19 +631,50 @@ theorem lift_type_lt {α : Type u} {β : Type v} {r s} [IsWellOrder α r] [IsWel (InitialSeg.ofIso (RelIso.preimage Equiv.ulift s).symm)⟩⟩ @[simp] -theorem lift_le {a b : Ordinal} : lift.{u,v} a ≤ lift.{u,v} b ↔ a ≤ b := - inductionOn a fun α r _ => - inductionOn b fun β s _ => by - rw [← lift_umax] - exact lift_type_le.{_,_,u} +theorem lift_le {a b : Ordinal} : lift.{u, v} a ≤ lift.{u, v} b ↔ a ≤ b := + inductionOn₂ a b fun α r _ β s _ => by + rw [← lift_umax] + exact lift_type_le.{_,_,u} + +@[simp] +theorem lift_inj {a b : Ordinal} : lift.{u, v} a = lift.{u, v} b ↔ a = b := by + simp_rw [le_antisymm_iff, lift_le] @[simp] -theorem lift_inj {a b : Ordinal} : lift.{u,v} a = lift.{u,v} b ↔ a = b := by - simp only [le_antisymm_iff, lift_le] +theorem lift_lt {a b : Ordinal} : lift.{u, v} a < lift.{u, v} b ↔ a < b := by + simp_rw [lt_iff_le_not_le, lift_le] @[simp] -theorem lift_lt {a b : Ordinal} : lift.{u,v} a < lift.{u,v} b ↔ a < b := by - simp only [lt_iff_le_not_le, lift_le] +theorem lift_typein_top {r : α → α → Prop} {s : β → β → Prop} + [IsWellOrder α r] [IsWellOrder β s] (f : r ≺i s) : lift.{u} (typein s f.top) = lift (type r) := + f.subrelIso.ordinal_lift_type_eq + +/-- Initial segment version of the lift operation on ordinals, embedding `Ordinal.{u}` in +`Ordinal.{v}` as an initial segment when `u ≤ v`. -/ +def liftInitialSeg : Ordinal.{v} ≤i Ordinal.{max u v} := by + refine ⟨RelEmbedding.ofMonotone lift.{u} (by simp), + fun a b ↦ Ordinal.inductionOn₂ a b fun α r _ β s _ h ↦ ?_⟩ + rw [RelEmbedding.ofMonotone_coe, ← lift_id'.{max u v} (type s), + ← lift_umax.{v, u}, lift_type_lt] at h + obtain ⟨f⟩ := h + use typein r f.top + rw [RelEmbedding.ofMonotone_coe, ← lift_umax, lift_typein_top, lift_id'] + +@[deprecated liftInitialSeg (since := "2024-09-21")] +alias lift.initialSeg := liftInitialSeg + +@[simp] +theorem liftInitialSeg_coe : (liftInitialSeg.{v, u} : Ordinal → Ordinal) = lift.{v, u} := + rfl + +set_option linter.deprecated false in +@[deprecated liftInitialSeg_coe (since := "2024-09-21")] +theorem lift.initialSeg_coe : (lift.initialSeg.{v, u} : Ordinal → Ordinal) = lift.{v, u} := + rfl + +@[simp] +theorem lift_lift (a : Ordinal.{u}) : lift.{w} (lift.{v} a) = lift.{max v w} a := + (liftInitialSeg.trans liftInitialSeg).eq liftInitialSeg a @[simp] theorem lift_zero : lift 0 = 0 := @@ -648,59 +685,25 @@ theorem lift_one : lift 1 = 1 := type_eq_one_of_unique _ @[simp] -theorem lift_card (a) : Cardinal.lift.{u,v} (card a)= card (lift.{u,v} a) := +theorem lift_card (a) : Cardinal.lift.{u, v} (card a) = card (lift.{u} a) := inductionOn a fun _ _ _ => rfl -theorem lift_down' {a : Cardinal.{u}} {b : Ordinal.{max u v}} - (h : card.{max u v} b ≤ Cardinal.lift.{v,u} a) : ∃ a', lift.{v,u} a' = b := - let ⟨c, e⟩ := Cardinal.lift_down h - Cardinal.inductionOn c - (fun α => - inductionOn b fun β s _ e' => by - rw [card_type, ← Cardinal.lift_id'.{max u v, u} #β, ← Cardinal.lift_umax.{u, v}, - lift_mk_eq.{u, max u v, max u v}] at e' - cases' e' with f - have g := RelIso.preimage f s - haveI := (g : f ⁻¹'o s ↪r s).isWellOrder - have := lift_type_eq.{u, max u v, max u v}.2 ⟨g⟩ - rw [lift_id, lift_umax.{u, v}] at this - exact ⟨_, this⟩) - e +theorem mem_range_lift_of_le {a : Ordinal.{u}} {b : Ordinal.{max u v}} (h : b ≤ lift.{v} a) : + b ∈ Set.range lift.{v} := + liftInitialSeg.mem_range_of_le h +@[deprecated mem_range_lift_of_le (since := "2024-10-07")] theorem lift_down {a : Ordinal.{u}} {b : Ordinal.{max u v}} (h : b ≤ lift.{v,u} a) : ∃ a', lift.{v,u} a' = b := - @lift_down' (card a) _ (by rw [lift_card]; exact card_le_card h) + mem_range_lift_of_le h theorem le_lift_iff {a : Ordinal.{u}} {b : Ordinal.{max u v}} : - b ≤ lift.{v,u} a ↔ ∃ a', lift.{v,u} a' = b ∧ a' ≤ a := - ⟨fun h => - let ⟨a', e⟩ := lift_down h - ⟨a', e, lift_le.1 <| e.symm ▸ h⟩, - fun ⟨_, e, h⟩ => e ▸ lift_le.2 h⟩ + b ≤ lift.{v} a ↔ ∃ a' ≤ a, lift.{v} a' = b := + liftInitialSeg.le_apply_iff theorem lt_lift_iff {a : Ordinal.{u}} {b : Ordinal.{max u v}} : - b < lift.{v,u} a ↔ ∃ a', lift.{v,u} a' = b ∧ a' < a := - ⟨fun h => - let ⟨a', e⟩ := lift_down (le_of_lt h) - ⟨a', e, lift_lt.1 <| e.symm ▸ h⟩, - fun ⟨_, e, h⟩ => e ▸ lift_lt.2 h⟩ - -/-- Initial segment version of the lift operation on ordinals, embedding `ordinal.{u}` in - `ordinal.{v}` as an initial segment when `u ≤ v`. -/ -def liftInitialSeg : @InitialSeg Ordinal.{u} Ordinal.{max u v} (· < ·) (· < ·) := - ⟨⟨⟨lift.{v}, fun _ _ => lift_inj.1⟩, lift_lt⟩, fun _ _ h => lift_down (le_of_lt h)⟩ - -@[deprecated liftInitialSeg (since := "2024-09-21")] -alias lift.initialSeg := liftInitialSeg - -@[simp] -theorem liftInitialSeg_coe : (liftInitialSeg.{u, v} : Ordinal → Ordinal) = lift.{v, u} := - rfl - -set_option linter.deprecated false in -@[deprecated liftInitialSeg_coe (since := "2024-09-21")] -theorem lift.initialSeg_coe : (lift.initialSeg.{u, v} : Ordinal → Ordinal) = lift.{v, u} := - rfl + b < lift.{v} a ↔ ∃ a' < a, lift.{v} a' = b := + liftInitialSeg.lt_apply_iff /-! ### The first infinite ordinal ω -/ @@ -709,9 +712,6 @@ theorem lift.initialSeg_coe : (lift.initialSeg.{u, v} : Ordinal → Ordinal) = l def omega0 : Ordinal.{u} := lift <| @type ℕ (· < ·) _ -@[deprecated Ordinal.omega0 (since := "2024-09-26")] -alias omega := omega0 - @[inherit_doc] scoped notation "ω" => Ordinal.omega0 @@ -745,21 +745,20 @@ the addition, together with properties of the other operations, are proved in /-- `o₁ + o₂` is the order on the disjoint union of `o₁` and `o₂` obtained by declaring that - every element of `o₁` is smaller than every element of `o₂`. -/ +every element of `o₁` is smaller than every element of `o₂`. -/ instance add : Add Ordinal.{u} := - ⟨fun o₁ o₂ => - Quotient.liftOn₂ o₁ o₂ (fun ⟨_, r, _⟩ ⟨_, s, _⟩ => type (Sum.Lex r s)) - fun _ _ _ _ ⟨f⟩ ⟨g⟩ => Quot.sound ⟨RelIso.sumLexCongr f g⟩⟩ + ⟨fun o₁ o₂ => Quotient.liftOn₂ o₁ o₂ (fun ⟨_, r, _⟩ ⟨_, s, _⟩ => type (Sum.Lex r s)) + fun _ _ _ _ ⟨f⟩ ⟨g⟩ => (RelIso.sumLexCongr f g).ordinal_type_eq⟩ instance addMonoidWithOne : AddMonoidWithOne Ordinal.{u} where add := (· + ·) zero := 0 one := 1 zero_add o := - inductionOn o fun α r _ => + inductionOn o fun α _ _ => Eq.symm <| Quotient.sound ⟨⟨(emptySum PEmpty α).symm, Sum.lex_inr_inr⟩⟩ add_zero o := - inductionOn o fun α r _ => + inductionOn o fun α _ _ => Eq.symm <| Quotient.sound ⟨⟨(sumEmpty α PEmpty).symm, Sum.lex_inl_inl⟩⟩ add_assoc o₁ o₂ o₃ := Quotient.inductionOn₃ o₁ o₂ o₃ fun ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ => @@ -790,45 +789,17 @@ theorem card_ofNat (n : ℕ) [n.AtLeastTwo] : card.{u} (no_index (OfNat.ofNat n)) = OfNat.ofNat n := card_nat n --- Porting note: Rewritten proof of elim, previous version was difficult to debug -instance add_covariantClass_le : CovariantClass Ordinal.{u} Ordinal.{u} (· + ·) (· ≤ ·) where - elim := fun c a b h => by - revert h c - refine inductionOn a (fun α₁ r₁ _ ↦ ?_) - refine inductionOn b (fun α₂ r₂ _ ↦ ?_) - rintro c ⟨⟨⟨f, fo⟩, fi⟩⟩ - refine inductionOn c (fun β s _ ↦ ?_) - refine ⟨⟨⟨(Embedding.refl.{u+1} _).sumMap f, ?_⟩, ?_⟩⟩ - · intros a b - match a, b with - | Sum.inl a, Sum.inl b => exact Sum.lex_inl_inl.trans Sum.lex_inl_inl.symm - | Sum.inl a, Sum.inr b => apply iff_of_true <;> apply Sum.Lex.sep - | Sum.inr a, Sum.inl b => apply iff_of_false <;> exact Sum.lex_inr_inl - | Sum.inr a, Sum.inr b => exact Sum.lex_inr_inr.trans <| fo.trans Sum.lex_inr_inr.symm - · intros a b H - match a, b, H with - | _, Sum.inl b, _ => exact ⟨Sum.inl b, rfl⟩ - | Sum.inl a, Sum.inr b, H => exact (Sum.lex_inr_inl H).elim - | Sum.inr a, Sum.inr b, H => - let ⟨w, h⟩ := fi _ _ (Sum.lex_inr_inr.1 H) - exact ⟨Sum.inr w, congr_arg Sum.inr h⟩ - --- Porting note: Rewritten proof of elim, previous version was difficult to debug -instance add_swap_covariantClass_le : - CovariantClass Ordinal.{u} Ordinal.{u} (swap (· + ·)) (· ≤ ·) where - elim := fun c a b h => by - revert h c - refine inductionOn a (fun α₁ r₁ _ ↦ ?_) - refine inductionOn b (fun α₂ r₂ _ ↦ ?_) - rintro c ⟨⟨⟨f, fo⟩, fi⟩⟩ - refine inductionOn c (fun β s _ ↦ ?_) - exact @RelEmbedding.ordinal_type_le _ _ (Sum.Lex r₁ s) (Sum.Lex r₂ s) _ _ - ⟨f.sumMap (Embedding.refl _), by - intro a b - constructor <;> intro H - · cases' a with a a <;> cases' b with b b <;> cases H <;> constructor <;> - [rwa [← fo]; assumption] - · cases H <;> constructor <;> [rwa [fo]; assumption]⟩ +instance instAddLeftMono : AddLeftMono Ordinal.{u} where + elim c a b := by + refine inductionOn₃ a b c fun α r _ β s _ γ t _ ⟨f⟩ ↦ + (RelEmbedding.ofMonotone (Sum.recOn · Sum.inl (Sum.inr ∘ f)) ?_).ordinal_type_le + simp [f.map_rel_iff] + +instance instAddRightMono : AddRightMono Ordinal.{u} where + elim c a b := by + refine inductionOn₃ a b c fun α r _ β s _ γ t _ ⟨f⟩ ↦ + (RelEmbedding.ofMonotone (Sum.recOn · (Sum.inl ∘ f) Sum.inr) ?_).ordinal_type_le + simp [f.map_rel_iff] theorem le_add_right (a b : Ordinal) : a ≤ a + b := by simpa only [add_zero] using add_le_add_left (Ordinal.zero_le b) a @@ -852,32 +823,12 @@ theorem sInf_empty : sInf (∅ : Set Ordinal) = 0 := /-! ### Successor order properties -/ -private theorem succ_le_iff' {a b : Ordinal} : a + 1 ≤ b ↔ a < b := - ⟨lt_of_lt_of_le - (inductionOn a fun α r _ => - ⟨⟨⟨⟨fun x => Sum.inl x, fun _ _ => Sum.inl.inj⟩, Sum.lex_inl_inl⟩, - Sum.inr PUnit.unit, fun b => - Sum.recOn b (fun x => ⟨fun _ => ⟨x, rfl⟩, fun _ => Sum.Lex.sep _ _⟩) fun x => - Sum.lex_inr_inr.trans ⟨False.elim, fun ⟨x, H⟩ => Sum.inl_ne_inr H⟩⟩⟩), - inductionOn a fun α r hr => - inductionOn b fun β s hs ⟨⟨f, t, hf⟩⟩ => by - haveI := hs - refine ⟨⟨RelEmbedding.ofMonotone (Sum.rec f fun _ => t) (fun a b ↦ ?_), fun a b ↦ ?_⟩⟩ - · rcases a with (a | _) <;> rcases b with (b | _) - · simpa only [Sum.lex_inl_inl] using f.map_rel_iff.2 - · intro - rw [hf] - exact ⟨_, rfl⟩ - · exact False.elim ∘ Sum.lex_inr_inl - · exact False.elim ∘ Sum.lex_inr_inr.1 - · rcases a with (a | _) - · intro h - have := @PrincipalSeg.mem_range_of_rel _ _ _ _ _ ⟨f, t, hf⟩ _ _ h - cases' this with w h - exact ⟨Sum.inl w, h⟩ - · intro h - cases' (hf b).1 h with w h - exact ⟨Sum.inl w, h⟩⟩ +private theorem succ_le_iff' {a b : Ordinal} : a + 1 ≤ b ↔ a < b := by + refine inductionOn₂ a b fun α r _ β s _ ↦ ⟨?_, ?_⟩ <;> rintro ⟨f⟩ + · refine ⟨((InitialSeg.leAdd _ _).trans f).toPrincipalSeg fun h ↦ ?_⟩ + simpa using h (f (Sum.inr PUnit.unit)) + · apply (RelEmbedding.ofMonotone (Sum.recOn · f fun _ ↦ f.top) ?_).ordinal_type_le + simpa [f.map_rel_iff] using f.lt_top instance noMaxOrder : NoMaxOrder Ordinal := ⟨fun _ => ⟨_, succ_le_iff'.1 le_rfl⟩⟩ @@ -987,12 +938,12 @@ theorem enum_zero_le {r : α → α → Prop} [IsWellOrder α r] (h0 : 0 < type apply Ordinal.zero_le theorem enum_zero_le' {o : Ordinal} (h0 : 0 < o) (a : o.toType) : - enum (α := o.toType) (· < ·) ⟨0, by rwa [type_lt]⟩ ≤ a := by + enum (α := o.toType) (· < ·) ⟨0, type_toType _ ▸ h0⟩ ≤ a := by rw [← not_lt] apply enum_zero_le theorem le_enum_succ {o : Ordinal} (a : (succ o).toType) : - a ≤ enum (α := (succ o).toType) (· < ·) ⟨o, (by rw [type_lt]; exact lt_succ o)⟩ := by + a ≤ enum (α := (succ o).toType) (· < ·) ⟨o, (type_toType _ ▸ lt_succ o)⟩ := by rw [← enum_typein (α := (succ o).toType) (· < ·) a, enum_le_enum', Subtype.mk_le_mk, ← lt_succ_iff] apply typein_lt_self @@ -1004,16 +955,11 @@ theorem enum_inj {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : {o // /-- The order isomorphism between ordinals less than `o` and `o.toType`. -/ @[simps! (config := .lemmasOnly)] noncomputable def enumIsoToType (o : Ordinal) : Set.Iio o ≃o o.toType where - toFun x := - enum (α := o.toType) (· < ·) ⟨x.1, by - rw [type_lt] - exact x.2⟩ + toFun x := enum (α := o.toType) (· < ·) ⟨x.1, type_toType _ ▸ x.2⟩ invFun x := ⟨typein (α := o.toType) (· < ·) x, typein_lt_self x⟩ - left_inv := fun ⟨o', h⟩ => Subtype.ext_val (typein_enum _ _) - right_inv h := enum_typein _ _ - map_rel_iff' := by - rintro ⟨a, _⟩ ⟨b, _⟩ - apply enum_le_enum' + left_inv := fun ⟨_, _⟩ => Subtype.ext_val (typein_enum _ _) + right_inv _ := enum_typein _ _ + map_rel_iff' := enum_le_enum' _ @[deprecated (since := "2024-08-26")] alias enumIsoOut := enumIsoToType @@ -1038,8 +984,8 @@ def toTypeOrderBotOfPos {o : Ordinal} (ho : 0 < o) : OrderBot o.toType where noncomputable alias outOrderBotOfPos := toTypeOrderBotOfPos theorem enum_zero_eq_bot {o : Ordinal} (ho : 0 < o) : - enum (α := o.toType) (· < ·) ⟨0, by rwa [type_lt]⟩ = - have H := toTypeOrderBotOfPos ho + enum (α := o.toType) (· < ·) ⟨0, by rwa [type_toType]⟩ = + have _ := toTypeOrderBotOfPos ho (⊥ : o.toType) := rfl @@ -1063,12 +1009,17 @@ theorem lift_univ : lift.{w} univ.{u, v} = univ.{u, max v w} := theorem univ_umax : univ.{u, max (u + 1) v} = univ.{u, v} := congr_fun lift_umax _ -/-- Principal segment version of the lift operation on ordinals, embedding `ordinal.{u}` in - `ordinal.{v}` as a principal segment when `u < v`. -/ -def liftPrincipalSeg : @PrincipalSeg Ordinal.{u} Ordinal.{max (u + 1) v} (· < ·) (· < ·) := - ⟨↑liftInitialSeg.{u, max (u + 1) v}, univ.{u, v}, by +/-- Principal segment version of the lift operation on ordinals, embedding `Ordinal.{u}` in +`Ordinal.{v}` as a principal segment when `u < v`. -/ +def liftPrincipalSeg : Ordinal.{u} inductionOn b ?_; intro β s _ rw [univ, ← lift_umax]; constructor <;> intro h + · cases' h with a e + rw [← e] + refine inductionOn a ?_ + intro α r _ + exact lift_type_lt.{u, u + 1, max (u + 1) v}.2 ⟨typein r⟩ · rw [← lift_id (type s)] at h ⊢ cases' lift_type_lt.{_,_,v}.1 h with f cases' f with f a hf @@ -1077,23 +1028,17 @@ def liftPrincipalSeg : @PrincipalSeg Ordinal.{u} Ordinal.{max (u + 1) v} (· < -- Porting note: apply inductionOn does not work, refine does refine inductionOn a ?_ intro α r _ hf - refine - lift_type_eq.{u, max (u + 1) v, max (u + 1) v}.2 - ⟨(RelIso.ofSurjective (RelEmbedding.ofMonotone ?_ ?_) ?_).symm⟩ - · exact fun b => enum r ⟨f b, (hf _).2 ⟨_, rfl⟩⟩ + refine lift_type_eq.{u, max (u + 1) v, max (u + 1) v}.2 + ⟨(RelIso.ofSurjective (RelEmbedding.ofMonotone ?_ ?_) ?_).symm⟩ + · exact fun b => enum r ⟨f b, (hf _).1 ⟨_, rfl⟩⟩ · refine fun a b h => (typein_lt_typein r).1 ?_ rw [typein_enum, typein_enum] exact f.map_rel_iff.2 h · intro a' - cases' (hf _).1 (typein_lt_type _ a') with b e + cases' (hf _).2 (typein_lt_type _ a') with b e exists b simp only [RelEmbedding.ofMonotone_coe] - simp [e] - · cases' h with a e - rw [← e] - refine inductionOn a ?_ - intro α r _ - exact lift_type_lt.{u, u + 1, max (u + 1) v}.2 ⟨typein.principalSeg r⟩⟩ + simp [e]⟩ @[deprecated liftPrincipalSeg (since := "2024-09-21")] alias lift.principalSeg := liftPrincipalSeg @@ -1137,7 +1082,7 @@ open Ordinal @[simp] theorem mk_toType (o : Ordinal) : #o.toType = o.card := - (Ordinal.card_type _).symm.trans <| by rw [Ordinal.type_lt] + (Ordinal.card_type _).symm.trans <| by rw [Ordinal.type_toType] @[deprecated mk_toType (since := "2024-08-26")] alias mk_ordinal_out := mk_toType @@ -1190,10 +1135,10 @@ theorem lt_ord {c o} : o < ord c ↔ o.card < c := @[simp] theorem card_ord (c) : (ord c).card = c := - Quotient.inductionOn c fun α => by - let ⟨r, _, e⟩ := ord_eq α - -- Porting note: cardinal.mk_def is now Cardinal.mk'_def, not sure why - simp only [mk'_def, e, card_type] + c.inductionOn fun α ↦ let ⟨r, _, e⟩ := ord_eq α; e ▸ card_type r + +theorem card_surjective : Function.Surjective card := + fun c ↦ ⟨_, card_ord c⟩ /-- Galois coinsertion between `Cardinal.ord` and `Ordinal.card`. -/ def gciOrdCard : GaloisCoinsertion ord card := @@ -1244,7 +1189,7 @@ theorem ord_nat (n : ℕ) : ord n = n := (by induction' n with n IH · apply Ordinal.zero_le - · exact succ_le_of_lt (IH.trans_lt <| ord_lt_ord.2 <| natCast_lt.2 (Nat.lt_succ_self n))) + · exact succ_le_of_lt (IH.trans_lt <| ord_lt_ord.2 <| Nat.cast_lt.2 (Nat.lt_succ_self n))) @[simp] theorem ord_one : ord 1 = 1 := by simpa using ord_nat 1 @@ -1254,10 +1199,18 @@ theorem ord_one : ord 1 = 1 := by simpa using ord_nat 1 theorem ord_ofNat (n : ℕ) [n.AtLeastTwo] : ord (no_index (OfNat.ofNat n)) = OfNat.ofNat n := ord_nat n +@[simp] +theorem ord_aleph0 : ord.{u} ℵ₀ = ω := + le_antisymm (ord_le.2 le_rfl) <| + le_of_forall_lt fun o h => by + rcases Ordinal.lt_lift_iff.1 h with ⟨o, h', rfl⟩ + rw [lt_ord, ← lift_card, lift_lt_aleph0, ← typein_enum (· < ·) h'] + exact lt_aleph0_iff_fintype.2 ⟨Set.fintypeLTNat _⟩ + @[simp] theorem lift_ord (c) : Ordinal.lift.{u,v} (ord c) = ord (lift.{u,v} c) := by refine le_antisymm (le_of_forall_lt fun a ha => ?_) ?_ - · rcases Ordinal.lt_lift_iff.1 ha with ⟨a, rfl, _⟩ + · rcases Ordinal.lt_lift_iff.1 ha with ⟨a, _, rfl⟩ rwa [lt_ord, ← lift_card, lift_lt, ← lt_ord, ← Ordinal.lift_lt] · rw [ord_le, ← lift_card, card_ord] @@ -1342,7 +1295,7 @@ theorem lift_lt_univ' (c : Cardinal) : lift.{max (u + 1) v, u} c < univ.{u, v} : @[simp] theorem ord_univ : ord univ.{u, v} = Ordinal.univ.{u, v} := by refine le_antisymm (ord_card_le _) <| le_of_forall_lt fun o h => lt_ord.2 ?_ - have := liftPrincipalSeg.{u, v}.down.1 (by simpa only [liftPrincipalSeg_coe] using h) + have := liftPrincipalSeg.mem_range_of_rel_top (by simpa only [liftPrincipalSeg_coe] using h) rcases this with ⟨o, h'⟩ rw [← h', liftPrincipalSeg_coe, ← lift_card] apply lift_lt_univ' @@ -1351,17 +1304,17 @@ theorem lt_univ {c} : c < univ.{u, u + 1} ↔ ∃ c', c = lift.{u + 1, u} c' := ⟨fun h => by have := ord_lt_ord.2 h rw [ord_univ] at this - cases' liftPrincipalSeg.{u, u + 1}.down.1 (by simpa only [liftPrincipalSeg_top] ) with o e + cases' liftPrincipalSeg.mem_range_of_rel_top (by simpa only [liftPrincipalSeg_top]) with o e have := card_ord c rw [← e, liftPrincipalSeg_coe, ← lift_card] at this - exact ⟨_, this.symm⟩, fun ⟨c', e⟩ => e.symm ▸ lift_lt_univ _⟩ + exact ⟨_, this.symm⟩, fun ⟨_, e⟩ => e.symm ▸ lift_lt_univ _⟩ theorem lt_univ' {c} : c < univ.{u, v} ↔ ∃ c', c = lift.{max (u + 1) v, u} c' := ⟨fun h => by - let ⟨a, e, h'⟩ := lt_lift_iff.1 h + let ⟨a, h', e⟩ := lt_lift_iff.1 h rw [← univ_id] at h' rcases lt_univ.{u}.1 h' with ⟨c', rfl⟩ - exact ⟨c', by simp only [e.symm, lift_lift]⟩, fun ⟨c', e⟩ => e.symm ▸ lift_lt_univ' _⟩ + exact ⟨c', by simp only [e.symm, lift_lift]⟩, fun ⟨_, e⟩ => e.symm ▸ lift_lt_univ' _⟩ theorem small_iff_lift_mk_lt_univ {α : Type u} : Small.{v} α ↔ Cardinal.lift.{v+1,_} #α < univ.{v, max u (v + 1)} := by @@ -1449,6 +1402,16 @@ theorem card_eq_zero {o} : card o = 0 ↔ o = 0 := by theorem card_eq_one {o} : card o = 1 ↔ o = 1 := by simpa using card_eq_nat (n := 1) +theorem mem_range_lift_of_card_le {a : Cardinal.{u}} {b : Ordinal.{max u v}} + (h : card b ≤ Cardinal.lift.{v, u} a) : b ∈ Set.range lift.{v, u} := by + rw [card_le_iff, ← lift_succ, ← lift_ord] at h + exact mem_range_lift_of_le h.le + +@[deprecated mem_range_lift_of_card_le (since := "2024-10-07")] +theorem lift_down' {a : Cardinal.{u}} {b : Ordinal.{max u v}} + (h : card.{max u v} b ≤ Cardinal.lift.{v, u} a) : ∃ a', lift.{v, u} a' = b := + mem_range_lift_of_card_le h + -- See note [no_index around OfNat.ofNat] @[simp] theorem card_eq_ofNat {o} {n : ℕ} [n.AtLeastTwo] : diff --git a/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean b/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean index 1013da5c56c46..563ef369b373b 100644 --- a/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean +++ b/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean @@ -139,6 +139,6 @@ theorem CNF_sorted (b o : Ordinal) : ((CNF b o).map Prod.fst).Sorted (· > ·) : refine ⟨fun a H ↦ ?_, IH⟩ rw [mem_map] at H rcases H with ⟨⟨a, a'⟩, H, rfl⟩ - exact (CNF_fst_le_log H).trans_lt (log_mod_opow_log_lt_log_self hb ho hbo) + exact (CNF_fst_le_log H).trans_lt (log_mod_opow_log_lt_log_self hb hbo) end Ordinal diff --git a/Mathlib/SetTheory/Ordinal/Enum.lean b/Mathlib/SetTheory/Ordinal/Enum.lean new file mode 100644 index 0000000000000..4e5d4d38a7cf6 --- /dev/null +++ b/Mathlib/SetTheory/Ordinal/Enum.lean @@ -0,0 +1,145 @@ +/- +Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Violeta Hernández Palacios +-/ +import Mathlib.SetTheory.Ordinal.Arithmetic + +/-! +# Enumerating sets of ordinals by ordinals + +The ordinals have the peculiar property that every subset bounded above is a small type, while +themselves not being small. As a consequence of this, every unbounded subset of `Ordinal` is order +isomorphic to `Ordinal`. + +We define this correspondence as `enumOrd`, and use it to then define an order isomorphism +`enumOrdOrderIso`. + +This can be thought of as an ordinal analog of `Nat.nth`. +-/ + +universe u + +open Order Set + +namespace Ordinal + +variable {o a b : Ordinal.{u}} + +/-- Enumerator function for an unbounded set of ordinals. -/ +noncomputable def enumOrd (s : Set Ordinal.{u}) (o : Ordinal.{u}) : Ordinal.{u} := + sInf (s ∩ { b | ∀ c, c < o → enumOrd s c < b }) +termination_by o + +variable {s : Set Ordinal.{u}} + +@[deprecated (since := "2024-09-20")] +theorem enumOrd_def (o : Ordinal.{u}) : + enumOrd s o = sInf (s ∩ { b | ∀ c, c < o → enumOrd s c < b }) := by + rw [enumOrd] + +theorem enumOrd_le_of_forall_lt (ha : a ∈ s) (H : ∀ b < o, enumOrd s b < a) : enumOrd s o ≤ a := by + rw [enumOrd] + exact csInf_le' ⟨ha, H⟩ + +/-- The set in the definition of `enumOrd` is nonempty. -/ +private theorem enumOrd_nonempty (hs : ¬ BddAbove s) (o : Ordinal) : + (s ∩ { b | ∀ c, c < o → enumOrd s c < b }).Nonempty := by + rw [not_bddAbove_iff] at hs + obtain ⟨a, ha⟩ := bddAbove_of_small (enumOrd s '' Iio o) + obtain ⟨b, hb, hba⟩ := hs a + exact ⟨b, hb, fun c hc ↦ (ha (mem_image_of_mem _ hc)).trans_lt hba⟩ + +private theorem enumOrd_mem_aux (hs : ¬ BddAbove s) (o : Ordinal) : + enumOrd s o ∈ s ∩ { b | ∀ c, c < o → enumOrd s c < b } := by + rw [enumOrd] + exact csInf_mem (enumOrd_nonempty hs o) + +theorem enumOrd_mem (hs : ¬ BddAbove s) (o : Ordinal) : enumOrd s o ∈ s := + (enumOrd_mem_aux hs o).1 + +theorem enumOrd_strictMono (hs : ¬ BddAbove s) : StrictMono (enumOrd s) := + fun a b ↦ (enumOrd_mem_aux hs b).2 a + +theorem enumOrd_injective (hs : ¬ BddAbove s) : Function.Injective (enumOrd s) := + (enumOrd_strictMono hs).injective + +theorem enumOrd_inj (hs : ¬ BddAbove s) {a b : Ordinal} : enumOrd s a = enumOrd s b ↔ a = b := + (enumOrd_injective hs).eq_iff + +theorem enumOrd_le_enumOrd (hs : ¬ BddAbove s) {a b : Ordinal} : + enumOrd s a ≤ enumOrd s b ↔ a ≤ b := + (enumOrd_strictMono hs).le_iff_le + +theorem enumOrd_lt_enumOrd (hs : ¬ BddAbove s) {a b : Ordinal} : + enumOrd s a < enumOrd s b ↔ a < b := + (enumOrd_strictMono hs).lt_iff_lt + +theorem id_le_enumOrd (hs : ¬ BddAbove s) : id ≤ enumOrd s := + (enumOrd_strictMono hs).id_le + +theorem le_enumOrd_self (hs : ¬ BddAbove s) {a} : a ≤ enumOrd s a := + (enumOrd_strictMono hs).le_apply + +theorem enumOrd_succ_le (hs : ¬ BddAbove s) (ha : a ∈ s) (hb : enumOrd s b < a) : + enumOrd s (succ b) ≤ a := by + apply enumOrd_le_of_forall_lt ha + intro c hc + rw [lt_succ_iff] at hc + exact ((enumOrd_strictMono hs).monotone hc).trans_lt hb + +theorem range_enumOrd (hs : ¬ BddAbove s) : range (enumOrd s) = s := by + ext a + let t := { b | a ≤ enumOrd s b } + constructor + · rintro ⟨b, rfl⟩ + exact enumOrd_mem hs b + · intro ha + refine ⟨sInf t, (enumOrd_le_of_forall_lt ha ?_).antisymm ?_⟩ + · intro b hb + by_contra! hb' + exact hb.not_le (csInf_le' hb') + · exact csInf_mem (s := t) ⟨a, (enumOrd_strictMono hs).id_le a⟩ + +theorem enumOrd_surjective (hs : ¬ BddAbove s) {b : Ordinal} (hb : b ∈ s) : + ∃ a, enumOrd s a = b := by + rwa [← range_enumOrd hs] at hb + +theorem enumOrd_le_of_subset {t : Set Ordinal} (hs : ¬ BddAbove s) (hst : s ⊆ t) : + enumOrd t ≤ enumOrd s := by + intro a + rw [enumOrd, enumOrd] + apply csInf_le_csInf' (enumOrd_nonempty hs a) (inter_subset_inter hst _) + intro b hb c hc + exact (enumOrd_le_of_subset hs hst c).trans_lt <| hb c hc +termination_by a => a + +/-- A characterization of `enumOrd`: it is the unique strict monotonic function with range `s`. -/ +theorem eq_enumOrd (f : Ordinal → Ordinal) (hs : ¬ BddAbove s) : + enumOrd s = f ↔ StrictMono f ∧ range f = s := by + constructor + · rintro rfl + exact ⟨enumOrd_strictMono hs, range_enumOrd hs⟩ + · rintro ⟨h₁, h₂⟩ + rwa [← (enumOrd_strictMono hs).range_inj h₁, range_enumOrd hs, eq_comm] + +theorem enumOrd_range {f : Ordinal → Ordinal} (hf : StrictMono f) : enumOrd (range f) = f := + (eq_enumOrd _ hf.not_bddAbove_range_of_wellFoundedLT).2 ⟨hf, rfl⟩ + +@[simp] +theorem enumOrd_univ : enumOrd Set.univ = id := by + rw [← range_id] + exact enumOrd_range strictMono_id + +@[simp] +theorem enumOrd_zero : enumOrd s 0 = sInf s := by + rw [enumOrd] + simp [Ordinal.not_lt_zero] + +/-- An order isomorphism between an unbounded set of ordinals and the ordinals. -/ +noncomputable def enumOrdOrderIso (s : Set Ordinal) (hs : ¬ BddAbove s) : Ordinal ≃o s := + StrictMono.orderIsoOfSurjective (fun o => ⟨_, enumOrd_mem hs o⟩) (enumOrd_strictMono hs) fun s => + let ⟨a, ha⟩ := enumOrd_surjective hs s.prop + ⟨a, Subtype.eq ha⟩ + +end Ordinal diff --git a/Mathlib/SetTheory/Ordinal/Exponential.lean b/Mathlib/SetTheory/Ordinal/Exponential.lean index ca373660f3136..57fe4e7e7b0e4 100644 --- a/Mathlib/SetTheory/Ordinal/Exponential.lean +++ b/Mathlib/SetTheory/Ordinal/Exponential.lean @@ -100,29 +100,38 @@ theorem opow_natCast (a : Ordinal) (n : ℕ) : a ^ (n : Ordinal) = a ^ n := by | zero => rw [Nat.cast_zero, opow_zero, pow_zero] | succ n IH => rw [Nat.cast_succ, add_one_eq_succ, opow_succ, pow_succ, IH] -theorem opow_isNormal {a : Ordinal} (h : 1 < a) : IsNormal (a ^ ·) := +theorem isNormal_opow {a : Ordinal} (h : 1 < a) : IsNormal (a ^ ·) := have a0 : 0 < a := zero_lt_one.trans h ⟨fun b => by simpa only [mul_one, opow_succ] using (mul_lt_mul_iff_left (opow_pos b a0)).2 h, - fun b l c => opow_le_of_limit (ne_of_gt a0) l⟩ + fun _ l _ => opow_le_of_limit (ne_of_gt a0) l⟩ + +@[deprecated isNormal_opow (since := "2024-10-11")] +alias opow_isNormal := isNormal_opow theorem opow_lt_opow_iff_right {a b c : Ordinal} (a1 : 1 < a) : a ^ b < a ^ c ↔ b < c := - (opow_isNormal a1).lt_iff + (isNormal_opow a1).lt_iff theorem opow_le_opow_iff_right {a b c : Ordinal} (a1 : 1 < a) : a ^ b ≤ a ^ c ↔ b ≤ c := - (opow_isNormal a1).le_iff + (isNormal_opow a1).le_iff theorem opow_right_inj {a b c : Ordinal} (a1 : 1 < a) : a ^ b = a ^ c ↔ b = c := - (opow_isNormal a1).inj + (isNormal_opow a1).inj + +theorem isLimit_opow {a b : Ordinal} (a1 : 1 < a) : IsLimit b → IsLimit (a ^ b) := + (isNormal_opow a1).isLimit -theorem opow_isLimit {a b : Ordinal} (a1 : 1 < a) : IsLimit b → IsLimit (a ^ b) := - (opow_isNormal a1).isLimit +@[deprecated isLimit_opow (since := "2024-10-11")] +alias opow_isLimit := isLimit_opow -theorem opow_isLimit_left {a b : Ordinal} (l : IsLimit a) (hb : b ≠ 0) : IsLimit (a ^ b) := by +theorem isLimit_opow_left {a b : Ordinal} (l : IsLimit a) (hb : b ≠ 0) : IsLimit (a ^ b) := by rcases zero_or_succ_or_limit b with (e | ⟨b, rfl⟩ | l') · exact absurd e hb · rw [opow_succ] - exact mul_isLimit (opow_pos _ l.pos) l - · exact opow_isLimit l.one_lt l' + exact isLimit_mul (opow_pos _ l.pos) l + · exact isLimit_opow l.one_lt l' + +@[deprecated isLimit_opow_left (since := "2024-10-11")] +alias opow_isLimit_left := isLimit_opow_left theorem opow_le_opow_right {a b c : Ordinal} (h₁ : 0 < a) (h₂ : b ≤ c) : a ^ b ≤ a ^ c := by rcases lt_or_eq_of_le (one_le_iff_pos.2 h₁) with h₁ | h₁ @@ -148,6 +157,9 @@ theorem opow_le_opow_left {a b : Ordinal} (c : Ordinal) (ab : a ≤ b) : a ^ c (opow_le_of_limit a0 l).2 fun b' h => (IH _ h).trans (opow_le_opow_right ((Ordinal.pos_iff_ne_zero.2 a0).trans_le ab) h.le) +theorem opow_le_opow {a b c d : Ordinal} (hac : a ≤ c) (hbd : b ≤ d) (hc : 0 < c) : a ^ b ≤ c ^ d := + (opow_le_opow_left b hac).trans (opow_le_opow_right hc hbd) + theorem left_le_opow (a : Ordinal) {b : Ordinal} (b1 : 0 < b) : a ≤ a ^ b := by nth_rw 1 [← opow_one a] cases' le_or_gt a 1 with a1 a1 @@ -158,8 +170,12 @@ theorem left_le_opow (a : Ordinal) {b : Ordinal} (b1 : 0 < b) : a ≤ a ^ b := b rw [a1, one_opow, one_opow] rwa [opow_le_opow_iff_right a1, one_le_iff_pos] +theorem left_lt_opow {a b : Ordinal} (ha : 1 < a) (hb : 1 < b) : a < a ^ b := by + conv_lhs => rw [← opow_one a] + rwa [opow_lt_opow_iff_right ha] + theorem right_le_opow {a : Ordinal} (b : Ordinal) (a1 : 1 < a) : b ≤ a ^ b := - (opow_isNormal a1).id_le _ + (isNormal_opow a1).le_apply theorem opow_lt_opow_left_of_succ {a b c : Ordinal} (ab : a < b) : a ^ succ c < b ^ succ c := by rw [opow_succ, opow_succ] @@ -182,12 +198,12 @@ theorem opow_add (a b c : Ordinal) : a ^ (b + c) = a ^ b * a ^ c := by | H₃ c l IH => refine eq_of_forall_ge_iff fun d => - (((opow_isNormal a1).trans (add_isNormal b)).limit_le l).trans ?_ + (((isNormal_opow a1).trans (isNormal_add_right b)).limit_le l).trans ?_ dsimp only [Function.comp_def] simp (config := { contextual := true }) only [IH] exact - (((mul_isNormal <| opow_pos b (Ordinal.pos_iff_ne_zero.2 a0)).trans - (opow_isNormal a1)).limit_le + (((isNormal_mul_right <| opow_pos b (Ordinal.pos_iff_ne_zero.2 a0)).trans + (isNormal_opow a1)).limit_le l).symm theorem opow_one_add (a b : Ordinal) : a ^ (1 + b) = a * a ^ b := by rw [opow_add, opow_one] @@ -219,48 +235,63 @@ theorem opow_mul (a b c : Ordinal) : a ^ (b * c) = (a ^ b) ^ c := by | H₃ c l IH => refine eq_of_forall_ge_iff fun d => - (((opow_isNormal a1).trans (mul_isNormal (Ordinal.pos_iff_ne_zero.2 b0))).limit_le + (((isNormal_opow a1).trans (isNormal_mul_right (Ordinal.pos_iff_ne_zero.2 b0))).limit_le l).trans ?_ dsimp only [Function.comp_def] simp (config := { contextual := true }) only [IH] exact (opow_le_of_limit (opow_ne_zero _ a0) l).symm +theorem opow_mul_add_pos {b v : Ordinal} (hb : b ≠ 0) (u : Ordinal) (hv : v ≠ 0) (w : Ordinal) : + 0 < b ^ u * v + w := + (opow_pos u <| Ordinal.pos_iff_ne_zero.2 hb).trans_le <| + (le_mul_left _ <| Ordinal.pos_iff_ne_zero.2 hv).trans <| le_add_right _ _ + +theorem opow_mul_add_lt_opow_mul_succ {b u w : Ordinal} (v : Ordinal) (hw : w < b ^ u) : + b ^ u * v + w < b ^ u * succ v := by + rwa [mul_succ, add_lt_add_iff_left] + +theorem opow_mul_add_lt_opow_succ {b u v w : Ordinal} (hvb : v < b) (hw : w < b ^ u) : + b ^ u * v + w < b ^ succ u := by + convert (opow_mul_add_lt_opow_mul_succ v hw).trans_le + (mul_le_mul_left' (succ_le_of_lt hvb) _) using 1 + exact opow_succ b u + /-! ### Ordinal logarithm -/ /-- The ordinal logarithm is the solution `u` to the equation `x = b ^ u * v + w` where `v < b` and - `w < b ^ u`. -/ +`w < b ^ u`. -/ @[pp_nodot] def log (b : Ordinal) (x : Ordinal) : Ordinal := - if _h : 1 < b then pred (sInf { o | x < b ^ o }) else 0 + if 1 < b then pred (sInf { o | x < b ^ o }) else 0 /-- The set in the definition of `log` is nonempty. -/ -theorem log_nonempty {b x : Ordinal} (h : 1 < b) : { o : Ordinal | x < b ^ o }.Nonempty := +private theorem log_nonempty {b x : Ordinal} (h : 1 < b) : { o : Ordinal | x < b ^ o }.Nonempty := ⟨_, succ_le_iff.1 (right_le_opow _ h)⟩ -theorem log_def {b : Ordinal} (h : 1 < b) (x : Ordinal) : - log b x = pred (sInf { o | x < b ^ o }) := by simp only [log, dif_pos h] +theorem log_def {b : Ordinal} (h : 1 < b) (x : Ordinal) : log b x = pred (sInf { o | x < b ^ o }) := + if_pos h -theorem log_of_not_one_lt_left {b : Ordinal} (h : ¬1 < b) (x : Ordinal) : log b x = 0 := by - simp only [log, dif_neg h] +theorem log_of_left_le_one {b : Ordinal} (h : b ≤ 1) (x : Ordinal) : log b x = 0 := + if_neg h.not_lt -theorem log_of_left_le_one {b : Ordinal} (h : b ≤ 1) : ∀ x, log b x = 0 := - log_of_not_one_lt_left h.not_lt +@[deprecated log_of_left_le_one (since := "2024-10-10")] +theorem log_of_not_one_lt_left {b : Ordinal} (h : ¬1 < b) (x : Ordinal) : log b x = 0 := by + simp only [log, if_neg h] @[simp] theorem log_zero_left : ∀ b, log 0 b = 0 := log_of_left_le_one zero_le_one @[simp] -theorem log_zero_right (b : Ordinal) : log b 0 = 0 := - if b1 : 1 < b then by - rw [log_def b1, ← Ordinal.le_zero, pred_le] +theorem log_zero_right (b : Ordinal) : log b 0 = 0 := by + obtain hb | hb := lt_or_le 1 b + · rw [log_def hb, ← Ordinal.le_zero, pred_le, succ_zero] apply csInf_le' - dsimp - rw [succ_zero, opow_one] - exact zero_lt_one.trans b1 - else by simp only [log_of_not_one_lt_left b1] + rw [mem_setOf, opow_one] + exact bot_lt_of_lt hb + · rw [log_of_left_le_one hb] @[simp] theorem log_one_left : ∀ b, log 1 b = 0 := @@ -269,7 +300,7 @@ theorem log_one_left : ∀ b, log 1 b = 0 := theorem succ_log_def {b x : Ordinal} (hb : 1 < b) (hx : x ≠ 0) : succ (log b x) = sInf { o : Ordinal | x < b ^ o } := by let t := sInf { o : Ordinal | x < b ^ o } - have : x < (b^t) := csInf_mem (log_nonempty hb) + have : x < b ^ t := csInf_mem (log_nonempty hb) rcases zero_or_succ_or_limit t with (h | h | h) · refine ((one_le_iff_ne_zero.2 hx).not_lt ?_).elim simpa only [h, opow_zero] using this @@ -368,69 +399,75 @@ theorem log_eq_zero {b o : Ordinal} (hbo : o < b) : log b o = 0 := by · rwa [← Ordinal.le_zero, ← lt_succ_iff, succ_zero, ← lt_opow_iff_log_lt hb ho, opow_one] @[mono] -theorem log_mono_right (b : Ordinal) {x y : Ordinal} (xy : x ≤ y) : log b x ≤ log b y := - if hx : x = 0 then by simp only [hx, log_zero_right, Ordinal.zero_le] - else - if hb : 1 < b then - (opow_le_iff_le_log hb (lt_of_lt_of_le (Ordinal.pos_iff_ne_zero.2 hx) xy).ne').1 <| +theorem log_mono_right (b : Ordinal) {x y : Ordinal} (xy : x ≤ y) : log b x ≤ log b y := by + obtain rfl | hx := eq_or_ne x 0 + · simp_rw [log_zero_right, Ordinal.zero_le] + · obtain hb | hb := lt_or_le 1 b + · exact (opow_le_iff_le_log hb (hx.bot_lt.trans_le xy).ne').1 <| (opow_log_le_self _ hx).trans xy - else by simp only [log_of_not_one_lt_left hb, Ordinal.zero_le] + · rw [log_of_left_le_one hb, log_of_left_le_one hb] -theorem log_le_self (b x : Ordinal) : log b x ≤ x := - if hx : x = 0 then by simp only [hx, log_zero_right, Ordinal.zero_le] - else - if hb : 1 < b then (right_le_opow _ hb).trans (opow_log_le_self b hx) - else by simp only [log_of_not_one_lt_left hb, Ordinal.zero_le] +theorem log_le_self (b x : Ordinal) : log b x ≤ x := by + obtain rfl | hx := eq_or_ne x 0 + · rw [log_zero_right] + · obtain hb | hb := lt_or_le 1 b + · exact (right_le_opow _ hb).trans (opow_log_le_self b hx) + · simp_rw [log_of_left_le_one hb, Ordinal.zero_le] @[simp] -theorem log_one_right (b : Ordinal) : log b 1 = 0 := - if hb : 1 < b then log_eq_zero hb else log_of_not_one_lt_left hb 1 +theorem log_one_right (b : Ordinal) : log b 1 = 0 := by + obtain hb | hb := lt_or_le 1 b + · exact log_eq_zero hb + · exact log_of_left_le_one hb 1 theorem mod_opow_log_lt_self (b : Ordinal) {o : Ordinal} (ho : o ≠ 0) : o % (b ^ log b o) < o := by rcases eq_or_ne b 0 with (rfl | hb) · simpa using Ordinal.pos_iff_ne_zero.2 ho · exact (mod_lt _ <| opow_ne_zero _ hb).trans_le (opow_log_le_self _ ho) -theorem log_mod_opow_log_lt_log_self {b o : Ordinal} (hb : 1 < b) (ho : o ≠ 0) (hbo : b ≤ o) : +theorem log_mod_opow_log_lt_log_self {b o : Ordinal} (hb : 1 < b) (hbo : b ≤ o) : log b (o % (b ^ log b o)) < log b o := by rcases eq_or_ne (o % (b ^ log b o)) 0 with h | h · rw [h, log_zero_right] - apply log_pos hb ho hbo + exact log_pos hb (one_le_iff_ne_zero.1 (hb.le.trans hbo)) hbo · rw [← succ_le_iff, succ_log_def hb h] apply csInf_le' apply mod_lt rw [← Ordinal.pos_iff_ne_zero] exact opow_pos _ (zero_lt_one.trans hb) -theorem opow_mul_add_pos {b v : Ordinal} (hb : b ≠ 0) (u : Ordinal) (hv : v ≠ 0) (w : Ordinal) : - 0 < b ^ u * v + w := - (opow_pos u <| Ordinal.pos_iff_ne_zero.2 hb).trans_le <| - (le_mul_left _ <| Ordinal.pos_iff_ne_zero.2 hv).trans <| le_add_right _ _ - -theorem opow_mul_add_lt_opow_mul_succ {b u w : Ordinal} (v : Ordinal) (hw : w < b ^ u) : - b ^ u * v + w < b ^ u * succ v := by rwa [mul_succ, add_lt_add_iff_left] - -theorem opow_mul_add_lt_opow_succ {b u v w : Ordinal} (hvb : v < b) (hw : w < b ^ u) : - b ^ u * v + w < b ^ succ u := by - convert (opow_mul_add_lt_opow_mul_succ v hw).trans_le (mul_le_mul_left' (succ_le_of_lt hvb) _) - using 1 - exact opow_succ b u - -theorem log_opow_mul_add {b u v w : Ordinal} (hb : 1 < b) (hv : v ≠ 0) (hvb : v < b) - (hw : w < b ^ u) : log b (b ^ u * v + w) = u := by - have hne' := (opow_mul_add_pos (zero_lt_one.trans hb).ne' u hv w).ne' - by_contra! hne - cases' lt_or_gt_of_ne hne with h h - · rw [← lt_opow_iff_log_lt hb hne'] at h - exact h.not_le ((le_mul_left _ (Ordinal.pos_iff_ne_zero.2 hv)).trans (le_add_right _ _)) - · conv at h => change u < log b (b ^ u * v + w) - rw [← succ_le_iff, ← opow_le_iff_le_log hb hne'] at h - exact (not_lt_of_le h) (opow_mul_add_lt_opow_succ hvb hw) +theorem log_eq_iff {b x : Ordinal} (hb : 1 < b) (hx : x ≠ 0) (y : Ordinal) : + log b x = y ↔ b ^ y ≤ x ∧ x < b ^ succ y := by + constructor + · rintro rfl + use opow_log_le_self b hx, lt_opow_succ_log_self hb x + · rintro ⟨hx₁, hx₂⟩ + apply le_antisymm + · rwa [← lt_succ_iff, ← lt_opow_iff_log_lt hb hx] + · rwa [← opow_le_iff_le_log hb hx] + +theorem log_opow_mul_add {b u v w : Ordinal} (hb : 1 < b) (hv : v ≠ 0) (hw : w < b ^ u) : + log b (b ^ u * v + w) = u + log b v := by + rw [log_eq_iff hb] + · constructor + · rw [opow_add] + exact (mul_le_mul_left' (opow_log_le_self b hv) _).trans (le_add_right _ w) + · apply (add_lt_add_left hw _).trans_le + rw [← mul_succ, ← add_succ, opow_add] + apply mul_le_mul_left' + rw [succ_le_iff] + exact lt_opow_succ_log_self hb _ + · exact fun h ↦ mul_ne_zero (opow_ne_zero u (bot_lt_of_lt hb).ne') hv <| + left_eq_zero_of_add_eq_zero h + +theorem log_opow_mul {b v : Ordinal} (hb : 1 < b) (u : Ordinal) (hv : v ≠ 0) : + log b (b ^ u * v) = u + log b v := by + simpa using log_opow_mul_add hb hv (opow_pos u (bot_lt_of_lt hb)) theorem log_opow {b : Ordinal} (hb : 1 < b) (x : Ordinal) : log b (b ^ x) = x := by - convert log_opow_mul_add hb zero_ne_one.symm hb (opow_pos x (zero_lt_one.trans hb)) - using 1 - rw [add_zero, mul_one] + convert log_opow_mul hb x zero_ne_one.symm using 1 + · rw [mul_one] + · rw [log_one_right, add_zero] theorem div_opow_log_pos (b : Ordinal) {o : Ordinal} (ho : o ≠ 0) : 0 < o / (b ^ log b o) := by rcases eq_zero_or_pos b with (rfl | hb) @@ -444,11 +481,30 @@ theorem div_opow_log_lt {b : Ordinal} (o : Ordinal) (hb : 1 < b) : o / (b ^ log theorem add_log_le_log_mul {x y : Ordinal} (b : Ordinal) (hx : x ≠ 0) (hy : y ≠ 0) : log b x + log b y ≤ log b (x * y) := by - by_cases hb : 1 < b + obtain hb | hb := lt_or_le 1 b · rw [← opow_le_iff_le_log hb (mul_ne_zero hx hy), opow_add] exact mul_le_mul' (opow_log_le_self b hx) (opow_log_le_self b hy) - -- Porting note: `le_refl` is required. - simp only [log_of_not_one_lt_left hb, zero_add, le_refl] + · simpa only [log_of_left_le_one hb, zero_add] using le_rfl + +theorem omega0_opow_mul_nat_lt {a b : Ordinal} (h : a < b) (n : ℕ) : ω ^ a * n < ω ^ b := by + apply lt_of_lt_of_le _ (opow_le_opow_right omega0_pos (succ_le_of_lt h)) + rw [opow_succ] + exact mul_lt_mul_of_pos_left (nat_lt_omega0 n) (opow_pos a omega0_pos) + +theorem lt_omega0_opow {a b : Ordinal} (hb : b ≠ 0) : + a < ω ^ b ↔ ∃ c < b, ∃ n : ℕ, a < ω ^ c * n := by + refine ⟨fun ha ↦ ⟨_, lt_log_of_lt_opow hb ha, ?_⟩, + fun ⟨c, hc, n, hn⟩ ↦ hn.trans (omega0_opow_mul_nat_lt hc n)⟩ + obtain ⟨n, hn⟩ := lt_omega0.1 (div_opow_log_lt a one_lt_omega0) + use n.succ + rw [natCast_succ, ← hn] + exact lt_mul_succ_div a (opow_ne_zero _ omega0_ne_zero) + +theorem lt_omega0_opow_succ {a b : Ordinal} : a < ω ^ succ b ↔ ∃ n : ℕ, a < ω ^ b * n := by + refine ⟨fun ha ↦ ?_, fun ⟨n, hn⟩ ↦ hn.trans (omega0_opow_mul_nat_lt (lt_succ b) n)⟩ + obtain ⟨c, hc, n, hn⟩ := (lt_omega0_opow (succ_ne_zero b)).1 ha + refine ⟨n, hn.trans_le (mul_le_mul_right' ?_ _)⟩ + rwa [opow_le_opow_iff_right one_lt_omega0, ← lt_succ_iff] /-! ### Interaction with `Nat.cast` -/ @@ -461,18 +517,17 @@ theorem natCast_opow (m : ℕ) : ∀ n : ℕ, ↑(m ^ n : ℕ) = (m : Ordinal) ^ theorem iSup_pow {o : Ordinal} (ho : 0 < o) : ⨆ n : ℕ, o ^ n = o ^ ω := by simp_rw [← opow_natCast] rcases (one_le_iff_pos.2 ho).lt_or_eq with ho₁ | rfl - · exact (opow_isNormal ho₁).apply_omega0 + · exact (isNormal_opow ho₁).apply_omega0 · rw [one_opow] refine le_antisymm (Ordinal.iSup_le fun n => by rw [one_opow]) ?_ - convert Ordinal.le_iSup _ 0 - rw [Nat.cast_zero, opow_zero] + exact_mod_cast Ordinal.le_iSup _ 0 set_option linter.deprecated false in @[deprecated iSup_pow (since := "2024-08-27")] theorem sup_opow_nat {o : Ordinal} (ho : 0 < o) : (sup fun n : ℕ => o ^ n) = o ^ ω := by simp_rw [← opow_natCast] rcases (one_le_iff_pos.2 ho).lt_or_eq with ho₁ | rfl - · exact (opow_isNormal ho₁).apply_omega0 + · exact (isNormal_opow ho₁).apply_omega0 · rw [one_opow] refine le_antisymm (sup_le fun n => by rw [one_opow]) ?_ convert le_sup (fun n : ℕ => 1 ^ (n : Ordinal)) 0 diff --git a/Mathlib/SetTheory/Ordinal/FixedPoint.lean b/Mathlib/SetTheory/Ordinal/FixedPoint.lean index 4fe7f81c09218..d9f8f5bb5f7f8 100644 --- a/Mathlib/SetTheory/Ordinal/FixedPoint.lean +++ b/Mathlib/SetTheory/Ordinal/FixedPoint.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Violeta Hernández Palacios, Mario Carneiro. All rights reser Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios, Mario Carneiro -/ -import Mathlib.SetTheory.Ordinal.Arithmetic +import Mathlib.SetTheory.Ordinal.Enum import Mathlib.SetTheory.Ordinal.Exponential /-! @@ -60,7 +60,7 @@ theorem foldr_le_nfpFamily (f : ι → Ordinal → Ordinal) Ordinal.le_iSup _ _ theorem le_nfpFamily (f : ι → Ordinal → Ordinal) (a) : a ≤ nfpFamily f a := - Ordinal.le_iSup _ [] + Ordinal.le_iSup (fun _ ↦ List.foldr _ a _) [] theorem lt_nfpFamily {a b} : a < nfpFamily.{u, v} f b ↔ ∃ l, a < List.foldr f b l := Ordinal.lt_iSup @@ -129,6 +129,14 @@ theorem nfpFamily_eq_self {f : ι → Ordinal → Ordinal} {a} (h : ∀ i, f i a -- Todo: This is actually a special case of the fact the intersection of club sets is a club set. /-- A generalization of the fixed point lemma for normal functions: any family of normal functions has an unbounded set of common fixed points. -/ +theorem not_bddAbove_fp_family (H : ∀ i, IsNormal (f i)) : + ¬ BddAbove (⋂ i, Function.fixedPoints (f i)) := by + rw [not_bddAbove_iff] + refine fun a ↦ ⟨nfpFamily f (succ a), ?_, (lt_succ a).trans_le (le_nfpFamily f _)⟩ + rintro _ ⟨i, rfl⟩ + exact nfpFamily_fp (H i) _ + +@[deprecated not_bddAbove_fp_family (since := "2024-09-20")] theorem fp_family_unbounded (H : ∀ i, IsNormal (f i)) : (⋂ i, Function.fixedPoints (f i)).Unbounded (· < ·) := fun a => ⟨nfpFamily.{u, v} f a, fun s ⟨i, hi⟩ => by @@ -157,10 +165,13 @@ theorem derivFamily_limit (f : ι → Ordinal → Ordinal) {o} : IsLimit o → derivFamily.{u, v} f o = bsup.{max u v, u} o fun a _ => derivFamily.{u, v} f a := limitRecOn_limit _ _ _ _ -theorem derivFamily_isNormal (f : ι → Ordinal → Ordinal) : IsNormal (derivFamily f) := +theorem isNormal_derivFamily (f : ι → Ordinal → Ordinal) : IsNormal (derivFamily f) := ⟨fun o => by rw [derivFamily_succ, ← succ_le_iff]; apply le_nfpFamily, fun o l a => by rw [derivFamily_limit _ l, bsup_le_iff]⟩ +@[deprecated isNormal_derivFamily (since := "2024-10-11")] +alias derivFamily_isNormal := isNormal_derivFamily + theorem derivFamily_fp {i} (H : IsNormal (f i)) (o : Ordinal.{max u v}) : f i (derivFamily.{u, v} f o) = derivFamily.{u, v} f o := by induction' o using limitRecOn with o _ o l IH @@ -177,7 +188,7 @@ theorem le_iff_derivFamily (H : ∀ i, IsNormal (f i)) {a} : (∀ i, f i a ≤ a) ↔ ∃ o, derivFamily.{u, v} f o = a := ⟨fun ha => by suffices ∀ (o) (_ : a ≤ derivFamily.{u, v} f o), ∃ o, derivFamily.{u, v} f o = a from - this a (derivFamily_isNormal _).le_apply + this a (isNormal_derivFamily _).le_apply intro o induction' o using limitRecOn with o IH o l IH · intro h₁ @@ -197,7 +208,7 @@ theorem le_iff_derivFamily (H : ∀ i, IsNormal (f i)) {a} : exact let ⟨o', h, hl⟩ := h IH o' h (le_of_not_le hl), - fun ⟨o, e⟩ i => e ▸ (derivFamily_fp (H i) _).le⟩ + fun ⟨_, e⟩ i => e ▸ (derivFamily_fp (H i) _).le⟩ theorem fp_iff_derivFamily (H : ∀ i, IsNormal (f i)) {a} : (∀ i, f i a = a) ↔ ∃ o, derivFamily.{u, v} f o = a := @@ -206,8 +217,8 @@ theorem fp_iff_derivFamily (H : ∀ i, IsNormal (f i)) {a} : /-- For a family of normal functions, `Ordinal.derivFamily` enumerates the common fixed points. -/ theorem derivFamily_eq_enumOrd (H : ∀ i, IsNormal (f i)) : derivFamily.{u, v} f = enumOrd (⋂ i, Function.fixedPoints (f i)) := by - rw [← eq_enumOrd _ (fp_family_unbounded.{u, v} H)] - use (derivFamily_isNormal f).strictMono + rw [eq_comm, eq_enumOrd _ (not_bddAbove_fp_family H)] + use (isNormal_derivFamily f).strictMono rw [Set.range_eq_iff] refine ⟨?_, fun a ha => ?_⟩ · rintro a S ⟨i, hi⟩ @@ -242,7 +253,7 @@ theorem foldr_le_nfpBFamily {o : Ordinal} theorem le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a) : a ≤ nfpBFamily.{u, v} o f a := - Ordinal.le_iSup _ [] + Ordinal.le_iSup (fun _ ↦ List.foldr _ a _) [] theorem lt_nfpBFamily {a b} : a < nfpBFamily.{u, v} o f b ↔ ∃ l, a < List.foldr (familyOfBFamily o f) b l := @@ -254,7 +265,7 @@ theorem nfpBFamily_le_iff {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a 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.{u, v} + Ordinal.iSup_le theorem nfpBFamily_monotone (hf : ∀ i hi, Monotone (f i hi)) : Monotone (nfpBFamily.{u, v} o f) := nfpFamily_monotone fun _ => hf _ _ @@ -301,6 +312,16 @@ theorem nfpBFamily_eq_self {a} (h : ∀ i hi, f i hi a = a) : nfpBFamily.{u, v} /-- A generalization of the fixed point lemma for normal functions: any family of normal functions has an unbounded set of common fixed points. -/ +theorem not_bddAbove_fp_bfamily (H : ∀ i hi, IsNormal (f i hi)) : + ¬ BddAbove (⋂ (i) (hi), Function.fixedPoints (f i hi)) := by + rw [not_bddAbove_iff] + refine fun a ↦ ⟨nfpBFamily _ f (succ a), ?_, (lt_succ a).trans_le (le_nfpBFamily f _)⟩ + rw [Set.mem_iInter₂] + exact fun i hi ↦ nfpBFamily_fp (H i hi) _ + +/-- 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")] theorem fp_bfamily_unbounded (H : ∀ i hi, IsNormal (f i hi)) : (⋂ (i) (hi), Function.fixedPoints (f i hi)).Unbounded (· < ·) := fun a => ⟨nfpBFamily.{u, v} _ f a, by @@ -317,9 +338,12 @@ theorem derivBFamily_eq_derivFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Or derivBFamily.{u, v} o f = derivFamily.{u, v} (familyOfBFamily o f) := rfl -theorem derivBFamily_isNormal {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : +theorem isNormal_derivBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : IsNormal (derivBFamily o f) := - derivFamily_isNormal _ + isNormal_derivFamily _ + +@[deprecated isNormal_derivBFamily (since := "2024-10-11")] +alias derivBFamily_isNormal := isNormal_derivBFamily 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 @@ -347,8 +371,8 @@ theorem fp_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : /-- For a family of normal functions, `Ordinal.derivBFamily` enumerates the common fixed points. -/ theorem derivBFamily_eq_enumOrd (H : ∀ i hi, IsNormal (f i hi)) : derivBFamily.{u, v} o f = enumOrd (⋂ (i) (hi), Function.fixedPoints (f i hi)) := by - rw [← eq_enumOrd _ (fp_bfamily_unbounded.{u, v} H)] - use (derivBFamily_isNormal f).strictMono + rw [eq_comm, eq_enumOrd _ (not_bddAbove_fp_bfamily H)] + use (isNormal_derivBFamily f).strictMono rw [Set.range_eq_iff] refine ⟨fun a => Set.mem_iInter₂.2 fun i hi => derivBFamily_fp (H i hi) a, fun a ha => ?_⟩ rw [Set.mem_iInter₂] at ha @@ -398,7 +422,7 @@ theorem sup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) : theorem iterate_le_nfp (f a n) : f^[n] a ≤ nfp f a := by rw [← iSup_iterate_eq_nfp] - exact Ordinal.le_iSup _ n + exact Ordinal.le_iSup (fun n ↦ f^[n] a) n theorem le_nfp (f a) : a ≤ nfp f a := iterate_le_nfp f a 0 @@ -445,6 +469,14 @@ theorem nfp_eq_self {f : Ordinal → Ordinal} {a} (h : f a = a) : nfp f a = a := /-- The fixed point lemma for normal functions: any normal function has an unbounded set of fixed points. -/ +theorem not_bddAbove_fp (H : IsNormal f) : ¬ BddAbove (Function.fixedPoints f) := by + convert not_bddAbove_fp_family fun _ : Unit => H + exact (Set.iInter_const _).symm + +set_option linter.deprecated false in +/-- The fixed point lemma for normal functions: any normal function has an unbounded set of +fixed points. -/ +@[deprecated not_bddAbove_fp (since := "2024-09-20")] theorem fp_unbounded (H : IsNormal f) : (Function.fixedPoints f).Unbounded (· < ·) := by convert fp_family_unbounded fun _ : Unit => H exact (Set.iInter_const _).symm @@ -469,11 +501,14 @@ theorem deriv_succ (f o) : deriv f (succ o) = nfp f (succ (deriv f o)) := theorem deriv_limit (f) {o} : IsLimit o → deriv f o = bsup.{u, 0} o fun a _ => deriv f a := derivFamily_limit _ -theorem deriv_isNormal (f) : IsNormal (deriv f) := - derivFamily_isNormal _ +theorem isNormal_deriv (f) : IsNormal (deriv f) := + isNormal_derivFamily _ + +@[deprecated isNormal_deriv (since := "2024-10-11")] +alias deriv_isNormal := isNormal_deriv theorem deriv_id_of_nfp_id {f : Ordinal → Ordinal} (h : nfp f = id) : deriv f = id := - ((deriv_isNormal _).eq_iff_zero_and_succ IsNormal.refl).2 (by simp [h]) + ((isNormal_deriv _).eq_iff_zero_and_succ IsNormal.refl).2 (by simp [h]) theorem IsNormal.deriv_fp {f} (H : IsNormal f) : ∀ o, f (deriv f o) = deriv f o := @derivFamily_fp Unit (fun _ => f) Unit.unit H @@ -492,7 +527,7 @@ theorem deriv_eq_enumOrd (H : IsNormal f) : deriv f = enumOrd (Function.fixedPoi exact (Set.iInter_const _).symm theorem deriv_eq_id_of_nfp_eq_id {f : Ordinal → Ordinal} (h : nfp f = id) : deriv f = id := - (IsNormal.eq_iff_zero_and_succ (deriv_isNormal _) IsNormal.refl).2 <| by simp [h] + (IsNormal.eq_iff_zero_and_succ (isNormal_deriv _) IsNormal.refl).2 <| by simp [h] theorem nfp_zero_left (a) : nfp 0 a = a := by rw [← iSup_iterate_eq_nfp] @@ -529,9 +564,9 @@ theorem nfp_add_zero (a) : nfp (a + ·) 0 = a * ω := by · rw [iterate_succ_apply', Nat.add_comm, Nat.cast_add, Nat.cast_one, mul_one_add, hn] theorem nfp_add_eq_mul_omega0 {a b} (hba : b ≤ a * ω) : nfp (a + ·) b = a * ω := by - apply le_antisymm (nfp_le_fp (add_isNormal a).monotone hba _) + apply le_antisymm (nfp_le_fp (isNormal_add_right a).monotone hba _) · rw [← nfp_add_zero] - exact nfp_monotone (add_isNormal a).monotone (Ordinal.zero_le b) + exact nfp_monotone (isNormal_add_right a).monotone (Ordinal.zero_le b) · dsimp; rw [← mul_one_add, one_add_omega0] @[deprecated (since := "2024-09-30")] @@ -540,9 +575,9 @@ alias nfp_add_eq_mul_omega := nfp_add_eq_mul_omega0 theorem add_eq_right_iff_mul_omega0_le {a b : Ordinal} : a + b = b ↔ a * ω ≤ b := by refine ⟨fun h => ?_, fun h => ?_⟩ · rw [← nfp_add_zero a, ← deriv_zero_right] - cases' (add_isNormal a).fp_iff_deriv.1 h with c hc + cases' (isNormal_add_right a).fp_iff_deriv.1 h with c hc rw [← hc] - exact (deriv_isNormal _).monotone (Ordinal.zero_le _) + exact (isNormal_deriv _).monotone (Ordinal.zero_le _) · have := Ordinal.add_sub_cancel_of_le h nth_rw 1 [← this] rwa [← add_assoc, ← mul_one_add, one_add_omega0] @@ -552,14 +587,14 @@ alias add_eq_right_iff_mul_omega_le := add_eq_right_iff_mul_omega0_le theorem add_le_right_iff_mul_omega0_le {a b : Ordinal} : a + b ≤ b ↔ a * ω ≤ b := by rw [← add_eq_right_iff_mul_omega0_le] - exact (add_isNormal a).le_iff_eq + exact (isNormal_add_right a).le_iff_eq @[deprecated (since := "2024-09-30")] alias add_le_right_iff_mul_omega_le := add_le_right_iff_mul_omega0_le theorem deriv_add_eq_mul_omega0_add (a b : Ordinal.{u}) : deriv (a + ·) b = a * ω + b := by revert b - rw [← funext_iff, IsNormal.eq_iff_zero_and_succ (deriv_isNormal _) (add_isNormal _)] + rw [← funext_iff, IsNormal.eq_iff_zero_and_succ (isNormal_deriv _) (isNormal_add_right _)] refine ⟨?_, fun a h => ?_⟩ · rw [deriv_zero_right, add_zero] exact nfp_add_zero a @@ -594,10 +629,10 @@ theorem nfp_mul_eq_opow_omega0 {a b : Ordinal} (hb : 0 < b) (hba : b ≤ (a ^ ω simp_rw [Ordinal.le_zero.1 hba, zero_mul] exact nfp_zero_left 0 apply le_antisymm - · apply nfp_le_fp (mul_isNormal ha).monotone hba + · apply nfp_le_fp (isNormal_mul_right ha).monotone hba rw [← opow_one_add, one_add_omega0] rw [← nfp_mul_one ha] - exact nfp_monotone (mul_isNormal ha).monotone (one_le_iff_pos.2 hb) + exact nfp_monotone (isNormal_mul_right ha).monotone (one_le_iff_pos.2 hb) @[deprecated (since := "2024-09-30")] alias nfp_mul_eq_opow_omega := nfp_mul_eq_opow_omega0 @@ -611,7 +646,7 @@ theorem eq_zero_or_opow_omega0_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = intro hb rw [← nfp_mul_one ha] rw [← Ne, ← one_le_iff_ne_zero] at hb - exact nfp_le_fp (mul_isNormal ha).monotone hb (le_of_eq hab) + exact nfp_le_fp (isNormal_mul_right ha).monotone hb (le_of_eq hab) @[deprecated (since := "2024-09-30")] alias eq_zero_or_opow_omega_le_of_mul_eq_right := eq_zero_or_opow_omega0_le_of_mul_eq_right @@ -637,7 +672,7 @@ alias mul_eq_right_iff_opow_omega_dvd := mul_eq_right_iff_opow_omega0_dvd theorem mul_le_right_iff_opow_omega0_dvd {a b : Ordinal} (ha : 0 < a) : a * b ≤ b ↔ (a ^ ω) ∣ b := by rw [← mul_eq_right_iff_opow_omega0_dvd] - exact (mul_isNormal ha).le_iff_eq + exact (isNormal_mul_right ha).le_iff_eq @[deprecated (since := "2024-09-30")] alias mul_le_right_iff_opow_omega_dvd := mul_le_right_iff_opow_omega0_dvd @@ -645,16 +680,16 @@ alias mul_le_right_iff_opow_omega_dvd := mul_le_right_iff_opow_omega0_dvd theorem nfp_mul_opow_omega0_add {a c : Ordinal} (b) (ha : 0 < a) (hc : 0 < c) (hca : c ≤ a ^ ω) : nfp (a * ·) (a ^ ω * b + c) = (a ^ (ω : Ordinal.{u})) * succ b := by apply le_antisymm - · apply nfp_le_fp (mul_isNormal ha).monotone + · apply nfp_le_fp (isNormal_mul_right ha).monotone · rw [mul_succ] apply add_le_add_left hca · dsimp only; rw [← mul_assoc, ← opow_one_add, one_add_omega0] - · cases' mul_eq_right_iff_opow_omega0_dvd.1 ((mul_isNormal ha).nfp_fp ((a ^ ω) * b + c)) with - d hd + · obtain ⟨d, hd⟩ := + mul_eq_right_iff_opow_omega0_dvd.1 ((isNormal_mul_right ha).nfp_fp ((a ^ ω) * b + c)) rw [hd] apply mul_le_mul_left' have := le_nfp (a * ·) (a ^ ω * b + c) - erw [hd] at this + rw [hd] at this have := (add_lt_add_left hc (a ^ ω * b)).trans_le this rw [add_zero, mul_lt_mul_iff_left (opow_pos ω ha)] at this rwa [succ_le_iff] @@ -666,7 +701,7 @@ theorem deriv_mul_eq_opow_omega0_mul {a : Ordinal.{u}} (ha : 0 < a) (b) : deriv (a * ·) b = (a ^ ω) * b := by revert b rw [← funext_iff, - IsNormal.eq_iff_zero_and_succ (deriv_isNormal _) (mul_isNormal (opow_pos ω ha))] + IsNormal.eq_iff_zero_and_succ (isNormal_deriv _) (isNormal_mul_right (opow_pos ω ha))] refine ⟨?_, fun c h => ?_⟩ · dsimp only; rw [deriv_zero_right, nfp_mul_zero, mul_zero] · rw [deriv_succ, h] diff --git a/Mathlib/SetTheory/Ordinal/NaturalOps.lean b/Mathlib/SetTheory/Ordinal/NaturalOps.lean index b901e17cfa608..e4d93ce91b40d 100644 --- a/Mathlib/SetTheory/Ordinal/NaturalOps.lean +++ b/Mathlib/SetTheory/Ordinal/NaturalOps.lean @@ -307,7 +307,7 @@ theorem add_le_nadd : a + b ≤ a ♯ b := by | H₂ c h => rwa [add_succ, nadd_succ, succ_le_succ_iff] | H₃ c hc H => - simp_rw [← IsNormal.blsub_eq.{u, u} (add_isNormal a) hc, blsub_le_iff] + simp_rw [← IsNormal.blsub_eq.{u, u} (isNormal_add_right a) hc, blsub_le_iff] exact fun i hi => (H i hi).trans_lt (nadd_lt_nadd_left hi a) end Ordinal @@ -319,14 +319,13 @@ open Ordinal NaturalOps instance : Add NatOrdinal := ⟨nadd⟩ instance : SuccAddOrder NatOrdinal := ⟨fun x => (nadd_one x).symm⟩ -instance add_covariantClass_lt : CovariantClass NatOrdinal.{u} NatOrdinal.{u} (· + ·) (· < ·) := +instance addLeftStrictMono : AddLeftStrictMono NatOrdinal.{u} := ⟨fun a _ _ h => nadd_lt_nadd_left h a⟩ -instance add_covariantClass_le : CovariantClass NatOrdinal.{u} NatOrdinal.{u} (· + ·) (· ≤ ·) := +instance addLeftMono : AddLeftMono NatOrdinal.{u} := ⟨fun a _ _ h => nadd_le_nadd_left h a⟩ -instance add_contravariantClass_le : - ContravariantClass NatOrdinal.{u} NatOrdinal.{u} (· + ·) (· ≤ ·) := +instance addLeftReflectLE : AddLeftReflectLE NatOrdinal.{u} := ⟨fun a b c h => by by_contra! h' exact h.not_lt (add_lt_add_left h' a)⟩ @@ -335,8 +334,8 @@ instance orderedCancelAddCommMonoid : OrderedCancelAddCommMonoid NatOrdinal := { NatOrdinal.linearOrder with add := (· + ·) add_assoc := nadd_assoc - add_le_add_left := fun a b => add_le_add_left - le_of_add_le_add_left := fun a b c => le_of_add_le_add_left + add_le_add_left := fun _ _ => add_le_add_left + le_of_add_le_add_left := fun _ _ _ => le_of_add_le_add_left zero := 0 zero_add := zero_nadd add_zero := nadd_zero @@ -447,8 +446,11 @@ theorem nmul_def (a b : Ordinal) : /-- The set in the definition of `nmul` is nonempty. -/ private theorem nmul_nonempty (a b : Ordinal.{u}) : - {c : Ordinal.{u} | ∀ a' < a, ∀ b' < b, a' ⨳ b ♯ a ⨳ b' < c ♯ a' ⨳ b'}.Nonempty := - ⟨_, fun _ ha _ hb => (lt_blsub₂.{u, u, u} _ ha hb).trans_le le_self_nadd⟩ + {c : Ordinal.{u} | ∀ a' < a, ∀ b' < b, a' ⨳ b ♯ a ⨳ b' < c ♯ a' ⨳ b'}.Nonempty := by + obtain ⟨c, hc⟩ : BddAbove ((fun x ↦ x.1 ⨳ b ♯ a ⨳ x.2) '' Set.Iio a ×ˢ Set.Iio b) := + bddAbove_of_small _ + exact ⟨_, fun x hx y hy ↦ + (lt_succ_of_le <| hc <| Set.mem_image_of_mem _ <| Set.mk_mem_prod hx hy).trans_le le_self_nadd⟩ theorem nmul_nadd_lt {a' b' : Ordinal} (ha : a' < a) (hb : b' < b) : a' ⨳ b ♯ a ⨳ b' < a ⨳ b ♯ a' ⨳ b' := by @@ -688,8 +690,8 @@ instance : OrderedCommSemiring NatOrdinal.{u} := mul_one := nmul_one mul_comm := nmul_comm zero_le_one := @zero_le_one Ordinal _ _ _ _ - mul_le_mul_of_nonneg_left := fun a b c h _ => nmul_le_nmul_left h c - mul_le_mul_of_nonneg_right := fun a b c h _ => nmul_le_nmul_right h c } + mul_le_mul_of_nonneg_left := fun _ _ c h _ => nmul_le_nmul_left h c + mul_le_mul_of_nonneg_right := fun _ _ c h _ => nmul_le_nmul_right h c } namespace Ordinal @@ -721,7 +723,7 @@ theorem mul_le_nmul (a b : Ordinal.{u}) : a * b ≤ a ⨳ b := by · intro c hc H rcases eq_zero_or_pos a with (rfl | ha) · simp - · rw [← IsNormal.blsub_eq.{u, u} (mul_isNormal ha) hc, blsub_le_iff] + · rw [← IsNormal.blsub_eq.{u, u} (isNormal_mul_right ha) hc, blsub_le_iff] exact fun i hi => (H i hi).trans_lt (nmul_lt_nmul_of_pos_left hi ha) @[deprecated mul_le_nmul (since := "2024-08-20")] diff --git a/Mathlib/SetTheory/Ordinal/Nimber.lean b/Mathlib/SetTheory/Ordinal/Nimber.lean index 538d61ec4400d..b38f2ccbca68f 100644 --- a/Mathlib/SetTheory/Ordinal/Nimber.lean +++ b/Mathlib/SetTheory/Ordinal/Nimber.lean @@ -3,6 +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.Nat.Bitwise import Mathlib.SetTheory.Ordinal.Arithmetic /-! @@ -19,6 +20,12 @@ impartial game is equivalent to some game of nim. If `x ≈ nim o₁` and `y ≈ `x + y ≈ nim (o₁ + o₂)`, where the ordinals are summed together as nimbers. Unfortunately, the nim product admits no such characterization. +## Notation + +Following [On Numbers And Games][conway2001] (p. 121), we define notation `∗o` for the cast from +`Ordinal` to `Nimber`. Note that for general `n : ℕ`, `∗n` is **not** the same as `↑n`. For +instance, `∗2 ≠ 0`, whereas `↑2 = ↑1 + ↑1 = 0`. + ## Implementation notes The nimbers inherit the order from the ordinals - this makes working with minimum excluded values @@ -65,6 +72,9 @@ def Ordinal.toNimber : Ordinal ≃o Nimber := def Nimber.toOrdinal : Nimber ≃o Ordinal := OrderIso.refl _ +@[inherit_doc] +scoped[Nimber] prefix:75 "∗" => Ordinal.toNimber + namespace Nimber open Ordinal @@ -74,8 +84,8 @@ theorem toOrdinal_symm_eq : Nimber.toOrdinal.symm = Ordinal.toNimber := rfl @[simp] -theorem toOrdinal_toNimber (a : Nimber) : - Ordinal.toNimber (Nimber.toOrdinal a) = a := rfl +theorem toOrdinal_toNimber (a : Nimber) : ∗(Nimber.toOrdinal a) = a := + rfl theorem lt_wf : @WellFounded Nimber (· < ·) := Ordinal.lt_wf @@ -102,27 +112,27 @@ theorem toOrdinal_one : toOrdinal 1 = 1 := rfl @[simp] -theorem toOrdinal_eq_zero (a) : toOrdinal a = 0 ↔ a = 0 := +theorem toOrdinal_eq_zero {a} : toOrdinal a = 0 ↔ a = 0 := Iff.rfl @[simp] -theorem toOrdinal_eq_one (a) : toOrdinal a = 1 ↔ a = 1 := +theorem toOrdinal_eq_one {a} : toOrdinal a = 1 ↔ a = 1 := Iff.rfl @[simp] -theorem toOrdinal_max {a b : Nimber} : toOrdinal (max a b) = max (toOrdinal a) (toOrdinal b) := +theorem toOrdinal_max (a b : Nimber) : toOrdinal (max a b) = max (toOrdinal a) (toOrdinal b) := rfl @[simp] -theorem toOrdinal_min {a b : Nimber} : toOrdinal (min a b) = min (toOrdinal a) (toOrdinal b) := +theorem toOrdinal_min (a b : Nimber) : toOrdinal (min a b) = min (toOrdinal a) (toOrdinal b) := rfl -theorem succ_def (a : Nimber) : succ a = toNimber (toOrdinal a + 1) := +theorem succ_def (a : Nimber) : succ a = ∗(toOrdinal a + 1) := rfl /-- A recursor for `Nimber`. Use as `induction x`. -/ @[elab_as_elim, cases_eliminator, induction_eliminator] -protected def rec {β : Nimber → Sort*} (h : ∀ a, β (toNimber a)) : ∀ a, β a := fun a => +protected def rec {β : Nimber → Sort*} (h : ∀ a, β (∗a)) : ∀ a, β a := fun a => h (toOrdinal a) /-- `Ordinal.induction` but for `Nimber`. -/ @@ -138,6 +148,9 @@ protected theorem not_lt_zero (a : Nimber) : ¬ a < 0 := protected theorem pos_iff_ne_zero {a : Nimber} : 0 < a ↔ a ≠ 0 := Ordinal.pos_iff_ne_zero +theorem eq_nat_of_le_nat {a : Nimber} {b : ℕ} (h : a ≤ ∗b) : ∃ c : ℕ, a = ∗c := + Ordinal.lt_omega0.1 (h.trans_lt (nat_lt_omega0 b)) + instance small_Iio (a : Nimber.{u}) : Small.{u} (Set.Iio a) := Ordinal.small_Iio a instance small_Iic (a : Nimber.{u}) : Small.{u} (Set.Iic a) := Ordinal.small_Iic a instance small_Ico (a b : Nimber.{u}) : Small.{u} (Set.Ico a b) := Ordinal.small_Ico a b @@ -150,42 +163,40 @@ end Nimber theorem not_small_nimber : ¬ Small.{u} Nimber.{max u v} := not_small_ordinal -namespace Ordinal +open Nimber -variable {a b c : Ordinal.{u}} +namespace Ordinal @[simp] theorem toNimber_symm_eq : toNimber.symm = Nimber.toOrdinal := rfl @[simp] -theorem toNimber_toOrdinal (a : Ordinal) : Nimber.toOrdinal (toNimber a) = a := +theorem toNimber_toOrdinal (a : Ordinal) : Nimber.toOrdinal (∗a) = a := rfl @[simp] -theorem toNimber_zero : toNimber 0 = 0 := +theorem toNimber_zero : ∗0 = 0 := rfl @[simp] -theorem toNimber_one : toNimber 1 = 1 := +theorem toNimber_one : ∗1 = 1 := rfl @[simp] -theorem toNimber_eq_zero (a) : toNimber a = 0 ↔ a = 0 := +theorem toNimber_eq_zero {a} : ∗a = 0 ↔ a = 0 := Iff.rfl @[simp] -theorem toNimber_eq_one (a) : toNimber a = 1 ↔ a = 1 := +theorem toNimber_eq_one {a} : ∗a = 1 ↔ a = 1 := Iff.rfl @[simp] -theorem toNimber_max (a b : Ordinal) : - toNimber (max a b) = max (toNimber a) (toNimber b) := +theorem toNimber_max (a b : Ordinal) : ∗(max a b) = max (∗a) (∗b) := rfl @[simp] -theorem toNimber_min (a b : Ordinal) : - toNimber (min a b) = min (toNimber a) (toNimber b) := +theorem toNimber_min (a b : Ordinal) : ∗(min a b) = min (∗a) (∗b) := rfl end Ordinal @@ -358,4 +369,29 @@ theorem add_trichotomy {a b c : Nimber} (h : a + b + c ≠ 0) : · rw [← hx'] at hx exact Or.inr <| Or.inr hx +theorem lt_add_cases {a b c : Nimber} (h : a < b + c) : a + c < b ∨ a + b < c := by + obtain ha | hb | hc := add_trichotomy <| add_assoc a b c ▸ add_ne_zero_iff.2 h.ne + exacts [(h.asymm ha).elim, Or.inl <| add_comm c a ▸ hb, Or.inr hc] + +/-- Nimber addition of naturals corresponds to the bitwise XOR operation. -/ +theorem add_nat (a b : ℕ) : ∗a + ∗b = ∗(a ^^^ b) := by + apply le_antisymm + · apply add_le_of_forall_ne + all_goals + intro c hc + obtain ⟨c, rfl⟩ := eq_nat_of_le_nat hc.le + rw [OrderIso.lt_iff_lt] at hc + replace hc := Nat.cast_lt.1 hc + rw [add_nat] + simpa using hc.ne + · apply le_of_not_lt + intro hc + obtain ⟨c, hc'⟩ := eq_nat_of_le_nat hc.le + rw [hc', OrderIso.lt_iff_lt, Nat.cast_lt] at hc + obtain h | h := Nat.lt_xor_cases hc + · apply h.ne + simpa [Nat.xor_comm, Nat.xor_cancel_left, ← hc'] using add_nat (c ^^^ b) b + · apply h.ne + simpa [Nat.xor_comm, Nat.xor_cancel_left, ← hc'] using add_nat a (c ^^^ a) + end Nimber diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index fd54a141e2131..599622b062840 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -3,11 +3,10 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.Ordering.Lemmas +import Mathlib.Data.PNat.Basic import Mathlib.SetTheory.Ordinal.Principal import Mathlib.Tactic.NormNum -import Mathlib.Data.PNat.Basic /-! # Ordinal notation @@ -20,7 +19,7 @@ We say that `o` is in Cantor normal form - `ONote.NF o` - if either `o = 0` or `o = ω ^ e * n + a` with `a < ω ^ e` and `a` in Cantor normal form. The type `NONote` is the type of ordinals below `ε₀` in Cantor normal form. -Various operations (addition, subtraction, multiplication, power function) +Various operations (addition, subtraction, multiplication, exponentiation) are defined on `ONote` and `NONote`. -/ @@ -30,11 +29,10 @@ open Ordinal Order -- Porting note: the generated theorem is warned by `simpNF`. set_option genSizeOfSpec false in -/-- Recursive definition of an ordinal notation. `zero` denotes the - ordinal 0, and `oadd e n a` is intended to refer to `ω^e * n + a`. - For this to be valid Cantor normal form, we must have the exponents - decrease to the right, but we can't state this condition until we've - defined `repr`, so it is a separate definition `NF`. -/ +/-- Recursive definition of an ordinal notation. `zero` denotes the ordinal 0, and `oadd e n a` is +intended to refer to `ω ^ e * n + a`. For this to be a valid Cantor normal form, we must have the +exponents decrease to the right, but we can't state this condition until we've defined `repr`, so we +make it a separate definition `NF`. -/ inductive ONote : Type | zero : ONote | oadd : ONote → ℕ+ → ONote → ONote @@ -69,16 +67,16 @@ noncomputable def repr : ONote → Ordinal.{0} | 0 => 0 | oadd e n a => ω ^ repr e * n + repr a -/-- Auxiliary definition to print an ordinal notation -/ -def toStringAux1 (e : ONote) (n : ℕ) (s : String) : String := +/-- Print `ω^s*n`, omitting `s` if `e = 0` or `e = 1`, and omitting `n` if `n = 1` -/ +private def toString_aux (e : ONote) (n : ℕ) (s : String) : String := if e = 0 then toString n else (if e = 1 then "ω" else "ω^(" ++ s ++ ")") ++ if n = 1 then "" else "*" ++ toString n /-- Print an ordinal notation -/ def toString : ONote → String | zero => "0" - | oadd e n 0 => toStringAux1 e n (toString e) - | oadd e n a => toStringAux1 e n (toString e) ++ " + " ++ toString a + | oadd e n 0 => toString_aux e n (toString e) + | oadd e n a => toString_aux e n (toString e) ++ " + " ++ toString a open Lean in /-- Print an ordinal notation -/ @@ -136,12 +134,11 @@ theorem ofNat_one : ofNat 1 = 1 := @[simp] theorem repr_ofNat (n : ℕ) : repr (ofNat n) = n := by cases n <;> simp --- @[simp] -- Porting note (#10618): simp can prove this theorem repr_one : repr (ofNat 1) = (1 : ℕ) := repr_ofNat 1 theorem omega0_le_oadd (e n a) : ω ^ repr e ≤ repr (oadd e n a) := by refine le_trans ?_ (le_add_right _ _) - simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos (repr e) omega0_pos).2 (natCast_le.2 n.2) + simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos (repr e) omega0_pos).2 (Nat.cast_le.2 n.2) @[deprecated (since := "2024-09-30")] alias omega_le_oadd := omega0_le_oadd @@ -149,7 +146,10 @@ alias omega_le_oadd := omega0_le_oadd theorem oadd_pos (e n a) : 0 < oadd e n a := @lt_of_lt_of_le _ _ _ (ω ^ repr e) _ (opow_pos (repr e) omega0_pos) (omega0_le_oadd e n a) -/-- Compare ordinal notations -/ +/-- Comparison of ordinal notations: + +`ω ^ e₁ * n₁ + a₁` is less than `ω ^ e₂ * n₂ + a₂` when either `e₁ < e₂`, or `e₁ = e₂` and +`n₁ < n₂`, or `e₁ = e₂`, `n₁ = n₂`, and `a₁ < a₂`. -/ def cmp : ONote → ONote → Ordering | 0, 0 => Ordering.eq | _, 0 => Ordering.gt @@ -175,22 +175,20 @@ protected theorem zero_lt_one : (0 : ONote) < 1 := by simp only [lt_def, repr, opow_zero, Nat.succPNat_coe, Nat.cast_one, mul_one, add_zero, zero_lt_one] -/-- `NFBelow o b` says that `o` is a normal form ordinal notation - satisfying `repr o < ω ^ b`. -/ +/-- `NFBelow o b` says that `o` is a normal form ordinal notation satisfying `repr o < ω ^ b`. -/ inductive NFBelow : ONote → Ordinal.{0} → Prop | zero {b} : NFBelow 0 b | oadd' {e n a eb b} : NFBelow e eb → NFBelow a (repr e) → repr e < b → NFBelow (oadd e n a) b /-- A normal form ordinal notation has the form - ω ^ a₁ * n₁ + ω ^ a₂ * n₂ + ... ω ^ aₖ * nₖ - where `a₁ > a₂ > ... > aₖ` and all the `aᵢ` are - also in normal form. +`ω ^ a₁ * n₁ + ω ^ a₂ * n₂ + ⋯ + ω ^ aₖ * nₖ` + +where `a₁ > a₂ > ⋯ > aₖ` and all the `aᵢ` are also in normal form. - We will essentially only be interested in normal form - ordinal notations, but to avoid complicating the algorithms - we define everything over general ordinal notations and - only prove correctness with normal form as an invariant. -/ +We will essentially only be interested in normal form ordinal notations, but to avoid complicating +the algorithms, we define everything over general ordinal notations and only prove correctness with +normal form as an invariant. -/ class NF (o : ONote) : Prop where out : Exists (NFBelow o) @@ -276,7 +274,7 @@ theorem oadd_lt_oadd_2 {e o₁ o₂ : ONote} {n₁ n₂ : ℕ+} (h₁ : NF (oadd oadd e n₁ o₁ < oadd e n₂ o₂ := by simp only [lt_def, repr] refine lt_of_lt_of_le ((add_lt_add_iff_left _).2 h₁.snd'.repr_lt) (le_trans ?_ (le_add_right _ _)) - rwa [← mul_succ,Ordinal.mul_le_mul_iff_left (opow_pos _ omega0_pos), succ_le_iff, natCast_lt] + rwa [← mul_succ,Ordinal.mul_le_mul_iff_left (opow_pos _ omega0_pos), succ_le_iff, Nat.cast_lt] theorem oadd_lt_oadd_3 {e n a₁ a₂} (h : a₁ < a₂) : oadd e n a₁ < oadd e n a₂ := by rw [lt_def]; unfold repr @@ -284,8 +282,8 @@ theorem oadd_lt_oadd_3 {e n a₁ a₂} (h : a₁ < a₂) : oadd e n a₁ < oadd theorem cmp_compares : ∀ (a b : ONote) [NF a] [NF b], (cmp a b).Compares a b | 0, 0, _, _ => rfl - | oadd e n a, 0, _, _ => oadd_pos _ _ _ - | 0, oadd e n a, _, _ => oadd_pos _ _ _ + | oadd _ _ _, 0, _, _ => oadd_pos _ _ _ + | 0, oadd _ _ _, _, _ => oadd_pos _ _ _ | o₁@(oadd e₁ n₁ a₁), o₂@(oadd e₂ n₂ a₂), h₁, h₂ => by -- TODO: golf rw [cmp] have IHe := @cmp_compares _ _ h₁.fst h₂.fst @@ -346,9 +344,8 @@ theorem NF.of_dvd_omega0 {e n a} (h : NF (ONote.oadd e n a)) : @[deprecated (since := "2024-09-30")] alias NF.of_dvd_omega := NF.of_dvd_omega0 -/-- `TopBelow b o` asserts that the largest exponent in `o`, if - it exists, is less than `b`. This is an auxiliary definition - for decidability of `NF`. -/ +/-- `TopBelow b o` asserts that the largest exponent in `o`, if it exists, is less than `b`. This is +an auxiliary definition for decidability of `NF`. -/ def TopBelow (b : ONote) : ONote → Prop | 0 => True | oadd e _ _ => cmp e b = Ordering.lt @@ -453,7 +450,7 @@ theorem repr_add : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ + o₂) = rep cases he' : e' <;> simp only [he', zero_def, opow_zero, repr, gt_iff_lt] at this ⊢ <;> exact lt_of_le_of_lt (le_add_right _ _) this · simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos (repr e') omega0_pos).2 - (natCast_le.2 n'.pos) + (Nat.cast_le.2 n'.pos) · rw [ee, ← add_assoc, ← mul_add] theorem sub_nfBelow : ∀ {o₁ o₂ b}, NFBelow o₁ b → NF o₂ → NFBelow (o₁ - o₂) b @@ -481,7 +478,7 @@ instance sub_nf (o₁ o₂) : ∀ [NF o₁] [NF o₂], NF (o₁ - o₂) @[simp] theorem repr_sub : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ - o₂) = repr o₁ - repr o₂ | 0, o, _, h₂ => by cases o <;> exact (Ordinal.zero_sub _).symm - | oadd e n a, 0, _, _ => (Ordinal.sub_zero _).symm + | oadd _ _ _, 0, _, _ => (Ordinal.sub_zero _).symm | oadd e₁ n₁ a₁, oadd e₂ n₂ a₂, h₁, h₂ => by haveI := h₁.snd; haveI := h₂.snd; have h' := repr_sub a₁ a₂ conv_lhs at h' => dsimp [HSub.hSub, Sub.sub, sub] @@ -509,7 +506,7 @@ theorem repr_sub : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ - o₂) = rep refine (Ordinal.sub_eq_of_add_eq <| add_absorp h₂.snd'.repr_lt <| le_trans ?_ (le_add_right _ _)).symm - simpa using mul_le_mul_left' (natCast_le.2 <| Nat.succ_pos _) _ + exact Ordinal.le_mul_left _ (Nat.cast_lt.2 <| Nat.succ_pos _) · exact (Ordinal.sub_eq_of_add_eq <| add_absorp (h₂.below_of_lt ee).repr_lt <| omega0_le_oadd _ _ _).symm @@ -537,7 +534,7 @@ theorem oadd_mul (e₁ n₁ a₁ e₂ n₂ a₂) : theorem oadd_mul_nfBelow {e₁ n₁ a₁ b₁} (h₁ : NFBelow (oadd e₁ n₁ a₁) b₁) : ∀ {o₂ b₂}, NFBelow o₂ b₂ → NFBelow (oadd e₁ n₁ a₁ * o₂) (repr e₁ + b₂) - | 0, b₂, _ => NFBelow.zero + | 0, _, _ => NFBelow.zero | oadd e₂ n₂ a₂, b₂, h₂ => by have IH := oadd_mul_nfBelow h₁ h₂.snd by_cases e0 : e₂ = 0 <;> simp only [e0, oadd_mul, ↓reduceIte] @@ -553,12 +550,12 @@ theorem oadd_mul_nfBelow {e₁ n₁ a₁ b₁} (h₁ : NFBelow (oadd e₁ n₁ a instance mul_nf : ∀ (o₁ o₂) [NF o₁] [NF o₂], NF (o₁ * o₂) | 0, o, _, h₂ => by cases o <;> exact NF.zero - | oadd e n a, o, ⟨⟨b₁, hb₁⟩⟩, ⟨⟨b₂, hb₂⟩⟩ => ⟨⟨_, oadd_mul_nfBelow hb₁ hb₂⟩⟩ + | oadd _ _ _, _, ⟨⟨_, hb₁⟩⟩, ⟨⟨_, hb₂⟩⟩ => ⟨⟨_, oadd_mul_nfBelow hb₁ hb₂⟩⟩ @[simp] theorem repr_mul : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ * o₂) = repr o₁ * repr o₂ | 0, o, _, h₂ => by cases o <;> exact (zero_mul _).symm - | oadd e₁ n₁ a₁, 0, _, _ => (mul_zero _).symm + | oadd _ _ _, 0, _, _ => (mul_zero _).symm | oadd e₁ n₁ a₁, oadd e₂ n₂ a₂, h₁, h₂ => by have IH : repr (mul _ _) = _ := @repr_mul _ _ h₁ h₂.snd conv => @@ -566,7 +563,7 @@ theorem repr_mul : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ * o₂) = rep simp [(· * ·)] have ao : repr a₁ + ω ^ repr e₁ * (n₁ : ℕ) = ω ^ repr e₁ * (n₁ : ℕ) := by apply add_absorp h₁.snd'.repr_lt - simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos _ omega0_pos).2 (natCast_le.2 n₁.2) + simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos _ omega0_pos).2 (Nat.cast_le.2 n₁.2) by_cases e0 : e₂ = 0 · cases' Nat.exists_eq_succ_of_ne_zero n₂.ne_zero with x xe simp only [e0, repr, PNat.mul_coe, natCast_mul, opow_zero, one_mul] @@ -579,12 +576,13 @@ theorem repr_mul : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ * o₂) = rep rw [← mul_assoc] congr 2 have := mt repr_inj.1 e0 - rw [add_mul_limit ao (opow_isLimit_left omega0_isLimit this), mul_assoc, - mul_omega0_dvd (natCast_pos.2 n₁.pos) (nat_lt_omega0 _)] + rw [add_mul_limit ao (isLimit_opow_left isLimit_omega0 this), mul_assoc, + mul_omega0_dvd (Nat.cast_pos'.2 n₁.pos) (nat_lt_omega0 _)] simpa using opow_dvd_opow ω (one_le_iff_ne_zero.2 this) -/-- Calculate division and remainder of `o` mod ω. - `split' o = (a, n)` means `o = ω * a + n`. -/ +/-- Calculate division and remainder of `o` mod `ω`: + +`split' o = (a, n)` means `o = ω * a + n`. -/ def split' : ONote → ONote × ℕ | 0 => (0, 0) | oadd e n a => @@ -593,8 +591,9 @@ def split' : ONote → ONote × ℕ let (a', m) := split' a (oadd (e - 1) n a', m) -/-- Calculate division and remainder of `o` mod ω. - `split o = (a, n)` means `o = a + n`, where `ω ∣ a`. -/ +/-- Calculate division and remainder of `o` mod `ω`: + +`split o = (a, n)` means `o = a + n`, where `ω ∣ a`. -/ def split : ONote → ONote × ℕ | 0 => (0, 0) | oadd e n a => @@ -614,15 +613,13 @@ def mulNat : ONote → ℕ → ONote | _, 0 => 0 | oadd e n a, m + 1 => oadd e (n * m.succPNat) a -/-- Auxiliary definition to compute the ordinal notation for the ordinal -exponentiation in `opow` -/ +/-- Auxiliary definition to compute the ordinal notation for the ordinal exponentiation in `opow` -/ def opowAux (e a0 a : ONote) : ℕ → ℕ → ONote | _, 0 => 0 | 0, m + 1 => oadd e m.succPNat 0 | k + 1, m => scale (e + mulNat a0 k) a + (opowAux e a0 a k m) -/-- Auxiliary definition to compute the ordinal notation for the ordinal -exponentiation in `opow` -/ +/-- Auxiliary definition to compute the ordinal notation for the ordinal exponentiation in `opow` -/ def opowAux2 (o₂ : ONote) (o₁ : ONote × ℕ) : ONote := match o₁ with | (0, 0) => if o₂ = 0 then 1 else 0 @@ -637,8 +634,7 @@ def opowAux2 (o₂ : ONote) (o₁ : ONote × ℕ) : ONote := let eb := a0 * b scale (eb + mulNat a0 k) a + opowAux eb a0 (mulNat a m) k m -/-- `opow o₁ o₂` calculates the ordinal notation for - the ordinal exponential `o₁ ^ o₂`. -/ +/-- `opow o₁ o₂` calculates the ordinal notation for the ordinal exponential `o₁ ^ o₂`. -/ def opow (o₁ o₂ : ONote) : ONote := opowAux2 o₂ (split o₁) instance : Pow ONote ONote := @@ -793,7 +789,7 @@ theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr have := omega0_le_oadd e n a rw [repr] at this refine le_antisymm ?_ (opow_le_opow_left _ this) - apply (opow_le_of_limit ((opow_pos _ omega0_pos).trans_le this).ne' omega0_isLimit).2 + apply (opow_le_of_limit ((opow_pos _ omega0_pos).trans_le this).ne' isLimit_omega0).2 intro b l have := (No.below_of_lt (lt_succ _)).repr_lt rw [repr] at this @@ -804,8 +800,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 omega0_isLimit.2 _ l - · apply (principal_mul_omega0 (omega0_isLimit.2 _ h) l).le.trans + exact isLimit_omega0.2 _ l + · apply (principal_mul_omega0 (isLimit_omega0.2 _ h) l).le.trans simpa using mul_le_mul_right' (one_le_iff_ne_zero.2 e0) ω section @@ -860,7 +856,7 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω · exact lt_of_lt_of_le Rl (opow_le_opow_right omega0_pos <| - mul_le_mul_left' (succ_le_succ_iff.2 (natCast_le.2 (le_of_lt k.lt_succ_self))) _) + mul_le_mul_left' (succ_le_succ_iff.2 (Nat.cast_le.2 (le_of_lt k.lt_succ_self))) _) calc (ω0 ^ (k.succ : Ordinal)) * α' + R' _ = (ω0 ^ succ (k : Ordinal)) * α' + ((ω0 ^ (k : Ordinal)) * α' * m + R) := by @@ -872,12 +868,12 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω dvd_add (dvd_mul_of_dvd_left (by simpa using opow_dvd_opow ω (one_le_iff_ne_zero.2 e0)) _) d rw [mul_add (ω0 ^ (k : Ordinal)), add_assoc, ← mul_assoc, ← opow_succ, add_mul_limit _ (isLimit_iff_omega0_dvd.2 ⟨ne_of_gt α0, αd⟩), mul_assoc, - @mul_omega0_dvd n (natCast_pos.2 n.pos) (nat_lt_omega0 _) _ αd] + @mul_omega0_dvd n (Nat.cast_pos'.2 n.pos) (nat_lt_omega0 _) _ αd] apply @add_absorp _ (repr a0 * succ ↑k) · refine principal_add_omega0_opow _ ?_ Rl rw [opow_mul, opow_succ, Ordinal.mul_lt_mul_iff_left ω00] exact No.snd'.repr_lt - · have := mul_le_mul_left' (one_le_iff_pos.2 <| natCast_pos.2 n.pos) (ω0 ^ succ (k : Ordinal)) + · have := mul_le_mul_left' (one_le_iff_pos.2 <| Nat.cast_pos'.2 n.pos) (ω0 ^ succ (k : Ordinal)) rw [opow_mul] simpa [-opow_succ] · cases m @@ -938,8 +934,11 @@ theorem repr_opow (o₁ o₂) [NF o₁] [NF o₂] : repr (o₁ ^ o₂) = repr o rw [← opow_succ] exact (repr_opow_aux₂ _ ad a00 al _ _).2 -/-- Given an ordinal, returns `inl none` for `0`, `inl (some a)` for `a+1`, and - `inr f` for a limit ordinal `a`, where `f i` is a sequence converging to `a`. -/ +/-- Given an ordinal, returns: + +* `inl none` for `0` +* `inl (some a)` for `a + 1` +* `inr f` for a limit ordinal `a`, where `f i` is a sequence converging to `a` -/ def fundamentalSequence : ONote → (Option ONote) ⊕ (ℕ → ONote) | zero => Sum.inl none | oadd a m b => @@ -966,7 +965,7 @@ private theorem exists_lt_add {α} [hα : Nonempty α] {o : Ordinal} {f : α → private theorem exists_lt_mul_omega0' {o : Ordinal} ⦃a⦄ (h : a < o * ω) : ∃ i : ℕ, a < o * ↑i + o := by - obtain ⟨i, hi, h'⟩ := (lt_mul_of_limit omega0_isLimit).1 h + obtain ⟨i, hi, h'⟩ := (lt_mul_of_limit isLimit_omega0).1 h obtain ⟨i, rfl⟩ := lt_omega0.1 hi exact ⟨i, h'.trans_le (le_add_right _ _)⟩ @@ -977,10 +976,11 @@ private theorem exists_lt_omega0_opow' {α} {o b : Ordinal} (hb : 1 < b) (ho : o exact (H hd).imp fun i hi => h'.trans <| (opow_lt_opow_iff_right hb).2 hi /-- The property satisfied by `fundamentalSequence o`: - * `inl none` means `o = 0` - * `inl (some a)` means `o = succ a` - * `inr f` means `o` is a limit ordinal and `f` is a - strictly increasing sequence which converges to `o` -/ + +* `inl none` means `o = 0` +* `inl (some a)` means `o = succ a` +* `inr f` means `o` is a limit ordinal and `f` is a strictly increasing sequence which converges to + `o` -/ def FundamentalSequenceProp (o : ONote) : (Option ONote) ⊕ (ℕ → ONote) → Prop | Sum.inl none => o = 0 | Sum.inl (some a) => o.repr = succ a.repr ∧ (o.NF → a.NF) @@ -1003,13 +1003,6 @@ theorem fundamentalSequenceProp_inr (o f) : ∀ a, a < o.repr → ∃ i, a < (f i).repr := Iff.rfl -attribute - [eqns - fundamentalSequenceProp_inl_none - fundamentalSequenceProp_inl_some - fundamentalSequenceProp_inr] - FundamentalSequenceProp - theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamentalSequence o) := by induction' o with a m b iha ihb; · exact rfl rw [fundamentalSequence] @@ -1031,13 +1024,13 @@ theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamenta · exact ⟨rfl, inferInstance⟩ · have := opow_pos (repr a') omega0_pos refine - ⟨mul_isLimit this omega0_isLimit, fun i => + ⟨isLimit_mul this isLimit_omega0, fun i => ⟨this, ?_, fun H => @NF.oadd_zero _ _ (iha.2 H.fst)⟩, exists_lt_mul_omega0'⟩ rw [← mul_succ, ← natCast_succ, Ordinal.mul_lt_mul_iff_left this] apply nat_lt_omega0 · have := opow_pos (repr a') omega0_pos refine - ⟨add_isLimit _ (mul_isLimit this omega0_isLimit), fun i => ⟨this, ?_, ?_⟩, + ⟨isLimit_add _ (isLimit_mul this isLimit_omega0), fun i => ⟨this, ?_, ?_⟩, exists_lt_add exists_lt_mul_omega0'⟩ · rw [← mul_succ, ← natCast_succ, Ordinal.mul_lt_mul_iff_left this] apply nat_lt_omega0 @@ -1045,13 +1038,13 @@ theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamenta rw [repr, ← zero_def, repr, add_zero, iha.1, opow_succ, Ordinal.mul_lt_mul_iff_left this] apply nat_lt_omega0 · rcases iha with ⟨h1, h2, h3⟩ - refine ⟨opow_isLimit one_lt_omega0 h1, fun i => ?_, + refine ⟨isLimit_opow one_lt_omega0 h1, fun i => ?_, exists_lt_omega0_opow' one_lt_omega0 h1 h3⟩ obtain ⟨h4, h5, h6⟩ := h2 i exact ⟨h4, h5, fun H => @NF.oadd_zero _ _ (h6 H.fst)⟩ · rcases iha with ⟨h1, h2, h3⟩ refine - ⟨add_isLimit _ (opow_isLimit one_lt_omega0 h1), fun i => ?_, + ⟨isLimit_add _ (isLimit_opow one_lt_omega0 h1), fun i => ?_, exists_lt_add (exists_lt_omega0_opow' one_lt_omega0 h1 h3)⟩ obtain ⟨h4, h5, h6⟩ := h2 i refine ⟨h4, h5, fun H => H.fst.oadd _ (NF.below_of_lt' ?_ (@NF.oadd_zero _ _ (h6 H.fst)))⟩ @@ -1065,17 +1058,18 @@ theorem fundamentalSequence_has_prop (o) : FundamentalSequenceProp o (fundamenta · rcases ihb with ⟨h1, h2, h3⟩ simp only [repr] exact - ⟨Ordinal.add_isLimit _ h1, fun i => + ⟨Ordinal.isLimit_add _ h1, fun i => ⟨oadd_lt_oadd_3 (h2 i).1, oadd_lt_oadd_3 (h2 i).2.1, fun H => H.fst.oadd _ (NF.below_of_lt' (lt_trans (h2 i).2.1 H.snd'.repr_lt) ((h2 i).2.2 H.snd))⟩, exists_lt_add h3⟩ -/-- The fast growing hierarchy for ordinal notations `< ε₀`. This is a sequence of -functions `ℕ → ℕ` indexed by ordinals, with the definition: +/-- The fast growing hierarchy for ordinal notations `< ε₀`. This is a sequence of functions `ℕ → ℕ` +indexed by ordinals, with the definition: + * `f_0(n) = n + 1` -* `f_(α+1)(n) = f_α^[n](n)` -* `f_α(n) = f_(α[n])(n)` where `α` is a limit ordinal - and `α[i]` is the fundamental sequence converging to `α` -/ +* `f_(α + 1)(n) = f_α^[n](n)` +* `f_α(n) = f_(α[n])(n)` where `α` is a limit ordinal and `α[i]` is the fundamental sequence + converging to `α` -/ def fastGrowing : ONote → ℕ → ℕ | o => match fundamentalSequence o, fundamentalSequence_has_prop o with @@ -1088,7 +1082,7 @@ def fastGrowing : ONote → ℕ → ℕ fastGrowing (f i) i termination_by o => o --- Porting note: the bug of the linter, should be fixed. +-- Porting note: the linter bug should be fixed. @[nolint unusedHavesSuffices] theorem fastGrowing_def {o : ONote} {x} (e : fundamentalSequence o = x) : fastGrowing o = @@ -1125,8 +1119,6 @@ theorem fastGrowing_one : fastGrowing 1 = fun n => 2 * n := by suffices ∀ a b, Nat.succ^[a] b = b + a from this _ _ intro a b; induction a <;> simp [*, Function.iterate_succ', Nat.add_assoc, -Function.iterate_succ] -section - @[simp] theorem fastGrowing_two : fastGrowing 2 = fun n => (2 ^ n) * n := by rw [@fastGrowing_succ 2 1 rfl]; funext i; rw [fastGrowing_one] @@ -1134,12 +1126,9 @@ theorem fastGrowing_two : fastGrowing 2 = fun n => (2 ^ n) * n := by intro a b; induction a <;> simp [*, Function.iterate_succ, pow_succ, mul_assoc, -Function.iterate_succ] -end - -/-- We can extend the fast growing hierarchy one more step to `ε₀` itself, - using `ω^(ω^...^ω^0)` as the fundamental sequence converging to `ε₀` (which is not an `ONote`). - Extending the fast growing hierarchy beyond this requires a definition of fundamental sequence - for larger ordinals. -/ +/-- We can extend the fast growing hierarchy one more step to `ε₀` itself, using `ω ^ (ω ^ (⋯ ^ ω))` +as the fundamental sequence converging to `ε₀` (which is not an `ONote`). Extending the fast +growing hierarchy beyond this requires a definition of fundamental sequence for larger ordinals. -/ def fastGrowingε₀ (i : ℕ) : ℕ := fastGrowing ((fun a => a.oadd 1 0)^[i] 0) i @@ -1154,11 +1143,11 @@ theorem fastGrowingε₀_two : fastGrowingε₀ 2 = 2048 := by end ONote -/-- The type of normal ordinal notations. (It would have been - nicer to define this right in the inductive type, but `NF o` - requires `repr` which requires `ONote`, so all these things - would have to be defined at once, which messes up the VM - representation.) -/ +/-- The type of normal ordinal notations. + +It would have been nicer to define this right in the inductive type, but `NF o` requires `repr` +which requires `ONote`, so all these things would have to be defined at once, which messes up the VM +representation. -/ def NONote := { o : ONote // o.NF } @@ -1171,17 +1160,15 @@ open ONote instance NF (o : NONote) : NF o.1 := o.2 -/-- Construct a `NONote` from an ordinal notation - (and infer normality) -/ +/-- Construct a `NONote` from an ordinal notation (and infer normality) -/ def mk (o : ONote) [h : ONote.NF o] : NONote := ⟨o, h⟩ /-- The ordinal represented by an ordinal notation. - (This function is noncomputable because ordinal - arithmetic is noncomputable. In computational applications - `NONote` can be used exclusively without reference - to `Ordinal`, but this function allows for correctness - results to be stated.) -/ + +This function is noncomputable because ordinal arithmetic is noncomputable. In computational +applications `NONote` can be used exclusively without reference to `Ordinal`, but this function +allows for correctness results to be stated. -/ noncomputable def repr (o : NONote) : Ordinal := o.1.repr @@ -1233,7 +1220,7 @@ instance : LinearOrder NONote := instance : IsWellOrder NONote (· < ·) where -/-- Asserts that `repr a < ω ^ repr b`. Used in `NONote.recOn` -/ +/-- Asserts that `repr a < ω ^ repr b`. Used in `NONote.recOn`. -/ def below (a b : NONote) : Prop := NFBelow a.1 (repr b) @@ -1241,9 +1228,8 @@ def below (a b : NONote) : Prop := def oadd (e : NONote) (n : ℕ+) (a : NONote) (h : below a e) : NONote := ⟨_, NF.oadd e.2 n h⟩ -/-- This is a recursor-like theorem for `NONote` suggesting an - inductive definition, which can't actually be defined this - way due to conflicting dependencies. -/ +/-- This is a recursor-like theorem for `NONote` suggesting an inductive definition, which can't +actually be defined this way due to conflicting dependencies. -/ @[elab_as_elim] def recOn {C : NONote → Sort*} (o : NONote) (H0 : C 0) (H1 : ∀ e n a h, C e → C a → C (oadd e n a h)) : C o := by diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index 2835fd286b3f3..411bdf03b41b2 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -11,15 +11,17 @@ import Mathlib.SetTheory.Ordinal.FixedPoint We define principal or indecomposable ordinals, and we prove the standard properties about them. ## Main definitions and results + * `Principal`: A principal or indecomposable ordinal under some binary operation. We include 0 and any other typically excluded edge cases for simplicity. -* `unbounded_principal`: Principal ordinals are unbounded. +* `not_bddAbove_principal`: Principal ordinals (under any operation) are unbounded. * `principal_add_iff_zero_or_omega0_opow`: The main characterization theorem for additive principal ordinals. * `principal_mul_iff_le_two_or_omega0_opow_opow`: The main characterization theorem for multiplicative principal ordinals. ## TODO + * Prove that exponential principal ordinals are 0, 1, 2, ω, or epsilon numbers, i.e. fixed points of `fun x ↦ ω ^ x`. -/ @@ -56,6 +58,15 @@ theorem principal_iff_principal_swap {o : Ordinal} : theorem not_principal_iff {o : Ordinal} : ¬ Principal op o ↔ ∃ a < o, ∃ b < o, o ≤ op a b := by simp [Principal] +theorem principal_iff_of_monotone {o : Ordinal} + (h₁ : ∀ a, Monotone (op a)) (h₂ : ∀ a, Monotone (Function.swap op a)): + Principal op o ↔ ∀ a < o, op a a < o := by + use fun h a ha => h ha ha + intro H a b ha hb + obtain hab | hba := le_or_lt a b + · exact (h₂ b hab).trans_lt <| H b hb + · exact (h₁ a hba.le).trans_lt <| H a ha + theorem principal_zero : Principal op 0 := fun a _ h => (Ordinal.not_lt_zero a h).elim @@ -87,11 +98,35 @@ end Arbitrary /-! ### Principal ordinals are unbounded -/ -#adaptation_note /-- 2024-04-23 -After https://github.com/leanprover/lean4/pull/3965, -we need to write `lt_blsub₂.{u}` twice below, -where previously the universe annotation was not necessary. -This appears to be correct behaviour, as `lt_blsub₂.{0}` also works. -/ +/-- We give an explicit construction for a principal ordinal larger or equal than `o`. -/ +private theorem principal_nfp_iSup (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : + Principal op (nfp (fun x ↦ ⨆ y : Set.Iio x ×ˢ Set.Iio x, succ (op y.1.1 y.1.2)) o) := by + intro a b ha hb + rw [lt_nfp] at * + obtain ⟨m, ha⟩ := ha + obtain ⟨n, hb⟩ := hb + obtain h | h := le_total + ((fun x ↦ ⨆ y : Set.Iio x ×ˢ Set.Iio x, succ (op y.1.1 y.1.2))^[m] o) + ((fun x ↦ ⨆ y : Set.Iio x ×ˢ Set.Iio x, succ (op y.1.1 y.1.2))^[n] o) + · use n + 1 + rw [Function.iterate_succ'] + apply (lt_succ _).trans_le + exact Ordinal.le_iSup (fun y : Set.Iio _ ×ˢ Set.Iio _ ↦ succ (op y.1.1 y.1.2)) + ⟨_, Set.mk_mem_prod (ha.trans_le h) hb⟩ + · use m + 1 + rw [Function.iterate_succ'] + apply (lt_succ _).trans_le + exact Ordinal.le_iSup (fun y : Set.Iio _ ×ˢ Set.Iio _ ↦ succ (op y.1.1 y.1.2)) + ⟨_, Set.mk_mem_prod ha (hb.trans_le h)⟩ + +/-- Principal ordinals under any operation are unbounded. -/ +theorem not_bddAbove_principal (op : Ordinal → Ordinal → Ordinal) : + ¬ BddAbove { o | Principal op o } := by + rintro ⟨a, ha⟩ + exact ((le_nfp _ _).trans (ha (principal_nfp_iSup op (succ a)))).not_lt (lt_succ a) + +set_option linter.deprecated false in +@[deprecated (since := "2024-10-11")] theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Principal op (nfp (fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b)) o) := by intro a b ha hb @@ -108,14 +143,14 @@ theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordin rw [Function.iterate_succ'] exact lt_blsub₂ (@fun a _ b _ => op a b) hm (hn.trans_le h) -/-- Principal ordinals under any operation form a ZFC proper class. -/ +set_option linter.deprecated false in +@[deprecated (since := "2024-10-11")] theorem unbounded_principal (op : Ordinal → Ordinal → Ordinal) : Set.Unbounded (· < ·) { o | Principal op o } := fun o => ⟨_, principal_nfp_blsub₂ op o, (le_nfp _ o).not_lt⟩ /-! #### Additive principal ordinals -/ - theorem principal_add_one : Principal (· + ·) 1 := principal_one_iff.2 <| zero_add 0 @@ -139,13 +174,13 @@ theorem principal_add_iff_add_left_eq_self {o : Ordinal} : Principal (· + ·) o ↔ ∀ a < o, a + o = o := by refine ⟨fun ho a hao => ?_, fun h a b hao hbo => ?_⟩ · cases' lt_or_le 1 o with ho₁ ho₁ - · exact op_eq_self_of_principal hao (add_isNormal a) ho (principal_add_isLimit ho₁ ho) + · exact op_eq_self_of_principal hao (isNormal_add_right a) ho (principal_add_isLimit ho₁ ho) · rcases le_one_iff.1 ho₁ with (rfl | rfl) · exact (Ordinal.not_lt_zero a hao).elim · rw [lt_one_iff_zero] at hao rw [hao, zero_add] · rw [← h a hao] - exact (add_isNormal a).strictMono hbo + exact (isNormal_add_right a).strictMono hbo theorem exists_lt_add_of_not_principal_add {a} (ha : ¬Principal (· + ·) a) : ∃ b < a, ∃ c < a, b + c = a := by @@ -158,7 +193,7 @@ theorem exists_lt_add_of_not_principal_add {a} (ha : ¬Principal (· + ·) a) : theorem principal_add_iff_add_lt_ne_self {a} : Principal (· + ·) a ↔ ∀ b < a, ∀ c < a, b + c ≠ a := - ⟨fun ha b hb c hc => (ha hb hc).ne, fun H => by + ⟨fun ha _ hb _ hc => (ha hb hc).ne, fun H => by by_contra! ha rcases exists_lt_add_of_not_principal_add ha with ⟨b, hb, c, hc, rfl⟩ exact (H b hb c hc).irrefl⟩ @@ -184,11 +219,11 @@ theorem add_omega0_opow {a b : Ordinal} (h : a < ω ^ b) : a + ω ^ b = ω ^ b : · rw [opow_zero, ← succ_zero, lt_succ_iff, Ordinal.le_zero] at h rw [h, zero_add] · rw [opow_succ] at h - rcases (lt_mul_of_limit omega0_isLimit).1 h with ⟨x, xo, ax⟩ + rcases (lt_mul_of_limit isLimit_omega0).1 h with ⟨x, xo, ax⟩ apply (add_le_add_right ax.le _).trans rw [opow_succ, ← mul_add, add_omega0 xo] · rcases (lt_opow_of_limit omega0_ne_zero l).1 h with ⟨x, xb, ax⟩ - apply (((add_isNormal a).trans <| opow_isNormal one_lt_omega0).limit_le l).2 + apply (((isNormal_add_right a).trans <| isNormal_opow one_lt_omega0).limit_le l).2 intro y yb calc a + ω ^ y ≤ a + ω ^ max x y := add_le_add_left (opow_le_opow_right omega0_pos (le_max_right x y)) _ @@ -218,7 +253,7 @@ theorem principal_add_iff_zero_or_omega0_opow {o : Ordinal} : fun ⟨b, e⟩ => e.symm ▸ fun a => add_omega0_opow⟩ have := H _ h have := lt_opow_succ_log_self one_lt_omega0 o - rw [opow_succ, lt_mul_of_limit omega0_isLimit] at this + rw [opow_succ, lt_mul_of_limit isLimit_omega0] at this rcases this with ⟨a, ao, h'⟩ rcases lt_omega0.1 ao with ⟨n, rfl⟩ clear ao @@ -265,7 +300,6 @@ theorem mul_principal_add_is_principal_add (a : Ordinal.{u}) {b : Ordinal.{u}} ( /-! #### Multiplicative principal ordinals -/ - theorem principal_mul_one : Principal (· * ·) 1 := by rw [principal_one_iff] exact zero_mul _ @@ -288,7 +322,7 @@ theorem principal_mul_of_le_two {o : Ordinal} (ho : o ≤ 2) : Principal (· * theorem principal_add_of_principal_mul {o : Ordinal} (ho : Principal (· * ·) o) (ho₂ : o ≠ 2) : Principal (· + ·) o := by cases' lt_or_gt_of_ne ho₂ with ho₁ ho₂ - · replace ho₁ : o < succ 1 := by simpa using ho₁ + · replace ho₁ : o < succ 1 := by rwa [succ_one] rw [lt_succ_iff] at ho₁ exact principal_add_of_le_one ho₁ · refine fun a b hao hbo => lt_of_le_of_lt ?_ (ho (max_lt hao hbo) ho₂) @@ -298,7 +332,7 @@ theorem principal_add_of_principal_mul {o : Ordinal} (ho : Principal (· * ·) o theorem principal_mul_isLimit {o : Ordinal.{u}} (ho₂ : 2 < o) (ho : Principal (· * ·) o) : o.IsLimit := - principal_add_isLimit ((lt_succ 1).trans (by simpa using ho₂)) + principal_add_isLimit ((lt_succ 1).trans (succ_one ▸ ho₂)) (principal_add_of_principal_mul ho (ne_of_gt ho₂)) theorem principal_mul_iff_mul_left_eq {o : Ordinal} : @@ -307,15 +341,15 @@ theorem principal_mul_iff_mul_left_eq {o : Ordinal} : · cases' le_or_gt o 2 with ho ho · convert one_mul o apply le_antisymm - · have : a < succ 1 := hao.trans_le (by simpa using ho) - rwa [lt_succ_iff] at this + · rw [← lt_succ_iff, succ_one] + exact hao.trans_le ho · rwa [← succ_le_iff, succ_zero] at ha₀ - · exact op_eq_self_of_principal hao (mul_isNormal ha₀) h (principal_mul_isLimit ho h) + · exact op_eq_self_of_principal hao (isNormal_mul_right ha₀) h (principal_mul_isLimit ho h) · rcases eq_or_ne a 0 with (rfl | ha) · dsimp only; rwa [zero_mul] rw [← Ordinal.pos_iff_ne_zero] at ha rw [← h a ha hao] - exact (mul_isNormal ha).strictMono hbo + exact (isNormal_mul_right ha).strictMono hbo theorem principal_mul_omega0 : Principal (· * ·) ω := fun a b ha hb => match a, b, lt_omega0.1 ha, lt_omega0.1 hb with @@ -337,11 +371,12 @@ theorem mul_lt_omega0_opow {a b c : Ordinal} (c0 : 0 < c) (ha : a < ω ^ c) (hb rcases zero_or_succ_or_limit c with (rfl | ⟨c, rfl⟩ | l) · exact (lt_irrefl _).elim c0 · rw [opow_succ] at ha - rcases ((mul_isNormal <| opow_pos _ omega0_pos).limit_lt omega0_isLimit).1 ha with ⟨n, hn, an⟩ + obtain ⟨n, hn, an⟩ := + ((isNormal_mul_right <| opow_pos _ omega0_pos).limit_lt isLimit_omega0).1 ha apply (mul_le_mul_right' (le_of_lt an) _).trans_lt rw [opow_succ, mul_assoc, mul_lt_mul_iff_left (opow_pos _ omega0_pos)] exact principal_mul_omega0 hn hb - · rcases ((opow_isNormal one_lt_omega0).limit_lt l).1 ha with ⟨x, hx, ax⟩ + · 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 @@ -356,7 +391,7 @@ theorem mul_omega0_opow_opow {a b : Ordinal} (a0 : 0 < a) (h : a < ω ^ ω ^ b) exact mul_omega0 a0 h · apply le_antisymm · obtain ⟨x, xb, ax⟩ := - (lt_opow_of_limit omega0_ne_zero (opow_isLimit_left omega0_isLimit b0)).1 h + (lt_opow_of_limit omega0_ne_zero (isLimit_opow_left isLimit_omega0 b0)).1 h apply (mul_le_mul_right' (le_of_lt ax) _).trans rw [← opow_add, add_omega0_opow xb] · conv_lhs => rw [← one_mul (ω ^ _)] @@ -408,9 +443,9 @@ theorem mul_eq_opow_log_succ {a b : Ordinal.{u}} (ha : a ≠ 0) (hb : Principal (hb₂ : 2 < b) : a * b = b ^ succ (log b a) := by apply le_antisymm · have hbl := principal_mul_isLimit hb₂ hb - rw [← IsNormal.bsup_eq.{u, u} (mul_isNormal (Ordinal.pos_iff_ne_zero.2 ha)) hbl, bsup_le_iff] + rw [← (isNormal_mul_right (Ordinal.pos_iff_ne_zero.2 ha)).bsup_eq hbl, bsup_le_iff] intro c hcb - have hb₁ : 1 < b := (lt_succ 1).trans (by rwa [succ_one]) + have hb₁ : 1 < b := one_lt_two.trans 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] @@ -422,7 +457,6 @@ theorem mul_eq_opow_log_succ {a b : Ordinal.{u}} (ha : a ≠ 0) (hb : Principal /-! #### Exponential principal ordinals -/ - theorem principal_opow_omega0 : Principal (· ^ ·) ω := fun a b ha hb => match a, b, lt_omega0.1 ha, lt_omega0.1 hb with | _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by @@ -433,7 +467,7 @@ theorem principal_opow_omega0 : Principal (· ^ ·) ω := fun a b ha hb => alias principal_opow_omega := principal_opow_omega0 theorem opow_omega0 {a : Ordinal} (a1 : 1 < a) (h : a < ω) : a ^ ω = ω := - ((opow_le_of_limit (one_le_iff_ne_zero.1 <| le_of_lt a1) omega0_isLimit).2 fun _ hb => + ((opow_le_of_limit (one_le_iff_ne_zero.1 <| le_of_lt a1) isLimit_omega0).2 fun _ hb => (principal_opow_omega0 h hb).le).antisymm (right_le_opow _ a1) diff --git a/Mathlib/SetTheory/Ordinal/Rank.lean b/Mathlib/SetTheory/Ordinal/Rank.lean new file mode 100644 index 0000000000000..e4b3808a56625 --- /dev/null +++ b/Mathlib/SetTheory/Ordinal/Rank.lean @@ -0,0 +1,127 @@ +/- +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.SetTheory.Ordinal.Arithmetic + +/-! +# Rank in a well-founded relation + +For `r` a well-founded relation, `IsWellFounded.rank r a` is recursively defined as the least +ordinal greater than the ranks of all elements below `a`. +-/ + +universe u + +variable {α : Type u} {a b : α} + +/-! ### Rank of an accessible value -/ + +namespace Acc + +variable {r : α → α → Prop} + +/-- The rank of an element `a` accessible under a relation `r` is defined recursively as the +smallest ordinal greater than the ranks of all elements below it (i.e. elements `b` such that +`r b a`). -/ +noncomputable def rank (h : Acc r a) : Ordinal.{u} := + Acc.recOn h fun a _h ih => ⨆ b : { b // r b a }, Order.succ (ih b b.2) + +theorem rank_eq (h : Acc r a) : + h.rank = ⨆ b : { b // r b a }, Order.succ (h.inv b.2).rank := by + change (Acc.intro a fun _ => h.inv).rank = _ + rfl + +/-- if `r a b` then the rank of `a` is less than the rank of `b`. -/ +theorem rank_lt_of_rel (hb : Acc r b) (h : r a b) : (hb.inv h).rank < hb.rank := + (Order.lt_succ _).trans_le <| by + rw [hb.rank_eq] + exact Ordinal.le_iSup _ (⟨a, h⟩ : {a // r a b}) + +theorem mem_range_rank_of_le {o : Ordinal} (ha : Acc r a) (ho : o ≤ ha.rank) : + ∃ (b : α) (hb : Acc r b), hb.rank = o := by + obtain rfl | ho := ho.eq_or_lt + · exact ⟨a, ha, rfl⟩ + · revert ho + refine ha.recOn fun a ha IH ho ↦ ?_ + rw [rank_eq, Ordinal.lt_iSup] at ho + obtain ⟨⟨b, hb⟩, ho⟩ := ho + rw [Order.lt_succ_iff] at ho + obtain rfl | ho := ho.eq_or_lt + exacts [⟨b, ha b hb, rfl⟩, IH _ hb ho] + +end Acc + +/-! ### Rank in a well-founded relation -/ + +namespace IsWellFounded + +variable (r : α → α → Prop) [hwf : IsWellFounded α r] + +/-- The rank of an element `a` under a well-founded relation `r` is defined recursively as the +smallest ordinal greater than the ranks of all elements below it (i.e. elements `b` such that +`r b a`). -/ +noncomputable def rank (a : α) : Ordinal.{u} := + (hwf.apply r a).rank + +theorem rank_eq (a : α) : rank r a = ⨆ b : { b // r b a }, Order.succ (rank r b) := + (hwf.apply r a).rank_eq + +variable {r : α → α → Prop} [hwf : IsWellFounded α r] + +theorem rank_lt_of_rel (h : r a b) : rank r a < rank r b := + Acc.rank_lt_of_rel _ h + +theorem mem_range_rank_of_le {o : Ordinal} (h : o ≤ rank r a) : o ∈ Set.range (rank r) := by + obtain ⟨b, hb, rfl⟩ := Acc.mem_range_rank_of_le (hwf.apply r a) h + exact ⟨b, rfl⟩ + +end IsWellFounded + +theorem WellFoundedLT.rank_strictMono [Preorder α] [WellFoundedLT α] : + StrictMono (IsWellFounded.rank (α := α) (· < ·)) := + fun _ _ => IsWellFounded.rank_lt_of_rel + +theorem WellFoundedGT.rank_strictAnti [Preorder α] [WellFoundedGT α] : + StrictAnti (IsWellFounded.rank (α := α) (· > ·)) := + fun _ _ a => IsWellFounded.rank_lt_of_rel a + +@[simp] +theorem IsWellFounded.rank_eq_typein (r) [IsWellOrder α r] : rank r = Ordinal.typein r := by + classical + letI := linearOrderOfSTO r + ext a + exact InitialSeg.eq (⟨(OrderEmbedding.ofStrictMono _ WellFoundedLT.rank_strictMono).ltEmbedding, + fun a b h ↦ mem_range_rank_of_le h.le⟩) (Ordinal.typein r) a + +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 +smallest ordinal greater than the ranks of all elements below it (i.e. elements `b` such that +`r b a`). -/ +@[deprecated IsWellFounded.rank (since := "2024-09-07")] +noncomputable def rank (a : α) : Ordinal.{u} := + (hwf.apply a).rank + +@[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 + +@[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 + +@[deprecated WellFoundedLT.rank_strictMono (since := "2024-09-07")] +theorem rank_strictMono [Preorder α] [WellFoundedLT α] : + StrictMono (rank <| @wellFounded_lt α _ _) := fun _ _ => rank_lt_of_rel _ + +@[deprecated WellFoundedGT.rank_strictAnti (since := "2024-09-07")] +theorem rank_strictAnti [Preorder α] [WellFoundedGT α] : + StrictAnti (rank <| @wellFounded_gt α _ _) := fun _ _ => rank_lt_of_rel wellFounded_gt + +end WellFounded diff --git a/Mathlib/SetTheory/Ordinal/Topology.lean b/Mathlib/SetTheory/Ordinal/Topology.lean index 73e5ab814961e..14986ed23a289 100644 --- a/Mathlib/SetTheory/Ordinal/Topology.lean +++ b/Mathlib/SetTheory/Ordinal/Topology.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ -import Mathlib.SetTheory.Ordinal.Arithmetic +import Mathlib.SetTheory.Ordinal.Enum import Mathlib.Tactic.TFAE import Mathlib.Topology.Order.Monotone @@ -219,27 +219,26 @@ theorem isNormal_iff_strictMono_and_continuous (f : Ordinal.{u} → Ordinal.{u}) ⟨_, toType_nonempty_iff_ne_zero.2 ho.1, typein (· < ·), fun i => h _ (typein_lt_self i), sup_typein_limit ho.2⟩ -theorem enumOrd_isNormal_iff_isClosed (hs : s.Unbounded (· < ·)) : +theorem enumOrd_isNormal_iff_isClosed (hs : ¬ BddAbove s) : IsNormal (enumOrd s) ↔ IsClosed s := by have Hs := enumOrd_strictMono hs refine ⟨fun h => isClosed_iff_iSup.2 fun {ι} hι f hf => ?_, fun h => (isNormal_iff_strictMono_limit _).2 ⟨Hs, fun a ha o H => ?_⟩⟩ - · let g : ι → Ordinal.{u} := fun i => (enumOrdOrderIso hs).symm ⟨_, hf i⟩ + · let g : ι → Ordinal.{u} := fun i => (enumOrdOrderIso s hs).symm ⟨_, hf i⟩ suffices enumOrd s (⨆ i, g i) = ⨆ i, f i by rw [← this] exact enumOrd_mem hs _ rw [IsNormal.map_iSup h g] congr ext x - change ((enumOrdOrderIso hs) _).val = f x + change (enumOrdOrderIso s hs _).val = f x rw [OrderIso.apply_symm_apply] · 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) - cases' enumOrd_surjective hs _ - (h ha.1 (fun b _ => enumOrd s b) fun b _ => enumOrd_mem hs b) with - b hb + obtain ⟨b, hb⟩ := enumOrd_surjective hs (h ha.1 (fun b _ => enumOrd s b) + fun b _ => enumOrd_mem hs b) rw [← hb] apply Hs.monotone by_contra! hba @@ -247,4 +246,140 @@ theorem enumOrd_isNormal_iff_isClosed (hs : s.Unbounded (· < ·)) : rw [hb] exact le_bsup.{u, u} _ _ (ha.2 _ hba) +open Set Filter Set.Notation + +/-- An ordinal is an accumulation point of a set of ordinals if it is positive and there +are elements in the set arbitrarily close to the ordinal from below. -/ +def IsAcc (o : Ordinal) (S : Set Ordinal) : Prop := + AccPt o (𝓟 S) + +/-- A set of ordinals is closed below an ordinal if it contains all of +its accumulation points below the ordinal. -/ +def IsClosedBelow (S : Set Ordinal) (o : Ordinal) : Prop := + IsClosed (Iio o ↓∩ S) + +theorem isAcc_iff (o : Ordinal) (S : Set Ordinal) : o.IsAcc S ↔ + o ≠ 0 ∧ ∀ p < o, (S ∩ Ioo p o).Nonempty := by + dsimp [IsAcc] + constructor + · rw [accPt_iff_nhds] + intro h + constructor + · rintro rfl + obtain ⟨x, hx⟩ := h (Iio 1) (Iio_mem_nhds zero_lt_one) + exact hx.2 <| lt_one_iff_zero.mp hx.1.1 + · intro p plt + obtain ⟨x, hx⟩ := h (Ioo p (o + 1)) <| Ioo_mem_nhds plt (lt_succ o) + use x + refine ⟨hx.1.2, ⟨hx.1.1.1, lt_of_le_of_ne ?_ hx.2⟩⟩ + have := hx.1.1.2 + rwa [← succ_eq_add_one, lt_succ_iff] at this + · rw [accPt_iff_nhds] + intro h u umem + obtain ⟨l, hl⟩ := exists_Ioc_subset_of_mem_nhds umem ⟨0, Ordinal.pos_iff_ne_zero.mpr h.1⟩ + obtain ⟨x, hx⟩ := h.2 l hl.1 + use x + exact ⟨⟨hl.2 ⟨hx.2.1, hx.2.2.le⟩, hx.1⟩, hx.2.2.ne⟩ + +theorem IsAcc.forall_lt {o : Ordinal} {S : Set Ordinal} (h : o.IsAcc S) : + ∀ p < o, (S ∩ Ioo p o).Nonempty := ((isAcc_iff _ _).mp h).2 + +theorem IsAcc.pos {o : Ordinal} {S : Set Ordinal} (h : o.IsAcc S) : + 0 < o := Ordinal.pos_iff_ne_zero.mpr ((isAcc_iff _ _).mp h).1 + +theorem IsAcc.isLimit {o : Ordinal} {S : Set Ordinal} (h : o.IsAcc S) : IsLimit o := by + rw [isAcc_iff] at h + refine isLimit_of_not_succ_of_ne_zero (fun ⟨x, hx⟩ ↦ ?_) h.1 + rcases h.2 x (lt_of_lt_of_le (lt_succ x) hx.symm.le) with ⟨p, hp⟩ + exact (hx.symm ▸ (succ_le_iff.mpr hp.2.1)).not_lt hp.2.2 + +theorem IsAcc.mono {o : Ordinal} {S T : Set Ordinal} (h : S ⊆ T) (ho : o.IsAcc S) : + o.IsAcc T := by + rw [isAcc_iff] at * + exact ⟨ho.1, fun p plto ↦ (ho.2 p plto).casesOn fun s hs ↦ ⟨s, h hs.1, hs.2⟩⟩ + +theorem IsAcc.inter_Ioo_nonempty {o : Ordinal} {S : Set Ordinal} (hS : o.IsAcc S) + {p : Ordinal} (hp : p < o) : (S ∩ Ioo p o).Nonempty := hS.forall_lt p hp + +-- todo: prove this for a general linear `SuccOrder`. +theorem accPt_subtype {p o : Ordinal} (S : Set Ordinal) (hpo : p < o) : + AccPt p (𝓟 S) ↔ AccPt ⟨p, hpo⟩ (𝓟 (Iio o ↓∩ S)) := by + constructor + · intro h + have plim : p.IsLimit := IsAcc.isLimit h + rw [accPt_iff_nhds] at * + intro u hu + obtain ⟨l, hl⟩ := exists_Ioc_subset_of_mem_nhds hu ⟨⟨0, plim.pos.trans hpo⟩, plim.pos⟩ + obtain ⟨x, hx⟩ := h (Ioo l (p + 1)) (Ioo_mem_nhds hl.1 (lt_add_one _)) + use ⟨x, lt_of_le_of_lt (lt_succ_iff.mp hx.1.1.2) hpo⟩ + refine ⟨?_, Subtype.coe_ne_coe.mp hx.2⟩ + exact ⟨hl.2 ⟨hx.1.1.1, by exact_mod_cast lt_succ_iff.mp hx.1.1.2⟩, hx.1.2⟩ + · intro h + rw [accPt_iff_nhds] at * + intro u hu + by_cases ho : p + 1 < o + · have ppos : p ≠ 0 := by + rintro rfl + rw [zero_add] at ho + specialize h (Iio ⟨1, ho⟩) (Iio_mem_nhds (Subtype.mk_lt_mk.mpr zero_lt_one)) + obtain ⟨_, h⟩ := h + exact h.2 <| Subtype.mk_eq_mk.mpr (lt_one_iff_zero.mp h.1.1) + have plim : p.IsLimit := by + contrapose! h + obtain ⟨q, hq⟩ := ((zero_or_succ_or_limit p).resolve_left ppos).resolve_right h + use (Ioo ⟨q, ((hq ▸ lt_succ q).trans hpo)⟩ ⟨p + 1, ho⟩) + constructor + · exact Ioo_mem_nhds (by simp only [hq, Subtype.mk_lt_mk, lt_succ]) (lt_succ p) + · intro _ mem + have aux1 := Subtype.mk_lt_mk.mp mem.1.1 + have aux2 := Subtype.mk_lt_mk.mp mem.1.2 + rw [Subtype.mk_eq_mk] + rw [hq] at aux2 ⊢ + exact ((succ_le_iff.mpr aux1).antisymm (le_of_lt_succ aux2)).symm + obtain ⟨l, hl⟩ := exists_Ioc_subset_of_mem_nhds hu ⟨0, plim.pos⟩ + obtain ⟨x, hx⟩ := h (Ioo ⟨l, hl.1.trans hpo⟩ ⟨p + 1, ho⟩) (Ioo_mem_nhds hl.1 (lt_add_one p)) + use x + exact ⟨⟨hl.2 ⟨hx.1.1.1, lt_succ_iff.mp hx.1.1.2⟩, hx.1.2⟩, fun h ↦ hx.2 (SetCoe.ext h)⟩ + have hp : o = p + 1 := (le_succ_iff_eq_or_le.mp (le_of_not_lt ho)).resolve_right + (not_le_of_lt hpo) + have ppos : p ≠ 0 := by + rintro rfl + obtain ⟨x, hx⟩ := h Set.univ univ_mem + have : ↑x < o := x.2 + simp_rw [hp, zero_add, lt_one_iff_zero] at this + exact hx.2 (SetCoe.ext this) + obtain ⟨l, hl⟩ := exists_Ioc_subset_of_mem_nhds hu ⟨0, Ordinal.pos_iff_ne_zero.mpr ppos⟩ + obtain ⟨x, hx⟩ := h (Ioi ⟨l, hl.1.trans hpo⟩) (Ioi_mem_nhds hl.1) + use x + refine ⟨⟨hl.2 ⟨hx.1.1, ?_⟩, hx.1.2⟩, fun h ↦ hx.2 (SetCoe.ext h)⟩ + rw [← lt_add_one_iff, ← hp] + exact x.2 + +theorem isClosedBelow_iff {S : Set Ordinal} {o : Ordinal} : IsClosedBelow S o ↔ + ∀ p < o, IsAcc p S → p ∈ S := by + dsimp [IsClosedBelow] + constructor + · intro h p plto hp + have : AccPt ⟨p, plto⟩ (𝓟 (Iio o ↓∩ S)) := (accPt_subtype _ _).mp hp + rw [isClosed_iff_clusterPt] at h + exact h ⟨p, plto⟩ this.clusterPt + · intro h + rw [isClosed_iff_clusterPt] + intro r hr + match clusterPt_principal.mp hr with + | .inl h => exact h + | .inr h' => exact h r.1 r.2 <| (accPt_subtype _ _).mpr h' + +alias ⟨IsClosedBelow.forall_lt, _⟩ := isClosedBelow_iff + +theorem IsClosedBelow.sInter {o : Ordinal} {S : Set (Set Ordinal)} + (h : ∀ C ∈ S, IsClosedBelow C o) : IsClosedBelow (⋂₀ S) o := by + rw [isClosedBelow_iff] + intro p plto pAcc C CmemS + exact (h C CmemS).forall_lt p plto (pAcc.mono (sInter_subset_of_mem CmemS)) + +theorem IsClosedBelow.iInter {ι : Type u} {f : ι → Set Ordinal} {o : Ordinal} + (h : ∀ i, IsClosedBelow (f i) o) : IsClosedBelow (⋂ i, f i) o := + IsClosedBelow.sInter fun _ ⟨i, hi⟩ ↦ hi ▸ (h i) + end Ordinal diff --git a/Mathlib/SetTheory/Surreal/Dyadic.lean b/Mathlib/SetTheory/Surreal/Dyadic.lean index f47d76361786e..66e64a35705b5 100644 --- a/Mathlib/SetTheory/Surreal/Dyadic.lean +++ b/Mathlib/SetTheory/Surreal/Dyadic.lean @@ -5,10 +5,12 @@ Authors: Apurva Nakade -/ import Mathlib.Algebra.Algebra.Defs import Mathlib.Algebra.Order.Group.Basic -import Mathlib.Algebra.Order.Ring.Basic -import Mathlib.RingTheory.Localization.Basic +import Mathlib.GroupTheory.MonoidLocalization.Away +import Mathlib.RingTheory.Localization.Defs import Mathlib.SetTheory.Game.Birthday import Mathlib.SetTheory.Surreal.Multiplication +import Mathlib.Tactic.Linarith +import Mathlib.Algebra.Ring.Regular /-! # Dyadic numbers diff --git a/Mathlib/SetTheory/ZFC/Basic.lean b/Mathlib/SetTheory/ZFC/Basic.lean index 137369f0640e1..788bd0c5e0138 100644 --- a/Mathlib/SetTheory/ZFC/Basic.lean +++ b/Mathlib/SetTheory/ZFC/Basic.lean @@ -250,20 +250,17 @@ private theorem mem_wf_aux : ∀ {x y : PSet.{u}}, Equiv x y → Acc (· ∈ ·) theorem mem_wf : @WellFounded PSet (· ∈ ·) := ⟨fun x => mem_wf_aux <| Equiv.refl x⟩ +instance : IsWellFounded PSet (· ∈ ·) := + ⟨mem_wf⟩ + instance : WellFoundedRelation PSet := ⟨_, mem_wf⟩ -instance : IsAsymm PSet (· ∈ ·) := - mem_wf.isAsymm - -instance : IsIrrefl PSet (· ∈ ·) := - mem_wf.isIrrefl - theorem mem_asymm {x y : PSet} : x ∈ y → y ∉ x := - asymm (r := (· ∈ ·)) + asymm_of (· ∈ ·) theorem mem_irrefl (x : PSet) : x ∉ x := - irrefl (r := (· ∈ ·)) x + irrefl_of (· ∈ ·) x /-- Convert a pre-set to a `Set` of pre-sets. -/ def toSet (u : PSet.{u}) : Set PSet.{u} := @@ -367,7 +364,7 @@ theorem mem_insert_of_mem {y z : PSet} (x) (h : z ∈ y) : z ∈ insert x y := @[simp] theorem mem_singleton {x y : PSet} : x ∈ ({y} : PSet) ↔ Equiv x y := mem_insert_iff.trans - ⟨fun o => Or.rec (fun h => h) (fun n => absurd n (not_mem_empty _)) o, Or.inl⟩ + ⟨fun o => Or.rec id (fun n => absurd n (not_mem_empty _)) o, Or.inl⟩ theorem mem_pair {x y z : PSet} : x ∈ ({y, z} : PSet) ↔ Equiv x y ∨ Equiv x z := by simp @@ -1017,21 +1014,17 @@ theorem mem_wf : @WellFounded ZFSet (· ∈ ·) := theorem inductionOn {p : ZFSet → Prop} (x) (h : ∀ x, (∀ y ∈ x, p y) → p x) : p x := mem_wf.induction x h +instance : IsWellFounded ZFSet (· ∈ ·) := + ⟨mem_wf⟩ + instance : WellFoundedRelation ZFSet := ⟨_, mem_wf⟩ -instance : IsAsymm ZFSet (· ∈ ·) := - mem_wf.isAsymm - --- Porting note: this can't be inferred automatically for some reason. -instance : IsIrrefl ZFSet (· ∈ ·) := - mem_wf.isIrrefl - theorem mem_asymm {x y : ZFSet} : x ∈ y → y ∉ x := - asymm (r := (· ∈ ·)) + asymm_of (· ∈ ·) theorem mem_irrefl (x : ZFSet) : x ∉ x := - irrefl (r := (· ∈ ·)) x + irrefl_of (· ∈ ·) x theorem regularity (x : ZFSet.{u}) (h : x ≠ ∅) : ∃ y ∈ x, x ∩ y = ∅ := by_contradiction fun ne => @@ -1310,21 +1303,17 @@ theorem mem_wf : @WellFounded Class.{u} (· ∈ ·) := rintro B ⟨x, rfl, _⟩ exact H x⟩ +instance : IsWellFounded Class (· ∈ ·) := + ⟨mem_wf⟩ + instance : WellFoundedRelation Class := ⟨_, mem_wf⟩ -instance : IsAsymm Class (· ∈ ·) := - mem_wf.isAsymm - --- Porting note: this can't be inferred automatically for some reason. -instance : IsIrrefl Class (· ∈ ·) := - mem_wf.isIrrefl - theorem mem_asymm {x y : Class} : x ∈ y → y ∉ x := - asymm (r := (· ∈ ·)) + asymm_of (· ∈ ·) theorem mem_irrefl (x : Class) : x ∉ x := - irrefl (r := (· ∈ ·)) x + irrefl_of (· ∈ ·) x /-- **There is no universal set.** This is stated as `univ ∉ univ`, meaning that `univ` (the class of all sets) is proper (does not @@ -1564,7 +1553,7 @@ private lemma toSet_equiv_aux {s : Set ZFSet.{u}} (hs : Small.{u} s) : @[simps apply_coe] noncomputable def toSet_equiv : ZFSet.{u} ≃ {s : Set ZFSet.{u} // Small.{u, u+1} s} where toFun x := ⟨x.toSet, x.small_toSet⟩ - invFun := fun ⟨s, h⟩ ↦ mk <| PSet.mk (Shrink s) fun x ↦ ((equivShrink.{u, u+1} s).symm x).1.out + invFun := fun ⟨s, _⟩ ↦ mk <| PSet.mk (Shrink s) fun x ↦ ((equivShrink.{u, u+1} s).symm x).1.out left_inv := Function.rightInverse_of_injective_of_leftInverse (by intros x y; simp) fun s ↦ Subtype.coe_injective <| toSet_equiv_aux s.2 right_inv s := Subtype.coe_injective <| toSet_equiv_aux s.2 diff --git a/Mathlib/SetTheory/ZFC/Ordinal.lean b/Mathlib/SetTheory/ZFC/Ordinal.lean index fc7b53d80cedd..56dbcfb274d7a 100644 --- a/Mathlib/SetTheory/ZFC/Ordinal.lean +++ b/Mathlib/SetTheory/ZFC/Ordinal.lean @@ -80,7 +80,7 @@ protected theorem IsTransitive.powerset (h : x.IsTransitive) : (powerset x).IsTr theorem isTransitive_iff_sUnion_subset : x.IsTransitive ↔ (⋃₀ x : ZFSet) ⊆ x := ⟨fun h y hy => by rcases mem_sUnion.1 hy with ⟨z, hz, hz'⟩ - exact h.mem_trans hz' hz, fun H y hy z hz => H <| mem_sUnion_of_mem hz hy⟩ + exact h.mem_trans hz' hz, fun H _ hy _ hz => H <| mem_sUnion_of_mem hz hy⟩ alias ⟨IsTransitive.sUnion_subset, _⟩ := isTransitive_iff_sUnion_subset diff --git a/Mathlib/SetTheory/ZFC/Rank.lean b/Mathlib/SetTheory/ZFC/Rank.lean index 2cecc412eaa35..9ab8f265dc4f9 100644 --- a/Mathlib/SetTheory/ZFC/Rank.lean +++ b/Mathlib/SetTheory/ZFC/Rank.lean @@ -3,14 +3,14 @@ Copyright (c) 2024 Dexin Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Dexin Zhang -/ -import Mathlib.SetTheory.Ordinal.Arithmetic +import Mathlib.SetTheory.Ordinal.Rank import Mathlib.SetTheory.ZFC.Basic /-! # Ordinal ranks of PSet and ZFSet In this file, we define the ordinal ranks of `PSet` and `ZFSet`. These ranks are the same as -`WellFounded.rank` over `∈`, but are defined in a way that the universe levels of ranks are the +`IsWellFounded.rank` over `∈`, but are defined in a way that the universe levels of ranks are the same as the indexing types. ## Definitions @@ -109,15 +109,15 @@ theorem le_succ_rank_sUnion : rank x ≤ succ (rank (⋃₀ x)) := by rw [mem_sUnion] exists z -/-- `PSet.rank` is equal to the `WellFounded.rank` over `∈`. -/ -theorem rank_eq_wfRank : lift.{u + 1, u} (rank x) = mem_wf.rank x := by +/-- `PSet.rank` is equal to the `IsWellFounded.rank` over `∈`. -/ +theorem rank_eq_wfRank : lift.{u + 1, u} (rank x) = IsWellFounded.rank (α := PSet) (· ∈ ·) x := by induction' x using mem_wf.induction with x ih - rw [mem_wf.rank_eq] + rw [IsWellFounded.rank_eq] simp_rw [← fun y : { y // y ∈ x } => ih y y.2] - apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le.{u + 1, u} _) <;> intro h + apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le _) <;> intro h · rw [lt_lift_iff] - rintro ⟨o, rfl, h⟩ - simpa [Ordinal.lt_iSup.{u + 1, u}] using lt_rank_iff.1 h + rintro ⟨o, h, rfl⟩ + simpa [Ordinal.lt_iSup] using lt_rank_iff.1 h · simpa using rank_lt_of_mem h.2 end PSet @@ -195,15 +195,15 @@ theorem rank_range {α : Type u} {f : α → ZFSet.{max u v}} : · simpa [rank_le_iff] using lt_lsub _ · simp [rank_lt_of_mem] -/-- `ZFSet.rank` is equal to the `WellFounded.rank` over `∈`. -/ -theorem rank_eq_wfRank : lift.{u + 1, u} (rank x) = mem_wf.rank x := by +/-- `ZFSet.rank` is equal to the `IsWellFounded.rank` over `∈`. -/ +theorem rank_eq_wfRank : lift.{u + 1, u} (rank x) = IsWellFounded.rank (α := ZFSet) (· ∈ ·) x := by induction' x using inductionOn with x ih - rw [mem_wf.rank_eq] + rw [IsWellFounded.rank_eq] simp_rw [← fun y : { y // y ∈ x } => ih y y.2] - apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le.{u + 1, u} _) <;> intro h + apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le _) <;> intro h · rw [lt_lift_iff] - rintro ⟨o, rfl, h⟩ - simpa [Ordinal.lt_iSup.{u + 1, u}] using lt_rank_iff.1 h + rintro ⟨o, h, rfl⟩ + simpa [Ordinal.lt_iSup] using lt_rank_iff.1 h · simpa using rank_lt_of_mem h.2 end ZFSet diff --git a/Mathlib/Std/Data/HashMap.lean b/Mathlib/Std/Data/HashMap.lean index 19199a7f7e67b..5226d253de305 100644 --- a/Mathlib/Std/Data/HashMap.lean +++ b/Mathlib/Std/Data/HashMap.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Std.Data.HashMap.Basic +import Mathlib.Init /-! # Convenience functions for hash maps diff --git a/Mathlib/Tactic.lean b/Mathlib/Tactic.lean index a7379f3dc58f9..a3fe4d46b7e75 100644 --- a/Mathlib/Tactic.lean +++ b/Mathlib/Tactic.lean @@ -62,6 +62,7 @@ import Mathlib.Tactic.Contrapose import Mathlib.Tactic.Conv import Mathlib.Tactic.Convert import Mathlib.Tactic.Core +import Mathlib.Tactic.DeclarationNames import Mathlib.Tactic.DefEqTransformations import Mathlib.Tactic.DeprecateMe import Mathlib.Tactic.DeriveFintype @@ -81,6 +82,8 @@ import Mathlib.Tactic.FailIfNoProgress import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.FinCases import Mathlib.Tactic.Find +import Mathlib.Tactic.Finiteness +import Mathlib.Tactic.Finiteness.Attr import Mathlib.Tactic.FunProp import Mathlib.Tactic.FunProp.Attr import Mathlib.Tactic.FunProp.ContDiff @@ -140,9 +143,12 @@ import Mathlib.Tactic.Linter.FlexibleLinter import Mathlib.Tactic.Linter.GlobalAttributeIn import Mathlib.Tactic.Linter.HashCommandLinter import Mathlib.Tactic.Linter.HaveLetLinter +import Mathlib.Tactic.Linter.Header import Mathlib.Tactic.Linter.Lint import Mathlib.Tactic.Linter.MinImports +import Mathlib.Tactic.Linter.Multigoal import Mathlib.Tactic.Linter.OldObtain +import Mathlib.Tactic.Linter.PPRoundtrip import Mathlib.Tactic.Linter.RefineLinter import Mathlib.Tactic.Linter.Style import Mathlib.Tactic.Linter.TextBased @@ -176,6 +182,7 @@ import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.NatSqrt import Mathlib.Tactic.NormNum.OfScientific import Mathlib.Tactic.NormNum.Pow +import Mathlib.Tactic.NormNum.PowMod import Mathlib.Tactic.NormNum.Prime import Mathlib.Tactic.NormNum.Result import Mathlib.Tactic.NthRewrite @@ -200,7 +207,6 @@ import Mathlib.Tactic.ReduceModChar import Mathlib.Tactic.ReduceModChar.Ext import Mathlib.Tactic.Relation.Rfl import Mathlib.Tactic.Relation.Symm -import Mathlib.Tactic.Relation.Trans import Mathlib.Tactic.Rename import Mathlib.Tactic.RenameBVar import Mathlib.Tactic.Replace @@ -208,6 +214,7 @@ import Mathlib.Tactic.RewriteSearch import Mathlib.Tactic.Rify import Mathlib.Tactic.Ring import Mathlib.Tactic.Ring.Basic +import Mathlib.Tactic.Ring.Compare import Mathlib.Tactic.Ring.PNat import Mathlib.Tactic.Ring.RingNF import Mathlib.Tactic.Sat.FromLRAT diff --git a/Mathlib/Tactic/AdaptationNote.lean b/Mathlib/Tactic/AdaptationNote.lean index d8700ceceb3c2..76c6b0df66e79 100644 --- a/Mathlib/Tactic/AdaptationNote.lean +++ b/Mathlib/Tactic/AdaptationNote.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Mathlib.Init -import Lean +import Lean.Meta.Tactic.TryThis /-! # Adaptation notes diff --git a/Mathlib/Tactic/Algebraize.lean b/Mathlib/Tactic/Algebraize.lean index 74c3a9eaf8230..1218a802e04ae 100644 --- a/Mathlib/Tactic/Algebraize.lean +++ b/Mathlib/Tactic/Algebraize.lean @@ -38,10 +38,12 @@ specified declaration should be one of the following: 1. An inductive type (i.e. the `Algebra` property itself), in this case it is assumed that the `RingHom` and the `Algebra` property are definitionally the same, and the tactic will construct the -`Algebra` property by giving the `RingHom` property as a term. -2. A constructor for the `Algebra` property. In this case it is assumed that the `RingHom` property -is the last argument of the constructor, and that no other explicit argument is needed. The tactic -then constructs the `Algebra` property by applying the constructor to the `RingHom` property. +`Algebra` property by giving the `RingHom` property as a term. Due to how this is peformed, we also +need to assume that the `Algebra` property can be constructed only from the homomorphism, so it can +not have any other explicit arguments. +2. A lemma (or constructor) proving the `Algebra` property from the `RingHom` property. In this case +it is assumed that the `RingHom` property is the final argument, and that no other explicit argument +is needed. The tactic then constructs the `Algebra` property by applying the lemma or constructor. Here are three examples of properties tagged with the `algebraize` attribute: ``` @@ -98,9 +100,9 @@ There are two cases for what declaration corresponding to this `Name` can be. 1. An inductive type (i.e. the `Algebra` property itself), in this case it is assumed that the `RingHom` and the `Algebra` property are definitionally the same, and the tactic will construct the `Algebra` property by giving the `RingHom` property as a term. -2. A constructor for the `Algebra` property. In this case it is assumed that the `RingHom` property -is the last argument of the constructor, and that no other explicit argument is needed. The tactic -then constructs the `Algebra` property by applying the constructor to the `RingHom` property. +2. A lemma (or constructor) proving the `Algebra` property from the `RingHom` property. In this case +it is assumed that the `RingHom` property is the final argument, and that no other explicit argument +is needed. The tactic then constructs the `Algebra` property by applying the lemma or constructor. Finally, if no argument is provided to the `algebraize` attribute, it is assumed that the tagged declaration has name `RingHom.Property` and that the corresponding `Algebra` property has name @@ -171,7 +173,8 @@ def addProperties (t : Array Expr) : TacticM Unit := withMainContext do let (nm, args) := decl.type.getAppFnArgs -- Check if the type of the current hypothesis has been tagged with the `algebraize` attribute match Attr.algebraizeAttr.getParam? (← getEnv) nm with - -- If it has, `p` will be the name of the corresponding `Algebra` property (or a constructor) + -- If it has, `p` will either be the name of the corresponding `Algebra` property, or a + -- lemma/constructor. | some p => -- The last argument of the `RingHom` property is assumed to be `f` let f := args[args.size - 1]! @@ -184,42 +187,27 @@ def addProperties (t : Array Expr) : TacticM Unit := withMainContext do /- If the attribute points to the corresponding `Algebra` property itself, we assume that it is definitionally the same as the `RingHom` property. Then, we just need to construct its type and the local declaration will already give a valid term. -/ - match cinfo with - | .inductInfo _ => + if cinfo.isInductive then let pargs := pargs.set! 0 args[0]! let pargs := pargs.set! 1 args[1]! let tp ← mkAppOptM p pargs -- This should be the type `Algebra.Property A B` unless (← synthInstance? tp).isSome do liftMetaTactic fun mvarid => do let nm ← mkFreshBinderNameForTactic `algebraizeInst - let mvar ← mvarid.define nm tp decl.toExpr - let (_, mvar) ← mvar.intro1P + let (_, mvar) ← mvarid.note nm decl.toExpr tp return [mvar] - /- Otherwise, the attribute points to a constructor of the `Algebra` property. In this case, - we assume that the `RingHom` property is the last argument of the constructor (and that - this is all we need to supply explicitly). -/ - | .ctorInfo ctor => - -- construct the desired value + /- Otherwise, the attribute points to a lemma or a constructor for the `Algebra` property. + In this case, we assume that the `RingHom` property is the last argument of the lemma or + constructor (and that this is all we need to supply explicitly). -/ + else let pargs := pargs.set! (n - 1) decl.toExpr let val ← mkAppOptM p pargs - - -- construct the expected type - let alg ← mkAppOptM ``Algebra #[args[0]!, args[1]!, none, none] - let algInst := (← synthInstance? alg) - let mut argsType := Array.mkArray (ctor.numParams) (none : Option Expr) - argsType := argsType.set! 0 args[0]! - argsType := argsType.set! 1 args[1]! - argsType := argsType.set! (ctor.numParams - 1) algInst - let tp := ← mkAppOptM ctor.induct argsType - + let tp ← inferType val unless (← synthInstance? tp).isSome do liftMetaTactic fun mvarid => do let nm ← mkFreshBinderNameForTactic `algebraizeInst - let mvar ← mvarid.define nm tp val - let (_, mvar) ← mvar.intro1P + let (_, mvar) ← mvarid.note nm val return [mvar] - | _ => logError s!"bad argument to `algebraize` attribute: {p}. \ - Only supporting inductive types or constructors." | none => return /-- Configuration for `algebraize`. -/ @@ -256,7 +244,7 @@ so in other words it only adds `Algebra` and `IsScalarTower` instances. -/ syntax "algebraize" (ppSpace config)? (ppSpace algebraizeTermSeq)? : tactic elab_rules : tactic - | `(tactic| algebraize $[$config]? $args) => do + | `(tactic| algebraize $[$config]? $args) => withMainContext do let cfg ← elabAlgebraizeConfig (mkOptionalNode config) let t ← match args with | `(algebraizeTermSeq| [$rs,*]) => rs.getElems.mapM fun i => Term.elabTerm i none diff --git a/Mathlib/Tactic/Bound.lean b/Mathlib/Tactic/Bound.lean index 47591bb967e5d..58f217d6fa30f 100644 --- a/Mathlib/Tactic/Bound.lean +++ b/Mathlib/Tactic/Bound.lean @@ -112,7 +112,7 @@ lemma Nat.cast_pos_of_pos {R : Type} [OrderedSemiring R] [Nontrivial R] {n : ℕ Nat.cast_pos.mpr lemma Nat.one_le_cast_of_le {α : Type} [AddCommMonoidWithOne α] [PartialOrder α] - [CovariantClass α α (fun (x y : α) => x + y) fun (x y : α) => x ≤ y] [ZeroLEOneClass α] + [AddLeftMono α] [ZeroLEOneClass α] [CharZero α] {n : ℕ} : 1 ≤ n → 1 ≤ (n : α) := Nat.one_le_cast.mpr diff --git a/Mathlib/Tactic/CC/Lemmas.lean b/Mathlib/Tactic/CC/Lemmas.lean index 12348c1e7b4cb..1ebda77fc703d 100644 --- a/Mathlib/Tactic/CC/Lemmas.lean +++ b/Mathlib/Tactic/CC/Lemmas.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ +import Mathlib.Init + /-! Lemmas use by the congruence closure module -/ namespace Mathlib.Tactic.CC diff --git a/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean b/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean index 2e58492c79e90..7104020508294 100644 --- a/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean +++ b/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean @@ -27,7 +27,7 @@ open CategoryTheory CategoryTheory.FreeBicategory open scoped Bicategory -variable {B : Type u} [Bicategory.{w, v} B] {a b c d e : B} +variable {B : Type u} [Bicategory.{w, v} B] {a b c d : B} namespace Mathlib.Tactic.BicategoryCoherence diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean b/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean index 52e90c1260e65..4fb144875c348 100644 --- a/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean +++ b/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean @@ -3,7 +3,8 @@ Copyright (c) 2024 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ -import Lean +import Lean.Meta.Basic +import Mathlib.Init /-! # Datatypes for bicategory like structures diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean b/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean index 63738eff6d0a9..3fec5a6a72318 100644 --- a/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean +++ b/Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ +import Lean.Meta.AppBuilder import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes /-! @@ -256,7 +257,7 @@ structure Eval.Result where proof : Expr deriving Inhabited -variable {m : Type → Type} [Monad m] +variable {m : Type → Type} /-- Evaluate the expression `α ≫ β`. -/ class MkEvalComp (m : Type → Type) where @@ -344,7 +345,7 @@ class MkEval (m : Type → Type) extends mkEvalMonoidalComp (η θ : Mor₂) (α : Structural) (η' θ' αθ ηαθ : NormalExpr) (e_η e_θ e_αθ e_ηαθ : Expr) : m Expr -variable {ρ : Type} [Context ρ] +variable {ρ : Type} variable [MonadMor₂Iso (CoherenceM ρ)] [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)] open MkEvalComp MonadMor₂Iso MonadNormalExpr @@ -501,12 +502,11 @@ end open MkEval -variable {ρ : Type} [Context ρ] +variable {ρ : Type} [MonadMor₁ (CoherenceM ρ)] [MonadMor₂Iso (CoherenceM ρ)] [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)] [MonadMor₂ (CoherenceM ρ)] - [MkMor₂ (CoherenceM ρ)] /-- Trace the proof of the normalization. -/ def traceProof (nm : Name) (result : Expr) : CoherenceM ρ Unit := do diff --git a/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean index fb4cf07da5033..a8b1adeae88c4 100644 --- a/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean +++ b/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Yuma Mizuno. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yuma Mizuno -/ +import Lean.Meta.Tactic.Apply import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes /-! diff --git a/Mathlib/Tactic/CategoryTheory/Reassoc.lean b/Mathlib/Tactic/CategoryTheory/Reassoc.lean index f76eba34bf8a9..7861b38db0151 100644 --- a/Mathlib/Tactic/CategoryTheory/Reassoc.lean +++ b/Mathlib/Tactic/CategoryTheory/Reassoc.lean @@ -63,7 +63,7 @@ that are already right associated. Note that if you want both the lemma and the reassociated lemma to be `simp` lemmas, you should tag the lemma `@[reassoc (attr := simp)]`. The variant `@[simp, reassoc]` on a lemma `F` will tag `F` with `@[simp]`, -but not `F_apply` (this is sometimes useful). +but not `F_assoc` (this is sometimes useful). -/ syntax (name := reassoc) "reassoc" (" (" &"attr" ":=" Parser.Term.attrInstance,* ")")? : attr diff --git a/Mathlib/Tactic/CategoryTheory/Slice.lean b/Mathlib/Tactic/CategoryTheory/Slice.lean index f3f88410158c6..d0c2105619b6e 100644 --- a/Mathlib/Tactic/CategoryTheory/Slice.lean +++ b/Mathlib/Tactic/CategoryTheory/Slice.lean @@ -2,7 +2,6 @@ Copyright (c) 2018 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison - -/ import Mathlib.CategoryTheory.Category.Basic import Mathlib.Tactic.Conv diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean index f9c7a25eb782c..c864e4fc60f26 100644 --- a/Mathlib/Tactic/Common.lean +++ b/Mathlib/Tactic/Common.lean @@ -79,7 +79,6 @@ import Mathlib.Tactic.PushNeg import Mathlib.Tactic.RSuffices import Mathlib.Tactic.Recover import Mathlib.Tactic.Relation.Rfl -import Mathlib.Tactic.Relation.Trans import Mathlib.Tactic.Rename import Mathlib.Tactic.RenameBVar import Mathlib.Tactic.Says diff --git a/Mathlib/Tactic/DeclarationNames.lean b/Mathlib/Tactic/DeclarationNames.lean new file mode 100644 index 0000000000000..c9cb53158e7bc --- /dev/null +++ b/Mathlib/Tactic/DeclarationNames.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2024 Moritz Firsching. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa, Moritz Firsching +-/ + +import Lean.DeclarationRange +import Lean.ResolveName +-- transitively imported in Mathlib.Init + +/-! +This file contains functions that are used by multiple linters. +-/ + +open Lean Parser Elab Command Meta +namespace Mathlib.Linter + +/-- +If `pos` is a `String.Pos`, then `getNamesFrom pos` returns the array of identifiers +for the names of the declarations whose syntax begins in position at least `pos`. +-/ +def getNamesFrom {m} [Monad m] [MonadEnv m] [MonadFileMap m] (pos : String.Pos) : + m (Array Syntax) := do + let drs := declRangeExt.getState (← getEnv) + let fm ← getFileMap + let mut nms := #[] + for (nm, rgs) in drs do + if pos ≤ fm.ofPosition rgs.range.pos then + let ofPos1 := fm.ofPosition rgs.selectionRange.pos + let ofPos2 := fm.ofPosition rgs.selectionRange.endPos + nms := nms.push (mkIdentFrom (.ofRange ⟨ofPos1, ofPos2⟩) nm) + return nms + +/-- +If `stx` is a syntax node for an `export` statement, then `getAliasSyntax stx` returns the array of +identifiers with the "exported" names. +-/ +def getAliasSyntax {m} [Monad m] [MonadResolveName m] (stx : Syntax) : m (Array Syntax) := do + let mut aliases := #[] + if let `(export $_ ($ids*)) := stx then + let currNamespace ← getCurrNamespace + for idStx in ids do + let id := idStx.getId + aliases := aliases.push + (mkIdentFrom (.ofRange (idStx.raw.getRange?.getD default)) (currNamespace ++ id)) + return aliases diff --git a/Mathlib/Tactic/DeprecateMe.lean b/Mathlib/Tactic/DeprecateMe.lean index 3fb56313bec00..b84b97f0b4c2c 100644 --- a/Mathlib/Tactic/DeprecateMe.lean +++ b/Mathlib/Tactic/DeprecateMe.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:(str)? 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/DeriveToExpr.lean b/Mathlib/Tactic/DeriveToExpr.lean index a7b7b1a781888..17641b54aaa81 100644 --- a/Mathlib/Tactic/DeriveToExpr.lean +++ b/Mathlib/Tactic/DeriveToExpr.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Lean.Elab.Deriving.Ord import Mathlib.Tactic.ToLevel /-! diff --git a/Mathlib/Tactic/FBinop.lean b/Mathlib/Tactic/FBinop.lean index 01903971c62dd..c5588d2133cf5 100644 --- a/Mathlib/Tactic/FBinop.lean +++ b/Mathlib/Tactic/FBinop.lean @@ -3,6 +3,8 @@ Copyright (c) 2023 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Lean.Elab.App +import Lean.Elab.BuiltinNotation import Mathlib.Tactic.ToExpr /-! # Elaborator for functorial binary operators diff --git a/Mathlib/Tactic/FieldSimp.lean b/Mathlib/Tactic/FieldSimp.lean index b02abb4f47983..af1f591fc5fcb 100644 --- a/Mathlib/Tactic/FieldSimp.lean +++ b/Mathlib/Tactic/FieldSimp.lean @@ -6,7 +6,7 @@ Authors: Sébastien Gouëzel, David Renshaw import Lean.Elab.Tactic.Basic import Lean.Meta.Tactic.Simp.Main -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Basic import Mathlib.Tactic.Positivity.Core import Mathlib.Tactic.NormNum.Core import Mathlib.Util.DischargerAsTactic diff --git a/Mathlib/Tactic/Finiteness.lean b/Mathlib/Tactic/Finiteness.lean new file mode 100644 index 0000000000000..2fbf21e35dea8 --- /dev/null +++ b/Mathlib/Tactic/Finiteness.lean @@ -0,0 +1,64 @@ +/- +Copyright (c) 2023 Heather Macbeth. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Heather Macbeth +-/ +import Mathlib.Tactic.Positivity.Core + +/-! +# Finiteness tactic + +This file implements a basic `finiteness` tactic, designed to solve goals of the form `*** < ∞` and +(equivalently) `*** ≠ ∞` in the extended nonnegative reals (`ENNReal`, aka `ℝ≥0∞`). + +It works recursively according to the syntax of the expression. It is implemented as an `aesop` rule +set. + +## Syntax + +Standard `aesop` syntax applies. Namely one can write +* `finiteness (add unfold [def1, def2])` to make `finiteness` unfold `def1`, `def2` +* `finiteness?` for the tactic to show what proof it found +* etc +* Note that `finiteness` disables `simp`, so `finiteness (add simp [lemma1, lemma2])` does not do + anything more than a bare `finiteness`. + +We also provide `finiteness_nonterminal` as a version of `finiteness` that doesn't have to close the +goal. + +## TODO + +Improve `finiteness` to also deal with other situations, such as balls in proper spaces with +a locally finite measure. +-/ + +open Aesop.BuiltinRules in +attribute [aesop (rule_sets := [finiteness]) safe -50] assumption intros + +set_option linter.unusedTactic false in +add_aesop_rules safe tactic (rule_sets := [finiteness]) (by positivity) + +/-- Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended +nonnegative reals (`ℝ≥0∞`). -/ +macro (name := finiteness) "finiteness" c:Aesop.tactic_clause* : tactic => +`(tactic| + aesop $c* + (config := { introsTransparency? := some .reducible, terminal := true, enableSimp := false }) + (rule_sets := [$(Lean.mkIdent `finiteness):ident, -default, -builtin])) + +/-- Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended +nonnegative reals (`ℝ≥0∞`). -/ +macro (name := finiteness?) "finiteness?" c:Aesop.tactic_clause* : tactic => +`(tactic| + aesop? $c* + (config := { introsTransparency? := some .reducible, terminal := true, enableSimp := false }) + (rule_sets := [$(Lean.mkIdent `finiteness):ident, -default, -builtin])) + +/-- Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended +nonnegative reals (`ℝ≥0∞`). -/ +macro (name := finiteness_nonterminal) "finiteness_nonterminal" c:Aesop.tactic_clause* : tactic => +`(tactic| + aesop $c* + (config := { introsTransparency? := some .reducible, terminal := false, enableSimp := false, + warnOnNonterminal := false }) + (rule_sets := [$(Lean.mkIdent `finiteness):ident, -default, -builtin])) diff --git a/Mathlib/Tactic/Finiteness/Attr.lean b/Mathlib/Tactic/Finiteness/Attr.lean new file mode 100644 index 0000000000000..93264ceb6d54e --- /dev/null +++ b/Mathlib/Tactic/Finiteness/Attr.lean @@ -0,0 +1,10 @@ +/- +Copyright (c) 2024 Floris van Doorn. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Floris van Doorn +-/ +import Aesop + +/-! # Finiteness tactic attribute -/ + +declare_aesop_rule_sets [finiteness] diff --git a/Mathlib/Tactic/FunProp/Attr.lean b/Mathlib/Tactic/FunProp/Attr.lean index b77b4b9cf2b0d..55a876dcd0943 100644 --- a/Mathlib/Tactic/FunProp/Attr.lean +++ b/Mathlib/Tactic/FunProp/Attr.lean @@ -3,8 +3,6 @@ Copyright (c) 2024 Tomáš Skřivan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ -import Lean - import Mathlib.Tactic.FunProp.Decl import Mathlib.Tactic.FunProp.Theorems diff --git a/Mathlib/Tactic/FunProp/ContDiff.lean b/Mathlib/Tactic/FunProp/ContDiff.lean index adc20fffe2b95..037d1812296a5 100644 --- a/Mathlib/Tactic/FunProp/ContDiff.lean +++ b/Mathlib/Tactic/FunProp/ContDiff.lean @@ -23,8 +23,7 @@ variable {K : Type*} [NontriviallyNormedField K] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace K F] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace K G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace K G'] -variable {f f₀ f₁ g : E → F} {x} {s t} {n} +variable {f : E → F} {x} {s} {n} theorem contDiff_id' : ContDiff K n (fun x : E => x) := contDiff_id @@ -42,8 +41,8 @@ theorem ContDiffAt.comp' {f : E → F} {g : F → G} (hg : ContDiffAt K n g (f x -- theorem ContDiffOn.comp'' {g : F → G} {t : Set F} (hg : ContDiffOn K n g t) -- (hf : ContDiffOn K n f s) (st : Set.MapsTo f s t) : ContDiffOn K n (fun x => g (f x)) s := -variable {ι ι' : Type*} [Fintype ι] [Fintype ι'] {F' : ι → Type*} [∀ i, NormedAddCommGroup (F' i)] - [∀ i, NormedSpace K (F' i)] {φ : ∀ i, E → F' i} {Φ : E → ∀ i, F' i} +variable {ι : Type*} [Fintype ι] {F' : ι → Type*} [∀ i, NormedAddCommGroup (F' i)] + [∀ i, NormedSpace K (F' i)] {Φ : E → ∀ i, F' i} theorem contDiff_pi' (hΦ : ∀ i, ContDiff K n fun x => Φ x i) : ContDiff K n Φ := contDiff_pi.2 hΦ @@ -60,8 +59,7 @@ section div variable {K : Type*} [NontriviallyNormedField K] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] -variable {F : Type*} [NormedAddCommGroup F] [NormedSpace K F] -variable {f f₀ f₁ g : E → F} {x} {s t} {n} +variable {s} theorem ContDiffOn.div' [CompleteSpace K] {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 := @@ -74,7 +72,6 @@ end div section deriv variable {K : Type*} [NontriviallyNormedField K] -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace K F] /-- Original version `ContDiff.differentiable_iteratedDeriv` introduces a new variable `(n:ℕ∞)` diff --git a/Mathlib/Tactic/FunProp/Core.lean b/Mathlib/Tactic/FunProp/Core.lean index e337933dc09dc..7cfc38fde4b73 100644 --- a/Mathlib/Tactic/FunProp/Core.lean +++ b/Mathlib/Tactic/FunProp/Core.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Tomáš Skřivan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ -import Lean import Mathlib.Tactic.FunProp.Theorems import Mathlib.Tactic.FunProp.ToBatteries import Mathlib.Tactic.FunProp.Types diff --git a/Mathlib/Tactic/FunProp/Decl.lean b/Mathlib/Tactic/FunProp/Decl.lean index c744ad6ea026b..d91b7a71fec56 100644 --- a/Mathlib/Tactic/FunProp/Decl.lean +++ b/Mathlib/Tactic/FunProp/Decl.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ import Mathlib.Init -import Lean /-! ## `funProp` environment extension that stores all registered function properties diff --git a/Mathlib/Tactic/FunProp/Differentiable.lean b/Mathlib/Tactic/FunProp/Differentiable.lean index 1d81eec7d76f2..a692cd880dab5 100644 --- a/Mathlib/Tactic/FunProp/Differentiable.lean +++ b/Mathlib/Tactic/FunProp/Differentiable.lean @@ -29,8 +29,7 @@ variable {K : Type*} [NontriviallyNormedField K] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace K F] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace K G] -variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace K G'] -variable {f f₀ f₁ g : E → F} {x} {s t} +variable {f : E → F} {x} {s} theorem differentiableOn_id' : DifferentiableOn K (fun x : E => x) s := diff --git a/Mathlib/Tactic/FunProp/Elab.lean b/Mathlib/Tactic/FunProp/Elab.lean index afa3b31d7cf78..358e01ab84df1 100644 --- a/Mathlib/Tactic/FunProp/Elab.lean +++ b/Mathlib/Tactic/FunProp/Elab.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Tomáš Skřivan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ -import Lean import Mathlib.Tactic.FunProp.Core /-! diff --git a/Mathlib/Tactic/FunProp/FunctionData.lean b/Mathlib/Tactic/FunProp/FunctionData.lean index 04be35eced734..d61e54219b61d 100644 --- a/Mathlib/Tactic/FunProp/FunctionData.lean +++ b/Mathlib/Tactic/FunProp/FunctionData.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Tomáš Skřivan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ -import Lean import Qq import Mathlib.Tactic.FunProp.Mor diff --git a/Mathlib/Tactic/FunProp/Mor.lean b/Mathlib/Tactic/FunProp/Mor.lean index 73bf51afe47f0..1b27bf7755713 100644 --- a/Mathlib/Tactic/FunProp/Mor.lean +++ b/Mathlib/Tactic/FunProp/Mor.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Tomáš Skřivan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ -import Lean import Mathlib.Data.FunLike.Basic import Mathlib.Tactic.FunProp.ToBatteries diff --git a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean index da93ffa29a9af..876dc3a14dc35 100644 --- a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean +++ b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean @@ -449,7 +449,7 @@ partial def reduce (e : Expr) (config : WhnfCoreConfig) : MetaM Expr := do /-- Repeatedly apply reduce while stripping lambda binders and introducing their variables -/ @[specialize] partial def lambdaTelescopeReduce {m} [Monad m] [MonadLiftT MetaM m] [MonadControlT MetaM m] - [Inhabited α] (e : Expr) (fvars : List FVarId) (config : WhnfCoreConfig) + [Nonempty α] (e : Expr) (fvars : List FVarId) (config : WhnfCoreConfig) (k : Expr → List FVarId → m α) : m α := do match ← reduce e config with | .lam n d b bi => @@ -864,8 +864,6 @@ def mkDTExprs (e : Expr) (config : WhnfCoreConfig) (onlySpecific : Bool) /-! ## Inserting intro a RefinedDiscrTree -/ -variable {α : Type} - /-- If `vs` contains an element `v'` such that `v == v'`, then replace `v'` with `v`. Otherwise, push `v`. See issue #2155 diff --git a/Mathlib/Tactic/FunProp/ToBatteries.lean b/Mathlib/Tactic/FunProp/ToBatteries.lean index 11ce07dbc78c3..f3affc6579c3d 100644 --- a/Mathlib/Tactic/FunProp/ToBatteries.lean +++ b/Mathlib/Tactic/FunProp/ToBatteries.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Tomáš Skřivan -/ import Mathlib.Init -import Lean /-! ## `funProp` missing function from standard library diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index bf7982ef2748e..a47257466df27 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Mario Carneiro, Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Heather Macbeth -/ +import Lean import Mathlib.Order.Defs import Mathlib.Tactic.Core import Mathlib.Tactic.GCongr.ForwardAttr @@ -78,8 +79,8 @@ functions which have different theories when different typeclass assumptions app the following lemma is stored with the same `@[gcongr]` data as `mul_le_mul` above, and the two lemmas are simply tried in succession to determine which has the typeclasses relevant to the goal: ``` -theorem mul_le_mul' [Mul α] [Preorder α] [CovariantClass α α (· * ·) (· ≤ ·)] - [CovariantClass α α (Function.swap (· * ·)) (· ≤ ·)] {a b c d : α} (h₁ : a ≤ b) (h₂ : c ≤ d) : +theorem mul_le_mul' [Mul α] [Preorder α] [MulLeftMono α] + [MulRightMono α] {a b c d : α} (h₁ : a ≤ b) (h₂ : c ≤ d) : a * c ≤ b * d ``` diff --git a/Mathlib/Tactic/Inhabit.lean b/Mathlib/Tactic/Inhabit.lean index cda2beb10fd0b..816030deb4acc 100644 --- a/Mathlib/Tactic/Inhabit.lean +++ b/Mathlib/Tactic/Inhabit.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Joshua Clune. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joshua Clune -/ -import Lean +import Lean.Elab.Tactic.ElabTerm import Mathlib.Tactic.TypeStar /-! diff --git a/Mathlib/Tactic/IrreducibleDef.lean b/Mathlib/Tactic/IrreducibleDef.lean index bfdf7272c85bd..4c123c5a59d82 100644 --- a/Mathlib/Tactic/IrreducibleDef.lean +++ b/Mathlib/Tactic/IrreducibleDef.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ -import Lean import Mathlib.Tactic.Eqns import Mathlib.Data.Subtype diff --git a/Mathlib/Tactic/Lemma.lean b/Mathlib/Tactic/Lemma.lean index 901874a9f585a..10d49cd8d8a8f 100644 --- a/Mathlib/Tactic/Lemma.lean +++ b/Mathlib/Tactic/Lemma.lean @@ -12,8 +12,9 @@ import Lean.Parser.Command open Lean +-- higher priority to override the one in Batteries /-- `lemma` means the same as `theorem`. It is used to denote "less important" theorems -/ -syntax (name := lemma) declModifiers +syntax (name := lemma) (priority := default + 1) declModifiers group("lemma " declId ppIndent(declSig) declVal) : command /-- Implementation of the `lemma` command, by macro expansion to `theorem`. -/ diff --git a/Mathlib/Tactic/Linter.lean b/Mathlib/Tactic/Linter.lean index e5c4da4423d3c..2f67da1bea192 100644 --- a/Mathlib/Tactic/Linter.lean +++ b/Mathlib/Tactic/Linter.lean @@ -11,3 +11,4 @@ This file is ignored by `shake`: import Mathlib.Tactic.Linter.FlexibleLinter import Mathlib.Tactic.Linter.HaveLetLinter import Mathlib.Tactic.Linter.MinImports +import Mathlib.Tactic.Linter.PPRoundtrip diff --git a/Mathlib/Tactic/Linter/AdmitLinter.lean b/Mathlib/Tactic/Linter/AdmitLinter.lean index 602952c5a6692..1252ba144e746 100644 --- a/Mathlib/Tactic/Linter/AdmitLinter.lean +++ b/Mathlib/Tactic/Linter/AdmitLinter.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa, Adomas Baliuka -/ import Lean.Elab.Command +import Mathlib.Init /-! # The "admit" linter @@ -53,3 +54,4 @@ def admitLinter : Linter where run := withSetOptionIn fun stx => do initialize addLinter admitLinter end AdmitLinter +end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/FlexibleLinter.lean b/Mathlib/Tactic/Linter/FlexibleLinter.lean index 525285a97bfef..b4e55dd675316 100644 --- a/Mathlib/Tactic/Linter/FlexibleLinter.lean +++ b/Mathlib/Tactic/Linter/FlexibleLinter.lean @@ -5,7 +5,7 @@ Authors: Damiano Testa -/ import Lean.Elab.Command import Batteries.Data.Array.Basic -import Batteries.Lean.HashSet +import Mathlib.Init /-! # The "flexible" linter diff --git a/Mathlib/Tactic/Linter/HashCommandLinter.lean b/Mathlib/Tactic/Linter/HashCommandLinter.lean index 66cac438ada34..3dd02b5342952 100644 --- a/Mathlib/Tactic/Linter/HashCommandLinter.lean +++ b/Mathlib/Tactic/Linter/HashCommandLinter.lean @@ -5,7 +5,6 @@ Authors: Damiano Testa -/ import Lean.Elab.Command -import Batteries.Lean.HashSet /-! # `#`-command linter diff --git a/Mathlib/Tactic/Linter/Header.lean b/Mathlib/Tactic/Linter/Header.lean new file mode 100644 index 0000000000000..4089b703bfc7e --- /dev/null +++ b/Mathlib/Tactic/Linter/Header.lean @@ -0,0 +1,318 @@ +/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Rothgang, Damiano Testa +-/ +import Lean.Elab.Command + +/-! +# The "header" linter + +The "header" style linter checks that a file starts with +``` +/- +Copyright ... +Apache ... +Authors ... +-/ + +import statements* +module doc-string* +remaining file +``` +It emits a warning if +* the copyright statement is malformed; +* `Mathlib.Tactic` is imported; +* any import in `Lake` is present; +* the first non-`import` command is not a module doc-string. + +The linter allows `import`-only files and does not require a copyright statement in `Mathlib.Init`. + +## Implementation +The strategy used by the linter is as follows. +The linter computes the end position of the first module doc-string of the file, +resorting to the end of the file, if there is no module doc-string. +Next, the linter tries to parse the file up to the position determined above. + +If the parsing is successful, the linter checks the resulting `Syntax` and behaves accordingly. + +If the parsing is not successful, this already means there is some "problematic" command +after the imports. In particular, there is a command that is not a module doc-string +immediately following the last import: the file should be flagged by the linter. +Hence, the linter then falls back to parsing the header of the file, adding a spurious `section` +after it. +This makes it possible for the linter to check the entire header of the file, emit warnings that +could arise from this part and also flag that the file should contain a module doc-string after +the `import` statements. +-/ + +open Lean Elab Command + +namespace Mathlib.Linter + +/-- +`firstNonImport? stx` assumes that the input `Syntax` is of kind `Lean.Parser.Module.module`. +It returns +* `none`, if `stx` consists only of `import` statements, +* the first non-`import` command in `stx`, otherwise. + +The intended use-case is to use the output of `testParseModule` as the input of +`firstNonImport?`. +-/ +def firstNonImport? : Syntax → Option Syntax + | .node _ ``Lean.Parser.Module.module #[_header, .node _ `null args] => args[0]? + | _=> some .missing -- this is unreachable, if the input comes from `testParseModule` + +/-- `getImportIds s` takes as input `s : Syntax`. +It returns the array of all `import` identifiers in `s`. -/ +-- We cannot use `importsOf` instead, as +-- - that function is defined in the `ImportGraph` project; we would like to minimise imports +-- to Mathlib.Init (where this linter is imported) +-- - that function does not return the Syntax corresponding to each import, +-- which we use to log more precise warnings. +partial +def getImportIds (s : Syntax) : Array Syntax := + let rest : Array Syntax := (s.getArgs.map getImportIds).flatten + if s.isOfKind ``Lean.Parser.Module.import then + rest.push (s.getArgs.getD 2 default) + else + rest + +/-- +`parseUpToHere pos post` takes as input `pos : String.Pos` and the optional `post : String`. +It parses the current file from the beginning until `pos`, appending `post` at the end. +It returns a syntax node of kind `Lean.Parser.Module.module`. +The option of appending a final string to the text gives more control to avoid syntax errors, +for instance in the presence of `#guard_msgs in` or `set_option ... in`. + +Note that this parsing will *not* be successful on every file. However, if the linter is +parsing the file linearly, it will only need to parse +* the imports (that are always parseable) and +* the first non-import command that is supposed to be a module doc-string (so again always + parseable). + +In conclusion, either the parsing is successful, and the linter can continue with its analysis, +or the parsing is not successful and the linter will flag a missing module doc-string! +-/ +def parseUpToHere (pos : String.Pos) (post : String := "") : CommandElabM Syntax := do + let upToHere : Substring := { str := (← getFileMap).source, startPos := ⟨0⟩, stopPos := pos } + -- Append a further string after the content of `upToHere`. + Parser.testParseModule (← getEnv) "linter.style.header" (upToHere.toString ++ post) + +/-- `toSyntax s pattern` converts the two input strings into a `Syntax`, assuming that `pattern` +is a substring of `s`: +the syntax is an atom with value `pattern` whose the range is the range of `pattern` in `s`. -/ +def toSyntax (s pattern : String) (offset : String.Pos := 0) : Syntax := + let beg := ((s.splitOn pattern).getD 0 "").endPos + offset + let fin := (((s.splitOn pattern).getD 0 "") ++ pattern).endPos + offset + mkAtomFrom (.ofRange ⟨beg, fin⟩) pattern + +/-- Return if `line` looks like a correct authors line in a copyright header. + +The `offset` input is used to shift the position information of the `Syntax` that the command +produces. +`authorsLineChecks` computes a position for its warning *relative to `line`*. +The `offset` input passes on the starting position of `line` in the whole file. +-/ +def authorsLineChecks (line : String) (offset : String.Pos) : Array (Syntax × String) := + Id.run do + -- We cannot reasonably validate the author names, so we look only for a few common mistakes: + -- the line starting wrongly, double spaces, using ' and ' between names, + -- and ending the line with a period. + let mut stxs := #[] + if !line.startsWith "Authors: " then + stxs := stxs.push + (toSyntax line (line.take "Authors: ".length) offset, + s!"The authors line should begin with 'Authors: '") + if (line.splitOn " ").length != 1 then + stxs := stxs.push (toSyntax line " " offset, s!"Double spaces are not allowed.") + if (line.splitOn " and ").length != 1 then + stxs := stxs.push (toSyntax line " and " offset, s!"Please, do not use 'and'; use ',' instead.") + if line.back == '.' then + stxs := stxs.push + (toSyntax line "." offset, + s!"Please, do not end the authors' line with a period.") + return stxs + +/-- The main function to validate the copyright string. +The input is the copyright string, the output is an array of `Syntax × String` encoding: +* the `Syntax` factors are atoms whose ranges are "best guesses" for where the changes should + take place; the embedded string is the current text that the linter flagged; +* the `String` factor is the linter message. + +The linter checks that +* the first and last line of the copyright are a `("/-", "-/")` pair, each on its own line; +* the first line is begins with `Copyright (c) 20` and ends with `. All rights reserved.`; +* the second line is `Released under Apache 2.0 license as described in the file LICENSE.`; +* the remainder of the string begins with `Authors: `, does not end with `.` and + contains no ` and ` nor a double space, except possibly after a line break. +-/ +def copyrightHeaderChecks (copyright : String) : Array (Syntax × String) := Id.run do + -- First, we merge lines ending in `,`: two spaces after the line-break are ok, + -- but so is only one or none. We take care of *not* adding more consecutive spaces, though. + -- This is to allow the copyright or authors' lines to span several lines. + let preprocessCopyright := (copyright.replace ",\n " ", ").replace ",\n" "," + -- Filter out everything after the first isolated `-/`. + let pieces := preprocessCopyright.splitOn "\n-/" + let copyright := (pieces.getD 0 "") ++ "\n-/" + let stdText (s : String) := + s!"Malformed or missing copyright header: `{s}` should be alone on its own line." + let mut output := #[] + if (pieces.getD 1 "\n").take 1 != "\n" then + output := output.push (toSyntax copyright "-/", s!"{stdText "-/"}") + let lines := copyright.splitOn "\n" + let closeComment := lines.getLastD "" + match lines with + | openComment :: copyrightAuthor :: license :: authorsLines => + -- The header should start and end with blank comments. + match openComment, closeComment with + | "/-", "-/" => output := output + | "/-", _ => + output := output.push (toSyntax copyright closeComment, s!"{stdText "-/"}") + | _, _ => + output := output.push (toSyntax copyright openComment, s!"{stdText ("/".push '-')}") + -- Validate the first copyright line. + let copStart := "Copyright (c) 20" + let copStop := ". All rights reserved." + if !copyrightAuthor.startsWith copStart then + output := output.push + (toSyntax copyright (copyrightAuthor.take copStart.length), + s!"Copyright line should start with 'Copyright (c) YYYY'") + if !copyrightAuthor.endsWith copStop then + output := output.push + (toSyntax copyright (copyrightAuthor.takeRight copStop.length), + s!"Copyright line should end with '. All rights reserved.'") + -- Validate the authors line(s). The last line is the closing comment: trim that off right away. + let authorsLines := authorsLines.dropLast + -- Complain about a missing authors line. + if authorsLines.length == 0 then + output := output.push (toSyntax copyright "-/", s!"Copyright too short!") + else + -- If the list of authors spans multiple lines, all but the last line should end with a trailing + -- comma. This excludes e.g. other comments in the copyright header. + let authorsLine := "\n".intercalate authorsLines + let authorsStart := (("\n".intercalate [openComment, copyrightAuthor, license, ""])).endPos + if authorsLines.length > 1 && !authorsLines.dropLast.all (·.endsWith ",") then + output := output.push ((toSyntax copyright authorsLine), + "If an authors line spans multiple lines, \ + each line but the last must end with a trailing comma") + output := output.append (authorsLineChecks authorsLine authorsStart) + let expectedLicense := "Released under Apache 2.0 license as described in the file LICENSE." + if license != expectedLicense then + output := output.push (toSyntax copyright license, + s!"Second copyright line should be \"{expectedLicense}\"") + | _ => + output := output.push (toSyntax copyright "-/", s!"Copyright too short!") + return output + +/-- Check the `Syntax` `imports` for broad imports: either `Mathlib.Tactic` or any import +starting with `Lake`. -/ +def broadImportsCheck (imports : Array Syntax) (mainModule : Name) : Array (Syntax × String) := Id.run do + let mut output := #[] + for i in imports do + match i.getId with + | `Mathlib.Tactic => + output := output.push (i, s!"Files in mathlib cannot import the whole tactic folder.") + | `Mathlib.Tactic.Replace => + if mainModule != `Mathlib.Tactic then output := output.push (i, + s!"Mathlib.Tactic.Replace defines a deprecated form of the 'replace' tactic; \ + please do not use it in mathlib.") + | `Mathlib.Tactic.Have => + if ![`Mathlib.Tactic, `Mathlib.Tactic.Replace].contains mainModule then + output := output.push (i, + s!"Mathlib.Tactic.Have defines a deprecated form of the 'have' tactic; \ + please do not use it in mathlib.") + | modName => + if modName.getRoot == `Lake then + output := output.push (i, + s!"In the past, importing 'Lake' in mathlib has led to dramatic slow-downs of the linter \ + (see e.g. mathlib4#13779). Please consider carefully if this import is useful and \ + make sure to benchmark it. If this is fine, feel free to allow this linter.") + else if (`Mathlib.Deprecated).isPrefixOf modName && + !(`Mathlib.Deprecated).isPrefixOf mainModule then + -- We do not complain about files in the `Deprecated` directory importing one another. + output := output.push (i, s!"Files in the `Deprecated` directory are not supposed to be imported.") + + return output + +/-- +The "header" style linter checks that a file starts with +``` +/- +Copyright ... +Apache ... +Authors ... +-/ + +import statements* +module doc-string* +remaining file +``` +It emits a warning if +* the copyright statement is malformed; +* `Mathlib.Tactic` is imported; +* any import in `Lake` is present; +* the first non-`import` command is not a module doc-string. + +The linter allows `import`-only files and does not require a copyright statement in `Mathlib.Init`. +-/ +register_option linter.style.header : Bool := { + defValue := false + descr := "enable the header style linter" +} + +namespace Style.header + +@[inherit_doc Mathlib.Linter.linter.style.header] +def headerLinter : Linter where run := withSetOptionIn fun stx ↦ do + unless Linter.getLinterValue linter.style.header (← getOptions) do + return + if (← get).messages.hasErrors then + return + let mainModule ← getMainModule + -- `Mathlib.lean` imports `Mathlib.Tactic`, which the broad imports check below would flag. + -- Since that file is imports-only, we can simply skip linting it. + if mainModule == `Mathlib then return + let fm ← getFileMap + let md := (getMainModuleDoc (← getEnv)).toArray + -- The end of the first module doc-string, or the end of the file if there is none. + let firstDocModPos := match md[0]? with + | none => fm.positions.back + | some doc => fm.ofPosition doc.declarationRange.endPos + unless stx.getTailPos? == some firstDocModPos do + return + -- We try to parse the file up to `firstDocModPos`. + let upToStx ← parseUpToHere firstDocModPos <|> (do + -- If parsing failed, there is some command which is not a module docstring. + -- In that case, we parse until the end of the imports and add an extra `section` afterwards, + -- so we trigger a "no module doc-string" warning. + let fil ← getFileName + let (stx, _) ← Parser.parseHeader { input := fm.source, fileName := fil, fileMap := fm } + parseUpToHere (stx.getTailPos?.getD default) "\nsection") + let importIds := getImportIds upToStx + -- Report on broad imports. + for (imp, msg) in broadImportsCheck importIds mainModule do + Linter.logLint linter.style.header imp msg + let afterImports := firstNonImport? upToStx + if afterImports.isNone then return + let copyright := match upToStx.getHeadInfo with + | .original lead .. => lead.toString + | _ => "" + -- Report any errors about the copyright line. + if mainModule != `Mathlib.Init then + for (stx, m) in copyrightHeaderChecks copyright do + Linter.logLint linter.style.header stx m!"* '{stx.getAtomVal}':\n{m}\n" + -- Report a missing module doc-string. + match afterImports with + | none => return + | some (.node _ ``Lean.Parser.Command.moduleDoc _) => return + | some rest => + Linter.logLint linter.style.header rest + m!"The module doc-string for a file should be the first command after the imports.\n\ + Please, add a module doc-string before `{stx}`." + +initialize addLinter headerLinter + +end Style.header + +end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/Lint.lean b/Mathlib/Tactic/Linter/Lint.lean index 6d00f05354dde..280dad9777e59 100644 --- a/Mathlib/Tactic/Linter/Lint.lean +++ b/Mathlib/Tactic/Linter/Lint.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ import Batteries.Tactic.Lint +import Mathlib.Tactic.DeclarationNames /-! # Linters for Mathlib @@ -77,29 +78,20 @@ namespace DupNamespaceLinter open Lean Parser Elab Command Meta -/-- `getIds stx` extracts the `declId` nodes from the `Syntax` `stx`. -If `stx` is an `alias` or an `export`, then it extracts an `ident`, instead of a `declId`. -/ -partial -def getIds : Syntax → Array Syntax - | .node _ `Batteries.Tactic.Alias.alias args => args[2:3] - | .node _ ``Lean.Parser.Command.export args => (args[3:4] : Array Syntax).map (·[0]) - | stx@(.node _ _ args) => - ((args.attach.map fun ⟨a, _⟩ ↦ getIds a).foldl (· ++ ·) #[stx]).filter (·.getKind == ``declId) - | _ => default - @[inherit_doc linter.dupNamespace] def dupNamespace : Linter where run := withSetOptionIn fun stx ↦ do if Linter.getLinterValue linter.dupNamespace (← getOptions) then - match getIds stx with - | #[id] => - let ns := (← getScope).currNamespace - let declName := ns ++ (if id.getKind == ``declId then id[0].getId else id.getId) - let nm := declName.components - let some (dup, _) := nm.zip (nm.tailD []) |>.find? fun (x, y) ↦ x == y - | return - Linter.logLint linter.dupNamespace id - m!"The namespace '{dup}' is duplicated in the declaration '{declName}'" - | _ => return + let mut aliases := #[] + if let some exp := stx.find? (·.isOfKind `Lean.Parser.Command.export) then + aliases ← getAliasSyntax exp + for id in (← getNamesFrom (stx.getPos?.getD default)) ++ aliases do + let declName := id.getId + if declName.hasMacroScopes then continue + let nm := declName.components + let some (dup, _) := nm.zip (nm.tailD []) |>.find? fun (x, y) ↦ x == y + | continue + Linter.logLint linter.dupNamespace id + m!"The namespace '{dup}' is duplicated in the declaration '{declName}'" initialize addLinter dupNamespace @@ -311,7 +303,7 @@ The "longFile" linter emits a warning on files which are longer than a certain n /-- The "longFile" linter emits a warning on files which are longer than a certain number of lines -(1500 by default on mathlib, no limit for downstream projects). +(`linter.style.longFileDefValue` by default on mathlib, no limit for downstream projects). If this option is set to `N` lines, the linter warns once a file has more than `N` lines. A value of `0` silences the linter entirely. -/ @@ -354,6 +346,7 @@ def longFileLinter : Linter where run := withSetOptionIn fun stx ↦ do if let some init := stx.getTailPos? then -- the last line: we subtract 1, since the last line is expected to be empty let lastLine := ((← getFileMap).toPosition init).line + -- In this case, the file has an allowed length, and the linter option is unnecessarily set. if lastLine ≤ defValue && defValue < linterBound then logWarningAt stx <| .tagged linter.style.longFile.name m!"The default value of the `longFile` linter is {defValue}.\n\ @@ -365,12 +358,23 @@ def longFileLinter : Linter where run := withSetOptionIn fun stx ↦ do -- `candidate` is necessarily bigger than `lastLine` and hence bigger than `defValue` let candidate := (lastLine / 100) * 100 + 200 let candidate := max candidate defValue - if linterBound < lastLine then + -- In this case, the file is longer than the default and also than what the option says. + if defValue ≤ linterBound && linterBound < lastLine then logWarningAt stx <| .tagged linter.style.longFile.name m!"This file is {lastLine} lines long, but the limit is {linterBound}.\n\n\ You can extend the allowed length of the file using \ `set_option linter.style.longFile {candidate}`.\n\ You can completely disable this linter by setting the length limit to `0`." + else + -- Finally, the file exceeds the default value, but not the option: we only allow the value + -- of the option to be `candidate` or `candidate + 100`. + -- In particular, this flags any option that is set to an unnecessarily high value. + if linterBound == candidate || linterBound + 100 == candidate then return + else + logWarningAt stx <| .tagged linter.style.longFile.name + m!"This file is {lastLine} lines long. \ + The current limit is {linterBound}, but it is expected to be {candidate}:\n\ + `set_option linter.style.longFile {candidate}`." initialize addLinter longFileLinter @@ -414,7 +418,7 @@ def longLineLinter : Linter where run := withSetOptionIn fun stx ↦ do if (line.splitOn "http").length ≤ 1 then let stringMsg := if line.contains '"' then "\nYou can use \"string gaps\" to format long strings: within a string quotation, \ - using a '\' at the end of a line allows you to continue the string on the following \ + using a '\\' at the end of a line allows you to continue the string on the following \ line, removing all intervening whitespace." else "" Linter.logLint linter.style.longLine (.ofRange ⟨line.startPos, line.stopPos⟩) diff --git a/Mathlib/Tactic/Linter/MinImports.lean b/Mathlib/Tactic/Linter/MinImports.lean index 202d32297ca82..0aad206e77cf8 100644 --- a/Mathlib/Tactic/Linter/MinImports.lean +++ b/Mathlib/Tactic/Linter/MinImports.lean @@ -28,8 +28,26 @@ The "minImports" linter tracks information about minimal imports over several co namespace Mathlib.Linter -/-- `minImportsRef` keeps track of cumulative imports across multiple commands. -/ -initialize minImportsRef : IO.Ref NameSet ← IO.mkRef {} +/-- +`ImportState` is the structure keeping track of the data that the `minImports` linter uses. +* `transClosure` is the import graph of the current file. +* `minImports` is the `NameSet` of minimal imports to build the file up to the current command. +* `importSize` is the number of transitive imports to build the file up to the current command. +-/ +structure ImportState where + /-- The transitive closure of the import graph of the current file. The value is `none` only at + initialization time, as the linter immediately sets it to its value for the current file. -/ + transClosure : Option (NameMap NameSet) := none + /-- The minimal imports needed to build the file up to the current command. -/ + minImports : NameSet := {} + /-- The number of transitive imports needed to build the file up to the current command. -/ + importSize : Nat := 0 + deriving Inhabited + +/-- +`minImportsRef` keeps track of cumulative imports across multiple commands, using `ImportState`. +-/ +initialize minImportsRef : IO.Ref ImportState ← IO.mkRef {} /-- `#reset_min_imports` sets to empty the current list of cumulative imports. -/ elab "#reset_min_imports" : command => minImportsRef.set {} @@ -41,30 +59,52 @@ computed so far, it emits a warning mentioning the bigger minimal imports. Unlike the related `#min_imports` command, the linter takes into account notation and tactic information. -It also works incrementally, providing information that it better suited, for instance, to split +It also works incrementally, providing information that is better suited, for instance, to split files. - -/ +-/ register_option linter.minImports : Bool := { defValue := false descr := "enable the minImports linter" } +/-- The `linter.minImports.increases` regulates whether the `minImports` linter reports the +change in number of imports, when it reports import changes. +Setting this option to `false` helps with test stability. +-/ +register_option linter.minImports.increases : Bool := { + defValue := true + descr := "enable reporting increase-size change in the minImports linter" +} + namespace MinImports open Mathlib.Command.MinImports +/-- `importsBelow tc ms` takes as input a `NameMap NameSet` `tc`, representing the +`transitiveClosure` of the imports of the current module, and a `NameSet` of module names `ms`. +It returns the modules that are transitively imported by `ms`, using the data in `tc`. +-/ +def importsBelow (tc : NameMap NameSet) (ms : NameSet) : NameSet := + ms.fold (·.append <| tc.findD · default) ms + @[inherit_doc Mathlib.Linter.linter.minImports] -def minImportsLinter : Linter where run := withSetOptionIn fun stx => do +def minImportsLinter : Linter where run := withSetOptionIn fun stx ↦ do unless Linter.getLinterValue linter.minImports (← getOptions) do return - if (← MonadState.get).messages.hasErrors then + if (← get).messages.hasErrors then return if stx == (← `(command| set_option $(mkIdent `linter.minImports) true)) then return - let importsSoFar ← minImportsRef.get + let env ← getEnv + -- the first time `minImportsRef` is read, it has `transClosure = none`; + -- in this case, we set it to be the `transClosure` for the file. + if (← minImportsRef.get).transClosure.isNone then + minImportsRef.modify ({· with transClosure := env.importGraph.transitiveClosure}) + let impState ← minImportsRef.get + let (importsSoFar, oldCumulImps) := (impState.minImports, impState.importSize) -- when the linter reaches the end of the file or `#exit`, it gives a report if #[``Parser.Command.eoi, ``Lean.Parser.Command.exit].contains stx.getKind then let explicitImportsInFile : NameSet := - .fromArray (((← getEnv).imports.map (·.module)).erase `Init) Name.quickCmp + .fromArray ((env.imports.map (·.module)).erase `Init) Name.quickCmp let newImps := importsSoFar.diff explicitImportsInFile let currentlyUnneededImports := explicitImportsInFile.diff importsSoFar -- we read the current file, to do a custom parsing of the imports: @@ -85,15 +125,28 @@ def minImportsLinter : Linter where run := withSetOptionIn fun stx => do logWarningAt ((impMods.find? (·.isOfKind `import)).getD default) m!"-- missing imports\n{"\n".intercalate withImport.toList}" let id ← getId stx - let newImports := getIrredundantImports (← getEnv) (← getAllImports stx id) + let newImports := getIrredundantImports env (← getAllImports stx id) let tot := (newImports.append importsSoFar) - let redundant := (← getEnv).findRedundantImports tot.toArray + let redundant := env.findRedundantImports tot.toArray let currImports := tot.diff redundant let currImpArray := currImports.toArray.qsort Name.lt if currImpArray != #[] && currImpArray ≠ importsSoFar.toArray.qsort Name.lt then - minImportsRef.modify fun _ => currImports - Linter.logLint linter.minImports stx m!"Imports increased to\n{currImpArray}" + let newCumulImps := -- We should always be in the situation where `getD` finds something + (importsBelow (impState.transClosure.getD env.importGraph.transitiveClosure) tot).size + minImportsRef.modify ({· with minImports := currImports, importSize := newCumulImps}) + let new := currImpArray.filter (!importsSoFar.contains ·) + let redundant := importsSoFar.toArray.filter (!currImports.contains ·) + -- to make `test` files more stable, we suppress the exact count of import changes if + -- the `linter.minImports.increases` option is `false` + let byCount := if Linter.getLinterValue linter.minImports.increases (← getOptions) then + m!"by {newCumulImps - oldCumulImps} " + else + m!"" + Linter.logLint linter.minImports stx <| + m!"Imports increased {byCount}to\n{currImpArray}\n\n\ + New imports: {new}\n" ++ + if redundant.isEmpty then m!"" else m!"\nNow redundant: {redundant}\n" initialize addLinter minImportsLinter diff --git a/Mathlib/Tactic/Linter/Multigoal.lean b/Mathlib/Tactic/Linter/Multigoal.lean new file mode 100644 index 0000000000000..aa24f8a50aef1 --- /dev/null +++ b/Mathlib/Tactic/Linter/Multigoal.lean @@ -0,0 +1,167 @@ +/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa +-/ +import Lean.Elab.Command + +/-! +# The "multiGoal" linter + +The "multiGoal" linter emits a warning where there is more than a single goal in scope. +There is an exception: a tactic that closes *all* remaining goals is allowed. + +There are a few tactics, such as `skip`, `swap` or the `try` combinator, that are intended to work +specifically in such a situation. +Otherwise, the mathlib style guide ask that goals be focused until there is only one active goal +at a time. +If this focusing does not happen, the linter emits a warning. +Typically, the focusing is achieved by the `cdot`: `·`, but, e.g., `focus` or `on_goal x` +also serve a similar purpose. + +TODO: +* Should the linter flag unnecessary scoping as well? + For instance, should + ```lean + example : True := by + · · exact .intro + ``` + raise a warning? +* Custom support for "accumulating side-goals", so that once they are all in scope + they can be solved in bulk via `all_goals` or a similar tactic. +* In development, `on_goal` has been partly used as a way of silencing the linter + precisely to allow the accumulation referred to in the previous item. + Maybe revisit usages of `on_goal` and also nested `induction` and `cases`. +-/ + +open Lean Elab + +namespace Mathlib.Linter + +/-- The "multiGoal" linter emits a warning when there are multiple active goals. -/ +register_option linter.style.multiGoal : Bool := { + defValue := false + descr := "enable the multiGoal linter" +} + +namespace Style.multiGoal + +/-- The `SyntaxNodeKind`s in `exclusions` correspond to tactics that the linter allows, +even though there are multiple active goals. +Reasons for admitting a kind in `exclusions` include +* the tactic focuses on one goal, e.g. `·`, `focus`, `on_goal i =>`, ...; +* the tactic is reordering the goals, e.g. `swap`, `rotate_left`, ...; +* the tactic is structuring a proof, e.g. `skip`, `<;>`, ...; +* the tactic is creating new goals, e.g. `constructor`, `cases`, `induction`, .... + +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 [ + -- structuring a proof + ``Lean.Parser.Term.cdot, + ``cdot, + ``cdotTk, + ``Lean.Parser.Tactic.tacticSeqBracketed, + `«;», + `«<;>», + ``Lean.Parser.Tactic.«tactic_<;>_», + `«{», + `«]», + `null, + `then, + `else, + ``Lean.Parser.Tactic.«tacticNext_=>_», + ``Lean.Parser.Tactic.tacticSeq1Indented, + ``Lean.Parser.Tactic.tacticSeq, + -- re-ordering goals + `Batteries.Tactic.tacticSwap, + ``Lean.Parser.Tactic.rotateLeft, + ``Lean.Parser.Tactic.rotateRight, + ``Lean.Parser.Tactic.skip, + `Batteries.Tactic.«tacticOn_goal-_=>_», + `Mathlib.Tactic.«tacticSwap_var__,,», + -- tactic combinators + ``Lean.Parser.Tactic.tacticRepeat_, + ``Lean.Parser.Tactic.tacticTry_, + -- creating new goals + ``Lean.Parser.Tactic.paren, + ``Lean.Parser.Tactic.case, + ``Lean.Parser.Tactic.constructor, + `Mathlib.Tactic.tacticAssumption', + ``Lean.Parser.Tactic.induction, + ``Lean.Parser.Tactic.cases, + ``Lean.Parser.Tactic.intros, + ``Lean.Parser.Tactic.injections, + ``Lean.Parser.Tactic.substVars, + `Batteries.Tactic.«tacticPick_goal-_», + ``Lean.Parser.Tactic.case', + `«tactic#adaptation_note_», + `tacticSleep_heartbeats_ + ] + +/-- The `SyntaxNodeKind`s in `ignoreBranch` correspond to tactics that disable the linter from +their first application until the corresponding proof branch is closed. +Reasons for ignoring these tactics include +* the linter gets confused by the proof management, e.g. `conv`; +* the tactics are *intended* to act on multiple goals, e.g. `repeat`, `any_goals`, `all_goals`, ... + +There is some overlap in scope between `exclusions` and `ignoreBranch`. +-/ +abbrev ignoreBranch : Std.HashSet SyntaxNodeKind := .ofList [ + ``Lean.Parser.Tactic.Conv.conv, + `Mathlib.Tactic.Conv.convLHS, + `Mathlib.Tactic.Conv.convRHS, + ``Lean.Parser.Tactic.first, + ``Lean.Parser.Tactic.repeat', + ``Lean.Parser.Tactic.tacticIterate____, + ``Lean.Parser.Tactic.anyGoals, + ``Lean.Parser.Tactic.allGoals, + ``Lean.Parser.Tactic.focus, + ``Lean.Parser.Tactic.failIfSuccess, + `Mathlib.Tactic.successIfFailWithMsg + ] + +/-- `getManyGoals t` returns the syntax nodes of the `InfoTree` `t` corresponding to tactic calls +which +* leave at least one goal that was not present before it ran; +* are not excluded through `exclusions` or `ignoreBranch`; + +together with the total number of goals. +-/ +partial +def getManyGoals : InfoTree → Array (Syntax × Nat) + | .node info args => + let kargs := (args.map getManyGoals).toArray.flatten + if let .ofTacticInfo info := info then + if ignoreBranch.contains info.stx.getKind then #[] else + if let .original .. := info.stx.getHeadInfo then + let newGoals := info.goalsAfter.filter (info.goalsBefore.contains ·) + if newGoals.length != 0 && !exclusions.contains info.stx.getKind then + kargs.push (info.stx, newGoals.length) + else kargs + else kargs + else kargs + | .context _ t => getManyGoals t + | _ => default + +@[inherit_doc Mathlib.Linter.linter.style.multiGoal] +def multiGoalLinter : Linter where run := withSetOptionIn fun _stx ↦ do + unless Linter.getLinterValue linter.style.multiGoal (← getOptions) do + return + if (← get).messages.hasErrors then + return + let trees ← getInfoTrees + for t in trees.toArray do + for (s, n) in getManyGoals t do + Linter.logLint linter.style.multiGoal s + m!"There are {n+1} unclosed goals before '{s}' and \ + at least one remaining goal afterwards.\n\ + Please focus on the current goal, for instance using `·` (typed as \"\\.\")." + +initialize addLinter multiGoalLinter + +end Style.multiGoal + +end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/PPRoundtrip.lean b/Mathlib/Tactic/Linter/PPRoundtrip.lean new file mode 100644 index 0000000000000..f6f25280cc338 --- /dev/null +++ b/Mathlib/Tactic/Linter/PPRoundtrip.lean @@ -0,0 +1,144 @@ +/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa +-/ + +import Lean.Elab.Command +import Mathlib.Init + +/-! +# The "ppRoundtrip" linter + +The "ppRoundtrip" linter emits a warning when the syntax of a command differs substantially +from the pretty-printed version of itself. +-/ +open Lean Elab Command + +namespace Mathlib.Linter + +/-- +The "ppRoundtrip" linter emits a warning when the syntax of a command differs substantially +from the pretty-printed version of itself. + +The linter makes an effort to start the highlighting at the first difference. +However, it may not always be successful. +It also prints both the source code and the "expected code" in a 5-character radius from +the first difference. +-/ +register_option linter.ppRoundtrip : Bool := { + defValue := false + descr := "enable the ppRoundtrip linter" +} + +/-- `polishPP s` takes as input a `String` `s`, assuming that it is the output of +pretty-printing a lean command. +The main intent is to convert `s` to a reasonable candidate for a desirable source code format. +The function first replaces consecutive whitespace sequences into a single space (` `), in an +attempt to side-step line-break differences. +After that, it applies some pre-emptive changes: +* doc-module beginnings tend to have some whitespace following them, so we add a space back in; +* name quotations such as ``` ``Nat``` get pretty-printed as ``` `` Nat```, so we remove a space + after double back-ticks, but take care of adding one more for triple (or more) back-ticks; +* `notation3` is not followed by a pretty-printer space, so we add it here (#15515). +-/ +def polishPP (s : String) : String := + let s := s.split (·.isWhitespace) + (" ".intercalate (s.filter (!·.isEmpty))) + |>.replace "/-!" "/-! " + |>.replace "``` " "``` " -- avoid losing an existing space after the triple back-ticks + -- as a consequence of the following replacement + |>.replace "`` " "``" -- weird pp ```#eval ``«Nat»``` pretty-prints as ```#eval `` «Nat»``` + |>.replace "notation3(" "notation3 (" + |>.replace "notation3\"" "notation3 \"" + +/-- `polishSource s` is similar to `polishPP s`, but expects the input to be actual source code. +For this reason, `polishSource s` performs more conservative changes: +it only replace all whitespace starting from a linebreak (`\n`) with a single whitespace. -/ +def polishSource (s : String) : String × Array Nat := + let split := s.split (· == '\n') + 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 s := (split.map .trimLeft).filter (· != "") + (" ".intercalate (s.filter (!·.isEmpty)), preWS) + +/-- `posToShiftedPos lths diff` takes as input an array `lths` of natural numbers, +and one further natural number `diff`. +It adds up the elements of `lths` occupying the odd positions, as long as the sum of the +elements in the even positions does not exceed `diff`. +It returns the sum of the accumulated odds and `diff`. +This is useful to figure out the difference between the output of `polishSource s` and `s` itself. +It plays a role similar to the `fileMap`. -/ +def posToShiftedPos (lths : Array Nat) (diff : Nat) : Nat := Id.run do + let mut (ws, noWS) := (diff, 0) + for con in [:lths.size / 2] do + let curr := lths[2 * con]! + if noWS + curr < diff then + noWS := noWS + curr + ws := ws + lths[2 * con + 1]! + else + break + return ws + +/-- `zoomString str centre offset` returns the substring of `str` consisting of the `offset` +characters around the `centre`th character. -/ +def zoomString (str : String) (centre offset : Nat) : Substring := + { str := str, startPos := ⟨centre - offset⟩, stopPos := ⟨centre + offset⟩ } + +/-- `capSourceInfo s p` "shortens" all end-position information in the `SourceInfo` `s` to be +at most `p`, trimming down also the relevant substrings. -/ +def capSourceInfo (s : SourceInfo) (p : Nat) : SourceInfo := + match s with + | .original leading pos trailing endPos => + .original leading pos {trailing with stopPos := ⟨min endPos.1 p⟩} ⟨min endPos.1 p⟩ + | .synthetic pos endPos canonical => + .synthetic pos ⟨min endPos.1 p⟩ canonical + | .none => s + +/-- `capSyntax stx p` applies `capSourceInfo · s` to all `SourceInfo`s in all +`node`s, `atom`s and `ident`s contained in `stx`. + +This is used to trim away all "fluff" that follows a command: comments and whitespace after +a command get removed with `capSyntax stx stx.getTailPos?.get!`. +-/ +partial +def capSyntax (stx : Syntax) (p : Nat) : Syntax := + match stx with + | .node si k args => .node (capSourceInfo si p) k (args.map (capSyntax · p)) + | .atom si val => .atom (capSourceInfo si p) (val.take p) + | .ident si r v pr => .ident (capSourceInfo si p) { r with stopPos := ⟨min r.stopPos.1 p⟩ } v pr + | s => s + +namespace PPRoundtrip + +@[inherit_doc Mathlib.Linter.linter.ppRoundtrip] +def ppRoundtrip : Linter where run := withSetOptionIn fun stx ↦ do + unless Linter.getLinterValue linter.ppRoundtrip (← getOptions) do + return + if (← MonadState.get).messages.hasErrors then + return + let stx := capSyntax stx (stx.getTailPos?.getD default).1 + let origSubstring := stx.getSubstring?.getD default + let (real, lths) := polishSource origSubstring.toString + let fmt ← (liftCoreM do PrettyPrinter.ppCategory `command stx <|> (do + Linter.logLint linter.ppRoundtrip stx + m!"The ppRoundtrip linter had some parsing issues: \ + feel free to silence it with `set_option linter.ppRoundtrip false in` \ + and report this error!" + return real)) + let st := polishPP fmt.pretty + if st != real then + let diff := real.firstDiffPos st + let pos := posToShiftedPos lths diff.1 + origSubstring.startPos.1 + let f := origSubstring.str.drop (pos) + let extraLth := (f.takeWhile (· != st.get diff)).length + let srcCtxt := zoomString real diff.1 5 + let ppCtxt := zoomString st diff.1 5 + Linter.logLint linter.ppRoundtrip (.ofRange ⟨⟨pos⟩, ⟨pos + extraLth + 1⟩⟩) + m!"source context\n'{srcCtxt}'\n'{ppCtxt}'\npretty-printed context" + +initialize addLinter ppRoundtrip + +end Mathlib.Linter.PPRoundtrip diff --git a/Mathlib/Tactic/Linter/TextBased.lean b/Mathlib/Tactic/Linter/TextBased.lean index b4556c694d081..81ddc7216b380 100644 --- a/Mathlib/Tactic/Linter/TextBased.lean +++ b/Mathlib/Tactic/Linter/TextBased.lean @@ -147,8 +147,10 @@ def compare (existing new : ErrorContext) : ComparisonResult := -- Generally, comparable errors must have equal `StyleError`s, but there are some exceptions. else match (existing.error, new.error) with -- We do *not* care about the *kind* of wrong copyright, - -- nor about the particular length of a too long line. + -- nor about the kind or line number of a duplicate import. | (StyleError.copyright _, StyleError.copyright _) => ComparisonResult.Comparable true + | (StyleError.duplicateImport _ _, StyleError.duplicateImport _ _) => + ComparisonResult.Comparable true -- In all other cases, `StyleErrors` must compare equal. | (a, b) => if a == b then ComparisonResult.Comparable true else ComparisonResult.Different diff --git a/Mathlib/Tactic/Linter/UnusedTactic.lean b/Mathlib/Tactic/Linter/UnusedTactic.lean index 7528d2a53673f..37f23d5e87ded 100644 --- a/Mathlib/Tactic/Linter/UnusedTactic.lean +++ b/Mathlib/Tactic/Linter/UnusedTactic.lean @@ -92,6 +92,8 @@ initialize allowedRef : IO.Ref (Std.HashSet SyntaxNodeKind) ← |>.insert `Mathlib.Tactic.tacticMatch_target_ |>.insert `change? |>.insert `«tactic#adaptation_note_» + |>.insert `tacticSleep_heartbeats_ + |>.insert `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: diff --git a/Mathlib/Tactic/MkIffOfInductiveProp.lean b/Mathlib/Tactic/MkIffOfInductiveProp.lean index 151383da0f1f0..a509a3f017a4c 100644 --- a/Mathlib/Tactic/MkIffOfInductiveProp.lean +++ b/Mathlib/Tactic/MkIffOfInductiveProp.lean @@ -3,7 +3,8 @@ 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, David Renshaw -/ -import Lean +import Lean.Elab.DeclarationRange +import Lean.Meta.Tactic.Cases import Mathlib.Lean.Meta import Mathlib.Lean.Name import Mathlib.Tactic.TypeStar diff --git a/Mathlib/Tactic/Module.lean b/Mathlib/Tactic/Module.lean index 3d0d70d2126ca..fd9b22fd82518 100644 --- a/Mathlib/Tactic/Module.lean +++ b/Mathlib/Tactic/Module.lean @@ -483,7 +483,8 @@ partial def reduceCoefficientwise {R : Q(Type u)} {_ : Q(AddCommMonoid $M)} {_ : let pf : Q(NF.eval $(l₁.toNF) = NF.eval $(l₁.toNF)) := q(rfl) pure ([], pf) /- if one of the lists is empty and the other one is not, recurse down the nonempty one, - forming goals that each of the listed coefficents is equal to zero -/ + forming goals that each of the listed coefficients is equal to + zero -/ | [], ((a, x), _) ::ᵣ L => let mvar : Q((0:$R) = $a) ← mkFreshExprMVar q((0:$R) = $a) let (mvars, pf) ← reduceCoefficientwise iRM [] L @@ -562,8 +563,8 @@ def algebraMapThms : Array Name := #[``eq_natCast, ``eq_intCast, ``eq_ratCast] /-- Postprocessing for the scalar goals constructed in the `match_scalars` and `module` tactics. These goals feature a proliferation of `algebraMap` operations (because the scalars start in `ℕ` and get successively bumped up by `algebraMap`s as new semirings are encountered), so we reinterpret the -most commonly occuring `algebraMap`s (those out of `ℕ`, `ℤ` and `ℚ`) into their standard forms (`ℕ`, -`ℤ` and `ℚ` casts) and then try to disperse the casts using the various `push_cast` lemmas. -/ +most commonly occurring `algebraMap`s (those out of `ℕ`, `ℤ` and `ℚ`) into their standard forms +(`ℕ`, `ℤ` and `ℚ` casts) and then try to disperse the casts using the various `push_cast` lemmas. -/ def postprocess (mvarId : MVarId) : MetaM MVarId := do -- collect the available `push_cast` lemmas let mut thms : SimpTheorems := ← NormCast.pushCastExt.getTheorems diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 094ce46b60265..87cf3bdb6add4 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Damiano Testa -/ import Mathlib.Algebra.Group.Basic +import Mathlib.Lean.Meta /-! diff --git a/Mathlib/Tactic/NormNum/Basic.lean b/Mathlib/Tactic/NormNum/Basic.lean index f2921c511d2d3..f22cd76b3016b 100644 --- a/Mathlib/Tactic/NormNum/Basic.lean +++ b/Mathlib/Tactic/NormNum/Basic.lean @@ -25,6 +25,14 @@ See other files in this directory for many more plugins. universe u +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + namespace Mathlib open Lean hiding Rat mkRat open Meta diff --git a/Mathlib/Tactic/NormNum/Core.lean b/Mathlib/Tactic/NormNum/Core.lean index 2c3834acb555f..16ce0f37ed44d 100644 --- a/Mathlib/Tactic/NormNum/Core.lean +++ b/Mathlib/Tactic/NormNum/Core.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Lean.Expr.Rat import Mathlib.Tactic.NormNum.Result import Mathlib.Util.Qq import Lean.Elab.Tactic.Location @@ -93,7 +94,7 @@ def derive {α : Q(Type u)} (e : Q($α)) (post := false) : MetaM (Result e) := d trace[Tactic.norm_num] "{ext.name}:\n{e} ==> {new}" return new catch err => - trace[Tactic.norm_num] "{e} failed: {err.toMessageData}" + trace[Tactic.norm_num] "{ext.name} failed {e}: {err.toMessageData}" s.restore throwError "{e}: no norm_nums apply" diff --git a/Mathlib/Tactic/NormNum/DivMod.lean b/Mathlib/Tactic/NormNum/DivMod.lean index 821532050c549..2ad7e4703023d 100644 --- a/Mathlib/Tactic/NormNum/DivMod.lean +++ b/Mathlib/Tactic/NormNum/DivMod.lean @@ -13,6 +13,14 @@ This file adds support for the `%`, `/`, and `∣` (divisibility) operators on ` to the `norm_num` tactic. -/ +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + namespace Mathlib open Lean hiding Rat mkRat open Meta diff --git a/Mathlib/Tactic/NormNum/Eq.lean b/Mathlib/Tactic/NormNum/Eq.lean index 3c0cdec603d27..a97a3fd671669 100644 --- a/Mathlib/Tactic/NormNum/Eq.lean +++ b/Mathlib/Tactic/NormNum/Eq.lean @@ -11,6 +11,14 @@ import Mathlib.Tactic.NormNum.Inv variable {α : Type*} +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + open Lean Meta Qq namespace Mathlib.Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/GCD.lean b/Mathlib/Tactic/NormNum/GCD.lean index 55f86434e67e5..1e3b522bdd15a 100644 --- a/Mathlib/Tactic/NormNum/GCD.lean +++ b/Mathlib/Tactic/NormNum/GCD.lean @@ -15,6 +15,14 @@ Note that `Nat.coprime` is reducible and defined in terms of `Nat.gcd`, so the ` also indirectly provides a `Nat.coprime` extension. -/ +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + namespace Tactic namespace NormNum diff --git a/Mathlib/Tactic/NormNum/Ineq.lean b/Mathlib/Tactic/NormNum/Ineq.lean index 987fbd80ced59..b19927601b352 100644 --- a/Mathlib/Tactic/NormNum/Ineq.lean +++ b/Mathlib/Tactic/NormNum/Ineq.lean @@ -13,6 +13,14 @@ import Mathlib.Algebra.Order.Ring.Cast # `norm_num` extensions for inequalities. -/ +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + open Lean Meta Qq namespace Mathlib.Meta.NormNum @@ -108,12 +116,21 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ let ⟨u, α, a⟩ ← inferTypeQ' a have b : Q($α) := b let ra ← derive a; let rb ← derive b + let lα ← synthInstanceQ q(LE $α) + guard <|← withNewMCtxDepth <| isDefEq f q(LE.le (α := $α)) + core lα ra rb +where + /-- Identify (as `true` or `false`) expressions of the form `a ≤ b`, where `a` and `b` are numeric + expressions whose evaluations to `NormNum.Result` have already been computed. -/ + core {u : Level} {α : Q(Type u)} (lα : Q(LE $α)) {a b : Q($α)} + (ra : NormNum.Result a) (rb : NormNum.Result b) : MetaM (NormNum.Result q($a ≤ $b)) := do + let e := q($a ≤ $b) let rec intArm : MetaM (Result e) := do let _i ← inferOrderedRing α - guard <|← withNewMCtxDepth <| isDefEq f q(LE.le (α := $α)) haveI' : $e =Q ($a ≤ $b) := ⟨⟩ let ⟨za, na, pa⟩ ← ra.toInt q(OrderedRing.toRing) let ⟨zb, nb, pb⟩ ← rb.toInt q(OrderedRing.toRing) + assumeInstancesCommute if decide (za ≤ zb) then let r : Q(decide ($na ≤ $nb) = true) := (q(Eq.refl true) : Expr) return .isTrue q(isInt_le_true $pa $pb $r) @@ -125,10 +142,10 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ let rec ratArm : MetaM (Result e) := do -- We need a division ring with an order, and `LinearOrderedField` is the closest mathlib has. let _i ← inferLinearOrderedField α - guard <|← withNewMCtxDepth <| isDefEq f q(LE.le (α := $α)) haveI' : $e =Q ($a ≤ $b) := ⟨⟩ let ⟨qa, na, da, pa⟩ ← ra.toRat' q(Field.toDivisionRing) let ⟨qb, nb, db, pb⟩ ← rb.toRat' q(Field.toDivisionRing) + assumeInstancesCommute if decide (qa ≤ qb) then let r : Q(decide ($na * $db ≤ $nb * $da) = true) := (q(Eq.refl true) : Expr) return (.isTrue q(isRat_le_true $pa $pb $r)) @@ -144,8 +161,8 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ let _i ← inferOrderedSemiring α haveI' : $ra =Q by clear! $ra $rb; infer_instance := ⟨⟩ haveI' : $rb =Q by clear! $ra $rb; infer_instance := ⟨⟩ - guard <|← withNewMCtxDepth <| isDefEq f q(LE.le (α := $α)) haveI' : $e =Q ($a ≤ $b) := ⟨⟩ + assumeInstancesCommute if na.natLit! ≤ nb.natLit! then let r : Q(Nat.ble $na $nb = true) := (q(Eq.refl true) : Expr) return .isTrue q(isNat_le_true $pa $pb $r) @@ -163,13 +180,21 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ let ⟨u, α, a⟩ ← inferTypeQ' a have b : Q($α) := b let ra ← derive a; let rb ← derive b + let lα ← synthInstanceQ q(LT $α) + guard <|← withNewMCtxDepth <| isDefEq f q(LT.lt (α := $α)) + core lα ra rb +where + /-- Identify (as `true` or `false`) expressions of the form `a < b`, where `a` and `b` are numeric + expressions whose evaluations to `NormNum.Result` have already been computed. -/ + core {u : Level} {α : Q(Type u)} (lα : Q(LT $α)) {a b : Q($α)} + (ra : NormNum.Result a) (rb : NormNum.Result b) : MetaM (NormNum.Result q($a < $b)) := do + let e := q($a < $b) let rec intArm : MetaM (Result e) := do let _i ← inferOrderedRing α - assumeInstancesCommute - guard <|← withNewMCtxDepth <| isDefEq f q(LT.lt (α := $α)) haveI' : $e =Q ($a < $b) := ⟨⟩ let ⟨za, na, pa⟩ ← ra.toInt q(OrderedRing.toRing) let ⟨zb, nb, pb⟩ ← rb.toInt q(OrderedRing.toRing) + assumeInstancesCommute if za < zb then if let .some _i ← trySynthInstanceQ (q(@Nontrivial $α) : Q(Prop)) then let r : Q(decide ($na < $nb) = true) := (q(Eq.refl true) : Expr) @@ -184,7 +209,6 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ let _i ← inferLinearOrderedField α assumeInstancesCommute haveI' : $e =Q ($a < $b) := ⟨⟩ - guard <|← withNewMCtxDepth <| isDefEq f q(LT.lt (α := $α)) let ⟨qa, na, da, pa⟩ ← ra.toRat' q(Field.toDivisionRing) let ⟨qb, nb, db, pb⟩ ← rb.toRat' q(Field.toDivisionRing) if qa < qb then @@ -202,7 +226,7 @@ such that `norm_num` successfully recognises both `a` and `b`. -/ haveI' : $ra =Q by clear! $ra $rb; infer_instance := ⟨⟩ haveI' : $rb =Q by clear! $ra $rb; infer_instance := ⟨⟩ haveI' : $e =Q ($a < $b) := ⟨⟩ - guard <|← withNewMCtxDepth <| isDefEq f q(LT.lt (α := $α)) + assumeInstancesCommute if na.natLit! < nb.natLit! then if let .some _i ← trySynthInstanceQ q(CharZero $α) then let r : Q(Nat.ble $nb $na = false) := (q(Eq.refl false) : Expr) diff --git a/Mathlib/Tactic/NormNum/Inv.lean b/Mathlib/Tactic/NormNum/Inv.lean index 5b30fb59f8e8b..b153337b22695 100644 --- a/Mathlib/Tactic/NormNum/Inv.lean +++ b/Mathlib/Tactic/NormNum/Inv.lean @@ -13,6 +13,14 @@ import Mathlib.Algebra.Field.Basic variable {u : Lean.Level} +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + namespace Mathlib.Meta.NormNum open Lean.Meta Qq diff --git a/Mathlib/Tactic/NormNum/IsCoprime.lean b/Mathlib/Tactic/NormNum/IsCoprime.lean index 1b69efa7dc001..abb193758c7a4 100644 --- a/Mathlib/Tactic/NormNum/IsCoprime.lean +++ b/Mathlib/Tactic/NormNum/IsCoprime.lean @@ -46,7 +46,7 @@ def proveIntIsCoprime (ex ey : Q(ℤ)) : Q(IsCoprime $ex $ey) ⊕ Q(¬ IsCoprime /-- Evaluates the `IsCoprime` predicate over `ℤ`. -/ @[norm_num IsCoprime (_ : ℤ) (_ : ℤ)] -def evalIntIsCoprime : NormNumExt where eval {u α} e := do +def evalIntIsCoprime : NormNumExt where eval {_ _} e := do let .app (.app _ (x : Q(ℤ))) (y : Q(ℤ)) ← Meta.whnfR e | failure let ⟨ex, p⟩ ← deriveInt x _ let ⟨ey, q⟩ ← deriveInt y _ diff --git a/Mathlib/Tactic/NormNum/LegendreSymbol.lean b/Mathlib/Tactic/NormNum/LegendreSymbol.lean index dfb3def6ba7c4..166fc060cfcdc 100644 --- a/Mathlib/Tactic/NormNum/LegendreSymbol.lean +++ b/Mathlib/Tactic/NormNum/LegendreSymbol.lean @@ -356,6 +356,14 @@ namespace NormNum open Lean Elab Tactic Qq Mathlib.Meta.NormNum +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + /-- This is the `norm_num` plug-in that evaluates Jacobi symbols. -/ @[norm_num jacobiSym _ _] def evalJacobiSym : NormNumExt where eval {u α} e := do diff --git a/Mathlib/Tactic/NormNum/NatFib.lean b/Mathlib/Tactic/NormNum/NatFib.lean index c1d41a1943975..4ac286c3557e7 100644 --- a/Mathlib/Tactic/NormNum/NatFib.lean +++ b/Mathlib/Tactic/NormNum/NatFib.lean @@ -103,7 +103,7 @@ theorem isNat_fib : {x nx z : ℕ} → IsNat x nx → Nat.fib nx = z → IsNat ( /-- Evaluates the `Nat.fib` function. -/ @[norm_num Nat.fib _] -def evalNatFib : NormNumExt where eval {u α} e := do +def evalNatFib : NormNumExt where eval {_ _} e := do let .app _ (x : Q(ℕ)) ← Meta.whnfR e | failure let sℕ : Q(AddMonoidWithOne ℕ) := q(instAddMonoidWithOneNat) let ⟨ex, p⟩ ← deriveNat x sℕ diff --git a/Mathlib/Tactic/NormNum/NatSqrt.lean b/Mathlib/Tactic/NormNum/NatSqrt.lean index bcdc436d88495..bda1f991d15c4 100644 --- a/Mathlib/Tactic/NormNum/NatSqrt.lean +++ b/Mathlib/Tactic/NormNum/NatSqrt.lean @@ -42,7 +42,7 @@ def proveNatSqrt (ex : Q(ℕ)) : (ey : Q(ℕ)) × Q(Nat.sqrt $ex = $ey) := /-- Evaluates the `Nat.sqrt` function. -/ @[norm_num Nat.sqrt _] -def evalNatSqrt : NormNumExt where eval {u α} e := do +def evalNatSqrt : NormNumExt where eval {_ _} e := do let .app _ (x : Q(ℕ)) ← Meta.whnfR e | failure let sℕ : Q(AddMonoidWithOne ℕ) := q(instAddMonoidWithOneNat) let ⟨ex, p⟩ ← deriveNat x sℕ diff --git a/Mathlib/Tactic/NormNum/Pow.lean b/Mathlib/Tactic/NormNum/Pow.lean index 0744f331ef692..6f238a046d057 100644 --- a/Mathlib/Tactic/NormNum/Pow.lean +++ b/Mathlib/Tactic/NormNum/Pow.lean @@ -10,6 +10,14 @@ import Mathlib.Tactic.NormNum.Basic ## `norm_num` plugin for `^`. -/ +#adaptation_note +/-- +Since https://github.com/leanprover/lean4/pull/5338, +the unused variable linter can not see usages of variables in +`haveI' : ⋯ =Q ⋯ := ⟨⟩` clauses, so generates many false positives. +-/ +set_option linter.unusedVariables false + namespace Mathlib open Lean hiding Rat mkRat open Meta diff --git a/Mathlib/Tactic/NormNum/PowMod.lean b/Mathlib/Tactic/NormNum/PowMod.lean new file mode 100644 index 0000000000000..f50964e19a2b3 --- /dev/null +++ b/Mathlib/Tactic/NormNum/PowMod.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2023 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.Tactic.NormNum.Pow + +/-! +# `norm_num` handling for expressions of the form `a ^ b % m`. + +These expressions can often be evaluated efficiently in cases where first evaluating `a ^ b` and +then reducing mod `m` is not feasible. We provide a function `evalNatPowMod` which is used by the +`reduce_mod_char` tactic to efficiently evaluate powers in rings with positive characteristic. + +The approach taken here is identical to (and copied from) the development in `NormNum/Pow.lean`. + +## TODO + +* Adapt the `norm_num` extensions for `Nat.mod` and `Int.emod` to efficiently evaluate expressions + of the form `a ^ b % m` using `evalNatPowMod`. + +-/ + +set_option autoImplicit true + +namespace Mathlib +open Lean hiding Rat mkRat +open Meta + +namespace Meta.NormNum +open Qq + +/-- Represents and proves equalities of the form `a^b % m = c` for natural numbers. -/ +structure IsNatPowModT (p : Prop) (a b m c : Nat) : Prop where + run' : p → Nat.mod (Nat.pow a b) m = c + +theorem IsNatPowModT.run + (p : IsNatPowModT (Nat.mod (Nat.pow a (nat_lit 1)) m = Nat.mod a m) a b m c) : + Nat.mod (Nat.pow a b) m = c := p.run' (congr_arg (fun x => x % m) (Nat.pow_one a)) + +theorem IsNatPowModT.trans (h1 : IsNatPowModT p a b m c) + (h2 : IsNatPowModT (Nat.mod (Nat.pow a b) m = c) a b' m c') : IsNatPowModT p a b' m c' := + ⟨h2.run' ∘ h1.run'⟩ + +theorem IsNatPowModT.bit0 : + IsNatPowModT (Nat.mod (Nat.pow a b) m = c) a (nat_lit 2 * b) m (Nat.mod (Nat.mul c c) m) := + ⟨fun h1 => by simp only [two_mul, Nat.pow_eq, pow_add, ← h1, Nat.mul_eq]; exact Nat.mul_mod ..⟩ + +theorem natPow_zero_natMod_zero : Nat.mod (Nat.pow a (nat_lit 0)) (nat_lit 0) = nat_lit 1 := by + with_unfolding_all rfl +theorem natPow_zero_natMod_one : Nat.mod (Nat.pow a (nat_lit 0)) (nat_lit 1) = nat_lit 0 := by + with_unfolding_all rfl +theorem natPow_zero_natMod_succ_succ : + Nat.mod (Nat.pow a (nat_lit 0)) (Nat.succ (Nat.succ m)) = nat_lit 1 := by + rw [natPow_zero] + apply Nat.mod_eq_of_lt + exact Nat.one_lt_succ_succ _ +theorem natPow_one_natMod : Nat.mod (Nat.pow a (nat_lit 1)) m = Nat.mod a m := by rw [natPow_one] + +theorem IsNatPowModT.bit1 : + IsNatPowModT (Nat.mod (Nat.pow a b) m = c) a (nat_lit 2 * b + 1) m + (Nat.mod (Nat.mul c (Nat.mod (Nat.mul c a) m)) m) := + ⟨by + rintro rfl + show a ^ (2 * b + 1) % m = (a ^ b % m) * ((a ^ b % m * a) % m) % m + rw [pow_add, two_mul, pow_add, pow_one, Nat.mul_mod (a ^ b % m) a, Nat.mod_mod, + ← Nat.mul_mod (a ^ b) a, ← Nat.mul_mod, mul_assoc]⟩ + +/-- Evaluates and proves `a^b % m` for natural numbers using fast modular exponentiation. -/ +partial def evalNatPowMod (a b m : Q(ℕ)) : (c : Q(ℕ)) × Q(Nat.mod (Nat.pow $a $b) $m = $c) := + if b.natLit! = 0 then + haveI : $b =Q 0 := ⟨⟩ + if m.natLit! = 0 then -- a ^ 0 % 0 = 1 + haveI : $m =Q 0 := ⟨⟩ + ⟨q(nat_lit 1), q(natPow_zero_natMod_zero)⟩ + else + have m' : Q(ℕ) := mkRawNatLit (m.natLit! - 1) + if m'.natLit! = 0 then -- a ^ 0 % 1 = 0 + haveI : $m =Q 1 := ⟨⟩ + ⟨q(nat_lit 0), q(natPow_zero_natMod_one)⟩ + else -- a ^ 0 % m = 1 + have m'' : Q(ℕ) := mkRawNatLit (m'.natLit! - 1) + haveI : $m =Q Nat.succ (Nat.succ $m'') := ⟨⟩ + ⟨q(nat_lit 1), q(natPow_zero_natMod_succ_succ)⟩ + else if b.natLit! = 1 then -- a ^ 1 % m = a % m + have c : Q(ℕ) := mkRawNatLit (a.natLit! % m.natLit!) + haveI : $b =Q 1 := ⟨⟩ + haveI : $c =Q Nat.mod $a $m := ⟨⟩ + ⟨c, q(natPow_one_natMod)⟩ + else + have c₀ : Q(ℕ) := mkRawNatLit (a.natLit! % m.natLit!) + haveI : $c₀ =Q Nat.mod $a $m := ⟨⟩ + let ⟨c, p⟩ := go b.natLit!.log2 a m (mkRawNatLit 1) c₀ b _ .rfl + ⟨c, q(($p).run)⟩ +where + /-- Invariants: `a ^ b₀ % m = c₀`, `depth > 0`, `b >>> depth = b₀` -/ + go (depth : Nat) (a m b₀ c₀ b : Q(ℕ)) + (p : Q(Prop)) (hp : $p =Q (Nat.mod (Nat.pow $a $b₀) $m = $c₀)) : + (c : Q(ℕ)) × Q(IsNatPowModT $p $a $b $m $c) := + let b' := b.natLit! + let m' := m.natLit! + if depth ≤ 1 then + let a' := a.natLit! + let c₀' := c₀.natLit! + if b' &&& 1 == 0 then + have c : Q(ℕ) := mkRawNatLit ((c₀' * c₀') % m') + haveI : $c =Q Nat.mod (Nat.mul $c₀ $c₀) $m := ⟨⟩ + haveI : $b =Q 2 * $b₀ := ⟨⟩ + ⟨c, q(IsNatPowModT.bit0)⟩ + else + have c : Q(ℕ) := mkRawNatLit ((c₀' * ((c₀' * a') % m')) % m') + haveI : $c =Q Nat.mod (Nat.mul $c₀ (Nat.mod (Nat.mul $c₀ $a) $m)) $m := ⟨⟩ + haveI : $b =Q 2 * $b₀ + 1 := ⟨⟩ + ⟨c, q(IsNatPowModT.bit1)⟩ + else + let d := depth >>> 1 + have hi : Q(ℕ) := mkRawNatLit (b' >>> d) + let ⟨c1, p1⟩ := go (depth - d) a m b₀ c₀ hi p (by exact hp) + let ⟨c2, p2⟩ := go d a m hi c1 b q(Nat.mod (Nat.pow $a $hi) $m = $c1) ⟨⟩ + ⟨c2, q(($p1).trans $p2)⟩ +end NormNum +end Meta +end Mathlib diff --git a/Mathlib/Tactic/NormNum/Prime.lean b/Mathlib/Tactic/NormNum/Prime.lean index 4f9a95a5d7158..be12f0e31793f 100644 --- a/Mathlib/Tactic/NormNum/Prime.lean +++ b/Mathlib/Tactic/NormNum/Prime.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Tactic.NormNum.Basic -import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.Prime.Basic /-! # `norm_num` extensions on natural numbers @@ -118,7 +118,7 @@ theorem isNat_minFac_4 : {n n' k : ℕ} → /-- The `norm_num` extension which identifies expressions of the form `minFac n`. -/ @[norm_num Nat.minFac _] partial def evalMinFac : - NormNumExt where eval {u α} e := do + NormNumExt where eval {_ _} e := do let .app (.const ``Nat.minFac _) (n : Q(ℕ)) ← whnfR e | failure let sℕ : Q(AddMonoidWithOne ℕ) := q(instAddMonoidWithOneNat) let ⟨nn, pn⟩ ← deriveNat n sℕ @@ -175,7 +175,7 @@ theorem isNat_prime_2 : {n n' : ℕ} → theorem isNat_not_prime {n n' : ℕ} (h : IsNat n n') : ¬n'.Prime → ¬n.Prime := isNat.natElim h /-- The `norm_num` extension which identifies expressions of the form `Nat.Prime n`. -/ -@[norm_num Nat.Prime _] def evalNatPrime : NormNumExt where eval {u α} e := do +@[norm_num Nat.Prime _] def evalNatPrime : NormNumExt where eval {_ _} e := do let .app (.const `Nat.Prime _) (n : Q(ℕ)) ← whnfR e | failure let ⟨nn, pn⟩ ← deriveNat n _ let n' := nn.natLit! diff --git a/Mathlib/Tactic/PPWithUniv.lean b/Mathlib/Tactic/PPWithUniv.lean index ad26e61447be9..f8ab6d21522db 100644 --- a/Mathlib/Tactic/PPWithUniv.lean +++ b/Mathlib/Tactic/PPWithUniv.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ import Mathlib.Init -import Lean /-! # Attribute to pretty-print universe level parameters by default diff --git a/Mathlib/Tactic/Polyrith.lean b/Mathlib/Tactic/Polyrith.lean index f20d12e722d99..b6da0ce70e38b 100644 --- a/Mathlib/Tactic/Polyrith.lean +++ b/Mathlib/Tactic/Polyrith.lean @@ -3,7 +3,6 @@ Copyright (c) 2022 Dhruv Bhatia. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Dhruv Bhatia, Eric Wieser, Mario Carneiro -/ -import Mathlib.Algebra.Order.Field.Rat import Mathlib.Tactic.LinearCombination /-! @@ -392,7 +391,6 @@ Notes: Many thanks to the Sage team and organization for allowing this use. * This tactic assumes that the user has `python3` installed and available on the path. (Test by opening a terminal and executing `python3 --version`.) - It also assumes that the `requests` library is installed: `python3 -m pip install requests`. Examples: diff --git a/Mathlib/Tactic/Positivity/Basic.lean b/Mathlib/Tactic/Positivity/Basic.lean index 44f3d57c3fec7..6d1cf31d771de 100644 --- a/Mathlib/Tactic/Positivity/Basic.lean +++ b/Mathlib/Tactic/Positivity/Basic.lean @@ -159,16 +159,16 @@ such that `positivity` successfully recognises both `a` and `b`. -/ let ra ← core zα pα a; let rb ← core zα pα b match ra, rb with | .positive pa, .positive pb => - let _a ← synthInstanceQ (q(CovariantClass $α $α (·+·) (·<·)) : Q(Prop)) + let _a ← synthInstanceQ (q(AddLeftStrictMono $α) : Q(Prop)) pure (.positive q(add_pos $pa $pb)) | .positive pa, .nonnegative pb => - let _a ← synthInstanceQ (q(CovariantClass $α $α (swap (·+·)) (·<·)) : Q(Prop)) + let _a ← synthInstanceQ (q(AddRightStrictMono $α) : Q(Prop)) pure (.positive q(lt_add_of_pos_of_le $pa $pb)) | .nonnegative pa, .positive pb => - let _a ← synthInstanceQ (q(CovariantClass $α $α (·+·) (·<·)) : Q(Prop)) + let _a ← synthInstanceQ (q(AddLeftStrictMono $α) : Q(Prop)) pure (.positive q(lt_add_of_le_of_pos $pa $pb)) | .nonnegative pa, .nonnegative pb => - let _a ← synthInstanceQ (q(CovariantClass $α $α (·+·) (·≤·)) : Q(Prop)) + let _a ← synthInstanceQ (q(AddLeftMono $α) : Q(Prop)) pure (.nonnegative q(add_nonneg $pa $pb)) | _, _ => failure @@ -304,7 +304,7 @@ def evalPow : PositivityExt where eval {u α} zα pα e := do | .none => pure .none private theorem abs_pos_of_ne_zero {α : Type*} [AddGroup α] [LinearOrder α] - [CovariantClass α α (·+·) (·≤·)] {a : α} : a ≠ 0 → 0 < |a| := abs_pos.mpr + [AddLeftMono α] {a : α} : a ≠ 0 → 0 < |a| := abs_pos.mpr /-- The `positivity` extension which identifies expressions of the form `|a|`. -/ @[positivity |_|] @@ -500,9 +500,11 @@ def evalRatDen : PositivityExt where eval {u α} _ _ e := do /-- Extension for `posPart`. `a⁺` is always nonegative, and positive if `a` is. -/ @[positivity _⁺] -def evalPosPart : PositivityExt where eval zα pα e := do +def evalPosPart : PositivityExt where eval {u α} zα pα e := do match e with - | ~q(@posPart _ $instαlat $instαgrp $a) => + | ~q(@posPart _ $instαpospart $a) => + let _instαlat ← synthInstanceQ q(Lattice $α) + let _instαgrp ← synthInstanceQ q(AddGroup $α) assertInstancesCommute -- FIXME: There seems to be a bug in `Positivity.core` that makes it fail (instead of returning -- `.none`) here sometimes. See eg the first test for `posPart`. This is why we need `catchNone` @@ -513,9 +515,11 @@ def evalPosPart : PositivityExt where eval zα pα e := do /-- Extension for `negPart`. `a⁻` is always nonegative. -/ @[positivity _⁻] -def evalNegPart : PositivityExt where eval _ _ e := do +def evalNegPart : PositivityExt where eval {u α} _ _ e := do match e with - | ~q(@negPart _ $instαlat $instαgrp $a) => + | ~q(@negPart _ $instαnegpart $a) => + let _instαlat ← synthInstanceQ q(Lattice $α) + let _instαgrp ← synthInstanceQ q(AddGroup $α) assertInstancesCommute return .nonnegative q(negPart_nonneg $a) | _ => throwError "not `negPart`" diff --git a/Mathlib/Tactic/Positivity/Finset.lean b/Mathlib/Tactic/Positivity/Finset.lean index 6326f5d927658..fdfd20e10b554 100644 --- a/Mathlib/Tactic/Positivity/Finset.lean +++ b/Mathlib/Tactic/Positivity/Finset.lean @@ -3,7 +3,9 @@ Copyright (c) 2023 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ +import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Data.Finset.Density +import Mathlib.Tactic.NormNum.Basic import Mathlib.Tactic.Positivity.Core /-! @@ -18,7 +20,7 @@ namespace Mathlib.Meta.Positivity open Qq Lean Meta Finset -/-- Extension for `Finset.card`. `s.card` is positive if `s` is nonempty. +/-- Extension for `Finset.card`. `#s` is positive if `s` is nonempty. It calls `Mathlib.Meta.proveFinsetNonempty` to attempt proving that the finset is nonempty. -/ @[positivity Finset.card _] @@ -40,7 +42,7 @@ def evalFintypeCard : PositivityExt where eval {u α} _ _ e := do return .positive q(@Fintype.card_pos $β $instβ $instβno) | _ => throwError "not Fintype.card" -/-- Extension for `Finset.dens`. `s.card` is positive if `s` is nonempty. +/-- Extension for `Finset.dens`. `s.dens` is positive if `s` is nonempty. It calls `Mathlib.Meta.proveFinsetNonempty` to attempt proving that the finset is nonempty. -/ @[positivity Finset.dens _] @@ -52,10 +54,45 @@ def evalFinsetDens : PositivityExt where eval {u 𝕜} _ _ e := do return .positive q(@Nonempty.dens_pos $α $instα $s $ps) | _, _, _ => throwError "not Finset.dens" +/-- The `positivity` extension which proves that `∑ i ∈ s, f i` is nonnegative if `f` is, and +positive if each `f i` is and `s` is nonempty. + +TODO: The following example does not work +``` +example (s : Finset ℕ) (f : ℕ → ℤ) (hf : ∀ n, 0 ≤ f n) : 0 ≤ s.sum f := by positivity +``` +because `compareHyp` can't look for assumptions behind binders. +-/ +@[positivity Finset.sum _ _] +def evalFinsetSum : PositivityExt where eval {u α} zα pα e := do + match e with + | ~q(@Finset.sum $ι _ $instα $s $f) => + let i : Q($ι) ← mkFreshExprMVarQ q($ι) .syntheticOpaque + have body : Q($α) := .betaRev f #[i] + let rbody ← core zα pα body + let p_pos : Option Q(0 < $e) := ← (do + let .positive pbody := rbody | pure none -- Fail if the body is not provably positive + let .some ps ← proveFinsetNonempty s | pure none + let .some pα' ← trySynthInstanceQ q(OrderedCancelAddCommMonoid $α) | pure none + assertInstancesCommute + let pr : Q(∀ i, 0 < $f i) ← mkLambdaFVars #[i] pbody + return some q(@sum_pos $ι $α $pα' $f $s (fun i _ ↦ $pr i) $ps)) + -- Try to show that the sum is positive + if let some p_pos := p_pos then + return .positive p_pos + -- Fall back to showing that the sum is nonnegative + else + let pbody ← rbody.toNonneg + let pr : Q(∀ i, 0 ≤ $f i) ← mkLambdaFVars #[i] pbody + let pα' ← synthInstanceQ q(OrderedAddCommMonoid $α) + assertInstancesCommute + return .nonnegative q(@sum_nonneg $ι $α $pα' $f $s fun i _ ↦ $pr i) + | _ => throwError "not Finset.sum" + variable {α : Type*} {s : Finset α} -example : 0 ≤ s.card := by positivity -example (hs : s.Nonempty) : 0 < s.card := by positivity +example : 0 ≤ #s := by positivity +example (hs : s.Nonempty) : 0 < #s := by positivity variable [Fintype α] @@ -63,13 +100,13 @@ example : 0 ≤ Fintype.card α := by positivity example : 0 ≤ dens s := by positivity example (hs : s.Nonempty) : 0 < dens s := by positivity example (hs : s.Nonempty) : dens s ≠ 0 := by positivity -example [Nonempty α] : 0 < (univ : Finset α).card := by positivity +example [Nonempty α] : 0 < #(univ : Finset α) := by positivity example [Nonempty α] : 0 < Fintype.card α := by positivity example [Nonempty α] : 0 < dens (univ : Finset α) := by positivity example [Nonempty α] : dens (univ : Finset α) ≠ 0 := by positivity example {G : Type*} {A : Finset G} : - let f := fun _ : G ↦ 1; (∀ s, f s ^ 2 = 1) → 0 ≤ A.card := by + let f := fun _ : G ↦ 1; (∀ s, f s ^ 2 = 1) → 0 ≤ #A := by intros positivity -- Should succeed despite failing to prove `A` is nonempty. diff --git a/Mathlib/Tactic/ProjectionNotation.lean b/Mathlib/Tactic/ProjectionNotation.lean index d56a57bf0f447..6c9e5c80d3883 100644 --- a/Mathlib/Tactic/ProjectionNotation.lean +++ b/Mathlib/Tactic/ProjectionNotation.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Lean.Elab.AuxDef import Mathlib.Init -import Lean /-! # Pretty printing projection notation diff --git a/Mathlib/Tactic/ProxyType.lean b/Mathlib/Tactic/ProxyType.lean index 049a25a2ae59f..0722e80c40878 100644 --- a/Mathlib/Tactic/ProxyType.lean +++ b/Mathlib/Tactic/ProxyType.lean @@ -3,7 +3,6 @@ Copyright (c) 2023 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ -import Lean import Mathlib.Tactic.Core import Mathlib.Logic.Equiv.Defs diff --git a/Mathlib/Tactic/Recover.lean b/Mathlib/Tactic/Recover.lean index abae8c5304d60..1ea7db1987f97 100644 --- a/Mathlib/Tactic/Recover.lean +++ b/Mathlib/Tactic/Recover.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner, Siddhartha Gadgil, Jannis Limperg -/ import Mathlib.Init -import Lean /-! # The `recover` tactic modifier diff --git a/Mathlib/Tactic/ReduceModChar.lean b/Mathlib/Tactic/ReduceModChar.lean index 8a3886895ef48..859630e1b3a4f 100644 --- a/Mathlib/Tactic/ReduceModChar.lean +++ b/Mathlib/Tactic/ReduceModChar.lean @@ -6,6 +6,7 @@ Authors: Anne Baanen import Mathlib.Data.ZMod.Basic import Mathlib.RingTheory.Polynomial.Basic import Mathlib.Tactic.NormNum.DivMod +import Mathlib.Tactic.NormNum.PowMod import Mathlib.Tactic.ReduceModChar.Ext /-! @@ -44,26 +45,62 @@ open Mathlib.Meta.NormNum variable {u : Level} +lemma CharP.isInt_of_mod {e' r : ℤ} {α : Type*} [Ring α] {n n' : ℕ} (inst : CharP α n) {e : α} + (he : IsInt e e') (hn : IsNat n n') (h₂ : IsInt (e' % n') r) : IsInt e r := + ⟨by rw [he.out, CharP.intCast_eq_intCast_mod α n, show n = n' from hn.out, h₂.out, Int.cast_id]⟩ + +lemma CharP.isNat_pow {α} [Semiring α] : ∀ {f : α → ℕ → α} {a : α} {a' b b' c n n' : ℕ}, + CharP α n → f = HPow.hPow → IsNat a a' → IsNat b b' → IsNat n n' → + Nat.mod (Nat.pow a' b') n' = c → IsNat (f a b) c + | _, _, a, _, b, _, _, n, _, rfl, ⟨h⟩, ⟨rfl⟩, ⟨rfl⟩, rfl => ⟨by + rw [h, Nat.cast_id, Nat.pow_eq, ← Nat.cast_pow, CharP.natCast_eq_natCast_mod α n] + rfl⟩ + +/-- Evaluates `e` to an integer using `norm_num` and reduces the result modulo `n`. -/ +def normBareNumeral {α : Q(Type u)} (n n' : Q(ℕ)) (pn : Q(IsNat «$n» «$n'»)) + (e : Q($α)) (_ : Q(Ring $α)) (instCharP : Q(CharP $α $n)) : MetaM (Result e) := do + let ⟨ze, ne, pe⟩ ← Result.toInt _ (← Mathlib.Meta.NormNum.derive e) + let rr ← evalIntMod.go _ _ ze q(IsInt.raw_refl $ne) _ <| + .isNat q(instAddMonoidWithOne) _ q(isNat_natCast _ _ (IsNat.raw_refl $n')) + let ⟨zr, nr, pr⟩ ← rr.toInt _ + return .isInt _ nr zr q(CharP.isInt_of_mod $instCharP $pe $pn $pr) + +mutual + + /-- Given an expression of the form `a ^ b` in a ring of characteristic `n`, reduces `a` + modulo `n` recursively and then calculates `a ^ b` using fast modular exponentiation. -/ + partial def normPow {α : Q(Type u)} (n n' : Q(ℕ)) (pn : Q(IsNat «$n» «$n'»)) (e : Q($α)) + (_ : Q(Ring $α)) (instCharP : Q(CharP $α $n)) : MetaM (Result e) := do + let .app (.app (f : Q($α → ℕ → $α)) (a : Q($α))) (b : Q(ℕ)) ← whnfR e | failure + let .isNat sα na pa ← normIntNumeral' n n' pn a _ instCharP | failure + let ⟨nb, pb⟩ ← Mathlib.Meta.NormNum.deriveNat b q(instAddMonoidWithOneNat) + guard <|← withNewMCtxDepth <| isDefEq f q(HPow.hPow (α := $α)) + haveI' : $e =Q $a ^ $b := ⟨⟩ + haveI' : $f =Q HPow.hPow := ⟨⟩ + have ⟨c, r⟩ := evalNatPowMod na nb n' + assumeInstancesCommute + return .isNat sα c q(CharP.isNat_pow (f := $f) $instCharP (.refl $f) $pa $pb $pn $r) + + /-- If `e` is of the form `a ^ b`, reduce it using fast modular exponentation, otherwise + reduce it using `norm_num`. -/ + partial def normIntNumeral' {α : Q(Type u)} (n n' : Q(ℕ)) (pn : Q(IsNat «$n» «$n'»)) + (e : Q($α)) (_ : Q(Ring $α)) (instCharP : Q(CharP $α $n)) : MetaM (Result e) := + normPow n n' pn e _ instCharP <|> normBareNumeral n n' pn e _ instCharP + +end + lemma CharP.intCast_eq_mod (R : Type _) [Ring R] (p : ℕ) [CharP R p] (k : ℤ) : (k : R) = (k % p : ℤ) := by calc (k : R) = ↑(k % p + p * (k / p)) := by rw [Int.emod_add_ediv] _ = ↑(k % p) := by simp [CharP.cast_eq_zero R] -lemma CharP.isInt_of_mod {e' r : ℤ} {α : Type _} [Ring α] {n n' : ℕ} (inst : CharP α n) {e : α} - (he : IsInt e e') (hn : IsNat n n') (h₂ : IsInt (e' % n') r) : IsInt e r := - ⟨by rw [he.out, CharP.intCast_eq_mod α n, show n = n' from hn.out, h₂.out, Int.cast_id]⟩ - /-- Given an integral expression `e : t` such that `t` is a ring of characteristic `n`, reduce `e` modulo `n`. -/ -partial def normIntNumeral {α : Q(Type u)} (n : Q(ℕ)) (e : Q($α)) (instRing : Q(Ring $α)) +partial def normIntNumeral {α : Q(Type u)} (n : Q(ℕ)) (e : Q($α)) (_ : Q(Ring $α)) (instCharP : Q(CharP $α $n)) : MetaM (Result e) := do - let ⟨ze, ne, pe⟩ ← Result.toInt instRing (← Mathlib.Meta.NormNum.derive e) let ⟨n', pn⟩ ← deriveNat n q(instAddMonoidWithOneNat) - let rr ← evalIntMod.go _ _ ze q(IsInt.raw_refl $ne) _ <| - .isNat q(instAddMonoidWithOne) _ q(isNat_natCast _ _ (IsNat.raw_refl $n')) - let ⟨zr, nr, pr⟩ ← rr.toInt q(Int.instRing) - return .isInt instRing nr zr q(CharP.isInt_of_mod $instCharP $pe $pn $pr) + normIntNumeral' n n' pn e _ instCharP lemma CharP.neg_eq_sub_one_mul {α : Type _} [Ring α] (n : ℕ) (inst : CharP α n) (b : α) (a : ℕ) (a' : α) (p : IsNat (n - 1 : α) a) (pa : a = a') : diff --git a/Mathlib/Tactic/Relation/Trans.lean b/Mathlib/Tactic/Relation/Trans.lean deleted file mode 100644 index 290d23e9aeb70..0000000000000 --- a/Mathlib/Tactic/Relation/Trans.lean +++ /dev/null @@ -1,222 +0,0 @@ -/- -Copyright (c) 2022 Siddhartha Gadgil. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Siddhartha Gadgil, Mario Carneiro --/ -import Mathlib.Lean.Meta -import Mathlib.Lean.Elab.Tactic.Basic -import Lean.Elab.Tactic.ElabTerm -import Mathlib.Tactic.TypeStar - -/-! -# `trans` tactic - -This implements the `trans` tactic, which can apply transitivity theorems with an optional middle -variable argument. --/ - -namespace Mathlib.Tactic -open Lean Meta Elab - -initialize registerTraceClass `Tactic.trans - -/-- Discrimation tree settings for the `trans` extension. -/ -def transExt.config : WhnfCoreConfig := {} - -/-- Environment extension storing transitivity lemmas -/ -initialize transExt : - SimpleScopedEnvExtension (Name × Array DiscrTree.Key) (DiscrTree Name) ← - registerSimpleScopedEnvExtension { - addEntry := fun dt (n, ks) ↦ dt.insertCore ks n - initial := {} - } - -initialize registerBuiltinAttribute { - name := `trans - descr := "transitive relation" - add := fun decl _ kind ↦ MetaM.run' do - let declTy := (← getConstInfo decl).type - let (xs, _, targetTy) ← withReducible <| forallMetaTelescopeReducing declTy - let fail := throwError - "@[trans] attribute only applies to lemmas proving - x ∼ y → y ∼ z → x ∼ z, got {indentExpr declTy} with target {indentExpr targetTy}" - let .app (.app rel _) _ := targetTy | fail - let some yzHyp := xs.back? | fail - let some xyHyp := xs.pop.back? | fail - let .app (.app _ _) _ ← inferType yzHyp | fail - let .app (.app _ _) _ ← inferType xyHyp | fail - let key ← withReducible <| DiscrTree.mkPath rel transExt.config - transExt.add (decl, key) kind -} - -universe u v in -/-- Composition using the `Trans` class in the homogeneous case. -/ -def _root_.Trans.simple {α : Sort u} {r : α → α → Sort v} {a b c : α} [Trans r r r] : - r a b → r b c → r a c := trans - -universe u v w in -/-- Composition using the `Trans` class in the general case. -/ -def _root_.Trans.het {α β γ : Sort*} {a : α} {b : β} {c : γ} - {r : α → β → Sort u} {s : β → γ → Sort v} {t : outParam (α → γ → Sort w)} [Trans r s t] : - r a b → s b c → t a c := trans - -open Lean.Elab.Tactic - -/-- solving `e ← mkAppM' f #[x]` -/ -def getExplicitFuncArg? (e : Expr) : MetaM (Option <| Expr × Expr) := do - match e with - | Expr.app f a => do - if ← isDefEq (← mkAppM' f #[a]) e then - return some (f, a) - else - getExplicitFuncArg? f - | _ => return none - -/-- solving `tgt ← mkAppM' rel #[x, z]` given `tgt = f z` -/ -def getExplicitRelArg? (tgt f z : Expr) : MetaM (Option <| Expr × Expr) := do - match f with - | Expr.app rel x => do - let check: Bool ← do - try - let folded ← mkAppM' rel #[x, z] - isDefEq folded tgt - catch _ => - pure false - if check then - return some (rel, x) - else - getExplicitRelArg? tgt rel z - | _ => return none - -/-- refining `tgt ← mkAppM' rel #[x, z]` dropping more arguments if possible -/ -def getExplicitRelArgCore (tgt rel x z : Expr) : MetaM (Expr × Expr) := do - match rel with - | Expr.app rel' _ => do - let check: Bool ← do - try - let folded ← mkAppM' rel' #[x, z] - isDefEq folded tgt - catch _ => - pure false - if !check then - return (rel, x) - else - getExplicitRelArgCore tgt rel' x z - | _ => return (rel ,x) - -/-- Internal definition for `trans` tactic. Either a binary relation or a non-dependent -arrow. -/ -inductive TransRelation - | app (rel : Expr) - | implies (name : Name) (bi : BinderInfo) - -/-- Finds an explicit binary relation in the argument, if possible. -/ -def getRel (tgt : Expr) : MetaM (Option (TransRelation × Expr × Expr)) := do - match tgt with - | .forallE name binderType body info => return .some (.implies name info, binderType, body) - | .app f z => - match (← getExplicitRelArg? tgt f z) with - | some (rel, x) => - let (rel, x) ← getExplicitRelArgCore tgt rel x z - return some (.app rel, x, z) - | none => - return none - | _ => return none - -/-- -`trans` applies to a goal whose target has the form `t ~ u` where `~` is a transitive relation, -that is, a relation which has a transitivity lemma tagged with the attribute [trans]. - -* `trans s` replaces the goal with the two subgoals `t ~ s` and `s ~ u`. -* If `s` is omitted, then a metavariable is used instead. - -Additionally, `trans` also applies to a goal whose target has the form `t → u`, -in which case it replaces the goal with `t → s` and `s → u`. --/ -elab "trans" t?:(ppSpace colGt term)? : tactic => withMainContext do - let tgt ← getMainTarget'' - let .some (rel, x, z) ← getRel tgt | - throwError (m!"transitivity lemmas only apply to binary relations and " ++ - m!"non-dependent arrows, not {indentExpr tgt}") - match rel with - | .implies name info => - -- only consider non-dependent arrows - if z.hasLooseBVars then - throwError "`trans` is not implemented for dependent arrows{indentExpr tgt}" - -- parse the intermeditate term - let middleType ← mkFreshExprMVar none - let t'? ← t?.mapM (elabTermWithHoles · middleType (← getMainTag)) - let middle ← (t'?.map (pure ·.1)).getD (mkFreshExprMVar middleType) - liftMetaTactic fun goal => do - -- create two new goals - let g₁ ← mkFreshExprMVar (some <| .forallE name x middle info) .synthetic - let g₂ ← mkFreshExprMVar (some <| .forallE name middle z info) .synthetic - -- close the original goal with `fun x => g₂ (g₁ x)` - goal.assign (.lam name x (.app g₂ (.app g₁ (.bvar 0))) .default) - pure <| [g₁.mvarId!, g₂.mvarId!] ++ if let some (_, gs') := t'? then gs' else [middle.mvarId!] - return - | .app rel => - trace[Tactic.trans]"goal decomposed" - trace[Tactic.trans]"rel: {indentExpr rel}" - trace[Tactic.trans]"x: {indentExpr x}" - trace[Tactic.trans]"z: {indentExpr z}" - -- first trying the homogeneous case - try - let ty ← inferType x - let t'? ← t?.mapM (elabTermWithHoles · ty (← getMainTag)) - let s ← saveState - trace[Tactic.trans]"trying homogeneous case" - let lemmas := - (← (transExt.getState (← getEnv)).getUnify rel transExt.config).push ``Trans.simple - for lem in lemmas do - trace[Tactic.trans]"trying lemma {lem}" - try - liftMetaTactic fun g ↦ do - let lemTy ← inferType (← mkConstWithLevelParams lem) - let arity ← withReducible <| forallTelescopeReducing lemTy fun es _ ↦ pure es.size - let y ← (t'?.map (pure ·.1)).getD (mkFreshExprMVar ty) - let g₁ ← mkFreshExprMVar (some <| ← mkAppM' rel #[x, y]) .synthetic - let g₂ ← mkFreshExprMVar (some <| ← mkAppM' rel #[y, z]) .synthetic - g.assign (← mkAppOptM lem (mkArray (arity - 2) none ++ #[some g₁, some g₂])) - pure <| [g₁.mvarId!, g₂.mvarId!] ++ - if let some (_, gs') := t'? then gs' else [y.mvarId!] - return - catch _ => s.restore - pure () - catch _ => - trace[Tactic.trans]"trying heterogeneous case" - let t'? ← t?.mapM (elabTermWithHoles · none (← getMainTag)) - let s ← saveState - for lem in (← (transExt.getState (← getEnv)).getUnify rel transExt.config).push - ``HEq.trans |>.push ``HEq.trans do - try - liftMetaTactic fun g ↦ do - trace[Tactic.trans]"trying lemma {lem}" - let lemTy ← inferType (← mkConstWithLevelParams lem) - let arity ← withReducible <| forallTelescopeReducing lemTy fun es _ ↦ pure es.size - trace[Tactic.trans]"arity: {arity}" - trace[Tactic.trans]"lemma-type: {lemTy}" - let y ← (t'?.map (pure ·.1)).getD (mkFreshExprMVar none) - trace[Tactic.trans]"obtained y: {y}" - trace[Tactic.trans]"rel: {indentExpr rel}" - trace[Tactic.trans]"x:{indentExpr x}" - trace[Tactic.trans]"z: {indentExpr z}" - let g₂ ← mkFreshExprMVar (some <| ← mkAppM' rel #[y, z]) .synthetic - trace[Tactic.trans]"obtained g₂: {g₂}" - let g₁ ← mkFreshExprMVar (some <| ← mkAppM' rel #[x, y]) .synthetic - trace[Tactic.trans]"obtained g₁: {g₁}" - g.assign (← mkAppOptM lem (mkArray (arity - 2) none ++ #[some g₁, some g₂])) - pure <| [g₁.mvarId!, g₂.mvarId!] ++ if let some (_, gs') := t'? then gs' else [y.mvarId!] - return - catch e => - trace[Tactic.trans]"failed: {e.toMessageData}" - s.restore - throwError m!"no applicable transitivity lemma found for {indentExpr tgt}" - -syntax "transitivity" (ppSpace colGt term)? : tactic -set_option hygiene false in -macro_rules - | `(tactic| transitivity) => `(tactic| trans) - | `(tactic| transitivity $e) => `(tactic| trans $e) - -end Mathlib.Tactic diff --git a/Mathlib/Tactic/Rename.lean b/Mathlib/Tactic/Rename.lean index 207f568849012..5d56eda7db2d6 100644 --- a/Mathlib/Tactic/Rename.lean +++ b/Mathlib/Tactic/Rename.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Lean.Elab.Tactic.ElabTerm import Mathlib.Init -import Lean /-! # The `rename'` tactic diff --git a/Mathlib/Tactic/RenameBVar.lean b/Mathlib/Tactic/RenameBVar.lean index fe1706f2eacfc..f1b7e26041efa 100644 --- a/Mathlib/Tactic/RenameBVar.lean +++ b/Mathlib/Tactic/RenameBVar.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Patrick Massot -/ -import Lean +import Lean.Elab.Tactic.Location import Mathlib.Util.Tactic import Mathlib.Lean.Expr.Basic @@ -29,13 +29,13 @@ def renameBVarTarget (mvarId : MVarId) (old new : Name) : MetaM Unit := modifyTarget mvarId fun e ↦ e.renameBVar old new /-- -* `rename_bvar old new` renames all bound variables named `old` to `new` in the target. -* `rename_bvar old new at h` does the same in hypothesis `h`. +* `rename_bvar old → new` renames all bound variables named `old` to `new` in the target. +* `rename_bvar old → new at h` does the same in hypothesis `h`. ```lean example (P : ℕ → ℕ → Prop) (h : ∀ n, ∃ m, P n m) : ∀ l, ∃ m, P l m := by - rename_bvar n q at h -- h is now ∀ (q : ℕ), ∃ (m : ℕ), P q m, - rename_bvar m n -- target is now ∀ (l : ℕ), ∃ (n : ℕ), P k n, + rename_bvar n → q at h -- h is now ∀ (q : ℕ), ∃ (m : ℕ), P q m, + rename_bvar m → n -- target is now ∀ (l : ℕ), ∃ (n : ℕ), P k n, exact h -- Lean does not care about those bound variable names ``` Note: name clashes are resolved automatically. diff --git a/Mathlib/Tactic/Ring/Basic.lean b/Mathlib/Tactic/Ring/Basic.lean index dcd4f4ddf5f6f..b25109521ba02 100644 --- a/Mathlib/Tactic/Ring/Basic.lean +++ b/Mathlib/Tactic/Ring/Basic.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, Aurélien Saue, Anne Baanen -/ -import Mathlib.Algebra.Order.Ring.Rat import Mathlib.Tactic.NormNum.Inv import Mathlib.Tactic.NormNum.Pow import Mathlib.Util.AtomM @@ -75,6 +74,8 @@ This feature wasn't needed yet, so it's not implemented yet. ring, semiring, exponent, power -/ +assert_not_exists OrderedAddCommMonoid + namespace Mathlib.Tactic namespace Ring @@ -885,7 +886,7 @@ def evalPow {a : Q($α)} {b : Q(ℕ)} (va : ExSum sα a) (vb : ExSum sℕ b) : return ⟨_, vd, q(pow_add $pc₁ $pc₂ $pd)⟩ /-- This cache contains data required by the `ring` tactic during execution. -/ -structure Cache {α : Q(Type u)} (sα : Q(CommSemiring $α)) := +structure Cache {α : Q(Type u)} (sα : Q(CommSemiring $α)) where /-- A ring instance on `α`, if available. -/ rα : Option Q(Ring $α) /-- A division ring instance on `α`, if available. -/ diff --git a/Mathlib/Tactic/Ring/Compare.lean b/Mathlib/Tactic/Ring/Compare.lean new file mode 100644 index 0000000000000..967a8599abab2 --- /dev/null +++ b/Mathlib/Tactic/Ring/Compare.lean @@ -0,0 +1,239 @@ +/- +Copyright (c) 2024 Heather Macbeth. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Heather Macbeth +-/ +import Mathlib.Tactic.Ring.Basic +import Mathlib.Tactic.NormNum.Ineq + +/-! +# Automation for proving inequalities in commutative (semi)rings + +This file provides automation for proving certain kinds of inequalities in commutative semirings: +goals of the form `A ≤ B` and `A < B` for which the ring-normal forms of `A` and `B` differ by a +nonnegative (resp. positive) constant. + +For example, `⊢ x + 3 + y < y + x + 4` is in scope because the normal forms of the LHS and RHS are, +respectively, `3 + (x + y)` and `4 + (x + y)`, which differ by an additive constant. + +## Main declarations + +* `Mathlib.Tactic.Ring.proveLE`: prove goals of the form `A ≤ B` (subject to the scope constraints + described) +* `Mathlib.Tactic.Ring.proveLT`: prove goals of the form `A < B` (subject to the scope constraints + described) + +## Implementation notes + +The automation is provided in the `MetaM` monad; that is, these functions are not user-facing. It +would not be hard to provide user-facing versions (see the test file), but the scope of this +automation is rather specialized and might be confusing to users. It is also subsumed by `linarith`. +-/ + +namespace Mathlib.Tactic.Ring + +open Lean Qq Meta + +/-! Rather than having the metaprograms `Mathlib.Tactic.Ring.evalLE` and +`Mathlib.Tactic.Ring.evalLT` perform all type class inference at the point of use, we record in +advance, as `abbrev`s, a few type class deductions which will certainly be necessary. They add no +new information (they can already be proved by `inferInstance`). + +This helps in speeding up the metaprograms in this file substantially -- about a 50% reduction in +heartbeat count in representative test cases -- since otherwise a substantial fraction of their +runtime is devoted to type class inference. -/ + +section Typeclass + +/-- `OrderedCommSemiring` implies `CommSemiring`. -/ +abbrev cs_of_ocs (α : Type*) [OrderedCommSemiring α] : CommSemiring α := inferInstance + +/-- `OrderedCommSemiring` implies `AddMonoidWithOne`. -/ +abbrev amwo_of_ocs (α : Type*) [OrderedCommSemiring α] : AddMonoidWithOne α := inferInstance + +/-- `OrderedCommSemiring` implies `LE`. -/ +abbrev le_of_ocs (α : Type*) [OrderedCommSemiring α] : LE α := inferInstance + +/-- `StrictOrderedCommSemiring` implies `CommSemiring`. -/ +abbrev cs_of_socs (α : Type*) [StrictOrderedCommSemiring α] : CommSemiring α := inferInstance + +/-- `StrictOrderedCommSemiring` implies `AddMonoidWithOne`. -/ +abbrev amwo_of_socs (α : Type*) [StrictOrderedCommSemiring α] : AddMonoidWithOne α := inferInstance + +/-- `StrictOrderedCommSemiring` implies `LT`. -/ +abbrev lt_of_socs (α : Type*) [StrictOrderedCommSemiring α] : LT α := inferInstance + +end Typeclass + +/-! The lemmas like `add_le_add_right` in the root namespace are stated under minimal type classes, +typically just `[AddRightMono α]` or similar. Here we restate these +lemmas under stronger type class assumptions (`[OrderedCommSemiring α]` or similar), which helps in +speeding up the metaprograms in this file (`Mathlib.Tactic.Ring.proveLT` and +`Mathlib.Tactic.Ring.proveLE`) substantially -- about a 50% reduction in heartbeat count in +representative test cases -- since otherwise a substantial fraction of their runtime is devoted to +type class inference. + +These metaprograms at least require `CommSemiring`, `LE`/`LT`, and all +`CovariantClass`/`ContravariantClass` permutations for addition, and in their main use case (in +`linear_combination`) the `Preorder` type class is also required, so it is rather little loss of +generality simply to require `OrderedCommSemiring`/`StrictOrderedCommSemiring`. -/ + +section Lemma + +theorem add_le_add_right {α : Type*} [OrderedCommSemiring α] {b c : α} (bc : b ≤ c) (a : α) : + b + a ≤ c + a := + _root_.add_le_add_right bc a + +theorem add_le_of_nonpos_left {α : Type*} [OrderedCommSemiring α] (a : α) {b : α} (h : b ≤ 0) : + b + a ≤ a := + _root_.add_le_of_nonpos_left h + +theorem le_add_of_nonneg_left {α : Type*} [OrderedCommSemiring α] (a : α) {b : α} (h : 0 ≤ b) : + a ≤ b + a := + _root_.le_add_of_nonneg_left h + +theorem add_lt_add_right {α : Type*} [StrictOrderedCommSemiring α] {b c : α} (bc : b < c) (a : α) : + b + a < c + a := + _root_.add_lt_add_right bc a + +theorem add_lt_of_neg_left {α : Type*} [StrictOrderedCommSemiring α] (a : α) {b : α} (h : b < 0) : + b + a < a := + _root_.add_lt_of_neg_left a h + +theorem lt_add_of_pos_left {α : Type*} [StrictOrderedCommSemiring α] (a : α) {b : α} (h : 0 < b) : + a < b + a := + _root_.lt_add_of_pos_left a h + +end Lemma + +/-- Inductive type carrying the two kinds of errors which can arise in the metaprograms +`Mathlib.Tactic.Ring.evalLE` and `Mathlib.Tactic.Ring.evalLT`. -/ +inductive ExceptType | tooSmall | notComparable +export ExceptType (tooSmall notComparable) + +/-- In a commutative semiring, given `Ring.ExSum` objects `va`, `vb` which differ by a positive +(additive) constant, construct a proof of `$a < $b`, where `a` (resp. `b`) is the expression in the +semiring to which `va` (resp. `vb`) evaluates. -/ +def evalLE {v : Level} {α : Q(Type v)} (_ : Q(OrderedCommSemiring $α)) {a b : Q($α)} + (va : Ring.ExSum q(cs_of_ocs $α) a) (vb : Ring.ExSum q(cs_of_ocs $α) b) : + MetaM (Except ExceptType Q($a ≤ $b)) := do + let lα : Q(LE $α) := q(le_of_ocs $α) + assumeInstancesCommute + let ⟨_, pz⟩ ← NormNum.mkOfNat α q(amwo_of_ocs $α) (mkRawNatLit 0) + let rz : NormNum.Result q((0:$α)) := + NormNum.Result.isNat q(amwo_of_ocs $α) (mkRawNatLit 0) (q(NormNum.isNat_ofNat $α $pz):) + match va, vb with + /- `0 ≤ 0` -/ + | .zero, .zero => pure <| .ok (q(le_refl (0:$α)):) + /- For numerals `ca` and `cb`, `ca + x ≤ cb + x` if `ca ≤ cb` -/ + | .add (b := a') (.const (e := xa) ca hypa) va', .add (.const (e := xb) cb hypb) vb' => do + unless va'.eq vb' do return .error notComparable + let rxa := NormNum.Result.ofRawRat ca xa hypa + let rxb := NormNum.Result.ofRawRat cb xb hypb + let NormNum.Result.isTrue pf ← NormNum.evalLE.core lα rxa rxb | return .error tooSmall + pure <| .ok (q(add_le_add_right (a := $a') $pf):) + /- For a numeral `ca ≤ 0`, `ca + x ≤ x` -/ + | .add (.const (e := xa) ca hypa) va', _ => do + unless va'.eq vb do return .error notComparable + let rxa := NormNum.Result.ofRawRat ca xa hypa + let NormNum.Result.isTrue pf ← NormNum.evalLE.core lα rxa rz | return .error tooSmall + pure <| .ok (q(add_le_of_nonpos_left (a := $b) $pf):) + /- For a numeral `0 ≤ cb`, `x ≤ cb + x` -/ + | _, .add (.const (e := xb) cb hypb) vb' => do + unless va.eq vb' do return .error notComparable + let rxb := NormNum.Result.ofRawRat cb xb hypb + let NormNum.Result.isTrue pf ← NormNum.evalLE.core lα rz rxb | return .error tooSmall + pure <| .ok (q(le_add_of_nonneg_left (a := $a) $pf):) + | _, _ => return .error notComparable + +/-- In a commutative semiring, given `Ring.ExSum` objects `va`, `vb` which differ by a positive +(additive) constant, construct a proof of `$a < $b`, where `a` (resp. `b`) is the expression in the +semiring to which `va` (resp. `vb`) evaluates. -/ +def evalLT {v : Level} {α : Q(Type v)} (_ : Q(StrictOrderedCommSemiring $α)) {a b : Q($α)} + (va : Ring.ExSum q(cs_of_socs $α) a) (vb : Ring.ExSum q(cs_of_socs $α) b) : + MetaM (Except ExceptType Q($a < $b)) := do + let lα : Q(LT $α) := q(lt_of_socs $α) + assumeInstancesCommute + let ⟨_, pz⟩ ← NormNum.mkOfNat α q(amwo_of_socs $α) (mkRawNatLit 0) + let rz : NormNum.Result q((0:$α)) := + NormNum.Result.isNat q(amwo_of_socs $α) (mkRawNatLit 0) (q(NormNum.isNat_ofNat $α $pz):) + match va, vb with + /- `0 < 0` -/ + | .zero, .zero => return .error tooSmall + /- For numerals `ca` and `cb`, `ca + x < cb + x` if `ca < cb` -/ + | .add (b := a') (.const (e := xa) ca hypa) va', .add (.const (e := xb) cb hypb) vb' => do + unless va'.eq vb' do return .error notComparable + let rxa := NormNum.Result.ofRawRat ca xa hypa + let rxb := NormNum.Result.ofRawRat cb xb hypb + let NormNum.Result.isTrue pf ← NormNum.evalLT.core lα rxa rxb | return .error tooSmall + pure <| .ok (q(add_lt_add_right $pf $a'):) + /- For a numeral `ca < 0`, `ca + x < x` -/ + | .add (.const (e := xa) ca hypa) va', _ => do + unless va'.eq vb do return .error notComparable + let rxa := NormNum.Result.ofRawRat ca xa hypa + let NormNum.Result.isTrue pf ← NormNum.evalLT.core lα rxa rz | return .error tooSmall + have pf : Q($xa < 0) := pf + pure <| .ok (q(add_lt_of_neg_left $b $pf):) + /- For a numeral `0 < cb`, `x < cb + x` -/ + | _, .add (.const (e := xb) cb hypb) vb' => do + unless va.eq vb' do return .error notComparable + let rxb := NormNum.Result.ofRawRat cb xb hypb + let NormNum.Result.isTrue pf ← NormNum.evalLT.core lα rz rxb | return .error tooSmall + pure <| .ok (q(lt_add_of_pos_left $a $pf):) + | _, _ => return .error notComparable + +theorem le_congr {α : Type*} [LE α] {a b c d : α} (h1 : a = b) (h2 : b ≤ c) (h3 : d = c) : + a ≤ d := by + rwa [h1, h3] + +theorem lt_congr {α : Type*} [LT α] {a b c d : α} (h1 : a = b) (h2 : b < c) (h3 : d = c) : + a < d := by + rwa [h1, h3] + +/-- Prove goals of the form `A ≤ B` in an ordered commutative semiring, if the ring-normal forms of +`A` and `B` differ by a nonnegative (additive) constant. -/ +def proveLE (g : MVarId) : MetaM Unit := do + let some (α, e₁, e₂) := (← whnfR <|← instantiateMVars <|← g.getType).le? + | throwError "ring failed: not of the form `A ≤ B`" + let .sort u ← whnf (← inferType α) | unreachable! + let v ← try u.dec catch _ => throwError "not a type{indentExpr α}" + have α : Q(Type v) := α + let sα ← synthInstanceQ q(OrderedCommSemiring $α) + assumeInstancesCommute + have e₁ : Q($α) := e₁; have e₂ : Q($α) := e₂ + let c ← mkCache q(cs_of_ocs $α) + let (⟨a, va, pa⟩, ⟨b, vb, pb⟩) + ← AtomM.run .instances do pure (← eval q(cs_of_ocs $α) c e₁, ← eval q(cs_of_ocs $α) c e₂) + match ← evalLE sα va vb with + | .ok p => g.assign q(le_congr $pa $p $pb) + | .error e => + let g' ← mkFreshExprMVar (← (← ringCleanupRef.get) q($a ≤ $b)) + match e with + | notComparable => + throwError "ring failed, ring expressions not equal up to an additive constant\n{g'.mvarId!}" + | tooSmall => throwError "comparison failed, LHS is larger\n{g'.mvarId!}" + +/-- Prove goals of the form `A < B` in an ordered commutative semiring, if the ring-normal forms of +`A` and `B` differ by a positive (additive) constant. -/ +def proveLT (g : MVarId) : MetaM Unit := do + let some (α, e₁, e₂) := (← whnfR <|← instantiateMVars <|← g.getType).lt? + | throwError "ring failed: not of the form `A < B`" + let .sort u ← whnf (← inferType α) | unreachable! + let v ← try u.dec catch _ => throwError "not a type{indentExpr α}" + have α : Q(Type v) := α + let sα ← synthInstanceQ q(StrictOrderedCommSemiring $α) + assumeInstancesCommute + have e₁ : Q($α) := e₁; have e₂ : Q($α) := e₂ + let c ← mkCache q(cs_of_socs $α) + let (⟨a, va, pa⟩, ⟨b, vb, pb⟩) + ← AtomM.run .instances do pure (← eval q(cs_of_socs $α) c e₁, ← eval q(cs_of_socs $α) c e₂) + match ← evalLT sα va vb with + | .ok p => g.assign q(lt_congr $pa $p $pb) + | .error e => + let g' ← mkFreshExprMVar (← (← ringCleanupRef.get) q($a < $b)) + match e with + | notComparable => + throwError "ring failed, ring expressions not equal up to an additive constant\n{g'.mvarId!}" + | tooSmall => throwError "comparison failed, LHS is at least as large\n{g'.mvarId!}" + +end Mathlib.Tactic.Ring diff --git a/Mathlib/Tactic/Says.lean b/Mathlib/Tactic/Says.lean index 87f93ae495ba1..29bd33ed183cf 100644 --- a/Mathlib/Tactic/Says.lean +++ b/Mathlib/Tactic/Says.lean @@ -40,7 +40,7 @@ register_option says.verify : Bool := register_option says.no_verify_in_CI : Bool := { defValue := false group := "says" - descr := "Disable reverification, even if `the `CI` environment variable is set." } + descr := "Disable reverification, even if the `CI` environment variable is set." } open Parser Tactic diff --git a/Mathlib/Tactic/Set.lean b/Mathlib/Tactic/Set.lean index 742da43bb1561..8124af120c76e 100644 --- a/Mathlib/Tactic/Set.lean +++ b/Mathlib/Tactic/Set.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Ian Benway -/ import Mathlib.Init -import Lean +import Lean.Elab.Tactic.ElabTerm /-! # The `set` tactic diff --git a/Mathlib/Tactic/SimpIntro.lean b/Mathlib/Tactic/SimpIntro.lean index 7012c998ee2ba..1ac777e1d63a5 100644 --- a/Mathlib/Tactic/SimpIntro.lean +++ b/Mathlib/Tactic/SimpIntro.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Lean.Elab.Tactic.Simp import Mathlib.Init -import Lean /-! # `simp_intro` tactic -/ diff --git a/Mathlib/Tactic/SimpRw.lean b/Mathlib/Tactic/SimpRw.lean index fc9e243d4cc87..cb3c8940ddf1b 100644 --- a/Mathlib/Tactic/SimpRw.lean +++ b/Mathlib/Tactic/SimpRw.lean @@ -5,7 +5,6 @@ Authors: Anne Baanen, Mario Carneiro, Alex J. Best -/ import Mathlib.Init -import Lean /-! # The `simp_rw` tactic diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index 1caba0e4825ab..3b28a506c4d61 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -317,8 +317,7 @@ Some common uses: This will generate `foo_apply` lemmas for each declaration `foo`. * If you prefer `coe_foo` lemmas that state equalities between functions, use `initialize_simps_projections MulHom (toFun → coe, as_prefix coe)` - In this case you have to use `@[simps (config := .asFn)]` or equivalently - `@[simps (config := .asFn)]` whenever you call `@[simps]`. + In this case you have to use `@[simps (config := .asFn)]` whenever you call `@[simps]`. * You can also initialize to use both, in which case you have to choose which one to use by default, by using either of the following ``` diff --git a/Mathlib/Tactic/SplitIfs.lean b/Mathlib/Tactic/SplitIfs.lean index 97bfe7da56045..49287e1c5ec75 100644 --- a/Mathlib/Tactic/SplitIfs.lean +++ b/Mathlib/Tactic/SplitIfs.lean @@ -3,7 +3,9 @@ Copyright (c) 2018 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner, David Renshaw -/ -import Lean +import Lean.Elab.Tactic.Location +import Lean.Meta.Tactic.SplitIf +import Lean.Elab.Tactic.Simp import Mathlib.Tactic.Core /-! diff --git a/Mathlib/Tactic/StacksAttribute.lean b/Mathlib/Tactic/StacksAttribute.lean index 0dc60503a6780..54b458ff6ba3d 100644 --- a/Mathlib/Tactic/StacksAttribute.lean +++ b/Mathlib/Tactic/StacksAttribute.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ import Lean.Elab.Command +import Mathlib.Init /-! # The `stacks` and `kerodon` attributes diff --git a/Mathlib/Tactic/Substs.lean b/Mathlib/Tactic/Substs.lean index b5f3ea55b20d3..aad863daed3e9 100644 --- a/Mathlib/Tactic/Substs.lean +++ b/Mathlib/Tactic/Substs.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Evan Lohn, Mario Carneiro -/ import Mathlib.Init -import Lean /-! # The `substs` macro diff --git a/Mathlib/Tactic/SuccessIfFailWithMsg.lean b/Mathlib/Tactic/SuccessIfFailWithMsg.lean index 70bb4e7e8468d..3881cd09cfd2c 100644 --- a/Mathlib/Tactic/SuccessIfFailWithMsg.lean +++ b/Mathlib/Tactic/SuccessIfFailWithMsg.lean @@ -3,8 +3,9 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Simon Hudon, Sébastien Gouëzel, Kim Morrison, Thomas Murrills -/ +import Lean.Elab.Eval +import Lean.Elab.Tactic.BuiltinTactic import Mathlib.Init -import Lean /-! # Success If Fail With Message @@ -15,7 +16,7 @@ It's mostly useful in tests, where we want to make sure that tactics fail in cer circumstances. -/ -open Lean Elab Meta Tactic Syntax +open Lean Elab Tactic namespace Mathlib.Tactic diff --git a/Mathlib/Tactic/ToAdditive/Frontend.lean b/Mathlib/Tactic/ToAdditive/Frontend.lean index bdc528a294073..c0d0ef7afdcfa 100644 --- a/Mathlib/Tactic/ToAdditive/Frontend.lean +++ b/Mathlib/Tactic/ToAdditive/Frontend.lean @@ -16,7 +16,7 @@ import Lean.Meta.Tactic.Rfl import Lean.Meta.Match.MatcherInfo import Batteries.Lean.NameMapAttribute import Batteries.Tactic.Lint -- useful to lint this file and for DiscrTree.elements -import Mathlib.Tactic.Relation.Trans -- just to copy the attribute +import Batteries.Tactic.Trans import Mathlib.Tactic.Eqns -- just to copy the attribute import Mathlib.Tactic.Simps.Basic @@ -1048,6 +1048,8 @@ def fixAbbreviation : List String → List String => "function" :: "_" :: "semiconj" :: fixAbbreviation s | "function" :: "_" :: "add" :: "Commute" :: s => "function" :: "_" :: "commute" :: fixAbbreviation s + | "Zero" :: "Le" :: "Part" :: s => "PosPart" :: fixAbbreviation s + | "Le" :: "Zero" :: "Part" :: s => "NegPart" :: fixAbbreviation s | "zero" :: "Le" :: "Part" :: s => "posPart" :: fixAbbreviation s | "le" :: "Zero" :: "Part" :: s => "negPart" :: fixAbbreviation s | "Division" :: "Add" :: "Monoid" :: s => "SubtractionMonoid" :: fixAbbreviation s @@ -1165,7 +1167,7 @@ partial def applyAttributes (stx : Syntax) (rawAttrs : Array Syntax) (thisAttr s (fun b n => (b.tree.values.any fun t => t.declName = n)) thisAttr `ext src tgt warnAttr stx Lean.Meta.Rfl.reflExt (·.values.contains ·) thisAttr `refl src tgt warnAttr stx Lean.Meta.Symm.symmExt (·.values.contains ·) thisAttr `symm src tgt - warnAttr stx Mathlib.Tactic.transExt (·.values.contains ·) thisAttr `trans src tgt + warnAttr stx Batteries.Tactic.transExt (·.values.contains ·) thisAttr `trans src tgt warnAttr stx Lean.Meta.coeExt (·.contains ·) thisAttr `coe src tgt warnParametricAttr stx Lean.Linter.deprecatedAttr thisAttr `deprecated src tgt -- the next line also warns for `@[to_additive, simps]`, because of the application times diff --git a/Mathlib/Tactic/ToExpr.lean b/Mathlib/Tactic/ToExpr.lean index b02e21d2b44bb..8997800729532 100644 --- a/Mathlib/Tactic/ToExpr.lean +++ b/Mathlib/Tactic/ToExpr.lean @@ -50,8 +50,6 @@ end override namespace Mathlib open Lean -deriving instance ToExpr for Int - set_option autoImplicit true in deriving instance ToExpr for ULift diff --git a/Mathlib/Tactic/TryThis.lean b/Mathlib/Tactic/TryThis.lean index 9e0c3ea6a3cc0..3d4814c3d4087 100644 --- a/Mathlib/Tactic/TryThis.lean +++ b/Mathlib/Tactic/TryThis.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Init -import Lean +import Lean.Meta.Tactic.TryThis /-! # 'Try this' tactic macro diff --git a/Mathlib/Tactic/UnsetOption.lean b/Mathlib/Tactic/UnsetOption.lean index 032d3f10d0be6..f91917e409006 100644 --- a/Mathlib/Tactic/UnsetOption.lean +++ b/Mathlib/Tactic/UnsetOption.lean @@ -22,8 +22,7 @@ behaviour is different from any user set value. namespace Lean.Elab -variable {m : Type → Type} [Monad m] [MonadOptions m] [MonadExceptOf Exception m] [MonadRef m] -variable [AddErrorMessageContext m] [MonadLiftT (EIO Exception) m] [MonadInfoTree m] +variable {m : Type → Type} [Monad m] [MonadOptions m] [MonadRef m] [MonadInfoTree m] /-- unset the option specified by id -/ def elabUnsetOption (id : Syntax) : m Options := do diff --git a/Mathlib/Tactic/Widget/CongrM.lean b/Mathlib/Tactic/Widget/CongrM.lean index 9c259c3daaf30..dad4520d652cc 100644 --- a/Mathlib/Tactic/Widget/CongrM.lean +++ b/Mathlib/Tactic/Widget/CongrM.lean @@ -6,6 +6,7 @@ Authors: Patrick Massot import Mathlib.Tactic.Widget.SelectPanelUtils import Mathlib.Tactic.CongrM +import Batteries.Lean.Position /-! # CongrM widget diff --git a/Mathlib/Tactic/Widget/InteractiveUnfold.lean b/Mathlib/Tactic/Widget/InteractiveUnfold.lean index b88ea0416d05d..7d3eae135546f 100644 --- a/Mathlib/Tactic/Widget/InteractiveUnfold.lean +++ b/Mathlib/Tactic/Widget/InteractiveUnfold.lean @@ -225,7 +225,7 @@ elab stx:"unfold?" : tactic => do /-- `#unfold? e` gives all unfolds of `e`. In tactic mode, use `unfold?` instead. -/ -syntax (name := unfoldCommand) "#unfold?" term : command +syntax (name := unfoldCommand) "#unfold? " term : command open Elab /-- Elaborate a `#unfold?` command. -/ diff --git a/Mathlib/Tactic/Widget/StringDiagram.lean b/Mathlib/Tactic/Widget/StringDiagram.lean index 9ba22761bcd5e..c2745df6eff9a 100644 --- a/Mathlib/Tactic/Widget/StringDiagram.lean +++ b/Mathlib/Tactic/Widget/StringDiagram.lean @@ -182,7 +182,7 @@ def WhiskerLeft.nodes (v h₁ h₂ : ℕ) : WhiskerLeft → List Node let ss := η.nodes v (h₁ + 1) (h₂ + 1) s :: ss -variable {ρ : Type} [Context ρ] [MonadMor₁ (CoherenceM ρ)] +variable {ρ : Type} [MonadMor₁ (CoherenceM ρ)] /-- The list of nodes at the top of a string diagram. -/ def topNodes (η : WhiskerLeft) : CoherenceM ρ (List Node) := do diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean index 55ef7dc3e20fa..7b73daf4bdbcb 100644 --- a/Mathlib/Testing/SlimCheck/Functions.lean +++ b/Mathlib/Testing/SlimCheck/Functions.lean @@ -289,7 +289,7 @@ theorem List.applyId_zip_eq [DecidableEq α] {xs ys : List α} (h₀ : List.Nodu | nil => cases h₂ | cons x' xs xs_ih => cases i - · simp only [length_cons, lt_add_iff_pos_left, add_pos_iff, zero_lt_one, or_true, + · simp only [length_cons, lt_add_iff_pos_left, add_pos_iff, Nat.lt_add_one, or_true, getElem?_eq_getElem, getElem_cons_zero, Option.some.injEq] at h₂ subst h₂ cases ys @@ -330,7 +330,7 @@ theorem applyId_mem_iff [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs specialize xs_ih h₅ h₃ h₄ h₆ simp only [Ne.symm h, xs_ih, List.mem_cons] suffices val ∈ ys by tauto - erw [← Option.mem_def, List.mem_dlookup_iff] at h₃ + rw [← Option.mem_def, List.mem_dlookup_iff] at h₃ · simp only [Prod.toSigma, List.mem_map, heq_iff_eq, Prod.exists] at h₃ rcases h₃ with ⟨a, b, h₃, h₄, h₅⟩ apply (List.of_mem_zip h₃).2 @@ -423,7 +423,7 @@ one is a permutation of the other. -/ protected def shrink {α : Type} [DecidableEq α] : InjectiveFunction α → List (InjectiveFunction α) - | ⟨xs, h₀, h₁⟩ => do + | ⟨_, h₀, h₁⟩ => do let ⟨xs', ys', h₀, h₁⟩ ← InjectiveFunction.shrinkPerm ⟨_, _, h₀, h₁⟩ have h₃ : xs'.length ≤ ys'.length := le_of_eq (List.Perm.length_eq h₀) have h₄ : ys'.length ≤ xs'.length := le_of_eq (List.Perm.length_eq h₀.symm) diff --git a/Mathlib/Testing/SlimCheck/Gen.lean b/Mathlib/Testing/SlimCheck/Gen.lean index 0f3d66842989e..8429d8cbfff50 100644 --- a/Mathlib/Testing/SlimCheck/Gen.lean +++ b/Mathlib/Testing/SlimCheck/Gen.lean @@ -101,7 +101,7 @@ def permutationOf : (xs : List α) → Gen { ys // xs ~ ys } | x::xs => do let ⟨ys, h1⟩ ← permutationOf xs let ⟨n, _, h3⟩ ← ULiftable.up <| choose Nat 0 ys.length (Nat.zero_le _) - pure ⟨insertNth n x ys, Perm.trans (Perm.cons _ h1) (perm_insertNth _ _ h3).symm⟩ + pure ⟨insertIdx n x ys, Perm.trans (Perm.cons _ h1) (perm_insertIdx _ _ h3).symm⟩ /-- Given two generators produces a tuple consisting out of the result of both -/ def prodOf {α : Type u} {β : Type v} (x : Gen α) (y : Gen β) : Gen (α × β) := do diff --git a/Mathlib/Testing/SlimCheck/Sampleable.lean b/Mathlib/Testing/SlimCheck/Sampleable.lean index f5cedcf3cb680..cb9e8a50dcfb2 100644 --- a/Mathlib/Testing/SlimCheck/Sampleable.lean +++ b/Mathlib/Testing/SlimCheck/Sampleable.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Henrik Böving. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Henrik Böving, Simon Hudon -/ +import Batteries.Data.Rat.Basic import Mathlib.Algebra.Order.Ring.Int import Mathlib.Data.List.Monad import Mathlib.Testing.SlimCheck.Gen @@ -187,7 +188,7 @@ open Shrinkable instance List.shrinkable [Shrinkable α] : Shrinkable (List α) where shrink := fun L => (L.mapIdx fun i _ => L.eraseIdx i) ++ - (L.mapIdx fun i a => (shrink a).map fun a' => L.modifyNth (fun _ => a') i).join + (L.mapIdx fun i a => (shrink a).map fun a' => L.modify (fun _ => a') i).join end Shrinkers diff --git a/Mathlib/Testing/SlimCheck/Testable.lean b/Mathlib/Testing/SlimCheck/Testable.lean index e4ece33e569d8..5028ce46f4cae 100644 --- a/Mathlib/Testing/SlimCheck/Testable.lean +++ b/Mathlib/Testing/SlimCheck/Testable.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Henrik Böving, Simon Hudon -/ import Mathlib.Testing.SlimCheck.Sampleable -import Lean /-! # `Testable` Class @@ -423,7 +422,7 @@ end Testable section PrintableProp -variable {α : Type*} {x y : α} +variable {α : Type*} instance Eq.printableProp [Repr α] {x y : α} : PrintableProp (x = y) where printProp := s!"{repr x} = {repr y}" diff --git a/Mathlib/Topology/AlexandrovDiscrete.lean b/Mathlib/Topology/AlexandrovDiscrete.lean index 517c0d910bfeb..aceac53facf2d 100644 --- a/Mathlib/Topology/AlexandrovDiscrete.lean +++ b/Mathlib/Topology/AlexandrovDiscrete.lean @@ -114,7 +114,7 @@ lemma closure_sUnion (S : Set (Set α)) : closure (⋃₀ S) = ⋃ s ∈ S, clos end AlexandrovDiscrete -lemma Inducing.alexandrovDiscrete [AlexandrovDiscrete α] {f : β → α} (h : Inducing f) : +lemma IsInducing.alexandrovDiscrete [AlexandrovDiscrete α] {f : β → α} (h : IsInducing f) : AlexandrovDiscrete β where isOpen_sInter S hS := by simp_rw [h.isOpen_iff] at hS ⊢ @@ -122,6 +122,9 @@ lemma Inducing.alexandrovDiscrete [AlexandrovDiscrete α] {f : β → α} (h : I refine ⟨_, isOpen_iInter₂ hU, ?_⟩ simp_rw [preimage_iInter, htU, sInter_eq_biInter] +@[deprecated (since := "2024-10-28")] +alias Inducing.alexandrovDiscrete := IsInducing.alexandrovDiscrete + end lemma AlexandrovDiscrete.sup {t₁ t₂ : TopologicalSpace α} (_ : @AlexandrovDiscrete α t₁) @@ -139,7 +142,7 @@ lemma alexandrovDiscrete_iSup {t : ι → TopologicalSpace α} (_ : ∀ i, @Alex section variable [TopologicalSpace α] [TopologicalSpace β] [AlexandrovDiscrete α] [AlexandrovDiscrete β] - {s t : Set α} {a x y : α} + {s t : Set α} {a : α} @[simp] lemma isOpen_exterior : IsOpen (exterior s) := by rw [exterior_def]; exact isOpen_sInter fun _ ↦ And.left @@ -186,7 +189,7 @@ instance AlexandrovDiscrete.toLocallyCompactSpace : LocallyCompactSpace α where exterior_singleton_subset_iff_mem_nhds.2 hU, isCompact_singleton.exterior⟩ instance Subtype.instAlexandrovDiscrete {p : α → Prop} : AlexandrovDiscrete {a // p a} := - inducing_subtype_val.alexandrovDiscrete + IsInducing.subtypeVal.alexandrovDiscrete instance Quotient.instAlexandrovDiscrete {s : Setoid α} : AlexandrovDiscrete (Quotient s) := alexandrovDiscrete_coinduced diff --git a/Mathlib/Topology/Algebra/ClopenNhdofOne.lean b/Mathlib/Topology/Algebra/ClopenNhdofOne.lean new file mode 100644 index 0000000000000..b254276d388f7 --- /dev/null +++ b/Mathlib/Topology/Algebra/ClopenNhdofOne.lean @@ -0,0 +1,30 @@ +/- +Copyright (c) 2024 Nailin Guan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nailin Guan, Yi Song, Xuchun Li +-/ +import Mathlib.GroupTheory.Index +import Mathlib.Topology.Algebra.ClosedSubgroup +import Mathlib.Topology.Algebra.OpenSubgroup +/-! +# Existence of an open normal subgroup in any clopen neighborhood of the neutral element + +This file proves the lemma `TopologicalGroup.exist_openNormalSubgroup_sub_clopen_nhd_of_one`, which +states that in a compact topological group, for any clopen neighborhood of 1, +there exists an open normal subgroup contained within it. + +This file is split out from the file `OpenSubgroup` because it needs more imports. +-/ + +namespace TopologicalGroup + +theorem exist_openNormalSubgroup_sub_clopen_nhd_of_one {G : Type*} [Group G] [TopologicalSpace G] + [TopologicalGroup G] [CompactSpace G] {W : Set G} (WClopen : IsClopen W) (einW : 1 ∈ W) : + ∃ H : OpenNormalSubgroup G, (H : Set G) ⊆ W := by + rcases exist_openSubgroup_sub_clopen_nhd_of_one WClopen einW with ⟨H, hH⟩ + have : Subgroup.FiniteIndex H := H.finiteIndex_of_finite_quotient + use { toSubgroup := Subgroup.normalCore H + isOpen' := Subgroup.isOpen_of_isClosed_of_finiteIndex _ (H.normalCore_isClosed H.isClosed) } + exact fun _ b ↦ hH (H.normalCore_le b) + +end TopologicalGroup diff --git a/Mathlib/Topology/Algebra/ConstMulAction.lean b/Mathlib/Topology/Algebra/ConstMulAction.lean index 39bd780335969..9993c091a7057 100644 --- a/Mathlib/Topology/Algebra/ConstMulAction.lean +++ b/Mathlib/Topology/Algebra/ConstMulAction.lean @@ -3,12 +3,13 @@ Copyright (c) 2021 Alex Kontorovich, Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex Kontorovich, Heather Macbeth -/ +import Mathlib.Algebra.Module.ULift +import Mathlib.Data.Set.Pointwise.SMul +import Mathlib.GroupTheory.GroupAction.Defs import Mathlib.Topology.Algebra.Constructions -import Mathlib.Topology.Homeomorph -import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.Topology.Bases +import Mathlib.Topology.Homeomorph import Mathlib.Topology.Support -import Mathlib.Algebra.Module.ULift /-! # Monoid actions continuous in the second variable @@ -79,7 +80,7 @@ theorem Filter.Tendsto.const_smul {f : β → α} {l : Filter β} {a : α} (hf : (c : M) : Tendsto (fun x => c • f x) l (𝓝 (c • a)) := ((continuous_const_smul _).tendsto _).comp hf -variable [TopologicalSpace β] {f : β → M} {g : β → α} {b : β} {s : Set β} +variable [TopologicalSpace β] {g : β → α} {b : β} {s : Set β} @[to_additive] nonrec theorem ContinuousWithinAt.const_smul (hg : ContinuousWithinAt g s b) (c : M) : @@ -142,12 +143,15 @@ theorem Inseparable.const_smul {x y : α} (h : Inseparable x y) (c : M) : h.map (continuous_const_smul c) @[to_additive] -theorem Inducing.continuousConstSMul {N β : Type*} [SMul N β] [TopologicalSpace β] - {g : β → α} (hg : Inducing g) (f : N → M) (hf : ∀ {c : N} {x : β}, g (c • x) = f c • g x) : +theorem IsInducing.continuousConstSMul {N β : Type*} [SMul N β] [TopologicalSpace β] + {g : β → α} (hg : IsInducing g) (f : N → M) (hf : ∀ {c : N} {x : β}, g (c • x) = f c • g x) : ContinuousConstSMul N β where continuous_const_smul c := by simpa only [Function.comp_def, hf, hg.continuous_iff] using hg.continuous.const_smul (f c) +@[deprecated (since := "2024-10-28")] +alias Inducing.continuousConstSMul := IsInducing.continuousConstSMul + end SMul section Monoid @@ -258,7 +262,7 @@ theorem subset_interior_smul_right {s : Set G} {t : Set α} : s • interior t @[to_additive (attr := simp)] theorem smul_mem_nhds_smul_iff {t : Set α} (g : G) {a : α} : g • t ∈ 𝓝 (g • a) ↔ t ∈ 𝓝 a := - (Homeomorph.smul g).openEmbedding.image_mem_nhds + (Homeomorph.smul g).isOpenEmbedding.image_mem_nhds @[to_additive] alias ⟨_, smul_mem_nhds_smul⟩ := smul_mem_nhds_smul_iff diff --git a/Mathlib/Topology/Algebra/Constructions.lean b/Mathlib/Topology/Algebra/Constructions.lean index 96db33647784a..538b78c7654c8 100644 --- a/Mathlib/Topology/Algebra/Constructions.lean +++ b/Mathlib/Topology/Algebra/Constructions.lean @@ -48,12 +48,11 @@ def opHomeomorph : M ≃ₜ Mᵐᵒᵖ where continuous_invFun := continuous_unop @[to_additive] -instance instT2Space [T2Space M] : T2Space Mᵐᵒᵖ := - opHomeomorph.symm.embedding.t2Space +instance instT2Space [T2Space M] : T2Space Mᵐᵒᵖ := opHomeomorph.t2Space @[to_additive] instance instDiscreteTopology [DiscreteTopology M] : DiscreteTopology Mᵐᵒᵖ := - opHomeomorph.symm.embedding.discreteTopology + opHomeomorph.symm.isEmbedding.discreteTopology @[to_additive (attr := simp)] theorem map_op_nhds (x : M) : map (op : M → Mᵐᵒᵖ) (𝓝 x) = 𝓝 (op x) := @@ -86,34 +85,37 @@ instance instTopologicalSpaceUnits : TopologicalSpace Mˣ := TopologicalSpace.induced (embedProduct M) inferInstance @[to_additive] -theorem inducing_embedProduct : Inducing (embedProduct M) := - ⟨rfl⟩ +theorem isInducing_embedProduct : IsInducing (embedProduct M) := ⟨rfl⟩ + +@[deprecated (since := "2024-10-28")] alias inducing_embedProduct := isInducing_embedProduct @[to_additive] -theorem embedding_embedProduct : Embedding (embedProduct M) := - ⟨inducing_embedProduct, embedProduct_injective M⟩ +theorem isEmbedding_embedProduct : IsEmbedding (embedProduct M) := + ⟨isInducing_embedProduct, embedProduct_injective M⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_embedProduct := isEmbedding_embedProduct @[to_additive] -instance instT2Space [T2Space M] : T2Space Mˣ := - embedding_embedProduct.t2Space +instance instT2Space [T2Space M] : T2Space Mˣ := isEmbedding_embedProduct.t2Space @[to_additive] instance instDiscreteTopology [DiscreteTopology M] : DiscreteTopology Mˣ := - embedding_embedProduct.discreteTopology + isEmbedding_embedProduct.discreteTopology @[to_additive] lemma topology_eq_inf : instTopologicalSpaceUnits = .induced (val : Mˣ → M) ‹_› ⊓ .induced (fun u ↦ ↑u⁻¹ : Mˣ → M) ‹_› := by - simp only [inducing_embedProduct.1, instTopologicalSpaceProd, induced_inf, + simp only [isInducing_embedProduct.1, instTopologicalSpaceProd, induced_inf, instTopologicalSpaceMulOpposite, induced_compose]; rfl /-- An auxiliary lemma that can be used to prove that coercion `Mˣ → M` is a topological embedding. -Use `Units.embedding_val₀`, `Units.embedding_val`, or `toUnits_homeomorph` instead. -/ +Use `Units.isEmbedding_val₀`, `Units.isEmbedding_val`, or `toUnits_homeomorph` instead. -/ @[to_additive "An auxiliary lemma that can be used to prove that coercion `AddUnits M → M` is a -topological embedding. Use `AddUnits.embedding_val` or `toAddUnits_homeomorph` instead."] -lemma embedding_val_mk' {M : Type*} [Monoid M] [TopologicalSpace M] {f : M → M} +topological embedding. Use `AddUnits.isEmbedding_val` or `toAddUnits_homeomorph` instead."] +lemma isEmbedding_val_mk' {M : Type*} [Monoid M] [TopologicalSpace M] {f : M → M} (hc : ContinuousOn f {x : M | IsUnit x}) (hf : ∀ u : Mˣ, f u.1 = ↑u⁻¹) : - Embedding (val : Mˣ → M) := by + IsEmbedding (val : Mˣ → M) := by refine ⟨⟨?_⟩, ext⟩ rw [topology_eq_inf, inf_eq_left, ← continuous_iff_le_induced, @continuous_iff_continuousAt _ _ (.induced _ _)] @@ -121,13 +123,16 @@ lemma embedding_val_mk' {M : Type*} [Monoid M] [TopologicalSpace M] {f : M → M simp only [← hf, nhds_induced, Filter.mem_map] at hs ⊢ exact ⟨_, mem_inf_principal.1 (hc u u.isUnit hs), fun u' hu' ↦ hu' u'.isUnit⟩ +@[deprecated (since := "2024-10-26")] +alias embedding_val_mk' := isEmbedding_val_mk' + /-- An auxiliary lemma that can be used to prove that coercion `Mˣ → M` is a topological embedding. -Use `Units.embedding_val₀`, `Units.embedding_val`, or `toUnits_homeomorph` instead. -/ +Use `Units.isEmbedding_val₀`, `Units.isEmbedding_val`, or `toUnits_homeomorph` instead. -/ @[to_additive "An auxiliary lemma that can be used to prove that coercion `AddUnits M → M` is a -topological embedding. Use `AddUnits.embedding_val` or `toAddUnits_homeomorph` instead."] +topological embedding. Use `AddUnits.isEmbedding_val` or `toAddUnits_homeomorph` instead."] lemma embedding_val_mk {M : Type*} [DivisionMonoid M] [TopologicalSpace M] - (h : ContinuousOn Inv.inv {x : M | IsUnit x}) : Embedding (val : Mˣ → M) := - embedding_val_mk' h fun u ↦ (val_inv_eq_inv_val u).symm + (h : ContinuousOn Inv.inv {x : M | IsUnit x}) : IsEmbedding (val : Mˣ → M) := + isEmbedding_val_mk' h fun u ↦ (val_inv_eq_inv_val u).symm @[to_additive] theorem continuous_embedProduct : Continuous (embedProduct M) := @@ -140,8 +145,8 @@ theorem continuous_val : Continuous ((↑) : Mˣ → M) := @[to_additive] protected theorem continuous_iff {f : X → Mˣ} : Continuous f ↔ Continuous (val ∘ f) ∧ Continuous (fun x => ↑(f x)⁻¹ : X → M) := by - simp only [inducing_embedProduct.continuous_iff, embedProduct_apply, Function.comp_def, - continuous_prod_mk, opHomeomorph.symm.inducing.continuous_iff, opHomeomorph_symm_apply, + simp only [isInducing_embedProduct.continuous_iff, embedProduct_apply, Function.comp_def, + continuous_prod_mk, opHomeomorph.symm.isInducing.continuous_iff, opHomeomorph_symm_apply, unop_op] @[to_additive] diff --git a/Mathlib/Topology/Algebra/Constructions/DomMulAct.lean b/Mathlib/Topology/Algebra/Constructions/DomMulAct.lean index 9c399af02e789..78867bf04f7da 100644 --- a/Mathlib/Topology/Algebra/Constructions/DomMulAct.lean +++ b/Mathlib/Topology/Algebra/Constructions/DomMulAct.lean @@ -20,8 +20,7 @@ since the types aren't definitionally equal. topological space, group action, domain action -/ -open Filter TopologicalSpace -open scoped Topology +open Filter TopologicalSpace Topology namespace DomMulAct @@ -47,60 +46,88 @@ def mkHomeomorph : M ≃ₜ Mᵈᵐᵃ where @[to_additive (attr := simp)] theorem coe_mkHomeomorph_symm : ⇑(mkHomeomorph : M ≃ₜ Mᵈᵐᵃ).symm = mk.symm := rfl -@[to_additive] theorem inducing_mk : Inducing (@mk M) := mkHomeomorph.inducing -@[to_additive] theorem embedding_mk : Embedding (@mk M) := mkHomeomorph.embedding -@[to_additive] theorem openEmbedding_mk : OpenEmbedding (@mk M) := mkHomeomorph.openEmbedding -@[to_additive] theorem closedEmbedding_mk : ClosedEmbedding (@mk M) := mkHomeomorph.closedEmbedding -@[to_additive] theorem quotientMap_mk : QuotientMap (@mk M) := mkHomeomorph.quotientMap +@[to_additive] theorem isInducing_mk : IsInducing (@mk M) := mkHomeomorph.isInducing +@[to_additive] theorem isEmbedding_mk : IsEmbedding (@mk M) := mkHomeomorph.isEmbedding +@[to_additive] theorem isOpenEmbedding_mk : IsOpenEmbedding (@mk M) := mkHomeomorph.isOpenEmbedding +@[to_additive] theorem isClosedEmbedding_mk : IsClosedEmbedding (@mk M) := + mkHomeomorph.isClosedEmbedding +@[to_additive] theorem isQuotientMap_mk : IsQuotientMap (@mk M) := mkHomeomorph.isQuotientMap -@[to_additive] theorem inducing_mk_symm : Inducing (@mk M).symm := mkHomeomorph.symm.inducing -@[to_additive] theorem embedding_mk_symm : Embedding (@mk M).symm := mkHomeomorph.symm.embedding +@[deprecated (since := "2024-10-28")] alias inducing_mk := isInducing_mk + +@[deprecated (since := "2024-10-26")] +alias embedding_mk := isEmbedding_mk + +@[deprecated (since := "2024-10-22")] +alias quotientMap_mk := isQuotientMap_mk + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_mk := isClosedEmbedding_mk + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_mk := isOpenEmbedding_mk + +@[to_additive] theorem isInducing_mk_symm : IsInducing (@mk M).symm := mkHomeomorph.symm.isInducing +@[to_additive] theorem isEmbedding_mk_symm : IsEmbedding (@mk M).symm := + mkHomeomorph.symm.isEmbedding + +@[deprecated (since := "2024-10-28")] alias inducing_mk_symm := isInducing_mk_symm + +@[deprecated (since := "2024-10-26")] +alias embedding_mk_symm := isEmbedding_mk_symm @[to_additive] -theorem openEmbedding_mk_symm : OpenEmbedding (@mk M).symm := mkHomeomorph.symm.openEmbedding +theorem isOpenEmbedding_mk_symm : IsOpenEmbedding (@mk M).symm := mkHomeomorph.symm.isOpenEmbedding @[to_additive] -theorem closedEmbedding_mk_symm : ClosedEmbedding (@mk M).symm := mkHomeomorph.symm.closedEmbedding +theorem isClosedEmbedding_mk_symm : IsClosedEmbedding (@mk M).symm := + mkHomeomorph.symm.isClosedEmbedding + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_mk_symm := isClosedEmbedding_mk_symm @[to_additive] -theorem quotientMap_mk_symm : QuotientMap (@mk M).symm := mkHomeomorph.symm.quotientMap +theorem isQuotientMap_mk_symm : IsQuotientMap (@mk M).symm := mkHomeomorph.symm.isQuotientMap + +@[deprecated (since := "2024-10-22")] +alias quotientMap_mk_symm := isQuotientMap_mk_symm -@[to_additive] instance instT0Space [T0Space M] : T0Space Mᵈᵐᵃ := embedding_mk_symm.t0Space -@[to_additive] instance instT1Space [T1Space M] : T1Space Mᵈᵐᵃ := embedding_mk_symm.t1Space -@[to_additive] instance instT2Space [T2Space M] : T2Space Mᵈᵐᵃ := embedding_mk_symm.t2Space -@[to_additive] instance instT25Space [T25Space M] : T25Space Mᵈᵐᵃ := embedding_mk_symm.t25Space -@[to_additive] instance instT3Space [T3Space M] : T3Space Mᵈᵐᵃ := embedding_mk_symm.t3Space -@[to_additive] instance instT4Space [T4Space M] : T4Space Mᵈᵐᵃ := closedEmbedding_mk_symm.t4Space -@[to_additive] instance instT5Space [T5Space M] : T5Space Mᵈᵐᵃ := closedEmbedding_mk_symm.t5Space +@[to_additive] instance instT0Space [T0Space M] : T0Space Mᵈᵐᵃ := mkHomeomorph.t0Space +@[to_additive] instance instT1Space [T1Space M] : T1Space Mᵈᵐᵃ := mkHomeomorph.t1Space +@[to_additive] instance instT2Space [T2Space M] : T2Space Mᵈᵐᵃ := mkHomeomorph.t2Space +@[to_additive] instance instT25Space [T25Space M] : T25Space Mᵈᵐᵃ := mkHomeomorph.t25Space +@[to_additive] instance instT3Space [T3Space M] : T3Space Mᵈᵐᵃ := mkHomeomorph.t3Space +@[to_additive] instance instT4Space [T4Space M] : T4Space Mᵈᵐᵃ := mkHomeomorph.t4Space +@[to_additive] instance instT5Space [T5Space M] : T5Space Mᵈᵐᵃ := mkHomeomorph.t5Space -@[to_additive] instance instR0Space [R0Space M] : R0Space Mᵈᵐᵃ := embedding_mk_symm.r0Space -@[to_additive] instance instR1Space [R1Space M] : R1Space Mᵈᵐᵃ := embedding_mk_symm.r1Space +@[to_additive] instance instR0Space [R0Space M] : R0Space Mᵈᵐᵃ := isEmbedding_mk_symm.r0Space +@[to_additive] instance instR1Space [R1Space M] : R1Space Mᵈᵐᵃ := isEmbedding_mk_symm.r1Space @[to_additive] -instance instRegularSpace [RegularSpace M] : RegularSpace Mᵈᵐᵃ := embedding_mk_symm.regularSpace +instance instRegularSpace [RegularSpace M] : RegularSpace Mᵈᵐᵃ := isEmbedding_mk_symm.regularSpace @[to_additive] -instance instNormalSpace [NormalSpace M] : NormalSpace Mᵈᵐᵃ := closedEmbedding_mk_symm.normalSpace +instance instNormalSpace [NormalSpace M] : NormalSpace Mᵈᵐᵃ := mkHomeomorph.normalSpace @[to_additive] instance instCompletelyNormalSpace [CompletelyNormalSpace M] : CompletelyNormalSpace Mᵈᵐᵃ := - closedEmbedding_mk_symm.completelyNormalSpace + mkHomeomorph.symm.isEmbedding.completelyNormalSpace @[to_additive] instance instDiscreteTopology [DiscreteTopology M] : DiscreteTopology Mᵈᵐᵃ := - embedding_mk_symm.discreteTopology + isEmbedding_mk_symm.discreteTopology @[to_additive] instance instSeparableSpace [SeparableSpace M] : SeparableSpace Mᵈᵐᵃ := - quotientMap_mk.separableSpace + isQuotientMap_mk.separableSpace @[to_additive] instance instFirstCountableTopology [FirstCountableTopology M] : FirstCountableTopology Mᵈᵐᵃ := - inducing_mk_symm.firstCountableTopology + isInducing_mk_symm.firstCountableTopology @[to_additive] instance instSecondCountableTopology [SecondCountableTopology M] : SecondCountableTopology Mᵈᵐᵃ := - inducing_mk_symm.secondCountableTopology + isInducing_mk_symm.secondCountableTopology @[to_additive] instance instCompactSpace [CompactSpace M] : CompactSpace Mᵈᵐᵃ := @@ -108,12 +135,12 @@ instance instCompactSpace [CompactSpace M] : CompactSpace Mᵈᵐᵃ := @[to_additive] instance instLocallyCompactSpace [LocallyCompactSpace M] : LocallyCompactSpace Mᵈᵐᵃ := - openEmbedding_mk_symm.locallyCompactSpace + isOpenEmbedding_mk_symm.locallyCompactSpace @[to_additive] instance instWeaklyLocallyCompactSpace [WeaklyLocallyCompactSpace M] : WeaklyLocallyCompactSpace Mᵈᵐᵃ := - closedEmbedding_mk_symm.weaklyLocallyCompactSpace + isClosedEmbedding_mk_symm.weaklyLocallyCompactSpace @[to_additive (attr := simp)] theorem map_mk_nhds (x : M) : map (mk : M → Mᵈᵐᵃ) (𝓝 x) = 𝓝 (mk x) := diff --git a/Mathlib/Topology/Algebra/ContinuousAffineMap.lean b/Mathlib/Topology/Algebra/ContinuousAffineMap.lean index b2d7477d2d987..0c94ea673275e 100644 --- a/Mathlib/Topology/Algebra/ContinuousAffineMap.lean +++ b/Mathlib/Topology/Algebra/ContinuousAffineMap.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ import Mathlib.LinearAlgebra.AffineSpace.AffineMap -import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.Algebra.Module.Basic /-! diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean index a753c9397ac13..f2d88910ccaaa 100644 --- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean +++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean @@ -30,49 +30,45 @@ variable (F A B C D E : Type*) [Monoid A] [Monoid B] [Monoid C] [Monoid D] [Comm /-- The type of continuous additive monoid homomorphisms from `A` to `B`. When possible, instead of parametrizing results over `(f : ContinuousAddMonoidHom A B)`, -you should parametrize over `(F : Type*) [ContinuousAddMonoidHomClass F A B] (f : F)`. +you should parametrize +over `(F : Type*) [FunLike F A B] [ContinuousMapClass F A B] [AddMonoidHomClass F A B] (f : F)`. -When you extend this structure, make sure to extend `ContinuousAddMonoidHomClass`. -/ +When you extend this structure, +make sure to extend `ContinuousMapClass` and/or `AddMonoidHomClass`, if needed. -/ structure ContinuousAddMonoidHom (A B : Type*) [AddMonoid A] [AddMonoid B] [TopologicalSpace A] - [TopologicalSpace B] extends A →+ B where - /-- Proof of continuity of the Hom. -/ - continuous_toFun : @Continuous A B _ _ toFun + [TopologicalSpace B] extends A →+ B, C(A, B) /-- The type of continuous monoid homomorphisms from `A` to `B`. When possible, instead of parametrizing results over `(f : ContinuousMonoidHom A B)`, -you should parametrize over `(F : Type*) [ContinuousMonoidHomClass F A B] (f : F)`. +you should parametrize +over `(F : Type*) [FunLike F A B] [ContinuousMapClass F A B] [MonoidHomClass F A B] (f : F)`. -When you extend this structure, make sure to extend `ContinuousAddMonoidHomClass`. -/ +When you extend this structure, +make sure to extend `ContinuousMapClass` and/or `MonoidHomClass`, if needed. -/ @[to_additive "The type of continuous additive monoid homomorphisms from `A` to `B`."] -structure ContinuousMonoidHom extends A →* B where - /-- Proof of continuity of the Hom. -/ - continuous_toFun : @Continuous A B _ _ toFun +structure ContinuousMonoidHom extends A →* B, C(A, B) section /-- `ContinuousAddMonoidHomClass F A B` states that `F` is a type of continuous additive monoid homomorphisms. -You should also extend this typeclass when you extend `ContinuousAddMonoidHom`. -/ --- Porting note: Changed A B to outParam to help synthesizing order -class ContinuousAddMonoidHomClass (A B : outParam Type*) [AddMonoid A] [AddMonoid B] +Deprecated and changed from a `class` to a `structure`. +Use `[AddMonoidHomClass F A B] [ContinuousMapClass F A B]` instead. -/ +structure ContinuousAddMonoidHomClass (A B : outParam Type*) [AddMonoid A] [AddMonoid B] [TopologicalSpace A] [TopologicalSpace B] [FunLike F A B] - extends AddMonoidHomClass F A B : Prop where - /-- Proof of the continuity of the map. -/ - map_continuous (f : F) : Continuous f + extends AddMonoidHomClass F A B, ContinuousMapClass F A B : Prop /-- `ContinuousMonoidHomClass F A B` states that `F` is a type of continuous monoid homomorphisms. -You should also extend this typeclass when you extend `ContinuousMonoidHom`. -/ --- Porting note: Changed A B to outParam to help synthesizing order -@[to_additive] -class ContinuousMonoidHomClass (A B : outParam Type*) [Monoid A] [Monoid B] +Deprecated and changed from a `class` to a `structure`. +Use `[MonoidHomClass F A B] [ContinuousMapClass F A B]` instead. -/ +@[to_additive (attr := deprecated (since := "2024-10-08"))] +structure ContinuousMonoidHomClass (A B : outParam Type*) [Monoid A] [Monoid B] [TopologicalSpace A] [TopologicalSpace B] [FunLike F A B] - extends MonoidHomClass F A B : Prop where - /-- Proof of the continuity of the map. -/ - map_continuous (f : F) : Continuous f + extends MonoidHomClass F A B, ContinuousMapClass F A B : Prop end @@ -82,18 +78,18 @@ add_decl_doc ContinuousMonoidHom.toMonoidHom /-- Reinterpret a `ContinuousAddMonoidHom` as an `AddMonoidHom`. -/ add_decl_doc ContinuousAddMonoidHom.toAddMonoidHom --- See note [lower instance priority] -@[to_additive] -instance (priority := 100) ContinuousMonoidHomClass.toContinuousMapClass - [FunLike F A B] [ContinuousMonoidHomClass F A B] : ContinuousMapClass F A B := - { ‹ContinuousMonoidHomClass F A B› with } +/-- Reinterpret a `ContinuousMonoidHom` as a `ContinuousMap`. -/ +add_decl_doc ContinuousMonoidHom.toContinuousMap + +/-- Reinterpret a `ContinuousAddMonoidHom` as a `ContinuousMap`. -/ +add_decl_doc ContinuousAddMonoidHom.toContinuousMap namespace ContinuousMonoidHom variable {A B C D E} @[to_additive] -instance funLike : FunLike (ContinuousMonoidHom A B) A B where +instance instFunLike : FunLike (ContinuousMonoidHom A B) A B where coe f := f.toFun coe_injective' f g h := by obtain ⟨⟨⟨ _ , _ ⟩, _⟩, _⟩ := f @@ -101,47 +97,47 @@ instance funLike : FunLike (ContinuousMonoidHom A B) A B where congr @[to_additive] -instance ContinuousMonoidHomClass : ContinuousMonoidHomClass (ContinuousMonoidHom A B) A B where +instance instMonoidHomClass : MonoidHomClass (ContinuousMonoidHom A B) A B where map_mul f := f.map_mul' map_one f := f.map_one' + +@[to_additive] +instance instContinuousMapClass : ContinuousMapClass (ContinuousMonoidHom A B) A B where map_continuous f := f.continuous_toFun @[to_additive (attr := ext)] theorem ext {f g : ContinuousMonoidHom A B} (h : ∀ x, f x = g x) : f = g := DFunLike.ext _ _ h -/-- Reinterpret a `ContinuousMonoidHom` as a `ContinuousMap`. -/ -@[to_additive "Reinterpret a `ContinuousAddMonoidHom` as a `ContinuousMap`."] -def toContinuousMap (f : ContinuousMonoidHom A B) : C(A, B) := - { f with } - @[to_additive] theorem toContinuousMap_injective : Injective (toContinuousMap : _ → C(A, B)) := fun f g h => ext <| by convert DFunLike.ext_iff.1 h --- Porting note: Removed simps because given definition is not a constructor application -/-- Construct a `ContinuousMonoidHom` from a `Continuous` `MonoidHom`. -/ -@[to_additive "Construct a `ContinuousAddMonoidHom` from a `Continuous` `AddMonoidHom`."] -def mk' (f : A →* B) (hf : Continuous f) : ContinuousMonoidHom A B := - { f with continuous_toFun := (hf : Continuous f.toFun)} +@[deprecated (since := "2024-10-08")] protected alias mk' := mk + +@[deprecated (since := "2024-10-08")] +protected alias _root_.ContinuousAddMonoidHom.mk' := ContinuousAddMonoidHom.mk + +set_option linter.existingAttributeWarning false in +attribute [to_additive existing] ContinuousMonoidHom.mk' /-- Composition of two continuous homomorphisms. -/ @[to_additive (attr := simps!) "Composition of two continuous homomorphisms."] def comp (g : ContinuousMonoidHom B C) (f : ContinuousMonoidHom A B) : ContinuousMonoidHom A C := - mk' (g.toMonoidHom.comp f.toMonoidHom) (g.continuous_toFun.comp f.continuous_toFun) + ⟨g.toMonoidHom.comp f.toMonoidHom, (map_continuous g).comp (map_continuous f)⟩ /-- Product of two continuous homomorphisms on the same space. -/ @[to_additive (attr := simps!) prod "Product of two continuous homomorphisms on the same space."] def prod (f : ContinuousMonoidHom A B) (g : ContinuousMonoidHom A C) : ContinuousMonoidHom A (B × C) := - mk' (f.toMonoidHom.prod g.toMonoidHom) (f.continuous_toFun.prod_mk g.continuous_toFun) + ⟨f.toMonoidHom.prod g.toMonoidHom, f.continuous_toFun.prod_mk g.continuous_toFun⟩ /-- Product of two continuous homomorphisms on different spaces. -/ @[to_additive (attr := simps!) prodMap "Product of two continuous homomorphisms on different spaces."] def prodMap (f : ContinuousMonoidHom A C) (g : ContinuousMonoidHom B D) : ContinuousMonoidHom (A × B) (C × D) := - mk' (f.toMonoidHom.prodMap g.toMonoidHom) (f.continuous_toFun.prodMap g.continuous_toFun) + ⟨f.toMonoidHom.prodMap g.toMonoidHom, f.continuous_toFun.prodMap g.continuous_toFun⟩ @[deprecated (since := "2024-10-05")] alias prod_map := prodMap @[deprecated (since := "2024-10-05")] @@ -155,7 +151,7 @@ variable (A B C D E) /-- The trivial continuous homomorphism. -/ @[to_additive (attr := simps!) "The trivial continuous homomorphism."] def one : ContinuousMonoidHom A B := - mk' 1 continuous_const + ⟨1, continuous_const⟩ @[to_additive] instance : Inhabited (ContinuousMonoidHom A B) := @@ -164,19 +160,19 @@ instance : Inhabited (ContinuousMonoidHom A B) := /-- The identity continuous homomorphism. -/ @[to_additive (attr := simps!) "The identity continuous homomorphism."] def id : ContinuousMonoidHom A A := - mk' (MonoidHom.id A) continuous_id + ⟨.id A, continuous_id⟩ /-- The continuous homomorphism given by projection onto the first factor. -/ @[to_additive (attr := simps!) "The continuous homomorphism given by projection onto the first factor."] def fst : ContinuousMonoidHom (A × B) A := - mk' (MonoidHom.fst A B) continuous_fst + ⟨MonoidHom.fst A B, continuous_fst⟩ /-- The continuous homomorphism given by projection onto the second factor. -/ @[to_additive (attr := simps!) "The continuous homomorphism given by projection onto the second factor."] def snd : ContinuousMonoidHom (A × B) B := - mk' (MonoidHom.snd A B) continuous_snd + ⟨MonoidHom.snd A B, continuous_snd⟩ /-- The continuous homomorphism given by inclusion of the first factor. -/ @[to_additive (attr := simps!) @@ -203,12 +199,12 @@ def swap : ContinuousMonoidHom (A × B) (B × A) := /-- The continuous homomorphism given by multiplication. -/ @[to_additive (attr := simps!) "The continuous homomorphism given by addition."] def mul : ContinuousMonoidHom (E × E) E := - mk' mulMonoidHom continuous_mul + ⟨mulMonoidHom, continuous_mul⟩ /-- The continuous homomorphism given by inversion. -/ @[to_additive (attr := simps!) "The continuous homomorphism given by negation."] def inv : ContinuousMonoidHom E E := - mk' invMonoidHom continuous_inv + ⟨invMonoidHom, continuous_inv⟩ variable {A B C D E} @@ -236,13 +232,27 @@ instance : TopologicalSpace (ContinuousMonoidHom A B) := variable (A B C D E) @[to_additive] -theorem inducing_toContinuousMap : Inducing (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := - ⟨rfl⟩ +theorem isInducing_toContinuousMap : + IsInducing (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := ⟨rfl⟩ + +@[deprecated (since := "2024-10-28")] alias inducing_toContinuousMap := isInducing_toContinuousMap @[to_additive] -theorem embedding_toContinuousMap : - Embedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := - ⟨inducing_toContinuousMap A B, toContinuousMap_injective⟩ +theorem isEmbedding_toContinuousMap : + IsEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := + ⟨isInducing_toContinuousMap A B, toContinuousMap_injective⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_toContinuousMap := isEmbedding_toContinuousMap + +@[to_additive] +instance instContinuousEvalConst : ContinuousEvalConst (ContinuousMonoidHom A B) A B := + .of_continuous_forget (isInducing_toContinuousMap A B).continuous + +@[to_additive] +instance instContinuousEval [LocallyCompactPair A B] : + ContinuousEval (ContinuousMonoidHom A B) A B := + .of_continuous_forget (isInducing_toContinuousMap A B).continuous @[to_additive] lemma range_toContinuousMap : @@ -253,25 +263,28 @@ lemma range_toContinuousMap : exact ⟨{ f with map_one' := h1, map_mul' := hmul }, rfl⟩ @[to_additive] -theorem closedEmbedding_toContinuousMap [ContinuousMul B] [T2Space B] : - ClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) where - toEmbedding := embedding_toContinuousMap A B +theorem isClosedEmbedding_toContinuousMap [ContinuousMul B] [T2Space B] : + IsClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) where + toIsEmbedding := isEmbedding_toContinuousMap A B isClosed_range := by simp only [range_toContinuousMap, Set.setOf_and, Set.setOf_forall] - refine .inter (isClosed_singleton.preimage (ContinuousMap.continuous_eval_const 1)) <| + refine .inter (isClosed_singleton.preimage (continuous_eval_const 1)) <| isClosed_iInter fun x ↦ isClosed_iInter fun y ↦ ?_ - exact isClosed_eq (ContinuousMap.continuous_eval_const (x * y)) <| - .mul (ContinuousMap.continuous_eval_const x) (ContinuousMap.continuous_eval_const y) + exact isClosed_eq (continuous_eval_const (x * y)) <| + .mul (continuous_eval_const x) (continuous_eval_const y) + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_toContinuousMap := isClosedEmbedding_toContinuousMap variable {A B C D E} @[to_additive] instance [T2Space B] : T2Space (ContinuousMonoidHom A B) := - (embedding_toContinuousMap A B).t2Space + (isEmbedding_toContinuousMap A B).t2Space @[to_additive] instance : TopologicalGroup (ContinuousMonoidHom A E) := - let hi := inducing_toContinuousMap A E + let hi := isInducing_toContinuousMap A E let hc := hi.continuous { continuous_mul := hi.continuous_iff.mpr (continuous_mul.comp (Continuous.prodMap hc hc)) continuous_inv := hi.continuous_iff.mpr (continuous_inv.comp hc) } @@ -280,27 +293,27 @@ instance : TopologicalGroup (ContinuousMonoidHom A E) := theorem continuous_of_continuous_uncurry {A : Type*} [TopologicalSpace A] (f : A → ContinuousMonoidHom B C) (h : Continuous (Function.uncurry fun x y => f x y)) : Continuous f := - (inducing_toContinuousMap _ _).continuous_iff.mpr + (isInducing_toContinuousMap _ _).continuous_iff.mpr (ContinuousMap.continuous_of_continuous_uncurry _ h) @[to_additive] theorem continuous_comp [LocallyCompactSpace B] : Continuous fun f : ContinuousMonoidHom A B × ContinuousMonoidHom B C => f.2.comp f.1 := - (inducing_toContinuousMap A C).continuous_iff.2 <| + (isInducing_toContinuousMap A C).continuous_iff.2 <| ContinuousMap.continuous_comp'.comp - ((inducing_toContinuousMap A B).prodMap (inducing_toContinuousMap B C)).continuous + ((isInducing_toContinuousMap A B).prodMap (isInducing_toContinuousMap B C)).continuous @[to_additive] theorem continuous_comp_left (f : ContinuousMonoidHom A B) : Continuous fun g : ContinuousMonoidHom B C => g.comp f := - (inducing_toContinuousMap A C).continuous_iff.2 <| - f.toContinuousMap.continuous_comp_left.comp (inducing_toContinuousMap B C).continuous + (isInducing_toContinuousMap A C).continuous_iff.2 <| + f.toContinuousMap.continuous_precomp.comp (isInducing_toContinuousMap B C).continuous @[to_additive] theorem continuous_comp_right (f : ContinuousMonoidHom B C) : Continuous fun g : ContinuousMonoidHom A B => f.comp g := - (inducing_toContinuousMap A C).continuous_iff.2 <| - f.toContinuousMap.continuous_comp.comp (inducing_toContinuousMap A B).continuous + (isInducing_toContinuousMap A C).continuous_iff.2 <| + f.toContinuousMap.continuous_postcomp.comp (isInducing_toContinuousMap A B).continuous variable (E) @@ -365,7 +378,7 @@ theorem locallyCompactSpace_of_equicontinuousAt (U : Set X) (V : Set Y) have h3 : IsOpen T := isOpen_induced (ContinuousMap.isOpen_setOf_mapsTo hU isOpen_interior) exact h1.mono (interior_maximal h2 h3) exact TopologicalSpace.PositiveCompacts.locallyCompactSpace_of_group - ⟨⟨S2, (inducing_toContinuousMap X Y).isCompact_iff.mpr + ⟨⟨S2, (isInducing_toContinuousMap X Y).isCompact_iff.mpr (ArzelaAscoli.isCompact_of_equicontinuous S3 hS4.isCompact h)⟩, hS2⟩ variable [LocallyCompactSpace X] diff --git a/Mathlib/Topology/Algebra/Equicontinuity.lean b/Mathlib/Topology/Algebra/Equicontinuity.lean index d81fb26a3877a..b2eff285e0920 100644 --- a/Mathlib/Topology/Algebra/Equicontinuity.lean +++ b/Mathlib/Topology/Algebra/Equicontinuity.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker -/ import Mathlib.Topology.Algebra.UniformConvergence +import Mathlib.Topology.UniformSpace.Equicontinuity /-! # Algebra-related equicontinuity criterions diff --git a/Mathlib/Topology/Algebra/Field.lean b/Mathlib/Topology/Algebra/Field.lean index 0b7ccfdded133..c897f0bb8fa18 100644 --- a/Mathlib/Topology/Algebra/Field.lean +++ b/Mathlib/Topology/Algebra/Field.lean @@ -101,7 +101,7 @@ open Topology theorem IsLocalMin.inv {f : α → β} {a : α} (h1 : IsLocalMin f a) (h2 : ∀ᶠ z in 𝓝 a, 0 < f z) : IsLocalMax f⁻¹ a := by - filter_upwards [h1, h2] with z h3 h4 using(inv_le_inv h4 h2.self_of_nhds).mpr h3 + filter_upwards [h1, h2] with z h3 h4 using(inv_le_inv₀ h4 h2.self_of_nhds).mpr h3 end LocalExtr diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index 49c268a901a0c..cc7be69cbeef0 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -3,13 +3,9 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ -import Mathlib.GroupTheory.GroupAction.ConjAct -import Mathlib.GroupTheory.GroupAction.Quotient -import Mathlib.Topology.Algebra.Monoid -import Mathlib.Topology.Algebra.Constructions -import Mathlib.Topology.Maps.OpenQuotient +import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Order.Archimedean.Basic -import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Topology.Algebra.Monoid /-! # Topological groups @@ -378,11 +374,13 @@ theorem continuousInv_inf {t₁ t₂ : TopologicalSpace G} (h₁ : @ContinuousIn end LatticeOps @[to_additive] -theorem Inducing.continuousInv {G H : Type*} [Inv G] [Inv H] [TopologicalSpace G] - [TopologicalSpace H] [ContinuousInv H] {f : G → H} (hf : Inducing f) +theorem IsInducing.continuousInv {G H : Type*} [Inv G] [Inv H] [TopologicalSpace G] + [TopologicalSpace H] [ContinuousInv H] {f : G → H} (hf : IsInducing f) (hf_inv : ∀ x, f x⁻¹ = (f x)⁻¹) : ContinuousInv G := ⟨hf.continuous_iff.2 <| by simpa only [Function.comp_def, hf_inv] using hf.continuous.inv⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.continuousInv := IsInducing.continuousInv + section TopologicalGroup /-! @@ -547,7 +545,7 @@ open MulOpposite @[to_additive] instance [Inv α] [ContinuousInv α] : ContinuousInv αᵐᵒᵖ := - opHomeomorph.symm.inducing.continuousInv unop_inv + opHomeomorph.symm.isInducing.continuousInv unop_inv /-- If multiplication is continuous in `α`, then it also is in `αᵐᵒᵖ`. -/ @[to_additive "If addition is continuous in `α`, then it also is in `αᵃᵒᵖ`."] @@ -587,24 +585,25 @@ theorem Homeomorph.shearMulRight_symm_coe : variable {G} @[to_additive] -protected theorem Inducing.topologicalGroup {F : Type*} [Group H] [TopologicalSpace H] - [FunLike F H G] [MonoidHomClass F H G] (f : F) (hf : Inducing f) : TopologicalGroup H := +protected theorem IsInducing.topologicalGroup {F : Type*} [Group H] [TopologicalSpace H] + [FunLike F H G] [MonoidHomClass F H G] (f : F) (hf : IsInducing f) : TopologicalGroup H := { toContinuousMul := hf.continuousMul _ toContinuousInv := hf.continuousInv (map_inv f) } +@[deprecated (since := "2024-10-28")] alias Inducing.topologicalGroup := IsInducing.topologicalGroup + @[to_additive] --- Porting note: removed `protected` (needs to be in namespace) theorem topologicalGroup_induced {F : Type*} [Group H] [FunLike F H G] [MonoidHomClass F H G] (f : F) : @TopologicalGroup H (induced f ‹_›) _ := letI := induced f ‹_› - Inducing.topologicalGroup f ⟨rfl⟩ + IsInducing.topologicalGroup f ⟨rfl⟩ namespace Subgroup @[to_additive] instance (S : Subgroup G) : TopologicalGroup S := - Inducing.topologicalGroup S.subtype inducing_subtype_val + IsInducing.subtypeVal.topologicalGroup S.subtype end Subgroup @@ -847,87 +846,6 @@ theorem TopologicalGroup.exists_antitone_basis_nhds_one [FirstCountableTopology end TopologicalGroup -namespace QuotientGroup - -variable [TopologicalSpace G] [Group G] - -@[to_additive] -instance instTopologicalSpace (N : Subgroup G) : TopologicalSpace (G ⧸ N) := - instTopologicalSpaceQuotient - -@[to_additive] -instance [CompactSpace G] (N : Subgroup G) : CompactSpace (G ⧸ N) := - Quotient.compactSpace - -@[to_additive] -theorem quotientMap_mk (N : Subgroup G) : QuotientMap (mk : G → G ⧸ N) := - quotientMap_quot_mk - -@[to_additive] -theorem continuous_mk {N : Subgroup G} : Continuous (mk : G → G ⧸ N) := - continuous_quot_mk - -section ContinuousMul - -variable [ContinuousMul G] {N : Subgroup G} - -@[to_additive] -theorem isOpenMap_coe : IsOpenMap ((↑) : G → G ⧸ N) := isOpenMap_quotient_mk'_mul - -@[to_additive] -theorem isOpenQuotientMap_mk : IsOpenQuotientMap (mk : G → G ⧸ N) := - MulAction.isOpenQuotientMap_quotientMk - -@[to_additive (attr := simp)] -theorem dense_preimage_mk {s : Set (G ⧸ N)} : Dense ((↑) ⁻¹' s : Set G) ↔ Dense s := - isOpenQuotientMap_mk.dense_preimage_iff - -@[to_additive] -theorem dense_image_mk {s : Set G} : - Dense (mk '' s : Set (G ⧸ N)) ↔ Dense (s * (N : Set G)) := by - rw [← dense_preimage_mk, preimage_image_mk_eq_mul] - -@[to_additive] -instance instContinuousSMul : ContinuousSMul G (G ⧸ N) where - continuous_smul := by - rw [← (IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).continuous_comp_iff] - exact continuous_mk.comp continuous_mul - -variable (N) - -/-- Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient. -/ -@[to_additive - "Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient."] -theorem nhds_eq (x : G) : 𝓝 (x : G ⧸ N) = Filter.map (↑) (𝓝 x) := - (isOpenQuotientMap_mk.map_nhds_eq _).symm - -@[to_additive] -instance instFirstCountableTopology [FirstCountableTopology G] : - FirstCountableTopology (G ⧸ N) where - nhds_generated_countable := mk_surjective.forall.2 fun x ↦ nhds_eq N x ▸ inferInstance - -@[to_additive (attr := deprecated (since := "2024-08-05"))] -theorem nhds_one_isCountablyGenerated [FirstCountableTopology G] [N.Normal] : - (𝓝 (1 : G ⧸ N)).IsCountablyGenerated := - inferInstance - -end ContinuousMul - -variable [TopologicalGroup G] (N : Subgroup G) - -@[to_additive] -instance instTopologicalGroup [N.Normal] : TopologicalGroup (G ⧸ N) where - continuous_mul := by - rw [← (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).continuous_comp_iff] - exact continuous_mk.comp continuous_mul - continuous_inv := continuous_inv.quotient_map' _ - -@[to_additive (attr := deprecated (since := "2024-08-05"))] -theorem _root_.topologicalGroup_quotient [N.Normal] : TopologicalGroup (G ⧸ N) := - instTopologicalGroup N - -end QuotientGroup - /-- A typeclass saying that `p : G × G ↦ p.1 - p.2` is a continuous function. This property automatically holds for topological additive groups but it also holds, e.g., for `ℝ≥0`. -/ class ContinuousSub (G : Type*) [TopologicalSpace G] [Sub G] : Prop where @@ -1132,7 +1050,8 @@ theorem MulAction.isClosedMap_quotient [CompactSpace α] : letI := orbitRel α β IsClosedMap (Quotient.mk' : β → Quotient (orbitRel α β)) := by intro t ht - rw [← quotientMap_quotient_mk'.isClosed_preimage, MulAction.quotient_preimage_image_eq_union_mul] + rw [← isQuotientMap_quotient_mk'.isClosed_preimage, + MulAction.quotient_preimage_image_eq_union_mul] convert ht.smul_left_of_isCompact (isCompact_univ (X := α)) rw [← biUnion_univ, ← iUnion_smul_left_image] rfl @@ -1250,13 +1169,6 @@ theorem IsClosed.mul_right_of_isCompact (ht : IsClosed t) (hs : IsCompact s) : rw [← image_op_smul] exact IsClosed.smul_left_of_isCompact ht (hs.image continuous_op) -@[to_additive] -theorem QuotientGroup.isClosedMap_coe {H : Subgroup G} (hH : IsCompact (H : Set G)) : - IsClosedMap ((↑) : G → G ⧸ H) := by - intro t ht - rw [← (quotientMap_mk H).isClosed_preimage, preimage_image_mk_eq_mul] - exact ht.mul_right_of_isCompact hH - @[to_additive] lemma subset_mul_closure_one {G} [MulOneClass G] [TopologicalSpace G] (s : Set G) : s ⊆ s * (closure {1} : Set G) := by @@ -1348,7 +1260,7 @@ variable {G} @[to_additive] theorem group_inseparable_iff {x y : G} : Inseparable x y ↔ x / y ∈ closure (1 : Set G) := by rw [← singleton_one, ← specializes_iff_mem_closure, specializes_comm, specializes_iff_inseparable, - ← (Homeomorph.mulRight y⁻¹).embedding.inseparable_iff] + ← (Homeomorph.mulRight y⁻¹).isEmbedding.inseparable_iff] simp [div_eq_mul_inv] @[to_additive] @@ -1382,13 +1294,6 @@ theorem exists_closed_nhds_one_inv_eq_mul_subset {U : Set G} (hU : U ∈ 𝓝 1) variable (S : Subgroup G) [Subgroup.Normal S] [IsClosed (S : Set G)] -@[to_additive] -instance Subgroup.t3_quotient_of_isClosed (S : Subgroup G) [Subgroup.Normal S] - [hS : IsClosed (S : Set G)] : T3Space (G ⧸ S) := by - rw [← QuotientGroup.ker_mk' S] at hS - haveI := TopologicalGroup.t1Space (G ⧸ S) (quotientMap_quotient_mk'.isClosed_preimage.mp hS) - infer_instance - /-- A subgroup `S` of a topological group `G` acts on `G` properly discontinuously on the left, if it is discrete in the sense that `S ∩ K` is finite for all compact `K`. (See also `DiscreteTopology`.) -/ @@ -1618,18 +1523,6 @@ theorem exists_isCompact_isClosed_nhds_one [WeaklyLocallyCompactSpace G] : let ⟨K, hK₁, hKcomp, hKcl⟩ := exists_mem_nhds_isCompact_isClosed (1 : G) ⟨K, hKcomp, hKcl, hK₁⟩ -/-- A quotient of a locally compact group is locally compact. -/ -@[to_additive] -instance [LocallyCompactSpace G] (N : Subgroup G) : LocallyCompactSpace (G ⧸ N) := by - refine ⟨fun x n hn ↦ ?_⟩ - let π := ((↑) : G → G ⧸ N) - have C : Continuous π := continuous_quotient_mk' - obtain ⟨y, rfl⟩ : ∃ y, π y = x := Quot.exists_rep x - have : π ⁻¹' n ∈ 𝓝 y := preimage_nhds_coinduced hn - rcases local_compact_nhds this with ⟨s, s_mem, hs, s_comp⟩ - exact ⟨π '' s, QuotientGroup.isOpenMap_coe.image_mem_nhds s_mem, mapsTo'.mp hs, - s_comp.image C⟩ - end section @@ -1665,30 +1558,6 @@ instance {G} [TopologicalSpace G] [AddGroup G] [TopologicalAddGroup G] : TopologicalGroup (Multiplicative G) where continuous_inv := @continuous_neg G _ _ _ -section Quotient - -variable [Group G] [TopologicalSpace G] [ContinuousMul G] {Γ : Subgroup G} - -@[to_additive] -instance QuotientGroup.continuousConstSMul : ContinuousConstSMul G (G ⧸ Γ) where - continuous_const_smul g := by - convert ((@continuous_const _ _ _ _ g).mul continuous_id).quotient_map' _ - -@[to_additive] -theorem QuotientGroup.continuous_smul₁ (x : G ⧸ Γ) : Continuous fun g : G => g • x := by - induction x using QuotientGroup.induction_on - exact continuous_quotient_mk'.comp (continuous_mul_right _) - -/-- The quotient of a second countable topological group by a subgroup is second countable. -/ -@[to_additive - "The quotient of a second countable additive topological group by a subgroup is second - countable."] -instance QuotientGroup.secondCountableTopology [SecondCountableTopology G] : - SecondCountableTopology (G ⧸ Γ) := - ContinuousConstSMul.secondCountableTopology - -end Quotient - /-- If `G` is a group with topological `⁻¹`, then it is homeomorphic to its units. -/ @[to_additive " If `G` is an additive group with topological negation, then it is homeomorphic to its additive units."] @@ -1697,9 +1566,12 @@ def toUnits_homeomorph [Group G] [TopologicalSpace G] [ContinuousInv G] : G ≃ continuous_toFun := Units.continuous_iff.2 ⟨continuous_id, continuous_inv⟩ continuous_invFun := Units.continuous_val -@[to_additive] theorem Units.embedding_val [Group G] [TopologicalSpace G] [ContinuousInv G] : - Embedding (val : Gˣ → G) := - toUnits_homeomorph.symm.embedding +@[to_additive] theorem Units.isEmbedding_val [Group G] [TopologicalSpace G] [ContinuousInv G] : + IsEmbedding (val : Gˣ → G) := + toUnits_homeomorph.symm.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias Units.embedding_val := Units.isEmbedding_val namespace Units @@ -1911,7 +1783,7 @@ topologies contained in the intersection of `s` and `t`. -/ instance : CompleteSemilatticeInf (GroupTopology α) := { inferInstanceAs (InfSet (GroupTopology α)), inferInstanceAs (PartialOrder (GroupTopology α)) with - sInf_le := fun S a haS => toTopologicalSpace_le.1 <| sInf_le ⟨a, haS, rfl⟩ + sInf_le := fun _ a haS => toTopologicalSpace_le.1 <| sInf_le ⟨a, haS, rfl⟩ le_sInf := by intro S a hab apply (inferInstanceAs (CompleteLattice (TopologicalSpace α))).le_sInf @@ -1944,4 +1816,4 @@ theorem coinduced_continuous {α β : Type*} [t : TopologicalSpace α] [Group β end GroupTopology -set_option linter.style.longFile 2100 +set_option linter.style.longFile 2000 diff --git a/Mathlib/Topology/Algebra/Group/Quotient.lean b/Mathlib/Topology/Algebra/Group/Quotient.lean new file mode 100644 index 0000000000000..d4e000715092d --- /dev/null +++ b/Mathlib/Topology/Algebra/Group/Quotient.lean @@ -0,0 +1,136 @@ +/- +Copyright (c) 2017 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot, Yury Kudryashov +-/ +import Mathlib.GroupTheory.GroupAction.Quotient +import Mathlib.GroupTheory.QuotientGroup.Defs +import Mathlib.Topology.Algebra.Group.Basic +import Mathlib.Topology.Maps.OpenQuotient + +/-! +# Topology on the quotient group + +In this file we define topology on `G ⧸ N`, where `N` is a subgroup of `G`, +and prove basic properties of this topology. +-/ + +open scoped Pointwise Topology + +variable {G : Type*} [TopologicalSpace G] [Group G] + +namespace QuotientGroup + +@[to_additive] +instance instTopologicalSpace (N : Subgroup G) : TopologicalSpace (G ⧸ N) := + instTopologicalSpaceQuotient + +@[to_additive] +instance [CompactSpace G] (N : Subgroup G) : CompactSpace (G ⧸ N) := + Quotient.compactSpace + +@[to_additive] +theorem isQuotientMap_mk (N : Subgroup G) : IsQuotientMap (mk : G → G ⧸ N) := + isQuotientMap_quot_mk + +@[deprecated (since := "2024-10-22")] +alias quotientMap_mk := isQuotientMap_mk + +@[to_additive] +theorem continuous_mk {N : Subgroup G} : Continuous (mk : G → G ⧸ N) := + continuous_quot_mk + +section ContinuousMul + +variable [ContinuousMul G] {N : Subgroup G} + +@[to_additive] +theorem isOpenMap_coe : IsOpenMap ((↑) : G → G ⧸ N) := isOpenMap_quotient_mk'_mul + +@[to_additive] +theorem isOpenQuotientMap_mk : IsOpenQuotientMap (mk : G → G ⧸ N) := + MulAction.isOpenQuotientMap_quotientMk + +@[to_additive (attr := simp)] +theorem dense_preimage_mk {s : Set (G ⧸ N)} : Dense ((↑) ⁻¹' s : Set G) ↔ Dense s := + isOpenQuotientMap_mk.dense_preimage_iff + +@[to_additive] +theorem dense_image_mk {s : Set G} : + Dense (mk '' s : Set (G ⧸ N)) ↔ Dense (s * (N : Set G)) := by + rw [← dense_preimage_mk, preimage_image_mk_eq_mul] + +@[to_additive] +instance instContinuousSMul : ContinuousSMul G (G ⧸ N) where + continuous_smul := by + rw [← (IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).continuous_comp_iff] + exact continuous_mk.comp continuous_mul + +@[to_additive] +instance instContinuousConstSMul : ContinuousConstSMul G (G ⧸ N) := inferInstance + +/-- A quotient of a locally compact group is locally compact. -/ +@[to_additive] +instance instLocallyCompactSpace [LocallyCompactSpace G] (N : Subgroup G) : + LocallyCompactSpace (G ⧸ N) := + QuotientGroup.isOpenQuotientMap_mk.locallyCompactSpace + +@[to_additive (attr := deprecated (since := "2024-10-05"))] +theorem continuous_smul₁ (x : G ⧸ N) : Continuous fun g : G => g • x := + continuous_id.smul continuous_const + +variable (N) + +/-- Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient. -/ +@[to_additive + "Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient."] +theorem nhds_eq (x : G) : 𝓝 (x : G ⧸ N) = Filter.map (↑) (𝓝 x) := + (isOpenQuotientMap_mk.map_nhds_eq _).symm + +@[to_additive] +instance instFirstCountableTopology [FirstCountableTopology G] : + FirstCountableTopology (G ⧸ N) where + nhds_generated_countable := mk_surjective.forall.2 fun x ↦ nhds_eq N x ▸ inferInstance + +/-- The quotient of a second countable topological group by a subgroup is second countable. -/ +@[to_additive + "The quotient of a second countable additive topological group by a subgroup is second + countable."] +instance instSecondCountableTopology [SecondCountableTopology G] : + SecondCountableTopology (G ⧸ N) := + ContinuousConstSMul.secondCountableTopology + +@[to_additive (attr := deprecated (since := "2024-08-05"))] +theorem nhds_one_isCountablyGenerated [FirstCountableTopology G] [N.Normal] : + (𝓝 (1 : G ⧸ N)).IsCountablyGenerated := + inferInstance + +end ContinuousMul + +variable [TopologicalGroup G] (N : Subgroup G) + +@[to_additive] +instance instTopologicalGroup [N.Normal] : TopologicalGroup (G ⧸ N) where + continuous_mul := by + rw [← (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).continuous_comp_iff] + exact continuous_mk.comp continuous_mul + continuous_inv := continuous_inv.quotient_map' _ + +@[to_additive (attr := deprecated (since := "2024-08-05"))] +theorem _root_.topologicalGroup_quotient [N.Normal] : TopologicalGroup (G ⧸ N) := + instTopologicalGroup N + +@[to_additive] +theorem isClosedMap_coe {H : Subgroup G} (hH : IsCompact (H : Set G)) : + IsClosedMap ((↑) : G → G ⧸ H) := by + intro t ht + rw [← (isQuotientMap_mk H).isClosed_preimage, preimage_image_mk_eq_mul] + exact ht.mul_right_of_isCompact hH + +@[to_additive] +instance instT3Space [N.Normal] [hN : IsClosed (N : Set G)] : T3Space (G ⧸ N) := by + rw [← QuotientGroup.ker_mk' N] at hN + haveI := TopologicalGroup.t1Space (G ⧸ N) ((isQuotientMap_mk N).isClosed_preimage.mp hN) + infer_instance + +end QuotientGroup diff --git a/Mathlib/Topology/Algebra/GroupCompletion.lean b/Mathlib/Topology/Algebra/GroupCompletion.lean index cadc887e6ae6e..6cf8c9761c59d 100644 --- a/Mathlib/Topology/Algebra/GroupCompletion.lean +++ b/Mathlib/Topology/Algebra/GroupCompletion.lean @@ -3,7 +3,6 @@ Copyright (c) 2018 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Johannes Hölzl -/ -import Mathlib.Topology.Algebra.UniformGroup import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Topology.UniformSpace.Completion @@ -136,8 +135,8 @@ instance : SubNegMonoid (Completion α) := zsmul_succ' := fun n a ↦ Completion.induction_on a (isClosed_eq continuous_map <| continuous_map₂ continuous_map continuous_id) fun a ↦ - show Int.ofNat n.succ • (a : Completion α) = _ by - rw [← coe_smul, show Int.ofNat n.succ • a = Int.ofNat n • a + a from + show (n.succ : ℤ) • (a : Completion α) = _ by + rw [← coe_smul, show (n.succ : ℤ) • a = (n : ℤ) • a + a from SubNegMonoid.zsmul_succ' n a, coe_add, coe_smul] zsmul_neg' := fun n a ↦ Completion.induction_on a diff --git a/Mathlib/Topology/Algebra/GroupWithZero.lean b/Mathlib/Topology/Algebra/GroupWithZero.lean index b601051b87dc5..17c7548166c68 100644 --- a/Mathlib/Topology/Algebra/GroupWithZero.lean +++ b/Mathlib/Topology/Algebra/GroupWithZero.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Pi.Lemmas +import Mathlib.Algebra.GroupWithZero.Units.Equiv import Mathlib.Topology.Algebra.Monoid import Mathlib.Topology.Homeomorph @@ -128,10 +129,13 @@ end Inv₀ /-- If `G₀` is a group with zero with topology such that `x ↦ x⁻¹` is continuous at all nonzero points. Then the coercion `G₀ˣ → G₀` is a topological embedding. -/ -theorem Units.embedding_val₀ [GroupWithZero G₀] [TopologicalSpace G₀] [HasContinuousInv₀ G₀] : - Embedding (val : G₀ˣ → G₀) := +theorem Units.isEmbedding_val₀ [GroupWithZero G₀] [TopologicalSpace G₀] [HasContinuousInv₀ G₀] : + IsEmbedding (val : G₀ˣ → G₀) := embedding_val_mk <| (continuousOn_inv₀ (G₀ := G₀)).mono fun _ ↦ IsUnit.ne_zero +@[deprecated (since := "2024-10-26")] +alias Units.embedding_val₀ := Units.isEmbedding_val₀ + section NhdsInv variable [GroupWithZero G₀] [TopologicalSpace G₀] [HasContinuousInv₀ G₀] {x : G₀} diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index bc17c8afdc322..56029818b2015 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -186,12 +186,14 @@ protected theorem HasProd.map [CommMonoid γ] [TopologicalSpace γ] (hf : HasPro exact (hg.tendsto a).comp hf @[to_additive] -protected theorem Inducing.hasProd_iff [CommMonoid γ] [TopologicalSpace γ] {G} - [FunLike G α γ] [MonoidHomClass G α γ] {g : G} (hg : Inducing g) (f : β → α) (a : α) : +protected theorem IsInducing.hasProd_iff [CommMonoid γ] [TopologicalSpace γ] {G} + [FunLike G α γ] [MonoidHomClass G α γ] {g : G} (hg : IsInducing g) (f : β → α) (a : α) : HasProd (g ∘ f) (g a) ↔ HasProd f a := by simp_rw [HasProd, comp_apply, ← map_prod] exact hg.tendsto_nhds_iff.symm +@[deprecated (since := "2024-10-28")] alias Inducing.hasProd_iff := IsInducing.hasProd_iff + @[to_additive] protected theorem Multipliable.map [CommMonoid γ] [TopologicalSpace γ] (hf : Multipliable f) {G} [FunLike G α γ] [MonoidHomClass G α γ] (g : G) (hg : Continuous g) : Multipliable (g ∘ f) := @@ -212,8 +214,8 @@ theorem Multipliable.map_tprod [CommMonoid γ] [TopologicalSpace γ] [T2Space γ g (∏' i, f i) = ∏' i, g (f i) := (HasProd.tprod_eq (HasProd.map hf.hasProd g hg)).symm @[to_additive] -theorem Inducing.multipliable_iff_tprod_comp_mem_range [CommMonoid γ] [TopologicalSpace γ] - [T2Space γ] {G} [FunLike G α γ] [MonoidHomClass G α γ] {g : G} (hg : Inducing g) (f : β → α) : +lemma IsInducing.multipliable_iff_tprod_comp_mem_range [CommMonoid γ] [TopologicalSpace γ] + [T2Space γ] {G} [FunLike G α γ] [MonoidHomClass G α γ] {g : G} (hg : IsInducing g) (f : β → α) : Multipliable f ↔ Multipliable (g ∘ f) ∧ ∏' i, g (f i) ∈ Set.range g := by constructor · intro hf @@ -227,6 +229,10 @@ theorem Inducing.multipliable_iff_tprod_comp_mem_range [CommMonoid γ] [Topologi simp_rw [comp_apply, ← ha] at this exact (hg.hasProd_iff f a).mp this +@[deprecated (since := "2024-10-28")] +alias Inducing.multipliable_iff_tprod_comp_mem_range := + IsInducing.multipliable_iff_tprod_comp_mem_range + /-- "A special case of `Multipliable.map_iff_of_leftInverse` for convenience" -/ @[to_additive "A special case of `Summable.map_iff_of_leftInverse` for convenience"] protected theorem Multipliable.map_iff_of_equiv [CommMonoid γ] [TopologicalSpace γ] {G} @@ -572,7 +578,7 @@ theorem tprod_eq_mul_tprod_ite' [DecidableEq β] {f : β → α} (b : β) ∏' x, f x = ∏' x, (ite (x = b) (f x) 1 * update f b 1 x) := tprod_congr fun n ↦ by split_ifs with h <;> simp [update_apply, h] _ = (∏' x, ite (x = b) (f x) 1) * ∏' x, update f b 1 x := - tprod_mul ⟨ite (b = b) (f b) 1, hasProd_single b fun b hb ↦ if_neg hb⟩ hf + tprod_mul ⟨ite (b = b) (f b) 1, hasProd_single b fun _ hb ↦ if_neg hb⟩ hf _ = ite (b = b) (f b) 1 * ∏' x, update f b 1 x := by congr exact tprod_eq_mulSingle b fun b' hb' ↦ if_neg hb' diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean index b47e95b56f4ad..47d09ed95c689 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean @@ -86,7 +86,7 @@ theorem HasProd.sigma {γ : β → Type*} {f : (Σ b : β, γ b) → α} {g : β use u.image Sigma.fst, trivial intro bs hbs simp only [Set.mem_preimage, Finset.le_iff_subset] at hu - have : Tendsto (fun t : Finset (Σb, γ b) ↦ ∏ p ∈ t.filter fun p ↦ p.1 ∈ bs, f p) atTop + have : Tendsto (fun t : Finset (Σb, γ b) ↦ ∏ p ∈ t with p.1 ∈ bs, f p) atTop (𝓝 <| ∏ b ∈ bs, g b) := by simp only [← sigma_preimage_mk, prod_sigma] refine tendsto_finset_prod _ fun b _ ↦ ?_ @@ -161,17 +161,17 @@ theorem HasProd.of_sigma {γ : β → Type*} {f : (Σ b : β, γ b) → α} {g : obtain ⟨t0, st0, ht0⟩ : ∃ t0, ∏ i ∈ t0, g i ∈ v ∧ s.image Sigma.fst ⊆ t0 := by have A : ∀ᶠ t0 in (atTop : Filter (Finset β)), ∏ i ∈ t0, g i ∈ v := hg (v_open.mem_nhds hv) exact (A.and (Ici_mem_atTop _)).exists - have L : Tendsto (fun t : Finset (Σb, γ b) ↦ ∏ p ∈ t.filter fun p ↦ p.1 ∈ t0, f p) atTop + have L : Tendsto (fun t : Finset (Σb, γ b) ↦ ∏ p ∈ t with p.1 ∈ t0, f p) atTop (𝓝 <| ∏ b ∈ t0, g b) := by simp only [← sigma_preimage_mk, prod_sigma] refine tendsto_finset_prod _ fun b _ ↦ ?_ change Tendsto (fun t ↦ (fun t ↦ ∏ s ∈ t, f ⟨b, s⟩) (preimage t (Sigma.mk b) _)) atTop (𝓝 (g b)) exact (hf b).comp (tendsto_finset_preimage_atTop_atTop (sigma_mk_injective)) - have : ∃ t, ∏ p ∈ t.filter (fun p ↦ p.1 ∈ t0), f p ∈ v ∧ s ⊆ t := + have : ∃ t, ∏ p ∈ t with p.1 ∈ t0, f p ∈ v ∧ s ⊆ t := ((Tendsto.eventually_mem L (v_open.mem_nhds st0)).and (Ici_mem_atTop _)).exists obtain ⟨t, tv, st⟩ := this - refine ⟨t.filter (fun p ↦ p.1 ∈ t0), fun x hx ↦ ?_, vu tv⟩ + refine ⟨{p ∈ t | p.1 ∈ t0}, fun x hx ↦ ?_, vu tv⟩ simpa only [mem_filter, st hx, true_and] using ht0 (mem_image_of_mem Sigma.fst hx) variable [CompleteSpace α] diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean index 92ae820ce40a0..2bf685cd201e1 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean @@ -5,7 +5,7 @@ Authors: Johannes Hölzl -/ import Mathlib.Algebra.BigOperators.Finprod import Mathlib.Order.Filter.AtTopBot.BigOperators -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Infinite sum and product over a topological monoid diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean index 9532cd4e53ab9..057b3e6ac56a0 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean @@ -5,7 +5,8 @@ Authors: Johannes Hölzl -/ import Mathlib.SetTheory.Cardinal.Finite import Mathlib.Topology.Algebra.InfiniteSum.Basic -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Topology.UniformSpace.Cauchy +import Mathlib.Topology.Algebra.UniformGroup.Defs /-! # Infinite sums and products in topological groups @@ -241,9 +242,9 @@ theorem Multipliable.multipliable_of_eq_one_or_self (hf : Multipliable f) exact multipliable_iff_vanishing.2 fun e he ↦ let ⟨s, hs⟩ := multipliable_iff_vanishing.1 hf e he ⟨s, fun t ht ↦ - have eq : ∏ b ∈ t.filter fun b ↦ g b = f b, f b = ∏ b ∈ t, g b := + have eq : ∏ b ∈ t with g b = f b, f b = ∏ b ∈ t, g b := calc - ∏ b ∈ t.filter fun b ↦ g b = f b, f b = ∏ b ∈ t.filter fun b ↦ g b = f b, g b := + ∏ b ∈ t with g b = f b, f b = ∏ b ∈ t with g b = f b, g b := Finset.prod_congr rfl fun b hb ↦ (Finset.mem_filter.1 hb).2.symm _ = ∏ b ∈ t, g b := by {refine Finset.prod_subset (Finset.filter_subset _ _) ?_ diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean index 88fad0d581136..612e335b22582 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean @@ -269,10 +269,10 @@ alias ⟨Summable.of_abs, Summable.abs⟩ := summable_abs_iff theorem Finite.of_summable_const [LinearOrderedAddCommGroup α] [TopologicalSpace α] [Archimedean α] [OrderClosedTopology α] {b : α} (hb : 0 < b) (hf : Summable fun _ : ι ↦ b) : Finite ι := by - have H : ∀ s : Finset ι, s.card • b ≤ ∑' _ : ι, b := fun s ↦ by + have H : ∀ s : Finset ι, #s • b ≤ ∑' _ : ι, b := fun s ↦ by simpa using sum_le_hasSum s (fun a _ ↦ hb.le) hf.hasSum obtain ⟨n, hn⟩ := Archimedean.arch (∑' _ : ι, b) hb - have : ∀ s : Finset ι, s.card ≤ n := fun s ↦ by + have : ∀ s : Finset ι, #s ≤ n := fun s ↦ by simpa [nsmul_le_nsmul_iff_left hb] using (H s).trans hn have : Fintype ι := fintypeOfFinsetCardLe n this infer_instance diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Real.lean b/Mathlib/Topology/Algebra/InfiniteSum/Real.lean index 1ba9e35f1b1fc..76bd90df592fd 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Real.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Real.lean @@ -5,7 +5,6 @@ Authors: Sébastien Gouëzel, Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Topology.Algebra.InfiniteSum.Order -import Mathlib.Topology.Instances.Real import Mathlib.Topology.Instances.ENNReal /-! diff --git a/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean b/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean index 0391d939b2f46..93a4d39bc7ed4 100644 --- a/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean @@ -447,9 +447,8 @@ end Semiring section Ring -variable {R M M' N N' ι : Type*} [Ring R] [AddCommGroup M] [Module R M] [TopologicalSpace M] - [AddCommGroup M'] [Module R M'] [TopologicalSpace M'] [AddCommGroup N] [Module R N] - [TopologicalSpace N] [AddCommGroup N'] [Module R N'] [TopologicalSpace N'] {n : ℕ} +variable {R M N ι : Type*} [Ring R] [AddCommGroup M] [Module R M] [TopologicalSpace M] + [AddCommGroup N] [Module R N] [TopologicalSpace N] (f g : M [⋀^ι]→L[R] N) @[simp] @@ -489,10 +488,9 @@ end Ring section CommSemiring -variable {R M M' N N' ι : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] - [TopologicalSpace M] [AddCommMonoid M'] [Module R M'] [TopologicalSpace M'] [AddCommMonoid N] - [Module R N] [TopologicalSpace N] [AddCommMonoid N'] [Module R N'] [TopologicalSpace N'] {n : ℕ} - (f g : M [⋀^ι]→L[R] N) +variable {R M N ι : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [TopologicalSpace M] [AddCommMonoid N] [Module R N] [TopologicalSpace N] + (f : M [⋀^ι]→L[R] N) theorem map_piecewise_smul [DecidableEq ι] (c : ι → R) (m : ι → M) (s : Finset ι) : f (s.piecewise (fun i => c i • m i) m) = (∏ i ∈ s, c i) • f m := @@ -561,7 +559,7 @@ end Module section SMulRight -variable {R A M N ι : Type*} [CommSemiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M] +variable {R M N ι : Type*} [CommSemiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module R N] [TopologicalSpace R] [TopologicalSpace M] [TopologicalSpace N] [ContinuousSMul R N] (f : M [⋀^ι]→L[R] R) (z : N) @@ -592,8 +590,8 @@ variable (R M N N') /-- `ContinuousLinearMap.compContinuousAlternatingMap` as a bundled bilinear map. -/ def _root_.ContinuousLinearMap.compContinuousAlternatingMapₗ : (N →L[R] N') →ₗ[R] (M [⋀^ι]→L[R] N) →ₗ[R] (M [⋀^ι]→L[R] N') := - LinearMap.mk₂ R ContinuousLinearMap.compContinuousAlternatingMap (fun f₁ f₂ g => rfl) - (fun c f g => rfl) (fun f g₁ g₂ => by ext1; apply f.map_add) fun c f g => by ext1; simp + LinearMap.mk₂ R ContinuousLinearMap.compContinuousAlternatingMap (fun _ _ _ => rfl) + (fun _ _ _ => rfl) (fun f g₁ g₂ => by ext1; apply f.map_add) fun c f g => by ext1; simp end Semiring @@ -603,7 +601,7 @@ namespace ContinuousMultilinearMap variable {R M N ι : Type*} [Semiring R] [AddCommMonoid M] [Module R M] [TopologicalSpace M] [AddCommGroup N] [Module R N] [TopologicalSpace N] [TopologicalAddGroup N] [Fintype ι] - [DecidableEq ι] (f g : ContinuousMultilinearMap R (fun _ : ι => M) N) + [DecidableEq ι] (f : ContinuousMultilinearMap R (fun _ : ι => M) N) /-- Alternatization of a continuous multilinear map. -/ @[simps (config := .lemmasOnly) apply_toContinuousMultilinearMap] diff --git a/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean b/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean index 9f613d081db1f..0ec905dcba11e 100644 --- a/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean +++ b/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean @@ -36,7 +36,7 @@ lemma isClosed_range_toContinuousMultilinearMap [ContinuousSMul 𝕜 E] [T2Space ContinuousMultilinearMap 𝕜 (fun _ : ι ↦ E) F)) := by simp only [range_toContinuousMultilinearMap, setOf_forall] repeat refine isClosed_iInter fun _ ↦ ?_ - exact isClosed_singleton.preimage (ContinuousMultilinearMap.continuous_eval_const _) + exact isClosed_singleton.preimage (continuous_eval_const _) end IsClosedRange @@ -77,16 +77,31 @@ instance instUniformContinuousConstSMul {M : Type*} UniformContinuousConstSMul M (E [⋀^ι]→L[𝕜] F) := isUniformEmbedding_toContinuousMultilinearMap.uniformContinuousConstSMul fun _ _ ↦ rfl +theorem isUniformInducing_postcomp {G : Type*} [AddCommGroup G] [UniformSpace G] [UniformAddGroup G] + [Module 𝕜 G] (g : F →L[𝕜] G) (hg : IsUniformInducing g) : + IsUniformInducing (g.compContinuousAlternatingMap : (E [⋀^ι]→L[𝕜] F) → (E [⋀^ι]→L[𝕜] G)) := by + rw [← isUniformEmbedding_toContinuousMultilinearMap.1.of_comp_iff] + exact (ContinuousMultilinearMap.isUniformInducing_postcomp g hg).comp + isUniformEmbedding_toContinuousMultilinearMap.1 + section CompleteSpace -variable [ContinuousSMul 𝕜 E] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] [T2Space F] +variable [ContinuousSMul 𝕜 E] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] open UniformOnFun in theorem completeSpace (h : RestrictGenTopology {s : Set (ι → E) | IsVonNBounded 𝕜 s}) : CompleteSpace (E [⋀^ι]→L[𝕜] F) := by + wlog hF : T2Space F generalizing F + · rw [(isUniformInducing_postcomp (SeparationQuotient.mkCLM _ _) + SeparationQuotient.isUniformInducing_mk).completeSpace_congr] + · exact this inferInstance + · intro f + use (SeparationQuotient.outCLM _ _).compContinuousAlternatingMap f + ext + simp have := ContinuousMultilinearMap.completeSpace (F := F) h rw [completeSpace_iff_isComplete_range - isUniformEmbedding_toContinuousMultilinearMap.toUniformInducing] + isUniformEmbedding_toContinuousMultilinearMap.isUniformInducing] apply isClosed_range_toContinuousMultilinearMap.isComplete instance instCompleteSpace [TopologicalAddGroup E] [SequentialSpace (ι → E)] : @@ -119,24 +134,31 @@ end UniformAddGroup variable [TopologicalSpace F] [TopologicalAddGroup F] -lemma embedding_toContinuousMultilinearMap : - Embedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F → _)) := +lemma isEmbedding_toContinuousMultilinearMap : + IsEmbedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F → _)) := letI := TopologicalAddGroup.toUniformSpace F haveI := comm_topologicalAddGroup_is_uniform (G := F) - isUniformEmbedding_toContinuousMultilinearMap.embedding + isUniformEmbedding_toContinuousMultilinearMap.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_toContinuousMultilinearMap := isEmbedding_toContinuousMultilinearMap + +instance instTopologicalAddGroup : TopologicalAddGroup (E [⋀^ι]→L[𝕜] F) := + isEmbedding_toContinuousMultilinearMap.topologicalAddGroup + (toContinuousMultilinearMapLinear (R := ℕ)) @[continuity, fun_prop] lemma continuous_toContinuousMultilinearMap : Continuous (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F → _)) := - embedding_toContinuousMultilinearMap.continuous + isEmbedding_toContinuousMultilinearMap.continuous instance instContinuousConstSMul {M : Type*} [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜 M F] [ContinuousConstSMul M F] : ContinuousConstSMul M (E [⋀^ι]→L[𝕜] F) := - embedding_toContinuousMultilinearMap.continuousConstSMul id rfl + isEmbedding_toContinuousMultilinearMap.continuousConstSMul id rfl instance instContinuousSMul [ContinuousSMul 𝕜 F] : ContinuousSMul 𝕜 (E [⋀^ι]→L[𝕜] F) := - embedding_toContinuousMultilinearMap.continuousSMul continuous_id rfl + isEmbedding_toContinuousMultilinearMap.continuousSMul continuous_id rfl theorem hasBasis_nhds_zero_of_basis {ι' : Type*} {p : ι' → Prop} {b : ι' → Set F} (h : (𝓝 (0 : F)).HasBasis p b) : @@ -154,26 +176,27 @@ theorem hasBasis_nhds_zero : variable [ContinuousSMul 𝕜 E] -lemma closedEmbedding_toContinuousMultilinearMap [T2Space F] : - ClosedEmbedding (toContinuousMultilinearMap : +lemma isClosedEmbedding_toContinuousMultilinearMap [T2Space F] : + IsClosedEmbedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F) → ContinuousMultilinearMap 𝕜 (fun _ : ι ↦ E) F) := - ⟨embedding_toContinuousMultilinearMap, isClosed_range_toContinuousMultilinearMap⟩ + ⟨isEmbedding_toContinuousMultilinearMap, isClosed_range_toContinuousMultilinearMap⟩ -@[continuity, fun_prop] -theorem continuous_eval_const (x : ι → E) : - Continuous fun p : E [⋀^ι]→L[𝕜] F ↦ p x := - (ContinuousMultilinearMap.continuous_eval_const x).comp continuous_toContinuousMultilinearMap +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_toContinuousMultilinearMap := isClosedEmbedding_toContinuousMultilinearMap -theorem continuous_coe_fun : - Continuous (DFunLike.coe : E [⋀^ι]→L[𝕜] F → (ι → E) → F) := - continuous_pi continuous_eval_const +instance instContinuousEvalConst : ContinuousEvalConst (E [⋀^ι]→L[𝕜] F) (ι → E) F := + .of_continuous_forget continuous_toContinuousMultilinearMap + +@[deprecated (since := "2024-10-05")] +protected alias continuous_eval_const := continuous_eval_const + +@[deprecated (since := "2024-10-05")] +protected alias continuous_coe_fun := continuous_coeFun instance instT2Space [T2Space F] : T2Space (E [⋀^ι]→L[𝕜] F) := - .of_injective_continuous DFunLike.coe_injective continuous_coe_fun + .of_injective_continuous DFunLike.coe_injective continuous_coeFun -instance instT3Space [T2Space F] : T2Space (E [⋀^ι]→L[𝕜] F) := - letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F - haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform +instance instT3Space [T2Space F] : T3Space (E [⋀^ι]→L[𝕜] F) := inferInstance section RestrictScalars @@ -181,16 +204,19 @@ section RestrictScalars variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] [Module 𝕜' E] [IsScalarTower 𝕜' 𝕜 E] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] -theorem embedding_restrictScalars : - Embedding (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := +theorem isEmbedding_restrictScalars : + IsEmbedding (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - (isUniformEmbedding_restrictScalars _).embedding + (isUniformEmbedding_restrictScalars _).isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_restrictScalars := isEmbedding_restrictScalars @[continuity, fun_prop] theorem continuous_restrictScalars : Continuous (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := - embedding_restrictScalars.continuous + isEmbedding_restrictScalars.continuous variable (𝕜') in /-- `ContinuousMultilinearMap.restrictScalars` as a `ContinuousLinearMap`. -/ diff --git a/Mathlib/Topology/Algebra/Module/Basic.lean b/Mathlib/Topology/Algebra/Module/Basic.lean index db5489036d28f..bfc61f20f238b 100644 --- a/Mathlib/Topology/Algebra/Module/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Basic.lean @@ -4,15 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Frédéric Dupuis, Heather Macbeth -/ +import Mathlib.Algebra.Module.Opposite +import Mathlib.LinearAlgebra.Finsupp +import Mathlib.LinearAlgebra.Projection import Mathlib.Topology.Algebra.Ring.Basic -import Mathlib.Topology.Algebra.MulAction -import Mathlib.Topology.Algebra.UniformGroup -import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.UniformSpace.UniformEmbedding -import Mathlib.Algebra.Algebra.Defs -import Mathlib.LinearAlgebra.Projection -import Mathlib.LinearAlgebra.Pi -import Mathlib.LinearAlgebra.Finsupp +import Mathlib.Topology.Algebra.Group.Quotient +import Mathlib.Topology.Algebra.UniformGroup.Defs /-! # Theory of topological modules and continuous linear maps. @@ -102,7 +100,7 @@ variable {ι R M₁ M₂ : Type*} [Semiring R] [AddCommMonoid M₁] [AddCommMono theorem continuousSMul_induced : @ContinuousSMul R M₁ _ u (t.induced f) := let _ : TopologicalSpace M₁ := t.induced f - Inducing.continuousSMul ⟨rfl⟩ continuous_id (map_smul f _ _) + IsInducing.continuousSMul ⟨rfl⟩ continuous_id (map_smul f _ _) end LatticeOps @@ -131,9 +129,8 @@ end Submodule section closure -variable {R R' : Type u} {M M' : Type v} [Semiring R] [Ring R'] - [TopologicalSpace M] [AddCommMonoid M] [TopologicalSpace M'] [AddCommGroup M'] [Module R M] - [ContinuousConstSMul R M] [Module R' M'] [ContinuousConstSMul R' M'] +variable {R : Type u} {M : Type v} [Semiring R] [TopologicalSpace M] [AddCommMonoid M] [Module R M] + [ContinuousConstSMul R M] theorem Submodule.mapsTo_smul_closure (s : Submodule R M) (c : R) : Set.MapsTo (c • ·) (closure s : Set M) (closure s) := @@ -246,10 +243,6 @@ class ContinuousSemilinearMapClass (F : Type*) {R S : outParam Type*} [Semiring [Module S M₂] [FunLike F M M₂] extends SemilinearMapClass F σ M M₂, ContinuousMapClass F M M₂ : Prop --- `σ`, `R` and `S` become metavariables, but they are all outparams so it's OK --- Porting note(#12094): removed nolint; dangerous_instance linter not ported yet --- attribute [nolint dangerous_instance] ContinuousSemilinearMapClass.toContinuousMapClass - /-- `ContinuousLinearMapClass F R M M₂` asserts `F` is a type of bundled continuous `R`-linear maps `M → M₂`. This is an abbreviation for `ContinuousSemilinearMapClass F (RingHom.id R) M M₂`. -/ @@ -383,11 +376,6 @@ instance continuousSemilinearMapClass : map_continuous f := f.2 map_smulₛₗ f := f.toLinearMap.map_smul' --- see Note [function coercion] -/-- Coerce continuous linear maps to functions. -/ ---instance toFun' : CoeFun (M₁ →SL[σ₁₂] M₂) fun _ => M₁ → M₂ := ⟨DFunLike.coe⟩ - --- porting note (#10618): was `simp`, now `simp only` proves it theorem coe_mk (f : M₁ →ₛₗ[σ₁₂] M₂) (h) : (mk f h : M₁ →ₛₗ[σ₁₂] M₂) = f := rfl @@ -439,6 +427,16 @@ theorem coe_copy (f : M₁ →SL[σ₁₂] M₂) (f' : M₁ → M₂) (h : f' = theorem copy_eq (f : M₁ →SL[σ₁₂] M₂) (f' : M₁ → M₂) (h : f' = ⇑f) : f.copy f' h = f := DFunLike.ext' h +theorem range_coeFn_eq : + Set.range ((⇑) : (M₁ →SL[σ₁₂] M₂) → (M₁ → M₂)) = + {f | Continuous f} ∩ Set.range ((⇑) : (M₁ →ₛₗ[σ₁₂] M₂) → (M₁ → M₂)) := by + ext f + constructor + · rintro ⟨f, rfl⟩ + exact ⟨f.continuous, f, rfl⟩ + · rintro ⟨hfc, f, rfl⟩ + exact ⟨⟨f, hfc⟩, rfl⟩ + -- make some straightforward lemmas available to `simp`. protected theorem map_zero (f : M₁ →SL[σ₁₂] M₂) : f (0 : M₁) = 0 := map_zero f @@ -446,11 +444,10 @@ protected theorem map_zero (f : M₁ →SL[σ₁₂] M₂) : f (0 : M₁) = 0 := protected theorem map_add (f : M₁ →SL[σ₁₂] M₂) (x y : M₁) : f (x + y) = f x + f y := map_add f x y --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] protected theorem map_smulₛₗ (f : M₁ →SL[σ₁₂] M₂) (c : R₁) (x : M₁) : f (c • x) = σ₁₂ c • f x := (toLinearMap _).map_smulₛₗ _ _ --- @[simp] -- Porting note (#10618): simp can prove this protected theorem map_smul [Module R₁ M₂] (f : M₁ →L[R₁] M₂) (c : R₁) (x : M₁) : f (c • x) = c • f x := by simp only [RingHom.id_apply, ContinuousLinearMap.map_smulₛₗ] @@ -460,11 +457,6 @@ theorem map_smul_of_tower {R S : Type*} [Semiring S] [SMul R M₁] [Module S M f (c • x) = c • f x := LinearMap.CompatibleSMul.map_smul (f : M₁ →ₗ[S] M₂) c x -@[deprecated _root_.map_sum (since := "2023-09-16")] -protected theorem map_sum {ι : Type*} (f : M₁ →SL[σ₁₂] M₂) (s : Finset ι) (g : ι → M₁) : - f (∑ i ∈ s, g i) = ∑ i ∈ s, f (g i) := - map_sum .. - @[simp, norm_cast] theorem coe_coe (f : M₁ →SL[σ₁₂] M₂) : ⇑(f : M₁ →ₛₗ[σ₁₂] M₂) = f := rfl @@ -1139,7 +1131,7 @@ theorem pi_apply (f : ∀ i, M →L[R] φ i) (c : M) (i : ι) : pi f c i = f i c rfl theorem pi_eq_zero (f : ∀ i, M →L[R] φ i) : pi f = 0 ↔ ∀ i, f i = 0 := by - simp only [ContinuousLinearMap.ext_iff, pi_apply, Function.funext_iff] + simp only [ContinuousLinearMap.ext_iff, pi_apply, funext_iff] exact forall_swap theorem pi_zero : pi (fun _ => 0 : ∀ i, M →L[R] φ i) = 0 := @@ -1191,11 +1183,7 @@ def iInfKerProjEquiv {I J : Set ι} [DecidablePred fun i => i ∈ I] (hd : Disjo continuous_invFun := Continuous.subtype_mk (continuous_pi fun i => by - -- Porting note: Was `dsimp`. - change - Continuous (⇑(if h : i ∈ I then LinearMap.proj (R := R) (ι := ↥I) - (φ := fun i : ↥I => φ i) ⟨i, h⟩ else - (0 : ((i : I) → φ i) →ₗ[R] φ i))) + dsimp split_ifs <;> [apply continuous_apply; exact continuous_zero]) _ @@ -1431,7 +1419,7 @@ variable {R R₂ R₃ S S₃ : Type*} [Semiring R] [Semiring R₂] [Semiring R [SMulCommClass R₃ S₃ M₃] [ContinuousConstSMul S₃ M₃] [Module S N₂] [ContinuousConstSMul S N₂] [SMulCommClass R S N₂] [Module S N₃] [SMulCommClass R S N₃] [ContinuousConstSMul S N₃] {σ₁₂ : R →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R →+* R₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] (c : S) - (h : M₂ →SL[σ₂₃] M₃) (f g : M →SL[σ₁₂] M₂) (x y z : M) + (h : M₂ →SL[σ₂₃] M₃) (f : M →SL[σ₁₂] M₂) /-- `ContinuousLinearMap.prod` as an `Equiv`. -/ @[simps apply] @@ -1518,7 +1506,7 @@ section CommRing variable {R : Type*} [CommRing R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] {M₂ : Type*} [TopologicalSpace M₂] [AddCommGroup M₂] {M₃ : Type*} [TopologicalSpace M₃] [AddCommGroup M₃] - [Module R M] [Module R M₂] [Module R M₃] [ContinuousConstSMul R M₃] + [Module R M] [Module R M₂] [Module R M₃] variable [TopologicalAddGroup M₂] [ContinuousConstSMul R M₂] @@ -1609,10 +1597,10 @@ variable {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} [Semiring R₁] [Semiring {σ₂₃ : R₂ →+* R₃} {σ₃₂ : R₃ →+* R₂} [RingHomInvPair σ₂₃ σ₃₂] [RingHomInvPair σ₃₂ σ₂₃] {σ₁₃ : R₁ →+* R₃} {σ₃₁ : R₃ →+* R₁} [RingHomInvPair σ₁₃ σ₃₁] [RingHomInvPair σ₃₁ σ₁₃] [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] [RingHomCompTriple σ₃₂ σ₂₁ σ₃₁] {M₁ : Type*} - [TopologicalSpace M₁] [AddCommMonoid M₁] {M'₁ : Type*} [TopologicalSpace M'₁] [AddCommMonoid M'₁] + [TopologicalSpace M₁] [AddCommMonoid M₁] {M₂ : Type*} [TopologicalSpace M₂] [AddCommMonoid M₂] {M₃ : Type*} [TopologicalSpace M₃] [AddCommMonoid M₃] {M₄ : Type*} [TopologicalSpace M₄] [AddCommMonoid M₄] [Module R₁ M₁] - [Module R₁ M'₁] [Module R₂ M₂] [Module R₃ M₃] + [Module R₂ M₂] [Module R₃ M₃] /-- A continuous linear equivalence induces a continuous linear map. -/ @[coe] @@ -1643,11 +1631,6 @@ instance continuousSemilinearEquivClass : map_continuous := continuous_toFun inv_continuous := continuous_invFun --- see Note [function coercion] --- /-- Coerce continuous linear equivs to maps. -/ --- instance : CoeFun (M₁ ≃SL[σ₁₂] M₂) fun _ => M₁ → M₂ := --- ⟨fun f => f⟩ - theorem coe_apply (e : M₁ ≃SL[σ₁₂] M₂) (b : M₁) : (e : M₁ →SL[σ₁₂] M₂) b = e b := rfl @@ -1700,23 +1683,19 @@ theorem map_nhds_eq (e : M₁ ≃SL[σ₁₂] M₂) (x : M₁) : map e (𝓝 x) e.toHomeomorph.map_nhds_eq x -- Make some straightforward lemmas available to `simp`. --- @[simp] -- Porting note (#10618): simp can prove this theorem map_zero (e : M₁ ≃SL[σ₁₂] M₂) : e (0 : M₁) = 0 := (e : M₁ →SL[σ₁₂] M₂).map_zero --- @[simp] -- Porting note (#10618): simp can prove this theorem map_add (e : M₁ ≃SL[σ₁₂] M₂) (x y : M₁) : e (x + y) = e x + e y := (e : M₁ →SL[σ₁₂] M₂).map_add x y --- @[simp] -- Porting note (#10618): simp can prove this +@[simp] theorem map_smulₛₗ (e : M₁ ≃SL[σ₁₂] M₂) (c : R₁) (x : M₁) : e (c • x) = σ₁₂ c • e x := (e : M₁ →SL[σ₁₂] M₂).map_smulₛₗ c x --- @[simp] -- Porting note (#10618): simp can prove this theorem map_smul [Module R₁ M₂] (e : M₁ ≃L[R₁] M₂) (c : R₁) (x : M₁) : e (c • x) = c • e x := (e : M₁ →L[R₁] M₂).map_smul c x --- @[simp] -- Porting note (#10618): simp can prove this theorem map_eq_zero_iff (e : M₁ ≃SL[σ₁₂] M₂) {x : M₁} : e x = 0 ↔ x = 0 := e.toLinearEquiv.map_eq_zero_iff @@ -1760,6 +1739,10 @@ protected def refl : M₁ ≃L[R₁] M₁ := continuous_toFun := continuous_id continuous_invFun := continuous_id } +@[simp] +theorem refl_apply (x : M₁) : + ContinuousLinearEquiv.refl R₁ M₁ x = x := rfl + end @[simp, norm_cast] @@ -2030,6 +2013,31 @@ def arrowCongrEquiv (e₁₂ : M₁ ≃SL[σ₁₂] M₂) (e₄₃ : M₄ ≃SL[ ContinuousLinearMap.ext fun x => by simp only [ContinuousLinearMap.comp_apply, apply_symm_apply, coe_coe] +section piCongrRight + +variable {ι : Type*} {M : ι → Type*} [∀ i, TopologicalSpace (M i)] [∀ i, AddCommMonoid (M i)] + [∀ i, Module R₁ (M i)] {N : ι → Type*} [∀ i, TopologicalSpace (N i)] [∀ i, AddCommMonoid (N i)] + [∀ i, Module R₁ (N i)] (f : (i : ι) → M i ≃L[R₁] N i) + +/-- Combine a family of continuous linear equivalences into a continuous linear equivalence of +pi-types. -/ +def piCongrRight : ((i : ι) → M i) ≃L[R₁] (i : ι) → N i := + { LinearEquiv.piCongrRight fun i ↦ f i with + continuous_toFun := by + exact continuous_pi fun i ↦ (f i).continuous_toFun.comp (continuous_apply i) + continuous_invFun := by + exact continuous_pi fun i => (f i).continuous_invFun.comp (continuous_apply i) } + +@[simp] +theorem piCongrRight_apply (m : (i : ι) → M i) (i : ι) : + piCongrRight f m i = (f i) (m i) := rfl + +@[simp] +theorem piCongrRight_symm_apply (n : (i : ι) → N i) (i : ι) : + (piCongrRight f).symm n i = (f i).symm (n i) := rfl + +end piCongrRight + end AddCommMonoid section AddCommGroup @@ -2065,6 +2073,26 @@ theorem skewProd_symm_apply (e : M ≃L[R] M₂) (e' : M₃ ≃L[R] M₄) (f : M (e.skewProd e' f).symm x = (e.symm x.1, e'.symm (x.2 - f (e.symm x.1))) := rfl +variable (R) in +/-- The negation map as a continuous linear equivalence. -/ +def neg [ContinuousNeg M] : + M ≃L[R] M := + { LinearEquiv.neg R with + continuous_toFun := continuous_neg + continuous_invFun := continuous_neg } + +@[simp] +theorem coe_neg [ContinuousNeg M] : + (neg R : M → M) = -id := rfl + +@[simp] +theorem neg_apply [ContinuousNeg M] (x : M) : + neg R x = -x := by simp + +@[simp] +theorem symm_neg [ContinuousNeg M] : + (neg R : M ≃L[R] M).symm = neg R := rfl + end AddCommGroup section Ring @@ -2074,11 +2102,9 @@ variable {R : Type*} [Ring R] {R₂ : Type*} [Ring R₂] {M : Type*} [Topologica variable {σ₁₂ : R →+* R₂} {σ₂₁ : R₂ →+* R} [RingHomInvPair σ₁₂ σ₂₁] [RingHomInvPair σ₂₁ σ₁₂] --- @[simp] -- Porting note (#10618): simp can prove this theorem map_sub (e : M ≃SL[σ₁₂] M₂) (x y : M) : e (x - y) = e x - e y := (e : M →SL[σ₁₂] M₂).map_sub x y --- @[simp] -- Porting note (#10618): simp can prove this theorem map_neg (e : M ≃SL[σ₁₂] M₂) (x : M) : e (-x) = -e x := (e : M →SL[σ₁₂] M₂).map_neg x @@ -2320,7 +2346,6 @@ end ContinuousLinearMap namespace Submodule variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] - {M₂ : Type*} [TopologicalSpace M₂] [AddCommGroup M₂] [Module R M₂] open ContinuousLinearMap @@ -2398,10 +2423,22 @@ instance continuousSMul_quotient [TopologicalSpace R] [TopologicalAddGroup M] [C instance t3_quotient_of_isClosed [TopologicalAddGroup M] [IsClosed (S : Set M)] : T3Space (M ⧸ S) := letI : IsClosed (S.toAddSubgroup : Set M) := ‹_› - S.toAddSubgroup.t3_quotient_of_isClosed + QuotientAddGroup.instT3Space S.toAddSubgroup end Submodule end Quotient +namespace MulOpposite + +variable (R : Type*) [Semiring R] [τR : TopologicalSpace R] [TopologicalSemiring R] + {M : Type*} [AddCommMonoid M] [Module R M] [TopologicalSpace M] [ContinuousSMul R M] + +/-- The function `op` is a continuous linear equivalence. -/ +@[simps!] +def opContinuousLinearEquiv : M ≃L[R] Mᵐᵒᵖ where + __ := MulOpposite.opLinearEquiv R + +end MulOpposite + set_option linter.style.longFile 2500 diff --git a/Mathlib/Topology/Algebra/Module/Cardinality.lean b/Mathlib/Topology/Algebra/Module/Cardinality.lean index c45fb8205558f..845e4610d726e 100644 --- a/Mathlib/Topology/Algebra/Module/Cardinality.lean +++ b/Mathlib/Topology/Algebra/Module/Cardinality.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.Algebra.Module.Card -import Mathlib.SetTheory.Cardinal.CountableCover -import Mathlib.SetTheory.Cardinal.Continuum import Mathlib.Analysis.SpecificLimits.Normed +import Mathlib.SetTheory.Cardinal.Continuum +import Mathlib.SetTheory.Cardinal.CountableCover +import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.Topology.MetricSpace.Perfect /-! @@ -77,7 +78,7 @@ lemma cardinal_eq_of_mem_nhds_zero simp_rw [← inv_pow] apply tendsto_pow_atTop_nhds_zero_of_norm_lt_one rw [norm_inv] - exact inv_lt_one hc + exact inv_lt_one_of_one_lt₀ hc exact Tendsto.smul_const this x rw [zero_smul] at this filter_upwards [this hs] with n (hn : (c ^ n)⁻¹ • x ∈ s) diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 2cf817161d306..bdab9d7a3ba36 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -374,7 +374,6 @@ theorem toLinearEquiv_toContinuousLinearEquiv (e : E ≃ₗ[𝕜] F) : ext x rfl --- Porting note (#10618): @[simp] can prove this theorem toLinearEquiv_toContinuousLinearEquiv_symm (e : E ≃ₗ[𝕜] F) : e.toContinuousLinearEquiv.symm.toLinearEquiv = e.symm := by ext x @@ -518,24 +517,30 @@ theorem Submodule.closed_of_finiteDimensional s.complete_of_finiteDimensional.isClosed /-- An injective linear map with finite-dimensional domain is a closed embedding. -/ -theorem LinearMap.closedEmbedding_of_injective [T2Space E] [FiniteDimensional 𝕜 E] {f : E →ₗ[𝕜] F} - (hf : LinearMap.ker f = ⊥) : ClosedEmbedding f := +theorem LinearMap.isClosedEmbedding_of_injective [T2Space E] [FiniteDimensional 𝕜 E] {f : E →ₗ[𝕜] F} + (hf : LinearMap.ker f = ⊥) : IsClosedEmbedding f := let g := LinearEquiv.ofInjective f (LinearMap.ker_eq_bot.mp hf) - { embedding_subtype_val.comp g.toContinuousLinearEquiv.toHomeomorph.embedding with + { IsEmbedding.subtypeVal.comp g.toContinuousLinearEquiv.toHomeomorph.isEmbedding with isClosed_range := by haveI := f.finiteDimensional_range simpa [LinearMap.range_coe f] using f.range.closed_of_finiteDimensional } -theorem closedEmbedding_smul_left [T2Space E] {c : E} (hc : c ≠ 0) : - ClosedEmbedding fun x : 𝕜 => x • c := - LinearMap.closedEmbedding_of_injective (LinearMap.ker_toSpanSingleton 𝕜 E hc) +@[deprecated (since := "2024-10-20")] +alias LinearMap.closedEmbedding_of_injective := LinearMap.isClosedEmbedding_of_injective + +theorem isClosedEmbedding_smul_left [T2Space E] {c : E} (hc : c ≠ 0) : + IsClosedEmbedding fun x : 𝕜 => x • c := + LinearMap.isClosedEmbedding_of_injective (LinearMap.ker_toSpanSingleton 𝕜 E hc) + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_smul_left := isClosedEmbedding_smul_left -- `smul` is a closed map in the first argument. theorem isClosedMap_smul_left [T2Space E] (c : E) : IsClosedMap fun x : 𝕜 => x • c := by by_cases hc : c = 0 · simp_rw [hc, smul_zero] exact isClosedMap_const - · exact (closedEmbedding_smul_left hc).isClosedMap + · exact (isClosedEmbedding_smul_left hc).isClosedMap theorem ContinuousLinearMap.exists_right_inverse_of_surjective [FiniteDimensional 𝕜 F] (f : E →L[𝕜] F) (hf : LinearMap.range f = ⊤) : diff --git a/Mathlib/Topology/Algebra/Module/ModuleTopology.lean b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean new file mode 100644 index 0000000000000..c742c3c16e6a4 --- /dev/null +++ b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean @@ -0,0 +1,265 @@ +/- +Copyright (c) 2024 Kevin Buzzard. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kevin Buzzard, Will Sawin +-/ +import Mathlib.Topology.Algebra.Module.Basic + +/-! +# A "module topology" for modules over a topological ring + +If `R` is a topological ring acting on an additive abelian group `A`, we define the +*module topology* to be the finest topology on `A` making both the maps +`• : R × A → A` and `+ : A × A → A` continuous (with all the products having the +product topology). Note that `- : A → A` is also automatically continuous as it is `a ↦ (-1) • a`. + +This topology was suggested by Will Sawin [here](https://mathoverflow.net/a/477763/1384). + + +## Mathematical details + +I (buzzard) don't know of any reference for this other than Sawin's mathoverflow answer, +so I expand some of the details here. + +First note that the definition makes sense in far more generality (for example `R` just needs to +be a topological space acting on an additive monoid). + +Next note that there *is* a finest topology with this property! Indeed, topologies on a fixed +type form a complete lattice (infinite infs and sups exist). So if `τ` is the Inf of all +the topologies on `A` which make `+` and `•` continuous, then the claim is that `+` and `•` +are still continuous for `τ` (note that topologies are ordered so that finer topologies +are smaller). To show `+ : A × A → A` is continuous we equivalently need to show +that the pushforward of the product topology `τ × τ` along `+` is `≤ τ`, and because `τ` is +the greatest lower bound of the topologies making `•` and `+` continuous, +it suffices to show that it's `≤ σ` for any topology `σ` on `A` which makes `+` and `•` continuous. +However pushforward and products are monotone, so `τ × τ ≤ σ × σ`, and the pushforward of +`σ × σ` is `≤ σ` because that's precisely the statement that `+` is continuous for `σ`. +The proof for `•` follows mutatis mutandis. + +A *topological module* for a topological ring `R` is an `R`-module `A` with a topology +making `+` and `•` continuous. The discussion so far has shown that the module topology makes +an `R`-module `A` into a topological module, and moreover is the finest topology with this property. + +A crucial observation is that if `M` is a topological `R`-module, if `A` is an `R`-module with no +topology, and if `φ : A → M` is linear, then the pullback of `M`'s topology to `A` is a topology +making `A` into a topological module. Let's for example check that `•` is continuous. +If `U ⊆ A` is open then by definition of the pullback topology, `U = φ⁻¹(V)` for some open `V ⊆ M`, +and now the pullback of `U` under `•` is just the pullback along the continuous map +`id × φ : R × A → R × M` of the preimage of `V` under the continuous map `• : R × M → M`, +so it's open. The proof for `+` is similar. + +As a consequence of this, we see that if `φ : A → M` is a linear map between topological `R`-modules +modules and if `A` has the module topology, then `φ` is automatically continuous. +Indeed the argument above shows that if `A → M` is linear then the module +topology on `A` is `≤` the pullback of the module topology on `M` (because it's the inf of a set +containing this topology) which is the definition of continuity. + +We also deduce that the module topology is a functor from the category of `R`-modules +(`R` a topological ring) to the category of topological `R`-modules, and it is perhaps +unsurprising that this is an adjoint to the forgetful functor. Indeed, if `A` is an `R`-module +and `M` is a topological `R`-module, then the previous paragraph shows that +the linear maps `A → M` are precisely the continuous linear maps +from (`A` with its module topology) to `M`, so the module topology is a left adjoint +to the forgetful functor. + +This file develops the theory of the module topology. We prove that the module topology on +`R` as a module over itself is `R`'s original topology, and that the module topology +is isomorphism-invariant. + +## Main theorems + +* `TopologicalSemiring.toIsModuleTopology : IsModuleTopology R R`. The module + topology on `R` is `R`'s topology. +* `IsModuleTopology.iso [IsModuleTopology R A] (e : A ≃L[R] B) : IsModuleTopology R B`. If `A` and + `B` are `R`-modules with topologies, if `e` is a topological isomorphism between them, + and if `A` has the module topology, then `B` has the module topology. + +## TODO + +Forthcoming PRs from the FLT repo will show that the module topology on a (binary or finite) product +of modules is the product of the module topologies, and that the module topology on the quotient +of a module `M` is the quotient topology when `M` is equipped with the module topology. + +We will also show the slightly more subtle result that if `M`, `N` and `P` are `R`-modules +equipped with the module topology and if furthermore `M` is finite as an `R`-module, +then any bilinear map `M × N → P` is continuous. + +As a consequence of this, we deduce that if `R` is a commutative topological ring +and `A` is an `R`-algebra of finite type as `R`-module, then `A` with its module +topology becomes a topological ring (i.e., multiplication is continuous). + +Other TODOs (not done in the FLT repo): + +* The module topology is a functor from the category of `R`-modules + to the category of topological `R`-modules, and it's an adjoint to the forgetful functor. + +-/ + +section basics + +/- +This section is just boilerplate, defining the module topology and making +some infrastructure. Note that we don't even need that `R` is a ring +in the main definitions, just that it acts on `A`. +-/ +variable (R : Type*) [TopologicalSpace R] (A : Type*) [Add A] [SMul R A] + +/-- The module topology, for a module `A` over a topological ring `R`. It's the finest topology +making addition and the `R`-action continuous, or equivalently the finest topology making `A` +into a topological `R`-module. More precisely it's the Inf of the set of +topologies with these properties; theorems `continuousSMul` and `continuousAdd` show +that the module topology also has these properties. -/ +abbrev moduleTopology : TopologicalSpace A := + sInf {t | @ContinuousSMul R A _ _ t ∧ @ContinuousAdd A t _} + +/-- A class asserting that the topology on a module over a topological ring `R` is +the module topology. See `moduleTopology` for more discussion of the module topology. -/ +class IsModuleTopology [τA : TopologicalSpace A] : Prop where + /-- Note that this should not be used directly, and `eq_moduleTopology`, which takes `R` and `A` + explicitly, should be used instead. -/ + eq_moduleTopology' : τA = moduleTopology R A + +theorem eq_moduleTopology [τA : TopologicalSpace A] [IsModuleTopology R A] : + τA = moduleTopology R A := + IsModuleTopology.eq_moduleTopology' (R := R) (A := A) + +/-- Scalar multiplication `• : R × A → A` is continuous if `R` is a topological +ring, and `A` is an `R` module with the module topology. -/ +theorem ModuleTopology.continuousSMul : @ContinuousSMul R A _ _ (moduleTopology R A) := + /- Proof: We need to prove that the product topology is finer than the pullback + of the module topology. But the module topology is an Inf and thus a limit, + and pullback is a right adjoint, so it preserves limits. + We must thus show that the product topology is finer than an Inf, so it suffices + to show it's a lower bound, which is not hard. All this is wrapped into + `continuousSMul_sInf`. + -/ + continuousSMul_sInf fun _ h ↦ h.1 + +/-- Addition `+ : A × A → A` is continuous if `R` is a topological +ring, and `A` is an `R` module with the module topology. -/ +theorem ModuleTopology.continuousAdd : @ContinuousAdd A (moduleTopology R A) _ := + continuousAdd_sInf fun _ h ↦ h.2 + +instance IsModuleTopology.toContinuousSMul [TopologicalSpace A] [IsModuleTopology R A] : + ContinuousSMul R A := eq_moduleTopology R A ▸ ModuleTopology.continuousSMul R A + +-- this can't be an instance because typclass inference can't be expected to find `R`. +theorem IsModuleTopology.toContinuousAdd [TopologicalSpace A] [IsModuleTopology R A] : + ContinuousAdd A := eq_moduleTopology R A ▸ ModuleTopology.continuousAdd R A + +/-- The module topology is `≤` any topology making `A` into a topological module. -/ +theorem moduleTopology_le [τA : TopologicalSpace A] [ContinuousSMul R A] [ContinuousAdd A] : + moduleTopology R A ≤ τA := sInf_le ⟨inferInstance, inferInstance⟩ + +end basics + +namespace IsModuleTopology + +section basics + +variable {R : Type*} [TopologicalSpace R] + {A : Type*} [Add A] [SMul R A] [τA : TopologicalSpace A] + +/-- If `A` is a topological `R`-module and the identity map from (`A` with its given +topology) to (`A` with the module topology) is continuous, then the topology on `A` is +the module topology. -/ +theorem of_continuous_id [ContinuousAdd A] [ContinuousSMul R A] + (h : @Continuous A A τA (moduleTopology R A) id): + IsModuleTopology R A where + -- The topologies are equal because each is finer than the other. One inclusion + -- follows from the continuity hypothesis; the other is because the module topology + -- is the inf of all the topologies making `A` a topological module. + eq_moduleTopology' := le_antisymm (continuous_id_iff_le.1 h) (moduleTopology_le _ _) + +/-- The zero module has the module topology. -/ +instance instSubsingleton [Subsingleton A] : IsModuleTopology R A where + eq_moduleTopology' := Subsingleton.elim _ _ + +end basics + +section iso + +variable {R : Type*} [τR : TopologicalSpace R] [Semiring R] +variable {A : Type*} [AddCommMonoid A] [Module R A] [τA : TopologicalSpace A] [IsModuleTopology R A] +variable {B : Type*} [AddCommMonoid B] [Module R B] [τB : TopologicalSpace B] + +/-- If `A` and `B` are `R`-modules, homeomorphic via an `R`-linear homeomorphism, and if +`A` has the module topology, then so does `B`. -/ +theorem iso (e : A ≃L[R] B) : IsModuleTopology R B where + eq_moduleTopology' := by + -- get these in before I start putting new topologies on A and B and have to use `@` + let g : A →ₗ[R] B := e + let g' : B →ₗ[R] A := e.symm + let h : A →+ B := e + let h' : B →+ A := e.symm + simp_rw [e.toHomeomorph.symm.isInducing.1, eq_moduleTopology R A, moduleTopology, induced_sInf] + apply congr_arg + ext τ -- from this point on the definitions of `g`, `g'` etc above don't work without `@`. + rw [Set.mem_image] + constructor + · rintro ⟨σ, ⟨hσ1, hσ2⟩, rfl⟩ + exact ⟨continuousSMul_induced g', continuousAdd_induced h'⟩ + · rintro ⟨h1, h2⟩ + use τ.induced e + rw [induced_compose] + refine ⟨⟨continuousSMul_induced g, continuousAdd_induced h⟩, ?_⟩ + nth_rw 2 [← induced_id (t := τ)] + simp + +end iso + +section self + +variable (R : Type*) [Semiring R] [τR : TopologicalSpace R] [TopologicalSemiring R] + +/-! +We now fix once and for all a topological semiring `R`. + +We first prove that the module topology on `R` considered as a module over itself, +is `R`'s topology. +-/ + +/-- The topology on a topological semiring `R` agrees with the module topology when considering +`R` as an `R`-module in the obvious way (i.e., via `Semiring.toModule`). -/ +instance _root_.TopologicalSemiring.toIsModuleTopology : IsModuleTopology R R := by + /- By a previous lemma it suffices to show that the identity from (R,usual) to + (R, module topology) is continuous. -/ + apply of_continuous_id + /- + The idea needed here is to rewrite the identity function as the composite of `r ↦ (r,1)` + from `R` to `R × R`, and multiplication `R × R → R`. + -/ + rw [show (id : R → R) = (fun rs ↦ rs.1 • rs.2) ∘ (fun r ↦ (r, 1)) by ext; simp] + /- + It thus suffices to show that each of these maps are continuous. For this claim to even make + sense, we need to topologise `R × R`. The trick is to do this by giving the first `R` the usual + topology `τR` and the second `R` the module topology. To do this we have to "fight mathlib" + a bit with `@`, because there is more than one topology on `R` here. + -/ + apply @Continuous.comp R (R × R) R τR (@instTopologicalSpaceProd R R τR (moduleTopology R R)) + (moduleTopology R R) + · /- + The map R × R → R is `•`, so by a fundamental property of the module topology, + this is continuous. -/ + exact @continuous_smul _ _ _ _ (moduleTopology R R) <| ModuleTopology.continuousSMul .. + · /- + The map `R → R × R` sending `r` to `(r,1)` is a map into a product, so it suffices to show + that each of the two factors is continuous. But the first is the identity function + on `(R, usual topology)` and the second is a constant function. -/ + exact @Continuous.prod_mk _ _ _ _ (moduleTopology R R) _ _ _ continuous_id <| + @continuous_const _ _ _ (moduleTopology R R) _ + +end self + +section MulOpposite + +variable (R : Type*) [Semiring R] [τR : TopologicalSpace R] [TopologicalSemiring R] + +/-- The module topology coming from the action of the topological ring `Rᵐᵒᵖ` on `R` + (via `Semiring.toOppositeModule`, i.e. via `(op r) • m = m * r`) is `R`'s topology. -/ +instance _root_.TopologicalSemiring.toOppositeIsModuleTopology : IsModuleTopology Rᵐᵒᵖ R := + .iso (MulOpposite.opContinuousLinearEquiv Rᵐᵒᵖ).symm + +end MulOpposite + +end IsModuleTopology diff --git a/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean index ad413d2ba21ae..1a0a5179e3380 100644 --- a/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean @@ -78,9 +78,6 @@ instance continuousMapClass : ContinuousMapClass (ContinuousMultilinearMap R M₁ M₂) (∀ i, M₁ i) M₂ where map_continuous := ContinuousMultilinearMap.cont -instance : CoeFun (ContinuousMultilinearMap R M₁ M₂) fun _ => (∀ i, M₁ i) → M₂ := - ⟨fun f => f⟩ - /-- See Note [custom simps projection]. We need to specify this projection explicitly in this case, because it is a composition of multiple projections. -/ def Simps.apply (L₁ : ContinuousMultilinearMap R M₁ M₂) (v : ∀ i, M₁ i) : M₂ := diff --git a/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean index c73eb8c4be001..b0140825f8817 100644 --- a/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean +++ b/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean @@ -5,6 +5,8 @@ Authors: Yury Kudryashov -/ import Mathlib.Topology.Algebra.Module.Multilinear.Bounded import Mathlib.Topology.Algebra.Module.UniformConvergence +import Mathlib.Topology.Algebra.SeparationQuotient.Section +import Mathlib.Topology.Hom.ContinuousEvalConst /-! # Topology on continuous multilinear maps @@ -65,16 +67,24 @@ section UniformAddGroup variable [UniformSpace F] [UniformAddGroup F] +lemma isUniformInducing_toUniformOnFun : + IsUniformInducing (toUniformOnFun : + ContinuousMultilinearMap 𝕜 E F → ((Π i, E i) →ᵤ[{s | IsVonNBounded 𝕜 s}] F)) := ⟨rfl⟩ + lemma isUniformEmbedding_toUniformOnFun : - IsUniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) where - inj := DFunLike.coe_injective - comap_uniformity := rfl + IsUniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) := + ⟨isUniformInducing_toUniformOnFun, DFunLike.coe_injective⟩ @[deprecated (since := "2024-10-01")] alias uniformEmbedding_toUniformOnFun := isUniformEmbedding_toUniformOnFun -lemma embedding_toUniformOnFun : Embedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) := - isUniformEmbedding_toUniformOnFun.embedding +lemma isEmbedding_toUniformOnFun : + IsEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → + ((Π i, E i) →ᵤ[{s | IsVonNBounded 𝕜 s}] F)) := + isUniformEmbedding_toUniformOnFun.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_toUniformOnFun := isEmbedding_toUniformOnFun theorem uniformContinuous_coe_fun [∀ i, ContinuousSMul 𝕜 (E i)] : UniformContinuous (DFunLike.coe : ContinuousMultilinearMap 𝕜 E F → (Π i, E i) → F) := @@ -96,19 +106,33 @@ instance instUniformContinuousConstSMul {M : Type*} haveI := uniformContinuousConstSMul_of_continuousConstSMul M F isUniformEmbedding_toUniformOnFun.uniformContinuousConstSMul fun _ _ ↦ rfl +theorem isUniformInducing_postcomp + {G : Type*} [AddCommGroup G] [UniformSpace G] [UniformAddGroup G] [Module 𝕜 G] + (g : F →L[𝕜] G) (hg : IsUniformInducing g) : + IsUniformInducing (g.compContinuousMultilinearMap : + ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜 E G) := by + rw [← isUniformInducing_toUniformOnFun.of_comp_iff] + exact (UniformOnFun.postcomp_isUniformInducing hg).comp isUniformInducing_toUniformOnFun + section CompleteSpace -variable [∀ i, ContinuousSMul 𝕜 (E i)] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] [T2Space F] +variable [∀ i, ContinuousSMul 𝕜 (E i)] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] open UniformOnFun in theorem completeSpace (h : RestrictGenTopology {s : Set (Π i, E i) | IsVonNBounded 𝕜 s}) : CompleteSpace (ContinuousMultilinearMap 𝕜 E F) := by classical + wlog hF : T2Space F generalizing F + · rw [(isUniformInducing_postcomp (SeparationQuotient.mkCLM _ _) + SeparationQuotient.isUniformInducing_mk).completeSpace_congr] + · exact this inferInstance + · intro f + use (SeparationQuotient.outCLM _ _).compContinuousMultilinearMap f + simp [DFunLike.ext_iff] have H : ∀ {m : Π i, E i}, Continuous fun f : (Π i, E i) →ᵤ[{s | IsVonNBounded 𝕜 s}] F ↦ toFun _ f m := (uniformContinuous_eval (isVonNBounded_covers) _).continuous - rw [completeSpace_iff_isComplete_range isUniformEmbedding_toUniformOnFun.toUniformInducing, - range_toUniformOnFun] + rw [completeSpace_iff_isComplete_range isUniformInducing_toUniformOnFun, range_toUniformOnFun] simp only [setOf_and, setOf_forall] apply_rules [IsClosed.isComplete, IsClosed.inter] · exact UniformOnFun.isClosed_setOf_continuous h @@ -152,6 +176,11 @@ end UniformAddGroup variable [TopologicalSpace F] [TopologicalAddGroup F] +instance instTopologicalAddGroup : TopologicalAddGroup (ContinuousMultilinearMap 𝕜 E F) := + letI := TopologicalAddGroup.toUniformSpace F + haveI := comm_topologicalAddGroup_is_uniform (G := F) + inferInstance + instance instContinuousConstSMul {M : Type*} [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜 M F] [ContinuousConstSMul M F] : ContinuousConstSMul M (ContinuousMultilinearMap 𝕜 E F) := by @@ -166,7 +195,7 @@ instance instContinuousSMul [ContinuousSMul 𝕜 F] : let φ : ContinuousMultilinearMap 𝕜 E F →ₗ[𝕜] (Π i, E i) → F := { toFun := (↑), map_add' := fun _ _ ↦ rfl, map_smul' := fun _ _ ↦ rfl } UniformOnFun.continuousSMul_induced_of_image_bounded _ _ _ _ φ - embedding_toUniformOnFun.toInducing fun _ _ hu ↦ hu.image_multilinear _ + isEmbedding_toUniformOnFun.isInducing fun _ _ hu ↦ hu.image_multilinear _ theorem hasBasis_nhds_zero_of_basis {ι : Type*} {p : ι → Prop} {b : ι → Set F} (h : (𝓝 (0 : F)).HasBasis p b) : @@ -188,38 +217,42 @@ theorem hasBasis_nhds_zero : variable [∀ i, ContinuousSMul 𝕜 (E i)] -theorem continuous_eval_const (x : Π i, E i) : - Continuous fun p : ContinuousMultilinearMap 𝕜 E F ↦ p x := by - letI := TopologicalAddGroup.toUniformSpace F - haveI := comm_topologicalAddGroup_is_uniform (G := F) - exact (uniformContinuous_eval_const x).continuous +instance : ContinuousEvalConst (ContinuousMultilinearMap 𝕜 E F) (Π i, E i) F where + continuous_eval_const x := + let _ := TopologicalAddGroup.toUniformSpace F + have _ := comm_topologicalAddGroup_is_uniform (G := F) + (uniformContinuous_eval_const x).continuous +@[deprecated (since := "2024-10-05")] protected alias continuous_eval_const := continuous_eval_const @[deprecated (since := "2024-04-10")] alias continuous_eval_left := continuous_eval_const - -theorem continuous_coe_fun : - Continuous (DFunLike.coe : ContinuousMultilinearMap 𝕜 E F → (Π i, E i) → F) := - continuous_pi continuous_eval_const +@[deprecated (since := "2024-10-05")] protected alias continuous_coe_fun := continuous_coeFun instance instT2Space [T2Space F] : T2Space (ContinuousMultilinearMap 𝕜 E F) := - .of_injective_continuous DFunLike.coe_injective continuous_coe_fun + .of_injective_continuous DFunLike.coe_injective continuous_coeFun + +instance instT3Space [T2Space F] : T3Space (ContinuousMultilinearMap 𝕜 E F) := + inferInstance section RestrictScalars variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] [∀ i, Module 𝕜' (E i)] [∀ i, IsScalarTower 𝕜' 𝕜 (E i)] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] -theorem embedding_restrictScalars : - Embedding +theorem isEmbedding_restrictScalars : + IsEmbedding (restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) := letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - (isUniformEmbedding_restrictScalars _).embedding + (isUniformEmbedding_restrictScalars _).isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_restrictScalars := isEmbedding_restrictScalars @[continuity, fun_prop] theorem continuous_restrictScalars : Continuous (restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) := - embedding_restrictScalars.continuous + isEmbedding_restrictScalars.continuous variable (𝕜') in /-- `ContinuousMultilinearMap.restrictScalars` as a `ContinuousLinearMap`. -/ diff --git a/Mathlib/Topology/Algebra/Module/StrongTopology.lean b/Mathlib/Topology/Algebra/Module/StrongTopology.lean index 08a7eee1b0c36..8a419b712dd6e 100644 --- a/Mathlib/Topology/Algebra/Module/StrongTopology.lean +++ b/Mathlib/Topology/Algebra/Module/StrongTopology.lean @@ -1,9 +1,11 @@ /- Copyright (c) 2022 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Anatole Dedecker +Authors: Anatole Dedecker, Yury Kudryashov -/ import Mathlib.Topology.Algebra.Module.UniformConvergence +import Mathlib.Topology.Algebra.SeparationQuotient.Section +import Mathlib.Topology.Hom.ContinuousEvalConst /-! # Strong topologies on the space of continuous linear maps @@ -54,7 +56,6 @@ sets). uniform convergence, bounded convergence -/ - open scoped Topology UniformConvergence Uniformity open Filter Set Function Bornology @@ -74,17 +75,16 @@ uniform convergence on the elements of `𝔖`". If the continuous linear image of any element of `𝔖` is bounded, this makes `E →SL[σ] F` a topological vector space. -/ @[nolint unusedArguments] -def UniformConvergenceCLM [TopologicalSpace F] [TopologicalAddGroup F] (_ : Set (Set E)) := - E →SL[σ] F +def UniformConvergenceCLM [TopologicalSpace F] (_ : Set (Set E)) := E →SL[σ] F namespace UniformConvergenceCLM -instance instFunLike [TopologicalSpace F] [TopologicalAddGroup F] - (𝔖 : Set (Set E)) : FunLike (UniformConvergenceCLM σ F 𝔖) E F := +instance instFunLike [TopologicalSpace F] (𝔖 : Set (Set E)) : + FunLike (UniformConvergenceCLM σ F 𝔖) E F := ContinuousLinearMap.funLike -instance instContinuousSemilinearMapClass [TopologicalSpace F] [TopologicalAddGroup F] - (𝔖 : Set (Set E)) : ContinuousSemilinearMapClass (UniformConvergenceCLM σ F 𝔖) σ E F := +instance instContinuousSemilinearMapClass [TopologicalSpace F] (𝔖 : Set (Set E)) : + ContinuousSemilinearMapClass (UniformConvergenceCLM σ F 𝔖) σ E F := ContinuousLinearMap.continuousSemilinearMapClass instance instTopologicalSpace [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 : Set (Set E)) : @@ -119,17 +119,24 @@ theorem uniformity_toTopologicalSpace_eq [UniformSpace F] [UniformAddGroup F] ( UniformConvergenceCLM.instTopologicalSpace σ F 𝔖 := rfl +theorem isUniformInducing_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) : + IsUniformInducing (α := UniformConvergenceCLM σ F 𝔖) (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe) := + ⟨rfl⟩ + theorem isUniformEmbedding_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) : IsUniformEmbedding (α := UniformConvergenceCLM σ F 𝔖) (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe) := - ⟨⟨rfl⟩, DFunLike.coe_injective⟩ + ⟨isUniformInducing_coeFn .., DFunLike.coe_injective⟩ @[deprecated (since := "2024-10-01")] alias uniformEmbedding_coeFn := isUniformEmbedding_coeFn -theorem embedding_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) : - Embedding (X := UniformConvergenceCLM σ F 𝔖) (Y := E →ᵤ[𝔖] F) +theorem isEmbedding_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) : + IsEmbedding (X := UniformConvergenceCLM σ F 𝔖) (Y := E →ᵤ[𝔖] F) (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe) := - IsUniformEmbedding.embedding (isUniformEmbedding_coeFn _ _ _) + IsUniformEmbedding.isEmbedding (isUniformEmbedding_coeFn _ _ _) + +@[deprecated (since := "2024-10-26")] +alias embedding_coeFn := isEmbedding_coeFn instance instAddCommGroup [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 : Set (Set E)) : AddCommGroup (UniformConvergenceCLM σ F 𝔖) := ContinuousLinearMap.addCommGroup @@ -151,12 +158,21 @@ instance instTopologicalAddGroup [TopologicalSpace F] [TopologicalAddGroup F] haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform infer_instance +theorem continuousEvalConst [TopologicalSpace F] [TopologicalAddGroup F] + (𝔖 : Set (Set E)) (h𝔖 : ⋃₀ 𝔖 = Set.univ) : + ContinuousEvalConst (UniformConvergenceCLM σ F 𝔖) E F where + continuous_eval_const x := by + letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F + haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform + exact (UniformOnFun.uniformContinuous_eval h𝔖 x).continuous.comp + (isEmbedding_coeFn σ F 𝔖).continuous + theorem t2Space [TopologicalSpace F] [TopologicalAddGroup F] [T2Space F] (𝔖 : Set (Set E)) (h𝔖 : ⋃₀ 𝔖 = univ) : T2Space (UniformConvergenceCLM σ F 𝔖) := by letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform haveI : T2Space (E →ᵤ[𝔖] F) := UniformOnFun.t2Space_of_covering h𝔖 - exact (embedding_coeFn σ F 𝔖).t2Space + exact (isEmbedding_coeFn σ F 𝔖).t2Space instance instDistribMulAction (M : Type*) [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜₂ M F] [TopologicalSpace F] [TopologicalAddGroup F] [ContinuousConstSMul M F] (𝔖 : Set (Set E)) : @@ -185,7 +201,7 @@ theorem hasBasis_nhds_zero_of_basis [TopologicalSpace F] [TopologicalAddGroup F] fun Si => { f : E →SL[σ] F | ∀ x ∈ Si.1, f x ∈ b Si.2 } := by letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - rw [(embedding_coeFn σ F 𝔖).toInducing.nhds_eq_comap] + rw [(isEmbedding_coeFn σ F 𝔖).isInducing.nhds_eq_comap] exact (UniformOnFun.hasBasis_nhds_zero_of_basis 𝔖 h𝔖₁ h𝔖₂ h).comap DFunLike.coe theorem hasBasis_nhds_zero [TopologicalSpace F] [TopologicalAddGroup F] @@ -202,7 +218,7 @@ theorem nhds_zero_eq_of_basis [TopologicalSpace F] [TopologicalAddGroup F] (𝔖 𝓟 {f : UniformConvergenceCLM σ F 𝔖 | MapsTo f s (b i)} := by letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - rw [(embedding_coeFn σ F 𝔖).toInducing.nhds_eq_comap, + rw [(isEmbedding_coeFn σ F 𝔖).isInducing.nhds_eq_comap, UniformOnFun.nhds_eq_of_basis _ _ h.uniformity_of_nhds_zero] simp [MapsTo] @@ -254,7 +270,7 @@ instance instUniformContinuousConstSMul (M : Type*) [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜₂ M F] [UniformSpace F] [UniformAddGroup F] [UniformContinuousConstSMul M F] (𝔖 : Set (Set E)) : UniformContinuousConstSMul M (UniformConvergenceCLM σ F 𝔖) := - (isUniformEmbedding_coeFn σ F 𝔖).toUniformInducing.uniformContinuousConstSMul fun _ _ ↦ by rfl + (isUniformInducing_coeFn σ F 𝔖).uniformContinuousConstSMul fun _ _ ↦ by rfl instance instContinuousConstSMul (M : Type*) [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜₂ M F] @@ -269,9 +285,35 @@ theorem tendsto_iff_tendstoUniformlyOn {ι : Type*} {p : Filter ι} [UniformSpac [UniformAddGroup F] (𝔖 : Set (Set E)) {a : ι → UniformConvergenceCLM σ F 𝔖} {a₀ : UniformConvergenceCLM σ F 𝔖} : Filter.Tendsto a p (𝓝 a₀) ↔ ∀ s ∈ 𝔖, TendstoUniformlyOn (a · ·) a₀ p s := by - rw [(embedding_coeFn σ F 𝔖).tendsto_nhds_iff, UniformOnFun.tendsto_iff_tendstoUniformlyOn] + rw [(isEmbedding_coeFn σ F 𝔖).tendsto_nhds_iff, UniformOnFun.tendsto_iff_tendstoUniformlyOn] rfl +variable {F} in +theorem isUniformInducing_postcomp + {G : Type*} [AddCommGroup G] [UniformSpace G] [UniformAddGroup G] + {𝕜₃ : Type*} [NormedField 𝕜₃] [Module 𝕜₃ G] + {τ : 𝕜₂ →+* 𝕜₃} {ρ : 𝕜₁ →+* 𝕜₃} [RingHomCompTriple σ τ ρ] [UniformSpace F] [UniformAddGroup F] + (g : F →SL[τ] G) (hg : IsUniformInducing g) (𝔖 : Set (Set E)) : + IsUniformInducing (α := UniformConvergenceCLM σ F 𝔖) (β := UniformConvergenceCLM ρ G 𝔖) + g.comp := by + rw [← (isUniformInducing_coeFn _ _ _).of_comp_iff] + exact (UniformOnFun.postcomp_isUniformInducing hg).comp (isUniformInducing_coeFn _ _ _) + +theorem completeSpace [UniformSpace F] [UniformAddGroup F] [ContinuousSMul 𝕜₂ F] [CompleteSpace F] + {𝔖 : Set (Set E)} (h𝔖 : RestrictGenTopology 𝔖) (h𝔖U : ⋃₀ 𝔖 = univ) : + CompleteSpace (UniformConvergenceCLM σ F 𝔖) := by + wlog hF : T2Space F generalizing F + · rw [(isUniformInducing_postcomp σ (SeparationQuotient.mkCLM 𝕜₂ F) + SeparationQuotient.isUniformInducing_mk _).completeSpace_congr] + exacts [this _ inferInstance, SeparationQuotient.postcomp_mkCLM_surjective F σ E] + rw [completeSpace_iff_isComplete_range (isUniformInducing_coeFn _ _ _)] + apply IsClosed.isComplete + have H₁ : IsClosed {f : E →ᵤ[𝔖] F | Continuous ((UniformOnFun.toFun 𝔖) f)} := + UniformOnFun.isClosed_setOf_continuous h𝔖 + convert H₁.inter <| (LinearMap.isClosed_range_coe E F σ).preimage + (UniformOnFun.uniformContinuous_toFun h𝔖U).continuous + exact ContinuousLinearMap.range_coeFn_eq + variable {𝔖₁ 𝔖₂ : Set (Set E)} theorem uniformSpace_mono [UniformSpace F] [UniformAddGroup F] (h : 𝔖₂ ⊆ 𝔖₁) : @@ -321,11 +363,13 @@ instance uniformSpace [UniformSpace F] [UniformAddGroup F] : UniformSpace (E → instance uniformAddGroup [UniformSpace F] [UniformAddGroup F] : UniformAddGroup (E →SL[σ] F) := UniformConvergenceCLM.instUniformAddGroup σ F _ -instance [TopologicalSpace F] [TopologicalAddGroup F] [ContinuousSMul 𝕜₁ E] [T2Space F] : - T2Space (E →SL[σ] F) := - UniformConvergenceCLM.t2Space σ F _ - (Set.eq_univ_of_forall fun x => - Set.mem_sUnion_of_mem (Set.mem_singleton x) (isVonNBounded_singleton x)) +instance instContinuousEvalConst [TopologicalSpace F] [TopologicalAddGroup F] + [ContinuousSMul 𝕜₁ E] : ContinuousEvalConst (E →SL[σ] F) E F := + UniformConvergenceCLM.continuousEvalConst σ F _ Bornology.isVonNBounded_covers + +instance instT2Space [TopologicalSpace F] [TopologicalAddGroup F] [ContinuousSMul 𝕜₁ E] + [T2Space F] : T2Space (E →SL[σ] F) := + UniformConvergenceCLM.t2Space σ F _ Bornology.isVonNBounded_covers protected theorem hasBasis_nhds_zero_of_basis [TopologicalSpace F] [TopologicalAddGroup F] {ι : Type*} {p : ι → Prop} {b : ι → Set F} (h : (𝓝 0 : Filter F).HasBasis p b) : @@ -405,6 +449,16 @@ theorem isVonNBounded_iff {R : Type*} [NormedDivisionRing R] ∀ s, IsVonNBounded 𝕜₁ s → IsVonNBounded R (Set.image2 (fun f x ↦ f x) S s) := UniformConvergenceCLM.isVonNBounded_iff +theorem completeSpace [UniformSpace F] [UniformAddGroup F] [ContinuousSMul 𝕜₂ F] [CompleteSpace F] + [ContinuousSMul 𝕜₁ E] (h : RestrictGenTopology {s : Set E | IsVonNBounded 𝕜₁ s}) : + CompleteSpace (E →SL[σ] F) := + UniformConvergenceCLM.completeSpace _ _ h isVonNBounded_covers + +instance instCompleteSpace [TopologicalAddGroup E] [ContinuousSMul 𝕜₁ E] [SequentialSpace E] + [UniformSpace F] [UniformAddGroup F] [ContinuousSMul 𝕜₂ F] [CompleteSpace F] : + CompleteSpace (E →SL[σ] F) := + completeSpace <| .of_seq fun _ _ h ↦ (h.isVonNBounded_range 𝕜₁).insert _ + variable (G) [TopologicalSpace F] [TopologicalSpace G] /-- Pre-composition by a *fixed* continuous linear map as a continuous linear map. @@ -419,11 +473,11 @@ def precomp [TopologicalAddGroup G] [ContinuousConstSMul 𝕜₃ G] [RingHomSurj cont := by letI : UniformSpace G := TopologicalAddGroup.toUniformSpace G haveI : UniformAddGroup G := comm_topologicalAddGroup_is_uniform - rw [(UniformConvergenceCLM.embedding_coeFn _ _ _).continuous_iff] + rw [(UniformConvergenceCLM.isEmbedding_coeFn _ _ _).continuous_iff] -- Porting note: without this, the following doesn't work change Continuous ((fun f ↦ UniformOnFun.ofFun _ (f ∘ L)) ∘ DFunLike.coe) exact (UniformOnFun.precomp_uniformContinuous fun S hS => hS.image L).continuous.comp - (UniformConvergenceCLM.embedding_coeFn _ _ _).continuous + (UniformConvergenceCLM.isEmbedding_coeFn _ _ _).continuous variable (E) {G} @@ -441,10 +495,10 @@ def postcomp [TopologicalAddGroup F] [TopologicalAddGroup G] [ContinuousConstSMu haveI : UniformAddGroup G := comm_topologicalAddGroup_is_uniform letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - rw [(UniformConvergenceCLM.embedding_coeFn _ _ _).continuous_iff] + rw [(UniformConvergenceCLM.isEmbedding_coeFn _ _ _).continuous_iff] exact (UniformOnFun.postcomp_uniformContinuous L.uniformContinuous).continuous.comp - (UniformConvergenceCLM.embedding_coeFn _ _ _).continuous + (UniformConvergenceCLM.isEmbedding_coeFn _ _ _).continuous end BoundedSets @@ -495,16 +549,19 @@ variable [TopologicalSpace F] [TopologicalAddGroup F] [Module 𝕜 F] (𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] [Module 𝕜' E] [IsScalarTower 𝕜' 𝕜 E] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] -theorem embedding_restrictScalars : - Embedding (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) := +theorem isEmbedding_restrictScalars : + IsEmbedding (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) := letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform - (isUniformEmbedding_restrictScalars _).embedding + (isUniformEmbedding_restrictScalars _).isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_restrictScalars := isEmbedding_restrictScalars @[continuity, fun_prop] theorem continuous_restrictScalars : Continuous (restrictScalars 𝕜' : (E →L[𝕜] F) → (E →L[𝕜'] F)) := - (embedding_restrictScalars _).continuous + (isEmbedding_restrictScalars _).continuous variable (𝕜 E F) variable (𝕜'' : Type*) [Ring 𝕜''] diff --git a/Mathlib/Topology/Algebra/Module/UniformConvergence.lean b/Mathlib/Topology/Algebra/Module/UniformConvergence.lean index c00130455d747..0813707e769d6 100644 --- a/Mathlib/Topology/Algebra/Module/UniformConvergence.lean +++ b/Mathlib/Topology/Algebra/Module/UniformConvergence.lean @@ -57,11 +57,11 @@ i.e., the pointwise scalar multiplication is continuous in both variables. For convenience we require that `H` is a vector space over `𝕜` with a topology induced by `UniformFun.ofFun ∘ φ`, where `φ : H →ₗ[𝕜] (α → E)`. -/ lemma UniformFun.continuousSMul_induced_of_range_bounded (φ : hom) - (hφ : Inducing (ofFun ∘ φ)) (h : ∀ u : H, Bornology.IsVonNBounded 𝕜 (Set.range (φ u))) : + (hφ : IsInducing (ofFun ∘ φ)) (h : ∀ u : H, Bornology.IsVonNBounded 𝕜 (Set.range (φ u))) : ContinuousSMul 𝕜 H := by have : TopologicalAddGroup H := let ofFun' : (α → E) →+ (α →ᵤ E) := AddMonoidHom.id _ - Inducing.topologicalAddGroup (ofFun'.comp (φ : H →+ (α → E))) hφ + IsInducing.topologicalAddGroup (ofFun'.comp (φ : H →+ (α → E))) hφ have hb : (𝓝 (0 : H)).HasBasis (· ∈ 𝓝 (0 : E)) fun V ↦ {u | ∀ x, φ u x ∈ V} := by simp only [hφ.nhds_eq_comap, Function.comp_apply, map_zero] exact UniformFun.hasBasis_nhds_zero.comap _ @@ -91,10 +91,10 @@ For convenience, we don't literally ask for `H : Submodule (α →ᵤ[𝔖] E)`. result for any vector space `H` equipped with a linear inducing to `α →ᵤ[𝔖] E`, which is often easier to use. We also state the `Submodule` version as `UniformOnFun.continuousSMul_submodule_of_image_bounded`. -/ -theorem UniformOnFun.continuousSMul_induced_of_image_bounded (φ : hom) (hφ : Inducing (ofFun 𝔖 ∘ φ)) +lemma UniformOnFun.continuousSMul_induced_of_image_bounded (φ : hom) (hφ : IsInducing (ofFun 𝔖 ∘ φ)) (h : ∀ u : H, ∀ s ∈ 𝔖, Bornology.IsVonNBounded 𝕜 ((φ u : α → E) '' s)) : ContinuousSMul 𝕜 H := by - obtain rfl := hφ.induced; clear hφ + obtain rfl := hφ.eq_induced; clear hφ simp only [induced_iInf, UniformOnFun.topologicalSpace_eq, induced_compose] refine continuousSMul_iInf fun s ↦ continuousSMul_iInf fun hs ↦ ?_ letI : TopologicalSpace H := @@ -115,6 +115,6 @@ theorem UniformOnFun.continuousSMul_submodule_of_image_bounded (H : Submodule (h : ∀ u ∈ H, ∀ s ∈ 𝔖, Bornology.IsVonNBounded 𝕜 (u '' s)) : @ContinuousSMul 𝕜 H _ _ ((UniformOnFun.topologicalSpace α E 𝔖).induced ((↑) : H → α →ᵤ[𝔖] E)) := UniformOnFun.continuousSMul_induced_of_image_bounded 𝕜 α E H - (LinearMap.id.domRestrict H : H →ₗ[𝕜] α → E) inducing_subtype_val fun ⟨u, hu⟩ => h u hu + (LinearMap.id.domRestrict H : H →ₗ[𝕜] α → E) IsInducing.subtypeVal fun ⟨u, hu⟩ => h u hu end Module diff --git a/Mathlib/Topology/Algebra/Module/WeakBilin.lean b/Mathlib/Topology/Algebra/Module/WeakBilin.lean index 916301730f678..256a8a929210a 100644 --- a/Mathlib/Topology/Algebra/Module/WeakBilin.lean +++ b/Mathlib/Topology/Algebra/Module/WeakBilin.lean @@ -106,14 +106,17 @@ theorem continuous_of_continuous_eval [TopologicalSpace α] {g : α → WeakBili continuous_induced_rng.2 (continuous_pi_iff.mpr h) /-- The coercion `(fun x y => B x y) : E → (F → 𝕜)` is an embedding. -/ -theorem embedding {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} (hB : Function.Injective B) : - Embedding fun (x : WeakBilin B) y => B x y := - Function.Injective.embedding_induced <| LinearMap.coe_injective.comp hB +theorem isEmbedding {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} (hB : Function.Injective B) : + IsEmbedding fun (x : WeakBilin B) y => B x y := + Function.Injective.isEmbedding_induced <| LinearMap.coe_injective.comp hB + +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding theorem tendsto_iff_forall_eval_tendsto {l : Filter α} {f : α → WeakBilin B} {x : WeakBilin B} (hB : Function.Injective B) : Tendsto f l (𝓝 x) ↔ ∀ y, Tendsto (fun i => B (f i) y) l (𝓝 (B x y)) := by - rw [← tendsto_pi_nhds, Embedding.tendsto_nhds_iff (embedding hB)] + rw [← tendsto_pi_nhds, (isEmbedding hB).tendsto_nhds_iff] rfl /-- Addition in `WeakBilin B` is continuous. -/ diff --git a/Mathlib/Topology/Algebra/Module/WeakDual.lean b/Mathlib/Topology/Algebra/Module/WeakDual.lean index 1a71efa833d83..d2bdbb2408760 100644 --- a/Mathlib/Topology/Algebra/Module/WeakDual.lean +++ b/Mathlib/Topology/Algebra/Module/WeakDual.lean @@ -102,11 +102,6 @@ instance instFunLike : FunLike (WeakDual 𝕜 E) E 𝕜 := instance instContinuousLinearMapClass : ContinuousLinearMapClass (WeakDual 𝕜 E) 𝕜 E 𝕜 := ContinuousLinearMap.continuousSemilinearMapClass -/-- Helper instance for when there's too many metavariables to apply `DFunLike.hasCoeToFun` -directly. -/ -instance : CoeFun (WeakDual 𝕜 E) fun _ => E → 𝕜 := - DFunLike.hasCoeToFun - /-- If a monoid `M` distributively continuously acts on `𝕜` and this action commutes with multiplication on `𝕜`, then it acts on `WeakDual 𝕜 E`. -/ instance instMulAction (M) [Monoid M] [DistribMulAction M 𝕜] [SMulCommClass 𝕜 M 𝕜] @@ -148,9 +143,7 @@ theorem continuous_of_continuous_eval [TopologicalSpace α] {g : α → WeakDual continuous_induced_rng.2 (continuous_pi_iff.mpr h) instance instT2Space [T2Space 𝕜] : T2Space (WeakDual 𝕜 E) := - Embedding.t2Space <| - WeakBilin.embedding <| - show Function.Injective (topDualPairing 𝕜 E) from ContinuousLinearMap.coe_injective + (WeakBilin.isEmbedding ContinuousLinearMap.coe_injective).t2Space end Semiring diff --git a/Mathlib/Topology/Algebra/Monoid.lean b/Mathlib/Topology/Algebra/Monoid.lean index 77b696c9d052c..b711def8cff6f 100644 --- a/Mathlib/Topology/Algebra/Monoid.lean +++ b/Mathlib/Topology/Algebra/Monoid.lean @@ -7,8 +7,8 @@ import Mathlib.Algebra.BigOperators.Finprod import Mathlib.Order.Filter.Pointwise import Mathlib.Topology.Algebra.MulAction import Mathlib.Algebra.BigOperators.Pi -import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Algebra.Group.ULift +import Mathlib.Topology.ContinuousMap.Defs /-! # Theory of topological monoids @@ -302,8 +302,6 @@ theorem isClosed_setOf_map_mul [Mul M₁] [Mul M₂] [ContinuousMul M₂] : isClosed_iInter fun x => isClosed_iInter fun y => isClosed_eq (continuous_apply _) - -- Porting note: proof was: - -- `((continuous_apply _).mul (continuous_apply _))` (by continuity) -- Porting note: split variables command over two lines, can't change explicitness at the same time @@ -343,21 +341,23 @@ theorem MonoidHom.isClosed_range_coe : IsClosed (Set.range ((↑) : (M₁ →* M end PointwiseLimits @[to_additive] -theorem Inducing.continuousMul {M N F : Type*} [Mul M] [Mul N] [FunLike F M N] [MulHomClass F M N] - [TopologicalSpace M] [TopologicalSpace N] [ContinuousMul N] (f : F) (hf : Inducing f) : - ContinuousMul M := +theorem IsInducing.continuousMul {M N F : Type*} [Mul M] [Mul N] [FunLike F M N] + [MulHomClass F M N] [TopologicalSpace M] [TopologicalSpace N] [ContinuousMul N] (f : F) + (hf : IsInducing f) : ContinuousMul M := ⟨(hf.continuousSMul hf.continuous (map_mul f _ _)).1⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.continuousMul := IsInducing.continuousMul + @[to_additive] theorem continuousMul_induced {M N F : Type*} [Mul M] [Mul N] [FunLike F M N] [MulHomClass F M N] [TopologicalSpace N] [ContinuousMul N] (f : F) : @ContinuousMul M (induced f ‹_›) _ := letI := induced f ‹_› - Inducing.continuousMul f ⟨rfl⟩ + IsInducing.continuousMul f ⟨rfl⟩ @[to_additive] instance Subsemigroup.continuousMul [TopologicalSpace M] [Semigroup M] [ContinuousMul M] (S : Subsemigroup M) : ContinuousMul S := - Inducing.continuousMul ({ toFun := (↑), map_mul' := fun _ _ => rfl} : MulHom S M) ⟨rfl⟩ + IsInducing.continuousMul ({ toFun := (↑), map_mul' := fun _ _ => rfl} : MulHom S M) ⟨rfl⟩ @[to_additive] instance Submonoid.continuousMul [TopologicalSpace M] [Monoid M] [ContinuousMul M] @@ -614,8 +614,7 @@ of the monoid, with respect to the induced topology, is continuous. Negation is also continuous, but we register this in a later file, `Topology.Algebra.Group`, because the predicate `ContinuousNeg` has not yet been defined."] -instance : ContinuousMul αˣ := - inducing_embedProduct.continuousMul (embedProduct α) +instance : ContinuousMul αˣ := isInducing_embedProduct.continuousMul (embedProduct α) end Units diff --git a/Mathlib/Topology/Algebra/MulAction.lean b/Mathlib/Topology/Algebra/MulAction.lean index 91dc843aa0507..39f700ad8f4b0 100644 --- a/Mathlib/Topology/Algebra/MulAction.lean +++ b/Mathlib/Topology/Algebra/MulAction.lean @@ -177,17 +177,19 @@ Then the action of `N` on `X` is continuous as well. In many cases, `f = id` so that `g` is an action homomorphism in the sense of `AddActionHom`. However, this version also works for `f = AddUnits.val`."] -lemma Inducing.continuousSMul {N : Type*} [SMul N Y] [TopologicalSpace N] {f : N → M} - (hg : Inducing g) (hf : Continuous f) (hsmul : ∀ {c x}, g (c • x) = f c • g x) : +lemma IsInducing.continuousSMul {N : Type*} [SMul N Y] [TopologicalSpace N] {f : N → M} + (hg : IsInducing g) (hf : Continuous f) (hsmul : ∀ {c x}, g (c • x) = f c • g x) : ContinuousSMul N Y where continuous_smul := by simpa only [hg.continuous_iff, Function.comp_def, hsmul] using (hf.comp continuous_fst).smul <| hg.continuous.comp continuous_snd +@[deprecated (since := "2024-10-28")] alias Inducing.continuousSMul := IsInducing.continuousSMul + @[to_additive] instance SMulMemClass.continuousSMul {S : Type*} [SetLike S X] [SMulMemClass S M X] (s : S) : ContinuousSMul M s := - inducing_subtype_val.continuousSMul continuous_id rfl + IsInducing.subtypeVal.continuousSMul continuous_id rfl end SMul @@ -197,7 +199,7 @@ variable [Monoid M] [MulAction M X] [ContinuousSMul M X] @[to_additive] instance Units.continuousSMul : ContinuousSMul Mˣ X := - inducing_id.continuousSMul Units.continuous_val rfl + IsInducing.id.continuousSMul Units.continuous_val rfl /-- If an action is continuous, then composing this action with a continuous homomorphism gives again a continuous action. -/ @@ -211,7 +213,7 @@ theorem MulAction.continuousSMul_compHom @[to_additive] instance Submonoid.continuousSMul {S : Submonoid M} : ContinuousSMul S X := - inducing_id.continuousSMul continuous_subtype_val rfl + IsInducing.id.continuousSMul continuous_subtype_val rfl end Monoid diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean index 6550bf2652504..06b301dde6cb3 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean @@ -60,7 +60,7 @@ variable {K : Type*} [Group K] [TopologicalSpace K] [NonarchimedeanGroup K] /-- If a topological group embeds into a nonarchimedean group, then it is nonarchimedean. -/ @[to_additive] -theorem nonarchimedean_of_emb (f : G →* H) (emb : OpenEmbedding f) : NonarchimedeanGroup H := +theorem nonarchimedean_of_emb (f : G →* H) (emb : IsOpenEmbedding f) : NonarchimedeanGroup H := { is_nonarchimedean := fun U hU => have h₁ : f ⁻¹' U ∈ 𝓝 (1 : G) := by apply emb.continuous.tendsto @@ -75,7 +75,7 @@ the cartesian product of two nonarchimedean groups contains the cartesian produc an open neighborhood in each group."] theorem prod_subset {U} (hU : U ∈ 𝓝 (1 : G × K)) : ∃ (V : OpenSubgroup G) (W : OpenSubgroup K), (V : Set G) ×ˢ (W : Set K) ⊆ U := by - erw [nhds_prod_eq, Filter.mem_prod_iff] at hU + rw [nhds_prod_eq, Filter.mem_prod_iff] at hU rcases hU with ⟨U₁, hU₁, U₂, hU₂, h⟩ cases' is_nonarchimedean _ hU₁ with V hV cases' is_nonarchimedean _ hU₂ with W hW @@ -97,7 +97,7 @@ theorem prod_self_subset {U} (hU : U ∈ 𝓝 (1 : G × G)) : /-- The cartesian product of two nonarchimedean groups is nonarchimedean. -/ @[to_additive "The cartesian product of two nonarchimedean groups is nonarchimedean."] instance : NonarchimedeanGroup (G × K) where - is_nonarchimedean U hU := + is_nonarchimedean _ hU := let ⟨V, W, h⟩ := prod_subset hU ⟨V.prod W, ‹_›⟩ diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/TotallyDisconnected.lean b/Mathlib/Topology/Algebra/Nonarchimedean/TotallyDisconnected.lean new file mode 100644 index 0000000000000..fd36afa2ef8c6 --- /dev/null +++ b/Mathlib/Topology/Algebra/Nonarchimedean/TotallyDisconnected.lean @@ -0,0 +1,60 @@ +/- +Copyright (c) 2024 Jou Glasheen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jou Glasheen, Kevin Buzzard, David Loeffler, Yongle Hu, Johan Commelin +-/ + +import Mathlib.Topology.Algebra.Nonarchimedean.Basic + +/-! +# Total separatedness of nonarchimedean groups + +In this file, we prove that a nonarchimedean group is a totally separated topological space. +The fact that a nonarchimedean group is a totally disconnected topological space +is implied by the fact that a nonarchimedean group is totally separated. + +## Main results + +- `NonarchimedeanGroup.instTotallySeparated`: + A nonarchimedean group is a totally separated topological space. + +## Notation + + - `G` : Is a nonarchimedean group. + - `V` : Is an open subgroup which is a neighbourhood of the identity in `G`. + +## References + +See Proposition 2.3.9 and Problem 63 in [F. Q. Gouvêa, *p-adic numbers*][gouvea1997]. +-/ + +open Pointwise TopologicalSpace + +variable {G : Type*} [TopologicalSpace G] [Group G] [NonarchimedeanGroup G] [T2Space G] + +namespace NonarchimedeanGroup + +@[to_additive] +lemma exists_openSubgroup_separating {a b : G} (h : a ≠ b) : + ∃ (V : OpenSubgroup G), Disjoint (a • (V : Set G)) (b • V) := by + obtain ⟨u, v, _, open_v, mem_u, mem_v, dis⟩ := t2_separation (h ∘ inv_mul_eq_one.mp) + obtain ⟨V, hV⟩ := is_nonarchimedean v (open_v.mem_nhds mem_v) + use V + simp only [Disjoint, Set.le_eq_subset, Set.bot_eq_empty, Set.subset_empty_iff] + intros x mem_aV mem_bV + by_contra! con + obtain ⟨s, hs⟩ := con + have hsa : s ∈ a • (V : Set G) := mem_aV hs + have hsb : s ∈ b • (V : Set G) := mem_bV hs + rw [mem_leftCoset_iff] at hsa hsb + refine dis.subset_compl_right mem_u (hV ?_) + simpa [mul_assoc] using mul_mem hsa (inv_mem hsb) + +@[to_additive] +instance (priority := 100) instTotallySeparated : TotallySeparatedSpace G where + isTotallySeparated_univ x _ y _ hxy := by + obtain ⟨V, dxy⟩ := exists_openSubgroup_separating hxy + exact ⟨_, _, V.isOpen.smul x, (V.isClosed.smul x).isOpen_compl, mem_own_leftCoset .., + dxy.subset_compl_left <| mem_own_leftCoset .., by simp, disjoint_compl_right⟩ + +end NonarchimedeanGroup diff --git a/Mathlib/Topology/Algebra/OpenSubgroup.lean b/Mathlib/Topology/Algebra/OpenSubgroup.lean index 99c3a4c276f10..e604312216e17 100644 --- a/Mathlib/Topology/Algebra/OpenSubgroup.lean +++ b/Mathlib/Topology/Algebra/OpenSubgroup.lean @@ -3,7 +3,10 @@ Copyright (c) 2019 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Nailin Guan -/ -import Mathlib.RingTheory.Ideal.Basic +import Mathlib.Algebra.Module.Submodule.Lattice +import Mathlib.Order.OmegaCompletePartialOrder +import Mathlib.RingTheory.Ideal.Defs +import Mathlib.Topology.Algebra.Group.Quotient import Mathlib.Topology.Algebra.Ring.Basic import Mathlib.Topology.Sets.Opens @@ -453,3 +456,110 @@ instance [ContinuousMul G] : Lattice (OpenNormalSubgroup G) := end OpenNormalSubgroup end + +/-! +# Existence of an open subgroup in any clopen neighborhood of the neutral element + +This section proves the lemma `TopologicalGroup.exist_openSubgroup_sub_clopen_nhd_of_one`, which +states that in a compact topological group, for any clopen neighborhood of 1, +there exists an open subgroup contained within it. +-/ + +open scoped Pointwise + +variable {G : Type*} [TopologicalSpace G] + +structure TopologicalAddGroup.addNegClosureNhd (T W : Set G) [AddGroup G] : Prop where + nhd : T ∈ 𝓝 0 + neg : -T = T + isOpen : IsOpen T + add : W + T ⊆ W + +/-- For a set `W`, `T` is a neighborhood of `1` which is open, statble under inverse and satisfies +`T * W ⊆ W`. -/ +@[to_additive +"For a set `W`, `T` is a neighborhood of `0` which is open, stable under negation and satisfies +`T + W ⊆ W`. "] +structure TopologicalGroup.mulInvClosureNhd (T W : Set G) [Group G] : Prop where + nhd : T ∈ 𝓝 1 + inv : T⁻¹ = T + isOpen : IsOpen T + mul : W * T ⊆ W + +namespace TopologicalGroup + +variable [Group G] [TopologicalGroup G] [CompactSpace G] + +open Set Filter + +@[to_additive] +lemma exist_mul_closure_nhd {W : Set G} (WClopen : IsClopen W) : ∃ T ∈ 𝓝 (1 : G), W * T ⊆ W := by + apply WClopen.isClosed.isCompact.induction_on (p := fun S ↦ ∃ T ∈ 𝓝 (1 : G), S * T ⊆ W) + ⟨Set.univ ,by simp only [univ_mem, empty_mul, empty_subset, and_self]⟩ + (fun _ _ huv ⟨T, hT, mem⟩ ↦ ⟨T, hT, (mul_subset_mul_right huv).trans mem⟩) + fun U V ⟨T₁, hT₁, mem1⟩ ⟨T₂, hT₂, mem2⟩ ↦ ⟨T₁ ∩ T₂, inter_mem hT₁ hT₂, by + rw [union_mul] + exact union_subset (mul_subset_mul_left inter_subset_left |>.trans mem1) + (mul_subset_mul_left inter_subset_right |>.trans mem2) ⟩ + intro x memW + have : (x, 1) ∈ (fun p ↦ p.1 * p.2) ⁻¹' W := by simp [memW] + rcases isOpen_prod_iff.mp (continuous_mul.isOpen_preimage W <| WClopen.2) x 1 this with + ⟨U, V, Uopen, Vopen, xmemU, onememV, prodsub⟩ + have h6 : U * V ⊆ W := mul_subset_iff.mpr (fun _ hx _ hy ↦ prodsub (mk_mem_prod hx hy)) + exact ⟨U ∩ W, ⟨U, Uopen.mem_nhds xmemU, W, fun _ a ↦ a, rfl⟩, + V, IsOpen.mem_nhds Vopen onememV, fun _ a ↦ h6 ((mul_subset_mul_right inter_subset_left) a)⟩ + +@[to_additive] +lemma exists_mulInvClosureNhd {W : Set G} (WClopen : IsClopen W) : + ∃ T, mulInvClosureNhd T W := by + rcases exist_mul_closure_nhd WClopen with ⟨S, Smemnhds, mulclose⟩ + rcases mem_nhds_iff.mp Smemnhds with ⟨U, UsubS, Uopen, onememU⟩ + use U ∩ U⁻¹ + constructor + · simp [Uopen.mem_nhds onememU, inv_mem_nhds_one] + · simp [inter_comm] + · exact Uopen.inter Uopen.inv + · exact fun a ha ↦ mulclose (mul_subset_mul_left UsubS (mul_subset_mul_left inter_subset_left ha)) + +@[to_additive] +theorem exist_openSubgroup_sub_clopen_nhd_of_one {G : Type*} [Group G] [TopologicalSpace G] + [TopologicalGroup G] [CompactSpace G] {W : Set G} (WClopen : IsClopen W) (einW : 1 ∈ W) : + ∃ H : OpenSubgroup G, (H : Set G) ⊆ W := by + rcases exists_mulInvClosureNhd WClopen with ⟨V, hV⟩ + let S : Subgroup G := { + carrier := ⋃ n , V ^ (n + 1) + mul_mem' := fun ha hb ↦ by + rcases mem_iUnion.mp ha with ⟨k, hk⟩ + rcases mem_iUnion.mp hb with ⟨l, hl⟩ + apply mem_iUnion.mpr + use k + 1 + l + rw [add_assoc, pow_add] + exact Set.mul_mem_mul hk hl + one_mem' := by + apply mem_iUnion.mpr + use 0 + simp [mem_of_mem_nhds hV.nhd] + inv_mem' := fun ha ↦ by + rcases mem_iUnion.mp ha with ⟨k, hk⟩ + apply mem_iUnion.mpr + use k + rw [← hV.inv] + simpa only [inv_pow, Set.mem_inv, inv_inv] using hk } + have : IsOpen (⋃ n , V ^ (n + 1)) := by + refine isOpen_iUnion (fun n ↦ ?_) + rw [pow_succ] + exact hV.isOpen.mul_left + use ⟨S, this⟩ + have mulVpow (n : ℕ) : W * V ^ (n + 1) ⊆ W := by + induction' n with n ih + · simp [hV.mul] + · rw [pow_succ, ← mul_assoc] + exact (Set.mul_subset_mul_right ih).trans hV.mul + have (n : ℕ) : V ^ (n + 1) ⊆ W * V ^ (n + 1) := by + intro x xin + rw [Set.mem_mul] + use 1, einW, x, xin + rw [one_mul] + apply iUnion_subset fun i _ a ↦ mulVpow i (this i a) + +end TopologicalGroup diff --git a/Mathlib/Topology/Algebra/Order/Field.lean b/Mathlib/Topology/Algebra/Order/Field.lean index 9779411cedf57..8e6a51ab5faed 100644 --- a/Mathlib/Topology/Algebra/Order/Field.lean +++ b/Mathlib/Topology/Algebra/Order/Field.lean @@ -141,6 +141,40 @@ theorem Filter.Tendsto.inv_tendsto_atTop (h : Tendsto f l atTop) : Tendsto f⁻ theorem Filter.Tendsto.inv_tendsto_zero (h : Tendsto f l (𝓝[>] 0)) : Tendsto f⁻¹ l atTop := tendsto_inv_zero_atTop.comp h +/-- If `g` tends to zero and there exists a constant `C : 𝕜` such that eventually `|f x| ≤ C`, + then the product `f * g` tends to zero. -/ +theorem bdd_le_mul_tendsto_zero' {f g : α → 𝕜} (C : 𝕜) (hf : ∀ᶠ x in l, |f x| ≤ C) + (hg : Tendsto g l (𝓝 0)) : Tendsto (fun x ↦ f x * g x) l (𝓝 0) := by + rw [tendsto_zero_iff_abs_tendsto_zero] + have hC : Tendsto (fun x ↦ |C * g x|) l (𝓝 0) := by + convert (hg.const_mul C).abs + simp_rw [mul_zero, abs_zero] + apply tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds hC + · filter_upwards [hf] with x _ using abs_nonneg _ + · filter_upwards [hf] with x hx + simp only [comp_apply, abs_mul] + exact mul_le_mul_of_nonneg_right (hx.trans (le_abs_self C)) (abs_nonneg _) + +/-- If `g` tends to zero and there exist constants `b B : 𝕜` such that eventually `b ≤ f x| ≤ B`, + then the product `f * g` tends to zero. -/ +theorem bdd_le_mul_tendsto_zero {f g : α → 𝕜} {b B : 𝕜} (hb : ∀ᶠ x in l, b ≤ f x) + (hB : ∀ᶠ x in l, f x ≤ B) (hg : Tendsto g l (𝓝 0)) : + Tendsto (fun x ↦ f x * g x) l (𝓝 0) := by + set C := max |b| |B| + have hbC : -C ≤ b := neg_le.mpr (le_max_of_le_left (neg_le_abs b)) + have hBC : B ≤ C := le_max_of_le_right (le_abs_self B) + apply bdd_le_mul_tendsto_zero' C _ hg + filter_upwards [hb, hB] + exact fun x hbx hBx ↦ abs_le.mpr ⟨hbC.trans hbx, hBx.trans hBC⟩ + +/-- If `g` tends to `atTop` and there exist constants `b B : 𝕜` such that eventually + `b ≤ f x| ≤ B`, then the quotient `f / g` tends to zero. -/ +theorem tendsto_bdd_div_atTop_nhds_zero {f g : α → 𝕜} {b B : 𝕜} + (hb : ∀ᶠ x in l, b ≤ f x) (hB : ∀ᶠ x in l, f x ≤ B) (hg : Tendsto g l atTop) : + Tendsto (fun x => f x / g x) l (𝓝 0) := by + simp only [div_eq_mul_inv] + exact bdd_le_mul_tendsto_zero hb hB hg.inv_tendsto_atTop + /-- The function `x^(-n)` tends to `0` at `+∞` for any positive natural `n`. A version for positive real powers exists as `tendsto_rpow_neg_atTop`. -/ theorem tendsto_pow_neg_atTop {n : ℕ} (hn : n ≠ 0) : @@ -195,10 +229,10 @@ instance (priority := 100) LinearOrderedSemifield.toHasContinuousInv₀ {𝕜} · obtain ⟨x', h₀, hxx', h₁⟩ : ∃ x', 0 < x' ∧ x ≤ x' ∧ x' < 1 := ⟨max x (1 / 2), one_half_pos.trans_le (le_max_right _ _), le_max_left _ _, max_lt hx one_half_lt_one⟩ - filter_upwards [Ioo_mem_nhds one_pos (one_lt_inv h₀ h₁)] with y hy - exact hxx'.trans_lt <| inv_inv x' ▸ inv_lt_inv_of_lt hy.1 hy.2 - · filter_upwards [Ioi_mem_nhds (inv_lt_one hx)] with y hy - simpa only [inv_inv] using inv_lt_inv_of_lt (inv_pos.2 <| one_pos.trans hx) hy + filter_upwards [Ioo_mem_nhds one_pos ((one_lt_inv₀ h₀).2 h₁)] with y hy + exact hxx'.trans_lt <| lt_inv_of_lt_inv₀ hy.1 hy.2 + · filter_upwards [Ioi_mem_nhds (inv_lt_one_of_one_lt₀ hx)] with y hy + exact inv_lt_of_inv_lt₀ (by positivity) hy instance (priority := 100) LinearOrderedField.toTopologicalDivisionRing : TopologicalDivisionRing 𝕜 := ⟨⟩ diff --git a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean index 2514169662c24..18a175654b3dd 100644 --- a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean +++ b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean @@ -271,7 +271,7 @@ variable [CompleteLinearOrder α] [TopologicalSpace α] [FirstCountableTopology @[simp] theorem limsup_eq_bot : f.limsup u = ⊥ ↔ u =ᶠ[f] ⊥ := ⟨fun h => - (EventuallyLE.trans eventually_le_limsup <| Eventually.of_forall fun _ => h.le).mono fun x hx => + (EventuallyLE.trans eventually_le_limsup <| Eventually.of_forall fun _ => h.le).mono fun _ hx => le_antisymm hx bot_le, fun h => by rw [limsup_congr h] @@ -525,7 +525,7 @@ variable [ConditionallyCompleteLinearOrder R] [TopologicalSpace R] [OrderTopolog /-- `liminf (c + xᵢ) = c + liminf xᵢ`. -/ lemma limsup_const_add (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] - [CovariantClass R R (fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [AddLeftMono R] (f : ι → R) (c : R) (bdd_above : F.IsBoundedUnder (· ≤ ·) f) (cobdd : F.IsCoboundedUnder (· ≤ ·) f) : Filter.limsup (fun i ↦ c + f i) F = c + Filter.limsup f F := (Monotone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ c + x) @@ -533,7 +533,7 @@ lemma limsup_const_add (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] /-- `limsup (xᵢ + c) = (limsup xᵢ) + c`. -/ lemma limsup_add_const (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] - [CovariantClass R R (Function.swap fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [AddRightMono R] (f : ι → R) (c : R) (bdd_above : F.IsBoundedUnder (· ≤ ·) f) (cobdd : F.IsCoboundedUnder (· ≤ ·) f) : Filter.limsup (fun i ↦ f i + c) F = Filter.limsup f F + c := (Monotone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ x + c) @@ -541,7 +541,7 @@ lemma limsup_add_const (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] /-- `liminf (c + xᵢ) = c + limsup xᵢ`. -/ lemma liminf_const_add (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] - [CovariantClass R R (fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [AddLeftMono R] (f : ι → R) (c : R) (cobdd : F.IsCoboundedUnder (· ≥ ·) f) (bdd_below : F.IsBoundedUnder (· ≥ ·) f) : Filter.liminf (fun i ↦ c + f i) F = c + Filter.liminf f F := (Monotone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ c + x) @@ -549,7 +549,7 @@ lemma liminf_const_add (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] /-- `liminf (xᵢ + c) = (liminf xᵢ) + c`. -/ lemma liminf_add_const (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] - [CovariantClass R R (Function.swap fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [AddRightMono R] (f : ι → R) (c : R) (cobdd : F.IsCoboundedUnder (· ≥ ·) f) (bdd_below : F.IsBoundedUnder (· ≥ ·) f) : Filter.liminf (fun i ↦ f i + c) F = Filter.liminf f F + c := (Monotone.map_limsInf_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ x + c) @@ -557,7 +557,7 @@ lemma liminf_add_const (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] /-- `limsup (c - xᵢ) = c - liminf xᵢ`. -/ lemma limsup_const_sub (F : Filter ι) [AddCommSemigroup R] [Sub R] [ContinuousSub R] [OrderedSub R] - [CovariantClass R R (fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [AddLeftMono R] (f : ι → R) (c : R) (cobdd : F.IsCoboundedUnder (· ≥ ·) f) (bdd_below : F.IsBoundedUnder (· ≥ ·) f) : Filter.limsup (fun i ↦ c - f i) F = c - Filter.liminf f F := by rcases F.eq_or_neBot with rfl | _ @@ -594,7 +594,7 @@ lemma limsup_sub_const (F : Filter ι) [AddCommSemigroup R] [Sub R] [ContinuousS /-- `liminf (c - xᵢ) = c - limsup xᵢ`. -/ lemma liminf_const_sub (F : Filter ι) [NeBot F] [AddCommSemigroup R] [Sub R] [ContinuousSub R] - [OrderedSub R] [CovariantClass R R (fun x y ↦ x + y) fun x y ↦ x ≤ y] (f : ι → R) (c : R) + [OrderedSub R] [AddLeftMono R] (f : ι → R) (c : R) (bdd_above : F.IsBoundedUnder (· ≤ ·) f) (cobdd : F.IsCoboundedUnder (· ≤ ·) f) : Filter.liminf (fun i ↦ c - f i) F = c - Filter.limsup f F := (Antitone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : R) ↦ c - x) diff --git a/Mathlib/Topology/Algebra/PontryaginDual.lean b/Mathlib/Topology/Algebra/PontryaginDual.lean index 262a7e2fde965..4229049cf7321 100644 --- a/Mathlib/Topology/Algebra/PontryaginDual.lean +++ b/Mathlib/Topology/Algebra/PontryaginDual.lean @@ -22,9 +22,9 @@ isomorphic to its double dual. open Pointwise Function -variable (A B C D E G : Type*) [Monoid A] [Monoid B] [Monoid C] [Monoid D] [CommGroup E] [Group G] - [TopologicalSpace A] [TopologicalSpace B] [TopologicalSpace C] [TopologicalSpace D] - [TopologicalSpace E] [TopologicalSpace G] [TopologicalGroup E] [TopologicalGroup G] +variable (A B C G H : Type*) [Monoid A] [Monoid B] [Monoid C] [CommGroup G] [Group H] + [TopologicalSpace A] [TopologicalSpace B] [TopologicalSpace C] + [TopologicalSpace G] [TopologicalSpace H] [TopologicalGroup G] [TopologicalGroup H] /-- The Pontryagin dual of `A` is the group of continuous homomorphism `A → Circle`. -/ def PontryaginDual := @@ -48,7 +48,7 @@ instance : TopologicalGroup (PontryaginDual A) := noncomputable instance : Inhabited (PontryaginDual A) := (inferInstance : Inhabited (ContinuousMonoidHom A Circle)) -instance [LocallyCompactSpace G] : LocallyCompactSpace (PontryaginDual G) := by +instance [LocallyCompactSpace H] : LocallyCompactSpace (PontryaginDual H) := by let Vn : ℕ → Set Circle := fun n ↦ Circle.exp '' { x | |x| < Real.pi / 2 ^ (n + 1)} have hVn : ∀ n x, x ∈ Vn n ↔ |Complex.arg x| < Real.pi / 2 ^ (n + 1) := by @@ -75,17 +75,20 @@ instance [LocallyCompactSpace G] : LocallyCompactSpace (PontryaginDual G) := by refine (Nat.le_ceil (Real.pi / x)).trans ?_ exact_mod_cast (Nat.le_succ _).trans (Nat.lt_two_pow _).le -variable {A B C D E} +variable {A B C G} namespace PontryaginDual open ContinuousMonoidHom instance : FunLike (PontryaginDual A) A Circle := - ContinuousMonoidHom.funLike + ContinuousMonoidHom.instFunLike -noncomputable instance : ContinuousMonoidHomClass (PontryaginDual A) A Circle := - ContinuousMonoidHom.ContinuousMonoidHomClass +noncomputable instance instContinuousMapClass : ContinuousMapClass (PontryaginDual A) A Circle := + ContinuousMonoidHom.instContinuousMapClass + +noncomputable instance instMonoidHomClass : MonoidHomClass (PontryaginDual A) A Circle := + ContinuousMonoidHom.instMonoidHomClass /-- `PontryaginDual` is a contravariant functor. -/ noncomputable def map (f : ContinuousMonoidHom A B) : @@ -107,15 +110,15 @@ theorem map_comp (g : ContinuousMonoidHom B C) (f : ContinuousMonoidHom A B) : ext fun _x => ext fun _y => rfl @[simp] -nonrec theorem map_mul (f g : ContinuousMonoidHom A E) : map (f * g) = map f * map g := +nonrec theorem map_mul (f g : ContinuousMonoidHom A G) : map (f * g) = map f * map g := ext fun x => ext fun y => map_mul x (f y) (g y) -variable (A B C D E) +variable (A B C G) /-- `ContinuousMonoidHom.dual` as a `ContinuousMonoidHom`. -/ -noncomputable def mapHom [LocallyCompactSpace E] : - ContinuousMonoidHom (ContinuousMonoidHom A E) - (ContinuousMonoidHom (PontryaginDual E) (PontryaginDual A)) where +noncomputable def mapHom [LocallyCompactSpace G] : + ContinuousMonoidHom (ContinuousMonoidHom A G) + (ContinuousMonoidHom (PontryaginDual G) (PontryaginDual A)) where toFun := map map_one' := map_one map_mul' := map_mul diff --git a/Mathlib/Topology/Algebra/ProperAction.lean b/Mathlib/Topology/Algebra/ProperAction/Basic.lean similarity index 50% rename from Mathlib/Topology/Algebra/ProperAction.lean rename to Mathlib/Topology/Algebra/ProperAction/Basic.lean index d37212b162f3c..5b68b2d2d0d6f 100644 --- a/Mathlib/Topology/Algebra/ProperAction.lean +++ b/Mathlib/Topology/Algebra/ProperAction/Basic.lean @@ -3,10 +3,9 @@ Copyright (c) 2024 Anatole Dedeker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedeker, Etienne Marion, Florestan Martin-Baillon, Vincent Guirardel -/ -import Mathlib.Topology.Algebra.Group.Basic import Mathlib.Topology.Algebra.MulAction import Mathlib.Topology.Maps.Proper.Basic -import Mathlib.Topology.Sequences +import Mathlib.Topology.Maps.OpenQuotient /-! # Proper group action @@ -14,9 +13,6 @@ import Mathlib.Topology.Sequences In this file we define proper action of a group on a topological space, and we prove that in this case the quotient space is T2. We also give equivalent definitions of proper action using ultrafilters and show the transfer of proper action to a closed subgroup. -We give sufficient conditions on the topological space such that the action is properly -discontinuous (see `ProperlyDiscontinuousSMul`) if and only if it is continuous in -the first variable (see `ContinuousConstSMul`) and proper in the sense defined here. ## Main definitions @@ -29,19 +25,6 @@ the first variable (see `ContinuousConstSMul`) and proper in the sense defined h on a topological space `X`, then the quotient space is Hausdorff (T2). * `t2Space_of_properSMul_of_t2Group`: If a T2 group acts properly on a topological space, then this topological space is T2. -* `properlyDiscontinuousSMul_iff_properSMul`: If a discrete group acts on a T2 space `X` such that - `X × X` is compactly generated, then the action is properly discontinuous if and only if it is - continuous in the second variable and proper. This in particular true if `X` is locally compact - or first-countable. - -## Implementation notes - -Concerning `properlyDiscontinuousSMul_iff_properSMul`, this result should be the only one needed -to link properly discontinuous and proper actions. - -TODO: Replace the compactly generated hypothesis by a typeclass instance such that -`WeaklyLocallyCompactSpace.isProperMap_iff_isCompact_preimage` and -`SequentialSpace.isProperMap_iff_isCompact_preimage` are inferred by typeclass inference. ## References @@ -73,9 +56,8 @@ class ProperSMul (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [Group attribute [to_additive existing] properSMul_iff -variable {G X Y Z : Type*} [Group G] [MulAction G X] [MulAction G Y] -variable [TopologicalSpace G] [TopologicalSpace X] [TopologicalSpace Y] -variable [TopologicalSpace Z] +variable {G X : Type*} [Group G] [MulAction G X] +variable [TopologicalSpace G] [TopologicalSpace X] /-- If a group acts properly then in particular it acts continuously. -/ @[to_additive "If a group acts properly then in particular it acts continuously."] @@ -131,12 +113,12 @@ theorem t2Space_quotient_mulAction_of_properSMul [ProperSMul G X] : let π : X → Quotient R := Quotient.mk' have : IsOpenQuotientMap (Prod.map π π) := MulAction.isOpenQuotientMap_quotientMk.prodMap MulAction.isOpenQuotientMap_quotientMk - rw [← this.quotientMap.isClosed_preimage] + rw [← this.isQuotientMap.isClosed_preimage] convert ProperSMul.isProperMap_smul_pair.isClosedMap.isClosed_range · ext ⟨x₁, x₂⟩ simp only [mem_preimage, map_apply, mem_diagonal_iff, mem_range, Prod.mk.injEq, Prod.exists, exists_eq_right] - rw [Quotient.eq_rel, MulAction.orbitRel_apply, MulAction.mem_orbit_iff] + rw [Quotient.eq', MulAction.orbitRel_apply, MulAction.mem_orbit_iff] all_goals infer_instance /-- If a T2 group acts properly on a topological space, then this topological space is T2. -/ @@ -145,12 +127,10 @@ then this topological space is T2."] theorem t2Space_of_properSMul_of_t2Group [h_proper : ProperSMul G X] [T2Space G] : T2Space X := by let f := fun x : X ↦ ((1 : G), x) have proper_f : IsProperMap f := by - apply isProperMap_of_closedEmbedding - rw [closedEmbedding_iff] - constructor + refine IsClosedEmbedding.isProperMap ⟨?_, ?_⟩ · let g := fun gx : G × X ↦ gx.2 have : Function.LeftInverse g f := fun x ↦ by simp - exact this.embedding (by fun_prop) (by fun_prop) + exact this.isEmbedding (by fun_prop) (by fun_prop) · have : range f = ({1} ×ˢ univ) := by simp rw [this] exact isClosed_singleton.prod isClosed_univ @@ -168,109 +148,20 @@ then `H` also acts properly on `X`. -/ @[to_additive "If two groups `H` and `G` act on a topological space `X` such that `G` acts properly and there exists a group homomorphims `H → G` which is a closed embedding compatible with the actions, then `H` also acts properly on `X`."] -theorem properSMul_of_closedEmbedding {H : Type*} [Group H] [MulAction H X] [TopologicalSpace H] - [ProperSMul G X] (f : H →* G) (f_clemb : ClosedEmbedding f) +theorem properSMul_of_isClosedEmbedding {H : Type*} [Group H] [MulAction H X] [TopologicalSpace H] + [ProperSMul G X] (f : H →* G) (f_clemb : IsClosedEmbedding f) (f_compat : ∀ (h : H) (x : X), f h • x = h • x) : ProperSMul H X where isProperMap_smul_pair := by - have := isProperMap_of_closedEmbedding f_clemb - have h : IsProperMap (Prod.map f (fun x : X ↦ x)) := this.prodMap isProperMap_id + have h : IsProperMap (Prod.map f (fun x : X ↦ x)) := f_clemb.isProperMap.prodMap isProperMap_id have : (fun hx : H × X ↦ (hx.1 • hx.2, hx.2)) = (fun hx ↦ (f hx.1 • hx.2, hx.2)) := by simp [f_compat] rw [this] exact h.comp <| ProperSMul.isProperMap_smul_pair +@[deprecated (since := "2024-10-20")] +alias properSMul_of_closedEmbedding := properSMul_of_isClosedEmbedding + /-- If `H` is a closed subgroup of `G` and `G` acts properly on X then so does `H`. -/ @[to_additive "If `H` is a closed subgroup of `G` and `G` acts properly on X then so does `H`."] instance {H : Subgroup G} [ProperSMul G X] [H_closed : IsClosed (H : Set G)] : ProperSMul H X := - properSMul_of_closedEmbedding H.subtype H_closed.closedEmbedding_subtype_val fun _ _ ↦ rfl - -/-- If a discrete group acts on a T2 space `X` such that `X × X` is compactly generated, -then the action is properly discontinuous if and only if it is continuous in the second variable -and proper. -/ -theorem properlyDiscontinuousSMul_iff_properSMul [T2Space X] [DiscreteTopology G] - [ContinuousConstSMul G X] - (compactlyGenerated : ∀ s : Set (X × X), IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K)) : - ProperlyDiscontinuousSMul G X ↔ ProperSMul G X := by - constructor - · intro h - rw [properSMul_iff] - -- We have to show that `f : (g, x) ↦ (g • x, x)` is proper. - -- Continuity follows from continuity of `g • ·` and the fact that `G` has the - -- discrete topology, thanks to `continuous_of_partial_of_discrete`. - -- Because `X × X` is compactly generated, to show that f is proper - -- it is enough to show that the preimage of a compact set `K` is compact. - refine (isProperMap_iff_isCompact_preimage compactlyGenerated).2 - ⟨(continuous_prod_mk.2 - ⟨continuous_prod_of_discrete_left.2 continuous_const_smul, by fun_prop⟩), - fun K hK ↦ ?_⟩ - -- We set `K' := pr₁(K) ∪ pr₂(K)`, which is compact because `K` is compact and `pr₁` and - -- `pr₂` are continuous. We halso have that `K ⊆ K' × K'`, and `K` is closed because `X` is T2. - -- Therefore `f ⁻¹ (K)` is also closed and `f ⁻¹ (K) ⊆ f ⁻¹ (K' × K')`, thus it suffices to - -- show that `f ⁻¹ (K' × K')` is compact. - let K' := fst '' K ∪ snd '' K - have hK' : IsCompact K' := (hK.image continuous_fst).union (hK.image continuous_snd) - let E := {g : G | Set.Nonempty ((g • ·) '' K' ∩ K')} - -- The set `E` is finite because the action is properly discontinuous. - have fin : Set.Finite E := by - simp_rw [E, nonempty_iff_ne_empty] - exact h.finite_disjoint_inter_image hK' hK' - -- Therefore we can rewrite `f ⁻¹ (K' × K')` as a finite union of compact sets. - have : (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) ⁻¹' (K' ×ˢ K') = - ⋃ g ∈ E, {g} ×ˢ ((g⁻¹ • ·) '' K' ∩ K') := by - ext gx - simp only [mem_preimage, mem_prod, nonempty_def, mem_inter_iff, mem_image, - exists_exists_and_eq_and, mem_setOf_eq, singleton_prod, iUnion_exists, biUnion_and', - mem_iUnion, exists_prop, E] - constructor - · exact fun ⟨gx_mem, x_mem⟩ ↦ ⟨gx.2, x_mem, gx.1, gx_mem, - ⟨gx.2, ⟨⟨gx.1 • gx.2, gx_mem, by simp⟩, x_mem⟩, rfl⟩⟩ - · rintro ⟨x, -, g, -, ⟨-, ⟨⟨x', x'_mem, rfl⟩, ginvx'_mem⟩, rfl⟩⟩ - exact ⟨by simpa, by simpa⟩ - -- Indeed each set in this finite union is the product of a singleton and - -- the intersection of the compact `K'` with its image by some element `g`, and this image is - -- compact because `g • ·` is continuous. - have : IsCompact ((fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) ⁻¹' (K' ×ˢ K')) := - this ▸ fin.isCompact_biUnion fun g hg ↦ - isCompact_singleton.prod <| (hK'.image <| continuous_const_smul _).inter hK' - -- We conclude as explained above. - exact this.of_isClosed_subset (hK.isClosed.preimage <| - continuous_prod_mk.2 - ⟨continuous_prod_of_discrete_left.2 continuous_const_smul, by fun_prop⟩) <| - preimage_mono fun x hx ↦ ⟨Or.inl ⟨x, hx, rfl⟩, Or.inr ⟨x, hx, rfl⟩⟩ - · intro h; constructor - intro K L hK hL - simp_rw [← nonempty_iff_ne_empty] - -- We want to show that a subset of `G` is finite, but as `G` has the discrete topology it - -- is enough to show that this subset is compact. - apply IsCompact.finite_of_discrete - -- Now set `h : (g, x) ↦ (g⁻¹ • x, x)`, because `f` is proper by hypothesis, so is `h`. - have : IsProperMap (fun gx : G × X ↦ (gx.1⁻¹ • gx.2, gx.2)) := - (IsProperMap.prodMap (Homeomorph.isProperMap (Homeomorph.inv G)) isProperMap_id).comp <| - ProperSMul.isProperMap_smul_pair - --But we also have that `{g | Set.Nonempty ((g • ·) '' K ∩ L)} = h ⁻¹ (K × L)`, which - -- concludes the proof. - have eq : {g | Set.Nonempty ((g • ·) '' K ∩ L)} = - fst '' ((fun gx : G × X ↦ (gx.1⁻¹ • gx.2, gx.2)) ⁻¹' (K ×ˢ L)) := by - simp_rw [nonempty_def] - ext g; constructor - · exact fun ⟨_, ⟨x, x_mem, rfl⟩, hx⟩ ↦ ⟨(g, g • x), ⟨by simpa, hx⟩, rfl⟩ - · rintro ⟨gx, hgx, rfl⟩ - exact ⟨gx.2, ⟨gx.1⁻¹ • gx.2, hgx.1, by simp⟩, hgx.2⟩ - exact eq ▸ IsCompact.image (this.isCompact_preimage <| hK.prod hL) continuous_fst - -/-- If a discrete group acts on a T2 and locally compact space `X`, -then the action is properly discontinuous if and only if it is continuous in the second variable -and proper. -/ -theorem WeaklyLocallyCompactSpace.properlyDiscontinuousSMul_iff_properSMul [T2Space X] - [WeaklyLocallyCompactSpace X] [DiscreteTopology G] [ContinuousConstSMul G X] : - ProperlyDiscontinuousSMul G X ↔ ProperSMul G X := - _root_.properlyDiscontinuousSMul_iff_properSMul - (fun _ ↦ compactlyGenerated_of_weaklyLocallyCompactSpace) - -/-- If a discrete group acts on a T2 and first-countable space `X`, -then the action is properly discontinuous if and only if it is continuous in the second variable -and proper. -/ -theorem FirstCountableTopology.properlyDiscontinuousSMul_iff_properSMul [T2Space X] - [FirstCountableTopology X] [DiscreteTopology G] [ContinuousConstSMul G X] : - ProperlyDiscontinuousSMul G X ↔ ProperSMul G X := - _root_.properlyDiscontinuousSMul_iff_properSMul (fun _ ↦ compactlyGenerated_of_sequentialSpace) + properSMul_of_isClosedEmbedding H.subtype H_closed.isClosedEmbedding_subtypeVal fun _ _ ↦ rfl diff --git a/Mathlib/Topology/Algebra/ProperAction/ProperlyDiscontinuous.lean b/Mathlib/Topology/Algebra/ProperAction/ProperlyDiscontinuous.lean new file mode 100644 index 0000000000000..72185f7fb509a --- /dev/null +++ b/Mathlib/Topology/Algebra/ProperAction/ProperlyDiscontinuous.lean @@ -0,0 +1,106 @@ +/- +Copyright (c) 2024 Anatole Dedeker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Etienne Marion +-/ +import Mathlib.Topology.Algebra.ProperAction.Basic +import Mathlib.Topology.Maps.Proper.CompactlyGenerated + +/-! +# When a proper action is properly discontinuous + +This file proves that if a discrete group acts on a T2 space `X` such that `X × X` is compactly +generated, and if the action is continuous in the second variable, then the action is properly +discontinuous if and only if it is proper. This is in particular true if `X` is first-countable or +weakly locally compact. + +## Main statement +* `properlyDiscontinuousSMul_iff_properSMul`: If a discrete group acts on a T2 space `X` such that + `X × X` is compactly generated, and if the action is continuous in the second variable, + then the action is properly discontinuous if and only if it is proper. + +## Tags + +grouup action, proper action, properly discontinuous, compactly generated +-/ + +variable {G X : Type*} [Group G] [MulAction G X] [TopologicalSpace G] [TopologicalSpace X] + +open Prod Set + +/-- If a discrete group acts on a T2 space `X` such that `X × X` is compactly +generated, and if the action is continuous in the second variable, then the action is properly +discontinuous if and only if it is proper. This is in particular true if `X` is first-countable or +weakly locally compact. + +There was an older version of this theorem which was changed to this one to make use +of the `CompactlyGeneratedSpace` typeclass. (since 2024-11-10) -/ +theorem properlyDiscontinuousSMul_iff_properSMul [T2Space X] [DiscreteTopology G] + [ContinuousConstSMul G X] [CompactlyGeneratedSpace (X × X)] : + ProperlyDiscontinuousSMul G X ↔ ProperSMul G X := by + constructor + · intro h + rw [properSMul_iff] + -- We have to show that `f : (g, x) ↦ (g • x, x)` is proper. + -- Continuity follows from continuity of `g • ·` and the fact that `G` has the + -- discrete topology, thanks to `continuous_of_partial_of_discrete`. + -- Because `X × X` is compactly generated, to show that f is proper + -- it is enough to show that the preimage of a compact set `K` is compact. + refine isProperMap_iff_isCompact_preimage.2 + ⟨(continuous_prod_mk.2 + ⟨continuous_prod_of_discrete_left.2 continuous_const_smul, by fun_prop⟩), + fun K hK ↦ ?_⟩ + -- We set `K' := pr₁(K) ∪ pr₂(K)`, which is compact because `K` is compact and `pr₁` and + -- `pr₂` are continuous. We halso have that `K ⊆ K' × K'`, and `K` is closed because `X` is T2. + -- Therefore `f ⁻¹ (K)` is also closed and `f ⁻¹ (K) ⊆ f ⁻¹ (K' × K')`, thus it suffices to + -- show that `f ⁻¹ (K' × K')` is compact. + let K' := fst '' K ∪ snd '' K + have hK' : IsCompact K' := (hK.image continuous_fst).union (hK.image continuous_snd) + let E := {g : G | Set.Nonempty ((g • ·) '' K' ∩ K')} + -- The set `E` is finite because the action is properly discontinuous. + have fin : Set.Finite E := by + simp_rw [E, nonempty_iff_ne_empty] + exact h.finite_disjoint_inter_image hK' hK' + -- Therefore we can rewrite `f ⁻¹ (K' × K')` as a finite union of compact sets. + have : (fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) ⁻¹' (K' ×ˢ K') = + ⋃ g ∈ E, {g} ×ˢ ((g⁻¹ • ·) '' K' ∩ K') := by + ext gx + simp only [mem_preimage, mem_prod, nonempty_def, mem_inter_iff, mem_image, + exists_exists_and_eq_and, mem_setOf_eq, singleton_prod, iUnion_exists, biUnion_and', + mem_iUnion, exists_prop, E] + constructor + · exact fun ⟨gx_mem, x_mem⟩ ↦ ⟨gx.2, x_mem, gx.1, gx_mem, + ⟨gx.2, ⟨⟨gx.1 • gx.2, gx_mem, by simp⟩, x_mem⟩, rfl⟩⟩ + · rintro ⟨x, -, g, -, ⟨-, ⟨⟨x', x'_mem, rfl⟩, ginvx'_mem⟩, rfl⟩⟩ + exact ⟨by simpa, by simpa⟩ + -- Indeed each set in this finite union is the product of a singleton and + -- the intersection of the compact `K'` with its image by some element `g`, and this image is + -- compact because `g • ·` is continuous. + have : IsCompact ((fun gx : G × X ↦ (gx.1 • gx.2, gx.2)) ⁻¹' (K' ×ˢ K')) := + this ▸ fin.isCompact_biUnion fun g hg ↦ + isCompact_singleton.prod <| (hK'.image <| continuous_const_smul _).inter hK' + -- We conclude as explained above. + exact this.of_isClosed_subset (hK.isClosed.preimage <| + continuous_prod_mk.2 + ⟨continuous_prod_of_discrete_left.2 continuous_const_smul, by fun_prop⟩) <| + preimage_mono fun x hx ↦ ⟨Or.inl ⟨x, hx, rfl⟩, Or.inr ⟨x, hx, rfl⟩⟩ + · intro h; constructor + intro K L hK hL + simp_rw [← nonempty_iff_ne_empty] + -- We want to show that a subset of `G` is finite, but as `G` has the discrete topology it + -- is enough to show that this subset is compact. + apply IsCompact.finite_of_discrete + -- Now set `h : (g, x) ↦ (g⁻¹ • x, x)`, because `f` is proper by hypothesis, so is `h`. + have : IsProperMap (fun gx : G × X ↦ (gx.1⁻¹ • gx.2, gx.2)) := + (IsProperMap.prodMap (Homeomorph.isProperMap (Homeomorph.inv G)) isProperMap_id).comp <| + ProperSMul.isProperMap_smul_pair + --But we also have that `{g | Set.Nonempty ((g • ·) '' K ∩ L)} = h ⁻¹ (K × L)`, which + -- concludes the proof. + have eq : {g | Set.Nonempty ((g • ·) '' K ∩ L)} = + fst '' ((fun gx : G × X ↦ (gx.1⁻¹ • gx.2, gx.2)) ⁻¹' (K ×ˢ L)) := by + simp_rw [nonempty_def] + ext g; constructor + · exact fun ⟨_, ⟨x, x_mem, rfl⟩, hx⟩ ↦ ⟨(g, g • x), ⟨by simpa, hx⟩, rfl⟩ + · rintro ⟨gx, hgx, rfl⟩ + exact ⟨gx.2, ⟨gx.1⁻¹ • gx.2, hgx.1, by simp⟩, hgx.2⟩ + exact eq ▸ IsCompact.image (this.isCompact_preimage <| hK.prod hL) continuous_fst diff --git a/Mathlib/Topology/Algebra/Ring/Basic.lean b/Mathlib/Topology/Algebra/Ring/Basic.lean index 94cf82277f373..5376e1e26055f 100644 --- a/Mathlib/Topology/Algebra/Ring/Basic.lean +++ b/Mathlib/Topology/Algebra/Ring/Basic.lean @@ -164,7 +164,7 @@ instance [NonUnitalNonAssocSemiring α] [TopologicalSpace α] [TopologicalSemiri TopologicalSemiring αᵐᵒᵖ := ⟨⟩ instance [NonUnitalNonAssocRing α] [TopologicalSpace α] [ContinuousNeg α] : ContinuousNeg αᵐᵒᵖ := - opHomeomorph.symm.inducing.continuousNeg fun _ => rfl + opHomeomorph.symm.isInducing.continuousNeg fun _ => rfl instance [NonUnitalNonAssocRing α] [TopologicalSpace α] [TopologicalRing α] : TopologicalRing αᵐᵒᵖ := ⟨⟩ diff --git a/Mathlib/Topology/Algebra/Ring/Ideal.lean b/Mathlib/Topology/Algebra/Ring/Ideal.lean index aa3cf06eb57a1..b6224bda75b37 100644 --- a/Mathlib/Topology/Algebra/Ring/Ideal.lean +++ b/Mathlib/Topology/Algebra/Ring/Ideal.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot -/ import Mathlib.Topology.Algebra.Ring.Basic -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.Topology.Algebra.Group.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Defs /-! # Ideals and quotients of topological rings @@ -57,12 +58,15 @@ theorem QuotientRing.isOpenMap_coe : IsOpenMap (mk N) := theorem QuotientRing.isOpenQuotientMap_mk : IsOpenQuotientMap (mk N) := QuotientAddGroup.isOpenQuotientMap_mk -theorem QuotientRing.quotientMap_coe_coe : QuotientMap fun p : R × R => (mk N p.1, mk N p.2) := - ((isOpenQuotientMap_mk N).prodMap (isOpenQuotientMap_mk N)).quotientMap +theorem QuotientRing.isQuotientMap_coe_coe : IsQuotientMap fun p : R × R => (mk N p.1, mk N p.2) := + ((isOpenQuotientMap_mk N).prodMap (isOpenQuotientMap_mk N)).isQuotientMap + +@[deprecated (since := "2024-10-22")] +alias QuotientRing.quotientMap_coe_coe := QuotientRing.isQuotientMap_coe_coe instance topologicalRing_quotient : TopologicalRing (R ⧸ N) where __ := QuotientAddGroup.instTopologicalAddGroup _ - continuous_mul := (QuotientRing.quotientMap_coe_coe N).continuous_iff.2 <| + continuous_mul := (QuotientRing.isQuotientMap_coe_coe N).continuous_iff.2 <| continuous_quot_mk.comp continuous_mul end CommRing diff --git a/Mathlib/Topology/Algebra/Semigroup.lean b/Mathlib/Topology/Algebra/Semigroup.lean index 9069ed9f766ed..327643f2aa4c3 100644 --- a/Mathlib/Topology/Algebra/Semigroup.lean +++ b/Mathlib/Topology/Algebra/Semigroup.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 David Wärn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Wärn -/ -import Mathlib.Topology.Separation import Mathlib.Algebra.Group.Defs +import Mathlib.Topology.Separation.Basic /-! # Idempotents in topological semigroups diff --git a/Mathlib/Topology/Algebra/SeparationQuotient.lean b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean similarity index 80% rename from Mathlib/Topology/Algebra/SeparationQuotient.lean rename to Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean index 070cdf516d506..1f2427e29b56f 100644 --- a/Mathlib/Topology/Algebra/SeparationQuotient.lean +++ b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean @@ -3,9 +3,7 @@ Copyright (c) 2024 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.Topology.Algebra.Module.Basic -import Mathlib.Topology.Maps.OpenQuotient /-! # Algebraic operations on `SeparationQuotient` @@ -21,6 +19,8 @@ Finally, we construct a section of the quotient map which is a continuous linear map `SeparationQuotient E →L[K] E`. -/ +assert_not_exists LinearIndependent + namespace SeparationQuotient section SMul @@ -36,7 +36,7 @@ theorem mk_smul (c : M) (x : X) : mk (c • x) = c • mk x := rfl @[to_additive] instance instContinuousConstSMul : ContinuousConstSMul M (SeparationQuotient X) where - continuous_const_smul c := quotientMap_mk.continuous_iff.2 <| + continuous_const_smul c := isQuotientMap_mk.continuous_iff.2 <| continuous_mk.comp <| continuous_const_smul c @[to_additive] @@ -67,7 +67,7 @@ end SMul instance instContinuousSMul {M X : Type*} [SMul M X] [TopologicalSpace M] [TopologicalSpace X] [ContinuousSMul M X] : ContinuousSMul M (SeparationQuotient X) where continuous_smul := by - rw [(IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).quotientMap.continuous_iff] + rw [(IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).isQuotientMap.continuous_iff] exact continuous_mk.comp continuous_smul instance instSMulZeroClass {M X : Type*} [Zero X] [SMulZeroClass M X] [TopologicalSpace X] @@ -93,7 +93,7 @@ theorem mk_mul [Mul M] [ContinuousMul M] (a b : M) : mk (a * b) = mk a * mk b := @[to_additive] instance instContinuousMul [Mul M] [ContinuousMul M] : ContinuousMul (SeparationQuotient M) where - continuous_mul := quotientMap_prodMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_mul + continuous_mul := isQuotientMap_prodMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_mul @[to_additive] instance instCommMagma [CommMagma M] [ContinuousMul M] : CommMagma (SeparationQuotient M) := @@ -154,7 +154,7 @@ theorem mk_inv [Inv G] [ContinuousInv G] (x : G) : mk x⁻¹ = (mk x)⁻¹ := rf @[to_additive] instance instContinuousInv [Inv G] [ContinuousInv G] : ContinuousInv (SeparationQuotient G) where - continuous_inv := quotientMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_inv + continuous_inv := isQuotientMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_inv @[to_additive] instance instInvolutiveInv [InvolutiveInv G] [ContinuousInv G] : @@ -175,7 +175,7 @@ theorem mk_div [Div G] [ContinuousDiv G] (x y : G) : mk (x / y) = mk x / mk y := @[to_additive] instance instContinuousDiv [Div G] [ContinuousDiv G] : ContinuousDiv (SeparationQuotient G) where - continuous_div' := quotientMap_prodMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_div' + continuous_div' := isQuotientMap_prodMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_div' instance instZSMul [AddGroup G] [TopologicalAddGroup G] : SMul ℤ (SeparationQuotient G) := inferInstance @@ -333,6 +333,12 @@ instance instCommRing [CommRing R] [TopologicalRing R] : surjective_mk.commRing mk mk_zero mk_one mk_add mk_mul mk_neg mk_sub mk_smul mk_smul mk_pow mk_natCast mk_intCast +/-- `SeparationQuotient.mk` as a `RingHom`. -/ +@[simps] +def mkRingHom [NonAssocSemiring R] [TopologicalSemiring R] : R →+* SeparationQuotient R where + toFun := mk + map_one' := mk_one; map_zero' := mk_zero; map_add' := mk_add; map_mul' := mk_mul + end Ring section DistribSMul @@ -375,76 +381,19 @@ def mkCLM : M →L[R] SeparationQuotient M where end Module -section VectorSpace - -variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] - [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousConstSMul K E] - -/-- There exists a continuous `K`-linear map from `SeparationQuotient E` to `E` -such that `mk (outCLM x) = x` for all `x`. +section Algebra +variable {R A : Type*} [CommSemiring R] [Semiring A] [Algebra R A] + [TopologicalSpace A] [TopologicalSemiring A] [ContinuousConstSMul R A] -Note that continuity of this map comes for free, because `mk` is a topology inducing map. --/ -theorem exists_out_continuousLinearMap : - ∃ f : SeparationQuotient E →L[K] E, mkCLM K E ∘L f = .id K (SeparationQuotient E) := by - rcases (mkCLM K E).toLinearMap.exists_rightInverse_of_surjective - (LinearMap.range_eq_top.mpr surjective_mk) with ⟨f, hf⟩ - replace hf : mk ∘ f = id := congr_arg DFunLike.coe hf - exact ⟨⟨f, inducing_mk.continuous_iff.2 (by continuity)⟩, DFunLike.ext' hf⟩ - -/-- A continuous `K`-linear map from `SeparationQuotient E` to `E` -such that `mk (outCLM x) = x` for all `x`. -/ -noncomputable def outCLM : SeparationQuotient E →L[K] E := - (exists_out_continuousLinearMap K E).choose - -@[simp] -theorem mkCLM_comp_outCLM : mkCLM K E ∘L outCLM K E = .id K (SeparationQuotient E) := - (exists_out_continuousLinearMap K E).choose_spec - -variable {E} in -@[simp] -theorem mk_outCLM (x : SeparationQuotient E) : mk (outCLM K E x) = x := - DFunLike.congr_fun (mkCLM_comp_outCLM K E) x +instance instAlgebra : Algebra R (SeparationQuotient A) where + toRingHom := mkRingHom.comp (algebraMap R A) + commutes' r := Quotient.ind fun a => congrArg _ <| Algebra.commutes r a + smul_def' r := Quotient.ind fun a => congrArg _ <| Algebra.smul_def r a @[simp] -theorem mk_comp_outCLM : mk ∘ outCLM K E = id := funext (mk_outCLM K) - -variable {K} in -theorem postcomp_mkCLM_surjective {L : Type*} [Semiring L] (σ : L →+* K) - (F : Type*) [AddCommMonoid F] [Module L F] [TopologicalSpace F] : - Function.Surjective ((mkCLM K E).comp : (F →SL[σ] E) → (F →SL[σ] SeparationQuotient E)) := by - intro f - use (outCLM K E).comp f - rw [← ContinuousLinearMap.comp_assoc, mkCLM_comp_outCLM, ContinuousLinearMap.id_comp] - -/-- The `SeparationQuotient.outCLM K E` map is a topological embedding. -/ -theorem outCLM_embedding : Embedding (outCLM K E) := - Function.LeftInverse.embedding (mk_outCLM K) continuous_mk (map_continuous _) - -theorem outCLM_injective : Function.Injective (outCLM K E) := - (outCLM_embedding K E).injective - -end VectorSpace - -section VectorSpaceUniform - -variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] - [UniformSpace E] [UniformAddGroup E] [ContinuousConstSMul K E] - -theorem outCLM_uniformInducing : UniformInducing (outCLM K E) := by - rw [← uniformInducing_mk.uniformInducing_comp_iff, mk_comp_outCLM] - exact uniformInducing_id - -theorem outCLM_isUniformEmbedding : IsUniformEmbedding (outCLM K E) where - inj := outCLM_injective K E - toUniformInducing := outCLM_uniformInducing K E - -@[deprecated (since := "2024-10-01")] -alias outCLM_uniformEmbedding := outCLM_isUniformEmbedding - -theorem outCLM_uniformContinuous : UniformContinuous (outCLM K E) := - (outCLM_uniformInducing K E).uniformContinuous +theorem mk_algebraMap (r : R) : mk (algebraMap R A r) = algebraMap R (SeparationQuotient A) r := + rfl -end VectorSpaceUniform +end Algebra end SeparationQuotient diff --git a/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean b/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean new file mode 100644 index 0000000000000..6f092da76b987 --- /dev/null +++ b/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean @@ -0,0 +1,96 @@ +/- +Copyright (c) 2024 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import Mathlib.Algebra.Module.Projective +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.Topology.Algebra.SeparationQuotient.Basic +import Mathlib.Topology.Maps.OpenQuotient + +/-! +# Algebraic operations on `SeparationQuotient` + +In this file we construct a section of the quotient map `E → SeparationQuotient E` as a continuous +linear map `SeparationQuotient E →L[K] E`. +-/ + +namespace SeparationQuotient +section VectorSpace + +variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] + [TopologicalSpace E] [TopologicalAddGroup E] [ContinuousConstSMul K E] + +/-- There exists a continuous `K`-linear map from `SeparationQuotient E` to `E` +such that `mk (outCLM x) = x` for all `x`. + +Note that continuity of this map comes for free, because `mk` is a topology inducing map. +-/ +theorem exists_out_continuousLinearMap : + ∃ f : SeparationQuotient E →L[K] E, mkCLM K E ∘L f = .id K (SeparationQuotient E) := by + rcases (mkCLM K E).toLinearMap.exists_rightInverse_of_surjective + (LinearMap.range_eq_top.mpr surjective_mk) with ⟨f, hf⟩ + replace hf : mk ∘ f = id := congr_arg DFunLike.coe hf + exact ⟨⟨f, isInducing_mk.continuous_iff.2 (by continuity)⟩, DFunLike.ext' hf⟩ + +/-- A continuous `K`-linear map from `SeparationQuotient E` to `E` +such that `mk (outCLM x) = x` for all `x`. -/ +noncomputable def outCLM : SeparationQuotient E →L[K] E := + (exists_out_continuousLinearMap K E).choose + +@[simp] +theorem mkCLM_comp_outCLM : mkCLM K E ∘L outCLM K E = .id K (SeparationQuotient E) := + (exists_out_continuousLinearMap K E).choose_spec + +variable {E} in +@[simp] +theorem mk_outCLM (x : SeparationQuotient E) : mk (outCLM K E x) = x := + DFunLike.congr_fun (mkCLM_comp_outCLM K E) x + +@[simp] +theorem mk_comp_outCLM : mk ∘ outCLM K E = id := funext (mk_outCLM K) + +variable {K} in +theorem postcomp_mkCLM_surjective {L : Type*} [Semiring L] (σ : L →+* K) + (F : Type*) [AddCommMonoid F] [Module L F] [TopologicalSpace F] : + Function.Surjective ((mkCLM K E).comp : (F →SL[σ] E) → (F →SL[σ] SeparationQuotient E)) := by + intro f + use (outCLM K E).comp f + rw [← ContinuousLinearMap.comp_assoc, mkCLM_comp_outCLM, ContinuousLinearMap.id_comp] + +/-- The `SeparationQuotient.outCLM K E` map is a topological embedding. -/ +theorem isEmbedding_outCLM : IsEmbedding (outCLM K E) := + Function.LeftInverse.isEmbedding (mk_outCLM K) continuous_mk (map_continuous _) + +@[deprecated (since := "2024-10-26")] +alias outCLM_embedding := isEmbedding_outCLM + +theorem outCLM_injective : Function.Injective (outCLM K E) := + (isEmbedding_outCLM K E).injective + +end VectorSpace + +section VectorSpaceUniform + +variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] + [UniformSpace E] [UniformAddGroup E] [ContinuousConstSMul K E] + +theorem outCLM_isUniformInducing : IsUniformInducing (outCLM K E) := by + rw [← isUniformInducing_mk.isUniformInducing_comp_iff, mk_comp_outCLM] + exact .id + +@[deprecated (since := "2024-10-05")] +alias outCLM_uniformInducing := outCLM_isUniformInducing + +theorem outCLM_isUniformEmbedding : IsUniformEmbedding (outCLM K E) where + inj := outCLM_injective K E + toIsUniformInducing := outCLM_isUniformInducing K E + +@[deprecated (since := "2024-10-01")] +alias outCLM_uniformEmbedding := outCLM_isUniformEmbedding + +theorem outCLM_uniformContinuous : UniformContinuous (outCLM K E) := + (outCLM_isUniformInducing K E).uniformContinuous + +end VectorSpaceUniform +end SeparationQuotient diff --git a/Mathlib/Topology/Algebra/Star.lean b/Mathlib/Topology/Algebra/Star.lean index abbca7eae5b32..88af814e80c6e 100644 --- a/Mathlib/Topology/Algebra/Star.lean +++ b/Mathlib/Topology/Algebra/Star.lean @@ -6,7 +6,7 @@ Authors: Eric Wieser import Mathlib.Algebra.Star.Pi import Mathlib.Algebra.Star.Prod import Mathlib.Topology.Algebra.Constructions -import Mathlib.Topology.ContinuousMap.Basic +import Mathlib.Topology.ContinuousMap.Defs /-! # Continuity of `star` diff --git a/Mathlib/Topology/Algebra/StarSubalgebra.lean b/Mathlib/Topology/Algebra/StarSubalgebra.lean index 0703fc4753013..aa060d9b1f6f7 100644 --- a/Mathlib/Topology/Algebra/StarSubalgebra.lean +++ b/Mathlib/Topology/Algebra/StarSubalgebra.lean @@ -33,14 +33,18 @@ instance [TopologicalSemiring A] (s : StarSubalgebra R A) : TopologicalSemiring s.toSubalgebra.topologicalSemiring /-- The `StarSubalgebra.inclusion` of a star subalgebra is an `Embedding`. -/ -theorem embedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ S₂) : Embedding (inclusion h) := - { induced := Eq.symm induced_compose - inj := Subtype.map_injective h Function.injective_id } - -/-- The `StarSubalgebra.inclusion` of a closed star subalgebra is a `ClosedEmbedding`. -/ -theorem closedEmbedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ S₂) - (hS₁ : IsClosed (S₁ : Set A)) : ClosedEmbedding (inclusion h) := - { embedding_inclusion h with +lemma isEmbedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ S₂) : + IsEmbedding (inclusion h) where + eq_induced := Eq.symm induced_compose + inj := Subtype.map_injective h Function.injective_id + +@[deprecated (since := "2024-10-26")] +alias embedding_inclusion := isEmbedding_inclusion + +/-- The `StarSubalgebra.inclusion` of a closed star subalgebra is a `IsClosedEmbedding`. -/ +theorem isClosedEmbedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ S₂) + (hS₁ : IsClosed (S₁ : Set A)) : IsClosedEmbedding (inclusion h) := + { IsEmbedding.inclusion h with isClosed_range := isClosed_induced_iff.2 ⟨S₁, hS₁, by convert (Set.range_subtype_map id _).symm @@ -48,6 +52,9 @@ theorem closedEmbedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ · intro _ h' apply h h' ⟩ } +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_inclusion := isClosedEmbedding_inclusion + variable [TopologicalSemiring A] [ContinuousStar A] variable [TopologicalSpace B] [Semiring B] [Algebra R B] [StarRing B] @@ -99,7 +106,7 @@ theorem map_topologicalClosure_le [StarModule R B] [TopologicalSemiring B] [Cont image_closure_subset_closure_image hφ theorem topologicalClosure_map [StarModule R B] [TopologicalSemiring B] [ContinuousStar B] - (s : StarSubalgebra R A) (φ : A →⋆ₐ[R] B) (hφ : ClosedEmbedding φ) : + (s : StarSubalgebra R A) (φ : A →⋆ₐ[R] B) (hφ : IsClosedEmbedding φ) : (map φ s).topologicalClosure = map φ s.topologicalClosure := SetLike.coe_injective <| hφ.closure_image_eq _ @@ -132,7 +139,7 @@ theorem _root_.StarAlgHom.ext_topologicalClosure [T2Space B] {S : StarSubalgebra φ = ψ := by rw [DFunLike.ext'_iff] have : Dense (Set.range <| inclusion (le_topologicalClosure S)) := by - refine embedding_subtype_val.toInducing.dense_iff.2 fun x => ?_ + refine IsInducing.subtypeVal.dense_iff.2 fun x => ?_ convert show ↑x ∈ closure (S : Set A) from x.prop rw [← Set.range_comp] exact @@ -205,9 +212,9 @@ theorem le_of_isClosed_of_mem {S : StarSubalgebra R A} (hS : IsClosed (S : Set A (hx : x ∈ S) : elementalStarAlgebra R x ≤ S := topologicalClosure_minimal (adjoin_le <| Set.singleton_subset_iff.2 hx) hS -/-- The coercion from an elemental algebra to the full algebra as a `ClosedEmbedding`. -/ -theorem closedEmbedding_coe (x : A) : ClosedEmbedding ((↑) : elementalStarAlgebra R x → A) := - { induced := rfl +/-- The coercion from an elemental algebra to the full algebra as a `IsClosedEmbedding`. -/ +theorem isClosedEmbedding_coe (x : A) : IsClosedEmbedding ((↑) : elementalStarAlgebra R x → A) := + { eq_induced := rfl inj := Subtype.coe_injective isClosed_range := by convert isClosed R x @@ -217,6 +224,9 @@ theorem closedEmbedding_coe (x : A) : ClosedEmbedding ((↑) : elementalStarAlge rintro ⟨y, rfl⟩ exact y.prop, fun hy => ⟨⟨y, hy⟩, rfl⟩⟩ } +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_coe := isClosedEmbedding_coe + @[elab_as_elim] theorem induction_on {x y : A} (hy : y ∈ elementalStarAlgebra R x) {P : (u : A) → u ∈ elementalStarAlgebra R x → Prop} @@ -229,27 +239,24 @@ theorem induction_on {x y : A} P y hy := by apply closure (adjoin R {x} : Set A) subset_closure (fun y hy ↦ ?_) y hy rw [SetLike.mem_coe, ← mem_toSubalgebra, adjoin_toSubalgebra] at hy - induction hy using Algebra.adjoin_induction'' with + induction hy using Algebra.adjoin_induction with | mem u hu => obtain ((rfl : u = x) | (hu : star u = x)) := by simpa using hu · exact self · simp_rw [← hu, star_star] at star_self exact star_self | algebraMap r => exact algebraMap r - | add u hu_mem v hv_mem hu hv => + | add u v hu_mem hv_mem hu hv => exact add u (subset_closure hu_mem) v (subset_closure hv_mem) (hu hu_mem) (hv hv_mem) - | mul u hu_mem v hv_mem hu hv => + | mul u v hu_mem hv_mem hu hv => exact mul u (subset_closure hu_mem) v (subset_closure hv_mem) (hu hu_mem) (hv hv_mem) theorem starAlgHomClass_ext [T2Space B] {F : Type*} {a : A} [FunLike F (elementalStarAlgebra R a) B] [AlgHomClass F R _ B] [StarHomClass F _ B] {φ ψ : F} (hφ : Continuous φ) (hψ : Continuous ψ) (h : φ ⟨a, self_mem R a⟩ = ψ ⟨a, self_mem R a⟩) : φ = ψ := by - -- Note: help with unfolding `elementalStarAlgebra` - have : StarHomClass F (↥(topologicalClosure (adjoin R {a}))) B := - inferInstanceAs (StarHomClass F (elementalStarAlgebra R a) B) refine StarAlgHomClass.ext_topologicalClosure hφ hψ fun x => ?_ - refine adjoin_induction' x ?_ ?_ ?_ ?_ ?_ + refine adjoin_induction_subtype x ?_ ?_ ?_ ?_ ?_ exacts [fun y hy => by simpa only [Set.mem_singleton_iff.mp hy] using h, fun r => by simp only [AlgHomClass.commutes], fun x y hx hy => by simp only [map_add, hx, hy], fun x y hx hy => by simp only [map_mul, hx, hy], fun x hx => by simp only [map_star, hx]] diff --git a/Mathlib/Topology/Algebra/UniformConvergence.lean b/Mathlib/Topology/Algebra/UniformConvergence.lean index beee906368d6e..d734abc5df1d3 100644 --- a/Mathlib/Topology/Algebra/UniformConvergence.lean +++ b/Mathlib/Topology/Algebra/UniformConvergence.lean @@ -5,6 +5,7 @@ Authors: Anatole Dedecker -/ import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Algebra.Module.Pi +import Mathlib.Topology.UniformSpace.UniformConvergenceTopology /-! # Algebraic facts about the topology of uniform convergence diff --git a/Mathlib/Topology/Algebra/UniformField.lean b/Mathlib/Topology/Algebra/UniformField.lean index 6746d27d74d8b..b0532ff29f706 100644 --- a/Mathlib/Topology/Algebra/UniformField.lean +++ b/Mathlib/Topology/Algebra/UniformField.lean @@ -150,9 +150,9 @@ instance instField : Field (hat K) where inv_zero := by simp only [Inv.inv, ite_true] -- TODO: use a better defeq nnqsmul := _ - nnqsmul_def := fun q a => rfl + nnqsmul_def := fun _ _ => rfl qsmul := _ - qsmul_def := fun a x => rfl + qsmul_def := fun _ _ => rfl instance : TopologicalDivisionRing (hat K) := { Completion.topologicalRing with @@ -176,11 +176,11 @@ variable (L : Type*) [Field L] [UniformSpace L] [CompletableTopField L] instance Subfield.completableTopField (K : Subfield L) : CompletableTopField K where nice F F_cau inf_F := by let i : K →+* L := K.subtype - have hi : UniformInducing i := isUniformEmbedding_subtype_val.toUniformInducing + have hi : IsUniformInducing i := isUniformEmbedding_subtype_val.isUniformInducing rw [← hi.cauchy_map_iff] at F_cau ⊢ rw [map_comm (show (i ∘ fun x => x⁻¹) = (fun x => x⁻¹) ∘ i by ext; rfl)] apply CompletableTopField.nice _ F_cau - rw [← Filter.push_pull', ← map_zero i, ← hi.inducing.nhds_eq_comap, inf_F, Filter.map_bot] + rw [← Filter.push_pull', ← map_zero i, ← hi.isInducing.nhds_eq_comap, inf_F, Filter.map_bot] instance (priority := 100) completableTopField_of_complete (L : Type*) [Field L] [UniformSpace L] [TopologicalDivisionRing L] [T0Space L] [CompleteSpace L] : CompletableTopField L where @@ -201,14 +201,14 @@ variable {α β : Type*} [Field β] [b : UniformSpace β] [CompletableTopField /-- The pullback of a completable topological field along a uniform inducing ring homomorphism is a completable topological field. -/ -theorem UniformInducing.completableTopField +theorem IsUniformInducing.completableTopField [UniformSpace α] [T0Space α] - {f : α →+* β} (hf : UniformInducing f) : + {f : α →+* β} (hf : IsUniformInducing f) : CompletableTopField α := by refine CompletableTopField.mk (fun F F_cau inf_F => ?_) - rw [← UniformInducing.cauchy_map_iff hf] at F_cau ⊢ + rw [← IsUniformInducing.cauchy_map_iff hf] at F_cau ⊢ have h_comm : (f ∘ fun x => x⁻¹) = (fun x => x⁻¹) ∘ f := by ext; simp only [Function.comp_apply, map_inv₀, Subfield.coe_inv] rw [Filter.map_comm h_comm] apply CompletableTopField.nice _ F_cau - rw [← Filter.push_pull', ← map_zero f, ← hf.inducing.nhds_eq_comap, inf_F, Filter.map_bot] + rw [← Filter.push_pull', ← map_zero f, ← hf.isInducing.nhds_eq_comap, inf_F, Filter.map_bot] diff --git a/Mathlib/Topology/Algebra/UniformFilterBasis.lean b/Mathlib/Topology/Algebra/UniformFilterBasis.lean index 09c3ba45192d2..055353936b31b 100644 --- a/Mathlib/Topology/Algebra/UniformFilterBasis.lean +++ b/Mathlib/Topology/Algebra/UniformFilterBasis.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot -/ import Mathlib.Topology.Algebra.FilterBasis -import Mathlib.Topology.Algebra.UniformGroup /-! # Uniform properties of neighborhood bases in topological algebra diff --git a/Mathlib/Topology/Algebra/UniformGroup.lean b/Mathlib/Topology/Algebra/UniformGroup/Basic.lean similarity index 58% rename from Mathlib/Topology/Algebra/UniformGroup.lean rename to Mathlib/Topology/Algebra/UniformGroup/Basic.lean index a8167d4c22d8d..9f937bc52f9d4 100644 --- a/Mathlib/Topology/Algebra/UniformGroup.lean +++ b/Mathlib/Topology/Algebra/UniformGroup/Basic.lean @@ -7,26 +7,16 @@ import Mathlib.Topology.UniformSpace.UniformConvergence import Mathlib.Topology.UniformSpace.UniformEmbedding import Mathlib.Topology.UniformSpace.CompleteSeparated import Mathlib.Topology.UniformSpace.Compact -import Mathlib.Topology.Algebra.Group.Basic +import Mathlib.Topology.Algebra.UniformGroup.Defs +import Mathlib.Topology.Algebra.Group.Quotient import Mathlib.Topology.DiscreteSubset import Mathlib.Tactic.Abel /-! # Uniform structure on topological groups -This file defines uniform groups and its additive counterpart. These typeclasses should be -preferred over using `[TopologicalSpace α] [TopologicalGroup α]` since every topological -group naturally induces a uniform structure. - -## Main declarations -* `UniformGroup` and `UniformAddGroup`: Multiplicative and additive uniform groups, that - i.e., groups with uniformly continuous `(*)` and `(⁻¹)` / `(+)` and `(-)`. - ## Main results -* `TopologicalAddGroup.toUniformSpace` and `comm_topologicalAddGroup_is_uniform` can be used - to construct a canonical uniformity for a topological add group. - * extension of ℤ-bilinear maps to complete groups (useful for ring completions) * `QuotientGroup.completeSpace` and `QuotientAddGroup.completeSpace` guarantee that quotients @@ -44,122 +34,8 @@ open Filter Set variable {α : Type*} {β : Type*} -/-- A uniform group is a group in which multiplication and inversion are uniformly continuous. -/ -class UniformGroup (α : Type*) [UniformSpace α] [Group α] : Prop where - uniformContinuous_div : UniformContinuous fun p : α × α => p.1 / p.2 - -/-- A uniform additive group is an additive group in which addition - and negation are uniformly continuous. -/ -class UniformAddGroup (α : Type*) [UniformSpace α] [AddGroup α] : Prop where - uniformContinuous_sub : UniformContinuous fun p : α × α => p.1 - p.2 - -attribute [to_additive] UniformGroup - -@[to_additive] -theorem UniformGroup.mk' {α} [UniformSpace α] [Group α] - (h₁ : UniformContinuous fun p : α × α => p.1 * p.2) (h₂ : UniformContinuous fun p : α => p⁻¹) : - UniformGroup α := - ⟨by simpa only [div_eq_mul_inv] using - h₁.comp (uniformContinuous_fst.prod_mk (h₂.comp uniformContinuous_snd))⟩ - variable [UniformSpace α] [Group α] [UniformGroup α] -@[to_additive] -theorem uniformContinuous_div : UniformContinuous fun p : α × α => p.1 / p.2 := - UniformGroup.uniformContinuous_div - -@[to_additive] -theorem UniformContinuous.div [UniformSpace β] {f : β → α} {g : β → α} (hf : UniformContinuous f) - (hg : UniformContinuous g) : UniformContinuous fun x => f x / g x := - uniformContinuous_div.comp (hf.prod_mk hg) - -@[to_additive] -theorem UniformContinuous.inv [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : - UniformContinuous fun x => (f x)⁻¹ := by - have : UniformContinuous fun x => 1 / f x := uniformContinuous_const.div hf - simp_all - -@[to_additive] -theorem uniformContinuous_inv : UniformContinuous fun x : α => x⁻¹ := - uniformContinuous_id.inv - -@[to_additive] -theorem UniformContinuous.mul [UniformSpace β] {f : β → α} {g : β → α} (hf : UniformContinuous f) - (hg : UniformContinuous g) : UniformContinuous fun x => f x * g x := by - have : UniformContinuous fun x => f x / (g x)⁻¹ := hf.div hg.inv - simp_all - -@[to_additive] -theorem uniformContinuous_mul : UniformContinuous fun p : α × α => p.1 * p.2 := - uniformContinuous_fst.mul uniformContinuous_snd - -@[to_additive] -theorem UniformContinuous.mul_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) - (a : α) : UniformContinuous fun x ↦ f x * a := - hf.mul uniformContinuous_const - -@[to_additive] -theorem UniformContinuous.const_mul [UniformSpace β] {f : β → α} (hf : UniformContinuous f) - (a : α) : UniformContinuous fun x ↦ a * f x := - uniformContinuous_const.mul hf - -@[to_additive] -theorem uniformContinuous_mul_left (a : α) : UniformContinuous fun b : α => a * b := - uniformContinuous_id.const_mul _ - -@[to_additive] -theorem uniformContinuous_mul_right (a : α) : UniformContinuous fun b : α => b * a := - uniformContinuous_id.mul_const _ - -@[to_additive] -theorem UniformContinuous.div_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) - (a : α) : UniformContinuous fun x ↦ f x / a := - hf.div uniformContinuous_const - -@[to_additive] -theorem uniformContinuous_div_const (a : α) : UniformContinuous fun b : α => b / a := - uniformContinuous_id.div_const _ - -@[to_additive UniformContinuous.const_nsmul] -theorem UniformContinuous.pow_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : - ∀ n : ℕ, UniformContinuous fun x => f x ^ n - | 0 => by - simp_rw [pow_zero] - exact uniformContinuous_const - | n + 1 => by - simp_rw [pow_succ'] - exact hf.mul (hf.pow_const n) - -@[to_additive uniformContinuous_const_nsmul] -theorem uniformContinuous_pow_const (n : ℕ) : UniformContinuous fun x : α => x ^ n := - uniformContinuous_id.pow_const n - -@[to_additive UniformContinuous.const_zsmul] -theorem UniformContinuous.zpow_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : - ∀ n : ℤ, UniformContinuous fun x => f x ^ n - | (n : ℕ) => by - simp_rw [zpow_natCast] - exact hf.pow_const _ - | Int.negSucc n => by - simp_rw [zpow_negSucc] - exact (hf.pow_const _).inv - -@[to_additive uniformContinuous_const_zsmul] -theorem uniformContinuous_zpow_const (n : ℤ) : UniformContinuous fun x : α => x ^ n := - uniformContinuous_id.zpow_const n - -@[to_additive] -instance (priority := 10) UniformGroup.to_topologicalGroup : TopologicalGroup α where - continuous_mul := uniformContinuous_mul.continuous - continuous_inv := uniformContinuous_inv.continuous - -@[to_additive] -instance [UniformSpace β] [Group β] [UniformGroup β] : UniformGroup (α × β) := - ⟨((uniformContinuous_fst.comp uniformContinuous_fst).div - (uniformContinuous_fst.comp uniformContinuous_snd)).prod_mk - ((uniformContinuous_snd.comp uniformContinuous_fst).div - (uniformContinuous_snd.comp uniformContinuous_snd))⟩ - @[to_additive] instance Pi.instUniformGroup {ι : Type*} {G : ι → Type*} [∀ i, UniformSpace (G i)] [∀ i, Group (G i)] [∀ i, UniformGroup (G i)] : UniformGroup (∀ i, G i) where @@ -167,17 +43,6 @@ instance Pi.instUniformGroup {ι : Type*} {G : ι → Type*} [∀ i, UniformSpac (uniformContinuous_proj G i).comp uniformContinuous_fst |>.div <| (uniformContinuous_proj G i).comp uniformContinuous_snd -@[to_additive] -theorem uniformity_translate_mul (a : α) : ((𝓤 α).map fun x : α × α => (x.1 * a, x.2 * a)) = 𝓤 α := - le_antisymm (uniformContinuous_id.mul uniformContinuous_const) - (calc - 𝓤 α = - ((𝓤 α).map fun x : α × α => (x.1 * a⁻¹, x.2 * a⁻¹)).map fun x : α × α => - (x.1 * a, x.2 * a) := by simp [Filter.map_map, Function.comp_def] - _ ≤ (𝓤 α).map fun x : α × α => (x.1 * a, x.2 * a) := - Filter.map_mono (uniformContinuous_id.mul uniformContinuous_const) - ) - @[to_additive] theorem isUniformEmbedding_translate_mul (a : α) : IsUniformEmbedding fun x : α => x * a := { comap_uniformity := by @@ -189,54 +54,26 @@ theorem isUniformEmbedding_translate_mul (a : α) : IsUniformEmbedding fun x : @[deprecated (since := "2024-10-01")] alias uniformEmbedding_translate_mul := isUniformEmbedding_translate_mul -namespace MulOpposite - -@[to_additive] -instance : UniformGroup αᵐᵒᵖ := - ⟨uniformContinuous_op.comp - ((uniformContinuous_unop.comp uniformContinuous_snd).inv.mul <| - uniformContinuous_unop.comp uniformContinuous_fst)⟩ - -end MulOpposite - section LatticeOps variable [Group β] @[to_additive] -theorem uniformGroup_sInf {us : Set (UniformSpace β)} (h : ∀ u ∈ us, @UniformGroup β u _) : - @UniformGroup β (sInf us) _ := - -- Porting note: {_} does not find `sInf us` instance, see `continuousSMul_sInf` - @UniformGroup.mk β (_) _ <| - uniformContinuous_sInf_rng.mpr fun u hu => - uniformContinuous_sInf_dom₂ hu hu (@UniformGroup.uniformContinuous_div β u _ (h u hu)) - -@[to_additive] -theorem uniformGroup_iInf {ι : Sort*} {us' : ι → UniformSpace β} - (h' : ∀ i, @UniformGroup β (us' i) _) : @UniformGroup β (⨅ i, us' i) _ := by - rw [← sInf_range] - exact uniformGroup_sInf (Set.forall_mem_range.mpr h') - -@[to_additive] -theorem uniformGroup_inf {u₁ u₂ : UniformSpace β} (h₁ : @UniformGroup β u₁ _) - (h₂ : @UniformGroup β u₂ _) : @UniformGroup β (u₁ ⊓ u₂) _ := by - rw [inf_eq_iInf] - refine uniformGroup_iInf fun b => ?_ - cases b <;> assumption - -@[to_additive] -lemma UniformInducing.uniformGroup {γ : Type*} [Group γ] [UniformSpace γ] [UniformGroup γ] +lemma IsUniformInducing.uniformGroup {γ : Type*} [Group γ] [UniformSpace γ] [UniformGroup γ] [UniformSpace β] {F : Type*} [FunLike F β γ] [MonoidHomClass F β γ] - (f : F) (hf : UniformInducing f) : + (f : F) (hf : IsUniformInducing f) : UniformGroup β where uniformContinuous_div := by simp_rw [hf.uniformContinuous_iff, Function.comp_def, map_div] exact uniformContinuous_div.comp (hf.uniformContinuous.prodMap hf.uniformContinuous) +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformGroup := IsUniformInducing.uniformGroup + @[to_additive] protected theorem UniformGroup.comap {γ : Type*} [Group γ] {u : UniformSpace γ} [UniformGroup γ] {F : Type*} [FunLike F β γ] [MonoidHomClass F β γ] (f : F) : @UniformGroup β (u.comap f) _ := - letI : UniformSpace β := u.comap f; UniformInducing.uniformGroup f ⟨rfl⟩ + letI : UniformSpace β := u.comap f; IsUniformInducing.uniformGroup f ⟨rfl⟩ end LatticeOps @@ -247,147 +84,6 @@ instance uniformGroup (S : Subgroup α) : UniformGroup S := .comap S.subtype end Subgroup -section - -variable (α) - -@[to_additive] -theorem uniformity_eq_comap_nhds_one : 𝓤 α = comap (fun x : α × α => x.2 / x.1) (𝓝 (1 : α)) := by - rw [nhds_eq_comap_uniformity, Filter.comap_comap] - refine le_antisymm (Filter.map_le_iff_le_comap.1 ?_) ?_ - · intro s hs - rcases mem_uniformity_of_uniformContinuous_invariant uniformContinuous_div hs with ⟨t, ht, hts⟩ - refine mem_map.2 (mem_of_superset ht ?_) - rintro ⟨a, b⟩ - simpa [subset_def] using hts a b a - · intro s hs - rcases mem_uniformity_of_uniformContinuous_invariant uniformContinuous_mul hs with ⟨t, ht, hts⟩ - refine ⟨_, ht, ?_⟩ - rintro ⟨a, b⟩ - simpa [subset_def] using hts 1 (b / a) a - -@[to_additive] -theorem uniformity_eq_comap_nhds_one_swapped : - 𝓤 α = comap (fun x : α × α => x.1 / x.2) (𝓝 (1 : α)) := by - rw [← comap_swap_uniformity, uniformity_eq_comap_nhds_one, comap_comap] - rfl - -@[to_additive] -theorem UniformGroup.ext {G : Type*} [Group G] {u v : UniformSpace G} (hu : @UniformGroup G u _) - (hv : @UniformGroup G v _) - (h : @nhds _ u.toTopologicalSpace 1 = @nhds _ v.toTopologicalSpace 1) : u = v := - UniformSpace.ext <| by - rw [@uniformity_eq_comap_nhds_one _ u _ hu, @uniformity_eq_comap_nhds_one _ v _ hv, h] - -@[to_additive] -theorem UniformGroup.ext_iff {G : Type*} [Group G] {u v : UniformSpace G} - (hu : @UniformGroup G u _) (hv : @UniformGroup G v _) : - u = v ↔ @nhds _ u.toTopologicalSpace 1 = @nhds _ v.toTopologicalSpace 1 := - ⟨fun h => h ▸ rfl, hu.ext hv⟩ - -variable {α} - -@[to_additive] -theorem UniformGroup.uniformity_countably_generated [(𝓝 (1 : α)).IsCountablyGenerated] : - (𝓤 α).IsCountablyGenerated := by - rw [uniformity_eq_comap_nhds_one] - exact Filter.comap.isCountablyGenerated _ _ - -open MulOpposite - -@[to_additive] -theorem uniformity_eq_comap_inv_mul_nhds_one : - 𝓤 α = comap (fun x : α × α => x.1⁻¹ * x.2) (𝓝 (1 : α)) := by - rw [← comap_uniformity_mulOpposite, uniformity_eq_comap_nhds_one, ← op_one, ← comap_unop_nhds, - comap_comap, comap_comap] - simp [Function.comp_def] - -@[to_additive] -theorem uniformity_eq_comap_inv_mul_nhds_one_swapped : - 𝓤 α = comap (fun x : α × α => x.2⁻¹ * x.1) (𝓝 (1 : α)) := by - rw [← comap_swap_uniformity, uniformity_eq_comap_inv_mul_nhds_one, comap_comap] - rfl - -end - -@[to_additive] -theorem Filter.HasBasis.uniformity_of_nhds_one {ι} {p : ι → Prop} {U : ι → Set α} - (h : (𝓝 (1 : α)).HasBasis p U) : - (𝓤 α).HasBasis p fun i => { x : α × α | x.2 / x.1 ∈ U i } := by - rw [uniformity_eq_comap_nhds_one] - exact h.comap _ - -@[to_additive] -theorem Filter.HasBasis.uniformity_of_nhds_one_inv_mul {ι} {p : ι → Prop} {U : ι → Set α} - (h : (𝓝 (1 : α)).HasBasis p U) : - (𝓤 α).HasBasis p fun i => { x : α × α | x.1⁻¹ * x.2 ∈ U i } := by - rw [uniformity_eq_comap_inv_mul_nhds_one] - exact h.comap _ - -@[to_additive] -theorem Filter.HasBasis.uniformity_of_nhds_one_swapped {ι} {p : ι → Prop} {U : ι → Set α} - (h : (𝓝 (1 : α)).HasBasis p U) : - (𝓤 α).HasBasis p fun i => { x : α × α | x.1 / x.2 ∈ U i } := by - rw [uniformity_eq_comap_nhds_one_swapped] - exact h.comap _ - -@[to_additive] -theorem Filter.HasBasis.uniformity_of_nhds_one_inv_mul_swapped {ι} {p : ι → Prop} {U : ι → Set α} - (h : (𝓝 (1 : α)).HasBasis p U) : - (𝓤 α).HasBasis p fun i => { x : α × α | x.2⁻¹ * x.1 ∈ U i } := by - rw [uniformity_eq_comap_inv_mul_nhds_one_swapped] - exact h.comap _ - -@[to_additive] -theorem uniformContinuous_of_tendsto_one {hom : Type*} [UniformSpace β] [Group β] [UniformGroup β] - [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} (h : Tendsto f (𝓝 1) (𝓝 1)) : - UniformContinuous f := by - have : - ((fun x : β × β => x.2 / x.1) ∘ fun x : α × α => (f x.1, f x.2)) = fun x : α × α => - f (x.2 / x.1) := by ext; simp only [Function.comp_apply, map_div] - rw [UniformContinuous, uniformity_eq_comap_nhds_one α, uniformity_eq_comap_nhds_one β, - tendsto_comap_iff, this] - exact Tendsto.comp h tendsto_comap - -/-- A group homomorphism (a bundled morphism of a type that implements `MonoidHomClass`) between -two uniform groups is uniformly continuous provided that it is continuous at one. See also -`continuous_of_continuousAt_one`. -/ -@[to_additive "An additive group homomorphism (a bundled morphism of a type that implements -`AddMonoidHomClass`) between two uniform additive groups is uniformly continuous provided that it -is continuous at zero. See also `continuous_of_continuousAt_zero`."] -theorem uniformContinuous_of_continuousAt_one {hom : Type*} [UniformSpace β] [Group β] - [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] - (f : hom) (hf : ContinuousAt f 1) : - UniformContinuous f := - uniformContinuous_of_tendsto_one (by simpa using hf.tendsto) - -@[to_additive] -theorem MonoidHom.uniformContinuous_of_continuousAt_one [UniformSpace β] [Group β] [UniformGroup β] - (f : α →* β) (hf : ContinuousAt f 1) : UniformContinuous f := - _root_.uniformContinuous_of_continuousAt_one f hf - -/-- A homomorphism from a uniform group to a discrete uniform group is continuous if and only if -its kernel is open. -/ -@[to_additive "A homomorphism from a uniform additive group to a discrete uniform additive group is -continuous if and only if its kernel is open."] -theorem UniformGroup.uniformContinuous_iff_open_ker {hom : Type*} [UniformSpace β] - [DiscreteTopology β] [Group β] [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] - {f : hom} : - UniformContinuous f ↔ IsOpen ((f : α →* β).ker : Set α) := by - refine ⟨fun hf => ?_, fun hf => ?_⟩ - · apply (isOpen_discrete ({1} : Set β)).preimage hf.continuous - · apply uniformContinuous_of_continuousAt_one - rw [ContinuousAt, nhds_discrete β, map_one, tendsto_pure] - exact hf.mem_nhds (map_one f) - -@[to_additive] -theorem uniformContinuous_monoidHom_of_continuous {hom : Type*} [UniformSpace β] [Group β] - [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} (h : Continuous f) : - UniformContinuous f := - uniformContinuous_of_tendsto_one <| - suffices Tendsto f (𝓝 1) (𝓝 (f 1)) by rwa [map_one] at this - h.tendsto 1 - @[to_additive] theorem CauchySeq.mul {ι : Type*} [Preorder ι] {u v : ι → α} (hu : CauchySeq u) (hv : CauchySeq v) : CauchySeq (u * v) := @@ -414,6 +110,11 @@ theorem totallyBounded_iff_subset_finite_iUnion_nhds_one {s : Set α} : (𝓝 (1 : α)).basis_sets.uniformity_of_nhds_one_inv_mul_swapped.totallyBounded_iff.trans <| by simp [← preimage_smul_inv, preimage] +@[to_additive] +theorem totallyBounded_inv {s : Set α} (hs : TotallyBounded s) : TotallyBounded (s⁻¹) := by + convert TotallyBounded.image hs uniformContinuous_inv + aesop + section UniformConvergence variable {ι : Type*} {l : Filter ι} {l' : Filter β} {f f' : ι → β → α} {g g' : β → α} {s : Set β} @@ -470,38 +171,8 @@ open Filter variable (G : Type*) [Group G] [TopologicalSpace G] [TopologicalGroup G] -/-- The right uniformity on a topological group (as opposed to the left uniformity). - -Warning: in general the right and left uniformities do not coincide and so one does not obtain a -`UniformGroup` structure. Two important special cases where they _do_ coincide are for -commutative groups (see `comm_topologicalGroup_is_uniform`) and for compact groups (see -`topologicalGroup_is_uniform_of_compactSpace`). -/ -@[to_additive "The right uniformity on a topological additive group (as opposed to the left -uniformity). - -Warning: in general the right and left uniformities do not coincide and so one does not obtain a -`UniformAddGroup` structure. Two important special cases where they _do_ coincide are for -commutative additive groups (see `comm_topologicalAddGroup_is_uniform`) and for compact -additive groups (see `topologicalAddGroup_is_uniform_of_compactSpace`)."] -def TopologicalGroup.toUniformSpace : UniformSpace G where - uniformity := comap (fun p : G × G => p.2 / p.1) (𝓝 1) - symm := - have : Tendsto (fun p : G × G ↦ (p.2 / p.1)⁻¹) (comap (fun p : G × G ↦ p.2 / p.1) (𝓝 1)) - (𝓝 1⁻¹) := tendsto_id.inv.comp tendsto_comap - by simpa [tendsto_comap_iff] - comp := Tendsto.le_comap fun U H ↦ by - rcases exists_nhds_one_split H with ⟨V, V_nhds, V_mul⟩ - refine mem_map.2 (mem_of_superset (mem_lift' <| preimage_mem_comap V_nhds) ?_) - rintro ⟨x, y⟩ ⟨z, hz₁, hz₂⟩ - simpa using V_mul _ hz₂ _ hz₁ - nhds_eq_comap_uniformity _ := by simp only [comap_comap, Function.comp_def, nhds_translation_div] - attribute [local instance] TopologicalGroup.toUniformSpace -@[to_additive] -theorem uniformity_eq_comap_nhds_one' : 𝓤 G = comap (fun p : G × G => p.2 / p.1) (𝓝 (1 : G)) := - rfl - @[to_additive] theorem topologicalGroup_is_uniform_of_compactSpace [CompactSpace G] : UniformGroup G := ⟨by @@ -572,75 +243,8 @@ theorem TopologicalGroup.tendstoLocallyUniformlyOn_iff {ι α : Type*} [Topologi end TopologicalGroup -section TopologicalCommGroup - -universe u v w x - -open Filter - -variable (G : Type*) [CommGroup G] [TopologicalSpace G] [TopologicalGroup G] - -section - -attribute [local instance] TopologicalGroup.toUniformSpace - -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 - -open Set - -end - -@[to_additive] -theorem UniformGroup.toUniformSpace_eq {G : Type*} [u : UniformSpace G] [Group G] - [UniformGroup G] : TopologicalGroup.toUniformSpace G = u := by - ext : 1 - rw [uniformity_eq_comap_nhds_one' G, uniformity_eq_comap_nhds_one G] - -end TopologicalCommGroup - open Filter Set Function -section - -variable {α : Type*} {β : Type*} {hom : Type*} -variable [TopologicalSpace α] [Group α] [TopologicalGroup α] - --- β is a dense subgroup of α, inclusion is denoted by e -variable [TopologicalSpace β] [Group β] -variable [FunLike hom β α] [MonoidHomClass hom β α] {e : hom} - -@[to_additive] -theorem tendsto_div_comap_self (de : IsDenseInducing e) (x₀ : α) : - Tendsto (fun t : β × β => t.2 / t.1) ((comap fun p : β × β => (e p.1, e p.2)) <| 𝓝 (x₀, x₀)) - (𝓝 1) := by - have comm : ((fun x : α × α => x.2 / x.1) ∘ fun t : β × β => (e t.1, e t.2)) = - e ∘ fun t : β × β => t.2 / t.1 := by - ext t - change e t.2 / e t.1 = e (t.2 / t.1) - rw [← map_div e t.2 t.1] - have lim : Tendsto (fun x : α × α => x.2 / x.1) (𝓝 (x₀, x₀)) (𝓝 (e 1)) := by - simpa using (continuous_div'.comp (@continuous_swap α α _ _)).tendsto (x₀, x₀) - simpa using de.tendsto_comap_nhds_nhds lim comm - -end - namespace IsDenseInducing variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} diff --git a/Mathlib/Topology/Algebra/UniformGroup/Defs.lean b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean new file mode 100644 index 0000000000000..1ebc4e5aa7b0d --- /dev/null +++ b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean @@ -0,0 +1,543 @@ +/- +Copyright (c) 2018 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Johannes Hölzl +-/ +import Mathlib.Topology.UniformSpace.Basic +import Mathlib.Topology.Algebra.Group.Basic + +/-! +# Uniform structure on topological groups + +This file defines uniform groups and its additive counterpart. These typeclasses should be +preferred over using `[TopologicalSpace α] [TopologicalGroup α]` since every topological +group naturally induces a uniform structure. + +## Main declarations +* `UniformGroup` and `UniformAddGroup`: Multiplicative and additive uniform groups, + i.e., groups with uniformly continuous `(*)` and `(⁻¹)` / `(+)` and `(-)`. + +## Main results + +* `TopologicalAddGroup.toUniformSpace` and `comm_topologicalAddGroup_is_uniform` can be used + to construct a canonical uniformity for a topological add group. + +See `Mathlib.Topology.Algebra.UniformGroup.Basic` for further results. +-/ + +assert_not_exists Cauchy + +noncomputable section + +open Uniformity Topology Filter Pointwise + +section UniformGroup + +open Filter Set + +variable {α : Type*} {β : Type*} + +/-- A uniform group is a group in which multiplication and inversion are uniformly continuous. -/ +class UniformGroup (α : Type*) [UniformSpace α] [Group α] : Prop where + uniformContinuous_div : UniformContinuous fun p : α × α => p.1 / p.2 + +/-- A uniform additive group is an additive group in which addition + and negation are uniformly continuous. -/ +class UniformAddGroup (α : Type*) [UniformSpace α] [AddGroup α] : Prop where + uniformContinuous_sub : UniformContinuous fun p : α × α => p.1 - p.2 + +attribute [to_additive] UniformGroup + +@[to_additive] +theorem UniformGroup.mk' {α} [UniformSpace α] [Group α] + (h₁ : UniformContinuous fun p : α × α => p.1 * p.2) (h₂ : UniformContinuous fun p : α => p⁻¹) : + UniformGroup α := + ⟨by simpa only [div_eq_mul_inv] using + h₁.comp (uniformContinuous_fst.prod_mk (h₂.comp uniformContinuous_snd))⟩ + +variable [UniformSpace α] [Group α] [UniformGroup α] + +@[to_additive] +theorem uniformContinuous_div : UniformContinuous fun p : α × α => p.1 / p.2 := + UniformGroup.uniformContinuous_div + +@[to_additive] +theorem UniformContinuous.div [UniformSpace β] {f : β → α} {g : β → α} (hf : UniformContinuous f) + (hg : UniformContinuous g) : UniformContinuous fun x => f x / g x := + uniformContinuous_div.comp (hf.prod_mk hg) + +@[to_additive] +theorem UniformContinuous.inv [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : + UniformContinuous fun x => (f x)⁻¹ := by + have : UniformContinuous fun x => 1 / f x := uniformContinuous_const.div hf + simp_all + +@[to_additive] +theorem uniformContinuous_inv : UniformContinuous fun x : α => x⁻¹ := + uniformContinuous_id.inv + +@[to_additive] +theorem UniformContinuous.mul [UniformSpace β] {f : β → α} {g : β → α} (hf : UniformContinuous f) + (hg : UniformContinuous g) : UniformContinuous fun x => f x * g x := by + have : UniformContinuous fun x => f x / (g x)⁻¹ := hf.div hg.inv + simp_all + +@[to_additive] +theorem uniformContinuous_mul : UniformContinuous fun p : α × α => p.1 * p.2 := + uniformContinuous_fst.mul uniformContinuous_snd + +@[to_additive] +theorem UniformContinuous.mul_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) + (a : α) : UniformContinuous fun x ↦ f x * a := + hf.mul uniformContinuous_const + +@[to_additive] +theorem UniformContinuous.const_mul [UniformSpace β] {f : β → α} (hf : UniformContinuous f) + (a : α) : UniformContinuous fun x ↦ a * f x := + uniformContinuous_const.mul hf + +@[to_additive] +theorem uniformContinuous_mul_left (a : α) : UniformContinuous fun b : α => a * b := + uniformContinuous_id.const_mul _ + +@[to_additive] +theorem uniformContinuous_mul_right (a : α) : UniformContinuous fun b : α => b * a := + uniformContinuous_id.mul_const _ + +@[to_additive] +theorem UniformContinuous.div_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) + (a : α) : UniformContinuous fun x ↦ f x / a := + hf.div uniformContinuous_const + +@[to_additive] +theorem uniformContinuous_div_const (a : α) : UniformContinuous fun b : α => b / a := + uniformContinuous_id.div_const _ + +@[to_additive UniformContinuous.const_nsmul] +theorem UniformContinuous.pow_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : + ∀ n : ℕ, UniformContinuous fun x => f x ^ n + | 0 => by + simp_rw [pow_zero] + exact uniformContinuous_const + | n + 1 => by + simp_rw [pow_succ'] + exact hf.mul (hf.pow_const n) + +@[to_additive uniformContinuous_const_nsmul] +theorem uniformContinuous_pow_const (n : ℕ) : UniformContinuous fun x : α => x ^ n := + uniformContinuous_id.pow_const n + +@[to_additive UniformContinuous.const_zsmul] +theorem UniformContinuous.zpow_const [UniformSpace β] {f : β → α} (hf : UniformContinuous f) : + ∀ n : ℤ, UniformContinuous fun x => f x ^ n + | (n : ℕ) => by + simp_rw [zpow_natCast] + exact hf.pow_const _ + | Int.negSucc n => by + simp_rw [zpow_negSucc] + exact (hf.pow_const _).inv + +@[to_additive uniformContinuous_const_zsmul] +theorem uniformContinuous_zpow_const (n : ℤ) : UniformContinuous fun x : α => x ^ n := + uniformContinuous_id.zpow_const n + +@[to_additive] +instance (priority := 10) UniformGroup.to_topologicalGroup : TopologicalGroup α where + continuous_mul := uniformContinuous_mul.continuous + continuous_inv := uniformContinuous_inv.continuous + +@[to_additive] +instance [UniformSpace β] [Group β] [UniformGroup β] : UniformGroup (α × β) := + ⟨((uniformContinuous_fst.comp uniformContinuous_fst).div + (uniformContinuous_fst.comp uniformContinuous_snd)).prod_mk + ((uniformContinuous_snd.comp uniformContinuous_fst).div + (uniformContinuous_snd.comp uniformContinuous_snd))⟩ + +@[to_additive] +theorem uniformity_translate_mul (a : α) : ((𝓤 α).map fun x : α × α => (x.1 * a, x.2 * a)) = 𝓤 α := + le_antisymm (uniformContinuous_id.mul uniformContinuous_const) + (calc + 𝓤 α = + ((𝓤 α).map fun x : α × α => (x.1 * a⁻¹, x.2 * a⁻¹)).map fun x : α × α => + (x.1 * a, x.2 * a) := by simp [Filter.map_map, Function.comp_def] + _ ≤ (𝓤 α).map fun x : α × α => (x.1 * a, x.2 * a) := + Filter.map_mono (uniformContinuous_id.mul uniformContinuous_const) + ) + +namespace MulOpposite + +@[to_additive] +instance : UniformGroup αᵐᵒᵖ := + ⟨uniformContinuous_op.comp + ((uniformContinuous_unop.comp uniformContinuous_snd).inv.mul <| + uniformContinuous_unop.comp uniformContinuous_fst)⟩ + +end MulOpposite + +section LatticeOps + +variable [Group β] + +@[to_additive] +theorem uniformGroup_sInf {us : Set (UniformSpace β)} (h : ∀ u ∈ us, @UniformGroup β u _) : + @UniformGroup β (sInf us) _ := + -- Porting note: {_} does not find `sInf us` instance, see `continuousSMul_sInf` + @UniformGroup.mk β (_) _ <| + uniformContinuous_sInf_rng.mpr fun u hu => + uniformContinuous_sInf_dom₂ hu hu (@UniformGroup.uniformContinuous_div β u _ (h u hu)) + +@[to_additive] +theorem uniformGroup_iInf {ι : Sort*} {us' : ι → UniformSpace β} + (h' : ∀ i, @UniformGroup β (us' i) _) : @UniformGroup β (⨅ i, us' i) _ := by + rw [← sInf_range] + exact uniformGroup_sInf (Set.forall_mem_range.mpr h') + +@[to_additive] +theorem uniformGroup_inf {u₁ u₂ : UniformSpace β} (h₁ : @UniformGroup β u₁ _) + (h₂ : @UniformGroup β u₂ _) : @UniformGroup β (u₁ ⊓ u₂) _ := by + rw [inf_eq_iInf] + refine uniformGroup_iInf fun b => ?_ + cases b <;> assumption + +end LatticeOps + +section + +variable (α) + +@[to_additive] +theorem uniformity_eq_comap_nhds_one : 𝓤 α = comap (fun x : α × α => x.2 / x.1) (𝓝 (1 : α)) := by + rw [nhds_eq_comap_uniformity, Filter.comap_comap] + refine le_antisymm (Filter.map_le_iff_le_comap.1 ?_) ?_ + · intro s hs + rcases mem_uniformity_of_uniformContinuous_invariant uniformContinuous_div hs with ⟨t, ht, hts⟩ + refine mem_map.2 (mem_of_superset ht ?_) + rintro ⟨a, b⟩ + simpa [subset_def] using hts a b a + · intro s hs + rcases mem_uniformity_of_uniformContinuous_invariant uniformContinuous_mul hs with ⟨t, ht, hts⟩ + refine ⟨_, ht, ?_⟩ + rintro ⟨a, b⟩ + simpa [subset_def] using hts 1 (b / a) a + +@[to_additive] +theorem uniformity_eq_comap_nhds_one_swapped : + 𝓤 α = comap (fun x : α × α => x.1 / x.2) (𝓝 (1 : α)) := by + rw [← comap_swap_uniformity, uniformity_eq_comap_nhds_one, comap_comap] + rfl + +@[to_additive] +theorem UniformGroup.ext {G : Type*} [Group G] {u v : UniformSpace G} (hu : @UniformGroup G u _) + (hv : @UniformGroup G v _) + (h : @nhds _ u.toTopologicalSpace 1 = @nhds _ v.toTopologicalSpace 1) : u = v := + UniformSpace.ext <| by + rw [@uniformity_eq_comap_nhds_one _ u _ hu, @uniformity_eq_comap_nhds_one _ v _ hv, h] + +@[to_additive] +theorem UniformGroup.ext_iff {G : Type*} [Group G] {u v : UniformSpace G} + (hu : @UniformGroup G u _) (hv : @UniformGroup G v _) : + u = v ↔ @nhds _ u.toTopologicalSpace 1 = @nhds _ v.toTopologicalSpace 1 := + ⟨fun h => h ▸ rfl, hu.ext hv⟩ + +variable {α} + +@[to_additive] +theorem UniformGroup.uniformity_countably_generated [(𝓝 (1 : α)).IsCountablyGenerated] : + (𝓤 α).IsCountablyGenerated := by + rw [uniformity_eq_comap_nhds_one] + exact Filter.comap.isCountablyGenerated _ _ + +open MulOpposite + +@[to_additive] +theorem uniformity_eq_comap_inv_mul_nhds_one : + 𝓤 α = comap (fun x : α × α => x.1⁻¹ * x.2) (𝓝 (1 : α)) := by + rw [← comap_uniformity_mulOpposite, uniformity_eq_comap_nhds_one, ← op_one, ← comap_unop_nhds, + comap_comap, comap_comap] + simp [Function.comp_def] + +@[to_additive] +theorem uniformity_eq_comap_inv_mul_nhds_one_swapped : + 𝓤 α = comap (fun x : α × α => x.2⁻¹ * x.1) (𝓝 (1 : α)) := by + rw [← comap_swap_uniformity, uniformity_eq_comap_inv_mul_nhds_one, comap_comap] + rfl + +end + +@[to_additive] +theorem Filter.HasBasis.uniformity_of_nhds_one {ι} {p : ι → Prop} {U : ι → Set α} + (h : (𝓝 (1 : α)).HasBasis p U) : + (𝓤 α).HasBasis p fun i => { x : α × α | x.2 / x.1 ∈ U i } := by + rw [uniformity_eq_comap_nhds_one] + exact h.comap _ + +@[to_additive] +theorem Filter.HasBasis.uniformity_of_nhds_one_inv_mul {ι} {p : ι → Prop} {U : ι → Set α} + (h : (𝓝 (1 : α)).HasBasis p U) : + (𝓤 α).HasBasis p fun i => { x : α × α | x.1⁻¹ * x.2 ∈ U i } := by + rw [uniformity_eq_comap_inv_mul_nhds_one] + exact h.comap _ + +@[to_additive] +theorem Filter.HasBasis.uniformity_of_nhds_one_swapped {ι} {p : ι → Prop} {U : ι → Set α} + (h : (𝓝 (1 : α)).HasBasis p U) : + (𝓤 α).HasBasis p fun i => { x : α × α | x.1 / x.2 ∈ U i } := by + rw [uniformity_eq_comap_nhds_one_swapped] + exact h.comap _ + +@[to_additive] +theorem Filter.HasBasis.uniformity_of_nhds_one_inv_mul_swapped {ι} {p : ι → Prop} {U : ι → Set α} + (h : (𝓝 (1 : α)).HasBasis p U) : + (𝓤 α).HasBasis p fun i => { x : α × α | x.2⁻¹ * x.1 ∈ U i } := by + rw [uniformity_eq_comap_inv_mul_nhds_one_swapped] + exact h.comap _ + +@[to_additive] +theorem uniformContinuous_of_tendsto_one {hom : Type*} [UniformSpace β] [Group β] [UniformGroup β] + [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} (h : Tendsto f (𝓝 1) (𝓝 1)) : + UniformContinuous f := by + have : + ((fun x : β × β => x.2 / x.1) ∘ fun x : α × α => (f x.1, f x.2)) = fun x : α × α => + f (x.2 / x.1) := by ext; simp only [Function.comp_apply, map_div] + rw [UniformContinuous, uniformity_eq_comap_nhds_one α, uniformity_eq_comap_nhds_one β, + tendsto_comap_iff, this] + exact Tendsto.comp h tendsto_comap + +/-- A group homomorphism (a bundled morphism of a type that implements `MonoidHomClass`) between +two uniform groups is uniformly continuous provided that it is continuous at one. See also +`continuous_of_continuousAt_one`. -/ +@[to_additive "An additive group homomorphism (a bundled morphism of a type that implements +`AddMonoidHomClass`) between two uniform additive groups is uniformly continuous provided that it +is continuous at zero. See also `continuous_of_continuousAt_zero`."] +theorem uniformContinuous_of_continuousAt_one {hom : Type*} [UniformSpace β] [Group β] + [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] + (f : hom) (hf : ContinuousAt f 1) : + UniformContinuous f := + uniformContinuous_of_tendsto_one (by simpa using hf.tendsto) + +@[to_additive] +theorem MonoidHom.uniformContinuous_of_continuousAt_one [UniformSpace β] [Group β] [UniformGroup β] + (f : α →* β) (hf : ContinuousAt f 1) : UniformContinuous f := + _root_.uniformContinuous_of_continuousAt_one f hf + +/-- A homomorphism from a uniform group to a discrete uniform group is continuous if and only if +its kernel is open. -/ +@[to_additive "A homomorphism from a uniform additive group to a discrete uniform additive group is +continuous if and only if its kernel is open."] +theorem UniformGroup.uniformContinuous_iff_open_ker {hom : Type*} [UniformSpace β] + [DiscreteTopology β] [Group β] [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] + {f : hom} : + UniformContinuous f ↔ IsOpen ((f : α →* β).ker : Set α) := by + refine ⟨fun hf => ?_, fun hf => ?_⟩ + · apply (isOpen_discrete ({1} : Set β)).preimage hf.continuous + · apply uniformContinuous_of_continuousAt_one + rw [ContinuousAt, nhds_discrete β, map_one, tendsto_pure] + exact hf.mem_nhds (map_one f) + +@[to_additive] +theorem uniformContinuous_monoidHom_of_continuous {hom : Type*} [UniformSpace β] [Group β] + [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} (h : Continuous f) : + UniformContinuous f := + uniformContinuous_of_tendsto_one <| + suffices Tendsto f (𝓝 1) (𝓝 (f 1)) by rwa [map_one] at this + h.tendsto 1 + +end UniformGroup + +section TopologicalGroup + +open Filter + +variable (G : Type*) [Group G] [TopologicalSpace G] [TopologicalGroup G] + +/-- The right uniformity on a topological group (as opposed to the left uniformity). + +Warning: in general the right and left uniformities do not coincide and so one does not obtain a +`UniformGroup` structure. Two important special cases where they _do_ coincide are for +commutative groups (see `comm_topologicalGroup_is_uniform`) and for compact groups (see +`topologicalGroup_is_uniform_of_compactSpace`). -/ +@[to_additive "The right uniformity on a topological additive group (as opposed to the left +uniformity). + +Warning: in general the right and left uniformities do not coincide and so one does not obtain a +`UniformAddGroup` structure. Two important special cases where they _do_ coincide are for +commutative additive groups (see `comm_topologicalAddGroup_is_uniform`) and for compact +additive groups (see `topologicalAddGroup_is_uniform_of_compactSpace`)."] +def TopologicalGroup.toUniformSpace : UniformSpace G where + uniformity := comap (fun p : G × G => p.2 / p.1) (𝓝 1) + symm := + have : Tendsto (fun p : G × G ↦ (p.2 / p.1)⁻¹) (comap (fun p : G × G ↦ p.2 / p.1) (𝓝 1)) + (𝓝 1⁻¹) := tendsto_id.inv.comp tendsto_comap + by simpa [tendsto_comap_iff] + comp := Tendsto.le_comap fun U H ↦ by + rcases exists_nhds_one_split H with ⟨V, V_nhds, V_mul⟩ + refine mem_map.2 (mem_of_superset (mem_lift' <| preimage_mem_comap V_nhds) ?_) + rintro ⟨x, y⟩ ⟨z, hz₁, hz₂⟩ + simpa using V_mul _ hz₂ _ hz₁ + nhds_eq_comap_uniformity _ := by simp only [comap_comap, Function.comp_def, nhds_translation_div] + +attribute [local instance] TopologicalGroup.toUniformSpace + +@[to_additive] +theorem uniformity_eq_comap_nhds_one' : 𝓤 G = comap (fun p : G × G => p.2 / p.1) (𝓝 (1 : G)) := + rfl + +end TopologicalGroup + +section TopologicalCommGroup + +universe u v w x + +open Filter + +variable (G : Type*) [CommGroup G] [TopologicalSpace G] [TopologicalGroup G] + +section + +attribute [local instance] TopologicalGroup.toUniformSpace + +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 + +open Set + +end + +@[to_additive] +theorem UniformGroup.toUniformSpace_eq {G : Type*} [u : UniformSpace G] [Group G] + [UniformGroup G] : TopologicalGroup.toUniformSpace G = u := by + ext : 1 + rw [uniformity_eq_comap_nhds_one' G, uniformity_eq_comap_nhds_one G] + +end TopologicalCommGroup + +open Filter Set Function + +section + +variable {α : Type*} {β : Type*} {hom : Type*} +variable [TopologicalSpace α] [Group α] [TopologicalGroup α] + +-- β is a dense subgroup of α, inclusion is denoted by e +variable [TopologicalSpace β] [Group β] +variable [FunLike hom β α] [MonoidHomClass hom β α] {e : hom} + +@[to_additive] +theorem tendsto_div_comap_self (de : IsDenseInducing e) (x₀ : α) : + Tendsto (fun t : β × β => t.2 / t.1) ((comap fun p : β × β => (e p.1, e p.2)) <| 𝓝 (x₀, x₀)) + (𝓝 1) := by + have comm : ((fun x : α × α => x.2 / x.1) ∘ fun t : β × β => (e t.1, e t.2)) = + e ∘ fun t : β × β => t.2 / t.1 := by + ext t + change e t.2 / e t.1 = e (t.2 / t.1) + rw [← map_div e t.2 t.1] + have lim : Tendsto (fun x : α × α => x.2 / x.1) (𝓝 (x₀, x₀)) (𝓝 (e 1)) := by + simpa using (continuous_div'.comp (@continuous_swap α α _ _)).tendsto (x₀, x₀) + simpa using de.tendsto_comap_nhds_nhds lim comm + +end + +namespace IsDenseInducing + +variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} +variable {G : Type*} + +-- β is a dense subgroup of α, inclusion is denoted by e +-- δ is a dense subgroup of γ, inclusion is denoted by f +variable [TopologicalSpace α] [AddCommGroup α] [TopologicalAddGroup α] +variable [TopologicalSpace β] [AddCommGroup β] +variable [TopologicalSpace γ] [AddCommGroup γ] [TopologicalAddGroup γ] +variable [TopologicalSpace δ] [AddCommGroup δ] +variable [UniformSpace G] [AddCommGroup G] +variable {e : β →+ α} (de : IsDenseInducing e) +variable {f : δ →+ γ} (df : IsDenseInducing f) +variable {φ : β →+ δ →+ G} +variable (hφ : Continuous (fun p : β × δ => φ p.1 p.2)) +variable {W' : Set G} (W'_nhd : W' ∈ 𝓝 (0 : G)) +include de hφ + +include W'_nhd in +private theorem extend_Z_bilin_aux (x₀ : α) (y₁ : δ) : ∃ U₂ ∈ comap e (𝓝 x₀), ∀ x ∈ U₂, ∀ x' ∈ U₂, + (fun p : β × δ => φ p.1 p.2) (x' - x, y₁) ∈ W' := by + let Nx := 𝓝 x₀ + let ee := fun u : β × β => (e u.1, e u.2) + have lim1 : Tendsto (fun a : β × β => (a.2 - a.1, y₁)) + (comap e Nx ×ˢ comap e Nx) (𝓝 (0, y₁)) := by + have := Tendsto.prod_mk (tendsto_sub_comap_self de x₀) + (tendsto_const_nhds : Tendsto (fun _ : β × β => y₁) (comap ee <| 𝓝 (x₀, x₀)) (𝓝 y₁)) + rw [nhds_prod_eq, prod_comap_comap_eq, ← nhds_prod_eq] + exact (this : _) + have lim2 : Tendsto (fun p : β × δ => φ p.1 p.2) (𝓝 (0, y₁)) (𝓝 0) := by + simpa using hφ.tendsto (0, y₁) + have lim := lim2.comp lim1 + rw [tendsto_prod_self_iff] at lim + simp_rw [forall_mem_comm] + exact lim W' W'_nhd + +variable [UniformAddGroup G] + +include df W'_nhd in +private theorem extend_Z_bilin_key (x₀ : α) (y₀ : γ) : ∃ U ∈ comap e (𝓝 x₀), ∃ V ∈ comap f (𝓝 y₀), + ∀ x ∈ U, ∀ x' ∈ U, ∀ (y) (_ : y ∈ V) (y') (_ : y' ∈ V), + (fun p : β × δ => φ p.1 p.2) (x', y') - (fun p : β × δ => φ p.1 p.2) (x, y) ∈ W' := by + let ee := fun u : β × β => (e u.1, e u.2) + let ff := fun u : δ × δ => (f u.1, f u.2) + have lim_φ : Filter.Tendsto (fun p : β × δ => φ p.1 p.2) (𝓝 (0, 0)) (𝓝 0) := by + simpa using hφ.tendsto (0, 0) + have lim_φ_sub_sub : + Tendsto (fun p : (β × β) × δ × δ => (fun p : β × δ => φ p.1 p.2) (p.1.2 - p.1.1, p.2.2 - p.2.1)) + ((comap ee <| 𝓝 (x₀, x₀)) ×ˢ (comap ff <| 𝓝 (y₀, y₀))) (𝓝 0) := by + have lim_sub_sub : + Tendsto (fun p : (β × β) × δ × δ => (p.1.2 - p.1.1, p.2.2 - p.2.1)) + (comap ee (𝓝 (x₀, x₀)) ×ˢ comap ff (𝓝 (y₀, y₀))) (𝓝 0 ×ˢ 𝓝 0) := by + have := Filter.prod_mono (tendsto_sub_comap_self de x₀) (tendsto_sub_comap_self df y₀) + rwa [prod_map_map_eq] at this + rw [← nhds_prod_eq] at lim_sub_sub + exact Tendsto.comp lim_φ lim_sub_sub + rcases exists_nhds_zero_quarter W'_nhd with ⟨W, W_nhd, W4⟩ + have : + ∃ U₁ ∈ comap e (𝓝 x₀), ∃ V₁ ∈ comap f (𝓝 y₀), ∀ (x) (_ : x ∈ U₁) (x') (_ : x' ∈ U₁), + ∀ (y) (_ : y ∈ V₁) (y') (_ : y' ∈ V₁), (fun p : β × δ => φ p.1 p.2) (x' - x, y' - y) ∈ W := by + rcases tendsto_prod_iff.1 lim_φ_sub_sub W W_nhd with ⟨U, U_in, V, V_in, H⟩ + rw [nhds_prod_eq, ← prod_comap_comap_eq, mem_prod_same_iff] at U_in V_in + rcases U_in with ⟨U₁, U₁_in, HU₁⟩ + rcases V_in with ⟨V₁, V₁_in, HV₁⟩ + exists U₁, U₁_in, V₁, V₁_in + intro x x_in x' x'_in y y_in y' y'_in + exact H _ _ (HU₁ (mk_mem_prod x_in x'_in)) (HV₁ (mk_mem_prod y_in y'_in)) + rcases this with ⟨U₁, U₁_nhd, V₁, V₁_nhd, H⟩ + obtain ⟨x₁, x₁_in⟩ : U₁.Nonempty := (de.comap_nhds_neBot _).nonempty_of_mem U₁_nhd + obtain ⟨y₁, y₁_in⟩ : V₁.Nonempty := (df.comap_nhds_neBot _).nonempty_of_mem V₁_nhd + have cont_flip : Continuous fun p : δ × β => φ.flip p.1 p.2 := by + show Continuous ((fun p : β × δ => φ p.1 p.2) ∘ Prod.swap) + exact hφ.comp continuous_swap + rcases extend_Z_bilin_aux de hφ W_nhd x₀ y₁ with ⟨U₂, U₂_nhd, HU⟩ + rcases extend_Z_bilin_aux df cont_flip W_nhd y₀ x₁ with ⟨V₂, V₂_nhd, HV⟩ + exists U₁ ∩ U₂, inter_mem U₁_nhd U₂_nhd, V₁ ∩ V₂, inter_mem V₁_nhd V₂_nhd + rintro x ⟨xU₁, xU₂⟩ x' ⟨x'U₁, x'U₂⟩ y ⟨yV₁, yV₂⟩ y' ⟨y'V₁, y'V₂⟩ + have key_formula : φ x' y' - φ x y + = φ (x' - x) y₁ + φ (x' - x) (y' - y₁) + φ x₁ (y' - y) + φ (x - x₁) (y' - y) := by simp; abel + rw [key_formula] + have h₁ := HU x xU₂ x' x'U₂ + have h₂ := H x xU₁ x' x'U₁ y₁ y₁_in y' y'V₁ + have h₃ := HV y yV₂ y' y'V₂ + have h₄ := H x₁ x₁_in x xU₁ y yV₁ y' y'V₁ + exact W4 h₁ h₂ h₃ h₄ + +end IsDenseInducing diff --git a/Mathlib/Topology/Algebra/UniformMulAction.lean b/Mathlib/Topology/Algebra/UniformMulAction.lean index d98b4c082accb..e64a29e9f4052 100644 --- a/Mathlib/Topology/Algebra/UniformMulAction.lean +++ b/Mathlib/Topology/Algebra/UniformMulAction.lean @@ -3,8 +3,9 @@ Copyright (c) 2022 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Algebra.Module.Opposite import Mathlib.Topology.UniformSpace.Completion +import Mathlib.Topology.Algebra.UniformGroup.Defs /-! # Multiplicative action on the completion of a uniform space @@ -88,13 +89,16 @@ theorem UniformContinuous.const_smul [UniformContinuousConstSMul M X] {f : Y → (uniformContinuous_const_smul c).comp hf @[to_additive] -lemma UniformInducing.uniformContinuousConstSMul [SMul M Y] [UniformContinuousConstSMul M Y] - {f : X → Y} (hf : UniformInducing f) (hsmul : ∀ (c : M) x, f (c • x) = c • f x) : +lemma IsUniformInducing.uniformContinuousConstSMul [SMul M Y] [UniformContinuousConstSMul M Y] + {f : X → Y} (hf : IsUniformInducing f) (hsmul : ∀ (c : M) x, f (c • x) = c • f x) : UniformContinuousConstSMul M X where uniformContinuous_const_smul c := by simpa only [hf.uniformContinuous_iff, Function.comp_def, hsmul] using hf.uniformContinuous.const_smul c +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformContinuousConstSMul := IsUniformInducing.uniformContinuousConstSMul + /-- If a scalar action is central, then its right action is uniform continuous when its left action is. -/ @[to_additive "If an additive action is central, then its right action is uniform diff --git a/Mathlib/Topology/Algebra/UniformRing.lean b/Mathlib/Topology/Algebra/UniformRing.lean index 81be27c4b6eab..68e733258377c 100644 --- a/Mathlib/Topology/Algebra/UniformRing.lean +++ b/Mathlib/Topology/Algebra/UniformRing.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Algebra.Defs import Mathlib.Logic.Equiv.TransferInstance import Mathlib.Topology.Algebra.GroupCompletion import Mathlib.Topology.Algebra.Ring.Ideal +import Mathlib.Topology.Algebra.UniformGroup.Basic /-! # Completion of topological rings: @@ -222,7 +223,7 @@ variable {α : Type*} theorem inseparableSetoid_ring (α) [CommRing α] [TopologicalSpace α] [TopologicalRing α] : inseparableSetoid α = Submodule.quotientRel (Ideal.closure ⊥) := Setoid.ext fun x y => - addGroup_inseparable_iff.trans <| .trans (by rfl) (Submodule.quotientRel_r_def _).symm + addGroup_inseparable_iff.trans <| .trans (by rfl) (Submodule.quotientRel_def _).symm @[deprecated (since := "2024-03-09")] alias ring_sep_rel := inseparableSetoid_ring @@ -259,11 +260,11 @@ def sepQuotRingEquivRingQuot (α) [CommRing α] [TopologicalSpace α] [Topologic instance topologicalRing [CommRing α] [TopologicalSpace α] [TopologicalRing α] : TopologicalRing (SeparationQuotient α) where toContinuousAdd := - Inducing.continuousAdd (sepQuotRingEquivRingQuot α) (sepQuotHomeomorphRingQuot α).inducing + (sepQuotHomeomorphRingQuot α).isInducing.continuousAdd (sepQuotRingEquivRingQuot α) toContinuousMul := - Inducing.continuousMul (sepQuotRingEquivRingQuot α) (sepQuotHomeomorphRingQuot α).inducing + (sepQuotHomeomorphRingQuot α).isInducing.continuousMul (sepQuotRingEquivRingQuot α) toContinuousNeg := - Inducing.continuousNeg (sepQuotHomeomorphRingQuot α).inducing <| + (sepQuotHomeomorphRingQuot α).isInducing.continuousNeg <| map_neg (sepQuotRingEquivRingQuot α) end UniformSpace @@ -276,8 +277,8 @@ variable {γ : Type*} [UniformSpace γ] [Semiring γ] [TopologicalSemiring γ] variable [T2Space γ] [CompleteSpace γ] /-- The dense inducing extension as a ring homomorphism. -/ -noncomputable def IsDenseInducing.extendRingHom {i : α →+* β} {f : α →+* γ} (ue : UniformInducing i) - (dr : DenseRange i) (hf : UniformContinuous f) : β →+* γ where +noncomputable def IsDenseInducing.extendRingHom {i : α →+* β} {f : α →+* γ} + (ue : IsUniformInducing i) (dr : DenseRange i) (hf : UniformContinuous f) : β →+* γ where toFun := (ue.isDenseInducing dr).extend f map_one' := by convert IsDenseInducing.extend_eq (ue.isDenseInducing dr) hf.continuous 1 diff --git a/Mathlib/Topology/Algebra/Valued/NormedValued.lean b/Mathlib/Topology/Algebra/Valued/NormedValued.lean index 2c9ce7c08f2c8..19c82cd591ba9 100644 --- a/Mathlib/Topology/Algebra/Valued/NormedValued.lean +++ b/Mathlib/Topology/Algebra/Valued/NormedValued.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: María Inés de Frutos-Fernández -/ import Mathlib.Analysis.Normed.Field.Basic -import Mathlib.Analysis.Normed.Group.Uniform +import Mathlib.Analysis.Normed.Group.Ultra import Mathlib.RingTheory.Valuation.RankOne import Mathlib.Topology.Algebra.Valued.ValuationTopology @@ -30,7 +30,9 @@ open Filter Set Valuation open scoped NNReal -variable {K : Type*} [hK : NormedField K] (h : IsNonarchimedean (norm : K → ℝ)) +section + +variable {K : Type*} [hK : NormedField K] [IsUltrametricDist K] namespace NormedField @@ -40,15 +42,16 @@ def valuation : Valuation K ℝ≥0 where map_zero' := nnnorm_zero map_one' := nnnorm_one map_mul' := nnnorm_mul - map_add_le_max' := h + map_add_le_max' := IsUltrametricDist.norm_add_le_max -theorem valuation_apply (x : K) : valuation h x = ‖x‖₊ := rfl +@[simp] +theorem valuation_apply (x : K) : valuation x = ‖x‖₊ := rfl /-- The valued field structure on a nonarchimedean normed field `K`, determined by the norm. -/ def toValued : Valued K ℝ≥0 := { hK.toUniformSpace, @NonUnitalNormedRing.toNormedAddCommGroup K _ with - v := valuation h + v := valuation is_topological_valuation := fun U => by rw [Metric.mem_nhds_iff] exact ⟨fun ⟨ε, hε, h⟩ => @@ -56,8 +59,18 @@ def toValued : Valued K ℝ≥0 := fun ⟨ε, hε⟩ => ⟨(ε : ℝ), NNReal.coe_pos.mpr (Units.zero_lt _), fun x hx ↦ hε (mem_ball_zero_iff.mp hx)⟩⟩ } +instance {K : Type*} [NontriviallyNormedField K] [IsUltrametricDist K] : + Valuation.RankOne (valuation (K := K)) where + hom := .id _ + strictMono' := strictMono_id + nontrivial' := (exists_one_lt_norm K).imp fun x h ↦ by + have h' : x ≠ 0 := norm_eq_zero.not.mp (h.gt.trans' (by simp)).ne' + simp [valuation_apply, ← NNReal.coe_inj, h.ne', h'] + end NormedField +end + namespace Valued variable {L : Type*} [Field L] {Γ₀ : Type*} [LinearOrderedCommGroupWithZero Γ₀] @@ -126,4 +139,75 @@ def toNormedField : NormedField L := exact ⟨fun a b hab => lt_of_lt_of_le hab (min_le_left _ _), fun a b hab => lt_of_lt_of_le hab (min_le_right _ _)⟩ } +-- When a field is valued, one inherits a `NormedField`. +-- Scoped instance to avoid a typeclass loop or non-defeq topology or norms. +scoped[Valued] attribute [instance] Valued.toNormedField +scoped[NormedField] attribute [instance] NormedField.toValued + +section NormedField + +open scoped Valued + +protected lemma isNonarchimedean_norm : IsNonarchimedean ((‖·‖): L → ℝ) := Valued.norm_add_le + +instance : IsUltrametricDist L := + ⟨fun x y z ↦ by + refine (Valued.norm_add_le (x - y) (y - z)).trans_eq' ?_ + simp only [sub_add_sub_cancel] + rfl ⟩ + +lemma coe_valuation_eq_rankOne_hom_comp_valuation : ⇑NormedField.valuation = hv.hom ∘ val.v := rfl + +end NormedField + +variable {L} {Γ₀} + +namespace toNormedField + +variable {x x' : L} + +@[simp] +theorem norm_le_iff : ‖x‖ ≤ ‖x'‖ ↔ val.v x ≤ val.v x' := + (Valuation.RankOne.strictMono val.v).le_iff_le + +@[simp] +theorem norm_lt_iff : ‖x‖ < ‖x'‖ ↔ val.v x < val.v x' := + (Valuation.RankOne.strictMono val.v).lt_iff_lt + +@[simp] +theorem norm_le_one_iff : ‖x‖ ≤ 1 ↔ val.v x ≤ 1 := by + simpa only [_root_.map_one] using (Valuation.RankOne.strictMono val.v).le_iff_le (b := 1) + +@[simp] +theorem norm_lt_one_iff : ‖x‖ < 1 ↔ val.v x < 1 := by + simpa only [_root_.map_one] using (Valuation.RankOne.strictMono val.v).lt_iff_lt (b := 1) + +@[simp] +theorem one_le_norm_iff : 1 ≤ ‖x‖ ↔ 1 ≤ val.v x := by + simpa only [_root_.map_one] using (Valuation.RankOne.strictMono val.v).le_iff_le (a := 1) + +@[simp] +theorem one_lt_norm_iff : 1 < ‖x‖ ↔ 1 < val.v x := by + simpa only [_root_.map_one] using (Valuation.RankOne.strictMono val.v).lt_iff_lt (a := 1) + +end toNormedField + +/-- +The nontrivially normed field structure determined by a rank one valuation. +-/ +def toNontriviallyNormedField: NontriviallyNormedField L := { + val.toNormedField with + non_trivial := by + obtain ⟨x, hx⟩ := Valuation.RankOne.nontrivial val.v + rcases Valuation.val_le_one_or_val_inv_le_one val.v x with h | h + · use x⁻¹ + simp only [toNormedField.one_lt_norm_iff, map_inv₀, one_lt_inv₀ (zero_lt_iff.mpr hx.1), + lt_of_le_of_ne h hx.2] + · use x + simp only [map_inv₀, inv_le_one₀ <| zero_lt_iff.mpr hx.1] at h + simp only [toNormedField.one_lt_norm_iff, lt_of_le_of_ne h hx.2.symm] +} + +scoped[Valued] attribute [instance] Valued.toNontriviallyNormedField + end Valued diff --git a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean index 22bb1f84d63f6..8cdff99b6d7fe 100644 --- a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean +++ b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean @@ -89,9 +89,6 @@ class Valued (R : Type u) [Ring R] (Γ₀ : outParam (Type v)) v : Valuation R Γ₀ is_topological_valuation : ∀ s, s ∈ 𝓝 (0 : R) ↔ ∃ γ : Γ₀ˣ, { x : R | v x < γ } ⊆ s --- Porting note(#12094): removed nolint; dangerous_instance linter not ported yet ---attribute [nolint dangerous_instance] Valued.toUniformSpace - namespace Valued /-- Alternative `Valued` constructor for use when there is no preferred `UniformSpace` structure. -/ diff --git a/Mathlib/Topology/Algebra/Valued/ValuedField.lean b/Mathlib/Topology/Algebra/Valued/ValuedField.lean index 99151442537d6..1ea189adaa60b 100644 --- a/Mathlib/Topology/Algebra/Valued/ValuedField.lean +++ b/Mathlib/Topology/Algebra/Valued/ValuedField.lean @@ -194,7 +194,7 @@ theorem continuous_extension : Continuous (Valued.extension : hat K → Γ₀) : intro x₀ rcases eq_or_ne x₀ 0 with (rfl | h) · refine ⟨0, ?_⟩ - erw [← Completion.isDenseInducing_coe.toInducing.nhds_eq_comap] + erw [← Completion.isDenseInducing_coe.isInducing.nhds_eq_comap] exact Valued.continuous_valuation.tendsto' 0 0 (map_zero v) · have preimage_one : v ⁻¹' {(1 : Γ₀)} ∈ 𝓝 (1 : K) := by have : (v (1 : K) : Γ₀) ≠ 0 := by diff --git a/Mathlib/Topology/Algebra/WithZeroTopology.lean b/Mathlib/Topology/Algebra/WithZeroTopology.lean index 8b290b9995546..59382fdd867a4 100644 --- a/Mathlib/Topology/Algebra/WithZeroTopology.lean +++ b/Mathlib/Topology/Algebra/WithZeroTopology.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot -/ +import Mathlib.Algebra.Order.GroupWithZero.Canonical import Mathlib.Topology.Algebra.GroupWithZero import Mathlib.Topology.Order.OrderClosed diff --git a/Mathlib/Topology/Baire/BaireMeasurable.lean b/Mathlib/Topology/Baire/BaireMeasurable.lean index 02a160951b95f..1c08bafa7d149 100644 --- a/Mathlib/Topology/Baire/BaireMeasurable.lean +++ b/Mathlib/Topology/Baire/BaireMeasurable.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Felix Weilacher. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Felix Weilacher -/ -import Mathlib.Topology.GDelta +import Mathlib.Topology.GDelta.UniformSpace import Mathlib.Topology.LocallyClosed import Mathlib.MeasureTheory.Constructions.EventuallyMeasurable import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic diff --git a/Mathlib/Topology/Baire/Lemmas.lean b/Mathlib/Topology/Baire/Lemmas.lean index 7091aebfeb216..926a6354ec0f2 100644 --- a/Mathlib/Topology/Baire/Lemmas.lean +++ b/Mathlib/Topology/Baire/Lemmas.lean @@ -3,7 +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.Topology.GDelta +import Mathlib.Topology.GDelta.Basic /-! # Baire spaces diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index bc50dd33b1af8..c8cbd51c229d2 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -142,7 +142,7 @@ theorem isTopologicalBasis_of_isOpen_of_nhds {s : Set (Set α)} (h_open : ∀ u IsTopologicalBasis s := .of_hasBasis_nhds <| fun a ↦ (nhds_basis_opens a).to_hasBasis' (by simpa [and_assoc] using h_nhds a) - fun t ⟨hts, hat⟩ ↦ (h_open _ hts).mem_nhds hat + fun _ ⟨hts, hat⟩ ↦ (h_open _ hts).mem_nhds hat /-- A set `s` is in the neighbourhood of `a` iff there is some basis set `t`, which contains `a` and is itself contained in `s`. -/ @@ -236,16 +236,19 @@ theorem IsTopologicalBasis.exists_nonempty_subset {B : Set (Set α)} (hb : IsTop theorem isTopologicalBasis_opens : IsTopologicalBasis { U : Set α | IsOpen U } := isTopologicalBasis_of_isOpen_of_nhds (by tauto) (by tauto) -protected theorem IsTopologicalBasis.inducing {β} [TopologicalSpace β] {f : α → β} {T : Set (Set β)} - (hf : Inducing f) (h : IsTopologicalBasis T) : IsTopologicalBasis ((preimage f) '' T) := +protected lemma IsTopologicalBasis.isInducing {β} [TopologicalSpace β] {f : α → β} {T : Set (Set β)} + (hf : IsInducing f) (h : IsTopologicalBasis T) : IsTopologicalBasis ((preimage f) '' T) := .of_hasBasis_nhds fun a ↦ by convert (hf.basis_nhds (h.nhds_hasBasis (a := f a))).to_image_id with s aesop +@[deprecated (since := "2024-10-28")] +alias IsTopologicalBasis.inducing := IsTopologicalBasis.isInducing + protected theorem IsTopologicalBasis.induced {α} [s : TopologicalSpace β] (f : α → β) {T : Set (Set β)} (h : IsTopologicalBasis T) : IsTopologicalBasis (t := induced f s) ((preimage f) '' T) := - h.inducing (t := induced f s) (inducing_induced f) + h.isInducing (t := induced f s) (.induced f) protected theorem IsTopologicalBasis.inf {t₁ t₂ : TopologicalSpace β} {B₁ B₂ : Set (Set β)} (h₁ : IsTopologicalBasis (t := t₁) B₁) (h₂ : IsTopologicalBasis (t := t₂) B₂) : @@ -352,10 +355,13 @@ protected theorem _root_.DenseRange.separableSpace [SeparableSpace α] [Topologi let ⟨s, s_cnt, s_dense⟩ := exists_countable_dense α ⟨⟨f '' s, Countable.image s_cnt f, h.dense_image h' s_dense⟩⟩ -theorem _root_.QuotientMap.separableSpace [SeparableSpace α] [TopologicalSpace β] {f : α → β} - (hf : QuotientMap f) : SeparableSpace β := +theorem _root_.IsQuotientMap.separableSpace [SeparableSpace α] [TopologicalSpace β] {f : α → β} + (hf : IsQuotientMap f) : SeparableSpace β := hf.surjective.denseRange.separableSpace hf.continuous +@[deprecated (since := "2024-10-22")] +alias _root_.QuotientMap.separableSpace := _root_.IsQuotientMap.separableSpace + /-- The product of two separable spaces is a separable space. -/ instance [TopologicalSpace β] [SeparableSpace α] [SeparableSpace β] : SeparableSpace (α × β) := by rcases exists_countable_dense α with ⟨s, hsc, hsd⟩ @@ -382,10 +388,10 @@ instance {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, exact hyu ⟨i, _⟩ instance [SeparableSpace α] {r : α → α → Prop} : SeparableSpace (Quot r) := - quotientMap_quot_mk.separableSpace + isQuotientMap_quot_mk.separableSpace instance [SeparableSpace α] {s : Setoid α} : SeparableSpace (Quotient s) := - quotientMap_quot_mk.separableSpace + isQuotientMap_quot_mk.separableSpace /-- A topological space with discrete topology is separable iff it is countable. -/ theorem separableSpace_iff_countable [DiscreteTopology α] : SeparableSpace α ↔ Countable α := by @@ -573,7 +579,7 @@ theorem isTopologicalBasis_subtype {α : Type*} [TopologicalSpace α] {B : Set (Set α)} (h : TopologicalSpace.IsTopologicalBasis B) (p : α → Prop) : IsTopologicalBasis (Set.preimage (Subtype.val (p := p)) '' B) := - h.inducing ⟨rfl⟩ + h.isInducing ⟨rfl⟩ section variable {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] @@ -656,17 +662,23 @@ instance Subtype.firstCountableTopology (s : Set α) [FirstCountableTopology α] FirstCountableTopology s := firstCountableTopology_induced s α (↑) -protected theorem _root_.Inducing.firstCountableTopology {β : Type*} - [TopologicalSpace β] [FirstCountableTopology β] {f : α → β} (hf : Inducing f) : +protected theorem _root_.IsInducing.firstCountableTopology {β : Type*} + [TopologicalSpace β] [FirstCountableTopology β] {f : α → β} (hf : IsInducing f) : FirstCountableTopology α := by rw [hf.1] exact firstCountableTopology_induced α β f -protected theorem _root_.Embedding.firstCountableTopology {β : Type*} - [TopologicalSpace β] [FirstCountableTopology β] {f : α → β} (hf : Embedding f) : +@[deprecated (since := "2024-10-28")] +alias _root_.Inducing.firstCountableTopology := _root_.IsInducing.firstCountableTopology + +protected theorem _root_.IsEmbedding.firstCountableTopology {β : Type*} + [TopologicalSpace β] [FirstCountableTopology β] {f : α → β} (hf : IsEmbedding f) : FirstCountableTopology α := hf.1.firstCountableTopology +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.firstCountableTopology := IsEmbedding.firstCountableTopology + namespace FirstCountableTopology /-- In a first-countable space, a cluster point `x` of a sequence @@ -887,8 +899,8 @@ theorem IsTopologicalBasis.sum {s : Set (Set α)} (hs : IsTopologicalBasis s) {t IsTopologicalBasis ((fun u => Sum.inl '' u) '' s ∪ (fun u => Sum.inr '' u) '' t) := by apply isTopologicalBasis_of_isOpen_of_nhds · rintro u (⟨w, hw, rfl⟩ | ⟨w, hw, rfl⟩) - · exact openEmbedding_inl.isOpenMap w (hs.isOpen hw) - · exact openEmbedding_inr.isOpenMap w (ht.isOpen hw) + · exact isOpenEmbedding_inl.isOpenMap w (hs.isOpen hw) + · exact isOpenEmbedding_inr.isOpenMap w (ht.isOpen hw) · rintro (x | x) u hxu u_open · obtain ⟨v, vs, xv, vu⟩ : ∃ v ∈ s, x ∈ v ∧ v ⊆ Sum.inl ⁻¹' u := hs.exists_subset_of_mem_open hxu (isOpen_sum_iff.1 u_open).1 @@ -917,8 +929,8 @@ section Quotient variable {X : Type*} [TopologicalSpace X] {Y : Type*} [TopologicalSpace Y] {π : X → Y} /-- The image of a topological basis under an open quotient map is a topological basis. -/ -theorem IsTopologicalBasis.quotientMap {V : Set (Set X)} (hV : IsTopologicalBasis V) - (h' : QuotientMap π) (h : IsOpenMap π) : IsTopologicalBasis (Set.image π '' V) := by +theorem IsTopologicalBasis.isQuotientMap {V : Set (Set X)} (hV : IsTopologicalBasis V) + (h' : IsQuotientMap π) (h : IsOpenMap π) : IsTopologicalBasis (Set.image π '' V) := by apply isTopologicalBasis_of_isOpen_of_nhds · rintro - ⟨U, U_in_V, rfl⟩ apply h U (hV.isOpen U_in_V) @@ -931,13 +943,19 @@ theorem IsTopologicalBasis.quotientMap {V : Set (Set X)} (hV : IsTopologicalBasi have πZ_in_U : π '' Z ⊆ U := (Set.image_subset _ Z_in_W).trans (image_preimage_subset π U) exact ⟨π '' Z, ⟨Z, Z_in_V, rfl⟩, ⟨x, x_in_Z, rfl⟩, πZ_in_U⟩ +@[deprecated (since := "2024-10-22")] +alias IsTopologicalBasis.quotientMap := IsTopologicalBasis.isQuotientMap + /-- A second countable space is mapped by an open quotient map to a second countable space. -/ -theorem _root_.QuotientMap.secondCountableTopology [SecondCountableTopology X] (h' : QuotientMap π) - (h : IsOpenMap π) : SecondCountableTopology Y where +theorem _root_.IsQuotientMap.secondCountableTopology [SecondCountableTopology X] + (h' : IsQuotientMap π) (h : IsOpenMap π) : SecondCountableTopology Y where is_open_generated_countable := by obtain ⟨V, V_countable, -, V_generates⟩ := exists_countable_basis X exact ⟨Set.image π '' V, V_countable.image (Set.image π), - (V_generates.quotientMap h' h).eq_generateFrom⟩ + (V_generates.isQuotientMap h' h).eq_generateFrom⟩ + +@[deprecated (since := "2024-10-22")] +alias _root_.QuotientMap.secondCountableTopology := _root_.IsQuotientMap.secondCountableTopology variable {S : Setoid X} @@ -945,12 +963,12 @@ variable {S : Setoid X} theorem IsTopologicalBasis.quotient {V : Set (Set X)} (hV : IsTopologicalBasis V) (h : IsOpenMap (Quotient.mk' : X → Quotient S)) : IsTopologicalBasis (Set.image (Quotient.mk' : X → Quotient S) '' V) := - hV.quotientMap quotientMap_quotient_mk' h + hV.isQuotientMap isQuotientMap_quotient_mk' h /-- An open quotient of a second countable space is second countable. -/ theorem Quotient.secondCountableTopology [SecondCountableTopology X] (h : IsOpenMap (Quotient.mk' : X → Quotient S)) : SecondCountableTopology (Quotient S) := - quotientMap_quotient_mk'.secondCountableTopology h + isQuotientMap_quotient_mk'.secondCountableTopology h end Quotient @@ -960,18 +978,21 @@ open TopologicalSpace variable {α β : Type*} [TopologicalSpace α] {f : α → β} -protected theorem Inducing.secondCountableTopology [TopologicalSpace β] [SecondCountableTopology β] - (hf : Inducing f) : SecondCountableTopology α := by +protected theorem IsInducing.secondCountableTopology [TopologicalSpace β] + [SecondCountableTopology β] (hf : IsInducing f) : SecondCountableTopology α := by rw [hf.1] exact secondCountableTopology_induced α β f -protected theorem Embedding.secondCountableTopology +@[deprecated (since := "2024-10-28")] +alias Inducing.secondCountableTopology := IsInducing.secondCountableTopology + +protected theorem IsEmbedding.secondCountableTopology [TopologicalSpace β] [SecondCountableTopology β] - (hf : Embedding f) : SecondCountableTopology α := + (hf : IsEmbedding f) : SecondCountableTopology α := hf.1.secondCountableTopology -protected theorem Embedding.separableSpace - [TopologicalSpace β] [SecondCountableTopology β] {f : α → β} (hf : Embedding f) : +protected theorem IsEmbedding.separableSpace + [TopologicalSpace β] [SecondCountableTopology β] {f : α → β} (hf : IsEmbedding f) : TopologicalSpace.SeparableSpace α := by have := hf.secondCountableTopology exact SecondCountableTopology.to_separableSpace diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index 388fd5adcf054..9961f73158dbd 100644 --- a/Mathlib/Topology/Basic.lean +++ b/Mathlib/Topology/Basic.lean @@ -90,7 +90,7 @@ end protected theorem TopologicalSpace.ext_iff {t t' : TopologicalSpace X} : t = t' ↔ ∀ s, IsOpen[t] s ↔ IsOpen[t'] s := - ⟨fun h s => h ▸ Iff.rfl, fun h => by ext; exact h _⟩ + ⟨fun h _ => h ▸ Iff.rfl, fun h => by ext; exact h _⟩ theorem isOpen_fold {t : TopologicalSpace X} : t.IsOpen s = IsOpen[t] s := rfl @@ -309,7 +309,7 @@ theorem interior_union_isClosed_of_interior_empty (h₁ : IsClosed s) (h₂ : interior t = ∅) : interior (s ∪ t) = interior s := have : interior (s ∪ t) ⊆ s := fun x ⟨u, ⟨(hu₁ : IsOpen u), (hu₂ : u ⊆ s ∪ t)⟩, (hx₁ : x ∈ u)⟩ => by_contradiction fun hx₂ : x ∉ s => - have : u \ s ⊆ t := fun x ⟨h₁, h₂⟩ => Or.resolve_left (hu₂ h₁) h₂ + have : u \ s ⊆ t := fun _ ⟨h₁, h₂⟩ => Or.resolve_left (hu₂ h₁) h₂ have : u \ s ⊆ interior t := by rwa [(IsOpen.sdiff hu₁ h₁).subset_interior_iff] have : u \ s ⊆ ∅ := by rwa [h₂] at this this ⟨hx₁, hx₂⟩ @@ -799,9 +799,11 @@ theorem frequently_frequently_nhds {p : X → Prop} : simp only [not_frequently, eventually_eventually_nhds] @[simp] -theorem eventually_mem_nhds : (∀ᶠ x' in 𝓝 x, s ∈ 𝓝 x') ↔ s ∈ 𝓝 x := +theorem eventually_mem_nhds_iff : (∀ᶠ x' in 𝓝 x, s ∈ 𝓝 x') ↔ s ∈ 𝓝 x := eventually_eventually_nhds +@[deprecated (since := "2024-10-04")] alias eventually_mem_nhds := eventually_mem_nhds_iff + @[simp] theorem nhds_bind_nhds : (𝓝 x).bind 𝓝 = 𝓝 x := Filter.ext fun _ => eventually_eventually_nhds @@ -851,13 +853,13 @@ theorem tendsto_atTop_nhds [Nonempty α] [SemilatticeSup α] {f : α → X} : theorem tendsto_const_nhds {f : Filter α} : Tendsto (fun _ : α => x) f (𝓝 x) := tendsto_nhds.mpr fun _ _ ha => univ_mem' fun _ => ha -theorem tendsto_atTop_of_eventually_const {ι : Type*} [SemilatticeSup ι] [Nonempty ι] +theorem tendsto_atTop_of_eventually_const {ι : Type*} [Preorder ι] {u : ι → X} {i₀ : ι} (h : ∀ i ≥ i₀, u i = x) : Tendsto u atTop (𝓝 x) := - Tendsto.congr' (EventuallyEq.symm (eventually_atTop.mpr ⟨i₀, h⟩)) tendsto_const_nhds + Tendsto.congr' (EventuallyEq.symm ((eventually_ge_atTop i₀).mono h)) tendsto_const_nhds -theorem tendsto_atBot_of_eventually_const {ι : Type*} [SemilatticeInf ι] [Nonempty ι] +theorem tendsto_atBot_of_eventually_const {ι : Type*} [Preorder ι] {u : ι → X} {i₀ : ι} (h : ∀ i ≤ i₀, u i = x) : Tendsto u atBot (𝓝 x) := - Tendsto.congr' (EventuallyEq.symm (eventually_atBot.mpr ⟨i₀, h⟩)) tendsto_const_nhds + tendsto_atTop_of_eventually_const (ι := ιᵒᵈ) h theorem pure_le_nhds : pure ≤ (𝓝 : X → Filter X) := fun _ _ hs => mem_pure.2 <| mem_of_mem_nhds hs @@ -1029,6 +1031,17 @@ theorem AccPt.mono {F G : Filter X} (h : AccPt x F) (hFG : F ≤ G) : AccPt x G theorem AccPt.clusterPt (x : X) (F : Filter X) (h : AccPt x F) : ClusterPt x F := ((acc_iff_cluster x F).mp h).mono inf_le_right +theorem clusterPt_principal {x : X} {C : Set X} : + ClusterPt x (𝓟 C) ↔ x ∈ C ∨ AccPt x (𝓟 C) := by + constructor + · intro h + by_contra! hc + rw [acc_principal_iff_cluster] at hc + simp_all only [not_false_eq_true, diff_singleton_eq_self, not_true_eq_false, hc.1] + · rintro (h | h) + · exact clusterPt_principal_iff.mpr fun _ mem ↦ ⟨x, ⟨mem_of_mem_nhds mem, h⟩⟩ + · exact h.clusterPt + /-! ### Interior, closure and frontier in terms of neighborhoods -/ @@ -1060,7 +1073,7 @@ theorem isOpen_iff_nhds : IsOpen s ↔ ∀ x ∈ s, 𝓝 x ≤ 𝓟 s := theorem TopologicalSpace.ext_iff_nhds {X} {t t' : TopologicalSpace X} : t = t' ↔ ∀ x, @nhds _ t x = @nhds _ t' x := - ⟨fun H x ↦ congrFun (congrArg _ H) _, fun H ↦ by ext; simp_rw [@isOpen_iff_nhds _ _ _, H]⟩ + ⟨fun H _ ↦ congrFun (congrArg _ H) _, fun H ↦ by ext; simp_rw [@isOpen_iff_nhds _ _ _, H]⟩ alias ⟨_, TopologicalSpace.ext_nhds⟩ := TopologicalSpace.ext_iff_nhds @@ -1142,7 +1155,6 @@ theorem dense_compl_singleton (x : X) [NeBot (𝓝[≠] x)] : Dense ({x}ᶜ : Se /-- If `x` is not an isolated point of a topological space, then the closure of `{x}ᶜ` is the whole space. -/ --- Porting note (#10618): was a `@[simp]` lemma but `simp` can prove it theorem closure_compl_singleton (x : X) [NeBot (𝓝[≠] x)] : closure {x}ᶜ = (univ : Set X) := (dense_compl_singleton x).closure_eq @@ -1400,7 +1412,7 @@ theorem ContinuousAt.eventually_mem {f : X → Y} {x : X} (hf : ContinuousAt f x (hs : s ∈ 𝓝 (f x)) : ∀ᶠ y in 𝓝 x, f y ∈ s := hf hs -/-- If a function ``f` tends to somewhere other than `𝓝 (f x)` at `x`, +/-- If a function `f` tends to somewhere other than `𝓝 (f x)` at `x`, then `f` is not continuous at `x` -/ lemma not_continuousAt_of_tendsto {f : X → Y} {l₁ : Filter X} {l₂ : Filter Y} {x : X} diff --git a/Mathlib/Topology/Category/CompHaus/Basic.lean b/Mathlib/Topology/Category/CompHaus/Basic.lean index 0306bef4b8f7d..00e0ff959c9f6 100644 --- a/Mathlib/Topology/Category/CompHaus/Basic.lean +++ b/Mathlib/Topology/Category/CompHaus/Basic.lean @@ -93,7 +93,7 @@ noncomputable def stoneCechEquivalence (X : TopCat.{u}) (Y : CompHaus.{u}) : continuous_toFun := continuous_stoneCechExtend f.2 } left_inv := by rintro ⟨f : StoneCech X ⟶ Y, hf : Continuous f⟩ - -- Porting note: `ext` fails. + -- Porting note (#11041): `ext` fails. apply ContinuousMap.ext intro (x : StoneCech X) refine congr_fun ?_ x @@ -103,7 +103,7 @@ noncomputable def stoneCechEquivalence (X : TopCat.{u}) (Y : CompHaus.{u}) : apply continuous_stoneCechUnit right_inv := by rintro ⟨f : (X : Type _) ⟶ Y, hf : Continuous f⟩ - -- Porting note: `ext` fails. + -- Porting note (#11041): `ext` fails. apply ContinuousMap.ext intro exact congr_fun (stoneCechExtend_extends hf) _ @@ -203,7 +203,7 @@ theorem epi_iff_surjective {X Y : CompHaus.{u}} (f : X ⟶ Y) : Epi f ↔ Functi have H : h = g := by rw [← cancel_epi f] ext x - -- Porting note: `ext` doesn't apply these two lemmas. + -- Porting note (#11041): `ext` doesn't apply these two lemmas. apply ULift.ext apply Subtype.ext dsimp diff --git a/Mathlib/Topology/Category/CompHaus/Projective.lean b/Mathlib/Topology/Category/CompHaus/Projective.lean index 97532c9b45d96..def47e5abc989 100644 --- a/Mathlib/Topology/Category/CompHaus/Projective.lean +++ b/Mathlib/Topology/Category/CompHaus/Projective.lean @@ -51,8 +51,9 @@ instance projective_ultrafilter (X : Type*) : Projective (of <| Ultrafilter X) w -- The next two lines should not be needed. let g'' : ContinuousMap Y Z := g have : g'' ∘ g' = id := hg'.comp_eq_id - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] + -- This used to be `rw`, but we need `rw; rfl` after leanprover/lean4#2644 + rw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] + rfl /-- For any compact Hausdorff space `X`, the natural map `Ultrafilter X → X` is a projective presentation. -/ diff --git a/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean b/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean index 3305414bc773f..cea29cf78b297 100644 --- a/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean @@ -33,20 +33,20 @@ If `π` is a surjective morphism in `CompHausLike P`, then it is an effective ep noncomputable def effectiveEpiStruct {B X : CompHausLike P} (π : X ⟶ B) (hπ : Function.Surjective π) : EffectiveEpiStruct π where - desc e h := (QuotientMap.of_surjective_continuous hπ π.continuous).lift e fun a b hab ↦ + desc e h := (IsQuotientMap.of_surjective_continuous hπ π.continuous).lift e fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) a - fac e h := ((QuotientMap.of_surjective_continuous hπ π.continuous).lift_comp e + fac e h := ((IsQuotientMap.of_surjective_continuous hπ π.continuous).lift_comp e fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) a) uniq e h g hm := by - suffices g = (QuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv ⟨e, + suffices g = (IsQuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv ⟨e, fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) a⟩ by assumption - rw [← Equiv.symm_apply_eq (QuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv] + rw [← Equiv.symm_apply_eq (IsQuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv] ext - simp only [QuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] + simp only [IsQuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] rfl theorem preregular [HasExplicitPullbacks P] diff --git a/Mathlib/Topology/Category/CompHausLike/Limits.lean b/Mathlib/Topology/Category/CompHausLike/Limits.lean index 845abc60f56e7..3e5a965f2dce5 100644 --- a/Mathlib/Topology/Category/CompHausLike/Limits.lean +++ b/Mathlib/Topology/Category/CompHausLike/Limits.lean @@ -150,20 +150,26 @@ variable {P : TopCat.{u} → Prop} [HasExplicitFiniteCoproducts.{0} P] example : HasFiniteCoproducts (CompHausLike.{u} P) := inferInstance /-- The inclusion maps into the explicit finite coproduct are open embeddings. -/ -lemma finiteCoproduct.openEmbedding_ι (a : α) : - OpenEmbedding (finiteCoproduct.ι X a) := - openEmbedding_sigmaMk (σ := fun a ↦ (X a)) +lemma finiteCoproduct.isOpenEmbedding_ι (a : α) : + IsOpenEmbedding (finiteCoproduct.ι X a) := + isOpenEmbedding_sigmaMk (σ := fun a ↦ (X a)) + +@[deprecated (since := "2024-10-18")] +alias finiteCoproduct.openEmbedding_ι := finiteCoproduct.isOpenEmbedding_ι /-- The inclusion maps into the abstract finite coproduct are open embeddings. -/ -lemma Sigma.openEmbedding_ι (a : α) : - OpenEmbedding (Sigma.ι X a) := by - refine OpenEmbedding.of_comp _ (homeoOfIso ((colimit.isColimit _).coconePointUniqueUpToIso - (finiteCoproduct.isColimit X))).openEmbedding ?_ - convert finiteCoproduct.openEmbedding_ι X a +lemma Sigma.isOpenEmbedding_ι (a : α) : + IsOpenEmbedding (Sigma.ι X a) := by + refine IsOpenEmbedding.of_comp _ (homeoOfIso ((colimit.isColimit _).coconePointUniqueUpToIso + (finiteCoproduct.isColimit X))).isOpenEmbedding ?_ + convert finiteCoproduct.isOpenEmbedding_ι X a ext x change (Sigma.ι X a ≫ _) x = _ simp +@[deprecated (since := "2024-10-18")] +alias Sigma.openEmbedding_ι := Sigma.isOpenEmbedding_ι + /-- The functor to `TopCat` preserves finite coproducts if they exist. -/ instance (P) [HasExplicitFiniteCoproducts.{0} P] : PreservesFiniteCoproducts (compHausLikeToTop P) := by @@ -332,12 +338,12 @@ instance [HasExplicitPullbacksOfInclusions P] : HasPullbacksOfInclusions (CompHa theorem hasPullbacksOfInclusions (hP' : ∀ ⦃X Y B : CompHausLike.{u} P⦄ (f : X ⟶ B) (g : Y ⟶ B) - (_ : OpenEmbedding f), HasExplicitPullback f g) : + (_ : IsOpenEmbedding f), HasExplicitPullback f g) : HasExplicitPullbacksOfInclusions P := { hasProp := by intro _ _ _ f apply hP' - exact Sigma.openEmbedding_ι _ _ } + exact Sigma.isOpenEmbedding_ι _ _ } /-- The functor to `TopCat` preserves pullbacks of inclusions if they exist. -/ noncomputable instance [HasExplicitPullbacksOfInclusions P] : @@ -350,7 +356,7 @@ instance [HasExplicitPullbacksOfInclusions P] : FinitaryExtensive (CompHausLike finitaryExtensive_of_preserves_and_reflects (compHausLikeToTop P) theorem finitaryExtensive (hP' : ∀ ⦃X Y B : CompHausLike.{u} P⦄ (f : X ⟶ B) (g : Y ⟶ B) - (_ : OpenEmbedding f), HasExplicitPullback f g) : + (_ : IsOpenEmbedding f), HasExplicitPullback f g) : FinitaryExtensive (CompHausLike P) := have := hasPullbacksOfInclusions hP' finitaryExtensive_of_preserves_and_reflects (compHausLikeToTop P) diff --git a/Mathlib/Topology/Category/Compactum.lean b/Mathlib/Topology/Category/Compactum.lean index 1bb55e129ab03..d8ccb28743f15 100644 --- a/Mathlib/Topology/Category/Compactum.lean +++ b/Mathlib/Topology/Category/Compactum.lean @@ -457,7 +457,7 @@ end compactumToCompHaus `compactumToCompHaus`. -/ def compactumToCompHausCompForget : compactumToCompHaus ⋙ CategoryTheory.forget CompHaus ≅ Compactum.forget := - NatIso.ofComponents fun X => eqToIso rfl + NatIso.ofComponents fun _ => eqToIso rfl /- TODO: `forget CompHaus` is monadic, as it is isomorphic to the composition diff --git a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean index 48104258a6815..bb092cf45b600 100644 --- a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean +++ b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean @@ -79,8 +79,7 @@ abbrev proj (n : ℕ) : S ⟶ S.diagram.obj ⟨n⟩ := S.asLimitCone.π.app ⟨n lemma lightToProfinite_map_proj_eq (n : ℕ) : lightToProfinite.map (S.proj n) = (lightToProfinite.obj S).asLimitCone.π.app _ := by - simp? says simp only [toCompHausLike_obj, Functor.comp_obj, - FintypeCat.toLightProfinite_obj_toTop_α, toCompHausLike_map, coe_of] + simp only [toCompHausLike_obj, Functor.comp_obj, toCompHausLike_map, coe_of] let c : Cone (S.diagram ⋙ lightToProfinite) := S.toLightDiagram.cone let hc : IsLimit c := S.toLightDiagram.isLimit exact liftedLimitMapsToOriginal_inv_map_π hc _ diff --git a/Mathlib/Topology/Category/LightProfinite/Basic.lean b/Mathlib/Topology/Category/LightProfinite/Basic.lean index 56a5871cbcd22..7c68c83456754 100644 --- a/Mathlib/Topology/Category/LightProfinite/Basic.lean +++ b/Mathlib/Topology/Category/LightProfinite/Basic.lean @@ -100,7 +100,7 @@ attribute [local instance] FintypeCat.discreteTopology /-- The natural functor from `Fintype` to `LightProfinite`, endowing a finite type with the discrete topology. -/ -@[simps!] +@[simps! map_apply] def FintypeCat.toLightProfinite : FintypeCat ⥤ LightProfinite where obj A := LightProfinite.of A map f := ⟨f, by continuity⟩ @@ -145,7 +145,7 @@ def limitCone {J : Type v} [SmallCategory J] [CountableCategory J] constructor · infer_instance · change SecondCountableTopology ({ u : ∀ j : J, F.obj j | _ } : Type _) - apply inducing_subtype_val.secondCountableTopology } + apply IsInducing.subtypeVal.secondCountableTopology } π := { app := (CompHaus.limitCone.{v, u} (F ⋙ lightProfiniteToCompHaus)).π.app naturality := by @@ -160,7 +160,7 @@ def limitConeIsLimit {J : Type v} [SmallCategory J] [CountableCategory J] lift S := (CompHaus.limitConeIsLimit.{v, u} (F ⋙ lightProfiniteToCompHaus)).lift (lightProfiniteToCompHaus.mapCone S) - uniq S m h := (CompHaus.limitConeIsLimit.{v, u} _).uniq (lightProfiniteToCompHaus.mapCone S) _ h + uniq S _ h := (CompHaus.limitConeIsLimit.{v, u} _).uniq (lightProfiniteToCompHaus.mapCone S) _ h noncomputable instance createsCountableLimits {J : Type v} [SmallCategory J] [CountableCategory J] : CreatesLimitsOfShape J lightToProfinite.{max v u} where @@ -338,7 +338,7 @@ noncomputable def LightProfinite.equivDiagram : LightProfinite.{u} ≌ LightDiag inverse := lightDiagramToLightProfinite unitIso := Iso.refl _ counitIso := NatIso.ofComponents - (fun X ↦ lightDiagramToProfinite.preimageIso (Iso.refl _)) (by + (fun _ ↦ lightDiagramToProfinite.preimageIso (Iso.refl _)) (by intro _ _ f simp only [Functor.comp_obj, lightDiagramToLightProfinite_obj, lightProfiniteToLightDiagram_obj, Functor.id_obj, Functor.comp_map, diff --git a/Mathlib/Topology/Category/LightProfinite/Sequence.lean b/Mathlib/Topology/Category/LightProfinite/Sequence.lean index ae729f14b1979..adba9b5392add 100644 --- a/Mathlib/Topology/Category/LightProfinite/Sequence.lean +++ b/Mathlib/Topology/Category/LightProfinite/Sequence.lean @@ -29,8 +29,8 @@ noncomputable def natUnionInftyEmbedding : C(OnePoint ℕ, ℝ) where The continuous map from `ℕ∪{∞}` to `ℝ` sending `n` to `1/(n+1)` and `∞` to `0` is a closed embedding. -/ -lemma closedEmbedding_natUnionInftyEmbedding : ClosedEmbedding natUnionInftyEmbedding := by - refine closedEmbedding_of_continuous_injective_closed +lemma isClosedEmbedding_natUnionInftyEmbedding : IsClosedEmbedding natUnionInftyEmbedding := by + refine .of_continuous_injective_isClosedMap natUnionInftyEmbedding.continuous ?_ ?_ · rintro (_|n) (_|m) h · rfl @@ -45,7 +45,10 @@ lemma closedEmbedding_natUnionInftyEmbedding : ClosedEmbedding natUnionInftyEmbe rw [h] · exact fun _ hC => (hC.isCompact.image natUnionInftyEmbedding.continuous).isClosed -instance : MetrizableSpace (OnePoint ℕ) := closedEmbedding_natUnionInftyEmbedding.metrizableSpace +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_natUnionInftyEmbedding := isClosedEmbedding_natUnionInftyEmbedding + +instance : MetrizableSpace (OnePoint ℕ) := isClosedEmbedding_natUnionInftyEmbedding.metrizableSpace /-- The one point compactification of the natural numbers as a light profinite set. -/ abbrev NatUnionInfty : LightProfinite := of (OnePoint ℕ) diff --git a/Mathlib/Topology/Category/Profinite/AsLimit.lean b/Mathlib/Topology/Category/Profinite/AsLimit.lean index 812192fbc0757..9a23eb81a082a 100644 --- a/Mathlib/Topology/Category/Profinite/AsLimit.lean +++ b/Mathlib/Topology/Category/Profinite/AsLimit.lean @@ -66,7 +66,8 @@ instance isIso_asLimitCone_lift : IsIso ((limitConeIsLimit.{u, u} X.diagram).lif · obtain ⟨b, hb⟩ := DiscreteQuotient.exists_of_compat (fun S => a.val S) fun _ _ h => a.prop (homOfLE h) use b - -- ext S : 3 -- Porting note: `ext` does not work, replaced with following three lines. + -- ext S : 3 -- Porting note (#11041): `ext` does not work, replaced with following + -- three lines. apply Subtype.ext apply funext rintro S diff --git a/Mathlib/Topology/Category/Profinite/Basic.lean b/Mathlib/Topology/Category/Profinite/Basic.lean index fdde9e65b27a8..45aaebd8b6c14 100644 --- a/Mathlib/Topology/Category/Profinite/Basic.lean +++ b/Mathlib/Topology/Category/Profinite/Basic.lean @@ -140,7 +140,7 @@ attribute [local instance] FintypeCat.discreteTopology /-- The natural functor from `Fintype` to `Profinite`, endowing a finite type with the discrete topology. -/ -@[simps] +@[simps map_apply] def FintypeCat.toProfinite : FintypeCat ⥤ Profinite where obj A := Profinite.of A map f := ⟨f, by continuity⟩ @@ -189,7 +189,7 @@ def limitConeIsLimit {J : Type v} [SmallCategory J] (F : J ⥤ Profinite.{max u lift S := (CompHaus.limitConeIsLimit.{v, u} (F ⋙ profiniteToCompHaus)).lift (profiniteToCompHaus.mapCone S) - uniq S m h := (CompHaus.limitConeIsLimit.{v, u} _).uniq (profiniteToCompHaus.mapCone S) _ h + uniq S _ h := (CompHaus.limitConeIsLimit.{v, u} _).uniq (profiniteToCompHaus.mapCone S) _ h /-- The adjunction between CompHaus.to_Profinite and Profinite.to_CompHaus -/ def toProfiniteAdjToCompHaus : CompHaus.toProfinite ⊣ profiniteToCompHaus := diff --git a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean index acb77ad51c59d..fb9774c83263f 100644 --- a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean +++ b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean @@ -168,8 +168,7 @@ theorem exists_locallyConstant_finite_nonempty {α : Type*} [Finite α] [Nonempt dsimp [σ] have h1 : ι (f x) = gg (C.π.app j x) := by change f.map (fun a b => if a = b then (0 : Fin 2) else 1) x = _ - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [h] + rw [h] rfl have h2 : ∃ a : α, ι a = gg (C.π.app j x) := ⟨f x, h1⟩ -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 diff --git a/Mathlib/Topology/Category/Profinite/Extend.lean b/Mathlib/Topology/Category/Profinite/Extend.lean index 2c00a5e5808e0..bbdcf1c6b88fc 100644 --- a/Mathlib/Topology/Category/Profinite/Extend.lean +++ b/Mathlib/Topology/Category/Profinite/Extend.lean @@ -126,12 +126,7 @@ def cone (S : Profinite) : pt := G.obj S π := { app := fun i ↦ G.map i.hom - naturality := fun _ _ f ↦ (by - have := f.w - simp only [const_obj_obj, StructuredArrow.left_eq_id, const_obj_map, Category.id_comp, - StructuredArrow.w] at this - simp only [const_obj_obj, comp_obj, StructuredArrow.proj_obj, const_obj_map, Category.id_comp, - Functor.comp_map, StructuredArrow.proj_map, ← map_comp, StructuredArrow.w]) } + naturality := fun _ _ f ↦ (by simp [← map_comp]) } example : G.mapCone c = (cone G c.pt).whisker (functor c) := rfl @@ -166,8 +161,7 @@ def cocone (S : Profinite) : have := f.w simp only [op_obj, const_obj_obj, op_map, CostructuredArrow.right_eq_id, const_obj_map, Category.comp_id] at this - simp only [comp_obj, CostructuredArrow.proj_obj, op_obj, const_obj_obj, Functor.comp_map, - CostructuredArrow.proj_map, op_map, ← map_comp, this, const_obj_map, Category.comp_id]) } + simp [← map_comp, this]) } example : G.mapCocone c.op = (cocone G c.pt).whisker (functorOp c) := rfl diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean index d9f4b3c3fea60..d4b021e2620d3 100644 --- a/Mathlib/Topology/Category/Profinite/Nobeling.lean +++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean @@ -1354,13 +1354,13 @@ 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.ofHom (πs C o)) := by +theorem succ_mono : CategoryTheory.Mono (ModuleCat.asHom (πs C o)) := by rw [ModuleCat.mono_iff_injective] exact injective_πs _ _ include hC in theorem succ_exact : - (ShortComplex.mk (ModuleCat.ofHom (πs C o)) (ModuleCat.ofHom (Linear_CC' C hsC ho)) + (ShortComplex.mk (ModuleCat.asHom (πs C o)) (ModuleCat.asHom (Linear_CC' C hsC ho)) (by ext; apply CC_comp_zero)).Exact := by rw [ShortComplex.moduleCat_exact_iff] intro f @@ -1478,7 +1478,7 @@ theorem span_sum : Set.range (eval C) = Set.range (Sum.elim theorem square_commutes : SumEval C ho ∘ Sum.inl = - ModuleCat.ofHom (πs C o) ∘ eval (π C (ord I · < o)) := by + ModuleCat.asHom (π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 +1644,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.ofHom] at hse + dsimp [ModuleCat.asHom] at hse -- Rewrite `this` using exact sequence manipulations to conclude that a term is in the range of -- the linear map `πs`: @@ -1701,8 +1701,8 @@ 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.ofHom (Linear_CC' C hsC ho) ∘ SumEval C ho ∘ Sum.inr) := by - dsimp [SumEval, ModuleCat.ofHom] + 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] intro h let f := MaxToGood C hC hsC ho h₁ @@ -1779,7 +1779,7 @@ def GoodProducts.Basis (hC : IsClosed C) : end Induction -variable {S : Profinite} {ι : S → I → Bool} (hι : ClosedEmbedding ι) +variable {S : Profinite} {ι : S → I → Bool} (hι : IsClosedEmbedding ι) include hι /-- @@ -1788,7 +1788,7 @@ Given a profinite set `S` and a closed embedding `S → (I → Bool)`, the `ℤ` -/ theorem Nobeling_aux : Module.Free ℤ (LocallyConstant S ℤ) := Module.Free.of_equiv' (Module.Free.of_basis <| GoodProducts.Basis _ hι.isClosed_range) (LocallyConstant.congrLeftₗ ℤ - (Homeomorph.ofEmbedding ι hι.toEmbedding)).symm + (.ofIsEmbedding ι hι.isEmbedding)).symm end NobelingProof @@ -1801,8 +1801,8 @@ def Nobeling.ι : S → ({C : Set S // IsClopen C} → Bool) := fun s C => decid open scoped Classical in /-- The map `Nobeling.ι` is a closed embedding. -/ -theorem Nobeling.embedding : ClosedEmbedding (Nobeling.ι S) := by - apply Continuous.closedEmbedding +theorem Nobeling.isClosedEmbedding : IsClosedEmbedding (Nobeling.ι S) := by + apply Continuous.isClosedEmbedding · dsimp (config := { unfoldPartialApp := true }) [ι] refine continuous_pi ?_ intro C @@ -1826,6 +1826,9 @@ theorem Nobeling.embedding : ClosedEmbedding (Nobeling.ι S) := by rw [← congr_fun h ⟨C, hC⟩] exact decide_eq_true hh.1 +@[deprecated (since := "2024-10-26")] +alias Nobeling.embedding := Nobeling.isClosedEmbedding + end Profinite open Profinite NobelingProof @@ -1835,6 +1838,6 @@ instance LocallyConstant.freeOfProfinite (S : Profinite.{u}) : Module.Free ℤ (LocallyConstant S ℤ) := @Nobeling_aux {C : Set S // IsClopen C} (IsWellOrder.linearOrder WellOrderingRel) WellOrderingRel.isWellOrder - S (Nobeling.ι S) (Nobeling.embedding S) + S (Nobeling.ι S) (Nobeling.isClosedEmbedding S) set_option linter.style.longFile 2000 diff --git a/Mathlib/Topology/Category/Profinite/Projective.lean b/Mathlib/Topology/Category/Profinite/Projective.lean index 98eb2deeef7fc..55521c4ffef71 100644 --- a/Mathlib/Topology/Category/Profinite/Projective.lean +++ b/Mathlib/Topology/Category/Profinite/Projective.lean @@ -50,8 +50,9 @@ instance projective_ultrafilter (X : Type u) : Projective (of <| Ultrafilter X) -- Porting note: same fix as in `Topology.Category.CompHaus.Projective` let g'' : ContinuousMap Y Z := g have : g'' ∘ g' = id := hg'.comp_eq_id - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] + -- This used to be `rw`, but we need `rw; rfl` after leanprover/lean4#2644 + rw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] + rfl /-- For any profinite `X`, the natural map `Ultrafilter X → X` is a projective presentation. -/ def projectivePresentation (X : Profinite.{u}) : ProjectivePresentation X where diff --git a/Mathlib/Topology/Category/Stonean/Limits.lean b/Mathlib/Topology/Category/Stonean/Limits.lean index 9a344de319c22..bb3322edc7eeb 100644 --- a/Mathlib/Topology/Category/Stonean/Limits.lean +++ b/Mathlib/Topology/Category/Stonean/Limits.lean @@ -24,7 +24,7 @@ namespace Stonean instance : HasExplicitFiniteCoproducts.{w, u} (fun Y ↦ ExtremallyDisconnected Y) where hasProp _ := { hasProp := show ExtremallyDisconnected (Σ (_a : _), _) from inferInstance} -variable {X Y Z : Stonean} {f : X ⟶ Z} (i : Y ⟶ Z) (hi : OpenEmbedding f) +variable {X Y Z : Stonean} {f : X ⟶ Z} (i : Y ⟶ Z) (hi : IsOpenEmbedding f) include hi lemma extremallyDisconnected_preimage : ExtremallyDisconnected (i ⁻¹' (Set.range f)) where @@ -33,13 +33,13 @@ lemma extremallyDisconnected_preimage : ExtremallyDisconnected (i ⁻¹' (Set.ra ⟨IsClosed.preimage i.continuous (isCompact_range f.continuous).isClosed, IsOpen.preimage i.continuous hi.isOpen_range⟩ rw [← (closure U).preimage_image_eq Subtype.coe_injective, - ← h.1.closedEmbedding_subtype_val.closure_image_eq U] + ← h.1.isClosedEmbedding_subtypeVal.closure_image_eq U] exact isOpen_induced (ExtremallyDisconnected.open_closure _ - (h.2.openEmbedding_subtype_val.isOpenMap U hU)) + (h.2.isOpenEmbedding_subtypeVal.isOpenMap U hU)) lemma extremallyDisconnected_pullback : ExtremallyDisconnected {xy : X × Y | f xy.1 = i xy.2} := have := extremallyDisconnected_preimage i hi - let e := (TopCat.pullbackHomeoPreimage i i.2 f hi.toEmbedding).symm + let e := (TopCat.pullbackHomeoPreimage i i.2 f hi.isEmbedding).symm let e' : {xy : X × Y | f xy.1 = i xy.2} ≃ₜ {xy : Y × X | i xy.1 = f xy.2} := by exact TopCat.homeoOfIso ((TopCat.pullbackIsoProdSubtype f i).symm ≪≫ pullbackSymmetry _ _ ≪≫ diff --git a/Mathlib/Topology/Category/TopCat/Adjunctions.lean b/Mathlib/Topology/Category/TopCat/Adjunctions.lean index e42823dc49ca5..52f1591638bd4 100644 --- a/Mathlib/Topology/Category/TopCat/Adjunctions.lean +++ b/Mathlib/Topology/Category/TopCat/Adjunctions.lean @@ -27,15 +27,15 @@ namespace TopCat `Top ⥤ Type`. -/ @[simps! unit counit] def adj₁ : discrete ⊣ forget TopCat.{u} where - unit := { app := fun X => id } - counit := { app := fun X => ⟨id, continuous_bot⟩ } + unit := { app := fun _ => id } + counit := { app := fun _ => ⟨id, continuous_bot⟩ } /-- Equipping a type with the trivial topology is right adjoint to the forgetful functor `Top ⥤ Type`. -/ @[simps! unit counit] def adj₂ : forget TopCat.{u} ⊣ trivial where - unit := { app := fun X => ⟨id, continuous_top⟩ } - counit := { app := fun X => id } + unit := { app := fun _ => ⟨id, continuous_top⟩ } + counit := { app := fun _ => id } instance : (forget TopCat.{u}).IsRightAdjoint := ⟨_, ⟨adj₁⟩⟩ diff --git a/Mathlib/Topology/Category/TopCat/Basic.lean b/Mathlib/Topology/Category/TopCat/Basic.lean index 9addb98e719ef..87760f303fc0e 100644 --- a/Mathlib/Topology/Category/TopCat/Basic.lean +++ b/Mathlib/Topology/Category/TopCat/Basic.lean @@ -47,22 +47,16 @@ instance : CoeSort TopCat Type* where instance topologicalSpaceUnbundled (X : TopCat) : TopologicalSpace X := X.str --- We leave this temporarily as a reminder of the downstream instances #13170 --- -- Porting note: cannot find a coercion to function otherwise --- -- attribute [instance] ConcreteCategory.instFunLike in --- instance (X Y : TopCat.{u}) : CoeFun (X ⟶ Y) fun _ => X → Y where --- coe (f : C(X, Y)) := f - instance instFunLike (X Y : TopCat) : FunLike (X ⟶ Y) X Y := inferInstanceAs <| FunLike C(X, Y) X Y -instance instMonoidHomClass (X Y : TopCat) : ContinuousMapClass (X ⟶ Y) X Y := +instance instContinuousMapClass (X Y : TopCat) : ContinuousMapClass (X ⟶ Y) X Y := inferInstanceAs <| ContinuousMapClass C(X, Y) X Y --- Porting note (#10618): simp can prove this; removed simp +@[simp] theorem id_app (X : TopCat.{u}) (x : ↑X) : (𝟙 X : X ⟶ X) x = x := rfl --- Porting note (#10618): simp can prove this; removed simp +@[simp] theorem comp_app {X Y Z : TopCat.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : (f ≫ g : X → Z) x = g (f x) := rfl @@ -132,8 +126,8 @@ def trivial : Type u ⥤ TopCat.{u} where @[simps] def isoOfHomeo {X Y : TopCat.{u}} (f : X ≃ₜ Y) : X ≅ Y where -- Porting note: previously ⟨f⟩ for hom (inv) and tidy closed proofs - hom := f.toContinuousMap - inv := f.symm.toContinuousMap + hom := (f : C(X, Y)) + inv := (f.symm : C(Y, X)) hom_inv_id := by ext; exact f.symm_apply_apply _ inv_hom_id := by ext; exact f.apply_symm_apply _ @@ -161,30 +155,54 @@ theorem of_homeoOfIso {X Y : TopCat.{u}} (f : X ≅ Y) : isoOfHomeo (homeoOfIso ext rfl +lemma isIso_of_bijective_of_isOpenMap {X Y : TopCat.{u}} (f : X ⟶ Y) + (hfbij : Function.Bijective f) (hfcl : IsOpenMap f) : IsIso f := + let e : X ≃ₜ Y := Homeomorph.homeomorphOfContinuousOpen + (Equiv.ofBijective f hfbij) f.continuous hfcl + inferInstanceAs <| IsIso (TopCat.isoOfHomeo e).hom + +lemma isIso_of_bijective_of_isClosedMap {X Y : TopCat.{u}} (f : X ⟶ Y) + (hfbij : Function.Bijective f) (hfcl : IsClosedMap f) : IsIso f := + let e : X ≃ₜ Y := Homeomorph.homeomorphOfContinuousClosed + (Equiv.ofBijective f hfbij) f.continuous hfcl + inferInstanceAs <| IsIso (TopCat.isoOfHomeo e).hom + -- Porting note: simpNF requested partially simped version below -theorem openEmbedding_iff_comp_isIso {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : - OpenEmbedding (f ≫ g) ↔ OpenEmbedding f := - (TopCat.homeoOfIso (asIso g)).openEmbedding.of_comp_iff f +theorem isOpenEmbedding_iff_comp_isIso {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : + IsOpenEmbedding (f ≫ g) ↔ IsOpenEmbedding f := + (TopCat.homeoOfIso (asIso g)).isOpenEmbedding.of_comp_iff f + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_comp_isIso := isOpenEmbedding_iff_comp_isIso @[simp] -theorem openEmbedding_iff_comp_isIso' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : - OpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ OpenEmbedding f := by +theorem isOpenEmbedding_iff_comp_isIso' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : + IsOpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ IsOpenEmbedding f := by simp only [← Functor.map_comp] - exact openEmbedding_iff_comp_isIso f g + exact isOpenEmbedding_iff_comp_isIso f g + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_comp_isIso' := isOpenEmbedding_iff_comp_isIso' -- Porting note: simpNF requested partially simped version below -theorem openEmbedding_iff_isIso_comp {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : - OpenEmbedding (f ≫ g) ↔ OpenEmbedding g := by +theorem isOpenEmbedding_iff_isIso_comp {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : + IsOpenEmbedding (f ≫ g) ↔ IsOpenEmbedding g := by constructor · intro h - convert h.comp (TopCat.homeoOfIso (asIso f).symm).openEmbedding + convert h.comp (TopCat.homeoOfIso (asIso f).symm).isOpenEmbedding exact congrArg _ (IsIso.inv_hom_id_assoc f g).symm - · exact fun h => h.comp (TopCat.homeoOfIso (asIso f)).openEmbedding + · exact fun h => h.comp (TopCat.homeoOfIso (asIso f)).isOpenEmbedding + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_isIso_comp := isOpenEmbedding_iff_isIso_comp @[simp] -theorem openEmbedding_iff_isIso_comp' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : - OpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ OpenEmbedding g := by +theorem isOpenEmbedding_iff_isIso_comp' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : + IsOpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ IsOpenEmbedding g := by simp only [← Functor.map_comp] - exact openEmbedding_iff_isIso_comp f g + exact isOpenEmbedding_iff_isIso_comp f g + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_isIso_comp' := isOpenEmbedding_iff_isIso_comp' end TopCat diff --git a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean index 35693a3a1dedc..75c863468db2e 100644 --- a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean @@ -9,7 +9,7 @@ import Mathlib.Topology.Category.TopCat.Limits.Pullbacks # Effective epimorphisms in `TopCat` -This file proves the result `TopCat.effectiveEpi_iff_quotientMap`: +This file proves the result `TopCat.effectiveEpi_iff_isQuotientMap`: The effective epimorphisms in `TopCat` are precisely the quotient maps. -/ @@ -22,22 +22,22 @@ namespace TopCat /-- Implementation: If `π` is a morphism in `TopCat` which is a quotient map, then it is an effective -epimorphism. The theorem `TopCat.effectiveEpi_iff_quotientMap` should be used instead of +epimorphism. The theorem `TopCat.effectiveEpi_iff_isQuotientMap` should be used instead of this definition. -/ noncomputable -def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : QuotientMap π) : +def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : IsQuotientMap π) : EffectiveEpiStruct π where - /- `QuotientMap.lift` gives the required morphism -/ + /- `IsQuotientMap.lift` gives the required morphism -/ desc e h := hπ.lift e fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) a - /- `QuotientMap.lift_comp` gives the factorisation -/ + /- `IsQuotientMap.lift_comp` gives the factorisation -/ fac e h := (hπ.lift_comp e fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) a) - /- Uniqueness follows from the fact that `QuotientMap.lift` is an equivalence (given by - `QuotientMap.liftEquiv`). -/ + /- Uniqueness follows from the fact that `IsQuotientMap.lift` is an equivalence (given by + `IsQuotientMap.liftEquiv`). -/ uniq e h g hm := by suffices g = hπ.liftEquiv ⟨e, fun a b hab ↦ DFunLike.congr_fun @@ -45,12 +45,12 @@ def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : Quo a⟩ by assumption rw [← Equiv.symm_apply_eq hπ.liftEquiv] ext - simp only [QuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] + simp only [IsQuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] rfl /-- The effective epimorphisms in `TopCat` are precisely the quotient maps. -/ -theorem effectiveEpi_iff_quotientMap {B X : TopCat.{u}} (π : X ⟶ B) : - EffectiveEpi π ↔ QuotientMap π := by +theorem effectiveEpi_iff_isQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) : + EffectiveEpi π ↔ IsQuotientMap π := by /- The backward direction is given by `effectiveEpiStructOfQuotientMap` above. -/ refine ⟨fun _ ↦ ?_, fun hπ ↦ ⟨⟨effectiveEpiStructOfQuotientMap π hπ⟩⟩⟩ /- Since `TopCat` has pullbacks, `π` is in fact a `RegularEpi`. This means that it exhibits `B` as @@ -59,8 +59,8 @@ theorem effectiveEpi_iff_quotientMap {B X : TopCat.{u}} (π : X ⟶ B) : have hπ : RegularEpi π := inferInstance let F := parallelPair hπ.left hπ.right let i : B ≅ colimit F := hπ.isColimit.coconePointUniqueUpToIso (colimit.isColimit _) - suffices QuotientMap (homeoOfIso i ∘ π) by - simpa [← Function.comp_assoc] using (homeoOfIso i).symm.quotientMap.comp this + suffices IsQuotientMap (homeoOfIso i ∘ π) by + simpa [← Function.comp_assoc] using (homeoOfIso i).symm.isQuotientMap.comp this constructor /- Effective epimorphisms are epimorphisms and epimorphisms in `TopCat` are surjective. -/ · change Function.Surjective (π ≫ i.hom) @@ -73,4 +73,7 @@ theorem effectiveEpi_iff_quotientMap {B X : TopCat.{u}} (π : X ⟶ B) : rw [isOpen_coinduced (f := (homeoOfIso i ∘ π)), coequalizer_isOpen_iff _ U, ← this] rfl +@[deprecated (since := "2024-10-22")] +alias effectiveEpi_iff_quotientMap := effectiveEpi_iff_isQuotientMap + end TopCat diff --git a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean index 6cfe839d9f554..e7833bab71d89 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean @@ -68,9 +68,9 @@ Generally you should just use `limit.isLimit F`, unless you need the actual defi def limitConeIsLimit (F : J ⥤ TopCat.{max v u}) : IsLimit (limitCone.{v,u} F) where lift S := { toFun := fun x => - ⟨fun j => S.π.app _ x, fun f => by + ⟨fun _ => S.π.app _ x, fun f => by dsimp - erw [← S.w f] + rw [← S.w f] rfl⟩ continuous_toFun := Continuous.subtype_mk (continuous_pi fun j => (S.π.app j).2) fun x i j f => by diff --git a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean index 7350fd1934dc2..f0d717923cbaa 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean @@ -46,12 +46,12 @@ theorem isTopologicalBasis_cofiltered_limit (hC : IsLimit C) (T : ∀ j, Set (Se let D := limitConeInfi F -- The isomorphism between the cone point of `C` and the cone point of `D`. let E : C.pt ≅ D.pt := hC.conePointUniqueUpToIso (limitConeInfiIsLimit _) - have hE : Inducing E.hom := (TopCat.homeoOfIso E).inducing + have hE : IsInducing E.hom := (TopCat.homeoOfIso E).isInducing -- Reduce to the assertion of the theorem with `D` instead of `C`. suffices IsTopologicalBasis {U : Set D.pt | ∃ (j : _) (V : Set (F.obj j)), V ∈ T j ∧ U = D.π.app j ⁻¹' V} by - convert this.inducing hE + convert this.isInducing hE ext U0 constructor · rintro ⟨j, V, hV, rfl⟩ @@ -104,7 +104,7 @@ theorem isTopologicalBasis_cofiltered_limit (hC : IsLimit C) (T : ∀ j, Set (Se rw [Set.preimage_iInter] apply congrArg ext1 e - erw [Set.preimage_iInter] + rw [Set.preimage_iInter] apply congrArg ext1 he -- Porting note: needed more hand holding here @@ -113,7 +113,7 @@ theorem isTopologicalBasis_cofiltered_limit (hC : IsLimit C) (T : ∀ j, Set (Se rw [dif_pos he, ← Set.preimage_comp] apply congrFun apply congrArg - erw [← coe_comp, D.w] -- now `erw` after #13170 + rw [← coe_comp, D.w] rfl end CofilteredLimit diff --git a/Mathlib/Topology/Category/TopCat/Limits/Products.lean b/Mathlib/Topology/Category/TopCat/Limits/Products.lean index 12a0b862fc298..7036388381771 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Products.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Products.lean @@ -47,11 +47,9 @@ def piFanIsLimit {ι : Type v} (α : ι → TopCat.{max v u}) : IsLimit (piFan intro S m h apply ContinuousMap.ext; intro x funext i - set_option tactic.skipAssignedInstances false in - dsimp - rw [ContinuousMap.coe_mk, ← h ⟨i⟩] + simp [ContinuousMap.coe_mk, ← h ⟨i⟩] rfl - fac s j := rfl + fac _ _ := rfl /-- The product is homeomorphic to the product of the underlying spaces, equipped with the product topology. @@ -125,7 +123,7 @@ theorem sigmaIsoSigma_inv_apply {ι : Type v} (α : ι → TopCat.{max v u}) (i theorem induced_of_isLimit {F : J ⥤ TopCat.{max v u}} (C : Cone F) (hC : IsLimit C) : C.pt.str = ⨅ j, (F.obj j).str.induced (C.π.app j) := by let homeo := homeoOfIso (hC.conePointUniqueUpToIso (limitConeInfiIsLimit F)) - refine homeo.inducing.induced.trans ?_ + refine homeo.isInducing.eq_induced.trans ?_ change induced homeo (⨅ j : J, _) = _ simp [induced_iInf, induced_compose] rfl @@ -161,7 +159,7 @@ def prodBinaryFanIsLimit (X Y : TopCat.{u}) : IsLimit (prodBinaryFan X Y) where rintro S (_ | _) <;> {dsimp; ext; rfl} uniq := by intro S m h - -- Porting note: used to be `ext x` + -- Porting note (#11041): used to be `ext x` refine ContinuousMap.ext (fun (x : ↥(S.pt)) => Prod.ext ?_ ?_) · specialize h ⟨WalkingPair.left⟩ apply_fun fun e => e x at h @@ -210,7 +208,7 @@ theorem prod_topology {X Y : TopCat.{u}} : induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓ induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by let homeo := homeoOfIso (prodIsoProd X Y) - refine homeo.inducing.induced.trans ?_ + refine homeo.isInducing.eq_induced.trans ?_ change induced homeo (_ ⊓ _) = _ simp [induced_compose] rfl @@ -224,7 +222,7 @@ theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) : · rintro ⟨y, rfl⟩ simp_rw [Set.mem_inter_iff, Set.mem_preimage, Set.mem_range] -- sizable changes in this proof after #13170 - erw [← comp_apply, ← comp_apply] + rw [← comp_apply, ← comp_apply] simp_rw [Limits.prod.map_fst, Limits.prod.map_snd, comp_apply] exact ⟨exists_apply_eq_apply _ _, exists_apply_eq_apply _ _⟩ @@ -236,29 +234,34 @@ theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) : · change limit.π (pair Y Z) _ ((prod.map f g) _) = _ erw [← comp_apply, Limits.prod.map_fst] change (_ ≫ _ ≫ f) _ = _ - erw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app] + rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app] exact hx₁ · change limit.π (pair Y Z) _ ((prod.map f g) _) = _ erw [← comp_apply, Limits.prod.map_snd] change (_ ≫ _ ≫ g) _ = _ - erw [TopCat.prodIsoProd_inv_snd_assoc,TopCat.comp_app] + rw [TopCat.prodIsoProd_inv_snd_assoc,TopCat.comp_app] exact hx₂ -theorem inducing_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Inducing f) - (hg : Inducing g) : Inducing (Limits.prod.map f g) := by +theorem isInducing_prodMap {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : IsInducing f) + (hg : IsInducing g) : IsInducing (Limits.prod.map f g) := by constructor simp_rw [topologicalSpace_coe, prod_topology, induced_inf, induced_compose, ← coe_comp, prod.map_fst, prod.map_snd, coe_comp, ← induced_compose (g := f), ← induced_compose (g := g)] - erw [← hf.induced, ← hg.induced] -- now `erw` after #13170 + erw [← hf.eq_induced, ← hg.eq_induced] -- now `erw` after #13170 rfl -- `rfl` was not needed before #13170 -theorem embedding_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Embedding f) - (hg : Embedding g) : Embedding (Limits.prod.map f g) := - ⟨inducing_prod_map hf.toInducing hg.toInducing, by +@[deprecated (since := "2024-10-28")] alias inducing_prod_map := isInducing_prodMap + +theorem isEmbedding_prodMap {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : IsEmbedding f) + (hg : IsEmbedding g) : IsEmbedding (Limits.prod.map f g) := + ⟨isInducing_prodMap hf.isInducing hg.isInducing, by haveI := (TopCat.mono_iff_injective _).mpr hf.inj haveI := (TopCat.mono_iff_injective _).mpr hg.inj exact (TopCat.mono_iff_injective _).mp inferInstance⟩ +@[deprecated (since := "2024-10-26")] +alias embedding_prod_map := isEmbedding_prodMap + end Prod /-- The binary coproduct cofan in `TopCat`. -/ @@ -283,7 +286,8 @@ def binaryCofanIsColimit (X Y : TopCat.{u}) : IsColimit (TopCat.binaryCofan X Y) theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : Nonempty (IsColimit c) ↔ - OpenEmbedding c.inl ∧ OpenEmbedding c.inr ∧ IsCompl (Set.range c.inl) (Set.range c.inr) := by + IsOpenEmbedding c.inl ∧ IsOpenEmbedding c.inr ∧ + IsCompl (Set.range c.inl) (Set.range c.inr) := by classical constructor · rintro ⟨h⟩ @@ -293,9 +297,9 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : h.comp_coconePointUniqueUpToIso_inv (binaryCofanIsColimit X Y) ⟨WalkingPair.right⟩] dsimp refine ⟨(homeoOfIso <| h.coconePointUniqueUpToIso - (binaryCofanIsColimit X Y)).symm.openEmbedding.comp openEmbedding_inl, + (binaryCofanIsColimit X Y)).symm.isOpenEmbedding.comp isOpenEmbedding_inl, (homeoOfIso <| h.coconePointUniqueUpToIso - (binaryCofanIsColimit X Y)).symm.openEmbedding.comp openEmbedding_inr, ?_⟩ + (binaryCofanIsColimit X Y)).symm.isOpenEmbedding.comp isOpenEmbedding_inr, ?_⟩ erw [Set.range_comp, ← eq_compl_iff_isCompl, Set.range_comp _ Sum.inr, ← Set.image_compl_eq (homeoOfIso <| h.coconePointUniqueUpToIso (binaryCofanIsColimit X Y)).symm.bijective, Set.compl_range_inr, Set.image_comp] @@ -315,7 +319,7 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : · revert h x apply (IsOpen.continuousOn_iff _).mp · rw [continuousOn_iff_continuous_restrict] - convert_to Continuous (f ∘ (Homeomorph.ofEmbedding _ h₁.toEmbedding).symm) + convert_to Continuous (f ∘ (Homeomorph.ofIsEmbedding _ h₁.isEmbedding).symm) · ext ⟨x, hx⟩ exact dif_pos hx apply Continuous.comp @@ -329,14 +333,14 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : rintro a (h : a ∈ (Set.range c.inl)ᶜ) rwa [eq_compl_iff_isCompl.mpr h₃.symm] convert_to Continuous - (g ∘ (Homeomorph.ofEmbedding _ h₂.toEmbedding).symm ∘ Subtype.map _ this) + (g ∘ (Homeomorph.ofIsEmbedding _ h₂.isEmbedding).symm ∘ Subtype.map _ this) · ext ⟨x, hx⟩ exact dif_neg hx apply Continuous.comp · exact g.continuous_toFun · apply Continuous.comp · continuity - · rw [embedding_subtype_val.toInducing.continuous_iff] + · rw [IsEmbedding.subtypeVal.isInducing.continuous_iff] exact continuous_subtype_val · change IsOpen (Set.range c.inl)ᶜ rw [← eq_compl_iff_isCompl.mpr h₃.symm] @@ -346,8 +350,7 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : refine (dif_pos ?_).trans ?_ · exact ⟨x, rfl⟩ · dsimp - conv_lhs => erw [Equiv.ofInjective_symm_apply] - rfl -- `rfl` was not needed here before #13170 + conv_lhs => rw [Equiv.ofInjective_symm_apply] · intro T f g ext x refine (dif_neg ?_).trans ?_ diff --git a/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean b/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean index 7701c3fb0e265..8c8900dc78066 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean @@ -71,12 +71,14 @@ def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) refine ⟨?_, ?_, ?_⟩ · delta pullbackCone ext a - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [comp_apply, ContinuousMap.coe_mk] + -- This used to be `rw`, but we need `rw; rfl` after leanprover/lean4#2644 + rw [comp_apply, ContinuousMap.coe_mk] + rfl · delta pullbackCone ext a - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [comp_apply, ContinuousMap.coe_mk] + -- This used to be `rw`, but we need `rw; rfl` after leanprover/lean4#2644 + rw [comp_apply, ContinuousMap.coe_mk] + rfl · intro m h₁ h₂ -- Porting note (#11041): used to be `ext x`. apply ContinuousMap.ext; intro x @@ -133,7 +135,7 @@ theorem pullback_topology {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : induced (pullback.fst f g) X.str ⊓ induced (pullback.snd f g) Y.str := by let homeo := homeoOfIso (pullbackIsoProdSubtype f g) - refine homeo.inducing.induced.trans ?_ + refine homeo.isInducing.eq_induced.trans ?_ change induced homeo (induced _ ( (induced Prod.fst X.str) ⊓ (induced Prod.snd Y.str))) = _ simp only [induced_compose, induced_inf] congr @@ -159,7 +161,7 @@ theorem range_pullback_to_prod {X Y Z : TopCat} (f : X ⟶ Z) (g : Y ⟶ Z) : noncomputable def pullbackHomeoPreimage {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] - (f : X → Z) (hf : Continuous f) (g : Y → Z) (hg : Embedding g) : + (f : X → Z) (hf : Continuous f) (g : Y → Z) (hg : IsEmbedding g) : { p : X × Y // f p.1 = g p.2 } ≃ₜ f ⁻¹' Set.range g where toFun := fun x ↦ ⟨x.1.1, _, x.2.symm⟩ invFun := fun x ↦ ⟨⟨x.1, Exists.choose x.2⟩, (Exists.choose_spec x.2).symm⟩ @@ -169,24 +171,29 @@ def pullbackHomeoPreimage apply hg.inj convert x.prop exact Exists.choose_spec (p := fun y ↦ g y = f (↑x : X × Y).1) _ - right_inv := fun x ↦ rfl + right_inv := fun _ ↦ rfl continuous_toFun := by apply Continuous.subtype_mk exact continuous_fst.comp continuous_subtype_val continuous_invFun := by apply Continuous.subtype_mk - refine continuous_prod_mk.mpr ⟨continuous_subtype_val, hg.toInducing.continuous_iff.mpr ?_⟩ + refine continuous_prod_mk.mpr ⟨continuous_subtype_val, hg.isInducing.continuous_iff.mpr ?_⟩ convert hf.comp continuous_subtype_val ext x exact Exists.choose_spec x.2 -theorem inducing_pullback_to_prod {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : - Inducing <| ⇑(prod.lift (pullback.fst f g) (pullback.snd f g)) := +theorem isInducing_pullback_to_prod {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : + IsInducing <| ⇑(prod.lift (pullback.fst f g) (pullback.snd f g)) := ⟨by simp [topologicalSpace_coe, prod_topology, pullback_topology, induced_compose, ← coe_comp]⟩ -theorem embedding_pullback_to_prod {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : - Embedding <| ⇑(prod.lift (pullback.fst f g) (pullback.snd f g)) := - ⟨inducing_pullback_to_prod f g, (TopCat.mono_iff_injective _).mp inferInstance⟩ +@[deprecated (since := "2024-10-28")] alias inducing_pullback_to_prod := isInducing_pullback_to_prod + +theorem isEmbedding_pullback_to_prod {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : + IsEmbedding <| ⇑(prod.lift (pullback.fst f g) (pullback.snd f g)) := + ⟨isInducing_pullback_to_prod f g, (TopCat.mono_iff_injective _).mp inferInstance⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_pullback_to_prod := isEmbedding_pullback_to_prod /-- If the map `S ⟶ T` is mono, then there is a description of the image of `W ×ₛ X ⟶ Y ×ₜ Z`. -/ theorem range_pullback_map {W X Y Z S T : TopCat} (f₁ : W ⟶ S) (f₂ : X ⟶ S) (g₁ : Y ⟶ T) @@ -198,13 +205,13 @@ theorem range_pullback_map {W X Y Z S T : TopCat} (f₁ : W ⟶ S) (f₂ : X ⟶ constructor · rintro ⟨y, rfl⟩ simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_range] - erw [← comp_apply, ← comp_apply] -- now `erw` after #13170 + rw [← comp_apply, ← comp_apply] simp only [limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, comp_apply] exact ⟨exists_apply_eq_apply _ _, exists_apply_eq_apply _ _⟩ rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩ have : f₁ x₁ = f₂ x₂ := by apply (TopCat.mono_iff_injective _).mp H₃ - erw [← comp_apply, eq₁, ← comp_apply, eq₂, -- now `erw` after #13170 + rw [← comp_apply, eq₁, ← comp_apply, eq₂, comp_apply, comp_apply, hx₁, hx₂, ← comp_apply, pullback.condition] rfl -- `rfl` was not needed before #13170 use (pullbackIsoProdSubtype f₁ f₂).inv ⟨⟨x₁, x₂⟩, this⟩ @@ -214,17 +221,14 @@ theorem range_pullback_map {W X Y Z S T : TopCat} (f₁ : W ⟶ S) (f₂ : X ⟶ erw [← comp_apply, ← comp_apply] -- now `erw` after #13170 · simp only [Category.assoc, limit.lift_π, PullbackCone.mk_π_app_one] simp only [cospan_one, pullbackIsoProdSubtype_inv_fst_assoc, comp_apply] - erw [pullbackFst_apply, hx₁] - rw [← limit.w _ WalkingCospan.Hom.inl, cospan_map_inl, comp_apply (g := g₁)] - rfl -- `rfl` was not needed before #13170 + rw [pullbackFst_apply, hx₁, ← limit.w _ WalkingCospan.Hom.inl, cospan_map_inl, + comp_apply (g := g₁)] · simp only [cospan_left, limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, pullbackIsoProdSubtype_inv_fst_assoc, comp_apply] erw [hx₁] -- now `erw` after #13170 - rfl -- `rfl` was not needed before #13170 · simp only [cospan_right, limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, pullbackIsoProdSubtype_inv_snd_assoc, comp_apply] erw [hx₂] -- now `erw` after #13170 - rfl -- `rfl` was not needed before #13170 theorem pullback_fst_range {X Y S : TopCat} (f : X ⟶ S) (g : Y ⟶ S) : Set.range (pullback.fst f g) = { x : X | ∃ y : Y, f x = g y } := by @@ -259,20 +263,22 @@ W ⟶ Y X ⟶ Z ``` -/ -theorem pullback_map_embedding_of_embeddings {W X Y Z S T : TopCat.{u}} (f₁ : W ⟶ S) (f₂ : X ⟶ S) - (g₁ : Y ⟶ T) (g₂ : Z ⟶ T) {i₁ : W ⟶ Y} {i₂ : X ⟶ Z} (H₁ : Embedding i₁) (H₂ : Embedding i₂) - (i₃ : S ⟶ T) (eq₁ : f₁ ≫ i₃ = i₁ ≫ g₁) (eq₂ : f₂ ≫ i₃ = i₂ ≫ g₂) : - Embedding (pullback.map f₁ f₂ g₁ g₂ i₁ i₂ i₃ eq₁ eq₂) := by - refine - embedding_of_embedding_compose (ContinuousMap.continuous_toFun _) - (show Continuous (prod.lift (pullback.fst g₁ g₂) (pullback.snd g₁ g₂)) from +theorem pullback_map_isEmbedding {W X Y Z S T : TopCat.{u}} (f₁ : W ⟶ S) (f₂ : X ⟶ S) + (g₁ : Y ⟶ T) (g₂ : Z ⟶ T) {i₁ : W ⟶ Y} {i₂ : X ⟶ Z} (H₁ : IsEmbedding i₁) + (H₂ : IsEmbedding i₂) (i₃ : S ⟶ T) (eq₁ : f₁ ≫ i₃ = i₁ ≫ g₁) (eq₂ : f₂ ≫ i₃ = i₂ ≫ g₂) : + IsEmbedding (pullback.map f₁ f₂ g₁ g₂ i₁ i₂ i₃ eq₁ eq₂) := by + refine .of_comp (ContinuousMap.continuous_toFun _) + (show Continuous (prod.lift (pullback.fst g₁ g₂) (pullback.snd g₁ g₂)) from ContinuousMap.continuous_toFun _) ?_ suffices - Embedding (prod.lift (pullback.fst f₁ f₂) (pullback.snd f₁ f₂) ≫ Limits.prod.map i₁ i₂) by + IsEmbedding (prod.lift (pullback.fst f₁ f₂) (pullback.snd f₁ f₂) ≫ Limits.prod.map i₁ i₂) by simpa [← coe_comp] using this rw [coe_comp] - exact Embedding.comp (embedding_prod_map H₁ H₂) (embedding_pullback_to_prod _ _) + exact (isEmbedding_prodMap H₁ H₂).comp (isEmbedding_pullback_to_prod _ _) + +@[deprecated (since := "2024-10-26")] +alias pullback_map_embedding_of_embeddings := pullback_map_isEmbedding /-- If there is a diagram where the morphisms `W ⟶ Y` and `X ⟶ Z` are open embeddings, and `S ⟶ T` is mono, then the induced morphism `W ×ₛ X ⟶ Y ×ₜ Z` is also an open embedding. @@ -285,13 +291,13 @@ W ⟶ Y X ⟶ Z ``` -/ -theorem pullback_map_openEmbedding_of_open_embeddings {W X Y Z S T : TopCat.{u}} (f₁ : W ⟶ S) - (f₂ : X ⟶ S) (g₁ : Y ⟶ T) (g₂ : Z ⟶ T) {i₁ : W ⟶ Y} {i₂ : X ⟶ Z} (H₁ : OpenEmbedding i₁) - (H₂ : OpenEmbedding i₂) (i₃ : S ⟶ T) [H₃ : Mono i₃] (eq₁ : f₁ ≫ i₃ = i₁ ≫ g₁) - (eq₂ : f₂ ≫ i₃ = i₂ ≫ g₂) : OpenEmbedding (pullback.map f₁ f₂ g₁ g₂ i₁ i₂ i₃ eq₁ eq₂) := by +theorem pullback_map_isOpenEmbedding {W X Y Z S T : TopCat.{u}} (f₁ : W ⟶ S) + (f₂ : X ⟶ S) (g₁ : Y ⟶ T) (g₂ : Z ⟶ T) {i₁ : W ⟶ Y} {i₂ : X ⟶ Z} (H₁ : IsOpenEmbedding i₁) + (H₂ : IsOpenEmbedding i₂) (i₃ : S ⟶ T) [H₃ : Mono i₃] (eq₁ : f₁ ≫ i₃ = i₁ ≫ g₁) + (eq₂ : f₂ ≫ i₃ = i₂ ≫ g₂) : IsOpenEmbedding (pullback.map f₁ f₂ g₁ g₂ i₁ i₂ i₃ eq₁ eq₂) := by constructor · apply - pullback_map_embedding_of_embeddings f₁ f₂ g₁ g₂ H₁.toEmbedding H₂.toEmbedding i₃ eq₁ eq₂ + pullback_map_isEmbedding f₁ f₂ g₁ g₂ H₁.isEmbedding H₂.isEmbedding i₃ eq₁ eq₂ · rw [range_pullback_map] apply IsOpen.inter <;> apply Continuous.isOpen_preimage · apply ContinuousMap.continuous_toFun @@ -299,59 +305,79 @@ theorem pullback_map_openEmbedding_of_open_embeddings {W X Y Z S T : TopCat.{u}} · apply ContinuousMap.continuous_toFun · exact H₂.isOpen_range -theorem snd_embedding_of_left_embedding {X Y S : TopCat} {f : X ⟶ S} (H : Embedding f) (g : Y ⟶ S) : - Embedding <| ⇑(pullback.snd f g) := by - convert (homeoOfIso (asIso (pullback.snd (𝟙 S) g))).embedding.comp - (pullback_map_embedding_of_embeddings (i₂ := 𝟙 Y) - f g (𝟙 S) g H (homeoOfIso (Iso.refl _)).embedding (𝟙 _) rfl (by simp)) +@[deprecated (since := "2024-10-18")] +alias pullback_map_openEmbedding_of_open_embeddings := pullback_map_isOpenEmbedding + + +lemma snd_isEmbedding_of_left {X Y S : TopCat} {f : X ⟶ S} (H : IsEmbedding f) (g : Y ⟶ S) : + IsEmbedding <| ⇑(pullback.snd f g) := by + convert (homeoOfIso (asIso (pullback.snd (𝟙 S) g))).isEmbedding.comp + (pullback_map_isEmbedding (i₂ := 𝟙 Y) + f g (𝟙 S) g H (homeoOfIso (Iso.refl _)).isEmbedding (𝟙 _) rfl (by simp)) erw [← coe_comp] simp -theorem fst_embedding_of_right_embedding {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} - (H : Embedding g) : Embedding <| ⇑(pullback.fst f g) := by - convert (homeoOfIso (asIso (pullback.fst f (𝟙 S)))).embedding.comp - (pullback_map_embedding_of_embeddings (i₁ := 𝟙 X) - f g f (𝟙 _) (homeoOfIso (Iso.refl _)).embedding H (𝟙 _) rfl (by simp)) +@[deprecated (since := "2024-10-26")] +alias snd_embedding_of_left_embedding := snd_isEmbedding_of_left + +theorem fst_isEmbedding_of_right {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} + (H : IsEmbedding g) : IsEmbedding <| ⇑(pullback.fst f g) := by + convert (homeoOfIso (asIso (pullback.fst f (𝟙 S)))).isEmbedding.comp + (pullback_map_isEmbedding (i₁ := 𝟙 X) + f g f (𝟙 _) (homeoOfIso (Iso.refl _)).isEmbedding H (𝟙 _) rfl (by simp)) erw [← coe_comp] simp -theorem embedding_of_pullback_embeddings {X Y S : TopCat} {f : X ⟶ S} {g : Y ⟶ S} (H₁ : Embedding f) - (H₂ : Embedding g) : Embedding (limit.π (cospan f g) WalkingCospan.one) := by - convert H₂.comp (snd_embedding_of_left_embedding H₁ g) - erw [← coe_comp] - rw [← limit.w _ WalkingCospan.Hom.inr] +@[deprecated (since := "2024-10-26")] +alias fst_embedding_of_right_embedding := fst_isEmbedding_of_right + +theorem isEmbedding_of_pullback {X Y S : TopCat} {f : X ⟶ S} {g : Y ⟶ S} (H₁ : IsEmbedding f) + (H₂ : IsEmbedding g) : IsEmbedding (limit.π (cospan f g) WalkingCospan.one) := by + convert H₂.comp (snd_isEmbedding_of_left H₁ g) + rw [← coe_comp, ← limit.w _ WalkingCospan.Hom.inr] rfl -theorem snd_openEmbedding_of_left_openEmbedding {X Y S : TopCat} {f : X ⟶ S} (H : OpenEmbedding f) - (g : Y ⟶ S) : OpenEmbedding <| ⇑(pullback.snd f g) := by - convert (homeoOfIso (asIso (pullback.snd (𝟙 S) g))).openEmbedding.comp - (pullback_map_openEmbedding_of_open_embeddings (i₂ := 𝟙 Y) f g (𝟙 _) g H - (homeoOfIso (Iso.refl _)).openEmbedding (𝟙 _) rfl (by simp)) +@[deprecated (since := "2024-10-26")] +alias embedding_of_pullback_embeddings := isEmbedding_of_pullback + +theorem snd_isOpenEmbedding_of_left {X Y S : TopCat} {f : X ⟶ S} (H : IsOpenEmbedding f) + (g : Y ⟶ S) : IsOpenEmbedding <| ⇑(pullback.snd f g) := by + convert (homeoOfIso (asIso (pullback.snd (𝟙 S) g))).isOpenEmbedding.comp + (pullback_map_isOpenEmbedding (i₂ := 𝟙 Y) f g (𝟙 _) g H + (homeoOfIso (Iso.refl _)).isOpenEmbedding (𝟙 _) rfl (by simp)) erw [← coe_comp] simp -theorem fst_openEmbedding_of_right_openEmbedding {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} - (H : OpenEmbedding g) : OpenEmbedding <| ⇑(pullback.fst f g) := by - convert (homeoOfIso (asIso (pullback.fst f (𝟙 S)))).openEmbedding.comp - (pullback_map_openEmbedding_of_open_embeddings (i₁ := 𝟙 X) f g f (𝟙 _) - (homeoOfIso (Iso.refl _)).openEmbedding H (𝟙 _) rfl (by simp)) +@[deprecated (since := "2024-10-18")] +alias snd_openEmbedding_of_left_openEmbedding := snd_isOpenEmbedding_of_left + +theorem fst_isOpenEmbedding_of_right {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} + (H : IsOpenEmbedding g) : IsOpenEmbedding <| ⇑(pullback.fst f g) := by + convert (homeoOfIso (asIso (pullback.fst f (𝟙 S)))).isOpenEmbedding.comp + (pullback_map_isOpenEmbedding (i₁ := 𝟙 X) f g f (𝟙 _) + (homeoOfIso (Iso.refl _)).isOpenEmbedding H (𝟙 _) rfl (by simp)) erw [← coe_comp] simp +@[deprecated (since := "2024-10-18")] +alias fst_openEmbedding_of_right_openEmbedding := fst_isOpenEmbedding_of_right + /-- If `X ⟶ S`, `Y ⟶ S` are open embeddings, then so is `X ×ₛ Y ⟶ S`. -/ -theorem openEmbedding_of_pullback_open_embeddings {X Y S : TopCat} {f : X ⟶ S} {g : Y ⟶ S} - (H₁ : OpenEmbedding f) (H₂ : OpenEmbedding g) : - OpenEmbedding (limit.π (cospan f g) WalkingCospan.one) := by - convert H₂.comp (snd_openEmbedding_of_left_openEmbedding H₁ g) - erw [← coe_comp] - rw [← limit.w _ WalkingCospan.Hom.inr] +theorem isOpenEmbedding_of_pullback_open_embeddings {X Y S : TopCat} {f : X ⟶ S} {g : Y ⟶ S} + (H₁ : IsOpenEmbedding f) (H₂ : IsOpenEmbedding g) : + IsOpenEmbedding (limit.π (cospan f g) WalkingCospan.one) := by + convert H₂.comp (snd_isOpenEmbedding_of_left H₁ g) + rw [← coe_comp, ← limit.w _ WalkingCospan.Hom.inr] rfl +@[deprecated (since := "2024-10-18")] +alias openEmbedding_of_pullback_open_embeddings := isOpenEmbedding_of_pullback_open_embeddings + theorem fst_iso_of_right_embedding_range_subset {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} - (hg : Embedding g) (H : Set.range f ⊆ Set.range g) : + (hg : IsEmbedding g) (H : Set.range f ⊆ Set.range g) : IsIso (pullback.fst f g) := by let esto : (pullback f g : TopCat) ≃ₜ X := - (Homeomorph.ofEmbedding _ (fst_embedding_of_right_embedding f hg)).trans + (Homeomorph.ofIsEmbedding _ (fst_isEmbedding_of_right f hg)).trans { toFun := Subtype.val invFun := fun x => ⟨x, by @@ -361,10 +387,10 @@ theorem fst_iso_of_right_embedding_range_subset {X Y S : TopCat} (f : X ⟶ S) { right_inv := fun x => rfl } convert (isoOfHomeo esto).isIso_hom -theorem snd_iso_of_left_embedding_range_subset {X Y S : TopCat} {f : X ⟶ S} (hf : Embedding f) +theorem snd_iso_of_left_embedding_range_subset {X Y S : TopCat} {f : X ⟶ S} (hf : IsEmbedding f) (g : Y ⟶ S) (H : Set.range g ⊆ Set.range f) : IsIso (pullback.snd f g) := by let esto : (pullback f g : TopCat) ≃ₜ Y := - (Homeomorph.ofEmbedding _ (snd_embedding_of_left_embedding hf g)).trans + (Homeomorph.ofIsEmbedding _ (snd_isEmbedding_of_left hf g)).trans { toFun := Subtype.val invFun := fun x => ⟨x, by diff --git a/Mathlib/Topology/Category/TopCat/OpenNhds.lean b/Mathlib/Topology/Category/TopCat/OpenNhds.lean index d9325ee6922be..fdfe88f737c64 100644 --- a/Mathlib/Topology/Category/TopCat/OpenNhds.lean +++ b/Mathlib/Topology/Category/TopCat/OpenNhds.lean @@ -86,8 +86,11 @@ def inclusion (x : X) : OpenNhds x ⥤ Opens X := theorem inclusion_obj (x : X) (U) (p) : (inclusion x).obj ⟨U, p⟩ = U := rfl -theorem openEmbedding {x : X} (U : OpenNhds x) : OpenEmbedding U.1.inclusion' := - U.1.openEmbedding +theorem isOpenEmbedding {x : X} (U : OpenNhds x) : IsOpenEmbedding U.1.inclusion' := + U.1.isOpenEmbedding + +@[deprecated (since := "2024-10-18")] +alias openEmbedding := isOpenEmbedding /-- The preimage functor from neighborhoods of `f x` to neighborhoods of `x`. -/ def map (x : X) : OpenNhds (f x) ⥤ OpenNhds x where @@ -145,7 +148,7 @@ def functorNhds (h : IsOpenMap f) (x : X) : OpenNhds x ⥤ OpenNhds (f x) where /-- An open map `f : X ⟶ Y` induces an adjunction between `OpenNhds x` and `OpenNhds (f x)`. -/ def adjunctionNhds (h : IsOpenMap f) (x : X) : IsOpenMap.functorNhds h x ⊣ OpenNhds.map f x where - unit := { app := fun U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } - counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } + unit := { app := fun _ => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } + counit := { app := fun _ => homOfLE fun _ ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } end IsOpenMap diff --git a/Mathlib/Topology/Category/TopCat/Opens.lean b/Mathlib/Topology/Category/TopCat/Opens.lean index 988c19dba4faa..bbb4a6f5369a9 100644 --- a/Mathlib/Topology/Category/TopCat/Opens.lean +++ b/Mathlib/Topology/Category/TopCat/Opens.lean @@ -99,9 +99,7 @@ realising each open set as a topological space itself. -/ def toTopCat (X : TopCat.{u}) : Opens X ⥤ TopCat where obj U := ⟨U, inferInstance⟩ - map i := - ⟨fun x => ⟨x.1, i.le x.2⟩, - (Embedding.continuous_iff embedding_subtype_val).2 continuous_induced_dom⟩ + map i := ⟨fun x ↦ ⟨x.1, i.le x.2⟩, IsEmbedding.subtypeVal.continuous_iff.2 continuous_induced_dom⟩ @[simp] theorem toTopCat_map (X : TopCat.{u}) {U V : Opens X} {f : U ⟶ V} {x} {h} : @@ -119,20 +117,23 @@ def inclusion' {X : TopCat.{u}} (U : Opens X) : (toTopCat X).obj U ⟶ X where theorem coe_inclusion' {X : TopCat} {U : Opens X} : (inclusion' U : U → X) = Subtype.val := rfl -theorem openEmbedding {X : TopCat.{u}} (U : Opens X) : OpenEmbedding (inclusion' U) := - IsOpen.openEmbedding_subtype_val U.2 +theorem isOpenEmbedding {X : TopCat.{u}} (U : Opens X) : IsOpenEmbedding (inclusion' U) := + IsOpen.isOpenEmbedding_subtypeVal U.2 + +@[deprecated (since := "2024-10-18")] +alias openEmbedding := isOpenEmbedding /-- The inclusion of the top open subset (i.e. the whole space) is an isomorphism. -/ def inclusionTopIso (X : TopCat.{u}) : (toTopCat X).obj ⊤ ≅ X where hom := inclusion' ⊤ - inv := ⟨fun x => ⟨x, trivial⟩, continuous_def.2 fun U ⟨_, hS, hSU⟩ => hSU ▸ hS⟩ + inv := ⟨fun x => ⟨x, trivial⟩, continuous_def.2 fun _ ⟨_, hS, hSU⟩ => hSU ▸ hS⟩ /-- `Opens.map f` gives the functor from open sets in Y to open set in X, given by taking preimages under f. -/ def map (f : X ⟶ Y) : Opens Y ⥤ Opens X where obj U := ⟨f ⁻¹' (U : Set Y), U.isOpen.preimage f.continuous⟩ - map i := ⟨⟨fun x h => i.le h⟩⟩ + map i := ⟨⟨fun _ h => i.le h⟩⟩ @[simp] theorem map_coe (f : X ⟶ Y) (U : Opens Y) : ((map f).obj U : Set X) = f ⁻¹' (U : Set Y) := @@ -281,8 +282,8 @@ def IsOpenMap.functor {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) : Opens X -/ def IsOpenMap.adjunction {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) : Adjunction hf.functor (TopologicalSpace.Opens.map f) where - unit := { app := fun U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } - counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } + unit := { app := fun _ => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } + counit := { app := fun _ => homOfLE fun _ ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } instance IsOpenMap.functorFullOfMono {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) [H : Mono f] : hf.functor.Full where @@ -294,20 +295,26 @@ instance IsOpenMap.functorFullOfMono {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMa instance IsOpenMap.functor_faithful {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) : hf.functor.Faithful where -lemma OpenEmbedding.functor_obj_injective {X Y : TopCat} {f : X ⟶ Y} (hf : OpenEmbedding f) : +lemma IsOpenEmbedding.functor_obj_injective {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenEmbedding f) : Function.Injective hf.isOpenMap.functor.obj := fun _ _ e ↦ Opens.ext (Set.image_injective.mpr hf.inj (congr_arg (↑· : Opens Y → Set Y) e)) +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.functor_obj_injective := IsOpenEmbedding.functor_obj_injective + namespace TopologicalSpace.Opens open TopologicalSpace @[simp] -theorem openEmbedding_obj_top {X : TopCat} (U : Opens X) : - U.openEmbedding.isOpenMap.functor.obj ⊤ = U := by +theorem isOpenEmbedding_obj_top {X : TopCat} (U : Opens X) : + U.isOpenEmbedding.isOpenMap.functor.obj ⊤ = U := by ext1 exact Set.image_univ.trans Subtype.range_coe +@[deprecated (since := "2024-10-18")] +alias openEmbedding_obj_top := isOpenEmbedding_obj_top + @[simp] theorem inclusion'_map_eq_top {X : TopCat} (U : Opens X) : (Opens.map U.inclusion').obj U = ⊤ := by ext1 @@ -315,10 +322,10 @@ theorem inclusion'_map_eq_top {X : TopCat} (U : Opens X) : (Opens.map U.inclusio @[simp] theorem adjunction_counit_app_self {X : TopCat} (U : Opens X) : - U.openEmbedding.isOpenMap.adjunction.counit.app U = eqToHom (by simp) := Subsingleton.elim _ _ + U.isOpenEmbedding.isOpenMap.adjunction.counit.app U = eqToHom (by simp) := Subsingleton.elim _ _ theorem inclusion'_top_functor (X : TopCat) : - (@Opens.openEmbedding X ⊤).isOpenMap.functor = map (inclusionTopIso X).inv := by + (@Opens.isOpenEmbedding X ⊤).isOpenMap.functor = map (inclusionTopIso X).inv := by refine CategoryTheory.Functor.ext ?_ ?_ · intro U ext x @@ -335,35 +342,35 @@ theorem functor_obj_map_obj {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) (U : exact ⟨x, hx, rfl⟩ -- Porting note: added to ease the proof of `functor_map_eq_inf` -lemma set_range_forget_map_inclusion' {X : TopCat} (U : Opens X) : - Set.range ((forget TopCat).map (inclusion' U)) = (U : Set X) := by +lemma set_range_inclusion' {X : TopCat} (U : Opens X) : + Set.range (inclusion' U) = (U : Set X) := by ext x constructor · rintro ⟨x, rfl⟩ exact x.2 · intro h exact ⟨⟨x, h⟩, rfl⟩ +@[deprecated (since := "2024-09-07")] alias set_range_forget_map_inclusion' := set_range_inclusion' @[simp] theorem functor_map_eq_inf {X : TopCat} (U V : Opens X) : - U.openEmbedding.isOpenMap.functor.obj ((Opens.map U.inclusion').obj V) = V ⊓ U := by + U.isOpenEmbedding.isOpenMap.functor.obj ((Opens.map U.inclusion').obj V) = V ⊓ U := by ext1 - refine Set.image_preimage_eq_inter_range.trans ?_ - erw [set_range_forget_map_inclusion' U] - rfl + simp only [IsOpenMap.functor_obj_coe, map_coe, coe_inf, + Set.image_preimage_eq_inter_range, set_range_inclusion' U] -theorem map_functor_eq' {X U : TopCat} (f : U ⟶ X) (hf : OpenEmbedding f) (V) : +theorem map_functor_eq' {X U : TopCat} (f : U ⟶ X) (hf : IsOpenEmbedding f) (V) : ((Opens.map f).obj <| hf.isOpenMap.functor.obj V) = V := Opens.ext <| Set.preimage_image_eq _ hf.inj @[simp] theorem map_functor_eq {X : TopCat} {U : Opens X} (V : Opens U) : - ((Opens.map U.inclusion').obj <| U.openEmbedding.isOpenMap.functor.obj V) = V := - TopologicalSpace.Opens.map_functor_eq' _ U.openEmbedding V + ((Opens.map U.inclusion').obj <| U.isOpenEmbedding.isOpenMap.functor.obj V) = V := + TopologicalSpace.Opens.map_functor_eq' _ U.isOpenEmbedding V @[simp] theorem adjunction_counit_map_functor {X : TopCat} {U : Opens X} (V : Opens U) : - U.openEmbedding.isOpenMap.adjunction.counit.app (U.openEmbedding.isOpenMap.functor.obj V) = + U.isOpenEmbedding.isOpenMap.adjunction.counit.app (U.isOpenEmbedding.isOpenMap.functor.obj V) = eqToHom (by dsimp; rw [map_functor_eq V]) := by subsingleton diff --git a/Mathlib/Topology/Category/TopCat/Yoneda.lean b/Mathlib/Topology/Category/TopCat/Yoneda.lean index 65ed0d1e00d83..d898269d9ac23 100644 --- a/Mathlib/Topology/Category/TopCat/Yoneda.lean +++ b/Mathlib/Topology/Category/TopCat/Yoneda.lean @@ -59,7 +59,7 @@ theorem piComparison_fac {α : Type} (X : α → TopCat) : /-- The universe polymorphic Yoneda presheaf on `TopCat` preserves finite products. -/ noncomputable instance : PreservesFiniteProducts (yonedaPresheaf'.{w, w'} Y) where - preserves J _ := + preserves _ _ := { preservesLimit := fun {K} => have : ∀ {α : Type} (X : α → TopCat), PreservesLimit (Discrete.functor (fun x ↦ op (X x))) (yonedaPresheaf'.{w, w'} Y) := fun X => @PreservesProduct.ofIsoComparison _ _ _ _ diff --git a/Mathlib/Topology/Category/TopCommRingCat.lean b/Mathlib/Topology/Category/TopCommRingCat.lean index b6734c03f35c7..d8e2fce858d9a 100644 --- a/Mathlib/Topology/Category/TopCommRingCat.lean +++ b/Mathlib/Topology/Category/TopCommRingCat.lean @@ -54,7 +54,7 @@ instance : ConcreteCategory TopCommRingCat.{u} where map := fun f => f.val } -- Porting note: Old proof was `forget_faithful := { }` forget_faithful := - { map_injective := fun {_ _ a b} h => Subtype.ext <| RingHom.coe_inj h } + { map_injective := fun {_ _ _ _} h => Subtype.ext <| RingHom.coe_inj h } /-- Construct a bundled `TopCommRingCat` from the underlying type and the appropriate typeclasses. -/ diff --git a/Mathlib/Topology/Category/UniformSpace.lean b/Mathlib/Topology/Category/UniformSpace.lean index 0b3083f80e4e6..dc6f68256827c 100644 --- a/Mathlib/Topology/Category/UniformSpace.lean +++ b/Mathlib/Topology/Category/UniformSpace.lean @@ -191,7 +191,7 @@ noncomputable def adj : completionFunctor ⊣ forget₂ CpltSepUniformSpace Unif { homEquiv := fun X Y => { toFun := fun f => completionHom X ≫ f invFun := fun f => extensionHom f - left_inv := fun f => by dsimp; erw [extension_comp_coe] + left_inv := fun f => by dsimp; rw [extension_comp_coe] right_inv := fun f => by apply Subtype.eq; funext x; cases f exact @Completion.extension_coe _ _ _ _ _ (CpltSepUniformSpace.t0Space _) diff --git a/Mathlib/Topology/Clopen.lean b/Mathlib/Topology/Clopen.lean index c560e10009cd9..a8d606274a879 100644 --- a/Mathlib/Topology/Clopen.lean +++ b/Mathlib/Topology/Clopen.lean @@ -102,6 +102,10 @@ theorem isClopen_inter_of_disjoint_cover_clopen {s a b : Set X} (h : IsClopen s) rintro x ⟨hx₁, hx₂⟩ exact ⟨hx₁, by simpa [not_mem_of_mem_compl hx₂] using cover hx₁⟩ +theorem isClopen_of_disjoint_cover_open {a b : Set X} (cover : univ ⊆ a ∪ b) + (ha : IsOpen a) (hb : IsOpen b) (hab : Disjoint a b) : IsClopen a := + univ_inter a ▸ isClopen_inter_of_disjoint_cover_clopen isClopen_univ cover ha hb hab + @[simp] theorem isClopen_discrete [DiscreteTopology X] (s : Set X) : IsClopen s := ⟨isClosed_discrete _, isOpen_discrete _⟩ @@ -114,12 +118,15 @@ theorem isClopen_range_inr : IsClopen (range (Sum.inr : Y → X ⊕ Y)) := theorem isClopen_range_sigmaMk {X : ι → Type*} [∀ i, TopologicalSpace (X i)] {i : ι} : IsClopen (Set.range (@Sigma.mk ι X i)) := - ⟨closedEmbedding_sigmaMk.isClosed_range, openEmbedding_sigmaMk.isOpen_range⟩ + ⟨isClosedEmbedding_sigmaMk.isClosed_range, isOpenEmbedding_sigmaMk.isOpen_range⟩ -protected theorem QuotientMap.isClopen_preimage {f : X → Y} (hf : QuotientMap f) {s : Set Y} : +protected theorem IsQuotientMap.isClopen_preimage {f : X → Y} (hf : IsQuotientMap f) {s : Set Y} : IsClopen (f ⁻¹' s) ↔ IsClopen s := and_congr hf.isClosed_preimage hf.isOpen_preimage +@[deprecated (since := "2024-10-22")] +alias QuotientMap.isClopen_preimage := IsQuotientMap.isClopen_preimage + theorem continuous_boolIndicator_iff_isClopen (U : Set X) : Continuous U.boolIndicator ↔ IsClopen U := by rw [continuous_bool_rng true, preimage_boolIndicator_true] diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index 0338dd8e2d361..82c9d0719beea 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Reid Barton. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Reid Barton -/ +import Mathlib.Topology.Hom.ContinuousEval import Mathlib.Topology.ContinuousMap.Basic /-! @@ -77,27 +78,50 @@ lemma continuous_compactOpen {f : X → C(Y, Z)} : section Functorial /-- `C(X, ·)` is a functor. -/ -theorem continuous_comp (g : C(Y, Z)) : Continuous (ContinuousMap.comp g : C(X, Y) → C(X, Z)) := +theorem continuous_postcomp (g : C(Y, Z)) : Continuous (ContinuousMap.comp g : C(X, Y) → C(X, Z)) := continuous_compactOpen.2 fun _K hK _U hU ↦ isOpen_setOf_mapsTo hK (hU.preimage g.2) +@[deprecated (since := "2024-10-19")] alias continuous_comp := continuous_postcomp + /-- If `g : C(Y, Z)` is a topology inducing map, then the composition `ContinuousMap.comp g : C(X, Y) → C(X, Z)` is a topology inducing map too. -/ -theorem inducing_comp (g : C(Y, Z)) (hg : Inducing g) : Inducing (g.comp : C(X, Y) → C(X, Z)) where - induced := by +theorem isInducing_postcomp (g : C(Y, Z)) (hg : IsInducing g) : + IsInducing (g.comp : C(X, Y) → C(X, Z)) where + eq_induced := by simp only [compactOpen_eq, induced_generateFrom_eq, image_image2, hg.setOf_isOpen, image2_image_right, MapsTo, mem_preimage, preimage_setOf_eq, comp_apply] +@[deprecated (since := "2024-10-28")] alias inducing_postcomp := isInducing_postcomp + +@[deprecated (since := "2024-10-19")] alias inducing_comp := isInducing_postcomp + /-- If `g : C(Y, Z)` is a topological embedding, then the composition `ContinuousMap.comp g : C(X, Y) → C(X, Z)` is an embedding too. -/ -theorem embedding_comp (g : C(Y, Z)) (hg : Embedding g) : Embedding (g.comp : C(X, Y) → C(X, Z)) := - ⟨inducing_comp g hg.1, fun _ _ ↦ (cancel_left hg.2).1⟩ +theorem isEmbedding_postcomp (g : C(Y, Z)) (hg : IsEmbedding g) : + IsEmbedding (g.comp : C(X, Y) → C(X, Z)) := + ⟨isInducing_postcomp g hg.1, fun _ _ ↦ (cancel_left hg.2).1⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_postcomp := isEmbedding_postcomp + +@[deprecated (since := "2024-10-19")] alias embedding_comp := isEmbedding_postcomp /-- `C(·, Z)` is a functor. -/ -@[fun_prop] -theorem continuous_comp_left (f : C(X, Y)) : Continuous (fun g => g.comp f : C(Y, Z) → C(X, Z)) := +@[continuity, fun_prop] +theorem continuous_precomp (f : C(X, Y)) : Continuous (fun g => g.comp f : C(Y, Z) → C(X, Z)) := continuous_compactOpen.2 fun K hK U hU ↦ by simpa only [mapsTo_image_iff] using isOpen_setOf_mapsTo (hK.image f.2) hU +@[deprecated (since := "2024-10-19")] alias continuous_comp_left := continuous_precomp + +variable (Z) in +/-- Precomposition by a continuous map is itself a continuous map between spaces of continuous maps. +-/ +@[simps apply] +def compRightContinuousMap (f : C(X, Y)) : + C(C(Y, Z), C(X, Z)) where + toFun g := g.comp f + /-- Any pair of homeomorphisms `X ≃ₜ Z` and `Y ≃ₜ T` gives rise to a homeomorphism `C(X, Y) ≃ₜ C(Z, T)`. -/ protected def _root_.Homeomorph.arrowCongr (φ : X ≃ₜ Z) (ψ : Y ≃ₜ T) : @@ -106,8 +130,16 @@ protected def _root_.Homeomorph.arrowCongr (φ : X ≃ₜ Z) (ψ : Y ≃ₜ T) : invFun f := .comp ψ.symm <| f.comp φ left_inv f := ext fun _ ↦ ψ.left_inv (f _) |>.trans <| congrArg f <| φ.left_inv _ right_inv f := ext fun _ ↦ ψ.right_inv (f _) |>.trans <| congrArg f <| φ.right_inv _ - continuous_toFun := continuous_comp _ |>.comp <| continuous_comp_left _ - continuous_invFun := continuous_comp _ |>.comp <| continuous_comp_left _ + continuous_toFun := continuous_postcomp _ |>.comp <| continuous_precomp _ + continuous_invFun := continuous_postcomp _ |>.comp <| continuous_precomp _ + +variable (Z) in +/-- Precomposition by a homeomorphism is itself a homeomorphism between spaces of continuous maps. +-/ +@[deprecated Homeomorph.arrowCongr (since := "2024-10-19")] +def compRightHomeomorph (f : X ≃ₜ Y) : + C(Y, Z) ≃ₜ C(X, Z) := + .arrowCongr f.symm (.refl _) variable [LocallyCompactPair Y Z] @@ -160,27 +192,24 @@ section Ev /-- The evaluation map `C(X, Y) × X → Y` is continuous if `X, Y` is a locally compact pair of spaces. -/ -@[continuity] -theorem continuous_eval [LocallyCompactPair X Y] : Continuous fun p : C(X, Y) × X => p.1 p.2 := by - simp_rw [continuous_iff_continuousAt, ContinuousAt, (nhds_basis_opens _).tendsto_right_iff] - rintro ⟨f, x⟩ U ⟨hx : f x ∈ U, hU : IsOpen U⟩ - rcases exists_mem_nhds_isCompact_mapsTo f.continuous (hU.mem_nhds hx) with ⟨K, hxK, hK, hKU⟩ - filter_upwards [prod_mem_nhds (eventually_mapsTo hK hU hKU) hxK] using fun _ h ↦ h.1 h.2 +instance [LocallyCompactPair X Y] : ContinuousEval C(X, Y) X Y where + continuous_eval := by + simp_rw [continuous_iff_continuousAt, ContinuousAt, (nhds_basis_opens _).tendsto_right_iff] + rintro ⟨f, x⟩ U ⟨hx : f x ∈ U, hU : IsOpen U⟩ + rcases exists_mem_nhds_isCompact_mapsTo f.continuous (hU.mem_nhds hx) with ⟨K, hxK, hK, hKU⟩ + filter_upwards [prod_mem_nhds (eventually_mapsTo hK hU hKU) hxK] using fun _ h ↦ h.1 h.2 -/-- Evaluation of a continuous map `f` at a point `x` is continuous in `f`. +@[deprecated (since := "2024-10-01")] protected alias continuous_eval := continuous_eval -Porting note: merged `continuous_eval_const` with `continuous_eval_const'` removing unneeded -assumptions. -/ -@[continuity] -theorem continuous_eval_const (a : X) : Continuous fun f : C(X, Y) => f a := - continuous_def.2 fun U hU ↦ by simpa using isOpen_setOf_mapsTo (isCompact_singleton (x := a)) hU +instance : ContinuousEvalConst C(X, Y) X Y where + continuous_eval_const x := + continuous_def.2 fun U hU ↦ by simpa using isOpen_setOf_mapsTo isCompact_singleton hU -/-- Coercion from `C(X, Y)` with compact-open topology to `X → Y` with pointwise convergence -topology is a continuous map. +@[deprecated (since := "2024-10-01")] protected alias continuous_eval_const := continuous_eval_const -Porting note: merged `continuous_coe` with `continuous_coe'` removing unneeded assumptions. -/ +@[deprecated continuous_coeFun (since := "2024-10-01")] theorem continuous_coe : Continuous ((⇑) : C(X, Y) → (X → Y)) := - continuous_pi continuous_eval_const + continuous_coeFun lemma isClosed_setOf_mapsTo {t : Set Y} (ht : IsClosed t) (s : Set X) : IsClosed {f : C(X, Y) | MapsTo f s t} := @@ -192,7 +221,7 @@ lemma isClopen_setOf_mapsTo (hK : IsCompact K) (hU : IsClopen U) : @[norm_cast] lemma specializes_coe {f g : C(X, Y)} : ⇑f ⤳ ⇑g ↔ f ⤳ g := by - refine ⟨fun h ↦ ?_, fun h ↦ h.map continuous_coe⟩ + refine ⟨fun h ↦ ?_, fun h ↦ h.map continuous_coeFun⟩ suffices ∀ K, IsCompact K → ∀ U, IsOpen U → MapsTo g K U → MapsTo f K U by simpa [specializes_iff_pure, nhds_compactOpen] exact fun K _ U hU hg x hx ↦ (h.map (continuous_apply x)).mem_open hU (hg hx) @@ -202,7 +231,7 @@ lemma inseparable_coe {f g : C(X, Y)} : Inseparable (f : X → Y) g ↔ Insepara simp only [inseparable_iff_specializes_and, specializes_coe] instance [T0Space Y] : T0Space C(X, Y) := - t0Space_of_injective_of_continuous DFunLike.coe_injective continuous_coe + t0Space_of_injective_of_continuous DFunLike.coe_injective continuous_coeFun instance [R0Space Y] : R0Space C(X, Y) where specializes_symmetric f g h := by @@ -210,10 +239,10 @@ instance [R0Space Y] : R0Space C(X, Y) where exact h.symm instance [T1Space Y] : T1Space C(X, Y) := - t1Space_of_injective_of_continuous DFunLike.coe_injective continuous_coe + t1Space_of_injective_of_continuous DFunLike.coe_injective continuous_coeFun instance [R1Space Y] : R1Space C(X, Y) := - .of_continuous_specializes_imp continuous_coe fun _ _ ↦ specializes_coe.1 + .of_continuous_specializes_imp continuous_coeFun fun _ _ ↦ specializes_coe.1 instance [T2Space Y] : T2Space C(X, Y) := inferInstance @@ -236,7 +265,7 @@ section InfInduced /-- For any subset `s` of `X`, the restriction of continuous functions to `s` is continuous as a function from `C(X, Y)` to `C(s, Y)` with their respective compact-open topologies. -/ theorem continuous_restrict (s : Set X) : Continuous fun F : C(X, Y) => F.restrict s := - continuous_comp_left <| restrict s <| .id X + continuous_precomp <| restrict s <| .id X theorem compactOpen_le_induced (s : Set X) : (ContinuousMap.compactOpen : TopologicalSpace C(X, Y)) ≤ @@ -260,7 +289,7 @@ theorem compactOpen_eq_iInf_induced : alias compactOpen_eq_sInf_induced := compactOpen_eq_iInf_induced theorem nhds_compactOpen_eq_iInf_nhds_induced (f : C(X, Y)) : - 𝓝 f = ⨅ (s) (hs : IsCompact s), (𝓝 (f.restrict s)).comap (ContinuousMap.restrict s) := by + 𝓝 f = ⨅ (s) (_ : IsCompact s), (𝓝 (f.restrict s)).comap (ContinuousMap.restrict s) := by rw [compactOpen_eq_iInf_induced] simp only [nhds_iInf, nhds_induced] @@ -342,7 +371,7 @@ section Curry compact, then this is a homeomorphism, see `Homeomorph.curry`. -/ def curry (f : C(X × Y, Z)) : C(X, C(Y, Z)) where toFun a := ⟨Function.curry f a, f.continuous.comp <| by fun_prop⟩ - continuous_toFun := (continuous_comp f).comp continuous_coev + continuous_toFun := (continuous_postcomp f).comp continuous_coev @[simp] theorem curry_apply (f : C(X × Y, Z)) (a : X) (b : Y) : f.curry a b = f (a, b) := @@ -388,7 +417,8 @@ theorem continuous_uncurry [LocallyCompactSpace X] [LocallyCompactSpace Y] : Continuous (uncurry : C(X, C(Y, Z)) → C(X × Y, Z)) := by apply continuous_of_continuous_uncurry rw [← (Homeomorph.prodAssoc _ _ _).comp_continuous_iff'] - apply continuous_eval.comp (continuous_eval.prodMap continuous_id) + dsimp [Function.comp_def] + exact (continuous_fst.fst.eval continuous_fst.snd).eval continuous_snd /-- The family of constant maps: `Y → C(X, Y)` as a continuous map. -/ def const' : C(Y, C(X, Y)) := @@ -442,12 +472,12 @@ theorem continuousMapOfUnique_symm_apply [Unique X] (f : C(X, Y)) : end Homeomorph -section QuotientMap +section IsQuotientMap variable {X₀ X Y Z : Type*} [TopologicalSpace X₀] [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] [LocallyCompactSpace Y] {f : X₀ → X} -theorem QuotientMap.continuous_lift_prod_left (hf : QuotientMap f) {g : X × Y → Z} +theorem IsQuotientMap.continuous_lift_prod_left (hf : IsQuotientMap f) {g : X × Y → Z} (hg : Continuous fun p : X₀ × Y => g (f p.1, p.2)) : Continuous g := by let Gf : C(X₀, C(Y, Z)) := ContinuousMap.curry ⟨_, hg⟩ have h : ∀ x : X, Continuous fun y => g (x, y) := by @@ -460,11 +490,17 @@ theorem QuotientMap.continuous_lift_prod_left (hf : QuotientMap f) {g : X × Y exact Gf.continuous exact ContinuousMap.continuous_uncurry_of_continuous ⟨G, this⟩ -theorem QuotientMap.continuous_lift_prod_right (hf : QuotientMap f) {g : Y × X → Z} +@[deprecated (since := "2024-10-22")] +alias QuotientMap.continuous_lift_prod_left := IsQuotientMap.continuous_lift_prod_left + +theorem IsQuotientMap.continuous_lift_prod_right (hf : IsQuotientMap f) {g : Y × X → Z} (hg : Continuous fun p : Y × X₀ => g (p.1, f p.2)) : Continuous g := by have : Continuous fun p : X₀ × Y => g ((Prod.swap p).1, f (Prod.swap p).2) := hg.comp continuous_swap have : Continuous fun p : X₀ × Y => (g ∘ Prod.swap) (f p.1, p.2) := this exact (hf.continuous_lift_prod_left this).comp continuous_swap -end QuotientMap +@[deprecated (since := "2024-10-22")] +alias QuotientMap.continuous_lift_prod_right := IsQuotientMap.continuous_lift_prod_right + +end IsQuotientMap diff --git a/Mathlib/Topology/Compactification/OnePoint.lean b/Mathlib/Topology/Compactification/OnePoint.lean index ffe89b1a9a2a8..ab60bb393fa73 100644 --- a/Mathlib/Topology/Compactification/OnePoint.lean +++ b/Mathlib/Topology/Compactification/OnePoint.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yourong Zang, Yury Kudryashov -/ import Mathlib.Data.Fintype.Option -import Mathlib.Topology.Separation import Mathlib.Topology.Sets.Opens /-! @@ -44,7 +43,7 @@ In this section we define `OnePoint X` to be the disjoint union of `X` and `∞` -/ -variable {X : Type*} +variable {X Y : Type*} /-- The OnePoint extension of an arbitrary topological space `X` -/ def OnePoint (X : Type*) := @@ -68,6 +67,11 @@ scoped notation "∞" => OnePoint.infty /-- Coercion from `X` to `OnePoint X`. -/ @[coe, match_pattern] def some : X → OnePoint X := Option.some +@[simp] +lemma some_eq_iff (x₁ x₂ : X) : (some x₁ = some x₂) ↔ (x₁ = x₂) := by + rw [iff_eq_eq] + exact Option.some.injEq x₁ x₂ + instance : CoeTC X (OnePoint X) := ⟨some⟩ instance : Inhabited (OnePoint X) := ⟨∞⟩ @@ -108,6 +112,13 @@ protected def rec {C : OnePoint X → Sort*} (h₁ : C ∞) (h₂ : ∀ x : X, C | ∞ => h₁ | (x : X) => h₂ x +/-- An elimination principle for `OnePoint`. -/ +@[inline] protected def elim : OnePoint X → Y → (X → Y) → Y := Option.elim + +@[simp] theorem elim_infty (y : Y) (f : X → Y) : ∞.elim y f = y := rfl + +@[simp] theorem elim_some (y : Y) (f : X → Y) (x : X) : (some x).elim y f = f x := rfl + theorem isCompl_range_coe_infty : IsCompl (range ((↑) : X → OnePoint X)) {∞} := isCompl_range_some_none X @@ -187,7 +198,7 @@ instance : TopologicalSpace (OnePoint X) where rw [preimage_sUnion] exact isOpen_biUnion fun s hs => (ho s hs).2 -variable {s : Set (OnePoint X)} {t : Set X} +variable {s : Set (OnePoint X)} theorem isOpen_def : IsOpen s ↔ (∞ ∈ s → IsCompact ((↑) ⁻¹' s : Set X)ᶜ) ∧ IsOpen ((↑) ⁻¹' s : Set X) := @@ -241,28 +252,31 @@ theorem continuous_coe : Continuous ((↑) : X → OnePoint X) := theorem isOpenMap_coe : IsOpenMap ((↑) : X → OnePoint X) := fun _ => isOpen_image_coe.2 -theorem openEmbedding_coe : OpenEmbedding ((↑) : X → OnePoint X) := - openEmbedding_of_continuous_injective_open continuous_coe coe_injective isOpenMap_coe +theorem isOpenEmbedding_coe : IsOpenEmbedding ((↑) : X → OnePoint X) := + isOpenEmbedding_of_continuous_injective_open continuous_coe coe_injective isOpenMap_coe + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_coe := isOpenEmbedding_coe theorem isOpen_range_coe : IsOpen (range ((↑) : X → OnePoint X)) := - openEmbedding_coe.isOpen_range + isOpenEmbedding_coe.isOpen_range theorem isClosed_infty : IsClosed ({∞} : Set (OnePoint X)) := by rw [← compl_range_coe, isClosed_compl_iff] exact isOpen_range_coe theorem nhds_coe_eq (x : X) : 𝓝 ↑x = map ((↑) : X → OnePoint X) (𝓝 x) := - (openEmbedding_coe.map_nhds_eq x).symm + (isOpenEmbedding_coe.map_nhds_eq x).symm theorem nhdsWithin_coe_image (s : Set X) (x : X) : 𝓝[(↑) '' s] (x : OnePoint X) = map (↑) (𝓝[s] x) := - (openEmbedding_coe.toEmbedding.map_nhdsWithin_eq _ _).symm + (isOpenEmbedding_coe.isEmbedding.map_nhdsWithin_eq _ _).symm theorem nhdsWithin_coe (s : Set (OnePoint X)) (x : X) : 𝓝[s] ↑x = map (↑) (𝓝[(↑) ⁻¹' s] x) := - (openEmbedding_coe.map_nhdsWithin_preimage_eq _ _).symm + (isOpenEmbedding_coe.map_nhdsWithin_preimage_eq _ _).symm theorem comap_coe_nhds (x : X) : comap ((↑) : X → OnePoint X) (𝓝 x) = 𝓝 x := - (openEmbedding_coe.toInducing.nhds_eq_comap x).symm + (isOpenEmbedding_coe.isInducing.nhds_eq_comap x).symm /-- If `x` is not an isolated point of `X`, then `x : OnePoint X` is not an isolated point of `OnePoint X`. -/ @@ -393,7 +407,7 @@ noncomputable def continuousMapDiscreteEquiv (Y : Type*) [DiscreteTopology X] [T ⟨fun x ↦ f x, ⟨f ∞, continuous_iff_from_discrete f |>.mp <| map_continuous f⟩⟩ exact Classical.choose_spec f'.property · simp - right_inv f := rfl + right_inv _ := rfl lemma continuous_iff_from_nat {Y : Type*} [TopologicalSpace Y] (f : OnePoint ℕ → Y) : Continuous f ↔ Tendsto (fun x : ℕ ↦ f x) atTop (𝓝 (f ∞)) := by @@ -427,18 +441,18 @@ theorem denseRange_coe [NoncompactSpace X] : DenseRange ((↑) : X → OnePoint exact dense_compl_singleton _ theorem isDenseEmbedding_coe [NoncompactSpace X] : IsDenseEmbedding ((↑) : X → OnePoint X) := - { openEmbedding_coe with dense := denseRange_coe } + { isOpenEmbedding_coe with dense := denseRange_coe } @[deprecated (since := "2024-09-30")] alias denseEmbedding_coe := isDenseEmbedding_coe @[simp, norm_cast] theorem specializes_coe {x y : X} : (x : OnePoint X) ⤳ y ↔ x ⤳ y := - openEmbedding_coe.toInducing.specializes_iff + isOpenEmbedding_coe.isInducing.specializes_iff @[simp, norm_cast] theorem inseparable_coe {x y : X} : Inseparable (x : OnePoint X) y ↔ Inseparable x y := - openEmbedding_coe.toInducing.inseparable_iff + isOpenEmbedding_coe.isInducing.inseparable_iff theorem not_specializes_infty_coe {x : X} : ¬Specializes ∞ (x : OnePoint X) := isClosed_infty.not_specializes rfl (coe_ne_infty x) @@ -538,6 +552,51 @@ instance (X : Type*) [TopologicalSpace X] [DiscreteTopology X] : rw [OnePoint.isOpen_iff_of_not_mem] exacts [isOpen_discrete _, (Option.some_ne_none val).symm] +section Uniqueness + +variable [TopologicalSpace Y] [T2Space Y] [CompactSpace Y] + (y : Y) (f : X → Y) (hf : IsEmbedding f) (hy : range f = {y}ᶜ) + +open scoped Classical in +/-- If `f` embeds `X` into a compact Hausdorff space `Y`, and has exactly one point outside its +range, then `(Y, f)` is the one-point compactification of `X`. -/ +noncomputable def equivOfIsEmbeddingOfRangeEq : + OnePoint X ≃ₜ Y := + have _i := hf.t2Space + have : Tendsto f (coclosedCompact X) (𝓝 y) := by + rw [coclosedCompact_eq_cocompact, hasBasis_cocompact.tendsto_left_iff] + intro N hN + obtain ⟨U, hU₁, hU₂, hU₃⟩ := mem_nhds_iff.mp hN + refine ⟨f⁻¹' Uᶜ, ?_, by simpa using (mapsTo_preimage f U).mono_right hU₁⟩ + rw [hf.isCompact_iff, image_preimage_eq_iff.mpr (by simpa [hy])] + exact (isClosed_compl_iff.mpr hU₂).isCompact + let e : OnePoint X ≃ Y := + { toFun := fun p ↦ p.elim y f + invFun := fun q ↦ if hq : q = y then ∞ else ↑(show q ∈ range f from by simpa [hy]).choose + left_inv := fun p ↦ by + induction' p using OnePoint.rec with p + · simp + · have hp : f p ≠ y := by simpa [hy] using mem_range_self (f := f) p + simpa [hp] using hf.injective (mem_range_self p).choose_spec + right_inv := fun q ↦ by + rcases eq_or_ne q y with rfl | hq + · simp + · have hq' : q ∈ range f := by simpa [hy] + simpa [hq] using hq'.choose_spec } + Continuous.homeoOfEquivCompactToT2 <| (continuous_iff e).mpr ⟨this, hf.continuous⟩ + +@[simp] +lemma equivOfIsEmbeddingOfRangeEq_apply_coe (x : X) : + equivOfIsEmbeddingOfRangeEq y f hf hy x = f x := + rfl + +@[simp] +lemma equivOfIsEmbeddingOfRangeEq_apply_infty : + equivOfIsEmbeddingOfRangeEq y f hf hy ∞ = y := + rfl + +end Uniqueness + end OnePoint /-- A concrete counterexample shows that `Continuous.homeoOfEquivCompactToT2` diff --git a/Mathlib/Topology/Compactification/OnePointEquiv.lean b/Mathlib/Topology/Compactification/OnePointEquiv.lean new file mode 100644 index 0000000000000..4282e6d8b60e4 --- /dev/null +++ b/Mathlib/Topology/Compactification/OnePointEquiv.lean @@ -0,0 +1,72 @@ +/- +Copyright (c) 2024 Bjørn Kjos-Hanssen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bjørn Kjos-Hanssen, Oliver Nash +-/ +import Mathlib.LinearAlgebra.Projectivization.Basic +import Mathlib.Topology.Compactification.OnePoint + +/-! +# One-point compactification and projectivization + +We construct a set-theoretic equivalence between +`OnePoint K` and the projectivization `ℙ K (K × K)` for an arbitrary division ring `K`. + +TODO: Add the extension of this equivalence to a homeomorphism in the case `K = ℝ`, +where `OnePoint ℝ` gets the topology of one-point compactification. + + +## Main definitions and results + +* `OnePoint.equivProjectivization` : the equivalence `OnePoint K ≃ ℙ K (K × K)`. + +## Tags + +one-point extension, projectivization +-/ + +open scoped LinearAlgebra.Projectivization OnePoint +open Projectivization + +namespace OnePoint +variable (K : Type*) [DivisionRing K] [DecidableEq K] + +/-- The one-point compactification of a division ring `K` is equivalent to + the projectivivization `ℙ K (K × K)`. -/ +def equivProjectivization : + OnePoint K ≃ ℙ K (K × K) where + toFun p := Option.elim p (mk K (1, 0) (by simp)) (fun t ↦ mk K (t, 1) (by simp)) + invFun p := by + refine Projectivization.lift + (fun u : {v : K × K // v ≠ 0} ↦ if u.1.2 ≠ 0 then ((u.1.2)⁻¹ * u.1.1) else ∞) ?_ p + rintro ⟨-, hv⟩ ⟨⟨x, y⟩, hw⟩ t rfl + have ht : t ≠ 0 := by rintro rfl; simp at hv + by_cases h₀ : y = 0 <;> simp [h₀, ht, mul_assoc] + left_inv p := by cases p <;> simp [OnePoint.infty, OnePoint.some] + right_inv p := by + induction' p using ind with p hp + obtain ⟨x, y⟩ := p + by_cases h₀ : y = 0 <;> + simp only [Option.elim, ne_eq, ite_not, h₀, Projectivization.lift_mk, reduceIte] + · have h₀' : x ≠ 0 := by aesop + simp only [mk_eq_mk_iff, Prod.smul_mk, smul_zero, Prod.mk.injEq, and_true] + exact ⟨Units.mk0 _ (inv_ne_zero h₀'), by simp [h₀']⟩ + · simp only [mk_eq_mk_iff, Prod.smul_mk, Prod.mk.injEq] + exact ⟨Units.mk0 _ (inv_ne_zero h₀), by simp [h₀]⟩ + +@[simp] +lemma equivProjectivization_apply_infinity : + equivProjectivization K ∞ = mk K ⟨1, 0⟩ (by simp) := + rfl + +@[simp] +lemma equivProjectivization_apply_coe (t : K) : + equivProjectivization K t = mk K ⟨t, 1⟩ (by simp) := + rfl + +@[simp] +lemma equivProjectivization_symm_apply_mk (x y : K) (h : (x, y) ≠ 0) : + (equivProjectivization K).symm (mk K ⟨x, y⟩ h) = if y = 0 then ∞ else y⁻¹ * x := by + simp [equivProjectivization] + +end OnePoint diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index b83613bdfbf38..e5b37b93acd10 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov -/ -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Tendsto import Mathlib.Topology.Bases import Mathlib.Data.Set.Accumulate import Mathlib.Topology.Bornology.Basic @@ -222,7 +222,7 @@ theorem IsCompact.disjoint_nhdsSet_right {l : Filter X} (hs : IsCompact s) : -- Porting note (#11215): TODO: reformulate using `Disjoint` /-- For every directed family of closed sets whose intersection avoids a compact set, there exists a single element of the family which itself avoids this compact set. -/ -theorem IsCompact.elim_directed_family_closed {ι : Type v} [hι : Nonempty ι] (hs : IsCompact s) +theorem IsCompact.elim_directed_family_closed {ι : Type v} [Nonempty ι] (hs : IsCompact s) (t : ι → Set X) (htc : ∀ i, IsClosed (t i)) (hst : (s ∩ ⋂ i, t i) = ∅) (hdt : Directed (· ⊇ ·) t) : ∃ i : ι, s ∩ t i = ∅ := let ⟨t, ht⟩ := @@ -241,7 +241,7 @@ there exists a finite subfamily whose intersection avoids this compact set. -/ theorem IsCompact.elim_finite_subfamily_closed {ι : Type v} (hs : IsCompact s) (t : ι → Set X) (htc : ∀ i, IsClosed (t i)) (hst : (s ∩ ⋂ i, t i) = ∅) : ∃ u : Finset ι, (s ∩ ⋂ i ∈ u, t i) = ∅ := - hs.elim_directed_family_closed _ (fun t ↦ isClosed_biInter fun _ _ ↦ htc _) + hs.elim_directed_family_closed _ (fun _ ↦ isClosed_biInter fun _ _ ↦ htc _) (by rwa [← iInter_eq_iInter_finset]) (directed_of_isDirected_le fun _ _ h ↦ biInter_subset_biInter_left h) @@ -378,7 +378,7 @@ theorem IsCompact.mem_nhdsSet_prod_of_forall {K : Set X} {Y} {l : Filter Y} {s : theorem IsCompact.nhdsSet_prod_eq_biSup {K : Set X} (hK : IsCompact K) {Y} (l : Filter Y) : (𝓝ˢ K) ×ˢ l = ⨆ x ∈ K, 𝓝 x ×ˢ l := le_antisymm (fun s hs ↦ hK.mem_nhdsSet_prod_of_forall <| by simpa using hs) - (iSup₂_le fun x hx ↦ prod_mono (nhds_le_nhdsSet hx) le_rfl) + (iSup₂_le fun _ hx ↦ prod_mono (nhds_le_nhdsSet hx) le_rfl) theorem IsCompact.prod_nhdsSet_eq_biSup {K : Set Y} (hK : IsCompact K) {X} (l : Filter X) : l ×ˢ (𝓝ˢ K) = ⨆ y ∈ K, l ×ˢ 𝓝 y := by @@ -435,7 +435,7 @@ theorem isCompact_empty : IsCompact (∅ : Set X) := fun _f hnf hsf => Not.elim hnf.ne <| empty_mem_iff_bot.1 <| le_principal_iff.1 hsf @[simp] -theorem isCompact_singleton {x : X} : IsCompact ({x} : Set X) := fun f hf hfa => +theorem isCompact_singleton {x : X} : IsCompact ({x} : Set X) := fun _ hf hfa => ⟨x, rfl, ClusterPt.of_le_nhds' (hfa.trans <| by simpa only [principal_singleton] using pure_le_nhds x) hf⟩ @@ -897,51 +897,71 @@ theorem exists_subset_nhds_of_compactSpace [CompactSpace X] [Nonempty ι] (hU : ∀ x ∈ ⋂ i, V i, U ∈ 𝓝 x) : ∃ i, V i ⊆ U := exists_subset_nhds_of_isCompact' hV (fun i => (hV_closed i).isCompact) hV_closed hU -/-- If `f : X → Y` is an `Inducing` map, the image `f '' s` of a set `s` is compact +/-- If `f : X → Y` is an inducing map, the image `f '' s` of a set `s` is compact if and only if `s` is compact. -/ -theorem Inducing.isCompact_iff {f : X → Y} (hf : Inducing f) : +theorem IsInducing.isCompact_iff {f : X → Y} (hf : IsInducing f) : IsCompact s ↔ IsCompact (f '' s) := by refine ⟨fun hs => hs.image hf.continuous, fun hs F F_ne_bot F_le => ?_⟩ obtain ⟨_, ⟨x, x_in : x ∈ s, rfl⟩, hx : ClusterPt (f x) (map f F)⟩ := hs ((map_mono F_le).trans_eq map_principal) exact ⟨x, x_in, hf.mapClusterPt_iff.1 hx⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.isCompact_iff := IsInducing.isCompact_iff + /-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is compact if and only if `s` is compact. -/ -theorem Embedding.isCompact_iff {f : X → Y} (hf : Embedding f) : - IsCompact s ↔ IsCompact (f '' s) := hf.toInducing.isCompact_iff +theorem IsEmbedding.isCompact_iff {f : X → Y} (hf : IsEmbedding f) : + IsCompact s ↔ IsCompact (f '' s) := hf.isInducing.isCompact_iff + +@[deprecated (since := "2024-10-26")] +alias Embedding.isCompact_iff := IsEmbedding.isCompact_iff /-- The preimage of a compact set under an inducing map is a compact set. -/ -theorem Inducing.isCompact_preimage {f : X → Y} (hf : Inducing f) (hf' : IsClosed (range f)) +theorem IsInducing.isCompact_preimage {f : X → Y} (hf : IsInducing f) (hf' : IsClosed (range f)) {K : Set Y} (hK : IsCompact K) : IsCompact (f ⁻¹' K) := by replace hK := hK.inter_right hf' rwa [hf.isCompact_iff, image_preimage_eq_inter_range] -lemma Inducing.isCompact_preimage_iff {f : X → Y} (hf : Inducing f) {K : Set Y} +@[deprecated (since := "2024-10-28")] +alias Inducing.isCompact_preimage := IsInducing.isCompact_preimage + +lemma IsInducing.isCompact_preimage_iff {f : X → Y} (hf : IsInducing f) {K : Set Y} (Kf : K ⊆ range f) : IsCompact (f ⁻¹' K) ↔ IsCompact K := by rw [hf.isCompact_iff, image_preimage_eq_of_subset Kf] +@[deprecated (since := "2024-10-28")] +alias Inducing.isCompact_preimage_iff := IsInducing.isCompact_preimage_iff + /-- The preimage of a compact set in the image of an inducing map is compact. -/ -lemma Inducing.isCompact_preimage' {f : X → Y} (hf : Inducing f) {K : Set Y} +lemma IsInducing.isCompact_preimage' {f : X → Y} (hf : IsInducing f) {K : Set Y} (hK : IsCompact K) (Kf : K ⊆ range f) : IsCompact (f ⁻¹' K) := (hf.isCompact_preimage_iff Kf).2 hK +@[deprecated (since := "2024-10-28")] +alias Inducing.isCompact_preimage' := IsInducing.isCompact_preimage' + /-- The preimage of a compact set under a closed embedding is a compact set. -/ -theorem ClosedEmbedding.isCompact_preimage {f : X → Y} (hf : ClosedEmbedding f) +theorem IsClosedEmbedding.isCompact_preimage {f : X → Y} (hf : IsClosedEmbedding f) {K : Set Y} (hK : IsCompact K) : IsCompact (f ⁻¹' K) := - hf.toInducing.isCompact_preimage (hf.isClosed_range) hK + hf.isInducing.isCompact_preimage (hf.isClosed_range) hK + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.isCompact_preimage := IsClosedEmbedding.isCompact_preimage /-- A closed embedding is proper, ie, inverse images of compact sets are contained in compacts. -Moreover, the preimage of a compact set is compact, see `ClosedEmbedding.isCompact_preimage`. -/ -theorem ClosedEmbedding.tendsto_cocompact {f : X → Y} (hf : ClosedEmbedding f) : +Moreover, the preimage of a compact set is compact, see `IsClosedEmbedding.isCompact_preimage`. -/ +theorem IsClosedEmbedding.tendsto_cocompact {f : X → Y} (hf : IsClosedEmbedding f) : Tendsto f (Filter.cocompact X) (Filter.cocompact Y) := Filter.hasBasis_cocompact.tendsto_right_iff.mpr fun _K hK => (hf.isCompact_preimage hK).compl_mem_cocompact +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.tendsto_cocompact := IsClosedEmbedding.tendsto_cocompact + /-- Sets of subtype are compact iff the image under a coercion is. -/ theorem Subtype.isCompact_iff {p : X → Prop} {s : Set { x // p x }} : IsCompact s ↔ IsCompact ((↑) '' s : Set X) := - embedding_subtype_val.isCompact_iff + IsEmbedding.subtypeVal.isCompact_iff theorem isCompact_iff_isCompact_univ : IsCompact s ↔ IsCompact (univ : Set s) := by rw [Subtype.isCompact_iff, image_univ, Subtype.range_coe] @@ -956,13 +976,19 @@ theorem exists_nhds_ne_inf_principal_neBot (hs : IsCompact s) (hs' : s.Infinite) ∃ z ∈ s, (𝓝[≠] z ⊓ 𝓟 s).NeBot := hs'.exists_accPt_of_subset_isCompact hs Subset.rfl -protected theorem ClosedEmbedding.noncompactSpace [NoncompactSpace X] {f : X → Y} - (hf : ClosedEmbedding f) : NoncompactSpace Y := +protected theorem IsClosedEmbedding.noncompactSpace [NoncompactSpace X] {f : X → Y} + (hf : IsClosedEmbedding f) : NoncompactSpace Y := noncompactSpace_of_neBot hf.tendsto_cocompact.neBot -protected theorem ClosedEmbedding.compactSpace [h : CompactSpace Y] {f : X → Y} - (hf : ClosedEmbedding f) : CompactSpace X := - ⟨by rw [hf.toInducing.isCompact_iff, image_univ]; exact hf.isClosed_range.isCompact⟩ +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.noncompactSpace := IsClosedEmbedding.noncompactSpace + +protected theorem IsClosedEmbedding.compactSpace [h : CompactSpace Y] {f : X → Y} + (hf : IsClosedEmbedding f) : CompactSpace X := + ⟨by rw [hf.isInducing.isCompact_iff, image_univ]; exact hf.isClosed_range.isCompact⟩ + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.compactSpace := IsClosedEmbedding.compactSpace theorem IsCompact.prod {t : Set Y} (hs : IsCompact s) (ht : IsCompact t) : IsCompact (s ×ˢ t) := by @@ -981,7 +1007,7 @@ instance (priority := 100) Finite.compactSpace [Finite X] : CompactSpace X where isCompact_univ := finite_univ.isCompact instance ULift.compactSpace [CompactSpace X] : CompactSpace (ULift.{v} X) := - ULift.closedEmbedding_down.compactSpace + ULift.isClosedEmbedding_down.compactSpace /-- The product of two compact spaces is compact. -/ instance [CompactSpace X] [CompactSpace Y] : CompactSpace (X × Y) := diff --git a/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean b/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean index fbcd4585a405a..09080f8e326cd 100644 --- a/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean +++ b/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean @@ -94,6 +94,13 @@ instance (X : Type v) [t : TopologicalSpace X] [DiscreteTopology X] : rw [DiscreteTopology.eq_bot (t := t)] exact bot_le +#adaptation_note +/-- +The new unused variable linter in +https://github.com/leanprover/lean4/pull/5338 +flags `[tY : TopologicalSpace Y]`, but we want to use this as a named argument. +-/ +set_option linter.unusedVariables false in /-- Let `f : X → Y`. Suppose that to prove that `f` is continuous, it suffices to show that for every compact Hausdorff space `K` and every continuous map `g : K → X`, `f ∘ g` is continuous. Then `X` is compactly generated. -/ @@ -307,10 +314,17 @@ instance {ι : Type u} {X : ι → Type v} have hg : Continuous g := continuous_sigmaMk.comp <| hf.comp continuous_uLift_down exact (h _ g hg).preimage continuous_uLift_up +variable [T2Space X] + +theorem CompactlyGeneratedSpace.isClosed_iff_of_t2 [CompactlyGeneratedSpace X] (s : Set X) : + IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K) where + mp hs _ hK := hs.inter hK.isClosed + mpr := CompactlyGeneratedSpace.isClosed + /-- Let `s ⊆ X`. Suppose that `X` is Hausdorff, and that to prove that `s` is closed, it suffices to show that for every compact set `K ⊆ X`, `s ∩ K` is closed. Then `X` is compactly generated. -/ -theorem compactlyGeneratedSpace_of_isClosed_of_t2 [T2Space X] +theorem compactlyGeneratedSpace_of_isClosed_of_t2 (h : ∀ s, (∀ (K : Set X), IsCompact K → IsClosed (s ∩ K)) → IsClosed s) : CompactlyGeneratedSpace X := by refine compactlyGeneratedSpace_of_isClosed fun s hs ↦ h s fun K hK ↦ ?_ @@ -323,15 +337,15 @@ open scoped Set.Notation in /-- Let `s ⊆ X`. Suppose that `X` is Hausdorff, and that to prove that `s` is open, it suffices to show that for every compact set `K ⊆ X`, `s ∩ K` is open in `K`. Then `X` is compactly generated. -/ -theorem compactlyGeneratedSpace_of_isOpen_of_t2 [T2Space X] +theorem compactlyGeneratedSpace_of_isOpen_of_t2 (h : ∀ s, (∀ (K : Set X), IsCompact K → IsOpen (K ↓∩ s)) → IsOpen s) : CompactlyGeneratedSpace X := by refine compactlyGeneratedSpace_of_isOpen fun s hs ↦ h s fun K hK ↦ ?_ have : CompactSpace ↑K := isCompact_iff_compactSpace.1 hK exact hs _ Subtype.val continuous_subtype_val -/-- A Hausdorff and weakly locally compact space and compactly generated. -/ -instance (priority := 100) [WeaklyLocallyCompactSpace X] [T2Space X] : +/-- A Hausdorff and weakly locally compact space is compactly generated. -/ +instance (priority := 100) [WeaklyLocallyCompactSpace X] : CompactlyGeneratedSpace X := by refine compactlyGeneratedSpace_of_isClosed_of_t2 fun s h ↦ ?_ rw [isClosed_iff_forall_filter] diff --git a/Mathlib/Topology/Compactness/Lindelof.lean b/Mathlib/Topology/Compactness/Lindelof.lean index 6cbd814c5efbe..759b7f7b5172c 100644 --- a/Mathlib/Topology/Compactness/Lindelof.lean +++ b/Mathlib/Topology/Compactness/Lindelof.lean @@ -306,7 +306,7 @@ theorem isLindelof_empty : IsLindelof (∅ : Set X) := fun _f hnf _ hsf ↦ /-- A singleton set is a Lindelof set. -/ @[simp] -theorem isLindelof_singleton {x : X} : IsLindelof ({x} : Set X) := fun f hf _ hfa ↦ +theorem isLindelof_singleton {x : X} : IsLindelof ({x} : Set X) := fun _ hf _ hfa ↦ ⟨x, rfl, ClusterPt.of_le_nhds' (hfa.trans <| by simpa only [principal_singleton] using pure_le_nhds x) hf⟩ @@ -599,42 +599,57 @@ theorem isLindelof_range [LindelofSpace X] {f : X → Y} (hf : Continuous f) : theorem isLindelof_diagonal [LindelofSpace X] : IsLindelof (diagonal X) := @range_diag X ▸ isLindelof_range (continuous_id.prod_mk continuous_id) -/-- If `f : X → Y` is an `Inducing` map, the image `f '' s` of a set `s` is Lindelöf +/-- If `f : X → Y` is an inducing map, the image `f '' s` of a set `s` is Lindelöf if and only if `s` is compact. -/ -theorem Inducing.isLindelof_iff {f : X → Y} (hf : Inducing f) : +theorem IsInducing.isLindelof_iff {f : X → Y} (hf : IsInducing f) : IsLindelof s ↔ IsLindelof (f '' s) := by refine ⟨fun hs => hs.image hf.continuous, fun hs F F_ne_bot _ F_le => ?_⟩ obtain ⟨_, ⟨x, x_in : x ∈ s, rfl⟩, hx : ClusterPt (f x) (map f F)⟩ := hs ((map_mono F_le).trans_eq map_principal) exact ⟨x, x_in, hf.mapClusterPt_iff.1 hx⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.isLindelof_iff := IsInducing.isLindelof_iff + /-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is Lindelöf if and only if `s` is Lindelöf. -/ -theorem Embedding.isLindelof_iff {f : X → Y} (hf : Embedding f) : - IsLindelof s ↔ IsLindelof (f '' s) := hf.toInducing.isLindelof_iff +theorem IsEmbedding.isLindelof_iff {f : X → Y} (hf : IsEmbedding f) : + IsLindelof s ↔ IsLindelof (f '' s) := hf.isInducing.isLindelof_iff + +@[deprecated (since := "2024-10-26")] +alias Embedding.isLindelof_iff := IsEmbedding.isLindelof_iff /-- The preimage of a Lindelöf set under an inducing map is a Lindelöf set. -/ -theorem Inducing.isLindelof_preimage {f : X → Y} (hf : Inducing f) (hf' : IsClosed (range f)) - {K : Set Y} (hK : IsLindelof K) : IsLindelof (f ⁻¹' K) := by +theorem IsInducing.isLindelof_preimage {f : X → Y} (hf : IsInducing f) + (hf' : IsClosed (range f)) {K : Set Y} (hK : IsLindelof K) : IsLindelof (f ⁻¹' K) := by replace hK := hK.inter_right hf' rwa [hf.isLindelof_iff, image_preimage_eq_inter_range] +@[deprecated (since := "2024-10-28")] +alias Inducing.isLindelof_preimage := IsInducing.isLindelof_preimage + /-- The preimage of a Lindelöf set under a closed embedding is a Lindelöf set. -/ -theorem ClosedEmbedding.isLindelof_preimage {f : X → Y} (hf : ClosedEmbedding f) +theorem IsClosedEmbedding.isLindelof_preimage {f : X → Y} (hf : IsClosedEmbedding f) {K : Set Y} (hK : IsLindelof K) : IsLindelof (f ⁻¹' K) := - hf.toInducing.isLindelof_preimage (hf.isClosed_range) hK + hf.isInducing.isLindelof_preimage (hf.isClosed_range) hK + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.isLindelof_preimage := IsClosedEmbedding.isLindelof_preimage /-- A closed embedding is proper, ie, inverse images of Lindelöf sets are contained in Lindelöf. -Moreover, the preimage of a Lindelöf set is Lindelöf, see `ClosedEmbedding.isLindelof_preimage`. -/ -theorem ClosedEmbedding.tendsto_coLindelof {f : X → Y} (hf : ClosedEmbedding f) : +Moreover, the preimage of a Lindelöf set is Lindelöf, see +`IsClosedEmbedding.isLindelof_preimage`. -/ +theorem IsClosedEmbedding.tendsto_coLindelof {f : X → Y} (hf : IsClosedEmbedding f) : Tendsto f (Filter.coLindelof X) (Filter.coLindelof Y) := hasBasis_coLindelof.tendsto_right_iff.mpr fun _K hK => (hf.isLindelof_preimage hK).compl_mem_coLindelof +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.tendsto_coLindelof := IsClosedEmbedding.tendsto_coLindelof + /-- Sets of subtype are Lindelöf iff the image under a coercion is. -/ theorem Subtype.isLindelof_iff {p : X → Prop} {s : Set { x // p x }} : IsLindelof s ↔ IsLindelof ((↑) '' s : Set X) := - embedding_subtype_val.isLindelof_iff + IsEmbedding.subtypeVal.isLindelof_iff theorem isLindelof_iff_isLindelof_univ : IsLindelof s ↔ IsLindelof (univ : Set s) := by rw [Subtype.isLindelof_iff, image_univ, Subtype.range_coe] @@ -648,13 +663,19 @@ theorem IsLindelof.countable (hs : IsLindelof s) (hs' : DiscreteTopology s) : s. countable_coe_iff.mp (@countable_of_Lindelof_of_discrete _ _ (isLindelof_iff_LindelofSpace.mp hs) hs') -protected theorem ClosedEmbedding.nonLindelofSpace [NonLindelofSpace X] {f : X → Y} - (hf : ClosedEmbedding f) : NonLindelofSpace Y := +protected theorem IsClosedEmbedding.nonLindelofSpace [NonLindelofSpace X] {f : X → Y} + (hf : IsClosedEmbedding f) : NonLindelofSpace Y := nonLindelofSpace_of_neBot hf.tendsto_coLindelof.neBot -protected theorem ClosedEmbedding.LindelofSpace [h : LindelofSpace Y] {f : X → Y} - (hf : ClosedEmbedding f) : LindelofSpace X := - ⟨by rw [hf.toInducing.isLindelof_iff, image_univ]; exact hf.isClosed_range.isLindelof⟩ +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.nonLindelofSpace := IsClosedEmbedding.nonLindelofSpace + +protected theorem IsClosedEmbedding.LindelofSpace [h : LindelofSpace Y] {f : X → Y} + (hf : IsClosedEmbedding f) : LindelofSpace X := + ⟨by rw [hf.isInducing.isLindelof_iff, image_univ]; exact hf.isClosed_range.isLindelof⟩ + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.LindelofSpace := IsClosedEmbedding.LindelofSpace /-- Countable topological spaces are Lindelof. -/ instance (priority := 100) Countable.LindelofSpace [Countable X] : LindelofSpace X where diff --git a/Mathlib/Topology/Compactness/LocallyCompact.lean b/Mathlib/Topology/Compactness/LocallyCompact.lean index e0c44089ecd15..18dc3f4d92407 100644 --- a/Mathlib/Topology/Compactness/LocallyCompact.lean +++ b/Mathlib/Topology/Compactness/LocallyCompact.lean @@ -35,15 +35,25 @@ instance {ι : Type*} [Finite ι] {X : ι → Type*} [(i : ι) → TopologicalSp instance (priority := 100) [CompactSpace X] : WeaklyLocallyCompactSpace X where exists_compact_mem_nhds _ := ⟨univ, isCompact_univ, univ_mem⟩ -protected theorem ClosedEmbedding.weaklyLocallyCompactSpace [WeaklyLocallyCompactSpace Y] - {f : X → Y} (hf : ClosedEmbedding f) : WeaklyLocallyCompactSpace X where +protected theorem IsClosedEmbedding.weaklyLocallyCompactSpace [WeaklyLocallyCompactSpace Y] + {f : X → Y} (hf : IsClosedEmbedding f) : WeaklyLocallyCompactSpace X where exists_compact_mem_nhds x := let ⟨K, hK, hKx⟩ := exists_compact_mem_nhds (f x) ⟨f ⁻¹' K, hf.isCompact_preimage hK, hf.continuous.continuousAt hKx⟩ +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.weaklyLocallyCompactSpace := IsClosedEmbedding.weaklyLocallyCompactSpace + protected theorem IsClosed.weaklyLocallyCompactSpace [WeaklyLocallyCompactSpace X] {s : Set X} (hs : IsClosed s) : WeaklyLocallyCompactSpace s := - (closedEmbedding_subtype_val hs).weaklyLocallyCompactSpace + hs.isClosedEmbedding_subtypeVal.weaklyLocallyCompactSpace + +theorem IsOpenQuotientMap.weaklyLocallyCompactSpace [WeaklyLocallyCompactSpace X] + {f : X → Y} (hf : IsOpenQuotientMap f) : WeaklyLocallyCompactSpace Y where + exists_compact_mem_nhds := by + refine hf.surjective.forall.2 fun x ↦ ?_ + rcases exists_compact_mem_nhds x with ⟨K, hKc, hKx⟩ + exact ⟨f '' K, hKc.image hf.continuous, hf.isOpenMap.image_mem_nhds hKx⟩ /-- In a weakly locally compact space, every compact set is contained in the interior of a compact set. -/ @@ -166,10 +176,17 @@ theorem exists_compact_between [LocallyCompactSpace X] {K U : Set X} (hK : IsCom let ⟨L, hKL, hL, hLU⟩ := exists_mem_nhdsSet_isCompact_mapsTo continuous_id hK hU h_KU ⟨L, hL, subset_interior_iff_mem_nhdsSet.2 hKL, hLU⟩ +theorem IsOpenQuotientMap.locallyCompactSpace [LocallyCompactSpace X] {f : X → Y} + (hf : IsOpenQuotientMap f) : LocallyCompactSpace Y where + local_compact_nhds := by + refine hf.surjective.forall.2 fun x U hU ↦ ?_ + rcases local_compact_nhds (hf.continuous.continuousAt hU) with ⟨K, hKx, hKU, hKc⟩ + exact ⟨f '' K, hf.isOpenMap.image_mem_nhds hKx, image_subset_iff.2 hKU, hKc.image hf.continuous⟩ + /-- If `f` is a topology inducing map with a locally compact codomain and a locally closed range, then the domain of `f` is a locally compact space. -/ -theorem Inducing.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} (hf : Inducing f) - (h : IsLocallyClosed (range f)) : LocallyCompactSpace X := by +theorem IsInducing.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} + (hf : IsInducing f) (h : IsLocallyClosed (range f)) : LocallyCompactSpace X := by rcases h with ⟨U, Z, hU, hZ, hUZ⟩ have (x : X) : (𝓝 x).HasBasis (fun s ↦ (s ∈ 𝓝 (f x) ∧ IsCompact s) ∧ s ⊆ U) (fun s ↦ f ⁻¹' (s ∩ Z)) := by @@ -181,17 +198,26 @@ theorem Inducing.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} (hf : rw [hf.isCompact_preimage_iff] exacts [hs.inter_right hZ, hUZ ▸ by gcongr] -protected theorem ClosedEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} - (hf : ClosedEmbedding f) : LocallyCompactSpace X := - hf.toInducing.locallyCompactSpace hf.isClosed_range.isLocallyClosed +@[deprecated (since := "2024-10-28")] +alias Inducing.locallyCompactSpace := IsInducing.locallyCompactSpace + +protected theorem IsClosedEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} + (hf : IsClosedEmbedding f) : LocallyCompactSpace X := + hf.isInducing.locallyCompactSpace hf.isClosed_range.isLocallyClosed + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.locallyCompactSpace := IsClosedEmbedding.locallyCompactSpace + +protected theorem IsOpenEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} + (hf : IsOpenEmbedding f) : LocallyCompactSpace X := + hf.isInducing.locallyCompactSpace hf.isOpen_range.isLocallyClosed -protected theorem OpenEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} - (hf : OpenEmbedding f) : LocallyCompactSpace X := - hf.toInducing.locallyCompactSpace hf.isOpen_range.isLocallyClosed +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.locallyCompactSpace := IsOpenEmbedding.locallyCompactSpace protected theorem IsLocallyClosed.locallyCompactSpace [LocallyCompactSpace X] {s : Set X} (hs : IsLocallyClosed s) : LocallyCompactSpace s := - embedding_subtype_val.locallyCompactSpace <| by rwa [Subtype.range_val] + IsEmbedding.subtypeVal.locallyCompactSpace <| by rwa [Subtype.range_val] protected theorem IsClosed.locallyCompactSpace [LocallyCompactSpace X] {s : Set X} (hs : IsClosed s) : LocallyCompactSpace s := diff --git a/Mathlib/Topology/Compactness/Paracompact.lean b/Mathlib/Topology/Compactness/Paracompact.lean index ea4ab6733b402..638f75142b792 100644 --- a/Mathlib/Topology/Compactness/Paracompact.lean +++ b/Mathlib/Topology/Compactness/Paracompact.lean @@ -107,8 +107,8 @@ theorem precise_refinement_set [ParacompactSpace X] {s : Set X} (hs : IsClosed s · simp only [iUnion_option, ← compl_subset_iff_union] at vc exact Subset.trans (subset_compl_comm.1 <| vu Option.none) vc -theorem ClosedEmbedding.paracompactSpace [ParacompactSpace Y] {e : X → Y} (he : ClosedEmbedding e) : - ParacompactSpace X where +theorem IsClosedEmbedding.paracompactSpace [ParacompactSpace Y] {e : X → Y} + (he : IsClosedEmbedding e) : ParacompactSpace X where locallyFinite_refinement α s ho hu := by choose U hUo hU using fun a ↦ he.isOpen_iff.1 (ho a) simp only [← hU] at hu ⊢ @@ -119,8 +119,11 @@ theorem ClosedEmbedding.paracompactSpace [ParacompactSpace Y] {e : X → Y} (he hVf.preimage_continuous he.continuous, fun a ↦ ⟨a, preimage_mono (hVU a)⟩⟩ simpa only [range_subset_iff, mem_iUnion, iUnion_eq_univ_iff] using heV +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.paracompactSpace := IsClosedEmbedding.paracompactSpace + theorem Homeomorph.paracompactSpace_iff (e : X ≃ₜ Y) : ParacompactSpace X ↔ ParacompactSpace Y := - ⟨fun _ ↦ e.symm.closedEmbedding.paracompactSpace, fun _ ↦ e.closedEmbedding.paracompactSpace⟩ + ⟨fun _ ↦ e.symm.isClosedEmbedding.paracompactSpace, fun _ ↦ e.isClosedEmbedding.paracompactSpace⟩ /-- The product of a compact space and a paracompact space is a paracompact space. The formalization is based on https://dantopology.wordpress.com/2009/10/24/compact-x-paracompact-is-paracompact/ diff --git a/Mathlib/Topology/Compactness/SigmaCompact.lean b/Mathlib/Topology/Compactness/SigmaCompact.lean index 7518114ce3802..7baecf496533a 100644 --- a/Mathlib/Topology/Compactness/SigmaCompact.lean +++ b/Mathlib/Topology/Compactness/SigmaCompact.lean @@ -97,10 +97,10 @@ lemma IsSigmaCompact.image_of_continuousOn {f : X → Y} {s : Set X} (hs : IsSig lemma IsSigmaCompact.image {f : X → Y} (hf : Continuous f) {s : Set X} (hs : IsSigmaCompact s) : IsSigmaCompact (f '' s) := hs.image_of_continuousOn hf.continuousOn -/-- If `f : X → Y` is `Inducing`, the image `f '' s` of a set `s` is σ-compact +/-- If `f : X → Y` is an inducing map, the image `f '' s` of a set `s` is σ-compact if and only `s` is σ-compact. -/ -lemma Inducing.isSigmaCompact_iff {f : X → Y} {s : Set X} - (hf : Inducing f) : IsSigmaCompact s ↔ IsSigmaCompact (f '' s) := by +lemma IsInducing.isSigmaCompact_iff {f : X → Y} {s : Set X} + (hf : IsInducing f) : IsSigmaCompact s ↔ IsSigmaCompact (f '' s) := by constructor · exact fun h ↦ h.image hf.continuous · rintro ⟨L, hcomp, hcov⟩ @@ -118,16 +118,22 @@ lemma Inducing.isSigmaCompact_iff {f : X → Y} {s : Set X} _ = f ⁻¹' (f '' s) ∩ s := by rw [hcov] _ = s := inter_eq_right.mpr (subset_preimage_image _ _) +@[deprecated (since := "2024-10-28")] +alias Inducing.isSigmaCompact_iff := IsInducing.isSigmaCompact_iff + /-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is σ-compact if and only `s` is σ-compact. -/ -lemma Embedding.isSigmaCompact_iff {f : X → Y} {s : Set X} - (hf : Embedding f) : IsSigmaCompact s ↔ IsSigmaCompact (f '' s) := - hf.toInducing.isSigmaCompact_iff +lemma IsEmbedding.isSigmaCompact_iff {f : X → Y} {s : Set X} + (hf : IsEmbedding f) : IsSigmaCompact s ↔ IsSigmaCompact (f '' s) := + hf.isInducing.isSigmaCompact_iff + +@[deprecated (since := "2024-10-26")] +alias Embedding.isSigmaCompact_iff := IsEmbedding.isSigmaCompact_iff /-- Sets of subtype are σ-compact iff the image under a coercion is. -/ lemma Subtype.isSigmaCompact_iff {p : X → Prop} {s : Set { a // p a }} : IsSigmaCompact s ↔ IsSigmaCompact ((↑) '' s : Set X) := - embedding_subtype_val.isSigmaCompact_iff + IsEmbedding.subtypeVal.isSigmaCompact_iff /-- A σ-compact space is a space that is the union of a countable collection of compact subspaces. Note that a locally compact separable T₂ space need not be σ-compact. @@ -249,17 +255,20 @@ instance [Countable ι] {X : ι → Type*} [∀ i, TopologicalSpace (X i)] refine ⟨max k n, k, le_max_left _ _, mem_image_of_mem _ ?_⟩ exact compactCovering_subset _ (le_max_right _ _) hn -protected theorem ClosedEmbedding.sigmaCompactSpace {e : Y → X} (he : ClosedEmbedding e) : +protected theorem IsClosedEmbedding.sigmaCompactSpace {e : Y → X} (he : IsClosedEmbedding e) : SigmaCompactSpace Y := - ⟨⟨fun n => e ⁻¹' compactCovering X n, fun n => + ⟨⟨fun n => e ⁻¹' compactCovering X n, fun _ => he.isCompact_preimage (isCompact_compactCovering _ _), by rw [← preimage_iUnion, iUnion_compactCovering, preimage_univ]⟩⟩ +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.sigmaCompactSpace := IsClosedEmbedding.sigmaCompactSpace + theorem IsClosed.sigmaCompactSpace {s : Set X} (hs : IsClosed s) : SigmaCompactSpace s := - (closedEmbedding_subtype_val hs).sigmaCompactSpace + hs.isClosedEmbedding_subtypeVal.sigmaCompactSpace instance [SigmaCompactSpace Y] : SigmaCompactSpace (ULift.{u} Y) := - ULift.closedEmbedding_down.sigmaCompactSpace + ULift.isClosedEmbedding_down.sigmaCompactSpace /-- If `X` is a `σ`-compact space, then a locally finite family of nonempty sets of `X` can have only countably many elements, `Set.Countable` version. -/ diff --git a/Mathlib/Topology/Connected/Basic.lean b/Mathlib/Topology/Connected/Basic.lean index 54b61ed7b660c..62b4af523a63f 100644 --- a/Mathlib/Topology/Connected/Basic.lean +++ b/Mathlib/Topology/Connected/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov -/ -import Mathlib.Data.Set.Basic +import Mathlib.Data.Set.SymmDiff import Mathlib.Order.SuccPred.Relation import Mathlib.Topology.Irreducible @@ -207,7 +207,7 @@ variable [LinearOrder β] [SuccOrder β] [IsSuccArchimedean β] such that any two neighboring sets meet is preconnected. -/ theorem IsPreconnected.iUnion_of_chain {s : β → Set α} (H : ∀ n, IsPreconnected (s n)) (K : ∀ n, (s n ∩ s (succ n)).Nonempty) : IsPreconnected (⋃ n, s n) := - IsPreconnected.iUnion_of_reflTransGen H fun i j => + IsPreconnected.iUnion_of_reflTransGen H fun _ _ => reflTransGen_of_succ _ (fun i _ => K i) fun i _ => by rw [inter_comm] exact K i @@ -216,7 +216,7 @@ theorem IsPreconnected.iUnion_of_chain {s : β → Set α} (H : ∀ n, IsPreconn such that any two neighboring sets meet is connected. -/ theorem IsConnected.iUnion_of_chain [Nonempty β] {s : β → Set α} (H : ∀ n, IsConnected (s n)) (K : ∀ n, (s n ∩ s (succ n)).Nonempty) : IsConnected (⋃ n, s n) := - IsConnected.iUnion_of_reflTransGen H fun i j => + IsConnected.iUnion_of_reflTransGen H fun _ _ => reflTransGen_of_succ _ (fun i _ => K i) fun i _ => by rw [inter_comm] exact K i @@ -320,8 +320,8 @@ theorem isPreconnected_closed_iff {s : Set α} : rw [← compl_union] at this exact this.ne_empty huv.disjoint_compl_right.inter_eq⟩ -theorem Inducing.isPreconnected_image [TopologicalSpace β] {s : Set α} {f : α → β} - (hf : Inducing f) : IsPreconnected (f '' s) ↔ IsPreconnected s := by +theorem IsInducing.isPreconnected_image [TopologicalSpace β] {s : Set α} {f : α → β} + (hf : IsInducing f) : IsPreconnected (f '' s) ↔ IsPreconnected s := by refine ⟨fun h => ?_, fun h => h.image _ hf.continuous.continuousOn⟩ rintro u v hu' hv' huv ⟨x, hxs, hxu⟩ ⟨y, hys, hyv⟩ rcases hf.isOpen_iff.1 hu' with ⟨u, hu, rfl⟩ @@ -331,6 +331,9 @@ theorem Inducing.isPreconnected_image [TopologicalSpace β] {s : Set α} {f : α ⟨_, ⟨z, hzs, rfl⟩, hzuv⟩ exact ⟨z, hzs, hzuv⟩ +@[deprecated (since := "2024-10-28")] +alias Inducing.isPreconnected_image := IsInducing.isPreconnected_image + /- TODO: The following lemmas about connection of preimages hold more generally for strict maps (the quotient and subspace topologies of the image agree) whose fibers are preconnected. -/ @@ -497,7 +500,7 @@ theorem isPreconnected_connectedComponent {x : α} : IsPreconnected (connectedCo theorem isPreconnected_connectedComponentIn {x : α} {F : Set α} : IsPreconnected (connectedComponentIn F x) := by rw [connectedComponentIn]; split_ifs - · exact inducing_subtype_val.isPreconnected_image.mpr isPreconnected_connectedComponent + · exact IsInducing.subtypeVal.isPreconnected_image.mpr isPreconnected_connectedComponent · exact isPreconnected_empty theorem isConnected_connectedComponent {x : α} : IsConnected (connectedComponent x) := @@ -514,7 +517,7 @@ theorem IsPreconnected.subset_connectedComponent {x : α} {s : Set α} (H1 : IsP theorem IsPreconnected.subset_connectedComponentIn {x : α} {F : Set α} (hs : IsPreconnected s) (hxs : x ∈ s) (hsF : s ⊆ F) : s ⊆ connectedComponentIn F x := by have : IsPreconnected (((↑) : F → α) ⁻¹' s) := by - refine inducing_subtype_val.isPreconnected_image.mp ?_ + refine IsInducing.subtypeVal.isPreconnected_image.mp ?_ rwa [Subtype.image_preimage_coe, inter_eq_right.mpr hsF] have h2xs : (⟨x, hsF hxs⟩ : F) ∈ (↑) ⁻¹' s := by rw [mem_preimage] @@ -701,7 +704,7 @@ instance (priority := 100) IrreducibleSpace.connectedSpace (α : Type u) [Topolo theorem Subtype.preconnectedSpace {s : Set α} (h : IsPreconnected s) : PreconnectedSpace s where isPreconnected_univ := by - rwa [← inducing_subtype_val.isPreconnected_image, image_univ, Subtype.range_val] + rwa [← IsInducing.subtypeVal.isPreconnected_image, image_univ, Subtype.range_val] theorem Subtype.connectedSpace {s : Set α} (h : IsConnected s) : ConnectedSpace s where toPreconnectedSpace := Subtype.preconnectedSpace h.isPreconnected diff --git a/Mathlib/Topology/Connected/Clopen.lean b/Mathlib/Topology/Connected/Clopen.lean index cfba16bc1231f..205522d936fa0 100644 --- a/Mathlib/Topology/Connected/Clopen.lean +++ b/Mathlib/Topology/Connected/Clopen.lean @@ -99,7 +99,7 @@ theorem Continuous.exists_lift_sigma [ConnectedSpace α] [∀ i, TopologicalSpac exact ⟨i, hs.trans_subset (image_subset_range _ _)⟩ rcases range_subset_range_iff_exists_comp.1 hi with ⟨g, rfl⟩ refine ⟨i, g, ?_, rfl⟩ - rwa [← embedding_sigmaMk.continuous_iff] at hf + rwa [← IsEmbedding.sigmaMk.continuous_iff] at hf theorem nonempty_inter [PreconnectedSpace α] {s t : Set α} : IsOpen s → IsOpen t → s ∪ t = univ → s.Nonempty → t.Nonempty → (s ∩ t).Nonempty := by @@ -453,18 +453,24 @@ theorem preimage_connectedComponent_connected [TopologicalSpace β] {f : α → from (this.trans T₂_v.1).trans inter_subset_right exact preimage_mono h -theorem QuotientMap.preimage_connectedComponent [TopologicalSpace β] {f : α → β} - (hf : QuotientMap f) (h_fibers : ∀ y : β, IsConnected (f ⁻¹' {y})) (a : α) : +theorem IsQuotientMap.preimage_connectedComponent [TopologicalSpace β] {f : α → β} + (hf : IsQuotientMap f) (h_fibers : ∀ y : β, IsConnected (f ⁻¹' {y})) (a : α) : f ⁻¹' connectedComponent (f a) = connectedComponent a := ((preimage_connectedComponent_connected h_fibers (fun _ => hf.isClosed_preimage.symm) _).subset_connectedComponent mem_connectedComponent).antisymm (hf.continuous.mapsTo_connectedComponent a) -theorem QuotientMap.image_connectedComponent [TopologicalSpace β] {f : α → β} (hf : QuotientMap f) +@[deprecated (since := "2024-10-22")] +alias QuotientMap.preimage_connectedComponent := IsQuotientMap.preimage_connectedComponent + +lemma IsQuotientMap.image_connectedComponent [TopologicalSpace β] {f : α → β} (hf : IsQuotientMap f) (h_fibers : ∀ y : β, IsConnected (f ⁻¹' {y})) (a : α) : f '' connectedComponent a = connectedComponent (f a) := by rw [← hf.preimage_connectedComponent h_fibers, image_preimage_eq _ hf.surjective] +@[deprecated (since := "2024-10-22")] +alias QuotientMap.image_connectedComponent := IsQuotientMap.image_connectedComponent + end Preconnected section connectedComponentSetoid @@ -505,12 +511,15 @@ instance : TopologicalSpace (ConnectedComponents α) := theorem surjective_coe : Surjective (mk : α → ConnectedComponents α) := surjective_quot_mk _ -theorem quotientMap_coe : QuotientMap (mk : α → ConnectedComponents α) := - quotientMap_quot_mk +theorem isQuotientMap_coe : IsQuotientMap (mk : α → ConnectedComponents α) := + isQuotientMap_quot_mk + +@[deprecated (since := "2024-10-22")] +alias quotientMap_coe := isQuotientMap_coe @[continuity] theorem continuous_coe : Continuous (mk : α → ConnectedComponents α) := - quotientMap_coe.continuous + isQuotientMap_coe.continuous @[simp] theorem range_coe : range (mk : α → ConnectedComponents α) = univ := diff --git a/Mathlib/Topology/Connected/LocallyConnected.lean b/Mathlib/Topology/Connected/LocallyConnected.lean index 52d6a10719be2..065d40db50471 100644 --- a/Mathlib/Topology/Connected/LocallyConnected.lean +++ b/Mathlib/Topology/Connected/LocallyConnected.lean @@ -120,8 +120,8 @@ theorem locallyConnectedSpace_of_connected_bases {ι : Type*} (b : α → ι → (fun i hi => ⟨b x i, ⟨(hbasis x).mem_of_mem hi, hconnected x i hi⟩, subset_rfl⟩) fun s hs => ⟨(hbasis x).index s hs.1, ⟨(hbasis x).property_index hs.1, (hbasis x).set_index_subset hs.1⟩⟩ -theorem OpenEmbedding.locallyConnectedSpace [LocallyConnectedSpace α] [TopologicalSpace β] - {f : β → α} (h : OpenEmbedding f) : LocallyConnectedSpace β := by +theorem IsOpenEmbedding.locallyConnectedSpace [LocallyConnectedSpace α] [TopologicalSpace β] + {f : β → α} (h : IsOpenEmbedding f) : LocallyConnectedSpace β := by refine locallyConnectedSpace_of_connected_bases (fun _ s ↦ f ⁻¹' s) (fun x s ↦ (IsOpen s ∧ f x ∈ s ∧ IsConnected s) ∧ s ⊆ range f) (fun x ↦ ?_) (fun x s hxs ↦ hxs.1.2.2.isPreconnected.preimage_of_isOpenMap h.inj h.isOpenMap hxs.2) @@ -129,8 +129,11 @@ theorem OpenEmbedding.locallyConnectedSpace [LocallyConnectedSpace α] [Topologi exact LocallyConnectedSpace.open_connected_basis (f x) |>.restrict_subset (h.isOpen_range.mem_nhds <| mem_range_self _) |>.comap _ +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.locallyConnectedSpace := IsOpenEmbedding.locallyConnectedSpace + theorem IsOpen.locallyConnectedSpace [LocallyConnectedSpace α] {U : Set α} (hU : IsOpen U) : LocallyConnectedSpace U := - hU.openEmbedding_subtype_val.locallyConnectedSpace + hU.isOpenEmbedding_subtypeVal.locallyConnectedSpace end LocallyConnectedSpace diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index 644fcb694b3a8..7db33a85e7b36 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -85,12 +85,6 @@ instance Path.funLike : FunLike (Path x y) I X where instance Path.continuousMapClass : ContinuousMapClass (Path x y) I X where map_continuous γ := show Continuous γ.toContinuousMap by fun_prop --- Porting note: not necessary in light of the instance above -/- -instance : CoeFun (Path x y) fun _ => I → X := - ⟨fun p => p.toFun⟩ --/ - @[ext] protected theorem Path.ext : ∀ {γ₁ γ₂ : Path x y}, (γ₁ : I → X) = γ₂ → γ₁ = γ₂ := by rintro ⟨⟨x, h11⟩, h12, h13⟩ ⟨⟨x, h21⟩, h22, h23⟩ rfl @@ -198,14 +192,14 @@ compact-open topology on the space `C(I,X)` of continuous maps from `I` to `X`. instance topologicalSpace : TopologicalSpace (Path x y) := TopologicalSpace.induced ((↑) : _ → C(I, X)) ContinuousMap.compactOpen -theorem continuous_eval : Continuous fun p : Path x y × I => p.1 p.2 := - ContinuousMap.continuous_eval.comp <| - (continuous_induced_dom (α := Path x y)).prodMap continuous_id +instance : ContinuousEval (Path x y) I X := .of_continuous_forget continuous_induced_dom -@[continuity] +@[deprecated (since := "2024-10-04")] protected alias continuous_eval := continuous_eval + +@[deprecated Continuous.eval (since := "2024-10-04")] theorem _root_.Continuous.path_eval {Y} [TopologicalSpace Y] {f : Y → Path x y} {g : Y → I} - (hf : Continuous f) (hg : Continuous g) : Continuous fun y => f y (g y) := - Continuous.comp continuous_eval (hf.prod_mk hg) + (hf : Continuous f) (hg : Continuous g) : Continuous fun y => f y (g y) := by + continuity theorem continuous_uncurry_iff {Y} [TopologicalSpace Y] {g : Y → Path x y} : Continuous ↿g ↔ Continuous g := @@ -427,7 +421,7 @@ theorem symm_continuous_family {ι : Type*} [TopologicalSpace ι] @[continuity] theorem continuous_symm : Continuous (symm : Path x y → Path y x) := - continuous_uncurry_iff.mp <| symm_continuous_family _ (continuous_fst.path_eval continuous_snd) + continuous_uncurry_iff.mp <| symm_continuous_family _ (continuous_fst.eval continuous_snd) @[continuity] theorem continuous_uncurry_extend_of_continuous_family {ι : Type*} [TopologicalSpace ι] @@ -785,13 +779,37 @@ theorem Specializes.joinedIn (h : x ⤳ y) (hx : x ∈ F) (hy : y ∈ F) : Joine theorem Inseparable.joinedIn (h : Inseparable x y) (hx : x ∈ F) (hy : y ∈ F) : JoinedIn F x y := h.specializes.joinedIn hx hy -/-! ### Path component -/ +theorem JoinedIn.map_continuousOn (h : JoinedIn F x y) {f : X → Y} (hf : ContinuousOn f F) : + JoinedIn (f '' F) (f x) (f y) := + let ⟨γ, hγ⟩ := h + ⟨γ.map' <| hf.mono (range_subset_iff.mpr hγ), fun t ↦ mem_image_of_mem _ (hγ t)⟩ + +theorem JoinedIn.map (h : JoinedIn F x y) {f : X → Y} (hf : Continuous f) : + JoinedIn (f '' F) (f x) (f y) := + h.map_continuousOn hf.continuousOn + +theorem IsInducing.joinedIn_image {f : X → Y} (hf : IsInducing f) (hx : x ∈ F) + (hy : y ∈ F) : JoinedIn (f '' F) (f x) (f y) ↔ JoinedIn F x y := by + refine ⟨?_, (.map · hf.continuous)⟩ + rintro ⟨γ, hγ⟩ + choose γ' hγ'F hγ' using hγ + have h₀ : x ⤳ γ' 0 := by rw [← hf.specializes_iff, hγ', γ.source] + have h₁ : γ' 1 ⤳ y := by rw [← hf.specializes_iff, hγ', γ.target] + have h : JoinedIn F (γ' 0) (γ' 1) := by + refine ⟨⟨⟨γ', ?_⟩, rfl, rfl⟩, hγ'F⟩ + simpa only [hf.continuous_iff, comp_def, hγ'] using map_continuous γ + exact (h₀.joinedIn hx (hγ'F _)).trans <| h.trans <| h₁.joinedIn (hγ'F _) hy + +@[deprecated (since := "2024-10-28")] alias Inducing.joinedIn_image := IsInducing.joinedIn_image +/-! ### Path component -/ /-- The path component of `x` is the set of points that can be joined to `x`. -/ def pathComponent (x : X) := { y | Joined x y } +theorem mem_pathComponent_iff : x ∈ pathComponent y ↔ Joined y x := .rfl + @[simp] theorem mem_pathComponent_self (x : X) : x ∈ pathComponent x := Joined.refl x @@ -832,6 +850,24 @@ theorem Joined.mem_pathComponent (hyz : Joined y z) (hxy : y ∈ pathComponent x z ∈ pathComponent x := hxy.trans hyz +theorem mem_pathComponentIn_self (h : x ∈ F) : x ∈ pathComponentIn x F := + JoinedIn.refl h + +theorem pathComponentIn_subset : pathComponentIn x F ⊆ F := + fun _ hy ↦ hy.target_mem + +theorem pathComponentIn_nonempty_iff : (pathComponentIn x F).Nonempty ↔ x ∈ F := + ⟨fun ⟨_, ⟨γ, hγ⟩⟩ ↦ γ.source ▸ hγ 0, fun hx ↦ ⟨x, mem_pathComponentIn_self hx⟩⟩ + +theorem pathComponentIn_congr (h : x ∈ pathComponentIn y F) : + pathComponentIn x F = pathComponentIn y F := by + ext; exact ⟨h.trans, h.symm.trans⟩ + +@[gcongr] +theorem pathComponentIn_mono {G : Set X} (h : F ⊆ G) : + pathComponentIn x F ⊆ pathComponentIn x G := + fun _ ⟨γ, hγ⟩ ↦ ⟨γ, fun t ↦ h (hγ t)⟩ + /-! ### Path connected sets -/ @@ -867,30 +903,25 @@ theorem IsPathConnected.image' (hF : IsPathConnected F) exact hf.mono (range_subset_iff.2 (hx y_in).somePath_mem) /-- If `f` is continuous and `F` is path-connected, so is `f(F)`. -/ -theorem IsPathConnected.image (hF : IsPathConnected F) {f : X → Y} - (hf : Continuous f) : IsPathConnected (f '' F) := hF.image' hf.continuousOn +theorem IsPathConnected.image (hF : IsPathConnected F) {f : X → Y} (hf : Continuous f) : + IsPathConnected (f '' F) := + hF.image' hf.continuousOn -/-- If `f : X → Y` is a `Inducing`, `f(F)` is path-connected iff `F` is. -/ -nonrec theorem Inducing.isPathConnected_iff {f : X → Y} (hf : Inducing f) : +/-- If `f : X → Y` is an inducing map, `f(F)` is path-connected iff `F` is. -/ +nonrec theorem IsInducing.isPathConnected_iff {f : X → Y} (hf : IsInducing f) : IsPathConnected F ↔ IsPathConnected (f '' F) := by - refine ⟨fun hF ↦ hF.image hf.continuous, fun hF ↦ ?_⟩ - simp? [isPathConnected_iff] at hF ⊢ says - simp only [isPathConnected_iff, image_nonempty, mem_image, forall_exists_index, - and_imp, forall_apply_eq_imp_iff₂] at hF ⊢ - refine ⟨hF.1, fun x hx y hy ↦ ?_⟩ - rcases hF.2 x hx y hy with ⟨γ, hγ⟩ - choose γ' hγ' hγγ' using hγ - have key₁ : Inseparable x (γ' 0) := by rw [← hf.inseparable_iff, hγγ' 0, γ.source] - have key₂ : Inseparable (γ' 1) y := by rw [← hf.inseparable_iff, hγγ' 1, γ.target] - refine key₁.joinedIn hx (hγ' 0) |>.trans ⟨⟨⟨γ', ?_⟩, rfl, rfl⟩, hγ'⟩ |>.trans - (key₂.joinedIn (hγ' 1) hy) - simpa [hf.continuous_iff] using γ.continuous.congr fun t ↦ (hγγ' t).symm + simp only [IsPathConnected, forall_mem_image, exists_mem_image] + refine exists_congr fun x ↦ and_congr_right fun hx ↦ forall₂_congr fun y hy ↦ ?_ + rw [hf.joinedIn_image hx hy] + +@[deprecated (since := "2024-10-28")] +alias Inducing.isPathConnected_iff := IsInducing.isPathConnected_iff /-- If `h : X → Y` is a homeomorphism, `h(s)` is path-connected iff `s` is. -/ @[simp] theorem Homeomorph.isPathConnected_image {s : Set X} (h : X ≃ₜ Y) : IsPathConnected (h '' s) ↔ IsPathConnected s := - h.inducing.isPathConnected_iff.symm + h.isInducing.isPathConnected_iff.symm /-- If `h : X → Y` is a homeomorphism, `h⁻¹(s)` is path-connected iff `s` is. -/ @[simp] @@ -905,11 +936,26 @@ theorem IsPathConnected.mem_pathComponent (h : IsPathConnected F) (x_in : x ∈ theorem IsPathConnected.subset_pathComponent (h : IsPathConnected F) (x_in : x ∈ F) : F ⊆ pathComponent x := fun _y y_in => h.mem_pathComponent x_in y_in +theorem IsPathConnected.subset_pathComponentIn {s : Set X} (hs : IsPathConnected s) + (hxs : x ∈ s) (hsF : s ⊆ F) : s ⊆ pathComponentIn x F := + fun y hys ↦ (hs.joinedIn x hxs y hys).mono hsF + theorem isPathConnected_singleton (x : X) : IsPathConnected ({x} : Set X) := by refine ⟨x, rfl, ?_⟩ rintro y rfl exact JoinedIn.refl rfl +theorem isPathConnected_pathComponentIn (h : x ∈ F) : IsPathConnected (pathComponentIn x F) := + ⟨x, mem_pathComponentIn_self h, fun ⟨γ, hγ⟩ ↦ by + refine ⟨γ, fun t ↦ + ⟨(γ.truncateOfLE t.2.1).cast (γ.extend_zero.symm) (γ.extend_extends' t).symm, fun t' ↦ ?_⟩⟩ + dsimp [Path.truncateOfLE, Path.truncate] + exact γ.extend_extends' ⟨min (max t'.1 0) t.1, by simp [t.2.1, t.2.2]⟩ ▸ hγ _⟩ + +theorem isPathConnected_pathComponent : IsPathConnected (pathComponent x) := by + rw [← pathComponentIn_univ] + exact isPathConnected_pathComponentIn (mem_univ x) + theorem IsPathConnected.union {U V : Set X} (hU : IsPathConnected U) (hV : IsPathConnected V) (hUV : (U ∩ V).Nonempty) : IsPathConnected (U ∪ V) := by rcases hUV with ⟨x, xU, xV⟩ @@ -922,10 +968,7 @@ theorem IsPathConnected.union {U V : Set X} (hU : IsPathConnected U) (hV : IsPat ambient type `U` (when `U` contains `W`). -/ theorem IsPathConnected.preimage_coe {U W : Set X} (hW : IsPathConnected W) (hWU : W ⊆ U) : IsPathConnected (((↑) : U → X) ⁻¹' W) := by - rcases hW with ⟨x, x_in, hx⟩ - use ⟨x, hWU x_in⟩, by simp [x_in] - rintro ⟨y, hyU⟩ hyW - exact ⟨(hx hyW).joined_subtype.somePath.map (continuous_inclusion hWU), by simp⟩ + rwa [IsInducing.subtypeVal.isPathConnected_iff, Subtype.image_preimage_val, inter_eq_right.2 hWU] theorem IsPathConnected.exists_path_through_family {n : ℕ} {s : Set X} (h : IsPathConnected s) (p : Fin (n + 1) → X) (hp : ∀ i, p i ∈ s) : @@ -997,6 +1040,7 @@ theorem IsPathConnected.exists_path_through_family' {n : ℕ} /-- A topological space is path-connected if it is non-empty and every two points can be joined by a continuous path. -/ +@[mk_iff] class PathConnectedSpace (X : Type*) [TopologicalSpace X] : Prop where /-- A path-connected space must be nonempty. -/ nonempty : Nonempty X @@ -1025,31 +1069,12 @@ def somePath (x y : X) : Path x y := end PathConnectedSpace -theorem isPathConnected_iff_pathConnectedSpace : IsPathConnected F ↔ PathConnectedSpace F := by - rw [isPathConnected_iff] - constructor - · rintro ⟨⟨x, x_in⟩, h⟩ - refine ⟨⟨⟨x, x_in⟩⟩, ?_⟩ - rintro ⟨y, y_in⟩ ⟨z, z_in⟩ - have H := h y y_in z z_in - rwa [joinedIn_iff_joined y_in z_in] at H - · rintro ⟨⟨x, x_in⟩, H⟩ - refine ⟨⟨x, x_in⟩, fun y y_in z z_in => ?_⟩ - rw [joinedIn_iff_joined y_in z_in] - apply H - theorem pathConnectedSpace_iff_univ : PathConnectedSpace X ↔ IsPathConnected (univ : Set X) := by - constructor - · intro h - haveI := @PathConnectedSpace.nonempty X _ _ - inhabit X - refine ⟨default, mem_univ _, ?_⟩ - intros y _hy - simpa using PathConnectedSpace.joined default y - · intro h - have h' := h.joinedIn - cases' h with x h - exact ⟨⟨x⟩, by simpa using h'⟩ + simp [pathConnectedSpace_iff, isPathConnected_iff, nonempty_iff_univ_nonempty] + +theorem isPathConnected_iff_pathConnectedSpace : IsPathConnected F ↔ PathConnectedSpace F := by + rw [pathConnectedSpace_iff_univ, IsInducing.subtypeVal.isPathConnected_iff, image_univ, + Subtype.range_val_subtype, setOf_mem_eq] theorem isPathConnected_univ [PathConnectedSpace X] : IsPathConnected (univ : Set X) := pathConnectedSpace_iff_univ.mp inferInstance @@ -1111,6 +1136,7 @@ end PathConnectedSpace /-! ### Locally path connected spaces -/ +section LocPathConnectedSpace /-- A topological space is locally path connected, at every point, path connected neighborhoods form a neighborhood basis. -/ @@ -1120,66 +1146,73 @@ class LocPathConnectedSpace (X : Type*) [TopologicalSpace X] : Prop where export LocPathConnectedSpace (path_connected_basis) -theorem locPathConnected_of_bases {p : ι → Prop} {s : X → ι → Set X} - (h : ∀ x, (𝓝 x).HasBasis p (s x)) (h' : ∀ x i, p i → IsPathConnected (s x i)) : - LocPathConnectedSpace X := by - constructor - intro x - apply (h x).to_hasBasis - · intro i pi - exact ⟨s x i, ⟨(h x).mem_of_mem pi, h' x i pi⟩, by rfl⟩ - · rintro U ⟨U_in, _hU⟩ - rcases (h x).mem_iff.mp U_in with ⟨i, pi, hi⟩ - tauto - -theorem pathConnectedSpace_iff_connectedSpace [LocPathConnectedSpace X] : - PathConnectedSpace X ↔ ConnectedSpace X := by - constructor - · intro h - infer_instance - · intro hX - rw [pathConnectedSpace_iff_eq] - use Classical.arbitrary X - refine IsClopen.eq_univ ⟨?_, ?_⟩ (by simp) - · rw [isClosed_iff_nhds] - intro y H - rcases (path_connected_basis y).ex_mem with ⟨U, ⟨U_in, hU⟩⟩ - rcases H U U_in with ⟨z, hz, hz'⟩ - exact (hU.joinedIn z hz y <| mem_of_mem_nhds U_in).joined.mem_pathComponent hz' - · rw [isOpen_iff_mem_nhds] - intro y y_in - rcases (path_connected_basis y).ex_mem with ⟨U, ⟨U_in, hU⟩⟩ - apply mem_of_superset U_in - rw [← pathComponent_congr y_in] - exact hU.subset_pathComponent (mem_of_mem_nhds U_in) - -theorem pathConnected_subset_basis [LocPathConnectedSpace X] {U : Set X} (h : IsOpen U) - (hx : x ∈ U) : (𝓝 x).HasBasis (fun s : Set X => s ∈ 𝓝 x ∧ IsPathConnected s ∧ s ⊆ U) id := +theorem LocPathConnectedSpace.of_bases {p : X → ι → Prop} {s : X → ι → Set X} + (h : ∀ x, (𝓝 x).HasBasis (p x) (s x)) (h' : ∀ x i, p x i → IsPathConnected (s x i)) : + LocPathConnectedSpace X where + path_connected_basis x := by + rw [hasBasis_self] + intro t ht + rcases (h x).mem_iff.mp ht with ⟨i, hpi, hi⟩ + exact ⟨s x i, (h x).mem_of_mem hpi, h' x i hpi, hi⟩ + +@[deprecated (since := "2024-10-16")] +alias locPathConnected_of_bases := LocPathConnectedSpace.of_bases + +variable [LocPathConnectedSpace X] + +/-- In a locally path connected space, each path component is an open set. -/ +protected theorem IsOpen.pathComponent (x : X) : IsOpen (pathComponent x) := by + rw [isOpen_iff_mem_nhds] + intro y hxy + rcases (path_connected_basis y).ex_mem with ⟨V, hVy, hVc⟩ + filter_upwards [hVy] with z hz + exact hxy.out.trans (hVc.joinedIn _ (mem_of_mem_nhds hVy) _ hz).joined + +/-- In a locally path connected space, each path component is a closed set. -/ +protected theorem IsClosed.pathComponent (x : X) : IsClosed (pathComponent x) := by + rw [← isOpen_compl_iff, isOpen_iff_mem_nhds] + intro y hxy + rcases (path_connected_basis y).ex_mem with ⟨V, hVy, hVc⟩ + filter_upwards [hVy] with z hz hxz + exact hxy <| hxz.trans (hVc.joinedIn _ hz _ (mem_of_mem_nhds hVy)).joined + +/-- In a locally path connected space, each path component is a clopen set. -/ +protected theorem IsClopen.pathComponent (x : X) : IsClopen (pathComponent x) := + ⟨.pathComponent x, .pathComponent x⟩ + +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 + +theorem pathComponent_eq_connectedComponent (x : X) : pathComponent x = connectedComponent x := + (pathComponent_subset_component x).antisymm <| + (IsClopen.pathComponent x).connectedComponent_subset (mem_pathComponent_self _) + +theorem pathConnected_subset_basis {U : Set X} (h : IsOpen U) (hx : x ∈ U) : + (𝓝 x).HasBasis (fun s : Set X => s ∈ 𝓝 x ∧ IsPathConnected s ∧ s ⊆ U) id := (path_connected_basis x).hasBasis_self_subset (IsOpen.mem_nhds h hx) -theorem locPathConnected_of_isOpen [LocPathConnectedSpace X] {U : Set X} (h : IsOpen U) : - LocPathConnectedSpace U := - ⟨by - rintro ⟨x, x_in⟩ - rw [nhds_subtype_eq_comap] - constructor - intro V - rw [(HasBasis.comap ((↑) : U → X) (pathConnected_subset_basis h x_in)).mem_iff] - constructor - · rintro ⟨W, ⟨W_in, hW, hWU⟩, hWV⟩ - exact ⟨Subtype.val ⁻¹' W, ⟨⟨preimage_mem_comap W_in, hW.preimage_coe hWU⟩, hWV⟩⟩ - · rintro ⟨W, ⟨W_in, hW⟩, hWV⟩ - refine - ⟨(↑) '' W, - ⟨Filter.image_coe_mem_of_mem_comap (IsOpen.mem_nhds h x_in) W_in, - hW.image continuous_subtype_val, Subtype.coe_image_subset U W⟩, - ?_⟩ - rintro x ⟨y, ⟨y_in, hy⟩⟩ - rw [← Subtype.coe_injective hy] - tauto⟩ - -theorem IsOpen.isConnected_iff_isPathConnected [LocPathConnectedSpace X] {U : Set X} - (U_op : IsOpen U) : IsPathConnected U ↔ IsConnected U := by +theorem IsOpenEmbedding.locPathConnectedSpace {e : Y → X} (he : IsOpenEmbedding e) : + LocPathConnectedSpace Y := + have (y : Y) : + (𝓝 y).HasBasis (fun s ↦ s ∈ 𝓝 (e y) ∧ IsPathConnected s ∧ s ⊆ range e) (e ⁻¹' ·) := + he.basis_nhds <| pathConnected_subset_basis he.isOpen_range (mem_range_self _) + .of_bases this fun x s ⟨_, hs, hse⟩ ↦ by + rwa [he.isPathConnected_iff, image_preimage_eq_of_subset hse] + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.locPathConnectedSpace := IsOpenEmbedding.locPathConnectedSpace + +theorem IsOpen.locPathConnectedSpace {U : Set X} (h : IsOpen U) : LocPathConnectedSpace U := + (isOpenEmbedding_subtypeVal h).locPathConnectedSpace + +@[deprecated (since := "2024-10-17")] +alias locPathConnected_of_isOpen := IsOpen.locPathConnectedSpace + +theorem IsOpen.isConnected_iff_isPathConnected {U : Set X} (U_op : IsOpen U) : + IsConnected U ↔ IsPathConnected U := by rw [isConnected_iff_connectedSpace, isPathConnected_iff_pathConnectedSpace] - haveI := locPathConnected_of_isOpen U_op - exact pathConnectedSpace_iff_connectedSpace + haveI := U_op.locPathConnectedSpace + exact pathConnectedSpace_iff_connectedSpace.symm + +end LocPathConnectedSpace diff --git a/Mathlib/Topology/Connected/Separation.lean b/Mathlib/Topology/Connected/Separation.lean index 8ce21856914c0..f5e3e067c4839 100644 --- a/Mathlib/Topology/Connected/Separation.lean +++ b/Mathlib/Topology/Connected/Separation.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Dagur Asgeirsson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Separation and (dis)connectedness properties of topological spaces. diff --git a/Mathlib/Topology/Connected/TotallyDisconnected.lean b/Mathlib/Topology/Connected/TotallyDisconnected.lean index 0da1004c037f4..2c3fd5760bfaa 100644 --- a/Mathlib/Topology/Connected/TotallyDisconnected.lean +++ b/Mathlib/Topology/Connected/TotallyDisconnected.lean @@ -141,25 +141,34 @@ theorem isTotallyDisconnected_of_image [TopologicalSpace β] {f : α → β} (hf h _ (image_subset f hts) (ht.image f <| hf.mono hts) (mem_image_of_mem f x_in) (mem_image_of_mem f y_in) -theorem Embedding.isTotallyDisconnected [TopologicalSpace β] {f : α → β} (hf : Embedding f) - {s : Set α} (h : IsTotallyDisconnected (f '' s)) : IsTotallyDisconnected s := +lemma IsEmbedding.isTotallyDisconnected [TopologicalSpace β] {f : α → β} {s : Set α} + (hf : IsEmbedding f) (h : IsTotallyDisconnected (f '' s)) : IsTotallyDisconnected s := isTotallyDisconnected_of_image hf.continuous.continuousOn hf.inj h -lemma Embedding.isTotallyDisconnected_image [TopologicalSpace β] {f : α → β} (hf : Embedding f) - {s : Set α} : IsTotallyDisconnected (f '' s) ↔ IsTotallyDisconnected s := by +@[deprecated (since := "2024-10-26")] +alias Embedding.isTotallyDisconnected := IsEmbedding.isTotallyDisconnected + +lemma IsEmbedding.isTotallyDisconnected_image [TopologicalSpace β] {f : α → β} {s : Set α} + (hf : IsEmbedding f) : IsTotallyDisconnected (f '' s) ↔ IsTotallyDisconnected s := by refine ⟨hf.isTotallyDisconnected, fun hs u hus hu ↦ ?_⟩ obtain ⟨v, hvs, rfl⟩ : ∃ v, v ⊆ s ∧ f '' v = u := ⟨f ⁻¹' u ∩ s, inter_subset_right, by rwa [image_preimage_inter, inter_eq_left]⟩ - rw [hf.toInducing.isPreconnected_image] at hu + rw [hf.isInducing.isPreconnected_image] at hu exact (hs v hvs hu).image _ -lemma Embedding.isTotallyDisconnected_range [TopologicalSpace β] {f : α → β} (hf : Embedding f) : - IsTotallyDisconnected (range f) ↔ TotallyDisconnectedSpace α := by +@[deprecated (since := "2024-10-26")] +alias Embedding.isTotallyDisconnected_image := IsEmbedding.isTotallyDisconnected_image + +lemma IsEmbedding.isTotallyDisconnected_range [TopologicalSpace β] {f : α → β} + (hf : IsEmbedding f) : IsTotallyDisconnected (range f) ↔ TotallyDisconnectedSpace α := by rw [totallyDisconnectedSpace_iff, ← image_univ, hf.isTotallyDisconnected_image] +@[deprecated (since := "2024-10-26")] +alias Embedding.isTotallyDisconnected_range := IsEmbedding.isTotallyDisconnected_range + lemma totallyDisconnectedSpace_subtype_iff {s : Set α} : TotallyDisconnectedSpace s ↔ IsTotallyDisconnected s := by - rw [← embedding_subtype_val.isTotallyDisconnected_range, Subtype.range_val] + rw [← IsEmbedding.subtypeVal.isTotallyDisconnected_range, Subtype.range_val] instance Subtype.totallyDisconnectedSpace {α : Type*} {p : α → Prop} [TopologicalSpace α] [TotallyDisconnectedSpace α] : TotallyDisconnectedSpace (Subtype p) := @@ -195,7 +204,7 @@ alias IsTotallySeparated.isTotallyDisconnected := isTotallyDisconnected_of_isTot /-- A space is totally separated if any two points can be separated by two disjoint open sets covering the whole space. -/ -class TotallySeparatedSpace (α : Type u) [TopologicalSpace α] : Prop where +@[mk_iff] class TotallySeparatedSpace (α : Type u) [TopologicalSpace α] : Prop where /-- The universal set `Set.univ` in a totally separated space is totally separated. -/ isTotallySeparated_univ : IsTotallySeparated (univ : Set α) @@ -210,15 +219,19 @@ instance (priority := 100) TotallySeparatedSpace.of_discrete (α : Type*) [Topol ⟨fun _ _ b _ h => ⟨{b}ᶜ, {b}, isOpen_discrete _, isOpen_discrete _, h, rfl, (compl_union_self _).symm.subset, disjoint_compl_left⟩⟩ +theorem totallySeparatedSpace_iff_exists_isClopen {α : Type*} [TopologicalSpace α] : + TotallySeparatedSpace α ↔ ∀ x y : α, x ≠ y → ∃ U : Set α, IsClopen U ∧ x ∈ U ∧ y ∈ Uᶜ := by + simp only [totallySeparatedSpace_iff, IsTotallySeparated, Set.Pairwise, mem_univ, true_implies] + refine forall₃_congr fun x y _ ↦ + ⟨fun ⟨U, V, hU, hV, Ux, Vy, f, disj⟩ ↦ ?_, fun ⟨U, hU, Ux, Ucy⟩ ↦ ?_⟩ + · exact ⟨U, isClopen_of_disjoint_cover_open f hU hV disj, + Ux, fun Uy ↦ Set.disjoint_iff.mp disj ⟨Uy, Vy⟩⟩ + · exact ⟨U, Uᶜ, hU.2, hU.compl.2, Ux, Ucy, (Set.union_compl_self U).ge, disjoint_compl_right⟩ + theorem exists_isClopen_of_totally_separated {α : Type*} [TopologicalSpace α] [TotallySeparatedSpace α] {x y : α} (hxy : x ≠ y) : - ∃ U : Set α, IsClopen U ∧ x ∈ U ∧ y ∈ Uᶜ := by - obtain ⟨U, V, hU, hV, Ux, Vy, f, disj⟩ := - TotallySeparatedSpace.isTotallySeparated_univ (Set.mem_univ x) (Set.mem_univ y) hxy - have hU := isClopen_inter_of_disjoint_cover_clopen isClopen_univ f hU hV disj - rw [univ_inter _] at hU - rw [← Set.subset_compl_iff_disjoint_right, subset_compl_comm] at disj - exact ⟨U, hU, Ux, disj Vy⟩ + ∃ U : Set α, IsClopen U ∧ x ∈ U ∧ y ∈ Uᶜ := + totallySeparatedSpace_iff_exists_isClopen.mp ‹_› _ _ hxy end TotallySeparated @@ -260,12 +273,11 @@ theorem Continuous.connectedComponentsLift_unique (h : Continuous f) (g : Connec (hg : g ∘ (↑) = f) : g = h.connectedComponentsLift := connectedComponents_lift_unique' <| hg.trans h.connectedComponentsLift_comp_coe.symm - instance ConnectedComponents.totallyDisconnectedSpace : TotallyDisconnectedSpace (ConnectedComponents α) := by rw [totallyDisconnectedSpace_iff_connectedComponent_singleton] refine ConnectedComponents.surjective_coe.forall.2 fun x => ?_ - rw [← ConnectedComponents.quotientMap_coe.image_connectedComponent, ← + rw [← ConnectedComponents.isQuotientMap_coe.image_connectedComponent, ← connectedComponents_preimage_singleton, image_preimage_eq _ ConnectedComponents.surjective_coe] refine ConnectedComponents.surjective_coe.forall.2 fun y => ?_ rw [connectedComponents_preimage_singleton] diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 655e49f24bd70..4544c981222a1 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -628,7 +628,7 @@ theorem prod_generateFrom_generateFrom_eq {X Y : Type*} {s : Set (Set X)} {t : S generateFrom (image2 (· ×ˢ ·) s t) := let G := generateFrom (image2 (· ×ˢ ·) s t) le_antisymm - (le_generateFrom fun g ⟨u, hu, v, hv, g_eq⟩ => + (le_generateFrom fun _ ⟨_, hu, _, hv, g_eq⟩ => g_eq.symm ▸ @IsOpen.prod _ _ (generateFrom s) (generateFrom t) _ _ (GenerateOpen.basic _ hu) (GenerateOpen.basic _ hv)) @@ -656,7 +656,7 @@ theorem prod_generateFrom_generateFrom_eq {X Y : Type*} {s : Set (Set X)} {t : S theorem prod_eq_generateFrom : instTopologicalSpaceProd = generateFrom { g | ∃ (s : Set X) (t : Set Y), IsOpen s ∧ IsOpen t ∧ g = s ×ˢ t } := - le_antisymm (le_generateFrom fun g ⟨s, t, hs, ht, g_eq⟩ => g_eq.symm ▸ hs.prod ht) + le_antisymm (le_generateFrom fun _ ⟨_, _, hs, ht, g_eq⟩ => g_eq.symm ▸ hs.prod ht) (le_inf (forall_mem_image.2 fun t ht => GenerateOpen.basic _ ⟨t, univ, by simpa [Set.prod_eq] using ht⟩) @@ -739,11 +739,17 @@ theorem isOpen_prod_iff' {s : Set X} {t : Set Y} : simp only [st.1.ne_empty, st.2.ne_empty, not_false_iff, or_false] at H exact H.1.prod H.2 -theorem quotientMap_fst [Nonempty Y] : QuotientMap (Prod.fst : X × Y → X) := - isOpenMap_fst.to_quotientMap continuous_fst Prod.fst_surjective +theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := + isOpenMap_fst.isQuotientMap continuous_fst Prod.fst_surjective -theorem quotientMap_snd [Nonempty X] : QuotientMap (Prod.snd : X × Y → Y) := - isOpenMap_snd.to_quotientMap continuous_snd Prod.snd_surjective +@[deprecated (since := "2024-10-22")] +alias quotientMap_fst := isQuotientMap_fst + +theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := + isOpenMap_snd.isQuotientMap continuous_snd Prod.snd_surjective + +@[deprecated (since := "2024-10-22")] +alias quotientMap_snd := isQuotientMap_snd theorem closure_prod_eq {s : Set X} {t : Set Y} : closure (s ×ˢ t) = closure s ×ˢ closure t := ext fun ⟨a, b⟩ => by @@ -790,27 +796,38 @@ theorem DenseRange.prodMap {ι : Type*} {κ : Type*} {f : ι → Y} {g : κ → @[deprecated (since := "2024-10-05")] alias DenseRange.prod_map := DenseRange.prodMap -theorem Inducing.prodMap {f : X → Y} {g : Z → W} (hf : Inducing f) (hg : Inducing g) : - Inducing (Prod.map f g) := - inducing_iff_nhds.2 fun (x, z) => by simp_rw [Prod.map_def, nhds_prod_eq, hf.nhds_eq_comap, +lemma IsInducing.prodMap {f : X → Y} {g : Z → W} (hf : IsInducing f) (hg : IsInducing g) : + IsInducing (Prod.map f g) := + isInducing_iff_nhds.2 fun (x, z) => by simp_rw [Prod.map_def, nhds_prod_eq, hf.nhds_eq_comap, hg.nhds_eq_comap, prod_comap_comap_eq] -@[deprecated (since := "2024-10-05")] alias Inducing.prod_map := Inducing.prodMap +@[deprecated (since := "2024-10-28")] alias Inducing.prodMap := IsInducing.prodMap + +@[deprecated (since := "2024-10-05")] alias Inducing.prod_map := IsInducing.prodMap @[simp] -theorem inducing_const_prod {x : X} {f : Y → Z} : (Inducing fun x' => (x, f x')) ↔ Inducing f := by - simp_rw [inducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, Function.comp_def, - induced_const, top_inf_eq] +lemma isInducing_const_prod {x : X} {f : Y → Z} : + IsInducing (fun x' => (x, f x')) ↔ IsInducing f := by + simp_rw [isInducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, + Function.comp_def, induced_const, top_inf_eq] + +@[deprecated (since := "2024-10-28")] alias inducing_const_prod := isInducing_const_prod @[simp] -theorem inducing_prod_const {y : Y} {f : X → Z} : (Inducing fun x => (f x, y)) ↔ Inducing f := by - simp_rw [inducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, Function.comp_def, - induced_const, inf_top_eq] +lemma isInducing_prod_const {y : Y} {f : X → Z} : + IsInducing (fun x => (f x, y)) ↔ IsInducing f := by + simp_rw [isInducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, + Function.comp_def, induced_const, inf_top_eq] + +@[deprecated (since := "2024-10-28")] alias inducing_prod_const := isInducing_prod_const -theorem Embedding.prodMap {f : X → Y} {g : Z → W} (hf : Embedding f) (hg : Embedding g) : - Embedding (Prod.map f g) := - { hf.toInducing.prodMap hg.toInducing with - inj := fun ⟨x₁, z₁⟩ ⟨x₂, z₂⟩ => by simp [hf.inj.eq_iff, hg.inj.eq_iff] } +lemma IsEmbedding.prodMap {f : X → Y} {g : Z → W} (hf : IsEmbedding f) + (hg : IsEmbedding g) : IsEmbedding (Prod.map f g) where + toIsInducing := hf.isInducing.prodMap hg.isInducing + inj := hf.inj.prodMap hg.inj + +@[deprecated (since := "2024-10-26")] +alias Embedding.prodMap := IsEmbedding.prodMap @[deprecated (since := "2024-10-05")] alias Embedding.prod_map := Embedding.prodMap @@ -823,17 +840,26 @@ protected theorem IsOpenMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenMap @[deprecated (since := "2024-10-05")] alias IsOpenMap.prod := IsOpenMap.prodMap -protected theorem OpenEmbedding.prodMap {f : X → Y} {g : Z → W} (hf : OpenEmbedding f) - (hg : OpenEmbedding g) : OpenEmbedding (Prod.map f g) := - openEmbedding_of_embedding_open (hf.1.prodMap hg.1) (hf.isOpenMap.prodMap hg.isOpenMap) +protected theorem IsOpenEmbedding.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenEmbedding f) + (hg : IsOpenEmbedding g) : IsOpenEmbedding (Prod.map f g) := + .of_isEmbedding_isOpenMap (hf.1.prodMap hg.1) (hf.isOpenMap.prodMap hg.isOpenMap) + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.prodMap := IsOpenEmbedding.prodMap + +@[deprecated (since := "2024-10-05")] alias IsOpenEmbedding.prod := IsOpenEmbedding.prodMap + +lemma isEmbedding_graph {f : X → Y} (hf : Continuous f) : IsEmbedding fun x => (x, f x) := + .of_comp (continuous_id.prod_mk hf) continuous_fst .id -@[deprecated (since := "2024-10-05")] alias OpenEmbedding.prod := OpenEmbedding.prodMap +@[deprecated (since := "2024-10-26")] +alias embedding_graph := isEmbedding_graph -theorem embedding_graph {f : X → Y} (hf : Continuous f) : Embedding fun x => (x, f x) := - embedding_of_embedding_compose (continuous_id.prod_mk hf) continuous_fst embedding_id +lemma isEmbedding_prodMk (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) := + .of_comp (Continuous.Prod.mk x) continuous_snd .id -theorem embedding_prod_mk (x : X) : Embedding (Prod.mk x : Y → X × Y) := - embedding_of_embedding_compose (Continuous.Prod.mk x) continuous_snd embedding_id +@[deprecated (since := "2024-10-26")] +alias embedding_prod_mk := isEmbedding_prodMk theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := @@ -880,11 +906,9 @@ theorem continuous_isRight : Continuous (isRight : X ⊕ Y → Bool) := continuous_sum_dom.2 ⟨continuous_const, continuous_const⟩ @[continuity, fun_prop] --- Porting note: the proof was `continuous_sup_rng_left continuous_coinduced_rng` theorem continuous_inl : Continuous (@inl X Y) := ⟨fun _ => And.left⟩ @[continuity, fun_prop] --- Porting note: the proof was `continuous_sup_rng_right continuous_coinduced_rng` theorem continuous_inr : Continuous (@inr X Y) := ⟨fun _ => And.right⟩ @[fun_prop, continuity] @@ -904,23 +928,29 @@ theorem isOpenMap_inl : IsOpenMap (@inl X Y) := fun u hu => by theorem isOpenMap_inr : IsOpenMap (@inr X Y) := fun u hu => by simpa [isOpen_sum_iff, preimage_image_eq u Sum.inr_injective] -theorem openEmbedding_inl : OpenEmbedding (@inl X Y) := - openEmbedding_of_continuous_injective_open continuous_inl inl_injective isOpenMap_inl +theorem isOpenEmbedding_inl : IsOpenEmbedding (@inl X Y) := + isOpenEmbedding_of_continuous_injective_open continuous_inl inl_injective isOpenMap_inl -theorem openEmbedding_inr : OpenEmbedding (@inr X Y) := - openEmbedding_of_continuous_injective_open continuous_inr inr_injective isOpenMap_inr +@[deprecated (since := "2024-10-18")] +alias openEmbedding_inl := isOpenEmbedding_inl -theorem embedding_inl : Embedding (@inl X Y) := - openEmbedding_inl.1 +theorem isOpenEmbedding_inr : IsOpenEmbedding (@inr X Y) := + isOpenEmbedding_of_continuous_injective_open continuous_inr inr_injective isOpenMap_inr -theorem embedding_inr : Embedding (@inr X Y) := - openEmbedding_inr.1 +@[deprecated (since := "2024-10-18")] +alias openEmbedding_inr := isOpenEmbedding_inr + +protected lemma IsEmbedding.inl : IsEmbedding (@inl X Y) := isOpenEmbedding_inl.1 +protected lemma IsEmbedding.inr : IsEmbedding (@inr X Y) := isOpenEmbedding_inr.1 + +@[deprecated (since := "2024-10-26")] +alias embedding_inr := IsEmbedding.inr theorem isOpen_range_inl : IsOpen (range (inl : X → X ⊕ Y)) := - openEmbedding_inl.2 + isOpenEmbedding_inl.2 theorem isOpen_range_inr : IsOpen (range (inr : Y → X ⊕ Y)) := - openEmbedding_inr.2 + isOpenEmbedding_inr.2 theorem isClosed_range_inl : IsClosed (range (inl : X → X ⊕ Y)) := by rw [← isOpen_compl_iff, compl_range_inl] @@ -930,23 +960,29 @@ theorem isClosed_range_inr : IsClosed (range (inr : Y → X ⊕ Y)) := by rw [← isOpen_compl_iff, compl_range_inr] exact isOpen_range_inl -theorem closedEmbedding_inl : ClosedEmbedding (inl : X → X ⊕ Y) := - ⟨embedding_inl, isClosed_range_inl⟩ +theorem isClosedEmbedding_inl : IsClosedEmbedding (inl : X → X ⊕ Y) := + ⟨.inl, isClosed_range_inl⟩ + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_inl := isClosedEmbedding_inl -theorem closedEmbedding_inr : ClosedEmbedding (inr : Y → X ⊕ Y) := - ⟨embedding_inr, isClosed_range_inr⟩ +theorem isClosedEmbedding_inr : IsClosedEmbedding (inr : Y → X ⊕ Y) := + ⟨.inr, isClosed_range_inr⟩ + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_inr := isClosedEmbedding_inr theorem nhds_inl (x : X) : 𝓝 (inl x : X ⊕ Y) = map inl (𝓝 x) := - (openEmbedding_inl.map_nhds_eq _).symm + (isOpenEmbedding_inl.map_nhds_eq _).symm theorem nhds_inr (y : Y) : 𝓝 (inr y : X ⊕ Y) = map inr (𝓝 y) := - (openEmbedding_inr.map_nhds_eq _).symm + (isOpenEmbedding_inr.map_nhds_eq _).symm @[simp] theorem continuous_sum_map {f : X → Y} {g : Z → W} : Continuous (Sum.map f g) ↔ Continuous f ∧ Continuous g := continuous_sum_elim.trans <| - embedding_inl.continuous_iff.symm.and embedding_inr.continuous_iff.symm + IsEmbedding.inl.continuous_iff.symm.and IsEmbedding.inr.continuous_iff.symm @[continuity, fun_prop] theorem Continuous.sum_map {f : X → Y} {g : Z → W} (hf : Continuous f) (hg : Continuous g) : @@ -974,7 +1010,7 @@ theorem isClosedMap_sum {f : X ⊕ Y → Z} : IsClosedMap f ↔ (IsClosedMap fun a => f (.inl a)) ∧ IsClosedMap fun b => f (.inr b) := by constructor · intro h - exact ⟨h.comp closedEmbedding_inl.isClosedMap, h.comp closedEmbedding_inr.isClosedMap⟩ + exact ⟨h.comp isClosedEmbedding_inl.isClosedMap, h.comp isClosedEmbedding_inr.isClosedMap⟩ · rintro h Z hZ rw [isClosed_sum_iff] at hZ convert (h.1 _ hZ.1).union (h.2 _ hZ.2) @@ -987,18 +1023,27 @@ section Subtype variable [TopologicalSpace X] [TopologicalSpace Y] {p : X → Prop} -theorem inducing_subtype_val {t : Set Y} : Inducing ((↑) : t → Y) := ⟨rfl⟩ +lemma IsInducing.subtypeVal {t : Set Y} : IsInducing ((↑) : t → Y) := ⟨rfl⟩ + +@[deprecated (since := "2024-10-28")] alias inducing_subtype_val := IsInducing.subtypeVal -theorem Inducing.of_codRestrict {f : X → Y} {t : Set Y} (ht : ∀ x, f x ∈ t) - (h : Inducing (t.codRestrict f ht)) : Inducing f := - inducing_subtype_val.comp h +lemma IsInducing.of_codRestrict {f : X → Y} {t : Set Y} (ht : ∀ x, f x ∈ t) + (h : IsInducing (t.codRestrict f ht)) : IsInducing f := subtypeVal.comp h -theorem embedding_subtype_val : Embedding ((↑) : Subtype p → X) := - ⟨inducing_subtype_val, Subtype.coe_injective⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.of_codRestrict := IsInducing.of_codRestrict -theorem closedEmbedding_subtype_val (h : IsClosed { a | p a }) : - ClosedEmbedding ((↑) : Subtype p → X) := - ⟨embedding_subtype_val, by rwa [Subtype.range_coe_subtype]⟩ +lemma IsEmbedding.subtypeVal : IsEmbedding ((↑) : Subtype p → X) := + ⟨.subtypeVal, Subtype.coe_injective⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_subtype_val := IsEmbedding.subtypeVal + +theorem IsClosedEmbedding.subtypeVal (h : IsClosed {a | p a}) : + IsClosedEmbedding ((↑) : Subtype p → X) := + ⟨.subtypeVal, by rwa [Subtype.range_coe_subtype]⟩ + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_subtype_val := IsClosedEmbedding.subtypeVal @[continuity, fun_prop] theorem continuous_subtype_val : Continuous (@Subtype.val X p) := @@ -1008,24 +1053,29 @@ theorem Continuous.subtype_val {f : Y → Subtype p} (hf : Continuous f) : Continuous fun x => (f x : X) := continuous_subtype_val.comp hf -theorem IsOpen.openEmbedding_subtype_val {s : Set X} (hs : IsOpen s) : - OpenEmbedding ((↑) : s → X) := - ⟨embedding_subtype_val, (@Subtype.range_coe _ s).symm ▸ hs⟩ +theorem IsOpen.isOpenEmbedding_subtypeVal {s : Set X} (hs : IsOpen s) : + IsOpenEmbedding ((↑) : s → X) := + ⟨.subtypeVal, (@Subtype.range_coe _ s).symm ▸ hs⟩ + +@[deprecated (since := "2024-10-18")] +alias IsOpen.openEmbedding_subtype_val := IsOpen.isOpenEmbedding_subtypeVal theorem IsOpen.isOpenMap_subtype_val {s : Set X} (hs : IsOpen s) : IsOpenMap ((↑) : s → X) := - hs.openEmbedding_subtype_val.isOpenMap + hs.isOpenEmbedding_subtypeVal.isOpenMap theorem IsOpenMap.restrict {f : X → Y} (hf : IsOpenMap f) {s : Set X} (hs : IsOpen s) : IsOpenMap (s.restrict f) := hf.comp hs.isOpenMap_subtype_val -nonrec theorem IsClosed.closedEmbedding_subtype_val {s : Set X} (hs : IsClosed s) : - ClosedEmbedding ((↑) : s → X) := - closedEmbedding_subtype_val hs +lemma IsClosed.isClosedEmbedding_subtypeVal {s : Set X} (hs : IsClosed s) : + IsClosedEmbedding ((↑) : s → X) := .subtypeVal hs + +@[deprecated (since := "2024-10-20")] +alias IsClosed.closedEmbedding_subtype_val := IsClosed.isClosedEmbedding_subtypeVal theorem IsClosed.isClosedMap_subtype_val {s : Set X} (hs : IsClosed s) : IsClosedMap ((↑) : s → X) := - hs.closedEmbedding_subtype_val.isClosedMap + hs.isClosedEmbedding_subtypeVal.isClosedMap @[continuity, fun_prop] theorem Continuous.subtype_mk {f : Y → X} (h : Continuous f) (hp : ∀ x, p (f x)) : @@ -1044,11 +1094,11 @@ theorem continuousAt_subtype_val {p : X → Prop} {x : Subtype p} : continuous_subtype_val.continuousAt theorem Subtype.dense_iff {s : Set X} {t : Set s} : Dense t ↔ s ⊆ closure ((↑) '' t) := by - rw [inducing_subtype_val.dense_iff, SetCoe.forall] + rw [IsInducing.subtypeVal.dense_iff, SetCoe.forall] rfl theorem map_nhds_subtype_val {s : Set X} (x : s) : map ((↑) : s → X) (𝓝 x) = 𝓝[s] ↑x := by - rw [inducing_subtype_val.map_nhds_eq, Subtype.range_val] + rw [IsInducing.subtypeVal.map_nhds_eq, Subtype.range_val] theorem map_nhds_subtype_coe_eq_nhds {x : X} (hx : p x) (h : ∀ᶠ x in 𝓝 x, p x) : map ((↑) : Subtype p → X) (𝓝 ⟨x, hx⟩) = 𝓝 x := @@ -1068,7 +1118,7 @@ theorem closure_subtype {x : { a // p a }} {s : Set { a // p a }} : @[simp] theorem continuousAt_codRestrict_iff {f : X → Y} {t : Set Y} (h1 : ∀ x, f x ∈ t) {x : X} : ContinuousAt (codRestrict f t h1) x ↔ ContinuousAt f x := - inducing_subtype_val.continuousAt_iff + IsInducing.subtypeVal.continuousAt_iff alias ⟨_, ContinuousAt.codRestrict⟩ := continuousAt_codRestrict_iff @@ -1095,22 +1145,30 @@ theorem Continuous.restrictPreimage {f : X → Y} {s : Set Y} (h : Continuous f) Continuous (s.restrictPreimage f) := h.restrict _ -theorem Inducing.codRestrict {e : X → Y} (he : Inducing e) {s : Set Y} (hs : ∀ x, e x ∈ s) : - Inducing (codRestrict e s hs) := - inducing_of_inducing_compose (he.continuous.codRestrict hs) continuous_subtype_val he +theorem IsInducing.codRestrict {e : X → Y} (he : IsInducing e) {s : Set Y} + (hs : ∀ x, e x ∈ s) : IsInducing (codRestrict e s hs) := + he.of_comp (he.continuous.codRestrict hs) continuous_subtype_val + +@[deprecated (since := "2024-10-28")] alias Inducing.codRestrict := IsInducing.codRestrict + +protected lemma IsEmbedding.codRestrict {e : X → Y} (he : IsEmbedding e) (s : Set Y) + (hs : ∀ x, e x ∈ s) : IsEmbedding (codRestrict e s hs) := + he.of_comp (he.continuous.codRestrict hs) continuous_subtype_val -theorem Embedding.codRestrict {e : X → Y} (he : Embedding e) (s : Set Y) (hs : ∀ x, e x ∈ s) : - Embedding (codRestrict e s hs) := - embedding_of_embedding_compose (he.continuous.codRestrict hs) continuous_subtype_val he +@[deprecated (since := "2024-10-26")] +alias Embedding.codRestrict := IsEmbedding.codRestrict -theorem embedding_inclusion {s t : Set X} (h : s ⊆ t) : Embedding (inclusion h) := - embedding_subtype_val.codRestrict _ _ +protected lemma IsEmbedding.inclusion {s t : Set X} (h : s ⊆ t) : + IsEmbedding (inclusion h) := IsEmbedding.subtypeVal.codRestrict _ _ + +@[deprecated (since := "2024-10-26")] +alias embedding_inclusion := IsEmbedding.inclusion /-- Let `s, t ⊆ X` be two subsets of a topological space `X`. If `t ⊆ s` and the topology induced by `X`on `s` is discrete, then also the topology induces on `t` is discrete. -/ theorem DiscreteTopology.of_subset {X : Type*} [TopologicalSpace X] {s t : Set X} (_ : DiscreteTopology s) (ts : t ⊆ s) : DiscreteTopology t := - (embedding_inclusion ts).discreteTopology + (IsEmbedding.inclusion ts).discreteTopology /-- Let `s` be a discrete subset of a topological space. Then the preimage of `s` by a continuous injective map is also discrete. -/ @@ -1122,20 +1180,30 @@ theorem DiscreteTopology.preimage_of_continuous_injective {X Y : Type*} [Topolog /-- If `f : X → Y` is a quotient map, then its restriction to the preimage of an open set is a quotient map too. -/ -theorem QuotientMap.restrictPreimage_isOpen {f : X → Y} (hf : QuotientMap f) - {s : Set Y} (hs : IsOpen s) : QuotientMap (s.restrictPreimage f) := by - refine quotientMap_iff.2 ⟨hf.surjective.restrictPreimage _, fun U ↦ ?_⟩ - rw [hs.openEmbedding_subtype_val.open_iff_image_open, ← hf.isOpen_preimage, - (hs.preimage hf.continuous).openEmbedding_subtype_val.open_iff_image_open, +theorem IsQuotientMap.restrictPreimage_isOpen {f : X → Y} (hf : IsQuotientMap f) + {s : Set Y} (hs : IsOpen s) : IsQuotientMap (s.restrictPreimage f) := by + refine isQuotientMap_iff.2 ⟨hf.surjective.restrictPreimage _, fun U ↦ ?_⟩ + rw [hs.isOpenEmbedding_subtypeVal.open_iff_image_open, ← hf.isOpen_preimage, + (hs.preimage hf.continuous).isOpenEmbedding_subtypeVal.open_iff_image_open, image_val_preimage_restrictPreimage] +@[deprecated (since := "2024-10-22")] +alias QuotientMap.restrictPreimage_isOpen := IsQuotientMap.restrictPreimage_isOpen + open scoped Set.Notation in lemma isClosed_preimage_val {s t : Set X} : IsClosed (s ↓∩ t) ↔ s ∩ closure (s ∩ t) ⊆ t := by - rw [← closure_eq_iff_isClosed, embedding_subtype_val.closure_eq_preimage_closure_image, + rw [← closure_eq_iff_isClosed, IsEmbedding.subtypeVal.closure_eq_preimage_closure_image, ← Subtype.val_injective.image_injective.eq_iff, Subtype.image_preimage_coe, Subtype.image_preimage_coe, subset_antisymm_iff, and_iff_left, Set.subset_inter_iff, and_iff_right] exacts [Set.inter_subset_left, Set.subset_inter Set.inter_subset_left subset_closure] + +theorem frontier_inter_open_inter {s t : Set X} (ht : IsOpen t) : + frontier (s ∩ t) ∩ t = frontier s ∩ t := by + simp only [Set.inter_comm _ t, ← Subtype.preimage_coe_eq_preimage_coe_iff, + ht.isOpenMap_subtype_val.preimage_frontier_eq_frontier_preimage continuous_subtype_val, + Subtype.preimage_coe_self_inter] + end Subtype section Quotient @@ -1143,9 +1211,12 @@ section Quotient variable [TopologicalSpace X] [TopologicalSpace Y] variable {r : X → X → Prop} {s : Setoid X} -theorem quotientMap_quot_mk : QuotientMap (@Quot.mk X r) := +theorem isQuotientMap_quot_mk : IsQuotientMap (@Quot.mk X r) := ⟨Quot.exists_rep, rfl⟩ +@[deprecated (since := "2024-10-22")] +alias quotientMap_quot_mk := isQuotientMap_quot_mk + @[continuity, fun_prop] theorem continuous_quot_mk : Continuous (@Quot.mk X r) := continuous_coinduced_rng @@ -1155,8 +1226,11 @@ theorem continuous_quot_lift {f : X → Y} (hr : ∀ a b, r a b → f a = f b) ( Continuous (Quot.lift f hr : Quot r → Y) := continuous_coinduced_dom.2 h -theorem quotientMap_quotient_mk' : QuotientMap (@Quotient.mk' X s) := - quotientMap_quot_mk +theorem isQuotientMap_quotient_mk' : IsQuotientMap (@Quotient.mk' X s) := + isQuotientMap_quot_mk + +@[deprecated (since := "2024-10-22")] +alias quotientMap_quotient_mk' := isQuotientMap_quotient_mk' theorem continuous_quotient_mk' : Continuous (@Quotient.mk' X s) := continuous_coinduced_rng @@ -1166,7 +1240,7 @@ theorem Continuous.quotient_lift {f : X → Y} (h : Continuous f) (hs : ∀ a b, continuous_coinduced_dom.2 h theorem Continuous.quotient_liftOn' {f : X → Y} (h : Continuous f) - (hs : ∀ a b, @Setoid.r _ s a b → f a = f b) : + (hs : ∀ a b, s a b → f a = f b) : Continuous (fun x => Quotient.liftOn' x f hs : Quotient s → Y) := h.quotient_lift hs @@ -1436,7 +1510,7 @@ theorem pi_eq_generateFrom : generateFrom { g | ∃ (s : ∀ a, Set (π a)) (i : Finset ι), (∀ a ∈ i, IsOpen (s a)) ∧ g = pi (↑i) s } := calc Pi.topologicalSpace - _ = @Pi.topologicalSpace ι π fun a => generateFrom { s | IsOpen s } := by + _ = @Pi.topologicalSpace ι π fun _ => generateFrom { s | IsOpen s } := by simp only [generateFrom_setOf_isOpen] _ = _ := pi_generateFrom_eq @@ -1468,7 +1542,7 @@ map `g : X → Π i, π i`. This lemma shows that infimum of the topologies on ` the `f i` as `i : ι` varies is simply the topology on `X` induced by `g : X → Π i, π i` where `Π i, π i` is endowed with the usual product topology. -/ theorem inducing_iInf_to_pi {X : Type*} (f : ∀ i, X → π i) : - @Inducing X (∀ i, π i) (⨅ i, induced (f i) inferInstance) _ fun x i => f i x := + @IsInducing X (∀ i, π i) (⨅ i, induced (f i) inferInstance) _ fun x i => f i x := letI := ⨅ i, induced (f i) inferInstance; ⟨(induced_to_pi _).symm⟩ variable [Finite ι] [∀ i, DiscreteTopology (π i)] @@ -1523,26 +1597,35 @@ theorem isClosedMap_sigmaMk {i : ι} : IsClosedMap (@Sigma.mk ι σ i) := by theorem isClosed_range_sigmaMk {i : ι} : IsClosed (range (@Sigma.mk ι σ i)) := isClosedMap_sigmaMk.isClosed_range -theorem openEmbedding_sigmaMk {i : ι} : OpenEmbedding (@Sigma.mk ι σ i) := - openEmbedding_of_continuous_injective_open continuous_sigmaMk sigma_mk_injective +theorem isOpenEmbedding_sigmaMk {i : ι} : IsOpenEmbedding (@Sigma.mk ι σ i) := + isOpenEmbedding_of_continuous_injective_open continuous_sigmaMk sigma_mk_injective isOpenMap_sigmaMk -theorem closedEmbedding_sigmaMk {i : ι} : ClosedEmbedding (@Sigma.mk ι σ i) := - closedEmbedding_of_continuous_injective_closed continuous_sigmaMk sigma_mk_injective +@[deprecated (since := "2024-10-18")] +alias openEmbedding_sigmaMk := isOpenEmbedding_sigmaMk + +theorem isClosedEmbedding_sigmaMk {i : ι} : IsClosedEmbedding (@Sigma.mk ι σ i) := + .of_continuous_injective_isClosedMap continuous_sigmaMk sigma_mk_injective isClosedMap_sigmaMk -theorem embedding_sigmaMk {i : ι} : Embedding (@Sigma.mk ι σ i) := - closedEmbedding_sigmaMk.1 +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_sigmaMk := isClosedEmbedding_sigmaMk + +lemma IsEmbedding.sigmaMk {i : ι} : IsEmbedding (@Sigma.mk ι σ i) := + isClosedEmbedding_sigmaMk.1 + +@[deprecated (since := "2024-10-26")] +alias embedding_sigmaMk := IsEmbedding.sigmaMk theorem Sigma.nhds_mk (i : ι) (x : σ i) : 𝓝 (⟨i, x⟩ : Sigma σ) = Filter.map (Sigma.mk i) (𝓝 x) := - (openEmbedding_sigmaMk.map_nhds_eq x).symm + (isOpenEmbedding_sigmaMk.map_nhds_eq x).symm theorem Sigma.nhds_eq (x : Sigma σ) : 𝓝 x = Filter.map (Sigma.mk x.1) (𝓝 x.2) := by cases x apply Sigma.nhds_mk theorem comap_sigmaMk_nhds (i : ι) (x : σ i) : comap (Sigma.mk i) (𝓝 ⟨i, x⟩) = 𝓝 x := - (embedding_sigmaMk.nhds_eq_comap _).symm + (IsEmbedding.sigmaMk.nhds_eq_comap _).symm theorem isOpen_sigma_fst_preimage (s : Set ι) : IsOpen (Sigma.fst ⁻¹' s : Set (Σ a, σ a)) := by rw [← biUnion_of_singleton s, preimage_iUnion₂] @@ -1567,13 +1650,13 @@ theorem continuous_sigma {f : Sigma σ → X} (hf : ∀ i, Continuous fun a => f spaces) is inducing iff its restriction to each component is inducing and each the image of each component under `f` can be separated from the images of all other components by an open set. -/ theorem inducing_sigma {f : Sigma σ → X} : - Inducing f ↔ (∀ i, Inducing (f ∘ Sigma.mk i)) ∧ + IsInducing f ↔ (∀ i, IsInducing (f ∘ Sigma.mk i)) ∧ (∀ i, ∃ U, IsOpen U ∧ ∀ x, f x ∈ U ↔ x.1 = i) := by - refine ⟨fun h ↦ ⟨fun i ↦ h.comp embedding_sigmaMk.1, fun i ↦ ?_⟩, ?_⟩ + refine ⟨fun h ↦ ⟨fun i ↦ h.comp IsEmbedding.sigmaMk.1, fun i ↦ ?_⟩, ?_⟩ · rcases h.isOpen_iff.1 (isOpen_range_sigmaMk (i := i)) with ⟨U, hUo, hU⟩ refine ⟨U, hUo, ?_⟩ simpa [Set.ext_iff] using hU - · refine fun ⟨h₁, h₂⟩ ↦ inducing_iff_nhds.2 fun ⟨i, x⟩ ↦ ?_ + · refine fun ⟨h₁, h₂⟩ ↦ isInducing_iff_nhds.2 fun ⟨i, x⟩ ↦ ?_ rw [Sigma.nhds_mk, (h₁ i).nhds_eq_comap, comp_apply, ← comap_comap, map_comap_of_mem] rcases h₂ i with ⟨U, hUo, hU⟩ filter_upwards [preimage_mem_comap <| hUo.mem_nhds <| (hU _).2 rfl] with y hy @@ -1582,7 +1665,8 @@ theorem inducing_sigma {f : Sigma σ → X} : @[simp 1100] theorem continuous_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} : Continuous (Sigma.map f₁ f₂) ↔ ∀ i, Continuous (f₂ i) := - continuous_sigma_iff.trans <| by simp only [Sigma.map, embedding_sigmaMk.continuous_iff, comp_def] + continuous_sigma_iff.trans <| by + simp only [Sigma.map, IsEmbedding.sigmaMk.continuous_iff, comp_def] @[continuity, fun_prop] theorem Continuous.sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (hf : ∀ i, Continuous (f₂ i)) : @@ -1595,22 +1679,31 @@ theorem isOpenMap_sigma {f : Sigma σ → X} : IsOpenMap f ↔ ∀ i, IsOpenMap theorem isOpenMap_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} : IsOpenMap (Sigma.map f₁ f₂) ↔ ∀ i, IsOpenMap (f₂ i) := isOpenMap_sigma.trans <| - forall_congr' fun i => (@openEmbedding_sigmaMk _ _ _ (f₁ i)).isOpenMap_iff.symm + forall_congr' fun i => (@isOpenEmbedding_sigmaMk _ _ _ (f₁ i)).isOpenMap_iff.symm + +lemma isInducing_sigmaMap {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} + (h₁ : Injective f₁) : IsInducing (Sigma.map f₁ f₂) ↔ ∀ i, IsInducing (f₂ i) := by + simp only [isInducing_iff_nhds, Sigma.forall, Sigma.nhds_mk, Sigma.map_mk, + ← map_sigma_mk_comap h₁, map_inj sigma_mk_injective] -theorem inducing_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (h₁ : Injective f₁) : - Inducing (Sigma.map f₁ f₂) ↔ ∀ i, Inducing (f₂ i) := by - simp only [inducing_iff_nhds, Sigma.forall, Sigma.nhds_mk, Sigma.map_mk, ← map_sigma_mk_comap h₁, - map_inj sigma_mk_injective] +@[deprecated (since := "2024-10-28")] alias inducing_sigma_map := isInducing_sigmaMap -theorem embedding_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (h : Injective f₁) : - Embedding (Sigma.map f₁ f₂) ↔ ∀ i, Embedding (f₂ i) := by - simp only [embedding_iff, Injective.sigma_map, inducing_sigma_map h, forall_and, h.sigma_map_iff] +lemma isEmbedding_sigmaMap {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} + (h : Injective f₁) : IsEmbedding (Sigma.map f₁ f₂) ↔ ∀ i, IsEmbedding (f₂ i) := by + simp only [isEmbedding_iff, Injective.sigma_map, isInducing_sigmaMap h, forall_and, + h.sigma_map_iff] -theorem openEmbedding_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (h : Injective f₁) : - OpenEmbedding (Sigma.map f₁ f₂) ↔ ∀ i, OpenEmbedding (f₂ i) := by - simp only [openEmbedding_iff_embedding_open, isOpenMap_sigma_map, embedding_sigma_map h, +@[deprecated (since := "2024-10-26")] +alias embedding_sigma_map := isEmbedding_sigmaMap + +theorem isOpenEmbedding_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (h : Injective f₁) : + IsOpenEmbedding (Sigma.map f₁ f₂) ↔ ∀ i, IsOpenEmbedding (f₂ i) := by + simp only [isOpenEmbedding_iff_isEmbedding_isOpenMap, isOpenMap_sigma_map, isEmbedding_sigmaMap h, forall_and] +@[deprecated (since := "2024-10-18")] +alias openEmbedding_sigma_map := isOpenEmbedding_sigma_map + end Sigma section ULift @@ -1631,15 +1724,21 @@ theorem continuous_uLift_down [TopologicalSpace X] : Continuous (ULift.down : UL theorem continuous_uLift_up [TopologicalSpace X] : Continuous (ULift.up : X → ULift.{v, u} X) := continuous_induced_rng.2 continuous_id -theorem embedding_uLift_down [TopologicalSpace X] : Embedding (ULift.down : ULift.{v, u} X → X) := - ⟨⟨rfl⟩, ULift.down_injective⟩ +lemma IsEmbedding.uliftDown [TopologicalSpace X] : + IsEmbedding (ULift.down : ULift.{v, u} X → X) := ⟨⟨rfl⟩, ULift.down_injective⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_uLift_down := IsEmbedding.uliftDown + +theorem ULift.isClosedEmbedding_down [TopologicalSpace X] : + IsClosedEmbedding (ULift.down : ULift.{v, u} X → X) := + ⟨.uliftDown, by simp only [ULift.down_surjective.range_eq, isClosed_univ]⟩ -theorem ULift.closedEmbedding_down [TopologicalSpace X] : - ClosedEmbedding (ULift.down : ULift.{v, u} X → X) := - ⟨embedding_uLift_down, by simp only [ULift.down_surjective.range_eq, isClosed_univ]⟩ +@[deprecated (since := "2024-10-20")] +alias ULift.closedEmbedding_down := ULift.isClosedEmbedding_down instance [TopologicalSpace X] [DiscreteTopology X] : DiscreteTopology (ULift X) := - embedding_uLift_down.discreteTopology + IsEmbedding.uliftDown.discreteTopology end ULift @@ -1683,4 +1782,4 @@ theorem Filter.Eventually.prod_nhdsSet {p : X × Y → Prop} {px : X → Prop} { end NhdsSet -set_option linter.style.longFile 1700 +set_option linter.style.longFile 1900 diff --git a/Mathlib/Topology/ContinuousMap/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean index 4e62f17e049be..c8e869fee7be1 100644 --- a/Mathlib/Topology/ContinuousMap/Algebra.lean +++ b/Mathlib/Topology/ContinuousMap/Algebra.lean @@ -13,7 +13,6 @@ import Mathlib.Topology.Algebra.Module.Basic import Mathlib.Topology.Algebra.InfiniteSum.Basic import Mathlib.Topology.Algebra.Ring.Basic import Mathlib.Topology.Algebra.Star -import Mathlib.Topology.Algebra.UniformGroup import Mathlib.Topology.ContinuousMap.Ordered import Mathlib.Topology.UniformSpace.CompactConvergence @@ -372,25 +371,27 @@ instance [CommGroup β] [TopologicalGroup β] : TopologicalGroup C(α, β) where uniformContinuous_inv.comp_tendstoUniformlyOn (tendsto_iff_forall_compact_tendstoUniformlyOn.mp Filter.tendsto_id K hK) --- TODO: rewrite the next three lemmas for products and deduce sum case via `to_additive`, once --- definition of `tprod` is in place -/-- If `α` is locally compact, and an infinite sum of functions in `C(α, β)` -converges to `g` (for the compact-open topology), then the pointwise sum converges to `g x` for -all `x ∈ α`. -/ -theorem hasSum_apply {γ : Type*} [AddCommMonoid β] [ContinuousAdd β] - {f : γ → C(α, β)} {g : C(α, β)} (hf : HasSum f g) (x : α) : - HasSum (fun i : γ => f i x) (g x) := by - let ev : C(α, β) →+ β := (Pi.evalAddMonoidHom _ x).comp coeFnAddMonoidHom - exact hf.map ev (ContinuousMap.continuous_eval_const x) - -theorem summable_apply [AddCommMonoid β] [ContinuousAdd β] {γ : Type*} {f : γ → C(α, β)} - (hf : Summable f) (x : α) : Summable fun i : γ => f i x := - (hasSum_apply hf.hasSum x).summable - -theorem tsum_apply [T2Space β] [AddCommMonoid β] [ContinuousAdd β] {γ : Type*} {f : γ → C(α, β)} - (hf : Summable f) (x : α) : - ∑' i : γ, f i x = (∑' i : γ, f i) x := - (hasSum_apply hf.hasSum x).tsum_eq +/-- If an infinite product of functions in `C(α, β)` converges to `g` +(for the compact-open topology), then the pointwise product converges to `g x` for all `x ∈ α`. -/ +@[to_additive + "If an infinite sum of functions in `C(α, β)` converges to `g` (for the compact-open topology), +then the pointwise sum converges to `g x` for all `x ∈ α`."] +theorem hasProd_apply {γ : Type*} [CommMonoid β] [ContinuousMul β] + {f : γ → C(α, β)} {g : C(α, β)} (hf : HasProd f g) (x : α) : + HasProd (fun i : γ => f i x) (g x) := by + let ev : C(α, β) →* β := (Pi.evalMonoidHom _ x).comp coeFnMonoidHom + exact hf.map ev (continuous_eval_const x) + +@[to_additive] +theorem multipliable_apply [CommMonoid β] [ContinuousMul β] {γ : Type*} {f : γ → C(α, β)} + (hf : Multipliable f) (x : α) : Multipliable fun i : γ => f i x := + (hasProd_apply hf.hasProd x).multipliable + +@[to_additive] +theorem tprod_apply [T2Space β] [CommMonoid β] [ContinuousMul β] {γ : Type*} {f : γ → C(α, β)} + (hf : Multipliable f) (x : α) : + ∏' i : γ, f i x = (∏' i : γ, f i) x := + (hasProd_apply hf.hasProd x).tprod_eq end ContinuousMap @@ -579,6 +580,18 @@ instance [SMul R M] [ContinuousConstSMul R M] [SMul R₁ M] [ContinuousConstSMul instance [SMul R M] [SMul Rᵐᵒᵖ M] [ContinuousConstSMul R M] [IsCentralScalar R M] : IsCentralScalar R C(α, M) where op_smul_eq_smul _ _ := ext fun _ => op_smul_eq_smul _ _ +instance [SMul R M] [ContinuousConstSMul R M] [Mul M] [ContinuousMul M] [IsScalarTower R M M] : + IsScalarTower R C(α, M) C(α, M) where + smul_assoc _ _ _ := ext fun _ => smul_mul_assoc .. + +instance [SMul R M] [ContinuousConstSMul R M] [Mul M] [ContinuousMul M] [SMulCommClass R M M] : + SMulCommClass R C(α, M) C(α, M) where + smul_comm _ _ _ := ext fun _ => (mul_smul_comm ..).symm + +instance [SMul R M] [ContinuousConstSMul R M] [Mul M] [ContinuousMul M] [SMulCommClass M R M] : + SMulCommClass C(α, M) R C(α, M) where + smul_comm _ _ _ := ext fun _ => smul_comm (_ : M) .. + instance [Monoid R] [MulAction R M] [ContinuousConstSMul R M] : MulAction R C(α, M) := Function.Injective.mulAction _ coe_injective coe_smul @@ -683,6 +696,10 @@ def ContinuousMap.compRightAlgHom {α β : Type*} [TopologicalSpace α] [Topolog map_mul' _ _ := ext fun _ ↦ rfl commutes' _ := ext fun _ ↦ rfl +theorem ContinuousMap.compRightAlgHom_continuous {α β : Type*} [TopologicalSpace α] + [TopologicalSpace β] (f : C(α, β)) : Continuous (compRightAlgHom R A f) := + continuous_precomp f + variable {A} /-- Coercion to a function as an `AlgHom`. -/ @@ -818,15 +835,13 @@ variable {β : Type*} [TopologicalSpace β] /-! `C(α, β)`is a lattice ordered group -/ @[to_additive] -instance instCovariantClass_mul_le_left [PartialOrder β] [Mul β] [ContinuousMul β] - [CovariantClass β β (· * ·) (· ≤ ·)] : - CovariantClass C(α, β) C(α, β) (· * ·) (· ≤ ·) := +instance instMulLeftMono [PartialOrder β] [Mul β] [ContinuousMul β] [MulLeftMono β] : + MulLeftMono C(α, β) := ⟨fun _ _ _ hg₁₂ x => mul_le_mul_left' (hg₁₂ x) _⟩ @[to_additive] -instance instCovariantClass_mul_le_right [PartialOrder β] [Mul β] [ContinuousMul β] - [CovariantClass β β (Function.swap (· * ·)) (· ≤ ·)] : - CovariantClass C(α, β) C(α, β) (Function.swap (· * ·)) (· ≤ ·) := +instance instMulRightMono [PartialOrder β] [Mul β] [ContinuousMul β] [MulRightMono β] : + MulRightMono C(α, β) := ⟨fun _ _ _ hg₁₂ x => mul_le_mul_right' (hg₁₂ x) _⟩ variable [Group β] [TopologicalGroup β] [Lattice β] [TopologicalLattice β] @@ -1008,7 +1023,7 @@ variable [ContinuousStar A] [Algebra 𝕜 A] actually a homeomorphism. -/ @[simps] def compStarAlgEquiv' (f : X ≃ₜ Y) : C(Y, A) ≃⋆ₐ[𝕜] C(X, A) := - { f.toContinuousMap.compStarAlgHom' 𝕜 A with + { (f : C(X, Y)).compStarAlgHom' 𝕜 A with toFun := (f : C(X, Y)).compStarAlgHom' 𝕜 A invFun := (f.symm : C(Y, X)).compStarAlgHom' 𝕜 A left_inv := fun g => by @@ -1017,7 +1032,7 @@ def compStarAlgEquiv' (f : X ≃ₜ Y) : C(Y, A) ≃⋆ₐ[𝕜] C(X, A) := right_inv := fun g => by simp only [ContinuousMap.compStarAlgHom'_apply, ContinuousMap.comp_assoc, symm_comp_toContinuousMap, ContinuousMap.comp_id] - map_smul' := fun k a => map_smul (f.toContinuousMap.compStarAlgHom' 𝕜 A) k a } + map_smul' := fun k a => map_smul ((f : C(X, Y)).compStarAlgHom' 𝕜 A) k a } end Homeomorph diff --git a/Mathlib/Topology/ContinuousMap/Basic.lean b/Mathlib/Topology/ContinuousMap/Basic.lean index c5f501967a7b2..852cf38dfab8f 100644 --- a/Mathlib/Topology/ContinuousMap/Basic.lean +++ b/Mathlib/Topology/ContinuousMap/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Nicolò Cavalleri -/ import Mathlib.Data.Set.UnionLift +import Mathlib.Topology.ContinuousMap.Defs import Mathlib.Topology.Homeomorph /-! @@ -19,37 +20,6 @@ be satisfied by itself and all stricter types. open Function open scoped Topology -/-- The type of continuous maps from `α` to `β`. - -When possible, instead of parametrizing results over `(f : C(α, β))`, -you should parametrize over `{F : Type*} [ContinuousMapClass F α β] (f : F)`. - -When you extend this structure, make sure to extend `ContinuousMapClass`. -/ -structure ContinuousMap (α β : Type*) [TopologicalSpace α] [TopologicalSpace β] where - /-- The function `α → β` -/ - protected toFun : α → β - /-- Proposition that `toFun` is continuous -/ - protected continuous_toFun : Continuous toFun := by continuity - -/-- The type of continuous maps from `α` to `β`. -/ -notation "C(" α ", " β ")" => ContinuousMap α β - -section - -/-- `ContinuousMapClass F α β` states that `F` is a type of continuous maps. - -You should extend this class when you extend `ContinuousMap`. -/ -class ContinuousMapClass (F : Type*) (α β : outParam Type*) - [TopologicalSpace α] [TopologicalSpace β] [FunLike F α β] : Prop where - /-- Continuity -/ - map_continuous (f : F) : Continuous f - -end - -export ContinuousMapClass (map_continuous) - -attribute [continuity, fun_prop] map_continuous - section ContinuousMapClass variable {F α β : Type*} [TopologicalSpace α] [TopologicalSpace β] [FunLike F α β] @@ -61,11 +31,6 @@ theorem map_continuousAt (f : F) (a : α) : ContinuousAt f a := theorem map_continuousWithinAt (f : F) (s : Set α) (a : α) : ContinuousWithinAt f s a := (map_continuous f).continuousWithinAt -/-- Coerce a bundled morphism with a `ContinuousMapClass` instance to a `ContinuousMap`. -/ -@[coe] def toContinuousMap (f : F) : C(α, β) := ⟨f, map_continuous f⟩ - -instance : CoeTC F C(α, β) := ⟨toContinuousMap⟩ - end ContinuousMapClass /-! ### Continuous maps -/ @@ -76,75 +41,11 @@ namespace ContinuousMap variable {α β γ δ : Type*} [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] [TopologicalSpace δ] -instance funLike : FunLike C(α, β) α β where - coe := ContinuousMap.toFun - coe_injective' f g h := by cases f; cases g; congr - -instance toContinuousMapClass : ContinuousMapClass C(α, β) α β where - map_continuous := ContinuousMap.continuous_toFun - -@[simp] -theorem toFun_eq_coe {f : C(α, β)} : f.toFun = (f : α → β) := - rfl - -instance : CanLift (α → β) C(α, β) DFunLike.coe Continuous := ⟨fun f hf ↦ ⟨⟨f, hf⟩, rfl⟩⟩ - -/-- See note [custom simps projection]. -/ -def Simps.apply (f : C(α, β)) : α → β := f - --- this must come after the coe_to_fun definition -initialize_simps_projections ContinuousMap (toFun → apply) - -@[simp] -- Porting note: removed `norm_cast` attribute -protected theorem coe_coe {F : Type*} [FunLike F α β] [ContinuousMapClass F α β] (f : F) : - ⇑(f : C(α, β)) = f := - rfl - -@[ext] -theorem ext {f g : C(α, β)} (h : ∀ a, f a = g a) : f = g := - DFunLike.ext _ _ h - -/-- Copy of a `ContinuousMap` with a new `toFun` equal to the old one. Useful to fix definitional -equalities. -/ -protected def copy (f : C(α, β)) (f' : α → β) (h : f' = f) : C(α, β) where - toFun := f' - continuous_toFun := h.symm ▸ f.continuous_toFun - -@[simp] -theorem coe_copy (f : C(α, β)) (f' : α → β) (h : f' = f) : ⇑(f.copy f' h) = f' := - rfl - -theorem copy_eq (f : C(α, β)) (f' : α → β) (h : f' = f) : f.copy f' h = f := - DFunLike.ext' h - variable {f g : C(α, β)} -/-- Deprecated. Use `map_continuous` instead. -/ -protected theorem continuous (f : C(α, β)) : Continuous f := - f.continuous_toFun - -@[continuity] -theorem continuous_set_coe (s : Set C(α, β)) (f : s) : Continuous (f : α → β) := - f.1.continuous - /-- Deprecated. Use `map_continuousAt` instead. -/ protected theorem continuousAt (f : C(α, β)) (x : α) : ContinuousAt f x := - f.continuous.continuousAt - -/-- Deprecated. Use `DFunLike.congr_fun` instead. -/ -protected theorem congr_fun {f g : C(α, β)} (H : f = g) (x : α) : f x = g x := - H ▸ rfl - -/-- Deprecated. Use `DFunLike.congr_arg` instead. -/ -protected theorem congr_arg (f : C(α, β)) {x y : α} (h : x = y) : f x = f y := - h ▸ rfl - -theorem coe_injective : @Function.Injective C(α, β) (α → β) (↑) := fun f g h => by - cases f; cases g; congr - -@[simp] -theorem coe_mk (f : α → β) (h : Continuous f) : ⇑(⟨f, h⟩ : C(α, β)) = f := - rfl + map_continuousAt f x theorem map_specializes (f : C(α, β)) {x y : α} (h : x ⤳ y) : f x ⤳ f y := h.map f.2 @@ -378,13 +279,14 @@ theorem restrict_apply_mk (f : C(α, β)) (s : Set α) (x : α) (hx : x ∈ s) : theorem injective_restrict [T2Space β] {s : Set α} (hs : Dense s) : Injective (restrict s : C(α, β) → C(s, β)) := fun f g h ↦ - DFunLike.ext' <| f.continuous.ext_on hs g.continuous <| Set.restrict_eq_restrict_iff.1 <| - congr_arg DFunLike.coe h + DFunLike.ext' <| (map_continuous f).ext_on hs (map_continuous g) <| + Set.restrict_eq_restrict_iff.1 <| congr_arg DFunLike.coe h /-- The restriction of a continuous map to the preimage of a set. -/ @[simps] def restrictPreimage (f : C(α, β)) (s : Set β) : C(f ⁻¹' s, s) := - ⟨s.restrictPreimage f, continuous_iff_continuousAt.mpr fun _ => f.2.continuousAt.restrictPreimage⟩ + ⟨s.restrictPreimage f, continuous_iff_continuousAt.mpr fun _ ↦ + (map_continuousAt f _).restrictPreimage⟩ end Restrict @@ -402,8 +304,8 @@ noncomputable def liftCover : C(α, β) := Set.iUnion_eq_univ_iff.2 fun x ↦ (hS x).imp fun _ ↦ mem_of_mem_nhds mk (Set.liftCover S (fun i ↦ φ i) hφ H) <| continuous_of_cover_nhds hS fun i ↦ by rw [continuousOn_iff_continuous_restrict] - simpa (config := { unfoldPartialApp := true }) only [Set.restrict, Set.liftCover_coe] using - (φ i).continuous + simpa (config := { unfoldPartialApp := true }) only [Set.restrict, Set.liftCover_coe] + using map_continuous (φ i) variable {S φ hφ hS} @@ -461,19 +363,19 @@ variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalS def Function.RightInverse.homeomorph {f' : C(Y, X)} (hf : Function.RightInverse f' f) : Quotient (Setoid.ker f) ≃ₜ Y where toEquiv := Setoid.quotientKerEquivOfRightInverse _ _ hf - continuous_toFun := quotientMap_quot_mk.continuous_iff.mpr f.continuous - continuous_invFun := continuous_quotient_mk'.comp f'.continuous + continuous_toFun := isQuotientMap_quot_mk.continuous_iff.mpr (map_continuous f) + continuous_invFun := continuous_quotient_mk'.comp (map_continuous f') -namespace QuotientMap +namespace IsQuotientMap /-- The homeomorphism from the quotient of a quotient map to its codomain. This is `Setoid.quotientKerEquivOfSurjective` as a homeomorphism. -/ @[simps!] -noncomputable def homeomorph (hf : QuotientMap f) : Quotient (Setoid.ker f) ≃ₜ Y where +noncomputable def homeomorph (hf : IsQuotientMap f) : Quotient (Setoid.ker f) ≃ₜ Y where toEquiv := Setoid.quotientKerEquivOfSurjective _ hf.surjective - continuous_toFun := quotientMap_quot_mk.continuous_iff.mpr hf.continuous + continuous_toFun := isQuotientMap_quot_mk.continuous_iff.mpr hf.continuous continuous_invFun := by rw [hf.continuous_iff] convert continuous_quotient_mk' @@ -482,7 +384,7 @@ noncomputable def homeomorph (hf : QuotientMap f) : Quotient (Setoid.ker f) ≃ (Setoid.quotientKerEquivOfSurjective f hf.surjective).symm_apply_eq] rfl -variable (hf : QuotientMap f) (g : C(X, Z)) (h : Function.FactorsThrough g f) +variable (hf : IsQuotientMap f) (g : C(X, Z)) (h : Function.FactorsThrough g f) /-- Descend a continuous map, which is constant on the fibres, along a quotient map. -/ @[simps] @@ -492,7 +394,7 @@ noncomputable def lift : C(Y, Z) where continuous_toFun := Continuous.comp (continuous_quot_lift _ g.2) (Homeomorph.continuous _) /-- -The obvious triangle induced by `QuotientMap.lift` commutes: +The obvious triangle induced by `IsQuotientMap.lift` commutes: ``` g X --→ Z @@ -507,7 +409,7 @@ theorem lift_comp : (hf.lift g h).comp f = g := by ext simpa using h (Function.rightInverse_surjInv _ _) -/-- `QuotientMap.lift` as an equivalence. -/ +/-- `IsQuotientMap.lift` as an equivalence. -/ @[simps] noncomputable def liftEquiv : { g : C(X, Z) // Function.FactorsThrough g f} ≃ C(Y, Z) where toFun g := hf.lift g g.prop @@ -518,7 +420,7 @@ noncomputable def liftEquiv : { g : C(X, Z) // Function.FactorsThrough g f} ≃ ext a simpa using congrArg g (Function.rightInverse_surjInv hf.surjective a) -end QuotientMap +end IsQuotientMap end Lift @@ -527,19 +429,15 @@ namespace Homeomorph variable {α β γ : Type*} [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] variable (f : α ≃ₜ β) (g : β ≃ₜ γ) +instance instContinuousMapClass : ContinuousMapClass (α ≃ₜ β) α β where + map_continuous f := f.continuous_toFun + /-- The forward direction of a homeomorphism, as a bundled continuous map. -/ -@[simps] -def toContinuousMap (e : α ≃ₜ β) : C(α, β) := +@[simps, deprecated _root_.toContinuousMap (since := "2024-10-12")] +protected def toContinuousMap (e : α ≃ₜ β) : C(α, β) := ⟨e, e.continuous_toFun⟩ -/-- `Homeomorph.toContinuousMap` as a coercion. -/ -instance : Coe (α ≃ₜ β) C(α, β) := - ⟨Homeomorph.toContinuousMap⟩ - --- Porting note: Syntactic tautology -/- theorem toContinuousMap_as_coe : f.toContinuousMap = f := - rfl --/ +attribute [deprecated ContinuousMap.coe_apply (since := "2024-10-12")] toContinuousMap_apply @[simp] theorem coe_refl : (Homeomorph.refl α : C(α, α)) = ContinuousMap.id α := diff --git a/Mathlib/Topology/ContinuousMap/Bounded.lean b/Mathlib/Topology/ContinuousMap/Bounded.lean index a1fa188b5cc16..037cf9103630a 100644 --- a/Mathlib/Topology/ContinuousMap/Bounded.lean +++ b/Mathlib/Topology/ContinuousMap/Bounded.lean @@ -187,8 +187,8 @@ theorem dist_lt_iff_of_nonempty_compact [Nonempty α] [CompactSpace α] : instance instPseudoMetricSpace : PseudoMetricSpace (α →ᵇ β) where dist_self f := le_antisymm ((dist_le le_rfl).2 fun x => by simp) dist_nonneg' dist_comm f g := by simp [dist_eq, dist_comm] - dist_triangle f g h := (dist_le (add_nonneg dist_nonneg' dist_nonneg')).2 - fun x => le_trans (dist_triangle _ _ _) (add_le_add (dist_coe_le_dist _) (dist_coe_le_dist _)) + dist_triangle _ _ _ := (dist_le (add_nonneg dist_nonneg' dist_nonneg')).2 + fun _ => le_trans (dist_triangle _ _ _) (add_le_add (dist_coe_le_dist _) (dist_coe_le_dist _)) -- Porting note (#10888): added proof for `edist_dist` edist_dist x y := by dsimp; congr; simp [dist_nonneg'] @@ -239,16 +239,21 @@ theorem tendsto_iff_tendstoUniformly {ι : Type*} {F : ι → α →ᵇ β} {f : (half_lt_self ε_pos)) /-- The topology on `α →ᵇ β` is exactly the topology induced by the natural map to `α →ᵤ β`. -/ -theorem inducing_coeFn : Inducing (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) → α →ᵤ β) := by - rw [inducing_iff_nhds] +theorem isInducing_coeFn : IsInducing (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) → α →ᵤ β) := by + rw [isInducing_iff_nhds] refine fun f => eq_of_forall_le_iff fun l => ?_ rw [← tendsto_iff_comap, ← tendsto_id', tendsto_iff_tendstoUniformly, UniformFun.tendsto_iff_tendstoUniformly] simp [comp_def] --- TODO: upgrade to a `IsUniformEmbedding` -theorem embedding_coeFn : Embedding (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) → α →ᵤ β) := - ⟨inducing_coeFn, fun _ _ h => ext fun x => congr_fun h x⟩ +@[deprecated (since := "2024-10-28")] alias inducing_coeFn := isInducing_coeFn + +-- TODO: upgrade to `IsUniformEmbedding` +theorem isEmbedding_coeFn : IsEmbedding (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) → α →ᵤ β) := + ⟨isInducing_coeFn, fun _ _ h => ext fun x => congr_fun h x⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_coeFn := isEmbedding_coeFn variable (α) @@ -441,6 +446,13 @@ theorem isometry_extend (f : α ↪ δ) (h : δ →ᵇ β) : Isometry fun g : α end Extend +/-- The indicator function of a clopen set, as a bounded continuous function. -/ +@[simps] +noncomputable def indicator (s : Set α) (hs : IsClopen s) : BoundedContinuousFunction α ℝ where + toFun := s.indicator 1 + continuous_toFun := continuous_indicator (by simp [hs]) <| continuous_const.continuousOn + map_bounded' := ⟨1, fun x y ↦ by by_cases hx : x ∈ s <;> by_cases hy : y ∈ s <;> simp [hx, hy]⟩ + end Basics section ArzelaAscoli @@ -524,7 +536,7 @@ theorem arzela_ascoli₂ (s : Set β) (hs : IsCompact s) (A : Set (α →ᵇ β) fun f hf => ?_ · haveI : CompactSpace s := isCompact_iff_compactSpace.1 hs refine arzela_ascoli₁ _ (continuous_iff_isClosed.1 (continuous_comp M) _ closed) ?_ - rw [isUniformEmbedding_subtype_val.toUniformInducing.equicontinuous_iff] + rw [isUniformEmbedding_subtype_val.isUniformInducing.equicontinuous_iff] exact H.comp (A.restrictPreimage F) · let g := codRestrict s f fun x => in_s f x hf rw [show f = F g by ext; rfl] at hf ⊢ @@ -1013,6 +1025,16 @@ theorem coe_smul (c : 𝕜) (f : α →ᵇ β) : ⇑(c • f) = fun x => c • f theorem smul_apply (c : 𝕜) (f : α →ᵇ β) (x : α) : (c • f) x = c • f x := rfl +instance instIsScalarTower {𝕜' : Type*} [PseudoMetricSpace 𝕜'] [Zero 𝕜'] [SMul 𝕜' β] + [BoundedSMul 𝕜' β] [SMul 𝕜' 𝕜] [IsScalarTower 𝕜' 𝕜 β] : + IsScalarTower 𝕜' 𝕜 (α →ᵇ β) where + smul_assoc _ _ _ := ext fun _ ↦ smul_assoc .. + +instance instSMulCommClass {𝕜' : Type*} [PseudoMetricSpace 𝕜'] [Zero 𝕜'] [SMul 𝕜' β] + [BoundedSMul 𝕜' β] [SMulCommClass 𝕜' 𝕜 β] : + SMulCommClass 𝕜' 𝕜 (α →ᵇ β) where + smul_comm _ _ _ := ext fun _ ↦ smul_comm .. + instance instIsCentralScalar [SMul 𝕜ᵐᵒᵖ β] [IsCentralScalar 𝕜 β] : IsCentralScalar 𝕜 (α →ᵇ β) where op_smul_eq_smul _ _ := ext fun _ => op_smul_eq_smul _ _ @@ -1065,8 +1087,8 @@ variable (𝕜) /-- The evaluation at a point, as a continuous linear map from `α →ᵇ β` to `β`. -/ def evalCLM (x : α) : (α →ᵇ β) →L[𝕜] β where toFun f := f x - map_add' f g := add_apply _ _ - map_smul' c f := smul_apply _ _ _ + map_add' _ _ := add_apply _ _ + map_smul' _ _ := smul_apply _ _ _ @[simp] theorem evalCLM_apply (x : α) (f : α →ᵇ β) : evalCLM 𝕜 x f = f x := rfl @@ -1162,10 +1184,18 @@ instance instNonUnitalSeminormedRing : NonUnitalSeminormedRing (α →ᵇ R) := end Seminormed +instance instNonUnitalSeminormedCommRing [NonUnitalSeminormedCommRing R] : + NonUnitalSeminormedCommRing (α →ᵇ R) where + mul_comm _ _ := ext fun _ ↦ mul_comm .. + instance instNonUnitalNormedRing [NonUnitalNormedRing R] : NonUnitalNormedRing (α →ᵇ R) where __ := instNonUnitalSeminormedRing __ := instNormedAddCommGroup +instance instNonUnitalNormedCommRing [NonUnitalNormedCommRing R] : + NonUnitalNormedCommRing (α →ᵇ R) where + mul_comm := mul_comm + end NonUnital section Seminormed @@ -1246,6 +1276,23 @@ instance instNormedCommRing [NormedCommRing R] : NormedCommRing (α →ᵇ R) wh end NormedCommRing +section NonUnitalAlgebra + +-- these hypotheses could be generalized if we generalize `BoundedSMul` to `Bornology`. +variable {𝕜 : Type*} [PseudoMetricSpace 𝕜] [TopologicalSpace α] [NonUnitalSeminormedRing β] +variable [Zero 𝕜] [SMul 𝕜 β] [BoundedSMul 𝕜 β] + +instance [IsScalarTower 𝕜 β β] : IsScalarTower 𝕜 (α →ᵇ β) (α →ᵇ β) where + smul_assoc _ _ _ := ext fun _ ↦ smul_mul_assoc .. + +instance [SMulCommClass 𝕜 β β] : SMulCommClass 𝕜 (α →ᵇ β) (α →ᵇ β) where + smul_comm _ _ _ := ext fun _ ↦ (mul_smul_comm ..).symm + +instance [SMulCommClass 𝕜 β β] : SMulCommClass (α →ᵇ β) 𝕜 (α →ᵇ β) where + smul_comm _ _ _ := ext fun _ ↦ mul_smul_comm .. + +end NonUnitalAlgebra + section NormedAlgebra /-! diff --git a/Mathlib/Topology/ContinuousMap/Compact.lean b/Mathlib/Topology/ContinuousMap/Compact.lean index f68ff46c4011d..9400fa18c4860 100644 --- a/Mathlib/Topology/ContinuousMap/Compact.lean +++ b/Mathlib/Topology/ContinuousMap/Compact.lean @@ -29,8 +29,8 @@ open NNReal BoundedContinuousFunction Set Metric namespace ContinuousMap -variable {α β E : Type*} [TopologicalSpace α] [CompactSpace α] [MetricSpace β] - [NormedAddCommGroup E] +variable {α β E : Type*} +variable [TopologicalSpace α] [CompactSpace α] [PseudoMetricSpace β] [SeminormedAddCommGroup E] section @@ -47,8 +47,8 @@ def equivBoundedOfCompact : C(α, β) ≃ (α →ᵇ β) := ext rfl⟩ -theorem uniformInducing_equivBoundedOfCompact : UniformInducing (equivBoundedOfCompact α β) := - UniformInducing.mk' +theorem isUniformInducing_equivBoundedOfCompact : IsUniformInducing (equivBoundedOfCompact α β) := + IsUniformInducing.mk' (by simp only [hasBasis_compactConvergenceUniformity.mem_iff, uniformity_basis_dist_le.mem_iff] exact fun s => @@ -59,8 +59,12 @@ theorem uniformInducing_equivBoundedOfCompact : UniformInducing (equivBoundedOfC ⟨⟨Set.univ, { p | dist p.1 p.2 ≤ ε }⟩, ⟨isCompact_univ, ⟨ε, hε, fun _ h => h⟩⟩, fun ⟨f, g⟩ h => hs _ _ (ht ((dist_le hε.le).mpr fun x => h x (mem_univ x)))⟩⟩) +@[deprecated (since := "2024-10-05")] +alias uniformInducing_equivBoundedOfCompact := isUniformInducing_equivBoundedOfCompact + theorem isUniformEmbedding_equivBoundedOfCompact : IsUniformEmbedding (equivBoundedOfCompact α β) := - { uniformInducing_equivBoundedOfCompact α β with inj := (equivBoundedOfCompact α β).injective } + { isUniformInducing_equivBoundedOfCompact α β with + inj := (equivBoundedOfCompact α β).injective } @[deprecated (since := "2024-10-01")] alias uniformEmbedding_equivBoundedOfCompact := isUniformEmbedding_equivBoundedOfCompact @@ -85,9 +89,14 @@ theorem addEquivBoundedOfCompact_apply [AddMonoid β] [LipschitzAdd β] : ⇑(addEquivBoundedOfCompact α β) = mkOfCompact := rfl -instance metricSpace : MetricSpace C(α, β) := +instance instPseudoMetricSpace : PseudoMetricSpace C(α, β) := + (isUniformEmbedding_equivBoundedOfCompact α β).comapPseudoMetricSpace _ + +instance instMetricSpace {β : Type*} [MetricSpace β] : + MetricSpace C(α, β) := (isUniformEmbedding_equivBoundedOfCompact α β).comapMetricSpace _ + /-- When `α` is compact, and `β` is a metric space, the bounded continuous maps `α →ᵇ β` are isometric to `C(α, β)`. -/ @@ -136,6 +145,13 @@ theorem dist_lt_iff (C0 : (0 : ℝ) < C) : dist f g < C ↔ ∀ x : α, dist (f rw [← dist_mkOfCompact, dist_lt_iff_of_compact C0] simp only [mkOfCompact_apply] +instance {R} [Zero R] [Zero β] [PseudoMetricSpace R] [SMul R β] [BoundedSMul R β] : + BoundedSMul R C(α, β) where + dist_smul_pair' r f g := by + simpa only [← dist_mkOfCompact] using dist_smul_pair r (mkOfCompact f) (mkOfCompact g) + dist_pair_smul' r₁ r₂ f := by + simpa only [← dist_mkOfCompact] using dist_pair_smul r₁ r₂ (mkOfCompact f) + end -- TODO at some point we will need lemmas characterising this norm! @@ -153,13 +169,17 @@ theorem _root_.BoundedContinuousFunction.norm_toContinuousMap_eq (f : α →ᵇ open BoundedContinuousFunction -instance : NormedAddCommGroup C(α, E) := - { ContinuousMap.metricSpace _ _, - ContinuousMap.instAddCommGroupContinuousMap with - dist_eq := fun x y => by - rw [← norm_mkOfCompact, ← dist_mkOfCompact, dist_eq_norm, mkOfCompact_sub] - dist := dist - norm := norm } +instance : SeminormedAddCommGroup C(α, E) where + __ := ContinuousMap.instPseudoMetricSpace _ _ + __ := ContinuousMap.instAddCommGroupContinuousMap + dist_eq x y := by + rw [← norm_mkOfCompact, ← dist_mkOfCompact, dist_eq_norm, mkOfCompact_sub] + dist := dist + norm := norm + +instance {E : Type*} [NormedAddCommGroup E] : NormedAddCommGroup C(α, E) where + __ : SeminormedAddCommGroup C(α, E) := inferInstance + __ : MetricSpace C(α, E) := inferInstance instance [Nonempty α] [One E] [NormOneClass E] : NormOneClass C(α, E) where norm_one := by simp only [← norm_mkOfCompact, mkOfCompact_one, norm_one] @@ -218,11 +238,40 @@ end section -variable {R : Type*} [NormedRing R] +variable {R : Type*} + +instance [NonUnitalSeminormedRing R] : NonUnitalSeminormedRing C(α, R) where + __ : SeminormedAddCommGroup C(α, R) := inferInstance + __ : NonUnitalRing C(α, R) := inferInstance + norm_mul f g := norm_mul_le (mkOfCompact f) (mkOfCompact g) + +instance [NonUnitalSeminormedCommRing R] : NonUnitalSeminormedCommRing C(α, R) where + __ : NonUnitalSeminormedRing C(α, R) := inferInstance + __ : NonUnitalCommRing C(α, R) := inferInstance -instance : NormedRing C(α, R) := - { (inferInstance : NormedAddCommGroup C(α, R)), ContinuousMap.instRing with - norm_mul := fun f g => norm_mul_le (mkOfCompact f) (mkOfCompact g) } +instance [SeminormedRing R] : SeminormedRing C(α, R) where + __ : NonUnitalSeminormedRing C(α, R) := inferInstance + __ : Ring C(α, R) := inferInstance + +instance [SeminormedCommRing R] : SeminormedCommRing C(α, R) where + __ : SeminormedRing C(α, R) := inferInstance + __ : CommRing C(α, R) := inferInstance + +instance [NonUnitalNormedRing R] : NonUnitalNormedRing C(α, R) where + __ : NormedAddCommGroup C(α, R) := inferInstance + __ : NonUnitalSeminormedRing C(α, R) := inferInstance + +instance [NonUnitalNormedCommRing R] : NonUnitalNormedCommRing C(α, R) where + __ : NonUnitalNormedRing C(α, R) := inferInstance + __ : NonUnitalCommRing C(α, R) := inferInstance + +instance [NormedRing R] : NormedRing C(α, R) where + __ : NormedAddCommGroup C(α, R) := inferInstance + __ : SeminormedRing C(α, R) := inferInstance + +instance [NormedCommRing R] : NormedCommRing C(α, R) where + __ : NormedRing C(α, R) := inferInstance + __ : CommRing C(α, R) := inferInstance end @@ -231,7 +280,7 @@ section variable {𝕜 : Type*} [NormedField 𝕜] [NormedSpace 𝕜 E] instance normedSpace : NormedSpace 𝕜 C(α, E) where - norm_smul_le c f := (norm_smul_le c (mkOfCompact f) : _) + norm_smul_le := norm_smul_le section @@ -246,7 +295,7 @@ def linearIsometryBoundedOfCompact : C(α, E) ≃ₗᵢ[𝕜] α →ᵇ E := map_smul' := fun c f => by ext norm_cast - norm_map' := fun f => rfl } + norm_map' := fun _ => rfl } variable {α E} @@ -290,7 +339,7 @@ end section -variable {𝕜 : Type*} {γ : Type*} [NormedField 𝕜] [NormedRing γ] [NormedAlgebra 𝕜 γ] +variable {𝕜 : Type*} {γ : Type*} [NormedField 𝕜] [SeminormedRing γ] [NormedAlgebra 𝕜 γ] instance : NormedAlgebra 𝕜 C(α, γ) := { ContinuousMap.normedSpace, ContinuousMap.algebra with } @@ -304,7 +353,7 @@ namespace ContinuousMap section UniformContinuity variable {α β : Type*} -variable [MetricSpace α] [CompactSpace α] [MetricSpace β] +variable [PseudoMetricSpace α] [CompactSpace α] [PseudoMetricSpace β] /-! We now set up some declarations making it convenient to use uniform continuity. @@ -338,7 +387,7 @@ section CompLeft variable (X : Type*) {𝕜 β γ : Type*} [TopologicalSpace X] [CompactSpace X] [NontriviallyNormedField 𝕜] -variable [NormedAddCommGroup β] [NormedSpace 𝕜 β] [NormedAddCommGroup γ] [NormedSpace 𝕜 γ] +variable [SeminormedAddCommGroup β] [NormedSpace 𝕜 β] [SeminormedAddCommGroup γ] [NormedSpace 𝕜 γ] open ContinuousMap @@ -368,55 +417,6 @@ end CompLeft namespace ContinuousMap -/-! -We now setup variations on `compRight* f`, where `f : C(X, Y)` -(that is, precomposition by a continuous map), -as a morphism `C(Y, T) → C(X, T)`, respecting various types of structure. - -In particular: -* `compRightContinuousMap`, the bundled continuous map (for this we need `X Y` compact). -* `compRightHomeomorph`, when we precompose by a homeomorphism. -* `compRightAlgHom`, when `T = R` is a topological ring. --/ - - -section CompRight - -/-- Precomposition by a continuous map is itself a continuous map between spaces of continuous maps. --/ -def compRightContinuousMap {X Y : Type*} (T : Type*) [TopologicalSpace X] [CompactSpace X] - [TopologicalSpace Y] [CompactSpace Y] [MetricSpace T] (f : C(X, Y)) : C(C(Y, T), C(X, T)) where - toFun g := g.comp f - continuous_toFun := by - refine Metric.continuous_iff.mpr ?_ - intro g ε ε_pos - refine ⟨ε, ε_pos, fun g' h => ?_⟩ - rw [ContinuousMap.dist_lt_iff ε_pos] at h ⊢ - exact fun x => h (f x) - -@[simp] -theorem compRightContinuousMap_apply {X Y : Type*} (T : Type*) [TopologicalSpace X] - [CompactSpace X] [TopologicalSpace Y] [CompactSpace Y] [MetricSpace T] (f : C(X, Y)) - (g : C(Y, T)) : (compRightContinuousMap T f) g = g.comp f := - rfl - -/-- Precomposition by a homeomorphism is itself a homeomorphism between spaces of continuous maps. --/ -def compRightHomeomorph {X Y : Type*} (T : Type*) [TopologicalSpace X] [CompactSpace X] - [TopologicalSpace Y] [CompactSpace Y] [MetricSpace T] (f : X ≃ₜ Y) : C(Y, T) ≃ₜ C(X, T) where - toFun := compRightContinuousMap T f.toContinuousMap - invFun := compRightContinuousMap T f.symm.toContinuousMap - left_inv g := ext fun _ => congr_arg g (f.apply_symm_apply _) - right_inv g := ext fun _ => congr_arg g (f.symm_apply_apply _) - -theorem compRightAlgHom_continuous {X Y : Type*} (R A : Type*) [TopologicalSpace X] - [CompactSpace X] [TopologicalSpace Y] [CompactSpace Y] [CommSemiring R] [Semiring A] - [MetricSpace A] [TopologicalSemiring A] [Algebra R A] (f : C(X, Y)) : - Continuous (compRightAlgHom R A f) := - map_continuous (compRightContinuousMap A f) - -end CompRight - section LocalNormalConvergence /-! ### Local normal convergence @@ -425,7 +425,6 @@ A sum of continuous functions (on a locally compact space) is "locally normally sum of its sup-norms on any compact subset is summable. This implies convergence in the topology of `C(X, E)` (i.e. locally uniform convergence). -/ - open TopologicalSpace variable {X : Type*} [TopologicalSpace X] [LocallyCompactSpace X] @@ -460,7 +459,7 @@ Furthermore, if `α` is compact and `β` is a C⋆-ring, then `C(α, β)` is a C section NormedSpace variable {α : Type*} {β : Type*} -variable [TopologicalSpace α] [NormedAddCommGroup β] [StarAddMonoid β] [NormedStarGroup β] +variable [TopologicalSpace α] [SeminormedAddCommGroup β] [StarAddMonoid β] [NormedStarGroup β] theorem _root_.BoundedContinuousFunction.mkOfCompact_star [CompactSpace α] (f : C(α, β)) : mkOfCompact (star f) = star (mkOfCompact f) := @@ -476,9 +475,9 @@ end NormedSpace section CStarRing variable {α : Type*} {β : Type*} -variable [TopologicalSpace α] [NormedRing β] [StarRing β] +variable [TopologicalSpace α] [CompactSpace α] -instance [CompactSpace α] [CStarRing β] : CStarRing C(α, β) where +instance [NonUnitalNormedRing β] [StarRing β] [CStarRing β] : CStarRing C(α, β) where norm_mul_self_le f := by rw [← sq, ← Real.le_sqrt (norm_nonneg _) (norm_nonneg _), ContinuousMap.norm_le _ (Real.sqrt_nonneg _)] diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index 2b51d3ea2f2d0..cb59956edbce0 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -119,7 +119,6 @@ theorem eq_of_empty [IsEmpty α] (f g : C_c(α, β)) : f = g := def ContinuousMap.liftCompactlySupported [CompactSpace α] : C(α, β) ≃ C_c(α, β) where toFun f := { toFun := f - continuous_toFun := f.continuous hasCompactSupport' := HasCompactSupport.of_compactSpace f } invFun f := f left_inv _ := rfl @@ -168,7 +167,7 @@ theorem mul_apply [MulZeroClass β] [ContinuousMul β] (f g : C_c(α, β)) : (f instance [Zero β] [TopologicalSpace γ] [SMulZeroClass γ β] [ContinuousSMul γ β] {F : Type*} [FunLike F α γ] [ContinuousMapClass F α γ] : SMul F C_c(α, β) where smul f g := - ⟨⟨fun x ↦ f x • g x, (map_continuous f).smul g.continuous⟩, g.hasCompactSupport'.smul_left⟩ + ⟨⟨fun x ↦ f x • g x, (map_continuous f).smul (map_continuous g)⟩, g.hasCompactSupport.smul_left⟩ @[simp] theorem coe_smulc [Zero β] [TopologicalSpace γ] [SMulZeroClass γ β] [ContinuousSMul γ β] @@ -209,7 +208,7 @@ def coeFnMonoidHom [AddMonoid β] [ContinuousAdd β] : C_c(α, β) →+ α → instance [Zero β] {R : Type*} [SMulZeroClass R β] [ContinuousConstSMul R β] : SMul R C_c(α, β) := - ⟨fun r f => ⟨⟨r • ⇑f, Continuous.const_smul f.continuous r⟩, HasCompactSupport.smul_left f.2⟩⟩ + ⟨fun r f => ⟨⟨r • ⇑f, (map_continuous f).const_smul r⟩, HasCompactSupport.smul_left f.2⟩⟩ @[simp, norm_cast] theorem coe_smul [Zero β] {R : Type*} [SMulZeroClass R β] [ContinuousConstSMul R β] (r : R) @@ -448,8 +447,6 @@ theorem zero_comp (g : β →co γ) : (0 : C_c(γ, δ)).comp g = 0 := end -variable [T2Space γ] - /-- Composition as an additive monoid homomorphism. -/ def compAddMonoidHom [AddMonoid δ] [ContinuousAdd δ] (g : β →co γ) : C_c(γ, δ) →+ C_c(β, δ) where toFun f := f.comp g diff --git a/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean index 7dcfc9a8fff16..ddcc9bd155c7c 100644 --- a/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean +++ b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean @@ -80,20 +80,36 @@ lemma le_def [PartialOrder R] (f g : C(X, R)₀) : f ≤ g ↔ ∀ x, f x ≤ g protected instance instTopologicalSpace : TopologicalSpace C(X, R)₀ := TopologicalSpace.induced ((↑) : C(X, R)₀ → C(X, R)) inferInstance -lemma embedding_toContinuousMap : Embedding ((↑) : C(X, R)₀ → C(X, R)) where - induced := rfl +lemma isEmbedding_toContinuousMap : IsEmbedding ((↑) : C(X, R)₀ → C(X, R)) where + eq_induced := rfl inj _ _ h := ext fun x ↦ congr($(h) x) -instance [T0Space R] : T0Space C(X, R)₀ := embedding_toContinuousMap.t0Space -instance [T1Space R] : T1Space C(X, R)₀ := embedding_toContinuousMap.t1Space -instance [T2Space R] : T2Space C(X, R)₀ := embedding_toContinuousMap.t2Space +@[deprecated (since := "2024-10-26")] +alias embedding_toContinuousMap := isEmbedding_toContinuousMap -lemma closedEmbedding_toContinuousMap [T1Space R] : - ClosedEmbedding ((↑) : C(X, R)₀ → C(X, R)) where - toEmbedding := embedding_toContinuousMap +instance [T0Space R] : T0Space C(X, R)₀ := isEmbedding_toContinuousMap.t0Space +instance [R0Space R] : R0Space C(X, R)₀ := isEmbedding_toContinuousMap.r0Space +instance [T1Space R] : T1Space C(X, R)₀ := isEmbedding_toContinuousMap.t1Space +instance [R1Space R] : R1Space C(X, R)₀ := isEmbedding_toContinuousMap.r1Space +instance [T2Space R] : T2Space C(X, R)₀ := isEmbedding_toContinuousMap.t2Space +instance [RegularSpace R] : RegularSpace C(X, R)₀ := isEmbedding_toContinuousMap.regularSpace +instance [T3Space R] : T3Space C(X, R)₀ := isEmbedding_toContinuousMap.t3Space + +instance instContinuousEvalConst : ContinuousEvalConst C(X, R)₀ X R := + .of_continuous_forget isEmbedding_toContinuousMap.continuous + +instance instContinuousEval [LocallyCompactPair X R] : ContinuousEval C(X, R)₀ X R := + .of_continuous_forget isEmbedding_toContinuousMap.continuous + +lemma isClosedEmbedding_toContinuousMap [T1Space R] : + IsClosedEmbedding ((↑) : C(X, R)₀ → C(X, R)) where + toIsEmbedding := isEmbedding_toContinuousMap isClosed_range := by rw [range_toContinuousMap] - exact isClosed_singleton.preimage <| ContinuousMap.continuous_eval_const 0 + exact isClosed_singleton.preimage <| continuous_eval_const 0 + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_toContinuousMap := isClosedEmbedding_toContinuousMap @[fun_prop] lemma continuous_comp_left {X Y Z : Type*} [TopologicalSpace X] @@ -277,8 +293,8 @@ lemma isUniformEmbedding_toContinuousMap : alias uniformEmbedding_toContinuousMap := isUniformEmbedding_toContinuousMap instance [T1Space R] [CompleteSpace C(X, R)] : CompleteSpace C(X, R)₀ := - completeSpace_iff_isComplete_range isUniformEmbedding_toContinuousMap.toUniformInducing - |>.mpr closedEmbedding_toContinuousMap.isClosed_range.isComplete + completeSpace_iff_isComplete_range isUniformEmbedding_toContinuousMap.isUniformInducing + |>.mpr isClosedEmbedding_toContinuousMap.isClosed_range.isComplete lemma isUniformEmbedding_comp {Y : Type*} [UniformSpace Y] [Zero Y] (g : C(Y, R)₀) (hg : IsUniformEmbedding g) : IsUniformEmbedding (g.comp · : C(X, Y)₀ → C(X, R)₀) := @@ -293,15 +309,15 @@ alias uniformEmbedding_comp := isUniformEmbedding_comp sending `0 : X` to `0 : Y`. -/ def _root_.UniformEquiv.arrowCongrLeft₀ {Y : Type*} [TopologicalSpace Y] [Zero Y] (f : X ≃ₜ Y) (hf : f 0 = 0) : C(X, R)₀ ≃ᵤ C(Y, R)₀ where - toFun g := g.comp ⟨f.symm.toContinuousMap, (f.toEquiv.apply_eq_iff_eq_symm_apply.eq ▸ hf).symm⟩ - invFun g := g.comp ⟨f.toContinuousMap, hf⟩ + toFun g := g.comp ⟨f.symm, (f.toEquiv.apply_eq_iff_eq_symm_apply.eq ▸ hf).symm⟩ + invFun g := g.comp ⟨f, hf⟩ left_inv g := ext fun _ ↦ congrArg g <| f.left_inv _ right_inv g := ext fun _ ↦ congrArg g <| f.right_inv _ uniformContinuous_toFun := isUniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <| - ContinuousMap.uniformContinuous_comp_left f.symm.toContinuousMap |>.comp + ContinuousMap.uniformContinuous_comp_left (f.symm : C(Y, X)) |>.comp isUniformEmbedding_toContinuousMap.uniformContinuous uniformContinuous_invFun := isUniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <| - ContinuousMap.uniformContinuous_comp_left f.toContinuousMap |>.comp + ContinuousMap.uniformContinuous_comp_left (f : C(X, Y)) |>.comp isUniformEmbedding_toContinuousMap.uniformContinuous end UniformSpace @@ -351,6 +367,9 @@ noncomputable instance [MetricSpace R] [Zero R]: MetricSpace C(α, R)₀ := noncomputable instance [NormedAddCommGroup R] : Norm C(α, R)₀ where norm f := ‖(f : C(α, R))‖ +lemma norm_def [NormedAddCommGroup R] (f : C(α, R)₀) : ‖f‖ = ‖(f : C(α, R))‖ := + rfl + noncomputable instance [NormedCommRing R] : NonUnitalNormedCommRing C(α, R)₀ where dist_eq f g := NormedAddGroup.dist_eq (f : C(α, R)) g norm_mul f g := NormedRing.norm_mul (f : C(α, R)) g diff --git a/Mathlib/Topology/ContinuousMap/Defs.lean b/Mathlib/Topology/ContinuousMap/Defs.lean new file mode 100644 index 0000000000000..e1ee866070f68 --- /dev/null +++ b/Mathlib/Topology/ContinuousMap/Defs.lean @@ -0,0 +1,140 @@ +/- +Copyright (c) 2020 Nicolò Cavalleri. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nicolò Cavalleri, Yury Kudryashov +-/ +import Mathlib.Tactic.Continuity +import Mathlib.Tactic.Lift +import Mathlib.Topology.Defs.Basic + +/-! +# Continuous bundled maps + +In this file we define the type `ContinuousMap` of continuous bundled maps. + +We use the `DFunLike` design, so each type of morphisms has a companion typeclass +which is meant to be satisfied by itself and all stricter types. +-/ + +open Function +open scoped Topology + +/-- The type of continuous maps from `X` to `Y`. + +When possible, instead of parametrizing results over `(f : C(X, Y))`, +you should parametrize over `{F : Type*} [ContinuousMapClass F X Y] (f : F)`. + +When you extend this structure, make sure to extend `ContinuousMapClass`. -/ +structure ContinuousMap (X Y : Type*) [TopologicalSpace X] [TopologicalSpace Y] where + /-- The function `X → Y` -/ + protected toFun : X → Y + /-- Proposition that `toFun` is continuous -/ + protected continuous_toFun : Continuous toFun := by continuity + +/-- The type of continuous maps from `X` to `Y`. -/ +notation "C(" X ", " Y ")" => ContinuousMap X Y + +section + +/-- `ContinuousMapClass F X Y` states that `F` is a type of continuous maps. + +You should extend this class when you extend `ContinuousMap`. -/ +class ContinuousMapClass (F : Type*) (X Y : outParam Type*) + [TopologicalSpace X] [TopologicalSpace Y] [FunLike F X Y] : Prop where + /-- Continuity -/ + map_continuous (f : F) : Continuous f + +end + +export ContinuousMapClass (map_continuous) + +attribute [continuity, fun_prop] map_continuous + +section ContinuousMapClass + +variable {F X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [FunLike F X Y] +variable [ContinuousMapClass F X Y] + +/-- Coerce a bundled morphism with a `ContinuousMapClass` instance to a `ContinuousMap`. -/ +@[coe] def toContinuousMap (f : F) : C(X, Y) := ⟨f, map_continuous f⟩ + +instance : CoeTC F C(X, Y) := ⟨toContinuousMap⟩ + +end ContinuousMapClass + +/-! ### Continuous maps -/ + + +namespace ContinuousMap + +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + +instance instFunLike : FunLike C(X, Y) X Y where + coe := ContinuousMap.toFun + coe_injective' f g h := by cases f; cases g; congr + +instance instContinuousMapClass : ContinuousMapClass C(X, Y) X Y where + map_continuous := ContinuousMap.continuous_toFun + +@[simp] +theorem toFun_eq_coe {f : C(X, Y)} : f.toFun = (f : X → Y) := + rfl + +instance : CanLift (X → Y) C(X, Y) DFunLike.coe Continuous := ⟨fun f hf ↦ ⟨⟨f, hf⟩, rfl⟩⟩ + +/-- See note [custom simps projection]. -/ +def Simps.apply (f : C(X, Y)) : X → Y := f + +-- this must come after the coe_to_fun definition +initialize_simps_projections ContinuousMap (toFun → apply) + +@[simp] -- Porting note: removed `norm_cast` attribute +protected theorem coe_coe {F : Type*} [FunLike F X Y] [ContinuousMapClass F X Y] (f : F) : + ⇑(f : C(X, Y)) = f := + rfl + +protected theorem coe_apply {F : Type*} [FunLike F X Y] [ContinuousMapClass F X Y] (f : F) (x : X) : + (f : C(X, Y)) x = f x := + rfl + +@[ext] +theorem ext {f g : C(X, Y)} (h : ∀ a, f a = g a) : f = g := + DFunLike.ext _ _ h + +/-- Copy of a `ContinuousMap` with a new `toFun` equal to the old one. Useful to fix definitional +equalities. -/ +protected def copy (f : C(X, Y)) (f' : X → Y) (h : f' = f) : C(X, Y) where + toFun := f' + continuous_toFun := h.symm ▸ f.continuous_toFun + +@[simp] +theorem coe_copy (f : C(X, Y)) (f' : X → Y) (h : f' = f) : ⇑(f.copy f' h) = f' := + rfl + +theorem copy_eq (f : C(X, Y)) (f' : X → Y) (h : f' = f) : f.copy f' h = f := + DFunLike.ext' h + +/-- Deprecated. Use `map_continuous` instead. -/ +protected theorem continuous (f : C(X, Y)) : Continuous f := + f.continuous_toFun + +@[deprecated map_continuous (since := "2024-09-29")] +theorem continuous_set_coe (s : Set C(X, Y)) (f : s) : Continuous (f : X → Y) := + map_continuous _ + +/-- Deprecated. Use `DFunLike.congr_fun` instead. -/ +protected theorem congr_fun {f g : C(X, Y)} (H : f = g) (x : X) : f x = g x := + H ▸ rfl + +/-- Deprecated. Use `DFunLike.congr_arg` instead. -/ +protected theorem congr_arg (f : C(X, Y)) {x y : X} (h : x = y) : f x = f y := + h ▸ rfl + +theorem coe_injective : Function.Injective (DFunLike.coe : C(X, Y) → (X → Y)) := + DFunLike.coe_injective + +@[simp] +theorem coe_mk (f : X → Y) (h : Continuous f) : ⇑(⟨f, h⟩ : C(X, Y)) = f := + rfl + +end ContinuousMap diff --git a/Mathlib/Topology/ContinuousMap/Ideals.lean b/Mathlib/Topology/ContinuousMap/Ideals.lean index 5edb4350d5274..44324eab0595f 100644 --- a/Mathlib/Topology/ContinuousMap/Ideals.lean +++ b/Mathlib/Topology/ContinuousMap/Ideals.lean @@ -86,7 +86,7 @@ def idealOfSet (s : Set X) : Ideal C(X, R) where carrier := {f : C(X, R) | ∀ x ∈ sᶜ, f x = 0} add_mem' {f g} hf hg x hx := by simp [hf x hx, hg x hx, coe_add, Pi.add_apply, add_zero] zero_mem' _ _ := rfl - smul_mem' c f hf x hx := mul_zero (c x) ▸ congr_arg (fun y => c x * y) (hf x hx) + smul_mem' c _ hf x hx := mul_zero (c x) ▸ congr_arg (fun y => c x * y) (hf x hx) theorem idealOfSet_closed [T2Space R] (s : Set X) : IsClosed (idealOfSet R s : Set C(X, R)) := by @@ -388,8 +388,8 @@ variable [Nontrivial 𝕜] [NoZeroDivisors 𝕜] def continuousMapEval : C(X, characterSpace 𝕜 C(X, 𝕜)) where toFun x := ⟨{ toFun := fun f => f x - map_add' := fun f g => rfl - map_smul' := fun z f => rfl + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl cont := continuous_eval_const x }, by rw [CharacterSpace.eq_set_map_one_map_mul]; exact ⟨rfl, fun f g => rfl⟩⟩ continuous_toFun := by diff --git a/Mathlib/Topology/ContinuousMap/LocallyConstant.lean b/Mathlib/Topology/ContinuousMap/LocallyConstant.lean index dce7a9a92d359..bbe26fe3ba211 100644 --- a/Mathlib/Topology/ContinuousMap/LocallyConstant.lean +++ b/Mathlib/Topology/ContinuousMap/LocallyConstant.lean @@ -15,7 +15,7 @@ import Mathlib.Topology.ContinuousMap.Algebra namespace LocallyConstant -variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (f : LocallyConstant X Y) +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] /-- The inclusion of locally-constant functions into continuous functions as a multiplicative monoid hom. -/ diff --git a/Mathlib/Topology/ContinuousMap/Ordered.lean b/Mathlib/Topology/ContinuousMap/Ordered.lean index 24c45724b82b7..14a4185687a12 100644 --- a/Mathlib/Topology/ContinuousMap/Ordered.lean +++ b/Mathlib/Topology/ContinuousMap/Ordered.lean @@ -3,9 +3,9 @@ Copyright (c) 2021 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison, Shing Tak Lam -/ -import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.Order.Lattice import Mathlib.Topology.Order.ProjIcc +import Mathlib.Topology.ContinuousMap.Defs /-! # Bundled continuous maps into orders, with order-compatible topology diff --git a/Mathlib/Topology/ContinuousMap/Polynomial.lean b/Mathlib/Topology/ContinuousMap/Polynomial.lean index 83a3dd5e6a0ed..237d38cd410f8 100644 --- a/Mathlib/Topology/ContinuousMap/Polynomial.lean +++ b/Mathlib/Topology/ContinuousMap/Polynomial.lean @@ -164,7 +164,7 @@ open ContinuousMap /-- The preimage of polynomials on `[0,1]` under the pullback map by `x ↦ (b-a) * x + a` is the polynomials on `[a,b]`. -/ theorem polynomialFunctions.comap_compRightAlgHom_iccHomeoI (a b : ℝ) (h : a < b) : - (polynomialFunctions I).comap (compRightAlgHom ℝ ℝ (iccHomeoI a b h).symm.toContinuousMap) = + (polynomialFunctions I).comap (compRightAlgHom ℝ ℝ (iccHomeoI a b h).symm) = polynomialFunctions (Set.Icc a b) := by ext f fconstructor diff --git a/Mathlib/Topology/ContinuousMap/Sigma.lean b/Mathlib/Topology/ContinuousMap/Sigma.lean index a444781b712f5..1cd4139bd4088 100644 --- a/Mathlib/Topology/ContinuousMap/Sigma.lean +++ b/Mathlib/Topology/ContinuousMap/Sigma.lean @@ -41,10 +41,10 @@ variable {X ι : Type*} {Y : ι → Type*} [TopologicalSpace X] [∀ i, Topologi namespace ContinuousMap -theorem embedding_sigmaMk_comp [Nonempty X] : - Embedding (fun g : Σ i, C(X, Y i) ↦ (sigmaMk g.1).comp g.2) where - toInducing := inducing_sigma.2 - ⟨fun i ↦ (sigmaMk i).inducing_comp embedding_sigmaMk.toInducing, fun i ↦ +theorem isEmbedding_sigmaMk_comp [Nonempty X] : + IsEmbedding (fun g : Σ i, C(X, Y i) ↦ (sigmaMk g.1).comp g.2) where + toIsInducing := inducing_sigma.2 + ⟨fun i ↦ (sigmaMk i).isInducing_postcomp IsEmbedding.sigmaMk.isInducing, fun i ↦ let ⟨x⟩ := ‹Nonempty X› ⟨_, (isOpen_sigma_fst_preimage {i}).preimage (continuous_eval_const x), fun _ ↦ Iff.rfl⟩⟩ inj := by @@ -53,6 +53,9 @@ theorem embedding_sigmaMk_comp [Nonempty X] : Function.eq_of_sigmaMk_comp <| congr_arg DFunLike.coe h simpa using hg +@[deprecated (since := "2024-10-26")] +alias embedding_sigmaMk_comp := isEmbedding_sigmaMk_comp + section ConnectedSpace variable [ConnectedSpace X] @@ -63,7 +66,7 @@ some `i` and a continuous map `g : C(X, Y i)`. See also `Continuous.exists_lift_ with unbundled functions and `ContinuousMap.sigmaCodHomeomorph` for a homeomorphism defined using this fact. -/ theorem exists_lift_sigma (f : C(X, Σ i, Y i)) : ∃ i g, f = (sigmaMk i).comp g := - let ⟨i, g, hg, hfg⟩ := f.continuous.exists_lift_sigma + let ⟨i, g, hg, hfg⟩ := (map_continuous f).exists_lift_sigma ⟨i, ⟨g, hg⟩, DFunLike.ext' hfg⟩ variable (X Y) @@ -75,10 +78,10 @@ continuous maps `C(X, Y i)`. The inverse map sends `⟨i, g⟩` to `ContinuousMap.comp (ContinuousMap.sigmaMk i) g`. -/ @[simps! symm_apply] def sigmaCodHomeomorph : C(X, Σ i, Y i) ≃ₜ Σ i, C(X, Y i) := - .symm <| Equiv.toHomeomorphOfInducing - (.ofBijective _ ⟨embedding_sigmaMk_comp.inj, fun f ↦ + .symm <| Equiv.toHomeomorphOfIsInducing + (.ofBijective _ ⟨isEmbedding_sigmaMk_comp.inj, fun f ↦ let ⟨i, g, hg⟩ := f.exists_lift_sigma; ⟨⟨i, g⟩, hg.symm⟩⟩) - embedding_sigmaMk_comp.toInducing + isEmbedding_sigmaMk_comp.isInducing end ConnectedSpace diff --git a/Mathlib/Topology/ContinuousMap/StarOrdered.lean b/Mathlib/Topology/ContinuousMap/StarOrdered.lean index b894be96cbeb1..3b07ebe1a7087 100644 --- a/Mathlib/Topology/ContinuousMap/StarOrdered.lean +++ b/Mathlib/Topology/ContinuousMap/StarOrdered.lean @@ -92,12 +92,12 @@ instance instStarOrderedRing {R : Type*} refine ⟨star s' * s' + p', ?_, by rw [add_assoc]⟩ exact add_mem (AddSubmonoid.subset_closure ⟨s', rfl⟩) hp'_mem · rintro ⟨p, hp, rfl⟩ - induction hp using AddSubmonoid.closure_induction' generalizing f with + induction hp using AddSubmonoid.closure_induction generalizing f with | mem s s_mem => obtain ⟨s, rfl⟩ := s_mem exact fun x ↦ le_add_of_nonneg_right (star_mul_self_nonneg (s x)) | one => simp - | mul g₁ _ g₂ _ h₁ h₂ => calc + | mul g₁ g₂ _ _ h₁ h₂ => calc f ≤ f + g₁ := h₁ f _ ≤ (f + g₁) + g₂ := h₂ (f + g₁) _ = f + (g₁ + g₂) := add_assoc _ _ _ diff --git a/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean index ff47e32977e60..18ef947a9a9db 100644 --- a/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean +++ b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean @@ -222,9 +222,7 @@ theorem sublattice_closure_eq_top (L : Set C(X, ℝ)) (nA : L.Nonempty) have W_nhd : ∀ x, W x ∈ 𝓝 x := by intro x refine IsOpen.mem_nhds ?_ ?_ - · -- Porting note: mathlib3 `continuity` found `continuous_set_coe` - apply isOpen_lt (continuous_set_coe _ _) - continuity + · apply isOpen_lt <;> fun_prop · dsimp only [W, Set.mem_setOf_eq] rw [h_eq] exact lt_add_of_pos_right _ pos @@ -423,6 +421,39 @@ theorem polynomialFunctions.starClosure_topologicalClosure {𝕜 : Type*} [RCLik ContinuousMap.starSubalgebra_topologicalClosure_eq_top_of_separatesPoints _ (Subalgebra.separatesPoints_monotone le_sup_left (polynomialFunctions_separatesPoints s)) +/-- An induction principle for `C(s, 𝕜)`. -/ +@[elab_as_elim] +theorem ContinuousMap.induction_on {𝕜 : Type*} [RCLike 𝕜] {s : Set 𝕜} + {p : C(s, 𝕜) → Prop} (const : ∀ r, p (.const s r)) (id : p (.restrict s <| .id 𝕜)) + (star_id : p (star (.restrict s <| .id 𝕜))) + (add : ∀ f g, p f → p g → p (f + g)) (mul : ∀ f g, p f → p g → p (f * g)) + (closure : (∀ f ∈ (polynomialFunctions s).starClosure, p f) → ∀ f, p f) (f : C(s, 𝕜)) : + p f := by + refine closure (fun f hf => ?_) f + rw [polynomialFunctions.starClosure_eq_adjoin_X] at hf + induction hf using Algebra.adjoin_induction with + | mem f hf => + simp only [Set.mem_union, Set.mem_singleton_iff, Set.mem_star] at hf + rw [star_eq_iff_star_eq, eq_comm (b := f)] at hf + obtain (rfl | rfl) := hf + all_goals simpa only [toContinuousMapOnAlgHom_apply, toContinuousMapOn_X_eq_restrict_id] + | algebraMap r => exact const r + | add _ _ _ _ hf hg => exact add _ _ hf hg + | mul _ _ _ _ hf hg => exact mul _ _ hf hg + +open Topology in +@[elab_as_elim] +theorem ContinuousMap.induction_on_of_compact {𝕜 : Type*} [RCLike 𝕜] {s : Set 𝕜} [CompactSpace s] + {p : C(s, 𝕜) → Prop} (const : ∀ r, p (.const s r)) (id : p (.restrict s <| .id 𝕜)) + (star_id : p (star (.restrict s <| .id 𝕜))) + (add : ∀ f g, p f → p g → p (f + g)) (mul : ∀ f g, p f → p g → p (f * g)) + (frequently : ∀ f, (∃ᶠ g in 𝓝 f, p g) → p f) (f : C(s, 𝕜)) : + p f := by + refine f.induction_on const id star_id add mul fun h f ↦ frequently f ?_ + have := polynomialFunctions.starClosure_topologicalClosure s ▸ mem_top (x := f) + rw [← SetLike.mem_coe, topologicalClosure_coe, mem_closure_iff_frequently] at this + exact this.mp <| .of_forall h + /-- Continuous algebra homomorphisms from `C(s, ℝ)` into an `ℝ`-algebra `A` which agree at `X : 𝕜[X]` (interpreted as a continuous map) are, in fact, equal. -/ @[ext (iff := false)] @@ -455,17 +486,11 @@ end PolynomialFunctions section ContinuousMapZero -variable {X : Type*} [TopologicalSpace X] {𝕜 : Type*} [RCLike 𝕜] +variable {𝕜 : Type*} [RCLike 𝕜] open NonUnitalStarAlgebra Submodule namespace ContinuousMap -/- -`set_option maxSynthPendingDepth 2` after https://github.com/leanprover/lean4/pull/4119 -allows use to remove some shortcut instances. --/ -set_option maxSynthPendingDepth 2 - lemma adjoin_id_eq_span_one_union (s : Set 𝕜) : ((StarAlgebra.adjoin 𝕜 {(restrict s (.id 𝕜) : C(s, 𝕜))}) : Set C(s, 𝕜)) = span 𝕜 ({(1 : C(s, 𝕜))} ∪ (adjoin 𝕜 {(restrict s (.id 𝕜) : C(s, 𝕜))})) := by @@ -488,13 +513,13 @@ lemma nonUnitalStarAlgebraAdjoin_id_subset_ker_evalStarAlgHom {s : Set 𝕜} (h0 (adjoin 𝕜 {restrict s (.id 𝕜)} : Set C(s, 𝕜)) ⊆ RingHom.ker (evalStarAlgHom 𝕜 𝕜 (⟨0, h0⟩ : s)) := by intro f hf - induction hf using adjoin_induction' with + induction hf using adjoin_induction with | mem f hf => obtain rfl := Set.mem_singleton_iff.mp hf rfl - | add f _ g _ hf hg => exact add_mem hf hg + | add f g _ _ hf hg => exact add_mem hf hg | zero => exact zero_mem _ - | mul f _ g _ _ hg => exact Ideal.mul_mem_left _ f hg + | mul f g _ _ _ hg => exact Ideal.mul_mem_left _ f hg | smul r f _ hf => rw [SetLike.mem_coe, RingHom.mem_ker] at hf ⊢ rw [map_smul, hf, smul_zero] @@ -550,7 +575,8 @@ lemma ker_evalStarAlgHom_eq_closure_adjoin_id (s : Set 𝕜) (h0 : 0 ∈ s) [Com end ContinuousMap -open ContinuousMapZero in +open scoped ContinuousMapZero + /-- If `s : Set 𝕜` with `RCLike 𝕜` is compact and contains `0`, then the non-unital star subalgebra generated by the identity function in `C(s, 𝕜)₀` is dense. This can be seen as a version of the Weierstrass approximation theorem. -/ @@ -558,8 +584,8 @@ lemma ContinuousMapZero.adjoin_id_dense {s : Set 𝕜} [Zero s] (h0 : ((0 : s) : [CompactSpace s] : Dense (adjoin 𝕜 {(.id h0 : C(s, 𝕜)₀)} : Set C(s, 𝕜)₀) := by have h0' : 0 ∈ s := h0 ▸ (0 : s).property rw [dense_iff_closure_eq, - ← closedEmbedding_toContinuousMap.injective.preimage_image (closure _), - ← closedEmbedding_toContinuousMap.closure_image_eq, ← coe_toContinuousMapHom, + ← isClosedEmbedding_toContinuousMap.injective.preimage_image (closure _), + ← isClosedEmbedding_toContinuousMap.closure_image_eq, ← coe_toContinuousMapHom, ← NonUnitalStarSubalgebra.coe_map, NonUnitalStarAlgHom.map_adjoin_singleton, toContinuousMapHom_apply, toContinuousMap_id h0, ← ContinuousMap.ker_evalStarAlgHom_eq_closure_adjoin_id s h0'] @@ -568,4 +594,66 @@ lemma ContinuousMapZero.adjoin_id_dense {s : Set 𝕜} [Zero s] (h0 : ((0 : s) : ContinuousMap.evalStarAlgHom_apply, ContinuousMap.coe_coe] rw [show ⟨0, h0'⟩ = (0 : s) by ext; exact h0.symm, _root_.map_zero f] +/-- An induction principle for `C(s, 𝕜)₀`. -/ +@[elab_as_elim] +lemma ContinuousMapZero.induction_on {s : Set 𝕜} [Zero s] (h0 : ((0 : s) : 𝕜) = 0) + {p : C(s, 𝕜)₀ → Prop} (zero : p 0) (id : p (.id h0)) (star_id : p (star (.id h0))) + (add : ∀ f g, p f → p g → p (f + g)) (mul : ∀ f g, p f → p g → p (f * g)) + (smul : ∀ (r : 𝕜) f, p f → p (r • f)) + (closure : (∀ f ∈ adjoin 𝕜 {(.id h0 : C(s, 𝕜)₀)}, p f) → ∀ f, p f) (f : C(s, 𝕜)₀) : + p f := by + refine closure (fun f hf => ?_) f + induction hf using NonUnitalAlgebra.adjoin_induction with + | mem f hf => + simp only [Set.mem_union, Set.mem_singleton_iff, Set.mem_star] at hf + rw [star_eq_iff_star_eq, eq_comm (b := f)] at hf + obtain (rfl | rfl) := hf + all_goals assumption + | zero => exact zero + | add _ _ _ _ hf hg => exact add _ _ hf hg + | mul _ _ _ _ hf hg => exact mul _ _ hf hg + | smul _ _ _ hf => exact smul _ _ hf + +open Topology in +@[elab_as_elim] +theorem ContinuousMapZero.induction_on_of_compact {s : Set 𝕜} [Zero s] (h0 : ((0 : s) : 𝕜) = 0) + [CompactSpace s] {p : C(s, 𝕜)₀ → Prop} (zero : p 0) (id : p (.id h0)) + (star_id : p (star (.id h0))) (add : ∀ f g, p f → p g → p (f + g)) + (mul : ∀ f g, p f → p g → p (f * g)) (smul : ∀ (r : 𝕜) f, p f → p (r • f)) + (frequently : ∀ f, (∃ᶠ g in 𝓝 f, p g) → p f) (f : C(s, 𝕜)₀) : + p f := by + refine f.induction_on h0 zero id star_id add mul smul fun h f ↦ frequently f ?_ + have := (ContinuousMapZero.adjoin_id_dense h0).closure_eq ▸ Set.mem_univ (x := f) + exact mem_closure_iff_frequently.mp this |>.mp <| .of_forall h + +lemma ContinuousMapZero.nonUnitalStarAlgHom_apply_mul_eq_zero {𝕜 A : Type*} + [RCLike 𝕜] [NonUnitalRing A] [StarRing A] [TopologicalSpace A] [TopologicalSemiring A] + [T2Space A] [Module 𝕜 A] [IsScalarTower 𝕜 A A] {s : Set 𝕜} [Zero s] [CompactSpace s] + (h0 : (0 : s) = (0 : 𝕜)) (φ : C(s, 𝕜)₀ →⋆ₙₐ[𝕜] A) (a : A) (hmul_id : φ (.id h0) * a = 0) + (hmul_star_id : φ (star (.id h0)) * a = 0) (hφ : Continuous φ) (f : C(s, 𝕜)₀) : + φ f * a = 0 := by + induction f using ContinuousMapZero.induction_on_of_compact h0 with + | zero => simp [map_zero] + | id => exact hmul_id + | star_id => exact hmul_star_id + | add _ _ h₁ h₂ => simp only [map_add, add_mul, h₁, h₂, zero_add] + | mul _ _ _ h => simp only [map_mul, mul_assoc, h, mul_zero] + | smul _ _ h => rw [map_smul, smul_mul_assoc, h, smul_zero] + | frequently f h => exact h.mem_of_closed <| isClosed_eq (by fun_prop) continuous_zero + +lemma ContinuousMapZero.mul_nonUnitalStarAlgHom_apply_eq_zero {𝕜 A : Type*} + [RCLike 𝕜] [NonUnitalRing A] [StarRing A] [TopologicalSpace A] [TopologicalSemiring A] + [T2Space A] [Module 𝕜 A] [SMulCommClass 𝕜 A A] {s : Set 𝕜} [Zero s] [CompactSpace s] + (h0 : (0 : s) = (0 : 𝕜)) (φ : C(s, 𝕜)₀ →⋆ₙₐ[𝕜] A) (a : A) (hmul_id : a * φ (.id h0) = 0) + (hmul_star_id : a * φ (star (.id h0)) = 0) (hφ : Continuous φ) (f : C(s, 𝕜)₀) : + a * φ f = 0 := by + induction f using ContinuousMapZero.induction_on_of_compact h0 with + | zero => simp [map_zero] + | id => exact hmul_id + | star_id => exact hmul_star_id + | add _ _ h₁ h₂ => simp only [map_add, mul_add, h₁, h₂, zero_add] + | mul _ _ h _ => simp only [map_mul, ← mul_assoc, h, zero_mul] + | smul _ _ h => rw [map_smul, mul_smul_comm, h, smul_zero] + | frequently f h => exact h.mem_of_closed <| isClosed_eq (by fun_prop) continuous_zero + end ContinuousMapZero diff --git a/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean b/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean index 4e9903ccc7400..1177d31231b59 100644 --- a/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean +++ b/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean @@ -43,16 +43,22 @@ def productOfMemOpens : C(X, Opens X → Prop) where toFun x u := x ∈ u continuous_toFun := continuous_pi_iff.2 fun u => continuous_Prop.2 u.isOpen -theorem productOfMemOpens_inducing : Inducing (productOfMemOpens X) := by +theorem productOfMemOpens_isInducing : IsInducing (productOfMemOpens X) := by convert inducing_iInf_to_pi fun (u : Opens X) (x : X) => x ∈ u apply eq_induced_by_maps_to_sierpinski +@[deprecated (since := "2024-10-28")] +alias productOfMemOpens_inducing := productOfMemOpens_isInducing + theorem productOfMemOpens_injective [T0Space X] : Function.Injective (productOfMemOpens X) := by intro x1 x2 h apply Inseparable.eq - rw [← Inducing.inseparable_iff (productOfMemOpens_inducing X), h] + rw [← IsInducing.inseparable_iff (productOfMemOpens_isInducing X), h] + +theorem productOfMemOpens_isEmbedding [T0Space X] : IsEmbedding (productOfMemOpens X) := + .mk (productOfMemOpens_isInducing X) (productOfMemOpens_injective X) -theorem productOfMemOpens_embedding [T0Space X] : Embedding (productOfMemOpens X) := - Embedding.mk (productOfMemOpens_inducing X) (productOfMemOpens_injective X) +@[deprecated (since := "2024-10-26")] +alias productOfMemOpens_embedding := productOfMemOpens_isEmbedding end TopologicalSpace diff --git a/Mathlib/Topology/ContinuousMap/Units.lean b/Mathlib/Topology/ContinuousMap/Units.lean index 0337bcc434faa..b63040d502d1d 100644 --- a/Mathlib/Topology/ContinuousMap/Units.lean +++ b/Mathlib/Topology/ContinuousMap/Units.lean @@ -33,8 +33,8 @@ def unitsLift : C(X, Mˣ) ≃ C(X, M)ˣ where toFun f := { val := ⟨fun x => f x, Units.continuous_val.comp f.continuous⟩ inv := ⟨fun x => ↑(f x)⁻¹, Units.continuous_val.comp (continuous_inv.comp f.continuous)⟩ - val_inv := ext fun x => Units.mul_inv _ - inv_val := ext fun x => Units.inv_mul _ } + val_inv := ext fun _ => Units.mul_inv _ + inv_val := ext fun _ => Units.inv_mul _ } invFun f := { toFun := fun x => ⟨(f : C(X, M)) x, (↑f⁻¹ : C(X, M)) x, diff --git a/Mathlib/Topology/ContinuousMap/Weierstrass.lean b/Mathlib/Topology/ContinuousMap/Weierstrass.lean index fbfdd66fb2023..5e1edd95c1dc8 100644 --- a/Mathlib/Topology/ContinuousMap/Weierstrass.lean +++ b/Mathlib/Topology/ContinuousMap/Weierstrass.lean @@ -55,10 +55,10 @@ theorem polynomialFunctions_closure_eq_top (a b : ℝ) : · -- We can pullback continuous functions on `[a,b]` to continuous functions on `[0,1]`, -- by precomposing with an affine map. let W : C(Set.Icc a b, ℝ) →ₐ[ℝ] C(I, ℝ) := - compRightAlgHom ℝ ℝ (iccHomeoI a b h).symm.toContinuousMap + compRightAlgHom ℝ ℝ (iccHomeoI a b h).symm -- This operation is itself a homeomorphism -- (with respect to the norm topologies on continuous functions). - let W' : C(Set.Icc a b, ℝ) ≃ₜ C(I, ℝ) := compRightHomeomorph ℝ (iccHomeoI a b h).symm + let W' : C(Set.Icc a b, ℝ) ≃ₜ C(I, ℝ) := (iccHomeoI a b h).arrowCongr (.refl _) have w : (W : C(Set.Icc a b, ℝ) → C(I, ℝ)) = W' := rfl -- Thus we take the statement of the Weierstrass approximation theorem for `[0,1]`, have p := polynomialFunctions_closure_eq_top' diff --git a/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean b/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean index c8c2dd96d5d02..c995eda23b8e7 100644 --- a/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean +++ b/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean @@ -381,7 +381,7 @@ theorem toBCF_injective : Function.Injective (toBCF : C₀(α, β) → α →ᵇ end -variable {C : ℝ} {f g : C₀(α, β)} +variable {f g : C₀(α, β)} /-- The type of continuous functions vanishing at infinity, with the uniform distance induced by the inclusion `ZeroAtInftyContinuousMap.toBCF`, is a pseudo-metric space. -/ @@ -428,7 +428,7 @@ theorem isClosed_range_toBCF : IsClosed (range (toBCF : C₀(α, β) → α → /-- Continuous functions vanishing at infinity taking values in a complete space form a complete space. -/ instance instCompleteSpace [CompleteSpace β] : CompleteSpace C₀(α, β) := - (completeSpace_iff_isComplete_range isometry_toBCF.uniformInducing).mpr + (completeSpace_iff_isComplete_range isometry_toBCF.isUniformInducing).mpr isClosed_range_toBCF.isComplete end Metric diff --git a/Mathlib/Topology/ContinuousOn.lean b/Mathlib/Topology/ContinuousOn.lean index b526794778cbb..c4d96278ccf4e 100644 --- a/Mathlib/Topology/ContinuousOn.lean +++ b/Mathlib/Topology/ContinuousOn.lean @@ -9,13 +9,14 @@ import Mathlib.Topology.Constructions /-! # Neighborhoods and continuity relative to a subset -This file defines relative versions +This file develops API on the relative versions * `nhdsWithin` of `nhds` * `ContinuousOn` of `Continuous` * `ContinuousWithinAt` of `ContinuousAt` -and proves their basic properties, including the relationships between +related to continuity, which are defined in previous definition files. +Their basic properties studied in this file include the relationships between these restricted notions and the corresponding notions for the subtype equipped with the subspace topology. @@ -29,9 +30,13 @@ equipped with the subspace topology. open Set Filter Function Topology Filter -variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} +variable {α β γ δ : Type*} variable [TopologicalSpace α] +/-! +## Properties of the neighborhood-within filter +-/ + @[simp] theorem nhds_bind_nhdsWithin {a : α} {s : Set α} : ((𝓝 a).bind fun x => 𝓝[s] x) = 𝓝[s] a := bind_inf_principal.trans <| congr_arg₂ _ nhds_bind_nhds rfl @@ -54,12 +59,20 @@ theorem mem_closure_ne_iff_frequently_within {z : α} {s : Set α} : simp [mem_closure_iff_frequently, frequently_nhdsWithin_iff] @[simp] -theorem eventually_nhdsWithin_nhdsWithin {a : α} {s : Set α} {p : α → Prop} : +theorem eventually_eventually_nhdsWithin {a : α} {s : Set α} {p : α → Prop} : (∀ᶠ y in 𝓝[s] a, ∀ᶠ x in 𝓝[s] y, p x) ↔ ∀ᶠ x in 𝓝[s] a, p x := by refine ⟨fun h => ?_, fun h => (eventually_nhds_nhdsWithin.2 h).filter_mono inf_le_left⟩ simp only [eventually_nhdsWithin_iff] at h ⊢ exact h.mono fun x hx hxs => (hx hxs).self_of_nhds hxs +@[deprecated (since := "2024-10-04")] +alias eventually_nhdsWithin_nhdsWithin := eventually_eventually_nhdsWithin + +@[simp] +theorem eventually_mem_nhdsWithin_iff {x : α} {s t : Set α} : + (∀ᶠ x' in 𝓝[s] x, t ∈ 𝓝[s] x') ↔ t ∈ 𝓝[s] x := + eventually_eventually_nhdsWithin + theorem nhdsWithin_eq (a : α) (s : Set α) : 𝓝[s] a = ⨅ t ∈ { t : Set α | a ∈ t ∧ IsOpen t }, 𝓟 (t ∩ s) := ((nhds_basis_opens a).inf_principal s).eq_biInf @@ -192,6 +205,33 @@ theorem nhdsWithin_union (a : α) (s t : Set α) : 𝓝[s ∪ t] a = 𝓝[s] a delta nhdsWithin rw [← inf_sup_left, sup_principal] +theorem nhds_eq_nhdsWithin_sup_nhdsWithin (b : α) {I₁ I₂ : Set α} (hI : Set.univ = I₁ ∪ I₂) : + nhds b = nhdsWithin b I₁ ⊔ nhdsWithin b I₂ := by + rw [← nhdsWithin_univ b, hI, nhdsWithin_union] + +/-- If `L` and `R` are neighborhoods of `b` within sets whose union is `Set.univ`, then +`L ∪ R` is a neighborhood of `b`. -/ +theorem union_mem_nhds_of_mem_nhdsWithin {b : α} + {I₁ I₂ : Set α} (h : Set.univ = I₁ ∪ I₂) + {L : Set α} (hL : L ∈ nhdsWithin b I₁) + {R : Set α} (hR : R ∈ nhdsWithin b I₂) : L ∪ R ∈ nhds b := by + rw [← nhdsWithin_univ b, h, nhdsWithin_union] + exact ⟨mem_of_superset hL (by aesop), mem_of_superset hR (by aesop)⟩ + + +/-- Writing a punctured neighborhood filter as a sup of left and right filters. -/ +lemma punctured_nhds_eq_nhdsWithin_sup_nhdsWithin [LinearOrder α] {x : α} : + 𝓝[≠] x = 𝓝[<] x ⊔ 𝓝[>] x := by + rw [← Iio_union_Ioi, nhdsWithin_union] + + +/-- Obtain a "predictably-sided" neighborhood of `b` from two one-sided neighborhoods. -/ +theorem nhds_of_Ici_Iic [LinearOrder α] {b : α} + {L : Set α} (hL : L ∈ 𝓝[≤] b) + {R : Set α} (hR : R ∈ 𝓝[≥] b) : L ∩ Iic b ∪ R ∩ Ici b ∈ 𝓝 b := + union_mem_nhds_of_mem_nhdsWithin Iic_union_Ici.symm + (inter_mem hL self_mem_nhdsWithin) (inter_mem hR self_mem_nhdsWithin) + theorem nhdsWithin_biUnion {ι} {I : Set ι} (hI : I.Finite) (s : ι → Set α) (a : α) : 𝓝[⋃ i ∈ I, s i] a = ⨆ i ∈ I, 𝓝[s i] a := Set.Finite.induction_on hI (by simp) fun _ _ hT ↦ by @@ -291,6 +331,8 @@ instance Pi.instNeBotNhdsWithinIoi [Nonempty ι] [∀ i, Preorder (π i)] {x : [∀ i, (𝓝[>] x i).NeBot] : (𝓝[>] x).NeBot := Pi.instNeBotNhdsWithinIio (π := fun i ↦ (π i)ᵒᵈ) (x := fun i ↦ OrderDual.toDual (x i)) +end Pi + theorem Filter.Tendsto.piecewise_nhdsWithin {f g : α → β} {t : Set α} [∀ x, Decidable (x ∈ t)] {a : α} {s : Set α} {l : Filter β} (h₀ : Tendsto f (𝓝[s ∩ t] a) l) (h₁ : Tendsto g (𝓝[s ∩ tᶜ] a) l) : Tendsto (piecewise t f g) (𝓝[s] a) l := by @@ -430,19 +472,24 @@ theorem tendsto_nhdsWithin_iff_subtype {s : Set α} {a : α} (h : a ∈ s) (f : Tendsto f (𝓝[s] a) l ↔ Tendsto (s.restrict f) (𝓝 ⟨a, h⟩) l := by rw [nhdsWithin_eq_map_subtype_coe h, tendsto_map'_iff]; rfl +/-! +## Local continuity properties of functions +-/ + variable [TopologicalSpace β] [TopologicalSpace γ] [TopologicalSpace δ] + {f g : α → β} {s s' s₁ t : Set α} {x : α} + +/-! +### `ContinuousWithinAt` +-/ /-- If a function is continuous within `s` at `x`, then it tends to `f x` within `s` by definition. We register this fact for use with the dot notation, especially to use `Filter.Tendsto.comp` as `ContinuousWithinAt.comp` will have a different meaning. -/ -theorem ContinuousWithinAt.tendsto {f : α → β} {s : Set α} {x : α} (h : ContinuousWithinAt f s x) : +theorem ContinuousWithinAt.tendsto (h : ContinuousWithinAt f s x) : Tendsto f (𝓝[s] x) (𝓝 (f x)) := h -theorem ContinuousOn.continuousWithinAt {f : α → β} {s : Set α} {x : α} (hf : ContinuousOn f s) - (hx : x ∈ s) : ContinuousWithinAt f s x := - hf x hx - theorem continuousWithinAt_univ (f : α → β) (x : α) : ContinuousWithinAt f Set.univ x ↔ ContinuousAt f x := by rw [ContinuousAt, ContinuousWithinAt, nhdsWithin_univ] @@ -455,102 +502,53 @@ theorem continuousWithinAt_iff_continuousAt_restrict (f : α → β) {x : α} {s ContinuousWithinAt f s x ↔ ContinuousAt (s.restrict f) ⟨x, h⟩ := tendsto_nhdsWithin_iff_subtype h f _ -theorem ContinuousWithinAt.tendsto_nhdsWithin {f : α → β} {x : α} {s : Set α} {t : Set β} - (h : ContinuousWithinAt f s x) (ht : MapsTo f s t) : Tendsto f (𝓝[s] x) (𝓝[t] f x) := +theorem ContinuousWithinAt.tendsto_nhdsWithin {t : Set β} + (h : ContinuousWithinAt f s x) (ht : MapsTo f s t) : + Tendsto f (𝓝[s] x) (𝓝[t] f x) := tendsto_inf.2 ⟨h, tendsto_principal.2 <| mem_inf_of_right <| mem_principal.2 <| ht⟩ -theorem ContinuousWithinAt.tendsto_nhdsWithin_image {f : α → β} {x : α} {s : Set α} - (h : ContinuousWithinAt f s x) : Tendsto f (𝓝[s] x) (𝓝[f '' s] f x) := +theorem ContinuousWithinAt.tendsto_nhdsWithin_image (h : ContinuousWithinAt f s x) : + Tendsto f (𝓝[s] x) (𝓝[f '' s] f x) := h.tendsto_nhdsWithin (mapsTo_image _ _) -theorem ContinuousWithinAt.prod_map {f : α → γ} {g : β → δ} {s : Set α} {t : Set β} {x : α} {y : β} - (hf : ContinuousWithinAt f s x) (hg : ContinuousWithinAt g t y) : - ContinuousWithinAt (Prod.map f g) (s ×ˢ t) (x, y) := by - unfold ContinuousWithinAt at * - rw [nhdsWithin_prod_eq, Prod.map, nhds_prod_eq] - exact hf.prod_map hg - -theorem continuousWithinAt_prod_of_discrete_left [DiscreteTopology α] - {f : α × β → γ} {s : Set (α × β)} {x : α × β} : - ContinuousWithinAt f s x ↔ ContinuousWithinAt (f ⟨x.1, ·⟩) {b | (x.1, b) ∈ s} x.2 := by - rw [← x.eta]; simp_rw [ContinuousWithinAt, nhdsWithin, nhds_prod_eq, nhds_discrete, pure_prod, - ← map_inf_principal_preimage]; rfl - -theorem continuousWithinAt_prod_of_discrete_right [DiscreteTopology β] - {f : α × β → γ} {s : Set (α × β)} {x : α × β} : - ContinuousWithinAt f s x ↔ ContinuousWithinAt (f ⟨·, x.2⟩) {a | (a, x.2) ∈ s} x.1 := by - rw [← x.eta]; simp_rw [ContinuousWithinAt, nhdsWithin, nhds_prod_eq, nhds_discrete, prod_pure, - ← map_inf_principal_preimage]; rfl - -theorem continuousAt_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} {x : α × β} : - ContinuousAt f x ↔ ContinuousAt (f ⟨x.1, ·⟩) x.2 := by - simp_rw [← continuousWithinAt_univ]; exact continuousWithinAt_prod_of_discrete_left - -theorem continuousAt_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} {x : α × β} : - ContinuousAt f x ↔ ContinuousAt (f ⟨·, x.2⟩) x.1 := by - simp_rw [← continuousWithinAt_univ]; exact continuousWithinAt_prod_of_discrete_right - -theorem continuousOn_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} {s : Set (α × β)} : - ContinuousOn f s ↔ ∀ a, ContinuousOn (f ⟨a, ·⟩) {b | (a, b) ∈ s} := by - simp_rw [ContinuousOn, Prod.forall, continuousWithinAt_prod_of_discrete_left]; rfl - -theorem continuousOn_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} {s : Set (α × β)} : - ContinuousOn f s ↔ ∀ b, ContinuousOn (f ⟨·, b⟩) {a | (a, b) ∈ s} := by - simp_rw [ContinuousOn, Prod.forall, continuousWithinAt_prod_of_discrete_right]; apply forall_swap - -/-- If a function `f a b` is such that `y ↦ f a b` is continuous for all `a`, and `a` lives in a -discrete space, then `f` is continuous, and vice versa. -/ -theorem continuous_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} : - Continuous f ↔ ∀ a, Continuous (f ⟨a, ·⟩) := by - simp_rw [continuous_iff_continuousOn_univ]; exact continuousOn_prod_of_discrete_left - -theorem continuous_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} : - Continuous f ↔ ∀ b, Continuous (f ⟨·, b⟩) := by - simp_rw [continuous_iff_continuousOn_univ]; exact continuousOn_prod_of_discrete_right - -theorem isOpenMap_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} : - IsOpenMap f ↔ ∀ a, IsOpenMap (f ⟨a, ·⟩) := by - simp_rw [isOpenMap_iff_nhds_le, Prod.forall, nhds_prod_eq, nhds_discrete, pure_prod, map_map] - rfl - -theorem isOpenMap_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} : - IsOpenMap f ↔ ∀ b, IsOpenMap (f ⟨·, b⟩) := by - simp_rw [isOpenMap_iff_nhds_le, Prod.forall, forall_swap (α := α) (β := β), nhds_prod_eq, - nhds_discrete, prod_pure, map_map]; rfl +theorem nhdsWithin_le_comap (ctsf : ContinuousWithinAt f s x) : + 𝓝[s] x ≤ comap f (𝓝[f '' s] f x) := + ctsf.tendsto_nhdsWithin_image.le_comap -theorem continuousWithinAt_pi {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] - {f : α → ∀ i, π i} {s : Set α} {x : α} : - ContinuousWithinAt f s x ↔ ∀ i, ContinuousWithinAt (fun y => f y i) s x := - tendsto_pi_nhds +theorem ContinuousWithinAt.preimage_mem_nhdsWithin {t : Set β} + (h : ContinuousWithinAt f s x) (ht : t ∈ 𝓝 (f x)) : f ⁻¹' t ∈ 𝓝[s] x := + h ht -theorem continuousOn_pi {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] - {f : α → ∀ i, π i} {s : Set α} : ContinuousOn f s ↔ ∀ i, ContinuousOn (fun y => f y i) s := - ⟨fun h i x hx => tendsto_pi_nhds.1 (h x hx) i, fun h x hx => tendsto_pi_nhds.2 fun i => h i x hx⟩ +theorem ContinuousWithinAt.preimage_mem_nhdsWithin' {t : Set β} + (h : ContinuousWithinAt f s x) (ht : t ∈ 𝓝[f '' s] f x) : f ⁻¹' t ∈ 𝓝[s] x := + h.tendsto_nhdsWithin (mapsTo_image _ _) ht -@[fun_prop] -theorem continuousOn_pi' {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] - {f : α → ∀ i, π i} {s : Set α} (hf : ∀ i, ContinuousOn (fun y => f y i) s) : - ContinuousOn f s := - continuousOn_pi.2 hf +theorem ContinuousWithinAt.preimage_mem_nhdsWithin'' {y : β} {s t : Set β} + (h : ContinuousWithinAt f (f ⁻¹' s) x) (ht : t ∈ 𝓝[s] y) (hxy : y = f x) : + f ⁻¹' t ∈ 𝓝[f ⁻¹' s] x := by + rw [hxy] at ht + exact h.preimage_mem_nhdsWithin' (nhdsWithin_mono _ (image_preimage_subset f s) ht) -theorem ContinuousWithinAt.fin_insertNth {n} {π : Fin (n + 1) → Type*} - [∀ i, TopologicalSpace (π i)] (i : Fin (n + 1)) {f : α → π i} {a : α} {s : Set α} - (hf : ContinuousWithinAt f s a) {g : α → ∀ j : Fin n, π (i.succAbove j)} - (hg : ContinuousWithinAt g s a) : ContinuousWithinAt (fun a => i.insertNth (f a) (g a)) s a := - hf.tendsto.fin_insertNth i hg +theorem continuousWithinAt_of_not_mem_closure (hx : x ∉ closure s) : + ContinuousWithinAt f s x := by + rw [mem_closure_iff_nhdsWithin_neBot, not_neBot] at hx + rw [ContinuousWithinAt, hx] + exact tendsto_bot -nonrec theorem ContinuousOn.fin_insertNth {n} {π : Fin (n + 1) → Type*} - [∀ i, TopologicalSpace (π i)] (i : Fin (n + 1)) {f : α → π i} {s : Set α} - (hf : ContinuousOn f s) {g : α → ∀ j : Fin n, π (i.succAbove j)} (hg : ContinuousOn g s) : - ContinuousOn (fun a => i.insertNth (f a) (g a)) s := fun a ha => - (hf a ha).fin_insertNth i (hg a ha) +/-! +### `ContinuousOn` +-/ -theorem continuousOn_iff {f : α → β} {s : Set α} : +theorem continuousOn_iff : ContinuousOn f s ↔ ∀ x ∈ s, ∀ t : Set β, IsOpen t → f x ∈ t → ∃ u, IsOpen u ∧ x ∈ u ∧ u ∩ s ⊆ f ⁻¹' t := by simp only [ContinuousOn, ContinuousWithinAt, tendsto_nhds, mem_nhdsWithin] -theorem continuousOn_iff_continuous_restrict {f : α → β} {s : Set α} : +theorem ContinuousOn.continuousWithinAt (hf : ContinuousOn f s) (hx : x ∈ s) : + ContinuousWithinAt f s x := + hf x hx + +theorem continuousOn_iff_continuous_restrict : ContinuousOn f s ↔ Continuous (s.restrict f) := by rw [ContinuousOn, continuous_iff_continuousAt]; constructor · rintro h ⟨x, xs⟩ @@ -561,11 +559,11 @@ theorem continuousOn_iff_continuous_restrict {f : α → β} {s : Set α} : -- Porting note: 2 new lemmas alias ⟨ContinuousOn.restrict, _⟩ := continuousOn_iff_continuous_restrict -theorem ContinuousOn.restrict_mapsTo {f : α → β} {s : Set α} {t : Set β} (hf : ContinuousOn f s) - (ht : MapsTo f s t) : Continuous (ht.restrict f s t) := +theorem ContinuousOn.restrict_mapsTo {t : Set β} (hf : ContinuousOn f s) (ht : MapsTo f s t) : + Continuous (ht.restrict f s t) := hf.restrict.codRestrict _ -theorem continuousOn_iff' {f : α → β} {s : Set α} : +theorem continuousOn_iff' : ContinuousOn f s ↔ ∀ t : Set β, IsOpen t → ∃ u, IsOpen u ∧ f ⁻¹' t ∩ s = u ∩ s := by have : ∀ t, IsOpen (s.restrict f ⁻¹' t) ↔ ∃ u : Set α, IsOpen u ∧ f ⁻¹' t ∩ s = u ∩ s := by intro t @@ -590,7 +588,7 @@ theorem ContinuousOn.mono_rng {α β : Type*} {t₁ : TopologicalSpace α} {t₂ @ContinuousOn α β t₁ t₃ f s := fun x hx _u hu => h₂ x hx <| nhds_mono h₁ hu -theorem continuousOn_iff_isClosed {f : α → β} {s : Set α} : +theorem continuousOn_iff_isClosed : ContinuousOn f s ↔ ∀ t : Set β, IsClosed t → ∃ u, IsClosed u ∧ f ⁻¹' t ∩ s = u ∩ s := by have : ∀ t, IsClosed (s.restrict f ⁻¹' t) ↔ ∃ u : Set α, IsClosed u ∧ f ⁻¹' t ∩ s = u ∩ s := by intro t @@ -598,11 +596,7 @@ theorem continuousOn_iff_isClosed {f : α → β} {s : Set α} : simp only [Subtype.preimage_coe_eq_preimage_coe_iff, eq_comm, Set.inter_comm s] rw [continuousOn_iff_continuous_restrict, continuous_iff_isClosed]; simp only [this] -theorem ContinuousOn.prod_map {f : α → γ} {g : β → δ} {s : Set α} {t : Set β} - (hf : ContinuousOn f s) (hg : ContinuousOn g t) : ContinuousOn (Prod.map f g) (s ×ˢ t) := - fun ⟨x, y⟩ ⟨hx, hy⟩ => ContinuousWithinAt.prod_map (hf x hx) (hg y hy) - -theorem continuous_of_cover_nhds {ι : Sort*} {f : α → β} {s : ι → Set α} +theorem continuous_of_cover_nhds {ι : Sort*} {s : ι → Set α} (hs : ∀ x : α, ∃ i, s i ∈ 𝓝 x) (hf : ∀ i, ContinuousOn f (s i)) : Continuous f := continuous_iff_continuousAt.mpr fun x ↦ let ⟨i, hi⟩ := hs x; by @@ -621,204 +615,359 @@ theorem Set.Subsingleton.continuousOn {s : Set α} (hs : s.Subsingleton) (f : α ContinuousOn f s := hs.induction_on (continuousOn_empty f) (continuousOn_singleton f) -theorem nhdsWithin_le_comap {x : α} {s : Set α} {f : α → β} (ctsf : ContinuousWithinAt f s x) : - 𝓝[s] x ≤ comap f (𝓝[f '' s] f x) := - ctsf.tendsto_nhdsWithin_image.le_comap +theorem continuousOn_open_iff (hs : IsOpen s) : + ContinuousOn f s ↔ ∀ t, IsOpen t → IsOpen (s ∩ f ⁻¹' t) := by + rw [continuousOn_iff'] + constructor + · intro h t ht + rcases h t ht with ⟨u, u_open, hu⟩ + rw [inter_comm, hu] + apply IsOpen.inter u_open hs + · intro h t ht + refine ⟨s ∩ f ⁻¹' t, h t ht, ?_⟩ + rw [@inter_comm _ s (f ⁻¹' t), inter_assoc, inter_self] + +theorem ContinuousOn.isOpen_inter_preimage {t : Set β} + (hf : ContinuousOn f s) (hs : IsOpen s) (ht : IsOpen t) : IsOpen (s ∩ f ⁻¹' t) := + (continuousOn_open_iff hs).1 hf t ht + +theorem ContinuousOn.isOpen_preimage {t : Set β} (h : ContinuousOn f s) + (hs : IsOpen s) (hp : f ⁻¹' t ⊆ s) (ht : IsOpen t) : IsOpen (f ⁻¹' t) := by + convert (continuousOn_open_iff hs).mp h t ht + rw [inter_comm, inter_eq_self_of_subset_left hp] + +theorem ContinuousOn.preimage_isClosed_of_isClosed {t : Set β} + (hf : ContinuousOn f s) (hs : IsClosed s) (ht : IsClosed t) : IsClosed (s ∩ f ⁻¹' t) := by + rcases continuousOn_iff_isClosed.1 hf t ht with ⟨u, hu⟩ + rw [inter_comm, hu.2] + apply IsClosed.inter hu.1 hs + +theorem ContinuousOn.preimage_interior_subset_interior_preimage {t : Set β} + (hf : ContinuousOn f s) (hs : IsOpen s) : s ∩ f ⁻¹' interior t ⊆ s ∩ interior (f ⁻¹' t) := + calc + s ∩ f ⁻¹' interior t ⊆ interior (s ∩ f ⁻¹' t) := + interior_maximal (inter_subset_inter (Subset.refl _) (preimage_mono interior_subset)) + (hf.isOpen_inter_preimage hs isOpen_interior) + _ = s ∩ interior (f ⁻¹' t) := by rw [interior_inter, hs.interior_eq] + +theorem continuousOn_of_locally_continuousOn + (h : ∀ x ∈ s, ∃ t, IsOpen t ∧ x ∈ t ∧ ContinuousOn f (s ∩ t)) : ContinuousOn f s := by + intro x xs + rcases h x xs with ⟨t, open_t, xt, ct⟩ + have := ct x ⟨xs, xt⟩ + rwa [ContinuousWithinAt, ← nhdsWithin_restrict _ xt open_t] at this + +theorem continuousOn_to_generateFrom_iff {β : Type*} {T : Set (Set β)} {f : α → β} : + @ContinuousOn α β _ (.generateFrom T) f s ↔ ∀ x ∈ s, ∀ t ∈ T, f x ∈ t → f ⁻¹' t ∈ 𝓝[s] x := + forall₂_congr fun x _ => by + delta ContinuousWithinAt + simp only [TopologicalSpace.nhds_generateFrom, tendsto_iInf, tendsto_principal, mem_setOf_eq, + and_imp] + exact forall_congr' fun t => forall_swap + +-- Porting note: dropped an unneeded assumption +theorem continuousOn_isOpen_of_generateFrom {β : Type*} {s : Set α} {T : Set (Set β)} {f : α → β} + (h : ∀ t ∈ T, IsOpen (s ∩ f ⁻¹' t)) : + @ContinuousOn α β _ (.generateFrom T) f s := + continuousOn_to_generateFrom_iff.2 fun _x hx t ht hxt => mem_nhdsWithin.2 + ⟨_, h t ht, ⟨hx, hxt⟩, fun _y hy => hy.1.2⟩ -theorem ContinuousWithinAt.mono {f : α → β} {s t : Set α} {x : α} (h : ContinuousWithinAt f t x) +/-! +### Congruence and monotonicity properties with respect to sets +-/ + +theorem ContinuousWithinAt.mono (h : ContinuousWithinAt f t x) (hs : s ⊆ t) : ContinuousWithinAt f s x := h.mono_left (nhdsWithin_mono x hs) -theorem ContinuousWithinAt.mono_of_mem {f : α → β} {s t : Set α} {x : α} - (h : ContinuousWithinAt f t x) (hs : t ∈ 𝓝[s] x) : ContinuousWithinAt f s x := +theorem ContinuousWithinAt.mono_of_mem_nhdsWithin (h : ContinuousWithinAt f t x) (hs : t ∈ 𝓝[s] x) : + ContinuousWithinAt f s x := h.mono_left (nhdsWithin_le_of_mem hs) -theorem continuousWithinAt_congr_nhds {f : α → β} {s t : Set α} {x : α} (h : 𝓝[s] x = 𝓝[t] x) : +@[deprecated (since := "2024-10-18")] +alias ContinuousWithinAt.mono_of_mem := ContinuousWithinAt.mono_of_mem_nhdsWithin + +/-- If two sets coincide around `x`, then being continuous within one or the other at `x` is +equivalent. See also `continuousWithinAt_congr_set'` which requires that the sets coincide +locally away from a point `y`, in a T1 space. -/ +theorem continuousWithinAt_congr_set (h : s =ᶠ[𝓝 x] t) : ContinuousWithinAt f s x ↔ ContinuousWithinAt f t x := by - simp only [ContinuousWithinAt, h] + simp only [ContinuousWithinAt, nhdsWithin_eq_iff_eventuallyEq.mpr h] + +@[deprecated (since := "2024-10-18")] +alias continuousWithinAt_congr_nhds := continuousWithinAt_congr_set + +theorem ContinuousWithinAt.congr_set (hf : ContinuousWithinAt f s x) (h : s =ᶠ[𝓝 x] t) : + ContinuousWithinAt f t x := + (continuousWithinAt_congr_set h).1 hf + +@[deprecated (since := "2024-10-18")] +alias ContinuousWithinAt.congr_nhds := ContinuousWithinAt.congr_set -theorem continuousWithinAt_inter' {f : α → β} {s t : Set α} {x : α} (h : t ∈ 𝓝[s] x) : +theorem continuousWithinAt_inter' (h : t ∈ 𝓝[s] x) : ContinuousWithinAt f (s ∩ t) x ↔ ContinuousWithinAt f s x := by simp [ContinuousWithinAt, nhdsWithin_restrict'' s h] -theorem continuousWithinAt_inter {f : α → β} {s t : Set α} {x : α} (h : t ∈ 𝓝 x) : +theorem continuousWithinAt_inter (h : t ∈ 𝓝 x) : ContinuousWithinAt f (s ∩ t) x ↔ ContinuousWithinAt f s x := by simp [ContinuousWithinAt, nhdsWithin_restrict' s h] -theorem continuousWithinAt_union {f : α → β} {s t : Set α} {x : α} : +theorem continuousWithinAt_union : ContinuousWithinAt f (s ∪ t) x ↔ ContinuousWithinAt f s x ∧ ContinuousWithinAt f t x := by simp only [ContinuousWithinAt, nhdsWithin_union, tendsto_sup] -theorem ContinuousWithinAt.union {f : α → β} {s t : Set α} {x : α} (hs : ContinuousWithinAt f s x) - (ht : ContinuousWithinAt f t x) : ContinuousWithinAt f (s ∪ t) x := +theorem ContinuousWithinAt.union (hs : ContinuousWithinAt f s x) (ht : ContinuousWithinAt f t x) : + ContinuousWithinAt f (s ∪ t) x := continuousWithinAt_union.2 ⟨hs, ht⟩ -theorem ContinuousWithinAt.mem_closure_image {f : α → β} {s : Set α} {x : α} - (h : ContinuousWithinAt f s x) (hx : x ∈ closure s) : f x ∈ closure (f '' s) := - haveI := mem_closure_iff_nhdsWithin_neBot.1 hx - mem_closure_of_tendsto h <| mem_of_superset self_mem_nhdsWithin (subset_preimage_image f s) - -theorem ContinuousWithinAt.mem_closure {f : α → β} {s : Set α} {x : α} {A : Set β} - (h : ContinuousWithinAt f s x) (hx : x ∈ closure s) (hA : MapsTo f s A) : f x ∈ closure A := - closure_mono (image_subset_iff.2 hA) (h.mem_closure_image hx) - -theorem Set.MapsTo.closure_of_continuousWithinAt {f : α → β} {s : Set α} {t : Set β} - (h : MapsTo f s t) (hc : ∀ x ∈ closure s, ContinuousWithinAt f s x) : - MapsTo f (closure s) (closure t) := fun x hx => (hc x hx).mem_closure hx h - -theorem Set.MapsTo.closure_of_continuousOn {f : α → β} {s : Set α} {t : Set β} (h : MapsTo f s t) - (hc : ContinuousOn f (closure s)) : MapsTo f (closure s) (closure t) := - h.closure_of_continuousWithinAt fun x hx => (hc x hx).mono subset_closure - -theorem ContinuousWithinAt.image_closure {f : α → β} {s : Set α} - (hf : ∀ x ∈ closure s, ContinuousWithinAt f s x) : f '' closure s ⊆ closure (f '' s) := - ((mapsTo_image f s).closure_of_continuousWithinAt hf).image_subset - -theorem ContinuousOn.image_closure {f : α → β} {s : Set α} (hf : ContinuousOn f (closure s)) : - f '' closure s ⊆ closure (f '' s) := - ContinuousWithinAt.image_closure fun x hx => (hf x hx).mono subset_closure - @[simp] -theorem continuousWithinAt_singleton {f : α → β} {x : α} : ContinuousWithinAt f {x} x := by +theorem continuousWithinAt_singleton : ContinuousWithinAt f {x} x := by simp only [ContinuousWithinAt, nhdsWithin_singleton, tendsto_pure_nhds] @[simp] -theorem continuousWithinAt_insert_self {f : α → β} {x : α} {s : Set α} : +theorem continuousWithinAt_insert_self : ContinuousWithinAt f (insert x s) x ↔ ContinuousWithinAt f s x := by simp only [← singleton_union, continuousWithinAt_union, continuousWithinAt_singleton, true_and] -alias ⟨_, ContinuousWithinAt.insert_self⟩ := continuousWithinAt_insert_self +protected alias ⟨_, ContinuousWithinAt.insert⟩ := continuousWithinAt_insert_self + +@[deprecated (since := "2024-10-10")] +protected alias ContinuousWithinAt.insert_self := ContinuousWithinAt.insert -theorem ContinuousWithinAt.diff_iff {f : α → β} {s t : Set α} {x : α} +/- `continuousWithinAt_insert` gives the same equivalence but at a point `y` possibly different +from `x`. As this requires the space to be T1, and this property is not available in this file, +this is found in another file although it is part of the basic API for `continuousWithinAt`. -/ + +theorem ContinuousWithinAt.diff_iff (ht : ContinuousWithinAt f t x) : ContinuousWithinAt f (s \ t) x ↔ ContinuousWithinAt f s x := ⟨fun h => (h.union ht).mono <| by simp only [diff_union_self, subset_union_left], fun h => h.mono diff_subset⟩ +/-- See also `continuousWithinAt_diff_singleton` for the case of `s \ {y}`, but +requiring `T1Space α. -/ @[simp] -theorem continuousWithinAt_diff_self {f : α → β} {s : Set α} {x : α} : +theorem continuousWithinAt_diff_self : ContinuousWithinAt f (s \ {x}) x ↔ ContinuousWithinAt f s x := continuousWithinAt_singleton.diff_iff @[simp] -theorem continuousWithinAt_compl_self {f : α → β} {a : α} : - ContinuousWithinAt f {a}ᶜ a ↔ ContinuousAt f a := by +theorem continuousWithinAt_compl_self : + ContinuousWithinAt f {x}ᶜ x ↔ ContinuousAt f x := by rw [compl_eq_univ_diff, continuousWithinAt_diff_self, continuousWithinAt_univ] -@[simp] -theorem continuousWithinAt_update_same [DecidableEq α] {f : α → β} {s : Set α} {x : α} {y : β} : - ContinuousWithinAt (update f x y) s x ↔ Tendsto f (𝓝[s \ {x}] x) (𝓝 y) := - calc - ContinuousWithinAt (update f x y) s x ↔ Tendsto (update f x y) (𝓝[s \ {x}] x) (𝓝 y) := by - { rw [← continuousWithinAt_diff_self, ContinuousWithinAt, update_same] } - _ ↔ Tendsto f (𝓝[s \ {x}] x) (𝓝 y) := - tendsto_congr' <| eventually_nhdsWithin_iff.2 <| Eventually.of_forall - fun z hz => update_noteq hz.2 _ _ - -@[simp] -theorem continuousAt_update_same [DecidableEq α] {f : α → β} {x : α} {y : β} : - ContinuousAt (Function.update f x y) x ↔ Tendsto f (𝓝[≠] x) (𝓝 y) := by - rw [← continuousWithinAt_univ, continuousWithinAt_update_same, compl_eq_univ_diff] - -theorem IsOpenMap.continuousOn_image_of_leftInvOn {f : α → β} {s : Set α} - (h : IsOpenMap (s.restrict f)) {finv : β → α} (hleft : LeftInvOn finv f s) : - ContinuousOn finv (f '' s) := by - refine continuousOn_iff'.2 fun t ht => ⟨f '' (t ∩ s), ?_, ?_⟩ - · rw [← image_restrict] - exact h _ (ht.preimage continuous_subtype_val) - · rw [inter_eq_self_of_subset_left (image_subset f inter_subset_right), hleft.image_inter'] - -theorem IsOpenMap.continuousOn_range_of_leftInverse {f : α → β} (hf : IsOpenMap f) {finv : β → α} - (hleft : Function.LeftInverse finv f) : ContinuousOn finv (range f) := by - rw [← image_univ] - exact (hf.restrict isOpen_univ).continuousOn_image_of_leftInvOn fun x _ => hleft x - -theorem ContinuousOn.congr_mono {f g : α → β} {s s₁ : Set α} (h : ContinuousOn f s) - (h' : EqOn g f s₁) (h₁ : s₁ ⊆ s) : ContinuousOn g s₁ := by - intro x hx - unfold ContinuousWithinAt - have A := (h x (h₁ hx)).mono h₁ - unfold ContinuousWithinAt at A - rw [← h' hx] at A - exact A.congr' h'.eventuallyEq_nhdsWithin.symm +theorem ContinuousOn.mono (hf : ContinuousOn f s) (h : t ⊆ s) : + ContinuousOn f t := fun x hx => (hf x (h hx)).mono_left (nhdsWithin_mono _ h) -theorem ContinuousOn.congr {f g : α → β} {s : Set α} (h : ContinuousOn f s) (h' : EqOn g f s) : - ContinuousOn g s := - h.congr_mono h' (Subset.refl _) +theorem antitone_continuousOn {f : α → β} : Antitone (ContinuousOn f) := fun _s _t hst hf => + hf.mono hst -theorem continuousOn_congr {f g : α → β} {s : Set α} (h' : EqOn g f s) : - ContinuousOn g s ↔ ContinuousOn f s := - ⟨fun h => ContinuousOn.congr h h'.symm, fun h => h.congr h'⟩ +/-! +### Relation between `ContinuousAt` and `ContinuousWithinAt` +-/ -theorem ContinuousAt.continuousWithinAt {f : α → β} {s : Set α} {x : α} (h : ContinuousAt f x) : +theorem ContinuousAt.continuousWithinAt (h : ContinuousAt f x) : ContinuousWithinAt f s x := ContinuousWithinAt.mono ((continuousWithinAt_univ f x).2 h) (subset_univ _) -theorem continuousWithinAt_iff_continuousAt {f : α → β} {s : Set α} {x : α} (h : s ∈ 𝓝 x) : +theorem continuousWithinAt_iff_continuousAt (h : s ∈ 𝓝 x) : ContinuousWithinAt f s x ↔ ContinuousAt f x := by rw [← univ_inter s, continuousWithinAt_inter h, continuousWithinAt_univ] -theorem ContinuousWithinAt.continuousAt {f : α → β} {s : Set α} {x : α} +theorem ContinuousWithinAt.continuousAt (h : ContinuousWithinAt f s x) (hs : s ∈ 𝓝 x) : ContinuousAt f x := (continuousWithinAt_iff_continuousAt hs).mp h -theorem IsOpen.continuousOn_iff {f : α → β} {s : Set α} (hs : IsOpen s) : +theorem IsOpen.continuousOn_iff (hs : IsOpen s) : ContinuousOn f s ↔ ∀ ⦃a⦄, a ∈ s → ContinuousAt f a := forall₂_congr fun _ => continuousWithinAt_iff_continuousAt ∘ hs.mem_nhds -theorem ContinuousOn.continuousAt {f : α → β} {s : Set α} {x : α} (h : ContinuousOn f s) +theorem ContinuousOn.continuousAt (h : ContinuousOn f s) (hx : s ∈ 𝓝 x) : ContinuousAt f x := (h x (mem_of_mem_nhds hx)).continuousAt hx -theorem ContinuousAt.continuousOn {f : α → β} {s : Set α} (hcont : ∀ x ∈ s, ContinuousAt f x) : +theorem continuousOn_of_forall_continuousAt (hcont : ∀ x ∈ s, ContinuousAt f x) : ContinuousOn f s := fun x hx => (hcont x hx).continuousWithinAt -theorem ContinuousWithinAt.comp {g : β → γ} {f : α → β} {s : Set α} {t : Set β} {x : α} - (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) (h : MapsTo f s t) : - ContinuousWithinAt (g ∘ f) s x := - hg.tendsto.comp (hf.tendsto_nhdsWithin h) +@[deprecated (since := "2024-10-30")] +alias ContinuousAt.continuousOn := continuousOn_of_forall_continuousAt -theorem ContinuousWithinAt.comp' {g : β → γ} {f : α → β} {s : Set α} {t : Set β} {x : α} - (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) : - ContinuousWithinAt (g ∘ f) (s ∩ f ⁻¹' t) x := - hg.comp (hf.mono inter_subset_left) inter_subset_right +@[fun_prop] +theorem Continuous.continuousOn (h : Continuous f) : ContinuousOn f s := by + rw [continuous_iff_continuousOn_univ] at h + exact h.mono (subset_univ _) -theorem ContinuousAt.comp_continuousWithinAt {g : β → γ} {f : α → β} {s : Set α} {x : α} - (hg : ContinuousAt g (f x)) (hf : ContinuousWithinAt f s x) : ContinuousWithinAt (g ∘ f) s x := - hg.continuousWithinAt.comp hf (mapsTo_univ _ _) +theorem Continuous.continuousWithinAt (h : Continuous f) : + ContinuousWithinAt f s x := + h.continuousAt.continuousWithinAt -theorem ContinuousOn.comp {g : β → γ} {f : α → β} {s : Set α} {t : Set β} (hg : ContinuousOn g t) - (hf : ContinuousOn f s) (h : MapsTo f s t) : ContinuousOn (g ∘ f) s := fun x hx => - ContinuousWithinAt.comp (hg _ (h hx)) (hf x hx) h -@[fun_prop] -theorem ContinuousOn.comp'' {g : β → γ} {f : α → β} {s : Set α} {t : Set β} (hg : ContinuousOn g t) - (hf : ContinuousOn f s) (h : Set.MapsTo f s t) : ContinuousOn (fun x => g (f x)) s := - ContinuousOn.comp hg hf h +/-! +### Congruence properties with respect to functions +-/ -theorem ContinuousOn.mono {f : α → β} {s t : Set α} (hf : ContinuousOn f s) (h : t ⊆ s) : - ContinuousOn f t := fun x hx => (hf x (h hx)).mono_left (nhdsWithin_mono _ h) +theorem ContinuousOn.congr_mono (h : ContinuousOn f s) (h' : EqOn g f s₁) (h₁ : s₁ ⊆ s) : + ContinuousOn g s₁ := by + intro x hx + unfold ContinuousWithinAt + have A := (h x (h₁ hx)).mono h₁ + unfold ContinuousWithinAt at A + rw [← h' hx] at A + exact A.congr' h'.eventuallyEq_nhdsWithin.symm -theorem antitone_continuousOn {f : α → β} : Antitone (ContinuousOn f) := fun _s _t hst hf => - hf.mono hst +theorem ContinuousOn.congr (h : ContinuousOn f s) (h' : EqOn g f s) : + ContinuousOn g s := + h.congr_mono h' (Subset.refl _) -@[fun_prop] -theorem ContinuousOn.comp' {g : β → γ} {f : α → β} {s : Set α} {t : Set β} (hg : ContinuousOn g t) - (hf : ContinuousOn f s) : ContinuousOn (g ∘ f) (s ∩ f ⁻¹' t) := +theorem continuousOn_congr (h' : EqOn g f s) : + ContinuousOn g s ↔ ContinuousOn f s := + ⟨fun h => ContinuousOn.congr h h'.symm, fun h => h.congr h'⟩ + +theorem Filter.EventuallyEq.congr_continuousWithinAt (h : f =ᶠ[𝓝[s] x] g) (hx : f x = g x) : + ContinuousWithinAt f s x ↔ ContinuousWithinAt g s x := by + rw [ContinuousWithinAt, hx, tendsto_congr' h, ContinuousWithinAt] + +theorem ContinuousWithinAt.congr_of_eventuallyEq + (h : ContinuousWithinAt f s x) (h₁ : g =ᶠ[𝓝[s] x] f) (hx : g x = f x) : + ContinuousWithinAt g s x := + (h₁.congr_continuousWithinAt hx).2 h + +theorem ContinuousWithinAt.congr_of_eventuallyEq_of_mem + (h : ContinuousWithinAt f s x) (h₁ : g =ᶠ[𝓝[s] x] f) (hx : x ∈ s) : + ContinuousWithinAt g s x := + h.congr_of_eventuallyEq h₁ (mem_of_mem_nhdsWithin hx h₁ :) + +theorem Filter.EventuallyEq.congr_continuousWithinAt_of_mem (h : f =ᶠ[𝓝[s] x] g) (hx : x ∈ s) : + ContinuousWithinAt f s x ↔ ContinuousWithinAt g s x := + ⟨fun h' ↦ h'.congr_of_eventuallyEq_of_mem h.symm hx, + fun h' ↦ h'.congr_of_eventuallyEq_of_mem h hx⟩ + +theorem ContinuousWithinAt.congr_of_eventuallyEq_insert + (h : ContinuousWithinAt f s x) (h₁ : g =ᶠ[𝓝[insert x s] x] f) : + ContinuousWithinAt g s x := + h.congr_of_eventuallyEq (nhdsWithin_mono _ (subset_insert _ _) h₁) + (mem_of_mem_nhdsWithin (mem_insert _ _) h₁ :) + +theorem Filter.EventuallyEq.congr_continuousWithinAt_of_insert (h : f =ᶠ[𝓝[insert x s] x] g) : + ContinuousWithinAt f s x ↔ ContinuousWithinAt g s x := + ⟨fun h' ↦ h'.congr_of_eventuallyEq_insert h.symm, + fun h' ↦ h'.congr_of_eventuallyEq_insert h⟩ + +theorem ContinuousWithinAt.congr (h : ContinuousWithinAt f s x) + (h₁ : ∀ y ∈ s, g y = f y) (hx : g x = f x) : ContinuousWithinAt g s x := + h.congr_of_eventuallyEq (mem_of_superset self_mem_nhdsWithin h₁) hx + +theorem continuousWithinAt_congr (h₁ : ∀ y ∈ s, g y = f y) (hx : g x = f x) : + ContinuousWithinAt g s x ↔ ContinuousWithinAt f s x := + ⟨fun h' ↦ h'.congr (fun x hx ↦ (h₁ x hx).symm) hx.symm, fun h' ↦ h'.congr h₁ hx⟩ + +theorem ContinuousWithinAt.congr_of_mem (h : ContinuousWithinAt f s x) + (h₁ : ∀ y ∈ s, g y = f y) (hx : x ∈ s) : ContinuousWithinAt g s x := + h.congr h₁ (h₁ x hx) + +theorem continuousWithinAt_congr_of_mem (h₁ : ∀ y ∈ s, g y = f y) (hx : x ∈ s) : + ContinuousWithinAt g s x ↔ ContinuousWithinAt f s x := + continuousWithinAt_congr h₁ (h₁ x hx) + +theorem ContinuousWithinAt.congr_of_insert (h : ContinuousWithinAt f s x) + (h₁ : ∀ y ∈ insert x s, g y = f y) : ContinuousWithinAt g s x := + h.congr (fun y hy ↦ h₁ y (mem_insert_of_mem _ hy)) (h₁ x (mem_insert _ _)) + +theorem continuousWithinAt_congr_of_insert + (h₁ : ∀ y ∈ insert x s, g y = f y) : + ContinuousWithinAt g s x ↔ ContinuousWithinAt f s x := + continuousWithinAt_congr (fun y hy ↦ h₁ y (mem_insert_of_mem _ hy)) (h₁ x (mem_insert _ _)) + +theorem ContinuousWithinAt.congr_mono + (h : ContinuousWithinAt f s x) (h' : EqOn g f s₁) (h₁ : s₁ ⊆ s) (hx : g x = f x) : + ContinuousWithinAt g s₁ x := + (h.mono h₁).congr h' hx + +theorem ContinuousAt.congr_of_eventuallyEq (h : ContinuousAt f x) (hg : g =ᶠ[𝓝 x] f) : + ContinuousAt g x := by + simp only [← continuousWithinAt_univ] at h ⊢ + exact h.congr_of_eventuallyEq_of_mem (by rwa [nhdsWithin_univ]) (mem_univ x) + +/-! +### Composition +-/ + +theorem ContinuousWithinAt.comp {g : β → γ} {t : Set β} + (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) (h : MapsTo f s t) : + ContinuousWithinAt (g ∘ f) s x := + hg.tendsto.comp (hf.tendsto_nhdsWithin h) + +theorem ContinuousWithinAt.comp_of_eq {g : β → γ} {t : Set β} {y : β} + (hg : ContinuousWithinAt g t y) (hf : ContinuousWithinAt f s x) (h : MapsTo f s t) + (hy : f x = y) : ContinuousWithinAt (g ∘ f) s x := by + subst hy; exact hg.comp hf h + +theorem ContinuousWithinAt.comp_inter {g : β → γ} {t : Set β} + (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) : + ContinuousWithinAt (g ∘ f) (s ∩ f ⁻¹' t) x := hg.comp (hf.mono inter_subset_left) inter_subset_right +@[deprecated (since := "2024-10-10")] +protected alias ContinuousWithinAt.comp' := ContinuousWithinAt.comp_inter + +theorem ContinuousWithinAt.comp_inter_of_eq {g : β → γ} {t : Set β} {y : β} + (hg : ContinuousWithinAt g t y) (hf : ContinuousWithinAt f s x) (hy : f x = y) : + ContinuousWithinAt (g ∘ f) (s ∩ f ⁻¹' t) x := by + subst hy; exact hg.comp_inter hf + +theorem ContinuousWithinAt.comp_of_preimage_mem_nhdsWithin {g : β → γ} {t : Set β} + (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) (h : f ⁻¹' t ∈ 𝓝[s] x) : + ContinuousWithinAt (g ∘ f) s x := + hg.tendsto.comp (tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within f hf h) + +theorem ContinuousWithinAt.comp_of_preimage_mem_nhdsWithin_of_eq {g : β → γ} {t : Set β} {y : β} + (hg : ContinuousWithinAt g t y) (hf : ContinuousWithinAt f s x) (h : f ⁻¹' t ∈ 𝓝[s] x) + (hy : f x = y) : + ContinuousWithinAt (g ∘ f) s x := by + subst hy; exact hg.comp_of_preimage_mem_nhdsWithin hf h + +theorem ContinuousWithinAt.comp_of_mem_nhdsWithin_image {g : β → γ} {t : Set β} + (hg : ContinuousWithinAt g t (f x)) (hf : ContinuousWithinAt f s x) + (hs : t ∈ 𝓝[f '' s] f x) : ContinuousWithinAt (g ∘ f) s x := + (hg.mono_of_mem_nhdsWithin hs).comp hf (mapsTo_image f s) + +theorem ContinuousWithinAt.comp_of_mem_nhdsWithin_image_of_eq {g : β → γ} {t : Set β} {y : β} + (hg : ContinuousWithinAt g t y) (hf : ContinuousWithinAt f s x) + (hs : t ∈ 𝓝[f '' s] y) (hy : f x = y) : ContinuousWithinAt (g ∘ f) s x := by + subst hy; exact hg.comp_of_mem_nhdsWithin_image hf hs + +theorem ContinuousAt.comp_continuousWithinAt {g : β → γ} + (hg : ContinuousAt g (f x)) (hf : ContinuousWithinAt f s x) : ContinuousWithinAt (g ∘ f) s x := + hg.continuousWithinAt.comp hf (mapsTo_univ _ _) + +theorem ContinuousAt.comp_continuousWithinAt_of_eq {g : β → γ} {y : β} + (hg : ContinuousAt g y) (hf : ContinuousWithinAt f s x) (hy : f x = y) : + ContinuousWithinAt (g ∘ f) s x := by + subst hy; exact hg.comp_continuousWithinAt hf + +/-- See also `ContinuousOn.comp'` using the form `fun y ↦ g (f y)` instead of `g ∘ f`. -/ +theorem ContinuousOn.comp {g : β → γ} {t : Set β} (hg : ContinuousOn g t) + (hf : ContinuousOn f s) (h : MapsTo f s t) : ContinuousOn (g ∘ f) s := fun x hx => + ContinuousWithinAt.comp (hg _ (h hx)) (hf x hx) h + +/-- Variant of `ContinuousOn.comp` using the form `fun y ↦ g (f y)` instead of `g ∘ f`. -/ @[fun_prop] -theorem Continuous.continuousOn {f : α → β} {s : Set α} (h : Continuous f) : ContinuousOn f s := by - rw [continuous_iff_continuousOn_univ] at h - exact h.mono (subset_univ _) +theorem ContinuousOn.comp' {g : β → γ} {f : α → β} {s : Set α} {t : Set β} (hg : ContinuousOn g t) + (hf : ContinuousOn f s) (h : Set.MapsTo f s t) : ContinuousOn (fun x => g (f x)) s := + ContinuousOn.comp hg hf h -theorem Continuous.continuousWithinAt {f : α → β} {s : Set α} {x : α} (h : Continuous f) : - ContinuousWithinAt f s x := - h.continuousAt.continuousWithinAt +@[fun_prop] +theorem ContinuousOn.comp_inter {g : β → γ} {t : Set β} (hg : ContinuousOn g t) + (hf : ContinuousOn f s) : ContinuousOn (g ∘ f) (s ∩ f ⁻¹' t) := + hg.comp (hf.mono inter_subset_left) inter_subset_right +/-- See also `Continuous.comp_continuousOn'` using the form `fun y ↦ g (f y)` +instead of `g ∘ f`. -/ theorem Continuous.comp_continuousOn {g : β → γ} {f : α → β} {s : Set α} (hg : Continuous g) (hf : ContinuousOn f s) : ContinuousOn (g ∘ f) s := hg.continuousOn.comp hf (mapsTo_univ _ _) +/-- Variant of `Continuous.comp_continuousOn` using the form `fun y ↦ g (f y)` +instead of `g ∘ f`. -/ @[fun_prop] theorem Continuous.comp_continuousOn' {α β γ : Type*} [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] {g : β → γ} @@ -831,60 +980,189 @@ theorem ContinuousOn.comp_continuous {g : β → γ} {f : α → β} {s : Set β rw [continuous_iff_continuousOn_univ] at * exact hg.comp hf fun x _ => hs x +theorem ContinuousOn.image_comp_continuous {g : β → γ} {f : α → β} {s : Set α} + (hg : ContinuousOn g (f '' s)) (hf : Continuous f) : ContinuousOn (g ∘ f) s := + hg.comp hf.continuousOn (s.mapsTo_image f) + +theorem ContinuousAt.comp₂_continuousWithinAt {f : β × γ → δ} {g : α → β} {h : α → γ} {x : α} + {s : Set α} (hf : ContinuousAt f (g x, h x)) (hg : ContinuousWithinAt g s x) + (hh : ContinuousWithinAt h s x) : + ContinuousWithinAt (fun x ↦ f (g x, h x)) s x := + ContinuousAt.comp_continuousWithinAt hf (hg.prod_mk_nhds hh) + +theorem ContinuousAt.comp₂_continuousWithinAt_of_eq {f : β × γ → δ} {g : α → β} + {h : α → γ} {x : α} {s : Set α} {y : β × γ} (hf : ContinuousAt f y) + (hg : ContinuousWithinAt g s x) (hh : ContinuousWithinAt h s x) (e : (g x, h x) = y) : + ContinuousWithinAt (fun x ↦ f (g x, h x)) s x := by + rw [← e] at hf + exact hf.comp₂_continuousWithinAt hg hh + + +/-! +### Image +-/ + +theorem ContinuousWithinAt.mem_closure_image + (h : ContinuousWithinAt f s x) (hx : x ∈ closure s) : f x ∈ closure (f '' s) := + haveI := mem_closure_iff_nhdsWithin_neBot.1 hx + mem_closure_of_tendsto h <| mem_of_superset self_mem_nhdsWithin (subset_preimage_image f s) + +theorem ContinuousWithinAt.mem_closure {t : Set β} + (h : ContinuousWithinAt f s x) (hx : x ∈ closure s) (ht : MapsTo f s t) : f x ∈ closure t := + closure_mono (image_subset_iff.2 ht) (h.mem_closure_image hx) + +theorem Set.MapsTo.closure_of_continuousWithinAt {t : Set β} + (h : MapsTo f s t) (hc : ∀ x ∈ closure s, ContinuousWithinAt f s x) : + MapsTo f (closure s) (closure t) := fun x hx => (hc x hx).mem_closure hx h + +theorem Set.MapsTo.closure_of_continuousOn {t : Set β} (h : MapsTo f s t) + (hc : ContinuousOn f (closure s)) : MapsTo f (closure s) (closure t) := + h.closure_of_continuousWithinAt fun x hx => (hc x hx).mono subset_closure + +theorem ContinuousWithinAt.image_closure + (hf : ∀ x ∈ closure s, ContinuousWithinAt f s x) : f '' closure s ⊆ closure (f '' s) := + ((mapsTo_image f s).closure_of_continuousWithinAt hf).image_subset + +theorem ContinuousOn.image_closure (hf : ContinuousOn f (closure s)) : + f '' closure s ⊆ closure (f '' s) := + ContinuousWithinAt.image_closure fun x hx => (hf x hx).mono subset_closure + +/-! +### Product +-/ + +theorem ContinuousWithinAt.prod_map {f : α → γ} {g : β → δ} {s : Set α} {t : Set β} {x : α} {y : β} + (hf : ContinuousWithinAt f s x) (hg : ContinuousWithinAt g t y) : + ContinuousWithinAt (Prod.map f g) (s ×ˢ t) (x, y) := by + unfold ContinuousWithinAt at * + rw [nhdsWithin_prod_eq, Prod.map, nhds_prod_eq] + exact hf.prod_map hg + +theorem continuousWithinAt_prod_of_discrete_left [DiscreteTopology α] + {f : α × β → γ} {s : Set (α × β)} {x : α × β} : + ContinuousWithinAt f s x ↔ ContinuousWithinAt (f ⟨x.1, ·⟩) {b | (x.1, b) ∈ s} x.2 := by + rw [← x.eta]; simp_rw [ContinuousWithinAt, nhdsWithin, nhds_prod_eq, nhds_discrete, pure_prod, + ← map_inf_principal_preimage]; rfl + +theorem continuousWithinAt_prod_of_discrete_right [DiscreteTopology β] + {f : α × β → γ} {s : Set (α × β)} {x : α × β} : + ContinuousWithinAt f s x ↔ ContinuousWithinAt (f ⟨·, x.2⟩) {a | (a, x.2) ∈ s} x.1 := by + rw [← x.eta]; simp_rw [ContinuousWithinAt, nhdsWithin, nhds_prod_eq, nhds_discrete, prod_pure, + ← map_inf_principal_preimage]; rfl + +theorem continuousAt_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} {x : α × β} : + ContinuousAt f x ↔ ContinuousAt (f ⟨x.1, ·⟩) x.2 := by + simp_rw [← continuousWithinAt_univ]; exact continuousWithinAt_prod_of_discrete_left + +theorem continuousAt_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} {x : α × β} : + ContinuousAt f x ↔ ContinuousAt (f ⟨·, x.2⟩) x.1 := by + simp_rw [← continuousWithinAt_univ]; exact continuousWithinAt_prod_of_discrete_right + +theorem continuousOn_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} {s : Set (α × β)} : + ContinuousOn f s ↔ ∀ a, ContinuousOn (f ⟨a, ·⟩) {b | (a, b) ∈ s} := by + simp_rw [ContinuousOn, Prod.forall, continuousWithinAt_prod_of_discrete_left]; rfl + +theorem continuousOn_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} {s : Set (α × β)} : + ContinuousOn f s ↔ ∀ b, ContinuousOn (f ⟨·, b⟩) {a | (a, b) ∈ s} := by + simp_rw [ContinuousOn, Prod.forall, continuousWithinAt_prod_of_discrete_right]; apply forall_swap + +/-- If a function `f a b` is such that `y ↦ f a b` is continuous for all `a`, and `a` lives in a +discrete space, then `f` is continuous, and vice versa. -/ +theorem continuous_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} : + Continuous f ↔ ∀ a, Continuous (f ⟨a, ·⟩) := by + simp_rw [continuous_iff_continuousOn_univ]; exact continuousOn_prod_of_discrete_left + +theorem continuous_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} : + Continuous f ↔ ∀ b, Continuous (f ⟨·, b⟩) := by + simp_rw [continuous_iff_continuousOn_univ]; exact continuousOn_prod_of_discrete_right + +theorem isOpenMap_prod_of_discrete_left [DiscreteTopology α] {f : α × β → γ} : + IsOpenMap f ↔ ∀ a, IsOpenMap (f ⟨a, ·⟩) := by + simp_rw [isOpenMap_iff_nhds_le, Prod.forall, nhds_prod_eq, nhds_discrete, pure_prod, map_map] + rfl + +theorem isOpenMap_prod_of_discrete_right [DiscreteTopology β] {f : α × β → γ} : + IsOpenMap f ↔ ∀ b, IsOpenMap (f ⟨·, b⟩) := by + simp_rw [isOpenMap_iff_nhds_le, Prod.forall, forall_swap (α := α) (β := β), nhds_prod_eq, + nhds_discrete, prod_pure, map_map]; rfl + +theorem ContinuousOn.prod_map {f : α → γ} {g : β → δ} {s : Set α} {t : Set β} + (hf : ContinuousOn f s) (hg : ContinuousOn g t) : ContinuousOn (Prod.map f g) (s ×ˢ t) := + fun ⟨x, y⟩ ⟨hx, hy⟩ => ContinuousWithinAt.prod_map (hf x hx) (hg y hy) + +theorem ContinuousWithinAt.prod {f : α → β} {g : α → γ} {s : Set α} {x : α} + (hf : ContinuousWithinAt f s x) (hg : ContinuousWithinAt g s x) : + ContinuousWithinAt (fun x => (f x, g x)) s x := + hf.prod_mk_nhds hg + @[fun_prop] -theorem continuousOn_apply {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] - (i : ι) (s) : ContinuousOn (fun p : ∀ i, π i => p i) s := - Continuous.continuousOn (continuous_apply i) +theorem ContinuousOn.prod {f : α → β} {g : α → γ} {s : Set α} (hf : ContinuousOn f s) + (hg : ContinuousOn g s) : ContinuousOn (fun x => (f x, g x)) s := fun x hx => + ContinuousWithinAt.prod (hf x hx) (hg x hx) -theorem ContinuousWithinAt.preimage_mem_nhdsWithin {f : α → β} {x : α} {s : Set α} {t : Set β} - (h : ContinuousWithinAt f s x) (ht : t ∈ 𝓝 (f x)) : f ⁻¹' t ∈ 𝓝[s] x := - h ht +theorem continuousOn_fst {s : Set (α × β)} : ContinuousOn Prod.fst s := + continuous_fst.continuousOn -theorem Set.LeftInvOn.map_nhdsWithin_eq {f : α → β} {g : β → α} {x : β} {s : Set β} - (h : LeftInvOn f g s) (hx : f (g x) = x) (hf : ContinuousWithinAt f (g '' s) (g x)) - (hg : ContinuousWithinAt g s x) : map g (𝓝[s] x) = 𝓝[g '' s] g x := by - apply le_antisymm - · exact hg.tendsto_nhdsWithin (mapsTo_image _ _) - · have A : g ∘ f =ᶠ[𝓝[g '' s] g x] id := - h.rightInvOn_image.eqOn.eventuallyEq_of_mem self_mem_nhdsWithin - refine le_map_of_right_inverse A ?_ - simpa only [hx] using hf.tendsto_nhdsWithin (h.mapsTo (surjOn_image _ _)) +theorem continuousWithinAt_fst {s : Set (α × β)} {p : α × β} : ContinuousWithinAt Prod.fst s p := + continuous_fst.continuousWithinAt -theorem Function.LeftInverse.map_nhds_eq {f : α → β} {g : β → α} {x : β} - (h : Function.LeftInverse f g) (hf : ContinuousWithinAt f (range g) (g x)) - (hg : ContinuousAt g x) : map g (𝓝 x) = 𝓝[range g] g x := by - simpa only [nhdsWithin_univ, image_univ] using - (h.leftInvOn univ).map_nhdsWithin_eq (h x) (by rwa [image_univ]) hg.continuousWithinAt +@[fun_prop] +theorem ContinuousOn.fst {f : α → β × γ} {s : Set α} (hf : ContinuousOn f s) : + ContinuousOn (fun x => (f x).1) s := + continuous_fst.comp_continuousOn hf -theorem ContinuousWithinAt.preimage_mem_nhdsWithin' {f : α → β} {x : α} {s : Set α} {t : Set β} - (h : ContinuousWithinAt f s x) (ht : t ∈ 𝓝[f '' s] f x) : f ⁻¹' t ∈ 𝓝[s] x := - h.tendsto_nhdsWithin (mapsTo_image _ _) ht +theorem ContinuousWithinAt.fst {f : α → β × γ} {s : Set α} {a : α} (h : ContinuousWithinAt f s a) : + ContinuousWithinAt (fun x => (f x).fst) s a := + continuousAt_fst.comp_continuousWithinAt h -theorem ContinuousWithinAt.preimage_mem_nhdsWithin'' - {f : α → β} {x : α} {y : β} {s t : Set β} - (h : ContinuousWithinAt f (f ⁻¹' s) x) (ht : t ∈ 𝓝[s] y) (hxy : y = f x) : - f ⁻¹' t ∈ 𝓝[f ⁻¹' s] x := by - rw [hxy] at ht - exact h.preimage_mem_nhdsWithin' (nhdsWithin_mono _ (image_preimage_subset f s) ht) +theorem continuousOn_snd {s : Set (α × β)} : ContinuousOn Prod.snd s := + continuous_snd.continuousOn -theorem Filter.EventuallyEq.congr_continuousWithinAt {f g : α → β} {s : Set α} {x : α} - (h : f =ᶠ[𝓝[s] x] g) (hx : f x = g x) : - ContinuousWithinAt f s x ↔ ContinuousWithinAt g s x := by - rw [ContinuousWithinAt, hx, tendsto_congr' h, ContinuousWithinAt] +theorem continuousWithinAt_snd {s : Set (α × β)} {p : α × β} : ContinuousWithinAt Prod.snd s p := + continuous_snd.continuousWithinAt -theorem ContinuousWithinAt.congr_of_eventuallyEq {f f₁ : α → β} {s : Set α} {x : α} - (h : ContinuousWithinAt f s x) (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : - ContinuousWithinAt f₁ s x := - (h₁.congr_continuousWithinAt hx).2 h +@[fun_prop] +theorem ContinuousOn.snd {f : α → β × γ} {s : Set α} (hf : ContinuousOn f s) : + ContinuousOn (fun x => (f x).2) s := + continuous_snd.comp_continuousOn hf -theorem ContinuousWithinAt.congr {f f₁ : α → β} {s : Set α} {x : α} (h : ContinuousWithinAt f s x) - (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : ContinuousWithinAt f₁ s x := - h.congr_of_eventuallyEq (mem_of_superset self_mem_nhdsWithin h₁) hx +theorem ContinuousWithinAt.snd {f : α → β × γ} {s : Set α} {a : α} (h : ContinuousWithinAt f s a) : + ContinuousWithinAt (fun x => (f x).snd) s a := + continuousAt_snd.comp_continuousWithinAt h -theorem ContinuousWithinAt.congr_mono {f g : α → β} {s s₁ : Set α} {x : α} - (h : ContinuousWithinAt f s x) (h' : EqOn g f s₁) (h₁ : s₁ ⊆ s) (hx : g x = f x) : - ContinuousWithinAt g s₁ x := - (h.mono h₁).congr h' hx +theorem continuousWithinAt_prod_iff {f : α → β × γ} {s : Set α} {x : α} : + ContinuousWithinAt f s x ↔ + ContinuousWithinAt (Prod.fst ∘ f) s x ∧ ContinuousWithinAt (Prod.snd ∘ f) s x := + ⟨fun h => ⟨h.fst, h.snd⟩, fun ⟨h1, h2⟩ => h1.prod h2⟩ + +/-! +### Pi +-/ + +theorem continuousWithinAt_pi {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] + {f : α → ∀ i, π i} {s : Set α} {x : α} : + ContinuousWithinAt f s x ↔ ∀ i, ContinuousWithinAt (fun y => f y i) s x := + tendsto_pi_nhds + +theorem continuousOn_pi {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] + {f : α → ∀ i, π i} {s : Set α} : ContinuousOn f s ↔ ∀ i, ContinuousOn (fun y => f y i) s := + ⟨fun h i x hx => tendsto_pi_nhds.1 (h x hx) i, fun h x hx => tendsto_pi_nhds.2 fun i => h i x hx⟩ + +@[fun_prop] +theorem continuousOn_pi' {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] + {f : α → ∀ i, π i} {s : Set α} (hf : ∀ i, ContinuousOn (fun y => f y i) s) : + ContinuousOn f s := + continuousOn_pi.2 hf + +@[fun_prop] +theorem continuousOn_apply {ι : Type*} {π : ι → Type*} [∀ i, TopologicalSpace (π i)] + (i : ι) (s) : ContinuousOn (fun p : ∀ i, π i => p i) s := + Continuous.continuousOn (continuous_apply i) + + +/-! +### Specific functions +-/ @[fun_prop] theorem continuousOn_const {s : Set α} {c : β} : ContinuousOn (fun _ => c) s := @@ -908,119 +1186,110 @@ protected theorem ContinuousOn.iterate {f : α → α} {s : Set α} (hcont : Con | 0 => continuousOn_id | (n + 1) => (hcont.iterate hmaps n).comp hcont hmaps -theorem continuousOn_open_iff {f : α → β} {s : Set α} (hs : IsOpen s) : - ContinuousOn f s ↔ ∀ t, IsOpen t → IsOpen (s ∩ f ⁻¹' t) := by - rw [continuousOn_iff'] - constructor - · intro h t ht - rcases h t ht with ⟨u, u_open, hu⟩ - rw [inter_comm, hu] - apply IsOpen.inter u_open hs - · intro h t ht - refine ⟨s ∩ f ⁻¹' t, h t ht, ?_⟩ - rw [@inter_comm _ s (f ⁻¹' t), inter_assoc, inter_self] - -theorem ContinuousOn.isOpen_inter_preimage {f : α → β} {s : Set α} {t : Set β} - (hf : ContinuousOn f s) (hs : IsOpen s) (ht : IsOpen t) : IsOpen (s ∩ f ⁻¹' t) := - (continuousOn_open_iff hs).1 hf t ht - -theorem ContinuousOn.isOpen_preimage {f : α → β} {s : Set α} {t : Set β} (h : ContinuousOn f s) - (hs : IsOpen s) (hp : f ⁻¹' t ⊆ s) (ht : IsOpen t) : IsOpen (f ⁻¹' t) := by - convert (continuousOn_open_iff hs).mp h t ht - rw [inter_comm, inter_eq_self_of_subset_left hp] - -theorem ContinuousOn.preimage_isClosed_of_isClosed {f : α → β} {s : Set α} {t : Set β} - (hf : ContinuousOn f s) (hs : IsClosed s) (ht : IsClosed t) : IsClosed (s ∩ f ⁻¹' t) := by - rcases continuousOn_iff_isClosed.1 hf t ht with ⟨u, hu⟩ - rw [inter_comm, hu.2] - apply IsClosed.inter hu.1 hs - -theorem ContinuousOn.preimage_interior_subset_interior_preimage {f : α → β} {s : Set α} {t : Set β} - (hf : ContinuousOn f s) (hs : IsOpen s) : s ∩ f ⁻¹' interior t ⊆ s ∩ interior (f ⁻¹' t) := - calc - s ∩ f ⁻¹' interior t ⊆ interior (s ∩ f ⁻¹' t) := - interior_maximal (inter_subset_inter (Subset.refl _) (preimage_mono interior_subset)) - (hf.isOpen_inter_preimage hs isOpen_interior) - _ = s ∩ interior (f ⁻¹' t) := by rw [interior_inter, hs.interior_eq] - -theorem continuousOn_of_locally_continuousOn {f : α → β} {s : Set α} - (h : ∀ x ∈ s, ∃ t, IsOpen t ∧ x ∈ t ∧ ContinuousOn f (s ∩ t)) : ContinuousOn f s := by - intro x xs - rcases h x xs with ⟨t, open_t, xt, ct⟩ - have := ct x ⟨xs, xt⟩ - rwa [ContinuousWithinAt, ← nhdsWithin_restrict _ xt open_t] at this +theorem ContinuousWithinAt.fin_insertNth {n} {π : Fin (n + 1) → Type*} + [∀ i, TopologicalSpace (π i)] (i : Fin (n + 1)) {f : α → π i} {a : α} {s : Set α} + (hf : ContinuousWithinAt f s a) {g : α → ∀ j : Fin n, π (i.succAbove j)} + (hg : ContinuousWithinAt g s a) : ContinuousWithinAt (fun a => i.insertNth (f a) (g a)) s a := + hf.tendsto.fin_insertNth i hg -theorem continuousOn_to_generateFrom_iff {β} {s : Set α} {T : Set (Set β)} {f : α → β} : - @ContinuousOn α β _ (.generateFrom T) f s ↔ ∀ x ∈ s, ∀ t ∈ T, f x ∈ t → f ⁻¹' t ∈ 𝓝[s] x := - forall₂_congr fun x _ => by - delta ContinuousWithinAt - simp only [TopologicalSpace.nhds_generateFrom, tendsto_iInf, tendsto_principal, mem_setOf_eq, - and_imp] - exact forall_congr' fun t => forall_swap +nonrec theorem ContinuousOn.fin_insertNth {n} {π : Fin (n + 1) → Type*} + [∀ i, TopologicalSpace (π i)] (i : Fin (n + 1)) {f : α → π i} {s : Set α} + (hf : ContinuousOn f s) {g : α → ∀ j : Fin n, π (i.succAbove j)} (hg : ContinuousOn g s) : + ContinuousOn (fun a => i.insertNth (f a) (g a)) s := fun a ha => + (hf a ha).fin_insertNth i (hg a ha) --- Porting note: dropped an unneeded assumption -theorem continuousOn_isOpen_of_generateFrom {β : Type*} {s : Set α} {T : Set (Set β)} {f : α → β} - (h : ∀ t ∈ T, IsOpen (s ∩ f ⁻¹' t)) : - @ContinuousOn α β _ (.generateFrom T) f s := - continuousOn_to_generateFrom_iff.2 fun _x hx t ht hxt => mem_nhdsWithin.2 - ⟨_, h t ht, ⟨hx, hxt⟩, fun _y hy => hy.1.2⟩ +theorem Set.LeftInvOn.map_nhdsWithin_eq {f : α → β} {g : β → α} {x : β} {s : Set β} + (h : LeftInvOn f g s) (hx : f (g x) = x) (hf : ContinuousWithinAt f (g '' s) (g x)) + (hg : ContinuousWithinAt g s x) : map g (𝓝[s] x) = 𝓝[g '' s] g x := by + apply le_antisymm + · exact hg.tendsto_nhdsWithin (mapsTo_image _ _) + · have A : g ∘ f =ᶠ[𝓝[g '' s] g x] id := + h.rightInvOn_image.eqOn.eventuallyEq_of_mem self_mem_nhdsWithin + refine le_map_of_right_inverse A ?_ + simpa only [hx] using hf.tendsto_nhdsWithin (h.mapsTo (surjOn_image _ _)) -theorem ContinuousWithinAt.prod {f : α → β} {g : α → γ} {s : Set α} {x : α} - (hf : ContinuousWithinAt f s x) (hg : ContinuousWithinAt g s x) : - ContinuousWithinAt (fun x => (f x, g x)) s x := - hf.prod_mk_nhds hg +theorem Function.LeftInverse.map_nhds_eq {f : α → β} {g : β → α} {x : β} + (h : Function.LeftInverse f g) (hf : ContinuousWithinAt f (range g) (g x)) + (hg : ContinuousAt g x) : map g (𝓝 x) = 𝓝[range g] g x := by + simpa only [nhdsWithin_univ, image_univ] using + (h.leftInvOn univ).map_nhdsWithin_eq (h x) (by rwa [image_univ]) hg.continuousWithinAt -@[fun_prop] -theorem ContinuousOn.prod {f : α → β} {g : α → γ} {s : Set α} (hf : ContinuousOn f s) - (hg : ContinuousOn g s) : ContinuousOn (fun x => (f x, g x)) s := fun x hx => - ContinuousWithinAt.prod (hf x hx) (hg x hx) +lemma IsInducing.continuousWithinAt_iff {f : α → β} {g : β → γ} (hg : IsInducing g) + {s : Set α} {x : α} : ContinuousWithinAt f s x ↔ ContinuousWithinAt (g ∘ f) s x := by + simp_rw [ContinuousWithinAt, hg.tendsto_nhds_iff]; rfl -theorem ContinuousAt.comp₂_continuousWithinAt {f : β × γ → δ} {g : α → β} {h : α → γ} {x : α} - {s : Set α} (hf : ContinuousAt f (g x, h x)) (hg : ContinuousWithinAt g s x) - (hh : ContinuousWithinAt h s x) : - ContinuousWithinAt (fun x ↦ f (g x, h x)) s x := - ContinuousAt.comp_continuousWithinAt hf (hg.prod hh) +@[deprecated (since := "2024-10-28")] +alias Inducing.continuousWithinAt_iff := IsInducing.continuousWithinAt_iff -theorem ContinuousAt.comp₂_continuousWithinAt_of_eq {f : β × γ → δ} {g : α → β} - {h : α → γ} {x : α} {s : Set α} {y : β × γ} (hf : ContinuousAt f y) - (hg : ContinuousWithinAt g s x) (hh : ContinuousWithinAt h s x) (e : (g x, h x) = y) : - ContinuousWithinAt (fun x ↦ f (g x, h x)) s x := by - rw [← e] at hf - exact hf.comp₂_continuousWithinAt hg hh +lemma IsInducing.continuousOn_iff {f : α → β} {g : β → γ} (hg : IsInducing g) + {s : Set α} : ContinuousOn f s ↔ ContinuousOn (g ∘ f) s := by + simp_rw [ContinuousOn, hg.continuousWithinAt_iff] -theorem Inducing.continuousWithinAt_iff {f : α → β} {g : β → γ} (hg : Inducing g) {s : Set α} - {x : α} : ContinuousWithinAt f s x ↔ ContinuousWithinAt (g ∘ f) s x := by - simp_rw [ContinuousWithinAt, Inducing.tendsto_nhds_iff hg]; rfl +@[deprecated (since := "2024-10-28")] alias Inducing.continuousOn_iff := IsInducing.continuousOn_iff -theorem Inducing.continuousOn_iff {f : α → β} {g : β → γ} (hg : Inducing g) {s : Set α} : - ContinuousOn f s ↔ ContinuousOn (g ∘ f) s := by - simp_rw [ContinuousOn, hg.continuousWithinAt_iff] +lemma IsEmbedding.continuousOn_iff {f : α → β} {g : β → γ} (hg : IsEmbedding g) + {s : Set α} : ContinuousOn f s ↔ ContinuousOn (g ∘ f) s := + hg.isInducing.continuousOn_iff -theorem Embedding.continuousOn_iff {f : α → β} {g : β → γ} (hg : Embedding g) {s : Set α} : - ContinuousOn f s ↔ ContinuousOn (g ∘ f) s := - Inducing.continuousOn_iff hg.1 +@[deprecated (since := "2024-10-26")] +alias Embedding.continuousOn_iff := IsEmbedding.continuousOn_iff -theorem Embedding.map_nhdsWithin_eq {f : α → β} (hf : Embedding f) (s : Set α) (x : α) : +lemma IsEmbedding.map_nhdsWithin_eq {f : α → β} (hf : IsEmbedding f) (s : Set α) (x : α) : map f (𝓝[s] x) = 𝓝[f '' s] f x := by rw [nhdsWithin, Filter.map_inf hf.inj, hf.map_nhds_eq, map_principal, ← nhdsWithin_inter', inter_eq_self_of_subset_right (image_subset_range _ _)] -theorem OpenEmbedding.map_nhdsWithin_preimage_eq {f : α → β} (hf : OpenEmbedding f) (s : Set β) +@[deprecated (since := "2024-10-26")] +alias Embedding.map_nhdsWithin_eq := IsEmbedding.map_nhdsWithin_eq + +theorem IsOpenEmbedding.map_nhdsWithin_preimage_eq {f : α → β} (hf : IsOpenEmbedding f) (s : Set β) (x : α) : map f (𝓝[f ⁻¹' s] x) = 𝓝[s] f x := by - rw [hf.toEmbedding.map_nhdsWithin_eq, image_preimage_eq_inter_range] + rw [hf.isEmbedding.map_nhdsWithin_eq, image_preimage_eq_inter_range] apply nhdsWithin_eq_nhdsWithin (mem_range_self _) hf.isOpen_range rw [inter_assoc, inter_self] -theorem QuotientMap.continuousOn_isOpen_iff {f : α → β} {g : β → γ} (h : QuotientMap f) {s : Set β} - (hs : IsOpen s) : ContinuousOn g s ↔ ContinuousOn (g ∘ f) (f ⁻¹' s) := by +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.map_nhdsWithin_preimage_eq := IsOpenEmbedding.map_nhdsWithin_preimage_eq + +theorem IsQuotientMap.continuousOn_isOpen_iff {f : α → β} {g : β → γ} (h : IsQuotientMap f) + {s : Set β} (hs : IsOpen s) : ContinuousOn g s ↔ ContinuousOn (g ∘ f) (f ⁻¹' s) := by simp only [continuousOn_iff_continuous_restrict, (h.restrictPreimage_isOpen hs).continuous_iff] rfl -theorem continuousWithinAt_of_not_mem_closure {f : α → β} {s : Set α} {x : α} (hx : x ∉ closure s) : - ContinuousWithinAt f s x := by - rw [mem_closure_iff_nhdsWithin_neBot, not_neBot] at hx - rw [ContinuousWithinAt, hx] - exact tendsto_bot +@[deprecated (since := "2024-10-22")] +alias QuotientMap.continuousOn_isOpen_iff := IsQuotientMap.continuousOn_isOpen_iff + +theorem IsOpenMap.continuousOn_image_of_leftInvOn {f : α → β} {s : Set α} + (h : IsOpenMap (s.restrict f)) {finv : β → α} (hleft : LeftInvOn finv f s) : + ContinuousOn finv (f '' s) := by + refine continuousOn_iff'.2 fun t ht => ⟨f '' (t ∩ s), ?_, ?_⟩ + · rw [← image_restrict] + exact h _ (ht.preimage continuous_subtype_val) + · rw [inter_eq_self_of_subset_left (image_subset f inter_subset_right), hleft.image_inter'] + +theorem IsOpenMap.continuousOn_range_of_leftInverse {f : α → β} (hf : IsOpenMap f) {finv : β → α} + (hleft : Function.LeftInverse finv f) : ContinuousOn finv (range f) := by + rw [← image_univ] + exact (hf.restrict isOpen_univ).continuousOn_image_of_leftInvOn fun x _ => hleft x + +/-! +### Continuity of piecewise defined functions +-/ + +@[simp] +theorem continuousWithinAt_update_same [DecidableEq α] {y : β} : + ContinuousWithinAt (update f x y) s x ↔ Tendsto f (𝓝[s \ {x}] x) (𝓝 y) := + calc + ContinuousWithinAt (update f x y) s x ↔ Tendsto (update f x y) (𝓝[s \ {x}] x) (𝓝 y) := by + { rw [← continuousWithinAt_diff_self, ContinuousWithinAt, update_same] } + _ ↔ Tendsto f (𝓝[s \ {x}] x) (𝓝 y) := + tendsto_congr' <| eventually_nhdsWithin_iff.2 <| Eventually.of_forall + fun _ hz => update_noteq hz.2 _ _ + +@[simp] +theorem continuousAt_update_same [DecidableEq α] {y : β} : + ContinuousAt (Function.update f x y) x ↔ Tendsto f (𝓝[≠] x) (𝓝 y) := by + rw [← continuousWithinAt_univ, continuousWithinAt_update_same, compl_eq_univ_diff] theorem ContinuousOn.if' {s : Set α} {p : α → Prop} {f g : α → β} [∀ a, Decidable (p a)] (hpf : ∀ a ∈ s ∩ frontier { a | p a }, @@ -1048,15 +1317,14 @@ theorem ContinuousOn.if' {s : Set α} {p : α → Prop} {f g : α → β} [∀ a this (closure_inter_subset_inter_closure _ _ h).2 · exact (hg x hx).congr (fun y hy => if_neg hy.2) (if_neg hx.2) -theorem ContinuousOn.piecewise' {s t : Set α} {f g : α → β} [∀ a, Decidable (a ∈ t)] +theorem ContinuousOn.piecewise' [∀ a, Decidable (a ∈ t)] (hpf : ∀ a ∈ s ∩ frontier t, Tendsto f (𝓝[s ∩ t] a) (𝓝 (piecewise t f g a))) (hpg : ∀ a ∈ s ∩ frontier t, Tendsto g (𝓝[s ∩ tᶜ] a) (𝓝 (piecewise t f g a))) (hf : ContinuousOn f <| s ∩ t) (hg : ContinuousOn g <| s ∩ tᶜ) : ContinuousOn (piecewise t f g) s := hf.if' hpf hpg hg -theorem ContinuousOn.if {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] {p : α → Prop} - [∀ a, Decidable (p a)] {s : Set α} {f g : α → β} +theorem ContinuousOn.if {p : α → Prop} [∀ a, Decidable (p a)] (hp : ∀ a ∈ s ∩ frontier { a | p a }, f a = g a) (hf : ContinuousOn f <| s ∩ closure { a | p a }) (hg : ContinuousOn g <| s ∩ closure { a | ¬p a }) : @@ -1075,12 +1343,12 @@ theorem ContinuousOn.if {α β : Type*} [TopologicalSpace α] [TopologicalSpace · exact hf.mono (inter_subset_inter_right s subset_closure) · exact hg.mono (inter_subset_inter_right s subset_closure) -theorem ContinuousOn.piecewise {s t : Set α} {f g : α → β} [∀ a, Decidable (a ∈ t)] +theorem ContinuousOn.piecewise [∀ a, Decidable (a ∈ t)] (ht : ∀ a ∈ s ∩ frontier t, f a = g a) (hf : ContinuousOn f <| s ∩ closure t) (hg : ContinuousOn g <| s ∩ closure tᶜ) : ContinuousOn (piecewise t f g) s := hf.if ht hg -theorem continuous_if' {p : α → Prop} {f g : α → β} [∀ a, Decidable (p a)] +theorem continuous_if' {p : α → Prop} [∀ a, Decidable (p a)] (hpf : ∀ a ∈ frontier { x | p x }, Tendsto f (𝓝[{ x | p x }] a) (𝓝 <| ite (p a) (f a) (g a))) (hpg : ∀ a ∈ frontier { x | p x }, Tendsto g (𝓝[{ x | ¬p x }] a) (𝓝 <| ite (p a) (f a) (g a))) (hf : ContinuousOn f { x | p x }) (hg : ContinuousOn g { x | ¬p x }) : @@ -1088,39 +1356,39 @@ theorem continuous_if' {p : α → Prop} {f g : α → β} [∀ a, Decidable (p rw [continuous_iff_continuousOn_univ] apply ContinuousOn.if' <;> simp [*] <;> assumption -theorem continuous_if {p : α → Prop} {f g : α → β} [∀ a, Decidable (p a)] +theorem continuous_if {p : α → Prop} [∀ a, Decidable (p a)] (hp : ∀ a ∈ frontier { x | p x }, f a = g a) (hf : ContinuousOn f (closure { x | p x })) (hg : ContinuousOn g (closure { x | ¬p x })) : Continuous fun a => if p a then f a else g a := by rw [continuous_iff_continuousOn_univ] apply ContinuousOn.if <;> simpa -theorem Continuous.if {p : α → Prop} {f g : α → β} [∀ a, Decidable (p a)] +theorem Continuous.if {p : α → Prop} [∀ a, Decidable (p a)] (hp : ∀ a ∈ frontier { x | p x }, f a = g a) (hf : Continuous f) (hg : Continuous g) : Continuous fun a => if p a then f a else g a := continuous_if hp hf.continuousOn hg.continuousOn -theorem continuous_if_const (p : Prop) {f g : α → β} [Decidable p] (hf : p → Continuous f) +theorem continuous_if_const (p : Prop) [Decidable p] (hf : p → Continuous f) (hg : ¬p → Continuous g) : Continuous fun a => if p then f a else g a := by split_ifs with h exacts [hf h, hg h] -theorem Continuous.if_const (p : Prop) {f g : α → β} [Decidable p] (hf : Continuous f) +theorem Continuous.if_const (p : Prop) [Decidable p] (hf : Continuous f) (hg : Continuous g) : Continuous fun a => if p then f a else g a := continuous_if_const p (fun _ => hf) fun _ => hg -theorem continuous_piecewise {s : Set α} {f g : α → β} [∀ a, Decidable (a ∈ s)] +theorem continuous_piecewise [∀ a, Decidable (a ∈ s)] (hs : ∀ a ∈ frontier s, f a = g a) (hf : ContinuousOn f (closure s)) (hg : ContinuousOn g (closure sᶜ)) : Continuous (piecewise s f g) := continuous_if hs hf hg -theorem Continuous.piecewise {s : Set α} {f g : α → β} [∀ a, Decidable (a ∈ s)] +theorem Continuous.piecewise [∀ a, Decidable (a ∈ s)] (hs : ∀ a ∈ frontier s, f a = g a) (hf : Continuous f) (hg : Continuous g) : Continuous (piecewise s f g) := hf.if hs hg section Indicator -variable [One β] {f : α → β} {s : Set α} +variable [One β] @[to_additive] lemma continuous_mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf : ContinuousOn f (closure s)) : @@ -1134,7 +1402,7 @@ protected lemma Continuous.mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf end Indicator -theorem IsOpen.ite' {s s' t : Set α} (hs : IsOpen s) (hs' : IsOpen s') +theorem IsOpen.ite' (hs : IsOpen s) (hs' : IsOpen s') (ht : ∀ x ∈ frontier t, x ∈ s ↔ x ∈ s') : IsOpen (t.ite s s') := by classical simp only [isOpen_iff_continuous_mem, Set.ite] at * @@ -1143,74 +1411,42 @@ theorem IsOpen.ite' {s s' t : Set α} (hs : IsOpen s) (hs' : IsOpen s') rename_i x by_cases hx : x ∈ t <;> simp [hx] -theorem IsOpen.ite {s s' t : Set α} (hs : IsOpen s) (hs' : IsOpen s') +theorem IsOpen.ite (hs : IsOpen s) (hs' : IsOpen s') (ht : s ∩ frontier t = s' ∩ frontier t) : IsOpen (t.ite s s') := hs.ite' hs' fun x hx => by simpa [hx] using Set.ext_iff.1 ht x -theorem ite_inter_closure_eq_of_inter_frontier_eq {s s' t : Set α} +theorem ite_inter_closure_eq_of_inter_frontier_eq (ht : s ∩ frontier t = s' ∩ frontier t) : t.ite s s' ∩ closure t = s ∩ closure t := by rw [closure_eq_self_union_frontier, inter_union_distrib_left, inter_union_distrib_left, ite_inter_self, ite_inter_of_inter_eq _ ht] -theorem ite_inter_closure_compl_eq_of_inter_frontier_eq {s s' t : Set α} +theorem ite_inter_closure_compl_eq_of_inter_frontier_eq (ht : s ∩ frontier t = s' ∩ frontier t) : t.ite s s' ∩ closure tᶜ = s' ∩ closure tᶜ := by rw [← ite_compl, ite_inter_closure_eq_of_inter_frontier_eq] rwa [frontier_compl, eq_comm] -theorem continuousOn_piecewise_ite' {s s' t : Set α} {f f' : α → β} [∀ x, Decidable (x ∈ t)] - (h : ContinuousOn f (s ∩ closure t)) (h' : ContinuousOn f' (s' ∩ closure tᶜ)) - (H : s ∩ frontier t = s' ∩ frontier t) (Heq : EqOn f f' (s ∩ frontier t)) : - ContinuousOn (t.piecewise f f') (t.ite s s') := by +theorem continuousOn_piecewise_ite' [∀ x, Decidable (x ∈ t)] + (h : ContinuousOn f (s ∩ closure t)) (h' : ContinuousOn g (s' ∩ closure tᶜ)) + (H : s ∩ frontier t = s' ∩ frontier t) (Heq : EqOn f g (s ∩ frontier t)) : + ContinuousOn (t.piecewise f g) (t.ite s s') := by apply ContinuousOn.piecewise · rwa [ite_inter_of_inter_eq _ H] · rwa [ite_inter_closure_eq_of_inter_frontier_eq H] · rwa [ite_inter_closure_compl_eq_of_inter_frontier_eq H] -theorem continuousOn_piecewise_ite {s s' t : Set α} {f f' : α → β} [∀ x, Decidable (x ∈ t)] - (h : ContinuousOn f s) (h' : ContinuousOn f' s') (H : s ∩ frontier t = s' ∩ frontier t) - (Heq : EqOn f f' (s ∩ frontier t)) : ContinuousOn (t.piecewise f f') (t.ite s s') := - continuousOn_piecewise_ite' (h.mono inter_subset_left) (h'.mono inter_subset_left) H - Heq - -theorem frontier_inter_open_inter {s t : Set α} (ht : IsOpen t) : - frontier (s ∩ t) ∩ t = frontier s ∩ t := by - simp only [Set.inter_comm _ t, ← Subtype.preimage_coe_eq_preimage_coe_iff, - ht.isOpenMap_subtype_val.preimage_frontier_eq_frontier_preimage continuous_subtype_val, - Subtype.preimage_coe_self_inter] - -theorem continuousOn_fst {s : Set (α × β)} : ContinuousOn Prod.fst s := - continuous_fst.continuousOn - -theorem continuousWithinAt_fst {s : Set (α × β)} {p : α × β} : ContinuousWithinAt Prod.fst s p := - continuous_fst.continuousWithinAt - -@[fun_prop] -theorem ContinuousOn.fst {f : α → β × γ} {s : Set α} (hf : ContinuousOn f s) : - ContinuousOn (fun x => (f x).1) s := - continuous_fst.comp_continuousOn hf - -theorem ContinuousWithinAt.fst {f : α → β × γ} {s : Set α} {a : α} (h : ContinuousWithinAt f s a) : - ContinuousWithinAt (fun x => (f x).fst) s a := - continuousAt_fst.comp_continuousWithinAt h - -theorem continuousOn_snd {s : Set (α × β)} : ContinuousOn Prod.snd s := - continuous_snd.continuousOn - -theorem continuousWithinAt_snd {s : Set (α × β)} {p : α × β} : ContinuousWithinAt Prod.snd s p := - continuous_snd.continuousWithinAt - -@[fun_prop] -theorem ContinuousOn.snd {f : α → β × γ} {s : Set α} (hf : ContinuousOn f s) : - ContinuousOn (fun x => (f x).2) s := - continuous_snd.comp_continuousOn hf - -theorem ContinuousWithinAt.snd {f : α → β × γ} {s : Set α} {a : α} (h : ContinuousWithinAt f s a) : - ContinuousWithinAt (fun x => (f x).snd) s a := - continuousAt_snd.comp_continuousWithinAt h - -theorem continuousWithinAt_prod_iff {f : α → β × γ} {s : Set α} {x : α} : - ContinuousWithinAt f s x ↔ - ContinuousWithinAt (Prod.fst ∘ f) s x ∧ ContinuousWithinAt (Prod.snd ∘ f) s x := - ⟨fun h => ⟨h.fst, h.snd⟩, fun ⟨h1, h2⟩ => h1.prod h2⟩ - -end Pi +theorem continuousOn_piecewise_ite [∀ x, Decidable (x ∈ t)] + (h : ContinuousOn f s) (h' : ContinuousOn g s') (H : s ∩ frontier t = s' ∩ frontier t) + (Heq : EqOn f g (s ∩ frontier t)) : ContinuousOn (t.piecewise f g) (t.ite s s') := + continuousOn_piecewise_ite' (h.mono inter_subset_left) (h'.mono inter_subset_left) H Heq + + +/-- If `f` is continuous on an open set `s` and continuous at each point of another +set `t` then `f` is continuous on `s ∪ t`. -/ +lemma ContinuousOn.union_continuousAt + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + {s t : Set X} {f : X → Y} (s_op : IsOpen s) + (hs : ContinuousOn f s) (ht : ∀ x ∈ t, ContinuousAt f x) : + ContinuousOn f (s ∪ t) := + continuousOn_of_forall_continuousAt <| fun _ hx => hx.elim + (fun h => ContinuousWithinAt.continuousAt (continuousWithinAt hs h) <| IsOpen.mem_nhds s_op h) + (ht _) diff --git a/Mathlib/Topology/CountableSeparatingOn.lean b/Mathlib/Topology/CountableSeparatingOn.lean index fd76eddbe41b3..4531e4bdaaa85 100644 --- a/Mathlib/Topology/CountableSeparatingOn.lean +++ b/Mathlib/Topology/CountableSeparatingOn.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Topology.Separation import Mathlib.Order.Filter.CountableSeparatingOn +import Mathlib.Topology.Separation.Basic /-! # Countable separating families of sets in topological spaces diff --git a/Mathlib/Topology/Covering.lean b/Mathlib/Topology/Covering.lean index 97aae6bbbf86b..eb79ab9ca1ca9 100644 --- a/Mathlib/Topology/Covering.lean +++ b/Mathlib/Topology/Covering.lean @@ -63,7 +63,7 @@ theorem to_isEvenlyCovered_preimage {x : X} {I : Type*} [TopologicalSpace I] (h : IsEvenlyCovered f x I) : IsEvenlyCovered f x (f ⁻¹' {x}) := let ⟨_, h2⟩ := h ⟨((Classical.choose h2).preimageSingletonHomeomorph - (Classical.choose_spec h2)).embedding.discreteTopology, + (Classical.choose_spec h2)).isEmbedding.discreteTopology, _, h.mem_toTrivialization_baseSet⟩ end IsEvenlyCovered @@ -87,7 +87,7 @@ protected theorem continuousAt (hf : IsCoveringMapOn f s) {x : E} (hx : f x ∈ (hf (f x) hx).continuousAt protected theorem continuousOn (hf : IsCoveringMapOn f s) : ContinuousOn f (f ⁻¹' s) := - ContinuousAt.continuousOn fun _ => hf.continuousAt + continuousOn_of_forall_continuousAt fun _ => hf.continuousAt protected theorem isLocalHomeomorphOn (hf : IsCoveringMapOn f s) : IsLocalHomeomorphOn f (f ⁻¹' s) := by @@ -152,8 +152,11 @@ protected theorem isLocalHomeomorph : IsLocalHomeomorph f := protected theorem isOpenMap : IsOpenMap f := hf.isLocalHomeomorph.isOpenMap -protected theorem quotientMap (hf' : Function.Surjective f) : QuotientMap f := - hf.isOpenMap.to_quotientMap hf.continuous hf' +theorem isQuotientMap (hf' : Function.Surjective f) : IsQuotientMap f := + hf.isOpenMap.isQuotientMap hf.continuous hf' + +@[deprecated (since := "2024-10-22")] +alias quotientMap := isQuotientMap protected theorem isSeparatedMap : IsSeparatedMap f := fun e₁ e₂ he hne ↦ by diff --git a/Mathlib/Topology/Defs/Induced.lean b/Mathlib/Topology/Defs/Induced.lean index 2b89c259917e8..b1e7999bf3ba4 100644 --- a/Mathlib/Topology/Defs/Induced.lean +++ b/Mathlib/Topology/Defs/Induced.lean @@ -22,21 +22,21 @@ as well as topology inducing maps, topological embeddings, and quotient maps. `s : Set Y` is open if the preimage of `s` is open. This is the finest topology that makes `f` continuous. -* `Inducing`: a map `f : X → Y` is called *inducing*, +* `IsInducing`: a map `f : X → Y` is called *inducing*, if the topology on the domain is equal to the induced topology. * `Embedding`: a map `f : X → Y` is an *embedding*, if it is a topology inducing map and it is injective. -* `OpenEmbedding`: a map `f : X → Y` is an *open embedding*, +* `IsOpenEmbedding`: a map `f : X → Y` is an *open embedding*, if it is an embedding and its range is open. An open embedding is an open map. -* `ClosedEmbedding`: a map `f : X → Y` is an *open embedding*, +* `IsClosedEmbedding`: a map `f : X → Y` is an *open embedding*, if it is an embedding and its range is open. An open embedding is an open map. -* `QuotientMap`: a map `f : X → Y` is a *quotient map*, +* `IsQuotientMap`: a map `f : X → Y` is a *quotient map*, if it is surjective and the topology on the codomain is equal to the coinduced topology. -/ @@ -75,7 +75,7 @@ instance _root_.instTopologicalSpaceSubtype {p : X → Prop} [t : TopologicalSpa def coinduced (f : X → Y) (t : TopologicalSpace X) : TopologicalSpace Y where IsOpen s := IsOpen (f ⁻¹' s) isOpen_univ := t.isOpen_univ - isOpen_inter s₁ s₂ h₁ h₂ := h₁.inter h₂ + isOpen_inter _ _ h₁ h₂ := h₁.inter h₂ isOpen_sUnion s h := by simpa only [preimage_sUnion] using isOpen_biUnion h end TopologicalSpace @@ -98,34 +98,47 @@ structure RestrictGenTopology (S : Set (Set X)) : Prop where by the topology on `Y` through `f`, meaning that a set `s : Set X` is open iff it is the preimage under `f` of some open set `t : Set Y`. -/ @[mk_iff] -structure Inducing (f : X → Y) : Prop where +structure IsInducing (f : X → Y) : Prop where /-- The topology on the domain is equal to the induced topology. -/ - induced : tX = tY.induced f + eq_induced : tX = tY.induced f + +@[deprecated (since := "2024-10-28")] alias Inducing := IsInducing /-- A function between topological spaces is an embedding if it is injective, and for all `s : Set X`, `s` is open iff it is the preimage of an open set. -/ @[mk_iff] -structure Embedding [TopologicalSpace X] [TopologicalSpace Y] (f : X → Y) extends - Inducing f : Prop where +structure IsEmbedding (f : X → Y) extends IsInducing f : Prop where /-- A topological embedding is injective. -/ inj : Function.Injective f +@[deprecated (since := "2024-10-26")] +alias Embedding := IsEmbedding + /-- An open embedding is an embedding with open range. -/ @[mk_iff] -structure OpenEmbedding (f : X → Y) extends Embedding f : Prop where +structure IsOpenEmbedding (f : X → Y) extends IsEmbedding f : Prop where /-- The range of an open embedding is an open set. -/ isOpen_range : IsOpen <| range f +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding := IsOpenEmbedding + /-- A closed embedding is an embedding with closed image. -/ @[mk_iff] -structure ClosedEmbedding (f : X → Y) extends Embedding f : Prop where +structure IsClosedEmbedding (f : X → Y) extends IsEmbedding f : Prop where /-- The range of a closed embedding is a closed set. -/ isClosed_range : IsClosed <| range f +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding := IsClosedEmbedding + /-- A function between topological spaces is a quotient map if it is surjective, and for all `s : Set Y`, `s` is open iff its preimage is an open set. -/ -@[mk_iff quotientMap_iff'] -structure QuotientMap {X : Type*} {Y : Type*} [tX : TopologicalSpace X] [tY : TopologicalSpace Y] +@[mk_iff isQuotientMap_iff'] +structure IsQuotientMap {X : Type*} {Y : Type*} [tX : TopologicalSpace X] [tY : TopologicalSpace Y] (f : X → Y) : Prop where surjective : Function.Surjective f eq_coinduced : tY = tX.coinduced f + +@[deprecated (since := "2024-10-22")] +alias QuotientMap := IsQuotientMap diff --git a/Mathlib/Topology/DenseEmbedding.lean b/Mathlib/Topology/DenseEmbedding.lean index 210caa3dca529..aec896b2eef4b 100644 --- a/Mathlib/Topology/DenseEmbedding.lean +++ b/Mathlib/Topology/DenseEmbedding.lean @@ -3,8 +3,8 @@ Copyright (c) 2019 Reid Barton. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ -import Mathlib.Topology.Separation import Mathlib.Topology.Bases +import Mathlib.Topology.Separation.Basic /-! # Dense embeddings @@ -12,8 +12,8 @@ import Mathlib.Topology.Bases This file defines three properties of functions: * `DenseRange f` means `f` has dense image; -* `IsDenseInducing i` means `i` is also `Inducing`, namely it induces the topology on its codomain; -* `IsDenseEmbedding e` means `e` is further an `Embedding`, namely it is injective and `Inducing`. +* `IsDenseInducing i` means `i` is also inducing, namely it induces the topology on its codomain; +* `IsDenseEmbedding e` means `e` is further an embedding, namely it is injective and `Inducing`. The main theorem `continuous_extend` gives a criterion for a function `f : X → Z` to a T₃ space Z to extend along a dense embedding @@ -33,7 +33,7 @@ variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} /-- `i : α → β` is "dense inducing" if it has dense range and the topology on `α` is the one induced by `i` from the topology on `β`. -/ structure IsDenseInducing [TopologicalSpace α] [TopologicalSpace β] (i : α → β) - extends Inducing i : Prop where + extends IsInducing i : Prop where /-- The range of a dense inducing map is a dense set. -/ protected dense : DenseRange i @@ -42,11 +42,13 @@ namespace IsDenseInducing variable [TopologicalSpace α] [TopologicalSpace β] variable {i : α → β} +lemma isInducing (di : IsDenseInducing i) : IsInducing i := di.toIsInducing + theorem nhds_eq_comap (di : IsDenseInducing i) : ∀ a : α, 𝓝 a = comap i (𝓝 <| i a) := - di.toInducing.nhds_eq_comap + di.isInducing.nhds_eq_comap protected theorem continuous (di : IsDenseInducing i) : Continuous i := - di.toInducing.continuous + di.isInducing.continuous theorem closure_range (di : IsDenseInducing i) : closure (range i) = univ := di.dense.closure_range @@ -66,7 +68,7 @@ theorem closure_image_mem_nhds {s : Set α} {a : α} (di : IsDenseInducing i) (h theorem dense_image (di : IsDenseInducing i) {s : Set α} : Dense (i '' s) ↔ Dense s := by refine ⟨fun H x => ?_, di.dense.dense_image di.continuous⟩ - rw [di.toInducing.closure_eq_preimage_closure_image, H.closure_eq, preimage_univ] + rw [di.isInducing.closure_eq_preimage_closure_image, H.closure_eq, preimage_univ] trivial /-- If `i : α → β` is a dense embedding with dense complement of the range, then any compact set in @@ -84,7 +86,7 @@ theorem interior_compact_eq_empty [T2Space β] (di : IsDenseInducing i) (hd : De protected theorem prodMap [TopologicalSpace γ] [TopologicalSpace δ] {e₁ : α → β} {e₂ : γ → δ} (de₁ : IsDenseInducing e₁) (de₂ : IsDenseInducing e₂) : IsDenseInducing (Prod.map e₁ e₂) where - toInducing := de₁.toInducing.prodMap de₂.toInducing + toIsInducing := de₁.isInducing.prodMap de₂.isInducing dense := de₁.dense.prodMap de₂.dense @[deprecated (since := "2024-10-06")] @@ -154,7 +156,7 @@ theorem extend_eq' [T2Space γ] {f : α → γ} (di : IsDenseInducing i) (hf : ∀ b, ∃ c, Tendsto f (comap i (𝓝 b)) (𝓝 c)) (a : α) : di.extend f (i a) = f a := by rcases hf (i a) with ⟨b, hb⟩ refine di.extend_eq_at' b ?_ - rwa [← di.toInducing.nhds_eq_comap] at hb + rwa [← di.isInducing.nhds_eq_comap] at hb theorem extend_unique_at [T2Space γ] {b : β} {f : α → γ} {g : β → γ} (di : IsDenseInducing i) (hf : ∀ᶠ x in comap i (𝓝 b), g (i x) = f x) (hg : ContinuousAt g b) : di.extend f b = g b := by @@ -197,10 +199,10 @@ theorem continuous_extend [T3Space γ] {f : α → γ} (di : IsDenseInducing i) continuous_iff_continuousAt.mpr fun _ => di.continuousAt_extend <| univ_mem' hf theorem mk' (i : α → β) (c : Continuous i) (dense : ∀ x, x ∈ closure (range i)) - (H : ∀ (a : α), ∀ s ∈ 𝓝 a, ∃ t ∈ 𝓝 (i a), ∀ b, i b ∈ t → b ∈ s) : IsDenseInducing i := - { toInducing := inducing_iff_nhds.2 fun a => + (H : ∀ (a : α), ∀ s ∈ 𝓝 a, ∃ t ∈ 𝓝 (i a), ∀ b, i b ∈ t → b ∈ s) : IsDenseInducing i where + toIsInducing := isInducing_iff_nhds.2 fun a => le_antisymm (c.tendsto _).le_comap (by simpa [Filter.le_def] using H a) - dense } + dense := dense end IsDenseInducing @@ -228,9 +230,10 @@ variable {e : α → β} theorem inj_iff (de : IsDenseEmbedding e) {x y} : e x = e y ↔ x = y := de.inj.eq_iff -theorem to_embedding (de : IsDenseEmbedding e) : Embedding e := - { induced := de.induced - inj := de.inj } +theorem isEmbedding (de : IsDenseEmbedding e) : IsEmbedding e where __ := de + +@[deprecated (since := "2024-10-26")] +alias to_embedding := isEmbedding /-- If the domain of a `IsDenseEmbedding` is a separable space, then so is its codomain. -/ protected theorem separableSpace [SeparableSpace α] (de : IsDenseEmbedding e) : SeparableSpace β := @@ -251,23 +254,23 @@ def subtypeEmb {α : Type*} (p : α → Prop) (e : α → β) (x : { x // p x }) ⟨e x, subset_closure <| mem_image_of_mem e x.prop⟩ protected theorem subtype (de : IsDenseEmbedding e) (p : α → Prop) : - IsDenseEmbedding (subtypeEmb p e) := - { dense := - dense_iff_closure_eq.2 <| by - ext ⟨x, hx⟩ - rw [image_eq_range] at hx - simpa [closure_subtype, ← range_comp, (· ∘ ·)] - inj := (de.inj.comp Subtype.coe_injective).codRestrict _ - induced := - (induced_iff_nhds_eq _).2 fun ⟨x, hx⟩ => by - simp [subtypeEmb, nhds_subtype_eq_comap, de.toInducing.nhds_eq_comap, comap_comap, - Function.comp_def] } + IsDenseEmbedding (subtypeEmb p e) where + dense := + dense_iff_closure_eq.2 <| by + ext ⟨x, hx⟩ + rw [image_eq_range] at hx + simpa [closure_subtype, ← range_comp, (· ∘ ·)] + inj := (de.inj.comp Subtype.coe_injective).codRestrict _ + eq_induced := + (induced_iff_nhds_eq _).2 fun ⟨x, hx⟩ => by + simp [subtypeEmb, nhds_subtype_eq_comap, de.isInducing.nhds_eq_comap, comap_comap, + Function.comp_def] theorem dense_image (de : IsDenseEmbedding e) {s : Set α} : Dense (e '' s) ↔ Dense s := de.toIsDenseInducing.dense_image protected lemma id {α : Type*} [TopologicalSpace α] : IsDenseEmbedding (id : α → α) := - { embedding_id with dense := denseRange_id } + { IsEmbedding.id with dense := denseRange_id } end IsDenseEmbedding @@ -276,7 +279,7 @@ alias denseEmbedding_id := IsDenseEmbedding.id theorem Dense.isDenseEmbedding_val [TopologicalSpace α] {s : Set α} (hs : Dense s) : IsDenseEmbedding ((↑) : s → α) := - { embedding_subtype_val with dense := hs.denseRange_val } + { IsEmbedding.subtypeVal with dense := hs.denseRange_val } @[deprecated (since := "2024-09-30")] alias Dense.denseEmbedding_val := Dense.isDenseEmbedding_val @@ -341,7 +344,7 @@ theorem Filter.HasBasis.hasBasis_of_isDenseInducing [TopologicalSpace α] [Topol refine ⟨fun hT => ?_, fun hT => ?_⟩ · obtain ⟨T', hT₁, hT₂, hT₃⟩ := exists_mem_nhds_isClosed_subset hT have hT₄ : f ⁻¹' T' ∈ 𝓝 x := by - rw [hf.toInducing.nhds_eq_comap x] + rw [hf.isInducing.nhds_eq_comap x] exact ⟨T', hT₁, Subset.rfl⟩ obtain ⟨i, hi, hi'⟩ := (h _).mp hT₄ exact diff --git a/Mathlib/Topology/DiscreteQuotient.lean b/Mathlib/Topology/DiscreteQuotient.lean index a6413350f7c54..4048f4765b17f 100644 --- a/Mathlib/Topology/DiscreteQuotient.lean +++ b/Mathlib/Topology/DiscreteQuotient.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Calle Sönne, Adam Topaz -/ import Mathlib.Data.Setoid.Partition -import Mathlib.Topology.Separation import Mathlib.Topology.LocallyConstant.Basic /-! @@ -69,7 +68,7 @@ variable {α X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [Topologic @[ext] -- Porting note: in Lean 4, uses projection to `r` instead of `Setoid`. structure DiscreteQuotient (X : Type*) [TopologicalSpace X] extends Setoid X where /-- For every point `x`, the set `{ y | Rel x y }` is an open set. -/ - protected isOpen_setOf_rel : ∀ x, IsOpen (setOf (toSetoid.Rel x)) + protected isOpen_setOf_rel : ∀ x, IsOpen (setOf (toSetoid x)) namespace DiscreteQuotient @@ -81,13 +80,13 @@ lemma toSetoid_injective : Function.Injective (@toSetoid X _) /-- Construct a discrete quotient from a clopen set. -/ def ofIsClopen {A : Set X} (h : IsClopen A) : DiscreteQuotient X where toSetoid := ⟨fun x y => x ∈ A ↔ y ∈ A, fun _ => Iff.rfl, Iff.symm, Iff.trans⟩ - isOpen_setOf_rel x := by by_cases hx : x ∈ A <;> simp [Setoid.Rel, hx, h.1, h.2, ← compl_setOf] + isOpen_setOf_rel x := by by_cases hx : x ∈ A <;> simp [hx, h.1, h.2, ← compl_setOf] -theorem refl : ∀ x, S.Rel x x := S.refl' +theorem refl : ∀ x, S.toSetoid x x := S.refl' -theorem symm (x y : X) : S.Rel x y → S.Rel y x := S.symm' +theorem symm (x y : X) : S.toSetoid x y → S.toSetoid y x := S.symm' -theorem trans (x y z : X) : S.Rel x y → S.Rel y z → S.Rel x z := S.trans' +theorem trans (x y z : X) : S.toSetoid x y → S.toSetoid y z → S.toSetoid x z := S.trans' /-- The setoid whose quotient yields the discrete quotient. -/ add_decl_doc toSetoid @@ -101,21 +100,24 @@ instance : TopologicalSpace S := /-- The projection from `X` to the given discrete quotient. -/ def proj : X → S := Quotient.mk'' -theorem fiber_eq (x : X) : S.proj ⁻¹' {S.proj x} = setOf (S.Rel x) := +theorem fiber_eq (x : X) : S.proj ⁻¹' {S.proj x} = setOf (S.toSetoid x) := Set.ext fun _ => eq_comm.trans Quotient.eq'' theorem proj_surjective : Function.Surjective S.proj := Quotient.surjective_Quotient_mk'' -theorem proj_quotientMap : QuotientMap S.proj := - quotientMap_quot_mk +theorem proj_isQuotientMap : IsQuotientMap S.proj := + isQuotientMap_quot_mk + +@[deprecated (since := "2024-10-22")] +alias proj_quotientMap := proj_isQuotientMap theorem proj_continuous : Continuous S.proj := - S.proj_quotientMap.continuous + S.proj_isQuotientMap.continuous instance : DiscreteTopology S := singletons_open_iff_discrete.1 <| S.proj_surjective.forall.2 fun x => by - rw [← S.proj_quotientMap.isOpen_preimage, fiber_eq] + rw [← S.proj_isQuotientMap.isOpen_preimage, fiber_eq] exact S.isOpen_setOf_rel _ theorem proj_isLocallyConstant : IsLocallyConstant S.proj := @@ -130,7 +132,7 @@ theorem isOpen_preimage (A : Set S) : IsOpen (S.proj ⁻¹' A) := theorem isClosed_preimage (A : Set S) : IsClosed (S.proj ⁻¹' A) := (S.isClopen_preimage A).1 -theorem isClopen_setOf_rel (x : X) : IsClopen (setOf (S.Rel x)) := by +theorem isClopen_setOf_rel (x : X) : IsClopen (setOf (S.toSetoid x)) := by rw [← fiber_eq] apply isClopen_preimage @@ -182,7 +184,7 @@ variable {A B C : DiscreteQuotient X} /-- The map induced by a refinement of a discrete quotient. -/ def ofLE (h : A ≤ B) : A → B := - Quotient.map' (fun x => x) h + Quotient.map' id h @[simp] theorem ofLE_refl : ofLE (le_refl A) = id := by @@ -359,7 +361,7 @@ lemma comp_finsetClopens [CompactSpace X] : (Set.image (fun (t : Clopens X) ↦ t.carrier) ∘ Finset.toSet) ∘ finsetClopens X = fun ⟨f, _⟩ ↦ f.classes := by ext d - simp only [Setoid.classes, Setoid.Rel, Set.mem_setOf_eq, Function.comp_apply, + simp only [Setoid.classes, Set.mem_setOf_eq, Function.comp_apply, finsetClopens, Set.coe_toFinset, Set.mem_image, Set.mem_range, exists_exists_eq_and] constructor diff --git a/Mathlib/Topology/DiscreteSubset.lean b/Mathlib/Topology/DiscreteSubset.lean index 5238fbf4e8e1e..70e38c4cc3f54 100644 --- a/Mathlib/Topology/DiscreteSubset.lean +++ b/Mathlib/Topology/DiscreteSubset.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash, Bhavik Mehta, Daniel Weber -/ import Mathlib.Topology.Constructions -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Discrete subsets of topological spaces @@ -69,7 +69,7 @@ lemma tendsto_cofinite_cocompact_of_discrete [DiscreteTopology X] lemma IsClosed.tendsto_coe_cofinite_of_discreteTopology {s : Set X} (hs : IsClosed s) (_hs' : DiscreteTopology s) : Tendsto ((↑) : s → X) cofinite (cocompact _) := - tendsto_cofinite_cocompact_of_discrete hs.closedEmbedding_subtype_val.tendsto_cocompact + tendsto_cofinite_cocompact_of_discrete hs.isClosedEmbedding_subtypeVal.tendsto_cocompact lemma IsClosed.tendsto_coe_cofinite_iff [T1Space X] [WeaklyLocallyCompactSpace X] {s : Set X} (hs : IsClosed s) : diff --git a/Mathlib/Topology/EMetricSpace/Basic.lean b/Mathlib/Topology/EMetricSpace/Basic.lean index deca954dd5665..0aba00ba4c0d7 100644 --- a/Mathlib/Topology/EMetricSpace/Basic.lean +++ b/Mathlib/Topology/EMetricSpace/Basic.lean @@ -58,18 +58,21 @@ theorem edist_le_range_sum_of_edist_le {f : ℕ → α} (n : ℕ) {d : ℕ → namespace EMetric -theorem uniformInducing_iff [PseudoEMetricSpace β] {f : α → β} : - UniformInducing f ↔ UniformContinuous f ∧ +theorem isUniformInducing_iff [PseudoEMetricSpace β] {f : α → β} : + IsUniformInducing f ↔ UniformContinuous f ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, edist (f a) (f b) < ε → edist a b < δ := - uniformInducing_iff'.trans <| Iff.rfl.and <| + isUniformInducing_iff'.trans <| Iff.rfl.and <| ((uniformity_basis_edist.comap _).le_basis_iff uniformity_basis_edist).trans <| by simp only [subset_def, Prod.forall]; rfl +@[deprecated (since := "2024-10-05")] +alias uniformInducing_iff := isUniformInducing_iff + /-- ε-δ characterization of uniform embeddings on pseudoemetric spaces -/ nonrec theorem isUniformEmbedding_iff [PseudoEMetricSpace β] {f : α → β} : IsUniformEmbedding f ↔ Function.Injective f ∧ UniformContinuous f ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, edist (f a) (f b) < ε → edist a b < δ := - (isUniformEmbedding_iff _).trans <| and_comm.trans <| Iff.rfl.and uniformInducing_iff + (isUniformEmbedding_iff _).trans <| and_comm.trans <| Iff.rfl.and isUniformInducing_iff @[deprecated (since := "2024-10-01")] alias uniformEmbedding_iff := isUniformEmbedding_iff @@ -77,7 +80,7 @@ alias uniformEmbedding_iff := isUniformEmbedding_iff /-- If a map between pseudoemetric spaces is a uniform embedding then the edistance between `f x` and `f y` is controlled in terms of the distance between `x` and `y`. -In fact, this lemma holds for a `UniformInducing` map. +In fact, this lemma holds for a `IsUniformInducing` map. TODO: generalize? -/ theorem controlled_of_isUniformEmbedding [PseudoEMetricSpace β] {f : α → β} (h : IsUniformEmbedding f) : @@ -242,7 +245,7 @@ theorem EMetric.isUniformEmbedding_iff' [EMetricSpace β] {f : γ → β} : IsUniformEmbedding f ↔ (∀ ε > 0, ∃ δ > 0, ∀ {a b : γ}, edist a b < δ → edist (f a) (f b) < ε) ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : γ}, edist (f a) (f b) < ε → edist a b < δ := by - rw [isUniformEmbedding_iff_uniformInducing, uniformInducing_iff, uniformContinuous_iff] + rw [isUniformEmbedding_iff_isUniformInducing, isUniformInducing_iff, uniformContinuous_iff] @[deprecated (since := "2024-10-01")] alias EMetric.uniformEmbedding_iff' := EMetric.isUniformEmbedding_iff' diff --git a/Mathlib/Topology/EMetricSpace/Defs.lean b/Mathlib/Topology/EMetricSpace/Defs.lean index 2b6096cad74f3..a75f1b0ea7b64 100644 --- a/Mathlib/Topology/EMetricSpace/Defs.lean +++ b/Mathlib/Topology/EMetricSpace/Defs.lean @@ -311,7 +311,7 @@ instance Prod.pseudoEMetricSpaceMax [PseudoEMetricSpace β] : PseudoEMetricSpace edist x y := edist x.1 y.1 ⊔ edist x.2 y.2 edist_self x := by simp edist_comm x y := by simp [edist_comm] - edist_triangle x y z := + edist_triangle _ _ _ := max_le (le_trans (edist_triangle _ _ _) (add_le_add (le_max_left _ _) (le_max_left _ _))) (le_trans (edist_triangle _ _ _) (add_le_add (le_max_right _ _) (le_max_right _ _))) uniformity_edist := uniformity_prod.trans <| by @@ -548,7 +548,7 @@ theorem _root_.TopologicalSpace.IsSeparable.separableSpace {s : Set α} (hs : Is rcases hs.exists_countable_dense_subset with ⟨t, hts, htc, hst⟩ lift t to Set s using hts refine ⟨⟨t, countable_of_injective_of_countable_image Subtype.coe_injective.injOn htc, ?_⟩⟩ - rwa [inducing_subtype_val.dense_iff, Subtype.forall] + rwa [IsInducing.subtypeVal.dense_iff, Subtype.forall] end Compact diff --git a/Mathlib/Topology/EMetricSpace/Paracompact.lean b/Mathlib/Topology/EMetricSpace/Paracompact.lean index f7e7082bc036a..b725de087262c 100644 --- a/Mathlib/Topology/EMetricSpace/Paracompact.lean +++ b/Mathlib/Topology/EMetricSpace/Paracompact.lean @@ -48,14 +48,12 @@ instance (priority := 100) instParacompactSpace [PseudoEMetricSpace α] : Paraco refine ⟨fun ι s ho hcov => ?_⟩ simp only [iUnion_eq_univ_iff] at hcov -- choose a well founded order on `S` - -- Porting note (#11215): TODO: add lemma that claims `∃ i : LinearOrder ι, WellFoundedLT ι` - let _ : LinearOrder ι := by classical exact linearOrderOfSTO WellOrderingRel - have wf : WellFounded ((· < ·) : ι → ι → Prop) := @IsWellFounded.wf ι WellOrderingRel _ + obtain ⟨_, wf⟩ := exists_wellOrder ι -- Let `ind x` be the minimal index `s : S` such that `x ∈ s`. - set ind : α → ι := fun x => wf.min { i : ι | x ∈ s i } (hcov x) - have mem_ind : ∀ x, x ∈ s (ind x) := fun x => wf.min_mem _ (hcov x) + set ind : α → ι := fun x => wellFounded_lt.min { i : ι | x ∈ s i } (hcov x) + have mem_ind : ∀ x, x ∈ s (ind x) := fun x => wellFounded_lt.min_mem _ (hcov x) have nmem_of_lt_ind : ∀ {x i}, i < ind x → x ∉ s i := @fun x i hlt hxi => - wf.not_lt_min _ (hcov x) hxi hlt + wellFounded_lt.not_lt_min _ (hcov x) hxi hlt /- The refinement `D : ℕ → ι → Set α` is defined recursively. For each `n` and `i`, `D n i` is the union of balls `ball x (1 / 2 ^ n)` over all points `x` such that diff --git a/Mathlib/Topology/EMetricSpace/Pi.lean b/Mathlib/Topology/EMetricSpace/Pi.lean index bbf987884575b..4e1672b11e5fb 100644 --- a/Mathlib/Topology/EMetricSpace/Pi.lean +++ b/Mathlib/Topology/EMetricSpace/Pi.lean @@ -59,7 +59,7 @@ spaces. -/ instance pseudoEMetricSpacePi [∀ b, PseudoEMetricSpace (π b)] : PseudoEMetricSpace (∀ b, π b) where edist_self f := bot_unique <| Finset.sup_le <| by simp edist_comm f g := by simp [edist_pi_def, edist_comm] - edist_triangle f g h := edist_pi_le_iff.2 fun b => le_trans (edist_triangle _ (g b) _) + edist_triangle _ g _ := edist_pi_le_iff.2 fun b => le_trans (edist_triangle _ (g b) _) (add_le_add (edist_le_pi_edist _ _ _) (edist_le_pi_edist _ _ _)) toUniformSpace := Pi.uniformSpace _ uniformity_edist := by diff --git a/Mathlib/Topology/ExtendFrom.lean b/Mathlib/Topology/ExtendFrom.lean index 1c043eb2756ea..015142b528778 100644 --- a/Mathlib/Topology/ExtendFrom.lean +++ b/Mathlib/Topology/ExtendFrom.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Anatole Dedecker -/ -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Extending a function from a subset diff --git a/Mathlib/Topology/Exterior.lean b/Mathlib/Topology/Exterior.lean index fcf995f4c441a..8b46e6e2b00e1 100644 --- a/Mathlib/Topology/Exterior.lean +++ b/Mathlib/Topology/Exterior.lean @@ -19,7 +19,7 @@ In this file we prove basic properties of this operation. open Set Filter open scoped Topology -variable {X : Type*} [TopologicalSpace X] {s t : Set X} {x y : X} +variable {ι : Sort*} {X : Type*} [TopologicalSpace X] {s t : Set X} {x y : X} lemma exterior_singleton_eq_ker_nhds (x : X) : exterior {x} = (𝓝 x).ker := by simp [exterior] @@ -49,8 +49,7 @@ lemma IsOpen.exterior_subset (ht : IsOpen t) : exterior s ⊆ t ↔ s ⊆ t := @[deprecated (since := "2024-09-18")] alias IsOpen.exterior_subset_iff := IsOpen.exterior_subset @[simp] -theorem exterior_iUnion {ι : Sort*} (s : ι → Set X) : - exterior (⋃ i, s i) = ⋃ i, exterior (s i) := by +theorem exterior_iUnion (s : ι → Set X) : exterior (⋃ i, s i) = ⋃ i, exterior (s i) := by simp only [exterior, nhdsSet_iUnion, ker_iSup] @[simp] @@ -84,6 +83,15 @@ theorem exterior_eq_exterior_iff_nhdsSet : exterior s = exterior t ↔ 𝓝ˢ s lemma specializes_iff_exterior_subset : x ⤳ y ↔ exterior {x} ⊆ exterior {y} := by simp [Specializes] +theorem exterior_iInter_subset {s : ι → Set X} : exterior (⋂ i, s i) ⊆ ⋂ i, exterior (s i) := + exterior_mono.map_iInf_le + +theorem exterior_inter_subset {s t : Set X} : exterior (s ∩ t) ⊆ exterior s ∩ exterior t := + exterior_mono.map_inf_le _ _ + +theorem exterior_sInter_subset {s : Set (Set X)} : exterior (⋂₀ s) ⊆ ⋂ x ∈ s, exterior x := + exterior_mono.map_sInf_le + @[simp] lemma exterior_empty : exterior (∅ : Set X) = ∅ := isOpen_empty.exterior_eq @[simp] lemma exterior_univ : exterior (univ : Set X) = univ := isOpen_univ.exterior_eq diff --git a/Mathlib/Topology/ExtremallyDisconnected.lean b/Mathlib/Topology/ExtremallyDisconnected.lean index f81a6b4448fd2..78aa72828e83e 100644 --- a/Mathlib/Topology/ExtremallyDisconnected.lean +++ b/Mathlib/Topology/ExtremallyDisconnected.lean @@ -45,7 +45,7 @@ class ExtremallyDisconnected : Prop where theorem extremallyDisconnected_of_homeo {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [ExtremallyDisconnected X] (e : X ≃ₜ Y) : ExtremallyDisconnected Y where open_closure U hU := by - rw [e.symm.inducing.closure_eq_preimage_closure_image, Homeomorph.isOpen_preimage] + rw [e.symm.isInducing.closure_eq_preimage_closure_image, Homeomorph.isOpen_preimage] exact ExtremallyDisconnected.open_closure _ (e.symm.isOpen_image.mpr hU) section TotallySeparated diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean index 39a1e8d2edc2b..1a91fbb11f56c 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -179,7 +179,7 @@ variable [TopologicalSpace B] [TopologicalSpace F] (E : B → Type*) for which the fibers are all homeomorphic to `F`, such that the local situation around each point is a direct product. -/ class FiberBundle where - totalSpaceMk_inducing' : ∀ b : B, Inducing (@TotalSpace.mk B F E b) + totalSpaceMk_isInducing' : ∀ b : B, IsInducing (@TotalSpace.mk B F E b) trivializationAtlas' : Set (Trivialization F (π F E)) trivializationAt' : B → Trivialization F (π F E) mem_baseSet_trivializationAt' : ∀ b : B, b ∈ (trivializationAt' b).baseSet @@ -189,7 +189,9 @@ namespace FiberBundle variable [FiberBundle F E] (b : B) -theorem totalSpaceMk_inducing : Inducing (@TotalSpace.mk B F E b) := totalSpaceMk_inducing' b +theorem totalSpaceMk_isInducing : IsInducing (@TotalSpace.mk B F E b) := totalSpaceMk_isInducing' b + +@[deprecated (since := "2024-10-28")] alias totalSpaceMk_inducing := totalSpaceMk_isInducing /-- Atlas of a fiber bundle. -/ abbrev trivializationAtlas : Set (Trivialization F (π F E)) := trivializationAtlas' @@ -205,7 +207,7 @@ theorem trivialization_mem_atlas : trivializationAt F E b ∈ trivializationAtla end FiberBundle -export FiberBundle (totalSpaceMk_inducing trivializationAtlas trivializationAt +export FiberBundle (totalSpaceMk_isInducing trivializationAtlas trivializationAt mem_baseSet_trivializationAt trivialization_mem_atlas) variable {F} @@ -252,21 +254,30 @@ theorem surjective_proj [Nonempty F] : Function.Surjective (π F E) := fun b => /-- The projection from a fiber bundle with a nonempty fiber to its base is a quotient map. -/ -theorem quotientMap_proj [Nonempty F] : QuotientMap (π F E) := - (isOpenMap_proj F E).to_quotientMap (continuous_proj F E) (surjective_proj F E) +theorem isQuotientMap_proj [Nonempty F] : IsQuotientMap (π F E) := + (isOpenMap_proj F E).isQuotientMap (continuous_proj F E) (surjective_proj F E) + +@[deprecated (since := "2024-10-22")] +alias quotientMap_proj := isQuotientMap_proj theorem continuous_totalSpaceMk (x : B) : Continuous (@TotalSpace.mk B F E x) := - (totalSpaceMk_inducing F E x).continuous + (totalSpaceMk_isInducing F E x).continuous -theorem totalSpaceMk_embedding (x : B) : Embedding (@TotalSpace.mk B F E x) := - ⟨totalSpaceMk_inducing F E x, TotalSpace.mk_injective x⟩ +theorem totalSpaceMk_isEmbedding (x : B) : IsEmbedding (@TotalSpace.mk B F E x) := + ⟨totalSpaceMk_isInducing F E x, TotalSpace.mk_injective x⟩ -theorem totalSpaceMk_closedEmbedding [T1Space B] (x : B) : - ClosedEmbedding (@TotalSpace.mk B F E x) := - ⟨totalSpaceMk_embedding F E x, by +@[deprecated (since := "2024-10-26")] +alias totalSpaceMk_embedding := totalSpaceMk_isEmbedding + +theorem totalSpaceMk_isClosedEmbedding [T1Space B] (x : B) : + IsClosedEmbedding (@TotalSpace.mk B F E x) := + ⟨totalSpaceMk_isEmbedding F E x, by rw [TotalSpace.range_mk] exact isClosed_singleton.preimage <| continuous_proj F E⟩ +@[deprecated (since := "2024-10-20")] +alias totalSpaceMk_closedEmbedding := totalSpaceMk_isClosedEmbedding + variable {E F} @[simp, mfld_simps] @@ -665,17 +676,16 @@ theorem mem_localTrivAt_baseSet (b : B) : b ∈ (Z.localTrivAt b).baseSet := by rw [localTrivAt, ← baseSet_at] exact Z.mem_baseSet_at b --- Porting note (#10618): was @[simp, mfld_simps], now `simp` can prove it theorem mk_mem_localTrivAt_source : (⟨b, a⟩ : Z.TotalSpace) ∈ (Z.localTrivAt b).source := by simp only [mfld_simps] /-- A fiber bundle constructed from core is indeed a fiber bundle. -/ instance fiberBundle : FiberBundle F Z.Fiber where - totalSpaceMk_inducing' b := inducing_iff_nhds.2 fun x ↦ by + totalSpaceMk_isInducing' b := isInducing_iff_nhds.2 fun x ↦ by rw [(Z.localTrivAt b).nhds_eq_comap_inf_principal (mk_mem_localTrivAt_source _ _ _), comap_inf, comap_principal, comap_comap] simp only [Function.comp_def, localTrivAt_apply_mk, Trivialization.coe_coe, - ← (embedding_prod_mk b).nhds_eq_comap] + ← (isEmbedding_prodMk b).nhds_eq_comap] convert_to 𝓝 x = 𝓝 x ⊓ 𝓟 univ · congr exact eq_univ_of_forall (mk_mem_localTrivAt_source Z _) @@ -719,7 +729,7 @@ structure FiberPrebundle where pretrivialization_mem_atlas : ∀ x : B, pretrivializationAt x ∈ pretrivializationAtlas continuous_trivChange : ∀ e, e ∈ pretrivializationAtlas → ∀ e', e' ∈ pretrivializationAtlas → ContinuousOn (e ∘ e'.toPartialEquiv.symm) (e'.target ∩ e'.toPartialEquiv.symm ⁻¹' e.source) - totalSpaceMk_inducing : ∀ b : B, Inducing (pretrivializationAt b ∘ TotalSpace.mk b) + totalSpaceMk_isInducing : ∀ b : B, IsInducing (pretrivializationAt b ∘ TotalSpace.mk b) namespace FiberPrebundle @@ -790,17 +800,16 @@ theorem continuous_totalSpaceMk (b : B) : let e := a.trivializationOfMemPretrivializationAtlas (a.pretrivialization_mem_atlas b) rw [e.toPartialHomeomorph.continuous_iff_continuous_comp_left (a.totalSpaceMk_preimage_source b)] - exact continuous_iff_le_induced.mpr (le_antisymm_iff.mp (a.totalSpaceMk_inducing b).induced).1 + exact continuous_iff_le_induced.2 (a.totalSpaceMk_isInducing b).eq_induced.le theorem inducing_totalSpaceMk_of_inducing_comp (b : B) - (h : Inducing (a.pretrivializationAt b ∘ TotalSpace.mk b)) : - @Inducing _ _ _ a.totalSpaceTopology (TotalSpace.mk b) := by + (h : IsInducing (a.pretrivializationAt b ∘ TotalSpace.mk b)) : + @IsInducing _ _ _ a.totalSpaceTopology (TotalSpace.mk b) := by letI := a.totalSpaceTopology rw [← restrict_comp_codRestrict (a.mem_pretrivializationAt_source b)] at h - apply Inducing.of_codRestrict (a.mem_pretrivializationAt_source b) - refine inducing_of_inducing_compose ?_ (continuousOn_iff_continuous_restrict.mp - (a.trivializationOfMemPretrivializationAtlas - (a.pretrivialization_mem_atlas b)).continuousOn_toFun) h + apply IsInducing.of_codRestrict (a.mem_pretrivializationAt_source b) + refine h.of_comp ?_ (continuousOn_iff_continuous_restrict.mp + (a.trivializationOfMemPretrivializationAtlas (a.pretrivialization_mem_atlas b)).continuousOn) exact (a.continuous_totalSpaceMk b).codRestrict (a.mem_pretrivializationAt_source b) /-- Make a `FiberBundle` from a `FiberPrebundle`. Concretely this means @@ -811,8 +820,8 @@ establishes that for the topology constructed on the sigma-type using "trivializations" (i.e., homeomorphisms with respect to the constructed topology). -/ def toFiberBundle : @FiberBundle B F _ _ E a.totalSpaceTopology _ := let _ := a.totalSpaceTopology - { totalSpaceMk_inducing' := fun b ↦ a.inducing_totalSpaceMk_of_inducing_comp b - (a.totalSpaceMk_inducing b) + { totalSpaceMk_isInducing' := fun b ↦ a.inducing_totalSpaceMk_of_inducing_comp b + (a.totalSpaceMk_isInducing b) trivializationAtlas' := { e | ∃ (e₀ : _) (he₀ : e₀ ∈ a.pretrivializationAtlas), e = a.trivializationOfMemPretrivializationAtlas he₀ }, diff --git a/Mathlib/Topology/FiberBundle/Constructions.lean b/Mathlib/Topology/FiberBundle/Constructions.lean index b5cac2629b8cf..92ca7461c46c4 100644 --- a/Mathlib/Topology/FiberBundle/Constructions.lean +++ b/Mathlib/Topology/FiberBundle/Constructions.lean @@ -43,12 +43,14 @@ instance topologicalSpace [t₁ : TopologicalSpace B] variable [TopologicalSpace B] [TopologicalSpace F] -theorem inducing_toProd : Inducing (TotalSpace.toProd B F) := +theorem isInducing_toProd : IsInducing (TotalSpace.toProd B F) := ⟨by simp only [instTopologicalSpaceProd, induced_inf, induced_compose]; rfl⟩ +@[deprecated (since := "2024-10-28")] alias inducing_toProd := isInducing_toProd + /-- Homeomorphism between the total space of the trivial bundle and the Cartesian product. -/ def homeomorphProd : TotalSpace F (Trivial B F) ≃ₜ B × F := - (TotalSpace.toProd _ _).toHomeomorphOfInducing (inducing_toProd B F) + (TotalSpace.toProd _ _).toHomeomorphOfIsInducing (isInducing_toProd B F) /-- Local trivialization for trivial bundle. -/ def trivialization : Trivialization F (π F (Bundle.Trivial B F)) where @@ -72,8 +74,8 @@ instance fiberBundle : FiberBundle F (Bundle.Trivial B F) where trivializationAt' _ := trivialization B F mem_baseSet_trivializationAt' := mem_univ trivialization_mem_atlas' _ := mem_singleton _ - totalSpaceMk_inducing' _ := (homeomorphProd B F).symm.inducing.comp - (inducing_const_prod.2 inducing_id) + totalSpaceMk_isInducing' _ := (homeomorphProd B F).symm.isInducing.comp + (isInducing_const_prod.2 .id) theorem eq_trivialization (e : Trivialization F (π F (Bundle.Trivial B F))) [i : MemTrivializationAtlas e] : e = trivialization B F := i.out @@ -102,12 +104,15 @@ instance FiberBundle.Prod.topologicalSpace : TopologicalSpace (TotalSpace (F₁ inferInstance /-- The diagonal map from the total space of the fiberwise product of two fiber bundles -`E₁`, `E₂` into `TotalSpace F₁ E₁ × TotalSpace F₂ E₂` is `Inducing`. -/ -theorem FiberBundle.Prod.inducing_diag : - Inducing (fun p ↦ (⟨p.1, p.2.1⟩, ⟨p.1, p.2.2⟩) : +`E₁`, `E₂` into `TotalSpace F₁ E₁ × TotalSpace F₂ E₂` is an inducing map. -/ +theorem FiberBundle.Prod.isInducing_diag : + IsInducing (fun p ↦ (⟨p.1, p.2.1⟩, ⟨p.1, p.2.2⟩) : TotalSpace (F₁ × F₂) (E₁ ×ᵇ E₂) → TotalSpace F₁ E₁ × TotalSpace F₂ E₂) := ⟨rfl⟩ +@[deprecated (since := "2024-10-28")] +alias FiberBundle.Prod.inducing_diag := FiberBundle.Prod.isInducing_diag + end Defs open FiberBundle @@ -135,7 +140,7 @@ theorem Prod.continuous_to_fun : ContinuousOn (Prod.toFun' e₁ e₂) fun p ↦ ((⟨p.1, p.2.1⟩ : TotalSpace F₁ E₁), (⟨p.1, p.2.2⟩ : TotalSpace F₂ E₂)) let f₂ : TotalSpace F₁ E₁ × TotalSpace F₂ E₂ → (B × F₁) × B × F₂ := fun p ↦ ⟨e₁ p.1, e₂ p.2⟩ let f₃ : (B × F₁) × B × F₂ → B × F₁ × F₂ := fun p ↦ ⟨p.1.1, p.1.2, p.2.2⟩ - have hf₁ : Continuous f₁ := (Prod.inducing_diag F₁ E₁ F₂ E₂).continuous + have hf₁ : Continuous f₁ := (Prod.isInducing_diag F₁ E₁ F₂ E₂).continuous have hf₂ : ContinuousOn f₂ (e₁.source ×ˢ e₂.source) := e₁.toPartialHomeomorph.continuousOn.prod_map e₂.toPartialHomeomorph.continuousOn have hf₃ : Continuous f₃ := by fun_prop @@ -174,7 +179,7 @@ theorem Prod.right_inv {x : B × F₁ × F₂} theorem Prod.continuous_inv_fun : ContinuousOn (Prod.invFun' e₁ e₂) ((e₁.baseSet ∩ e₂.baseSet) ×ˢ univ) := by - rw [(Prod.inducing_diag F₁ E₁ F₂ E₂).continuousOn_iff] + rw [(Prod.isInducing_diag F₁ E₁ F₂ E₂).continuousOn_iff] have H₁ : Continuous fun p : B × F₁ × F₂ ↦ ((p.1, p.2.1), (p.1, p.2.2)) := by fun_prop refine (e₁.continuousOn_symm.prod_map e₂.continuousOn_symm).comp H₁.continuousOn ?_ exact fun x h ↦ ⟨⟨h.1.1, mem_univ _⟩, ⟨h.1.2, mem_univ _⟩⟩ @@ -189,13 +194,13 @@ noncomputable def prod : Trivialization (F₁ × F₂) (π (F₁ × F₂) (E₁ invFun := Prod.invFun' e₁ e₂ source := π (F₁ × F₂) (E₁ ×ᵇ E₂) ⁻¹' (e₁.baseSet ∩ e₂.baseSet) target := (e₁.baseSet ∩ e₂.baseSet) ×ˢ Set.univ - map_source' x h := ⟨h, Set.mem_univ _⟩ - map_target' x h := h.1 - left_inv' x := Prod.left_inv - right_inv' x := Prod.right_inv + map_source' _ h := ⟨h, Set.mem_univ _⟩ + map_target' _ h := h.1 + left_inv' _ := Prod.left_inv + right_inv' _ := Prod.right_inv open_source := by convert (e₁.open_source.prod e₂.open_source).preimage - (FiberBundle.Prod.inducing_diag F₁ E₁ F₂ E₂).continuous + (FiberBundle.Prod.isInducing_diag F₁ E₁ F₂ E₂).continuous ext x simp only [Trivialization.source_eq, mfld_simps] open_target := (e₁.open_baseSet.inter e₂.open_baseSet).prod isOpen_univ @@ -205,7 +210,7 @@ noncomputable def prod : Trivialization (F₁ × F₂) (π (F₁ × F₂) (E₁ open_baseSet := e₁.open_baseSet.inter e₂.open_baseSet source_eq := rfl target_eq := rfl - proj_toFun x _ := rfl + proj_toFun _ _ := rfl @[simp] theorem baseSet_prod : (prod e₁ e₂).baseSet = e₁.baseSet ∩ e₂.baseSet := rfl @@ -222,9 +227,9 @@ variable [∀ x, Zero (E₁ x)] [∀ x, Zero (E₂ x)] [∀ x : B, TopologicalSp /-- The product of two fiber bundles is a fiber bundle. -/ noncomputable instance FiberBundle.prod : FiberBundle (F₁ × F₂) (E₁ ×ᵇ E₂) where - totalSpaceMk_inducing' b := by - rw [← (Prod.inducing_diag F₁ E₁ F₂ E₂).of_comp_iff] - exact (totalSpaceMk_inducing F₁ E₁ b).prodMap (totalSpaceMk_inducing F₂ E₂ b) + totalSpaceMk_isInducing' b := by + rw [← (Prod.isInducing_diag F₁ E₁ F₂ E₂).of_comp_iff] + exact (totalSpaceMk_isInducing F₁ E₁ b).prodMap (totalSpaceMk_isInducing F₂ E₂ b) trivializationAtlas' := { e | ∃ (e₁ : Trivialization F₁ (π F₁ E₁)) (e₂ : Trivialization F₂ (π F₂ E₂)) (_ : MemTrivializationAtlas e₁) (_ : MemTrivializationAtlas e₂), @@ -250,11 +255,8 @@ universe u v w₁ w₂ U variable {B : Type u} (F : Type v) (E : B → Type w₁) {B' : Type w₂} (f : B' → B) -instance [∀ x : B, TopologicalSpace (E x)] : ∀ x : B', TopologicalSpace ((f *ᵖ E) x) := by - -- Porting note: Original proof was `delta_instance Bundle.Pullback` - intro x - rw [Bundle.Pullback] - infer_instance +instance [∀ x : B, TopologicalSpace (E x)] : ∀ x : B', TopologicalSpace ((f *ᵖ E) x) := + inferInstanceAs (∀ x, TopologicalSpace (E (f x))) variable [TopologicalSpace B'] [TopologicalSpace (TotalSpace F E)] @@ -277,7 +279,7 @@ theorem Pullback.continuous_lift (f : B' → B) : Continuous (@Pullback.lift B F exact inf_le_right theorem inducing_pullbackTotalSpaceEmbedding (f : B' → B) : - Inducing (@pullbackTotalSpaceEmbedding B F E B' f) := by + IsInducing (@pullbackTotalSpaceEmbedding B F E B' f) := by constructor simp_rw [instTopologicalSpaceProd, induced_inf, induced_compose, Pullback.TotalSpace.topologicalSpace, pullbackTopology_def] @@ -291,7 +293,7 @@ theorem Pullback.continuous_totalSpaceMk [∀ x, TopologicalSpace (E x)] [FiberB {f : B' → B} {x : B'} : Continuous (@TotalSpace.mk _ F (f *ᵖ E) x) := by simp only [continuous_iff_le_induced, Pullback.TotalSpace.topologicalSpace, induced_compose, induced_inf, Function.comp_def, induced_const, top_inf_eq, pullbackTopology_def] - exact le_of_eq (FiberBundle.totalSpaceMk_inducing F E (f x)).induced + exact (FiberBundle.totalSpaceMk_isInducing F E (f x)).eq_induced.le variable {E F} variable [∀ _b, Zero (E _b)] {K : Type U} [FunLike K B' B] [ContinuousMapClass K B' B] @@ -339,13 +341,13 @@ noncomputable def Trivialization.pullback (e : Trivialization F (π F E)) (f : K rw [e.source_eq] rfl target_eq := rfl - proj_toFun y _ := rfl + proj_toFun _ _ := rfl noncomputable instance FiberBundle.pullback [∀ x, TopologicalSpace (E x)] [FiberBundle F E] (f : K) : FiberBundle F ((f : B' → B) *ᵖ E) where - totalSpaceMk_inducing' x := - inducing_of_inducing_compose (Pullback.continuous_totalSpaceMk F E) - (Pullback.continuous_lift F E f) (totalSpaceMk_inducing F E (f x)) + totalSpaceMk_isInducing' x := + (totalSpaceMk_isInducing F E (f x)).of_comp (Pullback.continuous_totalSpaceMk F E) + (Pullback.continuous_lift F E f) trivializationAtlas' := { ef | ∃ (e : Trivialization F (π F E)) (_ : MemTrivializationAtlas e), ef = e.pullback f } trivializationAt' x := (trivializationAt F E (f x)).pullback f diff --git a/Mathlib/Topology/FiberBundle/IsHomeomorphicTrivialBundle.lean b/Mathlib/Topology/FiberBundle/IsHomeomorphicTrivialBundle.lean index 865f13eb7f366..cc38260442348 100644 --- a/Mathlib/Topology/FiberBundle/IsHomeomorphicTrivialBundle.lean +++ b/Mathlib/Topology/FiberBundle/IsHomeomorphicTrivialBundle.lean @@ -52,9 +52,12 @@ protected theorem isOpenMap_proj (h : IsHomeomorphicTrivialFiberBundle F proj) : obtain ⟨e, rfl⟩ := h.proj_eq; exact isOpenMap_fst.comp e.isOpenMap /-- The projection from a trivial fiber bundle to its base is open. -/ -protected theorem quotientMap_proj [Nonempty F] (h : IsHomeomorphicTrivialFiberBundle F proj) : - QuotientMap proj := - h.isOpenMap_proj.to_quotientMap h.continuous_proj h.surjective_proj +protected theorem isQuotientMap_proj [Nonempty F] (h : IsHomeomorphicTrivialFiberBundle F proj) : + IsQuotientMap proj := + h.isOpenMap_proj.isQuotientMap h.continuous_proj h.surjective_proj + +@[deprecated (since := "2024-10-22")] +alias quotientMap_proj := IsHomeomorphicTrivialFiberBundle.isQuotientMap_proj end IsHomeomorphicTrivialFiberBundle diff --git a/Mathlib/Topology/FiberBundle/Trivialization.lean b/Mathlib/Topology/FiberBundle/Trivialization.lean index 87a1362341a73..dfc2f24a5deeb 100644 --- a/Mathlib/Topology/FiberBundle/Trivialization.lean +++ b/Mathlib/Topology/FiberBundle/Trivialization.lean @@ -50,7 +50,7 @@ type of linear trivializations is not even particularly well-behaved. open TopologicalSpace Filter Set Bundle Function open scoped Topology -variable {ι : Type*} {B : Type*} (F : Type*) {E : B → Type*} +variable {B : Type*} (F : Type*) {E : B → Type*} variable {Z : Type*} [TopologicalSpace B] [TopologicalSpace F] {proj : Z → B} /-- This structure contains the information left for a local trivialization (which is implemented @@ -194,7 +194,7 @@ theorem symm_trans_target_eq (e e' : Pretrivialization F proj) : (e.toPartialEquiv.symm.trans e'.toPartialEquiv).target = (e.baseSet ∩ e'.baseSet) ×ˢ univ := by rw [← PartialEquiv.symm_source, symm_trans_symm, symm_trans_source_eq, inter_comm] -variable (e' : Pretrivialization F (π F E)) {x' : TotalSpace F E} {b : B} {y : E b} +variable (e' : Pretrivialization F (π F E)) {b : B} {y : E b} @[simp] theorem coe_mem_source : ↑y ∈ e'.source ↔ b ∈ e'.baseSet := @@ -502,7 +502,7 @@ theorem continuousAt_of_comp_left {X : Type*} [TopologicalSpace X] {f : X → Z} rw [e.source_eq, ← preimage_comp] exact hf_proj.preimage_mem_nhds (e.open_baseSet.mem_nhds he) -variable (e' : Trivialization F (π F E)) {x' : TotalSpace F E} {b : B} {y : E b} +variable (e' : Trivialization F (π F E)) {b : B} {y : E b} protected theorem continuousOn : ContinuousOn e' e'.source := e'.continuousOn_toFun @@ -643,8 +643,6 @@ theorem coordChangeHomeomorph_coe (e₁ e₂ : Trivialization F proj) {b : B} (h (h₂ : b ∈ e₂.baseSet) : ⇑(e₁.coordChangeHomeomorph e₂ h₁ h₂) = e₁.coordChange e₂ b := rfl -variable {B' : Type*} [TopologicalSpace B'] - theorem isImage_preimage_prod (e : Trivialization F proj) (s : Set B) : e.toPartialHomeomorph.IsImage (proj ⁻¹' s) (s ×ˢ univ) := fun x hx => by simp [e.coe_fst', hx] diff --git a/Mathlib/Topology/Filter.lean b/Mathlib/Topology/Filter.lean index 17a22a272b238..f335f5e5dbf47 100644 --- a/Mathlib/Topology/Filter.lean +++ b/Mathlib/Topology/Filter.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Order.Filter.Lift -import Mathlib.Topology.Separation import Mathlib.Order.Interval.Set.Monotone +import Mathlib.Topology.Separation.Basic /-! # Topology on the set of filters on a type @@ -57,7 +57,7 @@ theorem isTopologicalBasis_Iic_principal : { exists_subset_inter := by rintro _ ⟨s, rfl⟩ _ ⟨t, rfl⟩ l hl exact ⟨Iic (𝓟 s) ∩ Iic (𝓟 t), ⟨s ∩ t, by simp⟩, hl, Subset.rfl⟩ - sUnion_eq := sUnion_eq_univ_iff.2 fun l => ⟨Iic ⊤, ⟨univ, congr_arg Iic principal_univ⟩, + sUnion_eq := sUnion_eq_univ_iff.2 fun _ => ⟨Iic ⊤, ⟨univ, congr_arg Iic principal_univ⟩, mem_Iic.2 le_top⟩ eq_generateFrom := rfl } @@ -183,16 +183,18 @@ theorem nhds_nhds (x : X) : 𝓝 (𝓝 x) = ⨅ (s : Set X) (_ : IsOpen s) (_ : x ∈ s), 𝓟 (Iic (𝓟 s)) := by simp only [(nhds_basis_opens x).nhds.eq_biInf, iInf_and, @iInf_comm _ (_ ∈ _)] -theorem inducing_nhds : Inducing (𝓝 : X → Filter X) := - inducing_iff_nhds.2 fun x => +theorem isInducing_nhds : IsInducing (𝓝 : X → Filter X) := + isInducing_iff_nhds.2 fun x => (nhds_def' _).trans <| by simp (config := { contextual := true }) only [nhds_nhds, comap_iInf, comap_principal, Iic_principal, preimage_setOf_eq, ← mem_interior_iff_mem_nhds, setOf_mem_eq, IsOpen.interior_eq] +@[deprecated (since := "2024-10-28")] alias inducing_nhds := isInducing_nhds + @[continuity] theorem continuous_nhds : Continuous (𝓝 : X → Filter X) := - inducing_nhds.continuous + isInducing_nhds.continuous protected theorem Tendsto.nhds {f : α → X} {l : Filter α} {x : X} (h : Tendsto f l (𝓝 x)) : Tendsto (𝓝 ∘ f) l (𝓝 (𝓝 x)) := diff --git a/Mathlib/Topology/GDelta.lean b/Mathlib/Topology/GDelta/Basic.lean similarity index 87% rename from Mathlib/Topology/GDelta.lean rename to Mathlib/Topology/GDelta/Basic.lean index 94a3d1bec4af6..60e2975ce2246 100644 --- a/Mathlib/Topology/GDelta.lean +++ b/Mathlib/Topology/GDelta/Basic.lean @@ -3,8 +3,9 @@ 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, Yury Kudryashov -/ -import Mathlib.Topology.UniformSpace.Basic +import Mathlib.Algebra.Group.Defs import Mathlib.Order.Filter.CountableInter +import Mathlib.Topology.Basic /-! # `Gδ` sets @@ -24,8 +25,7 @@ In this file we define `Gδ` sets and prove their basic properties. ## Main results -We prove that finite or countable intersections of Gδ sets are Gδ sets. We also prove that the -continuity set of a function from a topological space to an (e)metric space is a Gδ set. +We prove that finite or countable intersections of Gδ sets are Gδ sets. - `isClosed_isNowhereDense_iff_compl`: a closed set is nowhere dense iff its complement is open and dense @@ -33,16 +33,19 @@ its complement is open and dense union of nowhere dense sets - subsets of meagre sets are meagre; countable unions of meagre sets are meagre +See `Mathlib.Topology.GDelta.UniformSpace` for the proof that +continuity set of a function from a topological space to a uniform space is a Gδ set. + ## Tags Gδ set, residual set, nowhere dense set, meagre set -/ +assert_not_exists UniformSpace noncomputable section open Topology TopologicalSpace Filter Encodable Set -open scoped Uniformity variable {X Y ι : Type*} {ι' : Sort*} @@ -154,34 +157,8 @@ alias isGδ_biUnion := IsGδ.biUnion theorem IsGδ.iUnion [Finite ι'] {f : ι' → Set X} (h : ∀ i, IsGδ (f i)) : IsGδ (⋃ i, f i) := .sUnion (finite_range _) <| forall_mem_range.2 h -theorem IsClosed.isGδ {X : Type*} [UniformSpace X] [IsCountablyGenerated (𝓤 X)] {s : Set X} - (hs : IsClosed s) : IsGδ s := by - rcases (@uniformity_hasBasis_open X _).exists_antitone_subbasis with ⟨U, hUo, hU, -⟩ - rw [← hs.closure_eq, ← hU.biInter_biUnion_ball] - refine .biInter (to_countable _) fun n _ => IsOpen.isGδ ?_ - exact isOpen_biUnion fun x _ => UniformSpace.isOpen_ball _ (hUo _).2 - end IsGδ -section ContinuousAt - -variable [TopologicalSpace X] - -/-- The set of points where a function is continuous is a Gδ set. -/ -theorem IsGδ.setOf_continuousAt [UniformSpace Y] [IsCountablyGenerated (𝓤 Y)] (f : X → Y) : - IsGδ { x | ContinuousAt f x } := by - obtain ⟨U, _, hU⟩ := (@uniformity_hasBasis_open_symmetric Y _).exists_antitone_subbasis - simp only [Uniform.continuousAt_iff_prod, nhds_prod_eq] - simp only [(nhds_basis_opens _).prod_self.tendsto_iff hU.toHasBasis, forall_prop_of_true, - setOf_forall, id] - refine .iInter fun k ↦ IsOpen.isGδ <| isOpen_iff_mem_nhds.2 fun x ↦ ?_ - rintro ⟨s, ⟨hsx, hso⟩, hsU⟩ - filter_upwards [IsOpen.mem_nhds hso hsx] with _ hy using ⟨s, ⟨hy, hso⟩, hsU⟩ - -@[deprecated (since := "2024-02-15")] alias isGδ_setOf_continuousAt := IsGδ.setOf_continuousAt - -end ContinuousAt - section residual variable [TopologicalSpace X] diff --git a/Mathlib/Topology/GDelta/UniformSpace.lean b/Mathlib/Topology/GDelta/UniformSpace.lean new file mode 100644 index 0000000000000..aa957353a7f05 --- /dev/null +++ b/Mathlib/Topology/GDelta/UniformSpace.lean @@ -0,0 +1,55 @@ +/- +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, Yury Kudryashov +-/ +import Mathlib.Topology.GDelta.Basic +import Mathlib.Topology.UniformSpace.Basic +import Mathlib.Order.Filter.CountableInter + +/-! +# `Gδ` sets and uniform spaces + +## Main results +We prove that the continuity set of a function from a topological space to a uniform space is a +Gδ set. + +-/ + + +noncomputable section + +open Topology TopologicalSpace Filter Encodable Set +open scoped Uniformity + +variable {X Y ι : Type*} {ι' : Sort*} + +section IsGδ + +theorem IsClosed.isGδ {X : Type*} [UniformSpace X] [IsCountablyGenerated (𝓤 X)] {s : Set X} + (hs : IsClosed s) : IsGδ s := by + rcases (@uniformity_hasBasis_open X _).exists_antitone_subbasis with ⟨U, hUo, hU, -⟩ + rw [← hs.closure_eq, ← hU.biInter_biUnion_ball] + refine .biInter (to_countable _) fun n _ => IsOpen.isGδ ?_ + exact isOpen_biUnion fun x _ => UniformSpace.isOpen_ball _ (hUo _).2 + +end IsGδ + +section ContinuousAt + +variable [TopologicalSpace X] + +/-- The set of points where a function is continuous is a Gδ set. -/ +theorem IsGδ.setOf_continuousAt [UniformSpace Y] [IsCountablyGenerated (𝓤 Y)] (f : X → Y) : + IsGδ { x | ContinuousAt f x } := by + obtain ⟨U, _, hU⟩ := (@uniformity_hasBasis_open_symmetric Y _).exists_antitone_subbasis + simp only [Uniform.continuousAt_iff_prod, nhds_prod_eq] + simp only [(nhds_basis_opens _).prod_self.tendsto_iff hU.toHasBasis, forall_prop_of_true, + setOf_forall, id] + refine .iInter fun k ↦ IsOpen.isGδ <| isOpen_iff_mem_nhds.2 fun x ↦ ?_ + rintro ⟨s, ⟨hsx, hso⟩, hsU⟩ + filter_upwards [IsOpen.mem_nhds hso hsx] with _ hy using ⟨s, ⟨hy, hso⟩, hsU⟩ + +@[deprecated (since := "2024-02-15")] alias isGδ_setOf_continuousAt := IsGδ.setOf_continuousAt + +end ContinuousAt diff --git a/Mathlib/Topology/Germ.lean b/Mathlib/Topology/Germ.lean index 5b1e7856f5d62..35d47bcfa9b8a 100644 --- a/Mathlib/Topology/Germ.lean +++ b/Mathlib/Topology/Germ.lean @@ -30,9 +30,6 @@ to the corresponding germ of functions `X → Z` at `x ∈ X` resp. `Y → Z` at `f` is constant. -/ -variable {F G : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] - [NormedAddCommGroup G] [NormedSpace ℝ G] - open scoped Topology open Filter Set diff --git a/Mathlib/Topology/Gluing.lean b/Mathlib/Topology/Gluing.lean index d620e28015df4..65f52bacfc964 100644 --- a/Mathlib/Topology/Gluing.lean +++ b/Mathlib/Topology/Gluing.lean @@ -46,7 +46,7 @@ provided. * `TopCat.GlueData.preimage_range`: The preimage of the image of `U i` in `U j` is `V i j`. * `TopCat.GlueData.preimage_image_eq_image`: The preimage of the image of some `U ⊆ U i` is given by XXX. -* `TopCat.GlueData.ι_openEmbedding`: Each of the `ι i`s are open embeddings. +* `TopCat.GlueData.ι_isOpenEmbedding`: Each of the `ι i`s are open embeddings. -/ @@ -84,8 +84,8 @@ conditions are stated in a less categorical way. -/ -- porting note (#5171): removed @[nolint has_nonempty_instance] structure GlueData extends GlueData TopCat where - f_open : ∀ i j, OpenEmbedding (f i j) - f_mono := fun i j => (TopCat.mono_iff_injective _).mpr (f_open i j).toEmbedding.inj + f_open : ∀ i j, IsOpenEmbedding (f i j) + f_mono i j := (TopCat.mono_iff_injective _).mpr (f_open i j).isEmbedding.inj namespace GlueData @@ -121,8 +121,7 @@ def Rel (a b : Σ i, ((D.U i : TopCat) : Type _)) : Prop := theorem rel_equiv : Equivalence D.Rel := ⟨fun x => Or.inl (refl x), by rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩) - exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, e₂, by erw [← e₁, D.t_inv_apply]⟩], by - -- previous line now `erw` after #13170 + exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, e₂, by rw [← e₁, D.t_inv_apply]⟩], by rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩) · exact id rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩) @@ -167,10 +166,8 @@ theorem eqvGen_of_π_eq let diagram := parallelPair 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap ⋙ forget _ have : colimit.ι diagram one x = colimit.ι diagram one y := by dsimp only [coequalizer.π, ContinuousMap.toFun_eq_coe] at h - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [← ι_preservesColimitsIso_hom, forget_map_eq_coe, types_comp_apply, h] + rw [← ι_preservesColimitIso_hom, forget_map_eq_coe, types_comp_apply, h] simp - rfl have : (colimit.ι diagram _ ≫ colim.map _ ≫ (colimit.isoColimitCocone _).hom) _ = (colimit.ι diagram _ ≫ colim.map _ ≫ (colimit.isoColimitCocone _).hom) _ := @@ -216,8 +213,7 @@ theorem ι_eq_iff_rel (i j : D.J) (x : D.U i) (y : D.U j) : dsimp only at * -- Porting note: there were `subst e₁` and `subst e₂`, instead of the `rw` rw [← e₁, ← e₂] at * - erw [D.glue_condition_apply] -- now `erw` after #13170 - rfl -- now `rfl` after #13170 + rw [D.glue_condition_apply] theorem ι_injective (i : D.J) : Function.Injective (𝖣.ι i) := by intro x y h @@ -240,9 +236,7 @@ theorem image_inter (i j : D.J) : · exact ⟨inv (D.f i i) x₁, by -- porting note (#10745): was `simp [eq₁]` -- See https://github.com/leanprover-community/mathlib4/issues/5026 - rw [TopCat.comp_app] - erw [CategoryTheory.IsIso.inv_hom_id_apply] - rw [eq₁]⟩ + rw [TopCat.comp_app, CategoryTheory.IsIso.inv_hom_id_apply, eq₁]⟩ · -- Porting note: was -- dsimp only at *; substs e₁ eq₁; exact ⟨y, by simp⟩ dsimp only at * @@ -250,7 +244,7 @@ theorem image_inter (i j : D.J) : exact ⟨y, by simp [e₁]⟩ · rintro ⟨x, hx⟩ refine ⟨⟨D.f i j x, hx⟩, ⟨D.f j i (D.t _ _ x), ?_⟩⟩ - erw [D.glue_condition_apply] -- now `erw` after #13170 + rw [D.glue_condition_apply] exact hx theorem preimage_range (i j : D.J) : 𝖣.ι j ⁻¹' Set.range (𝖣.ι i) = Set.range (D.f j i) := by @@ -266,8 +260,7 @@ theorem preimage_image_eq_image (i j : D.J) (U : Set (𝖣.U i)) : generalize 𝖣.ι i '' U = U' -- next 4 lines were `simp` before #13170 simp only [GlueData.diagram_l, GlueData.diagram_r, Set.mem_preimage, coe_comp, Function.comp_apply] - erw [D.glue_condition_apply] - rfl + rw [D.glue_condition_apply] rw [← this, Set.image_preimage_eq_inter_range] symm apply Set.inter_eq_self_of_subset_left @@ -299,10 +292,13 @@ theorem open_image_open (i : D.J) (U : Opens (𝖣.U i)) : IsOpen (𝖣.ι i '' apply (D.t j i ≫ D.f i j).continuous_toFun.isOpen_preimage exact U.isOpen -theorem ι_openEmbedding (i : D.J) : OpenEmbedding (𝖣.ι i) := - openEmbedding_of_continuous_injective_open (𝖣.ι i).continuous_toFun (D.ι_injective i) fun U h => +theorem ι_isOpenEmbedding (i : D.J) : IsOpenEmbedding (𝖣.ι i) := + isOpenEmbedding_of_continuous_injective_open (𝖣.ι i).continuous_toFun (D.ι_injective i) fun U h => D.open_image_open i ⟨U, h⟩ +@[deprecated (since := "2024-10-18")] +alias ι_openEmbedding := ι_isOpenEmbedding + /-- A family of gluing data consists of 1. An index type `J` 2. A bundled topological space `U i` for each `i : J`. @@ -349,10 +345,7 @@ def MkCore.t' (h : MkCore.{u}) (i j k : h.J) : refine ⟨⟨⟨(h.t i j x.1.1).1, ?_⟩, h.t i j x.1.1⟩, rfl⟩ rcases x with ⟨⟨⟨x, hx⟩, ⟨x', hx'⟩⟩, rfl : x = x'⟩ exact h.t_inter _ ⟨x, hx⟩ hx' - -- Porting note: was `continuity`, see https://github.com/leanprover-community/mathlib4/issues/5030 - have : Continuous (h.t i j) := map_continuous (self := ContinuousMap.toContinuousMapClass) _ - set_option tactic.skipAssignedInstances false in - exact ((Continuous.subtype_mk (by fun_prop) _).prod_mk (by fun_prop)).subtype_mk _ + fun_prop /-- This is a constructor of `TopCat.GlueData` whose arguments are in terms of elements and intersections rather than subobjects and pullbacks. Please refer to `TopCat.GlueData.MkCore` for @@ -366,9 +359,9 @@ def mk' (h : MkCore.{u}) : TopCat.GlueData where -- Porting note (#12129): additional beta reduction needed beta_reduce exact (h.V_id i).symm ▸ (Opens.inclusionTopIso (h.U i)).isIso_hom - f_open := fun i j : h.J => (h.V i j).openEmbedding + f_open := fun i j : h.J => (h.V i j).isOpenEmbedding t := h.t - t_id i := by ext; erw [h.t_id]; rfl -- now `erw` after #13170 + t_id i := by ext; rw [h.t_id]; rfl t' := h.t' t_fac i j k := by delta MkCore.t' @@ -383,24 +376,13 @@ def mk' (h : MkCore.{u}) : TopCat.GlueData where simp only [Iso.inv_hom_id_assoc, Category.assoc, Category.id_comp] rw [← Iso.eq_inv_comp, Iso.inv_hom_id] ext1 ⟨⟨⟨x, hx⟩, ⟨x', hx'⟩⟩, rfl : x = x'⟩ - -- The next 9 tactics (up to `convert ...` were a single `rw` before leanprover/lean4#2644 - -- rw [comp_app, ContinuousMap.coe_mk, comp_app, id_app, ContinuousMap.coe_mk, Subtype.mk_eq_mk, - -- Prod.mk.inj_iff, Subtype.mk_eq_mk, Subtype.ext_iff, and_self_iff] - erw [comp_app] --, comp_app, id_app] -- now `erw` after #13170 - -- erw [ContinuousMap.coe_mk] - conv_lhs => erw [ContinuousMap.coe_mk] - erw [id_app] - rw [ContinuousMap.coe_mk] - erw [Subtype.mk_eq_mk] - rw [Prod.mk.inj_iff] - erw [Subtype.mk_eq_mk] - rw [Subtype.ext_iff] - rw [and_self_iff] + rw [comp_app, ContinuousMap.coe_mk, comp_app, id_app, ContinuousMap.coe_mk, Subtype.mk_eq_mk, + Prod.mk.inj_iff, Subtype.mk_eq_mk, Subtype.ext_iff, and_self_iff] convert congr_arg Subtype.val (h.t_inv k i ⟨x, hx'⟩) using 3 refine Subtype.ext ?_ exact h.cocycle i j k ⟨x, hx⟩ hx' -- Porting note: was not necessary in mathlib3 - f_mono i j := (TopCat.mono_iff_injective _).mpr fun x y h => Subtype.ext h + f_mono _ _ := (TopCat.mono_iff_injective _).mpr fun _ _ h => Subtype.ext h variable {α : Type u} [TopologicalSpace α] {J : Type u} (U : J → Opens α) @@ -410,7 +392,7 @@ def ofOpenSubsets : TopCat.GlueData.{u} := mk'.{u} { J U := fun i => (Opens.toTopCat <| TopCat.of α).obj (U i) - V := fun i j => (Opens.map <| Opens.inclusion' _).obj (U j) + 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 ?_ ?_ @@ -421,15 +403,15 @@ def ofOpenSubsets : TopCat.GlueData.{u} := -- Porting note: no longer needed `cases U i`! simp t_id := fun i => by ext; rfl - t_inter := fun i j k x hx => hx - cocycle := fun i j k x h => rfl } + t_inter := fun _ _ _ _ hx => hx + cocycle := fun _ _ _ _ _ => rfl } /-- The canonical map from the glue of a family of open subsets `α` into `α`. -This map is an open embedding (`fromOpenSubsetsGlue_openEmbedding`), +This map is an open embedding (`fromOpenSubsetsGlue_isOpenEmbedding`), and its range is `⋃ i, (U i : Set α)` (`range_fromOpenSubsetsGlue`). -/ def fromOpenSubsetsGlue : (ofOpenSubsets U).toGlueData.glued ⟶ TopCat.of α := - Multicoequalizer.desc _ _ (fun x => Opens.inclusion' _) (by rintro ⟨i, j⟩; ext x; rfl) + Multicoequalizer.desc _ _ (fun _ => Opens.inclusion' _) (by rintro ⟨i, j⟩; ext x; rfl) -- Porting note: `elementwise` here produces a bad lemma, -- where too much has been simplified, despite the `nosimp`. @@ -442,9 +424,8 @@ theorem fromOpenSubsetsGlue_injective : Function.Injective (fromOpenSubsetsGlue intro x y e obtain ⟨i, ⟨x, hx⟩, rfl⟩ := (ofOpenSubsets U).ι_jointly_surjective x obtain ⟨j, ⟨y, hy⟩, rfl⟩ := (ofOpenSubsets U).ι_jointly_surjective y - -- Porting note: now it is `erw`, it was `rw` -- see the porting note on `ι_fromOpenSubsetsGlue` - erw [ι_fromOpenSubsetsGlue_apply, ι_fromOpenSubsetsGlue_apply] at e + rw [ι_fromOpenSubsetsGlue_apply, ι_fromOpenSubsetsGlue_apply] at e change x = y at e subst e rw [(ofOpenSubsets U).ι_eq_iff_rel] @@ -460,31 +441,30 @@ theorem fromOpenSubsetsGlue_isOpenMap : IsOpenMap (fromOpenSubsetsGlue U) := by use fromOpenSubsetsGlue U '' s ∩ Set.range (@Opens.inclusion' (TopCat.of α) (U i)) use Set.inter_subset_left constructor - · erw [← Set.image_preimage_eq_inter_range] - apply (Opens.openEmbedding (X := TopCat.of α) (U i)).isOpenMap + · rw [← Set.image_preimage_eq_inter_range] + 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 exact Set.preimage_image_eq _ (fromOpenSubsetsGlue_injective U) · refine ⟨Set.mem_image_of_mem _ hx, ?_⟩ - -- Porting note: another `rw ↦ erw` - -- See above. - erw [ι_fromOpenSubsetsGlue_apply] + rw [ι_fromOpenSubsetsGlue_apply] exact Set.mem_range_self _ -theorem fromOpenSubsetsGlue_openEmbedding : OpenEmbedding (fromOpenSubsetsGlue U) := - openEmbedding_of_continuous_injective_open (ContinuousMap.continuous_toFun _) +theorem fromOpenSubsetsGlue_isOpenEmbedding : IsOpenEmbedding (fromOpenSubsetsGlue U) := + isOpenEmbedding_of_continuous_injective_open (ContinuousMap.continuous_toFun _) (fromOpenSubsetsGlue_injective U) (fromOpenSubsetsGlue_isOpenMap U) +@[deprecated (since := "2024-10-18")] +alias fromOpenSubsetsGlue_openEmbedding := fromOpenSubsetsGlue_isOpenEmbedding + theorem range_fromOpenSubsetsGlue : Set.range (fromOpenSubsetsGlue U) = ⋃ i, (U i : Set α) := by ext constructor · rintro ⟨x, rfl⟩ obtain ⟨i, ⟨x, hx'⟩, rfl⟩ := (ofOpenSubsets U).ι_jointly_surjective x - -- Porting note: another `rw ↦ erw` - -- See above - erw [ι_fromOpenSubsetsGlue_apply] + rw [ι_fromOpenSubsetsGlue_apply] exact Set.subset_iUnion _ i hx' · rintro ⟨_, ⟨i, rfl⟩, hx⟩ rename_i x diff --git a/Mathlib/Topology/Hom/ContinuousEval.lean b/Mathlib/Topology/Hom/ContinuousEval.lean new file mode 100644 index 0000000000000..7667c58b0d186 --- /dev/null +++ b/Mathlib/Topology/Hom/ContinuousEval.lean @@ -0,0 +1,69 @@ +/- +Copyright (c) 2024 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import Mathlib.Topology.Hom.ContinuousEvalConst +import Mathlib.Topology.ContinuousMap.Defs + +/-! +# Bundled maps with evaluation continuous in both variables + +In this file we define a class `ContinuousEval F X Y` +saying that `F` is a bundled morphism class (in the sense of `FunLike`) +with a topology such that `fun (f, x) : F × X ↦ f x` is a continuous function. +-/ + +open scoped Topology +open Filter + +/-- A typeclass saying that `F` is a bundled morphism class (in the sense of `FunLike`) +with a topology such that `fun (f, x) : F × X ↦ f x` is a continuous function. -/ +class ContinuousEval (F : Type*) (X Y : outParam Type*) [FunLike F X Y] + [TopologicalSpace F] [TopologicalSpace X] [TopologicalSpace Y] : Prop where + /-- Evaluation of a bundled morphism at a point is continuous in both variables. -/ + continuous_eval : Continuous fun fx : F × X ↦ fx.1 fx.2 + +export ContinuousEval (continuous_eval) + +variable {F X Y Z : Type*} [FunLike F X Y] + [TopologicalSpace F] [TopologicalSpace X] [TopologicalSpace Y] [ContinuousEval F X Y] + [TopologicalSpace Z] {f : Z → F} {g : Z → X} {s : Set Z} {z : Z} + +@[continuity, fun_prop] +protected theorem Continuous.eval (hf : Continuous f) (hg : Continuous g) : + Continuous fun z ↦ f z (g z) := + continuous_eval.comp (hf.prod_mk hg) + +/-- If a type `F'` of bundled morphisms admits a continuous projection +to a type satisfying `ContinuousEval`, +then `F'` satisfies this predicate too. + +The word "forget" in the name is motivated by the term "forgetful functor". -/ +theorem ContinuousEval.of_continuous_forget {F' : Type*} [FunLike F' X Y] [TopologicalSpace F'] + {f : F' → F} (hc : Continuous f) (hf : ∀ g, ⇑(f g) = g := by intro; rfl) : + ContinuousEval F' X Y where + continuous_eval := by simpa only [← hf] using hc.fst'.eval continuous_snd + +instance (priority := 100) ContinuousEval.toContinuousMapClass : ContinuousMapClass F X Y where + map_continuous _ := continuous_const.eval continuous_id + +instance (priority := 100) ContinuousEval.toContinuousEvalConst : ContinuousEvalConst F X Y where + continuous_eval_const _ := continuous_id.eval continuous_const + +protected theorem Filter.Tendsto.eval {α : Type*} {l : Filter α} {f : α → F} {f₀ : F} + {g : α → X} {x₀ : X} (hf : Tendsto f l (𝓝 f₀)) (hg : Tendsto g l (𝓝 x₀)) : + Tendsto (fun a ↦ f a (g a)) l (𝓝 (f₀ x₀)) := + (ContinuousEval.continuous_eval.tendsto _).comp (hf.prod_mk_nhds hg) + +protected nonrec theorem ContinuousAt.eval (hf : ContinuousAt f z) (hg : ContinuousAt g z) : + ContinuousAt (fun z ↦ f z (g z)) z := + hf.eval hg + +protected nonrec theorem ContinuousWithinAt.eval (hf : ContinuousWithinAt f s z) + (hg : ContinuousWithinAt g s z) : ContinuousWithinAt (fun z ↦ f z (g z)) s z := + hf.eval hg + +protected theorem ContinuousOn.eval (hf : ContinuousOn f s) (hg : ContinuousOn g s) : + ContinuousOn (fun z ↦ f z (g z)) s := + fun z hz ↦ (hf z hz).eval (hg z hz) diff --git a/Mathlib/Topology/Hom/ContinuousEvalConst.lean b/Mathlib/Topology/Hom/ContinuousEvalConst.lean new file mode 100644 index 0000000000000..6793028a59d88 --- /dev/null +++ b/Mathlib/Topology/Hom/ContinuousEvalConst.lean @@ -0,0 +1,89 @@ +/- +Copyright (c) 2024 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import Mathlib.Topology.Constructions + +/-! +# Bundled morphisms with continuous evaluation at a point + +In this file we define a typeclass +saying that `F` is a type of bundled morphisms (in the sense of `DFunLike`) +with a topology on `F` such that evaluation at a point is continuous in `f : F`. + +## Implementation Notes + +For now, we define the typeclass for non-dependent bundled functions only. +Whenever we add a type of bundled dependent functions with a topology having this property, +we may decide to generalize from `FunLike` to `DFunLike`. +-/ + +open scoped Topology +open Filter + +/-- A typeclass saying that `F` is a type of bundled morphisms (in the sense of `DFunLike`) +with a topology on `F` such that evaluation at a point is continuous in `f : F`. -/ +class ContinuousEvalConst (F : Type*) (α X : outParam Type*) [FunLike F α X] + [TopologicalSpace F] [TopologicalSpace X] : Prop where + continuous_eval_const (x : α) : Continuous fun f : F ↦ f x + +export ContinuousEvalConst (continuous_eval_const) + +section ContinuousEvalConst + +variable {F α X Z : Type*} [FunLike F α X] [TopologicalSpace F] [TopologicalSpace X] + [ContinuousEvalConst F α X] [TopologicalSpace Z] {f : Z → F} {s : Set Z} {z : Z} + +/-- If a type `F'` of bundled morphisms admits a continuous projection +to a type satisfying `ContinuousEvalConst`, +then `F'` satisfies this predicate too. + +The word "forget" in the name is motivated by the term "forgetful functor". -/ +theorem ContinuousEvalConst.of_continuous_forget {F' : Type*} [FunLike F' α X] [TopologicalSpace F'] + {f : F' → F} (hc : Continuous f) (hf : ∀ g, ⇑(f g) = g := by intro; rfl) : + ContinuousEvalConst F' α X where + continuous_eval_const x := by simpa only [← hf] using (continuous_eval_const x).comp hc + +@[continuity, fun_prop] +protected theorem Continuous.eval_const (hf : Continuous f) (x : α) : Continuous (f · x) := + (continuous_eval_const x).comp hf + +theorem continuous_coeFun : Continuous (DFunLike.coe : F → α → X) := + continuous_pi continuous_eval_const + +protected theorem Continuous.coeFun (hf : Continuous f) : Continuous fun z ↦ ⇑(f z) := + continuous_pi hf.eval_const + +protected theorem Filter.Tendsto.eval_const {ι : Type*} {l : Filter ι} {f : ι → F} {g : F} + (hf : Tendsto f l (𝓝 g)) (a : α) : Tendsto (f · a) l (𝓝 (g a)) := + ((continuous_id.eval_const a).tendsto _).comp hf + +protected theorem Filter.Tendsto.coeFun {ι : Type*} {l : Filter ι} {f : ι → F} {g : F} + (hf : Tendsto f l (𝓝 g)) : Tendsto (fun i ↦ ⇑(f i)) l (𝓝 ⇑g) := + (continuous_id.coeFun.tendsto _).comp hf + +protected nonrec theorem ContinuousAt.eval_const (hf : ContinuousAt f z) (x : α) : + ContinuousAt (f · x) z := + hf.eval_const x + +protected nonrec theorem ContinuousAt.coeFun (hf : ContinuousAt f z) : + ContinuousAt (fun z ↦ ⇑(f z)) z := + hf.coeFun + +protected nonrec theorem ContinuousWithinAt.eval_const (hf : ContinuousWithinAt f s z) (x : α) : + ContinuousWithinAt (f · x) s z := + hf.eval_const x + +protected nonrec theorem ContinuousWithinAt.coeFun (hf : ContinuousWithinAt f s z) : + ContinuousWithinAt (fun z ↦ ⇑(f z)) s z := + hf.coeFun + +protected theorem ContinuousOn.eval_const (hf : ContinuousOn f s) (x : α) : + ContinuousOn (f · x) s := + fun z hz ↦ (hf z hz).eval_const x + +protected theorem ContinuousOn.coeFun (hf : ContinuousOn f s) (x : α) : ContinuousOn (f · x) s := + fun z hz ↦ (hf z hz).eval_const x + +end ContinuousEvalConst diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean index 6d33a57317001..17cbd37091ef9 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -60,8 +60,6 @@ instance : EquivLike (X ≃ₜ Y) X Y where right_inv h := h.right_inv coe_injective' _ _ H _ := toEquiv_injective <| DFunLike.ext' H -instance : CoeFun (X ≃ₜ Y) fun _ ↦ X → Y := ⟨DFunLike.coe⟩ - @[simp] theorem homeomorph_mk_coe (a : X ≃ Y) (b c) : (Homeomorph.mk a b c : X → Y) = a := rfl @@ -205,37 +203,45 @@ theorem preimage_image (h : X ≃ₜ Y) (s : Set X) : h ⁻¹' (h '' s) = s := lemma image_compl (h : X ≃ₜ Y) (s : Set X) : h '' (sᶜ) = (h '' s)ᶜ := h.toEquiv.image_compl s -protected theorem inducing (h : X ≃ₜ Y) : Inducing h := - inducing_of_inducing_compose h.continuous h.symm.continuous <| by - simp only [symm_comp_self, inducing_id] +lemma isInducing (h : X ≃ₜ Y) : IsInducing h := + .of_comp h.continuous h.symm.continuous <| by simp only [symm_comp_self, IsInducing.id] + +@[deprecated (since := "2024-10-28")] alias inducing := isInducing -theorem induced_eq (h : X ≃ₜ Y) : TopologicalSpace.induced h ‹_› = ‹_› := - h.inducing.1.symm +theorem induced_eq (h : X ≃ₜ Y) : TopologicalSpace.induced h ‹_› = ‹_› := h.isInducing.1.symm -protected theorem quotientMap (h : X ≃ₜ Y) : QuotientMap h := - QuotientMap.of_quotientMap_compose h.symm.continuous h.continuous <| by - simp only [self_comp_symm, QuotientMap.id] +theorem isQuotientMap (h : X ≃ₜ Y) : IsQuotientMap h := + IsQuotientMap.of_comp h.symm.continuous h.continuous <| by + simp only [self_comp_symm, IsQuotientMap.id] + +@[deprecated (since := "2024-10-22")] +alias quotientMap := isQuotientMap theorem coinduced_eq (h : X ≃ₜ Y) : TopologicalSpace.coinduced h ‹_› = ‹_› := - h.quotientMap.2.symm + h.isQuotientMap.2.symm + +theorem isEmbedding (h : X ≃ₜ Y) : IsEmbedding h := ⟨h.isInducing, h.injective⟩ -protected theorem embedding (h : X ≃ₜ Y) : Embedding h := - ⟨h.inducing, h.injective⟩ +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding /-- Homeomorphism given an embedding. -/ -noncomputable def ofEmbedding (f : X → Y) (hf : Embedding f) : X ≃ₜ Set.range f where +noncomputable def ofIsEmbedding (f : X → Y) (hf : IsEmbedding f) : X ≃ₜ Set.range f where continuous_toFun := hf.continuous.subtype_mk _ continuous_invFun := hf.continuous_iff.2 <| by simp [continuous_subtype_val] toEquiv := Equiv.ofInjective f hf.inj +@[deprecated (since := "2024-10-26")] +alias ofEmbedding := ofIsEmbedding + protected theorem secondCountableTopology [SecondCountableTopology Y] (h : X ≃ₜ Y) : SecondCountableTopology X := - h.inducing.secondCountableTopology + h.isInducing.secondCountableTopology /-- If `h : X → Y` is a homeomorphism, `h(s)` is compact iff `s` is. -/ @[simp] theorem isCompact_image {s : Set X} (h : X ≃ₜ Y) : IsCompact (h '' s) ↔ IsCompact s := - h.embedding.isCompact_iff.symm + h.isEmbedding.isCompact_iff.symm /-- If `h : X → Y` is a homeomorphism, `h⁻¹(s)` is compact iff `s` is. -/ @[simp] @@ -246,7 +252,7 @@ theorem isCompact_preimage {s : Set Y} (h : X ≃ₜ Y) : IsCompact (h ⁻¹' s) @[simp] theorem isSigmaCompact_image {s : Set X} (h : X ≃ₜ Y) : IsSigmaCompact (h '' s) ↔ IsSigmaCompact s := - h.embedding.isSigmaCompact_iff.symm + h.isEmbedding.isSigmaCompact_iff.symm /-- If `h : X → Y` is a homeomorphism, `h⁻¹(s)` is σ-compact iff `s` is. -/ @[simp] @@ -296,27 +302,21 @@ theorem map_cocompact (h : X ≃ₜ Y) : map h (cocompact X) = cocompact Y := by protected theorem compactSpace [CompactSpace X] (h : X ≃ₜ Y) : CompactSpace Y where isCompact_univ := h.symm.isCompact_preimage.2 isCompact_univ -protected theorem t0Space [T0Space X] (h : X ≃ₜ Y) : T0Space Y := - h.symm.embedding.t0Space - -protected theorem t1Space [T1Space X] (h : X ≃ₜ Y) : T1Space Y := - h.symm.embedding.t1Space - -protected theorem t2Space [T2Space X] (h : X ≃ₜ Y) : T2Space Y := - h.symm.embedding.t2Space - -protected theorem t3Space [T3Space X] (h : X ≃ₜ Y) : T3Space Y := - h.symm.embedding.t3Space +protected theorem t0Space [T0Space X] (h : X ≃ₜ Y) : T0Space Y := h.symm.isEmbedding.t0Space +protected theorem t1Space [T1Space X] (h : X ≃ₜ Y) : T1Space Y := h.symm.isEmbedding.t1Space +protected theorem t2Space [T2Space X] (h : X ≃ₜ Y) : T2Space Y := h.symm.isEmbedding.t2Space +protected theorem t25Space [T25Space X] (h : X ≃ₜ Y) : T25Space Y := h.symm.isEmbedding.t25Space +protected theorem t3Space [T3Space X] (h : X ≃ₜ Y) : T3Space Y := h.symm.isEmbedding.t3Space theorem isDenseEmbedding (h : X ≃ₜ Y) : IsDenseEmbedding h := - { h.embedding with dense := h.surjective.denseRange } + { h.isEmbedding with dense := h.surjective.denseRange } @[deprecated (since := "2024-09-30")] alias denseEmbedding := isDenseEmbedding @[simp] theorem isOpen_preimage (h : X ≃ₜ Y) {s : Set Y} : IsOpen (h ⁻¹' s) ↔ IsOpen s := - h.quotientMap.isOpen_preimage + h.isQuotientMap.isOpen_preimage @[simp] theorem isOpen_image (h : X ≃ₜ Y) {s : Set X} : IsOpen (h '' s) ↔ IsOpen s := by @@ -334,17 +334,23 @@ theorem isClosed_image (h : X ≃ₜ Y) {s : Set X} : IsClosed (h '' s) ↔ IsCl protected theorem isClosedMap (h : X ≃ₜ Y) : IsClosedMap h := fun _ => h.isClosed_image.2 -protected theorem openEmbedding (h : X ≃ₜ Y) : OpenEmbedding h := - openEmbedding_of_embedding_open h.embedding h.isOpenMap +theorem isOpenEmbedding (h : X ≃ₜ Y) : IsOpenEmbedding h := + .of_isEmbedding_isOpenMap h.isEmbedding h.isOpenMap -protected theorem closedEmbedding (h : X ≃ₜ Y) : ClosedEmbedding h := - closedEmbedding_of_embedding_closed h.embedding h.isClosedMap +@[deprecated (since := "2024-10-18")] +alias openEmbedding := isOpenEmbedding + +theorem isClosedEmbedding (h : X ≃ₜ Y) : IsClosedEmbedding h := + .of_isEmbedding_isClosedMap h.isEmbedding h.isClosedMap + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding := isClosedEmbedding protected theorem normalSpace [NormalSpace X] (h : X ≃ₜ Y) : NormalSpace Y := - h.symm.closedEmbedding.normalSpace + h.symm.isClosedEmbedding.normalSpace -protected theorem t4Space [T4Space X] (h : X ≃ₜ Y) : T4Space Y := - h.symm.closedEmbedding.t4Space +protected theorem t4Space [T4Space X] (h : X ≃ₜ Y) : T4Space Y := h.symm.isClosedEmbedding.t4Space +protected theorem t5Space [T5Space X] (h : X ≃ₜ Y) : T5Space Y := h.symm.isClosedEmbedding.t5Space theorem preimage_closure (h : X ≃ₜ Y) (s : Set Y) : h ⁻¹' closure s = closure (h ⁻¹' s) := h.isOpenMap.preimage_closure_eq_closure_preimage h.continuous _ @@ -367,22 +373,22 @@ theorem image_frontier (h : X ≃ₜ Y) (s : Set X) : h '' frontier s = frontier @[to_additive] theorem _root_.HasCompactMulSupport.comp_homeomorph {M} [One M] {f : Y → M} (hf : HasCompactMulSupport f) (φ : X ≃ₜ Y) : HasCompactMulSupport (f ∘ φ) := - hf.comp_closedEmbedding φ.closedEmbedding + hf.comp_isClosedEmbedding φ.isClosedEmbedding @[simp] theorem map_nhds_eq (h : X ≃ₜ Y) (x : X) : map h (𝓝 x) = 𝓝 (h x) := - h.embedding.map_nhds_of_mem _ (by simp) + h.isEmbedding.map_nhds_of_mem _ (by simp) @[simp] theorem map_punctured_nhds_eq (h : X ≃ₜ Y) (x : X) : map h (𝓝[≠] x) = 𝓝[≠] (h x) := by - convert h.embedding.map_nhdsWithin_eq ({x}ᶜ) x + convert h.isEmbedding.map_nhdsWithin_eq ({x}ᶜ) x rw [h.image_compl, Set.image_singleton] theorem symm_map_nhds_eq (h : X ≃ₜ Y) (x : X) : map h.symm (𝓝 (h x)) = 𝓝 x := by rw [h.symm.map_nhds_eq, h.symm_apply_apply] theorem nhds_eq_comap (h : X ≃ₜ Y) (x : X) : 𝓝 x = comap h (𝓝 (h x)) := - h.inducing.nhds_eq_comap x + h.isInducing.nhds_eq_comap x @[simp] theorem comap_nhds_eq (h : X ≃ₜ Y) (y : Y) : comap h (𝓝 y) = 𝓝 (h.symm y) := by @@ -403,8 +409,8 @@ theorem locallyConnectedSpace [i : LocallyConnectedSpace Y] (h : X ≃ₜ Y) : the domain is a locally compact space. -/ theorem locallyCompactSpace_iff (h : X ≃ₜ Y) : LocallyCompactSpace X ↔ LocallyCompactSpace Y := by - exact ⟨fun _ => h.symm.openEmbedding.locallyCompactSpace, - fun _ => h.closedEmbedding.locallyCompactSpace⟩ + exact ⟨fun _ => h.symm.isOpenEmbedding.locallyCompactSpace, + fun _ => h.isClosedEmbedding.locallyCompactSpace⟩ /-- If a bijective map `e : X ≃ Y` is continuous and open, then it is a homeomorphism. -/ @[simps toEquiv] @@ -417,6 +423,16 @@ def homeomorphOfContinuousOpen (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpe apply e.image_eq_preimage toEquiv := e +/-- If a bijective map `e : X ≃ Y` is continuous and closed, then it is a homeomorphism. -/ +def homeomorphOfContinuousClosed (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsClosedMap e) : X ≃ₜ Y where + continuous_toFun := h₁ + continuous_invFun := by + rw [continuous_iff_isClosed] + intro s hs + convert ← h₂ s hs using 1 + apply e.image_eq_preimage + toEquiv := e + @[simp] theorem homeomorphOfContinuousOpen_apply (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpenMap e) : ⇑(homeomorphOfContinuousOpen e h₁ h₂) = e := rfl @@ -428,27 +444,27 @@ theorem homeomorphOfContinuousOpen_symm_apply (e : X ≃ Y) (h₁ : Continuous e @[simp] theorem comp_continuousOn_iff (h : X ≃ₜ Y) (f : Z → X) (s : Set Z) : ContinuousOn (h ∘ f) s ↔ ContinuousOn f s := - h.inducing.continuousOn_iff.symm + h.isInducing.continuousOn_iff.symm @[simp] theorem comp_continuous_iff (h : X ≃ₜ Y) {f : Z → X} : Continuous (h ∘ f) ↔ Continuous f := - h.inducing.continuous_iff.symm + h.isInducing.continuous_iff.symm @[simp] theorem comp_continuous_iff' (h : X ≃ₜ Y) {f : Y → Z} : Continuous (f ∘ h) ↔ Continuous f := - h.quotientMap.continuous_iff.symm + h.isQuotientMap.continuous_iff.symm theorem comp_continuousAt_iff (h : X ≃ₜ Y) (f : Z → X) (z : Z) : ContinuousAt (h ∘ f) z ↔ ContinuousAt f z := - h.inducing.continuousAt_iff.symm + h.isInducing.continuousAt_iff.symm theorem comp_continuousAt_iff' (h : X ≃ₜ Y) (f : Y → Z) (x : X) : ContinuousAt (f ∘ h) x ↔ ContinuousAt f (h x) := - h.inducing.continuousAt_iff' (by simp) + h.isInducing.continuousAt_iff' (by simp) theorem comp_continuousWithinAt_iff (h : X ≃ₜ Y) (f : Z → X) (s : Set Z) (z : Z) : ContinuousWithinAt f s z ↔ ContinuousWithinAt (h ∘ f) s z := - h.inducing.continuousWithinAt_iff + h.isInducing.continuousWithinAt_iff @[simp] theorem comp_isOpenMap_iff (h : X ≃ₜ Y) {f : Z → X} : IsOpenMap (h ∘ f) ↔ IsOpenMap f := by @@ -687,6 +703,49 @@ def ulift.{u, v} {X : Type u} [TopologicalSpace X] : ULift.{v, u} X ≃ₜ X whe continuous_invFun := continuous_uLift_up toEquiv := Equiv.ulift +/-- The natural homeomorphism `(ι ⊕ ι' → X) ≃ₜ (ι → X) × (ι' → X)`. +`Equiv.sumArrowEquivProdArrow` as a homeomorphism. -/ +@[simps!] +def sumArrowHomeomorphProdArrow {ι ι' : Type*} : (ι ⊕ ι' → X) ≃ₜ (ι → X) × (ι' → X) where + toEquiv := Equiv.sumArrowEquivProdArrow _ _ _ + continuous_toFun := by + simp only [Equiv.sumArrowEquivProdArrow, Equiv.coe_fn_mk, continuous_prod_mk] + continuity + continuous_invFun := continuous_pi fun i ↦ match i with + | .inl i => by apply (continuous_apply _).comp' continuous_fst + | .inr i => by apply (continuous_apply _).comp' continuous_snd + +private theorem _root_.Fin.appendEquiv_eq_Homeomorph (m n : ℕ) : Fin.appendEquiv m n = + ((sumArrowHomeomorphProdArrow).symm.trans + (piCongrLeft (Y := fun _ ↦ X) finSumFinEquiv)).toEquiv := by + ext ⟨x1, x2⟩ l + simp only [sumArrowHomeomorphProdArrow, Equiv.sumArrowEquivProdArrow, + finSumFinEquiv, Fin.addCases, Fin.appendEquiv, Fin.append, Equiv.coe_fn_mk] + by_cases h : l < m + · simp [h] + · simp [h] + +theorem _root_.Fin.continuous_append (m n : ℕ) : + Continuous fun (p : (Fin m → X) × (Fin n → X)) ↦ Fin.append p.1 p.2 := by + suffices Continuous (Fin.appendEquiv m n) by exact this + rw [Fin.appendEquiv_eq_Homeomorph] + exact Homeomorph.continuous_toFun _ + +/-- The natural homeomorphism between `(Fin m → X) × (Fin n → X)` and `Fin (m + n) → X`. +`Fin.appendEquiv` as a homeomorphism.-/ +@[simps!] +def _root_.Fin.appendHomeomorph (m n : ℕ) : (Fin m → X) × (Fin n → X) ≃ₜ (Fin (m + n) → X) where + toEquiv := Fin.appendEquiv m n + continuous_toFun := Fin.continuous_append m n + continuous_invFun := by + rw [Fin.appendEquiv_eq_Homeomorph] + exact Homeomorph.continuous_invFun _ + +@[simp] +theorem _root_.Fin.appendHomeomorph_toEquiv (m n : ℕ) : + (Fin.appendHomeomorph (X := X) m n).toEquiv = Fin.appendEquiv m n := + rfl + section Distrib /-- `(X ⊕ Y) × Z` is homeomorphic to `X × Z ⊕ Y × Z`. -/ @@ -811,7 +870,7 @@ variable {Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace @[simps toEquiv] def toHomeomorph (e : X ≃ Y) (he : ∀ s, IsOpen (e ⁻¹' s) ↔ IsOpen s) : X ≃ₜ Y where toEquiv := e - continuous_toFun := continuous_def.2 fun s ↦ (he _).2 + continuous_toFun := continuous_def.2 fun _ ↦ (he _).2 continuous_invFun := continuous_def.2 fun s ↦ by convert (he _).1; simp @[simp] lemma coe_toHomeomorph (e : X ≃ Y) (he) : ⇑(e.toHomeomorph he) = e := rfl @@ -829,11 +888,13 @@ lemma toHomeomorph_trans (e : X ≃ Y) (f : Y ≃ Z) (he hf) : /-- An inducing equiv between topological spaces is a homeomorphism. -/ @[simps toEquiv] -- Porting note (#11215): TODO: was `@[simps]` -def toHomeomorphOfInducing (f : X ≃ Y) (hf : Inducing f) : X ≃ₜ Y := +def toHomeomorphOfIsInducing (f : X ≃ Y) (hf : IsInducing f) : X ≃ₜ Y := { f with continuous_toFun := hf.continuous continuous_invFun := hf.continuous_iff.2 <| by simpa using continuous_id } +@[deprecated (since := "2024-10-28")] alias toHomeomorphOfInducing := toHomeomorphOfIsInducing + end Equiv namespace Continuous @@ -897,13 +958,25 @@ noncomputable def homeomorph : X ≃ₜ Y where toEquiv := Equiv.ofBijective f hf.bijective protected lemma isClosedMap : IsClosedMap f := (hf.homeomorph f).isClosedMap -protected lemma inducing : Inducing f := (hf.homeomorph f).inducing -protected lemma quotientMap : QuotientMap f := (hf.homeomorph f).quotientMap -protected lemma embedding : Embedding f := (hf.homeomorph f).embedding -protected lemma openEmbedding : OpenEmbedding f := (hf.homeomorph f).openEmbedding -protected lemma closedEmbedding : ClosedEmbedding f := (hf.homeomorph f).closedEmbedding +lemma isInducing : IsInducing f := (hf.homeomorph f).isInducing +lemma isQuotientMap : IsQuotientMap f := (hf.homeomorph f).isQuotientMap +lemma isEmbedding : IsEmbedding f := (hf.homeomorph f).isEmbedding +lemma isOpenEmbedding : IsOpenEmbedding f := (hf.homeomorph f).isOpenEmbedding +lemma isClosedEmbedding : IsClosedEmbedding f := (hf.homeomorph f).isClosedEmbedding lemma isDenseEmbedding : IsDenseEmbedding f := (hf.homeomorph f).isDenseEmbedding +@[deprecated (since := "2024-10-28")] alias inducing := isInducing + +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding + +@[deprecated (since := "2024-10-22")] +alias quotientMap := isQuotientMap + +@[deprecated (since := "2024-10-20")] alias closedEmbedding := isClosedEmbedding +@[deprecated (since := "2024-10-18")] +alias openEmbedding := isOpenEmbedding + @[deprecated (since := "2024-09-30")] alias denseEmbedding := isDenseEmbedding @@ -922,11 +995,14 @@ lemma isHomeomorph_iff_exists_inverse : IsHomeomorph f ↔ Continuous f ∧ ∃ · exact (Homeomorph.mk ⟨f, g, hg.1, hg.2.1⟩ hf hg.2.2).isHomeomorph /-- A map is a homeomorphism iff it is a surjective embedding. -/ -lemma isHomeomorph_iff_embedding_surjective : IsHomeomorph f ↔ Embedding f ∧ Surjective f where - mp hf := ⟨hf.embedding, hf.surjective⟩ - mpr h := ⟨h.1.continuous, ((openEmbedding_iff f).2 ⟨h.1, h.2.range_eq ▸ isOpen_univ⟩).isOpenMap, +lemma isHomeomorph_iff_isEmbedding_surjective : IsHomeomorph f ↔ IsEmbedding f ∧ Surjective f where + mp hf := ⟨hf.isEmbedding, hf.surjective⟩ + mpr h := ⟨h.1.continuous, ((isOpenEmbedding_iff f).2 ⟨h.1, h.2.range_eq ▸ isOpen_univ⟩).isOpenMap, h.1.inj, h.2⟩ +@[deprecated (since := "2024-10-26")] +alias isHomeomorph_iff_embedding_surjective := isHomeomorph_iff_isEmbedding_surjective + /-- A map is a homeomorphism iff it is continuous, closed and bijective. -/ lemma isHomeomorph_iff_continuous_isClosedMap_bijective : IsHomeomorph f ↔ Continuous f ∧ IsClosedMap f ∧ Function.Bijective f := @@ -956,8 +1032,8 @@ lemma IsHomeomorph.sigmaMap {ι κ : Type*} {X : ι → Type*} {Y : κ → Type* [∀ i, TopologicalSpace (X i)] [∀ i, TopologicalSpace (Y i)] {f : ι → κ} (hf : Bijective f) {g : (i : ι) → X i → Y (f i)} (hg : ∀ i, IsHomeomorph (g i)) : IsHomeomorph (Sigma.map f g) := by - simp_rw [isHomeomorph_iff_embedding_surjective,] at hg ⊢ - exact ⟨(embedding_sigma_map hf.1).2 fun i ↦ (hg i).1, hf.2.sigma_map fun i ↦ (hg i).2⟩ + simp_rw [isHomeomorph_iff_isEmbedding_surjective,] at hg ⊢ + exact ⟨(isEmbedding_sigmaMap hf.1).2 fun i ↦ (hg i).1, hf.2.sigma_map fun i ↦ (hg i).2⟩ lemma IsHomeomorph.pi_map {ι : Type*} {X Y : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, TopologicalSpace (Y i)] {f : (i : ι) → X i → Y i} (h : ∀ i, IsHomeomorph (f i)) : diff --git a/Mathlib/Topology/Homotopy/Contractible.lean b/Mathlib/Topology/Homotopy/Contractible.lean index 34bf5c1a00185..42461b28209d2 100644 --- a/Mathlib/Topology/Homotopy/Contractible.lean +++ b/Mathlib/Topology/Homotopy/Contractible.lean @@ -91,9 +91,9 @@ protected theorem Homeomorph.contractibleSpace_iff (e : X ≃ₜ Y) : namespace ContractibleSpace -instance [Unique Y] : ContractibleSpace Y := by - have : ContractibleSpace (Unit) := ⟨⟨HomotopyEquiv.refl Unit⟩⟩ - apply (Homeomorph.homeomorphOfUnique Y Unit).contractibleSpace +instance [Nonempty Y] [Subsingleton Y] : ContractibleSpace Y := + let ⟨_⟩ := nonempty_unique Y + ⟨⟨(Homeomorph.homeomorphOfUnique Y Unit).toHomotopyEquiv⟩⟩ variable (X Y) in theorem hequiv [ContractibleSpace X] [ContractibleSpace Y] : diff --git a/Mathlib/Topology/Homotopy/HSpaces.lean b/Mathlib/Topology/Homotopy/HSpaces.lean index 15648773fa822..fba0212ad88f5 100644 --- a/Mathlib/Topology/Homotopy/HSpaces.lean +++ b/Mathlib/Topology/Homotopy/HSpaces.lean @@ -163,7 +163,7 @@ def qRight (p : I × I) : I := theorem continuous_qRight : Continuous qRight := continuous_projIcc.comp <| - Continuous.div (by fun_prop) (by fun_prop) fun x ↦ (add_pos zero_lt_one).ne' + Continuous.div (by fun_prop) (by fun_prop) fun _ ↦ (add_pos zero_lt_one).ne' theorem qRight_zero_left (θ : I) : qRight (0, θ) = 0 := Set.projIcc_of_le_left _ <| by simp only [coe_zero, mul_zero, zero_div, le_refl] @@ -212,7 +212,7 @@ def delayReflRight (θ : I) (γ : Path x y) : Path x y where theorem continuous_delayReflRight : Continuous fun p : I × Path x y => delayReflRight p.1 p.2 := continuous_uncurry_iff.mp <| - (continuous_snd.comp continuous_fst).path_eval <| + (continuous_snd.comp continuous_fst).eval <| continuous_qRight.comp <| continuous_snd.prod_mk <| continuous_fst.comp continuous_fst theorem delayReflRight_zero (γ : Path x y) : delayReflRight 0 γ = γ.trans (Path.refl y) := by diff --git a/Mathlib/Topology/Homotopy/HomotopyGroup.lean b/Mathlib/Topology/Homotopy/HomotopyGroup.lean index daaa41db02500..65ce882fec5b0 100644 --- a/Mathlib/Topology/Homotopy/HomotopyGroup.lean +++ b/Mathlib/Topology/Homotopy/HomotopyGroup.lean @@ -111,6 +111,11 @@ theorem ext (f g : Ω^ N X x) (H : ∀ y, f y = g y) : f = g := theorem mk_apply (f : C(I^N, X)) (H y) : (⟨f, H⟩ : Ω^ N X x) y = f y := rfl +instance instContinuousEval : ContinuousEval (Ω^ N X x) (I^N) X := + .of_continuous_forget continuous_subtype_val + +instance instContinuousEvalConst : ContinuousEvalConst (Ω^ N X x) (I^N) X := inferInstance + /-- Copy of a `GenLoop` with a new map from the unit cube equal to the old one. Useful to fix definitional equalities. -/ def copy (f : Ω^ N X x) (g : (I^N) → X) (h : g = f) : Ω^ N X x := @@ -175,7 +180,7 @@ variable [DecidableEq N] @[simps] def toLoop (i : N) (p : Ω^ N X x) : Ω (Ω^ { j // j ≠ i } X x) const where toFun t := - ⟨(p.val.comp (Cube.insertAt i).toContinuousMap).curry t, fun y yH => + ⟨(p.val.comp (Cube.insertAt i)).curry t, fun y yH => p.property (Cube.insertAt i (t, y)) (Cube.insertAt_boundary i <| Or.inr yH)⟩ source' := by ext t; refine p.property (Cube.insertAt i (0, t)) ⟨i, Or.inl ?_⟩; simp target' := by ext t; refine p.property (Cube.insertAt i (1, t)) ⟨i, Or.inr ?_⟩; simp @@ -184,10 +189,10 @@ def toLoop (i : N) (p : Ω^ N X x) : Ω (Ω^ { j // j ≠ i } X x) const where theorem continuous_toLoop (i : N) : Continuous (@toLoop N X _ x _ i) := Path.continuous_uncurry_iff.1 <| Continuous.subtype_mk - (ContinuousMap.continuous_eval.comp <| + (continuous_eval.comp <| Continuous.prodMap (ContinuousMap.continuous_curry.comp <| - (ContinuousMap.continuous_comp_left _).comp continuous_subtype_val) + (ContinuousMap.continuous_precomp _).comp continuous_subtype_val) continuous_id) _ @@ -195,10 +200,10 @@ theorem continuous_toLoop (i : N) : Continuous (@toLoop N X _ x _ i) := @[simps] def fromLoop (i : N) (p : Ω (Ω^ { j // j ≠ i } X x) const) : Ω^ N X x := ⟨(ContinuousMap.comp ⟨Subtype.val, by fun_prop⟩ p.toContinuousMap).uncurry.comp - (Cube.splitAt i).toContinuousMap, + (Cube.splitAt i), by rintro y ⟨j, Hj⟩ - simp only [ContinuousMap.comp_apply, toContinuousMap_apply, + simp only [ContinuousMap.comp_apply, ContinuousMap.coe_coe, funSplitAt_apply, ContinuousMap.uncurry_apply, ContinuousMap.coe_mk, Function.uncurry_apply_pair] obtain rfl | Hne := eq_or_ne j i @@ -206,9 +211,9 @@ def fromLoop (i : N) (p : Ω (Ω^ { j // j ≠ i } X x) const) : Ω^ N X x := · exact GenLoop.boundary _ _ ⟨⟨j, Hne⟩, Hj⟩⟩ theorem continuous_fromLoop (i : N) : Continuous (@fromLoop N X _ x _ i) := - ((ContinuousMap.continuous_comp_left _).comp <| + ((ContinuousMap.continuous_precomp _).comp <| ContinuousMap.continuous_uncurry.comp <| - (ContinuousMap.continuous_comp _).comp continuous_induced_dom).subtype_mk + (ContinuousMap.continuous_postcomp _).comp continuous_induced_dom).subtype_mk _ theorem to_from (i : N) (p : Ω (Ω^ { j // j ≠ i } X x) const) : toLoop i (fromLoop i p) = p := by @@ -238,8 +243,8 @@ theorem fromLoop_apply (i : N) {p : Ω (Ω^ { j // j ≠ i } X x) const} {t : I^ /-- Composition with `Cube.insertAt` as a continuous map. -/ abbrev cCompInsert (i : N) : C(C(I^N, X), C(I × I^{ j // j ≠ i }, X)) := - ⟨fun f => f.comp (Cube.insertAt i).toContinuousMap, - (Cube.insertAt i).toContinuousMap.continuous_comp_left⟩ + ⟨fun f => f.comp (Cube.insertAt i), + (toContinuousMap <| Cube.insertAt i).continuous_precomp⟩ /-- A homotopy between `n+1`-dimensional loops `p` and `q` constant on the boundary seen as a homotopy between two paths in the space of `n`-dimensional paths. -/ @@ -248,7 +253,7 @@ def homotopyTo (i : N) {p q : Ω^ N X x} (H : p.1.HomotopyRel q.1 (Cube.boundary ((⟨_, ContinuousMap.continuous_curry⟩ : C(_, _)).comp <| (cCompInsert i).comp H.toContinuousMap.curry).uncurry --- porting note (#11083): `@[simps]` no longer too slow in Lean 4 but does not generate this lemma. +-- porting note: `@[simps]` generates this lemma but it's named `homotopyTo_apply_apply` instead theorem homotopyTo_apply (i : N) {p q : Ω^ N X x} (H : p.1.HomotopyRel q.1 <| Cube.boundary N) (t : I × I) (tₙ : I^{ j // j ≠ i }) : homotopyTo i H t tₙ = H (t.fst, Cube.insertAt i (t.snd, tₙ)) := @@ -275,8 +280,7 @@ theorem homotopicTo (i : N) {p q : Ω^ N X x} : C(I × I^N, X) := (ContinuousMap.comp ⟨_, ContinuousMap.continuous_uncurry⟩ (ContinuousMap.comp ⟨Subtype.val, by continuity⟩ H.toContinuousMap).curry).uncurry.comp <| - (ContinuousMap.id I).prodMap (Cube.splitAt i).toContinuousMap --- porting note (#11083): @[simps!] no longer too slow in Lean 4. + (ContinuousMap.id I).prodMap (Cube.splitAt i) theorem homotopicFrom (i : N) {p q : Ω^ N X x} : (toLoop i p).Homotopic (toLoop i q) → Homotopic p q := by @@ -285,15 +289,14 @@ theorem homotopicFrom (i : N) {p q : Ω^ N X x} : · rintro t y ⟨j, jH⟩ erw [homotopyFrom_apply] obtain rfl | h := eq_or_ne j i - · simp only [Prod.map_apply, id_eq, toContinuousMap_apply, funSplitAt_apply, - Function.uncurry_apply_pair] + · simp only [Prod.map_apply, id_eq, funSplitAt_apply, Function.uncurry_apply_pair] rw [H.eq_fst] exacts [congr_arg p ((Cube.splitAt j).left_inv _), jH] · rw [p.2 _ ⟨j, jH⟩]; apply boundary; exact ⟨⟨j, h⟩, jH⟩ all_goals intro apply (homotopyFrom_apply _ _ _).trans - simp only [Prod.map_apply, id_eq, toContinuousMap_apply, funSplitAt_apply, + simp only [Prod.map_apply, id_eq, funSplitAt_apply, Function.uncurry_apply_pair, ContinuousMap.HomotopyWith.apply_zero, ContinuousMap.HomotopyWith.apply_one, ne_eq, Path.coe_toContinuousMap, toLoop_apply_coe, ContinuousMap.curry_apply, ContinuousMap.comp_apply] @@ -311,7 +314,7 @@ def transAt (i : N) (f g : Ω^ N X x) : Ω^ N X x := (by ext1; symm dsimp only [Path.trans, fromLoop, Path.coe_mk_mk, Function.comp_apply, mk_apply, - ContinuousMap.comp_apply, toContinuousMap_apply, funSplitAt_apply, + ContinuousMap.comp_apply, ContinuousMap.coe_coe, funSplitAt_apply, ContinuousMap.uncurry_apply, ContinuousMap.coe_mk, Function.uncurry_apply_pair] split_ifs · show f _ = _; congr 1 @@ -373,7 +376,6 @@ def genLoopHomeoOfIsEmpty (N x) [IsEmpty N] : Ω^ N X x ≃ₜ X where invFun y := ⟨ContinuousMap.const _ y, fun _ ⟨i, _⟩ => isEmptyElim i⟩ left_inv f := by ext; exact congr_arg f (Subsingleton.elim _ _) right_inv _ := rfl - continuous_toFun := (ContinuousMap.continuous_eval_const (0 : N → I)).comp continuous_induced_dom continuous_invFun := ContinuousMap.const'.2.subtype_mk _ /-- The homotopy "group" indexed by an empty type is in bijection with diff --git a/Mathlib/Topology/Homotopy/Path.lean b/Mathlib/Topology/Homotopy/Path.lean index 254ed2b7f70dc..a5ad060e6071e 100644 --- a/Mathlib/Topology/Homotopy/Path.lean +++ b/Mathlib/Topology/Homotopy/Path.lean @@ -188,15 +188,7 @@ def reparam (p : Path x₀ x₁) (f : I → I) (hf : Continuous f) (hf₀ : f 0 · rw [Set.mem_singleton_iff] at hx rw [hx] simp [hf₁] - continuous_toFun := by - -- Porting note: was `continuity` in auto-param - refine continuous_const.path_eval ?_ - apply Continuous.subtype_mk - apply Continuous.add <;> apply Continuous.mul - · exact continuous_induced_dom.comp (unitInterval.continuous_symm.comp continuous_fst) - · continuity - · continuity - · continuity + continuous_toFun := by fun_prop /-- Suppose `F : Homotopy p q`. Then we have a `Homotopy p.symm q.symm` by reversing the second argument. diff --git a/Mathlib/Topology/Homotopy/Product.lean b/Mathlib/Topology/Homotopy/Product.lean index a898bde525861..cc848a691b504 100644 --- a/Mathlib/Topology/Homotopy/Product.lean +++ b/Mathlib/Topology/Homotopy/Product.lean @@ -72,7 +72,7 @@ def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) : prop' := by intro t x hx dsimp only [coe_mk, pi_eval, toFun_eq_coe, HomotopyWith.coe_toContinuousMap] - simp only [Function.funext_iff, ← forall_and] + simp only [funext_iff, ← forall_and] intro i exact (homotopies i).prop' t x hx } diff --git a/Mathlib/Topology/IndicatorConstPointwise.lean b/Mathlib/Topology/IndicatorConstPointwise.lean index c1f6ad354e8ff..deb980b52a7e8 100644 --- a/Mathlib/Topology/IndicatorConstPointwise.lean +++ b/Mathlib/Topology/IndicatorConstPointwise.lean @@ -3,7 +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.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Pointwise convergence of indicator functions diff --git a/Mathlib/Topology/Inseparable.lean b/Mathlib/Topology/Inseparable.lean index a179072f0d072..c0065281d89e6 100644 --- a/Mathlib/Topology/Inseparable.lean +++ b/Mathlib/Topology/Inseparable.lean @@ -132,6 +132,8 @@ theorem Specializes.trans : x ⤳ y → y ⤳ z → x ⤳ z := theorem specializes_of_eq (e : x = y) : x ⤳ y := e ▸ specializes_refl x +alias Specializes.of_eq := specializes_of_eq + theorem specializes_of_nhdsWithin (h₁ : 𝓝[s] x ≤ 𝓝[s] y) (h₂ : x ∈ s) : x ⤳ y := specializes_iff_pure.2 <| calc @@ -146,12 +148,14 @@ theorem Specializes.map_of_continuousAt (h : x ⤳ y) (hy : ContinuousAt f y) : theorem Specializes.map (h : x ⤳ y) (hf : Continuous f) : f x ⤳ f y := h.map_of_continuousAt hf.continuousAt -theorem Inducing.specializes_iff (hf : Inducing f) : f x ⤳ f y ↔ x ⤳ y := by +theorem IsInducing.specializes_iff (hf : IsInducing f) : f x ⤳ f y ↔ x ⤳ y := by simp only [specializes_iff_mem_closure, hf.closure_eq_preimage_closure_image, image_singleton, mem_preimage] +@[deprecated (since := "2024-10-28")] alias Inducing.specializes_iff := IsInducing.specializes_iff + theorem subtype_specializes_iff {p : X → Prop} (x y : Subtype p) : x ⤳ y ↔ (x : X) ⤳ y := - inducing_subtype_val.specializes_iff.symm + IsInducing.subtypeVal.specializes_iff.symm @[simp] theorem specializes_prod {x₁ x₂ : X} {y₁ y₂ : Y} : (x₁, y₁) ⤳ (x₂, y₂) ↔ x₁ ⤳ x₂ ∧ y₁ ⤳ y₂ := by @@ -357,20 +361,27 @@ lemma IsClosedMap.specializingMap (hf : IsClosedMap f) : SpecializingMap f := specializingMap_iff_stableUnderSpecialization_image_singleton.mpr <| fun _ ↦ (hf _ isClosed_closure).stableUnderSpecialization -lemma Inducing.specializingMap (hf : Inducing f) (h : StableUnderSpecialization (range f)) : - SpecializingMap f := by +lemma IsInducing.specializingMap (hf : IsInducing f) + (h : StableUnderSpecialization (range f)) : SpecializingMap f := by intros x y e obtain ⟨y, rfl⟩ := h e ⟨x, rfl⟩ exact ⟨_, hf.specializes_iff.mp e, rfl⟩ -lemma Inducing.generalizingMap (hf : Inducing f) (h : StableUnderGeneralization (range f)) : - GeneralizingMap f := by +@[deprecated (since := "2024-10-28")] alias Inducing.specializingMap := IsInducing.specializingMap + +lemma IsInducing.generalizingMap (hf : IsInducing f) + (h : StableUnderGeneralization (range f)) : GeneralizingMap f := by intros x y e obtain ⟨y, rfl⟩ := h e ⟨x, rfl⟩ exact ⟨_, hf.specializes_iff.mp e, rfl⟩ -lemma OpenEmbedding.generalizingMap (hf : OpenEmbedding f) : GeneralizingMap f := - hf.toInducing.generalizingMap hf.isOpen_range.stableUnderGeneralization +@[deprecated (since := "2024-10-28")] alias Inducing.generalizingMap := IsInducing.generalizingMap + +lemma IsOpenEmbedding.generalizingMap (hf : IsOpenEmbedding f) : GeneralizingMap f := + hf.isInducing.generalizingMap hf.isOpen_range.stableUnderGeneralization + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.generalizingMap := IsOpenEmbedding.generalizingMap lemma SpecializingMap.stableUnderSpecialization_range (h : SpecializingMap f) : StableUnderSpecialization (range f) := @@ -432,11 +443,13 @@ theorem inseparable_iff_closure_eq : (x ~ᵢ y) ↔ closure ({x} : Set X) = clos theorem inseparable_of_nhdsWithin_eq (hx : x ∈ s) (hy : y ∈ s) (h : 𝓝[s] x = 𝓝[s] y) : x ~ᵢ y := (specializes_of_nhdsWithin h.le hx).antisymm (specializes_of_nhdsWithin h.ge hy) -theorem Inducing.inseparable_iff (hf : Inducing f) : (f x ~ᵢ f y) ↔ (x ~ᵢ y) := by +theorem IsInducing.inseparable_iff (hf : IsInducing f) : (f x ~ᵢ f y) ↔ (x ~ᵢ y) := by simp only [inseparable_iff_specializes_and, hf.specializes_iff] +@[deprecated (since := "2024-10-28")] alias Inducing.inseparable_iff := IsInducing.inseparable_iff + theorem subtype_inseparable_iff {p : X → Prop} (x y : Subtype p) : (x ~ᵢ y) ↔ ((x : X) ~ᵢ y) := - inducing_subtype_val.inseparable_iff.symm + IsInducing.subtypeVal.inseparable_iff.symm @[simp] theorem inseparable_prod {x₁ x₂ : X} {y₁ y₂ : Y} : ((x₁, y₁) ~ᵢ (x₂, y₂)) ↔ (x₁ ~ᵢ x₂) ∧ (y₁ ~ᵢ y₂) := by @@ -510,8 +523,11 @@ namespace SeparationQuotient /-- The natural map from a topological space to its separation quotient. -/ def mk : X → SeparationQuotient X := Quotient.mk'' -theorem quotientMap_mk : QuotientMap (mk : X → SeparationQuotient X) := - quotientMap_quot_mk +theorem isQuotientMap_mk : IsQuotientMap (mk : X → SeparationQuotient X) := + isQuotientMap_quot_mk + +@[deprecated (since := "2024-10-22")] +alias quotientMap_mk := isQuotientMap_mk @[fun_prop, continuity] theorem continuous_mk : Continuous (mk : X → SeparationQuotient X) := @@ -547,7 +563,7 @@ theorem preimage_image_mk_open (hs : IsOpen s) : mk ⁻¹' (mk '' s) = s := by exact ((mk_eq_mk.1 hxy).mem_open_iff hs).1 hys theorem isOpenMap_mk : IsOpenMap (mk : X → SeparationQuotient X) := fun s hs => - quotientMap_mk.isOpen_preimage.1 <| by rwa [preimage_image_mk_open hs] + isQuotientMap_mk.isOpen_preimage.1 <| by rwa [preimage_image_mk_open hs] theorem isOpenQuotientMap_mk : IsOpenQuotientMap (mk : X → SeparationQuotient X) := ⟨surjective_mk, continuous_mk, isOpenMap_mk⟩ @@ -557,20 +573,22 @@ theorem preimage_image_mk_closed (hs : IsClosed s) : mk ⁻¹' (mk '' s) = s := rintro x ⟨y, hys, hxy⟩ exact ((mk_eq_mk.1 hxy).mem_closed_iff hs).1 hys -theorem inducing_mk : Inducing (mk : X → SeparationQuotient X) := +theorem isInducing_mk : IsInducing (mk : X → SeparationQuotient X) := ⟨le_antisymm (continuous_iff_le_induced.1 continuous_mk) fun s hs => ⟨mk '' s, isOpenMap_mk s hs, preimage_image_mk_open hs⟩⟩ +@[deprecated (since := "2024-10-28")] alias inducing_mk := isInducing_mk + theorem isClosedMap_mk : IsClosedMap (mk : X → SeparationQuotient X) := - inducing_mk.isClosedMap <| by rw [range_mk]; exact isClosed_univ + isInducing_mk.isClosedMap <| by rw [range_mk]; exact isClosed_univ @[simp] theorem comap_mk_nhds_mk : comap mk (𝓝 (mk x)) = 𝓝 x := - (inducing_mk.nhds_eq_comap _).symm + (isInducing_mk.nhds_eq_comap _).symm @[simp] theorem comap_mk_nhdsSet_image : comap mk (𝓝ˢ (mk '' s)) = 𝓝ˢ s := - (inducing_mk.nhdsSet_eq_comap _).symm + (isInducing_mk.nhdsSet_eq_comap _).symm theorem map_mk_nhds : map mk (𝓝 x) = 𝓝 (mk x) := by rw [← comap_mk_nhds_mk, map_comap_of_surjective surjective_mk] @@ -603,8 +621,11 @@ theorem map_mk_nhdsWithin_preimage (s : Set (SeparationQuotient X)) (x : X) : rw [nhdsWithin, ← comap_principal, Filter.push_pull, nhdsWithin, map_mk_nhds] /-- The map `(x, y) ↦ (mk x, mk y)` is a quotient map. -/ -theorem quotientMap_prodMap_mk : QuotientMap (Prod.map mk mk : X × Y → _) := - (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).quotientMap +theorem isQuotientMap_prodMap_mk : IsQuotientMap (Prod.map mk mk : X × Y → _) := + (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).isQuotientMap + +@[deprecated (since := "2024-10-22")] +alias quotientMap_prodMap_mk := isQuotientMap_prodMap_mk /-- Lift a map `f : X → α` such that `Inseparable x y → f x = f y` to a map `SeparationQuotient X → α`. -/ @@ -706,5 +727,5 @@ end SeparationQuotient theorem continuous_congr_of_inseparable (h : ∀ x, f x ~ᵢ g x) : Continuous f ↔ Continuous g := by - simp_rw [SeparationQuotient.inducing_mk.continuous_iff (Y := Y)] + simp_rw [SeparationQuotient.isInducing_mk.continuous_iff (Y := Y)] exact continuous_congr fun x ↦ SeparationQuotient.mk_eq_mk.mpr (h x) diff --git a/Mathlib/Topology/Instances/AddCircle.lean b/Mathlib/Topology/Instances/AddCircle.lean index 3295ee564f992..3a4b8e7bacfd0 100644 --- a/Mathlib/Topology/Instances/AddCircle.lean +++ b/Mathlib/Topology/Instances/AddCircle.lean @@ -9,6 +9,7 @@ import Mathlib.Data.Nat.Totient import Mathlib.GroupTheory.Divisible import Mathlib.Topology.Connected.PathConnected import Mathlib.Topology.IsLocalHomeomorph +import Mathlib.Topology.Instances.ZMultiples /-! # The additive circle @@ -152,10 +153,6 @@ theorem coe_eq_zero_of_pos_iff (hp : 0 < p) {x : 𝕜} (hx : 0 < x) : theorem coe_period : (p : AddCircle p) = 0 := (QuotientAddGroup.eq_zero_iff p).2 <| mem_zmultiples p -/- Porting note (#10618): `simp` attribute removed because linter reports: -simp can prove this: - by simp only [@mem_zmultiples, @QuotientAddGroup.mk_add_of_mem] --/ theorem coe_add_period (x : 𝕜) : ((x + p : 𝕜) : AddCircle p) = x := by rw [coe_add, ← eq_sub_iff_add_eq', sub_self, coe_period] @@ -271,7 +268,7 @@ theorem continuousAt_equivIoc (hx : x ≠ a) : ContinuousAt (equivIoc p a) x := open_target := isOpen_compl_singleton continuousOn_toFun := (AddCircle.continuous_mk' p).continuousOn continuousOn_invFun := by - exact ContinuousAt.continuousOn + exact continuousOn_of_forall_continuousAt (fun _ ↦ continuousAt_subtype_val.comp ∘ continuousAt_equivIco p a) lemma isLocalHomeomorph_coe [DiscreteTopology (zmultiples p)] [DenselyOrdered 𝕜] : @@ -591,16 +588,14 @@ homeomorphism of topological spaces. -/ def homeoIccQuot [TopologicalSpace 𝕜] [OrderTopology 𝕜] : 𝕋 ≃ₜ Quot (EndpointIdent p a) where toEquiv := equivIccQuot p a continuous_toFun := by - -- Porting note: was `simp_rw` - rw [quotientMap_quotient_mk'.continuous_iff] - simp_rw [continuous_iff_continuousAt, + simp_rw [isQuotientMap_quotient_mk'.continuous_iff, continuous_iff_continuousAt, continuousAt_iff_continuous_left_right] intro x; constructor on_goal 1 => erw [equivIccQuot_comp_mk_eq_toIocMod] on_goal 2 => erw [equivIccQuot_comp_mk_eq_toIcoMod] all_goals apply continuous_quot_mk.continuousAt.comp_continuousWithinAt - rw [inducing_subtype_val.continuousWithinAt_iff] + rw [IsInducing.subtypeVal.continuousWithinAt_iff] · apply continuous_left_toIocMod · apply continuous_right_toIcoMod continuous_invFun := diff --git a/Mathlib/Topology/Instances/CantorSet.lean b/Mathlib/Topology/Instances/CantorSet.lean index 22167d7ac0fbb..1d0c114f0a3e2 100644 --- a/Mathlib/Topology/Instances/CantorSet.lean +++ b/Mathlib/Topology/Instances/CantorSet.lean @@ -5,7 +5,6 @@ Authors: Artur Szafarczyk, Suraj Krishna M S, Jean-Baptiste Stiegler, Isabelle D Tomáš Jakl, Lorenzo Zanichelli, Alina Yan, Emilie Uthaiwat, Jana Göken, Filippo A. E. Nuccio -/ -import Mathlib.Topology.Metrizable.Basic import Mathlib.Topology.Algebra.GroupWithZero import Mathlib.Topology.Instances.Real @@ -86,8 +85,8 @@ lemma isClosed_preCantorSet (n : ℕ) : IsClosed (preCantorSet n) := by | zero => exact isClosed_Icc | succ n ih => refine IsClosed.union ?_ ?_ - · simpa [f, div_eq_inv_mul] using f.closedEmbedding.closed_iff_image_closed.mp ih - · simpa [g, f, div_eq_inv_mul] using g.closedEmbedding.closed_iff_image_closed.mp ih + · simpa [f, div_eq_inv_mul] using f.isClosedEmbedding.closed_iff_image_closed.mp ih + · simpa [g, f, div_eq_inv_mul] using g.isClosedEmbedding.closed_iff_image_closed.mp ih /-- The ternary Cantor set is closed. -/ lemma isClosed_cantorSet : IsClosed cantorSet := diff --git a/Mathlib/Topology/Instances/Complex.lean b/Mathlib/Topology/Instances/Complex.lean index 6b8e3c0862a14..f48381256f115 100644 --- a/Mathlib/Topology/Instances/Complex.lean +++ b/Mathlib/Topology/Instances/Complex.lean @@ -23,15 +23,15 @@ open ComplexConjugate /-- The only closed subfields of `ℂ` are `ℝ` and `ℂ`. -/ theorem Complex.subfield_eq_of_closed {K : Subfield ℂ} (hc : IsClosed (K : Set ℂ)) : - K = ofReal.fieldRange ∨ K = ⊤ := by - suffices range (ofReal' : ℝ → ℂ) ⊆ K by + K = ofRealHom.fieldRange ∨ K = ⊤ := by + suffices range (ofReal : ℝ → ℂ) ⊆ K by rw [range_subset_iff, ← coe_algebraMap] at this have := (Subalgebra.isSimpleOrder_of_finrank finrank_real_complex).eq_bot_or_eq_top (Subfield.toIntermediateField K this).toSubalgebra simp_rw [← SetLike.coe_set_eq, IntermediateField.coe_toSubalgebra] at this ⊢ exact this - suffices range (ofReal' : ℝ → ℂ) ⊆ closure (Set.range ((ofReal' : ℝ → ℂ) ∘ ((↑) : ℚ → ℝ))) by + suffices range (ofReal : ℝ → ℂ) ⊆ closure (Set.range ((ofReal : ℝ → ℂ) ∘ ((↑) : ℚ → ℝ))) by refine subset_trans this ?_ rw [← IsClosed.closure_eq hc] apply closure_mono @@ -52,9 +52,9 @@ theorem Complex.uniformContinuous_ringHom_eq_id_or_conj (K : Subfield ℂ) {ψ : letI : TopologicalRing K.topologicalClosure := Subring.instTopologicalRing K.topologicalClosure.toSubring set ι : K → K.topologicalClosure := ⇑(Subfield.inclusion K.le_topologicalClosure) - have ui : UniformInducing ι := + have ui : IsUniformInducing ι := ⟨by - erw [uniformity_subtype, uniformity_subtype, Filter.comap_comap] + rw [uniformity_subtype, uniformity_subtype, Filter.comap_comap] congr ⟩ let di := ui.isDenseInducing (?_ : DenseRange ι) · -- extψ : closure(K) →+* ℂ is the extension of ψ : K →+* ℂ @@ -65,19 +65,19 @@ theorem Complex.uniformContinuous_ringHom_eq_id_or_conj (K : Subfield ℂ) {ψ : let j := RingEquiv.subfieldCongr h -- ψ₁ is the continuous ring hom `ℝ →+* ℂ` constructed from `j : closure (K) ≃+* ℝ` -- and `extψ : closure (K) →+* ℂ` - let ψ₁ := RingHom.comp extψ (RingHom.comp j.symm.toRingHom ofReal.rangeRestrict) + let ψ₁ := RingHom.comp extψ (RingHom.comp j.symm.toRingHom ofRealHom.rangeRestrict) -- Porting note: was `by continuity!` and was used inline have hψ₁ : Continuous ψ₁ := by simpa only [RingHom.coe_comp] using hψ.comp ((continuous_algebraMap ℝ ℂ).subtype_mk _) ext1 x - rsuffices ⟨r, hr⟩ : ∃ r : ℝ, ofReal.rangeRestrict r = j (ι x) + rsuffices ⟨r, hr⟩ : ∃ r : ℝ, ofRealHom.rangeRestrict r = j (ι x) · have := RingHom.congr_fun (ringHom_eq_ofReal_of_continuous hψ₁) r -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [RingHom.comp_apply, RingHom.comp_apply, hr, RingEquiv.toRingHom_eq_coe] at this convert this using 1 · exact (IsDenseInducing.extend_eq di hc.continuous _).symm - · rw [← ofReal.coe_rangeRestrict, hr] + · rw [← ofRealHom.coe_rangeRestrict, hr] rfl obtain ⟨r, hr⟩ := SetLike.coe_mem (j (ι x)) exact ⟨r, Subtype.ext hr⟩ diff --git a/Mathlib/Topology/Instances/ENNReal.lean b/Mathlib/Topology/Instances/ENNReal.lean index 5623966b95601..b06d55e4da6e6 100644 --- a/Mathlib/Topology/Instances/ENNReal.lean +++ b/Mathlib/Topology/Instances/ENNReal.lean @@ -19,7 +19,7 @@ import Mathlib.Topology.Metrizable.Uniformity noncomputable section open Set Filter Metric Function -open scoped Topology ENNReal NNReal +open scoped Finset Topology ENNReal NNReal variable {α : Type*} {β : Type*} {γ : Type*} @@ -45,13 +45,16 @@ instance : T5Space ℝ≥0∞ := inferInstance instance : T4Space ℝ≥0∞ := inferInstance instance : SecondCountableTopology ℝ≥0∞ := - orderIsoUnitIntervalBirational.toHomeomorph.embedding.secondCountableTopology + orderIsoUnitIntervalBirational.toHomeomorph.isEmbedding.secondCountableTopology instance : MetrizableSpace ENNReal := - orderIsoUnitIntervalBirational.toHomeomorph.embedding.metrizableSpace + orderIsoUnitIntervalBirational.toHomeomorph.isEmbedding.metrizableSpace -theorem embedding_coe : Embedding ((↑) : ℝ≥0 → ℝ≥0∞) := - coe_strictMono.embedding_of_ordConnected <| by rw [range_coe']; exact ordConnected_Iio +theorem isEmbedding_coe : IsEmbedding ((↑) : ℝ≥0 → ℝ≥0∞) := + coe_strictMono.isEmbedding_of_ordConnected <| by rw [range_coe']; exact ordConnected_Iio + +@[deprecated (since := "2024-10-26")] +alias embedding_coe := isEmbedding_coe theorem isOpen_ne_top : IsOpen { a : ℝ≥0∞ | a ≠ ∞ } := isOpen_ne @@ -59,27 +62,30 @@ theorem isOpen_Ico_zero : IsOpen (Ico 0 b) := by rw [ENNReal.Ico_eq_Iio] exact isOpen_Iio -theorem openEmbedding_coe : OpenEmbedding ((↑) : ℝ≥0 → ℝ≥0∞) := - ⟨embedding_coe, by rw [range_coe']; exact isOpen_Iio⟩ +theorem isOpenEmbedding_coe : IsOpenEmbedding ((↑) : ℝ≥0 → ℝ≥0∞) := + ⟨isEmbedding_coe, by rw [range_coe']; exact isOpen_Iio⟩ + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_coe := isOpenEmbedding_coe theorem coe_range_mem_nhds : range ((↑) : ℝ≥0 → ℝ≥0∞) ∈ 𝓝 (r : ℝ≥0∞) := - IsOpen.mem_nhds openEmbedding_coe.isOpen_range <| mem_range_self _ + IsOpen.mem_nhds isOpenEmbedding_coe.isOpen_range <| mem_range_self _ @[norm_cast] theorem tendsto_coe {f : Filter α} {m : α → ℝ≥0} {a : ℝ≥0} : Tendsto (fun a => (m a : ℝ≥0∞)) f (𝓝 ↑a) ↔ Tendsto m f (𝓝 a) := - embedding_coe.tendsto_nhds_iff.symm + isEmbedding_coe.tendsto_nhds_iff.symm @[fun_prop] theorem continuous_coe : Continuous ((↑) : ℝ≥0 → ℝ≥0∞) := - embedding_coe.continuous + isEmbedding_coe.continuous theorem continuous_coe_iff {α} [TopologicalSpace α] {f : α → ℝ≥0} : (Continuous fun a => (f a : ℝ≥0∞)) ↔ Continuous f := - embedding_coe.continuous_iff.symm + isEmbedding_coe.continuous_iff.symm theorem nhds_coe {r : ℝ≥0} : 𝓝 (r : ℝ≥0∞) = (𝓝 r).map (↑) := - (openEmbedding_coe.map_nhds_eq r).symm + (isOpenEmbedding_coe.map_nhds_eq r).symm theorem tendsto_nhds_coe_iff {α : Type*} {l : Filter α} {x : ℝ≥0} {f : ℝ≥0∞ → α} : Tendsto f (𝓝 ↑x) l ↔ Tendsto (f ∘ (↑) : ℝ≥0 → α) (𝓝 x) l := by @@ -91,7 +97,7 @@ theorem continuousAt_coe_iff {α : Type*} [TopologicalSpace α] {x : ℝ≥0} {f theorem nhds_coe_coe {r p : ℝ≥0} : 𝓝 ((r : ℝ≥0∞), (p : ℝ≥0∞)) = (𝓝 (r, p)).map fun p : ℝ≥0 × ℝ≥0 => (↑p.1, ↑p.2) := - ((openEmbedding_coe.prodMap openEmbedding_coe).map_nhds_eq (r, p)).symm + ((isOpenEmbedding_coe.prodMap isOpenEmbedding_coe).map_nhds_eq (r, p)).symm theorem continuous_ofReal : Continuous ENNReal.ofReal := (continuous_coe_iff.2 continuous_id).comp continuous_real_toNNReal @@ -153,7 +159,7 @@ theorem tendsto_nhds_top_iff_nat {m : α → ℝ≥0∞} {f : Filter α} : tendsto_nhds_top_iff_nnreal.trans ⟨fun h n => by simpa only [ENNReal.coe_natCast] using h n, fun h x => let ⟨n, hn⟩ := exists_nat_gt x - (h n).mono fun y => lt_trans <| by rwa [← ENNReal.coe_natCast, coe_lt_coe]⟩ + (h n).mono fun _ => lt_trans <| by rwa [← ENNReal.coe_natCast, coe_lt_coe]⟩ theorem tendsto_nhds_top {m : α → ℝ≥0∞} {f : Filter α} (h : ∀ n : ℕ, ∀ᶠ a in f, ↑n < m a) : Tendsto m f (𝓝 ∞) := @@ -419,7 +425,7 @@ theorem continuousOn_sub_left (a : ℝ≥0∞) : ContinuousOn (a - ·) { x : ℝ theorem continuous_sub_right (a : ℝ≥0∞) : Continuous fun x : ℝ≥0∞ => x - a := by by_cases a_infty : a = ∞ - · simp [a_infty, continuous_const] + · simp [a_infty, continuous_const, tsub_eq_zero_of_le] · rw [show (fun x => x - a) = (fun p : ℝ≥0∞ × ℝ≥0∞ => p.fst - p.snd) ∘ fun x => ⟨x, a⟩ by rfl] apply ContinuousOn.comp_continuous continuousOn_sub (continuous_id'.prod_mk continuous_const) intro x @@ -825,11 +831,11 @@ theorem finite_const_le_of_tsum_ne_top {ι : Type*} {a : ι → ℝ≥0∞} (tsu /-- Markov's inequality for `Finset.card` and `tsum` in `ℝ≥0∞`. -/ theorem finset_card_const_le_le_of_tsum_le {ι : Type*} {a : ι → ℝ≥0∞} {c : ℝ≥0∞} (c_ne_top : c ≠ ∞) (tsum_le_c : ∑' i, a i ≤ c) {ε : ℝ≥0∞} (ε_ne_zero : ε ≠ 0) : - ∃ hf : { i : ι | ε ≤ a i }.Finite, ↑hf.toFinset.card ≤ c / ε := by + ∃ hf : { i : ι | ε ≤ a i }.Finite, #hf.toFinset ≤ c / ε := by have hf : { i : ι | ε ≤ a i }.Finite := finite_const_le_of_tsum_ne_top (ne_top_of_le_ne_top c_ne_top tsum_le_c) ε_ne_zero refine ⟨hf, (ENNReal.le_div_iff_mul_le (.inl ε_ne_zero) (.inr c_ne_top)).2 ?_⟩ - calc ↑hf.toFinset.card * ε = ∑ _i ∈ hf.toFinset, ε := by rw [Finset.sum_const, nsmul_eq_mul] + calc #hf.toFinset * ε = ∑ _i ∈ hf.toFinset, ε := by rw [Finset.sum_const, nsmul_eq_mul] _ ≤ ∑ i ∈ hf.toFinset, a i := Finset.sum_le_sum fun i => hf.mem_toFinset.1 _ ≤ ∑' i, a i := ENNReal.sum_le_tsum _ _ ≤ c := tsum_le_c @@ -1090,7 +1096,7 @@ theorem edist_ne_top_of_mem_ball {a : β} {r : ℝ≥0∞} (x y : ball a r) : ed ne_of_lt <| calc edist x y ≤ edist a x + edist a y := edist_triangle_left x.1 y.1 a - _ < r + r := by rw [edist_comm a x, edist_comm a y]; exact add_lt_add x.2 y.2 + _ < r + r := by rw [edist_comm a x, edist_comm a y]; exact ENNReal.add_lt_add x.2 y.2 _ ≤ ∞ := le_top /-- Each ball in an extended metric space gives us a metric space, as the edist @@ -1361,6 +1367,33 @@ lemma liminf_const_sub (F : Filter ι) [NeBot F] (f : ι → ℝ≥0∞) {c : (Antitone.map_limsSup_of_continuousAt (F := F.map f) (f := fun (x : ℝ≥0∞) ↦ c - x) (fun _ _ h ↦ tsub_le_tsub_left h c) (continuous_sub_left c_ne_top).continuousAt).symm +lemma le_limsup_mul {α : Type*} {f : Filter α} {u v : α → ℝ≥0∞} : + limsup u f * liminf v f ≤ limsup (u * v) f := + mul_le_of_forall_lt fun a a_u b b_v ↦ (le_limsup_iff).2 fun c c_ab ↦ + Frequently.mono (Frequently.and_eventually ((frequently_lt_of_lt_limsup) a_u) + ((eventually_lt_of_lt_liminf) b_v)) fun _ ab_x ↦ c_ab.trans (mul_lt_mul ab_x.1 ab_x.2) + +/-- See also `ENNReal.limsup_mul_le`.-/ +lemma limsup_mul_le' {α : Type*} {f : Filter α} {u v : α → ℝ≥0∞} + (h : limsup u f ≠ 0 ∨ limsup v f ≠ ∞) (h' : limsup u f ≠ ∞ ∨ limsup v f ≠ 0) : + limsup (u * v) f ≤ limsup u f * limsup v f := by + refine le_mul_of_forall_lt h h' fun a a_u b b_v ↦ (limsup_le_iff).2 fun c c_ab ↦ ?_ + filter_upwards [eventually_lt_of_limsup_lt a_u, eventually_lt_of_limsup_lt b_v] with x a_x b_x + exact (mul_lt_mul a_x b_x).trans c_ab + +lemma le_liminf_mul {α : Type*} {f : Filter α} {u v : α → ℝ≥0∞} : + liminf u f * liminf v f ≤ liminf (u * v) f := by + refine mul_le_of_forall_lt fun a a_u b b_v ↦ (le_liminf_iff).2 fun c c_ab ↦ ?_ + filter_upwards [eventually_lt_of_lt_liminf a_u, eventually_lt_of_lt_liminf b_v] with x a_x b_x + exact c_ab.trans (mul_lt_mul a_x b_x) + +lemma liminf_mul_le {α : Type*} {f : Filter α} {u v : α → ℝ≥0∞} + (h : limsup u f ≠ 0 ∨ liminf v f ≠ ∞) (h' : limsup u f ≠ ∞ ∨ liminf v f ≠ 0) : + liminf (u * v) f ≤ limsup u f * liminf v f := + le_mul_of_forall_lt h h' fun a a_u b b_v ↦ (liminf_le_iff).2 fun c c_ab ↦ + Frequently.mono (((frequently_lt_of_liminf_lt) b_v).and_eventually + ((eventually_lt_of_limsup_lt) a_u)) fun _ ab_x ↦ (mul_lt_mul ab_x.2 ab_x.1).trans c_ab + /-- If `xs : ι → ℝ≥0∞` is bounded, then we have `liminf (toReal ∘ xs) = toReal (liminf xs)`. -/ lemma liminf_toReal_eq {ι : Type*} {F : Filter ι} [NeBot F] {b : ℝ≥0∞} (b_ne_top : b ≠ ∞) {xs : ι → ℝ≥0∞} (le_b : ∀ᶠ i in F, xs i ≤ b) : diff --git a/Mathlib/Topology/Instances/ENat.lean b/Mathlib/Topology/Instances/ENat.lean index ee7773df5b64b..7372c30ed2795 100644 --- a/Mathlib/Topology/Instances/ENat.lean +++ b/Mathlib/Topology/Instances/ENat.lean @@ -30,14 +30,20 @@ instance : OrderTopology ℕ∞ := ⟨rfl⟩ @[simp] theorem range_natCast : range ((↑) : ℕ → ℕ∞) = Iio ⊤ := WithTop.range_coe -theorem embedding_natCast : Embedding ((↑) : ℕ → ℕ∞) := - Nat.strictMono_cast.embedding_of_ordConnected <| range_natCast ▸ ordConnected_Iio +theorem isEmbedding_natCast : IsEmbedding ((↑) : ℕ → ℕ∞) := + Nat.strictMono_cast.isEmbedding_of_ordConnected <| range_natCast ▸ ordConnected_Iio -theorem openEmbedding_natCast : OpenEmbedding ((↑) : ℕ → ℕ∞) := - ⟨embedding_natCast, range_natCast ▸ isOpen_Iio⟩ +@[deprecated (since := "2024-10-26")] +alias embedding_natCast := isEmbedding_natCast + +theorem isOpenEmbedding_natCast : IsOpenEmbedding ((↑) : ℕ → ℕ∞) := + ⟨isEmbedding_natCast, range_natCast ▸ isOpen_Iio⟩ + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_natCast := isOpenEmbedding_natCast theorem nhds_natCast (n : ℕ) : 𝓝 (n : ℕ∞) = pure (n : ℕ∞) := by - simp [← openEmbedding_natCast.map_nhds_eq] + simp [← isOpenEmbedding_natCast.map_nhds_eq] @[simp] protected theorem nhds_eq_pure {n : ℕ∞} (h : n ≠ ⊤) : 𝓝 n = pure n := by @@ -89,7 +95,7 @@ protected theorem continuousAt_sub {a b : ℕ∞} (h : a ≠ ⊤ ∨ b ≠ ⊤) simpa [ContinuousAt, nhds_prod_eq] using tendsto_pure_nhds _ _ | (a : ℕ), ⊤, _ => suffices ∀ᶠ b in 𝓝 ⊤, (a - b : ℕ∞) = 0 by - simpa [ContinuousAt, nhds_prod_eq] + simpa [ContinuousAt, nhds_prod_eq, tsub_eq_zero_of_le] filter_upwards [le_mem_nhds (WithTop.coe_lt_top a)] with b using tsub_eq_zero_of_le | ⊤, (b : ℕ), _ => suffices ∀ n : ℕ, ∀ᶠ a : ℕ∞ in 𝓝 ⊤, b + n < a by diff --git a/Mathlib/Topology/Instances/EReal.lean b/Mathlib/Topology/Instances/EReal.lean index 4d970aa153cb8..cedc98e15dfa0 100644 --- a/Mathlib/Topology/Instances/EReal.lean +++ b/Mathlib/Topology/Instances/EReal.lean @@ -48,29 +48,35 @@ instance : SecondCountableTopology EReal := /-! ### Real coercion -/ -theorem embedding_coe : Embedding ((↑) : ℝ → EReal) := - coe_strictMono.embedding_of_ordConnected <| by rw [range_coe_eq_Ioo]; exact ordConnected_Ioo +theorem isEmbedding_coe : IsEmbedding ((↑) : ℝ → EReal) := + coe_strictMono.isEmbedding_of_ordConnected <| by rw [range_coe_eq_Ioo]; exact ordConnected_Ioo -theorem openEmbedding_coe : OpenEmbedding ((↑) : ℝ → EReal) := - ⟨embedding_coe, by simp only [range_coe_eq_Ioo, isOpen_Ioo]⟩ +@[deprecated (since := "2024-10-26")] +alias embedding_coe := isEmbedding_coe + +theorem isOpenEmbedding_coe : IsOpenEmbedding ((↑) : ℝ → EReal) := + ⟨isEmbedding_coe, by simp only [range_coe_eq_Ioo, isOpen_Ioo]⟩ + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_coe := isOpenEmbedding_coe @[norm_cast] theorem tendsto_coe {α : Type*} {f : Filter α} {m : α → ℝ} {a : ℝ} : Tendsto (fun a => (m a : EReal)) f (𝓝 ↑a) ↔ Tendsto m f (𝓝 a) := - embedding_coe.tendsto_nhds_iff.symm + isEmbedding_coe.tendsto_nhds_iff.symm theorem _root_.continuous_coe_real_ereal : Continuous ((↑) : ℝ → EReal) := - embedding_coe.continuous + isEmbedding_coe.continuous theorem continuous_coe_iff {f : α → ℝ} : (Continuous fun a => (f a : EReal)) ↔ Continuous f := - embedding_coe.continuous_iff.symm + isEmbedding_coe.continuous_iff.symm theorem nhds_coe {r : ℝ} : 𝓝 (r : EReal) = (𝓝 r).map (↑) := - (openEmbedding_coe.map_nhds_eq r).symm + (isOpenEmbedding_coe.map_nhds_eq r).symm theorem nhds_coe_coe {r p : ℝ} : 𝓝 ((r : EReal), (p : EReal)) = (𝓝 (r, p)).map fun p : ℝ × ℝ => (↑p.1, ↑p.2) := - ((openEmbedding_coe.prodMap openEmbedding_coe).map_nhds_eq (r, p)).symm + ((isOpenEmbedding_coe.prodMap isOpenEmbedding_coe).map_nhds_eq (r, p)).symm theorem tendsto_toReal {a : EReal} (ha : a ≠ ⊤) (h'a : a ≠ ⊥) : Tendsto EReal.toReal (𝓝 a) (𝓝 a.toReal) := by @@ -89,24 +95,30 @@ def neBotTopHomeomorphReal : ({⊥, ⊤}ᶜ : Set EReal) ≃ₜ ℝ where /-! ### ENNReal coercion -/ -theorem embedding_coe_ennreal : Embedding ((↑) : ℝ≥0∞ → EReal) := - coe_ennreal_strictMono.embedding_of_ordConnected <| by +theorem isEmbedding_coe_ennreal : IsEmbedding ((↑) : ℝ≥0∞ → EReal) := + coe_ennreal_strictMono.isEmbedding_of_ordConnected <| by rw [range_coe_ennreal]; exact ordConnected_Ici -theorem closedEmbedding_coe_ennreal : ClosedEmbedding ((↑) : ℝ≥0∞ → EReal) := - ⟨embedding_coe_ennreal, by rw [range_coe_ennreal]; exact isClosed_Ici⟩ +@[deprecated (since := "2024-10-26")] +alias embedding_coe_ennreal := isEmbedding_coe_ennreal + +theorem isClosedEmbedding_coe_ennreal : IsClosedEmbedding ((↑) : ℝ≥0∞ → EReal) := + ⟨isEmbedding_coe_ennreal, by rw [range_coe_ennreal]; exact isClosed_Ici⟩ + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_coe_ennreal := isClosedEmbedding_coe_ennreal @[norm_cast] theorem tendsto_coe_ennreal {α : Type*} {f : Filter α} {m : α → ℝ≥0∞} {a : ℝ≥0∞} : Tendsto (fun a => (m a : EReal)) f (𝓝 ↑a) ↔ Tendsto m f (𝓝 a) := - embedding_coe_ennreal.tendsto_nhds_iff.symm + isEmbedding_coe_ennreal.tendsto_nhds_iff.symm theorem _root_.continuous_coe_ennreal_ereal : Continuous ((↑) : ℝ≥0∞ → EReal) := - embedding_coe_ennreal.continuous + isEmbedding_coe_ennreal.continuous theorem continuous_coe_ennreal_iff {f : α → ℝ≥0∞} : (Continuous fun a => (f a : EReal)) ↔ Continuous f := - embedding_coe_ennreal.continuous_iff.symm + isEmbedding_coe_ennreal.continuous_iff.symm /-! ### Neighborhoods of infinity -/ @@ -184,22 +196,11 @@ lemma tendsto_toReal_atBot : Tendsto EReal.toReal (𝓝[≠] ⊥) atBot := by variable {α : Type*} {u v : α → EReal} -lemma add_iInf_le_iInf_add : (⨅ x, u x) + (⨅ x, v x) ≤ ⨅ x, (u + v) x := by - refine add_le_of_forall_add_le fun a a_u b b_v ↦ ?_ - rw [lt_iInf_iff] at a_u b_v - rcases a_u with ⟨c, a_c, c_u⟩ - rcases b_v with ⟨d, b_d, d_v⟩ - simp only [Pi.add_apply, le_iInf_iff] - exact fun x ↦ add_le_add (lt_of_lt_of_le a_c (c_u x)).le (lt_of_lt_of_le b_d (d_v x)).le - -lemma iSup_add_le_add_iSup (h : ⨆ x, u x ≠ ⊥ ∨ ⨆ x, v x ≠ ⊤) (h' : ⨆ x, u x ≠ ⊤ ∨ ⨆ x, v x ≠ ⊥) : - ⨆ x, (u + v) x ≤ (⨆ x, u x) + (⨆ x, v x) := by - refine le_add_of_forall_le_add h h' fun a a_u b b_v ↦ ?_ - rw [gt_iff_lt, iSup_lt_iff] at a_u b_v - rcases a_u with ⟨c, a_c, c_u⟩ - rcases b_v with ⟨d, b_d, d_v⟩ - simp only [Pi.add_apply, iSup_le_iff] - exact fun x ↦ add_le_add (lt_of_le_of_lt (c_u x) a_c).le (lt_of_le_of_lt (d_v x) b_d).le +lemma add_iInf_le_iInf_add : (⨅ x, u x) + ⨅ x, v x ≤ ⨅ x, (u + v) x := + le_iInf fun i ↦ add_le_add (iInf_le u i) (iInf_le v i) + +lemma iSup_add_le_add_iSup : ⨆ x, (u + v) x ≤ (⨆ x, u x) + ⨆ x, v x := + iSup_le fun i ↦ add_le_add (le_iSup u i) (le_iSup v i) /-! ### Liminfs and Limsups -/ @@ -226,14 +227,14 @@ lemma limsup_add_le_add_limsup (h : limsup u f ≠ ⊥ ∨ limsup v f ≠ ⊤) exact (add_lt_add a_x b_x).trans c_ab lemma limsup_add_liminf_le_limsup_add : (limsup u f) + (liminf v f) ≤ limsup (u + v) f := - add_le_of_forall_add_le fun a a_u b b_v ↦ (le_limsup_iff).2 fun c c_ab ↦ + add_le_of_forall_add_le fun _ a_u _ b_v ↦ (le_limsup_iff).2 fun _ c_ab ↦ Frequently.mono (Frequently.and_eventually ((frequently_lt_of_lt_limsup) a_u) ((eventually_lt_of_lt_liminf) b_v)) fun _ ab_x ↦ c_ab.trans (add_lt_add ab_x.1 ab_x.2) lemma liminf_add_le_limsup_add_liminf (h : limsup u f ≠ ⊥ ∨ liminf v f ≠ ⊤) (h' : limsup u f ≠ ⊤ ∨ liminf v f ≠ ⊥) : liminf (u + v) f ≤ (limsup u f) + (liminf v f) := - le_add_of_forall_le_add h h' fun a a_u b b_v ↦ (liminf_le_iff).2 fun c c_ab ↦ + le_add_of_forall_le_add h h' fun _ a_u _ b_v ↦ (liminf_le_iff).2 fun _ c_ab ↦ Frequently.mono (Frequently.and_eventually ((frequently_lt_of_liminf_lt) b_v) ((eventually_lt_of_limsup_lt) a_u)) fun _ ab_x ↦ (add_lt_add ab_x.2 ab_x.1).trans c_ab diff --git a/Mathlib/Topology/Instances/Int.lean b/Mathlib/Topology/Instances/Int.lean index 5ee25d7b929f2..536b95e356e15 100644 --- a/Mathlib/Topology/Instances/Int.lean +++ b/Mathlib/Topology/Instances/Int.lean @@ -45,8 +45,11 @@ theorem isUniformEmbedding_coe_real : IsUniformEmbedding ((↑) : ℤ → ℝ) : @[deprecated (since := "2024-10-01")] alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real -theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℤ → ℝ) := - closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist +theorem isClosedEmbedding_coe_real : IsClosedEmbedding ((↑) : ℤ → ℝ) := + isClosedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_coe_real := isClosedEmbedding_coe_real instance : MetricSpace ℤ := Int.isUniformEmbedding_coe_real.comapMetricSpace _ diff --git a/Mathlib/Topology/Instances/Irrational.lean b/Mathlib/Topology/Instances/Irrational.lean index fc7c1f606e691..f395be578fdff 100644 --- a/Mathlib/Topology/Instances/Irrational.lean +++ b/Mathlib/Topology/Instances/Irrational.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Data.Real.Irrational import Mathlib.Data.Rat.Encodable -import Mathlib.Topology.GDelta +import Mathlib.Topology.Separation.GDelta /-! # Topology of irrational numbers @@ -71,7 +71,7 @@ instance : DenselyOrdered { x // Irrational x } := theorem eventually_forall_le_dist_cast_div (hx : Irrational x) (n : ℕ) : ∀ᶠ ε : ℝ in 𝓝 0, ∀ m : ℤ, ε ≤ dist x (m / n) := by have A : IsClosed (range (fun m => (n : ℝ)⁻¹ * m : ℤ → ℝ)) := - ((isClosedMap_smul₀ (n⁻¹ : ℝ)).comp Int.closedEmbedding_coe_real.isClosedMap).isClosed_range + ((isClosedMap_smul₀ (n⁻¹ : ℝ)).comp Int.isClosedEmbedding_coe_real.isClosedMap).isClosed_range have B : x ∉ range (fun m => (n : ℝ)⁻¹ * m : ℤ → ℝ) := by rintro ⟨m, rfl⟩ simp at hx diff --git a/Mathlib/Topology/Instances/Matrix.lean b/Mathlib/Topology/Instances/Matrix.lean index 3d40bfe074344..dc4f941c6159d 100644 --- a/Mathlib/Topology/Instances/Matrix.lean +++ b/Mathlib/Topology/Instances/Matrix.lean @@ -256,7 +256,7 @@ end Continuity section tsum -variable [Semiring α] [AddCommMonoid R] [TopologicalSpace R] [Module α R] +variable [AddCommMonoid R] [TopologicalSpace R] theorem HasSum.matrix_transpose {f : X → Matrix m n R} {a : Matrix m n R} (hf : HasSum f a) : HasSum (fun x => (f x)ᵀ) aᵀ := diff --git a/Mathlib/Topology/Instances/NNReal.lean b/Mathlib/Topology/Instances/NNReal.lean index d6ef63c1b5f66..74d38ed33d8a5 100644 --- a/Mathlib/Topology/Instances/NNReal.lean +++ b/Mathlib/Topology/Instances/NNReal.lean @@ -6,8 +6,9 @@ Authors: Johan Commelin import Mathlib.Data.NNReal.Star import Mathlib.Topology.Algebra.InfiniteSum.Order import Mathlib.Topology.Algebra.InfiniteSum.Ring -import Mathlib.Topology.Instances.Real +import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.MetricSpace.Isometry +import Mathlib.Topology.Instances.Real /-! # Topology on `ℝ≥0` @@ -288,7 +289,7 @@ end Monotone instance instProperSpace : ProperSpace ℝ≥0 where isCompact_closedBall x r := by - have emb : ClosedEmbedding ((↑) : ℝ≥0 → ℝ) := Isometry.closedEmbedding fun _ ↦ congrFun rfl + have emb : IsClosedEmbedding ((↑) : ℝ≥0 → ℝ) := Isometry.isClosedEmbedding fun _ ↦ congrFun rfl exact emb.isCompact_preimage (K := Metric.closedBall x r) (isCompact_closedBall _ _) end NNReal diff --git a/Mathlib/Topology/Instances/Nat.lean b/Mathlib/Topology/Instances/Nat.lean index e90ce1cbe65b7..c5719cb578fc2 100644 --- a/Mathlib/Topology/Instances/Nat.lean +++ b/Mathlib/Topology/Instances/Nat.lean @@ -37,8 +37,11 @@ theorem isUniformEmbedding_coe_real : IsUniformEmbedding ((↑) : ℕ → ℝ) : @[deprecated (since := "2024-10-01")] alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real -theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℕ → ℝ) := - closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist +theorem isClosedEmbedding_coe_real : IsClosedEmbedding ((↑) : ℕ → ℝ) := + isClosedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_coe_real := isClosedEmbedding_coe_real instance : MetricSpace ℕ := Nat.isUniformEmbedding_coe_real.comapMetricSpace _ diff --git a/Mathlib/Topology/Instances/Rat.lean b/Mathlib/Topology/Instances/Rat.lean index c6e661d02abb8..a09e2b65750df 100644 --- a/Mathlib/Topology/Instances/Rat.lean +++ b/Mathlib/Topology/Instances/Rat.lean @@ -42,8 +42,11 @@ theorem isDenseEmbedding_coe_real : IsDenseEmbedding ((↑) : ℚ → ℝ) := @[deprecated (since := "2024-09-30")] alias denseEmbedding_coe_real := isDenseEmbedding_coe_real -theorem embedding_coe_real : Embedding ((↑) : ℚ → ℝ) := - isDenseEmbedding_coe_real.to_embedding +theorem isEmbedding_coe_real : IsEmbedding ((↑) : ℚ → ℝ) := + isDenseEmbedding_coe_real.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding_coe_real := isEmbedding_coe_real theorem continuous_coe_real : Continuous ((↑) : ℚ → ℝ) := uniformContinuous_coe_real.continuous @@ -60,8 +63,11 @@ theorem Nat.isUniformEmbedding_coe_rat : IsUniformEmbedding ((↑) : ℕ → ℚ @[deprecated (since := "2024-10-01")] alias Nat.uniformEmbedding_coe_rat := Nat.isUniformEmbedding_coe_rat -theorem Nat.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℕ → ℚ) := - closedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Nat.pairwise_one_le_dist +theorem Nat.isClosedEmbedding_coe_rat : IsClosedEmbedding ((↑) : ℕ → ℚ) := + isClosedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Nat.pairwise_one_le_dist + +@[deprecated (since := "2024-10-20")] +alias Nat.closedEmbedding_coe_rat := Nat.isClosedEmbedding_coe_rat @[norm_cast, simp] theorem Int.dist_cast_rat (x y : ℤ) : dist (x : ℚ) y = dist x y := by @@ -73,15 +79,18 @@ theorem Int.isUniformEmbedding_coe_rat : IsUniformEmbedding ((↑) : ℤ → ℚ @[deprecated (since := "2024-10-01")] alias Int.uniformEmbedding_coe_rat := Int.isUniformEmbedding_coe_rat -theorem Int.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℤ → ℚ) := - closedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist +theorem Int.isClosedEmbedding_coe_rat : IsClosedEmbedding ((↑) : ℤ → ℚ) := + isClosedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist + +@[deprecated (since := "2024-10-20")] +alias Int.closedEmbedding_coe_rat := Int.isClosedEmbedding_coe_rat namespace Rat -instance : NoncompactSpace ℚ := Int.closedEmbedding_coe_rat.noncompactSpace +instance : NoncompactSpace ℚ := Int.isClosedEmbedding_coe_rat.noncompactSpace theorem uniformContinuous_add : UniformContinuous fun p : ℚ × ℚ => p.1 + p.2 := - Rat.isUniformEmbedding_coe_real.toUniformInducing.uniformContinuous_iff.2 <| by + Rat.isUniformEmbedding_coe_real.isUniformInducing.uniformContinuous_iff.2 <| by simp only [Function.comp_def, Rat.cast_add] exact Real.uniformContinuous_add.comp (Rat.uniformContinuous_coe_real.prodMap Rat.uniformContinuous_coe_real) @@ -106,7 +115,7 @@ instance : TopologicalRing ℚ := inferInstance nonrec theorem totallyBounded_Icc (a b : ℚ) : TotallyBounded (Icc a b) := by simpa only [preimage_cast_Icc] - using totallyBounded_preimage Rat.isUniformEmbedding_coe_real.toUniformInducing + using totallyBounded_preimage Rat.isUniformEmbedding_coe_real.isUniformInducing (totallyBounded_Icc (a : ℝ) b) end Rat diff --git a/Mathlib/Topology/Instances/RatLemmas.lean b/Mathlib/Topology/Instances/RatLemmas.lean index 69619e025121f..1f633201490d0 100644 --- a/Mathlib/Topology/Instances/RatLemmas.lean +++ b/Mathlib/Topology/Instances/RatLemmas.lean @@ -36,7 +36,7 @@ local notation "ℚ∞" => OnePoint ℚ namespace Rat -variable {p q : ℚ} {s t : Set ℚ} +variable {p : ℚ} {s : Set ℚ} theorem interior_compact_eq_empty (hs : IsCompact s) : interior s = ∅ := isDenseEmbedding_coe_real.toIsDenseInducing.interior_compact_eq_empty dense_irrational hs @@ -72,7 +72,7 @@ theorem not_secondCountableTopology_opc : ¬SecondCountableTopology ℚ∞ := by exact not_firstCountableTopology_opc inferInstance instance : TotallyDisconnectedSpace ℚ := by - clear p q s t + clear p s refine ⟨fun s hsu hs x hx y hy => ?_⟩; clear hsu by_contra! H : x ≠ y wlog hlt : x < y diff --git a/Mathlib/Topology/Instances/Real.lean b/Mathlib/Topology/Instances/Real.lean index 16325c2f3e0ab..38e3de8b03bad 100644 --- a/Mathlib/Topology/Instances/Real.lean +++ b/Mathlib/Topology/Instances/Real.lean @@ -3,8 +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 -/ -import Mathlib.Algebra.Module.Rat -import Mathlib.Algebra.Module.Submodule.Lattice import Mathlib.Algebra.Periodic import Mathlib.Data.Real.Star import Mathlib.Topology.Algebra.Order.Archimedean @@ -12,13 +10,15 @@ import Mathlib.Topology.Algebra.Order.Field import Mathlib.Topology.Algebra.Star import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Topology.Instances.Int -import Mathlib.Topology.Metrizable.Basic import Mathlib.Topology.Order.Bornology +import Mathlib.Topology.Algebra.UniformGroup.Defs /-! # Topological properties of ℝ -/ +assert_not_exists UniformOnFun + noncomputable section open Filter Int Metric Set TopologicalSpace Bornology @@ -28,7 +28,7 @@ universe u v w variable {α : Type u} {β : Type v} {γ : Type w} -instance : NoncompactSpace ℝ := Int.closedEmbedding_coe_real.noncompactSpace +instance : NoncompactSpace ℝ := Int.isClosedEmbedding_coe_real.noncompactSpace theorem Real.uniformContinuous_add : UniformContinuous fun p : ℝ × ℝ => p.1 + p.2 := Metric.uniformContinuous_iff.2 fun _ε ε0 => @@ -61,13 +61,13 @@ instance : SecondCountableTopology ℝ := secondCountable_of_proper theorem Real.isTopologicalBasis_Ioo_rat : @IsTopologicalBasis ℝ _ (⋃ (a : ℚ) (b : ℚ) (_ : a < b), {Ioo (a : ℝ) b}) := isTopologicalBasis_of_isOpen_of_nhds (by simp (config := { contextual := true }) [isOpen_Ioo]) - fun a v hav hv => - let ⟨l, u, ⟨hl, hu⟩, h⟩ := mem_nhds_iff_exists_Ioo_subset.mp (IsOpen.mem_nhds hv hav) + fun a _ hav hv => + let ⟨_, _, ⟨hl, hu⟩, h⟩ := mem_nhds_iff_exists_Ioo_subset.mp (IsOpen.mem_nhds hv hav) let ⟨q, hlq, hqa⟩ := exists_rat_btwn hl let ⟨p, hap, hpu⟩ := exists_rat_btwn hu ⟨Ioo q p, by simp only [mem_iUnion] - exact ⟨q, p, Rat.cast_lt.1 <| hqa.trans hap, rfl⟩, ⟨hqa, hap⟩, fun a' ⟨hqa', ha'p⟩ => + exact ⟨q, p, Rat.cast_lt.1 <| hqa.trans hap, rfl⟩, ⟨hqa, hap⟩, fun _ ⟨hqa', ha'p⟩ => h ⟨hlq.trans hqa', ha'p.trans hpu⟩⟩ @[simp] @@ -142,7 +142,7 @@ theorem closure_of_rat_image_lt {q : ℚ} : Subset.antisymm (isClosed_Ici.closure_subset_iff.2 (image_subset_iff.2 fun p (h : q < p) => by simpa using h.le)) - fun x hx => mem_closure_iff_nhds.2 fun t ht => + fun x hx => mem_closure_iff_nhds.2 fun _ ht => let ⟨ε, ε0, hε⟩ := Metric.mem_nhds_iff.1 ht let ⟨p, h₁, h₂⟩ := exists_rat_btwn ((lt_add_iff_pos_right x).2 ε0) ⟨p, hε <| by rwa [mem_ball, Real.dist_eq, abs_of_pos (sub_pos.2 h₁), sub_lt_iff_lt_add'], @@ -184,49 +184,3 @@ theorem Periodic.isBounded_of_continuous [PseudoMetricSpace α] {f : ℝ → α} end Function end Periodic - -section Subgroups - -namespace Int - -open Metric - -/-- This is a special case of `NormedSpace.discreteTopology_zmultiples`. It exists only to simplify -dependencies. -/ -instance {a : ℝ} : DiscreteTopology (AddSubgroup.zmultiples a) := by - rcases eq_or_ne a 0 with (rfl | ha) - · rw [AddSubgroup.zmultiples_zero_eq_bot] - exact Subsingleton.discreteTopology (α := (⊥ : Submodule ℤ ℝ)) - rw [discreteTopology_iff_isOpen_singleton_zero, isOpen_induced_iff] - refine ⟨ball 0 |a|, isOpen_ball, ?_⟩ - ext ⟨x, hx⟩ - obtain ⟨k, rfl⟩ := AddSubgroup.mem_zmultiples_iff.mp hx - simp [ha, Real.dist_eq, abs_mul, (by norm_cast : |(k : ℝ)| < 1 ↔ |k| < 1)] - -/-- Under the coercion from `ℤ` to `ℝ`, inverse images of compact sets are finite. -/ -theorem tendsto_coe_cofinite : Tendsto ((↑) : ℤ → ℝ) cofinite (cocompact ℝ) := by - apply (castAddHom ℝ).tendsto_coe_cofinite_of_discrete cast_injective - rw [range_castAddHom] - infer_instance - -/-- For nonzero `a`, the "multiples of `a`" map `zmultiplesHom` from `ℤ` to `ℝ` is discrete, i.e. -inverse images of compact sets are finite. -/ -theorem tendsto_zmultiplesHom_cofinite {a : ℝ} (ha : a ≠ 0) : - Tendsto (zmultiplesHom ℝ a) cofinite (cocompact ℝ) := by - apply (zmultiplesHom ℝ a).tendsto_coe_cofinite_of_discrete <| smul_left_injective ℤ ha - rw [AddSubgroup.range_zmultiplesHom] - infer_instance - -end Int - -namespace AddSubgroup - -/-- The subgroup "multiples of `a`" (`zmultiples a`) is a discrete subgroup of `ℝ`, i.e. its -intersection with compact sets is finite. -/ -theorem tendsto_zmultiples_subtype_cofinite (a : ℝ) : - Tendsto (zmultiples a).subtype cofinite (cocompact ℝ) := - (zmultiples a).tendsto_coe_cofinite_of_discrete - -end AddSubgroup - -end Subgroups diff --git a/Mathlib/Topology/Instances/TrivSqZeroExt.lean b/Mathlib/Topology/Instances/TrivSqZeroExt.lean index 0868eabcd9e01..1ef2a9105f02b 100644 --- a/Mathlib/Topology/Instances/TrivSqZeroExt.lean +++ b/Mathlib/Topology/Instances/TrivSqZeroExt.lean @@ -63,11 +63,17 @@ theorem continuous_inl [Zero M] : Continuous (inl : R → tsze R M) := theorem continuous_inr [Zero R] : Continuous (inr : M → tsze R M) := continuous_const.prod_mk continuous_id -theorem embedding_inl [Zero M] : Embedding (inl : R → tsze R M) := - embedding_of_embedding_compose continuous_inl continuous_fst embedding_id +theorem IsEmbedding.inl [Zero M] : IsEmbedding (inl : R → tsze R M) := + .of_comp continuous_inl continuous_fst .id -theorem embedding_inr [Zero R] : Embedding (inr : M → tsze R M) := - embedding_of_embedding_compose continuous_inr continuous_snd embedding_id +@[deprecated (since := "2024-10-26")] +alias embedding_inl := IsEmbedding.inl + +theorem IsEmbedding.inr [Zero R] : IsEmbedding (inr : M → tsze R M) := + .of_comp continuous_inr continuous_snd .id + +@[deprecated (since := "2024-10-26")] +alias embedding_inr := IsEmbedding.inr variable (R M) diff --git a/Mathlib/Topology/Instances/ZMultiples.lean b/Mathlib/Topology/Instances/ZMultiples.lean new file mode 100644 index 0000000000000..59324feb87ba2 --- /dev/null +++ b/Mathlib/Topology/Instances/ZMultiples.lean @@ -0,0 +1,76 @@ +/- +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.Module.Rat +import Mathlib.Algebra.Module.Submodule.Lattice +import Mathlib.Algebra.Periodic +import Mathlib.Data.Real.Star +import Mathlib.Topology.Algebra.Order.Archimedean +import Mathlib.Topology.Algebra.Order.Field +import Mathlib.Topology.Algebra.Star +import Mathlib.Topology.Algebra.UniformMulAction +import Mathlib.Topology.Instances.Int +import Mathlib.Topology.Metrizable.Basic +import Mathlib.Topology.Order.Bornology +import Mathlib.Topology.Algebra.UniformGroup.Defs +import Mathlib.Topology.Instances.Real +import Mathlib.Topology.Algebra.UniformGroup.Basic + +/-! +The subgroup "multiples of `a`" (`zmultiples a`) is a discrete subgroup of `ℝ`, i.e. its +intersection with compact sets is finite. +-/ + + +noncomputable section + +open Filter Int Metric Set TopologicalSpace Bornology +open scoped Topology Uniformity Interval + +universe u v w + +variable {α : Type u} {β : Type v} {γ : Type w} + +namespace Int + +open Metric + +/-- This is a special case of `NormedSpace.discreteTopology_zmultiples`. It exists only to simplify +dependencies. -/ +instance {a : ℝ} : DiscreteTopology (AddSubgroup.zmultiples a) := by + rcases eq_or_ne a 0 with (rfl | ha) + · rw [AddSubgroup.zmultiples_zero_eq_bot] + exact Subsingleton.discreteTopology (α := (⊥ : Submodule ℤ ℝ)) + rw [discreteTopology_iff_isOpen_singleton_zero, isOpen_induced_iff] + refine ⟨ball 0 |a|, isOpen_ball, ?_⟩ + ext ⟨x, hx⟩ + obtain ⟨k, rfl⟩ := AddSubgroup.mem_zmultiples_iff.mp hx + simp [ha, Real.dist_eq, abs_mul, (by norm_cast : |(k : ℝ)| < 1 ↔ |k| < 1)] + +/-- Under the coercion from `ℤ` to `ℝ`, inverse images of compact sets are finite. -/ +theorem tendsto_coe_cofinite : Tendsto ((↑) : ℤ → ℝ) cofinite (cocompact ℝ) := by + apply (castAddHom ℝ).tendsto_coe_cofinite_of_discrete cast_injective + rw [range_castAddHom] + infer_instance + +/-- For nonzero `a`, the "multiples of `a`" map `zmultiplesHom` from `ℤ` to `ℝ` is discrete, i.e. +inverse images of compact sets are finite. -/ +theorem tendsto_zmultiplesHom_cofinite {a : ℝ} (ha : a ≠ 0) : + Tendsto (zmultiplesHom ℝ a) cofinite (cocompact ℝ) := by + apply (zmultiplesHom ℝ a).tendsto_coe_cofinite_of_discrete <| smul_left_injective ℤ ha + rw [AddSubgroup.range_zmultiplesHom] + infer_instance + +end Int + +namespace AddSubgroup + +/-- The subgroup "multiples of `a`" (`zmultiples a`) is a discrete subgroup of `ℝ`, i.e. its +intersection with compact sets is finite. -/ +theorem tendsto_zmultiples_subtype_cofinite (a : ℝ) : + Tendsto (zmultiples a).subtype cofinite (cocompact ℝ) := + (zmultiples a).tendsto_coe_cofinite_of_discrete + +end AddSubgroup diff --git a/Mathlib/Topology/Irreducible.lean b/Mathlib/Topology/Irreducible.lean index 8a868fe36faa7..4855d9e0f6e57 100644 --- a/Mathlib/Topology/Irreducible.lean +++ b/Mathlib/Topology/Irreducible.lean @@ -212,6 +212,11 @@ instance (priority := 100) {X} [Infinite X] : IrreducibleSpace (CofiniteTopology simpa only [compl_union, compl_compl] using ((hu hu').union (hv hv')).infinite_compl.nonempty toNonempty := (inferInstance : Nonempty X) +theorem irreducibleComponents_eq_singleton [IrreducibleSpace X] : + irreducibleComponents X = {univ} := + Set.ext fun _ ↦ IsGreatest.maximal_iff (s := IsIrreducible (X := X)) + ⟨IrreducibleSpace.isIrreducible_univ X, fun _ _ ↦ Set.subset_univ _⟩ + /-- A set `s` is irreducible if and only if for every finite collection of open sets all of whose members intersect `s`, `s` also intersects the intersection of the entire collection @@ -292,7 +297,7 @@ theorem IsPreirreducible.interior (ht : IsPreirreducible t) : IsPreirreducible ( ht.open_subset isOpen_interior interior_subset theorem IsPreirreducible.preimage (ht : IsPreirreducible t) {f : Y → X} - (hf : OpenEmbedding f) : IsPreirreducible (f ⁻¹' t) := by + (hf : IsOpenEmbedding f) : IsPreirreducible (f ⁻¹' t) := by rintro U V hU hV ⟨x, hx, hx'⟩ ⟨y, hy, hy'⟩ obtain ⟨_, h₁, ⟨y, h₂, rfl⟩, ⟨y', h₃, h₄⟩⟩ := ht _ _ (hf.isOpenMap _ hU) (hf.isOpenMap _ hV) ⟨f x, hx, Set.mem_image_of_mem f hx'⟩ diff --git a/Mathlib/Topology/IsLocalHomeomorph.lean b/Mathlib/Topology/IsLocalHomeomorph.lean index 6351032d8967e..fc16679217147 100644 --- a/Mathlib/Topology/IsLocalHomeomorph.lean +++ b/Mathlib/Topology/IsLocalHomeomorph.lean @@ -39,22 +39,26 @@ the source of some `e : PartialHomeomorph X Y` with `f = e`. -/ def IsLocalHomeomorphOn := ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ f = e -theorem isLocalHomeomorphOn_iff_openEmbedding_restrict {f : X → Y} : - IsLocalHomeomorphOn f s ↔ ∀ x ∈ s, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by +theorem isLocalHomeomorphOn_iff_isOpenEmbedding_restrict {f : X → Y} : + IsLocalHomeomorphOn f s ↔ ∀ x ∈ s, ∃ U ∈ 𝓝 x, IsOpenEmbedding (U.restrict f) := by refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩ · obtain ⟨e, hxe, rfl⟩ := h x hx - exact ⟨e.source, e.open_source.mem_nhds hxe, e.openEmbedding_restrict⟩ + exact ⟨e.source, e.open_source.mem_nhds hxe, e.isOpenEmbedding_restrict⟩ · obtain ⟨U, hU, emb⟩ := h x hx - have : OpenEmbedding ((interior U).restrict f) := by - refine emb.comp ⟨embedding_inclusion interior_subset, ?_⟩ + have : IsOpenEmbedding ((interior U).restrict f) := by + refine emb.comp ⟨.inclusion interior_subset, ?_⟩ rw [Set.range_inclusion]; exact isOpen_induced isOpen_interior - obtain ⟨cont, inj, openMap⟩ := openEmbedding_iff_continuous_injective_open.mp this + obtain ⟨cont, inj, openMap⟩ := isOpenEmbedding_iff_continuous_injective_open.mp this haveI : Nonempty X := ⟨x⟩ exact ⟨PartialHomeomorph.ofContinuousOpenRestrict (Set.injOn_iff_injective.mpr inj).toPartialEquiv (continuousOn_iff_continuous_restrict.mpr cont) openMap isOpen_interior, mem_interior_iff_mem_nhds.mpr hU, rfl⟩ +@[deprecated (since := "2024-10-18")] +alias isLocalHomeomorphOn_iff_openEmbedding_restrict := + isLocalHomeomorphOn_iff_isOpenEmbedding_restrict + namespace IsLocalHomeomorphOn /-- Proves that `f` satisfies `IsLocalHomeomorphOn f s`. The condition `h` is weaker than the @@ -113,7 +117,7 @@ protected theorem continuousAt (hf : IsLocalHomeomorphOn f s) {x : X} (hx : x (hf.map_nhds_eq hx).le protected theorem continuousOn (hf : IsLocalHomeomorphOn f s) : ContinuousOn f s := - ContinuousAt.continuousOn fun _x ↦ hf.continuousAt + continuousOn_of_forall_continuousAt fun _x ↦ hf.continuousAt protected theorem comp (hg : IsLocalHomeomorphOn g t) (hf : IsLocalHomeomorphOn f s) (h : Set.MapsTo f s t) : IsLocalHomeomorphOn (g ∘ f) s := by @@ -141,14 +145,20 @@ theorem isLocalHomeomorph_iff_isLocalHomeomorphOn_univ : protected theorem IsLocalHomeomorph.isLocalHomeomorphOn (hf : IsLocalHomeomorph f) : IsLocalHomeomorphOn f s := fun x _ ↦ hf x -theorem isLocalHomeomorph_iff_openEmbedding_restrict {f : X → Y} : - IsLocalHomeomorph f ↔ ∀ x : X, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by +theorem isLocalHomeomorph_iff_isOpenEmbedding_restrict {f : X → Y} : + IsLocalHomeomorph f ↔ ∀ x : X, ∃ U ∈ 𝓝 x, IsOpenEmbedding (U.restrict f) := by simp_rw [isLocalHomeomorph_iff_isLocalHomeomorphOn_univ, - isLocalHomeomorphOn_iff_openEmbedding_restrict, imp_iff_right (Set.mem_univ _)] + isLocalHomeomorphOn_iff_isOpenEmbedding_restrict, imp_iff_right (Set.mem_univ _)] + +@[deprecated (since := "2024-10-18")] +alias isLocalHomeomorph_iff_openEmbedding_restrict := isLocalHomeomorph_iff_isOpenEmbedding_restrict + +theorem IsOpenEmbedding.isLocalHomeomorph (hf : IsOpenEmbedding f) : IsLocalHomeomorph f := + isLocalHomeomorph_iff_isOpenEmbedding_restrict.mpr fun _ ↦ + ⟨_, Filter.univ_mem, hf.comp (Homeomorph.Set.univ X).isOpenEmbedding⟩ -theorem OpenEmbedding.isLocalHomeomorph (hf : OpenEmbedding f) : IsLocalHomeomorph f := - isLocalHomeomorph_iff_openEmbedding_restrict.mpr fun _ ↦ - ⟨_, Filter.univ_mem, hf.comp (Homeomorph.Set.univ X).openEmbedding⟩ +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.isLocalHomeomorph := IsOpenEmbedding.isLocalHomeomorph variable (f) @@ -194,15 +204,21 @@ protected theorem comp (hg : IsLocalHomeomorph g) (hf : IsLocalHomeomorph f) : (hg.isLocalHomeomorphOn.comp hf.isLocalHomeomorphOn (Set.univ.mapsTo_univ f)) /-- An injective local homeomorphism is an open embedding. -/ -theorem openEmbedding_of_injective (hf : IsLocalHomeomorph f) (hi : f.Injective) : - OpenEmbedding f := - openEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap +theorem isOpenEmbedding_of_injective (hf : IsLocalHomeomorph f) (hi : f.Injective) : + IsOpenEmbedding f := + isOpenEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_of_injective := isOpenEmbedding_of_injective /-- A surjective embedding is a homeomorphism. -/ -noncomputable def _root_.Embedding.toHomeomeomorph_of_surjective (hf : Embedding f) +noncomputable def _root_.IsEmbedding.toHomeomorph_of_surjective (hf : IsEmbedding f) (hsurj : Function.Surjective f) : X ≃ₜ Y := Homeomorph.homeomorphOfContinuousOpen (Equiv.ofBijective f ⟨hf.inj, hsurj⟩) - hf.continuous (hf.toOpenEmbedding_of_surjective hsurj).isOpenMap + hf.continuous (hf.isOpenEmbedding_of_surjective hsurj).isOpenMap + +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.toHomeomeomorph_of_surjective := IsEmbedding.toHomeomorph_of_surjective /-- A bijective local homeomorphism is a homeomorphism. -/ noncomputable def toHomeomorph_of_bijective (hf : IsLocalHomeomorph f) (hb : f.Bijective) : @@ -210,9 +226,12 @@ noncomputable def toHomeomorph_of_bijective (hf : IsLocalHomeomorph f) (hb : f.B Homeomorph.homeomorphOfContinuousOpen (Equiv.ofBijective f hb) hf.continuous hf.isOpenMap /-- Continuous local sections of a local homeomorphism are open embeddings. -/ -theorem openEmbedding_of_comp (hf : IsLocalHomeomorph g) (hgf : OpenEmbedding (g ∘ f)) - (cont : Continuous f) : OpenEmbedding f := - (hgf.isLocalHomeomorph.of_comp hf cont).openEmbedding_of_injective hgf.inj.of_comp +theorem isOpenEmbedding_of_comp (hf : IsLocalHomeomorph g) (hgf : IsOpenEmbedding (g ∘ f)) + (cont : Continuous f) : IsOpenEmbedding f := + (hgf.isLocalHomeomorph.of_comp hf cont).isOpenEmbedding_of_injective hgf.inj.of_comp + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_of_comp := isOpenEmbedding_of_comp open TopologicalSpace in /-- Ranges of continuous local sections of a local homeomorphism @@ -221,7 +240,8 @@ theorem isTopologicalBasis (hf : IsLocalHomeomorph f) : IsTopologicalBasis {U : Set X | ∃ V : Set Y, IsOpen V ∧ ∃ s : C(V,X), f ∘ s = (↑) ∧ Set.range s = U} := by refine isTopologicalBasis_of_isOpen_of_nhds ?_ fun x U hx hU ↦ ?_ · rintro _ ⟨U, hU, s, hs, rfl⟩ - refine (openEmbedding_of_comp hf (hs ▸ ⟨embedding_subtype_val, ?_⟩) s.continuous).isOpen_range + refine (isOpenEmbedding_of_comp hf (hs ▸ ⟨IsEmbedding.subtypeVal, ?_⟩) + s.continuous).isOpen_range rwa [Subtype.range_val] · obtain ⟨f, hxf, rfl⟩ := hf x refine ⟨f.source ∩ U, ⟨f.target ∩ f.symm ⁻¹' U, f.symm.isOpen_inter_preimage hU, diff --git a/Mathlib/Topology/JacobsonSpace.lean b/Mathlib/Topology/JacobsonSpace.lean new file mode 100644 index 0000000000000..026f3d5e6a8de --- /dev/null +++ b/Mathlib/Topology/JacobsonSpace.lean @@ -0,0 +1,176 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.Topology.LocalAtTarget +import Mathlib.Topology.Separation.Basic +import Mathlib.Tactic.StacksAttribute + +/-! + +# Jacobson spaces + +## Main results +- `JacobsonSpace`: The class of jacobson spaces, i.e. + spaces such that the set of closed points are dense in every closed subspace. +- `jacobsonSpace_iff_locallyClosed`: + `X` is a jacobson space iff every locally closed subset contains a closed point of `X`. +- `JacobsonSpace.discreteTopology`: + If `X` only has finitely many closed points, then the topology on `X` is discrete. + +## References +- https://stacks.math.columbia.edu/tag/005T + +-/ + + +variable (X) {Y} [TopologicalSpace X] [TopologicalSpace Y] {f : X → Y} + +section closedPoints + +/-- The set of closed points. -/ +def closedPoints : Set X := setOf (IsClosed {·}) + +variable {X} + +@[simp] +lemma mem_closedPoints_iff {x} : x ∈ closedPoints X ↔ IsClosed {x} := Iff.rfl + +lemma preimage_closedPoints_subset (hf : Function.Injective f) (hf' : Continuous f) : + f ⁻¹' closedPoints Y ⊆ closedPoints X := by + intros x hx + rw [mem_closedPoints_iff] + convert continuous_iff_isClosed.mp hf' _ hx + rw [← Set.image_singleton, Set.preimage_image_eq _ hf] + +lemma IsClosedEmbedding.preimage_closedPoints (hf : IsClosedEmbedding f) : + f ⁻¹' closedPoints Y = closedPoints X := by + ext x + simp [mem_closedPoints_iff, ← Set.image_singleton, hf.closed_iff_image_closed] + +lemma closedPoints_eq_univ [T2Space X] : + closedPoints X = Set.univ := + Set.eq_univ_iff_forall.mpr fun _ ↦ isClosed_singleton + +end closedPoints + +/-- The class of jacobson spaces, i.e. +spaces such that the set of closed points are dense in every closed subspace. -/ +@[mk_iff, stacks 005U] +class JacobsonSpace : Prop where + closure_inter_closedPoints : ∀ {Z}, IsClosed Z → closure (Z ∩ closedPoints X) = Z + +export JacobsonSpace (closure_inter_closedPoints) + +variable {X} + +lemma closure_closedPoints [JacobsonSpace X] : closure (closedPoints X) = Set.univ := by + simpa using closure_inter_closedPoints isClosed_univ + +lemma jacobsonSpace_iff_locallyClosed : + JacobsonSpace X ↔ ∀ Z, Z.Nonempty → IsLocallyClosed Z → (Z ∩ closedPoints X).Nonempty := by + rw [jacobsonSpace_iff] + constructor + · simp_rw [isLocallyClosed_iff_isOpen_coborder, coborder, isOpen_compl_iff, + Set.nonempty_iff_ne_empty] + intros H Z hZ hZ' e + have : Z ⊆ closure Z \ Z := by + refine subset_closure.trans ?_ + nth_rw 1 [← H isClosed_closure] + rw [hZ'.closure_subset_iff, Set.subset_diff, Set.disjoint_iff, Set.inter_assoc, + Set.inter_comm _ Z, e] + exact ⟨Set.inter_subset_left, Set.inter_subset_right⟩ + rw [Set.subset_diff, disjoint_self, Set.bot_eq_empty] at this + exact hZ this.2 + · intro H Z hZ + refine subset_antisymm (hZ.closure_subset_iff.mpr Set.inter_subset_left) ?_ + rw [← Set.disjoint_compl_left_iff_subset, Set.disjoint_iff_inter_eq_empty, + ← Set.not_nonempty_iff_eq_empty] + intro H' + have := H _ H' (isClosed_closure.isOpen_compl.isLocallyClosed.inter hZ.isLocallyClosed) + rw [Set.nonempty_iff_ne_empty, Set.inter_assoc, ne_eq, + ← Set.disjoint_iff_inter_eq_empty, Set.disjoint_compl_left_iff_subset] at this + exact this subset_closure + +lemma nonempty_inter_closedPoints [JacobsonSpace X] {Z : Set X} + (hZ : Z.Nonempty) (hZ' : IsLocallyClosed Z) : (Z ∩ closedPoints X).Nonempty := + jacobsonSpace_iff_locallyClosed.mp inferInstance Z hZ hZ' + +lemma isClosed_singleton_of_isLocallyClosed_singleton [JacobsonSpace X] {x : X} + (hx : IsLocallyClosed {x}) : IsClosed {x} := by + obtain ⟨_, ⟨y, rfl : y = x, rfl⟩, hy'⟩ := + nonempty_inter_closedPoints (Set.singleton_nonempty x) hx + exact hy' + +lemma IsOpenEmbedding.preimage_closedPoints (hf : IsOpenEmbedding f) [JacobsonSpace Y] : + f ⁻¹' closedPoints Y = closedPoints X := by + apply subset_antisymm (preimage_closedPoints_subset hf.inj hf.continuous) + intros x hx + apply isClosed_singleton_of_isLocallyClosed_singleton + rw [← Set.image_singleton] + exact (hx.isLocallyClosed.image hf.isInducing hf.isOpen_range.isLocallyClosed) + +lemma JacobsonSpace.of_isOpenEmbedding [JacobsonSpace Y] (hf : IsOpenEmbedding f) : + JacobsonSpace X := by + rw [jacobsonSpace_iff_locallyClosed, ← hf.preimage_closedPoints] + intros Z hZ hZ' + obtain ⟨_, ⟨x, hx, rfl⟩, hx'⟩ := nonempty_inter_closedPoints + (hZ.image f) (hZ'.image hf.isInducing hf.isOpen_range.isLocallyClosed) + exact ⟨_, hx, hx'⟩ + +lemma JacobsonSpace.of_isClosedEmbedding [JacobsonSpace Y] (hf : IsClosedEmbedding f) : + JacobsonSpace X := by + rw [jacobsonSpace_iff_locallyClosed, ← hf.preimage_closedPoints] + intros Z hZ hZ' + obtain ⟨_, ⟨x, hx, rfl⟩, hx'⟩ := nonempty_inter_closedPoints + (hZ.image f) (hZ'.image hf.isInducing hf.isClosed_range.isLocallyClosed) + exact ⟨_, hx, hx'⟩ + +lemma JacobsonSpace.discreteTopology [JacobsonSpace X] + (h : (closedPoints X).Finite) : DiscreteTopology X := by + have : closedPoints X = Set.univ := by + rw [← Set.univ_subset_iff, ← closure_closedPoints, + closure_subset_iff_isClosed, ← (closedPoints X).biUnion_of_singleton] + exact h.isClosed_biUnion fun _ ↦ id + have inst : Finite X := Set.finite_univ_iff.mp (this ▸ h) + rw [← forall_open_iff_discrete] + intro s + rw [← isClosed_compl_iff, ← sᶜ.biUnion_of_singleton] + refine sᶜ.toFinite.isClosed_biUnion fun x _ ↦ ?_ + rw [← mem_closedPoints_iff, this] + trivial + +instance (priority := 100) [Finite X] [JacobsonSpace X] : DiscreteTopology X := + JacobsonSpace.discreteTopology (Set.toFinite _) + +instance (priority := 100) [T2Space X] : JacobsonSpace X := + ⟨by simp [closedPoints_eq_univ, closure_eq_iff_isClosed]⟩ + +open TopologicalSpace in +lemma jacobsonSpace_iff_of_iSup_eq_top {ι : Type*} {U : ι → Opens X} (hU : iSup U = ⊤) : + JacobsonSpace X ↔ ∀ i, JacobsonSpace (U i) := by + refine ⟨fun H i ↦ .of_isOpenEmbedding (U i).2.isOpenEmbedding_subtypeVal, fun H ↦ ?_⟩ + rw [jacobsonSpace_iff_locallyClosed] + intros Z hZ hZ' + have : (⋃ i, (U i : Set X)) = Set.univ := by rw [← Opens.coe_iSup]; injection hU + have : (⋃ i, Z ∩ U i) = Z := by rw [← Set.inter_iUnion, this, Set.inter_univ] + rw [← this, Set.nonempty_iUnion] at hZ + obtain ⟨i, x, hx, hx'⟩ := hZ + obtain ⟨y, hy, hy'⟩ := (jacobsonSpace_iff_locallyClosed.mp (H i)) (Subtype.val ⁻¹' Z) + ⟨⟨x, hx'⟩, hx⟩ (hZ'.preimage continuous_subtype_val) + refine ⟨y, hy, (isClosed_iff_coe_preimage_of_iSup_eq_top hU _).mpr fun j ↦ ?_⟩ + by_cases h : (y : X) ∈ U j + · convert_to IsClosed {(⟨y, h⟩ : U j)} + · ext z; exact @Subtype.coe_inj _ _ z ⟨y, h⟩ + apply isClosed_singleton_of_isLocallyClosed_singleton + convert (hy'.isLocallyClosed.image IsEmbedding.subtypeVal.isInducing + (U i).2.isOpenEmbedding_subtypeVal.isOpen_range.isLocallyClosed).preimage + continuous_subtype_val + rw [Set.image_singleton] + ext z + exact (@Subtype.coe_inj _ _ z ⟨y, h⟩).symm + · convert isClosed_empty + rw [Set.eq_empty_iff_forall_not_mem] + intro z (hz : z.1 = y.1) + exact h (hz ▸ z.2) diff --git a/Mathlib/Topology/KrullDimension.lean b/Mathlib/Topology/KrullDimension.lean index b5eee2e982ae4..9a25326df9e83 100644 --- a/Mathlib/Topology/KrullDimension.lean +++ b/Mathlib/Topology/KrullDimension.lean @@ -40,7 +40,7 @@ def IrreducibleCloseds.map {f : X → Y} (hf1 : Continuous f) (hf2 : IsClosedMap /-- Taking images under a closed embedding is strictly monotone on the preorder of irreducible closeds. -/ -lemma IrreducibleCloseds.map_strictMono {f : X → Y} (hf : ClosedEmbedding f) : +lemma IrreducibleCloseds.map_strictMono {f : X → Y} (hf : IsClosedEmbedding f) : StrictMono (IrreducibleCloseds.map hf.continuous hf.isClosedMap) := fun ⦃_ _⦄ UltV ↦ hf.inj.image_strictMono UltV @@ -48,16 +48,19 @@ lemma IrreducibleCloseds.map_strictMono {f : X → Y} (hf : ClosedEmbedding f) : If `f : X → Y` is a closed embedding, then the Krull dimension of `X` is less than or equal to the Krull dimension of `Y`. -/ -theorem ClosedEmbedding.topologicalKrullDim_le (f : X → Y) (hf : ClosedEmbedding f) : +theorem IsClosedEmbedding.topologicalKrullDim_le (f : X → Y) (hf : IsClosedEmbedding f) : topologicalKrullDim X ≤ topologicalKrullDim Y := krullDim_le_of_strictMono _ (IrreducibleCloseds.map_strictMono hf) +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.topologicalKrullDim_le := IsClosedEmbedding.topologicalKrullDim_le + /-- The topological Krull dimension is invariant under homeomorphisms -/ theorem IsHomeomorph.topologicalKrullDim_eq (f : X → Y) (h : IsHomeomorph f) : topologicalKrullDim X = topologicalKrullDim Y := have fwd : topologicalKrullDim X ≤ topologicalKrullDim Y := - ClosedEmbedding.topologicalKrullDim_le f h.closedEmbedding + IsClosedEmbedding.topologicalKrullDim_le f h.isClosedEmbedding have bwd : topologicalKrullDim Y ≤ topologicalKrullDim X := - ClosedEmbedding.topologicalKrullDim_le (h.homeomorph f).symm - (h.homeomorph f).symm.closedEmbedding + IsClosedEmbedding.topologicalKrullDim_le (h.homeomorph f).symm + (h.homeomorph f).symm.isClosedEmbedding le_antisymm fwd bwd diff --git a/Mathlib/Topology/List.lean b/Mathlib/Topology/List.lean index f9e3f9ddbdfc3..fd9df79a1b592 100644 --- a/Mathlib/Topology/List.lean +++ b/Mathlib/Topology/List.lean @@ -115,10 +115,11 @@ theorem continuousAt_length : ∀ l : List α, ContinuousAt List.length l := by refine Tendsto.comp (tendsto_pure_pure (fun x => x + 1) _) ?_ exact Tendsto.comp ih tendsto_snd -theorem tendsto_insertNth' {a : α} : +/-- Continuity of `insertIdx` in terms of `Tendsto`. -/ +theorem tendsto_insertIdx' {a : α} : ∀ {n : ℕ} {l : List α}, - Tendsto (fun p : α × List α => insertNth n p.1 p.2) (𝓝 a ×ˢ 𝓝 l) (𝓝 (insertNth n a l)) - | 0, l => tendsto_cons + Tendsto (fun p : α × List α => insertIdx n p.1 p.2) (𝓝 a ×ˢ 𝓝 l) (𝓝 (insertIdx n a l)) + | 0, _ => tendsto_cons | n + 1, [] => by simp | n + 1, a'::l => by have : 𝓝 a ×ˢ 𝓝 (a'::l) = @@ -128,16 +129,22 @@ theorem tendsto_insertNth' {a : α} : rw [this, tendsto_map'_iff] exact (tendsto_fst.comp tendsto_snd).cons - ((@tendsto_insertNth' _ n l).comp <| tendsto_fst.prod_mk <| tendsto_snd.comp tendsto_snd) + ((@tendsto_insertIdx' _ n l).comp <| tendsto_fst.prod_mk <| tendsto_snd.comp tendsto_snd) -theorem tendsto_insertNth {β} {n : ℕ} {a : α} {l : List α} {f : β → α} {g : β → List α} +@[deprecated (since := "2024-10-21")] alias tendsto_insertNth' := tendsto_insertIdx' + +theorem tendsto_insertIdx {β} {n : ℕ} {a : α} {l : List α} {f : β → α} {g : β → List α} {b : Filter β} (hf : Tendsto f b (𝓝 a)) (hg : Tendsto g b (𝓝 l)) : - Tendsto (fun b : β => insertNth n (f b) (g b)) b (𝓝 (insertNth n a l)) := - tendsto_insertNth'.comp (Tendsto.prod_mk hf hg) + Tendsto (fun b : β => insertIdx n (f b) (g b)) b (𝓝 (insertIdx n a l)) := + tendsto_insertIdx'.comp (Tendsto.prod_mk hf hg) + +@[deprecated (since := "2024-10-21")] alias tendsto_insertNth := tendsto_insertIdx' -theorem continuous_insertNth {n : ℕ} : Continuous fun p : α × List α => insertNth n p.1 p.2 := +theorem continuous_insertIdx {n : ℕ} : Continuous fun p : α × List α => insertIdx n p.1 p.2 := continuous_iff_continuousAt.mpr fun ⟨a, l⟩ => by - rw [ContinuousAt, nhds_prod_eq]; exact tendsto_insertNth' + rw [ContinuousAt, nhds_prod_eq]; exact tendsto_insertIdx' + +@[deprecated (since := "2024-10-21")] alias continuous_insertNth := continuous_insertIdx theorem tendsto_eraseIdx : ∀ {n : ℕ} {l : List α}, Tendsto (eraseIdx · n) (𝓝 l) (𝓝 (eraseIdx l n)) @@ -184,23 +191,30 @@ theorem tendsto_cons {n : ℕ} {a : α} {l : Vector α n} : rw [tendsto_subtype_rng, Vector.cons_val] exact tendsto_fst.cons (Tendsto.comp continuousAt_subtype_val tendsto_snd) -theorem tendsto_insertNth {n : ℕ} {i : Fin (n + 1)} {a : α} : +theorem tendsto_insertIdx {n : ℕ} {i : Fin (n + 1)} {a : α} : ∀ {l : Vector α n}, - Tendsto (fun p : α × Vector α n => Vector.insertNth p.1 i p.2) (𝓝 a ×ˢ 𝓝 l) - (𝓝 (Vector.insertNth a i l)) + Tendsto (fun p : α × Vector α n => Vector.insertIdx p.1 i p.2) (𝓝 a ×ˢ 𝓝 l) + (𝓝 (Vector.insertIdx a i l)) | ⟨l, hl⟩ => by - rw [Vector.insertNth, tendsto_subtype_rng] - simp only [Vector.insertNth_val] - exact List.tendsto_insertNth tendsto_fst (Tendsto.comp continuousAt_subtype_val tendsto_snd : _) + rw [Vector.insertIdx, tendsto_subtype_rng] + simp only [Vector.insertIdx_val] + exact List.tendsto_insertIdx tendsto_fst (Tendsto.comp continuousAt_subtype_val tendsto_snd : _) -theorem continuous_insertNth' {n : ℕ} {i : Fin (n + 1)} : - Continuous fun p : α × Vector α n => Vector.insertNth p.1 i p.2 := +@[deprecated (since := "2024-10-21")] alias tendsto_insertNth := tendsto_insertIdx' + +/-- 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_iff_continuousAt.mpr fun ⟨a, l⟩ => by - rw [ContinuousAt, nhds_prod_eq]; exact tendsto_insertNth + 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} + (hf : Continuous f) (hg : Continuous g) : Continuous fun b => Vector.insertIdx (f b) i (g b) := + continuous_insertIdx'.comp (hf.prod_mk hg : _) -theorem continuous_insertNth {n : ℕ} {i : Fin (n + 1)} {f : β → α} {g : β → Vector α n} - (hf : Continuous f) (hg : Continuous g) : Continuous fun b => Vector.insertNth (f b) i (g b) := - continuous_insertNth'.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 diff --git a/Mathlib/Topology/LocalAtTarget.lean b/Mathlib/Topology/LocalAtTarget.lean index 5970438a142e8..93be91c747049 100644 --- a/Mathlib/Topology/LocalAtTarget.lean +++ b/Mathlib/Topology/LocalAtTarget.lean @@ -10,10 +10,10 @@ import Mathlib.Topology.LocallyClosed # Properties of maps that are local at the target. We show that the following properties of continuous maps are local at the target : -- `Inducing` -- `Embedding` -- `OpenEmbedding` -- `ClosedEmbedding` +- `IsInducing` +- `IsEmbedding` +- `IsOpenEmbedding` +- `IsClosedEmbedding` -/ @@ -23,36 +23,59 @@ open TopologicalSpace Set Filter open Topology Filter variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] {f : α → β} -variable {s : Set β} {ι : Type*} {U : ι → Opens β} +variable {ι : Type*} {U : ι → Opens β} -theorem Set.restrictPreimage_inducing (s : Set β) (h : Inducing f) : - Inducing (s.restrictPreimage f) := by - simp_rw [← inducing_subtype_val.of_comp_iff, inducing_iff_nhds, restrictPreimage, +theorem Set.restrictPreimage_isInducing (s : Set β) (h : IsInducing f) : + IsInducing (s.restrictPreimage f) := by + simp_rw [← IsInducing.subtypeVal.of_comp_iff, isInducing_iff_nhds, restrictPreimage, MapsTo.coe_restrict, restrict_eq, ← @Filter.comap_comap _ _ _ _ _ f, Function.comp_apply] at h ⊢ intro a - rw [← h, ← inducing_subtype_val.nhds_eq_comap] + rw [← h, ← IsInducing.subtypeVal.nhds_eq_comap] -alias Inducing.restrictPreimage := Set.restrictPreimage_inducing +@[deprecated (since := "2024-10-28")] +alias Set.restrictPreimage_inducing := Set.restrictPreimage_isInducing -theorem Set.restrictPreimage_embedding (s : Set β) (h : Embedding f) : - Embedding (s.restrictPreimage f) := +alias IsInducing.restrictPreimage := Set.restrictPreimage_isInducing + +@[deprecated (since := "2024-10-28")] alias Inducing.restrictPreimage := IsInducing.restrictPreimage + +theorem Set.restrictPreimage_isEmbedding (s : Set β) (h : IsEmbedding f) : + IsEmbedding (s.restrictPreimage f) := ⟨h.1.restrictPreimage s, h.2.restrictPreimage s⟩ -alias Embedding.restrictPreimage := Set.restrictPreimage_embedding +@[deprecated (since := "2024-10-26")] +alias Set.restrictPreimage_embedding := Set.restrictPreimage_isEmbedding + +alias IsEmbedding.restrictPreimage := Set.restrictPreimage_isEmbedding -theorem Set.restrictPreimage_openEmbedding (s : Set β) (h : OpenEmbedding f) : - OpenEmbedding (s.restrictPreimage f) := +@[deprecated (since := "2024-10-26")] +alias Embedding.restrictPreimage := IsEmbedding.restrictPreimage + +theorem Set.restrictPreimage_isOpenEmbedding (s : Set β) (h : IsOpenEmbedding f) : + IsOpenEmbedding (s.restrictPreimage f) := ⟨h.1.restrictPreimage s, (s.range_restrictPreimage f).symm ▸ continuous_subtype_val.isOpen_preimage _ h.isOpen_range⟩ -alias OpenEmbedding.restrictPreimage := Set.restrictPreimage_openEmbedding +@[deprecated (since := "2024-10-18")] +alias Set.restrictPreimage_openEmbedding := Set.restrictPreimage_isOpenEmbedding + +alias IsOpenEmbedding.restrictPreimage := Set.restrictPreimage_isOpenEmbedding + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.restrictPreimage := IsOpenEmbedding.restrictPreimage -theorem Set.restrictPreimage_closedEmbedding (s : Set β) (h : ClosedEmbedding f) : - ClosedEmbedding (s.restrictPreimage f) := +theorem Set.restrictPreimage_isClosedEmbedding (s : Set β) (h : IsClosedEmbedding f) : + IsClosedEmbedding (s.restrictPreimage f) := ⟨h.1.restrictPreimage s, - (s.range_restrictPreimage f).symm ▸ inducing_subtype_val.isClosed_preimage _ h.isClosed_range⟩ + (s.range_restrictPreimage f).symm ▸ IsInducing.subtypeVal.isClosed_preimage _ h.isClosed_range⟩ -alias ClosedEmbedding.restrictPreimage := Set.restrictPreimage_closedEmbedding +@[deprecated (since := "2024-10-20")] +alias Set.restrictPreimage_closedEmbedding := Set.restrictPreimage_isClosedEmbedding + +alias IsClosedEmbedding.restrictPreimage := Set.restrictPreimage_isClosedEmbedding + +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.restrictPreimage := IsClosedEmbedding.restrictPreimage theorem IsClosedMap.restrictPreimage (H : IsClosedMap f) (s : Set β) : IsClosedMap (s.restrictPreimage f) := by @@ -96,7 +119,7 @@ theorem isOpen_iff_coe_preimage_of_iSup_eq_top (s : Set β) : -- Porting note: rewrote to avoid ´simp´ issues rw [isOpen_iff_inter_of_iSup_eq_top hU s] refine forall_congr' fun i => ?_ - rw [(U _).2.openEmbedding_subtype_val.open_iff_image_open] + rw [(U _).2.isOpenEmbedding_subtypeVal.open_iff_image_open] erw [Set.image_preimage_eq_inter_range] rw [Subtype.range_coe, Opens.carrier_eq_coe] @@ -110,7 +133,7 @@ theorem isLocallyClosed_iff_coe_preimage_of_iSup_eq_top (s : Set β) : rw [isOpen_iff_coe_preimage_of_iSup_eq_top hU] exact forall_congr' fun i ↦ by have : coborder ((↑) ⁻¹' s : Set (U i)) = Subtype.val ⁻¹' coborder s := by - exact (U i).isOpen.openEmbedding_subtype_val.coborder_preimage _ + exact (U i).isOpen.isOpenEmbedding_subtypeVal.coborder_preimage _ rw [this] theorem isOpenMap_iff_isOpenMap_of_iSup_eq_top : @@ -138,26 +161,26 @@ theorem isClosedMap_iff_isClosedMap_of_iSup_eq_top : exact ⟨fun ⟨a, b, c⟩ => ⟨a, b, c.symm ▸ hx, c⟩, fun ⟨a, b, _, c⟩ => ⟨a, b, c⟩⟩ theorem inducing_iff_inducing_of_iSup_eq_top (h : Continuous f) : - Inducing f ↔ ∀ i, Inducing ((U i).1.restrictPreimage f) := by - simp_rw [← inducing_subtype_val.of_comp_iff, inducing_iff_nhds, restrictPreimage, + IsInducing f ↔ ∀ i, IsInducing ((U i).1.restrictPreimage f) := by + simp_rw [← IsInducing.subtypeVal.of_comp_iff, isInducing_iff_nhds, restrictPreimage, MapsTo.coe_restrict, restrict_eq, ← @Filter.comap_comap _ _ _ _ _ f] constructor · intro H i x - rw [Function.comp_apply, ← H, ← inducing_subtype_val.nhds_eq_comap] + rw [Function.comp_apply, ← H, ← IsInducing.subtypeVal.nhds_eq_comap] · intro H x obtain ⟨i, hi⟩ := Opens.mem_iSup.mp (show f x ∈ iSup U by rw [hU] trivial) - erw [← OpenEmbedding.map_nhds_eq (h.1 _ (U i).2).openEmbedding_subtype_val ⟨x, hi⟩] - rw [(H i) ⟨x, hi⟩, Filter.subtype_coe_map_comap, Function.comp_apply, Subtype.coe_mk, + rw [← IsOpenEmbedding.map_nhds_eq (h.1 _ (U i).2).isOpenEmbedding_subtypeVal ⟨x, hi⟩, + (H i) ⟨x, hi⟩, Filter.subtype_coe_map_comap, Function.comp_apply, Subtype.coe_mk, inf_eq_left, Filter.le_principal_iff] exact Filter.preimage_mem_comap ((U i).2.mem_nhds hi) -theorem embedding_iff_embedding_of_iSup_eq_top (h : Continuous f) : - Embedding f ↔ ∀ i, Embedding ((U i).1.restrictPreimage f) := by - simp_rw [embedding_iff] +theorem isEmbedding_iff_of_iSup_eq_top (h : Continuous f) : + IsEmbedding f ↔ ∀ i, IsEmbedding ((U i).1.restrictPreimage f) := by + simp_rw [isEmbedding_iff] rw [forall_and] apply and_congr · apply inducing_iff_inducing_of_iSup_eq_top <;> assumption @@ -165,20 +188,43 @@ theorem embedding_iff_embedding_of_iSup_eq_top (h : Continuous f) : convert congr_arg SetLike.coe hU simp -theorem openEmbedding_iff_openEmbedding_of_iSup_eq_top (h : Continuous f) : - OpenEmbedding f ↔ ∀ i, OpenEmbedding ((U i).1.restrictPreimage f) := by - simp_rw [openEmbedding_iff] +@[deprecated (since := "2024-10-26")] +alias embedding_iff_embedding_of_iSup_eq_top := isEmbedding_iff_of_iSup_eq_top + +theorem isOpenEmbedding_iff_isOpenEmbedding_of_iSup_eq_top (h : Continuous f) : + IsOpenEmbedding f ↔ ∀ i, IsOpenEmbedding ((U i).1.restrictPreimage f) := by + simp_rw [isOpenEmbedding_iff] rw [forall_and] apply and_congr - · apply embedding_iff_embedding_of_iSup_eq_top <;> assumption + · apply isEmbedding_iff_of_iSup_eq_top <;> assumption · simp_rw [Set.range_restrictPreimage] apply isOpen_iff_coe_preimage_of_iSup_eq_top hU -theorem closedEmbedding_iff_closedEmbedding_of_iSup_eq_top (h : Continuous f) : - ClosedEmbedding f ↔ ∀ i, ClosedEmbedding ((U i).1.restrictPreimage f) := by - simp_rw [closedEmbedding_iff] +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_openEmbedding_of_iSup_eq_top := + isOpenEmbedding_iff_isOpenEmbedding_of_iSup_eq_top + +theorem isClosedEmbedding_iff_isClosedEmbedding_of_iSup_eq_top (h : Continuous f) : + IsClosedEmbedding f ↔ ∀ i, IsClosedEmbedding ((U i).1.restrictPreimage f) := by + simp_rw [isClosedEmbedding_iff] rw [forall_and] apply and_congr - · apply embedding_iff_embedding_of_iSup_eq_top <;> assumption + · apply isEmbedding_iff_of_iSup_eq_top <;> assumption · simp_rw [Set.range_restrictPreimage] apply isClosed_iff_coe_preimage_of_iSup_eq_top hU + +omit [TopologicalSpace α] in +theorem denseRange_iff_denseRange_of_iSup_eq_top : + DenseRange f ↔ ∀ i, DenseRange ((U i).1.restrictPreimage f) := by + simp_rw [denseRange_iff_closure_range, Set.range_restrictPreimage, + ← (U _).2.isOpenEmbedding_subtypeVal.isOpenMap.preimage_closure_eq_closure_preimage + continuous_subtype_val] + simp only [Opens.carrier_eq_coe, SetLike.coe_sort_coe, preimage_eq_univ_iff, + Subtype.range_coe_subtype, SetLike.mem_coe] + rw [← iUnion_subset_iff, ← Set.univ_subset_iff, iff_iff_eq] + congr 1 + simpa using congr(($hU).1).symm + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_iff_closedEmbedding_of_iSup_eq_top := + isClosedEmbedding_iff_isClosedEmbedding_of_iSup_eq_top diff --git a/Mathlib/Topology/LocallyClosed.lean b/Mathlib/Topology/LocallyClosed.lean index fd260f0e11c03..7367eb02b1278 100644 --- a/Mathlib/Topology/LocallyClosed.lean +++ b/Mathlib/Topology/LocallyClosed.lean @@ -91,10 +91,13 @@ lemma coborder_preimage (hf : IsOpenMap f) (hf' : Continuous f) (s : Set Y) : (hf.coborder_preimage_subset s).antisymm (hf'.preimage_coborder_subset s) protected -lemma OpenEmbedding.coborder_preimage (hf : OpenEmbedding f) (s : Set Y) : +lemma IsOpenEmbedding.coborder_preimage (hf : IsOpenEmbedding f) (s : Set Y) : coborder (f ⁻¹' s) = f ⁻¹' (coborder s) := coborder_preimage hf.isOpenMap hf.continuous s +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.coborder_preimage := IsOpenEmbedding.coborder_preimage + lemma isClosed_preimage_val_coborder : IsClosed (coborder s ↓∩ s) := by rw [isClosed_preimage_val, inter_eq_right.mpr subset_coborder, coborder_inter_closure] @@ -112,8 +115,8 @@ lemma IsLocallyClosed.preimage {s : Set Y} (hs : IsLocallyClosed s) exact ⟨_, _, hU.preimage hf, hZ.preimage hf, preimage_inter⟩ nonrec -lemma Inducing.isLocallyClosed_iff {s : Set X} - {f : X → Y} (hf : Inducing f) : +lemma IsInducing.isLocallyClosed_iff {s : Set X} + {f : X → Y} (hf : IsInducing f) : IsLocallyClosed s ↔ ∃ s' : Set Y, IsLocallyClosed s' ∧ f ⁻¹' s' = s := by simp_rw [IsLocallyClosed, hf.isOpen_iff, hf.isClosed_iff] constructor @@ -122,14 +125,20 @@ lemma Inducing.isLocallyClosed_iff {s : Set X} · rintro ⟨_, ⟨U, Z, hU, hZ, rfl⟩, rfl⟩ exact ⟨_, _, ⟨U, hU, rfl⟩, ⟨Z, hZ, rfl⟩, rfl⟩ -lemma Embedding.isLocallyClosed_iff {s : Set X} - {f : X → Y} (hf : Embedding f) : +@[deprecated (since := "2024-10-28")] +alias Inducing.isLocallyClosed_iff := IsInducing.isLocallyClosed_iff + +lemma IsEmbedding.isLocallyClosed_iff {s : Set X} + {f : X → Y} (hf : IsEmbedding f) : IsLocallyClosed s ↔ ∃ s' : Set Y, IsLocallyClosed s' ∧ s' ∩ range f = f '' s := by - simp_rw [hf.toInducing.isLocallyClosed_iff, + simp_rw [hf.isInducing.isLocallyClosed_iff, ← (image_injective.mpr hf.inj).eq_iff, image_preimage_eq_inter_range] +@[deprecated (since := "2024-10-26")] +alias Embedding.isLocallyClosed_iff := IsEmbedding.isLocallyClosed_iff + lemma IsLocallyClosed.image {s : Set X} (hs : IsLocallyClosed s) - {f : X → Y} (hf : Inducing f) (hf' : IsLocallyClosed (range f)) : + {f : X → Y} (hf : IsInducing f) (hf' : IsLocallyClosed (range f)) : IsLocallyClosed (f '' s) := by obtain ⟨t, ht, rfl⟩ := hf.isLocallyClosed_iff.mp hs rw [image_preimage_eq_inter_range] @@ -177,7 +186,7 @@ lemma isLocallyClosed_tfae (s : Set X) : · exact (subset_iUnion₂ _ _ <| hxU x ·) tfae_have 5 → 1 | H => by - convert H.isLocallyClosed.image inducing_subtype_val + convert H.isLocallyClosed.image IsInducing.subtypeVal (by simpa using isClosed_closure.isLocallyClosed) simpa using subset_closure tfae_finish diff --git a/Mathlib/Topology/LocallyConstant/Basic.lean b/Mathlib/Topology/LocallyConstant/Basic.lean index 401cf78da5d19..916e783447b5b 100644 --- a/Mathlib/Topology/LocallyConstant/Basic.lean +++ b/Mathlib/Topology/LocallyConstant/Basic.lean @@ -358,7 +358,7 @@ def unflip {X α β : Type*} [Finite α] [TopologicalSpace X] (f : α → Locall toFun x a := f a x isLocallyConstant := IsLocallyConstant.iff_isOpen_fiber.2 fun g => by have : (fun (x : X) (a : α) => f a x) ⁻¹' {g} = ⋂ a : α, f a ⁻¹' {g a} := by - ext; simp [Function.funext_iff] + ext; simp [funext_iff] rw [this] exact isOpen_iInter_of_finite fun a => (f a).isLocallyConstant _ diff --git a/Mathlib/Topology/LocallyFinite.lean b/Mathlib/Topology/LocallyFinite.lean index f8fbbee18a97d..fef472c111a08 100644 --- a/Mathlib/Topology/LocallyFinite.lean +++ b/Mathlib/Topology/LocallyFinite.lean @@ -197,7 +197,7 @@ theorem LocallyFinite.sum_elim {g : ι' → Set X} (hf : LocallyFinite f) (hg : theorem locallyFinite_option {f : Option ι → Set X} : LocallyFinite f ↔ LocallyFinite (f ∘ some) := by - rw [← (Equiv.optionEquivSumPUnit.{_, 0} ι).symm.locallyFinite_comp_iff, locallyFinite_sum] + rw [← (Equiv.optionEquivSumPUnit.{0, _} ι).symm.locallyFinite_comp_iff, locallyFinite_sum] simp only [locallyFinite_of_finite, and_true] rfl diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index de7a4ffef4499..aaa5792fc662c 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -15,17 +15,17 @@ This file introduces the following properties of a map `f : X → Y` between top (Open and closed maps need not be continuous.) -* `Inducing f` means the topology on `X` is the one induced via `f` from the topology on `Y`. +* `IsInducing f` means the topology on `X` is the one induced via `f` from the topology on `Y`. These behave like embeddings except they need not be injective. Instead, points of `X` which are identified by `f` are also inseparable in the topology on `X`. -* `Embedding f` means `f` is inducing and also injective. Equivalently, `f` identifies `X` with +* `IsEmbedding f` means `f` is inducing and also injective. Equivalently, `f` identifies `X` with a subspace of `Y`. -* `OpenEmbedding f` means `f` is an embedding with open image, so it identifies `X` with an +* `IsOpenEmbedding f` means `f` is an embedding with open image, so it identifies `X` with an open subspace of `Y`. Equivalently, `f` is an embedding and an open map. -* `ClosedEmbedding f` similarly means `f` is an embedding with closed image, so it identifies +* `IsClosedEmbedding f` similarly means `f` is an embedding with closed image, so it identifies `X` with a closed subspace of `Y`. Equivalently, `f` is an embedding and a closed map. -* `QuotientMap f` is the dual condition to `Embedding f`: `f` is surjective and the topology +* `IsQuotientMap f` is the dual condition to `IsEmbedding f`: `f` is surjective and the topology on `Y` is the one coinduced via `f` from the topology on `X`. Equivalently, `f` identifies `Y` with a quotient of `X`. Quotient maps are also sometimes known as identification maps. @@ -48,233 +48,288 @@ open TopologicalSpace Topology Filter variable {X : Type*} {Y : Type*} {Z : Type*} {ι : Type*} {f : X → Y} {g : Y → Z} -section Inducing +section IsInducing variable [TopologicalSpace Y] -theorem inducing_induced (f : X → Y) : @Inducing X Y (TopologicalSpace.induced f ‹_›) _ f := - @Inducing.mk _ _ (TopologicalSpace.induced f ‹_›) _ _ rfl +protected lemma IsInducing.induced (f : X → Y) : @IsInducing X Y (induced f ‹_›) _ f := + @IsInducing.mk _ _ (TopologicalSpace.induced f ‹_›) _ _ rfl + +@[deprecated (since := "2024-10-28")] alias inducing_induced := IsInducing.induced variable [TopologicalSpace X] -theorem inducing_id : Inducing (@id X) := - ⟨induced_id.symm⟩ +protected lemma IsInducing.id : IsInducing (@id X) := ⟨induced_id.symm⟩ + +@[deprecated (since := "2024-10-28")] alias inducing_id := IsInducing.id variable [TopologicalSpace Z] -protected theorem Inducing.comp (hg : Inducing g) (hf : Inducing f) : - Inducing (g ∘ f) := - ⟨by rw [hf.induced, hg.induced, induced_compose]⟩ +protected lemma IsInducing.comp (hg : IsInducing g) (hf : IsInducing f) : + IsInducing (g ∘ f) := + ⟨by rw [hf.eq_induced, hg.eq_induced, induced_compose]⟩ -theorem Inducing.of_comp_iff (hg : Inducing g) : - Inducing (g ∘ f) ↔ Inducing f := by +@[deprecated (since := "2024-10-28")] alias Inducing.comp := IsInducing.comp + +lemma IsInducing.of_comp_iff (hg : IsInducing g) : IsInducing (g ∘ f) ↔ IsInducing f := by refine ⟨fun h ↦ ?_, hg.comp⟩ - rw [inducing_iff, hg.induced, induced_compose, h.induced] + rw [isInducing_iff, hg.eq_induced, induced_compose, h.eq_induced] + +@[deprecated (since := "2024-10-28")] alias Inducing.of_comp_iff := IsInducing.of_comp_iff -theorem inducing_of_inducing_compose - (hf : Continuous f) (hg : Continuous g) (hgf : Inducing (g ∘ f)) : Inducing f := +lemma IsInducing.of_comp (hf : Continuous f) (hg : Continuous g) (hgf : IsInducing (g ∘ f)) : + IsInducing f := ⟨le_antisymm (by rwa [← continuous_iff_le_induced]) (by - rw [hgf.induced, ← induced_compose] + rw [hgf.eq_induced, ← induced_compose] exact induced_mono hg.le_induced)⟩ -theorem inducing_iff_nhds : Inducing f ↔ ∀ x, 𝓝 x = comap f (𝓝 (f x)) := - (inducing_iff _).trans (induced_iff_nhds_eq f) +@[deprecated (since := "2024-10-28")] alias inducing_of_inducing_compose := IsInducing.of_comp -namespace Inducing +lemma isInducing_iff_nhds : IsInducing f ↔ ∀ x, 𝓝 x = comap f (𝓝 (f x)) := + (isInducing_iff _).trans (induced_iff_nhds_eq f) -theorem nhds_eq_comap (hf : Inducing f) : ∀ x : X, 𝓝 x = comap f (𝓝 <| f x) := - inducing_iff_nhds.1 hf +@[deprecated (since := "2024-10-28")] alias inducing_iff_nhds := isInducing_iff_nhds -theorem basis_nhds {p : ι → Prop} {s : ι → Set Y} (hf : Inducing f) {x : X} +namespace IsInducing + +lemma nhds_eq_comap (hf : IsInducing f) : ∀ x : X, 𝓝 x = comap f (𝓝 <| f x) := + isInducing_iff_nhds.1 hf + +lemma basis_nhds {p : ι → Prop} {s : ι → Set Y} (hf : IsInducing f) {x : X} (h_basis : (𝓝 (f x)).HasBasis p s) : (𝓝 x).HasBasis p (preimage f ∘ s) := hf.nhds_eq_comap x ▸ h_basis.comap f -theorem nhdsSet_eq_comap (hf : Inducing f) (s : Set X) : +lemma nhdsSet_eq_comap (hf : IsInducing f) (s : Set X) : 𝓝ˢ s = comap f (𝓝ˢ (f '' s)) := by simp only [nhdsSet, sSup_image, comap_iSup, hf.nhds_eq_comap, iSup_image] -theorem map_nhds_eq (hf : Inducing f) (x : X) : (𝓝 x).map f = 𝓝[range f] f x := - hf.induced.symm ▸ map_nhds_induced_eq x +lemma map_nhds_eq (hf : IsInducing f) (x : X) : (𝓝 x).map f = 𝓝[range f] f x := + hf.eq_induced ▸ map_nhds_induced_eq x -theorem map_nhds_of_mem (hf : Inducing f) (x : X) (h : range f ∈ 𝓝 (f x)) : - (𝓝 x).map f = 𝓝 (f x) := - hf.induced.symm ▸ map_nhds_induced_of_mem h +lemma map_nhds_of_mem (hf : IsInducing f) (x : X) (h : range f ∈ 𝓝 (f x)) : + (𝓝 x).map f = 𝓝 (f x) := hf.eq_induced ▸ map_nhds_induced_of_mem h -theorem mapClusterPt_iff (hf : Inducing f) {x : X} {l : Filter X} : +lemma mapClusterPt_iff (hf : IsInducing f) {x : X} {l : Filter X} : MapClusterPt (f x) l f ↔ ClusterPt x l := by delta MapClusterPt ClusterPt rw [← Filter.push_pull', ← hf.nhds_eq_comap, map_neBot_iff] -theorem image_mem_nhdsWithin (hf : Inducing f) {x : X} {s : Set X} (hs : s ∈ 𝓝 x) : +lemma image_mem_nhdsWithin (hf : IsInducing f) {x : X} {s : Set X} (hs : s ∈ 𝓝 x) : f '' s ∈ 𝓝[range f] f x := hf.map_nhds_eq x ▸ image_mem_map hs -theorem tendsto_nhds_iff {f : ι → Y} {l : Filter ι} {y : Y} (hg : Inducing g) : +lemma tendsto_nhds_iff {f : ι → Y} {l : Filter ι} {y : Y} (hg : IsInducing g) : Tendsto f l (𝓝 y) ↔ Tendsto (g ∘ f) l (𝓝 (g y)) := by rw [hg.nhds_eq_comap, tendsto_comap_iff] -theorem continuousAt_iff (hg : Inducing g) {x : X} : +lemma continuousAt_iff (hg : IsInducing g) {x : X} : ContinuousAt f x ↔ ContinuousAt (g ∘ f) x := hg.tendsto_nhds_iff -theorem continuous_iff (hg : Inducing g) : +lemma continuous_iff (hg : IsInducing g) : Continuous f ↔ Continuous (g ∘ f) := by simp_rw [continuous_iff_continuousAt, hg.continuousAt_iff] -theorem continuousAt_iff' (hf : Inducing f) {x : X} (h : range f ∈ 𝓝 (f x)) : +lemma continuousAt_iff' (hf : IsInducing f) {x : X} (h : range f ∈ 𝓝 (f x)) : ContinuousAt (g ∘ f) x ↔ ContinuousAt g (f x) := by simp_rw [ContinuousAt, Filter.Tendsto, ← hf.map_nhds_of_mem _ h, Filter.map_map, comp] -protected theorem continuous (hf : Inducing f) : Continuous f := +protected lemma continuous (hf : IsInducing f) : Continuous f := hf.continuous_iff.mp continuous_id -theorem closure_eq_preimage_closure_image (hf : Inducing f) (s : Set X) : +lemma closure_eq_preimage_closure_image (hf : IsInducing f) (s : Set X) : closure s = f ⁻¹' closure (f '' s) := by ext x - rw [Set.mem_preimage, ← closure_induced, hf.induced] + rw [Set.mem_preimage, ← closure_induced, hf.eq_induced] -theorem isClosed_iff (hf : Inducing f) {s : Set X} : - IsClosed s ↔ ∃ t, IsClosed t ∧ f ⁻¹' t = s := by rw [hf.induced, isClosed_induced_iff] +theorem isClosed_iff (hf : IsInducing f) {s : Set X} : + IsClosed s ↔ ∃ t, IsClosed t ∧ f ⁻¹' t = s := by rw [hf.eq_induced, isClosed_induced_iff] -theorem isClosed_iff' (hf : Inducing f) {s : Set X} : - IsClosed s ↔ ∀ x, f x ∈ closure (f '' s) → x ∈ s := by rw [hf.induced, isClosed_induced_iff'] +theorem isClosed_iff' (hf : IsInducing f) {s : Set X} : + IsClosed s ↔ ∀ x, f x ∈ closure (f '' s) → x ∈ s := by rw [hf.eq_induced, isClosed_induced_iff'] -theorem isClosed_preimage (h : Inducing f) (s : Set Y) (hs : IsClosed s) : +theorem isClosed_preimage (h : IsInducing f) (s : Set Y) (hs : IsClosed s) : IsClosed (f ⁻¹' s) := (isClosed_iff h).mpr ⟨s, hs, rfl⟩ -theorem isOpen_iff (hf : Inducing f) {s : Set X} : - IsOpen s ↔ ∃ t, IsOpen t ∧ f ⁻¹' t = s := by rw [hf.induced, isOpen_induced_iff] +theorem isOpen_iff (hf : IsInducing f) {s : Set X} : + IsOpen s ↔ ∃ t, IsOpen t ∧ f ⁻¹' t = s := by rw [hf.eq_induced, isOpen_induced_iff] -theorem setOf_isOpen (hf : Inducing f) : +theorem setOf_isOpen (hf : IsInducing f) : {s : Set X | IsOpen s} = preimage f '' {t | IsOpen t} := Set.ext fun _ ↦ hf.isOpen_iff -theorem dense_iff (hf : Inducing f) {s : Set X} : +theorem dense_iff (hf : IsInducing f) {s : Set X} : Dense s ↔ ∀ x, f x ∈ closure (f '' s) := by simp only [Dense, hf.closure_eq_preimage_closure_image, mem_preimage] -theorem of_subsingleton [Subsingleton X] (f : X → Y) : Inducing f := +theorem of_subsingleton [Subsingleton X] (f : X → Y) : IsInducing f := ⟨Subsingleton.elim _ _⟩ -end Inducing +end IsInducing.IsInducing -end Inducing +namespace IsEmbedding -section Embedding +lemma induced [t : TopologicalSpace Y] (hf : Injective f) : + @IsEmbedding X Y (t.induced f) t f := + @IsEmbedding.mk X Y (t.induced f) t _ (.induced f) hf -theorem Function.Injective.embedding_induced [t : TopologicalSpace Y] (hf : Injective f) : - @_root_.Embedding X Y (t.induced f) t f := - @_root_.Embedding.mk X Y (t.induced f) t _ (inducing_induced f) hf +alias _root_.Function.Injective.isEmbedding_induced := IsEmbedding.induced + +@[deprecated (since := "2024-10-26")] +alias Function.Injective.embedding_induced := _root_.Function.Injective.isEmbedding_induced variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] -theorem Embedding.mk' (f : X → Y) (inj : Injective f) (induced : ∀ x, comap f (𝓝 (f x)) = 𝓝 x) : - Embedding f := - ⟨inducing_iff_nhds.2 fun x => (induced x).symm, inj⟩ +lemma isInducing (hf : IsEmbedding f) : IsInducing f := hf.toIsInducing + +@[deprecated (since := "2024-10-28")] alias inducing := isInducing + +lemma mk' (f : X → Y) (inj : Injective f) (induced : ∀ x, comap f (𝓝 (f x)) = 𝓝 x) : + IsEmbedding f := + ⟨isInducing_iff_nhds.2 fun x => (induced x).symm, inj⟩ + +@[deprecated (since := "2024-10-26")] +alias Embedding.mk' := mk' + +protected lemma id : IsEmbedding (@id X) := ⟨.id, fun _ _ h => h⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_id := IsEmbedding.id + +protected lemma comp (hg : IsEmbedding g) (hf : IsEmbedding f) : IsEmbedding (g ∘ f) := + { hg.isInducing.comp hf.isInducing with inj := fun _ _ h => hf.inj <| hg.inj h } -theorem embedding_id : Embedding (@id X) := - ⟨inducing_id, fun _ _ h => h⟩ +@[deprecated (since := "2024-10-26")] +alias Embedding.comp := IsEmbedding.comp -protected theorem Embedding.comp (hg : Embedding g) (hf : Embedding f) : - Embedding (g ∘ f) := - { hg.toInducing.comp hf.toInducing with inj := fun _ _ h => hf.inj <| hg.inj h } +lemma of_comp_iff (hg : IsEmbedding g) : IsEmbedding (g ∘ f) ↔ IsEmbedding f := by + simp_rw [isEmbedding_iff, hg.isInducing.of_comp_iff, hg.inj.of_comp_iff f] -theorem Embedding.of_comp_iff (hg : Embedding g) : Embedding (g ∘ f) ↔ Embedding f := by - simp_rw [embedding_iff, hg.toInducing.of_comp_iff, hg.inj.of_comp_iff f] +@[deprecated (since := "2024-10-26")] +alias Embedding.of_comp_iff := of_comp_iff -theorem embedding_of_embedding_compose - (hf : Continuous f) (hg : Continuous g) (hgf : Embedding (g ∘ f)) : Embedding f := - { induced := (inducing_of_inducing_compose hf hg hgf.toInducing).induced - inj := fun x₁ x₂ h => hgf.inj <| by simp [h, (· ∘ ·)] } +protected lemma of_comp (hf : Continuous f) (hg : Continuous g) (hgf : IsEmbedding (g ∘ f)) : + IsEmbedding f where + toIsInducing := hgf.isInducing.of_comp hf hg + inj := hgf.inj.of_comp -protected theorem Function.LeftInverse.embedding {f : X → Y} {g : Y → X} (h : LeftInverse f g) - (hf : Continuous f) (hg : Continuous g) : _root_.Embedding g := - embedding_of_embedding_compose hg hf <| h.comp_eq_id.symm ▸ embedding_id +@[deprecated (since := "2024-10-26")] +alias embedding_of_embedding_compose := IsEmbedding.of_comp -theorem Embedding.map_nhds_eq (hf : Embedding f) (x : X) : - (𝓝 x).map f = 𝓝[range f] f x := +lemma of_leftInverse {f : X → Y} {g : Y → X} (h : LeftInverse f g) (hf : Continuous f) + (hg : Continuous g) : IsEmbedding g := .of_comp hg hf <| h.comp_eq_id.symm ▸ .id + +alias _root_.Function.LeftInverse.isEmbedding := of_leftInverse + +@[deprecated (since := "2024-10-26")] +alias _root_.Function.LeftInverse.embedding := Function.LeftInverse.isEmbedding + +lemma map_nhds_eq (hf : IsEmbedding f) (x : X) : (𝓝 x).map f = 𝓝[range f] f x := hf.1.map_nhds_eq x -theorem Embedding.map_nhds_of_mem (hf : Embedding f) (x : X) (h : range f ∈ 𝓝 (f x)) : +@[deprecated (since := "2024-10-26")] +alias Embedding.map_nhds_eq := map_nhds_eq + +lemma map_nhds_of_mem (hf : IsEmbedding f) (x : X) (h : range f ∈ 𝓝 (f x)) : (𝓝 x).map f = 𝓝 (f x) := hf.1.map_nhds_of_mem x h -theorem Embedding.tendsto_nhds_iff {f : ι → Y} {l : Filter ι} {y : Y} - (hg : Embedding g) : Tendsto f l (𝓝 y) ↔ Tendsto (g ∘ f) l (𝓝 (g y)) := - hg.toInducing.tendsto_nhds_iff +@[deprecated (since := "2024-10-26")] +alias Embedding.map_nhds_of_mem := map_nhds_of_mem -theorem Embedding.continuous_iff (hg : Embedding g) : - Continuous f ↔ Continuous (g ∘ f) := - Inducing.continuous_iff hg.1 +lemma tendsto_nhds_iff {f : ι → Y} {l : Filter ι} {y : Y} (hg : IsEmbedding g) : + Tendsto f l (𝓝 y) ↔ Tendsto (g ∘ f) l (𝓝 (g y)) := hg.isInducing.tendsto_nhds_iff -theorem Embedding.continuous (hf : Embedding f) : Continuous f := - Inducing.continuous hf.1 +lemma continuous_iff (hg : IsEmbedding g) : Continuous f ↔ Continuous (g ∘ f) := + hg.isInducing.continuous_iff -theorem Embedding.closure_eq_preimage_closure_image (hf : Embedding f) (s : Set X) : +@[deprecated (since := "2024-10-26")] +alias Embedding.continuous_iff := continuous_iff + +lemma continuous (hf : IsEmbedding f) : Continuous f := hf.isInducing.continuous + +lemma closure_eq_preimage_closure_image (hf : IsEmbedding f) (s : Set X) : closure s = f ⁻¹' closure (f '' s) := hf.1.closure_eq_preimage_closure_image s +@[deprecated (since := "2024-10-26")] +alias Embedding.closure_eq_preimage_closure_image := closure_eq_preimage_closure_image + /-- The topology induced under an inclusion `f : X → Y` from a discrete topological space `Y` is the discrete topology on `X`. See also `DiscreteTopology.of_continuous_injective`. -/ -theorem Embedding.discreteTopology [DiscreteTopology Y] (hf : Embedding f) : DiscreteTopology X := +lemma discreteTopology [DiscreteTopology Y] (hf : IsEmbedding f) : DiscreteTopology X := .of_continuous_injective hf.continuous hf.inj -theorem Embedding.of_subsingleton [Subsingleton X] (f : X → Y) : Embedding f := +@[deprecated (since := "2024-10-26")] +alias Embedding.discreteTopology := discreteTopology + +lemma of_subsingleton [Subsingleton X] (f : X → Y) : IsEmbedding f := ⟨.of_subsingleton f, f.injective_of_subsingleton⟩ -end Embedding +@[deprecated (since := "2024-10-26")] +alias Embedding.of_subsingleton := of_subsingleton + +end IsEmbedding -section QuotientMap +section IsQuotientMap variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] -theorem quotientMap_iff : QuotientMap f ↔ Surjective f ∧ ∀ s : Set Y, IsOpen s ↔ IsOpen (f ⁻¹' s) := - (quotientMap_iff' _).trans <| and_congr Iff.rfl TopologicalSpace.ext_iff +lemma isQuotientMap_iff : IsQuotientMap f ↔ Surjective f ∧ ∀ s, IsOpen s ↔ IsOpen (f ⁻¹' s) := + (isQuotientMap_iff' _).trans <| and_congr Iff.rfl TopologicalSpace.ext_iff -theorem quotientMap_iff_closed : - QuotientMap f ↔ Surjective f ∧ ∀ s : Set Y, IsClosed s ↔ IsClosed (f ⁻¹' s) := - quotientMap_iff.trans <| Iff.rfl.and <| compl_surjective.forall.trans <| by +@[deprecated (since := "2024-10-22")] +alias quotientMap_iff := isQuotientMap_iff + +theorem isQuotientMap_iff_closed : + IsQuotientMap f ↔ Surjective f ∧ ∀ s : Set Y, IsClosed s ↔ IsClosed (f ⁻¹' s) := + isQuotientMap_iff.trans <| Iff.rfl.and <| compl_surjective.forall.trans <| by simp only [isOpen_compl_iff, preimage_compl] -namespace QuotientMap +@[deprecated (since := "2024-10-22")] +alias quotientMap_iff_closed := isQuotientMap_iff_closed + +namespace IsQuotientMap -protected theorem id : QuotientMap (@id X) := +protected theorem id : IsQuotientMap (@id X) := ⟨fun x => ⟨x, rfl⟩, coinduced_id.symm⟩ -protected theorem comp (hg : QuotientMap g) (hf : QuotientMap f) : QuotientMap (g ∘ f) := +protected theorem comp (hg : IsQuotientMap g) (hf : IsQuotientMap f) : IsQuotientMap (g ∘ f) := ⟨hg.surjective.comp hf.surjective, by rw [hg.eq_coinduced, hf.eq_coinduced, coinduced_compose]⟩ -protected theorem of_quotientMap_compose (hf : Continuous f) (hg : Continuous g) - (hgf : QuotientMap (g ∘ f)) : QuotientMap g := +protected theorem of_comp (hf : Continuous f) (hg : Continuous g) + (hgf : IsQuotientMap (g ∘ f)) : IsQuotientMap g := ⟨hgf.1.of_comp, le_antisymm (by rw [hgf.eq_coinduced, ← coinduced_compose]; exact coinduced_mono hf.coinduced_le) hg.coinduced_le⟩ +@[deprecated (since := "2024-10-22")] +alias of_quotientMap_compose := IsQuotientMap.of_comp + theorem of_inverse {g : Y → X} (hf : Continuous f) (hg : Continuous g) (h : LeftInverse g f) : - QuotientMap g := - QuotientMap.of_quotientMap_compose hf hg <| h.comp_eq_id.symm ▸ QuotientMap.id + IsQuotientMap g := .of_comp hf hg <| h.comp_eq_id.symm ▸ IsQuotientMap.id -protected theorem continuous_iff (hf : QuotientMap f) : Continuous g ↔ Continuous (g ∘ f) := by +protected theorem continuous_iff (hf : IsQuotientMap f) : Continuous g ↔ Continuous (g ∘ f) := by rw [continuous_iff_coinduced_le, continuous_iff_coinduced_le, hf.eq_coinduced, coinduced_compose] -protected theorem continuous (hf : QuotientMap f) : Continuous f := +protected theorem continuous (hf : IsQuotientMap f) : Continuous f := hf.continuous_iff.mp continuous_id -protected theorem isOpen_preimage (hf : QuotientMap f) {s : Set Y} : IsOpen (f ⁻¹' s) ↔ IsOpen s := - ((quotientMap_iff.1 hf).2 s).symm +protected lemma isOpen_preimage (hf : IsQuotientMap f) {s : Set Y} : IsOpen (f ⁻¹' s) ↔ IsOpen s := + ((isQuotientMap_iff.1 hf).2 s).symm -protected theorem isClosed_preimage (hf : QuotientMap f) {s : Set Y} : +protected theorem isClosed_preimage (hf : IsQuotientMap f) {s : Set Y} : IsClosed (f ⁻¹' s) ↔ IsClosed s := - ((quotientMap_iff_closed.1 hf).2 s).symm + ((isQuotientMap_iff_closed.1 hf).2 s).symm -end QuotientMap +end IsQuotientMap -end QuotientMap +end IsQuotientMap section OpenMap variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] @@ -326,11 +381,14 @@ theorem of_inverse {f' : Y → X} (h : Continuous f') (l_inv : LeftInverse f f') of_sections fun _ => ⟨f', h.continuousAt, r_inv _, l_inv⟩ /-- A continuous surjective open map is a quotient map. -/ -theorem to_quotientMap (open_map : IsOpenMap f) (cont : Continuous f) (surj : Surjective f) : - QuotientMap f := - quotientMap_iff.2 +theorem isQuotientMap (open_map : IsOpenMap f) (cont : Continuous f) (surj : Surjective f) : + IsQuotientMap f := + isQuotientMap_iff.2 ⟨surj, fun s => ⟨fun h => h.preimage cont, fun h => surj.image_preimage s ▸ open_map _ h⟩⟩ +@[deprecated (since := "2024-10-22")] +alias to_quotientMap := isQuotientMap + theorem interior_preimage_subset_preimage_interior (hf : IsOpenMap f) {s : Set Y} : interior (f ⁻¹' s) ⊆ f ⁻¹' interior s := hf.mapsTo_interior (mapsTo_preimage _ _) @@ -375,9 +433,12 @@ theorem isOpenMap_iff_interior : IsOpenMap f ↔ ∀ s, f '' interior s ⊆ inte _ ⊆ interior (f '' u) := hs u⟩ /-- An inducing map with an open range is an open map. -/ -protected theorem Inducing.isOpenMap (hi : Inducing f) (ho : IsOpen (range f)) : IsOpenMap f := +protected lemma IsInducing.isOpenMap (hi : IsInducing f) (ho : IsOpen (range f)) : + IsOpenMap f := IsOpenMap.of_nhds_le fun _ => (hi.map_nhds_of_mem _ <| IsOpen.mem_nhds ho <| mem_range_self _).ge +@[deprecated (since := "2024-10-28")] alias Inducing.isOpenMap := IsInducing.isOpenMap + /-- Preimage of a dense set under an open map is dense. -/ protected theorem Dense.preimage {s : Set Y} (hs : Dense s) (hf : IsOpenMap f) : Dense (f ⁻¹' s) := fun x ↦ @@ -419,19 +480,25 @@ theorem isClosed_range (hf : IsClosedMap f) : IsClosed (range f) := @[deprecated (since := "2024-03-17")] alias closed_range := isClosed_range -theorem to_quotientMap (hcl : IsClosedMap f) (hcont : Continuous f) - (hsurj : Surjective f) : QuotientMap f := - quotientMap_iff_closed.2 ⟨hsurj, fun s => +theorem isQuotientMap (hcl : IsClosedMap f) (hcont : Continuous f) + (hsurj : Surjective f) : IsQuotientMap f := + isQuotientMap_iff_closed.2 ⟨hsurj, fun s => ⟨fun hs => hs.preimage hcont, fun hs => hsurj.image_preimage s ▸ hcl _ hs⟩⟩ +@[deprecated (since := "2024-10-22")] +alias to_quotientMap := isQuotientMap + end IsClosedMap -theorem Inducing.isClosedMap (hf : Inducing f) (h : IsClosed (range f)) : IsClosedMap f := by +lemma IsInducing.isClosedMap (hf : IsInducing f) (h : IsClosed (range f)) : + IsClosedMap f := by intro s hs rcases hf.isClosed_iff.1 hs with ⟨t, ht, rfl⟩ rw [image_preimage_eq_inter_range] exact ht.inter h +@[deprecated (since := "2024-10-28")] alias Inducing.isClosedMap := IsInducing.isClosedMap + theorem isClosedMap_iff_closure_image : IsClosedMap f ↔ ∀ s, closure (f '' s) ⊆ f '' closure s := ⟨IsClosedMap.closure_image_subset, fun hs c hc => @@ -470,153 +537,226 @@ theorem IsClosedMap.mapClusterPt_iff_lift'_closure end IsClosedMap -section OpenEmbedding +section IsOpenEmbedding variable [TopologicalSpace X] [TopologicalSpace Y] -theorem OpenEmbedding.isOpenMap (hf : OpenEmbedding f) : IsOpenMap f := - hf.toEmbedding.toInducing.isOpenMap hf.isOpen_range +lemma IsOpenEmbedding.isEmbedding (hf : IsOpenEmbedding f) : IsEmbedding f := hf.toIsEmbedding +lemma IsOpenEmbedding.isInducing (hf : IsOpenEmbedding f) : IsInducing f := + hf.isEmbedding.isInducing + +@[deprecated (since := "2024-10-28")] alias IsOpenEmbedding.inducing := IsOpenEmbedding.isInducing -theorem OpenEmbedding.map_nhds_eq (hf : OpenEmbedding f) (x : X) : +lemma IsOpenEmbedding.isOpenMap (hf : IsOpenEmbedding f) : IsOpenMap f := + hf.isEmbedding.isInducing.isOpenMap hf.isOpen_range + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.isOpenMap := IsOpenEmbedding.isOpenMap + +theorem IsOpenEmbedding.map_nhds_eq (hf : IsOpenEmbedding f) (x : X) : map f (𝓝 x) = 𝓝 (f x) := - hf.toEmbedding.map_nhds_of_mem _ <| hf.isOpen_range.mem_nhds <| mem_range_self _ + hf.isEmbedding.map_nhds_of_mem _ <| hf.isOpen_range.mem_nhds <| mem_range_self _ + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.map_nhds_eq := IsOpenEmbedding.map_nhds_eq -theorem OpenEmbedding.open_iff_image_open (hf : OpenEmbedding f) {s : Set X} : +theorem IsOpenEmbedding.open_iff_image_open (hf : IsOpenEmbedding f) {s : Set X} : IsOpen s ↔ IsOpen (f '' s) := ⟨hf.isOpenMap s, fun h => by - convert ← h.preimage hf.toEmbedding.continuous + convert ← h.preimage hf.isEmbedding.continuous apply preimage_image_eq _ hf.inj⟩ -theorem OpenEmbedding.tendsto_nhds_iff [TopologicalSpace Z] {f : ι → Y} {l : Filter ι} {y : Y} - (hg : OpenEmbedding g) : Tendsto f l (𝓝 y) ↔ Tendsto (g ∘ f) l (𝓝 (g y)) := - hg.toEmbedding.tendsto_nhds_iff +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.open_iff_image_open := IsOpenEmbedding.open_iff_image_open -theorem OpenEmbedding.tendsto_nhds_iff' (hf : OpenEmbedding f) {l : Filter Z} {x : X} : +theorem IsOpenEmbedding.tendsto_nhds_iff [TopologicalSpace Z] {f : ι → Y} {l : Filter ι} {y : Y} + (hg : IsOpenEmbedding g) : Tendsto f l (𝓝 y) ↔ Tendsto (g ∘ f) l (𝓝 (g y)) := + hg.isEmbedding.tendsto_nhds_iff + +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.tendsto_nhds_iff := IsOpenEmbedding.tendsto_nhds_iff + +theorem IsOpenEmbedding.tendsto_nhds_iff' (hf : IsOpenEmbedding f) {l : Filter Z} {x : X} : Tendsto (g ∘ f) (𝓝 x) l ↔ Tendsto g (𝓝 (f x)) l := by rw [Tendsto, ← map_map, hf.map_nhds_eq]; rfl -theorem OpenEmbedding.continuousAt_iff [TopologicalSpace Z] (hf : OpenEmbedding f) {x : X} : +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.tendsto_nhds_iff' := IsOpenEmbedding.tendsto_nhds_iff' + +theorem IsOpenEmbedding.continuousAt_iff [TopologicalSpace Z] (hf : IsOpenEmbedding f) {x : X} : ContinuousAt (g ∘ f) x ↔ ContinuousAt g (f x) := hf.tendsto_nhds_iff' -theorem OpenEmbedding.continuous (hf : OpenEmbedding f) : Continuous f := - hf.toEmbedding.continuous +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.continuousAt_iff := IsOpenEmbedding.continuousAt_iff + +theorem IsOpenEmbedding.continuous (hf : IsOpenEmbedding f) : Continuous f := + hf.isEmbedding.continuous -theorem OpenEmbedding.open_iff_preimage_open (hf : OpenEmbedding f) {s : Set Y} +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.continuous := IsOpenEmbedding.continuous + +lemma IsOpenEmbedding.open_iff_preimage_open (hf : IsOpenEmbedding f) {s : Set Y} (hs : s ⊆ range f) : IsOpen s ↔ IsOpen (f ⁻¹' s) := by rw [hf.open_iff_image_open, image_preimage_eq_inter_range, inter_eq_self_of_subset_left hs] -theorem openEmbedding_of_embedding_open (h₁ : Embedding f) (h₂ : IsOpenMap f) : - OpenEmbedding f := +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.open_iff_preimage_open := IsOpenEmbedding.open_iff_preimage_open + +lemma IsOpenEmbedding.of_isEmbedding_isOpenMap (h₁ : IsEmbedding f) (h₂ : IsOpenMap f) : + IsOpenEmbedding f := ⟨h₁, h₂.isOpen_range⟩ -/-- A surjective embedding is an `OpenEmbedding`. -/ -theorem _root_.Embedding.toOpenEmbedding_of_surjective (hf : Embedding f) (hsurj : f.Surjective) : - OpenEmbedding f := +@[deprecated (since := "2024-10-26")] +alias isOpenEmbedding_of_embedding_open := IsOpenEmbedding.of_isEmbedding_isOpenMap + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_of_embedding_open := IsOpenEmbedding.of_isEmbedding_isOpenMap + +/-- A surjective embedding is an `IsOpenEmbedding`. -/ +lemma IsEmbedding.isOpenEmbedding_of_surjective (hf : IsEmbedding f) (hsurj : f.Surjective) : + IsOpenEmbedding f := ⟨hf, hsurj.range_eq ▸ isOpen_univ⟩ -theorem openEmbedding_iff_embedding_open : - OpenEmbedding f ↔ Embedding f ∧ IsOpenMap f := - ⟨fun h => ⟨h.1, h.isOpenMap⟩, fun h => openEmbedding_of_embedding_open h.1 h.2⟩ +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.toIsOpenEmbedding_of_surjective := IsEmbedding.isOpenEmbedding_of_surjective + +alias IsOpenEmbedding.of_isEmbedding := IsEmbedding.isOpenEmbedding_of_surjective + +@[deprecated (since := "2024-10-18")] +alias _root_.Embedding.toOpenEmbedding_of_surjective := IsEmbedding.isOpenEmbedding_of_surjective + +lemma isOpenEmbedding_iff_isEmbedding_isOpenMap : IsOpenEmbedding f ↔ IsEmbedding f ∧ IsOpenMap f := + ⟨fun h => ⟨h.1, h.isOpenMap⟩, fun h => .of_isEmbedding_isOpenMap h.1 h.2⟩ -theorem openEmbedding_of_continuous_injective_open - (h₁ : Continuous f) (h₂ : Injective f) (h₃ : IsOpenMap f) : OpenEmbedding f := by - simp only [openEmbedding_iff_embedding_open, embedding_iff, inducing_iff_nhds, *, and_true] +@[deprecated (since := "2024-10-26")] +alias isOpenEmbedding_iff_embedding_open := isOpenEmbedding_iff_isEmbedding_isOpenMap + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_embedding_open := isOpenEmbedding_iff_isEmbedding_isOpenMap + +theorem isOpenEmbedding_of_continuous_injective_open + (h₁ : Continuous f) (h₂ : Injective f) (h₃ : IsOpenMap f) : IsOpenEmbedding f := by + simp only [isOpenEmbedding_iff_isEmbedding_isOpenMap, isEmbedding_iff, isInducing_iff_nhds, *, + and_true] exact fun x => le_antisymm (h₁.tendsto _).le_comap (@comap_map _ _ (𝓝 x) _ h₂ ▸ comap_mono (h₃.nhds_le _)) -theorem openEmbedding_iff_continuous_injective_open : - OpenEmbedding f ↔ Continuous f ∧ Injective f ∧ IsOpenMap f := +theorem isOpenEmbedding_iff_continuous_injective_open : + IsOpenEmbedding f ↔ Continuous f ∧ Injective f ∧ IsOpenMap f := ⟨fun h => ⟨h.continuous, h.inj, h.isOpenMap⟩, fun h => - openEmbedding_of_continuous_injective_open h.1 h.2.1 h.2.2⟩ + isOpenEmbedding_of_continuous_injective_open h.1 h.2.1 h.2.2⟩ + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_iff_continuous_injective_open := isOpenEmbedding_iff_continuous_injective_open -theorem openEmbedding_id : OpenEmbedding (@id X) := - ⟨embedding_id, IsOpenMap.id.isOpen_range⟩ +theorem isOpenEmbedding_id : IsOpenEmbedding (@id X) := + ⟨.id, IsOpenMap.id.isOpen_range⟩ -namespace OpenEmbedding +@[deprecated (since := "2024-10-18")] +alias openEmbedding_id := isOpenEmbedding_id + +namespace IsOpenEmbedding variable [TopologicalSpace Z] -protected theorem comp (hg : OpenEmbedding g) - (hf : OpenEmbedding f) : OpenEmbedding (g ∘ f) := +protected theorem comp (hg : IsOpenEmbedding g) + (hf : IsOpenEmbedding f) : IsOpenEmbedding (g ∘ f) := ⟨hg.1.comp hf.1, (hg.isOpenMap.comp hf.isOpenMap).isOpen_range⟩ -theorem isOpenMap_iff (hg : OpenEmbedding g) : +theorem isOpenMap_iff (hg : IsOpenEmbedding g) : IsOpenMap f ↔ IsOpenMap (g ∘ f) := by simp_rw [isOpenMap_iff_nhds_le, ← map_map, comp, ← hg.map_nhds_eq, Filter.map_le_map_iff hg.inj] -theorem of_comp_iff (f : X → Y) (hg : OpenEmbedding g) : - OpenEmbedding (g ∘ f) ↔ OpenEmbedding f := by - simp only [openEmbedding_iff_continuous_injective_open, ← hg.isOpenMap_iff, ← +theorem of_comp_iff (f : X → Y) (hg : IsOpenEmbedding g) : + IsOpenEmbedding (g ∘ f) ↔ IsOpenEmbedding f := by + simp only [isOpenEmbedding_iff_continuous_injective_open, ← hg.isOpenMap_iff, ← hg.1.continuous_iff, hg.inj.of_comp_iff] -theorem of_comp (f : X → Y) (hg : OpenEmbedding g) - (h : OpenEmbedding (g ∘ f)) : OpenEmbedding f := - (OpenEmbedding.of_comp_iff f hg).1 h +theorem of_comp (f : X → Y) (hg : IsOpenEmbedding g) + (h : IsOpenEmbedding (g ∘ f)) : IsOpenEmbedding f := + (IsOpenEmbedding.of_comp_iff f hg).1 h -theorem of_isEmpty [IsEmpty X] (f : X → Y) : OpenEmbedding f := - openEmbedding_of_embedding_open (.of_subsingleton f) (IsOpenMap.of_isEmpty f) +theorem of_isEmpty [IsEmpty X] (f : X → Y) : IsOpenEmbedding f := + of_isEmbedding_isOpenMap (.of_subsingleton f) (.of_isEmpty f) -theorem image_mem_nhds {f : X → Y} (hf : OpenEmbedding f) {s : Set X} {x : X} : +theorem image_mem_nhds {f : X → Y} (hf : IsOpenEmbedding f) {s : Set X} {x : X} : f '' s ∈ 𝓝 (f x) ↔ s ∈ 𝓝 x := by rw [← hf.map_nhds_eq, mem_map, preimage_image_eq _ hf.inj] -end OpenEmbedding +end IsOpenEmbedding -end OpenEmbedding +end IsOpenEmbedding -section ClosedEmbedding +section IsClosedEmbedding variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] -namespace ClosedEmbedding +namespace IsClosedEmbedding + +lemma isEmbedding (hf : IsClosedEmbedding f) : IsEmbedding f := hf.toIsEmbedding +lemma isInducing (hf : IsClosedEmbedding f) : IsInducing f := hf.isEmbedding.isInducing +lemma continuous (hf : IsClosedEmbedding f) : Continuous f := hf.isEmbedding.continuous -theorem tendsto_nhds_iff {g : ι → X} {l : Filter ι} {x : X} (hf : ClosedEmbedding f) : - Tendsto g l (𝓝 x) ↔ Tendsto (f ∘ g) l (𝓝 (f x)) := - hf.toEmbedding.tendsto_nhds_iff +@[deprecated (since := "2024-10-28")] alias inducing := isInducing -theorem continuous (hf : ClosedEmbedding f) : Continuous f := - hf.toEmbedding.continuous +lemma tendsto_nhds_iff {g : ι → X} {l : Filter ι} {x : X} (hf : IsClosedEmbedding f) : + Tendsto g l (𝓝 x) ↔ Tendsto (f ∘ g) l (𝓝 (f x)) := hf.isEmbedding.tendsto_nhds_iff -theorem isClosedMap (hf : ClosedEmbedding f) : IsClosedMap f := - hf.toEmbedding.toInducing.isClosedMap hf.isClosed_range +lemma isClosedMap (hf : IsClosedEmbedding f) : IsClosedMap f := + hf.isEmbedding.isInducing.isClosedMap hf.isClosed_range -theorem closed_iff_image_closed (hf : ClosedEmbedding f) {s : Set X} : +theorem closed_iff_image_closed (hf : IsClosedEmbedding f) {s : Set X} : IsClosed s ↔ IsClosed (f '' s) := ⟨hf.isClosedMap s, fun h => by rw [← preimage_image_eq s hf.inj] exact h.preimage hf.continuous⟩ -theorem closed_iff_preimage_closed (hf : ClosedEmbedding f) {s : Set Y} +theorem closed_iff_preimage_closed (hf : IsClosedEmbedding f) {s : Set Y} (hs : s ⊆ range f) : IsClosed s ↔ IsClosed (f ⁻¹' s) := by rw [hf.closed_iff_image_closed, image_preimage_eq_of_subset hs] -theorem _root_.closedEmbedding_of_embedding_closed (h₁ : Embedding f) (h₂ : IsClosedMap f) : - ClosedEmbedding f := +lemma of_isEmbedding_isClosedMap (h₁ : IsEmbedding f) (h₂ : IsClosedMap f) : + IsClosedEmbedding f := ⟨h₁, image_univ (f := f) ▸ h₂ univ isClosed_univ⟩ -theorem _root_.closedEmbedding_of_continuous_injective_closed (h₁ : Continuous f) (h₂ : Injective f) - (h₃ : IsClosedMap f) : ClosedEmbedding f := by - refine closedEmbedding_of_embedding_closed ⟨⟨?_⟩, h₂⟩ h₃ +@[deprecated (since := "2024-10-26")] +alias _root_.IsClosedEmbedding.of_embedding_closed := of_isEmbedding_isClosedMap + +@[deprecated (since := "2024-10-20")] +alias _root_.closedEmbedding_of_embedding_closed := of_isEmbedding_isClosedMap + +lemma _root_.IsClosedEmbedding.of_continuous_injective_isClosedMap (h₁ : Continuous f) + (h₂ : Injective f) (h₃ : IsClosedMap f) : IsClosedEmbedding f := by + refine .of_isEmbedding_isClosedMap ⟨⟨?_⟩, h₂⟩ h₃ refine h₁.le_induced.antisymm fun s hs => ?_ refine ⟨(f '' sᶜ)ᶜ, (h₃ _ hs.isClosed_compl).isOpen_compl, ?_⟩ rw [preimage_compl, preimage_image_eq _ h₂, compl_compl] -theorem _root_.closedEmbedding_id : ClosedEmbedding (@id X) := - ⟨embedding_id, IsClosedMap.id.isClosed_range⟩ +@[deprecated (since := "2024-10-20")] +alias _root_.closedEmbedding_of_continuous_injective_closed := + IsClosedEmbedding.of_continuous_injective_isClosedMap -theorem comp (hg : ClosedEmbedding g) (hf : ClosedEmbedding f) : - ClosedEmbedding (g ∘ f) := - ⟨hg.toEmbedding.comp hf.toEmbedding, (hg.isClosedMap.comp hf.isClosedMap).isClosed_range⟩ +theorem _root_.isClosedEmbedding_id : IsClosedEmbedding (@id X) := + ⟨.id, IsClosedMap.id.isClosed_range⟩ -theorem of_comp_iff (hg : ClosedEmbedding g) : - ClosedEmbedding (g ∘ f) ↔ ClosedEmbedding f := by - simp_rw [closedEmbedding_iff, hg.toEmbedding.of_comp_iff, Set.range_comp, +@[deprecated (since := "2024-10-20")] +alias _root_.closedEmbedding_id := _root_.isClosedEmbedding_id + +theorem comp (hg : IsClosedEmbedding g) (hf : IsClosedEmbedding f) : + IsClosedEmbedding (g ∘ f) := + ⟨hg.isEmbedding.comp hf.isEmbedding, (hg.isClosedMap.comp hf.isClosedMap).isClosed_range⟩ + +lemma of_comp_iff (hg : IsClosedEmbedding g) : IsClosedEmbedding (g ∘ f) ↔ IsClosedEmbedding f := by + simp_rw [isClosedEmbedding_iff, hg.isEmbedding.of_comp_iff, Set.range_comp, ← hg.closed_iff_image_closed] -theorem closure_image_eq (hf : ClosedEmbedding f) (s : Set X) : +@[deprecated (since := "2024-10-26")] +alias Embedding.of_comp_iff := of_comp_iff + +theorem closure_image_eq (hf : IsClosedEmbedding f) (s : Set X) : closure (f '' s) = f '' closure s := hf.isClosedMap.closure_image_eq_of_continuous hf.continuous s -end ClosedEmbedding +end IsClosedEmbedding -end ClosedEmbedding +end IsClosedEmbedding diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index 88433f7a190fd..4f593b59638a1 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -32,15 +32,24 @@ namespace IsOpenQuotientMap protected theorem id : IsOpenQuotientMap (id : X → X) := ⟨surjective_id, continuous_id, .id⟩ /-- An open quotient map is a quotient map. -/ -theorem quotientMap (h : IsOpenQuotientMap f) : QuotientMap f := - h.isOpenMap.to_quotientMap h.continuous h.surjective +theorem isQuotientMap (h : IsOpenQuotientMap f) : IsQuotientMap f := + h.isOpenMap.isQuotientMap h.continuous h.surjective -theorem iff_isOpenMap_quotientMap : IsOpenQuotientMap f ↔ IsOpenMap f ∧ QuotientMap f := - ⟨fun h ↦ ⟨h.isOpenMap, h.quotientMap⟩, fun ⟨ho, hq⟩ ↦ ⟨hq.surjective, hq.continuous, ho⟩⟩ +@[deprecated (since := "2024-10-22")] +alias quotientMap := isQuotientMap -theorem of_isOpenMap_quotientMap (ho : IsOpenMap f) (hq : QuotientMap f) : +theorem iff_isOpenMap_isQuotientMap : IsOpenQuotientMap f ↔ IsOpenMap f ∧ IsQuotientMap f := + ⟨fun h ↦ ⟨h.isOpenMap, h.isQuotientMap⟩, fun ⟨ho, hq⟩ ↦ ⟨hq.surjective, hq.continuous, ho⟩⟩ + +@[deprecated (since := "2024-10-22")] +alias iff_isOpenMap_quotientMap := iff_isOpenMap_isQuotientMap + +theorem of_isOpenMap_isQuotientMap (ho : IsOpenMap f) (hq : IsQuotientMap f) : IsOpenQuotientMap f := - iff_isOpenMap_quotientMap.2 ⟨ho, hq⟩ + iff_isOpenMap_isQuotientMap.2 ⟨ho, hq⟩ + +@[deprecated (since := "2024-10-22")] +alias of_isOpenMap_quotientMap := of_isOpenMap_isQuotientMap theorem comp {g : Y → Z} (hg : IsOpenQuotientMap g) (hf : IsOpenQuotientMap f) : IsOpenQuotientMap (g ∘ f) := @@ -51,7 +60,7 @@ theorem map_nhds_eq (h : IsOpenQuotientMap f) (x : X) : map f (𝓝 x) = 𝓝 (f theorem continuous_comp_iff (h : IsOpenQuotientMap f) {g : Y → Z} : Continuous (g ∘ f) ↔ Continuous g := - h.quotientMap.continuous_iff.symm + h.isQuotientMap.continuous_iff.symm theorem continuousAt_comp_iff (h : IsOpenQuotientMap f) {g : Y → Z} {x : X} : ContinuousAt (g ∘ f) x ↔ ContinuousAt g (f x) := by diff --git a/Mathlib/Topology/Maps/Proper/Basic.lean b/Mathlib/Topology/Maps/Proper/Basic.lean index 00bd0a3bd8677..bd8b9f6139ec2 100644 --- a/Mathlib/Topology/Maps/Proper/Basic.lean +++ b/Mathlib/Topology/Maps/Proper/Basic.lean @@ -5,7 +5,6 @@ Authors: Anatole Dedecker, Etienne Marion -/ import Mathlib.Topology.Homeomorph import Mathlib.Topology.Filter -import Mathlib.Topology.Defs.Sequences /-! # Proper maps between topological spaces @@ -20,8 +19,7 @@ the following equivalent conditions: of `ℱ`. We take 3 as the definition in `IsProperMap`, and we show the equivalence with 1, 2, and some -other variations. We also show the usual characterization of proper maps to a locally compact -Hausdorff space as continuous maps such that preimages of compact sets are compact. +other variations. ## Main statements @@ -30,11 +28,6 @@ Hausdorff space as continuous maps such that preimages of compact sets are compa * `IsProperMap.pi_map`: any product of proper maps is proper. * `isProperMap_iff_isClosedMap_and_compact_fibers`: a map is proper if and only if it is continuous, closed, and has compact fibers -* `isProperMap_iff_isCompact_preimage`: a map to a Hausdorff compactly generated space is proper if - and only if it is continuous and preimages of compact sets are compact. This is in particular - true if the space is locally compact or sequential. -* `isProperMap_iff_universally_closed`: a map is proper if and only if it is continuous and - universally closed, in the sense of condition 2. above. ## Implementation notes @@ -45,14 +38,6 @@ particular for the theory of proper group actions. That means that our terminolo align with that of [Stacks: Characterizing proper maps](https://stacks.math.columbia.edu/tag/005M), instead our definition of `IsProperMap` coincides with what they call "Bourbaki-proper". -Concerning `isProperMap_iff_isCompact_preimage`, this result should be the only one needed to link -the definition of a proper map and the criteria "preimage of compact sets are compact", however -the notion of compactly generated space is not yet in Mathlib (TODO) -so it is used as an intermediate result to prove -`WeaklyLocallyCompactSpace.isProperMap_iff_isCompact_preimage` and -`SequentialSpace.isProperMap_iff_isCompact_preimage`. In the future those should be inferred -by typeclass inference. - Regarding the proofs, we don't really follow Bourbaki and go for more filter-heavy proofs, as usual. In particular, their arguments rely heavily on restriction of closed maps (see `IsClosedMap.restrictPreimage`), which makes them somehow annoying to formalize in type theory. @@ -288,17 +273,25 @@ protected lemma IsHomeomorph.isProperMap (hf : IsHomeomorph f) : IsProperMap f : @[simp] lemma isProperMap_id : IsProperMap (id : X → X) := IsHomeomorph.id.isProperMap /-- A closed embedding is proper. -/ -lemma isProperMap_of_closedEmbedding (hf : ClosedEmbedding f) : IsProperMap f := +lemma IsClosedEmbedding.isProperMap (hf : IsClosedEmbedding f) : IsProperMap f := isProperMap_of_isClosedMap_of_inj hf.continuous hf.inj hf.isClosedMap +@[deprecated (since := "2024-10-20")] +alias isProperMap_of_closedEmbedding := IsClosedEmbedding.isProperMap + /-- The coercion from a closed subset is proper. -/ -lemma isProperMap_subtype_val_of_closed {U : Set X} (hU : IsClosed U) : IsProperMap ((↑) : U → X) := - isProperMap_of_closedEmbedding hU.closedEmbedding_subtype_val +lemma IsClosed.isProperMap_subtypeVal {C : Set X} (hC : IsClosed C) : IsProperMap ((↑) : C → X) := + hC.isClosedEmbedding_subtypeVal.isProperMap + +@[deprecated (since := "2024-10-20")] +alias isProperMap_subtype_val_of_closed := IsClosed.isProperMap_subtypeVal /-- The restriction of a proper map to a closed subset is proper. -/ -lemma isProperMap_restr_of_proper_of_closed {U : Set X} (hf : IsProperMap f) (hU : IsClosed U) : - IsProperMap (fun x : U ↦ f x) := - IsProperMap.comp (isProperMap_subtype_val_of_closed hU) hf +lemma IsProperMap.restrict {C : Set X} (hf : IsProperMap f) (hC : IsClosed C) : + IsProperMap fun x : C ↦ f x := hC.isProperMap_subtypeVal.comp hf + +@[deprecated (since := "2024-10-20")] +alias isProperMap_restr_of_proper_of_closed := IsProperMap.restrict /-- The range of a proper map is closed. -/ lemma IsProperMap.isClosed_range (hf : IsProperMap f) : IsClosed (range f) := @@ -322,95 +315,6 @@ lemma isProperMap_iff_isClosedMap_and_tendsto_cofinite [T1Space Y] : theorem Continuous.isProperMap [CompactSpace X] [T2Space Y] (hf : Continuous f) : IsProperMap f := isProperMap_iff_isClosedMap_and_tendsto_cofinite.2 ⟨hf, hf.isClosedMap, by simp⟩ -/-- If `Y` is Hausdorff and compactly generated, then proper maps `X → Y` are exactly -continuous maps such that the preimage of any compact set is compact. - -This result should be the only one needed to link the definition of a proper map and -the criteria "preimage of compact sets are compact", but the notion of compactly generated space -is not yet in Mathlib (TODO) so we use it as an intermediate result to prove -`WeaklyLocallyCompactSpace.isProperMap_iff_isCompact_preimage` and -`SequentialSpace.isProperMap_iff_isCompact_preimage`. In the future those should be inferred -by typeclass inference. -/ -theorem isProperMap_iff_isCompact_preimage [T2Space Y] - (compactlyGenerated : ∀ s : Set Y, IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K)) : - IsProperMap f ↔ Continuous f ∧ ∀ ⦃K⦄, IsCompact K → IsCompact (f ⁻¹' K) where - mp hf := ⟨hf.continuous, fun _ ↦ hf.isCompact_preimage⟩ - mpr := fun ⟨hf, h⟩ ↦ isProperMap_iff_isClosedMap_and_compact_fibers.2 - ⟨hf, fun _ hs ↦ (compactlyGenerated _).2 - fun _ hK ↦ image_inter_preimage .. ▸ (((h hK).inter_left hs).image hf).isClosed, - fun _ ↦ h isCompact_singleton⟩ - -/-- A locally compact space is compactly generated. -/ -theorem compactlyGenerated_of_weaklyLocallyCompactSpace [T2Space X] [WeaklyLocallyCompactSpace X] - {s : Set X} : IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K) := by - refine ⟨fun hs K hK ↦ hs.inter hK.isClosed, fun h ↦ ?_⟩ - rw [isClosed_iff_forall_filter] - intro x ℱ hℱ₁ hℱ₂ hℱ₃ - rcases exists_compact_mem_nhds x with ⟨K, hK, K_mem⟩ - exact mem_of_mem_inter_left <| isClosed_iff_forall_filter.1 (h hK) x ℱ hℱ₁ - (inf_principal ▸ le_inf hℱ₂ (le_trans hℱ₃ <| le_principal_iff.2 K_mem)) hℱ₃ - -/-- If `Y` is locally compact and Hausdorff, then proper maps `X → Y` are exactly continuous maps -such that the preimage of any compact set is compact. - -This result is a direct consequence of `isProperMap_iff_isCompact_preimage`, because any -Hausdorff and weakly locally compact space is compactly generated. -In the future it should be inferred by typeclass inference, however compactly generated spaces -are not yet in Mathlib (TODO), therefore we also add this theorem. -/ -theorem WeaklyLocallyCompactSpace.isProperMap_iff_isCompact_preimage [T2Space Y] - [WeaklyLocallyCompactSpace Y] : - IsProperMap f ↔ Continuous f ∧ ∀ ⦃K⦄, IsCompact K → IsCompact (f ⁻¹' K) := - _root_.isProperMap_iff_isCompact_preimage - (fun _ ↦ compactlyGenerated_of_weaklyLocallyCompactSpace) - -/-- A sequential space is compactly generated. -/ -theorem compactlyGenerated_of_sequentialSpace [T2Space X] [SequentialSpace X] {s : Set X} : - IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K) := by - refine ⟨fun hs K hK ↦ hs.inter hK.isClosed, - fun h ↦ SequentialSpace.isClosed_of_seq _ fun u p hu hup ↦ - mem_of_mem_inter_left ((h hup.isCompact_insert_range).mem_of_tendsto hup ?_)⟩ - simp only [mem_inter_iff, mem_insert_iff, mem_range, exists_apply_eq_apply, or_true, and_true, - eventually_atTop, ge_iff_le] - exact ⟨0, fun n _ ↦ hu n⟩ - -/-- If `Y` is sequential and Hausdorff, then proper maps `X → Y` are exactly continuous maps -such that the preimage of any compact set is compact. - -This result is a direct consequence of `isProperMap_iff_isCompact_preimage`, because any -Hausdorff and sequential space is compactly generated. In the future it should be inferred -by typeclass inference, however compactly generated spaces are not yet in Mathlib (TODO), -therefore we also add this theorem. -/ -theorem SequentialSpace.isProperMap_iff_isCompact_preimage [T2Space Y] [SequentialSpace Y] : - IsProperMap f ↔ Continuous f ∧ ∀ ⦃K⦄, IsCompact K → IsCompact (f ⁻¹' K) := - _root_.isProperMap_iff_isCompact_preimage - (fun _ ↦ compactlyGenerated_of_sequentialSpace) - -/-- Version of `isProperMap_iff_isCompact_preimage` in terms of `cocompact`. -/ -lemma isProperMap_iff_tendsto_cocompact [T2Space Y] - (compactlyGenerated : ∀ s : Set Y, IsClosed s ↔ ∀ ⦃K⦄, IsCompact K → IsClosed (s ∩ K)) : - IsProperMap f ↔ Continuous f ∧ Tendsto f (cocompact X) (cocompact Y) := by - simp_rw [isProperMap_iff_isCompact_preimage compactlyGenerated, - hasBasis_cocompact.tendsto_right_iff, ← mem_preimage, eventually_mem_set, preimage_compl] - refine and_congr_right fun f_cont ↦ - ⟨fun H K hK ↦ (H hK).compl_mem_cocompact, fun H K hK ↦ ?_⟩ - rcases mem_cocompact.mp (H K hK) with ⟨K', hK', hK'y⟩ - exact hK'.of_isClosed_subset (hK.isClosed.preimage f_cont) - (compl_le_compl_iff_le.mp hK'y) - -/-- Version of `WeaklyLocallyCompactSpace.isProperMap_iff_isCompact_preimage` -in terms of `cocompact`. -/ -lemma WeaklyLocallyCompactSpace.isProperMap_iff_tendsto_cocompact [T2Space Y] - [WeaklyLocallyCompactSpace Y] : - IsProperMap f ↔ Continuous f ∧ Tendsto f (cocompact X) (cocompact Y) := - _root_.isProperMap_iff_tendsto_cocompact - (fun _ ↦ compactlyGenerated_of_weaklyLocallyCompactSpace) - -/-- Version of `SequentialSpace.isProperMap_iff_isCompact_preimage` in terms of `cocompact`. -/ -lemma SequentialSpace.isProperMap_iff_tendsto_cocompact [T2Space Y] [SequentialSpace Y] : - IsProperMap f ↔ Continuous f ∧ Tendsto f (cocompact X) (cocompact Y) := - _root_.isProperMap_iff_tendsto_cocompact - (fun _ ↦ compactlyGenerated_of_sequentialSpace) - /-- A proper map `f : X → Y` is **universally closed**: for any topological space `Z`, the map `Prod.map f id : X × Z → Y × Z` is closed. We will prove in `isProperMap_iff_universally_closed` that proper maps are exactly continuous maps which have this property, but this result should be diff --git a/Mathlib/Topology/Maps/Proper/CompactlyGenerated.lean b/Mathlib/Topology/Maps/Proper/CompactlyGenerated.lean new file mode 100644 index 0000000000000..6213ed0602433 --- /dev/null +++ b/Mathlib/Topology/Maps/Proper/CompactlyGenerated.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2024 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker, Etienne Marion +-/ +import Mathlib.Topology.Compactness.CompactlyGeneratedSpace +import Mathlib.Topology.Maps.Proper.Basic + +/-! +# A map is proper iff preimage of compact sets are compact + +This file proves that if `Y` is a Hausdorff and compactly generated space, a continuous map +`f : X → Y` is proper if and only if preimage of compact sets are compact. +-/ + +open Set Filter + +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] +variable [T2Space Y] [CompactlyGeneratedSpace Y] +variable {f : X → Y} + +/-- If `Y` is Hausdorff and compactly generated, then proper maps `X → Y` are exactly +continuous maps such that the preimage of any compact set is compact. This is in particular true +if `Y` is Hausdorff and sequential or locally compact. + +There was an older version of this theorem which was changed to this one to make use +of the `CompactlyGeneratedSpace` typeclass. (since 2024-11-10) -/ +theorem isProperMap_iff_isCompact_preimage : + IsProperMap f ↔ Continuous f ∧ ∀ ⦃K⦄, IsCompact K → IsCompact (f ⁻¹' K) where + mp hf := ⟨hf.continuous, fun _ ↦ hf.isCompact_preimage⟩ + mpr := fun ⟨hf, h⟩ ↦ isProperMap_iff_isClosedMap_and_compact_fibers.2 + ⟨hf, fun _ hs ↦ CompactlyGeneratedSpace.isClosed + fun _ hK ↦ image_inter_preimage .. ▸ (((h hK).inter_left hs).image hf).isClosed, + fun _ ↦ h isCompact_singleton⟩ + +/-- Version of `isProperMap_iff_isCompact_preimage` in terms of `cocompact`. + +There was an older version of this theorem which was changed to this one to make use +of the `CompactlyGeneratedSpace` typeclass. (since 2024-11-10) -/ +lemma isProperMap_iff_tendsto_cocompact : + IsProperMap f ↔ Continuous f ∧ Tendsto f (cocompact X) (cocompact Y) := by + simp_rw [isProperMap_iff_isCompact_preimage, + hasBasis_cocompact.tendsto_right_iff, ← mem_preimage, eventually_mem_set, preimage_compl] + refine and_congr_right fun f_cont ↦ + ⟨fun H K hK ↦ (H hK).compl_mem_cocompact, fun H K hK ↦ ?_⟩ + rcases mem_cocompact.mp (H K hK) with ⟨K', hK', hK'y⟩ + exact hK'.of_isClosed_subset (hK.isClosed.preimage f_cont) + (compl_le_compl_iff_le.mp hK'y) diff --git a/Mathlib/Topology/MetricSpace/Algebra.lean b/Mathlib/Topology/MetricSpace/Algebra.lean index 724512392f31b..e8a16f85a6d7a 100644 --- a/Mathlib/Topology/MetricSpace/Algebra.lean +++ b/Mathlib/Topology/MetricSpace/Algebra.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ import Mathlib.Topology.Algebra.MulAction +import Mathlib.Topology.Algebra.SeparationQuotient.Basic import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Topology.MetricSpace.Lipschitz @@ -185,21 +186,21 @@ instance Pi.instBoundedSMul {α : Type*} {β : ι → Type*} [PseudoMetricSpace [∀ i, PseudoMetricSpace (β i)] [Zero α] [∀ i, Zero (β i)] [∀ i, SMul α (β i)] [∀ i, BoundedSMul α (β i)] : BoundedSMul α (∀ i, β i) where dist_smul_pair' x y₁ y₂ := - (dist_pi_le_iff <| by positivity).2 fun i ↦ + (dist_pi_le_iff <| by positivity).2 fun _ ↦ (dist_smul_pair _ _ _).trans <| mul_le_mul_of_nonneg_left (dist_le_pi_dist _ _ _) dist_nonneg dist_pair_smul' x₁ x₂ y := - (dist_pi_le_iff <| by positivity).2 fun i ↦ + (dist_pi_le_iff <| by positivity).2 fun _ ↦ (dist_pair_smul _ _ _).trans <| mul_le_mul_of_nonneg_left (dist_le_pi_dist _ 0 _) dist_nonneg instance Pi.instBoundedSMul' {α β : ι → Type*} [∀ i, PseudoMetricSpace (α i)] [∀ i, PseudoMetricSpace (β i)] [∀ i, Zero (α i)] [∀ i, Zero (β i)] [∀ i, SMul (α i) (β i)] [∀ i, BoundedSMul (α i) (β i)] : BoundedSMul (∀ i, α i) (∀ i, β i) where dist_smul_pair' x y₁ y₂ := - (dist_pi_le_iff <| by positivity).2 fun i ↦ + (dist_pi_le_iff <| by positivity).2 fun _ ↦ (dist_smul_pair _ _ _).trans <| mul_le_mul (dist_le_pi_dist _ 0 _) (dist_le_pi_dist _ _ _) dist_nonneg dist_nonneg dist_pair_smul' x₁ x₂ y := - (dist_pi_le_iff <| by positivity).2 fun i ↦ + (dist_pi_le_iff <| by positivity).2 fun _ ↦ (dist_pair_smul _ _ _).trans <| mul_le_mul (dist_le_pi_dist _ _ _) (dist_le_pi_dist _ 0 _) dist_nonneg dist_nonneg @@ -213,5 +214,11 @@ instance Prod.instBoundedSMul {α β γ : Type*} [PseudoMetricSpace α] [PseudoM max_le ((dist_pair_smul _ _ _).trans <| mul_le_mul_of_nonneg_left (le_max_left _ _) dist_nonneg) ((dist_pair_smul _ _ _).trans <| mul_le_mul_of_nonneg_left (le_max_right _ _) dist_nonneg) +instance {α β : Type*} + [PseudoMetricSpace α] [PseudoMetricSpace β] [Zero α] [Zero β] [SMul α β] [BoundedSMul α β] : + BoundedSMul α (SeparationQuotient β) where + dist_smul_pair' _ := Quotient.ind₂ <| dist_smul_pair _ + dist_pair_smul' _ _ := Quotient.ind <| dist_pair_smul _ _ + -- We don't have the `SMul α γ → SMul β δ → SMul (α × β) (γ × δ)` instance, but if we did, then -- `BoundedSMul α γ → BoundedSMul β δ → BoundedSMul (α × β) (γ × δ)` would hold diff --git a/Mathlib/Topology/MetricSpace/Antilipschitz.lean b/Mathlib/Topology/MetricSpace/Antilipschitz.lean index ac87aa46237ea..809699925af5d 100644 --- a/Mathlib/Topology/MetricSpace/Antilipschitz.lean +++ b/Mathlib/Topology/MetricSpace/Antilipschitz.lean @@ -143,29 +143,35 @@ theorem comap_uniformity_le (hf : AntilipschitzWith K f) : (𝓤 β).comap (Prod rw [mul_comm] exact ENNReal.mul_lt_of_lt_div hx -protected theorem uniformInducing (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : - UniformInducing f := +theorem isUniformInducing (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : + IsUniformInducing f := ⟨le_antisymm hf.comap_uniformity_le hfc.le_comap⟩ +@[deprecated (since := "2024-10-05")] +alias uniformInducing := isUniformInducing + lemma isUniformEmbedding {α β : Type*} [EMetricSpace α] [PseudoEMetricSpace β] {K : ℝ≥0} {f : α → β} (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : IsUniformEmbedding f := - ⟨hf.uniformInducing hfc, hf.injective⟩ + ⟨hf.isUniformInducing hfc, hf.injective⟩ @[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding theorem isComplete_range [CompleteSpace α] (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : IsComplete (range f) := - (hf.uniformInducing hfc).isComplete_range + (hf.isUniformInducing hfc).isComplete_range theorem isClosed_range {α β : Type*} [PseudoEMetricSpace α] [EMetricSpace β] [CompleteSpace α] {f : α → β} {K : ℝ≥0} (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : IsClosed (range f) := (hf.isComplete_range hfc).isClosed -theorem closedEmbedding {α : Type*} {β : Type*} [EMetricSpace α] [EMetricSpace β] {K : ℝ≥0} +theorem isClosedEmbedding {α : Type*} {β : Type*} [EMetricSpace α] [EMetricSpace β] {K : ℝ≥0} {f : α → β} [CompleteSpace α] (hf : AntilipschitzWith K f) (hfc : UniformContinuous f) : - ClosedEmbedding f := - { (hf.isUniformEmbedding hfc).embedding with isClosed_range := hf.isClosed_range hfc } + IsClosedEmbedding f := + { (hf.isUniformEmbedding hfc).isEmbedding with isClosed_range := hf.isClosed_range hfc } + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding := isClosedEmbedding theorem subtype_coe (s : Set α) : AntilipschitzWith 1 ((↑) : s → α) := AntilipschitzWith.id.restrict s diff --git a/Mathlib/Topology/MetricSpace/Basic.lean b/Mathlib/Topology/MetricSpace/Basic.lean index 028c1ab133161..7ba147f5faf72 100644 --- a/Mathlib/Topology/MetricSpace/Basic.lean +++ b/Mathlib/Topology/MetricSpace/Basic.lean @@ -36,7 +36,7 @@ theorem isUniformEmbedding_iff' [MetricSpace β] {f : γ → β} : IsUniformEmbedding f ↔ (∀ ε > 0, ∃ δ > 0, ∀ {a b : γ}, dist a b < δ → dist (f a) (f b) < ε) ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : γ}, dist (f a) (f b) < ε → dist a b < δ := by - rw [isUniformEmbedding_iff_uniformInducing, uniformInducing_iff, uniformContinuous_iff] + rw [isUniformEmbedding_iff_isUniformInducing, isUniformInducing_iff, uniformContinuous_iff] @[deprecated (since := "2024-10-01")] alias uniformEmbedding_iff' := isUniformEmbedding_iff' @@ -56,10 +56,13 @@ theorem isClosed_of_pairwise_le_dist {s : Set γ} {ε : ℝ} (hε : 0 < ε) (hs : s.Pairwise fun x y => ε ≤ dist x y) : IsClosed s := isClosed_of_spaced_out (dist_mem_uniformity hε) <| by simpa using hs -theorem closedEmbedding_of_pairwise_le_dist {α : Type*} [TopologicalSpace α] [DiscreteTopology α] +theorem isClosedEmbedding_of_pairwise_le_dist {α : Type*} [TopologicalSpace α] [DiscreteTopology α] {ε : ℝ} (hε : 0 < ε) {f : α → γ} (hf : Pairwise fun x y => ε ≤ dist (f x) (f y)) : - ClosedEmbedding f := - closedEmbedding_of_spaced_out (dist_mem_uniformity hε) <| by simpa using hf + IsClosedEmbedding f := + isClosedEmbedding_of_spaced_out (dist_mem_uniformity hε) <| by simpa using hf + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_of_pairwise_le_dist := isClosedEmbedding_of_pairwise_le_dist /-- If `f : β → α` sends any two distinct points to points at distance at least `ε > 0`, then `f` is a uniform embedding with respect to the discrete uniformity on `β`. -/ @@ -109,9 +112,12 @@ alias UniformEmbedding.comapMetricSpace := IsUniformEmbedding.comapMetricSpace /-- Pull back a metric space structure by an embedding. This is a version of `MetricSpace.induced` useful in case if the domain already has a `TopologicalSpace` structure. -/ -abbrev Embedding.comapMetricSpace {α β} [TopologicalSpace α] [m : MetricSpace β] (f : α → β) - (h : Embedding f) : MetricSpace α := - .replaceTopology (.induced f h.inj m) h.induced +abbrev IsEmbedding.comapMetricSpace {α β} [TopologicalSpace α] [m : MetricSpace β] + (f : α → β) (h : IsEmbedding f) : MetricSpace α := + .replaceTopology (.induced f h.inj m) h.eq_induced + +@[deprecated (since := "2024-10-26")] +alias Embedding.comapMetricSpace := IsEmbedding.comapMetricSpace instance Subtype.metricSpace {α : Type*} {p : α → Prop} [MetricSpace α] : MetricSpace (Subtype p) := diff --git a/Mathlib/Topology/MetricSpace/Bilipschitz.lean b/Mathlib/Topology/MetricSpace/Bilipschitz.lean index 432fad174bbe3..0e69f60fc5dbc 100644 --- a/Mathlib/Topology/MetricSpace/Bilipschitz.lean +++ b/Mathlib/Topology/MetricSpace/Bilipschitz.lean @@ -55,7 +55,7 @@ instance : UniformSpace α := (inferInstance : UniformSpace β).comap f in order to avoid abuse of the definitional equality `α := β`. -/ lemma uniformity_eq_of_bilipschitz (hf₁ : AntilipschitzWith K₁ f) (hf₂ : LipschitzWith K₂ f) : 𝓤[(inferInstance : UniformSpace β).comap f] = 𝓤 α := - hf₁.uniformInducing hf₂.uniformContinuous |>.comap_uniformity + hf₁.isUniformInducing hf₂.uniformContinuous |>.comap_uniformity end Uniformity diff --git a/Mathlib/Topology/MetricSpace/Bounded.lean b/Mathlib/Topology/MetricSpace/Bounded.lean index 5ce1a3fd60a5e..7bd2d18acad75 100644 --- a/Mathlib/Topology/MetricSpace/Bounded.lean +++ b/Mathlib/Topology/MetricSpace/Bounded.lean @@ -3,7 +3,7 @@ Copyright (c) 2015, 2017 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébastien Gouëzel -/ -import Mathlib.Topology.Algebra.Order.Compact +import Mathlib.Topology.Order.Compact import Mathlib.Topology.MetricSpace.ProperSpace import Mathlib.Topology.MetricSpace.Cauchy import Mathlib.Topology.EMetricSpace.Diam diff --git a/Mathlib/Topology/MetricSpace/Closeds.lean b/Mathlib/Topology/MetricSpace/Closeds.lean index cf5140b7380c9..32f085537b00a 100644 --- a/Mathlib/Topology/MetricSpace/Closeds.lean +++ b/Mathlib/Topology/MetricSpace/Closeds.lean @@ -38,9 +38,9 @@ variable {α : Type u} [EMetricSpace α] {s : Set α} on the type of closed subsets -/ instance Closeds.emetricSpace : EMetricSpace (Closeds α) where edist s t := hausdorffEdist (s : Set α) t - edist_self s := hausdorffEdist_self - edist_comm s t := hausdorffEdist_comm - edist_triangle s t u := hausdorffEdist_triangle + edist_self _ := hausdorffEdist_self + edist_comm _ _ := hausdorffEdist_comm + edist_triangle _ _ _ := hausdorffEdist_triangle eq_of_edist_eq_zero {s t} h := Closeds.ext <| (hausdorffEdist_zero_iff_eq_of_closed s.closed t.closed).1 h @@ -224,9 +224,9 @@ instance Closeds.compactSpace [CompactSpace α] : CompactSpace (Closeds α) := where the edistance is the Hausdorff edistance -/ instance NonemptyCompacts.emetricSpace : EMetricSpace (NonemptyCompacts α) where edist s t := hausdorffEdist (s : Set α) t - edist_self s := hausdorffEdist_self - edist_comm s t := hausdorffEdist_comm - edist_triangle s t u := hausdorffEdist_triangle + edist_self _ := hausdorffEdist_self + edist_comm _ _ := hausdorffEdist_comm + edist_triangle _ _ _ := hausdorffEdist_triangle eq_of_edist_eq_zero {s t} h := NonemptyCompacts.ext <| by have : closure (s : Set α) = closure t := hausdorffEdist_zero_iff_closure_eq_closure.1 h rwa [s.isCompact.isClosed.closure_eq, t.isCompact.isClosed.closure_eq] at this @@ -281,14 +281,14 @@ theorem NonemptyCompacts.isClosed_in_closeds [CompleteSpace α] : from the same statement for closed subsets -/ instance NonemptyCompacts.completeSpace [CompleteSpace α] : CompleteSpace (NonemptyCompacts α) := (completeSpace_iff_isComplete_range - NonemptyCompacts.ToCloseds.isUniformEmbedding.toUniformInducing).2 <| + NonemptyCompacts.ToCloseds.isUniformEmbedding.isUniformInducing).2 <| NonemptyCompacts.isClosed_in_closeds.isComplete /-- In a compact space, the type of nonempty compact subsets is compact. This follows from the same statement for closed subsets -/ instance NonemptyCompacts.compactSpace [CompactSpace α] : CompactSpace (NonemptyCompacts α) := ⟨by - rw [NonemptyCompacts.ToCloseds.isUniformEmbedding.embedding.isCompact_iff, image_univ] + rw [NonemptyCompacts.ToCloseds.isUniformEmbedding.isEmbedding.isCompact_iff, image_univ] exact NonemptyCompacts.isClosed_in_closeds.isCompact⟩ /-- In a second countable space, the type of nonempty compact subsets is second countable -/ diff --git a/Mathlib/Topology/MetricSpace/Contracting.lean b/Mathlib/Topology/MetricSpace/Contracting.lean index 2fcec8e182a86..ac3f24a9253fa 100644 --- a/Mathlib/Topology/MetricSpace/Contracting.lean +++ b/Mathlib/Topology/MetricSpace/Contracting.lean @@ -137,7 +137,7 @@ theorem efixedPoint_eq_of_edist_lt_top (hf : ContractingWith K f) {x : α} (hx : efixedPoint f hf x hx = efixedPoint f hf y hy := by refine (hf.eq_or_edist_eq_top_of_fixedPoints ?_ ?_).elim id fun h' ↦ False.elim (ne_of_lt ?_ h') <;> try apply efixedPoint_isFixedPt - change edistLtTopSetoid.Rel _ _ + change edistLtTopSetoid _ _ trans x · apply Setoid.symm' -- Porting note: Originally `symm` exact hf.edist_efixedPoint_lt_top hx @@ -221,7 +221,7 @@ theorem efixedPoint_eq_of_edist_lt_top' (hf : ContractingWith K f) {s : Set α} efixedPoint' f hsc hsf hfs x hxs hx = efixedPoint' f htc htf hft y hyt hy := by refine (hf.eq_or_edist_eq_top_of_fixedPoints ?_ ?_).elim id fun h' ↦ False.elim (ne_of_lt ?_ h') <;> try apply efixedPoint_isFixedPt' - change edistLtTopSetoid.Rel _ _ + change edistLtTopSetoid _ _ trans x · apply Setoid.symm' -- Porting note: Originally `symm` apply edist_efixedPoint_lt_top' diff --git a/Mathlib/Topology/MetricSpace/Dilation.lean b/Mathlib/Topology/MetricSpace/Dilation.lean index 0741095653d32..3e66eb3f4f28b 100644 --- a/Mathlib/Topology/MetricSpace/Dilation.lean +++ b/Mathlib/Topology/MetricSpace/Dilation.lean @@ -87,9 +87,6 @@ instance funLike : FunLike (α →ᵈ β) α β where instance toDilationClass : DilationClass (α →ᵈ β) α β where edist_eq' f := edist_eq' f -instance : CoeFun (α →ᵈ β) fun _ => α → β := - DFunLike.hasCoeToFun - @[simp] theorem toFun_eq_coe {f : α →ᵈ β} : f.toFun = (f : α → β) := rfl @@ -270,8 +267,8 @@ protected def id (α) [PseudoEMetricSpace α] : α →ᵈ α where instance : Inhabited (α →ᵈ α) := ⟨Dilation.id α⟩ -@[simp] -- Porting note: Removed `@[protected]` -theorem coe_id : ⇑(Dilation.id α) = id := +@[simp] +protected theorem coe_id : ⇑(Dilation.id α) = id := rfl theorem ratio_id : ratio (Dilation.id α) = 1 := by @@ -326,7 +323,7 @@ instance : Monoid (α →ᵈ α) where mul := comp mul_one := comp_id one_mul := id_comp - mul_assoc f g h := comp_assoc _ _ _ + mul_assoc _ _ _ := comp_assoc _ _ _ theorem one_def : (1 : α →ᵈ α) = Dilation.id α := rfl @@ -370,12 +367,15 @@ theorem cancel_left {g : β →ᵈ γ} {f₁ f₂ : α →ᵈ β} (hg : Injectiv ⟨fun h => Dilation.ext fun x => hg <| by rw [← comp_apply, h, comp_apply], fun h => h ▸ rfl⟩ /-- A dilation from a metric space is a uniform inducing map -/ -protected theorem uniformInducing : UniformInducing (f : α → β) := - (antilipschitz f).uniformInducing (lipschitz f).uniformContinuous +theorem isUniformInducing : IsUniformInducing (f : α → β) := + (antilipschitz f).isUniformInducing (lipschitz f).uniformContinuous + +@[deprecated (since := "2024-10-05")] +alias uniformInducing := isUniformInducing theorem tendsto_nhds_iff {ι : Type*} {g : ι → α} {a : Filter ι} {b : α} : Filter.Tendsto g a (𝓝 b) ↔ Filter.Tendsto ((f : α → β) ∘ g) a (𝓝 (f b)) := - (Dilation.uniformInducing f).inducing.tendsto_nhds_iff + (Dilation.isUniformInducing f).isInducing.tendsto_nhds_iff /-- A dilation is continuous. -/ theorem toContinuous : Continuous (f : α → β) := @@ -406,11 +406,11 @@ theorem mapsTo_emetric_closedBall (x : α) (r' : ℝ≥0∞) : theorem comp_continuousOn_iff {γ} [TopologicalSpace γ] {g : γ → α} {s : Set γ} : ContinuousOn ((f : α → β) ∘ g) s ↔ ContinuousOn g s := - (Dilation.uniformInducing f).inducing.continuousOn_iff.symm + (Dilation.isUniformInducing f).isInducing.continuousOn_iff.symm theorem comp_continuous_iff {γ} [TopologicalSpace γ] {g : γ → α} : Continuous ((f : α → β) ∘ g) ↔ Continuous g := - (Dilation.uniformInducing f).inducing.continuous_iff.symm + (Dilation.isUniformInducing f).isInducing.continuous_iff.symm end PseudoEmetricDilation @@ -427,14 +427,19 @@ lemma isUniformEmbedding [PseudoEMetricSpace β] [DilationClass F α β] (f : F) @[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding /-- A dilation from a metric space is an embedding -/ -protected theorem embedding [PseudoEMetricSpace β] [DilationClass F α β] (f : F) : - Embedding (f : α → β) := - (Dilation.isUniformEmbedding f).embedding +theorem isEmbedding [PseudoEMetricSpace β] [DilationClass F α β] (f : F) : + IsEmbedding (f : α → β) := + (Dilation.isUniformEmbedding f).isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding /-- A dilation from a complete emetric space is a closed embedding -/ -protected theorem closedEmbedding [CompleteSpace α] [EMetricSpace β] [DilationClass F α β] (f : F) : - ClosedEmbedding f := - (antilipschitz f).closedEmbedding (lipschitz f).uniformContinuous +lemma isClosedEmbedding [CompleteSpace α] [EMetricSpace β] [DilationClass F α β] (f : F) : + IsClosedEmbedding f := + (antilipschitz f).isClosedEmbedding (lipschitz f).uniformContinuous + +@[deprecated (since := "2024-10-20")] alias closedEmbedding := isClosedEmbedding end EmetricDilation diff --git a/Mathlib/Topology/MetricSpace/DilationEquiv.lean b/Mathlib/Topology/MetricSpace/DilationEquiv.lean index d510cd58fb9e7..3fffba7e08305 100644 --- a/Mathlib/Topology/MetricSpace/DilationEquiv.lean +++ b/Mathlib/Topology/MetricSpace/DilationEquiv.lean @@ -60,9 +60,6 @@ instance : EquivLike (X ≃ᵈ Y) X Y where instance : DilationEquivClass (X ≃ᵈ Y) X Y where edist_eq' f := f.edist_eq' -instance : CoeFun (X ≃ᵈ Y) fun _ ↦ (X → Y) where - coe f := f - @[simp] theorem coe_toEquiv (e : X ≃ᵈ Y) : ⇑e.toEquiv = e := rfl @[ext] diff --git a/Mathlib/Topology/MetricSpace/Gluing.lean b/Mathlib/Topology/MetricSpace/Gluing.lean index 53a7579e013fa..f11b797b3559e 100644 --- a/Mathlib/Topology/MetricSpace/Gluing.lean +++ b/Mathlib/Topology/MetricSpace/Gluing.lean @@ -129,8 +129,8 @@ private theorem glueDist_triangle_inl_inr_inl (Φ : Z → X) (Ψ : Z → Y) (ε private theorem glueDist_triangle (Φ : Z → X) (Ψ : Z → Y) (ε : ℝ) (H : ∀ p q, |dist (Φ p) (Φ q) - dist (Ψ p) (Ψ q)| ≤ 2 * ε) : ∀ x y z, glueDist Φ Ψ ε x z ≤ glueDist Φ Ψ ε x y + glueDist Φ Ψ ε y z - | .inl x, .inl y, .inl z => dist_triangle _ _ _ - | .inr x, .inr y, .inr z => dist_triangle _ _ _ + | .inl _, .inl _, .inl _ => dist_triangle _ _ _ + | .inr _, .inr _, .inr _ => dist_triangle _ _ _ | .inr x, .inl y, .inl z => by simp only [← glueDist_swap Φ] apply glueDist_triangle_inl_inr_inr @@ -139,7 +139,7 @@ private theorem glueDist_triangle (Φ : Z → X) (Ψ : Z → Y) (ε : ℝ) | .inl x, .inl y, .inr z => by simpa only [← glueDist_swap Φ, glueDist_comm, add_comm, Sum.swap_inl, Sum.swap_inr] using glueDist_triangle_inl_inr_inr Ψ Φ ε z y x - | .inl x, .inr y, .inr z => glueDist_triangle_inl_inr_inr .. + | .inl _, .inr _, .inr _ => glueDist_triangle_inl_inr_inr .. | .inl x, .inr y, .inl z => glueDist_triangle_inl_inr_inl Φ Ψ ε H x y z | .inr x, .inl y, .inr z => by simp only [← glueDist_swap Φ] @@ -243,8 +243,7 @@ private theorem Sum.mem_uniformity (s : Set ((X ⊕ Y) × (X ⊕ Y))) : · cases not_le_of_lt (lt_of_lt_of_le h (min_le_right _ _)) Sum.one_le_dist_inr_inl · exact hY (lt_of_lt_of_le h (le_trans (min_le_left _ _) (min_le_right _ _))) · rintro ⟨ε, ε0, H⟩ - constructor <;> rw [Filter.mem_sets, Filter.mem_map, mem_uniformity_dist] <;> - exact ⟨ε, ε0, fun h => H _ _ h⟩ + constructor <;> rw [Filter.mem_map, mem_uniformity_dist] <;> exact ⟨ε, ε0, fun h => H _ _ h⟩ /-- The distance on the disjoint union indeed defines a metric space. All the distance properties follow from our choice of the distance. The harder work is to show that the uniform structure @@ -432,7 +431,7 @@ protected theorem completeSpace [∀ i, CompleteSpace (E i)] : CompleteSpace (Σ set U := { p : (Σk, E k) × Σk, E k | dist p.1 p.2 < 1 } have hc : ∀ i, IsComplete (s i) := fun i => by simp only [s, ← range_sigmaMk] - exact (isometry_mk i).uniformInducing.isComplete_range + exact (isometry_mk i).isUniformInducing.isComplete_range have hd : ∀ (i j), ∀ x ∈ s i, ∀ y ∈ s j, (x, y) ∈ U → i = j := fun i j x hx y hy hxy => (Eq.symm hx).trans ((fst_eq_of_dist_lt_one _ _ hxy).trans hy) refine completeSpace_of_isComplete_univ ?_ diff --git a/Mathlib/Topology/MetricSpace/GromovHausdorff.lean b/Mathlib/Topology/MetricSpace/GromovHausdorff.lean index 8b58e2adf2ada..7082a492d3c8f 100644 --- a/Mathlib/Topology/MetricSpace/GromovHausdorff.lean +++ b/Mathlib/Topology/MetricSpace/GromovHausdorff.lean @@ -789,7 +789,7 @@ theorem totallyBounded {t : Set GHSpace} {C : ℝ} {u : ℕ → ℝ} {K : ℕ exact fun hp' => (hp hp').elim · rcases hcov _ (Set.not_not_mem.1 hp) n with ⟨s, ⟨scard, scover⟩⟩ rcases Cardinal.lt_aleph0.1 (lt_of_le_of_lt scard (Cardinal.nat_lt_aleph0 _)) with ⟨N, hN⟩ - rw [hN, Cardinal.natCast_le] at scard + rw [hN, Nat.cast_le] at scard have : #s = #(Fin N) := by rw [hN, Cardinal.mk_fin] cases' Quotient.exact this with E use s, N, scard, E diff --git a/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean b/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean index 9a6979a644bb1..1610895150222 100644 --- a/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean +++ b/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean @@ -432,9 +432,9 @@ predistance is given by the candidate. Then, we will identify points at `0` pred to obtain a genuine metric space. -/ def premetricOptimalGHDist : PseudoMetricSpace (X ⊕ Y) where dist p q := optimalGHDist X Y (p, q) - dist_self x := candidates_refl (optimalGHDist_mem_candidatesB X Y) - dist_comm x y := candidates_symm (optimalGHDist_mem_candidatesB X Y) - dist_triangle x y z := candidates_triangle (optimalGHDist_mem_candidatesB X Y) + dist_self _ := candidates_refl (optimalGHDist_mem_candidatesB X Y) + dist_comm _ _ := candidates_symm (optimalGHDist_mem_candidatesB X Y) + dist_triangle _ _ _ := candidates_triangle (optimalGHDist_mem_candidatesB X Y) -- Porting note (#10888): added proof for `edist_dist` edist_dist x y := by simp only diff --git a/Mathlib/Topology/MetricSpace/HausdorffDimension.lean b/Mathlib/Topology/MetricSpace/HausdorffDimension.lean index 46a5798a92a07..eba2e6682959f 100644 --- a/Mathlib/Topology/MetricSpace/HausdorffDimension.lean +++ b/Mathlib/Topology/MetricSpace/HausdorffDimension.lean @@ -254,7 +254,7 @@ end -/ -variable {C K r : ℝ≥0} {f : X → Y} {s t : Set X} +variable {C K r : ℝ≥0} {f : X → Y} {s : Set X} /-- If `f` is a Hölder continuous map with exponent `r > 0`, then `dimH (f '' s) ≤ dimH s / r`. -/ theorem HolderOnWith.dimH_image_le (h : HolderOnWith C r f s) (hr : 0 < r) : diff --git a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean index fc2c6abdca52c..698c804dacc7e 100644 --- a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean +++ b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean @@ -114,7 +114,7 @@ the edist from `x` to `y` -/ theorem infEdist_le_infEdist_add_edist : infEdist x s ≤ infEdist y s + edist x y := calc ⨅ z ∈ s, edist x z ≤ ⨅ z ∈ s, edist y z + edist x y := - iInf₂_mono fun z _ => (edist_triangle _ _ _).trans_eq (add_comm _ _) + iInf₂_mono fun _ _ => (edist_triangle _ _ _).trans_eq (add_comm _ _) _ = (⨅ z ∈ s, edist y z) + edist x y := by simp only [ENNReal.iInf_add] theorem infEdist_le_edist_add_infEdist : infEdist x s ≤ edist x y + infEdist y s := by @@ -249,7 +249,7 @@ irreducible_def hausdorffEdist {α : Type u} [PseudoEMetricSpace α] (s t : Set section HausdorffEdist -variable [PseudoEMetricSpace α] [PseudoEMetricSpace β] {x y : α} {s t u : Set α} {Φ : α → β} +variable [PseudoEMetricSpace α] [PseudoEMetricSpace β] {x : α} {s t u : Set α} {Φ : α → β} /-- The Hausdorff edistance of a set to itself vanishes. -/ @[simp] @@ -378,7 +378,6 @@ theorem hausdorffEdist_closure₂ : hausdorffEdist s (closure t) = hausdorffEdis simp [@hausdorffEdist_comm _ _ s _] /-- The Hausdorff edistance between sets or their closures is the same. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem hausdorffEdist_closure : hausdorffEdist (closure s) (closure t) = hausdorffEdist s t := by simp @@ -451,7 +450,7 @@ theorem infEdist_ne_top (h : s.Nonempty) : infEdist x s ≠ ⊤ := by rcases h with ⟨y, hy⟩ exact ne_top_of_le_ne_top (edist_ne_top _ _) (infEdist_le_edist_of_mem hy) --- Porting note (#11215): TODO: make it a `simp` lemma +@[simp] theorem infEdist_eq_top_iff : infEdist x s = ∞ ↔ s = ∅ := by rcases s.eq_empty_or_nonempty with rfl | hs <;> simp [*, Nonempty.ne_empty, infEdist_ne_top] @@ -777,7 +776,6 @@ theorem hausdorffDist_closure₂ : hausdorffDist s (closure t) = hausdorffDist s simp [hausdorffDist] /-- The Hausdorff distances between two sets and their closures coincide. -/ --- @[simp] -- Porting note (#10618): simp can prove this theorem hausdorffDist_closure : hausdorffDist (closure s) (closure t) = hausdorffDist s t := by simp [hausdorffDist] diff --git a/Mathlib/Topology/MetricSpace/Holder.lean b/Mathlib/Topology/MetricSpace/Holder.lean index da0e2b14c4f81..70758a458af3f 100644 --- a/Mathlib/Topology/MetricSpace/Holder.lean +++ b/Mathlib/Topology/MetricSpace/Holder.lean @@ -239,7 +239,7 @@ end PseudoMetric section Metric -variable [PseudoMetricSpace X] [MetricSpace Y] {C r : ℝ≥0} {f : X → Y} +variable [PseudoMetricSpace X] [MetricSpace Y] {r : ℝ≥0} {f : X → Y} @[simp] lemma holderWith_zero_iff : HolderWith 0 r f ↔ ∀ x₁ x₂, f x₁ = f x₂ := by diff --git a/Mathlib/Topology/MetricSpace/HolderNorm.lean b/Mathlib/Topology/MetricSpace/HolderNorm.lean new file mode 100644 index 0000000000000..424128d4adb85 --- /dev/null +++ b/Mathlib/Topology/MetricSpace/HolderNorm.lean @@ -0,0 +1,265 @@ +/- +Copyright (c) 2024 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying +-/ +import Mathlib.Topology.MetricSpace.Holder + +/-! +# Hölder norm + +This file defines the Hölder (semi-)norm for Hölder functions alongside some basic properties. +The `r`-Hölder norm of a function `f : X → Y` between two metric spaces is the least non-negative +real number `C` for which `f` is `r`-Hölder continuous with constant `C`, i.e. it is the least `C` +for which `WithHolder C r f` is true. + +## Main definitions + +* `eHolderNorm r f`: `r`-Hölder (semi-)norm in `ℝ≥0∞` of a function `f`. +* `nnHolderNorm r f`: `r`-Hölder (semi-)norm in `ℝ≥0` of a function `f`. +* `MemHolder r f`: Predicate for a function `f` being `r`-Hölder continuous. + +## Main results + +* `eHolderNorm_eq_zero`: the Hölder norm of a function is zero if and only if it is constant. +* `MemHolder.holderWith`: The Hölder norm of a Hölder function `f` is a Hölder constant of `f`. + +## Tags + +Hölder norm, Hoelder norm, Holder norm + +-/ + +variable {X Y : Type*} + +open Filter Set + +open NNReal ENNReal Topology + +section PseudoEMetricSpace + +variable [PseudoEMetricSpace X] [PseudoEMetricSpace Y] {r : ℝ≥0} {f : X → Y} + +/-- The `r`-Hölder (semi-)norm in `ℝ≥0∞` of a function `f` is the least non-negative real +number `C` for which `f` is `r`-Hölder continuous with constant `C`. This is `∞` if no such +non-negative real exists. -/ +noncomputable +def eHolderNorm (r : ℝ≥0) (f : X → Y) : ℝ≥0∞ := ⨅ (C) (_ : HolderWith C r f), C + +/-- The `r`-Hölder (semi)norm in `ℝ≥0`. -/ +noncomputable +def nnHolderNorm (r : ℝ≥0) (f : X → Y) : ℝ≥0 := (eHolderNorm r f).toNNReal + +/-- A function `f` is `MemHolder r f` if it is Hölder continuous. Namely, `f` has a finite +`r`-Hölder constant. This is equivalent to `f` having finite Hölder norm. +c.f. `memHolder_iff`. -/ +def MemHolder (r : ℝ≥0) (f : X → Y) : Prop := ∃ C, HolderWith C r f + +lemma HolderWith.memHolder {C : ℝ≥0} (hf : HolderWith C r f) : MemHolder r f := ⟨C, hf⟩ + +@[simp] lemma eHolderNorm_lt_top : eHolderNorm r f < ∞ ↔ MemHolder r f := by + refine ⟨fun h => ?_, + fun hf => let ⟨C, hC⟩ := hf; iInf_lt_top.2 ⟨C, iInf_lt_top.2 ⟨hC, coe_lt_top⟩⟩⟩ + simp_rw [eHolderNorm, iInf_lt_top] at h + exact let ⟨C, hC, _⟩ := h; ⟨C, hC⟩ + +lemma eHolderNorm_ne_top : eHolderNorm r f ≠ ∞ ↔ MemHolder r f := by + rw [← eHolderNorm_lt_top, lt_top_iff_ne_top] + +@[simp] lemma eHolderNorm_eq_top : eHolderNorm r f = ∞ ↔ ¬ MemHolder r f := by + rw [← eHolderNorm_ne_top, not_not] + +protected alias ⟨_, MemHolder.eHolderNorm_lt_top⟩ := eHolderNorm_lt_top +protected alias ⟨_, MemHolder.eHolderNorm_ne_top⟩ := eHolderNorm_ne_top + +lemma coe_nnHolderNorm_le_eHolderNorm {r : ℝ≥0} {f : X → Y} : + (nnHolderNorm r f : ℝ≥0∞) ≤ eHolderNorm r f := + coe_toNNReal_le_self + +variable (X) in +@[simp] +lemma eHolderNorm_const (r : ℝ≥0) (c : Y) : eHolderNorm r (Function.const X c) = 0 := by + rw [eHolderNorm, ← ENNReal.bot_eq_zero, iInf₂_eq_bot] + exact fun C' hC' => ⟨0, .const, hC'⟩ + +variable (X) in +@[simp] +lemma eHolderNorm_zero [Zero Y] (r : ℝ≥0) : eHolderNorm r (0 : X → Y) = 0 := + eHolderNorm_const X r 0 + +variable (X) in +@[simp] +lemma nnHolderNorm_const (r : ℝ≥0) (c : Y) : nnHolderNorm r (Function.const X c) = 0 := by + refine le_antisymm (ENNReal.coe_le_coe.1 <| + le_trans coe_nnHolderNorm_le_eHolderNorm ?_) (zero_le _) + rw [eHolderNorm_const] + rfl + +variable (X) in +@[simp] +lemma nnHolderNorm_zero [Zero Y] (r : ℝ≥0) : nnHolderNorm r (0 : X → Y) = 0 := + nnHolderNorm_const X r 0 + +attribute [simp] eHolderNorm_const eHolderNorm_zero + +lemma eHolderNorm_of_isEmpty [hX : IsEmpty X] : + eHolderNorm r f = 0 := by + rw [eHolderNorm, ← ENNReal.bot_eq_zero, iInf₂_eq_bot] + exact fun ε hε => ⟨0, .of_isEmpty, hε⟩ + +lemma HolderWith.eHolderNorm_le {C : ℝ≥0} (hf : HolderWith C r f) : + eHolderNorm r f ≤ C := + iInf₂_le C hf + +/-- See also `memHolder_const` for the version with the spelling `fun _ ↦ c`. -/ +@[simp] +lemma memHolder_const {c : Y} : MemHolder r (Function.const X c) := + (HolderWith.const (C := 0)).memHolder + +/-- Version of `memHolder_const` with the spelling `fun _ ↦ c` for the constant function. -/ +@[simp] +lemma memHolder_const' {c : Y} : MemHolder r (fun _ ↦ c : X → Y) := + memHolder_const + +@[simp] +lemma memHolder_zero [Zero Y] : MemHolder r (0 : X → Y) := + memHolder_const + +end PseudoEMetricSpace + +section MetricSpace + +variable [MetricSpace X] [EMetricSpace Y] + +lemma eHolderNorm_eq_zero {r : ℝ≥0} {f : X → Y} : + eHolderNorm r f = 0 ↔ ∀ x₁ x₂, f x₁ = f x₂ := by + constructor + · refine fun h x₁ x₂ => ?_ + by_cases hx : x₁ = x₂ + · rw [hx] + · rw [eHolderNorm, ← ENNReal.bot_eq_zero, iInf₂_eq_bot] at h + rw [← edist_eq_zero, ← le_zero_iff] + refine le_of_forall_lt' fun b hb => ?_ + obtain ⟨C, hC, hC'⟩ := h (b / edist x₁ x₂ ^ (r : ℝ)) + (ENNReal.div_pos hb.ne.symm (ENNReal.rpow_lt_top_of_nonneg zero_le_coe + (edist_lt_top x₁ x₂).ne).ne) + exact lt_of_le_of_lt (hC x₁ x₂) <| ENNReal.mul_lt_of_lt_div hC' + · intro h + cases' isEmpty_or_nonempty X with hX hX + · haveI := hX + exact eHolderNorm_of_isEmpty + · rw [← eHolderNorm_const X r (f hX.some)] + congr + simp [funext_iff, h _ hX.some] + +lemma MemHolder.holderWith {r : ℝ≥0} {f : X → Y} (hf : MemHolder r f) : + HolderWith (nnHolderNorm r f) r f := by + intros x₁ x₂ + by_cases hx : x₁ = x₂ + · simp only [hx, edist_self, zero_le] + rw [nnHolderNorm, eHolderNorm, coe_toNNReal] + on_goal 2 => exact hf.eHolderNorm_lt_top.ne + have h₁ : edist x₁ x₂ ^ (r : ℝ) ≠ 0 := + (Ne.symm <| ne_of_lt <| ENNReal.rpow_pos (edist_pos.2 hx) (edist_lt_top x₁ x₂).ne) + have h₂ : edist x₁ x₂ ^ (r : ℝ) ≠ ∞ := by + simp [(edist_lt_top x₁ x₂).ne] + rw [← ENNReal.div_le_iff h₁ h₂] + refine le_iInf₂ fun C hC => ?_ + rw [ENNReal.div_le_iff h₁ h₂] + exact hC x₁ x₂ + +lemma memHolder_iff_holderWith {r : ℝ≥0} {f : X → Y} : + MemHolder r f ↔ HolderWith (nnHolderNorm r f) r f := + ⟨MemHolder.holderWith, HolderWith.memHolder⟩ + +lemma MemHolder.coe_nnHolderNorm_eq_eHolderNorm + {r : ℝ≥0} {f : X → Y} (hf : MemHolder r f) : + (nnHolderNorm r f : ℝ≥0∞) = eHolderNorm r f := by + rw [nnHolderNorm, coe_toNNReal] + exact ne_of_lt <| lt_of_le_of_lt hf.holderWith.eHolderNorm_le <| coe_lt_top + +lemma HolderWith.nnholderNorm_le {C r : ℝ≥0} {f : X → Y} (hf : HolderWith C r f) : + nnHolderNorm r f ≤ C := by + rw [← ENNReal.coe_le_coe, hf.memHolder.coe_nnHolderNorm_eq_eHolderNorm] + exact hf.eHolderNorm_le + +lemma MemHolder.comp {r s : ℝ≥0} {Z : Type*} [MetricSpace Z] {f : Z → X} {g : X → Y} + (hf : MemHolder r f) (hg : MemHolder s g) : MemHolder (s * r) (g ∘ f) := + (hg.holderWith.comp hf.holderWith).memHolder + +lemma MemHolder.nnHolderNorm_eq_zero {r : ℝ≥0} {f : X → Y} (hf : MemHolder r f) : + nnHolderNorm r f = 0 ↔ ∀ x₁ x₂, f x₁ = f x₂ := by + rw [← ENNReal.coe_eq_zero, hf.coe_nnHolderNorm_eq_eHolderNorm, eHolderNorm_eq_zero] + +end MetricSpace + +section SeminormedAddCommGroup + +variable [MetricSpace X] [NormedAddCommGroup Y] +variable {r : ℝ≥0} {f g : X → Y} + +lemma MemHolder.add (hf : MemHolder r f) (hg : MemHolder r g) : MemHolder r (f + g) := + (hf.holderWith.add hg.holderWith).memHolder + +lemma MemHolder.smul {𝕜} [NormedDivisionRing 𝕜] [Module 𝕜 Y] [BoundedSMul 𝕜 Y] + {c : 𝕜} (hf : MemHolder r f) : MemHolder r (c • f) := + (hf.holderWith.smul c).memHolder + +lemma MemHolder.nsmul [Module ℝ Y] [BoundedSMul ℝ Y] (n : ℕ) (hf : MemHolder r f) : + MemHolder r (n • f) := by + simp [← Nat.cast_smul_eq_nsmul (R := ℝ), hf.smul] + +lemma MemHolder.nnHolderNorm_add_le (hf : MemHolder r f) (hg : MemHolder r g) : + nnHolderNorm r (f + g) ≤ nnHolderNorm r f + nnHolderNorm r g := + (hf.add hg).holderWith.nnholderNorm_le.trans <| + coe_le_coe.2 (hf.holderWith.add hg.holderWith).nnholderNorm_le + +lemma eHolderNorm_add_le : + eHolderNorm r (f + g) ≤ eHolderNorm r f + eHolderNorm r g := by + by_cases hfg : MemHolder r f ∧ MemHolder r g + · obtain ⟨hf, hg⟩ := hfg + rw [← hf.coe_nnHolderNorm_eq_eHolderNorm, ← hg.coe_nnHolderNorm_eq_eHolderNorm, + ← (hf.add hg).coe_nnHolderNorm_eq_eHolderNorm, ← coe_add, ENNReal.coe_le_coe] + exact hf.nnHolderNorm_add_le hg + · rw [Classical.not_and_iff_or_not_not, ← eHolderNorm_eq_top, ← eHolderNorm_eq_top] at hfg + obtain (h | h) := hfg + all_goals simp [h] + +lemma eHolderNorm_smul {α} [NormedDivisionRing α] [Module α Y] [BoundedSMul α Y] (c : α) : + eHolderNorm r (c • f) = ‖c‖₊ * eHolderNorm r f := by + by_cases hc : ‖c‖₊ = 0 + · rw [nnnorm_eq_zero] at hc + simp [hc] + by_cases hf : MemHolder r f + · refine le_antisymm ((hf.holderWith.smul c).eHolderNorm_le.trans ?_) <| mul_le_of_le_div' ?_ + · rw [coe_mul, hf.coe_nnHolderNorm_eq_eHolderNorm, mul_comm] + · rw [← (hf.holderWith.smul c).memHolder.coe_nnHolderNorm_eq_eHolderNorm, ← coe_div hc] + refine HolderWith.eHolderNorm_le fun x₁ x₂ => ?_ + rw [coe_div hc, ← ENNReal.mul_div_right_comm, + ENNReal.le_div_iff_mul_le (Or.inl <| coe_ne_zero.2 hc) <| Or.inl coe_ne_top, + mul_comm, ← smul_eq_mul, ← ENNReal.smul_def, ← edist_smul₀, ← Pi.smul_apply, + ← Pi.smul_apply] + exact hf.smul.holderWith x₁ x₂ + · rw [← eHolderNorm_eq_top] at hf + rw [hf, mul_top <| coe_ne_zero.2 hc, eHolderNorm_eq_top] + rw [nnnorm_eq_zero] at hc + intro h + have := h.smul (c := c⁻¹) + rw [inv_smul_smul₀ hc] at this + exact this.eHolderNorm_lt_top.ne hf + +lemma MemHolder.nnHolderNorm_smul {α} [NormedDivisionRing α] [Module α Y] [BoundedSMul α Y] + (hf : MemHolder r f) (c : α) : + nnHolderNorm r (c • f) = ‖c‖₊ * nnHolderNorm r f := by + rw [← ENNReal.coe_inj, coe_mul, hf.coe_nnHolderNorm_eq_eHolderNorm, + hf.smul.coe_nnHolderNorm_eq_eHolderNorm, eHolderNorm_smul] + +lemma eHolderNorm_nsmul [Module ℝ Y] [BoundedSMul ℝ Y] (n : ℕ) : + eHolderNorm r (n • f) = n • eHolderNorm r f := by + simp [← Nat.cast_smul_eq_nsmul (R := ℝ), eHolderNorm_smul] + +lemma MemHolder.nnHolderNorm_nsmul [Module ℝ Y] [BoundedSMul ℝ Y] (n : ℕ) (hf : MemHolder r f) : + nnHolderNorm r (n • f) = n • nnHolderNorm r f := by + simp [← Nat.cast_smul_eq_nsmul (R := ℝ), hf.nnHolderNorm_smul] + +end SeminormedAddCommGroup diff --git a/Mathlib/Topology/MetricSpace/Infsep.lean b/Mathlib/Topology/MetricSpace/Infsep.lean index e451f9e7817b3..c47889bcd8b41 100644 --- a/Mathlib/Topology/MetricSpace/Infsep.lean +++ b/Mathlib/Topology/MetricSpace/Infsep.lean @@ -246,7 +246,7 @@ theorem einfsep_pos_of_finite [Finite s] : 0 < s.einfsep := by · rcases hs.einfsep_exists_of_finite with ⟨x, _hx, y, _hy, hxy, hxy'⟩ exact hxy'.symm ▸ edist_pos.2 hxy · rw [not_nontrivial_iff] at hs - exact hs.einfsep.symm ▸ WithTop.zero_lt_top + exact hs.einfsep.symm ▸ WithTop.top_pos theorem relatively_discrete_of_finite [Finite s] : ∃ C > 0, ∀ x ∈ s, ∀ y ∈ s, x ≠ y → C ≤ edist x y := by diff --git a/Mathlib/Topology/MetricSpace/IsometricSMul.lean b/Mathlib/Topology/MetricSpace/IsometricSMul.lean index 1d8b4a236200b..8bbc25f34f0ab 100644 --- a/Mathlib/Topology/MetricSpace/IsometricSMul.lean +++ b/Mathlib/Topology/MetricSpace/IsometricSMul.lean @@ -405,19 +405,19 @@ instance ULift.isometricSMul' : IsometricSMul M (ULift X) := @[to_additive] instance {ι} {X : ι → Type*} [Fintype ι] [∀ i, SMul M (X i)] [∀ i, PseudoEMetricSpace (X i)] [∀ i, IsometricSMul M (X i)] : IsometricSMul M (∀ i, X i) := - ⟨fun c => isometry_dcomp (fun _ => (c • ·)) fun i => isometry_smul (X i) c⟩ + ⟨fun c => .piMap (fun _ => (c • ·)) fun i => isometry_smul (X i) c⟩ @[to_additive] instance Pi.isometricSMul' {ι} {M X : ι → Type*} [Fintype ι] [∀ i, SMul (M i) (X i)] [∀ i, PseudoEMetricSpace (X i)] [∀ i, IsometricSMul (M i) (X i)] : IsometricSMul (∀ i, M i) (∀ i, X i) := - ⟨fun c => isometry_dcomp (fun i => (c i • ·)) fun _ => isometry_smul _ _⟩ + ⟨fun c => .piMap (fun i => (c i • ·)) fun _ => isometry_smul _ _⟩ @[to_additive] instance Pi.isometricSMul'' {ι} {M : ι → Type*} [Fintype ι] [∀ i, Mul (M i)] [∀ i, PseudoEMetricSpace (M i)] [∀ i, IsometricSMul (M i)ᵐᵒᵖ (M i)] : IsometricSMul (∀ i, M i)ᵐᵒᵖ (∀ i, M i) := - ⟨fun c => isometry_dcomp (fun i (x : M i) => x * c.unop i) fun _ => isometry_mul_right _⟩ + ⟨fun c => .piMap (fun i (x : M i) => x * c.unop i) fun _ => isometry_mul_right _⟩ instance Additive.isometricVAdd : IsometricVAdd (Additive M) X := ⟨fun c => isometry_smul X (toMul c)⟩ diff --git a/Mathlib/Topology/MetricSpace/Isometry.lean b/Mathlib/Topology/MetricSpace/Isometry.lean index 8b05b577ab5bf..969dd91549017 100644 --- a/Mathlib/Topology/MetricSpace/Isometry.lean +++ b/Mathlib/Topology/MetricSpace/Isometry.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.MetricSpace.Antilipschitz +import Mathlib.Data.Fintype.Lattice /-! # Isometries @@ -84,10 +85,12 @@ theorem prod_map {δ} [PseudoEMetricSpace δ] {f : α → β} {g : γ → δ} (h (hg : Isometry g) : Isometry (Prod.map f g) := fun x y => by simp only [Prod.edist_eq, Prod.map_fst, hf.edist_eq, Prod.map_snd, hg.edist_eq] -theorem _root_.isometry_dcomp {ι} [Fintype ι] {α β : ι → Type*} [∀ i, PseudoEMetricSpace (α i)] +protected theorem piMap {ι} [Fintype ι] {α β : ι → Type*} [∀ i, PseudoEMetricSpace (α i)] [∀ i, PseudoEMetricSpace (β i)] (f : ∀ i, α i → β i) (hf : ∀ i, Isometry (f i)) : - Isometry (fun g : (i : ι) → α i => fun i => f i (g i)) := fun x y => by - simp only [edist_pi_def, (hf _).edist_eq] + Isometry (Pi.map f) := fun x y => by + simp only [edist_pi_def, (hf _).edist_eq, Pi.map_apply] + +@[deprecated (since := "2024-10-06")] alias _root_.isometry_dcomp := Isometry.piMap /-- The composition of isometries is an isometry. -/ theorem comp {g : β → γ} {f : α → β} (hg : Isometry g) (hf : Isometry f) : Isometry (g ∘ f) := @@ -98,12 +101,15 @@ protected theorem uniformContinuous (hf : Isometry f) : UniformContinuous f := hf.lipschitz.uniformContinuous /-- An isometry from a metric space is a uniform inducing map -/ -protected theorem uniformInducing (hf : Isometry f) : UniformInducing f := - hf.antilipschitz.uniformInducing hf.uniformContinuous +theorem isUniformInducing (hf : Isometry f) : IsUniformInducing f := + hf.antilipschitz.isUniformInducing hf.uniformContinuous + +@[deprecated (since := "2024-10-05")] +alias uniformInducing := isUniformInducing theorem tendsto_nhds_iff {ι : Type*} {f : α → β} {g : ι → α} {a : Filter ι} {b : α} (hf : Isometry f) : Filter.Tendsto g a (𝓝 b) ↔ Filter.Tendsto (f ∘ g) a (𝓝 (f b)) := - hf.uniformInducing.inducing.tendsto_nhds_iff + hf.isUniformInducing.isInducing.tendsto_nhds_iff /-- An isometry is continuous. -/ protected theorem continuous (hf : Isometry f) : Continuous f := @@ -144,11 +150,11 @@ theorem _root_.isometry_subtype_coe {s : Set α} : Isometry ((↑) : s → α) : theorem comp_continuousOn_iff {γ} [TopologicalSpace γ] (hf : Isometry f) {g : γ → α} {s : Set γ} : ContinuousOn (f ∘ g) s ↔ ContinuousOn g s := - hf.uniformInducing.inducing.continuousOn_iff.symm + hf.isUniformInducing.isInducing.continuousOn_iff.symm theorem comp_continuous_iff {γ} [TopologicalSpace γ] (hf : Isometry f) {g : γ → α} : Continuous (f ∘ g) ↔ Continuous g := - hf.uniformInducing.inducing.continuous_iff.symm + hf.isUniformInducing.isInducing.continuous_iff.symm end PseudoEmetricIsometry @@ -168,13 +174,18 @@ lemma isUniformEmbedding (hf : Isometry f) : IsUniformEmbedding f := @[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding /-- An isometry from an emetric space is an embedding -/ -protected theorem embedding (hf : Isometry f) : Embedding f := - hf.isUniformEmbedding.embedding +theorem isEmbedding (hf : Isometry f) : IsEmbedding f := hf.isUniformEmbedding.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias embedding := isEmbedding /-- An isometry from a complete emetric space is a closed embedding -/ -theorem closedEmbedding [CompleteSpace α] [EMetricSpace γ] {f : α → γ} (hf : Isometry f) : - ClosedEmbedding f := - hf.antilipschitz.closedEmbedding hf.lipschitz.uniformContinuous +theorem isClosedEmbedding [CompleteSpace α] [EMetricSpace γ] {f : α → γ} (hf : Isometry f) : + IsClosedEmbedding f := + hf.antilipschitz.isClosedEmbedding hf.lipschitz.uniformContinuous + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding := isClosedEmbedding end EmetricIsometry @@ -238,11 +249,14 @@ alias UniformEmbedding.to_isometry := IsUniformEmbedding.to_isometry /-- An embedding from a topological space to a metric space is an isometry with respect to the induced metric space structure on the source space. -/ -theorem Embedding.to_isometry {α β} [TopologicalSpace α] [MetricSpace β] {f : α → β} - (h : Embedding f) : (letI := h.comapMetricSpace f; Isometry f) := +theorem IsEmbedding.to_isometry {α β} [TopologicalSpace α] [MetricSpace β] {f : α → β} + (h : IsEmbedding f) : (letI := h.comapMetricSpace f; Isometry f) := let _ := h.comapMetricSpace f Isometry.of_dist_eq fun _ _ => rfl +@[deprecated (since := "2024-10-26")] +alias Embedding.to_isometry := IsEmbedding.to_isometry + -- such a bijection need not exist /-- `α` and `β` are isometric if there is an isometric bijection between them. -/ -- Porting note(#5171): was @[nolint has_nonempty_instance] @@ -453,9 +467,9 @@ instance : Group (α ≃ᵢ α) where one := IsometryEquiv.refl _ mul e₁ e₂ := e₂.trans e₁ inv := IsometryEquiv.symm - mul_assoc e₁ e₂ e₃ := rfl - one_mul e := ext fun _ => rfl - mul_one e := ext fun _ => rfl + mul_assoc _ _ _ := rfl + one_mul _ := ext fun _ => rfl + mul_one _ := ext fun _ => rfl inv_mul_cancel e := ext e.symm_apply_apply @[simp] theorem coe_one : ⇑(1 : α ≃ᵢ α) = id := rfl @@ -470,11 +484,59 @@ theorem mul_apply (e₁ e₂ : α ≃ᵢ α) (x : α) : (e₁ * e₂) x = e₁ ( theorem completeSpace_iff (e : α ≃ᵢ β) : CompleteSpace α ↔ CompleteSpace β := by simp only [completeSpace_iff_isComplete_univ, ← e.range_eq_univ, ← image_univ, - isComplete_image_iff e.isometry.uniformInducing] + isComplete_image_iff e.isometry.isUniformInducing] protected theorem completeSpace [CompleteSpace β] (e : α ≃ᵢ β) : CompleteSpace α := e.completeSpace_iff.2 ‹_› +/-- The natural isometry `∀ i, Y i ≃ᵢ ∀ j, Y (e.symm j)` obtained from a bijection `ι ≃ ι'` of +fintypes. `Equiv.piCongrLeft'` as an `IsometryEquiv`.-/ +@[simps!] +def piCongrLeft' {ι' : Type*} [Fintype ι] [Fintype ι'] {Y : ι → Type*} + [∀ j, PseudoEMetricSpace (Y j)] (e : ι ≃ ι') : (∀ i, Y i) ≃ᵢ ∀ j, Y (e.symm j) where + toEquiv := Equiv.piCongrLeft' _ e + isometry_toFun x1 x2 := by + simp_rw [edist_pi_def, Finset.sup_univ_eq_iSup] + exact (Equiv.iSup_comp (g := fun b ↦ edist (x1 b) (x2 b)) e.symm) + +/-- The natural isometry `∀ i, Y (e i) ≃ᵢ ∀ j, Y j` obtained from a bijection `ι ≃ ι'` of fintypes. +`Equiv.piCongrLeft` as an `IsometryEquiv`. -/ +@[simps!] +def piCongrLeft {ι' : Type*} [Fintype ι] [Fintype ι'] {Y : ι' → Type*} + [∀ j, PseudoEMetricSpace (Y j)] (e : ι ≃ ι') : (∀ i, Y (e i)) ≃ᵢ ∀ j, Y j := + (piCongrLeft' e.symm).symm + +/-- The natural isometry `(α ⊕ β → γ) ≃ᵢ (α → γ) × (β → γ)` between the type of maps on a sum of +fintypes `α ⊕ β` and the pairs of functions on the types `α` and `β`. +`Equiv.sumArrowEquivProdArrow` as an `IsometryEquiv`.-/ +@[simps!] +def sumArrowIsometryEquivProdArrow [Fintype α] [Fintype β] : (α ⊕ β → γ) ≃ᵢ (α → γ) × (β → γ) where + toEquiv := Equiv.sumArrowEquivProdArrow _ _ _ + isometry_toFun _ _ := by simp [Prod.edist_eq, edist_pi_def, Finset.sup_univ_eq_iSup, iSup_sum] + +@[simp] +theorem sumArrowIsometryEquivProdArrow_toHomeomorph {α β : Type*} [Fintype α] [Fintype β] : + sumArrowIsometryEquivProdArrow.toHomeomorph + = Homeomorph.sumArrowHomeomorphProdArrow (ι := α) (ι' := β) (X := γ) := + rfl + +theorem _root_.Fin.edist_append_eq_max_edist (m n : ℕ) {x x2 : Fin m → α} {y y2 : Fin n → α} : + edist (Fin.append x y) (Fin.append x2 y2) = max (edist x x2) (edist y y2) := by + simp [edist_pi_def, Finset.sup_univ_eq_iSup, ← Equiv.iSup_comp (e := finSumFinEquiv), + Prod.edist_eq, iSup_sum] + +/-- The natural `IsometryEquiv` between `(Fin m → α) × (Fin n → α)` and `Fin (m + n) → α`. +`Fin.appendEquiv` as an `IsometryEquiv`.-/ +@[simps!] +def _root_.Fin.appendIsometry (m n : ℕ) : (Fin m → α) × (Fin n → α) ≃ᵢ (Fin (m + n) → α) where + toEquiv := Fin.appendEquiv _ _ + isometry_toFun _ _ := by simp_rw [Fin.appendEquiv, Fin.edist_append_eq_max_edist, Prod.edist_eq] + +@[simp] +theorem _root_.Fin.appendIsometry_toHomeomorph (m n : ℕ) : + (Fin.appendIsometry m n).toHomeomorph = Fin.appendHomeomorph (X := α) m n := + rfl + variable (ι α) /-- `Equiv.funUnique` as an `IsometryEquiv`. -/ diff --git a/Mathlib/Topology/MetricSpace/Kuratowski.lean b/Mathlib/Topology/MetricSpace/Kuratowski.lean index 8063585c24d8e..5a21609d09845 100644 --- a/Mathlib/Topology/MetricSpace/Kuratowski.lean +++ b/Mathlib/Topology/MetricSpace/Kuratowski.lean @@ -19,16 +19,16 @@ noncomputable section open Set Metric TopologicalSpace NNReal ENNReal lp Function -universe u v w +universe u -variable {α : Type u} {β : Type v} {γ : Type w} +variable {α : Type u} namespace KuratowskiEmbedding /-! ### Any separable metric space can be embedded isometrically in ℓ^∞(ℕ, ℝ) -/ -variable {f g : ℓ^∞(ℕ)} {n : ℕ} {C : ℝ} [MetricSpace α] (x : ℕ → α) (a b : α) +variable {n : ℕ} [MetricSpace α] (x : ℕ → α) (a : α) /-- A metric space can be embedded in `l^∞(ℝ)` via the distances to points in a fixed countable set, if this set is dense. This map is given in `kuratowskiEmbedding`, diff --git a/Mathlib/Topology/MetricSpace/MetricSeparated.lean b/Mathlib/Topology/MetricSpace/MetricSeparated.lean index 2529db5502ed7..520ee661e1219 100644 --- a/Mathlib/Topology/MetricSpace/MetricSeparated.lean +++ b/Mathlib/Topology/MetricSpace/MetricSeparated.lean @@ -27,7 +27,7 @@ def IsMetricSeparated {X : Type*} [EMetricSpace X] (s t : Set X) := namespace IsMetricSeparated -variable {X : Type*} [EMetricSpace X] {s t : Set X} {x y : X} +variable {X : Type*} [EMetricSpace X] {s t : Set X} @[symm] theorem symm (h : IsMetricSeparated s t) : IsMetricSeparated t s := diff --git a/Mathlib/Topology/MetricSpace/PiNat.lean b/Mathlib/Topology/MetricSpace/PiNat.lean index 8c9627c5ed747..bfd470b9972da 100644 --- a/Mathlib/Topology/MetricSpace/PiNat.lean +++ b/Mathlib/Topology/MetricSpace/PiNat.lean @@ -51,7 +51,7 @@ noncomputable section open Topology TopologicalSpace Set Metric Filter Function -attribute [local simp] pow_le_pow_iff_right one_lt_two inv_le_inv zero_le_two zero_lt_two +attribute [local simp] pow_le_pow_iff_right one_lt_two inv_le_inv₀ zero_le_two zero_lt_two variable {E : ℕ → Type*} @@ -264,7 +264,7 @@ theorem dist_triangle_nonarch (x y z : ∀ n, E n) : dist x z ≤ max (dist x y) · simp rcases eq_or_ne y z with (rfl | hyz) · simp - simp only [dist_eq_of_ne, hxz, hxy, hyz, inv_le_inv, one_div, inv_pow, zero_lt_two, Ne, + simp only [dist_eq_of_ne, hxz, hxy, hyz, inv_le_inv₀, one_div, inv_pow, zero_lt_two, Ne, not_false_iff, le_max_iff, pow_le_pow_iff_right, one_lt_two, pow_pos, min_le_iff.1 (min_firstDiff_le x y z hxz)] @@ -294,7 +294,7 @@ theorem apply_eq_of_dist_lt {x y : ∀ n, E n} {n : ℕ} (h : dist x y < (1 / 2) rcases eq_or_ne x y with (rfl | hne) · rfl have : n < firstDiff x y := by - simpa [dist_eq_of_ne hne, inv_lt_inv, pow_lt_pow_iff_right, one_lt_two] using h + simpa [dist_eq_of_ne hne, inv_lt_inv₀, pow_lt_pow_iff_right, one_lt_two] using h exact apply_eq_of_lt_firstDiff (hi.trans_lt this) /-- A function to a pseudo-metric-space is `1`-Lipschitz if and only if points in the same cylinder diff --git a/Mathlib/Topology/MetricSpace/Polish.lean b/Mathlib/Topology/MetricSpace/Polish.lean index 66175bc090fb4..d244b44980242 100644 --- a/Mathlib/Topology/MetricSpace/Polish.lean +++ b/Mathlib/Topology/MetricSpace/Polish.lean @@ -140,35 +140,38 @@ theorem exists_nat_nat_continuous_surjective (α : Type*) [TopologicalSpace α] exists_nat_nat_continuous_surjective_of_completeSpace α /-- Given a closed embedding into a Polish space, the source space is also Polish. -/ -theorem _root_.ClosedEmbedding.polishSpace [TopologicalSpace α] [TopologicalSpace β] [PolishSpace β] - {f : α → β} (hf : ClosedEmbedding f) : PolishSpace α := by +lemma _root_.IsClosedEmbedding.polishSpace [TopologicalSpace α] [TopologicalSpace β] [PolishSpace β] + {f : α → β} (hf : IsClosedEmbedding f) : PolishSpace α := by letI := upgradePolishSpace β - letI : MetricSpace α := hf.toEmbedding.comapMetricSpace f - haveI : SecondCountableTopology α := hf.toEmbedding.secondCountableTopology + letI : MetricSpace α := hf.isEmbedding.comapMetricSpace f + haveI : SecondCountableTopology α := hf.isEmbedding.secondCountableTopology have : CompleteSpace α := by - rw [completeSpace_iff_isComplete_range hf.toEmbedding.to_isometry.uniformInducing] + rw [completeSpace_iff_isComplete_range hf.isEmbedding.to_isometry.isUniformInducing] exact hf.isClosed_range.isComplete infer_instance +@[deprecated (since := "2024-10-20")] +alias _root_.ClosedEmbedding.polishSpace := _root_.IsClosedEmbedding.polishSpace + /-- Any countable discrete space is Polish. -/ instance (priority := 50) polish_of_countable [TopologicalSpace α] [h : Countable α] [DiscreteTopology α] : PolishSpace α := by obtain ⟨f, hf⟩ := h.exists_injective_nat - have : ClosedEmbedding f := by - apply closedEmbedding_of_continuous_injective_closed continuous_of_discreteTopology hf - exact fun t _ => isClosed_discrete _ + have : IsClosedEmbedding f := + .of_continuous_injective_isClosedMap continuous_of_discreteTopology hf + fun t _ ↦ isClosed_discrete _ exact this.polishSpace /-- Pulling back a Polish topology under an equiv gives again a Polish topology. -/ theorem _root_.Equiv.polishSpace_induced [t : TopologicalSpace β] [PolishSpace β] (f : α ≃ β) : @PolishSpace α (t.induced f) := letI : TopologicalSpace α := t.induced f - (f.toHomeomorphOfInducing ⟨rfl⟩).closedEmbedding.polishSpace + (f.toHomeomorphOfIsInducing ⟨rfl⟩).isClosedEmbedding.polishSpace /-- A closed subset of a Polish space is also Polish. -/ theorem _root_.IsClosed.polishSpace [TopologicalSpace α] [PolishSpace α] {s : Set α} (hs : IsClosed s) : PolishSpace s := - (IsClosed.closedEmbedding_subtype_val hs).polishSpace + hs.isClosedEmbedding_subtypeVal.polishSpace instance instPolishSpaceUniv [TopologicalSpace α] [PolishSpace α] : PolishSpace (univ : Set α) := @@ -211,8 +214,7 @@ theorem exists_polishSpace_forall_le {ι : Type*} [Countable ι] [t : Topologica .iInf ⟨none, Option.forall.2 ⟨le_rfl, hm⟩⟩ <| Option.forall.2 ⟨p, h'm⟩⟩ instance : PolishSpace ENNReal := - ClosedEmbedding.polishSpace ⟨ENNReal.orderIsoUnitIntervalBirational.toHomeomorph.embedding, - ENNReal.orderIsoUnitIntervalBirational.range_eq ▸ isClosed_univ⟩ + ENNReal.orderIsoUnitIntervalBirational.toHomeomorph.isClosedEmbedding.polishSpace end PolishSpace diff --git a/Mathlib/Topology/MetricSpace/ProperSpace/Lemmas.lean b/Mathlib/Topology/MetricSpace/ProperSpace/Lemmas.lean index d582d83e1a6e6..f75b63205c5b6 100644 --- a/Mathlib/Topology/MetricSpace/ProperSpace/Lemmas.lean +++ b/Mathlib/Topology/MetricSpace/ProperSpace/Lemmas.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.Algebra.Order.Compact +import Mathlib.Topology.Order.Compact import Mathlib.Topology.MetricSpace.ProperSpace import Mathlib.Topology.Order.IntermediateValue import Mathlib.Topology.Order.LocalExtr diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean b/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean index 346e0e97d3e23..340bdd4348398 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean @@ -18,9 +18,9 @@ Further results about pseudo-metric spaces. open Set Filter TopologicalSpace Bornology open scoped ENNReal NNReal Uniformity Topology -universe u v w +universe u v -variable {α : Type u} {β : Type v} {X ι : Type*} +variable {α : Type u} {β : Type v} {ι : Type*} variable [PseudoMetricSpace α] @@ -59,19 +59,21 @@ theorem dist_le_range_sum_of_dist_le {f : ℕ → α} (n : ℕ) {d : ℕ → ℝ namespace Metric -- instantiate pseudometric space as a topology -variable {x y z : α} {δ ε ε₁ ε₂ : ℝ} {s : Set α} -nonrec theorem uniformInducing_iff [PseudoMetricSpace β] {f : α → β} : - UniformInducing f ↔ UniformContinuous f ∧ +nonrec theorem isUniformInducing_iff [PseudoMetricSpace β] {f : α → β} : + IsUniformInducing f ↔ UniformContinuous f ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := - uniformInducing_iff'.trans <| Iff.rfl.and <| + isUniformInducing_iff'.trans <| Iff.rfl.and <| ((uniformity_basis_dist.comap _).le_basis_iff uniformity_basis_dist).trans <| by simp only [subset_def, Prod.forall, gt_iff_lt, preimage_setOf_eq, Prod.map_apply, mem_setOf] +@[deprecated (since := "2024-10-05")] +alias uniformInducing_iff := isUniformInducing_iff + nonrec theorem isUniformEmbedding_iff [PseudoMetricSpace β] {f : α → β} : IsUniformEmbedding f ↔ Function.Injective f ∧ UniformContinuous f ∧ ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := by - rw [isUniformEmbedding_iff, and_comm, uniformInducing_iff] + rw [isUniformEmbedding_iff, and_comm, isUniformInducing_iff] @[deprecated (since := "2024-10-01")] alias uniformEmbedding_iff := isUniformEmbedding_iff @@ -160,6 +162,8 @@ protected theorem cauchy_iff {f : Filter α} : Cauchy f ↔ NeBot f ∧ ∀ ε > 0, ∃ t ∈ f, ∀ x ∈ t, ∀ y ∈ t, dist x y < ε := uniformity_basis_dist.cauchy_iff +variable {s : Set α} + /-- Given a point `x` in a discrete subset `s` of a pseudometric space, there is an open ball centered at `x` and intersecting `s` only at `x`. -/ theorem exists_ball_inter_eq_singleton_of_mem_discrete [DiscreteTopology s] {x : α} (hx : x ∈ s) : @@ -201,27 +205,27 @@ theorem cauchySeq_iff_tendsto_dist_atTop_0 [Nonempty β] [SemilatticeSup β] {u end Real -namespace Metric - -variable {x y z : α} {ε ε₁ ε₂ : ℝ} {s : Set α} - -- Porting note: `TopologicalSpace.IsSeparable.separableSpace` moved to `EMetricSpace` /-- The preimage of a separable set by an inducing map is separable. -/ -protected theorem _root_.Inducing.isSeparable_preimage {f : β → α} [TopologicalSpace β] - (hf : Inducing f) {s : Set α} (hs : IsSeparable s) : IsSeparable (f ⁻¹' s) := by +protected lemma IsInducing.isSeparable_preimage {f : β → α} [TopologicalSpace β] + (hf : IsInducing f) {s : Set α} (hs : IsSeparable s) : IsSeparable (f ⁻¹' s) := by have : SeparableSpace s := hs.separableSpace have : SecondCountableTopology s := UniformSpace.secondCountable_of_separable _ - have : Inducing ((mapsTo_preimage f s).restrict _ _ _) := - (hf.comp inducing_subtype_val).codRestrict _ + have : IsInducing ((mapsTo_preimage f s).restrict _ _ _) := + (hf.comp IsInducing.subtypeVal).codRestrict _ have := this.secondCountableTopology exact .of_subtype _ -protected theorem _root_.Embedding.isSeparable_preimage {f : β → α} [TopologicalSpace β] - (hf : Embedding f) {s : Set α} (hs : IsSeparable s) : IsSeparable (f ⁻¹' s) := - hf.toInducing.isSeparable_preimage hs +@[deprecated (since := "2024-10-28")] +alias _root_.Inducing.isSeparable_preimage := IsInducing.isSeparable_preimage -end Metric +protected theorem IsEmbedding.isSeparable_preimage {f : β → α} [TopologicalSpace β] + (hf : IsEmbedding f) {s : Set α} (hs : IsSeparable s) : IsSeparable (f ⁻¹' s) := + hf.isInducing.isSeparable_preimage hs + +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.isSeparable_preimage := IsEmbedding.isSeparable_preimage /-- A compact set is separable. -/ theorem IsCompact.isSeparable {s : Set α} (hs : IsCompact s) : IsSeparable s := diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean b/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean index 3ad6637ff4565..cde9eb4f13f6b 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean @@ -23,11 +23,11 @@ variable {α β : Type*} [PseudoMetricSpace α] abbrev PseudoMetricSpace.induced {α β} (f : α → β) (m : PseudoMetricSpace β) : PseudoMetricSpace α where dist x y := dist (f x) (f y) - dist_self x := dist_self _ - dist_comm x y := dist_comm _ _ - dist_triangle x y z := dist_triangle _ _ _ + dist_self _ := dist_self _ + dist_comm _ _ := dist_comm _ _ + dist_triangle _ _ _ := dist_triangle _ _ _ edist x y := edist (f x) (f y) - edist_dist x y := edist_dist _ _ + edist_dist _ _ := edist_dist _ _ toUniformSpace := UniformSpace.comap f m.toUniformSpace uniformity_dist := (uniformity_basis_dist.comap _).eq_biInf toBornology := Bornology.induced f @@ -37,17 +37,23 @@ abbrev PseudoMetricSpace.induced {α β} (f : α → β) (m : PseudoMetricSpace /-- Pull back a pseudometric space structure by an inducing map. This is a version of `PseudoMetricSpace.induced` useful in case if the domain already has a `TopologicalSpace` structure. -/ -def Inducing.comapPseudoMetricSpace {α β} [TopologicalSpace α] [m : PseudoMetricSpace β] {f : α → β} - (hf : Inducing f) : PseudoMetricSpace α := - .replaceTopology (.induced f m) hf.induced +def IsInducing.comapPseudoMetricSpace {α β : Type*} [TopologicalSpace α] [m : PseudoMetricSpace β] + {f : α → β} (hf : IsInducing f) : PseudoMetricSpace α := + .replaceTopology (.induced f m) hf.eq_induced + +@[deprecated (since := "2024-10-28")] +alias Inducing.comapPseudoMetricSpace := IsInducing.comapPseudoMetricSpace /-- Pull back a pseudometric space structure by a uniform inducing map. This is a version of `PseudoMetricSpace.induced` useful in case if the domain already has a `UniformSpace` structure. -/ -def UniformInducing.comapPseudoMetricSpace {α β} [UniformSpace α] [m : PseudoMetricSpace β] - (f : α → β) (h : UniformInducing f) : PseudoMetricSpace α := +def IsUniformInducing.comapPseudoMetricSpace {α β} [UniformSpace α] [m : PseudoMetricSpace β] + (f : α → β) (h : IsUniformInducing f) : PseudoMetricSpace α := .replaceUniformity (.induced f m) h.comap_uniformity.symm +@[deprecated (since := "2024-10-08")] alias UniformInducing.comapPseudoMetricSpace := + IsUniformInducing.comapPseudoMetricSpace + instance Subtype.pseudoMetricSpace {p : α → Prop} : PseudoMetricSpace (Subtype p) := PseudoMetricSpace.induced Subtype.val ‹_› @@ -144,7 +150,7 @@ variable [PseudoMetricSpace β] instance Prod.pseudoMetricSpaceMax : PseudoMetricSpace (α × β) := let i := PseudoEMetricSpace.toPseudoMetricSpaceOfDist (fun x y : α × β => dist x.1 y.1 ⊔ dist x.2 y.2) - (fun x y => (max_lt (edist_lt_top _ _) (edist_lt_top _ _)).ne) fun x y => by + (fun _ _ => (max_lt (edist_lt_top _ _) (edist_lt_top _ _)).ne) fun x y => by simp only [sup_eq_max, dist_edist, ← ENNReal.toReal_max (edist_ne_top _ _) (edist_ne_top _ _), Prod.edist_eq] i.replaceBornology fun s => by diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean index 89df0d0b39ba3..19689b2f5cdf6 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean @@ -59,7 +59,7 @@ def UniformSpace.ofDist (dist : α → α → ℝ) (dist_self : ∀ x : α, dist abbrev Bornology.ofDist {α : Type*} (dist : α → α → ℝ) (dist_comm : ∀ x y, dist x y = dist y x) (dist_triangle : ∀ x y z, dist x z ≤ dist x y + dist y z) : Bornology α := Bornology.ofBounded { s : Set α | ∃ C, ∀ ⦃x⦄, x ∈ s → ∀ ⦃y⦄, y ∈ s → dist x y ≤ C } - ⟨0, fun x hx y => hx.elim⟩ (fun s ⟨c, hc⟩ t h => ⟨c, fun x hx y hy => hc (h hx) (h hy)⟩) + ⟨0, fun _ hx _ => hx.elim⟩ (fun _ ⟨c, hc⟩ _ h => ⟨c, fun _ hx _ hy => hc (h hx) (h hy)⟩) (fun s hs t ht => by rcases s.eq_empty_or_nonempty with rfl | ⟨x, hx⟩ · rwa [empty_union] @@ -401,6 +401,15 @@ theorem sphere_eq_empty_of_subsingleton [Subsingleton α] (hε : ε ≠ 0) : sph instance sphere_isEmpty_of_subsingleton [Subsingleton α] [NeZero ε] : IsEmpty (sphere x ε) := by rw [sphere_eq_empty_of_subsingleton (NeZero.ne ε)]; infer_instance +theorem closedBall_eq_singleton_of_subsingleton [Subsingleton α] (h : 0 ≤ ε) : + closedBall x ε = {x} := by + ext x' + simpa [Subsingleton.allEq x x'] + +theorem ball_eq_singleton_of_subsingleton [Subsingleton α] (h : 0 < ε) : ball x ε = {x} := by + ext x' + simpa [Subsingleton.allEq x x'] + theorem mem_closedBall_self (h : 0 ≤ ε) : x ∈ closedBall x ε := by rwa [mem_closedBall, dist_self] @@ -1013,8 +1022,8 @@ section Real instance Real.pseudoMetricSpace : PseudoMetricSpace ℝ where dist x y := |x - y| dist_self := by simp [abs_zero] - dist_comm x y := abs_sub_comm _ _ - dist_triangle x y z := abs_sub_le _ _ _ + dist_comm _ _ := abs_sub_comm _ _ + dist_triangle _ _ _ := abs_sub_le _ _ _ theorem Real.dist_eq (x y : ℝ) : dist x y = |x - y| := rfl diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean b/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean index 92a7c3925b2a1..c7b60bab973a9 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean @@ -3,6 +3,7 @@ Copyright (c) 2015, 2017 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébastien Gouëzel -/ +import Mathlib.Data.ENNReal.Lemmas import Mathlib.Topology.Bornology.Constructions import Mathlib.Topology.EMetricSpace.Pi import Mathlib.Topology.MetricSpace.Pseudo.Defs diff --git a/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean b/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean index 37a5faee8383a..b3e9cec910f90 100644 --- a/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean +++ b/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Kalle Kytölä. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ -import Mathlib.Data.ENNReal.Basic +import Mathlib.Data.ENNReal.Lemmas import Mathlib.Topology.ContinuousMap.Bounded import Mathlib.Topology.MetricSpace.Thickening @@ -86,7 +86,7 @@ theorem thickenedIndicatorAux_zero {δ : ℝ} (δ_pos : 0 < δ) (E : Set α) {x have key := tsub_le_tsub (@rfl _ (1 : ℝ≥0∞)).le (ENNReal.div_le_div x_out (@rfl _ (ENNReal.ofReal δ : ℝ≥0∞)).le) rw [ENNReal.div_self (ne_of_gt (ENNReal.ofReal_pos.mpr δ_pos)) ofReal_ne_top] at key - simpa using key + simpa [tsub_self] using key theorem thickenedIndicatorAux_mono {δ₁ δ₂ : ℝ} (hle : δ₁ ≤ δ₂) (E : Set α) : thickenedIndicatorAux δ₁ E ≤ thickenedIndicatorAux δ₂ E := @@ -128,7 +128,7 @@ theorem thickenedIndicatorAux_tendsto_indicator_closure {δseq : ℕ → ℝ} specialize δseq_lim ε ε_pos simp only [dist_zero_right, Real.norm_eq_abs, eventually_atTop] at δseq_lim rcases δseq_lim with ⟨N, hN⟩ - apply @tendsto_atTop_of_eventually_const _ _ _ _ _ _ _ N + apply tendsto_atTop_of_eventually_const (i₀ := N) intro n n_large have key : x ∉ thickening ε E := by simpa only [thickening, mem_setOf_eq, not_lt] using ε_lt.le refine le_antisymm ?_ bot_le diff --git a/Mathlib/Topology/MetricSpace/Thickening.lean b/Mathlib/Topology/MetricSpace/Thickening.lean index 99f8f79bb287c..d5414b1bc048e 100644 --- a/Mathlib/Topology/MetricSpace/Thickening.lean +++ b/Mathlib/Topology/MetricSpace/Thickening.lean @@ -34,7 +34,7 @@ open NNReal ENNReal Topology Set Filter Bornology universe u v w -variable {ι : Sort*} {α : Type u} {β : Type v} +variable {ι : Sort*} {α : Type u} namespace Metric diff --git a/Mathlib/Topology/MetricSpace/Ultra/TotallyDisconnected.lean b/Mathlib/Topology/MetricSpace/Ultra/TotallyDisconnected.lean deleted file mode 100644 index 161f861120e27..0000000000000 --- a/Mathlib/Topology/MetricSpace/Ultra/TotallyDisconnected.lean +++ /dev/null @@ -1,25 +0,0 @@ -/- -Copyright (c) 2024 Yakov Pechersky. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Yakov Pechersky, David Loeffler --/ -import Mathlib.Topology.MetricSpace.Defs -import Mathlib.Topology.MetricSpace.Ultra.Basic - -/-! -# Ultrametric spaces are totally disconnected - -In a metric space with an ultrametric, the space is totally disconnected. - -## Tags - -ultrametric, nonarchimedean, totally disconnected --/ -open Metric IsUltrametricDist - -instance {X : Type*} [MetricSpace X] [IsUltrametricDist X] : TotallyDisconnectedSpace X := by - refine (totallyDisconnectedSpace_iff X).mpr (isTotallyDisconnected_of_isClopen_set fun x y h ↦ ?_) - obtain ⟨r, hr, hr'⟩ := exists_between (dist_pos.mpr h) - refine ⟨_, IsUltrametricDist.isClopen_ball x r, ?_, ?_⟩ - · simp only [mem_ball, dist_self, hr] - · simp only [mem_ball, dist_comm, not_lt, hr'.le] diff --git a/Mathlib/Topology/MetricSpace/Ultra/TotallySeparated.lean b/Mathlib/Topology/MetricSpace/Ultra/TotallySeparated.lean new file mode 100644 index 0000000000000..09edc0330ec3e --- /dev/null +++ b/Mathlib/Topology/MetricSpace/Ultra/TotallySeparated.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2024 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yakov Pechersky, David Loeffler +-/ +import Mathlib.Topology.MetricSpace.Defs +import Mathlib.Topology.MetricSpace.Ultra.Basic + +/-! +# Ultrametric spaces are totally separated + +In a metric space with an ultrametric, the space is totally separated, hence totally disconnected. + +## Tags + +ultrametric, nonarchimedean, totally separated, totally disconnected +-/ +open Metric IsUltrametricDist + +instance {X : Type*} [MetricSpace X] [IsUltrametricDist X] : TotallySeparatedSpace X := + totallySeparatedSpace_iff_exists_isClopen.mpr fun x y h ↦ by + obtain ⟨r, hr, hr'⟩ := exists_between (dist_pos.mpr h) + refine ⟨_, IsUltrametricDist.isClopen_ball x r, ?_, ?_⟩ + · simp only [mem_ball, dist_self, hr] + · simp only [Set.mem_compl, mem_ball, dist_comm, not_lt, hr'.le] + +example {X : Type*} [MetricSpace X] [IsUltrametricDist X] : TotallyDisconnectedSpace X := + inferInstance diff --git a/Mathlib/Topology/Metrizable/Basic.lean b/Mathlib/Topology/Metrizable/Basic.lean index 80f40eafabe28..aa0533c1aae41 100644 --- a/Mathlib/Topology/Metrizable/Basic.lean +++ b/Mathlib/Topology/Metrizable/Basic.lean @@ -44,11 +44,14 @@ instance pseudoMetrizableSpace_prod [PseudoMetrizableSpace X] [PseudoMetrizableS /-- Given an inducing map of a topological space into a pseudo metrizable space, the source space is also pseudo metrizable. -/ -theorem _root_.Inducing.pseudoMetrizableSpace [PseudoMetrizableSpace Y] {f : X → Y} - (hf : Inducing f) : PseudoMetrizableSpace X := +theorem _root_.IsInducing.pseudoMetrizableSpace [PseudoMetrizableSpace Y] {f : X → Y} + (hf : IsInducing f) : PseudoMetrizableSpace X := letI : PseudoMetricSpace Y := pseudoMetrizableSpacePseudoMetric Y ⟨⟨hf.comapPseudoMetricSpace, rfl⟩⟩ +@[deprecated (since := "2024-10-28")] +alias _root_.Inducing.pseudoMetrizableSpace := _root_.IsInducing.pseudoMetrizableSpace + /-- Every pseudo-metrizable space is first countable. -/ instance (priority := 100) PseudoMetrizableSpace.firstCountableTopology [h : PseudoMetrizableSpace X] : FirstCountableTopology X := by @@ -59,7 +62,7 @@ instance (priority := 100) PseudoMetrizableSpace.firstCountableTopology instance PseudoMetrizableSpace.subtype [PseudoMetrizableSpace X] (s : Set X) : PseudoMetrizableSpace s := - inducing_subtype_val.pseudoMetrizableSpace + IsInducing.subtypeVal.pseudoMetrizableSpace instance pseudoMetrizableSpace_pi [∀ i, PseudoMetrizableSpace (π i)] : PseudoMetrizableSpace (∀ i, π i) := by @@ -98,13 +101,16 @@ instance metrizableSpace_prod [MetrizableSpace X] [MetrizableSpace Y] : Metrizab /-- Given an embedding of a topological space into a metrizable space, the source space is also metrizable. -/ -theorem _root_.Embedding.metrizableSpace [MetrizableSpace Y] {f : X → Y} (hf : Embedding f) : - MetrizableSpace X := +theorem _root_.IsEmbedding.metrizableSpace [MetrizableSpace Y] {f : X → Y} + (hf : IsEmbedding f) : MetrizableSpace X := letI : MetricSpace Y := metrizableSpaceMetric Y ⟨⟨hf.comapMetricSpace f, rfl⟩⟩ +@[deprecated (since := "2024-10-26")] +alias _root_.Embedding.metrizableSpace := IsEmbedding.metrizableSpace + instance MetrizableSpace.subtype [MetrizableSpace X] (s : Set X) : MetrizableSpace s := - embedding_subtype_val.metrizableSpace + IsEmbedding.subtypeVal.metrizableSpace instance metrizableSpace_pi [∀ i, MetrizableSpace (π i)] : MetrizableSpace (∀ i, π i) := by cases nonempty_fintype ι diff --git a/Mathlib/Topology/Metrizable/Uniformity.lean b/Mathlib/Topology/Metrizable/Uniformity.lean index 3dc4176d75c21..c4bd746dd6f0d 100644 --- a/Mathlib/Topology/Metrizable/Uniformity.lean +++ b/Mathlib/Topology/Metrizable/Uniformity.lean @@ -79,7 +79,7 @@ noncomputable def ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x, d x append_assoc, append_assoc] rw [length_cons, length_append, length_singleton] -- Porting note: `edist_dist` is no longer inferred - edist_dist x y := rfl + edist_dist _ _ := rfl theorem dist_ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x, d x x = 0) (dist_comm : ∀ x y, d x y = d y x) (x y : X) : @@ -173,7 +173,6 @@ theorem le_two_mul_dist_ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x end PseudoMetricSpace --- Porting note (#11083): this is slower than in Lean3 for some reason... /-- If `X` is a uniform space with countably generated uniformity filter, there exists a `PseudoMetricSpace` structure compatible with the `UniformSpace` structure. Use `UniformSpace.pseudoMetricSpace` or `UniformSpace.metricSpace` instead. -/ diff --git a/Mathlib/Topology/Metrizable/Urysohn.lean b/Mathlib/Topology/Metrizable/Urysohn.lean index bddb6a6ead668..ce5e3289dd04e 100644 --- a/Mathlib/Topology/Metrizable/Urysohn.lean +++ b/Mathlib/Topology/Metrizable/Urysohn.lean @@ -32,7 +32,7 @@ variable (X : Type*) [TopologicalSpace X] [RegularSpace X] [SecondCountableTopol /-- For a regular topological space with second countable topology, there exists an inducing map to `l^∞ = ℕ →ᵇ ℝ`. -/ -theorem exists_inducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Inducing f := by +theorem exists_isInducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, IsInducing f := by -- Choose a countable basis, and consider the set `s` of pairs of set `(U, V)` such that `U ∈ B`, -- `V ∈ B`, and `closure U ⊆ V`. rcases exists_countable_basis X with ⟨B, hBc, -, hB⟩ @@ -43,10 +43,10 @@ theorem exists_inducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Inducing f := by -- with the discrete topology and deal with `s →ᵇ ℝ` instead. letI : TopologicalSpace s := ⊥ haveI : DiscreteTopology s := ⟨rfl⟩ - rsuffices ⟨f, hf⟩ : ∃ f : X → s →ᵇ ℝ, Inducing f + rsuffices ⟨f, hf⟩ : ∃ f : X → s →ᵇ ℝ, IsInducing f · exact ⟨fun x => (f x).extend (Encodable.encode' s) 0, (BoundedContinuousFunction.isometry_extend (Encodable.encode' s) - (0 : ℕ →ᵇ ℝ)).embedding.toInducing.comp hf⟩ + (0 : ℕ →ᵇ ℝ)).isEmbedding.isInducing.comp hf⟩ have hd : ∀ UV : s, Disjoint (closure UV.1.1) UV.1.2ᶜ := fun UV => disjoint_compl_right.mono_right (compl_subset_compl.2 UV.2.2) -- Choose a sequence of `εₙ > 0`, `n : s`, that is bounded above by `1` and tends to zero @@ -73,7 +73,7 @@ theorem exists_inducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Inducing f := by ⟨⟨fun UV => f UV x, continuous_of_discreteTopology⟩, 1, fun UV₁ UV₂ => Real.dist_le_of_mem_Icc_01 (hf01 _ _) (hf01 _ _)⟩ have hF : ∀ x UV, F x UV = f UV x := fun _ _ => rfl - refine ⟨F, inducing_iff_nhds.2 fun x => le_antisymm ?_ ?_⟩ + refine ⟨F, isInducing_iff_nhds.2 fun x => le_antisymm ?_ ?_⟩ · /- First we prove that `F` is continuous. Given `δ > 0`, consider the set `T` of `(U, V) ∈ s` such that `ε (U, V) ≥ δ`. Since `ε` tends to zero, `T` is finite. Since each `f` is continuous, we can choose a neighborhood such that `dist (F y (U, V)) (F x (U, V)) ≤ δ` for any @@ -103,12 +103,14 @@ theorem exists_inducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Inducing f := by rw [hF, hF, hfε UV hy, hf0 UV hxU, Pi.zero_apply, dist_zero_right] exact le_abs_self _ +@[deprecated (since := "2024-10-28")] alias exists_inducing_l_infty := exists_isInducing_l_infty + /-- *Urysohn's metrization theorem* (Tychonoff's version): a regular topological space with second countable topology `X` is metrizable, i.e., there exists a pseudometric space structure that generates the same topology. -/ instance (priority := 90) PseudoMetrizableSpace.of_regularSpace_secondCountableTopology : PseudoMetrizableSpace X := - let ⟨_, hf⟩ := exists_inducing_l_infty X + let ⟨_, hf⟩ := exists_isInducing_l_infty X hf.pseudoMetrizableSpace end RegularSpace @@ -116,8 +118,8 @@ end RegularSpace variable (X : Type*) [TopologicalSpace X] [T3Space X] [SecondCountableTopology X] /-- A T₃ topological space with second countable topology can be embedded into `l^∞ = ℕ →ᵇ ℝ`. -/ -theorem exists_embedding_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Embedding f := - let ⟨f, hf⟩ := exists_inducing_l_infty X; ⟨f, hf.embedding⟩ +theorem exists_embedding_l_infty : ∃ f : X → ℕ →ᵇ ℝ, IsEmbedding f := + let ⟨f, hf⟩ := exists_isInducing_l_infty X; ⟨f, hf.isEmbedding⟩ /-- *Urysohn's metrization theorem* (Tychonoff's version): a T₃ topological space with second countable topology `X` is metrizable, i.e., there exists a metric space structure that generates the diff --git a/Mathlib/Topology/NhdsSet.lean b/Mathlib/Topology/NhdsSet.lean index 3a3f45b2eeff7..9b361653607e1 100644 --- a/Mathlib/Topology/NhdsSet.lean +++ b/Mathlib/Topology/NhdsSet.lean @@ -162,6 +162,12 @@ if `X` has two elements and the coarse topology and `s` and `t` are distinct sin theorem nhdsSet_inter_le (s t : Set X) : 𝓝ˢ (s ∩ t) ≤ 𝓝ˢ s ⊓ 𝓝ˢ t := (monotone_nhdsSet (X := X)).map_inf_le s t +theorem nhdsSet_iInter_le {ι : Sort*} (s : ι → Set X) : 𝓝ˢ (⋂ i, s i) ≤ ⨅ i, 𝓝ˢ (s i) := + (monotone_nhdsSet (X := X)).map_iInf_le + +theorem nhdsSet_sInter_le (s : Set (Set X)) : 𝓝ˢ (⋂₀ s) ≤ ⨅ x ∈ s, 𝓝ˢ x := + (monotone_nhdsSet (X := X)).map_sInf_le + variable (s) in theorem IsClosed.nhdsSet_le_sup (h : IsClosed t) : 𝓝ˢ s ≤ 𝓝ˢ (s ∩ t) ⊔ 𝓟 (tᶜ) := calc diff --git a/Mathlib/Topology/NoetherianSpace.lean b/Mathlib/Topology/NoetherianSpace.lean index 88d07a7493deb..a6cc5bec77c31 100644 --- a/Mathlib/Topology/NoetherianSpace.lean +++ b/Mathlib/Topology/NoetherianSpace.lean @@ -43,12 +43,10 @@ variable (α β : Type*) [TopologicalSpace α] [TopologicalSpace β] namespace TopologicalSpace /-- Type class for noetherian spaces. It is defined to be spaces whose open sets satisfies ACC. -/ -@[mk_iff] -class NoetherianSpace : Prop where - wellFounded_opens : WellFounded ((· > ·) : Opens α → Opens α → Prop) +abbrev NoetherianSpace : Prop := WellFoundedGT (Opens α) theorem noetherianSpace_iff_opens : NoetherianSpace α ↔ ∀ s : Opens α, IsCompact (s : Set α) := by - rw [noetherianSpace_iff, CompleteLattice.wellFounded_iff_isSupFiniteCompact, + rw [NoetherianSpace, CompleteLattice.wellFoundedGT_iff_isSupFiniteCompact, CompleteLattice.isSupFiniteCompact_iff_all_elements_compact] exact forall_congr' Opens.isCompactElement_iff @@ -64,26 +62,28 @@ protected theorem NoetherianSpace.isCompact [NoetherianSpace α] (s : Set α) : hUo Set.Subset.rfl with ⟨t, ht⟩ exact ⟨t, hs.trans ht⟩ --- Porting note: fixed NS -protected theorem _root_.Inducing.noetherianSpace [NoetherianSpace α] {i : β → α} - (hi : Inducing i) : NoetherianSpace β := +protected theorem _root_.IsInducing.noetherianSpace [NoetherianSpace α] {i : β → α} + (hi : IsInducing i) : NoetherianSpace β := (noetherianSpace_iff_opens _).2 fun _ => hi.isCompact_iff.2 (NoetherianSpace.isCompact _) +@[deprecated (since := "2024-10-28")] +alias _root_.Inducing.noetherianSpace := _root_.IsInducing.noetherianSpace + /-- [Stacks: Lemma 0052 (1)](https://stacks.math.columbia.edu/tag/0052)-/ instance NoetherianSpace.set [NoetherianSpace α] (s : Set α) : NoetherianSpace s := - inducing_subtype_val.noetherianSpace + IsInducing.subtypeVal.noetherianSpace variable (α) open List in theorem noetherianSpace_TFAE : TFAE [NoetherianSpace α, - WellFounded fun s t : Closeds α => s < t, + WellFoundedLT (Closeds α), ∀ s : Set α, IsCompact s, ∀ s : Opens α, IsCompact (s : Set α)] := by tfae_have 1 ↔ 2 := by - refine (noetherianSpace_iff α).trans (Opens.compl_bijective.2.wellFounded_iff ?_) - exact (@OrderIso.compl (Set α)).lt_iff_lt.symm + simp_rw [isWellFounded_iff] + exact Opens.compl_bijective.2.wellFounded_iff (@OrderIso.compl (Set α)).lt_iff_lt.symm tfae_have 1 ↔ 4 := noetherianSpace_iff_opens α tfae_have 1 → 3 := @NoetherianSpace.isCompact α _ tfae_have 3 → 4 := fun h s => h s @@ -94,9 +94,13 @@ variable {α} theorem noetherianSpace_iff_isCompact : NoetherianSpace α ↔ ∀ s : Set α, IsCompact s := (noetherianSpace_TFAE α).out 0 2 +instance [NoetherianSpace α] : WellFoundedLT (Closeds α) := + Iff.mp ((noetherianSpace_TFAE α).out 0 1) ‹_› + +@[deprecated (since := "2024-10-07")] theorem NoetherianSpace.wellFounded_closeds [NoetherianSpace α] : WellFounded fun s t : Closeds α => s < t := - Iff.mp ((noetherianSpace_TFAE α).out 0 1) ‹_› + wellFounded_lt instance {α} : NoetherianSpace (CofiniteTopology α) := by simp only [noetherianSpace_iff_isCompact, isCompact_iff_ultrafilter_le_nhds, @@ -123,7 +127,7 @@ theorem NoetherianSpace.range [NoetherianSpace α] (f : α → β) (hf : Continu theorem noetherianSpace_set_iff (s : Set α) : NoetherianSpace s ↔ ∀ t, t ⊆ s → IsCompact t := by - simp only [noetherianSpace_iff_isCompact, embedding_subtype_val.isCompact_iff, + simp only [noetherianSpace_iff_isCompact, IsEmbedding.subtypeVal.isCompact_iff, Subtype.forall_set_subtype] @[simp] @@ -153,7 +157,7 @@ instance (priority := 100) Finite.to_noetherianSpace [Finite α] : NoetherianSpa /-- In a Noetherian space, every closed set is a finite union of irreducible closed sets. -/ theorem NoetherianSpace.exists_finite_set_closeds_irreducible [NoetherianSpace α] (s : Closeds α) : ∃ S : Set (Closeds α), S.Finite ∧ (∀ t ∈ S, IsIrreducible (t : Set α)) ∧ s = sSup S := by - apply wellFounded_closeds.induction s; clear s + apply wellFounded_lt.induction s; clear s intro s H rcases eq_or_ne s ⊥ with rfl | h₀ · use ∅; simp diff --git a/Mathlib/Topology/OmegaCompletePartialOrder.lean b/Mathlib/Topology/OmegaCompletePartialOrder.lean index 89f1e3ee2fa58..c7890d3939837 100644 --- a/Mathlib/Topology/OmegaCompletePartialOrder.lean +++ b/Mathlib/Topology/OmegaCompletePartialOrder.lean @@ -6,6 +6,7 @@ Authors: Simon Hudon import Mathlib.Topology.Basic import Mathlib.Order.UpperLower.Basic import Mathlib.Order.OmegaCompletePartialOrder +import Mathlib.Topology.Order.ScottTopology /-! # Scott Topological Spaces @@ -23,6 +24,14 @@ open Set OmegaCompletePartialOrder universe u +open Topology.IsScott in +@[simp] lemma Topology.IsScott.ωscottContinuous_iff_continuous {α : Type*} + [OmegaCompletePartialOrder α] [TopologicalSpace α] + [Topology.IsScott α (Set.range fun c : Chain α => Set.range c)] {f : α → Prop} : + ωScottContinuous f ↔ Continuous f := by + rw [ωScottContinuous, scottContinuous_iff_continuous (fun a b hab => by + use Chain.pair a b hab; exact OmegaCompletePartialOrder.Chain.range_pair a b hab)] + -- "Scott", "ωSup" namespace Scott @@ -67,6 +76,17 @@ instance Scott.topologicalSpace (α : Type u) [OmegaCompletePartialOrder α] : isOpen_inter := Scott.IsOpen.inter α isOpen_sUnion := Scott.isOpen_sUnion α +lemma isOpen_iff_ωScottContinuous_mem {α} [OmegaCompletePartialOrder α] {s : Set (Scott α)} : + IsOpen s ↔ ωScottContinuous fun x ↦ x ∈ s := by rfl + +lemma scott_eq_Scott {α} [OmegaCompletePartialOrder α] : + Topology.scott α (Set.range fun c : Chain α => Set.range c) = Scott.topologicalSpace α := by + ext U + letI := Topology.scott α (Set.range fun c : Chain α => Set.range c) + rw [isOpen_iff_ωScottContinuous_mem, @isOpen_iff_continuous_mem, + @Topology.IsScott.ωscottContinuous_iff_continuous _ _ + (Topology.scott α (Set.range fun c : Chain α => Set.range c)) ({ topology_eq_scott := rfl })] + section notBelow variable {α : Type*} [OmegaCompletePartialOrder α] (y : Scott α) diff --git a/Mathlib/Topology/Order.lean b/Mathlib/Topology/Order.lean index c1c9b629e8592..173ade1245b1d 100644 --- a/Mathlib/Topology/Order.lean +++ b/Mathlib/Topology/Order.lean @@ -269,7 +269,7 @@ theorem continuous_of_discreteTopology [TopologicalSpace β] {f : α → β} : C singleton is open. -/ theorem continuous_discrete_rng {α} [TopologicalSpace α] [TopologicalSpace β] [DiscreteTopology β] {f : α → β} : Continuous f ↔ ∀ b : β, IsOpen (f ⁻¹' {b}) := - ⟨fun h b => (isOpen_discrete _).preimage h, fun h => ⟨fun s _ => by + ⟨fun h _ => (isOpen_discrete _).preimage h, fun h => ⟨fun s _ => by rw [← biUnion_of_singleton s, preimage_iUnion₂] exact isOpen_biUnion fun _ _ => h _⟩⟩ @@ -393,6 +393,11 @@ theorem induced_iInf {ι : Sort w} {t : ι → TopologicalSpace α} : (⨅ i, t i).induced g = ⨅ i, (t i).induced g := (gc_coinduced_induced g).u_iInf +@[simp] +theorem induced_sInf {s : Set (TopologicalSpace α)} : + TopologicalSpace.induced g (sInf s) = sInf (TopologicalSpace.induced g '' s) := by + rw [sInf_eq_iInf', sInf_image', induced_iInf] + @[simp] theorem coinduced_bot : (⊥ : TopologicalSpace α).coinduced f = ⊥ := (gc_coinduced_induced f).l_bot @@ -406,6 +411,11 @@ theorem coinduced_iSup {ι : Sort w} {t : ι → TopologicalSpace α} : (⨆ i, t i).coinduced f = ⨆ i, (t i).coinduced f := (gc_coinduced_induced f).l_iSup +@[simp] +theorem coinduced_sSup {s : Set (TopologicalSpace α)} : + TopologicalSpace.coinduced f (sSup s) = sSup ((TopologicalSpace.coinduced f) '' s) := by + rw [sSup_eq_iSup', sSup_image', coinduced_iSup] + theorem induced_id [t : TopologicalSpace α] : t.induced id = t := TopologicalSpace.ext <| funext fun s => propext <| ⟨fun ⟨_, hs, h⟩ => h ▸ hs, fun hs => ⟨s, hs, rfl⟩⟩ diff --git a/Mathlib/Topology/Order/Basic.lean b/Mathlib/Topology/Order/Basic.lean index 3e2cc3f13ebe9..ca052f92ae658 100644 --- a/Mathlib/Topology/Order/Basic.lean +++ b/Mathlib/Topology/Order/Basic.lean @@ -232,11 +232,14 @@ nonrec theorem StrictMono.induced_topology_eq_preorder {α β : Type*} [LinearOr /-- A strictly monotone function between linear orders with order topology is a topological embedding provided that the range of `f` is order-connected. -/ -theorem StrictMono.embedding_of_ordConnected {α β : Type*} [LinearOrder α] [LinearOrder β] +theorem StrictMono.isEmbedding_of_ordConnected {α β : Type*} [LinearOrder α] [LinearOrder β] [TopologicalSpace α] [h : OrderTopology α] [TopologicalSpace β] [OrderTopology β] {f : α → β} - (hf : StrictMono f) (hc : OrdConnected (range f)) : Embedding f := + (hf : StrictMono f) (hc : OrdConnected (range f)) : IsEmbedding f := ⟨⟨h.1.trans <| Eq.symm <| hf.induced_topology_eq_preorder hc⟩, hf.injective⟩ +@[deprecated (since := "2024-10-26")] +alias StrictMono.embedding_of_ordConnected := StrictMono.isEmbedding_of_ordConnected + /-- On a `Set.OrdConnected` subset of a linear order, the order topology for the restriction of the order is the same as the restriction to the subset of the order topology. -/ instance orderTopology_of_ordConnected {α : Type u} [TopologicalSpace α] [LinearOrder α] @@ -284,10 +287,10 @@ theorem nhdsWithin_Iic_basis [TopologicalSpace α] [LinearOrder α] [OrderTopolo nhdsWithin_Iic_basis' (exists_lt a) theorem nhds_top_order [TopologicalSpace α] [Preorder α] [OrderTop α] [OrderTopology α] : - 𝓝 (⊤ : α) = ⨅ (l) (h₂ : l < ⊤), 𝓟 (Ioi l) := by simp [nhds_eq_order (⊤ : α)] + 𝓝 (⊤ : α) = ⨅ (l) (_ : l < ⊤), 𝓟 (Ioi l) := by simp [nhds_eq_order (⊤ : α)] theorem nhds_bot_order [TopologicalSpace α] [Preorder α] [OrderBot α] [OrderTopology α] : - 𝓝 (⊥ : α) = ⨅ (l) (h₂ : ⊥ < l), 𝓟 (Iio l) := by simp [nhds_eq_order (⊥ : α)] + 𝓝 (⊥ : α) = ⨅ (l) (_ : ⊥ < l), 𝓟 (Iio l) := by simp [nhds_eq_order (⊥ : α)] theorem nhds_top_basis [TopologicalSpace α] [LinearOrder α] [OrderTop α] [OrderTopology α] [Nontrivial α] : (𝓝 ⊤).HasBasis (fun a : α => a < ⊤) fun a : α => Ioi a := by diff --git a/Mathlib/Topology/Order/Bornology.lean b/Mathlib/Topology/Order/Bornology.lean index e2307a276340e..93afbf73aa4ae 100644 --- a/Mathlib/Topology/Order/Bornology.lean +++ b/Mathlib/Topology/Order/Bornology.lean @@ -29,8 +29,8 @@ and below. -/ def orderBornology : Bornology α := .ofBounded {s | BddBelow s ∧ BddAbove s} (by simp) - (fun s hs t hst ↦ ⟨hs.1.mono hst, hs.2.mono hst⟩) - (fun s hs t ht ↦ ⟨hs.1.union ht.1, hs.2.union ht.2⟩) + (fun _ hs _ hst ↦ ⟨hs.1.mono hst, hs.2.mono hst⟩) + (fun _ hs _ ht ↦ ⟨hs.1.union ht.1, hs.2.union ht.2⟩) (by simp) @[simp] lemma orderBornology_isBounded : orderBornology.IsBounded s ↔ BddBelow s ∧ BddAbove s := by diff --git a/Mathlib/Topology/Order/Bounded.lean b/Mathlib/Topology/Order/Bounded.lean index 9d7a19e970c6f..39c572fe4f2d0 100644 --- a/Mathlib/Topology/Order/Bounded.lean +++ b/Mathlib/Topology/Order/Bounded.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ import Mathlib.Topology.Bornology.Basic -import Mathlib.Topology.Instances.Real import Mathlib.Order.LiminfLimsup +import Mathlib.Topology.Instances.Real /-! # Relating order and metric boundedness diff --git a/Mathlib/Topology/Order/Category/FrameAdjunction.lean b/Mathlib/Topology/Order/Category/FrameAdjunction.lean index e44b0f9de9062..9f2055bd85c47 100644 --- a/Mathlib/Topology/Order/Category/FrameAdjunction.lean +++ b/Mathlib/Topology/Order/Category/FrameAdjunction.lean @@ -97,7 +97,7 @@ a point `x` of the space `X` a point of the locale of opens of `X`. -/ @[simps] def localePointOfSpacePoint (x : X) : PT (Opens X) where toFun := (x ∈ ·) - map_inf' a b := rfl + map_inf' _ _ := rfl map_top' := rfl map_sSup' S := by simp [Prop.exists_iff] diff --git a/Mathlib/Topology/Algebra/Order/Compact.lean b/Mathlib/Topology/Order/Compact.lean similarity index 100% rename from Mathlib/Topology/Algebra/Order/Compact.lean rename to Mathlib/Topology/Order/Compact.lean diff --git a/Mathlib/Topology/Order/DenselyOrdered.lean b/Mathlib/Topology/Order/DenselyOrdered.lean index 80ad140e2daf8..e427346122b7a 100644 --- a/Mathlib/Topology/Order/DenselyOrdered.lean +++ b/Mathlib/Topology/Order/DenselyOrdered.lean @@ -13,7 +13,7 @@ open Set Filter TopologicalSpace Topology Function open OrderDual (toDual ofDual) -variable {α β γ : Type*} +variable {α β : Type*} section DenselyOrdered diff --git a/Mathlib/Topology/Order/Hom/Basic.lean b/Mathlib/Topology/Order/Hom/Basic.lean index 94dd1b5acb371..b0e27200893c5 100644 --- a/Mathlib/Topology/Order/Hom/Basic.lean +++ b/Mathlib/Topology/Order/Hom/Basic.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Order.Hom.Basic -import Mathlib.Topology.ContinuousMap.Basic +import Mathlib.Topology.Basic +import Mathlib.Topology.ContinuousMap.Defs /-! # Continuous order homomorphisms diff --git a/Mathlib/Topology/Order/IntermediateValue.lean b/Mathlib/Topology/Order/IntermediateValue.lean index 9b86197c50a9e..12e59d849ba91 100644 --- a/Mathlib/Topology/Order/IntermediateValue.lean +++ b/Mathlib/Topology/Order/IntermediateValue.lean @@ -45,7 +45,7 @@ intermediate value theorem, connected space, connected set open Filter OrderDual TopologicalSpace Function Set open scoped Topology Filter Interval -universe u v w +universe u v /-! ### Intermediate value theorem on a (pre)connected space @@ -216,9 +216,7 @@ theorem IsPreconnected.eq_univ_of_unbounded {s : Set α} (hs : IsPreconnected s) end -variable {α : Type u} {β : Type v} {γ : Type w} [ConditionallyCompleteLinearOrder α] - [TopologicalSpace α] [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] - [OrderTopology β] [Nonempty γ] +variable {α : Type u} [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [OrderTopology α] /-- A bounded connected subset of a conditionally complete linear order includes the open interval `(Inf s, Sup s)`. -/ diff --git a/Mathlib/Topology/Order/IsLUB.lean b/Mathlib/Topology/Order/IsLUB.lean index 2d6f0f82dc720..39f599a2851f8 100644 --- a/Mathlib/Topology/Order/IsLUB.lean +++ b/Mathlib/Topology/Order/IsLUB.lean @@ -14,12 +14,11 @@ open Set Filter TopologicalSpace Topology Function open OrderDual (toDual ofDual) -variable {α β γ : Type*} +variable {α γ : Type*} section OrderTopology -variable [TopologicalSpace α] [TopologicalSpace β] [LinearOrder α] [LinearOrder β] [OrderTopology α] - [OrderTopology β] +variable [TopologicalSpace α] [LinearOrder α] [OrderTopology α] theorem IsLUB.frequently_mem {a : α} {s : Set α} (ha : IsLUB s a) (hs : s.Nonempty) : ∃ᶠ x in 𝓝[≤] a, x ∈ s := by diff --git a/Mathlib/Topology/Order/LawsonTopology.lean b/Mathlib/Topology/Order/LawsonTopology.lean index 61c08e2a6fe21..21658cac3dd92 100644 --- a/Mathlib/Topology/Order/LawsonTopology.lean +++ b/Mathlib/Topology/Order/LawsonTopology.lean @@ -49,7 +49,7 @@ Lawson topology, preorder open Set TopologicalSpace -variable {α β : Type*} +variable {α : Type*} namespace Topology @@ -61,7 +61,7 @@ section Preorder /-- The Lawson topology is defined as the meet of `Topology.lower` and the `Topology.scott`. -/ -def lawson (α : Type*) [Preorder α] : TopologicalSpace α := lower α ⊓ scott α +def lawson (α : Type*) [Preorder α] : TopologicalSpace α := lower α ⊓ scott α univ variable (α) [Preorder α] [TopologicalSpace α] @@ -80,13 +80,13 @@ variable (α) [Preorder α] [TopologicalSpace α] [IsLawson α] /-- The complements of the upper closures of finite sets intersected with Scott open sets form a basis for the lawson topology. -/ -def lawsonBasis := { s : Set α | ∃ t : Set α, t.Finite ∧ ∃ u : Set α, IsOpen[scott α] u ∧ +def lawsonBasis := { s : Set α | ∃ t : Set α, t.Finite ∧ ∃ u : Set α, IsOpen[scott α univ] u ∧ u \ upperClosure t = s } protected theorem isTopologicalBasis : TopologicalSpace.IsTopologicalBasis (lawsonBasis α) := by have lawsonBasis_image2 : lawsonBasis α = (image2 (fun x x_1 ↦ ⇑WithLower.toLower ⁻¹' x ∩ ⇑WithScott.toScott ⁻¹' x_1) - (IsLower.lowerBasis (WithLower α)) {U | IsOpen[scott α] U}) := by + (IsLower.lowerBasis (WithLower α)) {U | IsOpen[scott α univ] U}) := by rw [lawsonBasis, image2, IsLower.lowerBasis] simp_rw [diff_eq_compl_inter] aesop @@ -94,11 +94,12 @@ protected theorem isTopologicalBasis : TopologicalSpace.IsTopologicalBasis (laws convert IsTopologicalBasis.inf_induced IsLower.isTopologicalBasis (isTopologicalBasis_opens (α := WithScott α)) WithLower.toLower WithScott.toScott - erw [@topology_eq_lawson α _ _ _] - rw [lawson] + rw [@topology_eq_lawson α _ _ _, lawson] apply (congrArg₂ Inf.inf _) _ - · letI _ := lower α; exact @IsLower.withLowerHomeomorph α ‹_› (lower α) ⟨rfl⟩ |>.inducing.induced - letI _ := scott α; exact @IsScott.withScottHomeomorph α _ (scott α) ⟨rfl⟩ |>.inducing.induced + · letI _ := lower α + exact (@IsLower.withLowerHomeomorph α ‹_› (lower α) ⟨rfl⟩).isInducing.eq_induced + · letI _ := scott α univ + exact (@IsScott.withScottHomeomorph α _ (scott α univ) ⟨rfl⟩).isInducing.eq_induced end Preorder end IsLawson @@ -144,7 +145,7 @@ instance instIsLawson : IsLawson (WithLawson α) := ⟨rfl⟩ /-- If `α` is equipped with the Lawson topology, then it is homeomorphic to `WithLawson α`. -/ def homeomorph [TopologicalSpace α] [IsLawson α] : WithLawson α ≃ₜ α := - ofLawson.toHomeomorphOfInducing ⟨by erw [IsLawson.topology_eq_lawson (α := α), induced_id]; rfl⟩ + ofLawson.toHomeomorphOfIsInducing ⟨by erw [IsLawson.topology_eq_lawson (α := α), induced_id]; rfl⟩ theorem isOpen_preimage_ofLawson {S : Set α} : IsOpen (ofLawson ⁻¹' S) ↔ (lawson α).IsOpen S := Iff.rfl @@ -162,11 +163,11 @@ section Preorder variable [Preorder α] -lemma lawson_le_scott : lawson α ≤ scott α := inf_le_right +lemma lawson_le_scott : lawson α ≤ scott α univ := inf_le_right lemma lawson_le_lower : lawson α ≤ lower α := inf_le_left -lemma scottHausdorff_le_lawson : scottHausdorff α ≤ lawson α := +lemma scottHausdorff_le_lawson : scottHausdorff α univ ≤ lawson α := le_inf scottHausdorff_le_lower scottHausdorff_le_scott lemma lawsonClosed_of_scottClosed (s : Set α) (h : IsClosed (WithScott.ofScott ⁻¹' s)) : @@ -178,24 +179,24 @@ lemma lawsonClosed_of_lowerClosed (s : Set α) (h : IsClosed (WithLower.ofLower /-- An upper set is Lawson open if and only if it is Scott open -/ lemma lawsonOpen_iff_scottOpen_of_isUpperSet {s : Set α} (h : IsUpperSet s) : IsOpen (WithLawson.ofLawson ⁻¹' s) ↔ IsOpen (WithScott.ofScott ⁻¹' s) := - ⟨fun hs => IsScott.isOpen_iff_isUpperSet_and_scottHausdorff_open.mpr + ⟨fun hs => IsScott.isOpen_iff_isUpperSet_and_scottHausdorff_open (D := univ).mpr ⟨h, (scottHausdorff_le_lawson s) hs⟩, lawson_le_scott _⟩ variable (L : TopologicalSpace α) (S : TopologicalSpace α) -variable [@IsLawson α _ L] [@IsScott α _ S] +variable [@IsLawson α _ L] [@IsScott α univ _ S] lemma isLawson_le_isScott : L ≤ S := by - rw [@IsScott.topology_eq α _ S _, @IsLawson.topology_eq_lawson α _ L _] + rw [@IsScott.topology_eq α univ _ S _, @IsLawson.topology_eq_lawson α _ L _] exact inf_le_right -lemma scottHausdorff_le_isLawson : scottHausdorff α ≤ L := by +lemma scottHausdorff_le_isLawson : scottHausdorff α univ ≤ L := by rw [@IsLawson.topology_eq_lawson α _ L _] exact scottHausdorff_le_lawson /-- An upper set is Lawson open if and only if it is Scott open -/ lemma lawsonOpen_iff_scottOpen_of_isUpperSet' (s : Set α) (h : IsUpperSet s) : IsOpen[L] s ↔ IsOpen[S] s := by - rw [@IsLawson.topology_eq_lawson α _ L _, @IsScott.topology_eq α _ S _] + rw [@IsLawson.topology_eq_lawson α _ L _, @IsScott.topology_eq α univ _ S _] exact lawsonOpen_iff_scottOpen_of_isUpperSet h lemma lawsonClosed_iff_scottClosed_of_isLowerSet (s : Set α) (h : IsLowerSet s) : diff --git a/Mathlib/Topology/Order/LocalExtr.lean b/Mathlib/Topology/Order/LocalExtr.lean index 8253ac222956f..6e58a0c6754b9 100644 --- a/Mathlib/Topology/Order/LocalExtr.lean +++ b/Mathlib/Topology/Order/LocalExtr.lean @@ -520,3 +520,21 @@ theorem Filter.EventuallyEq.isLocalExtr_iff {f g : α → β} {a : α} (heq : f heq.isExtrFilter_iff heq.eq_of_nhds end Eventually + +/-- If `f` is monotone to the left and antitone to the right, then it has a local maximum. -/ +lemma isLocalMax_of_mono_anti' {α : Type*} [TopologicalSpace α] [LinearOrder α] + {β : Type*} [Preorder β] {b : α} {f : α → β} + {a : Set α} (ha : a ∈ 𝓝[≤] b) {c : Set α} (hc : c ∈ 𝓝[≥] b) + (h₀ : MonotoneOn f a) (h₁ : AntitoneOn f c) : IsLocalMax f b := + have : b ∈ a := mem_of_mem_nhdsWithin (by simp) ha + have : b ∈ c := mem_of_mem_nhdsWithin (by simp) hc + mem_of_superset (nhds_of_Ici_Iic ha hc) (fun x _ => by rcases le_total x b <;> aesop) + +/-- If `f` is antitone to the left and monotone to the right, then it has a local minimum. -/ +lemma isLocalMin_of_anti_mono' {α : Type*} [TopologicalSpace α] [LinearOrder α] + {β : Type*} [Preorder β] {b : α} {f : α → β} + {a : Set α} (ha : a ∈ 𝓝[≤] b) {c : Set α} (hc : c ∈ 𝓝[≥] b) + (h₀ : AntitoneOn f a) (h₁ : MonotoneOn f c) : IsLocalMin f b := + have : b ∈ a := mem_of_mem_nhdsWithin (by simp) ha + have : b ∈ c := mem_of_mem_nhdsWithin (by simp) hc + mem_of_superset (nhds_of_Ici_Iic ha hc) (fun x _ => by rcases le_total x b <;> aesop) diff --git a/Mathlib/Topology/Order/LowerUpperTopology.lean b/Mathlib/Topology/Order/LowerUpperTopology.lean index 95dc12c92c61f..6a77b7876bb67 100644 --- a/Mathlib/Topology/Order/LowerUpperTopology.lean +++ b/Mathlib/Topology/Order/LowerUpperTopology.lean @@ -198,7 +198,7 @@ variable {α} /-- If `α` is equipped with the lower topology, then it is homeomorphic to `WithLower α`. -/ def withLowerHomeomorph : WithLower α ≃ₜ α := - WithLower.ofLower.toHomeomorphOfInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ + WithLower.ofLower.toHomeomorphOfIsInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ theorem isOpen_iff_generate_Ici_compl : IsOpen s ↔ GenerateOpen { t | ∃ a, (Ici a)ᶜ = t } s := by rw [topology_eq α]; rfl @@ -354,7 +354,7 @@ variable {α} /-- If `α` is equipped with the upper topology, then it is homeomorphic to `WithUpper α`. -/ def withUpperHomeomorph : WithUpper α ≃ₜ α := - WithUpper.ofUpper.toHomeomorphOfInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ + WithUpper.ofUpper.toHomeomorphOfIsInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ theorem isOpen_iff_generate_Iic_compl : IsOpen s ↔ GenerateOpen { t | ∃ a, (Iic a)ᶜ = t } s := by rw [topology_eq α]; rfl diff --git a/Mathlib/Topology/Order/Monotone.lean b/Mathlib/Topology/Order/Monotone.lean index c807d80f962d5..c6aefd9a4b657 100644 --- a/Mathlib/Topology/Order/Monotone.lean +++ b/Mathlib/Topology/Order/Monotone.lean @@ -19,12 +19,12 @@ open Set Filter TopologicalSpace Topology Function open OrderDual (toDual ofDual) -variable {α β γ : Type*} +variable {α β : Type*} section ConditionallyCompleteLinearOrder variable [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [OrderTopology α] - [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderClosedTopology β] [Nonempty γ] + [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderClosedTopology β] /-- A monotone function continuous at the supremum of a nonempty set sends this supremum to the supremum of the image of this set. -/ @@ -150,7 +150,7 @@ end ConditionallyCompleteLinearOrder section CompleteLinearOrder variable [CompleteLinearOrder α] [TopologicalSpace α] [OrderTopology α] [CompleteLinearOrder β] - [TopologicalSpace β] [OrderClosedTopology β] [Nonempty γ] + [TopologicalSpace β] [OrderClosedTopology β] theorem sSup_mem_closure {s : Set α} (hs : s.Nonempty) : sSup s ∈ closure s := (isLUB_sSup s).mem_closure hs @@ -255,7 +255,6 @@ end CompleteLinearOrder section ConditionallyCompleteLinearOrder variable [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [OrderTopology α] - [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderClosedTopology β] [Nonempty γ] theorem csSup_mem_closure {s : Set α} (hs : s.Nonempty) (B : BddAbove s) : sSup s ∈ closure s := (isLUB_csSup hs B).mem_closure hs diff --git a/Mathlib/Topology/Order/MonotoneContinuity.lean b/Mathlib/Topology/Order/MonotoneContinuity.lean index 9c1a04ed46bec..ac6195f5ca345 100644 --- a/Mathlib/Topology/Order/MonotoneContinuity.lean +++ b/Mathlib/Topology/Order/MonotoneContinuity.lean @@ -253,7 +253,7 @@ theorem continuousAt_of_monotoneOn_of_image_mem_nhds [DenselyOrdered β] {f : α theorem Monotone.continuous_of_denseRange [DenselyOrdered β] {f : α → β} (h_mono : Monotone f) (h_dense : DenseRange f) : Continuous f := continuous_iff_continuousAt.mpr fun a => - continuousAt_of_monotoneOn_of_closure_image_mem_nhds (fun x _ y _ hxy => h_mono hxy) + continuousAt_of_monotoneOn_of_closure_image_mem_nhds (fun _ _ _ _ hxy => h_mono hxy) univ_mem <| by simp only [image_univ, h_dense.closure_eq, univ_mem] diff --git a/Mathlib/Topology/Order/OrderClosed.lean b/Mathlib/Topology/Order/OrderClosed.lean index e2763d592bc24..9cdc99b9b7005 100644 --- a/Mathlib/Topology/Order/OrderClosed.lean +++ b/Mathlib/Topology/Order/OrderClosed.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov -/ -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Order-closed topologies diff --git a/Mathlib/Topology/Order/OrderClosedExtr.lean b/Mathlib/Topology/Order/OrderClosedExtr.lean new file mode 100644 index 0000000000000..0e6754114a397 --- /dev/null +++ b/Mathlib/Topology/Order/OrderClosedExtr.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2024 Bjørn Kjos-Hanssen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bjørn Kjos-Hanssen, Patrick Massot +-/ + +import Mathlib.Topology.Order.OrderClosed +import Mathlib.Topology.Order.LocalExtr + +/-! +# Local maxima from monotonicity and antitonicity + +In this file we prove a lemma that is useful for the First Derivative Test in calculus, +and its dual. + +## Main statements + +* `isLocalMax_of_mono_anti` : if a function `f` is monotone to the left of `x` + and antitone to the right of `x` then `f` has a local maximum at `x`. + +* `isLocalMin_of_anti_mono` : the dual statement for minima. + +* `isLocalMax_of_mono_anti'` : a version of `isLocalMax_of_mono_anti` for filters. + +* `isLocalMin_of_anti_mono'` : a version of `isLocalMax_of_mono_anti'` for minima. + +-/ + +open Set Topology Filter + +/-- If `f` is monotone on `(a,b]` and antitone on `[b,c)` then `f` has +a local maximum at `b`. -/ +lemma isLocalMax_of_mono_anti + {α : Type*} [TopologicalSpace α] [LinearOrder α] [OrderClosedTopology α] + {β : Type*} [Preorder β] + {a b c : α} (g₀ : a < b) (g₁ : b < c) {f : α → β} + (h₀ : MonotoneOn f (Ioc a b)) + (h₁ : AntitoneOn f (Ico b c)) : IsLocalMax f b := + isLocalMax_of_mono_anti' (Ioc_mem_nhdsWithin_Iic' g₀) (Ico_mem_nhdsWithin_Ici' g₁) h₀ h₁ + + + +/-- If `f` is antitone on `(a,b]` and monotone on `[b,c)` then `f` has +a local minimum at `b`. -/ +lemma isLocalMin_of_anti_mono + {α : Type*} [TopologicalSpace α] [LinearOrder α] [OrderClosedTopology α] + {β : Type*} [Preorder β] {a b c : α} (g₀ : a < b) (g₁ : b < c) {f : α → β} + (h₀ : AntitoneOn f (Ioc a b)) (h₁ : MonotoneOn f (Ico b c)) : IsLocalMin f b := + mem_of_superset (Ioo_mem_nhds g₀ g₁) (fun x hx => by rcases le_total x b <;> aesop) diff --git a/Mathlib/Topology/Order/Priestley.lean b/Mathlib/Topology/Order/Priestley.lean index ca780c30f0cc8..bdad508392e4a 100644 --- a/Mathlib/Topology/Order/Priestley.lean +++ b/Mathlib/Topology/Order/Priestley.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Order.UpperLower.Basic -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Priestley spaces diff --git a/Mathlib/Topology/Order/ProjIcc.lean b/Mathlib/Topology/Order/ProjIcc.lean index 993c017bb989f..7c90ab75b6439 100644 --- a/Mathlib/Topology/Order/ProjIcc.lean +++ b/Mathlib/Topology/Order/ProjIcc.lean @@ -29,13 +29,16 @@ variable [TopologicalSpace α] [OrderTopology α] [TopologicalSpace β] [Topolog theorem continuous_projIcc : Continuous (projIcc a b h) := (continuous_const.max <| continuous_const.min continuous_id).subtype_mk _ -theorem quotientMap_projIcc : QuotientMap (projIcc a b h) := - quotientMap_iff.2 ⟨projIcc_surjective h, fun s => +theorem isQuotientMap_projIcc : IsQuotientMap (projIcc a b h) := + isQuotientMap_iff.2 ⟨projIcc_surjective h, fun s => ⟨fun hs => hs.preimage continuous_projIcc, fun hs => ⟨_, hs, by ext; simp⟩⟩⟩ +@[deprecated (since := "2024-10-22")] +alias quotientMap_projIcc := isQuotientMap_projIcc + @[simp] theorem continuous_IccExtend_iff {f : Icc a b → β} : Continuous (IccExtend h f) ↔ Continuous f := - quotientMap_projIcc.continuous_iff.symm + isQuotientMap_projIcc.continuous_iff.symm /-- See Note [continuity lemma statement]. -/ protected theorem Continuous.IccExtend {f : γ → Icc a b → β} {g : γ → α} (hf : Continuous ↿f) diff --git a/Mathlib/Topology/Algebra/Order/Rolle.lean b/Mathlib/Topology/Order/Rolle.lean similarity index 98% rename from Mathlib/Topology/Algebra/Order/Rolle.lean rename to Mathlib/Topology/Order/Rolle.lean index 57a3118c4e740..31fa140f80c8a 100644 --- a/Mathlib/Topology/Algebra/Order/Rolle.lean +++ b/Mathlib/Topology/Order/Rolle.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Topology.Order.ExtendFrom -import Mathlib.Topology.Algebra.Order.Compact +import Mathlib.Topology.Order.Compact import Mathlib.Topology.Order.LocalExtr import Mathlib.Topology.Order.T5 diff --git a/Mathlib/Topology/Order/ScottTopology.lean b/Mathlib/Topology/Order/ScottTopology.lean index 6f26fd5939149..aa61fdf937da2 100644 --- a/Mathlib/Topology/Order/ScottTopology.lean +++ b/Mathlib/Topology/Order/ScottTopology.lean @@ -68,11 +68,25 @@ variable {α β : Type*} section Preorder variable [Preorder α] {s t : Set α} +/-- A set `s` is said to be inaccessible by directed joins on `D` if, when the least upper bound of +a directed set `d` in `D` lies in `s` then `d` has non-empty intersection with `s`. -/ +def DirSupInaccOn (D : Set (Set α)) (s : Set α) : Prop := + ∀ ⦃d⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a⦄, IsLUB d a → a ∈ s → (d ∩ s).Nonempty + /-- A set `s` is said to be inaccessible by directed joins if, when the least upper bound of a directed set `d` lies in `s` then `d` has non-empty intersection with `s`. -/ def DirSupInacc (s : Set α) : Prop := ∀ ⦃d⦄, d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a⦄, IsLUB d a → a ∈ s → (d ∩ s).Nonempty +@[simp] lemma dirSupInaccOn_univ : DirSupInaccOn univ s ↔ DirSupInacc s := by + simp [DirSupInaccOn, DirSupInacc] + +@[simp] lemma DirSupInacc.dirSupInaccOn {D : Set (Set α)} : + DirSupInacc s → DirSupInaccOn D s := fun h _ _ d₂ d₃ _ hda => h d₂ d₃ hda + +lemma DirSupInaccOn.mono {D₁ D₂ : Set (Set α)} (hD : D₁ ⊆ D₂) (hf : DirSupInaccOn D₂ s) : + DirSupInaccOn D₁ s := fun ⦃_⦄ a ↦ hf (hD a) + /-- A set `s` is said to be closed under directed joins if, whenever a directed set `d` has a least upper bound `a` and is a subset of `s` then `a` also lies in `s`. @@ -107,7 +121,7 @@ lemma dirSupClosed_Iic (a : α) : DirSupClosed (Iic a) := fun _d _ _ _a ha ↦ ( end Preorder section CompleteLattice -variable [CompleteLattice α] {s t : Set α} +variable [CompleteLattice α] {s : Set α} lemma dirSupInacc_iff_forall_sSup : DirSupInacc s ↔ ∀ ⦃d⦄, d.Nonempty → DirectedOn (· ≤ ·) d → sSup d ∈ s → (d ∩ s).Nonempty := by @@ -124,54 +138,55 @@ namespace Topology /-! ### Scott-Hausdorff topology -/ section ScottHausdorff -variable [Preorder α] {s : Set α} /-- The Scott-Hausdorff topology. A set `u` is open in the Scott-Hausdorff topology iff when the least upper bound of a directed set `d` lies in `u` then there is a tail of `d` which is a subset of `u`. -/ -def scottHausdorff (α : Type*) [Preorder α] : TopologicalSpace α where - IsOpen u := ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a : α⦄, IsLUB d a → +def scottHausdorff (α : Type*) (D : Set (Set α)) [Preorder α] : TopologicalSpace α where + IsOpen u := ∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a : α⦄, IsLUB d a → a ∈ u → ∃ b ∈ d, Ici b ∩ d ⊆ u - isOpen_univ := fun d ⟨b, hb⟩ _ _ _ _ ↦ ⟨b, hb, (Ici b ∩ d).subset_univ⟩ - isOpen_inter s t hs ht d hd₁ hd₂ a hd₃ ha := by - obtain ⟨b₁, hb₁d, hb₁ds⟩ := hs hd₁ hd₂ hd₃ ha.1 - obtain ⟨b₂, hb₂d, hb₂dt⟩ := ht hd₁ hd₂ hd₃ ha.2 + isOpen_univ := fun d _ ⟨b, hb⟩ _ _ _ _ ↦ ⟨b, hb, (Ici b ∩ d).subset_univ⟩ + isOpen_inter s t hs ht d hd₀ hd₁ hd₂ a hd₃ ha := by + obtain ⟨b₁, hb₁d, hb₁ds⟩ := hs hd₀ hd₁ hd₂ hd₃ ha.1 + obtain ⟨b₂, hb₂d, hb₂dt⟩ := ht hd₀ hd₁ hd₂ hd₃ ha.2 obtain ⟨c, hcd, hc⟩ := hd₂ b₁ hb₁d b₂ hb₂d exact ⟨c, hcd, fun e ⟨hce, hed⟩ ↦ ⟨hb₁ds ⟨hc.1.trans hce, hed⟩, hb₂dt ⟨hc.2.trans hce, hed⟩⟩⟩ - isOpen_sUnion := fun s h d hd₁ hd₂ a hd₃ ⟨s₀, hs₀s, has₀⟩ ↦ by - obtain ⟨b, hbd, hbds₀⟩ := h s₀ hs₀s hd₁ hd₂ hd₃ has₀ + isOpen_sUnion := fun s h d hd₀ hd₁ hd₂ a hd₃ ⟨s₀, hs₀s, has₀⟩ ↦ by + obtain ⟨b, hbd, hbds₀⟩ := h s₀ hs₀s hd₀ hd₁ hd₂ hd₃ has₀ exact ⟨b, hbd, Set.subset_sUnion_of_subset s s₀ hbds₀ hs₀s⟩ -variable (α) [TopologicalSpace α] +variable (α) (D : Set (Set α)) [Preorder α] [TopologicalSpace α] /-- Predicate for an ordered topological space to be equipped with its Scott-Hausdorff topology. A set `u` is open in the Scott-Hausdorff topology iff when the least upper bound of a directed set `d` lies in `u` then there is a tail of `d` which is a subset of `u`. -/ class IsScottHausdorff : Prop where - topology_eq_scottHausdorff : ‹TopologicalSpace α› = scottHausdorff α + topology_eq_scottHausdorff : ‹TopologicalSpace α› = scottHausdorff α D -instance : @IsScottHausdorff α _ (scottHausdorff α) := - @IsScottHausdorff.mk _ _ (scottHausdorff α) rfl +instance : @IsScottHausdorff α D _ (scottHausdorff α D) := + @IsScottHausdorff.mk _ _ _ (scottHausdorff α D) rfl namespace IsScottHausdorff -variable [IsScottHausdorff α] {s : Set α} +variable {s : Set α} -lemma topology_eq : ‹_› = scottHausdorff α := topology_eq_scottHausdorff +lemma topology_eq [IsScottHausdorff α D] : ‹_› = scottHausdorff α D := topology_eq_scottHausdorff -variable {α} +variable {α D} -lemma isOpen_iff : - IsOpen s ↔ ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a : α⦄, IsLUB d a → - a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s := by erw [topology_eq_scottHausdorff (α := α)]; rfl +lemma isOpen_iff [IsScottHausdorff α D] : + IsOpen s ↔ ∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a : α⦄, IsLUB d a → + a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s := by rw [topology_eq_scottHausdorff (α := α) (D := D)]; rfl -lemma dirSupInacc_of_isOpen (h : IsOpen s) : DirSupInacc s := - fun d hd₁ hd₂ a hda hd₃ ↦ by - obtain ⟨b, hbd, hb⟩ := isOpen_iff.1 h hd₁ hd₂ hda hd₃; exact ⟨b, hbd, hb ⟨le_rfl, hbd⟩⟩ +lemma dirSupInaccOn_of_isOpen [IsScottHausdorff α D] (h : IsOpen s) : DirSupInaccOn D s := + fun d hd₀ hd₁ hd₂ a hda hd₃ ↦ by + obtain ⟨b, hbd, hb⟩ := isOpen_iff.mp h hd₀ hd₁ hd₂ hda hd₃; exact ⟨b, hbd, hb ⟨le_rfl, hbd⟩⟩ -lemma dirSupClosed_of_isClosed (h : IsClosed s) : DirSupClosed s := - (dirSupInacc_of_isOpen h.isOpen_compl).of_compl +lemma dirSupClosed_of_isClosed [IsScottHausdorff α univ] (h : IsClosed s) : DirSupClosed s := by + apply DirSupInacc.of_compl + rw [← dirSupInaccOn_univ] + exact (dirSupInaccOn_of_isOpen h.isOpen_compl) end IsScottHausdorff end ScottHausdorff @@ -179,10 +194,11 @@ end ScottHausdorff section ScottHausdorff namespace IsScottHausdorff -variable {s : Set α} [Preorder α] {t : TopologicalSpace α} [IsScottHausdorff α] +variable {s : Set α} [Preorder α] {t : TopologicalSpace α} [IsScottHausdorff α univ] lemma isOpen_of_isLowerSet (h : IsLowerSet s) : IsOpen s := - isOpen_iff.2 fun _d ⟨b, hb⟩ _ _ hda ha ↦ ⟨b, hb, fun _ hc ↦ h (mem_upperBounds.1 hda.1 _ hc.2) ha⟩ + (isOpen_iff (D := univ)).2 fun _d _ ⟨b, hb⟩ _ _ hda ha ↦ + ⟨b, hb, fun _ hc ↦ h (mem_upperBounds.1 hda.1 _ hc.2) ha⟩ lemma isClosed_of_isUpperSet (h : IsUpperSet s) : IsClosed s := isOpen_compl_iff.1 <| isOpen_of_isLowerSet h.compl @@ -194,105 +210,110 @@ end ScottHausdorff section Scott section Preorder -variable [Preorder α] /-- The Scott topology. It is defined as the join of the topology of upper sets and the Scott-Hausdorff topology. -/ -def scott (α : Type*) [Preorder α] : TopologicalSpace α := upperSet α ⊔ scottHausdorff α +def scott (α : Type*) (D : Set (Set α)) [Preorder α] : TopologicalSpace α := + upperSet α ⊔ scottHausdorff α D -lemma upperSet_le_scott : upperSet α ≤ scott α := le_sup_left +lemma upperSet_le_scott [Preorder α] : upperSet α ≤ scott α univ := le_sup_left -lemma scottHausdorff_le_scott : scottHausdorff α ≤ scott α := le_sup_right +lemma scottHausdorff_le_scott [Preorder α] : scottHausdorff α univ ≤ scott α univ:= le_sup_right -variable (α) [TopologicalSpace α] +variable (α) (D) [Preorder α] [TopologicalSpace α] /-- Predicate for an ordered topological space to be equipped with its Scott topology. The Scott topology is defined as the join of the topology of upper sets and the Scott Hausdorff topology. -/ class IsScott : Prop where - topology_eq_scott : ‹TopologicalSpace α› = scott α + topology_eq_scott : ‹TopologicalSpace α› = scott α D end Preorder namespace IsScott section Preorder -variable (α) [Preorder α] [TopologicalSpace α] [IsScott α] +variable (α) (D) [Preorder α] [TopologicalSpace α] -lemma topology_eq : ‹_› = scott α := topology_eq_scott +lemma topology_eq [IsScott α D] : ‹_› = scott α D := topology_eq_scott -variable {α} {s : Set α} {a : α} +variable {α} {D} {s : Set α} {a : α} -lemma isOpen_iff_isUpperSet_and_scottHausdorff_open : - IsOpen s ↔ IsUpperSet s ∧ IsOpen[scottHausdorff α] s := by erw [topology_eq α]; rfl +lemma isOpen_iff_isUpperSet_and_scottHausdorff_open [IsScott α D] : + IsOpen s ↔ IsUpperSet s ∧ IsOpen[scottHausdorff α D] s := by rw [topology_eq α D]; rfl -lemma isOpen_iff_isUpperSet_and_dirSupInacc : IsOpen s ↔ IsUpperSet s ∧ DirSupInacc s := by - rw [isOpen_iff_isUpperSet_and_scottHausdorff_open] +lemma isOpen_iff_isUpperSet_and_dirSupInaccOn [IsScott α D] : + IsOpen s ↔ IsUpperSet s ∧ DirSupInaccOn D s := by + rw [isOpen_iff_isUpperSet_and_scottHausdorff_open (D := D)] refine and_congr_right fun h ↦ - ⟨@IsScottHausdorff.dirSupInacc_of_isOpen _ _ (scottHausdorff α) _ _, - fun h' d d₁ d₂ _ d₃ ha ↦ ?_⟩ - obtain ⟨b, hbd, hbu⟩ := h' d₁ d₂ d₃ ha + ⟨@IsScottHausdorff.dirSupInaccOn_of_isOpen _ _ _ (scottHausdorff α D) _ _, + fun h' d d₀ d₁ d₂ _ d₃ ha ↦ ?_⟩ + obtain ⟨b, hbd, hbu⟩ := h' d₀ d₁ d₂ d₃ ha exact ⟨b, hbd, Subset.trans inter_subset_left (h.Ici_subset hbu)⟩ -lemma isClosed_iff_isLowerSet_and_dirSupClosed : IsClosed s ↔ IsLowerSet s ∧ DirSupClosed s := by - rw [← isOpen_compl_iff, isOpen_iff_isUpperSet_and_dirSupInacc, isUpperSet_compl, - dirSupInacc_compl] +lemma isClosed_iff_isLowerSet_and_dirSupClosed [IsScott α univ] : + IsClosed s ↔ IsLowerSet s ∧ DirSupClosed s := by + rw [← isOpen_compl_iff, isOpen_iff_isUpperSet_and_dirSupInaccOn (D := univ), isUpperSet_compl, + dirSupInaccOn_univ, dirSupInacc_compl] -lemma isUpperSet_of_isOpen : IsOpen s → IsUpperSet s := fun h ↦ - (isOpen_iff_isUpperSet_and_scottHausdorff_open.mp h).left +lemma isUpperSet_of_isOpen [IsScott α D] : IsOpen s → IsUpperSet s := fun h ↦ + (isOpen_iff_isUpperSet_and_scottHausdorff_open (D := D).mp h).left -lemma isLowerSet_of_isClosed : IsClosed s → IsLowerSet s := fun h ↦ +lemma isLowerSet_of_isClosed [IsScott α univ] : IsClosed s → IsLowerSet s := fun h ↦ (isClosed_iff_isLowerSet_and_dirSupClosed.mp h).left -lemma dirSupClosed_of_isClosed : IsClosed s → DirSupClosed s := fun h ↦ +lemma dirSupClosed_of_isClosed [IsScott α univ] : IsClosed s → DirSupClosed s := fun h ↦ (isClosed_iff_isLowerSet_and_dirSupClosed.mp h).right -lemma lowerClosure_subset_closure : ↑(lowerClosure s) ⊆ closure s := by +lemma lowerClosure_subset_closure [IsScott α univ] : ↑(lowerClosure s) ⊆ closure s := by convert closure.mono (@upperSet_le_scott α _) · rw [@IsUpperSet.closure_eq_lowerClosure α _ (upperSet α) ?_ s] infer_instance - · exact topology_eq α + · exact topology_eq α univ -lemma isClosed_Iic : IsClosed (Iic a) := +lemma isClosed_Iic [IsScott α univ] : IsClosed (Iic a) := isClosed_iff_isLowerSet_and_dirSupClosed.2 ⟨isLowerSet_Iic _, dirSupClosed_Iic _⟩ /-- The closure of a singleton `{a}` in the Scott topology is the right-closed left-infinite interval `(-∞,a]`. -/ -@[simp] lemma closure_singleton : closure {a} = Iic a := le_antisymm +@[simp] lemma closure_singleton [IsScott α univ] : closure {a} = Iic a := le_antisymm (closure_minimal (by rw [singleton_subset_iff, mem_Iic]) isClosed_Iic) <| by rw [← LowerSet.coe_Iic, ← lowerClosure_singleton] apply lowerClosure_subset_closure -variable [Preorder β] [TopologicalSpace β] [IsScott β] {f : α → β} +variable [Preorder β] [TopologicalSpace β] [IsScott β univ] {f : α → β} -lemma monotone_of_continuous (hf : Continuous f) : Monotone f := fun _ b hab ↦ by +lemma monotone_of_continuous [IsScott α D] (hf : Continuous f) : Monotone f := fun _ b hab ↦ by by_contra h simpa only [mem_compl_iff, mem_preimage, mem_Iic, le_refl, not_true] - using isUpperSet_of_isOpen ((isOpen_compl_iff.2 isClosed_Iic).preimage hf) hab h + using isUpperSet_of_isOpen (D := D) ((isOpen_compl_iff.2 isClosed_Iic).preimage hf) hab h -@[simp] lemma scottContinuous_iff_continuous : ScottContinuous f ↔ Continuous f := by +@[simp] lemma scottContinuous_iff_continuous {D : Set (Set α)} [Topology.IsScott α D] + (hD : ∀ a b : α, a ≤ b → {a, b} ∈ D) : ScottContinuousOn D f ↔ Continuous f := by refine ⟨fun h ↦ continuous_def.2 fun u hu ↦ ?_, ?_⟩ - · rw [isOpen_iff_isUpperSet_and_dirSupInacc] - exact ⟨(isUpperSet_of_isOpen hu).preimage h.monotone, fun _ hd₁ hd₂ _ hd₃ ha ↦ - image_inter_nonempty_iff.mp <| (isOpen_iff_isUpperSet_and_dirSupInacc.mp hu).2 (hd₁.image f) - (directedOn_image.mpr (hd₂.mono @(h.monotone))) (h hd₁ hd₂ hd₃) ha⟩ - · refine fun hf _ d₁ d₂ _ d₃ ↦ ⟨(monotone_of_continuous hf).mem_upperBounds_image d₃.1, + · rw [isOpen_iff_isUpperSet_and_dirSupInaccOn (D := D)] + exact ⟨(isUpperSet_of_isOpen (D := univ) hu).preimage (h.monotone D hD), + fun t h₀ hd₁ hd₂ a hd₃ ha ↦ image_inter_nonempty_iff.mp <| + (isOpen_iff_isUpperSet_and_dirSupInaccOn (D := univ).mp hu).2 trivial (Nonempty.image f hd₁) + (directedOn_image.mpr (hd₂.mono @(h.monotone D hD))) (h h₀ hd₁ hd₂ hd₃) ha⟩ + · refine fun hf t h₀ d₁ d₂ a d₃ ↦ + ⟨(monotone_of_continuous (D := D) hf).mem_upperBounds_image d₃.1, fun b hb ↦ ?_⟩ by_contra h let u := (Iic b)ᶜ - have hu : IsOpen (f ⁻¹' u) := (isOpen_compl_iff.2 isClosed_Iic).preimage hf - rw [isOpen_iff_isUpperSet_and_dirSupInacc] at hu - obtain ⟨c, hcd, hfcb⟩ := hu.2 d₁ d₂ d₃ h + have hu : IsOpen (f ⁻¹' u) := (isOpen_compl_iff.2 Topology.IsScott.isClosed_Iic).preimage hf + rw [isOpen_iff_isUpperSet_and_dirSupInaccOn (D := D)] at hu + obtain ⟨c, hcd, hfcb⟩ := hu.2 h₀ d₁ d₂ d₃ h simp [upperBounds] at hb exact hfcb <| hb _ hcd end Preorder section PartialOrder -variable [PartialOrder α] [TopologicalSpace α] [IsScott α] +variable [PartialOrder α] [TopologicalSpace α] [IsScott α univ] /-- The Scott topology on a partial order is T₀. @@ -308,7 +329,7 @@ section CompleteLinearOrder variable [CompleteLinearOrder α] -lemma isOpen_iff_Iic_compl_or_univ [TopologicalSpace α] [Topology.IsScott α] (U : Set α) : +lemma isOpen_iff_Iic_compl_or_univ [TopologicalSpace α] [Topology.IsScott α univ] (U : Set α) : IsOpen U ↔ U = univ ∨ ∃ a, (Iic a)ᶜ = U := by constructor · intro hU @@ -326,25 +347,25 @@ lemma isOpen_iff_Iic_compl_or_univ [TopologicalSpace α] [Topology.IsScott α] ( -- N.B. A number of conditions equivalent to `scott α = upper α` are given in Gierz _et al_, -- Chapter III, Exercise 3.23. -lemma scott_eq_upper_of_completeLinearOrder : scott α = upper α := by +lemma scott_eq_upper_of_completeLinearOrder : scott α univ = upper α := by letI := upper α ext U rw [@Topology.IsUpper.isTopologicalSpace_basis _ _ (upper α) ({ topology_eq_upperTopology := rfl }) U] - letI := scott α - rw [@isOpen_iff_Iic_compl_or_univ _ _ (scott α) ({ topology_eq_scott := rfl }) U] + letI := scott α univ + rw [@isOpen_iff_Iic_compl_or_univ _ _ (scott α univ) ({ topology_eq_scott := rfl }) U] /- The upper topology on a complete linear order is the Scott topology -/ -instance [TopologicalSpace α] [IsUpper α] : IsScott α where +instance [TopologicalSpace α] [IsUpper α] : IsScott α univ where topology_eq_scott := by rw [scott_eq_upper_of_completeLinearOrder] exact IsUpper.topology_eq α end CompleteLinearOrder -lemma isOpen_iff_scottContinuous_mem [Preorder α] {s : Set α} [TopologicalSpace α] [IsScott α] : - IsOpen s ↔ ScottContinuous fun x ↦ x ∈ s := by - rw [scottContinuous_iff_continuous] +lemma isOpen_iff_scottContinuous_mem [Preorder α] {s : Set α} [TopologicalSpace α] + [IsScott α univ] : IsOpen s ↔ ScottContinuous fun x ↦ x ∈ s := by + rw [← scottContinuousOn_univ, scottContinuous_iff_continuous (fun _ _ _ ↦ by trivial)] exact isOpen_iff_continuous_mem end IsScott @@ -384,34 +405,35 @@ instance [Inhabited α] : Inhabited (WithScott α) := ‹Inhabited α› variable [Preorder α] instance : Preorder (WithScott α) := ‹Preorder α› -instance : TopologicalSpace (WithScott α) := scott α -instance : IsScott (WithScott α) := ⟨rfl⟩ +instance : TopologicalSpace (WithScott α) := scott α univ +instance : IsScott (WithScott α) univ := ⟨rfl⟩ lemma isOpen_iff_isUpperSet_and_scottHausdorff_open' {u : Set α} : - IsOpen (WithScott.ofScott ⁻¹' u) ↔ IsUpperSet u ∧ (scottHausdorff α).IsOpen u := Iff.rfl + IsOpen (WithScott.ofScott ⁻¹' u) ↔ IsUpperSet u ∧ (scottHausdorff α univ).IsOpen u := Iff.rfl end WithScott end Scott variable [Preorder α] -lemma scottHausdorff_le_lower : scottHausdorff α ≤ lower α := - fun s h => IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α) +lemma scottHausdorff_le_lower : scottHausdorff α univ ≤ lower α := + fun s h => IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α univ) <| (@IsLower.isLowerSet_of_isOpen (Topology.WithLower α) _ _ _ s h) variable [TopologicalSpace α] /-- If `α` is equipped with the Scott topology, then it is homeomorphic to `WithScott α`. -/ -def IsScott.withScottHomeomorph [IsScott α] : WithScott α ≃ₜ α := - WithScott.ofScott.toHomeomorphOfInducing ⟨by erw [IsScott.topology_eq α, induced_id]; rfl⟩ +def IsScott.withScottHomeomorph [IsScott α univ] : WithScott α ≃ₜ α := + WithScott.ofScott.toHomeomorphOfIsInducing ⟨by erw [IsScott.topology_eq α univ, induced_id]; rfl⟩ -lemma IsScott.scottHausdorff_le [IsScott α] : scottHausdorff α ≤ ‹TopologicalSpace α› := by - rw [IsScott.topology_eq α, scott]; exact le_sup_right +lemma IsScott.scottHausdorff_le [IsScott α univ] : + scottHausdorff α univ ≤ ‹TopologicalSpace α› := by + rw [IsScott.topology_eq α univ, scott]; exact le_sup_right -lemma IsLower.scottHausdorff_le [IsLower α] : scottHausdorff α ≤ ‹TopologicalSpace α› := +lemma IsLower.scottHausdorff_le [IsLower α] : scottHausdorff α univ ≤ ‹TopologicalSpace α› := fun _ h ↦ - IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α) + IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α univ) <| IsLower.isLowerSet_of_isOpen h end Topology diff --git a/Mathlib/Topology/Order/UpperLowerSetTopology.lean b/Mathlib/Topology/Order/UpperLowerSetTopology.lean index 02681dbd9f86d..8c2d9de64d0b4 100644 --- a/Mathlib/Topology/Order/UpperLowerSetTopology.lean +++ b/Mathlib/Topology/Order/UpperLowerSetTopology.lean @@ -95,7 +95,7 @@ protected def rec {β : WithUpperSet α → Sort*} (h : ∀ a, β (toUpperSet a) instance [Nonempty α] : Nonempty (WithUpperSet α) := ‹Nonempty α› instance [Inhabited α] : Inhabited (WithUpperSet α) := ‹Inhabited α› -variable [Preorder α] [Preorder β] [Preorder γ] +variable [Preorder α] [Preorder β] instance : Preorder (WithUpperSet α) := ‹Preorder α› instance : TopologicalSpace (WithUpperSet α) := upperSet α @@ -220,7 +220,7 @@ instance _root_.OrderDual.instIsLowerSet [Preorder α] [TopologicalSpace α] [To /-- If `α` is equipped with the upper set topology, then it is homeomorphic to `WithUpperSet α`. -/ def WithUpperSetHomeomorph : WithUpperSet α ≃ₜ α := - WithUpperSet.ofUpperSet.toHomeomorphOfInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ + WithUpperSet.ofUpperSet.toHomeomorphOfIsInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ lemma isOpen_iff_isUpperSet : IsOpen s ↔ IsUpperSet s := by rw [topology_eq α] @@ -302,7 +302,7 @@ instance _root_.OrderDual.instIsUpperSet [Preorder α] [TopologicalSpace α] [To /-- If `α` is equipped with the lower set topology, then it is homeomorphic to `WithLowerSet α`. -/ def WithLowerSetHomeomorph : WithLowerSet α ≃ₜ α := - WithLowerSet.ofLowerSet.toHomeomorphOfInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ + WithLowerSet.ofLowerSet.toHomeomorphOfIsInducing ⟨by erw [topology_eq α, induced_id]; rfl⟩ lemma isOpen_iff_isLowerSet : IsOpen s ↔ IsLowerSet s := by rw [topology_eq α]; rfl diff --git a/Mathlib/Topology/Partial.lean b/Mathlib/Topology/Partial.lean index 8f7c0957e850a..5c1301d71d438 100644 --- a/Mathlib/Topology/Partial.lean +++ b/Mathlib/Topology/Partial.lean @@ -51,7 +51,7 @@ theorem open_dom_of_pcontinuous {f : X →. Y} (h : PContinuous f) : IsOpen f.Do rw [← PFun.preimage_univ]; exact h _ isOpen_univ theorem pcontinuous_iff' {f : X →. Y} : - PContinuous f ↔ ∀ {x y} (h : y ∈ f x), PTendsto' f (𝓝 x) (𝓝 y) := by + PContinuous f ↔ ∀ {x y} (_ : y ∈ f x), PTendsto' f (𝓝 x) (𝓝 y) := by constructor · intro h x y h' simp only [ptendsto'_def, mem_nhds_iff] diff --git a/Mathlib/Topology/PartialHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean index 98e7d2e0d5f74..0f70e094b5f72 100644 --- a/Mathlib/Topology/PartialHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -761,7 +761,7 @@ theorem trans_of_set' {s : Set Y} (hs : IsOpen s) : e.trans (ofSet s hs) = e.restr (e.source ∩ e ⁻¹' s) := by rw [trans_ofSet, restr_source_inter] theorem ofSet_trans {s : Set X} (hs : IsOpen s) : (ofSet s hs).trans e = e.restr s := - PartialHomeomorph.ext _ _ (fun x => rfl) (fun x => rfl) <| by simp [hs.interior_eq, inter_comm] + PartialHomeomorph.ext _ _ (fun _ => rfl) (fun _ => rfl) <| by simp [hs.interior_eq, inter_comm] theorem ofSet_trans' {s : Set X} (hs : IsOpen s) : (ofSet s hs).trans e = e.restr (e.source ∩ s) := by @@ -1092,18 +1092,24 @@ def toHomeomorphOfSourceEqUnivTargetEqUniv (h : e.source = (univ : Set X)) (h' : continuous_invFun := by simpa only [continuous_iff_continuousOn_univ, h'] using e.continuousOn_symm -theorem openEmbedding_restrict : OpenEmbedding (e.source.restrict e) := by - refine openEmbedding_of_continuous_injective_open (e.continuousOn.comp_continuous +theorem isOpenEmbedding_restrict : IsOpenEmbedding (e.source.restrict e) := by + refine isOpenEmbedding_of_continuous_injective_open (e.continuousOn.comp_continuous continuous_subtype_val Subtype.prop) e.injOn.injective fun V hV ↦ ?_ rw [Set.restrict_eq, Set.image_comp] exact e.isOpen_image_of_subset_source (e.open_source.isOpenMap_subtype_val V hV) fun _ ⟨x, _, h⟩ ↦ h ▸ x.2 +@[deprecated (since := "2024-10-18")] +alias openEmbedding_restrict := isOpenEmbedding_restrict + /-- A partial homeomorphism whose source is all of `X` defines an open embedding of `X` into `Y`. -The converse is also true; see `OpenEmbedding.toPartialHomeomorph`. -/ -theorem to_openEmbedding (h : e.source = Set.univ) : OpenEmbedding e := - e.openEmbedding_restrict.comp - ((Homeomorph.setCongr h).trans <| Homeomorph.Set.univ X).symm.openEmbedding +The converse is also true; see `IsOpenEmbedding.toPartialHomeomorph`. -/ +theorem to_isOpenEmbedding (h : e.source = Set.univ) : IsOpenEmbedding e := + e.isOpenEmbedding_restrict.comp + ((Homeomorph.setCongr h).trans <| Homeomorph.Set.univ X).symm.isOpenEmbedding + +@[deprecated (since := "2024-10-18")] +alias to_openEmbedding := to_isOpenEmbedding end PartialHomeomorph @@ -1156,15 +1162,16 @@ theorem trans_transPartialHomeomorph (e : X ≃ₜ Y) (e' : Y ≃ₜ Z) (f'' : P end Homeomorph -namespace OpenEmbedding +namespace IsOpenEmbedding -variable (f : X → Y) (h : OpenEmbedding f) +variable (f : X → Y) (h : IsOpenEmbedding f) /-- An open embedding of `X` into `Y`, with `X` nonempty, defines a partial homeomorphism -whose source is all of `X`. The converse is also true; see `PartialHomeomorph.to_openEmbedding`. -/ +whose source is all of `X`. The converse is also true; see +`PartialHomeomorph.to_isOpenEmbedding`. -/ @[simps! (config := mfld_cfg) apply source target] noncomputable def toPartialHomeomorph [Nonempty X] : PartialHomeomorph X Y := - PartialHomeomorph.ofContinuousOpen (h.toEmbedding.inj.injOn.toPartialEquiv f univ) + PartialHomeomorph.ofContinuousOpen (h.isEmbedding.inj.injOn.toPartialEquiv f univ) h.continuous.continuousOn h.isOpenMap isOpen_univ variable [Nonempty X] @@ -1178,7 +1185,7 @@ lemma toPartialHomeomorph_right_inv {x : Y} (hx : x ∈ Set.range f) : rw [← congr_fun (h.toPartialHomeomorph_apply f), PartialHomeomorph.right_inv] rwa [toPartialHomeomorph_target] -end OpenEmbedding +end IsOpenEmbedding /-! inclusion of an open set in a topological space -/ namespace TopologicalSpace.Opens @@ -1191,7 +1198,7 @@ variable (s : Opens X) (hs : Nonempty s) /-- The inclusion of an open subset `s` of a space `X` into `X` is a partial homeomorphism from the subtype `s` to `X`. -/ noncomputable def partialHomeomorphSubtypeCoe : PartialHomeomorph s X := - OpenEmbedding.toPartialHomeomorph _ s.2.openEmbedding_subtype_val + IsOpenEmbedding.toPartialHomeomorph _ s.2.isOpenEmbedding_subtypeVal @[simp, mfld_simps] theorem partialHomeomorphSubtypeCoe_coe : (s.partialHomeomorphSubtypeCoe hs : s → X) = (↑) := diff --git a/Mathlib/Topology/PartitionOfUnity.lean b/Mathlib/Topology/PartitionOfUnity.lean index 661a124cbc7d4..d5fb0185564ef 100644 --- a/Mathlib/Topology/PartitionOfUnity.lean +++ b/Mathlib/Topology/PartitionOfUnity.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.Finprod +import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.Topology.ContinuousMap.Algebra import Mathlib.Topology.Compactness.Paracompact import Mathlib.Topology.ShrinkingLemma @@ -339,7 +340,7 @@ protected def single (i : ι) (s : Set X) : BumpCovering ι X s where contrapose! hx rw [mem_singleton_iff] at hx simp [hx] - nonneg' := le_update_iff.2 ⟨fun x => zero_le_one, fun _ _ => le_rfl⟩ + nonneg' := le_update_iff.2 ⟨fun _ => zero_le_one, fun _ _ => le_rfl⟩ le_one' := update_le_iff.2 ⟨le_rfl, fun _ _ _ => zero_le_one⟩ eventuallyEq_one' x _ := ⟨i, by rw [Pi.single_eq_same, ContinuousMap.coe_one]⟩ @@ -506,7 +507,7 @@ def toPartitionOfUnity : PartitionOfUnity ι X s where toFun i := ⟨f.toPOUFun i, f.continuous_toPOUFun i⟩ locallyFinite' := f.locallyFinite.subset f.support_toPOUFun_subset nonneg' i x := - mul_nonneg (f.nonneg i x) (finprod_cond_nonneg fun j hj => sub_nonneg.2 <| f.le_one j x) + mul_nonneg (f.nonneg i x) (finprod_cond_nonneg fun j _ => sub_nonneg.2 <| f.le_one j x) sum_eq_one' x hx := by simp only [ContinuousMap.coe_mk, sum_toPOUFun_eq, sub_eq_self] apply finprod_eq_zero (fun i => 1 - f i x) (f.ind x hx) diff --git a/Mathlib/Topology/Perfect.lean b/Mathlib/Topology/Perfect.lean index 31622ec28846e..88e7d579f3dd7 100644 --- a/Mathlib/Topology/Perfect.lean +++ b/Mathlib/Topology/Perfect.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Felix Weilacher -/ -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Perfect Sets @@ -93,7 +93,7 @@ A topological space `X` is said to be perfect if its universe is a perfect set. Equivalently, this means that `𝓝[≠] x ≠ ⊥` for every point `x : X`. -/ @[mk_iff perfectSpace_def] -class PerfectSpace : Prop := +class PerfectSpace : Prop where univ_preperfect : Preperfect (Set.univ : Set α) theorem PerfectSpace.univ_perfect [PerfectSpace α] : Perfect (Set.univ : Set α) := diff --git a/Mathlib/Topology/QuasiSeparated.lean b/Mathlib/Topology/QuasiSeparated.lean index 869b89e96ebba..f4ab068bd84bc 100644 --- a/Mathlib/Topology/QuasiSeparated.lean +++ b/Mathlib/Topology/QuasiSeparated.lean @@ -3,7 +3,6 @@ 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.Topology.Separation import Mathlib.Topology.NoetherianSpace /-! @@ -22,7 +21,7 @@ open subsets, but their intersection `(0, 1]` is not. of any pairs of compact open subsets of `s` are still compact. - `QuasiSeparatedSpace`: A topological space is quasi-separated if the intersections of any pairs of compact open subsets are still compact. -- `QuasiSeparatedSpace.of_openEmbedding`: If `f : α → β` is an open embedding, and `β` is +- `QuasiSeparatedSpace.of_isOpenEmbedding`: If `f : α → β` is an open embedding, and `β` is a quasi-separated space, then so is `α`. -/ @@ -55,8 +54,8 @@ theorem isQuasiSeparated_univ {α : Type*} [TopologicalSpace α] [QuasiSeparated IsQuasiSeparated (Set.univ : Set α) := isQuasiSeparated_univ_iff.mpr inferInstance -theorem IsQuasiSeparated.image_of_embedding {s : Set α} (H : IsQuasiSeparated s) (h : Embedding f) : - IsQuasiSeparated (f '' s) := by +theorem IsQuasiSeparated.image_of_isEmbedding {s : Set α} (H : IsQuasiSeparated s) + (h : IsEmbedding f) : IsQuasiSeparated (f '' s) := by intro U V hU hU' hU'' hV hV' hV'' convert (H (f ⁻¹' U) (f ⁻¹' V) @@ -79,19 +78,25 @@ theorem IsQuasiSeparated.image_of_embedding {s : Set α} (H : IsQuasiSeparated s rw [Set.image_preimage_eq_inter_range, Set.inter_eq_left] exact hV.trans (Set.image_subset_range _ _) -theorem OpenEmbedding.isQuasiSeparated_iff (h : OpenEmbedding f) {s : Set α} : +@[deprecated (since := "2024-10-26")] +alias IsQuasiSeparated.image_of_embedding := IsQuasiSeparated.image_of_isEmbedding + +theorem IsOpenEmbedding.isQuasiSeparated_iff (h : IsOpenEmbedding f) {s : Set α} : IsQuasiSeparated s ↔ IsQuasiSeparated (f '' s) := by - refine ⟨fun hs => hs.image_of_embedding h.toEmbedding, ?_⟩ + refine ⟨fun hs => hs.image_of_isEmbedding h.isEmbedding, ?_⟩ intro H U V hU hU' hU'' hV hV' hV'' - rw [h.toEmbedding.isCompact_iff, Set.image_inter h.inj] + rw [h.isEmbedding.isCompact_iff, Set.image_inter h.inj] exact H (f '' U) (f '' V) (Set.image_subset _ hU) (h.isOpenMap _ hU') (hU''.image h.continuous) (Set.image_subset _ hV) (h.isOpenMap _ hV') (hV''.image h.continuous) +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.isQuasiSeparated_iff := IsOpenEmbedding.isQuasiSeparated_iff + theorem isQuasiSeparated_iff_quasiSeparatedSpace (s : Set α) (hs : IsOpen s) : IsQuasiSeparated s ↔ QuasiSeparatedSpace s := by rw [← isQuasiSeparated_univ_iff] - convert (hs.openEmbedding_subtype_val.isQuasiSeparated_iff (s := Set.univ)).symm + convert (hs.isOpenEmbedding_subtypeVal.isQuasiSeparated_iff (s := Set.univ)).symm simp theorem IsQuasiSeparated.of_subset {s t : Set α} (ht : IsQuasiSeparated t) (h : s ⊆ t) : @@ -110,7 +115,10 @@ theorem IsQuasiSeparated.of_quasiSeparatedSpace (s : Set α) [QuasiSeparatedSpac IsQuasiSeparated s := isQuasiSeparated_univ.of_subset (Set.subset_univ _) -theorem QuasiSeparatedSpace.of_openEmbedding (h : OpenEmbedding f) [QuasiSeparatedSpace β] : +theorem QuasiSeparatedSpace.of_isOpenEmbedding (h : IsOpenEmbedding f) [QuasiSeparatedSpace β] : QuasiSeparatedSpace α := isQuasiSeparated_univ_iff.mp (h.isQuasiSeparated_iff.mpr <| IsQuasiSeparated.of_quasiSeparatedSpace _) + +@[deprecated (since := "2024-10-18")] +alias QuasiSeparatedSpace.of_openEmbedding := QuasiSeparatedSpace.of_isOpenEmbedding diff --git a/Mathlib/Topology/SeparatedMap.lean b/Mathlib/Topology/SeparatedMap.lean index 67633a9c6069d..ee6f959bbb624 100644 --- a/Mathlib/Topology/SeparatedMap.lean +++ b/Mathlib/Topology/SeparatedMap.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Junyan Xu -/ import Mathlib.Topology.Connected.Basic -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Separated maps and locally injective maps out of a topological space. @@ -38,11 +38,14 @@ open scoped Topology variable {X Y A} [TopologicalSpace X] [TopologicalSpace A] -theorem embedding_toPullbackDiag (f : X → Y) : Embedding (toPullbackDiag f) := - Embedding.mk' _ (injective_toPullbackDiag f) fun x ↦ by +protected lemma IsEmbedding.toPullbackDiag (f : X → Y) : IsEmbedding (toPullbackDiag f) := + .mk' _ (injective_toPullbackDiag f) fun x ↦ by rw [toPullbackDiag, nhds_induced, Filter.comap_comap, nhds_prod_eq, Filter.comap_prod] erw [Filter.comap_id, inf_idem] +@[deprecated (since := "2024-10-26")] +alias embedding_toPullbackDiag := IsEmbedding.toPullbackDiag + lemma Continuous.mapPullback {X₁ X₂ Y₁ Y₂ Z₁ Z₂} [TopologicalSpace X₁] [TopologicalSpace X₂] [TopologicalSpace Z₁] [TopologicalSpace Z₂] {f₁ : X₁ → Y₁} {g₁ : Z₁ → Y₁} {f₂ : X₂ → Y₂} {g₂ : Z₂ → Y₂} @@ -86,16 +89,19 @@ theorem isSeparatedMap_iff_isClosed_diagonal {f : X → Y} : · obtain ⟨s₁, h₁, s₂, h₂, s_sub⟩ := mem_prod_iff.mp ht exact ⟨s₁, h₁, s₂, h₂, disjoint_left.2 fun x h₁ h₂ ↦ @t_sub ⟨(x, x), rfl⟩ (s_sub ⟨h₁, h₂⟩) rfl⟩ -theorem isSeparatedMap_iff_closedEmbedding {f : X → Y} : - IsSeparatedMap f ↔ ClosedEmbedding (toPullbackDiag f) := by +theorem isSeparatedMap_iff_isClosedEmbedding {f : X → Y} : + IsSeparatedMap f ↔ IsClosedEmbedding (toPullbackDiag f) := by rw [isSeparatedMap_iff_isClosed_diagonal, ← range_toPullbackDiag] - exact ⟨fun h ↦ ⟨embedding_toPullbackDiag f, h⟩, fun h ↦ h.isClosed_range⟩ + exact ⟨fun h ↦ ⟨.toPullbackDiag f, h⟩, fun h ↦ h.isClosed_range⟩ + +@[deprecated (since := "2024-10-20")] +alias isSeparatedMap_iff_closedEmbedding := isSeparatedMap_iff_isClosedEmbedding theorem isSeparatedMap_iff_isClosedMap {f : X → Y} : IsSeparatedMap f ↔ IsClosedMap (toPullbackDiag f) := - isSeparatedMap_iff_closedEmbedding.trans - ⟨ClosedEmbedding.isClosedMap, closedEmbedding_of_continuous_injective_closed - (embedding_toPullbackDiag f).continuous (injective_toPullbackDiag f)⟩ + isSeparatedMap_iff_isClosedEmbedding.trans + ⟨IsClosedEmbedding.isClosedMap, .of_continuous_injective_isClosedMap + (IsEmbedding.toPullbackDiag f).continuous (injective_toPullbackDiag f)⟩ open Function.Pullback in theorem IsSeparatedMap.pullback {f : X → Y} (sep : IsSeparatedMap f) (g : A → Y) : @@ -141,16 +147,19 @@ theorem isLocallyInjective_iff_isOpen_diagonal {f : X → Y} : exact ⟨t₁ ∩ t₂, Filter.inter_mem h₁ h₂, fun x₁ h₁ x₂ h₂ he ↦ @t_sub ⟨(x₁, x₂), he⟩ (prod_sub ⟨h₁.1, h₂.2⟩)⟩ -theorem IsLocallyInjective_iff_openEmbedding {f : X → Y} : - IsLocallyInjective f ↔ OpenEmbedding (toPullbackDiag f) := by +theorem IsLocallyInjective_iff_isOpenEmbedding {f : X → Y} : + IsLocallyInjective f ↔ IsOpenEmbedding (toPullbackDiag f) := by rw [isLocallyInjective_iff_isOpen_diagonal, ← range_toPullbackDiag] - exact ⟨fun h ↦ ⟨embedding_toPullbackDiag f, h⟩, fun h ↦ h.isOpen_range⟩ + exact ⟨fun h ↦ ⟨.toPullbackDiag f, h⟩, fun h ↦ h.isOpen_range⟩ + +@[deprecated (since := "2024-10-18")] +alias IsLocallyInjective_iff_openEmbedding := IsLocallyInjective_iff_isOpenEmbedding theorem isLocallyInjective_iff_isOpenMap {f : X → Y} : IsLocallyInjective f ↔ IsOpenMap (toPullbackDiag f) := - IsLocallyInjective_iff_openEmbedding.trans - ⟨OpenEmbedding.isOpenMap, openEmbedding_of_continuous_injective_open - (embedding_toPullbackDiag f).continuous (injective_toPullbackDiag f)⟩ + IsLocallyInjective_iff_isOpenEmbedding.trans + ⟨IsOpenEmbedding.isOpenMap, isOpenEmbedding_of_continuous_injective_open + (IsEmbedding.toPullbackDiag f).continuous (injective_toPullbackDiag f)⟩ theorem discreteTopology_iff_locallyInjective (y : Y) : DiscreteTopology X ↔ IsLocallyInjective fun _ : X ↦ y := by @@ -174,11 +183,25 @@ section eqLocus variable {f : X → Y} {g₁ g₂ : A → X} (h₁ : Continuous g₁) (h₂ : Continuous g₂) include h₁ h₂ +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/5338, +the unused variable linter flags `g` here, +but it is used in a type ascription to direct `fun_prop`. +-/ +set_option linter.unusedVariables false in theorem IsSeparatedMap.isClosed_eqLocus (sep : IsSeparatedMap f) (he : f ∘ g₁ = f ∘ g₂) : IsClosed {a | g₁ a = g₂ a} := let g : A → f.Pullback f := fun a ↦ ⟨⟨g₁ a, g₂ a⟩, congr_fun he a⟩ (isSeparatedMap_iff_isClosed_diagonal.mp sep).preimage (by fun_prop : Continuous g) +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/5338, +the unused variable linter flags `g` here, +but it is used in a type ascription to direct `fun_prop`. +-/ +set_option linter.unusedVariables false in theorem IsLocallyInjective.isOpen_eqLocus (inj : IsLocallyInjective f) (he : f ∘ g₁ = f ∘ g₂) : IsOpen {a | g₁ a = g₂ a} := let g : A → f.Pullback f := fun a ↦ ⟨⟨g₁ a, g₂ a⟩, congr_fun he a⟩ diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation/Basic.lean similarity index 92% rename from Mathlib/Topology/Separation.lean rename to Mathlib/Topology/Separation/Basic.lean index c2de323af42d9..59d6a1398c275 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation/Basic.lean @@ -7,7 +7,6 @@ import Mathlib.Topology.Compactness.Lindelof import Mathlib.Topology.Compactness.SigmaCompact import Mathlib.Topology.Connected.TotallyDisconnected import Mathlib.Topology.Inseparable -import Mathlib.Topology.GDelta /-! # Separation properties of topological spaces. @@ -50,19 +49,13 @@ This file defines the predicate `SeparatedNhds`, and common separation axioms us to conclude that this is equivalent to all subspaces being normal. Such a space is not necessarily Hausdorff or regular, even if it is T₀. * `T5Space`: A T₅ space is a completely normal T₁ space. T₅ implies T₄. -* `PerfectlyNormalSpace`: A perfectly normal space is a normal space such that - closed sets are Gδ. -* `T6Space`: A T₆ space is a Perfectly normal T₁ space. T₆ implies T₅. + +See `Mathlib.Topology.Separation.GDelta` for the definitions of `PerfectlyNormalSpace` and +`T6Space`. Note that `mathlib` adopts the modern convention that `m ≤ n` if and only if `T_m → T_n`, but occasionally the literature swaps definitions for e.g. T₃ and regular. -### TODO - -* Add perfectly normal and T6 spaces. -* Use `hasSeparatingCovers_iff_separatedNhds` to prove that perfectly normal spaces - are completely normal. - ## Main results ### T₀ spaces @@ -84,7 +77,7 @@ occasionally the literature swaps definitions for e.g. T₃ and regular. points of the form `(a, a) : X × X`) is closed under the product topology. * `separatedNhds_of_finset_finset`: Any two disjoint finsets are `SeparatedNhds`. * Most topological constructions preserve Hausdorffness; - these results are part of the typeclass inference system (e.g. `Embedding.t2Space`) + these results are part of the typeclass inference system (e.g. `IsEmbedding.t2Space`) * `Set.EqOn.closure`: If two functions are equal on some set `s`, they are equal on its closure. * `IsCompact.isClosed`: All compact sets are closed. * `WeaklyLocallyCompactSpace.locallyCompactSpace`: If a topological space is both @@ -124,6 +117,8 @@ If the space is also Lindelöf: -/ +assert_not_exists UniformSpace + open Function Set Filter Topology TopologicalSpace universe u v @@ -275,19 +270,31 @@ theorem t0Space_iff_not_inseparable (X : Type u) [TopologicalSpace X] : theorem Inseparable.eq [T0Space X] {x y : X} (h : Inseparable x y) : x = y := T0Space.t0 h -/-- A topology `Inducing` map from a T₀ space is injective. -/ -protected theorem Inducing.injective [TopologicalSpace Y] [T0Space X] {f : X → Y} - (hf : Inducing f) : Injective f := fun _ _ h => +/-- A topology inducing map from a T₀ space is injective. -/ +protected theorem IsInducing.injective [TopologicalSpace Y] [T0Space X] {f : X → Y} + (hf : IsInducing f) : Injective f := fun _ _ h => (hf.inseparable_iff.1 <| .of_eq h).eq -/-- A topology `Inducing` map from a T₀ space is a topological embedding. -/ -protected theorem Inducing.embedding [TopologicalSpace Y] [T0Space X] {f : X → Y} - (hf : Inducing f) : Embedding f := +@[deprecated (since := "2024-10-28")] alias Inducing.injective := IsInducing.injective + +/-- A topology inducing map from a T₀ space is a topological embedding. -/ +protected theorem IsInducing.isEmbedding [TopologicalSpace Y] [T0Space X] {f : X → Y} + (hf : IsInducing f) : IsEmbedding f := ⟨hf, hf.injective⟩ -lemma embedding_iff_inducing [TopologicalSpace Y] [T0Space X] {f : X → Y} : - Embedding f ↔ Inducing f := - ⟨Embedding.toInducing, Inducing.embedding⟩ +@[deprecated (since := "2024-10-28")] alias Inducing.isEmbedding := IsInducing.isEmbedding + +@[deprecated (since := "2024-10-26")] +alias Inducing.embedding := IsInducing.isEmbedding + +lemma isEmbedding_iff_isInducing [TopologicalSpace Y] [T0Space X] {f : X → Y} : + IsEmbedding f ↔ IsInducing f := + ⟨IsEmbedding.isInducing, IsInducing.isEmbedding⟩ + +@[deprecated (since := "2024-10-28")] alias isEmbedding_iff_inducing := isEmbedding_iff_isInducing + +@[deprecated (since := "2024-10-26")] +alias embedding_iff_inducing := isEmbedding_iff_isInducing theorem t0Space_iff_nhds_injective (X : Type u) [TopologicalSpace X] : T0Space X ↔ Injective (𝓝 : X → Filter X) := @@ -309,7 +316,7 @@ theorem inseparable_eq_eq [T0Space X] : Inseparable = @Eq X := theorem TopologicalSpace.IsTopologicalBasis.inseparable_iff {b : Set (Set X)} (hb : IsTopologicalBasis b) {x y : X} : Inseparable x y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) := - ⟨fun h s hs ↦ inseparable_iff_forall_open.1 h _ (hb.isOpen hs), + ⟨fun h _ hs ↦ inseparable_iff_forall_open.1 h _ (hb.isOpen hs), fun h ↦ hb.nhds_hasBasis.eq_of_same_basis <| by convert hb.nhds_hasBasis using 2 exact and_congr_right (h _)⟩ @@ -333,7 +340,7 @@ def specializationOrder (X) [TopologicalSpace X] [T0Space X] : PartialOrder X := instance SeparationQuotient.instT0Space : T0Space (SeparationQuotient X) := ⟨fun x y => Quotient.inductionOn₂' x y fun _ _ h => - SeparationQuotient.mk_eq_mk.2 <| SeparationQuotient.inducing_mk.inseparable_iff.1 h⟩ + SeparationQuotient.mk_eq_mk.2 <| SeparationQuotient.isInducing_mk.inseparable_iff.1 h⟩ theorem minimal_nonempty_closed_subsingleton [T0Space X] {s : Set X} (hs : IsClosed s) (hmin : ∀ t, t ⊆ s → t.Nonempty → IsClosed t → t = s) : s.Subsingleton := by @@ -399,12 +406,15 @@ theorem t0Space_of_injective_of_continuous [TopologicalSpace Y] {f : X → Y} (hf : Function.Injective f) (hf' : Continuous f) [T0Space Y] : T0Space X := ⟨fun _ _ h => hf <| (h.map hf').eq⟩ -protected theorem Embedding.t0Space [TopologicalSpace Y] [T0Space Y] {f : X → Y} - (hf : Embedding f) : T0Space X := +protected theorem IsEmbedding.t0Space [TopologicalSpace Y] [T0Space Y] {f : X → Y} + (hf : IsEmbedding f) : T0Space X := t0Space_of_injective_of_continuous hf.inj hf.continuous +@[deprecated (since := "2024-10-26")] +alias Embedding.t0Space := IsEmbedding.t0Space + instance Subtype.t0Space [T0Space X] {p : X → Prop} : T0Space (Subtype p) := - embedding_subtype_val.t0Space + IsEmbedding.subtypeVal.t0Space theorem t0Space_iff_or_not_mem_closure (X : Type u) [TopologicalSpace X] : T0Space X ↔ Pairwise fun a b : X => a ∉ closure ({b} : Set X) ∨ b ∉ closure ({a} : Set X) := by @@ -418,8 +428,7 @@ instance Pi.instT0Space {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace T0Space (∀ i, X i) := ⟨fun _ _ h => funext fun i => (h.map (continuous_apply i)).eq⟩ -instance ULift.instT0Space [T0Space X] : T0Space (ULift X) := - embedding_uLift_down.t0Space +instance ULift.instT0Space [T0Space X] : T0Space (ULift X) := IsEmbedding.uliftDown.t0Space theorem T0Space.of_cover (h : ∀ x y, Inseparable x y → ∃ s : Set X, x ∈ s ∧ y ∈ s ∧ T0Space s) : T0Space X := by @@ -462,11 +471,13 @@ theorem specializes_iff_inseparable : x ⤳ y ↔ Inseparable x y := /-- In an R₀ space, `Specializes` implies `Inseparable`. -/ alias ⟨Specializes.inseparable, _⟩ := specializes_iff_inseparable -theorem Inducing.r0Space [TopologicalSpace Y] {f : Y → X} (hf : Inducing f) : R0Space Y where +theorem IsInducing.r0Space [TopologicalSpace Y] {f : Y → X} (hf : IsInducing f) : R0Space Y where specializes_symmetric a b := by simpa only [← hf.specializes_iff] using Specializes.symm -instance {p : X → Prop} : R0Space {x // p x} := inducing_subtype_val.r0Space +@[deprecated (since := "2024-10-28")] alias Inducing.r0Space := IsInducing.r0Space + +instance {p : X → Prop} : R0Space {x // p x} := IsInducing.subtypeVal.r0Space instance [TopologicalSpace Y] [R0Space Y] : R0Space (X × Y) where specializes_symmetric _ _ h := h.fst.symm.prod h.snd.symm @@ -675,7 +686,7 @@ theorem continuousOn_update_iff [T1Space X] [DecidableEq X] [TopologicalSpace Y] rw [continuousWithinAt_update_of_ne hz.2] at H exact H.mono diff_subset · rw [continuousWithinAt_update_of_ne hzx] - refine (H z ⟨hzs, hzx⟩).mono_of_mem (inter_mem_nhdsWithin _ ?_) + refine (H z ⟨hzs, hzx⟩).mono_of_mem_nhdsWithin (inter_mem_nhdsWithin _ ?_) exact isOpen_ne.mem_nhds hzx · exact continuousWithinAt_update_same @@ -683,13 +694,16 @@ theorem t1Space_of_injective_of_continuous [TopologicalSpace Y] {f : X → Y} (hf : Function.Injective f) (hf' : Continuous f) [T1Space Y] : T1Space X := t1Space_iff_specializes_imp_eq.2 fun _ _ h => hf (h.map hf').eq -protected theorem Embedding.t1Space [TopologicalSpace Y] [T1Space Y] {f : X → Y} - (hf : Embedding f) : T1Space X := +protected theorem IsEmbedding.t1Space [TopologicalSpace Y] [T1Space Y] {f : X → Y} + (hf : IsEmbedding f) : T1Space X := t1Space_of_injective_of_continuous hf.inj hf.continuous +@[deprecated (since := "2024-10-26")] +alias Embedding.t1Space := IsEmbedding.t1Space + instance Subtype.t1Space {X : Type u} [TopologicalSpace X] [T1Space X] {p : X → Prop} : T1Space (Subtype p) := - embedding_subtype_val.t1Space + IsEmbedding.subtypeVal.t1Space instance [TopologicalSpace Y] [T1Space X] [T1Space Y] : T1Space (X × Y) := ⟨fun ⟨a, b⟩ => @singleton_prod_singleton _ _ a b ▸ isClosed_singleton.prod isClosed_singleton⟩ @@ -699,7 +713,7 @@ instance {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, ⟨fun f => univ_pi_singleton f ▸ isClosed_set_pi fun _ _ => isClosed_singleton⟩ instance ULift.instT1Space [T1Space X] : T1Space (ULift X) := - embedding_uLift_down.t1Space + IsEmbedding.uliftDown.t1Space -- see Note [lower instance priority] instance (priority := 100) TotallyDisconnectedSpace.t1Space [h : TotallyDisconnectedSpace X] : @@ -755,6 +769,14 @@ theorem insert_mem_nhdsWithin_of_subset_insert [T1Space X] {x y : X} {s t : Set rw [nhdsWithin_insert_of_ne h] exact mem_of_superset self_mem_nhdsWithin (subset_insert x s) +lemma eventuallyEq_insert [T1Space X] {s t : Set X} {x y : X} (h : s =ᶠ[𝓝[{y}ᶜ] x] t) : + (insert x s : Set X) =ᶠ[𝓝 x] (insert x t : Set X) := by + simp_rw [eventuallyEq_set] at h ⊢ + simp_rw [← union_singleton, ← nhdsWithin_univ, ← compl_union_self {x}, + nhdsWithin_union, eventually_sup, nhdsWithin_singleton, + eventually_pure, union_singleton, mem_insert_iff, true_or, and_true] + filter_upwards [nhdsWithin_compl_singleton_le x y h] with y using or_congr (Iff.rfl) + @[simp] theorem ker_nhds [T1Space X] (x : X) : (𝓝 x).ker = {x} := by simp [ker_nhds_eq_specializes] @@ -838,6 +860,29 @@ theorem eventually_ne_nhdsWithin [T1Space X] {a b : X} {s : Set X} (h : a ≠ b) ∀ᶠ x in 𝓝[s] a, x ≠ b := Filter.Eventually.filter_mono nhdsWithin_le_nhds <| eventually_ne_nhds h +theorem continuousWithinAt_insert [TopologicalSpace Y] [T1Space X] + {x y : X} {s : Set X} {f : X → Y} : + ContinuousWithinAt f (insert y s) x ↔ ContinuousWithinAt f s x := by + rcases eq_or_ne x y with (rfl | h) + · exact continuousWithinAt_insert_self + simp_rw [ContinuousWithinAt, nhdsWithin_insert_of_ne h] + +alias ⟨ContinuousWithinAt.of_insert, ContinuousWithinAt.insert'⟩ := continuousWithinAt_insert + +/-- See also `continuousWithinAt_diff_self` for the case `y = x` but not requiring `T1Space`. -/ +theorem continuousWithinAt_diff_singleton [TopologicalSpace Y] [T1Space X] + {x y : X} {s : Set X} {f : X → Y} : + ContinuousWithinAt f (s \ {y}) x ↔ ContinuousWithinAt f s x := by + rw [← continuousWithinAt_insert, insert_diff_singleton, continuousWithinAt_insert] + +/-- If two sets coincide locally around `x`, except maybe at `y`, then it is equivalent to be +continuous at `x` within one set or the other. -/ +theorem continuousWithinAt_congr_set' [TopologicalSpace Y] [T1Space X] + {x : X} {s t : Set X} {f : X → Y} (y : X) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) : + ContinuousWithinAt f s x ↔ ContinuousWithinAt f t x := by + rw [← continuousWithinAt_insert_self (s := s), ← continuousWithinAt_insert_self (s := t)] + exact continuousWithinAt_congr_set (eventuallyEq_insert h) + /-- To prove a function to a `T1Space` is continuous at some point `x`, it suffices to prove that `f` admits *some* limit at `x`. -/ theorem continuousAt_of_tendsto_nhds [TopologicalSpace Y] [T1Space Y] {f : X → Y} {x : X} {y : Y} @@ -900,43 +945,13 @@ instance (priority := 100) ConnectedSpace.neBot_nhdsWithin_compl_of_nontrivial_o contra (compl_union_self _) (Set.nonempty_compl_of_nontrivial _) (singleton_nonempty _) simp [compl_inter_self {x}] at contra -theorem IsGδ.compl_singleton (x : X) [T1Space X] : IsGδ ({x}ᶜ : Set X) := - isOpen_compl_singleton.isGδ - -@[deprecated (since := "2024-02-15")] alias isGδ_compl_singleton := IsGδ.compl_singleton - -theorem Set.Countable.isGδ_compl {s : Set X} [T1Space X] (hs : s.Countable) : IsGδ sᶜ := by - rw [← biUnion_of_singleton s, compl_iUnion₂] - exact .biInter hs fun x _ => .compl_singleton x - -theorem Set.Finite.isGδ_compl {s : Set X} [T1Space X] (hs : s.Finite) : IsGδ sᶜ := - hs.countable.isGδ_compl - -theorem Set.Subsingleton.isGδ_compl {s : Set X} [T1Space X] (hs : s.Subsingleton) : IsGδ sᶜ := - hs.finite.isGδ_compl - -theorem Finset.isGδ_compl [T1Space X] (s : Finset X) : IsGδ (sᶜ : Set X) := - s.finite_toSet.isGδ_compl - -protected theorem IsGδ.singleton [FirstCountableTopology X] [T1Space X] (x : X) : - IsGδ ({x} : Set X) := by - rcases (nhds_basis_opens x).exists_antitone_subbasis with ⟨U, hU, h_basis⟩ - rw [← biInter_basis_nhds h_basis.toHasBasis] - exact .biInter (to_countable _) fun n _ => (hU n).2.isGδ - -@[deprecated (since := "2024-02-15")] alias isGδ_singleton := IsGδ.singleton - -theorem Set.Finite.isGδ [FirstCountableTopology X] {s : Set X} [T1Space X] (hs : s.Finite) : - IsGδ s := - Finite.induction_on hs .empty fun _ _ ↦ .union (.singleton _) - theorem SeparationQuotient.t1Space_iff : T1Space (SeparationQuotient X) ↔ R0Space X := by rw [r0Space_iff, ((t1Space_TFAE (SeparationQuotient X)).out 0 9 :)] constructor · intro h x y xspecy - rw [← Inducing.specializes_iff inducing_mk, h xspecy] at * + rw [← IsInducing.specializes_iff isInducing_mk, h xspecy] at * · rintro h ⟨x⟩ ⟨y⟩ sxspecsy - have xspecy : x ⤳ y := (Inducing.specializes_iff inducing_mk).mp sxspecsy + have xspecy : x ⤳ y := isInducing_mk.specializes_iff.mp sxspecsy have yspecx : y ⤳ x := h xspecy erw [mk_eq_mk, inseparable_iff_specializes_and] exact ⟨xspecy, yspecx⟩ @@ -999,17 +1014,18 @@ theorem disjoint_nhdsWithin_of_mem_discrete {s : Set X} [DiscreteTopology s] {x ⟨{x}ᶜ ∩ V, inter_mem_nhdsWithin _ h, disjoint_iff_inter_eq_empty.mpr (by rw [inter_assoc, h', compl_inter_self])⟩ -theorem closedEmbedding_update {ι : Type*} {β : ι → Type*} +theorem isClosedEmbedding_update {ι : Type*} {β : ι → Type*} [DecidableEq ι] [(i : ι) → TopologicalSpace (β i)] (x : (i : ι) → β i) (i : ι) [(i : ι) → T1Space (β i)] : - ClosedEmbedding (update x i) := by - apply closedEmbedding_of_continuous_injective_closed - · exact continuous_const.update i continuous_id - · exact update_injective x i - · intro s hs - rw [update_image] - apply isClosed_set_pi - simp [forall_update_iff, hs, isClosed_singleton] + IsClosedEmbedding (update x i) := by + refine .of_continuous_injective_isClosedMap (continuous_const.update i continuous_id) + (update_injective x i) fun s hs ↦ ?_ + rw [update_image] + apply isClosed_set_pi + simp [forall_update_iff, hs, isClosed_singleton] + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_update := isClosedEmbedding_update /-! ### R₁ (preregular) spaces -/ @@ -1169,11 +1185,13 @@ theorem R1Space.of_continuous_specializes_imp [TopologicalSpace Y] {f : Y → X} specializes_or_disjoint_nhds x y := (specializes_or_disjoint_nhds (f x) (f y)).imp (hspec x y) <| ((hc.tendsto _).disjoint · (hc.tendsto _)) -theorem Inducing.r1Space [TopologicalSpace Y] {f : Y → X} (hf : Inducing f) : R1Space Y := +theorem IsInducing.r1Space [TopologicalSpace Y] {f : Y → X} (hf : IsInducing f) : R1Space Y := .of_continuous_specializes_imp hf.continuous fun _ _ ↦ hf.specializes_iff.1 +@[deprecated (since := "2024-10-28")] alias Inducing.r1Space := IsInducing.r1Space + protected theorem R1Space.induced (f : Y → X) : @R1Space Y (.induced f ‹_›) := - @Inducing.r1Space _ _ _ _ (.induced f _) f (inducing_induced f) + @IsInducing.r1Space _ _ _ _ (.induced f _) f (.induced f) instance (p : X → Prop) : R1Space (Subtype p) := .induced _ @@ -1544,7 +1562,7 @@ Hausdorff spaces: `f x ≠ f y`. We use this lemma to prove that topological spaces defined using `induced` are Hausdorff spaces. -* `separated_by_openEmbedding` says that for an open embedding `f : X → Y` of a Hausdorff space +* `separated_by_isOpenEmbedding` says that for an open embedding `f : X → Y` of a Hausdorff space `X`, the images of two distinct points `x y : X`, `x ≠ y` can be separated by open neighborhoods. We use this lemma to prove that topological spaces defined using `coinduced` are Hausdorff spaces. -/ @@ -1560,13 +1578,16 @@ theorem separated_by_continuous [TopologicalSpace Y] [T2Space Y] let ⟨u, v, uo, vo, xu, yv, uv⟩ := t2_separation h ⟨f ⁻¹' u, f ⁻¹' v, uo.preimage hf, vo.preimage hf, xu, yv, uv.preimage _⟩ -theorem separated_by_openEmbedding [TopologicalSpace Y] [T2Space X] - {f : X → Y} (hf : OpenEmbedding f) {x y : X} (h : x ≠ y) : +theorem separated_by_isOpenEmbedding [TopologicalSpace Y] [T2Space X] + {f : X → Y} (hf : IsOpenEmbedding f) {x y : X} (h : x ≠ y) : ∃ u v : Set Y, IsOpen u ∧ IsOpen v ∧ f x ∈ u ∧ f y ∈ v ∧ Disjoint u v := let ⟨u, v, uo, vo, xu, yv, uv⟩ := t2_separation h ⟨f '' u, f '' v, hf.isOpenMap _ uo, hf.isOpenMap _ vo, mem_image_of_mem _ xu, mem_image_of_mem _ yv, disjoint_image_of_injective hf.inj uv⟩ +@[deprecated (since := "2024-10-18")] +alias separated_by_openEmbedding := separated_by_isOpenEmbedding + instance {p : X → Prop} [T2Space X] : T2Space (Subtype p) := inferInstance instance Prod.t2Space [T2Space X] [TopologicalSpace Y] [T2Space Y] : T2Space (X × Y) := @@ -1580,21 +1601,24 @@ theorem T2Space.of_injective_continuous [TopologicalSpace Y] [T2Space Y] {f : X /-- If the codomain of a topological embedding is a Hausdorff space, then so is its domain. See also `T2Space.of_continuous_injective`. -/ -theorem Embedding.t2Space [TopologicalSpace Y] [T2Space Y] {f : X → Y} (hf : Embedding f) : - T2Space X := +theorem IsEmbedding.t2Space [TopologicalSpace Y] [T2Space Y] {f : X → Y} + (hf : IsEmbedding f) : T2Space X := .of_injective_continuous hf.inj hf.continuous +@[deprecated (since := "2024-10-26")] +alias Embedding.t2Space := IsEmbedding.t2Space + instance ULift.instT2Space [T2Space X] : T2Space (ULift X) := - embedding_uLift_down.t2Space + IsEmbedding.uliftDown.t2Space instance [T2Space X] [TopologicalSpace Y] [T2Space Y] : T2Space (X ⊕ Y) := by constructor rintro (x | x) (y | y) h - · exact separated_by_openEmbedding openEmbedding_inl <| ne_of_apply_ne _ h + · exact separated_by_isOpenEmbedding isOpenEmbedding_inl <| ne_of_apply_ne _ h · exact separated_by_continuous continuous_isLeft <| by simp · exact separated_by_continuous continuous_isLeft <| by simp - · exact separated_by_openEmbedding openEmbedding_inr <| ne_of_apply_ne _ h + · exact separated_by_isOpenEmbedding isOpenEmbedding_inr <| ne_of_apply_ne _ h instance Pi.t2Space {Y : X → Type v} [∀ a, TopologicalSpace (Y a)] [∀ a, T2Space (Y a)] : T2Space (∀ a, Y a) := @@ -1606,7 +1630,7 @@ instance Sigma.t2Space {ι} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [ rintro ⟨i, x⟩ ⟨j, y⟩ neq rcases eq_or_ne i j with (rfl | h) · replace neq : x ≠ y := ne_of_apply_ne _ neq - exact separated_by_openEmbedding openEmbedding_sigmaMk neq + exact separated_by_isOpenEmbedding isOpenEmbedding_sigmaMk neq · let _ := (⊥ : TopologicalSpace ι); have : DiscreteTopology ι := ⟨rfl⟩ exact separated_by_continuous (continuous_def.2 fun u _ => isOpen_sigma_fst_preimage u) h @@ -1629,7 +1653,7 @@ instance : TopologicalSpace (t2Quotient X) := /-- The map from a topological space to its largest T2 quotient. -/ def mk : X → t2Quotient X := Quotient.mk (t2Setoid X) -lemma mk_eq {x y : X} : mk x = mk y ↔ ∀ s : Setoid X, T2Space (Quotient s) → s.Rel x y := +lemma mk_eq {x y : X} : mk x = mk y ↔ ∀ s : Setoid X, T2Space (Quotient s) → s x y := Setoid.quotient_mk_sInf_eq variable (X) @@ -1724,7 +1748,7 @@ theorem eqOn_closure₂' [T2Space Z] {s : Set X} {t : Set Y} {f g : X → Y → (hg₂ : ∀ y, Continuous fun x => g x y) : ∀ x ∈ closure s, ∀ y ∈ closure t, f x y = g x y := suffices closure s ⊆ ⋂ y ∈ closure t, { x | f x y = g x y } by simpa only [subset_def, mem_iInter] (closure_minimal fun x hx => mem_iInter₂.2 <| Set.EqOn.closure (h x hx) (hf₁ _) (hg₁ _)) <| - isClosed_biInter fun y _ => isClosed_eq (hf₂ _) (hg₂ _) + isClosed_biInter fun _ _ => isClosed_eq (hf₂ _) (hg₂ _) theorem eqOn_closure₂ [T2Space Z] {s : Set X} {t : Set Y} {f g : X → Y → Z} (h : ∀ x ∈ s, ∀ y ∈ t, f x y = g x y) (hf : Continuous (uncurry f)) @@ -1751,9 +1775,12 @@ theorem Function.LeftInverse.isClosed_range [T2Space X] {f : X → Y} {g : Y → @[deprecated (since := "2024-03-17")] alias Function.LeftInverse.closed_range := Function.LeftInverse.isClosed_range -theorem Function.LeftInverse.closedEmbedding [T2Space X] {f : X → Y} {g : Y → X} - (h : Function.LeftInverse f g) (hf : Continuous f) (hg : Continuous g) : ClosedEmbedding g := - ⟨h.embedding hf hg, h.isClosed_range hf hg⟩ +theorem Function.LeftInverse.isClosedEmbedding [T2Space X] {f : X → Y} {g : Y → X} + (h : Function.LeftInverse f g) (hf : Continuous f) (hg : Continuous g) : IsClosedEmbedding g := + ⟨.of_leftInverse h hf hg, h.isClosed_range hf hg⟩ + +@[deprecated (since := "2024-10-20")] +alias Function.LeftInverse.closedEmbedding := Function.LeftInverse.isClosedEmbedding theorem SeparatedNhds.of_isCompact_isCompact [T2Space X] {s t : Set X} (hs : IsCompact s) (ht : IsCompact t) (hst : Disjoint s t) : SeparatedNhds s t := by @@ -1849,14 +1876,20 @@ protected theorem Continuous.isClosedMap [CompactSpace X] [T2Space Y] {f : X → (h : Continuous f) : IsClosedMap f := fun _s hs => (hs.isCompact.image h).isClosed /-- A continuous injective map from a compact space to a Hausdorff space is a closed embedding. -/ -theorem Continuous.closedEmbedding [CompactSpace X] [T2Space Y] {f : X → Y} (h : Continuous f) - (hf : Function.Injective f) : ClosedEmbedding f := - closedEmbedding_of_continuous_injective_closed h hf h.isClosedMap +theorem Continuous.isClosedEmbedding [CompactSpace X] [T2Space Y] {f : X → Y} (h : Continuous f) + (hf : Function.Injective f) : IsClosedEmbedding f := + .of_continuous_injective_isClosedMap h hf h.isClosedMap + +@[deprecated (since := "2024-10-20")] +alias Continuous.closedEmbedding := Continuous.isClosedEmbedding /-- A continuous surjective map from a compact space to a Hausdorff space is a quotient map. -/ -theorem QuotientMap.of_surjective_continuous [CompactSpace X] [T2Space Y] {f : X → Y} - (hsurj : Surjective f) (hcont : Continuous f) : QuotientMap f := - hcont.isClosedMap.to_quotientMap hcont hsurj +theorem IsQuotientMap.of_surjective_continuous [CompactSpace X] [T2Space Y] {f : X → Y} + (hsurj : Surjective f) (hcont : Continuous f) : IsQuotientMap f := + hcont.isClosedMap.isQuotientMap hcont hsurj + +@[deprecated (since := "2024-10-22")] +alias QuotientMap.of_surjective_continuous := IsQuotientMap.of_surjective_continuous theorem isPreirreducible_iff_subsingleton [T2Space X] {S : Set X} : IsPreirreducible S ↔ S.Subsingleton := by @@ -1879,6 +1912,10 @@ theorem not_preirreducible_nontrivial_t2 (X) [TopologicalSpace X] [Preirreducibl [Nontrivial X] [T2Space X] : False := (PreirreducibleSpace.isPreirreducible_univ (X := X)).subsingleton.not_nontrivial nontrivial_univ +theorem t2Space_antitone {X : Type*} : Antitone (@T2Space X) := + fun inst₁ inst₂ h_top h_t2 ↦ @T2Space.of_injective_continuous _ _ inst₁ inst₂ + h_t2 _ Function.injective_id <| continuous_id_of_le h_top + end Separation section RegularSpace @@ -2014,15 +2051,17 @@ theorem TopologicalSpace.IsTopologicalBasis.exists_closure_subset {B : Set (Set ∃ t ∈ B, x ∈ t ∧ closure t ⊆ s := by simpa only [exists_prop, and_assoc] using hB.nhds_hasBasis.nhds_closure.mem_iff.mp h -protected theorem Inducing.regularSpace [TopologicalSpace Y] {f : Y → X} (hf : Inducing f) : +protected theorem IsInducing.regularSpace [TopologicalSpace Y] {f : Y → X} (hf : IsInducing f) : RegularSpace Y := .of_hasBasis (fun b => by rw [hf.nhds_eq_comap b]; exact (closed_nhds_basis _).comap _) fun b s hs => by exact hs.2.preimage hf.continuous +@[deprecated (since := "2024-10-28")] alias Inducing.regularSpace := IsInducing.regularSpace + theorem regularSpace_induced (f : Y → X) : @RegularSpace Y (induced f ‹_›) := letI := induced f ‹_› - (inducing_induced f).regularSpace + (IsInducing.induced f).regularSpace theorem regularSpace_sInf {X} {T : Set (TopologicalSpace X)} (h : ∀ t ∈ T, @RegularSpace X t) : @RegularSpace X (sInf T) := by @@ -2046,7 +2085,7 @@ theorem RegularSpace.inf {X} {t₁ t₂ : TopologicalSpace X} (h₁ : @RegularSp exact regularSpace_iInf (Bool.forall_bool.2 ⟨h₂, h₁⟩) instance {p : X → Prop} : RegularSpace (Subtype p) := - embedding_subtype_val.toInducing.regularSpace + IsEmbedding.subtypeVal.isInducing.regularSpace instance [TopologicalSpace Y] [RegularSpace Y] : RegularSpace (X × Y) := (regularSpace_induced (@Prod.fst X Y)).inf (regularSpace_induced (@Prod.snd X Y)) @@ -2122,11 +2161,6 @@ theorem exists_open_between_and_isCompact_closure [LocallyCompactSpace X] [Regul refine ⟨interior L, isOpen_interior, KL, A.trans LU, ?_⟩ exact L_compact.closure_of_subset interior_subset -@[deprecated WeaklyLocallyCompactSpace.locallyCompactSpace (since := "2023-09-03")] -theorem locally_compact_of_compact [T2Space X] [CompactSpace X] : - LocallyCompactSpace X := - inferInstance - end LocallyCompactRegularSpace section T25 @@ -2166,12 +2200,15 @@ theorem T25Space.of_injective_continuous [TopologicalSpace Y] [T25Space Y] {f : t2_5 x y hne := (tendsto_lift'_closure_nhds hcont x).disjoint (t2_5 <| hinj.ne hne) (tendsto_lift'_closure_nhds hcont y) -theorem Embedding.t25Space [TopologicalSpace Y] [T25Space Y] {f : X → Y} (hf : Embedding f) : - T25Space X := +theorem IsEmbedding.t25Space [TopologicalSpace Y] [T25Space Y] {f : X → Y} + (hf : IsEmbedding f) : T25Space X := .of_injective_continuous hf.inj hf.continuous +@[deprecated (since := "2024-10-26")] +alias Embedding.t25Space := IsEmbedding.t25Space + instance Subtype.instT25Space [T25Space X] {p : X → Prop} : T25Space {x // p x} := - embedding_subtype_val.t25Space + IsEmbedding.subtypeVal.t25Space end T25 @@ -2195,16 +2232,19 @@ instance (priority := 100) T3Space.t25Space [T3Space X] : T25Space X := by simp only [← disjoint_nhds_nhdsSet, nhdsSet_singleton] at this exact this.elim id fun h => h.symm -protected theorem Embedding.t3Space [TopologicalSpace Y] [T3Space Y] {f : X → Y} - (hf : Embedding f) : T3Space X := +protected theorem IsEmbedding.t3Space [TopologicalSpace Y] [T3Space Y] {f : X → Y} + (hf : IsEmbedding f) : T3Space X := { toT0Space := hf.t0Space - toRegularSpace := hf.toInducing.regularSpace } + toRegularSpace := hf.isInducing.regularSpace } + +@[deprecated (since := "2024-10-26")] +alias Embedding.t3Space := IsEmbedding.t3Space instance Subtype.t3Space [T3Space X] {p : X → Prop} : T3Space (Subtype p) := - embedding_subtype_val.t3Space + IsEmbedding.subtypeVal.t3Space instance ULift.instT3Space [T3Space X] : T3Space (ULift X) := - embedding_uLift_down.t3Space + IsEmbedding.uliftDown.t3Space instance [TopologicalSpace Y] [T3Space X] [T3Space Y] : T3Space (X × Y) := ⟨⟩ @@ -2259,14 +2299,17 @@ theorem normal_exists_closure_subset [NormalSpace X] {s t : Set X} (hs : IsClose exact fun x hxs hxt => hs't'.le_bot ⟨hxs, hxt⟩ /-- If the codomain of a closed embedding is a normal space, then so is the domain. -/ -protected theorem ClosedEmbedding.normalSpace [TopologicalSpace Y] [NormalSpace Y] {f : X → Y} - (hf : ClosedEmbedding f) : NormalSpace X where +protected theorem IsClosedEmbedding.normalSpace [TopologicalSpace Y] [NormalSpace Y] {f : X → Y} + (hf : IsClosedEmbedding f) : NormalSpace X where normal s t hs ht hst := by have H : SeparatedNhds (f '' s) (f '' t) := NormalSpace.normal (f '' s) (f '' t) (hf.isClosedMap s hs) (hf.isClosedMap t ht) (disjoint_image_of_injective hf.inj hst) exact (H.preimage hf.continuous).mono (subset_preimage_image _ _) (subset_preimage_image _ _) +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.normalSpace := IsClosedEmbedding.normalSpace + instance (priority := 100) NormalSpace.of_compactSpace_r1Space [CompactSpace X] [R1Space X] : NormalSpace X where normal _s _t hs ht := .of_isCompact_isCompact_isClosed hs.isCompact ht.isCompact ht @@ -2304,13 +2347,16 @@ theorem T4Space.of_compactSpace_t2Space [CompactSpace X] [T2Space X] : T4Space X := inferInstance /-- If the codomain of a closed embedding is a T₄ space, then so is the domain. -/ -protected theorem ClosedEmbedding.t4Space [TopologicalSpace Y] [T4Space Y] {f : X → Y} - (hf : ClosedEmbedding f) : T4Space X where - toT1Space := hf.toEmbedding.t1Space +protected theorem IsClosedEmbedding.t4Space [TopologicalSpace Y] [T4Space Y] {f : X → Y} + (hf : IsClosedEmbedding f) : T4Space X where + toT1Space := hf.isEmbedding.t1Space toNormalSpace := hf.normalSpace +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.t4Space := IsClosedEmbedding.t4Space + instance ULift.instT4Space [T4Space X] : T4Space (ULift X) := - ULift.closedEmbedding_down.t4Space + ULift.isClosedEmbedding_down.t4Space namespace SeparationQuotient @@ -2347,34 +2393,40 @@ instance (priority := 100) CompletelyNormalSpace.toNormalSpace normal s t hs ht hd := separatedNhds_iff_disjoint.2 <| completely_normal (by rwa [hs.closure_eq]) (by rwa [ht.closure_eq]) -theorem Embedding.completelyNormalSpace [TopologicalSpace Y] [CompletelyNormalSpace Y] {e : X → Y} - (he : Embedding e) : CompletelyNormalSpace X := by +theorem IsEmbedding.completelyNormalSpace [TopologicalSpace Y] [CompletelyNormalSpace Y] + {e : X → Y} (he : IsEmbedding e) : CompletelyNormalSpace X := by refine ⟨fun s t hd₁ hd₂ => ?_⟩ - simp only [he.toInducing.nhdsSet_eq_comap] + simp only [he.isInducing.nhdsSet_eq_comap] refine disjoint_comap (completely_normal ?_ ?_) · rwa [← subset_compl_iff_disjoint_left, image_subset_iff, preimage_compl, ← he.closure_eq_preimage_closure_image, subset_compl_iff_disjoint_left] · rwa [← subset_compl_iff_disjoint_right, image_subset_iff, preimage_compl, ← he.closure_eq_preimage_closure_image, subset_compl_iff_disjoint_right] +@[deprecated (since := "2024-10-26")] +alias Embedding.completelyNormalSpace := IsEmbedding.completelyNormalSpace + /-- A subspace of a completely normal space is a completely normal space. -/ instance [CompletelyNormalSpace X] {p : X → Prop} : CompletelyNormalSpace { x // p x } := - embedding_subtype_val.completelyNormalSpace + IsEmbedding.subtypeVal.completelyNormalSpace instance ULift.instCompletelyNormalSpace [CompletelyNormalSpace X] : CompletelyNormalSpace (ULift X) := - embedding_uLift_down.completelyNormalSpace + IsEmbedding.uliftDown.completelyNormalSpace /-- A T₅ space is a completely normal T₁ space. -/ class T5Space (X : Type u) [TopologicalSpace X] extends T1Space X, CompletelyNormalSpace X : Prop -theorem Embedding.t5Space [TopologicalSpace Y] [T5Space Y] {e : X → Y} (he : Embedding e) : - T5Space X where +theorem IsEmbedding.t5Space [TopologicalSpace Y] [T5Space Y] {e : X → Y} + (he : IsEmbedding e) : T5Space X where __ := he.t1Space completely_normal := by - have := Embedding.completelyNormalSpace he + have := he.completelyNormalSpace exact completely_normal +@[deprecated (since := "2024-10-26")] +alias Embedding.t5Space := IsEmbedding.t5Space + -- see Note [lower instance priority] /-- A `T₅` space is a `T₄` space. -/ instance (priority := 100) T5Space.toT4Space [T5Space X] : T4Space X where @@ -2382,10 +2434,10 @@ instance (priority := 100) T5Space.toT4Space [T5Space X] : T4Space X where /-- A subspace of a T₅ space is a T₅ space. -/ instance [T5Space X] {p : X → Prop} : T5Space { x // p x } := - embedding_subtype_val.t5Space + IsEmbedding.subtypeVal.t5Space instance ULift.instT5Space [T5Space X] : T5Space (ULift X) := - embedding_uLift_down.t5Space + IsEmbedding.uliftDown.t5Space open SeparationQuotient @@ -2400,62 +2452,6 @@ instance [CompletelyNormalSpace X] [R0Space X] : T5Space (SeparationQuotient X) end CompletelyNormal -section PerfectlyNormal - -/-- A topological space `X` is a *perfectly normal space* provided it is normal and -closed sets are Gδ. -/ -class PerfectlyNormalSpace (X : Type u) [TopologicalSpace X] extends NormalSpace X : Prop where - closed_gdelta : ∀ ⦃h : Set X⦄, IsClosed h → IsGδ h - -/-- Lemma that allows the easy conclusion that perfectly normal spaces are completely normal. -/ -theorem Disjoint.hasSeparatingCover_closed_gdelta_right {s t : Set X} [NormalSpace X] - (st_dis : Disjoint s t) (t_cl : IsClosed t) (t_gd : IsGδ t) : HasSeparatingCover s t := by - obtain ⟨T, T_open, T_count, T_int⟩ := t_gd - rcases T.eq_empty_or_nonempty with rfl | T_nonempty - · rw [T_int, sInter_empty] at st_dis - rw [(s.disjoint_univ).mp st_dis] - exact t.hasSeparatingCover_empty_left - obtain ⟨g, g_surj⟩ := T_count.exists_surjective T_nonempty - choose g' g'_open clt_sub_g' clg'_sub_g using fun n ↦ by - apply normal_exists_closure_subset t_cl (T_open (g n).1 (g n).2) - rw [T_int] - exact sInter_subset_of_mem (g n).2 - have clg'_int : t = ⋂ i, closure (g' i) := by - apply (subset_iInter fun n ↦ (clt_sub_g' n).trans subset_closure).antisymm - rw [T_int] - refine subset_sInter fun t tinT ↦ ?_ - obtain ⟨n, gn⟩ := g_surj ⟨t, tinT⟩ - refine iInter_subset_of_subset n <| (clg'_sub_g n).trans ?_ - rw [gn] - use fun n ↦ (closure (g' n))ᶜ - constructor - · rw [← compl_iInter, subset_compl_comm, ← clg'_int] - exact st_dis.subset_compl_left - · refine fun n ↦ ⟨isOpen_compl_iff.mpr isClosed_closure, ?_⟩ - simp only [closure_compl, disjoint_compl_left_iff_subset] - rw [← closure_eq_iff_isClosed.mpr t_cl] at clt_sub_g' - exact subset_closure.trans <| (clt_sub_g' n).trans <| (g'_open n).subset_interior_closure - -instance (priority := 100) PerfectlyNormalSpace.toCompletelyNormalSpace - [PerfectlyNormalSpace X] : CompletelyNormalSpace X where - completely_normal _ _ hd₁ hd₂ := separatedNhds_iff_disjoint.mp <| - hasSeparatingCovers_iff_separatedNhds.mp - ⟨(hd₂.hasSeparatingCover_closed_gdelta_right isClosed_closure <| - closed_gdelta isClosed_closure).mono (fun ⦃_⦄ a ↦ a) subset_closure, - ((Disjoint.symm hd₁).hasSeparatingCover_closed_gdelta_right isClosed_closure <| - closed_gdelta isClosed_closure).mono (fun ⦃_⦄ a ↦ a) subset_closure⟩ - -/-- A T₆ space is a perfectly normal T₁ space. -/ -class T6Space (X : Type u) [TopologicalSpace X] extends T1Space X, PerfectlyNormalSpace X : Prop - --- see Note [lower instance priority] -/-- A `T₆` space is a `T₅` space. -/ -instance (priority := 100) T6Space.toT5Space [T6Space X] : T5Space X where - -- follows from type-class inference - -end PerfectlyNormal - - /-- In a compact T₂ space, the connected component of a point equals the intersection of all its clopen neighbourhoods. -/ theorem connectedComponent_eq_iInter_isClopen [T2Space X] [CompactSpace X] (x : X) : @@ -2560,7 +2556,7 @@ theorem nhds_basis_clopen (x : X) : (𝓝 x).HasBasis (fun s : Set X => x ∈ s rintro ⟨s, hs, hxs⟩ ⟨t, ht, hxt⟩ exact ⟨⟨s ∩ t, hs.inter ht, ⟨hxs, hxt⟩⟩, inter_subset_left, inter_subset_right⟩ have h_nhd : ∀ y ∈ ⋂ s : N, s.val, U ∈ 𝓝 y := fun y y_in => by - erw [hx, mem_singleton_iff] at y_in + rw [hx, mem_singleton_iff] at y_in rwa [y_in] exact exists_subset_nhds_of_compactSpace hdir hNcl h_nhd · rintro ⟨V, ⟨hxV, -, V_op⟩, hUV : V ⊆ U⟩ @@ -2598,11 +2594,11 @@ theorem loc_compact_Haus_tot_disc_of_zero_dim [TotallyDisconnectedSpace H] : haveI : CompactSpace s := isCompact_iff_compactSpace.1 comp obtain ⟨V : Set s, VisClopen, Vx, V_sub⟩ := compact_exists_isClopen_in_isOpen u_open_in_s xs have VisClopen' : IsClopen (((↑) : s → H) '' V) := by - refine ⟨comp.isClosed.closedEmbedding_subtype_val.closed_iff_image_closed.1 VisClopen.1, ?_⟩ + refine ⟨comp.isClosed.isClosedEmbedding_subtypeVal.closed_iff_image_closed.1 VisClopen.1, ?_⟩ let v : Set u := ((↑) : u → s) ⁻¹' V have : ((↑) : u → H) = ((↑) : s → H) ∘ ((↑) : u → s) := rfl - have f0 : Embedding ((↑) : u → H) := embedding_subtype_val.comp embedding_subtype_val - have f1 : OpenEmbedding ((↑) : u → H) := by + have f0 : IsEmbedding ((↑) : u → H) := IsEmbedding.subtypeVal.comp IsEmbedding.subtypeVal + have f1 : IsOpenEmbedding ((↑) : u → H) := by refine ⟨f0, ?_⟩ · have : Set.range ((↑) : u → H) = interior s := by rw [this, Set.range_comp, Subtype.range_coe, Subtype.image_preimage_coe] @@ -2648,8 +2644,8 @@ instance ConnectedComponents.t2 [T2Space X] [CompactSpace X] : T2Space (Connecte have hU : IsClopen U := isClopen_biInter_finset fun i _ => i.2.1 exact ⟨U, (↑) '' U, hU, ha, subset_iInter₂ fun s _ => s.2.1.connectedComponent_subset s.2.2, (connectedComponents_preimage_image U).symm ▸ hU.biUnion_connectedComponent_eq⟩ - rw [ConnectedComponents.quotientMap_coe.isClopen_preimage] at hU + rw [ConnectedComponents.isQuotientMap_coe.isClopen_preimage] at hU refine ⟨Vᶜ, V, hU.compl.isOpen, hU.isOpen, ?_, hb mem_connectedComponent, disjoint_compl_left⟩ exact fun h => flip Set.Nonempty.ne_empty ha ⟨a, mem_connectedComponent, h⟩ -set_option linter.style.longFile 2800 +set_option linter.style.longFile 2700 diff --git a/Mathlib/Topology/Separation/GDelta.lean b/Mathlib/Topology/Separation/GDelta.lean new file mode 100644 index 0000000000000..e7cf8efc00758 --- /dev/null +++ b/Mathlib/Topology/Separation/GDelta.lean @@ -0,0 +1,125 @@ +/- +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.Topology.Compactness.Lindelof +import Mathlib.Topology.Compactness.SigmaCompact +import Mathlib.Topology.Connected.TotallyDisconnected +import Mathlib.Topology.Inseparable +import Mathlib.Topology.Separation.Basic +import Mathlib.Topology.GDelta.Basic + +/-! +# Separation properties of topological spaces. + +## Main definitions + +* `PerfectlyNormalSpace`: A perfectly normal space is a normal space such that + closed sets are Gδ. +* `T6Space`: A T₆ space is a Perfectly normal T₁ space. T₆ implies T₅. + +Note that `mathlib` adopts the modern convention that `m ≤ n` if and only if `T_m → T_n`, but +occasionally the literature swaps definitions for e.g. T₃ and regular. + +### TODO + +* Use `hasSeparatingCovers_iff_separatedNhds` to prove that perfectly normal spaces + are completely normal. + +-/ + +open Function Set Filter Topology TopologicalSpace + +universe u v + +variable {X : Type*} {Y : Type*} [TopologicalSpace X] + +section Separation + +theorem IsGδ.compl_singleton (x : X) [T1Space X] : IsGδ ({x}ᶜ : Set X) := + isOpen_compl_singleton.isGδ + +@[deprecated (since := "2024-02-15")] alias isGδ_compl_singleton := IsGδ.compl_singleton + +theorem Set.Countable.isGδ_compl {s : Set X} [T1Space X] (hs : s.Countable) : IsGδ sᶜ := by + rw [← biUnion_of_singleton s, compl_iUnion₂] + exact .biInter hs fun x _ => .compl_singleton x + +theorem Set.Finite.isGδ_compl {s : Set X} [T1Space X] (hs : s.Finite) : IsGδ sᶜ := + hs.countable.isGδ_compl + +theorem Set.Subsingleton.isGδ_compl {s : Set X} [T1Space X] (hs : s.Subsingleton) : IsGδ sᶜ := + hs.finite.isGδ_compl + +theorem Finset.isGδ_compl [T1Space X] (s : Finset X) : IsGδ (sᶜ : Set X) := + s.finite_toSet.isGδ_compl + +protected theorem IsGδ.singleton [FirstCountableTopology X] [T1Space X] (x : X) : + IsGδ ({x} : Set X) := by + rcases (nhds_basis_opens x).exists_antitone_subbasis with ⟨U, hU, h_basis⟩ + rw [← biInter_basis_nhds h_basis.toHasBasis] + exact .biInter (to_countable _) fun n _ => (hU n).2.isGδ + +@[deprecated (since := "2024-02-15")] alias isGδ_singleton := IsGδ.singleton + +theorem Set.Finite.isGδ [FirstCountableTopology X] {s : Set X} [T1Space X] (hs : s.Finite) : + IsGδ s := + Finite.induction_on hs .empty fun _ _ ↦ .union (.singleton _) + + +section PerfectlyNormal + +/-- A topological space `X` is a *perfectly normal space* provided it is normal and +closed sets are Gδ. -/ +class PerfectlyNormalSpace (X : Type u) [TopologicalSpace X] extends NormalSpace X : Prop where + closed_gdelta : ∀ ⦃h : Set X⦄, IsClosed h → IsGδ h + +/-- Lemma that allows the easy conclusion that perfectly normal spaces are completely normal. -/ +theorem Disjoint.hasSeparatingCover_closed_gdelta_right {s t : Set X} [NormalSpace X] + (st_dis : Disjoint s t) (t_cl : IsClosed t) (t_gd : IsGδ t) : HasSeparatingCover s t := by + obtain ⟨T, T_open, T_count, T_int⟩ := t_gd + rcases T.eq_empty_or_nonempty with rfl | T_nonempty + · rw [T_int, sInter_empty] at st_dis + rw [(s.disjoint_univ).mp st_dis] + exact t.hasSeparatingCover_empty_left + obtain ⟨g, g_surj⟩ := T_count.exists_surjective T_nonempty + choose g' g'_open clt_sub_g' clg'_sub_g using fun n ↦ by + apply normal_exists_closure_subset t_cl (T_open (g n).1 (g n).2) + rw [T_int] + exact sInter_subset_of_mem (g n).2 + have clg'_int : t = ⋂ i, closure (g' i) := by + apply (subset_iInter fun n ↦ (clt_sub_g' n).trans subset_closure).antisymm + rw [T_int] + refine subset_sInter fun t tinT ↦ ?_ + obtain ⟨n, gn⟩ := g_surj ⟨t, tinT⟩ + refine iInter_subset_of_subset n <| (clg'_sub_g n).trans ?_ + rw [gn] + use fun n ↦ (closure (g' n))ᶜ + constructor + · rw [← compl_iInter, subset_compl_comm, ← clg'_int] + exact st_dis.subset_compl_left + · refine fun n ↦ ⟨isOpen_compl_iff.mpr isClosed_closure, ?_⟩ + simp only [closure_compl, disjoint_compl_left_iff_subset] + rw [← closure_eq_iff_isClosed.mpr t_cl] at clt_sub_g' + exact subset_closure.trans <| (clt_sub_g' n).trans <| (g'_open n).subset_interior_closure + +instance (priority := 100) PerfectlyNormalSpace.toCompletelyNormalSpace + [PerfectlyNormalSpace X] : CompletelyNormalSpace X where + completely_normal _ _ hd₁ hd₂ := separatedNhds_iff_disjoint.mp <| + hasSeparatingCovers_iff_separatedNhds.mp + ⟨(hd₂.hasSeparatingCover_closed_gdelta_right isClosed_closure <| + closed_gdelta isClosed_closure).mono (fun ⦃_⦄ a ↦ a) subset_closure, + ((Disjoint.symm hd₁).hasSeparatingCover_closed_gdelta_right isClosed_closure <| + closed_gdelta isClosed_closure).mono (fun ⦃_⦄ a ↦ a) subset_closure⟩ + +/-- A T₆ space is a perfectly normal T₁ space. -/ +class T6Space (X : Type u) [TopologicalSpace X] extends T1Space X, PerfectlyNormalSpace X : Prop + +-- see Note [lower instance priority] +/-- A `T₆` space is a `T₅` space. -/ +instance (priority := 100) T6Space.toT5Space [T6Space X] : T5Space X where + -- follows from type-class inference +end PerfectlyNormal + +end Separation diff --git a/Mathlib/Topology/Separation/NotNormal.lean b/Mathlib/Topology/Separation/NotNormal.lean index a022ac86d5359..348f0ea4324cb 100644 --- a/Mathlib/Topology/Separation/NotNormal.lean +++ b/Mathlib/Topology/Separation/NotNormal.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Data.Real.Cardinality -import Mathlib.Topology.Separation import Mathlib.Topology.TietzeExtension /-! # Not normal topological spaces diff --git a/Mathlib/Topology/Sequences.lean b/Mathlib/Topology/Sequences.lean index 2e0e2de87c365..06d32c20de64c 100644 --- a/Mathlib/Topology/Sequences.lean +++ b/Mathlib/Topology/Sequences.lean @@ -151,8 +151,8 @@ instance (priority := 100) FrechetUrysohnSpace.to_sequentialSpace [FrechetUrysoh SequentialSpace X := ⟨fun s hs => by rw [← closure_eq_iff_isClosed, ← seqClosure_eq_closure, hs.seqClosure_eq]⟩ -theorem Inducing.frechetUrysohnSpace [FrechetUrysohnSpace Y] {f : X → Y} (hf : Inducing f) : - FrechetUrysohnSpace X := by +theorem IsInducing.frechetUrysohnSpace [FrechetUrysohnSpace Y] {f : X → Y} + (hf : IsInducing f) : FrechetUrysohnSpace X := by refine ⟨fun s x hx ↦ ?_⟩ rw [hf.closure_eq_preimage_closure_image, mem_preimage, mem_closure_iff_seq_limit] at hx rcases hx with ⟨u, hus, hu⟩ @@ -160,10 +160,13 @@ theorem Inducing.frechetUrysohnSpace [FrechetUrysohnSpace Y] {f : X → Y} (hf : refine ⟨v, hv, ?_⟩ simpa only [hf.tendsto_nhds_iff, Function.comp_def, hvu] +@[deprecated (since := "2024-10-28")] +alias Inducing.frechetUrysohnSpace := IsInducing.frechetUrysohnSpace + /-- Subtype of a Fréchet-Urysohn space is a Fréchet-Urysohn space. -/ instance Subtype.instFrechetUrysohnSpace [FrechetUrysohnSpace X] {p : X → Prop} : FrechetUrysohnSpace (Subtype p) := - inducing_subtype_val.frechetUrysohnSpace + IsInducing.subtypeVal.frechetUrysohnSpace /-- In a sequential space, a set is closed iff it's sequentially closed. -/ theorem isSeqClosed_iff_isClosed [SequentialSpace X] {M : Set X} : IsSeqClosed M ↔ IsClosed M := @@ -192,7 +195,7 @@ theorem continuous_iff_seqContinuous [SequentialSpace X] {f : X → Y} : theorem SequentialSpace.coinduced [SequentialSpace X] {Y} (f : X → Y) : @SequentialSpace Y (.coinduced f ‹_›) := letI : TopologicalSpace Y := .coinduced f ‹_› - ⟨fun s hs ↦ isClosed_coinduced.2 (hs.preimage continuous_coinduced_rng.seqContinuous).isClosed⟩ + ⟨fun _ hs ↦ isClosed_coinduced.2 (hs.preimage continuous_coinduced_rng.seqContinuous).isClosed⟩ protected theorem SequentialSpace.iSup {X} {ι : Sort*} {t : ι → TopologicalSpace X} (h : ∀ i, @SequentialSpace X (t i)) : @SequentialSpace X (⨆ i, t i) := by @@ -207,14 +210,17 @@ protected theorem SequentialSpace.sup {X} {t₁ t₂ : TopologicalSpace X} rw [sup_eq_iSup] exact .iSup <| Bool.forall_bool.2 ⟨h₂, h₁⟩ -theorem QuotientMap.sequentialSpace [SequentialSpace X] {f : X → Y} (hf : QuotientMap f) : +theorem IsQuotientMap.sequentialSpace [SequentialSpace X] {f : X → Y} (hf : IsQuotientMap f) : SequentialSpace Y := hf.2.symm ▸ .coinduced f +@[deprecated (since := "2024-10-22")] +alias QuotientMap.sequentialSpace := IsQuotientMap.sequentialSpace + /-- The quotient of a sequential space is a sequential space. -/ instance Quotient.instSequentialSpace [SequentialSpace X] {s : Setoid X} : SequentialSpace (Quotient s) := - quotientMap_quot_mk.sequentialSpace + isQuotientMap_quot_mk.sequentialSpace /-- The sum (disjoint union) of two sequential spaces is a sequential space. -/ instance Sum.instSequentialSpace [SequentialSpace X] [SequentialSpace Y] : diff --git a/Mathlib/Topology/Sets/Opens.lean b/Mathlib/Topology/Sets/Opens.lean index cf7ecc4c6353c..8d8d697d4c8f2 100644 --- a/Mathlib/Topology/Sets/Opens.lean +++ b/Mathlib/Topology/Sets/Opens.lean @@ -243,15 +243,21 @@ def frameMinimalAxioms : Frame.MinimalAxioms (Opens α) where instance instFrame : Frame (Opens α) := .ofMinimalAxioms frameMinimalAxioms -theorem openEmbedding' (U : Opens α) : OpenEmbedding (Subtype.val : U → α) := - U.isOpen.openEmbedding_subtype_val +theorem isOpenEmbedding' (U : Opens α) : IsOpenEmbedding (Subtype.val : U → α) := + U.isOpen.isOpenEmbedding_subtypeVal -theorem openEmbedding_of_le {U V : Opens α} (i : U ≤ V) : - OpenEmbedding (Set.inclusion <| SetLike.coe_subset_coe.2 i) := - { toEmbedding := embedding_inclusion i - isOpen_range := by - rw [Set.range_inclusion i] - exact U.isOpen.preimage continuous_subtype_val } +@[deprecated (since := "2024-10-18")] +alias openEmbedding' := isOpenEmbedding' + +theorem isOpenEmbedding_of_le {U V : Opens α} (i : U ≤ V) : + IsOpenEmbedding (Set.inclusion <| SetLike.coe_subset_coe.2 i) where + toIsEmbedding := .inclusion i + isOpen_range := by + rw [Set.range_inclusion i] + exact U.isOpen.preimage continuous_subtype_val + +@[deprecated (since := "2024-10-18")] +alias openEmbedding_of_le := isOpenEmbedding_of_le theorem not_nonempty_iff_eq_bot (U : Opens α) : ¬Set.Nonempty (U : Set α) ↔ U = ⊥ := by rw [← coe_inj, coe_bot, ← Set.not_nonempty_iff_eq_empty] @@ -343,7 +349,7 @@ theorem isCompactElement_iff (s : Opens α) : def comap (f : C(α, β)) : FrameHom (Opens β) (Opens α) where toFun s := ⟨f ⁻¹' s, s.2.preimage f.continuous⟩ map_sSup' s := ext <| by simp only [coe_sSup, preimage_iUnion, biUnion_image, coe_mk] - map_inf' a b := rfl + map_inf' _ _ := rfl map_top' := rfl @[simp] @@ -379,10 +385,10 @@ theorem comap_injective [T0Space β] : Injective (comap : C(α, β) → FrameHom /-- A homeomorphism induces an order-preserving equivalence on open sets, by taking comaps. -/ @[simps (config := .asFn) apply] def _root_.Homeomorph.opensCongr (f : α ≃ₜ β) : Opens α ≃o Opens β where - toFun := Opens.comap f.symm.toContinuousMap - invFun := Opens.comap f.toContinuousMap - left_inv := fun U => ext <| f.toEquiv.preimage_symm_preimage _ - right_inv := fun U => ext <| f.toEquiv.symm_preimage_preimage _ + toFun := Opens.comap (f.symm : C(β, α)) + invFun := Opens.comap (f : C(α, β)) + left_inv _ := ext <| f.toEquiv.preimage_symm_preimage _ + right_inv _ := ext <| f.toEquiv.symm_preimage_preimage _ map_rel_iff' := by simp only [← SetLike.coe_subset_coe]; exact f.symm.surjective.preimage_subset_preimage_iff diff --git a/Mathlib/Topology/Sets/Order.lean b/Mathlib/Topology/Sets/Order.lean index f787206f3f3ad..1a139b07f9633 100644 --- a/Mathlib/Topology/Sets/Order.lean +++ b/Mathlib/Topology/Sets/Order.lean @@ -15,7 +15,7 @@ In this file we define the type of clopen upper sets. open Set TopologicalSpace -variable {α β : Type*} [TopologicalSpace α] [LE α] [TopologicalSpace β] [LE β] +variable {α : Type*} [TopologicalSpace α] [LE α] /-! ### Compact open sets -/ diff --git a/Mathlib/Topology/Sheaves/LocalPredicate.lean b/Mathlib/Topology/Sheaves/LocalPredicate.lean index c27257e4a8618..bf6e5eb7f9b01 100644 --- a/Mathlib/Topology/Sheaves/LocalPredicate.lean +++ b/Mathlib/Topology/Sheaves/LocalPredicate.lean @@ -73,7 +73,7 @@ variable (X) @[simps!] def continuousPrelocal (T : TopCat.{v}) : PrelocalPredicate fun _ : X => T where pred {_} f := Continuous f - res {_ _} i _ h := Continuous.comp h (Opens.openEmbedding_of_le i.le).continuous + res {_ _} i _ h := Continuous.comp h (Opens.isOpenEmbedding_of_le i.le).continuous /-- Satisfying the inhabited linter. -/ instance inhabitedPrelocalPredicate (T : TopCat.{v}) : @@ -114,7 +114,7 @@ def continuousLocal (T : TopCat.{v}) : LocalPredicate fun _ : X => T := dsimp at w rw [continuous_iff_continuousAt] at w specialize w ⟨x, m⟩ - simpa using (Opens.openEmbedding_of_le i.le).continuousAt_iff.1 w } + simpa using (Opens.isOpenEmbedding_of_le i.le).continuousAt_iff.1 w } /-- Satisfying the inhabited linter. -/ instance inhabitedLocalPredicate (T : TopCat.{v}) : Inhabited (LocalPredicate fun _ : X => T) := @@ -148,7 +148,7 @@ theorem PrelocalPredicate.sheafifyOf {T : X → Type v} {P : PrelocalPredicate T @[simps!] def subpresheafToTypes (P : PrelocalPredicate T) : Presheaf (Type v) X where obj U := { f : ∀ x : U.unop , T x // P.pred f } - map {U V} i f := ⟨fun x => f.1 (i.unop x), P.res i.unop f.1 f.2⟩ + map {_ _} i f := ⟨fun x => f.1 (i.unop x), P.res i.unop f.1 f.2⟩ namespace subpresheafToTypes @@ -157,7 +157,7 @@ variable (P : PrelocalPredicate T) /-- The natural transformation including the subpresheaf of functions satisfying a local predicate into the presheaf of all functions. -/ -def subtype : subpresheafToTypes P ⟶ presheafToTypes X T where app U f := f.1 +def subtype : subpresheafToTypes P ⟶ presheafToTypes X T where app _ f := f.1 open TopCat.Presheaf @@ -217,11 +217,9 @@ def stalkToFiber (P : LocalPredicate T) (x : X) : (subsheafToTypes P).presheaf.s -- Porting note (#11119): removed `simp` attribute, -- due to left hand side is not in simple normal form. -theorem stalkToFiber_germ (P : LocalPredicate T) (U : Opens X) (x : U) (f) : - stalkToFiber P x ((subsheafToTypes P).presheaf.germ x f) = f.1 x := by - dsimp [Presheaf.germ, stalkToFiber] - cases x - simp +theorem stalkToFiber_germ (P : LocalPredicate T) (U : Opens X) (x : X) (hx : x ∈ U) (f) : + stalkToFiber P x ((subsheafToTypes P).presheaf.germ U x hx f) = f.1 ⟨x, hx⟩ := by + simp [Presheaf.germ, stalkToFiber] /-- The `stalkToFiber` map is surjective at `x` if every point in the fiber `T x` has an allowed section passing through it. @@ -231,8 +229,8 @@ theorem stalkToFiber_surjective (P : LocalPredicate T) (x : X) Function.Surjective (stalkToFiber P x) := fun t => by rcases w t with ⟨U, f, h, rfl⟩ fconstructor - · exact (subsheafToTypes P).presheaf.germ ⟨x, U.2⟩ ⟨f, h⟩ - · exact stalkToFiber_germ _ U.1 ⟨x, U.2⟩ ⟨f, h⟩ + · exact (subsheafToTypes P).presheaf.germ _ x U.2 ⟨f, h⟩ + · exact stalkToFiber_germ P U.1 x U.2 ⟨f, h⟩ /-- The `stalkToFiber` map is injective at `x` if any two allowed sections which agree at `x` agree on some neighborhood of `x`. @@ -247,8 +245,8 @@ theorem stalkToFiber_injective (P : LocalPredicate T) (x : X) -- We promise to provide all the ingredients of the proof later: let Q : ∃ (W : (OpenNhds x)ᵒᵖ) (s : ∀ w : (unop W).1, T w) (hW : P.pred s), - tU = (subsheafToTypes P).presheaf.germ ⟨x, (unop W).2⟩ ⟨s, hW⟩ ∧ - tV = (subsheafToTypes P).presheaf.germ ⟨x, (unop W).2⟩ ⟨s, hW⟩ := + tU = (subsheafToTypes P).presheaf.germ _ x (unop W).2 ⟨s, hW⟩ ∧ + tV = (subsheafToTypes P).presheaf.germ _ x (unop W).2 ⟨s, hW⟩ := ?_ · choose W s hW e using Q exact e.1.trans e.2.symm diff --git a/Mathlib/Topology/Sheaves/LocallySurjective.lean b/Mathlib/Topology/Sheaves/LocallySurjective.lean index 9293f95add655..1e4b5176e114b 100644 --- a/Mathlib/Topology/Sheaves/LocallySurjective.lean +++ b/Mathlib/Topology/Sheaves/LocallySurjective.lean @@ -85,11 +85,11 @@ theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) : -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V. rcases hT.imageSieve_mem t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩ -- Then the germ of s maps to g. - use ℱ.germ ⟨x, hxV⟩ s + use ℱ.germ _ x hxV s -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative -- to lean 3. - convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1 - simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm + convert stalkFunctor_map_germ_apply V x hxV T s using 1 + simpa [h_eq] using (germ_res_apply 𝒢 ι x hxV t).symm · /- human proof: Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point. By surjectivity on stalks, the germ of t is the image of @@ -98,14 +98,14 @@ theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) : we have T(s) |_ W = t |_ W. -/ constructor intro U t x hxU - set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x + set t_x := 𝒢.germ _ x hxU t with ht_x obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x -- rfl : ℱ.germ x s = s_x have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by convert hs_x using 1 symm - convert stalkFunctor_map_germ_apply _ _ _ s + convert stalkFunctor_map_germ_apply _ _ _ _ s obtain ⟨W, hxW, hWV, hWU, h_eq⟩ := key_W refine ⟨W, hWU, ⟨ℱ.map hWV.op s, ?_⟩, hxW⟩ convert h_eq using 1 diff --git a/Mathlib/Topology/Sheaves/Operations.lean b/Mathlib/Topology/Sheaves/Operations.lean index 85cb01ea80e1a..4eec0af579f98 100644 --- a/Mathlib/Topology/Sheaves/Operations.lean +++ b/Mathlib/Topology/Sheaves/Operations.lean @@ -46,7 +46,7 @@ variable {F : X.Presheaf CommRingCat.{w}} (G : F.SubmonoidPresheaf) /-- The localization of a presheaf of `CommRing`s with respect to a `SubmonoidPresheaf`. -/ protected noncomputable def SubmonoidPresheaf.localizationPresheaf : X.Presheaf CommRingCat where obj U := CommRingCat.of <| Localization (G.obj U) - map {U V} i := CommRingCat.ofHom <| IsLocalization.map _ (F.map i) (G.map i) + map {_ _} i := CommRingCat.ofHom <| IsLocalization.map _ (F.map i) (G.map i) map_id U := by simp_rw [F.map_id] ext x @@ -81,14 +81,14 @@ sections whose restriction onto each stalk falls in the given submonoid. -/ @[simps] noncomputable def submonoidPresheafOfStalk (S : ∀ x : X, Submonoid (F.stalk x)) : F.SubmonoidPresheaf where - obj U := ⨅ x : U.unop, Submonoid.comap (F.germ x) (S x) + obj U := ⨅ x : U.unop, Submonoid.comap (F.germ U.unop x.1 x.2) (S x) map {U V} i := by intro s hs simp only [Submonoid.mem_comap, Submonoid.mem_iInf] at hs ⊢ intro x - change (F.map i.unop.op ≫ F.germ x) s ∈ _ + change (F.map i.unop.op ≫ F.germ V.unop x.1 x.2) s ∈ _ rw [F.germ_res] - exact hs ⟨_,_⟩ + exact hs ⟨_, i.unop.le x.2⟩ noncomputable instance : Inhabited F.SubmonoidPresheaf := ⟨F.submonoidPresheafOfStalk fun _ => ⊥⟩ @@ -121,11 +121,9 @@ instance (F : X.Sheaf CommRingCat.{w}) : Mono F.presheaf.toTotalQuotientPresheaf refine IsLocalization.injective (M := m) (S := Localization m) ?_ intro s hs t e apply section_ext F (unop U) - intro x + intro x hx rw [map_zero] - apply Submonoid.mem_iInf.mp hs x - -- Porting note: added `dsimp` to make `rw [← map_mul]` work - dsimp + apply Submonoid.mem_iInf.mp hs ⟨x, hx⟩ rw [← map_mul, e, map_zero] end Presheaf diff --git a/Mathlib/Topology/Sheaves/Presheaf.lean b/Mathlib/Topology/Sheaves/Presheaf.lean index 6b2b727509484..46dcaa719cd3a 100644 --- a/Mathlib/Topology/Sheaves/Presheaf.lean +++ b/Mathlib/Topology/Sheaves/Presheaf.lean @@ -242,9 +242,7 @@ theorem toPushforwardOfIso_app {X Y : TopCat} (H₁ : X ≅ Y) {ℱ : X.Presheaf (toPushforwardOfIso H₁ H₂).app U = ℱ.map (eqToHom (by simp [Opens.map, Set.preimage_preimage])) ≫ H₂.app (op ((Opens.map H₁.inv).obj (unop U))) := by - delta toPushforwardOfIso - simp [-Functor.map_comp, ← Functor.map_comp_assoc] - rfl + simp [toPushforwardOfIso, Adjunction.homEquiv_unit] /-- If `H : X ≅ Y` is a homeomorphism, then given an `H _* ℱ ⟶ 𝒢`, we may obtain an `ℱ ⟶ H ⁻¹ _* 𝒢`. @@ -259,7 +257,7 @@ theorem pushforwardToOfIso_app {X Y : TopCat} (H₁ : X ≅ Y) {ℱ : Y.Presheaf (pushforwardToOfIso H₁ H₂).app U = H₂.app (op ((Opens.map H₁.inv).obj (unop U))) ≫ 𝒢.map (eqToHom (by simp [Opens.map, Set.preimage_preimage])) := by - simp [pushforwardToOfIso, Equivalence.toAdjunction] + simp [pushforwardToOfIso, Equivalence.toAdjunction, Adjunction.homEquiv_counit] end Iso diff --git a/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean b/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean index 6049ed866f9d8..4ce4eaa2a3fd1 100644 --- a/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean +++ b/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean @@ -43,11 +43,11 @@ There is no requirement that the functions are continuous, here. -/ def presheafToTypes (T : X → Type v) : X.Presheaf (Type v) where obj U := ∀ x : U.unop, T x - map {U V} i g := fun x : V.unop => g (i.unop x) + map {_ V} i g := fun x : V.unop => g (i.unop x) map_id U := by ext g rfl - map_comp {U V W} i j := rfl + map_comp {_ _ _} _ _ := rfl @[simp] theorem presheafToTypes_obj {T : X → Type v} {U : (Opens X)ᵒᵖ} : @@ -70,11 +70,11 @@ There is no requirement that the functions are continuous, here. -/ def presheafToType (T : Type v) : X.Presheaf (Type v) where obj U := U.unop → T - map {U V} i g := g ∘ i.unop + map {_ _} i g := g ∘ i.unop map_id U := by ext g rfl - map_comp {U V W} i j := rfl + map_comp {_ _ _} _ _ := rfl @[simp] theorem presheafToType_obj {T : Type v} {U : (Opens X)ᵒᵖ} : @@ -121,7 +121,7 @@ this is a ring homomorphism (with respect to the pointwise ring operations on fu def map (X : TopCat.{u}ᵒᵖ) {R S : TopCommRingCat.{u}} (φ : R ⟶ S) : continuousFunctions X R ⟶ continuousFunctions X S where toFun g := g ≫ (forget₂ TopCommRingCat TopCat).map φ - -- Porting note: `ext` tactic does not work, since Lean can't see through `R ⟶ S` is just + -- Porting note (#11041): `ext` tactic does not work, since Lean can't see through `R ⟶ S` is just -- continuous ring homomorphism map_one' := ContinuousMap.ext fun _ => φ.1.map_one map_zero' := ContinuousMap.ext fun _ => φ.1.map_zero @@ -136,18 +136,18 @@ from `X : TopCat` to `R : TopCommRingCat` form a commutative ring, functorial in def commRingYoneda : TopCommRingCat.{u} ⥤ TopCat.{u}ᵒᵖ ⥤ CommRingCat.{u} where obj R := { obj := fun X => continuousFunctions X R - map := fun {X Y} f => continuousFunctions.pullback f R + map := fun {_ _} f => continuousFunctions.pullback f R map_id := fun X => by ext rfl - map_comp := fun {X Y Z} f g => rfl } - map {R S} φ := + map_comp := fun {_ _ _} _ _ => rfl } + map {_ _} φ := { app := fun X => continuousFunctions.map X φ - naturality := fun X Y f => rfl } + naturality := fun _ _ _ => rfl } map_id X := by ext rfl - map_comp {X Y Z} f g := rfl + map_comp {_ _ _} _ _ := rfl /-- The presheaf (of commutative rings), consisting of functions on an open set `U ⊆ X` with values in some topological commutative ring `T`. diff --git a/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean b/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean index 34b950b76fec8..5103d691a3229 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/EqualizerProducts.lean @@ -263,7 +263,7 @@ def coneEquivInverseObj (c : Limits.Cone (SheafConditionEqualizerProducts.diagra rintro rfl rcases x with (⟨i⟩ | ⟨⟩) <;> rcases y with (⟨⟩ | ⟨j, j⟩) <;> rcases f' with ⟨⟩ · dsimp - erw [F.map_id] + rw [F.map_id] simp · dsimp simp only [Category.id_comp, Category.assoc] @@ -284,7 +284,7 @@ def coneEquivInverseObj (c : Limits.Cone (SheafConditionEqualizerProducts.diagra simp rfl · dsimp - erw [F.map_id] + rw [F.map_id] simp } /-- Implementation of `SheafConditionPairwiseIntersections.coneEquiv`. -/ diff --git a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean index 9677da6bdf32e..890f87cb37276 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean @@ -103,7 +103,7 @@ of open sets below some `U i`. @[simps] def pairwiseToOpensLeCover : Pairwise ι ⥤ OpensLeCover U where obj := pairwiseToOpensLeCoverObj U - map {V W} i := pairwiseToOpensLeCoverMap U i + map {_ _} i := pairwiseToOpensLeCoverMap U i instance (V : OpensLeCover U) : Nonempty (StructuredArrow V (pairwiseToOpensLeCover U)) := ⟨@StructuredArrow.mk _ _ _ _ _ (single V.index) _ V.homToIndex⟩ diff --git a/Mathlib/Topology/Sheaves/SheafCondition/Sites.lean b/Mathlib/Topology/Sheaves/SheafCondition/Sites.lean index 07a4029efeb34..88541de424f6b 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/Sites.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/Sites.lean @@ -136,14 +136,14 @@ theorem coverDense_inducedFunctor {B : ι → Opens X} (h : Opens.IsBasis (Set.r end TopCat.Opens -section OpenEmbedding +section IsOpenEmbedding open TopCat.Presheaf Opposite variable {C : Type u} [Category.{v} C] variable {X Y : TopCat.{w}} {f : X ⟶ Y} {F : Y.Presheaf C} -theorem OpenEmbedding.compatiblePreserving (hf : OpenEmbedding f) : +theorem IsOpenEmbedding.compatiblePreserving (hf : IsOpenEmbedding f) : CompatiblePreserving (Opens.grothendieckTopology Y) hf.isOpenMap.functor := by haveI : Mono f := (TopCat.mono_iff_injective f).mpr hf.inj apply compatiblePreservingOfDownwardsClosed @@ -152,6 +152,9 @@ theorem OpenEmbedding.compatiblePreserving (hf : OpenEmbedding f) : obtain ⟨_, _, rfl⟩ := i.le h exact ⟨_, rfl⟩ +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.compatiblePreserving := IsOpenEmbedding.compatiblePreserving + theorem IsOpenMap.coverPreserving (hf : IsOpenMap f) : CoverPreserving (Opens.grothendieckTopology X) (Opens.grothendieckTopology Y) hf.functor := by constructor @@ -160,18 +163,24 @@ theorem IsOpenMap.coverPreserving (hf : IsOpenMap f) : exact ⟨_, hf.functor.map i, ⟨_, i, 𝟙 _, hV, rfl⟩, Set.mem_image_of_mem f hxV⟩ -lemma OpenEmbedding.functor_isContinuous (h : OpenEmbedding f) : +lemma IsOpenEmbedding.functor_isContinuous (h : IsOpenEmbedding f) : h.isOpenMap.functor.IsContinuous (Opens.grothendieckTopology X) (Opens.grothendieckTopology Y) := by apply Functor.isContinuous_of_coverPreserving · exact h.compatiblePreserving · exact h.isOpenMap.coverPreserving -theorem TopCat.Presheaf.isSheaf_of_openEmbedding (h : OpenEmbedding f) (hF : F.IsSheaf) : +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.functor_isContinuous := IsOpenEmbedding.functor_isContinuous + +theorem TopCat.Presheaf.isSheaf_of_isOpenEmbedding (h : IsOpenEmbedding f) (hF : F.IsSheaf) : IsSheaf (h.isOpenMap.functor.op ⋙ F) := by have := h.functor_isContinuous exact Functor.op_comp_isSheaf _ _ _ ⟨_, hF⟩ +@[deprecated (since := "2024-10-18")] +alias TopCat.Presheaf.isSheaf_of_openEmbedding := TopCat.Presheaf.isSheaf_of_isOpenEmbedding + variable (f) instance : RepresentablyFlat (Opens.map f) := by @@ -203,7 +212,7 @@ instance : (Opens.map f).IsContinuous (Opens.grothendieckTopology Y) · exact compatiblePreserving_opens_map f · exact coverPreserving_opens_map f -end OpenEmbedding +end IsOpenEmbedding namespace TopCat.Sheaf diff --git a/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean b/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean index c4439241d6da5..c3771d10ce996 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean @@ -138,7 +138,7 @@ section attribute [local instance] ConcreteCategory.hasCoeToSort ConcreteCategory.instFunLike variable [HasLimits C] [(forget C).ReflectsIsomorphisms] [PreservesLimits (forget C)] -variable {X : TopCat.{v}} (F : Presheaf C X) {ι : Type v} (U : ι → Opens X) +variable {X : TopCat.{v}} (F : Presheaf C X) /-- For presheaves valued in a concrete category, whose forgetful functor reflects isomorphisms and preserves limits, the sheaf condition in terms of unique gluings is equivalent to the usual one. diff --git a/Mathlib/Topology/Sheaves/Sheafify.lean b/Mathlib/Topology/Sheaves/Sheafify.lean index 423700fb192c9..36740da226f9a 100644 --- a/Mathlib/Topology/Sheaves/Sheafify.lean +++ b/Mathlib/Topology/Sheaves/Sheafify.lean @@ -44,8 +44,8 @@ namespace Sheafify The prelocal predicate on functions into the stalks, asserting that the function is equal to a germ. -/ def isGerm : PrelocalPredicate fun x => F.stalk x where - pred {U} f := ∃ g : F.obj (op U), ∀ x : U, f x = F.germ x g - res := fun i _ ⟨g, p⟩ => ⟨F.map i.op g, fun x => (p (i x)).trans (F.germ_res_apply i x g).symm⟩ + pred {U} f := ∃ g : F.obj (op U), ∀ x : U, f x = F.germ U x.1 x.2 g + res := fun i _ ⟨g, p⟩ => ⟨F.map i.op g, fun x ↦ (p (i x)).trans (F.germ_res_apply i x x.2 g).symm⟩ /-- The local predicate on functions into the stalks, asserting that the function is locally equal to a germ. @@ -66,12 +66,12 @@ sending each section to its germs. (This forms the unit of the adjunction.) -/ def toSheafify : F ⟶ F.sheafify.1 where - app U f := ⟨fun x => F.germ x f, PrelocalPredicate.sheafifyOf ⟨f, fun x => rfl⟩⟩ + app U f := ⟨fun x => F.germ _ x x.2 f, PrelocalPredicate.sheafifyOf ⟨f, fun x => rfl⟩⟩ naturality U U' f := by ext x apply Subtype.ext -- Porting note: Added `apply` ext ⟨u, m⟩ - exact germ_res_apply F f.unop ⟨u, m⟩ x + exact germ_res_apply F f.unop u m x /-- The natural morphism from the stalk of the sheafification to the original stalk. In `sheafifyStalkIso` we show this is an isomorphism. @@ -85,7 +85,7 @@ theorem stalkToFiber_surjective (x : X) : Function.Surjective (F.stalkToFiber x) obtain ⟨U, m, s, rfl⟩ := F.germ_exist _ t use ⟨U, m⟩ fconstructor - · exact fun y => F.germ y s + · exact fun y => F.germ _ _ y.2 s · exact ⟨PrelocalPredicate.sheafifyOf ⟨s, fun _ => rfl⟩, rfl⟩ theorem stalkToFiber_injective (x : X) : Function.Injective (F.stalkToFiber x) := by @@ -94,9 +94,9 @@ theorem stalkToFiber_injective (x : X) : Function.Injective (F.stalkToFiber x) : rcases hU ⟨x, U.2⟩ with ⟨U', mU, iU, gU, wU⟩ rcases hV ⟨x, V.2⟩ with ⟨V', mV, iV, gV, wV⟩ have wUx := wU ⟨x, mU⟩ - dsimp at wUx; erw [wUx] at e; clear wUx + dsimp at wUx; rw [wUx] at e; clear wUx have wVx := wV ⟨x, mV⟩ - dsimp at wVx; erw [wVx] at e; clear wVx + dsimp at wVx; rw [wVx] at e; clear wVx rcases F.germ_eq x mU mV gU gV e with ⟨W, mW, iU', iV', (e' : F.map iU'.op gU = F.map iV'.op gV)⟩ use ⟨W ⊓ (U' ⊓ V'), ⟨mW, mU, mV⟩⟩ refine ⟨?_, ?_, ?_⟩ @@ -108,7 +108,7 @@ theorem stalkToFiber_injective (x : X) : Function.Injective (F.stalkToFiber x) : specialize wU ⟨w.1, w.2.2.1⟩ specialize wV ⟨w.1, w.2.2.2⟩ dsimp at wU wV ⊢ - erw [wU, ← F.germ_res iU' ⟨w, w.2.1⟩, wV, ← F.germ_res iV' ⟨w, w.2.1⟩, + rw [wU, ← F.germ_res iU' w w.2.1, wV, ← F.germ_res iV' w w.2.1, CategoryTheory.types_comp_apply, CategoryTheory.types_comp_apply, e'] /-- The isomorphism between a stalk of the sheafification and the original stalk. diff --git a/Mathlib/Topology/Sheaves/Skyscraper.lean b/Mathlib/Topology/Sheaves/Skyscraper.lean index 9cdd092a962a9..5593582768775 100644 --- a/Mathlib/Topology/Sheaves/Skyscraper.lean +++ b/Mathlib/Topology/Sheaves/Skyscraper.lean @@ -52,7 +52,7 @@ point, then the skyscraper presheaf `𝓕` with value `A` is defined by `U ↦ A def skyscraperPresheaf : Presheaf C X where obj U := if p₀ ∈ unop U then A else terminal C map {U V} i := - if h : p₀ ∈ unop V then eqToHom <| by dsimp; erw [if_pos h, if_pos (leOfHom i.unop h)] + if h : p₀ ∈ unop V then eqToHom <| by dsimp; rw [if_pos h, if_pos (by simpa using i.unop.le h)] else ((if_neg h).symm.ndrec terminalIsTerminal).from _ map_id U := (em (p₀ ∈ U.unop)).elim (fun h => dif_pos h) fun h => @@ -161,6 +161,12 @@ noncomputable def skyscraperPresheafStalkOfSpecializes [HasColimits C] {y : X} ( (skyscraperPresheaf p₀ A).stalk y ≅ A := colimit.isoColimitCocone ⟨_, skyscraperPresheafCoconeIsColimitOfSpecializes p₀ A h⟩ +@[reassoc (attr := simp)] +lemma germ_skyscraperPresheafStalkOfSpecializes_hom [HasColimits C] {y : X} (h : p₀ ⤳ y) (U hU) : + (skyscraperPresheaf p₀ A).germ U y hU ≫ + (skyscraperPresheafStalkOfSpecializes p₀ A h).hom = eqToHom (if_pos (h.mem_open U.2 hU)) := + colimit.isoColimitCocone_ι_hom _ _ + /-- The cocone at `*` for the stalk functor of `skyscraperPresheaf p₀ A` when `y ∉ closure {p₀}` -/ @[simps] @@ -247,7 +253,7 @@ if `p₀ ∉ U`. def toSkyscraperPresheaf {𝓕 : Presheaf C X} {c : C} (f : 𝓕.stalk p₀ ⟶ c) : 𝓕 ⟶ skyscraperPresheaf p₀ c where app U := - if h : p₀ ∈ U.unop then 𝓕.germ ⟨p₀, h⟩ ≫ f ≫ eqToHom (if_pos h).symm + if h : p₀ ∈ U.unop then 𝓕.germ _ p₀ h ≫ f ≫ eqToHom (if_pos h).symm else ((if_neg h).symm.ndrec terminalIsTerminal).from _ naturality U V inc := by -- Porting note: don't know why original proof fell short of working, add `aesop_cat` finished @@ -256,22 +262,58 @@ def toSkyscraperPresheaf {𝓕 : Presheaf C X} {c : C} (f : 𝓕.stalk p₀ ⟶ by_cases hV : p₀ ∈ V.unop · have hU : p₀ ∈ U.unop := leOfHom inc.unop hV split_ifs - erw [← Category.assoc, 𝓕.germ_res inc.unop, Category.assoc, Category.assoc, eqToHom_trans] + rw [← Category.assoc, 𝓕.germ_res' inc, Category.assoc, Category.assoc, eqToHom_trans] · split_ifs exact ((if_neg hV).symm.ndrec terminalIsTerminal).hom_ext .. +/-- If `f : 𝓕 ⟶ skyscraperPresheaf p₀ c` is a natural transformation, then there is a morphism +`𝓕.stalk p₀ ⟶ c` defined as the morphism from colimit to cocone at `c`. +-/ +def fromStalk {𝓕 : Presheaf C X} {c : C} (f : 𝓕 ⟶ skyscraperPresheaf p₀ c) : 𝓕.stalk p₀ ⟶ c := + let χ : Cocone ((OpenNhds.inclusion p₀).op ⋙ 𝓕) := + Cocone.mk c <| + { app := fun U => f.app ((OpenNhds.inclusion p₀).op.obj U) ≫ eqToHom (if_pos U.unop.2) + naturality := fun U V inc => by + dsimp only [Functor.const_obj_map, Functor.const_obj_obj, Functor.comp_map, + Functor.comp_obj, Functor.op_obj, skyscraperPresheaf_obj] + rw [Category.comp_id, ← Category.assoc, comp_eqToHom_iff, Category.assoc, + eqToHom_trans, f.naturality, skyscraperPresheaf_map] + have hV : p₀ ∈ (OpenNhds.inclusion p₀).obj V.unop := V.unop.2 + simp only [dif_pos hV] } + colimit.desc _ χ + +@[reassoc (attr := simp)] +lemma germ_fromStalk {𝓕 : Presheaf C X} {c : C} (f : 𝓕 ⟶ skyscraperPresheaf p₀ c) (U) (hU) : + 𝓕.germ U p₀ hU ≫ fromStalk p₀ f = f.app (op U) ≫ eqToHom (if_pos hU) := + colimit.ι_desc _ _ + +theorem to_skyscraper_fromStalk {𝓕 : Presheaf C X} {c : C} (f : 𝓕 ⟶ skyscraperPresheaf p₀ c) : + toSkyscraperPresheaf p₀ (fromStalk _ f) = f := by + apply NatTrans.ext + ext U + dsimp + split_ifs with h + · rw [← Category.assoc, germ_fromStalk, Category.assoc, eqToHom_trans, eqToHom_refl, + Category.comp_id] + · exact ((if_neg h).symm.ndrec terminalIsTerminal).hom_ext .. + +theorem fromStalk_to_skyscraper {𝓕 : Presheaf C X} {c : C} (f : 𝓕.stalk p₀ ⟶ c) : + fromStalk p₀ (toSkyscraperPresheaf _ f) = f := by + refine 𝓕.stalk_hom_ext fun U hxU ↦ ?_ + rw [germ_fromStalk, toSkyscraperPresheaf_app, dif_pos hxU, Category.assoc, Category.assoc, + eqToHom_trans, eqToHom_refl, Category.comp_id, Presheaf.germ] + /-- The unit in `Presheaf.stalkFunctor ⊣ skyscraperPresheafFunctor` -/ @[simps] protected def unit : 𝟭 (Presheaf C X) ⟶ Presheaf.stalkFunctor C p₀ ⋙ skyscraperPresheafFunctor p₀ where - app 𝓕 := toSkyscraperPresheaf _ <| 𝟙 _ + app _ := toSkyscraperPresheaf _ <| 𝟙 _ naturality 𝓕 𝓖 f := by ext U; dsimp split_ifs with h - · simp only [Category.id_comp, ← Category.assoc]; rw [comp_eqToHom_iff] - simp only [Category.assoc, eqToHom_trans, eqToHom_refl, Category.comp_id] - erw [colimit.ι_map]; rfl + · simp only [Category.id_comp, Category.assoc, eqToHom_trans_assoc, eqToHom_refl, + Presheaf.stalkFunctor_map_germ_assoc, Presheaf.stalkFunctor_obj] · apply ((if_neg h).symm.ndrec terminalIsTerminal).hom_ext /-- The counit in `Presheaf.stalkFunctor ⊣ skyscraperPresheafFunctor` @@ -280,14 +322,7 @@ protected def unit : protected def counit : skyscraperPresheafFunctor p₀ ⋙ (Presheaf.stalkFunctor C p₀ : Presheaf C X ⥤ C) ⟶ 𝟭 C where app c := (skyscraperPresheafStalkOfSpecializes p₀ c specializes_rfl).hom - naturality x y f := colimit.hom_ext fun U => by - erw [← Category.assoc, colimit.ι_map, colimit.isoColimitCocone_ι_hom_assoc, - skyscraperPresheafCoconeOfSpecializes_ι_app (h := specializes_rfl), Category.assoc, - colimit.ι_desc, whiskeringLeft_obj_map, whiskerLeft_app, SkyscraperPresheafFunctor.map'_app, - dif_pos U.unop.2, skyscraperPresheafCoconeOfSpecializes_ι_app (h := specializes_rfl), - comp_eqToHom_iff, Category.assoc, eqToHom_comp_iff, ← Category.assoc, eqToHom_trans, - eqToHom_refl, Category.id_comp, comp_eqToHom_iff, Category.assoc, eqToHom_trans, eqToHom_refl, - Category.comp_id, CategoryTheory.Functor.id_map] + naturality x y f := TopCat.Presheaf.stalk_hom_ext _ fun U hxU ↦ by simp [hxU] end StalkSkyscraperPresheafAdjunctionAuxs @@ -346,7 +381,7 @@ def stalkSkyscraperSheafAdjunction [HasColimits C] : counit := StalkSkyscraperPresheafAdjunctionAuxs.counit p₀ left_triangle_components X := ((skyscraperPresheafStalkAdjunction p₀).left_triangle_components X.val) - right_triangle_components Y := + right_triangle_components _ := Sheaf.Hom.ext ((skyscraperPresheafStalkAdjunction p₀).right_triangle_components _) instance [HasColimits C] : (skyscraperSheafFunctor p₀ : C ⥤ Sheaf C X).IsRightAdjoint := diff --git a/Mathlib/Topology/Sheaves/Stalks.lean b/Mathlib/Topology/Sheaves/Stalks.lean index d1e8867ba7f1a..125a7e70f0fc4 100644 --- a/Mathlib/Topology/Sheaves/Stalks.lean +++ b/Mathlib/Topology/Sheaves/Stalks.lean @@ -89,46 +89,76 @@ theorem stalkFunctor_obj (ℱ : X.Presheaf C) (x : X) : (stalkFunctor C x).obj /-- The germ of a section of a presheaf over an open at a point of that open. -/ -def germ (F : X.Presheaf C) {U : Opens X} (x : U) : F.obj (op U) ⟶ stalk F x := - colimit.ι ((OpenNhds.inclusion x.1).op ⋙ F) (op ⟨U, x.2⟩) +def germ (F : X.Presheaf C) (U : Opens X) (x : X) (hx : x ∈ U) : F.obj (op U) ⟶ stalk F x := + colimit.ι ((OpenNhds.inclusion x).op ⋙ F) (op ⟨U, hx⟩) /-- The germ of a global section of a presheaf at a point. -/ def Γgerm (F : X.Presheaf C) (x : X) : F.obj (op ⊤) ⟶ stalk F x := - F.germ ⟨x, show x ∈ ⊤ by trivial⟩ + F.germ ⊤ x True.intro +@[reassoc] +theorem germ_res (F : X.Presheaf C) {U V : Opens X} (i : U ⟶ V) (x : X) (hx : x ∈ U) : + F.map i.op ≫ F.germ U x hx = F.germ V x (i.le hx) := + let i' : (⟨U, hx⟩ : OpenNhds x) ⟶ ⟨V, i.le hx⟩ := i + colimit.w ((OpenNhds.inclusion x).op ⋙ F) i'.op + +/-- A variant of `germ_res` with `op V ⟶ op U` +so that the LHS is more general and simp fires more easier. -/ @[reassoc (attr := simp)] -theorem germ_res (F : X.Presheaf C) {U V : Opens X} (i : U ⟶ V) (x : U) : - F.map i.op ≫ germ F x = germ F (i x : V) := - let i' : (⟨U, x.2⟩ : OpenNhds x.1) ⟶ ⟨V, (i x : V).2⟩ := i - colimit.w ((OpenNhds.inclusion x.1).op ⋙ F) i'.op +theorem germ_res' (F : X.Presheaf C) {U V : Opens X} (i : op V ⟶ op U) (x : X) (hx : x ∈ U) : + F.map i ≫ F.germ U x hx = F.germ V x (i.unop.le hx) := + let i' : (⟨U, hx⟩ : OpenNhds x) ⟶ ⟨V, i.unop.le hx⟩ := i.unop + colimit.w ((OpenNhds.inclusion x).op ⋙ F) i'.op @[reassoc] -lemma map_germ_eq_Γgerm (F : X.Presheaf C) {U : Opens X} {i : U ⟶ ⊤} (x : U) : - F.map i.op ≫ germ F x = Γgerm F (i x) := - germ_res F i x +lemma map_germ_eq_Γgerm (F : X.Presheaf C) {U : Opens X} {i : U ⟶ ⊤} (x : X) (hx : x ∈ U) : + F.map i.op ≫ F.germ U x hx = F.Γgerm x := + germ_res F i x hx + +attribute [local instance] ConcreteCategory.instFunLike in +theorem germ_res_apply (F : X.Presheaf C) + {U V : Opens X} (i : U ⟶ V) (x : X) (hx : x ∈ U) [ConcreteCategory C] (s) : + F.germ U x hx (F.map i.op s) = F.germ V x (i.le hx) s := by rw [← comp_apply, germ_res] --- Porting note: `@[elementwise]` did not generate the best lemma when applied to `germ_res` attribute [local instance] ConcreteCategory.instFunLike in -theorem germ_res_apply (F : X.Presheaf C) {U V : Opens X} (i : U ⟶ V) (x : U) [ConcreteCategory C] - (s) : germ F x (F.map i.op s) = germ F (i x) s := by rw [← comp_apply, germ_res] +theorem germ_res_apply' (F : X.Presheaf C) + {U V : Opens X} (i : op V ⟶ op U) (x : X) (hx : x ∈ U) [ConcreteCategory C] (s) : + F.germ U x hx (F.map i s) = F.germ V x (i.unop.le hx) s := by rw [← comp_apply, germ_res'] attribute [local instance] ConcreteCategory.instFunLike in -lemma Γgerm_res_apply (F : X.Presheaf C) {U : Opens X} {i : U ⟶ ⊤} (x : U) [ConcreteCategory C] - (s) : germ F x (F.map i.op s) = Γgerm F x.val s := germ_res_apply F i x s +lemma Γgerm_res_apply (F : X.Presheaf C) + {U : Opens X} {i : U ⟶ ⊤} (x : X) (hx : x ∈ U) [ConcreteCategory C] (s) : + F.germ U x hx (F.map i.op s) = F.Γgerm x s := F.germ_res_apply i x hx s /-- A morphism from the stalk of `F` at `x` to some object `Y` is completely determined by its composition with the `germ` morphisms. -/ @[ext] theorem stalk_hom_ext (F : X.Presheaf C) {x} {Y : C} {f₁ f₂ : F.stalk x ⟶ Y} - (ih : ∀ (U : Opens X) (hxU : x ∈ U), F.germ ⟨x, hxU⟩ ≫ f₁ = F.germ ⟨x, hxU⟩ ≫ f₂) : f₁ = f₂ := + (ih : ∀ (U : Opens X) (hxU : x ∈ U), F.germ U x hxU ≫ f₁ = F.germ U x hxU ≫ f₂) : f₁ = f₂ := colimit.hom_ext fun U => by induction' U using Opposite.rec with U; cases' U with U hxU; exact ih U hxU -@[reassoc (attr := simp), elementwise (attr := simp)] -theorem stalkFunctor_map_germ {F G : X.Presheaf C} (U : Opens X) (x : U) (f : F ⟶ G) : - germ F x ≫ (stalkFunctor C x.1).map f = f.app (op U) ≫ germ G x := - colimit.ι_map (whiskerLeft (OpenNhds.inclusion x.1).op f) (op ⟨U, x.2⟩) +@[reassoc (attr := simp)] +theorem stalkFunctor_map_germ {F G : X.Presheaf C} (U : Opens X) (x : X) (hx : x ∈ U) (f : F ⟶ G) : + F.germ U x hx ≫ (stalkFunctor C x).map f = f.app (op U) ≫ G.germ U x hx := + colimit.ι_map (whiskerLeft (OpenNhds.inclusion x).op f) (op ⟨U, hx⟩) + +attribute [local instance] ConcreteCategory.instFunLike in +theorem stalkFunctor_map_germ_apply [ConcreteCategory C] + {F G : X.Presheaf C} (U : Opens X) (x : X) (hx : x ∈ U) (f : F ⟶ G) (s) : + (stalkFunctor C x).map f (F.germ U x hx s) = G.germ U x hx (f.app (op U) s) := by + rw [← comp_apply, ← stalkFunctor_map_germ] + exact (comp_apply _ _ _).symm + +-- a variant of `stalkFunctor_map_germ_apply` that makes simpNF happy. +attribute [local instance] ConcreteCategory.instFunLike in +@[simp] +theorem stalkFunctor_map_germ_apply' [ConcreteCategory C] + {F G : X.Presheaf C} (U : Opens X) (x : X) (hx : x ∈ U) (f : F ⟶ G) (s) : + DFunLike.coe (F := F.stalk x ⟶ G.stalk x) ((stalkFunctor C x).map f) (F.germ U x hx s) = + G.germ U x hx (f.app (op U) s) := + stalkFunctor_map_germ_apply U x hx f s variable (C) @@ -143,8 +173,8 @@ def stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) (x : X) : (f _* F).stalk ( @[reassoc (attr := simp), elementwise (attr := simp)] theorem stalkPushforward_germ (f : X ⟶ Y) (F : X.Presheaf C) (U : Opens Y) - (x : (Opens.map f).obj U) : - (f _* F).germ ⟨(f : X → Y) (x : X), x.2⟩ ≫ F.stalkPushforward C f x = F.germ x := by + (x : X) (hx : f x ∈ U) : + (f _* F).germ U (f x) hx ≫ F.stalkPushforward C f x = F.germ ((Opens.map f).obj U) x hx := by simp [germ, stalkPushforward] -- Here are two other potential solutions, suggested by @fpvandoorn at @@ -178,8 +208,8 @@ theorem comp (ℱ : X.Presheaf C) (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : ext simp [germ, stalkPushforward] -theorem stalkPushforward_iso_of_openEmbedding {f : X ⟶ Y} (hf : OpenEmbedding f) (F : X.Presheaf C) - (x : X) : IsIso (F.stalkPushforward _ f x) := by +theorem stalkPushforward_iso_of_isOpenEmbedding {f : X ⟶ Y} (hf : IsOpenEmbedding f) + (F : X.Presheaf C) (x : X) : IsIso (F.stalkPushforward _ f x) := by haveI := Functor.initial_of_adjunction (hf.isOpenMap.adjunctionNhds x) convert ((Functor.Final.colimitIso (hf.isOpenMap.functorNhds x).op @@ -204,6 +234,9 @@ theorem stalkPushforward_iso_of_openEmbedding {f : X ⟶ Y} (hf : OpenEmbedding refine ((homOfLE ?_).op : op (unop U) ⟶ _) exact Set.image_preimage_subset _ _ +@[deprecated (since := "2024-10-18")] +alias stalkPushforward_iso_of_openEmbedding := stalkPushforward_iso_of_isOpenEmbedding + end stalkPushforward section stalkPullback @@ -217,19 +250,19 @@ def stalkPullbackHom (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) : @[reassoc (attr := simp)] lemma germ_stalkPullbackHom (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) (U : Opens Y) (hU : f x ∈ U) : - F.germ ⟨f x, hU⟩ ≫ stalkPullbackHom C f F x = + F.germ U (f x) hU ≫ stalkPullbackHom C f F x = ((pushforwardPullbackAdjunction C f).unit.app F).app _ ≫ - ((pullback C f).obj F).germ ⟨x, show x ∈ (Opens.map f).obj U from hU⟩ := by + ((pullback C f).obj F).germ ((Opens.map f).obj U) x hU := by simp [stalkPullbackHom, germ, stalkFunctor, stalkPushforward] /-- The morphism `(f⁻¹ℱ)(U) ⟶ ℱ_{f(x)}` for some `U ∋ x`. -/ -def germToPullbackStalk (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : U) : - ((pullback C f).obj F).obj (op U) ⟶ F.stalk ((f : X → Y) (x : X)) := +def germToPullbackStalk (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : X) (hx : x ∈ U) : + ((pullback C f).obj F).obj (op U) ⟶ F.stalk (f x) := ((Opens.map f).op.isPointwiseLeftKanExtensionLanUnit F (op U)).desc { pt := F.stalk ((f : X → Y) (x : X)) ι := - { app := fun V => F.germ ⟨((f : X → Y) (x : X)), V.hom.unop.le x.2⟩ - naturality := fun _ _ i => by erw [Category.comp_id]; exact F.germ_res i.left.unop _ } } + { app := fun V => F.germ _ (f x) (V.hom.unop.le hx) + naturality := fun _ _ i => by simp } } variable {C} in @[ext] @@ -248,20 +281,20 @@ lemma pullback_obj_obj_ext {Z : C} {f : X ⟶ Y} {F : Y.Presheaf C} (U : (Opens @[reassoc (attr := simp)] lemma pushforwardPullbackAdjunction_unit_pullback_map_germToPullbackStalk - (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : U) (V : Opens Y) + (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : X) (hx : x ∈ U) (V : Opens Y) (hV : U ≤ (Opens.map f).obj V) : ((pushforwardPullbackAdjunction C f).unit.app F).app (op V) ≫ - ((pullback C f).obj F).map (homOfLE hV).op ≫ germToPullbackStalk C f F U x = - F.germ ⟨f x, hV x.2⟩ := by + ((pullback C f).obj F).map (homOfLE hV).op ≫ germToPullbackStalk C f F U x hx = + F.germ _ (f x) (hV hx) := by simpa [pushforwardPullbackAdjunction] using ((Opens.map f).op.isPointwiseLeftKanExtensionLanUnit F (op U)).fac _ (CostructuredArrow.mk (homOfLE hV).op) @[reassoc (attr := simp)] lemma germToPullbackStalk_stalkPullbackHom - (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : U) : - germToPullbackStalk C f F U x ≫ stalkPullbackHom C f F x = - ((pullback C f).obj F).germ x := by + (f : X ⟶ Y) (F : Y.Presheaf C) (U : Opens X) (x : X) (hx : x ∈ U) : + germToPullbackStalk C f F U x hx ≫ stalkPullbackHom C f F x = + ((pullback C f).obj F).germ _ x hx := by ext V hV dsimp simp only [pushforwardPullbackAdjunction_unit_pullback_map_germToPullbackStalk_assoc, @@ -269,11 +302,11 @@ lemma germToPullbackStalk_stalkPullbackHom @[reassoc (attr := simp)] lemma pushforwardPullbackAdjunction_unit_app_app_germToPullbackStalk - (f : X ⟶ Y) (F : Y.Presheaf C) (V : (Opens Y)ᵒᵖ) (x : (Opens.map f).obj V.unop) : - ((pushforwardPullbackAdjunction C f).unit.app F).app V ≫ germToPullbackStalk C f F _ x = - F.germ ⟨f x, x.2⟩ := by + (f : X ⟶ Y) (F : Y.Presheaf C) (V : (Opens Y)ᵒᵖ) (x : X) (hx : f x ∈ V.unop) : + ((pushforwardPullbackAdjunction C f).unit.app F).app V ≫ germToPullbackStalk C f F _ x hx = + F.germ _ (f x) hx := by simpa using pushforwardPullbackAdjunction_unit_pullback_map_germToPullbackStalk - C f F ((Opens.map f).obj V.unop) x V.unop (by rfl) + C f F ((Opens.map f).obj V.unop) x hx V.unop (by rfl) /-- The morphism `(f⁻¹ℱ)ₓ ⟶ ℱ_{f(x)}`. -/ def stalkPullbackInv (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) : @@ -281,7 +314,7 @@ def stalkPullbackInv (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) : colimit.desc ((OpenNhds.inclusion x).op ⋙ (Presheaf.pullback C f).obj F) { pt := F.stalk (f x) ι := - { app := fun U => F.germToPullbackStalk _ f (unop U).1 ⟨x, (unop U).2⟩ + { app := fun U => F.germToPullbackStalk _ f (unop U).1 x (unop U).2 naturality := fun U V i => by dsimp ext W hW @@ -292,8 +325,8 @@ def stalkPullbackInv (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) : @[reassoc (attr := simp)] lemma germ_stalkPullbackInv (f : X ⟶ Y) (F : Y.Presheaf C) (x : X) (V : Opens X) (hV : x ∈ V) : - ((pullback C f).obj F).germ ⟨x, hV⟩ ≫ stalkPullbackInv C f F x = - F.germToPullbackStalk _ f V ⟨x, hV⟩ := by + ((pullback C f).obj F).germ _ x hV ≫ stalkPullbackInv C f F x = + F.germToPullbackStalk _ f V x hV := by apply colimit.ι_desc /-- The isomorphism `ℱ_{f(x)} ≅ (f⁻¹ℱ)ₓ`. -/ @@ -332,14 +365,12 @@ noncomputable def stalkSpecializes (F : X.Presheaf C) {x y : X} (h : x ⤳ y) : exact colimit.w ((OpenNhds.inclusion x).op ⋙ F) (show V' ⟶ U' from i.unop).op @[reassoc (attr := simp), elementwise nosimp] -theorem germ_stalkSpecializes (F : X.Presheaf C) {U : Opens X} {y : U} {x : X} (h : x ⤳ y) : - F.germ y ≫ F.stalkSpecializes h = F.germ (⟨x, h.mem_open U.isOpen y.prop⟩ : U) := +theorem germ_stalkSpecializes (F : X.Presheaf C) + {U : Opens X} {y : X} (hy : y ∈ U) {x : X} (h : x ⤳ y) : + F.germ U y hy ≫ F.stalkSpecializes h = F.germ U x (h.mem_open U.isOpen hy) := colimit.ι_desc _ _ -@[reassoc, elementwise nosimp] -theorem germ_stalkSpecializes' (F : X.Presheaf C) {U : Opens X} {x y : X} (h : x ⤳ y) - (hy : y ∈ U) : F.germ ⟨y, hy⟩ ≫ F.stalkSpecializes h = F.germ ⟨x, h.mem_open U.isOpen hy⟩ := - colimit.ι_desc _ _ +@[deprecated (since := "2024-07-30")] alias germ_stalkSpecializes' := germ_stalkSpecializes @[simp] theorem stalkSpecializes_refl {C : Type*} [Category C] [Limits.HasColimits C] {X : TopCat} @@ -391,8 +422,8 @@ attribute [local instance] ConcreteCategory.hasCoeToSort ConcreteCategory.instFu theorem germ_ext (F : X.Presheaf C) {U V : Opens X} {x : X} {hxU : x ∈ U} {hxV : x ∈ V} (W : Opens X) (hxW : x ∈ W) (iWU : W ⟶ U) (iWV : W ⟶ V) {sU : F.obj (op U)} {sV : F.obj (op V)} (ih : F.map iWU.op sU = F.map iWV.op sV) : - F.germ ⟨x, hxU⟩ sU = F.germ ⟨x, hxV⟩ sV := by - erw [← F.germ_res iWU ⟨x, hxW⟩, ← F.germ_res iWV ⟨x, hxW⟩, comp_apply, comp_apply, ih] + F.germ _ x hxU sU = F.germ _ x hxV sV := by + rw [← F.germ_res iWU x hxW, ← F.germ_res iWV x hxW, comp_apply, comp_apply, ih] variable [PreservesFilteredColimits (forget C)] @@ -401,7 +432,7 @@ For presheaves valued in a concrete category whose forgetful functor preserves f every element of the stalk is the germ of a section. -/ theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) : - ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by + ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ _ x m s = t := by obtain ⟨U, s, e⟩ := Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t revert s e @@ -411,7 +442,7 @@ theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) exact ⟨V, m, s, e⟩ theorem germ_eq (F : X.Presheaf C) {U V : Opens X} (x : X) (mU : x ∈ U) (mV : x ∈ V) - (s : F.obj (op U)) (t : F.obj (op V)) (h : germ F ⟨x, mU⟩ s = germ F ⟨x, mV⟩ t) : + (s : F.obj (op U)) (t : F.obj (op V)) (h : F.germ U x mU s = F.germ V x mV t) : ∃ (W : Opens X) (_m : x ∈ W) (iU : W ⟶ U) (iV : W ⟶ V), F.map iU.op s = F.map iV.op t := by obtain ⟨W, iU, iV, e⟩ := (Types.FilteredColimit.isColimit_eq_iff.{v, v} _ @@ -423,13 +454,12 @@ theorem stalkFunctor_map_injective_of_app_injective {F G : Presheaf C X} (f : F Function.Injective ((stalkFunctor C x).map f) := fun s t hst => by rcases germ_exist F x s with ⟨U₁, hxU₁, s, rfl⟩ rcases germ_exist F x t with ⟨U₂, hxU₂, t, rfl⟩ - erw [stalkFunctor_map_germ_apply _ ⟨x, _⟩] at hst - erw [stalkFunctor_map_germ_apply _ ⟨x, _⟩] at hst + rw [stalkFunctor_map_germ_apply, stalkFunctor_map_germ_apply] at hst obtain ⟨W, hxW, iWU₁, iWU₂, heq⟩ := G.germ_eq x hxU₁ hxU₂ _ _ hst rw [← comp_apply, ← comp_apply, ← f.naturality, ← f.naturality, comp_apply, comp_apply] at heq replace heq := h W heq - convert congr_arg (F.germ ⟨x, hxW⟩) heq using 1 - exacts [(F.germ_res_apply iWU₁ ⟨x, hxW⟩ s).symm, (F.germ_res_apply iWU₂ ⟨x, hxW⟩ t).symm] + convert congr_arg (F.germ _ x hxW) heq using 1 + exacts [(F.germ_res_apply iWU₁ x hxW s).symm, (F.germ_res_apply iWU₂ x hxW t).symm] variable [HasLimits C] [PreservesLimits (forget C)] [(forget C).ReflectsIsomorphisms] @@ -437,10 +467,10 @@ variable [HasLimits C] [PreservesLimits (forget C)] [(forget C).ReflectsIsomorph preserves limits and filtered colimits. Then two sections who agree on every stalk must be equal. -/ theorem section_ext (F : Sheaf C X) (U : Opens X) (s t : F.1.obj (op U)) - (h : ∀ x : U, F.presheaf.germ x s = F.presheaf.germ x t) : s = t := by + (h : ∀ (x : X) (hx : x ∈ U), F.presheaf.germ U x hx s = F.presheaf.germ U x hx t) : s = t := by -- We use `germ_eq` and the axiom of choice, to pick for every point `x` a neighbourhood -- `V x`, such that the restrictions of `s` and `t` to `V x` coincide. - choose V m i₁ i₂ heq using fun x : U => F.presheaf.germ_eq x.1 x.2 x.2 s t (h x) + choose V m i₁ i₂ heq using fun x : U => F.presheaf.germ_eq x.1 x.2 x.2 s t (h x.1 x.2) -- Since `F` is a sheaf, we can prove the equality locally, if we can show that these -- neighborhoods form a cover of `U`. apply F.eq_of_locally_eq' V U i₁ @@ -456,16 +486,16 @@ imply surjectivity of the components of a sheaf morphism. However it does imply is an epi, but this fact is not yet formalized. -/ theorem app_injective_of_stalkFunctor_map_injective {F : Sheaf C X} {G : Presheaf C X} (f : F.1 ⟶ G) - (U : Opens X) (h : ∀ x : U, Function.Injective ((stalkFunctor C x.val).map f)) : + (U : Opens X) (h : ∀ x ∈ U, Function.Injective ((stalkFunctor C x).map f)) : Function.Injective (f.app (op U)) := fun s t hst => - section_ext F _ _ _ fun x => - h x <| by erw [stalkFunctor_map_germ_apply, stalkFunctor_map_germ_apply, hst] + section_ext F _ _ _ fun x hx => + h x hx <| by rw [stalkFunctor_map_germ_apply, stalkFunctor_map_germ_apply, hst] theorem app_injective_iff_stalkFunctor_map_injective {F : Sheaf C X} {G : Presheaf C X} (f : F.1 ⟶ G) : (∀ x : X, Function.Injective ((stalkFunctor C x).map f)) ↔ ∀ U : Opens X, Function.Injective (f.app (op U)) := - ⟨fun h U => app_injective_of_stalkFunctor_map_injective f U fun x => h x.1, + ⟨fun h U => app_injective_of_stalkFunctor_map_injective f U fun x _ => h x, stalkFunctor_map_injective_of_app_injective f⟩ instance stalkFunctor_preserves_mono (x : X) : @@ -489,7 +519,7 @@ theorem mono_of_stalk_mono {F G : Sheaf C X} (f : F ⟶ G) [∀ x, Mono <| (stal (Sheaf.Hom.mono_iff_presheaf_mono _ _ _).mpr <| (NatTrans.mono_iff_mono_app _).mpr fun U => (ConcreteCategory.mono_iff_injective_of_preservesPullback _).mpr <| - app_injective_of_stalkFunctor_map_injective f.1 U.unop fun ⟨_x, _hx⟩ => + app_injective_of_stalkFunctor_map_injective f.1 U.unop fun _x _hx => (ConcreteCategory.mono_iff_injective_of_preservesPullback _).mp <| inferInstance theorem mono_iff_stalk_mono {F G : Sheaf C X} (f : F ⟶ G) : @@ -501,10 +531,13 @@ We claim that it suffices to find preimages *locally*. That is, for each `x : U` a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t` agree on `V`. -/ theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G) - (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1)) - (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)), + (U : Opens X) (hinj : ∀ x ∈ U, Function.Injective ((stalkFunctor C x).map f.1)) + (hsurj : ∀ (t x) (_ : x ∈ U), ∃ (V : Opens X) (_ : x ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)), f.1.app (op V) s = G.1.map iVU.op t) : Function.Surjective (f.1.app (op U)) := by + conv at hsurj => + enter [t] + rw [Subtype.forall' (p := (· ∈ U))] intro t -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a -- preimage under `f` on `V`. @@ -525,36 +558,36 @@ theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : -- What's left to show here is that the sections `sf` are compatible, i.e. they agree on -- the intersections `V x ⊓ V y`. We prove this by showing that all germs are equal. apply section_ext - intro z + intro z hz -- Here, we need to use injectivity of the stalk maps. - apply hinj ⟨z, (iVU x).le ((inf_le_left : V x ⊓ V y ≤ V x) z.2)⟩ + apply hinj z ((iVU x).le ((inf_le_left : V x ⊓ V y ≤ V x) hz)) dsimp only - erw [stalkFunctor_map_germ_apply, stalkFunctor_map_germ_apply] + rw [stalkFunctor_map_germ_apply, stalkFunctor_map_germ_apply] simp_rw [← comp_apply, f.1.naturality, comp_apply, heq, ← comp_apply, ← G.1.map_comp] rfl theorem app_surjective_of_stalkFunctor_map_bijective {F G : Sheaf C X} (f : F ⟶ G) (U : Opens X) - (h : ∀ x : U, Function.Bijective ((stalkFunctor C x.val).map f.1)) : + (h : ∀ x ∈ U, Function.Bijective ((stalkFunctor C x).map f.1)) : Function.Surjective (f.1.app (op U)) := by - refine app_surjective_of_injective_of_locally_surjective f U (fun x => (h x).1) fun t x => ?_ + refine app_surjective_of_injective_of_locally_surjective f U (And.left <| h · ·) fun t x hx => ?_ -- Now we need to prove our initial claim: That we can find preimages of `t` locally. -- Since `f` is surjective on stalks, we can find a preimage `s₀` of the germ of `t` at `x` - obtain ⟨s₀, hs₀⟩ := (h x).2 (G.presheaf.germ x t) + obtain ⟨s₀, hs₀⟩ := (h x hx).2 (G.presheaf.germ U x hx t) -- ... and this preimage must come from some section `s₁` defined on some open neighborhood `V₁` - obtain ⟨V₁, hxV₁, s₁, hs₁⟩ := F.presheaf.germ_exist x.1 s₀ + obtain ⟨V₁, hxV₁, s₁, hs₁⟩ := F.presheaf.germ_exist x s₀ subst hs₁; rename' hs₀ => hs₁ - erw [stalkFunctor_map_germ_apply V₁ ⟨x.1, hxV₁⟩ f.1 s₁] at hs₁ + rw [stalkFunctor_map_germ_apply V₁ x hxV₁ f.1 s₁] at hs₁ -- Now, the germ of `f.app (op V₁) s₁` equals the germ of `t`, hence they must coincide on -- some open neighborhood `V₂`. - obtain ⟨V₂, hxV₂, iV₂V₁, iV₂U, heq⟩ := G.presheaf.germ_eq x.1 hxV₁ x.2 _ _ hs₁ + obtain ⟨V₂, hxV₂, iV₂V₁, iV₂U, heq⟩ := G.presheaf.germ_eq x hxV₁ hx _ _ hs₁ -- The restriction of `s₁` to that neighborhood is our desired local preimage. use V₂, hxV₂, iV₂U, F.1.map iV₂V₁.op s₁ rw [← comp_apply, f.1.naturality, comp_apply, heq] theorem app_bijective_of_stalkFunctor_map_bijective {F G : Sheaf C X} (f : F ⟶ G) (U : Opens X) - (h : ∀ x : U, Function.Bijective ((stalkFunctor C x.val).map f.1)) : + (h : ∀ x ∈ U, Function.Bijective ((stalkFunctor C x).map f.1)) : Function.Bijective (f.1.app (op U)) := - ⟨app_injective_of_stalkFunctor_map_injective f.1 U fun x => (h x).1, + ⟨app_injective_of_stalkFunctor_map_injective f.1 U fun x hx => (h x hx).1, app_surjective_of_stalkFunctor_map_bijective f U h⟩ theorem app_isIso_of_stalkFunctor_map_iso {F G : Sheaf C X} (f : F ⟶ G) (U : Opens X) @@ -565,9 +598,9 @@ theorem app_isIso_of_stalkFunctor_map_iso {F G : Sheaf C X} (f : F ⟶ G) (U : O exact isIso_of_reflects_iso (f.1.app (op U)) (forget C) rw [isIso_iff_bijective] apply app_bijective_of_stalkFunctor_map_bijective - intro x + intro x hx apply (isIso_iff_bijective _).mp - exact Functor.map_isIso (forget C) ((stalkFunctor C x.1).map f.1) + exact Functor.map_isIso (forget C) ((stalkFunctor C (⟨x, hx⟩ : U).1).map f.1) -- Making this an instance would cause a loop in typeclass resolution with `Functor.map_isIso` /-- Let `F` and `G` be sheaves valued in a concrete category, whose forgetful functor reflects @@ -599,11 +632,11 @@ end Concrete instance algebra_section_stalk (F : X.Presheaf CommRingCat) {U : Opens X} (x : U) : Algebra (F.obj <| op U) (F.stalk x) := - (F.germ x).toAlgebra + (F.germ U x.1 x.2).toAlgebra @[simp] theorem stalk_open_algebraMap {X : TopCat} (F : X.Presheaf CommRingCat) {U : Opens X} (x : U) : - algebraMap (F.obj <| op U) (F.stalk x) = F.germ x := + algebraMap (F.obj <| op U) (F.stalk x) = F.germ U x.1 x.2 := rfl end TopCat.Presheaf diff --git a/Mathlib/Topology/ShrinkingLemma.lean b/Mathlib/Topology/ShrinkingLemma.lean index 49f989797cbfc..7cd187f075dfa 100644 --- a/Mathlib/Topology/ShrinkingLemma.lean +++ b/Mathlib/Topology/ShrinkingLemma.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Reid Barton -/ -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # The shrinking lemma @@ -74,8 +74,8 @@ protected theorem subset (v : PartialRefinement u s) (i : ι) : v i ⊆ u i := b open Classical in instance : PartialOrder (PartialRefinement u s) where le v₁ v₂ := v₁.carrier ⊆ v₂.carrier ∧ ∀ i ∈ v₁.carrier, v₁ i = v₂ i - le_refl v := ⟨Subset.refl _, fun _ _ => rfl⟩ - le_trans v₁ v₂ v₃ h₁₂ h₂₃ := + le_refl _ := ⟨Subset.refl _, fun _ _ => rfl⟩ + le_trans _ _ _ h₁₂ h₂₃ := ⟨Subset.trans h₁₂.1 h₂₃.1, fun i hi => (h₁₂.2 i hi).trans (h₂₃.2 i <| h₁₂.1 hi)⟩ le_antisymm v₁ v₂ h₁₂ h₂₁ := have hc : v₁.carrier = v₂.carrier := Subset.antisymm h₁₂.1 h₂₁.1 diff --git a/Mathlib/Topology/Sober.lean b/Mathlib/Topology/Sober.lean index a4717443959a5..5da3ae56e5cad 100644 --- a/Mathlib/Topology/Sober.lean +++ b/Mathlib/Topology/Sober.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.Topology.Separation import Mathlib.Topology.Sets.Closeds /-! @@ -19,6 +18,7 @@ stated via `[QuasiSober α] [T0Space α]`. * `IsGenericPoint` : `x` is the generic point of `S` if `S` is the closure of `x`. * `QuasiSober` : A space is quasi-sober if every irreducible closed subset has a generic point. +* `genericPoints` : The set of generic points of irreducible components. -/ @@ -108,14 +108,28 @@ noncomputable def IsIrreducible.genericPoint [QuasiSober α] {S : Set α} (hS : α := (QuasiSober.sober hS.closure isClosed_closure).choose -theorem IsIrreducible.genericPoint_spec [QuasiSober α] {S : Set α} (hS : IsIrreducible S) : +theorem IsIrreducible.isGenericPoint_genericPoint_closure + [QuasiSober α] {S : Set α} (hS : IsIrreducible S) : IsGenericPoint hS.genericPoint (closure S) := (QuasiSober.sober hS.closure isClosed_closure).choose_spec +theorem IsIrreducible.isGenericPoint_genericPoint [QuasiSober α] {S : Set α} + (hS : IsIrreducible S) (hS' : IsClosed S) : + IsGenericPoint hS.genericPoint S := by + convert hS.isGenericPoint_genericPoint_closure; exact hS'.closure_eq.symm + @[simp] theorem IsIrreducible.genericPoint_closure_eq [QuasiSober α] {S : Set α} (hS : IsIrreducible S) : closure ({hS.genericPoint} : Set α) = closure S := - hS.genericPoint_spec + hS.isGenericPoint_genericPoint_closure + +theorem IsIrreducible.closure_genericPoint [QuasiSober α] {S : Set α} + (hS : IsIrreducible S) (hS' : IsClosed S) : + closure ({hS.genericPoint} : Set α) = S := + hS.isGenericPoint_genericPoint_closure.trans hS'.closure_eq + +@[deprecated (since := "2024-10-03")] +alias IsIrreducible.genericPoint_spec := IsIrreducible.isGenericPoint_genericPoint_closure variable (α) @@ -124,18 +138,18 @@ noncomputable def genericPoint [QuasiSober α] [IrreducibleSpace α] : α := (IrreducibleSpace.isIrreducible_univ α).genericPoint theorem genericPoint_spec [QuasiSober α] [IrreducibleSpace α] : - IsGenericPoint (genericPoint α) ⊤ := by - simpa using (IrreducibleSpace.isIrreducible_univ α).genericPoint_spec + IsGenericPoint (genericPoint α) univ := by + simpa using (IrreducibleSpace.isIrreducible_univ α).isGenericPoint_genericPoint_closure @[simp] theorem genericPoint_closure [QuasiSober α] [IrreducibleSpace α] : - closure ({genericPoint α} : Set α) = ⊤ := + closure ({genericPoint α} : Set α) = univ := genericPoint_spec α variable {α} theorem genericPoint_specializes [QuasiSober α] [IrreducibleSpace α] (x : α) : genericPoint α ⤳ x := - (IsIrreducible.genericPoint_spec _).specializes (by simp) + (IsIrreducible.isGenericPoint_genericPoint_closure _).specializes (by simp) attribute [local instance] specializationOrder @@ -149,7 +163,7 @@ noncomputable def irreducibleSetEquivPoints [QuasiSober α] [T0Space α] : simp only [IsIrreducible.genericPoint_closure_eq, TopologicalSpace.IrreducibleCloseds.coe_mk, closure_eq_iff_isClosed.mpr s.3] rfl - right_inv x := isIrreducible_singleton.closure.genericPoint_spec.eq + right_inv x := isIrreducible_singleton.closure.isGenericPoint_genericPoint_closure.eq (by rw [closure_closure]; exact isGenericPoint_closure) map_rel_iff' := by rintro ⟨s, hs, hs'⟩ ⟨t, ht, ht'⟩ @@ -157,7 +171,7 @@ noncomputable def irreducibleSetEquivPoints [QuasiSober α] [T0Space α] : simp [hs'.closure_eq, ht'.closure_eq] rfl -theorem ClosedEmbedding.quasiSober {f : α → β} (hf : ClosedEmbedding f) [QuasiSober β] : +theorem IsClosedEmbedding.quasiSober {f : α → β} (hf : IsClosedEmbedding f) [QuasiSober β] : QuasiSober α where sober hS hS' := by have hS'' := hS.image f hf.continuous.continuousOn @@ -167,12 +181,15 @@ theorem ClosedEmbedding.quasiSober {f : α → β} (hf : ClosedEmbedding f) [Qua apply image_injective.mpr hf.inj rw [← hx.def, ← hf.closure_image_eq, image_singleton] -theorem OpenEmbedding.quasiSober {f : α → β} (hf : OpenEmbedding f) [QuasiSober β] : +@[deprecated (since := "2024-10-20")] +alias ClosedEmbedding.quasiSober := IsClosedEmbedding.quasiSober + +theorem IsOpenEmbedding.quasiSober {f : α → β} (hf : IsOpenEmbedding f) [QuasiSober β] : QuasiSober α where sober hS hS' := by have hS'' := hS.image f hf.continuous.continuousOn obtain ⟨x, hx⟩ := QuasiSober.sober hS''.closure isClosed_closure - obtain ⟨T, hT, rfl⟩ := hf.toInducing.isClosed_iff.mp hS' + obtain ⟨T, hT, rfl⟩ := hf.isInducing.isClosed_iff.mp hS' rw [image_preimage_eq_inter_range] at hx hS'' have hxT : x ∈ T := by rw [← hT.closure_eq] @@ -183,13 +200,16 @@ theorem OpenEmbedding.quasiSober {f : α → β} (hf : OpenEmbedding f) [QuasiSo simpa using subset_closure use y change _ = _ - rw [hf.toEmbedding.closure_eq_preimage_closure_image, image_singleton, show _ = _ from hx] + rw [hf.isEmbedding.closure_eq_preimage_closure_image, image_singleton, show _ = _ from hx] apply image_injective.mpr hf.inj ext z simp only [image_preimage_eq_inter_range, mem_inter_iff, and_congr_left_iff] exact fun hy => ⟨fun h => hT.closure_eq ▸ closure_mono inter_subset_left h, fun h => subset_closure ⟨h, hy⟩⟩ +@[deprecated (since := "2024-10-18")] +alias OpenEmbedding.quasiSober := IsOpenEmbedding.quasiSober + /-- A space is quasi sober if it can be covered by open quasi sober subsets. -/ theorem quasiSober_of_open_cover (S : Set (Set α)) (hS : ∀ s : S, IsOpen (s : Set α)) [hS' : ∀ s : S, QuasiSober s] (hS'' : ⋃₀ S = ⊤) : QuasiSober α := by @@ -201,15 +221,16 @@ theorem quasiSober_of_open_cover (S : Set (Set α)) (hS : ∀ s : S, IsOpen (s : trivial haveI : QuasiSober U := hS' ⟨U, hU⟩ have H : IsPreirreducible ((↑) ⁻¹' t : Set U) := - h.2.preimage (hS ⟨U, hU⟩).openEmbedding_subtype_val + h.2.preimage (hS ⟨U, hU⟩).isOpenEmbedding_subtypeVal replace H : IsIrreducible ((↑) ⁻¹' t : Set U) := ⟨⟨⟨x, hU'⟩, by simpa using hx⟩, H⟩ use H.genericPoint - have := continuous_subtype_val.closure_preimage_subset _ H.genericPoint_spec.mem + have := continuous_subtype_val.closure_preimage_subset _ H.isGenericPoint_genericPoint_closure.mem rw [h'.closure_eq] at this apply le_antisymm · apply h'.closure_subset_iff.mpr simpa using this - rw [← image_singleton, ← closure_image_closure continuous_subtype_val, H.genericPoint_spec.def] + rw [← image_singleton, ← closure_image_closure continuous_subtype_val, + H.isGenericPoint_genericPoint_closure.def] refine (subset_closure_inter_of_isPreirreducible_of_isOpen h.2 (hS ⟨U, hU⟩) ⟨x, hx, hU'⟩).trans (closure_mono ?_) rw [inter_comm t, ← Subtype.image_preimage_coe] @@ -222,3 +243,68 @@ instance (priority := 100) T2Space.quasiSober [T2Space α] : QuasiSober α where exact ⟨x, closure_singleton⟩ end Sober + +section genericPoints + +variable (α) in +/-- The set of generic points of irreducible components. -/ +def genericPoints : Set α := { x | closure {x} ∈ irreducibleComponents α } + +namespace genericPoints + +/-- The irreducible component of a generic point -/ +def component (x : genericPoints α) : irreducibleComponents α := + ⟨closure {x.1}, x.2⟩ + +lemma isGenericPoint (x : genericPoints α) : IsGenericPoint x.1 (component x).1 := rfl + +lemma component_injective [T0Space α] : Function.Injective (component (α := α)) := + fun x y e ↦ Subtype.ext ((isGenericPoint x).eq (e ▸ isGenericPoint y)) + +/-- The generic point of an irreducible component. -/ +noncomputable +def ofComponent [QuasiSober α] (x : irreducibleComponents α) : genericPoints α := + ⟨x.2.1.genericPoint, show _ ∈ irreducibleComponents α from + (x.2.1.isGenericPoint_genericPoint (isClosed_of_mem_irreducibleComponents x.1 x.2)).symm ▸ x.2⟩ + +lemma isGenericPoint_ofComponent [QuasiSober α] (x : irreducibleComponents α) : + IsGenericPoint (ofComponent x).1 x := + x.2.1.isGenericPoint_genericPoint (isClosed_of_mem_irreducibleComponents x.1 x.2) + +@[simp] +lemma component_ofComponent [QuasiSober α] (x : irreducibleComponents α) : + component (ofComponent x) = x := + Subtype.ext (isGenericPoint_ofComponent x) + +@[simp] +lemma ofComponent_component [T0Space α] [QuasiSober α] (x : genericPoints α) : + ofComponent (component x) = x := + component_injective (component_ofComponent _) + +lemma component_surjective [QuasiSober α] : Function.Surjective (component (α := α)) := + Function.HasRightInverse.surjective ⟨ofComponent, component_ofComponent⟩ + +lemma finite [T0Space α] (h : (irreducibleComponents α).Finite) : (genericPoints α).Finite := + @Finite.of_injective _ _ h _ component_injective + +/-- In a sober space, the generic points corresponds bijectively to irreducible components -/ +@[simps] +noncomputable +def equiv [T0Space α] [QuasiSober α] : genericPoints α ≃ irreducibleComponents α := + ⟨component, ofComponent, ofComponent_component, component_ofComponent⟩ + +lemma closure [QuasiSober α] : closure (genericPoints α) = Set.univ := by + refine Set.eq_univ_iff_forall.mpr fun x ↦ Set.subset_def.mp ?_ x mem_irreducibleComponent + refine (isGenericPoint_ofComponent + ⟨_, irreducibleComponent_mem_irreducibleComponents x⟩).symm.trans_subset (closure_mono ?_) + exact Set.singleton_subset_iff.mpr (ofComponent _).2 + +end genericPoints + +lemma genericPoints_eq_singleton [QuasiSober α] [IrreducibleSpace α] [T0Space α] : + genericPoints α = {genericPoint α} := by + ext x + rw [genericPoints, irreducibleComponents_eq_singleton] + exact ⟨((genericPoint_spec α).eq · |>.symm), (· ▸ genericPoint_spec α)⟩ + +end genericPoints diff --git a/Mathlib/Topology/Specialization.lean b/Mathlib/Topology/Specialization.lean index 0cec4f5ed17b5..bd57a351804bd 100644 --- a/Mathlib/Topology/Specialization.lean +++ b/Mathlib/Topology/Specialization.lean @@ -6,7 +6,6 @@ Authors: Yaël Dillies import Mathlib.Order.Category.Preord import Mathlib.Topology.Category.TopCat.Basic import Mathlib.Topology.ContinuousMap.Basic -import Mathlib.Topology.Separation import Mathlib.Topology.Order.UpperLowerSetTopology /-! @@ -63,7 +62,7 @@ instance instPartialOrder [T0Space α] : PartialOrder (Specialization α) := spe orders. -/ def map (f : C(α, β)) : Specialization α →o Specialization β where toFun := toEquiv ∘ f ∘ ofEquiv - monotone' := f.continuous.specialization_monotone + monotone' := (map_continuous f).specialization_monotone @[simp] lemma map_id : map (ContinuousMap.id α) = OrderHom.id := rfl @[simp] lemma map_comp (g : C(β, γ)) (f : C(α, β)) : map (g.comp f) = (map g).comp (map f) := rfl diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Support.lean index e5e52b3d9982f..2a3e19012527f 100644 --- a/Mathlib/Topology/Support.lean +++ b/Mathlib/Topology/Support.lean @@ -6,7 +6,7 @@ Authors: Floris van Doorn, Patrick Massot import Mathlib.Algebra.GroupWithZero.Indicator import Mathlib.Algebra.Order.Group.Unbundled.Abs import Mathlib.Algebra.Module.Basic -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # The topological support of a function @@ -32,7 +32,7 @@ Furthermore, we say that `f` has compact support if the topological support of ` open Function Set Filter Topology -variable {X α α' β γ δ M E R : Type*} +variable {X α α' β γ δ M R : Type*} section One @@ -98,9 +98,9 @@ theorem mulTSupport_mul [TopologicalSpace X] [Monoid α] {f g : X → α} : section -variable [TopologicalSpace α] [TopologicalSpace α'] -variable [One β] [One γ] [One δ] -variable {g : β → γ} {f : α → β} {f₂ : α → γ} {m : β → γ → δ} {x : α} +variable [TopologicalSpace α] +variable [One β] +variable {f : α → β} {x : α} @[to_additive] theorem not_mem_mulTSupport_iff_eventuallyEq : x ∉ mulTSupport f ↔ f =ᶠ[𝓝 x] 1 := by @@ -119,7 +119,7 @@ end section CompactSupport variable [TopologicalSpace α] [TopologicalSpace α'] variable [One β] [One γ] [One δ] -variable {g : β → γ} {f : α → β} {f₂ : α → γ} {m : β → γ → δ} {x : α} +variable {g : β → γ} {f : α → β} {f₂ : α → γ} {m : β → γ → δ} /-- A function `f` *has compact multiplicative support* or is *compactly supported* if the closure of the multiplicative support of `f` is compact. In a T₂ space this is equivalent to `f` being equal @@ -201,13 +201,16 @@ theorem _root_.hasCompactMulSupport_comp_left (hg : ∀ {x}, g x = 1 ↔ x = 1) simp_rw [hasCompactMulSupport_def, mulSupport_comp_eq g (@hg) f] @[to_additive] -theorem comp_closedEmbedding (hf : HasCompactMulSupport f) {g : α' → α} - (hg : ClosedEmbedding g) : HasCompactMulSupport (f ∘ g) := by +theorem comp_isClosedEmbedding (hf : HasCompactMulSupport f) {g : α' → α} + (hg : IsClosedEmbedding g) : HasCompactMulSupport (f ∘ g) := by rw [hasCompactMulSupport_def, Function.mulSupport_comp_eq_preimage] refine IsCompact.of_isClosed_subset (hg.isCompact_preimage hf) isClosed_closure ?_ - rw [hg.toEmbedding.closure_eq_preimage_closure_image] + rw [hg.isEmbedding.closure_eq_preimage_closure_image] exact preimage_mono (closure_mono <| image_preimage_subset _ _) +@[deprecated (since := "2024-10-20")] +alias comp_closedEmbedding := comp_isClosedEmbedding + @[to_additive] theorem comp₂_left (hf : HasCompactMulSupport f) (hf₂ : HasCompactMulSupport f₂) (hm : m 1 1 = 1) : @@ -257,7 +260,7 @@ theorem continuous_extend_one [TopologicalSpace β] {U : Set α'} (hU : IsOpen U continuous_of_mulTSupport fun x h ↦ by rw [show x = ↑(⟨x, Subtype.coe_image_subset _ _ (supp.mulTSupport_extend_one_subset continuous_subtype_val h)⟩ : U) by rfl, - ← (hU.openEmbedding_subtype_val).continuousAt_iff, extend_comp Subtype.val_injective] + ← (hU.isOpenEmbedding_subtypeVal).continuousAt_iff, extend_comp Subtype.val_injective] exact cont.continuousAt /-- If `f` has compact multiplicative support, then `f` tends to 1 at infinity. -/ @@ -294,7 +297,7 @@ section CompactSupport2 section Monoid variable [TopologicalSpace α] [MulOneClass β] -variable {f f' : α → β} {x : α} +variable {f f' : α → β} @[to_additive] theorem HasCompactMulSupport.mul (hf : HasCompactMulSupport f) (hf' : HasCompactMulSupport f') : @@ -320,7 +323,7 @@ end DivisionMonoid section SMulZeroClass variable [TopologicalSpace α] [Zero M] [SMulZeroClass R M] -variable {f : α → R} {f' : α → M} {x : α} +variable {f : α → R} {f' : α → M} theorem HasCompactSupport.smul_left (hf : HasCompactSupport f') : HasCompactSupport (f • f') := by rw [hasCompactSupport_iff_eventuallyEq] at hf ⊢ @@ -331,7 +334,7 @@ end SMulZeroClass section SMulWithZero variable [TopologicalSpace α] [Zero R] [Zero M] [SMulWithZero R M] -variable {f : α → R} {f' : α → M} {x : α} +variable {f : α → R} {f' : α → M} theorem HasCompactSupport.smul_right (hf : HasCompactSupport f) : HasCompactSupport (f • f') := by rw [hasCompactSupport_iff_eventuallyEq] at hf ⊢ @@ -345,7 +348,7 @@ end SMulWithZero section MulZeroClass variable [TopologicalSpace α] [MulZeroClass β] -variable {f f' : α → β} {x : α} +variable {f f' : α → β} theorem HasCompactSupport.mul_right (hf : HasCompactSupport f) : HasCompactSupport (f * f') := by rw [hasCompactSupport_iff_eventuallyEq] at hf ⊢ @@ -359,8 +362,7 @@ end MulZeroClass section OrderedAddGroup -variable {α β : Type*} [TopologicalSpace α] [AddGroup β] [Lattice β] - [CovariantClass β β (· + ·) (· ≤ ·)] +variable [TopologicalSpace α] [AddGroup β] [Lattice β] [AddLeftMono β] protected theorem HasCompactSupport.abs {f : α → β} (hf : HasCompactSupport f) : HasCompactSupport |f| := diff --git a/Mathlib/Topology/TietzeExtension.lean b/Mathlib/Topology/TietzeExtension.lean index b1e175559e9fd..6cd8c7e9d7af5 100644 --- a/Mathlib/Topology/TietzeExtension.lean +++ b/Mathlib/Topology/TietzeExtension.lean @@ -20,7 +20,7 @@ bounded function, then there exists a bounded extension of the same norm. The proof mostly follows . We patch a small gap in the proof for unbounded functions, see -`exists_extension_forall_exists_le_ge_of_closedEmbedding`. +`exists_extension_forall_exists_le_ge_of_isClosedEmbedding`. In addition we provide a class `TietzeExtension` encoding the idea that a topological space satisfies the Tietze extension theorem. This allows us to get a version of the Tietze extension @@ -68,9 +68,9 @@ theorem ContinuousMap.exists_restrict_eq (hs : IsClosed s) (f : C(s, Y)) : nonempty topological space `X₁` into a normal topological space `X`. Let `f` be a continuous function on `X₁` with values in a `TietzeExtension` space `Y`. Then there exists a continuous function `g : C(X, Y)` such that `g ∘ e = f`. -/ -theorem ContinuousMap.exists_extension (he : ClosedEmbedding e) (f : C(X₁, Y)) : +theorem ContinuousMap.exists_extension (he : IsClosedEmbedding e) (f : C(X₁, Y)) : ∃ (g : C(X, Y)), g.comp ⟨e, he.continuous⟩ = f := by - let e' : X₁ ≃ₜ Set.range e := Homeomorph.ofEmbedding _ he.toEmbedding + let e' : X₁ ≃ₜ Set.range e := Homeomorph.ofIsEmbedding _ he.isEmbedding obtain ⟨g, hg⟩ := (f.comp e'.symm).exists_restrict_eq he.isClosed_range exact ⟨g, by ext x; simpa using congr($(hg) ⟨e' x, x, rfl⟩)⟩ @@ -81,7 +81,7 @@ continuous function `g : C(X, Y)` such that `g ∘ e = f`. This version is provided for convenience and backwards compatibility. Here the composition is phrased in terms of bare functions. -/ -theorem ContinuousMap.exists_extension' (he : ClosedEmbedding e) (f : C(X₁, Y)) : +theorem ContinuousMap.exists_extension' (he : IsClosedEmbedding e) (f : C(X₁, Y)) : ∃ (g : C(X, Y)), g ∘ e = f := f.exists_extension he |>.imp fun g hg ↦ by ext x; congrm($(hg) x) @@ -104,7 +104,7 @@ the radius is strictly positive, so finding this as an instance will fail. Instead, it is intended to be used as a constructor for theorems about sets which *do* satisfy `[TietzeExtension t]` under some hypotheses. -/ -theorem ContinuousMap.exists_extension_forall_mem (he : ClosedEmbedding e) +theorem ContinuousMap.exists_extension_forall_mem (he : IsClosedEmbedding e) {Y : Type v} [TopologicalSpace Y] (f : C(X₁, Y)) {t : Set Y} (hf : ∀ x, f x ∈ t) [ht : TietzeExtension.{u, v} t] : ∃ (g : C(X, Y)), (∀ x, g x ∈ t) ∧ g.comp ⟨e, he.continuous⟩ = f := by @@ -126,9 +126,9 @@ instance Prod.instTietzeExtension {Y : Type v} {Z : Type w} [TopologicalSpace Y] obtain ⟨g₂, hg₂⟩ := (ContinuousMap.snd.comp f).exists_restrict_eq hs exact ⟨g₁.prodMk g₂, by ext1 x; congrm(($(hg₁) x), $(hg₂) x)⟩ -instance Unique.instTietzeExtension {Y : Type v} [TopologicalSpace Y] [Unique Y] : - TietzeExtension.{u, v} Y where - exists_restrict_eq' _ _ f := ⟨.const _ default, by ext; subsingleton⟩ +instance Unique.instTietzeExtension {Y : Type v} [TopologicalSpace Y] + [Nonempty Y] [Subsingleton Y] : TietzeExtension.{u, v} Y where + exists_restrict_eq' _ _ f := ‹Nonempty Y›.elim fun y ↦ ⟨.const _ y, by ext; subsingleton⟩ /-- Any retract of a `TietzeExtension` space is one itself. -/ theorem TietzeExtension.of_retract {Y : Type v} {Z : Type w} [TopologicalSpace Y] @@ -166,7 +166,7 @@ namespace BoundedContinuousFunction of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the norm `‖g‖ ≤ ‖f‖ / 3` such that the distance between `g ∘ e` and `f` is at most `(2 / 3) * ‖f‖`. -/ -theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbedding e) : +theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, ‖g‖ ≤ ‖f‖ / 3 ∧ dist (g.compContinuous e) f ≤ 2 / 3 * ‖f‖ := by have h3 : (0 : ℝ) < 3 := by norm_num1 have h23 : 0 < (2 / 3 : ℝ) := by norm_num1 @@ -216,8 +216,8 @@ theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbed embedding and bundled composition. If `e : C(X, Y)` is a closed embedding of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the same norm such that `g ∘ e = f`. -/ -theorem exists_extension_norm_eq_of_closedEmbedding' (f : X →ᵇ ℝ) (e : C(X, Y)) - (he : ClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, ‖g‖ = ‖f‖ ∧ g.compContinuous e = f := by +theorem exists_extension_norm_eq_of_isClosedEmbedding' (f : X →ᵇ ℝ) (e : C(X, Y)) + (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, ‖g‖ = ‖f‖ ∧ g.compContinuous e = f := by /- For the proof, we iterate `tietze_extension_step`. Each time we apply it to the difference between the previous approximation and `f`. -/ choose F hF_norm hF_dist using fun f : X →ᵇ ℝ => tietze_extension_step f e he @@ -261,36 +261,42 @@ theorem exists_extension_norm_eq_of_closedEmbedding' (f : X →ᵇ ℝ) (e : C(X · rw [← hge] exact norm_compContinuous_le _ _ +@[deprecated (since := "2024-10-20")] +alias exists_extension_norm_eq_of_closedEmbedding' := exists_extension_norm_eq_of_isClosedEmbedding' + /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version with a closed embedding and unbundled composition. If `e : C(X, Y)` is a closed embedding of a topological space into a normal topological space and `f : X →ᵇ ℝ` is a bounded continuous function, then there exists a bounded continuous function `g : Y →ᵇ ℝ` of the same norm such that `g ∘ e = f`. -/ -theorem exists_extension_norm_eq_of_closedEmbedding (f : X →ᵇ ℝ) {e : X → Y} - (he : ClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, ‖g‖ = ‖f‖ ∧ g ∘ e = f := by - rcases exists_extension_norm_eq_of_closedEmbedding' f ⟨e, he.continuous⟩ he with ⟨g, hg, rfl⟩ +theorem exists_extension_norm_eq_of_isClosedEmbedding (f : X →ᵇ ℝ) {e : X → Y} + (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, ‖g‖ = ‖f‖ ∧ g ∘ e = f := by + rcases exists_extension_norm_eq_of_isClosedEmbedding' f ⟨e, he.continuous⟩ he with ⟨g, hg, rfl⟩ exact ⟨g, hg, rfl⟩ +@[deprecated (since := "2024-10-20")] +alias exists_extension_norm_eq_of_closedEmbedding := exists_extension_norm_eq_of_isClosedEmbedding + /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version for a closed set. If `f` is a bounded continuous real-valued function defined on a closed set in a normal topological space, then it can be extended to a bounded continuous function of the same norm defined on the whole space. -/ theorem exists_norm_eq_restrict_eq_of_closed {s : Set Y} (f : s →ᵇ ℝ) (hs : IsClosed s) : ∃ g : Y →ᵇ ℝ, ‖g‖ = ‖f‖ ∧ g.restrict s = f := - exists_extension_norm_eq_of_closedEmbedding' f ((ContinuousMap.id _).restrict s) - (closedEmbedding_subtype_val hs) + exists_extension_norm_eq_of_isClosedEmbedding' f ((ContinuousMap.id _).restrict s) + hs.isClosedEmbedding_subtypeVal /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version for a closed embedding and a bounded continuous function that takes values in a non-trivial closed interval. -See also `exists_extension_forall_mem_of_closedEmbedding` for a more general statement that works +See also `exists_extension_forall_mem_of_isClosedEmbedding` for a more general statement that works for any interval (finite or infinite, open or closed). If `e : X → Y` is a closed embedding and `f : X →ᵇ ℝ` is a bounded continuous function such that `f x ∈ [a, b]` for all `x`, where `a ≤ b`, then there exists a bounded continuous function `g : Y →ᵇ ℝ` such that `g y ∈ [a, b]` for all `y` and `g ∘ e = f`. -/ -theorem exists_extension_forall_mem_Icc_of_closedEmbedding (f : X →ᵇ ℝ) {a b : ℝ} {e : X → Y} - (hf : ∀ x, f x ∈ Icc a b) (hle : a ≤ b) (he : ClosedEmbedding e) : +theorem exists_extension_forall_mem_Icc_of_isClosedEmbedding (f : X →ᵇ ℝ) {a b : ℝ} {e : X → Y} + (hf : ∀ x, f x ∈ Icc a b) (hle : a ≤ b) (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, (∀ y, g y ∈ Icc a b) ∧ g ∘ e = f := by - rcases exists_extension_norm_eq_of_closedEmbedding (f - const X ((a + b) / 2)) he with + rcases exists_extension_norm_eq_of_isClosedEmbedding (f - const X ((a + b) / 2)) he with ⟨g, hgf, hge⟩ refine ⟨const Y ((a + b) / 2) + g, fun y => ?_, ?_⟩ · suffices ‖f - const X ((a + b) / 2)‖ ≤ (b - a) / 2 by @@ -302,13 +308,17 @@ theorem exists_extension_forall_mem_Icc_of_closedEmbedding (f : X →ᵇ ℝ) {a have : g (e x) = f x - (a + b) / 2 := congr_fun hge x simp [this] +@[deprecated (since := "2024-10-20")] +alias exists_extension_forall_mem_Icc_of_closedEmbedding := + exists_extension_forall_mem_Icc_of_isClosedEmbedding + /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version for a closed embedding. Let `e` be a closed embedding of a nonempty topological space `X` into a normal topological space `Y`. Let `f` be a bounded continuous real-valued function on `X`. Then there exists a bounded continuous function `g : Y →ᵇ ℝ` such that `g ∘ e = f` and each value `g y` belongs to a closed interval `[f x₁, f x₂]` for some `x₁` and `x₂`. -/ -theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f : X →ᵇ ℝ) - {e : X → Y} (he : ClosedEmbedding e) : +theorem exists_extension_forall_exists_le_ge_of_isClosedEmbedding [Nonempty X] (f : X →ᵇ ℝ) + {e : X → Y} (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, (∀ y, ∃ x₁ x₂, g y ∈ Icc (f x₁) (f x₂)) ∧ g ∘ e = f := by inhabit X -- Put `a = ⨅ x, f x` and `b = ⨆ x, f x` @@ -321,7 +331,7 @@ theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f rcases hle.eq_or_lt with (rfl | hlt) · have : ∀ x, f x = a := by simpa using hmem use const Y a - simp [this, Function.funext_iff] + simp [this, funext_iff] -- Put `c = (a + b) / 2`. Then `a < c < b` and `c - a = b - c`. set c := (a + b) / 2 have hac : a < c := left_lt_add_div_two.2 hlt @@ -329,12 +339,12 @@ theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f have hsub : c - a = b - c := by field_simp [c] ring - /- Due to `exists_extension_forall_mem_Icc_of_closedEmbedding`, there exists an extension `g` + /- Due to `exists_extension_forall_mem_Icc_of_isClosedEmbedding`, there exists an extension `g` such that `g y ∈ [a, b]` for all `y`. However, if `a` and/or `b` do not belong to the range of `f`, then we need to ensure that these points do not belong to the range of `g`. This is done in two almost identical steps. First we deal with the case `∀ x, f x ≠ a`. -/ obtain ⟨g, hg_mem, hgf⟩ : ∃ g : Y →ᵇ ℝ, (∀ y, ∃ x, g y ∈ Icc (f x) b) ∧ g ∘ e = f := by - rcases exists_extension_forall_mem_Icc_of_closedEmbedding f hmem hle he with ⟨g, hg_mem, hgf⟩ + rcases exists_extension_forall_mem_Icc_of_isClosedEmbedding f hmem hle he with ⟨g, hg_mem, hgf⟩ -- If `a ∈ range f`, then we are done. rcases em (∃ x, f x = a) with (⟨x, rfl⟩ | ha') · exact ⟨g, fun y => ⟨x, hg_mem _⟩, hgf⟩ @@ -412,6 +422,10 @@ theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f · refine ⟨xl y, xu, ?_, hyxu.le⟩ simp [dg0 (Or.inr hc), hxl] +@[deprecated (since := "2024-10-20")] +alias exists_extension_forall_exists_le_ge_of_closedEmbedding := + exists_extension_forall_exists_le_ge_of_isClosedEmbedding + /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version for a closed embedding. Let `e` be a closed embedding of a nonempty topological space `X` into a normal topological space `Y`. Let `f` be a bounded continuous real-valued function on `X`. Let `t` be @@ -419,17 +433,21 @@ a nonempty convex set of real numbers (we use `OrdConnected` instead of `Convex` deduce this argument by typeclass search) such that `f x ∈ t` for all `x`. Then there exists a bounded continuous real-valued function `g : Y →ᵇ ℝ` such that `g y ∈ t` for all `y` and `g ∘ e = f`. -/ -theorem exists_extension_forall_mem_of_closedEmbedding (f : X →ᵇ ℝ) {t : Set ℝ} {e : X → Y} - [hs : OrdConnected t] (hf : ∀ x, f x ∈ t) (hne : t.Nonempty) (he : ClosedEmbedding e) : +theorem exists_extension_forall_mem_of_isClosedEmbedding (f : X →ᵇ ℝ) {t : Set ℝ} {e : X → Y} + [hs : OrdConnected t] (hf : ∀ x, f x ∈ t) (hne : t.Nonempty) (he : IsClosedEmbedding e) : ∃ g : Y →ᵇ ℝ, (∀ y, g y ∈ t) ∧ g ∘ e = f := by cases isEmpty_or_nonempty X · rcases hne with ⟨c, hc⟩ exact ⟨const Y c, fun _ => hc, funext fun x => isEmptyElim x⟩ - rcases exists_extension_forall_exists_le_ge_of_closedEmbedding f he with ⟨g, hg, hgf⟩ + rcases exists_extension_forall_exists_le_ge_of_isClosedEmbedding f he with ⟨g, hg, hgf⟩ refine ⟨g, fun y => ?_, hgf⟩ rcases hg y with ⟨xl, xu, h⟩ exact hs.out (hf _) (hf _) h +@[deprecated (since := "2024-10-20")] +alias exists_extension_forall_mem_of_closedEmbedding := + exists_extension_forall_mem_of_isClosedEmbedding + /-- **Tietze extension theorem** for real-valued bounded continuous maps, a version for a closed set. Let `s` be a closed set in a normal topological space `Y`. Let `f` be a bounded continuous real-valued function on `s`. Let `t` be a nonempty convex set of real numbers (we use @@ -439,9 +457,8 @@ that `f x ∈ t` for all `x : s`. Then there exists a bounded continuous real-va theorem exists_forall_mem_restrict_eq_of_closed {s : Set Y} (f : s →ᵇ ℝ) (hs : IsClosed s) {t : Set ℝ} [OrdConnected t] (hf : ∀ x, f x ∈ t) (hne : t.Nonempty) : ∃ g : Y →ᵇ ℝ, (∀ y, g y ∈ t) ∧ g.restrict s = f := by - rcases exists_extension_forall_mem_of_closedEmbedding f hf hne - (closedEmbedding_subtype_val hs) with - ⟨g, hg, hgf⟩ + obtain ⟨g, hg, hgf⟩ := + exists_extension_forall_mem_of_isClosedEmbedding f hf hne hs.isClosedEmbedding_subtypeVal exact ⟨g, hg, DFunLike.coe_injective hgf⟩ end BoundedContinuousFunction @@ -454,8 +471,8 @@ topological space `Y`. Let `f` be a continuous real-valued function on `X`. Let convex set of real numbers (we use `OrdConnected` instead of `Convex` to automatically deduce this argument by typeclass search) such that `f x ∈ t` for all `x`. Then there exists a continuous real-valued function `g : C(Y, ℝ)` such that `g y ∈ t` for all `y` and `g ∘ e = f`. -/ -theorem exists_extension_forall_mem_of_closedEmbedding (f : C(X, ℝ)) {t : Set ℝ} {e : X → Y} - [hs : OrdConnected t] (hf : ∀ x, f x ∈ t) (hne : t.Nonempty) (he : ClosedEmbedding e) : +theorem exists_extension_forall_mem_of_isClosedEmbedding (f : C(X, ℝ)) {t : Set ℝ} {e : X → Y} + [hs : OrdConnected t] (hf : ∀ x, f x ∈ t) (hne : t.Nonempty) (he : IsClosedEmbedding e) : ∃ g : C(Y, ℝ), (∀ y, g y ∈ t) ∧ g ∘ e = f := by have h : ℝ ≃o Ioo (-1 : ℝ) 1 := orderIsoIooNegOneOne ℝ let F : X →ᵇ ℝ := @@ -474,7 +491,7 @@ theorem exists_extension_forall_mem_of_closedEmbedding (f : C(X, ℝ)) {t : Set rcases hz with ⟨z, hz, rfl⟩ exact ⟨z, hs.out hx hy hz, rfl⟩ have hFt : ∀ x, F x ∈ t' := fun x => mem_image_of_mem _ (hf x) - rcases F.exists_extension_forall_mem_of_closedEmbedding hFt (hne.image _) he with ⟨G, hG, hGF⟩ + rcases F.exists_extension_forall_mem_of_isClosedEmbedding hFt (hne.image _) he with ⟨G, hG, hGF⟩ let g : C(Y, ℝ) := ⟨h.symm ∘ codRestrict G _ fun y => ht_sub (hG y), h.symm.continuous.comp <| G.continuous.subtype_mk _⟩ @@ -487,8 +504,15 @@ theorem exists_extension_forall_mem_of_closedEmbedding (f : C(X, ℝ)) {t : Set · ext x exact hgG.2 (congr_fun hGF _) +@[deprecated (since := "2024-10-20")] +alias exists_extension_forall_mem_of_closedEmbedding := + exists_extension_forall_mem_of_isClosedEmbedding + @[deprecated (since := "2024-01-16")] -alias exists_extension_of_closedEmbedding := exists_extension' +alias exists_extension_of_isClosedEmbedding := exists_extension' + +@[deprecated (since := "2024-10-20")] +alias exists_extension_of_closedEmbedding := exists_extension_of_isClosedEmbedding /-- **Tietze extension theorem** for real-valued continuous maps, a version for a closed set. Let `s` be a closed set in a normal topological space `Y`. Let `f` be a continuous real-valued function @@ -500,7 +524,7 @@ theorem exists_restrict_eq_forall_mem_of_closed {s : Set Y} (f : C(s, ℝ)) {t : [OrdConnected t] (ht : ∀ x, f x ∈ t) (hne : t.Nonempty) (hs : IsClosed s) : ∃ g : C(Y, ℝ), (∀ y, g y ∈ t) ∧ g.restrict s = f := let ⟨g, hgt, hgf⟩ := - exists_extension_forall_mem_of_closedEmbedding f ht hne (closedEmbedding_subtype_val hs) + exists_extension_forall_mem_of_isClosedEmbedding f ht hne hs.isClosedEmbedding_subtypeVal ⟨g, hgt, coe_injective hgf⟩ @[deprecated (since := "2024-01-16")] alias exists_restrict_eq_of_closed := exists_restrict_eq diff --git a/Mathlib/Topology/UniformSpace/AbsoluteValue.lean b/Mathlib/Topology/UniformSpace/AbsoluteValue.lean index 55efcadaf7133..b10faf84a84ef 100644 --- a/Mathlib/Topology/UniformSpace/AbsoluteValue.lean +++ b/Mathlib/Topology/UniformSpace/AbsoluteValue.lean @@ -34,7 +34,7 @@ variable {R : Type*} [CommRing R] (abv : AbsoluteValue R 𝕜) /-- The uniform structure coming from an absolute value. -/ def uniformSpace : UniformSpace R := .ofFun (fun x y => abv (y - x)) (by simp) (fun x y => abv.map_sub y x) - (fun x y z => (abv.sub_le _ _ _).trans_eq (add_comm _ _)) + (fun _ _ _ => (abv.sub_le _ _ _).trans_eq (add_comm _ _)) fun ε ε0 => ⟨ε / 2, half_pos ε0, fun _ h₁ _ h₂ => (add_lt_add h₁ h₂).trans_eq (add_halves ε)⟩ theorem hasBasis_uniformity : diff --git a/Mathlib/Topology/UniformSpace/AbstractCompletion.lean b/Mathlib/Topology/UniformSpace/AbstractCompletion.lean index d71b406019079..d5458eff1e284 100644 --- a/Mathlib/Topology/UniformSpace/AbstractCompletion.lean +++ b/Mathlib/Topology/UniformSpace/AbstractCompletion.lean @@ -66,7 +66,7 @@ structure AbstractCompletion (α : Type u) [UniformSpace α] where /-- The completion is a T₀ space. -/ separation : T0Space space /-- The map into the completion is uniform-inducing. -/ - uniformInducing : UniformInducing coe + isUniformInducing : IsUniformInducing coe /-- The map into the completion has dense range. -/ dense : DenseRange coe @@ -81,18 +81,20 @@ local notation "hatα" => pkg.space local notation "ι" => pkg.coe +@[deprecated (since := "2024-10-08")] alias uniformInducing := isUniformInducing + /-- If `α` is complete, then it is an abstract completion of itself. -/ def ofComplete [T0Space α] [CompleteSpace α] : AbstractCompletion α := - mk α id inferInstance inferInstance inferInstance uniformInducing_id denseRange_id + mk α id inferInstance inferInstance inferInstance .id denseRange_id theorem closure_range : closure (range ι) = univ := pkg.dense.closure_range theorem isDenseInducing : IsDenseInducing ι := - ⟨pkg.uniformInducing.inducing, pkg.dense⟩ + ⟨pkg.isUniformInducing.isInducing, pkg.dense⟩ theorem uniformContinuous_coe : UniformContinuous ι := - UniformInducing.uniformContinuous pkg.uniformInducing + IsUniformInducing.uniformContinuous pkg.isUniformInducing theorem continuous_coe : Continuous ι := pkg.uniformContinuous_coe.continuous @@ -130,7 +132,7 @@ variable [CompleteSpace β] theorem uniformContinuous_extend : UniformContinuous (pkg.extend f) := by by_cases hf : UniformContinuous f · rw [pkg.extend_def hf] - exact uniformContinuous_uniformly_extend pkg.uniformInducing pkg.dense hf + exact uniformContinuous_uniformly_extend pkg.isUniformInducing pkg.dense hf · change UniformContinuous (ite _ _ _) rw [if_neg hf] exact uniformContinuous_of_const fun a b => by congr 1 @@ -305,7 +307,7 @@ protected def prod : AbstractCompletion (α × β) where uniformStruct := inferInstance complete := inferInstance separation := inferInstance - uniformInducing := UniformInducing.prod pkg.uniformInducing pkg'.uniformInducing + isUniformInducing := IsUniformInducing.prod pkg.isUniformInducing pkg'.isUniformInducing dense := pkg.dense.prodMap pkg'.dense end Prod diff --git a/Mathlib/Topology/UniformSpace/Ascoli.lean b/Mathlib/Topology/UniformSpace/Ascoli.lean index 0b702ae3a22f7..db22e34405916 100644 --- a/Mathlib/Topology/UniformSpace/Ascoli.lean +++ b/Mathlib/Topology/UniformSpace/Ascoli.lean @@ -20,15 +20,15 @@ a family of compact subsets of `X`, and `α` is a uniform space. convergence coincide on equicontinuous subsets. This is the key fact that makes equicontinuity important in functional analysis. We state various versions of it: - as an equality of `UniformSpace`s: `Equicontinuous.comap_uniformFun_eq` - - in terms of `UniformInducing`: `Equicontinuous.uniformInducing_uniformFun_iff_pi` - - in terms of `Inducing`: `Equicontinuous.inducing_uniformFun_iff_pi` + - in terms of `IsUniformInducing`: `Equicontinuous.isUniformInducing_uniformFun_iff_pi` + - in terms of `IsInducing`: `Equicontinuous.inducing_uniformFun_iff_pi` - in terms of convergence along a filter: `Equicontinuous.tendsto_uniformFun_iff_pi` * As a consequence, if `𝔖` is a family of compact subsets of `X`, then the uniform structures of uniform convergence on `𝔖` and pointwise convergence on `⋃₀ 𝔖` coincide on equicontinuous subsets. Again, we prove multiple variations: - as an equality of `UniformSpace`s: `EquicontinuousOn.comap_uniformOnFun_eq` - - in terms of `UniformInducing`: `EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi'` - - in terms of `Inducing`: `EquicontinuousOn.inducing_uniformOnFun_iff_pi'` + - in terms of `IsUniformInducing`: `EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi'` + - in terms of `IsInducing`: `EquicontinuousOn.inducing_uniformOnFun_iff_pi'` - in terms of convergence along a filter: `EquicontinuousOn.tendsto_uniformOnFun_iff_pi'` * The **Arzela-Ascoli theorem** follows from the previous fact and Tykhonov's theorem. All of its variations can be found under the `ArzelaAscoli` namespace. @@ -70,8 +70,7 @@ equicontinuity, uniform convergence, ascoli open Set Filter Uniformity Topology Function UniformConvergence -variable {ι X Y α β : Type*} [TopologicalSpace X] [UniformSpace α] [UniformSpace β] -variable {F : ι → X → α} {G : ι → β → α} +variable {ι X α : Type*} [TopologicalSpace X] [UniformSpace α] {F : ι → X → α} /-- Let `X` be a compact topological space, `α` a uniform space, and `F : ι → (X → α)` an equicontinuous family. Then, the uniform structures of uniform convergence and pointwise @@ -80,7 +79,7 @@ convergence induce the same uniform structure on `ι`. In other words, pointwise convergence and uniform convergence coincide on an equicontinuous subset of `X → α`. -Consider using `Equicontinuous.uniformInducing_uniformFun_iff_pi` and +Consider using `Equicontinuous.isUniformInducing_uniformFun_iff_pi` and `Equicontinuous.inducing_uniformFun_iff_pi` instead, to avoid rewriting instances. -/ theorem Equicontinuous.comap_uniformFun_eq [CompactSpace X] (F_eqcont : Equicontinuous F) : (UniformFun.uniformSpace X α).comap F = @@ -131,15 +130,19 @@ convergence induce the same uniform structure on `ι`. In other words, pointwise convergence and uniform convergence coincide on an equicontinuous subset of `X → α`. -This is a version of `Equicontinuous.comap_uniformFun_eq` stated in terms of `UniformInducing` +This is a version of `Equicontinuous.comap_uniformFun_eq` stated in terms of `IsUniformInducing` for convenuence. -/ -lemma Equicontinuous.uniformInducing_uniformFun_iff_pi [UniformSpace ι] [CompactSpace X] +lemma Equicontinuous.isUniformInducing_uniformFun_iff_pi [UniformSpace ι] [CompactSpace X] (F_eqcont : Equicontinuous F) : - UniformInducing (UniformFun.ofFun ∘ F) ↔ UniformInducing F := by - rw [uniformInducing_iff_uniformSpace, uniformInducing_iff_uniformSpace, + IsUniformInducing (UniformFun.ofFun ∘ F) ↔ IsUniformInducing F := by + rw [isUniformInducing_iff_uniformSpace, isUniformInducing_iff_uniformSpace, ← F_eqcont.comap_uniformFun_eq] rfl +@[deprecated (since := "2024-10-05")] +alias Equicontinuous.uniformInducing_uniformFun_iff_pi := + Equicontinuous.isUniformInducing_uniformFun_iff_pi + /-- Let `X` be a compact topological space, `α` a uniform space, and `F : ι → (X → α)` an equicontinuous family. Then, the topologies of uniform convergence and pointwise convergence induce the same topology on `ι`. @@ -147,12 +150,12 @@ the same topology on `ι`. In other words, pointwise convergence and uniform convergence coincide on an equicontinuous subset of `X → α`. -This is a consequence of `Equicontinuous.comap_uniformFun_eq`, stated in terms of `Inducing` +This is a consequence of `Equicontinuous.comap_uniformFun_eq`, stated in terms of `IsInducing` for convenuence. -/ lemma Equicontinuous.inducing_uniformFun_iff_pi [TopologicalSpace ι] [CompactSpace X] (F_eqcont : Equicontinuous F) : - Inducing (UniformFun.ofFun ∘ F) ↔ Inducing F := by - rw [inducing_iff, inducing_iff] + IsInducing (UniformFun.ofFun ∘ F) ↔ IsInducing F := by + rw [isInducing_iff, isInducing_iff] change (_ = (UniformFun.uniformSpace X α |>.comap F |>.toTopologicalSpace)) ↔ (_ = (Pi.uniformSpace _ |>.comap F |>.toTopologicalSpace)) rw [F_eqcont.comap_uniformFun_eq] @@ -182,7 +185,7 @@ theorem Equicontinuous.tendsto_uniformFun_iff_pi [CompactSpace X] continuous_id -- ... hence, as announced, the product topology and uniform convergence topology -- coincide on `S`. - have ind : Inducing (UniformFun.ofFun ∘ (↑) : S → X →ᵤ α) := + have ind : IsInducing (UniformFun.ofFun ∘ (↑) : S → X →ᵤ α) := hS.inducing_uniformFun_iff_pi.mpr ⟨rfl⟩ -- By construction, `f` is in `S`. have f_mem : f ∈ S := mem_closure_of_tendsto H range_mem_map @@ -206,7 +209,7 @@ uniform structure on `ι`. In particular, pointwise convergence and compact convergence coincide on an equicontinuous subset of `X → α`. -Consider using `EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi'` and +Consider using `EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi'` and `EquicontinuousOn.inducing_uniformOnFun_iff_pi'` instead to avoid rewriting instances, as well as their unprimed versions in case `𝔖` covers `X`. -/ theorem EquicontinuousOn.comap_uniformOnFun_eq {𝔖 : Set (Set X)} (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) @@ -247,37 +250,45 @@ uniform structure on `ι`. In particular, pointwise convergence and compact convergence coincide on an equicontinuous subset of `X → α`. -This is a version of `EquicontinuousOn.comap_uniformOnFun_eq` stated in terms of `UniformInducing` +This is a version of `EquicontinuousOn.comap_uniformOnFun_eq` stated in terms of `IsUniformInducing` for convenuence. -/ -lemma EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi' [UniformSpace ι] +lemma EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi' [UniformSpace ι] {𝔖 : Set (Set X)} (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) : - UniformInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ - UniformInducing ((⋃₀ 𝔖).restrict ∘ F) := by - rw [uniformInducing_iff_uniformSpace, uniformInducing_iff_uniformSpace, + IsUniformInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ + IsUniformInducing ((⋃₀ 𝔖).restrict ∘ F) := by + rw [isUniformInducing_iff_uniformSpace, isUniformInducing_iff_uniformSpace, ← EquicontinuousOn.comap_uniformOnFun_eq 𝔖_compact F_eqcont] rfl +@[deprecated (since := "2024-10-05")] +alias EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi' := + EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi' + /-- Let `X` be a topological space, `𝔖` a covering of `X` by compact subsets, `α` a uniform space, and `F : ι → (X → α)` a family which is equicontinuous on each `K ∈ 𝔖`. Then, the uniform structures of uniform convergence on `𝔖` and pointwise convergence induce the same uniform structure on `ι`. -This is a specialization of `EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi'` to +This is a specialization of `EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi'` to the case where `𝔖` covers `X`. -/ -lemma EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi [UniformSpace ι] +lemma EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi [UniformSpace ι] {𝔖 : Set (Set X)} (𝔖_covers : ⋃₀ 𝔖 = univ) (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) : - UniformInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ - UniformInducing F := by + IsUniformInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ + IsUniformInducing F := by rw [eq_univ_iff_forall] at 𝔖_covers -- This obviously follows from the previous lemma, we formalize it by going through the -- isomorphism of uniform spaces between `(⋃₀ 𝔖) → α` and `X → α`. let φ : ((⋃₀ 𝔖) → α) ≃ᵤ (X → α) := UniformEquiv.piCongrLeft (β := fun _ ↦ α) (Equiv.subtypeUnivEquiv 𝔖_covers) - rw [EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi' 𝔖_compact F_eqcont, + rw [EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi' 𝔖_compact F_eqcont, show restrict (⋃₀ 𝔖) ∘ F = φ.symm ∘ F by rfl] - exact ⟨fun H ↦ φ.uniformInducing.comp H, fun H ↦ φ.symm.uniformInducing.comp H⟩ + exact ⟨fun H ↦ φ.isUniformInducing.comp H, fun H ↦ φ.symm.isUniformInducing.comp H⟩ + +@[deprecated (since := "2024-10-05")] +alias EquicontinuousOn.uniformInducing_uniformOnFun_iff_pi := + EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi /-- Let `X` be a topological space, `𝔖` a family of compact subsets of `X`, `α` a uniform space, and `F : ι → (X → α)` a family which is equicontinuous on each `K ∈ 𝔖`. Then, the topologies @@ -286,14 +297,14 @@ of uniform convergence on `𝔖` and pointwise convergence on `⋃₀ 𝔖` indu In particular, pointwise convergence and compact convergence coincide on an equicontinuous subset of `X → α`. -This is a consequence of `EquicontinuousOn.comap_uniformOnFun_eq` stated in terms of `Inducing` -for convenuence. -/ +This is a consequence of `EquicontinuousOn.comap_uniformOnFun_eq` stated in terms of `IsInducing` +for convenience. -/ lemma EquicontinuousOn.inducing_uniformOnFun_iff_pi' [TopologicalSpace ι] {𝔖 : Set (Set X)} (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) : - Inducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ - Inducing ((⋃₀ 𝔖).restrict ∘ F) := by - rw [inducing_iff, inducing_iff] + IsInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ + IsInducing ((⋃₀ 𝔖).restrict ∘ F) := by + rw [isInducing_iff, isInducing_iff] change (_ = ((UniformOnFun.uniformSpace X α 𝔖).comap F).toTopologicalSpace) ↔ (_ = ((Pi.uniformSpace _).comap ((⋃₀ 𝔖).restrict ∘ F)).toTopologicalSpace) rw [← EquicontinuousOn.comap_uniformOnFun_eq 𝔖_compact F_eqcont] @@ -304,11 +315,11 @@ of uniform convergence on `𝔖` and pointwise convergence induce the same topol This is a specialization of `EquicontinuousOn.inducing_uniformOnFun_iff_pi'` to the case where `𝔖` covers `X`. -/ -lemma EquicontinuousOn.inducing_uniformOnFun_iff_pi [TopologicalSpace ι] +lemma EquicontinuousOn.isInducing_uniformOnFun_iff_pi [TopologicalSpace ι] {𝔖 : Set (Set X)} (𝔖_covers : ⋃₀ 𝔖 = univ) (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) : - Inducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ - Inducing F := by + IsInducing (UniformOnFun.ofFun 𝔖 ∘ F) ↔ + IsInducing F := by rw [eq_univ_iff_forall] at 𝔖_covers -- This obviously follows from the previous lemma, we formalize it by going through the -- homeomorphism between `(⋃₀ 𝔖) → α` and `X → α`. @@ -316,7 +327,11 @@ lemma EquicontinuousOn.inducing_uniformOnFun_iff_pi [TopologicalSpace ι] (Equiv.subtypeUnivEquiv 𝔖_covers) rw [EquicontinuousOn.inducing_uniformOnFun_iff_pi' 𝔖_compact F_eqcont, show restrict (⋃₀ 𝔖) ∘ F = φ.symm ∘ F by rfl] - exact ⟨fun H ↦ φ.inducing.comp H, fun H ↦ φ.symm.inducing.comp H⟩ + exact ⟨fun H ↦ φ.isInducing.comp H, fun H ↦ φ.symm.isInducing.comp H⟩ + +@[deprecated (since := "2024-10-28")] +alias EquicontinuousOn.inducing_uniformOnFun_iff_pi := + EquicontinuousOn.isInducing_uniformOnFun_iff_pi -- TODO: find a way to factor common elements of this proof and the proof of -- `EquicontinuousOn.comap_uniformOnFun_eq` @@ -361,7 +376,7 @@ theorem EquicontinuousOn.tendsto_uniformOnFun_iff_pi (Equiv.subtypeUnivEquiv 𝔖_covers) rw [EquicontinuousOn.tendsto_uniformOnFun_iff_pi' 𝔖_compact F_eqcont, show restrict (⋃₀ 𝔖) ∘ F = φ.symm ∘ F by rfl, show restrict (⋃₀ 𝔖) f = φ.symm f by rfl, - φ.symm.inducing.tendsto_nhds_iff] + φ.symm.isInducing.tendsto_nhds_iff] /-- Let `X` be a topological space, `𝔖` a family of compact subsets of `X` and `α` a uniform space. An equicontinuous subset of `X → α` is closed in the topology of uniform @@ -411,14 +426,14 @@ and `F : ι → (X → α)`. Assume that: Then `ι` is compact. -/ theorem ArzelaAscoli.compactSpace_of_closed_inducing' [TopologicalSpace ι] {𝔖 : Set (Set X)} - (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_ind : Inducing (UniformOnFun.ofFun 𝔖 ∘ F)) + (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_ind : IsInducing (UniformOnFun.ofFun 𝔖 ∘ F)) (F_cl : IsClosed <| range <| UniformOnFun.ofFun 𝔖 ∘ F) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) (F_pointwiseCompact : ∀ K ∈ 𝔖, ∀ x ∈ K, ∃ Q, IsCompact Q ∧ ∀ i, F i x ∈ Q) : CompactSpace ι := by -- By equicontinuity, we know that the topology on `ι` is also the one induced by -- `restrict (⋃₀ 𝔖) ∘ F`. - have : Inducing (restrict (⋃₀ 𝔖) ∘ F) := by + have : IsInducing (restrict (⋃₀ 𝔖) ∘ F) := by rwa [EquicontinuousOn.inducing_uniformOnFun_iff_pi' 𝔖_compact F_eqcont] at F_ind -- Thus, we just have to check that the range of this map is compact. rw [← isCompact_univ_iff, this.isCompact_iff, image_univ] @@ -445,14 +460,17 @@ and `F : ι → (X → α)`. Assume that: * For all `x`, the range of `i ↦ F i x` is contained in some fixed compact subset. Then `ι` is compact. -/ -theorem ArzelaAscoli.compactSpace_of_closedEmbedding [TopologicalSpace ι] {𝔖 : Set (Set X)} - (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_clemb : ClosedEmbedding (UniformOnFun.ofFun 𝔖 ∘ F)) +theorem ArzelaAscoli.compactSpace_of_isClosedEmbedding [TopologicalSpace ι] {𝔖 : Set (Set X)} + (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) (F_clemb : IsClosedEmbedding (UniformOnFun.ofFun 𝔖 ∘ F)) (F_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn F K) (F_pointwiseCompact : ∀ K ∈ 𝔖, ∀ x ∈ K, ∃ Q, IsCompact Q ∧ ∀ i, F i x ∈ Q) : CompactSpace ι := - compactSpace_of_closed_inducing' 𝔖_compact F_clemb.toInducing F_clemb.isClosed_range + compactSpace_of_closed_inducing' 𝔖_compact F_clemb.isInducing F_clemb.isClosed_range F_eqcont F_pointwiseCompact +@[deprecated (since := "2024-10-20")] +alias ArzelaAscoli.compactSpace_of_closedEmbedding := ArzelaAscoli.compactSpace_of_isClosedEmbedding + /-- A version of the **Arzela-Ascoli theorem**. Let `X, ι` be topological spaces, `𝔖` a covering of `X` by compact subsets, `α` a T2 uniform space, @@ -463,13 +481,13 @@ Let `X, ι` be topological spaces, `𝔖` a covering of `X` by compact subsets, * For all `x ∈ ⋃₀ 𝔖`, the image of `s` under `i ↦ F i x` is contained in some fixed compact subset. Then `s` has compact closure in `ι`. -/ -theorem ArzelaAscoli.isCompact_closure_of_closedEmbedding [TopologicalSpace ι] [T2Space α] +theorem ArzelaAscoli.isCompact_closure_of_isClosedEmbedding [TopologicalSpace ι] [T2Space α] {𝔖 : Set (Set X)} (𝔖_compact : ∀ K ∈ 𝔖, IsCompact K) - (F_clemb : ClosedEmbedding (UniformOnFun.ofFun 𝔖 ∘ F)) + (F_clemb : IsClosedEmbedding (UniformOnFun.ofFun 𝔖 ∘ F)) {s : Set ι} (s_eqcont : ∀ K ∈ 𝔖, EquicontinuousOn (F ∘ ((↑) : s → ι)) K) (s_pointwiseCompact : ∀ K ∈ 𝔖, ∀ x ∈ K, ∃ Q, IsCompact Q ∧ ∀ i ∈ s, F i x ∈ Q) : IsCompact (closure s) := by - -- We apply `ArzelaAscoli.compactSpace_of_closedEmbedding` to the map + -- We apply `ArzelaAscoli.compactSpace_of_isClosedEmbedding` to the map -- `F ∘ (↑) : closure s → (X → α)`, for which all the hypotheses are easily verified. rw [isCompact_iff_compactSpace] have : ∀ K ∈ 𝔖, ∀ x ∈ K, Continuous (eval x ∘ F) := fun K hK x hx ↦ @@ -480,10 +498,14 @@ theorem ArzelaAscoli.isCompact_closure_of_closedEmbedding [TopologicalSpace ι] have cls_pointwiseCompact : ∀ K ∈ 𝔖, ∀ x ∈ K, ∃ Q, IsCompact Q ∧ ∀ i ∈ closure s, F i x ∈ Q := fun K hK x hx ↦ (s_pointwiseCompact K hK x hx).imp fun Q hQ ↦ ⟨hQ.1, closure_minimal hQ.2 <| hQ.1.isClosed.preimage (this K hK x hx)⟩ - exact ArzelaAscoli.compactSpace_of_closedEmbedding 𝔖_compact - (F_clemb.comp isClosed_closure.closedEmbedding_subtype_val) cls_eqcont + exact ArzelaAscoli.compactSpace_of_isClosedEmbedding 𝔖_compact + (F_clemb.comp isClosed_closure.isClosedEmbedding_subtypeVal) cls_eqcont fun K hK x hx ↦ (cls_pointwiseCompact K hK x hx).imp fun Q hQ ↦ ⟨hQ.1, by simpa using hQ.2⟩ +@[deprecated (since := "2024-10-20")] +alias ArzelaAscoli.isCompact_closure_of_closedEmbedding := + ArzelaAscoli.isCompact_closure_of_isClosedEmbedding + /-- A version of the **Arzela-Ascoli theorem**. If an equicontinuous family of continuous functions is compact in the pointwise topology, then it @@ -491,12 +513,11 @@ is compact in the compact open topology. -/ theorem ArzelaAscoli.isCompact_of_equicontinuous (S : Set C(X, α)) (hS1 : IsCompact (ContinuousMap.toFun '' S)) (hS2 : Equicontinuous ((↑) : S → X → α)) : IsCompact S := by - suffices h : Inducing (Equiv.Set.image (↑) S DFunLike.coe_injective) by + suffices h : IsInducing (Equiv.Set.image (↑) S DFunLike.coe_injective) by rw [isCompact_iff_compactSpace] at hS1 ⊢ - exact (Equiv.toHomeomorphOfInducing _ h).symm.compactSpace - rw [← inducing_subtype_val.of_comp_iff, ← EquicontinuousOn.inducing_uniformOnFun_iff_pi _ _ _] - · exact ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.inducing.comp - inducing_subtype_val + exact (Equiv.toHomeomorphOfIsInducing _ h).symm.compactSpace + rw [← IsInducing.subtypeVal.of_comp_iff, ← EquicontinuousOn.isInducing_uniformOnFun_iff_pi _ _ _] + · exact ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.isInducing.comp .subtypeVal · exact eq_univ_iff_forall.mpr (fun x ↦ mem_sUnion_of_mem (mem_singleton x) isCompact_singleton) · exact fun _ ↦ id · exact fun K _ ↦ hS2.equicontinuousOn K diff --git a/Mathlib/Topology/UniformSpace/Basic.lean b/Mathlib/Topology/UniformSpace/Basic.lean index caab9ab1db8cb..f720fa95c4ba6 100644 --- a/Mathlib/Topology/UniformSpace/Basic.lean +++ b/Mathlib/Topology/UniformSpace/Basic.lean @@ -836,7 +836,7 @@ theorem closure_eq_inter_uniformity {t : Set (α × α)} : closure t = ⋂ d ∈ closure t = ⋂ (V) (_ : V ∈ 𝓤 α ∧ SymmetricRel V), V ○ t ○ V := closure_eq_uniformity t _ = ⋂ V ∈ 𝓤 α, V ○ t ○ V := Eq.symm <| - UniformSpace.hasBasis_symmetric.biInter_mem fun V₁ V₂ hV => + UniformSpace.hasBasis_symmetric.biInter_mem fun _ _ hV => compRel_mono (compRel_mono hV Subset.rfl) hV _ = ⋂ V ∈ 𝓤 α, V ○ (t ○ V) := by simp only [compRel_assoc] @@ -854,7 +854,7 @@ theorem uniformity_eq_uniformity_interior : 𝓤 α = (𝓤 α).lift' interior : hs_comp ⟨x, h₁, y, h₂, h₃⟩ have : interior d ∈ 𝓤 α := by filter_upwards [hs] using this simp [this]) - fun s hs => ((𝓤 α).lift' interior).sets_of_superset (mem_lift' hs) interior_subset + fun _ hs => ((𝓤 α).lift' interior).sets_of_superset (mem_lift' hs) interior_subset theorem interior_mem_uniformity {s : Set (α × α)} (hs : s ∈ 𝓤 α) : interior s ∈ 𝓤 α := by rw [uniformity_eq_uniformity_interior]; exact mem_lift' hs @@ -1570,7 +1570,7 @@ the diagonal in the second part. -/ instance Sum.instUniformSpace : UniformSpace (α ⊕ β) where uniformity := map (fun p : α × α => (inl p.1, inl p.2)) (𝓤 α) ⊔ map (fun p : β × β => (inr p.1, inr p.2)) (𝓤 β) - symm := fun s hs ↦ ⟨symm_le_uniformity hs.1, symm_le_uniformity hs.2⟩ + symm := fun _ hs ↦ ⟨symm_le_uniformity hs.1, symm_le_uniformity hs.2⟩ comp := fun s hs ↦ by rcases comp_mem_uniformity_sets hs.1 with ⟨tα, htα, Htα⟩ rcases comp_mem_uniformity_sets hs.2 with ⟨tβ, htβ, Htβ⟩ diff --git a/Mathlib/Topology/UniformSpace/Compact.lean b/Mathlib/Topology/UniformSpace/Compact.lean index 175d8d75ed946..f8308127388e0 100644 --- a/Mathlib/Topology/UniformSpace/Compact.lean +++ b/Mathlib/Topology/UniformSpace/Compact.lean @@ -5,7 +5,6 @@ Authors: Patrick Massot, Yury Kudryashov -/ import Mathlib.Topology.UniformSpace.UniformConvergence import Mathlib.Topology.UniformSpace.Equicontinuity -import Mathlib.Topology.Separation import Mathlib.Topology.Support /-! @@ -70,7 +69,7 @@ theorem unique_uniformity_of_compact [t : TopologicalSpace γ] [CompactSpace γ] /-- The unique uniform structure inducing a given compact topological structure. -/ def uniformSpaceOfCompactT2 [TopologicalSpace γ] [CompactSpace γ] [T2Space γ] : UniformSpace γ where uniformity := 𝓝ˢ (diagonal γ) - symm := continuous_swap.tendsto_nhdsSet fun x => Eq.symm + symm := continuous_swap.tendsto_nhdsSet fun _ => Eq.symm comp := by /- This is the difficult part of the proof. We need to prove that, for each neighborhood `W` of the diagonal `Δ`, there exists a smaller neighborhood `V` such that `V ○ V ⊆ W`. diff --git a/Mathlib/Topology/UniformSpace/CompactConvergence.lean b/Mathlib/Topology/UniformSpace/CompactConvergence.lean index c316d5316d094..c70587a4d1137 100644 --- a/Mathlib/Topology/UniformSpace/CompactConvergence.lean +++ b/Mathlib/Topology/UniformSpace/CompactConvergence.lean @@ -252,11 +252,6 @@ theorem tendsto_iff_tendstoLocallyUniformly [WeaklyLocallyCompactSpace α] : obtain ⟨n, hn₁, hn₂⟩ := exists_compact_mem_nhds x exact ⟨n, hn₂, h n hn₁ V hV⟩ -@[deprecated tendsto_iff_tendstoLocallyUniformly (since := "2023-09-03")] -theorem tendstoLocallyUniformly_of_tendsto [WeaklyLocallyCompactSpace α] (h : Tendsto F p (𝓝 f)) : - TendstoLocallyUniformly (fun i a => F i a) f p := - tendsto_iff_tendstoLocallyUniformly.1 h - section Functorial variable {γ δ : Type*} [TopologicalSpace γ] [UniformSpace δ] @@ -267,11 +262,14 @@ theorem uniformContinuous_comp (g : C(β, δ)) (hg : UniformContinuous g) : UniformOnFun.postcomp_uniformContinuous hg |>.comp isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous -theorem uniformInducing_comp (g : C(β, δ)) (hg : UniformInducing g) : - UniformInducing (ContinuousMap.comp g : C(α, β) → C(α, δ)) := - isUniformEmbedding_toUniformOnFunIsCompact.toUniformInducing.of_comp_iff.mp <| - UniformOnFun.postcomp_uniformInducing hg |>.comp - isUniformEmbedding_toUniformOnFunIsCompact.toUniformInducing +theorem isUniformInducing_comp (g : C(β, δ)) (hg : IsUniformInducing g) : + IsUniformInducing (ContinuousMap.comp g : C(α, β) → C(α, δ)) := + isUniformEmbedding_toUniformOnFunIsCompact.isUniformInducing.of_comp_iff.mp <| + UniformOnFun.postcomp_isUniformInducing hg |>.comp + isUniformEmbedding_toUniformOnFunIsCompact.isUniformInducing + +@[deprecated (since := "2024-10-05")] +alias uniformInducing_comp := isUniformInducing_comp theorem isUniformEmbedding_comp (g : C(β, δ)) (hg : IsUniformEmbedding g) : IsUniformEmbedding (ContinuousMap.comp g : C(α, β) → C(α, δ)) := @@ -379,7 +377,7 @@ Sufficient conditions on `α` to satisfy this condition are (weak) local compact lemma completeSpace_of_restrictGenTopology (h : RestrictGenTopology {K : Set α | IsCompact K}) : CompleteSpace C(α, β) := by rw [completeSpace_iff_isComplete_range - isUniformEmbedding_toUniformOnFunIsCompact.toUniformInducing, + isUniformEmbedding_toUniformOnFunIsCompact.isUniformInducing, range_toUniformOnFunIsCompact, ← completeSpace_coe_iff_isComplete] exact (UniformOnFun.isClosed_setOf_continuous h).completeSpace_coe diff --git a/Mathlib/Topology/UniformSpace/CompareReals.lean b/Mathlib/Topology/UniformSpace/CompareReals.lean index 7f1c135164444..cbd5e14b28a91 100644 --- a/Mathlib/Topology/UniformSpace/CompareReals.lean +++ b/Mathlib/Topology/UniformSpace/CompareReals.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot -/ import Mathlib.Topology.UniformSpace.AbsoluteValue -import Mathlib.Topology.Instances.Real import Mathlib.Topology.Instances.Rat import Mathlib.Topology.UniformSpace.Completion +import Mathlib.Topology.Metrizable.Basic /-! # Comparison of Cauchy reals and Bourbaki reals @@ -70,9 +70,9 @@ def rationalCauSeqPkg : @AbstractCompletion ℚ <| (@AbsoluteValue.abs ℚ _).un (uniformStruct := by infer_instance) (complete := by infer_instance) (separation := by infer_instance) - (uniformInducing := by + (isUniformInducing := by rw [Rat.uniformSpace_eq] - exact Rat.isUniformEmbedding_coe_real.toUniformInducing) + exact Rat.isUniformEmbedding_coe_real.isUniformInducing) (dense := Rat.isDenseEmbedding_coe_real.dense) namespace CompareReals diff --git a/Mathlib/Topology/UniformSpace/CompleteSeparated.lean b/Mathlib/Topology/UniformSpace/CompleteSeparated.lean index 2fcb34197b931..5c4968e5a26e8 100644 --- a/Mathlib/Topology/UniformSpace/CompleteSeparated.lean +++ b/Mathlib/Topology/UniformSpace/CompleteSeparated.lean @@ -27,13 +27,19 @@ theorem IsComplete.isClosed [UniformSpace α] [T0Space α] {s : Set α} (h : IsC rcases h f this inf_le_right with ⟨y, ys, fy⟩ rwa [(tendsto_nhds_unique' ha inf_le_left fy : a = y)] -theorem IsUniformEmbedding.toClosedEmbedding [UniformSpace α] [UniformSpace β] [CompleteSpace α] +theorem IsUniformEmbedding.toIsClosedEmbedding [UniformSpace α] [UniformSpace β] [CompleteSpace α] [T0Space β] {f : α → β} (hf : IsUniformEmbedding f) : - ClosedEmbedding f := - ⟨hf.embedding, hf.toUniformInducing.isComplete_range.isClosed⟩ + IsClosedEmbedding f := + ⟨hf.isEmbedding, hf.isUniformInducing.isComplete_range.isClosed⟩ + +@[deprecated (since := "2024-10-20")] +alias IsUniformEmbedding.toClosedEmbedding := IsUniformEmbedding.toIsClosedEmbedding @[deprecated (since := "2024-10-01")] -alias UniformEmbedding.toClosedEmbedding := IsUniformEmbedding.toClosedEmbedding +alias UniformEmbedding.toIsClosedEmbedding := IsUniformEmbedding.toIsClosedEmbedding + +@[deprecated (since := "2024-10-20")] +alias UniformEmbedding.toClosedEmbedding := UniformEmbedding.toIsClosedEmbedding namespace IsDenseInducing diff --git a/Mathlib/Topology/UniformSpace/Completion.lean b/Mathlib/Topology/UniformSpace/Completion.lean index b8973237d30ae..ab6d988a20440 100644 --- a/Mathlib/Topology/UniformSpace/Completion.lean +++ b/Mathlib/Topology/UniformSpace/Completion.lean @@ -111,7 +111,7 @@ private theorem comp_gen : (((𝓤 α).lift' gen).lift' fun s => compRel s s) · exact monotone_gen · exact monotone_id.compRel monotone_id _ ≤ (𝓤 α).lift' fun s => gen <| compRel s s := - lift'_mono' fun s _hs => compRel_gen_gen_subset_gen_compRel + lift'_mono' fun _ _hs => compRel_gen_gen_subset_gen_compRel _ = ((𝓤 α).lift' fun s : Set (α × α) => compRel s s).lift' gen := by rw [lift'_lift'_assoc] · exact monotone_id.compRel monotone_id @@ -143,7 +143,7 @@ theorem mem_uniformity' {s : Set (CauchyFilter α × CauchyFilter α)} : def pureCauchy (a : α) : CauchyFilter α := ⟨pure a, cauchy_pure⟩ -theorem uniformInducing_pureCauchy : UniformInducing (pureCauchy : α → CauchyFilter α) := +theorem isUniformInducing_pureCauchy : IsUniformInducing (pureCauchy : α → CauchyFilter α) := ⟨have : (preimage fun x : α × α => (pureCauchy x.fst, pureCauchy x.snd)) ∘ gen = id := funext fun s => Set.ext fun ⟨a₁, a₂⟩ => by simp [preimage, gen, pureCauchy, prod_principal_principal] @@ -154,8 +154,11 @@ theorem uniformInducing_pureCauchy : UniformInducing (pureCauchy : α → Cauchy _ = 𝓤 α := by simp [this] ⟩ +@[deprecated (since := "2024-10-05")] +alias uniformInducing_pureCauchy := isUniformInducing_pureCauchy + theorem isUniformEmbedding_pureCauchy : IsUniformEmbedding (pureCauchy : α → CauchyFilter α) := - { uniformInducing_pureCauchy with + { isUniformInducing_pureCauchy with inj := fun _a₁ _a₂ h => pure_injective <| Subtype.ext_iff_val.1 h } @[deprecated (since := "2024-10-01")] @@ -184,7 +187,7 @@ theorem denseRange_pureCauchy : DenseRange (pureCauchy : α → CauchyFilter α) exact ⟨_, this⟩ theorem isDenseInducing_pureCauchy : IsDenseInducing (pureCauchy : α → CauchyFilter α) := - uniformInducing_pureCauchy.isDenseInducing denseRange_pureCauchy + isUniformInducing_pureCauchy.isDenseInducing denseRange_pureCauchy theorem isDenseEmbedding_pureCauchy : IsDenseEmbedding (pureCauchy : α → CauchyFilter α) := isUniformEmbedding_pureCauchy.isDenseEmbedding denseRange_pureCauchy @@ -205,11 +208,11 @@ section -- set_option eqn_compiler.zeta true instance : CompleteSpace (CauchyFilter α) := - completeSpace_extension uniformInducing_pureCauchy denseRange_pureCauchy fun f hf => + completeSpace_extension isUniformInducing_pureCauchy denseRange_pureCauchy fun f hf => let f' : CauchyFilter α := ⟨f, hf⟩ have : map pureCauchy f ≤ (𝓤 <| CauchyFilter α).lift' (preimage (Prod.mk f')) := - le_lift'.2 fun s hs => - let ⟨t, ht₁, (ht₂ : gen t ⊆ s)⟩ := (mem_lift'_sets monotone_gen).mp hs + le_lift'.2 fun _ hs => + let ⟨t, ht₁, ht₂⟩ := (mem_lift'_sets monotone_gen).mp hs let ⟨t', ht', (h : t' ×ˢ t' ⊆ t)⟩ := mem_prod_same_iff.mp (hf.right ht₁) have : t' ⊆ { y : α | (f', pureCauchy y) ∈ gen t } := fun x hx => (f ×ˢ pure x).sets_of_superset (prod_mem_prod ht' hx) h @@ -240,7 +243,7 @@ variable [T0Space β] theorem extend_pureCauchy {f : α → β} (hf : UniformContinuous f) (a : α) : extend f (pureCauchy a) = f a := by rw [extend, if_pos hf] - exact uniformly_extend_of_ind uniformInducing_pureCauchy denseRange_pureCauchy hf _ + exact uniformly_extend_of_ind isUniformInducing_pureCauchy denseRange_pureCauchy hf _ end T0Space @@ -249,7 +252,7 @@ variable [CompleteSpace β] theorem uniformContinuous_extend {f : α → β} : UniformContinuous (extend f) := by by_cases hf : UniformContinuous f · rw [extend, if_pos hf] - exact uniformContinuous_uniformly_extend uniformInducing_pureCauchy denseRange_pureCauchy hf + exact uniformContinuous_uniformly_extend isUniformInducing_pureCauchy denseRange_pureCauchy hf · rw [extend, if_neg hf] exact uniformContinuous_of_const fun a _b => by congr @@ -322,12 +325,15 @@ instance : Coe α (Completion α) := -- note [use has_coe_t] protected theorem coe_eq : ((↑) : α → Completion α) = SeparationQuotient.mk ∘ pureCauchy := rfl -theorem uniformInducing_coe : UniformInducing ((↑) : α → Completion α) := - SeparationQuotient.uniformInducing_mk.comp uniformInducing_pureCauchy +theorem isUniformInducing_coe : IsUniformInducing ((↑) : α → Completion α) := + SeparationQuotient.isUniformInducing_mk.comp isUniformInducing_pureCauchy + +@[deprecated (since := "2024-10-05")] +alias uniformInducing_coe := isUniformInducing_coe theorem comap_coe_eq_uniformity : ((𝓤 _).comap fun p : α × α => ((p.1 : Completion α), (p.2 : Completion α))) = 𝓤 α := - (uniformInducing_coe _).1 + (isUniformInducing_coe _).1 variable {α} @@ -344,7 +350,7 @@ def cPkg {α : Type*} [UniformSpace α] : AbstractCompletion α where uniformStruct := by infer_instance complete := by infer_instance separation := by infer_instance - uniformInducing := Completion.uniformInducing_coe α + isUniformInducing := Completion.isUniformInducing_coe α dense := Completion.denseRange_coe instance AbstractCompletion.inhabited : Inhabited (AbstractCompletion α) := @@ -375,7 +381,7 @@ theorem coe_injective [T0Space α] : Function.Injective ((↑) : α → Completi variable {α} theorem isDenseInducing_coe : IsDenseInducing ((↑) : α → Completion α) := - { (uniformInducing_coe α).inducing with dense := denseRange_coe } + { (isUniformInducing_coe α).isInducing with dense := denseRange_coe } /-- The uniform bijection between a complete space and its uniform completion. -/ def UniformCompletion.completeEquivSelf [CompleteSpace α] [T0Space α] : Completion α ≃ᵤ α := diff --git a/Mathlib/Topology/UniformSpace/Equicontinuity.lean b/Mathlib/Topology/UniformSpace/Equicontinuity.lean index 5fdd4c239966d..f3cca9f71ccdf 100644 --- a/Mathlib/Topology/UniformSpace/Equicontinuity.lean +++ b/Mathlib/Topology/UniformSpace/Equicontinuity.lean @@ -82,8 +82,8 @@ section open UniformSpace Filter Set Uniformity Topology UniformConvergence Function -variable {ι κ X X' Y Z α α' β β' γ 𝓕 : Type*} [tX : TopologicalSpace X] [tY : TopologicalSpace Y] - [tZ : TopologicalSpace Z] [uα : UniformSpace α] [uβ : UniformSpace β] [uγ : UniformSpace γ] +variable {ι κ X X' Y α α' β β' γ : Type*} [tX : TopologicalSpace X] [tY : TopologicalSpace Y] + [uα : UniformSpace α] [uβ : UniformSpace β] [uγ : UniformSpace γ] /-- A family `F : ι → X → α` of functions from a topological space to a uniform space is *equicontinuous at `x₀ : X`* if, for all entourages `U ∈ 𝓤 α`, there is a neighborhood `V` of `x₀` @@ -704,56 +704,74 @@ theorem Filter.HasBasis.uniformEquicontinuousOn_iff {κ₁ κ₂ : Type*} {p₁ /-- Given `u : α → β` a uniform inducing map, a family `𝓕 : ι → X → α` is equicontinuous at a point `x₀ : X` iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is equicontinuous at `x₀`. -/ -theorem UniformInducing.equicontinuousAt_iff {F : ι → X → α} {x₀ : X} {u : α → β} - (hu : UniformInducing u) : EquicontinuousAt F x₀ ↔ EquicontinuousAt ((u ∘ ·) ∘ F) x₀ := by - have := (UniformFun.postcomp_uniformInducing (α := ι) hu).inducing +theorem IsUniformInducing.equicontinuousAt_iff {F : ι → X → α} {x₀ : X} {u : α → β} + (hu : IsUniformInducing u) : EquicontinuousAt F x₀ ↔ EquicontinuousAt ((u ∘ ·) ∘ F) x₀ := by + have := (UniformFun.postcomp_isUniformInducing (α := ι) hu).isInducing rw [equicontinuousAt_iff_continuousAt, equicontinuousAt_iff_continuousAt, this.continuousAt_iff] rfl +@[deprecated (since := "2024-10-05")] +alias UniformInducing.equicontinuousAt_iff := IsUniformInducing.equicontinuousAt_iff + /-- Given `u : α → β` a uniform inducing map, a family `𝓕 : ι → X → α` is equicontinuous at a point `x₀ : X` within a subset `S : Set X` iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is equicontinuous at `x₀` within `S`. -/ -theorem UniformInducing.equicontinuousWithinAt_iff {F : ι → X → α} {S : Set X} {x₀ : X} {u : α → β} - (hu : UniformInducing u) : EquicontinuousWithinAt F S x₀ ↔ +lemma IsUniformInducing.equicontinuousWithinAt_iff {F : ι → X → α} {S : Set X} {x₀ : X} {u : α → β} + (hu : IsUniformInducing u) : EquicontinuousWithinAt F S x₀ ↔ EquicontinuousWithinAt ((u ∘ ·) ∘ F) S x₀ := by - have := (UniformFun.postcomp_uniformInducing (α := ι) hu).inducing + have := (UniformFun.postcomp_isUniformInducing (α := ι) hu).isInducing simp only [equicontinuousWithinAt_iff_continuousWithinAt, this.continuousWithinAt_iff] rfl +@[deprecated (since := "2024-10-05")] +alias UniformInducing.equicontinuousWithinAt_iff := IsUniformInducing.equicontinuousWithinAt_iff + /-- Given `u : α → β` a uniform inducing map, a family `𝓕 : ι → X → α` is equicontinuous iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is equicontinuous. -/ -theorem UniformInducing.equicontinuous_iff {F : ι → X → α} {u : α → β} (hu : UniformInducing u) : +lemma IsUniformInducing.equicontinuous_iff {F : ι → X → α} {u : α → β} (hu : IsUniformInducing u) : Equicontinuous F ↔ Equicontinuous ((u ∘ ·) ∘ F) := by congrm ∀ x, ?_ rw [hu.equicontinuousAt_iff] +@[deprecated (since := "2024-10-05")] +alias UniformInducing.equicontinuous_iff := IsUniformInducing.equicontinuous_iff + /-- Given `u : α → β` a uniform inducing map, a family `𝓕 : ι → X → α` is equicontinuous on a subset `S : Set X` iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is equicontinuous on `S`. -/ -theorem UniformInducing.equicontinuousOn_iff {F : ι → X → α} {S : Set X} {u : α → β} - (hu : UniformInducing u) : EquicontinuousOn F S ↔ EquicontinuousOn ((u ∘ ·) ∘ F) S := by +theorem IsUniformInducing.equicontinuousOn_iff {F : ι → X → α} {S : Set X} {u : α → β} + (hu : IsUniformInducing u) : EquicontinuousOn F S ↔ EquicontinuousOn ((u ∘ ·) ∘ F) S := by congrm ∀ x ∈ S, ?_ rw [hu.equicontinuousWithinAt_iff] +@[deprecated (since := "2024-10-05")] +alias UniformInducing.equicontinuousOn_iff := IsUniformInducing.equicontinuousOn_iff + /-- Given `u : α → γ` a uniform inducing map, a family `𝓕 : ι → β → α` is uniformly equicontinuous iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is uniformly equicontinuous. -/ -theorem UniformInducing.uniformEquicontinuous_iff {F : ι → β → α} {u : α → γ} - (hu : UniformInducing u) : UniformEquicontinuous F ↔ UniformEquicontinuous ((u ∘ ·) ∘ F) := by - have := UniformFun.postcomp_uniformInducing (α := ι) hu +theorem IsUniformInducing.uniformEquicontinuous_iff {F : ι → β → α} {u : α → γ} + (hu : IsUniformInducing u) : UniformEquicontinuous F ↔ UniformEquicontinuous ((u ∘ ·) ∘ F) := by + have := UniformFun.postcomp_isUniformInducing (α := ι) hu simp only [uniformEquicontinuous_iff_uniformContinuous, this.uniformContinuous_iff] rfl +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformEquicontinuous_iff := IsUniformInducing.uniformEquicontinuous_iff + /-- Given `u : α → γ` a uniform inducing map, a family `𝓕 : ι → β → α` is uniformly equicontinuous on a subset `S : Set β` iff the family `𝓕'`, obtained by composing each function of `𝓕` by `u`, is uniformly equicontinuous on `S`. -/ -theorem UniformInducing.uniformEquicontinuousOn_iff {F : ι → β → α} {S : Set β} {u : α → γ} - (hu : UniformInducing u) : +theorem IsUniformInducing.uniformEquicontinuousOn_iff {F : ι → β → α} {S : Set β} {u : α → γ} + (hu : IsUniformInducing u) : UniformEquicontinuousOn F S ↔ UniformEquicontinuousOn ((u ∘ ·) ∘ F) S := by - have := UniformFun.postcomp_uniformInducing (α := ι) hu + have := UniformFun.postcomp_isUniformInducing (α := ι) hu simp only [uniformEquicontinuousOn_iff_uniformContinuousOn, this.uniformContinuousOn_iff] rfl +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformEquicontinuousOn_iff := IsUniformInducing.uniformEquicontinuousOn_iff + /-- If a set of functions is equicontinuous at some `x₀` within a set `S`, the same is true for its closure in *any* topology for which evaluation at any `x ∈ S ∪ {x₀}` is continuous. Since this will be applied to `DFunLike` types, we state it for any topological space with a map diff --git a/Mathlib/Topology/UniformSpace/Equiv.lean b/Mathlib/Topology/UniformSpace/Equiv.lean index 21c97df293850..e9f383c879b3b 100644 --- a/Mathlib/Topology/UniformSpace/Equiv.lean +++ b/Mathlib/Topology/UniformSpace/Equiv.lean @@ -178,7 +178,7 @@ theorem symm_comp_self (h : α ≃ᵤ β) : (h.symm : β → α) ∘ h = id := theorem self_comp_symm (h : α ≃ᵤ β) : (h : α → β) ∘ h.symm = id := funext h.apply_symm_apply --- @[simp] -- Porting note (#10618): `simp` can prove this `simp only [Equiv.range_eq_univ]` +@[simp] theorem range_coe (h : α ≃ᵤ β) : range h = univ := h.surjective.range_eq @@ -188,22 +188,25 @@ theorem image_symm (h : α ≃ᵤ β) : image h.symm = preimage h := theorem preimage_symm (h : α ≃ᵤ β) : preimage h.symm = image h := (funext h.toEquiv.image_eq_preimage).symm --- @[simp] -- Porting note (#10618): `simp` can prove this `simp only [Equiv.image_preimage]` +@[simp] theorem image_preimage (h : α ≃ᵤ β) (s : Set β) : h '' (h ⁻¹' s) = s := h.toEquiv.image_preimage s ---@[simp] -- Porting note (#10618): `simp` can prove this `simp only [Equiv.preimage_image]` +@[simp] theorem preimage_image (h : α ≃ᵤ β) (s : Set α) : h ⁻¹' (h '' s) = s := h.toEquiv.preimage_image s -protected theorem uniformInducing (h : α ≃ᵤ β) : UniformInducing h := - uniformInducing_of_compose h.uniformContinuous h.symm.uniformContinuous <| by - simp only [symm_comp_self, uniformInducing_id] +theorem isUniformInducing (h : α ≃ᵤ β) : IsUniformInducing h := + IsUniformInducing.of_comp h.uniformContinuous h.symm.uniformContinuous <| by + simp only [symm_comp_self, IsUniformInducing.id] + +@[deprecated (since := "2024-10-05")] +alias uniformInducing := isUniformInducing theorem comap_eq (h : α ≃ᵤ β) : UniformSpace.comap h ‹_› = ‹_› := - h.uniformInducing.comap_uniformSpace + h.isUniformInducing.comap_uniformSpace -theorem isUniformEmbedding (h : α ≃ᵤ β) : IsUniformEmbedding h := ⟨h.uniformInducing, h.injective⟩ +lemma isUniformEmbedding (h : α ≃ᵤ β) : IsUniformEmbedding h := ⟨h.isUniformInducing, h.injective⟩ @[deprecated (since := "2024-10-01")] alias uniformEmbedding := isUniformEmbedding @@ -213,9 +216,9 @@ theorem completeSpace_iff (h : α ≃ᵤ β) : CompleteSpace α ↔ CompleteSpac /-- Uniform equiv given a uniform embedding. -/ noncomputable def ofIsUniformEmbedding (f : α → β) (hf : IsUniformEmbedding f) : α ≃ᵤ Set.range f where - uniformContinuous_toFun := hf.toUniformInducing.uniformContinuous.subtype_mk _ + uniformContinuous_toFun := hf.isUniformInducing.uniformContinuous.subtype_mk _ uniformContinuous_invFun := by - rw [hf.toUniformInducing.uniformContinuous_iff, Equiv.invFun_as_coe, + rw [hf.isUniformInducing.uniformContinuous_iff, Equiv.invFun_as_coe, Equiv.self_comp_ofInjective_symm] exact uniformContinuous_subtype_val toEquiv := Equiv.ofInjective f hf.inj @@ -331,7 +334,7 @@ def ulift : ULift.{v, u} α ≃ᵤ α := { Equiv.ulift with uniformContinuous_toFun := uniformContinuous_comap uniformContinuous_invFun := by - have hf : UniformInducing (@Equiv.ulift.{v, u} α).toFun := ⟨rfl⟩ + have hf : IsUniformInducing (@Equiv.ulift.{v, u} α).toFun := ⟨rfl⟩ simp_rw [hf.uniformContinuous_iff] exact uniformContinuous_id } @@ -370,8 +373,8 @@ end UniformEquiv /-- A uniform inducing equiv between uniform spaces is a uniform isomorphism. -/ -- @[simps] -- Porting note: removed, `simps?` produced no `simp` lemmas -def Equiv.toUniformEquivOfUniformInducing [UniformSpace α] [UniformSpace β] (f : α ≃ β) - (hf : UniformInducing f) : α ≃ᵤ β := +def Equiv.toUniformEquivOfIsUniformInducing [UniformSpace α] [UniformSpace β] (f : α ≃ β) + (hf : IsUniformInducing f) : α ≃ᵤ β := { f with uniformContinuous_toFun := hf.uniformContinuous uniformContinuous_invFun := hf.uniformContinuous_iff.2 <| by simpa using uniformContinuous_id } diff --git a/Mathlib/Topology/UniformSpace/Matrix.lean b/Mathlib/Topology/UniformSpace/Matrix.lean index 4afd736c939f3..cff2509e52dc9 100644 --- a/Mathlib/Topology/UniformSpace/Matrix.lean +++ b/Mathlib/Topology/UniformSpace/Matrix.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser, Heather Macbeth -/ -import Mathlib.Topology.Algebra.UniformGroup +import Mathlib.Topology.Algebra.UniformGroup.Basic import Mathlib.Topology.UniformSpace.Pi import Mathlib.Data.Matrix.Basic diff --git a/Mathlib/Topology/UniformSpace/Pi.lean b/Mathlib/Topology/UniformSpace/Pi.lean index 5c35d1206a3ad..783300913d8d4 100644 --- a/Mathlib/Topology/UniformSpace/Pi.lean +++ b/Mathlib/Topology/UniformSpace/Pi.lean @@ -122,8 +122,8 @@ protected theorem CompleteSpace.iInf {ι X : Type*} {u : ι → UniformSpace X} nontriviality X rcases ht with ⟨t, ht, hut⟩ -- The diagonal map `(X, ⨅ i, u i) → ∀ i, (X, u i)` is a uniform embedding. - have : @UniformInducing X (ι → X) (⨅ i, u i) (Pi.uniformSpace (U := u)) (const ι) := by - simp_rw [uniformInducing_iff, iInf_uniformity, Pi.uniformity, Filter.comap_iInf, + have : @IsUniformInducing X (ι → X) (⨅ i, u i) (Pi.uniformSpace (U := u)) (const ι) := by + simp_rw [isUniformInducing_iff, iInf_uniformity, Pi.uniformity, Filter.comap_iInf, Filter.comap_comap, comp_def, const, Prod.eta, comap_id'] -- Hence, it suffices to show that its range, the diagonal, is closed in `Π i, (X, u i)`. simp_rw [@completeSpace_iff_isComplete_range _ _ (_) (_) _ this, range_const_eq_diagonal, diff --git a/Mathlib/Topology/UniformSpace/Separation.lean b/Mathlib/Topology/UniformSpace/Separation.lean index f50de8d5deebd..60e6f6a085671 100644 --- a/Mathlib/Topology/UniformSpace/Separation.lean +++ b/Mathlib/Topology/UniformSpace/Separation.lean @@ -5,7 +5,7 @@ Authors: Johannes Hölzl, Patrick Massot, Yury Kudryashov -/ import Mathlib.Tactic.ApplyFun import Mathlib.Topology.UniformSpace.Basic -import Mathlib.Topology.Separation +import Mathlib.Topology.Separation.Basic /-! # Hausdorff properties of uniform spaces. Separation quotient. diff --git a/Mathlib/Topology/UniformSpace/UniformConvergence.lean b/Mathlib/Topology/UniformSpace/UniformConvergence.lean index 3d5593d33b3b1..aca68d49538ba 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergence.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.Separation import Mathlib.Topology.UniformSpace.Basic import Mathlib.Topology.UniformSpace.Cauchy @@ -598,11 +597,11 @@ theorem tendstoLocallyUniformlyOn_iff_tendstoLocallyUniformly_comp_coe : tendstoLocallyUniformlyOn_iff_forall_tendsto, ← map_nhds_subtype_val, prod_map_right]; rfl protected theorem TendstoUniformlyOn.tendstoLocallyUniformlyOn (h : TendstoUniformlyOn F f p s) : - TendstoLocallyUniformlyOn F f p s := fun u hu x _ => + TendstoLocallyUniformlyOn F f p s := fun u hu _ _ => ⟨s, self_mem_nhdsWithin, by simpa using h u hu⟩ protected theorem TendstoUniformly.tendstoLocallyUniformly (h : TendstoUniformly F f p) : - TendstoLocallyUniformly F f p := fun u hu x => ⟨univ, univ_mem, by simpa using h u hu⟩ + TendstoLocallyUniformly F f p := fun u hu _ => ⟨univ, univ_mem, by simpa using h u hu⟩ theorem TendstoLocallyUniformlyOn.mono (h : TendstoLocallyUniformlyOn F f p s) (h' : s' ⊆ s) : TendstoLocallyUniformlyOn F f p s' := by diff --git a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean index a2cae8ef68030..9a7542b8c7d0c 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean @@ -88,7 +88,7 @@ connection API to do most of the work. * `UniformOnFun.postcomp_uniformContinuous`: if `f : γ → β` is uniformly continuous, then `(fun g ↦ f ∘ g) : (α →ᵤ[𝔖] γ) → (α →ᵤ[𝔖] β)` is uniformly continuous. -* `UniformOnFun.postcomp_uniformInducing`: if `f : γ → β` is a uniform +* `UniformOnFun.postcomp_isUniformInducing`: if `f : γ → β` is a uniform inducing, then `(fun g ↦ f ∘ g) : (α →ᵤ[𝔖] γ) → (α →ᵤ[𝔖] β)` is a uniform inducing. * `UniformOnFun.precomp_uniformContinuous`: let `f : γ → α`, `𝔖 : Set (Set α)`, `𝔗 : Set (Set γ)`, and assume that `∀ T ∈ 𝔗, f '' T ∈ 𝔖`. Then, the function @@ -197,7 +197,7 @@ open UniformConvergence namespace UniformFun variable (α β : Type*) {γ ι : Type*} -variable {s s' : Set α} {x : α} {p : Filter ι} {g : ι → α} +variable {p : Filter ι} /-- Basis sets for the uniformity of uniform convergence: `gen α β V` is the set of pairs `(f, g)` of functions `α →ᵤ β` such that `∀ x, (f x, g x) ∈ V`. -/ @@ -367,11 +367,14 @@ a uniform inducing function for the uniform structures of uniform convergence. More precisely, if `f : γ → β` is uniform inducing, then `(f ∘ ·) : (α →ᵤ γ) → (α →ᵤ β)` is uniform inducing. -/ -protected theorem postcomp_uniformInducing [UniformSpace γ] {f : γ → β} (hf : UniformInducing f) : - UniformInducing (ofFun ∘ (f ∘ ·) ∘ toFun : (α →ᵤ γ) → α →ᵤ β) := +lemma postcomp_isUniformInducing [UniformSpace γ] {f : γ → β} + (hf : IsUniformInducing f) : IsUniformInducing (ofFun ∘ (f ∘ ·) ∘ toFun : (α →ᵤ γ) → α →ᵤ β) := ⟨((UniformFun.hasBasis_uniformity _ _).comap _).eq_of_same_basis <| UniformFun.hasBasis_uniformity_of_basis _ _ (hf.basis_uniformity (𝓤 β).basis_sets)⟩ +@[deprecated (since := "2024-10-05")] +alias postcomp_uniformInducing := postcomp_isUniformInducing + /-- Post-composition by a uniform embedding is a uniform embedding for the uniform structures of uniform convergence. @@ -380,7 +383,7 @@ then `(f ∘ ·) : (α →ᵤ γ) → (α →ᵤ β)` is a uniform embedding. -/ protected theorem postcomp_isUniformEmbedding [UniformSpace γ] {f : γ → β} (hf : IsUniformEmbedding f) : IsUniformEmbedding (ofFun ∘ (f ∘ ·) ∘ toFun : (α →ᵤ γ) → α →ᵤ β) where - toUniformInducing := UniformFun.postcomp_uniformInducing hf.toUniformInducing + toIsUniformInducing := UniformFun.postcomp_isUniformInducing hf.isUniformInducing inj _ _ H := funext fun _ ↦ hf.inj (congrFun H _) @[deprecated (since := "2024-10-01")] @@ -392,7 +395,7 @@ alias postcomp_uniformEmbedding := UniformFun.postcomp_isUniformEmbedding protected theorem comap_eq {f : γ → β} : 𝒰(α, γ, ‹UniformSpace β›.comap f) = 𝒰(α, β, _).comap (f ∘ ·) := by letI : UniformSpace γ := .comap f ‹_› - exact (UniformFun.postcomp_uniformInducing (f := f) ⟨rfl⟩).comap_uniformSpace.symm + exact (UniformFun.postcomp_isUniformInducing (f := f) ⟨rfl⟩).comap_uniformSpace.symm /-- Post-composition by a uniformly continuous function is uniformly continuous on `α →ᵤ β`. @@ -465,7 +468,7 @@ protected def uniformEquivProdArrow [UniformSpace γ] : (α →ᵤ β × γ) ≃ -- But `uβ × uγ` is defined as `comap fst uβ ⊓ comap snd uγ`, so we just have to apply -- `UniformFun.inf_eq` and `UniformFun.comap_eq`, which leaves us to check -- that some square commutes. - Equiv.toUniformEquivOfUniformInducing (Equiv.arrowProdEquivProdArrow _ _ _) <| by + Equiv.toUniformEquivOfIsUniformInducing (Equiv.arrowProdEquivProdArrow _ _ _) <| by constructor change comap (Prod.map (Equiv.arrowProdEquivProdArrow _ _ _) (Equiv.arrowProdEquivProdArrow _ _ _)) @@ -490,10 +493,10 @@ protected def uniformEquivPiComm : UniformEquiv (α →ᵤ ∀ i, δ i) (∀ i, -- But `Π i, uδ i` is defined as `⨅ i, comap (eval i) (uδ i)`, so we just have to apply -- `UniformFun.iInf_eq` and `UniformFun.comap_eq`, which leaves us to check -- that some square commutes. - @Equiv.toUniformEquivOfUniformInducing + @Equiv.toUniformEquivOfIsUniformInducing _ _ 𝒰(α, ∀ i, δ i, Pi.uniformSpace δ) (@Pi.uniformSpace ι (fun i => α → δ i) fun i => 𝒰(α, δ i, _)) (Equiv.piComm _) <| by - refine @UniformInducing.mk ?_ ?_ ?_ ?_ ?_ ?_ + refine @IsUniformInducing.mk ?_ ?_ ?_ ?_ ?_ ?_ change comap (Prod.map Function.swap Function.swap) _ = _ rw [← uniformity_comap] congr @@ -552,7 +555,7 @@ end UniformFun namespace UniformOnFun variable {α β : Type*} {γ ι : Type*} -variable {s s' : Set α} {x : α} {p : Filter ι} {g : ι → α} +variable {s : Set α} {p : Filter ι} local notation "𝒰(" α ", " β ", " u ")" => @UniformFun.uniformSpace α β u @@ -865,8 +868,8 @@ uniform structures of `𝔖`-convergence. More precisely, if `f : γ → β` is a uniform inducing, then `(fun g ↦ f ∘ g) : (α →ᵤ[𝔖] γ) → (α →ᵤ[𝔖] β)` is a uniform inducing. -/ -protected theorem postcomp_uniformInducing [UniformSpace γ] {f : γ → β} (hf : UniformInducing f) : - UniformInducing (ofFun 𝔖 ∘ (f ∘ ·) ∘ toFun 𝔖) := by +lemma postcomp_isUniformInducing [UniformSpace γ] {f : γ → β} + (hf : IsUniformInducing f) : IsUniformInducing (ofFun 𝔖 ∘ (f ∘ ·) ∘ toFun 𝔖) := by -- This is a direct consequence of `UniformOnFun.comap_eq` constructor replace hf : (𝓤 β).comap (Prod.map f f) = _ := hf.comap_uniformity @@ -876,6 +879,9 @@ protected theorem postcomp_uniformInducing [UniformSpace γ] {f : γ → β} (hf rw [← UniformSpace.ext hf, UniformOnFun.comap_eq] rfl +@[deprecated (since := "2024-10-05")] +alias postcomp_uniformInducing := postcomp_isUniformInducing + /-- Post-composition by a uniform embedding is a uniform embedding for the uniform structures of `𝔖`-convergence. @@ -883,7 +889,7 @@ More precisely, if `f : γ → β` is a uniform embedding, then `(fun g ↦ f ∘ g) : (α →ᵤ[𝔖] γ) → (α →ᵤ[𝔖] β)` is a uniform embedding. -/ protected theorem postcomp_isUniformEmbedding [UniformSpace γ] {f : γ → β} (hf : IsUniformEmbedding f) : IsUniformEmbedding (ofFun 𝔖 ∘ (f ∘ ·) ∘ toFun 𝔖) where - toUniformInducing := UniformOnFun.postcomp_uniformInducing hf.toUniformInducing + toIsUniformInducing := UniformOnFun.postcomp_isUniformInducing hf.isUniformInducing inj _ _ H := funext fun _ ↦ hf.inj (congrFun H _) @[deprecated (since := "2024-10-01")] @@ -1012,9 +1018,8 @@ protected def uniformEquivProdArrow [UniformSpace γ] : -- which leaves us to check that some square commutes. -- We could also deduce this from `UniformFun.uniformEquivProdArrow`, -- but it turns out to be more annoying. - ((UniformOnFun.ofFun 𝔖).symm.trans <| - (Equiv.arrowProdEquivProdArrow _ _ _).trans <| - (UniformOnFun.ofFun 𝔖).prodCongr (UniformOnFun.ofFun 𝔖)).toUniformEquivOfUniformInducing <| by + ((UniformOnFun.ofFun 𝔖).symm.trans <| (Equiv.arrowProdEquivProdArrow _ _ _).trans <| + (UniformOnFun.ofFun 𝔖).prodCongr (UniformOnFun.ofFun 𝔖)).toUniformEquivOfIsUniformInducing <| by constructor rw [uniformity_prod, comap_inf, comap_comap, comap_comap] have H := @UniformOnFun.inf_eq α (β × γ) 𝔖 @@ -1038,7 +1043,7 @@ protected def uniformEquivPiComm : (α →ᵤ[𝔖] ((i : ι) → δ i)) ≃ᵤ -- which leaves us to check that some square commutes. -- We could also deduce this from `UniformFun.uniformEquivPiComm`, but it turns out -- to be more annoying. - @Equiv.toUniformEquivOfUniformInducing (α →ᵤ[𝔖] ((i : ι) → δ i)) ((i : ι) → α →ᵤ[𝔖] δ i) + @Equiv.toUniformEquivOfIsUniformInducing (α →ᵤ[𝔖] ((i : ι) → δ i)) ((i : ι) → α →ᵤ[𝔖] δ i) _ _ (Equiv.piComm _) <| by constructor change comap (Prod.map Function.swap Function.swap) _ = _ diff --git a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean index adad8bcab4c26..95e056e6232c8 100644 --- a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean +++ b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean @@ -20,6 +20,7 @@ section universe u v w variable {α : Type u} {β : Type v} {γ : Type w} [UniformSpace α] [UniformSpace β] [UniformSpace γ] + {f : α → β} /-! ### Uniform inducing maps @@ -29,99 +30,167 @@ variable {α : Type u} {β : Type v} {γ : Type w} [UniformSpace α] [UniformSpa on `α` is the pullback of the uniformity filter on `β` under `Prod.map f f`. If `α` is a separated space, then this implies that `f` is injective, hence it is a `IsUniformEmbedding`. -/ @[mk_iff] -structure UniformInducing (f : α → β) : Prop where +structure IsUniformInducing (f : α → β) : Prop where /-- The uniformity filter on the domain is the pullback of the uniformity filter on the codomain under `Prod.map f f`. -/ comap_uniformity : comap (fun x : α × α => (f x.1, f x.2)) (𝓤 β) = 𝓤 α -lemma uniformInducing_iff_uniformSpace {f : α → β} : - UniformInducing f ↔ ‹UniformSpace β›.comap f = ‹UniformSpace α› := by - rw [uniformInducing_iff, UniformSpace.ext_iff, Filter.ext_iff] +@[deprecated (since := "2024-10-08")] alias UniformInducing := IsUniformInducing + +lemma isUniformInducing_iff_uniformSpace {f : α → β} : + IsUniformInducing f ↔ ‹UniformSpace β›.comap f = ‹UniformSpace α› := by + rw [isUniformInducing_iff, UniformSpace.ext_iff, Filter.ext_iff] rfl -protected alias ⟨UniformInducing.comap_uniformSpace, _⟩ := uniformInducing_iff_uniformSpace +@[deprecated (since := "2024-10-05")] +alias uniformInducing_iff_uniformSpace := isUniformInducing_iff_uniformSpace + +protected alias ⟨IsUniformInducing.comap_uniformSpace, _⟩ := isUniformInducing_iff_uniformSpace + +@[deprecated (since := "2024-10-08")] alias UniformInducing.comap_uniformSpace := + IsUniformInducing.comap_uniformSpace -lemma uniformInducing_iff' {f : α → β} : - UniformInducing f ↔ UniformContinuous f ∧ comap (Prod.map f f) (𝓤 β) ≤ 𝓤 α := by - rw [uniformInducing_iff, UniformContinuous, tendsto_iff_comap, le_antisymm_iff, and_comm]; rfl +lemma isUniformInducing_iff' {f : α → β} : + IsUniformInducing f ↔ UniformContinuous f ∧ comap (Prod.map f f) (𝓤 β) ≤ 𝓤 α := by + rw [isUniformInducing_iff, UniformContinuous, tendsto_iff_comap, le_antisymm_iff, and_comm]; rfl -protected lemma Filter.HasBasis.uniformInducing_iff {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'} +@[deprecated (since := "2024-10-05")] +alias uniformInducing_iff' := isUniformInducing_iff' + +protected lemma Filter.HasBasis.isUniformInducing_iff {ι ι'} {p : ι → Prop} {p' : ι' → Prop} {s s'} (h : (𝓤 α).HasBasis p s) (h' : (𝓤 β).HasBasis p' s') {f : α → β} : - UniformInducing f ↔ + IsUniformInducing f ↔ (∀ i, p' i → ∃ j, p j ∧ ∀ x y, (x, y) ∈ s j → (f x, f y) ∈ s' i) ∧ (∀ j, p j → ∃ i, p' i ∧ ∀ x y, (f x, f y) ∈ s' i → (x, y) ∈ s j) := by - simp [uniformInducing_iff', h.uniformContinuous_iff h', (h'.comap _).le_basis_iff h, subset_def] + simp [isUniformInducing_iff', h.uniformContinuous_iff h', (h'.comap _).le_basis_iff h, subset_def] + +@[deprecated (since := "2024-10-05")] +alias Filter.HasBasis.uniformInducing_iff := Filter.HasBasis.isUniformInducing_iff -theorem UniformInducing.mk' {f : α → β} - (h : ∀ s, s ∈ 𝓤 α ↔ ∃ t ∈ 𝓤 β, ∀ x y : α, (f x, f y) ∈ t → (x, y) ∈ s) : UniformInducing f := +theorem IsUniformInducing.mk' {f : α → β} + (h : ∀ s, s ∈ 𝓤 α ↔ ∃ t ∈ 𝓤 β, ∀ x y : α, (f x, f y) ∈ t → (x, y) ∈ s) : IsUniformInducing f := ⟨by simp [eq_comm, Filter.ext_iff, subset_def, h]⟩ -theorem uniformInducing_id : UniformInducing (@id α) := +@[deprecated (since := "2024-10-05")] +alias UniformInducing.mk' := IsUniformInducing.mk' + +theorem IsUniformInducing.id : IsUniformInducing (@id α) := ⟨by rw [← Prod.map_def, Prod.map_id, comap_id]⟩ -theorem UniformInducing.comp {g : β → γ} (hg : UniformInducing g) {f : α → β} - (hf : UniformInducing f) : UniformInducing (g ∘ f) := +@[deprecated (since := "2024-10-05")] +alias uniformInducing_id := IsUniformInducing.id + +theorem IsUniformInducing.comp {g : β → γ} (hg : IsUniformInducing g) {f : α → β} + (hf : IsUniformInducing f) : IsUniformInducing (g ∘ f) := ⟨by rw [← hf.1, ← hg.1, comap_comap]; rfl⟩ -theorem UniformInducing.of_comp_iff {g : β → γ} (hg : UniformInducing g) {f : α → β} : - UniformInducing (g ∘ f) ↔ UniformInducing f := by +@[deprecated (since := "2024-10-05")] +alias UniformInducing.comp := IsUniformInducing.comp + +theorem IsUniformInducing.of_comp_iff {g : β → γ} (hg : IsUniformInducing g) {f : α → β} : + IsUniformInducing (g ∘ f) ↔ IsUniformInducing f := by refine ⟨fun h ↦ ?_, hg.comp⟩ - rw [uniformInducing_iff, ← hg.comap_uniformity, comap_comap, ← h.comap_uniformity, + rw [isUniformInducing_iff, ← hg.comap_uniformity, comap_comap, ← h.comap_uniformity, Function.comp_def, Function.comp_def] -theorem UniformInducing.basis_uniformity {f : α → β} (hf : UniformInducing f) {ι : Sort*} +@[deprecated (since := "2024-10-05")] +alias UniformInducing.of_comp_iff := IsUniformInducing.of_comp_iff + +theorem IsUniformInducing.basis_uniformity {f : α → β} (hf : IsUniformInducing f) {ι : Sort*} {p : ι → Prop} {s : ι → Set (β × β)} (H : (𝓤 β).HasBasis p s) : (𝓤 α).HasBasis p fun i => Prod.map f f ⁻¹' s i := hf.1 ▸ H.comap _ -theorem UniformInducing.cauchy_map_iff {f : α → β} (hf : UniformInducing f) {F : Filter α} : +@[deprecated (since := "2024-10-05")] +alias UniformInducing.basis_uniformity := IsUniformInducing.basis_uniformity + +theorem IsUniformInducing.cauchy_map_iff {f : α → β} (hf : IsUniformInducing f) {F : Filter α} : Cauchy (map f F) ↔ Cauchy F := by simp only [Cauchy, map_neBot_iff, prod_map_map_eq, map_le_iff_le_comap, ← hf.comap_uniformity] -theorem uniformInducing_of_compose {f : α → β} {g : β → γ} (hf : UniformContinuous f) - (hg : UniformContinuous g) (hgf : UniformInducing (g ∘ f)) : UniformInducing f := by +@[deprecated (since := "2024-10-05")] +alias UniformInducing.cauchy_map_iff := IsUniformInducing.cauchy_map_iff + +theorem IsUniformInducing.of_comp {f : α → β} {g : β → γ} (hf : UniformContinuous f) + (hg : UniformContinuous g) (hgf : IsUniformInducing (g ∘ f)) : IsUniformInducing f := by refine ⟨le_antisymm ?_ hf.le_comap⟩ rw [← hgf.1, ← Prod.map_def, ← Prod.map_def, ← Prod.map_comp_map f f g g, ← comap_comap] exact comap_mono hg.le_comap -theorem UniformInducing.uniformContinuous {f : α → β} (hf : UniformInducing f) : - UniformContinuous f := (uniformInducing_iff'.1 hf).1 +@[deprecated (since := "2024-10-05")] +alias uniformInducing_of_compose := IsUniformInducing.of_comp + +theorem IsUniformInducing.uniformContinuous {f : α → β} (hf : IsUniformInducing f) : + UniformContinuous f := (isUniformInducing_iff'.1 hf).1 -theorem UniformInducing.uniformContinuous_iff {f : α → β} {g : β → γ} (hg : UniformInducing g) : +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformContinuous := IsUniformInducing.uniformContinuous + +theorem IsUniformInducing.uniformContinuous_iff {f : α → β} {g : β → γ} (hg : IsUniformInducing g) : UniformContinuous f ↔ UniformContinuous (g ∘ f) := by dsimp only [UniformContinuous, Tendsto] simp only [← hg.comap_uniformity, ← map_le_iff_le_comap, Filter.map_map, Function.comp_def] -protected theorem UniformInducing.uniformInducing_comp_iff {f : α → β} {g : β → γ} - (hg : UniformInducing g) : UniformInducing (g ∘ f) ↔ UniformInducing f := by - simp only [uniformInducing_iff, ← hg.comap_uniformity, comap_comap, Function.comp_def] +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformContinuous_iff := IsUniformInducing.uniformContinuous_iff + +protected theorem IsUniformInducing.isUniformInducing_comp_iff {f : α → β} {g : β → γ} + (hg : IsUniformInducing g) : IsUniformInducing (g ∘ f) ↔ IsUniformInducing f := by + simp only [isUniformInducing_iff, ← hg.comap_uniformity, comap_comap, Function.comp_def] -theorem UniformInducing.uniformContinuousOn_iff {f : α → β} {g : β → γ} {S : Set α} - (hg : UniformInducing g) : +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformInducing_comp_iff := IsUniformInducing.isUniformInducing_comp_iff + +theorem IsUniformInducing.uniformContinuousOn_iff {f : α → β} {g : β → γ} {S : Set α} + (hg : IsUniformInducing g) : UniformContinuousOn f S ↔ UniformContinuousOn (g ∘ f) S := by dsimp only [UniformContinuousOn, Tendsto] rw [← hg.comap_uniformity, ← map_le_iff_le_comap, Filter.map_map, comp_def, comp_def] -theorem UniformInducing.inducing {f : α → β} (h : UniformInducing f) : Inducing f := by +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformContinuousOn_iff := IsUniformInducing.uniformContinuousOn_iff + +theorem IsUniformInducing.isInducing {f : α → β} (h : IsUniformInducing f) : IsInducing f := by obtain rfl := h.comap_uniformSpace - exact inducing_induced f + exact .induced f + +@[deprecated (since := "2024-10-28")] +alias IsUniformInducing.inducing := IsUniformInducing.isInducing + +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isInducing := IsUniformInducing.isInducing -theorem UniformInducing.prod {α' : Type*} {β' : Type*} [UniformSpace α'] [UniformSpace β'] - {e₁ : α → α'} {e₂ : β → β'} (h₁ : UniformInducing e₁) (h₂ : UniformInducing e₂) : - UniformInducing fun p : α × β => (e₁ p.1, e₂ p.2) := +@[deprecated (since := "2024-10-28")] alias UniformInducing.inducing := UniformInducing.isInducing + +theorem IsUniformInducing.prod {α' : Type*} {β' : Type*} [UniformSpace α'] [UniformSpace β'] + {e₁ : α → α'} {e₂ : β → β'} (h₁ : IsUniformInducing e₁) (h₂ : IsUniformInducing e₂) : + IsUniformInducing fun p : α × β => (e₁ p.1, e₂ p.2) := ⟨by simp [Function.comp_def, uniformity_prod, ← h₁.1, ← h₂.1, comap_inf, comap_comap]⟩ -theorem UniformInducing.isDenseInducing {f : α → β} (h : UniformInducing f) (hd : DenseRange f) : - IsDenseInducing f := - { dense := hd - induced := h.inducing.induced } +@[deprecated (since := "2024-10-05")] +alias UniformInducing.prod := IsUniformInducing.prod + +lemma IsUniformInducing.isDenseInducing (h : IsUniformInducing f) (hd : DenseRange f) : + IsDenseInducing f where + toIsInducing := h.isInducing + dense := hd + +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isDenseInducing := IsUniformInducing.isDenseInducing -theorem SeparationQuotient.uniformInducing_mk : UniformInducing (mk : α → SeparationQuotient α) := +lemma SeparationQuotient.isUniformInducing_mk : + IsUniformInducing (mk : α → SeparationQuotient α) := ⟨comap_mk_uniformity⟩ -protected theorem UniformInducing.injective [T0Space α] {f : α → β} (h : UniformInducing f) : +@[deprecated (since := "2024-10-05")] +alias SeparationQuotient.uniformInducing_mk := SeparationQuotient.isUniformInducing_mk + +protected theorem IsUniformInducing.injective [T0Space α] {f : α → β} (h : IsUniformInducing f) : Injective f := - h.inducing.injective + h.isInducing.injective + +@[deprecated (since := "2024-10-05")] +alias UniformInducing.injective := IsUniformInducing.injective /-! ### Uniform embeddings @@ -130,16 +199,19 @@ protected theorem UniformInducing.injective [T0Space α] {f : α → β} (h : Un /-- A map `f : α → β` between uniform spaces is a *uniform embedding* if it is uniform inducing and injective. If `α` is a separated space, then the latter assumption follows from the former. -/ @[mk_iff] -structure IsUniformEmbedding (f : α → β) extends UniformInducing f : Prop where +structure IsUniformEmbedding (f : α → β) extends IsUniformInducing f : Prop where /-- A uniform embedding is injective. -/ inj : Function.Injective f +lemma IsUniformEmbedding.isUniformInducing (hf : IsUniformEmbedding f) : IsUniformInducing f := + hf.toIsUniformInducing + @[deprecated (since := "2024-10-03")] alias UniformEmbedding := IsUniformEmbedding theorem isUniformEmbedding_iff' {f : α → β} : IsUniformEmbedding f ↔ Injective f ∧ UniformContinuous f ∧ comap (Prod.map f f) (𝓤 β) ≤ 𝓤 α := by - rw [isUniformEmbedding_iff, and_comm, uniformInducing_iff'] + rw [isUniformEmbedding_iff, and_comm, isUniformInducing_iff'] @[deprecated (since := "2024-10-01")] alias uniformEmbedding_iff' := isUniformEmbedding_iff' @@ -149,7 +221,7 @@ theorem Filter.HasBasis.isUniformEmbedding_iff' {ι ι'} {p : ι → Prop} {p' : IsUniformEmbedding f ↔ Injective f ∧ (∀ i, p' i → ∃ j, p j ∧ ∀ x y, (x, y) ∈ s j → (f x, f y) ∈ s' i) ∧ (∀ j, p j → ∃ i, p' i ∧ ∀ x y, (f x, f y) ∈ s' i → (x, y) ∈ s j) := by - rw [isUniformEmbedding_iff, and_comm, h.uniformInducing_iff h'] + rw [isUniformEmbedding_iff, and_comm, h.isUniformInducing_iff h'] @[deprecated (since := "2024-10-01")] alias Filter.HasBasis.uniformEmbedding_iff' := Filter.HasBasis.isUniformEmbedding_iff' @@ -181,14 +253,14 @@ alias uniformEmbedding_set_inclusion := isUniformEmbedding_set_inclusion theorem IsUniformEmbedding.comp {g : β → γ} (hg : IsUniformEmbedding g) {f : α → β} (hf : IsUniformEmbedding f) : IsUniformEmbedding (g ∘ f) := - { hg.toUniformInducing.comp hf.toUniformInducing with inj := hg.inj.comp hf.inj } + { hg.isUniformInducing.comp hf.isUniformInducing with inj := hg.inj.comp hf.inj } @[deprecated (since := "2024-10-01")] alias UniformEmbedding.comp := IsUniformEmbedding.comp theorem IsUniformEmbedding.of_comp_iff {g : β → γ} (hg : IsUniformEmbedding g) {f : α → β} : IsUniformEmbedding (g ∘ f) ↔ IsUniformEmbedding f := by - simp_rw [isUniformEmbedding_iff, hg.toUniformInducing.of_comp_iff, hg.inj.of_comp_iff f] + simp_rw [isUniformEmbedding_iff, hg.isUniformInducing.of_comp_iff, hg.inj.of_comp_iff f] @[deprecated (since := "2024-10-01")] alias UniformEmbedding.of_comp_iff := IsUniformEmbedding.of_comp_iff @@ -218,21 +290,27 @@ theorem isUniformEmbedding_inr : IsUniformEmbedding (Sum.inr : β → α ⊕ β) @[deprecated (since := "2024-10-01")] alias uniformEmbedding_inr := isUniformEmbedding_inr -/-- If the domain of a `UniformInducing` map `f` is a T₀ space, then `f` is injective, +/-- If the domain of a `IsUniformInducing` map `f` is a T₀ space, then `f` is injective, hence it is a `IsUniformEmbedding`. -/ -protected theorem UniformInducing.isUniformEmbedding [T0Space α] {f : α → β} - (hf : UniformInducing f) : IsUniformEmbedding f := - ⟨hf, hf.inducing.injective⟩ +protected theorem IsUniformInducing.isUniformEmbedding [T0Space α] {f : α → β} + (hf : IsUniformInducing f) : IsUniformEmbedding f := + ⟨hf, hf.isInducing.injective⟩ + +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isUniformEmbedding := IsUniformInducing.isUniformEmbedding @[deprecated (since := "2024-10-01")] -alias UniformInducing.uniformEmbedding := UniformInducing.isUniformEmbedding +alias IsUniformInducing.uniformEmbedding := IsUniformInducing.isUniformEmbedding -theorem isUniformEmbedding_iff_uniformInducing [T0Space α] {f : α → β} : - IsUniformEmbedding f ↔ UniformInducing f := - ⟨IsUniformEmbedding.toUniformInducing, UniformInducing.isUniformEmbedding⟩ +theorem isUniformEmbedding_iff_isUniformInducing [T0Space α] {f : α → β} : + IsUniformEmbedding f ↔ IsUniformInducing f := + ⟨IsUniformEmbedding.isUniformInducing, IsUniformInducing.isUniformEmbedding⟩ + +@[deprecated (since := "2024-10-05")] +alias isUniformEmbedding_iff_uniformInducing := isUniformEmbedding_iff_isUniformInducing @[deprecated (since := "2024-10-01")] -alias uniformEmbedding_iff_uniformInducing := isUniformEmbedding_iff_uniformInducing +alias uniformEmbedding_iff_isUniformInducing := isUniformEmbedding_iff_isUniformInducing /-- If a map `f : α → β` sends any two distinct points to point that are **not** related by a fixed `s ∈ 𝓤 β`, then `f` is uniform inducing with respect to the discrete uniformity on `α`: @@ -252,21 +330,25 @@ theorem comap_uniformity_of_spaced_out {α} {f : α → β} {s : Set (β × β)} theorem isUniformEmbedding_of_spaced_out {α} {f : α → β} {s : Set (β × β)} (hs : s ∈ 𝓤 β) (hf : Pairwise fun x y => (f x, f y) ∉ s) : @IsUniformEmbedding α β ⊥ ‹_› f := by let _ : UniformSpace α := ⊥; have := discreteTopology_bot α - exact UniformInducing.isUniformEmbedding ⟨comap_uniformity_of_spaced_out hs hf⟩ + exact IsUniformInducing.isUniformEmbedding ⟨comap_uniformity_of_spaced_out hs hf⟩ @[deprecated (since := "2024-10-01")] alias uniformEmbedding_of_spaced_out := isUniformEmbedding_of_spaced_out -protected lemma IsUniformEmbedding.embedding {f : α → β} (h : IsUniformEmbedding f) : Embedding f := - { toInducing := h.toUniformInducing.inducing - inj := h.inj } +protected lemma IsUniformEmbedding.isEmbedding {f : α → β} (h : IsUniformEmbedding f) : + IsEmbedding f where + toIsInducing := h.toIsUniformInducing.isInducing + inj := h.inj + +@[deprecated (since := "2024-10-26")] +alias IsUniformEmbedding.embedding := IsUniformEmbedding.isEmbedding @[deprecated (since := "2024-10-01")] -alias UniformEmbedding.embedding := IsUniformEmbedding.embedding +alias UniformEmbedding.embedding := IsUniformEmbedding.isEmbedding theorem IsUniformEmbedding.isDenseEmbedding {f : α → β} (h : IsUniformEmbedding f) (hd : DenseRange f) : IsDenseEmbedding f := - { h.embedding with dense := hd } + { h.isEmbedding with dense := hd } @[deprecated (since := "2024-10-01")] alias UniformEmbedding.isDenseEmbedding := IsUniformEmbedding.isDenseEmbedding @@ -274,16 +356,19 @@ alias UniformEmbedding.isDenseEmbedding := IsUniformEmbedding.isDenseEmbedding @[deprecated (since := "2024-09-30")] alias IsUniformEmbedding.denseEmbedding := IsUniformEmbedding.isDenseEmbedding -theorem closedEmbedding_of_spaced_out {α} [TopologicalSpace α] [DiscreteTopology α] +theorem isClosedEmbedding_of_spaced_out {α} [TopologicalSpace α] [DiscreteTopology α] [T0Space β] {f : α → β} {s : Set (β × β)} (hs : s ∈ 𝓤 β) - (hf : Pairwise fun x y => (f x, f y) ∉ s) : ClosedEmbedding f := by + (hf : Pairwise fun x y => (f x, f y) ∉ s) : IsClosedEmbedding f := by rcases @DiscreteTopology.eq_bot α _ _ with rfl; let _ : UniformSpace α := ⊥ exact - { (isUniformEmbedding_of_spaced_out hs hf).embedding with + { (isUniformEmbedding_of_spaced_out hs hf).isEmbedding with isClosed_range := isClosed_range_of_spaced_out hs hf } -theorem closure_image_mem_nhds_of_uniformInducing {s : Set (α × α)} {e : α → β} (b : β) - (he₁ : UniformInducing e) (he₂ : IsDenseInducing e) (hs : s ∈ 𝓤 α) : +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_of_spaced_out := isClosedEmbedding_of_spaced_out + +theorem closure_image_mem_nhds_of_isUniformInducing {s : Set (α × α)} {e : α → β} (b : β) + (he₁ : IsUniformInducing e) (he₂ : IsDenseInducing e) (hs : s ∈ 𝓤 α) : ∃ a, closure (e '' { a' | (a, a') ∈ s }) ∈ 𝓝 b := by obtain ⟨U, ⟨hU, hUo, hsymm⟩, hs⟩ : ∃ U, (U ∈ 𝓤 β ∧ IsOpen U ∧ SymmetricRel U) ∧ Prod.map e e ⁻¹' U ⊆ s := by @@ -296,6 +381,9 @@ theorem closure_image_mem_nhds_of_uniformInducing {s : Set (α × α)} {e : α rcases he₂.dense.mem_nhds (inter_mem hV (ho.mem_nhds hy)) with ⟨x, hxV, hxU⟩ exact ⟨e x, hxV, mem_image_of_mem e hxU⟩ +@[deprecated (since := "2024-10-05")] +alias closure_image_mem_nhds_of_uniformInducing := closure_image_mem_nhds_of_isUniformInducing + theorem isUniformEmbedding_subtypeEmb (p : α → Prop) {e : α → β} (ue : IsUniformEmbedding e) (de : IsDenseEmbedding e) : IsUniformEmbedding (IsDenseEmbedding.subtypeEmb p e) := { comap_uniformity := by @@ -309,28 +397,31 @@ alias uniformEmbedding_subtypeEmb := isUniformEmbedding_subtypeEmb theorem IsUniformEmbedding.prod {α' : Type*} {β' : Type*} [UniformSpace α'] [UniformSpace β'] {e₁ : α → α'} {e₂ : β → β'} (h₁ : IsUniformEmbedding e₁) (h₂ : IsUniformEmbedding e₂) : IsUniformEmbedding fun p : α × β => (e₁ p.1, e₂ p.2) := - { h₁.toUniformInducing.prod h₂.toUniformInducing with inj := h₁.inj.prodMap h₂.inj } + { h₁.isUniformInducing.prod h₂.isUniformInducing with inj := h₁.inj.prodMap h₂.inj } @[deprecated (since := "2024-10-01")] alias UniformEmbedding.prod := IsUniformEmbedding.prod /-- A set is complete iff its image under a uniform inducing map is complete. -/ -theorem isComplete_image_iff {m : α → β} {s : Set α} (hm : UniformInducing m) : +theorem isComplete_image_iff {m : α → β} {s : Set α} (hm : IsUniformInducing m) : IsComplete (m '' s) ↔ IsComplete s := by have fact1 : SurjOn (map m) (Iic <| 𝓟 s) (Iic <| 𝓟 <| m '' s) := surjOn_image .. |>.filter_map_Iic have fact2 : MapsTo (map m) (Iic <| 𝓟 s) (Iic <| 𝓟 <| m '' s) := mapsTo_image .. |>.filter_map_Iic simp_rw [IsComplete, imp.swap (a := Cauchy _), ← mem_Iic (b := 𝓟 _), fact1.forall fact2, - hm.cauchy_map_iff, exists_mem_image, map_le_iff_le_comap, hm.inducing.nhds_eq_comap] + hm.cauchy_map_iff, exists_mem_image, map_le_iff_le_comap, hm.isInducing.nhds_eq_comap] -/-- If `f : X → Y` is an `UniformInducing` map, the image `f '' s` of a set `s` is complete +/-- If `f : X → Y` is an `IsUniformInducing` map, the image `f '' s` of a set `s` is complete if and only if `s` is complete. -/ -theorem UniformInducing.isComplete_iff {f : α → β} {s : Set α} (hf : UniformInducing f) : +theorem IsUniformInducing.isComplete_iff {f : α → β} {s : Set α} (hf : IsUniformInducing f) : IsComplete (f '' s) ↔ IsComplete s := isComplete_image_iff hf +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isComplete_iff := IsUniformInducing.isComplete_iff + /-- If `f : X → Y` is an `IsUniformEmbedding`, the image `f '' s` of a set `s` is complete if and only if `s` is complete. -/ theorem IsUniformEmbedding.isComplete_iff {f : α → β} {s : Set α} (hf : IsUniformEmbedding f) : - IsComplete (f '' s) ↔ IsComplete s := hf.toUniformInducing.isComplete_iff + IsComplete (f '' s) ↔ IsComplete s := hf.isUniformInducing.isComplete_iff @[deprecated (since := "2024-10-01")] alias UniformEmbedding.isComplete_iff := IsUniformEmbedding.isComplete_iff @@ -342,39 +433,48 @@ theorem Subtype.isComplete_iff {p : α → Prop} {s : Set { x // p x }} : alias ⟨isComplete_of_complete_image, _⟩ := isComplete_image_iff -theorem completeSpace_iff_isComplete_range {f : α → β} (hf : UniformInducing f) : +theorem completeSpace_iff_isComplete_range {f : α → β} (hf : IsUniformInducing f) : CompleteSpace α ↔ IsComplete (range f) := by rw [completeSpace_iff_isComplete_univ, ← isComplete_image_iff hf, image_univ] -alias ⟨_, UniformInducing.completeSpace⟩ := completeSpace_iff_isComplete_range +alias ⟨_, IsUniformInducing.completeSpace⟩ := completeSpace_iff_isComplete_range -theorem UniformInducing.isComplete_range [CompleteSpace α] {f : α → β} (hf : UniformInducing f) : +@[deprecated (since := "2024-10-08")] alias UniformInducing.completeSpace := + IsUniformInducing.completeSpace + +lemma IsUniformInducing.isComplete_range [CompleteSpace α] (hf : IsUniformInducing f) : IsComplete (range f) := (completeSpace_iff_isComplete_range hf).1 ‹_› +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isComplete_range := IsUniformInducing.isComplete_range + /-- If `f` is a surjective uniform inducing map, then its domain is a complete space iff its codomain is a complete space. See also `_root_.completeSpace_congr` for a version that assumes `f` to be an equivalence. -/ -theorem UniformInducing.completeSpace_congr {f : α → β} (hf : UniformInducing f) +theorem IsUniformInducing.completeSpace_congr {f : α → β} (hf : IsUniformInducing f) (hsurj : f.Surjective) : CompleteSpace α ↔ CompleteSpace β := by rw [completeSpace_iff_isComplete_range hf, hsurj.range_eq, completeSpace_iff_isComplete_univ] +@[deprecated (since := "2024-10-05")] +alias UniformInducing.completeSpace_congr := IsUniformInducing.completeSpace_congr + theorem SeparationQuotient.completeSpace_iff : CompleteSpace (SeparationQuotient α) ↔ CompleteSpace α := - .symm <| uniformInducing_mk.completeSpace_congr surjective_mk + .symm <| isUniformInducing_mk.completeSpace_congr surjective_mk instance SeparationQuotient.instCompleteSpace [CompleteSpace α] : CompleteSpace (SeparationQuotient α) := completeSpace_iff.2 ‹_› -/-- See also `UniformInducing.completeSpace_congr` +/-- See also `IsUniformInducing.completeSpace_congr` for a version that works for non-injective maps. -/ theorem completeSpace_congr {e : α ≃ β} (he : IsUniformEmbedding e) : CompleteSpace α ↔ CompleteSpace β := he.completeSpace_congr e.surjective theorem completeSpace_coe_iff_isComplete {s : Set α} : CompleteSpace s ↔ IsComplete s := by - rw [completeSpace_iff_isComplete_range isUniformEmbedding_subtype_val.toUniformInducing, + rw [completeSpace_iff_isComplete_range isUniformEmbedding_subtype_val.isUniformInducing, Subtype.range_coe] alias ⟨_, IsComplete.completeSpace_coe⟩ := completeSpace_coe_iff_isComplete @@ -384,45 +484,45 @@ theorem IsClosed.completeSpace_coe [CompleteSpace α] {s : Set α} (hs : IsClose hs.isComplete.completeSpace_coe theorem completeSpace_ulift_iff : CompleteSpace (ULift α) ↔ CompleteSpace α := - UniformInducing.completeSpace_congr ⟨rfl⟩ ULift.down_surjective + IsUniformInducing.completeSpace_congr ⟨rfl⟩ ULift.down_surjective /-- The lift of a complete space to another universe is still complete. -/ instance ULift.instCompleteSpace [CompleteSpace α] : CompleteSpace (ULift α) := completeSpace_ulift_iff.2 ‹_› -theorem completeSpace_extension {m : β → α} (hm : UniformInducing m) (dense : DenseRange m) +theorem completeSpace_extension {m : β → α} (hm : IsUniformInducing m) (dense : DenseRange m) (h : ∀ f : Filter β, Cauchy f → ∃ x : α, map m f ≤ 𝓝 x) : CompleteSpace α := ⟨fun {f : Filter α} (hf : Cauchy f) => let p : Set (α × α) → Set α → Set α := fun s t => { y : α | ∃ x : α, x ∈ t ∧ (x, y) ∈ s } let g := (𝓤 α).lift fun s => f.lift' (p s) - have mp₀ : Monotone p := fun a b h t s ⟨x, xs, xa⟩ => ⟨x, xs, h xa⟩ - have mp₁ : ∀ {s}, Monotone (p s) := fun h x ⟨y, ya, yxs⟩ => ⟨y, h ya, yxs⟩ - have : f ≤ g := le_iInf₂ fun s hs => le_iInf₂ fun t ht => + have mp₀ : Monotone p := fun _ _ h _ _ ⟨x, xs, xa⟩ => ⟨x, xs, h xa⟩ + have mp₁ : ∀ {s}, Monotone (p s) := fun h _ ⟨y, ya, yxs⟩ => ⟨y, h ya, yxs⟩ + have : f ≤ g := le_iInf₂ fun _ hs => le_iInf₂ fun _ ht => le_principal_iff.mpr <| mem_of_superset ht fun x hx => ⟨x, hx, refl_mem_uniformity hs⟩ have : NeBot g := hf.left.mono this have : NeBot (comap m g) := - comap_neBot fun t ht => + comap_neBot fun _ ht => let ⟨t', ht', ht_mem⟩ := (mem_lift_sets <| monotone_lift' monotone_const mp₀).mp ht - let ⟨t'', ht'', ht'_sub⟩ := (mem_lift'_sets mp₁).mp ht_mem - let ⟨x, (hx : x ∈ t'')⟩ := hf.left.nonempty_of_mem ht'' + let ⟨_, ht'', ht'_sub⟩ := (mem_lift'_sets mp₁).mp ht_mem + let ⟨x, hx⟩ := hf.left.nonempty_of_mem ht'' have h₀ : NeBot (𝓝[range m] x) := dense.nhdsWithin_neBot x have h₁ : { y | (x, y) ∈ t' } ∈ 𝓝[range m] x := @mem_inf_of_left α (𝓝 x) (𝓟 (range m)) _ <| mem_nhds_left x ht' have h₂ : range m ∈ 𝓝[range m] x := @mem_inf_of_right α (𝓝 x) (𝓟 (range m)) _ <| Subset.refl _ have : { y | (x, y) ∈ t' } ∩ range m ∈ 𝓝[range m] x := @inter_mem α (𝓝[range m] x) _ _ h₁ h₂ - let ⟨y, xyt', b, b_eq⟩ := h₀.nonempty_of_mem this + let ⟨_, xyt', b, b_eq⟩ := h₀.nonempty_of_mem this ⟨b, b_eq.symm ▸ ht'_sub ⟨x, hx, xyt'⟩⟩ have : Cauchy g := - ⟨‹NeBot g›, fun s hs => - let ⟨s₁, hs₁, (comp_s₁ : compRel s₁ s₁ ⊆ s)⟩ := comp_mem_uniformity_sets hs - let ⟨s₂, hs₂, (comp_s₂ : compRel s₂ s₂ ⊆ s₁)⟩ := comp_mem_uniformity_sets hs₁ + ⟨‹NeBot g›, fun _ hs => + let ⟨s₁, hs₁, comp_s₁⟩ := comp_mem_uniformity_sets hs + let ⟨s₂, hs₂, comp_s₂⟩ := comp_mem_uniformity_sets hs₁ let ⟨t, ht, (prod_t : t ×ˢ t ⊆ s₂)⟩ := mem_prod_same_iff.mp (hf.right hs₂) have hg₁ : p (preimage Prod.swap s₁) t ∈ g := mem_lift (symm_le_uniformity hs₁) <| @mem_lift' α α f _ t ht have hg₂ : p s₂ t ∈ g := mem_lift hs₂ <| @mem_lift' α α f _ t ht have hg : p (Prod.swap ⁻¹' s₁) t ×ˢ p s₂ t ∈ g ×ˢ g := @prod_mem_prod α α _ _ g g hg₁ hg₂ - (g ×ˢ g).sets_of_superset hg fun ⟨a, b⟩ ⟨⟨c₁, c₁t, hc₁⟩, ⟨c₂, c₂t, hc₂⟩⟩ => + (g ×ˢ g).sets_of_superset hg fun ⟨_, _⟩ ⟨⟨c₁, c₁t, hc₁⟩, ⟨c₂, c₂t, hc₂⟩⟩ => have : (c₁, c₂) ∈ t ×ˢ t := ⟨c₁t, c₂t⟩ comp_s₁ <| prod_mk_mem_compRel hc₁ <| comp_s₂ <| prod_mk_mem_compRel (prod_t this) hc₂⟩ have : Cauchy (Filter.comap m g) := ‹Cauchy g›.comap' (le_of_eq hm.comap_uniformity) ‹_› @@ -436,7 +536,7 @@ theorem completeSpace_extension {m : β → α} (hm : UniformInducing m) (dense _ ≤ 𝓝 x := le_nhds_of_cauchy_adhp ‹Cauchy g› this ⟩⟩ -lemma totallyBounded_image_iff {f : α → β} {s : Set α} (hf : UniformInducing f) : +lemma totallyBounded_image_iff {f : α → β} {s : Set α} (hf : IsUniformInducing f) : TotallyBounded (f '' s) ↔ TotallyBounded s := by refine ⟨fun hs ↦ ?_, fun h ↦ h.image hf.uniformContinuous⟩ simp_rw [(hf.basis_uniformity (basis_sets _)).totallyBounded_iff] @@ -445,33 +545,36 @@ lemma totallyBounded_image_iff {f : α → β} {s : Set α} (hf : UniformInducin use u, hfin rwa [biUnion_image, image_subset_iff, preimage_iUnion₂] at h -theorem totallyBounded_preimage {f : α → β} {s : Set β} (hf : UniformInducing f) +theorem totallyBounded_preimage {f : α → β} {s : Set β} (hf : IsUniformInducing f) (hs : TotallyBounded s) : TotallyBounded (f ⁻¹' s) := (totallyBounded_image_iff hf).1 <| hs.subset <| image_preimage_subset .. instance CompleteSpace.sum [CompleteSpace α] [CompleteSpace β] : CompleteSpace (α ⊕ β) := by rw [completeSpace_iff_isComplete_univ, ← range_inl_union_range_inr] - exact isUniformEmbedding_inl.toUniformInducing.isComplete_range.union - isUniformEmbedding_inr.toUniformInducing.isComplete_range + exact isUniformEmbedding_inl.isUniformInducing.isComplete_range.union + isUniformEmbedding_inr.isUniformInducing.isComplete_range end theorem isUniformEmbedding_comap {α : Type*} {β : Type*} {f : α → β} [u : UniformSpace β] (hf : Function.Injective f) : @IsUniformEmbedding α β (UniformSpace.comap f u) u f := @IsUniformEmbedding.mk _ _ (UniformSpace.comap f u) _ _ - (@UniformInducing.mk _ _ (UniformSpace.comap f u) _ _ rfl) hf + (@IsUniformInducing.mk _ _ (UniformSpace.comap f u) _ _ rfl) hf @[deprecated (since := "2024-10-01")] alias uniformEmbedding_comap := isUniformEmbedding_comap /-- Pull back a uniform space structure by an embedding, adjusting the new uniform structure to make sure that its topology is defeq to the original one. -/ -def Embedding.comapUniformSpace {α β} [TopologicalSpace α] [u : UniformSpace β] (f : α → β) - (h : Embedding f) : UniformSpace α := - (u.comap f).replaceTopology h.induced +def IsEmbedding.comapUniformSpace {α β} [TopologicalSpace α] [u : UniformSpace β] + (f : α → β) (h : IsEmbedding f) : UniformSpace α := + (u.comap f).replaceTopology h.eq_induced + +@[deprecated (since := "2024-10-26")] +alias Embedding.comapUniformSpace := IsEmbedding.comapUniformSpace theorem Embedding.to_isUniformEmbedding {α β} [TopologicalSpace α] [u : UniformSpace β] (f : α → β) - (h : Embedding f) : @IsUniformEmbedding α β (h.comapUniformSpace f) u f := + (h : IsEmbedding f) : @IsUniformEmbedding α β (h.comapUniformSpace f) u f := let _ := h.comapUniformSpace f { comap_uniformity := rfl inj := h.inj } @@ -482,10 +585,10 @@ alias Embedding.to_uniformEmbedding := Embedding.to_isUniformEmbedding section UniformExtension variable {α : Type*} {β : Type*} {γ : Type*} [UniformSpace α] [UniformSpace β] [UniformSpace γ] - {e : β → α} (h_e : UniformInducing e) (h_dense : DenseRange e) {f : β → γ} + {e : β → α} (h_e : IsUniformInducing e) (h_dense : DenseRange e) {f : β → γ} (h_f : UniformContinuous f) -local notation "ψ" => IsDenseInducing.extend (UniformInducing.isDenseInducing h_e h_dense) f +local notation "ψ" => IsDenseInducing.extend (IsUniformInducing.isDenseInducing h_e h_dense) f include h_e h_dense h_f in theorem uniformly_extend_exists [CompleteSpace γ] (a : α) : ∃ c, Tendsto f (comap e (𝓝 a)) (𝓝 c) := @@ -506,12 +609,12 @@ theorem uniform_extend_subtype [CompleteSpace γ] {p : α → Prop} {e : α → isUniformEmbedding_subtypeEmb _ he de have : b ∈ closure (e '' { x | p x }) := (closure_mono <| monotone_image <| hp) (mem_of_mem_nhds hb) - let ⟨c, hc⟩ := uniformly_extend_exists ue'.toUniformInducing de'.dense hf ⟨b, this⟩ + let ⟨c, hc⟩ := uniformly_extend_exists ue'.isUniformInducing de'.dense hf ⟨b, this⟩ replace hc : Tendsto (f ∘ Subtype.val (p := p)) (((𝓝 b).comap e).comap Subtype.val) (𝓝 c) := by simpa only [nhds_subtype_eq_comap, comap_comap, IsDenseEmbedding.subtypeEmb_coe] using hc refine ⟨c, (tendsto_comap'_iff ?_).1 hc⟩ rw [Subtype.range_coe_subtype] - exact ⟨_, hb, by rwa [← de.toInducing.closure_eq_preimage_closure_image, hs.closure_eq]⟩ + exact ⟨_, hb, by rwa [← de.isInducing.closure_eq_preimage_closure_image, hs.closure_eq]⟩ include h_e h_f in theorem uniformly_extend_spec [CompleteSpace γ] (a : α) : Tendsto f (comap e (𝓝 a)) (𝓝 (ψ a)) := by diff --git a/Mathlib/Topology/UnitInterval.lean b/Mathlib/Topology/UnitInterval.lean index 55c6405dda1b6..40404390094c0 100644 --- a/Mathlib/Topology/UnitInterval.lean +++ b/Mathlib/Topology/UnitInterval.lean @@ -209,6 +209,20 @@ theorem mul_pos_mem_iff {a t : ℝ} (ha : 0 < a) : a * t ∈ I ↔ t ∈ Set.Icc theorem two_mul_sub_one_mem_iff {t : ℝ} : 2 * t - 1 ∈ I ↔ t ∈ Set.Icc (1 / 2 : ℝ) 1 := by constructor <;> rintro ⟨h₁, h₂⟩ <;> constructor <;> linarith +/-- The unit interval as a submonoid of ℝ. -/ +def submonoid : Submonoid ℝ where + carrier := unitInterval + one_mem' := unitInterval.one_mem + mul_mem' := unitInterval.mul_mem + +@[simp] theorem coe_unitIntervalSubmonoid : submonoid = unitInterval := rfl +@[simp] theorem mem_unitIntervalSubmonoid {x} : x ∈ submonoid ↔ x ∈ unitInterval := + Iff.rfl + +protected theorem prod_mem {ι : Type*} {t : Finset ι} {f : ι → ℝ} + (h : ∀ c ∈ t, f c ∈ unitInterval) : + ∏ c ∈ t, f c ∈ unitInterval := _root_.prod_mem (S := unitInterval.submonoid) h + instance : LinearOrderedCommMonoidWithZero I where zero_mul i := zero_mul i mul_zero i := mul_zero i diff --git a/Mathlib/Topology/UrysohnsLemma.lean b/Mathlib/Topology/UrysohnsLemma.lean index 705eb5ca08358..f645df48176ff 100644 --- a/Mathlib/Topology/UrysohnsLemma.lean +++ b/Mathlib/Topology/UrysohnsLemma.lean @@ -6,9 +6,9 @@ Authors: Yury Kudryashov import Mathlib.Analysis.Normed.Affine.AddTorsor import Mathlib.LinearAlgebra.AffineSpace.Ordered import Mathlib.Topology.ContinuousMap.Basic -import Mathlib.Topology.GDelta import Mathlib.Analysis.NormedSpace.FunctionSeries import Mathlib.Analysis.SpecificLimits.Basic +import Mathlib.Topology.GDelta.Basic /-! # Urysohn's lemma diff --git a/Mathlib/Topology/VectorBundle/Basic.lean b/Mathlib/Topology/VectorBundle/Basic.lean index cf55b20054f31..31c9591760810 100644 --- a/Mathlib/Topology/VectorBundle/Basic.lean +++ b/Mathlib/Topology/VectorBundle/Basic.lean @@ -384,7 +384,7 @@ def continuousLinearMapAt (e : Trivialization F (π F E)) [e.IsLinear R] (b : B) rw [e.coe_linearMapAt b] classical refine continuous_if_const _ (fun hb => ?_) fun _ => continuous_zero - exact (e.continuousOn.comp_continuous (FiberBundle.totalSpaceMk_inducing F E b).continuous + exact (e.continuousOn.comp_continuous (FiberBundle.totalSpaceMk_isInducing F E b).continuous fun x => e.mem_source.mpr hb).snd } /-- Backwards map of `Trivialization.continuousLinearEquivAt`, defined everywhere. -/ @@ -394,7 +394,7 @@ def symmL (e : Trivialization F (π F E)) [e.IsLinear R] (b : B) : F →L[R] E b toFun := e.symm b -- given explicitly to help `simps` cont := by by_cases hb : b ∈ e.baseSet - · rw [(FiberBundle.totalSpaceMk_inducing F E b).continuous_iff] + · rw [(FiberBundle.totalSpaceMk_isInducing F E b).continuous_iff] exact e.continuousOn_symm.comp_continuous (continuous_const.prod_mk continuous_id) fun x ↦ mk_mem_prod hb (mem_univ x) · refine continuous_zero.congr fun x => (e.symm_apply_of_not_mem hb x).symm } @@ -420,7 +420,7 @@ def continuousLinearEquivAt (e : Trivialization F (π F E)) [e.IsLinear R] (b : toFun := fun y => (e ⟨b, y⟩).2 -- given explicitly to help `simps` invFun := e.symm b -- given explicitly to help `simps` continuous_toFun := (e.continuousOn.comp_continuous - (FiberBundle.totalSpaceMk_inducing F E b).continuous fun _ => e.mem_source.mpr hb).snd + (FiberBundle.totalSpaceMk_isInducing F E b).continuous fun _ => e.mem_source.mpr hb).snd continuous_invFun := (e.symmL R b).continuous } variable {R} @@ -756,7 +756,7 @@ structure VectorPrebundle where exists_coordChange : ∀ᵉ (e ∈ pretrivializationAtlas) (e' ∈ pretrivializationAtlas), ∃ f : B → F →L[R] F, ContinuousOn f (e.baseSet ∩ e'.baseSet) ∧ ∀ᵉ (b ∈ e.baseSet ∩ e'.baseSet) (v : F), f b v = (e' ⟨b, e.symm b v⟩).2 - totalSpaceMk_inducing : ∀ b : B, Inducing (pretrivializationAt b ∘ .mk b) + totalSpaceMk_isInducing : ∀ b : B, IsInducing (pretrivializationAt b ∘ .mk b) namespace VectorPrebundle diff --git a/Mathlib/Topology/VectorBundle/Hom.lean b/Mathlib/Topology/VectorBundle/Hom.lean index 3b7a3339e4105..2a67051dc12ae 100644 --- a/Mathlib/Topology/VectorBundle/Hom.lean +++ b/Mathlib/Topology/VectorBundle/Hom.lean @@ -109,8 +109,8 @@ def continuousLinearMap : invFun p := ⟨p.1, .comp (e₂.symmL 𝕜₂ p.1) (p.2.comp (e₁.continuousLinearMapAt 𝕜₁ p.1))⟩ source := Bundle.TotalSpace.proj ⁻¹' (e₁.baseSet ∩ e₂.baseSet) target := (e₁.baseSet ∩ e₂.baseSet) ×ˢ Set.univ - map_source' := fun ⟨x, L⟩ h => ⟨h, Set.mem_univ _⟩ - map_target' := fun ⟨x, f⟩ h => h.1 + map_source' := fun ⟨_, _⟩ h => ⟨h, Set.mem_univ _⟩ + map_target' := fun ⟨_, _⟩ h => h.1 left_inv' := fun ⟨x, L⟩ ⟨h₁, h₂⟩ => by simp only [TotalSpace.mk_inj] ext (v : E₁ x) @@ -209,7 +209,7 @@ def Bundle.ContinuousLinearMap.vectorPrebundle : exact ⟨continuousLinearMapCoordChange σ e₁ e₁' e₂ e₂', continuousOn_continuousLinearMapCoordChange, continuousLinearMapCoordChange_apply σ e₁ e₁' e₂ e₂'⟩ - totalSpaceMk_inducing := by + totalSpaceMk_isInducing := by intro b let L₁ : E₁ b ≃L[𝕜₁] F₁ := (trivializationAt F₁ E₁ b).continuousLinearEquivAt 𝕜₁ b @@ -218,7 +218,7 @@ def Bundle.ContinuousLinearMap.vectorPrebundle : (trivializationAt F₂ E₂ b).continuousLinearEquivAt 𝕜₂ b (mem_baseSet_trivializationAt _ _ _) let φ : (E₁ b →SL[σ] E₂ b) ≃L[𝕜₂] F₁ →SL[σ] F₂ := L₁.arrowCongrSL L₂ - have : Inducing fun x => (b, φ x) := inducing_const_prod.mpr φ.toHomeomorph.inducing + have : IsInducing fun x => (b, φ x) := isInducing_const_prod.mpr φ.toHomeomorph.isInducing convert this ext f dsimp [Pretrivialization.continuousLinearMap_apply] diff --git a/Mathlib/Util/AssertExistsExt.lean b/Mathlib/Util/AssertExistsExt.lean index e97a78563f4cf..01a1ab3953f48 100644 --- a/Mathlib/Util/AssertExistsExt.lean +++ b/Mathlib/Util/AssertExistsExt.lean @@ -5,6 +5,7 @@ Authors: Damiano Testa -/ import Lean.Environment +import Mathlib.Init /-! # Environment extension for tracking existence of declarations and imports @@ -12,8 +13,7 @@ import Lean.Environment This is used by the `assert_not_exists` and `assert_not_imported` commands. -/ -section -open Lean Elab Meta +open Lean namespace Mathlib.AssertNotExist diff --git a/Mathlib/Util/AtomM.lean b/Mathlib/Util/AtomM.lean index 2c411702a829b..0b829028c0b11 100644 --- a/Mathlib/Util/AtomM.lean +++ b/Mathlib/Util/AtomM.lean @@ -22,7 +22,7 @@ namespace Mathlib.Tactic open Lean Meta /-- The context (read-only state) of the `AtomM` monad. -/ -structure AtomM.Context := +structure AtomM.Context where /-- The reducibility setting for definitional equality of atoms -/ red : TransparencyMode /-- A simplification to apply to atomic expressions when they are encountered, @@ -31,7 +31,7 @@ structure AtomM.Context := deriving Inhabited /-- The mutable state of the `AtomM` monad. -/ -structure AtomM.State := +structure AtomM.State where /-- The list of atoms-up-to-defeq encountered thus far, used for atom sorting. -/ atoms : Array Expr := #[] diff --git a/Mathlib/Util/CountHeartbeats.lean b/Mathlib/Util/CountHeartbeats.lean index bbc00430ba743..65bb809fa657c 100644 --- a/Mathlib/Util/CountHeartbeats.lean +++ b/Mathlib/Util/CountHeartbeats.lean @@ -117,6 +117,31 @@ elab "count_heartbeats " "in" ppLine cmd:command : command => do Lean.Meta.Tactic.TryThis.addSuggestion (← getRef) (← set_option hygiene false in `(command| set_option maxHeartbeats $m in $cmd)) +/-- +Guard the minimal number of heartbeats used in the enclosed command. + +This is most useful in the context of debugging and minimizing an example of a slow declaration. +By guarding the number of heartbeats used in the slow declaration, +an error message will be generated if a minimization step makes the slow behaviour go away. + +The default number of minimal heartbeats is the value of `maxHeartbeats` (typically 200000). +Alternatively, you can specify a number of heartbeats to guard against, +using the syntax `guard_min_heartbeats n in cmd`. +-/ +elab "guard_min_heartbeats " n:(num)? "in" ppLine cmd:command : command => do + let max := (← Command.liftCoreM getMaxHeartbeats) / 1000 + let n := match n with + | some j => j.getNat + | none => max + let start ← IO.getNumHeartbeats + try + elabCommand (← `(command| set_option maxHeartbeats 0 in $cmd)) + finally + let finish ← IO.getNumHeartbeats + let elapsed := (finish - start) / 1000 + if elapsed < n then + logInfo m!"Used {elapsed} heartbeats, which is less than the minimum of {n}." + /-- Run a command, optionally restoring the original state, and report just the number of heartbeats. -/ diff --git a/Mathlib/Util/FormatTable.lean b/Mathlib/Util/FormatTable.lean index 036f4dfd32366..78b52c1eba4e5 100644 --- a/Mathlib/Util/FormatTable.lean +++ b/Mathlib/Util/FormatTable.lean @@ -38,14 +38,18 @@ def formatTable (headers : Array String) (table : Array (Array String)) String := Id.run do -- If no alignments are provided, default to left alignment for all columns. let alignments := alignments.getD (Array.mkArray headers.size Alignment.left) + -- Escape all vertical bar characters inside a table cell, + -- otherwise these could get interpreted as starting a new row or column. + let escapedHeaders := headers.map (fun header => header.replace "|" "\\|") + let escapedTable := table.map (fun row => row.map (fun cell => cell.replace "|" "\\|")) -- Compute the maximum width of each column. - let mut widths := headers.map (·.length) - for row in table do + let mut widths := escapedHeaders.map (·.length) + for row in escapedTable do for i in [0:widths.size] do widths := widths.set! i (max widths[i]! ((row[i]?.map (·.length)).getD 0)) -- Pad each cell with spaces to match the column width. - let paddedHeaders := headers.mapIdx fun i h => h.rightpad widths[i]! - let paddedTable := table.map fun row => row.mapIdx fun i cell => + let paddedHeaders := escapedHeaders.mapIdx fun i h => h.rightpad widths[i]! + let paddedTable := escapedTable.map fun row => row.mapIdx fun i cell => cell.justify alignments[i]! widths[i]! -- Construct the lines of the table let headerLine := "| " ++ String.intercalate " | " (paddedHeaders.toList) ++ " |" @@ -54,10 +58,12 @@ def formatTable (headers : Array String) (table : Array (Array String)) "| " ++ String.intercalate " | " (((widths.zip alignments).map fun ⟨w, a⟩ => - match a with - | Alignment.left => ":" ++ String.replicate (w-1) '-' - | Alignment.right => String.replicate (w-1) '-' ++ ":" - | Alignment.center => ":" ++ String.replicate (w-2) '-' ++ ":" + match w, a with + | 0, _ => "" + | 1, _ => "-" + | _ + 2, Alignment.left => ":" ++ String.replicate (w-1) '-' + | _ + 2, Alignment.right => String.replicate (w-1) '-' ++ ":" + | _ + 2, Alignment.center => ":" ++ String.replicate (w-2) '-' ++ ":" ).toList) ++ " |" let rowLines := paddedTable.map (fun row => "| " ++ String.intercalate " | " (row.toList) ++ " |") diff --git a/Mathlib/Util/IncludeStr.lean b/Mathlib/Util/IncludeStr.lean index 691268eaf5e17..662a23839c5ff 100644 --- a/Mathlib/Util/IncludeStr.lean +++ b/Mathlib/Util/IncludeStr.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Henrik Böving, Xubai Wang -/ import Mathlib.Init -import Lean /-! # Defines the `include_str` macro. diff --git a/Mathlib/Util/Notation3.lean b/Mathlib/Util/Notation3.lean index 9ca6324227c12..ed7d896d499e1 100644 --- a/Mathlib/Util/Notation3.lean +++ b/Mathlib/Util/Notation3.lean @@ -3,6 +3,8 @@ Copyright (c) 2021 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kyle Miller -/ +import Lean.Elab.BuiltinCommand +import Lean.Elab.MacroArgUtil import Mathlib.Lean.Elab.Term import Mathlib.Lean.PrettyPrinter.Delaborator import Mathlib.Tactic.ScopedNS diff --git a/Mathlib/Util/SleepHeartbeats.lean b/Mathlib/Util/SleepHeartbeats.lean index 7716e32f74a86..f6cb76c320e8d 100644 --- a/Mathlib/Util/SleepHeartbeats.lean +++ b/Mathlib/Util/SleepHeartbeats.lean @@ -34,7 +34,6 @@ elab "sleep_heartbeats " n:num : tactic => do option -/ | some m => sleepAtLeastHeartbeats (m * 1000) -set_option linter.unusedTactic false in example : 1 = 1 := by sleep_heartbeats 1000 rfl diff --git a/Mathlib/Util/Superscript.lean b/Mathlib/Util/Superscript.lean index a696144b7f9fe..85d3b2fecae7f 100644 --- a/Mathlib/Util/Superscript.lean +++ b/Mathlib/Util/Superscript.lean @@ -95,7 +95,8 @@ partial def satisfyTokensFn (p : Char → Bool) (errorMsg : String) (many := tru variable {α : Type u} [Inhabited α] (as : Array α) (leftOfPartition : α → Bool) in /-- Given a predicate `leftOfPartition` which is true for indexes `< i` and false for `≥ i`, returns `i`, by binary search. -/ -@[specialize] partial def partitionPoint (lo := 0) (hi := as.size) : Nat := +@[specialize] +def partitionPoint (lo := 0) (hi := as.size) : Nat := if lo < hi then let m := (lo + hi)/2 let a := as.get! m @@ -104,6 +105,7 @@ returns `i`, by binary search. -/ else partitionPoint lo m else lo + termination_by hi - lo /-- The core function for super/subscript parsing. It consists of three stages: diff --git a/Mathlib/Util/Tactic.lean b/Mathlib/Util/Tactic.lean index 41a28ecce696f..e46e14c30ba76 100644 --- a/Mathlib/Util/Tactic.lean +++ b/Mathlib/Util/Tactic.lean @@ -16,7 +16,7 @@ namespace Mathlib.Tactic open Lean Meta Tactic -variable {m : Type → Type} [Monad m] +variable {m : Type → Type} /-- `modifyMetavarDecl mvarId f` updates the `MetavarDecl` for `mvarId` with `f`. @@ -31,7 +31,7 @@ Conditions on `f`: If `mvarId` does not refer to a declared metavariable, nothing happens. -/ def modifyMetavarDecl [MonadMCtx m] (mvarId : MVarId) - (f : MetavarDecl → MetavarDecl) : m Unit := do + (f : MetavarDecl → MetavarDecl) : m Unit := modifyMCtx fun mctx ↦ match mctx.decls.find? mvarId with | none => mctx diff --git a/Mathlib/Util/WhatsNew.lean b/Mathlib/Util/WhatsNew.lean index bf3515832cd40..756af28e0f05a 100644 --- a/Mathlib/Util/WhatsNew.lean +++ b/Mathlib/Util/WhatsNew.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ import Mathlib.Init -import Lean /-! Defines a command wrapper that prints the changes the command makes to the diff --git a/Mathlib/Util/WithWeakNamespace.lean b/Mathlib/Util/WithWeakNamespace.lean index 04fcad50d7093..04e3e2f836205 100644 --- a/Mathlib/Util/WithWeakNamespace.lean +++ b/Mathlib/Util/WithWeakNamespace.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Daniel Selsam, Gabriel Ebner -/ import Mathlib.Init -import Lean /-! # Defines `with_weak_namespace` command. diff --git a/Shake/Main.lean b/Shake/Main.lean index e5b7645a31d81..20a8f24e116f0 100644 --- a/Shake/Main.lean +++ b/Shake/Main.lean @@ -35,6 +35,9 @@ Arguments: provided module(s) will be checked. Options: + --force + Skips the `lake build --no-build` sanity check + --fix Apply the suggested fixes directly. Make sure you have a clean checkout before running this, so you can review the changes. @@ -380,6 +383,8 @@ def toBitset (s : State) (ns : List Name) : Bitset := structure Args where /-- `--help`: shows the help -/ help : Bool := false + /-- `--force`: skips the `lake build --no-build` sanity check -/ + force : Bool := false /-- `--no-downstream`: disables downstream mode -/ downstream : Bool := true /-- `--gh-style`: output messages that can be parsed by `gh-problem-matcher-wrap` -/ @@ -422,6 +427,7 @@ def main (args : List String) : IO UInt32 := do let rec parseArgs (args : Args) : List String → Args | [] => args | "--help" :: rest => parseArgs { args with help := true } rest + | "--force" :: rest => parseArgs { args with force := true } rest | "--no-downstream" :: rest => parseArgs { args with downstream := false } rest | "--fix" :: rest => parseArgs { args with fix := true } rest | "--explain" :: rest => parseArgs { args with explain := true } rest @@ -438,9 +444,10 @@ def main (args : List String) : IO UInt32 := do IO.println help IO.Process.exit 0 - if (← IO.Process.output { cmd := "lake", args := #["build", "--no-build"] }).exitCode != 0 then - IO.println "There are out of date oleans. Run `lake build` or `lake exe cache get` first" - IO.Process.exit 1 + if !args.force then + if (← IO.Process.output { cmd := "lake", args := #["build", "--no-build"] }).exitCode != 0 then + IO.println "There are out of date oleans. Run `lake build` or `lake exe cache get` first" + IO.Process.exit 1 -- Parse the `--cfg` argument let srcSearchPath ← initSrcSearchPath diff --git a/bors.toml b/bors.toml index 6f0bc95fdaa7a..a94f6e08beeac 100644 --- a/bors.toml +++ b/bors.toml @@ -1,7 +1,7 @@ status = ["Build", "Lint style"] use_squash_merge = true timeout_sec = 28800 -block_labels = ["not-ready-to-merge", "WIP", "blocked-by-other-PR", "merge-conflict", "awaiting-CI"] +block_labels = ["WIP", "blocked-by-other-PR", "merge-conflict", "awaiting-CI"] delete_merged_branches = true update_base_for_deletes = true cut_body_after = "---" diff --git a/docs/overview.yaml b/docs/overview.yaml index d020bc5328e44..7113041d2dfc9 100644 --- a/docs/overview.yaml +++ b/docs/overview.yaml @@ -468,7 +468,7 @@ Data structures: Maps: key-value map: 'AList' red-black map: 'Batteries.RBMap' - hash map: 'Batteries.HashMap' + hash map: 'Std.HashMap' finitely supported function: 'Finsupp' finite map: 'Finmap' diff --git a/docs/references.bib b/docs/references.bib index 2f63bf3e561a3..f358fdab188cc 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -21,6 +21,17 @@ @Book{ abramsky_gabbay_maibaum_1994 zbl = {0829.68111} } +@Book{ Adamek_Rosicky_Vitale_2010, + place = {Cambridge}, + series = {Cambridge Tracts in Mathematics}, + title = {Algebraic Theories: A Categorical Introduction to General + Algebra}, + publisher = {Cambridge University Press}, + author = {Adámek, J. and Rosický, J. and Vitale, E. M.}, + year = {2010}, + collection = {Cambridge Tracts in Mathematics} +} + @InProceedings{ adhesive2004, author = {S. Lack and P. Soboci{\'n}ski}, title = {Adhesive categories}, @@ -1027,6 +1038,20 @@ @Book{ davey_priestley url = {https://doi.org/10.1017/CBO9780511809088} } +@Article{ day1972, + author = {Day, Brian}, + title = {A reflection theorem for closed categories}, + journal = {J. Pure Appl. Algebra}, + fjournal = {Journal of Pure and Applied Algebra}, + volume = {2}, + year = {1972}, + number = {1}, + pages = {1--11}, + issn = {0022-4049}, + doi = {10.1016/0022-4049(72)90021-7}, + url = {https://doi.org/10.1016/0022-4049(72)90021-7} +} + @InProceedings{ deligne_formulaire, author = {Deligne, P.}, title = {Courbes elliptiques: formulaire d'apr\`es {J}. {T}ate}, @@ -1901,6 +1926,14 @@ @Misc{ howard author = {Howard, Peter} } +@Book{ hua1982house, + author = {Hua, Loo-Keng}, + publisher = {Springer}, + title = {Introduction to Number Theory}, + year = {1982}, + pages = {489} +} + @Book{ HubbardWest-ode, author = {John H. Hubbard and Beverly H. West}, title = {Differential Equations: A Dynamical Systems Approach}, @@ -2088,6 +2121,14 @@ @Article{ Joyce1982 publisher = {Elsevier {BV}} } +@Book{ juskevic2022, + author = {Ju{\v{s}}kevi{\v{c}}, Adolf P and Winter, Eduard}, + title = {Leonhard Euler und Christian Goldbach: Briefwechsel + 1729--1764}, + year = {2022}, + publisher = {Walter de Gruyter GmbH \& Co KG} +} + @Article{ KahnMaltsiniotis2008, author = {Kahn, Bruno and Maltsiniotis, Georges}, title = {Structures de d\'{e}rivabilit\'{e}}, @@ -2223,14 +2264,6 @@ @Article{ kelleyVaught1953 doi = {10.2307/1990847} } -@Book{ keng1982house, - author = {Keng, Hua Loo}, - publisher = {Springer}, - title = {Introduction to Number Theory}, - year = {1982}, - pages = {489} -} - @Article{ kleiman1979, author = {Kleiman, Steven Lawrence}, title = {Misconceptions about {$K_X$}}, @@ -3268,6 +3301,16 @@ @Book{ verdier1996 mrnumber = {1453167} } +@Misc{ vistoli2004, + author = {Vistoli, Angelo}, + title = {Notes on {Grothendieck} topologies, fibered categories and + descent theory}, + year = {2004}, + howpublished = {Preprint, {arXiv}:math/0412512 [math.{AG}] (2004)}, + url = {https://arxiv.org/abs/math/0412512}, + arxiv = {arXiv:math/0412512} +} + @Book{ wall2018analytic, title = {Analytic Theory of Continued Fractions}, author = {Wall, H.S.}, diff --git a/lake-manifest.json b/lake-manifest.json index f6775f3aa1e59..46776e768a762 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,17 +5,17 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "daf1ed91789811cf6bbb7bf2f4dad6b3bad8fbf4", + "rev": "500a529408399c44d7e1649577e3c98697f95aa4", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", "inherited": false, - "configFile": "lakefile.lean"}, + "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "2b2f6d7fbe9d917fc010e9054c1ce11774c9088b", + "rev": "1357f4f49450abb9dfd4783e38219f4ce84f9785", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -25,7 +25,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "b20a88676fd00affb90cbc9f1ff004ae588103b3", + "rev": "9ac12945862fa39eab7795c2f79bb9aa0c8e332c", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -35,16 +35,16 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "eb08eee94098fe530ccd6d8751a86fe405473d4c", + "rev": "baa65c6339a56bd22b7292aa4511c54b3cc7a6af", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.42", + "inputRev": "v0.0.43", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", "type": "git", "subDir": null, - "scope": "", + "scope": "leanprover", "rev": "2cf1030dc2ae6b3632c84a09350b675ef3e347d0", "name": "Cli", "manifestFile": "lake-manifest.json", @@ -55,7 +55,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "63a7d4a353f48f6c5f1bc19d0f018b0513cb370a", + "rev": "c1970bea80ac3357a6a991a6d00d12e7435c12c7", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "4b61d4abc1659f15ffda5ec24fdebc229d51d066", + "rev": "7bedaed1ef024add1e171cc17706b012a9a37802", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/lakefile.lean b/lakefile.lean index 212047a97ac35..bc09c6e252447 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -10,7 +10,7 @@ open Lake DSL require "leanprover-community" / "batteries" @ git "main" require "leanprover-community" / "Qq" @ git "master" require "leanprover-community" / "aesop" @ git "master" -require "leanprover-community" / "proofwidgets" @ git "v0.0.42" +require "leanprover-community" / "proofwidgets" @ git "v0.0.43" require "leanprover-community" / "importGraph" @ git "main" require "leanprover-community" / "LeanSearchClient" @ git "main" from git "https://github.com/leanprover-community/LeanSearchClient" @ "main" @@ -31,12 +31,13 @@ abbrev mathlibOnlyLinters : Array LeanOption := #[ ⟨`linter.refine, true⟩, ⟨`linter.style.cdot, true⟩, ⟨`linter.style.dollarSyntax, true⟩, + ⟨`linter.style.header, true⟩, ⟨`linter.style.lambdaSyntax, true⟩, ⟨`linter.style.longLine, true⟩, ⟨`linter.style.longFile, .ofNat 1500⟩, ⟨`linter.style.missingEnd, true⟩, - ⟨`linter.style.setOption, true⟩, - ⟨`aesop.warn.applyIff, false⟩ -- This became a problem after https://github.com/leanprover-community/aesop/commit/29cf094e84ae9852f0011b47b6ddc684ffe4be5f + ⟨`linter.style.multiGoal, true⟩, + ⟨`linter.style.setOption, true⟩ ] /-- These options are passed as `leanOptions` to building mathlib, as well as the @@ -51,6 +52,8 @@ package mathlib where leanOptions := mathlibLeanOptions -- Mathlib also enforces these linter options, which are not active by default. moreServerOptions := mathlibOnlyLinters + -- Use Batteries' test driver for `lake test` + testDriver := "batteries/test" -- These are additional settings which do not affect the lake hash, -- so they can be enabled in CI and disabled locally or vice versa. -- Warning: Do not put any options here that actually change the olean files, @@ -132,16 +135,20 @@ lean_exe pole where weakLinkArgs := #["-lLake"] /-- -`lake exe test` is a thin wrapper around `lake exe batteries/test`, until -https://github.com/leanprover/lean4/issues/4121 is resolved. +`lake exe unused module_1 ... module_n` will analyze unused transitive imports in a given sequence. +The script expects the sequence to be in "reverse order", i.e. files imported later in `Mathlib` should +come earlier in the sequence. -You can also use it as e.g. `lake exe test conv eval_elab` to only run the named tests. +Outputs a markdown file (called `unused.md` by default) and a number of `lake exe graph` commands +highlighting particular ranges of transitively unused imports. + +Typically this should be run via `scripts/unused_in_pole.sh`. -/ -@[test_driver] -lean_exe test where - -- We could add the above `leanOptions` and `moreServerOptions`: currently, these do not take - -- effect as `test` is a `lean_exe`. With a `lean_lib`, it would work... - srcDir := "scripts" +lean_exe unused where + root := `LongestPole.Unused + supportInterpreter := true + -- Executables which import `Lake` must set `-lLake`. + weakLinkArgs := #["-lLake"] /-! ## Other configuration diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000000000..33a295aa934b5 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,95 @@ +# Miscellaneous scripts for working on mathlib + +This directory contains miscellaneous scripts that are useful for working on or with mathlib. +When adding a new script, please make sure to document it here, so other readers have a chance +to learn about it as well! + + +## Current scripts and their purpose + +**Installation scripts** +- `install_debian.sh`, `install_macos.sh` + Installation scripts referenced from the leanprover community install pages. + https://leanprover-community.github.io/install/debian.html + https://leanprover-community.github.io/install/macos.html + If these web pages are deprecated or removed, we should remove these scripts. + +**Tool for manual maintenance** +- `fix_unused.py` + Bulk processing of unused variable warnings, replacing them with `_`. + +**Analyzing Mathlib's import structure** +- `unused_in_pole.sh` (followed by an optional ``, defaulting to `Mathlib`) + calls `lake exe pole --loc --to ` to compute the longest + pole to a given target module, and then feeds this into + `lake exe unused` to analyze transitively unused imports. + Generates `unused.md` containing a markdown table showing the unused imports, + and suggests `lake exe graph` commands to visualize the largest "rectangles" of unused imports. + +**CI workflow** +- `mk_all.lean` + run via `lake exe mk_all`, regenerates the import-only files + `Mathlib.lean`, `Mathlib/Tactic.lean`, `Archive.lean` and `Counterexamples.lean` +- `lint-style.lean`, `lint-style.py`, `print-style-errors.sh` + style linters, written in Python and Lean. Run via `lake exe lint-style`. + Medium-term, the latter two scripts should be rewritten and incorporated in `lint-style.lean`. +- `lint-bib.sh` + normalize the BibTeX file `docs/references.bib` using `bibtool`. +- `yaml_check.py`, `check-yaml.lean` + Sanity checks for `undergrad.yaml`, `overview.yaml`, and `100.yaml`. +- `lean-pr-testing-comments.sh` + Generate comments and labels on a Lean or Batteries PR after CI has finished on a + `*-pr-testing-NNNN` branch. +- `update_nolints_CI.sh` + Update the `nolints.json` file to remove unneeded entries. Automatically run once a week. +- `bench_summary.lean` + Convert data retrieved from the speed center into a shorter, more accessible format, + and post a comment with this summary on github. +- `declarations_diff.sh` + Attempts to find which declarations have been removed and which have been added in the current PR + with respect to `master`, and posts a comment on github with the result. +- `autolabel.lean` is the Lean script in charge of automatically adding a `t-`label on eligible PRs. + Autolabelling is inferred by which directories the current PR modifies. + +**Managing nightly-testing and bump branches** +- `create-adaptation-pr.sh` implements some of the steps in the workflow described at + https://leanprover-community.github.io/contribute/tags_and_branches.html#mathlib-nightly-and-bump-branches + Specifically, it will: + - merge `master` into `bump/v4.x.y` + - create a new branch from `bump/v4.x.y`, called `bump/nightly-YYYY-MM-DD` + - merge `nightly-testing` into the new branch + - open a PR to merge the new branch back into `bump/v4.x.y` + - announce the PR on zulip + - 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. + +**Managing and tracking technical debt** +- `technical-debt-metrics.sh` + Prints information on certain kind of technical debt in Mathlib. + This output is automatically posted to zulip once a week. +- `init_creation.sh` + makes sure that every file in Mathlib transitively imports `Mathlib.init` + This may be removed soon, and replaced by a different mechanism. + +**Mathlib tactics** +- `polyrith_sage.py`, `polyrith_sage_helper.py` are required for `polyrith` + to communication with the Sage server. + +**Data files with linter exceptions** +- `nolints.json` contains exceptions for all `env_linter`s in mathlib. + For permanent and deliberate exceptions, add a `@[nolint lintername]` in the .lean file instead. +- `no_lints_prime_decls.txt` + contains temporary exceptions for the `docPrime` linter + +Both of these files should tend to zero over time; +please do not add new entries to these files. PRs removing (the need for) entries are welcome. + +**API surrounding CI** +- `update_PR_comment.sh` is a script that edits an existing message (or creates a new one). + It is used by the `PR_summary` workflow to maintain an up-to-date report with a searchable history. +- `get_tlabel.sh` extracts the `t-`label that a PR has (assuming that there is exactly one). + It is used by the `maintainer_merge` family of workflows to dispatch `maintainer merge` requests + to the appropriate topic on zulip. +- `count-trans-deps.py`, `import-graph-report.py` and `import_trans_difference.sh` produce various + summaries of changes in transitive imports that the `PR_summary` message incorporates. diff --git a/scripts/autolabel.lean b/scripts/autolabel.lean index 922e98d1fee24..76e42ae90b1fc 100644 --- a/scripts/autolabel.lean +++ b/scripts/autolabel.lean @@ -24,7 +24,7 @@ needs to be updated here if necessary: ## lake exe autolabel `lake exe autolabel` uses `git diff --name-only origin/master...HEAD` to determine which -files have been modifed and then finds all labels which should be added based on these changes. +files have been modified and then finds all labels which should be added based on these changes. These are printed for testing purposes. `lake exe autolabel [NUMBER]` will further try to add the applicable labels diff --git a/scripts/bench/temci-config.run.yml b/scripts/bench/temci-config.run.yml index dd8af5f9c062a..679eb6a0e6d8f 100644 --- a/scripts/bench/temci-config.run.yml +++ b/scripts/bench/temci-config.run.yml @@ -6,7 +6,8 @@ properties: ['wall-clock', 'task-clock', 'instructions:u', 'branches', 'branch-misses'] rusage_properties: ['maxrss'] cmd: | - bash -c 'set -eo pipefail; lake clean && LEAN_PATH=$(lean --print-libdir) lake build -v --lean ./scripts/bench/fake-root/bin/lean | ./scripts/bench/accumulate_profile.py | grep -v took' + # 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' parse_output: true runs: 1 - attributes: diff --git a/scripts/bench_summary.lean b/scripts/bench_summary.lean new file mode 100644 index 0000000000000..909dc9826ac4b --- /dev/null +++ b/scripts/bench_summary.lean @@ -0,0 +1,221 @@ +/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa +-/ + +import Lean.Elab.Command + +/-! +# Summary of `!bench` results + +This file contains a script that converts data retrieved from the speed-center into a +shorter, more accessible format, and post a comment with this summary on github. +-/ + +namespace BenchAction + +open Lean + +/-- `Bench` is a structure with the data used to compute the `!bench` summary. +It contains +* a string `file` (that could be `build`, `lint` or `~Mathlib.Path.To.File`); +* an integer `diff` representing the change in number of instructions for `file`; +* a float `reldiff` representing the percentage change in number of instructions for `file`. +-/ +structure Bench := + file : String + diff : Int + reldiff : Float + deriving FromJson, ToJson, Inhabited + +/-- `intDecs z exp prec` is a "generic" formatting of an integer `z`. +It writes `z` in the form `x.y * 10 ^ exp` (for non-negative integers `x`, `y` and `z`), +such that `y` has `prec` digits and returns +* the sign of `z` as a string (in fact, just either `+` or `-`); +* the integer `x`; +* the natural number `y` (that has `prec` digits). +-/ +def intDecs (z : Int) (exp : Nat := 9) (prec : Nat := 3) : String × Int × Nat := + let sgn := z.sign + let z := sgn * z + let p10 : Int := 10 ^ (exp - prec) + let idec := z / p10 + (if sgn < 0 then "-" else "+", idec / (10 ^ prec), (idec % 10 ^ prec).toNat) + +/-- `formatDiff z` uses `intDecs` to format an integer `z` as `±x.y⬝10⁹`. -/ +def formatDiff (z : Int) : String := + let (sgn, intDigs, decDigs) := intDecs z + s!"{sgn}{intDigs}.{decDigs}⬝10⁹" + +/-- Convert a `Float` into a formatted string of the form `±z.w%`. -/ +def formatPercent (reldiff : Float) : String := + -- shift by `2` twice: once to get a percentage, again for two decimal digits of precision + let reldiff := reldiff * 10 ^ 4 + let sgn : Int := if reldiff < 0 then -1 else 1 + let reldiff := (.ofInt sgn) * reldiff + let (sgn, intDigs, decDigs) := intDecs (sgn * reldiff.toUInt32.val) 0 2 + s!"({sgn}{intDigs}.{decDigs}%)" + +/-- +info: [(+0.0%), (+14.28%), (+0.20%), (-0.60%)] +--- +info: [+0.0⬝10⁹, +1.0⬝10⁹, +30.200⬝10⁹, -0.460⬝10⁹] +-/ +#guard_msgs in +run_cmd + let floats : Array Float := #[0, 1/7, 0.002, -0.006] + logInfo m!"{floats.map formatPercent}" + let ints : Array Int := #[0, 10^9, 302*10^8, -460000000] + logInfo m!"{ints.map formatDiff}" + +/-- +`formatFile file` converts a `String` into a formatted string of the form `` `file` ``, +removing leading non-letters. It is expected that `~` is the only leading non-letter. +-/ +def formatFile (file : String) : String := s!"`{file.dropWhile (!·.isAlpha)}`" + +/-- +`summary bc` converts a `Bench` into a formatted string of the form +``| `file` | ±x.y⬝10⁹ | ±z.w% |`` (technically, without the spaces). +-/ +def summary (bc : Bench) : String := + let middle := [formatFile bc.file, formatDiff bc.diff, formatPercent bc.reldiff] + "|".intercalate (""::middle ++ [""]) + +/-- +`toTable bcs` formats an array of `Bench`es into a markdown table whose columns are +the file name, the absolute change in instruction counts and the relative change as a percentage. +A typical entry may look like ``|`Mathlib.Analysis.Seminorm`|+2.509⬝10⁹|(+1.41%)|``. +-/ +def toTable (bcs : Array Bench) : String := + let header := "|File|Instructions|%|\n|-|-:|:-:|" + "\n".intercalate (header :: (bcs.map summary).toList) + +/-- +`toCollapsibleTable bcs roundDiff` is similar to `toTable bcs`, except that it returns +output enclosed in a `
` html-block. +The `` part tallies the number of entries in `bcs` whose instructions increased +resp. decreased by at least the amount `roundDiff`. +-/ +def toCollapsibleTable (bcs : Array Bench) (roundDiff : Int) : String := + s!"
{bcs.size} files, Instructions {formatDiff <| roundDiff * 10 ^ 9}\ + \n\n{toTable (bcs.qsort (·.diff > ·.diff))}\n
\n" + +/-- Assuming that the input is a `json`-string formatted to produce an array of `Bench`, +`benchOutput` returns the "significant" changes in numbers of instructions as a string. -/ +def benchOutput (jsonInput : String) : IO String := do + let data ← IO.ofExcept (Json.parse jsonInput >>= fromJson? (α := Array Bench)) + -- `head` contains the changes for `build` and `lint`, + -- `data` contains the instruction changes for individual files: + -- each filename is prefixed by `~`. + let (head, data) := data.partition (·.file.take 1 != "~") + -- Partition the `Bench`es into "bins", i.e. the subsets of all `Bench`es whose difference + -- in instructions lies in an interval `[n·10⁹, (n+1)·10⁹)`. + -- The values `n` need not be consecutive: we only retain non-empty bins. + let grouped := ((data.groupByKey (·.diff / (10 ^ 9))).toArray.qsort (·.1 > ·.1)).toList + -- We consider `build` and `lint` as their own groups, in this order. + let sortHead := (head.qsort (·.file < ·.file)).toList.map (0, #[·]) + let togetherSorted := sortHead ++ grouped + -- For better formatting, we merge consecutive bins with just a single *file* into one. + -- This covers the two steps `ts1` and `ts2`. + -- For example, `[..., (bound₁, #[a₁]), (bound₂, #[a₂]), (bound₃, #[a₃]), ...]` gets collapsed to + -- `[..., (none, #[a₁, a₂, a₃]), ...]`. + -- The `boundᵢ` entry becomes `none` for the collapsed entries, so that we know that these + -- should be printed individually instead of inside a `
`-block. + -- A single bin with just a single file is also marked with `none`, for the same reason. + let ts1 := togetherSorted.groupBy (·.2.size == 1 && ·.2.size == 1) + let ts2 := List.join <| ts1.map fun l ↦ + if (l.getD 0 default).2.size == 1 then + [(none, l.foldl (· ++ ·.2) #[])] + else + l.map fun (n, ar) ↦ (some n, ar) + + let mut overall := [] + for (bound, gs) in ts2 do + overall := overall ++ [ + match bound with + -- These entries are from "singleton" files in their range; we print them individually. + | none => toTable gs + -- These get a collapsible summary instead. + | some roundedDiff => toCollapsibleTable gs roundedDiff] + return "\n".intercalate overall + +open Lean Elab Command in +/-- `addBenchSummaryComment PR repo tempFile` adds a summary of benchmarking results +as a comment to a pull request. It takes as input +* the number `PR` and the name `repo` as a `String` containing the relevant pull-request + (it reads and posts comments there) +* the `String` `tempFile` of a temporary file where the command stores transient information. + +The code itself interfaces with the shell to retrieve and process json data and eventually +uses `benchOutput`. +Here is a summary of the steps: +* retrieve the last comment to the PR (using `gh pr view ...`), +* check if it was posted by `leanprover-bot`, +* try to retrieve the source and target commits from the url that the bot posts + and store them in `source` and `target`, +* query the speed center for the benchmarking data (using `curl url`), +* format and filter the returned JSON data (various times), + saving intermediate steps into `tempFile` (using `jq` multiple times), +* process the final string to produce a summary (using `benchOutput`), +* finally post the resulting output to the PR (using `gh pr comment ...`). +-/ +def addBenchSummaryComment (PR : Nat) (repo : String) (tempFile : String := "benchOutput.json") : + CommandElabM Unit := do + let PR := s!"{PR}" + let jq := ".comments | last | select(.author.login==\"leanprover-bot\") | .body" + let gh_pr_comments : IO.Process.SpawnArgs := + { cmd := "gh", args := #["pr", "view", PR, "--repo", repo, "--json", "comments", "--jq", jq] } + -- This is the content of the last comment made by `leanprover-bot` to the PR `PR`. + let output ← IO.Process.run gh_pr_comments + -- URLs of benchmarking results have the form {something}/compare/source_sha/to/target_sha, + -- where source_sha and target_sha are the commit hashes of the revisions being benchmarked. + -- The comment contains such a URL (and only one); parse the revisions from the comment. + let frags := output.split (· == '/') + let some compIdx := frags.findIdx? (· == "compare") | + logInfo "No 'compare' found in URL." + return + let source := frags.getD (compIdx + 1) "" + let target := (frags.getD (compIdx + 3) "").takeWhile (· != ')') + if (source.length, target.length) != (36, 36) then + logInfo m!"Found\nsource: '{source}'\ntarget: '{target}'\ninstead of two commit hashes." + return + dbg_trace s!"Using commits\nsource: '{source}'\ntarget: '{target}'\n" + let curlSpeedCenter : IO.Process.SpawnArgs := + { cmd := "curl" + args := #[s!"http://speed.lean-fro.org/mathlib4/api/compare/{source}/to/{target}?all_values=true"] } + let bench ← IO.Process.run curlSpeedCenter + IO.FS.writeFile (tempFile ++ ".src") bench + -- Extract all instruction changes whose magnitude is larger than `threshold`. + let threshold := s!"{10 ^ 9}" + let jq1 : IO.Process.SpawnArgs := + { cmd := "jq" + args := #["-r", "--arg", "thr", threshold, + ".differences | .[] | ($thr|tonumber) as $th | + select(.dimension.metric == \"instructions\" and ((.diff >= $th) or (.diff <= -$th)))", + (tempFile ++ ".src")] } + let firstFilter ← IO.Process.run jq1 + -- we leave `tempFile.src` unchanged and we switch to updating `tempfile`: this is useful for + -- debugging, as it preserves the original data downloaded from the speed-center + IO.FS.writeFile tempFile firstFilter + -- Write these in compact form, in the format suitable for `benchOutput`. + let jq2 : IO.Process.SpawnArgs := + { cmd := "jq" + args := #["-c", "[{file: .dimension.benchmark, diff: .diff, reldiff: .reldiff}]", tempFile] } + let secondFilter ← IO.Process.run jq2 + IO.FS.writeFile tempFile secondFilter + let jq3 : IO.Process.SpawnArgs := + { cmd := "jq", args := #["-n", "reduce inputs as $in (null; . + $in)", tempFile] } + let thirdFilter ← IO.Process.run jq3 + let report ← benchOutput thirdFilter + IO.println report + -- Post the computed summary as a github comment. + let add_comment : IO.Process.SpawnArgs := + { cmd := "gh", args := #["pr", "comment", PR, "--repo", repo, "--body", report] } + let _ ← IO.Process.run add_comment + +end BenchAction + +-- CI adds the following line, replacing `putPR` with the PR number: +--run_cmd BenchAction.addBenchSummaryComment putPR "leanprover-community/mathlib4" diff --git a/scripts/check-yaml.lean b/scripts/check-yaml.lean index 44aca0b63758a..89147aeed4c13 100644 --- a/scripts/check-yaml.lean +++ b/scripts/check-yaml.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ +import Lean.Util.SearchPath import Mathlib.Lean.CoreM import Mathlib.Tactic.ToExpr diff --git a/scripts/create-adaptation-pr.sh b/scripts/create-adaptation-pr.sh index 984012e61a1ad..c23bdea7335f4 100755 --- a/scripts/create-adaptation-pr.sh +++ b/scripts/create-adaptation-pr.sh @@ -18,7 +18,7 @@ IFS=$'\n\t' { # Default values -AUTO="no" +AUTO="yes" # Function to display usage usage() { @@ -28,7 +28,7 @@ usage() { echo "BUMPVERSION: The upcoming release that we are targeting, e.g., 'v4.10.0'" echo "NIGHTLYDATE: The date of the nightly toolchain currently used on 'nightly-testing'" echo "NIGHTLYSHA: The SHA of the nightly toolchain that we want to adapt to" - echo "AUTO: Optional flag to specify automatic mode, default is 'no'" + echo "AUTO: Optional flag to specify automatic mode, default is 'yes'" exit 1 } @@ -75,24 +75,6 @@ if ! command -v gh &> /dev/null; then exit 1 fi -# Check the CI status of the latest commit on the 'nightly-testing' branch -status=$(gh run list --branch nightly-testing | grep -m1 . | awk '{print $1}') -if [ "$status" != "completed" ]; then - if [ "$status" != "in_progress" ]; then - echo "The latest commit on the 'nightly-testing' branch did not pass CI. Please fix the issues and try again." - gh run list --branch nightly-testing - exit 1 - else - if [ "$AUTO" = "yes" ]; then - echo "Auto mode enabled. Bailing out because the latest commit on 'nightly-testing' is still running CI." - exit 1 - else - echo "The latest commit on 'nightly-testing' is still running CI." - read -p "Press enter to continue, or ctrl-C if you'd prefer to wait for CI." - fi - fi -fi - echo "### Creating a PR for the nightly adaptation for $NIGHTLYDATE" echo @@ -111,7 +93,7 @@ echo "### [auto] checkout 'bump/$BUMPVERSION' and merge the latest changes from git checkout "bump/$BUMPVERSION" git pull -git merge origin/master || true # ignore error if there are conflicts +git merge --no-edit origin/master || true # ignore error if there are conflicts # Check if there are merge conflicts if git diff --name-only --diff-filter=U | grep -q .; then @@ -156,7 +138,7 @@ echo echo "### [auto] create a new branch 'bump/nightly-$NIGHTLYDATE' and merge the latest changes from 'origin/nightly-testing'" git checkout -b "bump/nightly-$NIGHTLYDATE" -git merge $NIGHTLYSHA || true # ignore error if there are conflicts +git merge --no-edit $NIGHTLYSHA || true # ignore error if there are conflicts # Check if there are merge conflicts if git diff --name-only --diff-filter=U | grep -q .; then @@ -225,7 +207,7 @@ if git diff --name-only bump/$BUMPVERSION bump/nightly-$NIGHTLYDATE | grep -q .; echo "### [auto/user] post a link to the PR on Zulip" zulip_title="#$pr_number adaptations for nightly-$NIGHTLYDATE" - zulip_body="> $pr_title #$pr_number" + zulip_body="> $pr_title #$pr_number\\\n\\\nPlease review this PR. At the end of the month this diff will land in \\\`master\\\`." echo "Post the link to the PR in a new thread on the #nightly-testing channel on Zulip" echo "Here is a suggested message:" @@ -273,7 +255,7 @@ echo "### [auto] checkout the 'nightly-testing' branch and merge the new branch git checkout nightly-testing git pull -git merge "bump/nightly-$NIGHTLYDATE" || true # ignore error if there are conflicts +git merge --no-edit "bump/nightly-$NIGHTLYDATE" || true # ignore error if there are conflicts # Check if there are merge conflicts if git diff --name-only --diff-filter=U | grep -q .; then @@ -295,7 +277,7 @@ if git diff --name-only --diff-filter=U | grep -q . || ! git diff-index --quiet if [ "$AUTO" = "yes" ]; then echo "Auto mode enabled. Bailing out due to unresolved conflicts or uncommitted changes." echo "PR has been created, and message posted to Zulip." - echo "Error occured while merging the new branch into 'nightly-testing'." + echo "Error occurred while merging the new branch into 'nightly-testing'." exit 2 fi fi diff --git a/scripts/fix_unused.py b/scripts/fix_unused.py new file mode 100755 index 0000000000000..9475d07bf9a89 --- /dev/null +++ b/scripts/fix_unused.py @@ -0,0 +1,83 @@ +#! /usr/bin/env python3 + +# https://chatgpt.com/share/66f4e420-66bc-8001-8349-ce3cfb4f23c3 +# Usage: lake build | scripts/fix_unused.py + +# Bulk processing of unused variable warnings, replacing them with `_`. + +import re +import sys + +# Parse warning messages and extract file paths, line, column, and variable names +def parse_warnings(warning_lines): + pattern = r"warning: (\S+):(\d+):(\d+): unused variable `([^`]+)`" + warnings = [] + + for line in warning_lines: + match = re.match(pattern, line) + if match: + file_path, line_num, col_num, var_name = match.groups() + warnings.append({ + 'file_path': file_path, + 'line_num': int(line_num), + 'col_num': int(col_num), + 'var_name': var_name + }) + + return warnings + +# Find the actual column index, adjusting for multi-byte Unicode characters +def find_column_index(line, target_col): + """Return the index in the string where the column equals target_col, ignoring visual width.""" + current_col = 0 + for idx, char in enumerate(line): + # Move one "logical column" per character (whether wide or narrow) + if current_col >= target_col: + return idx + current_col += 1 + return len(line) # Return the end if column number exceeds the line length + +# Replace variable with `_` at the specified line and column in the file +def process_file(file_path, edits): + with open(file_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + + for edit in sorted(edits, key=lambda e: e['line_num'], reverse=True): + line_num = edit['line_num'] - 1 + col_num = edit['col_num'] - 1 + var_name = edit['var_name'] + line = lines[line_num] + + # Find the actual starting column index for the variable + actual_col = find_column_index(line, col_num) + + # Replace the variable with `_` + new_line = line[:actual_col] + line[actual_col:].replace(var_name, '_', 1) + lines[line_num] = new_line + + with open(file_path, 'w', encoding='utf-8') as f: + f.writelines(lines) + +# Process all warnings +def process_warnings(warnings): + file_edits = {} + + # Organize warnings by file + for warning in warnings: + file_path = warning['file_path'] + if file_path not in file_edits: + file_edits[file_path] = [] + file_edits[file_path].append(warning) + + # Process each file in reverse order of warnings + for file_path, edits in file_edits.items(): + print(f"Processing {file_path} with {len(edits)} edits.") + process_file(file_path, edits) + +if __name__ == "__main__": + # Read warning lines from stdin + warning_lines = sys.stdin.read().splitlines() + + # Parse and process warnings + warnings = parse_warnings(warning_lines) + process_warnings(warnings) diff --git a/scripts/init_creation.sh b/scripts/init_creation.sh index ea0358afeddc8..6dc6b3ec97ae2 100644 --- a/scripts/init_creation.sh +++ b/scripts/init_creation.sh @@ -7,8 +7,8 @@ IFS=$'\n\t' : <<'BASH_MODULE_DOC' -These are the commands to generate a "root" `Mathlib/Init.lean` file, imported by all the -`Mathlib` files that do not import any `Mathlib` file. +These are the commands to add an import of `Mathlib/Init.lean` to all `Mathlib` files +that do not import any `Mathlib` file. BASH_MODULE_DOC @@ -40,11 +40,3 @@ printf 'Adding `import Mathlib.Init` to all file that import no Mathlib file.\n' # The `sed` command appends the line `import Mathlib.Init` after the first # `-/[linebreaks]*` of each file printed by `mathlibNonImportingFiles`. sed -i -z 's=-/\n*=&import Mathlib.Init\n=' $(mathlibNonImportingFiles) - -printf 'Creating `Mathlib/Init.lean`.\n' - -# Creates the `Mathlib/Init.lean` files. -echo '-- This is the root file in Mathlib: it is imported by virtually *all* Mathlib files' > Mathlib/Init.lean - -printf $'Don\'t forget to add `Mathlib.Init` to the `ignoreImport` field of `scripts/noshake.json` -This ensures that `import Mathlib.Init` does not trigger a `shake` exception.\n' diff --git a/scripts/install_macos.sh b/scripts/install_macos.sh index f45895008d4a0..eb3e0863ce886 100755 --- a/scripts/install_macos.sh +++ b/scripts/install_macos.sh @@ -14,17 +14,22 @@ curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf elan toolchain install stable elan default stable -# Install the universal darwin build of VS Code -curl -L https://update.code.visualstudio.com/latest/darwin-universal/stable -o ~/Downloads/VSCode-darwin-universal.zip +# Check if VS Code is available on the command line +if ! command -v code &> /dev/null; then + # Install the universal darwin build of VS Code + curl -L https://update.code.visualstudio.com/latest/darwin-universal/stable -o ~/Downloads/VSCode-darwin-universal.zip -# Unzip the downloaded file to the Applications folder -unzip -o ~/Downloads/VSCode-darwin-universal.zip -d /Applications + # Unzip the downloaded file to the Applications folder + unzip -o ~/Downloads/VSCode-darwin-universal.zip -d /Applications -# Add the VS Code binary to the PATH to enable launching from the terminal -cat << EOF >> ~/.zprofile + # Add the VS Code binary to the PATH to enable launching from the terminal + cat >> ~/.zprofile << EOF # Add Visual Studio Code (code) export PATH="\$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin" EOF +else + echo "VS Code is already installed." +fi # Install the Lean4 VS Code extension code --install-extension leanprover.lean4 diff --git a/scripts/lint-style.lean b/scripts/lint-style.lean index a7eb1c953caa1..953800e9826f3 100644 --- a/scripts/lint-style.lean +++ b/scripts/lint-style.lean @@ -12,10 +12,34 @@ import Cli.Basic This files defines the `lint-style` executable which runs all text-based style linters. The linters themselves are defined in `Mathlib.Tactic.Linter.TextBased`. + +In addition, this checks that every file in `scripts` is documented in its top-level README. -/ open Cli Mathlib.Linter.TextBased +open System.FilePath + +/-- Verifies that every file in the `scripts` directory is documented in `scripts/README.md`. +Return `True` if there are undocumented scripts, otherwise `False`. -/ +def allScriptsDocumented : IO Bool := do + -- Retrieve all scripts (except for the `bench` directory). + let allScripts ← (walkDir "scripts" fun p ↦ pure (p.components.getD 1 "" != "bench")) + let allScripts := allScripts.erase ("scripts" / "bench")|>.erase ("scripts" / "README.md") + -- Check if the README text contains each file enclosed in backticks. + let readme : String ← IO.FS.readFile ("scripts" / "README.md") + -- These are data files for linter exceptions: don't complain about these *for now*. + let dataFiles := #["noshake.json", "nolints-style.txt"] + -- For now, there are no scripts in sub-directories that should be documented. + let fileNames := allScripts.map (·.fileName.get!) + let undocumented := fileNames.filter fun script ↦ + !readme.containsSubstr s!"`{script}`" && !dataFiles.contains script + if undocumented.size > 0 then + IO.println s!"error: found {undocumented.size} undocumented script(s): \ + please describe the script(s) in 'scripts/README.md'\n \ + {String.intercalate "," undocumented.toList}" + return undocumented.size == 0 + /-- Implementation of the `lint-style` command line program. -/ def lintStyleCli (args : Cli.Parsed) : IO UInt32 := do let style : ErrorFormat := match args.hasFlag "github" with @@ -26,15 +50,16 @@ def lintStyleCli (args : Cli.Parsed) : IO UInt32 := do let mut allModules := #[] for s in ["Archive.lean", "Counterexamples.lean", "Mathlib.lean"] do allModules := allModules.append ((← IO.FS.lines s).map (·.stripPrefix "import ")) - -- note: since we manually add "Batteries" to "Mathlib.lean", we remove it here manually + -- Note: since we manually add "Batteries" to "Mathlib.lean", we remove it here manually. allModules := allModules.erase "Batteries" - let numberErrorFiles ← lintModules allModules style fix + let mut numberErrors ← lintModules allModules style fix + if !(← allScriptsDocumented) then numberErrors := numberErrors + 1 -- If run with the `--fix` argument, return a zero exit code. -- Otherwise, make sure to return an exit code of at most 125, -- so this return value can be used further in shell scripts. if args.hasFlag "fix" then return 0 - else return min numberErrorFiles 125 + else return min numberErrors 125 /-- Setting up command line options and help text for `lake exe lint-style`. -/ -- so far, no help options or so: perhaps that is fine? diff --git a/scripts/mk_all.lean b/scripts/mk_all.lean index 309a4bf49d2c4..ff77e78553883 100644 --- a/scripts/mk_all.lean +++ b/scripts/mk_all.lean @@ -7,6 +7,8 @@ import Cli.Basic import Lake.CLI.Main import Mathlib.Util.GetAllModules +-- The `style.header` linter flags `import Lake.CLI.Main` as a potential performance issue. +set_option linter.style.header false /-! # Script to create a file importing all files from a folder @@ -24,7 +26,8 @@ it includes `Mathlib/Tactic`. -/ def getLeanLibs : IO (Array String) := do let (elanInstall?, leanInstall?, lakeInstall?) ← findInstall? let config ← MonadError.runEIO <| mkLoadConfig { elanInstall?, leanInstall?, lakeInstall? } - let ws ← MonadError.runEIO (MainM.runLogIO (loadWorkspace config)).toEIO + let some ws ← loadWorkspace config |>.toBaseIO + | throw <| IO.userError "failed to load Lake workspace" let package := ws.root let libs := (package.leanLibs.map (·.name)).map (·.toString) return if package.name == `mathlib then diff --git a/scripts/no_lints_prime_decls.txt b/scripts/no_lints_prime_decls.txt index de0b42c05c8e5..31bf8a6ea808e 100644 --- a/scripts/no_lints_prime_decls.txt +++ b/scripts/no_lints_prime_decls.txt @@ -1122,7 +1122,7 @@ EllipticCurve.coe_inv_variableChange_Δ' EllipticCurve.coe_map_Δ' EllipticCurve.coe_variableChange_Δ' em' -Embedding.mk' +IsEmbedding.mk' EMetric.diam_pos_iff' EMetric.diam_union' EMetric.mem_ball' @@ -1914,8 +1914,8 @@ Imo1969Q1.not_prime_of_int_mul' Imo2001Q2.imo2001_q2' imp_or' induced_orderTopology' -Inducing.continuousAt_iff' -Inducing.isClosed_iff' +IsInducing.continuousAt_iff' +IsInducing.isClosed_iff' inf_compl_eq_bot' inf_eq_half_smul_add_sub_abs_sub' inner_map_polarization' @@ -3521,7 +3521,7 @@ ONote.NF.below_of_lt' ONote.nf_repr_split' ONote.NF.snd' ONote.split_eq_scale_split' -OpenEmbedding.tendsto_nhds_iff' +IsOpenEmbedding.tendsto_nhds_iff' openSegment_eq_image' openSegment_eq_Ioo' Option.bind_congr' @@ -3840,7 +3840,6 @@ Polynomial.natTrailingDegree_eq_support_min' Polynomial.natTrailingDegree_mul' Polynomial.neg' Polynomial.ringHom_ext' -Polynomial.rootMultiplicity_eq_natTrailingDegree' Polynomial.rootMultiplicity_mul' Polynomial.rootMultiplicity_pos' Polynomial.rootSet_maps_to' @@ -3929,7 +3928,7 @@ ProbabilityTheory.cgf_const' ProbabilityTheory.cgf_zero' ProbabilityTheory.cond_apply' ProbabilityTheory.cond_cond_eq_cond_inter' -ProbabilityTheory.condCount_inter' +ProbabilityTheory.uniformOn_inter' ProbabilityTheory.condexp_ae_eq_integral_condexpKernel' ProbabilityTheory.condexpKernel_ae_eq_condexp' ProbabilityTheory.CondIndepSets.condIndep' @@ -4040,7 +4039,7 @@ Quotient.liftOn₂'_mk'' Quotient.liftOn'_mk'' Quotient.map₂'_mk'' Quotient.map'_mk'' -quotientMap_quotient_mk' +isQuotientMap_quotient_mk' Quotient.mk_out' Quotient.out_eq' Quotient.sound' @@ -4429,6 +4428,7 @@ star_comm_self' StarConvex.sub' star_inv' Stream' +Stream'.corec' Stream'.drop_tail' Stream'.get_succ_iterate' Stream'.Seq1.map_join' @@ -4639,8 +4639,8 @@ toIocMod_sub_zsmul' toIocMod_zsmul_add' toIxxMod_total' TopCat.GlueData.preimage_image_eq_image' -TopCat.openEmbedding_iff_comp_isIso' -TopCat.openEmbedding_iff_isIso_comp' +TopCat.isOpenEmbedding_iff_comp_isIso' +TopCat.isOpenEmbedding_iff_isIso_comp' TopCat.Presheaf.germ_stalkSpecializes' TopCat.Presheaf.pushforward_eq' TopCat.Presheaf.pushforward_map_app' @@ -4650,8 +4650,9 @@ TopologicalSpace.Opens.coe_inclusion' TopologicalSpace.Opens.map_comp_obj' TopologicalSpace.Opens.map_functor_eq' TopologicalSpace.Opens.map_id_obj' -TopologicalSpace.Opens.openEmbedding' +TopologicalSpace.Opens.isOpenEmbedding' TopologicalSpace.Opens.set_range_forget_map_inclusion' +TopologicalSpace.Opens.set_range_inclusion' TopologicalSpace.SecondCountableTopology.mk' Topology.WithScott.isOpen_iff_isUpperSet_and_scottHausdorff_open' top_sdiff' @@ -4729,8 +4730,8 @@ uniformContinuous_nnnorm' uniformContinuous_norm' isUniformEmbedding_iff' UniformGroup.mk' -uniformInducing_iff' -UniformInducing.mk' +isUniformInducing_iff' +IsUniformInducing.mk' uniformity_basis_edist' uniformity_basis_edist_le' uniformity_eq_comap_nhds_one' @@ -4795,6 +4796,7 @@ WeierstrassCurve.leadingCoeff_preΨ' WeierstrassCurve.map_preΨ' WeierstrassCurve.natDegree_coeff_preΨ' WeierstrassCurve.natDegree_preΨ' +WeierstrassCurve.Projective.add_of_Y_ne' WeierstrassCurve.Projective.addX_eq' WeierstrassCurve.Projective.addY_of_X_eq' WeierstrassCurve.Projective.addZ_eq' diff --git a/scripts/nolints-style.txt b/scripts/nolints-style.txt index 9467ae24e5650..b1dbf8c926f9d 100644 --- a/scripts/nolints-style.txt +++ b/scripts/nolints-style.txt @@ -32,3 +32,7 @@ Mathlib/Tactic/Linter/TextBased.lean : line 84 : ERR_ADN : Found the string "Ada Mathlib/Tactic/Linter/TextBased.lean : line 274 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead Mathlib/Tactic/Linter/TextBased.lean : line 279 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead Mathlib/Tactic/Linter/TextBased.lean : line 280 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead + +-- The "duplicate imports" linter fires on this line inside a multi-line module docstring, +-- which says 'import statements': this is a false positive. +Mathlib/Tactic/Linter/Header.lean : line 228 : ERR_DIMP : Duplicate imports: import statements* (already imported on line 19) diff --git a/scripts/nolints.json b/scripts/nolints.json index 422dd44978cdf..438084797d9f2 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -84,8 +84,6 @@ ["docBlame", "Combinator.I"], ["docBlame", "Combinator.K"], ["docBlame", "Combinator.S"], - ["docBlame", "CommRingCat.forget_obj_eq_coe"], - ["docBlame", "CommSemiRingCat.forget_obj_eq_coe"], ["docBlame", "CompleteBooleanAlgebra.toCompleteAtomicBooleanAlgebra"], ["docBlame", "Computation.parallelRec"], ["docBlame", "Congr!.elabConfig"], @@ -312,13 +310,11 @@ ["docBlame", "ReaderT.callCC"], ["docBlame", "ReaderT.mk"], ["docBlame", "ReaderT.mkLabel"], - ["docBlame", "RingCat.forget_obj_eq_coe"], ["docBlame", "RingQuot.preLift"], ["docBlame", "RingQuot.preLiftAlgHom"], ["docBlame", "RingQuot.toQuot"], ["docBlame", "RootableBy.root"], ["docBlame", "SchwartzMap.toFun"], - ["docBlame", "SemiRingCat.forget_obj_eq_coe"], ["docBlame", "Semigrp.forget_obj_eq_coe"], ["docBlame", "Shrink.rec"], ["docBlame", "SlashAction.map"], @@ -506,7 +502,6 @@ ["docBlame", "Mathlib.Tactic.tacticMatch_target_"], ["docBlame", "Mathlib.Tactic.tacticSet!_"], ["docBlame", "Mathlib.Tactic.tacticSuffices_"], - ["docBlame", "Mathlib.Tactic.tacticTransitivity___"], ["docBlame", "Mathlib.Tactic.usingArg"], ["docBlame", "Mathlib.Tactic.withArgs"], ["docBlame", "Mathlib.WhatsNew.diffExtension"], @@ -712,10 +707,6 @@ ["docBlame", "Mathlib.Command.Variable.variable?.maxSteps"], ["docBlame", "Mathlib.Meta.NormNum.evalEq.intArm"], ["docBlame", "Mathlib.Meta.NormNum.evalEq.ratArm"], - ["docBlame", "Mathlib.Meta.NormNum.evalLE.intArm"], - ["docBlame", "Mathlib.Meta.NormNum.evalLE.ratArm"], - ["docBlame", "Mathlib.Meta.NormNum.evalLT.intArm"], - ["docBlame", "Mathlib.Meta.NormNum.evalLT.ratArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMinFac.aux"], ["docBlame", "Mathlib.Meta.NormNum.evalMinFac.core"], ["docBlame", "Mathlib.Meta.NormNum.evalNatPrime.core"], @@ -749,6 +740,10 @@ ["docBlame", "Mathlib.Tactic.Says.says.verify"], ["docBlame", "Mathlib.Meta.NormNum.evalAdd.core.intArm"], ["docBlame", "Mathlib.Meta.NormNum.evalAdd.core.ratArm"], + ["docBlame", "Mathlib.Meta.NormNum.evalLE.core.intArm"], + ["docBlame", "Mathlib.Meta.NormNum.evalLE.core.ratArm"], + ["docBlame", "Mathlib.Meta.NormNum.evalLT.core.intArm"], + ["docBlame", "Mathlib.Meta.NormNum.evalLT.core.ratArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.intArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.ratArm"], ["unusedArguments", "Combinator.K"]] diff --git a/scripts/noshake.json b/scripts/noshake.json index 6448419d87171..f2f21e3466599 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -41,6 +41,7 @@ "Mathlib.Control.Traversable.Lemmas", "Mathlib.Data.Finsupp.Notation", "Mathlib.Data.Int.Defs", + "Mathlib.Data.Int.Notation", "Mathlib.Data.Matrix.Notation", "Mathlib.Data.Matroid.Init", "Mathlib.Data.Nat.Notation", @@ -148,7 +149,6 @@ "Mathlib.Tactic.Recover", "Mathlib.Tactic.ReduceModChar.Ext", "Mathlib.Tactic.Relation.Symm", - "Mathlib.Tactic.Relation.Trans", "Mathlib.Tactic.Rename", "Mathlib.Tactic.RenameBVar", "Mathlib.Tactic.Replace", @@ -194,10 +194,12 @@ "ignoreAll": ["Batteries.Tactic.Basic", "Mathlib.Mathport.Syntax", "Mathlib.Tactic.Linter"], "ignore": - {"Mathlib.Topology.UniformSpace.Basic": ["Mathlib.Tactic.Monotonicity.Basic"], + {"Mathlib.Util.Notation3": ["Lean.Elab.BuiltinCommand"], + "Mathlib.Topology.UniformSpace.Basic": ["Mathlib.Tactic.Monotonicity.Basic"], "Mathlib.Topology.Sheaves.Forget": ["Mathlib.Algebra.Category.Ring.Limits"], "Mathlib.Topology.Order.LeftRightNhds": ["Mathlib.Algebra.Ring.Pointwise.Set"], + "Mathlib.Topology.JacobsonSpace": ["Mathlib.Tactic.StacksAttribute"], "Mathlib.Topology.Germ": ["Mathlib.Analysis.Normed.Module.Basic"], "Mathlib.Topology.Defs.Basic": ["Mathlib.Tactic.FunProp"], "Mathlib.Topology.Category.UniformSpace": @@ -217,9 +219,11 @@ "Mathlib.Tactic.ReduceModChar": ["Mathlib.Data.ZMod.Basic", "Mathlib.RingTheory.Polynomial.Basic"], "Mathlib.Tactic.ProxyType": ["Mathlib.Logic.Equiv.Defs"], + "Mathlib.Tactic.ProjectionNotation": ["Lean.Elab.AuxDef"], "Mathlib.Tactic.ProdAssoc": ["Mathlib.Logic.Equiv.Defs"], "Mathlib.Tactic.Positivity.Finset": - ["Mathlib.Data.Finset.Density", "Mathlib.Data.Fintype.Card"], + ["Mathlib.Algebra.Order.BigOperators.Group.Finset", + "Mathlib.Data.Finset.Density"], "Mathlib.Tactic.Positivity.Basic": ["Mathlib.Algebra.GroupPower.Order", "Mathlib.Algebra.Order.Group.PosPart", @@ -262,8 +266,13 @@ "Mathlib.Analysis.SpecialFunctions.Log.Deriv", "Mathlib.Tactic.FunProp", "Mathlib.Tactic.FunProp.Differentiable"], + "Mathlib.Tactic.Finiteness": + ["Mathlib.MeasureTheory.Constructions.Prod.Basic", + "Mathlib.Tactic.Finiteness.Attr", + "Mathlib.Tactic.Positivity.Core"], "Mathlib.Tactic.FinCases": ["Mathlib.Data.Fintype.Basic"], "Mathlib.Tactic.Eval": ["Qq.Macro"], + "Mathlib.Tactic.DeriveToExpr": ["Lean.Elab.Deriving.Ord"], "Mathlib.Tactic.DeriveFintype": ["Mathlib.Data.Fintype.Basic", "Mathlib.Data.Fintype.Sigma", @@ -295,7 +304,6 @@ ["Mathlib.Algebra.Group.ZeroOne", "Mathlib.Tactic.Bound.Init"], "Mathlib.Tactic.Bound": ["Mathlib.Algebra.Order.AbsoluteValue", - "Mathlib.Algebra.Order.BigOperators.Group.Finset", "Mathlib.Algebra.Order.Floor", "Mathlib.Analysis.Analytic.Basic", "Mathlib.Tactic.Bound.Init"], @@ -325,10 +333,9 @@ "Mathlib.Order.RelClasses": ["Batteries.WF"], "Mathlib.Order.Filter.ListTraverse": ["Mathlib.Control.Traversable.Instances"], + "Mathlib.Order.Defs": ["Batteries.Tactic.Trans"], + "Mathlib.Order.BoundedOrder": ["Mathlib.Tactic.Finiteness.Attr"], "Mathlib.Order.Basic": ["Batteries.Tactic.Classical"], - "Mathlib.NumberTheory.Harmonic.Defs": - ["Mathlib.Algebra.Order.BigOperators.Ring.Finset", - "Mathlib.Algebra.Order.Field.Basic"], "Mathlib.NumberTheory.Cyclotomic.Basic": ["Mathlib.Init.Core"], "Mathlib.NumberTheory.ArithmeticFunction": ["Mathlib.Tactic.ArithMult"], "Mathlib.MeasureTheory.MeasurableSpace.Defs": ["Mathlib.Tactic.FunProp.Attr"], @@ -336,7 +343,6 @@ "Mathlib.Logic.Function.Defs": ["Mathlib.Tactic.AdaptationNote"], "Mathlib.Logic.Function.Basic": ["Batteries.Tactic.Init"], "Mathlib.Logic.Equiv.Defs": ["Mathlib.Data.Bool.Basic"], - "Mathlib.Logic.Basic": ["Mathlib.Data.Int.Notation"], "Mathlib.LinearAlgebra.Matrix.Transvection": ["Mathlib.Data.Matrix.DMatrix"], "Mathlib.LinearAlgebra.Basic": ["Mathlib.Algebra.BigOperators.Group.Finset"], "Mathlib.LinearAlgebra.AffineSpace.FiniteDimensional": ["Mathlib.Init.Core"], @@ -344,15 +350,18 @@ "Mathlib.Lean.Meta": ["Batteries.Logic"], "Mathlib.Lean.Expr.ExtraRecognizers": ["Mathlib.Data.Set.Operations"], "Mathlib.Lean.Expr.Basic": ["Batteries.Logic"], - "Mathlib.Init.Data.Nat.Lemmas": ["Batteries.Data.Nat.Lemmas", "Batteries.WF"], "Mathlib.GroupTheory.MonoidLocalization.Basic": ["Mathlib.Init.Data.Prod"], "Mathlib.Geometry.Manifold.Sheaf.Smooth": ["Mathlib.CategoryTheory.Sites.Whiskering"], "Mathlib.Geometry.Manifold.PoincareConjecture": ["Mathlib.AlgebraicTopology.FundamentalGroupoid.SimplyConnected", "Mathlib.Util.Superscript"], + "Mathlib.Deprecated.NatLemmas": ["Batteries.Data.Nat.Lemmas", "Batteries.WF"], + "Mathlib.Deprecated.MinMax": ["Mathlib.Order.MinMax"], + "Mathlib.Deprecated.ByteArray": ["Batteries.Data.ByteSubarray"], "Mathlib.Data.Vector.Basic": ["Mathlib.Control.Applicative"], - "Mathlib.Data.Set.Image": ["Batteries.Tactic.Congr"], + "Mathlib.Data.Set.Image": + ["Batteries.Tactic.Congr", "Mathlib.Data.Set.SymmDiff"], "Mathlib.Data.Seq.Parallel": ["Mathlib.Init.Data.Prod"], "Mathlib.Data.PEquiv": ["Batteries.Tactic.Congr"], "Mathlib.Data.Ordmap.Ordnode": ["Mathlib.Data.Option.Basic"], @@ -363,12 +372,11 @@ "Mathlib.Data.List.Range": ["Batteries.Data.Nat.Lemmas"], "Mathlib.Data.List.ProdSigma": ["Batteries.Data.Nat.Lemmas", "Mathlib.Data.List.Basic"], - "Mathlib.Data.List.Lemmas": ["Mathlib.Data.List.InsertNth"], + "Mathlib.Data.List.Lemmas": ["Mathlib.Data.List.InsertIdx"], "Mathlib.Data.List.Defs": ["Batteries.Data.RBMap.Basic"], "Mathlib.Data.List.Basic": ["Mathlib.Control.Basic", "Mathlib.Data.Option.Basic"], "Mathlib.Data.LazyList.Basic": ["Mathlib.Lean.Thunk"], - "Mathlib.Data.Int.Order.Basic": ["Mathlib.Data.Int.Notation"], "Mathlib.Data.Int.Defs": ["Batteries.Data.Int.Order"], "Mathlib.Data.FunLike.Basic": ["Mathlib.Logic.Function.Basic"], "Mathlib.Data.Finset.Basic": ["Mathlib.Data.Finset.Attr"], @@ -381,6 +389,7 @@ ["Mathlib.Algebra.Order.Field.Basic"], "Mathlib.CategoryTheory.Sites.IsSheafFor": ["Mathlib.CategoryTheory.Limits.Shapes.Pullback.Mono"], + "Mathlib.CategoryTheory.Preadditive.Basic": ["Mathlib.Algebra.Module.End"], "Mathlib.CategoryTheory.Monoidal.Rigid.Basic": ["Mathlib.Tactic.CategoryTheory.Monoidal.Basic"], "Mathlib.CategoryTheory.Monoidal.Braided.Basic": @@ -418,9 +427,9 @@ "Mathlib.Algebra.Module.LinearMap.Basic": ["Mathlib.Algebra.Star.Basic"], "Mathlib.Algebra.Module.Equiv": ["Mathlib.Algebra.Star.Basic"], "Mathlib.Algebra.Homology.ModuleCat": ["Mathlib.Algebra.Homology.Homotopy"], + "Mathlib.Algebra.Group.Units.Basic": ["Mathlib.Tactic.Subsingleton"], "Mathlib.Algebra.Group.Units": ["Mathlib.Tactic.Subsingleton"], "Mathlib.Algebra.Group.Pi.Basic": ["Batteries.Tactic.Classical"], - "Mathlib.Algebra.Group.Defs": ["Mathlib.Data.Int.Notation"], "Mathlib.Algebra.GeomSum": ["Mathlib.Algebra.Order.BigOperators.Ring.Finset"], "Mathlib.Algebra.Category.Ring.Basic": ["Mathlib.CategoryTheory.ConcreteCategory.ReflectsIso"], diff --git a/scripts/polyrith_sage.py b/scripts/polyrith_sage.py index 42f7f58ccc7fd..9833e5923864e 100644 --- a/scripts/polyrith_sage.py +++ b/scripts/polyrith_sage.py @@ -1,10 +1,13 @@ # This file is part of the `polyrith` tactic in `src/tactic/polyrith.lean`. # It interfaces between Lean and the Sage web interface. -import requests import json -import sys from os.path import join, dirname +import sys +from typing import Dict, Any +import urllib.error +import urllib.parse +import urllib.request # These functions are used to format the output of Sage for parsing in Lean. # They are stored here as a string since they are passed to Sage via the web API. @@ -59,15 +62,19 @@ def __init__(self, ename, evalue, message='Error in Sage communication'): self.message = message super().__init__(self.message) -def parse_response(resp: str) -> str: +def parse_response(resp: str) -> Dict[str, Any]: exp, data = resp.split(';', 1) return dict(power=int(exp), coeffs=json.loads(data)) -def evaluate_in_sage(query: str) -> str: - data = {'code': query} - headers = {'content-type': 'application/x-www-form-urlencoded'} - response = requests.post('https://sagecell.sagemath.org/service', data, headers=headers).json() +def evaluate_in_sage(query: str) -> Dict[str, Any]: + data = urllib.parse.urlencode({'code': query}).encode('utf-8') + headers = {'Content-Type': 'application/x-www-form-urlencoded', + 'User-Agent': 'LeanProver (https://leanprover-community.github.io/)'} + req = urllib.request.Request('https://sagecell.sagemath.org/service', data=data, headers=headers) + with urllib.request.urlopen(req) as response: + response_data = response.read().decode() + response = json.loads(response_data) if response['success']: return parse_response(response.get('stdout')) elif 'execute_reply' in response and 'ename' in response['execute_reply'] and 'evalue' in response['execute_reply']: diff --git a/scripts/technical-debt-metrics.sh b/scripts/technical-debt-metrics.sh index 2c46d0c0ac79c..b06c1c7d412e0 100755 --- a/scripts/technical-debt-metrics.sh +++ b/scripts/technical-debt-metrics.sh @@ -3,6 +3,19 @@ # Make this script robust against unintentional errors. # See e.g. http://redsymbol.net/articles/unofficial-bash-strict-mode/ for explanation. set -euo pipefail + +# We need to make the script robust against changes on disk +# that might have happened during the script execution, e.g. from switching branches. +# We do that by making sure the entire script is parsed before execution starts +# using the following pattern +# { +# # script content +# exit +# } +# (see https://stackoverflow.com/a/2358432). +# So please do not delete the following line, or the final two lines of this script. +{ + IFS=$'\n\t' # `./scripts/technical-debt-metrics.sh` returns a tally of some technical debts in current Mathlib, @@ -17,6 +30,28 @@ currCommit="${1:-"$(git rev-parse HEAD)"}" # Similarly for the second argument. refCommit="${2:-"$(git log --pretty=%H --since="$(date -I -d 'last week')" | tail -n -1)"}" +## `computeDiff input` assumes that input consists of lines of the form `value|description` +## where `value` is a number and `description` is the statistic that `value` reports. +## `value` is non-negative, if it refers to the current commit and it is negative otherwise. +## The output is of the form `|current value|difference|description|`. +computeDiff () { + awk -F'|' 'BEGIN{con=1}{ + # order keeps track of maintaining the final order of the counters the same as the input one + # rdict stores the difference of the current value minus the old value + # curr stores the current value, making sure that the number is non-negative and does not start with `-` + if(rdict[$2] == "") {order[con]=$2; con++} + if((0 <= $1+0) && (!($1 ~ "-"))) {curr[$2]=$1} + rdict[$2]+=$1+0 + } END { + # loop over the "sorted" index in `order` + for(ind=1; ind<=con-1; ind++) { + # retrieve the description of the counter + val=order[ind] + # print `|current value|difference|name of counter|` + printf("|%s|%s|%s|\n", curr[val], rdict[val], val)} + }' "${1}" +} + # `tdc` produces a semi-formatted output of the form # ... # |description @@ -25,28 +60,28 @@ refCommit="${2:-"$(git log --pretty=%H --since="$(date -I -d 'last week')" | tai # The script uses the fact that a line represents a technical debt if and only if the text before # the first `|` is a number. This is then used for comparison and formatting. tdc () { -titlesAndRegexes=( - "porting notes" "Porting note" - "backwards compatibility flags" "set_option.*backward" - "skipAssignedInstances flags" "set_option tactic.skipAssignedInstances" - "adaptation notes" "adaptation_note" - "disabled simpNF lints" "nolint simpNF" - "disabled deprecation lints" "set_option linter.deprecated false" - "erw" "erw \[" - "maxHeartBeats modifications" "^ *set_option .*maxHeartbeats" +titlesPathsAndRegexes=( + "porting notes" "*" "Porting note" + "backwards compatibility flags" "*" "set_option.*backward" + "skipAssignedInstances flags" "*" "set_option tactic.skipAssignedInstances" + "adaptation notes" "*" "adaptation_note" + "disabled simpNF lints" "*" "nolint simpNF" + "disabled deprecation lints" "*" "set_option linter.deprecated false" + "erw" "*" "erw \[" + "maxHeartBeats modifications" ":^test" "^ *set_option .*maxHeartbeats" ) -printf '|Current number|Change|Type|\n|-:|:-:|:-|\n' -for i in ${!titlesAndRegexes[@]}; do - # loop on the odd-indexed entries and name each entry and the following - if (( (i + 1) % 2 )); then - title="${titlesAndRegexes[$i]}" - regex="${titlesAndRegexes[$(( i + 1 ))]}" +for i in ${!titlesPathsAndRegexes[@]}; do + # loop on every 3rd entry and name that entry and the following two + if (( i % 3 == 0 )); then + title="${titlesPathsAndRegexes[$i]}" + pathspec="${titlesPathsAndRegexes[$(( i + 1 ))]}" + regex="${titlesPathsAndRegexes[$(( i + 2 ))]}" if [ "${title}" == "porting notes" ] then fl="-i" # just for porting notes we ignore the case in the regex else fl="--" fi - printf '%s|%s\n' "$(git grep "${fl}" "${regex}" | wc -l)" "${title}" + printf '%s|%s\n' "$(git grep "${fl}" "${regex}" "${pathspec}" | wc -l)" "${title}" fi done @@ -55,47 +90,44 @@ printf '%s|%s\n' "$(grep -c 'docBlame' scripts/nolints.json)" "documentation nol printf '%s|%s\n' "$(git grep '^set_option linter.style.longFile [0-9]*' Mathlib | wc -l)" "large files" printf '%s|%s\n' "$(git grep "^open .*Classical" | grep -v " in$" -c)" "bare open (scoped) Classical" +printf '%s|%s\n' "$(wc -l < scripts/no_lints_prime_decls.txt)" "exceptions for the docPrime linter" + deprecatedFiles="$(git ls-files '**/Deprecated/*.lean' | xargs wc -l | sed 's=^ *==')" printf '%s|%s\n' "$(printf '%s' "${deprecatedFiles}" | wc -l)" "\`Deprecated\` files" -printf '%s|%s\n' "$(printf '%s\n' "${deprecatedFiles}" | grep total | sed 's= total==')" 'total LoC in `Deprecated` files' +printf '%s|%s\n\n' "$(printf '%s\n' "${deprecatedFiles}" | grep total | sed 's= total==')" 'total LoC in `Deprecated` files' +} -initFiles="$(git ls-files '**/Init/*.lean' | xargs wc -l | sed 's=^ *==')" +# collect the technical debts and the line counts of the deprecated file from the current mathlib +git checkout -q "${currCommit}" +new="$(tdc)" +newDeprecatedFiles="$(git ls-files '**/Deprecated/*.lean' | xargs wc -l | sed 's=^ *==')" +git switch -q - -printf '%s|%s\n' "$(printf '%s' "${initFiles}" | wc -l)" "\`Init\` files" -printf '%s|%s\n\n' "$(printf '%s\n' "${initFiles}" | grep total | sed 's= total==')" 'total LoC in `Init` files' +# collect the technical debts and the line counts of the deprecated file from the reference mathlib +git checkout -q "${refCommit}" +old="$(tdc | sed 's=^[0-9]=-&=')" +oldDeprecatedFiles="$(git ls-files '**/Deprecated/*.lean' | xargs wc -l | sed 's=^ *=-=')" +git switch -q - -printf $'```spoiler Changed \'Init\' lines by file\n%s\n```\n' "$( - printf '%s\n' "${initFiles}" | awk 'BEGIN{print("|LoC|Change|File|\n|-:|:-:|-|")} {printf("%s|%s\n", $1, $2)}' - )" -} +printf '|Current number|Change|Type|\n|-:|:-:|:-|\n' +printf '%s\n%s\n' "${old}" "${new}" | computeDiff - +deprSummary="$(printf '%s\n%s\n' "${oldDeprecatedFiles}" "${newDeprecatedFiles}" | tr ' ' '|' | computeDiff -)" -# collect the technical debts from the current mathlib -new="$(git checkout -q "${currCommit}" && tdc; git switch -q -)" - -# collect the technical debts from the reference mathlib -- switch to the -old="$(git checkout -q "${refCommit}" && tdc; git switch -q -)" - -# place the outputs side-by-side, using `@` as a separator -paste -d@ <(echo "$new") <(echo "${old}") | sed 's=@=|@|=' | - # each line should look like eithe - # [new number]|description@[old number]|descr - # or something that does not start with [number]| - # we split the lines into "words", using `|` as a separator - awk -F'|' ' - # if the first "word" is a number, then we write the 1st entry and compare it with the 4th - ($1+0 == $1) { printf("|%s|%s|%s|\n", $1, $1-$4, $2) } - # otherwise, the line is a "formatting" line, so we simply print it unchanged until we find `@` - !($1+0 == $1) { - for(i=1; i<=NF; i++) { - if ($i == "@") { break } - else { printf("%s|", $i) } - } - print "@" - }' | - # the sequence `@|` ending a line is an artifact of our process and we remove it - sed 's=|@$==' +printf $'```spoiler Changed \'Deprecated\' lines by file\n%s\n```\n' "$( + printf '%s\n' "${deprSummary}" | awk -F'|' 'BEGIN{print("|LoC|Change|File|\n|-:|:-:|-|")} + ($4 == "total") {total=$0} + (!($4 == "total")) { + printf("%s\n", $0) + } END {printf("%s\n", total)}' + )" baseURL='https://github.com/leanprover-community/mathlib4/commit' printf '\nCurrent commit [%s](%s)\n' "${currCommit:0:10}" "${baseURL}/${currCommit}" printf 'Reference commit [%s](%s)\n' "${refCommit:0:10}" "${baseURL}/${refCommit}" + +# These last two lines are needed to make the script robust against changes on disk +# that might have happened during the script execution, e.g. from switching branches +# See the top of the file for more details. +exit +} diff --git a/scripts/test.lean b/scripts/test.lean deleted file mode 100644 index f02a621637377..0000000000000 --- a/scripts/test.lean +++ /dev/null @@ -1,21 +0,0 @@ -/- -Copyright (c) 2024 Kim Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kim Morrison --/ -open IO.Process -open System - -/-- -Run tests, via the Batteries test runner. - -When https://github.com/leanprover/lean4/issues/4121 -"allow using an upstream executable as a lake `@[test_runner]`" -is resolved, this file can be replaced with a line in `lakefile.lean`. --/ -def main (args : List String) : IO Unit := do - -- ProofWidgets and Batteries may not have been completely built by `lake build` yet, - -- but they are needed by some tests. - _ ← (← spawn { cmd := "lake", args := #["build", "ProofWidgets", "Batteries"] }).wait - let exitcode ← (← spawn { cmd := "lake", args := #["exe", "batteries/test"] ++ args }).wait - exit exitcode.toUInt8 diff --git a/scripts/unused_in_pole.sh b/scripts/unused_in_pole.sh new file mode 100755 index 0000000000000..89d0761515351 --- /dev/null +++ b/scripts/unused_in_pole.sh @@ -0,0 +1,14 @@ +#! /bin/bash + +# Run `lake exe pole $1` (defaulting to Mathlib if no argument is provided) +# and then use `lake exe unused` to investigate unused transitive imports along the longest pole. + +# Create a file `unused.md` in the current directory, showing the unused transitive imports, +# and prints a `lake exe graph` commands showing the largest "rectangles" of unused imports +# (i.e. places where a large set of modules do not make use of a different large set of modules, +# even though they are transitively imported.) + +# Default to Mathlib if no argument is provided +target=${1:-Mathlib} + +lake exe pole --loc --to $target | tail -n +3 | cut -f2 -d '|' | awk '{$1=$1; print}' | grep -v "Lean\." | grep -v "Init\." | grep -v "Tactic\." | grep -v "^Mathlib$" | grep -v "^Mathlib.Init$" | xargs lake exe unused diff --git a/test/BinPow.lean b/test/BinPow.lean new file mode 100644 index 0000000000000..33b61a251e7fd --- /dev/null +++ b/test/BinPow.lean @@ -0,0 +1,13 @@ +import Mathlib.Data.ZMod.Defs + +-- A 1024-bit prime number +set_option linter.style.longLine false in +abbrev M : Nat := 0xb10b8f96a080e01dde92de5eae5d54ec52c99fbcfb06a3c69a6a9dca52d23b616073e28675a23d189838ef1e2ee652c013ecb4aea906112324975c3cd49b83bfaccbdd7d90c4bd7098488e9c219a73724effd6fae5644738faa31a4ff55bccc0a151af5f0dc8b4bd45bf37df365c1a65e68cfda76d4da708df1fb2bc2e4a4371 + +set_option linter.style.longLine false in +abbrev g : Nat := 0xa4d1cbd5c3fd34126765a442efb99905f8104dd258ac507fd6406cff14266d31266fea1e5c41564b777e690f5504f213160217b4b01b886a5e91547f9e2749f4d7fbd7d3b9a92ee1909d0d2263f80a76a6a24c087a091f531dbf0a0169b6a28ad662a4d18e73afa32d779d5918d08bc8858f4dcef97c2a24855e6eeb22b3b2e5 + +-- This should evaluate within a few seconds compared to never(ish) previously +/-- info: 1 -/ +#guard_msgs in +#eval (g : ZMod M) ^ (M - 1) diff --git a/test/BinaryRec.lean b/test/BinaryRec.lean new file mode 100644 index 0000000000000..1112d600d4af8 --- /dev/null +++ b/test/BinaryRec.lean @@ -0,0 +1,8 @@ +import Mathlib.Data.Nat.Bits + +def Nat.popcountTR (n : Nat) : Nat := + n.binaryRec (·) (fun b _ f x ↦ f (x + b.toNat)) 0 + +/-- info: 1 -/ +#guard_msgs in +#eval Nat.popcountTR (2 ^ 20240) diff --git a/test/CategoryTheory/Elementwise.lean b/test/CategoryTheory/Elementwise.lean index c28cc0073a784..4b8056c788b1f 100644 --- a/test/CategoryTheory/Elementwise.lean +++ b/test/CategoryTheory/Elementwise.lean @@ -92,7 +92,7 @@ lemma bar''' {M N K : MonCat} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f g (f x) = h x := by apply foo_apply w example (M N K : MonCat) (f : M ⟶ N) (g : N ⟶ K) (h : M ⟶ K) (w : f ≫ g = h) (m : M) : - g (f m) = h m := by erw [elementwise_of% w]; rfl -- Porting note: was `rw`, switched to `erw; rfl` + g (f m) = h m := by rw [elementwise_of% w] example (M N K : MonCat) (f : M ⟶ N) (g : N ⟶ K) (h : M ⟶ K) (w : f ≫ g = h) (m : M) : g (f m) = h m := by diff --git a/test/CategoryTheory/Sites/ConcreteSheafification.lean b/test/CategoryTheory/Sites/ConcreteSheafification.lean new file mode 100644 index 0000000000000..8f5491183bbc6 --- /dev/null +++ b/test/CategoryTheory/Sites/ConcreteSheafification.lean @@ -0,0 +1,34 @@ +import Mathlib.Algebra.Category.ModuleCat.Colimits +import Mathlib.Algebra.Category.ModuleCat.Limits +import Mathlib.Algebra.Category.ModuleCat.FilteredColimits +import Mathlib.CategoryTheory.Sites.Equivalence + +universe u + +open CategoryTheory + +section Small + +variable {C : Type u} [SmallCategory C] (J : GrothendieckTopology C) + +example : HasSheafify J (Type u) := inferInstance + +example (R : Type u) [Ring R] : HasSheafify J (ModuleCat.{u} R) := inferInstance + +end Small + +section Large + +variable {C : Type (u+1)} [LargeCategory C] (J : GrothendieckTopology C) + +example : HasSheafify J (Type (u+1)) := inferInstance + +example (R : Type (u+1)) [Ring R] : HasSheafify J (ModuleCat.{u+1} R) := inferInstance + +variable [EssentiallySmall.{u} C] + +example : HasSheafify J (Type u) := inferInstance + +example (R : Type u) [Ring R] : HasSheafify J (ModuleCat.{u} R) := inferInstance + +end Large diff --git a/test/CategoryTheory/Sites/PreservesSheafification.lean b/test/CategoryTheory/Sites/PreservesSheafification.lean new file mode 100644 index 0000000000000..813746eb759e5 --- /dev/null +++ b/test/CategoryTheory/Sites/PreservesSheafification.lean @@ -0,0 +1,30 @@ +import Mathlib.Algebra.Category.ModuleCat.Colimits +import Mathlib.Algebra.Category.ModuleCat.Limits +import Mathlib.Algebra.Category.ModuleCat.FilteredColimits +import Mathlib.CategoryTheory.Sites.Equivalence + +universe u + +open CategoryTheory GrothendieckTopology + +section Small + +variable {C : Type u} [SmallCategory C] (J : GrothendieckTopology C) (R : Type u) [Ring R] + +example : PreservesSheafification J (forget (ModuleCat.{u} R)) := inferInstance + +end Small + +section Large + +variable {C : Type (u+1)} [LargeCategory C] (J : GrothendieckTopology C) + +example (R : Type (u+1)) [Ring R] : PreservesSheafification J (forget (ModuleCat.{u+1} R)) := + inferInstance + +variable [EssentiallySmall.{u} C] + +example (R : Type u) [Ring R] : PreservesSheafification J (forget (ModuleCat.{u} R)) := + inferInstance + +end Large diff --git a/test/CategoryTheory/Sites/Whiskering.lean b/test/CategoryTheory/Sites/Whiskering.lean new file mode 100644 index 0000000000000..af2efea006a9d --- /dev/null +++ b/test/CategoryTheory/Sites/Whiskering.lean @@ -0,0 +1,28 @@ +import Mathlib.Algebra.Category.ModuleCat.Colimits +import Mathlib.Algebra.Category.ModuleCat.Limits +import Mathlib.Algebra.Category.ModuleCat.FilteredColimits +import Mathlib.CategoryTheory.Sites.Equivalence + +universe u + +open CategoryTheory GrothendieckTopology + +section Small + +variable {C : Type u} [SmallCategory C] (J : GrothendieckTopology C) (R : Type u) [Ring R] + +example : HasSheafCompose J (forget (ModuleCat.{u} R)) := inferInstance + +end Small + +section Large + +variable {C : Type (u+1)} [LargeCategory C] (J : GrothendieckTopology C) + +example (R : Type (u+1)) [Ring R] : HasSheafCompose J (forget (ModuleCat.{u+1} R)) := inferInstance + +variable [EssentiallySmall.{u} C] + +example (R : Type u) [Ring R] : HasSheafCompose J (forget (ModuleCat.{u} R)) := inferInstance + +end Large diff --git a/test/CountHeartbeats.lean b/test/CountHeartbeats.lean new file mode 100644 index 0000000000000..ab017f739b3c7 --- /dev/null +++ b/test/CountHeartbeats.lean @@ -0,0 +1,21 @@ +import Mathlib.Tactic.Ring + +set_option linter.style.header false + +/-- info: Used 7 heartbeats, which is less than the current maximum of 200000. -/ +#guard_msgs in +count_heartbeats in +example (a : Nat) : a = a := rfl + +/-- info: Used 7 heartbeats, which is less than the minimum of 200000. -/ +#guard_msgs in +guard_min_heartbeats in +example (a : Nat) : a = a := rfl + +/-- info: Used 7 heartbeats, which is less than the minimum of 2000. -/ +#guard_msgs in +guard_min_heartbeats 2000 in +example (a : Nat) : a = a := rfl + +guard_min_heartbeats 1 in +example (a : Nat) : a = a := rfl diff --git a/test/DFinsuppMultiLinear.lean b/test/DFinsuppMultiLinear.lean new file mode 100644 index 0000000000000..41ccc8e876c46 --- /dev/null +++ b/test/DFinsuppMultiLinear.lean @@ -0,0 +1,21 @@ +import Mathlib.LinearAlgebra.Multilinear.DFinsupp +import Mathlib.LinearAlgebra.Multilinear.Pi +import Mathlib.Data.DFinsupp.Notation + +/-- +info: fun₀ + | !["hello", "complicated", "world"] => 20 + | !["hello", "complicated", "test file"] => 30 + | !["goodbye", "complicated", "world"] => -20 + | !["goodbye", "complicated", "test file"] => -30 +-/ +#guard_msgs in +#eval MultilinearMap.dfinsuppFamily + (κ := fun _ => String) + (M := fun _ _ => ℤ) + (N := fun _ => ℤ) + (R := ℤ) + (f := fun _ => MultilinearMap.mkPiAlgebra ℤ (Fin 3) ℤ) ![ + fun₀ | "hello" => 1 | "goodbye" => -1, + fun₀ | "complicated" => 10, + fun₀ | "world" => 2 | "test file" => 3] diff --git a/test/Header.lean b/test/Header.lean new file mode 100644 index 0000000000000..5644cae930fee --- /dev/null +++ b/test/Header.lean @@ -0,0 +1,316 @@ +/- +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.Tactic.Linter.Header +import Lake +import /- -/ Mathlib.Tactic -- the `TextBased` linter does not flag this `broadImport` +import Mathlib.Tactic.Have +import Mathlib.Deprecated.Subfield + +/-- +warning: In the past, importing 'Lake' in mathlib has led to dramatic slow-downs of the linter (see e.g. mathlib4#13779). Please consider carefully if this import is useful and make sure to benchmark it. If this is fine, feel free to allow this linter. +note: this linter can be disabled with `set_option linter.style.header false` +--- +warning: Files in mathlib cannot import the whole tactic folder. +note: this linter can be disabled with `set_option linter.style.header false` +--- +warning: Mathlib.Tactic.Have defines a deprecated form of the 'have' tactic; please do not use it in mathlib. +note: this linter can be disabled with `set_option linter.style.header false` +--- +warning: Files in the `Deprecated` directory are not supposed to be imported. +note: this linter can be disabled with `set_option linter.style.header false` +--- +warning: The module doc-string for a file should be the first command after the imports. +Please, add a module doc-string before `/-!# Tests for the `docModule` linter +-/ +`. +note: this linter can be disabled with `set_option linter.style.header false` +-/ +#guard_msgs in +set_option linter.style.header true in + +/-! +# Tests for the `docModule` linter +-/ + +/-- +A convenience function that replaces `/` with `|`. +This converts `/-` and `-/` into `|-` and `-|` that no longer interfere with the ending of the +`#guard_msgs` doc-string. +-/ +def replaceMultilineComments (s : String) : String := + s.replace "/" "|" + +open Lean Elab Command in +/-- +`#check_copyright cop` takes as input the `String` `cop`, expected to be a copyright statement. +It logs details of what the linter would report if the `cop` is "malformed". +-/ +elab "#check_copyright " cop:str : command => do + let cop := cop.getString + for (s, m) in Mathlib.Linter.copyrightHeaderChecks cop do + if let some rg := s.getRange? then + logInfo + m!"Text: `{replaceMultilineComments s.getAtomVal}`\n\ + Range: {(rg.start, rg.stop)}\n\ + Message: '{replaceMultilineComments m}'" + +-- well-formed +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName, Name LastName, +Name LastName, + Name LastName, + Name LastName +-/ +" + +/-- +info: Text: ` |-` +Range: (0, 3) +Message: 'Malformed or missing copyright header: `|-` should be alone on its own line.' +-/ +#guard_msgs in +#check_copyright +" /- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/ +" + +-- The last line does not end with a newline. +/-- +info: Text: `-|` +Range: (149, 151) +Message: 'Malformed or missing copyright header: `-|` should be alone on its own line.' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/" + +/-- +info: Text: `Authors: Name LastName + +Here comes an implicit docstring which doesn't belong here!` +Range: (126, 209) +Message: 'If an authors line spans multiple lines, each line but the last must end with a trailing comma' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName + +Here comes an implicit docstring which doesn't belong here! +-/ +" + +/-- +info: Text: `Authors: Name LastName +Here comes an implicit docstring which shouldn't be here!` +Range: (126, 206) +Message: 'If an authors line spans multiple lines, each line but the last must end with a trailing comma' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +Here comes an implicit docstring which shouldn't be here! +-/ +" + +/-- +info: Text: `-|` +Range: (126, 128) +Message: 'Copyright too short!' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +-/ +" + +/-- +info: Text: `-|` +Range: (1, 3) +Message: 'Copyright too short!' +-/ +#guard_msgs in +#check_copyright "" + +/-- +info: Text: `-|` +Range: (1, 3) +Message: 'Copyright too short!' +-/ +#guard_msgs in +#check_copyright "" + +/-- +info: Text: `Cpyright (c) 202` +Range: (3, 19) +Message: 'Copyright line should start with 'Copyright (c) YYYY'' +-/ +#guard_msgs in +#check_copyright +"/- +Cpyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/ +" + +/-- +info: Text: `a. All rights reserve.` +Range: (34, 56) +Message: 'Copyright line should end with '. All rights reserved.'' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserve. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/ +" + +/-- +info: Text: `Rleased under Apache 2.0 license as described in the file LICENSE.` +Range: (58, 124) +Message: 'Second copyright line should be +"Released under Apache 2.0 license as described in the file LICENSE."' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Rleased under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/ +" + +/-- +info: Text: `A uthors:` +Range: (126, 135) +Message: 'The authors line should begin with 'Authors: '' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +A uthors: Name LastName +-/ +" + +/-- +info: Text: ` ` +Range: (139, 141) +Message: 'Double spaces are not allowed.' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName +-/ +" + +/-- +info: Text: `.` +Range: (148, 149) +Message: 'Please, do not end the authors' line with a period.' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName. +-/ +" + +/-- +info: Text: ` ` +Range: (149, 151) +Message: 'Double spaces are not allowed.' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName, + Name LastName +-/ +" + +-- The `Copyright` and `Authors` lines are allowed to overflow. +#check_copyright +"/- +Copyright (c) 2019 Reid Barton, Johan Commelin, Jesse Michael Han, Chris Hughes, Robert Y. Lewis, +Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Reid Barton, Johan Commelin, Jesse Michael Han, Chris Hughes, Robert Y. Lewis, + Patrick Massot +-/ +" + +-- However, in this case the wrapped lines must end with a comma. +/-- +info: Text: `(c) 2024 Damiano Testa` +Range: (13, 35) +Message: 'Copyright line should end with '. All rights reserved.'' +--- +info: Text: `Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName + and others.` +Range: (83, 187) +Message: 'If an authors line spans multiple lines, each line but the last must end with a trailing comma' +--- +info: Text: `Released ` +Range: (83, 92) +Message: 'The authors line should begin with 'Authors: '' +--- +info: Text: ` ` +Range: (174, 176) +Message: 'Double spaces are not allowed.' +--- +info: Text: ` and ` +Range: (175, 180) +Message: 'Please, do not use 'and'; use ',' instead.' +--- +info: Text: `.` +Range: (106, 107) +Message: 'Please, do not end the authors' line with a period.' +--- +info: Text: ` and many other authors. All rights reserved.` +Range: (36, 82) +Message: 'Second copyright line should be "Released under Apache 2.0 license as described in the file LICENSE."' +-/ +#guard_msgs in +#check_copyright +"/- +Copyright (c) 2024 Damiano Testa + and many other authors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Name LastName + and others. +-/ +" diff --git a/test/LibrarySearch/IsCompact.lean b/test/LibrarySearch/IsCompact.lean index 0428a0cc91ba1..0ac0af98ca6a4 100644 --- a/test/LibrarySearch/IsCompact.lean +++ b/test/LibrarySearch/IsCompact.lean @@ -1,5 +1,5 @@ import Mathlib.Topology.Instances.Real -import Mathlib.Topology.Algebra.Order.Compact +import Mathlib.Topology.Order.Compact -- TODO: uses sorry, but is hidden behind the `apply?` /-- warning: declaration uses 'sorry' -/ diff --git a/test/Lint.lean b/test/Lint.lean index 25bf9c9147d13..696ed83bf3054 100644 --- a/test/Lint.lean +++ b/test/Lint.lean @@ -7,6 +7,23 @@ import Mathlib.Order.SetNotation set_option linter.dupNamespace false +namespace termG +-- this creates a hygienic declaration starting with `termG.termG.«_@».test.Lint...` +-- and the linter ignores it +set_option linter.dupNamespace true in +local notation "G" => Unit + +/-- info: [termG, termG] -/ +#guard_msgs in +open Lean in +run_meta + let env ← getEnv + let consts := env.constants.toList.find? (·.1.getRoot == `termG) + let reps := (consts.map (·.1.components.take 2)).getD default + logInfo m!"{reps}" + guard (reps[0]! == reps[1]!) +end termG + /-- warning: The namespace 'add' is duplicated in the declaration 'add.add' note: this linter can be disabled with `set_option linter.dupNamespace false` @@ -25,8 +42,12 @@ note: this linter can be disabled with `set_option linter.dupNamespace false` set_option linter.dupNamespace true in def Foo.foo := True --- the `dupNamespace` linter does not notice that `to_additive` created `Foo.add.add`. +/-- +warning: The namespace 'add' is duplicated in the declaration 'Foo.add.add' +note: this linter can be disabled with `set_option linter.dupNamespace false` +-/ #guard_msgs in +set_option linter.dupNamespace true in @[to_additive] theorem add.mul : True := .intro -- However, the declaration `Foo.add.add` is present in the environment. @@ -52,10 +73,13 @@ namespace add /-- warning: The namespace 'add' is duplicated in the declaration 'add.add' note: this linter can be disabled with `set_option linter.dupNamespace false` +--- +warning: The namespace 'add' is duplicated in the declaration 'add.add' +note: this linter can be disabled with `set_option linter.dupNamespace false` -/ #guard_msgs in set_option linter.dupNamespace true in -export Nat (add) +export Nat (add add_comm add) end add @@ -288,7 +312,7 @@ info: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, info: " \" " : String --- warning: This line exceeds the 100 character limit, please shorten it! -You can use "string gaps" to format long strings: within a string quotation, using a '' at the end of a line allows you to continue the string on the following line, removing all intervening whitespace. +You can use "string gaps" to format long strings: within a string quotation, using a '\' at the end of a line allows you to continue the string on the following line, removing all intervening whitespace. note: this linter can be disabled with `set_option linter.style.longLine false` -/ #guard_msgs in diff --git a/test/LongFile.lean b/test/LongFile.lean index faec16c404806..635f2ab485c30 100644 --- a/test/LongFile.lean +++ b/test/LongFile.lean @@ -5,7 +5,8 @@ import Mathlib.Tactic.Linter.Lint Things to note: * `set_option linter.style.longFile 0` disables the linter, allowing us to set a value smaller than - `1500` without triggering the warning for setting a small value for the option; + `linter.style.longFileDefValue` without triggering the warning for setting a small value + for the option; * `guard_msgs ... in #exit` and `set_option ... in #exit` allow processing of the file *beyond* `#exit`, since they wrap `#exit` inside an anonymous section, making Lean active again *after* that anonymous section. @@ -20,49 +21,106 @@ The current value of 1500 does not exceed the allowed bound. Please, remove the `set_option linter.style.longFile 1500`. -/ #guard_msgs in --- Do not allow setting a "small" `longFile` linter option +-- Do not allow setting a `longFile` linter option if the file does not exceed the `defValue` set_option linter.style.longFile 1500 /-- warning: using 'exit' to interrupt Lean --- -warning: The default value of the `longFile` linter is 1500. -This file is 36 lines long which does not exceed the allowed bound. -Please, remove the `set_option linter.style.longFile 1600`. +warning: The default value of the `longFile` linter is 50. +This file is 38 lines long which does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 60`. -/ #guard_msgs in -- Do not allow unnecessarily increasing the `longFile` linter option -set_option linter.style.longFile 1600 in +set_option linter.style.longFileDefValue 50 in +set_option linter.style.longFile 60 in #exit /-- warning: using 'exit' to interrupt Lean --- -warning: This file is 51 lines long, but the limit is 10. +warning: This file is 52 lines long, but the limit is 20. -You can extend the allowed length of the file using `set_option linter.style.longFile 1500`. +You can extend the allowed length of the file using `set_option linter.style.longFile 200`. You can completely disable this linter by setting the length limit to `0`. -/ #guard_msgs in --- First, we silence the linter, so that we can set a default value smaller than 1500. -set_option linter.style.longFile 0 in --- Next, we test that the `longFile` linter warns when a file exceeds the allowed value. -set_option linter.style.longFile 10 in +-- We test that the `longFile` linter warns when a file exceeds the allowed value. +set_option linter.style.longFileDefValue 10 in +set_option linter.style.longFile 20 in +#exit + +/-- warning: using 'exit' to interrupt Lean -/ +#guard_msgs in +-- Check that the `candidate` value is allowed +set_option linter.style.longFileDefValue 10 in +set_option linter.style.longFile 200 in +#exit + +/-- warning: using 'exit' to interrupt Lean -/ +#guard_msgs in +-- Check that the `candidate - 100` value is allowed +set_option linter.style.longFileDefValue 10 in +set_option linter.style.longFile 100 in #exit /-- warning: using 'exit' to interrupt Lean --- -warning: The default value of the `longFile` linter is 1500. -This file is 66 lines long which does not exceed the allowed bound. -Please, remove the `set_option linter.style.longFile 1700`. +warning: This file is 78 lines long. The current limit is 101, but it is expected to be 200: +`set_option linter.style.longFile 200`. -/ #guard_msgs in --- First, we silence the linter, so that we can set a default value smaller than 1500. -set_option linter.style.longFile 0 in --- If we set the allowed bound for the `longFile` linter that is too large, --- the linter tells us to use a smaller bound. -set_option linter.style.longFile 1700 in +-- Check that a value different from `candidate` or `candidate - 100` value is not allowed +set_option linter.style.longFileDefValue 10 in +set_option linter.style.longFile 101 in #exit +-- The following test is a little artificial: it follows a path in the code that should only +-- be accessible after modifying the linter options appropriately. +-- Specifically, in the line `if lastLine ≤ defValue && defValue < linterBound then`, the failure +-- of *only* the second condition would produce the error message below +set_option linter.style.longFileDefValue 400 +set_option linter.style.longFile 500 +set_option linter.style.longFileDefValue 1000 +/-- +warning: using 'exit' to interrupt Lean +--- +warning: This file is 94 lines long. The current limit is 500, but it is expected to be 1000: +`set_option linter.style.longFile 1000`. +-/ +#guard_msgs in +#exit +/- +warning: using 'exit' to interrupt Lean +--- +warning: The default value of the `longFile` linter is 1000. +This file is 95 lines long which does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 500`. +-/ + +set_option linter.style.longFileDefValue 2000 +/-- +warning: The default value of the `longFile` linter is 2000. +The current value of 1999 does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 1999`. +-/ +#guard_msgs in +-- Do not allow setting a `longFile` linter option if the file does not exceed the `defValue` +set_option linter.style.longFile 1999 + end longFile + +set_option linter.style.longFileDefValue 400 + +/-- +warning: using 'exit' to interrupt Lean +--- +warning: The default value of the `longFile` linter is 400. +This file is 126 lines long which does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 5000`. +-/ +#guard_msgs in +set_option linter.style.longFile 5000 in +#exit diff --git a/test/MfldSetTac.lean b/test/MfldSetTac.lean index fd50fd05c2ca3..ad921934de097 100644 --- a/test/MfldSetTac.lean +++ b/test/MfldSetTac.lean @@ -47,7 +47,7 @@ test_sorry (e.toPartialEquiv.symm : β → α) = (e.symm : β → α) := test_sorry -structure ModelWithCorners (𝕜 E H : Type u) extends PartialEquiv H E := +structure ModelWithCorners (𝕜 E H : Type u) extends PartialEquiv H E where (source_eq : source = Set.univ) attribute [mfld_simps] ModelWithCorners.source_eq diff --git a/test/MinImports.lean b/test/MinImports.lean index abf1594c8f565..617d3e8807127 100644 --- a/test/MinImports.lean +++ b/test/MinImports.lean @@ -74,9 +74,14 @@ import Mathlib.Data.Nat.Notation #min_imports in lemma hi (n : ℕ) : n = n := by extract_goal; rfl +set_option linter.minImports.increases false +set_option linter.minImports true /-- warning: Imports increased to [Init.Guard, Mathlib.Data.Int.Notation] + +New imports: [Init.Guard, Mathlib.Data.Int.Notation] + note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in @@ -94,6 +99,9 @@ set_option linter.minImports false in /-- warning: Imports increased to [Init.Guard, Mathlib.Data.Int.Notation] + +New imports: [Init.Guard, Mathlib.Data.Int.Notation] + note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in @@ -109,6 +117,9 @@ set_option linter.minImports true /-- warning: Imports increased to [Mathlib.Tactic.Linter.MinImports] + +New imports: [Mathlib.Tactic.Linter.MinImports] + note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in @@ -117,6 +128,11 @@ note: this linter can be disabled with `set_option linter.minImports false` /-- warning: Imports increased to [Mathlib.Tactic.FunProp.Attr, Mathlib.Tactic.NormNum.Basic] + +New imports: [Mathlib.Tactic.FunProp.Attr, Mathlib.Tactic.NormNum.Basic] + +Now redundant: [Mathlib.Tactic.Linter.MinImports] + note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in diff --git a/test/MkIffOfInductive.lean b/test/MkIffOfInductive.lean index e2c50aa66a11b..340beef419ff7 100644 --- a/test/MkIffOfInductive.lean +++ b/test/MkIffOfInductive.lean @@ -1,5 +1,5 @@ import Mathlib.Tactic.MkIffOfInductiveProp -import Mathlib.Data.List.Perm +import Mathlib.Data.List.Perm.Lattice mk_iff_of_inductive_prop List.Chain test.chain_iff example {α : Type _} (R : α → α → Prop) (a : α) (al : List α) : diff --git a/test/Multigoal.lean b/test/Multigoal.lean new file mode 100644 index 0000000000000..e43848c0295dc --- /dev/null +++ b/test/Multigoal.lean @@ -0,0 +1,131 @@ +import Mathlib.Tactic.Basic +import Mathlib.Tactic.Conv +import Mathlib.Tactic.Linter.Multigoal +import Mathlib.Util.SleepHeartbeats +import Mathlib.Tactic.SuccessIfFailWithMsg + +-- The warning generated by `linter.style.multiGoal` is not suppressed by `#guard_msgs`, +-- because the linter is run on `#guard_msgs` itself. This is a known issue, see e.g. +-- https://leanprover.zulipchat.com/#narrow/stream/348111-batteries/topic/unreachableTactic.20linter.20not.20suppressed.20by.20.60.23guard_msgs.60 +-- We jump through an extra hoop here to silence the warning. +set_option linter.style.multiGoal false + +-- A deactivated linter does nothing. +example : True := by + by_cases 0 = 0 + exact .intro + exact .intro + +#guard_msgs(drop warning) in +set_option linter.style.multiGoal true in +/-- +warning: There are 2 unclosed goals before 'exact .intro' and at least one remaining goal afterwards. +Please focus on the current goal, for instance using `·` (typed as "\."). +note: this linter can be disabled with `set_option linter.style.multiGoal false` +-/ +#guard_msgs in +example : True := by + by_cases 0 = 0 + exact .intro + exact .intro + +#guard_msgs(drop warning) in +set_option linter.style.multiGoal true in +/-- +warning: There are 2 unclosed goals before 'assumption' and at least one remaining goal afterwards. +Please focus on the current goal, for instance using `·` (typed as "\."). +note: this linter can be disabled with `set_option linter.style.multiGoal false` +-/ +#guard_msgs in +example {n : Nat} (hn : n = 0) : n + 0 = 0 := by + conv => + congr + rw [← Nat.add_zero 0] + conv_lhs => + congr + rw [← Nat.add_zero n] + rfl + conv_rhs => + rw [← Nat.add_zero 0] + congr + rfl + rfl + by_cases 0 = 0 + assumption + assumption + +set_option linter.unusedTactic false in +#guard_msgs(drop warning) in +set_option linter.style.multiGoal true in +/-- +warning: There are 2 unclosed goals before 'rfl' and at least one remaining goal afterwards. +Please focus on the current goal, for instance using `·` (typed as "\."). +note: this linter can be disabled with `set_option linter.style.multiGoal false` +-/ +#guard_msgs in +example (p : Prop) (hp : p) : (0 = 0 ∧ p) ∨ 0 = 0 := by + iterate left; decide + repeat' left; decide + refine Or.inl ⟨?_, ?_⟩ + rfl + assumption + +#guard_msgs(drop warning) in +set_option linter.style.multiGoal true in +/-- +warning: There are 3 unclosed goals before 'rfl' and at least one remaining goal afterwards. +Please focus on the current goal, for instance using `·` (typed as "\."). +note: this linter can be disabled with `set_option linter.style.multiGoal false` +--- +warning: There are 2 unclosed goals before 'trivial' and at least one remaining goal afterwards. +Please focus on the current goal, for instance using `·` (typed as "\."). +note: this linter can be disabled with `set_option linter.style.multiGoal false` +-/ +#guard_msgs in +example : 0 = 0 ∧ 0 = 0 ∧ 0 = 0 := by + refine ⟨?_, ?_, ?_⟩ + rfl + trivial + rfl + +example (p : Bool) : 0 = 0 := by + cases p + case' false => rfl + case' true => rfl + +#guard_msgs in +-- `assumption'` is allowed, as it is useful precisely when there are multiple active goals. +example (p : Bool) (f : False) {h : 0 = 0} : 0 = 0 ∧ 0 = 1 := by + cases p <;> + constructor + assumption' + any_goals cases f + +#guard_msgs in +-- `focus` is ignored. +example : True ∧ True := by + constructor + focus + exact .intro + focus + exact .intro + +set_option linter.unusedTactic false in +example : 1 = 1 := by + sleep_heartbeats 1000 + rfl + +-- We test that a tactic closing all remaining goals does not trigger the linter. +macro "bi_trivial" : tactic => `(tactic| (trivial; trivial)) + +set_option linter.style.multiGoal true in +example : True ∧ True := by + constructor + bi_trivial + +-- Exclude `fail_if_success` and `success_if_fail_with_msg` from linting. +set_option linter.style.multiGoal true in +example : True := by + fail_if_success done + success_if_fail_with_msg "internal exception #4" done + exact .intro diff --git a/test/NthRewrite.lean b/test/NthRewrite.lean index 608d18fdb6bf8..287039007dce6 100644 --- a/test/NthRewrite.lean +++ b/test/NthRewrite.lean @@ -14,7 +14,7 @@ example [AddZeroClass G] {a : G} (h : a = a): a = (a + 0) := by example [AddZeroClass G] {a : G} : a + a = a + (a + 0) := by nth_rw 2 [← add_zero a] -structure F := +structure F where (a : ℕ) (v : Vector ℕ a) (p : v.val = []) @@ -22,7 +22,7 @@ structure F := example (f : F) : f.v.val = [] := by nth_rw 1 [f.p] -structure Cat := +structure Cat where (O : Type) (H : O → O → Type) (i : (o : O) → H o o) diff --git a/test/PPRoundtrip.lean b/test/PPRoundtrip.lean new file mode 100644 index 0000000000000..752a26277923b --- /dev/null +++ b/test/PPRoundtrip.lean @@ -0,0 +1,66 @@ +import Mathlib.Tactic.Linter.PPRoundtrip + +/-- +info: "a a" +--- +warning: source context +'al " a ' +'al " a a\n' +pretty-printed context +note: this linter can be disabled with `set_option linter.ppRoundtrip false` +-/ +#guard_msgs in +set_option linter.ppRoundtrip true in +#eval " a a\n " |>.trim + +/-- +warning: source context +'rd ¬ fa' +'rd ¬false' +pretty-printed context +note: this linter can be disabled with `set_option linter.ppRoundtrip false` +-/ +#guard_msgs in +set_option linter.ppRoundtrip true in +#guard ¬ false + +/-- +warning: source context +'le {a: Nat' +'le {a : Na' +pretty-printed context +note: this linter can be disabled with `set_option linter.ppRoundtrip false` +-/ +#guard_msgs in +set_option linter.ppRoundtrip true in +variable {a: Nat} + +/-- +warning: source context +' {a :Nat}' +' {a : Nat}' +pretty-printed context +note: this linter can be disabled with `set_option linter.ppRoundtrip false` +-/ +#guard_msgs in +set_option linter.ppRoundtrip true in +variable {a :Nat} + +/-- +info: (fun x1 x2 => x1 + x2) 0 1 : Nat +--- +warning: source context +'k (·+·) ' +'k (· + ·' +pretty-printed context +note: this linter can be disabled with `set_option linter.ppRoundtrip false` +-/ +#guard_msgs in +set_option linter.ppRoundtrip true in +#check (·+·) 0 1 + +#guard_msgs in +set_option linter.ppRoundtrip true in +-- check that trailing comments do not trigger the linter +example : 0 = 0 := by + rw [] -- this goal is closed by the `rfl` implied by `rw` diff --git a/test/Simps.lean b/test/Simps.lean index 4fb569642e899..cb6c499476837 100644 --- a/test/Simps.lean +++ b/test/Simps.lean @@ -91,7 +91,7 @@ initialize_simps_projections Something universe v u w -structure Equiv' (α : Sort _) (β : Sort _) := +structure Equiv' (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) (left_inv : invFun.LeftInverse toFun) @@ -101,7 +101,7 @@ infix:25 (priority := default+1) " ≃ " => Equiv' /- Since `prod` and `PProd` are a special case for `@[simps]`, we define a new structure to test the basic functionality.-/ -structure MyProd (α β : Type _) := (fst : α) (snd : β) +structure MyProd (α β : Type _) where (fst : α) (snd : β) def MyProd.map {α α' β β'} (f : α → α') (g : β → β') (x : MyProd α β) : MyProd α' β' := ⟨f x.1, g x.2⟩ @@ -262,7 +262,7 @@ run_cmd liftTermElabM <| do guard <| env.find? `rflWithData'_toEquiv_toFun |>.isNone guard <| env.find? `test_sneaky_extra |>.isNone -structure PartiallyAppliedStr := +structure PartiallyAppliedStr where (data : ℕ → MyProd ℕ ℕ) /- if we have a partially applied constructor, we treat it as if it were eta-expanded -/ @@ -279,7 +279,7 @@ run_cmd liftTermElabM <| do guard <| simpsAttr.getParam? env `partially_applied_term == #[`partially_applied_term_data_fst, `partially_applied_term_data_snd] -structure VeryPartiallyAppliedStr := +structure VeryPartiallyAppliedStr where (data : ∀β, ℕ → β → MyProd ℕ β) /- if we have a partially applied constructor, we treat it as if it were eta-expanded. @@ -424,12 +424,12 @@ run_cmd liftTermElabM <| do guard <| env.find? `pprodEquivProd22_invFun_snd |>.isSome /- Tests with universe levels -/ -class has_hom (obj : Type u) : Type (max u (v+1)) := +class has_hom (obj : Type u) : Type (max u (v+1)) where (hom : obj → obj → Type v) infixr:10 " ⟶ " => has_hom.hom -- type as \h -class CategoryStruct (obj : Type u) extends has_hom.{v} obj : Type (max u (v+1)) := +class CategoryStruct (obj : Type u) extends has_hom.{v} obj : Type (max u (v+1)) where (id : ∀ X : obj, hom X X) (comp : ∀ {X Y Z : obj}, (X ⟶ Y) → (Y ⟶ Z) → (X ⟶ Z)) @@ -450,7 +450,7 @@ example (X Y Z : Type u) (f : X ⟶ Y) (g : Y ⟶ Z) {k : X → Z} (h : ∀ x, g namespace coercing -structure FooStr := +structure FooStr where (c : Type) (x : c) @@ -462,7 +462,7 @@ instance : CoeSort FooStr Type := ⟨FooStr.c⟩ example {x : Type} (h : ℕ = x) : foo = x := by simp only [foo_c]; rw [h] example {x : ℕ} (h : (3 : ℕ) = x) : foo.x = x := by simp only [foo_x]; rw [h] -structure VooStr (n : ℕ) := +structure VooStr (n : ℕ) where (c : Type) (x : c) @@ -474,7 +474,7 @@ instance (n : ℕ) : CoeSort (VooStr n) Type := ⟨VooStr.c⟩ example {x : Type} (h : ℕ = x) : voo = x := by simp only [voo_c]; rw [h] example {x : ℕ} (h : (3 : ℕ) = x) : voo.x = x := by simp only [voo_x]; rw [h] -structure Equiv2 (α : Sort _) (β : Sort _) := +structure Equiv2 (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) (left_inv : invFun.LeftInverse toFun) @@ -515,7 +515,7 @@ class Semigroup (G : Type u) extends Mul G where example {α β} [Semigroup α] [Semigroup β] (x y : α × β) : x * y = (x.1 * y.1, x.2 * y.2) := by simp example {α β} [Semigroup α] [Semigroup β] (x y : α × β) : (x * y).1 = x.1 * y.1 := by simp -structure BSemigroup := +structure BSemigroup where (G : Type _) (op : G → G → G) -- (infix:60 " * " => op) -- this seems to be removed @@ -535,8 +535,8 @@ protected def prod (G H : BSemigroup) : BSemigroup := end BSemigroup -class ExtendingStuff (G : Type u) extends Mul G, Zero G, Neg G, HasSubset G := - (new_axiom : ∀ x : G, x * - 0 ⊆ - x) +class ExtendingStuff (G : Type u) extends Mul G, Zero G, Neg G, HasSubset G where + new_axiom : ∀ x : G, x * - 0 ⊆ - x @[simps] def bar : ExtendingStuff ℕ := { mul := (·*·) @@ -550,8 +550,8 @@ attribute [local instance] bar example (x : ℕ) : x * - 0 ⊆ - x := by simp end -class new_ExtendingStuff (G : Type u) extends Mul G, Zero G, Neg G, HasSubset G := - (new_axiom : ∀ x : G, x * - 0 ⊆ - x) +class new_ExtendingStuff (G : Type u) extends Mul G, Zero G, Neg G, HasSubset G where + new_axiom : ∀ x : G, x * - 0 ⊆ - x @[simps] def new_bar : new_ExtendingStuff ℕ := { mul := (·*·) @@ -570,7 +570,7 @@ end coercing namespace ManualCoercion -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -598,7 +598,7 @@ end ManualCoercion namespace FaultyManualCoercion -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -622,7 +622,7 @@ namespace ManualInitialize /- defining a manual coercion. -/ variable {α β γ : Sort _} -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -654,7 +654,7 @@ namespace FaultyUniverses variable {α β γ : Sort _} -structure Equiv (α : Sort u) (β : Sort v) := +structure Equiv (α : Sort u) (β : Sort v) where (toFun : α → β) (invFun : β → α) @@ -683,7 +683,7 @@ namespace ManualUniverses variable {α β γ : Sort _} -structure Equiv (α : Sort u) (β : Sort v) := +structure Equiv (α : Sort u) (β : Sort v) where (toFun : α → β) (invFun : β → α) @@ -704,7 +704,7 @@ end ManualUniverses namespace ManualProjectionNames -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -744,7 +744,7 @@ end ManualProjectionNames namespace PrefixProjectionNames -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -791,7 +791,7 @@ end PrefixProjectionNames -- test transparency setting -structure SetPlus (α : Type) := +structure SetPlus (α : Type) where (s : Set α) (x : α) (h : x ∈ s) @@ -818,7 +818,7 @@ example {x : Set ℕ} (h : Set.univ = x) : Nat.SetPlus3.s = x := by namespace NestedNonFullyApplied -structure Equiv (α : Sort _) (β : Sort _) := +structure Equiv (α : Sort _) (β : Sort _) where (toFun : α → β) (invFun : β → α) @@ -854,19 +854,19 @@ example (e : α ≃ β) {x : β → α} (h : e.invFun = x) : (Equiv.symm2.invFun end NestedNonFullyApplied -- test that type classes which are props work -class PropClass (n : ℕ) : Prop := - (has_true : True) +class PropClass (n : ℕ) : Prop where + has_true : True instance has_PropClass (n : ℕ) : PropClass n := ⟨trivial⟩ -structure NeedsPropClass (n : ℕ) [PropClass n] := +structure NeedsPropClass (n : ℕ) [PropClass n] where (t : True) @[simps] def test_PropClass : NeedsPropClass 1 := { t := trivial } /- check that when the coercion is given in eta-expanded form, we can also find the coercion. -/ -structure AlgHom (R A B : Type _) := +structure AlgHom (R A B : Type _) where (toFun : A → B) instance (R A B : Type _) : CoeFun (AlgHom R A B) (fun _ ↦ A → B) := ⟨fun f ↦ f.toFun⟩ @@ -931,7 +931,7 @@ section attribute [local simp] Nat.add -structure MyType := +structure MyType where (A : Type) @[simps (config := {simpRhs := true})] def myTypeDef : MyType := @@ -972,7 +972,7 @@ instance {α β} : CoeFun (α ≃ β) (fun _ ↦ α → β) := ⟨Equiv'.toFun @[simps] protected def Equiv'.symm {α β} (f : α ≃ β) : β ≃ α := ⟨f.invFun, f, f.right_inv, f.left_inv⟩ -structure DecoratedEquiv (α : Sort _) (β : Sort _) extends Equiv' α β := +structure DecoratedEquiv (α : Sort _) (β : Sort _) extends Equiv' α β where (P_toFun : Function.Injective toFun ) (P_invFun : Function.Injective invFun) @@ -1022,7 +1022,7 @@ example {α : Type} (x z : α) (h : x = z) : foo2 α x = z := by guard_target = x = z rw [h] -structure FurtherDecoratedEquiv (α : Sort _) (β : Sort _) extends DecoratedEquiv α β := +structure FurtherDecoratedEquiv (α : Sort _) (β : Sort _) extends DecoratedEquiv α β where (Q_toFun : Function.Surjective toFun ) (Q_invFun : Function.Surjective invFun ) @@ -1097,11 +1097,11 @@ def fffoo2 (α : Type) : OneMore α α := fffoo α /- test the case where a projection takes additional arguments. -/ variable {ι : Type _} [DecidableEq ι] (A : ι → Type _) -structure ZeroHom (M N : Type _) [Zero M] [Zero N] := +structure ZeroHom (M N : Type _) [Zero M] [Zero N] where (toFun : M → N) (map_zero' : toFun 0 = 0) -structure AddHom (M N : Type _) [Add M] [Add N] := +structure AddHom (M N : Type _) [Add M] [Add N] where (toFun : M → N) (map_add' : ∀ x y, toFun (x + y) = toFun x + toFun y) @@ -1112,7 +1112,7 @@ infixr:25 " →+ " => AddMonoidHom instance (M N : Type _) [AddMonoid M] [AddMonoid N] : CoeFun (M →+ N) (fun _ ↦ M → N) := ⟨(·.toFun)⟩ -class AddHomPlus [Add ι] [∀ i, AddCommMonoid (A i)] := +class AddHomPlus [Add ι] [∀ i, AddCommMonoid (A i)] where (myMul {i} : A i →+ A i) def AddHomPlus.Simps.apply [Add ι] [∀ i, AddCommMonoid (A i)] [AddHomPlus A] {i : ι} (x : A i) : @@ -1121,7 +1121,7 @@ def AddHomPlus.Simps.apply [Add ι] [∀ i, AddCommMonoid (A i)] [AddHomPlus A] initialize_simps_projections AddHomPlus (myMul_toFun → apply, -myMul) -class AddHomPlus2 [Add ι] := +class AddHomPlus2 [Add ι] where (myMul {i j} : A i ≃ (A j ≃ A (i + j))) def AddHomPlus2.Simps.mul [Add ι] [AddHomPlus2 A] {i j : ι} (x : A i) (y : A j) : A (i + j) := @@ -1153,7 +1153,7 @@ end comp_projs section /-! Check that the tactic also works if the elaborated type of `type` reduces to `Sort _`, but is not `Sort _` itself. -/ -structure MyFunctor (C D : Type _) := +structure MyFunctor (C D : Type _) where (obj : C → D) local infixr:26 " ⥤ " => MyFunctor diff --git a/test/Traversable.lean b/test/Traversable.lean index 136433f0ae4ea..ae7c2e2279e61 100644 --- a/test/Traversable.lean +++ b/test/Traversable.lean @@ -34,7 +34,7 @@ inductive RecData (α : Type u) : Type u #guard_msgs (drop info) in #synth LawfulTraversable RecData -unsafe structure MetaStruct (α : Type u) : Type u := +unsafe structure MetaStruct (α : Type u) : Type u where x : α y : ℤ z : List α diff --git a/test/algebraize.lean b/test/algebraize.lean index 7cebc3123da0a..1ccd695d0b920 100644 --- a/test/algebraize.lean +++ b/test/algebraize.lean @@ -38,6 +38,26 @@ an example. -/ def RingHom.testProperty3 {A B : Type*} [CommRing A] [CommRing B] (f : A →+* B) : Prop := f.testProperty1 +/- Test property for when the `RingHom` (and `Algebra`) property have an extra explicit argument, +and hence needs to be created through a lemma. See e.g. +`Algebra.IsStandardSmoothOfRelativeDimension` for an example. -/ +class Algebra.testProperty4 (n : ℕ) (A B : Type*) [CommRing A] [CommRing B] [Algebra A B] : Prop where + out : ∀ m, n = m + +/- Test property for when the `RingHom` (and `Algebra`) property have an extra explicit argument, +and hence needs to be created through a lemma. See e.g. +`Algebra.IsStandardSmoothOfRelativeDimension` for an example. -/ +@[algebraize testProperty4.toAlgebra] +def RingHom.testProperty4 (n : ℕ) {A B : Type*} [CommRing A] [CommRing B] (_ : A →+* B) : Prop := + ∀ m, n = m + +lemma testProperty4.toAlgebra (n : ℕ) {A B : Type*} [CommRing A] [CommRing B] (f : A →+* B) + (hf : f.testProperty4 n) : + letI : Algebra A B := f.toAlgebra + Algebra.testProperty4 n A B := + letI : Algebra A B := f.toAlgebra + { out := hf } + end example_definitions set_option tactic.hygienic false @@ -50,6 +70,15 @@ example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) : True := by guard_hyp algInst := f.toAlgebra trivial +/-- Synthesize algebra instance from ring hom defined using a `let` statement. -/ +example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) : True := by + let f' : A →+* B := f + fail_if_success -- Check that this instance is not available by default + have h : Algebra A B := inferInstance + algebraize [f'] + guard_hyp algInst := f'.toAlgebra + trivial + /-- Synthesize algebra instance from a composition -/ example (A B C : Type*) [CommRing A] [CommRing B] [CommRing C] (f : A →+* B) (g : B →+* C) : True := by @@ -70,17 +99,23 @@ example (A B C : Type*) [CommRing A] [CommRing B] [CommRing C] (f : A →+* B) ( example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty1) : True := by algebraize [f] - guard_hyp algebraizeInst : Algebra.testProperty1 A B := hf + guard_hyp algebraizeInst : Algebra.testProperty1 A B trivial example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty2) : True := by algebraize [f] - guard_hyp algebraizeInst : Module.testProperty2 A B := hf + guard_hyp algebraizeInst : Module.testProperty2 A B trivial example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty3) : True := by algebraize [f] - guard_hyp algebraizeInst : Algebra.testProperty3 A B := ⟨hf⟩ + guard_hyp algebraizeInst : Algebra.testProperty3 A B + trivial + +example (n : ℕ) (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty4 n) : + True := by + algebraize [f] + guard_hyp algebraizeInst : Algebra.testProperty4 n A B trivial /-- Synthesize from morphism property of a composition (and check that tower is also synthesized). -/ @@ -91,6 +126,6 @@ example (A B C : Type*) [CommRing A] [CommRing B] [CommRing C] (f : A →+* B) ( fail_if_success have h : IsScalarTower A B C := inferInstance algebraize [f, g, g.comp f] - guard_hyp algebraizeInst : Algebra.testProperty1 A C := hfg + guard_hyp algebraizeInst : Algebra.testProperty1 A C guard_hyp scalarTowerInst := IsScalarTower.of_algebraMap_eq' rfl trivial diff --git a/test/antidiagonal.lean b/test/antidiagonal.lean index c3e22116f5fe7..ea8da80cfaae9 100644 --- a/test/antidiagonal.lean +++ b/test/antidiagonal.lean @@ -14,9 +14,9 @@ section -- `antidiagonalTuple` is faster than `finAntidiagonal` by a small constant factor /-- info: 23426 -/ -#guard_msgs in #eval (finAntidiagonal 4 50).card +#guard_msgs in #eval #(finAntidiagonal 4 50) /-- info: 23426 -/ -#guard_msgs in #eval (Finset.Nat.antidiagonalTuple 4 50).card +#guard_msgs in #eval #(Finset.Nat.antidiagonalTuple 4 50) end diff --git a/test/cancel_denoms.lean b/test/cancel_denoms.lean index b717b67f56ee2..4d1001ecbcd6e 100644 --- a/test/cancel_denoms.lean +++ b/test/cancel_denoms.lean @@ -1,3 +1,4 @@ +import Mathlib.Algebra.Order.Field.Rat import Mathlib.Tactic.CancelDenoms import Mathlib.Tactic.Ring diff --git a/test/dfinsupp_notation.lean b/test/dfinsupp_notation.lean index ed6511532b5f9..ea4d3815079ae 100644 --- a/test/dfinsupp_notation.lean +++ b/test/dfinsupp_notation.lean @@ -7,20 +7,41 @@ example : (fun₀ | 1 | 2 | 3 => 3 | 3 => 4 : Π₀ i, Fin (i + 10)) 1 = 3 := by example : (fun₀ | 1 | 2 | 3 => 3 | 3 => 4 : Π₀ i, Fin (i + 10)) 2 = 3 := by simp example : (fun₀ | 1 | 2 | 3 => 3 | 3 => 4 : Π₀ i, Fin (i + 10)) 3 = 4 := by simp +section Repr + +/-- info: fun₀ | 1 => 3 | 2 => 3 : Π₀ (i : ℕ), Fin (i + 10) -/ +#guard_msgs in +#check (fun₀ | 1 => 3 | 2 => 3 : Π₀ i, Fin (i + 10)) + +/-- info: fun₀ | 2 => 7 -/ +#guard_msgs in +#eval ((fun₀ | 1 => 3 | 2 => 3) + (fun₀ | 1 => -3 | 2 => 4) : Π₀ _, ℤ) + /-- -info: +info: fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 -/ #guard_msgs in -#eval show Lean.MetaM Unit from - guard <| - reprStr (fun₀ | 1 => 3 | 2 => 3 : Π₀ i, Fin (i + 10)) - = "fun₀ | 1 => 3 | 2 => 3" +#eval (fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 : Π₀ _ : List String, ℕ) + +end Repr +section PrettyPrinter /-- -info: +info: fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 : Π₀ (i : List String), ℕ -/ #guard_msgs in -#eval show Lean.MetaM Unit from - guard <| - reprStr ((fun₀ | 1 => 3 | 2 => 3) + (fun₀ | 1 => -3 | 2 => 4) : Π₀ _, ℤ) - = "fun₀ | 2 => 7" +#check (fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 : Π₀ _ : List String, ℕ) + +end PrettyPrinter diff --git a/test/eval_elab.lean b/test/eval_elab.lean index 7e929bdda3698..da0e2ae6197d7 100644 --- a/test/eval_elab.lean +++ b/test/eval_elab.lean @@ -4,7 +4,7 @@ import Mathlib.Data.Finset.Sort #guard_expr eval% 2^10 =ₛ 1024 -#guard_expr (eval% 2^10 : Int) =ₛ .ofNat 1024 +#guard_expr (eval% 2^10 : Int) =ₛ (1024 : Int) -- https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/How.20to.20simplify.20this.20proof.20without.20using.20a.20have.20statement.3F/near/422294189 section from_zulip diff --git a/test/finiteness.lean b/test/finiteness.lean new file mode 100644 index 0000000000000..550f78f74a365 --- /dev/null +++ b/test/finiteness.lean @@ -0,0 +1,26 @@ +import Mathlib.Tactic.Finiteness +import Mathlib.Data.ENNReal.Real +import Mathlib.MeasureTheory.Measure.Typeclasses + +open MeasureTheory +open scoped ENNReal + +example : (1 : ℝ≥0∞) < ∞ := by finiteness +example : (3 : ℝ≥0∞) ≠ ∞ := by finiteness + +example (a : ℝ) (b : ℕ) : ENNReal.ofReal a + b < ∞ := by finiteness + +example {a : ℝ≥0∞} (ha : a ≠ ∞) : a + 3 < ∞ := by finiteness +example {a : ℝ≥0∞} (ha : a < ∞) : a + 3 < ∞ := by finiteness +/-- +Test that `finiteness_nonterminal` makes progress but does not fail on not +closing the goal. +-/ +example {a : ℝ≥0∞} (ha : a = 0) : a + 3 < ∞ := by finiteness_nonterminal; simp [ha] + +example (a : ℝ) : (ENNReal.ofReal (1 + a ^ 2))⁻¹ < ∞ := by finiteness + +example {α : Type*} (f : α → ℕ) : ∀ i, (f i : ℝ≥0∞) ≠ ∞ := by finiteness + +example {_ : MeasurableSpace α} (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ s ≠ ∞ := by + finiteness diff --git a/test/finsupp_notation.lean b/test/finsupp_notation.lean index e042b67a8903f..08e871dde99cb 100644 --- a/test/finsupp_notation.lean +++ b/test/finsupp_notation.lean @@ -12,14 +12,48 @@ example : (fun₀ | 1 | 2 | 3 => 3 | 3 => 4) 2 = 3 := by example : (fun₀ | 1 | 2 | 3 => 3 | 3 => 4) 3 = 4 := by simp +section repr + +/-- info: fun₀ | 1 => 3 | 2 => 3 -/ +#guard_msgs in +#eval (Finsupp.mk {1, 2} (fun | 1 | 2 => 3 | _ => 0) (fun x => by aesop)) + /-- -info: +info: fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 -/ #guard_msgs in -#eval show Lean.MetaM Unit from - guard <| - reprStr (Finsupp.mk {1, 2} (fun | 1 | 2 => 3 | _ => 0) (fun x => by aesop)) - = "fun₀ | 1 => 3 | 2 => 3" +#eval Finsupp.mk + {["there are five words here", "and five more words here"], + ["there are seven words but only here"], + ["just two"]} + (fun + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 + | _ => 0) + (fun x => by aesop) + +end repr + +section PrettyPrinter + +/-- +info: fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 : List String →₀ ℕ +-/ +#guard_msgs in +#check fun₀ + | ["there are five words here", "and five more words here"] => 5 + | ["there are seven words but only here"] => 7 + | ["just two"] => 2 + +end PrettyPrinter + /-! ## (computable) number theory examples -/ diff --git a/test/format_table.lean b/test/format_table.lean new file mode 100644 index 0000000000000..296df3992f7ec --- /dev/null +++ b/test/format_table.lean @@ -0,0 +1,17 @@ +import Mathlib.Util.FormatTable + +/-- +info: +| first | second header | third \| header | +| :-------------- | :-------------: | --------------: | +| item number one | item two | item c | +| the fourth item | the fourth item | escape \| this | +| align left | align center | align right | +-/ +#guard_msgs in +run_cmd Lean.logInfo ("\n" ++ formatTable + #["first", "second header", "third | header"] + #[#["item number one", "item two", "item c"], + #["the fourth item", "the fourth item", "escape | this"], + #["align left", "align center", "align right"]] + (.some #[.left, .center, .right])) diff --git a/test/instance_diamonds.lean b/test/instance_diamonds.lean index f26a6b719c7ff..8ced918dadd0d 100644 --- a/test/instance_diamonds.lean +++ b/test/instance_diamonds.lean @@ -153,7 +153,7 @@ example {k : Type _} [Semiring k] [Nontrivial k] : (Finsupp.comapSMul : SMul k (k →₀ k)) ≠ Finsupp.smulZeroClass.toSMul := by obtain ⟨u : k, hu⟩ := exists_ne (1 : k) intro h - simp only [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), Function.funext_iff, DFunLike.ext_iff] at h + simp only [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), funext_iff, DFunLike.ext_iff] at h replace h := h u (Finsupp.single 1 1) u classical rw [comapSMul_single, smul_apply, smul_eq_mul, mul_one, single_eq_same, smul_eq_mul, @@ -167,7 +167,7 @@ example {k : Type _} [Semiring k] [Nontrivial kˣ] : obtain ⟨u : kˣ, hu⟩ := exists_ne (1 : kˣ) haveI : Nontrivial k := ⟨⟨u, 1, Units.ext.ne hu⟩⟩ intro h - simp only [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), Function.funext_iff, DFunLike.ext_iff] at h + simp only [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), funext_iff, DFunLike.ext_iff] at h replace h := h u (Finsupp.single 1 1) u classical rw [comapSMul_single, smul_apply, Units.smul_def, smul_eq_mul, mul_one, single_eq_same, @@ -191,14 +191,14 @@ open Polynomial example [Semiring R] [Nontrivial R] : Polynomial.hasSMulPi _ _ ≠ (Pi.instSMul : SMul R[X] (R → R[X])) := by intro h - simp_rw [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), Function.funext_iff, Polynomial.ext_iff] at h + simp_rw [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), funext_iff, Polynomial.ext_iff] at h simpa using h X 1 1 0 /-- `Polynomial.hasSMulPi'` forms a diamond with `Pi.instSMul`. -/ example [CommSemiring R] [Nontrivial R] : Polynomial.hasSMulPi' _ _ _ ≠ (Pi.instSMul : SMul R[X] (R → R[X])) := by intro h - simp_rw [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), Function.funext_iff, Polynomial.ext_iff] at h + simp_rw [SMul.ext_iff, @SMul.smul_eq_hSMul _ _ (_), funext_iff, Polynomial.ext_iff] at h simpa using h X 1 1 0 -- fails `with_reducible_and_instances` #10906 diff --git a/test/instances/Ring_finiteness.lean b/test/instances/Ring_finiteness.lean new file mode 100644 index 0000000000000..89e9e0a99e860 --- /dev/null +++ b/test/instances/Ring_finiteness.lean @@ -0,0 +1,8 @@ +import Mathlib + +-- https://github.com/leanprover-community/mathlib4/pull/17557#issuecomment-2426920648 + +variable (R : Type*) [Ring R] [IsSemisimpleRing R] + +example : IsNoetherianRing R := inferInstance +example : IsArtinianRing R := inferInstance diff --git a/test/interactiveUnfold.lean b/test/interactiveUnfold.lean index 7972cf5866271..b17d3daa3cae8 100644 --- a/test/interactiveUnfold.lean +++ b/test/interactiveUnfold.lean @@ -57,7 +57,8 @@ info: Unfolds for 5 / 3: info: Unfolds for 1 + 1: · Ordinal.type (Sum.Lex EmptyRelation EmptyRelation) · ⟦{ α := PUnit.{u_1 + 1} ⊕ PUnit.{u_1 + 1}, r := Sum.Lex EmptyRelation EmptyRelation, wo := ⋯ }⟧ -· Quot.mk Setoid.r { α := PUnit.{u_1 + 1} ⊕ PUnit.{u_1 + 1}, r := Sum.Lex EmptyRelation EmptyRelation, wo := ⋯ } +· Quot.mk ⇑Ordinal.isEquivalent + { α := PUnit.{u_1 + 1} ⊕ PUnit.{u_1 + 1}, r := Sum.Lex EmptyRelation EmptyRelation, wo := ⋯ } -/ #guard_msgs in #unfold? (1 : Ordinal) + 1 diff --git a/test/linear_combination'.lean b/test/linear_combination'.lean index 14516504da879..36056748d622d 100644 --- a/test/linear_combination'.lean +++ b/test/linear_combination'.lean @@ -1,3 +1,4 @@ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Tactic.LinearCombination' import Mathlib.Tactic.Linarith diff --git a/test/linear_combination.lean b/test/linear_combination.lean index ac2eaed2036b2..6e8b23a79630f 100644 --- a/test/linear_combination.lean +++ b/test/linear_combination.lean @@ -1,3 +1,4 @@ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Tactic.LinearCombination import Mathlib.Tactic.Linarith @@ -229,6 +230,15 @@ example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y = -2 * y + 1 : /-! ### Cases that should fail -/ +/-- +error: ring failed, ring expressions not equal +a : ℤ +ha : a = 1 +⊢ -1 = 0 +-/ +#guard_msgs in +example (a : ℤ) (ha : a = 1) : a = 2 := by linear_combination ha + /-- error: ring failed, ring expressions not equal a : ℚ diff --git a/test/measurability.lean b/test/measurability.lean index 2ebf1a799ee68..d373a1d2d8576 100644 --- a/test/measurability.lean +++ b/test/measurability.lean @@ -82,7 +82,7 @@ example [Div β] [MeasurableDiv₂ β] (hf : Measurable f) (hg : Measurable g) example [AddCommMonoid β] [MeasurableAdd₂ β] {s : Finset ℕ} {F : ℕ → α → β} (hF : ∀ i, Measurable (F i)) : Measurable (∑ i ∈ s, (fun x => F (i+1) x + F i x)) := by - measurability + fun_prop example [AddCommMonoid β] [MeasurableAdd₂ β] {s : Finset ℕ} {F : ℕ → α → β} (hF : ∀ i, AEMeasurable (F i) μ) : AEMeasurable (∑ i ∈ s, (fun x => F (i+1) x + F i x)) μ := by diff --git a/test/module.lean b/test/module.lean index ee59dd02d0d9f..b3ec8f57b5789 100644 --- a/test/module.lean +++ b/test/module.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.LinearCombination import Mathlib.Tactic.Module diff --git a/test/norm_num_ext.lean b/test/norm_num_ext.lean index 4db23b8b748f9..d8ac0c6ac34e3 100644 --- a/test/norm_num_ext.lean +++ b/test/norm_num_ext.lean @@ -11,6 +11,7 @@ import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.NatSqrt import Mathlib.Tactic.NormNum.Prime import Mathlib.Tactic.NormNum.LegendreSymbol +import Mathlib.Tactic.NormNum.Pow /-! # Tests for `norm_num` extensions diff --git a/test/observe.lean b/test/observe.lean index 9a2b83728aaca..b595d01117739 100644 --- a/test/observe.lean +++ b/test/observe.lean @@ -1,4 +1,4 @@ -import Mathlib.Data.Nat.Prime.Basic +import Mathlib.Data.Nat.Prime.Factorial import Mathlib.Data.Nat.Factorial.Basic open Nat diff --git a/test/positivity.lean b/test/positivity.lean index fc773c8abd962..86a775d0e246c 100644 --- a/test/positivity.lean +++ b/test/positivity.lean @@ -4,6 +4,7 @@ import Mathlib.Analysis.Normed.Group.Basic import Mathlib.Analysis.SpecialFunctions.Pow.Real import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.MeasureTheory.Integral.Bochner +import Mathlib.Tactic.Positivity.Finset /-! # Tests for the `positivity` tactic @@ -289,8 +290,8 @@ example (n : ℕ+) : 0 < (↑n : ℕ) := by positivity example (n : ℕ) : 0 < n ! := by positivity example (n k : ℕ) : 0 < (n+1).ascFactorial k := by positivity --- example {α : Type _} (s : Finset α) (hs : s.Nonempty) : 0 < s.card := by positivity --- example {α : Type _} [Fintype α] [Nonempty α] : 0 < Fintype.card α := by positivity +example {α : Type _} (s : Finset α) (hs : s.Nonempty) : 0 < #s := by positivity +example {α : Type _} [Fintype α] [Nonempty α] : 0 < Fintype.card α := by positivity example {r : ℝ} : 0 < Real.exp r := by positivity diff --git a/test/reduce_mod_char.lean b/test/reduce_mod_char.lean index 597a56853552e..4180cc0fd347e 100644 --- a/test/reduce_mod_char.lean +++ b/test/reduce_mod_char.lean @@ -29,6 +29,46 @@ example : (X ^ 2 - 3 : (ZMod 4)[X]) = X ^ 2 + 1 := by reduce_mod_char -- Cleaning up `1 * X` and `X + 0`: example : (5 * X ^ 2 - 3 * X + 4 : (ZMod 4)[X]) = X ^ 2 + X := by reduce_mod_char +-- Exponentiation: +example : (11 : ZMod 987654319) ^ 987654318 = 1 := by reduce_mod_char +example : (-126432 : ZMod 1235412223) ^ 12355342321 = 1001528716 := by reduce_mod_char +example : (((((5 : ZMod 1235412223) ^ 5) ^ 5) ^ 5) ^ 5) ^ 5 = 806432269 := by reduce_mod_char +example : (2 : ZMod 75) ^ 0 = 1 := by reduce_mod_char +example : (0 : ZMod 34523432) ^ 0 = 1 := by reduce_mod_char +example : (0 : ZMod 56) ^ 90000000000000000 = 0 := by reduce_mod_char +example : (1 : ZMod 119) ^ 433440000000000000000000 = 1 := by reduce_mod_char +example : (75 : ZMod 111) ^ 1 = 75 := by reduce_mod_char +example : (23 : ZMod 19) ^ 1 = 4 := by reduce_mod_char +example : (1923423451 : ZMod 2) ^ 81000000000000000000 = 1 := by reduce_mod_char +example : (19 : ZMod 1) ^ 810000000000000000000 = 0 := by reduce_mod_char +example : (23423432049230423 : ZMod 0) ^ 0 = 1 := by reduce_mod_char +example : (23423432049230423 : ZMod 1) ^ 0 = 0 := by reduce_mod_char + +-- A 1024-bit prime number +set_option linter.style.longLine false in +abbrev p : Nat := 0xb10b8f96a080e01dde92de5eae5d54ec52c99fbcfb06a3c69a6a9dca52d23b616073e28675a23d189838ef1e2ee652c013ecb4aea906112324975c3cd49b83bfaccbdd7d90c4bd7098488e9c219a73724effd6fae5644738faa31a4ff55bccc0a151af5f0dc8b4bd45bf37df365c1a65e68cfda76d4da708df1fb2bc2e4a4371 + +set_option linter.style.longLine false in +abbrev g : Nat := 0xa4d1cbd5c3fd34126765a442efb99905f8104dd258ac507fd6406cff14266d31266fea1e5c41564b777e690f5504f213160217b4b01b886a5e91547f9e2749f4d7fbd7d3b9a92ee1909d0d2263f80a76a6a24c087a091f531dbf0a0169b6a28ad662a4d18e73afa32d779d5918d08bc8858f4dcef97c2a24855e6eeb22b3b2e5 + +example : (g : ZMod p) ^ (p - 1) = 1 := by reduce_mod_char + +-- The 20th Mersenne prime +abbrev q : Nat := 2 ^ 4423 - 1 + +-- This takes a little time but the 21st Mersenne prime is too large +set_option exponentiation.threshold 10000 in +example : (3 : ZMod q) ^ (q - 1) = 1 := by reduce_mod_char + +-- We don't unfold semi-reducible definitions +def q' := 2 +/-- +error: unsolved goals +⊢ 3 ^ (q' - 1) = 1 +-/ +#guard_msgs in +example : (3 : ZMod q') ^ (q' - 1) = 1 := by reduce_mod_char + -- Rewriting hypotheses: example (a : ZMod 7) (h : a + 7 = 2) : a = 2 := by reduce_mod_char at h diff --git a/test/renameBvar.lean b/test/renameBvar.lean new file mode 100644 index 0000000000000..07fe22319cebf --- /dev/null +++ b/test/renameBvar.lean @@ -0,0 +1,34 @@ +import Mathlib.Tactic.RenameBVar + +/- This test is somewhat flaky since it depends on the pretty printer. -/ +/-- +info: ℕ : Sort u_1 +P : ℕ → ℕ → Prop +h : ∀ (n : ℕ), ∃ m, P n m +⊢ ∀ (l : ℕ), ∃ m, P l m +--- +info: ℕ : Sort u_1 +P : ℕ → ℕ → Prop +h : ∀ (q : ℕ), ∃ m, P q m +⊢ ∀ (l : ℕ), ∃ m, P l m +--- +info: ℕ : Sort u_1 +P : ℕ → ℕ → Prop +h : ∀ (q : ℕ), ∃ m, P q m +⊢ ∀ (l : ℕ), ∃ n, P l n +--- +info: ℕ : Sort u_1 +P : ℕ → ℕ → Prop +h : ∀ (q : ℕ), ∃ m, P q m +⊢ ∀ (m : ℕ), ∃ n, P m n +-/ +#guard_msgs in +example (P : ℕ → ℕ → Prop) (h : ∀ n, ∃ m, P n m) : ∀ l, ∃ m, P l m := by + trace_state + rename_bvar n → q at h + trace_state + rename_bvar m → n + trace_state + rename_bvar l → m + trace_state + exact h diff --git a/test/rewrites.lean b/test/rewrites.lean index bbd4e2eef294f..2b4fe6758c081 100644 --- a/test/rewrites.lean +++ b/test/rewrites.lean @@ -1,6 +1,6 @@ import Mathlib.Data.Nat.Prime.Defs import Mathlib.CategoryTheory.Category.Basic -import Mathlib.Data.List.InsertNth +import Mathlib.Data.List.InsertIdx import Mathlib.Algebra.Group.Basic -- This is partially duplicative with the tests for `rw?` in Lean. diff --git a/test/ring.lean b/test/ring.lean index 5abd490bfa500..ffdfe755e4dec 100644 --- a/test/ring.lean +++ b/test/ring.lean @@ -1,3 +1,4 @@ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.Ring diff --git a/test/ring_compare.lean b/test/ring_compare.lean new file mode 100644 index 0000000000000..3e282d9fbfe30 --- /dev/null +++ b/test/ring_compare.lean @@ -0,0 +1,114 @@ +import Mathlib.Tactic.NormNum.OfScientific +import Mathlib.Tactic.Ring.Compare +import Mathlib.Tactic.Ring.RingNF + +open Lean Elab Tactic + +elab "ring_le" : tactic => liftMetaFinishingTactic Mathlib.Tactic.Ring.proveLE +elab "ring_lt" : tactic => liftMetaFinishingTactic Mathlib.Tactic.Ring.proveLT + +section Nat +variable {x y : ℕ} + +example : 3 ≤ (3:ℕ) := by ring_le +example : 1 ≤ (3:ℕ) := by ring_le +example : 0 ≤ (3:ℕ) + 1 := by ring_le +example : x ≤ x + 3 := by ring_le +example : x ≤ 1 + x := by ring_le +example : x + y + 1 ≤ y + x + 3 := by ring_le +example : x + y ≤ y + x + 3 := by ring_le +example : x + y + 1 ≤ y + 4 + x := by ring_le + +example : 1 < (3:ℕ) := by ring_lt +example : 0 < (3:ℕ) + 1 := by ring_lt +example : x < x + 3 := by ring_lt +example : x < 1 + x := by ring_lt +example : x + y + 1 < y + x + 3 := by ring_lt +example : x + y < y + x + 3 := by ring_lt +example : x + y + 1 < y + 4 + x := by ring_lt + +end Nat + +section LinearOrderedField +variable {K : Type*} [LinearOrderedField K] {x y : K} + +example : (0:K) ≤ 0 := by ring_le +example : 3 ≤ (3:K) := by ring_le +example : 1 ≤ (3:K) := by ring_le +example : -1 ≤ (3:K) := by ring_le +example : 1.5 ≤ (3:K) := by ring_le +example : 0 ≤ x + 3 - x := by ring_le +example : -1 ≤ x - x := by ring_le +example : x + y + 1 ≤ y + x + 3 := by ring_le +example : x + y + 1 ≤ y + x + 1 := by ring_le +example : x + y ≤ y + x + 3 := by ring_le +example : x + y - 3 ≤ y + x := by ring_le +example : x + y - x + 1 ≤ y + (4:K) := by ring_le + +example : 1 < (3:K) := by ring_lt +example : -1 < (3:K) := by ring_lt +example : 1.5 < (3:K) := by ring_lt +example : 0 < x + 3 - x := by ring_lt +example : -1 < x - x := by ring_lt +example : x + y + 1 < y + x + 3 := by ring_lt +example : x + y < y + x + 3 := by ring_lt +example : x + y - 3 < y + x := by ring_lt +example : x + y - x + 1 < y + (4:K) := by ring_lt + +/- The speed of `Mathlib.Tactic.Ring.proveLE` is very sensitive to how much typeclass inference is +demanded by the lemmas it orchestrates. This example took 1112 heartbeats (and 40 ms on a good +laptop) on an implementation with "minimal" typeclasses everywhere, e.g. lots of +`CovariantClass`/`ContravariantClass`, and takes 662 heartbeats (28 ms on a good laptop) on the +implementation at the time of joining Mathlib (October 2024). -/ +set_option maxHeartbeats 750 in +example : x + y - x + 1 ≤ y + (4:K) := by ring_le + +/- The speed of `Mathlib.Tactic.Ring.proveLT` is very sensitive to how much typeclass inference is +demanded by the lemmas it orchestrates. This example took 1410 heartbeats (and 48 ms on a good +laptop) on an implementation with "minimal" typeclasses everywhere, e.g. lots of +`CovariantClass`/`ContravariantClass`, and takes 676 heartbeats (28 ms on a good laptop) on the +implementation at the time of joining Mathlib (October 2024). -/ +set_option maxHeartbeats 750 in +example : x + y - x + 1 < y + (4:K) := by ring_lt + +/-- +error: ring failed, ring expressions not equal up to an additive constant +K : Type u_1 +inst✝ : LinearOrderedField K +x y : K +⊢ 1 + x + y ≤ 3 + y +-/ +#guard_msgs in +example : x + y + 1 ≤ y + 3 := by ring_le + +/-- +error: comparison failed, LHS is larger +K : Type u_1 +inst✝ : LinearOrderedField K +x y : K +⊢ 4 + x + y ≤ 3 + x + y +-/ +#guard_msgs in +example : x + y + 4 ≤ y + x + 3 := by ring_le + +/-- +error: ring failed, ring expressions not equal up to an additive constant +K : Type u_1 +inst✝ : LinearOrderedField K +x y : K +⊢ 1 + x + y < 3 + y +-/ +#guard_msgs in +example : x + y + 1 < y + 3 := by ring_lt + +/-- +error: comparison failed, LHS is at least as large +K : Type u_1 +inst✝ : LinearOrderedField K +x y : K +⊢ 4 + x + y < 4 + x + y +-/ +#guard_msgs in +example : x + y + 4 < y + x + 4 := by ring_lt + +end LinearOrderedField diff --git a/test/slow_simp.lean b/test/slow_simp.lean index fa6de3b23f5b9..651d0e10e6014 100644 --- a/test/slow_simp.lean +++ b/test/slow_simp.lean @@ -61,7 +61,7 @@ def PointedSpaceEquiv_inverse : Under (TopCat.of Unit) ⥤ PointedSpace where base := by have := f.w replace this := DFunLike.congr_fun this () - simp [- Under.w] at this + simp [-Under.w] at this simp exact this.symm } map_comp := by intros; simp_all; rfl -- This is the slow step. diff --git a/test/toAdditive.lean b/test/toAdditive.lean index cb1938438e035..bd2ad86c8e087 100644 --- a/test/toAdditive.lean +++ b/test/toAdditive.lean @@ -19,12 +19,12 @@ def foo0 {α} [Mul α] [One α] (x y : α) : α := x * y * 1 theorem bar0_works : bar0 3 4 = 7 := by decide -class my_has_pow (α : Type u) (β : Type v) := +class my_has_pow (α : Type u) (β : Type v) where (pow : α → β → α) instance : my_has_pow Nat Nat := ⟨fun a b => a ^ b⟩ -class my_has_scalar (M : Type u) (α : Type v) := +class my_has_scalar (M : Type u) (α : Type v) where (smul : M → α → α) instance : my_has_scalar Nat Nat := ⟨fun a b => a * b⟩ diff --git a/test/trans.lean b/test/trans.lean deleted file mode 100644 index 50b5bc01e7b20..0000000000000 --- a/test/trans.lean +++ /dev/null @@ -1,109 +0,0 @@ -import Mathlib.Tactic.Relation.Trans -import Mathlib.Tactic.GuardGoalNums - -set_option autoImplicit true --- testing that the attribute is recognized and used -def nleq (a b : Nat) : Prop := a ≤ b - -@[trans] def nleq_trans : nleq a b → nleq b c → nleq a c := Nat.le_trans - -example (a b c : Nat) : nleq a b → nleq b c → nleq a c := by - intro h₁ h₂ - trans b - assumption - assumption - -example (a b c : Nat) : nleq a b → nleq b c → nleq a c := by intros; trans <;> assumption - --- using `Trans` typeclass -@[trans] def eq_trans {a b c : α} : a = b → b = c → a = c := by - intro h₁ h₂ - apply Eq.trans h₁ h₂ - -example (a b c : Nat) : a = b → b = c → a = c := by intros; trans <;> assumption - -example (a b c : Nat) : a = b → b = c → a = c := by - intro h₁ h₂ - trans b - assumption - assumption - -example : @Trans Nat Nat Nat (· ≤ ·) (· ≤ ·) (· ≤ ·) := inferInstance - -example (a b c : Nat) : a ≤ b → b ≤ c → a ≤ c := by - intros h₁ h₂ - trans ?b - case b => exact b - exact h₁ - exact h₂ - -example (a b c : α) (R : α → α → Prop) [Trans R R R] : R a b → R b c → R a c := by - intros h₁ h₂ - trans ?b - case b => exact b - exact h₁ - exact h₂ - -example (a b c : Nat) : a ≤ b → b ≤ c → a ≤ c := by - intros h₁ h₂ - trans - exact h₁ - exact h₂ - -example (a b c : Nat) : a ≤ b → b ≤ c → a ≤ c := by intros; trans <;> assumption - -example (a b c : Nat) : a < b → b < c → a < c := by - intro h₁ h₂ - trans b - assumption - assumption - -example (a b c : Nat) : a < b → b < c → a < c := by intros; trans <;> assumption - -example (x n p : Nat) (h₁ : n * Nat.succ p ≤ x) : n * p ≤ x := by - trans - · apply Nat.mul_le_mul_left; apply Nat.le_succ - · apply h₁ - -example (a : α) (c : γ) : ∀ b : β, HEq a b → HEq b c → HEq a c := by - intro b h₁ h₂ - trans b - assumption - assumption - -def MyLE (n m : Nat) := ∃ k, n + k = m - -@[trans] theorem MyLE.trans {n m k : Nat} (h1 : MyLE n m) (h2 : MyLE m k) : MyLE n k := by - cases h1 - cases h2 - subst_vars - exact ⟨_, Eq.symm <| Nat.add_assoc _ _ _⟩ - -example {n m k : Nat} (h1 : MyLE n m) (h2 : MyLE m k) : MyLE n k := by - trans <;> assumption - -/-- `trans` for implications. -/ -example {A B C : Prop} (h : A → B) (g : B → C) : A → C := by - trans B - · guard_target =ₛ A → B -- ensure we have `B` and not a free metavariable. - exact h - · guard_target =ₛ B → C - exact g - -set_option linter.unusedTactic false in -/-- `trans` for arrows between types. -/ -example {A B C : Type} (h : A → B) (g : B → C) : A → C := by - trans - guard_goal_nums 3 -- 3rd goal is the middle term - · exact h - · exact g - -universe u v w - -set_option linter.unusedTactic false in -/-- `trans` for arrows between types. -/ -example {A : Type u} {B : Type v} {C : Type w} (h : A → B) (g : B → C) : A → C := by - trans - guard_goal_nums 3 -- 3rd goal is the middle term - · exact h - · exact g diff --git a/test/zmod.lean b/test/zmod.lean new file mode 100644 index 0000000000000..19fe7d3bb0c27 --- /dev/null +++ b/test/zmod.lean @@ -0,0 +1,15 @@ +import Mathlib.Data.ZMod.Defs + +-- A Mersenne exponent, chosen so the test below takes no more than a few seconds +-- but should be enough to trigger a stack overflow from a non-tail-recursive implementation +-- of exponentiation by repeated squaring. +def k := 11213 +def p := 2^k - 1 + +set_option exponentiation.threshold 100000 in +-- We ensure here that the `@[csimp]` attribute successfully replaces (at runtime) +-- the default value of `npowRec` for the exponentation operation in `Monoid` +-- with a tail-recursive implementation by repeated squaring. +/-- info: 1 -/ +#guard_msgs in +#eval (37 : ZMod p)^(p-1)